diff options
author | Paul Mackerras <paulus@samba.org> | 2008-01-31 03:25:51 +0300 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-01-31 03:25:51 +0300 |
commit | bd45ac0c5daae35e7c71138172e63df5cf644cf6 (patch) | |
tree | 5eb5a599bf6a9d7a8a34e802db932aa9e9555de4 /drivers | |
parent | 4eece4ccf997c0e6d8fdad3d842e37b16b8d705f (diff) | |
parent | 5bdeae46be6dfe9efa44a548bd622af325f4bdb4 (diff) | |
download | linux-bd45ac0c5daae35e7c71138172e63df5cf644cf6.tar.xz |
Merge branch 'linux-2.6'
Diffstat (limited to 'drivers')
1384 files changed, 169659 insertions, 87900 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index f4076d9e9902..08d4ae201597 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -90,8 +90,6 @@ source "drivers/dca/Kconfig" source "drivers/auxdisplay/Kconfig" -source "drivers/kvm/Kconfig" - source "drivers/uio/Kconfig" source "drivers/virtio/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 8cb37e3557d4..0ee9a8a4095e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_SCSI) += scsi/ obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_FUSION) += message/ obj-$(CONFIG_FIREWIRE) += firewire/ -obj-$(CONFIG_IEEE1394) += ieee1394/ +obj-y += ieee1394/ obj-$(CONFIG_UIO) += uio/ obj-y += cdrom/ obj-y += auxdisplay/ @@ -47,7 +47,6 @@ obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_PCCARD) += pcmcia/ obj-$(CONFIG_DIO) += dio/ obj-$(CONFIG_SBUS) += sbus/ -obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_ZORRO) += zorro/ obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ @@ -73,7 +72,7 @@ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_EDAC) += edac/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ -obj-$(CONFIG_LGUEST_GUEST) += lguest/ +obj-y += lguest/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_IDLE) += cpuidle/ obj-$(CONFIG_MMC) += mmc/ diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 3ec110ce00c8..8809654d6cc9 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -3,6 +3,7 @@ * * Check to see if the given machine has a known bad ACPI BIOS * or if the BIOS is too old. + * Check given machine against acpi_osi_dmi_table[]. * * Copyright (C) 2004 Len Brown <len.brown@intel.com> * Copyright (C) 2002 Andy Grover <andrew.grover@intel.com> @@ -50,6 +51,8 @@ struct acpi_blacklist_item { u32 is_critical_error; }; +static struct dmi_system_id acpi_osi_dmi_table[] __initdata; + /* * POLICY: If *anything* doesn't work, put it on the blacklist. * If they are critical errors, mark it critical, and abort driver load. @@ -165,5 +168,383 @@ int __init acpi_blacklisted(void) blacklisted += blacklist_by_year(); + dmi_check_system(acpi_osi_dmi_table); + return blacklisted; } +#ifdef CONFIG_DMI +static int __init dmi_enable_osi_linux(const struct dmi_system_id *d) +{ + acpi_dmi_osi_linux(1, d); /* enable */ + return 0; +} +static int __init dmi_disable_osi_linux(const struct dmi_system_id *d) +{ + acpi_dmi_osi_linux(0, d); /* disable */ + return 0; +} +static int __init dmi_unknown_osi_linux(const struct dmi_system_id *d) +{ + acpi_dmi_osi_linux(-1, d); /* unknown */ + return 0; +} + +/* + * Most BIOS that invoke OSI(Linux) do nothing with it. + * But some cause Linux to break. + * Only a couple use it to make Linux run better. + * + * Thus, Linux should continue to disable OSI(Linux) by default, + * should continue to discourage BIOS writers from using it, and + * should whitelist the few existing systems that require it. + * + * If it appears clear a vendor isn't using OSI(Linux) + * for anything constructive, blacklist them by name to disable + * unnecessary dmesg warnings on all of their products. + */ + +static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { + /* + * Disable OSI(Linux) warnings on all "Acer, inc." + * + * _OSI(Linux) disables the latest Windows BIOS code: + * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"), + * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"), + * _OSI(Linux) effect unknown: + * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Acer, inc.", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."), + }, + }, + /* + * Disable OSI(Linux) warnings on all "Acer" + * + * _OSI(Linux) effect unknown: + * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"), + * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"), + * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"), + * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"), + */ + { + .callback = dmi_unknown_osi_linux, + .ident = "Acer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "Apple Computer, Inc." + * + * _OSI(Linux) confirmed to be a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), + * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"), + * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), + * _OSI(Linux) effect unknown: + * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"), + * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), + * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Apple", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), + }, + }, + /* + * Disable OSI(Linux) warnings on all "BenQ" + * + * _OSI(Linux) confirmed to be a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "Joybook S31"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "BenQ", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "BenQ"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "Clevo Co." + * + * _OSI(Linux) confirmed to be a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "M570RU"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Clevo", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."), + }, + }, + /* + * Disable OSI(Linux) warnings on all "COMPAL" + * + * _OSI(Linux) confirmed to be a NOP: + * DMI_MATCH(DMI_BOARD_NAME, "HEL8X"), + * _OSI(Linux) unknown effect: + * DMI_MATCH(DMI_BOARD_NAME, "IFL91"), + */ + { + .callback = dmi_unknown_osi_linux, + .ident = "Compal", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), + }, + }, + { /* OSI(Linux) touches USB, breaks suspend to disk */ + .callback = dmi_disable_osi_linux, + .ident = "Dell Dimension 5150", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM051"), + }, + }, + { /* OSI(Linux) is a NOP */ + .callback = dmi_disable_osi_linux, + .ident = "Dell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"), + }, + }, + { /* OSI(Linux) effect unknown */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"), + }, + }, + { /* OSI(Linux) effect unknown */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"), + }, + }, + { /* OSI(Linux) effect unknown */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"), + }, + }, + { /* OSI(Linux) touches USB */ + .callback = dmi_disable_osi_linux, + .ident = "Dell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"), + }, + }, + { /* OSI(Linux) is a NOP */ + .callback = dmi_disable_osi_linux, + .ident = "Dell Vostro 1000", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 1000"), + }, + }, + { /* OSI(Linux) effect unknown */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"), + }, + }, + { /* OSI(Linux) effect unknown */ + .callback = dmi_unknown_osi_linux, + .ident = "Dialogue Flybook V5", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dialogue Technology Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Flybook V5"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "FUJITSU SIEMENS" + * + * _OSI(Linux) disables latest Windows BIOS code: + * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2510"), + * _OSI(Linux) confirmed to be a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1536"), + * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1556"), + * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 1546"), + * _OSI(Linux) unknown effect: + * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo M1425"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo Si 1520"), + * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Fujitsu Siemens", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "Hewlett-Packard" + * + * _OSI(Linux) confirmed to be a NOP: + * .ident = "HP Pavilion tx 1000" + * DMI_MATCH(DMI_BOARD_NAME, "30BF"), + * .ident = "HP Pavilion dv2000" + * DMI_MATCH(DMI_BOARD_NAME, "30B5"), + * .ident = "HP Pavilion dv5000", + * DMI_MATCH(DMI_BOARD_NAME, "30A7"), + * .ident = "HP Pavilion dv6300 30BC", + * DMI_MATCH(DMI_BOARD_NAME, "30BC"), + * .ident = "HP Pavilion dv6000", + * DMI_MATCH(DMI_BOARD_NAME, "30B7"), + * DMI_MATCH(DMI_BOARD_NAME, "30B8"), + * .ident = "HP Pavilion dv9000", + * DMI_MATCH(DMI_BOARD_NAME, "30B9"), + * .ident = "HP Pavilion dv9500", + * DMI_MATCH(DMI_BOARD_NAME, "30CB"), + * .ident = "HP/Compaq Presario C500", + * DMI_MATCH(DMI_BOARD_NAME, "30C6"), + * .ident = "HP/Compaq Presario F500", + * DMI_MATCH(DMI_BOARD_NAME, "30D3"), + * _OSI(Linux) unknown effect: + * .ident = "HP Pavilion dv6500", + * DMI_MATCH(DMI_BOARD_NAME, "30D0"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Hewlett-Packard", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + }, + }, + /* + * Lenovo has a mix of systems OSI(Linux) situations + * and thus we can not wildcard the vendor. + * + * _OSI(Linux) helps sound + * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"), + * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), + * _OSI(Linux) is a NOP: + * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), + */ + { + .callback = dmi_enable_osi_linux, + .ident = "Lenovo ThinkPad R61", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"), + }, + }, + { + .callback = dmi_enable_osi_linux, + .ident = "Lenovo ThinkPad T61", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), + }, + }, + { + .callback = dmi_unknown_osi_linux, + .ident = "Lenovo 3000 V100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"), + }, + }, + { + .callback = dmi_disable_osi_linux, + .ident = "Lenovo 3000 N100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "LG Electronics" + * + * _OSI(Linux) confirmed to be a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "LG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), + }, + }, + /* NEC - OSI(Linux) effect unknown */ + { + .callback = dmi_unknown_osi_linux, + .ident = "NEC VERSA M360", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC Computers SAS"), + DMI_MATCH(DMI_PRODUCT_NAME, "NEC VERSA M360"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "Samsung Electronics" + * + * OSI(Linux) disables PNP0C32 and other BIOS code for Windows: + * DMI_MATCH(DMI_PRODUCT_NAME, "R40P/R41P"), + * DMI_MATCH(DMI_PRODUCT_NAME, "R59P/R60P/R61P"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Samsung", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + }, + }, + /* + * Disable OSI(Linux) warnings on all "Sony Corporation" + * + * _OSI(Linux) is a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"), + * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ38GP_C"), + * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TZ21MN_N"), + * _OSI(Linux) unknown effect: + * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"), + */ + { + .callback = dmi_unknown_osi_linux, + .ident = "Sony", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + }, + }, + /* + * Disable OSI(Linux) warnings on all "TOSHIBA" + * + * _OSI(Linux) breaks sound (bugzilla 7787): + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P100"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P105"), + * _OSI(Linux) is a NOP: + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A100"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A210"), + * _OSI(Linux) unknown effect: + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A135"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite A200"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P205"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U305"), + */ + { + .callback = dmi_disable_osi_linux, + .ident = "Toshiba", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + }, + }, + {} +}; + +#endif /* CONFIG_DMI */ diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d7a115c362d1..1b4cf984b081 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -200,7 +200,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) * Get device's current power state */ acpi_bus_get_power(device->handle, &device->power.state); - if (state == device->power.state) { + if ((state == device->power.state) && !device->flags.force_power_state) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state)); return 0; @@ -743,7 +743,7 @@ static int __init acpi_bus_init(void) return -ENODEV; } -decl_subsys(acpi, NULL, NULL); +struct kobject *acpi_kobj; static int __init acpi_init(void) { @@ -755,10 +755,11 @@ static int __init acpi_init(void) return -ENODEV; } - result = firmware_register(&acpi_subsys); - if (result < 0) - printk(KERN_WARNING "%s: firmware_register error: %d\n", - __FUNCTION__, result); + acpi_kobj = kobject_create_and_add("acpi", firmware_kobj); + if (!acpi_kobj) { + printk(KERN_WARNING "%s: kset create error\n", __FUNCTION__); + acpi_kobj = NULL; + } result = acpi_bus_init(); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 97dc16155a55..987b967c7467 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -26,6 +26,9 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* Uncomment next line to get verbose print outs*/ +/* #define DEBUG */ + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -47,9 +50,6 @@ #undef PREFIX #define PREFIX "ACPI: EC: " -/* Uncomment next line to get verbose print outs*/ -/* #define DEBUG */ - /* EC status register */ #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ @@ -82,6 +82,7 @@ enum { EC_FLAGS_ADDRESS, /* Address is being written */ EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */ EC_FLAGS_WDATA, /* Data is being written */ + EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */ }; static int acpi_ec_remove(struct acpi_device *device, int type); @@ -138,26 +139,26 @@ static struct acpi_ec { static inline u8 acpi_ec_read_status(struct acpi_ec *ec) { u8 x = inb(ec->command_addr); - pr_debug(PREFIX "---> status = 0x%2x\n", x); + pr_debug(PREFIX "---> status = 0x%2.2x\n", x); return x; } static inline u8 acpi_ec_read_data(struct acpi_ec *ec) { u8 x = inb(ec->data_addr); - pr_debug(PREFIX "---> data = 0x%2x\n", x); + pr_debug(PREFIX "---> data = 0x%2.2x\n", x); return inb(ec->data_addr); } static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command) { - pr_debug(PREFIX "<--- command = 0x%2x\n", command); + pr_debug(PREFIX "<--- command = 0x%2.2x\n", command); outb(command, ec->command_addr); } static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data) { - pr_debug(PREFIX "<--- data = 0x%2x\n", data); + pr_debug(PREFIX "<--- data = 0x%2.2x\n", data); outb(data, ec->data_addr); } @@ -179,6 +180,10 @@ static inline int acpi_ec_check_status(struct acpi_ec *ec, enum ec_event event) static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) { int ret = 0; + + if (unlikely(event == ACPI_EC_EVENT_OBF_1 && + test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags))) + force_poll = 1; if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) && test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags))) force_poll = 1; @@ -192,7 +197,12 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) goto end; clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags); if (acpi_ec_check_status(ec, event)) { - if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { + if (event == ACPI_EC_EVENT_OBF_1) { + /* miss OBF_1 GPE, don't expect it */ + pr_info(PREFIX "missing OBF confirmation, " + "don't expect it any longer.\n"); + set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags); + } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) { /* miss address GPE, don't expect it anymore */ pr_info(PREFIX "missing address confirmation, " "don't expect it any longer.\n"); diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index a5a5532db268..a6e149d692cb 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -47,6 +47,8 @@ MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); static int acpi_fan_remove(struct acpi_device *device, int type); +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); +static int acpi_fan_resume(struct acpi_device *device); static const struct acpi_device_id fan_device_ids[] = { {"PNP0C0B", 0}, @@ -61,6 +63,8 @@ static struct acpi_driver acpi_fan_driver = { .ops = { .add = acpi_fan_add, .remove = acpi_fan_remove, + .suspend = acpi_fan_suspend, + .resume = acpi_fan_resume, }, }; @@ -191,6 +195,10 @@ static int acpi_fan_add(struct acpi_device *device) goto end; } + device->flags.force_power_state = 1; + acpi_bus_set_power(device->handle, state); + device->flags.force_power_state = 0; + result = acpi_fan_add_fs(device); if (result) goto end; @@ -216,6 +224,38 @@ static int acpi_fan_remove(struct acpi_device *device, int type) return 0; } +static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) +{ + if (!device) + return -EINVAL; + + acpi_bus_set_power(device->handle, ACPI_STATE_D0); + + return AE_OK; +} + +static int acpi_fan_resume(struct acpi_device *device) +{ + int result = 0; + int power_state = 0; + + if (!device) + return -EINVAL; + + result = acpi_bus_get_power(device->handle, &power_state); + if (result) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Error reading fan power state\n")); + return result; + } + + device->flags.force_power_state = 1; + acpi_bus_set_power(device->handle, power_state); + device->flags.force_power_state = 0; + + return result; +} + static int __init acpi_fan_init(void) { int result = 0; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index e3a673a00845..e53fb516f9d4 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -77,11 +77,55 @@ static struct workqueue_struct *kacpi_notify_wq; #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ static char osi_additional_string[OSI_STRING_LENGTH_MAX]; -static int osi_linux; /* disable _OSI(Linux) by default */ +/* + * "Ode to _OSI(Linux)" + * + * osi_linux -- Control response to BIOS _OSI(Linux) query. + * + * As Linux evolves, the features that it supports change. + * So an OSI string such as "Linux" is not specific enough + * to be useful across multiple versions of Linux. It + * doesn't identify any particular feature, interface, + * or even any particular version of Linux... + * + * Unfortunately, Linux-2.6.22 and earlier responded "yes" + * to a BIOS _OSI(Linux) query. When + * a reference mobile BIOS started using it, its use + * started to spread to many vendor platforms. + * As it is not supportable, we need to halt that spread. + * + * Today, most BIOS references to _OSI(Linux) are noise -- + * they have no functional effect and are just dead code + * carried over from the reference BIOS. + * + * The next most common case is that _OSI(Linux) harms Linux, + * usually by causing the BIOS to follow paths that are + * not tested during Windows validation. + * + * Finally, there is a short list of platforms + * where OSI(Linux) benefits Linux. + * + * In Linux-2.6.23, OSI(Linux) is first disabled by default. + * DMI is used to disable the dmesg warning about OSI(Linux) + * on platforms where it is known to have no effect. + * But a dmesg warning remains for systems where + * we do not know if OSI(Linux) is good or bad for the system. + * DMI is also used to enable OSI(Linux) for the machines + * that are known to need it. + * + * BIOS writers should NOT query _OSI(Linux) on future systems. + * It will be ignored by default, and to get Linux to + * not ignore it will require a kernel source update to + * add a DMI entry, or a boot-time "acpi_osi=Linux" invocation. + */ +#define OSI_LINUX_ENABLE 0 -#ifdef CONFIG_DMI -static struct __initdata dmi_system_id acpi_osl_dmi_table[]; -#endif +struct osi_linux { + unsigned int enable:1; + unsigned int dmi:1; + unsigned int cmdline:1; + unsigned int known:1; +} osi_linux = { OSI_LINUX_ENABLE, 0, 0, 0}; static void __init acpi_request_region (struct acpi_generic_address *addr, unsigned int length, char *desc) @@ -133,7 +177,6 @@ device_initcall(acpi_reserve_resources); acpi_status __init acpi_os_initialize(void) { - dmi_check_system(acpi_osl_dmi_table); return AE_OK; } @@ -964,13 +1007,37 @@ static int __init acpi_os_name_setup(char *str) __setup("acpi_os_name=", acpi_os_name_setup); -static void enable_osi_linux(int enable) { +static void __init set_osi_linux(unsigned int enable) +{ + if (osi_linux.enable != enable) { + osi_linux.enable = enable; + printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n", + enable ? "Add": "Delet"); + } + return; +} - if (osi_linux != enable) - printk(KERN_INFO PREFIX "%sabled _OSI(Linux)\n", - enable ? "En": "Dis"); +static void __init acpi_cmdline_osi_linux(unsigned int enable) +{ + osi_linux.cmdline = 1; /* cmdline set the default */ + set_osi_linux(enable); + + return; +} + +void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) +{ + osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */ + + printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); + + if (enable == -1) + return; + + osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */ + + set_osi_linux(enable); - osi_linux = enable; return; } @@ -987,12 +1054,12 @@ static int __init acpi_osi_setup(char *str) printk(KERN_INFO PREFIX "_OSI method disabled\n"); acpi_gbl_create_osi_method = FALSE; } else if (!strcmp("!Linux", str)) { - enable_osi_linux(0); + acpi_cmdline_osi_linux(0); /* !enable */ } else if (*str == '!') { if (acpi_osi_invalidate(++str) == AE_OK) printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); } else if (!strcmp("Linux", str)) { - enable_osi_linux(1); + acpi_cmdline_osi_linux(1); /* enable */ } else if (*osi_additional_string == '\0') { strncpy(osi_additional_string, str, OSI_STRING_LENGTH_MAX); printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); @@ -1141,6 +1208,34 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) return (AE_OK); } +/** + * acpi_dmi_dump - dump DMI slots needed for blacklist entry + * + * Returns 0 on success + */ +int acpi_dmi_dump(void) +{ + + if (!dmi_available) + return -1; + + printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n", + dmi_get_slot(DMI_SYS_VENDOR)); + printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n", + dmi_get_slot(DMI_PRODUCT_NAME)); + printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n", + dmi_get_slot(DMI_PRODUCT_VERSION)); + printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n", + dmi_get_slot(DMI_BOARD_NAME)); + printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n", + dmi_get_slot(DMI_BIOS_VENDOR)); + printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n", + dmi_get_slot(DMI_BIOS_DATE)); + + return 0; +} + + /****************************************************************************** * * FUNCTION: acpi_os_validate_interface @@ -1160,13 +1255,29 @@ acpi_os_validate_interface (char *interface) if (!strncmp(osi_additional_string, interface, OSI_STRING_LENGTH_MAX)) return AE_OK; if (!strcmp("Linux", interface)) { - printk(KERN_WARNING PREFIX - "System BIOS is requesting _OSI(Linux)\n"); - printk(KERN_WARNING PREFIX - "If \"acpi_osi=Linux\" works better,\n" - "Please send dmidecode " - "to linux-acpi@vger.kernel.org\n"); - if(osi_linux) + + printk(KERN_NOTICE PREFIX + "BIOS _OSI(Linux) query %s%s\n", + osi_linux.enable ? "honored" : "ignored", + osi_linux.cmdline ? " via cmdline" : + osi_linux.dmi ? " via DMI" : ""); + + if (!osi_linux.dmi) { + if (acpi_dmi_dump()) + printk(KERN_NOTICE PREFIX + "[please extract dmidecode output]\n"); + printk(KERN_NOTICE PREFIX + "Please send DMI info above to " + "linux-acpi@vger.kernel.org\n"); + } + if (!osi_linux.known && !osi_linux.cmdline) { + printk(KERN_NOTICE PREFIX + "If \"acpi_osi=%sLinux\" works better, " + "please notify linux-acpi@vger.kernel.org\n", + osi_linux.enable ? "!" : ""); + } + + if (osi_linux.enable) return AE_OK; } return AE_SUPPORT; @@ -1198,28 +1309,4 @@ acpi_os_validate_address ( return AE_OK; } -#ifdef CONFIG_DMI -static int dmi_osi_linux(const struct dmi_system_id *d) -{ - printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident); - enable_osi_linux(1); - return 0; -} - -static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { - /* - * Boxes that need _OSI(Linux) - */ - { - .callback = dmi_osi_linux, - .ident = "Intel Napa CRB", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"), - }, - }, - {} -}; -#endif /* CONFIG_DMI */ - #endif diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index c9f526e55392..5400ea173f6f 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -911,7 +911,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set); /* FIXME: we will remove this interface after all drivers call pci_disable_device */ static struct sysdev_class irqrouter_sysdev_class = { - set_kset_name("irqrouter"), + .name = "irqrouter", .resume = irqrouter_resume, }; diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2235f4e02d26..eb1f82f79153 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -357,6 +357,26 @@ int acpi_processor_resume(struct acpi_device * device) return 0; } +#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) +static int tsc_halts_in_c(int state) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + /* + * AMD Fam10h TSC will tick in all + * C/P/S0/S1 states when this bit is set. + */ + if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) + return 0; + /*FALL THROUGH*/ + case X86_VENDOR_INTEL: + /* Several cases known where TSC halts in C2 too */ + default: + return state > ACPI_STATE_C1; + } +} +#endif + #ifndef CONFIG_CPU_IDLE static void acpi_processor_idle(void) { @@ -516,7 +536,8 @@ static void acpi_processor_idle(void) #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) /* TSC halts in C2, so notify users */ - mark_tsc_unstable("possible TSC halt in C2"); + if (tsc_halts_in_c(ACPI_STATE_C2)) + mark_tsc_unstable("possible TSC halt in C2"); #endif /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2); @@ -534,6 +555,7 @@ static void acpi_processor_idle(void) break; case ACPI_STATE_C3: + acpi_unlazy_tlb(smp_processor_id()); /* * Must be done before busmaster disable as we might * need to access HPET ! @@ -579,7 +601,8 @@ static void acpi_processor_idle(void) #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) /* TSC halts in C3, so notify users */ - mark_tsc_unstable("TSC halts in C3"); + if (tsc_halts_in_c(ACPI_STATE_C3)) + mark_tsc_unstable("TSC halts in C3"); #endif /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2); @@ -1423,6 +1446,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, return 0; } + acpi_unlazy_tlb(smp_processor_id()); /* * Must be done before busmaster disable as we might need to * access HPET ! @@ -1443,7 +1467,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) /* TSC could halt in idle, so notify users */ - mark_tsc_unstable("TSC halts in idle");; + if (tsc_halts_in_c(cx->type)) + mark_tsc_unstable("TSC halts in idle");; #endif sleep_ticks = ticks_elapsed(t1, t2); @@ -1554,7 +1579,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC) /* TSC could halt in idle, so notify users */ - mark_tsc_unstable("TSC halts in idle"); + if (tsc_halts_in_c(ACPI_STATE_C3)) + mark_tsc_unstable("TSC halts in idle"); #endif sleep_ticks = ticks_elapsed(t1, t2); /* Tell the scheduler how much we idled: */ diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 6742d7bc4777..1685b40abda7 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -775,12 +775,12 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) acpi_processor_get_throttling_states(pr) || acpi_processor_get_platform_limit(pr)) { - if (acpi_processor_get_fadt_info(pr)) - return 0; pr->throttling.acpi_processor_get_throttling = &acpi_processor_get_throttling_fadt; pr->throttling.acpi_processor_set_throttling = &acpi_processor_set_throttling_fadt; + if (acpi_processor_get_fadt_info(pr)) + return 0; } else { pr->throttling.acpi_processor_get_throttling = &acpi_processor_get_throttling_ptc; diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index edee2806e37b..5ffe0ea18967 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -58,7 +58,7 @@ module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); FS Interface (/sys) -------------------------------------------------------------------------- */ static LIST_HEAD(acpi_table_attr_list); -static struct kobject tables_kobj; +static struct kobject *tables_kobj; struct acpi_table_attr { struct bin_attribute attr; @@ -135,11 +135,9 @@ static int acpi_system_sysfs_init(void) int table_index = 0; int result; - tables_kobj.parent = &acpi_subsys.kobj; - kobject_set_name(&tables_kobj, "tables"); - result = kobject_register(&tables_kobj); - if (result) - return result; + tables_kobj = kobject_create_and_add("tables", acpi_kobj); + if (!tables_kobj) + return -ENOMEM; do { result = acpi_get_table_by_index(table_index, &table_header); @@ -153,7 +151,7 @@ static int acpi_system_sysfs_init(void) acpi_table_attr_init(table_attr, table_header); result = - sysfs_create_bin_file(&tables_kobj, + sysfs_create_bin_file(tables_kobj, &table_attr->attr); if (result) { kfree(table_attr); @@ -163,6 +161,7 @@ static int acpi_system_sysfs_init(void) &acpi_table_attr_list); } } while (!result); + kobject_uevent(tables_kobj, KOBJ_ADD); return 0; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 75939dd06295..ae19c9b30d15 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -459,6 +459,15 @@ config PATA_NETCELL If unsure, say N. +config PATA_NINJA32 + tristate "Ninja32/Delkin Cardbus ATA support (Experimental)" + depends on PCI && EXPERIMENTAL + help + This option enables support for the Ninja32, Delkin and + possibly other brands of Cardbus ATA adapter + + If unsure, say N. + config PATA_NS87410 tristate "Nat Semi NS87410 PATA support (Experimental)" depends on PCI && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index ebcee64dd5e2..701651e37c89 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_PATA_IT821X) += pata_it821x.o obj-$(CONFIG_PATA_IT8213) += pata_it8213.o obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o +obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o obj-$(CONFIG_PATA_OPTI) += pata_opti.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 54f38c21dd95..6f089b899a1a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -198,18 +198,18 @@ enum { }; struct ahci_cmd_hdr { - u32 opts; - u32 status; - u32 tbl_addr; - u32 tbl_addr_hi; - u32 reserved[4]; + __le32 opts; + __le32 status; + __le32 tbl_addr; + __le32 tbl_addr_hi; + __le32 reserved[4]; }; struct ahci_sg { - u32 addr; - u32 addr_hi; - u32 reserved; - u32 flags_size; + __le32 addr; + __le32 addr_hi; + __le32 reserved; + __le32 flags_size; }; struct ahci_host_priv { @@ -597,6 +597,20 @@ static inline void __iomem *ahci_port_base(struct ata_port *ap) return __ahci_port_base(ap->host, ap->port_no); } +static void ahci_enable_ahci(void __iomem *mmio) +{ + u32 tmp; + + /* turn on AHCI_EN */ + tmp = readl(mmio + HOST_CTL); + if (!(tmp & HOST_AHCI_EN)) { + tmp |= HOST_AHCI_EN; + writel(tmp, mmio + HOST_CTL); + tmp = readl(mmio + HOST_CTL); /* flush && sanity check */ + WARN_ON(!(tmp & HOST_AHCI_EN)); + } +} + /** * ahci_save_initial_config - Save and fixup initial config values * @pdev: target PCI device @@ -619,6 +633,9 @@ static void ahci_save_initial_config(struct pci_dev *pdev, u32 cap, port_map; int i; + /* make sure AHCI mode is enabled before accessing CAP */ + ahci_enable_ahci(mmio); + /* Values prefixed with saved_ are written back to host after * reset. Values without are used for driver operation. */ @@ -1036,19 +1053,17 @@ static int ahci_deinit_port(struct ata_port *ap, const char **emsg) static int ahci_reset_controller(struct ata_host *host) { struct pci_dev *pdev = to_pci_dev(host->dev); + struct ahci_host_priv *hpriv = host->private_data; void __iomem *mmio = host->iomap[AHCI_PCI_BAR]; u32 tmp; /* we must be in AHCI mode, before using anything * AHCI-specific, such as HOST_RESET. */ - tmp = readl(mmio + HOST_CTL); - if (!(tmp & HOST_AHCI_EN)) { - tmp |= HOST_AHCI_EN; - writel(tmp, mmio + HOST_CTL); - } + ahci_enable_ahci(mmio); /* global controller reset */ + tmp = readl(mmio + HOST_CTL); if ((tmp & HOST_RESET) == 0) { writel(tmp | HOST_RESET, mmio + HOST_CTL); readl(mmio + HOST_CTL); /* flush */ @@ -1067,8 +1082,7 @@ static int ahci_reset_controller(struct ata_host *host) } /* turn on AHCI mode */ - writel(HOST_AHCI_EN, mmio + HOST_CTL); - (void) readl(mmio + HOST_CTL); /* flush */ + ahci_enable_ahci(mmio); /* some registers might be cleared on reset. restore initial values */ ahci_restore_initial_config(host); @@ -1078,8 +1092,10 @@ static int ahci_reset_controller(struct ata_host *host) /* configure PCS */ pci_read_config_word(pdev, 0x92, &tmp16); - tmp16 |= 0xf; - pci_write_config_word(pdev, 0x92, tmp16); + if ((tmp16 & hpriv->port_map) != hpriv->port_map) { + tmp16 |= hpriv->port_map; + pci_write_config_word(pdev, 0x92, tmp16); + } } return 0; @@ -1480,35 +1496,31 @@ static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl) { struct scatterlist *sg; - struct ahci_sg *ahci_sg; - unsigned int n_sg = 0; + struct ahci_sg *ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; + unsigned int si; VPRINTK("ENTER\n"); /* * Next, the S/G list. */ - ahci_sg = cmd_tbl + AHCI_CMD_TBL_HDR_SZ; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); - ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); - ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); - ahci_sg->flags_size = cpu_to_le32(sg_len - 1); - - ahci_sg++; - n_sg++; + ahci_sg[si].addr = cpu_to_le32(addr & 0xffffffff); + ahci_sg[si].addr_hi = cpu_to_le32((addr >> 16) >> 16); + ahci_sg[si].flags_size = cpu_to_le32(sg_len - 1); } - return n_sg; + return si; } static void ahci_qc_prep(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ahci_port_priv *pp = ap->private_data; - int is_atapi = is_atapi_taskfile(&qc->tf); + int is_atapi = ata_is_atapi(qc->tf.protocol); void *cmd_tbl; u32 opts; const u32 cmd_fis_len = 5; /* five dwords */ diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 90329982bef7..20534202fc79 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include <linux/libata.h> #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.13" +#define DRV_VERSION "0.2.15" /* * A generic parallel ATA driver using libata @@ -48,27 +48,47 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused) struct ata_port *ap = link->ap; int dma_enabled = 0; struct ata_device *dev; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); /* Bits 5 and 6 indicate if DMA is active on master/slave */ if (ap->ioaddr.bmdma_addr) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + if (pdev->vendor == PCI_VENDOR_ID_CENATEK) + dma_enabled = 0xFF; + ata_link_for_each_dev(dev, link) { - if (ata_dev_enabled(dev)) { - /* We don't really care */ - dev->pio_mode = XFER_PIO_0; - dev->dma_mode = XFER_MW_DMA_0; - /* We do need the right mode information for DMA or PIO - and this comes from the current configuration flags */ - if (dma_enabled & (1 << (5 + dev->devno))) { - ata_id_to_dma_mode(dev, XFER_MW_DMA_0); - dev->flags &= ~ATA_DFLAG_PIO; - } else { - ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); - dev->xfer_mode = XFER_PIO_0; - dev->xfer_shift = ATA_SHIFT_PIO; - dev->flags |= ATA_DFLAG_PIO; + if (!ata_dev_enabled(dev)) + continue; + + /* We don't really care */ + dev->pio_mode = XFER_PIO_0; + dev->dma_mode = XFER_MW_DMA_0; + /* We do need the right mode information for DMA or PIO + and this comes from the current configuration flags */ + if (dma_enabled & (1 << (5 + dev->devno))) { + unsigned int xfer_mask = ata_id_xfermask(dev->id); + const char *name; + + if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA)) + name = ata_mode_string(xfer_mask); + else { + /* SWDMA perhaps? */ + name = "DMA"; + xfer_mask |= ata_xfer_mode2mask(XFER_MW_DMA_0); } + + ata_dev_printk(dev, KERN_INFO, "configured for %s\n", + name); + + dev->xfer_mode = ata_xfer_mask2mode(xfer_mask); + dev->xfer_shift = ata_xfer_mode2shift(dev->xfer_mode); + dev->flags &= ~ATA_DFLAG_PIO; + } else { + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); + dev->xfer_mode = XFER_PIO_0; + dev->xfer_shift = ATA_SHIFT_PIO; + dev->flags |= ATA_DFLAG_PIO; } } return 0; @@ -185,6 +205,7 @@ static struct pci_device_id ata_generic[] = { { PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), }, { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), }, + { PCI_DEVICE(PCI_VENDOR_ID_CENATEK,PCI_DEVICE_ID_CENATEK_IDE), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), }, { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), }, diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index b406b39b878e..a65c8ae5c461 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -101,39 +101,21 @@ enum { ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ PIIX_SCC = 0x0A, /* sub-class code register */ + PIIX_SIDPR_BAR = 5, + PIIX_SIDPR_LEN = 16, + PIIX_SIDPR_IDX = 0, + PIIX_SIDPR_DATA = 4, - PIIX_FLAG_SCR = (1 << 26), /* SCR available */ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ + PIIX_FLAG_SIDPR = (1 << 29), /* SATA idx/data pair regs */ PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, - /* combined mode. if set, PATA is channel 0. - * if clear, PATA is channel 1. - */ - PIIX_PORT_ENABLED = (1 << 0), - PIIX_PORT_PRESENT = (1 << 4), - PIIX_80C_PRI = (1 << 5) | (1 << 4), PIIX_80C_SEC = (1 << 7) | (1 << 6), - /* controller IDs */ - piix_pata_mwdma = 0, /* PIIX3 MWDMA only */ - piix_pata_33, /* PIIX4 at 33Mhz */ - ich_pata_33, /* ICH up to UDMA 33 only */ - ich_pata_66, /* ICH up to 66 Mhz */ - ich_pata_100, /* ICH up to UDMA 100 */ - ich5_sata, - ich6_sata, - ich6_sata_ahci, - ich6m_sata_ahci, - ich8_sata_ahci, - ich8_2port_sata, - ich8m_apple_sata_ahci, /* locks up on second port enable */ - tolapai_sata_ahci, - piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ - /* constants for mapping table */ P0 = 0, /* port 0 */ P1 = 1, /* port 1 */ @@ -149,6 +131,24 @@ enum { PIIX_HOST_BROKEN_SUSPEND = (1 << 24), }; +enum piix_controller_ids { + /* controller IDs */ + piix_pata_mwdma, /* PIIX3 MWDMA only */ + piix_pata_33, /* PIIX4 at 33Mhz */ + ich_pata_33, /* ICH up to UDMA 33 only */ + ich_pata_66, /* ICH up to 66 Mhz */ + ich_pata_100, /* ICH up to UDMA 100 */ + ich5_sata, + ich6_sata, + ich6_sata_ahci, + ich6m_sata_ahci, + ich8_sata_ahci, + ich8_2port_sata, + ich8m_apple_sata_ahci, /* locks up on second port enable */ + tolapai_sata_ahci, + piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ +}; + struct piix_map_db { const u32 mask; const u16 port_enable; @@ -157,6 +157,7 @@ struct piix_map_db { struct piix_host_priv { const int *map; + void __iomem *sidpr; }; static int piix_init_one(struct pci_dev *pdev, @@ -167,6 +168,9 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); static int ich_pata_cable_detect(struct ata_port *ap); static u8 piix_vmw_bmdma_status(struct ata_port *ap); +static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); +static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); +static void piix_sidpr_error_handler(struct ata_port *ap); #ifdef CONFIG_PM static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int piix_pci_device_resume(struct pci_dev *pdev); @@ -321,7 +325,6 @@ static const struct ata_port_operations piix_pata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ata_cable_40wire, - .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, @@ -353,7 +356,6 @@ static const struct ata_port_operations ich_pata_ops = { .post_internal_cmd = ata_bmdma_post_internal_cmd, .cable_detect = ich_pata_cable_detect, - .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, @@ -380,7 +382,6 @@ static const struct ata_port_operations piix_sata_ops = { .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, @@ -419,6 +420,35 @@ static const struct ata_port_operations piix_vmw_ops = { .port_start = ata_port_start, }; +static const struct ata_port_operations piix_sidpr_sata_ops = { + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_data_xfer, + + .scr_read = piix_sidpr_scr_read, + .scr_write = piix_sidpr_scr_write, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = piix_sidpr_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_port_start, +}; + static const struct piix_map_db ich5_map_db = { .mask = 0x7, .port_enable = 0x3, @@ -526,7 +556,6 @@ static const struct piix_map_db *piix_map_db_table[] = { static struct ata_port_info piix_port_info[] = { [piix_pata_mwdma] = /* PIIX3 MWDMA only */ { - .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ @@ -535,7 +564,6 @@ static struct ata_port_info piix_port_info[] = { [piix_pata_33] = /* PIIX4 at 33MHz */ { - .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */ @@ -545,7 +573,6 @@ static struct ata_port_info piix_port_info[] = { [ich_pata_33] = /* ICH0 - ICH at 33Mhz*/ { - .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* Check: maybe 0x07 */ @@ -555,7 +582,6 @@ static struct ata_port_info piix_port_info[] = { [ich_pata_66] = /* ICH controllers up to 66MHz */ { - .sht = &piix_sht, .flags = PIIX_PATA_FLAGS, .pio_mask = 0x1f, /* pio 0-4 */ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */ @@ -565,7 +591,6 @@ static struct ata_port_info piix_port_info[] = { [ich_pata_100] = { - .sht = &piix_sht, .flags = PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x06, /* mwdma1-2 */ @@ -575,7 +600,6 @@ static struct ata_port_info piix_port_info[] = { [ich5_sata] = { - .sht = &piix_sht, .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ @@ -585,8 +609,7 @@ static struct ata_port_info piix_port_info[] = { [ich6_sata] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR, + .flags = PIIX_SATA_FLAGS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -595,9 +618,7 @@ static struct ata_port_info piix_port_info[] = { [ich6_sata_ahci] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -606,9 +627,7 @@ static struct ata_port_info piix_port_info[] = { [ich6m_sata_ahci] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -617,9 +636,8 @@ static struct ata_port_info piix_port_info[] = { [ich8_sata_ahci] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | + PIIX_FLAG_SIDPR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -628,9 +646,8 @@ static struct ata_port_info piix_port_info[] = { [ich8_2port_sata] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | + PIIX_FLAG_SIDPR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -639,9 +656,7 @@ static struct ata_port_info piix_port_info[] = { [tolapai_sata_ahci] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -650,9 +665,8 @@ static struct ata_port_info piix_port_info[] = { [ich8m_apple_sata_ahci] = { - .sht = &piix_sht, - .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | - PIIX_FLAG_AHCI, + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_AHCI | + PIIX_FLAG_SIDPR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = ATA_UDMA6, @@ -1001,6 +1015,180 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev) do_pata_set_dmamode(ap, adev, 1); } +/* + * Serial ATA Index/Data Pair Superset Registers access + * + * Beginning from ICH8, there's a sane way to access SCRs using index + * and data register pair located at BAR5. This creates an + * interesting problem of mapping two SCRs to one port. + * + * Although they have separate SCRs, the master and slave aren't + * independent enough to be treated as separate links - e.g. softreset + * resets both. Also, there's no protocol defined for hard resetting + * singled device sharing the virtual port (no defined way to acquire + * device signature). This is worked around by merging the SCR values + * into one sensible value and requesting follow-up SRST after + * hardreset. + * + * SCR merging is perfomed in nibbles which is the unit contents in + * SCRs are organized. If two values are equal, the value is used. + * When they differ, merge table which lists precedence of possible + * values is consulted and the first match or the last entry when + * nothing matches is used. When there's no merge table for the + * specific nibble, value from the first port is used. + */ +static const int piix_sidx_map[] = { + [SCR_STATUS] = 0, + [SCR_ERROR] = 2, + [SCR_CONTROL] = 1, +}; + +static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg) +{ + struct ata_port *ap = dev->link->ap; + struct piix_host_priv *hpriv = ap->host->private_data; + + iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg], + hpriv->sidpr + PIIX_SIDPR_IDX); +} + +static int piix_sidpr_read(struct ata_device *dev, unsigned int reg) +{ + struct piix_host_priv *hpriv = dev->link->ap->host->private_data; + + piix_sidpr_sel(dev, reg); + return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); +} + +static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val) +{ + struct piix_host_priv *hpriv = dev->link->ap->host->private_data; + + piix_sidpr_sel(dev, reg); + iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); +} + +u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl) +{ + u32 val = 0; + int i, mi; + + for (i = 0, mi = 0; i < 32 / 4; i++) { + u8 c0 = (val0 >> (i * 4)) & 0xf; + u8 c1 = (val1 >> (i * 4)) & 0xf; + u8 merged = c0; + const int *cur; + + /* if no merge preference, assume the first value */ + cur = merge_tbl[mi]; + if (!cur) + goto done; + mi++; + + /* if two values equal, use it */ + if (c0 == c1) + goto done; + + /* choose the first match or the last from the merge table */ + while (*cur != -1) { + if (c0 == *cur || c1 == *cur) + break; + cur++; + } + if (*cur == -1) + cur--; + merged = *cur; + done: + val |= merged << (i * 4); + } + + return val; +} + +static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val) +{ + const int * const sstatus_merge_tbl[] = { + /* DET */ (const int []){ 1, 3, 0, 4, 3, -1 }, + /* SPD */ (const int []){ 2, 1, 0, -1 }, + /* IPM */ (const int []){ 6, 2, 1, 0, -1 }, + NULL, + }; + const int * const scontrol_merge_tbl[] = { + /* DET */ (const int []){ 1, 0, 4, 0, -1 }, + /* SPD */ (const int []){ 0, 2, 1, 0, -1 }, + /* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 }, + NULL, + }; + u32 v0, v1; + + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + + if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) { + *val = piix_sidpr_read(&ap->link.device[0], reg); + return 0; + } + + v0 = piix_sidpr_read(&ap->link.device[0], reg); + v1 = piix_sidpr_read(&ap->link.device[1], reg); + + switch (reg) { + case SCR_STATUS: + *val = piix_merge_scr(v0, v1, sstatus_merge_tbl); + break; + case SCR_ERROR: + *val = v0 | v1; + break; + case SCR_CONTROL: + *val = piix_merge_scr(v0, v1, scontrol_merge_tbl); + break; + } + + return 0; +} + +static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) +{ + if (reg >= ARRAY_SIZE(piix_sidx_map)) + return -EINVAL; + + piix_sidpr_write(&ap->link.device[0], reg, val); + + if (ap->flags & ATA_FLAG_SLAVE_POSS) + piix_sidpr_write(&ap->link.device[1], reg, val); + + return 0; +} + +static int piix_sidpr_hardreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context); + int rc; + + /* do hardreset */ + rc = sata_link_hardreset(link, timing, deadline); + if (rc) { + ata_link_printk(link, KERN_ERR, + "COMRESET failed (errno=%d)\n", rc); + return rc; + } + + /* TODO: phy layer with polling, timeouts, etc. */ + if (ata_link_offline(link)) { + *class = ATA_DEV_NONE; + return 0; + } + + return -EAGAIN; +} + +static void piix_sidpr_error_handler(struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, + piix_sidpr_hardreset, ata_std_postreset); +} + #ifdef CONFIG_PM static int piix_broken_suspend(void) { @@ -1034,6 +1222,13 @@ static int piix_broken_suspend(void) }, }, { + .ident = "TECRA M6", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M6"), + }, + }, + { .ident = "TECRA M7", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), @@ -1048,6 +1243,13 @@ static int piix_broken_suspend(void) }, }, { + .ident = "Satellite R20", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite R20"), + }, + }, + { .ident = "Satellite R25", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), @@ -1253,10 +1455,10 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) return no_piix_dma; } -static void __devinit piix_init_pcs(struct pci_dev *pdev, - struct ata_port_info *pinfo, +static void __devinit piix_init_pcs(struct ata_host *host, const struct piix_map_db *map_db) { + struct pci_dev *pdev = to_pci_dev(host->dev); u16 pcs, new_pcs; pci_read_config_word(pdev, ICH5_PCS, &pcs); @@ -1270,11 +1472,10 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev, } } -static void __devinit piix_init_sata_map(struct pci_dev *pdev, - struct ata_port_info *pinfo, - const struct piix_map_db *map_db) +static const int *__devinit piix_init_sata_map(struct pci_dev *pdev, + struct ata_port_info *pinfo, + const struct piix_map_db *map_db) { - struct piix_host_priv *hpriv = pinfo[0].private_data; const int *map; int i, invalid_map = 0; u8 map_value; @@ -1298,7 +1499,6 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, case IDE: WARN_ON((i & 1) || map[i + 1] != IDE); pinfo[i / 2] = piix_port_info[ich_pata_100]; - pinfo[i / 2].private_data = hpriv; i++; printk(" IDE IDE"); break; @@ -1316,7 +1516,33 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, dev_printk(KERN_ERR, &pdev->dev, "invalid MAP value %u\n", map_value); - hpriv->map = map; + return map; +} + +static void __devinit piix_init_sidpr(struct ata_host *host) +{ + struct pci_dev *pdev = to_pci_dev(host->dev); + struct piix_host_priv *hpriv = host->private_data; + int i; + + /* check for availability */ + for (i = 0; i < 4; i++) + if (hpriv->map[i] == IDE) + return; + + if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) + return; + + if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 || + pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN) + return; + + if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME)) + return; + + hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR]; + host->ports[0]->ops = &piix_sidpr_sata_ops; + host->ports[1]->ops = &piix_sidpr_sata_ops; } static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) @@ -1375,8 +1601,10 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct device *dev = &pdev->dev; struct ata_port_info port_info[2]; const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] }; - struct piix_host_priv *hpriv; unsigned long port_flags; + struct ata_host *host; + struct piix_host_priv *hpriv; + int rc; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, @@ -1386,17 +1614,31 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!in_module_init) return -ENODEV; + port_info[0] = piix_port_info[ent->driver_data]; + port_info[1] = piix_port_info[ent->driver_data]; + + port_flags = port_info[0].flags; + + /* enable device and prepare host */ + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + /* SATA map init can change port_info, do it before prepping host */ hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; - port_info[0] = piix_port_info[ent->driver_data]; - port_info[1] = piix_port_info[ent->driver_data]; - port_info[0].private_data = hpriv; - port_info[1].private_data = hpriv; + if (port_flags & ATA_FLAG_SATA) + hpriv->map = piix_init_sata_map(pdev, port_info, + piix_map_db_table[ent->driver_data]); - port_flags = port_info[0].flags; + rc = ata_pci_prepare_sff_host(pdev, ppi, &host); + if (rc) + return rc; + host->private_data = hpriv; + /* initialize controller */ if (port_flags & PIIX_FLAG_AHCI) { u8 tmp; pci_read_config_byte(pdev, PIIX_SCC, &tmp); @@ -1407,12 +1649,9 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } } - /* Initialize SATA map */ if (port_flags & ATA_FLAG_SATA) { - piix_init_sata_map(pdev, port_info, - piix_map_db_table[ent->driver_data]); - piix_init_pcs(pdev, port_info, - piix_map_db_table[ent->driver_data]); + piix_init_pcs(host, piix_map_db_table[ent->driver_data]); + piix_init_sidpr(host); } /* apply IOCFG bit18 quirk */ @@ -1431,12 +1670,14 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) /* This writes into the master table but it does not really matter for this errata as we will apply it to all the PIIX devices on the board */ - port_info[0].mwdma_mask = 0; - port_info[0].udma_mask = 0; - port_info[1].mwdma_mask = 0; - port_info[1].udma_mask = 0; + host->ports[0]->mwdma_mask = 0; + host->ports[0]->udma_mask = 0; + host->ports[1]->mwdma_mask = 0; + host->ports[1]->udma_mask = 0; } - return ata_pci_init_one(pdev, ppi); + + pci_set_master(pdev); + return ata_pci_activate_sff_host(host, ata_interrupt, &piix_sht); } static int __init piix_init(void) diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 7bf4befd96bc..9e8ec19260af 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -442,40 +442,77 @@ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf) } /** + * ata_acpi_gtm_xfermode - determine xfermode from GTM parameter + * @dev: target device + * @gtm: GTM parameter to use + * + * Determine xfermask for @dev from @gtm. + * + * LOCKING: + * None. + * + * RETURNS: + * Determined xfermask. + */ +unsigned long ata_acpi_gtm_xfermask(struct ata_device *dev, + const struct ata_acpi_gtm *gtm) +{ + unsigned long xfer_mask = 0; + unsigned int type; + int unit; + u8 mode; + + /* we always use the 0 slot for crap hardware */ + unit = dev->devno; + if (!(gtm->flags & 0x10)) + unit = 0; + + /* PIO */ + mode = ata_timing_cycle2mode(ATA_SHIFT_PIO, gtm->drive[unit].pio); + xfer_mask |= ata_xfer_mode2mask(mode); + + /* See if we have MWDMA or UDMA data. We don't bother with + * MWDMA if UDMA is available as this means the BIOS set UDMA + * and our error changedown if it works is UDMA to PIO anyway. + */ + if (!(gtm->flags & (1 << (2 * unit)))) + type = ATA_SHIFT_MWDMA; + else + type = ATA_SHIFT_UDMA; + + mode = ata_timing_cycle2mode(type, gtm->drive[unit].dma); + xfer_mask |= ata_xfer_mode2mask(mode); + + return xfer_mask; +} +EXPORT_SYMBOL_GPL(ata_acpi_gtm_xfermask); + +/** * ata_acpi_cbl_80wire - Check for 80 wire cable * @ap: Port to check + * @gtm: GTM data to use * - * Return 1 if the ACPI mode data for this port indicates the BIOS selected - * an 80wire mode. + * Return 1 if the @gtm indicates the BIOS selected an 80wire mode. */ - -int ata_acpi_cbl_80wire(struct ata_port *ap) +int ata_acpi_cbl_80wire(struct ata_port *ap, const struct ata_acpi_gtm *gtm) { - const struct ata_acpi_gtm *gtm = ata_acpi_init_gtm(ap); - int valid = 0; + struct ata_device *dev; - if (!gtm) - return 0; + ata_link_for_each_dev(dev, &ap->link) { + unsigned long xfer_mask, udma_mask; + + if (!ata_dev_enabled(dev)) + continue; + + xfer_mask = ata_acpi_gtm_xfermask(dev, gtm); + ata_unpack_xfermask(xfer_mask, NULL, NULL, &udma_mask); + + if (udma_mask & ~ATA_UDMA_MASK_40C) + return 1; + } - /* Split timing, DMA enabled */ - if ((gtm->flags & 0x11) == 0x11 && gtm->drive[0].dma < 55) - valid |= 1; - if ((gtm->flags & 0x14) == 0x14 && gtm->drive[1].dma < 55) - valid |= 2; - /* Shared timing, DMA enabled */ - if ((gtm->flags & 0x11) == 0x01 && gtm->drive[0].dma < 55) - valid |= 1; - if ((gtm->flags & 0x14) == 0x04 && gtm->drive[0].dma < 55) - valid |= 2; - - /* Drive check */ - if ((valid & 1) && ata_dev_enabled(&ap->link.device[0])) - return 1; - if ((valid & 2) && ata_dev_enabled(&ap->link.device[1])) - return 1; return 0; } - EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); static void ata_acpi_gtf_to_tf(struct ata_device *dev, @@ -776,6 +813,36 @@ void ata_acpi_on_resume(struct ata_port *ap) } /** + * ata_acpi_set_state - set the port power state + * @ap: target ATA port + * @state: state, on/off + * + * This function executes the _PS0/_PS3 ACPI method to set the power state. + * ACPI spec requires _PS0 when IDE power on and _PS3 when power off + */ +void ata_acpi_set_state(struct ata_port *ap, pm_message_t state) +{ + struct ata_device *dev; + + if (!ap->acpi_handle || (ap->flags & ATA_FLAG_ACPI_SATA)) + return; + + /* channel first and then drives for power on and vica versa + for power off */ + if (state.event == PM_EVENT_ON) + acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D0); + + ata_link_for_each_dev(dev, &ap->link) { + if (dev->acpi_handle && ata_dev_enabled(dev)) + acpi_bus_set_power(dev->acpi_handle, + state.event == PM_EVENT_ON ? + ACPI_STATE_D0 : ACPI_STATE_D3); + } + if (state.event != PM_EVENT_ON) + acpi_bus_set_power(ap->acpi_handle, ACPI_STATE_D3); +} + +/** * ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration * @dev: target ATA device * diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6380726f7538..bdbd55af7022 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -119,6 +119,10 @@ int libata_noacpi = 0; module_param_named(noacpi, libata_noacpi, int, 0444); MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set"); +int libata_allow_tpm = 0; +module_param_named(allow_tpm, libata_allow_tpm, int, 0444); +MODULE_PARM_DESC(allow_tpm, "Permit the use of TPM commands"); + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); @@ -450,9 +454,9 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, * RETURNS: * Packed xfer_mask. */ -static unsigned int ata_pack_xfermask(unsigned int pio_mask, - unsigned int mwdma_mask, - unsigned int udma_mask) +unsigned long ata_pack_xfermask(unsigned long pio_mask, + unsigned long mwdma_mask, + unsigned long udma_mask) { return ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | @@ -469,10 +473,8 @@ static unsigned int ata_pack_xfermask(unsigned int pio_mask, * Unpack @xfer_mask into @pio_mask, @mwdma_mask and @udma_mask. * Any NULL distination masks will be ignored. */ -static void ata_unpack_xfermask(unsigned int xfer_mask, - unsigned int *pio_mask, - unsigned int *mwdma_mask, - unsigned int *udma_mask) +void ata_unpack_xfermask(unsigned long xfer_mask, unsigned long *pio_mask, + unsigned long *mwdma_mask, unsigned long *udma_mask) { if (pio_mask) *pio_mask = (xfer_mask & ATA_MASK_PIO) >> ATA_SHIFT_PIO; @@ -486,9 +488,9 @@ static const struct ata_xfer_ent { int shift, bits; u8 base; } ata_xfer_tbl[] = { - { ATA_SHIFT_PIO, ATA_BITS_PIO, XFER_PIO_0 }, - { ATA_SHIFT_MWDMA, ATA_BITS_MWDMA, XFER_MW_DMA_0 }, - { ATA_SHIFT_UDMA, ATA_BITS_UDMA, XFER_UDMA_0 }, + { ATA_SHIFT_PIO, ATA_NR_PIO_MODES, XFER_PIO_0 }, + { ATA_SHIFT_MWDMA, ATA_NR_MWDMA_MODES, XFER_MW_DMA_0 }, + { ATA_SHIFT_UDMA, ATA_NR_UDMA_MODES, XFER_UDMA_0 }, { -1, }, }; @@ -503,9 +505,9 @@ static const struct ata_xfer_ent { * None. * * RETURNS: - * Matching XFER_* value, 0 if no match found. + * Matching XFER_* value, 0xff if no match found. */ -static u8 ata_xfer_mask2mode(unsigned int xfer_mask) +u8 ata_xfer_mask2mode(unsigned long xfer_mask) { int highbit = fls(xfer_mask) - 1; const struct ata_xfer_ent *ent; @@ -513,7 +515,7 @@ static u8 ata_xfer_mask2mode(unsigned int xfer_mask) for (ent = ata_xfer_tbl; ent->shift >= 0; ent++) if (highbit >= ent->shift && highbit < ent->shift + ent->bits) return ent->base + highbit - ent->shift; - return 0; + return 0xff; } /** @@ -528,13 +530,14 @@ static u8 ata_xfer_mask2mode(unsigned int xfer_mask) * RETURNS: * Matching xfer_mask, 0 if no match found. */ -static unsigned int ata_xfer_mode2mask(u8 xfer_mode) +unsigned long ata_xfer_mode2mask(u8 xfer_mode) { const struct ata_xfer_ent *ent; for (ent = ata_xfer_tbl; ent->shift >= 0; ent++) if (xfer_mode >= ent->base && xfer_mode < ent->base + ent->bits) - return 1 << (ent->shift + xfer_mode - ent->base); + return ((2 << (ent->shift + xfer_mode - ent->base)) - 1) + & ~((1 << ent->shift) - 1); return 0; } @@ -550,7 +553,7 @@ static unsigned int ata_xfer_mode2mask(u8 xfer_mode) * RETURNS: * Matching xfer_shift, -1 if no match found. */ -static int ata_xfer_mode2shift(unsigned int xfer_mode) +int ata_xfer_mode2shift(unsigned long xfer_mode) { const struct ata_xfer_ent *ent; @@ -574,7 +577,7 @@ static int ata_xfer_mode2shift(unsigned int xfer_mode) * Constant C string representing highest speed listed in * @mode_mask, or the constant C string "<n/a>". */ -static const char *ata_mode_string(unsigned int xfer_mask) +const char *ata_mode_string(unsigned long xfer_mask) { static const char * const xfer_mode_str[] = { "PIO0", @@ -947,8 +950,8 @@ unsigned int ata_dev_try_classify(struct ata_device *dev, int present, if (r_err) *r_err = err; - /* see if device passed diags: if master then continue and warn later */ - if (err == 0 && dev->devno == 0) + /* see if device passed diags: continue and warn later */ + if (err == 0) /* diagnostic fail : do nothing _YET_ */ dev->horkage |= ATA_HORKAGE_DIAGNOSTIC; else if (err == 1) @@ -1286,48 +1289,6 @@ static int ata_hpa_resize(struct ata_device *dev) } /** - * ata_id_to_dma_mode - Identify DMA mode from id block - * @dev: device to identify - * @unknown: mode to assume if we cannot tell - * - * Set up the timing values for the device based upon the identify - * reported values for the DMA mode. This function is used by drivers - * which rely upon firmware configured modes, but wish to report the - * mode correctly when possible. - * - * In addition we emit similarly formatted messages to the default - * ata_dev_set_mode handler, in order to provide consistency of - * presentation. - */ - -void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown) -{ - unsigned int mask; - u8 mode; - - /* Pack the DMA modes */ - mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA; - if (dev->id[53] & 0x04) - mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA; - - /* Select the mode in use */ - mode = ata_xfer_mask2mode(mask); - - if (mode != 0) { - ata_dev_printk(dev, KERN_INFO, "configured for %s\n", - ata_mode_string(mask)); - } else { - /* SWDMA perhaps ? */ - mode = unknown; - ata_dev_printk(dev, KERN_INFO, "configured for DMA\n"); - } - - /* Configure the device reporting */ - dev->xfer_mode = mode; - dev->xfer_shift = ata_xfer_mode2shift(mode); -} - -/** * ata_noop_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select @@ -1464,9 +1425,9 @@ static inline void ata_dump_id(const u16 *id) * RETURNS: * Computed xfermask */ -static unsigned int ata_id_xfermask(const u16 *id) +unsigned long ata_id_xfermask(const u16 *id) { - unsigned int pio_mask, mwdma_mask, udma_mask; + unsigned long pio_mask, mwdma_mask, udma_mask; /* Usual case. Word 53 indicates word 64 is valid */ if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { @@ -1519,7 +1480,7 @@ static unsigned int ata_id_xfermask(const u16 *id) } /** - * ata_port_queue_task - Queue port_task + * ata_pio_queue_task - Queue port_task * @ap: The ata_port to queue port_task for * @fn: workqueue function to be scheduled * @data: data for @fn to use @@ -1531,16 +1492,15 @@ static unsigned int ata_id_xfermask(const u16 *id) * one task is active at any given time. * * libata core layer takes care of synchronization between - * port_task and EH. ata_port_queue_task() may be ignored for EH + * port_task and EH. ata_pio_queue_task() may be ignored for EH * synchronization. * * LOCKING: * Inherited from caller. */ -void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data, - unsigned long delay) +static void ata_pio_queue_task(struct ata_port *ap, void *data, + unsigned long delay) { - PREPARE_DELAYED_WORK(&ap->port_task, fn); ap->port_task_data = data; /* may fail if ata_port_flush_task() in progress */ @@ -2090,7 +2050,7 @@ int ata_dev_configure(struct ata_device *dev) struct ata_eh_context *ehc = &dev->link->eh_context; int print_info = ehc->i.flags & ATA_EHI_PRINTINFO; const u16 *id = dev->id; - unsigned int xfer_mask; + unsigned long xfer_mask; char revbuf[7]; /* XYZ-99\0 */ char fwrevbuf[ATA_ID_FW_REV_LEN+1]; char modelbuf[ATA_ID_PROD_LEN+1]; @@ -2161,8 +2121,14 @@ int ata_dev_configure(struct ata_device *dev) "supports DRM functions and may " "not be fully accessable.\n"); snprintf(revbuf, 7, "CFA"); - } else + } else { snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id)); + /* Warn the user if the device has TPM extensions */ + if (ata_id_has_tpm(id)) + ata_dev_printk(dev, KERN_WARNING, + "supports DRM functions and may " + "not be fully accessable.\n"); + } dev->n_sectors = ata_id_n_sectors(id); @@ -2295,19 +2261,8 @@ int ata_dev_configure(struct ata_device *dev) dev->flags |= ATA_DFLAG_DIPM; } - if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { - /* Let the user know. We don't want to disallow opens for - rescue purposes, or in case the vendor is just a blithering - idiot */ - if (print_info) { - ata_dev_printk(dev, KERN_WARNING, -"Drive reports diagnostics failure. This may indicate a drive\n"); - ata_dev_printk(dev, KERN_WARNING, -"fault or invalid emulation. Contact drive vendor for information.\n"); - } - } - - /* limit bridge transfers to udma5, 200 sectors */ + /* Limit PATA drive on SATA cable bridge transfers to udma5, + 200 sectors */ if (ata_dev_knobble(dev)) { if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, @@ -2336,6 +2291,21 @@ int ata_dev_configure(struct ata_device *dev) if (ap->ops->dev_config) ap->ops->dev_config(dev); + if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + /* Let the user know. We don't want to disallow opens for + rescue purposes, or in case the vendor is just a blithering + idiot. Do this after the dev_config call as some controllers + with buggy firmware may want to avoid reporting false device + bugs */ + + if (print_info) { + ata_dev_printk(dev, KERN_WARNING, +"Drive reports diagnostics failure. This may indicate a drive\n"); + ata_dev_printk(dev, KERN_WARNING, +"fault or invalid emulation. Contact drive vendor for information.\n"); + } + } + if (ata_msg_probe(ap)) ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n", __FUNCTION__, ata_chk_status(ap)); @@ -2387,6 +2357,18 @@ int ata_cable_unknown(struct ata_port *ap) } /** + * ata_cable_ignore - return ignored PATA cable. + * @ap: port + * + * Helper method for drivers which don't use cable type to limit + * transfer mode. + */ +int ata_cable_ignore(struct ata_port *ap) +{ + return ATA_CBL_PATA_IGN; +} + +/** * ata_cable_sata - return SATA cable type * @ap: port * @@ -2781,38 +2763,33 @@ int sata_set_spd(struct ata_link *link) */ static const struct ata_timing ata_timing[] = { +/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, + { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, - { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, - { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, - { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, - { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, - { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 }, - { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, - { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, - { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 }, /* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */ - - { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, - { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, - { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, - - { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, - { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, - { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, - - { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 }, - { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 }, - { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, - { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, - - { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, - { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, - { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, - -/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, { 0xFF } }; @@ -2845,14 +2822,16 @@ void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b, if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma); } -static const struct ata_timing *ata_timing_find_mode(unsigned short speed) +const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) { - const struct ata_timing *t; + const struct ata_timing *t = ata_timing; + + while (xfer_mode > t->mode) + t++; - for (t = ata_timing; t->mode != speed; t++) - if (t->mode == 0xFF) - return NULL; - return t; + if (xfer_mode == t->mode) + return t; + return NULL; } int ata_timing_compute(struct ata_device *adev, unsigned short speed, @@ -2927,6 +2906,57 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, } /** + * ata_timing_cycle2mode - find xfer mode for the specified cycle duration + * @xfer_shift: ATA_SHIFT_* value for transfer type to examine. + * @cycle: cycle duration in ns + * + * Return matching xfer mode for @cycle. The returned mode is of + * the transfer type specified by @xfer_shift. If @cycle is too + * slow for @xfer_shift, 0xff is returned. If @cycle is faster + * than the fastest known mode, the fasted mode is returned. + * + * LOCKING: + * None. + * + * RETURNS: + * Matching xfer_mode, 0xff if no match found. + */ +u8 ata_timing_cycle2mode(unsigned int xfer_shift, int cycle) +{ + u8 base_mode = 0xff, last_mode = 0xff; + const struct ata_xfer_ent *ent; + const struct ata_timing *t; + + for (ent = ata_xfer_tbl; ent->shift >= 0; ent++) + if (ent->shift == xfer_shift) + base_mode = ent->base; + + for (t = ata_timing_find_mode(base_mode); + t && ata_xfer_mode2shift(t->mode) == xfer_shift; t++) { + unsigned short this_cycle; + + switch (xfer_shift) { + case ATA_SHIFT_PIO: + case ATA_SHIFT_MWDMA: + this_cycle = t->cycle; + break; + case ATA_SHIFT_UDMA: + this_cycle = t->udma; + break; + default: + return 0xff; + } + + if (cycle > this_cycle) + break; + + last_mode = t->mode; + } + + return last_mode; +} + +/** * ata_down_xfermask_limit - adjust dev xfer masks downward * @dev: Device to adjust xfer masks * @sel: ATA_DNXFER_* selector @@ -2944,8 +2974,8 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) { char buf[32]; - unsigned int orig_mask, xfer_mask; - unsigned int pio_mask, mwdma_mask, udma_mask; + unsigned long orig_mask, xfer_mask; + unsigned long pio_mask, mwdma_mask, udma_mask; int quiet, highbit; quiet = !!(sel & ATA_DNXFER_QUIET); @@ -3039,7 +3069,7 @@ static int ata_dev_set_mode(struct ata_device *dev) /* Early MWDMA devices do DMA but don't allow DMA mode setting. Don't fail an MWDMA0 set IFF the device indicates it is in MWDMA0 */ - if (dev->xfer_shift == ATA_SHIFT_MWDMA && + if (dev->xfer_shift == ATA_SHIFT_MWDMA && dev->dma_mode == XFER_MW_DMA_0 && (dev->id[63] >> 8) & 1) err_mask &= ~AC_ERR_DEV; @@ -3089,7 +3119,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 1: calculate xfer_mask */ ata_link_for_each_dev(dev, link) { - unsigned int pio_mask, dma_mask; + unsigned long pio_mask, dma_mask; unsigned int mode_mask; if (!ata_dev_enabled(dev)) @@ -3115,7 +3145,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) dev->dma_mode = ata_xfer_mask2mode(dma_mask); found = 1; - if (dev->dma_mode) + if (dev->dma_mode != 0xff) used_dma = 1; } if (!found) @@ -3126,7 +3156,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) if (!ata_dev_enabled(dev)) continue; - if (!dev->pio_mode) { + if (dev->pio_mode == 0xff) { ata_dev_printk(dev, KERN_WARNING, "no PIO support\n"); rc = -EINVAL; goto out; @@ -3140,7 +3170,7 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) /* step 3: set host DMA timings */ ata_link_for_each_dev(dev, link) { - if (!ata_dev_enabled(dev) || !dev->dma_mode) + if (!ata_dev_enabled(dev) || dev->dma_mode == 0xff) continue; dev->xfer_mode = dev->dma_mode; @@ -3173,31 +3203,6 @@ int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) } /** - * ata_set_mode - Program timings and issue SET FEATURES - XFER - * @link: link on which timings will be programmed - * @r_failed_dev: out paramter for failed device - * - * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If - * ata_set_mode() fails, pointer to the failing device is - * returned in @r_failed_dev. - * - * LOCKING: - * PCI/etc. bus probe sem. - * - * RETURNS: - * 0 on success, negative errno otherwise - */ -int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) -{ - struct ata_port *ap = link->ap; - - /* has private set_mode? */ - if (ap->ops->set_mode) - return ap->ops->set_mode(link, r_failed_dev); - return ata_do_set_mode(link, r_failed_dev); -} - -/** * ata_tf_to_host - issue ATA taskfile to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set @@ -4363,7 +4368,14 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev) tf.feature = SETFEATURES_XFER; tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_POLLING; tf.protocol = ATA_PROT_NODATA; - tf.nsect = dev->xfer_mode; + /* If we are using IORDY we must send the mode setting command */ + if (ata_pio_need_iordy(dev)) + tf.nsect = dev->xfer_mode; + /* If the device has IORDY and the controller does not - turn it off */ + else if (ata_id_has_iordy(dev->id)) + tf.nsect = 0x01; + else /* In the ancient relic department - skip all of this */ + return 0; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); @@ -4462,17 +4474,13 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, void ata_sg_clean(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scatterlist *sg = qc->__sg; + struct scatterlist *sg = qc->sg; int dir = qc->dma_dir; void *pad_buf = NULL; - WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP)); WARN_ON(sg == NULL); - if (qc->flags & ATA_QCFLAG_SINGLE) - WARN_ON(qc->n_elem > 1); - - VPRINTK("unmapping %u sg elements\n", qc->n_elem); + VPRINTK("unmapping %u sg elements\n", qc->mapped_n_elem); /* if we padded the buffer out to 32-bit bound, and data * xfer direction is from-device, we must copy from the @@ -4481,31 +4489,20 @@ void ata_sg_clean(struct ata_queued_cmd *qc) if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE)) pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); - if (qc->flags & ATA_QCFLAG_SG) { - if (qc->n_elem) - dma_unmap_sg(ap->dev, sg, qc->n_elem, dir); - /* restore last sg */ - sg_last(sg, qc->orig_n_elem)->length += qc->pad_len; - if (pad_buf) { - struct scatterlist *psg = &qc->pad_sgent; - void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); - memcpy(addr + psg->offset, pad_buf, qc->pad_len); - kunmap_atomic(addr, KM_IRQ0); - } - } else { - if (qc->n_elem) - dma_unmap_single(ap->dev, - sg_dma_address(&sg[0]), sg_dma_len(&sg[0]), - dir); - /* restore sg */ - sg->length += qc->pad_len; - if (pad_buf) - memcpy(qc->buf_virt + sg->length - qc->pad_len, - pad_buf, qc->pad_len); + if (qc->mapped_n_elem) + dma_unmap_sg(ap->dev, sg, qc->mapped_n_elem, dir); + /* restore last sg */ + if (qc->last_sg) + *qc->last_sg = qc->saved_last_sg; + if (pad_buf) { + struct scatterlist *psg = &qc->extra_sg[1]; + void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); + memcpy(addr + psg->offset, pad_buf, qc->pad_len); + kunmap_atomic(addr, KM_IRQ0); } qc->flags &= ~ATA_QCFLAG_DMAMAP; - qc->__sg = NULL; + qc->sg = NULL; } /** @@ -4523,13 +4520,10 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int idx; + unsigned int si, pi; - WARN_ON(qc->__sg == NULL); - WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); - - idx = 0; - ata_for_each_sg(sg, qc) { + pi = 0; + for_each_sg(qc->sg, sg, qc->n_elem, si) { u32 addr, offset; u32 sg_len, len; @@ -4546,18 +4540,17 @@ static void ata_fill_sg(struct ata_queued_cmd *qc) if ((offset + sg_len) > 0x10000) len = 0x10000 - offset; - ap->prd[idx].addr = cpu_to_le32(addr); - ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); + ap->prd[pi].addr = cpu_to_le32(addr); + ap->prd[pi].flags_len = cpu_to_le32(len & 0xffff); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); - idx++; + pi++; sg_len -= len; addr += len; } } - if (idx) - ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } /** @@ -4577,13 +4570,10 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int idx; - - WARN_ON(qc->__sg == NULL); - WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + unsigned int si, pi; - idx = 0; - ata_for_each_sg(sg, qc) { + pi = 0; + for_each_sg(qc->sg, sg, qc->n_elem, si) { u32 addr, offset; u32 sg_len, len, blen; @@ -4601,25 +4591,24 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) len = 0x10000 - offset; blen = len & 0xffff; - ap->prd[idx].addr = cpu_to_le32(addr); + ap->prd[pi].addr = cpu_to_le32(addr); if (blen == 0) { /* Some PATA chipsets like the CS5530 can't cope with 0x0000 meaning 64K as the spec says */ - ap->prd[idx].flags_len = cpu_to_le32(0x8000); + ap->prd[pi].flags_len = cpu_to_le32(0x8000); blen = 0x8000; - ap->prd[++idx].addr = cpu_to_le32(addr + 0x8000); + ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000); } - ap->prd[idx].flags_len = cpu_to_le32(blen); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); + ap->prd[pi].flags_len = cpu_to_le32(blen); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len); - idx++; + pi++; sg_len -= len; addr += len; } } - if (idx) - ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + ap->prd[pi - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } /** @@ -4669,8 +4658,8 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc) */ static int atapi_qc_may_overflow(struct ata_queued_cmd *qc) { - if (qc->tf.protocol != ATA_PROT_ATAPI && - qc->tf.protocol != ATA_PROT_ATAPI_DMA) + if (qc->tf.protocol != ATAPI_PROT_PIO && + qc->tf.protocol != ATAPI_PROT_DMA) return 0; if (qc->tf.flags & ATA_TFLAG_WRITE) @@ -4756,33 +4745,6 @@ void ata_dumb_qc_prep(struct ata_queued_cmd *qc) void ata_noop_qc_prep(struct ata_queued_cmd *qc) { } /** - * ata_sg_init_one - Associate command with memory buffer - * @qc: Command to be associated - * @buf: Memory buffer - * @buflen: Length of memory buffer, in bytes. - * - * Initialize the data-related elements of queued_cmd @qc - * to point to a single memory buffer, @buf of byte length @buflen. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) -{ - qc->flags |= ATA_QCFLAG_SINGLE; - - qc->__sg = &qc->sgent; - qc->n_elem = 1; - qc->orig_n_elem = 1; - qc->buf_virt = buf; - qc->nbytes = buflen; - qc->cursg = qc->__sg; - - sg_init_one(&qc->sgent, buf, buflen); -} - -/** * ata_sg_init - Associate command with scatter-gather table. * @qc: Command to be associated * @sg: Scatter-gather table. @@ -4795,84 +4757,103 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) * LOCKING: * spin_lock_irqsave(host lock) */ - void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem) { - qc->flags |= ATA_QCFLAG_SG; - qc->__sg = sg; + qc->sg = sg; qc->n_elem = n_elem; - qc->orig_n_elem = n_elem; - qc->cursg = qc->__sg; + qc->cursg = qc->sg; } -/** - * ata_sg_setup_one - DMA-map the memory buffer associated with a command. - * @qc: Command with memory buffer to be mapped. - * - * DMA-map the memory buffer associated with queued_cmd @qc. - * - * LOCKING: - * spin_lock_irqsave(host lock) - * - * RETURNS: - * Zero on success, negative on error. - */ - -static int ata_sg_setup_one(struct ata_queued_cmd *qc) +static unsigned int ata_sg_setup_extra(struct ata_queued_cmd *qc, + unsigned int *n_elem_extra, + unsigned int *nbytes_extra) { struct ata_port *ap = qc->ap; - int dir = qc->dma_dir; - struct scatterlist *sg = qc->__sg; - dma_addr_t dma_address; - int trim_sg = 0; + unsigned int n_elem = qc->n_elem; + struct scatterlist *lsg, *copy_lsg = NULL, *tsg = NULL, *esg = NULL; + + *n_elem_extra = 0; + *nbytes_extra = 0; + + /* needs padding? */ + qc->pad_len = qc->nbytes & 3; + + if (likely(!qc->pad_len)) + return n_elem; + + /* locate last sg and save it */ + lsg = sg_last(qc->sg, n_elem); + qc->last_sg = lsg; + qc->saved_last_sg = *lsg; + + sg_init_table(qc->extra_sg, ARRAY_SIZE(qc->extra_sg)); - /* we must lengthen transfers to end on a 32-bit boundary */ - qc->pad_len = sg->length & 3; if (qc->pad_len) { + struct scatterlist *psg = &qc->extra_sg[1]; void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); - struct scatterlist *psg = &qc->pad_sgent; + unsigned int offset; WARN_ON(qc->dev->class != ATA_DEV_ATAPI); memset(pad_buf, 0, ATA_DMA_PAD_SZ); - if (qc->tf.flags & ATA_TFLAG_WRITE) - memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len, - qc->pad_len); + /* psg->page/offset are used to copy to-be-written + * data in this function or read data in ata_sg_clean. + */ + offset = lsg->offset + lsg->length - qc->pad_len; + sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT), + qc->pad_len, offset_in_page(offset)); + + if (qc->tf.flags & ATA_TFLAG_WRITE) { + void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); + memcpy(pad_buf, addr + psg->offset, qc->pad_len); + kunmap_atomic(addr, KM_IRQ0); + } sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ); sg_dma_len(psg) = ATA_DMA_PAD_SZ; - /* trim sg */ - sg->length -= qc->pad_len; - if (sg->length == 0) - trim_sg = 1; - DPRINTK("padding done, sg->length=%u pad_len=%u\n", - sg->length, qc->pad_len); - } + /* Trim the last sg entry and chain the original and + * padding sg lists. + * + * Because chaining consumes one sg entry, one extra + * sg entry is allocated and the last sg entry is + * copied to it if the length isn't zero after padded + * amount is removed. + * + * If the last sg entry is completely replaced by + * padding sg entry, the first sg entry is skipped + * while chaining. + */ + lsg->length -= qc->pad_len; + if (lsg->length) { + copy_lsg = &qc->extra_sg[0]; + tsg = &qc->extra_sg[0]; + } else { + n_elem--; + tsg = &qc->extra_sg[1]; + } - if (trim_sg) { - qc->n_elem--; - goto skip_map; - } + esg = &qc->extra_sg[1]; - dma_address = dma_map_single(ap->dev, qc->buf_virt, - sg->length, dir); - if (dma_mapping_error(dma_address)) { - /* restore sg */ - sg->length += qc->pad_len; - return -1; + (*n_elem_extra)++; + (*nbytes_extra) += 4 - qc->pad_len; } - sg_dma_address(sg) = dma_address; - sg_dma_len(sg) = sg->length; + if (copy_lsg) + sg_set_page(copy_lsg, sg_page(lsg), lsg->length, lsg->offset); -skip_map: - DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg), - qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); + sg_chain(lsg, 1, tsg); + sg_mark_end(esg); - return 0; + /* sglist can't start with chaining sg entry, fast forward */ + if (qc->sg == lsg) { + qc->sg = tsg; + qc->cursg = tsg; + } + + return n_elem; } /** @@ -4888,75 +4869,30 @@ skip_map: * Zero on success, negative on error. * */ - static int ata_sg_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scatterlist *sg = qc->__sg; - struct scatterlist *lsg = sg_last(qc->__sg, qc->n_elem); - int n_elem, pre_n_elem, dir, trim_sg = 0; + unsigned int n_elem, n_elem_extra, nbytes_extra; VPRINTK("ENTER, ata%u\n", ap->print_id); - WARN_ON(!(qc->flags & ATA_QCFLAG_SG)); - /* we must lengthen transfers to end on a 32-bit boundary */ - qc->pad_len = lsg->length & 3; - if (qc->pad_len) { - void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); - struct scatterlist *psg = &qc->pad_sgent; - unsigned int offset; - - WARN_ON(qc->dev->class != ATA_DEV_ATAPI); + n_elem = ata_sg_setup_extra(qc, &n_elem_extra, &nbytes_extra); - memset(pad_buf, 0, ATA_DMA_PAD_SZ); - - /* - * psg->page/offset are used to copy to-be-written - * data in this function or read data in ata_sg_clean. - */ - offset = lsg->offset + lsg->length - qc->pad_len; - sg_init_table(psg, 1); - sg_set_page(psg, nth_page(sg_page(lsg), offset >> PAGE_SHIFT), - qc->pad_len, offset_in_page(offset)); - - if (qc->tf.flags & ATA_TFLAG_WRITE) { - void *addr = kmap_atomic(sg_page(psg), KM_IRQ0); - memcpy(pad_buf, addr + psg->offset, qc->pad_len); - kunmap_atomic(addr, KM_IRQ0); + if (n_elem) { + n_elem = dma_map_sg(ap->dev, qc->sg, n_elem, qc->dma_dir); + if (n_elem < 1) { + /* restore last sg */ + if (qc->last_sg) + *qc->last_sg = qc->saved_last_sg; + return -1; } - - sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ); - sg_dma_len(psg) = ATA_DMA_PAD_SZ; - /* trim last sg */ - lsg->length -= qc->pad_len; - if (lsg->length == 0) - trim_sg = 1; - - DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n", - qc->n_elem - 1, lsg->length, qc->pad_len); - } - - pre_n_elem = qc->n_elem; - if (trim_sg && pre_n_elem) - pre_n_elem--; - - if (!pre_n_elem) { - n_elem = 0; - goto skip_map; - } - - dir = qc->dma_dir; - n_elem = dma_map_sg(ap->dev, sg, pre_n_elem, dir); - if (n_elem < 1) { - /* restore last sg */ - lsg->length += qc->pad_len; - return -1; + DPRINTK("%d sg elements mapped\n", n_elem); } - DPRINTK("%d sg elements mapped\n", n_elem); - -skip_map: - qc->n_elem = n_elem; + qc->n_elem = qc->mapped_n_elem = n_elem; + qc->n_elem += n_elem_extra; + qc->nbytes += nbytes_extra; + qc->flags |= ATA_QCFLAG_DMAMAP; return 0; } @@ -4985,63 +4921,77 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words) /** * ata_data_xfer - Transfer data by PIO - * @adev: device to target + * @dev: device to target * @buf: data buffer * @buflen: buffer length - * @write_data: read/write + * @rw: read/write * * Transfer data from/to the device data register by PIO. * * LOCKING: * Inherited from caller. + * + * RETURNS: + * Bytes consumed. */ -void ata_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +unsigned int ata_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; + struct ata_port *ap = dev->link->ap; + void __iomem *data_addr = ap->ioaddr.data_addr; unsigned int words = buflen >> 1; /* Transfer multiple of 2 bytes */ - if (write_data) - iowrite16_rep(ap->ioaddr.data_addr, buf, words); + if (rw == READ) + ioread16_rep(data_addr, buf, words); else - ioread16_rep(ap->ioaddr.data_addr, buf, words); + iowrite16_rep(data_addr, buf, words); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { - u16 align_buf[1] = { 0 }; + __le16 align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (write_data) { - memcpy(align_buf, trailing_buf, 1); - iowrite16(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); - } else { - align_buf[0] = cpu_to_le16(ioread16(ap->ioaddr.data_addr)); + if (rw == READ) { + align_buf[0] = cpu_to_le16(ioread16(data_addr)); memcpy(trailing_buf, align_buf, 1); + } else { + memcpy(align_buf, trailing_buf, 1); + iowrite16(le16_to_cpu(align_buf[0]), data_addr); } + words++; } + + return words << 1; } /** * ata_data_xfer_noirq - Transfer data by PIO - * @adev: device to target + * @dev: device to target * @buf: data buffer * @buflen: buffer length - * @write_data: read/write + * @rw: read/write * * Transfer data from/to the device data register by PIO. Do the * transfer with interrupts disabled. * * LOCKING: * Inherited from caller. + * + * RETURNS: + * Bytes consumed. */ -void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +unsigned int ata_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { unsigned long flags; + unsigned int consumed; + local_irq_save(flags); - ata_data_xfer(adev, buf, buflen, write_data); + consumed = ata_data_xfer(dev, buf, buflen, rw); local_irq_restore(flags); + + return consumed; } @@ -5152,13 +5102,13 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) ata_altstatus(ap); /* flush */ switch (qc->tf.protocol) { - case ATA_PROT_ATAPI: + case ATAPI_PROT_PIO: ap->hsm_task_state = HSM_ST; break; - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_NODATA: ap->hsm_task_state = HSM_ST_LAST; break; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: ap->hsm_task_state = HSM_ST_LAST; /* initiate bmdma */ ap->ops->bmdma_start(qc); @@ -5300,12 +5250,15 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) bytes = (bc_hi << 8) | bc_lo; /* shall be cleared to zero, indicating xfer of data */ - if (ireason & (1 << 0)) + if (unlikely(ireason & (1 << 0))) goto err_out; /* make sure transfer direction matches expected */ i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0; - if (do_write != i_write) + if (unlikely(do_write != i_write)) + goto err_out; + + if (unlikely(!bytes)) goto err_out; VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); @@ -5341,7 +5294,7 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q (qc->tf.flags & ATA_TFLAG_WRITE)) return 1; - if (is_atapi_taskfile(&qc->tf) && + if (ata_is_atapi(qc->tf.protocol) && !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) return 1; } @@ -5506,7 +5459,7 @@ fsm_start: case HSM_ST: /* complete command or read/write the data register */ - if (qc->tf.protocol == ATA_PROT_ATAPI) { + if (qc->tf.protocol == ATAPI_PROT_PIO) { /* ATAPI PIO protocol */ if ((status & ATA_DRQ) == 0) { /* No more data to transfer or device error. @@ -5664,7 +5617,7 @@ fsm_start: msleep(2); status = ata_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ata_port_queue_task(ap, ata_pio_task, qc, ATA_SHORT_PAUSE); + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); return; } } @@ -5805,6 +5758,22 @@ static void fill_result_tf(struct ata_queued_cmd *qc) ap->ops->tf_read(ap, &qc->result_tf); } +static void ata_verify_xfer(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + + if (ata_tag_internal(qc->tag)) + return; + + if (ata_is_nodata(qc->tf.protocol)) + return; + + if ((dev->mwdma_mask || dev->udma_mask) && ata_is_pio(qc->tf.protocol)) + return; + + dev->flags &= ~ATA_DFLAG_DUBIOUS_XFER; +} + /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete @@ -5876,6 +5845,9 @@ void ata_qc_complete(struct ata_queued_cmd *qc) break; } + if (unlikely(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) + ata_verify_xfer(qc); + __ata_qc_complete(qc); } else { if (qc->flags & ATA_QCFLAG_EH_SCHEDULED) @@ -5938,30 +5910,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active, return nr_done; } -static inline int ata_should_dma_map(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - - switch (qc->tf.protocol) { - case ATA_PROT_NCQ: - case ATA_PROT_DMA: - case ATA_PROT_ATAPI_DMA: - return 1; - - case ATA_PROT_ATAPI: - case ATA_PROT_PIO: - if (ap->flags & ATA_FLAG_PIO_DMA) - return 1; - - /* fall through */ - - default: - return 0; - } - - /* never reached */ -} - /** * ata_qc_issue - issue taskfile to device * @qc: command to issue to device @@ -5978,6 +5926,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; /* Make sure only one non-NCQ command is outstanding. The * check is skipped for old EH because it reuses active qc to @@ -5985,7 +5934,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) */ WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); - if (qc->tf.protocol == ATA_PROT_NCQ) { + if (ata_is_ncq(prot)) { WARN_ON(link->sactive & (1 << qc->tag)); if (!link->sactive) @@ -6001,17 +5950,18 @@ void ata_qc_issue(struct ata_queued_cmd *qc) qc->flags |= ATA_QCFLAG_ACTIVE; ap->qc_active |= 1 << qc->tag; - if (ata_should_dma_map(qc)) { - if (qc->flags & ATA_QCFLAG_SG) { - if (ata_sg_setup(qc)) - goto sg_err; - } else if (qc->flags & ATA_QCFLAG_SINGLE) { - if (ata_sg_setup_one(qc)) - goto sg_err; - } - } else { - qc->flags &= ~ATA_QCFLAG_DMAMAP; - } + /* We guarantee to LLDs that they will have at least one + * non-zero sg if the command is a data command. + */ + BUG_ON(ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes)); + + /* ata_sg_setup() may update nbytes */ + qc->raw_nbytes = qc->nbytes; + + if (ata_is_dma(prot) || (ata_is_pio(prot) && + (ap->flags & ATA_FLAG_PIO_DMA))) + if (ata_sg_setup(qc)) + goto sg_err; /* if device is sleeping, schedule softreset and abort the link */ if (unlikely(qc->dev->flags & ATA_DFLAG_SLEEPING)) { @@ -6029,7 +5979,6 @@ void ata_qc_issue(struct ata_queued_cmd *qc) return; sg_err: - qc->flags &= ~ATA_QCFLAG_DMAMAP; qc->err_mask |= AC_ERR_SYSTEM; err: ata_qc_complete(qc); @@ -6064,11 +6013,11 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) switch (qc->tf.protocol) { case ATA_PROT_PIO: case ATA_PROT_NODATA: - case ATA_PROT_ATAPI: - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: qc->tf.flags |= ATA_TFLAG_POLLING; break; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: if (qc->dev->flags & ATA_DFLAG_CDB_INTR) /* see ata_dma_blacklisted() */ BUG(); @@ -6091,7 +6040,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST_LAST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_port_queue_task(ap, ata_pio_task, qc, 0); + ata_pio_queue_task(ap, qc, 0); break; @@ -6113,7 +6062,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_WRITE) { /* PIO data out protocol */ ap->hsm_task_state = HSM_ST_FIRST; - ata_port_queue_task(ap, ata_pio_task, qc, 0); + ata_pio_queue_task(ap, qc, 0); /* always send first data block using * the ata_pio_task() codepath. @@ -6123,7 +6072,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) ap->hsm_task_state = HSM_ST; if (qc->tf.flags & ATA_TFLAG_POLLING) - ata_port_queue_task(ap, ata_pio_task, qc, 0); + ata_pio_queue_task(ap, qc, 0); /* if polling, ata_pio_task() handles the rest. * otherwise, interrupt handler takes over from here. @@ -6132,8 +6081,8 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) break; - case ATA_PROT_ATAPI: - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: if (qc->tf.flags & ATA_TFLAG_POLLING) ata_qc_set_polling(qc); @@ -6144,10 +6093,10 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if ((!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) || (qc->tf.flags & ATA_TFLAG_POLLING)) - ata_port_queue_task(ap, ata_pio_task, qc, 0); + ata_pio_queue_task(ap, qc, 0); break; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ @@ -6156,7 +6105,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) /* send cdb by polling if no cdb interrupt */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - ata_port_queue_task(ap, ata_pio_task, qc, 0); + ata_pio_queue_task(ap, qc, 0); break; default: @@ -6200,15 +6149,15 @@ inline unsigned int ata_host_intr(struct ata_port *ap, */ /* Check the ATA_DFLAG_CDB_INTR flag is enough here. - * The flag was turned on only for atapi devices. - * No need to check is_atapi_taskfile(&qc->tf) again. + * The flag was turned on only for atapi devices. No + * need to check ata_is_atapi(qc->tf.protocol) again. */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) goto idle_irq; break; case HSM_ST_LAST: if (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + qc->tf.protocol == ATAPI_PROT_DMA) { /* check status of DMA engine */ host_stat = ap->ops->bmdma_status(ap); VPRINTK("ata%u: host_stat 0x%X\n", @@ -6250,7 +6199,7 @@ inline unsigned int ata_host_intr(struct ata_port *ap, ata_hsm_move(ap, qc, status, 0); if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + qc->tf.protocol == ATAPI_PROT_DMA)) ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); return 1; /* irq handled */ @@ -6772,7 +6721,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host) ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN; #endif - INIT_DELAYED_WORK(&ap->port_task, NULL); + INIT_DELAYED_WORK(&ap->port_task, ata_pio_task); INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_LIST_HEAD(&ap->eh_done_q); @@ -7589,7 +7538,6 @@ EXPORT_SYMBOL_GPL(ata_host_register); EXPORT_SYMBOL_GPL(ata_host_activate); EXPORT_SYMBOL_GPL(ata_host_detach); EXPORT_SYMBOL_GPL(ata_sg_init); -EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_hsm_move); EXPORT_SYMBOL_GPL(ata_qc_complete); EXPORT_SYMBOL_GPL(ata_qc_complete_multiple); @@ -7601,6 +7549,13 @@ EXPORT_SYMBOL_GPL(ata_std_dev_select); EXPORT_SYMBOL_GPL(sata_print_link_status); EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); +EXPORT_SYMBOL_GPL(ata_pack_xfermask); +EXPORT_SYMBOL_GPL(ata_unpack_xfermask); +EXPORT_SYMBOL_GPL(ata_xfer_mask2mode); +EXPORT_SYMBOL_GPL(ata_xfer_mode2mask); +EXPORT_SYMBOL_GPL(ata_xfer_mode2shift); +EXPORT_SYMBOL_GPL(ata_mode_string); +EXPORT_SYMBOL_GPL(ata_id_xfermask); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); EXPORT_SYMBOL_GPL(ata_exec_command); @@ -7643,7 +7598,6 @@ EXPORT_SYMBOL_GPL(ata_wait_register); EXPORT_SYMBOL_GPL(ata_busy_sleep); EXPORT_SYMBOL_GPL(ata_wait_after_reset); EXPORT_SYMBOL_GPL(ata_wait_ready); -EXPORT_SYMBOL_GPL(ata_port_queue_task); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); @@ -7662,18 +7616,20 @@ 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_id_to_dma_mode); EXPORT_SYMBOL_GPL(ata_scsi_simulate); EXPORT_SYMBOL_GPL(ata_pio_need_iordy); +EXPORT_SYMBOL_GPL(ata_timing_find_mode); EXPORT_SYMBOL_GPL(ata_timing_compute); EXPORT_SYMBOL_GPL(ata_timing_merge); +EXPORT_SYMBOL_GPL(ata_timing_cycle2mode); #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(ata_pci_init_sff_host); EXPORT_SYMBOL_GPL(ata_pci_init_bmdma); EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host); +EXPORT_SYMBOL_GPL(ata_pci_activate_sff_host); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); #ifdef CONFIG_PM @@ -7715,4 +7671,5 @@ EXPORT_SYMBOL_GPL(ata_dev_try_classify); EXPORT_SYMBOL_GPL(ata_cable_40wire); EXPORT_SYMBOL_GPL(ata_cable_80wire); EXPORT_SYMBOL_GPL(ata_cable_unknown); +EXPORT_SYMBOL_GPL(ata_cable_ignore); EXPORT_SYMBOL_GPL(ata_cable_sata); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 21a81cd148e4..4e31071acc02 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -46,9 +46,26 @@ #include "libata.h" enum { + /* speed down verdicts */ ATA_EH_SPDN_NCQ_OFF = (1 << 0), ATA_EH_SPDN_SPEED_DOWN = (1 << 1), ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), + ATA_EH_SPDN_KEEP_ERRORS = (1 << 3), + + /* error flags */ + ATA_EFLAG_IS_IO = (1 << 0), + ATA_EFLAG_DUBIOUS_XFER = (1 << 1), + + /* error categories */ + ATA_ECAT_NONE = 0, + ATA_ECAT_ATA_BUS = 1, + ATA_ECAT_TOUT_HSM = 2, + ATA_ECAT_UNK_DEV = 3, + ATA_ECAT_DUBIOUS_NONE = 4, + ATA_ECAT_DUBIOUS_ATA_BUS = 5, + ATA_ECAT_DUBIOUS_TOUT_HSM = 6, + ATA_ECAT_DUBIOUS_UNK_DEV = 7, + ATA_ECAT_NR = 8, }; /* Waiting in ->prereset can never be reliable. It's sometimes nice @@ -213,12 +230,13 @@ void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset, if (offset < 0) ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start); else - ata_port_desc(ap, "%s 0x%llx", name, start + offset); + ata_port_desc(ap, "%s 0x%llx", name, + start + (unsigned long long)offset); } #endif /* CONFIG_PCI */ -static void ata_ering_record(struct ata_ering *ering, int is_io, +static void ata_ering_record(struct ata_ering *ering, unsigned int eflags, unsigned int err_mask) { struct ata_ering_entry *ent; @@ -229,11 +247,20 @@ static void ata_ering_record(struct ata_ering *ering, int is_io, ering->cursor %= ATA_ERING_SIZE; ent = &ering->ring[ering->cursor]; - ent->is_io = is_io; + ent->eflags = eflags; ent->err_mask = err_mask; ent->timestamp = get_jiffies_64(); } +static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering) +{ + struct ata_ering_entry *ent = &ering->ring[ering->cursor]; + + if (ent->err_mask) + return ent; + return NULL; +} + static void ata_ering_clear(struct ata_ering *ering) { memset(ering, 0, sizeof(*ering)); @@ -445,9 +472,20 @@ void ata_scsi_error(struct Scsi_Host *host) spin_lock_irqsave(ap->lock, flags); __ata_port_for_each_link(link, ap) { + struct ata_eh_context *ehc = &link->eh_context; + struct ata_device *dev; + memset(&link->eh_context, 0, sizeof(link->eh_context)); link->eh_context.i = link->eh_info; memset(&link->eh_info, 0, sizeof(link->eh_info)); + + ata_link_for_each_dev(dev, link) { + int devno = dev->devno; + + ehc->saved_xfer_mode[devno] = dev->xfer_mode; + if (ata_ncq_enabled(dev)) + ehc->saved_ncq_enabled |= 1 << devno; + } } ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; @@ -1260,10 +1298,10 @@ static unsigned int atapi_eh_request_sense(struct ata_queued_cmd *qc) /* is it pointless to prefer PIO for "safety reasons"? */ if (ap->flags & ATA_FLAG_PIO_DMA) { - tf.protocol = ATA_PROT_ATAPI_DMA; + tf.protocol = ATAPI_PROT_DMA; tf.feature |= ATAPI_PKT_DMA; } else { - tf.protocol = ATA_PROT_ATAPI; + tf.protocol = ATAPI_PROT_PIO; tf.lbam = SCSI_SENSE_BUFFERSIZE; tf.lbah = 0; } @@ -1451,20 +1489,29 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return action; } -static int ata_eh_categorize_error(int is_io, unsigned int err_mask) +static int ata_eh_categorize_error(unsigned int eflags, unsigned int err_mask, + int *xfer_ok) { + int base = 0; + + if (!(eflags & ATA_EFLAG_DUBIOUS_XFER)) + *xfer_ok = 1; + + if (!*xfer_ok) + base = ATA_ECAT_DUBIOUS_NONE; + if (err_mask & AC_ERR_ATA_BUS) - return 1; + return base + ATA_ECAT_ATA_BUS; if (err_mask & AC_ERR_TIMEOUT) - return 2; + return base + ATA_ECAT_TOUT_HSM; - if (is_io) { + if (eflags & ATA_EFLAG_IS_IO) { if (err_mask & AC_ERR_HSM) - return 2; + return base + ATA_ECAT_TOUT_HSM; if ((err_mask & (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) - return 3; + return base + ATA_ECAT_UNK_DEV; } return 0; @@ -1472,18 +1519,22 @@ static int ata_eh_categorize_error(int is_io, unsigned int err_mask) struct speed_down_verdict_arg { u64 since; - int nr_errors[4]; + int xfer_ok; + int nr_errors[ATA_ECAT_NR]; }; static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) { struct speed_down_verdict_arg *arg = void_arg; - int cat = ata_eh_categorize_error(ent->is_io, ent->err_mask); + int cat; if (ent->timestamp < arg->since) return -1; + cat = ata_eh_categorize_error(ent->eflags, ent->err_mask, + &arg->xfer_ok); arg->nr_errors[cat]++; + return 0; } @@ -1495,22 +1546,48 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) * whether NCQ needs to be turned off, transfer speed should be * stepped down, or falling back to PIO is necessary. * - * Cat-1 is ATA_BUS error for any command. + * ECAT_ATA_BUS : ATA_BUS error for any command + * + * ECAT_TOUT_HSM : TIMEOUT for any command or HSM violation for + * IO commands + * + * ECAT_UNK_DEV : Unknown DEV error for IO commands + * + * ECAT_DUBIOUS_* : Identical to above three but occurred while + * data transfer hasn't been verified. + * + * Verdicts are + * + * NCQ_OFF : Turn off NCQ. + * + * SPEED_DOWN : Speed down transfer speed but don't fall back + * to PIO. + * + * FALLBACK_TO_PIO : Fall back to PIO. + * + * Even if multiple verdicts are returned, only one action is + * taken per error. An action triggered by non-DUBIOUS errors + * clears ering, while one triggered by DUBIOUS_* errors doesn't. + * This is to expedite speed down decisions right after device is + * initially configured. * - * Cat-2 is TIMEOUT for any command or HSM violation for known - * supported commands. + * The followings are speed down rules. #1 and #2 deal with + * DUBIOUS errors. * - * Cat-3 is is unclassified DEV error for known supported - * command. + * 1. If more than one DUBIOUS_ATA_BUS or DUBIOUS_TOUT_HSM errors + * occurred during last 5 mins, SPEED_DOWN and FALLBACK_TO_PIO. * - * NCQ needs to be turned off if there have been more than 3 - * Cat-2 + Cat-3 errors during last 10 minutes. + * 2. If more than one DUBIOUS_TOUT_HSM or DUBIOUS_UNK_DEV errors + * occurred during last 5 mins, NCQ_OFF. * - * Speed down is necessary if there have been more than 3 Cat-1 + - * Cat-2 errors or 10 Cat-3 errors during last 10 minutes. + * 3. If more than 8 ATA_BUS, TOUT_HSM or UNK_DEV errors + * ocurred during last 5 mins, FALLBACK_TO_PIO * - * Falling back to PIO mode is necessary if there have been more - * than 10 Cat-1 + Cat-2 + Cat-3 errors during last 5 minutes. + * 4. If more than 3 TOUT_HSM or UNK_DEV errors occurred + * during last 10 mins, NCQ_OFF. + * + * 5. If more than 3 ATA_BUS or TOUT_HSM errors, or more than 6 + * UNK_DEV errors occurred during last 10 mins, SPEED_DOWN. * * LOCKING: * Inherited from caller. @@ -1525,23 +1602,38 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) struct speed_down_verdict_arg arg; unsigned int verdict = 0; - /* scan past 10 mins of error history */ + /* scan past 5 mins of error history */ memset(&arg, 0, sizeof(arg)); - arg.since = j64 - min(j64, j10mins); + arg.since = j64 - min(j64, j5mins); ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); - if (arg.nr_errors[2] + arg.nr_errors[3] > 3) - verdict |= ATA_EH_SPDN_NCQ_OFF; - if (arg.nr_errors[1] + arg.nr_errors[2] > 3 || arg.nr_errors[3] > 10) - verdict |= ATA_EH_SPDN_SPEED_DOWN; + if (arg.nr_errors[ATA_ECAT_DUBIOUS_ATA_BUS] + + arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] > 1) + verdict |= ATA_EH_SPDN_SPEED_DOWN | + ATA_EH_SPDN_FALLBACK_TO_PIO | ATA_EH_SPDN_KEEP_ERRORS; - /* scan past 3 mins of error history */ + if (arg.nr_errors[ATA_ECAT_DUBIOUS_TOUT_HSM] + + arg.nr_errors[ATA_ECAT_DUBIOUS_UNK_DEV] > 1) + verdict |= ATA_EH_SPDN_NCQ_OFF | ATA_EH_SPDN_KEEP_ERRORS; + + if (arg.nr_errors[ATA_ECAT_ATA_BUS] + + arg.nr_errors[ATA_ECAT_TOUT_HSM] + + arg.nr_errors[ATA_ECAT_UNK_DEV] > 6) + verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO; + + /* scan past 10 mins of error history */ memset(&arg, 0, sizeof(arg)); - arg.since = j64 - min(j64, j5mins); + arg.since = j64 - min(j64, j10mins); ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); - if (arg.nr_errors[1] + arg.nr_errors[2] + arg.nr_errors[3] > 10) - verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO; + if (arg.nr_errors[ATA_ECAT_TOUT_HSM] + + arg.nr_errors[ATA_ECAT_UNK_DEV] > 3) + verdict |= ATA_EH_SPDN_NCQ_OFF; + + if (arg.nr_errors[ATA_ECAT_ATA_BUS] + + arg.nr_errors[ATA_ECAT_TOUT_HSM] > 3 || + arg.nr_errors[ATA_ECAT_UNK_DEV] > 6) + verdict |= ATA_EH_SPDN_SPEED_DOWN; return verdict; } @@ -1549,7 +1641,7 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) /** * ata_eh_speed_down - record error and speed down if necessary * @dev: Failed device - * @is_io: Did the device fail during normal IO? + * @eflags: mask of ATA_EFLAG_* flags * @err_mask: err_mask of the error * * Record error and examine error history to determine whether @@ -1563,18 +1655,20 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) * RETURNS: * Determined recovery action. */ -static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, - unsigned int err_mask) +static unsigned int ata_eh_speed_down(struct ata_device *dev, + unsigned int eflags, unsigned int err_mask) { + struct ata_link *link = dev->link; + int xfer_ok = 0; unsigned int verdict; unsigned int action = 0; /* don't bother if Cat-0 error */ - if (ata_eh_categorize_error(is_io, err_mask) == 0) + if (ata_eh_categorize_error(eflags, err_mask, &xfer_ok) == 0) return 0; /* record error and determine whether speed down is necessary */ - ata_ering_record(&dev->ering, is_io, err_mask); + ata_ering_record(&dev->ering, eflags, err_mask); verdict = ata_eh_speed_down_verdict(dev); /* turn off NCQ? */ @@ -1590,7 +1684,7 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, /* speed down? */ if (verdict & ATA_EH_SPDN_SPEED_DOWN) { /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->link) == 0) { + if (sata_down_spd_limit(link) == 0) { action |= ATA_EH_HARDRESET; goto done; } @@ -1618,10 +1712,10 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, } /* Fall back to PIO? Slowing down to PIO is meaningless for - * SATA. Consider it only for PATA. + * SATA ATA devices. Consider it only for PATA and SATAPI. */ if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) && - (dev->link->ap->cbl != ATA_CBL_SATA) && + (link->ap->cbl != ATA_CBL_SATA || dev->class == ATA_DEV_ATAPI) && (dev->xfer_shift != ATA_SHIFT_PIO)) { if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { dev->spdn_cnt = 0; @@ -1633,7 +1727,8 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, return 0; done: /* device has been slowed down, blow error history */ - ata_ering_clear(&dev->ering); + if (!(verdict & ATA_EH_SPDN_KEEP_ERRORS)) + ata_ering_clear(&dev->ering); return action; } @@ -1653,8 +1748,8 @@ static void ata_eh_link_autopsy(struct ata_link *link) struct ata_port *ap = link->ap; struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev; - unsigned int all_err_mask = 0; - int tag, is_io = 0; + unsigned int all_err_mask = 0, eflags = 0; + int tag; u32 serror; int rc; @@ -1713,15 +1808,15 @@ static void ata_eh_link_autopsy(struct ata_link *link) ehc->i.dev = qc->dev; all_err_mask |= qc->err_mask; if (qc->flags & ATA_QCFLAG_IO) - is_io = 1; + eflags |= ATA_EFLAG_IS_IO; } /* enforce default EH actions */ if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) ehc->i.action |= ATA_EH_SOFTRESET; - else if ((is_io && all_err_mask) || - (!is_io && (all_err_mask & ~AC_ERR_DEV))) + else if (((eflags & ATA_EFLAG_IS_IO) && all_err_mask) || + (!(eflags & ATA_EFLAG_IS_IO) && (all_err_mask & ~AC_ERR_DEV))) ehc->i.action |= ATA_EH_REVALIDATE; /* If we have offending qcs and the associated failed device, @@ -1743,8 +1838,11 @@ static void ata_eh_link_autopsy(struct ata_link *link) ata_dev_enabled(link->device)))) dev = link->device; - if (dev) - ehc->i.action |= ata_eh_speed_down(dev, is_io, all_err_mask); + if (dev) { + if (dev->flags & ATA_DFLAG_DUBIOUS_XFER) + eflags |= ATA_EFLAG_DUBIOUS_XFER; + ehc->i.action |= ata_eh_speed_down(dev, eflags, all_err_mask); + } DPRINTK("EXIT\n"); } @@ -1880,8 +1978,8 @@ static void ata_eh_link_report(struct ata_link *link) [ATA_PROT_PIO] = "pio", [ATA_PROT_DMA] = "dma", [ATA_PROT_NCQ] = "ncq", - [ATA_PROT_ATAPI] = "pio", - [ATA_PROT_ATAPI_DMA] = "dma", + [ATAPI_PROT_PIO] = "pio", + [ATAPI_PROT_DMA] = "dma", }; snprintf(data_buf, sizeof(data_buf), " %s %u %s", @@ -1889,7 +1987,7 @@ static void ata_eh_link_report(struct ata_link *link) dma_str[qc->dma_dir]); } - if (is_atapi_taskfile(&qc->tf)) + if (ata_is_atapi(qc->tf.protocol)) snprintf(cdb_buf, sizeof(cdb_buf), "cdb %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n ", @@ -2329,6 +2427,58 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, return rc; } +/** + * ata_set_mode - Program timings and issue SET FEATURES - XFER + * @link: link on which timings will be programmed + * @r_failed_dev: out paramter for failed device + * + * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If + * ata_set_mode() fails, pointer to the failing device is + * returned in @r_failed_dev. + * + * LOCKING: + * PCI/etc. bus probe sem. + * + * RETURNS: + * 0 on success, negative errno otherwise + */ +int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev) +{ + struct ata_port *ap = link->ap; + struct ata_device *dev; + int rc; + + /* if data transfer is verified, clear DUBIOUS_XFER on ering top */ + ata_link_for_each_dev(dev, link) { + if (!(dev->flags & ATA_DFLAG_DUBIOUS_XFER)) { + struct ata_ering_entry *ent; + + ent = ata_ering_top(&dev->ering); + if (ent) + ent->eflags &= ~ATA_EFLAG_DUBIOUS_XFER; + } + } + + /* has private set_mode? */ + if (ap->ops->set_mode) + rc = ap->ops->set_mode(link, r_failed_dev); + else + rc = ata_do_set_mode(link, r_failed_dev); + + /* if transfer mode has changed, set DUBIOUS_XFER on device */ + ata_link_for_each_dev(dev, link) { + struct ata_eh_context *ehc = &link->eh_context; + u8 saved_xfer_mode = ehc->saved_xfer_mode[dev->devno]; + u8 saved_ncq = !!(ehc->saved_ncq_enabled & (1 << dev->devno)); + + if (dev->xfer_mode != saved_xfer_mode || + ata_ncq_enabled(dev) != saved_ncq) + dev->flags |= ATA_DFLAG_DUBIOUS_XFER; + } + + return rc; +} + static int ata_link_nr_enabled(struct ata_link *link) { struct ata_device *dev; @@ -2375,6 +2525,24 @@ static int ata_eh_skip_recovery(struct ata_link *link) return 1; } +static int ata_eh_schedule_probe(struct ata_device *dev) +{ + struct ata_eh_context *ehc = &dev->link->eh_context; + + if (!(ehc->i.probe_mask & (1 << dev->devno)) || + (ehc->did_probe_mask & (1 << dev->devno))) + return 0; + + ata_eh_detach_dev(dev); + ata_dev_init(dev); + ehc->did_probe_mask |= (1 << dev->devno); + ehc->i.action |= ATA_EH_SOFTRESET; + ehc->saved_xfer_mode[dev->devno] = 0; + ehc->saved_ncq_enabled &= ~(1 << dev->devno); + + return 1; +} + static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) { struct ata_eh_context *ehc = &dev->link->eh_context; @@ -2406,16 +2574,9 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err) if (ata_link_offline(dev->link)) ata_eh_detach_dev(dev); - /* probe if requested */ - if ((ehc->i.probe_mask & (1 << dev->devno)) && - !(ehc->did_probe_mask & (1 << dev->devno))) { - ata_eh_detach_dev(dev); - ata_dev_init(dev); - + /* schedule probe if necessary */ + if (ata_eh_schedule_probe(dev)) ehc->tries[dev->devno] = ATA_EH_DEV_TRIES; - ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; - } return 1; } else { @@ -2492,14 +2653,9 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (dev->flags & ATA_DFLAG_DETACH) ata_eh_detach_dev(dev); - if (!ata_dev_enabled(dev) && - ((ehc->i.probe_mask & (1 << dev->devno)) && - !(ehc->did_probe_mask & (1 << dev->devno)))) { - ata_eh_detach_dev(dev); - ata_dev_init(dev); - ehc->did_probe_mask |= (1 << dev->devno); - ehc->i.action |= ATA_EH_SOFTRESET; - } + /* schedule probe if necessary */ + if (!ata_dev_enabled(dev)) + ata_eh_schedule_probe(dev); } } @@ -2747,6 +2903,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) if (ap->ops->port_suspend) rc = ap->ops->port_suspend(ap, ap->pm_mesg); + ata_acpi_set_state(ap, PMSG_SUSPEND); out: /* report result */ spin_lock_irqsave(ap->lock, flags); @@ -2792,6 +2949,8 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) WARN_ON(!(ap->pflags & ATA_PFLAG_SUSPENDED)); + ata_acpi_set_state(ap, PMSG_ON); + if (ap->ops->port_resume) rc = ap->ops->port_resume(ap); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 14daf4848f09..c02c490122dc 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -517,7 +517,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev, qc->scsicmd = cmd; qc->scsidone = done; - qc->__sg = scsi_sglist(cmd); + qc->sg = scsi_sglist(cmd); qc->n_elem = scsi_sg_count(cmd); } else { cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1); @@ -839,7 +839,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev, if (dev->class == ATA_DEV_ATAPI) { struct request_queue *q = sdev->request_queue; blk_queue_max_hw_segments(q, q->max_hw_segments - 1); - } + + /* set the min alignment */ + blk_queue_update_dma_alignment(sdev->request_queue, + ATA_DMA_PAD_SZ - 1); + } else + /* ATA devices must be sector aligned */ + blk_queue_update_dma_alignment(sdev->request_queue, + ATA_SECT_SIZE - 1); if (dev->class == ATA_DEV_ATA) sdev->manage_start_stop = 1; @@ -878,7 +885,7 @@ int ata_scsi_slave_config(struct scsi_device *sdev) if (dev) ata_scsi_dev_config(sdev, dev); - return 0; /* scsi layer doesn't check return value, sigh */ + return 0; } /** @@ -2210,7 +2217,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, /* sector size */ ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE); + ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff); } else { /* sector count, 64-bit */ ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); @@ -2224,7 +2231,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, /* sector size */ ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE); + ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff); } return 0; @@ -2331,7 +2338,7 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) DPRINTK("ATAPI request sense\n"); /* FIXME: is this needed? */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); ap->ops->tf_read(ap, &qc->tf); @@ -2341,7 +2348,9 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) ata_qc_reinit(qc); - ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); + /* setup sg table and init transfer direction */ + sg_init_one(&qc->sgent, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); + ata_sg_init(qc, &qc->sgent, 1); qc->dma_dir = DMA_FROM_DEVICE; memset(&qc->cdb, 0, qc->dev->cdb_len); @@ -2352,10 +2361,10 @@ static void atapi_request_sense(struct ata_queued_cmd *qc) qc->tf.command = ATA_CMD_PACKET; if (ata_pio_use_silly(ap)) { - qc->tf.protocol = ATA_PROT_ATAPI_DMA; + qc->tf.protocol = ATAPI_PROT_DMA; qc->tf.feature |= ATAPI_PKT_DMA; } else { - qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.protocol = ATAPI_PROT_PIO; qc->tf.lbam = SCSI_SENSE_BUFFERSIZE; qc->tf.lbah = 0; } @@ -2526,12 +2535,12 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc) if (using_pio || nodata) { /* no data, or PIO data xfer */ if (nodata) - qc->tf.protocol = ATA_PROT_ATAPI_NODATA; + qc->tf.protocol = ATAPI_PROT_NODATA; else - qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.protocol = ATAPI_PROT_PIO; } else { /* DMA data xfer */ - qc->tf.protocol = ATA_PROT_ATAPI_DMA; + qc->tf.protocol = ATAPI_PROT_DMA; qc->tf.feature |= ATAPI_PKT_DMA; if (atapi_dmadir && (scmd->sc_data_direction != DMA_TO_DEVICE)) @@ -2690,6 +2699,24 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) goto invalid_fld; + /* + * Filter TPM commands by default. These provide an + * essentially uncontrolled encrypted "back door" between + * applications and the disk. Set libata.allow_tpm=1 if you + * have a real reason for wanting to use them. This ensures + * that installed software cannot easily mess stuff up without + * user intent. DVR type users will probably ship with this enabled + * for movie content management. + * + * Note that for ATA8 we can issue a DCS change and DCS freeze lock + * for this and should do in future but that it is not sufficient as + * DCS is an optional feature set. Thus we also do the software filter + * so that we comply with the TC consortium stated goal that the user + * can turn off TC features of their system. + */ + if (tf->command >= 0x5C && tf->command <= 0x5F && !libata_allow_tpm) + goto invalid_fld; + /* We may not issue DMA commands if no DMA mode is set */ if (tf->protocol == ATA_PROT_DMA && dev->dma_mode == 0) goto invalid_fld; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index b7ac80b4b1fb..60cd4b179766 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -147,7 +147,9 @@ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) * @tf: ATA taskfile register set for storing input * * Reads ATA taskfile registers for currently-selected device - * into @tf. + * into @tf. Assumes the device has a fully SFF compliant task file + * layout and behaviour. If you device does not (eg has a different + * status method) then you will need to provide a replacement tf_read * * LOCKING: * Inherited from caller. @@ -156,7 +158,7 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - tf->command = ata_chk_status(ap); + tf->command = ata_check_status(ap); tf->feature = ioread8(ioaddr->error_addr); tf->nsect = ioread8(ioaddr->nsect_addr); tf->lbal = ioread8(ioaddr->lbal_addr); @@ -415,7 +417,7 @@ void ata_bmdma_drive_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ap->hsm_task_state = HSM_ST_IDLE; if (qc && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA)) { + qc->tf.protocol == ATAPI_PROT_DMA)) { u8 host_stat; host_stat = ap->ops->bmdma_status(ap); @@ -549,7 +551,7 @@ int ata_pci_init_bmdma(struct ata_host *host) return rc; /* request and iomap DMA region */ - rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME); + rc = pcim_iomap_regions(pdev, 1 << 4, dev_driver_string(gdev)); if (rc) { dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n"); return -ENOMEM; @@ -619,7 +621,8 @@ int ata_pci_init_sff_host(struct ata_host *host) continue; } - rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME); + rc = pcim_iomap_regions(pdev, 0x3 << base, + dev_driver_string(gdev)); if (rc) { dev_printk(KERN_WARNING, gdev, "failed to request/iomap BARs for port %d " @@ -711,6 +714,99 @@ int ata_pci_prepare_sff_host(struct pci_dev *pdev, } /** + * ata_pci_activate_sff_host - start SFF host, request IRQ and register it + * @host: target SFF ATA host + * @irq_handler: irq_handler used when requesting IRQ(s) + * @sht: scsi_host_template to use when registering the host + * + * This is the counterpart of ata_host_activate() for SFF ATA + * hosts. This separate helper is necessary because SFF hosts + * use two separate interrupts in legacy mode. + * + * LOCKING: + * Inherited from calling layer (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_pci_activate_sff_host(struct ata_host *host, + irq_handler_t irq_handler, + struct scsi_host_template *sht) +{ + struct device *dev = host->dev; + struct pci_dev *pdev = to_pci_dev(dev); + const char *drv_name = dev_driver_string(host->dev); + int legacy_mode = 0, rc; + + rc = ata_host_start(host); + if (rc) + return rc; + + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + u8 tmp8, mask; + + /* TODO: What if one channel is in native mode ... */ + pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); + mask = (1 << 2) | (1 << 0); + if ((tmp8 & mask) != mask) + legacy_mode = 1; +#if defined(CONFIG_NO_ATA_LEGACY) + /* Some platforms with PCI limits cannot address compat + port space. In that case we punt if their firmware has + left a device in compatibility mode */ + if (legacy_mode) { + printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); + return -EOPNOTSUPP; + } +#endif + } + + if (!devres_open_group(dev, NULL, GFP_KERNEL)) + return -ENOMEM; + + if (!legacy_mode && pdev->irq) { + rc = devm_request_irq(dev, pdev->irq, irq_handler, + IRQF_SHARED, drv_name, host); + if (rc) + goto out; + + ata_port_desc(host->ports[0], "irq %d", pdev->irq); + ata_port_desc(host->ports[1], "irq %d", pdev->irq); + } else if (legacy_mode) { + if (!ata_port_is_dummy(host->ports[0])) { + rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), + irq_handler, IRQF_SHARED, + drv_name, host); + if (rc) + goto out; + + ata_port_desc(host->ports[0], "irq %d", + ATA_PRIMARY_IRQ(pdev)); + } + + if (!ata_port_is_dummy(host->ports[1])) { + rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), + irq_handler, IRQF_SHARED, + drv_name, host); + if (rc) + goto out; + + ata_port_desc(host->ports[1], "irq %d", + ATA_SECONDARY_IRQ(pdev)); + } + } + + rc = ata_host_register(host, sht); + out: + if (rc == 0) + devres_remove_group(dev, NULL); + else + devres_release_group(dev, NULL); + + return rc; +} + +/** * ata_pci_init_one - Initialize/register PCI IDE host controller * @pdev: Controller to be initialized * @ppi: array of port_info, must be enough for two ports @@ -739,8 +835,6 @@ int ata_pci_init_one(struct pci_dev *pdev, struct device *dev = &pdev->dev; const struct ata_port_info *pi = NULL; struct ata_host *host = NULL; - u8 mask; - int legacy_mode = 0; int i, rc; DPRINTK("ENTER\n"); @@ -762,95 +856,24 @@ int ata_pci_init_one(struct pci_dev *pdev, if (!devres_open_group(dev, NULL, GFP_KERNEL)) return -ENOMEM; - /* FIXME: Really for ATA it isn't safe because the device may be - multi-purpose and we want to leave it alone if it was already - enabled. Secondly for shared use as Arjan says we want refcounting - - Checking dev->is_enabled is insufficient as this is not set at - boot for the primary video which is BIOS enabled - */ - rc = pcim_enable_device(pdev); if (rc) - goto err_out; + goto out; - if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - u8 tmp8; - - /* TODO: What if one channel is in native mode ... */ - pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); - mask = (1 << 2) | (1 << 0); - if ((tmp8 & mask) != mask) - legacy_mode = 1; -#if defined(CONFIG_NO_ATA_LEGACY) - /* Some platforms with PCI limits cannot address compat - port space. In that case we punt if their firmware has - left a device in compatibility mode */ - if (legacy_mode) { - printk(KERN_ERR "ata: Compatibility mode ATA is not supported on this platform, skipping.\n"); - rc = -EOPNOTSUPP; - goto err_out; - } -#endif - } - - /* prepare host */ + /* prepare and activate SFF host */ rc = ata_pci_prepare_sff_host(pdev, ppi, &host); if (rc) - goto err_out; + goto out; pci_set_master(pdev); + rc = ata_pci_activate_sff_host(host, pi->port_ops->irq_handler, + pi->sht); + out: + if (rc == 0) + devres_remove_group(&pdev->dev, NULL); + else + devres_release_group(&pdev->dev, NULL); - /* start host and request IRQ */ - rc = ata_host_start(host); - if (rc) - goto err_out; - - if (!legacy_mode && pdev->irq) { - /* We may have no IRQ assigned in which case we can poll. This - shouldn't happen on a sane system but robustness is cheap - in this case */ - rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - if (rc) - goto err_out; - - ata_port_desc(host->ports[0], "irq %d", pdev->irq); - ata_port_desc(host->ports[1], "irq %d", pdev->irq); - } else if (legacy_mode) { - if (!ata_port_is_dummy(host->ports[0])) { - rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev), - pi->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - if (rc) - goto err_out; - - ata_port_desc(host->ports[0], "irq %d", - ATA_PRIMARY_IRQ(pdev)); - } - - if (!ata_port_is_dummy(host->ports[1])) { - rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev), - pi->port_ops->irq_handler, - IRQF_SHARED, DRV_NAME, host); - if (rc) - goto err_out; - - ata_port_desc(host->ports[1], "irq %d", - ATA_SECONDARY_IRQ(pdev)); - } - } - - /* register */ - rc = ata_host_register(host, pi->sht); - if (rc) - goto err_out; - - devres_remove_group(dev, NULL); - return 0; - -err_out: - devres_release_group(dev, NULL); return rc; } diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index bbe59c2fd1e2..409ffb9af163 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -60,6 +60,7 @@ extern int atapi_dmadir; extern int atapi_passthru16; extern int libata_fua; extern int libata_noacpi; +extern int libata_allow_tpm; extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev); extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, u64 block, u32 n_block, unsigned int tf_flags, @@ -85,7 +86,6 @@ extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link); extern int sata_set_spd_needed(struct ata_link *link); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); -extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_issue(struct ata_queued_cmd *qc); @@ -113,6 +113,7 @@ extern int ata_acpi_on_suspend(struct ata_port *ap); extern void ata_acpi_on_resume(struct ata_port *ap); extern int ata_acpi_on_devcfg(struct ata_device *dev); extern void ata_acpi_on_disable(struct ata_device *dev); +extern void ata_acpi_set_state(struct ata_port *ap, pm_message_t state); #else static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { } static inline void ata_acpi_associate(struct ata_host *host) { } @@ -121,6 +122,8 @@ static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; } static inline void ata_acpi_on_resume(struct ata_port *ap) { } static inline int ata_acpi_on_devcfg(struct ata_device *dev) { return 0; } static inline void ata_acpi_on_disable(struct ata_device *dev) { } +static inline void ata_acpi_set_state(struct ata_port *ap, + pm_message_t state) { } #endif /* libata-scsi.c */ @@ -183,6 +186,7 @@ extern void ata_eh_report(struct ata_port *ap); extern int ata_eh_reset(struct ata_link *link, int classify, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset); +extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset, diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index e4542ab9c7f8..244098a80ce4 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -81,17 +81,6 @@ static void pacpi_error_handler(struct ata_port *ap) NULL, ata_std_postreset); } -/* Welcome to ACPI, bring a bucket */ -static const unsigned int pio_cycle[7] = { - 600, 383, 240, 180, 120, 100, 80 -}; -static const unsigned int mwdma_cycle[5] = { - 480, 150, 120, 100, 80 -}; -static const unsigned int udma_cycle[7] = { - 120, 80, 60, 45, 30, 20, 15 -}; - /** * pacpi_discover_modes - filter non ACPI modes * @adev: ATA device @@ -103,56 +92,20 @@ static const unsigned int udma_cycle[7] = { static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev) { - int unit = adev->devno; struct pata_acpi *acpi = ap->private_data; - int i; - u32 t; - unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO); - struct ata_acpi_gtm probe; + unsigned int xfer_mask; probe = acpi->gtm; - /* We always use the 0 slot for crap hardware */ - if (!(probe.flags & 0x10)) - unit = 0; - ata_acpi_gtm(ap, &probe); - /* Start by scanning for PIO modes */ - for (i = 0; i < 7; i++) { - t = probe.drive[unit].pio; - if (t <= pio_cycle[i]) { - mask |= (2 << (ATA_SHIFT_PIO + i)) - 1; - break; - } - } + xfer_mask = ata_acpi_gtm_xfermask(adev, &probe); - /* See if we have MWDMA or UDMA data. We don't bother with MWDMA - if UDMA is availabe as this means the BIOS set UDMA and our - error changedown if it works is UDMA to PIO anyway */ - if (probe.flags & (1 << (2 * unit))) { - /* MWDMA */ - for (i = 0; i < 5; i++) { - t = probe.drive[unit].dma; - if (t <= mwdma_cycle[i]) { - mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1; - break; - } - } - } else { - /* UDMA */ - for (i = 0; i < 7; i++) { - t = probe.drive[unit].dma; - if (t <= udma_cycle[i]) { - mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1; - break; - } - } - } - if (mask & (0xF8 << ATA_SHIFT_UDMA)) + if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA)) ap->cbl = ATA_CBL_PATA80; - return mask; + + return xfer_mask; } /** @@ -180,12 +133,14 @@ static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev) { int unit = adev->devno; struct pata_acpi *acpi = ap->private_data; + const struct ata_timing *t; if (!(acpi->gtm.flags & 0x10)) unit = 0; /* Now stuff the nS values into the structure */ - acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0]; + t = ata_timing_find_mode(adev->pio_mode); + acpi->gtm.drive[unit].pio = t->cycle; ata_acpi_stm(ap, &acpi->gtm); /* See what mode we actually got */ ata_acpi_gtm(ap, &acpi->gtm); @@ -201,16 +156,18 @@ static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev) { int unit = adev->devno; struct pata_acpi *acpi = ap->private_data; + const struct ata_timing *t; if (!(acpi->gtm.flags & 0x10)) unit = 0; /* Now stuff the nS values into the structure */ + t = ata_timing_find_mode(adev->dma_mode); if (adev->dma_mode >= XFER_UDMA_0) { - acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0]; + acpi->gtm.drive[unit].dma = t->udma; acpi->gtm.flags |= (1 << (2 * unit)); } else { - acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0]; + acpi->gtm.drive[unit].dma = t->cycle; acpi->gtm.flags &= ~(1 << (2 * unit)); } ata_acpi_stm(ap, &acpi->gtm); diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 8caf9afc8b90..7e68edf3c0f3 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -64,7 +64,7 @@ static int ali_cable_override(struct pci_dev *pdev) if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF) return 1; /* Mitac 8317 (Winbook-A) and relatives */ - if (pdev->subsystem_vendor == 0x1071 && pdev->subsystem_device == 0x8317) + if (pdev->subsystem_vendor == 0x1071 && pdev->subsystem_device == 0x8317) return 1; /* Systems by DMI */ if (dmi_check_system(cable_dmi_table)) diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 3cc27b514654..761a66608d7b 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -220,6 +220,62 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) timing_setup(ap, adev, 0x40, adev->dma_mode, 4); } +/* Both host-side and drive-side detection results are worthless on NV + * PATAs. Ignore them and just follow what BIOS configured. Both the + * current configuration in PCI config reg and ACPI GTM result are + * cached during driver attach and are consulted to select transfer + * mode. + */ +static unsigned long nv_mode_filter(struct ata_device *dev, + unsigned long xfer_mask) +{ + static const unsigned int udma_mask_map[] = + { ATA_UDMA2, ATA_UDMA1, ATA_UDMA0, 0, + ATA_UDMA3, ATA_UDMA4, ATA_UDMA5, ATA_UDMA6 }; + struct ata_port *ap = dev->link->ap; + char acpi_str[32] = ""; + u32 saved_udma, udma; + const struct ata_acpi_gtm *gtm; + unsigned long bios_limit = 0, acpi_limit = 0, limit; + + /* find out what BIOS configured */ + udma = saved_udma = (unsigned long)ap->host->private_data; + + if (ap->port_no == 0) + udma >>= 16; + if (dev->devno == 0) + udma >>= 8; + + if ((udma & 0xc0) == 0xc0) + bios_limit = ata_pack_xfermask(0, 0, udma_mask_map[udma & 0x7]); + + /* consult ACPI GTM too */ + gtm = ata_acpi_init_gtm(ap); + if (gtm) { + acpi_limit = ata_acpi_gtm_xfermask(dev, gtm); + + snprintf(acpi_str, sizeof(acpi_str), " (%u:%u:0x%x)", + gtm->drive[0].dma, gtm->drive[1].dma, gtm->flags); + } + + /* be optimistic, EH can take care of things if something goes wrong */ + limit = bios_limit | acpi_limit; + + /* If PIO or DMA isn't configured at all, don't limit. Let EH + * handle it. + */ + if (!(limit & ATA_MASK_PIO)) + limit |= ATA_MASK_PIO; + if (!(limit & (ATA_MASK_MWDMA | ATA_MASK_UDMA))) + limit |= ATA_MASK_MWDMA | ATA_MASK_UDMA; + + ata_port_printk(ap, KERN_DEBUG, "nv_mode_filter: 0x%lx&0x%lx->0x%lx, " + "BIOS=0x%lx (0x%x) ACPI=0x%lx%s\n", + xfer_mask, limit, xfer_mask & limit, bios_limit, + saved_udma, acpi_limit, acpi_str); + + return xfer_mask & limit; +} /** * nv_probe_init - cable detection @@ -252,31 +308,6 @@ static void nv_error_handler(struct ata_port *ap) ata_std_postreset); } -static int nv_cable_detect(struct ata_port *ap) -{ - static const u8 bitmask[2] = {0x03, 0x0C}; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u8 ata66; - u16 udma; - int cbl; - - pci_read_config_byte(pdev, 0x52, &ata66); - if (ata66 & bitmask[ap->port_no]) - cbl = ATA_CBL_PATA80; - else - cbl = ATA_CBL_PATA40; - - /* We now have to double check because the Nvidia boxes BIOS - doesn't always set the cable bits but does set mode bits */ - pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma); - if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400) - cbl = ATA_CBL_PATA80; - /* And a triple check across suspend/resume with ACPI around */ - if (ata_acpi_cbl_80wire(ap)) - cbl = ATA_CBL_PATA80; - return cbl; -} - /** * nv100_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -314,6 +345,14 @@ static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev) timing_setup(ap, adev, 0x50, adev->dma_mode, 4); } +static void nv_host_stop(struct ata_host *host) +{ + u32 udma = (unsigned long)host->private_data; + + /* restore PCI config register 0x60 */ + pci_write_config_dword(to_pci_dev(host->dev), 0x60, udma); +} + static struct scsi_host_template amd_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -478,7 +517,8 @@ static struct ata_port_operations nv100_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = nv_cable_detect, + .cable_detect = ata_cable_ignore, + .mode_filter = nv_mode_filter, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -495,6 +535,7 @@ static struct ata_port_operations nv100_port_ops = { .irq_on = ata_irq_on, .port_start = ata_sff_port_start, + .host_stop = nv_host_stop, }; static struct ata_port_operations nv133_port_ops = { @@ -511,7 +552,8 @@ static struct ata_port_operations nv133_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = nv_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = nv_cable_detect, + .cable_detect = ata_cable_ignore, + .mode_filter = nv_mode_filter, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -528,6 +570,7 @@ static struct ata_port_operations nv133_port_ops = { .irq_on = ata_irq_on, .port_start = ata_sff_port_start, + .host_stop = nv_host_stop, }; static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) @@ -614,7 +657,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .port_ops = &amd100_port_ops } }; - const struct ata_port_info *ppi[] = { NULL, NULL }; + struct ata_port_info pi; + const struct ata_port_info *ppi[] = { &pi, NULL }; static int printed_version; int type = id->driver_data; u8 fifo; @@ -628,6 +672,19 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (type == 1 && pdev->revision > 0x7) type = 2; + /* Serenade ? */ + if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD && + pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) + type = 6; /* UDMA 100 only */ + + /* + * Okay, type is determined now. Apply type-specific workarounds. + */ + pi = info[type]; + + if (type < 3) + ata_pci_clear_simplex(pdev); + /* Check for AMD7411 */ if (type == 3) /* FIFO is broken */ @@ -635,16 +692,17 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) else pci_write_config_byte(pdev, 0x41, fifo | 0xF0); - /* Serenade ? */ - if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD && - pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE) - type = 6; /* UDMA 100 only */ + /* Cable detection on Nvidia chips doesn't work too well, + * cache BIOS programmed UDMA mode. + */ + if (type == 7 || type == 8) { + u32 udma; - if (type < 3) - ata_pci_clear_simplex(pdev); + pci_read_config_dword(pdev, 0x60, &udma); + pi.private_data = (void *)(unsigned long)udma; + } /* And fire it up */ - ppi[0] = &info[type]; return ata_pci_init_one(pdev, ppi); } diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index 7842cc487359..a32e3c44a606 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -832,6 +832,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) { unsigned short config = WDSIZE_16; struct scatterlist *sg; + unsigned int si; pr_debug("in atapi dma setup\n"); /* Program the ATA_CTRL register with dir */ @@ -839,7 +840,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) /* fill the ATAPI DMA controller */ set_dma_config(CH_ATAPI_TX, config); set_dma_x_modify(CH_ATAPI_TX, 2); - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg)); set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1); } @@ -848,7 +849,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc) /* fill the ATAPI DMA controller */ set_dma_config(CH_ATAPI_RX, config); set_dma_x_modify(CH_ATAPI_RX, 2); - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg)); set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1); } @@ -867,6 +868,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; struct scatterlist *sg; + unsigned int si; pr_debug("in atapi dma start\n"); if (!(ap->udma_mask || ap->mwdma_mask)) @@ -881,7 +883,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) * data cache is enabled. Otherwise, this loop * is an empty loop and optimized out. */ - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { flush_dcache_range(sg_dma_address(sg), sg_dma_address(sg) + sg_dma_len(sg)); } @@ -910,7 +912,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc) ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST); /* Set transfer length to buffer len */ - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1)); } @@ -932,6 +934,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; + unsigned int si; pr_debug("in atapi dma stop\n"); if (!(ap->udma_mask || ap->mwdma_mask)) @@ -950,7 +953,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc) * data cache is enabled. Otherwise, this loop * is an empty loop and optimized out. */ - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { invalidate_dcache_range( sg_dma_address(sg), sg_dma_address(sg) @@ -1167,34 +1170,36 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap) * Note: Original code is ata_data_xfer(). */ -static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +static unsigned int bfin_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; - unsigned int words = buflen >> 1; - unsigned short *buf16 = (u16 *) buf; + struct ata_port *ap = dev->link->ap; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; + unsigned int words = buflen >> 1; + unsigned short *buf16 = (u16 *)buf; /* Transfer multiple of 2 bytes */ - if (write_data) { - write_atapi_data(base, words, buf16); - } else { + if (rw == READ) read_atapi_data(base, words, buf16); - } + else + write_atapi_data(base, words, buf16); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { unsigned short align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (write_data) { - memcpy(align_buf, trailing_buf, 1); - write_atapi_data(base, 1, align_buf); - } else { + if (rw == READ) { read_atapi_data(base, 1, align_buf); memcpy(trailing_buf, align_buf, 1); + } else { + memcpy(align_buf, trailing_buf, 1); + write_atapi_data(base, 1, align_buf); } + words++; } + + return words << 1; } /** diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 33f7f0843f4f..d4590f546c49 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -198,7 +198,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi }; const struct ata_port_info *ppi[2]; u8 pcicfg; - void *iomap[5]; + void __iomem *iomap[5]; struct ata_host *host; struct ata_ioports *ioaddr; int i, rc; diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index c79f066c2bc9..68eb34929cec 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -847,15 +847,16 @@ static u32 hpt374_read_freq(struct pci_dev *pdev) u32 freq; unsigned long io_base = pci_resource_start(pdev, 4); if (PCI_FUNC(pdev->devfn) & 1) { - struct pci_dev *pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1); + struct pci_dev *pdev_0; + + pdev_0 = pci_get_slot(pdev->bus, pdev->devfn - 1); /* Someone hot plugged the controller on us ? */ if (pdev_0 == NULL) return 0; io_base = pci_resource_start(pdev_0, 4); freq = inl(io_base + 0x90); pci_dev_put(pdev_0); - } - else + } else freq = inl(io_base + 0x90); return freq; } diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 842fe08a3c13..5b8586dac63b 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -224,6 +224,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) struct pata_icside_state *state = ap->host->private_data; struct scatterlist *sg, *rsg = state->sg; unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE; + unsigned int si; /* * We are simplex; BUG if we try to fiddle with DMA @@ -234,7 +235,7 @@ static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc) /* * Copy ATAs scattered sg list into a contiguous array of sg */ - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { memcpy(rsg, sg, sizeof(*sg)); rsg++; } diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index ca9aae09daed..109ddd42c266 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -430,7 +430,7 @@ static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command); - return AC_ERR_INVALID; + return AC_ERR_DEV; } /** @@ -516,6 +516,37 @@ static void it821x_dev_config(struct ata_device *adev) printk("(%dK stripe)", adev->id[146]); printk(".\n"); } + /* This is a controller firmware triggered funny, don't + report the drive faulty! */ + adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC; +} + +/** + * it821x_ident_hack - Hack identify data up + * @ap: Port + * + * Walk 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) +{ + 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 */ + } + } + return ata_cable_unknown(ap); } @@ -634,7 +665,7 @@ static struct ata_port_operations it821x_smart_port_ops = { .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, - .cable_detect = ata_cable_unknown, + .cable_detect = it821x_ident_hack, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 120b5bfa7ce6..030878fedeb5 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -42,13 +42,13 @@ static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error) return 0; } -static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +static unsigned int ixp4xx_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw) { unsigned int i; unsigned int words = buflen >> 1; u16 *buf16 = (u16 *) buf; - struct ata_port *ap = adev->link->ap; + struct ata_port *ap = dev->link->ap; void __iomem *mmio = ap->ioaddr.data_addr; struct ixp4xx_pata_data *data = ap->host->dev->platform_data; @@ -59,30 +59,32 @@ static void ixp4xx_mmio_data_xfer(struct ata_device *adev, unsigned char *buf, udelay(100); /* Transfer multiple of 2 bytes */ - if (write_data) { - for (i = 0; i < words; i++) - writew(buf16[i], mmio); - } else { + if (rw == READ) for (i = 0; i < words; i++) buf16[i] = readw(mmio); - } + else + for (i = 0; i < words; i++) + writew(buf16[i], mmio); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { u16 align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (write_data) { - memcpy(align_buf, trailing_buf, 1); - writew(align_buf[0], mmio); - } else { + if (rw == READ) { align_buf[0] = readw(mmio); memcpy(trailing_buf, align_buf, 1); + } else { + memcpy(align_buf, trailing_buf, 1); + writew(align_buf[0], mmio); } + words++; } udelay(100); *data->cs0_cfg |= 0x01; + + return words << 1; } static struct scsi_host_template ixp4xx_sht = { diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 17159b5e1e43..333dc15f8ccf 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -28,7 +28,6 @@ * * Unsupported but docs exist: * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220 - * Winbond W83759A * * This driver handles legacy (that is "ISA/VLB side") IDE ports found * on PC class systems. There are three hybrid devices that are exceptions @@ -36,7 +35,7 @@ * the MPIIX where the tuning is PCI side but the IDE is "ISA side". * * Specific support is included for the ht6560a/ht6560b/opti82c611a/ - * opti82c465mv/promise 20230c/20630 + * opti82c465mv/promise 20230c/20630/winbond83759A * * Use the autospeed and pio_mask options with: * Appian ADI/2 aka CLPD7220 or AIC25VL01. @@ -47,9 +46,6 @@ * For now use autospeed and pio_mask as above with the W83759A. This may * change. * - * TODO - * Merge existing pata_qdi driver - * */ #include <linux/kernel.h> @@ -64,12 +60,13 @@ #include <linux/platform_device.h> #define DRV_NAME "pata_legacy" -#define DRV_VERSION "0.5.5" +#define DRV_VERSION "0.6.5" #define NR_HOST 6 -static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; -static int legacy_irq[NR_HOST] = { 14, 15, 11, 10, 8, 12 }; +static int all; +module_param(all, int, 0444); +MODULE_PARM_DESC(all, "Grab all legacy port devices, even if PCI(0=off, 1=on)"); struct legacy_data { unsigned long timing; @@ -80,21 +77,107 @@ struct legacy_data { }; +enum controller { + BIOS = 0, + SNOOP = 1, + PDC20230 = 2, + HT6560A = 3, + HT6560B = 4, + OPTI611A = 5, + OPTI46X = 6, + QDI6500 = 7, + QDI6580 = 8, + QDI6580DP = 9, /* Dual channel mode is different */ + W83759A = 10, + + UNKNOWN = -1 +}; + + +struct legacy_probe { + unsigned char *name; + unsigned long port; + unsigned int irq; + unsigned int slot; + enum controller type; + unsigned long private; +}; + +struct legacy_controller { + const char *name; + struct ata_port_operations *ops; + unsigned int pio_mask; + unsigned int flags; + int (*setup)(struct platform_device *, struct legacy_probe *probe, + struct legacy_data *data); +}; + +static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; + +static struct legacy_probe probe_list[NR_HOST]; static struct legacy_data legacy_data[NR_HOST]; static struct ata_host *legacy_host[NR_HOST]; static int nr_legacy_host; -static int probe_all; /* Set to check all ISA port ranges */ -static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */ -static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */ -static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */ -static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */ -static int autospeed; /* Chip present which snoops speed changes */ -static int pio_mask = 0x1F; /* PIO range for autospeed devices */ +static int probe_all; /* Set to check all ISA port ranges */ +static int ht6560a; /* HT 6560A on primary 1, second 2, both 3 */ +static int ht6560b; /* HT 6560A on primary 1, second 2, both 3 */ +static int opti82c611a; /* Opti82c611A on primary 1, sec 2, both 3 */ +static int opti82c46x; /* Opti 82c465MV present(pri/sec autodetect) */ +static int qdi; /* Set to probe QDI controllers */ +static int winbond; /* Set to probe Winbond controllers, + give I/O port if non stdanard */ +static int autospeed; /* Chip present which snoops speed changes */ +static int pio_mask = 0x1F; /* PIO range for autospeed devices */ static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ /** + * legacy_probe_add - Add interface to probe list + * @port: Controller port + * @irq: IRQ number + * @type: Controller type + * @private: Controller specific info + * + * Add an entry into the probe list for ATA controllers. This is used + * to add the default ISA slots and then to build up the table + * further according to other ISA/VLB/Weird device scans + * + * An I/O port list is used to keep ordering stable and sane, as we + * don't have any good way to talk about ordering otherwise + */ + +static int legacy_probe_add(unsigned long port, unsigned int irq, + enum controller type, unsigned long private) +{ + struct legacy_probe *lp = &probe_list[0]; + int i; + struct legacy_probe *free = NULL; + + for (i = 0; i < NR_HOST; i++) { + if (lp->port == 0 && free == NULL) + free = lp; + /* Matching port, or the correct slot for ordering */ + if (lp->port == port || legacy_port[i] == port) { + free = lp; + break; + } + lp++; + } + if (free == NULL) { + printk(KERN_ERR "pata_legacy: Too many interfaces.\n"); + return -1; + } + /* Fill in the entry for later probing */ + free->port = port; + free->irq = irq; + free->type = type; + free->private = private; + return 0; +} + + +/** * legacy_set_mode - mode setting * @link: IDE link * @unused: Device that failed when error is returned @@ -113,7 +196,8 @@ static int legacy_set_mode(struct ata_link *link, struct ata_device **unused) ata_link_for_each_dev(dev, link) { if (ata_dev_enabled(dev)) { - ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); + ata_dev_printk(dev, KERN_INFO, + "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; @@ -171,7 +255,7 @@ static struct ata_port_operations simple_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; static struct ata_port_operations legacy_port_ops = { @@ -198,15 +282,16 @@ static struct ata_port_operations legacy_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* * Promise 20230C and 20620 support * - * This controller supports PIO0 to PIO2. We set PIO timings conservatively to - * allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to - * controller and PIO'd to the host and not supported. + * This controller supports PIO0 to PIO2. We set PIO timings + * conservatively to allow for 50MHz Vesa Local Bus. The 20620 DMA + * support is weird being DMA to controller and PIO'd to the host + * and not supported. */ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -221,8 +306,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) local_irq_save(flags); /* Unlock the control interface */ - do - { + do { inb(0x1F5); outb(inb(0x1F2) | 0x80, 0x1F2); inb(0x1F2); @@ -231,7 +315,7 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) inb(0x1F2); inb(0x1F2); } - while((inb(0x1F2) & 0x80) && --tries); + while ((inb(0x1F2) & 0x80) && --tries); local_irq_restore(flags); @@ -249,13 +333,14 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev) } -static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) +static unsigned int pdc_data_xfer_vlb(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; - int slop = buflen & 3; - unsigned long flags; + if (ata_id_has_dword_io(dev->id)) { + struct ata_port *ap = dev->link->ap; + int slop = buflen & 3; + unsigned long flags; - if (ata_id_has_dword_io(adev->id)) { local_irq_save(flags); /* Perform the 32bit I/O synchronization sequence */ @@ -264,26 +349,27 @@ static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsig ioread8(ap->ioaddr.nsect_addr); /* Now the data */ - - if (write_data) - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else + if (rw == READ) ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { - __le32 pad = 0; - if (write_data) { - memcpy(&pad, buf + buflen - slop, slop); - iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); - } else { + u32 pad; + if (rw == READ) { pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); memcpy(buf + buflen - slop, &pad, slop); + } else { + memcpy(&pad, buf + buflen - slop, slop); + iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); } + buflen += 4 - slop; } local_irq_restore(flags); - } - else - ata_data_xfer_noirq(adev, buf, buflen, write_data); + } else + buflen = ata_data_xfer_noirq(dev, buf, buflen, rw); + + return buflen; } static struct ata_port_operations pdc20230_port_ops = { @@ -310,14 +396,14 @@ static struct ata_port_operations pdc20230_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* * Holtek 6560A support * - * This controller supports PIO0 to PIO2 (no IORDY even though higher timings - * can be loaded). + * This controller supports PIO0 to PIO2 (no IORDY even though higher + * timings can be loaded). */ static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev) @@ -364,14 +450,14 @@ static struct ata_port_operations ht6560a_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* * Holtek 6560B support * - * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting - * unless we see an ATAPI device in which case we force it off. + * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO + * setting unless we see an ATAPI device in which case we force it off. * * FIXME: need to implement 2nd channel support. */ @@ -398,7 +484,7 @@ static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev) if (adev->class != ATA_DEV_ATA) { u8 rconf = inb(0x3E6); if (rconf & 0x24) { - rconf &= ~ 0x24; + rconf &= ~0x24; outb(rconf, 0x3E6); } } @@ -423,13 +509,13 @@ static struct ata_port_operations ht6560b_port_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ + .data_xfer = ata_data_xfer, /* FIXME: Check 32bit and noirq */ .irq_handler = ata_interrupt, .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -462,7 +548,8 @@ static u8 opti_syscfg(u8 reg) * This controller supports PIO0 to PIO3. */ -static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void opti82c611a_set_piomode(struct ata_port *ap, + struct ata_device *adev) { u8 active, recover, setup; struct ata_timing t; @@ -549,7 +636,7 @@ static struct ata_port_operations opti82c611a_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; /* @@ -681,77 +768,398 @@ static struct ata_port_operations opti82c46x_port_ops = { .irq_clear = ata_bmdma_irq_clear, .irq_on = ata_irq_on, - .port_start = ata_port_start, + .port_start = ata_sff_port_start, }; +static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing t; + struct legacy_data *qdi = ap->host->private_data; + int active, recovery; + u8 timing; + + /* Get the timing data in cycles */ + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + if (qdi->fast) { + active = 8 - FIT(t.active, 1, 8); + recovery = 18 - FIT(t.recover, 3, 18); + } else { + active = 9 - FIT(t.active, 2, 9); + recovery = 15 - FIT(t.recover, 0, 15); + } + timing = (recovery << 4) | active | 0x08; + + qdi->clock[adev->devno] = timing; + + outb(timing, qdi->timing); +} /** - * legacy_init_one - attach a legacy interface - * @port: port number - * @io: I/O port start - * @ctrl: control port + * qdi6580dp_set_piomode - PIO setup for dual channel + * @ap: Port + * @adev: Device * @irq: interrupt line * - * Register an ISA bus IDE interface. Such interfaces are PIO and we - * assume do not support IRQ sharing. + * In dual channel mode the 6580 has one clock per channel and we have + * to software clockswitch in qc_issue_prot. */ -static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq) +static void qdi6580dp_set_piomode(struct ata_port *ap, struct ata_device *adev) { - struct legacy_data *ld = &legacy_data[nr_legacy_host]; - struct ata_host *host; - struct ata_port *ap; - struct platform_device *pdev; - struct ata_port_operations *ops = &legacy_port_ops; - void __iomem *io_addr, *ctrl_addr; - int pio_modes = pio_mask; - u32 mask = (1 << port); - u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; - int ret; + struct ata_timing t; + struct legacy_data *qdi = ap->host->private_data; + int active, recovery; + u8 timing; - pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); + /* Get the timing data in cycles */ + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + if (qdi->fast) { + active = 8 - FIT(t.active, 1, 8); + recovery = 18 - FIT(t.recover, 3, 18); + } else { + active = 9 - FIT(t.active, 2, 9); + recovery = 15 - FIT(t.recover, 0, 15); + } + timing = (recovery << 4) | active | 0x08; - ret = -EBUSY; - if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || - devm_request_region(&pdev->dev, ctrl, 1, "pata_legacy") == NULL) - goto fail; + qdi->clock[adev->devno] = timing; - ret = -ENOMEM; - io_addr = devm_ioport_map(&pdev->dev, io, 8); - ctrl_addr = devm_ioport_map(&pdev->dev, ctrl, 1); - if (!io_addr || !ctrl_addr) - goto fail; + outb(timing, qdi->timing + 2 * ap->port_no); + /* Clear the FIFO */ + if (adev->class != ATA_DEV_ATA) + outb(0x5F, qdi->timing + 3); +} - if (ht6560a & mask) { - ops = &ht6560a_port_ops; - pio_modes = 0x07; - iordy = ATA_FLAG_NO_IORDY; - } - if (ht6560b & mask) { - ops = &ht6560b_port_ops; - pio_modes = 0x1F; - } - if (opti82c611a & mask) { - ops = &opti82c611a_port_ops; - pio_modes = 0x0F; +/** + * qdi6580_set_piomode - PIO setup for single channel + * @ap: Port + * @adev: Device + * + * In single channel mode the 6580 has one clock per device and we can + * avoid the requirement to clock switch. We also have to load the timing + * into the right clock according to whether we are master or slave. + */ + +static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing t; + struct legacy_data *qdi = ap->host->private_data; + int active, recovery; + u8 timing; + + /* Get the timing data in cycles */ + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + if (qdi->fast) { + active = 8 - FIT(t.active, 1, 8); + recovery = 18 - FIT(t.recover, 3, 18); + } else { + active = 9 - FIT(t.active, 2, 9); + recovery = 15 - FIT(t.recover, 0, 15); } - if (opti82c46x & mask) { - ops = &opti82c46x_port_ops; - pio_modes = 0x0F; + timing = (recovery << 4) | active | 0x08; + qdi->clock[adev->devno] = timing; + outb(timing, qdi->timing + 2 * adev->devno); + /* Clear the FIFO */ + if (adev->class != ATA_DEV_ATA) + outb(0x5F, qdi->timing + 3); +} + +/** + * qdi_qc_issue_prot - command issue + * @qc: command pending + * + * Called when the libata layer is about to issue a command. We wrap + * this interface so that we can load the correct ATA timings. + */ + +static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_device *adev = qc->dev; + struct legacy_data *qdi = ap->host->private_data; + + if (qdi->clock[adev->devno] != qdi->last) { + if (adev->pio_mode) { + qdi->last = qdi->clock[adev->devno]; + outb(qdi->clock[adev->devno], qdi->timing + + 2 * ap->port_no); + } } + return ata_qc_issue_prot(qc); +} - /* Probe for automatically detectable controllers */ +static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int rw) +{ + struct ata_port *ap = adev->link->ap; + int slop = buflen & 3; - if (io == 0x1F0 && ops == &legacy_port_ops) { - unsigned long flags; + if (ata_id_has_dword_io(adev->id)) { + if (rw == WRITE) + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - local_irq_save(flags); + if (unlikely(slop)) { + u32 pad; + if (rw == WRITE) { + memcpy(&pad, buf + buflen - slop, slop); + pad = le32_to_cpu(pad); + iowrite32(pad, ap->ioaddr.data_addr); + } else { + pad = ioread32(ap->ioaddr.data_addr); + pad = cpu_to_le32(pad); + memcpy(buf + buflen - slop, &pad, slop); + } + } + return (buflen + 3) & ~3; + } else + return ata_data_xfer(adev, buf, buflen, rw); +} + +static int qdi_port(struct platform_device *dev, + struct legacy_probe *lp, struct legacy_data *ld) +{ + if (devm_request_region(&dev->dev, lp->private, 4, "qdi") == NULL) + return -EBUSY; + ld->timing = lp->private; + return 0; +} + +static struct ata_port_operations qdi6500_port_ops = { + .set_piomode = qdi6500_set_piomode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = qdi_qc_issue_prot, + + .data_xfer = vlb32_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static struct ata_port_operations qdi6580_port_ops = { + .set_piomode = qdi6580_set_piomode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = vlb32_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static struct ata_port_operations qdi6580dp_port_ops = { + .set_piomode = qdi6580dp_set_piomode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = qdi_qc_issue_prot, + + .data_xfer = vlb32_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static DEFINE_SPINLOCK(winbond_lock); + +static void winbond_writecfg(unsigned long port, u8 reg, u8 val) +{ + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + outb(val, port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); +} + +static u8 winbond_readcfg(unsigned long port, u8 reg) +{ + u8 val; + + unsigned long flags; + spin_lock_irqsave(&winbond_lock, flags); + outb(reg, port + 0x01); + val = inb(port + 0x02); + spin_unlock_irqrestore(&winbond_lock, flags); + + return val; +} + +static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct ata_timing t; + struct legacy_data *winbond = ap->host->private_data; + int active, recovery; + u8 reg; + int timing = 0x88 + (ap->port_no * 4) + (adev->devno * 2); + + reg = winbond_readcfg(winbond->timing, 0x81); + + /* Get the timing data in cycles */ + if (reg & 0x40) /* Fast VLB bus, assume 50MHz */ + ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000); + else + ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000); + + active = (FIT(t.active, 3, 17) - 1) & 0x0F; + recovery = (FIT(t.recover, 1, 15) + 1) & 0x0F; + timing = (active << 4) | recovery; + winbond_writecfg(winbond->timing, timing, reg); + + /* Load the setup timing */ + + reg = 0x35; + if (adev->class != ATA_DEV_ATA) + reg |= 0x08; /* FIFO off */ + if (!ata_pio_need_iordy(adev)) + reg |= 0x02; /* IORDY off */ + reg |= (FIT(t.setup, 0, 3) << 6); + winbond_writecfg(winbond->timing, timing + 1, reg); +} + +static int winbond_port(struct platform_device *dev, + struct legacy_probe *lp, struct legacy_data *ld) +{ + if (devm_request_region(&dev->dev, lp->private, 4, "winbond") == NULL) + return -EBUSY; + ld->timing = lp->private; + return 0; +} + +static struct ata_port_operations winbond_port_ops = { + .set_piomode = winbond_set_piomode, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = vlb32_data_xfer, + + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + .port_start = ata_sff_port_start, +}; + +static struct legacy_controller controllers[] = { + {"BIOS", &legacy_port_ops, 0x1F, + ATA_FLAG_NO_IORDY, NULL }, + {"Snooping", &simple_port_ops, 0x1F, + 0 , NULL }, + {"PDC20230", &pdc20230_port_ops, 0x7, + ATA_FLAG_NO_IORDY, NULL }, + {"HT6560A", &ht6560a_port_ops, 0x07, + ATA_FLAG_NO_IORDY, NULL }, + {"HT6560B", &ht6560b_port_ops, 0x1F, + ATA_FLAG_NO_IORDY, NULL }, + {"OPTI82C611A", &opti82c611a_port_ops, 0x0F, + 0 , NULL }, + {"OPTI82C46X", &opti82c46x_port_ops, 0x0F, + 0 , NULL }, + {"QDI6500", &qdi6500_port_ops, 0x07, + ATA_FLAG_NO_IORDY, qdi_port }, + {"QDI6580", &qdi6580_port_ops, 0x1F, + 0 , qdi_port }, + {"QDI6580DP", &qdi6580dp_port_ops, 0x1F, + 0 , qdi_port }, + {"W83759A", &winbond_port_ops, 0x1F, + 0 , winbond_port } +}; + +/** + * probe_chip_type - Discover controller + * @probe: Probe entry to check + * + * Probe an ATA port and identify the type of controller. We don't + * check if the controller appears to be driveless at this point. + */ + +static __init int probe_chip_type(struct legacy_probe *probe) +{ + int mask = 1 << probe->slot; + + if (winbond && (probe->port == 0x1F0 || probe->port == 0x170)) { + u8 reg = winbond_readcfg(winbond, 0x81); + reg |= 0x80; /* jumpered mode off */ + winbond_writecfg(winbond, 0x81, reg); + reg = winbond_readcfg(winbond, 0x83); + reg |= 0xF0; /* local control */ + winbond_writecfg(winbond, 0x83, reg); + reg = winbond_readcfg(winbond, 0x85); + reg |= 0xF0; /* programmable timing */ + winbond_writecfg(winbond, 0x85, reg); + + reg = winbond_readcfg(winbond, 0x81); + + if (reg & mask) + return W83759A; + } + if (probe->port == 0x1F0) { + unsigned long flags; + local_irq_save(flags); /* Probes */ - inb(0x1F5); outb(inb(0x1F2) | 0x80, 0x1F2); + inb(0x1F5); inb(0x1F2); inb(0x3F6); inb(0x3F6); @@ -760,29 +1168,83 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl if ((inb(0x1F2) & 0x80) == 0) { /* PDC20230c or 20630 ? */ - printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n"); - pio_modes = 0x07; - ops = &pdc20230_port_ops; - iordy = ATA_FLAG_NO_IORDY; + printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller" + " detected.\n"); udelay(100); inb(0x1F5); + local_irq_restore(flags); + return PDC20230; } else { outb(0x55, 0x1F2); inb(0x1F2); inb(0x1F2); - if (inb(0x1F2) == 0x00) { - printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n"); - } + if (inb(0x1F2) == 0x00) + printk(KERN_INFO "PDC20230-B VLB ATA " + "controller detected.\n"); + local_irq_restore(flags); + return BIOS; } local_irq_restore(flags); } + if (ht6560a & mask) + return HT6560A; + if (ht6560b & mask) + return HT6560B; + if (opti82c611a & mask) + return OPTI611A; + if (opti82c46x & mask) + return OPTI46X; + if (autospeed & mask) + return SNOOP; + return BIOS; +} + + +/** + * legacy_init_one - attach a legacy interface + * @pl: probe record + * + * Register an ISA bus IDE interface. Such interfaces are PIO and we + * assume do not support IRQ sharing. + */ + +static __init int legacy_init_one(struct legacy_probe *probe) +{ + struct legacy_controller *controller = &controllers[probe->type]; + int pio_modes = controller->pio_mask; + unsigned long io = probe->port; + u32 mask = (1 << probe->slot); + struct ata_port_operations *ops = controller->ops; + struct legacy_data *ld = &legacy_data[probe->slot]; + struct ata_host *host = NULL; + struct ata_port *ap; + struct platform_device *pdev; + struct ata_device *dev; + void __iomem *io_addr, *ctrl_addr; + u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; + int ret; - /* Chip does mode setting by command snooping */ - if (ops == &legacy_port_ops && (autospeed & mask)) - ops = &simple_port_ops; + iordy |= controller->flags; + + pdev = platform_device_register_simple(DRV_NAME, probe->slot, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + ret = -EBUSY; + if (devm_request_region(&pdev->dev, io, 8, "pata_legacy") == NULL || + devm_request_region(&pdev->dev, io + 0x0206, 1, + "pata_legacy") == NULL) + goto fail; ret = -ENOMEM; + io_addr = devm_ioport_map(&pdev->dev, io, 8); + ctrl_addr = devm_ioport_map(&pdev->dev, io + 0x0206, 1); + if (!io_addr || !ctrl_addr) + goto fail; + if (controller->setup) + if (controller->setup(pdev, probe, ld) < 0) + goto fail; host = ata_host_alloc(&pdev->dev, 1); if (!host) goto fail; @@ -795,19 +1257,29 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ap->ioaddr.altstatus_addr = ctrl_addr; ap->ioaddr.ctl_addr = ctrl_addr; ata_std_ports(&ap->ioaddr); - ap->private_data = ld; + ap->host->private_data = ld; - ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl); + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, io + 0x0206); - ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht); + ret = ata_host_activate(host, probe->irq, ata_interrupt, 0, + &legacy_sht); if (ret) goto fail; - - legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev); ld->platform_dev = pdev; - return 0; + /* Nothing found means we drop the port as its probably not there */ + + ret = -ENODEV; + ata_link_for_each_dev(dev, &ap->link) { + if (!ata_dev_absent(dev)) { + legacy_host[probe->slot] = host; + ld->platform_dev = pdev; + return 0; + } + } fail: + if (host) + ata_host_detach(host); platform_device_unregister(pdev); return ret; } @@ -818,13 +1290,15 @@ fail: * @master: set this if we find an ATA master * @master: set this if we find an ATA secondary * - * A small number of vendors implemented early PCI ATA interfaces on bridge logic - * without the ATA interface being PCI visible. Where we have a matching PCI driver - * we must skip the relevant device here. If we don't know about it then the legacy - * driver is the right driver anyway. + * A small number of vendors implemented early PCI ATA interfaces + * on bridge logic without the ATA interface being PCI visible. + * Where we have a matching PCI driver we must skip the relevant + * device here. If we don't know about it then the legacy driver + * is the right driver anyway. */ -static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary) +static void __init legacy_check_special_cases(struct pci_dev *p, int *primary, + int *secondary) { /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */ if (p->vendor == 0x1078 && p->device == 0x0000) { @@ -840,7 +1314,8 @@ static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *sec if (p->vendor == 0x8086 && p->device == 0x1234) { u16 r; pci_read_config_word(p, 0x6C, &r); - if (r & 0x8000) { /* ATA port enabled */ + if (r & 0x8000) { + /* ATA port enabled */ if (r & 0x4000) *secondary = 1; else @@ -850,6 +1325,114 @@ static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *sec } } +static __init void probe_opti_vlb(void) +{ + /* If an OPTI 82C46X is present find out where the channels are */ + static const char *optis[4] = { + "3/463MV", "5MV", + "5MVA", "5MVB" + }; + u8 chans = 1; + u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; + + opti82c46x = 3; /* Assume master and slave first */ + printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", + optis[ctrl]); + if (ctrl == 3) + chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; + ctrl = opti_syscfg(0xAC); + /* Check enabled and this port is the 465MV port. On the + MVB we may have two channels */ + if (ctrl & 8) { + if (chans == 2) { + legacy_probe_add(0x1F0, 14, OPTI46X, 0); + legacy_probe_add(0x170, 15, OPTI46X, 0); + } + if (ctrl & 4) + legacy_probe_add(0x170, 15, OPTI46X, 0); + else + legacy_probe_add(0x1F0, 14, OPTI46X, 0); + } else + legacy_probe_add(0x1F0, 14, OPTI46X, 0); +} + +static __init void qdi65_identify_port(u8 r, u8 res, unsigned long port) +{ + static const unsigned long ide_port[2] = { 0x170, 0x1F0 }; + /* Check card type */ + if ((r & 0xF0) == 0xC0) { + /* QD6500: single channel */ + if (r & 8) + /* Disabled ? */ + return; + legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), + QDI6500, port); + } + if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { + /* QD6580: dual channel */ + if (!request_region(port + 2 , 2, "pata_qdi")) { + release_region(port, 2); + return; + } + res = inb(port + 3); + /* Single channel mode ? */ + if (res & 1) + legacy_probe_add(ide_port[r & 0x01], 14 + (r & 0x01), + QDI6580, port); + else { /* Dual channel mode */ + legacy_probe_add(0x1F0, 14, QDI6580DP, port); + /* port + 0x02, r & 0x04 */ + legacy_probe_add(0x170, 15, QDI6580DP, port + 2); + } + release_region(port + 2, 2); + } +} + +static __init void probe_qdi_vlb(void) +{ + unsigned long flags; + static const unsigned long qd_port[2] = { 0x30, 0xB0 }; + int i; + + /* + * Check each possible QD65xx base address + */ + + for (i = 0; i < 2; i++) { + unsigned long port = qd_port[i]; + u8 r, res; + + + if (request_region(port, 2, "pata_qdi")) { + /* Check for a card */ + local_irq_save(flags); + /* I have no h/w that needs this delay but it + is present in the historic code */ + r = inb(port); + udelay(1); + outb(0x19, port); + udelay(1); + res = inb(port); + udelay(1); + outb(r, port); + udelay(1); + local_irq_restore(flags); + + /* Fail */ + if (res == 0x19) { + release_region(port, 2); + continue; + } + /* Passes the presence test */ + r = inb(port + 1); + udelay(1); + /* Check port agrees with port set */ + if ((r & 2) >> 1 == i) + qdi65_identify_port(r, res, port); + release_region(port, 2); + } + } +} /** * legacy_init - attach legacy interfaces @@ -867,15 +1450,17 @@ static __init int legacy_init(void) int ct = 0; int primary = 0; int secondary = 0; - int last_port = NR_HOST; + int pci_present = 0; + struct legacy_probe *pl = &probe_list[0]; + int slot = 0; struct pci_dev *p = NULL; for_each_pci_dev(p) { int r; - /* Check for any overlap of the system ATA mappings. Native mode controllers - stuck on these addresses or some devices in 'raid' mode won't be found by - the storage class test */ + /* Check for any overlap of the system ATA mappings. Native + mode controllers stuck on these addresses or some devices + in 'raid' mode won't be found by the storage class test */ for (r = 0; r < 6; r++) { if (pci_resource_start(p, r) == 0x1f0) primary = 1; @@ -885,49 +1470,39 @@ static __init int legacy_init(void) /* Check for special cases */ legacy_check_special_cases(p, &primary, &secondary); - /* If PCI bus is present then don't probe for tertiary legacy ports */ - if (probe_all == 0) - last_port = 2; + /* If PCI bus is present then don't probe for tertiary + legacy ports */ + pci_present = 1; } - /* If an OPTI 82C46X is present find out where the channels are */ - if (opti82c46x) { - static const char *optis[4] = { - "3/463MV", "5MV", - "5MVA", "5MVB" - }; - u8 chans = 1; - u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6; - - opti82c46x = 3; /* Assume master and slave first */ - printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]); - if (ctrl == 3) - chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1; - ctrl = opti_syscfg(0xAC); - /* Check enabled and this port is the 465MV port. On the - MVB we may have two channels */ - if (ctrl & 8) { - if (ctrl & 4) - opti82c46x = 2; /* Slave */ - else - opti82c46x = 1; /* Master */ - if (chans == 2) - opti82c46x = 3; /* Master and Slave */ - } /* Slave only */ - else if (chans == 1) - opti82c46x = 1; + if (winbond == 1) + winbond = 0x130; /* Default port, alt is 1B0 */ + + if (primary == 0 || all) + legacy_probe_add(0x1F0, 14, UNKNOWN, 0); + if (secondary == 0 || all) + legacy_probe_add(0x170, 15, UNKNOWN, 0); + + if (probe_all || !pci_present) { + /* ISA/VLB extra ports */ + legacy_probe_add(0x1E8, 11, UNKNOWN, 0); + legacy_probe_add(0x168, 10, UNKNOWN, 0); + legacy_probe_add(0x1E0, 8, UNKNOWN, 0); + legacy_probe_add(0x160, 12, UNKNOWN, 0); } - for (i = 0; i < last_port; i++) { - /* Skip primary if we have seen a PCI one */ - if (i == 0 && primary == 1) - continue; - /* Skip secondary if we have seen a PCI one */ - if (i == 1 && secondary == 1) + if (opti82c46x) + probe_opti_vlb(); + if (qdi) + probe_qdi_vlb(); + + for (i = 0; i < NR_HOST; i++, pl++) { + if (pl->port == 0) continue; - if (legacy_init_one(i, legacy_port[i], - legacy_port[i] + 0x0206, - legacy_irq[i]) == 0) + if (pl->type == UNKNOWN) + pl->type = probe_chip_type(pl); + pl->slot = slot++; + if (legacy_init_one(pl) == 0) ct++; } if (ct != 0) @@ -941,11 +1516,8 @@ static __exit void legacy_exit(void) for (i = 0; i < nr_legacy_host; i++) { struct legacy_data *ld = &legacy_data[i]; - ata_host_detach(legacy_host[i]); platform_device_unregister(ld->platform_dev); - if (ld->timing) - release_region(ld->timing, 2); } } @@ -960,9 +1532,9 @@ module_param(ht6560a, int, 0); module_param(ht6560b, int, 0); module_param(opti82c611a, int, 0); module_param(opti82c46x, int, 0); +module_param(qdi, int, 0); module_param(pio_mask, int, 0); module_param(iordy_mask, int, 0); module_init(legacy_init); module_exit(legacy_exit); - diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 1a7ca37168b2..5413ebfa72e5 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -364,7 +364,7 @@ mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) { unsigned int ipb_freq; struct resource res_mem; - int ata_irq = NO_IRQ; + int ata_irq; struct mpc52xx_ata __iomem *ata_regs; struct mpc52xx_ata_priv *priv; int rv; diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c new file mode 100644 index 000000000000..1c1b83541d13 --- /dev/null +++ b/drivers/ata/pata_ninja32.c @@ -0,0 +1,214 @@ +/* + * pata_ninja32.c - Ninja32 PATA for new ATA layer + * (C) 2007 Red Hat Inc + * Alan Cox <alan@redhat.com> + * + * Note: The controller like many controllers has shared timings for + * PIO and DMA. We thus flip to the DMA timings in dma_start and flip back + * in the dma_stop function. Thus we actually don't need a set_dmamode + * method as the PIO method is always called and will set the right PIO + * timing parameters. + * + * The Ninja32 Cardbus is not a generic SFF controller. Instead it is + * laid out as follows off BAR 0. This is based upon Mark Lord's delkin + * driver and the extensive analysis done by the BSD developers, notably + * ITOH Yasufumi. + * + * Base + 0x00 IRQ Status + * Base + 0x01 IRQ control + * Base + 0x02 Chipset control + * Base + 0x04 VDMA and reset control + wait bits + * Base + 0x08 BMIMBA + * Base + 0x0C DMA Length + * Base + 0x10 Taskfile + * Base + 0x18 BMDMA Status ? + * Base + 0x1C + * Base + 0x1D Bus master control + * bit 0 = enable + * bit 1 = 0 write/1 read + * bit 2 = 1 sgtable + * bit 3 = go + * bit 4-6 wait bits + * bit 7 = done + * Base + 0x1E AltStatus + * Base + 0x1F timing register + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <scsi/scsi_host.h> +#include <linux/libata.h> + +#define DRV_NAME "pata_ninja32" +#define DRV_VERSION "0.0.1" + + +/** + * ninja32_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + * + * Called to do the PIO mode setup. Our timing registers are shared + * but we want to set the PIO timing by default. + */ + +static void ninja32_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + static u16 pio_timing[5] = { + 0xd6, 0x85, 0x44, 0x33, 0x13 + }; + iowrite8(pio_timing[adev->pio_mode - XFER_PIO_0], + ap->ioaddr.bmdma_addr + 0x1f); + ap->private_data = adev; +} + + +static void ninja32_dev_select(struct ata_port *ap, unsigned int device) +{ + struct ata_device *adev = &ap->link.device[device]; + if (ap->private_data != adev) { + iowrite8(0xd6, ap->ioaddr.bmdma_addr + 0x1f); + ata_std_dev_select(ap, device); + ninja32_set_piomode(ap, adev); + } +} + +static struct scsi_host_template ninja32_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +}; + +static struct ata_port_operations ninja32_port_ops = { + .set_piomode = ninja32_set_piomode, + .mode_filter = ata_pci_default_filter, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ninja32_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + +static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct ata_host *host; + struct ata_port *ap; + void __iomem *base; + int rc; + + host = ata_host_alloc(&dev->dev, 1); + if (!host) + return -ENOMEM; + ap = host->ports[0]; + + /* Set up the PCI device */ + rc = pcim_enable_device(dev); + if (rc) + return rc; + rc = pcim_iomap_regions(dev, 1 << 0, DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(dev); + if (rc) + return rc; + + host->iomap = pcim_iomap_table(dev); + rc = pci_set_dma_mask(dev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(dev, ATA_DMA_MASK); + if (rc) + return rc; + pci_set_master(dev); + + /* Set up the register mappings */ + base = host->iomap[0]; + if (!base) + return -ENOMEM; + ap->ops = &ninja32_port_ops; + ap->pio_mask = 0x1F; + ap->flags |= ATA_FLAG_SLAVE_POSS; + + ap->ioaddr.cmd_addr = base + 0x10; + ap->ioaddr.ctl_addr = base + 0x1E; + ap->ioaddr.altstatus_addr = base + 0x1E; + ap->ioaddr.bmdma_addr = base; + ata_std_ports(&ap->ioaddr); + + iowrite8(0x05, base + 0x01); /* Enable interrupt lines */ + iowrite8(0xB3, base + 0x02); /* Burst, ?? setup */ + iowrite8(0x00, base + 0x04); /* WAIT0 ? */ + /* FIXME: Should we disable them at remove ? */ + return ata_host_activate(host, dev->irq, ata_interrupt, + IRQF_SHARED, &ninja32_sht); +} + +static const struct pci_device_id ninja32[] = { + { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x1145, 0xf024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { }, +}; + +static struct pci_driver ninja32_pci_driver = { + .name = DRV_NAME, + .id_table = ninja32, + .probe = ninja32_init_one, + .remove = ata_pci_remove_one +}; + +static int __init ninja32_init(void) +{ + return pci_register_driver(&ninja32_pci_driver); +} + +static void __exit ninja32_exit(void) +{ + pci_unregister_driver(&ninja32_pci_driver); +} + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("low-level driver for Ninja32 ATA"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ninja32); +MODULE_VERSION(DRV_VERSION); + +module_init(ninja32_init); +module_exit(ninja32_exit); diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index fd36099428a4..3e7f6a9da28b 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -42,7 +42,7 @@ #define DRV_NAME "pata_pcmcia" -#define DRV_VERSION "0.3.2" +#define DRV_VERSION "0.3.3" /* * Private data structure to glue stuff together @@ -86,6 +86,47 @@ static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_d return ata_do_set_mode(link, r_failed_dev); } +/** + * pcmcia_set_mode_8bit - PCMCIA specific mode setup + * @link: link + * @r_failed_dev: Return pointer for failed device + * + * For the simple emulated 8bit stuff the less we do the better. + */ + +static int pcmcia_set_mode_8bit(struct ata_link *link, + struct ata_device **r_failed_dev) +{ + return 0; +} + +/** + * ata_data_xfer_8bit - Transfer data by 8bit PIO + * @dev: device to target + * @buf: data buffer + * @buflen: buffer length + * @rw: read/write + * + * Transfer data from/to the device data register by 8 bit PIO. + * + * LOCKING: + * Inherited from caller. + */ + +static unsigned int ata_data_xfer_8bit(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw) +{ + struct ata_port *ap = dev->link->ap; + + if (rw == READ) + ioread8_rep(ap->ioaddr.data_addr, buf, buflen); + else + iowrite8_rep(ap->ioaddr.data_addr, buf, buflen); + + return buflen; +} + + static struct scsi_host_template pcmcia_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -129,6 +170,31 @@ static struct ata_port_operations pcmcia_port_ops = { .port_start = ata_sff_port_start, }; +static struct ata_port_operations pcmcia_8bit_port_ops = { + .set_mode = pcmcia_set_mode_8bit, + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + .cable_detect = ata_cable_40wire, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .data_xfer = ata_data_xfer_8bit, + + .irq_clear = ata_bmdma_irq_clear, + .irq_on = ata_irq_on, + + .port_start = ata_sff_port_start, +}; + #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) @@ -153,9 +219,12 @@ static int pcmcia_init_one(struct pcmcia_device *pdev) cistpl_cftable_entry_t dflt; } *stk = NULL; cistpl_cftable_entry_t *cfg; - int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM; + int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM, p; unsigned long io_base, ctl_base; void __iomem *io_addr, *ctl_addr; + int n_ports = 1; + + struct ata_port_operations *ops = &pcmcia_port_ops; info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) @@ -282,27 +351,32 @@ next_entry: /* FIXME: Could be more ports at base + 0x10 but we only deal with one right now */ if (pdev->io.NumPorts1 >= 0x20) - printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n"); + n_ports = 2; + if (pdev->manf_id == 0x0097 && pdev->card_id == 0x1620) + ops = &pcmcia_8bit_port_ops; /* * Having done the PCMCIA plumbing the ATA side is relatively * sane. */ ret = -ENOMEM; - host = ata_host_alloc(&pdev->dev, 1); + host = ata_host_alloc(&pdev->dev, n_ports); if (!host) goto failed; - ap = host->ports[0]; - ap->ops = &pcmcia_port_ops; - ap->pio_mask = 1; /* ISA so PIO 0 cycles */ - ap->flags |= ATA_FLAG_SLAVE_POSS; - ap->ioaddr.cmd_addr = io_addr; - ap->ioaddr.altstatus_addr = ctl_addr; - ap->ioaddr.ctl_addr = ctl_addr; - ata_std_ports(&ap->ioaddr); + for (p = 0; p < n_ports; p++) { + ap = host->ports[p]; - ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); + ap->ops = ops; + ap->pio_mask = 1; /* ISA so PIO 0 cycles */ + ap->flags |= ATA_FLAG_SLAVE_POSS; + ap->ioaddr.cmd_addr = io_addr + 0x10 * p; + ap->ioaddr.altstatus_addr = ctl_addr + 0x10 * p; + ap->ioaddr.ctl_addr = ctl_addr + 0x10 * p; + ata_std_ports(&ap->ioaddr); + + ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base); + } /* activate */ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt, @@ -360,6 +434,7 @@ static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904), PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ + PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 2622577521a1..028af5dbeed6 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -348,7 +348,7 @@ static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long ata_id_c_string(pair->id, model_num, ATA_ID_PROD, ATA_ID_PROD_LEN + 1); /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */ - if (strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6) + if (strstr(model_num, "Maxtor") == NULL && pair->dma_mode == XFER_UDMA_6) mask &= ~ (1 << (6 + ATA_SHIFT_UDMA)); return ata_pci_default_filter(adev, mask); diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 6c9689b59b06..3ed866723e0c 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -168,8 +168,7 @@ static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc) pdc202xx_set_dmamode(ap, qc->dev); /* Cases the state machine will not complete correctly without help */ - if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA) - { + if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATAPI_PROT_DMA) { len = qc->nbytes / 2; if (tf->flags & ATA_TFLAG_WRITE) @@ -208,7 +207,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc) void __iomem *atapi_reg = master + 0x20 + (4 * ap->port_no); /* Cases the state machine will not complete correctly */ - if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) { + if (tf->protocol == ATAPI_PROT_DMA || (tf->flags & ATA_TFLAG_LBA48)) { iowrite32(0, atapi_reg); iowrite8(ioread8(clock) & ~sel66, clock); } diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index a4c0e502cb42..9f308ed76cc8 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -124,29 +124,33 @@ static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc) return ata_qc_issue_prot(qc); } -static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) +static unsigned int qdi_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; - int slop = buflen & 3; + if (ata_id_has_dword_io(dev->id)) { + struct ata_port *ap = dev->link->ap; + int slop = buflen & 3; - if (ata_id_has_dword_io(adev->id)) { - if (write_data) - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else + if (rw == READ) ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { - __le32 pad = 0; - if (write_data) { - memcpy(&pad, buf + buflen - slop, slop); - iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); - } else { + u32 pad; + if (rw == READ) { pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); memcpy(buf + buflen - slop, &pad, slop); + } else { + memcpy(&pad, buf + buflen - slop, slop); + iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); } + buflen += 4 - slop; } } else - ata_data_xfer(adev, buf, buflen, write_data); + buflen = ata_data_xfer(dev, buf, buflen, rw); + + return buflen; } static struct scsi_host_template qdi_sht = { diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index ea2ef9fc15be..55055b27524c 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -768,45 +768,47 @@ static u8 scc_bmdma_status (struct ata_port *ap) /** * scc_data_xfer - Transfer data by PIO - * @adev: device for this I/O + * @dev: device for this I/O * @buf: data buffer * @buflen: buffer length - * @write_data: read/write + * @rw: read/write * * Note: Original code is ata_data_xfer(). */ -static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, - unsigned int buflen, int write_data) +static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; + struct ata_port *ap = dev->link->ap; unsigned int words = buflen >> 1; unsigned int i; u16 *buf16 = (u16 *) buf; void __iomem *mmio = ap->ioaddr.data_addr; /* Transfer multiple of 2 bytes */ - if (write_data) { - for (i = 0; i < words; i++) - out_be32(mmio, cpu_to_le16(buf16[i])); - } else { + if (rw == READ) for (i = 0; i < words; i++) buf16[i] = le16_to_cpu(in_be32(mmio)); - } + else + for (i = 0; i < words; i++) + out_be32(mmio, cpu_to_le16(buf16[i])); /* Transfer trailing 1 byte, if any. */ if (unlikely(buflen & 0x01)) { u16 align_buf[1] = { 0 }; unsigned char *trailing_buf = buf + buflen - 1; - if (write_data) { - memcpy(align_buf, trailing_buf, 1); - out_be32(mmio, cpu_to_le16(align_buf[0])); - } else { + if (rw == READ) { align_buf[0] = le16_to_cpu(in_be32(mmio)); memcpy(trailing_buf, align_buf, 1); + } else { + memcpy(align_buf, trailing_buf, 1); + out_be32(mmio, cpu_to_le16(align_buf[0])); } + words++; } + + return words << 1; } /** diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index 8bed88873720..9c523fbf529e 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -41,7 +41,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_serverworks" -#define DRV_VERSION "0.4.2" +#define DRV_VERSION "0.4.3" #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ @@ -102,7 +102,7 @@ static int osb4_cable(struct ata_port *ap) { } /** - * csb4_cable - CSB5/6 cable detect + * csb_cable - CSB5/6 cable detect * @ap: ATA port to check * * Serverworks default arrangement is to use the drive side detection @@ -110,7 +110,7 @@ static int osb4_cable(struct ata_port *ap) { */ static int csb_cable(struct ata_port *ap) { - return ATA_CBL_PATA80; + return ATA_CBL_PATA_UNK; } struct sv_cable_table { @@ -231,7 +231,6 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo return ata_pci_default_filter(adev, mask); } - /** * serverworks_set_piomode - set initial PIO mode data * @ap: ATA interface @@ -243,7 +242,7 @@ static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned lo static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev) { static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; - int offset = 1 + (2 * ap->port_no) - adev->devno; + int offset = 1 + 2 * ap->port_no - adev->devno; int devbits = (2 * ap->port_no + adev->devno) * 4; u16 csb5_pio; struct pci_dev *pdev = to_pci_dev(ap->host->dev); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 453d72bf2598..39627ab684bf 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -185,7 +185,8 @@ static int via_cable_detect(struct ata_port *ap) { if (ata66 & (0x10100000 >> (16 * ap->port_no))) return ATA_CBL_PATA80; /* Check with ACPI so we can spot BIOS reported SATA bridges */ - if (ata_acpi_cbl_80wire(ap)) + if (ata_acpi_init_gtm(ap) && + ata_acpi_cbl_80wire(ap, ata_acpi_init_gtm(ap))) return ATA_CBL_PATA80; return ATA_CBL_PATA40; } diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 7116a9e7a8b2..99c92eda217b 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -92,29 +92,33 @@ static void winbond_set_piomode(struct ata_port *ap, struct ata_device *adev) } -static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) +static unsigned int winbond_data_xfer(struct ata_device *dev, + unsigned char *buf, unsigned int buflen, int rw) { - struct ata_port *ap = adev->link->ap; + struct ata_port *ap = dev->link->ap; int slop = buflen & 3; - if (ata_id_has_dword_io(adev->id)) { - if (write_data) - iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); - else + if (ata_id_has_dword_io(dev->id)) { + if (rw == READ) ioread32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); + else + iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2); if (unlikely(slop)) { - __le32 pad = 0; - if (write_data) { - memcpy(&pad, buf + buflen - slop, slop); - iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); - } else { + u32 pad; + if (rw == READ) { pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); memcpy(buf + buflen - slop, &pad, slop); + } else { + memcpy(&pad, buf + buflen - slop, slop); + iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); } + buflen += 4 - slop; } } else - ata_data_xfer(adev, buf, buflen, write_data); + buflen = ata_data_xfer(dev, buf, buflen, rw); + + return buflen; } static struct scsi_host_template winbond_sht = { @@ -191,7 +195,7 @@ static __init int winbond_init_one(unsigned long port) reg = winbond_readcfg(port, 0x81); if (!(reg & 0x03)) /* Disabled */ - return 0; + return -ENODEV; for (i = 0; i < 2 ; i ++) { unsigned long cmd_port = 0x1F0 - (0x80 * i); diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index bd4c2a3c88d7..8e1b7e9c0ae4 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -321,8 +321,9 @@ static int adma_fill_sg(struct ata_queued_cmd *qc) u8 *buf = pp->pkt, *last_buf = NULL; int i = (2 + buf[3]) * 8; u8 pFLAGS = pORD | ((qc->tf.flags & ATA_TFLAG_WRITE) ? pDIRO : 0); + unsigned int si; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { u32 addr; u32 len; @@ -455,7 +456,7 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc) adma_packet_start(qc); return 0; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: BUG(); break; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index d015b4adcfe0..922d7b2efba8 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -333,13 +333,14 @@ static unsigned int sata_fsl_fill_sg(struct ata_queued_cmd *qc, void *cmd_desc, struct prde *prd_ptr_to_indirect_ext = NULL; unsigned indirect_ext_segment_sz = 0; dma_addr_t indirect_ext_segment_paddr; + unsigned int si; VPRINTK("SATA FSL : cd = 0x%x, prd = 0x%x\n", cmd_desc, prd); indirect_ext_segment_paddr = cmd_desc_paddr + SATA_FSL_CMD_DESC_OFFSET_TO_PRDT + SATA_FSL_MAX_PRD_DIRECT * 16; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { dma_addr_t sg_addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); @@ -417,7 +418,7 @@ static void sata_fsl_qc_prep(struct ata_queued_cmd *qc) } /* setup "ACMD - atapi command" in cmd. desc. if this is ATAPI cmd */ - if (is_atapi_taskfile(&qc->tf)) { + if (ata_is_atapi(qc->tf.protocol)) { desc_info |= ATAPI_CMD; memset((void *)&cd->acmd, 0, 32); memcpy((void *)&cd->acmd, qc->cdb, qc->dev->cdb_len); diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 323c087e8cc1..96e614a1c169 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -585,7 +585,7 @@ static struct ata_port_operations inic_port_ops = { }; static struct ata_port_info inic_port_info = { - /* For some reason, ATA_PROT_ATAPI is broken on this + /* For some reason, ATAPI_PROT_PIO is broken on this * controller, and no, PIO_POLLING does't fix it. It somehow * manages to report the wrong ireason and ignoring ireason * results in machine lock up. Tell libata to always prefer diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 37b850ae0845..7e72463a90eb 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1136,9 +1136,10 @@ static void mv_fill_sg(struct ata_queued_cmd *qc) struct mv_port_priv *pp = qc->ap->private_data; struct scatterlist *sg; struct mv_sg *mv_sg, *last_sg = NULL; + unsigned int si; mv_sg = pp->sg_tbl; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { dma_addr_t addr = sg_dma_address(sg); u32 sg_len = sg_dma_len(sg); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index ed5dc7cb50cd..a0f98fdab7a0 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1336,21 +1336,18 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) { struct nv_adma_port_priv *pp = qc->ap->private_data; - unsigned int idx; struct nv_adma_prd *aprd; struct scatterlist *sg; + unsigned int si; VPRINTK("ENTER\n"); - idx = 0; - - ata_for_each_sg(sg, qc) { - aprd = (idx < 5) ? &cpb->aprd[idx] : - &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (idx-5)]; - nv_adma_fill_aprd(qc, sg, idx, aprd); - idx++; + for_each_sg(qc->sg, sg, qc->n_elem, si) { + aprd = (si < 5) ? &cpb->aprd[si] : + &pp->aprd[NV_ADMA_SGTBL_LEN * qc->tag + (si-5)]; + nv_adma_fill_aprd(qc, sg, si, aprd); } - if (idx > 5) + if (si > 5) cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); else cpb->next_aprd = cpu_to_le64(0); @@ -1995,17 +1992,14 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int idx; struct nv_swncq_port_priv *pp = ap->private_data; struct ata_prd *prd; - - WARN_ON(qc->__sg == NULL); - WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); + unsigned int si, idx; prd = pp->prd + ATA_MAX_PRD * qc->tag; idx = 0; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { u32 addr, offset; u32 sg_len, len; @@ -2027,8 +2021,7 @@ static void nv_swncq_fill_sg(struct ata_queued_cmd *qc) } } - if (idx) - prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap, diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index 7914def54fa3..a07d319f6e8c 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -450,19 +450,19 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) struct pdc_port_priv *pp = ap->private_data; u8 *buf = pp->pkt; u32 *buf32 = (u32 *) buf; - unsigned int dev_sel, feature, nbytes; + unsigned int dev_sel, feature; /* set control bits (byte 0), zero delay seq id (byte 3), * and seq id (byte 2) */ switch (qc->tf.protocol) { - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: if (!(qc->tf.flags & ATA_TFLAG_WRITE)) buf32[0] = cpu_to_le32(PDC_PKT_READ); else buf32[0] = 0; break; - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_NODATA: buf32[0] = cpu_to_le32(PDC_PKT_NODATA); break; default: @@ -473,45 +473,37 @@ static void pdc_atapi_pkt(struct ata_queued_cmd *qc) buf32[2] = 0; /* no next-packet */ /* select drive */ - if (sata_scr_valid(&ap->link)) { + if (sata_scr_valid(&ap->link)) dev_sel = PDC_DEVICE_SATA; - } else { - dev_sel = ATA_DEVICE_OBS; - if (qc->dev->devno != 0) - dev_sel |= ATA_DEV1; - } + else + dev_sel = qc->tf.device; + buf[12] = (1 << 5) | ATA_REG_DEVICE; buf[13] = dev_sel; buf[14] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_CLEAR_BSY; buf[15] = dev_sel; /* once more, waiting for BSY to clear */ buf[16] = (1 << 5) | ATA_REG_NSECT; - buf[17] = 0x00; + buf[17] = qc->tf.nsect; buf[18] = (1 << 5) | ATA_REG_LBAL; - buf[19] = 0x00; + buf[19] = qc->tf.lbal; /* set feature and byte counter registers */ - if (qc->tf.protocol != ATA_PROT_ATAPI_DMA) { + if (qc->tf.protocol != ATAPI_PROT_DMA) feature = PDC_FEATURE_ATAPI_PIO; - /* set byte counter register to real transfer byte count */ - nbytes = qc->nbytes; - if (nbytes > 0xffff) - nbytes = 0xffff; - } else { + else feature = PDC_FEATURE_ATAPI_DMA; - /* set byte counter register to 0 */ - nbytes = 0; - } + buf[20] = (1 << 5) | ATA_REG_FEATURE; buf[21] = feature; buf[22] = (1 << 5) | ATA_REG_BYTEL; - buf[23] = nbytes & 0xFF; + buf[23] = qc->tf.lbam; buf[24] = (1 << 5) | ATA_REG_BYTEH; - buf[25] = (nbytes >> 8) & 0xFF; + buf[25] = qc->tf.lbah; /* send ATAPI packet command 0xA0 */ buf[26] = (1 << 5) | ATA_REG_CMD; - buf[27] = ATA_CMD_PACKET; + buf[27] = qc->tf.command; /* select drive and check DRQ */ buf[28] = (1 << 5) | ATA_REG_DEVICE | PDC_PKT_WAIT_DRDY; @@ -541,17 +533,15 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; struct scatterlist *sg; - unsigned int idx; const u32 SG_COUNT_ASIC_BUG = 41*4; + unsigned int si, idx; + u32 len; if (!(qc->flags & ATA_QCFLAG_DMAMAP)) return; - WARN_ON(qc->__sg == NULL); - WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); - idx = 0; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { u32 addr, offset; u32 sg_len, len; @@ -578,29 +568,27 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc) } } - if (idx) { - u32 len = le32_to_cpu(ap->prd[idx - 1].flags_len); + len = le32_to_cpu(ap->prd[idx - 1].flags_len); - if (len > SG_COUNT_ASIC_BUG) { - u32 addr; + if (len > SG_COUNT_ASIC_BUG) { + u32 addr; - VPRINTK("Splitting last PRD.\n"); + VPRINTK("Splitting last PRD.\n"); - addr = le32_to_cpu(ap->prd[idx - 1].addr); - ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG); + addr = le32_to_cpu(ap->prd[idx - 1].addr); + ap->prd[idx - 1].flags_len = cpu_to_le32(len - SG_COUNT_ASIC_BUG); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx - 1, addr, SG_COUNT_ASIC_BUG); - addr = addr + len - SG_COUNT_ASIC_BUG; - len = SG_COUNT_ASIC_BUG; - ap->prd[idx].addr = cpu_to_le32(addr); - ap->prd[idx].flags_len = cpu_to_le32(len); - VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); + addr = addr + len - SG_COUNT_ASIC_BUG; + len = SG_COUNT_ASIC_BUG; + ap->prd[idx].addr = cpu_to_le32(addr); + ap->prd[idx].flags_len = cpu_to_le32(len); + VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len); - idx++; - } - - ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); + idx++; } + + ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -627,14 +615,14 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc) pdc_pkt_footer(&qc->tf, pp->pkt, i); break; - case ATA_PROT_ATAPI: + case ATAPI_PROT_PIO: pdc_fill_sg(qc); break; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: pdc_fill_sg(qc); /*FALLTHROUGH*/ - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_NODATA: pdc_atapi_pkt(qc); break; @@ -754,8 +742,8 @@ static inline unsigned int pdc_host_intr(struct ata_port *ap, switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: - case ATA_PROT_ATAPI_DMA: - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_DMA: + case ATAPI_PROT_NODATA: qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); ata_qc_complete(qc); handled = 1; @@ -900,7 +888,7 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc) static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) { switch (qc->tf.protocol) { - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_NODATA: if (qc->dev->flags & ATA_DFLAG_CDB_INTR) break; /*FALLTHROUGH*/ @@ -908,7 +896,7 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) if (qc->tf.flags & ATA_TFLAG_POLLING) break; /*FALLTHROUGH*/ - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: case ATA_PROT_DMA: pdc_packet_start(qc); return 0; @@ -922,16 +910,14 @@ static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc) static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { - WARN_ON(tf->protocol == ATA_PROT_DMA || - tf->protocol == ATA_PROT_ATAPI_DMA); + WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); ata_tf_load(ap, tf); } static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { - WARN_ON(tf->protocol == ATA_PROT_DMA || - tf->protocol == ATA_PROT_ATAPI_DMA); + WARN_ON(tf->protocol == ATA_PROT_DMA || tf->protocol == ATAPI_PROT_DMA); ata_exec_command(ap, tf); } diff --git a/drivers/ata/sata_promise.h b/drivers/ata/sata_promise.h index 6ee5e190262d..00d6000e546f 100644 --- a/drivers/ata/sata_promise.h +++ b/drivers/ata/sata_promise.h @@ -46,7 +46,7 @@ static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf, unsigned int devno, u8 *buf) { u8 dev_reg; - u32 *buf32 = (u32 *) buf; + __le32 *buf32 = (__le32 *) buf; /* set control bits (byte 0), zero delay seq id (byte 3), * and seq id (byte 2) diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index c68b241805fd..91cc12c82040 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -287,14 +287,10 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) struct scatterlist *sg; struct ata_port *ap = qc->ap; struct qs_port_priv *pp = ap->private_data; - unsigned int nelem; u8 *prd = pp->pkt + QS_CPB_BYTES; + unsigned int si; - WARN_ON(qc->__sg == NULL); - WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); - - nelem = 0; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { u64 addr; u32 len; @@ -306,12 +302,11 @@ static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) *(__le32 *)prd = cpu_to_le32(len); prd += sizeof(u64); - VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, + VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", si, (unsigned long long)addr, len); - nelem++; } - return nelem; + return si; } static void qs_qc_prep(struct ata_queued_cmd *qc) @@ -376,7 +371,7 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc) qs_packet_start(qc); return 0; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: BUG(); break; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index f5119bf40c24..0b8191b52f97 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -416,15 +416,14 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) */ /* Check the ATA_DFLAG_CDB_INTR flag is enough here. - * The flag was turned on only for atapi devices. - * No need to check is_atapi_taskfile(&qc->tf) again. + * The flag was turned on only for atapi devices. No + * need to check ata_is_atapi(qc->tf.protocol) again. */ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) goto err_hsm; break; case HSM_ST_LAST: - if (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA) { + if (ata_is_dma(qc->tf.protocol)) { /* clear DMA-Start bit */ ap->ops->bmdma_stop(qc); @@ -451,8 +450,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) /* kick HSM in the ass */ ata_hsm_move(ap, qc, status, 0); - if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol)) ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2); return; diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index 864c1c1b8511..b4b1f91ea693 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -813,8 +813,9 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, { struct scatterlist *sg; struct sil24_sge *last_sge = NULL; + unsigned int si; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { sge->addr = cpu_to_le64(sg_dma_address(sg)); sge->cnt = cpu_to_le32(sg_dma_len(sg)); sge->flags = 0; @@ -823,8 +824,7 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, sge++; } - if (likely(last_sge)) - last_sge->flags = cpu_to_le32(SGE_TRM); + last_sge->flags = cpu_to_le32(SGE_TRM); } static int sil24_qc_defer(struct ata_queued_cmd *qc) @@ -852,9 +852,7 @@ static int sil24_qc_defer(struct ata_queued_cmd *qc) * set. * */ - int is_excl = (prot == ATA_PROT_ATAPI || - prot == ATA_PROT_ATAPI_NODATA || - prot == ATA_PROT_ATAPI_DMA || + int is_excl = (ata_is_atapi(prot) || (qc->flags & ATA_QCFLAG_RESULT_TF)); if (unlikely(ap->excl_link)) { @@ -885,35 +883,21 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) cb = &pp->cmd_block[sil24_tag(qc->tag)]; - switch (qc->tf.protocol) { - case ATA_PROT_PIO: - case ATA_PROT_DMA: - case ATA_PROT_NCQ: - case ATA_PROT_NODATA: + if (!ata_is_atapi(qc->tf.protocol)) { prb = &cb->ata.prb; sge = cb->ata.sge; - break; - - case ATA_PROT_ATAPI: - case ATA_PROT_ATAPI_DMA: - case ATA_PROT_ATAPI_NODATA: + } else { prb = &cb->atapi.prb; sge = cb->atapi.sge; memset(cb->atapi.cdb, 0, 32); memcpy(cb->atapi.cdb, qc->cdb, qc->dev->cdb_len); - if (qc->tf.protocol != ATA_PROT_ATAPI_NODATA) { + if (ata_is_data(qc->tf.protocol)) { if (qc->tf.flags & ATA_TFLAG_WRITE) ctrl = PRB_CTRL_PACKET_WRITE; else ctrl = PRB_CTRL_PACKET_READ; } - break; - - default: - prb = NULL; /* shut up, gcc */ - sge = NULL; - BUG(); } prb->ctrl = cpu_to_le16(ctrl); diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 4d857185f33b..e3d56bc6726d 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -334,7 +334,7 @@ static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf, { u32 addr; unsigned int dw = PDC_DIMM_APKT_PRD >> 2; - u32 *buf32 = (u32 *) buf; + __le32 *buf32 = (__le32 *) buf; /* output ATA packet S/G table */ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA + @@ -356,7 +356,7 @@ static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf, { u32 addr; unsigned int dw = PDC_DIMM_HPKT_PRD >> 2; - u32 *buf32 = (u32 *) buf; + __le32 *buf32 = (__le32 *) buf; /* output Host DMA packet S/G table */ addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA + @@ -377,7 +377,7 @@ static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf, unsigned int portno) { unsigned int i, dw; - u32 *buf32 = (u32 *) buf; + __le32 *buf32 = (__le32 *) buf; u8 dev_reg; unsigned int dimm_sg = PDC_20621_DIMM_BASE + @@ -429,7 +429,8 @@ static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf, unsigned int portno) { unsigned int dw; - u32 tmp, *buf32 = (u32 *) buf; + u32 tmp; + __le32 *buf32 = (__le32 *) buf; unsigned int host_sg = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) + @@ -473,7 +474,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc) void __iomem *mmio = ap->host->iomap[PDC_MMIO_BAR]; void __iomem *dimm_mmio = ap->host->iomap[PDC_DIMM_BAR]; unsigned int portno = ap->port_no; - unsigned int i, idx, total_len = 0, sgt_len; + unsigned int i, si, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP)); @@ -487,7 +488,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc) * Build S/G table */ idx = 0; - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { buf[idx++] = cpu_to_le32(sg_dma_address(sg)); buf[idx++] = cpu_to_le32(sg_dma_len(sg)); total_len += sg_dma_len(sg); @@ -700,7 +701,7 @@ static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc) pdc20621_packet_start(qc); return 0; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: BUG(); break; diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index b34b3829f6a9..7b44a5965155 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -2163,7 +2163,6 @@ static int __devinit amb_init (amb_dev * dev) static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev) { unsigned char pool; - memset (dev, 0, sizeof(amb_dev)); // set up known dev items straight away dev->pci_dev = pci_dev; @@ -2253,7 +2252,7 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_ goto out_disable; } - dev = kmalloc (sizeof(amb_dev), GFP_KERNEL); + dev = kzalloc(sizeof(amb_dev), GFP_KERNEL); if (!dev) { PRINTK (KERN_ERR, "out of memory!"); err = -ENOMEM; diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 3b64a99772ea..2e3395b7e8c1 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -1,5 +1,3 @@ -/* $Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $ */ - /* he.c @@ -99,10 +97,6 @@ #define HPRINTK(fmt,args...) do { } while (0) #endif /* HE_DEBUG */ -/* version definition */ - -static char *version = "$Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $"; - /* declarations */ static int he_open(struct atm_vcc *vcc); @@ -366,7 +360,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) struct he_dev *he_dev = NULL; int err = 0; - printk(KERN_INFO "he: %s\n", version); + printk(KERN_INFO "ATM he driver\n"); if (pci_enable_device(pci_dev)) return -EIO; @@ -1643,6 +1637,8 @@ he_stop(struct he_dev *he_dev) if (he_dev->rbpl_base) { #ifdef USE_RBPL_POOL + int i; + for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { void *cpuaddr = he_dev->rbpl_virt[i].virt; dma_addr_t dma_handle = he_dev->rbpl_base[i].phys; @@ -1665,6 +1661,8 @@ he_stop(struct he_dev *he_dev) #ifdef USE_RBPS if (he_dev->rbps_base) { #ifdef USE_RBPS_POOL + int i; + for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { void *cpuaddr = he_dev->rbps_virt[i].virt; dma_addr_t dma_handle = he_dev->rbps_base[i].phys; @@ -2933,7 +2931,7 @@ he_proc_read(struct atm_dev *dev, loff_t *pos, char *page) left = *pos; if (!left--) - return sprintf(page, "%s\n", version); + return sprintf(page, "ATM he driver\n"); if (!left--) return sprintf(page, "%s%s\n\n", diff --git a/drivers/base/Makefile b/drivers/base/Makefile index b39ea3f59c9b..63e09c015ca0 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -11,6 +11,9 @@ obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o obj-$(CONFIG_SMP) += topology.o +ifeq ($(CONFIG_SYSFS),y) +obj-$(CONFIG_MODULES) += module.o +endif obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o ifeq ($(CONFIG_DEBUG_DRIVER),y) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 7370d7cf5988..3b43e8a9f87e 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -61,7 +61,7 @@ attribute_container_classdev_to_container(struct class_device *classdev) } EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); -static struct list_head attribute_container_list; +static LIST_HEAD(attribute_container_list); static DEFINE_MUTEX(attribute_container_mutex); @@ -320,9 +320,14 @@ attribute_container_add_attrs(struct class_device *classdev) struct class_device_attribute **attrs = cont->attrs; int i, error; - if (!attrs) + BUG_ON(attrs && cont->grp); + + if (!attrs && !cont->grp) return 0; + if (cont->grp) + return sysfs_create_group(&classdev->kobj, cont->grp); + for (i = 0; attrs[i]; i++) { error = class_device_create_file(classdev, attrs[i]); if (error) @@ -378,9 +383,14 @@ attribute_container_remove_attrs(struct class_device *classdev) struct class_device_attribute **attrs = cont->attrs; int i; - if (!attrs) + if (!attrs && !cont->grp) return; + if (cont->grp) { + sysfs_remove_group(&classdev->kobj, cont->grp); + return ; + } + for (i = 0; attrs[i]; i++) class_device_remove_file(classdev, attrs[i]); } @@ -429,10 +439,3 @@ attribute_container_find_class_device(struct attribute_container *cont, return cdev; } EXPORT_SYMBOL_GPL(attribute_container_find_class_device); - -int __init -attribute_container_init(void) -{ - INIT_LIST_HEAD(&attribute_container_list); - return 0; -} diff --git a/drivers/base/base.h b/drivers/base/base.h index 10b2fb6c9ce6..c0444146c09a 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -1,6 +1,42 @@ -/* initialisation functions */ +/** + * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure. + * + * @subsys - the struct kset that defines this bus. This is the main kobject + * @drivers_kset - the list of drivers associated with this bus + * @devices_kset - the list of devices associated with this bus + * @klist_devices - the klist to iterate over the @devices_kset + * @klist_drivers - the klist to iterate over the @drivers_kset + * @bus_notifier - the bus notifier list for anything that cares about things + * on this bus. + * @bus - pointer back to the struct bus_type that this structure is associated + * with. + * + * This structure is the one that is the actual kobject allowing struct + * bus_type to be statically allocated safely. Nothing outside of the driver + * core should ever touch these fields. + */ +struct bus_type_private { + struct kset subsys; + struct kset *drivers_kset; + struct kset *devices_kset; + struct klist klist_devices; + struct klist klist_drivers; + struct blocking_notifier_head bus_notifier; + unsigned int drivers_autoprobe:1; + struct bus_type *bus; +}; + +struct driver_private { + struct kobject kobj; + struct klist klist_devices; + struct klist_node knode_bus; + struct module_kobject *mkobj; + struct device_driver *driver; +}; +#define to_driver(obj) container_of(obj, struct driver_private, kobj) +/* initialisation functions */ extern int devices_init(void); extern int buses_init(void); extern int classes_init(void); @@ -13,17 +49,16 @@ static inline int hypervisor_init(void) { return 0; } extern int platform_bus_init(void); extern int system_bus_init(void); extern int cpu_dev_init(void); -extern int attribute_container_init(void); -extern int bus_add_device(struct device * dev); -extern void bus_attach_device(struct device * dev); -extern void bus_remove_device(struct device * dev); +extern int bus_add_device(struct device *dev); +extern void bus_attach_device(struct device *dev); +extern void bus_remove_device(struct device *dev); -extern int bus_add_driver(struct device_driver *); -extern void bus_remove_driver(struct device_driver *); +extern int bus_add_driver(struct device_driver *drv); +extern void bus_remove_driver(struct device_driver *drv); -extern void driver_detach(struct device_driver * drv); -extern int driver_probe_device(struct device_driver *, struct device *); +extern void driver_detach(struct device_driver *drv); +extern int driver_probe_device(struct device_driver *drv, struct device *dev); extern void sysdev_shutdown(void); extern int sysdev_suspend(pm_message_t state); @@ -44,4 +79,13 @@ extern char *make_class_name(const char *name, struct kobject *kobj); extern int devres_release_all(struct device *dev); -extern struct kset devices_subsys; +extern struct kset *devices_kset; + +#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) +extern void module_add_driver(struct module *mod, struct device_driver *drv); +extern void module_remove_driver(struct device_driver *drv); +#else +static inline void module_add_driver(struct module *mod, + struct device_driver *drv) { } +static inline void module_remove_driver(struct device_driver *drv) { } +#endif diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 9a19b071c573..055989e94799 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 * @@ -17,14 +19,13 @@ #include "power/power.h" #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) -#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj) +#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj) /* * sysfs bindings for drivers */ #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr) -#define to_driver(obj) container_of(obj, struct device_driver, kobj) static int __must_check bus_rescan_devices_helper(struct device *dev, @@ -32,37 +33,40 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, static struct bus_type *bus_get(struct bus_type *bus) { - return bus ? container_of(kset_get(&bus->subsys), - struct bus_type, subsys) : NULL; + if (bus) { + kset_get(&bus->p->subsys); + return bus; + } + return NULL; } static void bus_put(struct bus_type *bus) { - kset_put(&bus->subsys); + if (bus) + kset_put(&bus->p->subsys); } -static ssize_t -drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_driver(kobj); + struct driver_attribute *drv_attr = to_drv_attr(attr); + struct driver_private *drv_priv = to_driver(kobj); ssize_t ret = -EIO; if (drv_attr->show) - ret = drv_attr->show(drv, buf); + ret = drv_attr->show(drv_priv->driver, buf); return ret; } -static ssize_t -drv_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct driver_attribute * drv_attr = to_drv_attr(attr); - struct device_driver * drv = to_driver(kobj); + struct driver_attribute *drv_attr = to_drv_attr(attr); + struct driver_private *drv_priv = to_driver(kobj); ssize_t ret = -EIO; if (drv_attr->store) - ret = drv_attr->store(drv, buf, count); + ret = drv_attr->store(drv_priv->driver, buf, count); return ret; } @@ -71,22 +75,12 @@ static struct sysfs_ops driver_sysfs_ops = { .store = drv_attr_store, }; - -static void driver_release(struct kobject * kobj) +static void driver_release(struct kobject *kobj) { - /* - * Yes this is an empty release function, it is this way because struct - * device is always a static object, not a dynamic one. Yes, this is - * not nice and bad, but remember, drivers are code, reference counted - * by the module count, not a device, which is really data. And yes, - * in the future I do want to have all drivers be created dynamically, - * and am working toward that goal, but it will take a bit longer... - * - * But do not let this example give _anyone_ the idea that they can - * create a release function without any code in it at all, to do that - * is almost always wrong. If you have any questions about this, - * please send an email to <greg@kroah.com> - */ + struct driver_private *drv_priv = to_driver(kobj); + + pr_debug("driver: '%s': %s\n", kobject_name(kobj), __FUNCTION__); + kfree(drv_priv); } static struct kobj_type driver_ktype = { @@ -94,34 +88,30 @@ static struct kobj_type driver_ktype = { .release = driver_release, }; - /* * sysfs bindings for buses */ - - -static ssize_t -bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(kobj); + struct bus_attribute *bus_attr = to_bus_attr(attr); + struct bus_type_private *bus_priv = to_bus(kobj); ssize_t ret = 0; if (bus_attr->show) - ret = bus_attr->show(bus, buf); + ret = bus_attr->show(bus_priv->bus, buf); return ret; } -static ssize_t -bus_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct bus_attribute * bus_attr = to_bus_attr(attr); - struct bus_type * bus = to_bus(kobj); + struct bus_attribute *bus_attr = to_bus_attr(attr); + struct bus_type_private *bus_priv = to_bus(kobj); ssize_t ret = 0; if (bus_attr->store) - ret = bus_attr->store(bus, buf, count); + ret = bus_attr->store(bus_priv->bus, buf, count); return ret; } @@ -130,24 +120,26 @@ static struct sysfs_ops bus_sysfs_ops = { .store = bus_attr_store, }; -int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) +int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) { int error; if (bus_get(bus)) { - error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); + error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } else error = -EINVAL; return error; } +EXPORT_SYMBOL_GPL(bus_create_file); -void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) +void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr) { if (bus_get(bus)) { - sysfs_remove_file(&bus->subsys.kobj, &attr->attr); + sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr); bus_put(bus); } } +EXPORT_SYMBOL_GPL(bus_remove_file); static struct kobj_type bus_ktype = { .sysfs_ops = &bus_sysfs_ops, @@ -166,20 +158,11 @@ static struct kset_uevent_ops bus_uevent_ops = { .filter = bus_uevent_filter, }; -static decl_subsys(bus, &bus_ktype, &bus_uevent_ops); +static struct kset *bus_kset; #ifdef CONFIG_HOTPLUG /* Manually detach a device from its associated driver. */ -static int driver_helper(struct device *dev, void *data) -{ - const char *name = data; - - if (strcmp(name, dev->bus_id) == 0) - return 1; - return 0; -} - static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) { @@ -187,7 +170,7 @@ static ssize_t driver_unbind(struct device_driver *drv, struct device *dev; int err = -ENODEV; - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + dev = bus_find_device_by_name(bus, NULL, buf); if (dev && dev->driver == drv) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); @@ -214,7 +197,7 @@ static ssize_t driver_bind(struct device_driver *drv, struct device *dev; int err = -ENODEV; - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + dev = bus_find_device_by_name(bus, NULL, buf); if (dev && dev->driver == NULL) { if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); @@ -224,10 +207,13 @@ static ssize_t driver_bind(struct device_driver *drv, if (dev->parent) up(&dev->parent->sem); - if (err > 0) /* success */ + if (err > 0) { + /* success */ err = count; - else if (err == 0) /* driver didn't accept device */ + } else if (err == 0) { + /* driver didn't accept device */ err = -ENODEV; + } } put_device(dev); bus_put(bus); @@ -237,16 +223,16 @@ static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) { - return sprintf(buf, "%d\n", bus->drivers_autoprobe); + return sprintf(buf, "%d\n", bus->p->drivers_autoprobe); } static ssize_t store_drivers_autoprobe(struct bus_type *bus, const char *buf, size_t count) { if (buf[0] == '0') - bus->drivers_autoprobe = 0; + bus->p->drivers_autoprobe = 0; else - bus->drivers_autoprobe = 1; + bus->p->drivers_autoprobe = 1; return count; } @@ -255,7 +241,7 @@ static ssize_t store_drivers_probe(struct bus_type *bus, { struct device *dev; - dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); + dev = bus_find_device_by_name(bus, NULL, buf); if (!dev) return -ENODEV; if (bus_rescan_devices_helper(dev, NULL) != 0) @@ -264,49 +250,49 @@ static ssize_t store_drivers_probe(struct bus_type *bus, } #endif -static struct device * next_device(struct klist_iter * i) +static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); + struct klist_node *n = klist_next(i); return n ? container_of(n, struct device, knode_bus) : NULL; } /** - * bus_for_each_dev - device iterator. - * @bus: bus type. - * @start: device to start iterating from. - * @data: data for the callback. - * @fn: function to be called for each device. + * bus_for_each_dev - device iterator. + * @bus: bus type. + * @start: device to start iterating from. + * @data: data for the callback. + * @fn: function to be called for each device. * - * Iterate over @bus's list of devices, and call @fn for each, - * passing it @data. If @start is not NULL, we use that device to - * begin iterating from. + * Iterate over @bus's list of devices, and call @fn for each, + * passing it @data. If @start is not NULL, we use that device to + * begin iterating from. * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. * - * NOTE: The device that returns a non-zero value is not retained - * in any way, nor is its refcount incremented. If the caller needs - * to retain this data, it should do, and increment the reference - * count in the supplied callback. + * NOTE: The device that returns a non-zero value is not retained + * in any way, nor is its refcount incremented. If the caller needs + * to retain this data, it should do, and increment the reference + * count in the supplied callback. */ - -int bus_for_each_dev(struct bus_type * bus, struct device * start, - void * data, int (*fn)(struct device *, void *)) +int bus_for_each_dev(struct bus_type *bus, struct device *start, + void *data, int (*fn)(struct device *, void *)) { struct klist_iter i; - struct device * dev; + struct device *dev; int error = 0; if (!bus) return -EINVAL; - klist_iter_init_node(&bus->klist_devices, &i, + klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); return error; } +EXPORT_SYMBOL_GPL(bus_for_each_dev); /** * bus_find_device - device iterator for locating a particular device. @@ -323,9 +309,9 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start, * if it does. If the callback returns non-zero, this function will * return to the caller and not iterate over any more devices. */ -struct device * bus_find_device(struct bus_type *bus, - struct device *start, void *data, - int (*match)(struct device *, void *)) +struct device *bus_find_device(struct bus_type *bus, + struct device *start, void *data, + int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *dev; @@ -333,7 +319,7 @@ struct device * bus_find_device(struct bus_type *bus, if (!bus) return NULL; - klist_iter_init_node(&bus->klist_devices, &i, + klist_iter_init_node(&bus->p->klist_devices, &i, (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) @@ -341,51 +327,83 @@ struct device * bus_find_device(struct bus_type *bus, klist_iter_exit(&i); return dev; } +EXPORT_SYMBOL_GPL(bus_find_device); + +static int match_name(struct device *dev, void *data) +{ + const char *name = data; + if (strcmp(name, dev->bus_id) == 0) + return 1; + return 0; +} -static struct device_driver * next_driver(struct klist_iter * i) +/** + * bus_find_device_by_name - device iterator for locating a particular device of a specific name + * @bus: bus type + * @start: Device to begin with + * @name: name of the device to match + * + * This is similar to the bus_find_device() function above, but it handles + * searching by a name automatically, no need to write another strcmp matching + * function. + */ +struct device *bus_find_device_by_name(struct bus_type *bus, + struct device *start, const char *name) { - struct klist_node * n = klist_next(i); - return n ? container_of(n, struct device_driver, knode_bus) : NULL; + return bus_find_device(bus, start, (void *)name, match_name); +} +EXPORT_SYMBOL_GPL(bus_find_device_by_name); + +static struct device_driver *next_driver(struct klist_iter *i) +{ + struct klist_node *n = klist_next(i); + struct driver_private *drv_priv; + + if (n) { + drv_priv = container_of(n, struct driver_private, knode_bus); + return drv_priv->driver; + } + return NULL; } /** - * bus_for_each_drv - driver iterator - * @bus: bus we're dealing with. - * @start: driver to start iterating on. - * @data: data to pass to the callback. - * @fn: function to call for each driver. + * bus_for_each_drv - driver iterator + * @bus: bus we're dealing with. + * @start: driver to start iterating on. + * @data: data to pass to the callback. + * @fn: function to call for each driver. * - * This is nearly identical to the device iterator above. - * We iterate over each driver that belongs to @bus, and call - * @fn for each. If @fn returns anything but 0, we break out - * and return it. If @start is not NULL, we use it as the head - * of the list. + * This is nearly identical to the device iterator above. + * We iterate over each driver that belongs to @bus, and call + * @fn for each. If @fn returns anything but 0, we break out + * and return it. If @start is not NULL, we use it as the head + * of the list. * - * NOTE: we don't return the driver that returns a non-zero - * value, nor do we leave the reference count incremented for that - * driver. If the caller needs to know that info, it must set it - * in the callback. It must also be sure to increment the refcount - * so it doesn't disappear before returning to the caller. + * NOTE: we don't return the driver that returns a non-zero + * value, nor do we leave the reference count incremented for that + * driver. If the caller needs to know that info, it must set it + * in the callback. It must also be sure to increment the refcount + * so it doesn't disappear before returning to the caller. */ - -int bus_for_each_drv(struct bus_type * bus, struct device_driver * start, - void * data, int (*fn)(struct device_driver *, void *)) +int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, + void *data, int (*fn)(struct device_driver *, void *)) { struct klist_iter i; - struct device_driver * drv; + struct device_driver *drv; int error = 0; if (!bus) return -EINVAL; - klist_iter_init_node(&bus->klist_drivers, &i, - start ? &start->knode_bus : NULL); + klist_iter_init_node(&bus->p->klist_drivers, &i, + start ? &start->p->knode_bus : NULL); while ((drv = next_driver(&i)) && !error) error = fn(drv, data); klist_iter_exit(&i); return error; } +EXPORT_SYMBOL_GPL(bus_for_each_drv); static int device_add_attrs(struct bus_type *bus, struct device *dev) { @@ -396,7 +414,7 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev) return 0; for (i = 0; attr_name(bus->dev_attrs[i]); i++) { - error = device_create_file(dev,&bus->dev_attrs[i]); + error = device_create_file(dev, &bus->dev_attrs[i]); if (error) { while (--i >= 0) device_remove_file(dev, &bus->dev_attrs[i]); @@ -406,13 +424,13 @@ static int device_add_attrs(struct bus_type *bus, struct device *dev) return error; } -static void device_remove_attrs(struct bus_type * bus, struct device * dev) +static void device_remove_attrs(struct bus_type *bus, struct device *dev) { int i; if (bus->dev_attrs) { for (i = 0; attr_name(bus->dev_attrs[i]); i++) - device_remove_file(dev,&bus->dev_attrs[i]); + device_remove_file(dev, &bus->dev_attrs[i]); } } @@ -420,7 +438,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev) static int make_deprecated_bus_links(struct device *dev) { return sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "bus"); + &dev->bus->p->subsys.kobj, "bus"); } static void remove_deprecated_bus_links(struct device *dev) @@ -433,28 +451,28 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } #endif /** - * bus_add_device - add device to bus - * @dev: device being added + * bus_add_device - add device to bus + * @dev: device being added * - * - Add the device to its bus's list of devices. - * - Create link to device's bus. + * - Add the device to its bus's list of devices. + * - Create link to device's bus. */ -int bus_add_device(struct device * dev) +int bus_add_device(struct device *dev) { - struct bus_type * bus = bus_get(dev->bus); + struct bus_type *bus = bus_get(dev->bus); int error = 0; if (bus) { - pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); + pr_debug("bus: '%s': add device %s\n", bus->name, dev->bus_id); error = device_add_attrs(bus, dev); if (error) goto out_put; - error = sysfs_create_link(&bus->devices.kobj, + error = sysfs_create_link(&bus->p->devices_kset->kobj, &dev->kobj, dev->bus_id); if (error) goto out_id; error = sysfs_create_link(&dev->kobj, - &dev->bus->subsys.kobj, "subsystem"); + &dev->bus->p->subsys.kobj, "subsystem"); if (error) goto out_subsys; error = make_deprecated_bus_links(dev); @@ -466,7 +484,7 @@ int bus_add_device(struct device * dev) out_deprecated: sysfs_remove_link(&dev->kobj, "subsystem"); out_subsys: - sysfs_remove_link(&bus->devices.kobj, dev->bus_id); + sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id); out_id: device_remove_attrs(bus, dev); out_put: @@ -475,56 +493,58 @@ out_put: } /** - * bus_attach_device - add device to bus - * @dev: device tried to attach to a driver + * bus_attach_device - add device to bus + * @dev: device tried to attach to a driver * - * - Add device to bus's list of devices. - * - Try to attach to driver. + * - Add device to bus's list of devices. + * - Try to attach to driver. */ -void bus_attach_device(struct device * dev) +void bus_attach_device(struct device *dev) { struct bus_type *bus = dev->bus; int ret = 0; if (bus) { dev->is_registered = 1; - if (bus->drivers_autoprobe) + if (bus->p->drivers_autoprobe) ret = device_attach(dev); WARN_ON(ret < 0); if (ret >= 0) - klist_add_tail(&dev->knode_bus, &bus->klist_devices); + klist_add_tail(&dev->knode_bus, &bus->p->klist_devices); else dev->is_registered = 0; } } /** - * bus_remove_device - remove device from bus - * @dev: device to be removed + * bus_remove_device - remove device from bus + * @dev: device to be removed * - * - Remove symlink from bus's directory. - * - Delete device from bus's list. - * - Detach from its driver. - * - Drop reference taken in bus_add_device(). + * - Remove symlink from bus's directory. + * - Delete device from bus's list. + * - Detach from its driver. + * - Drop reference taken in bus_add_device(). */ -void bus_remove_device(struct device * dev) +void bus_remove_device(struct device *dev) { if (dev->bus) { sysfs_remove_link(&dev->kobj, "subsystem"); remove_deprecated_bus_links(dev); - sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); + sysfs_remove_link(&dev->bus->p->devices_kset->kobj, + dev->bus_id); device_remove_attrs(dev->bus, dev); if (dev->is_registered) { dev->is_registered = 0; klist_del(&dev->knode_bus); } - pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); + pr_debug("bus: '%s': remove device %s\n", + dev->bus->name, dev->bus_id); device_release_driver(dev); bus_put(dev->bus); } } -static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv) +static int driver_add_attrs(struct bus_type *bus, struct device_driver *drv) { int error = 0; int i; @@ -533,19 +553,19 @@ static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv) for (i = 0; attr_name(bus->drv_attrs[i]); i++) { error = driver_create_file(drv, &bus->drv_attrs[i]); if (error) - goto Err; + goto err; } } - Done: +done: return error; - Err: +err: while (--i >= 0) driver_remove_file(drv, &bus->drv_attrs[i]); - goto Done; + goto done; } - -static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv) +static void driver_remove_attrs(struct bus_type *bus, + struct device_driver *drv) { int i; @@ -616,39 +636,46 @@ static ssize_t driver_uevent_store(struct device_driver *drv, enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&drv->kobj, action); + kobject_uevent(&drv->p->kobj, action); return count; } static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); /** - * bus_add_driver - Add a driver to the bus. - * @drv: driver. - * + * bus_add_driver - Add a driver to the bus. + * @drv: driver. */ int bus_add_driver(struct device_driver *drv) { - struct bus_type * bus = bus_get(drv->bus); + struct bus_type *bus; + struct driver_private *priv; int error = 0; + bus = bus_get(drv->bus); if (!bus) return -EINVAL; - pr_debug("bus %s: add driver %s\n", bus->name, drv->name); - error = kobject_set_name(&drv->kobj, "%s", drv->name); - if (error) - goto out_put_bus; - drv->kobj.kset = &bus->drivers; - error = kobject_register(&drv->kobj); + pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + klist_init(&priv->klist_devices, NULL, NULL); + priv->driver = drv; + drv->p = priv; + priv->kobj.kset = bus->p->drivers_kset; + error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, + "%s", drv->name); if (error) goto out_put_bus; - if (drv->bus->drivers_autoprobe) { + if (drv->bus->p->drivers_autoprobe) { error = driver_attach(drv); if (error) goto out_unregister; } - klist_add_tail(&drv->knode_bus, &bus->klist_drivers); + klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); module_add_driver(drv->owner, drv); error = driver_create_file(drv, &driver_attr_uevent); @@ -669,24 +696,24 @@ int bus_add_driver(struct device_driver *drv) __FUNCTION__, drv->name); } + kobject_uevent(&priv->kobj, KOBJ_ADD); return error; out_unregister: - kobject_unregister(&drv->kobj); + kobject_put(&priv->kobj); out_put_bus: bus_put(bus); return error; } /** - * bus_remove_driver - delete driver from bus's knowledge. - * @drv: driver. + * bus_remove_driver - delete driver from bus's knowledge. + * @drv: driver. * - * Detach the driver from the devices it controls, and remove - * it from its bus's list of drivers. Finally, we drop the reference - * to the bus we took in bus_add_driver(). + * Detach the driver from the devices it controls, and remove + * it from its bus's list of drivers. Finally, we drop the reference + * to the bus we took in bus_add_driver(). */ - -void bus_remove_driver(struct device_driver * drv) +void bus_remove_driver(struct device_driver *drv) { if (!drv->bus) return; @@ -694,18 +721,17 @@ void bus_remove_driver(struct device_driver * drv) remove_bind_files(drv); driver_remove_attrs(drv->bus, drv); driver_remove_file(drv, &driver_attr_uevent); - klist_remove(&drv->knode_bus); - pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); + klist_remove(&drv->p->knode_bus); + pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name); driver_detach(drv); module_remove_driver(drv); - kobject_unregister(&drv->kobj); + kobject_put(&drv->p->kobj); bus_put(drv->bus); } - /* Helper for bus_rescan_devices's iter */ static int __must_check bus_rescan_devices_helper(struct device *dev, - void *data) + void *data) { int ret = 0; @@ -727,10 +753,11 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, * attached and rescan it against existing drivers to see if it matches * any by calling device_attach() for the unbound devices. */ -int bus_rescan_devices(struct bus_type * bus) +int bus_rescan_devices(struct bus_type *bus) { return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); } +EXPORT_SYMBOL_GPL(bus_rescan_devices); /** * device_reprobe - remove driver for a device and probe for a new driver @@ -755,55 +782,55 @@ int device_reprobe(struct device *dev) EXPORT_SYMBOL_GPL(device_reprobe); /** - * find_bus - locate bus by name. - * @name: name of bus. + * find_bus - locate bus by name. + * @name: name of bus. * - * Call kset_find_obj() to iterate over list of buses to - * find a bus by name. Return bus if found. + * Call kset_find_obj() to iterate over list of buses to + * find a bus by name. Return bus if found. * - * Note that kset_find_obj increments bus' reference count. + * Note that kset_find_obj increments bus' reference count. */ #if 0 -struct bus_type * find_bus(char * name) +struct bus_type *find_bus(char *name) { - struct kobject * k = kset_find_obj(&bus_subsys.kset, name); + struct kobject *k = kset_find_obj(bus_kset, name); return k ? to_bus(k) : NULL; } #endif /* 0 */ /** - * bus_add_attrs - Add default attributes for this bus. - * @bus: Bus that has just been registered. + * bus_add_attrs - Add default attributes for this bus. + * @bus: Bus that has just been registered. */ -static int bus_add_attrs(struct bus_type * bus) +static int bus_add_attrs(struct bus_type *bus) { int error = 0; int i; if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) { - error = bus_create_file(bus,&bus->bus_attrs[i]); + error = bus_create_file(bus, &bus->bus_attrs[i]); if (error) - goto Err; + goto err; } } - Done: +done: return error; - Err: +err: while (--i >= 0) - bus_remove_file(bus,&bus->bus_attrs[i]); - goto Done; + bus_remove_file(bus, &bus->bus_attrs[i]); + goto done; } -static void bus_remove_attrs(struct bus_type * bus) +static void bus_remove_attrs(struct bus_type *bus) { int i; if (bus->bus_attrs) { for (i = 0; attr_name(bus->bus_attrs[i]); i++) - bus_remove_file(bus,&bus->bus_attrs[i]); + bus_remove_file(bus, &bus->bus_attrs[i]); } } @@ -827,32 +854,42 @@ static ssize_t bus_uevent_store(struct bus_type *bus, enum kobject_action action; if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&bus->subsys.kobj, action); + kobject_uevent(&bus->p->subsys.kobj, action); return count; } static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); /** - * bus_register - register a bus with the system. - * @bus: bus. + * bus_register - register a bus with the system. + * @bus: bus. * - * Once we have that, we registered the bus with the kobject - * infrastructure, then register the children subsystems it has: - * the devices and drivers that belong to the bus. + * Once we have that, we registered the bus with the kobject + * infrastructure, then register the children subsystems it has: + * the devices and drivers that belong to the bus. */ -int bus_register(struct bus_type * bus) +int bus_register(struct bus_type *bus) { int retval; + struct bus_type_private *priv; + + priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); + if (!priv) + return -ENOMEM; - BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier); + priv->bus = bus; + bus->p = priv; - retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name); + BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); + + retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); if (retval) goto out; - bus->subsys.kobj.kset = &bus_subsys; + priv->subsys.kobj.kset = bus_kset; + priv->subsys.kobj.ktype = &bus_ktype; + priv->drivers_autoprobe = 1; - retval = subsystem_register(&bus->subsys); + retval = kset_register(&priv->subsys); if (retval) goto out; @@ -860,23 +897,23 @@ int bus_register(struct bus_type * bus) if (retval) goto bus_uevent_fail; - kobject_set_name(&bus->devices.kobj, "devices"); - bus->devices.kobj.parent = &bus->subsys.kobj; - retval = kset_register(&bus->devices); - if (retval) + priv->devices_kset = kset_create_and_add("devices", NULL, + &priv->subsys.kobj); + if (!priv->devices_kset) { + retval = -ENOMEM; goto bus_devices_fail; + } - kobject_set_name(&bus->drivers.kobj, "drivers"); - bus->drivers.kobj.parent = &bus->subsys.kobj; - bus->drivers.ktype = &driver_ktype; - retval = kset_register(&bus->drivers); - if (retval) + priv->drivers_kset = kset_create_and_add("drivers", NULL, + &priv->subsys.kobj); + if (!priv->drivers_kset) { + retval = -ENOMEM; goto bus_drivers_fail; + } - klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); - klist_init(&bus->klist_drivers, NULL, NULL); + klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); + klist_init(&priv->klist_drivers, NULL, NULL); - bus->drivers_autoprobe = 1; retval = add_probe_files(bus); if (retval) goto bus_probe_files_fail; @@ -885,66 +922,73 @@ int bus_register(struct bus_type * bus) if (retval) goto bus_attrs_fail; - pr_debug("bus type '%s' registered\n", bus->name); + pr_debug("bus: '%s': registered\n", bus->name); return 0; bus_attrs_fail: remove_probe_files(bus); bus_probe_files_fail: - kset_unregister(&bus->drivers); + kset_unregister(bus->p->drivers_kset); bus_drivers_fail: - kset_unregister(&bus->devices); + kset_unregister(bus->p->devices_kset); bus_devices_fail: bus_remove_file(bus, &bus_attr_uevent); bus_uevent_fail: - subsystem_unregister(&bus->subsys); + kset_unregister(&bus->p->subsys); + kfree(bus->p); out: return retval; } +EXPORT_SYMBOL_GPL(bus_register); /** - * bus_unregister - remove a bus from the system - * @bus: bus. + * bus_unregister - remove a bus from the system + * @bus: bus. * - * Unregister the child subsystems and the bus itself. - * Finally, we call bus_put() to release the refcount + * Unregister the child subsystems and the bus itself. + * Finally, we call bus_put() to release the refcount */ -void bus_unregister(struct bus_type * bus) +void bus_unregister(struct bus_type *bus) { - pr_debug("bus %s: unregistering\n", bus->name); + pr_debug("bus: '%s': unregistering\n", bus->name); bus_remove_attrs(bus); remove_probe_files(bus); - kset_unregister(&bus->drivers); - kset_unregister(&bus->devices); + kset_unregister(bus->p->drivers_kset); + kset_unregister(bus->p->devices_kset); bus_remove_file(bus, &bus_attr_uevent); - subsystem_unregister(&bus->subsys); + kset_unregister(&bus->p->subsys); + kfree(bus->p); } +EXPORT_SYMBOL_GPL(bus_unregister); int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) { - return blocking_notifier_chain_register(&bus->bus_notifier, nb); + return blocking_notifier_chain_register(&bus->p->bus_notifier, nb); } EXPORT_SYMBOL_GPL(bus_register_notifier); int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) { - return blocking_notifier_chain_unregister(&bus->bus_notifier, nb); + return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb); } EXPORT_SYMBOL_GPL(bus_unregister_notifier); -int __init buses_init(void) +struct kset *bus_get_kset(struct bus_type *bus) { - return subsystem_register(&bus_subsys); + return &bus->p->subsys; } +EXPORT_SYMBOL_GPL(bus_get_kset); +struct klist *bus_get_device_klist(struct bus_type *bus) +{ + return &bus->p->klist_devices; +} +EXPORT_SYMBOL_GPL(bus_get_device_klist); -EXPORT_SYMBOL_GPL(bus_for_each_dev); -EXPORT_SYMBOL_GPL(bus_find_device); -EXPORT_SYMBOL_GPL(bus_for_each_drv); - -EXPORT_SYMBOL_GPL(bus_register); -EXPORT_SYMBOL_GPL(bus_unregister); -EXPORT_SYMBOL_GPL(bus_rescan_devices); - -EXPORT_SYMBOL_GPL(bus_create_file); -EXPORT_SYMBOL_GPL(bus_remove_file); +int __init buses_init(void) +{ + bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); + if (!bus_kset) + return -ENOMEM; + return 0; +} diff --git a/drivers/base/class.c b/drivers/base/class.c index a863bb091e11..9d915376c313 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -17,16 +17,17 @@ #include <linux/kdev_t.h> #include <linux/err.h> #include <linux/slab.h> +#include <linux/genhd.h> #include "base.h" #define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) #define to_class(obj) container_of(obj, struct class, subsys.kobj) -static ssize_t -class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct class_attribute * class_attr = to_class_attr(attr); - struct class * dc = to_class(kobj); + struct class_attribute *class_attr = to_class_attr(attr); + struct class *dc = to_class(kobj); ssize_t ret = -EIO; if (class_attr->show) @@ -34,12 +35,11 @@ class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) return ret; } -static ssize_t -class_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct class_attribute * class_attr = to_class_attr(attr); - struct class * dc = to_class(kobj); + struct class_attribute *class_attr = to_class_attr(attr); + struct class *dc = to_class(kobj); ssize_t ret = -EIO; if (class_attr->store) @@ -47,7 +47,7 @@ class_attr_store(struct kobject * kobj, struct attribute * attr, return ret; } -static void class_release(struct kobject * kobj) +static void class_release(struct kobject *kobj) { struct class *class = to_class(kobj); @@ -71,20 +71,20 @@ static struct kobj_type class_ktype = { }; /* Hotplug events for classes go to the class_obj subsys */ -static decl_subsys(class, &class_ktype, NULL); +static struct kset *class_kset; -int class_create_file(struct class * cls, const struct class_attribute * attr) +int class_create_file(struct class *cls, const struct class_attribute *attr) { int error; - if (cls) { + if (cls) error = sysfs_create_file(&cls->subsys.kobj, &attr->attr); - } else + else error = -EINVAL; return error; } -void class_remove_file(struct class * cls, const struct class_attribute * attr) +void class_remove_file(struct class *cls, const struct class_attribute *attr) { if (cls) sysfs_remove_file(&cls->subsys.kobj, &attr->attr); @@ -93,48 +93,48 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) static struct class *class_get(struct class *cls) { if (cls) - return container_of(kset_get(&cls->subsys), struct class, subsys); + return container_of(kset_get(&cls->subsys), + struct class, subsys); return NULL; } -static void class_put(struct class * cls) +static void class_put(struct class *cls) { if (cls) kset_put(&cls->subsys); } - -static int add_class_attrs(struct class * cls) +static int add_class_attrs(struct class *cls) { int i; int error = 0; if (cls->class_attrs) { for (i = 0; attr_name(cls->class_attrs[i]); i++) { - error = class_create_file(cls,&cls->class_attrs[i]); + error = class_create_file(cls, &cls->class_attrs[i]); if (error) - goto Err; + goto error; } } - Done: +done: return error; - Err: +error: while (--i >= 0) - class_remove_file(cls,&cls->class_attrs[i]); - goto Done; + class_remove_file(cls, &cls->class_attrs[i]); + goto done; } -static void remove_class_attrs(struct class * cls) +static void remove_class_attrs(struct class *cls) { int i; if (cls->class_attrs) { for (i = 0; attr_name(cls->class_attrs[i]); i++) - class_remove_file(cls,&cls->class_attrs[i]); + class_remove_file(cls, &cls->class_attrs[i]); } } -int class_register(struct class * cls) +int class_register(struct class *cls) { int error; @@ -149,9 +149,16 @@ int class_register(struct class * cls) if (error) return error; - cls->subsys.kobj.kset = &class_subsys; +#if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) + /* let the block class directory show up in the root of sysfs */ + if (cls != &block_class) + cls->subsys.kobj.kset = class_kset; +#else + cls->subsys.kobj.kset = class_kset; +#endif + cls->subsys.kobj.ktype = &class_ktype; - error = subsystem_register(&cls->subsys); + error = kset_register(&cls->subsys); if (!error) { error = add_class_attrs(class_get(cls)); class_put(cls); @@ -159,11 +166,11 @@ int class_register(struct class * cls) return error; } -void class_unregister(struct class * cls) +void class_unregister(struct class *cls) { pr_debug("device class '%s': unregistering\n", cls->name); remove_class_attrs(cls); - subsystem_unregister(&cls->subsys); + kset_unregister(&cls->subsys); } static void class_create_release(struct class *cls) @@ -241,8 +248,8 @@ void class_destroy(struct class *cls) /* Class Device Stuff */ -int class_device_create_file(struct class_device * class_dev, - const struct class_device_attribute * attr) +int class_device_create_file(struct class_device *class_dev, + const struct class_device_attribute *attr) { int error = -EINVAL; if (class_dev) @@ -250,8 +257,8 @@ int class_device_create_file(struct class_device * class_dev, return error; } -void class_device_remove_file(struct class_device * class_dev, - const struct class_device_attribute * attr) +void class_device_remove_file(struct class_device *class_dev, + const struct class_device_attribute *attr) { if (class_dev) sysfs_remove_file(&class_dev->kobj, &attr->attr); @@ -273,12 +280,11 @@ void class_device_remove_bin_file(struct class_device *class_dev, sysfs_remove_bin_file(&class_dev->kobj, attr); } -static ssize_t -class_device_attr_show(struct kobject * kobj, struct attribute * attr, - char * buf) +static ssize_t class_device_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) { - struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr); - struct class_device * cd = to_class_dev(kobj); + struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr); + struct class_device *cd = to_class_dev(kobj); ssize_t ret = 0; if (class_dev_attr->show) @@ -286,12 +292,12 @@ class_device_attr_show(struct kobject * kobj, struct attribute * attr, return ret; } -static ssize_t -class_device_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t class_device_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) { - struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr); - struct class_device * cd = to_class_dev(kobj); + struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr); + struct class_device *cd = to_class_dev(kobj); ssize_t ret = 0; if (class_dev_attr->store) @@ -304,10 +310,10 @@ static struct sysfs_ops class_dev_sysfs_ops = { .store = class_device_attr_store, }; -static void class_dev_release(struct kobject * kobj) +static void class_dev_release(struct kobject *kobj) { struct class_device *cd = to_class_dev(kobj); - struct class * cls = cd->class; + struct class *cls = cd->class; pr_debug("device class '%s': release.\n", cd->class_id); @@ -316,8 +322,8 @@ static void class_dev_release(struct kobject * kobj) else if (cls->release) cls->release(cd); else { - printk(KERN_ERR "Class Device '%s' does not have a release() function, " - "it is broken and must be fixed.\n", + printk(KERN_ERR "Class Device '%s' does not have a release() " + "function, it is broken and must be fixed.\n", cd->class_id); WARN_ON(1); } @@ -428,7 +434,8 @@ static int class_uevent(struct kset *kset, struct kobject *kobj, add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + dev->driver->name); } if (class_dev->uevent) { @@ -452,43 +459,49 @@ static struct kset_uevent_ops class_uevent_ops = { .uevent = class_uevent, }; -static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); - +/* + * DO NOT copy how this is created, kset_create_and_add() should be + * called, but this is a hold-over from the old-way and will be deleted + * entirely soon. + */ +static struct kset class_obj_subsys = { + .uevent_ops = &class_uevent_ops, +}; -static int class_device_add_attrs(struct class_device * cd) +static int class_device_add_attrs(struct class_device *cd) { int i; int error = 0; - struct class * cls = cd->class; + struct class *cls = cd->class; if (cls->class_dev_attrs) { for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) { error = class_device_create_file(cd, - &cls->class_dev_attrs[i]); + &cls->class_dev_attrs[i]); if (error) - goto Err; + goto err; } } - Done: +done: return error; - Err: +err: while (--i >= 0) - class_device_remove_file(cd,&cls->class_dev_attrs[i]); - goto Done; + class_device_remove_file(cd, &cls->class_dev_attrs[i]); + goto done; } -static void class_device_remove_attrs(struct class_device * cd) +static void class_device_remove_attrs(struct class_device *cd) { int i; - struct class * cls = cd->class; + struct class *cls = cd->class; if (cls->class_dev_attrs) { for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) - class_device_remove_file(cd,&cls->class_dev_attrs[i]); + class_device_remove_file(cd, &cls->class_dev_attrs[i]); } } -static int class_device_add_groups(struct class_device * cd) +static int class_device_add_groups(struct class_device *cd) { int i; int error = 0; @@ -498,7 +511,8 @@ static int class_device_add_groups(struct class_device * cd) error = sysfs_create_group(&cd->kobj, cd->groups[i]); if (error) { while (--i >= 0) - sysfs_remove_group(&cd->kobj, cd->groups[i]); + sysfs_remove_group(&cd->kobj, + cd->groups[i]); goto out; } } @@ -507,14 +521,12 @@ out: return error; } -static void class_device_remove_groups(struct class_device * cd) +static void class_device_remove_groups(struct class_device *cd) { int i; - if (cd->groups) { - for (i = 0; cd->groups[i]; i++) { + if (cd->groups) + for (i = 0; cd->groups[i]; i++) sysfs_remove_group(&cd->kobj, cd->groups[i]); - } - } } static ssize_t show_dev(struct class_device *class_dev, char *buf) @@ -537,8 +549,8 @@ static struct class_device_attribute class_uevent_attr = void class_device_initialize(struct class_device *class_dev) { - kobj_set_kset_s(class_dev, class_obj_subsys); - kobject_init(&class_dev->kobj); + class_dev->kobj.kset = &class_obj_subsys; + kobject_init(&class_dev->kobj, &class_device_ktype); INIT_LIST_HEAD(&class_dev->node); } @@ -566,16 +578,13 @@ int class_device_add(struct class_device *class_dev) class_dev->class_id); /* first, register with generic layer. */ - error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id); - if (error) - goto out2; - if (parent_class_dev) class_dev->kobj.parent = &parent_class_dev->kobj; else class_dev->kobj.parent = &parent_class->subsys.kobj; - error = kobject_add(&class_dev->kobj); + error = kobject_add(&class_dev->kobj, class_dev->kobj.parent, + "%s", class_dev->class_id); if (error) goto out2; @@ -642,7 +651,7 @@ int class_device_add(struct class_device *class_dev) out3: kobject_del(&class_dev->kobj); out2: - if(parent_class_dev) + if (parent_class_dev) class_device_put(parent_class_dev); class_put(parent_class); out1: @@ -659,9 +668,11 @@ int class_device_register(struct class_device *class_dev) /** * class_device_create - creates a class device and registers it with sysfs * @cls: pointer to the struct class that this device should be registered to. - * @parent: pointer to the parent struct class_device of this new device, if any. + * @parent: pointer to the parent struct class_device of this new device, if + * any. * @devt: the dev_t for the char device to be added. - * @device: a pointer to a struct device that is assiociated with this class device. + * @device: a pointer to a struct device that is assiociated with this class + * device. * @fmt: string for the class device's name * * This function can be used by char device classes. A struct @@ -785,7 +796,7 @@ void class_device_destroy(struct class *cls, dev_t devt) class_device_unregister(class_dev); } -struct class_device * class_device_get(struct class_device *class_dev) +struct class_device *class_device_get(struct class_device *class_dev) { if (class_dev) return to_class_dev(kobject_get(&class_dev->kobj)); @@ -798,6 +809,139 @@ void class_device_put(struct class_device *class_dev) kobject_put(&class_dev->kobj); } +/** + * class_for_each_device - device iterator + * @class: the class we're iterating + * @data: data for the callback + * @fn: function to be called for each device + * + * Iterate over @class's list of devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + * + * Note, we hold class->sem in this function, so it can not be + * re-acquired in @fn, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +int class_for_each_device(struct class *class, void *data, + int (*fn)(struct device *, void *)) +{ + struct device *dev; + int error = 0; + + if (!class) + return -EINVAL; + down(&class->sem); + list_for_each_entry(dev, &class->devices, node) { + dev = get_device(dev); + if (dev) { + error = fn(dev, data); + put_device(dev); + } else + error = -ENODEV; + if (error) + break; + } + up(&class->sem); + + return error; +} +EXPORT_SYMBOL_GPL(class_for_each_device); + +/** + * class_find_device - device iterator for locating a particular device + * @class: the class we're iterating + * @data: data for the match function + * @match: function to check device + * + * This is similar to the class_for_each_dev() function above, but it + * returns a reference to a device that is 'found' for later use, as + * determined by the @match callback. + * + * The callback should return 0 if the device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more devices. + * + * Note, you will need to drop the reference with put_device() after use. + * + * We hold class->sem in this function, so it can not be + * re-acquired in @match, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +struct device *class_find_device(struct class *class, void *data, + int (*match)(struct device *, void *)) +{ + struct device *dev; + int found = 0; + + if (!class) + return NULL; + + down(&class->sem); + list_for_each_entry(dev, &class->devices, node) { + dev = get_device(dev); + if (dev) { + if (match(dev, data)) { + found = 1; + break; + } else + put_device(dev); + } else + break; + } + up(&class->sem); + + return found ? dev : NULL; +} +EXPORT_SYMBOL_GPL(class_find_device); + +/** + * class_find_child - device iterator for locating a particular class_device + * @class: the class we're iterating + * @data: data for the match function + * @match: function to check class_device + * + * This function returns a reference to a class_device that is 'found' for + * later use, as determined by the @match callback. + * + * The callback should return 0 if the class_device doesn't match and non-zero + * if it does. If the callback returns non-zero, this function will + * return to the caller and not iterate over any more class_devices. + * + * Note, you will need to drop the reference with class_device_put() after use. + * + * We hold class->sem in this function, so it can not be + * re-acquired in @match, otherwise it will self-deadlocking. For + * example, calls to add or remove class members would be verboten. + */ +struct class_device *class_find_child(struct class *class, void *data, + int (*match)(struct class_device *, void *)) +{ + struct class_device *dev; + int found = 0; + + if (!class) + return NULL; + + down(&class->sem); + list_for_each_entry(dev, &class->children, node) { + dev = class_device_get(dev); + if (dev) { + if (match(dev, data)) { + found = 1; + break; + } else + class_device_put(dev); + } else + break; + } + up(&class->sem); + + return found ? dev : NULL; +} +EXPORT_SYMBOL_GPL(class_find_child); int class_interface_register(struct class_interface *class_intf) { @@ -829,7 +973,7 @@ int class_interface_register(struct class_interface *class_intf) void class_interface_unregister(struct class_interface *class_intf) { - struct class * parent = class_intf->class; + struct class *parent = class_intf->class; struct class_device *class_dev; struct device *dev; @@ -853,15 +997,14 @@ void class_interface_unregister(struct class_interface *class_intf) int __init classes_init(void) { - int retval; - - retval = subsystem_register(&class_subsys); - if (retval) - return retval; + class_kset = kset_create_and_add("class", NULL, NULL); + if (!class_kset) + return -ENOMEM; /* ick, this is ugly, the things we go through to keep from showing up * in sysfs... */ kset_init(&class_obj_subsys); + kobject_set_name(&class_obj_subsys.kobj, "class_obj"); if (!class_obj_subsys.kobj.parent) class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; return 0; diff --git a/drivers/base/core.c b/drivers/base/core.c index 2683eac30c68..b1727876182c 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -18,18 +18,26 @@ #include <linux/string.h> #include <linux/kdev_t.h> #include <linux/notifier.h> - +#include <linux/genhd.h> #include <asm/semaphore.h> #include "base.h" #include "power/power.h" -int (*platform_notify)(struct device * dev) = NULL; -int (*platform_notify_remove)(struct device * dev) = NULL; +int (*platform_notify)(struct device *dev) = NULL; +int (*platform_notify_remove)(struct device *dev) = NULL; -/* - * sysfs bindings for devices. - */ +#ifdef CONFIG_BLOCK +static inline int device_is_not_partition(struct device *dev) +{ + return !(dev->type == &part_type); +} +#else +static inline int device_is_not_partition(struct device *dev) +{ + return 1; +} +#endif /** * dev_driver_string - Return a device's driver name, if at all possible @@ -51,11 +59,11 @@ EXPORT_SYMBOL(dev_driver_string); #define to_dev(obj) container_of(obj, struct device, kobj) #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) -static ssize_t -dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) +static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) { - struct device_attribute * dev_attr = to_dev_attr(attr); - struct device * dev = to_dev(kobj); + struct device_attribute *dev_attr = to_dev_attr(attr); + struct device *dev = to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->show) @@ -63,12 +71,11 @@ dev_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) return ret; } -static ssize_t -dev_attr_store(struct kobject * kobj, struct attribute * attr, - const char * buf, size_t count) +static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t count) { - struct device_attribute * dev_attr = to_dev_attr(attr); - struct device * dev = to_dev(kobj); + struct device_attribute *dev_attr = to_dev_attr(attr); + struct device *dev = to_dev(kobj); ssize_t ret = -EIO; if (dev_attr->store) @@ -90,9 +97,9 @@ static struct sysfs_ops dev_sysfs_ops = { * reaches 0. We forward the call to the device's release * method, which should handle actually freeing the structure. */ -static void device_release(struct kobject * kobj) +static void device_release(struct kobject *kobj) { - struct device * dev = to_dev(kobj); + struct device *dev = to_dev(kobj); if (dev->release) dev->release(dev); @@ -101,8 +108,8 @@ static void device_release(struct kobject * kobj) else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); else { - printk(KERN_ERR "Device '%s' does not have a release() function, " - "it is broken and must be fixed.\n", + printk(KERN_ERR "Device '%s' does not have a release() " + "function, it is broken and must be fixed.\n", dev->bus_id); WARN_ON(1); } @@ -185,7 +192,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); if (dev->driver) - add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); + add_uevent_var(env, "PHYSDEVDRIVER=%s", + dev->driver->name); } #endif @@ -193,15 +201,16 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->bus && dev->bus->uevent) { retval = dev->bus->uevent(dev, env); if (retval) - pr_debug ("%s: bus uevent() returned %d\n", - __FUNCTION__, retval); + pr_debug("device: '%s': %s: bus uevent() returned %d\n", + dev->bus_id, __FUNCTION__, retval); } /* have the class specific function add its stuff */ if (dev->class && dev->class->dev_uevent) { retval = dev->class->dev_uevent(dev, env); if (retval) - pr_debug("%s: class uevent() returned %d\n", + pr_debug("device: '%s': %s: class uevent() " + "returned %d\n", dev->bus_id, __FUNCTION__, retval); } @@ -209,7 +218,8 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, if (dev->type && dev->type->uevent) { retval = dev->type->uevent(dev, env); if (retval) - pr_debug("%s: dev_type uevent() returned %d\n", + pr_debug("device: '%s': %s: dev_type uevent() " + "returned %d\n", dev->bus_id, __FUNCTION__, retval); } @@ -325,7 +335,8 @@ static int device_add_groups(struct device *dev, error = sysfs_create_group(&dev->kobj, groups[i]); if (error) { while (--i >= 0) - sysfs_remove_group(&dev->kobj, groups[i]); + sysfs_remove_group(&dev->kobj, + groups[i]); break; } } @@ -401,20 +412,15 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr, static struct device_attribute devt_attr = __ATTR(dev, S_IRUGO, show_dev, NULL); -/* - * devices_subsys - structure to be registered with kobject core. - */ - -decl_subsys(devices, &device_ktype, &device_uevent_ops); - +/* kset to create /sys/devices/ */ +struct kset *devices_kset; /** - * device_create_file - create sysfs attribute file for device. - * @dev: device. - * @attr: device attribute descriptor. + * device_create_file - create sysfs attribute file for device. + * @dev: device. + * @attr: device attribute descriptor. */ - -int device_create_file(struct device * dev, struct device_attribute * attr) +int device_create_file(struct device *dev, struct device_attribute *attr) { int error = 0; if (get_device(dev)) { @@ -425,12 +431,11 @@ int device_create_file(struct device * dev, struct device_attribute * attr) } /** - * device_remove_file - remove sysfs attribute file. - * @dev: device. - * @attr: device attribute descriptor. + * device_remove_file - remove sysfs attribute file. + * @dev: device. + * @attr: device attribute descriptor. */ - -void device_remove_file(struct device * dev, struct device_attribute * attr) +void device_remove_file(struct device *dev, struct device_attribute *attr) { if (get_device(dev)) { sysfs_remove_file(&dev->kobj, &attr->attr); @@ -511,22 +516,20 @@ static void klist_children_put(struct klist_node *n) put_device(dev); } - /** - * device_initialize - init device structure. - * @dev: device. + * device_initialize - init device structure. + * @dev: device. * - * This prepares the device for use by other layers, - * including adding it to the device hierarchy. - * It is the first half of device_register(), if called by - * that, though it can also be called separately, so one - * may use @dev's fields (e.g. the refcount). + * This prepares the device for use by other layers, + * including adding it to the device hierarchy. + * It is the first half of device_register(), if called by + * that, though it can also be called separately, so one + * may use @dev's fields (e.g. the refcount). */ - void device_initialize(struct device *dev) { - kobj_set_kset_s(dev, devices_subsys); - kobject_init(&dev->kobj); + dev->kobj.kset = devices_kset; + kobject_init(&dev->kobj, &device_ktype); klist_init(&dev->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); @@ -539,36 +542,39 @@ void device_initialize(struct device *dev) } #ifdef CONFIG_SYSFS_DEPRECATED -static struct kobject * get_device_parent(struct device *dev, - struct device *parent) +static struct kobject *get_device_parent(struct device *dev, + struct device *parent) { - /* - * Set the parent to the class, not the parent device - * for topmost devices in class hierarchy. - * This keeps sysfs from having a symlink to make old - * udevs happy - */ + /* class devices without a parent live in /sys/class/<classname>/ */ if (dev->class && (!parent || parent->class != dev->class)) return &dev->class->subsys.kobj; + /* all other devices keep their parent */ else if (parent) return &parent->kobj; return NULL; } + +static inline void cleanup_device_parent(struct device *dev) {} +static inline void cleanup_glue_dir(struct device *dev, + struct kobject *glue_dir) {} #else static struct kobject *virtual_device_parent(struct device *dev) { static struct kobject *virtual_dir = NULL; if (!virtual_dir) - virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual"); + virtual_dir = kobject_create_and_add("virtual", + &devices_kset->kobj); return virtual_dir; } -static struct kobject * get_device_parent(struct device *dev, - struct device *parent) +static struct kobject *get_device_parent(struct device *dev, + struct device *parent) { + int retval; + if (dev->class) { struct kobject *kobj = NULL; struct kobject *parent_kobj; @@ -576,8 +582,8 @@ static struct kobject * get_device_parent(struct device *dev, /* * If we have no parent, we live in "virtual". - * Class-devices with a bus-device as parent, live - * in a class-directory to prevent namespace collisions. + * Class-devices with a non class-device as parent, live + * in a "glue" directory to prevent namespace collisions. */ if (parent == NULL) parent_kobj = virtual_device_parent(dev); @@ -598,25 +604,45 @@ static struct kobject * get_device_parent(struct device *dev, return kobj; /* or create a new class-directory at the parent device */ - return kobject_kset_add_dir(&dev->class->class_dirs, - parent_kobj, dev->class->name); + k = kobject_create(); + if (!k) + return NULL; + k->kset = &dev->class->class_dirs; + retval = kobject_add(k, parent_kobj, "%s", dev->class->name); + if (retval < 0) { + kobject_put(k); + return NULL; + } + /* do not emit an uevent for this simple "glue" directory */ + return k; } if (parent) return &parent->kobj; return NULL; } + +static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) +{ + /* see if we live in a "glue" directory */ + if (!dev->class || glue_dir->kset != &dev->class->class_dirs) + return; + + kobject_put(glue_dir); +} + +static void cleanup_device_parent(struct device *dev) +{ + cleanup_glue_dir(dev, dev->kobj.parent); +} #endif -static int setup_parent(struct device *dev, struct device *parent) +static void setup_parent(struct device *dev, struct device *parent) { struct kobject *kobj; kobj = get_device_parent(dev, parent); - if (IS_ERR(kobj)) - return PTR_ERR(kobj); if (kobj) dev->kobj.parent = kobj; - return 0; } static int device_add_class_symlinks(struct device *dev) @@ -625,65 +651,76 @@ static int device_add_class_symlinks(struct device *dev) if (!dev->class) return 0; + error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, "subsystem"); if (error) goto out; - /* - * If this is not a "fake" compatible device, then create the - * symlink from the class to the device. - */ - if (dev->kobj.parent != &dev->class->subsys.kobj) { + +#ifdef CONFIG_SYSFS_DEPRECATED + /* stacked class devices need a symlink in the class directory */ + if (dev->kobj.parent != &dev->class->subsys.kobj && + device_is_not_partition(dev)) { error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, dev->bus_id); if (error) goto out_subsys; } - if (dev->parent) { -#ifdef CONFIG_SYSFS_DEPRECATED - { - struct device *parent = dev->parent; - char *class_name; - - /* - * In old sysfs stacked class devices had 'device' - * link pointing to real device instead of parent - */ - while (parent->class && !parent->bus && parent->parent) - parent = parent->parent; - - error = sysfs_create_link(&dev->kobj, - &parent->kobj, - "device"); - if (error) - goto out_busid; - class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - error = sysfs_create_link(&dev->parent->kobj, - &dev->kobj, class_name); - kfree(class_name); - if (error) - goto out_device; - } -#else - error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, + if (dev->parent && device_is_not_partition(dev)) { + struct device *parent = dev->parent; + char *class_name; + + /* + * stacked class devices have the 'device' link + * pointing to the bus device instead of the parent + */ + while (parent->class && !parent->bus && parent->parent) + parent = parent->parent; + + error = sysfs_create_link(&dev->kobj, + &parent->kobj, "device"); if (error) goto out_busid; -#endif + + class_name = make_class_name(dev->class->name, + &dev->kobj); + if (class_name) + error = sysfs_create_link(&dev->parent->kobj, + &dev->kobj, class_name); + kfree(class_name); + if (error) + goto out_device; } return 0; -#ifdef CONFIG_SYSFS_DEPRECATED out_device: - if (dev->parent) + if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); -#endif out_busid: - if (dev->kobj.parent != &dev->class->subsys.kobj) + if (dev->kobj.parent != &dev->class->subsys.kobj && + device_is_not_partition(dev)) sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#else + /* link in the class directory pointing to the device */ + error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, + dev->bus_id); + if (error) + goto out_subsys; + + if (dev->parent && device_is_not_partition(dev)) { + error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, + "device"); + if (error) + goto out_busid; + } + return 0; + +out_busid: + sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#endif + out_subsys: sysfs_remove_link(&dev->kobj, "subsystem"); out: @@ -694,8 +731,9 @@ static void device_remove_class_symlinks(struct device *dev) { if (!dev->class) return; - if (dev->parent) { + #ifdef CONFIG_SYSFS_DEPRECATED + if (dev->parent && device_is_not_partition(dev)) { char *class_name; class_name = make_class_name(dev->class->name, &dev->kobj); @@ -703,45 +741,59 @@ static void device_remove_class_symlinks(struct device *dev) sysfs_remove_link(&dev->parent->kobj, class_name); kfree(class_name); } -#endif sysfs_remove_link(&dev->kobj, "device"); } - if (dev->kobj.parent != &dev->class->subsys.kobj) + + if (dev->kobj.parent != &dev->class->subsys.kobj && + device_is_not_partition(dev)) sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#else + if (dev->parent && device_is_not_partition(dev)) + sysfs_remove_link(&dev->kobj, "device"); + + sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); +#endif + sysfs_remove_link(&dev->kobj, "subsystem"); } /** - * device_add - add device to device hierarchy. - * @dev: device. + * device_add - add device to device hierarchy. + * @dev: device. * - * This is part 2 of device_register(), though may be called - * separately _iff_ device_initialize() has been called separately. + * This is part 2 of device_register(), though may be called + * separately _iff_ device_initialize() has been called separately. * - * This adds it to the kobject hierarchy via kobject_add(), adds it - * to the global and sibling lists for the device, then - * adds it to the other relevant subsystems of the driver model. + * This adds it to the kobject hierarchy via kobject_add(), adds it + * to the global and sibling lists for the device, then + * adds it to the other relevant subsystems of the driver model. */ int device_add(struct device *dev) { struct device *parent = NULL; struct class_interface *class_intf; - int error = -EINVAL; + int error; + + error = pm_sleep_lock(); + if (error) { + dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__); + dump_stack(); + return error; + } dev = get_device(dev); - if (!dev || !strlen(dev->bus_id)) + if (!dev || !strlen(dev->bus_id)) { + error = -EINVAL; goto Error; + } - pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); + pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); parent = get_device(dev->parent); - error = setup_parent(dev, parent); - if (error) - goto Error; + setup_parent(dev, parent); /* first, register with generic layer. */ - kobject_set_name(&dev->kobj, "%s", dev->bus_id); - error = kobject_add(&dev->kobj); + error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); if (error) goto Error; @@ -751,7 +803,7 @@ int device_add(struct device *dev) /* notify clients of device entry (new way) */ if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_ADD_DEVICE, dev); error = device_create_file(dev, &uevent_attr); @@ -795,13 +847,14 @@ int device_add(struct device *dev) } Done: put_device(dev); + pm_sleep_unlock(); return error; BusError: device_pm_remove(dev); dpm_sysfs_remove(dev); PMError: if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); device_remove_attrs(dev); AttrsError: @@ -809,124 +862,84 @@ int device_add(struct device *dev) SymlinkError: if (MAJOR(dev->devt)) device_remove_file(dev, &devt_attr); - - if (dev->class) { - sysfs_remove_link(&dev->kobj, "subsystem"); - /* If this is not a "fake" compatible device, remove the - * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_remove_link(&dev->class->subsys.kobj, - dev->bus_id); - if (parent) { -#ifdef CONFIG_SYSFS_DEPRECATED - char *class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - sysfs_remove_link(&dev->parent->kobj, - class_name); - kfree(class_name); -#endif - sysfs_remove_link(&dev->kobj, "device"); - } - } ueventattrError: device_remove_file(dev, &uevent_attr); attrError: kobject_uevent(&dev->kobj, KOBJ_REMOVE); kobject_del(&dev->kobj); Error: + cleanup_device_parent(dev); if (parent) put_device(parent); goto Done; } - /** - * device_register - register a device with the system. - * @dev: pointer to the device structure + * device_register - register a device with the system. + * @dev: pointer to the device structure * - * This happens in two clean steps - initialize the device - * and add it to the system. The two steps can be called - * separately, but this is the easiest and most common. - * I.e. you should only call the two helpers separately if - * have a clearly defined need to use and refcount the device - * before it is added to the hierarchy. + * This happens in two clean steps - initialize the device + * and add it to the system. The two steps can be called + * separately, but this is the easiest and most common. + * I.e. you should only call the two helpers separately if + * have a clearly defined need to use and refcount the device + * before it is added to the hierarchy. */ - int device_register(struct device *dev) { device_initialize(dev); return device_add(dev); } - /** - * get_device - increment reference count for device. - * @dev: device. + * get_device - increment reference count for device. + * @dev: device. * - * This simply forwards the call to kobject_get(), though - * we do take care to provide for the case that we get a NULL - * pointer passed in. + * This simply forwards the call to kobject_get(), though + * we do take care to provide for the case that we get a NULL + * pointer passed in. */ - -struct device * get_device(struct device * dev) +struct device *get_device(struct device *dev) { return dev ? to_dev(kobject_get(&dev->kobj)) : NULL; } - /** - * put_device - decrement reference count. - * @dev: device in question. + * put_device - decrement reference count. + * @dev: device in question. */ -void put_device(struct device * dev) +void put_device(struct device *dev) { + /* might_sleep(); */ if (dev) kobject_put(&dev->kobj); } - /** - * device_del - delete device from system. - * @dev: device. + * device_del - delete device from system. + * @dev: device. * - * This is the first part of the device unregistration - * sequence. This removes the device from the lists we control - * from here, has it removed from the other driver model - * subsystems it was added to in device_add(), and removes it - * from the kobject hierarchy. + * This is the first part of the device unregistration + * sequence. This removes the device from the lists we control + * from here, has it removed from the other driver model + * subsystems it was added to in device_add(), and removes it + * from the kobject hierarchy. * - * NOTE: this should be called manually _iff_ device_add() was - * also called manually. + * NOTE: this should be called manually _iff_ device_add() was + * also called manually. */ - -void device_del(struct device * dev) +void device_del(struct device *dev) { - struct device * parent = dev->parent; + struct device *parent = dev->parent; struct class_interface *class_intf; + device_pm_remove(dev); if (parent) klist_del(&dev->knode_parent); if (MAJOR(dev->devt)) device_remove_file(dev, &devt_attr); if (dev->class) { - sysfs_remove_link(&dev->kobj, "subsystem"); - /* If this is not a "fake" compatible device, remove the - * symlink from the class to the device. */ - if (dev->kobj.parent != &dev->class->subsys.kobj) - sysfs_remove_link(&dev->class->subsys.kobj, - dev->bus_id); - if (parent) { -#ifdef CONFIG_SYSFS_DEPRECATED - char *class_name = make_class_name(dev->class->name, - &dev->kobj); - if (class_name) - sysfs_remove_link(&dev->parent->kobj, - class_name); - kfree(class_name); -#endif - sysfs_remove_link(&dev->kobj, "device"); - } + device_remove_class_symlinks(dev); down(&dev->class->sem); /* notify any interfaces that the device is now gone */ @@ -936,31 +949,6 @@ void device_del(struct device * dev) /* remove the device from the class list */ list_del_init(&dev->node); up(&dev->class->sem); - - /* If we live in a parent class-directory, unreference it */ - if (dev->kobj.parent->kset == &dev->class->class_dirs) { - struct device *d; - int other = 0; - - /* - * if we are the last child of our class, delete - * our class-directory at this parent - */ - down(&dev->class->sem); - list_for_each_entry(d, &dev->class->devices, node) { - if (d == dev) - continue; - if (d->kobj.parent == dev->kobj.parent) { - other = 1; - break; - } - } - if (!other) - kobject_del(dev->kobj.parent); - - kobject_put(dev->kobj.parent); - up(&dev->class->sem); - } } device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); @@ -979,57 +967,55 @@ void device_del(struct device * dev) if (platform_notify_remove) platform_notify_remove(dev); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); - device_pm_remove(dev); kobject_uevent(&dev->kobj, KOBJ_REMOVE); + cleanup_device_parent(dev); kobject_del(&dev->kobj); - if (parent) - put_device(parent); + put_device(parent); } /** - * device_unregister - unregister device from system. - * @dev: device going away. + * device_unregister - unregister device from system. + * @dev: device going away. * - * We do this in two parts, like we do device_register(). First, - * we remove it from all the subsystems with device_del(), then - * we decrement the reference count via put_device(). If that - * is the final reference count, the device will be cleaned up - * via device_release() above. Otherwise, the structure will - * stick around until the final reference to the device is dropped. + * We do this in two parts, like we do device_register(). First, + * we remove it from all the subsystems with device_del(), then + * we decrement the reference count via put_device(). If that + * is the final reference count, the device will be cleaned up + * via device_release() above. Otherwise, the structure will + * stick around until the final reference to the device is dropped. */ -void device_unregister(struct device * dev) +void device_unregister(struct device *dev) { - pr_debug("DEV: Unregistering device. ID = '%s'\n", dev->bus_id); + pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); device_del(dev); put_device(dev); } - -static struct device * next_device(struct klist_iter * i) +static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); + struct klist_node *n = klist_next(i); return n ? container_of(n, struct device, knode_parent) : NULL; } /** - * device_for_each_child - device child iterator. - * @parent: parent struct device. - * @data: data for the callback. - * @fn: function to be called for each device. + * device_for_each_child - device child iterator. + * @parent: parent struct device. + * @data: data for the callback. + * @fn: function to be called for each device. * - * Iterate over @parent's child devices, and call @fn for each, - * passing it @data. + * Iterate over @parent's child devices, and call @fn for each, + * passing it @data. * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. */ -int device_for_each_child(struct device * parent, void * data, - int (*fn)(struct device *, void *)) +int device_for_each_child(struct device *parent, void *data, + int (*fn)(struct device *dev, void *data)) { struct klist_iter i; - struct device * child; + struct device *child; int error = 0; klist_iter_init(&parent->klist_children, &i); @@ -1054,8 +1040,8 @@ int device_for_each_child(struct device * parent, void * data, * current device can be obtained, this function will return to the caller * and not iterate over any more devices. */ -struct device * device_find_child(struct device *parent, void *data, - int (*match)(struct device *, void *)) +struct device *device_find_child(struct device *parent, void *data, + int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *child; @@ -1073,7 +1059,10 @@ struct device * device_find_child(struct device *parent, void *data, int __init devices_init(void) { - return subsystem_register(&devices_subsys); + devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); + if (!devices_kset) + return -ENOMEM; + return 0; } EXPORT_SYMBOL_GPL(device_for_each_child); @@ -1094,7 +1083,7 @@ EXPORT_SYMBOL_GPL(device_remove_file); static void device_create_release(struct device *dev) { - pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id); + pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); kfree(dev); } @@ -1156,14 +1145,11 @@ error: EXPORT_SYMBOL_GPL(device_create); /** - * device_destroy - removes a device that was created with device_create() + * find_device - finds a device that was created with device_create() * @class: pointer to the struct class that this device was registered with * @devt: the dev_t of the device that was previously registered - * - * This call unregisters and cleans up a device that was created with a - * call to device_create(). */ -void device_destroy(struct class *class, dev_t devt) +static struct device *find_device(struct class *class, dev_t devt) { struct device *dev = NULL; struct device *dev_tmp; @@ -1176,12 +1162,54 @@ void device_destroy(struct class *class, dev_t devt) } } up(&class->sem); + return dev; +} +/** + * device_destroy - removes a device that was created with device_create() + * @class: pointer to the struct class that this device was registered with + * @devt: the dev_t of the device that was previously registered + * + * This call unregisters and cleans up a device that was created with a + * call to device_create(). + */ +void device_destroy(struct class *class, dev_t devt) +{ + struct device *dev; + + dev = find_device(class, devt); if (dev) device_unregister(dev); } EXPORT_SYMBOL_GPL(device_destroy); +#ifdef CONFIG_PM_SLEEP +/** + * destroy_suspended_device - asks the PM core to remove a suspended device + * @class: pointer to the struct class that this device was registered with + * @devt: the dev_t of the device that was previously registered + * + * This call notifies the PM core of the necessity to unregister a suspended + * device created with a call to device_create() (devices cannot be + * unregistered directly while suspended, since the PM core holds their + * semaphores at that time). + * + * It can only be called within the scope of a system sleep transition. In + * practice this means it has to be directly or indirectly invoked either by + * a suspend or resume method, or by the PM core (e.g. via + * disable_nonboot_cpus() or enable_nonboot_cpus()). + */ +void destroy_suspended_device(struct class *class, dev_t devt) +{ + struct device *dev; + + dev = find_device(class, devt); + if (dev) + device_pm_schedule_removal(dev); +} +EXPORT_SYMBOL_GPL(destroy_suspended_device); +#endif /* CONFIG_PM_SLEEP */ + /** * device_rename - renames a device * @dev: the pointer to the struct device to be renamed @@ -1198,7 +1226,8 @@ int device_rename(struct device *dev, char *new_name) if (!dev) return -EINVAL; - pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); + pr_debug("device: '%s': %s: renaming to '%s'\n", dev->bus_id, + __FUNCTION__, new_name); #ifdef CONFIG_SYSFS_DEPRECATED if ((dev->class) && (dev->parent)) @@ -1279,8 +1308,7 @@ static int device_move_class_links(struct device *dev, class_name); if (error) sysfs_remove_link(&dev->kobj, "device"); - } - else + } else error = 0; out: kfree(class_name); @@ -1311,16 +1339,13 @@ int device_move(struct device *dev, struct device *new_parent) return -EINVAL; new_parent = get_device(new_parent); - new_parent_kobj = get_device_parent (dev, new_parent); - if (IS_ERR(new_parent_kobj)) { - error = PTR_ERR(new_parent_kobj); - put_device(new_parent); - goto out; - } - pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id, - new_parent ? new_parent->bus_id : "<NULL>"); + new_parent_kobj = get_device_parent(dev, new_parent); + + pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, + __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>"); error = kobject_move(&dev->kobj, new_parent_kobj); if (error) { + cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); goto out; } @@ -1343,6 +1368,7 @@ int device_move(struct device *dev, struct device *new_parent) klist_add_tail(&dev->knode_parent, &old_parent->klist_children); } + cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); goto out; } @@ -1352,5 +1378,23 @@ out: put_device(dev); return error; } - EXPORT_SYMBOL_GPL(device_move); + +/** + * device_shutdown - call ->shutdown() on each device to shutdown. + */ +void device_shutdown(void) +{ + struct device *dev, *devn; + + list_for_each_entry_safe_reverse(dev, devn, &devices_kset->list, + kobj.entry) { + if (dev->bus && dev->bus->shutdown) { + dev_dbg(dev, "shutdown\n"); + dev->bus->shutdown(dev); + } else if (dev->driver && dev->driver->shutdown) { + dev_dbg(dev, "shutdown\n"); + dev->driver->shutdown(dev); + } + } +} diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 40545071e3c9..c5885f5ce0ac 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -14,7 +14,7 @@ #include "base.h" struct sysdev_class cpu_sysdev_class = { - set_kset_name("cpu"), + .name = "cpu", }; EXPORT_SYMBOL(cpu_sysdev_class); diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 7ac474db88c5..a5cde94bb982 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -1,18 +1,20 @@ /* - * drivers/base/dd.c - The core device/driver interactions. + * drivers/base/dd.c - The core device/driver interactions. * - * This file contains the (sometimes tricky) code that controls the - * interactions between devices and drivers, which primarily includes - * driver binding and unbinding. + * This file contains the (sometimes tricky) code that controls the + * interactions between devices and drivers, which primarily includes + * driver binding and unbinding. * - * All of this code used to exist in drivers/base/bus.c, but was - * relocated to here in the name of compartmentalization (since it wasn't - * strictly code just for the 'struct bus_type'. + * All of this code used to exist in drivers/base/bus.c, but was + * relocated to here in the name of compartmentalization (since it wasn't + * strictly code just for the 'struct bus_type'. * - * Copyright (c) 2002-5 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2002-5 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * - * This file is released under the GPLv2 + * This file is released under the GPLv2 */ #include <linux/device.h> @@ -23,8 +25,6 @@ #include "base.h" #include "power/power.h" -#define to_drv(node) container_of(node, struct device_driver, kobj.entry) - static void driver_bound(struct device *dev) { @@ -34,27 +34,27 @@ static void driver_bound(struct device *dev) return; } - pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id, dev->driver->name); + pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->bus_id, + __FUNCTION__, dev->driver->name); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); + klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) { int ret; - ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, + ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj, kobject_name(&dev->kobj)); if (ret == 0) { - ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj, + ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj, "driver"); if (ret) - sysfs_remove_link(&dev->driver->kobj, + sysfs_remove_link(&dev->driver->p->kobj, kobject_name(&dev->kobj)); } return ret; @@ -65,24 +65,24 @@ static void driver_sysfs_remove(struct device *dev) struct device_driver *drv = dev->driver; if (drv) { - sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); + sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj)); sysfs_remove_link(&dev->kobj, "driver"); } } /** - * device_bind_driver - bind a driver to one device. - * @dev: device. + * device_bind_driver - bind a driver to one device. + * @dev: device. * - * Allow manual attachment of a driver to a device. - * Caller must have already set @dev->driver. + * Allow manual attachment of a driver to a device. + * Caller must have already set @dev->driver. * - * Note that this does not modify the bus reference count - * nor take the bus's rwsem. Please verify those are accounted - * for before calling this. (It is ok to call with no other effort - * from a driver's probe() method.) + * Note that this does not modify the bus reference count + * nor take the bus's rwsem. Please verify those are accounted + * for before calling this. (It is ok to call with no other effort + * from a driver's probe() method.) * - * This function must be called with @dev->sem held. + * This function must be called with @dev->sem held. */ int device_bind_driver(struct device *dev) { @@ -93,6 +93,7 @@ int device_bind_driver(struct device *dev) driver_bound(dev); return ret; } +EXPORT_SYMBOL_GPL(device_bind_driver); static atomic_t probe_count = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); @@ -102,8 +103,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) int ret = 0; atomic_inc(&probe_count); - pr_debug("%s: Probing driver %s with device %s\n", - drv->bus->name, drv->name, dev->bus_id); + pr_debug("bus: '%s': %s: probing driver %s with device %s\n", + drv->bus->name, __FUNCTION__, drv->name, dev->bus_id); WARN_ON(!list_empty(&dev->devres_head)); dev->driver = drv; @@ -125,8 +126,8 @@ static int really_probe(struct device *dev, struct device_driver *drv) driver_bound(dev); ret = 1; - pr_debug("%s: Bound Device %s to Driver %s\n", - drv->bus->name, dev->bus_id, drv->name); + pr_debug("bus: '%s': %s: bound device %s to driver %s\n", + drv->bus->name, __FUNCTION__, dev->bus_id, drv->name); goto done; probe_failed: @@ -183,7 +184,7 @@ int driver_probe_done(void) * This function must be called with @dev->sem held. When called for a * USB interface, @dev->parent->sem must be held as well. */ -int driver_probe_device(struct device_driver * drv, struct device * dev) +int driver_probe_device(struct device_driver *drv, struct device *dev) { int ret = 0; @@ -192,8 +193,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev) if (drv->bus->match && !drv->bus->match(dev, drv)) goto done; - pr_debug("%s: Matched Device %s with Driver %s\n", - drv->bus->name, dev->bus_id, drv->name); + pr_debug("bus: '%s': %s: matched device %s with driver %s\n", + drv->bus->name, __FUNCTION__, dev->bus_id, drv->name); ret = really_probe(dev, drv); @@ -201,27 +202,27 @@ done: return ret; } -static int __device_attach(struct device_driver * drv, void * data) +static int __device_attach(struct device_driver *drv, void *data) { - struct device * dev = data; + struct device *dev = data; return driver_probe_device(drv, dev); } /** - * device_attach - try to attach device to a driver. - * @dev: device. + * device_attach - try to attach device to a driver. + * @dev: device. * - * Walk the list of drivers that the bus has and call - * driver_probe_device() for each pair. If a compatible - * pair is found, break out and return. + * Walk the list of drivers that the bus has and call + * driver_probe_device() for each pair. If a compatible + * pair is found, break out and return. * - * Returns 1 if the device was bound to a driver; - * 0 if no matching device was found; - * -ENODEV if the device is not registered. + * Returns 1 if the device was bound to a driver; + * 0 if no matching device was found; + * -ENODEV if the device is not registered. * - * When called for a USB interface, @dev->parent->sem must be held. + * When called for a USB interface, @dev->parent->sem must be held. */ -int device_attach(struct device * dev) +int device_attach(struct device *dev) { int ret = 0; @@ -240,10 +241,11 @@ int device_attach(struct device * dev) up(&dev->sem); return ret; } +EXPORT_SYMBOL_GPL(device_attach); -static int __driver_attach(struct device * dev, void * data) +static int __driver_attach(struct device *dev, void *data) { - struct device_driver * drv = data; + struct device_driver *drv = data; /* * Lock device and try to bind to it. We drop the error @@ -268,35 +270,35 @@ static int __driver_attach(struct device * dev, void * data) } /** - * driver_attach - try to bind driver to devices. - * @drv: driver. + * driver_attach - try to bind driver to devices. + * @drv: driver. * - * Walk the list of devices that the bus has on it and try to - * match the driver with each one. If driver_probe_device() - * returns 0 and the @dev->driver is set, we've found a - * compatible pair. + * Walk the list of devices that the bus has on it and try to + * match the driver with each one. If driver_probe_device() + * returns 0 and the @dev->driver is set, we've found a + * compatible pair. */ -int driver_attach(struct device_driver * drv) +int driver_attach(struct device_driver *drv) { return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); } +EXPORT_SYMBOL_GPL(driver_attach); /* - * __device_release_driver() must be called with @dev->sem held. - * When called for a USB interface, @dev->parent->sem must be held as well. + * __device_release_driver() must be called with @dev->sem held. + * When called for a USB interface, @dev->parent->sem must be held as well. */ -static void __device_release_driver(struct device * dev) +static void __device_release_driver(struct device *dev) { - struct device_driver * drv; + struct device_driver *drv; - drv = get_driver(dev->driver); + drv = dev->driver; if (drv) { driver_sysfs_remove(dev); sysfs_remove_link(&dev->kobj, "driver"); - klist_remove(&dev->knode_driver); if (dev->bus) - blocking_notifier_call_chain(&dev->bus->bus_notifier, + blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_UNBIND_DRIVER, dev); @@ -306,18 +308,18 @@ static void __device_release_driver(struct device * dev) drv->remove(dev); devres_release_all(dev); dev->driver = NULL; - put_driver(drv); + klist_remove(&dev->knode_driver); } } /** - * device_release_driver - manually detach device from driver. - * @dev: device. + * device_release_driver - manually detach device from driver. + * @dev: device. * - * Manually detach device from driver. - * When called for a USB interface, @dev->parent->sem must be held. + * Manually detach device from driver. + * When called for a USB interface, @dev->parent->sem must be held. */ -void device_release_driver(struct device * dev) +void device_release_driver(struct device *dev) { /* * If anyone calls device_release_driver() recursively from @@ -328,26 +330,26 @@ void device_release_driver(struct device * dev) __device_release_driver(dev); up(&dev->sem); } - +EXPORT_SYMBOL_GPL(device_release_driver); /** * driver_detach - detach driver from all devices it controls. * @drv: driver. */ -void driver_detach(struct device_driver * drv) +void driver_detach(struct device_driver *drv) { - struct device * dev; + struct device *dev; for (;;) { - spin_lock(&drv->klist_devices.k_lock); - if (list_empty(&drv->klist_devices.k_list)) { - spin_unlock(&drv->klist_devices.k_lock); + spin_lock(&drv->p->klist_devices.k_lock); + if (list_empty(&drv->p->klist_devices.k_list)) { + spin_unlock(&drv->p->klist_devices.k_lock); break; } - dev = list_entry(drv->klist_devices.k_list.prev, + dev = list_entry(drv->p->klist_devices.k_list.prev, struct device, knode_driver.n_node); get_device(dev); - spin_unlock(&drv->klist_devices.k_lock); + spin_unlock(&drv->p->klist_devices.k_lock); if (dev->parent) /* Needed for USB */ down(&dev->parent->sem); @@ -360,9 +362,3 @@ void driver_detach(struct device_driver * drv) put_device(dev); } } - -EXPORT_SYMBOL_GPL(device_bind_driver); -EXPORT_SYMBOL_GPL(device_release_driver); -EXPORT_SYMBOL_GPL(device_attach); -EXPORT_SYMBOL_GPL(driver_attach); - diff --git a/drivers/base/driver.c b/drivers/base/driver.c index eb11475293ed..a35f04121a00 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -3,6 +3,8 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 * @@ -15,46 +17,42 @@ #include "base.h" #define to_dev(node) container_of(node, struct device, driver_list) -#define to_drv(obj) container_of(obj, struct device_driver, kobj) -static struct device * next_device(struct klist_iter * i) +static struct device *next_device(struct klist_iter *i) { - struct klist_node * n = klist_next(i); + struct klist_node *n = klist_next(i); return n ? container_of(n, struct device, knode_driver) : NULL; } /** - * driver_for_each_device - Iterator for devices bound to a driver. - * @drv: Driver we're iterating. - * @start: Device to begin with - * @data: Data to pass to the callback. - * @fn: Function to call for each device. + * driver_for_each_device - Iterator for devices bound to a driver. + * @drv: Driver we're iterating. + * @start: Device to begin with + * @data: Data to pass to the callback. + * @fn: Function to call for each device. * - * Iterate over the @drv's list of devices calling @fn for each one. + * Iterate over the @drv's list of devices calling @fn for each one. */ - -int driver_for_each_device(struct device_driver * drv, struct device * start, - void * data, int (*fn)(struct device *, void *)) +int driver_for_each_device(struct device_driver *drv, struct device *start, + void *data, int (*fn)(struct device *, void *)) { struct klist_iter i; - struct device * dev; + struct device *dev; int error = 0; if (!drv) return -EINVAL; - klist_iter_init_node(&drv->klist_devices, &i, + klist_iter_init_node(&drv->p->klist_devices, &i, start ? &start->knode_driver : NULL); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); return error; } - EXPORT_SYMBOL_GPL(driver_for_each_device); - /** * driver_find_device - device iterator for locating a particular device. * @drv: The device's driver @@ -70,9 +68,9 @@ EXPORT_SYMBOL_GPL(driver_for_each_device); * if it does. If the callback returns non-zero, this function will * return to the caller and not iterate over any more devices. */ -struct device * driver_find_device(struct device_driver *drv, - struct device * start, void * data, - int (*match)(struct device *, void *)) +struct device *driver_find_device(struct device_driver *drv, + struct device *start, void *data, + int (*match)(struct device *dev, void *data)) { struct klist_iter i; struct device *dev; @@ -80,7 +78,7 @@ struct device * driver_find_device(struct device_driver *drv, if (!drv) return NULL; - klist_iter_init_node(&drv->klist_devices, &i, + klist_iter_init_node(&drv->p->klist_devices, &i, (start ? &start->knode_driver : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) @@ -91,111 +89,179 @@ struct device * driver_find_device(struct device_driver *drv, EXPORT_SYMBOL_GPL(driver_find_device); /** - * driver_create_file - create sysfs file for driver. - * @drv: driver. - * @attr: driver attribute descriptor. + * driver_create_file - create sysfs file for driver. + * @drv: driver. + * @attr: driver attribute descriptor. */ - -int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) +int driver_create_file(struct device_driver *drv, + struct driver_attribute *attr) { int error; if (get_driver(drv)) { - error = sysfs_create_file(&drv->kobj, &attr->attr); + error = sysfs_create_file(&drv->p->kobj, &attr->attr); put_driver(drv); } else error = -EINVAL; return error; } - +EXPORT_SYMBOL_GPL(driver_create_file); /** - * driver_remove_file - remove sysfs file for driver. - * @drv: driver. - * @attr: driver attribute descriptor. + * driver_remove_file - remove sysfs file for driver. + * @drv: driver. + * @attr: driver attribute descriptor. */ - -void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) +void driver_remove_file(struct device_driver *drv, + struct driver_attribute *attr) { if (get_driver(drv)) { - sysfs_remove_file(&drv->kobj, &attr->attr); + sysfs_remove_file(&drv->p->kobj, &attr->attr); put_driver(drv); } } - +EXPORT_SYMBOL_GPL(driver_remove_file); /** - * get_driver - increment driver reference count. - * @drv: driver. + * driver_add_kobj - add a kobject below the specified driver + * + * You really don't want to do this, this is only here due to one looney + * iseries driver, go poke those developers if you are annoyed about + * this... */ -struct device_driver * get_driver(struct device_driver * drv) +int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, + const char *fmt, ...) { - return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; + va_list args; + char *name; + + va_start(args, fmt); + name = kvasprintf(GFP_KERNEL, fmt, args); + va_end(args); + + if (!name) + return -ENOMEM; + + return kobject_add(kobj, &drv->p->kobj, "%s", name); } +EXPORT_SYMBOL_GPL(driver_add_kobj); + +/** + * get_driver - increment driver reference count. + * @drv: driver. + */ +struct device_driver *get_driver(struct device_driver *drv) +{ + if (drv) { + struct driver_private *priv; + struct kobject *kobj; + kobj = kobject_get(&drv->p->kobj); + priv = to_driver(kobj); + return priv->driver; + } + return NULL; +} +EXPORT_SYMBOL_GPL(get_driver); /** - * put_driver - decrement driver's refcount. - * @drv: driver. + * put_driver - decrement driver's refcount. + * @drv: driver. */ -void put_driver(struct device_driver * drv) +void put_driver(struct device_driver *drv) +{ + kobject_put(&drv->p->kobj); +} +EXPORT_SYMBOL_GPL(put_driver); + +static int driver_add_groups(struct device_driver *drv, + struct attribute_group **groups) { - kobject_put(&drv->kobj); + int error = 0; + int i; + + if (groups) { + for (i = 0; groups[i]; i++) { + error = sysfs_create_group(&drv->p->kobj, groups[i]); + if (error) { + while (--i >= 0) + sysfs_remove_group(&drv->p->kobj, + groups[i]); + break; + } + } + } + return error; +} + +static void driver_remove_groups(struct device_driver *drv, + struct attribute_group **groups) +{ + int i; + + if (groups) + for (i = 0; groups[i]; i++) + sysfs_remove_group(&drv->p->kobj, groups[i]); } /** - * driver_register - register driver with bus - * @drv: driver to register + * driver_register - register driver with bus + * @drv: driver to register * - * We pass off most of the work to the bus_add_driver() call, - * since most of the things we have to do deal with the bus - * structures. + * We pass off most of the work to the bus_add_driver() call, + * since most of the things we have to do deal with the bus + * structures. */ -int driver_register(struct device_driver * drv) +int driver_register(struct device_driver *drv) { + int ret; + if ((drv->bus->probe && drv->probe) || (drv->bus->remove && drv->remove) || - (drv->bus->shutdown && drv->shutdown)) { - printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name); - } - klist_init(&drv->klist_devices, NULL, NULL); - return bus_add_driver(drv); + (drv->bus->shutdown && drv->shutdown)) + printk(KERN_WARNING "Driver '%s' needs updating - please use " + "bus_type methods\n", drv->name); + ret = bus_add_driver(drv); + if (ret) + return ret; + ret = driver_add_groups(drv, drv->groups); + if (ret) + bus_remove_driver(drv); + return ret; } +EXPORT_SYMBOL_GPL(driver_register); /** - * driver_unregister - remove driver from system. - * @drv: driver. + * driver_unregister - remove driver from system. + * @drv: driver. * - * Again, we pass off most of the work to the bus-level call. + * Again, we pass off most of the work to the bus-level call. */ - -void driver_unregister(struct device_driver * drv) +void driver_unregister(struct device_driver *drv) { + driver_remove_groups(drv, drv->groups); bus_remove_driver(drv); } +EXPORT_SYMBOL_GPL(driver_unregister); /** - * driver_find - locate driver on a bus by its name. - * @name: name of the driver. - * @bus: bus to scan for the driver. + * driver_find - locate driver on a bus by its name. + * @name: name of the driver. + * @bus: bus to scan for the driver. * - * Call kset_find_obj() to iterate over list of drivers on - * a bus to find driver by name. Return driver if found. + * Call kset_find_obj() to iterate over list of drivers on + * a bus to find driver by name. Return driver if found. * - * Note that kset_find_obj increments driver's reference count. + * Note that kset_find_obj increments driver's reference count. */ struct device_driver *driver_find(const char *name, struct bus_type *bus) { - struct kobject *k = kset_find_obj(&bus->drivers, name); - if (k) - return to_drv(k); + struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); + struct driver_private *priv; + + if (k) { + priv = to_driver(k); + return priv->driver; + } return NULL; } - -EXPORT_SYMBOL_GPL(driver_register); -EXPORT_SYMBOL_GPL(driver_unregister); -EXPORT_SYMBOL_GPL(get_driver); -EXPORT_SYMBOL_GPL(put_driver); EXPORT_SYMBOL_GPL(driver_find); - -EXPORT_SYMBOL_GPL(driver_create_file); -EXPORT_SYMBOL_GPL(driver_remove_file); diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c index 90c862932169..113815556809 100644 --- a/drivers/base/firmware.c +++ b/drivers/base/firmware.c @@ -3,11 +3,11 @@ * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (c) 2007 Novell Inc. * * This file is released under the GPLv2 - * */ - #include <linux/kobject.h> #include <linux/module.h> #include <linux/init.h> @@ -15,23 +15,13 @@ #include "base.h" -static decl_subsys(firmware, NULL, NULL); - -int firmware_register(struct kset *s) -{ - kobj_set_kset_s(s, firmware_subsys); - return subsystem_register(s); -} - -void firmware_unregister(struct kset *s) -{ - subsystem_unregister(s); -} +struct kobject *firmware_kobj; +EXPORT_SYMBOL_GPL(firmware_kobj); int __init firmware_init(void) { - return subsystem_register(&firmware_subsys); + firmware_kobj = kobject_create_and_add("firmware", NULL); + if (!firmware_kobj) + return -ENOMEM; + return 0; } - -EXPORT_SYMBOL_GPL(firmware_register); -EXPORT_SYMBOL_GPL(firmware_unregister); diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c index 7080b413ddc9..6428cba3aadd 100644 --- a/drivers/base/hypervisor.c +++ b/drivers/base/hypervisor.c @@ -2,19 +2,23 @@ * hypervisor.c - /sys/hypervisor subsystem. * * Copyright (C) IBM Corp. 2006 + * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * Copyright (C) 2007 Novell Inc. * * This file is released under the GPLv2 */ #include <linux/kobject.h> #include <linux/device.h> - #include "base.h" -decl_subsys(hypervisor, NULL, NULL); -EXPORT_SYMBOL_GPL(hypervisor_subsys); +struct kobject *hypervisor_kobj; +EXPORT_SYMBOL_GPL(hypervisor_kobj); int __init hypervisor_init(void) { - return subsystem_register(&hypervisor_subsys); + hypervisor_kobj = kobject_create_and_add("hypervisor", NULL); + if (!hypervisor_kobj) + return -ENOMEM; + return 0; } diff --git a/drivers/base/init.c b/drivers/base/init.c index 37138154f9e8..7bd9b6a5b01f 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -1,10 +1,8 @@ /* - * * Copyright (c) 2002-3 Patrick Mochel * Copyright (c) 2002-3 Open Source Development Labs * * This file is released under the GPLv2 - * */ #include <linux/device.h> @@ -14,12 +12,11 @@ #include "base.h" /** - * driver_init - initialize driver model. + * driver_init - initialize driver model. * - * Call the driver model init functions to initialize their - * subsystems. Called early from init/main.c. + * Call the driver model init functions to initialize their + * subsystems. Called early from init/main.c. */ - void __init driver_init(void) { /* These are the core pieces */ @@ -36,5 +33,4 @@ void __init driver_init(void) system_bus_init(); cpu_dev_init(); memory_dev_init(); - attribute_container_init(); } diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 7868707c7eda..7ae413fdd5fc 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -26,7 +26,7 @@ #define MEMORY_CLASS_NAME "memory" static struct sysdev_class memory_sysdev_class = { - set_kset_name(MEMORY_CLASS_NAME), + .name = MEMORY_CLASS_NAME, }; static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) diff --git a/drivers/base/module.c b/drivers/base/module.c new file mode 100644 index 000000000000..103be9cacb05 --- /dev/null +++ b/drivers/base/module.c @@ -0,0 +1,94 @@ +/* + * module.c - module sysfs fun for drivers + * + * This file is released under the GPLv2 + * + */ +#include <linux/device.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/string.h> +#include "base.h" + +static char *make_driver_name(struct device_driver *drv) +{ + char *driver_name; + + driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2, + GFP_KERNEL); + if (!driver_name) + return NULL; + + sprintf(driver_name, "%s:%s", drv->bus->name, drv->name); + return driver_name; +} + +static void module_create_drivers_dir(struct module_kobject *mk) +{ + if (!mk || mk->drivers_dir) + return; + + mk->drivers_dir = kobject_create_and_add("drivers", &mk->kobj); +} + +void module_add_driver(struct module *mod, struct device_driver *drv) +{ + char *driver_name; + int no_warn; + struct module_kobject *mk = NULL; + + if (!drv) + return; + + if (mod) + mk = &mod->mkobj; + else if (drv->mod_name) { + struct kobject *mkobj; + + /* Lookup built-in module entry in /sys/modules */ + mkobj = kset_find_obj(module_kset, drv->mod_name); + if (mkobj) { + mk = container_of(mkobj, struct module_kobject, kobj); + /* remember our module structure */ + drv->p->mkobj = mk; + /* kset_find_obj took a reference */ + kobject_put(mkobj); + } + } + + if (!mk) + return; + + /* Don't check return codes; these calls are idempotent */ + no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); + driver_name = make_driver_name(drv); + if (driver_name) { + module_create_drivers_dir(mk); + no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj, + driver_name); + kfree(driver_name); + } +} + +void module_remove_driver(struct device_driver *drv) +{ + struct module_kobject *mk = NULL; + char *driver_name; + + if (!drv) + return; + + sysfs_remove_link(&drv->p->kobj, "module"); + + if (drv->owner) + mk = &drv->owner->mkobj; + else if (drv->p->mkobj) + mk = drv->p->mkobj; + if (mk && mk->drivers_dir) { + driver_name = make_driver_name(drv); + if (driver_name) { + sysfs_remove_link(mk->drivers_dir, driver_name); + kfree(driver_name); + } + } +} diff --git a/drivers/base/node.c b/drivers/base/node.c index 88eeed72b5d6..e59861f18ce5 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -15,7 +15,7 @@ #include <linux/device.h> static struct sysdev_class node_class = { - set_kset_name("node"), + .name = "node", }; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index fb5609241482..efaf282c438c 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -20,7 +20,8 @@ #include "base.h" -#define to_platform_driver(drv) (container_of((drv), struct platform_driver, driver)) +#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ + driver)) struct device platform_bus = { .bus_id = "platform", @@ -28,14 +29,13 @@ struct device platform_bus = { EXPORT_SYMBOL_GPL(platform_bus); /** - * platform_get_resource - get a resource for a device - * @dev: platform device - * @type: resource type - * @num: resource index + * platform_get_resource - get a resource for a device + * @dev: platform device + * @type: resource type + * @num: resource index */ -struct resource * -platform_get_resource(struct platform_device *dev, unsigned int type, - unsigned int num) +struct resource *platform_get_resource(struct platform_device *dev, + unsigned int type, unsigned int num) { int i; @@ -43,8 +43,7 @@ platform_get_resource(struct platform_device *dev, unsigned int type, struct resource *r = &dev->resource[i]; if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM| - IORESOURCE_IRQ|IORESOURCE_DMA)) - == type) + IORESOURCE_IRQ|IORESOURCE_DMA)) == type) if (num-- == 0) return r; } @@ -53,9 +52,9 @@ platform_get_resource(struct platform_device *dev, unsigned int type, EXPORT_SYMBOL_GPL(platform_get_resource); /** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @num: IRQ number index + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @num: IRQ number index */ int platform_get_irq(struct platform_device *dev, unsigned int num) { @@ -66,14 +65,13 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) EXPORT_SYMBOL_GPL(platform_get_irq); /** - * platform_get_resource_byname - get a resource for a device by name - * @dev: platform device - * @type: resource type - * @name: resource name + * platform_get_resource_byname - get a resource for a device by name + * @dev: platform device + * @type: resource type + * @name: resource name */ -struct resource * -platform_get_resource_byname(struct platform_device *dev, unsigned int type, - char *name) +struct resource *platform_get_resource_byname(struct platform_device *dev, + unsigned int type, char *name) { int i; @@ -90,22 +88,23 @@ platform_get_resource_byname(struct platform_device *dev, unsigned int type, EXPORT_SYMBOL_GPL(platform_get_resource_byname); /** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @name: IRQ name + * platform_get_irq - get an IRQ for a device + * @dev: platform device + * @name: IRQ name */ int platform_get_irq_byname(struct platform_device *dev, char *name) { - struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); + struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, + name); return r ? r->start : -ENXIO; } EXPORT_SYMBOL_GPL(platform_get_irq_byname); /** - * platform_add_devices - add a numbers of platform devices - * @devs: array of platform devices to add - * @num: number of platform devices in array + * platform_add_devices - add a numbers of platform devices + * @devs: array of platform devices to add + * @num: number of platform devices in array */ int platform_add_devices(struct platform_device **devs, int num) { @@ -130,12 +129,11 @@ struct platform_object { }; /** - * platform_device_put - * @pdev: platform device to free + * platform_device_put + * @pdev: platform device to free * - * Free all memory associated with a platform device. This function - * must _only_ be externally called in error cases. All other usage - * is a bug. + * Free all memory associated with a platform device. This function must + * _only_ be externally called in error cases. All other usage is a bug. */ void platform_device_put(struct platform_device *pdev) { @@ -146,7 +144,8 @@ EXPORT_SYMBOL_GPL(platform_device_put); static void platform_device_release(struct device *dev) { - struct platform_object *pa = container_of(dev, struct platform_object, pdev.dev); + struct platform_object *pa = container_of(dev, struct platform_object, + pdev.dev); kfree(pa->pdev.dev.platform_data); kfree(pa->pdev.resource); @@ -154,12 +153,12 @@ static void platform_device_release(struct device *dev) } /** - * platform_device_alloc - * @name: base name of the device we're adding - * @id: instance id + * platform_device_alloc + * @name: base name of the device we're adding + * @id: instance id * - * Create a platform device object which can have other objects attached - * to it, and which will have attached objects freed when it is released. + * Create a platform device object which can have other objects attached + * to it, and which will have attached objects freed when it is released. */ struct platform_device *platform_device_alloc(const char *name, int id) { @@ -179,16 +178,17 @@ struct platform_device *platform_device_alloc(const char *name, int id) EXPORT_SYMBOL_GPL(platform_device_alloc); /** - * platform_device_add_resources - * @pdev: platform device allocated by platform_device_alloc to add resources to - * @res: set of resources that needs to be allocated for the device - * @num: number of resources + * platform_device_add_resources + * @pdev: platform device allocated by platform_device_alloc to add resources to + * @res: set of resources that needs to be allocated for the device + * @num: number of resources * - * Add a copy of the resources to the platform device. The memory - * associated with the resources will be freed when the platform - * device is released. + * Add a copy of the resources to the platform device. The memory + * associated with the resources will be freed when the platform device is + * released. */ -int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num) +int platform_device_add_resources(struct platform_device *pdev, + struct resource *res, unsigned int num) { struct resource *r; @@ -203,16 +203,17 @@ int platform_device_add_resources(struct platform_device *pdev, struct resource EXPORT_SYMBOL_GPL(platform_device_add_resources); /** - * platform_device_add_data - * @pdev: platform device allocated by platform_device_alloc to add resources to - * @data: platform specific data for this platform device - * @size: size of platform specific data + * platform_device_add_data + * @pdev: platform device allocated by platform_device_alloc to add resources to + * @data: platform specific data for this platform device + * @size: size of platform specific data * - * Add a copy of platform specific data to the platform device's platform_data - * pointer. The memory associated with the platform data will be freed - * when the platform device is released. + * Add a copy of platform specific data to the platform device's + * platform_data pointer. The memory associated with the platform data + * will be freed when the platform device is released. */ -int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size) +int platform_device_add_data(struct platform_device *pdev, const void *data, + size_t size) { void *d; @@ -226,11 +227,11 @@ int platform_device_add_data(struct platform_device *pdev, const void *data, siz EXPORT_SYMBOL_GPL(platform_device_add_data); /** - * platform_device_add - add a platform device to device hierarchy - * @pdev: platform device we're adding + * platform_device_add - add a platform device to device hierarchy + * @pdev: platform device we're adding * - * This is part 2 of platform_device_register(), though may be called - * separately _iff_ pdev was allocated by platform_device_alloc(). + * This is part 2 of platform_device_register(), though may be called + * separately _iff_ pdev was allocated by platform_device_alloc(). */ int platform_device_add(struct platform_device *pdev) { @@ -289,13 +290,12 @@ int platform_device_add(struct platform_device *pdev) EXPORT_SYMBOL_GPL(platform_device_add); /** - * platform_device_del - remove a platform-level device - * @pdev: platform device we're removing + * platform_device_del - remove a platform-level device + * @pdev: platform device we're removing * - * Note that this function will also release all memory- and port-based - * resources owned by the device (@dev->resource). This function - * must _only_ be externally called in error cases. All other usage - * is a bug. + * Note that this function will also release all memory- and port-based + * resources owned by the device (@dev->resource). This function must + * _only_ be externally called in error cases. All other usage is a bug. */ void platform_device_del(struct platform_device *pdev) { @@ -314,11 +314,10 @@ void platform_device_del(struct platform_device *pdev) EXPORT_SYMBOL_GPL(platform_device_del); /** - * platform_device_register - add a platform-level device - * @pdev: platform device we're adding - * + * platform_device_register - add a platform-level device + * @pdev: platform device we're adding */ -int platform_device_register(struct platform_device * pdev) +int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); return platform_device_add(pdev); @@ -326,14 +325,14 @@ int platform_device_register(struct platform_device * pdev) EXPORT_SYMBOL_GPL(platform_device_register); /** - * platform_device_unregister - unregister a platform-level device - * @pdev: platform device we're unregistering + * platform_device_unregister - unregister a platform-level device + * @pdev: platform device we're unregistering * - * Unregistration is done in 2 steps. First we release all resources - * and remove it from the subsystem, then we drop reference count by - * calling platform_device_put(). + * Unregistration is done in 2 steps. First we release all resources + * and remove it from the subsystem, then we drop reference count by + * calling platform_device_put(). */ -void platform_device_unregister(struct platform_device * pdev) +void platform_device_unregister(struct platform_device *pdev) { platform_device_del(pdev); platform_device_put(pdev); @@ -341,27 +340,29 @@ void platform_device_unregister(struct platform_device * pdev) EXPORT_SYMBOL_GPL(platform_device_unregister); /** - * platform_device_register_simple - * @name: base name of the device we're adding - * @id: instance id - * @res: set of resources that needs to be allocated for the device - * @num: number of resources + * platform_device_register_simple + * @name: base name of the device we're adding + * @id: instance id + * @res: set of resources that needs to be allocated for the device + * @num: number of resources * - * This function creates a simple platform device that requires minimal - * resource and memory management. Canned release function freeing - * memory allocated for the device allows drivers using such devices - * to be unloaded without waiting for the last reference to the device - * to be dropped. + * This function creates a simple platform device that requires minimal + * resource and memory management. Canned release function freeing memory + * allocated for the device allows drivers using such devices to be + * unloaded without waiting for the last reference to the device to be + * dropped. * - * This interface is primarily intended for use with legacy drivers - * which probe hardware directly. Because such drivers create sysfs - * device nodes themselves, rather than letting system infrastructure - * handle such device enumeration tasks, they don't fully conform to - * the Linux driver model. In particular, when such drivers are built - * as modules, they can't be "hotplugged". + * This interface is primarily intended for use with legacy drivers which + * probe hardware directly. Because such drivers create sysfs device nodes + * themselves, rather than letting system infrastructure handle such device + * enumeration tasks, they don't fully conform to the Linux driver model. + * In particular, when such drivers are built as modules, they can't be + * "hotplugged". */ -struct platform_device *platform_device_register_simple(char *name, int id, - struct resource *res, unsigned int num) +struct platform_device *platform_device_register_simple(const char *name, + int id, + struct resource *res, + unsigned int num) { struct platform_device *pdev; int retval; @@ -436,8 +437,8 @@ static int platform_drv_resume(struct device *_dev) } /** - * platform_driver_register - * @drv: platform driver structure + * platform_driver_register + * @drv: platform driver structure */ int platform_driver_register(struct platform_driver *drv) { @@ -457,8 +458,8 @@ int platform_driver_register(struct platform_driver *drv) EXPORT_SYMBOL_GPL(platform_driver_register); /** - * platform_driver_unregister - * @drv: platform driver structure + * platform_driver_unregister + * @drv: platform driver structure */ void platform_driver_unregister(struct platform_driver *drv) { @@ -497,12 +498,12 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv, * if the probe was successful, and make sure any forced probes of * new devices fail. */ - spin_lock(&platform_bus_type.klist_drivers.k_lock); + spin_lock(&platform_bus_type.p->klist_drivers.k_lock); drv->probe = NULL; - if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) + if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) retval = -ENODEV; drv->driver.probe = platform_drv_probe_fail; - spin_unlock(&platform_bus_type.klist_drivers.k_lock); + spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); if (code != retval) platform_driver_unregister(drv); @@ -516,8 +517,8 @@ EXPORT_SYMBOL_GPL(platform_driver_probe); * (b) sysfs attribute lets new-style coldplug recover from hotplug events * mishandled before system is fully running: "modprobe $(cat modalias)" */ -static ssize_t -modalias_show(struct device *dev, struct device_attribute *a, char *buf) +static ssize_t modalias_show(struct device *dev, struct device_attribute *a, + char *buf) { struct platform_device *pdev = to_platform_device(dev); int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); @@ -538,26 +539,24 @@ static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } - /** - * platform_match - bind platform device to platform driver. - * @dev: device. - * @drv: driver. + * platform_match - bind platform device to platform driver. + * @dev: device. + * @drv: driver. * - * Platform device IDs are assumed to be encoded like this: - * "<name><instance>", where <name> is a short description of the - * type of device, like "pci" or "floppy", and <instance> is the - * enumerated instance of the device, like '0' or '42'. - * Driver IDs are simply "<name>". - * So, extract the <name> from the platform_device structure, - * and compare it against the name of the driver. Return whether - * they match or not. + * Platform device IDs are assumed to be encoded like this: + * "<name><instance>", where <name> is a short description of the type of + * device, like "pci" or "floppy", and <instance> is the enumerated + * instance of the device, like '0' or '42'. Driver IDs are simply + * "<name>". So, extract the <name> from the platform_device structure, + * and compare it against the name of the driver. Return whether they match + * or not. */ - -static int platform_match(struct device * dev, struct device_driver * drv) +static int platform_match(struct device *dev, struct device_driver *drv) { - struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct platform_device *pdev; + pdev = container_of(dev, struct platform_device, dev); return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0); } @@ -574,9 +573,10 @@ static int platform_suspend(struct device *dev, pm_message_t mesg) static int platform_suspend_late(struct device *dev, pm_message_t mesg) { struct platform_driver *drv = to_platform_driver(dev->driver); - struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct platform_device *pdev; int ret = 0; + pdev = container_of(dev, struct platform_device, dev); if (dev->driver && drv->suspend_late) ret = drv->suspend_late(pdev, mesg); @@ -586,16 +586,17 @@ static int platform_suspend_late(struct device *dev, pm_message_t mesg) static int platform_resume_early(struct device *dev) { struct platform_driver *drv = to_platform_driver(dev->driver); - struct platform_device *pdev = container_of(dev, struct platform_device, dev); + struct platform_device *pdev; int ret = 0; + pdev = container_of(dev, struct platform_device, dev); if (dev->driver && drv->resume_early) ret = drv->resume_early(pdev); return ret; } -static int platform_resume(struct device * dev) +static int platform_resume(struct device *dev) { int ret = 0; diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 44504e6618fb..de28dfd3b96c 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,11 +1,6 @@ -obj-y := shutdown.o obj-$(CONFIG_PM) += sysfs.o obj-$(CONFIG_PM_SLEEP) += main.o obj-$(CONFIG_PM_TRACE) += trace.o -ifeq ($(CONFIG_DEBUG_DRIVER),y) -EXTRA_CFLAGS += -DDEBUG -endif -ifeq ($(CONFIG_PM_VERBOSE),y) -EXTRA_CFLAGS += -DDEBUG -endif +ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG +ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 691ffb64cc37..200ed5fafd50 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -24,20 +24,45 @@ #include <linux/mutex.h> #include <linux/pm.h> #include <linux/resume-trace.h> +#include <linux/rwsem.h> #include "../base.h" #include "power.h" +/* + * The entries in the dpm_active list are in a depth first order, simply + * because children are guaranteed to be discovered after parents, and + * are inserted at the back of the list on discovery. + * + * All the other lists are kept in the same order, for consistency. + * However the lists aren't always traversed in the same order. + * Semaphores must be acquired from the top (i.e., front) down + * and released in the opposite order. Devices must be suspended + * from the bottom (i.e., end) up and resumed in the opposite order. + * That way no parent will be suspended while it still has an active + * child. + * + * Since device_pm_add() may be called with a device semaphore held, + * we must never try to acquire a device semaphore while holding + * dpm_list_mutex. + */ + LIST_HEAD(dpm_active); +static LIST_HEAD(dpm_locked); static LIST_HEAD(dpm_off); static LIST_HEAD(dpm_off_irq); +static LIST_HEAD(dpm_destroy); -static DEFINE_MUTEX(dpm_mtx); static DEFINE_MUTEX(dpm_list_mtx); -int (*platform_enable_wakeup)(struct device *dev, int is_on); +static DECLARE_RWSEM(pm_sleep_rwsem); +int (*platform_enable_wakeup)(struct device *dev, int is_on); +/** + * device_pm_add - add a device to the list of active devices + * @dev: Device to be added to the list + */ void device_pm_add(struct device *dev) { pr_debug("PM: Adding info for %s:%s\n", @@ -48,8 +73,36 @@ void device_pm_add(struct device *dev) mutex_unlock(&dpm_list_mtx); } +/** + * device_pm_remove - remove a device from the list of active devices + * @dev: Device to be removed from the list + * + * This function also removes the device's PM-related sysfs attributes. + */ void device_pm_remove(struct device *dev) { + /* + * If this function is called during a suspend, it will be blocked, + * because we're holding the device's semaphore at that time, which may + * lead to a deadlock. In that case we want to print a warning. + * However, it may also be called by unregister_dropped_devices() with + * the device's semaphore released, in which case the warning should + * not be printed. + */ + if (down_trylock(&dev->sem)) { + if (down_read_trylock(&pm_sleep_rwsem)) { + /* No suspend in progress, wait on dev->sem */ + down(&dev->sem); + up_read(&pm_sleep_rwsem); + } else { + /* Suspend in progress, we may deadlock */ + dev_warn(dev, "Suspicious %s during suspend\n", + __FUNCTION__); + dump_stack(); + /* The user has been warned ... */ + down(&dev->sem); + } + } pr_debug("PM: Removing info for %s:%s\n", dev->bus ? dev->bus->name : "No Bus", kobject_name(&dev->kobj)); @@ -57,25 +110,124 @@ void device_pm_remove(struct device *dev) dpm_sysfs_remove(dev); list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); + up(&dev->sem); +} + +/** + * device_pm_schedule_removal - schedule the removal of a suspended device + * @dev: Device to destroy + * + * Moves the device to the dpm_destroy list for further processing by + * unregister_dropped_devices(). + */ +void device_pm_schedule_removal(struct device *dev) +{ + pr_debug("PM: Preparing for removal: %s:%s\n", + dev->bus ? dev->bus->name : "No Bus", + kobject_name(&dev->kobj)); + mutex_lock(&dpm_list_mtx); + list_move_tail(&dev->power.entry, &dpm_destroy); + mutex_unlock(&dpm_list_mtx); +} + +/** + * pm_sleep_lock - mutual exclusion for registration and suspend + * + * Returns 0 if no suspend is underway and device registration + * may proceed, otherwise -EBUSY. + */ +int pm_sleep_lock(void) +{ + if (down_read_trylock(&pm_sleep_rwsem)) + return 0; + + return -EBUSY; +} + +/** + * pm_sleep_unlock - mutual exclusion for registration and suspend + * + * This routine undoes the effect of device_pm_add_lock + * when a device's registration is complete. + */ +void pm_sleep_unlock(void) +{ + up_read(&pm_sleep_rwsem); } /*------------------------- Resume routines -------------------------*/ /** - * resume_device - Restore state for one device. + * resume_device_early - Power on one device (early resume). * @dev: Device. * + * Must be called with interrupts disabled. */ - -static int resume_device(struct device * dev) +static int resume_device_early(struct device *dev) { int error = 0; TRACE_DEVICE(dev); TRACE_RESUME(0); - down(&dev->sem); + if (dev->bus && dev->bus->resume_early) { + dev_dbg(dev, "EARLY resume\n"); + error = dev->bus->resume_early(dev); + } + + TRACE_RESUME(error); + return error; +} + +/** + * dpm_power_up - Power on all regular (non-sysdev) devices. + * + * Walk the dpm_off_irq list and power each device up. This + * is used for devices that required they be powered down with + * interrupts disabled. As devices are powered on, they are moved + * to the dpm_off list. + * + * Must be called with interrupts disabled and only one CPU running. + */ +static void dpm_power_up(void) +{ + + while (!list_empty(&dpm_off_irq)) { + struct list_head *entry = dpm_off_irq.next; + struct device *dev = to_device(entry); + + list_move_tail(entry, &dpm_off); + resume_device_early(dev); + } +} + +/** + * device_power_up - Turn on all devices that need special attention. + * + * Power on system devices, then devices that required we shut them down + * with interrupts disabled. + * + * Must be called with interrupts disabled. + */ +void device_power_up(void) +{ + sysdev_resume(); + dpm_power_up(); +} +EXPORT_SYMBOL_GPL(device_power_up); + +/** + * resume_device - Restore state for one device. + * @dev: Device. + * + */ +static int resume_device(struct device *dev) +{ + int error = 0; + + TRACE_DEVICE(dev); + TRACE_RESUME(0); if (dev->bus && dev->bus->resume) { dev_dbg(dev,"resuming\n"); @@ -92,126 +244,94 @@ static int resume_device(struct device * dev) error = dev->class->resume(dev); } - up(&dev->sem); - TRACE_RESUME(error); return error; } - -static int resume_device_early(struct device * dev) -{ - int error = 0; - - TRACE_DEVICE(dev); - TRACE_RESUME(0); - if (dev->bus && dev->bus->resume_early) { - dev_dbg(dev,"EARLY resume\n"); - error = dev->bus->resume_early(dev); - } - TRACE_RESUME(error); - return error; -} - -/* - * Resume the devices that have either not gone through - * the late suspend, or that did go through it but also - * went through the early resume +/** + * dpm_resume - Resume every device. + * + * Resume the devices that have either not gone through + * the late suspend, or that did go through it but also + * went through the early resume. + * + * Take devices from the dpm_off_list, resume them, + * and put them on the dpm_locked list. */ static void dpm_resume(void) { mutex_lock(&dpm_list_mtx); while(!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.next; - struct device * dev = to_device(entry); - - get_device(dev); - list_move_tail(entry, &dpm_active); + struct list_head *entry = dpm_off.next; + struct device *dev = to_device(entry); + list_move_tail(entry, &dpm_locked); mutex_unlock(&dpm_list_mtx); resume_device(dev); mutex_lock(&dpm_list_mtx); - put_device(dev); } mutex_unlock(&dpm_list_mtx); } - /** - * device_resume - Restore state of each device in system. + * unlock_all_devices - Release each device's semaphore * - * Walk the dpm_off list, remove each entry, resume the device, - * then add it to the dpm_active list. + * Go through the dpm_off list. Put each device on the dpm_active + * list and unlock it. */ - -void device_resume(void) +static void unlock_all_devices(void) { - might_sleep(); - mutex_lock(&dpm_mtx); - dpm_resume(); - mutex_unlock(&dpm_mtx); -} - -EXPORT_SYMBOL_GPL(device_resume); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_locked)) { + struct list_head *entry = dpm_locked.prev; + struct device *dev = to_device(entry); + list_move(entry, &dpm_active); + up(&dev->sem); + } + mutex_unlock(&dpm_list_mtx); +} /** - * dpm_power_up - Power on some devices. - * - * Walk the dpm_off_irq list and power each device up. This - * is used for devices that required they be powered down with - * interrupts disabled. As devices are powered on, they are moved - * to the dpm_active list. + * unregister_dropped_devices - Unregister devices scheduled for removal * - * Interrupts must be disabled when calling this. + * Unregister all devices on the dpm_destroy list. */ - -static void dpm_power_up(void) +static void unregister_dropped_devices(void) { - while(!list_empty(&dpm_off_irq)) { - struct list_head * entry = dpm_off_irq.next; - struct device * dev = to_device(entry); + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_destroy)) { + struct list_head *entry = dpm_destroy.next; + struct device *dev = to_device(entry); - list_move_tail(entry, &dpm_off); - resume_device_early(dev); + up(&dev->sem); + mutex_unlock(&dpm_list_mtx); + /* This also removes the device from the list */ + device_unregister(dev); + mutex_lock(&dpm_list_mtx); } + mutex_unlock(&dpm_list_mtx); } - /** - * device_power_up - Turn on all devices that need special attention. + * device_resume - Restore state of each device in system. * - * Power on system devices then devices that required we shut them down - * with interrupts disabled. - * Called with interrupts disabled. + * Resume all the devices, unlock them all, and allow new + * devices to be registered once again. */ - -void device_power_up(void) +void device_resume(void) { - sysdev_resume(); - dpm_power_up(); + might_sleep(); + dpm_resume(); + unlock_all_devices(); + unregister_dropped_devices(); + up_write(&pm_sleep_rwsem); } - -EXPORT_SYMBOL_GPL(device_power_up); +EXPORT_SYMBOL_GPL(device_resume); /*------------------------- Suspend routines -------------------------*/ -/* - * The entries in the dpm_active list are in a depth first order, simply - * because children are guaranteed to be discovered after parents, and - * are inserted at the back of the list on discovery. - * - * All list on the suspend path are done in reverse order, so we operate - * on the leaves of the device tree (or forests, depending on how you want - * to look at it ;) first. As nodes are removed from the back of the list, - * they are inserted into the front of their destintation lists. - * - * Things are the reverse on the resume path - iterations are done in - * forward order, and nodes are inserted at the back of their destination - * lists. This way, the ancestors will be accessed before their descendents. - */ - static inline char *suspend_verb(u32 event) { switch (event) { @@ -222,7 +342,6 @@ static inline char *suspend_verb(u32 event) } } - static void suspend_device_dbg(struct device *dev, pm_message_t state, char *info) { @@ -232,16 +351,73 @@ suspend_device_dbg(struct device *dev, pm_message_t state, char *info) } /** - * suspend_device - Save state of one device. + * suspend_device_late - Shut down one device (late suspend). * @dev: Device. * @state: Power state device is entering. + * + * This is called with interrupts off and only a single CPU running. */ +static int suspend_device_late(struct device *dev, pm_message_t state) +{ + int error = 0; -static int suspend_device(struct device * dev, pm_message_t state) + if (dev->bus && dev->bus->suspend_late) { + suspend_device_dbg(dev, state, "LATE "); + error = dev->bus->suspend_late(dev, state); + suspend_report_result(dev->bus->suspend_late, error); + } + return error; +} + +/** + * device_power_down - Shut down special devices. + * @state: Power state to enter. + * + * Power down devices that require interrupts to be disabled + * and move them from the dpm_off list to the dpm_off_irq list. + * Then power down system devices. + * + * Must be called with interrupts disabled and only one CPU running. + */ +int device_power_down(pm_message_t state) +{ + int error = 0; + + while (!list_empty(&dpm_off)) { + struct list_head *entry = dpm_off.prev; + struct device *dev = to_device(entry); + + list_del_init(&dev->power.entry); + error = suspend_device_late(dev, state); + if (error) { + printk(KERN_ERR "Could not power down device %s: " + "error %d\n", + kobject_name(&dev->kobj), error); + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_off); + break; + } + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_off_irq); + } + + if (!error) + error = sysdev_suspend(state); + if (error) + dpm_power_up(); + return error; +} +EXPORT_SYMBOL_GPL(device_power_down); + +/** + * suspend_device - Save state of one device. + * @dev: Device. + * @state: Power state device is entering. + */ +int suspend_device(struct device *dev, pm_message_t state) { int error = 0; - down(&dev->sem); if (dev->power.power_state.event) { dev_dbg(dev, "PM: suspend %d-->%d\n", dev->power.power_state.event, state.event); @@ -264,123 +440,105 @@ static int suspend_device(struct device * dev, pm_message_t state) error = dev->bus->suspend(dev, state); suspend_report_result(dev->bus->suspend, error); } - up(&dev->sem); - return error; -} - - -/* - * This is called with interrupts off, only a single CPU - * running. We can't acquire a mutex or semaphore (and we don't - * need the protection) - */ -static int suspend_device_late(struct device *dev, pm_message_t state) -{ - int error = 0; - - if (dev->bus && dev->bus->suspend_late) { - suspend_device_dbg(dev, state, "LATE "); - error = dev->bus->suspend_late(dev, state); - suspend_report_result(dev->bus->suspend_late, error); - } return error; } /** - * device_suspend - Save state and stop all devices in system. - * @state: Power state to put each device in. + * dpm_suspend - Suspend every device. + * @state: Power state to put each device in. * - * Walk the dpm_active list, call ->suspend() for each device, and move - * it to the dpm_off list. + * Walk the dpm_locked list. Suspend each device and move it + * to the dpm_off list. * * (For historical reasons, if it returns -EAGAIN, that used to mean * that the device would be called again with interrupts disabled. * These days, we use the "suspend_late()" callback for that, so we * print a warning and consider it an error). - * - * If we get a different error, try and back out. - * - * If we hit a failure with any of the devices, call device_resume() - * above to bring the suspended devices back to life. - * */ - -int device_suspend(pm_message_t state) +static int dpm_suspend(pm_message_t state) { int error = 0; - might_sleep(); - mutex_lock(&dpm_mtx); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_active) && error == 0) { - struct list_head * entry = dpm_active.prev; - struct device * dev = to_device(entry); + while (!list_empty(&dpm_locked)) { + struct list_head *entry = dpm_locked.prev; + struct device *dev = to_device(entry); - get_device(dev); + list_del_init(&dev->power.entry); mutex_unlock(&dpm_list_mtx); - error = suspend_device(dev, state); - - mutex_lock(&dpm_list_mtx); - - /* Check if the device got removed */ - if (!list_empty(&dev->power.entry)) { - /* Move it to the dpm_off list */ - if (!error) - list_move(&dev->power.entry, &dpm_off); - } - if (error) + if (error) { printk(KERN_ERR "Could not suspend device %s: " - "error %d%s\n", - kobject_name(&dev->kobj), error, - error == -EAGAIN ? " (please convert to suspend_late)" : ""); - put_device(dev); + "error %d%s\n", + kobject_name(&dev->kobj), + error, + (error == -EAGAIN ? + " (please convert to suspend_late)" : + "")); + mutex_lock(&dpm_list_mtx); + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_locked); + mutex_unlock(&dpm_list_mtx); + break; + } + mutex_lock(&dpm_list_mtx); + if (list_empty(&dev->power.entry)) + list_add(&dev->power.entry, &dpm_off); } mutex_unlock(&dpm_list_mtx); - if (error) - dpm_resume(); - mutex_unlock(&dpm_mtx); return error; } -EXPORT_SYMBOL_GPL(device_suspend); - /** - * device_power_down - Shut down special devices. - * @state: Power state to enter. + * lock_all_devices - Acquire every device's semaphore * - * Walk the dpm_off_irq list, calling ->power_down() for each device that - * couldn't power down the device with interrupts enabled. When we're - * done, power down system devices. + * Go through the dpm_active list. Carefully lock each device's + * semaphore and put it in on the dpm_locked list. */ - -int device_power_down(pm_message_t state) +static void lock_all_devices(void) { - int error = 0; - struct device * dev; + mutex_lock(&dpm_list_mtx); + while (!list_empty(&dpm_active)) { + struct list_head *entry = dpm_active.next; + struct device *dev = to_device(entry); - while (!list_empty(&dpm_off)) { - struct list_head * entry = dpm_off.prev; + /* Required locking order is dev->sem first, + * then dpm_list_mutex. Hence this awkward code. + */ + get_device(dev); + mutex_unlock(&dpm_list_mtx); + down(&dev->sem); + mutex_lock(&dpm_list_mtx); - dev = to_device(entry); - error = suspend_device_late(dev, state); - if (error) - goto Error; - list_move(&dev->power.entry, &dpm_off_irq); + if (list_empty(entry)) + up(&dev->sem); /* Device was removed */ + else + list_move_tail(entry, &dpm_locked); + put_device(dev); } + mutex_unlock(&dpm_list_mtx); +} + +/** + * device_suspend - Save state and stop all devices in system. + * + * Prevent new devices from being registered, then lock all devices + * and suspend them. + */ +int device_suspend(pm_message_t state) +{ + int error; - error = sysdev_suspend(state); - Done: + might_sleep(); + down_write(&pm_sleep_rwsem); + lock_all_devices(); + error = dpm_suspend(state); + if (error) + device_resume(); return error; - Error: - printk(KERN_ERR "Could not power down device %s: " - "error %d\n", kobject_name(&dev->kobj), error); - dpm_power_up(); - goto Done; } - -EXPORT_SYMBOL_GPL(device_power_down); +EXPORT_SYMBOL_GPL(device_suspend); void __suspend_report_result(const char *function, void *fn, int ret) { diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 379da4e958e0..6f0dfca8ebdd 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -1,10 +1,3 @@ -/* - * shutdown.c - */ - -extern void device_shutdown(void); - - #ifdef CONFIG_PM_SLEEP /* @@ -20,6 +13,9 @@ static inline struct device *to_device(struct list_head *entry) extern void device_pm_add(struct device *); extern void device_pm_remove(struct device *); +extern void device_pm_schedule_removal(struct device *); +extern int pm_sleep_lock(void); +extern void pm_sleep_unlock(void); #else /* CONFIG_PM_SLEEP */ @@ -32,6 +28,15 @@ static inline void device_pm_remove(struct device *dev) { } +static inline int pm_sleep_lock(void) +{ + return 0; +} + +static inline void pm_sleep_unlock(void) +{ +} + #endif #ifdef CONFIG_PM diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c deleted file mode 100644 index 56e8eaaac012..000000000000 --- a/drivers/base/power/shutdown.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * shutdown.c - power management functions for the device tree. - * - * Copyright (c) 2002-3 Patrick Mochel - * 2002-3 Open Source Development Lab - * - * This file is released under the GPLv2 - * - */ - -#include <linux/device.h> -#include <asm/semaphore.h> - -#include "../base.h" -#include "power.h" - -#define to_dev(node) container_of(node, struct device, kobj.entry) - - -/** - * We handle system devices differently - we suspend and shut them - * down last and resume them first. That way, we don't do anything stupid like - * shutting down the interrupt controller before any devices.. - * - * Note that there are not different stages for power management calls - - * they only get one called once when interrupts are disabled. - */ - - -/** - * device_shutdown - call ->shutdown() on each device to shutdown. - */ -void device_shutdown(void) -{ - struct device * dev, *devn; - - list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list, - kobj.entry) { - if (dev->bus && dev->bus->shutdown) { - dev_dbg(dev, "shutdown\n"); - dev->bus->shutdown(dev); - } else if (dev->driver && dev->driver->shutdown) { - dev_dbg(dev, "shutdown\n"); - dev->driver->shutdown(dev); - } - } -} - diff --git a/drivers/base/sys.c b/drivers/base/sys.c index ac7ff6d0c6e5..2f79c55acdcc 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c @@ -25,8 +25,6 @@ #include "base.h" -extern struct kset devices_subsys; - #define to_sysdev(k) container_of(k, struct sys_device, kobj) #define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr) @@ -128,18 +126,17 @@ void sysdev_class_remove_file(struct sysdev_class *c, } EXPORT_SYMBOL_GPL(sysdev_class_remove_file); -/* - * declare system_subsys - */ -static decl_subsys(system, &ktype_sysdev_class, NULL); +static struct kset *system_kset; int sysdev_class_register(struct sysdev_class * cls) { pr_debug("Registering sysdev class '%s'\n", kobject_name(&cls->kset.kobj)); INIT_LIST_HEAD(&cls->drivers); - cls->kset.kobj.parent = &system_subsys.kobj; - cls->kset.kobj.kset = &system_subsys; + cls->kset.kobj.parent = &system_kset->kobj; + cls->kset.kobj.ktype = &ktype_sysdev_class; + cls->kset.kobj.kset = system_kset; + kobject_set_name(&cls->kset.kobj, cls->name); return kset_register(&cls->kset); } @@ -228,20 +225,15 @@ int sysdev_register(struct sys_device * sysdev) if (!cls) return -EINVAL; + pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); + /* Make sure the kset is set */ sysdev->kobj.kset = &cls->kset; - /* But make sure we point to the right type for sysfs translation */ - sysdev->kobj.ktype = &ktype_sysdev; - error = kobject_set_name(&sysdev->kobj, "%s%d", - kobject_name(&cls->kset.kobj), sysdev->id); - if (error) - return error; - - pr_debug("Registering sys device '%s'\n", kobject_name(&sysdev->kobj)); - /* Register the object */ - error = kobject_register(&sysdev->kobj); + error = kobject_init_and_add(&sysdev->kobj, &ktype_sysdev, NULL, + "%s%d", kobject_name(&cls->kset.kobj), + sysdev->id); if (!error) { struct sysdev_driver * drv; @@ -258,6 +250,7 @@ int sysdev_register(struct sys_device * sysdev) } mutex_unlock(&sysdev_drivers_lock); } + kobject_uevent(&sysdev->kobj, KOBJ_ADD); return error; } @@ -272,7 +265,7 @@ void sysdev_unregister(struct sys_device * sysdev) } mutex_unlock(&sysdev_drivers_lock); - kobject_unregister(&sysdev->kobj); + kobject_put(&sysdev->kobj); } @@ -298,8 +291,7 @@ void sysdev_shutdown(void) pr_debug("Shutting Down System Devices\n"); mutex_lock(&sysdev_drivers_lock); - list_for_each_entry_reverse(cls, &system_subsys.list, - kset.kobj.entry) { + list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Shutting down type '%s':\n", @@ -361,9 +353,7 @@ int sysdev_suspend(pm_message_t state) pr_debug("Suspending System Devices\n"); - list_for_each_entry_reverse(cls, &system_subsys.list, - kset.kobj.entry) { - + list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { pr_debug("Suspending type '%s':\n", kobject_name(&cls->kset.kobj)); @@ -414,8 +404,7 @@ aux_driver: } /* resume other classes */ - list_for_each_entry_continue(cls, &system_subsys.list, - kset.kobj.entry) { + list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) { list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { pr_debug(" %s\n", kobject_name(&err_dev->kobj)); __sysdev_resume(err_dev); @@ -440,7 +429,7 @@ int sysdev_resume(void) pr_debug("Resuming System Devices\n"); - list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) { + list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) { struct sys_device * sysdev; pr_debug("Resuming type '%s':\n", @@ -458,8 +447,10 @@ int sysdev_resume(void) int __init system_bus_init(void) { - system_subsys.kobj.parent = &devices_subsys.kobj; - return subsystem_register(&system_subsys); + system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); + if (!system_kset) + return -ENOMEM; + return 0; } EXPORT_SYMBOL_GPL(sysdev_register); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 9030c373ce67..cd03473f3547 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -3455,19 +3455,12 @@ static inline bool DAC960_ProcessCompletedRequest(DAC960_Command_T *Command, bool SuccessfulIO) { struct request *Request = Command->Request; - int UpToDate; - - UpToDate = 0; - if (SuccessfulIO) - UpToDate = 1; + int Error = SuccessfulIO ? 0 : -EIO; pci_unmap_sg(Command->Controller->PCIDevice, Command->cmd_sglist, Command->SegmentCount, Command->DmaDirection); - if (!end_that_request_first(Request, UpToDate, Command->BlockCount)) { - add_disk_randomness(Request->rq_disk); - end_that_request_last(Request, UpToDate); - + if (!__blk_end_request(Request, Error, Command->BlockCount << 9)) { if (Command->Completion) { complete(Command->Completion); Command->Completion = NULL; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 4d0119ea9e35..f2122855d4ec 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -105,6 +105,17 @@ config PARIDE "MicroSolutions backpack protocol", "DataStor Commuter protocol" etc.). +config GDROM + tristate "SEGA Dreamcast GD-ROM drive" + depends on SH_DREAMCAST + help + A standard SEGA Dreamcast comes with a modified CD ROM drive called a + "GD-ROM" by SEGA to signify it is capable of reading special disks + with up to 1 GB of data. This drive will also read standard CD ROM + disks. Select this option to access any disks in your GD ROM drive. + Most users will want to say "Y" here. + You can also build this as a module which will be called gdrom.ko + source "drivers/block/paride/Kconfig" config BLK_CPQ_DA diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index ad00b3d94711..826d12381e21 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -15,8 +15,10 @@ static struct kmem_cache *buf_pool_cache; -static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_state(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, @@ -26,50 +28,47 @@ static ssize_t aoedisk_show_state(struct gendisk * disk, char *page) (d->nopen && !(d->flags & DEVFL_UP)) ? ",closewait" : ""); /* I'd rather see nopen exported so we can ditch closewait */ } -static ssize_t aoedisk_show_mac(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_mac(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, "%012llx\n", (unsigned long long)mac_addr(d->addr)); } -static ssize_t aoedisk_show_netif(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_netif(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, "%s\n", d->ifp->name); } /* firmware version */ -static ssize_t aoedisk_show_fwver(struct gendisk * disk, char *page) +static ssize_t aoedisk_show_fwver(struct device *dev, + struct device_attribute *attr, char *page) { + struct gendisk *disk = dev_to_disk(dev); struct aoedev *d = disk->private_data; return snprintf(page, PAGE_SIZE, "0x%04x\n", (unsigned int) d->fw_ver); } -static struct disk_attribute disk_attr_state = { - .attr = {.name = "state", .mode = S_IRUGO }, - .show = aoedisk_show_state -}; -static struct disk_attribute disk_attr_mac = { - .attr = {.name = "mac", .mode = S_IRUGO }, - .show = aoedisk_show_mac -}; -static struct disk_attribute disk_attr_netif = { - .attr = {.name = "netif", .mode = S_IRUGO }, - .show = aoedisk_show_netif -}; -static struct disk_attribute disk_attr_fwver = { - .attr = {.name = "firmware-version", .mode = S_IRUGO }, - .show = aoedisk_show_fwver +static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL); +static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL); +static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL); +static struct device_attribute dev_attr_firmware_version = { + .attr = { .name = "firmware-version", .mode = S_IRUGO, .owner = THIS_MODULE }, + .show = aoedisk_show_fwver, }; static struct attribute *aoe_attrs[] = { - &disk_attr_state.attr, - &disk_attr_mac.attr, - &disk_attr_netif.attr, - &disk_attr_fwver.attr, - NULL + &dev_attr_state.attr, + &dev_attr_mac.attr, + &dev_attr_netif.attr, + &dev_attr_firmware_version.attr, + NULL, }; static const struct attribute_group attr_group = { @@ -79,12 +78,12 @@ static const struct attribute_group attr_group = { static int aoedisk_add_sysfs(struct aoedev *d) { - return sysfs_create_group(&d->gd->kobj, &attr_group); + return sysfs_create_group(&d->gd->dev.kobj, &attr_group); } void aoedisk_rm_sysfs(struct aoedev *d) { - sysfs_remove_group(&d->gd->kobj, &attr_group); + sysfs_remove_group(&d->gd->dev.kobj, &attr_group); } static int diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index 39e563ea0878..d5480e34cb22 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -259,9 +259,8 @@ aoechr_init(void) return PTR_ERR(aoe_class); } for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_device_create(aoe_class, NULL, - MKDEV(AOE_MAJOR, chardevs[i].minor), - NULL, chardevs[i].name); + device_create(aoe_class, NULL, + MKDEV(AOE_MAJOR, chardevs[i].minor), chardevs[i].name); return 0; } @@ -272,7 +271,7 @@ aoechr_exit(void) int i; for (i = 0; i < ARRAY_SIZE(chardevs); ++i) - class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); + device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); class_destroy(aoe_class); unregister_chrdev(AOE_MAJOR, "aoechr"); } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 509b6490413b..855ce8e5efba 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1187,17 +1187,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, } } -static inline void complete_buffers(struct bio *bio, int status) -{ - while (bio) { - struct bio *xbh = bio->bi_next; - - bio->bi_next = NULL; - bio_endio(bio, status ? 0 : -EIO); - bio = xbh; - } -} - static void cciss_check_queues(ctlr_info_t *h) { int start_queue = h->next_to_run; @@ -1263,21 +1252,14 @@ static void cciss_softirq_done(struct request *rq) pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir); } - complete_buffers(rq->bio, (rq->errors == 0)); - - if (blk_fs_request(rq)) { - const int rw = rq_data_dir(rq); - - disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors); - } - #ifdef CCISS_DEBUG printk("Done with %p\n", rq); #endif /* CCISS_DEBUG */ - add_disk_randomness(rq->rq_disk); + if (blk_end_request(rq, (rq->errors == 0) ? 0 : -EIO, blk_rq_bytes(rq))) + BUG(); + spin_lock_irqsave(&h->lock, flags); - end_that_request_last(rq, (rq->errors == 0)); cmd_free(h, cmd, 1); cciss_check_queues(h); spin_unlock_irqrestore(&h->lock, flags); @@ -2542,9 +2524,7 @@ after_error_processing: resend_cciss_cmd(h, cmd); return; } - cmd->rq->data_len = 0; cmd->rq->completion_data = cmd; - blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE); blk_complete_request(cmd->rq); } diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index c8132d958795..69199185ff4b 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -167,7 +167,6 @@ static void start_io(ctlr_info_t *h); static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c); static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c); -static inline void complete_buffers(struct bio *bio, int ok); static inline void complete_command(cmdlist_t *cmd, int timeout); static irqreturn_t do_ida_intr(int irq, void *dev_id); @@ -980,26 +979,13 @@ static void start_io(ctlr_info_t *h) } } -static inline void complete_buffers(struct bio *bio, int ok) -{ - struct bio *xbh; - - while (bio) { - xbh = bio->bi_next; - bio->bi_next = NULL; - - bio_endio(bio, ok ? 0 : -EIO); - - bio = xbh; - } -} /* * Mark all buffers that cmd was responsible for */ static inline void complete_command(cmdlist_t *cmd, int timeout) { struct request *rq = cmd->rq; - int ok=1; + int error = 0; int i, ddir; if (cmd->req.hdr.rcode & RCODE_NONFATAL && @@ -1011,16 +997,17 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) if (cmd->req.hdr.rcode & RCODE_FATAL) { printk(KERN_WARNING "Fatal error on ida/c%dd%d\n", cmd->ctlr, cmd->hdr.unit); - ok = 0; + error = -EIO; } if (cmd->req.hdr.rcode & RCODE_INVREQ) { printk(KERN_WARNING "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n", cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd, cmd->req.hdr.blk, cmd->req.hdr.blk_cnt, cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode); - ok = 0; + error = -EIO; } - if (timeout) ok = 0; + if (timeout) + error = -EIO; /* unmap the DMA mapping for all the scatter gather elements */ if (cmd->req.hdr.cmd == IDA_READ) ddir = PCI_DMA_FROMDEVICE; @@ -1030,18 +1017,9 @@ static inline void complete_command(cmdlist_t *cmd, int timeout) pci_unmap_page(hba[cmd->ctlr]->pci_dev, cmd->req.sg[i].addr, cmd->req.sg[i].size, ddir); - complete_buffers(rq->bio, ok); - - if (blk_fs_request(rq)) { - const int rw = rq_data_dir(rq); - - disk_stat_add(rq->rq_disk, sectors[rw], rq->nr_sectors); - } - - add_disk_randomness(rq->rq_disk); - DBGPX(printk("Done with %p\n", rq);); - end_that_request_last(rq, ok ? 1 : -EIO); + if (__blk_end_request(rq, error, blk_rq_bytes(rq))) + BUG(); } /* diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 639ed14bb08d..32c79a55511b 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2287,21 +2287,19 @@ static int do_format(int drive, struct format_descr *tmp_format_req) * ============================= */ -static void floppy_end_request(struct request *req, int uptodate) +static void floppy_end_request(struct request *req, int error) { unsigned int nr_sectors = current_count_sectors; + unsigned int drive = (unsigned long)req->rq_disk->private_data; /* current_count_sectors can be zero if transfer failed */ - if (!uptodate) + if (error) nr_sectors = req->current_nr_sectors; - if (end_that_request_first(req, uptodate, nr_sectors)) + if (__blk_end_request(req, error, nr_sectors << 9)) return; - add_disk_randomness(req->rq_disk); - floppy_off((long)req->rq_disk->private_data); - blkdev_dequeue_request(req); - end_that_request_last(req, uptodate); /* We're done with the request */ + floppy_off(drive); current_req = NULL; } @@ -2332,7 +2330,7 @@ static void request_done(int uptodate) /* unlock chained buffers */ spin_lock_irqsave(q->queue_lock, flags); - floppy_end_request(req, 1); + floppy_end_request(req, 0); spin_unlock_irqrestore(q->queue_lock, flags); } else { if (rq_data_dir(req) == WRITE) { @@ -2346,7 +2344,7 @@ static void request_done(int uptodate) DRWE->last_error_generation = DRS->generation; } spin_lock_irqsave(q->queue_lock, flags); - floppy_end_request(req, 0); + floppy_end_request(req, -EIO); spin_unlock_irqrestore(q->queue_lock, flags); } } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index b4c0888aedc3..ae3106045ee5 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -100,17 +100,15 @@ static const char *nbdcmd_to_ascii(int cmd) static void nbd_end_request(struct request *req) { - int uptodate = (req->errors == 0) ? 1 : 0; + int error = req->errors ? -EIO : 0; struct request_queue *q = req->q; unsigned long flags; dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name, - req, uptodate? "done": "failed"); + req, error ? "failed" : "done"); spin_lock_irqsave(q->queue_lock, flags); - if (!end_that_request_first(req, uptodate, req->nr_sectors)) { - end_that_request_last(req, uptodate); - } + __blk_end_request(req, error, req->nr_sectors << 9); spin_unlock_irqrestore(q->queue_lock, flags); } @@ -375,14 +373,17 @@ harderror: return NULL; } -static ssize_t pid_show(struct gendisk *disk, char *page) +static ssize_t pid_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(page, "%ld\n", + struct gendisk *disk = dev_to_disk(dev); + + return sprintf(buf, "%ld\n", (long) ((struct nbd_device *)disk->private_data)->pid); } -static struct disk_attribute pid_attr = { - .attr = { .name = "pid", .mode = S_IRUGO }, +static struct device_attribute pid_attr = { + .attr = { .name = "pid", .mode = S_IRUGO, .owner = THIS_MODULE }, .show = pid_show, }; @@ -394,7 +395,7 @@ static int nbd_do_it(struct nbd_device *lo) BUG_ON(lo->magic != LO_MAGIC); lo->pid = current->pid; - ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr); + ret = sysfs_create_file(&lo->disk->dev.kobj, &pid_attr.attr); if (ret) { printk(KERN_ERR "nbd: sysfs_create_file failed!"); return ret; @@ -403,7 +404,7 @@ static int nbd_do_it(struct nbd_device *lo) while ((req = nbd_read_stat(lo)) != NULL) nbd_end_request(req); - sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr); + sysfs_remove_file(&lo->disk->dev.kobj, &pid_attr.attr); return 0; } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index d89e7d32a3b6..ab86e23ddc69 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -676,8 +676,8 @@ static int __init pg_init(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) - class_device_create(pg_class, NULL, MKDEV(major, unit), - NULL, "pg%u", unit); + device_create(pg_class, NULL, MKDEV(major, unit), + "pg%u", unit); } err = 0; goto out; @@ -695,7 +695,7 @@ static void __exit pg_exit(void) for (unit = 0; unit < PG_UNITS; unit++) { struct pg *dev = &devices[unit]; if (dev->present) - class_device_destroy(pg_class, MKDEV(major, unit)); + device_destroy(pg_class, MKDEV(major, unit)); } class_destroy(pg_class); unregister_chrdev(major, name); diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index b91accf12656..76096cad798f 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -972,10 +972,10 @@ static int __init pt_init(void) for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_device_create(pt_class, NULL, MKDEV(major, unit), - NULL, "pt%d", unit); - class_device_create(pt_class, NULL, MKDEV(major, unit + 128), - NULL, "pt%dn", unit); + device_create(pt_class, NULL, MKDEV(major, unit), + "pt%d", unit); + device_create(pt_class, NULL, MKDEV(major, unit + 128), + "pt%dn", unit); } goto out; @@ -990,8 +990,8 @@ static void __exit pt_exit(void) int unit; for (unit = 0; unit < PT_UNITS; unit++) if (pt[unit].present) { - class_device_destroy(pt_class, MKDEV(major, unit)); - class_device_destroy(pt_class, MKDEV(major, unit + 128)); + device_destroy(pt_class, MKDEV(major, unit)); + device_destroy(pt_class, MKDEV(major, unit + 128)); } class_destroy(pt_class); unregister_chrdev(major, name); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 3535ef896677..e9de1712e5a0 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -110,17 +110,18 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, struct kobj_type* ktype) { struct pktcdvd_kobj *p; + int error; + p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return NULL; - kobject_set_name(&p->kobj, "%s", name); - p->kobj.parent = parent; - p->kobj.ktype = ktype; p->pd = pd; - if (kobject_register(&p->kobj) != 0) { + error = kobject_init_and_add(&p->kobj, ktype, parent, "%s", name); + if (error) { kobject_put(&p->kobj); return NULL; } + kobject_uevent(&p->kobj, KOBJ_ADD); return p; } /* @@ -129,7 +130,7 @@ static struct pktcdvd_kobj* pkt_kobj_create(struct pktcdvd_device *pd, static void pkt_kobj_remove(struct pktcdvd_kobj *p) { if (p) - kobject_unregister(&p->kobj); + kobject_put(&p->kobj); } /* * default release function for pktcdvd kernel objects. @@ -301,18 +302,16 @@ static struct kobj_type kobj_pkt_type_wqueue = { static void pkt_sysfs_dev_new(struct pktcdvd_device *pd) { if (class_pktcdvd) { - pd->clsdev = class_device_create(class_pktcdvd, - NULL, pd->pkt_dev, - NULL, "%s", pd->name); - if (IS_ERR(pd->clsdev)) - pd->clsdev = NULL; + pd->dev = device_create(class_pktcdvd, NULL, pd->pkt_dev, "%s", pd->name); + if (IS_ERR(pd->dev)) + pd->dev = NULL; } - if (pd->clsdev) { + if (pd->dev) { pd->kobj_stat = pkt_kobj_create(pd, "stat", - &pd->clsdev->kobj, + &pd->dev->kobj, &kobj_pkt_type_stat); pd->kobj_wqueue = pkt_kobj_create(pd, "write_queue", - &pd->clsdev->kobj, + &pd->dev->kobj, &kobj_pkt_type_wqueue); } } @@ -322,7 +321,7 @@ static void pkt_sysfs_dev_remove(struct pktcdvd_device *pd) pkt_kobj_remove(pd->kobj_stat); pkt_kobj_remove(pd->kobj_wqueue); if (class_pktcdvd) - class_device_destroy(class_pktcdvd, pd->pkt_dev); + device_destroy(class_pktcdvd, pd->pkt_dev); } diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index e354bfc070e1..7483f947f0e9 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -229,7 +229,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) struct ps3_storage_device *dev = data; struct ps3disk_private *priv; struct request *req; - int res, read, uptodate; + int res, read, error; u64 tag, status; unsigned long num_sectors; const char *op; @@ -270,21 +270,17 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) if (status) { dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__, __LINE__, op, status); - uptodate = 0; + error = -EIO; } else { dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__, op); - uptodate = 1; + error = 0; if (read) ps3disk_scatter_gather(dev, req, 0); } spin_lock(&priv->lock); - if (!end_that_request_first(req, uptodate, num_sectors)) { - add_disk_randomness(req->rq_disk); - blkdev_dequeue_request(req); - end_that_request_last(req, uptodate); - } + __blk_end_request(req, error, num_sectors << 9); priv->req = NULL; ps3disk_do_request(dev, priv->queue); spin_unlock(&priv->lock); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index fac4c6cd04f7..66e30155b0ab 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -212,12 +212,9 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc) vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD); } -static void vdc_end_request(struct request *req, int uptodate, int num_sectors) +static void vdc_end_request(struct request *req, int error, int num_sectors) { - if (end_that_request_first(req, uptodate, num_sectors)) - return; - add_disk_randomness(req->rq_disk); - end_that_request_last(req, uptodate); + __blk_end_request(req, error, num_sectors << 9); } static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, @@ -242,7 +239,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, rqe->req = NULL; - vdc_end_request(req, !desc->status, desc->size >> 9); + vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9); if (blk_queue_stopped(port->disk->queue)) blk_start_queue(port->disk->queue); @@ -456,7 +453,7 @@ static void do_vdc_request(struct request_queue *q) blkdev_dequeue_request(req); if (__send_request(req) < 0) - vdc_end_request(req, 0, req->hard_nr_sectors); + vdc_end_request(req, -EIO, req->hard_nr_sectors); } } diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 52dc5e131718..cd5674b63faf 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -744,16 +744,14 @@ static unsigned int carm_fill_get_fw_ver(struct carm_host *host, static inline void carm_end_request_queued(struct carm_host *host, struct carm_request *crq, - int uptodate) + int error) { struct request *req = crq->rq; int rc; - rc = end_that_request_first(req, uptodate, req->hard_nr_sectors); + rc = __blk_end_request(req, error, blk_rq_bytes(req)); assert(rc == 0); - end_that_request_last(req, uptodate); - rc = carm_put_request(host, crq); assert(rc == 0); } @@ -793,9 +791,9 @@ static inline void carm_round_robin(struct carm_host *host) } static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, - int is_ok) + int error) { - carm_end_request_queued(host, crq, is_ok); + carm_end_request_queued(host, crq, error); if (max_queue == 1) carm_round_robin(host); else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && @@ -873,14 +871,14 @@ queue_one_request: sg = &crq->sg[0]; n_elem = blk_rq_map_sg(q, rq, sg); if (n_elem <= 0) { - carm_end_rq(host, crq, 0); + carm_end_rq(host, crq, -EIO); return; /* request with no s/g entries? */ } /* map scatterlist to PCI bus addresses */ n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir); if (n_elem <= 0) { - carm_end_rq(host, crq, 0); + carm_end_rq(host, crq, -EIO); return; /* request with no s/g entries? */ } crq->n_elem = n_elem; @@ -941,7 +939,7 @@ queue_one_request: static void carm_handle_array_info(struct carm_host *host, struct carm_request *crq, u8 *mem, - int is_ok) + int error) { struct carm_port *port; u8 *msg_data = mem + sizeof(struct carm_array_info); @@ -952,9 +950,9 @@ static void carm_handle_array_info(struct carm_host *host, DPRINTK("ENTER\n"); - carm_end_rq(host, crq, is_ok); + carm_end_rq(host, crq, error); - if (!is_ok) + if (error) goto out; if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST) goto out; @@ -1001,7 +999,7 @@ out: static void carm_handle_scan_chan(struct carm_host *host, struct carm_request *crq, u8 *mem, - int is_ok) + int error) { u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET; unsigned int i, dev_count = 0; @@ -1009,9 +1007,9 @@ static void carm_handle_scan_chan(struct carm_host *host, DPRINTK("ENTER\n"); - carm_end_rq(host, crq, is_ok); + carm_end_rq(host, crq, error); - if (!is_ok) { + if (error) { new_state = HST_ERROR; goto out; } @@ -1033,23 +1031,23 @@ out: } static void carm_handle_generic(struct carm_host *host, - struct carm_request *crq, int is_ok, + struct carm_request *crq, int error, int cur_state, int next_state) { DPRINTK("ENTER\n"); - carm_end_rq(host, crq, is_ok); + carm_end_rq(host, crq, error); assert(host->state == cur_state); - if (is_ok) - host->state = next_state; - else + if (error) host->state = HST_ERROR; + else + host->state = next_state; schedule_work(&host->fsm_task); } static inline void carm_handle_rw(struct carm_host *host, - struct carm_request *crq, int is_ok) + struct carm_request *crq, int error) { int pci_dir; @@ -1062,7 +1060,7 @@ static inline void carm_handle_rw(struct carm_host *host, pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir); - carm_end_rq(host, crq, is_ok); + carm_end_rq(host, crq, error); } static inline void carm_handle_resp(struct carm_host *host, @@ -1071,7 +1069,7 @@ static inline void carm_handle_resp(struct carm_host *host, u32 handle = le32_to_cpu(ret_handle_le); unsigned int msg_idx; struct carm_request *crq; - int is_ok = (status == RMSG_OK); + int error = (status == RMSG_OK) ? 0 : -EIO; u8 *mem; VPRINTK("ENTER, handle == 0x%x\n", handle); @@ -1090,7 +1088,7 @@ static inline void carm_handle_resp(struct carm_host *host, /* fast path */ if (likely(crq->msg_type == CARM_MSG_READ || crq->msg_type == CARM_MSG_WRITE)) { - carm_handle_rw(host, crq, is_ok); + carm_handle_rw(host, crq, error); return; } @@ -1100,7 +1098,7 @@ static inline void carm_handle_resp(struct carm_host *host, case CARM_MSG_IOCTL: { switch (crq->msg_subtype) { case CARM_IOC_SCAN_CHAN: - carm_handle_scan_chan(host, crq, mem, is_ok); + carm_handle_scan_chan(host, crq, mem, error); break; default: /* unknown / invalid response */ @@ -1112,21 +1110,21 @@ static inline void carm_handle_resp(struct carm_host *host, case CARM_MSG_MISC: { switch (crq->msg_subtype) { case MISC_ALLOC_MEM: - carm_handle_generic(host, crq, is_ok, + carm_handle_generic(host, crq, error, HST_ALLOC_BUF, HST_SYNC_TIME); break; case MISC_SET_TIME: - carm_handle_generic(host, crq, is_ok, + carm_handle_generic(host, crq, error, HST_SYNC_TIME, HST_GET_FW_VER); break; case MISC_GET_FW_VER: { struct carm_fw_ver *ver = (struct carm_fw_ver *) mem + sizeof(struct carm_msg_get_fw_ver); - if (is_ok) { + if (!error) { host->fw_ver = le32_to_cpu(ver->version); host->flags |= (ver->features & FL_FW_VER_MASK); } - carm_handle_generic(host, crq, is_ok, + carm_handle_generic(host, crq, error, HST_GET_FW_VER, HST_PORT_SCAN); break; } @@ -1140,7 +1138,7 @@ static inline void carm_handle_resp(struct carm_host *host, case CARM_MSG_ARRAY: { switch (crq->msg_subtype) { case CARM_ARRAY_INFO: - carm_handle_array_info(host, crq, mem, is_ok); + carm_handle_array_info(host, crq, mem, error); break; default: /* unknown / invalid response */ @@ -1159,7 +1157,7 @@ static inline void carm_handle_resp(struct carm_host *host, err_out: printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n", pci_name(host->pdev), crq->msg_type, crq->msg_subtype); - carm_end_rq(host, crq, 0); + carm_end_rq(host, crq, -EIO); } static inline void carm_handle_responses(struct carm_host *host) diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 08e909dc7944..c6179d6ac6e4 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -808,16 +808,16 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) static void ub_end_rq(struct request *rq, unsigned int scsi_status) { - int uptodate; + int error; if (scsi_status == 0) { - uptodate = 1; + error = 0; } else { - uptodate = 0; + error = -EIO; rq->errors = scsi_status; } - end_that_request_first(rq, uptodate, rq->hard_nr_sectors); - end_that_request_last(rq, uptodate); + if (__blk_end_request(rq, error, blk_rq_bytes(rq))) + BUG(); } static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun, diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index ab5d404faa11..9e61fca46117 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -229,13 +229,10 @@ static struct block_device_operations viodasd_fops = { /* * End a request */ -static void viodasd_end_request(struct request *req, int uptodate, +static void viodasd_end_request(struct request *req, int error, int num_sectors) { - if (end_that_request_first(req, uptodate, num_sectors)) - return; - add_disk_randomness(req->rq_disk); - end_that_request_last(req, uptodate); + __blk_end_request(req, error, num_sectors << 9); } /* @@ -374,12 +371,12 @@ static void do_viodasd_request(struct request_queue *q) blkdev_dequeue_request(req); /* check that request contains a valid command */ if (!blk_fs_request(req)) { - viodasd_end_request(req, 0, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, req->hard_nr_sectors); continue; } /* Try sending the request */ if (send_request(req) != 0) - viodasd_end_request(req, 0, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, req->hard_nr_sectors); } } @@ -591,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) num_req_outstanding--; spin_unlock_irqrestore(&viodasd_spinlock, irq_flags); - error = event->xRc != HvLpEvent_Rc_Good; + error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO; if (error) { const struct vio_error_entry *err; err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); @@ -601,7 +598,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) } qlock = req->q->queue_lock; spin_lock_irqsave(qlock, irq_flags); - viodasd_end_request(req, !error, num_sect); + viodasd_end_request(req, error, num_sect); spin_unlock_irqrestore(qlock, irq_flags); /* Finally, try to get more requests off of this device's queue */ diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 2bdebcb3ff16..8afce67c0aa5 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -452,7 +452,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) RING_IDX i, rp; unsigned long flags; struct blkfront_info *info = (struct blkfront_info *)dev_id; - int uptodate; + int error; spin_lock_irqsave(&blkif_io_lock, flags); @@ -477,13 +477,13 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) add_id_to_freelist(info, id); - uptodate = (bret->status == BLKIF_RSP_OKAY); + error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO; switch (bret->operation) { case BLKIF_OP_WRITE_BARRIER: if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) { printk(KERN_WARNING "blkfront: %s: write barrier op failed\n", info->gd->disk_name); - uptodate = -EOPNOTSUPP; + error = -EOPNOTSUPP; info->feature_barrier = 0; xlvbd_barrier(info); } @@ -494,10 +494,8 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id) dev_dbg(&info->xbdev->dev, "Bad return from blkdev data " "request: %x\n", bret->status); - ret = end_that_request_first(req, uptodate, - req->hard_nr_sectors); + ret = __blk_end_request(req, error, blk_rq_bytes(req)); BUG_ON(ret); - end_that_request_last(req, uptodate); break; default: BUG(); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index 82effce97c51..78ebfffc77e3 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -483,7 +483,6 @@ static void ace_fsm_dostate(struct ace_device *ace) u32 status; u16 val; int count; - int i; #if defined(DEBUG) dev_dbg(ace->dev, "fsm_state=%i, id_req_count=%i\n", @@ -688,7 +687,6 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* Transfer the next buffer */ - i = 16; if (ace->fsm_task == ACE_TASK_WRITE) ace->reg_ops->dataout(ace); else @@ -702,8 +700,8 @@ static void ace_fsm_dostate(struct ace_device *ace) } /* bio finished; is there another one? */ - i = ace->req->current_nr_sectors; - if (end_that_request_first(ace->req, 1, i)) { + if (__blk_end_request(ace->req, 0, + blk_rq_cur_bytes(ace->req))) { /* dev_dbg(ace->dev, "next block; h=%li c=%i\n", * ace->req->hard_nr_sectors, * ace->req->current_nr_sectors); @@ -718,9 +716,6 @@ static void ace_fsm_dostate(struct ace_device *ace) break; case ACE_FSM_STATE_REQ_COMPLETE: - /* Complete the block request */ - blkdev_dequeue_request(ace->req); - end_that_request_last(ace->req, 1); ace->req = NULL; /* Finished request; go to idle state */ diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile index 774c180a4e11..ecf85fda0fc1 100644 --- a/drivers/cdrom/Makefile +++ b/drivers/cdrom/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_PARIDE_PCD) += cdrom.o obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o obj-$(CONFIG_VIOCD) += viocd.o cdrom.o +obj-$(CONFIG_GDROM) += gdrom.o cdrom.o diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c new file mode 100644 index 000000000000..4e2bbcccc064 --- /dev/null +++ b/drivers/cdrom/gdrom.c @@ -0,0 +1,867 @@ +/* GD ROM driver for the SEGA Dreamcast + * copyright Adrian McMenamin, 2007 + * With thanks to Marcus Comstedt and Nathan Keynes + * for work in reversing PIO and DMA + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/cdrom.h> +#include <linux/genhd.h> +#include <linux/bio.h> +#include <linux/blkdev.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/wait.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <scsi/scsi.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/delay.h> +#include <asm/mach/dma.h> +#include <asm/mach/sysasic.h> + +#define GDROM_DEV_NAME "gdrom" +#define GD_SESSION_OFFSET 150 + +/* GD Rom commands */ +#define GDROM_COM_SOFTRESET 0x08 +#define GDROM_COM_EXECDIAG 0x90 +#define GDROM_COM_PACKET 0xA0 +#define GDROM_COM_IDDEV 0xA1 + +/* GD Rom registers */ +#define GDROM_BASE_REG 0xA05F7000 +#define GDROM_ALTSTATUS_REG (GDROM_BASE_REG + 0x18) +#define GDROM_DATA_REG (GDROM_BASE_REG + 0x80) +#define GDROM_ERROR_REG (GDROM_BASE_REG + 0x84) +#define GDROM_INTSEC_REG (GDROM_BASE_REG + 0x88) +#define GDROM_SECNUM_REG (GDROM_BASE_REG + 0x8C) +#define GDROM_BCL_REG (GDROM_BASE_REG + 0x90) +#define GDROM_BCH_REG (GDROM_BASE_REG + 0x94) +#define GDROM_DSEL_REG (GDROM_BASE_REG + 0x98) +#define GDROM_STATUSCOMMAND_REG (GDROM_BASE_REG + 0x9C) +#define GDROM_RESET_REG (GDROM_BASE_REG + 0x4E4) + +#define GDROM_DMA_STARTADDR_REG (GDROM_BASE_REG + 0x404) +#define GDROM_DMA_LENGTH_REG (GDROM_BASE_REG + 0x408) +#define GDROM_DMA_DIRECTION_REG (GDROM_BASE_REG + 0x40C) +#define GDROM_DMA_ENABLE_REG (GDROM_BASE_REG + 0x414) +#define GDROM_DMA_STATUS_REG (GDROM_BASE_REG + 0x418) +#define GDROM_DMA_WAIT_REG (GDROM_BASE_REG + 0x4A0) +#define GDROM_DMA_ACCESS_CTRL_REG (GDROM_BASE_REG + 0x4B8) + +#define GDROM_HARD_SECTOR 2048 +#define BLOCK_LAYER_SECTOR 512 +#define GD_TO_BLK 4 + +#define GDROM_DEFAULT_TIMEOUT (HZ * 7) + +static const struct { + int sense_key; + const char * const text; +} sense_texts[] = { + {NO_SENSE, "OK"}, + {RECOVERED_ERROR, "Recovered from error"}, + {NOT_READY, "Device not ready"}, + {MEDIUM_ERROR, "Disk not ready"}, + {HARDWARE_ERROR, "Hardware error"}, + {ILLEGAL_REQUEST, "Command has failed"}, + {UNIT_ATTENTION, "Device needs attention - disk may have been changed"}, + {DATA_PROTECT, "Data protection error"}, + {ABORTED_COMMAND, "Command aborted"}, +}; + +static struct platform_device *pd; +static int gdrom_major; +static DECLARE_WAIT_QUEUE_HEAD(command_queue); +static DECLARE_WAIT_QUEUE_HEAD(request_queue); + +static DEFINE_SPINLOCK(gdrom_lock); +static void gdrom_readdisk_dma(struct work_struct *work); +static DECLARE_WORK(work, gdrom_readdisk_dma); +static LIST_HEAD(gdrom_deferred); + +struct gdromtoc { + unsigned int entry[99]; + unsigned int first, last; + unsigned int leadout; +}; + +static struct gdrom_unit { + struct gendisk *disk; + struct cdrom_device_info *cd_info; + int status; + int pending; + int transfer; + char disk_type; + struct gdromtoc *toc; + struct request_queue *gdrom_rq; +} gd; + +struct gdrom_id { + char mid; + char modid; + char verid; + char padA[13]; + char mname[16]; + char modname[16]; + char firmver[16]; + char padB[16]; +}; + +static int gdrom_getsense(short *bufstring); +static int gdrom_packetcommand(struct cdrom_device_info *cd_info, + struct packet_command *command); +static int gdrom_hardreset(struct cdrom_device_info *cd_info); + +static bool gdrom_is_busy(void) +{ + return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0; +} + +static bool gdrom_data_request(void) +{ + return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) == 8; +} + +static bool gdrom_wait_clrbusy(void) +{ + unsigned long timeout = jiffies + GDROM_DEFAULT_TIMEOUT; + while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && + (time_before(jiffies, timeout))) + cpu_relax(); + return time_before(jiffies, timeout + 1); +} + +static bool gdrom_wait_busy_sleeps(void) +{ + unsigned long timeout; + /* Wait to get busy first */ + timeout = jiffies + GDROM_DEFAULT_TIMEOUT; + while (!gdrom_is_busy() && time_before(jiffies, timeout)) + cpu_relax(); + /* Now wait for busy to clear */ + return gdrom_wait_clrbusy(); +} + +static void gdrom_identifydevice(void *buf) +{ + int c; + short *data = buf; + /* If the device won't clear it has probably + * been hit by a serious failure - but we'll + * try to return a sense key even so */ + if (!gdrom_wait_clrbusy()) { + gdrom_getsense(NULL); + return; + } + ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG); + if (!gdrom_wait_busy_sleeps()) { + gdrom_getsense(NULL); + return; + } + /* now read in the data */ + for (c = 0; c < 40; c++) + data[c] = ctrl_inw(GDROM_DATA_REG); +} + +static void gdrom_spicommand(void *spi_string, int buflen) +{ + short *cmd = spi_string; + unsigned long timeout; + + /* ensure IRQ_WAIT is set */ + ctrl_outb(0x08, GDROM_ALTSTATUS_REG); + /* specify how many bytes we expect back */ + ctrl_outb(buflen & 0xFF, GDROM_BCL_REG); + ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG); + /* other parameters */ + ctrl_outb(0, GDROM_INTSEC_REG); + ctrl_outb(0, GDROM_SECNUM_REG); + ctrl_outb(0, GDROM_ERROR_REG); + /* Wait until we can go */ + if (!gdrom_wait_clrbusy()) { + gdrom_getsense(NULL); + return; + } + timeout = jiffies + GDROM_DEFAULT_TIMEOUT; + ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG); + while (!gdrom_data_request() && time_before(jiffies, timeout)) + cpu_relax(); + if (!time_before(jiffies, timeout + 1)) { + gdrom_getsense(NULL); + return; + } + outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6); +} + + +/* gdrom_command_executediagnostic: + * Used to probe for presence of working GDROM + * Restarts GDROM device and then applies standard ATA 3 + * Execute Diagnostic Command: a return of '1' indicates device 0 + * present and device 1 absent + */ +static char gdrom_execute_diagnostic(void) +{ + gdrom_hardreset(gd.cd_info); + if (!gdrom_wait_clrbusy()) + return 0; + ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG); + if (!gdrom_wait_busy_sleeps()) + return 0; + return ctrl_inb(GDROM_ERROR_REG); +} + +/* + * Prepare disk command + * byte 0 = 0x70 + * byte 1 = 0x1f + */ +static int gdrom_preparedisk_cmd(void) +{ + struct packet_command *spin_command; + spin_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL); + if (!spin_command) + return -ENOMEM; + spin_command->cmd[0] = 0x70; + spin_command->cmd[2] = 0x1f; + spin_command->buflen = 0; + gd.pending = 1; + gdrom_packetcommand(gd.cd_info, spin_command); + /* 60 second timeout */ + wait_event_interruptible_timeout(command_queue, gd.pending == 0, + GDROM_DEFAULT_TIMEOUT); + gd.pending = 0; + kfree(spin_command); + if (gd.status & 0x01) { + /* log an error */ + gdrom_getsense(NULL); + return -EIO; + } + return 0; +} + +/* + * Read TOC command + * byte 0 = 0x14 + * byte 1 = session + * byte 3 = sizeof TOC >> 8 ie upper byte + * byte 4 = sizeof TOC & 0xff ie lower byte + */ +static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session) +{ + int tocsize; + struct packet_command *toc_command; + int err = 0; + + toc_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL); + if (!toc_command) + return -ENOMEM; + tocsize = sizeof(struct gdromtoc); + toc_command->cmd[0] = 0x14; + toc_command->cmd[1] = session; + toc_command->cmd[3] = tocsize >> 8; + toc_command->cmd[4] = tocsize & 0xff; + toc_command->buflen = tocsize; + if (gd.pending) { + err = -EBUSY; + goto cleanup_readtoc_final; + } + gd.pending = 1; + gdrom_packetcommand(gd.cd_info, toc_command); + wait_event_interruptible_timeout(command_queue, gd.pending == 0, + GDROM_DEFAULT_TIMEOUT); + if (gd.pending) { + err = -EINVAL; + goto cleanup_readtoc; + } + insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2); + if (gd.status & 0x01) + err = -EINVAL; + +cleanup_readtoc: + gd.pending = 0; +cleanup_readtoc_final: + kfree(toc_command); + return err; +} + +/* TOC helpers */ +static int get_entry_lba(int track) +{ + return (cpu_to_be32(track & 0xffffff00) - GD_SESSION_OFFSET); +} + +static int get_entry_q_ctrl(int track) +{ + return (track & 0x000000f0) >> 4; +} + +static int get_entry_track(int track) +{ + return (track & 0x0000ff00) >> 8; +} + +static int gdrom_get_last_session(struct cdrom_device_info *cd_info, + struct cdrom_multisession *ms_info) +{ + int fentry, lentry, track, data, tocuse, err; + if (!gd.toc) + return -ENOMEM; + tocuse = 1; + /* Check if GD-ROM */ + err = gdrom_readtoc_cmd(gd.toc, 1); + /* Not a GD-ROM so check if standard CD-ROM */ + if (err) { + tocuse = 0; + err = gdrom_readtoc_cmd(gd.toc, 0); + if (err) { + printk(KERN_INFO "GDROM: Could not get CD " + "table of contents\n"); + return -ENXIO; + } + } + + fentry = get_entry_track(gd.toc->first); + lentry = get_entry_track(gd.toc->last); + /* Find the first data track */ + track = get_entry_track(gd.toc->last); + do { + data = gd.toc->entry[track - 1]; + if (get_entry_q_ctrl(data)) + break; /* ie a real data track */ + track--; + } while (track >= fentry); + + if ((track > 100) || (track < get_entry_track(gd.toc->first))) { + printk(KERN_INFO "GDROM: No data on the last " + "session of the CD\n"); + gdrom_getsense(NULL); + return -ENXIO; + } + + ms_info->addr_format = CDROM_LBA; + ms_info->addr.lba = get_entry_lba(data); + ms_info->xa_flag = 1; + return 0; +} + +static int gdrom_open(struct cdrom_device_info *cd_info, int purpose) +{ + /* spin up the disk */ + return gdrom_preparedisk_cmd(); +} + +/* this function is required even if empty */ +static void gdrom_release(struct cdrom_device_info *cd_info) +{ +} + +static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore) +{ + /* read the sense key */ + char sense = ctrl_inb(GDROM_ERROR_REG); + sense &= 0xF0; + if (sense == 0) + return CDS_DISC_OK; + if (sense == 0x20) + return CDS_DRIVE_NOT_READY; + /* default */ + return CDS_NO_INFO; +} + +static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore) +{ + /* check the sense key */ + return (ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60; +} + +/* reset the G1 bus */ +static int gdrom_hardreset(struct cdrom_device_info *cd_info) +{ + int count; + ctrl_outl(0x1fffff, GDROM_RESET_REG); + for (count = 0xa0000000; count < 0xa0200000; count += 4) + ctrl_inl(count); + return 0; +} + +/* keep the function looking like the universal + * CD Rom specification - returning int */ +static int gdrom_packetcommand(struct cdrom_device_info *cd_info, + struct packet_command *command) +{ + gdrom_spicommand(&command->cmd, command->buflen); + return 0; +} + +/* Get Sense SPI command + * From Marcus Comstedt + * cmd = 0x13 + * cmd + 4 = length of returned buffer + * Returns 5 16 bit words + */ +static int gdrom_getsense(short *bufstring) +{ + struct packet_command *sense_command; + short sense[5]; + int sense_key; + int err = -EIO; + + sense_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL); + if (!sense_command) + return -ENOMEM; + sense_command->cmd[0] = 0x13; + sense_command->cmd[4] = 10; + sense_command->buflen = 10; + /* even if something is pending try to get + * the sense key if possible */ + if (gd.pending && !gdrom_wait_clrbusy()) { + err = -EBUSY; + goto cleanup_sense_final; + } + gd.pending = 1; + gdrom_packetcommand(gd.cd_info, sense_command); + wait_event_interruptible_timeout(command_queue, gd.pending == 0, + GDROM_DEFAULT_TIMEOUT); + if (gd.pending) + goto cleanup_sense; + insw(PHYSADDR(GDROM_DATA_REG), &sense, sense_command->buflen/2); + if (sense[1] & 40) { + printk(KERN_INFO "GDROM: Drive not ready - command aborted\n"); + goto cleanup_sense; + } + sense_key = sense[1] & 0x0F; + if (sense_key < ARRAY_SIZE(sense_texts)) + printk(KERN_INFO "GDROM: %s\n", sense_texts[sense_key].text); + else + printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key); + if (bufstring) /* return addional sense data */ + memcpy(bufstring, &sense[4], 2); + if (sense_key < 2) + err = 0; + +cleanup_sense: + gd.pending = 0; +cleanup_sense_final: + kfree(sense_command); + return err; +} + +static struct cdrom_device_ops gdrom_ops = { + .open = gdrom_open, + .release = gdrom_release, + .drive_status = gdrom_drivestatus, + .media_changed = gdrom_mediachanged, + .get_last_session = gdrom_get_last_session, + .reset = gdrom_hardreset, + .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | + CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, + .n_minors = 1, +}; + +static int gdrom_bdops_open(struct inode *inode, struct file *file) +{ + return cdrom_open(gd.cd_info, inode, file); +} + +static int gdrom_bdops_release(struct inode *inode, struct file *file) +{ + return cdrom_release(gd.cd_info, file); +} + +static int gdrom_bdops_mediachanged(struct gendisk *disk) +{ + return cdrom_media_changed(gd.cd_info); +} + +static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, + unsigned cmd, unsigned long arg) +{ + return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg); +} + +static struct block_device_operations gdrom_bdops = { + .owner = THIS_MODULE, + .open = gdrom_bdops_open, + .release = gdrom_bdops_release, + .media_changed = gdrom_bdops_mediachanged, + .ioctl = gdrom_bdops_ioctl, +}; + +static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id) +{ + gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG); + if (gd.pending != 1) + return IRQ_HANDLED; + gd.pending = 0; + wake_up_interruptible(&command_queue); + return IRQ_HANDLED; +} + +static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id) +{ + gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG); + if (gd.transfer != 1) + return IRQ_HANDLED; + gd.transfer = 0; + wake_up_interruptible(&request_queue); + return IRQ_HANDLED; +} + +static int __devinit gdrom_set_interrupt_handlers(void) +{ + int err; + + err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, + IRQF_DISABLED, "gdrom_command", &gd); + if (err) + return err; + err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, + IRQF_DISABLED, "gdrom_dma", &gd); + if (err) + free_irq(HW_EVENT_GDROM_CMD, &gd); + return err; +} + +/* Implement DMA read using SPI command + * 0 -> 0x30 + * 1 -> mode + * 2 -> block >> 16 + * 3 -> block >> 8 + * 4 -> block + * 8 -> sectors >> 16 + * 9 -> sectors >> 8 + * 10 -> sectors + */ +static void gdrom_readdisk_dma(struct work_struct *work) +{ + int err, block, block_cnt; + struct packet_command *read_command; + struct list_head *elem, *next; + struct request *req; + unsigned long timeout; + + if (list_empty(&gdrom_deferred)) + return; + read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL); + if (!read_command) + return; /* get more memory later? */ + read_command->cmd[0] = 0x30; + read_command->cmd[1] = 0x20; + spin_lock(&gdrom_lock); + list_for_each_safe(elem, next, &gdrom_deferred) { + req = list_entry(elem, struct request, queuelist); + spin_unlock(&gdrom_lock); + block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET; + block_cnt = req->nr_sectors/GD_TO_BLK; + ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG); + ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG); + ctrl_outl(1, GDROM_DMA_DIRECTION_REG); + ctrl_outl(1, GDROM_DMA_ENABLE_REG); + read_command->cmd[2] = (block >> 16) & 0xFF; + read_command->cmd[3] = (block >> 8) & 0xFF; + read_command->cmd[4] = block & 0xFF; + read_command->cmd[8] = (block_cnt >> 16) & 0xFF; + read_command->cmd[9] = (block_cnt >> 8) & 0xFF; + read_command->cmd[10] = block_cnt & 0xFF; + /* set for DMA */ + ctrl_outb(1, GDROM_ERROR_REG); + /* other registers */ + ctrl_outb(0, GDROM_SECNUM_REG); + ctrl_outb(0, GDROM_BCL_REG); + ctrl_outb(0, GDROM_BCH_REG); + ctrl_outb(0, GDROM_DSEL_REG); + ctrl_outb(0, GDROM_INTSEC_REG); + /* Wait for registers to reset after any previous activity */ + timeout = jiffies + HZ / 2; + while (gdrom_is_busy() && time_before(jiffies, timeout)) + cpu_relax(); + ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG); + timeout = jiffies + HZ / 2; + /* Wait for packet command to finish */ + while (gdrom_is_busy() && time_before(jiffies, timeout)) + cpu_relax(); + gd.pending = 1; + gd.transfer = 1; + outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6); + timeout = jiffies + HZ / 2; + /* Wait for any pending DMA to finish */ + while (ctrl_inb(GDROM_DMA_STATUS_REG) && + time_before(jiffies, timeout)) + cpu_relax(); + /* start transfer */ + ctrl_outb(1, GDROM_DMA_STATUS_REG); + wait_event_interruptible_timeout(request_queue, + gd.transfer == 0, GDROM_DEFAULT_TIMEOUT); + err = gd.transfer; + gd.transfer = 0; + gd.pending = 0; + /* now seek to take the request spinlock + * before handling ending the request */ + spin_lock(&gdrom_lock); + list_del_init(&req->queuelist); + end_dequeued_request(req, 1 - err); + } + spin_unlock(&gdrom_lock); + kfree(read_command); +} + +static void gdrom_request_handler_dma(struct request *req) +{ + /* dequeue, add to list of deferred work + * and then schedule workqueue */ + blkdev_dequeue_request(req); + list_add_tail(&req->queuelist, &gdrom_deferred); + schedule_work(&work); +} + +static void gdrom_request(struct request_queue *rq) +{ + struct request *req; + + while ((req = elv_next_request(rq)) != NULL) { + if (!blk_fs_request(req)) { + printk(KERN_DEBUG "GDROM: Non-fs request ignored\n"); + end_request(req, 0); + } + if (rq_data_dir(req) != READ) { + printk(KERN_NOTICE "GDROM: Read only device -"); + printk(" write request ignored\n"); + end_request(req, 0); + } + if (req->nr_sectors) + gdrom_request_handler_dma(req); + else + end_request(req, 0); + } +} + +/* Print string identifying GD ROM device */ +static int __devinit gdrom_outputversion(void) +{ + struct gdrom_id *id; + char *model_name, *manuf_name, *firmw_ver; + int err = -ENOMEM; + + /* query device ID */ + id = kzalloc(sizeof(struct gdrom_id), GFP_KERNEL); + if (!id) + return err; + gdrom_identifydevice(id); + model_name = kstrndup(id->modname, 16, GFP_KERNEL); + if (!model_name) + goto free_id; + manuf_name = kstrndup(id->mname, 16, GFP_KERNEL); + if (!manuf_name) + goto free_model_name; + firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL); + if (!firmw_ver) + goto free_manuf_name; + printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", + model_name, manuf_name, firmw_ver); + err = 0; + kfree(firmw_ver); +free_manuf_name: + kfree(manuf_name); +free_model_name: + kfree(model_name); +free_id: + kfree(id); + return err; +} + +/* set the default mode for DMA transfer */ +static int __devinit gdrom_init_dma_mode(void) +{ + ctrl_outb(0x13, GDROM_ERROR_REG); + ctrl_outb(0x22, GDROM_INTSEC_REG); + if (!gdrom_wait_clrbusy()) + return -EBUSY; + ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG); + if (!gdrom_wait_busy_sleeps()) + return -EBUSY; + /* Memory protection setting for GDROM DMA + * Bits 31 - 16 security: 0x8843 + * Bits 15 and 7 reserved (0) + * Bits 14 - 8 start of transfer range in 1 MB blocks OR'ed with 0x80 + * Bits 6 - 0 end of transfer range in 1 MB blocks OR'ed with 0x80 + * (0x40 | 0x80) = start range at 0x0C000000 + * (0x7F | 0x80) = end range at 0x0FFFFFFF */ + ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG); + ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */ + return 0; +} + +static void __devinit probe_gdrom_setupcd(void) +{ + gd.cd_info->ops = &gdrom_ops; + gd.cd_info->capacity = 1; + strcpy(gd.cd_info->name, GDROM_DEV_NAME); + gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK| + CDC_SELECT_DISC; +} + +static void __devinit probe_gdrom_setupdisk(void) +{ + gd.disk->major = gdrom_major; + gd.disk->first_minor = 1; + gd.disk->minors = 1; + strcpy(gd.disk->disk_name, GDROM_DEV_NAME); +} + +static int __devinit probe_gdrom_setupqueue(void) +{ + blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR); + /* using DMA so memory will need to be contiguous */ + blk_queue_max_hw_segments(gd.gdrom_rq, 1); + /* set a large max size to get most from DMA */ + blk_queue_max_segment_size(gd.gdrom_rq, 0x40000); + gd.disk->queue = gd.gdrom_rq; + return gdrom_init_dma_mode(); +} + +/* + * register this as a block device and as compliant with the + * universal CD Rom driver interface + */ +static int __devinit probe_gdrom(struct platform_device *devptr) +{ + int err; + /* Start the device */ + if (gdrom_execute_diagnostic() != 1) { + printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n"); + return -ENODEV; + } + /* Print out firmware ID */ + if (gdrom_outputversion()) + return -ENOMEM; + /* Register GDROM */ + gdrom_major = register_blkdev(0, GDROM_DEV_NAME); + if (gdrom_major <= 0) + return gdrom_major; + printk(KERN_INFO "GDROM: Registered with major number %d\n", + gdrom_major); + /* Specify basic properties of drive */ + gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL); + if (!gd.cd_info) { + err = -ENOMEM; + goto probe_fail_no_mem; + } + probe_gdrom_setupcd(); + gd.disk = alloc_disk(1); + if (!gd.disk) { + err = -ENODEV; + goto probe_fail_no_disk; + } + probe_gdrom_setupdisk(); + if (register_cdrom(gd.cd_info)) { + err = -ENODEV; + goto probe_fail_cdrom_register; + } + gd.disk->fops = &gdrom_bdops; + /* latch on to the interrupt */ + err = gdrom_set_interrupt_handlers(); + if (err) + goto probe_fail_cmdirq_register; + gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock); + if (!gd.gdrom_rq) + goto probe_fail_requestq; + + err = probe_gdrom_setupqueue(); + if (err) + goto probe_fail_toc; + + gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL); + if (!gd.toc) + goto probe_fail_toc; + add_disk(gd.disk); + return 0; + +probe_fail_toc: + blk_cleanup_queue(gd.gdrom_rq); +probe_fail_requestq: + free_irq(HW_EVENT_GDROM_DMA, &gd); + free_irq(HW_EVENT_GDROM_CMD, &gd); +probe_fail_cmdirq_register: +probe_fail_cdrom_register: + del_gendisk(gd.disk); +probe_fail_no_disk: + kfree(gd.cd_info); + unregister_blkdev(gdrom_major, GDROM_DEV_NAME); + gdrom_major = 0; +probe_fail_no_mem: + printk(KERN_WARNING "GDROM: Probe failed - error is 0x%X\n", err); + return err; +} + +static int __devexit remove_gdrom(struct platform_device *devptr) +{ + flush_scheduled_work(); + blk_cleanup_queue(gd.gdrom_rq); + free_irq(HW_EVENT_GDROM_CMD, &gd); + free_irq(HW_EVENT_GDROM_DMA, &gd); + del_gendisk(gd.disk); + if (gdrom_major) + unregister_blkdev(gdrom_major, GDROM_DEV_NAME); + return unregister_cdrom(gd.cd_info); +} + +static struct platform_driver gdrom_driver = { + .probe = probe_gdrom, + .remove = __devexit_p(remove_gdrom), + .driver = { + .name = GDROM_DEV_NAME, + }, +}; + +static int __init init_gdrom(void) +{ + int rc; + gd.toc = NULL; + rc = platform_driver_register(&gdrom_driver); + if (rc) + return rc; + pd = platform_device_register_simple(GDROM_DEV_NAME, -1, NULL, 0); + if (IS_ERR(pd)) { + platform_driver_unregister(&gdrom_driver); + return PTR_ERR(pd); + } + return 0; +} + +static void __exit exit_gdrom(void) +{ + platform_device_unregister(pd); + platform_driver_unregister(&gdrom_driver); + kfree(gd.toc); +} + +module_init(init_gdrom); +module_exit(exit_gdrom); +MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>"); +MODULE_DESCRIPTION("SEGA Dreamcast GD-ROM Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index d8bb44b98a6a..8473b9f1da96 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -289,7 +289,7 @@ static int send_request(struct request *req) return 0; } -static void viocd_end_request(struct request *req, int uptodate) +static void viocd_end_request(struct request *req, int error) { int nsectors = req->hard_nr_sectors; @@ -302,11 +302,8 @@ static void viocd_end_request(struct request *req, int uptodate) if (!nsectors) nsectors = 1; - if (end_that_request_first(req, uptodate, nsectors)) + if (__blk_end_request(req, error, nsectors << 9)) BUG(); - add_disk_randomness(req->rq_disk); - blkdev_dequeue_request(req); - end_that_request_last(req, uptodate); } static int rwreq; @@ -317,11 +314,11 @@ static void do_viocd_request(struct request_queue *q) while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { if (!blk_fs_request(req)) - viocd_end_request(req, 0); + viocd_end_request(req, -EIO); else if (send_request(req) < 0) { printk(VIOCD_KERN_WARNING "unable to send message to OS/400!"); - viocd_end_request(req, 0); + viocd_end_request(req, -EIO); } else rwreq++; } @@ -532,9 +529,9 @@ return_complete: "with rc %d:0x%04X: %s\n", req, event->xRc, bevent->sub_result, err->msg); - viocd_end_request(req, 0); + viocd_end_request(req, -EIO); } else - viocd_end_request(req, 1); + viocd_end_request(req, 0); /* restart handling of incoming requests */ spin_unlock_irqrestore(&viocd_reqlock, flags); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 2e3a0d4bc4c2..466629594776 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -373,6 +373,16 @@ config ISTALLION To compile this driver as a module, choose M here: the module will be called istallion. +config NOZOMI + tristate "HSDPA Broadband Wireless Data Card - Globe Trotter" + depends on PCI && EXPERIMENTAL + help + If you have a HSDPA driver Broadband Wireless Data Card - + Globe Trotter PCMCIA card, say Y here. + + To compile this driver as a module, choose M here, the module + will be called nozomi. + config A2232 tristate "Commodore A2232 serial support (EXPERIMENTAL)" depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 07304d50e0cb..96fc01eddefe 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_SERIAL167) += serial167.o obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_DIGIEPCA) += epca.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index aa5ddb716ffb..1ffb381130c3 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -145,7 +145,6 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) void *addr = agp_generic_alloc_page(agp_bridge); u32 temp; - global_flush_tlb(); if (!addr) return NULL; @@ -162,7 +161,6 @@ static void ali_destroy_page(void * addr, int flags) if (flags & AGP_PAGE_DESTROY_UNMAP) { global_cache_flush(); /* is this really needed? --hch */ agp_generic_destroy_page(addr, flags); - global_flush_tlb(); } else agp_generic_destroy_page(addr, flags); } diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 832ded20fe70..2720882e66fe 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -147,7 +147,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); return -ENOMEM; } - flush_agp_mappings(); bridge->scratch_page_real = virt_to_gart(addr); bridge->scratch_page = @@ -191,7 +190,6 @@ err_out: if (bridge->driver->needs_scratch_page) { bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_UNMAP); - flush_agp_mappings(); bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_FREE); } @@ -219,7 +217,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) bridge->driver->needs_scratch_page) { bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_UNMAP); - flush_agp_mappings(); bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_FREE); } diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 64b2f6d7059d..1a4674ce0c71 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -197,7 +197,6 @@ void agp_free_memory(struct agp_memory *curr) for (i = 0; i < curr->page_count; i++) { curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP); } - flush_agp_mappings(); for (i = 0; i < curr->page_count; i++) { curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE); } @@ -267,8 +266,6 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, } new->bridge = bridge; - flush_agp_mappings(); - return new; } EXPORT_SYMBOL(agp_allocate_memory); diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index e72a83e2bad5..76f581c85a7d 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -527,7 +527,6 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge) if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { page = agp_generic_alloc_page(agp_bridge); - global_flush_tlb(); } else /* Returning NULL would cause problems */ /* AK: really dubious code. */ @@ -539,7 +538,6 @@ static void i460_destroy_page (void *page, int flags) { if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { agp_generic_destroy_page(page, flags); - global_flush_tlb(); } } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d87961993ccf..189efb6ef970 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -10,6 +10,8 @@ #include <linux/agp_backend.h> #include "agp.h" +#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588 +#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a #define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 #define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972 #define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980 @@ -208,13 +210,11 @@ static void *i8xx_alloc_pages(void) if (page == NULL) return NULL; - if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { - change_page_attr(page, 4, PAGE_KERNEL); - global_flush_tlb(); + if (set_pages_uc(page, 4) < 0) { + set_pages_wb(page, 4); __free_pages(page, 2); return NULL; } - global_flush_tlb(); get_page(page); atomic_inc(&agp_bridge->current_memory_agp); return page_address(page); @@ -228,8 +228,7 @@ static void i8xx_destroy_pages(void *addr) return; page = virt_to_page(addr); - change_page_attr(page, 4, PAGE_KERNEL); - global_flush_tlb(); + set_pages_wb(page, 4); put_page(page); __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); @@ -339,7 +338,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) switch (pg_count) { case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); - global_flush_tlb(); break; case 4: /* kludge to get 4 physical pages for ARGB cursor */ @@ -402,7 +400,6 @@ static void intel_i810_free_by_type(struct agp_memory *curr) else { agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]), AGP_PAGE_DESTROY_UNMAP); - global_flush_tlb(); agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]), AGP_PAGE_DESTROY_FREE); } @@ -526,7 +523,8 @@ static void intel_i830_init_gtt_entries(void) break; case I915_GMCH_GMS_STOLEN_48M: /* Check it's really I915G */ - if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || @@ -538,7 +536,8 @@ static void intel_i830_init_gtt_entries(void) break; case I915_GMCH_GMS_STOLEN_64M: /* Check it's really I915G */ - if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || @@ -1854,6 +1853,8 @@ static const struct intel_driver_description { { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865", &intel_845_driver, &intel_830_driver }, { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)", + NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G", NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM", @@ -2059,6 +2060,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82875_HB), ID(PCI_DEVICE_ID_INTEL_7505_0), ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_E7221_HB), ID(PCI_DEVICE_ID_INTEL_82915G_HB), ID(PCI_DEVICE_ID_INTEL_82915GM_HB), ID(PCI_DEVICE_ID_INTEL_82945G_HB), diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index f3593974496c..43d3c42df360 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -297,6 +297,7 @@ {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x258a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 4c16778e3f84..465ad35ed38f 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -600,63 +600,6 @@ static int hpet_is_known(struct hpet_data *hdp) return 0; } -EXPORT_SYMBOL(hpet_alloc); -EXPORT_SYMBOL(hpet_register); -EXPORT_SYMBOL(hpet_unregister); -EXPORT_SYMBOL(hpet_control); - -int hpet_register(struct hpet_task *tp, int periodic) -{ - unsigned int i; - u64 mask; - struct hpet_timer __iomem *timer; - struct hpet_dev *devp; - struct hpets *hpetp; - - switch (periodic) { - case 1: - mask = Tn_PER_INT_CAP_MASK; - break; - case 0: - mask = 0; - break; - default: - return -EINVAL; - } - - tp->ht_opaque = NULL; - - spin_lock_irq(&hpet_task_lock); - spin_lock(&hpet_lock); - - for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) - for (timer = hpetp->hp_hpet->hpet_timers, i = 0; - i < hpetp->hp_ntimer; i++, timer++) { - if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK) - != mask) - continue; - - devp = &hpetp->hp_dev[i]; - - if (devp->hd_flags & HPET_OPEN || devp->hd_task) { - devp = NULL; - continue; - } - - tp->ht_opaque = devp; - devp->hd_task = tp; - break; - } - - spin_unlock(&hpet_lock); - spin_unlock_irq(&hpet_task_lock); - - if (tp->ht_opaque) - return 0; - else - return -EBUSY; -} - static inline int hpet_tpcheck(struct hpet_task *tp) { struct hpet_dev *devp; @@ -706,24 +649,6 @@ int hpet_unregister(struct hpet_task *tp) return 0; } -int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) -{ - struct hpet_dev *devp; - int err; - - if ((err = hpet_tpcheck(tp))) - return err; - - spin_lock_irq(&hpet_lock); - devp = tp->ht_opaque; - if (devp->hd_task != tp) { - spin_unlock_irq(&hpet_lock); - return -ENXIO; - } - spin_unlock_irq(&hpet_lock); - return hpet_ioctl_common(devp, cmd, arg, 1); -} - static ctl_table hpet_table[] = { { .ctl_name = CTL_UNNUMBERED, @@ -806,14 +731,14 @@ static unsigned long hpet_calibrate(struct hpets *hpetp) int hpet_alloc(struct hpet_data *hdp) { - u64 cap, mcfg; + u64 cap, mcfg, hpet_config; struct hpet_dev *devp; - u32 i, ntimer; + u32 i, ntimer, irq; struct hpets *hpetp; size_t siz; struct hpet __iomem *hpet; static struct hpets *last = NULL; - unsigned long period; + unsigned long period, irq_bitmap; unsigned long long temp; /* @@ -840,11 +765,47 @@ int hpet_alloc(struct hpet_data *hdp) hpetp->hp_hpet_phys = hdp->hd_phys_address; hpetp->hp_ntimer = hdp->hd_nirqs; + hpet = hpetp->hp_hpet; - for (i = 0; i < hdp->hd_nirqs; i++) - hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i]; + /* Assign IRQs statically for legacy devices */ + hpetp->hp_dev[0].hd_hdwirq = hdp->hd_irq[0]; + hpetp->hp_dev[1].hd_hdwirq = hdp->hd_irq[1]; - hpet = hpetp->hp_hpet; + /* Assign IRQs dynamically for the others */ + for (i = 2, devp = &hpetp->hp_dev[2]; i < hdp->hd_nirqs; i++, devp++) { + struct hpet_timer __iomem *timer; + + timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; + + /* Check if there's already an IRQ assigned to the timer */ + if (hdp->hd_irq[i]) { + hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i]; + continue; + } + + hpet_config = readq(&timer->hpet_config); + irq_bitmap = (hpet_config & Tn_INT_ROUTE_CAP_MASK) + >> Tn_INT_ROUTE_CAP_SHIFT; + if (!irq_bitmap) + irq = 0; /* No valid IRQ Assignable */ + else { + irq = find_first_bit(&irq_bitmap, 32); + do { + hpet_config |= irq << Tn_INT_ROUTE_CNF_SHIFT; + writeq(hpet_config, &timer->hpet_config); + + /* + * Verify whether we have written a valid + * IRQ number by reading it back again + */ + hpet_config = readq(&timer->hpet_config); + if (irq == (hpet_config & Tn_INT_ROUTE_CNF_MASK) + >> Tn_INT_ROUTE_CNF_SHIFT) + break; /* Success */ + } while ((irq = (find_next_bit(&irq_bitmap, 32, irq)))); + } + hpetp->hp_dev[i].hd_hdwirq = irq; + } cap = readq(&hpet->hpet_cap); @@ -875,7 +836,8 @@ int hpet_alloc(struct hpet_data *hdp) hpetp->hp_which, hdp->hd_phys_address, hpetp->hp_ntimer > 1 ? "s" : ""); for (i = 0; i < hpetp->hp_ntimer; i++) - printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); + printk("%s %d", i > 0 ? "," : "", + hpetp->hp_dev[i].hd_hdwirq); printk("\n"); printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 8252f8668538..480fae29c9b2 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -27,7 +27,7 @@ #include <linux/init.h> #include <linux/kbd_kern.h> #include <linux/kernel.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/module.h> @@ -89,7 +89,7 @@ struct hvc_struct { int irq_requested; int irq; struct list_head next; - struct kobject kobj; /* ref count & hvc_struct lifetime */ + struct kref kref; /* ref count & hvc_struct lifetime */ }; /* dynamic list of hvc_struct instances */ @@ -110,7 +110,7 @@ static int last_hvc = -1; /* * Do not call this function with either the hvc_structs_lock or the hvc_struct - * lock held. If successful, this function increments the kobject reference + * lock held. If successful, this function increments the kref reference * count against the target hvc_struct so it should be released when finished. */ static struct hvc_struct *hvc_get_by_index(int index) @@ -123,7 +123,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kobject_get(&hp->kobj); + kref_get(&hp->kref); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -242,6 +242,23 @@ static int __init hvc_console_init(void) } console_initcall(hvc_console_init); +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kref *kref) +{ + struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + /* * hvc_instantiate() is an early console discovery method which locates * consoles * prior to the vio subsystem discovering them. Hotplugged @@ -261,7 +278,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kobject_put(&hp->kobj); + kref_put(&hp->kref, destroy_hvc_struct); return -1; } @@ -318,9 +335,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) unsigned long flags; int irq = 0; int rc = 0; - struct kobject *kobjp; - /* Auto increments kobject reference if found. */ + /* Auto increments kref reference if found. */ if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; @@ -341,8 +357,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (irq) hp->irq_requested = 1; - kobjp = &hp->kobj; - spin_unlock_irqrestore(&hp->lock, flags); /* check error, fallback to non-irq */ if (irq) @@ -352,7 +366,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * If the request_irq() fails and we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set - * tty fields and return the kobject reference. + * tty fields and return the kref reference. */ if (rc) { spin_lock_irqsave(&hp->lock, flags); @@ -360,7 +374,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -372,7 +386,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - struct kobject *kobjp; int irq = 0; unsigned long flags; @@ -382,7 +395,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) /* * No driver_data means that this close was issued after a failed * hvc_open by the tty layer's release_dev() function and we can just - * exit cleanly because the kobject reference wasn't made. + * exit cleanly because the kref reference wasn't made. */ if (!tty->driver_data) return; @@ -390,7 +403,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; spin_lock_irqsave(&hp->lock, flags); - kobjp = &hp->kobj; if (--hp->count == 0) { if (hp->irq_requested) irq = hp->irq; @@ -417,7 +429,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); } - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } static void hvc_hangup(struct tty_struct *tty) @@ -426,7 +438,6 @@ static void hvc_hangup(struct tty_struct *tty) unsigned long flags; int irq = 0; int temp_open_count; - struct kobject *kobjp; if (!hp) return; @@ -443,7 +454,6 @@ static void hvc_hangup(struct tty_struct *tty) return; } - kobjp = &hp->kobj; temp_open_count = hp->count; hp->count = 0; hp->n_outbuf = 0; @@ -457,7 +467,7 @@ static void hvc_hangup(struct tty_struct *tty) free_irq(irq, hp); while(temp_open_count) { --temp_open_count; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } } @@ -729,27 +739,6 @@ static const struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -/* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kobject *kobj) -{ - struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - spin_lock_irqsave(&hp->lock, flags); - list_del(&(hp->next)); - spin_unlock_irqrestore(&hp->lock, flags); - - spin_unlock(&hvc_structs_lock); - - kfree(hp); -} - -static struct kobj_type hvc_kobj_type = { - .release = destroy_hvc_struct, -}; - struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, struct hv_ops *ops, int outbuf_size) { @@ -776,8 +765,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kobject_init(&hp->kobj); - hp->kobj.ktype = &hvc_kobj_type; + kref_init(&hp->kref); spin_lock_init(&hp->lock); spin_lock(&hvc_structs_lock); @@ -806,12 +794,10 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, int __devexit hvc_remove(struct hvc_struct *hp) { unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; spin_lock_irqsave(&hp->lock, flags); tty = hp->tty; - kobjp = &hp->kobj; if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -821,12 +807,12 @@ int __devexit hvc_remove(struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); /* - * We 'put' the instance that was grabbed when the kobject instance - * was initialized using kobject_init(). Let the last holder of this - * kobject cause it to be removed, which will probably be the tty_hangup + * We 'put' the instance that was grabbed when the kref instance + * was initialized using kref_init(). Let the last holder of this + * kref cause it to be removed, which will probably be the tty_hangup * below. */ - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); /* * This function call will auto chain call hvc_hangup. The tty should diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 69d8866de783..fd7559084b82 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -57,11 +57,7 @@ * rescanning partner information upon a user's request. * * Each vty-server, prior to being exposed to this driver is reference counted - * using the 2.6 Linux kernel kobject construct. This kobject is also used by - * the vio bus to provide a vio device sysfs entry that this driver attaches - * device specific attributes to, including partner information. The vio bus - * framework also provides a sysfs entry for each vio driver. The hvcs driver - * provides driver attributes in this entry. + * using the 2.6 Linux kernel kref construct. * * For direction on installation and usage of this driver please reference * Documentation/powerpc/hvcs.txt. @@ -71,7 +67,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/major.h> @@ -293,12 +289,12 @@ struct hvcs_struct { int chars_in_buffer; /* - * Any variable below the kobject is valid before a tty is connected and + * Any variable below the kref is valid before a tty is connected and * stays valid after the tty is disconnected. These shouldn't be * whacked until the koject refcount reaches zero though some entries * may be changed via sysfs initiatives. */ - struct kobject kobj; /* ref count & hvcs_struct lifetime */ + struct kref kref; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ uint32_t p_unit_address; /* partner unit address */ uint32_t p_partition_ID; /* partner partition ID */ @@ -307,8 +303,8 @@ struct hvcs_struct { struct vio_dev *vdev; }; -/* Required to back map a kobject to its containing object */ -#define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj) +/* Required to back map a kref to its containing object */ +#define from_kref(k) container_of(k, struct hvcs_struct, kref) static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); @@ -334,7 +330,6 @@ static void hvcs_partner_free(struct hvcs_struct *hvcsd); static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, unsigned int irq, struct vio_dev *dev); -static void destroy_hvcs_struct(struct kobject *kobj); static int hvcs_open(struct tty_struct *tty, struct file *filp); static void hvcs_close(struct tty_struct *tty, struct file *filp); static void hvcs_hangup(struct tty_struct * tty); @@ -703,10 +698,10 @@ static void hvcs_return_index(int index) hvcs_index_list[index] = -1; } -/* callback when the kboject ref count reaches zero */ -static void destroy_hvcs_struct(struct kobject *kobj) +/* callback when the kref ref count reaches zero */ +static void destroy_hvcs_struct(struct kref *kref) { - struct hvcs_struct *hvcsd = from_kobj(kobj); + struct hvcs_struct *hvcsd = from_kref(kref); struct vio_dev *vdev; unsigned long flags; @@ -743,10 +738,6 @@ static void destroy_hvcs_struct(struct kobject *kobj) kfree(hvcsd); } -static struct kobj_type hvcs_kobj_type = { - .release = destroy_hvcs_struct, -}; - static int hvcs_get_index(void) { int i; @@ -791,9 +782,7 @@ static int __devinit hvcs_probe( spin_lock_init(&hvcsd->lock); /* Automatically incs the refcount the first time */ - kobject_init(&hvcsd->kobj); - /* Set up the callback for terminating the hvcs_struct's life */ - hvcsd->kobj.ktype = &hvcs_kobj_type; + kref_init(&hvcsd->kref); hvcsd->vdev = dev; dev->dev.driver_data = hvcsd; @@ -844,7 +833,6 @@ static int __devexit hvcs_remove(struct vio_dev *dev) { struct hvcs_struct *hvcsd = dev->dev.driver_data; unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; if (!hvcsd) @@ -856,15 +844,13 @@ static int __devexit hvcs_remove(struct vio_dev *dev) tty = hvcsd->tty; - kobjp = &hvcsd->kobj; - spin_unlock_irqrestore(&hvcsd->lock, flags); /* * Let the last holder of this object cause it to be removed, which * would probably be tty_hangup below. */ - kobject_put (kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); /* * The hangup is a scheduled function which will auto chain call @@ -1086,7 +1072,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, } /* - * This always increments the kobject ref count if the call is successful. + * This always increments the kref ref count if the call is successful. * Please remember to dec when you are done with the instance. * * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when @@ -1103,7 +1089,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { - kobject_get(&hvcsd->kobj); + kref_get(&hvcsd->kref); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); return hvcsd; @@ -1129,14 +1115,13 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) unsigned int irq; struct vio_dev *vdev; unsigned long unit_address; - struct kobject *kobjp; if (tty->driver_data) goto fast_open; /* * Is there a vty-server that shares the same index? - * This function increments the kobject index. + * This function increments the kref index. */ if (!(hvcsd = hvcs_get_by_index(tty->index))) { printk(KERN_WARNING "HVCS: open failed, no device associated" @@ -1181,7 +1166,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * and will grab the spinlock and free the connection if it fails. */ if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - kobject_put(&hvcsd->kobj); + kref_put(&hvcsd->kref, destroy_hvcs_struct); printk(KERN_WARNING "HVCS: enable device failed.\n"); return rc; } @@ -1192,17 +1177,11 @@ fast_open: hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (!kobject_get(&hvcsd->kobj)) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_ERR "HVCS: Kobject of open" - " hvcs doesn't exist.\n"); - return -EFAULT; /* Is this the right return value? */ - } - + kref_get(&hvcsd->kref); hvcsd->open_count++; - hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); + open_success: hvcs_kick(); @@ -1212,9 +1191,8 @@ open_success: return 0; error_release: - kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(&hvcsd->kobj); + kref_put(&hvcsd->kref, destroy_hvcs_struct); printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; @@ -1224,7 +1202,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) { struct hvcs_struct *hvcsd; unsigned long flags; - struct kobject *kobjp; int irq = NO_IRQ; /* @@ -1245,7 +1222,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - kobjp = &hvcsd->kobj; if (--hvcsd->open_count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1270,7 +1246,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); return; } else if (hvcsd->open_count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" @@ -1279,7 +1255,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) } spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); } static void hvcs_hangup(struct tty_struct * tty) @@ -1287,21 +1263,17 @@ static void hvcs_hangup(struct tty_struct * tty) struct hvcs_struct *hvcsd = tty->driver_data; unsigned long flags; int temp_open_count; - struct kobject *kobjp; int irq = NO_IRQ; spin_lock_irqsave(&hvcsd->lock, flags); - /* Preserve this so that we know how many kobject refs to put */ + /* Preserve this so that we know how many kref refs to put */ temp_open_count = hvcsd->open_count; /* - * Don't kobject put inside the spinlock because the destruction + * Don't kref put inside the spinlock because the destruction * callback may use the spinlock and it may get called before the - * spinlock has been released. Get a pointer to the kobject and - * kobject_put on that after releasing the spinlock. + * spinlock has been released. */ - kobjp = &hvcsd->kobj; - vio_disable_interrupts(hvcsd->vdev); hvcsd->todo_mask = 0; @@ -1324,7 +1296,7 @@ static void hvcs_hangup(struct tty_struct * tty) free_irq(irq, hvcsd); /* - * We need to kobject_put() for every open_count we have since the + * We need to kref_put() for every open_count we have since the * tty_hangup() function doesn't invoke a close per open connection on a * non-console device. */ @@ -1335,7 +1307,7 @@ static void hvcs_hangup(struct tty_struct * tty) * NOTE: If this hangup was signaled from user space then the * final put will never happen. */ - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); } } diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 556fd81fa815..c422e870dc52 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct pci_dev *amd_pdev; -static int amd_rng_data_present(struct hwrng *rng) +static int amd_rng_data_present(struct hwrng *rng, int wait) { u32 pmbase = (u32)rng->priv; + int data, i; - return !!(inl(pmbase + 0xF4) & 1); + for (i = 0; i < 20; i++) { + data = !!(inl(pmbase + 0xF4) & 1); + if (data || !wait) + break; + udelay(10); + } + return data; } static int amd_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 26a860adcb38..0118b9817a95 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng) rng->cleanup(rng); } -static inline int hwrng_data_present(struct hwrng *rng) +static inline int hwrng_data_present(struct hwrng *rng, int wait) { if (!rng->data_present) return 1; - return rng->data_present(rng); + return rng->data_present(rng, wait); } static inline int hwrng_data_read(struct hwrng *rng, u32 *data) @@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, { u32 data; ssize_t ret = 0; - int i, err = 0; - int data_present; + int err = 0; int bytes_read; while (size) { @@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, err = -ENODEV; goto out; } - if (filp->f_flags & O_NONBLOCK) { - data_present = hwrng_data_present(current_rng); - } else { - /* Some RNG require some time between data_reads to gather - * new entropy. Poll it. - */ - for (i = 0; i < 20; i++) { - data_present = hwrng_data_present(current_rng); - if (data_present) - break; - udelay(10); - } - } + bytes_read = 0; - if (data_present) + if (hwrng_data_present(current_rng, + !(filp->f_flags & O_NONBLOCK))) bytes_read = hwrng_data_read(current_rng, &data); mutex_unlock(&rng_mutex); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 8e8658dcd2e3..fed4ef5569f5 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data) return 4; } -static int geode_rng_data_present(struct hwrng *rng) +static int geode_rng_data_present(struct hwrng *rng, int wait) { void __iomem *mem = (void __iomem *)rng->priv; + int data, i; - return !!(readl(mem + GEODE_RNG_STATUS_REG)); + for (i = 0; i < 20; i++) { + data = !!(readl(mem + GEODE_RNG_STATUS_REG)); + if (data || !wait) + break; + udelay(10); + } + return data; } diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 753f46052b87..5cc651ef75eb 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/stop_machine.h> +#include <linux/delay.h> #include <asm/io.h> @@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem, return hwstatus_get(mem); } -static int intel_rng_data_present(struct hwrng *rng) +static int intel_rng_data_present(struct hwrng *rng, int wait) { void __iomem *mem = (void __iomem *)rng->priv; - - return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT); + int data, i; + + for (i = 0; i < 20; i++) { + data = !!(readb(mem + INTEL_RNG_STATUS) & + INTEL_RNG_DATA_PRESENT); + if (data || !wait) + break; + udelay(10); + } + return data; } static int intel_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 3f35a1c562b1..7e319951fa41 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -29,6 +29,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val) } /* REVISIT: Does the status bit really work on 16xx? */ -static int omap_rng_data_present(struct hwrng *rng) +static int omap_rng_data_present(struct hwrng *rng, int wait) { - return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; + int data, i; + + for (i = 0; i < 20; i++) { + data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; + if (data || !wait) + break; + udelay(10); + } + return data; } static int omap_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index 24ae3073991f..6d50e9bc700b 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/of_platform.h> #include <asm/io.h> @@ -41,12 +42,19 @@ #define MODULE_NAME "pasemi_rng" -static int pasemi_rng_data_present(struct hwrng *rng) +static int pasemi_rng_data_present(struct hwrng *rng, int wait) { void __iomem *rng_regs = (void __iomem *)rng->priv; - - return (in_le32(rng_regs + SDCRNG_CTL_REG) - & SDCRNG_CTL_FVLD_M) ? 1 : 0; + int data, i; + + for (i = 0; i < 20; i++) { + data = (in_le32(rng_regs + SDCRNG_CTL_REG) + & SDCRNG_CTL_FVLD_M) ? 1 : 0; + if (data || !wait) + break; + udelay(10); + } + return data; } static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index ec435cb25c4f..868e39fd42e4 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/msr.h> #include <asm/cpufeature.h> @@ -77,10 +78,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in) return eax_out; } -static int via_rng_data_present(struct hwrng *rng) +static int via_rng_data_present(struct hwrng *rng, int wait) { u32 bytes_out; u32 *via_rng_datum = (u32 *)(&rng->priv); + int i; /* We choose the recommended 1-byte-per-instruction RNG rate, * for greater randomness at the expense of speed. Larger @@ -95,12 +97,15 @@ static int via_rng_data_present(struct hwrng *rng) * completes. */ - *via_rng_datum = 0; /* paranoia, not really necessary */ - bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); - bytes_out &= VIA_XSTORE_CNT_MASK; - if (bytes_out == 0) - return 0; - return 1; + for (i = 0; i < 20; i++) { + *via_rng_datum = 0; /* paranoia, not really necessary */ + bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); + bytes_out &= VIA_XSTORE_CNT_MASK; + if (bytes_out || !wait) + break; + udelay(10); + } + return bytes_out ? 1 : 0; } static int via_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c new file mode 100644 index 000000000000..6076e662886a --- /dev/null +++ b/drivers/char/nozomi.c @@ -0,0 +1,1993 @@ +/* + * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter + * + * Written by: Ulf Jakobsson, + * Jan �erfeldt, + * Stefan Thomasson, + * + * Maintained by: Paul Hardwick (p.hardwick@option.com) + * + * Patches: + * Locking code changes for Vodafone by Sphere Systems Ltd, + * Andrew Bird (ajb@spheresystems.co.uk ) + * & Phil Sanderson + * + * Source has been ported from an implementation made by Filip Aben @ Option + * + * -------------------------------------------------------------------------- + * + * Copyright (c) 2005,2006 Option Wireless Sweden AB + * Copyright (c) 2006 Sphere Systems Ltd + * Copyright (c) 2006 Option Wireless n/v + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * -------------------------------------------------------------------------- + */ + +/* + * CHANGELOG + * Version 2.1d + * 11-November-2007 Jiri Slaby, Frank Seidel + * - Big rework of multicard support by Jiri + * - Major cleanups (semaphore to mutex, endianess, no major reservation) + * - Optimizations + * + * Version 2.1c + * 30-October-2007 Frank Seidel + * - Completed multicard support + * - Minor cleanups + * + * Version 2.1b + * 07-August-2007 Frank Seidel + * - Minor cleanups + * - theoretical multicard support + * + * Version 2.1 + * 03-July-2006 Paul Hardwick + * + * - Stability Improvements. Incorporated spinlock wraps patch. + * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room) + * - using __devexit macro for tty + * + * + * Version 2.0 + * 08-feb-2006 15:34:10:Ulf + * + * -Fixed issue when not waking up line disipine layer, could probably result + * in better uplink performance for 2.4. + * + * -Fixed issue with big endian during initalization, now proper toggle flags + * are handled between preloader and maincode. + * + * -Fixed flow control issue. + * + * -Added support for setting DTR. + * + * -For 2.4 kernels, removing temporary buffer that's not needed. + * + * -Reading CTS only for modem port (only port that supports it). + * + * -Return 0 in write_room instead of netative value, it's not handled in + * upper layer. + * + * -------------------------------------------------------------------------- + * Version 1.0 + * + * First version of driver, only tested with card of type F32_2. + * Works fine with 2.4 and 2.6 kernels. + * Driver also support big endian architecture. + */ + +/* Enable this to have a lot of debug printouts */ +#define DEBUG + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> + +#include <linux/delay.h> + + +#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ + __DATE__ " " __TIME__ ")" + +/* Macros definitions */ + +/* Default debug printout level */ +#define NOZOMI_DEBUG_LEVEL 0x00 + +#define P_BUF_SIZE 128 +#define NFO(_err_flag_, args...) \ +do { \ + char tmp[P_BUF_SIZE]; \ + snprintf(tmp, sizeof(tmp), ##args); \ + printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ + __FUNCTION__, tmp); \ +} while (0) + +#define DBG1(args...) D_(0x01, ##args) +#define DBG2(args...) D_(0x02, ##args) +#define DBG3(args...) D_(0x04, ##args) +#define DBG4(args...) D_(0x08, ##args) +#define DBG5(args...) D_(0x10, ##args) +#define DBG6(args...) D_(0x20, ##args) +#define DBG7(args...) D_(0x40, ##args) +#define DBG8(args...) D_(0x80, ##args) + +#ifdef DEBUG +/* Do we need this settable at runtime? */ +static int debug = NOZOMI_DEBUG_LEVEL; + +#define D(lvl, args...) do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ + while (0) +#define D_(lvl, args...) D(lvl, ##args) + +/* These printouts are always printed */ + +#else +static int debug; +#define D_(lvl, args...) +#endif + +/* TODO: rewrite to optimize macros... */ + +#define TMP_BUF_MAX 256 + +#define DUMP(buf__,len__) \ + do { \ + char tbuf[TMP_BUF_MAX] = {0};\ + if (len__ > 1) {\ + snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ + if (tbuf[len__-2] == '\r') {\ + tbuf[len__-2] = 'r';\ + } \ + DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ + } else {\ + DBG1("SENDING: '%s' (%d)", tbuf, len__);\ + } \ +} while (0) + +/* Defines */ +#define NOZOMI_NAME "nozomi" +#define NOZOMI_NAME_TTY "nozomi_tty" +#define DRIVER_DESC "Nozomi driver" + +#define NTTY_TTY_MAXMINORS 256 +#define NTTY_FIFO_BUFFER_SIZE 8192 + +/* Must be power of 2 */ +#define FIFO_BUFFER_SIZE_UL 8192 + +/* Size of tmp send buffer to card */ +#define SEND_BUF_MAX 1024 +#define RECEIVE_BUF_MAX 4 + + +/* Define all types of vendors and devices to support */ +#define VENDOR1 0x1931 /* Vendor Option */ +#define DEVICE1 0x000c /* HSDPA card */ + +#define R_IIR 0x0000 /* Interrupt Identity Register */ +#define R_FCR 0x0000 /* Flow Control Register */ +#define R_IER 0x0004 /* Interrupt Enable Register */ + +#define CONFIG_MAGIC 0xEFEFFEFE +#define TOGGLE_VALID 0x0000 + +/* Definition of interrupt tokens */ +#define MDM_DL1 0x0001 +#define MDM_UL1 0x0002 +#define MDM_DL2 0x0004 +#define MDM_UL2 0x0008 +#define DIAG_DL1 0x0010 +#define DIAG_DL2 0x0020 +#define DIAG_UL 0x0040 +#define APP1_DL 0x0080 +#define APP1_UL 0x0100 +#define APP2_DL 0x0200 +#define APP2_UL 0x0400 +#define CTRL_DL 0x0800 +#define CTRL_UL 0x1000 +#define RESET 0x8000 + +#define MDM_DL (MDM_DL1 | MDM_DL2) +#define MDM_UL (MDM_UL1 | MDM_UL2) +#define DIAG_DL (DIAG_DL1 | DIAG_DL2) + +/* modem signal definition */ +#define CTRL_DSR 0x0001 +#define CTRL_DCD 0x0002 +#define CTRL_RI 0x0004 +#define CTRL_CTS 0x0008 + +#define CTRL_DTR 0x0001 +#define CTRL_RTS 0x0002 + +#define MAX_PORT 4 +#define NOZOMI_MAX_PORTS 5 +#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) + +/* Type definitions */ + +/* + * There are two types of nozomi cards, + * one with 2048 memory and with 8192 memory + */ +enum card_type { + F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ + F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ +}; + +/* Two different toggle channels exist */ +enum channel_type { + CH_A = 0, + CH_B = 1, +}; + +/* Port definition for the card regarding flow control */ +enum ctrl_port_type { + CTRL_CMD = 0, + CTRL_MDM = 1, + CTRL_DIAG = 2, + CTRL_APP1 = 3, + CTRL_APP2 = 4, + CTRL_ERROR = -1, +}; + +/* Ports that the nozomi has */ +enum port_type { + PORT_MDM = 0, + PORT_DIAG = 1, + PORT_APP1 = 2, + PORT_APP2 = 3, + PORT_CTRL = 4, + PORT_ERROR = -1, +}; + +#ifdef __BIG_ENDIAN +/* Big endian */ + +struct toggles { + unsigned enabled:5; /* + * Toggle fields are valid if enabled is 0, + * else A-channels must always be used. + */ + unsigned diag_dl:1; + unsigned mdm_dl:1; + unsigned mdm_ul:1; +} __attribute__ ((packed)); + +/* Configuration table to read at startup of card */ +/* Is for now only needed during initialization phase */ +struct config_table { + u32 signature; + u16 product_information; + u16 version; + u8 pad3[3]; + struct toggles toggle; + u8 pad1[4]; + u16 dl_mdm_len1; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_start; + + u16 dl_diag_len1; + u16 dl_mdm_len2; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_app1_len; + + u16 dl_diag_len2; + u16 dl_ctrl_len; + u16 dl_app2_len; + u8 pad2[16]; + u16 ul_mdm_len1; + u16 ul_start; + u16 ul_diag_len; + u16 ul_mdm_len2; + u16 ul_app1_len; + u16 ul_app2_len; + u16 ul_ctrl_len; +} __attribute__ ((packed)); + +/* This stores all control downlink flags */ +struct ctrl_dl { + u8 port; + unsigned reserved:4; + unsigned CTS:1; + unsigned RI:1; + unsigned DCD:1; + unsigned DSR:1; +} __attribute__ ((packed)); + +/* This stores all control uplink flags */ +struct ctrl_ul { + u8 port; + unsigned reserved:6; + unsigned RTS:1; + unsigned DTR:1; +} __attribute__ ((packed)); + +#else +/* Little endian */ + +/* This represents the toggle information */ +struct toggles { + unsigned mdm_ul:1; + unsigned mdm_dl:1; + unsigned diag_dl:1; + unsigned enabled:5; /* + * Toggle fields are valid if enabled is 0, + * else A-channels must always be used. + */ +} __attribute__ ((packed)); + +/* Configuration table to read at startup of card */ +struct config_table { + u32 signature; + u16 version; + u16 product_information; + struct toggles toggle; + u8 pad1[7]; + u16 dl_start; + u16 dl_mdm_len1; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_mdm_len2; + u16 dl_diag_len1; + u16 dl_diag_len2; + u16 dl_app1_len; + u16 dl_app2_len; + u16 dl_ctrl_len; + u8 pad2[16]; + u16 ul_start; + u16 ul_mdm_len2; + u16 ul_mdm_len1; + u16 ul_diag_len; + u16 ul_app1_len; + u16 ul_app2_len; + u16 ul_ctrl_len; +} __attribute__ ((packed)); + +/* This stores all control downlink flags */ +struct ctrl_dl { + unsigned DSR:1; + unsigned DCD:1; + unsigned RI:1; + unsigned CTS:1; + unsigned reserverd:4; + u8 port; +} __attribute__ ((packed)); + +/* This stores all control uplink flags */ +struct ctrl_ul { + unsigned DTR:1; + unsigned RTS:1; + unsigned reserved:6; + u8 port; +} __attribute__ ((packed)); +#endif + +/* This holds all information that is needed regarding a port */ +struct port { + u8 update_flow_control; + struct ctrl_ul ctrl_ul; + struct ctrl_dl ctrl_dl; + struct kfifo *fifo_ul; + void __iomem *dl_addr[2]; + u32 dl_size[2]; + u8 toggle_dl; + void __iomem *ul_addr[2]; + u32 ul_size[2]; + u8 toggle_ul; + u16 token_dl; + + struct tty_struct *tty; + int tty_open_count; + /* mutex to ensure one access patch to this port */ + struct mutex tty_sem; + wait_queue_head_t tty_wait; + struct async_icount tty_icount; +}; + +/* Private data one for each card in the system */ +struct nozomi { + void __iomem *base_addr; + unsigned long flip; + + /* Pointers to registers */ + void __iomem *reg_iir; + void __iomem *reg_fcr; + void __iomem *reg_ier; + + u16 last_ier; + enum card_type card_type; + struct config_table config_table; /* Configuration table */ + struct pci_dev *pdev; + struct port port[NOZOMI_MAX_PORTS]; + u8 *send_buf; + + spinlock_t spin_mutex; /* secures access to registers and tty */ + + unsigned int index_start; + u32 open_ttys; +}; + +/* This is a data packet that is read or written to/from card */ +struct buffer { + u32 size; /* size is the length of the data buffer */ + u8 *data; +} __attribute__ ((packed)); + +/* Global variables */ +static struct pci_device_id nozomi_pci_tbl[] = { + {PCI_DEVICE(VENDOR1, DEVICE1)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); + +static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; +static struct tty_driver *ntty_driver; + +/* + * find card by tty_index + */ +static inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) +{ + return tty ? ndevs[tty->index / MAX_PORT] : NULL; +} + +static inline struct port *get_port_by_tty(const struct tty_struct *tty) +{ + struct nozomi *ndev = get_dc_by_tty(tty); + return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; +} + +/* + * TODO: + * -Optimize + * -Rewrite cleaner + */ + +static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, + u32 size_bytes) +{ + u32 i = 0; + const u32 *ptr = (__force u32 *) mem_addr_start; + u16 *buf16; + + if (unlikely(!ptr || !buf)) + goto out; + + /* shortcut for extremely often used cases */ + switch (size_bytes) { + case 2: /* 2 bytes */ + buf16 = (u16 *) buf; + *buf16 = __le16_to_cpu(readw((void __iomem *)ptr)); + goto out; + break; + case 4: /* 4 bytes */ + *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + goto out; + break; + } + + while (i < size_bytes) { + if (size_bytes - i == 2) { + /* Handle 2 bytes in the end */ + buf16 = (u16 *) buf; + *(buf16) = __le16_to_cpu(readw((void __iomem *)ptr)); + i += 2; + } else { + /* Read 4 bytes */ + *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + i += 4; + } + buf++; + ptr++; + } +out: + return; +} + +/* + * TODO: + * -Optimize + * -Rewrite cleaner + */ +static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf, + u32 size_bytes) +{ + u32 i = 0; + u32 *ptr = (__force u32 *) mem_addr_start; + u16 *buf16; + + if (unlikely(!ptr || !buf)) + return 0; + + /* shortcut for extremely often used cases */ + switch (size_bytes) { + case 2: /* 2 bytes */ + buf16 = (u16 *) buf; + writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + return 2; + break; + case 1: /* + * also needs to write 4 bytes in this case + * so falling through.. + */ + case 4: /* 4 bytes */ + writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + return 4; + break; + } + + while (i < size_bytes) { + if (size_bytes - i == 2) { + /* 2 bytes */ + buf16 = (u16 *) buf; + writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + i += 2; + } else { + /* 4 bytes */ + writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + i += 4; + } + buf++; + ptr++; + } + return i; +} + +/* Setup pointers to different channels and also setup buffer sizes. */ +static void setup_memory(struct nozomi *dc) +{ + void __iomem *offset = dc->base_addr + dc->config_table.dl_start; + /* The length reported is including the length field of 4 bytes, + * hence subtract with 4. + */ + const u16 buff_offset = 4; + + /* Modem port dl configuration */ + dc->port[PORT_MDM].dl_addr[CH_A] = offset; + dc->port[PORT_MDM].dl_addr[CH_B] = + (offset += dc->config_table.dl_mdm_len1); + dc->port[PORT_MDM].dl_size[CH_A] = + dc->config_table.dl_mdm_len1 - buff_offset; + dc->port[PORT_MDM].dl_size[CH_B] = + dc->config_table.dl_mdm_len2 - buff_offset; + + /* Diag port dl configuration */ + dc->port[PORT_DIAG].dl_addr[CH_A] = + (offset += dc->config_table.dl_mdm_len2); + dc->port[PORT_DIAG].dl_size[CH_A] = + dc->config_table.dl_diag_len1 - buff_offset; + dc->port[PORT_DIAG].dl_addr[CH_B] = + (offset += dc->config_table.dl_diag_len1); + dc->port[PORT_DIAG].dl_size[CH_B] = + dc->config_table.dl_diag_len2 - buff_offset; + + /* App1 port dl configuration */ + dc->port[PORT_APP1].dl_addr[CH_A] = + (offset += dc->config_table.dl_diag_len2); + dc->port[PORT_APP1].dl_size[CH_A] = + dc->config_table.dl_app1_len - buff_offset; + + /* App2 port dl configuration */ + dc->port[PORT_APP2].dl_addr[CH_A] = + (offset += dc->config_table.dl_app1_len); + dc->port[PORT_APP2].dl_size[CH_A] = + dc->config_table.dl_app2_len - buff_offset; + + /* Ctrl dl configuration */ + dc->port[PORT_CTRL].dl_addr[CH_A] = + (offset += dc->config_table.dl_app2_len); + dc->port[PORT_CTRL].dl_size[CH_A] = + dc->config_table.dl_ctrl_len - buff_offset; + + offset = dc->base_addr + dc->config_table.ul_start; + + /* Modem Port ul configuration */ + dc->port[PORT_MDM].ul_addr[CH_A] = offset; + dc->port[PORT_MDM].ul_size[CH_A] = + dc->config_table.ul_mdm_len1 - buff_offset; + dc->port[PORT_MDM].ul_addr[CH_B] = + (offset += dc->config_table.ul_mdm_len1); + dc->port[PORT_MDM].ul_size[CH_B] = + dc->config_table.ul_mdm_len2 - buff_offset; + + /* Diag port ul configuration */ + dc->port[PORT_DIAG].ul_addr[CH_A] = + (offset += dc->config_table.ul_mdm_len2); + dc->port[PORT_DIAG].ul_size[CH_A] = + dc->config_table.ul_diag_len - buff_offset; + + /* App1 port ul configuration */ + dc->port[PORT_APP1].ul_addr[CH_A] = + (offset += dc->config_table.ul_diag_len); + dc->port[PORT_APP1].ul_size[CH_A] = + dc->config_table.ul_app1_len - buff_offset; + + /* App2 port ul configuration */ + dc->port[PORT_APP2].ul_addr[CH_A] = + (offset += dc->config_table.ul_app1_len); + dc->port[PORT_APP2].ul_size[CH_A] = + dc->config_table.ul_app2_len - buff_offset; + + /* Ctrl ul configuration */ + dc->port[PORT_CTRL].ul_addr[CH_A] = + (offset += dc->config_table.ul_app2_len); + dc->port[PORT_CTRL].ul_size[CH_A] = + dc->config_table.ul_ctrl_len - buff_offset; +} + +/* Dump config table under initalization phase */ +#ifdef DEBUG +static void dump_table(const struct nozomi *dc) +{ + DBG3("signature: 0x%08X", dc->config_table.signature); + DBG3("version: 0x%04X", dc->config_table.version); + DBG3("product_information: 0x%04X", \ + dc->config_table.product_information); + DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); + DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); + DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); + DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); + + DBG3("dl_start: 0x%04X", dc->config_table.dl_start); + DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, + dc->config_table.dl_mdm_len1); + DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, + dc->config_table.dl_mdm_len2); + DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, + dc->config_table.dl_diag_len1); + DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, + dc->config_table.dl_diag_len2); + DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, + dc->config_table.dl_app1_len); + DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, + dc->config_table.dl_app2_len); + DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, + dc->config_table.dl_ctrl_len); + DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, + dc->config_table.ul_start); + DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, + dc->config_table.ul_mdm_len1); + DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, + dc->config_table.ul_mdm_len2); + DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, + dc->config_table.ul_diag_len); + DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, + dc->config_table.ul_app1_len); + DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, + dc->config_table.ul_app2_len); + DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, + dc->config_table.ul_ctrl_len); +} +#else +static __inline__ void dump_table(const struct nozomi *dc) { } +#endif + +/* + * Read configuration table from card under intalization phase + * Returns 1 if ok, else 0 + */ +static int nozomi_read_config_table(struct nozomi *dc) +{ + read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, + sizeof(struct config_table)); + + if (dc->config_table.signature != CONFIG_MAGIC) { + dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", + dc->config_table.signature, CONFIG_MAGIC); + return 0; + } + + if ((dc->config_table.version == 0) + || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { + int i; + DBG1("Second phase, configuring card"); + + setup_memory(dc); + + dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; + dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; + dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; + DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", + dc->port[PORT_MDM].toggle_ul, + dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); + + dump_table(dc); + + for (i = PORT_MDM; i < MAX_PORT; i++) { + dc->port[i].fifo_ul = + kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL); + memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); + memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); + } + + /* Enable control channel */ + dc->last_ier = dc->last_ier | CTRL_DL; + writew(dc->last_ier, dc->reg_ier); + + dev_info(&dc->pdev->dev, "Initialization OK!\n"); + return 1; + } + + if ((dc->config_table.version > 0) + && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { + u32 offset = 0; + DBG1("First phase: pushing upload buffers, clearing download"); + + dev_info(&dc->pdev->dev, "Version of card: %d\n", + dc->config_table.version); + + /* Here we should disable all I/O over F32. */ + setup_memory(dc); + + /* + * We should send ALL channel pair tokens back along + * with reset token + */ + + /* push upload modem buffers */ + write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], + (u32 *) &offset, 4); + write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], + (u32 *) &offset, 4); + + writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); + + DBG1("First phase done"); + } + + return 1; +} + +/* Enable uplink interrupts */ +static void enable_transmit_ul(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier |= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Disable uplink interrupts */ +static void disable_transmit_ul(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier &= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Enable downlink interrupts */ +static void enable_transmit_dl(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier |= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Disable downlink interrupts */ +static void disable_transmit_dl(enum port_type port, struct nozomi *dc) +{ + u16 mask[NOZOMI_MAX_PORTS] = \ + {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier &= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* + * Return 1 - send buffer to card and ack. + * Return 0 - don't ack, don't send buffer to card. + */ +static int send_data(enum port_type index, struct nozomi *dc) +{ + u32 size = 0; + struct port *port = &dc->port[index]; + u8 toggle = port->toggle_ul; + void __iomem *addr = port->ul_addr[toggle]; + u32 ul_size = port->ul_size[toggle]; + struct tty_struct *tty = port->tty; + + /* Get data from tty and place in buf for now */ + size = __kfifo_get(port->fifo_ul, dc->send_buf, + ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); + + if (size == 0) { + DBG4("No more data to send, disable link:"); + return 0; + } + + /* DUMP(buf, size); */ + + /* Write length + data */ + write_mem32(addr, (u32 *) &size, 4); + write_mem32(addr + 4, (u32 *) dc->send_buf, size); + + if (tty) + tty_wakeup(tty); + + return 1; +} + +/* If all data has been read, return 1, else 0 */ +static int receive_data(enum port_type index, struct nozomi *dc) +{ + u8 buf[RECEIVE_BUF_MAX] = { 0 }; + int size; + u32 offset = 4; + struct port *port = &dc->port[index]; + void __iomem *addr = port->dl_addr[port->toggle_dl]; + struct tty_struct *tty = port->tty; + int i; + + if (unlikely(!tty)) { + DBG1("tty not open for port: %d?", index); + return 1; + } + + read_mem32((u32 *) &size, addr, 4); + /* DBG1( "%d bytes port: %d", size, index); */ + + if (test_bit(TTY_THROTTLED, &tty->flags)) { + DBG1("No room in tty, don't read data, don't ack interrupt, " + "disable interrupt"); + + /* disable interrupt in downlink... */ + disable_transmit_dl(index, dc); + return 0; + } + + if (unlikely(size == 0)) { + dev_err(&dc->pdev->dev, "size == 0?\n"); + return 1; + } + + tty_buffer_request_room(tty, size); + + while (size > 0) { + read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); + + if (size == 1) { + tty_insert_flip_char(tty, buf[0], TTY_NORMAL); + size = 0; + } else if (size < RECEIVE_BUF_MAX) { + size -= tty_insert_flip_string(tty, (char *) buf, size); + } else { + i = tty_insert_flip_string(tty, \ + (char *) buf, RECEIVE_BUF_MAX); + size -= i; + offset += i; + } + } + + set_bit(index, &dc->flip); + + return 1; +} + +/* Debug for interrupts */ +#ifdef DEBUG +static char *interrupt2str(u16 interrupt) +{ + static char buf[TMP_BUF_MAX]; + char *p = buf; + + interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; + interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_DL2 ") : NULL; + + interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_UL1 ") : NULL; + interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_UL2 ") : NULL; + + interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_DL1 ") : NULL; + interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_DL2 ") : NULL; + + interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_UL ") : NULL; + + interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP1_DL ") : NULL; + interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP2_DL ") : NULL; + + interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP1_UL ") : NULL; + interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP2_UL ") : NULL; + + interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "CTRL_DL ") : NULL; + interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "CTRL_UL ") : NULL; + + interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "RESET ") : NULL; + + return buf; +} +#endif + +/* + * Receive flow control + * Return 1 - If ok, else 0 + */ +static int receive_flow_control(struct nozomi *dc) +{ + enum port_type port = PORT_MDM; + struct ctrl_dl ctrl_dl; + struct ctrl_dl old_ctrl; + u16 enable_ier = 0; + + read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); + + switch (ctrl_dl.port) { + case CTRL_CMD: + DBG1("The Base Band sends this value as a response to a " + "request for IMSI detach sent over the control " + "channel uplink (see section 7.6.1)."); + break; + case CTRL_MDM: + port = PORT_MDM; + enable_ier = MDM_DL; + break; + case CTRL_DIAG: + port = PORT_DIAG; + enable_ier = DIAG_DL; + break; + case CTRL_APP1: + port = PORT_APP1; + enable_ier = APP1_DL; + break; + case CTRL_APP2: + port = PORT_APP2; + enable_ier = APP2_DL; + break; + default: + dev_err(&dc->pdev->dev, + "ERROR: flow control received for non-existing port\n"); + return 0; + }; + + DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), + *((u16 *)&ctrl_dl)); + + old_ctrl = dc->port[port].ctrl_dl; + dc->port[port].ctrl_dl = ctrl_dl; + + if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { + DBG1("Disable interrupt (0x%04X) on port: %d", + enable_ier, port); + disable_transmit_ul(port, dc); + + } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { + + if (__kfifo_len(dc->port[port].fifo_ul)) { + DBG1("Enable interrupt (0x%04X) on port: %d", + enable_ier, port); + DBG1("Data in buffer [%d], enable transmit! ", + __kfifo_len(dc->port[port].fifo_ul)); + enable_transmit_ul(port, dc); + } else { + DBG1("No data in buffer..."); + } + } + + if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { + DBG1(" No change in mctrl"); + return 1; + } + /* Update statistics */ + if (old_ctrl.CTS != ctrl_dl.CTS) + dc->port[port].tty_icount.cts++; + if (old_ctrl.DSR != ctrl_dl.DSR) + dc->port[port].tty_icount.dsr++; + if (old_ctrl.RI != ctrl_dl.RI) + dc->port[port].tty_icount.rng++; + if (old_ctrl.DCD != ctrl_dl.DCD) + dc->port[port].tty_icount.dcd++; + + wake_up_interruptible(&dc->port[port].tty_wait); + + DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", + port, + dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, + dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); + + return 1; +} + +static enum ctrl_port_type port2ctrl(enum port_type port, + const struct nozomi *dc) +{ + switch (port) { + case PORT_MDM: + return CTRL_MDM; + case PORT_DIAG: + return CTRL_DIAG; + case PORT_APP1: + return CTRL_APP1; + case PORT_APP2: + return CTRL_APP2; + default: + dev_err(&dc->pdev->dev, + "ERROR: send flow control " \ + "received for non-existing port\n"); + }; + return CTRL_ERROR; +} + +/* + * Send flow control, can only update one channel at a time + * Return 0 - If we have updated all flow control + * Return 1 - If we need to update more flow control, ack current enable more + */ +static int send_flow_control(struct nozomi *dc) +{ + u32 i, more_flow_control_to_be_updated = 0; + u16 *ctrl; + + for (i = PORT_MDM; i < MAX_PORT; i++) { + if (dc->port[i].update_flow_control) { + if (more_flow_control_to_be_updated) { + /* We have more flow control to be updated */ + return 1; + } + dc->port[i].ctrl_ul.port = port2ctrl(i, dc); + ctrl = (u16 *)&dc->port[i].ctrl_ul; + write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ + (u32 *) ctrl, 2); + dc->port[i].update_flow_control = 0; + more_flow_control_to_be_updated = 1; + } + } + return 0; +} + +/* + * Handle donlink data, ports that are handled are modem and diagnostics + * Return 1 - ok + * Return 0 - toggle fields are out of sync + */ +static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, + u16 read_iir, u16 mask1, u16 mask2) +{ + if (*toggle == 0 && read_iir & mask1) { + if (receive_data(port, dc)) { + writew(mask1, dc->reg_fcr); + *toggle = !(*toggle); + } + + if (read_iir & mask2) { + if (receive_data(port, dc)) { + writew(mask2, dc->reg_fcr); + *toggle = !(*toggle); + } + } + } else if (*toggle == 1 && read_iir & mask2) { + if (receive_data(port, dc)) { + writew(mask2, dc->reg_fcr); + *toggle = !(*toggle); + } + + if (read_iir & mask1) { + if (receive_data(port, dc)) { + writew(mask1, dc->reg_fcr); + *toggle = !(*toggle); + } + } + } else { + dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", + *toggle); + return 0; + } + return 1; +} + +/* + * Handle uplink data, this is currently for the modem port + * Return 1 - ok + * Return 0 - toggle field are out of sync + */ +static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) +{ + u8 *toggle = &(dc->port[port].toggle_ul); + + if (*toggle == 0 && read_iir & MDM_UL1) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL1, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + + if (read_iir & MDM_UL2) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL2, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + } + + } else if (*toggle == 1 && read_iir & MDM_UL2) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL2, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + + if (read_iir & MDM_UL1) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL1, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + } + } else { + writew(read_iir & MDM_UL, dc->reg_fcr); + dev_err(&dc->pdev->dev, "port out of sync!\n"); + return 0; + } + return 1; +} + +static irqreturn_t interrupt_handler(int irq, void *dev_id) +{ + struct nozomi *dc = dev_id; + unsigned int a; + u16 read_iir; + + if (!dc) + return IRQ_NONE; + + spin_lock(&dc->spin_mutex); + read_iir = readw(dc->reg_iir); + + /* Card removed */ + if (read_iir == (u16)-1) + goto none; + /* + * Just handle interrupt enabled in IER + * (by masking with dc->last_ier) + */ + read_iir &= dc->last_ier; + + if (read_iir == 0) + goto none; + + + DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, + dc->last_ier); + + if (read_iir & RESET) { + if (unlikely(!nozomi_read_config_table(dc))) { + dc->last_ier = 0x0; + writew(dc->last_ier, dc->reg_ier); + dev_err(&dc->pdev->dev, "Could not read status from " + "card, we should disable interface\n"); + } else { + writew(RESET, dc->reg_fcr); + } + /* No more useful info if this was the reset interrupt. */ + goto exit_handler; + } + if (read_iir & CTRL_UL) { + DBG1("CTRL_UL"); + dc->last_ier &= ~CTRL_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_flow_control(dc)) { + writew(CTRL_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | CTRL_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & CTRL_DL) { + receive_flow_control(dc); + writew(CTRL_DL, dc->reg_fcr); + } + if (read_iir & MDM_DL) { + if (!handle_data_dl(dc, PORT_MDM, + &(dc->port[PORT_MDM].toggle_dl), read_iir, + MDM_DL1, MDM_DL2)) { + dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & MDM_UL) { + if (!handle_data_ul(dc, PORT_MDM, read_iir)) { + dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & DIAG_DL) { + if (!handle_data_dl(dc, PORT_DIAG, + &(dc->port[PORT_DIAG].toggle_dl), read_iir, + DIAG_DL1, DIAG_DL2)) { + dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & DIAG_UL) { + dc->last_ier &= ~DIAG_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_DIAG, dc)) { + writew(DIAG_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | DIAG_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & APP1_DL) { + if (receive_data(PORT_APP1, dc)) + writew(APP1_DL, dc->reg_fcr); + } + if (read_iir & APP1_UL) { + dc->last_ier &= ~APP1_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_APP1, dc)) { + writew(APP1_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | APP1_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & APP2_DL) { + if (receive_data(PORT_APP2, dc)) + writew(APP2_DL, dc->reg_fcr); + } + if (read_iir & APP2_UL) { + dc->last_ier &= ~APP2_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_APP2, dc)) { + writew(APP2_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | APP2_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + +exit_handler: + spin_unlock(&dc->spin_mutex); + for (a = 0; a < NOZOMI_MAX_PORTS; a++) + if (test_and_clear_bit(a, &dc->flip)) + tty_flip_buffer_push(dc->port[a].tty); + return IRQ_HANDLED; +none: + spin_unlock(&dc->spin_mutex); + return IRQ_NONE; +} + +static void nozomi_get_card_type(struct nozomi *dc) +{ + int i; + u32 size = 0; + + for (i = 0; i < 6; i++) + size += pci_resource_len(dc->pdev, i); + + /* Assume card type F32_8 if no match */ + dc->card_type = size == 2048 ? F32_2 : F32_8; + + dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); +} + +static void nozomi_setup_private_data(struct nozomi *dc) +{ + void __iomem *offset = dc->base_addr + dc->card_type / 2; + unsigned int i; + + dc->reg_fcr = (void __iomem *)(offset + R_FCR); + dc->reg_iir = (void __iomem *)(offset + R_IIR); + dc->reg_ier = (void __iomem *)(offset + R_IER); + dc->last_ier = 0; + dc->flip = 0; + + dc->port[PORT_MDM].token_dl = MDM_DL; + dc->port[PORT_DIAG].token_dl = DIAG_DL; + dc->port[PORT_APP1].token_dl = APP1_DL; + dc->port[PORT_APP2].token_dl = APP2_DL; + + for (i = 0; i < MAX_PORT; i++) + init_waitqueue_head(&dc->port[i].tty_wait); +} + +static ssize_t card_type_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + + return sprintf(buf, "%d\n", dc->card_type); +} +static DEVICE_ATTR(card_type, 0444, card_type_show, NULL); + +static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + + return sprintf(buf, "%u\n", dc->open_ttys); +} +static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL); + +static void make_sysfs_files(struct nozomi *dc) +{ + if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) + dev_err(&dc->pdev->dev, + "Could not create sysfs file for card_type\n"); + if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) + dev_err(&dc->pdev->dev, + "Could not create sysfs file for open_ttys\n"); +} + +static void remove_sysfs_files(struct nozomi *dc) +{ + device_remove_file(&dc->pdev->dev, &dev_attr_card_type); + device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); +} + +/* Allocate memory for one device */ +static int __devinit nozomi_card_init(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + resource_size_t start; + int ret; + struct nozomi *dc = NULL; + int ndev_idx; + int i; + + dev_dbg(&pdev->dev, "Init, new card found\n"); + + for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) + if (!ndevs[ndev_idx]) + break; + + if (ndev_idx >= ARRAY_SIZE(ndevs)) { + dev_err(&pdev->dev, "no free tty range for this card left\n"); + ret = -EIO; + goto err; + } + + dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); + if (unlikely(!dc)) { + dev_err(&pdev->dev, "Could not allocate memory\n"); + ret = -ENOMEM; + goto err_free; + } + + dc->pdev = pdev; + + /* Find out what card type it is */ + nozomi_get_card_type(dc); + + ret = pci_enable_device(dc->pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to enable PCI Device\n"); + goto err_free; + } + + start = pci_resource_start(dc->pdev, 0); + if (start == 0) { + dev_err(&pdev->dev, "No I/O address for card detected\n"); + ret = -ENODEV; + goto err_disable_device; + } + + ret = pci_request_regions(dc->pdev, NOZOMI_NAME); + if (ret) { + dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", + (int) /* nozomi_private.io_addr */ 0); + goto err_disable_device; + } + + dc->base_addr = ioremap(start, dc->card_type); + if (!dc->base_addr) { + dev_err(&pdev->dev, "Unable to map card MMIO\n"); + ret = -ENODEV; + goto err_rel_regs; + } + + dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); + if (!dc->send_buf) { + dev_err(&pdev->dev, "Could not allocate send buffer?\n"); + ret = -ENOMEM; + goto err_free_sbuf; + } + + spin_lock_init(&dc->spin_mutex); + + nozomi_setup_private_data(dc); + + /* Disable all interrupts */ + dc->last_ier = 0; + writew(dc->last_ier, dc->reg_ier); + + ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, + NOZOMI_NAME, dc); + if (unlikely(ret)) { + dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); + goto err_free_sbuf; + } + + DBG1("base_addr: %p", dc->base_addr); + + make_sysfs_files(dc); + + dc->index_start = ndev_idx * MAX_PORT; + ndevs[ndev_idx] = dc; + + for (i = 0; i < MAX_PORT; i++) { + mutex_init(&dc->port[i].tty_sem); + dc->port[i].tty_open_count = 0; + dc->port[i].tty = NULL; + tty_register_device(ntty_driver, dc->index_start + i, + &pdev->dev); + } + + /* Enable RESET interrupt. */ + dc->last_ier = RESET; + writew(dc->last_ier, dc->reg_ier); + + pci_set_drvdata(pdev, dc); + + return 0; + +err_free_sbuf: + kfree(dc->send_buf); + iounmap(dc->base_addr); +err_rel_regs: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); +err_free: + kfree(dc); +err: + return ret; +} + +static void __devexit tty_exit(struct nozomi *dc) +{ + unsigned int i; + + DBG1(" "); + + flush_scheduled_work(); + + for (i = 0; i < MAX_PORT; ++i) + if (dc->port[i].tty && \ + list_empty(&dc->port[i].tty->hangup_work.entry)) + tty_hangup(dc->port[i].tty); + + while (dc->open_ttys) + msleep(1); + + for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) + tty_unregister_device(ntty_driver, i); +} + +/* Deallocate memory for one device */ +static void __devexit nozomi_card_exit(struct pci_dev *pdev) +{ + int i; + struct ctrl_ul ctrl; + struct nozomi *dc = pci_get_drvdata(pdev); + + /* Disable all interrupts */ + dc->last_ier = 0; + writew(dc->last_ier, dc->reg_ier); + + tty_exit(dc); + + /* Send 0x0001, command card to resend the reset token. */ + /* This is to get the reset when the module is reloaded. */ + ctrl.port = 0x00; + ctrl.reserved = 0; + ctrl.RTS = 0; + ctrl.DTR = 1; + DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); + + /* Setup dc->reg addresses to we can use defines here */ + write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); + writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ + + remove_sysfs_files(dc); + + free_irq(pdev->irq, dc); + + for (i = 0; i < MAX_PORT; i++) + if (dc->port[i].fifo_ul) + kfifo_free(dc->port[i].fifo_ul); + + kfree(dc->send_buf); + + iounmap(dc->base_addr); + + pci_release_regions(pdev); + + pci_disable_device(pdev); + + ndevs[dc->index_start / MAX_PORT] = NULL; + + kfree(dc); +} + +static void set_rts(const struct tty_struct *tty, int rts) +{ + struct port *port = get_port_by_tty(tty); + + port->ctrl_ul.RTS = rts; + port->update_flow_control = 1; + enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); +} + +static void set_dtr(const struct tty_struct *tty, int dtr) +{ + struct port *port = get_port_by_tty(tty); + + DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); + + port->ctrl_ul.DTR = dtr; + port->update_flow_control = 1; + enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); +} + +/* + * ---------------------------------------------------------------------------- + * TTY code + * ---------------------------------------------------------------------------- + */ + +/* Called when the userspace process opens the tty, /dev/noz*. */ +static int ntty_open(struct tty_struct *tty, struct file *file) +{ + struct port *port = get_port_by_tty(tty); + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + if (!port || !dc) + return -ENODEV; + + if (mutex_lock_interruptible(&port->tty_sem)) + return -ERESTARTSYS; + + port->tty_open_count++; + dc->open_ttys++; + + /* Enable interrupt downlink for channel */ + if (port->tty_open_count == 1) { + tty->low_latency = 1; + tty->driver_data = port; + port->tty = tty; + DBG1("open: %d", port->token_dl); + spin_lock_irqsave(&dc->spin_mutex, flags); + dc->last_ier = dc->last_ier | port->token_dl; + writew(dc->last_ier, dc->reg_ier); + spin_unlock_irqrestore(&dc->spin_mutex, flags); + } + + mutex_unlock(&port->tty_sem); + + return 0; +} + +/* Called when the userspace process close the tty, /dev/noz*. */ +static void ntty_close(struct tty_struct *tty, struct file *file) +{ + struct nozomi *dc = get_dc_by_tty(tty); + struct port *port = tty->driver_data; + unsigned long flags; + + if (!dc || !port) + return; + + if (mutex_lock_interruptible(&port->tty_sem)) + return; + + if (!port->tty_open_count) + goto exit; + + dc->open_ttys--; + port->tty_open_count--; + + if (port->tty_open_count == 0) { + DBG1("close: %d", port->token_dl); + spin_lock_irqsave(&dc->spin_mutex, flags); + dc->last_ier &= ~(port->token_dl); + writew(dc->last_ier, dc->reg_ier); + spin_unlock_irqrestore(&dc->spin_mutex, flags); + } + +exit: + mutex_unlock(&port->tty_sem); +} + +/* + * called when the userspace process writes to the tty (/dev/noz*). + * Data is inserted into a fifo, which is then read and transfered to the modem. + */ +static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, + int count) +{ + int rval = -EINVAL; + struct nozomi *dc = get_dc_by_tty(tty); + struct port *port = tty->driver_data; + unsigned long flags; + + /* DBG1( "WRITEx: %d, index = %d", count, index); */ + + if (!dc || !port) + return -ENODEV; + + if (unlikely(!mutex_trylock(&port->tty_sem))) { + /* + * must test lock as tty layer wraps calls + * to this function with BKL + */ + dev_err(&dc->pdev->dev, "Would have deadlocked - " + "return EAGAIN\n"); + return -EAGAIN; + } + + if (unlikely(!port->tty_open_count)) { + DBG1(" "); + goto exit; + } + + rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count); + + /* notify card */ + if (unlikely(dc == NULL)) { + DBG1("No device context?"); + goto exit; + } + + spin_lock_irqsave(&dc->spin_mutex, flags); + /* CTS is only valid on the modem channel */ + if (port == &(dc->port[PORT_MDM])) { + if (port->ctrl_dl.CTS) { + DBG4("Enable interrupt"); + enable_transmit_ul(tty->index % MAX_PORT, dc); + } else { + dev_err(&dc->pdev->dev, + "CTS not active on modem port?\n"); + } + } else { + enable_transmit_ul(tty->index % MAX_PORT, dc); + } + spin_unlock_irqrestore(&dc->spin_mutex, flags); + +exit: + mutex_unlock(&port->tty_sem); + return rval; +} + +/* + * Calculate how much is left in device + * This method is called by the upper tty layer. + * #according to sources N_TTY.c it expects a value >= 0 and + * does not check for negative values. + */ +static int ntty_write_room(struct tty_struct *tty) +{ + struct port *port = tty->driver_data; + int room = 0; + struct nozomi *dc = get_dc_by_tty(tty); + + if (!dc || !port) + return 0; + if (!mutex_trylock(&port->tty_sem)) + return 0; + + if (!port->tty_open_count) + goto exit; + + room = port->fifo_ul->size - __kfifo_len(port->fifo_ul); + +exit: + mutex_unlock(&port->tty_sem); + return room; +} + +/* Gets io control parameters */ +static int ntty_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct port *port = tty->driver_data; + struct ctrl_dl *ctrl_dl = &port->ctrl_dl; + struct ctrl_ul *ctrl_ul = &port->ctrl_ul; + + return (ctrl_ul->RTS ? TIOCM_RTS : 0) | + (ctrl_ul->DTR ? TIOCM_DTR : 0) | + (ctrl_dl->DCD ? TIOCM_CAR : 0) | + (ctrl_dl->RI ? TIOCM_RNG : 0) | + (ctrl_dl->DSR ? TIOCM_DSR : 0) | + (ctrl_dl->CTS ? TIOCM_CTS : 0); +} + +/* Sets io controls parameters */ +static int ntty_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + if (set & TIOCM_RTS) + set_rts(tty, 1); + else if (clear & TIOCM_RTS) + set_rts(tty, 0); + + if (set & TIOCM_DTR) + set_dtr(tty, 1); + else if (clear & TIOCM_DTR) + set_dtr(tty, 0); + + return 0; +} + +static int ntty_cflags_changed(struct port *port, unsigned long flags, + struct async_icount *cprev) +{ + struct async_icount cnow = port->tty_icount; + int ret; + + ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || + ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || + ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || + ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); + + *cprev = cnow; + + return ret; +} + +static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) +{ + struct async_icount cnow = port->tty_icount; + struct serial_icounter_struct icount; + + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + return copy_to_user(argp, &icount, sizeof(icount)); +} + +static int ntty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct port *port = tty->driver_data; + void __user *argp = (void __user *)arg; + int rval = -ENOIOCTLCMD; + + DBG1("******** IOCTL, cmd: %d", cmd); + + switch (cmd) { + case TIOCMIWAIT: { + struct async_icount cprev = port->tty_icount; + + rval = wait_event_interruptible(port->tty_wait, + ntty_cflags_changed(port, arg, &cprev)); + break; + } case TIOCGICOUNT: + rval = ntty_ioctl_tiocgicount(port, argp); + break; + default: + DBG1("ERR: 0x%08X, %d", cmd, cmd); + break; + }; + + return rval; +} + +/* + * Called by the upper tty layer when tty buffers are ready + * to receive data again after a call to throttle. + */ +static void ntty_unthrottle(struct tty_struct *tty) +{ + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + DBG1("UNTHROTTLE"); + spin_lock_irqsave(&dc->spin_mutex, flags); + enable_transmit_dl(tty->index % MAX_PORT, dc); + set_rts(tty, 1); + + spin_unlock_irqrestore(&dc->spin_mutex, flags); +} + +/* + * Called by the upper tty layer when the tty buffers are almost full. + * The driver should stop send more data. + */ +static void ntty_throttle(struct tty_struct *tty) +{ + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + DBG1("THROTTLE"); + spin_lock_irqsave(&dc->spin_mutex, flags); + set_rts(tty, 0); + spin_unlock_irqrestore(&dc->spin_mutex, flags); +} + +/* just to discard single character writes */ +static void ntty_put_char(struct tty_struct *tty, unsigned char c) +{ + /* FIXME !!! */ + DBG2("PUT CHAR Function: %c", c); +} + +/* Returns number of chars in buffer, called by tty layer */ +static s32 ntty_chars_in_buffer(struct tty_struct *tty) +{ + struct port *port = tty->driver_data; + struct nozomi *dc = get_dc_by_tty(tty); + s32 rval; + + if (unlikely(!dc || !port)) { + rval = -ENODEV; + goto exit_in_buffer; + } + + if (unlikely(!port->tty_open_count)) { + dev_err(&dc->pdev->dev, "No tty open?\n"); + rval = -ENODEV; + goto exit_in_buffer; + } + + rval = __kfifo_len(port->fifo_ul); + +exit_in_buffer: + return rval; +} + +static struct tty_operations tty_ops = { + .ioctl = ntty_ioctl, + .open = ntty_open, + .close = ntty_close, + .write = ntty_write, + .write_room = ntty_write_room, + .unthrottle = ntty_unthrottle, + .throttle = ntty_throttle, + .chars_in_buffer = ntty_chars_in_buffer, + .put_char = ntty_put_char, + .tiocmget = ntty_tiocmget, + .tiocmset = ntty_tiocmset, +}; + +/* Module initialization */ +static struct pci_driver nozomi_driver = { + .name = NOZOMI_NAME, + .id_table = nozomi_pci_tbl, + .probe = nozomi_card_init, + .remove = __devexit_p(nozomi_card_exit), +}; + +static __init int nozomi_init(void) +{ + int ret; + + printk(KERN_INFO "Initializing %s\n", VERSION_STRING); + + ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); + if (!ntty_driver) + return -ENOMEM; + + ntty_driver->owner = THIS_MODULE; + ntty_driver->driver_name = NOZOMI_NAME_TTY; + ntty_driver->name = "noz"; + ntty_driver->major = 0; + ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; + ntty_driver->subtype = SERIAL_TYPE_NORMAL; + ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + ntty_driver->init_termios = tty_std_termios; + ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ + HUPCL | CLOCAL; + ntty_driver->init_termios.c_ispeed = 115200; + ntty_driver->init_termios.c_ospeed = 115200; + tty_set_operations(ntty_driver, &tty_ops); + + ret = tty_register_driver(ntty_driver); + if (ret) { + printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); + goto free_tty; + } + + ret = pci_register_driver(&nozomi_driver); + if (ret) { + printk(KERN_ERR "Nozomi: can't register pci driver\n"); + goto unr_tty; + } + + return 0; +unr_tty: + tty_unregister_driver(ntty_driver); +free_tty: + put_tty_driver(ntty_driver); + return ret; +} + +static __exit void nozomi_exit(void) +{ + printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); + pci_unregister_driver(&nozomi_driver); + tty_unregister_driver(ntty_driver); + put_tty_driver(ntty_driver); +} + +module_init(nozomi_init); +module_exit(nozomi_exit); + +module_param(debug, int, S_IRUGO | S_IWUSR); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 0c66b802736a..78b151c4d20f 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1,5 +1,5 @@ /* - * Real Time Clock interface for Linux + * Real Time Clock interface for Linux * * Copyright (C) 1996 Paul Gortmaker * @@ -17,7 +17,7 @@ * has been received. If a RTC interrupt has already happened, * it will output an unsigned long and then block. The output value * contains the interrupt status in the low byte and the number of - * interrupts since the last read in the remaining high bytes. The + * interrupts since the last read in the remaining high bytes. The * /dev/rtc interface can also be used with the select(2) call. * * This program is free software; you can redistribute it and/or @@ -104,12 +104,14 @@ static int rtc_has_irq = 1; #ifndef CONFIG_HPET_EMULATE_RTC #define is_hpet_enabled() 0 -#define hpet_set_alarm_time(hrs, min, sec) 0 -#define hpet_set_periodic_freq(arg) 0 -#define hpet_mask_rtc_irq_bit(arg) 0 -#define hpet_set_rtc_irq_bit(arg) 0 -#define hpet_rtc_timer_init() do { } while (0) -#define hpet_rtc_dropped_irq() 0 +#define hpet_set_alarm_time(hrs, min, sec) 0 +#define hpet_set_periodic_freq(arg) 0 +#define hpet_mask_rtc_irq_bit(arg) 0 +#define hpet_set_rtc_irq_bit(arg) 0 +#define hpet_rtc_timer_init() do { } while (0) +#define hpet_rtc_dropped_irq() 0 +#define hpet_register_irq_handler(h) 0 +#define hpet_unregister_irq_handler(h) 0 #ifdef RTC_IRQ static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) { @@ -147,7 +149,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, static unsigned int rtc_poll(struct file *file, poll_table *wait); #endif -static void get_rtc_alm_time (struct rtc_time *alm_tm); +static void get_rtc_alm_time(struct rtc_time *alm_tm); #ifdef RTC_IRQ static void set_rtc_irq_bit_locked(unsigned char bit); static void mask_rtc_irq_bit_locked(unsigned char bit); @@ -185,9 +187,9 @@ static int rtc_proc_open(struct inode *inode, struct file *file); * rtc_status but before mod_timer is called, which would then reenable the * timer (but you would need to have an awful timing before you'd trip on it) */ -static unsigned long rtc_status = 0; /* bitmapped status byte. */ -static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ -static unsigned long rtc_irq_data = 0; /* our output to the world */ +static unsigned long rtc_status; /* bitmapped status byte. */ +static unsigned long rtc_freq; /* Current periodic IRQ rate */ +static unsigned long rtc_irq_data; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ #ifdef RTC_IRQ @@ -195,7 +197,7 @@ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ * rtc_task_lock nests inside rtc_lock. */ static DEFINE_SPINLOCK(rtc_task_lock); -static rtc_task_t *rtc_callback = NULL; +static rtc_task_t *rtc_callback; #endif /* @@ -205,7 +207,7 @@ static rtc_task_t *rtc_callback = NULL; static unsigned long epoch = 1900; /* year corresponding to 0x00 */ -static const unsigned char days_in_mo[] = +static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* @@ -242,7 +244,7 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id) * the last read in the remainder of rtc_irq_data. */ - spin_lock (&rtc_lock); + spin_lock(&rtc_lock); rtc_irq_data += 0x100; rtc_irq_data &= ~0xff; if (is_hpet_enabled()) { @@ -259,16 +261,16 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id) if (rtc_status & RTC_TIMER_ON) mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - spin_unlock (&rtc_lock); + spin_unlock(&rtc_lock); /* Now do the rest of the actions */ spin_lock(&rtc_task_lock); if (rtc_callback) rtc_callback->func(rtc_callback->private_data); spin_unlock(&rtc_task_lock); - wake_up_interruptible(&rtc_wait); + wake_up_interruptible(&rtc_wait); - kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } @@ -335,7 +337,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, DECLARE_WAITQUEUE(wait, current); unsigned long data; ssize_t retval; - + if (rtc_has_irq == 0) return -EIO; @@ -358,11 +360,11 @@ static ssize_t rtc_read(struct file *file, char __user *buf, * confusing. And no, xchg() is not the answer. */ __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irq (&rtc_lock); + + spin_lock_irq(&rtc_lock); data = rtc_irq_data; rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); if (data != 0) break; @@ -378,10 +380,13 @@ static ssize_t rtc_read(struct file *file, char __user *buf, schedule(); } while (1); - if (count == sizeof(unsigned int)) - retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); - else - retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long); + if (count == sizeof(unsigned int)) { + retval = put_user(data, + (unsigned int __user *)buf) ?: sizeof(int); + } else { + retval = put_user(data, + (unsigned long __user *)buf) ?: sizeof(long); + } if (!retval) retval = count; out: @@ -394,7 +399,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { - struct rtc_time wtime; + struct rtc_time wtime; #ifdef RTC_IRQ if (rtc_has_irq == 0) { @@ -426,35 +431,41 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) } case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ { - unsigned long flags; /* can be called from isr via rtc_control() */ - spin_lock_irqsave (&rtc_lock, flags); + /* can be called from isr via rtc_control() */ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); mask_rtc_irq_bit_locked(RTC_PIE); if (rtc_status & RTC_TIMER_ON) { rtc_status &= ~RTC_TIMER_ON; del_timer(&rtc_irq_timer); } - spin_unlock_irqrestore (&rtc_lock, flags); + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; } case RTC_PIE_ON: /* Allow periodic ints */ { - unsigned long flags; /* can be called from isr via rtc_control() */ + /* can be called from isr via rtc_control() */ + unsigned long flags; + /* * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ if (!kernel && (rtc_freq > rtc_max_user_freq) && - (!capable(CAP_SYS_RESOURCE))) + (!capable(CAP_SYS_RESOURCE))) return -EACCES; - spin_lock_irqsave (&rtc_lock, flags); + spin_lock_irqsave(&rtc_lock, flags); if (!(rtc_status & RTC_TIMER_ON)) { mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); rtc_status |= RTC_TIMER_ON; } set_rtc_irq_bit_locked(RTC_PIE); - spin_unlock_irqrestore (&rtc_lock, flags); + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; } case RTC_UIE_OFF: /* Mask ints from RTC updates. */ @@ -477,7 +488,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) */ memset(&wtime, 0, sizeof(struct rtc_time)); get_rtc_alm_time(&wtime); - break; + break; } case RTC_ALM_SET: /* Store a time into the alarm */ { @@ -505,16 +516,21 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) */ } if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - if (sec < 60) BIN_TO_BCD(sec); - else sec = 0xff; - - if (min < 60) BIN_TO_BCD(min); - else min = 0xff; - - if (hrs < 24) BIN_TO_BCD(hrs); - else hrs = 0xff; + RTC_ALWAYS_BCD) { + if (sec < 60) + BIN_TO_BCD(sec); + else + sec = 0xff; + + if (min < 60) + BIN_TO_BCD(min); + else + min = 0xff; + + if (hrs < 24) + BIN_TO_BCD(hrs); + else + hrs = 0xff; } CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); @@ -563,11 +579,12 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) return -EINVAL; - + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; - if ((yrs -= epoch) > 255) /* They are unsigned */ + yrs -= epoch; + if (yrs > 255) /* They are unsigned */ return -EINVAL; spin_lock_irq(&rtc_lock); @@ -635,9 +652,10 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { int tmp = 0; unsigned char val; - unsigned long flags; /* can be called from isr via rtc_control() */ + /* can be called from isr via rtc_control() */ + unsigned long flags; - /* + /* * The max we can do is 8192Hz. */ if ((arg < 2) || (arg > 8192)) @@ -646,7 +664,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > rtc_max_user_freq) && + !capable(CAP_SYS_RESOURCE)) return -EACCES; while (arg > (1<<tmp)) @@ -674,11 +693,11 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) #endif case RTC_EPOCH_READ: /* Read the epoch. */ { - return put_user (epoch, (unsigned long __user *)arg); + return put_user(epoch, (unsigned long __user *)arg); } case RTC_EPOCH_SET: /* Set the epoch. */ { - /* + /* * There were no RTC clocks before 1900. */ if (arg < 1900) @@ -693,7 +712,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) default: return -ENOTTY; } - return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, + &wtime, sizeof wtime) ? -EFAULT : 0; } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -712,26 +732,25 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * needed here. Or anywhere else in this driver. */ static int rtc_open(struct inode *inode, struct file *file) { - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); - if(rtc_status & RTC_IS_OPEN) + if (rtc_status & RTC_IS_OPEN) goto out_busy; rtc_status |= RTC_IS_OPEN; rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); return 0; out_busy: - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); return -EBUSY; } -static int rtc_fasync (int fd, struct file *filp, int on) - +static int rtc_fasync(int fd, struct file *filp, int on) { - return fasync_helper (fd, filp, on, &rtc_async_queue); + return fasync_helper(fd, filp, on, &rtc_async_queue); } static int rtc_release(struct inode *inode, struct file *file) @@ -762,16 +781,16 @@ static int rtc_release(struct inode *inode, struct file *file) } spin_unlock_irq(&rtc_lock); - if (file->f_flags & FASYNC) { - rtc_fasync (-1, file, 0); - } + if (file->f_flags & FASYNC) + rtc_fasync(-1, file, 0); no_irq: #endif - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); rtc_irq_data = 0; rtc_status &= ~RTC_IS_OPEN; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); + return 0; } @@ -786,9 +805,9 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) poll_wait(file, &rtc_wait, wait); - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); l = rtc_irq_data; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); if (l != 0) return POLLIN | POLLRDNORM; @@ -796,14 +815,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) } #endif -/* - * exported stuffs - */ - -EXPORT_SYMBOL(rtc_register); -EXPORT_SYMBOL(rtc_unregister); -EXPORT_SYMBOL(rtc_control); - int rtc_register(rtc_task_t *task) { #ifndef RTC_IRQ @@ -829,6 +840,7 @@ int rtc_register(rtc_task_t *task) return 0; #endif } +EXPORT_SYMBOL(rtc_register); int rtc_unregister(rtc_task_t *task) { @@ -845,7 +857,7 @@ int rtc_unregister(rtc_task_t *task) return -ENXIO; } rtc_callback = NULL; - + /* disable controls */ if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { tmp = CMOS_READ(RTC_CONTROL); @@ -865,6 +877,7 @@ int rtc_unregister(rtc_task_t *task) return 0; #endif } +EXPORT_SYMBOL(rtc_unregister); int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) { @@ -883,7 +896,7 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) return rtc_do_ioctl(cmd, arg, 1); #endif } - +EXPORT_SYMBOL(rtc_control); /* * The various file operations we support. @@ -910,11 +923,11 @@ static struct miscdevice rtc_dev = { #ifdef CONFIG_PROC_FS static const struct file_operations rtc_proc_fops = { - .owner = THIS_MODULE, - .open = rtc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, + .owner = THIS_MODULE, + .open = rtc_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; #endif @@ -965,7 +978,7 @@ static int __init rtc_init(void) #ifdef CONFIG_SPARC32 for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if(strcmp(edev->prom_node->name, "rtc") == 0) { + if (strcmp(edev->prom_node->name, "rtc") == 0) { rtc_port = edev->resource[0].start; rtc_irq = edev->irqs[0]; goto found; @@ -986,7 +999,8 @@ found: * XXX Interrupt pin #7 in Espresso is shared between RTC and * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ - if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) { + if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", + (void *)&rtc_port)) { rtc_has_irq = 0; printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); return -EIO; @@ -1015,16 +1029,26 @@ no_irq: #ifdef RTC_IRQ if (is_hpet_enabled()) { + int err; + rtc_int_handler_ptr = hpet_rtc_interrupt; + err = hpet_register_irq_handler(rtc_interrupt); + if (err != 0) { + printk(KERN_WARNING "hpet_register_irq_handler failed " + "in rtc_init()."); + return err; + } } else { rtc_int_handler_ptr = rtc_interrupt; } - if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) { + if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, + "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ rtc_has_irq = 0; printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); rtc_release_region(); + return -EIO; } hpet_rtc_timer_init(); @@ -1036,6 +1060,7 @@ no_irq: if (misc_register(&rtc_dev)) { #ifdef RTC_IRQ free_irq(RTC_IRQ, NULL); + hpet_unregister_irq_handler(rtc_interrupt); rtc_has_irq = 0; #endif rtc_release_region(); @@ -1052,21 +1077,21 @@ no_irq: #if defined(__alpha__) || defined(__mips__) rtc_freq = HZ; - + /* Each operating system on an Alpha uses its own epoch. Let's try to guess which one we are using now. */ - + if (rtc_is_updating() != 0) msleep(20); - + spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); - + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ - + if (year < 20) { epoch = 2000; guess = "SRM (post-2000)"; @@ -1087,7 +1112,8 @@ no_irq: #endif } if (guess) - printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch); + printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", + guess, epoch); #endif #ifdef RTC_IRQ if (rtc_has_irq == 0) @@ -1096,8 +1122,12 @@ no_irq: spin_lock_irq(&rtc_lock); rtc_freq = 1024; if (!hpet_set_periodic_freq(rtc_freq)) { - /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ - CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); + /* + * Initialize periodic frequency to CMOS reset default, + * which is 1024Hz + */ + CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), + RTC_FREQ_SELECT); } spin_unlock_irq(&rtc_lock); no_irq2: @@ -1110,20 +1140,22 @@ no_irq2: return 0; } -static void __exit rtc_exit (void) +static void __exit rtc_exit(void) { cleanup_sysctl(); - remove_proc_entry ("driver/rtc", NULL); + remove_proc_entry("driver/rtc", NULL); misc_deregister(&rtc_dev); #ifdef CONFIG_SPARC32 if (rtc_has_irq) - free_irq (rtc_irq, &rtc_port); + free_irq(rtc_irq, &rtc_port); #else rtc_release_region(); #ifdef RTC_IRQ - if (rtc_has_irq) - free_irq (RTC_IRQ, NULL); + if (rtc_has_irq) { + free_irq(RTC_IRQ, NULL); + hpet_unregister_irq_handler(hpet_rtc_interrupt); + } #endif #endif /* CONFIG_SPARC32 */ } @@ -1133,14 +1165,14 @@ module_exit(rtc_exit); #ifdef RTC_IRQ /* - * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. + * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. * (usually during an IDE disk interrupt, with IRQ unmasking off) * Since the interrupt handler doesn't get called, the IRQ status * byte doesn't get read, and the RTC stops generating interrupts. * A timer is set, and will call this function if/when that happens. * To get it out of this stalled state, we just read the status. * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. - * (You *really* shouldn't be trying to use a non-realtime system + * (You *really* shouldn't be trying to use a non-realtime system * for something that requires a steady > 1KHz signal anyways.) */ @@ -1148,7 +1180,7 @@ static void rtc_dropped_irq(unsigned long data) { unsigned long freq; - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); if (hpet_rtc_dropped_irq()) { spin_unlock_irq(&rtc_lock); @@ -1167,13 +1199,15 @@ static void rtc_dropped_irq(unsigned long data) spin_unlock_irq(&rtc_lock); - if (printk_ratelimit()) - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); + if (printk_ratelimit()) { + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", + freq); + } /* Now we have new data */ wake_up_interruptible(&rtc_wait); - kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); } #endif @@ -1277,7 +1311,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * can take just over 2ms. We wait 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable - * periodic update complete interrupts, (via ioctl) and then + * periodic update complete interrupts, (via ioctl) and then * immediately read /dev/rtc which will block until you get the IRQ. * Once the read clears, read the RTC time (again via ioctl). Easy. */ @@ -1307,8 +1341,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irqrestore(&rtc_lock, flags); - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(rtc_tm->tm_sec); BCD_TO_BIN(rtc_tm->tm_min); BCD_TO_BIN(rtc_tm->tm_hour); @@ -1326,7 +1359,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += epoch - 1900; + if (rtc_tm->tm_year <= 69) rtc_tm->tm_year += 100; rtc_tm->tm_mon--; @@ -1347,8 +1381,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm) ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(alm_tm->tm_sec); BCD_TO_BIN(alm_tm->tm_min); BCD_TO_BIN(alm_tm->tm_hour); diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index 12ceed54ab18..5732ca3259f9 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -104,7 +104,6 @@ int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id return -EINVAL; } - cbq->nls = dev->nls; cbq->seq = 0; cbq->group = cbq->id.id.idx; @@ -146,7 +145,6 @@ struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls) spin_lock_init(&dev->queue_lock); dev->nls = nls; - dev->netlink_groups = 0; dev->cn_queue = create_workqueue(dev->name); if (!dev->cn_queue) { diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index bf9716b75513..fea2d3ed9cbd 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -88,6 +88,7 @@ int cn_netlink_send(struct cn_msg *msg, u32 __group, gfp_t gfp_mask) if (cn_cb_equal(&__cbq->id.id, &msg->id)) { found = 1; group = __cbq->group; + break; } } spin_unlock_bh(&dev->cbdev->queue_lock); @@ -181,33 +182,14 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v } /* - * Skb receive helper - checks skb and msg size and calls callback - * helper. - */ -static int __cn_rx_skb(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - u32 pid, uid, seq, group; - struct cn_msg *msg; - - pid = NETLINK_CREDS(skb)->pid; - uid = NETLINK_CREDS(skb)->uid; - seq = nlh->nlmsg_seq; - group = NETLINK_CB((skb)).dst_group; - msg = NLMSG_DATA(nlh); - - return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb); -} - -/* * Main netlink receiving function. * - * It checks skb and netlink header sizes and calls the skb receive - * helper with a shared skb. + * It checks skb, netlink header and msg sizes, and calls callback helper. */ static void cn_rx_skb(struct sk_buff *__skb) { + struct cn_msg *msg; struct nlmsghdr *nlh; - u32 len; int err; struct sk_buff *skb; @@ -223,11 +205,8 @@ static void cn_rx_skb(struct sk_buff *__skb) return; } - len = NLMSG_ALIGN(nlh->nlmsg_len); - if (len > skb->len) - len = skb->len; - - err = __cn_rx_skb(skb, nlh); + msg = NLMSG_DATA(nlh); + err = cn_call_callback(msg, (void (*)(void *))kfree_skb, skb); if (err < 0) kfree_skb(skb); } @@ -441,8 +420,7 @@ static int __devinit cn_init(void) dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls); if (!dev->cbdev) { - if (dev->nls->sk_socket) - sock_release(dev->nls->sk_socket); + netlink_kernel_release(dev->nls); return -EINVAL; } @@ -452,8 +430,7 @@ static int __devinit cn_init(void) if (err) { cn_already_initialized = 0; cn_queue_free_dev(dev->cbdev); - if (dev->nls->sk_socket) - sock_release(dev->nls->sk_socket); + netlink_kernel_release(dev->nls); return -EINVAL; } @@ -468,8 +445,7 @@ static void __devexit cn_fini(void) cn_del_callback(&dev->id); cn_queue_free_dev(dev->cbdev); - if (dev->nls->sk_socket) - sock_release(dev->nls->sk_socket); + netlink_kernel_release(dev->nls); } subsys_initcall(cn_init); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 79581fab82d6..b730d6709529 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -828,11 +828,8 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) memcpy(&new_policy, policy, sizeof(struct cpufreq_policy)); /* prepare interface data */ - policy->kobj.parent = &sys_dev->kobj; - policy->kobj.ktype = &ktype_cpufreq; - kobject_set_name(&policy->kobj, "cpufreq"); - - ret = kobject_register(&policy->kobj); + ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj, + "cpufreq"); if (ret) { unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; @@ -902,6 +899,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) goto err_out_unregister; } + kobject_uevent(&policy->kobj, KOBJ_ADD); module_put(cpufreq_driver->owner); dprintk("initialization complete\n"); cpufreq_debug_enable_ratelimit(); @@ -915,7 +913,7 @@ err_out_unregister: cpufreq_cpu_data[j] = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - kobject_unregister(&policy->kobj); + kobject_put(&policy->kobj); wait_for_completion(&policy->kobj_unregister); err_out_driver_exit: @@ -1032,8 +1030,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev) unlock_policy_rwsem_write(cpu); - kobject_unregister(&data->kobj); - kobject_put(&data->kobj); /* we need to make sure that the underlying kobj is actually @@ -1608,7 +1604,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); - if (policy->min > data->min && policy->min > policy->max) { + if (policy->min > data->max || policy->max < data->min) { ret = -EINVAL; goto error_out; } diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 0f3515e77d4b..088ea74edd34 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -277,7 +277,7 @@ static struct kobj_type ktype_state_cpuidle = { static void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i) { - kobject_unregister(&device->kobjs[i]->kobj); + kobject_put(&device->kobjs[i]->kobj); wait_for_completion(&device->kobjs[i]->kobj_unregister); kfree(device->kobjs[i]); device->kobjs[i] = NULL; @@ -300,14 +300,13 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) kobj->state = &device->states[i]; init_completion(&kobj->kobj_unregister); - kobj->kobj.parent = &device->kobj; - kobj->kobj.ktype = &ktype_state_cpuidle; - kobject_set_name(&kobj->kobj, "state%d", i); - ret = kobject_register(&kobj->kobj); + ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, + "state%d", i); if (ret) { kfree(kobj); goto error_state; } + kobject_uevent(&kobj->kobj, KOBJ_ADD); device->kobjs[i] = kobj; } @@ -339,12 +338,14 @@ int cpuidle_add_sysfs(struct sys_device *sysdev) { int cpu = sysdev->id; struct cpuidle_device *dev; + int error; dev = per_cpu(cpuidle_devices, cpu); - dev->kobj.parent = &sysdev->kobj; - dev->kobj.ktype = &ktype_cpuidle; - kobject_set_name(&dev->kobj, "%s", "cpuidle"); - return kobject_register(&dev->kobj); + error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &sysdev->kobj, + "cpuidle"); + if (!error) + kobject_uevent(&dev->kobj, KOBJ_ADD); + return error; } /** @@ -357,5 +358,5 @@ void cpuidle_remove_sysfs(struct sys_device *sysdev) struct cpuidle_device *dev; dev = per_cpu(cpuidle_devices, cpu); - kobject_unregister(&dev->kobj); + kobject_put(&dev->kobj); } diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index ddd3a259cea1..6b658d84d521 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -48,8 +48,6 @@ config CRYPTO_DEV_PADLOCK_SHA If unsure say M. The compiled module will be called padlock-sha.ko -source "arch/s390/crypto/Kconfig" - config CRYPTO_DEV_GEODE tristate "Support for the Geode LX AES engine" depends on X86_32 && PCI @@ -83,4 +81,82 @@ config ZCRYPT_MONOLITHIC that contains all parts of the crypto device driver (ap bus, request router and all the card drivers). +config CRYPTO_SHA1_S390 + tristate "SHA1 digest algorithm" + depends on S390 + select CRYPTO_ALGAPI + help + This is the s390 hardware accelerated implementation of the + SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). + +config CRYPTO_SHA256_S390 + tristate "SHA256 digest algorithm" + depends on S390 + select CRYPTO_ALGAPI + help + This is the s390 hardware accelerated implementation of the + SHA256 secure hash standard (DFIPS 180-2). + + This version of SHA implements a 256 bit hash with 128 bits of + security against collision attacks. + +config CRYPTO_DES_S390 + tristate "DES and Triple DES cipher algorithms" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This us the s390 hardware accelerated implementation of the + DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). + +config CRYPTO_AES_S390 + tristate "AES cipher algorithms" + depends on S390 + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + help + This is the s390 hardware accelerated implementation of the + AES cipher algorithms (FIPS-197). AES uses the Rijndael + algorithm. + + Rijndael appears to be consistently a very good performer in + both hardware and software across a wide range of computing + environments regardless of its use in feedback or non-feedback + modes. Its key setup time is excellent, and its key agility is + good. Rijndael's very low memory requirements make it very well + suited for restricted-space environments, in which it also + demonstrates excellent performance. Rijndael's operations are + among the easiest to defend against power and timing attacks. + + On s390 the System z9-109 currently only supports the key size + of 128 bit. + +config S390_PRNG + tristate "Pseudo random number generator device driver" + depends on S390 + default "m" + help + Select this option if you want to use the s390 pseudo random number + generator. The PRNG is part of the cryptographic processor functions + and uses triple-DES to generate secure random numbers like the + ANSI X9.17 standard. The PRNG is usable via the char device + /dev/prandom. + +config CRYPTO_DEV_HIFN_795X + tristate "Driver HIFN 795x crypto accelerator chips" + select CRYPTO_DES + select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER + select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG + depends on PCI + help + This option allows you to have support for HIFN 795x crypto adapters. + +config CRYPTO_DEV_HIFN_795X_RNG + bool "HIFN 795x random number generator" + depends on CRYPTO_DEV_HIFN_795X + help + Select this option if you want to enable the random number generator + on the HIFN 795x crypto adapters. + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index d070030f7d7e..c0327f0dadc5 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o +obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 711e246e1ef0..4801162919d9 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -13,44 +13,13 @@ #include <linux/crypto.h> #include <linux/spinlock.h> #include <crypto/algapi.h> +#include <crypto/aes.h> #include <asm/io.h> #include <asm/delay.h> #include "geode-aes.h" -/* Register definitions */ - -#define AES_CTRLA_REG 0x0000 - -#define AES_CTRL_START 0x01 -#define AES_CTRL_DECRYPT 0x00 -#define AES_CTRL_ENCRYPT 0x02 -#define AES_CTRL_WRKEY 0x04 -#define AES_CTRL_DCA 0x08 -#define AES_CTRL_SCA 0x10 -#define AES_CTRL_CBC 0x20 - -#define AES_INTR_REG 0x0008 - -#define AES_INTRA_PENDING (1 << 16) -#define AES_INTRB_PENDING (1 << 17) - -#define AES_INTR_PENDING (AES_INTRA_PENDING | AES_INTRB_PENDING) -#define AES_INTR_MASK 0x07 - -#define AES_SOURCEA_REG 0x0010 -#define AES_DSTA_REG 0x0014 -#define AES_LENA_REG 0x0018 -#define AES_WRITEKEY0_REG 0x0030 -#define AES_WRITEIV0_REG 0x0040 - -/* A very large counter that is used to gracefully bail out of an - * operation in case of trouble - */ - -#define AES_OP_TIMEOUT 0x50000 - /* Static structures */ static void __iomem * _iobase; @@ -87,9 +56,10 @@ do_crypt(void *src, void *dst, int len, u32 flags) /* Start the operation */ iowrite32(AES_CTRL_START | flags, _iobase + AES_CTRLA_REG); - do + do { status = ioread32(_iobase + AES_INTR_REG); - while(!(status & AES_INTRA_PENDING) && --counter); + cpu_relax(); + } while(!(status & AES_INTRA_PENDING) && --counter); /* Clear the event */ iowrite32((status & 0xFF) | AES_INTRA_PENDING, _iobase + AES_INTR_REG); @@ -101,6 +71,7 @@ geode_aes_crypt(struct geode_aes_op *op) { u32 flags = 0; unsigned long iflags; + int ret; if (op->len == 0) return 0; @@ -129,7 +100,8 @@ geode_aes_crypt(struct geode_aes_op *op) _writefield(AES_WRITEKEY0_REG, op->key); } - do_crypt(op->src, op->dst, op->len, flags); + ret = do_crypt(op->src, op->dst, op->len, flags); + BUG_ON(ret); if (op->mode == AES_MODE_CBC) _readfield(AES_WRITEIV0_REG, op->iv); @@ -141,18 +113,103 @@ geode_aes_crypt(struct geode_aes_op *op) /* CRYPTO-API Functions */ -static int -geode_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int len) +static int geode_setkey_cip(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) { struct geode_aes_op *op = crypto_tfm_ctx(tfm); + unsigned int ret; - if (len != AES_KEY_LENGTH) { + op->keylen = len; + + if (len == AES_KEYSIZE_128) { + memcpy(op->key, key, len); + return 0; + } + + if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { + /* not supported at all */ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; } - memcpy(op->key, key, len); - return 0; + /* + * The requested key size is not supported by HW, do a fallback + */ + op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); + + ret = crypto_cipher_setkey(op->fallback.cip, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key, + unsigned int len) +{ + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + unsigned int ret; + + op->keylen = len; + + if (len == AES_KEYSIZE_128) { + memcpy(op->key, key, len); + return 0; + } + + if (len != AES_KEYSIZE_192 && len != AES_KEYSIZE_256) { + /* not supported at all */ + tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; + } + + /* + * The requested key size is not supported by HW, do a fallback + */ + op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; + op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK); + + ret = crypto_blkcipher_setkey(op->fallback.blk, key, len); + if (ret) { + tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; + tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK); + } + return ret; +} + +static int fallback_blk_dec(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = op->fallback.blk; + + ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; +} +static int fallback_blk_enc(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + unsigned int ret; + struct crypto_blkcipher *tfm; + struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm); + + tfm = desc->tfm; + desc->tfm = op->fallback.blk; + + ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes); + + desc->tfm = tfm; + return ret; } static void @@ -160,8 +217,10 @@ geode_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct geode_aes_op *op = crypto_tfm_ctx(tfm); - if ((out == NULL) || (in == NULL)) + if (unlikely(op->keylen != AES_KEYSIZE_128)) { + crypto_cipher_encrypt_one(op->fallback.cip, out, in); return; + } op->src = (void *) in; op->dst = (void *) out; @@ -179,8 +238,10 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct geode_aes_op *op = crypto_tfm_ctx(tfm); - if ((out == NULL) || (in == NULL)) + if (unlikely(op->keylen != AES_KEYSIZE_128)) { + crypto_cipher_decrypt_one(op->fallback.cip, out, in); return; + } op->src = (void *) in; op->dst = (void *) out; @@ -192,24 +253,50 @@ geode_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) geode_aes_crypt(op); } +static int fallback_init_cip(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + op->fallback.cip = crypto_alloc_cipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(op->fallback.cip)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.blk); + } + + return 0; +} + +static void fallback_exit_cip(struct crypto_tfm *tfm) +{ + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + crypto_free_cipher(op->fallback.cip); + op->fallback.cip = NULL; +} static struct crypto_alg geode_alg = { - .cra_name = "aes", - .cra_driver_name = "geode-aes-128", - .cra_priority = 300, - .cra_alignmask = 15, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_name = "aes", + .cra_driver_name = "geode-aes", + .cra_priority = 300, + .cra_alignmask = 15, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_cip, + .cra_exit = fallback_exit_cip, .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = AES_KEY_LENGTH, - .cia_max_keysize = AES_KEY_LENGTH, - .cia_setkey = geode_setkey, - .cia_encrypt = geode_encrypt, - .cia_decrypt = geode_decrypt + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(geode_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = geode_setkey_cip, + .cia_encrypt = geode_encrypt, + .cia_decrypt = geode_decrypt } } }; @@ -223,8 +310,12 @@ geode_cbc_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_dec(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + op->iv = walk.iv; while((nbytes = walk.nbytes)) { op->src = walk.src.virt.addr, @@ -233,13 +324,9 @@ geode_cbc_decrypt(struct blkcipher_desc *desc, op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); op->dir = AES_DIR_DECRYPT; - memcpy(op->iv, walk.iv, AES_IV_LENGTH); - ret = geode_aes_crypt(op); - memcpy(walk.iv, op->iv, AES_IV_LENGTH); nbytes -= ret; - err = blkcipher_walk_done(desc, &walk, nbytes); } @@ -255,8 +342,12 @@ geode_cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_enc(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); + op->iv = walk.iv; while((nbytes = walk.nbytes)) { op->src = walk.src.virt.addr, @@ -265,8 +356,6 @@ geode_cbc_encrypt(struct blkcipher_desc *desc, op->len = nbytes - (nbytes % AES_MIN_BLOCK_SIZE); op->dir = AES_DIR_ENCRYPT; - memcpy(op->iv, walk.iv, AES_IV_LENGTH); - ret = geode_aes_crypt(op); nbytes -= ret; err = blkcipher_walk_done(desc, &walk, nbytes); @@ -275,22 +364,49 @@ geode_cbc_encrypt(struct blkcipher_desc *desc, return err; } +static int fallback_init_blk(struct crypto_tfm *tfm) +{ + const char *name = tfm->__crt_alg->cra_name; + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + op->fallback.blk = crypto_alloc_blkcipher(name, 0, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK); + + if (IS_ERR(op->fallback.blk)) { + printk(KERN_ERR "Error allocating fallback algo %s\n", name); + return PTR_ERR(op->fallback.blk); + } + + return 0; +} + +static void fallback_exit_blk(struct crypto_tfm *tfm) +{ + struct geode_aes_op *op = crypto_tfm_ctx(tfm); + + crypto_free_blkcipher(op->fallback.blk); + op->fallback.blk = NULL; +} + static struct crypto_alg geode_cbc_alg = { .cra_name = "cbc(aes)", - .cra_driver_name = "cbc-aes-geode-128", + .cra_driver_name = "cbc-aes-geode", .cra_priority = 400, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), .cra_alignmask = 15, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = AES_KEY_LENGTH, - .max_keysize = AES_KEY_LENGTH, - .setkey = geode_setkey, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(geode_cbc_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = geode_setkey_blk, .encrypt = geode_cbc_encrypt, .decrypt = geode_cbc_decrypt, .ivsize = AES_IV_LENGTH, @@ -307,6 +423,9 @@ geode_ecb_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_dec(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -334,6 +453,9 @@ geode_ecb_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err, ret; + if (unlikely(op->keylen != AES_KEYSIZE_128)) + return fallback_blk_enc(desc, dst, src, nbytes); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -353,28 +475,31 @@ geode_ecb_encrypt(struct blkcipher_desc *desc, } static struct crypto_alg geode_ecb_alg = { - .cra_name = "ecb(aes)", - .cra_driver_name = "ecb-aes-geode-128", + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-geode", .cra_priority = 400, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, + .cra_init = fallback_init_blk, + .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, .cra_ctxsize = sizeof(struct geode_aes_op), .cra_alignmask = 15, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = AES_KEY_LENGTH, - .max_keysize = AES_KEY_LENGTH, - .setkey = geode_setkey, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(geode_ecb_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = geode_setkey_blk, .encrypt = geode_ecb_encrypt, .decrypt = geode_ecb_decrypt, } } }; -static void +static void __devexit geode_aes_remove(struct pci_dev *dev) { crypto_unregister_alg(&geode_alg); @@ -389,7 +514,7 @@ geode_aes_remove(struct pci_dev *dev) } -static int +static int __devinit geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) { int ret; @@ -397,7 +522,7 @@ geode_aes_probe(struct pci_dev *dev, const struct pci_device_id *id) if ((ret = pci_enable_device(dev))) return ret; - if ((ret = pci_request_regions(dev, "geode-aes-128"))) + if ((ret = pci_request_regions(dev, "geode-aes"))) goto eenable; _iobase = pci_iomap(dev, 0, 0); @@ -472,7 +597,6 @@ geode_aes_exit(void) MODULE_AUTHOR("Advanced Micro Devices, Inc."); MODULE_DESCRIPTION("Geode LX Hardware AES driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("aes"); module_init(geode_aes_init); module_exit(geode_aes_exit); diff --git a/drivers/crypto/geode-aes.h b/drivers/crypto/geode-aes.h index f47968671ae7..f1855b50da48 100644 --- a/drivers/crypto/geode-aes.h +++ b/drivers/crypto/geode-aes.h @@ -9,9 +9,9 @@ #ifndef _GEODE_AES_H_ #define _GEODE_AES_H_ -#define AES_KEY_LENGTH 16 +/* driver logic flags */ #define AES_IV_LENGTH 16 - +#define AES_KEY_LENGTH 16 #define AES_MIN_BLOCK_SIZE 16 #define AES_MODE_ECB 0 @@ -22,6 +22,38 @@ #define AES_FLAGS_HIDDENKEY (1 << 0) +/* Register definitions */ + +#define AES_CTRLA_REG 0x0000 + +#define AES_CTRL_START 0x01 +#define AES_CTRL_DECRYPT 0x00 +#define AES_CTRL_ENCRYPT 0x02 +#define AES_CTRL_WRKEY 0x04 +#define AES_CTRL_DCA 0x08 +#define AES_CTRL_SCA 0x10 +#define AES_CTRL_CBC 0x20 + +#define AES_INTR_REG 0x0008 + +#define AES_INTRA_PENDING (1 << 16) +#define AES_INTRB_PENDING (1 << 17) + +#define AES_INTR_PENDING (AES_INTRA_PENDING | AES_INTRB_PENDING) +#define AES_INTR_MASK 0x07 + +#define AES_SOURCEA_REG 0x0010 +#define AES_DSTA_REG 0x0014 +#define AES_LENA_REG 0x0018 +#define AES_WRITEKEY0_REG 0x0030 +#define AES_WRITEIV0_REG 0x0040 + +/* A very large counter that is used to gracefully bail out of an + * operation in case of trouble + */ + +#define AES_OP_TIMEOUT 0x50000 + struct geode_aes_op { void *src; @@ -33,7 +65,13 @@ struct geode_aes_op { int len; u8 key[AES_KEY_LENGTH]; - u8 iv[AES_IV_LENGTH]; + u8 *iv; + + union { + struct crypto_blkcipher *blk; + struct crypto_cipher *cip; + } fallback; + u32 keylen; }; #endif diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c new file mode 100644 index 000000000000..dfbf24c4033c --- /dev/null +++ b/drivers/crypto/hifn_795x.c @@ -0,0 +1,2838 @@ +/* + * 2007+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru> + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mod_devicetable.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/dma-mapping.h> +#include <linux/scatterlist.h> +#include <linux/highmem.h> +#include <linux/interrupt.h> +#include <linux/crypto.h> +#include <linux/hw_random.h> +#include <linux/ktime.h> + +#include <crypto/algapi.h> +#include <crypto/des.h> + +#include <asm/kmap_types.h> + +#undef dprintk + +#define HIFN_TEST +//#define HIFN_DEBUG + +#ifdef HIFN_DEBUG +#define dprintk(f, a...) printk(f, ##a) +#else +#define dprintk(f, a...) do {} while (0) +#endif + +static char hifn_pll_ref[sizeof("extNNN")] = "ext"; +module_param_string(hifn_pll_ref, hifn_pll_ref, sizeof(hifn_pll_ref), 0444); +MODULE_PARM_DESC(hifn_pll_ref, + "PLL reference clock (pci[freq] or ext[freq], default ext)"); + +static atomic_t hifn_dev_number; + +#define ACRYPTO_OP_DECRYPT 0 +#define ACRYPTO_OP_ENCRYPT 1 +#define ACRYPTO_OP_HMAC 2 +#define ACRYPTO_OP_RNG 3 + +#define ACRYPTO_MODE_ECB 0 +#define ACRYPTO_MODE_CBC 1 +#define ACRYPTO_MODE_CFB 2 +#define ACRYPTO_MODE_OFB 3 + +#define ACRYPTO_TYPE_AES_128 0 +#define ACRYPTO_TYPE_AES_192 1 +#define ACRYPTO_TYPE_AES_256 2 +#define ACRYPTO_TYPE_3DES 3 +#define ACRYPTO_TYPE_DES 4 + +#define PCI_VENDOR_ID_HIFN 0x13A3 +#define PCI_DEVICE_ID_HIFN_7955 0x0020 +#define PCI_DEVICE_ID_HIFN_7956 0x001d + +/* I/O region sizes */ + +#define HIFN_BAR0_SIZE 0x1000 +#define HIFN_BAR1_SIZE 0x2000 +#define HIFN_BAR2_SIZE 0x8000 + +/* DMA registres */ + +#define HIFN_DMA_CRA 0x0C /* DMA Command Ring Address */ +#define HIFN_DMA_SDRA 0x1C /* DMA Source Data Ring Address */ +#define HIFN_DMA_RRA 0x2C /* DMA Result Ring Address */ +#define HIFN_DMA_DDRA 0x3C /* DMA Destination Data Ring Address */ +#define HIFN_DMA_STCTL 0x40 /* DMA Status and Control */ +#define HIFN_DMA_INTREN 0x44 /* DMA Interrupt Enable */ +#define HIFN_DMA_CFG1 0x48 /* DMA Configuration #1 */ +#define HIFN_DMA_CFG2 0x6C /* DMA Configuration #2 */ +#define HIFN_CHIP_ID 0x98 /* Chip ID */ + +/* + * Processing Unit Registers (offset from BASEREG0) + */ +#define HIFN_0_PUDATA 0x00 /* Processing Unit Data */ +#define HIFN_0_PUCTRL 0x04 /* Processing Unit Control */ +#define HIFN_0_PUISR 0x08 /* Processing Unit Interrupt Status */ +#define HIFN_0_PUCNFG 0x0c /* Processing Unit Configuration */ +#define HIFN_0_PUIER 0x10 /* Processing Unit Interrupt Enable */ +#define HIFN_0_PUSTAT 0x14 /* Processing Unit Status/Chip ID */ +#define HIFN_0_FIFOSTAT 0x18 /* FIFO Status */ +#define HIFN_0_FIFOCNFG 0x1c /* FIFO Configuration */ +#define HIFN_0_SPACESIZE 0x20 /* Register space size */ + +/* Processing Unit Control Register (HIFN_0_PUCTRL) */ +#define HIFN_PUCTRL_CLRSRCFIFO 0x0010 /* clear source fifo */ +#define HIFN_PUCTRL_STOP 0x0008 /* stop pu */ +#define HIFN_PUCTRL_LOCKRAM 0x0004 /* lock ram */ +#define HIFN_PUCTRL_DMAENA 0x0002 /* enable dma */ +#define HIFN_PUCTRL_RESET 0x0001 /* Reset processing unit */ + +/* Processing Unit Interrupt Status Register (HIFN_0_PUISR) */ +#define HIFN_PUISR_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUISR_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUISR_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUISR_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUISR_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUISR_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUISR_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUISR_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUISR_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUISR_DSTRESULT 0x0004 /* Destination result interrupt */ + +/* Processing Unit Configuration Register (HIFN_0_PUCNFG) */ +#define HIFN_PUCNFG_DRAMMASK 0xe000 /* DRAM size mask */ +#define HIFN_PUCNFG_DSZ_256K 0x0000 /* 256k dram */ +#define HIFN_PUCNFG_DSZ_512K 0x2000 /* 512k dram */ +#define HIFN_PUCNFG_DSZ_1M 0x4000 /* 1m dram */ +#define HIFN_PUCNFG_DSZ_2M 0x6000 /* 2m dram */ +#define HIFN_PUCNFG_DSZ_4M 0x8000 /* 4m dram */ +#define HIFN_PUCNFG_DSZ_8M 0xa000 /* 8m dram */ +#define HIFN_PUNCFG_DSZ_16M 0xc000 /* 16m dram */ +#define HIFN_PUCNFG_DSZ_32M 0xe000 /* 32m dram */ +#define HIFN_PUCNFG_DRAMREFRESH 0x1800 /* DRAM refresh rate mask */ +#define HIFN_PUCNFG_DRFR_512 0x0000 /* 512 divisor of ECLK */ +#define HIFN_PUCNFG_DRFR_256 0x0800 /* 256 divisor of ECLK */ +#define HIFN_PUCNFG_DRFR_128 0x1000 /* 128 divisor of ECLK */ +#define HIFN_PUCNFG_TCALLPHASES 0x0200 /* your guess is as good as mine... */ +#define HIFN_PUCNFG_TCDRVTOTEM 0x0100 /* your guess is as good as mine... */ +#define HIFN_PUCNFG_BIGENDIAN 0x0080 /* DMA big endian mode */ +#define HIFN_PUCNFG_BUS32 0x0040 /* Bus width 32bits */ +#define HIFN_PUCNFG_BUS16 0x0000 /* Bus width 16 bits */ +#define HIFN_PUCNFG_CHIPID 0x0020 /* Allow chipid from PUSTAT */ +#define HIFN_PUCNFG_DRAM 0x0010 /* Context RAM is DRAM */ +#define HIFN_PUCNFG_SRAM 0x0000 /* Context RAM is SRAM */ +#define HIFN_PUCNFG_COMPSING 0x0004 /* Enable single compression context */ +#define HIFN_PUCNFG_ENCCNFG 0x0002 /* Encryption configuration */ + +/* Processing Unit Interrupt Enable Register (HIFN_0_PUIER) */ +#define HIFN_PUIER_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUIER_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUIER_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUIER_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUIER_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUIER_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUIER_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUIER_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUIER_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUIER_DSTRESULT 0x0004 /* Destination result interrupt */ + +/* Processing Unit Status Register/Chip ID (HIFN_0_PUSTAT) */ +#define HIFN_PUSTAT_CMDINVAL 0x8000 /* Invalid command interrupt */ +#define HIFN_PUSTAT_DATAERR 0x4000 /* Data error interrupt */ +#define HIFN_PUSTAT_SRCFIFO 0x2000 /* Source FIFO ready interrupt */ +#define HIFN_PUSTAT_DSTFIFO 0x1000 /* Destination FIFO ready interrupt */ +#define HIFN_PUSTAT_DSTOVER 0x0200 /* Destination overrun interrupt */ +#define HIFN_PUSTAT_SRCCMD 0x0080 /* Source command interrupt */ +#define HIFN_PUSTAT_SRCCTX 0x0040 /* Source context interrupt */ +#define HIFN_PUSTAT_SRCDATA 0x0020 /* Source data interrupt */ +#define HIFN_PUSTAT_DSTDATA 0x0010 /* Destination data interrupt */ +#define HIFN_PUSTAT_DSTRESULT 0x0004 /* Destination result interrupt */ +#define HIFN_PUSTAT_CHIPREV 0x00ff /* Chip revision mask */ +#define HIFN_PUSTAT_CHIPENA 0xff00 /* Chip enabled mask */ +#define HIFN_PUSTAT_ENA_2 0x1100 /* Level 2 enabled */ +#define HIFN_PUSTAT_ENA_1 0x1000 /* Level 1 enabled */ +#define HIFN_PUSTAT_ENA_0 0x3000 /* Level 0 enabled */ +#define HIFN_PUSTAT_REV_2 0x0020 /* 7751 PT6/2 */ +#define HIFN_PUSTAT_REV_3 0x0030 /* 7751 PT6/3 */ + +/* FIFO Status Register (HIFN_0_FIFOSTAT) */ +#define HIFN_FIFOSTAT_SRC 0x7f00 /* Source FIFO available */ +#define HIFN_FIFOSTAT_DST 0x007f /* Destination FIFO available */ + +/* FIFO Configuration Register (HIFN_0_FIFOCNFG) */ +#define HIFN_FIFOCNFG_THRESHOLD 0x0400 /* must be written as 1 */ + +/* + * DMA Interface Registers (offset from BASEREG1) + */ +#define HIFN_1_DMA_CRAR 0x0c /* DMA Command Ring Address */ +#define HIFN_1_DMA_SRAR 0x1c /* DMA Source Ring Address */ +#define HIFN_1_DMA_RRAR 0x2c /* DMA Result Ring Address */ +#define HIFN_1_DMA_DRAR 0x3c /* DMA Destination Ring Address */ +#define HIFN_1_DMA_CSR 0x40 /* DMA Status and Control */ +#define HIFN_1_DMA_IER 0x44 /* DMA Interrupt Enable */ +#define HIFN_1_DMA_CNFG 0x48 /* DMA Configuration */ +#define HIFN_1_PLL 0x4c /* 795x: PLL config */ +#define HIFN_1_7811_RNGENA 0x60 /* 7811: rng enable */ +#define HIFN_1_7811_RNGCFG 0x64 /* 7811: rng config */ +#define HIFN_1_7811_RNGDAT 0x68 /* 7811: rng data */ +#define HIFN_1_7811_RNGSTS 0x6c /* 7811: rng status */ +#define HIFN_1_7811_MIPSRST 0x94 /* 7811: MIPS reset */ +#define HIFN_1_REVID 0x98 /* Revision ID */ +#define HIFN_1_UNLOCK_SECRET1 0xf4 +#define HIFN_1_UNLOCK_SECRET2 0xfc +#define HIFN_1_PUB_RESET 0x204 /* Public/RNG Reset */ +#define HIFN_1_PUB_BASE 0x300 /* Public Base Address */ +#define HIFN_1_PUB_OPLEN 0x304 /* Public Operand Length */ +#define HIFN_1_PUB_OP 0x308 /* Public Operand */ +#define HIFN_1_PUB_STATUS 0x30c /* Public Status */ +#define HIFN_1_PUB_IEN 0x310 /* Public Interrupt enable */ +#define HIFN_1_RNG_CONFIG 0x314 /* RNG config */ +#define HIFN_1_RNG_DATA 0x318 /* RNG data */ +#define HIFN_1_PUB_MEM 0x400 /* start of Public key memory */ +#define HIFN_1_PUB_MEMEND 0xbff /* end of Public key memory */ + +/* DMA Status and Control Register (HIFN_1_DMA_CSR) */ +#define HIFN_DMACSR_D_CTRLMASK 0xc0000000 /* Destinition Ring Control */ +#define HIFN_DMACSR_D_CTRL_NOP 0x00000000 /* Dest. Control: no-op */ +#define HIFN_DMACSR_D_CTRL_DIS 0x40000000 /* Dest. Control: disable */ +#define HIFN_DMACSR_D_CTRL_ENA 0x80000000 /* Dest. Control: enable */ +#define HIFN_DMACSR_D_ABORT 0x20000000 /* Destinition Ring PCIAbort */ +#define HIFN_DMACSR_D_DONE 0x10000000 /* Destinition Ring Done */ +#define HIFN_DMACSR_D_LAST 0x08000000 /* Destinition Ring Last */ +#define HIFN_DMACSR_D_WAIT 0x04000000 /* Destinition Ring Waiting */ +#define HIFN_DMACSR_D_OVER 0x02000000 /* Destinition Ring Overflow */ +#define HIFN_DMACSR_R_CTRL 0x00c00000 /* Result Ring Control */ +#define HIFN_DMACSR_R_CTRL_NOP 0x00000000 /* Result Control: no-op */ +#define HIFN_DMACSR_R_CTRL_DIS 0x00400000 /* Result Control: disable */ +#define HIFN_DMACSR_R_CTRL_ENA 0x00800000 /* Result Control: enable */ +#define HIFN_DMACSR_R_ABORT 0x00200000 /* Result Ring PCI Abort */ +#define HIFN_DMACSR_R_DONE 0x00100000 /* Result Ring Done */ +#define HIFN_DMACSR_R_LAST 0x00080000 /* Result Ring Last */ +#define HIFN_DMACSR_R_WAIT 0x00040000 /* Result Ring Waiting */ +#define HIFN_DMACSR_R_OVER 0x00020000 /* Result Ring Overflow */ +#define HIFN_DMACSR_S_CTRL 0x0000c000 /* Source Ring Control */ +#define HIFN_DMACSR_S_CTRL_NOP 0x00000000 /* Source Control: no-op */ +#define HIFN_DMACSR_S_CTRL_DIS 0x00004000 /* Source Control: disable */ +#define HIFN_DMACSR_S_CTRL_ENA 0x00008000 /* Source Control: enable */ +#define HIFN_DMACSR_S_ABORT 0x00002000 /* Source Ring PCI Abort */ +#define HIFN_DMACSR_S_DONE 0x00001000 /* Source Ring Done */ +#define HIFN_DMACSR_S_LAST 0x00000800 /* Source Ring Last */ +#define HIFN_DMACSR_S_WAIT 0x00000400 /* Source Ring Waiting */ +#define HIFN_DMACSR_ILLW 0x00000200 /* Illegal write (7811 only) */ +#define HIFN_DMACSR_ILLR 0x00000100 /* Illegal read (7811 only) */ +#define HIFN_DMACSR_C_CTRL 0x000000c0 /* Command Ring Control */ +#define HIFN_DMACSR_C_CTRL_NOP 0x00000000 /* Command Control: no-op */ +#define HIFN_DMACSR_C_CTRL_DIS 0x00000040 /* Command Control: disable */ +#define HIFN_DMACSR_C_CTRL_ENA 0x00000080 /* Command Control: enable */ +#define HIFN_DMACSR_C_ABORT 0x00000020 /* Command Ring PCI Abort */ +#define HIFN_DMACSR_C_DONE 0x00000010 /* Command Ring Done */ +#define HIFN_DMACSR_C_LAST 0x00000008 /* Command Ring Last */ +#define HIFN_DMACSR_C_WAIT 0x00000004 /* Command Ring Waiting */ +#define HIFN_DMACSR_PUBDONE 0x00000002 /* Public op done (7951 only) */ +#define HIFN_DMACSR_ENGINE 0x00000001 /* Command Ring Engine IRQ */ + +/* DMA Interrupt Enable Register (HIFN_1_DMA_IER) */ +#define HIFN_DMAIER_D_ABORT 0x20000000 /* Destination Ring PCIAbort */ +#define HIFN_DMAIER_D_DONE 0x10000000 /* Destination Ring Done */ +#define HIFN_DMAIER_D_LAST 0x08000000 /* Destination Ring Last */ +#define HIFN_DMAIER_D_WAIT 0x04000000 /* Destination Ring Waiting */ +#define HIFN_DMAIER_D_OVER 0x02000000 /* Destination Ring Overflow */ +#define HIFN_DMAIER_R_ABORT 0x00200000 /* Result Ring PCI Abort */ +#define HIFN_DMAIER_R_DONE 0x00100000 /* Result Ring Done */ +#define HIFN_DMAIER_R_LAST 0x00080000 /* Result Ring Last */ +#define HIFN_DMAIER_R_WAIT 0x00040000 /* Result Ring Waiting */ +#define HIFN_DMAIER_R_OVER 0x00020000 /* Result Ring Overflow */ +#define HIFN_DMAIER_S_ABORT 0x00002000 /* Source Ring PCI Abort */ +#define HIFN_DMAIER_S_DONE 0x00001000 /* Source Ring Done */ +#define HIFN_DMAIER_S_LAST 0x00000800 /* Source Ring Last */ +#define HIFN_DMAIER_S_WAIT 0x00000400 /* Source Ring Waiting */ +#define HIFN_DMAIER_ILLW 0x00000200 /* Illegal write (7811 only) */ +#define HIFN_DMAIER_ILLR 0x00000100 /* Illegal read (7811 only) */ +#define HIFN_DMAIER_C_ABORT 0x00000020 /* Command Ring PCI Abort */ +#define HIFN_DMAIER_C_DONE 0x00000010 /* Command Ring Done */ +#define HIFN_DMAIER_C_LAST 0x00000008 /* Command Ring Last */ +#define HIFN_DMAIER_C_WAIT 0x00000004 /* Command Ring Waiting */ +#define HIFN_DMAIER_PUBDONE 0x00000002 /* public op done (7951 only) */ +#define HIFN_DMAIER_ENGINE 0x00000001 /* Engine IRQ */ + +/* DMA Configuration Register (HIFN_1_DMA_CNFG) */ +#define HIFN_DMACNFG_BIGENDIAN 0x10000000 /* big endian mode */ +#define HIFN_DMACNFG_POLLFREQ 0x00ff0000 /* Poll frequency mask */ +#define HIFN_DMACNFG_UNLOCK 0x00000800 +#define HIFN_DMACNFG_POLLINVAL 0x00000700 /* Invalid Poll Scalar */ +#define HIFN_DMACNFG_LAST 0x00000010 /* Host control LAST bit */ +#define HIFN_DMACNFG_MODE 0x00000004 /* DMA mode */ +#define HIFN_DMACNFG_DMARESET 0x00000002 /* DMA Reset # */ +#define HIFN_DMACNFG_MSTRESET 0x00000001 /* Master Reset # */ + +/* PLL configuration register */ +#define HIFN_PLL_REF_CLK_HBI 0x00000000 /* HBI reference clock */ +#define HIFN_PLL_REF_CLK_PLL 0x00000001 /* PLL reference clock */ +#define HIFN_PLL_BP 0x00000002 /* Reference clock bypass */ +#define HIFN_PLL_PK_CLK_HBI 0x00000000 /* PK engine HBI clock */ +#define HIFN_PLL_PK_CLK_PLL 0x00000008 /* PK engine PLL clock */ +#define HIFN_PLL_PE_CLK_HBI 0x00000000 /* PE engine HBI clock */ +#define HIFN_PLL_PE_CLK_PLL 0x00000010 /* PE engine PLL clock */ +#define HIFN_PLL_RESERVED_1 0x00000400 /* Reserved bit, must be 1 */ +#define HIFN_PLL_ND_SHIFT 11 /* Clock multiplier shift */ +#define HIFN_PLL_ND_MULT_2 0x00000000 /* PLL clock multiplier 2 */ +#define HIFN_PLL_ND_MULT_4 0x00000800 /* PLL clock multiplier 4 */ +#define HIFN_PLL_ND_MULT_6 0x00001000 /* PLL clock multiplier 6 */ +#define HIFN_PLL_ND_MULT_8 0x00001800 /* PLL clock multiplier 8 */ +#define HIFN_PLL_ND_MULT_10 0x00002000 /* PLL clock multiplier 10 */ +#define HIFN_PLL_ND_MULT_12 0x00002800 /* PLL clock multiplier 12 */ +#define HIFN_PLL_IS_1_8 0x00000000 /* charge pump (mult. 1-8) */ +#define HIFN_PLL_IS_9_12 0x00010000 /* charge pump (mult. 9-12) */ + +#define HIFN_PLL_FCK_MAX 266 /* Maximum PLL frequency */ + +/* Public key reset register (HIFN_1_PUB_RESET) */ +#define HIFN_PUBRST_RESET 0x00000001 /* reset public/rng unit */ + +/* Public base address register (HIFN_1_PUB_BASE) */ +#define HIFN_PUBBASE_ADDR 0x00003fff /* base address */ + +/* Public operand length register (HIFN_1_PUB_OPLEN) */ +#define HIFN_PUBOPLEN_MOD_M 0x0000007f /* modulus length mask */ +#define HIFN_PUBOPLEN_MOD_S 0 /* modulus length shift */ +#define HIFN_PUBOPLEN_EXP_M 0x0003ff80 /* exponent length mask */ +#define HIFN_PUBOPLEN_EXP_S 7 /* exponent lenght shift */ +#define HIFN_PUBOPLEN_RED_M 0x003c0000 /* reducend length mask */ +#define HIFN_PUBOPLEN_RED_S 18 /* reducend length shift */ + +/* Public operation register (HIFN_1_PUB_OP) */ +#define HIFN_PUBOP_AOFFSET_M 0x0000007f /* A offset mask */ +#define HIFN_PUBOP_AOFFSET_S 0 /* A offset shift */ +#define HIFN_PUBOP_BOFFSET_M 0x00000f80 /* B offset mask */ +#define HIFN_PUBOP_BOFFSET_S 7 /* B offset shift */ +#define HIFN_PUBOP_MOFFSET_M 0x0003f000 /* M offset mask */ +#define HIFN_PUBOP_MOFFSET_S 12 /* M offset shift */ +#define HIFN_PUBOP_OP_MASK 0x003c0000 /* Opcode: */ +#define HIFN_PUBOP_OP_NOP 0x00000000 /* NOP */ +#define HIFN_PUBOP_OP_ADD 0x00040000 /* ADD */ +#define HIFN_PUBOP_OP_ADDC 0x00080000 /* ADD w/carry */ +#define HIFN_PUBOP_OP_SUB 0x000c0000 /* SUB */ +#define HIFN_PUBOP_OP_SUBC 0x00100000 /* SUB w/carry */ +#define HIFN_PUBOP_OP_MODADD 0x00140000 /* Modular ADD */ +#define HIFN_PUBOP_OP_MODSUB 0x00180000 /* Modular SUB */ +#define HIFN_PUBOP_OP_INCA 0x001c0000 /* INC A */ +#define HIFN_PUBOP_OP_DECA 0x00200000 /* DEC A */ +#define HIFN_PUBOP_OP_MULT 0x00240000 /* MULT */ +#define HIFN_PUBOP_OP_MODMULT 0x00280000 /* Modular MULT */ +#define HIFN_PUBOP_OP_MODRED 0x002c0000 /* Modular RED */ +#define HIFN_PUBOP_OP_MODEXP 0x00300000 /* Modular EXP */ + +/* Public status register (HIFN_1_PUB_STATUS) */ +#define HIFN_PUBSTS_DONE 0x00000001 /* operation done */ +#define HIFN_PUBSTS_CARRY 0x00000002 /* carry */ + +/* Public interrupt enable register (HIFN_1_PUB_IEN) */ +#define HIFN_PUBIEN_DONE 0x00000001 /* operation done interrupt */ + +/* Random number generator config register (HIFN_1_RNG_CONFIG) */ +#define HIFN_RNGCFG_ENA 0x00000001 /* enable rng */ + +#define HIFN_NAMESIZE 32 +#define HIFN_MAX_RESULT_ORDER 5 + +#define HIFN_D_CMD_RSIZE 24*4 +#define HIFN_D_SRC_RSIZE 80*4 +#define HIFN_D_DST_RSIZE 80*4 +#define HIFN_D_RES_RSIZE 24*4 + +#define HIFN_QUEUE_LENGTH HIFN_D_CMD_RSIZE-5 + +#define AES_MIN_KEY_SIZE 16 +#define AES_MAX_KEY_SIZE 32 + +#define HIFN_DES_KEY_LENGTH 8 +#define HIFN_3DES_KEY_LENGTH 24 +#define HIFN_MAX_CRYPT_KEY_LENGTH AES_MAX_KEY_SIZE +#define HIFN_IV_LENGTH 8 +#define HIFN_AES_IV_LENGTH 16 +#define HIFN_MAX_IV_LENGTH HIFN_AES_IV_LENGTH + +#define HIFN_MAC_KEY_LENGTH 64 +#define HIFN_MD5_LENGTH 16 +#define HIFN_SHA1_LENGTH 20 +#define HIFN_MAC_TRUNC_LENGTH 12 + +#define HIFN_MAX_COMMAND (8 + 8 + 8 + 64 + 260) +#define HIFN_MAX_RESULT (8 + 4 + 4 + 20 + 4) +#define HIFN_USED_RESULT 12 + +struct hifn_desc +{ + volatile u32 l; + volatile u32 p; +}; + +struct hifn_dma { + struct hifn_desc cmdr[HIFN_D_CMD_RSIZE+1]; + struct hifn_desc srcr[HIFN_D_SRC_RSIZE+1]; + struct hifn_desc dstr[HIFN_D_DST_RSIZE+1]; + struct hifn_desc resr[HIFN_D_RES_RSIZE+1]; + + u8 command_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_COMMAND]; + u8 result_bufs[HIFN_D_CMD_RSIZE][HIFN_MAX_RESULT]; + + u64 test_src, test_dst; + + /* + * Our current positions for insertion and removal from the descriptor + * rings. + */ + volatile int cmdi, srci, dsti, resi; + volatile int cmdu, srcu, dstu, resu; + int cmdk, srck, dstk, resk; +}; + +#define HIFN_FLAG_CMD_BUSY (1<<0) +#define HIFN_FLAG_SRC_BUSY (1<<1) +#define HIFN_FLAG_DST_BUSY (1<<2) +#define HIFN_FLAG_RES_BUSY (1<<3) +#define HIFN_FLAG_OLD_KEY (1<<4) + +#define HIFN_DEFAULT_ACTIVE_NUM 5 + +struct hifn_device +{ + char name[HIFN_NAMESIZE]; + + int irq; + + struct pci_dev *pdev; + void __iomem *bar[3]; + + unsigned long result_mem; + dma_addr_t dst; + + void *desc_virt; + dma_addr_t desc_dma; + + u32 dmareg; + + void *sa[HIFN_D_RES_RSIZE]; + + spinlock_t lock; + + void *priv; + + u32 flags; + int active, started; + struct delayed_work work; + unsigned long reset; + unsigned long success; + unsigned long prev_success; + + u8 snum; + + struct tasklet_struct tasklet; + + struct crypto_queue queue; + struct list_head alg_list; + + unsigned int pk_clk_freq; + +#ifdef CRYPTO_DEV_HIFN_795X_RNG + unsigned int rng_wait_time; + ktime_t rngtime; + struct hwrng rng; +#endif +}; + +#define HIFN_D_LENGTH 0x0000ffff +#define HIFN_D_NOINVALID 0x01000000 +#define HIFN_D_MASKDONEIRQ 0x02000000 +#define HIFN_D_DESTOVER 0x04000000 +#define HIFN_D_OVER 0x08000000 +#define HIFN_D_LAST 0x20000000 +#define HIFN_D_JUMP 0x40000000 +#define HIFN_D_VALID 0x80000000 + +struct hifn_base_command +{ + volatile u16 masks; + volatile u16 session_num; + volatile u16 total_source_count; + volatile u16 total_dest_count; +}; + +#define HIFN_BASE_CMD_COMP 0x0100 /* enable compression engine */ +#define HIFN_BASE_CMD_PAD 0x0200 /* enable padding engine */ +#define HIFN_BASE_CMD_MAC 0x0400 /* enable MAC engine */ +#define HIFN_BASE_CMD_CRYPT 0x0800 /* enable crypt engine */ +#define HIFN_BASE_CMD_DECODE 0x2000 +#define HIFN_BASE_CMD_SRCLEN_M 0xc000 +#define HIFN_BASE_CMD_SRCLEN_S 14 +#define HIFN_BASE_CMD_DSTLEN_M 0x3000 +#define HIFN_BASE_CMD_DSTLEN_S 12 +#define HIFN_BASE_CMD_LENMASK_HI 0x30000 +#define HIFN_BASE_CMD_LENMASK_LO 0x0ffff + +/* + * Structure to help build up the command data structure. + */ +struct hifn_crypt_command +{ + volatile u16 masks; + volatile u16 header_skip; + volatile u16 source_count; + volatile u16 reserved; +}; + +#define HIFN_CRYPT_CMD_ALG_MASK 0x0003 /* algorithm: */ +#define HIFN_CRYPT_CMD_ALG_DES 0x0000 /* DES */ +#define HIFN_CRYPT_CMD_ALG_3DES 0x0001 /* 3DES */ +#define HIFN_CRYPT_CMD_ALG_RC4 0x0002 /* RC4 */ +#define HIFN_CRYPT_CMD_ALG_AES 0x0003 /* AES */ +#define HIFN_CRYPT_CMD_MODE_MASK 0x0018 /* Encrypt mode: */ +#define HIFN_CRYPT_CMD_MODE_ECB 0x0000 /* ECB */ +#define HIFN_CRYPT_CMD_MODE_CBC 0x0008 /* CBC */ +#define HIFN_CRYPT_CMD_MODE_CFB 0x0010 /* CFB */ +#define HIFN_CRYPT_CMD_MODE_OFB 0x0018 /* OFB */ +#define HIFN_CRYPT_CMD_CLR_CTX 0x0040 /* clear context */ +#define HIFN_CRYPT_CMD_KSZ_MASK 0x0600 /* AES key size: */ +#define HIFN_CRYPT_CMD_KSZ_128 0x0000 /* 128 bit */ +#define HIFN_CRYPT_CMD_KSZ_192 0x0200 /* 192 bit */ +#define HIFN_CRYPT_CMD_KSZ_256 0x0400 /* 256 bit */ +#define HIFN_CRYPT_CMD_NEW_KEY 0x0800 /* expect new key */ +#define HIFN_CRYPT_CMD_NEW_IV 0x1000 /* expect new iv */ +#define HIFN_CRYPT_CMD_SRCLEN_M 0xc000 +#define HIFN_CRYPT_CMD_SRCLEN_S 14 + +/* + * Structure to help build up the command data structure. + */ +struct hifn_mac_command +{ + volatile u16 masks; + volatile u16 header_skip; + volatile u16 source_count; + volatile u16 reserved; +}; + +#define HIFN_MAC_CMD_ALG_MASK 0x0001 +#define HIFN_MAC_CMD_ALG_SHA1 0x0000 +#define HIFN_MAC_CMD_ALG_MD5 0x0001 +#define HIFN_MAC_CMD_MODE_MASK 0x000c +#define HIFN_MAC_CMD_MODE_HMAC 0x0000 +#define HIFN_MAC_CMD_MODE_SSL_MAC 0x0004 +#define HIFN_MAC_CMD_MODE_HASH 0x0008 +#define HIFN_MAC_CMD_MODE_FULL 0x0004 +#define HIFN_MAC_CMD_TRUNC 0x0010 +#define HIFN_MAC_CMD_RESULT 0x0020 +#define HIFN_MAC_CMD_APPEND 0x0040 +#define HIFN_MAC_CMD_SRCLEN_M 0xc000 +#define HIFN_MAC_CMD_SRCLEN_S 14 + +/* + * MAC POS IPsec initiates authentication after encryption on encodes + * and before decryption on decodes. + */ +#define HIFN_MAC_CMD_POS_IPSEC 0x0200 +#define HIFN_MAC_CMD_NEW_KEY 0x0800 + +struct hifn_comp_command +{ + volatile u16 masks; + volatile u16 header_skip; + volatile u16 source_count; + volatile u16 reserved; +}; + +#define HIFN_COMP_CMD_SRCLEN_M 0xc000 +#define HIFN_COMP_CMD_SRCLEN_S 14 +#define HIFN_COMP_CMD_ONE 0x0100 /* must be one */ +#define HIFN_COMP_CMD_CLEARHIST 0x0010 /* clear history */ +#define HIFN_COMP_CMD_UPDATEHIST 0x0008 /* update history */ +#define HIFN_COMP_CMD_LZS_STRIP0 0x0004 /* LZS: strip zero */ +#define HIFN_COMP_CMD_MPPC_RESTART 0x0004 /* MPPC: restart */ +#define HIFN_COMP_CMD_ALG_MASK 0x0001 /* compression mode: */ +#define HIFN_COMP_CMD_ALG_MPPC 0x0001 /* MPPC */ +#define HIFN_COMP_CMD_ALG_LZS 0x0000 /* LZS */ + +struct hifn_base_result +{ + volatile u16 flags; + volatile u16 session; + volatile u16 src_cnt; /* 15:0 of source count */ + volatile u16 dst_cnt; /* 15:0 of dest count */ +}; + +#define HIFN_BASE_RES_DSTOVERRUN 0x0200 /* destination overrun */ +#define HIFN_BASE_RES_SRCLEN_M 0xc000 /* 17:16 of source count */ +#define HIFN_BASE_RES_SRCLEN_S 14 +#define HIFN_BASE_RES_DSTLEN_M 0x3000 /* 17:16 of dest count */ +#define HIFN_BASE_RES_DSTLEN_S 12 + +struct hifn_comp_result +{ + volatile u16 flags; + volatile u16 crc; +}; + +#define HIFN_COMP_RES_LCB_M 0xff00 /* longitudinal check byte */ +#define HIFN_COMP_RES_LCB_S 8 +#define HIFN_COMP_RES_RESTART 0x0004 /* MPPC: restart */ +#define HIFN_COMP_RES_ENDMARKER 0x0002 /* LZS: end marker seen */ +#define HIFN_COMP_RES_SRC_NOTZERO 0x0001 /* source expired */ + +struct hifn_mac_result +{ + volatile u16 flags; + volatile u16 reserved; + /* followed by 0, 6, 8, or 10 u16's of the MAC, then crypt */ +}; + +#define HIFN_MAC_RES_MISCOMPARE 0x0002 /* compare failed */ +#define HIFN_MAC_RES_SRC_NOTZERO 0x0001 /* source expired */ + +struct hifn_crypt_result +{ + volatile u16 flags; + volatile u16 reserved; +}; + +#define HIFN_CRYPT_RES_SRC_NOTZERO 0x0001 /* source expired */ + +#ifndef HIFN_POLL_FREQUENCY +#define HIFN_POLL_FREQUENCY 0x1 +#endif + +#ifndef HIFN_POLL_SCALAR +#define HIFN_POLL_SCALAR 0x0 +#endif + +#define HIFN_MAX_SEGLEN 0xffff /* maximum dma segment len */ +#define HIFN_MAX_DMALEN 0x3ffff /* maximum dma length */ + +struct hifn_crypto_alg +{ + struct list_head entry; + struct crypto_alg alg; + struct hifn_device *dev; +}; + +#define ASYNC_SCATTERLIST_CACHE 16 + +#define ASYNC_FLAGS_MISALIGNED (1<<0) + +struct ablkcipher_walk +{ + struct scatterlist cache[ASYNC_SCATTERLIST_CACHE]; + u32 flags; + int num; +}; + +struct hifn_context +{ + u8 key[HIFN_MAX_CRYPT_KEY_LENGTH], *iv; + struct hifn_device *dev; + unsigned int keysize, ivsize; + u8 op, type, mode, unused; + struct ablkcipher_walk walk; + atomic_t sg_num; +}; + +#define crypto_alg_to_hifn(a) container_of(a, struct hifn_crypto_alg, alg) + +static inline u32 hifn_read_0(struct hifn_device *dev, u32 reg) +{ + u32 ret; + + ret = readl((char *)(dev->bar[0]) + reg); + + return ret; +} + +static inline u32 hifn_read_1(struct hifn_device *dev, u32 reg) +{ + u32 ret; + + ret = readl((char *)(dev->bar[1]) + reg); + + return ret; +} + +static inline void hifn_write_0(struct hifn_device *dev, u32 reg, u32 val) +{ + writel(val, (char *)(dev->bar[0]) + reg); +} + +static inline void hifn_write_1(struct hifn_device *dev, u32 reg, u32 val) +{ + writel(val, (char *)(dev->bar[1]) + reg); +} + +static void hifn_wait_puc(struct hifn_device *dev) +{ + int i; + u32 ret; + + for (i=10000; i > 0; --i) { + ret = hifn_read_0(dev, HIFN_0_PUCTRL); + if (!(ret & HIFN_PUCTRL_RESET)) + break; + + udelay(1); + } + + if (!i) + dprintk("%s: Failed to reset PUC unit.\n", dev->name); +} + +static void hifn_reset_puc(struct hifn_device *dev) +{ + hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); + hifn_wait_puc(dev); +} + +static void hifn_stop_device(struct hifn_device *dev) +{ + hifn_write_1(dev, HIFN_1_DMA_CSR, + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | + HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS); + hifn_write_0(dev, HIFN_0_PUIER, 0); + hifn_write_1(dev, HIFN_1_DMA_IER, 0); +} + +static void hifn_reset_dma(struct hifn_device *dev, int full) +{ + hifn_stop_device(dev); + + /* + * Setting poll frequency and others to 0. + */ + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + mdelay(1); + + /* + * Reset DMA. + */ + if (full) { + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE); + mdelay(1); + } else { + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MODE | + HIFN_DMACNFG_MSTRESET); + hifn_reset_puc(dev); + } + + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + + hifn_reset_puc(dev); +} + +static u32 hifn_next_signature(u_int32_t a, u_int cnt) +{ + int i; + u32 v; + + for (i = 0; i < cnt; i++) { + + /* get the parity */ + v = a & 0x80080125; + v ^= v >> 16; + v ^= v >> 8; + v ^= v >> 4; + v ^= v >> 2; + v ^= v >> 1; + + a = (v & 1) ^ (a << 1); + } + + return a; +} + +static struct pci2id { + u_short pci_vendor; + u_short pci_prod; + char card_id[13]; +} pci2id[] = { + { + PCI_VENDOR_ID_HIFN, + PCI_DEVICE_ID_HIFN_7955, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + PCI_VENDOR_ID_HIFN, + PCI_DEVICE_ID_HIFN_7956, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 } + } +}; + +#ifdef CRYPTO_DEV_HIFN_795X_RNG +static int hifn_rng_data_present(struct hwrng *rng, int wait) +{ + struct hifn_device *dev = (struct hifn_device *)rng->priv; + s64 nsec; + + nsec = ktime_to_ns(ktime_sub(ktime_get(), dev->rngtime)); + nsec -= dev->rng_wait_time; + if (nsec <= 0) + return 1; + if (!wait) + return 0; + ndelay(nsec); + return 1; +} + +static int hifn_rng_data_read(struct hwrng *rng, u32 *data) +{ + struct hifn_device *dev = (struct hifn_device *)rng->priv; + + *data = hifn_read_1(dev, HIFN_1_RNG_DATA); + dev->rngtime = ktime_get(); + return 4; +} + +static int hifn_register_rng(struct hifn_device *dev) +{ + /* + * We must wait at least 256 Pk_clk cycles between two reads of the rng. + */ + dev->rng_wait_time = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) * + 256; + + dev->rng.name = dev->name; + dev->rng.data_present = hifn_rng_data_present, + dev->rng.data_read = hifn_rng_data_read, + dev->rng.priv = (unsigned long)dev; + + return hwrng_register(&dev->rng); +} + +static void hifn_unregister_rng(struct hifn_device *dev) +{ + hwrng_unregister(&dev->rng); +} +#else +#define hifn_register_rng(dev) 0 +#define hifn_unregister_rng(dev) +#endif + +static int hifn_init_pubrng(struct hifn_device *dev) +{ + int i; + + hifn_write_1(dev, HIFN_1_PUB_RESET, hifn_read_1(dev, HIFN_1_PUB_RESET) | + HIFN_PUBRST_RESET); + + for (i=100; i > 0; --i) { + mdelay(1); + + if ((hifn_read_1(dev, HIFN_1_PUB_RESET) & HIFN_PUBRST_RESET) == 0) + break; + } + + if (!i) + dprintk("Chip %s: Failed to initialise public key engine.\n", + dev->name); + else { + hifn_write_1(dev, HIFN_1_PUB_IEN, HIFN_PUBIEN_DONE); + dev->dmareg |= HIFN_DMAIER_PUBDONE; + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + + dprintk("Chip %s: Public key engine has been sucessfully " + "initialised.\n", dev->name); + } + + /* + * Enable RNG engine. + */ + + hifn_write_1(dev, HIFN_1_RNG_CONFIG, + hifn_read_1(dev, HIFN_1_RNG_CONFIG) | HIFN_RNGCFG_ENA); + dprintk("Chip %s: RNG engine has been successfully initialised.\n", + dev->name); + +#ifdef CRYPTO_DEV_HIFN_795X_RNG + /* First value must be discarded */ + hifn_read_1(dev, HIFN_1_RNG_DATA); + dev->rngtime = ktime_get(); +#endif + return 0; +} + +static int hifn_enable_crypto(struct hifn_device *dev) +{ + u32 dmacfg, addr; + char *offtbl = NULL; + int i; + + for (i = 0; i < sizeof(pci2id)/sizeof(pci2id[0]); i++) { + if (pci2id[i].pci_vendor == dev->pdev->vendor && + pci2id[i].pci_prod == dev->pdev->device) { + offtbl = pci2id[i].card_id; + break; + } + } + + if (offtbl == NULL) { + dprintk("Chip %s: Unknown card!\n", dev->name); + return -ENODEV; + } + + dmacfg = hifn_read_1(dev, HIFN_1_DMA_CNFG); + + hifn_write_1(dev, HIFN_1_DMA_CNFG, + HIFN_DMACNFG_UNLOCK | HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE); + mdelay(1); + addr = hifn_read_1(dev, HIFN_1_UNLOCK_SECRET1); + mdelay(1); + hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, 0); + mdelay(1); + + for (i=0; i<12; ++i) { + addr = hifn_next_signature(addr, offtbl[i] + 0x101); + hifn_write_1(dev, HIFN_1_UNLOCK_SECRET2, addr); + + mdelay(1); + } + hifn_write_1(dev, HIFN_1_DMA_CNFG, dmacfg); + + dprintk("Chip %s: %s.\n", dev->name, pci_name(dev->pdev)); + + return 0; +} + +static void hifn_init_dma(struct hifn_device *dev) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + u32 dptr = dev->desc_dma; + int i; + + for (i=0; i<HIFN_D_CMD_RSIZE; ++i) + dma->cmdr[i].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, command_bufs[i][0])); + for (i=0; i<HIFN_D_RES_RSIZE; ++i) + dma->resr[i].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, result_bufs[i][0])); + + /* + * Setup LAST descriptors. + */ + dma->cmdr[HIFN_D_CMD_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, cmdr[0])); + dma->srcr[HIFN_D_SRC_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, srcr[0])); + dma->dstr[HIFN_D_DST_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, dstr[0])); + dma->resr[HIFN_D_RES_RSIZE].p = __cpu_to_le32(dptr + + offsetof(struct hifn_dma, resr[0])); + + dma->cmdu = dma->srcu = dma->dstu = dma->resu = 0; + dma->cmdi = dma->srci = dma->dsti = dma->resi = 0; + dma->cmdk = dma->srck = dma->dstk = dma->resk = 0; +} + +/* + * Initialize the PLL. We need to know the frequency of the reference clock + * to calculate the optimal multiplier. For PCI we assume 66MHz, since that + * allows us to operate without the risk of overclocking the chip. If it + * actually uses 33MHz, the chip will operate at half the speed, this can be + * overriden by specifying the frequency as module parameter (pci33). + * + * Unfortunately the PCI clock is not very suitable since the HIFN needs a + * stable clock and the PCI clock frequency may vary, so the default is the + * external clock. There is no way to find out its frequency, we default to + * 66MHz since according to Mike Ham of HiFn, almost every board in existence + * has an external crystal populated at 66MHz. + */ +static void hifn_init_pll(struct hifn_device *dev) +{ + unsigned int freq, m; + u32 pllcfg; + + pllcfg = HIFN_1_PLL | HIFN_PLL_RESERVED_1; + + if (strncmp(hifn_pll_ref, "ext", 3) == 0) + pllcfg |= HIFN_PLL_REF_CLK_PLL; + else + pllcfg |= HIFN_PLL_REF_CLK_HBI; + + if (hifn_pll_ref[3] != '\0') + freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); + else { + freq = 66; + printk(KERN_INFO "hifn795x: assuming %uMHz clock speed, " + "override with hifn_pll_ref=%.3s<frequency>\n", + freq, hifn_pll_ref); + } + + m = HIFN_PLL_FCK_MAX / freq; + + pllcfg |= (m / 2 - 1) << HIFN_PLL_ND_SHIFT; + if (m <= 8) + pllcfg |= HIFN_PLL_IS_1_8; + else + pllcfg |= HIFN_PLL_IS_9_12; + + /* Select clock source and enable clock bypass */ + hifn_write_1(dev, HIFN_1_PLL, pllcfg | + HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI | HIFN_PLL_BP); + + /* Let the chip lock to the input clock */ + mdelay(10); + + /* Disable clock bypass */ + hifn_write_1(dev, HIFN_1_PLL, pllcfg | + HIFN_PLL_PK_CLK_HBI | HIFN_PLL_PE_CLK_HBI); + + /* Switch the engines to the PLL */ + hifn_write_1(dev, HIFN_1_PLL, pllcfg | + HIFN_PLL_PK_CLK_PLL | HIFN_PLL_PE_CLK_PLL); + + /* + * The Fpk_clk runs at half the total speed. Its frequency is needed to + * calculate the minimum time between two reads of the rng. Since 33MHz + * is actually 33.333... we overestimate the frequency here, resulting + * in slightly larger intervals. + */ + dev->pk_clk_freq = 1000000 * (freq + 1) * m / 2; +} + +static void hifn_init_registers(struct hifn_device *dev) +{ + u32 dptr = dev->desc_dma; + + /* Initialization magic... */ + hifn_write_0(dev, HIFN_0_PUCTRL, HIFN_PUCTRL_DMAENA); + hifn_write_0(dev, HIFN_0_FIFOCNFG, HIFN_FIFOCNFG_THRESHOLD); + hifn_write_0(dev, HIFN_0_PUIER, HIFN_PUIER_DSTOVER); + + /* write all 4 ring address registers */ + hifn_write_1(dev, HIFN_1_DMA_CRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, cmdr[0]))); + hifn_write_1(dev, HIFN_1_DMA_SRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, srcr[0]))); + hifn_write_1(dev, HIFN_1_DMA_DRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, dstr[0]))); + hifn_write_1(dev, HIFN_1_DMA_RRAR, __cpu_to_le32(dptr + + offsetof(struct hifn_dma, resr[0]))); + + mdelay(2); +#if 0 + hifn_write_1(dev, HIFN_1_DMA_CSR, + HIFN_DMACSR_D_CTRL_DIS | HIFN_DMACSR_R_CTRL_DIS | + HIFN_DMACSR_S_CTRL_DIS | HIFN_DMACSR_C_CTRL_DIS | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | + HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | + HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | + HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | + HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | + HIFN_DMACSR_S_WAIT | + HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | + HIFN_DMACSR_C_WAIT | + HIFN_DMACSR_ENGINE | + HIFN_DMACSR_PUBDONE); +#else + hifn_write_1(dev, HIFN_1_DMA_CSR, + HIFN_DMACSR_C_CTRL_ENA | HIFN_DMACSR_S_CTRL_ENA | + HIFN_DMACSR_D_CTRL_ENA | HIFN_DMACSR_R_CTRL_ENA | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_D_DONE | HIFN_DMACSR_D_LAST | + HIFN_DMACSR_D_WAIT | HIFN_DMACSR_D_OVER | + HIFN_DMACSR_R_ABORT | HIFN_DMACSR_R_DONE | HIFN_DMACSR_R_LAST | + HIFN_DMACSR_R_WAIT | HIFN_DMACSR_R_OVER | + HIFN_DMACSR_S_ABORT | HIFN_DMACSR_S_DONE | HIFN_DMACSR_S_LAST | + HIFN_DMACSR_S_WAIT | + HIFN_DMACSR_C_ABORT | HIFN_DMACSR_C_DONE | HIFN_DMACSR_C_LAST | + HIFN_DMACSR_C_WAIT | + HIFN_DMACSR_ENGINE | + HIFN_DMACSR_PUBDONE); +#endif + hifn_read_1(dev, HIFN_1_DMA_CSR); + + dev->dmareg |= HIFN_DMAIER_R_DONE | HIFN_DMAIER_C_ABORT | + HIFN_DMAIER_D_OVER | HIFN_DMAIER_R_OVER | + HIFN_DMAIER_S_ABORT | HIFN_DMAIER_D_ABORT | HIFN_DMAIER_R_ABORT | + HIFN_DMAIER_ENGINE; + dev->dmareg &= ~HIFN_DMAIER_C_WAIT; + + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + hifn_read_1(dev, HIFN_1_DMA_IER); +#if 0 + hifn_write_0(dev, HIFN_0_PUCNFG, HIFN_PUCNFG_ENCCNFG | + HIFN_PUCNFG_DRFR_128 | HIFN_PUCNFG_TCALLPHASES | + HIFN_PUCNFG_TCDRVTOTEM | HIFN_PUCNFG_BUS32 | + HIFN_PUCNFG_DRAM); +#else + hifn_write_0(dev, HIFN_0_PUCNFG, 0x10342); +#endif + hifn_init_pll(dev); + + hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); + hifn_write_1(dev, HIFN_1_DMA_CNFG, HIFN_DMACNFG_MSTRESET | + HIFN_DMACNFG_DMARESET | HIFN_DMACNFG_MODE | HIFN_DMACNFG_LAST | + ((HIFN_POLL_FREQUENCY << 16 ) & HIFN_DMACNFG_POLLFREQ) | + ((HIFN_POLL_SCALAR << 8) & HIFN_DMACNFG_POLLINVAL)); +} + +static int hifn_setup_base_command(struct hifn_device *dev, u8 *buf, + unsigned dlen, unsigned slen, u16 mask, u8 snum) +{ + struct hifn_base_command *base_cmd; + u8 *buf_pos = buf; + + base_cmd = (struct hifn_base_command *)buf_pos; + base_cmd->masks = __cpu_to_le16(mask); + base_cmd->total_source_count = + __cpu_to_le16(slen & HIFN_BASE_CMD_LENMASK_LO); + base_cmd->total_dest_count = + __cpu_to_le16(dlen & HIFN_BASE_CMD_LENMASK_LO); + + dlen >>= 16; + slen >>= 16; + base_cmd->session_num = __cpu_to_le16(snum | + ((slen << HIFN_BASE_CMD_SRCLEN_S) & HIFN_BASE_CMD_SRCLEN_M) | + ((dlen << HIFN_BASE_CMD_DSTLEN_S) & HIFN_BASE_CMD_DSTLEN_M)); + + return sizeof(struct hifn_base_command); +} + +static int hifn_setup_crypto_command(struct hifn_device *dev, + u8 *buf, unsigned dlen, unsigned slen, + u8 *key, int keylen, u8 *iv, int ivsize, u16 mode) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + struct hifn_crypt_command *cry_cmd; + u8 *buf_pos = buf; + u16 cmd_len; + + cry_cmd = (struct hifn_crypt_command *)buf_pos; + + cry_cmd->source_count = __cpu_to_le16(dlen & 0xffff); + dlen >>= 16; + cry_cmd->masks = __cpu_to_le16(mode | + ((dlen << HIFN_CRYPT_CMD_SRCLEN_S) & + HIFN_CRYPT_CMD_SRCLEN_M)); + cry_cmd->header_skip = 0; + cry_cmd->reserved = 0; + + buf_pos += sizeof(struct hifn_crypt_command); + + dma->cmdu++; + if (dma->cmdu > 1) { + dev->dmareg |= HIFN_DMAIER_C_WAIT; + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + } + + if (keylen) { + memcpy(buf_pos, key, keylen); + buf_pos += keylen; + } + if (ivsize) { + memcpy(buf_pos, iv, ivsize); + buf_pos += ivsize; + } + + cmd_len = buf_pos - buf; + + return cmd_len; +} + +static int hifn_setup_src_desc(struct hifn_device *dev, struct page *page, + unsigned int offset, unsigned int size) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int idx; + dma_addr_t addr; + + addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_TODEVICE); + + idx = dma->srci; + + dma->srcr[idx].p = __cpu_to_le32(addr); + dma->srcr[idx].l = __cpu_to_le32(size) | HIFN_D_VALID | + HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST; + + if (++idx == HIFN_D_SRC_RSIZE) { + dma->srcr[idx].l = __cpu_to_le32(HIFN_D_VALID | + HIFN_D_JUMP | + HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + idx = 0; + } + + dma->srci = idx; + dma->srcu++; + + if (!(dev->flags & HIFN_FLAG_SRC_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_S_CTRL_ENA); + dev->flags |= HIFN_FLAG_SRC_BUSY; + } + + return size; +} + +static void hifn_setup_res_desc(struct hifn_device *dev) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + dma->resr[dma->resi].l = __cpu_to_le32(HIFN_USED_RESULT | + HIFN_D_VALID | HIFN_D_LAST); + /* + * dma->resr[dma->resi].l = __cpu_to_le32(HIFN_MAX_RESULT | HIFN_D_VALID | + * HIFN_D_LAST | HIFN_D_NOINVALID); + */ + + if (++dma->resi == HIFN_D_RES_RSIZE) { + dma->resr[HIFN_D_RES_RSIZE].l = __cpu_to_le32(HIFN_D_VALID | + HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | HIFN_D_LAST); + dma->resi = 0; + } + + dma->resu++; + + if (!(dev->flags & HIFN_FLAG_RES_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_R_CTRL_ENA); + dev->flags |= HIFN_FLAG_RES_BUSY; + } +} + +static void hifn_setup_dst_desc(struct hifn_device *dev, struct page *page, + unsigned offset, unsigned size) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int idx; + dma_addr_t addr; + + addr = pci_map_page(dev->pdev, page, offset, size, PCI_DMA_FROMDEVICE); + + idx = dma->dsti; + dma->dstr[idx].p = __cpu_to_le32(addr); + dma->dstr[idx].l = __cpu_to_le32(size | HIFN_D_VALID | + HIFN_D_MASKDONEIRQ | HIFN_D_NOINVALID | HIFN_D_LAST); + + if (++idx == HIFN_D_DST_RSIZE) { + dma->dstr[idx].l = __cpu_to_le32(HIFN_D_VALID | + HIFN_D_JUMP | HIFN_D_MASKDONEIRQ | + HIFN_D_LAST | HIFN_D_NOINVALID); + idx = 0; + } + dma->dsti = idx; + dma->dstu++; + + if (!(dev->flags & HIFN_FLAG_DST_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_D_CTRL_ENA); + dev->flags |= HIFN_FLAG_DST_BUSY; + } +} + +static int hifn_setup_dma(struct hifn_device *dev, struct page *spage, unsigned int soff, + struct page *dpage, unsigned int doff, unsigned int nbytes, void *priv, + struct hifn_context *ctx) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int cmd_len, sa_idx; + u8 *buf, *buf_pos; + u16 mask; + + dprintk("%s: spage: %p, soffset: %u, dpage: %p, doffset: %u, nbytes: %u, priv: %p, ctx: %p.\n", + dev->name, spage, soff, dpage, doff, nbytes, priv, ctx); + + sa_idx = dma->resi; + + hifn_setup_src_desc(dev, spage, soff, nbytes); + + buf_pos = buf = dma->command_bufs[dma->cmdi]; + + mask = 0; + switch (ctx->op) { + case ACRYPTO_OP_DECRYPT: + mask = HIFN_BASE_CMD_CRYPT | HIFN_BASE_CMD_DECODE; + break; + case ACRYPTO_OP_ENCRYPT: + mask = HIFN_BASE_CMD_CRYPT; + break; + case ACRYPTO_OP_HMAC: + mask = HIFN_BASE_CMD_MAC; + break; + default: + goto err_out; + } + + buf_pos += hifn_setup_base_command(dev, buf_pos, nbytes, + nbytes, mask, dev->snum); + + if (ctx->op == ACRYPTO_OP_ENCRYPT || ctx->op == ACRYPTO_OP_DECRYPT) { + u16 md = 0; + + if (ctx->keysize) + md |= HIFN_CRYPT_CMD_NEW_KEY; + if (ctx->iv && ctx->mode != ACRYPTO_MODE_ECB) + md |= HIFN_CRYPT_CMD_NEW_IV; + + switch (ctx->mode) { + case ACRYPTO_MODE_ECB: + md |= HIFN_CRYPT_CMD_MODE_ECB; + break; + case ACRYPTO_MODE_CBC: + md |= HIFN_CRYPT_CMD_MODE_CBC; + break; + case ACRYPTO_MODE_CFB: + md |= HIFN_CRYPT_CMD_MODE_CFB; + break; + case ACRYPTO_MODE_OFB: + md |= HIFN_CRYPT_CMD_MODE_OFB; + break; + default: + goto err_out; + } + + switch (ctx->type) { + case ACRYPTO_TYPE_AES_128: + if (ctx->keysize != 16) + goto err_out; + md |= HIFN_CRYPT_CMD_KSZ_128 | + HIFN_CRYPT_CMD_ALG_AES; + break; + case ACRYPTO_TYPE_AES_192: + if (ctx->keysize != 24) + goto err_out; + md |= HIFN_CRYPT_CMD_KSZ_192 | + HIFN_CRYPT_CMD_ALG_AES; + break; + case ACRYPTO_TYPE_AES_256: + if (ctx->keysize != 32) + goto err_out; + md |= HIFN_CRYPT_CMD_KSZ_256 | + HIFN_CRYPT_CMD_ALG_AES; + break; + case ACRYPTO_TYPE_3DES: + if (ctx->keysize != 24) + goto err_out; + md |= HIFN_CRYPT_CMD_ALG_3DES; + break; + case ACRYPTO_TYPE_DES: + if (ctx->keysize != 8) + goto err_out; + md |= HIFN_CRYPT_CMD_ALG_DES; + break; + default: + goto err_out; + } + + buf_pos += hifn_setup_crypto_command(dev, buf_pos, + nbytes, nbytes, ctx->key, ctx->keysize, + ctx->iv, ctx->ivsize, md); + } + + dev->sa[sa_idx] = priv; + + cmd_len = buf_pos - buf; + dma->cmdr[dma->cmdi].l = __cpu_to_le32(cmd_len | HIFN_D_VALID | + HIFN_D_LAST | HIFN_D_MASKDONEIRQ); + + if (++dma->cmdi == HIFN_D_CMD_RSIZE) { + dma->cmdr[dma->cmdi].l = __cpu_to_le32(HIFN_MAX_COMMAND | + HIFN_D_VALID | HIFN_D_LAST | + HIFN_D_MASKDONEIRQ | HIFN_D_JUMP); + dma->cmdi = 0; + } else + dma->cmdr[dma->cmdi-1].l |= __cpu_to_le32(HIFN_D_VALID); + + if (!(dev->flags & HIFN_FLAG_CMD_BUSY)) { + hifn_write_1(dev, HIFN_1_DMA_CSR, HIFN_DMACSR_C_CTRL_ENA); + dev->flags |= HIFN_FLAG_CMD_BUSY; + } + + hifn_setup_dst_desc(dev, dpage, doff, nbytes); + hifn_setup_res_desc(dev); + + return 0; + +err_out: + return -EINVAL; +} + +static int ablkcipher_walk_init(struct ablkcipher_walk *w, + int num, gfp_t gfp_flags) +{ + int i; + + num = min(ASYNC_SCATTERLIST_CACHE, num); + sg_init_table(w->cache, num); + + w->num = 0; + for (i=0; i<num; ++i) { + struct page *page = alloc_page(gfp_flags); + struct scatterlist *s; + + if (!page) + break; + + s = &w->cache[i]; + + sg_set_page(s, page, PAGE_SIZE, 0); + w->num++; + } + + return i; +} + +static void ablkcipher_walk_exit(struct ablkcipher_walk *w) +{ + int i; + + for (i=0; i<w->num; ++i) { + struct scatterlist *s = &w->cache[i]; + + __free_page(sg_page(s)); + + s->length = 0; + } + + w->num = 0; +} + +static int ablkcipher_add(void *daddr, unsigned int *drestp, struct scatterlist *src, + unsigned int size, unsigned int *nbytesp) +{ + unsigned int copy, drest = *drestp, nbytes = *nbytesp; + int idx = 0; + void *saddr; + + if (drest < size || size > nbytes) + return -EINVAL; + + while (size) { + copy = min(drest, src->length); + + saddr = kmap_atomic(sg_page(src), KM_SOFTIRQ1); + memcpy(daddr, saddr + src->offset, copy); + kunmap_atomic(saddr, KM_SOFTIRQ1); + + size -= copy; + drest -= copy; + nbytes -= copy; + daddr += copy; + + dprintk("%s: copy: %u, size: %u, drest: %u, nbytes: %u.\n", + __func__, copy, size, drest, nbytes); + + src++; + idx++; + } + + *nbytesp = nbytes; + *drestp = drest; + + return idx; +} + +static int ablkcipher_walk(struct ablkcipher_request *req, + struct ablkcipher_walk *w) +{ + unsigned blocksize = + crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req)); + unsigned alignmask = + crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req)); + struct scatterlist *src, *dst, *t; + void *daddr; + unsigned int nbytes = req->nbytes, offset, copy, diff; + int idx, tidx, err; + + tidx = idx = 0; + offset = 0; + while (nbytes) { + if (idx >= w->num && (w->flags & ASYNC_FLAGS_MISALIGNED)) + return -EINVAL; + + src = &req->src[idx]; + dst = &req->dst[idx]; + + dprintk("\n%s: slen: %u, dlen: %u, soff: %u, doff: %u, offset: %u, " + "blocksize: %u, nbytes: %u.\n", + __func__, src->length, dst->length, src->offset, + dst->offset, offset, blocksize, nbytes); + + if (src->length & (blocksize - 1) || + src->offset & (alignmask - 1) || + dst->length & (blocksize - 1) || + dst->offset & (alignmask - 1) || + offset) { + unsigned slen = src->length - offset; + unsigned dlen = PAGE_SIZE; + + t = &w->cache[idx]; + + daddr = kmap_atomic(sg_page(t), KM_SOFTIRQ0); + err = ablkcipher_add(daddr, &dlen, src, slen, &nbytes); + if (err < 0) + goto err_out_unmap; + + idx += err; + + copy = slen & ~(blocksize - 1); + diff = slen & (blocksize - 1); + + if (dlen < nbytes) { + /* + * Destination page does not have enough space + * to put there additional blocksized chunk, + * so we mark that page as containing only + * blocksize aligned chunks: + * t->length = (slen & ~(blocksize - 1)); + * and increase number of bytes to be processed + * in next chunk: + * nbytes += diff; + */ + nbytes += diff; + + /* + * Temporary of course... + * Kick author if you will catch this one. + */ + printk(KERN_ERR "%s: dlen: %u, nbytes: %u," + "slen: %u, offset: %u.\n", + __func__, dlen, nbytes, slen, offset); + printk(KERN_ERR "%s: please contact author to fix this " + "issue, generally you should not catch " + "this path under any condition but who " + "knows how did you use crypto code.\n" + "Thank you.\n", __func__); + BUG(); + } else { + copy += diff + nbytes; + + src = &req->src[idx]; + + err = ablkcipher_add(daddr + slen, &dlen, src, nbytes, &nbytes); + if (err < 0) + goto err_out_unmap; + + idx += err; + } + + t->length = copy; + t->offset = offset; + + kunmap_atomic(daddr, KM_SOFTIRQ0); + } else { + nbytes -= src->length; + idx++; + } + + tidx++; + } + + return tidx; + +err_out_unmap: + kunmap_atomic(daddr, KM_SOFTIRQ0); + return err; +} + +static int hifn_setup_session(struct ablkcipher_request *req) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev = ctx->dev; + struct page *spage, *dpage; + unsigned long soff, doff, flags; + unsigned int nbytes = req->nbytes, idx = 0, len; + int err = -EINVAL, sg_num; + struct scatterlist *src, *dst, *t; + unsigned blocksize = + crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(req)); + unsigned alignmask = + crypto_ablkcipher_alignmask(crypto_ablkcipher_reqtfm(req)); + + if (ctx->iv && !ctx->ivsize && ctx->mode != ACRYPTO_MODE_ECB) + goto err_out_exit; + + ctx->walk.flags = 0; + + while (nbytes) { + src = &req->src[idx]; + dst = &req->dst[idx]; + + if (src->length & (blocksize - 1) || + src->offset & (alignmask - 1) || + dst->length & (blocksize - 1) || + dst->offset & (alignmask - 1)) { + ctx->walk.flags |= ASYNC_FLAGS_MISALIGNED; + } + + nbytes -= src->length; + idx++; + } + + if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { + err = ablkcipher_walk_init(&ctx->walk, idx, GFP_ATOMIC); + if (err < 0) + return err; + } + + nbytes = req->nbytes; + idx = 0; + + sg_num = ablkcipher_walk(req, &ctx->walk); + + atomic_set(&ctx->sg_num, sg_num); + + spin_lock_irqsave(&dev->lock, flags); + if (dev->started + sg_num > HIFN_QUEUE_LENGTH) { + err = -EAGAIN; + goto err_out; + } + + dev->snum++; + dev->started += sg_num; + + while (nbytes) { + src = &req->src[idx]; + dst = &req->dst[idx]; + t = &ctx->walk.cache[idx]; + + if (t->length) { + spage = dpage = sg_page(t); + soff = doff = 0; + len = t->length; + } else { + spage = sg_page(src); + soff = src->offset; + + dpage = sg_page(dst); + doff = dst->offset; + + len = dst->length; + } + + idx++; + + err = hifn_setup_dma(dev, spage, soff, dpage, doff, nbytes, + req, ctx); + if (err) + goto err_out; + + nbytes -= len; + } + + dev->active = HIFN_DEFAULT_ACTIVE_NUM; + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; + +err_out: + spin_unlock_irqrestore(&dev->lock, flags); +err_out_exit: + if (err && printk_ratelimit()) + dprintk("%s: iv: %p [%d], key: %p [%d], mode: %u, op: %u, " + "type: %u, err: %d.\n", + dev->name, ctx->iv, ctx->ivsize, + ctx->key, ctx->keysize, + ctx->mode, ctx->op, ctx->type, err); + + return err; +} + +static int hifn_test(struct hifn_device *dev, int encdec, u8 snum) +{ + int n, err; + u8 src[16]; + struct hifn_context ctx; + u8 fips_aes_ecb_from_zero[16] = { + 0x66, 0xE9, 0x4B, 0xD4, + 0xEF, 0x8A, 0x2C, 0x3B, + 0x88, 0x4C, 0xFA, 0x59, + 0xCA, 0x34, 0x2B, 0x2E}; + + memset(src, 0, sizeof(src)); + memset(ctx.key, 0, sizeof(ctx.key)); + + ctx.dev = dev; + ctx.keysize = 16; + ctx.ivsize = 0; + ctx.iv = NULL; + ctx.op = (encdec)?ACRYPTO_OP_ENCRYPT:ACRYPTO_OP_DECRYPT; + ctx.mode = ACRYPTO_MODE_ECB; + ctx.type = ACRYPTO_TYPE_AES_128; + atomic_set(&ctx.sg_num, 1); + + err = hifn_setup_dma(dev, + virt_to_page(src), offset_in_page(src), + virt_to_page(src), offset_in_page(src), + sizeof(src), NULL, &ctx); + if (err) + goto err_out; + + msleep(200); + + dprintk("%s: decoded: ", dev->name); + for (n=0; n<sizeof(src); ++n) + dprintk("%02x ", src[n]); + dprintk("\n"); + dprintk("%s: FIPS : ", dev->name); + for (n=0; n<sizeof(fips_aes_ecb_from_zero); ++n) + dprintk("%02x ", fips_aes_ecb_from_zero[n]); + dprintk("\n"); + + if (!memcmp(src, fips_aes_ecb_from_zero, sizeof(fips_aes_ecb_from_zero))) { + printk(KERN_INFO "%s: AES 128 ECB test has been successfully " + "passed.\n", dev->name); + return 0; + } + +err_out: + printk(KERN_INFO "%s: AES 128 ECB test has been failed.\n", dev->name); + return -1; +} + +static int hifn_start_device(struct hifn_device *dev) +{ + int err; + + hifn_reset_dma(dev, 1); + + err = hifn_enable_crypto(dev); + if (err) + return err; + + hifn_reset_puc(dev); + + hifn_init_dma(dev); + + hifn_init_registers(dev); + + hifn_init_pubrng(dev); + + return 0; +} + +static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset, + struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) +{ + unsigned int srest = *srestp, nbytes = *nbytesp, copy; + void *daddr; + int idx = 0; + + if (srest < size || size > nbytes) + return -EINVAL; + + while (size) { + + copy = min(dst->length, srest); + + daddr = kmap_atomic(sg_page(dst), KM_IRQ0); + memcpy(daddr + dst->offset + offset, saddr, copy); + kunmap_atomic(daddr, KM_IRQ0); + + nbytes -= copy; + size -= copy; + srest -= copy; + saddr += copy; + offset = 0; + + dprintk("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n", + __func__, copy, size, srest, nbytes); + + dst++; + idx++; + } + + *nbytesp = nbytes; + *srestp = srest; + + return idx; +} + +static void hifn_process_ready(struct ablkcipher_request *req, int error) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev; + + dprintk("%s: req: %p, ctx: %p.\n", __func__, req, ctx); + + dev = ctx->dev; + dprintk("%s: req: %p, started: %d, sg_num: %d.\n", + __func__, req, dev->started, atomic_read(&ctx->sg_num)); + + if (--dev->started < 0) + BUG(); + + if (atomic_dec_and_test(&ctx->sg_num)) { + unsigned int nbytes = req->nbytes; + int idx = 0, err; + struct scatterlist *dst, *t; + void *saddr; + + if (ctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { + while (nbytes) { + t = &ctx->walk.cache[idx]; + dst = &req->dst[idx]; + + dprintk("\n%s: sg_page(t): %p, t->length: %u, " + "sg_page(dst): %p, dst->length: %u, " + "nbytes: %u.\n", + __func__, sg_page(t), t->length, + sg_page(dst), dst->length, nbytes); + + if (!t->length) { + nbytes -= dst->length; + idx++; + continue; + } + + saddr = kmap_atomic(sg_page(t), KM_IRQ1); + + err = ablkcipher_get(saddr, &t->length, t->offset, + dst, nbytes, &nbytes); + if (err < 0) { + kunmap_atomic(saddr, KM_IRQ1); + break; + } + + idx += err; + kunmap_atomic(saddr, KM_IRQ1); + } + + ablkcipher_walk_exit(&ctx->walk); + } + + req->base.complete(&req->base, error); + } +} + +static void hifn_check_for_completion(struct hifn_device *dev, int error) +{ + int i; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + for (i=0; i<HIFN_D_RES_RSIZE; ++i) { + struct hifn_desc *d = &dma->resr[i]; + + if (!(d->l & __cpu_to_le32(HIFN_D_VALID)) && dev->sa[i]) { + dev->success++; + dev->reset = 0; + hifn_process_ready(dev->sa[i], error); + dev->sa[i] = NULL; + } + + if (d->l & __cpu_to_le32(HIFN_D_DESTOVER | HIFN_D_OVER)) + if (printk_ratelimit()) + printk("%s: overflow detected [d: %u, o: %u] " + "at %d resr: l: %08x, p: %08x.\n", + dev->name, + !!(d->l & __cpu_to_le32(HIFN_D_DESTOVER)), + !!(d->l & __cpu_to_le32(HIFN_D_OVER)), + i, d->l, d->p); + } +} + +static void hifn_clear_rings(struct hifn_device *dev) +{ + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int i, u; + + dprintk("%s: ring cleanup 1: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " + "k: %d.%d.%d.%d.\n", + dev->name, + dma->cmdi, dma->srci, dma->dsti, dma->resi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + dma->cmdk, dma->srck, dma->dstk, dma->resk); + + i = dma->resk; u = dma->resu; + while (u != 0) { + if (dma->resr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + + if (i != HIFN_D_RES_RSIZE) + u--; + + if (++i == (HIFN_D_RES_RSIZE + 1)) + i = 0; + } + dma->resk = i; dma->resu = u; + + i = dma->srck; u = dma->srcu; + while (u != 0) { + if (i == HIFN_D_SRC_RSIZE) + i = 0; + if (dma->srcr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + i++, u--; + } + dma->srck = i; dma->srcu = u; + + i = dma->cmdk; u = dma->cmdu; + while (u != 0) { + if (dma->cmdr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + if (i != HIFN_D_CMD_RSIZE) + u--; + if (++i == (HIFN_D_CMD_RSIZE + 1)) + i = 0; + } + dma->cmdk = i; dma->cmdu = u; + + i = dma->dstk; u = dma->dstu; + while (u != 0) { + if (i == HIFN_D_DST_RSIZE) + i = 0; + if (dma->dstr[i].l & __cpu_to_le32(HIFN_D_VALID)) + break; + i++, u--; + } + dma->dstk = i; dma->dstu = u; + + dprintk("%s: ring cleanup 2: i: %d.%d.%d.%d, u: %d.%d.%d.%d, " + "k: %d.%d.%d.%d.\n", + dev->name, + dma->cmdi, dma->srci, dma->dsti, dma->resi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + dma->cmdk, dma->srck, dma->dstk, dma->resk); +} + +static void hifn_work(struct work_struct *work) +{ + struct delayed_work *dw = container_of(work, struct delayed_work, work); + struct hifn_device *dev = container_of(dw, struct hifn_device, work); + unsigned long flags; + int reset = 0; + u32 r = 0; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->active == 0) { + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + + if (dma->cmdu == 0 && (dev->flags & HIFN_FLAG_CMD_BUSY)) { + dev->flags &= ~HIFN_FLAG_CMD_BUSY; + r |= HIFN_DMACSR_C_CTRL_DIS; + } + if (dma->srcu == 0 && (dev->flags & HIFN_FLAG_SRC_BUSY)) { + dev->flags &= ~HIFN_FLAG_SRC_BUSY; + r |= HIFN_DMACSR_S_CTRL_DIS; + } + if (dma->dstu == 0 && (dev->flags & HIFN_FLAG_DST_BUSY)) { + dev->flags &= ~HIFN_FLAG_DST_BUSY; + r |= HIFN_DMACSR_D_CTRL_DIS; + } + if (dma->resu == 0 && (dev->flags & HIFN_FLAG_RES_BUSY)) { + dev->flags &= ~HIFN_FLAG_RES_BUSY; + r |= HIFN_DMACSR_R_CTRL_DIS; + } + if (r) + hifn_write_1(dev, HIFN_1_DMA_CSR, r); + } else + dev->active--; + + if (dev->prev_success == dev->success && dev->started) + reset = 1; + dev->prev_success = dev->success; + spin_unlock_irqrestore(&dev->lock, flags); + + if (reset) { + dprintk("%s: r: %08x, active: %d, started: %d, " + "success: %lu: reset: %d.\n", + dev->name, r, dev->active, dev->started, + dev->success, reset); + + if (++dev->reset >= 5) { + dprintk("%s: really hard reset.\n", dev->name); + hifn_reset_dma(dev, 1); + hifn_stop_device(dev); + hifn_start_device(dev); + dev->reset = 0; + } + + spin_lock_irqsave(&dev->lock, flags); + hifn_check_for_completion(dev, -EBUSY); + hifn_clear_rings(dev); + dev->started = 0; + spin_unlock_irqrestore(&dev->lock, flags); + } + + schedule_delayed_work(&dev->work, HZ); +} + +static irqreturn_t hifn_interrupt(int irq, void *data) +{ + struct hifn_device *dev = (struct hifn_device *)data; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + u32 dmacsr, restart; + + dmacsr = hifn_read_1(dev, HIFN_1_DMA_CSR); + + dprintk("%s: 1 dmacsr: %08x, dmareg: %08x, res: %08x [%d], " + "i: %d.%d.%d.%d, u: %d.%d.%d.%d.\n", + dev->name, dmacsr, dev->dmareg, dmacsr & dev->dmareg, dma->cmdi, + dma->cmdu, dma->srcu, dma->dstu, dma->resu, + dma->cmdi, dma->srci, dma->dsti, dma->resi); + + if ((dmacsr & dev->dmareg) == 0) + return IRQ_NONE; + + hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & dev->dmareg); + + if (dmacsr & HIFN_DMACSR_ENGINE) + hifn_write_0(dev, HIFN_0_PUISR, hifn_read_0(dev, HIFN_0_PUISR)); + if (dmacsr & HIFN_DMACSR_PUBDONE) + hifn_write_1(dev, HIFN_1_PUB_STATUS, + hifn_read_1(dev, HIFN_1_PUB_STATUS) | HIFN_PUBSTS_DONE); + + restart = dmacsr & (HIFN_DMACSR_R_OVER | HIFN_DMACSR_D_OVER); + if (restart) { + u32 puisr = hifn_read_0(dev, HIFN_0_PUISR); + + if (printk_ratelimit()) + printk("%s: overflow: r: %d, d: %d, puisr: %08x, d: %u.\n", + dev->name, !!(dmacsr & HIFN_DMACSR_R_OVER), + !!(dmacsr & HIFN_DMACSR_D_OVER), + puisr, !!(puisr & HIFN_PUISR_DSTOVER)); + if (!!(puisr & HIFN_PUISR_DSTOVER)) + hifn_write_0(dev, HIFN_0_PUISR, HIFN_PUISR_DSTOVER); + hifn_write_1(dev, HIFN_1_DMA_CSR, dmacsr & (HIFN_DMACSR_R_OVER | + HIFN_DMACSR_D_OVER)); + } + + restart = dmacsr & (HIFN_DMACSR_C_ABORT | HIFN_DMACSR_S_ABORT | + HIFN_DMACSR_D_ABORT | HIFN_DMACSR_R_ABORT); + if (restart) { + if (printk_ratelimit()) + printk("%s: abort: c: %d, s: %d, d: %d, r: %d.\n", + dev->name, !!(dmacsr & HIFN_DMACSR_C_ABORT), + !!(dmacsr & HIFN_DMACSR_S_ABORT), + !!(dmacsr & HIFN_DMACSR_D_ABORT), + !!(dmacsr & HIFN_DMACSR_R_ABORT)); + hifn_reset_dma(dev, 1); + hifn_init_dma(dev); + hifn_init_registers(dev); + } + + if ((dmacsr & HIFN_DMACSR_C_WAIT) && (dma->cmdu == 0)) { + dprintk("%s: wait on command.\n", dev->name); + dev->dmareg &= ~(HIFN_DMAIER_C_WAIT); + hifn_write_1(dev, HIFN_1_DMA_IER, dev->dmareg); + } + + tasklet_schedule(&dev->tasklet); + hifn_clear_rings(dev); + + return IRQ_HANDLED; +} + +static void hifn_flush(struct hifn_device *dev) +{ + unsigned long flags; + struct crypto_async_request *async_req; + struct hifn_context *ctx; + struct ablkcipher_request *req; + struct hifn_dma *dma = (struct hifn_dma *)dev->desc_virt; + int i; + + spin_lock_irqsave(&dev->lock, flags); + for (i=0; i<HIFN_D_RES_RSIZE; ++i) { + struct hifn_desc *d = &dma->resr[i]; + + if (dev->sa[i]) { + hifn_process_ready(dev->sa[i], + (d->l & __cpu_to_le32(HIFN_D_VALID))?-ENODEV:0); + } + } + + while ((async_req = crypto_dequeue_request(&dev->queue))) { + ctx = crypto_tfm_ctx(async_req->tfm); + req = container_of(async_req, struct ablkcipher_request, base); + + hifn_process_ready(req, -ENODEV); + } + spin_unlock_irqrestore(&dev->lock, flags); +} + +static int hifn_setkey(struct crypto_ablkcipher *cipher, const u8 *key, + unsigned int len) +{ + struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); + struct hifn_context *ctx = crypto_tfm_ctx(tfm); + struct hifn_device *dev = ctx->dev; + + if (len > HIFN_MAX_CRYPT_KEY_LENGTH) { + crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -1; + } + + if (len == HIFN_DES_KEY_LENGTH) { + u32 tmp[DES_EXPKEY_WORDS]; + int ret = des_ekey(tmp, key); + + if (unlikely(ret == 0) && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) { + tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY; + return -EINVAL; + } + } + + dev->flags &= ~HIFN_FLAG_OLD_KEY; + + memcpy(ctx->key, key, len); + ctx->keysize = len; + + return 0; +} + +static int hifn_handle_req(struct ablkcipher_request *req) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev = ctx->dev; + int err = -EAGAIN; + + if (dev->started + DIV_ROUND_UP(req->nbytes, PAGE_SIZE) <= HIFN_QUEUE_LENGTH) + err = hifn_setup_session(req); + + if (err == -EAGAIN) { + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + err = ablkcipher_enqueue_request(&dev->queue, req); + spin_unlock_irqrestore(&dev->lock, flags); + } + + return err; +} + +static int hifn_setup_crypto_req(struct ablkcipher_request *req, u8 op, + u8 type, u8 mode) +{ + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + unsigned ivsize; + + ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req)); + + if (req->info && mode != ACRYPTO_MODE_ECB) { + if (type == ACRYPTO_TYPE_AES_128) + ivsize = HIFN_AES_IV_LENGTH; + else if (type == ACRYPTO_TYPE_DES) + ivsize = HIFN_DES_KEY_LENGTH; + else if (type == ACRYPTO_TYPE_3DES) + ivsize = HIFN_3DES_KEY_LENGTH; + } + + if (ctx->keysize != 16 && type == ACRYPTO_TYPE_AES_128) { + if (ctx->keysize == 24) + type = ACRYPTO_TYPE_AES_192; + else if (ctx->keysize == 32) + type = ACRYPTO_TYPE_AES_256; + } + + ctx->op = op; + ctx->mode = mode; + ctx->type = type; + ctx->iv = req->info; + ctx->ivsize = ivsize; + + /* + * HEAVY TODO: needs to kick Herbert XU to write documentation. + * HEAVY TODO: needs to kick Herbert XU to write documentation. + * HEAVY TODO: needs to kick Herbert XU to write documentation. + */ + + return hifn_handle_req(req); +} + +static int hifn_process_queue(struct hifn_device *dev) +{ + struct crypto_async_request *async_req; + struct hifn_context *ctx; + struct ablkcipher_request *req; + unsigned long flags; + int err = 0; + + while (dev->started < HIFN_QUEUE_LENGTH) { + spin_lock_irqsave(&dev->lock, flags); + async_req = crypto_dequeue_request(&dev->queue); + spin_unlock_irqrestore(&dev->lock, flags); + + if (!async_req) + break; + + ctx = crypto_tfm_ctx(async_req->tfm); + req = container_of(async_req, struct ablkcipher_request, base); + + err = hifn_handle_req(req); + if (err) + break; + } + + return err; +} + +static int hifn_setup_crypto(struct ablkcipher_request *req, u8 op, + u8 type, u8 mode) +{ + int err; + struct hifn_context *ctx = crypto_tfm_ctx(req->base.tfm); + struct hifn_device *dev = ctx->dev; + + err = hifn_setup_crypto_req(req, op, type, mode); + if (err) + return err; + + if (dev->started < HIFN_QUEUE_LENGTH && dev->queue.qlen) + err = hifn_process_queue(dev); + + return err; +} + +/* + * AES ecryption functions. + */ +static inline int hifn_encrypt_aes_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); +} +static inline int hifn_encrypt_aes_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); +} +static inline int hifn_encrypt_aes_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); +} +static inline int hifn_encrypt_aes_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); +} + +/* + * AES decryption functions. + */ +static inline int hifn_decrypt_aes_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_ECB); +} +static inline int hifn_decrypt_aes_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); +} +static inline int hifn_decrypt_aes_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); +} +static inline int hifn_decrypt_aes_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); +} + +/* + * DES ecryption functions. + */ +static inline int hifn_encrypt_des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_encrypt_des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_encrypt_des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_encrypt_des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); +} + +/* + * DES decryption functions. + */ +static inline int hifn_decrypt_des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_decrypt_des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_decrypt_des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_decrypt_des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); +} + +/* + * 3DES ecryption functions. + */ +static inline int hifn_encrypt_3des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_encrypt_3des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_encrypt_3des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_encrypt_3des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); +} + +/* + * 3DES decryption functions. + */ +static inline int hifn_decrypt_3des_ecb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_ECB); +} +static inline int hifn_decrypt_3des_cbc(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); +} +static inline int hifn_decrypt_3des_cfb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); +} +static inline int hifn_decrypt_3des_ofb(struct ablkcipher_request *req) +{ + return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, + ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); +} + +struct hifn_alg_template +{ + char name[CRYPTO_MAX_ALG_NAME]; + char drv_name[CRYPTO_MAX_ALG_NAME]; + unsigned int bsize; + struct ablkcipher_alg ablkcipher; +}; + +static struct hifn_alg_template hifn_alg_templates[] = { + /* + * 3DES ECB, CBC, CFB and OFB modes. + */ + { + .name = "cfb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_cfb, + .decrypt = hifn_decrypt_3des_cfb, + }, + }, + { + .name = "ofb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_ofb, + .decrypt = hifn_decrypt_3des_ofb, + }, + }, + { + .name = "cbc(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_cbc, + .decrypt = hifn_decrypt_3des_cbc, + }, + }, + { + .name = "ecb(des3_ede)", .drv_name = "hifn-3des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_3DES_KEY_LENGTH, + .max_keysize = HIFN_3DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_3des_ecb, + .decrypt = hifn_decrypt_3des_ecb, + }, + }, + + /* + * DES ECB, CBC, CFB and OFB modes. + */ + { + .name = "cfb(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_cfb, + .decrypt = hifn_decrypt_des_cfb, + }, + }, + { + .name = "ofb(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_ofb, + .decrypt = hifn_decrypt_des_ofb, + }, + }, + { + .name = "cbc(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_cbc, + .decrypt = hifn_decrypt_des_cbc, + }, + }, + { + .name = "ecb(des)", .drv_name = "hifn-des", .bsize = 8, + .ablkcipher = { + .min_keysize = HIFN_DES_KEY_LENGTH, + .max_keysize = HIFN_DES_KEY_LENGTH, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_des_ecb, + .decrypt = hifn_decrypt_des_ecb, + }, + }, + + /* + * AES ECB, CBC, CFB and OFB modes. + */ + { + .name = "ecb(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_ecb, + .decrypt = hifn_decrypt_aes_ecb, + }, + }, + { + .name = "cbc(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_cbc, + .decrypt = hifn_decrypt_aes_cbc, + }, + }, + { + .name = "cfb(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_cfb, + .decrypt = hifn_decrypt_aes_cfb, + }, + }, + { + .name = "ofb(aes)", .drv_name = "hifn-aes", .bsize = 16, + .ablkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = hifn_setkey, + .encrypt = hifn_encrypt_aes_ofb, + .decrypt = hifn_decrypt_aes_ofb, + }, + }, +}; + +static int hifn_cra_init(struct crypto_tfm *tfm) +{ + struct crypto_alg *alg = tfm->__crt_alg; + struct hifn_crypto_alg *ha = crypto_alg_to_hifn(alg); + struct hifn_context *ctx = crypto_tfm_ctx(tfm); + + ctx->dev = ha->dev; + + return 0; +} + +static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t) +{ + struct hifn_crypto_alg *alg; + int err; + + alg = kzalloc(sizeof(struct hifn_crypto_alg), GFP_KERNEL); + if (!alg) + return -ENOMEM; + + snprintf(alg->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s", t->name); + snprintf(alg->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", t->drv_name); + + alg->alg.cra_priority = 300; + alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; + alg->alg.cra_blocksize = t->bsize; + alg->alg.cra_ctxsize = sizeof(struct hifn_context); + alg->alg.cra_alignmask = 15; + if (t->bsize == 8) + alg->alg.cra_alignmask = 3; + alg->alg.cra_type = &crypto_ablkcipher_type; + alg->alg.cra_module = THIS_MODULE; + alg->alg.cra_u.ablkcipher = t->ablkcipher; + alg->alg.cra_init = hifn_cra_init; + + alg->dev = dev; + + list_add_tail(&alg->entry, &dev->alg_list); + + err = crypto_register_alg(&alg->alg); + if (err) { + list_del(&alg->entry); + kfree(alg); + } + + return err; +} + +static void hifn_unregister_alg(struct hifn_device *dev) +{ + struct hifn_crypto_alg *a, *n; + + list_for_each_entry_safe(a, n, &dev->alg_list, entry) { + list_del(&a->entry); + crypto_unregister_alg(&a->alg); + kfree(a); + } +} + +static int hifn_register_alg(struct hifn_device *dev) +{ + int i, err; + + for (i=0; i<ARRAY_SIZE(hifn_alg_templates); ++i) { + err = hifn_alg_alloc(dev, &hifn_alg_templates[i]); + if (err) + goto err_out_exit; + } + + return 0; + +err_out_exit: + hifn_unregister_alg(dev); + return err; +} + +static void hifn_tasklet_callback(unsigned long data) +{ + struct hifn_device *dev = (struct hifn_device *)data; + + /* + * This is ok to call this without lock being held, + * althogh it modifies some parameters used in parallel, + * (like dev->success), but they are used in process + * context or update is atomic (like setting dev->sa[i] to NULL). + */ + hifn_check_for_completion(dev, 0); +} + +static int hifn_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err, i; + struct hifn_device *dev; + char name[8]; + + err = pci_enable_device(pdev); + if (err) + return err; + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) + goto err_out_disable_pci_device; + + snprintf(name, sizeof(name), "hifn%d", + atomic_inc_return(&hifn_dev_number)-1); + + err = pci_request_regions(pdev, name); + if (err) + goto err_out_disable_pci_device; + + if (pci_resource_len(pdev, 0) < HIFN_BAR0_SIZE || + pci_resource_len(pdev, 1) < HIFN_BAR1_SIZE || + pci_resource_len(pdev, 2) < HIFN_BAR2_SIZE) { + dprintk("%s: Broken hardware - I/O regions are too small.\n", + pci_name(pdev)); + err = -ENODEV; + goto err_out_free_regions; + } + + dev = kzalloc(sizeof(struct hifn_device) + sizeof(struct crypto_alg), + GFP_KERNEL); + if (!dev) { + err = -ENOMEM; + goto err_out_free_regions; + } + + INIT_LIST_HEAD(&dev->alg_list); + + snprintf(dev->name, sizeof(dev->name), "%s", name); + spin_lock_init(&dev->lock); + + for (i=0; i<3; ++i) { + unsigned long addr, size; + + addr = pci_resource_start(pdev, i); + size = pci_resource_len(pdev, i); + + dev->bar[i] = ioremap_nocache(addr, size); + if (!dev->bar[i]) + goto err_out_unmap_bars; + } + + dev->result_mem = __get_free_pages(GFP_KERNEL, HIFN_MAX_RESULT_ORDER); + if (!dev->result_mem) { + dprintk("Failed to allocate %d pages for result_mem.\n", + HIFN_MAX_RESULT_ORDER); + goto err_out_unmap_bars; + } + memset((void *)dev->result_mem, 0, PAGE_SIZE*(1<<HIFN_MAX_RESULT_ORDER)); + + dev->dst = pci_map_single(pdev, (void *)dev->result_mem, + PAGE_SIZE << HIFN_MAX_RESULT_ORDER, PCI_DMA_FROMDEVICE); + + dev->desc_virt = pci_alloc_consistent(pdev, sizeof(struct hifn_dma), + &dev->desc_dma); + if (!dev->desc_virt) { + dprintk("Failed to allocate descriptor rings.\n"); + goto err_out_free_result_pages; + } + memset(dev->desc_virt, 0, sizeof(struct hifn_dma)); + + dev->pdev = pdev; + dev->irq = pdev->irq; + + for (i=0; i<HIFN_D_RES_RSIZE; ++i) + dev->sa[i] = NULL; + + pci_set_drvdata(pdev, dev); + + tasklet_init(&dev->tasklet, hifn_tasklet_callback, (unsigned long)dev); + + crypto_init_queue(&dev->queue, 1); + + err = request_irq(dev->irq, hifn_interrupt, IRQF_SHARED, dev->name, dev); + if (err) { + dprintk("Failed to request IRQ%d: err: %d.\n", dev->irq, err); + dev->irq = 0; + goto err_out_free_desc; + } + + err = hifn_start_device(dev); + if (err) + goto err_out_free_irq; + + err = hifn_test(dev, 1, 0); + if (err) + goto err_out_stop_device; + + err = hifn_register_rng(dev); + if (err) + goto err_out_stop_device; + + err = hifn_register_alg(dev); + if (err) + goto err_out_unregister_rng; + + INIT_DELAYED_WORK(&dev->work, hifn_work); + schedule_delayed_work(&dev->work, HZ); + + dprintk("HIFN crypto accelerator card at %s has been " + "successfully registered as %s.\n", + pci_name(pdev), dev->name); + + return 0; + +err_out_unregister_rng: + hifn_unregister_rng(dev); +err_out_stop_device: + hifn_reset_dma(dev, 1); + hifn_stop_device(dev); +err_out_free_irq: + free_irq(dev->irq, dev->name); + tasklet_kill(&dev->tasklet); +err_out_free_desc: + pci_free_consistent(pdev, sizeof(struct hifn_dma), + dev->desc_virt, dev->desc_dma); + +err_out_free_result_pages: + pci_unmap_single(pdev, dev->dst, PAGE_SIZE << HIFN_MAX_RESULT_ORDER, + PCI_DMA_FROMDEVICE); + free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER); + +err_out_unmap_bars: + for (i=0; i<3; ++i) + if (dev->bar[i]) + iounmap(dev->bar[i]); + +err_out_free_regions: + pci_release_regions(pdev); + +err_out_disable_pci_device: + pci_disable_device(pdev); + + return err; +} + +static void hifn_remove(struct pci_dev *pdev) +{ + int i; + struct hifn_device *dev; + + dev = pci_get_drvdata(pdev); + + if (dev) { + cancel_delayed_work(&dev->work); + flush_scheduled_work(); + + hifn_unregister_rng(dev); + hifn_unregister_alg(dev); + hifn_reset_dma(dev, 1); + hifn_stop_device(dev); + + free_irq(dev->irq, dev->name); + tasklet_kill(&dev->tasklet); + + hifn_flush(dev); + + pci_free_consistent(pdev, sizeof(struct hifn_dma), + dev->desc_virt, dev->desc_dma); + pci_unmap_single(pdev, dev->dst, + PAGE_SIZE << HIFN_MAX_RESULT_ORDER, + PCI_DMA_FROMDEVICE); + free_pages(dev->result_mem, HIFN_MAX_RESULT_ORDER); + for (i=0; i<3; ++i) + if (dev->bar[i]) + iounmap(dev->bar[i]); + + kfree(dev); + } + + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id hifn_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7955) }, + { PCI_DEVICE(PCI_VENDOR_ID_HIFN, PCI_DEVICE_ID_HIFN_7956) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, hifn_pci_tbl); + +static struct pci_driver hifn_pci_driver = { + .name = "hifn795x", + .id_table = hifn_pci_tbl, + .probe = hifn_probe, + .remove = __devexit_p(hifn_remove), +}; + +static int __devinit hifn_init(void) +{ + unsigned int freq; + int err; + + if (strncmp(hifn_pll_ref, "ext", 3) && + strncmp(hifn_pll_ref, "pci", 3)) { + printk(KERN_ERR "hifn795x: invalid hifn_pll_ref clock, " + "must be pci or ext"); + return -EINVAL; + } + + /* + * For the 7955/7956 the reference clock frequency must be in the + * range of 20MHz-100MHz. For the 7954 the upper bound is 66.67MHz, + * but this chip is currently not supported. + */ + if (hifn_pll_ref[3] != '\0') { + freq = simple_strtoul(hifn_pll_ref + 3, NULL, 10); + if (freq < 20 || freq > 100) { + printk(KERN_ERR "hifn795x: invalid hifn_pll_ref " + "frequency, must be in the range " + "of 20-100"); + return -EINVAL; + } + } + + err = pci_register_driver(&hifn_pci_driver); + if (err < 0) { + dprintk("Failed to register PCI driver for %s device.\n", + hifn_pci_driver.name); + return -ENODEV; + } + + printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip " + "has been successfully registered.\n"); + + return 0; +} + +static void __devexit hifn_fini(void) +{ + pci_unregister_driver(&hifn_pci_driver); + + printk(KERN_INFO "Driver for HIFN 795x crypto accelerator chip " + "has been successfully unregistered.\n"); +} + +module_init(hifn_init); +module_exit(hifn_fini); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>"); +MODULE_DESCRIPTION("Driver for HIFN 795x crypto accelerator chip."); diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index 5f7e71810489..2f3ad3f7dfea 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -44,6 +44,7 @@ */ #include <crypto/algapi.h> +#include <crypto/aes.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> @@ -53,9 +54,6 @@ #include <asm/byteorder.h> #include "padlock.h" -#define AES_MIN_KEY_SIZE 16 /* in uint8_t units */ -#define AES_MAX_KEY_SIZE 32 /* ditto */ -#define AES_BLOCK_SIZE 16 /* ditto */ #define AES_EXTENDED_KEY_SIZE 64 /* in uint32_t units */ #define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t)) @@ -419,6 +417,11 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, /* ====== Encryption/decryption routines ====== */ /* These are the real call to PadLock. */ +static inline void padlock_reset_key(void) +{ + asm volatile ("pushfl; popfl"); +} + static inline void padlock_xcrypt(const u8 *input, u8 *output, void *key, void *control_word) { @@ -439,8 +442,6 @@ static void aes_crypt_copy(const u8 *in, u8 *out, u32 *key, struct cword *cword) static inline void aes_crypt(const u8 *in, u8 *out, u32 *key, struct cword *cword) { - asm volatile ("pushfl; popfl"); - /* padlock_xcrypt requires at least two blocks of data. */ if (unlikely(!(((unsigned long)in ^ (PAGE_SIZE - AES_BLOCK_SIZE)) & (PAGE_SIZE - 1)))) { @@ -459,7 +460,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, return; } - asm volatile ("pushfl; popfl"); /* enforce key reload. */ asm volatile ("test $1, %%cl;" "je 1f;" "lea -1(%%ecx), %%eax;" @@ -476,8 +476,6 @@ static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key, static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, u8 *iv, void *control_word, u32 count) { - /* Enforce key reload. */ - asm volatile ("pushfl; popfl"); /* rep xcryptcbc */ asm volatile (".byte 0xf3,0x0f,0xa7,0xd0" : "+S" (input), "+D" (output), "+a" (iv) @@ -488,12 +486,14 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key, static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); + padlock_reset_key(); aes_crypt(in, out, ctx->E, &ctx->cword.encrypt); } static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) { struct aes_ctx *ctx = aes_ctx(tfm); + padlock_reset_key(); aes_crypt(in, out, ctx->D, &ctx->cword.decrypt); } @@ -526,6 +526,8 @@ static int ecb_aes_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -548,6 +550,8 @@ static int ecb_aes_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -592,6 +596,8 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); @@ -616,6 +622,8 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, struct blkcipher_walk walk; int err; + padlock_reset_key(); + blkcipher_walk_init(&walk, dst, src, nbytes); err = blkcipher_walk_virt(desc, &walk); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index d59b2f417306..bcf52df30339 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -41,12 +41,12 @@ * the definition of dma_event_callback in dmaengine.h. * * Each device has a kref, which is initialized to 1 when the device is - * registered. A kref_get is done for each class_device registered. When the - * class_device is released, the coresponding kref_put is done in the release + * registered. A kref_get is done for each device registered. When the + * device is released, the coresponding kref_put is done in the release * method. Every time one of the device's channels is allocated to a client, * a kref_get occurs. When the channel is freed, the coresponding kref_put * happens. The device's release function does a completion, so - * unregister_device does a remove event, class_device_unregister, a kref_put + * unregister_device does a remove event, device_unregister, a kref_put * for the first reference, then waits on the completion for all other * references to finish. * @@ -77,9 +77,9 @@ static LIST_HEAD(dma_client_list); /* --- sysfs implementation --- */ -static ssize_t show_memcpy_count(struct class_device *cd, char *buf) +static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); unsigned long count = 0; int i; @@ -89,9 +89,10 @@ static ssize_t show_memcpy_count(struct class_device *cd, char *buf) return sprintf(buf, "%lu\n", count); } -static ssize_t show_bytes_transferred(struct class_device *cd, char *buf) +static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr, + char *buf) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); unsigned long count = 0; int i; @@ -101,9 +102,9 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf) return sprintf(buf, "%lu\n", count); } -static ssize_t show_in_use(struct class_device *cd, char *buf) +static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); int in_use = 0; if (unlikely(chan->slow_ref) && @@ -119,7 +120,7 @@ static ssize_t show_in_use(struct class_device *cd, char *buf) return sprintf(buf, "%d\n", in_use); } -static struct class_device_attribute dma_class_attrs[] = { +static struct device_attribute dma_attrs[] = { __ATTR(memcpy_count, S_IRUGO, show_memcpy_count, NULL), __ATTR(bytes_transferred, S_IRUGO, show_bytes_transferred, NULL), __ATTR(in_use, S_IRUGO, show_in_use, NULL), @@ -128,16 +129,16 @@ static struct class_device_attribute dma_class_attrs[] = { static void dma_async_device_cleanup(struct kref *kref); -static void dma_class_dev_release(struct class_device *cd) +static void dma_dev_release(struct device *dev) { - struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev); + struct dma_chan *chan = to_dma_chan(dev); kref_put(&chan->device->refcount, dma_async_device_cleanup); } static struct class dma_devclass = { - .name = "dma", - .class_dev_attrs = dma_class_attrs, - .release = dma_class_dev_release, + .name = "dma", + .dev_attrs = dma_attrs, + .dev_release = dma_dev_release, }; /* --- client and device registration --- */ @@ -377,12 +378,12 @@ int dma_async_device_register(struct dma_device *device) continue; chan->chan_id = chancnt++; - chan->class_dev.class = &dma_devclass; - chan->class_dev.dev = NULL; - snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d", + chan->dev.class = &dma_devclass; + chan->dev.parent = NULL; + snprintf(chan->dev.bus_id, BUS_ID_SIZE, "dma%dchan%d", device->dev_id, chan->chan_id); - rc = class_device_register(&chan->class_dev); + rc = device_register(&chan->dev); if (rc) { chancnt--; free_percpu(chan->local); @@ -411,7 +412,7 @@ err_out: if (chan->local == NULL) continue; kref_put(&device->refcount, dma_async_device_cleanup); - class_device_unregister(&chan->class_dev); + device_unregister(&chan->dev); chancnt--; free_percpu(chan->local); } @@ -445,7 +446,7 @@ void dma_async_device_unregister(struct dma_device *device) list_for_each_entry(chan, &device->channels, device_node) { dma_clients_notify_removed(chan); - class_device_unregister(&chan->class_dev); + device_unregister(&chan->dev); dma_chan_release(chan); } diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 70b837f23c43..53764577035f 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -246,16 +246,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) /* Init the devices's kobject */ memset(&edac_dev->kobj, 0, sizeof(struct kobject)); - edac_dev->kobj.ktype = &ktype_device_ctrl; - - /* set this new device under the edac_class kobject */ - edac_dev->kobj.parent = &edac_class->kset.kobj; - - /* generate sysfs "..../edac/<name>" */ - debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name); - err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name); - if (err) - goto err_out; /* Record which module 'owns' this control structure * and bump the ref count of the module @@ -268,12 +258,15 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) } /* register */ - err = kobject_register(&edac_dev->kobj); + err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl, + &edac_class->kset.kobj, + "%s", edac_dev->name); if (err) { debugf1("%s()Failed to register '.../edac/%s'\n", __func__, edac_dev->name); goto err_kobj_reg; } + kobject_uevent(&edac_dev->kobj, KOBJ_ADD); /* At this point, to 'free' the control struct, * edac_device_unregister_sysfs_main_kobj() must be used @@ -310,7 +303,7 @@ void edac_device_unregister_sysfs_main_kobj( * a) module_put() this module * b) 'kfree' the memory */ - kobject_unregister(&edac_dev->kobj); + kobject_put(&edac_dev->kobj); } /* edac_dev -> instance information */ @@ -533,12 +526,6 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, /* init this block's kobject */ memset(&block->kobj, 0, sizeof(struct kobject)); - block->kobj.parent = &instance->kobj; - block->kobj.ktype = &ktype_block_ctrl; - - err = kobject_set_name(&block->kobj, "%s", block->name); - if (err) - return err; /* bump the main kobject's reference count for this controller * and this instance is dependant on the main @@ -550,7 +537,9 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, } /* Add this block's kobject */ - err = kobject_register(&block->kobj); + err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl, + &instance->kobj, + "%s", block->name); if (err) { debugf1("%s() Failed to register instance '%s'\n", __func__, block->name); @@ -579,12 +568,13 @@ static int edac_device_create_block(struct edac_device_ctl_info *edac_dev, goto err_on_attrib; } } + kobject_uevent(&block->kobj, KOBJ_ADD); return 0; /* Error unwind stack */ err_on_attrib: - kobject_unregister(&block->kobj); + kobject_put(&block->kobj); err_out: return err; @@ -615,7 +605,7 @@ static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev, /* unregister this block's kobject, SEE: * edac_device_ctrl_block_release() callback operation */ - kobject_unregister(&block->kobj); + kobject_put(&block->kobj); } /* instance ctor/dtor code */ @@ -637,15 +627,8 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, /* Init the instance's kobject */ memset(&instance->kobj, 0, sizeof(struct kobject)); - /* set this new device under the edac_device main kobject */ - instance->kobj.parent = &edac_dev->kobj; - instance->kobj.ktype = &ktype_instance_ctrl; instance->ctl = edac_dev; - err = kobject_set_name(&instance->kobj, "%s", instance->name); - if (err) - goto err_out; - /* bump the main kobject's reference count for this controller * and this instance is dependant on the main */ @@ -655,8 +638,9 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, goto err_out; } - /* Formally register this instance's kobject */ - err = kobject_register(&instance->kobj); + /* Formally register this instance's kobject under the edac_device */ + err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl, + &edac_dev->kobj, "%s", instance->name); if (err != 0) { debugf2("%s() Failed to register instance '%s'\n", __func__, instance->name); @@ -679,6 +663,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, goto err_release_instance_kobj; } } + kobject_uevent(&instance->kobj, KOBJ_ADD); debugf4("%s() Registered instance %d '%s' kobject\n", __func__, idx, instance->name); @@ -687,7 +672,7 @@ static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev, /* error unwind stack */ err_release_instance_kobj: - kobject_unregister(&instance->kobj); + kobject_put(&instance->kobj); err_out: return err; @@ -712,7 +697,7 @@ static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev, /* unregister this instance's kobject, SEE: * edac_device_ctrl_instance_release() for callback operation */ - kobject_unregister(&instance->kobj); + kobject_put(&instance->kobj); } /* diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 3706b2bc0987..9aac88027fb3 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -380,13 +380,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, /* generate ..../edac/mc/mc<id>/csrow<index> */ memset(&csrow->kobj, 0, sizeof(csrow->kobj)); csrow->mci = mci; /* include container up link */ - csrow->kobj.parent = kobj_mci; - csrow->kobj.ktype = &ktype_csrow; - - /* name this instance of csrow<id> */ - err = kobject_set_name(&csrow->kobj, "csrow%d", index); - if (err) - goto err_out; /* bump the mci instance's kobject's ref count */ kobj = kobject_get(&mci->edac_mci_kobj); @@ -396,12 +389,13 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, } /* Instanstiate the csrow object */ - err = kobject_register(&csrow->kobj); + err = kobject_init_and_add(&csrow->kobj, &ktype_csrow, kobj_mci, + "csrow%d", index); if (err) goto err_release_top_kobj; /* At this point, to release a csrow kobj, one must - * call the kobject_unregister and allow that tear down + * call the kobject_put and allow that tear down * to work the releasing */ @@ -412,11 +406,11 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, err = edac_create_channel_files(&csrow->kobj, chan); if (err) { /* special case the unregister here */ - kobject_unregister(&csrow->kobj); + kobject_put(&csrow->kobj); goto err_out; } } - + kobject_uevent(&csrow->kobj, KOBJ_ADD); return 0; /* error unwind stack */ @@ -744,7 +738,6 @@ static struct kobj_type ktype_mc_set_attribs = { */ static struct kset mc_kset = { .kobj = {.ktype = &ktype_mc_set_attribs }, - .ktype = &ktype_mci, }; @@ -765,14 +758,6 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) /* Init the mci's kobject */ memset(kobj_mci, 0, sizeof(*kobj_mci)); - /* this instance become part of the mc_kset */ - kobj_mci->kset = &mc_kset; - - /* set the name of the mc<id> object */ - err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx); - if (err) - goto fail_out; - /* Record which module 'owns' this control structure * and bump the ref count of the module */ @@ -784,13 +769,18 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) goto fail_out; } + /* this instance become part of the mc_kset */ + kobj_mci->kset = &mc_kset; + /* register the mc<id> kobject to the mc_kset */ - err = kobject_register(kobj_mci); + err = kobject_init_and_add(kobj_mci, &ktype_mci, NULL, + "mc%d", mci->mc_idx); if (err) { debugf1("%s()Failed to register '.../edac/mc%d'\n", __func__, mci->mc_idx); goto kobj_reg_fail; } + kobject_uevent(kobj_mci, KOBJ_ADD); /* At this point, to 'free' the control struct, * edac_mc_unregister_sysfs_main_kobj() must be used @@ -818,7 +808,7 @@ fail_out: void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) { /* delete the kobj from the mc_kset */ - kobject_unregister(&mci->edac_mci_kobj); + kobject_put(&mci->edac_mci_kobj); } #define EDAC_DEVICE_SYMLINK "device" @@ -933,7 +923,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) fail1: for (i--; i >= 0; i--) { if (csrow->nr_pages > 0) { - kobject_unregister(&mci->csrows[i].kobj); + kobject_put(&mci->csrows[i].kobj); } } @@ -960,7 +950,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) for (i = 0; i < mci->nr_csrows; i++) { if (mci->csrows[i].nr_pages > 0) { debugf0("%s() unreg csrow-%d\n", __func__, i); - kobject_unregister(&mci->csrows[i].kobj); + kobject_put(&mci->csrows[i].kobj); } } @@ -977,7 +967,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s() unregister this mci kobj\n", __func__); /* unregister this instance's kobject */ - kobject_unregister(&mci->edac_mci_kobj); + kobject_put(&mci->edac_mci_kobj); } diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index e0c4a4086055..7e1374afd967 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -31,7 +31,7 @@ struct workqueue_struct *edac_workqueue; * need to export to other files in this modules */ static struct sysdev_class edac_class = { - set_kset_name("edac"), + .name = "edac", }; static int edac_class_valid; diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 69f5dddabddf..5b075da99145 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -162,14 +162,6 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) debugf0("%s()\n", __func__); - /* Set the parent and the instance's ktype */ - pci->kobj.parent = &edac_pci_top_main_kobj; - pci->kobj.ktype = &ktype_pci_instance; - - err = kobject_set_name(&pci->kobj, "pci%d", idx); - if (err) - return err; - /* First bump the ref count on the top main kobj, which will * track the number of PCI instances we have, and thus nest * properly on keeping the module loaded @@ -181,7 +173,8 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) } /* And now register this new kobject under the main kobj */ - err = kobject_register(&pci->kobj); + err = kobject_init_and_add(&pci->kobj, &ktype_pci_instance, + &edac_pci_top_main_kobj, "pci%d", idx); if (err != 0) { debugf2("%s() failed to register instance pci%d\n", __func__, idx); @@ -189,6 +182,7 @@ static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) goto error_out; } + kobject_uevent(&pci->kobj, KOBJ_ADD); debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx); return 0; @@ -211,7 +205,7 @@ void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci) * function release the main reference count and then * kfree the memory */ - kobject_unregister(&pci->kobj); + kobject_put(&pci->kobj); } /***************************** EDAC PCI sysfs root **********************/ @@ -364,14 +358,6 @@ int edac_pci_main_kobj_setup(void) goto decrement_count_fail; } - /* Need the kobject hook ups, and name setting */ - edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj; - edac_pci_top_main_kobj.parent = &edac_class->kset.kobj; - - err = kobject_set_name(&edac_pci_top_main_kobj, "pci"); - if (err) - goto decrement_count_fail; - /* Bump the reference count on this module to ensure the * modules isn't unloaded until we deconstruct the top * level main kobj for EDAC PCI @@ -383,23 +369,24 @@ int edac_pci_main_kobj_setup(void) } /* Instanstiate the pci object */ - /* FIXME: maybe new sysdev_create_subdir() */ - err = kobject_register(&edac_pci_top_main_kobj); + err = kobject_init_and_add(&edac_pci_top_main_kobj, &ktype_edac_pci_main_kobj, + &edac_class->kset.kobj, "pci"); if (err) { debugf1("Failed to register '.../edac/pci'\n"); - goto kobject_register_fail; + goto kobject_init_and_add_fail; } /* At this point, to 'release' the top level kobject * for EDAC PCI, then edac_pci_main_kobj_teardown() * must be used, for resources to be cleaned up properly */ + kobject_uevent(&edac_pci_top_main_kobj, KOBJ_ADD); debugf1("Registered '.../edac/pci' kobject\n"); return 0; /* Error unwind statck */ -kobject_register_fail: +kobject_init_and_add_fail: module_put(THIS_MODULE); decrement_count_fail: @@ -424,9 +411,9 @@ static void edac_pci_main_kobj_teardown(void) * main kobj */ if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) { - debugf0("%s() called kobject_unregister on main kobj\n", + debugf0("%s() called kobject_put on main kobj\n", __func__); - kobject_unregister(&edac_pci_top_main_kobj); + kobject_put(&edac_pci_top_main_kobj); } } diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c index 624ff3e082f6..c2169d215bf7 100644 --- a/drivers/firewire/fw-sbp2.c +++ b/drivers/firewire/fw-sbp2.c @@ -1238,6 +1238,12 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev) sdev->allow_restart = 1; + /* + * Update the dma alignment (minimum alignment requirements for + * start and end of DMA transfers) to be a sector + */ + blk_queue_update_dma_alignment(sdev->request_queue, 511); + if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36) sdev->inquiry_len = 36; diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index bc132d8f79cb..313c99cbdc62 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -173,8 +173,6 @@ static struct device *dmi_dev; if (dmi_get_system_info(_field)) \ sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr; -extern int dmi_available; - /* In a separate function to keep gcc 3.2 happy - do NOT merge this in dmi_id_init! */ static void __init dmi_id_init_attr_table(void) diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 0cdadea7a40e..9008ed5ef4ce 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -8,6 +8,8 @@ #include <linux/slab.h> #include <asm/dmi.h> +static char dmi_empty_string[] = " "; + static char * __init dmi_string(const struct dmi_header *dm, u8 s) { const u8 *bp = ((u8 *) dm) + dm->length; @@ -21,11 +23,16 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s) } if (*bp != 0) { - str = dmi_alloc(strlen(bp) + 1); + size_t len = strlen(bp)+1; + size_t cmp_len = len > 8 ? 8 : len; + + if (!memcmp(bp, dmi_empty_string, cmp_len)) + return dmi_empty_string; + str = dmi_alloc(len); if (str != NULL) strcpy(str, bp); else - printk(KERN_ERR "dmi_string: out of memory.\n"); + printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len); } } @@ -175,12 +182,23 @@ static void __init dmi_save_devices(const struct dmi_header *dm) } } +static struct dmi_device empty_oem_string_dev = { + .name = dmi_empty_string, +}; + static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) { int i, count = *(u8 *)(dm + 1); struct dmi_device *dev; for (i = 1; i <= count; i++) { + char *devname = dmi_string(dm, i); + + if (!strcmp(devname, dmi_empty_string)) { + list_add(&empty_oem_string_dev.list, &dmi_devices); + continue; + } + dev = dmi_alloc(sizeof(*dev)); if (!dev) { printk(KERN_ERR @@ -189,7 +207,7 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) } dev->type = DMI_DEV_TYPE_OEM_STRING; - dev->name = dmi_string(dm, i); + dev->name = devname; dev->device_data = NULL; list_add(&dev->list, &dmi_devices); @@ -331,9 +349,11 @@ void __init dmi_scan_machine(void) rc = dmi_present(q); if (!rc) { dmi_available = 1; + dmi_iounmap(p, 0x10000); return; } } + dmi_iounmap(p, 0x10000); } out: printk(KERN_INFO "DMI not present or invalid.\n"); } @@ -470,3 +490,11 @@ int dmi_get_year(int field) return year; } +/** + * dmi_get_slot - return dmi_ident[slot] + * @slot: index into dmi_ident[] + */ +char *dmi_get_slot(int slot) +{ + return(dmi_ident[slot]); +} diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 6942e065e609..d168223db159 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -631,7 +631,7 @@ static struct kobj_type edd_ktype = { .default_attrs = def_attrs, }; -static decl_subsys(edd, &edd_ktype, NULL); +static struct kset *edd_kset; /** @@ -693,7 +693,7 @@ edd_create_symlink_to_pcidev(struct edd_device *edev) static inline void edd_device_unregister(struct edd_device *edev) { - kobject_unregister(&edev->kobj); + kobject_put(&edev->kobj); } static void edd_populate_dir(struct edd_device * edev) @@ -721,12 +721,13 @@ edd_device_register(struct edd_device *edev, int i) if (!edev) return 1; edd_dev_set_info(edev, i); - kobject_set_name(&edev->kobj, "int13_dev%02x", - 0x80 + i); - kobj_set_kset_s(edev,edd_subsys); - error = kobject_register(&edev->kobj); - if (!error) + edev->kobj.kset = edd_kset; + error = kobject_init_and_add(&edev->kobj, &edd_ktype, NULL, + "int13_dev%02x", 0x80 + i); + if (!error) { edd_populate_dir(edev); + kobject_uevent(&edev->kobj, KOBJ_ADD); + } return error; } @@ -755,9 +756,9 @@ edd_init(void) return 1; } - rc = firmware_register(&edd_subsys); - if (rc) - return rc; + edd_kset = kset_create_and_add("edd", NULL, firmware_kobj); + if (!edd_kset) + return -ENOMEM; for (i = 0; i < edd_num_devices() && !rc; i++) { edev = kzalloc(sizeof (*edev), GFP_KERNEL); @@ -773,7 +774,7 @@ edd_init(void) } if (rc) - firmware_unregister(&edd_subsys); + kset_unregister(edd_kset); return rc; } @@ -787,7 +788,7 @@ edd_exit(void) if ((edev = edd_devices[i])) edd_device_unregister(edev); } - firmware_unregister(&edd_subsys); + kset_unregister(edd_kset); } late_initcall(edd_init); diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 858a7b95933b..f4f709d1370b 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -129,13 +129,6 @@ struct efivar_attribute { }; -#define EFI_ATTR(_name, _mode, _show, _store) \ -struct subsys_attribute efi_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode}, \ - .show = _show, \ - .store = _store, \ -}; - #define EFIVAR_ATTR(_name, _mode, _show, _store) \ struct efivar_attribute efivar_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode}, \ @@ -143,13 +136,6 @@ struct efivar_attribute efivar_attr_##_name = { \ .store = _store, \ }; -#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \ -struct subsys_attribute var_subsys_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode}, \ - .show = _show, \ - .store = _store, \ -}; - #define to_efivar_attr(_attr) container_of(_attr, struct efivar_attribute, attr) #define to_efivar_entry(obj) container_of(obj, struct efivar_entry, kobj) @@ -408,21 +394,16 @@ static struct kobj_type efivar_ktype = { .default_attrs = def_attrs, }; -static ssize_t -dummy(struct kset *kset, char *buf) -{ - return -ENODEV; -} - static inline void efivar_unregister(struct efivar_entry *var) { - kobject_unregister(&var->kobj); + kobject_put(&var->kobj); } -static ssize_t -efivar_create(struct kset *kset, const char *buf, size_t count) +static ssize_t efivar_create(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) { struct efi_variable *new_var = (struct efi_variable *)buf; struct efivar_entry *search_efivar, *n; @@ -479,8 +460,9 @@ efivar_create(struct kset *kset, const char *buf, size_t count) return count; } -static ssize_t -efivar_delete(struct kset *kset, const char *buf, size_t count) +static ssize_t efivar_delete(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) { struct efi_variable *del_var = (struct efi_variable *)buf; struct efivar_entry *search_efivar, *n; @@ -537,25 +519,26 @@ efivar_delete(struct kset *kset, const char *buf, size_t count) return count; } -static VAR_SUBSYS_ATTR(new_var, 0200, dummy, efivar_create); -static VAR_SUBSYS_ATTR(del_var, 0200, dummy, efivar_delete); +static struct bin_attribute var_subsys_attr_new_var = { + .attr = {.name = "new_var", .mode = 0200}, + .write = efivar_create, +}; -static struct subsys_attribute *var_subsys_attrs[] = { - &var_subsys_attr_new_var, - &var_subsys_attr_del_var, - NULL, +static struct bin_attribute var_subsys_attr_del_var = { + .attr = {.name = "del_var", .mode = 0200}, + .write = efivar_delete, }; /* * Let's not leave out systab information that snuck into * the efivars driver */ -static ssize_t -systab_read(struct kset *kset, char *buf) +static ssize_t systab_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *str = buf; - if (!kset || !buf) + if (!kobj || !buf) return -EINVAL; if (efi.mps != EFI_INVALID_TABLE_ADDR) @@ -576,15 +559,21 @@ systab_read(struct kset *kset, char *buf) return str - buf; } -static EFI_ATTR(systab, 0400, systab_read, NULL); +static struct kobj_attribute efi_attr_systab = + __ATTR(systab, 0400, systab_show, NULL); -static struct subsys_attribute *efi_subsys_attrs[] = { - &efi_attr_systab, +static struct attribute *efi_subsys_attrs[] = { + &efi_attr_systab.attr, NULL, /* maybe more in the future? */ }; -static decl_subsys(vars, &efivar_ktype, NULL); -static decl_subsys(efi, NULL, NULL); +static struct attribute_group efi_subsys_attr_group = { + .attrs = efi_subsys_attrs, +}; + + +static struct kset *vars_kset; +static struct kobject *efi_kobj; /* * efivar_create_sysfs_entry() @@ -628,15 +617,16 @@ efivar_create_sysfs_entry(unsigned long variable_name_size, *(short_name + strlen(short_name)) = '-'; efi_guid_unparse(vendor_guid, short_name + strlen(short_name)); - kobject_set_name(&new_efivar->kobj, "%s", short_name); - kobj_set_kset_s(new_efivar, vars_subsys); - i = kobject_register(&new_efivar->kobj); + new_efivar->kobj.kset = vars_kset; + i = kobject_init_and_add(&new_efivar->kobj, &efivar_ktype, NULL, + "%s", short_name); if (i) { kfree(short_name); kfree(new_efivar); return 1; } + kobject_uevent(&new_efivar->kobj, KOBJ_ADD); kfree(short_name); short_name = NULL; @@ -660,9 +650,8 @@ efivars_init(void) efi_status_t status = EFI_NOT_FOUND; efi_guid_t vendor_guid; efi_char16_t *variable_name; - struct subsys_attribute *attr; unsigned long variable_name_size = 1024; - int i, error = 0; + int error = 0; if (!efi_enabled) return -ENODEV; @@ -676,23 +665,18 @@ efivars_init(void) printk(KERN_INFO "EFI Variables Facility v%s %s\n", EFIVARS_VERSION, EFIVARS_DATE); - /* - * For now we'll register the efi subsys within this driver - */ - - error = firmware_register(&efi_subsys); - - if (error) { - printk(KERN_ERR "efivars: Firmware registration failed with error %d.\n", error); + /* For now we'll register the efi directory at /sys/firmware/efi */ + efi_kobj = kobject_create_and_add("efi", firmware_kobj); + if (!efi_kobj) { + printk(KERN_ERR "efivars: Firmware registration failed.\n"); + error = -ENOMEM; goto out_free; } - kobj_set_kset_s(&vars_subsys, efi_subsys); - - error = subsystem_register(&vars_subsys); - - if (error) { - printk(KERN_ERR "efivars: Subsystem registration failed with error %d.\n", error); + vars_kset = kset_create_and_add("vars", NULL, efi_kobj); + if (!vars_kset) { + printk(KERN_ERR "efivars: Subsystem registration failed.\n"); + error = -ENOMEM; goto out_firmware_unregister; } @@ -727,28 +711,28 @@ efivars_init(void) * Now add attributes to allow creation of new vars * and deletion of existing ones... */ - - for (i = 0; (attr = var_subsys_attrs[i]) && !error; i++) { - if (attr->show && attr->store) - error = subsys_create_file(&vars_subsys, attr); - } + error = sysfs_create_bin_file(&vars_kset->kobj, + &var_subsys_attr_new_var); + if (error) + printk(KERN_ERR "efivars: unable to create new_var sysfs file" + " due to error %d\n", error); + error = sysfs_create_bin_file(&vars_kset->kobj, + &var_subsys_attr_del_var); + if (error) + printk(KERN_ERR "efivars: unable to create del_var sysfs file" + " due to error %d\n", error); /* Don't forget the systab entry */ - - for (i = 0; (attr = efi_subsys_attrs[i]) && !error; i++) { - if (attr->show) - error = subsys_create_file(&efi_subsys, attr); - } - + error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); if (error) printk(KERN_ERR "efivars: Sysfs attribute export failed with error %d.\n", error); else goto out_free; - subsystem_unregister(&vars_subsys); + kset_unregister(vars_kset); out_firmware_unregister: - firmware_unregister(&efi_subsys); + kobject_put(efi_kobj); out_free: kfree(variable_name); @@ -768,8 +752,8 @@ efivars_exit(void) efivar_unregister(entry); } - subsystem_unregister(&vars_subsys); - firmware_unregister(&efi_subsys); + kset_unregister(vars_kset); + kobject_put(efi_kobj); } module_init(efivars_init); diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1ac5103f7c93..275dc522c738 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -1,7 +1,7 @@ # # Makefile for the HID driver # -hid-objs := hid-core.o hid-input.o +hid-objs := hid-core.o hid-input.o hid-input-quirks.o obj-$(CONFIG_HID) += hid.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2884b036495a..d73a768e176e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -26,6 +26,7 @@ #include <linux/input.h> #include <linux/wait.h> #include <linux/vmalloc.h> +#include <linux/sched.h> #include <linux/hid.h> #include <linux/hiddev.h> @@ -758,7 +759,9 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) { u64 x; - WARN_ON(n > 32); + if (n > 32) + printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n", + n, current->comm); report += offset >> 3; /* adjust byte index */ offset &= 7; /* now only need bit offset into one byte */ @@ -780,8 +783,13 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3 __le64 x; u64 m = (1ULL << n) - 1; - WARN_ON(n > 32); + if (n > 32) + printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n", + n, current->comm); + if (value > m) + printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n", + value, current->comm); WARN_ON(value > m); value &= m; diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c new file mode 100644 index 000000000000..a870ba58faa3 --- /dev/null +++ b/drivers/hid/hid-input-quirks.c @@ -0,0 +1,423 @@ +/* + * HID-input usage mapping quirks + * + * This is used to handle HID-input mappings for devices violating + * HUT 1.12 specification. + * + * Copyright (c) 2007-2008 Jiri Kosina + */ + +/* + * 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 + */ + +#include <linux/input.h> +#include <linux/hid.h> + +#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; *bit = input->absbit; *max = ABS_MAX; } while (0) +#define map_rel(c) do { usage->code = c; usage->type = EV_REL; *bit = input->relbit; *max = REL_MAX; } while (0) +#define map_key(c) do { usage->code = c; usage->type = EV_KEY; *bit = input->keybit; *max = KEY_MAX; } while (0) +#define map_led(c) do { usage->code = c; usage->type = EV_LED; *bit = input->ledbit; *max = LED_MAX; } while (0) + +#define map_abs_clear(c) do { map_abs(c); clear_bit(c, *bit); } while (0) +#define map_key_clear(c) do { map_key(c); clear_bit(c, *bit); } while (0) + +static int quirk_belkin_wkbd(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x03a: map_key_clear(KEY_SOUND); break; + case 0x03b: map_key_clear(KEY_CAMERA); break; + case 0x03c: map_key_clear(KEY_DOCUMENTS); break; + default: + return 0; + } + return 1; +} + +static int quirk_cherry_cymotion(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x301: map_key_clear(KEY_PROG1); break; + case 0x302: map_key_clear(KEY_PROG2); break; + case 0x303: map_key_clear(KEY_PROG3); break; + default: + return 0; + } + return 1; +} + +static int quirk_logitech_ultrax_remote(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) + return 0; + + set_bit(EV_REP, input->evbit); + switch(usage->hid & HID_USAGE) { + /* Reported on Logitech Ultra X Media Remote */ + case 0x004: map_key_clear(KEY_AGAIN); break; + case 0x00d: map_key_clear(KEY_HOME); break; + case 0x024: map_key_clear(KEY_SHUFFLE); break; + case 0x025: map_key_clear(KEY_TV); break; + case 0x026: map_key_clear(KEY_MENU); break; + case 0x031: map_key_clear(KEY_AUDIO); break; + case 0x032: map_key_clear(KEY_TEXT); break; + case 0x033: map_key_clear(KEY_LAST); break; + case 0x047: map_key_clear(KEY_MP3); break; + case 0x048: map_key_clear(KEY_DVD); break; + case 0x049: map_key_clear(KEY_MEDIA); break; + case 0x04a: map_key_clear(KEY_VIDEO); break; + case 0x04b: map_key_clear(KEY_ANGLE); break; + case 0x04c: map_key_clear(KEY_LANGUAGE); break; + case 0x04d: map_key_clear(KEY_SUBTITLE); break; + case 0x051: map_key_clear(KEY_RED); break; + case 0x052: map_key_clear(KEY_CLOSE); break; + + default: + return 0; + } + return 1; +} + +static int quirk_chicony_tactical_pad(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + + set_bit(EV_REP, input->evbit); + switch (usage->hid & HID_USAGE) { + case 0xff01: map_key_clear(BTN_1); break; + case 0xff02: map_key_clear(BTN_2); break; + case 0xff03: map_key_clear(BTN_3); break; + case 0xff04: map_key_clear(BTN_4); break; + case 0xff05: map_key_clear(BTN_5); break; + case 0xff06: map_key_clear(BTN_6); break; + case 0xff07: map_key_clear(BTN_7); break; + case 0xff08: map_key_clear(BTN_8); break; + case 0xff09: map_key_clear(BTN_9); break; + case 0xff0a: map_key_clear(BTN_A); break; + case 0xff0b: map_key_clear(BTN_B); break; + default: + return 0; + } + return 1; +} + +static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + + switch(usage->hid & HID_USAGE) { + case 0xfd06: map_key_clear(KEY_CHAT); break; + case 0xfd07: map_key_clear(KEY_PHONE); break; + case 0xff05: + set_bit(EV_REP, input->evbit); + map_key_clear(KEY_F13); + set_bit(KEY_F14, input->keybit); + set_bit(KEY_F15, input->keybit); + set_bit(KEY_F16, input->keybit); + set_bit(KEY_F17, input->keybit); + set_bit(KEY_F18, input->keybit); + default: + return 0; + } + return 1; +} + +static int quirk_microsoft_presenter_8k(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR) + return 0; + + set_bit(EV_REP, input->evbit); + switch(usage->hid & HID_USAGE) { + case 0xfd08: map_key_clear(KEY_FORWARD); break; + case 0xfd09: map_key_clear(KEY_BACK); break; + case 0xfd0b: map_key_clear(KEY_PLAYPAUSE); break; + case 0xfd0e: map_key_clear(KEY_CLOSE); break; + case 0xfd0f: map_key_clear(KEY_PLAY); break; + default: + return 0; + } + return 1; +} + +static int quirk_petalynx_remote(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) && + ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)) + return 0; + + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) + switch(usage->hid & HID_USAGE) { + case 0x05a: map_key_clear(KEY_TEXT); break; + case 0x05b: map_key_clear(KEY_RED); break; + case 0x05c: map_key_clear(KEY_GREEN); break; + case 0x05d: map_key_clear(KEY_YELLOW); break; + case 0x05e: map_key_clear(KEY_BLUE); break; + default: + return 0; + } + + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) + switch(usage->hid & HID_USAGE) { + case 0x0f6: map_key_clear(KEY_NEXT); break; + case 0x0fa: map_key_clear(KEY_BACK); break; + default: + return 0; + } + return 1; +} + +static int quirk_logitech_wireless(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x1001: map_key_clear(KEY_MESSENGER); break; + case 0x1003: map_key_clear(KEY_SOUND); break; + case 0x1004: map_key_clear(KEY_VIDEO); break; + case 0x1005: map_key_clear(KEY_AUDIO); break; + case 0x100a: map_key_clear(KEY_DOCUMENTS); break; + case 0x1011: map_key_clear(KEY_PREVIOUSSONG); break; + case 0x1012: map_key_clear(KEY_NEXTSONG); break; + case 0x1013: map_key_clear(KEY_CAMERA); break; + case 0x1014: map_key_clear(KEY_MESSENGER); break; + case 0x1015: map_key_clear(KEY_RECORD); break; + case 0x1016: map_key_clear(KEY_PLAYER); break; + case 0x1017: map_key_clear(KEY_EJECTCD); break; + case 0x1018: map_key_clear(KEY_MEDIA); break; + case 0x1019: map_key_clear(KEY_PROG1); break; + case 0x101a: map_key_clear(KEY_PROG2); break; + case 0x101b: map_key_clear(KEY_PROG3); break; + case 0x101f: map_key_clear(KEY_ZOOMIN); break; + case 0x1020: map_key_clear(KEY_ZOOMOUT); break; + case 0x1021: map_key_clear(KEY_ZOOMRESET); break; + case 0x1023: map_key_clear(KEY_CLOSE); break; + case 0x1027: map_key_clear(KEY_MENU); break; + /* this one is marked as 'Rotate' */ + case 0x1028: map_key_clear(KEY_ANGLE); break; + case 0x1029: map_key_clear(KEY_SHUFFLE); break; + case 0x102a: map_key_clear(KEY_BACK); break; + case 0x102b: map_key_clear(KEY_CYCLEWINDOWS); break; + case 0x1041: map_key_clear(KEY_BATTERY); break; + case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break; + case 0x1043: map_key_clear(KEY_SPREADSHEET); break; + case 0x1044: map_key_clear(KEY_PRESENTATION); break; + case 0x1045: map_key_clear(KEY_UNDO); break; + case 0x1046: map_key_clear(KEY_REDO); break; + case 0x1047: map_key_clear(KEY_PRINT); break; + case 0x1048: map_key_clear(KEY_SAVE); break; + case 0x1049: map_key_clear(KEY_PROG1); break; + case 0x104a: map_key_clear(KEY_PROG2); break; + case 0x104b: map_key_clear(KEY_PROG3); break; + case 0x104c: map_key_clear(KEY_PROG4); break; + + default: + return 0; + } + return 1; +} + +static int quirk_cherry_genius_29e(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x156: map_key_clear(KEY_WORDPROCESSOR); break; + case 0x157: map_key_clear(KEY_SPREADSHEET); break; + case 0x158: map_key_clear(KEY_PRESENTATION); break; + case 0x15c: map_key_clear(KEY_STOP); break; + + default: + return 0; + } + return 1; +} + +static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) + return 0; + + switch (usage->hid & HID_USAGE) { + case 0x230: map_key(BTN_MOUSE); break; + case 0x231: map_rel(REL_WHEEL); break; + /* + * this keyboard has a scrollwheel implemented in + * totally broken way. We map this usage temporarily + * to HWHEEL and handle it in the event quirk handler + */ + case 0x232: map_rel(REL_HWHEEL); break; + + default: + return 0; + } + return 1; +} + +#define VENDOR_ID_BELKIN 0x1020 +#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006 + +#define VENDOR_ID_CHERRY 0x046a +#define DEVICE_ID_CHERRY_CYMOTION 0x0023 + +#define VENDOR_ID_CHICONY 0x04f2 +#define DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 + +#define VENDOR_ID_EZKEY 0x0518 +#define DEVICE_ID_BTC_8193 0x0002 + +#define VENDOR_ID_LOGITECH 0x046d +#define DEVICE_ID_LOGITECH_RECEIVER 0xc101 +#define DEVICE_ID_S510_RECEIVER 0xc50c +#define DEVICE_ID_S510_RECEIVER_2 0xc517 +#define DEVICE_ID_MX3000_RECEIVER 0xc513 + +#define VENDOR_ID_MICROSOFT 0x045e +#define DEVICE_ID_MS4K 0x00db +#define DEVICE_ID_MS6K 0x00f9 +#define DEVICE_IS_MS_PRESENTER_8K_BT 0x0701 +#define DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 + +#define VENDOR_ID_MONTEREY 0x0566 +#define DEVICE_ID_GENIUS_KB29E 0x3004 + +#define VENDOR_ID_PETALYNX 0x18b1 +#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 + +static const struct hid_input_blacklist { + __u16 idVendor; + __u16 idProduct; + int (*quirk)(struct hid_usage *, struct input_dev *, unsigned long **, int *); +} hid_input_blacklist[] = { + { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd }, + + { VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion }, + + { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad }, + + { VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 }, + + { VENDOR_ID_LOGITECH, DEVICE_ID_LOGITECH_RECEIVER, quirk_logitech_ultrax_remote }, + { VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER, quirk_logitech_wireless }, + { VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER_2, quirk_logitech_wireless }, + { VENDOR_ID_LOGITECH, DEVICE_ID_MX3000_RECEIVER, quirk_logitech_wireless }, + + { VENDOR_ID_MICROSOFT, DEVICE_ID_MS4K, quirk_microsoft_ergonomy_kb }, + { VENDOR_ID_MICROSOFT, DEVICE_ID_MS6K, quirk_microsoft_ergonomy_kb }, + { VENDOR_ID_MICROSOFT, DEVICE_IS_MS_PRESENTER_8K_BT, quirk_microsoft_presenter_8k }, + { VENDOR_ID_MICROSOFT, DEVICE_ID_MS_PRESENTER_8K_USB, quirk_microsoft_presenter_8k }, + + { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e }, + + { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote }, + + { 0, 0, 0 } +}; + +int hidinput_mapping_quirks(struct hid_usage *usage, + struct input_dev *input, + unsigned long **bit, int *max) +{ + struct hid_device *device = input_get_drvdata(input); + int i = 0; + + while (hid_input_blacklist[i].quirk) { + if (hid_input_blacklist[i].idVendor == device->vendor && + hid_input_blacklist[i].idProduct == device->product) + return hid_input_blacklist[i].quirk(usage, input, bit, max); + i++; + } + return 0; +} + +void hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) +{ + struct input_dev *input; + + input = field->hidinput->input; + + if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) + || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { + if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; + else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; + return; + } + + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && + (usage->type == EV_REL) && + (usage->code == REL_WHEEL)) { + hid->delayed_value = value; + return; + } + + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && + (usage->hid == 0x000100b8)) { + input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value); + return; + } + + if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { + input_event(input, usage->type, usage->code, -value); + return; + } + + if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { + input_event(input, usage->type, REL_HWHEEL, value); + return; + } + + if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value)) + return; + + /* Handling MS keyboards special buttons */ + if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && + usage->hid == (HID_UP_MSVENDOR | 0xff05)) { + int key = 0; + static int last_key = 0; + switch (value) { + case 0x01: key = KEY_F14; break; + case 0x02: key = KEY_F15; break; + case 0x04: key = KEY_F16; break; + case 0x08: key = KEY_F17; break; + case 0x10: key = KEY_F18; break; + default: break; + } + if (key) { + input_event(input, usage->type, key, 1); + last_key = key; + } else { + input_event(input, usage->type, last_key, 0); + } + } + + /* handle the temporary quirky mapping to HWHEEL */ + if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT && + usage->type == EV_REL && usage->code == REL_HWHEEL) { + input_event(input, usage->type, REL_WHEEL, -value); + return; + } +} + + diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 0b27da7d7497..5325d98b4328 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -34,10 +34,10 @@ #include <linux/hid.h> #include <linux/hid-debug.h> -static int hid_pb_fnmode = 1; -module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644); +static int hid_apple_fnmode = 1; +module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644); MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); + "Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); #define unk KEY_UNKNOWN @@ -86,10 +86,6 @@ static const struct { #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) -/* hardware needing special handling due to colliding MSVENDOR page usages */ -#define IS_CHICONY_TACTICAL_PAD(x) (x->vendor == 0x04f2 && device->product == 0x0418) -#define IS_MS_KB(x) (x->vendor == 0x045e && (x->product == 0x00db || x->product == 0x00f9)) - #ifdef CONFIG_USB_HIDINPUT_POWERBOOK struct hidinput_key_translation { @@ -98,20 +94,36 @@ struct hidinput_key_translation { u8 flags; }; -#define POWERBOOK_FLAG_FKEY 0x01 +#define APPLE_FLAG_FKEY 0x01 + +static struct hidinput_key_translation apple_fn_keys[] = { + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_CYCLEWINDOWS, APPLE_FLAG_FKEY }, /* Exposé */ + { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */ + { KEY_F5, KEY_FN_F5 }, + { KEY_F6, KEY_FN_F6 }, + { KEY_F7, KEY_BACK, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_FORWARD, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { } +}; static struct hidinput_key_translation powerbook_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY }, - { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY }, - { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY }, - { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY }, - { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY }, - { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY }, - { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, { KEY_UP, KEY_PAGEUP }, { KEY_DOWN, KEY_PAGEDOWN }, { KEY_LEFT, KEY_HOME }, @@ -142,7 +154,7 @@ static struct hidinput_key_translation powerbook_numlock_keys[] = { { } }; -static struct hidinput_key_translation powerbook_iso_keyboard[] = { +static struct hidinput_key_translation apple_iso_keyboard[] = { { KEY_GRAVE, KEY_102ND }, { KEY_102ND, KEY_GRAVE }, { } @@ -160,39 +172,42 @@ static struct hidinput_key_translation *find_translation(struct hidinput_key_tra return NULL; } -static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, +int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, struct hid_usage *usage, __s32 value) { struct hidinput_key_translation *trans; if (usage->code == KEY_FN) { - if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON; - else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON; + if (value) hid->quirks |= HID_QUIRK_APPLE_FN_ON; + else hid->quirks &= ~HID_QUIRK_APPLE_FN_ON; input_event(input, usage->type, usage->code, value); return 1; } - if (hid_pb_fnmode) { + if (hid_apple_fnmode) { int do_translate; - trans = find_translation(powerbook_fn_keys, usage->code); + trans = find_translation((hid->product < 0x220 || + hid->product >= 0x300) ? + powerbook_fn_keys : apple_fn_keys, + usage->code); if (trans) { - if (test_bit(usage->code, hid->pb_pressed_fn)) + if (test_bit(usage->code, hid->apple_pressed_fn)) do_translate = 1; - else if (trans->flags & POWERBOOK_FLAG_FKEY) + else if (trans->flags & APPLE_FLAG_FKEY) do_translate = - (hid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (hid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); + (hid_apple_fnmode == 2 && (hid->quirks & HID_QUIRK_APPLE_FN_ON)) || + (hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON)); else - do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); + do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON); if (do_translate) { if (value) - set_bit(usage->code, hid->pb_pressed_fn); + set_bit(usage->code, hid->apple_pressed_fn); else - clear_bit(usage->code, hid->pb_pressed_fn); + clear_bit(usage->code, hid->apple_pressed_fn); input_event(input, usage->type, trans->to, value); @@ -217,8 +232,8 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, } } - if (hid->quirks & HID_QUIRK_POWERBOOK_ISO_KEYBOARD) { - trans = find_translation(powerbook_iso_keyboard, usage->code); + if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) { + trans = find_translation(apple_iso_keyboard, usage->code); if (trans) { input_event(input, usage->type, trans->to, value); return 1; @@ -228,31 +243,35 @@ static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, return 0; } -static void hidinput_pb_setup(struct input_dev *input) +static void hidinput_apple_setup(struct input_dev *input) { struct hidinput_key_translation *trans; set_bit(KEY_NUMLOCK, input->keybit); /* Enable all needed keys */ + for (trans = apple_fn_keys; trans->from; trans++) + set_bit(trans->to, input->keybit); + for (trans = powerbook_fn_keys; trans->from; trans++) set_bit(trans->to, input->keybit); for (trans = powerbook_numlock_keys; trans->from; trans++) set_bit(trans->to, input->keybit); - for (trans = powerbook_iso_keyboard; trans->from; trans++) + for (trans = apple_iso_keyboard; trans->from; trans++) set_bit(trans->to, input->keybit); } #else -static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) +inline int hidinput_apple_event(struct hid_device *hid, + struct input_dev *input, + struct hid_usage *usage, __s32 value) { return 0; } -static inline void hidinput_pb_setup(struct input_dev *input) +static inline void hidinput_apple_setup(struct input_dev *input) { } #endif @@ -343,7 +362,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel { struct input_dev *input = hidinput->input; struct hid_device *device = input_get_drvdata(input); - int max = 0, code; + int max = 0, code, ret; unsigned long *bit = NULL; field->hidinput = hidinput; @@ -362,6 +381,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel goto ignore; } + /* handle input mappings for quirky devices */ + ret = hidinput_mapping_quirks(usage, input, &bit, &max); + if (ret) + goto mapped; + switch (usage->hid & HID_USAGE_PAGE) { case HID_UP_UNDEFINED: @@ -549,14 +573,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x000: goto ignore; case 0x034: map_key_clear(KEY_SLEEP); break; case 0x036: map_key_clear(BTN_MISC); break; - /* - * The next three are reported by Belkin wireless - * keyboard (1020:0006). These values are "reserved" - * in HUT 1.12. - */ - case 0x03a: map_key_clear(KEY_SOUND); break; - case 0x03b: map_key_clear(KEY_CAMERA); break; - case 0x03c: map_key_clear(KEY_DOCUMENTS); break; case 0x040: map_key_clear(KEY_MENU); break; case 0x045: map_key_clear(KEY_RADIO); break; @@ -602,10 +618,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; - /* reserved in HUT 1.12. Reported on Petalynx remote */ - case 0x0f6: map_key_clear(KEY_NEXT); break; - case 0x0fa: map_key_clear(KEY_BACK); break; - case 0x182: map_key_clear(KEY_BOOKMARKS); break; case 0x183: map_key_clear(KEY_CONFIG); break; case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; @@ -665,51 +677,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; case 0x28c: map_key_clear(KEY_SEND); break; - /* Reported on a Cherry Cymotion keyboard */ - case 0x301: map_key_clear(KEY_PROG1); break; - case 0x302: map_key_clear(KEY_PROG2); break; - case 0x303: map_key_clear(KEY_PROG3); break; - - /* Reported on certain Logitech wireless keyboards */ - case 0x1001: map_key_clear(KEY_MESSENGER); break; - case 0x1003: map_key_clear(KEY_SOUND); break; - case 0x1004: map_key_clear(KEY_VIDEO); break; - case 0x1005: map_key_clear(KEY_AUDIO); break; - case 0x100a: map_key_clear(KEY_DOCUMENTS); break; - case 0x1011: map_key_clear(KEY_PREVIOUSSONG); break; - case 0x1012: map_key_clear(KEY_NEXTSONG); break; - case 0x1013: map_key_clear(KEY_CAMERA); break; - case 0x1014: map_key_clear(KEY_MESSENGER); break; - case 0x1015: map_key_clear(KEY_RECORD); break; - case 0x1016: map_key_clear(KEY_PLAYER); break; - case 0x1017: map_key_clear(KEY_EJECTCD); break; - case 0x1018: map_key_clear(KEY_MEDIA); break; - case 0x1019: map_key_clear(KEY_PROG1); break; - case 0x101a: map_key_clear(KEY_PROG2); break; - case 0x101b: map_key_clear(KEY_PROG3); break; - case 0x101f: map_key_clear(KEY_ZOOMIN); break; - case 0x1020: map_key_clear(KEY_ZOOMOUT); break; - case 0x1021: map_key_clear(KEY_ZOOMRESET); break; - case 0x1023: map_key_clear(KEY_CLOSE); break; - case 0x1027: map_key_clear(KEY_MENU); break; - /* this one is marked as 'Rotate' */ - case 0x1028: map_key_clear(KEY_ANGLE); break; - case 0x1029: map_key_clear(KEY_SHUFFLE); break; - case 0x102a: map_key_clear(KEY_BACK); break; - case 0x102b: map_key_clear(KEY_CYCLEWINDOWS); break; - case 0x1041: map_key_clear(KEY_BATTERY); break; - case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break; - case 0x1043: map_key_clear(KEY_SPREADSHEET); break; - case 0x1044: map_key_clear(KEY_PRESENTATION); break; - case 0x1045: map_key_clear(KEY_UNDO); break; - case 0x1046: map_key_clear(KEY_REDO); break; - case 0x1047: map_key_clear(KEY_PRINT); break; - case 0x1048: map_key_clear(KEY_SAVE); break; - case 0x1049: map_key_clear(KEY_PROG1); break; - case 0x104a: map_key_clear(KEY_PROG2); break; - case 0x104b: map_key_clear(KEY_PROG3); break; - case 0x104c: map_key_clear(KEY_PROG4); break; - default: goto ignore; } break; @@ -736,63 +703,16 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_MSVENDOR: - /* Unfortunately, there are multiple devices which - * emit usages from MSVENDOR page that require different - * handling. If this list grows too much in the future, - * more general handling will have to be introduced here - * (i.e. another blacklist). - */ - - /* Chicony Chicony KU-0418 tactical pad */ - if (IS_CHICONY_TACTICAL_PAD(device)) { - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0xff01: map_key_clear(BTN_1); break; - case 0xff02: map_key_clear(BTN_2); break; - case 0xff03: map_key_clear(BTN_3); break; - case 0xff04: map_key_clear(BTN_4); break; - case 0xff05: map_key_clear(BTN_5); break; - case 0xff06: map_key_clear(BTN_6); break; - case 0xff07: map_key_clear(BTN_7); break; - case 0xff08: map_key_clear(BTN_8); break; - case 0xff09: map_key_clear(BTN_9); break; - case 0xff0a: map_key_clear(BTN_A); break; - case 0xff0b: map_key_clear(BTN_B); break; - default: goto ignore; - } - - /* Microsoft Natural Ergonomic Keyboard 4000 */ - } else if (IS_MS_KB(device)) { - switch(usage->hid & HID_USAGE) { - case 0xfd06: - map_key_clear(KEY_CHAT); - break; - case 0xfd07: - map_key_clear(KEY_PHONE); - break; - case 0xff05: - set_bit(EV_REP, input->evbit); - map_key_clear(KEY_F13); - set_bit(KEY_F14, input->keybit); - set_bit(KEY_F15, input->keybit); - set_bit(KEY_F16, input->keybit); - set_bit(KEY_F17, input->keybit); - set_bit(KEY_F18, input->keybit); - default: goto ignore; - } - } else { - goto ignore; - } - break; + goto ignore; - case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ + case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */ set_bit(EV_REP, input->evbit); switch(usage->hid & HID_USAGE) { case 0x003: - /* The fn key on Apple PowerBooks */ + /* The fn key on Apple USB keyboards */ map_key_clear(KEY_FN); - hidinput_pb_setup(input); + hidinput_apple_setup(input); break; default: goto ignore; @@ -800,38 +720,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; case HID_UP_LOGIVENDOR: - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - /* Reported on Logitech Ultra X Media Remote */ - case 0x004: map_key_clear(KEY_AGAIN); break; - case 0x00d: map_key_clear(KEY_HOME); break; - case 0x024: map_key_clear(KEY_SHUFFLE); break; - case 0x025: map_key_clear(KEY_TV); break; - case 0x026: map_key_clear(KEY_MENU); break; - case 0x031: map_key_clear(KEY_AUDIO); break; - case 0x032: map_key_clear(KEY_TEXT); break; - case 0x033: map_key_clear(KEY_LAST); break; - case 0x047: map_key_clear(KEY_MP3); break; - case 0x048: map_key_clear(KEY_DVD); break; - case 0x049: map_key_clear(KEY_MEDIA); break; - case 0x04a: map_key_clear(KEY_VIDEO); break; - case 0x04b: map_key_clear(KEY_ANGLE); break; - case 0x04c: map_key_clear(KEY_LANGUAGE); break; - case 0x04d: map_key_clear(KEY_SUBTITLE); break; - case 0x051: map_key_clear(KEY_RED); break; - case 0x052: map_key_clear(KEY_CLOSE); break; - - /* Reported on Petalynx Maxter remote */ - case 0x05a: map_key_clear(KEY_TEXT); break; - case 0x05b: map_key_clear(KEY_RED); break; - case 0x05c: map_key_clear(KEY_GREEN); break; - case 0x05d: map_key_clear(KEY_YELLOW); break; - case 0x05e: map_key_clear(KEY_BLUE); break; - - default: goto ignore; - } - break; + goto ignore; + case HID_UP_PID: switch(usage->hid & HID_USAGE) { @@ -858,6 +749,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel break; } +mapped: if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { if (usage->hid == HID_GD_Z) map_rel(REL_HWHEEL); @@ -867,9 +759,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_key(BTN_1); } - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && - (usage->type == EV_REL) && (usage->code == REL_WHEEL)) - set_bit(REL_HWHEEL, bit); + if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 | + HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) && + (usage->code == REL_WHEEL)) + set_bit(REL_HWHEEL, bit); if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) @@ -960,25 +853,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct if (!usage->type) return; - if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { - if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - return; - } - - if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { - input_event(input, usage->type, usage->code, -value); - return; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { - input_event(input, usage->type, REL_HWHEEL, value); - return; - } - - if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) - return; + /* handle input events for quirky devices */ + hidinput_event_quirks(hid, field, usage, value); if (usage->hat_min < usage->hat_max || usage->hat_dir) { int hat_dir = usage->hat_dir; @@ -1039,25 +915,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } - /* Handling MS keyboards special buttons */ - if (IS_MS_KB(hid) && usage->hid == (HID_UP_MSVENDOR | 0xff05)) { - int key = 0; - static int last_key = 0; - switch (value) { - case 0x01: key = KEY_F14; break; - case 0x02: key = KEY_F15; break; - case 0x04: key = KEY_F16; break; - case 0x08: key = KEY_F17; break; - case 0x10: key = KEY_F18; break; - default: break; - } - if (key) { - input_event(input, usage->type, key, 1); - last_key = key; - } else { - input_event(input, usage->type, last_key, 0); - } - } /* report the usage code as scancode if the key status has changed */ if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index c557d7040a69..7160fa65d79b 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -25,12 +25,13 @@ comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB_HID && INPUT=n config USB_HIDINPUT_POWERBOOK - bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys" + bool "Enable support for Apple laptop/aluminum USB special keys" default n depends on USB_HID help Say Y here if you want support for the special keys (Fn, Numlock) on - Apple iBooks, PowerBooks, MacBooks and MacBook Pros. + Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB + keyboards. If unsure, say N. diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index a2552856476b..b77b61e0cd7b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -19,6 +19,7 @@ #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 +#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a #define USB_VENDOR_ID_AASHIMA 0x06d6 #define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 @@ -28,6 +29,9 @@ #define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 #define USB_DEVICE_ID_ACECAD_302 0x0008 +#define USB_VENDOR_ID_ADS_TECH 0x06e1 +#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 + #define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_DEVICE_ID_AIPTEK_01 0x0001 #define USB_DEVICE_ID_AIPTEK_10 0x0010 @@ -59,6 +63,9 @@ #define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a #define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b #define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c +#define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220 +#define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221 +#define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 @@ -94,6 +101,9 @@ #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff +#define USB_VENDOR_ID_CYGNAL 0x10c4 +#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a + #define USB_VENDOR_ID_CYPRESS 0x04b4 #define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 #define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 @@ -114,6 +124,9 @@ #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 +#define USB_VENDOR_ID_EZKEY 0x0518 +#define USB_DEVICE_ID_BTC_8193 0x0002 + #define USB_VENDOR_ID_GAMERON 0x0810 #define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 @@ -134,6 +147,9 @@ #define USB_DEVICE_ID_GOGOPEN 0x00ce #define USB_DEVICE_ID_PENPOWER 0x00f4 +#define USB_VENDOR_ID_GRETAGMACBETH 0x0971 +#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005 + #define USB_VENDOR_ID_GRIFFIN 0x077d #define USB_DEVICE_ID_POWERMATE 0x0410 #define USB_DEVICE_ID_SOUNDKNOB 0x04AA @@ -278,7 +294,9 @@ #define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d #define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e #define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f +#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 #define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 +#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a #define USB_DEVICE_ID_LOGITECH_KBD 0xc311 #define USB_DEVICE_ID_S510_RECEIVER 0xc50c #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 @@ -296,6 +314,12 @@ #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b +#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d +#define USB_DEVICE_ID_MS_NE4K 0x00db +#define USB_DEVICE_ID_MS_LK6K 0x00f9 + +#define USB_VENDOR_ID_MONTEREY 0x0566 +#define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_NCR 0x0404 #define USB_DEVICE_ID_NCR_FIRST 0x0300 @@ -324,6 +348,9 @@ #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 +#define USB_VENDOR_ID_SAMSUNG 0x0419 +#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 + #define USB_VENDOR_ID_SONY 0x054c #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 @@ -368,6 +395,7 @@ static const struct hid_blacklist { } hid_blacklist[] = { { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 }, + { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, @@ -390,6 +418,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT }, + { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT }, + + { USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE }, @@ -402,6 +433,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE}, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, @@ -423,6 +455,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE }, @@ -516,14 +549,18 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER }, + { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, @@ -531,7 +568,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, @@ -540,19 +579,22 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS }, @@ -638,10 +680,14 @@ static const struct hid_rdesc_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH }, + { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS }, { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX }, + { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE }, + { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX }, @@ -884,6 +930,8 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct) return quirks; } +EXPORT_SYMBOL_GPL(usbhid_lookup_quirk); + /* * Cherry Cymotion keyboard have an invalid HID report descriptor, * that needs fixing before we can parse it. @@ -914,6 +962,33 @@ static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize) } } +/* + * Samsung IrDA remote controller (reports as Cypress USB Mouse). + * + * Vendor specific report #4 has a size of 48 bit, + * and therefore is not accepted when inspecting the descriptors. + * As a workaround we reinterpret the report as: + * Variable type, count 6, size 8 bit, log. maximum 255 + * The burden to reconstruct the data is moved into user space. + */ +static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc, + int rsize) +{ + if (rsize >= 182 && rdesc[175] == 0x25 + && rdesc[176] == 0x40 + && rdesc[177] == 0x75 + && rdesc[178] == 0x30 + && rdesc[179] == 0x95 + && rdesc[180] == 0x01 + && rdesc[182] == 0x40) { + printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n"); + rdesc[176] = 0xff; + rdesc[178] = 0x08; + rdesc[180] = 0x06; + rdesc[182] = 0x42; + } +} + /* Petalynx Maxter Remote has maximum for consumer page set too low */ static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize) { @@ -965,6 +1040,14 @@ static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize) } } +static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize >= 30 && rdesc[29] == 0x05 + && rdesc[30] == 0x09) { + printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n"); + rdesc[30] = 0x0c; + } +} static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize) { @@ -982,6 +1065,13 @@ static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS) usbhid_fixup_macbook_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER) + usbhid_fixup_button_consumer_descriptor(rdesc, rsize); + + if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE) + usbhid_fixup_samsung_irda_descriptor(rdesc, rsize); + } /** diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c index 69882a726e99..144578b1a00c 100644 --- a/drivers/hid/usbhid/hid-tmff.c +++ b/drivers/hid/usbhid/hid-tmff.c @@ -137,7 +137,8 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef int hid_tmff_init(struct hid_device *hid) { struct tmff_device *tmff; - struct list_head *pos; + struct hid_report *report; + struct list_head *report_list; struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *input_dev = hidinput->input; const signed short *ff_bits = ff_joystick; @@ -149,8 +150,8 @@ int hid_tmff_init(struct hid_device *hid) return -ENOMEM; /* Find the report to use */ - list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) { - struct hid_report *report = (struct hid_report *)pos; + report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + list_for_each_entry(report, report_list, list) { int fieldnum; for (fieldnum = 0; fieldnum < report->maxfield; ++fieldnum) { diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 775a1ef28a29..5d9dbb47e4a8 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -235,6 +235,14 @@ static int usb_kbd_probe(struct usb_interface *iface, if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; +#ifdef CONFIG_USB_HID + if (usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)) + & HID_QUIRK_IGNORE) { + return -ENODEV; + } +#endif + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index f8ad6910d3d9..df0d96d989de 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -131,6 +131,14 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; +#ifdef CONFIG_USB_HID + if (usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)) + & (HID_QUIRK_IGNORE|HID_QUIRK_IGNORE_MOUSE)) { + return -ENODEV; + } +#endif + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index a37cb6b8593c..35812823787b 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -1,7 +1,7 @@ -/* ------------------------------------------------------------------------- */ -/* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters */ -/* ------------------------------------------------------------------------- */ -/* Copyright (C) 1995-2000 Simon G. Vogl +/* ------------------------------------------------------------------------- + * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters + * ------------------------------------------------------------------------- + * Copyright (C) 1995-2000 Simon G. Vogl 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 @@ -15,8 +15,8 @@ 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. */ -/* ------------------------------------------------------------------------- */ + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ------------------------------------------------------------------------- */ /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */ @@ -60,26 +60,26 @@ MODULE_PARM_DESC(i2c_debug, /* --- setting states on the bus with the right timing: --------------- */ -#define setsda(adap,val) adap->setsda(adap->data, val) -#define setscl(adap,val) adap->setscl(adap->data, val) -#define getsda(adap) adap->getsda(adap->data) -#define getscl(adap) adap->getscl(adap->data) +#define setsda(adap, val) adap->setsda(adap->data, val) +#define setscl(adap, val) adap->setscl(adap->data, val) +#define getsda(adap) adap->getsda(adap->data) +#define getscl(adap) adap->getscl(adap->data) static inline void sdalo(struct i2c_algo_bit_data *adap) { - setsda(adap,0); + setsda(adap, 0); udelay((adap->udelay + 1) / 2); } static inline void sdahi(struct i2c_algo_bit_data *adap) { - setsda(adap,1); + setsda(adap, 1); udelay((adap->udelay + 1) / 2); } static inline void scllo(struct i2c_algo_bit_data *adap) { - setscl(adap,0); + setscl(adap, 0); udelay(adap->udelay / 2); } @@ -91,22 +91,21 @@ static int sclhi(struct i2c_algo_bit_data *adap) { unsigned long start; - setscl(adap,1); + setscl(adap, 1); /* Not all adapters have scl sense line... */ if (!adap->getscl) goto done; - start=jiffies; - while (! getscl(adap) ) { - /* the hw knows how to read the clock line, - * so we wait until it actually gets high. - * This is safer as some chips may hold it low - * while they are processing data internally. - */ - if (time_after_eq(jiffies, start+adap->timeout)) { + start = jiffies; + while (!getscl(adap)) { + /* This hw knows how to read the clock line, so we wait + * until it actually gets high. This is safer as some + * chips may hold it low ("clock stretching") while they + * are processing data internally. + */ + if (time_after_eq(jiffies, start + adap->timeout)) return -ETIMEDOUT; - } cond_resched(); } #ifdef DEBUG @@ -118,11 +117,11 @@ static int sclhi(struct i2c_algo_bit_data *adap) done: udelay(adap->udelay); return 0; -} +} /* --- other auxiliary functions -------------------------------------- */ -static void i2c_start(struct i2c_algo_bit_data *adap) +static void i2c_start(struct i2c_algo_bit_data *adap) { /* assert: scl, sda are high */ setsda(adap, 0); @@ -130,7 +129,7 @@ static void i2c_start(struct i2c_algo_bit_data *adap) scllo(adap); } -static void i2c_repstart(struct i2c_algo_bit_data *adap) +static void i2c_repstart(struct i2c_algo_bit_data *adap) { /* assert: scl is low */ sdahi(adap); @@ -141,18 +140,18 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap) } -static void i2c_stop(struct i2c_algo_bit_data *adap) +static void i2c_stop(struct i2c_algo_bit_data *adap) { /* assert: scl is low */ sdalo(adap); - sclhi(adap); + sclhi(adap); setsda(adap, 1); udelay(adap->udelay); } -/* send a byte without start cond., look for arbitration, +/* send a byte without start cond., look for arbitration, check ackn. from slave */ /* returns: * 1 if the device acknowledged @@ -167,27 +166,33 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) struct i2c_algo_bit_data *adap = i2c_adap->algo_data; /* assert: scl is low */ - for ( i=7 ; i>=0 ; i-- ) { + for (i = 7; i >= 0; i--) { sb = (c >> i) & 1; - setsda(adap,sb); + setsda(adap, sb); udelay((adap->udelay + 1) / 2); - if (sclhi(adap)<0) { /* timed out */ + if (sclhi(adap) < 0) { /* timed out */ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " "timeout at bit #%d\n", (int)c, i); return -ETIMEDOUT; - }; - /* do arbitration here: - * if ( sb && ! getsda(adap) ) -> ouch! Get out of here. + } + /* FIXME do arbitration here: + * if (sb && !getsda(adap)) -> ouch! Get out of here. + * + * Report a unique code, so higher level code can retry + * the whole (combined) message and *NOT* issue STOP. */ scllo(adap); } sdahi(adap); - if (sclhi(adap)<0){ /* timeout */ + if (sclhi(adap) < 0) { /* timeout */ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " "timeout at ack\n", (int)c); return -ETIMEDOUT; - }; - /* read ack: SDA should be pulled down by slave */ + } + + /* read ack: SDA should be pulled down by slave, or it may + * NAK (usually to report problems with the data we wrote). + */ ack = !getsda(adap); /* ack: sda is pulled low -> success */ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, ack ? "A" : "NA"); @@ -198,24 +203,24 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) } -static int i2c_inb(struct i2c_adapter *i2c_adap) +static int i2c_inb(struct i2c_adapter *i2c_adap) { /* read byte via i2c port, without start/stop sequence */ /* acknowledge is sent in i2c_read. */ int i; - unsigned char indata=0; + unsigned char indata = 0; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; /* assert: scl is low */ sdahi(adap); - for (i=0;i<8;i++) { - if (sclhi(adap)<0) { /* timeout */ + for (i = 0; i < 8; i++) { + if (sclhi(adap) < 0) { /* timeout */ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " "#%d\n", 7 - i); return -ETIMEDOUT; - }; + } indata *= 2; - if ( getsda(adap) ) + if (getsda(adap)) indata |= 0x01; setscl(adap, 0); udelay(i == 7 ? adap->udelay / 2 : adap->udelay); @@ -228,66 +233,67 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) * Sanity check for the adapter hardware - check the reaction of * the bus lines only if it seems to be idle. */ -static int test_bus(struct i2c_algo_bit_data *adap, char* name) { - int scl,sda; +static int test_bus(struct i2c_algo_bit_data *adap, char *name) +{ + int scl, sda; - if (adap->getscl==NULL) + if (adap->getscl == NULL) pr_info("%s: Testing SDA only, SCL is not readable\n", name); - sda=getsda(adap); - scl=(adap->getscl==NULL?1:getscl(adap)); - if (!scl || !sda ) { + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl || !sda) { printk(KERN_WARNING "%s: bus seems to be busy\n", name); goto bailout; } sdalo(adap); - sda=getsda(adap); - scl=(adap->getscl==NULL?1:getscl(adap)); - if ( 0 != sda ) { + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (sda) { printk(KERN_WARNING "%s: SDA stuck high!\n", name); goto bailout; } - if ( 0 == scl ) { + if (!scl) { printk(KERN_WARNING "%s: SCL unexpected low " "while pulling SDA low!\n", name); goto bailout; - } + } sdahi(adap); - sda=getsda(adap); - scl=(adap->getscl==NULL?1:getscl(adap)); - if ( 0 == sda ) { + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!sda) { printk(KERN_WARNING "%s: SDA stuck low!\n", name); goto bailout; } - if ( 0 == scl ) { + if (!scl) { printk(KERN_WARNING "%s: SCL unexpected low " "while pulling SDA high!\n", name); goto bailout; } scllo(adap); - sda=getsda(adap); - scl=(adap->getscl==NULL?0:getscl(adap)); - if ( 0 != scl ) { + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 0 : getscl(adap); + if (scl) { printk(KERN_WARNING "%s: SCL stuck high!\n", name); goto bailout; } - if ( 0 == sda ) { + if (!sda) { printk(KERN_WARNING "%s: SDA unexpected low " "while pulling SCL low!\n", name); goto bailout; } - + sclhi(adap); - sda=getsda(adap); - scl=(adap->getscl==NULL?1:getscl(adap)); - if ( 0 == scl ) { + sda = getsda(adap); + scl = (adap->getscl == NULL) ? 1 : getscl(adap); + if (!scl) { printk(KERN_WARNING "%s: SCL stuck low!\n", name); goto bailout; } - if ( 0 == sda ) { + if (!sda) { printk(KERN_WARNING "%s: SDA unexpected low " "while pulling SCL high!\n", name); goto bailout; @@ -314,9 +320,10 @@ static int try_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries) { struct i2c_algo_bit_data *adap = i2c_adap->algo_data; - int i,ret = -1; - for (i=0;i<=retries;i++) { - ret = i2c_outb(i2c_adap,addr); + int i, ret = -1; + + for (i = 0; i <= retries; i++) { + ret = i2c_outb(i2c_adap, addr); if (ret == 1 || i == retries) break; bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); @@ -338,20 +345,38 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { const unsigned char *temp = msg->buf; int count = msg->len; - unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; + unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; - int wrcount=0; + int wrcount = 0; while (count > 0) { retval = i2c_outb(i2c_adap, *temp); - if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ - count--; + + /* OK/ACK; or ignored NAK */ + if ((retval > 0) || (nak_ok && (retval == 0))) { + count--; temp++; wrcount++; - } else { /* arbitration or no acknowledge */ - dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n"); - return (retval<0)? retval : -EFAULT; - /* got a better one ?? */ + + /* A slave NAKing the master means the slave didn't like + * something about the data it saw. For example, maybe + * the SMBus PEC was wrong. + */ + } else if (retval == 0) { + dev_err(&i2c_adap->dev, "sendbytes: NAK bailout.\n"); + return -EIO; + + /* Timeout; or (someday) lost arbitration + * + * FIXME Lost ARB implies retrying the transaction from + * the first message, after the "winning" master issues + * its STOP. As a rule, upper layer code has no reason + * to know or care about this ... it is *NOT* an error. + */ + } else { + dev_err(&i2c_adap->dev, "sendbytes: error %d\n", + retval); + return retval; } } return wrcount; @@ -376,14 +401,14 @@ static int acknak(struct i2c_adapter *i2c_adap, int is_ack) static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { int inval; - int rdcount=0; /* counts bytes read */ + int rdcount = 0; /* counts bytes read */ unsigned char *temp = msg->buf; int count = msg->len; const unsigned flags = msg->flags; while (count > 0) { inval = i2c_inb(i2c_adap); - if (inval>=0) { + if (inval >= 0) { *temp = inval; rdcount++; } else { /* read timed out */ @@ -431,7 +456,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) * returns: * 0 everything went okay, the chip ack'ed, or IGNORE_NAK flag was set * -x an error occurred (like: -EREMOTEIO if the device did not answer, or - * -ETIMEDOUT, for example if the lines are stuck...) + * -ETIMEDOUT, for example if the lines are stuck...) */ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { @@ -443,10 +468,10 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) int ret, retries; retries = nak_ok ? 0 : i2c_adap->retries; - - if ( (flags & I2C_M_TEN) ) { + + if (flags & I2C_M_TEN) { /* a ten bit address */ - addr = 0xf0 | (( msg->addr >> 7) & 0x03); + addr = 0xf0 | ((msg->addr >> 7) & 0x03); bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); @@ -456,33 +481,33 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) return -EREMOTEIO; } /* the remaining 8 bit address */ - ret = i2c_outb(i2c_adap,msg->addr & 0x7f); + ret = i2c_outb(i2c_adap, msg->addr & 0x7f); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ dev_err(&i2c_adap->dev, "died at 2nd address code\n"); return -EREMOTEIO; } - if ( flags & I2C_M_RD ) { + if (flags & I2C_M_RD) { bit_dbg(3, &i2c_adap->dev, "emitting repeated " "start condition\n"); i2c_repstart(adap); /* okay, now switch into reading mode */ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); - if ((ret!=1) && !nak_ok) { + if ((ret != 1) && !nak_ok) { dev_err(&i2c_adap->dev, "died at repeated address code\n"); return -EREMOTEIO; } } } else { /* normal 7bit address */ - addr = ( msg->addr << 1 ); - if (flags & I2C_M_RD ) + addr = msg->addr << 1; + if (flags & I2C_M_RD) addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR ) + if (flags & I2C_M_REV_DIR_ADDR) addr ^= 1; ret = try_address(i2c_adap, addr, retries); - if ((ret!=1) && !nak_ok) + if ((ret != 1) && !nak_ok) return -EREMOTEIO; } @@ -494,15 +519,14 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, { struct i2c_msg *pmsg; struct i2c_algo_bit_data *adap = i2c_adap->algo_data; - - int i,ret; + int i, ret; unsigned short nak_ok; bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); - for (i=0;i<num;i++) { + for (i = 0; i < num; i++) { pmsg = &msgs[i]; - nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; + nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { if (i) { bit_dbg(3, &i2c_adap->dev, "emitting " @@ -517,7 +541,7 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, goto bailout; } } - if (pmsg->flags & I2C_M_RD ) { + if (pmsg->flags & I2C_M_RD) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); if (ret >= 1) @@ -551,7 +575,7 @@ bailout: static u32 bit_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; @@ -565,8 +589,8 @@ static const struct i2c_algorithm i2c_bit_algo = { .functionality = bit_func, }; -/* - * registering functions to load algorithms at runtime +/* + * registering functions to load algorithms at runtime */ static int i2c_bit_prepare_bus(struct i2c_adapter *adap) { @@ -574,7 +598,7 @@ static int i2c_bit_prepare_bus(struct i2c_adapter *adap) if (bit_test) { int ret = test_bus(bit_adap, adap->name); - if (ret<0) + if (ret < 0) return -ENODEV; } diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index ab2e6f3498b4..8907b0191677 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -203,35 +203,6 @@ static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) /* ----- Utility functions */ -static inline int try_address(struct i2c_algo_pcf_data *adap, - unsigned char addr, int retries) -{ - int i, status, ret = -1; - int wfp; - for (i=0;i<retries;i++) { - i2c_outb(adap, addr); - i2c_start(adap); - status = get_pcf(adap, 1); - if ((wfp = wait_for_pin(adap, &status)) >= 0) { - if ((status & I2C_PCF_LRB) == 0) { - i2c_stop(adap); - break; /* success! */ - } - } - if (wfp == -EINTR) { - /* arbitration lost */ - udelay(adap->udelay); - return -EINTR; - } - i2c_stop(adap); - udelay(adap->udelay); - } - DEB2(if (i) printk(KERN_DEBUG "i2c-algo-pcf.o: needed %d retries for %d\n",i, - addr)); - return ret; -} - - static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, int count, int last) { @@ -321,47 +292,19 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, } -static inline int pcf_doAddress(struct i2c_algo_pcf_data *adap, - struct i2c_msg *msg, int retries) +static int pcf_doAddress(struct i2c_algo_pcf_data *adap, + struct i2c_msg *msg) { unsigned short flags = msg->flags; unsigned char addr; - int ret; - if ( (flags & I2C_M_TEN) ) { - /* a ten bit address */ - addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); - /* try extended address code...*/ - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk(KERN_ERR "died at extended address code.\n"); - return -EREMOTEIO; - } - /* the remaining 8 bit address */ - i2c_outb(adap,msg->addr & 0x7f); -/* Status check comes here */ - if (ret != 1) { - printk(KERN_ERR "died at 2nd address code.\n"); - return -EREMOTEIO; - } - if ( flags & I2C_M_RD ) { - i2c_repstart(adap); - /* okay, now switch into reading mode */ - addr |= 0x01; - ret = try_address(adap, addr, retries); - if (ret!=1) { - printk(KERN_ERR "died at extended address code.\n"); - return -EREMOTEIO; - } - } - } else { /* normal 7bit address */ - addr = ( msg->addr << 1 ); - if (flags & I2C_M_RD ) - addr |= 1; - if (flags & I2C_M_REV_DIR_ADDR ) - addr ^= 1; - i2c_outb(adap, addr); - } + + addr = msg->addr << 1; + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + i2c_outb(adap, addr); + return 0; } @@ -390,7 +333,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num);) - ret = pcf_doAddress(adap, pmsg, i2c_adap->retries); + ret = pcf_doAddress(adap, pmsg); /* Send START */ if (i == 0) { @@ -453,7 +396,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, static u32 pcf_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | - I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; + I2C_FUNC_PROTOCOL_MANGLING; } /* -----exported algorithm data: ------------------------------------- */ @@ -475,9 +418,7 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap) /* register new adapter to i2c module... */ adap->algo = &pcf_algo; - - adap->timeout = 100; /* default values, should */ - adap->retries = 3; /* be replaced by defines */ + adap->timeout = 100; if ((rval = pcf_init_8584(pcf_adap))) return rval; diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c466c6cfc2e5..b61f56b6f311 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -182,7 +182,8 @@ config I2C_I801 will be called i2c-i801. config I2C_I810 - tristate "Intel 810/815" + tristate "Intel 810/815 (DEPRECATED)" + default n depends on PCI select I2C_ALGOBIT help @@ -195,6 +196,8 @@ config I2C_I810 i815 i845G + This driver is deprecated in favor of the i810fb and intelfb drivers. + This driver can also be built as a module. If so, the module will be called i2c-i810. @@ -259,20 +262,6 @@ config I2C_IOP3XX This driver can also be built as a module. If so, the module will be called i2c-iop3xx. -config I2C_IXP4XX - tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)" - depends on ARCH_IXP4XX - select I2C_ALGOBIT - help - Say Y here if you have an Intel IXP4xx(420,421,422,425) based - system and are using GPIO lines for an I2C bus. - - This support is also available as a module. If so, the module - will be called i2c-ixp4xx. - - This driver is deprecated and will be dropped soon. Use i2c-gpio - instead. - config I2C_IXP2000 tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)" depends on ARCH_IXP2000 @@ -396,7 +385,8 @@ config I2C_PASEMI Supports the PA Semi PWRficient on-chip SMBus interfaces. config I2C_PROSAVAGE - tristate "S3/VIA (Pro)Savage" + tristate "S3/VIA (Pro)Savage (DEPRECATED)" + default n depends on PCI select I2C_ALGOBIT help @@ -407,6 +397,8 @@ config I2C_PROSAVAGE S3/VIA KM266/VT8375 aka ProSavage8 S3/VIA KM133/VT8365 aka Savage4 + This driver is deprecated in favor of the savagefb driver. + This support is also available as a module. If so, the module will be called i2c-prosavage. @@ -418,13 +410,16 @@ config I2C_S3C2410 Samsung S3C2410 based System-on-Chip devices. config I2C_SAVAGE4 - tristate "S3 Savage 4" - depends on PCI && EXPERIMENTAL + tristate "S3 Savage 4 (DEPRECATED)" + default n + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the S3 Savage 4 I2C interface. + This driver is deprecated in favor of the savagefb driver. + This driver can also be built as a module. If so, the module will be called i2c-savage4. @@ -611,7 +606,7 @@ config I2C_VIAPRO VT8231 VT8233/A VT8235 - VT8237R/A + VT8237R/A/S VT8251 CX700 @@ -648,7 +643,7 @@ config I2C_PCA_ISA config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on MV64X60 && EXPERIMENTAL + depends on (MV64X60 || ARCH_ORION) && EXPERIMENTAL help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 81d43c27cf93..ea7068f1eb6b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_I2C_I810) += i2c-i810.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o -obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 7490dc1771ae..573abe440842 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -334,6 +334,10 @@ static int __devinit amd756_probe(struct pci_dev *pdev, int error; u8 temp; + /* driver_data might come from user-space, so check it */ + if (id->driver_data > ARRAY_SIZE(chipname)) + return -EINVAL; + if (amd756_ioport) { dev_err(&pdev->dev, "Only one device supported " "(you have a strange motherboard, btw)\n"); @@ -405,6 +409,7 @@ static struct pci_driver amd756_driver = { .id_table = amd756_ids, .probe = amd756_probe, .remove = __devexit_p(amd756_remove), + .dynids.use_driver_data = 1, }; static int __init amd756_init(void) diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 2f684166c43d..1953b26da56a 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -30,14 +30,22 @@ #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/i2c.h> +#include <linux/slab.h> #include <asm/mach-au1x00/au1xxx.h> #include <asm/mach-au1x00/au1xxx_psc.h> -#include "i2c-au1550.h" +struct i2c_au1550_data { + u32 psc_base; + int xfer_timeout; + int ack_timeout; + struct i2c_adapter adap; + struct resource *ioarea; +}; static int wait_xfer_done(struct i2c_au1550_data *adap) @@ -105,7 +113,7 @@ wait_master_done(struct i2c_au1550_data *adap) } static int -do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) +do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q) { volatile psc_smb_t *sp; u32 stat; @@ -134,6 +142,10 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) if (rd) addr |= 1; + /* zero-byte xfers stop immediately */ + if (q) + addr |= PSC_SMBTXRX_STP; + /* Put byte into fifo, start up master. */ sp->psc_smbtxrx = addr; @@ -142,7 +154,7 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd) au_sync(); if (wait_ack(adap)) return -EIO; - return 0; + return (q) ? wait_master_done(adap) : 0; } static u32 @@ -262,7 +274,8 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) for (i = 0; !err && i < num; i++) { p = &msgs[i]; - err = do_address(adap, p->addr, p->flags & I2C_M_RD); + err = do_address(adap, p->addr, p->flags & I2C_M_RD, + (p->len == 0)); if (err || !p->len) continue; if (p->flags & I2C_M_RD) @@ -294,18 +307,48 @@ static const struct i2c_algorithm au1550_algo = { * Prior to calling us, the 50MHz clock frequency and routing * must have been set up for the PSC indicated by the adapter. */ -int -i2c_au1550_add_bus(struct i2c_adapter *i2c_adap) +static int __devinit +i2c_au1550_probe(struct platform_device *pdev) { - struct i2c_au1550_data *adap = i2c_adap->algo_data; - volatile psc_smb_t *sp; - u32 stat; + struct i2c_au1550_data *priv; + volatile psc_smb_t *sp; + struct resource *r; + u32 stat; + int ret; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -ENODEV; + goto out; + } + + priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + goto out; + } + + priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, + pdev->name); + if (!priv->ioarea) { + ret = -EBUSY; + goto out_mem; + } - i2c_adap->algo = &au1550_algo; + priv->psc_base = r->start; + priv->xfer_timeout = 200; + priv->ack_timeout = 200; + + priv->adap.id = I2C_HW_AU1550_PSC; + priv->adap.nr = pdev->id; + priv->adap.algo = &au1550_algo; + priv->adap.algo_data = priv; + priv->adap.dev.parent = &pdev->dev; + strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); /* Now, set up the PSC for SMBus PIO mode. */ - sp = (volatile psc_smb_t *)(adap->psc_base); + sp = (volatile psc_smb_t *)priv->psc_base; sp->psc_ctrl = PSC_CTRL_DISABLE; au_sync(); sp->psc_sel = PSC_SEL_PS_SMBUSMODE; @@ -343,87 +386,87 @@ i2c_au1550_add_bus(struct i2c_adapter *i2c_adap) au_sync(); } while ((stat & PSC_SMBSTAT_DR) == 0); - return i2c_add_adapter(i2c_adap); -} + ret = i2c_add_numbered_adapter(&priv->adap); + if (ret == 0) { + platform_set_drvdata(pdev, priv); + return 0; + } + /* disable the PSC */ + sp->psc_smbcfg = 0; + sp->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); -int -i2c_au1550_del_bus(struct i2c_adapter *adap) + release_resource(priv->ioarea); + kfree(priv->ioarea); +out_mem: + kfree(priv); +out: + return ret; +} + +static int __devexit +i2c_au1550_remove(struct platform_device *pdev) { - return i2c_del_adapter(adap); + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + platform_set_drvdata(pdev, NULL); + i2c_del_adapter(&priv->adap); + sp->psc_smbcfg = 0; + sp->psc_ctrl = PSC_CTRL_DISABLE; + au_sync(); + release_resource(priv->ioarea); + kfree(priv->ioarea); + kfree(priv); + return 0; } static int -pb1550_reg(struct i2c_client *client) +i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) { + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + sp->psc_ctrl = PSC_CTRL_SUSPEND; + au_sync(); return 0; } static int -pb1550_unreg(struct i2c_client *client) +i2c_au1550_resume(struct platform_device *pdev) { + struct i2c_au1550_data *priv = platform_get_drvdata(pdev); + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; + + sp->psc_ctrl = PSC_CTRL_ENABLE; + au_sync(); + while (!(sp->psc_smbstat & PSC_SMBSTAT_SR)) + au_sync(); return 0; } -static struct i2c_au1550_data pb1550_i2c_info = { - SMBUS_PSC_BASE, 200, 200 -}; - -static struct i2c_adapter pb1550_board_adapter = { - name: "pb1550 adapter", - id: I2C_HW_AU1550_PSC, - algo: NULL, - algo_data: &pb1550_i2c_info, - client_register: pb1550_reg, - client_unregister: pb1550_unreg, +static struct platform_driver au1xpsc_smbus_driver = { + .driver = { + .name = "au1xpsc_smbus", + .owner = THIS_MODULE, + }, + .probe = i2c_au1550_probe, + .remove = __devexit_p(i2c_au1550_remove), + .suspend = i2c_au1550_suspend, + .resume = i2c_au1550_resume, }; -/* BIG hack to support the control interface on the Wolfson WM8731 - * audio codec on the Pb1550 board. We get an address and two data - * bytes to write, create an i2c message, and send it across the - * i2c transfer function. We do this here because we have access to - * the i2c adapter structure. - */ -static struct i2c_msg wm_i2c_msg; /* We don't want this stuff on the stack */ -static u8 i2cbuf[2]; - -int -pb1550_wm_codec_write(u8 addr, u8 reg, u8 val) -{ - wm_i2c_msg.addr = addr; - wm_i2c_msg.flags = 0; - wm_i2c_msg.buf = i2cbuf; - wm_i2c_msg.len = 2; - i2cbuf[0] = reg; - i2cbuf[1] = val; - - return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1); -} - static int __init i2c_au1550_init(void) { - printk(KERN_INFO "Au1550 I2C: "); - - /* This is where we would set up a 50MHz clock source - * and routing. On the Pb1550, the SMBus is PSC2, which - * uses a shared clock with USB. This has been already - * configured by Yamon as a 48MHz clock, close enough - * for our work. - */ - if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0) { - printk("failed to initialize.\n"); - return -ENODEV; - } - - printk("initialized.\n"); - return 0; + return platform_driver_register(&au1xpsc_smbus_driver); } static void __exit i2c_au1550_exit(void) { - i2c_au1550_del_bus(&pb1550_board_adapter); + platform_driver_unregister(&au1xpsc_smbus_driver); } MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC."); diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 67224a424aba..7dbdaeb707a9 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -550,6 +550,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) p_adap = &iface->adap; p_adap->id = I2C_HW_BLACKFIN; + p_adap->nr = dev->id; strlcpy(p_adap->name, dev->name, sizeof(p_adap->name)); p_adap->algo = &bfin_twi_algorithm; p_adap->algo_data = iface; @@ -576,7 +577,7 @@ static int i2c_bfin_twi_probe(struct platform_device *dev) bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); SSYNC(); - rc = i2c_add_adapter(p_adap); + rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) free_irq(iface->irq, iface); else diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 67679882ebef..cce5a614758d 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -510,7 +510,6 @@ static int davinci_i2c_probe(struct platform_device *pdev) /* FIXME */ adap->timeout = 1; - adap->retries = 1; adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ac27e5f84ebe..aa9157913b9a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -4,6 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com> + Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,25 +22,34 @@ */ /* - SUPPORTED DEVICES PCI ID - 82801AA 2413 - 82801AB 2423 - 82801BA 2443 - 82801CA/CAM 2483 - 82801DB 24C3 (HW PEC supported) - 82801EB 24D3 (HW PEC supported) - 6300ESB 25A4 - ICH6 266A - ICH7 27DA - ESB2 269B - ICH8 283E - ICH9 2930 - Tolapai 5032 - This driver supports several versions of Intel's I/O Controller Hubs (ICH). - For SMBus support, they are similar to the PIIX4 and are part - of Intel's '810' and other chipsets. - See the file Documentation/i2c/busses/i2c-i801 for details. - I2C Block Read and Process Call are not supported. + Supports the following Intel I/O Controller Hubs (ICH): + + I/O Block I2C + region SMBus Block proc. block + Chip name PCI ID size PEC buffer call read + ---------------------------------------------------------------------- + 82801AA (ICH) 0x2413 16 no no no no + 82801AB (ICH0) 0x2423 16 no no no no + 82801BA (ICH2) 0x2443 16 no no no no + 82801CA (ICH3) 0x2483 32 soft no no no + 82801DB (ICH4) 0x24c3 32 hard yes no no + 82801E (ICH5) 0x24d3 32 hard yes yes yes + 6300ESB 0x25a4 32 hard yes yes yes + 82801F (ICH6) 0x266a 32 hard yes yes yes + 6310ESB/6320ESB 0x269b 32 hard yes yes yes + 82801G (ICH7) 0x27da 32 hard yes yes yes + 82801H (ICH8) 0x283e 32 hard yes yes yes + 82801I (ICH9) 0x2930 32 hard yes yes yes + Tolapai 0x5032 32 hard yes ? ? + + Features supported by this driver: + Software PEC no + Hardware PEC yes + Block buffer yes + Block process call transaction no + I2C block read transaction yes (doesn't use the block buffer) + + See the file Documentation/i2c/busses/i2c-i801 for details. */ /* Note: we assume there can only be one I801, with one SMBus interface */ @@ -62,9 +72,9 @@ #define SMBHSTDAT0 (5 + i801_smba) #define SMBHSTDAT1 (6 + i801_smba) #define SMBBLKDAT (7 + i801_smba) -#define SMBPEC (8 + i801_smba) /* ICH4 only */ -#define SMBAUXSTS (12 + i801_smba) /* ICH4 only */ -#define SMBAUXCTL (13 + i801_smba) /* ICH4 only */ +#define SMBPEC (8 + i801_smba) /* ICH3 and later */ +#define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */ +#define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */ /* PCI Address Constants */ #define SMBBAR 4 @@ -91,13 +101,13 @@ #define I801_BYTE 0x04 #define I801_BYTE_DATA 0x08 #define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* later chips only, unimplemented */ +#define I801_PROC_CALL 0x10 /* unimplemented */ #define I801_BLOCK_DATA 0x14 -#define I801_I2C_BLOCK_DATA 0x18 /* unimplemented */ +#define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ #define I801_BLOCK_LAST 0x34 -#define I801_I2C_BLOCK_LAST 0x38 /* unimplemented */ +#define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */ #define I801_START 0x40 -#define I801_PEC_EN 0x80 /* ICH4 only */ +#define I801_PEC_EN 0x80 /* ICH3 and later */ /* I801 Hosts Status register bits */ #define SMBHSTSTS_BYTE_DONE 0x80 @@ -113,7 +123,12 @@ static unsigned long i801_smba; static unsigned char i801_original_hstcfg; static struct pci_driver i801_driver; static struct pci_dev *I801_dev; -static int isich4; + +#define FEATURE_SMBUS_PEC (1 << 0) +#define FEATURE_BLOCK_BUFFER (1 << 1) +#define FEATURE_BLOCK_PROC (1 << 2) +#define FEATURE_I2C_BLOCK_READ (1 << 3) +static unsigned int i801_features; static int i801_transaction(int xact) { @@ -242,7 +257,8 @@ static int i801_block_transaction_by_block(union i2c_smbus_data *data, } static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, - char read_write, int hwpec) + char read_write, int command, + int hwpec) { int i, len; int smbcmd; @@ -259,16 +275,24 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, } for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) - smbcmd = I801_BLOCK_LAST; - else - smbcmd = I801_BLOCK_DATA; + if (i == len && read_write == I2C_SMBUS_READ) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA) + smbcmd = I801_I2C_BLOCK_LAST; + else + smbcmd = I801_BLOCK_LAST; + } else { + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_READ) + smbcmd = I801_I2C_BLOCK_DATA; + else + smbcmd = I801_BLOCK_DATA; + } outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); /* Make sure the SMBus host is ready to start transmitting */ temp = inb_p(SMBHSTSTS); @@ -332,7 +356,8 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, dev_dbg(&I801_dev->dev, "Error: no response!\n"); } - if (i == 1 && read_write == I2C_SMBUS_READ) { + if (i == 1 && read_write == I2C_SMBUS_READ + && command != I2C_SMBUS_I2C_BLOCK_DATA) { len = inb_p(SMBHSTDAT0); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) return -1; @@ -353,9 +378,9 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, temp); } dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i, + "ADD=%02x, DAT0=%02x, DAT1=%02x, BLKDAT=%02x\n", i, inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), - inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT)); + inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1), inb_p(SMBBLKDAT)); if (result < 0) return result; @@ -384,33 +409,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write, pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); pci_write_config_byte(I801_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN); - } else { + } else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) { dev_err(&I801_dev->dev, - "I2C_SMBUS_I2C_BLOCK_READ not DB!\n"); + "I2C block read is unsupported!\n"); return -1; } } - if (read_write == I2C_SMBUS_WRITE) { + if (read_write == I2C_SMBUS_WRITE + || command == I2C_SMBUS_I2C_BLOCK_DATA) { if (data->block[0] < 1) data->block[0] = 1; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) data->block[0] = I2C_SMBUS_BLOCK_MAX; } else { - data->block[0] = 32; /* max for reads */ + data->block[0] = 32; /* max for SMBus block reads */ } - if (isich4 && i801_set_block_buffer_mode() == 0 ) + if ((i801_features & FEATURE_BLOCK_BUFFER) + && !(command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_READ) + && i801_set_block_buffer_mode() == 0) result = i801_block_transaction_by_block(data, read_write, hwpec); else result = i801_block_transaction_byte_by_byte(data, read_write, - hwpec); + command, hwpec); if (result == 0 && hwpec) i801_wait_hwpec(); - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA + && read_write == I2C_SMBUS_WRITE) { /* restore saved configuration register value */ pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); } @@ -426,7 +456,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, int block = 0; int ret, xact = 0; - hwpec = isich4 && (flags & I2C_CLIENT_PEC) + hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; @@ -462,12 +492,23 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, xact = I801_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_I2C_BLOCK_DATA: outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD); outb_p(command, SMBHSTCMD); block = 1; break; + case I2C_SMBUS_I2C_BLOCK_DATA: + /* NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading */ + outb_p((addr & 0x7f) << 1, SMBHSTADD); + if (read_write == I2C_SMBUS_READ) { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ + outb_p(command, SMBHSTDAT1); + } else + outb_p(command, SMBHSTCMD); + block = 1; + break; case I2C_SMBUS_PROC_CALL: default: dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); @@ -487,7 +528,7 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, /* Some BIOSes don't like it when PEC is enabled at reboot or resume time, so we forcibly disable it after every transaction. Turn off E32B for the same reason. */ - if (hwpec) + if (hwpec || block) outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL); @@ -514,9 +555,11 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr, static u32 i801_func(struct i2c_adapter *adapter) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK - | (isich4 ? I2C_FUNC_SMBUS_PEC : 0); + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | + ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | + ((i801_features & FEATURE_I2C_BLOCK_READ) ? + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0); } static const struct i2c_algorithm smbus_algorithm = { @@ -556,8 +599,8 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id int err; I801_dev = dev; + i801_features = 0; switch (dev->device) { - case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_82801EB_3: case PCI_DEVICE_ID_INTEL_ESB_4: case PCI_DEVICE_ID_INTEL_ICH6_16: @@ -565,11 +608,13 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id case PCI_DEVICE_ID_INTEL_ESB2_17: case PCI_DEVICE_ID_INTEL_ICH8_5: case PCI_DEVICE_ID_INTEL_ICH9_6: + i801_features |= FEATURE_I2C_BLOCK_READ; + /* fall through */ + case PCI_DEVICE_ID_INTEL_82801DB_3: case PCI_DEVICE_ID_INTEL_TOLAPAI_1: - isich4 = 1; + i801_features |= FEATURE_SMBUS_PEC; + i801_features |= FEATURE_BLOCK_BUFFER; break; - default: - isich4 = 0; } err = pci_enable_device(dev); @@ -610,6 +655,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id else dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n"); + /* Clear special mode bits */ + if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) + outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), + SMBAUXCTL); + /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; @@ -678,9 +728,8 @@ static void __exit i2c_i801_exit(void) pci_unregister_driver(&i801_driver); } -MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " - "Philip Edelbrock <phil@netroedge.com>, " - "and Mark D. Studebaker <mdsxyz123@yahoo.com>"); +MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, " + "Jean Delvare <khali@linux-fr.org>"); MODULE_DESCRIPTION("I801 SMBus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 9b43ff7270d0..7c7eb0cfeceb 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -6,7 +6,7 @@ * Copyright (c) 2003, 2004 Zultys Technologies. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Based on original work by + * Based on original work by * Ian DaSilva <idasilva@mvista.com> * Armin Kuster <akuster@mvista.com> * Matt Porter <mporter@mvista.com> @@ -86,8 +86,8 @@ static void dump_iic_regs(const char* header, struct ibm_iic_private* dev) KERN_DEBUG " sts = 0x%02x, extsts = 0x%02x\n" KERN_DEBUG " clkdiv = 0x%02x, xfrcnt = 0x%02x\n" KERN_DEBUG " xtcntlss = 0x%02x, directcntl = 0x%02x\n", - in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), - in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), + in_8(&iic->cntl), in_8(&iic->mdcntl), in_8(&iic->sts), + in_8(&iic->extsts), in_8(&iic->clkdiv), in_8(&iic->xfrcnt), in_8(&iic->xtcntlss), in_8(&iic->directcntl)); } # define DUMP_REGS(h,dev) dump_iic_regs((h),(dev)) @@ -125,7 +125,7 @@ static inline void iic_interrupt_mode(struct ibm_iic_private* dev, int enable) { out_8(&dev->vaddr->intmsk, enable ? INTRMSK_EIMTC : 0); } - + /* * Initialize IIC interface. */ @@ -134,7 +134,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) volatile struct iic_regs __iomem *iic = dev->vaddr; DBG("%d: init\n", dev->idx); - + /* Clear master address */ out_8(&iic->lmadr, 0); out_8(&iic->hmadr, 0); @@ -160,7 +160,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) /* Clear control register */ out_8(&iic->cntl, 0); - + /* Enable interrupts if possible */ iic_interrupt_mode(dev, dev->irq >= 0); @@ -171,7 +171,7 @@ static void iic_dev_init(struct ibm_iic_private* dev) DUMP_REGS("iic_init", dev); } -/* +/* * Reset IIC interface */ static void iic_dev_reset(struct ibm_iic_private* dev) @@ -179,42 +179,42 @@ static void iic_dev_reset(struct ibm_iic_private* dev) volatile struct iic_regs __iomem *iic = dev->vaddr; int i; u8 dc; - + DBG("%d: soft reset\n", dev->idx); DUMP_REGS("reset", dev); - + /* Place chip in the reset state */ out_8(&iic->xtcntlss, XTCNTLSS_SRST); - + /* Check if bus is free */ - dc = in_8(&iic->directcntl); + dc = in_8(&iic->directcntl); if (!DIRCTNL_FREE(dc)){ DBG("%d: trying to regain bus control\n", dev->idx); - + /* Try to set bus free state */ - out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); - + out_8(&iic->directcntl, DIRCNTL_SDAC | DIRCNTL_SCC); + /* Wait until we regain bus control */ for (i = 0; i < 100; ++i){ dc = in_8(&iic->directcntl); if (DIRCTNL_FREE(dc)) break; - + /* Toggle SCL line */ dc ^= DIRCNTL_SCC; out_8(&iic->directcntl, dc); udelay(10); dc ^= DIRCNTL_SCC; out_8(&iic->directcntl, dc); - + /* be nice */ cond_resched(); } } - + /* Remove reset */ out_8(&iic->xtcntlss, 0); - + /* Reinitialize interface */ iic_dev_init(dev); } @@ -324,14 +324,14 @@ static irqreturn_t iic_handler(int irq, void *dev_id) { struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id; volatile struct iic_regs __iomem *iic = dev->vaddr; - - DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", + + DBG2("%d: irq handler, STS = 0x%02x, EXTSTS = 0x%02x\n", dev->idx, in_8(&iic->sts), in_8(&iic->extsts)); - + /* Acknowledge IRQ and wakeup iic_wait_for_tc */ out_8(&iic->sts, STS_IRQA | STS_SCMP); wake_up_interruptible(&dev->wq); - + return IRQ_HANDLED; } @@ -341,19 +341,19 @@ static irqreturn_t iic_handler(int irq, void *dev_id) */ static int iic_xfer_result(struct ibm_iic_private* dev) { - volatile struct iic_regs __iomem *iic = dev->vaddr; - + volatile struct iic_regs __iomem *iic = dev->vaddr; + if (unlikely(in_8(&iic->sts) & STS_ERR)){ - DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, + DBG("%d: xfer error, EXTSTS = 0x%02x\n", dev->idx, in_8(&iic->extsts)); - + /* Clear errors and possible pending IRQs */ - out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | + out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA); - + /* Flush master data buffer */ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); - + /* Is bus free? * If error happened during combined xfer * IIC interface is usually stuck in some strange @@ -376,11 +376,11 @@ static void iic_abort_xfer(struct ibm_iic_private* dev) { volatile struct iic_regs __iomem *iic = dev->vaddr; unsigned long x; - + DBG("%d: iic_abort_xfer\n", dev->idx); - + out_8(&iic->cntl, CNTL_HMT); - + /* * Wait for the abort command to complete. * It's not worth to be optimized, just poll (timeout >= 1 tick) @@ -405,13 +405,13 @@ static void iic_abort_xfer(struct ibm_iic_private* dev) * Returns the number of transferred bytes or error (<0) */ static int iic_wait_for_tc(struct ibm_iic_private* dev){ - + volatile struct iic_regs __iomem *iic = dev->vaddr; int ret = 0; - + if (dev->irq >= 0){ /* Interrupt mode */ - ret = wait_event_interruptible_timeout(dev->wq, + ret = wait_event_interruptible_timeout(dev->wq, !(in_8(&iic->sts) & STS_PT), dev->adap.timeout * HZ); if (unlikely(ret < 0)) @@ -424,37 +424,37 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){ else { /* Polling mode */ unsigned long x = jiffies + dev->adap.timeout * HZ; - + while (in_8(&iic->sts) & STS_PT){ if (unlikely(time_after(jiffies, x))){ DBG("%d: poll timeout\n", dev->idx); ret = -ETIMEDOUT; break; } - + if (unlikely(signal_pending(current))){ DBG("%d: poll interrupted\n", dev->idx); ret = -ERESTARTSYS; break; } schedule(); - } + } } - + if (unlikely(ret < 0)) iic_abort_xfer(dev); else ret = iic_xfer_result(dev); - + DBG2("%d: iic_wait_for_tc -> %d\n", dev->idx, ret); - + return ret; } /* * Low level master transfer routine */ -static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, +static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, int combined_xfer) { volatile struct iic_regs __iomem *iic = dev->vaddr; @@ -465,48 +465,48 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, u8 cntl = (in_8(&iic->cntl) & CNTL_AMD) | CNTL_PT; if (pm->flags & I2C_M_RD) cntl |= CNTL_RW; - + loops = (len + 3) / 4; for (i = 0; i < loops; ++i, len -= 4){ int count = len > 4 ? 4 : len; u8 cmd = cntl | ((count - 1) << CNTL_TCT_SHIFT); - + if (!(cntl & CNTL_RW)) for (j = 0; j < count; ++j) out_8((void __iomem *)&iic->mdbuf, *buf++); - + if (i < loops - 1) cmd |= CNTL_CHT; else if (combined_xfer) cmd |= CNTL_RPST; - + DBG2("%d: xfer_bytes, %d, CNTL = 0x%02x\n", dev->idx, count, cmd); - + /* Start transfer */ out_8(&iic->cntl, cmd); - + /* Wait for completion */ ret = iic_wait_for_tc(dev); if (unlikely(ret < 0)) break; else if (unlikely(ret != count)){ - DBG("%d: xfer_bytes, requested %d, transfered %d\n", + DBG("%d: xfer_bytes, requested %d, transfered %d\n", dev->idx, count, ret); - + /* If it's not a last part of xfer, abort it */ if (combined_xfer || (i < loops - 1)) iic_abort_xfer(dev); - + ret = -EREMOTEIO; - break; + break; } - + if (cntl & CNTL_RW) for (j = 0; j < count; ++j) *buf++ = in_8((void __iomem *)&iic->mdbuf); } - + return ret > 0 ? 0 : ret; } @@ -517,10 +517,10 @@ static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg) { volatile struct iic_regs __iomem *iic = dev->vaddr; u16 addr = msg->addr; - - DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, + + DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, addr, msg->flags & I2C_M_TEN ? 10 : 7); - + if (msg->flags & I2C_M_TEN){ out_8(&iic->cntl, CNTL_AMD); out_8(&iic->lmadr, addr); @@ -537,15 +537,15 @@ static inline int iic_invalid_address(const struct i2c_msg* p) return (p->addr > 0x3ff) || (!(p->flags & I2C_M_TEN) && (p->addr > 0x7f)); } -static inline int iic_address_neq(const struct i2c_msg* p1, +static inline int iic_address_neq(const struct i2c_msg* p1, const struct i2c_msg* p2) { - return (p1->addr != p2->addr) + return (p1->addr != p2->addr) || ((p1->flags & I2C_M_TEN) != (p2->flags & I2C_M_TEN)); -} +} /* - * Generic master transfer entrypoint. + * Generic master transfer entrypoint. * Returns the number of processed messages or error (<0) */ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) @@ -553,20 +553,20 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct ibm_iic_private* dev = (struct ibm_iic_private*)(i2c_get_adapdata(adap)); volatile struct iic_regs __iomem *iic = dev->vaddr; int i, ret = 0; - + DBG2("%d: iic_xfer, %d msg(s)\n", dev->idx, num); - + if (!num) return 0; - + /* Check the sanity of the passed messages. * Uhh, generic i2c layer is more suitable place for such code... */ if (unlikely(iic_invalid_address(&msgs[0]))){ - DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, + DBG("%d: invalid address 0x%03x (%d-bit)\n", dev->idx, msgs[0].addr, msgs[0].flags & I2C_M_TEN ? 10 : 7); return -EINVAL; - } + } for (i = 0; i < num; ++i){ if (unlikely(msgs[i].len <= 0)){ if (num == 1 && !msgs[0].len){ @@ -576,7 +576,7 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) */ return iic_smbus_quick(dev, &msgs[0]); } - DBG("%d: invalid len %d in msg[%d]\n", dev->idx, + DBG("%d: invalid len %d in msg[%d]\n", dev->idx, msgs[i].len, i); return -EINVAL; } @@ -585,34 +585,34 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) return -EINVAL; } } - + /* Check bus state */ if (unlikely((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE)){ DBG("%d: iic_xfer, bus is not free\n", dev->idx); - + /* Usually it means something serious has happend. * We *cannot* have unfinished previous transfer * so it doesn't make any sense to try to stop it. - * Probably we were not able to recover from the + * Probably we were not able to recover from the * previous error. * The only *reasonable* thing I can think of here * is soft reset. --ebs */ iic_dev_reset(dev); - + if ((in_8(&iic->extsts) & EXTSTS_BCS_MASK) != EXTSTS_BCS_FREE){ DBG("%d: iic_xfer, bus is still not free\n", dev->idx); return -EREMOTEIO; } - } + } else { /* Flush master data buffer (just in case) */ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); } - + /* Load slave address */ iic_address(dev, &msgs[0]); - + /* Do real transfer */ for (i = 0; i < num && !ret; ++i) ret = iic_xfer_bytes(dev, &msgs[i], i < num - 1); @@ -648,7 +648,7 @@ static inline u8 iic_clckdiv(unsigned int opb) /* Convert to MHz */ opb /= 1000000; - + if (opb < 20 || opb > 150){ printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n", opb); @@ -666,7 +666,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ struct i2c_adapter* adap; struct ocp_func_iic_data* iic_data = ocp->def->additions; int ret; - + if (!iic_data) printk(KERN_WARNING"ibm-iic%d: missing additional data!\n", ocp->def->index); @@ -679,7 +679,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ dev->idx = ocp->def->index; ocp_set_drvdata(ocp, dev); - + if (!request_mem_region(ocp->def->paddr, sizeof(struct iic_regs), "ibm_iic")) { ret = -EBUSY; @@ -692,7 +692,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){ ret = -ENXIO; goto fail2; } - + init_waitqueue_head(&dev->wq); dev->irq = iic_force_poll ? -1 : ocp->def->irq; @@ -702,29 +702,29 @@ static int __devinit iic_probe(struct ocp_device *ocp){ */ iic_interrupt_mode(dev, 0); if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){ - printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", + printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n", dev->idx, dev->irq); - /* Fallback to the polling mode */ + /* Fallback to the polling mode */ dev->irq = -1; } } - + if (dev->irq < 0) - printk(KERN_WARNING "ibm-iic%d: using polling mode\n", + printk(KERN_WARNING "ibm-iic%d: using polling mode\n", dev->idx); - + /* Board specific settings */ dev->fast_mode = iic_force_fast ? 1 : (iic_data ? iic_data->fast_mode : 0); - - /* clckdiv is the same for *all* IIC interfaces, + + /* clckdiv is the same for *all* IIC interfaces, * but I'd rather make a copy than introduce another global. --ebs */ dev->clckdiv = iic_clckdiv(ocp_sys_info.opb_bus_freq); DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv); - + /* Initialize IIC interface */ iic_dev_init(dev); - + /* Register it with i2c layer */ adap = &dev->adap; adap->dev.parent = &ocp->dev; @@ -736,7 +736,6 @@ static int __devinit iic_probe(struct ocp_device *ocp){ adap->client_register = NULL; adap->client_unregister = NULL; adap->timeout = 1; - adap->retries = 1; /* * If "dev->idx" is negative we consider it as zero. @@ -750,24 +749,24 @@ static int __devinit iic_probe(struct ocp_device *ocp){ dev->idx); goto fail; } - + printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx, dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); return 0; -fail: +fail: if (dev->irq >= 0){ iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); - } + } iounmap(dev->vaddr); -fail2: +fail2: release_mem_region(ocp->def->paddr, sizeof(struct iic_regs)); fail1: ocp_set_drvdata(ocp, NULL); - kfree(dev); + kfree(dev); return ret; } @@ -783,13 +782,13 @@ static void __devexit iic_remove(struct ocp_device *ocp) dev->idx); /* That's *very* bad, just shutdown IRQ ... */ if (dev->irq >= 0){ - iic_interrupt_mode(dev, 0); + iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); dev->irq = -1; } } else { if (dev->irq >= 0){ - iic_interrupt_mode(dev, 0); + iic_interrupt_mode(dev, 0); free_irq(dev->irq, dev); } iounmap(dev->vaddr); @@ -798,7 +797,7 @@ static void __devexit iic_remove(struct ocp_device *ocp) } } -static struct ocp_device_id ibm_iic_ids[] __devinitdata = +static struct ocp_device_id ibm_iic_ids[] __devinitdata = { { .vendor = OCP_VENDOR_IBM, .function = OCP_FUNC_IIC }, { .vendor = OCP_VENDOR_INVALID } diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h index 59d7b437f7ff..fdaa48292cb6 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.h +++ b/drivers/i2c/busses/i2c-ibm_iic.h @@ -2,11 +2,11 @@ * drivers/i2c/busses/i2c-ibm_iic.h * * Support for the IIC peripheral on IBM PPC 4xx - * + * * Copyright (c) 2003 Zultys Technologies. * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> * - * Based on original work by + * Based on original work by * Ian DaSilva <idasilva@mvista.com> * Armin Kuster <akuster@mvista.com> * Matt Porter <mporter@mvista.com> @@ -22,7 +22,7 @@ #ifndef __I2C_IBM_IIC_H_ #define __I2C_IBM_IIC_H_ -#include <linux/i2c.h> +#include <linux/i2c.h> struct iic_regs { u16 mdbuf; @@ -58,7 +58,7 @@ struct ibm_iic_private { #define CNTL_TCT_MASK 0x30 #define CNTL_TCT_SHIFT 4 #define CNTL_RPST 0x08 -#define CNTL_CHT 0x04 +#define CNTL_CHT 0x04 #define CNTL_RW 0x02 #define CNTL_PT 0x01 diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index c70146e4c2c0..ab41400c883e 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -490,7 +490,6 @@ iop3xx_i2c_probe(struct platform_device *pdev) * Default values...should these come in from board code? */ new_adapter->timeout = 100; - new_adapter->retries = 3; new_adapter->algo = &iop3xx_i2c_algo; init_waitqueue_head(&adapter_data->waitq); diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c deleted file mode 100644 index 069ed7f3b395..000000000000 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * drivers/i2c/busses/i2c-ixp4xx.c - * - * Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have - * an on board I2C controller but provide 16 GPIO pins that are often - * used to create an I2C bus. This driver provides an i2c_adapter - * interface that plugs in under algo_bit and drives the GPIO pins - * as instructed by the alogorithm driver. - * - * Author: Deepak Saxena <dsaxena@plexity.net> - * - * Copyright (c) 2003-2004 MontaVista Software Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * - * NOTE: Since different platforms will use different GPIO pins for - * I2C, this driver uses an IXP4xx-specific platform_data - * pointer to pass the GPIO numbers to the driver. This - * allows us to support all the different IXP4xx platforms - * w/o having to put #ifdefs in this driver. - * - * See arch/arm/mach-ixp4xx/ixdp425.c for an example of building a - * device list and filling in the ixp4xx_i2c_pins data structure - * that is passed as the platform_data to this driver. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> - -#include <asm/hardware.h> /* Pick up IXP4xx-specific bits */ - -static inline int ixp4xx_scl_pin(void *data) -{ - return ((struct ixp4xx_i2c_pins*)data)->scl_pin; -} - -static inline int ixp4xx_sda_pin(void *data) -{ - return ((struct ixp4xx_i2c_pins*)data)->sda_pin; -} - -static void ixp4xx_bit_setscl(void *data, int val) -{ - gpio_line_set(ixp4xx_scl_pin(data), 0); - gpio_line_config(ixp4xx_scl_pin(data), - val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); -} - -static void ixp4xx_bit_setsda(void *data, int val) -{ - gpio_line_set(ixp4xx_sda_pin(data), 0); - gpio_line_config(ixp4xx_sda_pin(data), - val ? IXP4XX_GPIO_IN : IXP4XX_GPIO_OUT ); -} - -static int ixp4xx_bit_getscl(void *data) -{ - int scl; - - gpio_line_config(ixp4xx_scl_pin(data), IXP4XX_GPIO_IN ); - gpio_line_get(ixp4xx_scl_pin(data), &scl); - - return scl; -} - -static int ixp4xx_bit_getsda(void *data) -{ - int sda; - - gpio_line_config(ixp4xx_sda_pin(data), IXP4XX_GPIO_IN ); - gpio_line_get(ixp4xx_sda_pin(data), &sda); - - return sda; -} - -struct ixp4xx_i2c_data { - struct ixp4xx_i2c_pins *gpio_pins; - struct i2c_adapter adapter; - struct i2c_algo_bit_data algo_data; -}; - -static int ixp4xx_i2c_remove(struct platform_device *plat_dev) -{ - struct ixp4xx_i2c_data *drv_data = platform_get_drvdata(plat_dev); - - platform_set_drvdata(plat_dev, NULL); - - i2c_del_adapter(&drv_data->adapter); - - kfree(drv_data); - - return 0; -} - -static int ixp4xx_i2c_probe(struct platform_device *plat_dev) -{ - int err; - struct ixp4xx_i2c_pins *gpio = plat_dev->dev.platform_data; - struct ixp4xx_i2c_data *drv_data = - kzalloc(sizeof(struct ixp4xx_i2c_data), GFP_KERNEL); - - if(!drv_data) - return -ENOMEM; - - drv_data->gpio_pins = gpio; - - /* - * We could make a lot of these structures static, but - * certain platforms may have multiple GPIO-based I2C - * buses for various device domains, so we need per-device - * algo_data->data. - */ - drv_data->algo_data.data = gpio; - drv_data->algo_data.setsda = ixp4xx_bit_setsda; - drv_data->algo_data.setscl = ixp4xx_bit_setscl; - drv_data->algo_data.getsda = ixp4xx_bit_getsda; - drv_data->algo_data.getscl = ixp4xx_bit_getscl; - drv_data->algo_data.udelay = 10; - drv_data->algo_data.timeout = 100; - - drv_data->adapter.id = I2C_HW_B_IXP4XX; - drv_data->adapter.class = I2C_CLASS_HWMON; - strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - sizeof(drv_data->adapter.name)); - drv_data->adapter.algo_data = &drv_data->algo_data; - - drv_data->adapter.dev.parent = &plat_dev->dev; - - gpio_line_config(gpio->scl_pin, IXP4XX_GPIO_IN); - gpio_line_config(gpio->sda_pin, IXP4XX_GPIO_IN); - gpio_line_set(gpio->scl_pin, 0); - gpio_line_set(gpio->sda_pin, 0); - - err = i2c_bit_add_bus(&drv_data->adapter); - if (err) { - printk(KERN_ERR "ERROR: Could not install %s\n", plat_dev->dev.bus_id); - - kfree(drv_data); - return err; - } - - platform_set_drvdata(plat_dev, drv_data); - - return 0; -} - -static struct platform_driver ixp4xx_i2c_driver = { - .probe = ixp4xx_i2c_probe, - .remove = ixp4xx_i2c_remove, - .driver = { - .name = "IXP4XX-I2C", - .owner = THIS_MODULE, - }, -}; - -static int __init ixp4xx_i2c_init(void) -{ - return platform_driver_register(&ixp4xx_i2c_driver); -} - -static void __exit ixp4xx_i2c_exit(void) -{ - platform_driver_unregister(&ixp4xx_i2c_driver); -} - -module_init(ixp4xx_i2c_init); -module_exit(ixp4xx_i2c_exit); - -MODULE_DESCRIPTION("GPIO-based I2C adapter for IXP4xx systems"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); - diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index d8de4ac88b7d..bbe787b243b7 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -180,7 +180,7 @@ static void mpc_i2c_stop(struct mpc_i2c *i2c) static int mpc_write(struct mpc_i2c *i2c, int target, const u8 * data, int length, int restart) { - int i; + int i, result; unsigned timeout = i2c->adap.timeout; u32 flags = restart ? CCR_RSTA : 0; @@ -192,15 +192,17 @@ static int mpc_write(struct mpc_i2c *i2c, int target, /* Write target byte */ writeb((target << 1), i2c->base + MPC_I2C_DR); - if (i2c_wait(i2c, timeout, 1) < 0) - return -1; + result = i2c_wait(i2c, timeout, 1); + if (result < 0) + return result; for (i = 0; i < length; i++) { /* Write data byte */ writeb(data[i], i2c->base + MPC_I2C_DR); - if (i2c_wait(i2c, timeout, 1) < 0) - return -1; + result = i2c_wait(i2c, timeout, 1); + if (result < 0) + return result; } return 0; @@ -210,7 +212,7 @@ static int mpc_read(struct mpc_i2c *i2c, int target, u8 * data, int length, int restart) { unsigned timeout = i2c->adap.timeout; - int i; + int i, result; u32 flags = restart ? CCR_RSTA : 0; /* Start with MEN */ @@ -221,8 +223,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target, /* Write target address byte - this time with the read flag set */ writeb((target << 1) | 1, i2c->base + MPC_I2C_DR); - if (i2c_wait(i2c, timeout, 1) < 0) - return -1; + result = i2c_wait(i2c, timeout, 1); + if (result < 0) + return result; if (length) { if (length == 1) @@ -234,8 +237,9 @@ static int mpc_read(struct mpc_i2c *i2c, int target, } for (i = 0; i < length; i++) { - if (i2c_wait(i2c, timeout, 0) < 0) - return -1; + result = i2c_wait(i2c, timeout, 0); + if (result < 0) + return result; /* Generate txack on next to last byte */ if (i == length - 2) @@ -309,7 +313,6 @@ static struct i2c_adapter mpc_ops = { .algo = &mpc_algo, .class = I2C_CLASS_HWMON, .timeout = 1, - .retries = 1 }; static int fsl_i2c_probe(struct platform_device *pdev) @@ -321,9 +324,9 @@ static int fsl_i2c_probe(struct platform_device *pdev) pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data; - if (!(i2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) { + i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + if (!i2c) return -ENOMEM; - } i2c->irq = platform_get_irq(pdev, 0); if (i2c->irq < 0) { diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index bb7bf68a7fb6..036e6a883e67 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -1,6 +1,6 @@ /* - * Driver for the i2c controller on the Marvell line of host bridges for MIPS - * and PPC (e.g, gt642[46]0, mv643[46]0, mv644[46]0). + * Driver for the i2c controller on the Marvell line of host bridges + * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, and Orion SoC family). * * Author: Mark A. Greer <mgreer@mvista.com> * @@ -14,7 +14,7 @@ #include <linux/spinlock.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/mv643xx.h> +#include <linux/mv643xx_i2c.h> #include <linux/platform_device.h> #include <asm/io.h> @@ -86,6 +86,7 @@ struct mv64xxx_i2c_data { u32 cntl_bits; void __iomem *reg_base; u32 reg_base_p; + u32 reg_size; u32 addr1; u32 addr2; u32 bytes_left; @@ -463,17 +464,20 @@ static int __devinit mv64xxx_i2c_map_regs(struct platform_device *pd, struct mv64xxx_i2c_data *drv_data) { - struct resource *r; + int size; + struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0); - if ((r = platform_get_resource(pd, IORESOURCE_MEM, 0)) && - request_mem_region(r->start, MV64XXX_I2C_REG_BLOCK_SIZE, - drv_data->adapter.name)) { + if (!r) + return -ENODEV; - drv_data->reg_base = ioremap(r->start, - MV64XXX_I2C_REG_BLOCK_SIZE); - drv_data->reg_base_p = r->start; - } else - return -ENOMEM; + size = r->end - r->start + 1; + + if (!request_mem_region(r->start, size, drv_data->adapter.name)) + return -EBUSY; + + drv_data->reg_base = ioremap(r->start, size); + drv_data->reg_base_p = r->start; + drv_data->reg_size = size; return 0; } @@ -483,8 +487,7 @@ mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) { if (drv_data->reg_base) { iounmap(drv_data->reg_base); - release_mem_region(drv_data->reg_base_p, - MV64XXX_I2C_REG_BLOCK_SIZE); + release_mem_region(drv_data->reg_base_p, drv_data->reg_size); } drv_data->reg_base = NULL; @@ -529,7 +532,6 @@ mv64xxx_i2c_probe(struct platform_device *pd) drv_data->adapter.owner = THIS_MODULE; drv_data->adapter.class = I2C_CLASS_HWMON; drv_data->adapter.timeout = pdata->timeout; - drv_data->adapter.retries = pdata->retries; drv_data->adapter.nr = pd->id; platform_set_drvdata(pd, drv_data); i2c_set_adapdata(&drv_data->adapter, drv_data); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 1bf590c74166..3dac920e53ea 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -351,6 +351,7 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_ pci_set_drvdata(dev, smbuses); switch(dev->device) { + case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS: case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS: smbuses[0].blockops = 1; diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f2552b19ea60..da6639707ea3 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -362,8 +362,6 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) omap_i2c_enable_clocks(dev); - /* REVISIT: initialize and use adap->retries. This is an optional - * feature */ if ((r = omap_i2c_wait_for_bb(dev)) < 0) goto out; diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index ca18e0be4901..1603c81e39d4 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -368,6 +368,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; + smbus->adapter.nr = PCI_FUNC(dev->devfn); /* set up the sysfs linkage to our parent device */ smbus->adapter.dev.parent = &dev->dev; @@ -375,7 +376,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | (CLK_100K_DIV & CTL_CLK_M))); - error = i2c_add_adapter(&smbus->adapter); + error = i2c_add_numbered_adapter(&smbus->adapter); if (error) goto out_release_region; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 167e4137ee21..9bbe96cef719 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -121,10 +121,6 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, { unsigned char temp; - /* match up the function */ - if (PCI_FUNC(PIIX4_dev->devfn) != id->driver_data) - return -ENODEV; - dev_info(&PIIX4_dev->dev, "Found %s device\n", pci_name(PIIX4_dev)); /* Don't access SMBus on IBM systems which get corrupted eeproms */ @@ -389,28 +385,21 @@ static struct i2c_adapter piix4_adapter = { }; static struct pci_device_id piix4_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3), - .driver_data = 3 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB), - .driver_data = 0 }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3), - .driver_data = 3 }, - { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3), - .driver_data = 0 }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB6) }, + { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_HT1000SB) }, { 0, } }; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 6426a61f8d4d..2598d29fd7a4 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -65,6 +65,7 @@ struct pxa_i2c { unsigned long iosize; int irq; + int use_pio; }; #define _IBMR(i2c) ((i2c)->reg_base + 0) @@ -163,6 +164,7 @@ static void i2c_pxa_show_state(struct pxa_i2c *i2c, int lno, const char *fname) #define eedbg(lvl, x...) do { if ((lvl) < 1) { printk(KERN_DEBUG "" x); } } while(0) static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret); +static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id); static void i2c_pxa_scream_blue_murder(struct pxa_i2c *i2c, const char *why) { @@ -554,6 +556,71 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) writel(icr, _ICR(i2c)); } +static int i2c_pxa_pio_set_master(struct pxa_i2c *i2c) +{ + /* make timeout the same as for interrupt based functions */ + long timeout = 2 * DEF_TIMEOUT; + + /* + * Wait for the bus to become free. + */ + while (timeout-- && readl(_ISR(i2c)) & (ISR_IBB | ISR_UB)) { + udelay(1000); + show_state(i2c); + } + + if (timeout <= 0) { + show_state(i2c); + dev_err(&i2c->adap.dev, + "i2c_pxa: timeout waiting for bus free\n"); + return I2C_RETRY; + } + + /* + * Set master mode. + */ + writel(readl(_ICR(i2c)) | ICR_SCLE, _ICR(i2c)); + + return 0; +} + +static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c, + struct i2c_msg *msg, int num) +{ + unsigned long timeout = 500000; /* 5 seconds */ + int ret = 0; + + ret = i2c_pxa_pio_set_master(i2c); + if (ret) + goto out; + + i2c->msg = msg; + i2c->msg_num = num; + i2c->msg_idx = 0; + i2c->msg_ptr = 0; + i2c->irqlogidx = 0; + + i2c_pxa_start_message(i2c); + + while (timeout-- && i2c->msg_num > 0) { + i2c_pxa_handler(0, i2c); + udelay(10); + } + + i2c_pxa_stop_message(i2c); + + /* + * We place the return code in i2c->msg_idx. + */ + ret = i2c->msg_idx; + +out: + if (timeout == 0) + i2c_pxa_scream_blue_murder(i2c, "timeout"); + + return ret; +} + /* * We are protected by the adapter bus mutex. */ @@ -610,6 +677,35 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) return ret; } +static int i2c_pxa_pio_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct pxa_i2c *i2c = adap->algo_data; + int ret, i; + + /* If the I2C controller is disabled we need to reset it + (probably due to a suspend/resume destroying state). We do + this here as we can then avoid worrying about resuming the + controller before its users. */ + if (!(readl(_ICR(i2c)) & ICR_IUE)) + i2c_pxa_reset(i2c); + + for (i = adap->retries; i >= 0; i--) { + ret = i2c_pxa_do_pio_xfer(i2c, msgs, num); + if (ret != I2C_RETRY) + goto out; + + if (i2c_debug) + dev_dbg(&adap->dev, "Retrying transmission\n"); + udelay(100); + } + i2c_pxa_scream_blue_murder(i2c, "exhausted retries"); + ret = -EREMOTEIO; + out: + i2c_pxa_set_slave(i2c, ret); + return ret; +} + /* * i2c_pxa_master_complete - complete the message and wake up. */ @@ -621,7 +717,8 @@ static void i2c_pxa_master_complete(struct pxa_i2c *i2c, int ret) i2c->msg_num = 0; if (ret) i2c->msg_idx = ret; - wake_up(&i2c->wait); + if (!i2c->use_pio) + wake_up(&i2c->wait); } static void i2c_pxa_irq_txempty(struct pxa_i2c *i2c, u32 isr) @@ -840,6 +937,37 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { .functionality = i2c_pxa_functionality, }; +static const struct i2c_algorithm i2c_pxa_pio_algorithm = { + .master_xfer = i2c_pxa_pio_xfer, + .functionality = i2c_pxa_functionality, +}; + +static void i2c_pxa_enable(struct platform_device *dev) +{ + if (cpu_is_pxa27x()) { + switch (dev->id) { + case 0: + pxa_gpio_mode(GPIO117_I2CSCL_MD); + pxa_gpio_mode(GPIO118_I2CSDA_MD); + break; + case 1: + local_irq_disable(); + PCFR |= PCFR_PI2CEN; + local_irq_enable(); + break; + } + } +} + +static void i2c_pxa_disable(struct platform_device *dev) +{ + if (cpu_is_pxa27x() && dev->id == 1) { + local_irq_disable(); + PCFR &= ~PCFR_PI2CEN; + local_irq_enable(); + } +} + #define res_len(r) ((r)->end - (r)->start + 1) static int i2c_pxa_probe(struct platform_device *dev) { @@ -864,7 +992,6 @@ static int i2c_pxa_probe(struct platform_device *dev) } i2c->adap.owner = THIS_MODULE; - i2c->adap.algo = &i2c_pxa_algorithm; i2c->adap.retries = 5; spin_lock_init(&i2c->lock); @@ -899,34 +1026,28 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif clk_enable(i2c->clk); -#ifdef CONFIG_PXA27x - switch (dev->id) { - case 0: - pxa_gpio_mode(GPIO117_I2CSCL_MD); - pxa_gpio_mode(GPIO118_I2CSDA_MD); - break; - case 1: - local_irq_disable(); - PCFR |= PCFR_PI2CEN; - local_irq_enable(); - } -#endif + i2c_pxa_enable(dev); - ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, - i2c->adap.name, i2c); - if (ret) - goto ereqirq; + if (plat) { + i2c->adap.class = plat->class; + i2c->use_pio = plat->use_pio; + } + if (i2c->use_pio) { + i2c->adap.algo = &i2c_pxa_pio_algorithm; + } else { + i2c->adap.algo = &i2c_pxa_algorithm; + ret = request_irq(irq, i2c_pxa_handler, IRQF_DISABLED, + i2c->adap.name, i2c); + if (ret) + goto ereqirq; + } i2c_pxa_reset(i2c); i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &dev->dev; - if (plat) { - i2c->adap.class = plat->class; - } - /* * If "dev->id" is negative we consider it as zero. * The reason to do so is to avoid sysfs names that only make @@ -952,17 +1073,11 @@ static int i2c_pxa_probe(struct platform_device *dev) return 0; eadapt: - free_irq(irq, i2c); + if (!i2c->use_pio) + free_irq(irq, i2c); ereqirq: clk_disable(i2c->clk); - -#ifdef CONFIG_PXA27x - if (dev->id == 1) { - local_irq_disable(); - PCFR &= ~PCFR_PI2CEN; - local_irq_enable(); - } -#endif + i2c_pxa_disable(dev); eremap: clk_put(i2c->clk); eclk: @@ -979,18 +1094,12 @@ static int i2c_pxa_remove(struct platform_device *dev) platform_set_drvdata(dev, NULL); i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq, i2c); + if (!i2c->use_pio) + free_irq(i2c->irq, i2c); clk_disable(i2c->clk); clk_put(i2c->clk); - -#ifdef CONFIG_PXA27x - if (dev->id == 1) { - local_irq_disable(); - PCFR &= ~PCFR_PI2CEN; - local_irq_enable(); - } -#endif + i2c_pxa_disable(dev); release_mem_region(i2c->iobase, i2c->iosize); kfree(i2c); diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 503a134ec803..8fbbdb4c2f35 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -36,14 +36,6 @@ struct i2c_algo_sibyte_data { /* ----- global defines ----------------------------------------------- */ #define SMB_CSR(a,r) ((long)(a->reg_base + r)) -/* ----- global variables --------------------------------------------- */ - -/* module parameters: - */ -static int bit_scan; /* have a look at what's hanging 'round */ -module_param(bit_scan, int, 0); -MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); - static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, unsigned short flags, char read_write, @@ -140,9 +132,8 @@ static const struct i2c_algorithm i2c_sibyte_algo = { /* * registering functions to load algorithms at runtime */ -int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) +int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) { - int i; struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; /* register new adapter to i2c module... */ @@ -152,24 +143,6 @@ int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); - /* scan bus */ - if (bit_scan) { - union i2c_smbus_data data; - int rc; - printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n", - i2c_adap->name); - for (i = 0x00; i < 0x7f; i++) { - /* XXXKW is this a realistic probe? */ - rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0, - I2C_SMBUS_BYTE_DATA, &data); - if (!rc) { - printk("(%02x)",i); - } else - printk("."); - } - printk("\n"); - } - return i2c_add_adapter(i2c_adap); } diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index 84df29da1ddc..c2a9f8c94f5e 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -1,8 +1,8 @@ /* - i2c-stub.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring + i2c-stub.c - I2C/SMBus chip emulator Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com> + Copyright (C) 2007 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,8 +37,8 @@ MODULE_PARM_DESC(chip_addr, struct stub_chip { u8 pointer; - u8 bytes[256]; - u16 words[256]; + u16 words[256]; /* Byte operations use the LSB as per SMBus + specification */ }; static struct stub_chip *stub_chips; @@ -75,7 +75,7 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, "wrote 0x%02x.\n", addr, command); } else { - data->byte = chip->bytes[chip->pointer++]; + data->byte = chip->words[chip->pointer++] & 0xff; dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, " "read 0x%02x.\n", addr, data->byte); @@ -86,12 +86,13 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags, case I2C_SMBUS_BYTE_DATA: if (read_write == I2C_SMBUS_WRITE) { - chip->bytes[command] = data->byte; + chip->words[command] &= 0xff00; + chip->words[command] |= data->byte; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "wrote 0x%02x at 0x%02x.\n", addr, data->byte, command); } else { - data->byte = chip->bytes[command]; + data->byte = chip->words[command] & 0xff; dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, " "read 0x%02x at 0x%02x.\n", addr, data->byte, command); diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index c9ce77f13c0e..77b13d027f86 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -4,7 +4,7 @@ Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>, Mark D. Studebaker <mdsxyz123@yahoo.com> - Copyright (C) 2005 - 2007 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2005 - 2008 Jean Delvare <khali@linux-fr.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,7 @@ VT8235 0x3177 yes VT8237R 0x3227 yes VT8237A 0x3337 yes + VT8237S 0x3372 yes VT8251 0x3287 yes CX700 0x8324 yes @@ -318,6 +319,10 @@ static int __devinit vt596_probe(struct pci_dev *pdev, unsigned char temp; int error = -ENODEV; + /* driver_data might come from user-space, so check it */ + if (id->driver_data & 1 || id->driver_data > 0xff) + return -EINVAL; + /* Determine the address of the SMBus areas */ if (force_addr) { vt596_smba = force_addr & 0xfff0; @@ -389,6 +394,7 @@ found: case PCI_DEVICE_ID_VIA_8251: case PCI_DEVICE_ID_VIA_8237: case PCI_DEVICE_ID_VIA_8237A: + case PCI_DEVICE_ID_VIA_8237S: case PCI_DEVICE_ID_VIA_8235: case PCI_DEVICE_ID_VIA_8233A: case PCI_DEVICE_ID_VIA_8233_0: @@ -440,6 +446,8 @@ static struct pci_device_id vt596_ids[] = { .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A), .driver_data = SMBBA3 }, + { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S), + .driver_data = SMBBA3 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4), .driver_data = SMBBA1 }, { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251), @@ -455,6 +463,7 @@ static struct pci_driver vt596_driver = { .name = "vt596_smbus", .id_table = vt596_ids, .probe = vt596_probe, + .dynids.use_driver_data = 1, }; static int __init i2c_vt596_init(void) diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 2e1c24f671cf..bd7082c2443d 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -4,32 +4,6 @@ menu "Miscellaneous I2C Chip support" -config SENSORS_DS1337 - tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)" - depends on EXPERIMENTAL - help - If you say yes here you get support for Dallas Semiconductor - DS1337 and DS1339 real-time clock chips. - - This driver can also be built as a module. If so, the module - will be called ds1337. - - This driver is deprecated and will be dropped soon. Use - rtc-ds1307 instead. - -config SENSORS_DS1374 - tristate "Dallas DS1374 Real Time Clock (DEPRECATED)" - depends on EXPERIMENTAL - help - If you say yes here you get support for Dallas Semiconductor - DS1374 real-time clock chips. - - This driver can also be built as a module. If so, the module - will be called ds1374. - - This driver is deprecated and will be dropped soon. Use - rtc-ds1374 instead. - config DS1682 tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm" depends on EXPERIMENTAL @@ -57,7 +31,7 @@ config SENSORS_PCF8574 default n help If you say yes here you get support for Philips PCF8574 and - PCF8574A chips. + PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus. This driver can also be built as a module. If so, the module will be called pcf8574. @@ -65,6 +39,20 @@ config SENSORS_PCF8574 These devices are hard to detect and rarely found on mainstream hardware. If unsure, say N. +config PCF8575 + tristate "Philips PCF8575" + default n + help + If you say yes here you get support for Philips PCF8575 chip. + This chip is a 16-bit I/O expander for the I2C bus. Several other + chip manufacturers sell equivalent chips, e.g. Texas Instruments. + + This driver can also be built as a module. If so, the module + will be called pcf8575. + + This device is hard to detect and is rarely found on mainstream + hardware. If unsure, say N. + config SENSORS_PCA9539 tristate "Philips PCA9539 16-bit I/O port" depends on EXPERIMENTAL @@ -100,12 +88,8 @@ config ISP1301_OMAP This driver can also be built as a module. If so, the module will be called isp1301_omap. -# NOTE: This isn't really OMAP-specific, except for the current -# interface location in <include/asm-arm/arch-omap/tps65010.h> -# and having mostly OMAP-specific board support config TPS65010 tristate "TPS6501x Power Management chips" - depends on ARCH_OMAP default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of @@ -116,18 +100,6 @@ config TPS65010 This driver can also be built as a module. If so, the module will be called tps65010. -config SENSORS_M41T00 - tristate "ST M41T00 RTC chip (DEPRECATED)" - depends on PPC32 - help - If you say yes here you get support for the ST M41T00 RTC chip. - - This driver can also be built as a module. If so, the module - will be called m41t00. - - This driver is deprecated and will be dropped soon. Use - rtc-ds1307 or rtc-m41t80 instead. - config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" depends on EXPERIMENTAL diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index ca924e105959..501f00cea782 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile @@ -2,14 +2,12 @@ # Makefile for miscellaneous I2C chip drivers. # -obj-$(CONFIG_SENSORS_DS1337) += ds1337.o -obj-$(CONFIG_SENSORS_DS1374) += ds1374.o obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o obj-$(CONFIG_SENSORS_MAX6875) += max6875.o -obj-$(CONFIG_SENSORS_M41T00) += m41t00.o obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o +obj-$(CONFIG_PCF8575) += pcf8575.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o obj-$(CONFIG_TPS65010) += tps65010.o diff --git a/drivers/i2c/chips/ds1337.c b/drivers/i2c/chips/ds1337.c deleted file mode 100644 index ec17d6b684a2..000000000000 --- a/drivers/i2c/chips/ds1337.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * linux/drivers/i2c/chips/ds1337.c - * - * Copyright (C) 2005 James Chapman <jchapman@katalix.com> - * - * based on linux/drivers/acorn/char/pcf8583.c - * Copyright (C) 2000 Russell King - * - * 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. - * - * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/string.h> -#include <linux/rtc.h> /* get the user-level API */ -#include <linux/bcd.h> -#include <linux/list.h> - -/* Device registers */ -#define DS1337_REG_HOUR 2 -#define DS1337_REG_DAY 3 -#define DS1337_REG_DATE 4 -#define DS1337_REG_MONTH 5 -#define DS1337_REG_CONTROL 14 -#define DS1337_REG_STATUS 15 - -/* FIXME - how do we export these interface constants? */ -#define DS1337_GET_DATE 0 -#define DS1337_SET_DATE 1 - -/* - * Functions declaration - */ -static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END }; - -I2C_CLIENT_INSMOD_1(ds1337); - -static int ds1337_attach_adapter(struct i2c_adapter *adapter); -static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind); -static void ds1337_init_client(struct i2c_client *client); -static int ds1337_detach_client(struct i2c_client *client); -static int ds1337_command(struct i2c_client *client, unsigned int cmd, - void *arg); - -/* - * Driver data (common to all clients) - */ -static struct i2c_driver ds1337_driver = { - .driver = { - .name = "ds1337", - }, - .attach_adapter = ds1337_attach_adapter, - .detach_client = ds1337_detach_client, - .command = ds1337_command, -}; - -/* - * Client data (each client gets its own) - */ -struct ds1337_data { - struct i2c_client client; - struct list_head list; -}; - -/* - * Internal variables - */ -static LIST_HEAD(ds1337_clients); - -static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value) -{ - s32 tmp = i2c_smbus_read_byte_data(client, reg); - - if (tmp < 0) - return -EIO; - - *value = tmp; - - return 0; -} - -/* - * Chip access functions - */ -static int ds1337_get_datetime(struct i2c_client *client, struct rtc_time *dt) -{ - int result; - u8 buf[7]; - u8 val; - struct i2c_msg msg[2]; - u8 offs = 0; - - if (!dt) { - dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); - return -EINVAL; - } - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &offs; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = sizeof(buf); - msg[1].buf = &buf[0]; - - result = i2c_transfer(client->adapter, msg, 2); - - dev_dbg(&client->dev, "%s: [%d] %02x %02x %02x %02x %02x %02x %02x\n", - __FUNCTION__, result, buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6]); - - if (result == 2) { - dt->tm_sec = BCD2BIN(buf[0]); - dt->tm_min = BCD2BIN(buf[1]); - val = buf[2] & 0x3f; - dt->tm_hour = BCD2BIN(val); - dt->tm_wday = BCD2BIN(buf[3]) - 1; - dt->tm_mday = BCD2BIN(buf[4]); - val = buf[5] & 0x7f; - dt->tm_mon = BCD2BIN(val) - 1; - dt->tm_year = BCD2BIN(buf[6]); - if (buf[5] & 0x80) - dt->tm_year += 100; - - dev_dbg(&client->dev, "%s: secs=%d, mins=%d, " - "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, dt->tm_sec, dt->tm_min, - dt->tm_hour, dt->tm_mday, - dt->tm_mon, dt->tm_year, dt->tm_wday); - - return 0; - } - - dev_err(&client->dev, "error reading data! %d\n", result); - return -EIO; -} - -static int ds1337_set_datetime(struct i2c_client *client, struct rtc_time *dt) -{ - int result; - u8 buf[8]; - u8 val; - struct i2c_msg msg[1]; - - if (!dt) { - dev_dbg(&client->dev, "%s: EINVAL: dt=NULL\n", __FUNCTION__); - return -EINVAL; - } - - dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, " - "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, - dt->tm_sec, dt->tm_min, dt->tm_hour, - dt->tm_mday, dt->tm_mon, dt->tm_year, dt->tm_wday); - - buf[0] = 0; /* reg offset */ - buf[1] = BIN2BCD(dt->tm_sec); - buf[2] = BIN2BCD(dt->tm_min); - buf[3] = BIN2BCD(dt->tm_hour); - buf[4] = BIN2BCD(dt->tm_wday + 1); - buf[5] = BIN2BCD(dt->tm_mday); - buf[6] = BIN2BCD(dt->tm_mon + 1); - val = dt->tm_year; - if (val >= 100) { - val -= 100; - buf[6] |= (1 << 7); - } - buf[7] = BIN2BCD(val); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = sizeof(buf); - msg[0].buf = &buf[0]; - - result = i2c_transfer(client->adapter, msg, 1); - if (result == 1) - return 0; - - dev_err(&client->dev, "error writing data! %d\n", result); - return -EIO; -} - -static int ds1337_command(struct i2c_client *client, unsigned int cmd, - void *arg) -{ - dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd); - - switch (cmd) { - case DS1337_GET_DATE: - return ds1337_get_datetime(client, arg); - - case DS1337_SET_DATE: - return ds1337_set_datetime(client, arg); - - default: - return -EINVAL; - } -} - -/* - * Public API for access to specific device. Useful for low-level - * RTC access from kernel code. - */ -int ds1337_do_command(int bus, int cmd, void *arg) -{ - struct list_head *walk; - struct list_head *tmp; - struct ds1337_data *data; - - list_for_each_safe(walk, tmp, &ds1337_clients) { - data = list_entry(walk, struct ds1337_data, list); - if (data->client.adapter->nr == bus) - return ds1337_command(&data->client, cmd, arg); - } - - return -ENODEV; -} - -static int ds1337_attach_adapter(struct i2c_adapter *adapter) -{ - return i2c_probe(adapter, &addr_data, ds1337_detect); -} - -/* - * The following function does more than just detection. If detection - * succeeds, it also registers the new chip. - */ -static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *new_client; - struct ds1337_data *data; - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_I2C)) - goto exit; - - if (!(data = kzalloc(sizeof(struct ds1337_data), GFP_KERNEL))) { - err = -ENOMEM; - goto exit; - } - INIT_LIST_HEAD(&data->list); - - /* The common I2C client data is placed right before the - * DS1337-specific data. - */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &ds1337_driver; - new_client->flags = 0; - - /* - * Now we do the remaining detection. A negative kind means that - * the driver was loaded with no force parameter (default), so we - * must both detect and identify the chip. A zero kind means that - * the driver was loaded with the force parameter, the detection - * step shall be skipped. A positive kind means that the driver - * was loaded with the force parameter and a given kind of chip is - * requested, so both the detection and the identification steps - * are skipped. - * - * For detection, we read registers that are most likely to cause - * detection failure, i.e. those that have more bits with fixed - * or reserved values. - */ - - /* Default to an DS1337 if forced */ - if (kind == 0) - kind = ds1337; - - if (kind < 0) { /* detection and identification */ - u8 data; - - /* Check that status register bits 6-2 are zero */ - if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) || - (data & 0x7c)) - goto exit_free; - - /* Check for a valid day register value */ - if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) || - (data == 0) || (data & 0xf8)) - goto exit_free; - - /* Check for a valid date register value */ - if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) || - (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) || - (data >= 0x32)) - goto exit_free; - - /* Check for a valid month register value */ - if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) || - (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) || - ((data >= 0x13) && (data <= 0x19))) - goto exit_free; - - /* Check that control register bits 6-5 are zero */ - if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) || - (data & 0x60)) - goto exit_free; - - kind = ds1337; - } - - if (kind == ds1337) - name = "ds1337"; - - /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - - /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto exit_free; - - /* Initialize the DS1337 chip */ - ds1337_init_client(new_client); - - /* Add client to local list */ - list_add(&data->list, &ds1337_clients); - - return 0; - -exit_free: - kfree(data); -exit: - return err; -} - -static void ds1337_init_client(struct i2c_client *client) -{ - u8 status, control; - - /* On some boards, the RTC isn't configured by boot firmware. - * Handle that case by starting/configuring the RTC now. - */ - status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); - control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL); - - if ((status & 0x80) || (control & 0x80)) { - /* RTC not running */ - u8 buf[1+16]; /* First byte is interpreted as address */ - struct i2c_msg msg[1]; - - dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__); - - /* Initialize all, including STATUS and CONTROL to zero */ - memset(buf, 0, sizeof(buf)); - - /* Write valid values in the date/time registers */ - buf[1+DS1337_REG_DAY] = 1; - buf[1+DS1337_REG_DATE] = 1; - buf[1+DS1337_REG_MONTH] = 1; - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = sizeof(buf); - msg[0].buf = &buf[0]; - - i2c_transfer(client->adapter, msg, 1); - } else { - /* Running: ensure that device is set in 24-hour mode */ - s32 val; - - val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR); - if ((val >= 0) && (val & (1 << 6))) - i2c_smbus_write_byte_data(client, DS1337_REG_HOUR, - val & 0x3f); - } -} - -static int ds1337_detach_client(struct i2c_client *client) -{ - int err; - struct ds1337_data *data = i2c_get_clientdata(client); - - if ((err = i2c_detach_client(client))) - return err; - - list_del(&data->list); - kfree(data); - return 0; -} - -static int __init ds1337_init(void) -{ - return i2c_add_driver(&ds1337_driver); -} - -static void __exit ds1337_exit(void) -{ - i2c_del_driver(&ds1337_driver); -} - -MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); -MODULE_DESCRIPTION("DS1337 RTC driver"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL_GPL(ds1337_do_command); - -module_init(ds1337_init); -module_exit(ds1337_exit); diff --git a/drivers/i2c/chips/ds1374.c b/drivers/i2c/chips/ds1374.c deleted file mode 100644 index 8a2ff0c114d9..000000000000 --- a/drivers/i2c/chips/ds1374.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * drivers/i2c/chips/ds1374.c - * - * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock - * - * Author: Randy Vinson <rvinson@mvista.com> - * - * Based on the m41t00.c by Mark Greer <mgreer@mvista.com> - * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -/* - * This i2c client/driver wedges between the drivers/char/genrtc.c RTC - * interface and the SMBus interface of the i2c subsystem. - * It would be more efficient to use i2c msgs/i2c_transfer directly but, as - * recommened in .../Documentation/i2c/writing-clients section - * "Sending and receiving", using SMBus level communication is preferred. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/rtc.h> -#include <linux/bcd.h> -#include <linux/mutex.h> -#include <linux/workqueue.h> - -#define DS1374_REG_TOD0 0x00 -#define DS1374_REG_TOD1 0x01 -#define DS1374_REG_TOD2 0x02 -#define DS1374_REG_TOD3 0x03 -#define DS1374_REG_WDALM0 0x04 -#define DS1374_REG_WDALM1 0x05 -#define DS1374_REG_WDALM2 0x06 -#define DS1374_REG_CR 0x07 -#define DS1374_REG_SR 0x08 -#define DS1374_REG_SR_OSF 0x80 -#define DS1374_REG_TCR 0x09 - -#define DS1374_DRV_NAME "ds1374" - -static DEFINE_MUTEX(ds1374_mutex); - -static struct i2c_driver ds1374_driver; -static struct i2c_client *save_client; - -static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_addr, - .probe = ignore, - .ignore = ignore, -}; - -static ulong ds1374_read_rtc(void) -{ - ulong time = 0; - int reg = DS1374_REG_WDALM0; - - while (reg--) { - s32 tmp; - if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) { - dev_warn(&save_client->dev, - "can't read from rtc chip\n"); - return 0; - } - time = (time << 8) | (tmp & 0xff); - } - return time; -} - -static void ds1374_write_rtc(ulong time) -{ - int reg; - - for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) { - if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff) - < 0) { - dev_warn(&save_client->dev, - "can't write to rtc chip\n"); - break; - } - time = time >> 8; - } -} - -static void ds1374_check_rtc_status(void) -{ - s32 tmp; - - tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR); - if (tmp < 0) { - dev_warn(&save_client->dev, - "can't read status from rtc chip\n"); - return; - } - if (tmp & DS1374_REG_SR_OSF) { - dev_warn(&save_client->dev, - "oscillator discontinuity flagged, time unreliable\n"); - tmp &= ~DS1374_REG_SR_OSF; - tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR, - tmp & 0xff); - if (tmp < 0) - dev_warn(&save_client->dev, - "can't clear discontinuity notification\n"); - } -} - -ulong ds1374_get_rtc_time(void) -{ - ulong t1, t2; - int limit = 10; /* arbitrary retry limit */ - - mutex_lock(&ds1374_mutex); - - /* - * Since the reads are being performed one byte at a time using - * the SMBus vs a 4-byte i2c transfer, there is a chance that a - * carry will occur during the read. To detect this, 2 reads are - * performed and compared. - */ - do { - t1 = ds1374_read_rtc(); - t2 = ds1374_read_rtc(); - } while (t1 != t2 && limit--); - - mutex_unlock(&ds1374_mutex); - - if (t1 != t2) { - dev_warn(&save_client->dev, - "can't get consistent time from rtc chip\n"); - t1 = 0; - } - - return t1; -} - -static ulong new_time; - -static void ds1374_set_work(struct work_struct *work) -{ - ulong t1, t2; - int limit = 10; /* arbitrary retry limit */ - - t1 = new_time; - - mutex_lock(&ds1374_mutex); - - /* - * Since the writes are being performed one byte at a time using - * the SMBus vs a 4-byte i2c transfer, there is a chance that a - * carry will occur during the write. To detect this, the write - * value is read back and compared. - */ - do { - ds1374_write_rtc(t1); - t2 = ds1374_read_rtc(); - } while (t1 != t2 && limit--); - - mutex_unlock(&ds1374_mutex); - - if (t1 != t2) - dev_warn(&save_client->dev, - "can't confirm time set from rtc chip\n"); -} - -static struct workqueue_struct *ds1374_workqueue; - -static DECLARE_WORK(ds1374_work, ds1374_set_work); - -int ds1374_set_rtc_time(ulong nowtime) -{ - new_time = nowtime; - - if (in_interrupt()) - queue_work(ds1374_workqueue, &ds1374_work); - else - ds1374_set_work(NULL); - - return 0; -} - -/* - ***************************************************************************** - * - * Driver Interface - * - ***************************************************************************** - */ -static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) -{ - struct i2c_client *client; - int rc; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); - client->addr = addr; - client->adapter = adap; - client->driver = &ds1374_driver; - - ds1374_workqueue = create_singlethread_workqueue("ds1374"); - if (!ds1374_workqueue) { - kfree(client); - return -ENOMEM; /* most expected reason */ - } - - if ((rc = i2c_attach_client(client)) != 0) { - kfree(client); - return rc; - } - - save_client = client; - - ds1374_check_rtc_status(); - - return 0; -} - -static int ds1374_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, ds1374_probe); -} - -static int ds1374_detach(struct i2c_client *client) -{ - int rc; - - if ((rc = i2c_detach_client(client)) == 0) { - kfree(i2c_get_clientdata(client)); - destroy_workqueue(ds1374_workqueue); - } - return rc; -} - -static struct i2c_driver ds1374_driver = { - .driver = { - .name = DS1374_DRV_NAME, - }, - .id = I2C_DRIVERID_DS1374, - .attach_adapter = ds1374_attach, - .detach_client = ds1374_detach, -}; - -static int __init ds1374_init(void) -{ - return i2c_add_driver(&ds1374_driver); -} - -static void __exit ds1374_exit(void) -{ - i2c_del_driver(&ds1374_driver); -} - -module_init(ds1374_init); -module_exit(ds1374_exit); - -MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>"); -MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 1a7eeebac506..fde297b21ad7 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c @@ -35,7 +35,7 @@ #include <linux/mutex.h> /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, +static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, I2C_CLIENT_END }; /* Insmod parameters */ diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c index b767603a07ba..2a3160153f54 100644 --- a/drivers/i2c/chips/isp1301_omap.c +++ b/drivers/i2c/chips/isp1301_omap.c @@ -100,7 +100,7 @@ struct isp1301 { #if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE) -#include <asm/arch/tps65010.h> +#include <linux/i2c/tps65010.h> #else @@ -259,12 +259,6 @@ static inline const char *state_name(struct isp1301 *isp) return state_string(isp->otg.state); } -#ifdef VERBOSE -#define dev_vdbg dev_dbg -#else -#define dev_vdbg(dev, fmt, arg...) do{}while(0) -#endif - /*-------------------------------------------------------------------------*/ /* NOTE: some of this ISP1301 setup is specific to H2 boards; diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c deleted file mode 100644 index 3fcb646e2073..000000000000 --- a/drivers/i2c/chips/m41t00.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * I2C client/driver for the ST M41T00 family of i2c rtc chips. - * - * Author: Mark A. Greer <mgreer@mvista.com> - * - * 2005, 2006 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - */ -/* - * This i2c client/driver wedges between the drivers/char/genrtc.c RTC - * interface and the SMBus interface of the i2c subsystem. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/rtc.h> -#include <linux/bcd.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -#include <linux/m41t00.h> -#include <asm/time.h> -#include <asm/rtc.h> - -static struct i2c_driver m41t00_driver; -static struct i2c_client *save_client; - -static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_addr, - .probe = ignore, - .ignore = ignore, -}; - -struct m41t00_chip_info { - u8 type; - char *name; - u8 read_limit; - u8 sec; /* Offsets for chip regs */ - u8 min; - u8 hour; - u8 day; - u8 mon; - u8 year; - u8 alarm_mon; - u8 alarm_hour; - u8 sqw; - u8 sqw_freq; -}; - -static struct m41t00_chip_info m41t00_chip_info_tbl[] = { - { - .type = M41T00_TYPE_M41T00, - .name = "m41t00", - .read_limit = 5, - .sec = 0, - .min = 1, - .hour = 2, - .day = 4, - .mon = 5, - .year = 6, - }, - { - .type = M41T00_TYPE_M41T81, - .name = "m41t81", - .read_limit = 1, - .sec = 1, - .min = 2, - .hour = 3, - .day = 5, - .mon = 6, - .year = 7, - .alarm_mon = 0xa, - .alarm_hour = 0xc, - .sqw = 0x13, - }, - { - .type = M41T00_TYPE_M41T85, - .name = "m41t85", - .read_limit = 1, - .sec = 1, - .min = 2, - .hour = 3, - .day = 5, - .mon = 6, - .year = 7, - .alarm_mon = 0xa, - .alarm_hour = 0xc, - .sqw = 0x13, - }, -}; -static struct m41t00_chip_info *m41t00_chip; - -ulong -m41t00_get_rtc_time(void) -{ - s32 sec, min, hour, day, mon, year; - s32 sec1, min1, hour1, day1, mon1, year1; - u8 reads = 0; - u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */ - struct i2c_msg msgs[] = { - { - .addr = save_client->addr, - .flags = 0, - .len = 1, - .buf = msgbuf, - }, - { - .addr = save_client->addr, - .flags = I2C_M_RD, - .len = 8, - .buf = buf, - }, - }; - - sec = min = hour = day = mon = year = 0; - - do { - if (i2c_transfer(save_client->adapter, msgs, 2) < 0) - goto read_err; - - sec1 = sec; - min1 = min; - hour1 = hour; - day1 = day; - mon1 = mon; - year1 = year; - - sec = buf[m41t00_chip->sec] & 0x7f; - min = buf[m41t00_chip->min] & 0x7f; - hour = buf[m41t00_chip->hour] & 0x3f; - day = buf[m41t00_chip->day] & 0x3f; - mon = buf[m41t00_chip->mon] & 0x1f; - year = buf[m41t00_chip->year]; - } while ((++reads < m41t00_chip->read_limit) && ((sec != sec1) - || (min != min1) || (hour != hour1) || (day != day1) - || (mon != mon1) || (year != year1))); - - if ((m41t00_chip->read_limit > 1) && ((sec != sec1) || (min != min1) - || (hour != hour1) || (day != day1) || (mon != mon1) - || (year != year1))) - goto read_err; - - sec = BCD2BIN(sec); - min = BCD2BIN(min); - hour = BCD2BIN(hour); - day = BCD2BIN(day); - mon = BCD2BIN(mon); - year = BCD2BIN(year); - - year += 1900; - if (year < 1970) - year += 100; - - return mktime(year, mon, day, hour, min, sec); - -read_err: - dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n"); - return 0; -} -EXPORT_SYMBOL_GPL(m41t00_get_rtc_time); - -static void -m41t00_set(void *arg) -{ - struct rtc_time tm; - int nowtime = *(int *)arg; - s32 sec, min, hour, day, mon, year; - u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 }; - struct i2c_msg msgs[] = { - { - .addr = save_client->addr, - .flags = 0, - .len = 1, - .buf = msgbuf, - }, - { - .addr = save_client->addr, - .flags = I2C_M_RD, - .len = 8, - .buf = buf, - }, - }; - - to_tm(nowtime, &tm); - tm.tm_year = (tm.tm_year - 1900) % 100; - - sec = BIN2BCD(tm.tm_sec); - min = BIN2BCD(tm.tm_min); - hour = BIN2BCD(tm.tm_hour); - day = BIN2BCD(tm.tm_mday); - mon = BIN2BCD(tm.tm_mon); - year = BIN2BCD(tm.tm_year); - - /* Read reg values into buf[0..7]/wbuf[1..8] */ - if (i2c_transfer(save_client->adapter, msgs, 2) < 0) { - dev_err(&save_client->dev, "m41t00_set: Read error\n"); - return; - } - - wbuf[0] = 0; /* offset into rtc's regs */ - buf[m41t00_chip->sec] = (buf[m41t00_chip->sec] & ~0x7f) | (sec & 0x7f); - buf[m41t00_chip->min] = (buf[m41t00_chip->min] & ~0x7f) | (min & 0x7f); - buf[m41t00_chip->hour] = (buf[m41t00_chip->hour] & ~0x3f) | (hour& 0x3f); - buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f); - buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f); - buf[m41t00_chip->year] = year; - - if (i2c_master_send(save_client, wbuf, 9) < 0) - dev_err(&save_client->dev, "m41t00_set: Write error\n"); -} - -static ulong new_time; -/* well, isn't this API just _lovely_? */ -static void -m41t00_barf(struct work_struct *unusable) -{ - m41t00_set(&new_time); -} - -static struct workqueue_struct *m41t00_wq; -static DECLARE_WORK(m41t00_work, m41t00_barf); - -int -m41t00_set_rtc_time(ulong nowtime) -{ - new_time = nowtime; - - if (in_interrupt()) - queue_work(m41t00_wq, &m41t00_work); - else - m41t00_set(&new_time); - - return 0; -} -EXPORT_SYMBOL_GPL(m41t00_set_rtc_time); - -/* - ***************************************************************************** - * - * platform_data Driver Interface - * - ***************************************************************************** - */ -static int __init -m41t00_platform_probe(struct platform_device *pdev) -{ - struct m41t00_platform_data *pdata; - int i; - - if (pdev && (pdata = pdev->dev.platform_data)) { - normal_addr[0] = pdata->i2c_addr; - - for (i=0; i<ARRAY_SIZE(m41t00_chip_info_tbl); i++) - if (m41t00_chip_info_tbl[i].type == pdata->type) { - m41t00_chip = &m41t00_chip_info_tbl[i]; - m41t00_chip->sqw_freq = pdata->sqw_freq; - return 0; - } - } - return -ENODEV; -} - -static int __exit -m41t00_platform_remove(struct platform_device *pdev) -{ - return 0; -} - -static struct platform_driver m41t00_platform_driver = { - .probe = m41t00_platform_probe, - .remove = m41t00_platform_remove, - .driver = { - .owner = THIS_MODULE, - .name = M41T00_DRV_NAME, - }, -}; - -/* - ***************************************************************************** - * - * Driver Interface - * - ***************************************************************************** - */ -static int -m41t00_probe(struct i2c_adapter *adap, int addr, int kind) -{ - struct i2c_client *client; - int rc; - - if (!i2c_check_functionality(adap, I2C_FUNC_I2C - | I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - strlcpy(client->name, m41t00_chip->name, I2C_NAME_SIZE); - client->addr = addr; - client->adapter = adap; - client->driver = &m41t00_driver; - - if ((rc = i2c_attach_client(client))) - goto attach_err; - - if (m41t00_chip->type != M41T00_TYPE_M41T00) { - /* If asked, disable SQW, set SQW frequency & re-enable */ - if (m41t00_chip->sqw_freq) - if (((rc = i2c_smbus_read_byte_data(client, - m41t00_chip->alarm_mon)) < 0) - || ((rc = i2c_smbus_write_byte_data(client, - m41t00_chip->alarm_mon, rc & ~0x40)) <0) - || ((rc = i2c_smbus_write_byte_data(client, - m41t00_chip->sqw, - m41t00_chip->sqw_freq)) < 0) - || ((rc = i2c_smbus_write_byte_data(client, - m41t00_chip->alarm_mon, rc | 0x40)) <0)) - goto sqw_err; - - /* Make sure HT (Halt Update) bit is cleared */ - if ((rc = i2c_smbus_read_byte_data(client, - m41t00_chip->alarm_hour)) < 0) - goto ht_err; - - if (rc & 0x40) - if ((rc = i2c_smbus_write_byte_data(client, - m41t00_chip->alarm_hour, rc & ~0x40))<0) - goto ht_err; - } - - /* Make sure ST (stop) bit is cleared */ - if ((rc = i2c_smbus_read_byte_data(client, m41t00_chip->sec)) < 0) - goto st_err; - - if (rc & 0x80) - if ((rc = i2c_smbus_write_byte_data(client, m41t00_chip->sec, - rc & ~0x80)) < 0) - goto st_err; - - m41t00_wq = create_singlethread_workqueue(m41t00_chip->name); - save_client = client; - return 0; - -st_err: - dev_err(&client->dev, "m41t00_probe: Can't clear ST bit\n"); - goto attach_err; -ht_err: - dev_err(&client->dev, "m41t00_probe: Can't clear HT bit\n"); - goto attach_err; -sqw_err: - dev_err(&client->dev, "m41t00_probe: Can't set SQW Frequency\n"); -attach_err: - kfree(client); - return rc; -} - -static int -m41t00_attach(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, m41t00_probe); -} - -static int -m41t00_detach(struct i2c_client *client) -{ - int rc; - - if ((rc = i2c_detach_client(client)) == 0) { - kfree(client); - destroy_workqueue(m41t00_wq); - } - return rc; -} - -static struct i2c_driver m41t00_driver = { - .driver = { - .name = M41T00_DRV_NAME, - }, - .id = I2C_DRIVERID_STM41T00, - .attach_adapter = m41t00_attach, - .detach_client = m41t00_detach, -}; - -static int __init -m41t00_init(void) -{ - int rc; - - if (!(rc = platform_driver_register(&m41t00_platform_driver))) - rc = i2c_add_driver(&m41t00_driver); - return rc; -} - -static void __exit -m41t00_exit(void) -{ - i2c_del_driver(&m41t00_driver); - platform_driver_unregister(&m41t00_platform_driver); -} - -module_init(m41t00_init); -module_exit(m41t00_exit); - -MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); -MODULE_DESCRIPTION("ST Microelectronics M41T00 RTC I2C Client Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c index 64692f666372..fb7ea5637eca 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/i2c/chips/max6875.c @@ -34,7 +34,7 @@ #include <linux/mutex.h> /* Do not scan - the MAX6875 access method will write to some EEPROM chips */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(max6875); diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 21c6dd69193c..b3b830ccf209 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c @@ -41,9 +41,11 @@ #include <linux/i2c.h> /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + I2C_CLIENT_END +}; /* Insmod parameters */ I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c new file mode 100644 index 000000000000..3ea08ac0bfa3 --- /dev/null +++ b/drivers/i2c/chips/pcf8575.c @@ -0,0 +1,214 @@ +/* + pcf8575.c + + About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus + produced by a.o. Philips Semiconductors. + + Copyright (C) 2006 Michael Hennerich, Analog Devices Inc. + <hennerich@blackfin.uclinux.org> + Based on pcf8574.c. + + Copyright (c) 2007 Bart Van Assche <bart.vanassche@gmail.com>. + Ported this driver from ucLinux to the mainstream Linux kernel. + + 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 <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/slab.h> /* kzalloc() */ +#include <linux/sysfs.h> /* sysfs_create_group() */ + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + I2C_CLIENT_END +}; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD; + + +/* Each client has this additional data */ +struct pcf8575_data { + struct i2c_client client; + int write; /* last written value, or error code */ +}; + +static int pcf8575_attach_adapter(struct i2c_adapter *adapter); +static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind); +static int pcf8575_detach_client(struct i2c_client *client); + +/* This is the driver that will be inserted */ +static struct i2c_driver pcf8575_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "pcf8575", + }, + .attach_adapter = pcf8575_attach_adapter, + .detach_client = pcf8575_detach_client, +}; + +/* following are the sysfs callback functions */ +static ssize_t show_read(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u16 val; + u8 iopin_state[2]; + + i2c_master_recv(client, iopin_state, 2); + + val = iopin_state[0]; + val |= iopin_state[1] << 8; + + return sprintf(buf, "%u\n", val); +} + +static DEVICE_ATTR(read, S_IRUGO, show_read, NULL); + +static ssize_t show_write(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pcf8575_data *data = dev_get_drvdata(dev); + if (data->write < 0) + return data->write; + return sprintf(buf, "%d\n", data->write); +} + +static ssize_t set_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct pcf8575_data *data = i2c_get_clientdata(client); + unsigned long val = simple_strtoul(buf, NULL, 10); + u8 iopin_state[2]; + + if (val > 0xffff) + return -EINVAL; + + data->write = val; + + iopin_state[0] = val & 0xFF; + iopin_state[1] = val >> 8; + + i2c_master_send(client, iopin_state, 2); + + return count; +} + +static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write); + +static struct attribute *pcf8575_attributes[] = { + &dev_attr_read.attr, + &dev_attr_write.attr, + NULL +}; + +static const struct attribute_group pcf8575_attr_group = { + .attrs = pcf8575_attributes, +}; + +/* + * Real code + */ + +static int pcf8575_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_probe(adapter, &addr_data, pcf8575_detect); +} + +/* This function is called by i2c_probe */ +static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct pcf8575_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + 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. */ + data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &pcf8575_driver; + strlcpy(client->name, "pcf8575", I2C_NAME_SIZE); + data->write = -EAGAIN; + + /* This is the place to detect whether the chip at the specified + address really is a PCF8575 chip. However, there is no method known + to detect whether an I2C chip is a PCF8575 or any other I2C chip. */ + + /* Tell the I2C layer a new client has arrived */ + err = i2c_attach_client(client); + if (err) + goto exit_free; + + /* Register sysfs hooks */ + err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group); + if (err) + goto exit_detach; + + return 0; + +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int pcf8575_detach_client(struct i2c_client *client) +{ + int err; + + sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group); + + err = i2c_detach_client(client); + if (err) + return err; + + kfree(i2c_get_clientdata(client)); + return 0; +} + +static int __init pcf8575_init(void) +{ + return i2c_add_driver(&pcf8575_driver); +} + +static void __exit pcf8575_exit(void) +{ + i2c_del_driver(&pcf8575_driver); +} + +MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>, " + "Bart Van Assche <bart.vanassche@gmail.com>"); +MODULE_DESCRIPTION("pcf8575 driver"); +MODULE_LICENSE("GPL"); + +module_init(pcf8575_init); +module_exit(pcf8575_exit); diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c index 4dc36376eb32..865f4409c06b 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/i2c/chips/pcf8591.c @@ -27,7 +27,7 @@ #include <linux/mutex.h> /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, +static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; /* Insmod parameters */ diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index e320994b981c..4154a9108859 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -31,7 +31,7 @@ #include <linux/seq_file.h> #include <linux/mutex.h> -#include <asm/arch/tps65010.h> +#include <linux/i2c/tps65010.h> /*-------------------------------------------------------------------------*/ diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c index 3de4b19ba08f..a10fd2791a69 100644 --- a/drivers/i2c/chips/tsl2550.c +++ b/drivers/i2c/chips/tsl2550.c @@ -432,11 +432,32 @@ static int __devexit tsl2550_remove(struct i2c_client *client) return 0; } +#ifdef CONFIG_PM + +static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg) +{ + return tsl2550_set_power_state(client, 0); +} + +static int tsl2550_resume(struct i2c_client *client) +{ + return tsl2550_set_power_state(client, 1); +} + +#else + +#define tsl2550_suspend NULL +#define tsl2550_resume NULL + +#endif /* CONFIG_PM */ + static struct i2c_driver tsl2550_driver = { .driver = { .name = TSL2550_DRV_NAME, .owner = THIS_MODULE, }, + .suspend = tsl2550_suspend, + .resume = tsl2550_resume, .probe = tsl2550_probe, .remove = __devexit_p(tsl2550_remove), }; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b5e13e405e72..96da22e9a5a4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -33,14 +33,15 @@ #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/completion.h> +#include <linux/hardirq.h> +#include <linux/irqflags.h> #include <asm/uaccess.h> +#include <asm/semaphore.h> #include "i2c-core.h" -static LIST_HEAD(adapters); -static LIST_HEAD(drivers); -static DEFINE_MUTEX(core_lists); +static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); #define is_newstyle_driver(d) ((d)->probe || (d)->remove) @@ -198,6 +199,25 @@ static struct bus_type i2c_bus_type = { .resume = i2c_device_resume, }; + +/** + * i2c_verify_client - return parameter as i2c_client, or NULL + * @dev: device, probably from some driver model iterator + * + * When traversing the driver model tree, perhaps using driver model + * iterators like @device_for_each_child(), you can't assume very much + * about the nodes you find. Use this function to avoid oopses caused + * by wrongly treating some non-I2C device as an i2c_client. + */ +struct i2c_client *i2c_verify_client(struct device *dev) +{ + return (dev->bus == &i2c_bus_type) + ? to_i2c_client(dev) + : NULL; +} +EXPORT_SYMBOL(i2c_verify_client); + + /** * i2c_new_device - instantiate an i2c device for use with a new style driver * @adap: the adapter managing the device @@ -276,6 +296,50 @@ void i2c_unregister_device(struct i2c_client *client) EXPORT_SYMBOL_GPL(i2c_unregister_device); +static int dummy_nop(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver dummy_driver = { + .driver.name = "dummy", + .probe = dummy_nop, + .remove = dummy_nop, +}; + +/** + * i2c_new_dummy - return a new i2c device bound to a dummy driver + * @adapter: the adapter managing the device + * @address: seven bit address to be used + * @type: optional label used for i2c_client.name + * Context: can sleep + * + * This returns an I2C client bound to the "dummy" driver, intended for use + * with devices that consume multiple addresses. Examples of such chips + * include various EEPROMS (like 24c04 and 24c08 models). + * + * These dummy devices have two main uses. First, most I2C and SMBus calls + * except i2c_transfer() need a client handle; the dummy will be that handle. + * And second, this prevents the specified address from being bound to a + * different driver. + * + * This returns the new i2c client, which should be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client * +i2c_new_dummy(struct i2c_adapter *adapter, u16 address, const char *type) +{ + struct i2c_board_info info = { + .driver_name = "dummy", + .addr = address, + }; + + if (type) + strlcpy(info.type, type, sizeof info.type); + return i2c_new_device(adapter, &info); +} +EXPORT_SYMBOL_GPL(i2c_new_dummy); + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ @@ -320,18 +384,27 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) mutex_unlock(&__i2c_board_lock); } +static int i2c_do_add_adapter(struct device_driver *d, void *data) +{ + struct i2c_driver *driver = to_i2c_driver(d); + struct i2c_adapter *adap = data; + + if (driver->attach_adapter) { + /* We ignore the return code; if it fails, too bad */ + driver->attach_adapter(adap); + } + return 0; +} + static int i2c_register_adapter(struct i2c_adapter *adap) { - int res = 0; - struct list_head *item; - struct i2c_driver *driver; + int res = 0, dummy; mutex_init(&adap->bus_lock); mutex_init(&adap->clist_lock); INIT_LIST_HEAD(&adap->clients); - mutex_lock(&core_lists); - list_add_tail(&adap->list, &adapters); + mutex_lock(&core_lock); /* Add the adapter to the driver core. * If the parent pointer is not set up, @@ -356,19 +429,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap) i2c_scan_static_board_info(adap); /* let legacy drivers scan this bus for matching devices */ - list_for_each(item,&drivers) { - driver = list_entry(item, struct i2c_driver, list); - if (driver->attach_adapter) - /* We ignore the return code; if it fails, too bad */ - driver->attach_adapter(adap); - } + dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, + i2c_do_add_adapter); out_unlock: - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); return res; out_list: - list_del(&adap->list); idr_remove(&i2c_adapter_idr, adap->nr); goto out_unlock; } @@ -394,11 +462,11 @@ retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; - mutex_lock(&core_lists); + mutex_lock(&core_lock); /* "above" here means "above or equal to", sigh */ res = idr_get_new_above(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, &id); - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); if (res < 0) { if (res == -EAGAIN) @@ -443,7 +511,7 @@ retry: if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) return -ENOMEM; - mutex_lock(&core_lists); + mutex_lock(&core_lock); /* "above" here means "above or equal to", sigh; * we need the "equal to" result to force the result */ @@ -452,7 +520,7 @@ retry: status = -EBUSY; idr_remove(&i2c_adapter_idr, id); } - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); if (status == -EAGAIN) goto retry; @@ -462,6 +530,21 @@ retry: } EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); +static int i2c_do_del_adapter(struct device_driver *d, void *data) +{ + struct i2c_driver *driver = to_i2c_driver(d); + struct i2c_adapter *adapter = data; + int res; + + if (!driver->detach_adapter) + return 0; + res = driver->detach_adapter(adapter); + if (res) + dev_err(&adapter->dev, "detach_adapter failed (%d) " + "for driver [%s]\n", res, driver->driver.name); + return res; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -473,35 +556,24 @@ EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); int i2c_del_adapter(struct i2c_adapter *adap) { struct list_head *item, *_n; - struct i2c_adapter *adap_from_list; - struct i2c_driver *driver; struct i2c_client *client; int res = 0; - mutex_lock(&core_lists); + mutex_lock(&core_lock); /* First make sure that this adapter was ever added */ - list_for_each_entry(adap_from_list, &adapters, list) { - if (adap_from_list == adap) - break; - } - if (adap_from_list != adap) { + if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); res = -EINVAL; goto out_unlock; } - list_for_each(item,&drivers) { - driver = list_entry(item, struct i2c_driver, list); - if (driver->detach_adapter) - if ((res = driver->detach_adapter(adap))) { - dev_err(&adap->dev, "detach_adapter failed " - "for driver [%s]\n", - driver->driver.name); - goto out_unlock; - } - } + /* Tell drivers about this removal */ + res = bus_for_each_drv(&i2c_bus_type, NULL, adap, + i2c_do_del_adapter); + if (res) + goto out_unlock; /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ @@ -529,7 +601,6 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* clean up the sysfs representation */ init_completion(&adap->dev_released); device_unregister(&adap->dev); - list_del(&adap->list); /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); @@ -540,7 +611,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); out_unlock: - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); return res; } EXPORT_SYMBOL(i2c_del_adapter); @@ -583,21 +654,23 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - mutex_lock(&core_lists); + mutex_lock(&core_lock); - list_add_tail(&driver->list,&drivers); pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); /* legacy drivers scan i2c busses directly */ if (driver->attach_adapter) { struct i2c_adapter *adapter; - list_for_each_entry(adapter, &adapters, list) { + down(&i2c_adapter_class.sem); + list_for_each_entry(adapter, &i2c_adapter_class.devices, + dev.node) { driver->attach_adapter(adapter); } + up(&i2c_adapter_class.sem); } - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); return 0; } EXPORT_SYMBOL(i2c_register_driver); @@ -609,11 +682,11 @@ EXPORT_SYMBOL(i2c_register_driver); */ void i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item1, *item2, *_n; + struct list_head *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; - mutex_lock(&core_lists); + mutex_lock(&core_lock); /* new-style driver? */ if (is_newstyle_driver(driver)) @@ -623,8 +696,8 @@ void i2c_del_driver(struct i2c_driver *driver) * attached. If so, detach them to be able to kill the driver * afterwards. */ - list_for_each(item1,&adapters) { - adap = list_entry(item1, struct i2c_adapter, list); + down(&i2c_adapter_class.sem); + list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) { if (driver->detach_adapter) { if (driver->detach_adapter(adap)) { dev_err(&adap->dev, "detach_adapter failed " @@ -648,40 +721,31 @@ void i2c_del_driver(struct i2c_driver *driver) } } } + up(&i2c_adapter_class.sem); unregister: driver_unregister(&driver->driver); - list_del(&driver->list); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); } EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ -static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) +static int __i2c_check_addr(struct device *dev, void *addrp) { - struct list_head *item; - struct i2c_client *client; + struct i2c_client *client = i2c_verify_client(dev); + int addr = *(int *)addrp; - list_for_each(item,&adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) - return -EBUSY; - } + if (client && client->addr == addr) + return -EBUSY; return 0; } static int i2c_check_addr(struct i2c_adapter *adapter, int addr) { - int rval; - - mutex_lock(&adapter->clist_lock); - rval = __i2c_check_addr(adapter, addr); - mutex_unlock(&adapter->clist_lock); - - return rval; + return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } int i2c_attach_client(struct i2c_client *client) @@ -689,15 +753,6 @@ int i2c_attach_client(struct i2c_client *client) struct i2c_adapter *adapter = client->adapter; int res = 0; - mutex_lock(&adapter->clist_lock); - if (__i2c_check_addr(client->adapter, client->addr)) { - res = -EBUSY; - goto out_unlock; - } - list_add_tail(&client->list,&adapter->clients); - - client->usage_count = 0; - client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; @@ -712,13 +767,17 @@ int i2c_attach_client(struct i2c_client *client) snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, client->dev.bus_id); res = device_register(&client->dev); if (res) - goto out_list; + goto out_err; + + mutex_lock(&adapter->clist_lock); + list_add_tail(&client->list, &adapter->clients); mutex_unlock(&adapter->clist_lock); + dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", + client->name, client->dev.bus_id); + if (adapter->client_register) { if (adapter->client_register(client)) { dev_dbg(&adapter->dev, "client_register " @@ -729,12 +788,9 @@ int i2c_attach_client(struct i2c_client *client) return 0; -out_list: - list_del(&client->list); +out_err: dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " "(%d)\n", client->name, client->addr, res); -out_unlock: - mutex_unlock(&adapter->clist_lock); return res; } EXPORT_SYMBOL(i2c_attach_client); @@ -744,12 +800,6 @@ int i2c_detach_client(struct i2c_client *client) struct i2c_adapter *adapter = client->adapter; int res = 0; - if (client->usage_count > 0) { - dev_warn(&client->dev, "Client [%s] still busy, " - "can't detach\n", client->name); - return -EBUSY; - } - if (adapter->client_unregister) { res = adapter->client_unregister(client); if (res) { @@ -762,9 +812,10 @@ int i2c_detach_client(struct i2c_client *client) mutex_lock(&adapter->clist_lock); list_del(&client->list); + mutex_unlock(&adapter->clist_lock); + init_completion(&client->released); device_unregister(&client->dev); - mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); out: @@ -772,72 +823,58 @@ int i2c_detach_client(struct i2c_client *client) } EXPORT_SYMBOL(i2c_detach_client); -static int i2c_inc_use_client(struct i2c_client *client) +/** + * i2c_use_client - increments the reference count of the i2c client structure + * @client: the client being referenced + * + * Each live reference to a client should be refcounted. The driver model does + * that automatically as part of driver binding, so that most drivers don't + * need to do this explicitly: they hold a reference until they're unbound + * from the device. + * + * A pointer to the client with the incremented reference counter is returned. + */ +struct i2c_client *i2c_use_client(struct i2c_client *client) { - - if (!try_module_get(client->driver->driver.owner)) - return -ENODEV; - if (!try_module_get(client->adapter->owner)) { - module_put(client->driver->driver.owner); - return -ENODEV; - } - - return 0; + get_device(&client->dev); + return client; } +EXPORT_SYMBOL(i2c_use_client); -static void i2c_dec_use_client(struct i2c_client *client) +/** + * i2c_release_client - release a use of the i2c client structure + * @client: the client being no longer referenced + * + * Must be called when a user of a client is finished with it. + */ +void i2c_release_client(struct i2c_client *client) { - module_put(client->driver->driver.owner); - module_put(client->adapter->owner); + put_device(&client->dev); } +EXPORT_SYMBOL(i2c_release_client); -int i2c_use_client(struct i2c_client *client) -{ - int ret; - - ret = i2c_inc_use_client(client); - if (ret) - return ret; - - client->usage_count++; - - return 0; -} -EXPORT_SYMBOL(i2c_use_client); +struct i2c_cmd_arg { + unsigned cmd; + void *arg; +}; -int i2c_release_client(struct i2c_client *client) +static int i2c_cmd(struct device *dev, void *_arg) { - if (!client->usage_count) { - pr_debug("i2c-core: %s used one too many times\n", - __FUNCTION__); - return -EPERM; - } - - client->usage_count--; - i2c_dec_use_client(client); + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_cmd_arg *arg = _arg; + if (client && client->driver && client->driver->command) + client->driver->command(client, arg->cmd, arg->arg); return 0; } -EXPORT_SYMBOL(i2c_release_client); void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { - struct list_head *item; - struct i2c_client *client; + struct i2c_cmd_arg cmd_arg; - mutex_lock(&adap->clist_lock); - list_for_each(item,&adap->clients) { - client = list_entry(item, struct i2c_client, list); - if (!try_module_get(client->driver->driver.owner)) - continue; - if (NULL != client->driver->command) { - mutex_unlock(&adap->clist_lock); - client->driver->command(client,cmd,arg); - mutex_lock(&adap->clist_lock); - } - module_put(client->driver->driver.owner); - } - mutex_unlock(&adap->clist_lock); + cmd_arg.cmd = cmd; + cmd_arg.arg = arg; + device_for_each_child(&adap->dev, &cmd_arg, i2c_cmd); } EXPORT_SYMBOL(i2c_clients_command); @@ -848,11 +885,24 @@ static int __init i2c_init(void) retval = bus_register(&i2c_bus_type); if (retval) return retval; - return class_register(&i2c_adapter_class); + retval = class_register(&i2c_adapter_class); + if (retval) + goto bus_err; + retval = i2c_add_driver(&dummy_driver); + if (retval) + goto class_err; + return 0; + +class_err: + class_unregister(&i2c_adapter_class); +bus_err: + bus_unregister(&i2c_bus_type); + return retval; } static void __exit i2c_exit(void) { + i2c_del_driver(&dummy_driver); class_unregister(&i2c_adapter_class); bus_unregister(&i2c_bus_type); } @@ -879,7 +929,15 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) } #endif - mutex_lock_nested(&adap->bus_lock, adap->level); + if (in_atomic() || irqs_disabled()) { + ret = mutex_trylock(&adap->bus_lock); + if (!ret) + /* I2C activity is ongoing. */ + return -EAGAIN; + } else { + mutex_lock_nested(&adap->bus_lock, adap->level); + } + ret = adap->algo->master_xfer(adap,msgs,num); mutex_unlock(&adap->bus_lock); @@ -978,7 +1036,7 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, } int i2c_probe(struct i2c_adapter *adapter, - struct i2c_client_address_data *address_data, + const struct i2c_client_address_data *address_data, int (*found_proc) (struct i2c_adapter *, int, int)) { int i, err; @@ -987,7 +1045,7 @@ int i2c_probe(struct i2c_adapter *adapter, /* Force entries are done first, and are not affected by ignore entries */ if (address_data->forces) { - unsigned short **forces = address_data->forces; + const unsigned short * const *forces = address_data->forces; int kind; for (kind = 0; forces[kind]; kind++) { @@ -1085,7 +1143,6 @@ i2c_new_probed_device(struct i2c_adapter *adap, return NULL; } - mutex_lock(&adap->clist_lock); for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { @@ -1095,7 +1152,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, } /* Check address availability */ - if (__i2c_check_addr(adap, addr_list[i])) { + if (i2c_check_addr(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); continue; @@ -1123,7 +1180,6 @@ i2c_new_probed_device(struct i2c_adapter *adap, break; } } - mutex_unlock(&adap->clist_lock); if (addr_list[i] == I2C_CLIENT_END) { dev_dbg(&adap->dev, "Probing failed, no device found\n"); @@ -1139,12 +1195,12 @@ struct i2c_adapter* i2c_get_adapter(int id) { struct i2c_adapter *adapter; - mutex_lock(&core_lists); + mutex_lock(&core_lock); adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; - mutex_unlock(&core_lists); + mutex_unlock(&core_lock); return adapter; } EXPORT_SYMBOL(i2c_get_adapter); diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index df540d5dfaf4..393e679d9faa 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -182,27 +182,22 @@ static ssize_t i2cdev_write (struct file *file, const char __user *buf, size_t c return ret; } +static int i2cdev_check(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + + if (!client || client->addr != *(unsigned int *)addrp) + return 0; + + return dev->driver ? -EBUSY : 0; +} + /* This address checking function differs from the one in i2c-core in that it considers an address with a registered device, but no - bound driver, as NOT busy. */ + driver bound to it, as NOT busy. */ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr) { - struct list_head *item; - struct i2c_client *client; - int res = 0; - - mutex_lock(&adapter->clist_lock); - list_for_each(item, &adapter->clients) { - client = list_entry(item, struct i2c_client, list); - if (client->addr == addr) { - if (client->driver) - res = -EBUSY; - break; - } - } - mutex_unlock(&adapter->clist_lock); - - return res; + return device_for_each_child(&adapter->dev, &addr, i2cdev_check); } static int i2cdev_ioctl(struct inode *inode, struct file *file, diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index fb06555708a8..64df55e20ab5 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -325,7 +325,7 @@ config BLK_DEV_PLATFORM If unsure, say N. config BLK_DEV_CMD640 - bool "CMD640 chipset bugfix/support" + tristate "CMD640 chipset bugfix/support" depends on X86 ---help--- The CMD-Technologies CMD640 IDE chip is used on many common 486 and @@ -359,9 +359,8 @@ config BLK_DEV_CMD640_ENHANCED Otherwise say N. config BLK_DEV_IDEPNP - bool "PNP EIDE support" + tristate "PNP EIDE support" depends on PNP - select IDE_GENERIC help If you have a PnP (Plug and Play) compatible EIDE card and would like the kernel to automatically detect and activate @@ -374,19 +373,20 @@ comment "PCI IDE chipsets support" config BLK_DEV_IDEPCI bool -config IDEPCI_SHARE_IRQ - bool "Sharing PCI IDE interrupts support" - depends on BLK_DEV_IDEPCI +config IDEPCI_PCIBUS_ORDER + bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)" + depends on BLK_DEV_IDE=y && BLK_DEV_IDEPCI + default y help - Some ATA/IDE chipsets have hardware support which allows for - sharing a single IRQ with other cards. To enable support for - this in the ATA/IDE driver, say Y here. + Probe IDE PCI devices in the order in which they appear on the + PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device) + instead of the order in which IDE PCI host drivers are loaded. - It is safe to say Y to this question, in most cases. - If unsure, say N. + Please note that this method of assuring stable naming of + IDE devices is unreliable and use other means for achieving + it (i.e. udev). -config IDEPCI_PCIBUS_ORDER - def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI + If in doubt, say N. # TODO: split it on per host driver config options (or module parameters) config BLK_DEV_OFFBOARD @@ -707,7 +707,6 @@ config BLK_DEV_SVWKS config BLK_DEV_SGIIOC4 tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 - select IDEPCI_SHARE_IRQ select BLK_DEV_IDEDMA_PCI help This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 @@ -801,7 +800,7 @@ config BLK_DEV_CELLEB endif config BLK_DEV_IDE_PMAC - bool "Builtin PowerMac IDE support" + tristate "Builtin PowerMac IDE support" depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y help This driver provides support for the built-in IDE controller on @@ -855,8 +854,9 @@ config BLK_DEV_IDE_AU1XXX_SEQTS_PER_RQ depends on BLK_DEV_IDE_AU1XXX config IDE_ARM - def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK) - select IDE_GENERIC + tristate "ARM IDE support" + depends on ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK) + default y config BLK_DEV_IDE_ICSIDE tristate "ICS IDE interface support" @@ -888,10 +888,9 @@ config BLK_DEV_IDE_BAST Simtec BAST or the Thorcom VR1000 config ETRAX_IDE - bool "ETRAX IDE support" + tristate "ETRAX IDE support" depends on CRIS && BROKEN select BLK_DEV_IDEDMA - select IDE_GENERIC help Enables the ETRAX IDE driver. @@ -923,17 +922,15 @@ config ETRAX_IDE_G27_RESET endchoice config IDE_H8300 - bool "H8300 IDE support" + tristate "H8300 IDE support" depends on H8300 - select IDE_GENERIC default y help Enables the H8300 IDE driver. config BLK_DEV_GAYLE - bool "Amiga Gayle IDE interface support" + tristate "Amiga Gayle IDE interface support" depends on AMIGA - select IDE_GENERIC help This is the IDE driver for the Amiga Gayle IDE interface. It supports both the `A1200 style' and `A4000 style' of the Gayle IDE interface, @@ -963,9 +960,8 @@ config BLK_DEV_IDEDOUBLER runtime using the "ide=doubler" kernel boot parameter. config BLK_DEV_BUDDHA - bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)" + tristate "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)" depends on ZORRO && EXPERIMENTAL - select IDE_GENERIC help This is the IDE driver for the IDE interfaces on the Buddha, Catweasel and X-Surf expansion boards. It supports up to two interfaces @@ -976,9 +972,8 @@ config BLK_DEV_BUDDHA to one of its IDE interfaces. config BLK_DEV_FALCON_IDE - bool "Falcon IDE interface support" + tristate "Falcon IDE interface support" depends on ATARI - select IDE_GENERIC help This is the IDE driver for the builtin IDE interface on the Atari Falcon. Say Y if you have a Falcon and want to use IDE devices (hard @@ -986,9 +981,8 @@ config BLK_DEV_FALCON_IDE interface. config BLK_DEV_MAC_IDE - bool "Macintosh Quadra/Powerbook IDE interface support" + tristate "Macintosh Quadra/Powerbook IDE interface support" depends on MAC - select IDE_GENERIC help This is the IDE driver for the builtin IDE interface on some m68k Macintosh models. It supports both the `Quadra style' (used in @@ -1000,18 +994,16 @@ config BLK_DEV_MAC_IDE builtin IDE interface. config BLK_DEV_Q40IDE - bool "Q40/Q60 IDE interface support" + tristate "Q40/Q60 IDE interface support" depends on Q40 - select IDE_GENERIC help Enable the on-board IDE controller in the Q40/Q60. This should normally be on; disable it only if you are running a custom hard drive subsystem through an expansion card. config BLK_DEV_MPC8xx_IDE - bool "MPC8xx IDE support" + tristate "MPC8xx IDE support" depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE - select IDE_GENERIC help This option provides support for IDE on Motorola MPC8xx Systems. Please see 'Type of MPC8xx IDE interface' for details. diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile index b181fc672057..0d2da89d15cf 100644 --- a/drivers/ide/Makefile +++ b/drivers/ide/Makefile @@ -7,41 +7,37 @@ # Note : at this point, these files are compiled on all systems. # In the future, some of these should be built conditionally. # -# First come modules that register themselves with the core +# link order is important here EXTRA_CFLAGS += -Idrivers/ide -obj-$(CONFIG_BLK_DEV_IDE) += pci/ - ide-core-y += ide.o ide-io.o ide-iops.o ide-lib.o ide-probe.o ide-taskfile.o -ide-core-$(CONFIG_BLK_DEV_CMD640) += pci/cmd640.o - -# Core IDE code - must come before legacy +# core IDE code ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o ide-core-$(CONFIG_IDE_PROC_FS) += ide-proc.o -ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o ide-core-$(CONFIG_BLK_DEV_IDEACPI) += ide-acpi.o -# built-in only drivers from arm/ -ide-core-$(CONFIG_IDE_ARM) += arm/ide_arm.o +obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o -# built-in only drivers from legacy/ -ide-core-$(CONFIG_BLK_DEV_BUDDHA) += legacy/buddha.o -ide-core-$(CONFIG_BLK_DEV_FALCON_IDE) += legacy/falconide.o -ide-core-$(CONFIG_BLK_DEV_GAYLE) += legacy/gayle.o -ide-core-$(CONFIG_BLK_DEV_MAC_IDE) += legacy/macide.o -ide-core-$(CONFIG_BLK_DEV_Q40IDE) += legacy/q40ide.o +ifeq ($(CONFIG_IDE_ARM), y) + ide-arm-core-y += arm/ide_arm.o + obj-y += ide-arm-core.o +endif -# built-in only drivers from ppc/ -ide-core-$(CONFIG_BLK_DEV_MPC8xx_IDE) += ppc/mpc8xx.o -ide-core-$(CONFIG_BLK_DEV_IDE_PMAC) += ppc/pmac.o +obj-$(CONFIG_BLK_DEV_IDE) += legacy/ pci/ -# built-in only drivers from h8300/ -ide-core-$(CONFIG_IDE_H8300) += h8300/ide-h8300.o +obj-$(CONFIG_IDEPCI_PCIBUS_ORDER) += ide-scan-pci.o -obj-$(CONFIG_BLK_DEV_IDE) += ide-core.o +ifeq ($(CONFIG_BLK_DEV_CMD640), y) + cmd640-core-y += pci/cmd640.o + obj-y += cmd640-core.o +endif + +obj-$(CONFIG_BLK_DEV_IDE) += cris/ ppc/ +obj-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o +obj-$(CONFIG_IDE_H8300) += h8300/ obj-$(CONFIG_IDE_GENERIC) += ide-generic.o obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o @@ -49,6 +45,20 @@ obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o obj-$(CONFIG_BLK_DEV_IDEFLOPPY) += ide-floppy.o -obj-$(CONFIG_BLK_DEV_IDE) += legacy/ arm/ mips/ -obj-$(CONFIG_BLK_DEV_HD) += legacy/ -obj-$(CONFIG_ETRAX_IDE) += cris/ +ifeq ($(CONFIG_BLK_DEV_IDECS), y) + ide-cs-core-y += legacy/ide-cs.o + obj-y += ide-cs-core.o +endif + +ifeq ($(CONFIG_BLK_DEV_PLATFORM), y) + ide-platform-core-y += legacy/ide_platform.o + obj-y += ide-platform-core.o +endif + +obj-$(CONFIG_BLK_DEV_IDE) += arm/ mips/ + +# old hd driver must be last +ifeq ($(CONFIG_BLK_DEV_HD), y) + hd-core-y += legacy/hd.o + obj-y += hd-core.o +endif diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile index 6a78f0755f26..5f63ad216862 100644 --- a/drivers/ide/arm/Makefile +++ b/drivers/ide/arm/Makefile @@ -3,4 +3,8 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o +ifeq ($(CONFIG_IDE_ARM), m) + obj-m += ide_arm.o +endif + EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c index 48db6167bb90..45bf9c825f2b 100644 --- a/drivers/ide/arm/bast-ide.c +++ b/drivers/ide/arm/bast-ide.c @@ -45,7 +45,7 @@ bastide_register(unsigned int base, unsigned int aux, int irq, hw.io_ports[IDE_CONTROL_OFFSET] = aux + (6 * 0x20); hw.irq = irq; - ide_register_hw(&hw, NULL, 0, hwif); + ide_register_hw(&hw, NULL, hwif); return 0; } diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index 93f71fcfc04d..8a5c7205b77c 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -272,8 +272,6 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) case XFER_SW_DMA_0: cycle_time = 480; break; - default: - return; } /* @@ -289,26 +287,10 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); } -static void icside_dma_host_off(ide_drive_t *drive) +static void icside_dma_host_set(ide_drive_t *drive, int on) { } -static void icside_dma_off_quietly(ide_drive_t *drive) -{ - drive->using_dma = 0; -} - -static void icside_dma_host_on(ide_drive_t *drive) -{ -} - -static int icside_dma_on(ide_drive_t *drive) -{ - drive->using_dma = 1; - - return 0; -} - static int icside_dma_end(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -424,10 +406,7 @@ static void icside_dma_init(ide_hwif_t *hwif) hwif->dmatable_dma = 0; hwif->set_dma_mode = icside_set_dma_mode; - hwif->dma_host_off = icside_dma_host_off; - hwif->dma_off_quietly = icside_dma_off_quietly; - hwif->dma_host_on = icside_dma_host_on; - hwif->ide_dma_on = icside_dma_on; + hwif->dma_host_set = icside_dma_host_set; hwif->dma_setup = icside_dma_setup; hwif->dma_exec_cmd = icside_dma_exec_cmd; hwif->dma_start = icside_dma_start; diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c index 8957cbadf5c2..60f2497542c0 100644 --- a/drivers/ide/arm/ide_arm.c +++ b/drivers/ide/arm/ide_arm.c @@ -24,12 +24,25 @@ # define IDE_ARM_IRQ IRQ_HARDDISK #endif -void __init ide_arm_init(void) +static int __init ide_arm_init(void) { + ide_hwif_t *hwif; hw_regs_t hw; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206); hw.irq = IDE_ARM_IRQ; - ide_register_hw(&hw, NULL, 1, NULL); + + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif) { + ide_init_port_hw(hwif, &hw); + idx[0] = hwif->index; + + ide_device_add(idx); + } + + return 0; } + +module_init(ide_arm_init); diff --git a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c index 0775a3afef48..e6b56d1d48f4 100644 --- a/drivers/ide/arm/rapide.c +++ b/drivers/ide/arm/rapide.c @@ -13,26 +13,18 @@ #include <asm/ecard.h> -static ide_hwif_t * -rapide_locate_hwif(void __iomem *base, void __iomem *ctrl, unsigned int sz, int irq) +static void rapide_setup_ports(hw_regs_t *hw, void __iomem *base, + void __iomem *ctrl, unsigned int sz, int irq) { unsigned long port = (unsigned long)base; - ide_hwif_t *hwif = ide_find_port(port); int i; - if (hwif == NULL) - goto out; - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hwif->io_ports[i] = port; + hw->io_ports[i] = port; port += sz; } - hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; - hwif->irq = irq; - hwif->mmio = 1; - default_hwif_mmiops(hwif); -out: - return hwif; + hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; + hw->irq = irq; } static int __devinit @@ -42,6 +34,7 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id) void __iomem *base; int ret; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; + hw_regs_t hw; ret = ecard_request_resources(ec); if (ret) @@ -53,11 +46,17 @@ rapide_probe(struct expansion_card *ec, const struct ecard_id *id) goto release; } - hwif = rapide_locate_hwif(base, base + 0x818, 1 << 6, ec->irq); + hwif = ide_find_port((unsigned long)base); if (hwif) { - hwif->hwif_data = base; - hwif->gendev.parent = &ec->dev; - hwif->noprobe = 0; + memset(&hw, 0, sizeof(hw)); + rapide_setup_ports(&hw, base, base + 0x818, 1 << 6, ec->irq); + hw.chipset = ide_generic; + hw.dev = &ec->dev; + + ide_init_port_hw(hwif, &hw); + + hwif->mmio = 1; + default_hwif_mmiops(hwif); idx[0] = hwif->index; diff --git a/drivers/ide/cris/Makefile b/drivers/ide/cris/Makefile index 6176e8d6b2e6..20b95960531f 100644 --- a/drivers/ide/cris/Makefile +++ b/drivers/ide/cris/Makefile @@ -1,3 +1,3 @@ EXTRA_CFLAGS += -Idrivers/ide -obj-y += ide-cris.o +obj-$(CONFIG_IDE_ETRAX) += ide-cris.o diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 476e0d65ed43..8c3294c4d23e 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -673,9 +673,8 @@ static void cris_ide_input_data (ide_drive_t *drive, void *, unsigned int); static void cris_ide_output_data (ide_drive_t *drive, void *, unsigned int); static void cris_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int); static void cris_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int); -static int cris_dma_on (ide_drive_t *drive); -static void cris_dma_off(ide_drive_t *drive) +static void cris_dma_host_set(ide_drive_t *drive, int on) { } @@ -747,8 +746,6 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) strobe = ATA_DMA2_STROBE; hold = ATA_DMA2_HOLD; break; - default: - return; } if (speed >= XFER_UDMA_0) @@ -757,13 +754,11 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); } -void __init -init_e100_ide (void) +static int __init init_e100_ide(void) { hw_regs_t hw; - int ide_offsets[IDE_NR_PORTS]; - int h; - int i; + int ide_offsets[IDE_NR_PORTS], h, i; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; printk("ide: ETRAX FS built-in ATA DMA controller\n"); @@ -780,9 +775,11 @@ init_e100_ide (void) ide_offsets, 0, 0, cris_ide_ack_intr, ide_default_irq(0)); - ide_register_hw(&hw, NULL, 1, &hwif); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif == NULL) continue; + ide_init_port_data(hwif, hwif->index); + ide_init_port_hw(hwif, &hw); hwif->mmio = 1; hwif->chipset = ide_etrax100; hwif->set_pio_mode = &cris_set_pio_mode; @@ -791,6 +788,7 @@ init_e100_ide (void) hwif->ata_output_data = &cris_ide_output_data; hwif->atapi_input_bytes = &cris_atapi_input_bytes; hwif->atapi_output_bytes = &cris_atapi_output_bytes; + hwif->dma_host_set = &cris_dma_host_set; hwif->ide_dma_end = &cris_dma_end; hwif->dma_setup = &cris_dma_setup; hwif->dma_exec_cmd = &cris_dma_exec_cmd; @@ -801,9 +799,6 @@ init_e100_ide (void) hwif->OUTBSYNC = &cris_ide_outbsync; hwif->INB = &cris_ide_inb; hwif->INW = &cris_ide_inw; - hwif->dma_host_off = &cris_dma_off; - hwif->dma_host_on = &cris_dma_on; - hwif->dma_off_quietly = &cris_dma_off; hwif->cbl = ATA_CBL_PATA40; hwif->host_flags |= IDE_HFLAG_NO_ATAPI_DMA; hwif->pio_mask = ATA_PIO4, @@ -811,6 +806,8 @@ init_e100_ide (void) hwif->drives[1].autotune = 1; hwif->ultra_mask = cris_ultra_mask; hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */ + + idx[h] = hwif->index; } /* Reset pulse */ @@ -823,14 +820,12 @@ init_e100_ide (void) cris_ide_set_speed(TYPE_PIO, ATA_PIO4_SETUP, ATA_PIO4_STROBE, ATA_PIO4_HOLD); cris_ide_set_speed(TYPE_DMA, 0, ATA_DMA2_STROBE, ATA_DMA2_HOLD); cris_ide_set_speed(TYPE_UDMA, ATA_UDMA2_CYC, ATA_UDMA2_DVS, 0); -} -static int cris_dma_on (ide_drive_t *drive) -{ + ide_device_add(idx); + return 0; } - static cris_dma_descr_type mydescr __attribute__ ((__aligned__(16))); /* @@ -1062,3 +1057,5 @@ static void cris_dma_start(ide_drive_t *drive) LED_DISK_READ(1); } } + +module_init(init_e100_ide); diff --git a/drivers/ide/h8300/Makefile b/drivers/ide/h8300/Makefile new file mode 100644 index 000000000000..5eba16f423f4 --- /dev/null +++ b/drivers/ide/h8300/Makefile @@ -0,0 +1,2 @@ + +obj-$(CONFIG_IDE_H8300) += ide-h8300.o diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c index 4a49b5c59acb..4f6d0191cf6c 100644 --- a/drivers/ide/h8300/ide-h8300.c +++ b/drivers/ide/h8300/ide-h8300.c @@ -84,11 +84,12 @@ static inline void hwif_setup(ide_hwif_t *hwif) hwif->INSL = NULL; } -void __init h8300_ide_init(void) +static int __init h8300_ide_init(void) { hw_regs_t hw; ide_hwif_t *hwif; - int idx; + int index; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; if (!request_region(CONFIG_H8300_IDE_BASE, H8300_IDE_GAP*8, "ide-h8300")) goto out_busy; @@ -100,16 +101,28 @@ void __init h8300_ide_init(void) hw_setup(&hw); /* register if */ - idx = ide_register_hw(&hw, NULL, 1, &hwif); - if (idx == -1) { + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif == NULL) { printk(KERN_ERR "ide-h8300: IDE I/F register failed\n"); - return; + return -ENOENT; } + index = hwif->index; + ide_init_port_data(hwif, index); + ide_init_port_hw(hwif, &hw); hwif_setup(hwif); - printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", idx); - return; + printk(KERN_INFO "ide%d: H8/300 generic IDE interface\n", index); + + idx[0] = index; + + ide_device_add(idx); + + return 0; out_busy: printk(KERN_ERR "ide-h8300: IDE I/F resource already used.\n"); + + return -EBUSY; } + +module_init(h8300_ide_init); diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 899d56536e80..e888fc35b27c 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -383,27 +383,19 @@ static int taskfile_load_raw(ide_drive_t *drive, gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); memset(&args, 0, sizeof(ide_task_t)); - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.data_phase = TASKFILE_NO_DATA; - args.handler = &task_no_data_intr; /* convert gtf to IDE Taskfile */ - args.tfRegister[1] = gtf->tfa[0]; /* 0x1f1 */ - args.tfRegister[2] = gtf->tfa[1]; /* 0x1f2 */ - args.tfRegister[3] = gtf->tfa[2]; /* 0x1f3 */ - args.tfRegister[4] = gtf->tfa[3]; /* 0x1f4 */ - args.tfRegister[5] = gtf->tfa[4]; /* 0x1f5 */ - args.tfRegister[6] = gtf->tfa[5]; /* 0x1f6 */ - args.tfRegister[7] = gtf->tfa[6]; /* 0x1f7 */ + memcpy(&args.tf_array[7], >f->tfa, 7); + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; if (ide_noacpitfs) { DEBPRINT("_GTF execution disabled\n"); return err; } - err = ide_raw_taskfile(drive, &args, NULL); + err = ide_no_data_taskfile(drive, &args); if (err) - printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n", + printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n", __FUNCTION__, err); return err; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index c7d77f0ad892..74c6087ada38 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -655,9 +655,9 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate) BUG(); } else { spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, - failed->data_len); - end_that_request_last(failed, 0); + if (__blk_end_request(failed, -EIO, + failed->data_len)) + BUG(); spin_unlock_irqrestore(&ide_lock, flags); } } else @@ -917,19 +917,13 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, if (ide_wait_stat(&startstop, drive, 0, BUSY_STAT, WAIT_READY)) return startstop; + /* FIXME: for Virtual DMA we must check harder */ if (info->dma) info->dma = !hwif->dma_setup(drive); /* Set up the controller registers. */ - /* FIXME: for Virtual DMA we must check harder */ - HWIF(drive)->OUTB(info->dma, IDE_FEATURE_REG); - HWIF(drive)->OUTB(0, IDE_IREASON_REG); - HWIF(drive)->OUTB(0, IDE_SECTOR_REG); - - HWIF(drive)->OUTB(xferlen & 0xff, IDE_BCOUNTL_REG); - HWIF(drive)->OUTB(xferlen >> 8 , IDE_BCOUNTH_REG); - if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); + ide_pktcmd_tf_load(drive, IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL | + IDE_TFLAG_NO_SELECT_MASK, xferlen, info->dma); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* waiting for CDB interrupt, not DMA yet. */ @@ -1653,6 +1647,17 @@ static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason) return 1; } +/* + * Called from blk_end_request_callback() after the data of the request + * is completed and before the request is completed. + * By returning value '1', blk_end_request_callback() returns immediately + * without completing the request. + */ +static int cdrom_newpc_intr_dummy_cb(struct request *rq) +{ + return 1; +} + typedef void (xfer_func_t)(ide_drive_t *, void *, u32); /* @@ -1691,9 +1696,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) return ide_error(drive, "dma error", stat); } - end_that_request_chunk(rq, 1, rq->data_len); - rq->data_len = 0; - goto end_request; + spin_lock_irqsave(&ide_lock, flags); + if (__blk_end_request(rq, 0, rq->data_len)) + BUG(); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); + + return ide_stopped; } /* @@ -1711,8 +1720,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) /* * If DRQ is clear, the command has completed. */ - if ((stat & DRQ_STAT) == 0) - goto end_request; + if ((stat & DRQ_STAT) == 0) { + spin_lock_irqsave(&ide_lock, flags); + if (__blk_end_request(rq, 0, 0)) + BUG(); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); + + return ide_stopped; + } /* * check which way to transfer data @@ -1765,7 +1781,14 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) rq->data_len -= blen; if (rq->bio) - end_that_request_chunk(rq, 1, blen); + /* + * The request can't be completed until DRQ is cleared. + * So complete the data, but don't complete the request + * using the dummy function for the callback feature + * of blk_end_request_callback(). + */ + blk_end_request_callback(rq, 0, blen, + cdrom_newpc_intr_dummy_cb); else rq->data += blen; } @@ -1786,14 +1809,6 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, NULL); return ide_started; - -end_request: - spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); - end_that_request_last(rq, 1); - HWGROUP(drive)->rq = NULL; - spin_unlock_irqrestore(&ide_lock, flags); - return ide_stopped; } static ide_startstop_t cdrom_write_intr(ide_drive_t *drive) diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index b1781908e1f2..717e114ced52 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id) return 0; /* lba_capacity value may be bad */ } +static const u8 ide_rw_cmds[] = { + WIN_MULTREAD, + WIN_MULTWRITE, + WIN_MULTREAD_EXT, + WIN_MULTWRITE_EXT, + WIN_READ, + WIN_WRITE, + WIN_READ_EXT, + WIN_WRITE_EXT, + WIN_READDMA, + WIN_WRITEDMA, + WIN_READDMA_EXT, + WIN_WRITEDMA_EXT, +}; + +static const u8 ide_data_phases[] = { + TASKFILE_MULTI_IN, + TASKFILE_MULTI_OUT, + TASKFILE_IN, + TASKFILE_OUT, + TASKFILE_IN_DMA, + TASKFILE_OUT_DMA, +}; + +static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma) +{ + u8 index, lba48, write; + + lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; + write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; + + if (dma) + index = drive->vdma ? 4 : 8; + else + index = drive->mult_count ? 0 : 4; + + task->tf.command = ide_rw_cmds[index + lba48 + write]; + + if (dma) + index = 8; /* fixup index */ + + task->data_phase = ide_data_phases[index / 2 + write]; +} + /* * __ide_do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. @@ -137,11 +181,11 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, { ide_hwif_t *hwif = HWIF(drive); unsigned int dma = drive->using_dma; + u16 nsectors = (u16)rq->nr_sectors; u8 lba48 = (drive->addressing == 1) ? 1 : 0; - task_ioreg_t command = WIN_NOP; - ata_nsector_t nsectors; - - nsectors.all = (u16) rq->nr_sectors; + ide_task_t task; + struct ide_taskfile *tf = &task.tf; + ide_startstop_t rc; if ((hwif->host_flags & IDE_HFLAG_NO_LBA48_DMA) && lba48 && dma) { if (block + rq->nr_sectors > 1ULL << 28) @@ -155,121 +199,71 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_map_sg(drive, rq); } - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - - /* FIXME: SELECT_MASK(drive, 0) ? */ + memset(&task, 0, sizeof(task)); + task.tf_flags = IDE_TFLAG_NO_SELECT_MASK; /* FIXME? */ + task.tf_flags |= (IDE_TFLAG_TF | IDE_TFLAG_DEVICE); if (drive->select.b.lba) { if (lba48) { - task_ioreg_t tasklets[10]; - pr_debug("%s: LBA=0x%012llx\n", drive->name, (unsigned long long)block); - tasklets[0] = 0; - tasklets[1] = 0; - tasklets[2] = nsectors.b.low; - tasklets[3] = nsectors.b.high; - tasklets[4] = (task_ioreg_t) block; - tasklets[5] = (task_ioreg_t) (block>>8); - tasklets[6] = (task_ioreg_t) (block>>16); - tasklets[7] = (task_ioreg_t) (block>>24); - if (sizeof(block) == 4) { - tasklets[8] = (task_ioreg_t) 0; - tasklets[9] = (task_ioreg_t) 0; - } else { - tasklets[8] = (task_ioreg_t)((u64)block >> 32); - tasklets[9] = (task_ioreg_t)((u64)block >> 40); + tf->hob_nsect = (nsectors >> 8) & 0xff; + tf->hob_lbal = (u8)(block >> 24); + if (sizeof(block) != 4) { + tf->hob_lbam = (u8)((u64)block >> 32); + tf->hob_lbah = (u8)((u64)block >> 40); } -#ifdef DEBUG - printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", - drive->name, tasklets[3], tasklets[2], - tasklets[9], tasklets[8], tasklets[7], - tasklets[6], tasklets[5], tasklets[4]); -#endif - hwif->OUTB(tasklets[1], IDE_FEATURE_REG); - hwif->OUTB(tasklets[3], IDE_NSECTOR_REG); - hwif->OUTB(tasklets[7], IDE_SECTOR_REG); - hwif->OUTB(tasklets[8], IDE_LCYL_REG); - hwif->OUTB(tasklets[9], IDE_HCYL_REG); - - hwif->OUTB(tasklets[0], IDE_FEATURE_REG); - hwif->OUTB(tasklets[2], IDE_NSECTOR_REG); - hwif->OUTB(tasklets[4], IDE_SECTOR_REG); - hwif->OUTB(tasklets[5], IDE_LCYL_REG); - hwif->OUTB(tasklets[6], IDE_HCYL_REG); - hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG); + + tf->nsect = nsectors & 0xff; + tf->lbal = (u8) block; + tf->lbam = (u8)(block >> 8); + tf->lbah = (u8)(block >> 16); + + task.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB); } else { - hwif->OUTB(0x00, IDE_FEATURE_REG); - hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); - hwif->OUTB(block, IDE_SECTOR_REG); - hwif->OUTB(block>>=8, IDE_LCYL_REG); - hwif->OUTB(block>>=8, IDE_HCYL_REG); - hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); + tf->nsect = nsectors & 0xff; + tf->lbal = block; + tf->lbam = block >>= 8; + tf->lbah = block >>= 8; + tf->device = (block >> 8) & 0xf; } } else { unsigned int sect,head,cyl,track; track = (int)block / drive->sect; sect = (int)block % drive->sect + 1; - hwif->OUTB(sect, IDE_SECTOR_REG); head = track % drive->head; cyl = track / drive->head; pr_debug("%s: CHS=%u/%u/%u\n", drive->name, cyl, head, sect); - hwif->OUTB(0x00, IDE_FEATURE_REG); - hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); - hwif->OUTB(cyl, IDE_LCYL_REG); - hwif->OUTB(cyl>>8, IDE_HCYL_REG); - hwif->OUTB(head|drive->select.all,IDE_SELECT_REG); + tf->nsect = nsectors & 0xff; + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device = head; } - if (dma) { - if (!hwif->dma_setup(drive)) { - if (rq_data_dir(rq)) { - command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; - if (drive->vdma) - command = lba48 ? WIN_WRITE_EXT: WIN_WRITE; - } else { - command = lba48 ? WIN_READDMA_EXT : WIN_READDMA; - if (drive->vdma) - command = lba48 ? WIN_READ_EXT: WIN_READ; - } - hwif->dma_exec_cmd(drive, command); - hwif->dma_start(drive); - return ide_started; - } - /* fallback to PIO */ - ide_init_sg_cmd(drive, rq); - } - - if (rq_data_dir(rq) == READ) { - - if (drive->mult_count) { - hwif->data_phase = TASKFILE_MULTI_IN; - command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD; - } else { - hwif->data_phase = TASKFILE_IN; - command = lba48 ? WIN_READ_EXT : WIN_READ; - } + if (rq_data_dir(rq)) + task.tf_flags |= IDE_TFLAG_WRITE; - ide_execute_command(drive, command, &task_in_intr, WAIT_CMD, NULL); - return ide_started; - } else { - if (drive->mult_count) { - hwif->data_phase = TASKFILE_MULTI_OUT; - command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; - } else { - hwif->data_phase = TASKFILE_OUT; - command = lba48 ? WIN_WRITE_EXT : WIN_WRITE; - } + ide_tf_set_cmd(drive, &task, dma); + if (!dma) + hwif->data_phase = task.data_phase; + task.rq = rq; - /* FIXME: ->OUTBSYNC ? */ - hwif->OUTB(command, IDE_COMMAND_REG); + rc = do_rw_taskfile(drive, &task); - return pre_task_out_intr(drive, rq); + if (rc == ide_stopped && dma) { + /* fallback to PIO */ + task.tf_flags |= IDE_TFLAG_DMA_PIO_FALLBACK; + ide_tf_set_cmd(drive, &task, 0); + hwif->data_phase = task.data_phase; + ide_init_sg_cmd(drive, rq); + rc = do_rw_taskfile(drive, &task); } + + return rc; } /* @@ -307,57 +301,29 @@ static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, s * Queries for true maximum capacity of the drive. * Returns maximum LBA address (> 0) of the drive, 0 if failed. */ -static unsigned long idedisk_read_native_max_address(ide_drive_t *drive) +static u64 idedisk_read_native_max_address(ide_drive_t *drive, int lba48) { ide_task_t args; - unsigned long addr = 0; + struct ide_taskfile *tf = &args.tf; + u64 addr = 0; /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_SELECT_OFFSET] = 0x40; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; + if (lba48) + tf->command = WIN_READ_NATIVE_MAX_EXT; + else + tf->command = WIN_READ_NATIVE_MAX; + tf->device = ATA_LBA; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + if (lba48) + args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB); /* submit command request */ - ide_raw_taskfile(drive, &args, NULL); + ide_no_data_taskfile(drive, &args); /* if OK, compute maximum address value */ - if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { - addr = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) - | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) - | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) - | ((args.tfRegister[IDE_SECTOR_OFFSET] )); - addr++; /* since the return value is (maxlba - 1), we add 1 */ - } - return addr; -} + if ((tf->status & 0x01) == 0) + addr = ide_get_lba_addr(tf, lba48) + 1; -static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive) -{ - ide_task_t args; - unsigned long long addr = 0; - - /* Create IDE/ATA command request structure */ - memset(&args, 0, sizeof(ide_task_t)); - - args.tfRegister[IDE_SELECT_OFFSET] = 0x40; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_READ_NATIVE_MAX_EXT; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - /* submit command request */ - ide_raw_taskfile(drive, &args, NULL); - - /* if OK, compute maximum address value */ - if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { - u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) | - (args.hobRegister[IDE_LCYL_OFFSET] << 8) | - args.hobRegister[IDE_SECTOR_OFFSET]; - u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | - ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | - (args.tfRegister[IDE_SECTOR_OFFSET]); - addr = ((__u64)high << 24) | low; - addr++; /* since the return value is (maxlba - 1), we add 1 */ - } return addr; } @@ -365,67 +331,37 @@ static unsigned long long idedisk_read_native_max_address_ext(ide_drive_t *drive * Sets maximum virtual LBA address of the drive. * Returns new maximum virtual LBA address (> 0) or 0 on failure. */ -static unsigned long idedisk_set_max_address(ide_drive_t *drive, unsigned long addr_req) -{ - ide_task_t args; - unsigned long addr_set = 0; - - addr_req--; - /* Create IDE/ATA command request structure */ - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); - args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >> 8) & 0xff); - args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >> 16) & 0xff); - args.tfRegister[IDE_SELECT_OFFSET] = ((addr_req >> 24) & 0x0f) | 0x40; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - /* submit command request */ - ide_raw_taskfile(drive, &args, NULL); - /* if OK, read new maximum address value */ - if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { - addr_set = ((args.tfRegister[IDE_SELECT_OFFSET] & 0x0f) << 24) - | ((args.tfRegister[ IDE_HCYL_OFFSET] ) << 16) - | ((args.tfRegister[ IDE_LCYL_OFFSET] ) << 8) - | ((args.tfRegister[IDE_SECTOR_OFFSET] )); - addr_set++; - } - return addr_set; -} - -static unsigned long long idedisk_set_max_address_ext(ide_drive_t *drive, unsigned long long addr_req) +static u64 idedisk_set_max_address(ide_drive_t *drive, u64 addr_req, int lba48) { ide_task_t args; - unsigned long long addr_set = 0; + struct ide_taskfile *tf = &args.tf; + u64 addr_set = 0; addr_req--; /* Create IDE/ATA command request structure */ memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_SECTOR_OFFSET] = ((addr_req >> 0) & 0xff); - args.tfRegister[IDE_LCYL_OFFSET] = ((addr_req >>= 8) & 0xff); - args.tfRegister[IDE_HCYL_OFFSET] = ((addr_req >>= 8) & 0xff); - args.tfRegister[IDE_SELECT_OFFSET] = 0x40; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SET_MAX_EXT; - args.hobRegister[IDE_SECTOR_OFFSET] = (addr_req >>= 8) & 0xff; - args.hobRegister[IDE_LCYL_OFFSET] = (addr_req >>= 8) & 0xff; - args.hobRegister[IDE_HCYL_OFFSET] = (addr_req >>= 8) & 0xff; - args.hobRegister[IDE_SELECT_OFFSET] = 0x40; - args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80); - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; + tf->lbal = (addr_req >> 0) & 0xff; + tf->lbam = (addr_req >>= 8) & 0xff; + tf->lbah = (addr_req >>= 8) & 0xff; + if (lba48) { + tf->hob_lbal = (addr_req >>= 8) & 0xff; + tf->hob_lbam = (addr_req >>= 8) & 0xff; + tf->hob_lbah = (addr_req >>= 8) & 0xff; + tf->command = WIN_SET_MAX_EXT; + } else { + tf->device = (addr_req >>= 8) & 0x0f; + tf->command = WIN_SET_MAX; + } + tf->device |= ATA_LBA; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + if (lba48) + args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_HOB); /* submit command request */ - ide_raw_taskfile(drive, &args, NULL); + ide_no_data_taskfile(drive, &args); /* if OK, compute maximum address value */ - if ((args.tfRegister[IDE_STATUS_OFFSET] & 0x01) == 0) { - u32 high = (args.hobRegister[IDE_HCYL_OFFSET] << 16) | - (args.hobRegister[IDE_LCYL_OFFSET] << 8) | - args.hobRegister[IDE_SECTOR_OFFSET]; - u32 low = ((args.tfRegister[IDE_HCYL_OFFSET])<<16) | - ((args.tfRegister[IDE_LCYL_OFFSET])<<8) | - (args.tfRegister[IDE_SECTOR_OFFSET]); - addr_set = ((__u64)high << 24) | low; - addr_set++; - } + if ((tf->status & 0x01) == 0) + addr_set = ide_get_lba_addr(tf, lba48) + 1; + return addr_set; } @@ -471,10 +407,8 @@ static void idedisk_check_hpa(ide_drive_t *drive) int lba48 = idedisk_supports_lba48(drive->id); capacity = drive->capacity64; - if (lba48) - set_max = idedisk_read_native_max_address_ext(drive); - else - set_max = idedisk_read_native_max_address(drive); + + set_max = idedisk_read_native_max_address(drive, lba48); if (ide_in_drive_list(drive->id, hpa_list)) { /* @@ -495,10 +429,8 @@ static void idedisk_check_hpa(ide_drive_t *drive) capacity, sectors_to_MB(capacity), set_max, sectors_to_MB(set_max)); - if (lba48) - set_max = idedisk_set_max_address_ext(drive, set_max); - else - set_max = idedisk_set_max_address(drive, set_max); + set_max = idedisk_set_max_address(drive, set_max, lba48); + if (set_max) { drive->capacity64 = set_max; printk(KERN_INFO "%s: Host Protected Area disabled.\n", @@ -556,32 +488,32 @@ static sector_t idedisk_capacity (ide_drive_t *drive) static int smart_enable(ide_drive_t *drive) { ide_task_t args; + struct ide_taskfile *tf = &args.tf; memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_FEATURE_OFFSET] = SMART_ENABLE; - args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; - args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - return ide_raw_taskfile(drive, &args, NULL); + tf->feature = SMART_ENABLE; + tf->lbam = SMART_LCYL_PASS; + tf->lbah = SMART_HCYL_PASS; + tf->command = WIN_SMART; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + return ide_no_data_taskfile(drive, &args); } static int get_smart_data(ide_drive_t *drive, u8 *buf, u8 sub_cmd) { ide_task_t args; + struct ide_taskfile *tf = &args.tf; memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_FEATURE_OFFSET] = sub_cmd; - args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; - args.tfRegister[IDE_LCYL_OFFSET] = SMART_LCYL_PASS; - args.tfRegister[IDE_HCYL_OFFSET] = SMART_HCYL_PASS; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SMART; - args.command_type = IDE_DRIVE_TASK_IN; - args.data_phase = TASKFILE_IN; - args.handler = &task_in_intr; + tf->feature = sub_cmd; + tf->nsect = 0x01; + tf->lbam = SMART_LCYL_PASS; + tf->lbah = SMART_HCYL_PASS; + tf->command = WIN_SMART; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + args.data_phase = TASKFILE_IN; (void) smart_enable(drive); - return ide_raw_taskfile(drive, &args, buf); + return ide_raw_taskfile(drive, &args, buf, 1); } static int proc_idedisk_read_cache @@ -659,19 +591,20 @@ static ide_proc_entry_t idedisk_proc[] = { static void idedisk_prepare_flush(struct request_queue *q, struct request *rq) { ide_drive_t *drive = q->queuedata; + ide_task_t task; - memset(rq->cmd, 0, sizeof(rq->cmd)); - + memset(&task, 0, sizeof(task)); if (ide_id_has_flush_cache_ext(drive->id) && (drive->capacity64 >= (1UL << 28))) - rq->cmd[0] = WIN_FLUSH_CACHE_EXT; + task.tf.command = WIN_FLUSH_CACHE_EXT; else - rq->cmd[0] = WIN_FLUSH_CACHE; + task.tf.command = WIN_FLUSH_CACHE; + task.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_OUT_DEVICE; + task.data_phase = TASKFILE_NO_DATA; - - rq->cmd_type = REQ_TYPE_ATA_TASK; + rq->cmd_type = REQ_TYPE_ATA_TASKFILE; rq->cmd_flags |= REQ_SOFTBARRIER; - rq->buffer = rq->cmd; + rq->special = &task; } /* @@ -687,8 +620,10 @@ static int set_multcount(ide_drive_t *drive, int arg) if (drive->special.b.set_multmode) return -EBUSY; + ide_init_drive_cmd (&rq); - rq.cmd_type = REQ_TYPE_ATA_CMD; + rq.cmd_type = REQ_TYPE_ATA_TASKFILE; + drive->mult_req = arg; drive->special.b.set_multmode = 1; (void) ide_do_drive_cmd (drive, &rq, ide_wait); @@ -753,12 +688,11 @@ static int write_cache(ide_drive_t *drive, int arg) if (ide_id_has_flush_cache(drive->id)) { memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? + args.tf.feature = arg ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - err = ide_raw_taskfile(drive, &args, NULL); + args.tf.command = WIN_SETFEATURES; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + err = ide_no_data_taskfile(drive, &args); if (err == 0) drive->wcache = arg; } @@ -774,12 +708,11 @@ static int do_idedisk_flushcache (ide_drive_t *drive) memset(&args, 0, sizeof(ide_task_t)); if (ide_id_has_flush_cache_ext(drive->id)) - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; + args.tf.command = WIN_FLUSH_CACHE_EXT; else - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - return ide_raw_taskfile(drive, &args, NULL); + args.tf.command = WIN_FLUSH_CACHE; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + return ide_no_data_taskfile(drive, &args); } static int set_acoustic (ide_drive_t *drive, int arg) @@ -790,13 +723,11 @@ static int set_acoustic (ide_drive_t *drive, int arg) return -EINVAL; memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_FEATURE_OFFSET] = (arg) ? SETFEATURES_EN_AAM : - SETFEATURES_DIS_AAM; - args.tfRegister[IDE_NSECTOR_OFFSET] = arg; - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETFEATURES; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - ide_raw_taskfile(drive, &args, NULL); + args.tf.feature = arg ? SETFEATURES_EN_AAM : SETFEATURES_DIS_AAM; + args.tf.nsect = arg; + args.tf.command = WIN_SETFEATURES; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + ide_no_data_taskfile(drive, &args); drive->acoustic = arg; return 0; } @@ -832,7 +763,6 @@ static void idedisk_add_settings(ide_drive_t *drive) ide_add_setting(drive, "bios_head", SETTING_RW, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); ide_add_setting(drive, "bios_sect", SETTING_RW, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); ide_add_setting(drive, "address", SETTING_RW, TYPE_BYTE, 0, 2, 1, 1, &drive->addressing, set_lba_addressing); - ide_add_setting(drive, "bswap", SETTING_READ, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); ide_add_setting(drive, "multcount", SETTING_RW, TYPE_BYTE, 0, id->max_multsect, 1, 1, &drive->mult_count, set_multcount); ide_add_setting(drive, "nowerr", SETTING_RW, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr); ide_add_setting(drive, "lun", SETTING_RW, TYPE_INT, 0, 7, 1, 1, &drive->lun, NULL); @@ -1041,6 +971,17 @@ static ide_driver_t idedisk_driver = { #endif }; +static int idedisk_set_doorlock(ide_drive_t *drive, int on) +{ + ide_task_t task; + + memset(&task, 0, sizeof(task)); + task.tf.command = on ? WIN_DOORLOCK : WIN_DOORUNLOCK; + task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + + return ide_no_data_taskfile(drive, &task); +} + static int idedisk_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; @@ -1055,18 +996,13 @@ static int idedisk_open(struct inode *inode, struct file *filp) idkp->openers++; if (drive->removable && idkp->openers == 1) { - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; check_disk_change(inode->i_bdev); /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) + if (drive->doorlocking && idedisk_set_doorlock(drive, 1)) drive->doorlocking = 0; } return 0; @@ -1082,12 +1018,7 @@ static int idedisk_release(struct inode *inode, struct file *filp) ide_cacheflush_p(drive); if (drive->removable && idkp->openers == 1) { - ide_task_t args; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK; - args.command_type = IDE_DRIVE_TASK_NO_DATA; - args.handler = &task_no_data_intr; - if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL)) + if (drive->doorlocking && idedisk_set_doorlock(drive, 0)) drive->doorlocking = 0; } diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 4703837bf1fc..5bf32038dc43 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -153,13 +153,7 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive) if (!dma_stat) { struct request *rq = HWGROUP(drive)->rq; - if (rq->rq_disk) { - ide_driver_t *drv; - - drv = *(ide_driver_t **)rq->rq_disk->private_data; - drv->end_request(drive, 1, rq->nr_sectors); - } else - ide_end_request(drive, 1, rq->nr_sectors); + task_end_request(drive, rq, stat); return ide_stopped; } printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", @@ -408,23 +402,29 @@ static int dma_timer_expiry (ide_drive_t *drive) } /** - * ide_dma_host_off - Generic DMA kill + * ide_dma_host_set - Enable/disable DMA on a host * @drive: drive to control * - * Perform the generic IDE controller DMA off operation. This - * works for most IDE bus mastering controllers + * Enable/disable DMA on an IDE controller following generic + * bus-mastering IDE controller behaviour. */ -void ide_dma_host_off(ide_drive_t *drive) +void ide_dma_host_set(ide_drive_t *drive, int on) { ide_hwif_t *hwif = HWIF(drive); u8 unit = (drive->select.b.unit & 0x01); u8 dma_stat = hwif->INB(hwif->dma_status); - hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status); + if (on) + dma_stat |= (1 << (5 + unit)); + else + dma_stat &= ~(1 << (5 + unit)); + + hwif->OUTB(dma_stat, hwif->dma_status); } -EXPORT_SYMBOL(ide_dma_host_off); +EXPORT_SYMBOL_GPL(ide_dma_host_set); +#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ /** * ide_dma_off_quietly - Generic DMA kill @@ -438,11 +438,10 @@ void ide_dma_off_quietly(ide_drive_t *drive) drive->using_dma = 0; ide_toggle_bounce(drive, 0); - drive->hwif->dma_host_off(drive); + drive->hwif->dma_host_set(drive, 0); } EXPORT_SYMBOL(ide_dma_off_quietly); -#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ /** * ide_dma_off - disable DMA on a device @@ -455,56 +454,29 @@ EXPORT_SYMBOL(ide_dma_off_quietly); void ide_dma_off(ide_drive_t *drive) { printk(KERN_INFO "%s: DMA disabled\n", drive->name); - drive->hwif->dma_off_quietly(drive); + ide_dma_off_quietly(drive); } EXPORT_SYMBOL(ide_dma_off); -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** - * ide_dma_host_on - Enable DMA on a host - * @drive: drive to enable for DMA - * - * Enable DMA on an IDE controller following generic bus mastering - * IDE controller behaviour - */ - -void ide_dma_host_on(ide_drive_t *drive) -{ - if (drive->using_dma) { - ide_hwif_t *hwif = HWIF(drive); - u8 unit = (drive->select.b.unit & 0x01); - u8 dma_stat = hwif->INB(hwif->dma_status); - - hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status); - } -} - -EXPORT_SYMBOL(ide_dma_host_on); - -/** - * __ide_dma_on - Enable DMA on a device + * ide_dma_on - Enable DMA on a device * @drive: drive to enable DMA on * * Enable IDE DMA for a device on this IDE controller. */ - -int __ide_dma_on (ide_drive_t *drive) -{ - /* consult the list of known "bad" drives */ - if (__ide_dma_bad_drive(drive)) - return 1; +void ide_dma_on(ide_drive_t *drive) +{ drive->using_dma = 1; ide_toggle_bounce(drive, 1); - drive->hwif->dma_host_on(drive); - - return 0; + drive->hwif->dma_host_set(drive, 1); } -EXPORT_SYMBOL(__ide_dma_on); +EXPORT_SYMBOL(ide_dma_on); +#ifdef CONFIG_BLK_DEV_IDEDMA_PCI /** * ide_dma_setup - begin a DMA phase * @drive: target device @@ -759,6 +731,7 @@ EXPORT_SYMBOL_GPL(ide_find_dma_mode); static int ide_tune_dma(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; u8 speed; if (noautodma || drive->nodma || (drive->id->capability & 1) == 0) @@ -771,15 +744,21 @@ static int ide_tune_dma(ide_drive_t *drive) if (ide_id_dma_bug(drive)) return 0; - if (drive->hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) + if (hwif->host_flags & IDE_HFLAG_TRUST_BIOS_FOR_DMA) return config_drive_for_dma(drive); speed = ide_max_dma_mode(drive); - if (!speed) - return 0; + if (!speed) { + /* is this really correct/needed? */ + if ((hwif->host_flags & IDE_HFLAG_CY82C693) && + ide_dma_good_drive(drive)) + return 1; + else + return 0; + } - if (drive->hwif->host_flags & IDE_HFLAG_NO_SET_MODE) + if (hwif->host_flags & IDE_HFLAG_NO_SET_MODE) return 0; if (ide_set_dma_mode(drive, speed)) @@ -824,25 +803,23 @@ err_out: int ide_set_dma(ide_drive_t *drive) { - ide_hwif_t *hwif = drive->hwif; int rc; + /* + * Force DMAing for the beginning of the check. + * Some chipsets appear to do interesting + * things, if not checked and cleared. + * PARANOIA!!! + */ + ide_dma_off_quietly(drive); + rc = ide_dma_check(drive); + if (rc) + return rc; - switch(rc) { - case -1: /* DMA needs to be disabled */ - hwif->dma_off_quietly(drive); - return -1; - case 0: /* DMA needs to be enabled */ - return hwif->ide_dma_on(drive); - case 1: /* DMA setting cannot be changed */ - break; - default: - BUG(); - break; - } + ide_dma_on(drive); - return rc; + return 0; } #ifdef CONFIG_BLK_DEV_IDEDMA_PCI @@ -968,11 +945,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) hwif->dma_base = base; - if (hwif->mate) - hwif->dma_master = hwif->channel ? hwif->mate->dma_base : base; - else - hwif->dma_master = base; - if (!(hwif->dma_command)) hwif->dma_command = hwif->dma_base; if (!(hwif->dma_vendor1)) @@ -984,14 +956,8 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) if (!(hwif->dma_prdtable)) hwif->dma_prdtable = (hwif->dma_base + 4); - if (!hwif->dma_off_quietly) - hwif->dma_off_quietly = &ide_dma_off_quietly; - if (!hwif->dma_host_off) - hwif->dma_host_off = &ide_dma_host_off; - if (!hwif->ide_dma_on) - hwif->ide_dma_on = &__ide_dma_on; - if (!hwif->dma_host_on) - hwif->dma_host_on = &ide_dma_host_on; + if (!hwif->dma_host_set) + hwif->dma_host_set = &ide_dma_host_set; if (!hwif->dma_setup) hwif->dma_setup = &ide_dma_setup; if (!hwif->dma_exec_cmd) @@ -1014,8 +980,6 @@ void ide_setup_dma(ide_hwif_t *hwif, unsigned long base, unsigned num_ports) hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio"); } printk("\n"); - - BUG_ON(!hwif->dma_master); } EXPORT_SYMBOL_GPL(ide_setup_dma); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 04a357808f2e..ff8232ef9659 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -369,27 +369,6 @@ typedef struct ide_floppy_obj { #define IDEFLOPPY_IOCTL_FORMAT_START 0x4602 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS 0x4603 -#if 0 -/* - * Special requests for our block device strategy routine. - */ -#define IDEFLOPPY_FIRST_RQ 90 - -/* - * IDEFLOPPY_PC_RQ is used to queue a packet command in the request queue. - */ -#define IDEFLOPPY_PC_RQ 90 - -#define IDEFLOPPY_LAST_RQ 90 - -/* - * A macro which can be used to check if a given request command - * originated in the driver or in the buffer cache layer. - */ -#define IDEFLOPPY_RQ_CMD(cmd) ((cmd >= IDEFLOPPY_FIRST_RQ) && (cmd <= IDEFLOPPY_LAST_RQ)) - -#endif - /* * Error codes which are returned in rq->errors to the higher part * of the driver. @@ -793,9 +772,8 @@ static void idefloppy_retry_pc (ide_drive_t *drive) { idefloppy_pc_t *pc; struct request *rq; - atapi_error_t error; - error.all = HWIF(drive)->INB(IDE_ERROR_REG); + (void)drive->hwif->INB(IDE_ERROR_REG); pc = idefloppy_next_pc_storage(drive); rq = idefloppy_next_rq_storage(drive); idefloppy_create_request_sense_cmd(pc); @@ -809,12 +787,12 @@ static void idefloppy_retry_pc (ide_drive_t *drive) static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; - atapi_status_t status; - atapi_bcount_t bcount; - atapi_ireason_t ireason; + ide_hwif_t *hwif = drive->hwif; idefloppy_pc_t *pc = floppy->pc; struct request *rq = pc->rq; unsigned int temp; + u16 bcount; + u8 stat, ireason; debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", __FUNCTION__); @@ -830,16 +808,16 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) } /* Clear the interrupt */ - status.all = HWIF(drive)->INB(IDE_STATUS_REG); + stat = drive->hwif->INB(IDE_STATUS_REG); - if (!status.b.drq) { /* No more interrupts */ + if ((stat & DRQ_STAT) == 0) { /* No more interrupts */ debug_log(KERN_INFO "Packet command completed, %d bytes " "transferred\n", pc->actually_transferred); clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable_in_hardirq(); - if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { + if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ debug_log(KERN_INFO "ide-floppy: %s: I/O error\n", drive->name); @@ -870,32 +848,32 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) } /* Get the number of bytes to transfer */ - bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); - bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); + bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | + hwif->INB(IDE_BCOUNTL_REG); /* on this interrupt */ - ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); + ireason = hwif->INB(IDE_IREASON_REG); - if (ireason.b.cod) { + if (ireason & CD) { printk(KERN_ERR "ide-floppy: CoD != 0 in idefloppy_pc_intr\n"); return ide_do_reset(drive); } - if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) { + if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk(KERN_ERR "ide-floppy: We wanted to %s, ", - ireason.b.io ? "Write":"Read"); + (ireason & IO) ? "Write" : "Read"); printk(KERN_ERR "but the floppy wants us to %s !\n", - ireason.b.io ? "Read":"Write"); + (ireason & IO) ? "Read" : "Write"); return ide_do_reset(drive); } if (!test_bit(PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ - temp = pc->actually_transferred + bcount.all; + temp = pc->actually_transferred + bcount; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-floppy: The floppy wants " "to send us more data than expected " "- discarding data\n"); - idefloppy_discard_data(drive,bcount.all); + idefloppy_discard_data(drive, bcount); BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &idefloppy_pc_intr, @@ -911,23 +889,21 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) if (test_bit(PC_WRITING, &pc->flags)) { if (pc->buffer != NULL) /* Write the current buffer */ - HWIF(drive)->atapi_output_bytes(drive, - pc->current_position, - bcount.all); + hwif->atapi_output_bytes(drive, pc->current_position, + bcount); else - idefloppy_output_buffers(drive, pc, bcount.all); + idefloppy_output_buffers(drive, pc, bcount); } else { if (pc->buffer != NULL) /* Read the current buffer */ - HWIF(drive)->atapi_input_bytes(drive, - pc->current_position, - bcount.all); + hwif->atapi_input_bytes(drive, pc->current_position, + bcount); else - idefloppy_input_buffers(drive, pc, bcount.all); + idefloppy_input_buffers(drive, pc, bcount); } /* Update the current position */ - pc->actually_transferred += bcount.all; - pc->current_position += bcount.all; + pc->actually_transferred += bcount; + pc->current_position += bcount; BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ @@ -943,15 +919,15 @@ static ide_startstop_t idefloppy_transfer_pc (ide_drive_t *drive) { ide_startstop_t startstop; idefloppy_floppy_t *floppy = drive->driver_data; - atapi_ireason_t ireason; + u8 ireason; if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { printk(KERN_ERR "ide-floppy: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); - if (!ireason.b.cod || ireason.b.io) { + ireason = drive->hwif->INB(IDE_IREASON_REG); + if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while " "issuing a packet command\n"); return ide_do_reset(drive); @@ -991,15 +967,15 @@ static ide_startstop_t idefloppy_transfer_pc1 (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; ide_startstop_t startstop; - atapi_ireason_t ireason; + u8 ireason; if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { printk(KERN_ERR "ide-floppy: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); - if (!ireason.b.cod || ireason.b.io) { + ireason = drive->hwif->INB(IDE_IREASON_REG); + if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) " "while issuing a packet command\n"); return ide_do_reset(drive); @@ -1041,21 +1017,9 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p { idefloppy_floppy_t *floppy = drive->driver_data; ide_hwif_t *hwif = drive->hwif; - atapi_feature_t feature; - atapi_bcount_t bcount; ide_handler_t *pkt_xfer_routine; - -#if 0 /* Accessing floppy->pc is not valid here, the previous pc may be gone - and have lived on another thread's stack; that stack may have become - unmapped meanwhile (CONFIG_DEBUG_PAGEALLOC). */ -#if IDEFLOPPY_DEBUG_BUGS - if (floppy->pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD && - pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { - printk(KERN_ERR "ide-floppy: possible ide-floppy.c bug - " - "Two request sense in serial were issued\n"); - } -#endif /* IDEFLOPPY_DEBUG_BUGS */ -#endif + u16 bcount; + u8 dma; if (floppy->failed_pc == NULL && pc->c[0] != IDEFLOPPY_REQUEST_SENSE_CMD) @@ -1093,25 +1057,20 @@ static ide_startstop_t idefloppy_issue_pc (ide_drive_t *drive, idefloppy_pc_t *p /* We haven't transferred any data yet */ pc->actually_transferred = 0; pc->current_position = pc->buffer; - bcount.all = min(pc->request_transfer, 63 * 1024); + bcount = min(pc->request_transfer, 63 * 1024); if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) ide_dma_off(drive); - feature.all = 0; + dma = 0; if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - feature.b.dma = !hwif->dma_setup(drive); + dma = !hwif->dma_setup(drive); - if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); - /* Use PIO/DMA */ - HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG); - HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG); - HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); - HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG); + ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK | + IDE_TFLAG_OUT_DEVICE, bcount, dma); - if (feature.b.dma) { /* Begin DMA, if necessary */ + if (dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); hwif->dma_start(drive); } @@ -1665,14 +1624,14 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg) /* Else assume format_unit has finished, and we're ** at 0x10000 */ } else { - atapi_status_t status; unsigned long flags; + u8 stat; local_irq_save(flags); - status.all = HWIF(drive)->INB(IDE_STATUS_REG); + stat = drive->hwif->INB(IDE_STATUS_REG); local_irq_restore(flags); - progress_indication = !status.b.dsc ? 0 : 0x10000; + progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000; } if (put_user(progress_indication, arg)) return (-EFAULT); diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 0f72b98d727f..bb30c29f6ec0 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -14,10 +14,16 @@ static int __init ide_generic_init(void) { + u8 idx[MAX_HWIFS]; + int i; + if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) ide_get_lock(NULL, NULL); /* for atari only */ - (void)ideprobe_init(); + for (i = 0; i < MAX_HWIFS; i++) + idx[i] = ide_hwifs[i].present ? 0xff : i; + + ide_device_add_all(idx); if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) ide_release_lock(); /* for atari only */ diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index bef781fec500..e6bb9cf24e3d 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -58,15 +58,19 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate, unsigned int nr_bytes, int dequeue) { int ret = 1; + int error = 0; + + if (uptodate <= 0) + error = uptodate ? uptodate : -EIO; /* * if failfast is set on a request, override number of sectors and * complete the whole request right now */ - if (blk_noretry_request(rq) && end_io_error(uptodate)) + if (blk_noretry_request(rq) && error) nr_bytes = rq->hard_nr_sectors << 9; - if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + if (!blk_fs_request(rq) && error && !rq->errors) rq->errors = -EIO; /* @@ -75,17 +79,12 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq, */ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { drive->state = 0; - HWGROUP(drive)->hwif->ide_dma_on(drive); + ide_dma_on(drive); } - if (!end_that_request_chunk(rq, uptodate, nr_bytes)) { - add_disk_randomness(rq->rq_disk); - if (dequeue) { - if (!list_empty(&rq->queuelist)) - blkdev_dequeue_request(rq); + if (!__blk_end_request(rq, error, nr_bytes)) { + if (dequeue) HWGROUP(drive)->rq = NULL; - } - end_that_request_last(rq, uptodate); ret = 0; } @@ -189,18 +188,14 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * return ide_stopped; } if (ide_id_has_flush_cache_ext(drive->id)) - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT; + args->tf.command = WIN_FLUSH_CACHE_EXT; else - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE; - args->command_type = IDE_DRIVE_TASK_NO_DATA; - args->handler = &task_no_data_intr; - return do_rw_taskfile(drive, args); + args->tf.command = WIN_FLUSH_CACHE; + goto out_do_tf; case idedisk_pm_standby: /* Suspend step 2 (standby) */ - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1; - args->command_type = IDE_DRIVE_TASK_NO_DATA; - args->handler = &task_no_data_intr; - return do_rw_taskfile(drive, args); + args->tf.command = WIN_STANDBYNOW1; + goto out_do_tf; case idedisk_pm_restore_pio: /* Resume step 1 (restore PIO) */ ide_set_max_pio(drive); @@ -214,10 +209,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * return ide_stopped; case idedisk_pm_idle: /* Resume step 2 (idle) */ - args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE; - args->command_type = IDE_DRIVE_TASK_NO_DATA; - args->handler = task_no_data_intr; - return do_rw_taskfile(drive, args); + args->tf.command = WIN_IDLEIMMEDIATE; + goto out_do_tf; case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */ /* @@ -225,9 +218,8 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * * we could be smarter and check for current xfer_speed * in struct drive etc... */ - if (drive->hwif->ide_dma_on == NULL) + if (drive->hwif->dma_host_set == NULL) break; - drive->hwif->dma_off_quietly(drive); /* * TODO: respect ->using_dma setting */ @@ -236,6 +228,11 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request * } pm->pm_step = ide_pm_state_completed; return ide_stopped; + +out_do_tf: + args->tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + args->data_phase = TASKFILE_NO_DATA; + return do_rw_taskfile(drive, args); } /** @@ -292,12 +289,54 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) drive->blocked = 0; blk_start_queue(drive->queue); } - blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; - end_that_request_last(rq, 1); + if (__blk_end_request(rq, 0, 0)) + BUG(); spin_unlock_irqrestore(&ide_lock, flags); } +void ide_tf_read(ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = drive->hwif; + struct ide_taskfile *tf = &task->tf; + + if (task->tf_flags & IDE_TFLAG_IN_DATA) { + u16 data = hwif->INW(IDE_DATA_REG); + + tf->data = data & 0xff; + tf->hob_data = (data >> 8) & 0xff; + } + + /* be sure we're looking at the low order bits */ + hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); + + if (task->tf_flags & IDE_TFLAG_IN_NSECT) + tf->nsect = hwif->INB(IDE_NSECTOR_REG); + if (task->tf_flags & IDE_TFLAG_IN_LBAL) + tf->lbal = hwif->INB(IDE_SECTOR_REG); + if (task->tf_flags & IDE_TFLAG_IN_LBAM) + tf->lbam = hwif->INB(IDE_LCYL_REG); + if (task->tf_flags & IDE_TFLAG_IN_LBAH) + tf->lbah = hwif->INB(IDE_HCYL_REG); + if (task->tf_flags & IDE_TFLAG_IN_DEVICE) + tf->device = hwif->INB(IDE_SELECT_REG); + + if (task->tf_flags & IDE_TFLAG_LBA48) { + hwif->OUTB(drive->ctl | 0x80, IDE_CONTROL_REG); + + if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE) + tf->hob_feature = hwif->INB(IDE_FEATURE_REG); + if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT) + tf->hob_nsect = hwif->INB(IDE_NSECTOR_REG); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL) + tf->hob_lbal = hwif->INB(IDE_SECTOR_REG); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM) + tf->hob_lbam = hwif->INB(IDE_LCYL_REG); + if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH) + tf->hob_lbah = hwif->INB(IDE_HCYL_REG); + } +} + /** * ide_end_drive_cmd - end an explicit drive command * @drive: command @@ -314,7 +353,6 @@ static void ide_complete_pm_request (ide_drive_t *drive, struct request *rq) void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) { - ide_hwif_t *hwif = HWIF(drive); unsigned long flags; struct request *rq; @@ -322,61 +360,18 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) rq = HWGROUP(drive)->rq; spin_unlock_irqrestore(&ide_lock, flags); - if (rq->cmd_type == REQ_TYPE_ATA_CMD) { - u8 *args = (u8 *) rq->buffer; - if (rq->errors == 0) - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - - if (args) { - args[0] = stat; - args[1] = err; - args[2] = hwif->INB(IDE_NSECTOR_REG); - } - } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { - u8 *args = (u8 *) rq->buffer; - if (rq->errors == 0) - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - - if (args) { - args[0] = stat; - args[1] = err; - /* be sure we're looking at the low order bits */ - hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); - args[2] = hwif->INB(IDE_NSECTOR_REG); - args[3] = hwif->INB(IDE_SECTOR_REG); - args[4] = hwif->INB(IDE_LCYL_REG); - args[5] = hwif->INB(IDE_HCYL_REG); - args[6] = hwif->INB(IDE_SELECT_REG); - } - } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { ide_task_t *args = (ide_task_t *) rq->special; if (rq->errors == 0) rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); if (args) { - if (args->tf_in_flags.b.data) { - u16 data = hwif->INW(IDE_DATA_REG); - args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; - args->hobRegister[IDE_DATA_OFFSET] = (data >> 8) & 0xFF; - } - args->tfRegister[IDE_ERROR_OFFSET] = err; - /* be sure we're looking at the low order bits */ - hwif->OUTB(drive->ctl & ~0x80, IDE_CONTROL_REG); - args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); - args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); - args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); - args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); - args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG); - args->tfRegister[IDE_STATUS_OFFSET] = stat; - - if (drive->addressing == 1) { - hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); - args->hobRegister[IDE_FEATURE_OFFSET] = hwif->INB(IDE_FEATURE_REG); - args->hobRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); - args->hobRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); - args->hobRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); - args->hobRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); - } + struct ide_taskfile *tf = &args->tf; + + tf->error = err; + tf->status = stat; + + ide_tf_read(drive, args); } } else if (blk_pm_request(rq)) { struct request_pm_state *pm = rq->data; @@ -391,10 +386,10 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) } spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); HWGROUP(drive)->rq = NULL; rq->errors = err; - end_that_request_last(rq, !rq->errors); + if (__blk_end_request(rq, (rq->errors ? -EIO : 0), 0)) + BUG(); spin_unlock_irqrestore(&ide_lock, flags); } @@ -615,90 +610,26 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg) return __ide_abort(drive, rq); } -/** - * ide_cmd - issue a simple drive command - * @drive: drive the command is for - * @cmd: command byte - * @nsect: sector byte - * @handler: handler for the command completion - * - * Issue a simple drive command with interrupts. - * The drive must be selected beforehand. - */ - -static void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, - ide_handler_t *handler) +static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf) { - ide_hwif_t *hwif = HWIF(drive); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(drive,0); - hwif->OUTB(nsect,IDE_NSECTOR_REG); - ide_execute_command(drive, cmd, handler, WAIT_CMD, NULL); + tf->nsect = drive->sect; + tf->lbal = drive->sect; + tf->lbam = drive->cyl; + tf->lbah = drive->cyl >> 8; + tf->device = ((drive->head - 1) | drive->select.all) & ~ATA_LBA; + tf->command = WIN_SPECIFY; } -/** - * drive_cmd_intr - drive command completion interrupt - * @drive: drive the completion interrupt occurred on - * - * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. - * We do any necessary data reading and then wait for the drive to - * go non busy. At that point we may read the error data and complete - * the request - */ - -static ide_startstop_t drive_cmd_intr (ide_drive_t *drive) +static void ide_tf_set_restore_cmd(ide_drive_t *drive, struct ide_taskfile *tf) { - struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); - u8 *args = (u8 *) rq->buffer; - u8 stat = hwif->INB(IDE_STATUS_REG); - int retries = 10; - - local_irq_enable_in_hardirq(); - if (rq->cmd_type == REQ_TYPE_ATA_CMD && - (stat & DRQ_STAT) && args && args[3]) { - u8 io_32bit = drive->io_32bit; - drive->io_32bit = 0; - hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); - drive->io_32bit = io_32bit; - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) - udelay(100); - } - - if (!OK_STAT(stat, READY_STAT, BAD_STAT)) - return ide_error(drive, "drive_cmd", stat); - /* calls ide_end_drive_cmd */ - ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); - return ide_stopped; + tf->nsect = drive->sect; + tf->command = WIN_RESTORE; } -static void ide_init_specify_cmd(ide_drive_t *drive, ide_task_t *task) +static void ide_tf_set_setmult_cmd(ide_drive_t *drive, struct ide_taskfile *tf) { - task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; - task->tfRegister[IDE_SECTOR_OFFSET] = drive->sect; - task->tfRegister[IDE_LCYL_OFFSET] = drive->cyl; - task->tfRegister[IDE_HCYL_OFFSET] = drive->cyl>>8; - task->tfRegister[IDE_SELECT_OFFSET] = ((drive->head-1)|drive->select.all)&0xBF; - task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY; - - task->handler = &set_geometry_intr; -} - -static void ide_init_restore_cmd(ide_drive_t *drive, ide_task_t *task) -{ - task->tfRegister[IDE_NSECTOR_OFFSET] = drive->sect; - task->tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE; - - task->handler = &recal_intr; -} - -static void ide_init_setmult_cmd(ide_drive_t *drive, ide_task_t *task) -{ - task->tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req; - task->tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT; - - task->handler = &set_multmode_intr; + tf->nsect = drive->mult_req; + tf->command = WIN_SETMULT; } static ide_startstop_t ide_disk_special(ide_drive_t *drive) @@ -707,19 +638,19 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) ide_task_t args; memset(&args, 0, sizeof(ide_task_t)); - args.command_type = IDE_DRIVE_TASK_NO_DATA; + args.data_phase = TASKFILE_NO_DATA; if (s->b.set_geometry) { s->b.set_geometry = 0; - ide_init_specify_cmd(drive, &args); + ide_tf_set_specify_cmd(drive, &args.tf); } else if (s->b.recalibrate) { s->b.recalibrate = 0; - ide_init_restore_cmd(drive, &args); + ide_tf_set_restore_cmd(drive, &args.tf); } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->mult_req > drive->id->max_multsect) drive->mult_req = drive->id->max_multsect; - ide_init_setmult_cmd(drive, &args); + ide_tf_set_setmult_cmd(drive, &args.tf); } else if (s->all) { int special = s->all; s->all = 0; @@ -727,6 +658,9 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive) return ide_stopped; } + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE | + IDE_TFLAG_CUSTOM_HANDLER; + do_rw_taskfile(drive, &args); return ide_started; @@ -801,7 +735,7 @@ static ide_startstop_t do_special (ide_drive_t *drive) if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { if (keep_dma) - hwif->ide_dma_on(drive); + ide_dma_on(drive); } } @@ -861,13 +795,10 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = HWIF(drive); - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - ide_task_t *args = rq->special; - - if (!args) - goto done; + ide_task_t *task = rq->special; - hwif->data_phase = args->data_phase; + if (task) { + hwif->data_phase = task->data_phase; switch (hwif->data_phase) { case TASKFILE_MULTI_OUT: @@ -880,57 +811,9 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, break; } - if (args->tf_out_flags.all != 0) - return flagged_taskfile(drive, args); - return do_rw_taskfile(drive, args); - } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) { - u8 *args = rq->buffer; - - if (!args) - goto done; -#ifdef DEBUG - printk("%s: DRIVE_TASK_CMD ", drive->name); - printk("cmd=0x%02x ", args[0]); - printk("fr=0x%02x ", args[1]); - printk("ns=0x%02x ", args[2]); - printk("sc=0x%02x ", args[3]); - printk("lcyl=0x%02x ", args[4]); - printk("hcyl=0x%02x ", args[5]); - printk("sel=0x%02x\n", args[6]); -#endif - hwif->OUTB(args[1], IDE_FEATURE_REG); - hwif->OUTB(args[3], IDE_SECTOR_REG); - hwif->OUTB(args[4], IDE_LCYL_REG); - hwif->OUTB(args[5], IDE_HCYL_REG); - hwif->OUTB((args[6] & 0xEF)|drive->select.all, IDE_SELECT_REG); - ide_cmd(drive, args[0], args[2], &drive_cmd_intr); - return ide_started; - } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) { - u8 *args = rq->buffer; - - if (!args) - goto done; -#ifdef DEBUG - printk("%s: DRIVE_CMD ", drive->name); - printk("cmd=0x%02x ", args[0]); - printk("sc=0x%02x ", args[1]); - printk("fr=0x%02x ", args[2]); - printk("xx=0x%02x\n", args[3]); -#endif - if (args[0] == WIN_SMART) { - hwif->OUTB(0x4f, IDE_LCYL_REG); - hwif->OUTB(0xc2, IDE_HCYL_REG); - hwif->OUTB(args[2],IDE_FEATURE_REG); - hwif->OUTB(args[1],IDE_SECTOR_REG); - ide_cmd(drive, args[0], args[3], &drive_cmd_intr); - return ide_started; - } - hwif->OUTB(args[2],IDE_FEATURE_REG); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return ide_started; - } - -done: + return do_rw_taskfile(drive, task); + } + /* * NULL is actually a valid way of waiting for * all current requests to be flushed from the queue. @@ -970,8 +853,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) if (rc) printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name); SELECT_DRIVE(drive); - if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); + ide_set_irq(drive, 1); rc = ide_wait_not_busy(HWIF(drive), 100000); if (rc) printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name); @@ -1003,6 +885,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) /* bail early if we've exceeded max_failures */ if (drive->max_failures && (drive->failures > drive->max_failures)) { + rq->cmd_flags |= REQ_FAILED; goto kill_rq; } @@ -1034,9 +917,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (drive->current_speed == 0xff) ide_config_drive_speed(drive, drive->desired_speed); - if (rq->cmd_type == REQ_TYPE_ATA_CMD || - rq->cmd_type == REQ_TYPE_ATA_TASK || - rq->cmd_type == REQ_TYPE_ATA_TASKFILE) + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) return execute_drive_cmd(drive, rq); else if (blk_pm_request(rq)) { struct request_pm_state *pm = rq->data; @@ -1244,11 +1125,13 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) } again: hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && - hwif != hwgroup->hwif && - hwif->io_ports[IDE_CONTROL_OFFSET]) { - /* set nIEN for previous hwif */ - SELECT_INTERRUPT(drive); + if (hwgroup->hwif->sharing_irq && hwif != hwgroup->hwif) { + /* + * set nIEN for previous hwif, drives in the + * quirk_list may not like intr setups/cleanups + */ + if (drive->quirk_list != 1) + ide_set_irq(drive, 0); } hwgroup->hwif = hwif; hwgroup->drive = drive; @@ -1361,7 +1244,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) */ drive->retry_pio++; drive->state = DMA_PIO_RETRY; - hwif->dma_off_quietly(drive); + ide_dma_off_quietly(drive); /* * un-busy drive etc (hwgroup->busy is cleared on return) and @@ -1454,12 +1337,8 @@ void ide_timer_expiry (unsigned long data) */ spin_unlock(&ide_lock); hwif = HWIF(drive); -#if DISABLE_IRQ_NOSYNC - disable_irq_nosync(hwif->irq); -#else /* disable_irq_nosync ?? */ disable_irq(hwif->irq); -#endif /* DISABLE_IRQ_NOSYNC */ /* local CPU only, * as if we were handling an interrupt */ local_irq_disable(); @@ -1710,7 +1589,6 @@ irqreturn_t ide_intr (int irq, void *dev_id) void ide_init_drive_cmd (struct request *rq) { memset(rq, 0, sizeof(*rq)); - rq->cmd_type = REQ_TYPE_ATA_CMD; rq->ref_count = 1; } @@ -1785,3 +1663,19 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio } EXPORT_SYMBOL(ide_do_drive_cmd); + +void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma) +{ + ide_task_t task; + + memset(&task, 0, sizeof(task)); + task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM | + IDE_TFLAG_OUT_FEATURE | tf_flags; + task.tf.feature = dma; /* Use PIO/DMA */ + task.tf.lbam = bcount & 0xff; + task.tf.lbah = (bcount >> 8) & 0xff; + + ide_tf_load(drive, &task); +} + +EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index bb9693dabe41..e2a7e95e1636 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -158,14 +158,6 @@ void default_hwif_mmiops (ide_hwif_t *hwif) EXPORT_SYMBOL(default_hwif_mmiops); -u32 ide_read_24 (ide_drive_t *drive) -{ - u8 hcyl = HWIF(drive)->INB(IDE_HCYL_REG); - u8 lcyl = HWIF(drive)->INB(IDE_LCYL_REG); - u8 sect = HWIF(drive)->INB(IDE_SECTOR_REG); - return (hcyl<<16)|(lcyl<<8)|sect; -} - void SELECT_DRIVE (ide_drive_t *drive) { if (HWIF(drive)->selectproc) @@ -175,26 +167,12 @@ void SELECT_DRIVE (ide_drive_t *drive) EXPORT_SYMBOL(SELECT_DRIVE); -void SELECT_INTERRUPT (ide_drive_t *drive) -{ - if (HWIF(drive)->intrproc) - HWIF(drive)->intrproc(drive); - else - HWIF(drive)->OUTB(drive->ctl|2, IDE_CONTROL_REG); -} - void SELECT_MASK (ide_drive_t *drive, int mask) { if (HWIF(drive)->maskproc) HWIF(drive)->maskproc(drive, mask); } -void QUIRK_LIST (ide_drive_t *drive) -{ - if (HWIF(drive)->quirkproc) - drive->quirk_list = HWIF(drive)->quirkproc(drive); -} - /* * Some localbus EIDE interfaces require a special access sequence * when using 32-bit I/O instructions to transfer data. We call this @@ -449,7 +427,6 @@ int drive_is_ready (ide_drive_t *drive) udelay(1); #endif -#ifdef CONFIG_IDEPCI_SHARE_IRQ /* * We do a passive status test under shared PCI interrupts on * cards that truly share the ATA side interrupt, but may also share @@ -459,7 +436,6 @@ int drive_is_ready (ide_drive_t *drive) if (IDE_CONTROL_REG) stat = hwif->INB(IDE_ALTSTATUS_REG); else -#endif /* CONFIG_IDEPCI_SHARE_IRQ */ /* Note: this may clear a pending IRQ!! */ stat = hwif->INB(IDE_STATUS_REG); @@ -642,9 +618,9 @@ no_80w: int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) { - if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && - (args->tfRegister[IDE_SECTOR_OFFSET] > XFER_UDMA_2) && - (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER)) { + if (args->tf.command == WIN_SETFEATURES && + args->tf.nsect > XFER_UDMA_2 && + args->tf.feature == SETFEATURES_XFER) { if (eighty_ninty_three(drive) == 0) { printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot " "be set\n", drive->name); @@ -662,9 +638,9 @@ int ide_ata66_check (ide_drive_t *drive, ide_task_t *args) */ int set_transfer (ide_drive_t *drive, ide_task_t *args) { - if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) && - (args->tfRegister[IDE_SECTOR_OFFSET] >= XFER_SW_DMA_0) && - (args->tfRegister[IDE_FEATURE_OFFSET] == SETFEATURES_XFER) && + if (args->tf.command == WIN_SETFEATURES && + args->tf.nsect >= XFER_SW_DMA_0 && + args->tf.feature == SETFEATURES_XFER && (drive->id->dma_ultra || drive->id->dma_mword || drive->id->dma_1word)) @@ -712,8 +688,7 @@ int ide_driveid_update(ide_drive_t *drive) */ SELECT_MASK(drive, 1); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl,IDE_CONTROL_REG); + ide_set_irq(drive, 1); msleep(50); hwif->OUTB(WIN_IDENTIFY, IDE_COMMAND_REG); timeout = jiffies + WAIT_WORSTCASE; @@ -766,8 +741,8 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) // msleep(50); #ifdef CONFIG_BLK_DEV_IDEDMA - if (hwif->ide_dma_on) /* check if host supports DMA */ - hwif->dma_host_off(drive); + if (hwif->dma_host_set) /* check if host supports DMA */ + hwif->dma_host_set(drive, 0); #endif /* Skip setting PIO flow-control modes on pre-EIDE drives */ @@ -796,13 +771,12 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) SELECT_DRIVE(drive); SELECT_MASK(drive, 0); udelay(1); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); + ide_set_irq(drive, 0); hwif->OUTB(speed, IDE_NSECTOR_REG); hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); - if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + if (drive->quirk_list == 2) + ide_set_irq(drive, 1); error = __ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT, @@ -823,10 +797,11 @@ int ide_config_drive_speed(ide_drive_t *drive, u8 speed) skip: #ifdef CONFIG_BLK_DEV_IDEDMA - if (speed >= XFER_SW_DMA_0) - hwif->dma_host_on(drive); - else if (hwif->ide_dma_on) /* check if host supports DMA */ - hwif->dma_off_quietly(drive); + if ((speed >= XFER_SW_DMA_0 || (hwif->host_flags & IDE_HFLAG_VDMA)) && + drive->using_dma) + hwif->dma_host_set(drive, 1); + else if (hwif->dma_host_set) /* check if host supports DMA */ + ide_dma_off_quietly(drive); #endif switch(speed) { @@ -902,8 +877,9 @@ EXPORT_SYMBOL(ide_set_handler); * handler and IRQ setup do not race. All IDE command kick off * should go via this function or do equivalent locking. */ - -void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry) + +void ide_execute_command(ide_drive_t *drive, u8 cmd, ide_handler_t *handler, + unsigned timeout, ide_expiry_t *expiry) { unsigned long flags; ide_hwgroup_t *hwgroup = HWGROUP(drive); @@ -1035,10 +1011,10 @@ static void check_dma_crc(ide_drive_t *drive) { #ifdef CONFIG_BLK_DEV_IDEDMA if (drive->crc_count) { - drive->hwif->dma_off_quietly(drive); + ide_dma_off_quietly(drive); ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive)); if (drive->current_speed >= XFER_SW_DMA_0) - (void) HWIF(drive)->ide_dma_on(drive); + ide_dma_on(drive); } else ide_dma_off(drive); #endif @@ -1051,8 +1027,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive) drive->special.all = 0; drive->special.b.set_geometry = legacy; drive->special.b.recalibrate = legacy; - if (OK_TO_RESET_CONTROLLER) - drive->mult_count = 0; + drive->mult_count = 0; if (!drive->keep_settings && !drive->using_dma) drive->mult_req = 0; if (drive->mult_req != drive->mult_count) @@ -1137,7 +1112,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) for (unit = 0; unit < MAX_DRIVES; ++unit) pre_reset(&hwif->drives[unit]); -#if OK_TO_RESET_CONTROLLER if (!IDE_CONTROL_REG) { spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped; @@ -1174,11 +1148,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) * state when the disks are reset this way. At least, the Winbond * 553 documentation says that */ - if (hwif->resetproc != NULL) { + if (hwif->resetproc) hwif->resetproc(drive); - } - -#endif /* OK_TO_RESET_CONTROLLER */ spin_unlock_irqrestore(&ide_lock, flags); return ide_started; diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 062d3bcb2471..9b44fbdfe41f 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -441,6 +441,12 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) * case could happen iff the transfer mode has already been set on * the device by ide-proc.c::set_xfer_rate()). */ + if (rate < XFER_PIO_0) { + if (hwif->host_flags & IDE_HFLAG_ABUSE_SET_DMA_MODE) + return ide_set_dma_mode(drive, rate); + else + return ide_config_drive_speed(drive, rate); + } return ide_set_dma_mode(drive, rate); } @@ -448,8 +454,7 @@ int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) static void ide_dump_opcode(ide_drive_t *drive) { struct request *rq; - u8 opcode = 0; - int found = 0; + ide_task_t *task = NULL; spin_lock(&ide_lock); rq = NULL; @@ -458,164 +463,129 @@ static void ide_dump_opcode(ide_drive_t *drive) spin_unlock(&ide_lock); if (!rq) return; - if (rq->cmd_type == REQ_TYPE_ATA_CMD || - rq->cmd_type == REQ_TYPE_ATA_TASK) { - char *args = rq->buffer; - if (args) { - opcode = args[0]; - found = 1; - } - } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - ide_task_t *args = rq->special; - if (args) { - task_struct_t *tf = (task_struct_t *) args->tfRegister; - opcode = tf->command; - found = 1; - } - } + + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) + task = rq->special; printk("ide: failed opcode was: "); - if (!found) - printk("unknown\n"); + if (task == NULL) + printk(KERN_CONT "unknown\n"); else - printk("0x%02x\n", opcode); + printk(KERN_CONT "0x%02x\n", task->tf.command); } -static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat) +u64 ide_get_lba_addr(struct ide_taskfile *tf, int lba48) { - ide_hwif_t *hwif = HWIF(drive); - unsigned long flags; - u8 err = 0; + u32 high, low; - local_irq_save(flags); - printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); - if (stat & BUSY_STAT) - printk("Busy "); - else { - if (stat & READY_STAT) printk("DriveReady "); - if (stat & WRERR_STAT) printk("DeviceFault "); - if (stat & SEEK_STAT) printk("SeekComplete "); - if (stat & DRQ_STAT) printk("DataRequest "); - if (stat & ECC_STAT) printk("CorrectedError "); - if (stat & INDEX_STAT) printk("Index "); - if (stat & ERR_STAT) printk("Error "); + if (lba48) + high = (tf->hob_lbah << 16) | (tf->hob_lbam << 8) | + tf->hob_lbal; + else + high = tf->device & 0xf; + low = (tf->lbah << 16) | (tf->lbam << 8) | tf->lbal; + + return ((u64)high << 24) | low; +} +EXPORT_SYMBOL_GPL(ide_get_lba_addr); + +static void ide_dump_sector(ide_drive_t *drive) +{ + ide_task_t task; + struct ide_taskfile *tf = &task.tf; + int lba48 = (drive->addressing == 1) ? 1 : 0; + + memset(&task, 0, sizeof(task)); + if (lba48) + task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_HOB_LBA | + IDE_TFLAG_LBA48; + else + task.tf_flags = IDE_TFLAG_IN_LBA | IDE_TFLAG_IN_DEVICE; + + ide_tf_read(drive, &task); + + if (lba48 || (tf->device & ATA_LBA)) + printk(", LBAsect=%llu", + (unsigned long long)ide_get_lba_addr(tf, lba48)); + else + printk(", CHS=%d/%d/%d", (tf->lbah << 8) + tf->lbam, + tf->device & 0xf, tf->lbal); +} + +static void ide_dump_ata_error(ide_drive_t *drive, u8 err) +{ + printk("{ "); + if (err & ABRT_ERR) printk("DriveStatusError "); + if (err & ICRC_ERR) + printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); + if (err & ECC_ERR) printk("UncorrectableError "); + if (err & ID_ERR) printk("SectorIdNotFound "); + if (err & TRK0_ERR) printk("TrackZeroNotFound "); + if (err & MARK_ERR) printk("AddrMarkNotFound "); + printk("}"); + if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || + (err & (ECC_ERR|ID_ERR|MARK_ERR))) { + ide_dump_sector(drive); + if (HWGROUP(drive) && HWGROUP(drive)->rq) + printk(", sector=%llu", + (unsigned long long)HWGROUP(drive)->rq->sector); } + printk("\n"); +} + +static void ide_dump_atapi_error(ide_drive_t *drive, u8 err) +{ + printk("{ "); + if (err & ILI_ERR) printk("IllegalLengthIndication "); + if (err & EOM_ERR) printk("EndOfMedia "); + if (err & ABRT_ERR) printk("AbortedCommand "); + if (err & MCR_ERR) printk("MediaChangeRequested "); + if (err & LFS_ERR) printk("LastFailedSense=0x%02x ", + (err & LFS_ERR) >> 4); printk("}\n"); - if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { - err = hwif->INB(IDE_ERROR_REG); - printk("%s: %s: error=0x%02x { ", drive->name, msg, err); - if (err & ABRT_ERR) printk("DriveStatusError "); - if (err & ICRC_ERR) - printk((err & ABRT_ERR) ? "BadCRC " : "BadSector "); - if (err & ECC_ERR) printk("UncorrectableError "); - if (err & ID_ERR) printk("SectorIdNotFound "); - if (err & TRK0_ERR) printk("TrackZeroNotFound "); - if (err & MARK_ERR) printk("AddrMarkNotFound "); - printk("}"); - if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || - (err & (ECC_ERR|ID_ERR|MARK_ERR))) { - if (drive->addressing == 1) { - __u64 sectors = 0; - u32 low = 0, high = 0; - hwif->OUTB(drive->ctl&~0x80, IDE_CONTROL_REG); - low = ide_read_24(drive); - hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG); - high = ide_read_24(drive); - sectors = ((__u64)high << 24) | low; - printk(", LBAsect=%llu, high=%d, low=%d", - (unsigned long long) sectors, - high, low); - } else { - u8 cur = hwif->INB(IDE_SELECT_REG); - if (cur & 0x40) { /* using LBA? */ - printk(", LBAsect=%ld", (unsigned long) - ((cur&0xf)<<24) - |(hwif->INB(IDE_HCYL_REG)<<16) - |(hwif->INB(IDE_LCYL_REG)<<8) - | hwif->INB(IDE_SECTOR_REG)); - } else { - printk(", CHS=%d/%d/%d", - (hwif->INB(IDE_HCYL_REG)<<8) + - hwif->INB(IDE_LCYL_REG), - cur & 0xf, - hwif->INB(IDE_SECTOR_REG)); - } - } - if (HWGROUP(drive) && HWGROUP(drive)->rq) - printk(", sector=%llu", - (unsigned long long)HWGROUP(drive)->rq->sector); - } - printk("\n"); - } - ide_dump_opcode(drive); - local_irq_restore(flags); - return err; } /** - * ide_dump_atapi_status - print human readable atapi status + * ide_dump_status - translate ATA/ATAPI error * @drive: drive that status applies to * @msg: text message to print * @stat: status byte to decode * * Error reporting, in human readable form (luxurious, but a memory hog). + * Combines the drive name, message and status byte to provide a + * user understandable explanation of the device error. */ -static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat) +u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) { unsigned long flags; + u8 err = 0; - atapi_status_t status; - atapi_error_t error; - - status.all = stat; - error.all = 0; local_irq_save(flags); printk("%s: %s: status=0x%02x { ", drive->name, msg, stat); - if (status.b.bsy) + if (stat & BUSY_STAT) printk("Busy "); else { - if (status.b.drdy) printk("DriveReady "); - if (status.b.df) printk("DeviceFault "); - if (status.b.dsc) printk("SeekComplete "); - if (status.b.drq) printk("DataRequest "); - if (status.b.corr) printk("CorrectedError "); - if (status.b.idx) printk("Index "); - if (status.b.check) printk("Error "); + if (stat & READY_STAT) printk("DriveReady "); + if (stat & WRERR_STAT) printk("DeviceFault "); + if (stat & SEEK_STAT) printk("SeekComplete "); + if (stat & DRQ_STAT) printk("DataRequest "); + if (stat & ECC_STAT) printk("CorrectedError "); + if (stat & INDEX_STAT) printk("Index "); + if (stat & ERR_STAT) printk("Error "); } printk("}\n"); - if (status.b.check && !status.b.bsy) { - error.all = HWIF(drive)->INB(IDE_ERROR_REG); - printk("%s: %s: error=0x%02x { ", drive->name, msg, error.all); - if (error.b.ili) printk("IllegalLengthIndication "); - if (error.b.eom) printk("EndOfMedia "); - if (error.b.abrt) printk("AbortedCommand "); - if (error.b.mcr) printk("MediaChangeRequested "); - if (error.b.sense_key) printk("LastFailedSense=0x%02x ", - error.b.sense_key); - printk("}\n"); + if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { + err = drive->hwif->INB(IDE_ERROR_REG); + printk("%s: %s: error=0x%02x ", drive->name, msg, err); + if (drive->media == ide_disk) + ide_dump_ata_error(drive, err); + else + ide_dump_atapi_error(drive, err); } ide_dump_opcode(drive); local_irq_restore(flags); - return error.all; -} - -/** - * ide_dump_status - translate ATA/ATAPI error - * @drive: drive the error occured on - * @msg: information string - * @stat: status byte - * - * Error reporting, in human readable form (luxurious, but a memory hog). - * Combines the drive name, message and status byte to provide a - * user understandable explanation of the device error. - */ - -u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) -{ - if (drive->media == ide_disk) - return ide_dump_ata_status(drive, msg, stat); - return ide_dump_atapi_status(drive, msg, stat); + return err; } EXPORT_SYMBOL(ide_dump_status); diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index e245521af7b5..cbbb0f75be92 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -31,7 +31,6 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id { hw_regs_t hw; ide_hwif_t *hwif; - int index; if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && pnp_irq_valid(dev, 0))) return -1; @@ -41,11 +40,19 @@ static int idepnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id pnp_port_start(dev, 1)); hw.irq = pnp_irq(dev, 0); - index = ide_register_hw(&hw, NULL, 1, &hwif); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif) { + u8 index = hwif->index; + u8 idx[4] = { index, 0xff, 0xff, 0xff }; + + ide_init_port_data(hwif, index); + ide_init_port_hw(hwif, &hw); - if (index != -1) { - printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index); + printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index); pnp_set_drvdata(dev,hwif); + + ide_device_add(idx); + return 0; } @@ -68,12 +75,15 @@ static struct pnp_driver idepnp_driver = { .remove = idepnp_remove, }; -void __init pnpide_init(void) +static int __init pnpide_init(void) { - pnp_register_driver(&idepnp_driver); + return pnp_register_driver(&idepnp_driver); } -void __exit pnpide_exit(void) +static void __exit pnpide_exit(void) { pnp_unregister_driver(&idepnp_driver); } + +module_init(pnpide_init); +module_exit(pnpide_exit); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 2994523be7bf..edf650b20c67 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -95,10 +95,10 @@ static void ide_disk_init_mult_count(ide_drive_t *drive) #ifdef CONFIG_IDEDISK_MULTI_MODE id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0; id->multsect_valid = id->multsect ? 1 : 0; - drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT; + drive->mult_req = id->multsect_valid ? id->max_multsect : 0; drive->special.b.set_multmode = drive->mult_req ? 1 : 0; #else /* original, pre IDE-NFG, per request of AC */ - drive->mult_req = INITIAL_MULT_COUNT; + drive->mult_req = 0; if (drive->mult_req > id->max_multsect) drive->mult_req = id->max_multsect; if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect)) @@ -234,7 +234,7 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd) drive->media = ide_disk; printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" ); - QUIRK_LIST(drive); + return; err_misc: @@ -350,22 +350,19 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) * the irq handler isn't expecting. */ if (IDE_CONTROL_REG) { - u8 ctl = drive->ctl | 2; if (!hwif->irq) { autoprobe = 1; cookie = probe_irq_on(); - /* enable device irq */ - ctl &= ~2; } - hwif->OUTB(ctl, IDE_CONTROL_REG); + ide_set_irq(drive, autoprobe); } retval = actual_try_to_identify(drive, cmd); if (autoprobe) { int irq; - /* mask device irq */ - hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG); + + ide_set_irq(drive, 0); /* clear drive IRQ */ (void) hwif->INB(IDE_STATUS_REG); udelay(5); @@ -385,6 +382,20 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) return retval; } +static int ide_busy_sleep(ide_hwif_t *hwif) +{ + unsigned long timeout = jiffies + WAIT_WORSTCASE; + u8 stat; + + do { + msleep(50); + stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); + if ((stat & BUSY_STAT) == 0) + return 0; + } while (time_before(jiffies, timeout)); + + return 1; +} /** * do_probe - probe an IDE device @@ -453,7 +464,6 @@ static int do_probe (ide_drive_t *drive, u8 cmd) if ((rc == 1 && cmd == WIN_PIDENTIFY) && ((drive->autotune == IDE_TUNE_DEFAULT) || (drive->autotune == IDE_TUNE_AUTO))) { - unsigned long timeout; printk("%s: no response (status = 0x%02x), " "resetting drive\n", drive->name, hwif->INB(IDE_STATUS_REG)); @@ -461,10 +471,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) hwif->OUTB(drive->select.all, IDE_SELECT_REG); msleep(50); hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); - timeout = jiffies; - while (((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && - time_before(jiffies, timeout + WAIT_WORSTCASE)) - msleep(50); + (void)ide_busy_sleep(hwif); rc = try_to_identify(drive, cmd); } if (rc == 1) @@ -492,20 +499,16 @@ static int do_probe (ide_drive_t *drive, u8 cmd) static void enable_nest (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned long timeout; printk("%s: enabling %s -- ", hwif->name, drive->id->model); SELECT_DRIVE(drive); msleep(50); hwif->OUTB(EXABYTE_ENABLE_NEST, IDE_COMMAND_REG); - timeout = jiffies + WAIT_WORSTCASE; - do { - if (time_after(jiffies, timeout)) { - printk("failed (timeout)\n"); - return; - } - msleep(50); - } while ((hwif->INB(IDE_STATUS_REG)) & BUSY_STAT); + + if (ide_busy_sleep(hwif)) { + printk(KERN_CONT "failed (timeout)\n"); + return; + } msleep(50); @@ -653,8 +656,7 @@ static int wait_hwif_ready(ide_hwif_t *hwif) /* Ignore disks that we will not probe for later. */ if (!drive->noprobe || drive->present) { SELECT_DRIVE(drive); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + ide_set_irq(drive, 1); mdelay(2); rc = ide_wait_not_busy(hwif, 35000); if (rc) @@ -673,19 +675,18 @@ out: /** * ide_undecoded_slave - look for bad CF adapters - * @hwif: interface + * @drive1: drive * * Analyse the drives on the interface and attempt to decide if we * have the same drive viewed twice. This occurs with crap CF adapters * and PCMCIA sometimes. */ -void ide_undecoded_slave(ide_hwif_t *hwif) +void ide_undecoded_slave(ide_drive_t *drive1) { - ide_drive_t *drive0 = &hwif->drives[0]; - ide_drive_t *drive1 = &hwif->drives[1]; + ide_drive_t *drive0 = &drive1->hwif->drives[0]; - if (drive0->present == 0 || drive1->present == 0) + if ((drive1->dn & 1) == 0 || drive0->present == 0) return; /* If the models don't match they are not the same product */ @@ -788,18 +789,11 @@ static void probe_hwif(ide_hwif_t *hwif) } } if (hwif->io_ports[IDE_CONTROL_OFFSET] && hwif->reset) { - unsigned long timeout = jiffies + WAIT_WORSTCASE; - u8 stat; - printk(KERN_WARNING "%s: reset\n", hwif->name); hwif->OUTB(12, hwif->io_ports[IDE_CONTROL_OFFSET]); udelay(10); hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]); - do { - msleep(50); - stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); - } while ((stat & BUSY_STAT) && time_after(timeout, jiffies)); - + (void)ide_busy_sleep(hwif); } local_irq_restore(flags); /* @@ -814,8 +808,12 @@ static void probe_hwif(ide_hwif_t *hwif) return; } - if (hwif->fixup) - hwif->fixup(hwif); + for (unit = 0; unit < MAX_DRIVES; unit++) { + ide_drive_t *drive = &hwif->drives[unit]; + + if (drive->present && hwif->quirkproc) + hwif->quirkproc(drive); + } for (unit = 0; unit < MAX_DRIVES; ++unit) { ide_drive_t *drive = &hwif->drives[unit]; @@ -830,16 +828,8 @@ static void probe_hwif(ide_hwif_t *hwif) drive->nice1 = 1; - if (hwif->ide_dma_on) { - /* - * Force DMAing for the beginning of the check. - * Some chipsets appear to do interesting - * things, if not checked and cleared. - * PARANOIA!!! - */ - hwif->dma_off_quietly(drive); + if (hwif->dma_host_set) ide_set_dma(drive); - } } } @@ -853,25 +843,6 @@ static void probe_hwif(ide_hwif_t *hwif) } } -static int hwif_init(ide_hwif_t *hwif); -static void hwif_register_devices(ide_hwif_t *hwif); - -static int probe_hwif_init(ide_hwif_t *hwif) -{ - probe_hwif(hwif); - - if (!hwif_init(hwif)) { - printk(KERN_INFO "%s: failed to initialize IDE interface\n", - hwif->name); - return -1; - } - - if (hwif->present) - hwif_register_devices(hwif); - - return 0; -} - #if MAX_HWIFS > 1 /* * save_match() is used to simplify logic in init_irq() below. @@ -968,11 +939,6 @@ static int ide_init_queue(ide_drive_t *drive) * Much of the code is for correctly detecting/handling irq sharing * and irq serialization situations. This is somewhat complex because * it handles static as well as dynamic (PCMCIA) IDE interfaces. - * - * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with - * interrupts completely disabled. This can be bad for interrupt latency, - * but anything else has led to problems on some machines. We re-enable - * interrupts as much as we can safely do in most places. */ static int init_irq (ide_hwif_t *hwif) { @@ -1055,17 +1021,13 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { - int sa = IRQF_DISABLED; + int sa = 0; #if defined(__mc68000__) || defined(CONFIG_APUS) sa = IRQF_SHARED; #endif /* __mc68000__ || CONFIG_APUS */ - if (IDE_CHIPSET_IS_PCI(hwif->chipset)) { + if (IDE_CHIPSET_IS_PCI(hwif->chipset)) sa = IRQF_SHARED; -#ifndef CONFIG_IDEPCI_SHARE_IRQ - sa |= IRQF_DISABLED; -#endif /* CONFIG_IDEPCI_SHARE_IRQ */ - } if (hwif->io_ports[IDE_CONTROL_OFFSET]) /* clear nIEN */ @@ -1173,7 +1135,7 @@ static struct kobject *exact_match(dev_t dev, int *part, void *data) { struct gendisk *p = data; *part &= (1 << PARTN_BITS) - 1; - return &p->kobj; + return &p->dev.kobj; } static int exact_lock(dev_t dev, void *data) @@ -1373,54 +1335,63 @@ static void hwif_register_devices(ide_hwif_t *hwif) } } -int ideprobe_init (void) +int ide_device_add_all(u8 *idx) { - unsigned int index; - int probe[MAX_HWIFS]; - - memset(probe, 0, MAX_HWIFS * sizeof(int)); - for (index = 0; index < MAX_HWIFS; ++index) - probe[index] = !ide_hwifs[index].present; - - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - probe_hwif(&ide_hwifs[index]); - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - hwif_init(&ide_hwifs[index]); - for (index = 0; index < MAX_HWIFS; ++index) { - if (probe[index]) { - ide_hwif_t *hwif = &ide_hwifs[index]; - if (!hwif->present) - continue; - if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced) - hwif->chipset = ide_generic; - hwif_register_devices(hwif); + ide_hwif_t *hwif; + int i, rc = 0; + + for (i = 0; i < MAX_HWIFS; i++) { + if (idx[i] == 0xff) + continue; + + probe_hwif(&ide_hwifs[idx[i]]); + } + + for (i = 0; i < MAX_HWIFS; i++) { + if (idx[i] == 0xff) + continue; + + hwif = &ide_hwifs[idx[i]]; + + if (hwif_init(hwif) == 0) { + printk(KERN_INFO "%s: failed to initialize IDE " + "interface\n", hwif->name); + rc = -1; + continue; } } - for (index = 0; index < MAX_HWIFS; ++index) - if (probe[index]) - ide_proc_register_port(&ide_hwifs[index]); - return 0; -} -EXPORT_SYMBOL_GPL(ideprobe_init); + for (i = 0; i < MAX_HWIFS; i++) { + if (idx[i] == 0xff) + continue; -int ide_device_add(u8 idx[4]) -{ - int i, rc = 0; + hwif = &ide_hwifs[idx[i]]; - for (i = 0; i < 4; i++) { - if (idx[i] != 0xff) - rc |= probe_hwif_init(&ide_hwifs[idx[i]]); + if (hwif->present) { + if (hwif->chipset == ide_unknown || + hwif->chipset == ide_forced) + hwif->chipset = ide_generic; + hwif_register_devices(hwif); + } } - for (i = 0; i < 4; i++) { + for (i = 0; i < MAX_HWIFS; i++) { if (idx[i] != 0xff) ide_proc_register_port(&ide_hwifs[idx[i]]); } return rc; } +EXPORT_SYMBOL_GPL(ide_device_add_all); + +int ide_device_add(u8 idx[4]) +{ + u8 idx_all[MAX_HWIFS]; + int i; + for (i = 0; i < MAX_HWIFS; i++) + idx_all[i] = (i < 4) ? idx[i] : 0xff; + + return ide_device_add_all(idx_all); +} EXPORT_SYMBOL_GPL(ide_device_add); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index a4007d30da52..aa663e7f46f2 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -346,14 +346,20 @@ static int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int va static int set_xfer_rate (ide_drive_t *drive, int arg) { + ide_task_t task; int err; if (arg < 0 || arg > 70) return -EINVAL; - err = ide_wait_cmd(drive, - WIN_SETFEATURES, (u8) arg, - SETFEATURES_XFER, 0, NULL); + memset(&task, 0, sizeof(task)); + task.tf.command = WIN_SETFEATURES; + task.tf.feature = SETFEATURES_XFER; + task.tf.nsect = (u8)arg; + task.tf_flags = IDE_TFLAG_OUT_FEATURE | IDE_TFLAG_OUT_NSECT | + IDE_TFLAG_IN_NSECT; + + err = ide_no_data_taskfile(drive, &task); if (!err && arg) { ide_set_xfer_rate(drive, (u8) arg); diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c new file mode 100644 index 000000000000..7ffa332d77ce --- /dev/null +++ b/drivers/ide/ide-scan-pci.c @@ -0,0 +1,121 @@ +/* + * support for probing IDE PCI devices in the PCI bus order + * + * Copyright (c) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (c) 1995-1998 Mark Lord + * + * May be copied or modified under the terms of the GNU General Public License + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ide.h> + +/* + * Module interfaces + */ + +static int pre_init = 1; /* Before first ordered IDE scan */ +static LIST_HEAD(ide_pci_drivers); + +/* + * __ide_pci_register_driver - attach IDE driver + * @driver: pci driver + * @module: owner module of the driver + * + * Registers a driver with the IDE layer. The IDE layer arranges that + * boot time setup is done in the expected device order and then + * hands the controllers off to the core PCI code to do the rest of + * the work. + * + * Returns are the same as for pci_register_driver + */ + +int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, + const char *mod_name) +{ + if (!pre_init) + return __pci_register_driver(driver, module, mod_name); + driver->driver.owner = module; + list_add_tail(&driver->node, &ide_pci_drivers); + return 0; +} +EXPORT_SYMBOL_GPL(__ide_pci_register_driver); + +/** + * ide_scan_pcidev - find an IDE driver for a device + * @dev: PCI device to check + * + * Look for an IDE driver to handle the device we are considering. + * This is only used during boot up to get the ordering correct. After + * boot up the pci layer takes over the job. + */ + +static int __init ide_scan_pcidev(struct pci_dev *dev) +{ + struct list_head *l; + struct pci_driver *d; + + list_for_each(l, &ide_pci_drivers) { + d = list_entry(l, struct pci_driver, node); + if (d->id_table) { + const struct pci_device_id *id = + pci_match_id(d->id_table, dev); + + if (id != NULL && d->probe(dev, id) >= 0) { + dev->driver = d; + pci_dev_get(dev); + return 1; + } + } + } + return 0; +} + +/** + * ide_scan_pcibus - perform the initial IDE driver scan + * + * Perform the initial bus rather than driver ordered scan of the + * PCI drivers. After this all IDE pci handling becomes standard + * module ordering not traditionally ordered. + */ + +int __init ide_scan_pcibus(void) +{ + struct pci_dev *dev = NULL; + struct pci_driver *d; + struct list_head *l, *n; + + pre_init = 0; + if (!ide_scan_direction) + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))) + ide_scan_pcidev(dev); + else + while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, + dev))) + ide_scan_pcidev(dev); + + /* + * Hand the drivers over to the PCI layer now we + * are post init. + */ + + list_for_each_safe(l, n, &ide_pci_drivers) { + list_del(l); + d = list_entry(l, struct pci_driver, node); + if (__pci_register_driver(d, d->driver.owner, + d->driver.mod_name)) + printk(KERN_ERR "%s: failed to register %s driver\n", + __FUNCTION__, d->driver.mod_name); + } + + return 0; +} + +static int __init ide_scan_pci(void) +{ + return ide_scan_pcibus(); +} + +module_init(ide_scan_pci); diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7b9181b5469d..d71a584f0765 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -615,16 +615,6 @@ typedef struct os_dat_s { /*************************** End of tunable parameters ***********************/ /* - * Debugging/Performance analysis - * - * I/O trace support - */ -#define USE_IOTRACE 0 -#if USE_IOTRACE -#define IO_IDETAPE_FIFO 500 -#endif - -/* * Read/Write error simulation */ #define SIMULATE_ERRORS 0 @@ -1700,6 +1690,11 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) if (error) tape->failed_pc = NULL; + if (!blk_special_request(rq)) { + ide_end_request(drive, uptodate, nr_sects); + return 0; + } + spin_lock_irqsave(&tape->spinlock, flags); /* The request was a pipelined data transfer request */ @@ -1818,9 +1813,8 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive) idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc; struct request *rq; - atapi_error_t error; - error.all = HWIF(drive)->INB(IDE_ERROR_REG); + (void)drive->hwif->INB(IDE_ERROR_REG); pc = idetape_next_pc_storage(drive); rq = idetape_next_rq_storage(drive); idetape_create_request_sense_cmd(pc); @@ -1858,15 +1852,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; - atapi_status_t status; - atapi_bcount_t bcount; - atapi_ireason_t ireason; idetape_pc_t *pc = tape->pc; - unsigned int temp; #if SIMULATE_ERRORS static int error_sim_count = 0; #endif + u16 bcount; + u8 stat, ireason; #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 4) @@ -1875,10 +1867,10 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) #endif /* IDETAPE_DEBUG_LOG */ /* Clear the interrupt */ - status.all = HWIF(drive)->INB(IDE_STATUS_REG); + stat = hwif->INB(IDE_STATUS_REG); if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { - if (HWIF(drive)->ide_dma_end(drive) || status.b.check) { + if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) { /* * A DMA error is sometimes expected. For example, * if the tape is crossing a filemark during a @@ -1912,7 +1904,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) } /* No more interrupts */ - if (!status.b.drq) { + if ((stat & DRQ_STAT) == 0) { #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred); @@ -1927,12 +1919,13 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) (++error_sim_count % 100) == 0) { printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name); - status.b.check = 1; + stat |= ERR_STAT; } #endif - if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) - status.b.check = 0; - if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ + if ((stat & ERR_STAT) && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) + stat &= ~ERR_STAT; + if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) { + /* Error detected */ #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 1) printk(KERN_INFO "ide-tape: %s: I/O error\n", @@ -1951,7 +1944,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) } pc->error = 0; if (test_bit(PC_WAIT_FOR_DSC, &pc->flags) && - !status.b.dsc) { + (stat & SEEK_STAT) == 0) { /* Media access command */ tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; @@ -1973,30 +1966,30 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) return ide_do_reset(drive); } /* Get the number of bytes to transfer on this interrupt. */ - bcount.b.high = hwif->INB(IDE_BCOUNTH_REG); - bcount.b.low = hwif->INB(IDE_BCOUNTL_REG); + bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | + hwif->INB(IDE_BCOUNTL_REG); - ireason.all = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(IDE_IREASON_REG); - if (ireason.b.cod) { + if (ireason & CD) { printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); return ide_do_reset(drive); } - if (ireason.b.io == test_bit(PC_WRITING, &pc->flags)) { + if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) { /* Hopefully, we will never get here */ printk(KERN_ERR "ide-tape: We wanted to %s, ", - ireason.b.io ? "Write":"Read"); + (ireason & IO) ? "Write" : "Read"); printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n", - ireason.b.io ? "Read":"Write"); + (ireason & IO) ? "Read" : "Write"); return ide_do_reset(drive); } if (!test_bit(PC_WRITING, &pc->flags)) { /* Reading - Check that we have enough space */ - temp = pc->actually_transferred + bcount.all; + temp = pc->actually_transferred + bcount; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); - idetape_discard_data(drive, bcount.all); + idetape_discard_data(drive, bcount); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; } @@ -2008,23 +2001,26 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) } if (test_bit(PC_WRITING, &pc->flags)) { if (pc->bh != NULL) - idetape_output_buffers(drive, pc, bcount.all); + idetape_output_buffers(drive, pc, bcount); else /* Write the current buffer */ - HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); + hwif->atapi_output_bytes(drive, pc->current_position, + bcount); } else { if (pc->bh != NULL) - idetape_input_buffers(drive, pc, bcount.all); + idetape_input_buffers(drive, pc, bcount); else /* Read the current buffer */ - HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); + hwif->atapi_input_bytes(drive, pc->current_position, + bcount); } /* Update the current position */ - pc->actually_transferred += bcount.all; - pc->current_position += bcount.all; + pc->actually_transferred += bcount; + pc->current_position += bcount; #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); + printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes " + "on that interrupt\n", pc->c[0], bcount); #endif /* And set the interrupt handler again */ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); @@ -2078,28 +2074,28 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; - atapi_ireason_t ireason; int retries = 100; ide_startstop_t startstop; + u8 ireason; if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all = hwif->INB(IDE_IREASON_REG); - while (retries-- && (!ireason.b.cod || ireason.b.io)) { + ireason = hwif->INB(IDE_IREASON_REG); + while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing " "a packet command, retrying\n"); udelay(100); - ireason.all = hwif->INB(IDE_IREASON_REG); + ireason = hwif->INB(IDE_IREASON_REG); if (retries == 0) { printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while " "issuing a packet command, ignoring\n"); - ireason.b.cod = 1; - ireason.b.io = 0; + ireason |= CD; + ireason &= ~IO; } } - if (!ireason.b.cod || ireason.b.io) { + if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing " "a packet command\n"); return ide_do_reset(drive); @@ -2120,8 +2116,8 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape { ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; - atapi_bcount_t bcount; int dma_ok = 0; + u16 bcount; #if IDETAPE_DEBUG_BUGS if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && @@ -2170,7 +2166,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape pc->actually_transferred = 0; pc->current_position = pc->buffer; /* Request to transfer the entire buffer at once */ - bcount.all = pc->request_transfer; + bcount = pc->request_transfer; if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { printk(KERN_WARNING "ide-tape: DMA disabled, " @@ -2180,12 +2176,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) dma_ok = !hwif->dma_setup(drive); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - hwif->OUTB(dma_ok ? 1 : 0, IDE_FEATURE_REG); /* Use PIO/DMA */ - hwif->OUTB(bcount.b.high, IDE_BCOUNTH_REG); - hwif->OUTB(bcount.b.low, IDE_BCOUNTL_REG); - hwif->OUTB(drive->select.all, IDE_SELECT_REG); + ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK | + IDE_TFLAG_OUT_DEVICE, bcount, dma_ok); + if (dma_ok) /* Will begin DMA later */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { @@ -2295,11 +2288,11 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; - atapi_status_t status; + u8 stat; - status.all = HWIF(drive)->INB(IDE_STATUS_REG); - if (status.b.dsc) { - if (status.b.check) { + stat = drive->hwif->INB(IDE_STATUS_REG); + if (stat & SEEK_STAT) { + if (stat & ERR_STAT) { /* Error detected */ if (pc->c[0] != IDETAPE_TEST_UNIT_READY_CMD) printk(KERN_ERR "ide-tape: %s: I/O error, ", @@ -2417,7 +2410,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = NULL; struct request *postponed_rq = tape->postponed_rq; - atapi_status_t status; + u8 stat; #if IDETAPE_DEBUG_LOG #if 0 @@ -2465,7 +2458,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, * If the tape is still busy, postpone our request and service * the other device meanwhile. */ - status.all = HWIF(drive)->INB(IDE_STATUS_REG); + stat = drive->hwif->INB(IDE_STATUS_REG); if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2)) set_bit(IDETAPE_IGNORE_DSC, &tape->flags); @@ -2481,7 +2474,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); calculate_speeds(drive); if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) && - !status.b.dsc) { + (stat & SEEK_STAT) == 0) { if (postponed_rq == NULL) { tape->dsc_polling_start = jiffies; tape->dsc_polling_frequency = tape->best_dsc_rw_frequency; @@ -2502,9 +2495,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } if (rq->cmd[0] & REQ_IDETAPE_READ) { tape->buffer_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); @@ -2512,9 +2502,6 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } if (rq->cmd[0] & REQ_IDETAPE_WRITE) { tape->buffer_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); @@ -3241,9 +3228,6 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) idetape_switch_buffers(tape, new_stage); idetape_add_stage_tail(drive, new_stage); tape->pipeline_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif calculate_speeds(drive); /* @@ -3493,9 +3477,6 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) idetape_remove_stage_head(drive); spin_unlock_irqrestore(&tape->spinlock, flags); tape->pipeline_head++; -#if USE_IOTRACE - IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor); -#endif calculate_speeds(drive); } #if IDETAPE_DEBUG_BUGS @@ -4724,10 +4705,8 @@ static void ide_tape_release(struct kref *kref) drive->dsc_overlap = 0; drive->driver_data = NULL; - class_device_destroy(idetape_sysfs_class, - MKDEV(IDETAPE_MAJOR, tape->minor)); - class_device_destroy(idetape_sysfs_class, - MKDEV(IDETAPE_MAJOR, tape->minor + 128)); + device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor)); + device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128)); idetape_devs[tape->minor] = NULL; g->private_data = NULL; put_disk(g); @@ -4884,10 +4863,10 @@ static int ide_tape_probe(ide_drive_t *drive) idetape_setup(drive, tape, minor); - class_device_create(idetape_sysfs_class, NULL, - MKDEV(IDETAPE_MAJOR, minor), &drive->gendev, "%s", tape->name); - class_device_create(idetape_sysfs_class, NULL, - MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name); + device_create(idetape_sysfs_class, &drive->gendev, + MKDEV(IDETAPE_MAJOR, minor), "%s", tape->name); + device_create(idetape_sysfs_class, &drive->gendev, + MKDEV(IDETAPE_MAJOR, minor + 128), "n%s", tape->name); g->fops = &idetape_block_ops; ide_register_region(g); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 2b60f1b0437e..5eb6fa15dc4d 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -35,93 +35,81 @@ #include <asm/uaccess.h> #include <asm/io.h> -static void ata_bswap_data (void *buffer, int wcount) +void ide_tf_load(ide_drive_t *drive, ide_task_t *task) { - u16 *p = buffer; - - while (wcount--) { - *p = *p << 8 | *p >> 8; p++; - *p = *p << 8 | *p >> 8; p++; - } -} - -static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount) -{ - HWIF(drive)->ata_input_data(drive, buffer, wcount); - if (drive->bswap) - ata_bswap_data(buffer, wcount); -} + ide_hwif_t *hwif = drive->hwif; + struct ide_taskfile *tf = &task->tf; + u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + HIHI = 0xFF; + +#ifdef DEBUG + printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " + "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n", + drive->name, tf->feature, tf->nsect, tf->lbal, + tf->lbam, tf->lbah, tf->device, tf->command); + printk("%s: hob: nsect 0x%02x lbal 0x%02x " + "lbam 0x%02x lbah 0x%02x\n", + drive->name, tf->hob_nsect, tf->hob_lbal, + tf->hob_lbam, tf->hob_lbah); +#endif -static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount) -{ - if (drive->bswap) { - ata_bswap_data(buffer, wcount); - HWIF(drive)->ata_output_data(drive, buffer, wcount); - ata_bswap_data(buffer, wcount); - } else { - HWIF(drive)->ata_output_data(drive, buffer, wcount); - } + ide_set_irq(drive, 1); + + if ((task->tf_flags & IDE_TFLAG_NO_SELECT_MASK) == 0) + SELECT_MASK(drive, 0); + + if (task->tf_flags & IDE_TFLAG_OUT_DATA) + hwif->OUTW((tf->hob_data << 8) | tf->data, IDE_DATA_REG); + + if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE) + hwif->OUTB(tf->hob_feature, IDE_FEATURE_REG); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT) + hwif->OUTB(tf->hob_nsect, IDE_NSECTOR_REG); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL) + hwif->OUTB(tf->hob_lbal, IDE_SECTOR_REG); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM) + hwif->OUTB(tf->hob_lbam, IDE_LCYL_REG); + if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH) + hwif->OUTB(tf->hob_lbah, IDE_HCYL_REG); + + if (task->tf_flags & IDE_TFLAG_OUT_FEATURE) + hwif->OUTB(tf->feature, IDE_FEATURE_REG); + if (task->tf_flags & IDE_TFLAG_OUT_NSECT) + hwif->OUTB(tf->nsect, IDE_NSECTOR_REG); + if (task->tf_flags & IDE_TFLAG_OUT_LBAL) + hwif->OUTB(tf->lbal, IDE_SECTOR_REG); + if (task->tf_flags & IDE_TFLAG_OUT_LBAM) + hwif->OUTB(tf->lbam, IDE_LCYL_REG); + if (task->tf_flags & IDE_TFLAG_OUT_LBAH) + hwif->OUTB(tf->lbah, IDE_HCYL_REG); + + if (task->tf_flags & IDE_TFLAG_OUT_DEVICE) + hwif->OUTB((tf->device & HIHI) | drive->select.all, IDE_SELECT_REG); } int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) { ide_task_t args; + memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_NSECTOR_OFFSET] = 0x01; + args.tf.nsect = 0x01; if (drive->media == ide_disk) - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_IDENTIFY; + args.tf.command = WIN_IDENTIFY; else - args.tfRegister[IDE_COMMAND_OFFSET] = WIN_PIDENTIFY; - args.command_type = IDE_DRIVE_TASK_IN; - args.data_phase = TASKFILE_IN; - args.handler = &task_in_intr; - return ide_raw_taskfile(drive, &args, buf); + args.tf.command = WIN_PIDENTIFY; + args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; + args.data_phase = TASKFILE_IN; + return ide_raw_taskfile(drive, &args, buf, 1); } -ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) +static int inline task_dma_ok(ide_task_t *task) { - ide_hwif_t *hwif = HWIF(drive); - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - u8 HIHI = (drive->addressing == 1) ? 0xE0 : 0xEF; - - /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ - if (IDE_CONTROL_REG) { - /* clear nIEN */ - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - } - SELECT_MASK(drive, 0); - - if (drive->addressing == 1) { - hwif->OUTB(hobfile->feature, IDE_FEATURE_REG); - hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG); - hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG); - hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG); - hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG); - } - - hwif->OUTB(taskfile->feature, IDE_FEATURE_REG); - hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); - hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG); - hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); - hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); - - hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); - - if (task->handler != NULL) { - if (task->prehandler != NULL) { - hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); - ndelay(400); /* FIXME */ - return task->prehandler(drive, task->rq); - } - ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); - return ide_started; - } + if (blk_fs_request(task->rq) || (task->tf_flags & IDE_TFLAG_FLAGGED)) + return 1; - if (!drive->using_dma) - return ide_stopped; - - switch (taskfile->command) { + switch (task->tf.command) { case WIN_WRITEDMA_ONCE: case WIN_WRITEDMA: case WIN_WRITEDMA_EXT: @@ -129,24 +117,79 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) case WIN_READDMA: case WIN_READDMA_EXT: case WIN_IDENTIFY_DMA: - if (!hwif->dma_setup(drive)) { - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); - return ide_started; - } - break; - default: - if (task->handler == NULL) - return ide_stopped; + return 1; } - return ide_stopped; + return 0; } +static ide_startstop_t task_no_data_intr(ide_drive_t *); +static ide_startstop_t set_geometry_intr(ide_drive_t *); +static ide_startstop_t recal_intr(ide_drive_t *); +static ide_startstop_t set_multmode_intr(ide_drive_t *); +static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); +static ide_startstop_t task_in_intr(ide_drive_t *); + +ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) +{ + ide_hwif_t *hwif = HWIF(drive); + struct ide_taskfile *tf = &task->tf; + ide_handler_t *handler = NULL; + + if (task->data_phase == TASKFILE_MULTI_IN || + task->data_phase == TASKFILE_MULTI_OUT) { + if (!drive->mult_count) { + printk(KERN_ERR "%s: multimode not set!\n", + drive->name); + return ide_stopped; + } + } + + if (task->tf_flags & IDE_TFLAG_FLAGGED) + task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS; + + if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) + ide_tf_load(drive, task); + + switch (task->data_phase) { + case TASKFILE_MULTI_OUT: + case TASKFILE_OUT: + hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG); + ndelay(400); /* FIXME */ + return pre_task_out_intr(drive, task->rq); + case TASKFILE_MULTI_IN: + case TASKFILE_IN: + handler = task_in_intr; + /* fall-through */ + case TASKFILE_NO_DATA: + if (handler == NULL) + handler = task_no_data_intr; + /* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */ + if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) { + switch (tf->command) { + case WIN_SPECIFY: handler = set_geometry_intr; break; + case WIN_RESTORE: handler = recal_intr; break; + case WIN_SETMULT: handler = set_multmode_intr; break; + } + } + ide_execute_command(drive, tf->command, handler, + WAIT_WORSTCASE, NULL); + return ide_started; + default: + if (task_dma_ok(task) == 0 || drive->using_dma == 0 || + hwif->dma_setup(drive)) + return ide_stopped; + hwif->dma_exec_cmd(drive, tf->command); + hwif->dma_start(drive); + return ide_started; + } +} +EXPORT_SYMBOL_GPL(do_rw_taskfile); + /* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */ -ide_startstop_t set_multmode_intr (ide_drive_t *drive) +static ide_startstop_t set_multmode_intr(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 stat; @@ -164,7 +207,7 @@ ide_startstop_t set_multmode_intr (ide_drive_t *drive) /* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */ -ide_startstop_t set_geometry_intr (ide_drive_t *drive) +static ide_startstop_t set_geometry_intr(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); int retries = 5; @@ -187,7 +230,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive) /* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */ -ide_startstop_t recal_intr (ide_drive_t *drive) +static ide_startstop_t recal_intr(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 stat; @@ -200,7 +243,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive) /* * Handler for commands without a data phase */ -ide_startstop_t task_no_data_intr (ide_drive_t *drive) +static ide_startstop_t task_no_data_intr(ide_drive_t *drive) { ide_task_t *args = HWGROUP(drive)->rq->special; ide_hwif_t *hwif = HWIF(drive); @@ -217,9 +260,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive) return ide_stopped; } -EXPORT_SYMBOL(task_no_data_intr); - -static u8 wait_drive_not_busy(ide_drive_t *drive) +u8 wait_drive_not_busy(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); int retries; @@ -227,8 +268,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) /* * Last sector was transfered, wait until drive is ready. - * This can take up to 10 usec, but we will wait max 1 ms - * (drive_cmd_intr() waits that long). + * This can take up to 10 usec, but we will wait max 1 ms. */ for (retries = 0; retries < 100; retries++) { if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) @@ -283,9 +323,9 @@ static void ide_pio_sector(ide_drive_t *drive, unsigned int write) /* do the actual data transfer */ if (write) - taskfile_output_data(drive, buf, SECTOR_WORDS); + hwif->ata_output_data(drive, buf, SECTOR_WORDS); else - taskfile_input_data(drive, buf, SECTOR_WORDS); + hwif->ata_input_data(drive, buf, SECTOR_WORDS); kunmap_atomic(buf, KM_BIO_SRC_IRQ); #ifdef CONFIG_HIGHMEM @@ -305,9 +345,18 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write) static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, unsigned int write) { + u8 saved_io_32bit = drive->io_32bit; + if (rq->bio) /* fs request */ rq->errors = 0; + if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + ide_task_t *task = rq->special; + + if (task->tf_flags & IDE_TFLAG_IO_16BIT) + drive->io_32bit = 0; + } + touch_softlockup_watchdog(); switch (drive->hwif->data_phase) { @@ -319,6 +368,8 @@ static void ide_pio_datablock(ide_drive_t *drive, struct request *rq, ide_pio_sector(drive, write); break; } + + drive->io_32bit = saved_io_32bit; } static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, @@ -356,40 +407,35 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, return ide_error(drive, s, stat); } -static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) +void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) { - HWIF(drive)->cursg = NULL; - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - ide_task_t *task = rq->special; + u8 err = drive->hwif->INB(IDE_ERROR_REG); - if (task->tf_out_flags.all) { - u8 err = drive->hwif->INB(IDE_ERROR_REG); - ide_end_drive_cmd(drive, stat, err); - return; - } + ide_end_drive_cmd(drive, stat, err); + return; } if (rq->rq_disk) { ide_driver_t *drv; drv = *(ide_driver_t **)rq->rq_disk->private_data;; - drv->end_request(drive, 1, rq->hard_nr_sectors); + drv->end_request(drive, 1, rq->nr_sectors); } else - ide_end_request(drive, 1, rq->hard_nr_sectors); + ide_end_request(drive, 1, rq->nr_sectors); } /* * Handler for command with PIO data-in phase (Read/Read Multiple). */ -ide_startstop_t task_in_intr (ide_drive_t *drive) +static ide_startstop_t task_in_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct request *rq = HWGROUP(drive)->rq; u8 stat = hwif->INB(IDE_STATUS_REG); /* new way for dealing with premature shared PCI interrupts */ - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { + if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) { if (stat & (ERR_STAT | DRQ_STAT)) return task_error(drive, rq, __FUNCTION__, stat); /* No data yet, so wait for another IRQ. */ @@ -402,7 +448,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive) /* If it was the last datablock check status and finish transfer. */ if (!hwif->nleft) { stat = wait_drive_not_busy(drive); - if (!OK_STAT(stat, 0, BAD_R_STAT)) + if (!OK_STAT(stat, 0, BAD_STAT)) return task_error(drive, rq, __FUNCTION__, stat); task_end_request(drive, rq, stat); return ide_stopped; @@ -413,7 +459,6 @@ ide_startstop_t task_in_intr (ide_drive_t *drive) return ide_started; } -EXPORT_SYMBOL(task_in_intr); /* * Handler for command with PIO data-out phase (Write/Write Multiple). @@ -443,11 +488,11 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive) return ide_started; } -ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) +static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; - if (ide_wait_stat(&startstop, drive, DATA_READY, + if (ide_wait_stat(&startstop, drive, DRQ_STAT, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", drive->name, @@ -464,9 +509,8 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) return ide_started; } -EXPORT_SYMBOL(pre_task_out_intr); -static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) +int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) { struct request rq; @@ -481,36 +525,27 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ - if (args->command_type != IDE_DRIVE_TASK_NO_DATA) { - if (data_size == 0) - rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; - else - rq.nr_sectors = data_size / SECTOR_SIZE; - - if (!rq.nr_sectors) { - printk(KERN_ERR "%s: in/out command without data\n", - drive->name); - return -EFAULT; - } + rq.hard_nr_sectors = rq.nr_sectors = nsect; + rq.hard_cur_sectors = rq.current_nr_sectors = nsect; - rq.hard_nr_sectors = rq.nr_sectors; - rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; + if (task->tf_flags & IDE_TFLAG_WRITE) + rq.cmd_flags |= REQ_RW; - if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) - rq.cmd_flags |= REQ_RW; - } + rq.special = task; + task->rq = &rq; - rq.special = args; - args->rq = &rq; return ide_do_drive_cmd(drive, &rq, ide_wait); } -int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf) +EXPORT_SYMBOL(ide_raw_taskfile); + +int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task) { - return ide_diag_taskfile(drive, args, 0, buf); -} + task->data_phase = TASKFILE_NO_DATA; -EXPORT_SYMBOL(ide_raw_taskfile); + return ide_raw_taskfile(drive, task, NULL, 0); +} +EXPORT_SYMBOL_GPL(ide_no_data_taskfile); #ifdef CONFIG_IDE_TASK_IOCTL int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) @@ -519,13 +554,12 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) ide_task_t args; u8 *outbuf = NULL; u8 *inbuf = NULL; - task_ioreg_t *argsptr = args.tfRegister; - task_ioreg_t *hobsptr = args.hobRegister; + u8 *data_buf = NULL; int err = 0; int tasksize = sizeof(struct ide_task_request_s); unsigned int taskin = 0; unsigned int taskout = 0; - u8 io_32bit = drive->io_32bit; + u16 nsect = 0; char __user *buf = (char __user *)arg; // printk("IDE Taskfile ...\n"); @@ -572,24 +606,52 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } memset(&args, 0, sizeof(ide_task_t)); - memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); - memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE); - args.tf_in_flags = req_task->in_flags; - args.tf_out_flags = req_task->out_flags; - args.data_phase = req_task->data_phase; - args.command_type = req_task->req_cmd; + memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2); + memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); + + args.data_phase = req_task->data_phase; + + args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE | + IDE_TFLAG_IN_TF; + if (drive->addressing == 1) + args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB); + + if (req_task->out_flags.all) { + args.tf_flags |= IDE_TFLAG_FLAGGED; + + if (req_task->out_flags.b.data) + args.tf_flags |= IDE_TFLAG_OUT_DATA; + + if (req_task->out_flags.b.nsector_hob) + args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT; + if (req_task->out_flags.b.sector_hob) + args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL; + if (req_task->out_flags.b.lcyl_hob) + args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM; + if (req_task->out_flags.b.hcyl_hob) + args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH; + + if (req_task->out_flags.b.error_feature) + args.tf_flags |= IDE_TFLAG_OUT_FEATURE; + if (req_task->out_flags.b.nsector) + args.tf_flags |= IDE_TFLAG_OUT_NSECT; + if (req_task->out_flags.b.sector) + args.tf_flags |= IDE_TFLAG_OUT_LBAL; + if (req_task->out_flags.b.lcyl) + args.tf_flags |= IDE_TFLAG_OUT_LBAM; + if (req_task->out_flags.b.hcyl) + args.tf_flags |= IDE_TFLAG_OUT_LBAH; + } else { + args.tf_flags |= IDE_TFLAG_OUT_TF; + if (args.tf_flags & IDE_TFLAG_LBA48) + args.tf_flags |= IDE_TFLAG_OUT_HOB; + } + + if (req_task->in_flags.b.data) + args.tf_flags |= IDE_TFLAG_IN_DATA; - drive->io_32bit = 0; switch(req_task->data_phase) { - case TASKFILE_OUT_DMAQ: - case TASKFILE_OUT_DMA: - err = ide_diag_taskfile(drive, &args, taskout, outbuf); - break; - case TASKFILE_IN_DMAQ: - case TASKFILE_IN_DMA: - err = ide_diag_taskfile(drive, &args, taskin, inbuf); - break; case TASKFILE_MULTI_OUT: if (!drive->mult_count) { /* (hs): give up if multcount is not set */ @@ -601,9 +663,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } /* fall through */ case TASKFILE_OUT: - args.prehandler = &pre_task_out_intr; - args.handler = &task_out_intr; - err = ide_diag_taskfile(drive, &args, taskout, outbuf); + /* fall through */ + case TASKFILE_OUT_DMAQ: + case TASKFILE_OUT_DMA: + nsect = taskout / SECTOR_SIZE; + data_buf = outbuf; break; case TASKFILE_MULTI_IN: if (!drive->mult_count) { @@ -616,22 +680,46 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) } /* fall through */ case TASKFILE_IN: - args.handler = &task_in_intr; - err = ide_diag_taskfile(drive, &args, taskin, inbuf); + /* fall through */ + case TASKFILE_IN_DMAQ: + case TASKFILE_IN_DMA: + nsect = taskin / SECTOR_SIZE; + data_buf = inbuf; break; case TASKFILE_NO_DATA: - args.handler = &task_no_data_intr; - err = ide_diag_taskfile(drive, &args, 0, NULL); break; default: err = -EFAULT; goto abort; } - memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE); - memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE); - req_task->in_flags = args.tf_in_flags; - req_task->out_flags = args.tf_out_flags; + if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) + nsect = 0; + else if (!nsect) { + nsect = (args.tf.hob_nsect << 8) | args.tf.nsect; + + if (!nsect) { + printk(KERN_ERR "%s: in/out command without data\n", + drive->name); + err = -EFAULT; + goto abort; + } + } + + if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) + args.tf_flags |= IDE_TFLAG_WRITE; + + err = ide_raw_taskfile(drive, &args, data_buf, nsect); + + memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2); + memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE); + + if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) && + req_task->in_flags.all == 0) { + req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; + if (drive->addressing == 1) + req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); + } if (copy_to_user(buf, req_task, tasksize)) { err = -EFAULT; @@ -658,40 +746,24 @@ abort: // printk("IDE Taskfile ioctl ended. rc = %i\n", err); - drive->io_32bit = io_32bit; - return err; } #endif -int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf) -{ - struct request rq; - u8 buffer[4]; - - if (!buf) - buf = buffer; - memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors); - ide_init_drive_cmd(&rq); - rq.buffer = buf; - *buf++ = cmd; - *buf++ = nsect; - *buf++ = feature; - *buf++ = sectors; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} - int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) { - int err = 0; - u8 args[4], *argbuf = args; - u8 xfer_rate = 0; - int argsize = 4; + u8 *buf = NULL; + int bufsize = 0, err = 0; + u8 args[4], xfer_rate = 0; ide_task_t tfargs; + struct ide_taskfile *tf = &tfargs.tf; if (NULL == (void *) arg) { struct request rq; + ide_init_drive_cmd(&rq); + rq.cmd_type = REQ_TYPE_ATA_TASKFILE; + return ide_do_drive_cmd(drive, &rq, ide_wait); } @@ -699,27 +771,40 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) return -EFAULT; memset(&tfargs, 0, sizeof(ide_task_t)); - tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2]; - tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3]; - tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1]; - tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00; - tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00; - tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00; - tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0]; + tf->feature = args[2]; + if (args[0] == WIN_SMART) { + tf->nsect = args[3]; + tf->lbal = args[1]; + tf->lbam = 0x4f; + tf->lbah = 0xc2; + tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT; + } else { + tf->nsect = args[1]; + tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE | + IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT; + } + tf->command = args[0]; + tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA; if (args[3]) { - argsize = 4 + (SECTOR_WORDS * 4 * args[3]); - argbuf = kzalloc(argsize, GFP_KERNEL); - if (argbuf == NULL) + tfargs.tf_flags |= IDE_TFLAG_IO_16BIT; + bufsize = SECTOR_WORDS * 4 * args[3]; + buf = kzalloc(bufsize, GFP_KERNEL); + if (buf == NULL) return -ENOMEM; } + if (set_transfer(drive, &tfargs)) { xfer_rate = args[1]; if (ide_ata66_check(drive, &tfargs)) goto abort; } - err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); + err = ide_raw_taskfile(drive, &tfargs, buf, args[3]); + + args[0] = tf->status; + args[1] = tf->error; + args[2] = tf->nsect; if (!err && xfer_rate) { /* active-retuning-calls future */ @@ -727,142 +812,38 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) ide_driveid_update(drive); } abort: - if (copy_to_user((void __user *)arg, argbuf, argsize)) + if (copy_to_user((void __user *)arg, &args, 4)) err = -EFAULT; - if (argsize > 4) - kfree(argbuf); + if (buf) { + if (copy_to_user((void __user *)(arg + 4), buf, bufsize)) + err = -EFAULT; + kfree(buf); + } return err; } -static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf) -{ - struct request rq; - - ide_init_drive_cmd(&rq); - rq.cmd_type = REQ_TYPE_ATA_TASK; - rq.buffer = buf; - return ide_do_drive_cmd(drive, &rq, ide_wait); -} - int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) { void __user *p = (void __user *)arg; int err = 0; - u8 args[7], *argbuf = args; - int argsize = 7; + u8 args[7]; + ide_task_t task; if (copy_from_user(args, p, 7)) return -EFAULT; - err = ide_wait_cmd_task(drive, argbuf); - if (copy_to_user(p, argbuf, argsize)) - err = -EFAULT; - return err; -} - -/* - * NOTICE: This is additions from IBM to provide a discrete interface, - * for selective taskregister access operations. Nice JOB Klaus!!! - * Glad to be able to work and co-develop this with you and IBM. - */ -ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) -{ - ide_hwif_t *hwif = HWIF(drive); - task_struct_t *taskfile = (task_struct_t *) task->tfRegister; - hob_struct_t *hobfile = (hob_struct_t *) task->hobRegister; - - if (task->data_phase == TASKFILE_MULTI_IN || - task->data_phase == TASKFILE_MULTI_OUT) { - if (!drive->mult_count) { - printk(KERN_ERR "%s: multimode not set!\n", drive->name); - return ide_stopped; - } - } - /* - * (ks) Check taskfile in flags. - * If set, then execute as it is defined. - * If not set, then define default settings. - * The default values are: - * read all taskfile registers (except data) - * read the hob registers (sector, nsector, lcyl, hcyl) - */ - if (task->tf_in_flags.all == 0) { - task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; - if (drive->addressing == 1) - task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); - } - - /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ - if (IDE_CONTROL_REG) - /* clear nIEN */ - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - SELECT_MASK(drive, 0); - - if (task->tf_out_flags.b.data) { - u16 data = taskfile->data + (hobfile->data << 8); - hwif->OUTW(data, IDE_DATA_REG); - } - - /* (ks) send hob registers first */ - if (task->tf_out_flags.b.nsector_hob) - hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG); - if (task->tf_out_flags.b.sector_hob) - hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG); - if (task->tf_out_flags.b.lcyl_hob) - hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG); - if (task->tf_out_flags.b.hcyl_hob) - hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG); - - /* (ks) Send now the standard registers */ - if (task->tf_out_flags.b.error_feature) - hwif->OUTB(taskfile->feature, IDE_FEATURE_REG); - /* refers to number of sectors to transfer */ - if (task->tf_out_flags.b.nsector) - hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); - /* refers to sector offset or start sector */ - if (task->tf_out_flags.b.sector) - hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG); - if (task->tf_out_flags.b.lcyl) - hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); - if (task->tf_out_flags.b.hcyl) - hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); - - /* - * (ks) In the flagged taskfile approch, we will use all specified - * registers and the register value will not be changed, except the - * select bit (master/slave) in the drive_head register. We must make - * sure that the desired drive is selected. - */ - hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG); - switch(task->data_phase) { + memset(&task, 0, sizeof(task)); + memcpy(&task.tf_array[7], &args[1], 6); + task.tf.command = args[0]; + task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE; - case TASKFILE_OUT_DMAQ: - case TASKFILE_OUT_DMA: - case TASKFILE_IN_DMAQ: - case TASKFILE_IN_DMA: - if (!drive->using_dma) - break; + err = ide_no_data_taskfile(drive, &task); - if (!hwif->dma_setup(drive)) { - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); - return ide_started; - } - break; + args[0] = task.tf.command; + memcpy(&args[1], &task.tf_array[7], 6); - default: - if (task->handler == NULL) - return ide_stopped; - - /* Issue the command */ - if (task->prehandler) { - hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); - ndelay(400); /* FIXME */ - return task->prehandler(drive, task->rq); - } - ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); - return ide_started; - } + if (copy_to_user(p, args, 7)) + err = -EFAULT; - return ide_stopped; + return err; } diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 54943da6e4e5..97894abd9ebc 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -95,7 +95,7 @@ DEFINE_MUTEX(ide_cfg_mtx); __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock); #ifdef CONFIG_IDEPCI_PCIBUS_ORDER -static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ +int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ #endif int noautodma = 0; @@ -116,7 +116,7 @@ EXPORT_SYMBOL(ide_hwifs); /* * Do not even *think* about calling this! */ -static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) +void ide_init_port_data(ide_hwif_t *hwif, unsigned int index) { unsigned int unit; @@ -159,6 +159,7 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) init_completion(&drive->gendev_rel_comp); } } +EXPORT_SYMBOL_GPL(ide_init_port_data); static void init_hwif_default(ide_hwif_t *hwif, unsigned int index) { @@ -177,8 +178,6 @@ static void init_hwif_default(ide_hwif_t *hwif, unsigned int index) #endif } -extern void ide_arm_init(void); - /* * init_ide_data() sets reasonable default values into all fields * of all instances of the hwifs and drives, but only on the first call. @@ -210,16 +209,13 @@ static void __init init_ide_data (void) /* Initialise all interface structures */ for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; - init_hwif_data(hwif, index); + ide_init_port_data(hwif, index); init_hwif_default(hwif, index); #if !defined(CONFIG_PPC32) || !defined(CONFIG_PCI) hwif->irq = ide_init_default_irq(hwif->io_ports[IDE_DATA_OFFSET]); #endif } -#ifdef CONFIG_IDE_ARM - ide_arm_init(); -#endif } /** @@ -414,8 +410,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->cds = tmp_hwif->cds; #endif - hwif->fixup = tmp_hwif->fixup; - hwif->set_pio_mode = tmp_hwif->set_pio_mode; hwif->set_dma_mode = tmp_hwif->set_dma_mode; hwif->mdma_filter = tmp_hwif->mdma_filter; @@ -424,7 +418,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->reset_poll = tmp_hwif->reset_poll; hwif->pre_reset = tmp_hwif->pre_reset; hwif->resetproc = tmp_hwif->resetproc; - hwif->intrproc = tmp_hwif->intrproc; hwif->maskproc = tmp_hwif->maskproc; hwif->quirkproc = tmp_hwif->quirkproc; hwif->busproc = tmp_hwif->busproc; @@ -434,16 +427,13 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes; hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes; + hwif->dma_host_set = tmp_hwif->dma_host_set; hwif->dma_setup = tmp_hwif->dma_setup; hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd; hwif->dma_start = tmp_hwif->dma_start; hwif->ide_dma_end = tmp_hwif->ide_dma_end; - hwif->ide_dma_on = tmp_hwif->ide_dma_on; - hwif->dma_off_quietly = tmp_hwif->dma_off_quietly; hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; - hwif->dma_host_on = tmp_hwif->dma_host_on; - hwif->dma_host_off = tmp_hwif->dma_host_off; hwif->dma_lost_irq = tmp_hwif->dma_lost_irq; hwif->dma_timeout = tmp_hwif->dma_timeout; @@ -468,7 +458,6 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) #endif hwif->dma_base = tmp_hwif->dma_base; - hwif->dma_master = tmp_hwif->dma_master; hwif->dma_command = tmp_hwif->dma_command; hwif->dma_vendor1 = tmp_hwif->dma_vendor1; hwif->dma_status = tmp_hwif->dma_status; @@ -602,7 +591,6 @@ void ide_unregister(unsigned int index) (void) ide_release_dma(hwif); hwif->dma_base = 0; - hwif->dma_master = 0; hwif->dma_command = 0; hwif->dma_vendor1 = 0; hwif->dma_status = 0; @@ -617,7 +605,7 @@ void ide_unregister(unsigned int index) tmp_hwif = *hwif; /* restore hwif data to pristine status */ - init_hwif_data(hwif, index); + ide_init_port_data(hwif, index); init_hwif_default(hwif, index); ide_hwif_restore(hwif, &tmp_hwif); @@ -683,24 +671,34 @@ void ide_setup_ports ( hw_regs_t *hw, */ } +void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) +{ + memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports)); + hwif->irq = hw->irq; + hwif->noprobe = 0; + hwif->chipset = hw->chipset; + hwif->gendev.parent = hw->dev; + hwif->ack_intr = hw->ack_intr; +} +EXPORT_SYMBOL_GPL(ide_init_port_hw); + /** * ide_register_hw - register IDE interface * @hw: hardware registers - * @fixup: fixup function - * @initializing: set while initializing built-in drivers + * @quirkproc: quirkproc function * @hwifp: pointer to returned hwif * * Register an IDE interface, specifying exactly the registers etc. - * Set init=1 iff calling before probes have taken place. * * Returns -1 on error. */ -int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *), - int initializing, ide_hwif_t **hwifp) +int ide_register_hw(hw_regs_t *hw, void (*quirkproc)(ide_drive_t *), + ide_hwif_t **hwifp) { int index, retry = 1; ide_hwif_t *hwif; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; do { for (index = 0; index < MAX_HWIFS; ++index) { @@ -712,8 +710,7 @@ int ide_register_hw(hw_regs_t *hw, void (*fixup)(ide_hwif_t *), hwif = &ide_hwifs[index]; if (hwif->hold) continue; - if ((!hwif->present && !hwif->mate && !initializing) || - (!hwif->io_ports[IDE_DATA_OFFSET] && initializing)) + if (!hwif->present && hwif->mate == NULL) goto found; } for (index = 0; index < MAX_HWIFS; index++) @@ -724,29 +721,23 @@ found: if (hwif->present) ide_unregister(index); else if (!hwif->hold) { - init_hwif_data(hwif, index); + ide_init_port_data(hwif, index); init_hwif_default(hwif, index); } if (hwif->present) return -1; - memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports)); - hwif->irq = hw->irq; - hwif->noprobe = 0; - hwif->fixup = fixup; - hwif->chipset = hw->chipset; - hwif->gendev.parent = hw->dev; - hwif->ack_intr = hw->ack_intr; - if (initializing == 0) { - u8 idx[4] = { index, 0xff, 0xff, 0xff }; + ide_init_port_hw(hwif, hw); + hwif->quirkproc = quirkproc; - ide_device_add(idx); - } + idx[0] = index; + + ide_device_add(idx); if (hwifp) *hwifp = hwif; - return (initializing || hwif->present) ? index : -1; + return hwif->present ? index : -1; } EXPORT_SYMBOL(ide_register_hw); @@ -839,7 +830,7 @@ int set_using_dma(ide_drive_t *drive, int arg) if (!drive->id || !(drive->id->capability & 1)) goto out; - if (hwif->ide_dma_on == NULL) + if (hwif->dma_host_set == NULL) goto out; err = -EBUSY; @@ -854,8 +845,7 @@ int set_using_dma(ide_drive_t *drive, int arg) err = 0; if (arg) { - hwif->dma_off_quietly(drive); - if (ide_set_dma(drive) || hwif->ide_dma_on(drive)) + if (ide_set_dma(drive)) err = -EIO; } else ide_dma_off(drive); @@ -888,7 +878,10 @@ int set_pio_mode(ide_drive_t *drive, int arg) if (drive->special.b.set_tune) return -EBUSY; + ide_init_drive_cmd(&rq); + rq.cmd_type = REQ_TYPE_ATA_TASKFILE; + drive->tune_req = (u8) arg; drive->special.b.set_tune = 1; (void) ide_do_drive_cmd(drive, &rq, ide_wait); @@ -1070,7 +1063,7 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device ide_init_hwif_ports(&hw, (unsigned long) args[0], (unsigned long) args[1], NULL); hw.irq = args[2]; - if (ide_register_hw(&hw, NULL, 0, NULL) == -1) + if (ide_register_hw(&hw, NULL, NULL) == -1) return -EIO; return 0; } @@ -1231,26 +1224,12 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m return 0; /* zero = nothing matched */ } -#ifdef CONFIG_BLK_DEV_ALI14XX extern int probe_ali14xx; -extern int ali14xx_init(void); -#endif -#ifdef CONFIG_BLK_DEV_UMC8672 extern int probe_umc8672; -extern int umc8672_init(void); -#endif -#ifdef CONFIG_BLK_DEV_DTC2278 extern int probe_dtc2278; -extern int dtc2278_init(void); -#endif -#ifdef CONFIG_BLK_DEV_HT6560B extern int probe_ht6560b; -extern int ht6560b_init(void); -#endif -#ifdef CONFIG_BLK_DEV_QD65XX extern int probe_qd65xx; -extern int qd65xx_init(void); -#endif +extern int cmd640_vlb; static int __initdata is_chipset_set[MAX_HWIFS]; @@ -1327,7 +1306,7 @@ static int __init ide_setup(char *s) if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { const char *hd_words[] = { "none", "noprobe", "nowerr", "cdrom", "nodma", - "autotune", "noautotune", "minus8", "swapdata", "bswap", + "autotune", "noautotune", "-8", "-9", "-10", "noflush", "remap", "remap63", "scsi", NULL }; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; @@ -1363,10 +1342,6 @@ static int __init ide_setup(char *s) case -7: /* "noautotune" */ drive->autotune = IDE_TUNE_NOAUTO; goto obsolete_option; - case -9: /* "swapdata" */ - case -10: /* "bswap" */ - drive->bswap = 1; - goto done; case -11: /* noflush */ drive->noflush = 1; goto done; @@ -1466,11 +1441,8 @@ static int __init ide_setup(char *s) #endif #ifdef CONFIG_BLK_DEV_CMD640 case -14: /* "cmd640_vlb" */ - { - extern int cmd640_vlb; /* flag for cmd640.c */ cmd640_vlb = 1; goto done; - } #endif #ifdef CONFIG_BLK_DEV_HT6560B case -13: /* "ht6560b" */ @@ -1560,79 +1532,6 @@ done: return 1; } -extern void __init pnpide_init(void); -extern void __exit pnpide_exit(void); -extern void __init h8300_ide_init(void); - -/* - * probe_for_hwifs() finds/initializes "known" IDE interfaces - */ -static void __init probe_for_hwifs (void) -{ -#ifdef CONFIG_IDEPCI_PCIBUS_ORDER - ide_scan_pcibus(ide_scan_direction); -#endif - -#ifdef CONFIG_ETRAX_IDE - { - extern void init_e100_ide(void); - init_e100_ide(); - } -#endif /* CONFIG_ETRAX_IDE */ -#ifdef CONFIG_BLK_DEV_CMD640 - { - extern void ide_probe_for_cmd640x(void); - ide_probe_for_cmd640x(); - } -#endif /* CONFIG_BLK_DEV_CMD640 */ -#ifdef CONFIG_BLK_DEV_IDE_PMAC - { - extern int pmac_ide_probe(void); - (void)pmac_ide_probe(); - } -#endif /* CONFIG_BLK_DEV_IDE_PMAC */ -#ifdef CONFIG_BLK_DEV_GAYLE - { - extern void gayle_init(void); - gayle_init(); - } -#endif /* CONFIG_BLK_DEV_GAYLE */ -#ifdef CONFIG_BLK_DEV_FALCON_IDE - { - extern void falconide_init(void); - falconide_init(); - } -#endif /* CONFIG_BLK_DEV_FALCON_IDE */ -#ifdef CONFIG_BLK_DEV_MAC_IDE - { - extern void macide_init(void); - macide_init(); - } -#endif /* CONFIG_BLK_DEV_MAC_IDE */ -#ifdef CONFIG_BLK_DEV_Q40IDE - { - extern void q40ide_init(void); - q40ide_init(); - } -#endif /* CONFIG_BLK_DEV_Q40IDE */ -#ifdef CONFIG_BLK_DEV_BUDDHA - { - extern void buddha_init(void); - buddha_init(); - } -#endif /* CONFIG_BLK_DEV_BUDDHA */ -#ifdef CONFIG_BLK_DEV_IDEPNP - pnpide_init(); -#endif -#ifdef CONFIG_H8300 - h8300_ide_init(); -#endif -} - -/* - * Probe module - */ - EXPORT_SYMBOL(ide_lock); static int ide_bus_match(struct device *dev, struct device_driver *drv) @@ -1779,30 +1678,6 @@ static int __init ide_init(void) proc_ide_create(); -#ifdef CONFIG_BLK_DEV_ALI14XX - if (probe_ali14xx) - (void)ali14xx_init(); -#endif -#ifdef CONFIG_BLK_DEV_UMC8672 - if (probe_umc8672) - (void)umc8672_init(); -#endif -#ifdef CONFIG_BLK_DEV_DTC2278 - if (probe_dtc2278) - (void)dtc2278_init(); -#endif -#ifdef CONFIG_BLK_DEV_HT6560B - if (probe_ht6560b) - (void)ht6560b_init(); -#endif -#ifdef CONFIG_BLK_DEV_QD65XX - if (probe_qd65xx) - (void)qd65xx_init(); -#endif - - /* Probe for special PCI and other "known" interface chipsets. */ - probe_for_hwifs(); - return 0; } @@ -1838,10 +1713,6 @@ void __exit cleanup_module (void) for (index = 0; index < MAX_HWIFS; ++index) ide_unregister(index); -#ifdef CONFIG_BLK_DEV_IDEPNP - pnpide_exit(); -#endif - proc_ide_destroy(); bus_unregister(&ide_bus_type); diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile index 409822349f10..7043ec7d1e05 100644 --- a/drivers/ide/legacy/Makefile +++ b/drivers/ide/legacy/Makefile @@ -1,15 +1,24 @@ +# link order is important here + obj-$(CONFIG_BLK_DEV_ALI14XX) += ali14xx.o +obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o obj-$(CONFIG_BLK_DEV_DTC2278) += dtc2278.o obj-$(CONFIG_BLK_DEV_HT6560B) += ht6560b.o obj-$(CONFIG_BLK_DEV_QD65XX) += qd65xx.o -obj-$(CONFIG_BLK_DEV_UMC8672) += umc8672.o -obj-$(CONFIG_BLK_DEV_IDECS) += ide-cs.o +obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o +obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o +obj-$(CONFIG_BLK_DEV_MAC_IDE) += macide.o +obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o +obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o -obj-$(CONFIG_BLK_DEV_PLATFORM) += ide_platform.o +ifeq ($(CONFIG_BLK_DEV_IDECS), m) + obj-m += ide-cs.o +endif -# Last of all -obj-$(CONFIG_BLK_DEV_HD) += hd.o +ifeq ($(CONFIG_BLK_DEV_PLATFORM), m) + obj-m += ide_platform.o +endif EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c index 38c3a6d63f30..5ec0be4cbad7 100644 --- a/drivers/ide/legacy/ali14xx.c +++ b/drivers/ide/legacy/ali14xx.c @@ -231,8 +231,7 @@ int probe_ali14xx = 0; module_param_named(probe, probe_ali14xx, bool, 0); MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets"); -/* Can be called directly from ide.c. */ -int __init ali14xx_init(void) +static int __init ali14xx_init(void) { if (probe_ali14xx == 0) goto out; @@ -248,9 +247,7 @@ out: return -ENODEV; } -#ifdef MODULE module_init(ali14xx_init); -#endif MODULE_AUTHOR("see local file"); MODULE_DESCRIPTION("support of ALI 14XX IDE chipsets"); diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c index 4a0be251a05f..74d28e058f55 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/legacy/buddha.c @@ -112,6 +112,7 @@ typedef enum BuddhaType_Enum { BOARD_BUDDHA, BOARD_CATWEASEL, BOARD_XSURF } BuddhaType; +static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" }; /* * Check and acknowledge the interrupt status @@ -143,11 +144,11 @@ static int xsurf_ack_intr(ide_hwif_t *hwif) * Probe for a Buddha or Catweasel IDE interface */ -void __init buddha_init(void) +static int __init buddha_init(void) { hw_regs_t hw; ide_hwif_t *hwif; - int i, index; + int i; struct zorro_dev *z = NULL; u_long buddha_board = 0; @@ -156,6 +157,8 @@ void __init buddha_init(void) while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { unsigned long board; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; + if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) { buddha_num_hwifs = BUDDHA_NUM_HWIFS; type=BOARD_BUDDHA; @@ -195,7 +198,10 @@ fail_base2: /* X-Surf doesn't have this. IRQs are always on */ if (type != BOARD_XSURF) z_writeb(0, buddha_board+BUDDHA_IRQ_MR); - + + printk(KERN_INFO "ide: %s IDE controller\n", + buddha_board_name[type]); + for(i=0;i<buddha_num_hwifs;i++) { if(type != BOARD_XSURF) { ide_setup_ports(&hw, (buddha_board+buddha_bases[i]), @@ -213,23 +219,23 @@ fail_base2: IRQ_AMIGA_PORTS); } - index = ide_register_hw(&hw, NULL, 1, &hwif); - if (index != -1) { + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif) { + u8 index = hwif->index; + + ide_init_port_data(hwif, index); + ide_init_port_hw(hwif, &hw); + hwif->mmio = 1; - printk("ide%d: ", index); - switch(type) { - case BOARD_BUDDHA: - printk("Buddha"); - break; - case BOARD_CATWEASEL: - printk("Catweasel"); - break; - case BOARD_XSURF: - printk("X-Surf"); - break; - } - printk(" IDE interface\n"); - } + + idx[i] = index; + } } + + ide_device_add(idx); } + + return 0; } + +module_init(buddha_init); diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c index 24a845d45bd2..13eee6da2806 100644 --- a/drivers/ide/legacy/dtc2278.c +++ b/drivers/ide/legacy/dtc2278.c @@ -150,8 +150,7 @@ int probe_dtc2278 = 0; module_param_named(probe, probe_dtc2278, bool, 0); MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets"); -/* Can be called directly from ide.c. */ -int __init dtc2278_init(void) +static int __init dtc2278_init(void) { if (probe_dtc2278 == 0) return -ENODEV; @@ -163,9 +162,7 @@ int __init dtc2278_init(void) return 0; } -#ifdef MODULE module_init(dtc2278_init); -#endif MODULE_AUTHOR("See Local File"); MODULE_DESCRIPTION("support of DTC-2278 VLB IDE chipsets"); diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index 7d7936f1b900..2860956bdcb0 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -62,19 +62,31 @@ EXPORT_SYMBOL(falconide_intr_lock); * Probe for a Falcon IDE interface */ -void __init falconide_init(void) +static int __init falconide_init(void) { if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { hw_regs_t hw; - int index; + + printk(KERN_INFO "ide: Falcon IDE controller\n"); ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets, 0, 0, NULL, // falconide_iops, IRQ_MFP_IDE); - index = ide_register_hw(&hw, NULL, 1, NULL); - if (index != -1) - printk("ide%d: Falcon IDE interface\n", index); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif) { + u8 index = hwif->index; + u8 idx[4] = { index, 0xff, 0xff, 0xff }; + + ide_init_port_data(hwif, index); + ide_init_port_hw(hwif, &hw); + + ide_device_add(idx); + } } + + return 0; } + +module_init(falconide_init); diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index 53331ee1e957..492fa047efc0 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -110,12 +110,13 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif) * Probe for a Gayle IDE interface (and optionally for an IDE doubler) */ -void __init gayle_init(void) +static int __init gayle_init(void) { int a4000, i; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; if (!MACH_IS_AMIGA) - return; + return -ENODEV; if ((a4000 = AMIGAHW_PRESENT(A4000_IDE)) || AMIGAHW_PRESENT(A1200_IDE)) goto found; @@ -125,15 +126,21 @@ void __init gayle_init(void) NULL)) goto found; #endif - return; + return -ENODEV; found: + printk(KERN_INFO "ide: Gayle IDE controller (A%d style%s)\n", + a4000 ? 4000 : 1200, +#ifdef CONFIG_BLK_DEV_IDEDOUBLER + ide_doubler ? ", IDE doubler" : +#endif + ""); + for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) { unsigned long base, ctrlport, irqport; ide_ack_intr_t *ack_intr; hw_regs_t hw; ide_hwif_t *hwif; - int index; unsigned long phys_base, res_start, res_n; if (a4000) { @@ -165,21 +172,23 @@ found: // &gayle_iops, IRQ_AMIGA_PORTS); - index = ide_register_hw(&hw, NULL, 1, &hwif); - if (index != -1) { + hwif = ide_find_port(base); + if (hwif) { + u8 index = hwif->index; + + ide_init_port_data(hwif, index); + ide_init_port_hw(hwif, &hw); + hwif->mmio = 1; - switch (i) { - case 0: - printk("ide%d: Gayle IDE interface (A%d style)\n", index, - a4000 ? 4000 : 1200); - break; -#ifdef CONFIG_BLK_DEV_IDEDOUBLER - case 1: - printk("ide%d: IDE doubler\n", index); - break; -#endif /* CONFIG_BLK_DEV_IDEDOUBLER */ - } + + idx[i] = index; } else release_mem_region(res_start, res_n); } + + ide_device_add(idx); + + return 0; } + +module_init(gayle_init); diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index a4245d13f11b..8da5031a6d05 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -307,8 +307,7 @@ int probe_ht6560b = 0; module_param_named(probe, probe_ht6560b, bool, 0); MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); -/* Can be called directly from ide.c. */ -int __init ht6560b_init(void) +static int __init ht6560b_init(void) { ide_hwif_t *hwif, *mate; static u8 idx[4] = { 0, 1, 0xff, 0xff }; @@ -369,9 +368,7 @@ release_region: return -ENODEV; } -#ifdef MODULE module_init(ht6560b_init); -#endif MODULE_AUTHOR("See Local File"); MODULE_DESCRIPTION("HT-6560B EIDE-controller support"); diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index 03715c058664..f4ea15b32969 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -153,7 +153,7 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq hw.irq = irq; hw.chipset = ide_pci; hw.dev = &handle->dev; - return ide_register_hw(&hw, &ide_undecoded_slave, 0, NULL); + return ide_register_hw(&hw, &ide_undecoded_slave, NULL); } /*====================================================================== diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c index 7bb79f53dac8..69a0fb0e564f 100644 --- a/drivers/ide/legacy/ide_platform.c +++ b/drivers/ide/legacy/ide_platform.c @@ -28,39 +28,27 @@ static struct { int index; } hwif_prop; -static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base, - void __iomem *ctrl, struct pata_platform_info *pdata, int irq, - int mmio) +static void __devinit plat_ide_setup_ports(hw_regs_t *hw, + void __iomem *base, + void __iomem *ctrl, + struct pata_platform_info *pdata, + int irq) { unsigned long port = (unsigned long)base; - ide_hwif_t *hwif = ide_find_port(port); int i; - if (hwif == NULL) - goto out; - - hwif->io_ports[IDE_DATA_OFFSET] = port; + hw->io_ports[IDE_DATA_OFFSET] = port; port += (1 << pdata->ioport_shift); for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++, port += (1 << pdata->ioport_shift)) - hwif->io_ports[i] = port; - - hwif->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; + hw->io_ports[i] = port; - hwif->irq = irq; + hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl; - hwif->chipset = ide_generic; + hw->irq = irq; - if (mmio) { - hwif->mmio = 1; - default_hwif_mmiops(hwif); - } - - hwif_prop.hwif = hwif; - hwif_prop.index = hwif->index; -out: - return hwif; + hw->chipset = ide_generic; } static int __devinit plat_ide_probe(struct platform_device *pdev) @@ -71,6 +59,7 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; int ret = 0; int mmio = 0; + hw_regs_t hw; pdata = pdev->dev.platform_data; @@ -106,15 +95,27 @@ static int __devinit plat_ide_probe(struct platform_device *pdev) res_alt->start, res_alt->end - res_alt->start + 1); } - hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase, - hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio); - + hwif = ide_find_port((unsigned long)hwif_prop.plat_ide_mapbase); if (!hwif) { ret = -ENODEV; goto out; } - hwif->gendev.parent = &pdev->dev; - hwif->noprobe = 0; + + memset(&hw, 0, sizeof(hw)); + plat_ide_setup_ports(&hw, hwif_prop.plat_ide_mapbase, + hwif_prop.plat_ide_alt_mapbase, + pdata, res_irq->start); + hw.dev = &pdev->dev; + + ide_init_port_hw(hwif, &hw); + + if (mmio) { + hwif->mmio = 1; + default_hwif_mmiops(hwif); + } + + hwif_prop.hwif = hwif; + hwif_prop.index = hwif->index; idx[0] = hwif->index; diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index 5c6aa77c2370..782d4c76c0e5 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -77,15 +77,17 @@ int macide_ack_intr(ide_hwif_t* hwif) return 0; } +static const char *mac_ide_name[] = + { "Quadra", "Powerbook", "Powerbook Baboon" }; + /* * Probe for a Macintosh IDE interface */ -void __init macide_init(void) +static int __init macide_init(void) { hw_regs_t hw; ide_hwif_t *hwif; - int index = -1; switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: @@ -93,48 +95,50 @@ void __init macide_init(void) 0, 0, macide_ack_intr, // quadra_ide_iops, IRQ_NUBUS_F); - index = ide_register_hw(&hw, NULL, 1, &hwif); break; case MAC_IDE_PB: ide_setup_ports(&hw, IDE_BASE, macide_offsets, 0, 0, macide_ack_intr, // macide_pb_iops, IRQ_NUBUS_C); - index = ide_register_hw(&hw, NULL, 1, &hwif); break; case MAC_IDE_BABOON: ide_setup_ports(&hw, BABOON_BASE, macide_offsets, 0, 0, NULL, // macide_baboon_iops, IRQ_BABOON_1); - index = ide_register_hw(&hw, NULL, 1, &hwif); - if (index == -1) break; - if (macintosh_config->ident == MAC_MODEL_PB190) { + break; + default: + return -ENODEV; + } + + printk(KERN_INFO "ide: Macintosh %s IDE controller\n", + mac_ide_name[macintosh_config->ide_type - 1]); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif) { + u8 index = hwif->index; + u8 idx[4] = { index, 0xff, 0xff, 0xff }; + + ide_init_port_data(hwif, index); + ide_init_port_hw(hwif, &hw); + + if (macintosh_config->ide_type == MAC_IDE_BABOON && + macintosh_config->ident == MAC_MODEL_PB190) { /* Fix breakage in ide-disk.c: drive capacity */ /* is not initialized for drives without a */ /* hardware ID, and we can't get that without */ /* probing the drive which freezes a 190. */ - - ide_drive_t *drive = &ide_hwifs[index].drives[0]; + ide_drive_t *drive = &hwif->drives[0]; drive->capacity64 = drive->cyl*drive->head*drive->sect; - } - break; - - default: - return; - } - if (index != -1) { hwif->mmio = 1; - if (macintosh_config->ide_type == MAC_IDE_QUADRA) - printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index); - else if (macintosh_config->ide_type == MAC_IDE_PB) - printk(KERN_INFO "ide%d: Macintosh Powerbook IDE interface\n", index); - else if (macintosh_config->ide_type == MAC_IDE_BABOON) - printk(KERN_INFO "ide%d: Macintosh Powerbook Baboon IDE interface\n", index); - else - printk(KERN_INFO "ide%d: Unknown Macintosh IDE interface\n", index); + + ide_device_add(idx); } + + return 0; } + +module_init(macide_init); diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index 6ea46a6723e2..f5329730df99 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -111,15 +111,17 @@ static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={ * Probe for Q40 IDE interfaces */ -void __init q40ide_init(void) +static int __init q40ide_init(void) { int i; ide_hwif_t *hwif; - int index; const char *name; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; if (!MACH_IS_Q40) - return ; + return -ENODEV; + + printk(KERN_INFO "ide: Q40 IDE controller\n"); for (i = 0; i < Q40IDE_NUM_HWIFS; i++) { hw_regs_t hw; @@ -141,10 +143,20 @@ void __init q40ide_init(void) 0, NULL, // m68kide_iops, q40ide_default_irq(pcide_bases[i])); - index = ide_register_hw(&hw, NULL, 1, &hwif); - // **FIXME** - if (index != -1) + + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); + if (hwif) { + ide_init_port_data(hwif, hwif->index); + ide_init_port_hw(hwif, &hw); hwif->mmio = 1; + + idx[i] = hwif->index; + } } + + ide_device_add(idx); + + return 0; } +module_init(q40ide_init); diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c index 912e73853faa..2bac4c1a6532 100644 --- a/drivers/ide/legacy/qd65xx.c +++ b/drivers/ide/legacy/qd65xx.c @@ -478,8 +478,7 @@ int probe_qd65xx = 0; module_param_named(probe, probe_qd65xx, bool, 0); MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); -/* Can be called directly from ide.c. */ -int __init qd65xx_init(void) +static int __init qd65xx_init(void) { if (probe_qd65xx == 0) return -ENODEV; @@ -492,9 +491,7 @@ int __init qd65xx_init(void) return 0; } -#ifdef MODULE module_init(qd65xx_init); -#endif MODULE_AUTHOR("Samuel Thibault"); MODULE_DESCRIPTION("support of qd65xx vlb ide chipset"); diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c index 79577b916874..a1ae1ae6699d 100644 --- a/drivers/ide/legacy/umc8672.c +++ b/drivers/ide/legacy/umc8672.c @@ -169,8 +169,7 @@ int probe_umc8672 = 0; module_param_named(probe, probe_umc8672, bool, 0); MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); -/* Can be called directly from ide.c. */ -int __init umc8672_init(void) +static int __init umc8672_init(void) { if (probe_umc8672 == 0) goto out; @@ -181,9 +180,7 @@ out: return -ENODEV;; } -#ifdef MODULE module_init(umc8672_init); -#endif MODULE_AUTHOR("Wolfram Podien"); MODULE_DESCRIPTION("Support for UMC 8672 IDE chipset"); diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index a4ce3ba15d61..2d3e5115b834 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -198,8 +198,6 @@ static void auide_set_dma_mode(ide_drive_t *drive, const u8 speed) break; #endif - default: - return; } au_writel(mem_sttime,MEM_STTIME2); @@ -397,26 +395,10 @@ static int auide_dma_test_irq(ide_drive_t *drive) return 0; } -static void auide_dma_host_on(ide_drive_t *drive) -{ -} - -static int auide_dma_on(ide_drive_t *drive) -{ - drive->using_dma = 1; - - return 0; -} - -static void auide_dma_host_off(ide_drive_t *drive) +static void auide_dma_host_set(ide_drive_t *drive, int on) { } -static void auide_dma_off_quietly(ide_drive_t *drive) -{ - drive->using_dma = 0; -} - static void auide_dma_lost_irq(ide_drive_t *drive) { printk(KERN_ERR "%s: IRQ lost\n", drive->name); @@ -643,12 +625,13 @@ static int au_ide_probe(struct device *dev) /* FIXME: This might possibly break PCMCIA IDE devices */ hwif = &ide_hwifs[pdev->id]; - hwif->irq = ahwif->irq; - hwif->chipset = ide_au1xxx; memset(&hw, 0, sizeof(hw)); auide_setup_ports(&hw, ahwif); - memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports)); + hw.irq = ahwif->irq; + hw.chipset = ide_au1xxx; + + ide_init_port_hw(hwif, &hw); hwif->ultra_mask = 0x0; /* Disable Ultra DMA */ #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA @@ -662,7 +645,6 @@ static int au_ide_probe(struct device *dev) hwif->pio_mask = ATA_PIO4; hwif->host_flags = IDE_HFLAG_POST_SET_MODE; - hwif->noprobe = 0; hwif->drives[0].unmask = 1; hwif->drives[1].unmask = 1; @@ -684,29 +666,25 @@ static int au_ide_probe(struct device *dev) hwif->set_dma_mode = &auide_set_dma_mode; #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - hwif->dma_off_quietly = &auide_dma_off_quietly; hwif->dma_timeout = &auide_dma_timeout; hwif->mdma_filter = &auide_mdma_filter; + hwif->dma_host_set = &auide_dma_host_set; hwif->dma_exec_cmd = &auide_dma_exec_cmd; hwif->dma_start = &auide_dma_start; hwif->ide_dma_end = &auide_dma_end; hwif->dma_setup = &auide_dma_setup; hwif->ide_dma_test_irq = &auide_dma_test_irq; - hwif->dma_host_off = &auide_dma_host_off; - hwif->dma_host_on = &auide_dma_host_on; hwif->dma_lost_irq = &auide_dma_lost_irq; - hwif->ide_dma_on = &auide_dma_on; -#else /* !CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */ +#endif hwif->channel = 0; - hwif->hold = 1; hwif->select_data = 0; /* no chipset-specific code */ hwif->config_data = 0; /* no chipset-specific code */ hwif->drives[0].autotune = 1; /* 1=autotune, 2=noautotune, 0=default */ hwif->drives[1].autotune = 1; -#endif + hwif->drives[0].no_io_32bit = 1; hwif->drives[1].no_io_32bit = 1; diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c index 521edd41b572..8b3959dfa2b7 100644 --- a/drivers/ide/mips/swarm.c +++ b/drivers/ide/mips/swarm.c @@ -117,6 +117,7 @@ static int __devinit swarm_ide_probe(struct device *dev) default_hwif_mmiops(hwif); /* Prevent resource map manipulation. */ hwif->mmio = 1; + hwif->chipset = ide_generic; hwif->noprobe = 0; for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index 95d1ea8f1f14..94803253e8af 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -36,4 +36,8 @@ obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o # Must appear at the end of the block obj-$(CONFIG_BLK_DEV_GENERIC) += generic.o +ifeq ($(CONFIG_BLK_DEV_CMD640), m) + obj-m += cmd640.o +endif + EXTRA_CFLAGS := -Idrivers/ide diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c index 44268504ae43..7f4d1857d555 100644 --- a/drivers/ide/pci/aec62xx.c +++ b/drivers/ide/pci/aec62xx.c @@ -202,6 +202,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, @@ -211,6 +212,7 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_NO_AUTODMA | + IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, @@ -220,7 +222,8 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_ABUSE_SET_DMA_MODE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA4, @@ -228,7 +231,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .name = "AEC6280", .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_ABUSE_SET_DMA_MODE | + IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -237,7 +242,9 @@ static const struct ide_port_info aec62xx_chipsets[] __devinitdata = { .init_chipset = init_chipset_aec62xx, .init_hwif = init_hwif_aec62xx, .enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAG_NO_ATAPI_DMA | + IDE_HFLAG_ABUSE_SET_DMA_MODE | + IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index ce293936af4b..49aa82e412b6 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -402,9 +402,6 @@ static void ali_set_dma_mode(ide_drive_t *drive, const u8 speed) u8 tmpbyte = 0x00; int m5229_udma = (hwif->channel) ? 0x57 : 0x56; - if (speed < XFER_PIO_0) - return; - if (speed == XFER_UDMA_6) speed1 = 0x47; diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 8d4125ec252c..cee51fdafcf6 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -266,6 +266,7 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif) #define IDE_HFLAGS_AMD \ (IDE_HFLAG_PIO_NO_BLACKLIST | \ IDE_HFLAG_PIO_NO_DOWNGRADE | \ + IDE_HFLAG_ABUSE_SET_DMA_MODE | \ IDE_HFLAG_POST_SET_MODE | \ IDE_HFLAG_IO_32BIT | \ IDE_HFLAG_UNMASK_IRQS | \ diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c index ef8e0164ef7a..491871984aaa 100644 --- a/drivers/ide/pci/atiixp.c +++ b/drivers/ide/pci/atiixp.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/atiixp.c Version 0.03 Aug 3 2007 + * linux/drivers/ide/pci/atiixp.c Version 0.05 Nov 9 2007 * * Copyright (C) 2003 ATI Inc. <hyu@ati.com> * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz @@ -43,47 +43,8 @@ static atiixp_ide_timing mdma_timing[] = { { 0x02, 0x00 }, }; -static int save_mdma_mode[4]; - static DEFINE_SPINLOCK(atiixp_lock); -static void atiixp_dma_host_on(ide_drive_t *drive) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - unsigned long flags; - u16 tmp16; - - spin_lock_irqsave(&atiixp_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); - if (save_mdma_mode[drive->dn]) - tmp16 &= ~(1 << drive->dn); - else - tmp16 |= (1 << drive->dn); - pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); - - spin_unlock_irqrestore(&atiixp_lock, flags); - - ide_dma_host_on(drive); -} - -static void atiixp_dma_host_off(ide_drive_t *drive) -{ - struct pci_dev *dev = drive->hwif->pci_dev; - unsigned long flags; - u16 tmp16; - - spin_lock_irqsave(&atiixp_lock, flags); - - pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &tmp16); - tmp16 &= ~(1 << drive->dn); - pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, tmp16); - - spin_unlock_irqrestore(&atiixp_lock, flags); - - ide_dma_host_off(drive); -} - /** * atiixp_set_pio_mode - set host controller for PIO mode * @drive: drive @@ -132,29 +93,33 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed) int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8; u32 tmp32; u16 tmp16; - - if (speed < XFER_MW_DMA_0) - return; + u16 udma_ctl = 0; spin_lock_irqsave(&atiixp_lock, flags); - save_mdma_mode[drive->dn] = 0; + pci_read_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, &udma_ctl); + if (speed >= XFER_UDMA_0) { pci_read_config_word(dev, ATIIXP_IDE_UDMA_MODE, &tmp16); tmp16 &= ~(0x07 << (drive->dn * 4)); tmp16 |= ((speed & 0x07) << (drive->dn * 4)); pci_write_config_word(dev, ATIIXP_IDE_UDMA_MODE, tmp16); - } else { - if ((speed >= XFER_MW_DMA_0) && (speed <= XFER_MW_DMA_2)) { - save_mdma_mode[drive->dn] = speed; - pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32); - tmp32 &= ~(0xff << timing_shift); - tmp32 |= (mdma_timing[speed & 0x03].recover_width << timing_shift) | - (mdma_timing[speed & 0x03].command_width << (timing_shift + 4)); - pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32); - } + + udma_ctl |= (1 << drive->dn); + } else if (speed >= XFER_MW_DMA_0) { + u8 i = speed & 0x03; + + pci_read_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, &tmp32); + tmp32 &= ~(0xff << timing_shift); + tmp32 |= (mdma_timing[i].recover_width << timing_shift) | + (mdma_timing[i].command_width << (timing_shift + 4)); + pci_write_config_dword(dev, ATIIXP_IDE_MDMA_TIMING, tmp32); + + udma_ctl &= ~(1 << drive->dn); } + pci_write_config_word(dev, ATIIXP_IDE_UDMA_CONTROL, udma_ctl); + spin_unlock_irqrestore(&atiixp_lock, flags); } @@ -184,9 +149,6 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif) hwif->cbl = ATA_CBL_PATA80; else hwif->cbl = ATA_CBL_PATA40; - - hwif->dma_host_on = &atiixp_dma_host_on; - hwif->dma_host_off = &atiixp_dma_host_off; } static const struct ide_port_info atiixp_pci_info[] __devinitdata = { diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 4aa48104e0c1..da3565e0071f 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -706,9 +706,9 @@ static int pci_conf2(void) } /* - * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c + * Probe for a cmd640 chipset, and initialize it if found. */ -int __init ide_probe_for_cmd640x (void) +static int __init cmd640x_init(void) { #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED int second_port_toggled = 0; @@ -717,6 +717,7 @@ int __init ide_probe_for_cmd640x (void) const char *bus_type, *port2; unsigned int index; u8 b, cfr; + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; if (cmd640_vlb && probe_for_cmd640_vlb()) { bus_type = "VLB"; @@ -769,6 +770,8 @@ int __init ide_probe_for_cmd640x (void) cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + idx[0] = cmd_hwif0->index; + /* * Ensure compatibility by always using the slowest timings * for access to the drive's command register block, @@ -826,6 +829,8 @@ int __init ide_probe_for_cmd640x (void) cmd_hwif1->pio_mask = ATA_PIO5; cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + + idx[1] = cmd_hwif1->index; } printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, cmd_hwif0->serialized ? "" : "not ", port2); @@ -872,6 +877,13 @@ int __init ide_probe_for_cmd640x (void) #ifdef CMD640_DUMP_REGS cmd640_dump_regs(); #endif + + ide_device_add(idx); + return 1; } +module_param_named(probe_vlb, cmd640_vlb, bool, 0); +MODULE_PARM_DESC(probe_vlb, "probe for VLB version of CMD640 chipset"); + +module_init(cmd640x_init); diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index bc553337b1be..cd4eb9def151 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/cmd64x.c Version 1.52 Dec 24, 2007 + * linux/drivers/ide/pci/cmd64x.c Version 1.53 Dec 24, 2007 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Due to massive hardware bugs, UltraDMA is only supported @@ -22,8 +22,6 @@ #include <asm/io.h> -#define DISPLAY_CMD64X_TIMINGS - #define CMD_DEBUG 0 #if CMD_DEBUG @@ -37,11 +35,6 @@ */ #define CFR 0x50 #define CFR_INTR_CH0 0x04 -#define CNTRL 0x51 -#define CNTRL_ENA_1ST 0x04 -#define CNTRL_ENA_2ND 0x08 -#define CNTRL_DIS_RA0 0x40 -#define CNTRL_DIS_RA1 0x80 #define CMDTIM 0x52 #define ARTTIM0 0x53 @@ -60,108 +53,13 @@ #define MRDMODE 0x71 #define MRDMODE_INTR_CH0 0x04 #define MRDMODE_INTR_CH1 0x08 -#define MRDMODE_BLK_CH0 0x10 -#define MRDMODE_BLK_CH1 0x20 -#define BMIDESR0 0x72 #define UDIDETCR0 0x73 #define DTPR0 0x74 #define BMIDECR1 0x78 #define BMIDECSR 0x79 -#define BMIDESR1 0x7A #define UDIDETCR1 0x7B #define DTPR1 0x7C -#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) -#include <linux/stat.h> -#include <linux/proc_fs.h> - -static u8 cmd64x_proc = 0; - -#define CMD_MAX_DEVS 5 - -static struct pci_dev *cmd_devs[CMD_MAX_DEVS]; -static int n_cmd_devs; - -static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index) -{ - char *p = buf; - u8 reg72 = 0, reg73 = 0; /* primary */ - u8 reg7a = 0, reg7b = 0; /* secondary */ - u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0; /* extra */ - - p += sprintf(p, "\nController: %d\n", index); - p += sprintf(p, "PCI-%x Chipset.\n", dev->device); - - (void) pci_read_config_byte(dev, CFR, ®50); - (void) pci_read_config_byte(dev, CNTRL, ®51); - (void) pci_read_config_byte(dev, ARTTIM23, ®57); - (void) pci_read_config_byte(dev, MRDMODE, ®71); - (void) pci_read_config_byte(dev, BMIDESR0, ®72); - (void) pci_read_config_byte(dev, UDIDETCR0, ®73); - (void) pci_read_config_byte(dev, BMIDESR1, ®7a); - (void) pci_read_config_byte(dev, UDIDETCR1, ®7b); - - /* PCI0643/6 originally didn't have the primary channel enable bit */ - if ((dev->device == PCI_DEVICE_ID_CMD_643) || - (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3)) - reg51 |= CNTRL_ENA_1ST; - - p += sprintf(p, "---------------- Primary Channel " - "---------------- Secondary Channel ------------\n"); - p += sprintf(p, " %s %s\n", - (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled", - (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled"); - p += sprintf(p, "---------------- drive0 --------- drive1 " - "-------- drive0 --------- drive1 ------\n"); - p += sprintf(p, "DMA enabled: %s %s" - " %s %s\n", - (reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ", - (reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no "); - p += sprintf(p, "UltraDMA mode: %s (%c) %s (%c)", - ( reg73 & 0x01) ? " on" : "off", - ((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') : - ((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') : - ((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') : - ((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?', - ( reg73 & 0x02) ? " on" : "off", - ((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') : - ((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') : - ((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') : - ((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?'); - p += sprintf(p, " %s (%c) %s (%c)\n", - ( reg7b & 0x01) ? " on" : "off", - ((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') : - ((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') : - ((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') : - ((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?', - ( reg7b & 0x02) ? " on" : "off", - ((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') : - ((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') : - ((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') : - ((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?'); - p += sprintf(p, "Interrupt: %s, %s %s, %s\n", - (reg71 & MRDMODE_BLK_CH0 ) ? "blocked" : "enabled", - (reg50 & CFR_INTR_CH0 ) ? "pending" : "clear ", - (reg71 & MRDMODE_BLK_CH1 ) ? "blocked" : "enabled", - (reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear "); - - return (char *)p; -} - -static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count) -{ - char *p = buffer; - int i; - - for (i = 0; i < n_cmd_devs; i++) { - struct pci_dev *dev = cmd_devs[i]; - p = print_cmd64x_get_info(p, dev, i); - } - return p-buffer; /* => must be less than 4k! */ -} - -#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */ - static u8 quantize_timing(int timing, int quant) { return (timing + quant - 1) / quant; @@ -322,8 +220,6 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) case XFER_MW_DMA_0: program_cycle_times(drive, 480, 215); break; - default: - return; } if (speed >= XFER_SW_DMA_0) @@ -333,14 +229,15 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) static int cmd648_ide_dma_end (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + unsigned long base = hwif->dma_base - (hwif->channel * 8); int err = __ide_dma_end(drive); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - u8 mrdmode = inb(hwif->dma_master + 0x01); + u8 mrdmode = inb(base + 1); /* clear the interrupt bit */ outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask, - hwif->dma_master + 0x01); + base + 1); return err; } @@ -365,10 +262,11 @@ static int cmd64x_ide_dma_end (ide_drive_t *drive) static int cmd648_ide_dma_test_irq (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); + unsigned long base = hwif->dma_base - (hwif->channel * 8); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; u8 dma_stat = inb(hwif->dma_status); - u8 mrdmode = inb(hwif->dma_master + 0x01); + u8 mrdmode = inb(base + 1); #ifdef DEBUG printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n", @@ -472,16 +370,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha mrdmode &= ~0x30; (void) pci_write_config_byte(dev, MRDMODE, (mrdmode | 0x02)); -#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_IDE_PROC_FS) - - cmd_devs[n_cmd_devs++] = dev; - - if (!cmd64x_proc) { - cmd64x_proc = 1; - ide_pci_create_host_proc("cmd64x", cmd64x_get_info); - } -#endif /* DISPLAY_CMD64X_TIMINGS && CONFIG_IDE_PROC_FS */ - return 0; } diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index 0466462fd21b..6ec00b8d7ec1 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c @@ -71,7 +71,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) ide_hwif_t *hwif = HWIF(drive); struct pci_dev *pdev = hwif->pci_dev; int controller = drive->dn > 1 ? 1 : 0; - u8 reg; /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */ @@ -91,11 +90,6 @@ static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio) pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1), (cs5520_pio_clocks[pio].recovery << 4) | (cs5520_pio_clocks[pio].assert)); - - /* Set the DMA enable/disable flag */ - reg = inb(hwif->dma_base + 0x02 + 8*controller); - reg |= 1<<((drive->dn&1)+5); - outb(reg, hwif->dma_base + 0x02 + 8*controller); } static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed) @@ -109,13 +103,14 @@ static void cs5520_set_dma_mode(ide_drive_t *drive, const u8 speed) * We wrap the DMA activate to set the vdma flag. This is needed * so that the IDE DMA layer issues PIO not DMA commands over the * DMA channel + * + * ATAPI is harder so disable it for now using IDE_HFLAG_NO_ATAPI_DMA */ - -static int cs5520_dma_on(ide_drive_t *drive) + +static void cs5520_dma_host_set(ide_drive_t *drive, int on) { - /* ATAPI is harder so leave it for now */ - drive->vdma = 1; - return 0; + drive->vdma = on; + ide_dma_host_set(drive, on); } static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) @@ -126,7 +121,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) if (hwif->dma_base == 0) return; - hwif->ide_dma_on = &cs5520_dma_on; + hwif->dma_host_set = &cs5520_dma_host_set; } #define DECLARE_CS_DEV(name_str) \ @@ -137,6 +132,7 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) IDE_HFLAG_CS5520 | \ IDE_HFLAG_VDMA | \ IDE_HFLAG_NO_ATAPI_DMA | \ + IDE_HFLAG_ABUSE_SET_DMA_MODE |\ IDE_HFLAG_BOOTABLE, \ .pio_mask = ATA_PIO4, \ } diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c index 547690395eee..df5966b33460 100644 --- a/drivers/ide/pci/cs5530.c +++ b/drivers/ide/pci/cs5530.c @@ -116,8 +116,6 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode) case XFER_MW_DMA_0: timings = 0x00077771; break; case XFER_MW_DMA_1: timings = 0x00012121; break; case XFER_MW_DMA_2: timings = 0x00002020; break; - default: - return; } basereg = CS5530_BASEREG(drive->hwif); reg = inl(basereg + 4); /* get drive0 config register */ diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c index ddcbeba671e1..50b3d7791f55 100644 --- a/drivers/ide/pci/cs5535.c +++ b/drivers/ide/pci/cs5535.c @@ -190,7 +190,7 @@ static const struct ide_port_info cs5535_chipset __devinitdata = { .name = "CS5535", .init_hwif = init_hwif_cs5535, .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_POST_SET_MODE | - IDE_HFLAG_BOOTABLE, + IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA4, diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c index 1cd4e9cb0521..3ec4c659a37d 100644 --- a/drivers/ide/pci/cy82c693.c +++ b/drivers/ide/pci/cy82c693.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/cy82c693.c Version 0.42 Oct 23, 2007 + * linux/drivers/ide/pci/cy82c693.c Version 0.44 Nov 8, 2007 * * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator @@ -176,17 +176,12 @@ static void compute_clocks (u8 pio, pio_clocks_t *p_pclk) * set DMA mode a specific channel for CY82C693 */ -static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) +static void cy82c693_set_dma_mode(ide_drive_t *drive, const u8 mode) { - u8 index = 0, data = 0; + ide_hwif_t *hwif = drive->hwif; + u8 single = (mode & 0x10) >> 4, index = 0, data = 0; - if (mode>2) /* make sure we set a valid mode */ - mode = 2; - - if (mode > drive->id->tDMA) /* to be absolutly sure we have a valid mode */ - mode = drive->id->tDMA; - - index = (HWIF(drive)->channel==0) ? CY82_INDEX_CHANNEL0 : CY82_INDEX_CHANNEL1; + index = hwif->channel ? CY82_INDEX_CHANNEL1 : CY82_INDEX_CHANNEL0; #if CY82C693_DEBUG_LOGS /* for debug let's show the previous values */ @@ -199,7 +194,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) (data&0x3), ((data>>2)&1)); #endif /* CY82C693_DEBUG_LOGS */ - data = (u8)mode|(u8)(single<<2); + data = (mode & 3) | (single << 2); outb(index, CY82_INDEX_PORT); outb(data, CY82_DATA_PORT); @@ -207,7 +202,7 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) #if CY82C693_DEBUG_INFO printk(KERN_INFO "%s (ch=%d, dev=%d): set DMA mode to %d (single=%d)\n", drive->name, HWIF(drive)->channel, drive->select.b.unit, - mode, single); + mode & 3, single); #endif /* CY82C693_DEBUG_INFO */ /* @@ -230,39 +225,6 @@ static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) #endif /* CY82C693_DEBUG_INFO */ } -/* - * used to set DMA mode for CY82C693 (single and multi modes) - */ -static int cy82c693_ide_dma_on (ide_drive_t *drive) -{ - struct hd_driveid *id = drive->id; - -#if CY82C693_DEBUG_INFO - printk (KERN_INFO "dma_on: %s\n", drive->name); -#endif /* CY82C693_DEBUG_INFO */ - - if (id != NULL) { - /* Enable DMA on any drive that has DMA - * (multi or single) enabled - */ - if (id->field_valid & 2) { /* regular DMA */ - int mmode, smode; - - mmode = id->dma_mword & (id->dma_mword >> 8); - smode = id->dma_1word & (id->dma_1word >> 8); - - if (mmode != 0) { - /* enable multi */ - cy82c693_dma_enable(drive, (mmode >> 1), 0); - } else if (smode != 0) { - /* enable single */ - cy82c693_dma_enable(drive, (smode >> 1), 1); - } - } - } - return __ide_dma_on(drive); -} - static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); @@ -429,11 +391,7 @@ static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const c static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif) { hwif->set_pio_mode = &cy82c693_set_pio_mode; - - if (hwif->dma_base == 0) - return; - - hwif->ide_dma_on = &cy82c693_ide_dma_on; + hwif->set_dma_mode = &cy82c693_set_dma_mode; } static void __devinit init_iops_cy82c693(ide_hwif_t *hwif) @@ -454,11 +412,11 @@ static const struct ide_port_info cy82c693_chipset __devinitdata = { .init_iops = init_iops_cy82c693, .init_hwif = init_hwif_cy82c693, .chipset = ide_cy82c693, - .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_TRUST_BIOS_FOR_DMA | + .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_CY82C693 | IDE_HFLAG_BOOTABLE, .pio_mask = ATA_PIO4, - .swdma_mask = ATA_SWDMA2_ONLY, - .mwdma_mask = ATA_MWDMA2_ONLY, + .swdma_mask = ATA_SWDMA2, + .mwdma_mask = ATA_MWDMA2, }; static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 83829081640a..26aa492071bb 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -80,7 +80,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) hw.irq = dev->irq; hw.chipset = ide_pci; /* this enables IRQ sharing */ - rc = ide_register_hw(&hw, &ide_undecoded_slave, 0, &hwif); + rc = ide_register_hw(&hw, &ide_undecoded_slave, &hwif); if (rc < 0) { printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); pci_disable_device(dev); diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index ae6307fae4f9..dfba0d13fcd3 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -129,14 +129,18 @@ static void __devinit init_hwif_hpt34x(ide_hwif_t *hwif) hwif->set_dma_mode = &hpt34x_set_mode; } +#define IDE_HFLAGS_HPT34X \ + (IDE_HFLAG_NO_ATAPI_DMA | \ + IDE_HFLAG_ABUSE_SET_DMA_MODE | \ + IDE_HFLAG_NO_AUTODMA) + static const struct ide_port_info hpt34x_chipsets[] __devinitdata = { { /* 0 */ .name = "HPT343", .init_chipset = init_chipset_hpt34x, .init_hwif = init_hwif_hpt34x, .extra = 16, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_NO_AUTODMA, + .host_flags = IDE_HFLAGS_HPT34X, .pio_mask = ATA_PIO5, }, { /* 1 */ @@ -144,9 +148,7 @@ static const struct ide_port_info hpt34x_chipsets[] __devinitdata = { .init_chipset = init_chipset_hpt34x, .init_hwif = init_hwif_hpt34x, .extra = 16, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_NO_AUTODMA | - IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT34X | IDE_HFLAG_OFF_BOARD, .pio_mask = ATA_PIO5, #ifdef CONFIG_HPT34X_AUTODMA .swdma_mask = ATA_SWDMA2, diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 9fce25bdec8a..12685939a813 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/hpt366.c Version 1.22 Dec 4, 2007 + * linux/drivers/ide/pci/hpt366.c Version 1.30 Dec 12, 2007 * * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> * Portions Copyright (C) 2001 Sun Microsystems, Inc. @@ -88,7 +88,7 @@ * - rename all the register related variables consistently * - move all the interrupt twiddling code from the speedproc handlers into * init_hwif_hpt366(), also grouping all the DMA related code together there - * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and + * - merge HPT36x/HPT37x speedproc handlers, fix PIO timing register mask and * separate the UltraDMA and MWDMA masks there to avoid changing PIO timings * when setting an UltraDMA mode * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select @@ -458,6 +458,13 @@ enum ata_clock { NUM_ATA_CLOCKS }; +struct hpt_timings { + u32 pio_mask; + u32 dma_mask; + u32 ultra_mask; + u32 *clock_table[NUM_ATA_CLOCKS]; +}; + /* * Hold all the HighPoint chip information in one place. */ @@ -468,7 +475,8 @@ struct hpt_info { u8 udma_mask; /* Allowed UltraDMA modes mask. */ u8 dpll_clk; /* DPLL clock in MHz */ u8 pci_clk; /* PCI clock in MHz */ - u32 **settings; /* Chipset settings table */ + struct hpt_timings *timings; /* Chipset timing data */ + u8 clock; /* ATA clock selected */ }; /* Supported HighPoint chips */ @@ -486,20 +494,30 @@ enum { HPT371N }; -static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = { - twenty_five_base_hpt36x, - thirty_three_base_hpt36x, - forty_base_hpt36x, - NULL, - NULL +static struct hpt_timings hpt36x_timings = { + .pio_mask = 0xc1f8ffff, + .dma_mask = 0x303800ff, + .ultra_mask = 0x30070000, + .clock_table = { + [ATA_CLOCK_25MHZ] = twenty_five_base_hpt36x, + [ATA_CLOCK_33MHZ] = thirty_three_base_hpt36x, + [ATA_CLOCK_40MHZ] = forty_base_hpt36x, + [ATA_CLOCK_50MHZ] = NULL, + [ATA_CLOCK_66MHZ] = NULL + } }; -static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = { - NULL, - thirty_three_base_hpt37x, - NULL, - fifty_base_hpt37x, - sixty_six_base_hpt37x +static struct hpt_timings hpt37x_timings = { + .pio_mask = 0xcfc3ffff, + .dma_mask = 0x31c001ff, + .ultra_mask = 0x303c0000, + .clock_table = { + [ATA_CLOCK_25MHZ] = NULL, + [ATA_CLOCK_33MHZ] = thirty_three_base_hpt37x, + [ATA_CLOCK_40MHZ] = NULL, + [ATA_CLOCK_50MHZ] = fifty_base_hpt37x, + [ATA_CLOCK_66MHZ] = sixty_six_base_hpt37x + } }; static const struct hpt_info hpt36x __devinitdata = { @@ -507,7 +525,7 @@ static const struct hpt_info hpt36x __devinitdata = { .chip_type = HPT36x, .udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ? ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2, .dpll_clk = 0, /* no DPLL */ - .settings = hpt36x_settings + .timings = &hpt36x_timings }; static const struct hpt_info hpt370 __devinitdata = { @@ -515,7 +533,7 @@ static const struct hpt_info hpt370 __devinitdata = { .chip_type = HPT370, .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, .dpll_clk = 48, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt370a __devinitdata = { @@ -523,7 +541,7 @@ static const struct hpt_info hpt370a __devinitdata = { .chip_type = HPT370A, .udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4, .dpll_clk = 48, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt374 __devinitdata = { @@ -531,7 +549,7 @@ static const struct hpt_info hpt374 __devinitdata = { .chip_type = HPT374, .udma_mask = ATA_UDMA5, .dpll_clk = 48, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt372 __devinitdata = { @@ -539,7 +557,7 @@ static const struct hpt_info hpt372 __devinitdata = { .chip_type = HPT372, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 55, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt372a __devinitdata = { @@ -547,7 +565,7 @@ static const struct hpt_info hpt372a __devinitdata = { .chip_type = HPT372A, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 66, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt302 __devinitdata = { @@ -555,7 +573,7 @@ static const struct hpt_info hpt302 __devinitdata = { .chip_type = HPT302, .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 66, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt371 __devinitdata = { @@ -563,7 +581,7 @@ static const struct hpt_info hpt371 __devinitdata = { .chip_type = HPT371, .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 66, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt372n __devinitdata = { @@ -571,7 +589,7 @@ static const struct hpt_info hpt372n __devinitdata = { .chip_type = HPT372N, .udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 77, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt302n __devinitdata = { @@ -579,7 +597,7 @@ static const struct hpt_info hpt302n __devinitdata = { .chip_type = HPT302N, .udma_mask = HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 77, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static const struct hpt_info hpt371n __devinitdata = { @@ -587,7 +605,7 @@ static const struct hpt_info hpt371n __devinitdata = { .chip_type = HPT371N, .udma_mask = HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5, .dpll_clk = 77, - .settings = hpt37x_settings + .timings = &hpt37x_timings }; static int check_in_drive_list(ide_drive_t *drive, const char **list) @@ -675,94 +693,50 @@ static u32 get_speed_setting(u8 speed, struct hpt_info *info) for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++) if (xfer_speeds[i] == speed) break; - /* - * NOTE: info->settings only points to the pointer - * to the list of the actual register values - */ - return (*info->settings)[i]; + + return info->timings->clock_table[info->clock][i]; } -static void hpt36x_set_mode(ide_drive_t *drive, const u8 speed) +static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = HWIF(drive)->pci_dev; struct hpt_info *info = pci_get_drvdata(dev); - u8 itr_addr = drive->dn ? 0x44 : 0x40; + struct hpt_timings *t = info->timings; + u8 itr_addr = 0x40 + (drive->dn * 4); u32 old_itr = 0; - u32 itr_mask, new_itr; - - itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : - (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); - - new_itr = get_speed_setting(speed, info); + u32 new_itr = get_speed_setting(speed, info); + u32 itr_mask = speed < XFER_MW_DMA_0 ? t->pio_mask : + (speed < XFER_UDMA_0 ? t->dma_mask : + t->ultra_mask); + pci_read_config_dword(dev, itr_addr, &old_itr); + new_itr = (old_itr & ~itr_mask) | (new_itr & itr_mask); /* * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well) * to avoid problems handling I/O errors later */ - pci_read_config_dword(dev, itr_addr, &old_itr); - new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); new_itr &= ~0xc0000000; pci_write_config_dword(dev, itr_addr, new_itr); } -static void hpt37x_set_mode(ide_drive_t *drive, const u8 speed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - struct hpt_info *info = pci_get_drvdata(dev); - u8 itr_addr = 0x40 + (drive->dn * 4); - u32 old_itr = 0; - u32 itr_mask, new_itr; - - itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : - (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); - - new_itr = get_speed_setting(speed, info); - - pci_read_config_dword(dev, itr_addr, &old_itr); - new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask); - - if (speed < XFER_MW_DMA_0) - new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - pci_write_config_dword(dev, itr_addr, new_itr); -} - -static void hpt3xx_set_mode(ide_drive_t *drive, const u8 speed) -{ - ide_hwif_t *hwif = HWIF(drive); - struct hpt_info *info = pci_get_drvdata(hwif->pci_dev); - - if (info->chip_type >= HPT370) - hpt37x_set_mode(drive, speed); - else /* hpt368: hpt_minimum_revision(dev, 2) */ - hpt36x_set_mode(drive, speed); -} - static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio) { hpt3xx_set_mode(drive, XFER_PIO_0 + pio); } -static int hpt3xx_quirkproc(ide_drive_t *drive) +static void hpt3xx_quirkproc(ide_drive_t *drive) { struct hd_driveid *id = drive->id; const char **list = quirk_drives; while (*list) - if (strstr(id->model, *list++)) - return 1; - return 0; -} - -static void hpt3xx_intrproc(ide_drive_t *drive) -{ - if (drive->quirk_list) - return; + if (strstr(id->model, *list++)) { + drive->quirk_list = 1; + return; + } - /* drives in the quirk_list may not like intr setups/cleanups */ - outb(drive->ctl | 2, IDE_CONTROL_REG); + drive->quirk_list = 0; } static void hpt3xx_maskproc(ide_drive_t *drive, int mask) @@ -914,32 +888,33 @@ static int hpt374_ide_dma_end(ide_drive_t *drive) static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode) { - u8 scr2 = inb(hwif->dma_master + 0x7b); + unsigned long base = hwif->extra_base; + u8 scr2 = inb(base + 0x6b); if ((scr2 & 0x7f) == mode) return; /* Tristate the bus */ - outb(0x80, hwif->dma_master + 0x73); - outb(0x80, hwif->dma_master + 0x77); + outb(0x80, base + 0x63); + outb(0x80, base + 0x67); /* Switch clock and reset channels */ - outb(mode, hwif->dma_master + 0x7b); - outb(0xc0, hwif->dma_master + 0x79); + outb(mode, base + 0x6b); + outb(0xc0, base + 0x69); /* * Reset the state machines. * NOTE: avoid accidentally enabling the disabled channels. */ - outb(inb(hwif->dma_master + 0x70) | 0x32, hwif->dma_master + 0x70); - outb(inb(hwif->dma_master + 0x74) | 0x32, hwif->dma_master + 0x74); + outb(inb(base + 0x60) | 0x32, base + 0x60); + outb(inb(base + 0x64) | 0x32, base + 0x64); /* Complete reset */ - outb(0x00, hwif->dma_master + 0x79); + outb(0x00, base + 0x69); /* Reconnect channels to bus */ - outb(0x00, hwif->dma_master + 0x73); - outb(0x00, hwif->dma_master + 0x77); + outb(0x00, base + 0x63); + outb(0x00, base + 0x67); } /** @@ -1210,7 +1185,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha * We also don't like using the DPLL because this causes glitches * on PRST-/SRST- when the state engine gets reset... */ - if (chip_type >= HPT374 || info->settings[clock] == NULL) { + if (chip_type >= HPT374 || info->timings->clock_table[clock] == NULL) { u16 f_low, delta = pci_clk < 50 ? 2 : 4; int adjust; @@ -1226,7 +1201,7 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha clock = ATA_CLOCK_50MHZ; } - if (info->settings[clock] == NULL) { + if (info->timings->clock_table[clock] == NULL) { printk(KERN_ERR "%s: unknown bus timing!\n", name); kfree(info); return -EIO; @@ -1267,15 +1242,10 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha printk("%s: using %d MHz PCI clock\n", name, pci_clk); } - /* - * Advance the table pointer to a slot which points to the list - * of the register values settings matching the clock being used. - */ - info->settings += clock; - /* Store the clock frequencies. */ info->dpll_clk = dpll_clk; info->pci_clk = pci_clk; + info->clock = clock; /* Point to this chip's own instance of the hpt_info structure. */ pci_set_drvdata(dev, info); @@ -1320,8 +1290,8 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) hwif->set_pio_mode = &hpt3xx_set_pio_mode; hwif->set_dma_mode = &hpt3xx_set_mode; + hwif->quirkproc = &hpt3xx_quirkproc; - hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; hwif->busproc = &hpt3xx_busproc; @@ -1494,6 +1464,11 @@ static int __devinit hpt36x_init(struct pci_dev *dev, struct pci_dev *dev2) return 0; } +#define IDE_HFLAGS_HPT3XX \ + (IDE_HFLAG_NO_ATAPI_DMA | \ + IDE_HFLAG_ABUSE_SET_DMA_MODE | \ + IDE_HFLAG_OFF_BOARD) + static const struct ide_port_info hpt366_chipsets[] __devinitdata = { { /* 0 */ .name = "HPT36x", @@ -1508,9 +1483,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { */ .enablebits = {{0x50,0x10,0x10}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAG_SINGLE | - IDE_HFLAG_NO_ATAPI_DMA | - IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT3XX | IDE_HFLAG_SINGLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 1 */ @@ -1520,7 +1493,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT3XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 2 */ @@ -1530,7 +1503,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT3XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 3 */ @@ -1540,7 +1513,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT3XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 4 */ @@ -1551,7 +1524,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .udma_mask = ATA_UDMA5, .extra = 240, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT3XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, },{ /* 5 */ @@ -1561,7 +1534,7 @@ static const struct ide_port_info hpt366_chipsets[] __devinitdata = { .init_dma = init_dma_hpt366, .enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}}, .extra = 240, - .host_flags = IDE_HFLAG_NO_ATAPI_DMA | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_HPT3XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, } diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c index 90b52ed37bfc..2a0f45c4f4c4 100644 --- a/drivers/ide/pci/it8213.c +++ b/drivers/ide/pci/it8213.c @@ -101,24 +101,11 @@ static void it8213_set_dma_mode(ide_drive_t *drive, const u8 speed) pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); - switch(speed) { - case XFER_UDMA_6: - case XFER_UDMA_4: - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: - break; - default: - return; - } - if (speed >= XFER_UDMA_0) { + u8 udma = speed - XFER_UDMA_0; + + u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); + if (!(reg48 & u_flag)) pci_write_config_byte(dev, 0x48, reg48 | u_flag); if (speed >= XFER_UDMA_5) { diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c index 99b7d763b6c7..e610a5340fdc 100644 --- a/drivers/ide/pci/it821x.c +++ b/drivers/ide/pci/it821x.c @@ -431,33 +431,29 @@ static u8 __devinit ata66_it821x(ide_hwif_t *hwif) } /** - * it821x_fixup - post init callback - * @hwif: interface + * it821x_quirkproc - post init callback + * @drive: drive * - * This callback is run after the drives have been probed but + * This callback is run after the drive has been probed but * before anything gets attached. It allows drivers to do any * final tuning that is needed, or fixups to work around bugs. */ -static void __devinit it821x_fixups(ide_hwif_t *hwif) +static void __devinit it821x_quirkproc(ide_drive_t *drive) { - struct it821x_dev *itdev = ide_get_hwifdata(hwif); - int i; + struct it821x_dev *itdev = ide_get_hwifdata(drive->hwif); + struct hd_driveid *id = drive->id; + u16 *idbits = (u16 *)drive->id; - if(!itdev->smart) { + if (!itdev->smart) { /* * If we are in pass through mode then not much * needs to be done, but we do bother to clear the * IRQ mask as we may well be in PIO (eg rev 0x10) * for now and we know unmasking is safe on this chipset. */ - for (i = 0; i < 2; i++) { - ide_drive_t *drive = &hwif->drives[i]; - if(drive->present) - drive->unmask = 1; - } - return; - } + drive->unmask = 1; + } else { /* * Perform fixups on smart mode. We need to "lose" some * capabilities the firmware lacks but does not filter, and @@ -465,16 +461,6 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif) * in RAID mode. */ - for(i = 0; i < 2; i++) { - ide_drive_t *drive = &hwif->drives[i]; - struct hd_driveid *id; - u16 *idbits; - - if(!drive->present) - continue; - id = drive->id; - idbits = (u16 *)drive->id; - /* Check for RAID v native */ if(strstr(id->model, "Integrated Technology Express")) { /* In raid mode the ident block is slightly buggy @@ -537,6 +523,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif) struct it821x_dev *idev = kzalloc(sizeof(struct it821x_dev), GFP_KERNEL); u8 conf; + hwif->quirkproc = &it821x_quirkproc; + if (idev == NULL) { printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n"); return; @@ -633,7 +621,6 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha .name = name_str, \ .init_chipset = init_chipset_it821x, \ .init_hwif = init_hwif_it821x, \ - .fixup = it821x_fixups, \ .host_flags = IDE_HFLAG_BOOTABLE, \ .pio_mask = ATA_PIO4, \ } diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c index 2b4f44e45a1a..89d2363a1ebd 100644 --- a/drivers/ide/pci/pdc202xx_new.c +++ b/drivers/ide/pci/pdc202xx_new.c @@ -146,7 +146,7 @@ static struct udma_timing { { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */ }; -static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed) +static void pdcnew_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); u8 adj = (drive->dn & 1) ? 0x08 : 0x00; @@ -162,45 +162,18 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed) if (max_dma_rate(hwif->pci_dev) == 4) { u8 mode = speed & 0x07; - switch (speed) { - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - set_indexed_reg(hwif, 0x10 + adj, - udma_timings[mode].reg10); - set_indexed_reg(hwif, 0x11 + adj, - udma_timings[mode].reg11); - set_indexed_reg(hwif, 0x12 + adj, - udma_timings[mode].reg12); - break; - - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - set_indexed_reg(hwif, 0x0e + adj, - mwdma_timings[mode].reg0e); - set_indexed_reg(hwif, 0x0f + adj, - mwdma_timings[mode].reg0f); - break; - case XFER_PIO_4: - case XFER_PIO_3: - case XFER_PIO_2: - case XFER_PIO_1: - case XFER_PIO_0: - set_indexed_reg(hwif, 0x0c + adj, - pio_timings[mode].reg0c); - set_indexed_reg(hwif, 0x0d + adj, - pio_timings[mode].reg0d); - set_indexed_reg(hwif, 0x13 + adj, - pio_timings[mode].reg13); - break; - default: - printk(KERN_ERR "pdc202xx_new: " - "Unknown speed %d ignored\n", speed); + if (speed >= XFER_UDMA_0) { + set_indexed_reg(hwif, 0x10 + adj, + udma_timings[mode].reg10); + set_indexed_reg(hwif, 0x11 + adj, + udma_timings[mode].reg11); + set_indexed_reg(hwif, 0x12 + adj, + udma_timings[mode].reg12); + } else { + set_indexed_reg(hwif, 0x0e + adj, + mwdma_timings[mode].reg0e); + set_indexed_reg(hwif, 0x0f + adj, + mwdma_timings[mode].reg0f); } } else if (speed == XFER_UDMA_2) { /* Set tHOLD bit to 0 if using UDMA mode 2 */ @@ -212,7 +185,14 @@ static void pdcnew_set_mode(ide_drive_t *drive, const u8 speed) static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio) { - pdcnew_set_mode(drive, XFER_PIO_0 + pio); + ide_hwif_t *hwif = drive->hwif; + u8 adj = (drive->dn & 1) ? 0x08 : 0x00; + + if (max_dma_rate(hwif->pci_dev) == 4) { + set_indexed_reg(hwif, 0x0c + adj, pio_timings[pio].reg0c); + set_indexed_reg(hwif, 0x0d + adj, pio_timings[pio].reg0d); + set_indexed_reg(hwif, 0x13 + adj, pio_timings[pio].reg13); + } } static u8 pdcnew_cable_detect(ide_hwif_t *hwif) @@ -223,14 +203,17 @@ static u8 pdcnew_cable_detect(ide_hwif_t *hwif) return ATA_CBL_PATA80; } -static int pdcnew_quirkproc(ide_drive_t *drive) +static void pdcnew_quirkproc(ide_drive_t *drive) { const char **list, *model = drive->id->model; for (list = pdc_quirk_drives; *list != NULL; list++) - if (strstr(model, *list) != NULL) - return 2; - return 0; + if (strstr(model, *list) != NULL) { + drive->quirk_list = 2; + return; + } + + drive->quirk_list = 0; } static void pdcnew_reset(ide_drive_t *drive) @@ -466,7 +449,7 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif) { hwif->set_pio_mode = &pdcnew_set_pio_mode; - hwif->set_dma_mode = &pdcnew_set_mode; + hwif->set_dma_mode = &pdcnew_set_dma_mode; hwif->quirkproc = &pdcnew_quirkproc; hwif->resetproc = &pdcnew_reset; diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c index e09742e2ba59..3a1e081fe390 100644 --- a/drivers/ide/pci/pdc202xx_old.c +++ b/drivers/ide/pci/pdc202xx_old.c @@ -162,7 +162,7 @@ static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) */ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) { - unsigned long clock_reg = hwif->dma_master + 0x11; + unsigned long clock_reg = hwif->extra_base + 0x01; u8 clock = inb(clock_reg); outb(clock | (hwif->channel ? 0x08 : 0x02), clock_reg); @@ -170,20 +170,23 @@ static void pdc_old_enable_66MHz_clock(ide_hwif_t *hwif) static void pdc_old_disable_66MHz_clock(ide_hwif_t *hwif) { - unsigned long clock_reg = hwif->dma_master + 0x11; + unsigned long clock_reg = hwif->extra_base + 0x01; u8 clock = inb(clock_reg); outb(clock & ~(hwif->channel ? 0x08 : 0x02), clock_reg); } -static int pdc202xx_quirkproc (ide_drive_t *drive) +static void pdc202xx_quirkproc(ide_drive_t *drive) { const char **list, *model = drive->id->model; for (list = pdc_quirk_drives; *list != NULL; list++) - if (strstr(model, *list) != NULL) - return 2; - return 0; + if (strstr(model, *list) != NULL) { + drive->quirk_list = 2; + return; + } + + drive->quirk_list = 0; } static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) @@ -193,7 +196,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive) if (drive->media != ide_disk || drive->addressing == 1) { struct request *rq = HWGROUP(drive)->rq; ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->dma_master; + unsigned long high_16 = hwif->extra_base - 16; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u32 word_count = 0; u8 clock = inb(high_16 + 0x11); @@ -212,7 +215,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) { if (drive->media != ide_disk || drive->addressing == 1) { ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->dma_master; + unsigned long high_16 = hwif->extra_base - 16; unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20); u8 clock = 0; @@ -228,7 +231,7 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive) static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); - unsigned long high_16 = hwif->dma_master; + unsigned long high_16 = hwif->extra_base - 16; u8 dma_stat = inb(hwif->dma_status); u8 sc1d = inb(high_16 + 0x001d); @@ -271,7 +274,7 @@ static void pdc202xx_dma_timeout(ide_drive_t *drive) static void pdc202xx_reset_host (ide_hwif_t *hwif) { - unsigned long high_16 = hwif->dma_master; + unsigned long high_16 = hwif->extra_base - 16; u8 udma_speed_flag = inb(high_16 | 0x001f); outb(udma_speed_flag | 0x10, high_16 | 0x001f); @@ -375,6 +378,11 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, } } +#define IDE_HFLAGS_PDC202XX \ + (IDE_HFLAG_ERROR_STOPS_FIFO | \ + IDE_HFLAG_ABUSE_SET_DMA_MODE | \ + IDE_HFLAG_OFF_BOARD) + #define DECLARE_PDC2026X_DEV(name_str, udma, extra_flags) \ { \ .name = name_str, \ @@ -382,9 +390,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, .init_hwif = init_hwif_pdc202xx, \ .init_dma = init_dma_pdc202xx, \ .extra = 48, \ - .host_flags = IDE_HFLAG_ERROR_STOPS_FIFO | \ - extra_flags | \ - IDE_HFLAG_OFF_BOARD, \ + .host_flags = IDE_HFLAGS_PDC202XX | extra_flags, \ .pio_mask = ATA_PIO4, \ .mwdma_mask = ATA_MWDMA2, \ .udma_mask = udma, \ @@ -397,8 +403,7 @@ static const struct ide_port_info pdc202xx_chipsets[] __devinitdata = { .init_hwif = init_hwif_pdc202xx, .init_dma = init_dma_pdc202xx, .extra = 16, - .host_flags = IDE_HFLAG_ERROR_STOPS_FIFO | - IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAGS_PDC202XX, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA2, diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 27781d294cea..bd6d3f77d30c 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -203,20 +203,11 @@ static void piix_set_dma_mode(ide_drive_t *drive, const u8 speed) pci_read_config_byte(dev, 0x54, ®54); pci_read_config_byte(dev, 0x55, ®55); - switch(speed) { - case XFER_UDMA_4: - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_5: - case XFER_UDMA_3: - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: break; - default: return; - } - if (speed >= XFER_UDMA_0) { + u8 udma = speed - XFER_UDMA_0; + + u_speed = min_t(u8, 2 - (udma & 1), udma) << (drive->dn * 4); + if (!(reg48 & u_flag)) pci_write_config_byte(dev, 0x48, reg48 | u_flag); if (speed == XFER_UDMA_5) { diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c index 707d5ff66b03..32fdf53379f5 100644 --- a/drivers/ide/pci/sc1200.c +++ b/drivers/ide/pci/sc1200.c @@ -135,59 +135,29 @@ static void sc1200_set_dma_mode(ide_drive_t *drive, const u8 mode) unsigned short pci_clock; unsigned int basereg = hwif->channel ? 0x50 : 0x40; + static const u32 udma_timing[3][3] = { + { 0x00921250, 0x00911140, 0x00911030 }, + { 0x00932470, 0x00922260, 0x00922140 }, + { 0x009436a1, 0x00933481, 0x00923261 }, + }; + + static const u32 mwdma_timing[3][3] = { + { 0x00077771, 0x00012121, 0x00002020 }, + { 0x000bbbb2, 0x00024241, 0x00013131 }, + { 0x000ffff3, 0x00035352, 0x00015151 }, + }; + pci_clock = sc1200_get_pci_clock(); /* * Note that each DMA mode has several timings associated with it. * The correct timing depends on the fast PCI clock freq. */ - timings = 0; - switch (mode) { - case XFER_UDMA_0: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00921250; break; - case PCI_CLK_48: timings = 0x00932470; break; - case PCI_CLK_66: timings = 0x009436a1; break; - } - break; - case XFER_UDMA_1: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00911140; break; - case PCI_CLK_48: timings = 0x00922260; break; - case PCI_CLK_66: timings = 0x00933481; break; - } - break; - case XFER_UDMA_2: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00911030; break; - case PCI_CLK_48: timings = 0x00922140; break; - case PCI_CLK_66: timings = 0x00923261; break; - } - break; - case XFER_MW_DMA_0: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00077771; break; - case PCI_CLK_48: timings = 0x000bbbb2; break; - case PCI_CLK_66: timings = 0x000ffff3; break; - } - break; - case XFER_MW_DMA_1: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00012121; break; - case PCI_CLK_48: timings = 0x00024241; break; - case PCI_CLK_66: timings = 0x00035352; break; - } - break; - case XFER_MW_DMA_2: - switch (pci_clock) { - case PCI_CLK_33: timings = 0x00002020; break; - case PCI_CLK_48: timings = 0x00013131; break; - case PCI_CLK_66: timings = 0x00015151; break; - } - break; - default: - return; - } + + if (mode >= XFER_UDMA_0) + timings = udma_timing[pci_clock][mode - XFER_UDMA_0]; + else + timings = mwdma_timing[pci_clock][mode - XFER_MW_DMA_0]; if (unit == 0) { /* are we configuring drive0? */ pci_read_config_dword(hwif->pci_dev, basereg+4, ®); @@ -250,9 +220,9 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) } if (mode != -1) { printk("SC1200: %s: changing (U)DMA mode\n", drive->name); - hwif->dma_off_quietly(drive); - if (ide_set_dma_mode(drive, mode) == 0) - hwif->dma_host_on(drive); + ide_dma_off_quietly(drive); + if (ide_set_dma_mode(drive, mode) == 0 && drive->using_dma) + hwif->dma_host_set(drive, 1); return; } @@ -260,66 +230,39 @@ static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio) } #ifdef CONFIG_PM -static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev) -{ - int h; - - for (h = 0; h < MAX_HWIFS; h++) { - ide_hwif_t *hwif = &ide_hwifs[h]; - if (prev) { - if (hwif == prev) - prev = NULL; // found previous, now look for next match - } else { - if (hwif && hwif->pci_dev == dev) - return hwif; // found next match - } - } - return NULL; // not found -} - -typedef struct sc1200_saved_state_s { - __u32 regs[4]; -} sc1200_saved_state_t; - +struct sc1200_saved_state { + u32 regs[8]; +}; static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) { - ide_hwif_t *hwif = NULL; - printk("SC1200: suspend(%u)\n", state.event); + /* + * we only save state when going from full power to less + */ if (state.event == PM_EVENT_ON) { - // we only save state when going from full power to less - - // - // Loop over all interfaces that are part of this PCI device: - // - while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { - sc1200_saved_state_t *ss; - unsigned int basereg, r; - // - // allocate a permanent save area, if not already allocated - // - ss = (sc1200_saved_state_t *)hwif->config_data; - if (ss == NULL) { - ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL); - if (ss == NULL) - return -ENOMEM; - hwif->config_data = (unsigned long)ss; - } - ss = (sc1200_saved_state_t *)hwif->config_data; - // - // Save timing registers: this may be unnecessary if - // BIOS also does it - // - basereg = hwif->channel ? 0x50 : 0x40; - for (r = 0; r < 4; ++r) { - pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]); - } + struct sc1200_saved_state *ss; + unsigned int r; + + /* + * allocate a permanent save area, if not already allocated + */ + ss = (struct sc1200_saved_state *)pci_get_drvdata(dev); + if (ss == NULL) { + ss = kmalloc(sizeof(*ss), GFP_KERNEL); + if (ss == NULL) + return -ENOMEM; + pci_set_drvdata(dev, ss); } - } - /* You don't need to iterate over disks -- sysfs should have done that for you already */ + /* + * save timing registers + * (this may be unnecessary if BIOS also does it) + */ + for (r = 0; r < 8; r++) + pci_read_config_dword(dev, 0x40 + r * 4, &ss->regs[r]); + } pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); @@ -328,30 +271,25 @@ static int sc1200_suspend (struct pci_dev *dev, pm_message_t state) static int sc1200_resume (struct pci_dev *dev) { - ide_hwif_t *hwif = NULL; - int i; + struct sc1200_saved_state *ss; + unsigned int r; + int i; i = pci_enable_device(dev); if (i) return i; - // - // loop over all interfaces that are part of this pci device: - // - while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { - unsigned int basereg, r; - sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data; - - // - // Restore timing registers: this may be unnecessary if BIOS also does it - // - basereg = hwif->channel ? 0x50 : 0x40; - if (ss != NULL) { - for (r = 0; r < 4; ++r) { - pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]); - } - } + ss = (struct sc1200_saved_state *)pci_get_drvdata(dev); + + /* + * restore timing registers + * (this may be unnecessary if BIOS also does it) + */ + if (ss) { + for (r = 0; r < 8; r++) + pci_write_config_dword(dev, 0x40 + r * 4, ss->regs[r]); } + return 0; } #endif diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c index ebb7132b9b84..24a85bbcd2a6 100644 --- a/drivers/ide/pci/scc_pata.c +++ b/drivers/ide/pci/scc_pata.c @@ -254,19 +254,7 @@ static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) offset = 0; /* 100MHz */ } - switch (speed) { - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - idx = speed - XFER_UDMA_0; - break; - default: - return; - } + idx = speed - XFER_UDMA_0; jcactsel = JCACTSELtbl[offset][idx]; if (is_slave) { diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c index a7280311357b..877c09bf4829 100644 --- a/drivers/ide/pci/serverworks.c +++ b/drivers/ide/pci/serverworks.c @@ -164,25 +164,12 @@ static void svwks_set_dma_mode(ide_drive_t *drive, const u8 speed) ultra_timing &= ~(0x0F << (4*unit)); ultra_enable &= ~(0x01 << drive->dn); - switch(speed) { - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - dma_timing |= dma_modes[speed - XFER_MW_DMA_0]; - break; - - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - dma_timing |= dma_modes[2]; - ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit)); - ultra_enable |= (0x01 << drive->dn); - default: - break; - } + if (speed >= XFER_UDMA_0) { + dma_timing |= dma_modes[2]; + ultra_timing |= (udma_modes[speed - XFER_UDMA_0] << (4 * unit)); + ultra_enable |= (0x01 << drive->dn); + } else if (speed >= XFER_MW_DMA_0) + dma_timing |= dma_modes[speed - XFER_MW_DMA_0]; pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); @@ -366,12 +353,17 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif) } } +#define IDE_HFLAGS_SVWKS \ + (IDE_HFLAG_LEGACY_IRQS | \ + IDE_HFLAG_ABUSE_SET_DMA_MODE | \ + IDE_HFLAG_BOOTABLE) + static const struct ide_port_info serverworks_chipsets[] __devinitdata = { { /* 0 */ .name = "SvrWks OSB4", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE, + .host_flags = IDE_HFLAGS_SVWKS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = 0x00, /* UDMA is problematic on OSB4 */ @@ -379,7 +371,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks CSB5", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE, + .host_flags = IDE_HFLAGS_SVWKS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -387,7 +379,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks CSB6", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_BOOTABLE, + .host_flags = IDE_HFLAGS_SVWKS, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -395,8 +387,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks CSB6", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE | - IDE_HFLAG_BOOTABLE, + .host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, @@ -404,8 +395,7 @@ static const struct ide_port_info serverworks_chipsets[] __devinitdata = { .name = "SvrWks HT1000", .init_chipset = init_chipset_svwks, .init_hwif = init_hwif_svwks, - .host_flags = IDE_HFLAG_LEGACY_IRQS | IDE_HFLAG_SINGLE | - IDE_HFLAG_BOOTABLE, + .host_flags = IDE_HFLAGS_SVWKS | IDE_HFLAG_SINGLE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA5, diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c index de820aa58cd0..9e0be7d54980 100644 --- a/drivers/ide/pci/sgiioc4.c +++ b/drivers/ide/pci/sgiioc4.c @@ -277,21 +277,6 @@ sgiioc4_ide_dma_end(ide_drive_t * drive) return dma_stat; } -static int -sgiioc4_ide_dma_on(ide_drive_t * drive) -{ - drive->using_dma = 1; - - return 0; -} - -static void sgiioc4_dma_off_quietly(ide_drive_t *drive) -{ - drive->using_dma = 0; - - drive->hwif->dma_host_off(drive); -} - static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed) { } @@ -303,13 +288,10 @@ sgiioc4_ide_dma_test_irq(ide_drive_t * drive) return sgiioc4_checkirq(HWIF(drive)); } -static void sgiioc4_dma_host_on(ide_drive_t * drive) -{ -} - -static void sgiioc4_dma_host_off(ide_drive_t * drive) +static void sgiioc4_dma_host_set(ide_drive_t *drive, int on) { - sgiioc4_clearirq(drive); + if (!on) + sgiioc4_clearirq(drive); } static void @@ -582,7 +564,6 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->pre_reset = NULL; /* No HBA specific pre_set needed */ hwif->resetproc = &sgiioc4_resetproc;/* Reset DMA engine, clear interrupts */ - hwif->intrproc = NULL; /* Enable or Disable interrupt from drive */ hwif->maskproc = &sgiioc4_maskproc; /* Mask on/off NIEN register */ hwif->quirkproc = NULL; hwif->busproc = NULL; @@ -594,14 +575,11 @@ ide_init_sgiioc4(ide_hwif_t * hwif) hwif->mwdma_mask = ATA_MWDMA2_ONLY; + hwif->dma_host_set = &sgiioc4_dma_host_set; hwif->dma_setup = &sgiioc4_ide_dma_setup; hwif->dma_start = &sgiioc4_ide_dma_start; hwif->ide_dma_end = &sgiioc4_ide_dma_end; - hwif->ide_dma_on = &sgiioc4_ide_dma_on; - hwif->dma_off_quietly = &sgiioc4_dma_off_quietly; hwif->ide_dma_test_irq = &sgiioc4_ide_dma_test_irq; - hwif->dma_host_on = &sgiioc4_dma_host_on; - hwif->dma_host_off = &sgiioc4_dma_host_off; hwif->dma_lost_irq = &sgiioc4_dma_lost_irq; hwif->dma_timeout = &ide_dma_timeout; } @@ -615,6 +593,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) ide_hwif_t *hwif; int h; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; + hw_regs_t hw; /* * Find an empty HWIF; if none available, return -ENOMEM. @@ -654,21 +633,16 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) return -ENOMEM; } - if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) { - hw_regs_t hw; - - /* Initialize the IO registers */ - memset(&hw, 0, sizeof(hw)); - sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport); - memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; - } + /* Initialize the IO registers */ + memset(&hw, 0, sizeof(hw)); + sgiioc4_init_hwif_ports(&hw, cmd_base, ctl, irqport); + hw.irq = dev->irq; + hw.chipset = ide_pci; + hw.dev = &dev->dev; + ide_init_port_hw(hwif, &hw); - hwif->irq = dev->irq; - hwif->chipset = ide_pci; hwif->pci_dev = dev; hwif->channel = 0; /* Single Channel chip */ - hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */ /* The IOC4 uses MMIO rather than Port IO. */ default_hwif_mmiops(hwif); diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 5709c252543b..908f37b4e0ee 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -278,27 +278,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) scsc = is_sata(hwif) ? 1 : scsc; - switch(speed) { - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - multi = dma[speed - XFER_MW_DMA_0]; - mode |= ((unit) ? 0x20 : 0x02); - break; - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - multi = dma[2]; - ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) : - (ultra5[speed - XFER_UDMA_0])); - mode |= ((unit) ? 0x30 : 0x03); - break; - default: - return; + if (speed >= XFER_UDMA_0) { + multi = dma[2]; + ultra |= (scsc ? ultra6[speed - XFER_UDMA_0] : + ultra5[speed - XFER_UDMA_0]); + mode |= (unit ? 0x30 : 0x03); + } else { + multi = dma[speed - XFER_MW_DMA_0]; + mode |= (unit ? 0x20 : 0x02); } if (hwif->mmio) { @@ -726,9 +713,6 @@ static int is_dev_seagate_sata(ide_drive_t *drive) const char *s = &drive->id->model[0]; unsigned len; - if (!drive->present) - return 0; - len = strnlen(s, sizeof(drive->id->model)); if ((len > 4) && (!memcmp(s, "ST", 2))) { @@ -743,18 +727,20 @@ static int is_dev_seagate_sata(ide_drive_t *drive) } /** - * siimage_fixup - post probe fixups - * @hwif: interface to fix up + * sil_quirkproc - post probe fixups + * @drive: drive * * Called after drive probe we use this to decide whether the * Seagate fixup must be applied. This used to be in init_iops but * that can occur before we know what drives are present. */ -static void __devinit siimage_fixup(ide_hwif_t *hwif) +static void __devinit sil_quirkproc(ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; + /* Try and raise the rqsize */ - if (!is_sata(hwif) || !is_dev_seagate_sata(&hwif->drives[0])) + if (!is_sata(hwif) || !is_dev_seagate_sata(drive)) hwif->rqsize = 128; } @@ -817,6 +803,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) hwif->set_pio_mode = &sil_set_pio_mode; hwif->set_dma_mode = &sil_set_dma_mode; + hwif->quirkproc = &sil_quirkproc; if (sata) { static int first = 1; @@ -855,7 +842,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif) .init_chipset = init_chipset_siimage, \ .init_iops = init_iops_siimage, \ .init_hwif = init_hwif_siimage, \ - .fixup = siimage_fixup, \ .host_flags = IDE_HFLAG_BOOTABLE, \ .pio_mask = ATA_PIO4, \ .mwdma_mask = ATA_MWDMA2, \ diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index d90b42917775..85d36996e6af 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -305,59 +305,56 @@ static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio) sis_program_timings(drive, XFER_PIO_0 + pio); } -static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed) +static void sis_ata133_program_udma_timings(ide_drive_t *drive, const u8 mode) { - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; + struct pci_dev *dev = drive->hwif->pci_dev; + u32 regdw = 0; + u8 drive_pci = sis_ata133_get_base(drive), clk, idx; - /* Config chip for mode */ - switch(speed) { - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - if (chipset_family >= ATA_133) { - u32 regdw = 0; - u8 drive_pci = sis_ata133_get_base(drive); - - pci_read_config_dword(dev, drive_pci, ®dw); - regdw |= 0x04; - regdw &= 0xfffff00f; - /* check if ATA133 enable */ - if (regdw & 0x08) { - regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8; - } else { - regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4; - regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8; - } - pci_write_config_dword(dev, (unsigned long)drive_pci, regdw); - } else { - u8 drive_pci = 0x40 + drive->dn * 2, reg = 0; - - pci_read_config_byte(dev, drive_pci+1, ®); - /* Force the UDMA bit on if we want to use UDMA */ - reg |= 0x80; - /* clean reg cycle time bits */ - reg &= ~((0xFF >> (8 - cycle_time_range[chipset_family])) - << cycle_time_offset[chipset_family]); - /* set reg cycle time bits */ - reg |= cycle_time_value[chipset_family][speed-XFER_UDMA_0] - << cycle_time_offset[chipset_family]; - pci_write_config_byte(dev, drive_pci+1, reg); - } - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - sis_program_timings(drive, speed); - break; - default: - break; - } + pci_read_config_dword(dev, drive_pci, ®dw); + + regdw |= 0x04; + regdw &= 0xfffff00f; + /* check if ATA133 enable */ + clk = (regdw & 0x08) ? ATA_133 : ATA_100; + idx = mode - XFER_UDMA_0; + regdw |= cycle_time_value[clk][idx] << 4; + regdw |= cvs_time_value[clk][idx] << 8; + + pci_write_config_dword(dev, drive_pci, regdw); +} + +static void sis_ata33_program_udma_timings(ide_drive_t *drive, const u8 mode) +{ + struct pci_dev *dev = drive->hwif->pci_dev; + u8 drive_pci = 0x40 + drive->dn * 2, reg = 0, i = chipset_family; + + pci_read_config_byte(dev, drive_pci + 1, ®); + + /* force the UDMA bit on if we want to use UDMA */ + reg |= 0x80; + /* clean reg cycle time bits */ + reg &= ~((0xff >> (8 - cycle_time_range[i])) << cycle_time_offset[i]); + /* set reg cycle time bits */ + reg |= cycle_time_value[i][mode - XFER_UDMA_0] << cycle_time_offset[i]; + + pci_write_config_byte(dev, drive_pci + 1, reg); +} + +static void sis_program_udma_timings(ide_drive_t *drive, const u8 mode) +{ + if (chipset_family >= ATA_133) /* ATA_133 */ + sis_ata133_program_udma_timings(drive, mode); + else /* ATA_33/66/100a/100/133a */ + sis_ata33_program_udma_timings(drive, mode); +} + +static void sis_set_dma_mode(ide_drive_t *drive, const u8 speed) +{ + if (speed >= XFER_UDMA_0) + sis_program_udma_timings(drive, speed); + else + sis_program_timings(drive, speed); } static u8 sis5513_ata133_udma_filter(ide_drive_t *drive) diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c index 147d783f7529..c7a125b66c29 100644 --- a/drivers/ide/pci/sl82c105.c +++ b/drivers/ide/pci/sl82c105.c @@ -13,6 +13,7 @@ * -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org * * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com> + * Copyright (C) 2007 Bartlomiej Zolnierkiewicz */ #include <linux/types.h> @@ -90,14 +91,8 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) drive->drive_data &= 0xffff0000; drive->drive_data |= drv_ctrl; - if (!drive->using_dma) { - /* - * If we are actually using MW DMA, then we can not - * reprogram the interface drive control register. - */ - pci_write_config_word(dev, reg, drv_ctrl); - pci_read_config_word (dev, reg, &drv_ctrl); - } + pci_write_config_word(dev, reg, drv_ctrl); + pci_read_config_word (dev, reg, &drv_ctrl); printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name, ide_xfer_verbose(pio + XFER_PIO_0), @@ -115,33 +110,14 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n", drive->name, ide_xfer_verbose(speed))); - switch (speed) { - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0]; + drv_ctrl = mwdma_timings[speed - XFER_MW_DMA_0]; - /* - * Store the DMA timings so that we can actually program - * them when DMA will be turned on... - */ - drive->drive_data &= 0x0000ffff; - drive->drive_data |= (unsigned long)drv_ctrl << 16; - - /* - * If we are already using DMA, we just reprogram - * the drive control register. - */ - if (drive->using_dma) { - struct pci_dev *dev = HWIF(drive)->pci_dev; - int reg = 0x44 + drive->dn * 4; - - pci_write_config_word(dev, reg, drv_ctrl); - } - break; - default: - return; - } + /* + * Store the DMA timings so that we can actually program + * them when DMA will be turned on... + */ + drive->drive_data &= 0x0000ffff; + drive->drive_data |= (unsigned long)drv_ctrl << 16; } /* @@ -209,6 +185,11 @@ static void sl82c105_dma_start(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; + int reg = 0x44 + drive->dn * 4; + + DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name)); + + pci_write_config_word(dev, reg, drive->drive_data >> 16); sl82c105_reset_host(dev); ide_dma_start(drive); @@ -222,64 +203,24 @@ static void sl82c105_dma_timeout(ide_drive_t *drive) ide_dma_timeout(drive); } -static int sl82c105_ide_dma_on(ide_drive_t *drive) -{ - struct pci_dev *dev = HWIF(drive)->pci_dev; - int rc, reg = 0x44 + drive->dn * 4; - - DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name)); - - rc = __ide_dma_on(drive); - if (rc == 0) { - pci_write_config_word(dev, reg, drive->drive_data >> 16); - - printk(KERN_INFO "%s: DMA enabled\n", drive->name); - } - return rc; -} - -static void sl82c105_dma_off_quietly(ide_drive_t *drive) +static int sl82c105_dma_end(ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; int reg = 0x44 + drive->dn * 4; + int ret; - DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name)); + DBG(("%s(drive:%s)\n", __FUNCTION__, drive->name)); - pci_write_config_word(dev, reg, drive->drive_data); + ret = __ide_dma_end(drive); - ide_dma_off_quietly(drive); -} + pci_write_config_word(dev, reg, drive->drive_data); -/* - * Ok, that is nasty, but we must make sure the DMA timings - * won't be used for a PIO access. The solution here is - * to make sure the 16 bits mode is diabled on the channel - * when DMA is enabled, thus causing the chip to use PIO0 - * timings for those operations. - */ -static void sl82c105_selectproc(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct pci_dev *dev = hwif->pci_dev; - u32 val, old, mask; - - //DBG(("sl82c105_selectproc(drive:%s)\n", drive->name)); - - mask = hwif->channel ? CTRL_P1F16 : CTRL_P0F16; - old = val = (u32)pci_get_drvdata(dev); - if (drive->using_dma) - val &= ~mask; - else - val |= mask; - if (old != val) { - pci_write_config_dword(dev, 0x40, val); - pci_set_drvdata(dev, (void *)val); - } + return ret; } /* * ATA reset will clear the 16 bits mode in the control - * register, we need to update our cache + * register, we need to reprogram it */ static void sl82c105_resetproc(ide_drive_t *drive) { @@ -289,7 +230,8 @@ static void sl82c105_resetproc(ide_drive_t *drive) DBG(("sl82c105_resetproc(drive:%s)\n", drive->name)); pci_read_config_dword(dev, 0x40, &val); - pci_set_drvdata(dev, (void *)val); + val |= (CTRL_P1F16 | CTRL_P0F16); + pci_write_config_dword(dev, 0x40, val); } /* @@ -342,7 +284,6 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c pci_read_config_dword(dev, 0x40, &val); val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16; pci_write_config_dword(dev, 0x40, val); - pci_set_drvdata(dev, (void *)val); return dev->irq; } @@ -358,7 +299,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) hwif->set_pio_mode = &sl82c105_set_pio_mode; hwif->set_dma_mode = &sl82c105_set_dma_mode; - hwif->selectproc = &sl82c105_selectproc; hwif->resetproc = &sl82c105_resetproc; if (!hwif->dma_base) @@ -377,10 +317,9 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif) hwif->mwdma_mask = ATA_MWDMA2; - hwif->ide_dma_on = &sl82c105_ide_dma_on; - hwif->dma_off_quietly = &sl82c105_dma_off_quietly; hwif->dma_lost_irq = &sl82c105_dma_lost_irq; hwif->dma_start = &sl82c105_dma_start; + hwif->ide_dma_end = &sl82c105_dma_end; hwif->dma_timeout = &sl82c105_dma_timeout; if (hwif->mate) diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index eb4445b229ed..dbbb46819a2d 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -91,19 +91,9 @@ static void slc90e66_set_dma_mode(ide_drive_t *drive, const u8 speed) pci_read_config_word(dev, 0x48, ®48); pci_read_config_word(dev, 0x4a, ®4a); - switch(speed) { - case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break; - case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break; - case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; - case XFER_UDMA_1: u_speed = 1 << (drive->dn * 4); break; - case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_SW_DMA_2: break; - default: return; - } - if (speed >= XFER_UDMA_0) { + u_speed = (speed - XFER_UDMA_0) << (drive->dn * 4); + if (!(reg48 & u_flag)) pci_write_config_word(dev, 0x48, reg48|u_flag); /* FIXME: (reg4a & a_speed) ? */ diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c index a66ebd14664e..e1faf6c2fe16 100644 --- a/drivers/ide/pci/tc86c001.c +++ b/drivers/ide/pci/tc86c001.c @@ -222,7 +222,8 @@ static const struct ide_port_info tc86c001_chipset __devinitdata = { .name = "TC86C001", .init_chipset = init_chipset_tc86c001, .init_hwif = init_hwif_tc86c001, - .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD, + .host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_OFF_BOARD | + IDE_HFLAG_ABUSE_SET_DMA_MODE, .pio_mask = ATA_PIO4, .mwdma_mask = ATA_MWDMA2, .udma_mask = ATA_UDMA4, diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c index a227c41d23a3..ae52a96a1cf9 100644 --- a/drivers/ide/pci/triflex.c +++ b/drivers/ide/pci/triflex.c @@ -81,8 +81,6 @@ static void triflex_set_mode(ide_drive_t *drive, const u8 speed) case XFER_PIO_0: timing = 0x0808; break; - default: - return; } triflex_timings &= ~(0xFFFF << (16 * unit)); diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c index 0151d7fdfb8a..04cd893e1ab0 100644 --- a/drivers/ide/pci/trm290.c +++ b/drivers/ide/pci/trm290.c @@ -241,11 +241,7 @@ static int trm290_ide_dma_test_irq (ide_drive_t *drive) return (status == 0x00ff); } -static void trm290_dma_host_on(ide_drive_t *drive) -{ -} - -static void trm290_dma_host_off(ide_drive_t *drive) +static void trm290_dma_host_set(ide_drive_t *drive, int on) { } @@ -289,8 +285,7 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif) ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); - hwif->dma_host_off = &trm290_dma_host_off; - hwif->dma_host_on = &trm290_dma_host_on; + hwif->dma_host_set = &trm290_dma_host_set; hwif->dma_setup = &trm290_dma_setup; hwif->dma_exec_cmd = &trm290_dma_exec_cmd; hwif->dma_start = &trm290_dma_start; diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index a0d3c16b68ec..4b32c90f4896 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -439,6 +439,7 @@ static const struct ide_port_info via82cxxx_chipset __devinitdata = { .enablebits = { { 0x40, 0x02, 0x02 }, { 0x40, 0x01, 0x01 } }, .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST | IDE_HFLAG_PIO_NO_DOWNGRADE | + IDE_HFLAG_ABUSE_SET_DMA_MODE | IDE_HFLAG_POST_SET_MODE | IDE_HFLAG_IO_32BIT | IDE_HFLAG_BOOTABLE, diff --git a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile new file mode 100644 index 000000000000..65af5848b28c --- /dev/null +++ b/drivers/ide/ppc/Makefile @@ -0,0 +1,3 @@ + +obj-$(CONFIG_BLK_DEV_IDE_PMAC) += pmac.o +obj-$(CONFIG_BLK_DEV_MPC8xx_IDE) += mpc8xx.o diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index 5f0da35ab5ad..3fd5d45b5e0e 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -838,3 +838,21 @@ void m8xx_ide_init(void) ppc_ide_md.default_io_base = m8xx_ide_default_io_base; ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports; } + +static int __init mpc8xx_ide_probe(void) +{ + u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; + +#ifdef IDE0_BASE_OFFSET + idx[0] = 0; +#ifdef IDE1_BASE_OFFSET + idx[1] = 1; +#endif +#endif + + ide_device_add(idx); + + return 0; +} + +module_init(mpc8xx_ide_probe); diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 7f7a59885777..736d12c8e68a 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -438,13 +438,8 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw, if (data_port == pmac_ide[ix].regbase) break; - if (ix >= MAX_HWIFS) { - /* Probably a PCI interface... */ - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i) - hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET; - hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port; - return; - } + if (ix >= MAX_HWIFS) + return; /* not an IDE PMAC interface */ for (i = 0; i < 8; ++i) hw->io_ports[i] = data_port + i * 0x10; @@ -833,38 +828,20 @@ static void pmac_ide_set_dma_mode(ide_drive_t *drive, const u8 speed) tl[0] = *timings; tl[1] = *timings2; - switch(speed) { #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - case XFER_UDMA_6: - case XFER_UDMA_5: - case XFER_UDMA_4: - case XFER_UDMA_3: - case XFER_UDMA_2: - case XFER_UDMA_1: - case XFER_UDMA_0: - if (pmif->kind == controller_kl_ata4) - ret = set_timings_udma_ata4(&tl[0], speed); - else if (pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6) - ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); - else if (pmif->kind == controller_sh_ata6) - ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); - else - ret = 1; - break; - case XFER_MW_DMA_2: - case XFER_MW_DMA_1: - case XFER_MW_DMA_0: - set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); - break; - case XFER_SW_DMA_2: - case XFER_SW_DMA_1: - case XFER_SW_DMA_0: - return; + if (speed >= XFER_UDMA_0) { + if (pmif->kind == controller_kl_ata4) + ret = set_timings_udma_ata4(&tl[0], speed); + else if (pmif->kind == controller_un_ata6 + || pmif->kind == controller_k2_ata6) + ret = set_timings_udma_ata6(&tl[0], &tl[1], speed); + else if (pmif->kind == controller_sh_ata6) + ret = set_timings_udma_shasta(&tl[0], &tl[1], speed); + else + ret = -1; + } else + set_timings_mdma(drive, pmif->kind, &tl[0], &tl[1], speed); #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ - default: - ret = 1; - } if (ret) return; @@ -1035,12 +1012,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif) * rare machines unfortunately, but it's better this way. */ static int -pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) +pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) { struct device_node *np = pmif->node; const int *bidp; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; - hw_regs_t hw; pmif->cable_80 = 0; pmif->broken_dma = pmif->broken_dma_warn = 0; @@ -1126,11 +1102,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) /* Tell common code _not_ to mess with resources */ hwif->mmio = 1; hwif->hwif_data = pmif; - memset(&hw, 0, sizeof(hw)); - pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, &hwif->irq); - memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports)); - hwif->chipset = ide_pmac; - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || pmif->mediabay; + hw->chipset = ide_pmac; + ide_init_port_hw(hwif, hw); + hwif->noprobe = pmif->mediabay; hwif->hold = pmif->mediabay; hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; hwif->drives[0].unmask = 1; @@ -1159,8 +1133,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) hwif->noprobe = 0; #endif /* CONFIG_PMAC_MEDIABAY */ - hwif->sg_max_nents = MAX_DCMDS; - #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC /* has a DBDMA controller channel */ if (pmif->dma_regs) @@ -1186,6 +1158,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) ide_hwif_t *hwif; pmac_ide_hwif_t *pmif; int i, rc; + hw_regs_t hw; i = 0; while (i < MAX_HWIFS && (ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0 @@ -1228,7 +1201,6 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) regbase = (unsigned long) base; hwif->pci_dev = mdev->bus->pdev; - hwif->gendev.parent = &mdev->ofdev.dev; pmif->mdev = mdev; pmif->node = mdev->ofdev.node; @@ -1246,7 +1218,12 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match) #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ dev_set_drvdata(&mdev->ofdev.dev, hwif); - rc = pmac_ide_setup_device(pmif, hwif); + memset(&hw, 0, sizeof(hw)); + pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL); + hw.irq = irq; + hw.dev = &mdev->ofdev.dev; + + rc = pmac_ide_setup_device(pmif, hwif, &hw); if (rc != 0) { /* The inteface is released to the common IDE layer */ dev_set_drvdata(&mdev->ofdev.dev, NULL); @@ -1305,6 +1282,7 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) void __iomem *base; unsigned long rbase, rlen; int i, rc; + hw_regs_t hw; np = pci_device_to_OF_node(pdev); if (np == NULL) { @@ -1338,7 +1316,6 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) } hwif->pci_dev = pdev; - hwif->gendev.parent = &pdev->dev; pmif->mdev = NULL; pmif->node = np; @@ -1355,7 +1332,12 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_drvdata(pdev, hwif); - rc = pmac_ide_setup_device(pmif, hwif); + memset(&hw, 0, sizeof(hw)); + pmac_ide_init_hwif_ports(&hw, pmif->regbase, 0, NULL); + hw.irq = pdev->irq; + hw.dev = &pdev->dev; + + rc = pmac_ide_setup_device(pmif, hwif, &hw); if (rc != 0) { /* The inteface is released to the common IDE layer */ pci_set_drvdata(pdev, NULL); @@ -1721,11 +1703,7 @@ pmac_ide_dma_test_irq (ide_drive_t *drive) return 1; } -static void pmac_ide_dma_host_off(ide_drive_t *drive) -{ -} - -static void pmac_ide_dma_host_on(ide_drive_t *drive) +static void pmac_ide_dma_host_set(ide_drive_t *drive, int on) { } @@ -1771,15 +1749,14 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) return; } - hwif->dma_off_quietly = &ide_dma_off_quietly; - hwif->ide_dma_on = &__ide_dma_on; + hwif->sg_max_nents = MAX_DCMDS; + + hwif->dma_host_set = &pmac_ide_dma_host_set; hwif->dma_setup = &pmac_ide_dma_setup; hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd; hwif->dma_start = &pmac_ide_dma_start; hwif->ide_dma_end = &pmac_ide_dma_end; hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; - hwif->dma_host_off = &pmac_ide_dma_host_off; - hwif->dma_host_on = &pmac_ide_dma_host_on; hwif->dma_timeout = &ide_dma_timeout; hwif->dma_lost_irq = &pmac_ide_dma_lost_irq; @@ -1809,3 +1786,5 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif) } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ + +module_init(pmac_ide_probe); diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c index d2cd5a3d38f8..676c66e72881 100644 --- a/drivers/ide/setup-pci.c +++ b/drivers/ide/setup-pci.c @@ -165,13 +165,17 @@ static unsigned long ide_get_or_set_dma_base(const struct ide_port_info *d, ide_ dma_base = pci_resource_start(dev, baridx); - if (dma_base == 0) + if (dma_base == 0) { printk(KERN_ERR "%s: DMA base is invalid\n", d->name); + return 0; + } } - if ((d->host_flags & IDE_HFLAG_CS5520) == 0 && dma_base) { + if (hwif->channel) + dma_base += 8; + + if ((d->host_flags & IDE_HFLAG_CS5520) == 0) { u8 simplex_stat = 0; - dma_base += hwif->channel ? 8 : 0; switch(dev->device) { case PCI_DEVICE_ID_AL_M5219: @@ -359,6 +363,8 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port unsigned long ctl = 0, base = 0; ide_hwif_t *hwif; u8 bootable = (d->host_flags & IDE_HFLAG_BOOTABLE) ? 1 : 0; + u8 oldnoprobe = 0; + struct hw_regs_s hw; if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) { /* Possibly we should fail if these checks report true */ @@ -381,26 +387,25 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, const struct ide_port } if ((hwif = ide_match_hwif(base, bootable, d->name)) == NULL) return NULL; /* no room in ide_hwifs[] */ - if (hwif->io_ports[IDE_DATA_OFFSET] != base || - hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) { - hw_regs_t hw; - - memset(&hw, 0, sizeof(hw)); -#ifndef CONFIG_IDE_ARCH_OBSOLETE_INIT - ide_std_init_ports(&hw, base, ctl | 2); -#else - ide_init_hwif_ports(&hw, base, ctl | 2, NULL); -#endif - memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports)); - hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET]; - } - hwif->chipset = d->chipset ? d->chipset : ide_pci; + + memset(&hw, 0, sizeof(hw)); + hw.irq = hwif->irq ? hwif->irq : irq; + hw.dev = &dev->dev; + hw.chipset = d->chipset ? d->chipset : ide_pci; + ide_std_init_ports(&hw, base, ctl | 2); + + if (hwif->io_ports[IDE_DATA_OFFSET] == base && + hwif->io_ports[IDE_CONTROL_OFFSET] == (ctl | 2)) + oldnoprobe = hwif->noprobe; + + ide_init_port_hw(hwif, &hw); + + hwif->noprobe = oldnoprobe; + hwif->pci_dev = dev; hwif->cds = d; hwif->channel = port; - if (!hwif->irq) - hwif->irq = irq; if (mate) { hwif->mate = mate; mate->mate = hwif; @@ -535,12 +540,8 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL) continue; - /* setup proper ancestral information */ - hwif->gendev.parent = &dev->dev; - *(idx + port) = hwif->index; - if (d->init_iops) d->init_iops(hwif); @@ -551,8 +552,6 @@ void ide_pci_setup_ports(struct pci_dev *dev, const struct ide_port_info *d, int (d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS)) hwif->irq = port ? 15 : 14; - hwif->fixup = d->fixup; - hwif->host_flags = d->host_flags; hwif->pio_mask = d->pio_mask; @@ -699,105 +698,3 @@ out: } EXPORT_SYMBOL_GPL(ide_setup_pci_devices); - -#ifdef CONFIG_IDEPCI_PCIBUS_ORDER -/* - * Module interfaces - */ - -static int pre_init = 1; /* Before first ordered IDE scan */ -static LIST_HEAD(ide_pci_drivers); - -/* - * __ide_pci_register_driver - attach IDE driver - * @driver: pci driver - * @module: owner module of the driver - * - * Registers a driver with the IDE layer. The IDE layer arranges that - * boot time setup is done in the expected device order and then - * hands the controllers off to the core PCI code to do the rest of - * the work. - * - * Returns are the same as for pci_register_driver - */ - -int __ide_pci_register_driver(struct pci_driver *driver, struct module *module, - const char *mod_name) -{ - if (!pre_init) - return __pci_register_driver(driver, module, mod_name); - driver->driver.owner = module; - list_add_tail(&driver->node, &ide_pci_drivers); - return 0; -} -EXPORT_SYMBOL_GPL(__ide_pci_register_driver); - -/** - * ide_scan_pcidev - find an IDE driver for a device - * @dev: PCI device to check - * - * Look for an IDE driver to handle the device we are considering. - * This is only used during boot up to get the ordering correct. After - * boot up the pci layer takes over the job. - */ - -static int __init ide_scan_pcidev(struct pci_dev *dev) -{ - struct list_head *l; - struct pci_driver *d; - - list_for_each(l, &ide_pci_drivers) { - d = list_entry(l, struct pci_driver, node); - if (d->id_table) { - const struct pci_device_id *id = - pci_match_id(d->id_table, dev); - - if (id != NULL && d->probe(dev, id) >= 0) { - dev->driver = d; - pci_dev_get(dev); - return 1; - } - } - } - return 0; -} - -/** - * ide_scan_pcibus - perform the initial IDE driver scan - * @scan_direction: set for reverse order scanning - * - * Perform the initial bus rather than driver ordered scan of the - * PCI drivers. After this all IDE pci handling becomes standard - * module ordering not traditionally ordered. - */ - -void __init ide_scan_pcibus (int scan_direction) -{ - struct pci_dev *dev = NULL; - struct pci_driver *d; - struct list_head *l, *n; - - pre_init = 0; - if (!scan_direction) - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev))) - ide_scan_pcidev(dev); - else - while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, - dev))) - ide_scan_pcidev(dev); - - /* - * Hand the drivers over to the PCI layer now we - * are post init. - */ - - list_for_each_safe(l, n, &ide_pci_drivers) { - list_del(l); - d = list_entry(l, struct pci_driver, node); - if (__pci_register_driver(d, d->driver.owner, - d->driver.mod_name)) - printk(KERN_ERR "%s: failed to register %s driver\n", - __FUNCTION__, d->driver.mod_name); - } -} -#endif diff --git a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile index 489c133664d5..1f8153b57503 100644 --- a/drivers/ieee1394/Makefile +++ b/drivers/ieee1394/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o +obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o diff --git a/drivers/ieee1394/init_ohci1394_dma.c b/drivers/ieee1394/init_ohci1394_dma.c new file mode 100644 index 000000000000..ddaab6eb8ace --- /dev/null +++ b/drivers/ieee1394/init_ohci1394_dma.c @@ -0,0 +1,285 @@ +/* + * init_ohci1394_dma.c - Initializes physical DMA on all OHCI 1394 controllers + * + * Copyright (C) 2006-2007 Bernhard Kaindl <bk@suse.de> + * + * Derived from drivers/ieee1394/ohci1394.c and arch/x86/kernel/early-quirks.c + * this file has functions to: + * - scan the PCI very early on boot for all OHCI 1394-compliant controllers + * - reset and initialize them and make them join the IEEE1394 bus and + * - enable physical DMA on them to allow remote debugging + * + * All code and data is marked as __init and __initdata, respective as + * during boot, all OHCI1394 controllers may be claimed by the firewire + * stack and at this point, this code should not touch them anymore. + * + * To use physical DMA after the initialization of the firewire stack, + * be sure that the stack enables it and (re-)attach after the bus reset + * which may be caused by the firewire stack initialization. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/interrupt.h> /* for ohci1394.h */ +#include <linux/delay.h> +#include <linux/pci.h> /* for PCI defines */ +#include <linux/init_ohci1394_dma.h> +#include <asm/pci-direct.h> /* for direct PCI config space access */ +#include <asm/fixmap.h> + +#include "ieee1394_types.h" +#include "ohci1394.h" + +int __initdata init_ohci1394_dma_early; + +/* Reads a PHY register of an OHCI-1394 controller */ +static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr) +{ + int i; + quadlet_t r; + + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) + break; + mdelay(1); + } + r = reg_read(ohci, OHCI1394_PhyControl); + + return (r & 0x00ff0000) >> 16; +} + +/* Writes to a PHY register of an OHCI-1394 controller */ +static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) +{ + int i; + + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + u32 r = reg_read(ohci, OHCI1394_PhyControl); + if (!(r & 0x00004000)) + break; + mdelay(1); + } +} + +/* Resets an OHCI-1394 controller (for sane state before initialization) */ +static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) { + int i; + + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (!(reg_read(ohci, OHCI1394_HCControlSet) + & OHCI1394_HCControl_softReset)) + break; + mdelay(1); + } +} + +/* Basic OHCI-1394 register and port inititalization */ +static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci) +{ + quadlet_t bus_options; + int num_ports, i; + + /* Put some defaults to these undefined bus options */ + bus_options = reg_read(ohci, OHCI1394_BusOptions); + bus_options |= 0x60000000; /* Enable CMC and ISC */ + bus_options &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ + bus_options &= ~0x18000000; /* Disable PMC and BMC */ + reg_write(ohci, OHCI1394_BusOptions, bus_options); + + /* Set the bus number */ + reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); + + /* Enable posted writes */ + reg_write(ohci, OHCI1394_HCControlSet, + OHCI1394_HCControl_postedWriteEnable); + + /* Clear link control register */ + reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); + + /* enable phys */ + reg_write(ohci, OHCI1394_LinkControlSet, + OHCI1394_LinkControl_RcvPhyPkt); + + /* Don't accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); + + /* Clear the Isochonouys interrupt masks */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); + + /* Accept asyncronous transfer requests from all nodes for now */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000); + + /* Specify asyncronous transfer retries */ + reg_write(ohci, OHCI1394_ATRetries, + OHCI1394_MAX_AT_REQ_RETRIES | + (OHCI1394_MAX_AT_RESP_RETRIES<<4) | + (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); + + /* We don't want hardware swapping */ + reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap); + + /* Enable link */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); + + /* If anything is connected to a port, make sure it is enabled */ + num_ports = get_phy_reg(ohci, 2) & 0xf; + for (i = 0; i < num_ports; i++) { + unsigned int status; + + set_phy_reg(ohci, 7, i); + status = get_phy_reg(ohci, 8); + + if (status & 0x20) + set_phy_reg(ohci, 8, status & ~1); + } +} + +/** + * init_ohci1394_wait_for_busresets - wait until bus resets are completed + * + * OHCI1394 initialization itself and any device going on- or offline + * and any cable issue cause a IEEE1394 bus reset. The OHCI1394 spec + * specifies that physical DMA is disabled on each bus reset and it + * has to be enabled after each bus reset when needed. We resort + * to polling here because on early boot, we have no interrupts. + */ +static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci) +{ + int i, events; + + for (i=0; i < 9; i++) { + mdelay(200); + events = reg_read(ohci, OHCI1394_IntEventSet); + if (events & OHCI1394_busReset) + reg_write(ohci, OHCI1394_IntEventClear, + OHCI1394_busReset); + } +} + +/** + * init_ohci1394_enable_physical_dma - Enable physical DMA for remote debugging + * This enables remote DMA access over IEEE1394 from every host for the low + * 4GB of address space. DMA accesses above 4GB are not available currently. + */ +static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci) +{ + reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff); + reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff); + reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000); +} + +/** + * init_ohci1394_reset_and_init_dma - init controller and enable DMA + * This initializes the given controller and enables physical DMA engine in it. + */ +static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci) +{ + /* Start off with a soft reset, clears everything to a sane state. */ + init_ohci1394_soft_reset(ohci); + + /* Accessing some registers without LPS enabled may cause lock up */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); + + /* Disable and clear interrupts */ + reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); + + mdelay(50); /* Wait 50msec to make sure we have full link enabled */ + + init_ohci1394_initialize(ohci); + /* + * The initialization causes at least one IEEE1394 bus reset. Enabling + * physical DMA only works *after* *all* bus resets have calmed down: + */ + init_ohci1394_wait_for_busresets(ohci); + + /* We had to wait and do this now if we want to debug early problems */ + init_ohci1394_enable_physical_dma(ohci); +} + +/** + * init_ohci1394_controller - Map the registers of the controller and init DMA + * This maps the registers of the specified controller and initializes it + */ +static inline void __init init_ohci1394_controller(int num, int slot, int func) +{ + unsigned long ohci_base; + struct ti_ohci ohci; + + printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394" + " at %02x:%02x.%x\n", num, slot, func); + + ohci_base = read_pci_config(num, slot, func, PCI_BASE_ADDRESS_0+(0<<2)) + & PCI_BASE_ADDRESS_MEM_MASK; + + set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base); + + ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE); + + init_ohci1394_reset_and_init_dma(&ohci); +} + +/** + * debug_init_ohci1394_dma - scan for OHCI1394 controllers and init DMA on them + * Scans the whole PCI space for OHCI1394 controllers and inits DMA on them + */ +void __init init_ohci1394_dma_on_all_controllers(void) +{ + int num, slot, func; + + if (!early_pci_allowed()) + return; + + /* Poor man's PCI discovery, the only thing we can do at early boot */ + for (num = 0; num < 32; num++) { + for (slot = 0; slot < 32; slot++) { + for (func = 0; func < 8; func++) { + u32 class = read_pci_config(num,slot,func, + PCI_CLASS_REVISION); + if ((class == 0xffffffff)) + continue; /* No device at this func */ + + if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI) + continue; /* Not an OHCI-1394 device */ + + init_ohci1394_controller(num, slot, func); + break; /* Assume one controller per device */ + } + } + } + printk(KERN_INFO "init_ohci1394_dma: finished initializing OHCI DMA\n"); +} + +/** + * setup_init_ohci1394_early - enables early OHCI1394 DMA initialization + */ +static int __init setup_ohci1394_dma(char *opt) +{ + if (!strcmp(opt, "early")) + init_ohci1394_dma_early = 1; + return 0; +} + +/* passing ohci1394_dma=early on boot causes early OHCI1394 DMA initialization */ +early_param("ohci1394_dma", setup_ohci1394_dma); diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 90dc75be3418..511e4321c6b6 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -727,33 +727,31 @@ static int nodemgr_bus_match(struct device * dev, struct device_driver * drv) static DEFINE_MUTEX(nodemgr_serialize_remove_uds); +static int __match_ne(struct device *dev, void *data) +{ + struct unit_directory *ud; + struct node_entry *ne = (struct node_entry *)data; + + ud = container_of(dev, struct unit_directory, unit_dev); + return ud->ne == ne; +} + static void nodemgr_remove_uds(struct node_entry *ne) { struct device *dev; - struct unit_directory *tmp, *ud; - - /* Iteration over nodemgr_ud_class.devices has to be protected by - * nodemgr_ud_class.sem, but device_unregister() will eventually - * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time, - * release the semaphore, and then unregister the ud. Since this code - * may be called from other contexts besides the knodemgrds, protect the - * gap after release of the semaphore by nodemgr_serialize_remove_uds. + struct unit_directory *ud; + + /* Use class_find device to iterate the devices. Since this code + * may be called from other contexts besides the knodemgrds, + * protect it by nodemgr_serialize_remove_uds. */ mutex_lock(&nodemgr_serialize_remove_uds); for (;;) { - ud = NULL; - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - tmp = container_of(dev, struct unit_directory, - unit_dev); - if (tmp->ne == ne) { - ud = tmp; - break; - } - } - up(&nodemgr_ud_class.sem); - if (ud == NULL) + dev = class_find_device(&nodemgr_ud_class, ne, __match_ne); + if (!dev) break; + ud = container_of(dev, struct unit_directory, unit_dev); + put_device(dev); device_unregister(&ud->unit_dev); device_unregister(&ud->device); } @@ -882,45 +880,66 @@ fail_alloc: return NULL; } +static int __match_ne_guid(struct device *dev, void *data) +{ + struct node_entry *ne; + u64 *guid = (u64 *)data; + + ne = container_of(dev, struct node_entry, node_dev); + return ne->guid == *guid; +} static struct node_entry *find_entry_by_guid(u64 guid) { struct device *dev; - struct node_entry *ne, *ret_ne = NULL; - - down(&nodemgr_ne_class.sem); - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); + struct node_entry *ne; - if (ne->guid == guid) { - ret_ne = ne; - break; - } - } - up(&nodemgr_ne_class.sem); + dev = class_find_device(&nodemgr_ne_class, &guid, __match_ne_guid); + if (!dev) + return NULL; + ne = container_of(dev, struct node_entry, node_dev); + put_device(dev); - return ret_ne; + return ne; } +struct match_nodeid_param { + struct hpsb_host *host; + nodeid_t nodeid; +}; + +static int __match_ne_nodeid(struct device *dev, void *data) +{ + int found = 0; + struct node_entry *ne; + struct match_nodeid_param *param = (struct match_nodeid_param *)data; + + if (!dev) + goto ret; + ne = container_of(dev, struct node_entry, node_dev); + if (ne->host == param->host && ne->nodeid == param->nodeid) + found = 1; +ret: + return found; +} static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid) { struct device *dev; - struct node_entry *ne, *ret_ne = NULL; + struct node_entry *ne; + struct match_nodeid_param param; - down(&nodemgr_ne_class.sem); - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); + param.host = host; + param.nodeid = nodeid; - if (ne->host == host && ne->nodeid == nodeid) { - ret_ne = ne; - break; - } - } - up(&nodemgr_ne_class.sem); + dev = class_find_device(&nodemgr_ne_class, ¶m, __match_ne_nodeid); + if (!dev) + return NULL; + ne = container_of(dev, struct node_entry, node_dev); + put_device(dev); - return ret_ne; + return ne; } @@ -1370,107 +1389,109 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) } } - -static void nodemgr_suspend_ne(struct node_entry *ne) +static int __nodemgr_driver_suspend(struct device *dev, void *data) { - struct device *dev; struct unit_directory *ud; struct device_driver *drv; + struct node_entry *ne = (struct node_entry *)data; int error; - HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", - NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); + ud = container_of(dev, struct unit_directory, unit_dev); + if (ud->ne == ne) { + drv = get_driver(ud->device.driver); + if (drv) { + error = 1; /* release if suspend is not implemented */ + if (drv->suspend) { + down(&ud->device.sem); + error = drv->suspend(&ud->device, PMSG_SUSPEND); + up(&ud->device.sem); + } + if (error) + device_release_driver(&ud->device); + put_driver(drv); + } + } - ne->in_limbo = 1; - WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); + return 0; +} - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne != ne) - continue; +static int __nodemgr_driver_resume(struct device *dev, void *data) +{ + struct unit_directory *ud; + struct device_driver *drv; + struct node_entry *ne = (struct node_entry *)data; + ud = container_of(dev, struct unit_directory, unit_dev); + if (ud->ne == ne) { drv = get_driver(ud->device.driver); - if (!drv) - continue; - - error = 1; /* release if suspend is not implemented */ - if (drv->suspend) { - down(&ud->device.sem); - error = drv->suspend(&ud->device, PMSG_SUSPEND); - up(&ud->device.sem); + if (drv) { + if (drv->resume) { + down(&ud->device.sem); + drv->resume(&ud->device); + up(&ud->device.sem); + } + put_driver(drv); } - if (error) - device_release_driver(&ud->device); - put_driver(drv); } - up(&nodemgr_ud_class.sem); -} + return 0; +} -static void nodemgr_resume_ne(struct node_entry *ne) +static void nodemgr_suspend_ne(struct node_entry *ne) { - struct device *dev; - struct unit_directory *ud; - struct device_driver *drv; + HPSB_DEBUG("Node suspended: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + NODE_BUS_ARGS(ne->host, ne->nodeid), + (unsigned long long)ne->guid); - ne->in_limbo = 0; - device_remove_file(&ne->device, &dev_attr_ne_in_limbo); + ne->in_limbo = 1; + WARN_ON(device_create_file(&ne->device, &dev_attr_ne_in_limbo)); - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne != ne) - continue; + class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_suspend); +} - drv = get_driver(ud->device.driver); - if (!drv) - continue; - if (drv->resume) { - down(&ud->device.sem); - drv->resume(&ud->device); - up(&ud->device.sem); - } - put_driver(drv); - } - up(&nodemgr_ud_class.sem); +static void nodemgr_resume_ne(struct node_entry *ne) +{ + ne->in_limbo = 0; + device_remove_file(&ne->device, &dev_attr_ne_in_limbo); + class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_driver_resume); HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); } - -static void nodemgr_update_pdrv(struct node_entry *ne) +static int __nodemgr_update_pdrv(struct device *dev, void *data) { - struct device *dev; struct unit_directory *ud; struct device_driver *drv; struct hpsb_protocol_driver *pdrv; + struct node_entry *ne = (struct node_entry *)data; int error; - down(&nodemgr_ud_class.sem); - list_for_each_entry(dev, &nodemgr_ud_class.devices, node) { - ud = container_of(dev, struct unit_directory, unit_dev); - if (ud->ne != ne) - continue; - + ud = container_of(dev, struct unit_directory, unit_dev); + if (ud->ne == ne) { drv = get_driver(ud->device.driver); - if (!drv) - continue; - - error = 0; - pdrv = container_of(drv, struct hpsb_protocol_driver, driver); - if (pdrv->update) { - down(&ud->device.sem); - error = pdrv->update(ud); - up(&ud->device.sem); + if (drv) { + error = 0; + pdrv = container_of(drv, struct hpsb_protocol_driver, + driver); + if (pdrv->update) { + down(&ud->device.sem); + error = pdrv->update(ud); + up(&ud->device.sem); + } + if (error) + device_release_driver(&ud->device); + put_driver(drv); } - if (error) - device_release_driver(&ud->device); - put_driver(drv); } - up(&nodemgr_ud_class.sem); + + return 0; +} + +static void nodemgr_update_pdrv(struct node_entry *ne) +{ + class_for_each_device(&nodemgr_ud_class, ne, __nodemgr_update_pdrv); } @@ -1529,13 +1550,31 @@ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int ge put_device(dev); } +struct probe_param { + struct host_info *hi; + int generation; +}; + +static int __nodemgr_node_probe(struct device *dev, void *data) +{ + struct probe_param *param = (struct probe_param *)data; + struct node_entry *ne; + + ne = container_of(dev, struct node_entry, node_dev); + if (!ne->needs_probe) + nodemgr_probe_ne(param->hi, ne, param->generation); + if (ne->needs_probe) + nodemgr_probe_ne(param->hi, ne, param->generation); + return 0; +} static void nodemgr_node_probe(struct host_info *hi, int generation) { struct hpsb_host *host = hi->host; - struct device *dev; - struct node_entry *ne; + struct probe_param param; + param.hi = hi; + param.generation = generation; /* Do some processing of the nodes we've probed. This pulls them * into the sysfs layer if needed, and can result in processing of * unit-directories, or just updating the node and it's @@ -1545,19 +1584,7 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) * while probes are time-consuming. (Well, those probes need some * improvement...) */ - down(&nodemgr_ne_class.sem); - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); - if (!ne->needs_probe) - nodemgr_probe_ne(hi, ne, generation); - } - list_for_each_entry(dev, &nodemgr_ne_class.devices, node) { - ne = container_of(dev, struct node_entry, node_dev); - if (ne->needs_probe) - nodemgr_probe_ne(hi, ne, generation); - } - up(&nodemgr_ne_class.sem); - + class_for_each_device(&nodemgr_ne_class, ¶m, __nodemgr_node_probe); /* If we had a bus reset while we were scanning the bus, it is * possible that we did not probe all nodes. In that case, we @@ -1757,6 +1784,22 @@ exit: return 0; } +struct host_iter_param { + void *data; + int (*cb)(struct hpsb_host *, void *); +}; + +static int __nodemgr_for_each_host(struct device *dev, void *data) +{ + struct hpsb_host *host; + struct host_iter_param *hip = (struct host_iter_param *)data; + int error = 0; + + host = container_of(dev, struct hpsb_host, host_dev); + error = hip->cb(host, hip->data); + + return error; +} /** * nodemgr_for_each_host - call a function for each IEEE 1394 host * @data: an address to supply to the callback @@ -1771,18 +1814,13 @@ exit: */ int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *)) { - struct device *dev; - struct hpsb_host *host; - int error = 0; - - down(&hpsb_host_class.sem); - list_for_each_entry(dev, &hpsb_host_class.devices, node) { - host = container_of(dev, struct hpsb_host, host_dev); + struct host_iter_param hip; + int error; - if ((error = cb(host, data))) - break; - } - up(&hpsb_host_class.sem); + hip.cb = cb; + hip.data = data; + error = class_for_each_device(&hpsb_host_class, &hip, + __nodemgr_for_each_host); return error; } diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index b83d254bc86e..1eda11abeb1e 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -1963,6 +1963,12 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev) lu->sdev = sdev; sdev->allow_restart = 1; + /* + * Update the dma alignment (minimum alignment requirements for + * start and end of DMA transfers) to be a sector + */ + blk_queue_update_dma_alignment(sdev->request_queue, 511); + if (lu->workarounds & SBP2_WORKAROUND_INQUIRY_36) sdev->inquiry_len = 36; return 0; diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 5381c80de10a..a58ad8a470f9 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -110,7 +110,7 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr) __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr; int ret; - dev = ip_dev_find(ip); + dev = ip_dev_find(&init_net, ip); if (!dev) return -EADDRNOTAVAIL; @@ -158,7 +158,7 @@ static void addr_send_arp(struct sockaddr_in *dst_in) memset(&fl, 0, sizeof fl); fl.nl_u.ip4_u.daddr = dst_ip; - if (ip_route_output_key(&rt, &fl)) + if (ip_route_output_key(&init_net, &rt, &fl)) return; neigh_event_send(rt->u.dst.neighbour, NULL); @@ -179,7 +179,7 @@ static int addr_resolve_remote(struct sockaddr_in *src_in, memset(&fl, 0, sizeof fl); fl.nl_u.ip4_u.daddr = dst_ip; fl.nl_u.ip4_u.saddr = src_ip; - ret = ip_route_output_key(&rt, &fl); + ret = ip_route_output_key(&init_net, &rt, &fl); if (ret) goto out; @@ -261,15 +261,15 @@ static int addr_resolve_local(struct sockaddr_in *src_in, __be32 dst_ip = dst_in->sin_addr.s_addr; int ret; - dev = ip_dev_find(dst_ip); + dev = ip_dev_find(&init_net, dst_ip); if (!dev) return -EADDRNOTAVAIL; - if (ZERONET(src_ip)) { + if (ipv4_is_zeronet(src_ip)) { src_in->sin_family = dst_in->sin_family; src_in->sin_addr.s_addr = dst_ip; ret = rdma_copy_addr(addr, dev, dev->dev_addr); - } else if (LOOPBACK(src_ip)) { + } else if (ipv4_is_loopback(src_ip)) { ret = rdma_translate_ip((struct sockaddr *)dst_in, addr); if (!ret) memcpy(addr->dst_dev_addr, dev->dev_addr, MAX_ADDR_LEN); diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 2e39236d189f..c0150147d347 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006 Intel Corporation. All rights reserved. + * Copyright (c) 2004-2007 Intel Corporation. All rights reserved. * Copyright (c) 2004 Topspin Corporation. All rights reserved. * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. @@ -37,12 +37,14 @@ #include <linux/completion.h> #include <linux/dma-mapping.h> +#include <linux/device.h> #include <linux/err.h> #include <linux/idr.h> #include <linux/interrupt.h> #include <linux/random.h> #include <linux/rbtree.h> #include <linux/spinlock.h> +#include <linux/sysfs.h> #include <linux/workqueue.h> #include <rdma/ib_cache.h> @@ -78,17 +80,94 @@ static struct ib_cm { struct workqueue_struct *wq; } cm; +/* Counter indexes ordered by attribute ID */ +enum { + CM_REQ_COUNTER, + CM_MRA_COUNTER, + CM_REJ_COUNTER, + CM_REP_COUNTER, + CM_RTU_COUNTER, + CM_DREQ_COUNTER, + CM_DREP_COUNTER, + CM_SIDR_REQ_COUNTER, + CM_SIDR_REP_COUNTER, + CM_LAP_COUNTER, + CM_APR_COUNTER, + CM_ATTR_COUNT, + CM_ATTR_ID_OFFSET = 0x0010, +}; + +enum { + CM_XMIT, + CM_XMIT_RETRIES, + CM_RECV, + CM_RECV_DUPLICATES, + CM_COUNTER_GROUPS +}; + +static char const counter_group_names[CM_COUNTER_GROUPS] + [sizeof("cm_rx_duplicates")] = { + "cm_tx_msgs", "cm_tx_retries", + "cm_rx_msgs", "cm_rx_duplicates" +}; + +struct cm_counter_group { + struct kobject obj; + atomic_long_t counter[CM_ATTR_COUNT]; +}; + +struct cm_counter_attribute { + struct attribute attr; + int index; +}; + +#define CM_COUNTER_ATTR(_name, _index) \ +struct cm_counter_attribute cm_##_name##_counter_attr = { \ + .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \ + .index = _index \ +} + +static CM_COUNTER_ATTR(req, CM_REQ_COUNTER); +static CM_COUNTER_ATTR(mra, CM_MRA_COUNTER); +static CM_COUNTER_ATTR(rej, CM_REJ_COUNTER); +static CM_COUNTER_ATTR(rep, CM_REP_COUNTER); +static CM_COUNTER_ATTR(rtu, CM_RTU_COUNTER); +static CM_COUNTER_ATTR(dreq, CM_DREQ_COUNTER); +static CM_COUNTER_ATTR(drep, CM_DREP_COUNTER); +static CM_COUNTER_ATTR(sidr_req, CM_SIDR_REQ_COUNTER); +static CM_COUNTER_ATTR(sidr_rep, CM_SIDR_REP_COUNTER); +static CM_COUNTER_ATTR(lap, CM_LAP_COUNTER); +static CM_COUNTER_ATTR(apr, CM_APR_COUNTER); + +static struct attribute *cm_counter_default_attrs[] = { + &cm_req_counter_attr.attr, + &cm_mra_counter_attr.attr, + &cm_rej_counter_attr.attr, + &cm_rep_counter_attr.attr, + &cm_rtu_counter_attr.attr, + &cm_dreq_counter_attr.attr, + &cm_drep_counter_attr.attr, + &cm_sidr_req_counter_attr.attr, + &cm_sidr_rep_counter_attr.attr, + &cm_lap_counter_attr.attr, + &cm_apr_counter_attr.attr, + NULL +}; + struct cm_port { struct cm_device *cm_dev; struct ib_mad_agent *mad_agent; + struct kobject port_obj; u8 port_num; + struct cm_counter_group counter_group[CM_COUNTER_GROUPS]; }; struct cm_device { struct list_head list; struct ib_device *device; + struct kobject dev_obj; u8 ack_delay; - struct cm_port port[0]; + struct cm_port *port[0]; }; struct cm_av { @@ -278,7 +357,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) list_for_each_entry(cm_dev, &cm.device_list, list) { if (!ib_find_cached_gid(cm_dev->device, &path->sgid, &p, NULL)) { - port = &cm_dev->port[p-1]; + port = cm_dev->port[p-1]; break; } } @@ -1270,6 +1349,9 @@ static void cm_dup_req_handler(struct cm_work *work, struct ib_mad_send_buf *msg = NULL; int ret; + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_REQ_COUNTER]); + /* Quick state check to discard duplicate REQs. */ if (cm_id_priv->id.state == IB_CM_REQ_RCVD) return; @@ -1616,6 +1698,8 @@ static void cm_dup_rep_handler(struct cm_work *work) if (!cm_id_priv) return; + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_REP_COUNTER]); ret = cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg); if (ret) goto deref; @@ -1781,6 +1865,8 @@ static int cm_rtu_handler(struct cm_work *work) if (cm_id_priv->id.state != IB_CM_REP_SENT && cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) { spin_unlock_irq(&cm_id_priv->lock); + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_RTU_COUNTER]); goto out; } cm_id_priv->id.state = IB_CM_ESTABLISHED; @@ -1958,6 +2044,8 @@ static int cm_dreq_handler(struct cm_work *work) cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id, dreq_msg->local_comm_id); if (!cm_id_priv) { + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_DREQ_COUNTER]); cm_issue_drep(work->port, work->mad_recv_wc); return -EINVAL; } @@ -1977,6 +2065,8 @@ static int cm_dreq_handler(struct cm_work *work) case IB_CM_MRA_REP_RCVD: break; case IB_CM_TIMEWAIT: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_DREQ_COUNTER]); if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) goto unlock; @@ -1988,6 +2078,10 @@ static int cm_dreq_handler(struct cm_work *work) if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; + case IB_CM_DREQ_RCVD: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_DREQ_COUNTER]); + goto unlock; default: goto unlock; } @@ -2339,10 +2433,20 @@ static int cm_mra_handler(struct cm_work *work) if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_OTHER || cm_id_priv->id.lap_state != IB_CM_LAP_SENT || ib_modify_mad(cm_id_priv->av.port->mad_agent, - cm_id_priv->msg, timeout)) + cm_id_priv->msg, timeout)) { + if (cm_id_priv->id.lap_state == IB_CM_MRA_LAP_RCVD) + atomic_long_inc(&work->port-> + counter_group[CM_RECV_DUPLICATES]. + counter[CM_MRA_COUNTER]); goto out; + } cm_id_priv->id.lap_state = IB_CM_MRA_LAP_RCVD; break; + case IB_CM_MRA_REQ_RCVD: + case IB_CM_MRA_REP_RCVD: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_MRA_COUNTER]); + /* fall through */ default: goto out; } @@ -2502,6 +2606,8 @@ static int cm_lap_handler(struct cm_work *work) case IB_CM_LAP_IDLE: break; case IB_CM_MRA_LAP_SENT: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_LAP_COUNTER]); if (cm_alloc_response_msg(work->port, work->mad_recv_wc, &msg)) goto unlock; @@ -2515,6 +2621,10 @@ static int cm_lap_handler(struct cm_work *work) if (ib_post_send_mad(msg, NULL)) cm_free_msg(msg); goto deref; + case IB_CM_LAP_RCVD: + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_LAP_COUNTER]); + goto unlock; default: goto unlock; } @@ -2796,6 +2906,8 @@ static int cm_sidr_req_handler(struct cm_work *work) cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv); if (cur_cm_id_priv) { spin_unlock_irq(&cm.lock); + atomic_long_inc(&work->port->counter_group[CM_RECV_DUPLICATES]. + counter[CM_SIDR_REQ_COUNTER]); goto out; /* Duplicate message. */ } cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; @@ -2990,6 +3102,27 @@ static void cm_send_handler(struct ib_mad_agent *mad_agent, struct ib_mad_send_wc *mad_send_wc) { struct ib_mad_send_buf *msg = mad_send_wc->send_buf; + struct cm_port *port; + u16 attr_index; + + port = mad_agent->context; + attr_index = be16_to_cpu(((struct ib_mad_hdr *) + msg->mad)->attr_id) - CM_ATTR_ID_OFFSET; + + /* + * If the send was in response to a received message (context[0] is not + * set to a cm_id), and is not a REJ, then it is a send that was + * manually retried. + */ + if (!msg->context[0] && (attr_index != CM_REJ_COUNTER)) + msg->retries = 1; + + atomic_long_add(1 + msg->retries, + &port->counter_group[CM_XMIT].counter[attr_index]); + if (msg->retries) + atomic_long_add(msg->retries, + &port->counter_group[CM_XMIT_RETRIES]. + counter[attr_index]); switch (mad_send_wc->status) { case IB_WC_SUCCESS: @@ -3148,8 +3281,10 @@ EXPORT_SYMBOL(ib_cm_notify); static void cm_recv_handler(struct ib_mad_agent *mad_agent, struct ib_mad_recv_wc *mad_recv_wc) { + struct cm_port *port = mad_agent->context; struct cm_work *work; enum ib_cm_event_type event; + u16 attr_id; int paths = 0; switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { @@ -3194,6 +3329,10 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, return; } + attr_id = be16_to_cpu(mad_recv_wc->recv_buf.mad->mad_hdr.attr_id); + atomic_long_inc(&port->counter_group[CM_RECV]. + counter[attr_id - CM_ATTR_ID_OFFSET]); + work = kmalloc(sizeof *work + sizeof(struct ib_sa_path_rec) * paths, GFP_KERNEL); if (!work) { @@ -3204,7 +3343,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, INIT_DELAYED_WORK(&work->work, cm_work_handler); work->cm_event.event = event; work->mad_recv_wc = mad_recv_wc; - work->port = (struct cm_port *)mad_agent->context; + work->port = port; queue_delayed_work(cm.wq, &work->work, 0); } @@ -3379,6 +3518,108 @@ static void cm_get_ack_delay(struct cm_device *cm_dev) cm_dev->ack_delay = attr.local_ca_ack_delay; } +static ssize_t cm_show_counter(struct kobject *obj, struct attribute *attr, + char *buf) +{ + struct cm_counter_group *group; + struct cm_counter_attribute *cm_attr; + + group = container_of(obj, struct cm_counter_group, obj); + cm_attr = container_of(attr, struct cm_counter_attribute, attr); + + return sprintf(buf, "%ld\n", + atomic_long_read(&group->counter[cm_attr->index])); +} + +static struct sysfs_ops cm_counter_ops = { + .show = cm_show_counter +}; + +static struct kobj_type cm_counter_obj_type = { + .sysfs_ops = &cm_counter_ops, + .default_attrs = cm_counter_default_attrs +}; + +static void cm_release_port_obj(struct kobject *obj) +{ + struct cm_port *cm_port; + + printk(KERN_ERR "free cm port\n"); + + cm_port = container_of(obj, struct cm_port, port_obj); + kfree(cm_port); +} + +static struct kobj_type cm_port_obj_type = { + .release = cm_release_port_obj +}; + +static void cm_release_dev_obj(struct kobject *obj) +{ + struct cm_device *cm_dev; + + printk(KERN_ERR "free cm dev\n"); + + cm_dev = container_of(obj, struct cm_device, dev_obj); + kfree(cm_dev); +} + +static struct kobj_type cm_dev_obj_type = { + .release = cm_release_dev_obj +}; + +struct class cm_class = { + .name = "infiniband_cm", +}; +EXPORT_SYMBOL(cm_class); + +static void cm_remove_fs_obj(struct kobject *obj) +{ + kobject_put(obj->parent); + kobject_put(obj); +} + +static int cm_create_port_fs(struct cm_port *port) +{ + int i, ret; + + ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type, + kobject_get(&port->cm_dev->dev_obj), + "%d", port->port_num); + if (ret) { + kfree(port); + return ret; + } + + for (i = 0; i < CM_COUNTER_GROUPS; i++) { + ret = kobject_init_and_add(&port->counter_group[i].obj, + &cm_counter_obj_type, + kobject_get(&port->port_obj), + "%s", counter_group_names[i]); + if (ret) + goto error; + } + + return 0; + +error: + while (i--) + cm_remove_fs_obj(&port->counter_group[i].obj); + cm_remove_fs_obj(&port->port_obj); + return ret; + +} + +static void cm_remove_port_fs(struct cm_port *port) +{ + int i; + + for (i = 0; i < CM_COUNTER_GROUPS; i++) + cm_remove_fs_obj(&port->counter_group[i].obj); + + cm_remove_fs_obj(&port->port_obj); +} + static void cm_add_one(struct ib_device *device) { struct cm_device *cm_dev; @@ -3397,7 +3638,7 @@ static void cm_add_one(struct ib_device *device) if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) return; - cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) * + cm_dev = kzalloc(sizeof(*cm_dev) + sizeof(*port) * device->phys_port_cnt, GFP_KERNEL); if (!cm_dev) return; @@ -3405,11 +3646,27 @@ static void cm_add_one(struct ib_device *device) cm_dev->device = device; cm_get_ack_delay(cm_dev); + ret = kobject_init_and_add(&cm_dev->dev_obj, &cm_dev_obj_type, + &cm_class.subsys.kobj, "%s", device->name); + if (ret) { + kfree(cm_dev); + return; + } + set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask); for (i = 1; i <= device->phys_port_cnt; i++) { - port = &cm_dev->port[i-1]; + port = kzalloc(sizeof *port, GFP_KERNEL); + if (!port) + goto error1; + + cm_dev->port[i-1] = port; port->cm_dev = cm_dev; port->port_num = i; + + ret = cm_create_port_fs(port); + if (ret) + goto error1; + port->mad_agent = ib_register_mad_agent(device, i, IB_QPT_GSI, ®_req, @@ -3418,11 +3675,11 @@ static void cm_add_one(struct ib_device *device) cm_recv_handler, port); if (IS_ERR(port->mad_agent)) - goto error1; + goto error2; ret = ib_modify_port(device, i, 0, &port_modify); if (ret) - goto error2; + goto error3; } ib_set_client_data(device, &cm_client, cm_dev); @@ -3431,17 +3688,20 @@ static void cm_add_one(struct ib_device *device) write_unlock_irqrestore(&cm.device_lock, flags); return; -error2: +error3: ib_unregister_mad_agent(port->mad_agent); +error2: + cm_remove_port_fs(port); error1: port_modify.set_port_cap_mask = 0; port_modify.clr_port_cap_mask = IB_PORT_CM_SUP; while (--i) { - port = &cm_dev->port[i-1]; + port = cm_dev->port[i-1]; ib_modify_port(device, port->port_num, 0, &port_modify); ib_unregister_mad_agent(port->mad_agent); + cm_remove_port_fs(port); } - kfree(cm_dev); + cm_remove_fs_obj(&cm_dev->dev_obj); } static void cm_remove_one(struct ib_device *device) @@ -3463,11 +3723,12 @@ static void cm_remove_one(struct ib_device *device) write_unlock_irqrestore(&cm.device_lock, flags); for (i = 1; i <= device->phys_port_cnt; i++) { - port = &cm_dev->port[i-1]; + port = cm_dev->port[i-1]; ib_modify_port(device, port->port_num, 0, &port_modify); ib_unregister_mad_agent(port->mad_agent); + cm_remove_port_fs(port); } - kfree(cm_dev); + cm_remove_fs_obj(&cm_dev->dev_obj); } static int __init ib_cm_init(void) @@ -3488,17 +3749,25 @@ static int __init ib_cm_init(void) idr_pre_get(&cm.local_id_table, GFP_KERNEL); INIT_LIST_HEAD(&cm.timewait_list); - cm.wq = create_workqueue("ib_cm"); - if (!cm.wq) + ret = class_register(&cm_class); + if (ret) return -ENOMEM; + cm.wq = create_workqueue("ib_cm"); + if (!cm.wq) { + ret = -ENOMEM; + goto error1; + } + ret = ib_register_client(&cm_client); if (ret) - goto error; + goto error2; return 0; -error: +error2: destroy_workqueue(cm.wq); +error1: + class_unregister(&cm_class); return ret; } @@ -3519,6 +3788,7 @@ static void __exit ib_cm_cleanup(void) } ib_unregister_client(&cm_client); + class_unregister(&cm_class); idr_destroy(&cm.local_id_table); } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 0751697ef984..1eff1b2c0e08 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -488,7 +488,8 @@ void rdma_destroy_qp(struct rdma_cm_id *id) } EXPORT_SYMBOL(rdma_destroy_qp); -static int cma_modify_qp_rtr(struct rdma_id_private *id_priv) +static int cma_modify_qp_rtr(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) { struct ib_qp_attr qp_attr; int qp_attr_mask, ret; @@ -514,13 +515,16 @@ static int cma_modify_qp_rtr(struct rdma_id_private *id_priv) if (ret) goto out; + if (conn_param) + qp_attr.max_dest_rd_atomic = conn_param->responder_resources; ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); out: mutex_unlock(&id_priv->qp_mutex); return ret; } -static int cma_modify_qp_rts(struct rdma_id_private *id_priv) +static int cma_modify_qp_rts(struct rdma_id_private *id_priv, + struct rdma_conn_param *conn_param) { struct ib_qp_attr qp_attr; int qp_attr_mask, ret; @@ -536,6 +540,8 @@ static int cma_modify_qp_rts(struct rdma_id_private *id_priv) if (ret) goto out; + if (conn_param) + qp_attr.max_rd_atomic = conn_param->initiator_depth; ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); out: mutex_unlock(&id_priv->qp_mutex); @@ -624,7 +630,8 @@ static inline int cma_zero_addr(struct sockaddr *addr) struct in6_addr *ip6; if (addr->sa_family == AF_INET) - return ZERONET(((struct sockaddr_in *) addr)->sin_addr.s_addr); + return ipv4_is_zeronet( + ((struct sockaddr_in *)addr)->sin_addr.s_addr); else { ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr; return (ip6->s6_addr32[0] | ip6->s6_addr32[1] | @@ -634,7 +641,7 @@ static inline int cma_zero_addr(struct sockaddr *addr) static inline int cma_loopback_addr(struct sockaddr *addr) { - return LOOPBACK(((struct sockaddr_in *) addr)->sin_addr.s_addr); + return ipv4_is_loopback(((struct sockaddr_in *) addr)->sin_addr.s_addr); } static inline int cma_any_addr(struct sockaddr *addr) @@ -866,11 +873,11 @@ static int cma_rep_recv(struct rdma_id_private *id_priv) { int ret; - ret = cma_modify_qp_rtr(id_priv); + ret = cma_modify_qp_rtr(id_priv, NULL); if (ret) goto reject; - ret = cma_modify_qp_rts(id_priv); + ret = cma_modify_qp_rts(id_priv, NULL); if (ret) goto reject; @@ -1122,8 +1129,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) cm_id->cm_handler = cma_ib_handler; ret = conn_id->id.event_handler(&conn_id->id, &event); - if (!ret) + if (!ret) { + cma_enable_remove(conn_id); goto out; + } /* Destroy the CM ID by returning a non-zero value. */ conn_id->cm_id.ib = NULL; @@ -1262,6 +1271,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, struct net_device *dev = NULL; struct rdma_cm_event event; int ret; + struct ib_device_attr attr; listen_id = cm_id->context; if (cma_disable_remove(listen_id, CMA_LISTEN)) @@ -1279,7 +1289,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, atomic_inc(&conn_id->dev_remove); conn_id->state = CMA_CONNECT; - dev = ip_dev_find(iw_event->local_addr.sin_addr.s_addr); + dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr); if (!dev) { ret = -EADDRNOTAVAIL; cma_enable_remove(conn_id); @@ -1311,10 +1321,19 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id, sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr; *sin = iw_event->remote_addr; + ret = ib_query_device(conn_id->id.device, &attr); + if (ret) { + cma_enable_remove(conn_id); + rdma_destroy_id(new_cm_id); + goto out; + } + memset(&event, 0, sizeof event); event.event = RDMA_CM_EVENT_CONNECT_REQUEST; event.param.conn.private_data = iw_event->private_data; event.param.conn.private_data_len = iw_event->private_data_len; + event.param.conn.initiator_depth = attr.max_qp_init_rd_atom; + event.param.conn.responder_resources = attr.max_qp_rd_atom; ret = conn_id->id.event_handler(&conn_id->id, &event); if (ret) { /* User wants to destroy the CM ID */ @@ -2272,7 +2291,7 @@ static int cma_connect_iw(struct rdma_id_private *id_priv, sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr; cm_id->remote_addr = *sin; - ret = cma_modify_qp_rtr(id_priv); + ret = cma_modify_qp_rtr(id_priv, conn_param); if (ret) goto out; @@ -2335,25 +2354,15 @@ static int cma_accept_ib(struct rdma_id_private *id_priv, struct rdma_conn_param *conn_param) { struct ib_cm_rep_param rep; - struct ib_qp_attr qp_attr; - int qp_attr_mask, ret; - - if (id_priv->id.qp) { - ret = cma_modify_qp_rtr(id_priv); - if (ret) - goto out; + int ret; - qp_attr.qp_state = IB_QPS_RTS; - ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, &qp_attr, - &qp_attr_mask); - if (ret) - goto out; + ret = cma_modify_qp_rtr(id_priv, conn_param); + if (ret) + goto out; - qp_attr.max_rd_atomic = conn_param->initiator_depth; - ret = ib_modify_qp(id_priv->id.qp, &qp_attr, qp_attr_mask); - if (ret) - goto out; - } + ret = cma_modify_qp_rts(id_priv, conn_param); + if (ret) + goto out; memset(&rep, 0, sizeof rep); rep.qp_num = id_priv->qp_num; @@ -2378,7 +2387,7 @@ static int cma_accept_iw(struct rdma_id_private *id_priv, struct iw_cm_conn_param iw_param; int ret; - ret = cma_modify_qp_rtr(id_priv); + ret = cma_modify_qp_rtr(id_priv, conn_param); if (ret) return ret; @@ -2598,11 +2607,9 @@ static void cma_set_mgid(struct rdma_id_private *id_priv, /* IPv6 address is an SA assigned MGID. */ memcpy(mgid, &sin6->sin6_addr, sizeof *mgid); } else { - ip_ib_mc_map(sin->sin_addr.s_addr, mc_map); + ip_ib_mc_map(sin->sin_addr.s_addr, dev_addr->broadcast, mc_map); if (id_priv->id.ps == RDMA_PS_UDP) mc_map[7] = 0x01; /* Use RDMA CM signature */ - mc_map[8] = ib_addr_get_pkey(dev_addr) >> 8; - mc_map[9] = (unsigned char) ib_addr_get_pkey(dev_addr); *mgid = *(union ib_gid *) (mc_map + 4); } } diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index e8d5f6b64998..6c7aa59794d4 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -139,7 +139,7 @@ static inline struct ib_pool_fmr *ib_fmr_cache_lookup(struct ib_fmr_pool *pool, static void ib_fmr_batch_release(struct ib_fmr_pool *pool) { int ret; - struct ib_pool_fmr *fmr; + struct ib_pool_fmr *fmr, *next; LIST_HEAD(unmap_list); LIST_HEAD(fmr_list); @@ -158,6 +158,20 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool) #endif } + /* + * The free_list may hold FMRs that have been put there + * because they haven't reached the max_remap count. + * Invalidate their mapping as well. + */ + list_for_each_entry_safe(fmr, next, &pool->free_list, list) { + if (fmr->remap_count == 0) + continue; + hlist_del_init(&fmr->cache_node); + fmr->remap_count = 0; + list_add_tail(&fmr->fmr->list, &fmr_list); + list_move(&fmr->list, &unmap_list); + } + list_splice(&pool->dirty_list, &unmap_list); INIT_LIST_HEAD(&pool->dirty_list); pool->dirty_len = 0; @@ -182,8 +196,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) struct ib_fmr_pool *pool = pool_ptr; do { - if (pool->dirty_len >= pool->dirty_watermark || - atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { + if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) < 0) { ib_fmr_batch_release(pool); atomic_inc(&pool->flush_ser); @@ -194,8 +207,7 @@ static int ib_fmr_cleanup_thread(void *pool_ptr) } set_current_state(TASK_INTERRUPTIBLE); - if (pool->dirty_len < pool->dirty_watermark && - atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && + if (atomic_read(&pool->flush_ser) - atomic_read(&pool->req_ser) >= 0 && !kthread_should_stop()) schedule(); __set_current_state(TASK_RUNNING); @@ -369,11 +381,6 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool) i = 0; list_for_each_entry_safe(fmr, tmp, &pool->free_list, list) { - if (fmr->remap_count) { - INIT_LIST_HEAD(&fmr_list); - list_add_tail(&fmr->fmr->list, &fmr_list); - ib_unmap_fmr(&fmr_list); - } ib_dealloc_fmr(fmr->fmr); list_del(&fmr->list); kfree(fmr); @@ -511,8 +518,10 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr) list_add_tail(&fmr->list, &pool->free_list); } else { list_add_tail(&fmr->list, &pool->dirty_list); - ++pool->dirty_len; - wake_up_process(pool->thread); + if (++pool->dirty_len >= pool->dirty_watermark) { + atomic_inc(&pool->req_ser); + wake_up_process(pool->thread); + } } } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 6f4287716ab1..fbe16d5250a4 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -701,7 +701,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, } /* Check to post send on QP or process locally */ - if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD) + if (smi_check_local_smp(smp, device) == IB_SMI_DISCARD && + smi_check_local_returning_smp(smp, device) == IB_SMI_DISCARD) goto out; local = kmalloc(sizeof *local, GFP_ATOMIC); @@ -752,8 +753,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, port_priv = ib_get_mad_port(mad_agent_priv->agent.device, mad_agent_priv->agent.port_num); if (port_priv) { - mad_priv->mad.mad.mad_hdr.tid = - ((struct ib_mad *)smp)->mad_hdr.tid; + memcpy(&mad_priv->mad.mad, smp, sizeof(struct ib_mad)); recv_mad_agent = find_mad_agent(port_priv, &mad_priv->mad.mad); } @@ -1100,7 +1100,9 @@ int ib_post_send_mad(struct ib_mad_send_buf *send_buf, mad_send_wr->tid = ((struct ib_mad_hdr *) send_buf->mad)->tid; /* Timeout will be updated after send completes */ mad_send_wr->timeout = msecs_to_jiffies(send_buf->timeout_ms); - mad_send_wr->retries = send_buf->retries; + mad_send_wr->max_retries = send_buf->retries; + mad_send_wr->retries_left = send_buf->retries; + send_buf->retries = 0; /* Reference for work request to QP + response */ mad_send_wr->refcount = 1 + (mad_send_wr->timeout > 0); mad_send_wr->status = IB_WC_SUCCESS; @@ -1931,15 +1933,6 @@ local: if (port_priv->device->process_mad) { int ret; - if (!response) { - printk(KERN_ERR PFX "No memory for response MAD\n"); - /* - * Is it better to assume that - * it wouldn't be processed ? - */ - goto out; - } - ret = port_priv->device->process_mad(port_priv->device, 0, port_priv->port_num, wc, &recv->grh, @@ -2282,8 +2275,6 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv) /* Empty wait list to prevent receives from finding a request */ list_splice_init(&mad_agent_priv->wait_list, &cancel_list); - /* Empty local completion list as well */ - list_splice_init(&mad_agent_priv->local_list, &cancel_list); spin_unlock_irqrestore(&mad_agent_priv->lock, flags); /* Report all cancelled requests */ @@ -2445,9 +2436,12 @@ static int retry_send(struct ib_mad_send_wr_private *mad_send_wr) { int ret; - if (!mad_send_wr->retries--) + if (!mad_send_wr->retries_left) return -ETIMEDOUT; + mad_send_wr->retries_left--; + mad_send_wr->send_buf.retries++; + mad_send_wr->timeout = msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); if (mad_send_wr->mad_agent_priv->agent.rmpp_version) { diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 9be5cc00a3a9..8b75010016ec 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -131,7 +131,8 @@ struct ib_mad_send_wr_private { struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; __be64 tid; unsigned long timeout; - int retries; + int max_retries; + int retries_left; int retry; int refcount; enum ib_wc_status status; diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index d43bc62005b3..a5e2a310f312 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -684,7 +684,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, if (seg_num > mad_send_wr->last_ack) { adjust_last_ack(mad_send_wr, seg_num); - mad_send_wr->retries = mad_send_wr->send_buf.retries; + mad_send_wr->retries_left = mad_send_wr->max_retries; } mad_send_wr->newwin = newwin; if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) { diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 1bc1fe605282..107f170c57cd 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -73,11 +73,20 @@ struct mcast_device { }; enum mcast_state { - MCAST_IDLE, MCAST_JOINING, MCAST_MEMBER, + MCAST_ERROR, +}; + +enum mcast_group_state { + MCAST_IDLE, MCAST_BUSY, - MCAST_ERROR + MCAST_GROUP_ERROR, + MCAST_PKEY_EVENT +}; + +enum { + MCAST_INVALID_PKEY_INDEX = 0xFFFF }; struct mcast_member; @@ -93,9 +102,10 @@ struct mcast_group { struct mcast_member *last_join; int members[3]; atomic_t refcount; - enum mcast_state state; + enum mcast_group_state state; struct ib_sa_query *query; int query_id; + u16 pkey_index; }; struct mcast_member { @@ -378,9 +388,19 @@ static int fail_join(struct mcast_group *group, struct mcast_member *member, static void process_group_error(struct mcast_group *group) { struct mcast_member *member; - int ret; + int ret = 0; + u16 pkey_index; + + if (group->state == MCAST_PKEY_EVENT) + ret = ib_find_pkey(group->port->dev->device, + group->port->port_num, + be16_to_cpu(group->rec.pkey), &pkey_index); spin_lock_irq(&group->lock); + if (group->state == MCAST_PKEY_EVENT && !ret && + group->pkey_index == pkey_index) + goto out; + while (!list_empty(&group->active_list)) { member = list_entry(group->active_list.next, struct mcast_member, list); @@ -399,6 +419,7 @@ static void process_group_error(struct mcast_group *group) } group->rec.join_state = 0; +out: group->state = MCAST_BUSY; spin_unlock_irq(&group->lock); } @@ -415,9 +436,9 @@ static void mcast_work_handler(struct work_struct *work) retest: spin_lock_irq(&group->lock); while (!list_empty(&group->pending_list) || - (group->state == MCAST_ERROR)) { + (group->state != MCAST_BUSY)) { - if (group->state == MCAST_ERROR) { + if (group->state != MCAST_BUSY) { spin_unlock_irq(&group->lock); process_group_error(group); goto retest; @@ -494,12 +515,19 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec, void *context) { struct mcast_group *group = context; + u16 pkey_index = MCAST_INVALID_PKEY_INDEX; if (status) process_join_error(group, status); else { + ib_find_pkey(group->port->dev->device, group->port->port_num, + be16_to_cpu(rec->pkey), &pkey_index); + spin_lock_irq(&group->port->lock); group->rec = *rec; + if (group->state == MCAST_BUSY && + group->pkey_index == MCAST_INVALID_PKEY_INDEX) + group->pkey_index = pkey_index; if (!memcmp(&mgid0, &group->rec.mgid, sizeof mgid0)) { rb_erase(&group->node, &group->port->table); mcast_insert(group->port, group, 1); @@ -539,6 +567,7 @@ static struct mcast_group *acquire_group(struct mcast_port *port, group->port = port; group->rec.mgid = *mgid; + group->pkey_index = MCAST_INVALID_PKEY_INDEX; INIT_LIST_HEAD(&group->pending_list); INIT_LIST_HEAD(&group->active_list); INIT_WORK(&group->work, mcast_work_handler); @@ -707,7 +736,8 @@ int ib_init_ah_from_mcmember(struct ib_device *device, u8 port_num, } EXPORT_SYMBOL(ib_init_ah_from_mcmember); -static void mcast_groups_lost(struct mcast_port *port) +static void mcast_groups_event(struct mcast_port *port, + enum mcast_group_state state) { struct mcast_group *group; struct rb_node *node; @@ -721,7 +751,8 @@ static void mcast_groups_lost(struct mcast_port *port) atomic_inc(&group->refcount); queue_work(mcast_wq, &group->work); } - group->state = MCAST_ERROR; + if (group->state != MCAST_GROUP_ERROR) + group->state = state; spin_unlock(&group->lock); } spin_unlock_irqrestore(&port->lock, flags); @@ -731,16 +762,20 @@ static void mcast_event_handler(struct ib_event_handler *handler, struct ib_event *event) { struct mcast_device *dev; + int index; dev = container_of(handler, struct mcast_device, event_handler); + index = event->element.port_num - dev->start_port; switch (event->event) { case IB_EVENT_PORT_ERR: case IB_EVENT_LID_CHANGE: case IB_EVENT_SM_CHANGE: case IB_EVENT_CLIENT_REREGISTER: - mcast_groups_lost(&dev->port[event->element.port_num - - dev->start_port]); + mcast_groups_event(&dev->port[index], MCAST_GROUP_ERROR); + break; + case IB_EVENT_PKEY_CHANGE: + mcast_groups_event(&dev->port[index], MCAST_PKEY_EVENT); break; default: break; diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h index 1cfc2984434f..aff96bac49b4 100644 --- a/drivers/infiniband/core/smi.h +++ b/drivers/infiniband/core/smi.h @@ -59,7 +59,8 @@ extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, u8 node_type, int port_num); /* - * Return 1 if the SMP should be handled by the local SMA/SM via process_mad + * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM + * via process_mad */ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp, struct ib_device *device) @@ -71,4 +72,19 @@ static inline enum smi_action smi_check_local_smp(struct ib_smp *smp, (smp->hop_ptr == smp->hop_cnt + 1)) ? IB_SMI_HANDLE : IB_SMI_DISCARD); } + +/* + * Return IB_SMI_HANDLE if the SMP should be handled by the local SMA/SM + * via process_mad + */ +static inline enum smi_action smi_check_local_returning_smp(struct ib_smp *smp, + struct ib_device *device) +{ + /* C14-13:3 -- We're at the end of the DR segment of path */ + /* C14-13:4 -- Hop Pointer == 0 -> give to SM */ + return ((device->process_mad && + ib_get_smp_direction(smp) && + !smp->hop_ptr) ? IB_SMI_HANDLE : IB_SMI_DISCARD); +} + #endif /* __SMI_H_ */ diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 3d4050681325..c864ef70fdf9 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -508,19 +508,10 @@ static int add_port(struct ib_device *device, int port_num) p->ibdev = device; p->port_num = port_num; - p->kobj.ktype = &port_type; - p->kobj.parent = kobject_get(&device->ports_parent); - if (!p->kobj.parent) { - ret = -EBUSY; - goto err; - } - - ret = kobject_set_name(&p->kobj, "%d", port_num); - if (ret) - goto err_put; - - ret = kobject_register(&p->kobj); + ret = kobject_init_and_add(&p->kobj, &port_type, + kobject_get(device->ports_parent), + "%d", port_num); if (ret) goto err_put; @@ -549,6 +540,7 @@ static int add_port(struct ib_device *device, int port_num) list_add_tail(&p->kobj.entry, &device->port_list); + kobject_uevent(&p->kobj, KOBJ_ADD); return 0; err_free_pkey: @@ -570,9 +562,7 @@ err_remove_pma: sysfs_remove_group(&p->kobj, &pma_group); err_put: - kobject_put(&device->ports_parent); - -err: + kobject_put(device->ports_parent); kfree(p); return ret; } @@ -694,16 +684,9 @@ int ib_device_register_sysfs(struct ib_device *device) goto err_unregister; } - device->ports_parent.parent = kobject_get(&class_dev->kobj); - if (!device->ports_parent.parent) { - ret = -EBUSY; - goto err_unregister; - } - ret = kobject_set_name(&device->ports_parent, "ports"); - if (ret) - goto err_put; - ret = kobject_register(&device->ports_parent); - if (ret) + device->ports_parent = kobject_create_and_add("ports", + kobject_get(&class_dev->kobj)); + if (!device->ports_parent) goto err_put; if (device->node_type == RDMA_NODE_IB_SWITCH) { @@ -731,7 +714,7 @@ err_put: sysfs_remove_group(p, &pma_group); sysfs_remove_group(p, &port->pkey_group); sysfs_remove_group(p, &port->gid_group); - kobject_unregister(p); + kobject_put(p); } } @@ -755,10 +738,10 @@ void ib_device_unregister_sysfs(struct ib_device *device) sysfs_remove_group(p, &pma_group); sysfs_remove_group(p, &port->pkey_group); sysfs_remove_group(p, &port->gid_group); - kobject_unregister(p); + kobject_put(p); } - kobject_unregister(&device->ports_parent); + kobject_put(device->ports_parent); class_device_unregister(&device->class_dev); } diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 424983f5b1ee..4291ab42a5b9 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -106,6 +106,9 @@ enum { IB_UCM_MAX_DEVICES = 32 }; +/* ib_cm and ib_user_cm modules share /sys/class/infiniband_cm */ +extern struct class cm_class; + #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR) static void ib_ucm_add_one(struct ib_device *device); @@ -1199,7 +1202,7 @@ static int ib_ucm_close(struct inode *inode, struct file *filp) return 0; } -static void ib_ucm_release_class_dev(struct class_device *class_dev) +static void ucm_release_class_dev(struct class_device *class_dev) { struct ib_ucm_device *dev; @@ -1217,11 +1220,6 @@ static const struct file_operations ucm_fops = { .poll = ib_ucm_poll, }; -static struct class ucm_class = { - .name = "infiniband_cm", - .release = ib_ucm_release_class_dev -}; - static ssize_t show_ibdev(struct class_device *class_dev, char *buf) { struct ib_ucm_device *dev; @@ -1257,9 +1255,10 @@ static void ib_ucm_add_one(struct ib_device *device) if (cdev_add(&ucm_dev->dev, IB_UCM_BASE_DEV + ucm_dev->devnum, 1)) goto err; - ucm_dev->class_dev.class = &ucm_class; + ucm_dev->class_dev.class = &cm_class; ucm_dev->class_dev.dev = device->dma_device; ucm_dev->class_dev.devt = ucm_dev->dev.dev; + ucm_dev->class_dev.release = ucm_release_class_dev; snprintf(ucm_dev->class_dev.class_id, BUS_ID_SIZE, "ucm%d", ucm_dev->devnum); if (class_device_register(&ucm_dev->class_dev)) @@ -1306,40 +1305,34 @@ static int __init ib_ucm_init(void) "infiniband_cm"); if (ret) { printk(KERN_ERR "ucm: couldn't register device number\n"); - goto err; + goto error1; } - ret = class_register(&ucm_class); - if (ret) { - printk(KERN_ERR "ucm: couldn't create class infiniband_cm\n"); - goto err_chrdev; - } - - ret = class_create_file(&ucm_class, &class_attr_abi_version); + ret = class_create_file(&cm_class, &class_attr_abi_version); if (ret) { printk(KERN_ERR "ucm: couldn't create abi_version attribute\n"); - goto err_class; + goto error2; } ret = ib_register_client(&ucm_client); if (ret) { printk(KERN_ERR "ucm: couldn't register client\n"); - goto err_class; + goto error3; } return 0; -err_class: - class_unregister(&ucm_class); -err_chrdev: +error3: + class_remove_file(&cm_class, &class_attr_abi_version); +error2: unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); -err: +error1: return ret; } static void __exit ib_ucm_cleanup(void) { ib_unregister_client(&ucm_client); - class_unregister(&ucm_class); + class_remove_file(&cm_class, &class_attr_abi_version); unregister_chrdev_region(IB_UCM_BASE_DEV, IB_UCM_MAX_DEVICES); idr_destroy(&ctx_id_table); } diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 90d675ad9ec8..15937eb38aae 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -31,6 +31,7 @@ */ #include <linux/completion.h> +#include <linux/file.h> #include <linux/mutex.h> #include <linux/poll.h> #include <linux/idr.h> @@ -991,6 +992,96 @@ out: return ret; } +static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2) +{ + /* Acquire mutex's based on pointer comparison to prevent deadlock. */ + if (file1 < file2) { + mutex_lock(&file1->mut); + mutex_lock(&file2->mut); + } else { + mutex_lock(&file2->mut); + mutex_lock(&file1->mut); + } +} + +static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2) +{ + if (file1 < file2) { + mutex_unlock(&file2->mut); + mutex_unlock(&file1->mut); + } else { + mutex_unlock(&file1->mut); + mutex_unlock(&file2->mut); + } +} + +static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file) +{ + struct ucma_event *uevent, *tmp; + + list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) + if (uevent->ctx == ctx) + list_move_tail(&uevent->list, &file->event_list); +} + +static ssize_t ucma_migrate_id(struct ucma_file *new_file, + const char __user *inbuf, + int in_len, int out_len) +{ + struct rdma_ucm_migrate_id cmd; + struct rdma_ucm_migrate_resp resp; + struct ucma_context *ctx; + struct file *filp; + struct ucma_file *cur_file; + int ret = 0; + + if (copy_from_user(&cmd, inbuf, sizeof(cmd))) + return -EFAULT; + + /* Get current fd to protect against it being closed */ + filp = fget(cmd.fd); + if (!filp) + return -ENOENT; + + /* Validate current fd and prevent destruction of id. */ + ctx = ucma_get_ctx(filp->private_data, cmd.id); + if (IS_ERR(ctx)) { + ret = PTR_ERR(ctx); + goto file_put; + } + + cur_file = ctx->file; + if (cur_file == new_file) { + resp.events_reported = ctx->events_reported; + goto response; + } + + /* + * Migrate events between fd's, maintaining order, and avoiding new + * events being added before existing events. + */ + ucma_lock_files(cur_file, new_file); + mutex_lock(&mut); + + list_move_tail(&ctx->list, &new_file->ctx_list); + ucma_move_events(ctx, new_file); + ctx->file = new_file; + resp.events_reported = ctx->events_reported; + + mutex_unlock(&mut); + ucma_unlock_files(cur_file, new_file); + +response: + if (copy_to_user((void __user *)(unsigned long)cmd.response, + &resp, sizeof(resp))) + ret = -EFAULT; + + ucma_put_ctx(ctx); +file_put: + fput(filp); + return ret; +} + static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) = { @@ -1012,6 +1103,7 @@ static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, + [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id }; static ssize_t ucma_write(struct file *filp, const char __user *buf, diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index b53eac4611de..4e915104ac4c 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -2,6 +2,7 @@ * Copyright (c) 2004 Topspin Communications. All rights reserved. * Copyright (c) 2005 Voltaire, Inc. All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2008 Cisco. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -42,7 +43,7 @@ #include <linux/cdev.h> #include <linux/dma-mapping.h> #include <linux/poll.h> -#include <linux/rwsem.h> +#include <linux/mutex.h> #include <linux/kref.h> #include <linux/compat.h> @@ -94,7 +95,7 @@ struct ib_umad_port { struct class_device *sm_class_dev; struct semaphore sm_sem; - struct rw_semaphore mutex; + struct mutex file_mutex; struct list_head file_list; struct ib_device *ib_dev; @@ -110,11 +111,11 @@ struct ib_umad_device { }; struct ib_umad_file { + struct mutex mutex; struct ib_umad_port *port; struct list_head recv_list; struct list_head send_list; struct list_head port_list; - spinlock_t recv_lock; spinlock_t send_lock; wait_queue_head_t recv_wait; struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; @@ -156,7 +157,7 @@ static int hdr_size(struct ib_umad_file *file) sizeof (struct ib_user_mad_hdr_old); } -/* caller must hold port->mutex at least for reading */ +/* caller must hold file->mutex */ static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) { return file->agents_dead ? NULL : file->agent[id]; @@ -168,32 +169,30 @@ static int queue_packet(struct ib_umad_file *file, { int ret = 1; - down_read(&file->port->mutex); + mutex_lock(&file->mutex); for (packet->mad.hdr.id = 0; packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; packet->mad.hdr.id++) if (agent == __get_agent(file, packet->mad.hdr.id)) { - spin_lock_irq(&file->recv_lock); list_add_tail(&packet->list, &file->recv_list); - spin_unlock_irq(&file->recv_lock); wake_up_interruptible(&file->recv_wait); ret = 0; break; } - up_read(&file->port->mutex); + mutex_unlock(&file->mutex); return ret; } static void dequeue_send(struct ib_umad_file *file, struct ib_umad_packet *packet) - { +{ spin_lock_irq(&file->send_lock); list_del(&packet->list); spin_unlock_irq(&file->send_lock); - } +} static void send_handler(struct ib_mad_agent *agent, struct ib_mad_send_wc *send_wc) @@ -341,10 +340,10 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, if (count < hdr_size(file)) return -EINVAL; - spin_lock_irq(&file->recv_lock); + mutex_lock(&file->mutex); while (list_empty(&file->recv_list)) { - spin_unlock_irq(&file->recv_lock); + mutex_unlock(&file->mutex); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; @@ -353,13 +352,13 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, !list_empty(&file->recv_list))) return -ERESTARTSYS; - spin_lock_irq(&file->recv_lock); + mutex_lock(&file->mutex); } packet = list_entry(file->recv_list.next, struct ib_umad_packet, list); list_del(&packet->list); - spin_unlock_irq(&file->recv_lock); + mutex_unlock(&file->mutex); if (packet->recv_wc) ret = copy_recv_mad(file, buf, packet, count); @@ -368,9 +367,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, if (ret < 0) { /* Requeue packet */ - spin_lock_irq(&file->recv_lock); + mutex_lock(&file->mutex); list_add(&packet->list, &file->recv_list); - spin_unlock_irq(&file->recv_lock); + mutex_unlock(&file->mutex); } else { if (packet->recv_wc) ib_free_recv_mad(packet->recv_wc); @@ -481,7 +480,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, goto err; } - down_read(&file->port->mutex); + mutex_lock(&file->mutex); agent = __get_agent(file, packet->mad.hdr.id); if (!agent) { @@ -577,7 +576,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, if (ret) goto err_send; - up_read(&file->port->mutex); + mutex_unlock(&file->mutex); return count; err_send: @@ -587,7 +586,7 @@ err_msg: err_ah: ib_destroy_ah(ah); err_up: - up_read(&file->port->mutex); + mutex_unlock(&file->mutex); err: kfree(packet); return ret; @@ -613,11 +612,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg, { struct ib_user_mad_reg_req ureq; struct ib_mad_reg_req req; - struct ib_mad_agent *agent; + struct ib_mad_agent *agent = NULL; int agent_id; int ret; - down_write(&file->port->mutex); + mutex_lock(&file->port->file_mutex); + mutex_lock(&file->mutex); if (!file->port->ib_dev) { ret = -EPIPE; @@ -666,13 +666,13 @@ found: send_handler, recv_handler, file); if (IS_ERR(agent)) { ret = PTR_ERR(agent); + agent = NULL; goto out; } if (put_user(agent_id, (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { ret = -EFAULT; - ib_unregister_mad_agent(agent); goto out; } @@ -690,7 +690,13 @@ found: ret = 0; out: - up_write(&file->port->mutex); + mutex_unlock(&file->mutex); + + if (ret && agent) + ib_unregister_mad_agent(agent); + + mutex_unlock(&file->port->file_mutex); + return ret; } @@ -703,7 +709,8 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) if (get_user(id, arg)) return -EFAULT; - down_write(&file->port->mutex); + mutex_lock(&file->port->file_mutex); + mutex_lock(&file->mutex); if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) { ret = -EINVAL; @@ -714,11 +721,13 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg) file->agent[id] = NULL; out: - up_write(&file->port->mutex); + mutex_unlock(&file->mutex); if (agent) ib_unregister_mad_agent(agent); + mutex_unlock(&file->port->file_mutex); + return ret; } @@ -726,12 +735,12 @@ static long ib_umad_enable_pkey(struct ib_umad_file *file) { int ret = 0; - down_write(&file->port->mutex); + mutex_lock(&file->mutex); if (file->already_used) ret = -EINVAL; else file->use_pkey_index = 1; - up_write(&file->port->mutex); + mutex_unlock(&file->mutex); return ret; } @@ -783,7 +792,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) if (!port) return -ENXIO; - down_write(&port->mutex); + mutex_lock(&port->file_mutex); if (!port->ib_dev) { ret = -ENXIO; @@ -797,7 +806,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) goto out; } - spin_lock_init(&file->recv_lock); + mutex_init(&file->mutex); spin_lock_init(&file->send_lock); INIT_LIST_HEAD(&file->recv_list); INIT_LIST_HEAD(&file->send_list); @@ -809,7 +818,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) list_add_tail(&file->port_list, &port->file_list); out: - up_write(&port->mutex); + mutex_unlock(&port->file_mutex); return ret; } @@ -821,7 +830,8 @@ static int ib_umad_close(struct inode *inode, struct file *filp) int already_dead; int i; - down_write(&file->port->mutex); + mutex_lock(&file->port->file_mutex); + mutex_lock(&file->mutex); already_dead = file->agents_dead; file->agents_dead = 1; @@ -834,14 +844,14 @@ static int ib_umad_close(struct inode *inode, struct file *filp) list_del(&file->port_list); - downgrade_write(&file->port->mutex); + mutex_unlock(&file->mutex); if (!already_dead) for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) if (file->agent[i]) ib_unregister_mad_agent(file->agent[i]); - up_read(&file->port->mutex); + mutex_unlock(&file->port->file_mutex); kfree(file); kref_put(&dev->ref, ib_umad_release_dev); @@ -914,10 +924,10 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp) }; int ret = 0; - down_write(&port->mutex); + mutex_lock(&port->file_mutex); if (port->ib_dev) ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); - up_write(&port->mutex); + mutex_unlock(&port->file_mutex); up(&port->sm_sem); @@ -981,7 +991,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, port->ib_dev = device; port->port_num = port_num; init_MUTEX(&port->sm_sem); - init_rwsem(&port->mutex); + mutex_init(&port->file_mutex); INIT_LIST_HEAD(&port->file_list); port->dev = cdev_alloc(); @@ -1052,6 +1062,7 @@ err_cdev: static void ib_umad_kill_port(struct ib_umad_port *port) { struct ib_umad_file *file; + int already_dead; int id; class_set_devdata(port->class_dev, NULL); @@ -1067,42 +1078,22 @@ static void ib_umad_kill_port(struct ib_umad_port *port) umad_port[port->dev_num] = NULL; spin_unlock(&port_lock); - down_write(&port->mutex); + mutex_lock(&port->file_mutex); port->ib_dev = NULL; - /* - * Now go through the list of files attached to this port and - * unregister all of their MAD agents. We need to hold - * port->mutex while doing this to avoid racing with - * ib_umad_close(), but we can't hold the mutex for writing - * while calling ib_unregister_mad_agent(), since that might - * deadlock by calling back into queue_packet(). So we - * downgrade our lock to a read lock, and then drop and - * reacquire the write lock for the next iteration. - * - * We do list_del_init() on the file's list_head so that the - * list_del in ib_umad_close() is still OK, even after the - * file is removed from the list. - */ - while (!list_empty(&port->file_list)) { - file = list_entry(port->file_list.next, struct ib_umad_file, - port_list); - + list_for_each_entry(file, &port->file_list, port_list) { + mutex_lock(&file->mutex); + already_dead = file->agents_dead; file->agents_dead = 1; - list_del_init(&file->port_list); - - downgrade_write(&port->mutex); + mutex_unlock(&file->mutex); for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) if (file->agent[id]) ib_unregister_mad_agent(file->agent[id]); - - up_read(&port->mutex); - down_write(&port->mutex); } - up_write(&port->mutex); + mutex_unlock(&port->file_mutex); clear_bit(port->dev_num, dev_map); } diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile index 36b98989b15e..7e7b5a66f042 100644 --- a/drivers/infiniband/hw/cxgb3/Makefile +++ b/drivers/infiniband/hw/cxgb3/Makefile @@ -1,5 +1,4 @@ -EXTRA_CFLAGS += -I$(TOPDIR)/drivers/net/cxgb3 \ - -I$(TOPDIR)/drivers/infiniband/hw/cxgb3/core +EXTRA_CFLAGS += -Idrivers/net/cxgb3 obj-$(CONFIG_INFINIBAND_CXGB3) += iw_cxgb3.o diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index eec6a30840ca..03c5ff62889a 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -179,7 +179,7 @@ int cxio_create_cq(struct cxio_rdev *rdev_p, struct t3_cq *cq) setup.size = 1UL << cq->size_log2; setup.credits = 65535; setup.credit_thres = 1; - if (rdev_p->t3cdev_p->type == T3B) + if (rdev_p->t3cdev_p->type != T3A) setup.ovfl_mode = 0; else setup.ovfl_mode = 1; @@ -584,7 +584,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr, { u32 i, nr_wqe, copy_len; u8 *copy_data; - u8 wr_len, utx_len; /* lenght in 8 byte flit */ + u8 wr_len, utx_len; /* length in 8 byte flit */ enum t3_wr_flags flag; __be64 *wqe; u64 utx_cmd; diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index c84d4ac49355..969d4d928455 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -315,7 +315,7 @@ struct t3_rdma_init_wr { __be32 ird; __be64 qp_dma_addr; /* 7 */ __be32 qp_dma_size; /* 8 */ - u32 irs; + __be32 irs; }; struct t3_genbit { @@ -324,7 +324,8 @@ struct t3_genbit { }; enum rdma_init_wr_flags { - RECVS_POSTED = 1, + RECVS_POSTED = (1<<0), + PRIV_QP = (1<<1), }; union t3_wr { diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 20ba372dd182..e9a08fa3dffe 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -332,7 +332,7 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip, } }; - if (ip_route_output_flow(&rt, &fl, NULL, 0)) + if (ip_route_output_flow(&init_net, &rt, &fl, NULL, 0)) return NULL; return rt; } @@ -1118,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) status2errno(rpl->status)); connect_reply_upcall(ep, status2errno(rpl->status)); state_set(&ep->com, DEAD); - if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status)) + if (ep->com.tdev->type != T3A && act_open_has_tid(rpl->status)) release_tid(ep->com.tdev, GET_TID(rpl), NULL); cxgb3_free_atid(ep->com.tdev, ep->atid); dst_release(ep->dst); @@ -1249,7 +1249,7 @@ static void reject_cr(struct t3cdev *tdev, u32 hwtid, __be32 peer_ip, skb_trim(skb, sizeof(struct cpl_tid_release)); skb_get(skb); - if (tdev->type == T3B) + if (tdev->type != T3A) release_tid(tdev, hwtid, skb); else { struct cpl_pass_accept_rpl *rpl; diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c index a6c2c4ba29e6..73bfd1656f86 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_mem.c +++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c @@ -122,6 +122,13 @@ int build_phys_page_list(struct ib_phys_buf *buffer_list, *total_size += buffer_list[i].size; if (i > 0) mask |= buffer_list[i].addr; + else + mask |= buffer_list[i].addr & PAGE_MASK; + if (i != num_phys_buf - 1) + mask |= buffer_list[i].addr + buffer_list[i].size; + else + mask |= (buffer_list[i].addr + buffer_list[i].size + + PAGE_SIZE - 1) & PAGE_MASK; } if (*total_size > 0xFFFFFFFFULL) diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index b5436ca92e68..df1838f8f94d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -39,6 +39,7 @@ #include <linux/list.h> #include <linux/spinlock.h> #include <linux/ethtool.h> +#include <linux/rtnetlink.h> #include <asm/io.h> #include <asm/irq.h> @@ -645,7 +646,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (err) goto err; - if (udata && t3b_device(rhp)) { + if (udata && !t3a_device(rhp)) { uresp.pbl_addr = (mhp->attr.pbl_addr - rhp->rdev.rnic_info.pbl_base) >> 3; PDBG("%s user resp pbl_addr 0x%x\n", __FUNCTION__, @@ -1053,7 +1054,9 @@ static ssize_t show_fw_ver(struct class_device *cdev, char *buf) struct net_device *lldev = dev->rdev.t3cdev_p->lldev; PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); + rtnl_lock(); lldev->ethtool_ops->get_drvinfo(lldev, &info); + rtnl_unlock(); return sprintf(buf, "%s\n", info.fw_version); } @@ -1065,7 +1068,9 @@ static ssize_t show_hca(struct class_device *cdev, char *buf) struct net_device *lldev = dev->rdev.t3cdev_p->lldev; PDBG("%s class dev 0x%p\n", __FUNCTION__, cdev); + rtnl_lock(); lldev->ethtool_ops->get_drvinfo(lldev, &info); + rtnl_unlock(); return sprintf(buf, "%s\n", info.driver); } diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index dd89b6b91f9c..ea2cdd73dd85 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -208,36 +208,19 @@ static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list, static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe, struct ib_recv_wr *wr) { - int i, err = 0; - u32 pbl_addr[4]; - u8 page_size[4]; + int i; if (wr->num_sge > T3_MAX_SGE) return -EINVAL; - err = iwch_sgl2pbl_map(rhp, wr->sg_list, wr->num_sge, pbl_addr, - page_size); - if (err) - return err; - wqe->recv.pagesz[0] = page_size[0]; - wqe->recv.pagesz[1] = page_size[1]; - wqe->recv.pagesz[2] = page_size[2]; - wqe->recv.pagesz[3] = page_size[3]; wqe->recv.num_sgle = cpu_to_be32(wr->num_sge); for (i = 0; i < wr->num_sge; i++) { wqe->recv.sgl[i].stag = cpu_to_be32(wr->sg_list[i].lkey); wqe->recv.sgl[i].len = cpu_to_be32(wr->sg_list[i].length); - - /* to in the WQE == the offset into the page */ - wqe->recv.sgl[i].to = cpu_to_be64(((u32) wr->sg_list[i].addr) % - (1UL << (12 + page_size[i]))); - - /* pbl_addr is the adapters address in the PBL */ - wqe->recv.pbl_addr[i] = cpu_to_be32(pbl_addr[i]); + wqe->recv.sgl[i].to = cpu_to_be64(wr->sg_list[i].addr); } for (; i < T3_MAX_SGE; i++) { wqe->recv.sgl[i].stag = 0; wqe->recv.sgl[i].len = 0; wqe->recv.sgl[i].to = 0; - wqe->recv.pbl_addr[i] = 0; } return 0; } @@ -659,6 +642,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) cxio_flush_rq(&qhp->wq, &rchp->cq, count); spin_unlock(&qhp->lock); spin_unlock_irqrestore(&rchp->lock, *flag); + (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context); /* locking heirarchy: cq lock first, then qp lock. */ spin_lock_irqsave(&schp->lock, *flag); @@ -668,6 +652,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) cxio_flush_sq(&qhp->wq, &schp->cq, count); spin_unlock(&qhp->lock); spin_unlock_irqrestore(&schp->lock, *flag); + (*schp->ibcq.comp_handler)(&schp->ibcq, schp->ibcq.cq_context); /* deref */ if (atomic_dec_and_test(&qhp->refcnt)) @@ -678,7 +663,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) { - if (t3b_device(qhp->rhp)) + if (qhp->ibqp.uobject) cxio_set_wq_in_error(&qhp->wq); else __flush_qp(qhp, flag); @@ -732,6 +717,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.qp_dma_addr = qhp->wq.dma_addr; init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0; + init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0; init_attr.irs = qhp->ep->rcv_seq; PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d " "flags 0x%x qpcaps 0x%x\n", __FUNCTION__, @@ -847,10 +833,11 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, disconnect = 1; ep = qhp->ep; } + flush_qp(qhp, &flag); break; case IWCH_QP_STATE_TERMINATE: qhp->attr.state = IWCH_QP_STATE_TERMINATE; - if (t3b_device(qhp->rhp)) + if (qhp->ibqp.uobject) cxio_set_wq_in_error(&qhp->wq); if (!internal) terminate = 1; diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c index f7782c882ab4..194c1c30cf63 100644 --- a/drivers/infiniband/hw/ehca/ehca_av.c +++ b/drivers/infiniband/hw/ehca/ehca_av.c @@ -1,7 +1,7 @@ /* * IBM eServer eHCA Infiniband device driver for Linux on POWER * - * adress vector functions + * address vector functions * * Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com> * Khadija Souissi <souissik@de.ibm.com> diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 74d2b72a11d8..f281d16040f5 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -94,7 +94,11 @@ struct ehca_sma_attr { struct ehca_sport { struct ib_cq *ibcq_aqp1; - struct ib_qp *ibqp_aqp1; + struct ib_qp *ibqp_sqp[2]; + /* lock to serialze modify_qp() calls for sqp in normal + * and irq path (when event PORT_ACTIVE is received first time) + */ + spinlock_t mod_sqp_lock; enum ib_port_state port_state; struct ehca_sma_attr saved_attr; }; @@ -141,6 +145,14 @@ enum ehca_ext_qp_type { EQPT_SRQ = 3, }; +/* struct to cache modify_qp()'s parms for GSI/SMI qp */ +struct ehca_mod_qp_parm { + int mask; + struct ib_qp_attr attr; +}; + +#define EHCA_MOD_QP_PARM_MAX 4 + struct ehca_qp { union { struct ib_qp ib_qp; @@ -164,10 +176,18 @@ struct ehca_qp { struct ehca_cq *recv_cq; unsigned int sqerr_purgeflag; struct hlist_node list_entries; + /* array to cache modify_qp()'s parms for GSI/SMI qp */ + struct ehca_mod_qp_parm *mod_qp_parm; + int mod_qp_parm_idx; /* mmap counter for resources mapped into user space */ u32 mm_count_squeue; u32 mm_count_rqueue; u32 mm_count_galpa; + /* unsolicited ack circumvention */ + int unsol_ack_circ; + int mtu_shift; + u32 message_count; + u32 packet_count; }; #define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ) @@ -323,6 +343,7 @@ extern int ehca_port_act_time; extern int ehca_use_hp_mr; extern int ehca_scaling_code; extern int ehca_lock_hcalls; +extern int ehca_nr_ports; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 79c25f51c21e..0467c158d4a9 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -246,7 +246,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, } else { if (h_ret != H_PAGE_REGISTERED) { ehca_err(device, "Registration of page failed " - "ehca_cq=%p cq_num=%x h_ret=%li" + "ehca_cq=%p cq_num=%x h_ret=%li " "counter=%i act_pages=%i", my_cq, my_cq->cq_number, h_ret, counter, param.act_pages); diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 3f617b27b954..863b34fa9ff9 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -62,6 +62,7 @@ #define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15) #define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16) #define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16) +#define NEQE_SPECIFIC_EVENT EHCA_BMASK_IBM(16, 23) #define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63) #define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7) @@ -354,17 +355,34 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) { u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe); u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe); + u8 spec_event; + struct ehca_sport *sport = &shca->sport[port - 1]; + unsigned long flags; switch (ec) { case 0x30: /* port availability change */ if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) { - shca->sport[port - 1].port_state = IB_PORT_ACTIVE; + int suppress_event; + /* replay modify_qp for sqps */ + spin_lock_irqsave(&sport->mod_sqp_lock, flags); + suppress_event = !sport->ibqp_sqp[IB_QPT_GSI]; + if (sport->ibqp_sqp[IB_QPT_SMI]) + ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_SMI]); + if (!suppress_event) + ehca_recover_sqp(sport->ibqp_sqp[IB_QPT_GSI]); + spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); + + /* AQP1 was destroyed, ignore this event */ + if (suppress_event) + break; + + sport->port_state = IB_PORT_ACTIVE; dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, "is active"); ehca_query_sma_attr(shca, port, - &shca->sport[port - 1].saved_attr); + &sport->saved_attr); } else { - shca->sport[port - 1].port_state = IB_PORT_DOWN; + sport->port_state = IB_PORT_DOWN; dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, "is inactive"); } @@ -378,11 +396,11 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) ehca_warn(&shca->ib_device, "disruptive port " "%d configuration change", port); - shca->sport[port - 1].port_state = IB_PORT_DOWN; + sport->port_state = IB_PORT_DOWN; dispatch_port_event(shca, port, IB_EVENT_PORT_ERR, "is inactive"); - shca->sport[port - 1].port_state = IB_PORT_ACTIVE; + sport->port_state = IB_PORT_ACTIVE; dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE, "is active"); } else @@ -394,6 +412,16 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe) case 0x33: /* trace stopped */ ehca_err(&shca->ib_device, "Traced stopped."); break; + case 0x34: /* util async event */ + spec_event = EHCA_BMASK_GET(NEQE_SPECIFIC_EVENT, eqe); + if (spec_event == 0x80) /* client reregister required */ + dispatch_port_event(shca, port, + IB_EVENT_CLIENT_REREGISTER, + "client reregister req."); + else + ehca_warn(&shca->ib_device, "Unknown util async " + "event %x on port %x", spec_event, port); + break; default: ehca_err(&shca->ib_device, "Unknown event code: %x on %s.", ec, shca->ib_device.name); diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h index 5485799cdc8d..c469bfde2708 100644 --- a/drivers/infiniband/hw/ehca/ehca_iverbs.h +++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h @@ -200,4 +200,6 @@ void ehca_free_fw_ctrlblock(void *ptr); #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr)) #endif +void ehca_recover_sqp(struct ib_qp *sqp); + #endif diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 6a56d86a2951..84c9b7b8669b 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -90,7 +90,8 @@ MODULE_PARM_DESC(hw_level, "hardware level" " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)"); MODULE_PARM_DESC(nr_ports, - "number of connected ports (default: 2)"); + "number of connected ports (-1: autodetect, 1: port one only, " + "2: two ports (default)"); MODULE_PARM_DESC(use_hp_mr, "high performance MRs (0: no (default), 1: yes)"); MODULE_PARM_DESC(port_act_time, @@ -511,7 +512,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) } sport->ibcq_aqp1 = ibcq; - if (sport->ibqp_aqp1) { + if (sport->ibqp_sqp[IB_QPT_GSI]) { ehca_err(&shca->ib_device, "AQP1 QP is already created."); ret = -EPERM; goto create_aqp1; @@ -537,7 +538,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port) ret = PTR_ERR(ibqp); goto create_aqp1; } - sport->ibqp_aqp1 = ibqp; + sport->ibqp_sqp[IB_QPT_GSI] = ibqp; return 0; @@ -550,7 +551,7 @@ static int ehca_destroy_aqp1(struct ehca_sport *sport) { int ret; - ret = ib_destroy_qp(sport->ibqp_aqp1); + ret = ib_destroy_qp(sport->ibqp_sqp[IB_QPT_GSI]); if (ret) { ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret); return ret; @@ -590,6 +591,11 @@ static struct attribute_group ehca_drv_attr_grp = { .attrs = ehca_drv_attrs }; +static struct attribute_group *ehca_drv_attr_groups[] = { + &ehca_drv_attr_grp, + NULL, +}; + #define EHCA_RESOURCE_ATTR(name) \ static ssize_t ehca_show_##name(struct device *dev, \ struct device_attribute *attr, \ @@ -688,7 +694,7 @@ static int __devinit ehca_probe(struct of_device *dev, struct ehca_shca *shca; const u64 *handle; struct ib_pd *ibpd; - int ret; + int ret, i; handle = of_get_property(dev->node, "ibm,hca-handle", NULL); if (!handle) { @@ -709,6 +715,8 @@ static int __devinit ehca_probe(struct of_device *dev, return -ENOMEM; } mutex_init(&shca->modify_mutex); + for (i = 0; i < ARRAY_SIZE(shca->sport); i++) + spin_lock_init(&shca->sport[i].mod_sqp_lock); shca->ofdev = dev; shca->ipz_hca_handle.handle = *handle; @@ -899,6 +907,9 @@ static struct of_platform_driver ehca_driver = { .match_table = ehca_device_table, .probe = ehca_probe, .remove = ehca_remove, + .driver = { + .groups = ehca_drv_attr_groups, + }, }; void ehca_poll_eqs(unsigned long data) @@ -926,7 +937,7 @@ void ehca_poll_eqs(unsigned long data) ehca_process_eq(shca, 0); } } - mod_timer(&poll_eqs_timer, jiffies + HZ); + mod_timer(&poll_eqs_timer, round_jiffies(jiffies + HZ)); spin_unlock(&shca_list_lock); } @@ -957,10 +968,6 @@ int __init ehca_module_init(void) goto module_init2; } - ret = sysfs_create_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp); - if (ret) /* only complain; we can live without attributes */ - ehca_gen_err("Cannot create driver attributes ret=%d", ret); - if (ehca_poll_all_eqs != 1) { ehca_gen_err("WARNING!!!"); ehca_gen_err("It is possible to lose interrupts."); @@ -986,7 +993,6 @@ void __exit ehca_module_exit(void) if (ehca_poll_all_eqs == 1) del_timer_sync(&poll_eqs_timer); - sysfs_remove_group(&ehca_driver.driver.kobj, &ehca_drv_attr_grp); ibmebus_unregister_driver(&ehca_driver); ehca_destroy_slab_caches(); diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index eff5fb55604b..1012f15a7140 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -592,10 +592,8 @@ static struct ehca_qp *internal_create_qp( goto create_qp_exit1; } - if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) - parms.sigtype = HCALL_SIGT_EVERY; - else - parms.sigtype = HCALL_SIGT_BY_WQE; + /* Always signal by WQE so we can hide circ. WQEs */ + parms.sigtype = HCALL_SIGT_BY_WQE; /* UD_AV CIRCUMVENTION */ max_send_sge = init_attr->cap.max_send_sge; @@ -618,6 +616,10 @@ static struct ehca_qp *internal_create_qp( parms.squeue.max_sge = max_send_sge; parms.rqueue.max_sge = max_recv_sge; + /* RC QPs need one more SWQE for unsolicited ack circumvention */ + if (qp_type == IB_QPT_RC) + parms.squeue.max_wr++; + if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) { if (HAS_SQ(my_qp)) ehca_determine_small_queue( @@ -650,6 +652,8 @@ static struct ehca_qp *internal_create_qp( parms.squeue.act_nr_sges = 1; parms.rqueue.act_nr_sges = 1; } + /* hide the extra WQE */ + parms.squeue.act_nr_wqes--; break; case IB_QPT_UD: case IB_QPT_GSI: @@ -729,12 +733,31 @@ static struct ehca_qp *internal_create_qp( init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes; my_qp->init_attr = *init_attr; + if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) { + shca->sport[init_attr->port_num - 1].ibqp_sqp[qp_type] = + &my_qp->ib_qp; + if (ehca_nr_ports < 0) { + /* alloc array to cache subsequent modify qp parms + * for autodetect mode + */ + my_qp->mod_qp_parm = + kzalloc(EHCA_MOD_QP_PARM_MAX * + sizeof(*my_qp->mod_qp_parm), + GFP_KERNEL); + if (!my_qp->mod_qp_parm) { + ehca_err(pd->device, + "Could not alloc mod_qp_parm"); + goto create_qp_exit4; + } + } + } + /* NOTE: define_apq0() not supported yet */ if (qp_type == IB_QPT_GSI) { h_ret = ehca_define_sqp(shca, my_qp, init_attr); if (h_ret != H_SUCCESS) { ret = ehca2ib_return_code(h_ret); - goto create_qp_exit4; + goto create_qp_exit5; } } @@ -743,7 +766,7 @@ static struct ehca_qp *internal_create_qp( if (ret) { ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%i", ret); - goto create_qp_exit4; + goto create_qp_exit5; } } @@ -769,12 +792,18 @@ static struct ehca_qp *internal_create_qp( if (ib_copy_to_udata(udata, &resp, sizeof resp)) { ehca_err(pd->device, "Copy to udata failed"); ret = -EINVAL; - goto create_qp_exit4; + goto create_qp_exit6; } } return my_qp; +create_qp_exit6: + ehca_cq_unassign_qp(my_qp->send_cq, my_qp->real_qp_num); + +create_qp_exit5: + kfree(my_qp->mod_qp_parm); + create_qp_exit4: if (HAS_RQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue); @@ -858,7 +887,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, update_mask, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { - ehca_err(pd->device, "Could not modify SRQ to INIT" + ehca_err(pd->device, "Could not modify SRQ to INIT " "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; @@ -872,7 +901,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, update_mask, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { - ehca_err(pd->device, "Could not enable SRQ" + ehca_err(pd->device, "Could not enable SRQ " "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; @@ -886,7 +915,7 @@ struct ib_srq *ehca_create_srq(struct ib_pd *pd, update_mask, mqpcb, my_qp->galpas.kernel); if (hret != H_SUCCESS) { - ehca_err(pd->device, "Could not modify SRQ to RTR" + ehca_err(pd->device, "Could not modify SRQ to RTR " "ehca_qp=%p qp_num=%x h_ret=%li", my_qp, my_qp->real_qp_num, hret); goto create_srq2; @@ -992,7 +1021,7 @@ static int internal_modify_qp(struct ib_qp *ibqp, unsigned long flags = 0; /* do query_qp to obtain current attr values */ - mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL); + mqpcb = ehca_alloc_fw_ctrlblock(GFP_ATOMIC); if (!mqpcb) { ehca_err(ibqp->device, "Could not get zeroed page for mqpcb " "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num); @@ -1180,6 +1209,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1); } if (attr_mask & IB_QP_PORT) { + struct ehca_sport *sport; + struct ehca_qp *aqp1; if (attr->port_num < 1 || attr->port_num > shca->num_ports) { ret = -EINVAL; ehca_err(ibqp->device, "Invalid port=%x. " @@ -1188,6 +1219,29 @@ static int internal_modify_qp(struct ib_qp *ibqp, shca->num_ports); goto modify_qp_exit2; } + sport = &shca->sport[attr->port_num - 1]; + if (!sport->ibqp_sqp[IB_QPT_GSI]) { + /* should not occur */ + ret = -EFAULT; + ehca_err(ibqp->device, "AQP1 was not created for " + "port=%x", attr->port_num); + goto modify_qp_exit2; + } + aqp1 = container_of(sport->ibqp_sqp[IB_QPT_GSI], + struct ehca_qp, ib_qp); + if (ibqp->qp_type != IB_QPT_GSI && + ibqp->qp_type != IB_QPT_SMI && + aqp1->mod_qp_parm) { + /* + * firmware will reject this modify_qp() because + * port is not activated/initialized fully + */ + ret = -EFAULT; + ehca_warn(ibqp->device, "Couldn't modify qp port=%x: " + "either port is being activated (try again) " + "or cabling issue", attr->port_num); + goto modify_qp_exit2; + } mqpcb->prim_phys_port = attr->port_num; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1); } @@ -1244,6 +1298,8 @@ static int internal_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_PATH_MTU) { + /* store ld(MTU) */ + my_qp->mtu_shift = attr->path_mtu + 7; mqpcb->path_mtu = attr->path_mtu; update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1); } @@ -1467,6 +1523,8 @@ modify_qp_exit1: int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, struct ib_udata *udata) { + struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca, + ib_device); struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp); struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd); @@ -1479,9 +1537,100 @@ int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, return -EINVAL; } + /* The if-block below caches qp_attr to be modified for GSI and SMI + * qps during the initialization by ib_mad. When the respective port + * is activated, ie we got an event PORT_ACTIVE, we'll replay the + * cached modify calls sequence, see ehca_recover_sqs() below. + * Why that is required: + * 1) If one port is connected, older code requires that port one + * to be connected and module option nr_ports=1 to be given by + * user, which is very inconvenient for end user. + * 2) Firmware accepts modify_qp() only if respective port has become + * active. Older code had a wait loop of 30sec create_qp()/ + * define_aqp1(), which is not appropriate in practice. This + * code now removes that wait loop, see define_aqp1(), and always + * reports all ports to ib_mad resp. users. Only activated ports + * will then usable for the users. + */ + if (ibqp->qp_type == IB_QPT_GSI || ibqp->qp_type == IB_QPT_SMI) { + int port = my_qp->init_attr.port_num; + struct ehca_sport *sport = &shca->sport[port - 1]; + unsigned long flags; + spin_lock_irqsave(&sport->mod_sqp_lock, flags); + /* cache qp_attr only during init */ + if (my_qp->mod_qp_parm) { + struct ehca_mod_qp_parm *p; + if (my_qp->mod_qp_parm_idx >= EHCA_MOD_QP_PARM_MAX) { + ehca_err(&shca->ib_device, + "mod_qp_parm overflow state=%x port=%x" + " type=%x", attr->qp_state, + my_qp->init_attr.port_num, + ibqp->qp_type); + spin_unlock_irqrestore(&sport->mod_sqp_lock, + flags); + return -EINVAL; + } + p = &my_qp->mod_qp_parm[my_qp->mod_qp_parm_idx]; + p->mask = attr_mask; + p->attr = *attr; + my_qp->mod_qp_parm_idx++; + ehca_dbg(&shca->ib_device, + "Saved qp_attr for state=%x port=%x type=%x", + attr->qp_state, my_qp->init_attr.port_num, + ibqp->qp_type); + spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); + return 0; + } + spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); + } + return internal_modify_qp(ibqp, attr, attr_mask, 0); } +void ehca_recover_sqp(struct ib_qp *sqp) +{ + struct ehca_qp *my_sqp = container_of(sqp, struct ehca_qp, ib_qp); + int port = my_sqp->init_attr.port_num; + struct ib_qp_attr attr; + struct ehca_mod_qp_parm *qp_parm; + int i, qp_parm_idx, ret; + unsigned long flags, wr_cnt; + + if (!my_sqp->mod_qp_parm) + return; + ehca_dbg(sqp->device, "SQP port=%x qp_num=%x", port, sqp->qp_num); + + qp_parm = my_sqp->mod_qp_parm; + qp_parm_idx = my_sqp->mod_qp_parm_idx; + for (i = 0; i < qp_parm_idx; i++) { + attr = qp_parm[i].attr; + ret = internal_modify_qp(sqp, &attr, qp_parm[i].mask, 0); + if (ret) { + ehca_err(sqp->device, "Could not modify SQP port=%x " + "qp_num=%x ret=%x", port, sqp->qp_num, ret); + goto free_qp_parm; + } + ehca_dbg(sqp->device, "SQP port=%x qp_num=%x in state=%x", + port, sqp->qp_num, attr.qp_state); + } + + /* re-trigger posted recv wrs */ + wr_cnt = my_sqp->ipz_rqueue.current_q_offset / + my_sqp->ipz_rqueue.qe_size; + if (wr_cnt) { + spin_lock_irqsave(&my_sqp->spinlock_r, flags); + hipz_update_rqa(my_sqp, wr_cnt); + spin_unlock_irqrestore(&my_sqp->spinlock_r, flags); + ehca_dbg(sqp->device, "doorbell port=%x qp_num=%x wr_cnt=%lx", + port, sqp->qp_num, wr_cnt); + } + +free_qp_parm: + kfree(qp_parm); + /* this prevents subsequent calls to modify_qp() to cache qp_attr */ + my_sqp->mod_qp_parm = NULL; +} + int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) @@ -1769,6 +1918,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device); struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd, ib_pd); + struct ehca_sport *sport = &shca->sport[my_qp->init_attr.port_num - 1]; u32 cur_pid = current->tgid; u32 qp_num = my_qp->real_qp_num; int ret; @@ -1815,6 +1965,14 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, port_num = my_qp->init_attr.port_num; qp_type = my_qp->init_attr.qp_type; + if (qp_type == IB_QPT_SMI || qp_type == IB_QPT_GSI) { + spin_lock_irqsave(&sport->mod_sqp_lock, flags); + kfree(my_qp->mod_qp_parm); + my_qp->mod_qp_parm = NULL; + shca->sport[port_num - 1].ibqp_sqp[qp_type] = NULL; + spin_unlock_irqrestore(&sport->mod_sqp_lock, flags); + } + /* no support for IB_QPT_SMI yet */ if (qp_type == IB_QPT_GSI) { struct ib_event event; diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c index ea91360835d3..3aacc8cf1e44 100644 --- a/drivers/infiniband/hw/ehca/ehca_reqs.c +++ b/drivers/infiniband/hw/ehca/ehca_reqs.c @@ -50,6 +50,9 @@ #include "hcp_if.h" #include "hipz_fns.h" +/* in RC traffic, insert an empty RDMA READ every this many packets */ +#define ACK_CIRC_THRESHOLD 2000000 + static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, struct ehca_wqe *wqe_p, struct ib_recv_wr *recv_wr) @@ -81,7 +84,7 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue, if (ehca_debug_level) { ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue); - ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); + ehca_dmp(wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe"); } return 0; @@ -135,7 +138,8 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr) static inline int ehca_write_swqe(struct ehca_qp *qp, struct ehca_wqe *wqe_p, - const struct ib_send_wr *send_wr) + const struct ib_send_wr *send_wr, + int hidden) { u32 idx; u64 dma_length; @@ -176,7 +180,9 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, wqe_p->wr_flag = 0; - if (send_wr->send_flags & IB_SEND_SIGNALED) + if ((send_wr->send_flags & IB_SEND_SIGNALED || + qp->init_attr.sq_sig_type == IB_SIGNAL_ALL_WR) + && !hidden) wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM; if (send_wr->opcode == IB_WR_SEND_WITH_IMM || @@ -199,7 +205,7 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8; wqe_p->local_ee_context_qkey = remote_qkey; - if (!send_wr->wr.ud.ah) { + if (unlikely(!send_wr->wr.ud.ah)) { ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp); return -EINVAL; } @@ -255,6 +261,15 @@ static inline int ehca_write_swqe(struct ehca_qp *qp, } /* eof idx */ wqe_p->u.nud.atomic_1st_op_dma_len = dma_length; + /* unsolicited ack circumvention */ + if (send_wr->opcode == IB_WR_RDMA_READ) { + /* on RDMA read, switch on and reset counters */ + qp->message_count = qp->packet_count = 0; + qp->unsol_ack_circ = 1; + } else + /* else estimate #packets */ + qp->packet_count += (dma_length >> qp->mtu_shift) + 1; + break; default: @@ -355,13 +370,49 @@ static inline void map_ib_wc_status(u32 cqe_status, *wc_status = IB_WC_SUCCESS; } +static inline int post_one_send(struct ehca_qp *my_qp, + struct ib_send_wr *cur_send_wr, + struct ib_send_wr **bad_send_wr, + int hidden) +{ + struct ehca_wqe *wqe_p; + int ret; + u64 start_offset = my_qp->ipz_squeue.current_q_offset; + + /* get pointer next to free WQE */ + wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue); + if (unlikely(!wqe_p)) { + /* too many posted work requests: queue overflow */ + if (bad_send_wr) + *bad_send_wr = cur_send_wr; + ehca_err(my_qp->ib_qp.device, "Too many posted WQEs " + "qp_num=%x", my_qp->ib_qp.qp_num); + return -ENOMEM; + } + /* write a SEND WQE into the QUEUE */ + ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr, hidden); + /* + * if something failed, + * reset the free entry pointer to the start value + */ + if (unlikely(ret)) { + my_qp->ipz_squeue.current_q_offset = start_offset; + if (bad_send_wr) + *bad_send_wr = cur_send_wr; + ehca_err(my_qp->ib_qp.device, "Could not write WQE " + "qp_num=%x", my_qp->ib_qp.qp_num); + return -EINVAL; + } + + return 0; +} + int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr, struct ib_send_wr **bad_send_wr) { struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp); struct ib_send_wr *cur_send_wr; - struct ehca_wqe *wqe_p; int wqe_cnt = 0; int ret = 0; unsigned long flags; @@ -369,37 +420,33 @@ int ehca_post_send(struct ib_qp *qp, /* LOCK the QUEUE */ spin_lock_irqsave(&my_qp->spinlock_s, flags); + /* Send an empty extra RDMA read if: + * 1) there has been an RDMA read on this connection before + * 2) no RDMA read occurred for ACK_CIRC_THRESHOLD link packets + * 3) we can be sure that any previous extra RDMA read has been + * processed so we don't overflow the SQ + */ + if (unlikely(my_qp->unsol_ack_circ && + my_qp->packet_count > ACK_CIRC_THRESHOLD && + my_qp->message_count > my_qp->init_attr.cap.max_send_wr)) { + /* insert an empty RDMA READ to fix up the remote QP state */ + struct ib_send_wr circ_wr; + memset(&circ_wr, 0, sizeof(circ_wr)); + circ_wr.opcode = IB_WR_RDMA_READ; + post_one_send(my_qp, &circ_wr, NULL, 1); /* ignore retcode */ + wqe_cnt++; + ehca_dbg(qp->device, "posted circ wr qp_num=%x", qp->qp_num); + my_qp->message_count = my_qp->packet_count = 0; + } + /* loop processes list of send reqs */ for (cur_send_wr = send_wr; cur_send_wr != NULL; cur_send_wr = cur_send_wr->next) { - u64 start_offset = my_qp->ipz_squeue.current_q_offset; - /* get pointer next to free WQE */ - wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue); - if (unlikely(!wqe_p)) { - /* too many posted work requests: queue overflow */ - if (bad_send_wr) - *bad_send_wr = cur_send_wr; - if (wqe_cnt == 0) { - ret = -ENOMEM; - ehca_err(qp->device, "Too many posted WQEs " - "qp_num=%x", qp->qp_num); - } - goto post_send_exit0; - } - /* write a SEND WQE into the QUEUE */ - ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr); - /* - * if something failed, - * reset the free entry pointer to the start value - */ + ret = post_one_send(my_qp, cur_send_wr, bad_send_wr, 0); if (unlikely(ret)) { - my_qp->ipz_squeue.current_q_offset = start_offset; - *bad_send_wr = cur_send_wr; - if (wqe_cnt == 0) { - ret = -EINVAL; - ehca_err(qp->device, "Could not write WQE " - "qp_num=%x", qp->qp_num); - } + /* if one or more WQEs were successful, don't fail */ + if (wqe_cnt) + ret = 0; goto post_send_exit0; } wqe_cnt++; @@ -410,6 +457,7 @@ int ehca_post_send(struct ib_qp *qp, post_send_exit0: iosync(); /* serialize GAL register access */ hipz_update_sqa(my_qp, wqe_cnt); + my_qp->message_count += wqe_cnt; spin_unlock_irqrestore(&my_qp->spinlock_s, flags); return ret; } diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c index f0792e5fbd02..79e72b25b252 100644 --- a/drivers/infiniband/hw/ehca/ehca_sqp.c +++ b/drivers/infiniband/hw/ehca/ehca_sqp.c @@ -40,11 +40,8 @@ */ -#include <linux/module.h> -#include <linux/err.h> #include "ehca_classes.h" #include "ehca_tools.h" -#include "ehca_qes.h" #include "ehca_iverbs.h" #include "hcp_if.h" @@ -93,6 +90,9 @@ u64 ehca_define_sqp(struct ehca_shca *shca, return H_PARAMETER; } + if (ehca_nr_ports < 0) /* autodetect mode */ + return H_SUCCESS; + for (counter = 0; shca->sport[port - 1].port_state != IB_PORT_ACTIVE && counter < ehca_port_act_time; diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index 851df8a75e79..414621095540 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h @@ -82,6 +82,16 @@ #define IPATH_IB_LINK_EXTERNAL 7 /* normal, disable local loopback */ /* + * These 3 values (SDR and DDR may be ORed for auto-speed + * negotiation) are used for the 3rd argument to path_f_set_ib_cfg + * with cmd IPATH_IB_CFG_SPD_ENB, by direct calls or via sysfs. They + * are also the the possible values for ipath_link_speed_enabled and active + * The values were chosen to match values used within the IB spec. + */ +#define IPATH_IB_SDR 1 +#define IPATH_IB_DDR 2 + +/* * stats maintained by the driver. For now, at least, this is global * to all minor devices. */ @@ -433,8 +443,9 @@ struct ipath_user_info { #define IPATH_CMD_UNUSED_2 26 #define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */ #define IPATH_CMD_POLL_TYPE 28 /* set the kind of polling we want */ +#define IPATH_CMD_ARMLAUNCH_CTRL 29 /* armlaunch detection control */ -#define IPATH_CMD_MAX 28 +#define IPATH_CMD_MAX 29 /* * Poll types @@ -477,6 +488,8 @@ struct ipath_cmd { __u64 port_info; /* enable/disable receipt of packets */ __u32 recv_ctrl; + /* enable/disable armlaunch errors (non-zero to enable) */ + __u32 armlaunch_ctrl; /* partition key to set */ __u16 part_key; /* user address of __u32 bitmask of active slaves */ @@ -579,7 +592,7 @@ struct ipath_flash { struct infinipath_counters { __u64 LBIntCnt; __u64 LBFlowStallCnt; - __u64 Reserved1; + __u64 TxSDmaDescCnt; /* was Reserved1 */ __u64 TxUnsupVLErrCnt; __u64 TxDataPktCnt; __u64 TxFlowPktCnt; @@ -615,12 +628,26 @@ struct infinipath_counters { __u64 RxP6HdrEgrOvflCnt; __u64 RxP7HdrEgrOvflCnt; __u64 RxP8HdrEgrOvflCnt; - __u64 Reserved6; - __u64 Reserved7; + __u64 RxP9HdrEgrOvflCnt; /* was Reserved6 */ + __u64 RxP10HdrEgrOvflCnt; /* was Reserved7 */ + __u64 RxP11HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP12HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP13HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP14HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP15HdrEgrOvflCnt; /* new for IBA7220 */ + __u64 RxP16HdrEgrOvflCnt; /* new for IBA7220 */ __u64 IBStatusChangeCnt; __u64 IBLinkErrRecoveryCnt; __u64 IBLinkDownedCnt; __u64 IBSymbolErrCnt; + /* The following are new for IBA7220 */ + __u64 RxVL15DroppedPktCnt; + __u64 RxOtherLocalPhyErrCnt; + __u64 PcieRetryBufDiagQwordCnt; + __u64 ExcessBufferOvflCnt; + __u64 LocalLinkIntegrityErrCnt; + __u64 RxVlErrCnt; + __u64 RxDlidFltrCnt; }; /* diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c index d1380c7a1703..a03bd28d9b48 100644 --- a/drivers/infiniband/hw/ipath/ipath_cq.c +++ b/drivers/infiniband/hw/ipath/ipath_cq.c @@ -421,7 +421,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) else n = head - tail; if (unlikely((u32)cqe < n)) { - ret = -EOVERFLOW; + ret = -EINVAL; goto bail_unlock; } for (n = 0; tail != head; n++) { diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h index 19c56e6491eb..d6f69532d83f 100644 --- a/drivers/infiniband/hw/ipath/ipath_debug.h +++ b/drivers/infiniband/hw/ipath/ipath_debug.h @@ -55,7 +55,7 @@ #define __IPATH_PKTDBG 0x80 /* print packet data */ /* print process startup (init)/exit messages */ #define __IPATH_PROCDBG 0x100 -/* print mmap/nopage stuff, not using VDBG any more */ +/* print mmap/fault stuff, not using VDBG any more */ #define __IPATH_MMDBG 0x200 #define __IPATH_ERRPKTDBG 0x400 #define __IPATH_USER_SEND 0x1000 /* use user mode send */ @@ -81,7 +81,7 @@ #define __IPATH_VERBDBG 0x0 /* very verbose debug */ #define __IPATH_PKTDBG 0x0 /* print packet data */ #define __IPATH_PROCDBG 0x0 /* process startup (init)/exit messages */ -/* print mmap/nopage stuff, not using VDBG any more */ +/* print mmap/fault stuff, not using VDBG any more */ #define __IPATH_MMDBG 0x0 #define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */ #define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */ diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c index 1f152ded1e3c..d5ff6ca2db30 100644 --- a/drivers/infiniband/hw/ipath/ipath_driver.c +++ b/drivers/infiniband/hw/ipath/ipath_driver.c @@ -121,6 +121,9 @@ static struct pci_driver ipath_driver = { .probe = ipath_init_one, .remove = __devexit_p(ipath_remove_one), .id_table = ipath_pci_tbl, + .driver = { + .groups = ipath_driver_attr_groups, + }, }; static void ipath_check_status(struct work_struct *work) @@ -331,6 +334,8 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd) udelay(1); } + ipath_disable_armlaunch(dd); + writeq(0, piobuf); /* length 0, no dwords actually sent */ ipath_flush_wc(); @@ -362,6 +367,7 @@ static void ipath_verify_pioperf(struct ipath_devdata *dd) done: /* disarm piobuf, so it's available again */ ipath_disarm_piobufs(dd, pbnum, 1); + ipath_enable_armlaunch(dd); } static int __devinit ipath_init_one(struct pci_dev *pdev, @@ -800,31 +806,37 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first, unsigned cnt) { unsigned i, last = first + cnt; - u64 sendctrl, sendorig; + unsigned long flags; ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first); - sendorig = dd->ipath_sendctrl; for (i = first; i < last; i++) { - sendctrl = sendorig | INFINIPATH_S_DISARM | - (i << INFINIPATH_S_DISARMPIOBUF_SHIFT); + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + /* + * The disarm-related bits are write-only, so it + * is ok to OR them in with our copy of sendctrl + * while we hold the lock. + */ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - sendctrl); + dd->ipath_sendctrl | INFINIPATH_S_DISARM | + (i << INFINIPATH_S_DISARMPIOBUF_SHIFT)); + /* can't disarm bufs back-to-back per iba7220 spec */ + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /* - * Write it again with current value, in case ipath_sendctrl changed - * while we were looping; no critical bits that would require - * locking. - * - * disable PIOAVAILUPD, then re-enable, reading scratch in + * Disable PIOAVAILUPD, then re-enable, reading scratch in * between. This seems to avoid a chip timing race that causes - * pioavail updates to memory to stop. + * pioavail updates to memory to stop. We xor as we don't + * know the state of the bit when we're called. */ + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD); - sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + dd->ipath_sendctrl ^ INFINIPATH_S_PIOBUFAVAILUPD); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /** @@ -1000,12 +1012,10 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len) * ipath_get_egrbuf - get an eager buffer * @dd: the infinipath device * @bufnum: the eager buffer to get - * @err: unused * * must only be called if ipath_pd[port] is known to be allocated */ -static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum, - int err) +static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum) { return dd->ipath_port0_skbinfo ? (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL; @@ -1097,13 +1107,14 @@ static void ipath_rcv_hdrerr(struct ipath_devdata *dd, /* * ipath_kreceive - receive a packet - * @dd: the infinipath device + * @pd: the infinipath port * * called from interrupt handler for errors or receive interrupt */ -void ipath_kreceive(struct ipath_devdata *dd) +void ipath_kreceive(struct ipath_portdata *pd) { u64 *rc; + struct ipath_devdata *dd = pd->port_dd; void *ebuf; const u32 rsize = dd->ipath_rcvhdrentsize; /* words */ const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */ @@ -1118,8 +1129,8 @@ void ipath_kreceive(struct ipath_devdata *dd) goto bail; } - l = dd->ipath_port0head; - hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr); + l = pd->port_head; + hdrqtail = ipath_get_rcvhdrtail(pd); if (l == hdrqtail) goto bail; @@ -1128,7 +1139,7 @@ reloop: u32 qp; u8 *bthbytes; - rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2)); + rc = (u64 *) (pd->port_rcvhdrq + (l << 2)); hdr = (struct ipath_message_header *)&rc[1]; /* * could make a network order version of IPATH_KD_QP, and @@ -1153,7 +1164,7 @@ reloop: etail = ipath_hdrget_index((__le32 *) rc); if (tlen > sizeof(*hdr) || etype == RCVHQ_RCV_TYPE_NON_KD) - ebuf = ipath_get_egrbuf(dd, etail, 0); + ebuf = ipath_get_egrbuf(dd, etail); } /* @@ -1188,7 +1199,7 @@ reloop: be32_to_cpu(hdr->bth[0]) & 0xff); else { /* - * error packet, type of error unknown. + * error packet, type of error unknown. * Probably type 3, but we don't know, so don't * even try to print the opcode, etc. */ @@ -1238,7 +1249,7 @@ reloop: * earlier packets, we "almost" guarantee we have covered * that case. */ - u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr); + u32 hqtail = ipath_get_rcvhdrtail(pd); if (hqtail != hdrqtail) { hdrqtail = hqtail; reloop = 1; /* loop 1 extra time at most */ @@ -1248,7 +1259,7 @@ reloop: pkttot += i; - dd->ipath_port0head = l; + pd->port_head = l; if (pkttot > ipath_stats.sps_maxpkts_call) ipath_stats.sps_maxpkts_call = pkttot; @@ -1332,14 +1343,9 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd) /* * Chip Errata: bug 6641; even and odd qwords>3 are swapped */ - if (i > 3) { - if (i & 1) - piov = le64_to_cpu( - dd->ipath_pioavailregs_dma[i - 1]); - else - piov = le64_to_cpu( - dd->ipath_pioavailregs_dma[i + 1]); - } else + if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) + piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i ^ 1]); + else piov = le64_to_cpu(dd->ipath_pioavailregs_dma[i]); pchg = _IPATH_ALL_CHECKBITS & ~(dd->ipath_pioavailshadow[i] ^ piov); @@ -1598,7 +1604,8 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd, /* clear for security and sanity on each use */ memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size); - memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE); + if (pd->port_rcvhdrtail_kvaddr) + memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE); /* * tell chip each time we init it, even if we are re-using previous @@ -1614,77 +1621,6 @@ bail: return ret; } -int ipath_waitfor_complete(struct ipath_devdata *dd, ipath_kreg reg_id, - u64 bits_to_wait_for, u64 * valp) -{ - unsigned long timeout; - u64 lastval, val; - int ret; - - lastval = ipath_read_kreg64(dd, reg_id); - /* wait a ridiculously long time */ - timeout = jiffies + msecs_to_jiffies(5); - do { - val = ipath_read_kreg64(dd, reg_id); - /* set so they have something, even on failures. */ - *valp = val; - if ((val & bits_to_wait_for) == bits_to_wait_for) { - ret = 0; - break; - } - if (val != lastval) - ipath_cdbg(VERBOSE, "Changed from %llx to %llx, " - "waiting for %llx bits\n", - (unsigned long long) lastval, - (unsigned long long) val, - (unsigned long long) bits_to_wait_for); - cond_resched(); - if (time_after(jiffies, timeout)) { - ipath_dbg("Didn't get bits %llx in register 0x%x, " - "got %llx\n", - (unsigned long long) bits_to_wait_for, - reg_id, (unsigned long long) *valp); - ret = -ENODEV; - break; - } - } while (1); - - return ret; -} - -/** - * ipath_waitfor_mdio_cmdready - wait for last command to complete - * @dd: the infinipath device - * - * Like ipath_waitfor_complete(), but we wait for the CMDVALID bit to go - * away indicating the last command has completed. It doesn't return data - */ -int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd) -{ - unsigned long timeout; - u64 val; - int ret; - - /* wait a ridiculously long time */ - timeout = jiffies + msecs_to_jiffies(5); - do { - val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_mdio); - if (!(val & IPATH_MDIO_CMDVALID)) { - ret = 0; - break; - } - cond_resched(); - if (time_after(jiffies, timeout)) { - ipath_dbg("CMDVALID stuck in mdio reg? (%llx)\n", - (unsigned long long) val); - ret = -ENODEV; - break; - } - } while (1); - - return ret; -} - /* * Flush all sends that might be in the ready to send state, as well as any @@ -2053,6 +1989,8 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val) */ void ipath_shutdown_device(struct ipath_devdata *dd) { + unsigned long flags; + ipath_dbg("Shutting down the device\n"); dd->ipath_flags |= IPATH_LINKUNK; @@ -2073,9 +2011,13 @@ void ipath_shutdown_device(struct ipath_devdata *dd) * gracefully stop all sends allowing any in progress to trickle out * first. */ - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL); + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + dd->ipath_sendctrl = 0; + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); /* flush it */ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); + /* * enough for anything that's going to trickle out to have actually * done so. @@ -2217,25 +2159,15 @@ static int __init infinipath_init(void) goto bail_unit; } - ret = ipath_driver_create_group(&ipath_driver.driver); - if (ret < 0) { - printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver " - "sysfs entries: error %d\n", -ret); - goto bail_pci; - } - ret = ipath_init_ipathfs(); if (ret < 0) { printk(KERN_ERR IPATH_DRV_NAME ": Unable to create " "ipathfs: error %d\n", -ret); - goto bail_group; + goto bail_pci; } goto bail; -bail_group: - ipath_driver_remove_group(&ipath_driver.driver); - bail_pci: pci_unregister_driver(&ipath_driver); @@ -2250,8 +2182,6 @@ static void __exit infinipath_cleanup(void) { ipath_exit_ipathfs(); - ipath_driver_remove_group(&ipath_driver.driver); - ipath_cdbg(VERBOSE, "Unregistering pci driver\n"); pci_unregister_driver(&ipath_driver); @@ -2344,5 +2274,34 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv) } return 0; } + +/* + * Disable and enable the armlaunch error. Used for PIO bandwidth testing on + * the 7220, which is count-based, rather than trigger-based. Safe for the + * driver check, since it's at init. Not completely safe when used for + * user-mode checking, since some error checking can be lost, but not + * particularly risky, and only has problematic side-effects in the face of + * very buggy user code. There is no reference counting, but that's also + * fine, given the intended use. + */ +void ipath_enable_armlaunch(struct ipath_devdata *dd) +{ + dd->ipath_lasterror &= ~INFINIPATH_E_SPIOARMLAUNCH; + ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, + INFINIPATH_E_SPIOARMLAUNCH); + dd->ipath_errormask |= INFINIPATH_E_SPIOARMLAUNCH; + ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, + dd->ipath_errormask); +} + +void ipath_disable_armlaunch(struct ipath_devdata *dd) +{ + /* so don't re-enable if already set */ + dd->ipath_maskederrs &= ~INFINIPATH_E_SPIOARMLAUNCH; + dd->ipath_errormask &= ~INFINIPATH_E_SPIOARMLAUNCH; + ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, + dd->ipath_errormask); +} + module_init(infinipath_init); module_exit(infinipath_cleanup); diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c index e7c25dbbcdc9..e28a42f53769 100644 --- a/drivers/infiniband/hw/ipath/ipath_eeprom.c +++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c @@ -510,10 +510,10 @@ int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset, { int ret; - ret = down_interruptible(&dd->ipath_eep_sem); + ret = mutex_lock_interruptible(&dd->ipath_eep_lock); if (!ret) { ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len); - up(&dd->ipath_eep_sem); + mutex_unlock(&dd->ipath_eep_lock); } return ret; @@ -524,10 +524,10 @@ int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset, { int ret; - ret = down_interruptible(&dd->ipath_eep_sem); + ret = mutex_lock_interruptible(&dd->ipath_eep_lock); if (!ret) { ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len); - up(&dd->ipath_eep_sem); + mutex_unlock(&dd->ipath_eep_lock); } return ret; @@ -574,7 +574,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) struct ipath_devdata *dd0 = ipath_lookup(0); if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) { - u8 *bguid, oguid; + u8 oguid; dd->ipath_guid = dd0->ipath_guid; bguid = (u8 *) & dd->ipath_guid; @@ -616,9 +616,9 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) goto bail; } - down(&dd->ipath_eep_sem); + mutex_lock(&dd->ipath_eep_lock); eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len); - up(&dd->ipath_eep_sem); + mutex_unlock(&dd->ipath_eep_lock); if (eep_stat) { ipath_dev_err(dd, "Failed reading GUID from eeprom\n"); @@ -674,7 +674,6 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd) * elsewhere for backward-compatibility. */ char *snp = dd->ipath_serial; - int len; memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix); snp[sizeof ifp->if_sprefix] = '\0'; len = strlen(snp); @@ -764,14 +763,14 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) /* Grab semaphore and read current EEPROM. If we get an * error, let go, but if not, keep it until we finish write. */ - ret = down_interruptible(&dd->ipath_eep_sem); + ret = mutex_lock_interruptible(&dd->ipath_eep_lock); if (ret) { ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n"); goto free_bail; } ret = ipath_eeprom_internal_read(dd, 0, buf, len); if (ret) { - up(&dd->ipath_eep_sem); + mutex_unlock(&dd->ipath_eep_lock); ipath_dev_err(dd, "Unable read EEPROM for logging\n"); goto free_bail; } @@ -779,7 +778,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) csum = flash_csum(ifp, 0); if (csum != ifp->if_csum) { - up(&dd->ipath_eep_sem); + mutex_unlock(&dd->ipath_eep_lock); ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n", csum, ifp->if_csum); ret = 1; @@ -849,7 +848,7 @@ int ipath_update_eeprom_log(struct ipath_devdata *dd) csum = flash_csum(ifp, 1); ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1); } - up(&dd->ipath_eep_sem); + mutex_unlock(&dd->ipath_eep_lock); if (ret) ipath_dev_err(dd, "Failed updating EEPROM\n"); diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index 5de3243a47c3..7e025c8e01b6 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c @@ -169,7 +169,7 @@ static int ipath_get_base_info(struct file *fp, kinfo->spi_piocnt = dd->ipath_pbufsport; kinfo->spi_piobufbase = (u64) pd->port_piobufs; kinfo->__spi_uregbase = (u64) dd->ipath_uregbase + - dd->ipath_palign * pd->port_port; + dd->ipath_ureg_align * pd->port_port; } else if (master) { kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) + (dd->ipath_pbufsport % subport_cnt); @@ -186,7 +186,7 @@ static int ipath_get_base_info(struct file *fp, } if (shared) { kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase + - dd->ipath_palign * pd->port_port; + dd->ipath_ureg_align * pd->port_port; kinfo->spi_port_rcvegrbuf = kinfo->spi_rcv_egrbufs; kinfo->spi_port_rcvhdr_base = kinfo->spi_rcvhdr_base; kinfo->spi_port_rcvhdr_tailaddr = kinfo->spi_rcvhdr_tailaddr; @@ -742,11 +742,12 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport, * updated and correct itself, even in the face of software * bugs. */ - *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0; - set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, + if (pd->port_rcvhdrtail_kvaddr) + ipath_clear_rcvhdrtail(pd); + set_bit(dd->ipath_r_portenable_shift + pd->port_port, &dd->ipath_rcvctrl); } else - clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, + clear_bit(dd->ipath_r_portenable_shift + pd->port_port, &dd->ipath_rcvctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); @@ -881,7 +882,7 @@ static int ipath_create_user_egr(struct ipath_portdata *pd) egrcnt = dd->ipath_rcvegrcnt; /* TID number offset for this port */ - egroff = pd->port_port * egrcnt; + egroff = (pd->port_port - 1) * egrcnt + dd->ipath_p0_rcvegrcnt; egrsize = dd->ipath_rcvegrbufsize; ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid " "offset %x, egrsize %u\n", egrcnt, egroff, egrsize); @@ -1049,11 +1050,6 @@ static int mmap_piobufs(struct vm_area_struct *vma, phys = dd->ipath_physaddr + piobufs; - /* - * Don't mark this as non-cached, or we don't get the - * write combining behavior we want on the PIO buffers! - */ - #if defined(__powerpc__) /* There isn't a generic way to specify writethrough mappings */ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; @@ -1120,33 +1116,24 @@ bail: } /* - * ipath_file_vma_nopage - handle a VMA page fault. + * ipath_file_vma_fault - handle a VMA page fault. */ -static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static int ipath_file_vma_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) { - unsigned long offset = address - vma->vm_start; - struct page *page = NOPAGE_SIGBUS; - void *pageptr; + struct page *page; - /* - * Convert the vmalloc address into a struct page. - */ - pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT)); - page = vmalloc_to_page(pageptr); + page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT)); if (!page) - goto out; - - /* Increment the reference count. */ + return VM_FAULT_SIGBUS; get_page(page); - if (type) - *type = VM_FAULT_MINOR; -out: - return page; + vmf->page = page; + + return 0; } static struct vm_operations_struct ipath_file_vm_ops = { - .nopage = ipath_file_vma_nopage, + .fault = ipath_file_vma_fault, }; static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr, @@ -1284,7 +1271,7 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma) goto bail; } - ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port; + ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port; if (!pd->port_subport_cnt) { /* port is not shared */ piocnt = dd->ipath_pbufsport; @@ -1400,7 +1387,10 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd, pollflag = ipath_poll_hdrqfull(pd); head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); - tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr; + if (pd->port_rcvhdrtail_kvaddr) + tail = ipath_get_rcvhdrtail(pd); + else + tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port); if (head != tail) pollflag |= POLLIN | POLLRDNORM; @@ -1410,7 +1400,7 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd, /* flush waiting flag so we don't miss an event */ wmb(); - set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, + set_bit(pd->port_port + dd->ipath_r_intravail_shift, &dd->ipath_rcvctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, @@ -1790,6 +1780,7 @@ static int find_shared_port(struct file *fp, } port_fp(fp) = pd; subport_fp(fp) = pd->port_cnt++; + pd->port_subpid[subport_fp(fp)] = current->pid; tidcursor_fp(fp) = 0; pd->active_slaves |= 1 << subport_fp(fp); ipath_cdbg(PROC, @@ -1920,8 +1911,7 @@ static int ipath_do_user_init(struct file *fp, */ head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port); ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port); - dd->ipath_lastegrheads[pd->port_port] = -1; - dd->ipath_lastrcvhdrqtails[pd->port_port] = -1; + pd->port_lastrcvhdrqtail = -1; ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n", pd->port_port, head32); pd->port_tidcursor = 0; /* start at beginning after open */ @@ -1941,11 +1931,13 @@ static int ipath_do_user_init(struct file *fp, * We explictly set the in-memory copy to 0 beforehand, so we don't * have to wait to be sure the DMA update has happened. */ - *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL; - set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port, + if (pd->port_rcvhdrtail_kvaddr) + ipath_clear_rcvhdrtail(pd); + set_bit(dd->ipath_r_portenable_shift + pd->port_port, &dd->ipath_rcvctrl); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, - dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD); + dd->ipath_rcvctrl & + ~(1ULL << dd->ipath_r_tailupd_shift)); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); /* Notify any waiting slaves */ @@ -2022,6 +2014,7 @@ static int ipath_close(struct inode *in, struct file *fp) * the slave(s) don't wait for receive data forever. */ pd->active_slaves &= ~(1 << fd->subport); + pd->port_subpid[fd->subport] = 0; mutex_unlock(&ipath_mutex); goto bail; } @@ -2054,9 +2047,9 @@ static int ipath_close(struct inode *in, struct file *fp) if (dd->ipath_kregbase) { int i; /* atomically clear receive enable port and intr avail. */ - clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, + clear_bit(dd->ipath_r_portenable_shift + port, &dd->ipath_rcvctrl); - clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, + clear_bit(pd->port_port + dd->ipath_r_intravail_shift, &dd->ipath_rcvctrl); ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); @@ -2149,11 +2142,15 @@ static int ipath_get_slave_info(struct ipath_portdata *pd, static int ipath_force_pio_avail_update(struct ipath_devdata *dd) { - u64 reg = dd->ipath_sendctrl; + unsigned long flags; - clear_bit(IPATH_S_PIOBUFAVAILUPD, ®); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, reg); + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, + dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); return 0; } @@ -2227,6 +2224,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, dest = &cmd.cmd.poll_type; src = &ucmd->cmd.poll_type; break; + case IPATH_CMD_ARMLAUNCH_CTRL: + copy = sizeof(cmd.cmd.armlaunch_ctrl); + dest = &cmd.cmd.armlaunch_ctrl; + src = &ucmd->cmd.armlaunch_ctrl; + break; default: ret = -EINVAL; goto bail; @@ -2302,6 +2304,12 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, case IPATH_CMD_POLL_TYPE: pd->poll_type = cmd.cmd.poll_type; break; + case IPATH_CMD_ARMLAUNCH_CTRL: + if (cmd.cmd.armlaunch_ctrl) + ipath_enable_armlaunch(pd->port_dd); + else + ipath_disable_armlaunch(pd->port_dd); + break; } if (ret >= 0) diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c index 262c25db05cd..23faba9d21eb 100644 --- a/drivers/infiniband/hw/ipath/ipath_fs.c +++ b/drivers/infiniband/hw/ipath/ipath_fs.c @@ -108,21 +108,16 @@ static const struct file_operations atomic_stats_ops = { .read = atomic_stats_read, }; -#define NUM_COUNTERS sizeof(struct infinipath_counters) / sizeof(u64) - static ssize_t atomic_counters_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - u64 counters[NUM_COUNTERS]; - u16 i; + struct infinipath_counters counters; struct ipath_devdata *dd; dd = file->f_path.dentry->d_inode->i_private; + dd->ipath_f_read_counters(dd, &counters); - for (i = 0; i < NUM_COUNTERS; i++) - counters[i] = ipath_snap_cntr(dd, i); - - return simple_read_from_buffer(buf, count, ppos, counters, + return simple_read_from_buffer(buf, count, ppos, &counters, sizeof counters); } @@ -243,8 +238,7 @@ static int create_device_files(struct super_block *sb, snprintf(unit, sizeof unit, "%02d", dd->ipath_unit); ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir, - (struct file_operations *) &simple_dir_operations, - dd); + &simple_dir_operations, dd); if (ret) { printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret); goto bail; diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c index ddbebe4bdb27..9e2ced3cdc5e 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6110.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c @@ -148,10 +148,57 @@ struct _infinipath_do_not_use_kernel_regs { unsigned long long ReservedSW2[4]; }; -#define IPATH_KREG_OFFSET(field) (offsetof(struct \ - _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +struct _infinipath_do_not_use_counters { + __u64 LBIntCnt; + __u64 LBFlowStallCnt; + __u64 Reserved1; + __u64 TxUnsupVLErrCnt; + __u64 TxDataPktCnt; + __u64 TxFlowPktCnt; + __u64 TxDwordCnt; + __u64 TxLenErrCnt; + __u64 TxMaxMinLenErrCnt; + __u64 TxUnderrunCnt; + __u64 TxFlowStallCnt; + __u64 TxDroppedPktCnt; + __u64 RxDroppedPktCnt; + __u64 RxDataPktCnt; + __u64 RxFlowPktCnt; + __u64 RxDwordCnt; + __u64 RxLenErrCnt; + __u64 RxMaxMinLenErrCnt; + __u64 RxICRCErrCnt; + __u64 RxVCRCErrCnt; + __u64 RxFlowCtrlErrCnt; + __u64 RxBadFormatCnt; + __u64 RxLinkProblemCnt; + __u64 RxEBPCnt; + __u64 RxLPCRCErrCnt; + __u64 RxBufOvflCnt; + __u64 RxTIDFullErrCnt; + __u64 RxTIDValidErrCnt; + __u64 RxPKeyMismatchCnt; + __u64 RxP0HdrEgrOvflCnt; + __u64 RxP1HdrEgrOvflCnt; + __u64 RxP2HdrEgrOvflCnt; + __u64 RxP3HdrEgrOvflCnt; + __u64 RxP4HdrEgrOvflCnt; + __u64 RxP5HdrEgrOvflCnt; + __u64 RxP6HdrEgrOvflCnt; + __u64 RxP7HdrEgrOvflCnt; + __u64 RxP8HdrEgrOvflCnt; + __u64 Reserved6; + __u64 Reserved7; + __u64 IBStatusChangeCnt; + __u64 IBLinkErrRecoveryCnt; + __u64 IBLinkDownedCnt; + __u64 IBSymbolErrCnt; +}; + +#define IPATH_KREG_OFFSET(field) (offsetof( \ + struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) #define IPATH_CREG_OFFSET(field) (offsetof( \ - struct infinipath_counters, field) / sizeof(u64)) + struct _infinipath_do_not_use_counters, field) / sizeof(u64)) static const struct ipath_kregs ipath_ht_kregs = { .kr_control = IPATH_KREG_OFFSET(Control), @@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_ht_cregs = { #define INFINIPATH_HWE_HTAPLL_RFSLIP 0x1000000000000000ULL #define INFINIPATH_HWE_SERDESPLLFAILED 0x2000000000000000ULL +#define IBA6110_IBCS_LINKTRAININGSTATE_MASK 0xf +#define IBA6110_IBCS_LINKSTATE_SHIFT 4 + /* kr_extstatus bits */ #define INFINIPATH_EXTS_FREQSEL 0x2 #define INFINIPATH_EXTS_SERDESSEL 0x4 @@ -296,6 +346,12 @@ static const struct ipath_cregs ipath_ht_cregs = { #define INFINIPATH_RT_BUFSIZE_MASK 0x3FFFULL #define INFINIPATH_RT_BUFSIZE_SHIFT 48 +#define INFINIPATH_R_INTRAVAIL_SHIFT 16 +#define INFINIPATH_R_TAILUPD_SHIFT 31 + +/* kr_xgxsconfig bits */ +#define INFINIPATH_XGXS_RESET 0x7ULL + /* * masks and bits that are different in different chips, or present only * in one @@ -652,7 +708,6 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, "with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u", boardrev); - ret = 1; break; } if (n) @@ -686,6 +741,13 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, dd->ipath_htspeed); ret = 0; + /* + * set here, not in ipath_init_*_funcs because we have to do + * it after we can read chip registers. + */ + dd->ipath_ureg_align = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign); + bail: return ret; } @@ -969,7 +1031,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, do { u8 cap_type; - /* the HT capability type byte is 3 bytes after the + /* + * The HT capability type byte is 3 bytes after the * capability byte. */ if (pci_read_config_byte(pdev, pos + 3, &cap_type)) { @@ -982,6 +1045,8 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd, } while ((pos = pci_find_next_capability(pdev, pos, PCI_CAP_ID_HT))); + dd->ipath_flags |= IPATH_SWAP_PIOBUFS; + bail: return ret; } @@ -1074,11 +1139,55 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd, static void ipath_init_ht_variables(struct ipath_devdata *dd) { + /* + * setup the register offsets, since they are different for each + * chip + */ + dd->ipath_kregs = &ipath_ht_kregs; + dd->ipath_cregs = &ipath_ht_cregs; + dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM; dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM; dd->ipath_gpio_sda = IPATH_GPIO_SDA; dd->ipath_gpio_scl = IPATH_GPIO_SCL; + /* + * Fill in data for field-values that change in newer chips. + * We dynamically specify only the mask for LINKTRAININGSTATE + * and only the shift for LINKSTATE, as they are the only ones + * that change. Also precalculate the 3 link states of interest + * and the combined mask. + */ + dd->ibcs_ls_shift = IBA6110_IBCS_LINKSTATE_SHIFT; + dd->ibcs_lts_mask = IBA6110_IBCS_LINKTRAININGSTATE_MASK; + dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK << + dd->ibcs_ls_shift) | dd->ibcs_lts_mask; + dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP << + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | + (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift); + dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP << + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | + (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift); + dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP << + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | + (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift); + + /* + * Fill in data for ibcc field-values that change in newer chips. + * We dynamically specify only the mask for LINKINITCMD + * and only the shift for LINKCMD and MAXPKTLEN, as they are + * the only ones that change. + */ + dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK; + dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT; + dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT; + + /* Fill in shifts for RcvCtrl. */ + dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT; + dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT; + dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT; + dd->ipath_r_portcfg_shift = 0; /* Not on IBA6110 */ + dd->ipath_i_bitsextant = (INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) | (INFINIPATH_I_RCVAVAIL_MASK << @@ -1135,6 +1244,8 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd) dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; + dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT; + dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT; /* * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity. @@ -1148,9 +1259,17 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd) INFINIPATH_HWE_RXEMEMPARITYERR_MASK << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT; - dd->ipath_eep_st_masks[2].errs_to_log = - INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET; + dd->ipath_eep_st_masks[2].errs_to_log = INFINIPATH_E_RESET; + dd->delay_mult = 2; /* SDR, 4X, can't change */ + + dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; + dd->ipath_link_speed_supported = IPATH_IB_SDR; + dd->ipath_link_width_enabled = IB_WIDTH_4X; + dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported; + /* these can't change for this chip, so set once */ + dd->ipath_link_width_active = dd->ipath_link_width_enabled; + dd->ipath_link_speed_active = dd->ipath_link_speed_enabled; } /** @@ -1205,14 +1324,16 @@ static void ipath_ht_init_hwerrors(struct ipath_devdata *dd) val &= ~INFINIPATH_HWE_HTCMISCERR4; /* - * PLL ignored because MDIO interface has a logic problem - * for reads, on Comstock and Ponderosa. BRINGUP + * PLL ignored because unused MDIO interface has a logic problem */ if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9) val &= ~INFINIPATH_HWE_SERDESPLLFAILED; dd->ipath_hwerrmask = val; } + + + /** * ipath_ht_bringup_serdes - bring up the serdes * @dd: the infinipath device @@ -1284,16 +1405,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd) } val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); - if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & - INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { - val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK << - INFINIPATH_XGXS_MDIOADDR_SHIFT); - /* - * we use address 3 - */ - val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; - change = 1; - } if (val & INFINIPATH_XGXS_RESET) { /* normally true after boot */ val &= ~INFINIPATH_XGXS_RESET; @@ -1329,21 +1440,6 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd) (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); - if (!ipath_waitfor_mdio_cmdready(dd)) { - ipath_write_kreg(dd, dd->ipath_kregs->kr_mdio, - ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, - IPATH_MDIO_CTRL_XGXS_REG_8, - 0)); - if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, - IPATH_MDIO_DATAVALID, &val)) - ipath_dbg("Never got MDIO data for XGXS status " - "read\n"); - else - ipath_cdbg(VERBOSE, "MDIO Read reg8, " - "'bank' 31 %x\n", (u32) val); - } else - ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); - return ret; /* for now, say we always succeeded */ } @@ -1396,6 +1492,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd, pa |= lenvalid | INFINIPATH_RT_VALID; } } + writeq(pa, tidptr); } @@ -1526,8 +1623,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd) } ipath_get_eeprom_info(dd); - if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' && - dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') { + if (dd->ipath_boardrev == 5) { /* * Later production QHT7040 has same changes as QHT7140, so * can use GPIO interrupts. They have serial #'s starting @@ -1602,6 +1698,210 @@ static void ipath_ht_free_irq(struct ipath_devdata *dd) dd->ipath_intconfig = 0; } +static struct ipath_message_header * +ipath_ht_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr) +{ + return (struct ipath_message_header *) + &rhf_addr[sizeof(u64) / sizeof(u32)]; +} + +static void ipath_ht_config_ports(struct ipath_devdata *dd, ushort cfgports) +{ + dd->ipath_portcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); + dd->ipath_p0_rcvegrcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt); +} + +static void ipath_ht_read_counters(struct ipath_devdata *dd, + struct infinipath_counters *cntrs) +{ + cntrs->LBIntCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt)); + cntrs->LBFlowStallCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt)); + cntrs->TxSDmaDescCnt = 0; + cntrs->TxUnsupVLErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt)); + cntrs->TxDataPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt)); + cntrs->TxFlowPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt)); + cntrs->TxDwordCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt)); + cntrs->TxLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt)); + cntrs->TxMaxMinLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt)); + cntrs->TxUnderrunCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt)); + cntrs->TxFlowStallCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt)); + cntrs->TxDroppedPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt)); + cntrs->RxDroppedPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt)); + cntrs->RxDataPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt)); + cntrs->RxFlowPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt)); + cntrs->RxDwordCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt)); + cntrs->RxLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt)); + cntrs->RxMaxMinLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt)); + cntrs->RxICRCErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt)); + cntrs->RxVCRCErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt)); + cntrs->RxFlowCtrlErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt)); + cntrs->RxBadFormatCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt)); + cntrs->RxLinkProblemCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt)); + cntrs->RxEBPCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt)); + cntrs->RxLPCRCErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt)); + cntrs->RxBufOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt)); + cntrs->RxTIDFullErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt)); + cntrs->RxTIDValidErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt)); + cntrs->RxPKeyMismatchCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt)); + cntrs->RxP0HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt)); + cntrs->RxP1HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt)); + cntrs->RxP2HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt)); + cntrs->RxP3HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt)); + cntrs->RxP4HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt)); + cntrs->RxP5HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP5HdrEgrOvflCnt)); + cntrs->RxP6HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP6HdrEgrOvflCnt)); + cntrs->RxP7HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP7HdrEgrOvflCnt)); + cntrs->RxP8HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP8HdrEgrOvflCnt)); + cntrs->RxP9HdrEgrOvflCnt = 0; + cntrs->RxP10HdrEgrOvflCnt = 0; + cntrs->RxP11HdrEgrOvflCnt = 0; + cntrs->RxP12HdrEgrOvflCnt = 0; + cntrs->RxP13HdrEgrOvflCnt = 0; + cntrs->RxP14HdrEgrOvflCnt = 0; + cntrs->RxP15HdrEgrOvflCnt = 0; + cntrs->RxP16HdrEgrOvflCnt = 0; + cntrs->IBStatusChangeCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt)); + cntrs->IBLinkErrRecoveryCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt)); + cntrs->IBLinkDownedCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt)); + cntrs->IBSymbolErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt)); + cntrs->RxVL15DroppedPktCnt = 0; + cntrs->RxOtherLocalPhyErrCnt = 0; + cntrs->PcieRetryBufDiagQwordCnt = 0; + cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs; + cntrs->LocalLinkIntegrityErrCnt = + (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ? + dd->ipath_lli_errs : dd->ipath_lli_errors; + cntrs->RxVlErrCnt = 0; + cntrs->RxDlidFltrCnt = 0; +} + + +/* no interrupt fallback for these chips */ +static int ipath_ht_nointr_fallback(struct ipath_devdata *dd) +{ + return 0; +} + + +/* + * reset the XGXS (between serdes and IBC). Slightly less intrusive + * than resetting the IBC or external link state, and useful in some + * cases to cause some retraining. To do this right, we reset IBC + * as well. + */ +static void ipath_ht_xgxs_reset(struct ipath_devdata *dd) +{ + u64 val, prev_val; + + prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); + val = prev_val | INFINIPATH_XGXS_RESET; + prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control & ~INFINIPATH_C_LINKENABLE); + ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); + ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch); + ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val); + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control); +} + + +static int ipath_ht_get_ib_cfg(struct ipath_devdata *dd, int which) +{ + int ret; + + switch (which) { + case IPATH_IB_CFG_LWID: + ret = dd->ipath_link_width_active; + break; + case IPATH_IB_CFG_SPD: + ret = dd->ipath_link_speed_active; + break; + case IPATH_IB_CFG_LWID_ENB: + ret = dd->ipath_link_width_enabled; + break; + case IPATH_IB_CFG_SPD_ENB: + ret = dd->ipath_link_speed_enabled; + break; + default: + ret = -ENOTSUPP; + break; + } + return ret; +} + + +/* we assume range checking is already done, if needed */ +static int ipath_ht_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val) +{ + int ret = 0; + + if (which == IPATH_IB_CFG_LWID_ENB) + dd->ipath_link_width_enabled = val; + else if (which == IPATH_IB_CFG_SPD_ENB) + dd->ipath_link_speed_enabled = val; + else + ret = -ENOTSUPP; + return ret; +} + + +static void ipath_ht_config_jint(struct ipath_devdata *dd, u16 a, u16 b) +{ +} + + +static int ipath_ht_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) +{ + ipath_setup_ht_setextled(dd, ipath_ib_linkstate(dd, ibcs), + ipath_ib_linktrstate(dd, ibcs)); + return 0; +} + + /** * ipath_init_iba6110_funcs - set up the chip-specific function pointers * @dd: the infinipath device @@ -1626,22 +1926,19 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd) dd->ipath_f_setextled = ipath_setup_ht_setextled; dd->ipath_f_get_base_info = ipath_ht_get_base_info; dd->ipath_f_free_irq = ipath_ht_free_irq; - - /* - * initialize chip-specific variables - */ dd->ipath_f_tidtemplate = ipath_ht_tidtemplate; + dd->ipath_f_intr_fallback = ipath_ht_nointr_fallback; + dd->ipath_f_get_msgheader = ipath_ht_get_msgheader; + dd->ipath_f_config_ports = ipath_ht_config_ports; + dd->ipath_f_read_counters = ipath_ht_read_counters; + dd->ipath_f_xgxs_reset = ipath_ht_xgxs_reset; + dd->ipath_f_get_ib_cfg = ipath_ht_get_ib_cfg; + dd->ipath_f_set_ib_cfg = ipath_ht_set_ib_cfg; + dd->ipath_f_config_jint = ipath_ht_config_jint; + dd->ipath_f_ib_updown = ipath_ht_ib_updown; /* - * setup the register offsets, since they are different for each - * chip - */ - dd->ipath_kregs = &ipath_ht_kregs; - dd->ipath_cregs = &ipath_ht_cregs; - - /* - * do very early init that is needed before ipath_f_bus is - * called + * initialize chip-specific variables */ ipath_init_ht_variables(dd); } diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c index 0103d6f4847b..c7a2f50824c0 100644 --- a/drivers/infiniband/hw/ipath/ipath_iba6120.c +++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c @@ -145,10 +145,57 @@ struct _infinipath_do_not_use_kernel_regs { unsigned long long Reserved12; }; -#define IPATH_KREG_OFFSET(field) (offsetof(struct \ - _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) +struct _infinipath_do_not_use_counters { + __u64 LBIntCnt; + __u64 LBFlowStallCnt; + __u64 Reserved1; + __u64 TxUnsupVLErrCnt; + __u64 TxDataPktCnt; + __u64 TxFlowPktCnt; + __u64 TxDwordCnt; + __u64 TxLenErrCnt; + __u64 TxMaxMinLenErrCnt; + __u64 TxUnderrunCnt; + __u64 TxFlowStallCnt; + __u64 TxDroppedPktCnt; + __u64 RxDroppedPktCnt; + __u64 RxDataPktCnt; + __u64 RxFlowPktCnt; + __u64 RxDwordCnt; + __u64 RxLenErrCnt; + __u64 RxMaxMinLenErrCnt; + __u64 RxICRCErrCnt; + __u64 RxVCRCErrCnt; + __u64 RxFlowCtrlErrCnt; + __u64 RxBadFormatCnt; + __u64 RxLinkProblemCnt; + __u64 RxEBPCnt; + __u64 RxLPCRCErrCnt; + __u64 RxBufOvflCnt; + __u64 RxTIDFullErrCnt; + __u64 RxTIDValidErrCnt; + __u64 RxPKeyMismatchCnt; + __u64 RxP0HdrEgrOvflCnt; + __u64 RxP1HdrEgrOvflCnt; + __u64 RxP2HdrEgrOvflCnt; + __u64 RxP3HdrEgrOvflCnt; + __u64 RxP4HdrEgrOvflCnt; + __u64 RxP5HdrEgrOvflCnt; + __u64 RxP6HdrEgrOvflCnt; + __u64 RxP7HdrEgrOvflCnt; + __u64 RxP8HdrEgrOvflCnt; + __u64 Reserved6; + __u64 Reserved7; + __u64 IBStatusChangeCnt; + __u64 IBLinkErrRecoveryCnt; + __u64 IBLinkDownedCnt; + __u64 IBSymbolErrCnt; +}; + +#define IPATH_KREG_OFFSET(field) (offsetof( \ + struct _infinipath_do_not_use_kernel_regs, field) / sizeof(u64)) #define IPATH_CREG_OFFSET(field) (offsetof( \ - struct infinipath_counters, field) / sizeof(u64)) + struct _infinipath_do_not_use_counters, field) / sizeof(u64)) static const struct ipath_kregs ipath_pe_kregs = { .kr_control = IPATH_KREG_OFFSET(Control), @@ -282,6 +329,9 @@ static const struct ipath_cregs ipath_pe_cregs = { #define INFINIPATH_HWE_PCIE0PLLFAILED 0x0800000000000000ULL #define INFINIPATH_HWE_SERDESPLLFAILED 0x1000000000000000ULL +#define IBA6120_IBCS_LINKTRAININGSTATE_MASK 0xf +#define IBA6120_IBCS_LINKSTATE_SHIFT 4 + /* kr_extstatus bits */ #define INFINIPATH_EXTS_FREQSEL 0x2 #define INFINIPATH_EXTS_SERDESSEL 0x4 @@ -296,6 +346,9 @@ static const struct ipath_cregs ipath_pe_cregs = { #define IPATH_GPIO_SCL (1ULL << \ (_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT)) +#define INFINIPATH_R_INTRAVAIL_SHIFT 16 +#define INFINIPATH_R_TAILUPD_SHIFT 31 + /* 6120 specific hardware errors... */ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = { INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"), @@ -320,10 +373,28 @@ static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = { INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) -static int ipath_pe_txe_recover(struct ipath_devdata *); static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *, u32, unsigned long); +/* + * On platforms using this chip, and not having ordered WC stores, we + * can get TXE parity errors due to speculative reads to the PIO buffers, + * and this, due to a chip bug can result in (many) false parity error + * reports. So it's a debug print on those, and an info print on systems + * where the speculative reads don't occur. + */ +static void ipath_pe_txe_recover(struct ipath_devdata *dd) +{ + if (ipath_unordered_wc()) + ipath_dbg("Recovering from TXE PIO parity error\n"); + else { + ++ipath_stats.sps_txeparity; + dev_info(&dd->pcidev->dev, + "Recovering from TXE PIO parity error\n"); + } +} + + /** * ipath_pe_handle_hwerrors - display hardware errors. * @dd: the infinipath device @@ -403,35 +474,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, * occur if a processor speculative read is done to the PIO * buffer while we are sending a packet, for example. */ - if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd)) + if (hwerrs & TXE_PIO_PARITY) { + ipath_pe_txe_recover(dd); hwerrs &= ~TXE_PIO_PARITY; - if (hwerrs) { - /* - * if any set that we aren't ignoring only make the - * complaint once, in case it's stuck or recurring, - * and we get here multiple times - * Force link down, so switch knows, and - * LEDs are turned off - */ - if (dd->ipath_flags & IPATH_INITTED) { - ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); - ipath_setup_pe_setextled(dd, - INFINIPATH_IBCS_L_STATE_DOWN, - INFINIPATH_IBCS_LT_STATE_DISABLED); - ipath_dev_err(dd, "Fatal Hardware Error (freeze " - "mode), no longer usable, SN %.16s\n", - dd->ipath_serial); - isfatal = 1; - } - /* - * Mark as having had an error for driver, and also - * for /sys and status word mapped to user programs. - * This marks unit as not usable, until reset - */ - *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; - *dd->ipath_statusp |= IPATH_STATUS_HWERROR; - dd->ipath_flags &= ~IPATH_INITTED; - } else { + } + if (!hwerrs) { static u32 freeze_cnt; freeze_cnt++; @@ -485,7 +532,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg, if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) { /* - * If it occurs, it is left masked since the eternal + * If it occurs, it is left masked since the external * interface is unused */ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED; @@ -563,6 +610,14 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, dd->ipath_f_put_tid = ipath_pe_put_tid_2; } + + /* + * set here, not in ipath_init_*_funcs because we have to do + * it after we can read chip registers. + */ + dd->ipath_ureg_align = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_pagealign); + return ret; } @@ -667,17 +722,8 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); prev_val = val; - if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & - INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { - val &= - ~(INFINIPATH_XGXS_MDIOADDR_MASK << - INFINIPATH_XGXS_MDIOADDR_SHIFT); - /* MDIO address 3 */ - val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; - } - if (val & INFINIPATH_XGXS_RESET) { + if (val & INFINIPATH_XGXS_RESET) val &= ~INFINIPATH_XGXS_RESET; - } if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { /* need to compensate for Tx inversion in partner */ @@ -707,21 +753,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd) (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); - if (!ipath_waitfor_mdio_cmdready(dd)) { - ipath_write_kreg( - dd, dd->ipath_kregs->kr_mdio, - ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, - IPATH_MDIO_CTRL_XGXS_REG_8, 0)); - if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, - IPATH_MDIO_DATAVALID, &val)) - ipath_dbg("Never got MDIO data for XGXS " - "status read\n"); - else - ipath_cdbg(VERBOSE, "MDIO Read reg8, " - "'bank' 31 %x\n", (u32) val); - } else - ipath_dbg("Never got MDIO cmdready for XGXS status read\n"); - return ret; } @@ -902,12 +933,27 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd, else ipath_dev_err(dd, "Can't find PCI Express " "capability!\n"); + + dd->ipath_link_width_supported = IB_WIDTH_1X | IB_WIDTH_4X; + dd->ipath_link_speed_supported = IPATH_IB_SDR; + dd->ipath_link_width_enabled = IB_WIDTH_4X; + dd->ipath_link_speed_enabled = dd->ipath_link_speed_supported; + /* these can't change for this chip, so set once */ + dd->ipath_link_width_active = dd->ipath_link_width_enabled; + dd->ipath_link_speed_active = dd->ipath_link_speed_enabled; return 0; } static void ipath_init_pe_variables(struct ipath_devdata *dd) { /* + * setup the register offsets, since they are different for each + * chip + */ + dd->ipath_kregs = &ipath_pe_kregs; + dd->ipath_cregs = &ipath_pe_cregs; + + /* * bits for selecting i2c direction and values, * used for I2C serial flash */ @@ -916,6 +962,43 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd) dd->ipath_gpio_sda = IPATH_GPIO_SDA; dd->ipath_gpio_scl = IPATH_GPIO_SCL; + /* + * Fill in data for field-values that change in newer chips. + * We dynamically specify only the mask for LINKTRAININGSTATE + * and only the shift for LINKSTATE, as they are the only ones + * that change. Also precalculate the 3 link states of interest + * and the combined mask. + */ + dd->ibcs_ls_shift = IBA6120_IBCS_LINKSTATE_SHIFT; + dd->ibcs_lts_mask = IBA6120_IBCS_LINKTRAININGSTATE_MASK; + dd->ibcs_mask = (INFINIPATH_IBCS_LINKSTATE_MASK << + dd->ibcs_ls_shift) | dd->ibcs_lts_mask; + dd->ib_init = (INFINIPATH_IBCS_LT_STATE_LINKUP << + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | + (INFINIPATH_IBCS_L_STATE_INIT << dd->ibcs_ls_shift); + dd->ib_arm = (INFINIPATH_IBCS_LT_STATE_LINKUP << + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | + (INFINIPATH_IBCS_L_STATE_ARM << dd->ibcs_ls_shift); + dd->ib_active = (INFINIPATH_IBCS_LT_STATE_LINKUP << + INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | + (INFINIPATH_IBCS_L_STATE_ACTIVE << dd->ibcs_ls_shift); + + /* + * Fill in data for ibcc field-values that change in newer chips. + * We dynamically specify only the mask for LINKINITCMD + * and only the shift for LINKCMD and MAXPKTLEN, as they are + * the only ones that change. + */ + dd->ibcc_lic_mask = INFINIPATH_IBCC_LINKINITCMD_MASK; + dd->ibcc_lc_shift = INFINIPATH_IBCC_LINKCMD_SHIFT; + dd->ibcc_mpl_shift = INFINIPATH_IBCC_MAXPKTLEN_SHIFT; + + /* Fill in shifts for RcvCtrl. */ + dd->ipath_r_portenable_shift = INFINIPATH_R_PORTENABLE_SHIFT; + dd->ipath_r_intravail_shift = INFINIPATH_R_INTRAVAIL_SHIFT; + dd->ipath_r_tailupd_shift = INFINIPATH_R_TAILUPD_SHIFT; + dd->ipath_r_portcfg_shift = 0; /* Not on IBA6120 */ + /* variables for sanity checking interrupt and errors */ dd->ipath_hwe_bitsextant = (INFINIPATH_HWE_RXEMEMPARITYERR_MASK << @@ -963,6 +1046,8 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd) dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK; dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK; + dd->ipath_i_rcvavail_shift = INFINIPATH_I_RCVAVAIL_SHIFT; + dd->ipath_i_rcvurg_shift = INFINIPATH_I_RCVURG_SHIFT; /* * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity. @@ -984,6 +1069,7 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd) INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET; + dd->delay_mult = 2; /* SDR, 4X, can't change */ } /* setup the MSI stuff again after a reset. I'd like to just call @@ -1289,6 +1375,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd) */ dd->ipath_rcvhdrentsize = 24; dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE; + dd->ipath_rhf_offset = 0; + dd->ipath_egrtidbase = (u64 __iomem *) + ((char __iomem *) dd->ipath_kregbase + dd->ipath_rcvegrbase); /* * To truly support a 4KB MTU (for usermode), we need to @@ -1359,34 +1448,204 @@ static void ipath_pe_free_irq(struct ipath_devdata *dd) dd->ipath_irq = 0; } + +static struct ipath_message_header * +ipath_pe_get_msgheader(struct ipath_devdata *dd, __le32 *rhf_addr) +{ + return (struct ipath_message_header *) + &rhf_addr[sizeof(u64) / sizeof(u32)]; +} + +static void ipath_pe_config_ports(struct ipath_devdata *dd, ushort cfgports) +{ + dd->ipath_portcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); + dd->ipath_p0_rcvegrcnt = + ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt); +} + +static void ipath_pe_read_counters(struct ipath_devdata *dd, + struct infinipath_counters *cntrs) +{ + cntrs->LBIntCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBIntCnt)); + cntrs->LBFlowStallCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(LBFlowStallCnt)); + cntrs->TxSDmaDescCnt = 0; + cntrs->TxUnsupVLErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnsupVLErrCnt)); + cntrs->TxDataPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDataPktCnt)); + cntrs->TxFlowPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowPktCnt)); + cntrs->TxDwordCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDwordCnt)); + cntrs->TxLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxLenErrCnt)); + cntrs->TxMaxMinLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxMaxMinLenErrCnt)); + cntrs->TxUnderrunCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxUnderrunCnt)); + cntrs->TxFlowStallCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxFlowStallCnt)); + cntrs->TxDroppedPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(TxDroppedPktCnt)); + cntrs->RxDroppedPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDroppedPktCnt)); + cntrs->RxDataPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDataPktCnt)); + cntrs->RxFlowPktCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowPktCnt)); + cntrs->RxDwordCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxDwordCnt)); + cntrs->RxLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLenErrCnt)); + cntrs->RxMaxMinLenErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxMaxMinLenErrCnt)); + cntrs->RxICRCErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxICRCErrCnt)); + cntrs->RxVCRCErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxVCRCErrCnt)); + cntrs->RxFlowCtrlErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxFlowCtrlErrCnt)); + cntrs->RxBadFormatCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBadFormatCnt)); + cntrs->RxLinkProblemCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLinkProblemCnt)); + cntrs->RxEBPCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxEBPCnt)); + cntrs->RxLPCRCErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxLPCRCErrCnt)); + cntrs->RxBufOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxBufOvflCnt)); + cntrs->RxTIDFullErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDFullErrCnt)); + cntrs->RxTIDValidErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxTIDValidErrCnt)); + cntrs->RxPKeyMismatchCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxPKeyMismatchCnt)); + cntrs->RxP0HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP0HdrEgrOvflCnt)); + cntrs->RxP1HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP1HdrEgrOvflCnt)); + cntrs->RxP2HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP2HdrEgrOvflCnt)); + cntrs->RxP3HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP3HdrEgrOvflCnt)); + cntrs->RxP4HdrEgrOvflCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(RxP4HdrEgrOvflCnt)); + cntrs->RxP5HdrEgrOvflCnt = 0; + cntrs->RxP6HdrEgrOvflCnt = 0; + cntrs->RxP7HdrEgrOvflCnt = 0; + cntrs->RxP8HdrEgrOvflCnt = 0; + cntrs->RxP9HdrEgrOvflCnt = 0; + cntrs->RxP10HdrEgrOvflCnt = 0; + cntrs->RxP11HdrEgrOvflCnt = 0; + cntrs->RxP12HdrEgrOvflCnt = 0; + cntrs->RxP13HdrEgrOvflCnt = 0; + cntrs->RxP14HdrEgrOvflCnt = 0; + cntrs->RxP15HdrEgrOvflCnt = 0; + cntrs->RxP16HdrEgrOvflCnt = 0; + cntrs->IBStatusChangeCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBStatusChangeCnt)); + cntrs->IBLinkErrRecoveryCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkErrRecoveryCnt)); + cntrs->IBLinkDownedCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBLinkDownedCnt)); + cntrs->IBSymbolErrCnt = + ipath_snap_cntr(dd, IPATH_CREG_OFFSET(IBSymbolErrCnt)); + cntrs->RxVL15DroppedPktCnt = 0; + cntrs->RxOtherLocalPhyErrCnt = 0; + cntrs->PcieRetryBufDiagQwordCnt = 0; + cntrs->ExcessBufferOvflCnt = dd->ipath_overrun_thresh_errs; + cntrs->LocalLinkIntegrityErrCnt = dd->ipath_lli_errs; + cntrs->RxVlErrCnt = 0; + cntrs->RxDlidFltrCnt = 0; +} + + +/* no interrupt fallback for these chips */ +static int ipath_pe_nointr_fallback(struct ipath_devdata *dd) +{ + return 0; +} + + /* - * On platforms using this chip, and not having ordered WC stores, we - * can get TXE parity errors due to speculative reads to the PIO buffers, - * and this, due to a chip bug can result in (many) false parity error - * reports. So it's a debug print on those, and an info print on systems - * where the speculative reads don't occur. - * Because we can get lots of false errors, we have no upper limit - * on recovery attempts on those platforms. + * reset the XGXS (between serdes and IBC). Slightly less intrusive + * than resetting the IBC or external link state, and useful in some + * cases to cause some retraining. To do this right, we reset IBC + * as well. */ -static int ipath_pe_txe_recover(struct ipath_devdata *dd) +static void ipath_pe_xgxs_reset(struct ipath_devdata *dd) { - if (ipath_unordered_wc()) - ipath_dbg("Recovering from TXE PIO parity error\n"); - else { - int cnt = ++ipath_stats.sps_txeparity; - if (cnt >= IPATH_MAX_PARITY_ATTEMPTS) { - if (cnt == IPATH_MAX_PARITY_ATTEMPTS) - ipath_dev_err(dd, - "Too many attempts to recover from " - "TXE parity, giving up\n"); - return 0; - } - dev_info(&dd->pcidev->dev, - "Recovering from TXE PIO parity error\n"); + u64 val, prev_val; + + prev_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); + val = prev_val | INFINIPATH_XGXS_RESET; + prev_val &= ~INFINIPATH_XGXS_RESET; /* be sure */ + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control & ~INFINIPATH_C_LINKENABLE); + ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); + ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch); + ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, prev_val); + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, + dd->ipath_control); +} + + +static int ipath_pe_get_ib_cfg(struct ipath_devdata *dd, int which) +{ + int ret; + + switch (which) { + case IPATH_IB_CFG_LWID: + ret = dd->ipath_link_width_active; + break; + case IPATH_IB_CFG_SPD: + ret = dd->ipath_link_speed_active; + break; + case IPATH_IB_CFG_LWID_ENB: + ret = dd->ipath_link_width_enabled; + break; + case IPATH_IB_CFG_SPD_ENB: + ret = dd->ipath_link_speed_enabled; + break; + default: + ret = -ENOTSUPP; + break; } - return 1; + return ret; +} + + +/* we assume range checking is already done, if needed */ +static int ipath_pe_set_ib_cfg(struct ipath_devdata *dd, int which, u32 val) +{ + int ret = 0; + + if (which == IPATH_IB_CFG_LWID_ENB) + dd->ipath_link_width_enabled = val; + else if (which == IPATH_IB_CFG_SPD_ENB) + dd->ipath_link_speed_enabled = val; + else + ret = -ENOTSUPP; + return ret; } +static void ipath_pe_config_jint(struct ipath_devdata *dd, u16 a, u16 b) +{ +} + + +static int ipath_pe_ib_updown(struct ipath_devdata *dd, int ibup, u64 ibcs) +{ + ipath_setup_pe_setextled(dd, ipath_ib_linkstate(dd, ibcs), + ipath_ib_linktrstate(dd, ibcs)); + return 0; +} + + /** * ipath_init_iba6120_funcs - set up the chip-specific function pointers * @dd: the infinipath device @@ -1407,7 +1666,7 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd) dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes; dd->ipath_f_clear_tids = ipath_pe_clear_tids; /* - * this may get changed after we read the chip revision, + * _f_put_tid may get changed after we read the chip revision, * but we start with the safe version for all revs */ dd->ipath_f_put_tid = ipath_pe_put_tid; @@ -1415,17 +1674,19 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd) dd->ipath_f_setextled = ipath_setup_pe_setextled; dd->ipath_f_get_base_info = ipath_pe_get_base_info; dd->ipath_f_free_irq = ipath_pe_free_irq; - - /* initialize chip-specific variables */ dd->ipath_f_tidtemplate = ipath_pe_tidtemplate; + dd->ipath_f_intr_fallback = ipath_pe_nointr_fallback; + dd->ipath_f_xgxs_reset = ipath_pe_xgxs_reset; + dd->ipath_f_get_msgheader = ipath_pe_get_msgheader; + dd->ipath_f_config_ports = ipath_pe_config_ports; + dd->ipath_f_read_counters = ipath_pe_read_counters; + dd->ipath_f_get_ib_cfg = ipath_pe_get_ib_cfg; + dd->ipath_f_set_ib_cfg = ipath_pe_set_ib_cfg; + dd->ipath_f_config_jint = ipath_pe_config_jint; + dd->ipath_f_ib_updown = ipath_pe_ib_updown; - /* - * setup the register offsets, since they are different for each - * chip - */ - dd->ipath_kregs = &ipath_pe_kregs; - dd->ipath_cregs = &ipath_pe_cregs; + /* initialize chip-specific variables */ ipath_init_pe_variables(dd); } diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c index 9dd0bacf8461..4471674975cd 100644 --- a/drivers/infiniband/hw/ipath/ipath_init_chip.c +++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c @@ -91,7 +91,7 @@ static int create_port0_egr(struct ipath_devdata *dd) struct ipath_skbinfo *skbinfo; int ret; - egrcnt = dd->ipath_rcvegrcnt; + egrcnt = dd->ipath_p0_rcvegrcnt; skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt); if (skbinfo == NULL) { @@ -244,8 +244,7 @@ static int init_chip_first(struct ipath_devdata *dd, * cfgports. We do still check and report a difference, if * not same (should be impossible). */ - dd->ipath_portcnt = - ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); + dd->ipath_f_config_ports(dd, ipath_cfgports); if (!ipath_cfgports) dd->ipath_cfgports = dd->ipath_portcnt; else if (ipath_cfgports <= dd->ipath_portcnt) { @@ -272,22 +271,7 @@ static int init_chip_first(struct ipath_devdata *dd, goto done; } - dd->ipath_lastegrheads = kzalloc(sizeof(*dd->ipath_lastegrheads) - * dd->ipath_cfgports, - GFP_KERNEL); - dd->ipath_lastrcvhdrqtails = - kzalloc(sizeof(*dd->ipath_lastrcvhdrqtails) - * dd->ipath_cfgports, GFP_KERNEL); - - if (!dd->ipath_lastegrheads || !dd->ipath_lastrcvhdrqtails) { - ipath_dev_err(dd, "Unable to allocate head arrays, " - "failing\n"); - ret = -ENOMEM; - goto done; - } - pd = create_portdata0(dd); - if (!pd) { ipath_dev_err(dd, "Unable to allocate portdata for port " "0, failing\n"); @@ -345,10 +329,10 @@ static int init_chip_first(struct ipath_devdata *dd, dd->ipath_piobcnt2k, dd->ipath_pio2kbase); spin_lock_init(&dd->ipath_tid_lock); - + spin_lock_init(&dd->ipath_sendctrl_lock); spin_lock_init(&dd->ipath_gpio_lock); spin_lock_init(&dd->ipath_eep_st_lock); - sema_init(&dd->ipath_eep_sem, 1); + mutex_init(&dd->ipath_eep_lock); done: *pdp = pd; @@ -372,9 +356,9 @@ static int init_chip_reset(struct ipath_devdata *dd, *pdp = dd->ipath_pd[0]; /* ensure chip does no sends or receives while we re-initialize */ dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U; - ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0); - ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0); + ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_control, dd->ipath_control); rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt); if (dd->ipath_portcnt != rtmp) @@ -487,6 +471,7 @@ static void enable_chip(struct ipath_devdata *dd, struct ipath_portdata *pd, int reinit) { u32 val; + unsigned long flags; int i; if (!reinit) @@ -495,19 +480,21 @@ static void enable_chip(struct ipath_devdata *dd, ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); /* Enable PIO send, and update of PIOavail regs to memory. */ dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE | INFINIPATH_S_PIOBUFAVAILUPD; - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - dd->ipath_sendctrl); + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); /* * enable port 0 receive, and receive interrupt. other ports * done as user opens and inits them. */ - dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD | - (1ULL << INFINIPATH_R_PORTENABLE_SHIFT) | - (1ULL << INFINIPATH_R_INTRAVAIL_SHIFT); + dd->ipath_rcvctrl = (1ULL << dd->ipath_r_tailupd_shift) | + (1ULL << dd->ipath_r_portenable_shift) | + (1ULL << dd->ipath_r_intravail_shift); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, dd->ipath_rcvctrl); @@ -523,12 +510,11 @@ static void enable_chip(struct ipath_devdata *dd, */ val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0); (void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0); - dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0); /* Initialize so we interrupt on next packet received */ (void)ipath_write_ureg(dd, ur_rcvhdrhead, dd->ipath_rhdrhead_intr_off | - dd->ipath_port0head, 0); + dd->ipath_pd[0]->port_head, 0); /* * by now pioavail updates to memory should have occurred, so @@ -542,12 +528,8 @@ static void enable_chip(struct ipath_devdata *dd, /* * Chip Errata bug 6641; even and odd qwords>3 are swapped. */ - if (i > 3) { - if (i & 1) - val = dd->ipath_pioavailregs_dma[i - 1]; - else - val = dd->ipath_pioavailregs_dma[i + 1]; - } + if (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) + val = dd->ipath_pioavailregs_dma[i ^ 1]; else val = dd->ipath_pioavailregs_dma[i]; dd->ipath_pioavailshadow[i] = le64_to_cpu(val); @@ -690,12 +672,13 @@ done: */ int ipath_init_chip(struct ipath_devdata *dd, int reinit) { - int ret = 0, i; + int ret = 0; u32 val32, kpiobufs; u32 piobufs, uports; u64 val; struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ gfp_t gfp_flags = GFP_USER | __GFP_COMP; + unsigned long flags; ret = init_housekeeping(dd, &pd, reinit); if (ret) @@ -746,7 +729,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) kpiobufs = ipath_kpiobufs; if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) { - i = (int) piobufs - + int i = (int) piobufs - (int) (uports * IPATH_MIN_USER_PORT_BUFCNT); if (i < 0) i = 0; @@ -827,8 +810,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, ~0ULL&~INFINIPATH_HWE_MEMBISTFAILED); ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL); - ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - INFINIPATH_S_PIOENABLE); + + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE; + ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); /* * before error clears, since we expect serdes pll errors during diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index c61f9da2964a..92e58c921522 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c @@ -683,7 +683,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) for (i = 0; i < dd->ipath_cfgports; i++) { struct ipath_portdata *pd = dd->ipath_pd[i]; if (i == 0) { - hd = dd->ipath_port0head; + hd = pd->port_head; tl = (u32) le64_to_cpu( *dd->ipath_hdrqtailptr); } else if (pd && pd->port_cnt && @@ -693,7 +693,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) * except kernel */ tl = *(u64 *) pd->port_rcvhdrtail_kvaddr; - if (tl == dd->ipath_lastrcvhdrqtails[i]) + if (tl == pd->port_lastrcvhdrqtail) continue; hd = ipath_read_ureg32(dd, ur_rcvhdrhead, i); @@ -703,7 +703,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) (!hd && tl == dd->ipath_hdrqlast)) { if (i == 0) chkerrpkts = 1; - dd->ipath_lastrcvhdrqtails[i] = tl; + pd->port_lastrcvhdrqtail = tl; pd->port_hdrqfull++; /* flush hdrqfull so that poll() sees it */ wmb(); @@ -712,6 +712,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) } } if (errs & INFINIPATH_E_RRCVEGRFULL) { + struct ipath_portdata *pd = dd->ipath_pd[0]; + /* * since this is of less importance and not likely to * happen without also getting hdrfull, only count @@ -719,7 +721,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) * vs user) */ ipath_stats.sps_etidfull++; - if (dd->ipath_port0head != + if (pd->port_head != (u32) le64_to_cpu(*dd->ipath_hdrqtailptr)) chkerrpkts = 1; } @@ -795,6 +797,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd) { int i, im; __le64 val; + unsigned long flags; /* disable error interrupts, to avoid confusion */ ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL); @@ -813,11 +816,14 @@ void ipath_clear_freeze(struct ipath_devdata *dd) dd->ipath_control); /* ensure pio avail updates continue */ + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD); ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, - dd->ipath_sendctrl); + dd->ipath_sendctrl); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); /* * We just enabled pioavailupdate, so dma copy is almost certainly @@ -825,8 +831,8 @@ void ipath_clear_freeze(struct ipath_devdata *dd) */ for (i = 0; i < dd->ipath_pioavregs; i++) { /* deal with 6110 chip bug */ - im = i > 3 ? ((i&1) ? i-1 : i+1) : i; - val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im); + im = i > 3 ? i ^ 1 : i; + val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im); dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i] = le64_to_cpu(val); } @@ -849,7 +855,7 @@ void ipath_clear_freeze(struct ipath_devdata *dd) /* this is separate to allow for better optimization of ipath_intr() */ -static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp) +static noinline void ipath_bad_intr(struct ipath_devdata *dd, u32 *unexpectp) { /* * sometimes happen during driver init and unload, don't want @@ -877,7 +883,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp) dd->ipath_f_free_irq(dd); } } - if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) { + if (ipath_read_ireg(dd, dd->ipath_kregs->kr_intmask)) { ipath_dev_err(dd, "%u unexpected interrupts, " "disabling interrupts completely\n", *unexpectp); @@ -892,7 +898,7 @@ static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp) "ignoring\n"); } -static void ipath_bad_regread(struct ipath_devdata *dd) +static noinline void ipath_bad_regread(struct ipath_devdata *dd) { static int allbits; @@ -920,31 +926,9 @@ static void ipath_bad_regread(struct ipath_devdata *dd) } } -static void handle_port_pioavail(struct ipath_devdata *dd) -{ - u32 i; - /* - * start from port 1, since for now port 0 is never using - * wait_event for PIO - */ - for (i = 1; dd->ipath_portpiowait && i < dd->ipath_cfgports; i++) { - struct ipath_portdata *pd = dd->ipath_pd[i]; - - if (pd && pd->port_cnt && - dd->ipath_portpiowait & (1U << i)) { - clear_bit(i, &dd->ipath_portpiowait); - if (test_bit(IPATH_PORT_WAITING_PIO, - &pd->port_flag)) { - clear_bit(IPATH_PORT_WAITING_PIO, - &pd->port_flag); - wake_up_interruptible(&pd->port_wait); - } - } - } -} - static void handle_layer_pioavail(struct ipath_devdata *dd) { + unsigned long flags; int ret; ret = ipath_ib_piobufavail(dd->verbs_dev); @@ -953,9 +937,12 @@ static void handle_layer_pioavail(struct ipath_devdata *dd) return; set: - set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /* @@ -969,7 +956,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) int i; int rcvdint = 0; - /* test_bit below needs this... */ + /* + * test_and_clear_bit(IPATH_PORT_WAITING_RCV) and + * test_and_clear_bit(IPATH_PORT_WAITING_URG) below + * would both like timely updates of the bits so that + * we don't pass them by unnecessarily. the rmb() + * here ensures that we see them promptly -- the + * corresponding wmb()'s are in ipath_poll_urgent() + * and ipath_poll_next()... + */ rmb(); portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & dd->ipath_i_rcvavail_mask) @@ -980,7 +975,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) if (portr & (1 << i) && pd && pd->port_cnt) { if (test_and_clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) { - clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, + clear_bit(i + dd->ipath_r_intravail_shift, &dd->ipath_rcvctrl); wake_up_interruptible(&pd->port_wait); rcvdint = 1; @@ -1039,7 +1034,7 @@ irqreturn_t ipath_intr(int irq, void *data) goto bail; } - istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); + istat = ipath_read_ireg(dd, dd->ipath_kregs->kr_intstatus); if (unlikely(!istat)) { ipath_stats.sps_nullintr++; @@ -1180,7 +1175,7 @@ irqreturn_t ipath_intr(int irq, void *data) * for receive are at the bottom. */ if (chk0rcv) { - ipath_kreceive(dd); + ipath_kreceive(dd->ipath_pd[0]); istat &= ~port0rbits; } @@ -1191,12 +1186,14 @@ irqreturn_t ipath_intr(int irq, void *data) handle_urcv(dd, istat); if (istat & INFINIPATH_I_SPIOBUFAVAIL) { - clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + unsigned long flags; + + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + dd->ipath_sendctrl &= ~INFINIPATH_S_PIOINTBUFAVAIL; ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); - - if (dd->ipath_portpiowait) - handle_port_pioavail(dd); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); handle_layer_pioavail(dd); } diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 8786dd7922e4..4cc0f95ea877 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h @@ -41,6 +41,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/dma-mapping.h> +#include <linux/mutex.h> #include <asm/io.h> #include <rdma/ib_verbs.h> @@ -140,6 +141,11 @@ struct ipath_portdata { u32 port_pionowait; /* total number of rcvhdrqfull errors */ u32 port_hdrqfull; + /* + * Used to suppress multiple instances of same + * port staying stuck at same point. + */ + u32 port_lastrcvhdrqtail; /* saved total number of rcvhdrqfull errors for poll edge trigger */ u32 port_hdrqfull_poll; /* total number of polled urgent packets */ @@ -148,6 +154,7 @@ struct ipath_portdata { u32 port_urgent_poll; /* pid of process using this port */ pid_t port_pid; + pid_t port_subpid[INFINIPATH_MAX_SUBPORT]; /* same size as task_struct .comm[] */ char port_comm[16]; /* pkeys set by this use of this port */ @@ -166,6 +173,8 @@ struct ipath_portdata { u32 active_slaves; /* Type of packets or conditions we want to poll for */ u16 poll_type; + /* port rcvhdrq head offset */ + u32 port_head; }; struct sk_buff; @@ -182,6 +191,22 @@ struct ipath_skbinfo { dma_addr_t phys; }; +/* + * Possible IB config parameters for ipath_f_get/set_ib_cfg() + */ +#define IPATH_IB_CFG_LIDLMC 0 /* Get/set LID (LS16b) and Mask (MS16b) */ +#define IPATH_IB_CFG_HRTBT 1 /* Get/set Heartbeat off/enable/auto */ +#define IPATH_IB_HRTBT_ON 3 /* Heartbeat enabled, sent every 100msec */ +#define IPATH_IB_HRTBT_OFF 0 /* Heartbeat off */ +#define IPATH_IB_CFG_LWID_ENB 2 /* Get/set allowed Link-width */ +#define IPATH_IB_CFG_LWID 3 /* Get currently active Link-width */ +#define IPATH_IB_CFG_SPD_ENB 4 /* Get/set allowed Link speeds */ +#define IPATH_IB_CFG_SPD 5 /* Get current Link spd */ +#define IPATH_IB_CFG_RXPOL_ENB 6 /* Get/set Auto-RX-polarity enable */ +#define IPATH_IB_CFG_LREV_ENB 7 /* Get/set Auto-Lane-reversal enable */ +#define IPATH_IB_CFG_LINKLATENCY 8 /* Get Auto-Lane-reversal enable */ + + struct ipath_devdata { struct list_head ipath_list; @@ -222,6 +247,8 @@ struct ipath_devdata { struct _ipath_layer ipath_layer; /* setup intr */ int (*ipath_f_intrsetup)(struct ipath_devdata *); + /* fallback to alternate interrupt type if possible */ + int (*ipath_f_intr_fallback)(struct ipath_devdata *); /* setup on-chip bus config */ int (*ipath_f_bus)(struct ipath_devdata *, struct pci_dev *); /* hard reset chip */ @@ -244,6 +271,18 @@ struct ipath_devdata { int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); /* free irq */ void (*ipath_f_free_irq)(struct ipath_devdata *); + struct ipath_message_header *(*ipath_f_get_msgheader) + (struct ipath_devdata *, __le32 *); + void (*ipath_f_config_ports)(struct ipath_devdata *, ushort); + int (*ipath_f_get_ib_cfg)(struct ipath_devdata *, int); + int (*ipath_f_set_ib_cfg)(struct ipath_devdata *, int, u32); + void (*ipath_f_config_jint)(struct ipath_devdata *, u16 , u16); + void (*ipath_f_read_counters)(struct ipath_devdata *, + struct infinipath_counters *); + void (*ipath_f_xgxs_reset)(struct ipath_devdata *); + /* per chip actions needed for IB Link up/down changes */ + int (*ipath_f_ib_updown)(struct ipath_devdata *, int, u64); + struct ipath_ibdev *verbs_dev; struct timer_list verbs_timer; /* total dwords sent (summed from counter) */ @@ -313,22 +352,12 @@ struct ipath_devdata { * supports, less gives more pio bufs/port, etc. */ u32 ipath_cfgports; - /* port0 rcvhdrq head offset */ - u32 ipath_port0head; /* count of port 0 hdrqfull errors */ u32 ipath_p0_hdrqfull; + /* port 0 number of receive eager buffers */ + u32 ipath_p0_rcvegrcnt; /* - * (*cfgports) used to suppress multiple instances of same - * port staying stuck at same point - */ - u32 *ipath_lastrcvhdrqtails; - /* - * (*cfgports) used to suppress multiple instances of same - * port staying stuck at same point - */ - u32 *ipath_lastegrheads; - /* * index of last piobuffer we used. Speeds up searching, by * starting at this point. Doesn't matter if multiple cpu's use and * update, last updater is only write that matters. Whenever it @@ -367,14 +396,15 @@ struct ipath_devdata { unsigned long ipath_wc_len; /* ref count for each pkey */ atomic_t ipath_pkeyrefs[4]; - /* shadow copy of all exptids physaddr; used only by funcsim */ - u64 *ipath_tidsimshadow; /* shadow copy of struct page *'s for exp tid pages */ struct page **ipath_pageshadow; /* shadow copy of dma handles for exp tid pages */ dma_addr_t *ipath_physshadow; - /* lock to workaround chip bug 9437 */ + u64 __iomem *ipath_egrtidbase; + /* lock to workaround chip bug 9437 and others */ + spinlock_t ipath_kernel_tid_lock; spinlock_t ipath_tid_lock; + spinlock_t ipath_sendctrl_lock; /* * IPATH_STATUS_*, @@ -395,6 +425,8 @@ struct ipath_devdata { void *ipath_dummy_hdrq; /* used after port close */ dma_addr_t ipath_dummy_hdrq_phys; + unsigned long ipath_ureg_align; /* user register alignment */ + /* * Shadow copies of registers; size indicates read access size. * Most of them are readonly, but some are write-only register, @@ -456,8 +488,6 @@ struct ipath_devdata { unsigned long ipath_rcvctrl; /* shadow kr_sendctrl */ unsigned long ipath_sendctrl; - /* ports waiting for PIOavail intr */ - unsigned long ipath_portpiowait; unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */ /* value we put in kr_rcvhdrcnt */ @@ -550,12 +580,26 @@ struct ipath_devdata { u8 ipath_minrev; /* board rev, from ipath_revision */ u8 ipath_boardrev; + + u8 ipath_r_portenable_shift; + u8 ipath_r_intravail_shift; + u8 ipath_r_tailupd_shift; + u8 ipath_r_portcfg_shift; + /* unit # of this chip, if present */ int ipath_unit; /* saved for restore after reset */ u8 ipath_pci_cacheline; /* LID mask control */ u8 ipath_lmc; + /* link width supported */ + u8 ipath_link_width_supported; + /* link speed supported */ + u8 ipath_link_speed_supported; + u8 ipath_link_width_enabled; + u8 ipath_link_speed_enabled; + u8 ipath_link_width_active; + u8 ipath_link_speed_active; /* Rx Polarity inversion (compensate for ~tx on partner) */ u8 ipath_rx_pol_inv; @@ -590,6 +634,8 @@ struct ipath_devdata { */ u32 ipath_i_rcvavail_mask; u32 ipath_i_rcvurg_mask; + u16 ipath_i_rcvurg_shift; + u16 ipath_i_rcvavail_shift; /* * Register bits for selecting i2c direction and values, used for @@ -603,6 +649,29 @@ struct ipath_devdata { /* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */ spinlock_t ipath_gpio_lock; + /* + * IB link and linktraining states and masks that vary per chip in + * some way. Set at init, to avoid each IB status change interrupt + */ + u8 ibcs_ls_shift; + u8 ibcs_lts_mask; + u32 ibcs_mask; + u32 ib_init; + u32 ib_arm; + u32 ib_active; + + u16 ipath_rhf_offset; /* offset of RHF within receive header entry */ + + /* + * shift/mask for linkcmd, linkinitcmd, maxpktlen in ibccontol + * reg. Changes for IBA7220 + */ + u8 ibcc_lic_mask; /* LinkInitCmd */ + u8 ibcc_lc_shift; /* LinkCmd */ + u8 ibcc_mpl_shift; /* Maxpktlen */ + + u8 delay_mult; + /* used to override LED behavior */ u8 ipath_led_override; /* Substituted for normal value, if non-zero */ u16 ipath_led_override_timeoff; /* delta to next timer event */ @@ -616,7 +685,7 @@ struct ipath_devdata { /* control access to actual counters, timer */ spinlock_t ipath_eep_st_lock; /* control high-level access to EEPROM */ - struct semaphore ipath_eep_sem; + struct mutex ipath_eep_lock; /* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */ uint64_t ipath_traffic_wds; /* active time is kept in seconds, but logged in hours */ @@ -630,6 +699,10 @@ struct ipath_devdata { * each of the counters to increment. */ struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT]; + + /* interrupt mitigation reload register info */ + u16 ipath_jint_idle_ticks; /* idle clock ticks */ + u16 ipath_jint_max_packets; /* max packets across all ports */ }; /* Private data for file operations */ @@ -690,7 +763,7 @@ void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *); int ipath_parse_ushort(const char *str, unsigned short *valp); -void ipath_kreceive(struct ipath_devdata *); +void ipath_kreceive(struct ipath_portdata *); int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned); int ipath_reset_device(int); void ipath_get_faststats(unsigned long); @@ -698,6 +771,8 @@ int ipath_set_linkstate(struct ipath_devdata *, u8); int ipath_set_mtu(struct ipath_devdata *, u16); int ipath_set_lid(struct ipath_devdata *, u32, u8); int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); +void ipath_enable_armlaunch(struct ipath_devdata *); +void ipath_disable_armlaunch(struct ipath_devdata *); /* for use in system calls, where we want to know device type, etc. */ #define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd @@ -744,9 +819,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); * are 64bit */ #define IPATH_32BITCOUNTERS 0x20000 /* can miss port0 rx interrupts */ + /* Interrupt register is 64 bits */ +#define IPATH_INTREG_64 0x40000 #define IPATH_DISABLED 0x80000 /* administratively disabled */ /* Use GPIO interrupts for new counters */ #define IPATH_GPIO_ERRINTRS 0x100000 +#define IPATH_SWAP_PIOBUFS 0x200000 + /* Suppress heartbeat, even if turning off loopback */ +#define IPATH_NO_HRTBT 0x1000000 +#define IPATH_HAS_MULT_IB_SPEED 0x8000000 /* Bits in GPIO for the added interrupts */ #define IPATH_GPIO_PORT0_BIT 2 @@ -758,8 +839,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); /* portdata flag bit offsets */ /* waiting for a packet to arrive */ #define IPATH_PORT_WAITING_RCV 2 - /* waiting for a PIO buffer to be available */ -#define IPATH_PORT_WAITING_PIO 3 /* master has not finished initializing */ #define IPATH_PORT_MASTER_UNINIT 4 /* waiting for an urgent packet to arrive */ @@ -767,8 +846,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); /* free up any allocated data at closes */ void ipath_free_data(struct ipath_portdata *dd); -int ipath_waitfor_mdio_cmdready(struct ipath_devdata *); -int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *); u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *); void ipath_init_iba6120_funcs(struct ipath_devdata *); void ipath_init_iba6110_funcs(struct ipath_devdata *); @@ -792,33 +869,6 @@ void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val); */ #define IPATH_DFLT_RCVHDRSIZE 9 -#define IPATH_MDIO_CMD_WRITE 1 -#define IPATH_MDIO_CMD_READ 2 -#define IPATH_MDIO_CLD_DIV 25 /* to get 2.5 Mhz mdio clock */ -#define IPATH_MDIO_CMDVALID 0x40000000 /* bit 30 */ -#define IPATH_MDIO_DATAVALID 0x80000000 /* bit 31 */ -#define IPATH_MDIO_CTRL_STD 0x0 - -static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data) -{ - return (((u64) IPATH_MDIO_CLD_DIV) << 32) | - (cmd << 26) | - (dev << 21) | - (reg << 16) | - (data & 0xFFFF); -} - - /* signal and fifo status, in bank 31 */ -#define IPATH_MDIO_CTRL_XGXS_REG_8 0x8 - /* controls loopback, redundancy */ -#define IPATH_MDIO_CTRL_8355_REG_1 0x10 - /* premph, encdec, etc. */ -#define IPATH_MDIO_CTRL_8355_REG_2 0x11 - /* Kchars, etc. */ -#define IPATH_MDIO_CTRL_8355_REG_6 0x15 -#define IPATH_MDIO_CTRL_8355_REG_9 0x18 -#define IPATH_MDIO_CTRL_8355_REG_10 0x1D - int ipath_get_user_pages(unsigned long, size_t, struct page **); void ipath_release_user_pages(struct page **, size_t); void ipath_release_user_pages_on_close(struct page **, size_t); @@ -863,7 +913,7 @@ static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd, return readl(regno + (u64 __iomem *) (dd->ipath_uregbase + (char __iomem *)dd->ipath_kregbase + - dd->ipath_palign * port)); + dd->ipath_ureg_align * port)); } /** @@ -880,7 +930,7 @@ static inline void ipath_write_ureg(const struct ipath_devdata *dd, { u64 __iomem *ubase = (u64 __iomem *) (dd->ipath_uregbase + (char __iomem *) dd->ipath_kregbase + - dd->ipath_palign * port); + dd->ipath_ureg_align * port); if (dd->ipath_kregbase) writeq(value, &ubase[regno]); } @@ -930,6 +980,53 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd, (char __iomem *)dd->ipath_kregbase)); } +static inline void ipath_write_creg(const struct ipath_devdata *dd, + ipath_creg regno, u64 value) +{ + if (dd->ipath_kregbase) + writeq(value, regno + (u64 __iomem *) + (dd->ipath_cregbase + + (char __iomem *)dd->ipath_kregbase)); +} + +static inline void ipath_clear_rcvhdrtail(const struct ipath_portdata *pd) +{ + *((u64 *) pd->port_rcvhdrtail_kvaddr) = 0ULL; +} + +static inline u32 ipath_get_rcvhdrtail(const struct ipath_portdata *pd) +{ + return (u32) le64_to_cpu(*((volatile __le64 *) + pd->port_rcvhdrtail_kvaddr)); +} + +static inline u64 ipath_read_ireg(const struct ipath_devdata *dd, ipath_kreg r) +{ + return (dd->ipath_flags & IPATH_INTREG_64) ? + ipath_read_kreg64(dd, r) : ipath_read_kreg32(dd, r); +} + +/* + * from contents of IBCStatus (or a saved copy), return linkstate + * Report ACTIVE_DEFER as ACTIVE, because we treat them the same + * everywhere, anyway (and should be, for almost all purposes). + */ +static inline u32 ipath_ib_linkstate(struct ipath_devdata *dd, u64 ibcs) +{ + u32 state = (u32)(ibcs >> dd->ibcs_ls_shift) & + INFINIPATH_IBCS_LINKSTATE_MASK; + if (state == INFINIPATH_IBCS_L_STATE_ACT_DEFER) + state = INFINIPATH_IBCS_L_STATE_ACTIVE; + return state; +} + +/* from contents of IBCStatus (or a saved copy), return linktrainingstate */ +static inline u32 ipath_ib_linktrstate(struct ipath_devdata *dd, u64 ibcs) +{ + return (u32)(ibcs >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & + dd->ibcs_lts_mask; +} + /* * sysfs interface. */ @@ -938,8 +1035,7 @@ struct device_driver; extern const char ib_ipath_version[]; -int ipath_driver_create_group(struct device_driver *); -void ipath_driver_remove_group(struct device_driver *); +extern struct attribute_group *ipath_driver_attr_groups[]; int ipath_device_create_group(struct device *, struct ipath_devdata *); void ipath_device_remove_group(struct device *, struct ipath_devdata *); diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c index 85a4aefc6c03..8f32b17a5eed 100644 --- a/drivers/infiniband/hw/ipath/ipath_keys.c +++ b/drivers/infiniband/hw/ipath/ipath_keys.c @@ -128,9 +128,8 @@ int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge, int ret; /* - * We use LKEY == zero to mean a physical kmalloc() address. - * This is a bit of a hack since we rely on dma_map_single() - * being reversible by calling bus_to_virt(). + * We use LKEY == zero for kernel virtual addresses + * (see ipath_get_dma_mr and ipath_dma.c). */ if (sge->lkey == 0) { struct ipath_pd *pd = to_ipd(qp->ibqp.pd); diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c index 3d1432d1e3f4..d98d5f103700 100644 --- a/drivers/infiniband/hw/ipath/ipath_mad.c +++ b/drivers/infiniband/hw/ipath/ipath_mad.c @@ -934,6 +934,7 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp, struct ib_pma_portsamplescontrol *p = (struct ib_pma_portsamplescontrol *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_cregs const *crp = dev->dd->ipath_cregs; unsigned long flags; u8 port_select = p->port_select; @@ -955,7 +956,10 @@ static int recv_pma_get_portsamplescontrol(struct ib_perf *pmp, p->counter_width = 4; /* 32 bit counters */ p->counter_mask0_9 = COUNTER_MASK0_9; spin_lock_irqsave(&dev->pending_lock, flags); - p->sample_status = dev->pma_sample_status; + if (crp->cr_psstat) + p->sample_status = ipath_read_creg32(dev->dd, crp->cr_psstat); + else + p->sample_status = dev->pma_sample_status; p->sample_start = cpu_to_be32(dev->pma_sample_start); p->sample_interval = cpu_to_be32(dev->pma_sample_interval); p->tag = cpu_to_be16(dev->pma_tag); @@ -975,8 +979,9 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp, struct ib_pma_portsamplescontrol *p = (struct ib_pma_portsamplescontrol *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_cregs const *crp = dev->dd->ipath_cregs; unsigned long flags; - u32 start; + u8 status; int ret; if (pmp->attr_mod != 0 || @@ -986,59 +991,67 @@ static int recv_pma_set_portsamplescontrol(struct ib_perf *pmp, goto bail; } - start = be32_to_cpu(p->sample_start); - if (start != 0) { - spin_lock_irqsave(&dev->pending_lock, flags); - if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_DONE) { - dev->pma_sample_status = - IB_PMA_SAMPLE_STATUS_STARTED; - dev->pma_sample_start = start; - dev->pma_sample_interval = - be32_to_cpu(p->sample_interval); - dev->pma_tag = be16_to_cpu(p->tag); - if (p->counter_select[0]) - dev->pma_counter_select[0] = - p->counter_select[0]; - if (p->counter_select[1]) - dev->pma_counter_select[1] = - p->counter_select[1]; - if (p->counter_select[2]) - dev->pma_counter_select[2] = - p->counter_select[2]; - if (p->counter_select[3]) - dev->pma_counter_select[3] = - p->counter_select[3]; - if (p->counter_select[4]) - dev->pma_counter_select[4] = - p->counter_select[4]; - } - spin_unlock_irqrestore(&dev->pending_lock, flags); + spin_lock_irqsave(&dev->pending_lock, flags); + if (crp->cr_psstat) + status = ipath_read_creg32(dev->dd, crp->cr_psstat); + else + status = dev->pma_sample_status; + if (status == IB_PMA_SAMPLE_STATUS_DONE) { + dev->pma_sample_start = be32_to_cpu(p->sample_start); + dev->pma_sample_interval = be32_to_cpu(p->sample_interval); + dev->pma_tag = be16_to_cpu(p->tag); + dev->pma_counter_select[0] = p->counter_select[0]; + dev->pma_counter_select[1] = p->counter_select[1]; + dev->pma_counter_select[2] = p->counter_select[2]; + dev->pma_counter_select[3] = p->counter_select[3]; + dev->pma_counter_select[4] = p->counter_select[4]; + if (crp->cr_psstat) { + ipath_write_creg(dev->dd, crp->cr_psinterval, + dev->pma_sample_interval); + ipath_write_creg(dev->dd, crp->cr_psstart, + dev->pma_sample_start); + } else + dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_STARTED; } + spin_unlock_irqrestore(&dev->pending_lock, flags); + ret = recv_pma_get_portsamplescontrol(pmp, ibdev, port); bail: return ret; } -static u64 get_counter(struct ipath_ibdev *dev, __be16 sel) +static u64 get_counter(struct ipath_ibdev *dev, + struct ipath_cregs const *crp, + __be16 sel) { u64 ret; switch (sel) { case IB_PMA_PORT_XMIT_DATA: - ret = dev->ipath_sword; + ret = (crp->cr_psxmitdatacount) ? + ipath_read_creg32(dev->dd, crp->cr_psxmitdatacount) : + dev->ipath_sword; break; case IB_PMA_PORT_RCV_DATA: - ret = dev->ipath_rword; + ret = (crp->cr_psrcvdatacount) ? + ipath_read_creg32(dev->dd, crp->cr_psrcvdatacount) : + dev->ipath_rword; break; case IB_PMA_PORT_XMIT_PKTS: - ret = dev->ipath_spkts; + ret = (crp->cr_psxmitpktscount) ? + ipath_read_creg32(dev->dd, crp->cr_psxmitpktscount) : + dev->ipath_spkts; break; case IB_PMA_PORT_RCV_PKTS: - ret = dev->ipath_rpkts; + ret = (crp->cr_psrcvpktscount) ? + ipath_read_creg32(dev->dd, crp->cr_psrcvpktscount) : + dev->ipath_rpkts; break; case IB_PMA_PORT_XMIT_WAIT: - ret = dev->ipath_xmit_wait; + ret = (crp->cr_psxmitwaitcount) ? + ipath_read_creg32(dev->dd, crp->cr_psxmitwaitcount) : + dev->ipath_xmit_wait; break; default: ret = 0; @@ -1053,14 +1066,21 @@ static int recv_pma_get_portsamplesresult(struct ib_perf *pmp, struct ib_pma_portsamplesresult *p = (struct ib_pma_portsamplesresult *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_cregs const *crp = dev->dd->ipath_cregs; + u8 status; int i; memset(pmp->data, 0, sizeof(pmp->data)); p->tag = cpu_to_be16(dev->pma_tag); - p->sample_status = cpu_to_be16(dev->pma_sample_status); + if (crp->cr_psstat) + status = ipath_read_creg32(dev->dd, crp->cr_psstat); + else + status = dev->pma_sample_status; + p->sample_status = cpu_to_be16(status); for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++) - p->counter[i] = cpu_to_be32( - get_counter(dev, dev->pma_counter_select[i])); + p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 : + cpu_to_be32( + get_counter(dev, crp, dev->pma_counter_select[i])); return reply((struct ib_smp *) pmp); } @@ -1071,16 +1091,23 @@ static int recv_pma_get_portsamplesresult_ext(struct ib_perf *pmp, struct ib_pma_portsamplesresult_ext *p = (struct ib_pma_portsamplesresult_ext *)pmp->data; struct ipath_ibdev *dev = to_idev(ibdev); + struct ipath_cregs const *crp = dev->dd->ipath_cregs; + u8 status; int i; memset(pmp->data, 0, sizeof(pmp->data)); p->tag = cpu_to_be16(dev->pma_tag); - p->sample_status = cpu_to_be16(dev->pma_sample_status); + if (crp->cr_psstat) + status = ipath_read_creg32(dev->dd, crp->cr_psstat); + else + status = dev->pma_sample_status; + p->sample_status = cpu_to_be16(status); /* 64 bits */ p->extended_width = __constant_cpu_to_be32(0x80000000); for (i = 0; i < ARRAY_SIZE(dev->pma_counter_select); i++) - p->counter[i] = cpu_to_be64( - get_counter(dev, dev->pma_counter_select[i])); + p->counter[i] = (status != IB_PMA_SAMPLE_STATUS_DONE) ? 0 : + cpu_to_be64( + get_counter(dev, crp, dev->pma_counter_select[i])); return reply((struct ib_smp *) pmp); } @@ -1113,6 +1140,8 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp, dev->z_local_link_integrity_errors; cntrs.excessive_buffer_overrun_errors -= dev->z_excessive_buffer_overrun_errors; + cntrs.vl15_dropped -= dev->z_vl15_dropped; + cntrs.vl15_dropped += dev->n_vl15_dropped; memset(pmp->data, 0, sizeof(pmp->data)); @@ -1156,10 +1185,10 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp, cntrs.excessive_buffer_overrun_errors = 0xFUL; p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) | cntrs.excessive_buffer_overrun_errors; - if (dev->n_vl15_dropped > 0xFFFFUL) + if (cntrs.vl15_dropped > 0xFFFFUL) p->vl15_dropped = __constant_cpu_to_be16(0xFFFF); else - p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped); + p->vl15_dropped = cpu_to_be16((u16)cntrs.vl15_dropped); if (cntrs.port_xmit_data > 0xFFFFFFFFUL) p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF); else @@ -1262,8 +1291,10 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp, dev->z_excessive_buffer_overrun_errors = cntrs.excessive_buffer_overrun_errors; - if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) + if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED) { dev->n_vl15_dropped = 0; + dev->z_vl15_dropped = cntrs.vl15_dropped; + } if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA) dev->z_port_xmit_data = cntrs.port_xmit_data; @@ -1434,7 +1465,7 @@ static int process_subn(struct ib_device *ibdev, int mad_flags, * before checking for other consumers. * Just tell the caller to process it normally. */ - ret = IB_MAD_RESULT_FAILURE; + ret = IB_MAD_RESULT_SUCCESS; goto bail; default: smp->status |= IB_SMP_UNSUP_METHOD; @@ -1516,7 +1547,7 @@ static int process_perf(struct ib_device *ibdev, u8 port_num, * before checking for other consumers. * Just tell the caller to process it normally. */ - ret = IB_MAD_RESULT_FAILURE; + ret = IB_MAD_RESULT_SUCCESS; goto bail; default: pmp->status |= IB_SMP_UNSUP_METHOD; diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c index b997ff88401b..80dc623cee40 100644 --- a/drivers/infiniband/hw/ipath/ipath_qp.c +++ b/drivers/infiniband/hw/ipath/ipath_qp.c @@ -387,8 +387,8 @@ int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err) struct ib_wc wc; int ret = 0; - ipath_dbg("QP%d/%d in error state\n", - qp->ibqp.qp_num, qp->remote_qpn); + ipath_dbg("QP%d/%d in error state (%d)\n", + qp->ibqp.qp_num, qp->remote_qpn, err); spin_lock(&dev->pending_lock); /* XXX What if its already removed by the timeout code? */ @@ -855,8 +855,6 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd, * See ipath_mmap() for details. */ if (udata && udata->outlen >= sizeof(__u64)) { - int err; - if (!qp->r_rq.wq) { __u64 offset = 0; diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c index 120a61b03bc4..459e46e2c016 100644 --- a/drivers/infiniband/hw/ipath/ipath_rc.c +++ b/drivers/infiniband/hw/ipath/ipath_rc.c @@ -647,6 +647,7 @@ static void send_rc_ack(struct ipath_qp *qp) queue_ack: spin_lock_irqsave(&qp->s_lock, flags); + dev->n_rc_qacks++; qp->s_flags |= IPATH_S_ACK_PENDING; qp->s_nak_state = qp->r_nak_state; qp->s_ack_psn = qp->r_ack_psn; @@ -798,11 +799,13 @@ bail: static inline void update_last_psn(struct ipath_qp *qp, u32 psn) { - if (qp->s_wait_credit) { - qp->s_wait_credit = 0; - tasklet_hi_schedule(&qp->s_task); + if (qp->s_last_psn != psn) { + qp->s_last_psn = psn; + if (qp->s_wait_credit) { + qp->s_wait_credit = 0; + tasklet_hi_schedule(&qp->s_task); + } } - qp->s_last_psn = psn; } /** @@ -1653,13 +1656,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr, case OP(SEND_FIRST): if (!ipath_get_rwqe(qp, 0)) { rnr_nak: - /* - * A RNR NAK will ACK earlier sends and RDMA writes. - * Don't queue the NAK if a RDMA read or atomic - * is pending though. - */ - if (qp->r_nak_state) - goto done; qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer; qp->r_ack_psn = qp->r_psn; goto send_ack; diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h index 708eba3165d7..6d2a17f9c1da 100644 --- a/drivers/infiniband/hw/ipath/ipath_registers.h +++ b/drivers/infiniband/hw/ipath/ipath_registers.h @@ -82,8 +82,7 @@ /* kr_rcvctrl bits */ #define INFINIPATH_R_PORTENABLE_SHIFT 0 -#define INFINIPATH_R_INTRAVAIL_SHIFT 16 -#define INFINIPATH_R_TAILUPD 0x80000000 +#define INFINIPATH_R_QPMAP_ENABLE (1ULL << 38) /* kr_intstatus, kr_intclear, kr_intmask bits */ #define INFINIPATH_I_RCVURG_SHIFT 0 @@ -272,20 +271,6 @@ #define INFINIPATH_EXTC_LEDGBLOK_ON 0x00000002ULL #define INFINIPATH_EXTC_LEDGBLERR_OFF 0x00000001ULL -/* kr_mdio bits */ -#define INFINIPATH_MDIO_CLKDIV_MASK 0x7FULL -#define INFINIPATH_MDIO_CLKDIV_SHIFT 32 -#define INFINIPATH_MDIO_COMMAND_MASK 0x7ULL -#define INFINIPATH_MDIO_COMMAND_SHIFT 26 -#define INFINIPATH_MDIO_DEVADDR_MASK 0x1FULL -#define INFINIPATH_MDIO_DEVADDR_SHIFT 21 -#define INFINIPATH_MDIO_REGADDR_MASK 0x1FULL -#define INFINIPATH_MDIO_REGADDR_SHIFT 16 -#define INFINIPATH_MDIO_DATA_MASK 0xFFFFULL -#define INFINIPATH_MDIO_DATA_SHIFT 0 -#define INFINIPATH_MDIO_CMDVALID 0x0000000040000000ULL -#define INFINIPATH_MDIO_RDDATAVALID 0x0000000080000000ULL - /* kr_partitionkey bits */ #define INFINIPATH_PKEY_SIZE 16 #define INFINIPATH_PKEY_MASK 0xFFFF @@ -303,8 +288,6 @@ /* kr_xgxsconfig bits */ #define INFINIPATH_XGXS_RESET 0x7ULL -#define INFINIPATH_XGXS_MDIOADDR_MASK 0xfULL -#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4 #define INFINIPATH_XGXS_RX_POL_SHIFT 19 #define INFINIPATH_XGXS_RX_POL_MASK 0xfULL @@ -470,6 +453,20 @@ struct ipath_cregs { ipath_creg cr_unsupvlcnt; ipath_creg cr_wordrcvcnt; ipath_creg cr_wordsendcnt; + ipath_creg cr_vl15droppedpktcnt; + ipath_creg cr_rxotherlocalphyerrcnt; + ipath_creg cr_excessbufferovflcnt; + ipath_creg cr_locallinkintegrityerrcnt; + ipath_creg cr_rxvlerrcnt; + ipath_creg cr_rxdlidfltrcnt; + ipath_creg cr_psstat; + ipath_creg cr_psstart; + ipath_creg cr_psinterval; + ipath_creg cr_psrcvdatacount; + ipath_creg cr_psrcvpktscount; + ipath_creg cr_psxmitdatacount; + ipath_creg cr_psxmitpktscount; + ipath_creg cr_psxmitwaitcount; }; #endif /* _IPATH_REGISTERS_H */ diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c index 54c61a972de2..a59bdbd0ed87 100644 --- a/drivers/infiniband/hw/ipath/ipath_ruc.c +++ b/drivers/infiniband/hw/ipath/ipath_ruc.c @@ -98,11 +98,15 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp) while (qp->s_rnr_timeout >= nqp->s_rnr_timeout) { qp->s_rnr_timeout -= nqp->s_rnr_timeout; l = l->next; - if (l->next == &dev->rnrwait) + if (l->next == &dev->rnrwait) { + nqp = NULL; break; + } nqp = list_entry(l->next, struct ipath_qp, timerwait); } + if (nqp) + nqp->s_rnr_timeout -= qp->s_rnr_timeout; list_add(&qp->timerwait, l); } spin_unlock_irqrestore(&dev->pending_lock, flags); @@ -479,9 +483,14 @@ done: static void want_buffer(struct ipath_devdata *dd) { - set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl); + unsigned long flags; + + spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags); + dd->ipath_sendctrl |= INFINIPATH_S_PIOINTBUFAVAIL; ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl); + ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); + spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags); } /** diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c index 2fef36f4b675..f772102e4713 100644 --- a/drivers/infiniband/hw/ipath/ipath_srq.c +++ b/drivers/infiniband/hw/ipath/ipath_srq.c @@ -94,8 +94,8 @@ bail: /** * ipath_create_srq - create a shared receive queue * @ibpd: the protection domain of the SRQ to create - * @attr: the attributes of the SRQ - * @udata: not used by the InfiniPath verbs driver + * @srq_init_attr: the attributes of the SRQ + * @udata: data from libipathverbs when creating a user SRQ */ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd, struct ib_srq_init_attr *srq_init_attr, diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c index f0271415cd5b..d2725cd11bdc 100644 --- a/drivers/infiniband/hw/ipath/ipath_stats.c +++ b/drivers/infiniband/hw/ipath/ipath_stats.c @@ -133,15 +133,16 @@ bail: static void ipath_qcheck(struct ipath_devdata *dd) { static u64 last_tot_hdrqfull; + struct ipath_portdata *pd = dd->ipath_pd[0]; size_t blen = 0; char buf[128]; *buf = 0; - if (dd->ipath_pd[0]->port_hdrqfull != dd->ipath_p0_hdrqfull) { + if (pd->port_hdrqfull != dd->ipath_p0_hdrqfull) { blen = snprintf(buf, sizeof buf, "port 0 hdrqfull %u", - dd->ipath_pd[0]->port_hdrqfull - + pd->port_hdrqfull - dd->ipath_p0_hdrqfull); - dd->ipath_p0_hdrqfull = dd->ipath_pd[0]->port_hdrqfull; + dd->ipath_p0_hdrqfull = pd->port_hdrqfull; } if (ipath_stats.sps_etidfull != dd->ipath_last_tidfull) { blen += snprintf(buf + blen, sizeof buf - blen, @@ -173,7 +174,7 @@ static void ipath_qcheck(struct ipath_devdata *dd) if (blen) ipath_dbg("%s\n", buf); - if (dd->ipath_port0head != (u32) + if (pd->port_head != (u32) le64_to_cpu(*dd->ipath_hdrqtailptr)) { if (dd->ipath_lastport0rcv_cnt == ipath_stats.sps_port0pkts) { @@ -181,7 +182,7 @@ static void ipath_qcheck(struct ipath_devdata *dd) "port0 hd=%llx tl=%x; port0pkts %llx\n", (unsigned long long) le64_to_cpu(*dd->ipath_hdrqtailptr), - dd->ipath_port0head, + pd->port_head, (unsigned long long) ipath_stats.sps_port0pkts); } @@ -237,7 +238,7 @@ static void ipath_chk_errormask(struct ipath_devdata *dd) void ipath_get_faststats(unsigned long opaque) { struct ipath_devdata *dd = (struct ipath_devdata *) opaque; - u32 val; + int i; static unsigned cnt; unsigned long flags; u64 traffic_wds; @@ -321,12 +322,11 @@ void ipath_get_faststats(unsigned long opaque) /* limit qfull messages to ~one per minute per port */ if ((++cnt & 0x10)) { - for (val = dd->ipath_cfgports - 1; ((int)val) >= 0; - val--) { - if (dd->ipath_lastegrheads[val] != -1) - dd->ipath_lastegrheads[val] = -1; - if (dd->ipath_lastrcvhdrqtails[val] != -1) - dd->ipath_lastrcvhdrqtails[val] = -1; + for (i = (int) dd->ipath_cfgports; --i >= 0; ) { + struct ipath_portdata *pd = dd->ipath_pd[i]; + + if (pd && pd->port_lastrcvhdrqtail != -1) + pd->port_lastrcvhdrqtail = -1; } } diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c index e1ad7cfc21fd..56dfc8a2344c 100644 --- a/drivers/infiniband/hw/ipath/ipath_sysfs.c +++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c @@ -363,6 +363,60 @@ static ssize_t show_unit(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_unit); } +static ssize_t show_jint_max_packets(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_max_packets); +} + +static ssize_t store_jint_max_packets(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + u16 v = 0; + int ret; + + ret = ipath_parse_ushort(buf, &v); + if (ret < 0) + ipath_dev_err(dd, "invalid jint_max_packets.\n"); + else + dd->ipath_f_config_jint(dd, dd->ipath_jint_idle_ticks, v); + + return ret; +} + +static ssize_t show_jint_idle_ticks(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%hu\n", dd->ipath_jint_idle_ticks); +} + +static ssize_t store_jint_idle_ticks(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + u16 v = 0; + int ret; + + ret = ipath_parse_ushort(buf, &v); + if (ret < 0) + ipath_dev_err(dd, "invalid jint_idle_ticks.\n"); + else + dd->ipath_f_config_jint(dd, v, dd->ipath_jint_max_packets); + + return ret; +} + #define DEVICE_COUNTER(name, attr) \ static ssize_t show_counter_##name(struct device *dev, \ struct device_attribute *attr, \ @@ -670,6 +724,257 @@ static ssize_t show_logged_errs(struct device *dev, return count; } +/* + * New sysfs entries to control various IB config. These all turn into + * accesses via ipath_f_get/set_ib_cfg. + * + * Get/Set heartbeat enable. Or of 1=enabled, 2=auto + */ +static ssize_t show_hrtbt_enb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_HRTBT); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +static ssize_t store_hrtbt_enb(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret, r; + u16 val; + + ret = ipath_parse_ushort(buf, &val); + if (ret >= 0 && val > 3) + ret = -EINVAL; + if (ret < 0) { + ipath_dev_err(dd, "attempt to set invalid Heartbeat enable\n"); + goto bail; + } + + /* + * Set the "intentional" heartbeat enable per either of + * "Enable" and "Auto", as these are normally set together. + * This bit is consulted when leaving loopback mode, + * because entering loopback mode overrides it and automatically + * disables heartbeat. + */ + r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_HRTBT, val); + if (r < 0) + ret = r; + else if (val == IPATH_IB_HRTBT_OFF) + dd->ipath_flags |= IPATH_NO_HRTBT; + else + dd->ipath_flags &= ~IPATH_NO_HRTBT; + +bail: + return ret; +} + +/* + * Get/Set Link-widths enabled. Or of 1=1x, 2=4x (this is human/IB centric, + * _not_ the particular encoding of any given chip) + */ +static ssize_t show_lwid_enb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +static ssize_t store_lwid_enb(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret, r; + u16 val; + + ret = ipath_parse_ushort(buf, &val); + if (ret >= 0 && (val == 0 || val > 3)) + ret = -EINVAL; + if (ret < 0) { + ipath_dev_err(dd, + "attempt to set invalid Link Width (enable)\n"); + goto bail; + } + + r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LWID_ENB, val); + if (r < 0) + ret = r; + +bail: + return ret; +} + +/* Get current link width */ +static ssize_t show_lwid(struct device *dev, + struct device_attribute *attr, + char *buf) + +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LWID); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +/* + * Get/Set Link-speeds enabled. Or of 1=SDR 2=DDR. + */ +static ssize_t show_spd_enb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +static ssize_t store_spd_enb(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret, r; + u16 val; + + ret = ipath_parse_ushort(buf, &val); + if (ret >= 0 && (val == 0 || val > (IPATH_IB_SDR | IPATH_IB_DDR))) + ret = -EINVAL; + if (ret < 0) { + ipath_dev_err(dd, + "attempt to set invalid Link Speed (enable)\n"); + goto bail; + } + + r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_SPD_ENB, val); + if (r < 0) + ret = r; + +bail: + return ret; +} + +/* Get current link speed */ +static ssize_t show_spd(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_SPD); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +/* + * Get/Set RX polarity-invert enable. 0=no, 1=yes. + */ +static ssize_t show_rx_polinv_enb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +static ssize_t store_rx_polinv_enb(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret, r; + u16 val; + + ret = ipath_parse_ushort(buf, &val); + if (ret < 0 || val > 1) + goto invalid; + + r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_RXPOL_ENB, val); + if (r < 0) { + ret = r; + goto bail; + } + + goto bail; +invalid: + ipath_dev_err(dd, "attempt to set invalid Rx Polarity (enable)\n"); +bail: + return ret; +} +/* + * Get/Set RX lane-reversal enable. 0=no, 1=yes. + */ +static ssize_t show_lanerev_enb(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret; + + ret = dd->ipath_f_get_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB); + if (ret >= 0) + ret = scnprintf(buf, PAGE_SIZE, "%d\n", ret); + return ret; +} + +static ssize_t store_lanerev_enb(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct ipath_devdata *dd = dev_get_drvdata(dev); + int ret, r; + u16 val; + + ret = ipath_parse_ushort(buf, &val); + if (ret >= 0 && val > 1) { + ret = -EINVAL; + ipath_dev_err(dd, + "attempt to set invalid Lane reversal (enable)\n"); + goto bail; + } + + r = dd->ipath_f_set_ib_cfg(dd, IPATH_IB_CFG_LREV_ENB, val); + if (r < 0) + ret = r; + +bail: + return ret; +} + static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL); static DRIVER_ATTR(version, S_IRUGO, show_version, NULL); @@ -683,6 +988,11 @@ static struct attribute_group driver_attr_group = { .attrs = driver_attributes }; +struct attribute_group *ipath_driver_attr_groups[] = { + &driver_attr_group, + NULL, +}; + static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid); static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc); static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid); @@ -701,6 +1011,10 @@ static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL); static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv); static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override); static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL); +static DEVICE_ATTR(jint_max_packets, S_IWUSR | S_IRUGO, + show_jint_max_packets, store_jint_max_packets); +static DEVICE_ATTR(jint_idle_ticks, S_IWUSR | S_IRUGO, + show_jint_idle_ticks, store_jint_idle_ticks); static struct attribute *dev_attributes[] = { &dev_attr_guid.attr, @@ -727,6 +1041,34 @@ static struct attribute_group dev_attr_group = { .attrs = dev_attributes }; +static DEVICE_ATTR(hrtbt_enable, S_IWUSR | S_IRUGO, show_hrtbt_enb, + store_hrtbt_enb); +static DEVICE_ATTR(link_width_enable, S_IWUSR | S_IRUGO, show_lwid_enb, + store_lwid_enb); +static DEVICE_ATTR(link_width, S_IRUGO, show_lwid, NULL); +static DEVICE_ATTR(link_speed_enable, S_IWUSR | S_IRUGO, show_spd_enb, + store_spd_enb); +static DEVICE_ATTR(link_speed, S_IRUGO, show_spd, NULL); +static DEVICE_ATTR(rx_pol_inv_enable, S_IWUSR | S_IRUGO, show_rx_polinv_enb, + store_rx_polinv_enb); +static DEVICE_ATTR(rx_lane_rev_enable, S_IWUSR | S_IRUGO, show_lanerev_enb, + store_lanerev_enb); + +static struct attribute *dev_ibcfg_attributes[] = { + &dev_attr_hrtbt_enable.attr, + &dev_attr_link_width_enable.attr, + &dev_attr_link_width.attr, + &dev_attr_link_speed_enable.attr, + &dev_attr_link_speed.attr, + &dev_attr_rx_pol_inv_enable.attr, + &dev_attr_rx_lane_rev_enable.attr, + NULL +}; + +static struct attribute_group dev_ibcfg_attr_group = { + .attrs = dev_ibcfg_attributes +}; + /** * ipath_expose_reset - create a device reset file * @dev: the device structure @@ -753,24 +1095,9 @@ int ipath_expose_reset(struct device *dev) return ret; } -int ipath_driver_create_group(struct device_driver *drv) -{ - int ret; - - ret = sysfs_create_group(&drv->kobj, &driver_attr_group); - - return ret; -} - -void ipath_driver_remove_group(struct device_driver *drv) -{ - sysfs_remove_group(&drv->kobj, &driver_attr_group); -} - int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) { int ret; - char unit[5]; ret = sysfs_create_group(&dev->kobj, &dev_attr_group); if (ret) @@ -780,11 +1107,26 @@ int ipath_device_create_group(struct device *dev, struct ipath_devdata *dd) if (ret) goto bail_attrs; - snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); - ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, unit); - if (ret == 0) - goto bail; + if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) { + ret = device_create_file(dev, &dev_attr_jint_idle_ticks); + if (ret) + goto bail_counter; + ret = device_create_file(dev, &dev_attr_jint_max_packets); + if (ret) + goto bail_idle; + ret = sysfs_create_group(&dev->kobj, &dev_ibcfg_attr_group); + if (ret) + goto bail_max; + } + + return 0; + +bail_max: + device_remove_file(dev, &dev_attr_jint_max_packets); +bail_idle: + device_remove_file(dev, &dev_attr_jint_idle_ticks); +bail_counter: sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); bail_attrs: sysfs_remove_group(&dev->kobj, &dev_attr_group); @@ -794,12 +1136,14 @@ bail: void ipath_device_remove_group(struct device *dev, struct ipath_devdata *dd) { - char unit[5]; + sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); - snprintf(unit, sizeof(unit), "%02d", dd->ipath_unit); - sysfs_remove_link(&dev->driver->kobj, unit); + if (dd->ipath_flags & IPATH_HAS_MULT_IB_SPEED) { + sysfs_remove_group(&dev->kobj, &dev_ibcfg_attr_group); + device_remove_file(dev, &dev_attr_jint_idle_ticks); + device_remove_file(dev, &dev_attr_jint_max_packets); + } - sysfs_remove_group(&dev->kobj, &dev_counter_attr_group); sysfs_remove_group(&dev->kobj, &dev_attr_group); device_remove_file(dev, &dev_attr_reset); diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c index b3df6f3c705e..de67eed08ed0 100644 --- a/drivers/infiniband/hw/ipath/ipath_ud.c +++ b/drivers/infiniband/hw/ipath/ipath_ud.c @@ -301,8 +301,6 @@ int ipath_make_ud_req(struct ipath_qp *qp) /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ qp->s_hdrwords = 7; - if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) - qp->s_hdrwords++; qp->s_cur_size = wqe->length; qp->s_cur_sge = &qp->s_sge; qp->s_wqe = wqe; @@ -327,6 +325,7 @@ int ipath_make_ud_req(struct ipath_qp *qp) ohdr = &qp->s_hdr.u.oth; } if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + qp->s_hdrwords++; ohdr->u.ud.imm_data = wqe->wr.imm_data; bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; } else diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c index c4c998446c7b..32d8f882e56c 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.c +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c @@ -943,7 +943,7 @@ bail: * ipath_verbs_send - send a packet * @qp: the QP to send on * @hdr: the packet header - * @hdrwords: the number of words in the header + * @hdrwords: the number of 32-bit words in the header * @ss: the SGE to send * @len: the length of the packet in bytes */ @@ -955,7 +955,10 @@ int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr, int ret; u32 dwords = (len + 3) >> 2; - /* +1 is for the qword padding of pbc */ + /* + * Calculate the send buffer trigger address. + * The +1 counts for the pbc control dword following the pbc length. + */ plen = hdrwords + dwords + 1; /* Drop non-VL15 packets if we are not in the active state */ @@ -1130,20 +1133,34 @@ static int ipath_query_device(struct ib_device *ibdev, return 0; } -const u8 ipath_cvt_physportstate[16] = { - [INFINIPATH_IBCS_LT_STATE_DISABLED] = 3, - [INFINIPATH_IBCS_LT_STATE_LINKUP] = 5, - [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2, - [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2, - [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1, - [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1, - [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4, - [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4, - [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4, - [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4, - [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6, - [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6, - [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6, +const u8 ipath_cvt_physportstate[32] = { + [INFINIPATH_IBCS_LT_STATE_DISABLED] = IB_PHYSPORTSTATE_DISABLED, + [INFINIPATH_IBCS_LT_STATE_LINKUP] = IB_PHYSPORTSTATE_LINKUP, + [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = IB_PHYSPORTSTATE_POLL, + [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = IB_PHYSPORTSTATE_POLL, + [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = IB_PHYSPORTSTATE_SLEEP, + [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = IB_PHYSPORTSTATE_SLEEP, + [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = + IB_PHYSPORTSTATE_CFG_TRAIN, + [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = + IB_PHYSPORTSTATE_CFG_TRAIN, + [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = + IB_PHYSPORTSTATE_CFG_TRAIN, + [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = IB_PHYSPORTSTATE_CFG_TRAIN, + [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = + IB_PHYSPORTSTATE_LINK_ERR_RECOVER, + [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = + IB_PHYSPORTSTATE_LINK_ERR_RECOVER, + [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = + IB_PHYSPORTSTATE_LINK_ERR_RECOVER, + [0x10] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x11] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x12] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x13] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x14] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x15] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x16] = IB_PHYSPORTSTATE_CFG_TRAIN, + [0x17] = IB_PHYSPORTSTATE_CFG_TRAIN }; u32 ipath_get_cr_errpkey(struct ipath_devdata *dd) @@ -1168,8 +1185,9 @@ static int ipath_query_port(struct ib_device *ibdev, ibcstat = dd->ipath_lastibcstat; props->state = ((ibcstat >> 4) & 0x3) + 1; /* See phys_state_show() */ - props->phys_state = ipath_cvt_physportstate[ - dd->ipath_lastibcstat & 0xf]; + props->phys_state = /* MEA: assumes shift == 0 */ + ipath_cvt_physportstate[dd->ipath_lastibcstat & + dd->ibcs_lts_mask]; props->port_cap_flags = dev->port_cap_flags; props->gid_tbl_len = 1; props->max_msg_sz = 0x80000000; @@ -1641,6 +1659,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd) cntrs.local_link_integrity_errors; idev->z_excessive_buffer_overrun_errors = cntrs.excessive_buffer_overrun_errors; + idev->z_vl15_dropped = cntrs.vl15_dropped; /* * The system image GUID is supposed to be the same for all diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h index 6ccb54f104a3..3d59736b49b2 100644 --- a/drivers/infiniband/hw/ipath/ipath_verbs.h +++ b/drivers/infiniband/hw/ipath/ipath_verbs.h @@ -554,6 +554,7 @@ struct ipath_ibdev { u32 z_pkey_violations; /* starting count for PMA */ u32 z_local_link_integrity_errors; /* starting count for PMA */ u32 z_excessive_buffer_overrun_errors; /* starting count for PMA */ + u32 z_vl15_dropped; /* starting count for PMA */ u32 n_rc_resends; u32 n_rc_acks; u32 n_rc_qacks; @@ -598,6 +599,7 @@ struct ipath_verbs_counters { u64 port_rcv_packets; u32 local_link_integrity_errors; u32 excessive_buffer_overrun_errors; + u32 vl15_dropped; }; static inline struct ipath_mr *to_imr(struct ib_mr *ibmr) @@ -830,7 +832,17 @@ unsigned ipath_get_pkey(struct ipath_devdata *, unsigned); extern const enum ib_wc_opcode ib_ipath_wc_opcode[]; +/* + * Below converts HCA-specific LinkTrainingState to IB PhysPortState + * values. + */ extern const u8 ipath_cvt_physportstate[]; +#define IB_PHYSPORTSTATE_SLEEP 1 +#define IB_PHYSPORTSTATE_POLL 2 +#define IB_PHYSPORTSTATE_DISABLED 3 +#define IB_PHYSPORTSTATE_CFG_TRAIN 4 +#define IB_PHYSPORTSTATE_LINKUP 5 +#define IB_PHYSPORTSTATE_LINK_ERR_RECOVER 6 extern const int ib_ipath_state_ops[]; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 9d32c49cc651..7950aa6e8184 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -313,6 +313,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_ib_srq *srq; int is_send; int is_error; + u32 g_mlpath_rqpn; u16 wqe_ctr; cqe = next_cqe_sw(cq); @@ -426,10 +427,10 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, wc->slid = be16_to_cpu(cqe->rlid); wc->sl = cqe->sl >> 4; - wc->src_qp = be32_to_cpu(cqe->g_mlpath_rqpn) & 0xffffff; - wc->dlid_path_bits = (be32_to_cpu(cqe->g_mlpath_rqpn) >> 24) & 0x7f; - wc->wc_flags |= be32_to_cpu(cqe->g_mlpath_rqpn) & 0x80000000 ? - IB_WC_GRH : 0; + g_mlpath_rqpn = be32_to_cpu(cqe->g_mlpath_rqpn); + wc->src_qp = g_mlpath_rqpn & 0xffffff; + wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f; + wc->wc_flags |= g_mlpath_rqpn & 0x80000000 ? IB_WC_GRH : 0; wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; } diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h index 15aa32eb78b6..7bbdd1f4e6c7 100644 --- a/drivers/infiniband/hw/mthca/mthca_dev.h +++ b/drivers/infiniband/hw/mthca/mthca_dev.h @@ -60,13 +60,12 @@ enum { MTHCA_FLAG_DDR_HIDDEN = 1 << 1, MTHCA_FLAG_SRQ = 1 << 2, - MTHCA_FLAG_MSI = 1 << 3, - MTHCA_FLAG_MSI_X = 1 << 4, - MTHCA_FLAG_NO_LAM = 1 << 5, - MTHCA_FLAG_FMR = 1 << 6, - MTHCA_FLAG_MEMFREE = 1 << 7, - MTHCA_FLAG_PCIE = 1 << 8, - MTHCA_FLAG_SINAI_OPT = 1 << 9 + MTHCA_FLAG_MSI_X = 1 << 3, + MTHCA_FLAG_NO_LAM = 1 << 4, + MTHCA_FLAG_FMR = 1 << 5, + MTHCA_FLAG_MEMFREE = 1 << 6, + MTHCA_FLAG_PCIE = 1 << 7, + MTHCA_FLAG_SINAI_OPT = 1 << 8 }; enum { diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index b29de51b7f35..b60eb5df96e8 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -827,8 +827,7 @@ int mthca_init_eq_table(struct mthca_dev *dev) if (err) goto err_out_free; - if (dev->mthca_flags & MTHCA_FLAG_MSI || - dev->mthca_flags & MTHCA_FLAG_MSI_X) { + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { dev->eq_table.clr_mask = 0; } else { dev->eq_table.clr_mask = @@ -839,8 +838,7 @@ int mthca_init_eq_table(struct mthca_dev *dev) dev->eq_table.arm_mask = 0; - intr = (dev->mthca_flags & MTHCA_FLAG_MSI) ? - 128 : dev->eq_table.inta_pin; + intr = dev->eq_table.inta_pin; err = mthca_create_eq(dev, dev->limits.num_cqs + MTHCA_NUM_SPARE_EQE, (dev->mthca_flags & MTHCA_FLAG_MSI_X) ? 128 : intr, diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 60de6f93869e..5cf8250d4e16 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -65,14 +65,9 @@ static int msi_x = 1; module_param(msi_x, int, 0444); MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero"); -static int msi = 0; -module_param(msi, int, 0444); -MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)"); - #else /* CONFIG_PCI_MSI */ #define msi_x (0) -#define msi (0) #endif /* CONFIG_PCI_MSI */ @@ -816,13 +811,11 @@ static int mthca_setup_hca(struct mthca_dev *dev) err = mthca_NOP(dev, &status); if (err || status) { - if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) { + if (dev->mthca_flags & MTHCA_FLAG_MSI_X) { mthca_warn(dev, "NOP command failed to generate interrupt " "(IRQ %d).\n", - dev->mthca_flags & MTHCA_FLAG_MSI_X ? - dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector : - dev->pdev->irq); - mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n"); + dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector); + mthca_warn(dev, "Trying again with MSI-X disabled.\n"); } else { mthca_err(dev, "NOP command failed to generate interrupt " "(IRQ %d), aborting.\n", @@ -1005,7 +998,7 @@ static struct { .flags = 0 }, [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 8, 200), .flags = MTHCA_FLAG_PCIE }, - [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 2, 0), + [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 3, 0), .flags = MTHCA_FLAG_MEMFREE | MTHCA_FLAG_PCIE }, [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 2, 0), @@ -1128,29 +1121,12 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type) if (msi_x && !mthca_enable_msi_x(mdev)) mdev->mthca_flags |= MTHCA_FLAG_MSI_X; - else if (msi) { - static int warned; - - if (!warned) { - printk(KERN_WARNING PFX "WARNING: MSI support will be " - "removed from the ib_mthca driver in January 2008.\n"); - printk(KERN_WARNING " If you are using MSI and cannot " - "switch to MSI-X, please tell " - "<general@lists.openfabrics.org>.\n"); - ++warned; - } - - if (!pci_enable_msi(pdev)) - mdev->mthca_flags |= MTHCA_FLAG_MSI; - } err = mthca_setup_hca(mdev); - if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) { + if (err == -EBUSY && (mdev->mthca_flags & MTHCA_FLAG_MSI_X)) { if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); - if (mdev->mthca_flags & MTHCA_FLAG_MSI) - pci_disable_msi(pdev); - mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI); + mdev->mthca_flags &= ~MTHCA_FLAG_MSI_X; err = mthca_setup_hca(mdev); } @@ -1192,8 +1168,6 @@ err_cleanup: err_close: if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); - if (mdev->mthca_flags & MTHCA_FLAG_MSI) - pci_disable_msi(pdev); mthca_close_hca(mdev); @@ -1246,8 +1220,6 @@ static void __mthca_remove_one(struct pci_dev *pdev) if (mdev->mthca_flags & MTHCA_FLAG_MSI_X) pci_disable_msix(pdev); - if (mdev->mthca_flags & MTHCA_FLAG_MSI) - pci_disable_msi(pdev); ib_dealloc_device(&mdev->ib_dev); mthca_release_regions(pdev, mdev->mthca_flags & diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index eb7edab0e836..fe250c60607d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -56,42 +56,43 @@ /* constants */ enum { - IPOIB_PACKET_SIZE = 2048, - IPOIB_BUF_SIZE = IPOIB_PACKET_SIZE + IB_GRH_BYTES, + IPOIB_PACKET_SIZE = 2048, + IPOIB_BUF_SIZE = IPOIB_PACKET_SIZE + IB_GRH_BYTES, - IPOIB_ENCAP_LEN = 4, + IPOIB_ENCAP_LEN = 4, - IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */ - IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN, - IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE, - IPOIB_CM_RX_SG = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE, - IPOIB_RX_RING_SIZE = 128, - IPOIB_TX_RING_SIZE = 64, + IPOIB_CM_MTU = 0x10000 - 0x10, /* padding to align header to 16 */ + IPOIB_CM_BUF_SIZE = IPOIB_CM_MTU + IPOIB_ENCAP_LEN, + IPOIB_CM_HEAD_SIZE = IPOIB_CM_BUF_SIZE % PAGE_SIZE, + IPOIB_CM_RX_SG = ALIGN(IPOIB_CM_BUF_SIZE, PAGE_SIZE) / PAGE_SIZE, + IPOIB_RX_RING_SIZE = 128, + IPOIB_TX_RING_SIZE = 64, IPOIB_MAX_QUEUE_SIZE = 8192, IPOIB_MIN_QUEUE_SIZE = 2, + IPOIB_CM_MAX_CONN_QP = 4096, - IPOIB_NUM_WC = 4, + IPOIB_NUM_WC = 4, IPOIB_MAX_PATH_REC_QUEUE = 3, - IPOIB_MAX_MCAST_QUEUE = 3, - - IPOIB_FLAG_OPER_UP = 0, - IPOIB_FLAG_INITIALIZED = 1, - IPOIB_FLAG_ADMIN_UP = 2, - IPOIB_PKEY_ASSIGNED = 3, - IPOIB_PKEY_STOP = 4, - IPOIB_FLAG_SUBINTERFACE = 5, - IPOIB_MCAST_RUN = 6, - IPOIB_STOP_REAPER = 7, - IPOIB_MCAST_STARTED = 8, - IPOIB_FLAG_ADMIN_CM = 9, + IPOIB_MAX_MCAST_QUEUE = 3, + + IPOIB_FLAG_OPER_UP = 0, + IPOIB_FLAG_INITIALIZED = 1, + IPOIB_FLAG_ADMIN_UP = 2, + IPOIB_PKEY_ASSIGNED = 3, + IPOIB_PKEY_STOP = 4, + IPOIB_FLAG_SUBINTERFACE = 5, + IPOIB_MCAST_RUN = 6, + IPOIB_STOP_REAPER = 7, + IPOIB_MCAST_STARTED = 8, + IPOIB_FLAG_ADMIN_CM = 9, IPOIB_FLAG_UMCAST = 10, IPOIB_MAX_BACKOFF_SECONDS = 16, - IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ + IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */ IPOIB_MCAST_FLAG_SENDONLY = 1, - IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ + IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, }; @@ -117,7 +118,7 @@ struct ipoib_pseudoheader { struct ipoib_mcast { struct ib_sa_mcmember_rec mcmember; struct ib_sa_multicast *mc; - struct ipoib_ah *ah; + struct ipoib_ah *ah; struct rb_node rb_node; struct list_head list; @@ -186,27 +187,29 @@ enum ipoib_cm_state { }; struct ipoib_cm_rx { - struct ib_cm_id *id; - struct ib_qp *qp; - struct list_head list; - struct net_device *dev; - unsigned long jiffies; - enum ipoib_cm_state state; + struct ib_cm_id *id; + struct ib_qp *qp; + struct ipoib_cm_rx_buf *rx_ring; + struct list_head list; + struct net_device *dev; + unsigned long jiffies; + enum ipoib_cm_state state; + int recv_count; }; struct ipoib_cm_tx { - struct ib_cm_id *id; - struct ib_qp *qp; + struct ib_cm_id *id; + struct ib_qp *qp; struct list_head list; struct net_device *dev; struct ipoib_neigh *neigh; struct ipoib_path *path; struct ipoib_tx_buf *tx_ring; - unsigned tx_head; - unsigned tx_tail; - unsigned long flags; - u32 mtu; - struct ib_wc ibwc[IPOIB_NUM_WC]; + unsigned tx_head; + unsigned tx_tail; + unsigned long flags; + u32 mtu; + struct ib_wc ibwc[IPOIB_NUM_WC]; }; struct ipoib_cm_rx_buf { @@ -215,25 +218,28 @@ struct ipoib_cm_rx_buf { }; struct ipoib_cm_dev_priv { - struct ib_srq *srq; + struct ib_srq *srq; struct ipoib_cm_rx_buf *srq_ring; - struct ib_cm_id *id; - struct list_head passive_ids; /* state: LIVE */ - struct list_head rx_error_list; /* state: ERROR */ - struct list_head rx_flush_list; /* state: FLUSH, drain not started */ - struct list_head rx_drain_list; /* state: FLUSH, drain started */ - struct list_head rx_reap_list; /* state: FLUSH, drain done */ + struct ib_cm_id *id; + struct list_head passive_ids; /* state: LIVE */ + struct list_head rx_error_list; /* state: ERROR */ + struct list_head rx_flush_list; /* state: FLUSH, drain not started */ + struct list_head rx_drain_list; /* state: FLUSH, drain started */ + struct list_head rx_reap_list; /* state: FLUSH, drain done */ struct work_struct start_task; struct work_struct reap_task; struct work_struct skb_task; struct work_struct rx_reap_task; struct delayed_work stale_task; struct sk_buff_head skb_queue; - struct list_head start_list; - struct list_head reap_list; - struct ib_wc ibwc[IPOIB_NUM_WC]; - struct ib_sge rx_sge[IPOIB_CM_RX_SG]; + struct list_head start_list; + struct list_head reap_list; + struct ib_wc ibwc[IPOIB_NUM_WC]; + struct ib_sge rx_sge[IPOIB_CM_RX_SG]; struct ib_recv_wr rx_wr; + int nonsrq_conn_qp; + int max_cm_mtu; + int num_frags; }; /* @@ -269,30 +275,30 @@ struct ipoib_dev_priv { struct work_struct pkey_event_task; struct ib_device *ca; - u8 port; - u16 pkey; - u16 pkey_index; - struct ib_pd *pd; - struct ib_mr *mr; - struct ib_cq *cq; - struct ib_qp *qp; - u32 qkey; + u8 port; + u16 pkey; + u16 pkey_index; + struct ib_pd *pd; + struct ib_mr *mr; + struct ib_cq *cq; + struct ib_qp *qp; + u32 qkey; union ib_gid local_gid; - u16 local_lid; + u16 local_lid; unsigned int admin_mtu; unsigned int mcast_mtu; struct ipoib_rx_buf *rx_ring; - spinlock_t tx_lock; + spinlock_t tx_lock; struct ipoib_tx_buf *tx_ring; - unsigned tx_head; - unsigned tx_tail; - struct ib_sge tx_sge; + unsigned tx_head; + unsigned tx_tail; + struct ib_sge tx_sge; struct ib_send_wr tx_wr; - unsigned tx_outstanding; + unsigned tx_outstanding; struct ib_wc ibwc[IPOIB_NUM_WC]; @@ -317,10 +323,10 @@ struct ipoib_dev_priv { struct ipoib_ah { struct net_device *dev; - struct ib_ah *ah; + struct ib_ah *ah; struct list_head list; - struct kref ref; - unsigned last_send; + struct kref ref; + unsigned last_send; }; struct ipoib_path { @@ -331,11 +337,11 @@ struct ipoib_path { struct list_head neigh_list; - int query_id; + int query_id; struct ib_sa_query *query; struct completion done; - struct rb_node rb_node; + struct rb_node rb_node; struct list_head list; }; @@ -344,7 +350,7 @@ struct ipoib_neigh { #ifdef CONFIG_INFINIBAND_IPOIB_CM struct ipoib_cm_tx *cm; #endif - union ib_gid dgid; + union ib_gid dgid; struct sk_buff_head queue; struct neighbour *neighbour; @@ -455,12 +461,14 @@ void ipoib_drain_cq(struct net_device *dev); #ifdef CONFIG_INFINIBAND_IPOIB_CM -#define IPOIB_FLAGS_RC 0x80 -#define IPOIB_FLAGS_UC 0x40 +#define IPOIB_FLAGS_RC 0x80 +#define IPOIB_FLAGS_UC 0x40 /* We don't support UC connections at the moment */ #define IPOIB_CM_SUPPORTED(ha) (ha[0] & (IPOIB_FLAGS_RC)) +extern int ipoib_max_conn_qp; + static inline int ipoib_cm_admin_enabled(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -491,6 +499,18 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t neigh->cm = tx; } +static inline int ipoib_cm_has_srq(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + return !!priv->cm.srq; +} + +static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + return priv->cm.max_cm_mtu; +} + void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx); int ipoib_cm_dev_open(struct net_device *dev); void ipoib_cm_dev_stop(struct net_device *dev); @@ -500,7 +520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev); struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path *path, struct ipoib_neigh *neigh); void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx); -void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, +void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, unsigned int mtu); void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc); void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc); @@ -508,6 +528,8 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc); struct ipoib_cm_tx; +#define ipoib_max_conn_qp 0 + static inline int ipoib_cm_admin_enabled(struct net_device *dev) { return 0; @@ -533,6 +555,16 @@ static inline void ipoib_cm_set(struct ipoib_neigh *neigh, struct ipoib_cm_tx *t { } +static inline int ipoib_cm_has_srq(struct net_device *dev) +{ + return 0; +} + +static inline unsigned int ipoib_cm_max_mtu(struct net_device *dev) +{ + return 0; +} + static inline void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_tx *tx) { @@ -582,7 +614,7 @@ int ipoib_cm_add_mode_attr(struct net_device *dev) return 0; } -static inline void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, +static inline void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, unsigned int mtu) { dev_kfree_skb_any(skb); @@ -624,12 +656,12 @@ extern struct ib_sa_client ipoib_sa_client; extern int ipoib_debug_level; #define ipoib_dbg(priv, format, arg...) \ - do { \ + do { \ if (ipoib_debug_level > 0) \ ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ } while (0) #define ipoib_dbg_mcast(priv, format, arg...) \ - do { \ + do { \ if (mcast_debug_level > 0) \ ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ } while (0) @@ -642,7 +674,7 @@ extern int ipoib_debug_level; #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA #define ipoib_dbg_data(priv, format, arg...) \ - do { \ + do { \ if (data_debug_level > 0) \ ipoib_printk(KERN_DEBUG, priv, format , ## arg); \ } while (0) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 059cf92b60a5..1818f958c250 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -39,6 +39,15 @@ #include <linux/icmpv6.h> #include <linux/delay.h> +#include "ipoib.h" + +int ipoib_max_conn_qp = 128; + +module_param_named(max_nonsrq_conn_qp, ipoib_max_conn_qp, int, 0444); +MODULE_PARM_DESC(max_nonsrq_conn_qp, + "Max number of connected-mode QPs per interface " + "(applied only if shared receive queue is not available)"); + #ifdef CONFIG_INFINIBAND_IPOIB_DEBUG_DATA static int data_debug_level; @@ -47,8 +56,6 @@ MODULE_PARM_DESC(cm_data_debug_level, "Enable data path debug tracing for connected mode if > 0"); #endif -#include "ipoib.h" - #define IPOIB_CM_IETF_ID 0x1000000000000000ULL #define IPOIB_CM_RX_UPDATE_TIME (256 * HZ) @@ -81,7 +88,7 @@ static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags, ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); } -static int ipoib_cm_post_receive(struct net_device *dev, int id) +static int ipoib_cm_post_receive_srq(struct net_device *dev, int id) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_recv_wr *bad_wr; @@ -89,13 +96,13 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id) priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV; - for (i = 0; i < IPOIB_CM_RX_SG; ++i) + for (i = 0; i < priv->cm.num_frags; ++i) priv->cm.rx_sge[i].addr = priv->cm.srq_ring[id].mapping[i]; ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr); if (unlikely(ret)) { ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret); - ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + ipoib_cm_dma_unmap_rx(priv, priv->cm.num_frags - 1, priv->cm.srq_ring[id].mapping); dev_kfree_skb_any(priv->cm.srq_ring[id].skb); priv->cm.srq_ring[id].skb = NULL; @@ -104,7 +111,33 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id) return ret; } -static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags, +static int ipoib_cm_post_receive_nonsrq(struct net_device *dev, + struct ipoib_cm_rx *rx, int id) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ib_recv_wr *bad_wr; + int i, ret; + + priv->cm.rx_wr.wr_id = id | IPOIB_OP_CM | IPOIB_OP_RECV; + + for (i = 0; i < IPOIB_CM_RX_SG; ++i) + priv->cm.rx_sge[i].addr = rx->rx_ring[id].mapping[i]; + + ret = ib_post_recv(rx->qp, &priv->cm.rx_wr, &bad_wr); + if (unlikely(ret)) { + ipoib_warn(priv, "post recv failed for buf %d (%d)\n", id, ret); + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + rx->rx_ring[id].mapping); + dev_kfree_skb_any(rx->rx_ring[id].skb); + rx->rx_ring[id].skb = NULL; + } + + return ret; +} + +static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, + struct ipoib_cm_rx_buf *rx_ring, + int id, int frags, u64 mapping[IPOIB_CM_RX_SG]) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -141,7 +174,7 @@ static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int goto partial_error; } - priv->cm.srq_ring[id].skb = skb; + rx_ring[id].skb = skb; return skb; partial_error: @@ -155,7 +188,23 @@ partial_error: return NULL; } -static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv* priv) +static void ipoib_cm_free_rx_ring(struct net_device *dev, + struct ipoib_cm_rx_buf *rx_ring) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + int i; + + for (i = 0; i < ipoib_recvq_size; ++i) + if (rx_ring[i].skb) { + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + rx_ring[i].mapping); + dev_kfree_skb_any(rx_ring[i].skb); + } + + kfree(rx_ring); +} + +static void ipoib_cm_start_rx_drain(struct ipoib_dev_priv *priv) { struct ib_send_wr *bad_wr; struct ipoib_cm_rx *p; @@ -208,12 +257,18 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, .qp_type = IB_QPT_RC, .qp_context = p, }; + + if (!ipoib_cm_has_srq(dev)) { + attr.cap.max_recv_wr = ipoib_recvq_size; + attr.cap.max_recv_sge = IPOIB_CM_RX_SG; + } + return ib_create_qp(priv->pd, &attr); } static int ipoib_cm_modify_rx_qp(struct net_device *dev, - struct ib_cm_id *cm_id, struct ib_qp *qp, - unsigned psn) + struct ib_cm_id *cm_id, struct ib_qp *qp, + unsigned psn) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_attr qp_attr; @@ -266,6 +321,60 @@ static int ipoib_cm_modify_rx_qp(struct net_device *dev, return 0; } +static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_id, + struct ipoib_cm_rx *rx) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + int ret; + int i; + + rx->rx_ring = kcalloc(ipoib_recvq_size, sizeof *rx->rx_ring, GFP_KERNEL); + if (!rx->rx_ring) + return -ENOMEM; + + spin_lock_irq(&priv->lock); + + if (priv->cm.nonsrq_conn_qp >= ipoib_max_conn_qp) { + spin_unlock_irq(&priv->lock); + ib_send_cm_rej(cm_id, IB_CM_REJ_NO_QP, NULL, 0, NULL, 0); + ret = -EINVAL; + goto err_free; + } else + ++priv->cm.nonsrq_conn_qp; + + spin_unlock_irq(&priv->lock); + + for (i = 0; i < ipoib_recvq_size; ++i) { + if (!ipoib_cm_alloc_rx_skb(dev, rx->rx_ring, i, IPOIB_CM_RX_SG - 1, + rx->rx_ring[i].mapping)) { + ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); + ret = -ENOMEM; + goto err_count; + } + ret = ipoib_cm_post_receive_nonsrq(dev, rx, i); + if (ret) { + ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq " + "failed for buf %d\n", i); + ret = -EIO; + goto err_count; + } + } + + rx->recv_count = ipoib_recvq_size; + + return 0; + +err_count: + spin_lock_irq(&priv->lock); + --priv->cm.nonsrq_conn_qp; + spin_unlock_irq(&priv->lock); + +err_free: + ipoib_cm_free_rx_ring(dev, rx->rx_ring); + + return ret; +} + static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id, struct ib_qp *qp, struct ib_cm_req_event_param *req, unsigned psn) @@ -281,7 +390,7 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id, rep.private_data_len = sizeof data; rep.flow_control = 0; rep.rnr_retry_count = req->rnr_retry_count; - rep.srq = 1; + rep.srq = ipoib_cm_has_srq(dev); rep.qp_num = qp->qp_num; rep.starting_psn = psn; return ib_send_cm_rep(cm_id, &rep); @@ -317,6 +426,12 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even if (ret) goto err_modify; + if (!ipoib_cm_has_srq(dev)) { + ret = ipoib_cm_nonsrq_init_rx(dev, cm_id, p); + if (ret) + goto err_modify; + } + spin_lock_irq(&priv->lock); queue_delayed_work(ipoib_workqueue, &priv->cm.stale_task, IPOIB_CM_RX_DELAY); @@ -401,12 +516,14 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space, void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) { struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_rx_buf *rx_ring; unsigned int wr_id = wc->wr_id & ~(IPOIB_OP_CM | IPOIB_OP_RECV); struct sk_buff *skb, *newskb; struct ipoib_cm_rx *p; unsigned long flags; u64 mapping[IPOIB_CM_RX_SG]; int frags; + int has_srq; ipoib_dbg_data(priv, "cm recv completion: id %d, status: %d\n", wr_id, wc->status); @@ -424,18 +541,32 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) return; } - skb = priv->cm.srq_ring[wr_id].skb; + p = wc->qp->qp_context; + + has_srq = ipoib_cm_has_srq(dev); + rx_ring = has_srq ? priv->cm.srq_ring : p->rx_ring; + + skb = rx_ring[wr_id].skb; if (unlikely(wc->status != IB_WC_SUCCESS)) { ipoib_dbg(priv, "cm recv error " "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); ++dev->stats.rx_dropped; - goto repost; + if (has_srq) + goto repost; + else { + if (!--p->recv_count) { + spin_lock_irqsave(&priv->lock, flags); + list_move(&p->list, &priv->cm.rx_reap_list); + spin_unlock_irqrestore(&priv->lock, flags); + queue_work(ipoib_workqueue, &priv->cm.rx_reap_task); + } + return; + } } if (unlikely(!(wr_id & IPOIB_CM_RX_UPDATE_MASK))) { - p = wc->qp->qp_context; if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) { spin_lock_irqsave(&priv->lock, flags); p->jiffies = jiffies; @@ -450,7 +581,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len, (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE; - newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping); + newskb = ipoib_cm_alloc_rx_skb(dev, rx_ring, wr_id, frags, mapping); if (unlikely(!newskb)) { /* * If we can't allocate a new RX buffer, dump @@ -461,8 +592,8 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) goto repost; } - ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping); - memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping); + ipoib_cm_dma_unmap_rx(priv, frags, rx_ring[wr_id].mapping); + memcpy(rx_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping); ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", wc->byte_len, wc->slid); @@ -483,9 +614,17 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) netif_receive_skb(skb); repost: - if (unlikely(ipoib_cm_post_receive(dev, wr_id))) - ipoib_warn(priv, "ipoib_cm_post_receive failed " - "for buf %d\n", wr_id); + if (has_srq) { + if (unlikely(ipoib_cm_post_receive_srq(dev, wr_id))) + ipoib_warn(priv, "ipoib_cm_post_receive_srq failed " + "for buf %d\n", wr_id); + } else { + if (unlikely(ipoib_cm_post_receive_nonsrq(dev, p, wr_id))) { + --p->recv_count; + ipoib_warn(priv, "ipoib_cm_post_receive_nonsrq failed " + "for buf %d\n", wr_id); + } + } } static inline int post_send(struct ipoib_dev_priv *priv, @@ -495,10 +634,10 @@ static inline int post_send(struct ipoib_dev_priv *priv, { struct ib_send_wr *bad_wr; - priv->tx_sge.addr = addr; - priv->tx_sge.length = len; + priv->tx_sge.addr = addr; + priv->tx_sge.length = len; - priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM; + priv->tx_wr.wr_id = wr_id | IPOIB_OP_CM; return ib_post_send(tx->qp, &priv->tx_wr, &bad_wr); } @@ -540,7 +679,7 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_ tx_req->mapping = addr; if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1), - addr, skb->len))) { + addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); ++dev->stats.tx_errors; ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE); @@ -657,10 +796,33 @@ err_cm: return ret; } +static void ipoib_cm_free_rx_reap_list(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + struct ipoib_cm_rx *rx, *n; + LIST_HEAD(list); + + spin_lock_irq(&priv->lock); + list_splice_init(&priv->cm.rx_reap_list, &list); + spin_unlock_irq(&priv->lock); + + list_for_each_entry_safe(rx, n, &list, list) { + ib_destroy_cm_id(rx->id); + ib_destroy_qp(rx->qp); + if (!ipoib_cm_has_srq(dev)) { + ipoib_cm_free_rx_ring(priv->dev, rx->rx_ring); + spin_lock_irq(&priv->lock); + --priv->cm.nonsrq_conn_qp; + spin_unlock_irq(&priv->lock); + } + kfree(rx); + } +} + void ipoib_cm_dev_stop(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - struct ipoib_cm_rx *p, *n; + struct ipoib_cm_rx *p; unsigned long begin; LIST_HEAD(list); int ret; @@ -706,15 +868,9 @@ void ipoib_cm_dev_stop(struct net_device *dev) spin_lock_irq(&priv->lock); } - list_splice_init(&priv->cm.rx_reap_list, &list); - spin_unlock_irq(&priv->lock); - list_for_each_entry_safe(p, n, &list, list) { - ib_destroy_cm_id(p->id); - ib_destroy_qp(p->qp); - kfree(p); - } + ipoib_cm_free_rx_reap_list(dev); cancel_delayed_work(&priv->cm.stale_task); } @@ -799,7 +955,7 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ .sq_sig_type = IB_SIGNAL_ALL_WR, .qp_type = IB_QPT_RC, .qp_context = tx - }; + }; return ib_create_qp(priv->pd, &attr); } @@ -816,28 +972,28 @@ static int ipoib_cm_send_req(struct net_device *dev, data.qpn = cpu_to_be32(priv->qp->qp_num); data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE); - req.primary_path = pathrec; - req.alternate_path = NULL; - req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn); - req.qp_num = qp->qp_num; - req.qp_type = qp->qp_type; - req.private_data = &data; - req.private_data_len = sizeof data; - req.flow_control = 0; + req.primary_path = pathrec; + req.alternate_path = NULL; + req.service_id = cpu_to_be64(IPOIB_CM_IETF_ID | qpn); + req.qp_num = qp->qp_num; + req.qp_type = qp->qp_type; + req.private_data = &data; + req.private_data_len = sizeof data; + req.flow_control = 0; - req.starting_psn = 0; /* FIXME */ + req.starting_psn = 0; /* FIXME */ /* * Pick some arbitrary defaults here; we could make these * module parameters if anyone cared about setting them. */ - req.responder_resources = 4; - req.remote_cm_response_timeout = 20; - req.local_cm_response_timeout = 20; - req.retry_count = 0; /* RFC draft warns against retries */ - req.rnr_retry_count = 0; /* RFC draft warns against retries */ - req.max_cm_retries = 15; - req.srq = 1; + req.responder_resources = 4; + req.remote_cm_response_timeout = 20; + req.local_cm_response_timeout = 20; + req.retry_count = 0; /* RFC draft warns against retries */ + req.rnr_retry_count = 0; /* RFC draft warns against retries */ + req.max_cm_retries = 15; + req.srq = ipoib_cm_has_srq(dev); return ib_send_cm_req(id, &req); } @@ -1150,7 +1306,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work) spin_unlock_irq(&priv->tx_lock); } -void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, +void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb, unsigned int mtu) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -1166,20 +1322,8 @@ void ipoib_cm_skb_too_long(struct net_device* dev, struct sk_buff *skb, static void ipoib_cm_rx_reap(struct work_struct *work) { - struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, - cm.rx_reap_task); - struct ipoib_cm_rx *p, *n; - LIST_HEAD(list); - - spin_lock_irq(&priv->lock); - list_splice_init(&priv->cm.rx_reap_list, &list); - spin_unlock_irq(&priv->lock); - - list_for_each_entry_safe(p, n, &list, list) { - ib_destroy_cm_id(p->id); - ib_destroy_qp(p->qp); - kfree(p); - } + ipoib_cm_free_rx_reap_list(container_of(work, struct ipoib_dev_priv, + cm.rx_reap_task)->dev); } static void ipoib_cm_stale_task(struct work_struct *work) @@ -1212,7 +1356,7 @@ static void ipoib_cm_stale_task(struct work_struct *work) } -static ssize_t show_mode(struct device *d, struct device_attribute *attr, +static ssize_t show_mode(struct device *d, struct device_attribute *attr, char *buf) { struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(d)); @@ -1255,16 +1399,40 @@ int ipoib_cm_add_mode_attr(struct net_device *dev) return device_create_file(&dev->dev, &dev_attr_mode); } -int ipoib_cm_dev_init(struct net_device *dev) +static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_srq_init_attr srq_init_attr = { .attr = { .max_wr = ipoib_recvq_size, - .max_sge = IPOIB_CM_RX_SG + .max_sge = max_sge } }; - int ret, i; + + priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr); + if (IS_ERR(priv->cm.srq)) { + if (PTR_ERR(priv->cm.srq) != -ENOSYS) + printk(KERN_WARNING "%s: failed to allocate SRQ, error %ld\n", + priv->ca->name, PTR_ERR(priv->cm.srq)); + priv->cm.srq = NULL; + return; + } + + priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, + GFP_KERNEL); + if (!priv->cm.srq_ring) { + printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", + priv->ca->name, ipoib_recvq_size); + ib_destroy_srq(priv->cm.srq); + priv->cm.srq = NULL; + } +} + +int ipoib_cm_dev_init(struct net_device *dev) +{ + struct ipoib_dev_priv *priv = netdev_priv(dev); + int i, ret; + struct ib_device_attr attr; INIT_LIST_HEAD(&priv->cm.passive_ids); INIT_LIST_HEAD(&priv->cm.reap_list); @@ -1281,43 +1449,53 @@ int ipoib_cm_dev_init(struct net_device *dev) skb_queue_head_init(&priv->cm.skb_queue); - priv->cm.srq = ib_create_srq(priv->pd, &srq_init_attr); - if (IS_ERR(priv->cm.srq)) { - ret = PTR_ERR(priv->cm.srq); - priv->cm.srq = NULL; + ret = ib_query_device(priv->ca, &attr); + if (ret) { + printk(KERN_WARNING "ib_query_device() failed with %d\n", ret); return ret; } - priv->cm.srq_ring = kzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring, - GFP_KERNEL); - if (!priv->cm.srq_ring) { - printk(KERN_WARNING "%s: failed to allocate CM ring (%d entries)\n", - priv->ca->name, ipoib_recvq_size); - ipoib_cm_dev_cleanup(dev); - return -ENOMEM; + ipoib_dbg(priv, "max_srq_sge=%d\n", attr.max_srq_sge); + + attr.max_srq_sge = min_t(int, IPOIB_CM_RX_SG, attr.max_srq_sge); + ipoib_cm_create_srq(dev, attr.max_srq_sge); + if (ipoib_cm_has_srq(dev)) { + priv->cm.max_cm_mtu = attr.max_srq_sge * PAGE_SIZE - 0x10; + priv->cm.num_frags = attr.max_srq_sge; + ipoib_dbg(priv, "max_cm_mtu = 0x%x, num_frags=%d\n", + priv->cm.max_cm_mtu, priv->cm.num_frags); + } else { + priv->cm.max_cm_mtu = IPOIB_CM_MTU; + priv->cm.num_frags = IPOIB_CM_RX_SG; } - for (i = 0; i < IPOIB_CM_RX_SG; ++i) + for (i = 0; i < priv->cm.num_frags; ++i) priv->cm.rx_sge[i].lkey = priv->mr->lkey; priv->cm.rx_sge[0].length = IPOIB_CM_HEAD_SIZE; - for (i = 1; i < IPOIB_CM_RX_SG; ++i) + for (i = 1; i < priv->cm.num_frags; ++i) priv->cm.rx_sge[i].length = PAGE_SIZE; priv->cm.rx_wr.next = NULL; priv->cm.rx_wr.sg_list = priv->cm.rx_sge; - priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG; + priv->cm.rx_wr.num_sge = priv->cm.num_frags; + + if (ipoib_cm_has_srq(dev)) { + for (i = 0; i < ipoib_recvq_size; ++i) { + if (!ipoib_cm_alloc_rx_skb(dev, priv->cm.srq_ring, i, + priv->cm.num_frags - 1, + priv->cm.srq_ring[i].mapping)) { + ipoib_warn(priv, "failed to allocate " + "receive buffer %d\n", i); + ipoib_cm_dev_cleanup(dev); + return -ENOMEM; + } - for (i = 0; i < ipoib_recvq_size; ++i) { - if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1, - priv->cm.srq_ring[i].mapping)) { - ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); - ipoib_cm_dev_cleanup(dev); - return -ENOMEM; - } - if (ipoib_cm_post_receive(dev, i)) { - ipoib_warn(priv, "ipoib_ib_post_receive failed for buf %d\n", i); - ipoib_cm_dev_cleanup(dev); - return -EIO; + if (ipoib_cm_post_receive_srq(dev, i)) { + ipoib_warn(priv, "ipoib_cm_post_receive_srq " + "failed for buf %d\n", i); + ipoib_cm_dev_cleanup(dev); + return -EIO; + } } } @@ -1328,7 +1506,7 @@ int ipoib_cm_dev_init(struct net_device *dev) void ipoib_cm_dev_cleanup(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - int i, ret; + int ret; if (!priv->cm.srq) return; @@ -1342,13 +1520,7 @@ void ipoib_cm_dev_cleanup(struct net_device *dev) priv->cm.srq = NULL; if (!priv->cm.srq_ring) return; - for (i = 0; i < ipoib_recvq_size; ++i) - if (priv->cm.srq_ring[i].skb) { - ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, - priv->cm.srq_ring[i].mapping); - dev_kfree_skb_any(priv->cm.srq_ring[i].skb); - priv->cm.srq_ring[i].skb = NULL; - } - kfree(priv->cm.srq_ring); + + ipoib_cm_free_rx_ring(dev, priv->cm.srq_ring); priv->cm.srq_ring = NULL; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c index 44c174182a82..8b882bbd1d05 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c @@ -124,7 +124,7 @@ static int ipoib_mcg_seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static struct seq_operations ipoib_mcg_seq_ops = { +static const struct seq_operations ipoib_mcg_seq_ops = { .start = ipoib_mcg_seq_start, .next = ipoib_mcg_seq_next, .stop = ipoib_mcg_seq_stop, @@ -230,7 +230,7 @@ static int ipoib_path_seq_show(struct seq_file *file, void *iter_ptr) return 0; } -static struct seq_operations ipoib_path_seq_ops = { +static const struct seq_operations ipoib_path_seq_ops = { .start = ipoib_path_seq_start, .next = ipoib_path_seq_next, .stop = ipoib_path_seq_stop, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 5063dd509ad2..52bc2bd5799a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -345,12 +345,12 @@ static inline int post_send(struct ipoib_dev_priv *priv, { struct ib_send_wr *bad_wr; - priv->tx_sge.addr = addr; - priv->tx_sge.length = len; + priv->tx_sge.addr = addr; + priv->tx_sge.length = len; - priv->tx_wr.wr_id = wr_id; + priv->tx_wr.wr_id = wr_id; priv->tx_wr.wr.ud.remote_qpn = qpn; - priv->tx_wr.wr.ud.ah = address; + priv->tx_wr.wr.ud.ah = address; return ib_post_send(priv->qp, &priv->tx_wr, &bad_wr); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index c9f6077b615e..a082466f4a83 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -182,17 +182,20 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) struct ipoib_dev_priv *priv = netdev_priv(dev); /* dev->mtu > 2K ==> connected mode */ - if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) { + if (ipoib_cm_admin_enabled(dev)) { + if (new_mtu > ipoib_cm_max_mtu(dev)) + return -EINVAL; + if (new_mtu > priv->mcast_mtu) ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", priv->mcast_mtu); + dev->mtu = new_mtu; return 0; } - if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) { + if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) return -EINVAL; - } priv->admin_mtu = new_mtu; @@ -474,8 +477,8 @@ static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid) INIT_LIST_HEAD(&path->neigh_list); memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); - path->pathrec.sgid = priv->local_gid; - path->pathrec.pkey = cpu_to_be16(priv->pkey); + path->pathrec.sgid = priv->local_gid; + path->pathrec.pkey = cpu_to_be16(priv->pkey); path->pathrec.numb_path = 1; path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; @@ -669,16 +672,6 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags))) return NETDEV_TX_LOCKED; - /* - * Check if our queue is stopped. Since we have the LLTX bit - * set, we can't rely on netif_stop_queue() preventing our - * xmit function from being called with a full queue. - */ - if (unlikely(netif_queue_stopped(dev))) { - spin_unlock_irqrestore(&priv->tx_lock, flags); - return NETDEV_TX_BUSY; - } - if (likely(skb->dst && skb->dst->neighbour)) { if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { ipoib_path_lookup(skb, dev); @@ -950,34 +943,34 @@ static void ipoib_setup(struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); - dev->open = ipoib_open; - dev->stop = ipoib_stop; - dev->change_mtu = ipoib_change_mtu; - dev->hard_start_xmit = ipoib_start_xmit; - dev->tx_timeout = ipoib_timeout; - dev->header_ops = &ipoib_header_ops; - dev->set_multicast_list = ipoib_set_mcast_list; - dev->neigh_setup = ipoib_neigh_setup_dev; + dev->open = ipoib_open; + dev->stop = ipoib_stop; + dev->change_mtu = ipoib_change_mtu; + dev->hard_start_xmit = ipoib_start_xmit; + dev->tx_timeout = ipoib_timeout; + dev->header_ops = &ipoib_header_ops; + dev->set_multicast_list = ipoib_set_mcast_list; + dev->neigh_setup = ipoib_neigh_setup_dev; netif_napi_add(dev, &priv->napi, ipoib_poll, 100); - dev->watchdog_timeo = HZ; + dev->watchdog_timeo = HZ; - dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; /* * We add in INFINIBAND_ALEN to allow for the destination * address "pseudoheader" for skbs without neighbour struct. */ - dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; - dev->addr_len = INFINIBAND_ALEN; - dev->type = ARPHRD_INFINIBAND; - dev->tx_queue_len = ipoib_sendq_size * 2; - dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX; + dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; + dev->addr_len = INFINIBAND_ALEN; + dev->type = ARPHRD_INFINIBAND; + dev->tx_queue_len = ipoib_sendq_size * 2; + dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX; /* MTU will be reset when mcast join happens */ - dev->mtu = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN; - priv->mcast_mtu = priv->admin_mtu = dev->mtu; + dev->mtu = IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN; + priv->mcast_mtu = priv->admin_mtu = dev->mtu; memcpy(dev->broadcast, ipv4_bcast_addr, INFINIBAND_ALEN); @@ -1268,6 +1261,9 @@ static int __init ipoib_init_module(void) ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE); +#ifdef CONFIG_INFINIBAND_IPOIB_CM + ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); +#endif ret = ipoib_register_debugfs(); if (ret) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 9bcfc7ad6aa6..2628339e3a99 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -702,7 +702,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) out: if (mcast && mcast->ah) { - if (skb->dst && + if (skb->dst && skb->dst->neighbour && !*to_ipoib_neigh(skb->dst->neighbour)) { struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, @@ -710,7 +710,7 @@ out: if (neigh) { kref_get(&mcast->ah->ref); - neigh->ah = mcast->ah; + neigh->ah = mcast->ah; list_add_tail(&neigh->list, &mcast->neigh_list); } } @@ -788,10 +788,6 @@ void ipoib_mcast_restart_task(struct work_struct *work) memcpy(mgid.raw, mclist->dmi_addr + 4, sizeof mgid); - /* Add in the P_Key */ - mgid.raw[4] = (priv->pkey >> 8) & 0xff; - mgid.raw[5] = priv->pkey & 0xff; - mcast = __ipoib_mcast_find(dev, &mgid); if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { struct ipoib_mcast *nmcast; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 3c6e45db0ab5..433e99ac227b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -172,8 +172,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) size = ipoib_sendq_size + ipoib_recvq_size + 1; ret = ipoib_cm_dev_init(dev); - if (!ret) - size += ipoib_recvq_size + 1 /* 1 extra for rx_drain_qp */; + if (!ret) { + if (ipoib_cm_has_srq(dev)) + size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ + else + size += ipoib_recvq_size * ipoib_max_conn_qp; + } priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); if (IS_ERR(priv->cq)) { @@ -197,12 +201,12 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->dev->dev_addr[2] = (priv->qp->qp_num >> 8) & 0xff; priv->dev->dev_addr[3] = (priv->qp->qp_num ) & 0xff; - priv->tx_sge.lkey = priv->mr->lkey; + priv->tx_sge.lkey = priv->mr->lkey; - priv->tx_wr.opcode = IB_WR_SEND; - priv->tx_wr.sg_list = &priv->tx_sge; - priv->tx_wr.num_sge = 1; - priv->tx_wr.send_flags = IB_SEND_SIGNALED; + priv->tx_wr.opcode = IB_WR_SEND; + priv->tx_wr.sg_list = &priv->tx_sge; + priv->tx_wr.num_sge = 1; + priv->tx_wr.send_flags = IB_SEND_SIGNALED; return 0; diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig index fe604c8d2996..77dedba829e6 100644 --- a/drivers/infiniband/ulp/iser/Kconfig +++ b/drivers/infiniband/ulp/iser/Kconfig @@ -8,5 +8,5 @@ config INFINIBAND_ISER that speak iSCSI over iSER over InfiniBand. The iSER protocol is defined by IETF. - See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt> - and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf> + See <http://www.ietf.org/rfc/rfc5046.txt> + and <http://www.infinibandta.org/members/spec/Annex_iSER.PDF> diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index bad8dacafd10..be1b9fbd416d 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -129,7 +129,7 @@ error: * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * **/ -static void +static int iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) { struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data; @@ -138,6 +138,7 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask) iser_ctask->command_sent = 0; iser_ctask->iser_conn = iser_conn; iser_ctask_rdma_init(iser_ctask); + return 0; } /** @@ -220,12 +221,6 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn, debug_scsi("ctask deq [cid %d itt 0x%x]\n", conn->id, ctask->itt); - /* - * serialize with TMF AbortTask - */ - if (ctask->mtask) - return error; - /* Send the cmd PDU */ if (!iser_ctask->command_sent) { error = iser_send_command(conn, ctask); @@ -406,6 +401,7 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit, ctask = session->cmds[i]; iser_ctask = ctask->dd_data; ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header; + ctask->hdr_max = sizeof(iser_ctask->desc.iscsi_header); } for (i = 0; i < session->mgmtpool_max; i++) { @@ -551,11 +547,13 @@ static struct scsi_host_template iscsi_iser_sht = { .module = THIS_MODULE, .name = "iSCSI Initiator over iSER, v." DRV_VER, .queuecommand = iscsi_queuecommand, + .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, .max_sectors = 1024, .cmd_per_lun = ISCSI_MAX_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, .proc_name = "iscsi_iser", @@ -582,7 +580,9 @@ static struct iscsi_transport iscsi_iser_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | - ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_NETDEV_NAME | ISCSI_HOST_INITIATOR_NAME, diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index a6f2303ed14a..83247f1fdf72 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -561,7 +561,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc, if (opcode == ISCSI_OP_SCSI_CMD_RSP) { itt = get_itt(hdr->itt); /* mask out cid and age bits */ if (!(itt < session->cmds_max)) - iser_err("itt can't be matched to task!!!" + iser_err("itt can't be matched to task!!! " "conn %p opcode %d cmds_max %d itt %d\n", conn->iscsi_conn,opcode,session->cmds_max,itt); /* use the mapping given with the cmds array indexed by itt */ @@ -621,9 +621,7 @@ void iser_snd_completion(struct iser_desc *tx_desc) struct iscsi_session *session = conn->session; spin_lock(&conn->session->lock); - list_del(&mtask->running); - __kfifo_put(session->mgmtpool.queue, (void*)&mtask, - sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); spin_unlock(&session->lock); } } diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 654a4dce0236..714b8db02b29 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -105,7 +105,7 @@ pd_err: } /** - * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR, + * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR, * CQ and PD created with the device associated with the adapator. */ static void iser_free_device_ib_res(struct iser_device *device) @@ -475,13 +475,11 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve iser_disconnected_handler(cma_id); break; case RDMA_CM_EVENT_DEVICE_REMOVAL: + iser_err("Device removal is currently unsupported\n"); BUG(); break; - case RDMA_CM_EVENT_CONNECT_RESPONSE: - BUG(); - break; - case RDMA_CM_EVENT_CONNECT_REQUEST: default: + iser_err("Unexpected RDMA CM event (%d)\n", event->event); break; } return ret; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index bdb6f8517401..195ce7c12319 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -272,7 +272,8 @@ static void srp_path_rec_completion(int status, target->status = status; if (status) - printk(KERN_ERR PFX "Got failed path rec status %d\n", status); + shost_printk(KERN_ERR, target->scsi_host, + PFX "Got failed path rec status %d\n", status); else target->path = *pathrec; complete(&target->done); @@ -303,7 +304,8 @@ static int srp_lookup_path(struct srp_target_port *target) wait_for_completion(&target->done); if (target->status < 0) - printk(KERN_WARNING PFX "Path record query failed\n"); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Path record query failed\n"); return target->status; } @@ -379,9 +381,10 @@ static int srp_send_req(struct srp_target_port *target) * the second 8 bytes to the local node GUID. */ if (srp_target_is_topspin(target)) { - printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround " - "activated for target GUID %016llx\n", - (unsigned long long) be64_to_cpu(target->ioc_guid)); + shost_printk(KERN_DEBUG, target->scsi_host, + PFX "Topspin/Cisco initiator port ID workaround " + "activated for target GUID %016llx\n", + (unsigned long long) be64_to_cpu(target->ioc_guid)); memset(req->priv.initiator_port_id, 0, 8); memcpy(req->priv.initiator_port_id + 8, &target->srp_host->dev->dev->node_guid, 8); @@ -400,7 +403,8 @@ static void srp_disconnect_target(struct srp_target_port *target) init_completion(&target->done); if (ib_send_cm_dreq(target->cm_id, NULL, 0)) { - printk(KERN_DEBUG PFX "Sending CM DREQ failed\n"); + shost_printk(KERN_DEBUG, target->scsi_host, + PFX "Sending CM DREQ failed\n"); return; } wait_for_completion(&target->done); @@ -568,7 +572,8 @@ static int srp_reconnect_target(struct srp_target_port *target) return ret; err: - printk(KERN_ERR PFX "reconnect failed (%d), removing target port.\n", ret); + shost_printk(KERN_ERR, target->scsi_host, + PFX "reconnect failed (%d), removing target port.\n", ret); /* * We couldn't reconnect, so kill our target port off. @@ -683,8 +688,9 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, if (scmnd->sc_data_direction != DMA_FROM_DEVICE && scmnd->sc_data_direction != DMA_TO_DEVICE) { - printk(KERN_WARNING PFX "Unhandled data direction %d\n", - scmnd->sc_data_direction); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Unhandled data direction %d\n", + scmnd->sc_data_direction); return -EINVAL; } @@ -786,8 +792,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) } else { scmnd = req->scmnd; if (!scmnd) - printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n", - (unsigned long long) rsp->tag); + shost_printk(KERN_ERR, target->scsi_host, + "Null scmnd for RSP w/tag %016llx\n", + (unsigned long long) rsp->tag); scmnd->result = rsp->status; if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { @@ -831,7 +838,8 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) if (0) { int i; - printk(KERN_ERR PFX "recv completion, opcode 0x%02x\n", opcode); + shost_printk(KERN_ERR, target->scsi_host, + PFX "recv completion, opcode 0x%02x\n", opcode); for (i = 0; i < wc->byte_len; ++i) { if (i % 8 == 0) @@ -852,11 +860,13 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) case SRP_T_LOGOUT: /* XXX Handle target logout */ - printk(KERN_WARNING PFX "Got target logout request\n"); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Got target logout request\n"); break; default: - printk(KERN_WARNING PFX "Unhandled SRP opcode 0x%02x\n", opcode); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Unhandled SRP opcode 0x%02x\n", opcode); break; } @@ -872,9 +882,10 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr) ib_req_notify_cq(cq, IB_CQ_NEXT_COMP); while (ib_poll_cq(cq, 1, &wc) > 0) { if (wc.status) { - printk(KERN_ERR PFX "failed %s status %d\n", - wc.wr_id & SRP_OP_RECV ? "receive" : "send", - wc.status); + shost_printk(KERN_ERR, target->scsi_host, + PFX "failed %s status %d\n", + wc.wr_id & SRP_OP_RECV ? "receive" : "send", + wc.status); target->qp_in_error = 1; break; } @@ -930,13 +941,18 @@ static int srp_post_recv(struct srp_target_port *target) * req_lim and tx_head. Lock cannot be dropped between call here and * call to __srp_post_send(). */ -static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target) +static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, + enum srp_request_type req_type) { + s32 min = (req_type == SRP_REQ_TASK_MGMT) ? 1 : 2; + if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) return NULL; - if (unlikely(target->req_lim < 1)) + if (target->req_lim < min) { ++target->zero_req_lim; + return NULL; + } return target->tx_ring[target->tx_head & SRP_SQ_SIZE]; } @@ -993,7 +1009,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, return 0; } - iu = __srp_get_tx_iu(target); + iu = __srp_get_tx_iu(target, SRP_REQ_NORMAL); if (!iu) goto err; @@ -1022,12 +1038,13 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, len = srp_map_data(scmnd, target, req); if (len < 0) { - printk(KERN_ERR PFX "Failed to map data\n"); + shost_printk(KERN_ERR, target->scsi_host, + PFX "Failed to map data\n"); goto err; } if (__srp_post_recv(target)) { - printk(KERN_ERR PFX "Recv failed\n"); + shost_printk(KERN_ERR, target->scsi_host, PFX "Recv failed\n"); goto err_unmap; } @@ -1035,7 +1052,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, DMA_TO_DEVICE); if (__srp_post_send(target, iu, len)) { - printk(KERN_ERR PFX "Send failed\n"); + shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n"); goto err_unmap; } @@ -1090,6 +1107,7 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event, struct srp_target_port *target) { + struct Scsi_Host *shost = target->scsi_host; struct ib_class_port_info *cpi; int opcode; @@ -1115,19 +1133,22 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, memcpy(target->path.dgid.raw, event->param.rej_rcvd.ari, 16); - printk(KERN_DEBUG PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", - (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), - (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); + shost_printk(KERN_DEBUG, shost, + PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n", + (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix), + (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id)); target->status = SRP_PORT_REDIRECT; } else { - printk(KERN_WARNING " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); + shost_printk(KERN_WARNING, shost, + " REJ reason: IB_CM_REJ_PORT_REDIRECT\n"); target->status = -ECONNRESET; } break; case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID: - printk(KERN_WARNING " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); + shost_printk(KERN_WARNING, shost, + " REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n"); target->status = -ECONNRESET; break; @@ -1138,20 +1159,21 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id, u32 reason = be32_to_cpu(rej->reason); if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE) - printk(KERN_WARNING PFX - "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); + shost_printk(KERN_WARNING, shost, + PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n"); else - printk(KERN_WARNING PFX - "SRP LOGIN REJECTED, reason 0x%08x\n", reason); + shost_printk(KERN_WARNING, shost, + PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason); } else - printk(KERN_WARNING " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," - " opcode 0x%02x\n", opcode); + shost_printk(KERN_WARNING, shost, + " REJ reason: IB_CM_REJ_CONSUMER_DEFINED," + " opcode 0x%02x\n", opcode); target->status = -ECONNRESET; break; default: - printk(KERN_WARNING " REJ reason 0x%x\n", - event->param.rej_rcvd.reason); + shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n", + event->param.rej_rcvd.reason); target->status = -ECONNRESET; } } @@ -1166,7 +1188,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) switch (event->event) { case IB_CM_REQ_ERROR: - printk(KERN_DEBUG PFX "Sending CM REQ failed\n"); + shost_printk(KERN_DEBUG, target->scsi_host, + PFX "Sending CM REQ failed\n"); comp = 1; target->status = -ECONNRESET; break; @@ -1184,7 +1207,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) target->scsi_host->can_queue = min(target->req_lim, target->scsi_host->can_queue); } else { - printk(KERN_WARNING PFX "Unhandled RSP opcode %#x\n", opcode); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Unhandled RSP opcode %#x\n", opcode); target->status = -ECONNRESET; break; } @@ -1230,20 +1254,23 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) break; case IB_CM_REJ_RECEIVED: - printk(KERN_DEBUG PFX "REJ received\n"); + shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n"); comp = 1; srp_cm_rej_handler(cm_id, event, target); break; case IB_CM_DREQ_RECEIVED: - printk(KERN_WARNING PFX "DREQ received - connection closed\n"); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "DREQ received - connection closed\n"); if (ib_send_cm_drep(cm_id, NULL, 0)) - printk(KERN_ERR PFX "Sending CM DREP failed\n"); + shost_printk(KERN_ERR, target->scsi_host, + PFX "Sending CM DREP failed\n"); break; case IB_CM_TIMEWAIT_EXIT: - printk(KERN_ERR PFX "connection closed\n"); + shost_printk(KERN_ERR, target->scsi_host, + PFX "connection closed\n"); comp = 1; target->status = 0; @@ -1255,7 +1282,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) break; default: - printk(KERN_WARNING PFX "Unhandled CM event %d\n", event->event); + shost_printk(KERN_WARNING, target->scsi_host, + PFX "Unhandled CM event %d\n", event->event); break; } @@ -1283,7 +1311,7 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target, init_completion(&req->done); - iu = __srp_get_tx_iu(target); + iu = __srp_get_tx_iu(target, SRP_REQ_TASK_MGMT); if (!iu) goto out; @@ -1332,7 +1360,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) struct srp_request *req; int ret = SUCCESS; - printk(KERN_ERR "SRP abort called\n"); + shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); if (target->qp_in_error) return FAILED; @@ -1362,7 +1390,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) struct srp_target_port *target = host_to_target(scmnd->device->host); struct srp_request *req, *tmp; - printk(KERN_ERR "SRP reset_device called\n"); + shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n"); if (target->qp_in_error) return FAILED; @@ -1389,7 +1417,7 @@ static int srp_reset_host(struct scsi_cmnd *scmnd) struct srp_target_port *target = host_to_target(scmnd->device->host); int ret = FAILED; - printk(KERN_ERR PFX "SRP reset_host called\n"); + shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n"); if (!srp_reconnect_target(target)) ret = SUCCESS; @@ -1814,8 +1842,9 @@ static ssize_t srp_create_target(struct class_device *class_dev, ib_get_cached_gid(host->dev->dev, host->port, 0, &target->path.sgid); - printk(KERN_DEBUG PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " - "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + shost_printk(KERN_DEBUG, target->scsi_host, PFX + "new target: id_ext %016llx ioc_guid %016llx pkey %04x " + "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", (unsigned long long) be64_to_cpu(target->id_ext), (unsigned long long) be64_to_cpu(target->ioc_guid), be16_to_cpu(target->path.pkey), @@ -1842,7 +1871,8 @@ static ssize_t srp_create_target(struct class_device *class_dev, target->qp_in_error = 0; ret = srp_connect_target(target); if (ret) { - printk(KERN_ERR PFX "Connection failed\n"); + shost_printk(KERN_ERR, target->scsi_host, + PFX "Connection failed\n"); goto err_cm_id; } diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index e3573e7038c4..4a3c1f37e4c2 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -79,6 +79,11 @@ enum srp_target_state { SRP_TARGET_REMOVED }; +enum srp_request_type { + SRP_REQ_NORMAL, + SRP_REQ_TASK_MGMT, +}; + struct srp_device { struct list_head dev_list; struct ib_device *dev; diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index a3637d870880..fed3c375ccf3 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -195,7 +195,7 @@ static struct of_platform_driver ebus_beep_driver = { .name = "beep", .match_table = ebus_beep_match, .probe = ebus_beep_probe, - .remove = sparcspkr_remove, + .remove = __devexit_p(sparcspkr_remove), .shutdown = sparcspkr_shutdown, }; @@ -236,7 +236,7 @@ static struct of_platform_driver isa_beep_driver = { .name = "beep", .match_table = isa_beep_match, .probe = isa_beep_probe, - .remove = sparcspkr_remove, + .remove = __devexit_p(sparcspkr_remove), .shutdown = sparcspkr_shutdown, }; diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index 8991ab0b4fe3..61cff8374e6c 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -39,6 +39,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/irq.h> @@ -62,8 +63,10 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr) int value = inb_p(pc110pad_io); int handshake = inb_p(pc110pad_io + 2); - outb_p(handshake | 1, pc110pad_io + 2); - outb_p(handshake & ~1, pc110pad_io + 2); + outb(handshake | 1, pc110pad_io + 2); + udelay(2); + outb(handshake & ~1, pc110pad_io + 2); + udelay(2); inb_p(0x64); pc110pad_data[pc110pad_count++] = value; diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index b1b2e07bf080..99d92f5c93d6 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -74,10 +74,10 @@ extern unsigned int get_clk_frequency_khz(int info); static unsigned long calc_waittime(struct corgi_ts *corgi_ts) { - unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len(); + unsigned long hsync_invperiod = corgi_ts->machinfo->get_hsync_invperiod(); - if (hsync_len) - return get_clk_frequency_khz(0)*1000/hsync_len; + if (hsync_invperiod) + return get_clk_frequency_khz(0)*1000/hsync_invperiod; else return 0; } @@ -114,7 +114,7 @@ static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, i if (timer2-timer1 > wait_time) { /* too slow - timeout, try again */ corgi_ts->machinfo->wait_hsync(); - /* get OSCR */ + /* get CCNT */ CCNT(timer1); /* Wait after HSync */ CCNT(timer2); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index f449daef3eed..23ae66c76d47 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1544,11 +1544,11 @@ static int __init capi_init(void) return PTR_ERR(capi_class); } - class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi"); + device_create(capi_class, NULL, MKDEV(capi_major, 0), "capi"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE if (capinc_tty_init() < 0) { - class_device_destroy(capi_class, MKDEV(capi_major, 0)); + device_destroy(capi_class, MKDEV(capi_major, 0)); class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); return -ENOMEM; @@ -1576,7 +1576,7 @@ static void __exit capi_exit(void) { proc_exit(); - class_device_destroy(capi_class, MKDEV(capi_major, 0)); + device_destroy(capi_class, MKDEV(capi_major, 0)); class_destroy(capi_class); unregister_chrdev(capi_major, "capi20"); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 48c1775ef5b3..cb42b690b45e 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -2332,13 +2332,14 @@ static int __init capidrv_init(void) static void __exit capidrv_exit(void) { - char rev[10]; + char rev[32]; char *p; if ((p = strchr(revision, ':')) != 0) { - strcpy(rev, p + 1); - p = strchr(rev, '$'); - *p = 0; + strncpy(rev, p + 1, sizeof(rev)); + rev[sizeof(rev)-1] = 0; + if ((p = strchr(rev, '$')) != 0) + *p = 0; } else { strcpy(rev, " ??? "); } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index a0317abaeb11..02bdaf22d7ea 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -106,12 +106,6 @@ enum debuglevel { activated */ }; -/* missing from linux/device.h ... */ -#ifndef dev_notice -#define dev_notice(dev, format, arg...) \ - dev_printk(KERN_NOTICE , dev , format , ## arg) -#endif - /* Kernel message macros for situations where dev_printk and friends cannot be * used for lack of reliable access to a device structure. * linux/usb.h already contains these but in an obsolete form which clutters diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig deleted file mode 100644 index 656920636cb2..000000000000 --- a/drivers/kvm/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -# -# KVM configuration -# -menuconfig VIRTUALIZATION - bool "Virtualization" - depends on X86 - default y - ---help--- - Say Y here to get to see options for using your Linux host to run other - operating systems inside virtual machines (guests). - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if VIRTUALIZATION - -config KVM - tristate "Kernel-based Virtual Machine (KVM) support" - depends on X86 && EXPERIMENTAL - select PREEMPT_NOTIFIERS - select ANON_INODES - ---help--- - Support hosting fully virtualized guest machines using hardware - virtualization extensions. You will need a fairly recent - processor equipped with virtualization extensions. You will also - need to select one or more of the processor modules below. - - This module provides access to the hardware capabilities through - a character device node named /dev/kvm. - - To compile this as a module, choose M here: the module - will be called kvm. - - If unsure, say N. - -config KVM_INTEL - tristate "KVM for Intel processors support" - depends on KVM - ---help--- - Provides support for KVM on Intel processors equipped with the VT - extensions. - -config KVM_AMD - tristate "KVM for AMD processors support" - depends on KVM - ---help--- - Provides support for KVM on AMD processors equipped with the AMD-V - (SVM) extensions. - -# OK, it's a little counter-intuitive to do this, but it puts it neatly under -# the virtualization menu. -source drivers/lguest/Kconfig - -endif # VIRTUALIZATION diff --git a/drivers/kvm/Makefile b/drivers/kvm/Makefile deleted file mode 100644 index e5a8f4d3e973..000000000000 --- a/drivers/kvm/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for Kernel-based Virtual Machine module -# - -kvm-objs := kvm_main.o mmu.o x86_emulate.o i8259.o irq.o lapic.o ioapic.o -obj-$(CONFIG_KVM) += kvm.o -kvm-intel-objs = vmx.o -obj-$(CONFIG_KVM_INTEL) += kvm-intel.o -kvm-amd-objs = svm.o -obj-$(CONFIG_KVM_AMD) += kvm-amd.o diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c deleted file mode 100644 index a679157bc599..000000000000 --- a/drivers/kvm/i8259.c +++ /dev/null @@ -1,450 +0,0 @@ -/* - * 8259 interrupt controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * Copyright (c) 2007 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * Authors: - * Yaozu (Eddie) Dong <Eddie.dong@intel.com> - * Port from Qemu. - */ -#include <linux/mm.h> -#include "irq.h" - -/* - * set irq level. If an edge is detected, then the IRR is set to 1 - */ -static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) -{ - int mask; - mask = 1 << irq; - if (s->elcr & mask) /* level triggered */ - if (level) { - s->irr |= mask; - s->last_irr |= mask; - } else { - s->irr &= ~mask; - s->last_irr &= ~mask; - } - else /* edge triggered */ - if (level) { - if ((s->last_irr & mask) == 0) - s->irr |= mask; - s->last_irr |= mask; - } else - s->last_irr &= ~mask; -} - -/* - * return the highest priority found in mask (highest = smallest - * number). Return 8 if no irq - */ -static inline int get_priority(struct kvm_kpic_state *s, int mask) -{ - int priority; - if (mask == 0) - return 8; - priority = 0; - while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) - priority++; - return priority; -} - -/* - * return the pic wanted interrupt. return -1 if none - */ -static int pic_get_irq(struct kvm_kpic_state *s) -{ - int mask, cur_priority, priority; - - mask = s->irr & ~s->imr; - priority = get_priority(s, mask); - if (priority == 8) - return -1; - /* - * compute current priority. If special fully nested mode on the - * master, the IRQ coming from the slave is not taken into account - * for the priority computation. - */ - mask = s->isr; - if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) - mask &= ~(1 << 2); - cur_priority = get_priority(s, mask); - if (priority < cur_priority) - /* - * higher priority found: an irq should be generated - */ - return (priority + s->priority_add) & 7; - else - return -1; -} - -/* - * raise irq to CPU if necessary. must be called every time the active - * irq may change - */ -static void pic_update_irq(struct kvm_pic *s) -{ - int irq2, irq; - - irq2 = pic_get_irq(&s->pics[1]); - if (irq2 >= 0) { - /* - * if irq request by slave pic, signal master PIC - */ - pic_set_irq1(&s->pics[0], 2, 1); - pic_set_irq1(&s->pics[0], 2, 0); - } - irq = pic_get_irq(&s->pics[0]); - if (irq >= 0) - s->irq_request(s->irq_request_opaque, 1); - else - s->irq_request(s->irq_request_opaque, 0); -} - -void kvm_pic_update_irq(struct kvm_pic *s) -{ - pic_update_irq(s); -} - -void kvm_pic_set_irq(void *opaque, int irq, int level) -{ - struct kvm_pic *s = opaque; - - pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); - pic_update_irq(s); -} - -/* - * acknowledge interrupt 'irq' - */ -static inline void pic_intack(struct kvm_kpic_state *s, int irq) -{ - if (s->auto_eoi) { - if (s->rotate_on_auto_eoi) - s->priority_add = (irq + 1) & 7; - } else - s->isr |= (1 << irq); - /* - * We don't clear a level sensitive interrupt here - */ - if (!(s->elcr & (1 << irq))) - s->irr &= ~(1 << irq); -} - -int kvm_pic_read_irq(struct kvm_pic *s) -{ - int irq, irq2, intno; - - irq = pic_get_irq(&s->pics[0]); - if (irq >= 0) { - pic_intack(&s->pics[0], irq); - if (irq == 2) { - irq2 = pic_get_irq(&s->pics[1]); - if (irq2 >= 0) - pic_intack(&s->pics[1], irq2); - else - /* - * spurious IRQ on slave controller - */ - irq2 = 7; - intno = s->pics[1].irq_base + irq2; - irq = irq2 + 8; - } else - intno = s->pics[0].irq_base + irq; - } else { - /* - * spurious IRQ on host controller - */ - irq = 7; - intno = s->pics[0].irq_base + irq; - } - pic_update_irq(s); - - return intno; -} - -static void pic_reset(void *opaque) -{ - struct kvm_kpic_state *s = opaque; - - s->last_irr = 0; - s->irr = 0; - s->imr = 0; - s->isr = 0; - s->priority_add = 0; - s->irq_base = 0; - s->read_reg_select = 0; - s->poll = 0; - s->special_mask = 0; - s->init_state = 0; - s->auto_eoi = 0; - s->rotate_on_auto_eoi = 0; - s->special_fully_nested_mode = 0; - s->init4 = 0; -} - -static void pic_ioport_write(void *opaque, u32 addr, u32 val) -{ - struct kvm_kpic_state *s = opaque; - int priority, cmd, irq; - - addr &= 1; - if (addr == 0) { - if (val & 0x10) { - pic_reset(s); /* init */ - /* - * deassert a pending interrupt - */ - s->pics_state->irq_request(s->pics_state-> - irq_request_opaque, 0); - s->init_state = 1; - s->init4 = val & 1; - if (val & 0x02) - printk(KERN_ERR "single mode not supported"); - if (val & 0x08) - printk(KERN_ERR - "level sensitive irq not supported"); - } else if (val & 0x08) { - if (val & 0x04) - s->poll = 1; - if (val & 0x02) - s->read_reg_select = val & 1; - if (val & 0x40) - s->special_mask = (val >> 5) & 1; - } else { - cmd = val >> 5; - switch (cmd) { - case 0: - case 4: - s->rotate_on_auto_eoi = cmd >> 2; - break; - case 1: /* end of interrupt */ - case 5: - priority = get_priority(s, s->isr); - if (priority != 8) { - irq = (priority + s->priority_add) & 7; - s->isr &= ~(1 << irq); - if (cmd == 5) - s->priority_add = (irq + 1) & 7; - pic_update_irq(s->pics_state); - } - break; - case 3: - irq = val & 7; - s->isr &= ~(1 << irq); - pic_update_irq(s->pics_state); - break; - case 6: - s->priority_add = (val + 1) & 7; - pic_update_irq(s->pics_state); - break; - case 7: - irq = val & 7; - s->isr &= ~(1 << irq); - s->priority_add = (irq + 1) & 7; - pic_update_irq(s->pics_state); - break; - default: - break; /* no operation */ - } - } - } else - switch (s->init_state) { - case 0: /* normal mode */ - s->imr = val; - pic_update_irq(s->pics_state); - break; - case 1: - s->irq_base = val & 0xf8; - s->init_state = 2; - break; - case 2: - if (s->init4) - s->init_state = 3; - else - s->init_state = 0; - break; - case 3: - s->special_fully_nested_mode = (val >> 4) & 1; - s->auto_eoi = (val >> 1) & 1; - s->init_state = 0; - break; - } -} - -static u32 pic_poll_read(struct kvm_kpic_state *s, u32 addr1) -{ - int ret; - - ret = pic_get_irq(s); - if (ret >= 0) { - if (addr1 >> 7) { - s->pics_state->pics[0].isr &= ~(1 << 2); - s->pics_state->pics[0].irr &= ~(1 << 2); - } - s->irr &= ~(1 << ret); - s->isr &= ~(1 << ret); - if (addr1 >> 7 || ret != 2) - pic_update_irq(s->pics_state); - } else { - ret = 0x07; - pic_update_irq(s->pics_state); - } - - return ret; -} - -static u32 pic_ioport_read(void *opaque, u32 addr1) -{ - struct kvm_kpic_state *s = opaque; - unsigned int addr; - int ret; - - addr = addr1; - addr &= 1; - if (s->poll) { - ret = pic_poll_read(s, addr1); - s->poll = 0; - } else - if (addr == 0) - if (s->read_reg_select) - ret = s->isr; - else - ret = s->irr; - else - ret = s->imr; - return ret; -} - -static void elcr_ioport_write(void *opaque, u32 addr, u32 val) -{ - struct kvm_kpic_state *s = opaque; - s->elcr = val & s->elcr_mask; -} - -static u32 elcr_ioport_read(void *opaque, u32 addr1) -{ - struct kvm_kpic_state *s = opaque; - return s->elcr; -} - -static int picdev_in_range(struct kvm_io_device *this, gpa_t addr) -{ - switch (addr) { - case 0x20: - case 0x21: - case 0xa0: - case 0xa1: - case 0x4d0: - case 0x4d1: - return 1; - default: - return 0; - } -} - -static void picdev_write(struct kvm_io_device *this, - gpa_t addr, int len, const void *val) -{ - struct kvm_pic *s = this->private; - unsigned char data = *(unsigned char *)val; - - if (len != 1) { - if (printk_ratelimit()) - printk(KERN_ERR "PIC: non byte write\n"); - return; - } - switch (addr) { - case 0x20: - case 0x21: - case 0xa0: - case 0xa1: - pic_ioport_write(&s->pics[addr >> 7], addr, data); - break; - case 0x4d0: - case 0x4d1: - elcr_ioport_write(&s->pics[addr & 1], addr, data); - break; - } -} - -static void picdev_read(struct kvm_io_device *this, - gpa_t addr, int len, void *val) -{ - struct kvm_pic *s = this->private; - unsigned char data = 0; - - if (len != 1) { - if (printk_ratelimit()) - printk(KERN_ERR "PIC: non byte read\n"); - return; - } - switch (addr) { - case 0x20: - case 0x21: - case 0xa0: - case 0xa1: - data = pic_ioport_read(&s->pics[addr >> 7], addr); - break; - case 0x4d0: - case 0x4d1: - data = elcr_ioport_read(&s->pics[addr & 1], addr); - break; - } - *(unsigned char *)val = data; -} - -/* - * callback when PIC0 irq status changed - */ -static void pic_irq_request(void *opaque, int level) -{ - struct kvm *kvm = opaque; - struct kvm_vcpu *vcpu = kvm->vcpus[0]; - - pic_irqchip(kvm)->output = level; - if (vcpu) - kvm_vcpu_kick(vcpu); -} - -struct kvm_pic *kvm_create_pic(struct kvm *kvm) -{ - struct kvm_pic *s; - s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); - if (!s) - return NULL; - s->pics[0].elcr_mask = 0xf8; - s->pics[1].elcr_mask = 0xde; - s->irq_request = pic_irq_request; - s->irq_request_opaque = kvm; - s->pics[0].pics_state = s; - s->pics[1].pics_state = s; - - /* - * Initialize PIO device - */ - s->dev.read = picdev_read; - s->dev.write = picdev_write; - s->dev.in_range = picdev_in_range; - s->dev.private = s; - kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev); - return s; -} diff --git a/drivers/kvm/ioapic.c b/drivers/kvm/ioapic.c deleted file mode 100644 index c7992e667fdb..000000000000 --- a/drivers/kvm/ioapic.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2001 MandrakeSoft S.A. - * - * MandrakeSoft S.A. - * 43, rue d'Aboukir - * 75002 Paris - France - * http://www.linux-mandrake.com/ - * http://www.mandrakesoft.com/ - * - * This library 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 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Yunhong Jiang <yunhong.jiang@intel.com> - * Yaozu (Eddie) Dong <eddie.dong@intel.com> - * Based on Xen 3.1 code. - */ - -#include "kvm.h" -#include <linux/kvm.h> -#include <linux/mm.h> -#include <linux/highmem.h> -#include <linux/smp.h> -#include <linux/hrtimer.h> -#include <linux/io.h> -#include <asm/processor.h> -#include <asm/msr.h> -#include <asm/page.h> -#include <asm/current.h> -#include <asm/apicdef.h> -#include <asm/io_apic.h> -#include "irq.h" -/* #define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ -#define ioapic_debug(fmt, arg...) -static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq); - -static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, - unsigned long addr, - unsigned long length) -{ - unsigned long result = 0; - - switch (ioapic->ioregsel) { - case IOAPIC_REG_VERSION: - result = ((((IOAPIC_NUM_PINS - 1) & 0xff) << 16) - | (IOAPIC_VERSION_ID & 0xff)); - break; - - case IOAPIC_REG_APIC_ID: - case IOAPIC_REG_ARB_ID: - result = ((ioapic->id & 0xf) << 24); - break; - - default: - { - u32 redir_index = (ioapic->ioregsel - 0x10) >> 1; - u64 redir_content; - - ASSERT(redir_index < IOAPIC_NUM_PINS); - - redir_content = ioapic->redirtbl[redir_index].bits; - result = (ioapic->ioregsel & 0x1) ? - (redir_content >> 32) & 0xffffffff : - redir_content & 0xffffffff; - break; - } - } - - return result; -} - -static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) -{ - union ioapic_redir_entry *pent; - - pent = &ioapic->redirtbl[idx]; - - if (!pent->fields.mask) { - ioapic_deliver(ioapic, idx); - if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) - pent->fields.remote_irr = 1; - } - if (!pent->fields.trig_mode) - ioapic->irr &= ~(1 << idx); -} - -static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) -{ - unsigned index; - - switch (ioapic->ioregsel) { - case IOAPIC_REG_VERSION: - /* Writes are ignored. */ - break; - - case IOAPIC_REG_APIC_ID: - ioapic->id = (val >> 24) & 0xf; - break; - - case IOAPIC_REG_ARB_ID: - break; - - default: - index = (ioapic->ioregsel - 0x10) >> 1; - - ioapic_debug("change redir index %x val %x", index, val); - if (index >= IOAPIC_NUM_PINS) - return; - if (ioapic->ioregsel & 1) { - ioapic->redirtbl[index].bits &= 0xffffffff; - ioapic->redirtbl[index].bits |= (u64) val << 32; - } else { - ioapic->redirtbl[index].bits &= ~0xffffffffULL; - ioapic->redirtbl[index].bits |= (u32) val; - ioapic->redirtbl[index].fields.remote_irr = 0; - } - if (ioapic->irr & (1 << index)) - ioapic_service(ioapic, index); - break; - } -} - -static void ioapic_inj_irq(struct kvm_ioapic *ioapic, - struct kvm_lapic *target, - u8 vector, u8 trig_mode, u8 delivery_mode) -{ - ioapic_debug("irq %d trig %d deliv %d", vector, trig_mode, - delivery_mode); - - ASSERT((delivery_mode == dest_Fixed) || - (delivery_mode == dest_LowestPrio)); - - kvm_apic_set_irq(target, vector, trig_mode); -} - -static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, - u8 dest_mode) -{ - u32 mask = 0; - int i; - struct kvm *kvm = ioapic->kvm; - struct kvm_vcpu *vcpu; - - ioapic_debug("dest %d dest_mode %d", dest, dest_mode); - - if (dest_mode == 0) { /* Physical mode. */ - if (dest == 0xFF) { /* Broadcast. */ - for (i = 0; i < KVM_MAX_VCPUS; ++i) - if (kvm->vcpus[i] && kvm->vcpus[i]->apic) - mask |= 1 << i; - return mask; - } - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = kvm->vcpus[i]; - if (!vcpu) - continue; - if (kvm_apic_match_physical_addr(vcpu->apic, dest)) { - if (vcpu->apic) - mask = 1 << i; - break; - } - } - } else if (dest != 0) /* Logical mode, MDA non-zero. */ - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = kvm->vcpus[i]; - if (!vcpu) - continue; - if (vcpu->apic && - kvm_apic_match_logical_addr(vcpu->apic, dest)) - mask |= 1 << vcpu->vcpu_id; - } - ioapic_debug("mask %x", mask); - return mask; -} - -static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) -{ - u8 dest = ioapic->redirtbl[irq].fields.dest_id; - u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; - u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode; - u8 vector = ioapic->redirtbl[irq].fields.vector; - u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; - u32 deliver_bitmask; - struct kvm_lapic *target; - struct kvm_vcpu *vcpu; - int vcpu_id; - - ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " - "vector=%x trig_mode=%x", - dest, dest_mode, delivery_mode, vector, trig_mode); - - deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode); - if (!deliver_bitmask) { - ioapic_debug("no target on destination"); - return; - } - - switch (delivery_mode) { - case dest_LowestPrio: - target = - kvm_apic_round_robin(ioapic->kvm, vector, deliver_bitmask); - if (target != NULL) - ioapic_inj_irq(ioapic, target, vector, - trig_mode, delivery_mode); - else - ioapic_debug("null round robin: " - "mask=%x vector=%x delivery_mode=%x", - deliver_bitmask, vector, dest_LowestPrio); - break; - case dest_Fixed: - for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { - if (!(deliver_bitmask & (1 << vcpu_id))) - continue; - deliver_bitmask &= ~(1 << vcpu_id); - vcpu = ioapic->kvm->vcpus[vcpu_id]; - if (vcpu) { - target = vcpu->apic; - ioapic_inj_irq(ioapic, target, vector, - trig_mode, delivery_mode); - } - } - break; - - /* TODO: NMI */ - default: - printk(KERN_WARNING "Unsupported delivery mode %d\n", - delivery_mode); - break; - } -} - -void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) -{ - u32 old_irr = ioapic->irr; - u32 mask = 1 << irq; - union ioapic_redir_entry entry; - - if (irq >= 0 && irq < IOAPIC_NUM_PINS) { - entry = ioapic->redirtbl[irq]; - level ^= entry.fields.polarity; - if (!level) - ioapic->irr &= ~mask; - else { - ioapic->irr |= mask; - if ((!entry.fields.trig_mode && old_irr != ioapic->irr) - || !entry.fields.remote_irr) - ioapic_service(ioapic, irq); - } - } -} - -static int get_eoi_gsi(struct kvm_ioapic *ioapic, int vector) -{ - int i; - - for (i = 0; i < IOAPIC_NUM_PINS; i++) - if (ioapic->redirtbl[i].fields.vector == vector) - return i; - return -1; -} - -void kvm_ioapic_update_eoi(struct kvm *kvm, int vector) -{ - struct kvm_ioapic *ioapic = kvm->vioapic; - union ioapic_redir_entry *ent; - int gsi; - - gsi = get_eoi_gsi(ioapic, vector); - if (gsi == -1) { - printk(KERN_WARNING "Can't find redir item for %d EOI\n", - vector); - return; - } - - ent = &ioapic->redirtbl[gsi]; - ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); - - ent->fields.remote_irr = 0; - if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) - ioapic_deliver(ioapic, gsi); -} - -static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr) -{ - struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; - - return ((addr >= ioapic->base_address && - (addr < ioapic->base_address + IOAPIC_MEM_LENGTH))); -} - -static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, - void *val) -{ - struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; - u32 result; - - ioapic_debug("addr %lx", (unsigned long)addr); - ASSERT(!(addr & 0xf)); /* check alignment */ - - addr &= 0xff; - switch (addr) { - case IOAPIC_REG_SELECT: - result = ioapic->ioregsel; - break; - - case IOAPIC_REG_WINDOW: - result = ioapic_read_indirect(ioapic, addr, len); - break; - - default: - result = 0; - break; - } - switch (len) { - case 8: - *(u64 *) val = result; - break; - case 1: - case 2: - case 4: - memcpy(val, (char *)&result, len); - break; - default: - printk(KERN_WARNING "ioapic: wrong length %d\n", len); - } -} - -static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, - const void *val) -{ - struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private; - u32 data; - - ioapic_debug("ioapic_mmio_write addr=%lx len=%d val=%p\n", - addr, len, val); - ASSERT(!(addr & 0xf)); /* check alignment */ - if (len == 4 || len == 8) - data = *(u32 *) val; - else { - printk(KERN_WARNING "ioapic: Unsupported size %d\n", len); - return; - } - - addr &= 0xff; - switch (addr) { - case IOAPIC_REG_SELECT: - ioapic->ioregsel = data; - break; - - case IOAPIC_REG_WINDOW: - ioapic_write_indirect(ioapic, data); - break; - - default: - break; - } -} - -int kvm_ioapic_init(struct kvm *kvm) -{ - struct kvm_ioapic *ioapic; - int i; - - ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL); - if (!ioapic) - return -ENOMEM; - kvm->vioapic = ioapic; - for (i = 0; i < IOAPIC_NUM_PINS; i++) - ioapic->redirtbl[i].fields.mask = 1; - ioapic->base_address = IOAPIC_DEFAULT_BASE_ADDRESS; - ioapic->dev.read = ioapic_mmio_read; - ioapic->dev.write = ioapic_mmio_write; - ioapic->dev.in_range = ioapic_in_range; - ioapic->dev.private = ioapic; - ioapic->kvm = kvm; - kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev); - return 0; -} diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c deleted file mode 100644 index 7628c7ff628f..000000000000 --- a/drivers/kvm/irq.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * irq.c: API for in kernel interrupt controller - * Copyright (c) 2007, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * Authors: - * Yaozu (Eddie) Dong <Eddie.dong@intel.com> - * - */ - -#include <linux/module.h> - -#include "kvm.h" -#include "irq.h" - -/* - * check if there is pending interrupt without - * intack. - */ -int kvm_cpu_has_interrupt(struct kvm_vcpu *v) -{ - struct kvm_pic *s; - - if (kvm_apic_has_interrupt(v) == -1) { /* LAPIC */ - if (kvm_apic_accept_pic_intr(v)) { - s = pic_irqchip(v->kvm); /* PIC */ - return s->output; - } else - return 0; - } - return 1; -} -EXPORT_SYMBOL_GPL(kvm_cpu_has_interrupt); - -/* - * Read pending interrupt vector and intack. - */ -int kvm_cpu_get_interrupt(struct kvm_vcpu *v) -{ - struct kvm_pic *s; - int vector; - - vector = kvm_get_apic_interrupt(v); /* APIC */ - if (vector == -1) { - if (kvm_apic_accept_pic_intr(v)) { - s = pic_irqchip(v->kvm); - s->output = 0; /* PIC */ - vector = kvm_pic_read_irq(s); - } - } - return vector; -} -EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); - -static void vcpu_kick_intr(void *info) -{ -#ifdef DEBUG - struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; - printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); -#endif -} - -void kvm_vcpu_kick(struct kvm_vcpu *vcpu) -{ - int ipi_pcpu = vcpu->cpu; - - if (waitqueue_active(&vcpu->wq)) { - wake_up_interruptible(&vcpu->wq); - ++vcpu->stat.halt_wakeup; - } - if (vcpu->guest_mode) - smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); -} - -void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) -{ - kvm_inject_apic_timer_irqs(vcpu); - /* TODO: PIT, RTC etc. */ -} -EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); - -void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) -{ - kvm_apic_timer_intr_post(vcpu, vec); - /* TODO: PIT, RTC etc. */ -} -EXPORT_SYMBOL_GPL(kvm_timer_intr_post); diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h deleted file mode 100644 index 11fc014e2b30..000000000000 --- a/drivers/kvm/irq.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * irq.h: in kernel interrupt controller related definitions - * Copyright (c) 2007, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * Authors: - * Yaozu (Eddie) Dong <Eddie.dong@intel.com> - * - */ - -#ifndef __IRQ_H -#define __IRQ_H - -#include "kvm.h" - -typedef void irq_request_func(void *opaque, int level); - -struct kvm_kpic_state { - u8 last_irr; /* edge detection */ - u8 irr; /* interrupt request register */ - u8 imr; /* interrupt mask register */ - u8 isr; /* interrupt service register */ - u8 priority_add; /* highest irq priority */ - u8 irq_base; - u8 read_reg_select; - u8 poll; - u8 special_mask; - u8 init_state; - u8 auto_eoi; - u8 rotate_on_auto_eoi; - u8 special_fully_nested_mode; - u8 init4; /* true if 4 byte init */ - u8 elcr; /* PIIX edge/trigger selection */ - u8 elcr_mask; - struct kvm_pic *pics_state; -}; - -struct kvm_pic { - struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ - irq_request_func *irq_request; - void *irq_request_opaque; - int output; /* intr from master PIC */ - struct kvm_io_device dev; -}; - -struct kvm_pic *kvm_create_pic(struct kvm *kvm); -void kvm_pic_set_irq(void *opaque, int irq, int level); -int kvm_pic_read_irq(struct kvm_pic *s); -int kvm_cpu_get_interrupt(struct kvm_vcpu *v); -int kvm_cpu_has_interrupt(struct kvm_vcpu *v); -void kvm_pic_update_irq(struct kvm_pic *s); - -#define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS -#define IOAPIC_VERSION_ID 0x11 /* IOAPIC version */ -#define IOAPIC_EDGE_TRIG 0 -#define IOAPIC_LEVEL_TRIG 1 - -#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 -#define IOAPIC_MEM_LENGTH 0x100 - -/* Direct registers. */ -#define IOAPIC_REG_SELECT 0x00 -#define IOAPIC_REG_WINDOW 0x10 -#define IOAPIC_REG_EOI 0x40 /* IA64 IOSAPIC only */ - -/* Indirect registers. */ -#define IOAPIC_REG_APIC_ID 0x00 /* x86 IOAPIC only */ -#define IOAPIC_REG_VERSION 0x01 -#define IOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */ - -struct kvm_ioapic { - u64 base_address; - u32 ioregsel; - u32 id; - u32 irr; - u32 pad; - union ioapic_redir_entry { - u64 bits; - struct { - u8 vector; - u8 delivery_mode:3; - u8 dest_mode:1; - u8 delivery_status:1; - u8 polarity:1; - u8 remote_irr:1; - u8 trig_mode:1; - u8 mask:1; - u8 reserve:7; - u8 reserved[4]; - u8 dest_id; - } fields; - } redirtbl[IOAPIC_NUM_PINS]; - struct kvm_io_device dev; - struct kvm *kvm; -}; - -struct kvm_lapic { - unsigned long base_address; - struct kvm_io_device dev; - struct { - atomic_t pending; - s64 period; /* unit: ns */ - u32 divide_count; - ktime_t last_update; - struct hrtimer dev; - } timer; - struct kvm_vcpu *vcpu; - struct page *regs_page; - void *regs; -}; - -#ifdef DEBUG -#define ASSERT(x) \ -do { \ - if (!(x)) { \ - printk(KERN_EMERG "assertion failed %s: %d: %s\n", \ - __FILE__, __LINE__, #x); \ - BUG(); \ - } \ -} while (0) -#else -#define ASSERT(x) do { } while (0) -#endif - -void kvm_vcpu_kick(struct kvm_vcpu *vcpu); -int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); -int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu); -int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu); -int kvm_create_lapic(struct kvm_vcpu *vcpu); -void kvm_lapic_reset(struct kvm_vcpu *vcpu); -void kvm_free_apic(struct kvm_lapic *apic); -u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu); -void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); -void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); -struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, - unsigned long bitmap); -u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); -void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); -int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); -void kvm_ioapic_update_eoi(struct kvm *kvm, int vector); -int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); -int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig); -void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); -int kvm_ioapic_init(struct kvm *kvm); -void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); -int kvm_lapic_enabled(struct kvm_vcpu *vcpu); -int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); -void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec); -void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); -void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); -void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); -void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); - -#endif diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h deleted file mode 100644 index 3b0bc4bda5f2..000000000000 --- a/drivers/kvm/kvm.h +++ /dev/null @@ -1,796 +0,0 @@ -#ifndef __KVM_H -#define __KVM_H - -/* - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include <linux/types.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/spinlock.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/preempt.h> -#include <asm/signal.h> - -#include <linux/kvm.h> -#include <linux/kvm_para.h> - -#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1) -#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD)) -#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS|0xFFFFFF0000000000ULL) - -#define KVM_GUEST_CR0_MASK \ - (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE \ - | X86_CR0_NW | X86_CR0_CD) -#define KVM_VM_CR0_ALWAYS_ON \ - (X86_CR0_PG | X86_CR0_PE | X86_CR0_WP | X86_CR0_NE | X86_CR0_TS \ - | X86_CR0_MP) -#define KVM_GUEST_CR4_MASK \ - (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE) -#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE) -#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE) - -#define INVALID_PAGE (~(hpa_t)0) -#define UNMAPPED_GVA (~(gpa_t)0) - -#define KVM_MAX_VCPUS 4 -#define KVM_ALIAS_SLOTS 4 -#define KVM_MEMORY_SLOTS 8 -#define KVM_NUM_MMU_PAGES 1024 -#define KVM_MIN_FREE_MMU_PAGES 5 -#define KVM_REFILL_PAGES 25 -#define KVM_MAX_CPUID_ENTRIES 40 - -#define DE_VECTOR 0 -#define NM_VECTOR 7 -#define DF_VECTOR 8 -#define TS_VECTOR 10 -#define NP_VECTOR 11 -#define SS_VECTOR 12 -#define GP_VECTOR 13 -#define PF_VECTOR 14 - -#define SELECTOR_TI_MASK (1 << 2) -#define SELECTOR_RPL_MASK 0x03 - -#define IOPL_SHIFT 12 - -#define KVM_PIO_PAGE_OFFSET 1 - -/* - * vcpu->requests bit members - */ -#define KVM_TLB_FLUSH 0 - -/* - * Address types: - * - * gva - guest virtual address - * gpa - guest physical address - * gfn - guest frame number - * hva - host virtual address - * hpa - host physical address - * hfn - host frame number - */ - -typedef unsigned long gva_t; -typedef u64 gpa_t; -typedef unsigned long gfn_t; - -typedef unsigned long hva_t; -typedef u64 hpa_t; -typedef unsigned long hfn_t; - -#define NR_PTE_CHAIN_ENTRIES 5 - -struct kvm_pte_chain { - u64 *parent_ptes[NR_PTE_CHAIN_ENTRIES]; - struct hlist_node link; -}; - -/* - * kvm_mmu_page_role, below, is defined as: - * - * bits 0:3 - total guest paging levels (2-4, or zero for real mode) - * bits 4:7 - page table level for this shadow (1-4) - * bits 8:9 - page table quadrant for 2-level guests - * bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode) - * bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde - */ -union kvm_mmu_page_role { - unsigned word; - struct { - unsigned glevels : 4; - unsigned level : 4; - unsigned quadrant : 2; - unsigned pad_for_nice_hex_output : 6; - unsigned metaphysical : 1; - unsigned hugepage_access : 3; - }; -}; - -struct kvm_mmu_page { - struct list_head link; - struct hlist_node hash_link; - - /* - * The following two entries are used to key the shadow page in the - * hash table. - */ - gfn_t gfn; - union kvm_mmu_page_role role; - - u64 *spt; - unsigned long slot_bitmap; /* One bit set per slot which has memory - * in this shadow page. - */ - int multimapped; /* More than one parent_pte? */ - int root_count; /* Currently serving as active root */ - union { - u64 *parent_pte; /* !multimapped */ - struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */ - }; -}; - -struct kvm_vcpu; -extern struct kmem_cache *kvm_vcpu_cache; - -/* - * x86 supports 3 paging modes (4-level 64-bit, 3-level 64-bit, and 2-level - * 32-bit). The kvm_mmu structure abstracts the details of the current mmu - * mode. - */ -struct kvm_mmu { - void (*new_cr3)(struct kvm_vcpu *vcpu); - int (*page_fault)(struct kvm_vcpu *vcpu, gva_t gva, u32 err); - void (*free)(struct kvm_vcpu *vcpu); - gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t gva); - hpa_t root_hpa; - int root_level; - int shadow_root_level; - - u64 *pae_root; -}; - -#define KVM_NR_MEM_OBJS 20 - -struct kvm_mmu_memory_cache { - int nobjs; - void *objects[KVM_NR_MEM_OBJS]; -}; - -/* - * We don't want allocation failures within the mmu code, so we preallocate - * enough memory for a single page fault in a cache. - */ -struct kvm_guest_debug { - int enabled; - unsigned long bp[4]; - int singlestep; -}; - -enum { - VCPU_REGS_RAX = 0, - VCPU_REGS_RCX = 1, - VCPU_REGS_RDX = 2, - VCPU_REGS_RBX = 3, - VCPU_REGS_RSP = 4, - VCPU_REGS_RBP = 5, - VCPU_REGS_RSI = 6, - VCPU_REGS_RDI = 7, -#ifdef CONFIG_X86_64 - VCPU_REGS_R8 = 8, - VCPU_REGS_R9 = 9, - VCPU_REGS_R10 = 10, - VCPU_REGS_R11 = 11, - VCPU_REGS_R12 = 12, - VCPU_REGS_R13 = 13, - VCPU_REGS_R14 = 14, - VCPU_REGS_R15 = 15, -#endif - NR_VCPU_REGS -}; - -enum { - VCPU_SREG_CS, - VCPU_SREG_DS, - VCPU_SREG_ES, - VCPU_SREG_FS, - VCPU_SREG_GS, - VCPU_SREG_SS, - VCPU_SREG_TR, - VCPU_SREG_LDTR, -}; - -struct kvm_pio_request { - unsigned long count; - int cur_count; - struct page *guest_pages[2]; - unsigned guest_page_offset; - int in; - int port; - int size; - int string; - int down; - int rep; -}; - -struct kvm_stat { - u32 pf_fixed; - u32 pf_guest; - u32 tlb_flush; - u32 invlpg; - - u32 exits; - u32 io_exits; - u32 mmio_exits; - u32 signal_exits; - u32 irq_window_exits; - u32 halt_exits; - u32 halt_wakeup; - u32 request_irq_exits; - u32 irq_exits; - u32 light_exits; - u32 efer_reload; -}; - -struct kvm_io_device { - void (*read)(struct kvm_io_device *this, - gpa_t addr, - int len, - void *val); - void (*write)(struct kvm_io_device *this, - gpa_t addr, - int len, - const void *val); - int (*in_range)(struct kvm_io_device *this, gpa_t addr); - void (*destructor)(struct kvm_io_device *this); - - void *private; -}; - -static inline void kvm_iodevice_read(struct kvm_io_device *dev, - gpa_t addr, - int len, - void *val) -{ - dev->read(dev, addr, len, val); -} - -static inline void kvm_iodevice_write(struct kvm_io_device *dev, - gpa_t addr, - int len, - const void *val) -{ - dev->write(dev, addr, len, val); -} - -static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr) -{ - return dev->in_range(dev, addr); -} - -static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) -{ - if (dev->destructor) - dev->destructor(dev); -} - -/* - * It would be nice to use something smarter than a linear search, TBD... - * Thankfully we dont expect many devices to register (famous last words :), - * so until then it will suffice. At least its abstracted so we can change - * in one place. - */ -struct kvm_io_bus { - int dev_count; -#define NR_IOBUS_DEVS 6 - struct kvm_io_device *devs[NR_IOBUS_DEVS]; -}; - -void kvm_io_bus_init(struct kvm_io_bus *bus); -void kvm_io_bus_destroy(struct kvm_io_bus *bus); -struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr); -void kvm_io_bus_register_dev(struct kvm_io_bus *bus, - struct kvm_io_device *dev); - -struct kvm_vcpu { - struct kvm *kvm; - struct preempt_notifier preempt_notifier; - int vcpu_id; - struct mutex mutex; - int cpu; - u64 host_tsc; - struct kvm_run *run; - int interrupt_window_open; - int guest_mode; - unsigned long requests; - unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ - DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); - unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ - unsigned long rip; /* needs vcpu_load_rsp_rip() */ - - unsigned long cr0; - unsigned long cr2; - unsigned long cr3; - gpa_t para_state_gpa; - struct page *para_state_page; - gpa_t hypercall_gpa; - unsigned long cr4; - unsigned long cr8; - u64 pdptrs[4]; /* pae */ - u64 shadow_efer; - u64 apic_base; - struct kvm_lapic *apic; /* kernel irqchip context */ -#define VCPU_MP_STATE_RUNNABLE 0 -#define VCPU_MP_STATE_UNINITIALIZED 1 -#define VCPU_MP_STATE_INIT_RECEIVED 2 -#define VCPU_MP_STATE_SIPI_RECEIVED 3 -#define VCPU_MP_STATE_HALTED 4 - int mp_state; - int sipi_vector; - u64 ia32_misc_enable_msr; - - struct kvm_mmu mmu; - - struct kvm_mmu_memory_cache mmu_pte_chain_cache; - struct kvm_mmu_memory_cache mmu_rmap_desc_cache; - struct kvm_mmu_memory_cache mmu_page_cache; - struct kvm_mmu_memory_cache mmu_page_header_cache; - - gfn_t last_pt_write_gfn; - int last_pt_write_count; - - struct kvm_guest_debug guest_debug; - - struct i387_fxsave_struct host_fx_image; - struct i387_fxsave_struct guest_fx_image; - int fpu_active; - int guest_fpu_loaded; - - int mmio_needed; - int mmio_read_completed; - int mmio_is_write; - int mmio_size; - unsigned char mmio_data[8]; - gpa_t mmio_phys_addr; - gva_t mmio_fault_cr2; - struct kvm_pio_request pio; - void *pio_data; - wait_queue_head_t wq; - - int sigset_active; - sigset_t sigset; - - struct kvm_stat stat; - - struct { - int active; - u8 save_iopl; - struct kvm_save_segment { - u16 selector; - unsigned long base; - u32 limit; - u32 ar; - } tr, es, ds, fs, gs; - } rmode; - int halt_request; /* real mode on Intel only */ - - int cpuid_nent; - struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES]; -}; - -struct kvm_mem_alias { - gfn_t base_gfn; - unsigned long npages; - gfn_t target_gfn; -}; - -struct kvm_memory_slot { - gfn_t base_gfn; - unsigned long npages; - unsigned long flags; - struct page **phys_mem; - unsigned long *dirty_bitmap; -}; - -struct kvm { - struct mutex lock; /* protects everything except vcpus */ - int naliases; - struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS]; - int nmemslots; - struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS]; - /* - * Hash table of struct kvm_mmu_page. - */ - struct list_head active_mmu_pages; - int n_free_mmu_pages; - struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; - struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; - unsigned long rmap_overflow; - struct list_head vm_list; - struct file *filp; - struct kvm_io_bus mmio_bus; - struct kvm_io_bus pio_bus; - struct kvm_pic *vpic; - struct kvm_ioapic *vioapic; - int round_robin_prev_vcpu; -}; - -static inline struct kvm_pic *pic_irqchip(struct kvm *kvm) -{ - return kvm->vpic; -} - -static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm) -{ - return kvm->vioapic; -} - -static inline int irqchip_in_kernel(struct kvm *kvm) -{ - return pic_irqchip(kvm) != 0; -} - -struct descriptor_table { - u16 limit; - unsigned long base; -} __attribute__((packed)); - -struct kvm_x86_ops { - int (*cpu_has_kvm_support)(void); /* __init */ - int (*disabled_by_bios)(void); /* __init */ - void (*hardware_enable)(void *dummy); /* __init */ - void (*hardware_disable)(void *dummy); - void (*check_processor_compatibility)(void *rtn); - int (*hardware_setup)(void); /* __init */ - void (*hardware_unsetup)(void); /* __exit */ - - /* Create, but do not attach this VCPU */ - struct kvm_vcpu *(*vcpu_create)(struct kvm *kvm, unsigned id); - void (*vcpu_free)(struct kvm_vcpu *vcpu); - void (*vcpu_reset)(struct kvm_vcpu *vcpu); - - void (*prepare_guest_switch)(struct kvm_vcpu *vcpu); - void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu); - void (*vcpu_put)(struct kvm_vcpu *vcpu); - void (*vcpu_decache)(struct kvm_vcpu *vcpu); - - int (*set_guest_debug)(struct kvm_vcpu *vcpu, - struct kvm_debug_guest *dbg); - void (*guest_debug_pre)(struct kvm_vcpu *vcpu); - int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); - int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); - u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); - void (*get_segment)(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg); - void (*set_segment)(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg); - void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); - void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu); - void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); - void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); - void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4); - void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer); - void (*get_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); - void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); - void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); - void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); - unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr); - void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value, - int *exception); - void (*cache_regs)(struct kvm_vcpu *vcpu); - void (*decache_regs)(struct kvm_vcpu *vcpu); - unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); - void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); - - void (*tlb_flush)(struct kvm_vcpu *vcpu); - void (*inject_page_fault)(struct kvm_vcpu *vcpu, - unsigned long addr, u32 err_code); - - void (*inject_gp)(struct kvm_vcpu *vcpu, unsigned err_code); - - void (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); - int (*handle_exit)(struct kvm_run *run, struct kvm_vcpu *vcpu); - void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); - void (*patch_hypercall)(struct kvm_vcpu *vcpu, - unsigned char *hypercall_addr); - int (*get_irq)(struct kvm_vcpu *vcpu); - void (*set_irq)(struct kvm_vcpu *vcpu, int vec); - void (*inject_pending_irq)(struct kvm_vcpu *vcpu); - void (*inject_pending_vectors)(struct kvm_vcpu *vcpu, - struct kvm_run *run); -}; - -extern struct kvm_x86_ops *kvm_x86_ops; - -/* The guest did something we don't support. */ -#define pr_unimpl(vcpu, fmt, ...) \ - do { \ - if (printk_ratelimit()) \ - printk(KERN_ERR "kvm: %i: cpu%i " fmt, \ - current->tgid, (vcpu)->vcpu_id , ## __VA_ARGS__); \ - } while(0) - -#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt) -#define vcpu_printf(vcpu, fmt...) kvm_printf(vcpu->kvm, fmt) - -int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id); -void kvm_vcpu_uninit(struct kvm_vcpu *vcpu); - -int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size, - struct module *module); -void kvm_exit_x86(void); - -int kvm_mmu_module_init(void); -void kvm_mmu_module_exit(void); - -void kvm_mmu_destroy(struct kvm_vcpu *vcpu); -int kvm_mmu_create(struct kvm_vcpu *vcpu); -int kvm_mmu_setup(struct kvm_vcpu *vcpu); - -int kvm_mmu_reset_context(struct kvm_vcpu *vcpu); -void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot); -void kvm_mmu_zap_all(struct kvm *kvm); - -hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa); -#define HPA_MSB ((sizeof(hpa_t) * 8) - 1) -#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB) -static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; } -hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva); -struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva); - -extern hpa_t bad_page_address; - -struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); -struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn); -void mark_page_dirty(struct kvm *kvm, gfn_t gfn); - -enum emulation_result { - EMULATE_DONE, /* no further processing */ - EMULATE_DO_MMIO, /* kvm_run filled with mmio request */ - EMULATE_FAIL, /* can't emulate this instruction */ -}; - -int emulate_instruction(struct kvm_vcpu *vcpu, struct kvm_run *run, - unsigned long cr2, u16 error_code); -void kvm_report_emulation_failure(struct kvm_vcpu *cvpu, const char *context); -void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); -void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); -void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, - unsigned long *rflags); - -unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr); -void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value, - unsigned long *rflags); -int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data); -int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); - -struct x86_emulate_ctxt; - -int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned port); -int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned long count, int down, - gva_t address, int rep, unsigned port); -void kvm_emulate_cpuid(struct kvm_vcpu *vcpu); -int kvm_emulate_halt(struct kvm_vcpu *vcpu); -int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address); -int emulate_clts(struct kvm_vcpu *vcpu); -int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, - unsigned long *dest); -int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, - unsigned long value); - -void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); -void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr0); -void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr0); -void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr0); -unsigned long get_cr8(struct kvm_vcpu *vcpu); -void lmsw(struct kvm_vcpu *vcpu, unsigned long msw); -void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l); - -int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata); -int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data); - -void fx_init(struct kvm_vcpu *vcpu); - -void kvm_resched(struct kvm_vcpu *vcpu); -void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); -void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); -void kvm_flush_remote_tlbs(struct kvm *kvm); - -int emulator_read_std(unsigned long addr, - void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu); -int emulator_write_emulated(unsigned long addr, - const void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu); - -unsigned long segment_base(u16 selector); - -void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *new, int bytes); -int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); -void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); -int kvm_mmu_load(struct kvm_vcpu *vcpu); -void kvm_mmu_unload(struct kvm_vcpu *vcpu); - -int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run); - -static inline void kvm_guest_enter(void) -{ - current->flags |= PF_VCPU; -} - -static inline void kvm_guest_exit(void) -{ - current->flags &= ~PF_VCPU; -} - -static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, - u32 error_code) -{ - return vcpu->mmu.page_fault(vcpu, gva, error_code); -} - -static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) -{ - if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES)) - __kvm_mmu_free_some_pages(vcpu); -} - -static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu) -{ - if (likely(vcpu->mmu.root_hpa != INVALID_PAGE)) - return 0; - - return kvm_mmu_load(vcpu); -} - -static inline int is_long_mode(struct kvm_vcpu *vcpu) -{ -#ifdef CONFIG_X86_64 - return vcpu->shadow_efer & EFER_LME; -#else - return 0; -#endif -} - -static inline int is_pae(struct kvm_vcpu *vcpu) -{ - return vcpu->cr4 & X86_CR4_PAE; -} - -static inline int is_pse(struct kvm_vcpu *vcpu) -{ - return vcpu->cr4 & X86_CR4_PSE; -} - -static inline int is_paging(struct kvm_vcpu *vcpu) -{ - return vcpu->cr0 & X86_CR0_PG; -} - -static inline int memslot_id(struct kvm *kvm, struct kvm_memory_slot *slot) -{ - return slot - kvm->memslots; -} - -static inline struct kvm_mmu_page *page_header(hpa_t shadow_page) -{ - struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT); - - return (struct kvm_mmu_page *)page_private(page); -} - -static inline u16 read_fs(void) -{ - u16 seg; - asm ("mov %%fs, %0" : "=g"(seg)); - return seg; -} - -static inline u16 read_gs(void) -{ - u16 seg; - asm ("mov %%gs, %0" : "=g"(seg)); - return seg; -} - -static inline u16 read_ldt(void) -{ - u16 ldt; - asm ("sldt %0" : "=g"(ldt)); - return ldt; -} - -static inline void load_fs(u16 sel) -{ - asm ("mov %0, %%fs" : : "rm"(sel)); -} - -static inline void load_gs(u16 sel) -{ - asm ("mov %0, %%gs" : : "rm"(sel)); -} - -#ifndef load_ldt -static inline void load_ldt(u16 sel) -{ - asm ("lldt %0" : : "rm"(sel)); -} -#endif - -static inline void get_idt(struct descriptor_table *table) -{ - asm ("sidt %0" : "=m"(*table)); -} - -static inline void get_gdt(struct descriptor_table *table) -{ - asm ("sgdt %0" : "=m"(*table)); -} - -static inline unsigned long read_tr_base(void) -{ - u16 tr; - asm ("str %0" : "=g"(tr)); - return segment_base(tr); -} - -#ifdef CONFIG_X86_64 -static inline unsigned long read_msr(unsigned long msr) -{ - u64 value; - - rdmsrl(msr, value); - return value; -} -#endif - -static inline void fx_save(struct i387_fxsave_struct *image) -{ - asm ("fxsave (%0)":: "r" (image)); -} - -static inline void fx_restore(struct i387_fxsave_struct *image) -{ - asm ("fxrstor (%0)":: "r" (image)); -} - -static inline void fpu_init(void) -{ - asm ("finit"); -} - -static inline u32 get_rdx_init_val(void) -{ - return 0x600; /* P6 family */ -} - -#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30" -#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2" -#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3" -#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30" -#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0" -#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0" -#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4" -#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4" -#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30" - -#define MSR_IA32_TIME_STAMP_COUNTER 0x010 - -#define TSS_IOPB_BASE_OFFSET 0x66 -#define TSS_BASE_SIZE 0x68 -#define TSS_IOPB_SIZE (65536 / 8) -#define TSS_REDIRECTION_SIZE (256 / 8) -#define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) - -#endif diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c deleted file mode 100644 index 47c10b8f89b3..000000000000 --- a/drivers/kvm/kvm_main.c +++ /dev/null @@ -1,3628 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. - * - * Copyright (C) 2006 Qumranet, Inc. - * - * Authors: - * Avi Kivity <avi@qumranet.com> - * Yaniv Kamay <yaniv@qumranet.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "kvm.h" -#include "x86_emulate.h" -#include "segment_descriptor.h" -#include "irq.h" - -#include <linux/kvm.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/percpu.h> -#include <linux/gfp.h> -#include <linux/mm.h> -#include <linux/miscdevice.h> -#include <linux/vmalloc.h> -#include <linux/reboot.h> -#include <linux/debugfs.h> -#include <linux/highmem.h> -#include <linux/file.h> -#include <linux/sysdev.h> -#include <linux/cpu.h> -#include <linux/sched.h> -#include <linux/cpumask.h> -#include <linux/smp.h> -#include <linux/anon_inodes.h> -#include <linux/profile.h> - -#include <asm/processor.h> -#include <asm/msr.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <asm/desc.h> - -MODULE_AUTHOR("Qumranet"); -MODULE_LICENSE("GPL"); - -static DEFINE_SPINLOCK(kvm_lock); -static LIST_HEAD(vm_list); - -static cpumask_t cpus_hardware_enabled; - -struct kvm_x86_ops *kvm_x86_ops; -struct kmem_cache *kvm_vcpu_cache; -EXPORT_SYMBOL_GPL(kvm_vcpu_cache); - -static __read_mostly struct preempt_ops kvm_preempt_ops; - -#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x) - -static struct kvm_stats_debugfs_item { - const char *name; - int offset; - struct dentry *dentry; -} debugfs_entries[] = { - { "pf_fixed", STAT_OFFSET(pf_fixed) }, - { "pf_guest", STAT_OFFSET(pf_guest) }, - { "tlb_flush", STAT_OFFSET(tlb_flush) }, - { "invlpg", STAT_OFFSET(invlpg) }, - { "exits", STAT_OFFSET(exits) }, - { "io_exits", STAT_OFFSET(io_exits) }, - { "mmio_exits", STAT_OFFSET(mmio_exits) }, - { "signal_exits", STAT_OFFSET(signal_exits) }, - { "irq_window", STAT_OFFSET(irq_window_exits) }, - { "halt_exits", STAT_OFFSET(halt_exits) }, - { "halt_wakeup", STAT_OFFSET(halt_wakeup) }, - { "request_irq", STAT_OFFSET(request_irq_exits) }, - { "irq_exits", STAT_OFFSET(irq_exits) }, - { "light_exits", STAT_OFFSET(light_exits) }, - { "efer_reload", STAT_OFFSET(efer_reload) }, - { NULL } -}; - -static struct dentry *debugfs_dir; - -#define MAX_IO_MSRS 256 - -#define CR0_RESERVED_BITS \ - (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \ - | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \ - | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG)) -#define CR4_RESERVED_BITS \ - (~(unsigned long)(X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE\ - | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE \ - | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR \ - | X86_CR4_OSXMMEXCPT | X86_CR4_VMXE)) - -#define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) -#define EFER_RESERVED_BITS 0xfffffffffffff2fe - -#ifdef CONFIG_X86_64 -// LDT or TSS descriptor in the GDT. 16 bytes. -struct segment_descriptor_64 { - struct segment_descriptor s; - u32 base_higher; - u32 pad_zero; -}; - -#endif - -static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, - unsigned long arg); - -unsigned long segment_base(u16 selector) -{ - struct descriptor_table gdt; - struct segment_descriptor *d; - unsigned long table_base; - typedef unsigned long ul; - unsigned long v; - - if (selector == 0) - return 0; - - asm ("sgdt %0" : "=m"(gdt)); - table_base = gdt.base; - - if (selector & 4) { /* from ldt */ - u16 ldt_selector; - - asm ("sldt %0" : "=g"(ldt_selector)); - table_base = segment_base(ldt_selector); - } - d = (struct segment_descriptor *)(table_base + (selector & ~7)); - v = d->base_low | ((ul)d->base_mid << 16) | ((ul)d->base_high << 24); -#ifdef CONFIG_X86_64 - if (d->system == 0 - && (d->type == 2 || d->type == 9 || d->type == 11)) - v |= ((ul)((struct segment_descriptor_64 *)d)->base_higher) << 32; -#endif - return v; -} -EXPORT_SYMBOL_GPL(segment_base); - -static inline int valid_vcpu(int n) -{ - return likely(n >= 0 && n < KVM_MAX_VCPUS); -} - -void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) -{ - if (!vcpu->fpu_active || vcpu->guest_fpu_loaded) - return; - - vcpu->guest_fpu_loaded = 1; - fx_save(&vcpu->host_fx_image); - fx_restore(&vcpu->guest_fx_image); -} -EXPORT_SYMBOL_GPL(kvm_load_guest_fpu); - -void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) -{ - if (!vcpu->guest_fpu_loaded) - return; - - vcpu->guest_fpu_loaded = 0; - fx_save(&vcpu->guest_fx_image); - fx_restore(&vcpu->host_fx_image); -} -EXPORT_SYMBOL_GPL(kvm_put_guest_fpu); - -/* - * Switches to specified vcpu, until a matching vcpu_put() - */ -static void vcpu_load(struct kvm_vcpu *vcpu) -{ - int cpu; - - mutex_lock(&vcpu->mutex); - cpu = get_cpu(); - preempt_notifier_register(&vcpu->preempt_notifier); - kvm_x86_ops->vcpu_load(vcpu, cpu); - put_cpu(); -} - -static void vcpu_put(struct kvm_vcpu *vcpu) -{ - preempt_disable(); - kvm_x86_ops->vcpu_put(vcpu); - preempt_notifier_unregister(&vcpu->preempt_notifier); - preempt_enable(); - mutex_unlock(&vcpu->mutex); -} - -static void ack_flush(void *_completed) -{ -} - -void kvm_flush_remote_tlbs(struct kvm *kvm) -{ - int i, cpu; - cpumask_t cpus; - struct kvm_vcpu *vcpu; - - cpus_clear(cpus); - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = kvm->vcpus[i]; - if (!vcpu) - continue; - if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests)) - continue; - cpu = vcpu->cpu; - if (cpu != -1 && cpu != raw_smp_processor_id()) - cpu_set(cpu, cpus); - } - smp_call_function_mask(cpus, ack_flush, NULL, 1); -} - -int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) -{ - struct page *page; - int r; - - mutex_init(&vcpu->mutex); - vcpu->cpu = -1; - vcpu->mmu.root_hpa = INVALID_PAGE; - vcpu->kvm = kvm; - vcpu->vcpu_id = id; - if (!irqchip_in_kernel(kvm) || id == 0) - vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; - else - vcpu->mp_state = VCPU_MP_STATE_UNINITIALIZED; - init_waitqueue_head(&vcpu->wq); - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) { - r = -ENOMEM; - goto fail; - } - vcpu->run = page_address(page); - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) { - r = -ENOMEM; - goto fail_free_run; - } - vcpu->pio_data = page_address(page); - - r = kvm_mmu_create(vcpu); - if (r < 0) - goto fail_free_pio_data; - - return 0; - -fail_free_pio_data: - free_page((unsigned long)vcpu->pio_data); -fail_free_run: - free_page((unsigned long)vcpu->run); -fail: - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(kvm_vcpu_init); - -void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) -{ - kvm_mmu_destroy(vcpu); - if (vcpu->apic) - hrtimer_cancel(&vcpu->apic->timer.dev); - kvm_free_apic(vcpu->apic); - free_page((unsigned long)vcpu->pio_data); - free_page((unsigned long)vcpu->run); -} -EXPORT_SYMBOL_GPL(kvm_vcpu_uninit); - -static struct kvm *kvm_create_vm(void) -{ - struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); - - if (!kvm) - return ERR_PTR(-ENOMEM); - - kvm_io_bus_init(&kvm->pio_bus); - mutex_init(&kvm->lock); - INIT_LIST_HEAD(&kvm->active_mmu_pages); - kvm_io_bus_init(&kvm->mmio_bus); - spin_lock(&kvm_lock); - list_add(&kvm->vm_list, &vm_list); - spin_unlock(&kvm_lock); - return kvm; -} - -/* - * Free any memory in @free but not in @dont. - */ -static void kvm_free_physmem_slot(struct kvm_memory_slot *free, - struct kvm_memory_slot *dont) -{ - int i; - - if (!dont || free->phys_mem != dont->phys_mem) - if (free->phys_mem) { - for (i = 0; i < free->npages; ++i) - if (free->phys_mem[i]) - __free_page(free->phys_mem[i]); - vfree(free->phys_mem); - } - - if (!dont || free->dirty_bitmap != dont->dirty_bitmap) - vfree(free->dirty_bitmap); - - free->phys_mem = NULL; - free->npages = 0; - free->dirty_bitmap = NULL; -} - -static void kvm_free_physmem(struct kvm *kvm) -{ - int i; - - for (i = 0; i < kvm->nmemslots; ++i) - kvm_free_physmem_slot(&kvm->memslots[i], NULL); -} - -static void free_pio_guest_pages(struct kvm_vcpu *vcpu) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(vcpu->pio.guest_pages); ++i) - if (vcpu->pio.guest_pages[i]) { - __free_page(vcpu->pio.guest_pages[i]); - vcpu->pio.guest_pages[i] = NULL; - } -} - -static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu) -{ - vcpu_load(vcpu); - kvm_mmu_unload(vcpu); - vcpu_put(vcpu); -} - -static void kvm_free_vcpus(struct kvm *kvm) -{ - unsigned int i; - - /* - * Unpin any mmu pages first. - */ - for (i = 0; i < KVM_MAX_VCPUS; ++i) - if (kvm->vcpus[i]) - kvm_unload_vcpu_mmu(kvm->vcpus[i]); - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - if (kvm->vcpus[i]) { - kvm_x86_ops->vcpu_free(kvm->vcpus[i]); - kvm->vcpus[i] = NULL; - } - } - -} - -static void kvm_destroy_vm(struct kvm *kvm) -{ - spin_lock(&kvm_lock); - list_del(&kvm->vm_list); - spin_unlock(&kvm_lock); - kvm_io_bus_destroy(&kvm->pio_bus); - kvm_io_bus_destroy(&kvm->mmio_bus); - kfree(kvm->vpic); - kfree(kvm->vioapic); - kvm_free_vcpus(kvm); - kvm_free_physmem(kvm); - kfree(kvm); -} - -static int kvm_vm_release(struct inode *inode, struct file *filp) -{ - struct kvm *kvm = filp->private_data; - - kvm_destroy_vm(kvm); - return 0; -} - -static void inject_gp(struct kvm_vcpu *vcpu) -{ - kvm_x86_ops->inject_gp(vcpu, 0); -} - -/* - * Load the pae pdptrs. Return true is they are all valid. - */ -static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) -{ - gfn_t pdpt_gfn = cr3 >> PAGE_SHIFT; - unsigned offset = ((cr3 & (PAGE_SIZE-1)) >> 5) << 2; - int i; - u64 *pdpt; - int ret; - struct page *page; - u64 pdpte[ARRAY_SIZE(vcpu->pdptrs)]; - - mutex_lock(&vcpu->kvm->lock); - page = gfn_to_page(vcpu->kvm, pdpt_gfn); - if (!page) { - ret = 0; - goto out; - } - - pdpt = kmap_atomic(page, KM_USER0); - memcpy(pdpte, pdpt+offset, sizeof(pdpte)); - kunmap_atomic(pdpt, KM_USER0); - - for (i = 0; i < ARRAY_SIZE(pdpte); ++i) { - if ((pdpte[i] & 1) && (pdpte[i] & 0xfffffff0000001e6ull)) { - ret = 0; - goto out; - } - } - ret = 1; - - memcpy(vcpu->pdptrs, pdpte, sizeof(vcpu->pdptrs)); -out: - mutex_unlock(&vcpu->kvm->lock); - - return ret; -} - -void set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) -{ - if (cr0 & CR0_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr0: 0x%lx #GP, reserved bits 0x%lx\n", - cr0, vcpu->cr0); - inject_gp(vcpu); - return; - } - - if ((cr0 & X86_CR0_NW) && !(cr0 & X86_CR0_CD)) { - printk(KERN_DEBUG "set_cr0: #GP, CD == 0 && NW == 1\n"); - inject_gp(vcpu); - return; - } - - if ((cr0 & X86_CR0_PG) && !(cr0 & X86_CR0_PE)) { - printk(KERN_DEBUG "set_cr0: #GP, set PG flag " - "and a clear PE flag\n"); - inject_gp(vcpu); - return; - } - - if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { -#ifdef CONFIG_X86_64 - if ((vcpu->shadow_efer & EFER_LME)) { - int cs_db, cs_l; - - if (!is_pae(vcpu)) { - printk(KERN_DEBUG "set_cr0: #GP, start paging " - "in long mode while PAE is disabled\n"); - inject_gp(vcpu); - return; - } - kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); - if (cs_l) { - printk(KERN_DEBUG "set_cr0: #GP, start paging " - "in long mode while CS.L == 1\n"); - inject_gp(vcpu); - return; - - } - } else -#endif - if (is_pae(vcpu) && !load_pdptrs(vcpu, vcpu->cr3)) { - printk(KERN_DEBUG "set_cr0: #GP, pdptrs " - "reserved bits\n"); - inject_gp(vcpu); - return; - } - - } - - kvm_x86_ops->set_cr0(vcpu, cr0); - vcpu->cr0 = cr0; - - mutex_lock(&vcpu->kvm->lock); - kvm_mmu_reset_context(vcpu); - mutex_unlock(&vcpu->kvm->lock); - return; -} -EXPORT_SYMBOL_GPL(set_cr0); - -void lmsw(struct kvm_vcpu *vcpu, unsigned long msw) -{ - set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f)); -} -EXPORT_SYMBOL_GPL(lmsw); - -void set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) -{ - if (cr4 & CR4_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); - inject_gp(vcpu); - return; - } - - if (is_long_mode(vcpu)) { - if (!(cr4 & X86_CR4_PAE)) { - printk(KERN_DEBUG "set_cr4: #GP, clearing PAE while " - "in long mode\n"); - inject_gp(vcpu); - return; - } - } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE) - && !load_pdptrs(vcpu, vcpu->cr3)) { - printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); - inject_gp(vcpu); - return; - } - - if (cr4 & X86_CR4_VMXE) { - printk(KERN_DEBUG "set_cr4: #GP, setting VMXE\n"); - inject_gp(vcpu); - return; - } - kvm_x86_ops->set_cr4(vcpu, cr4); - vcpu->cr4 = cr4; - mutex_lock(&vcpu->kvm->lock); - kvm_mmu_reset_context(vcpu); - mutex_unlock(&vcpu->kvm->lock); -} -EXPORT_SYMBOL_GPL(set_cr4); - -void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) -{ - if (is_long_mode(vcpu)) { - if (cr3 & CR3_L_MODE_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); - inject_gp(vcpu); - return; - } - } else { - if (is_pae(vcpu)) { - if (cr3 & CR3_PAE_RESERVED_BITS) { - printk(KERN_DEBUG - "set_cr3: #GP, reserved bits\n"); - inject_gp(vcpu); - return; - } - if (is_paging(vcpu) && !load_pdptrs(vcpu, cr3)) { - printk(KERN_DEBUG "set_cr3: #GP, pdptrs " - "reserved bits\n"); - inject_gp(vcpu); - return; - } - } else { - if (cr3 & CR3_NONPAE_RESERVED_BITS) { - printk(KERN_DEBUG - "set_cr3: #GP, reserved bits\n"); - inject_gp(vcpu); - return; - } - } - } - - mutex_lock(&vcpu->kvm->lock); - /* - * Does the new cr3 value map to physical memory? (Note, we - * catch an invalid cr3 even in real-mode, because it would - * cause trouble later on when we turn on paging anyway.) - * - * A real CPU would silently accept an invalid cr3 and would - * attempt to use it - with largely undefined (and often hard - * to debug) behavior on the guest side. - */ - if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) - inject_gp(vcpu); - else { - vcpu->cr3 = cr3; - vcpu->mmu.new_cr3(vcpu); - } - mutex_unlock(&vcpu->kvm->lock); -} -EXPORT_SYMBOL_GPL(set_cr3); - -void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) -{ - if (cr8 & CR8_RESERVED_BITS) { - printk(KERN_DEBUG "set_cr8: #GP, reserved bits 0x%lx\n", cr8); - inject_gp(vcpu); - return; - } - if (irqchip_in_kernel(vcpu->kvm)) - kvm_lapic_set_tpr(vcpu, cr8); - else - vcpu->cr8 = cr8; -} -EXPORT_SYMBOL_GPL(set_cr8); - -unsigned long get_cr8(struct kvm_vcpu *vcpu) -{ - if (irqchip_in_kernel(vcpu->kvm)) - return kvm_lapic_get_cr8(vcpu); - else - return vcpu->cr8; -} -EXPORT_SYMBOL_GPL(get_cr8); - -u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) -{ - if (irqchip_in_kernel(vcpu->kvm)) - return vcpu->apic_base; - else - return vcpu->apic_base; -} -EXPORT_SYMBOL_GPL(kvm_get_apic_base); - -void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) -{ - /* TODO: reserve bits check */ - if (irqchip_in_kernel(vcpu->kvm)) - kvm_lapic_set_base(vcpu, data); - else - vcpu->apic_base = data; -} -EXPORT_SYMBOL_GPL(kvm_set_apic_base); - -void fx_init(struct kvm_vcpu *vcpu) -{ - unsigned after_mxcsr_mask; - - /* Initialize guest FPU by resetting ours and saving into guest's */ - preempt_disable(); - fx_save(&vcpu->host_fx_image); - fpu_init(); - fx_save(&vcpu->guest_fx_image); - fx_restore(&vcpu->host_fx_image); - preempt_enable(); - - vcpu->cr0 |= X86_CR0_ET; - after_mxcsr_mask = offsetof(struct i387_fxsave_struct, st_space); - vcpu->guest_fx_image.mxcsr = 0x1f80; - memset((void *)&vcpu->guest_fx_image + after_mxcsr_mask, - 0, sizeof(struct i387_fxsave_struct) - after_mxcsr_mask); -} -EXPORT_SYMBOL_GPL(fx_init); - -/* - * Allocate some memory and give it an address in the guest physical address - * space. - * - * Discontiguous memory is allowed, mostly for framebuffers. - */ -static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, - struct kvm_memory_region *mem) -{ - int r; - gfn_t base_gfn; - unsigned long npages; - unsigned long i; - struct kvm_memory_slot *memslot; - struct kvm_memory_slot old, new; - - r = -EINVAL; - /* General sanity checks */ - if (mem->memory_size & (PAGE_SIZE - 1)) - goto out; - if (mem->guest_phys_addr & (PAGE_SIZE - 1)) - goto out; - if (mem->slot >= KVM_MEMORY_SLOTS) - goto out; - if (mem->guest_phys_addr + mem->memory_size < mem->guest_phys_addr) - goto out; - - memslot = &kvm->memslots[mem->slot]; - base_gfn = mem->guest_phys_addr >> PAGE_SHIFT; - npages = mem->memory_size >> PAGE_SHIFT; - - if (!npages) - mem->flags &= ~KVM_MEM_LOG_DIRTY_PAGES; - - mutex_lock(&kvm->lock); - - new = old = *memslot; - - new.base_gfn = base_gfn; - new.npages = npages; - new.flags = mem->flags; - - /* Disallow changing a memory slot's size. */ - r = -EINVAL; - if (npages && old.npages && npages != old.npages) - goto out_unlock; - - /* Check for overlaps */ - r = -EEXIST; - for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { - struct kvm_memory_slot *s = &kvm->memslots[i]; - - if (s == memslot) - continue; - if (!((base_gfn + npages <= s->base_gfn) || - (base_gfn >= s->base_gfn + s->npages))) - goto out_unlock; - } - - /* Deallocate if slot is being removed */ - if (!npages) - new.phys_mem = NULL; - - /* Free page dirty bitmap if unneeded */ - if (!(new.flags & KVM_MEM_LOG_DIRTY_PAGES)) - new.dirty_bitmap = NULL; - - r = -ENOMEM; - - /* Allocate if a slot is being created */ - if (npages && !new.phys_mem) { - new.phys_mem = vmalloc(npages * sizeof(struct page *)); - - if (!new.phys_mem) - goto out_unlock; - - memset(new.phys_mem, 0, npages * sizeof(struct page *)); - for (i = 0; i < npages; ++i) { - new.phys_mem[i] = alloc_page(GFP_HIGHUSER - | __GFP_ZERO); - if (!new.phys_mem[i]) - goto out_unlock; - set_page_private(new.phys_mem[i],0); - } - } - - /* Allocate page dirty bitmap if needed */ - if ((new.flags & KVM_MEM_LOG_DIRTY_PAGES) && !new.dirty_bitmap) { - unsigned dirty_bytes = ALIGN(npages, BITS_PER_LONG) / 8; - - new.dirty_bitmap = vmalloc(dirty_bytes); - if (!new.dirty_bitmap) - goto out_unlock; - memset(new.dirty_bitmap, 0, dirty_bytes); - } - - if (mem->slot >= kvm->nmemslots) - kvm->nmemslots = mem->slot + 1; - - *memslot = new; - - kvm_mmu_slot_remove_write_access(kvm, mem->slot); - kvm_flush_remote_tlbs(kvm); - - mutex_unlock(&kvm->lock); - - kvm_free_physmem_slot(&old, &new); - return 0; - -out_unlock: - mutex_unlock(&kvm->lock); - kvm_free_physmem_slot(&new, &old); -out: - return r; -} - -/* - * Get (and clear) the dirty memory log for a memory slot. - */ -static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, - struct kvm_dirty_log *log) -{ - struct kvm_memory_slot *memslot; - int r, i; - int n; - unsigned long any = 0; - - mutex_lock(&kvm->lock); - - r = -EINVAL; - if (log->slot >= KVM_MEMORY_SLOTS) - goto out; - - memslot = &kvm->memslots[log->slot]; - r = -ENOENT; - if (!memslot->dirty_bitmap) - goto out; - - n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; - - for (i = 0; !any && i < n/sizeof(long); ++i) - any = memslot->dirty_bitmap[i]; - - r = -EFAULT; - if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) - goto out; - - /* If nothing is dirty, don't bother messing with page tables. */ - if (any) { - kvm_mmu_slot_remove_write_access(kvm, log->slot); - kvm_flush_remote_tlbs(kvm); - memset(memslot->dirty_bitmap, 0, n); - } - - r = 0; - -out: - mutex_unlock(&kvm->lock); - return r; -} - -/* - * Set a new alias region. Aliases map a portion of physical memory into - * another portion. This is useful for memory windows, for example the PC - * VGA region. - */ -static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm, - struct kvm_memory_alias *alias) -{ - int r, n; - struct kvm_mem_alias *p; - - r = -EINVAL; - /* General sanity checks */ - if (alias->memory_size & (PAGE_SIZE - 1)) - goto out; - if (alias->guest_phys_addr & (PAGE_SIZE - 1)) - goto out; - if (alias->slot >= KVM_ALIAS_SLOTS) - goto out; - if (alias->guest_phys_addr + alias->memory_size - < alias->guest_phys_addr) - goto out; - if (alias->target_phys_addr + alias->memory_size - < alias->target_phys_addr) - goto out; - - mutex_lock(&kvm->lock); - - p = &kvm->aliases[alias->slot]; - p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT; - p->npages = alias->memory_size >> PAGE_SHIFT; - p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT; - - for (n = KVM_ALIAS_SLOTS; n > 0; --n) - if (kvm->aliases[n - 1].npages) - break; - kvm->naliases = n; - - kvm_mmu_zap_all(kvm); - - mutex_unlock(&kvm->lock); - - return 0; - -out: - return r; -} - -static int kvm_vm_ioctl_get_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) -{ - int r; - - r = 0; - switch (chip->chip_id) { - case KVM_IRQCHIP_PIC_MASTER: - memcpy (&chip->chip.pic, - &pic_irqchip(kvm)->pics[0], - sizeof(struct kvm_pic_state)); - break; - case KVM_IRQCHIP_PIC_SLAVE: - memcpy (&chip->chip.pic, - &pic_irqchip(kvm)->pics[1], - sizeof(struct kvm_pic_state)); - break; - case KVM_IRQCHIP_IOAPIC: - memcpy (&chip->chip.ioapic, - ioapic_irqchip(kvm), - sizeof(struct kvm_ioapic_state)); - break; - default: - r = -EINVAL; - break; - } - return r; -} - -static int kvm_vm_ioctl_set_irqchip(struct kvm *kvm, struct kvm_irqchip *chip) -{ - int r; - - r = 0; - switch (chip->chip_id) { - case KVM_IRQCHIP_PIC_MASTER: - memcpy (&pic_irqchip(kvm)->pics[0], - &chip->chip.pic, - sizeof(struct kvm_pic_state)); - break; - case KVM_IRQCHIP_PIC_SLAVE: - memcpy (&pic_irqchip(kvm)->pics[1], - &chip->chip.pic, - sizeof(struct kvm_pic_state)); - break; - case KVM_IRQCHIP_IOAPIC: - memcpy (ioapic_irqchip(kvm), - &chip->chip.ioapic, - sizeof(struct kvm_ioapic_state)); - break; - default: - r = -EINVAL; - break; - } - kvm_pic_update_irq(pic_irqchip(kvm)); - return r; -} - -static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn) -{ - int i; - struct kvm_mem_alias *alias; - - for (i = 0; i < kvm->naliases; ++i) { - alias = &kvm->aliases[i]; - if (gfn >= alias->base_gfn - && gfn < alias->base_gfn + alias->npages) - return alias->target_gfn + gfn - alias->base_gfn; - } - return gfn; -} - -static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn) -{ - int i; - - for (i = 0; i < kvm->nmemslots; ++i) { - struct kvm_memory_slot *memslot = &kvm->memslots[i]; - - if (gfn >= memslot->base_gfn - && gfn < memslot->base_gfn + memslot->npages) - return memslot; - } - return NULL; -} - -struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) -{ - gfn = unalias_gfn(kvm, gfn); - return __gfn_to_memslot(kvm, gfn); -} - -struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) -{ - struct kvm_memory_slot *slot; - - gfn = unalias_gfn(kvm, gfn); - slot = __gfn_to_memslot(kvm, gfn); - if (!slot) - return NULL; - return slot->phys_mem[gfn - slot->base_gfn]; -} -EXPORT_SYMBOL_GPL(gfn_to_page); - -/* WARNING: Does not work on aliased pages. */ -void mark_page_dirty(struct kvm *kvm, gfn_t gfn) -{ - struct kvm_memory_slot *memslot; - - memslot = __gfn_to_memslot(kvm, gfn); - if (memslot && memslot->dirty_bitmap) { - unsigned long rel_gfn = gfn - memslot->base_gfn; - - /* avoid RMW */ - if (!test_bit(rel_gfn, memslot->dirty_bitmap)) - set_bit(rel_gfn, memslot->dirty_bitmap); - } -} - -int emulator_read_std(unsigned long addr, - void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu) -{ - void *data = val; - - while (bytes) { - gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); - unsigned offset = addr & (PAGE_SIZE-1); - unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset); - unsigned long pfn; - struct page *page; - void *page_virt; - - if (gpa == UNMAPPED_GVA) - return X86EMUL_PROPAGATE_FAULT; - pfn = gpa >> PAGE_SHIFT; - page = gfn_to_page(vcpu->kvm, pfn); - if (!page) - return X86EMUL_UNHANDLEABLE; - page_virt = kmap_atomic(page, KM_USER0); - - memcpy(data, page_virt + offset, tocopy); - - kunmap_atomic(page_virt, KM_USER0); - - bytes -= tocopy; - data += tocopy; - addr += tocopy; - } - - return X86EMUL_CONTINUE; -} -EXPORT_SYMBOL_GPL(emulator_read_std); - -static int emulator_write_std(unsigned long addr, - const void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu) -{ - pr_unimpl(vcpu, "emulator_write_std: addr %lx n %d\n", addr, bytes); - return X86EMUL_UNHANDLEABLE; -} - -/* - * Only apic need an MMIO device hook, so shortcut now.. - */ -static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, - gpa_t addr) -{ - struct kvm_io_device *dev; - - if (vcpu->apic) { - dev = &vcpu->apic->dev; - if (dev->in_range(dev, addr)) - return dev; - } - return NULL; -} - -static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, - gpa_t addr) -{ - struct kvm_io_device *dev; - - dev = vcpu_find_pervcpu_dev(vcpu, addr); - if (dev == NULL) - dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); - return dev; -} - -static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, - gpa_t addr) -{ - return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr); -} - -static int emulator_read_emulated(unsigned long addr, - void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu) -{ - struct kvm_io_device *mmio_dev; - gpa_t gpa; - - if (vcpu->mmio_read_completed) { - memcpy(val, vcpu->mmio_data, bytes); - vcpu->mmio_read_completed = 0; - return X86EMUL_CONTINUE; - } else if (emulator_read_std(addr, val, bytes, vcpu) - == X86EMUL_CONTINUE) - return X86EMUL_CONTINUE; - - gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); - if (gpa == UNMAPPED_GVA) - return X86EMUL_PROPAGATE_FAULT; - - /* - * Is this MMIO handled locally? - */ - mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); - if (mmio_dev) { - kvm_iodevice_read(mmio_dev, gpa, bytes, val); - return X86EMUL_CONTINUE; - } - - vcpu->mmio_needed = 1; - vcpu->mmio_phys_addr = gpa; - vcpu->mmio_size = bytes; - vcpu->mmio_is_write = 0; - - return X86EMUL_UNHANDLEABLE; -} - -static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, - const void *val, int bytes) -{ - struct page *page; - void *virt; - - if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT)) - return 0; - page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); - if (!page) - return 0; - mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); - virt = kmap_atomic(page, KM_USER0); - kvm_mmu_pte_write(vcpu, gpa, val, bytes); - memcpy(virt + offset_in_page(gpa), val, bytes); - kunmap_atomic(virt, KM_USER0); - return 1; -} - -static int emulator_write_emulated_onepage(unsigned long addr, - const void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu) -{ - struct kvm_io_device *mmio_dev; - gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); - - if (gpa == UNMAPPED_GVA) { - kvm_x86_ops->inject_page_fault(vcpu, addr, 2); - return X86EMUL_PROPAGATE_FAULT; - } - - if (emulator_write_phys(vcpu, gpa, val, bytes)) - return X86EMUL_CONTINUE; - - /* - * Is this MMIO handled locally? - */ - mmio_dev = vcpu_find_mmio_dev(vcpu, gpa); - if (mmio_dev) { - kvm_iodevice_write(mmio_dev, gpa, bytes, val); - return X86EMUL_CONTINUE; - } - - vcpu->mmio_needed = 1; - vcpu->mmio_phys_addr = gpa; - vcpu->mmio_size = bytes; - vcpu->mmio_is_write = 1; - memcpy(vcpu->mmio_data, val, bytes); - - return X86EMUL_CONTINUE; -} - -int emulator_write_emulated(unsigned long addr, - const void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu) -{ - /* Crossing a page boundary? */ - if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { - int rc, now; - - now = -addr & ~PAGE_MASK; - rc = emulator_write_emulated_onepage(addr, val, now, vcpu); - if (rc != X86EMUL_CONTINUE) - return rc; - addr += now; - val += now; - bytes -= now; - } - return emulator_write_emulated_onepage(addr, val, bytes, vcpu); -} -EXPORT_SYMBOL_GPL(emulator_write_emulated); - -static int emulator_cmpxchg_emulated(unsigned long addr, - const void *old, - const void *new, - unsigned int bytes, - struct kvm_vcpu *vcpu) -{ - static int reported; - - if (!reported) { - reported = 1; - printk(KERN_WARNING "kvm: emulating exchange as write\n"); - } - return emulator_write_emulated(addr, new, bytes, vcpu); -} - -static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg) -{ - return kvm_x86_ops->get_segment_base(vcpu, seg); -} - -int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address) -{ - return X86EMUL_CONTINUE; -} - -int emulate_clts(struct kvm_vcpu *vcpu) -{ - kvm_x86_ops->set_cr0(vcpu, vcpu->cr0 & ~X86_CR0_TS); - return X86EMUL_CONTINUE; -} - -int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr, unsigned long *dest) -{ - struct kvm_vcpu *vcpu = ctxt->vcpu; - - switch (dr) { - case 0 ... 3: - *dest = kvm_x86_ops->get_dr(vcpu, dr); - return X86EMUL_CONTINUE; - default: - pr_unimpl(vcpu, "%s: unexpected dr %u\n", __FUNCTION__, dr); - return X86EMUL_UNHANDLEABLE; - } -} - -int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) -{ - unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; - int exception; - - kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); - if (exception) { - /* FIXME: better handling */ - return X86EMUL_UNHANDLEABLE; - } - return X86EMUL_CONTINUE; -} - -void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context) -{ - static int reported; - u8 opcodes[4]; - unsigned long rip = vcpu->rip; - unsigned long rip_linear; - - rip_linear = rip + get_segment_base(vcpu, VCPU_SREG_CS); - - if (reported) - return; - - emulator_read_std(rip_linear, (void *)opcodes, 4, vcpu); - - printk(KERN_ERR "emulation failed (%s) rip %lx %02x %02x %02x %02x\n", - context, rip, opcodes[0], opcodes[1], opcodes[2], opcodes[3]); - reported = 1; -} -EXPORT_SYMBOL_GPL(kvm_report_emulation_failure); - -struct x86_emulate_ops emulate_ops = { - .read_std = emulator_read_std, - .write_std = emulator_write_std, - .read_emulated = emulator_read_emulated, - .write_emulated = emulator_write_emulated, - .cmpxchg_emulated = emulator_cmpxchg_emulated, -}; - -int emulate_instruction(struct kvm_vcpu *vcpu, - struct kvm_run *run, - unsigned long cr2, - u16 error_code) -{ - struct x86_emulate_ctxt emulate_ctxt; - int r; - int cs_db, cs_l; - - vcpu->mmio_fault_cr2 = cr2; - kvm_x86_ops->cache_regs(vcpu); - - kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); - - emulate_ctxt.vcpu = vcpu; - emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu); - emulate_ctxt.cr2 = cr2; - emulate_ctxt.mode = (emulate_ctxt.eflags & X86_EFLAGS_VM) - ? X86EMUL_MODE_REAL : cs_l - ? X86EMUL_MODE_PROT64 : cs_db - ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; - - if (emulate_ctxt.mode == X86EMUL_MODE_PROT64) { - emulate_ctxt.cs_base = 0; - emulate_ctxt.ds_base = 0; - emulate_ctxt.es_base = 0; - emulate_ctxt.ss_base = 0; - } else { - emulate_ctxt.cs_base = get_segment_base(vcpu, VCPU_SREG_CS); - emulate_ctxt.ds_base = get_segment_base(vcpu, VCPU_SREG_DS); - emulate_ctxt.es_base = get_segment_base(vcpu, VCPU_SREG_ES); - emulate_ctxt.ss_base = get_segment_base(vcpu, VCPU_SREG_SS); - } - - emulate_ctxt.gs_base = get_segment_base(vcpu, VCPU_SREG_GS); - emulate_ctxt.fs_base = get_segment_base(vcpu, VCPU_SREG_FS); - - vcpu->mmio_is_write = 0; - vcpu->pio.string = 0; - r = x86_emulate_memop(&emulate_ctxt, &emulate_ops); - if (vcpu->pio.string) - return EMULATE_DO_MMIO; - - if ((r || vcpu->mmio_is_write) && run) { - run->exit_reason = KVM_EXIT_MMIO; - run->mmio.phys_addr = vcpu->mmio_phys_addr; - memcpy(run->mmio.data, vcpu->mmio_data, 8); - run->mmio.len = vcpu->mmio_size; - run->mmio.is_write = vcpu->mmio_is_write; - } - - if (r) { - if (kvm_mmu_unprotect_page_virt(vcpu, cr2)) - return EMULATE_DONE; - if (!vcpu->mmio_needed) { - kvm_report_emulation_failure(vcpu, "mmio"); - return EMULATE_FAIL; - } - return EMULATE_DO_MMIO; - } - - kvm_x86_ops->decache_regs(vcpu); - kvm_x86_ops->set_rflags(vcpu, emulate_ctxt.eflags); - - if (vcpu->mmio_is_write) { - vcpu->mmio_needed = 0; - return EMULATE_DO_MMIO; - } - - return EMULATE_DONE; -} -EXPORT_SYMBOL_GPL(emulate_instruction); - -/* - * The vCPU has executed a HLT instruction with in-kernel mode enabled. - */ -static void kvm_vcpu_block(struct kvm_vcpu *vcpu) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&vcpu->wq, &wait); - - /* - * We will block until either an interrupt or a signal wakes us up - */ - while (!kvm_cpu_has_interrupt(vcpu) - && !signal_pending(current) - && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE - && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) { - set_current_state(TASK_INTERRUPTIBLE); - vcpu_put(vcpu); - schedule(); - vcpu_load(vcpu); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&vcpu->wq, &wait); -} - -int kvm_emulate_halt(struct kvm_vcpu *vcpu) -{ - ++vcpu->stat.halt_exits; - if (irqchip_in_kernel(vcpu->kvm)) { - vcpu->mp_state = VCPU_MP_STATE_HALTED; - kvm_vcpu_block(vcpu); - if (vcpu->mp_state != VCPU_MP_STATE_RUNNABLE) - return -EINTR; - return 1; - } else { - vcpu->run->exit_reason = KVM_EXIT_HLT; - return 0; - } -} -EXPORT_SYMBOL_GPL(kvm_emulate_halt); - -int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) -{ - unsigned long nr, a0, a1, a2, a3, a4, a5, ret; - - kvm_x86_ops->cache_regs(vcpu); - ret = -KVM_EINVAL; -#ifdef CONFIG_X86_64 - if (is_long_mode(vcpu)) { - nr = vcpu->regs[VCPU_REGS_RAX]; - a0 = vcpu->regs[VCPU_REGS_RDI]; - a1 = vcpu->regs[VCPU_REGS_RSI]; - a2 = vcpu->regs[VCPU_REGS_RDX]; - a3 = vcpu->regs[VCPU_REGS_RCX]; - a4 = vcpu->regs[VCPU_REGS_R8]; - a5 = vcpu->regs[VCPU_REGS_R9]; - } else -#endif - { - nr = vcpu->regs[VCPU_REGS_RBX] & -1u; - a0 = vcpu->regs[VCPU_REGS_RAX] & -1u; - a1 = vcpu->regs[VCPU_REGS_RCX] & -1u; - a2 = vcpu->regs[VCPU_REGS_RDX] & -1u; - a3 = vcpu->regs[VCPU_REGS_RSI] & -1u; - a4 = vcpu->regs[VCPU_REGS_RDI] & -1u; - a5 = vcpu->regs[VCPU_REGS_RBP] & -1u; - } - switch (nr) { - default: - run->hypercall.nr = nr; - run->hypercall.args[0] = a0; - run->hypercall.args[1] = a1; - run->hypercall.args[2] = a2; - run->hypercall.args[3] = a3; - run->hypercall.args[4] = a4; - run->hypercall.args[5] = a5; - run->hypercall.ret = ret; - run->hypercall.longmode = is_long_mode(vcpu); - kvm_x86_ops->decache_regs(vcpu); - return 0; - } - vcpu->regs[VCPU_REGS_RAX] = ret; - kvm_x86_ops->decache_regs(vcpu); - return 1; -} -EXPORT_SYMBOL_GPL(kvm_hypercall); - -static u64 mk_cr_64(u64 curr_cr, u32 new_val) -{ - return (curr_cr & ~((1ULL << 32) - 1)) | new_val; -} - -void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) -{ - struct descriptor_table dt = { limit, base }; - - kvm_x86_ops->set_gdt(vcpu, &dt); -} - -void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) -{ - struct descriptor_table dt = { limit, base }; - - kvm_x86_ops->set_idt(vcpu, &dt); -} - -void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw, - unsigned long *rflags) -{ - lmsw(vcpu, msw); - *rflags = kvm_x86_ops->get_rflags(vcpu); -} - -unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr) -{ - kvm_x86_ops->decache_cr4_guest_bits(vcpu); - switch (cr) { - case 0: - return vcpu->cr0; - case 2: - return vcpu->cr2; - case 3: - return vcpu->cr3; - case 4: - return vcpu->cr4; - default: - vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); - return 0; - } -} - -void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, - unsigned long *rflags) -{ - switch (cr) { - case 0: - set_cr0(vcpu, mk_cr_64(vcpu->cr0, val)); - *rflags = kvm_x86_ops->get_rflags(vcpu); - break; - case 2: - vcpu->cr2 = val; - break; - case 3: - set_cr3(vcpu, val); - break; - case 4: - set_cr4(vcpu, mk_cr_64(vcpu->cr4, val)); - break; - default: - vcpu_printf(vcpu, "%s: unexpected cr %u\n", __FUNCTION__, cr); - } -} - -/* - * Register the para guest with the host: - */ -static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa) -{ - struct kvm_vcpu_para_state *para_state; - hpa_t para_state_hpa, hypercall_hpa; - struct page *para_state_page; - unsigned char *hypercall; - gpa_t hypercall_gpa; - - printk(KERN_DEBUG "kvm: guest trying to enter paravirtual mode\n"); - printk(KERN_DEBUG ".... para_state_gpa: %08Lx\n", para_state_gpa); - - /* - * Needs to be page aligned: - */ - if (para_state_gpa != PAGE_ALIGN(para_state_gpa)) - goto err_gp; - - para_state_hpa = gpa_to_hpa(vcpu, para_state_gpa); - printk(KERN_DEBUG ".... para_state_hpa: %08Lx\n", para_state_hpa); - if (is_error_hpa(para_state_hpa)) - goto err_gp; - - mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT); - para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT); - para_state = kmap(para_state_page); - - printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version); - printk(KERN_DEBUG ".... size: %d\n", para_state->size); - - para_state->host_version = KVM_PARA_API_VERSION; - /* - * We cannot support guests that try to register themselves - * with a newer API version than the host supports: - */ - if (para_state->guest_version > KVM_PARA_API_VERSION) { - para_state->ret = -KVM_EINVAL; - goto err_kunmap_skip; - } - - hypercall_gpa = para_state->hypercall_gpa; - hypercall_hpa = gpa_to_hpa(vcpu, hypercall_gpa); - printk(KERN_DEBUG ".... hypercall_hpa: %08Lx\n", hypercall_hpa); - if (is_error_hpa(hypercall_hpa)) { - para_state->ret = -KVM_EINVAL; - goto err_kunmap_skip; - } - - printk(KERN_DEBUG "kvm: para guest successfully registered.\n"); - vcpu->para_state_page = para_state_page; - vcpu->para_state_gpa = para_state_gpa; - vcpu->hypercall_gpa = hypercall_gpa; - - mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT); - hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT), - KM_USER1) + (hypercall_hpa & ~PAGE_MASK); - kvm_x86_ops->patch_hypercall(vcpu, hypercall); - kunmap_atomic(hypercall, KM_USER1); - - para_state->ret = 0; -err_kunmap_skip: - kunmap(para_state_page); - return 0; -err_gp: - return 1; -} - -int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) -{ - u64 data; - - switch (msr) { - case 0xc0010010: /* SYSCFG */ - case 0xc0010015: /* HWCR */ - case MSR_IA32_PLATFORM_ID: - case MSR_IA32_P5_MC_ADDR: - case MSR_IA32_P5_MC_TYPE: - case MSR_IA32_MC0_CTL: - case MSR_IA32_MCG_STATUS: - case MSR_IA32_MCG_CAP: - case MSR_IA32_MC0_MISC: - case MSR_IA32_MC0_MISC+4: - case MSR_IA32_MC0_MISC+8: - case MSR_IA32_MC0_MISC+12: - case MSR_IA32_MC0_MISC+16: - case MSR_IA32_UCODE_REV: - case MSR_IA32_PERF_STATUS: - case MSR_IA32_EBL_CR_POWERON: - /* MTRR registers */ - case 0xfe: - case 0x200 ... 0x2ff: - data = 0; - break; - case 0xcd: /* fsb frequency */ - data = 3; - break; - case MSR_IA32_APICBASE: - data = kvm_get_apic_base(vcpu); - break; - case MSR_IA32_MISC_ENABLE: - data = vcpu->ia32_misc_enable_msr; - break; -#ifdef CONFIG_X86_64 - case MSR_EFER: - data = vcpu->shadow_efer; - break; -#endif - default: - pr_unimpl(vcpu, "unhandled rdmsr: 0x%x\n", msr); - return 1; - } - *pdata = data; - return 0; -} -EXPORT_SYMBOL_GPL(kvm_get_msr_common); - -/* - * Reads an msr value (of 'msr_index') into 'pdata'. - * Returns 0 on success, non-0 otherwise. - * Assumes vcpu_load() was already called. - */ -int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) -{ - return kvm_x86_ops->get_msr(vcpu, msr_index, pdata); -} - -#ifdef CONFIG_X86_64 - -static void set_efer(struct kvm_vcpu *vcpu, u64 efer) -{ - if (efer & EFER_RESERVED_BITS) { - printk(KERN_DEBUG "set_efer: 0x%llx #GP, reserved bits\n", - efer); - inject_gp(vcpu); - return; - } - - if (is_paging(vcpu) - && (vcpu->shadow_efer & EFER_LME) != (efer & EFER_LME)) { - printk(KERN_DEBUG "set_efer: #GP, change LME while paging\n"); - inject_gp(vcpu); - return; - } - - kvm_x86_ops->set_efer(vcpu, efer); - - efer &= ~EFER_LMA; - efer |= vcpu->shadow_efer & EFER_LMA; - - vcpu->shadow_efer = efer; -} - -#endif - -int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) -{ - switch (msr) { -#ifdef CONFIG_X86_64 - case MSR_EFER: - set_efer(vcpu, data); - break; -#endif - case MSR_IA32_MC0_STATUS: - pr_unimpl(vcpu, "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n", - __FUNCTION__, data); - break; - case MSR_IA32_MCG_STATUS: - pr_unimpl(vcpu, "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n", - __FUNCTION__, data); - break; - case MSR_IA32_UCODE_REV: - case MSR_IA32_UCODE_WRITE: - case 0x200 ... 0x2ff: /* MTRRs */ - break; - case MSR_IA32_APICBASE: - kvm_set_apic_base(vcpu, data); - break; - case MSR_IA32_MISC_ENABLE: - vcpu->ia32_misc_enable_msr = data; - break; - /* - * This is the 'probe whether the host is KVM' logic: - */ - case MSR_KVM_API_MAGIC: - return vcpu_register_para(vcpu, data); - - default: - pr_unimpl(vcpu, "unhandled wrmsr: 0x%x\n", msr); - return 1; - } - return 0; -} -EXPORT_SYMBOL_GPL(kvm_set_msr_common); - -/* - * Writes msr value into into the appropriate "register". - * Returns 0 on success, non-0 otherwise. - * Assumes vcpu_load() was already called. - */ -int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) -{ - return kvm_x86_ops->set_msr(vcpu, msr_index, data); -} - -void kvm_resched(struct kvm_vcpu *vcpu) -{ - if (!need_resched()) - return; - cond_resched(); -} -EXPORT_SYMBOL_GPL(kvm_resched); - -void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) -{ - int i; - u32 function; - struct kvm_cpuid_entry *e, *best; - - kvm_x86_ops->cache_regs(vcpu); - function = vcpu->regs[VCPU_REGS_RAX]; - vcpu->regs[VCPU_REGS_RAX] = 0; - vcpu->regs[VCPU_REGS_RBX] = 0; - vcpu->regs[VCPU_REGS_RCX] = 0; - vcpu->regs[VCPU_REGS_RDX] = 0; - best = NULL; - for (i = 0; i < vcpu->cpuid_nent; ++i) { - e = &vcpu->cpuid_entries[i]; - if (e->function == function) { - best = e; - break; - } - /* - * Both basic or both extended? - */ - if (((e->function ^ function) & 0x80000000) == 0) - if (!best || e->function > best->function) - best = e; - } - if (best) { - vcpu->regs[VCPU_REGS_RAX] = best->eax; - vcpu->regs[VCPU_REGS_RBX] = best->ebx; - vcpu->regs[VCPU_REGS_RCX] = best->ecx; - vcpu->regs[VCPU_REGS_RDX] = best->edx; - } - kvm_x86_ops->decache_regs(vcpu); - kvm_x86_ops->skip_emulated_instruction(vcpu); -} -EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); - -static int pio_copy_data(struct kvm_vcpu *vcpu) -{ - void *p = vcpu->pio_data; - void *q; - unsigned bytes; - int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1; - - q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE, - PAGE_KERNEL); - if (!q) { - free_pio_guest_pages(vcpu); - return -ENOMEM; - } - q += vcpu->pio.guest_page_offset; - bytes = vcpu->pio.size * vcpu->pio.cur_count; - if (vcpu->pio.in) - memcpy(q, p, bytes); - else - memcpy(p, q, bytes); - q -= vcpu->pio.guest_page_offset; - vunmap(q); - free_pio_guest_pages(vcpu); - return 0; -} - -static int complete_pio(struct kvm_vcpu *vcpu) -{ - struct kvm_pio_request *io = &vcpu->pio; - long delta; - int r; - - kvm_x86_ops->cache_regs(vcpu); - - if (!io->string) { - if (io->in) - memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data, - io->size); - } else { - if (io->in) { - r = pio_copy_data(vcpu); - if (r) { - kvm_x86_ops->cache_regs(vcpu); - return r; - } - } - - delta = 1; - if (io->rep) { - delta *= io->cur_count; - /* - * The size of the register should really depend on - * current address size. - */ - vcpu->regs[VCPU_REGS_RCX] -= delta; - } - if (io->down) - delta = -delta; - delta *= io->size; - if (io->in) - vcpu->regs[VCPU_REGS_RDI] += delta; - else - vcpu->regs[VCPU_REGS_RSI] += delta; - } - - kvm_x86_ops->decache_regs(vcpu); - - io->count -= io->cur_count; - io->cur_count = 0; - - return 0; -} - -static void kernel_pio(struct kvm_io_device *pio_dev, - struct kvm_vcpu *vcpu, - void *pd) -{ - /* TODO: String I/O for in kernel device */ - - mutex_lock(&vcpu->kvm->lock); - if (vcpu->pio.in) - kvm_iodevice_read(pio_dev, vcpu->pio.port, - vcpu->pio.size, - pd); - else - kvm_iodevice_write(pio_dev, vcpu->pio.port, - vcpu->pio.size, - pd); - mutex_unlock(&vcpu->kvm->lock); -} - -static void pio_string_write(struct kvm_io_device *pio_dev, - struct kvm_vcpu *vcpu) -{ - struct kvm_pio_request *io = &vcpu->pio; - void *pd = vcpu->pio_data; - int i; - - mutex_lock(&vcpu->kvm->lock); - for (i = 0; i < io->cur_count; i++) { - kvm_iodevice_write(pio_dev, io->port, - io->size, - pd); - pd += io->size; - } - mutex_unlock(&vcpu->kvm->lock); -} - -int kvm_emulate_pio (struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned port) -{ - struct kvm_io_device *pio_dev; - - vcpu->run->exit_reason = KVM_EXIT_IO; - vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - vcpu->run->io.size = vcpu->pio.size = size; - vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; - vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = 1; - vcpu->run->io.port = vcpu->pio.port = port; - vcpu->pio.in = in; - vcpu->pio.string = 0; - vcpu->pio.down = 0; - vcpu->pio.guest_page_offset = 0; - vcpu->pio.rep = 0; - - kvm_x86_ops->cache_regs(vcpu); - memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4); - kvm_x86_ops->decache_regs(vcpu); - - kvm_x86_ops->skip_emulated_instruction(vcpu); - - pio_dev = vcpu_find_pio_dev(vcpu, port); - if (pio_dev) { - kernel_pio(pio_dev, vcpu, vcpu->pio_data); - complete_pio(vcpu); - return 1; - } - return 0; -} -EXPORT_SYMBOL_GPL(kvm_emulate_pio); - -int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, - int size, unsigned long count, int down, - gva_t address, int rep, unsigned port) -{ - unsigned now, in_page; - int i, ret = 0; - int nr_pages = 1; - struct page *page; - struct kvm_io_device *pio_dev; - - vcpu->run->exit_reason = KVM_EXIT_IO; - vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; - vcpu->run->io.size = vcpu->pio.size = size; - vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; - vcpu->run->io.count = vcpu->pio.count = vcpu->pio.cur_count = count; - vcpu->run->io.port = vcpu->pio.port = port; - vcpu->pio.in = in; - vcpu->pio.string = 1; - vcpu->pio.down = down; - vcpu->pio.guest_page_offset = offset_in_page(address); - vcpu->pio.rep = rep; - - if (!count) { - kvm_x86_ops->skip_emulated_instruction(vcpu); - return 1; - } - - if (!down) - in_page = PAGE_SIZE - offset_in_page(address); - else - in_page = offset_in_page(address) + size; - now = min(count, (unsigned long)in_page / size); - if (!now) { - /* - * String I/O straddles page boundary. Pin two guest pages - * so that we satisfy atomicity constraints. Do just one - * transaction to avoid complexity. - */ - nr_pages = 2; - now = 1; - } - if (down) { - /* - * String I/O in reverse. Yuck. Kill the guest, fix later. - */ - pr_unimpl(vcpu, "guest string pio down\n"); - inject_gp(vcpu); - return 1; - } - vcpu->run->io.count = now; - vcpu->pio.cur_count = now; - - if (vcpu->pio.cur_count == vcpu->pio.count) - kvm_x86_ops->skip_emulated_instruction(vcpu); - - for (i = 0; i < nr_pages; ++i) { - mutex_lock(&vcpu->kvm->lock); - page = gva_to_page(vcpu, address + i * PAGE_SIZE); - if (page) - get_page(page); - vcpu->pio.guest_pages[i] = page; - mutex_unlock(&vcpu->kvm->lock); - if (!page) { - inject_gp(vcpu); - free_pio_guest_pages(vcpu); - return 1; - } - } - - pio_dev = vcpu_find_pio_dev(vcpu, port); - if (!vcpu->pio.in) { - /* string PIO write */ - ret = pio_copy_data(vcpu); - if (ret >= 0 && pio_dev) { - pio_string_write(pio_dev, vcpu); - complete_pio(vcpu); - if (vcpu->pio.count == 0) - ret = 1; - } - } else if (pio_dev) - pr_unimpl(vcpu, "no string pio read support yet, " - "port %x size %d count %ld\n", - port, size, count); - - return ret; -} -EXPORT_SYMBOL_GPL(kvm_emulate_pio_string); - -/* - * Check if userspace requested an interrupt window, and that the - * interrupt window is open. - * - * No need to exit to userspace if we already have an interrupt queued. - */ -static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - return (!vcpu->irq_summary && - kvm_run->request_interrupt_window && - vcpu->interrupt_window_open && - (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF)); -} - -static void post_kvm_run_save(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; - kvm_run->cr8 = get_cr8(vcpu); - kvm_run->apic_base = kvm_get_apic_base(vcpu); - if (irqchip_in_kernel(vcpu->kvm)) - kvm_run->ready_for_interrupt_injection = 1; - else - kvm_run->ready_for_interrupt_injection = - (vcpu->interrupt_window_open && - vcpu->irq_summary == 0); -} - -static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - int r; - - if (unlikely(vcpu->mp_state == VCPU_MP_STATE_SIPI_RECEIVED)) { - printk("vcpu %d received sipi with vector # %x\n", - vcpu->vcpu_id, vcpu->sipi_vector); - kvm_lapic_reset(vcpu); - kvm_x86_ops->vcpu_reset(vcpu); - vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; - } - -preempted: - if (vcpu->guest_debug.enabled) - kvm_x86_ops->guest_debug_pre(vcpu); - -again: - r = kvm_mmu_reload(vcpu); - if (unlikely(r)) - goto out; - - preempt_disable(); - - kvm_x86_ops->prepare_guest_switch(vcpu); - kvm_load_guest_fpu(vcpu); - - local_irq_disable(); - - if (signal_pending(current)) { - local_irq_enable(); - preempt_enable(); - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.signal_exits; - goto out; - } - - if (irqchip_in_kernel(vcpu->kvm)) - kvm_x86_ops->inject_pending_irq(vcpu); - else if (!vcpu->mmio_read_completed) - kvm_x86_ops->inject_pending_vectors(vcpu, kvm_run); - - vcpu->guest_mode = 1; - kvm_guest_enter(); - - if (vcpu->requests) - if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) - kvm_x86_ops->tlb_flush(vcpu); - - kvm_x86_ops->run(vcpu, kvm_run); - - vcpu->guest_mode = 0; - local_irq_enable(); - - ++vcpu->stat.exits; - - /* - * We must have an instruction between local_irq_enable() and - * kvm_guest_exit(), so the timer interrupt isn't delayed by - * the interrupt shadow. The stat.exits increment will do nicely. - * But we need to prevent reordering, hence this barrier(): - */ - barrier(); - - kvm_guest_exit(); - - preempt_enable(); - - /* - * Profile KVM exit RIPs: - */ - if (unlikely(prof_on == KVM_PROFILING)) { - kvm_x86_ops->cache_regs(vcpu); - profile_hit(KVM_PROFILING, (void *)vcpu->rip); - } - - r = kvm_x86_ops->handle_exit(kvm_run, vcpu); - - if (r > 0) { - if (dm_request_for_irq_injection(vcpu, kvm_run)) { - r = -EINTR; - kvm_run->exit_reason = KVM_EXIT_INTR; - ++vcpu->stat.request_irq_exits; - goto out; - } - if (!need_resched()) { - ++vcpu->stat.light_exits; - goto again; - } - } - -out: - if (r > 0) { - kvm_resched(vcpu); - goto preempted; - } - - post_kvm_run_save(vcpu, kvm_run); - - return r; -} - - -static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - int r; - sigset_t sigsaved; - - vcpu_load(vcpu); - - if (unlikely(vcpu->mp_state == VCPU_MP_STATE_UNINITIALIZED)) { - kvm_vcpu_block(vcpu); - vcpu_put(vcpu); - return -EAGAIN; - } - - if (vcpu->sigset_active) - sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); - - /* re-sync apic's tpr */ - if (!irqchip_in_kernel(vcpu->kvm)) - set_cr8(vcpu, kvm_run->cr8); - - if (vcpu->pio.cur_count) { - r = complete_pio(vcpu); - if (r) - goto out; - } - - if (vcpu->mmio_needed) { - memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8); - vcpu->mmio_read_completed = 1; - vcpu->mmio_needed = 0; - r = emulate_instruction(vcpu, kvm_run, - vcpu->mmio_fault_cr2, 0); - if (r == EMULATE_DO_MMIO) { - /* - * Read-modify-write. Back to userspace. - */ - r = 0; - goto out; - } - } - - if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) { - kvm_x86_ops->cache_regs(vcpu); - vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret; - kvm_x86_ops->decache_regs(vcpu); - } - - r = __vcpu_run(vcpu, kvm_run); - -out: - if (vcpu->sigset_active) - sigprocmask(SIG_SETMASK, &sigsaved, NULL); - - vcpu_put(vcpu); - return r; -} - -static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, - struct kvm_regs *regs) -{ - vcpu_load(vcpu); - - kvm_x86_ops->cache_regs(vcpu); - - regs->rax = vcpu->regs[VCPU_REGS_RAX]; - regs->rbx = vcpu->regs[VCPU_REGS_RBX]; - regs->rcx = vcpu->regs[VCPU_REGS_RCX]; - regs->rdx = vcpu->regs[VCPU_REGS_RDX]; - regs->rsi = vcpu->regs[VCPU_REGS_RSI]; - regs->rdi = vcpu->regs[VCPU_REGS_RDI]; - regs->rsp = vcpu->regs[VCPU_REGS_RSP]; - regs->rbp = vcpu->regs[VCPU_REGS_RBP]; -#ifdef CONFIG_X86_64 - regs->r8 = vcpu->regs[VCPU_REGS_R8]; - regs->r9 = vcpu->regs[VCPU_REGS_R9]; - regs->r10 = vcpu->regs[VCPU_REGS_R10]; - regs->r11 = vcpu->regs[VCPU_REGS_R11]; - regs->r12 = vcpu->regs[VCPU_REGS_R12]; - regs->r13 = vcpu->regs[VCPU_REGS_R13]; - regs->r14 = vcpu->regs[VCPU_REGS_R14]; - regs->r15 = vcpu->regs[VCPU_REGS_R15]; -#endif - - regs->rip = vcpu->rip; - regs->rflags = kvm_x86_ops->get_rflags(vcpu); - - /* - * Don't leak debug flags in case they were set for guest debugging - */ - if (vcpu->guest_debug.enabled && vcpu->guest_debug.singlestep) - regs->rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); - - vcpu_put(vcpu); - - return 0; -} - -static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, - struct kvm_regs *regs) -{ - vcpu_load(vcpu); - - vcpu->regs[VCPU_REGS_RAX] = regs->rax; - vcpu->regs[VCPU_REGS_RBX] = regs->rbx; - vcpu->regs[VCPU_REGS_RCX] = regs->rcx; - vcpu->regs[VCPU_REGS_RDX] = regs->rdx; - vcpu->regs[VCPU_REGS_RSI] = regs->rsi; - vcpu->regs[VCPU_REGS_RDI] = regs->rdi; - vcpu->regs[VCPU_REGS_RSP] = regs->rsp; - vcpu->regs[VCPU_REGS_RBP] = regs->rbp; -#ifdef CONFIG_X86_64 - vcpu->regs[VCPU_REGS_R8] = regs->r8; - vcpu->regs[VCPU_REGS_R9] = regs->r9; - vcpu->regs[VCPU_REGS_R10] = regs->r10; - vcpu->regs[VCPU_REGS_R11] = regs->r11; - vcpu->regs[VCPU_REGS_R12] = regs->r12; - vcpu->regs[VCPU_REGS_R13] = regs->r13; - vcpu->regs[VCPU_REGS_R14] = regs->r14; - vcpu->regs[VCPU_REGS_R15] = regs->r15; -#endif - - vcpu->rip = regs->rip; - kvm_x86_ops->set_rflags(vcpu, regs->rflags); - - kvm_x86_ops->decache_regs(vcpu); - - vcpu_put(vcpu); - - return 0; -} - -static void get_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) -{ - return kvm_x86_ops->get_segment(vcpu, var, seg); -} - -static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - struct descriptor_table dt; - int pending_vec; - - vcpu_load(vcpu); - - get_segment(vcpu, &sregs->cs, VCPU_SREG_CS); - get_segment(vcpu, &sregs->ds, VCPU_SREG_DS); - get_segment(vcpu, &sregs->es, VCPU_SREG_ES); - get_segment(vcpu, &sregs->fs, VCPU_SREG_FS); - get_segment(vcpu, &sregs->gs, VCPU_SREG_GS); - get_segment(vcpu, &sregs->ss, VCPU_SREG_SS); - - get_segment(vcpu, &sregs->tr, VCPU_SREG_TR); - get_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - - kvm_x86_ops->get_idt(vcpu, &dt); - sregs->idt.limit = dt.limit; - sregs->idt.base = dt.base; - kvm_x86_ops->get_gdt(vcpu, &dt); - sregs->gdt.limit = dt.limit; - sregs->gdt.base = dt.base; - - kvm_x86_ops->decache_cr4_guest_bits(vcpu); - sregs->cr0 = vcpu->cr0; - sregs->cr2 = vcpu->cr2; - sregs->cr3 = vcpu->cr3; - sregs->cr4 = vcpu->cr4; - sregs->cr8 = get_cr8(vcpu); - sregs->efer = vcpu->shadow_efer; - sregs->apic_base = kvm_get_apic_base(vcpu); - - if (irqchip_in_kernel(vcpu->kvm)) { - memset(sregs->interrupt_bitmap, 0, - sizeof sregs->interrupt_bitmap); - pending_vec = kvm_x86_ops->get_irq(vcpu); - if (pending_vec >= 0) - set_bit(pending_vec, (unsigned long *)sregs->interrupt_bitmap); - } else - memcpy(sregs->interrupt_bitmap, vcpu->irq_pending, - sizeof sregs->interrupt_bitmap); - - vcpu_put(vcpu); - - return 0; -} - -static void set_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) -{ - return kvm_x86_ops->set_segment(vcpu, var, seg); -} - -static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, - struct kvm_sregs *sregs) -{ - int mmu_reset_needed = 0; - int i, pending_vec, max_bits; - struct descriptor_table dt; - - vcpu_load(vcpu); - - dt.limit = sregs->idt.limit; - dt.base = sregs->idt.base; - kvm_x86_ops->set_idt(vcpu, &dt); - dt.limit = sregs->gdt.limit; - dt.base = sregs->gdt.base; - kvm_x86_ops->set_gdt(vcpu, &dt); - - vcpu->cr2 = sregs->cr2; - mmu_reset_needed |= vcpu->cr3 != sregs->cr3; - vcpu->cr3 = sregs->cr3; - - set_cr8(vcpu, sregs->cr8); - - mmu_reset_needed |= vcpu->shadow_efer != sregs->efer; -#ifdef CONFIG_X86_64 - kvm_x86_ops->set_efer(vcpu, sregs->efer); -#endif - kvm_set_apic_base(vcpu, sregs->apic_base); - - kvm_x86_ops->decache_cr4_guest_bits(vcpu); - - mmu_reset_needed |= vcpu->cr0 != sregs->cr0; - vcpu->cr0 = sregs->cr0; - kvm_x86_ops->set_cr0(vcpu, sregs->cr0); - - mmu_reset_needed |= vcpu->cr4 != sregs->cr4; - kvm_x86_ops->set_cr4(vcpu, sregs->cr4); - if (!is_long_mode(vcpu) && is_pae(vcpu)) - load_pdptrs(vcpu, vcpu->cr3); - - if (mmu_reset_needed) - kvm_mmu_reset_context(vcpu); - - if (!irqchip_in_kernel(vcpu->kvm)) { - memcpy(vcpu->irq_pending, sregs->interrupt_bitmap, - sizeof vcpu->irq_pending); - vcpu->irq_summary = 0; - for (i = 0; i < ARRAY_SIZE(vcpu->irq_pending); ++i) - if (vcpu->irq_pending[i]) - __set_bit(i, &vcpu->irq_summary); - } else { - max_bits = (sizeof sregs->interrupt_bitmap) << 3; - pending_vec = find_first_bit( - (const unsigned long *)sregs->interrupt_bitmap, - max_bits); - /* Only pending external irq is handled here */ - if (pending_vec < max_bits) { - kvm_x86_ops->set_irq(vcpu, pending_vec); - printk("Set back pending irq %d\n", pending_vec); - } - } - - set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); - set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); - set_segment(vcpu, &sregs->es, VCPU_SREG_ES); - set_segment(vcpu, &sregs->fs, VCPU_SREG_FS); - set_segment(vcpu, &sregs->gs, VCPU_SREG_GS); - set_segment(vcpu, &sregs->ss, VCPU_SREG_SS); - - set_segment(vcpu, &sregs->tr, VCPU_SREG_TR); - set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR); - - vcpu_put(vcpu); - - return 0; -} - -void kvm_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) -{ - struct kvm_segment cs; - - get_segment(vcpu, &cs, VCPU_SREG_CS); - *db = cs.db; - *l = cs.l; -} -EXPORT_SYMBOL_GPL(kvm_get_cs_db_l_bits); - -/* - * List of msr numbers which we expose to userspace through KVM_GET_MSRS - * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. - * - * This list is modified at module load time to reflect the - * capabilities of the host cpu. - */ -static u32 msrs_to_save[] = { - MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, - MSR_K6_STAR, -#ifdef CONFIG_X86_64 - MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR, -#endif - MSR_IA32_TIME_STAMP_COUNTER, -}; - -static unsigned num_msrs_to_save; - -static u32 emulated_msrs[] = { - MSR_IA32_MISC_ENABLE, -}; - -static __init void kvm_init_msr_list(void) -{ - u32 dummy[2]; - unsigned i, j; - - for (i = j = 0; i < ARRAY_SIZE(msrs_to_save); i++) { - if (rdmsr_safe(msrs_to_save[i], &dummy[0], &dummy[1]) < 0) - continue; - if (j < i) - msrs_to_save[j] = msrs_to_save[i]; - j++; - } - num_msrs_to_save = j; -} - -/* - * Adapt set_msr() to msr_io()'s calling convention - */ -static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) -{ - return kvm_set_msr(vcpu, index, *data); -} - -/* - * Read or write a bunch of msrs. All parameters are kernel addresses. - * - * @return number of msrs set successfully. - */ -static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, - struct kvm_msr_entry *entries, - int (*do_msr)(struct kvm_vcpu *vcpu, - unsigned index, u64 *data)) -{ - int i; - - vcpu_load(vcpu); - - for (i = 0; i < msrs->nmsrs; ++i) - if (do_msr(vcpu, entries[i].index, &entries[i].data)) - break; - - vcpu_put(vcpu); - - return i; -} - -/* - * Read or write a bunch of msrs. Parameters are user addresses. - * - * @return number of msrs set successfully. - */ -static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs, - int (*do_msr)(struct kvm_vcpu *vcpu, - unsigned index, u64 *data), - int writeback) -{ - struct kvm_msrs msrs; - struct kvm_msr_entry *entries; - int r, n; - unsigned size; - - r = -EFAULT; - if (copy_from_user(&msrs, user_msrs, sizeof msrs)) - goto out; - - r = -E2BIG; - if (msrs.nmsrs >= MAX_IO_MSRS) - goto out; - - r = -ENOMEM; - size = sizeof(struct kvm_msr_entry) * msrs.nmsrs; - entries = vmalloc(size); - if (!entries) - goto out; - - r = -EFAULT; - if (copy_from_user(entries, user_msrs->entries, size)) - goto out_free; - - r = n = __msr_io(vcpu, &msrs, entries, do_msr); - if (r < 0) - goto out_free; - - r = -EFAULT; - if (writeback && copy_to_user(user_msrs->entries, entries, size)) - goto out_free; - - r = n; - -out_free: - vfree(entries); -out: - return r; -} - -/* - * Translate a guest virtual address to a guest physical address. - */ -static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, - struct kvm_translation *tr) -{ - unsigned long vaddr = tr->linear_address; - gpa_t gpa; - - vcpu_load(vcpu); - mutex_lock(&vcpu->kvm->lock); - gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr); - tr->physical_address = gpa; - tr->valid = gpa != UNMAPPED_GVA; - tr->writeable = 1; - tr->usermode = 0; - mutex_unlock(&vcpu->kvm->lock); - vcpu_put(vcpu); - - return 0; -} - -static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, - struct kvm_interrupt *irq) -{ - if (irq->irq < 0 || irq->irq >= 256) - return -EINVAL; - if (irqchip_in_kernel(vcpu->kvm)) - return -ENXIO; - vcpu_load(vcpu); - - set_bit(irq->irq, vcpu->irq_pending); - set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary); - - vcpu_put(vcpu); - - return 0; -} - -static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, - struct kvm_debug_guest *dbg) -{ - int r; - - vcpu_load(vcpu); - - r = kvm_x86_ops->set_guest_debug(vcpu, dbg); - - vcpu_put(vcpu); - - return r; -} - -static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma, - unsigned long address, - int *type) -{ - struct kvm_vcpu *vcpu = vma->vm_file->private_data; - unsigned long pgoff; - struct page *page; - - pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - if (pgoff == 0) - page = virt_to_page(vcpu->run); - else if (pgoff == KVM_PIO_PAGE_OFFSET) - page = virt_to_page(vcpu->pio_data); - else - return NOPAGE_SIGBUS; - get_page(page); - if (type != NULL) - *type = VM_FAULT_MINOR; - - return page; -} - -static struct vm_operations_struct kvm_vcpu_vm_ops = { - .nopage = kvm_vcpu_nopage, -}; - -static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_ops = &kvm_vcpu_vm_ops; - return 0; -} - -static int kvm_vcpu_release(struct inode *inode, struct file *filp) -{ - struct kvm_vcpu *vcpu = filp->private_data; - - fput(vcpu->kvm->filp); - return 0; -} - -static struct file_operations kvm_vcpu_fops = { - .release = kvm_vcpu_release, - .unlocked_ioctl = kvm_vcpu_ioctl, - .compat_ioctl = kvm_vcpu_ioctl, - .mmap = kvm_vcpu_mmap, -}; - -/* - * Allocates an inode for the vcpu. - */ -static int create_vcpu_fd(struct kvm_vcpu *vcpu) -{ - int fd, r; - struct inode *inode; - struct file *file; - - r = anon_inode_getfd(&fd, &inode, &file, - "kvm-vcpu", &kvm_vcpu_fops, vcpu); - if (r) - return r; - atomic_inc(&vcpu->kvm->filp->f_count); - return fd; -} - -/* - * Creates some virtual cpus. Good luck creating more than one. - */ -static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) -{ - int r; - struct kvm_vcpu *vcpu; - - if (!valid_vcpu(n)) - return -EINVAL; - - vcpu = kvm_x86_ops->vcpu_create(kvm, n); - if (IS_ERR(vcpu)) - return PTR_ERR(vcpu); - - preempt_notifier_init(&vcpu->preempt_notifier, &kvm_preempt_ops); - - /* We do fxsave: this must be aligned. */ - BUG_ON((unsigned long)&vcpu->host_fx_image & 0xF); - - vcpu_load(vcpu); - r = kvm_mmu_setup(vcpu); - vcpu_put(vcpu); - if (r < 0) - goto free_vcpu; - - mutex_lock(&kvm->lock); - if (kvm->vcpus[n]) { - r = -EEXIST; - mutex_unlock(&kvm->lock); - goto mmu_unload; - } - kvm->vcpus[n] = vcpu; - mutex_unlock(&kvm->lock); - - /* Now it's all set up, let userspace reach it */ - r = create_vcpu_fd(vcpu); - if (r < 0) - goto unlink; - return r; - -unlink: - mutex_lock(&kvm->lock); - kvm->vcpus[n] = NULL; - mutex_unlock(&kvm->lock); - -mmu_unload: - vcpu_load(vcpu); - kvm_mmu_unload(vcpu); - vcpu_put(vcpu); - -free_vcpu: - kvm_x86_ops->vcpu_free(vcpu); - return r; -} - -static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu) -{ - u64 efer; - int i; - struct kvm_cpuid_entry *e, *entry; - - rdmsrl(MSR_EFER, efer); - entry = NULL; - for (i = 0; i < vcpu->cpuid_nent; ++i) { - e = &vcpu->cpuid_entries[i]; - if (e->function == 0x80000001) { - entry = e; - break; - } - } - if (entry && (entry->edx & (1 << 20)) && !(efer & EFER_NX)) { - entry->edx &= ~(1 << 20); - printk(KERN_INFO "kvm: guest NX capability removed\n"); - } -} - -static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, - struct kvm_cpuid *cpuid, - struct kvm_cpuid_entry __user *entries) -{ - int r; - - r = -E2BIG; - if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) - goto out; - r = -EFAULT; - if (copy_from_user(&vcpu->cpuid_entries, entries, - cpuid->nent * sizeof(struct kvm_cpuid_entry))) - goto out; - vcpu->cpuid_nent = cpuid->nent; - cpuid_fix_nx_cap(vcpu); - return 0; - -out: - return r; -} - -static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) -{ - if (sigset) { - sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP)); - vcpu->sigset_active = 1; - vcpu->sigset = *sigset; - } else - vcpu->sigset_active = 0; - return 0; -} - -/* - * fxsave fpu state. Taken from x86_64/processor.h. To be killed when - * we have asm/x86/processor.h - */ -struct fxsave { - u16 cwd; - u16 swd; - u16 twd; - u16 fop; - u64 rip; - u64 rdp; - u32 mxcsr; - u32 mxcsr_mask; - u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ -#ifdef CONFIG_X86_64 - u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */ -#else - u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ -#endif -}; - -static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) -{ - struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image; - - vcpu_load(vcpu); - - memcpy(fpu->fpr, fxsave->st_space, 128); - fpu->fcw = fxsave->cwd; - fpu->fsw = fxsave->swd; - fpu->ftwx = fxsave->twd; - fpu->last_opcode = fxsave->fop; - fpu->last_ip = fxsave->rip; - fpu->last_dp = fxsave->rdp; - memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space); - - vcpu_put(vcpu); - - return 0; -} - -static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) -{ - struct fxsave *fxsave = (struct fxsave *)&vcpu->guest_fx_image; - - vcpu_load(vcpu); - - memcpy(fxsave->st_space, fpu->fpr, 128); - fxsave->cwd = fpu->fcw; - fxsave->swd = fpu->fsw; - fxsave->twd = fpu->ftwx; - fxsave->fop = fpu->last_opcode; - fxsave->rip = fpu->last_ip; - fxsave->rdp = fpu->last_dp; - memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space); - - vcpu_put(vcpu); - - return 0; -} - -static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu, - struct kvm_lapic_state *s) -{ - vcpu_load(vcpu); - memcpy(s->regs, vcpu->apic->regs, sizeof *s); - vcpu_put(vcpu); - - return 0; -} - -static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu, - struct kvm_lapic_state *s) -{ - vcpu_load(vcpu); - memcpy(vcpu->apic->regs, s->regs, sizeof *s); - kvm_apic_post_state_restore(vcpu); - vcpu_put(vcpu); - - return 0; -} - -static long kvm_vcpu_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) -{ - struct kvm_vcpu *vcpu = filp->private_data; - void __user *argp = (void __user *)arg; - int r = -EINVAL; - - switch (ioctl) { - case KVM_RUN: - r = -EINVAL; - if (arg) - goto out; - r = kvm_vcpu_ioctl_run(vcpu, vcpu->run); - break; - case KVM_GET_REGS: { - struct kvm_regs kvm_regs; - - memset(&kvm_regs, 0, sizeof kvm_regs); - r = kvm_vcpu_ioctl_get_regs(vcpu, &kvm_regs); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, &kvm_regs, sizeof kvm_regs)) - goto out; - r = 0; - break; - } - case KVM_SET_REGS: { - struct kvm_regs kvm_regs; - - r = -EFAULT; - if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) - goto out; - r = kvm_vcpu_ioctl_set_regs(vcpu, &kvm_regs); - if (r) - goto out; - r = 0; - break; - } - case KVM_GET_SREGS: { - struct kvm_sregs kvm_sregs; - - memset(&kvm_sregs, 0, sizeof kvm_sregs); - r = kvm_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs)) - goto out; - r = 0; - break; - } - case KVM_SET_SREGS: { - struct kvm_sregs kvm_sregs; - - r = -EFAULT; - if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) - goto out; - r = kvm_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs); - if (r) - goto out; - r = 0; - break; - } - case KVM_TRANSLATE: { - struct kvm_translation tr; - - r = -EFAULT; - if (copy_from_user(&tr, argp, sizeof tr)) - goto out; - r = kvm_vcpu_ioctl_translate(vcpu, &tr); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, &tr, sizeof tr)) - goto out; - r = 0; - break; - } - case KVM_INTERRUPT: { - struct kvm_interrupt irq; - - r = -EFAULT; - if (copy_from_user(&irq, argp, sizeof irq)) - goto out; - r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); - if (r) - goto out; - r = 0; - break; - } - case KVM_DEBUG_GUEST: { - struct kvm_debug_guest dbg; - - r = -EFAULT; - if (copy_from_user(&dbg, argp, sizeof dbg)) - goto out; - r = kvm_vcpu_ioctl_debug_guest(vcpu, &dbg); - if (r) - goto out; - r = 0; - break; - } - case KVM_GET_MSRS: - r = msr_io(vcpu, argp, kvm_get_msr, 1); - break; - case KVM_SET_MSRS: - r = msr_io(vcpu, argp, do_set_msr, 0); - break; - case KVM_SET_CPUID: { - struct kvm_cpuid __user *cpuid_arg = argp; - struct kvm_cpuid cpuid; - - r = -EFAULT; - if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid)) - goto out; - r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries); - if (r) - goto out; - break; - } - case KVM_SET_SIGNAL_MASK: { - struct kvm_signal_mask __user *sigmask_arg = argp; - struct kvm_signal_mask kvm_sigmask; - sigset_t sigset, *p; - - p = NULL; - if (argp) { - r = -EFAULT; - if (copy_from_user(&kvm_sigmask, argp, - sizeof kvm_sigmask)) - goto out; - r = -EINVAL; - if (kvm_sigmask.len != sizeof sigset) - goto out; - r = -EFAULT; - if (copy_from_user(&sigset, sigmask_arg->sigset, - sizeof sigset)) - goto out; - p = &sigset; - } - r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); - break; - } - case KVM_GET_FPU: { - struct kvm_fpu fpu; - - memset(&fpu, 0, sizeof fpu); - r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, &fpu, sizeof fpu)) - goto out; - r = 0; - break; - } - case KVM_SET_FPU: { - struct kvm_fpu fpu; - - r = -EFAULT; - if (copy_from_user(&fpu, argp, sizeof fpu)) - goto out; - r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu); - if (r) - goto out; - r = 0; - break; - } - case KVM_GET_LAPIC: { - struct kvm_lapic_state lapic; - - memset(&lapic, 0, sizeof lapic); - r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, &lapic, sizeof lapic)) - goto out; - r = 0; - break; - } - case KVM_SET_LAPIC: { - struct kvm_lapic_state lapic; - - r = -EFAULT; - if (copy_from_user(&lapic, argp, sizeof lapic)) - goto out; - r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);; - if (r) - goto out; - r = 0; - break; - } - default: - ; - } -out: - return r; -} - -static long kvm_vm_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) -{ - struct kvm *kvm = filp->private_data; - void __user *argp = (void __user *)arg; - int r = -EINVAL; - - switch (ioctl) { - case KVM_CREATE_VCPU: - r = kvm_vm_ioctl_create_vcpu(kvm, arg); - if (r < 0) - goto out; - break; - case KVM_SET_MEMORY_REGION: { - struct kvm_memory_region kvm_mem; - - r = -EFAULT; - if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) - goto out; - r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem); - if (r) - goto out; - break; - } - case KVM_GET_DIRTY_LOG: { - struct kvm_dirty_log log; - - r = -EFAULT; - if (copy_from_user(&log, argp, sizeof log)) - goto out; - r = kvm_vm_ioctl_get_dirty_log(kvm, &log); - if (r) - goto out; - break; - } - case KVM_SET_MEMORY_ALIAS: { - struct kvm_memory_alias alias; - - r = -EFAULT; - if (copy_from_user(&alias, argp, sizeof alias)) - goto out; - r = kvm_vm_ioctl_set_memory_alias(kvm, &alias); - if (r) - goto out; - break; - } - case KVM_CREATE_IRQCHIP: - r = -ENOMEM; - kvm->vpic = kvm_create_pic(kvm); - if (kvm->vpic) { - r = kvm_ioapic_init(kvm); - if (r) { - kfree(kvm->vpic); - kvm->vpic = NULL; - goto out; - } - } - else - goto out; - break; - case KVM_IRQ_LINE: { - struct kvm_irq_level irq_event; - - r = -EFAULT; - if (copy_from_user(&irq_event, argp, sizeof irq_event)) - goto out; - if (irqchip_in_kernel(kvm)) { - mutex_lock(&kvm->lock); - if (irq_event.irq < 16) - kvm_pic_set_irq(pic_irqchip(kvm), - irq_event.irq, - irq_event.level); - kvm_ioapic_set_irq(kvm->vioapic, - irq_event.irq, - irq_event.level); - mutex_unlock(&kvm->lock); - r = 0; - } - break; - } - case KVM_GET_IRQCHIP: { - /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ - struct kvm_irqchip chip; - - r = -EFAULT; - if (copy_from_user(&chip, argp, sizeof chip)) - goto out; - r = -ENXIO; - if (!irqchip_in_kernel(kvm)) - goto out; - r = kvm_vm_ioctl_get_irqchip(kvm, &chip); - if (r) - goto out; - r = -EFAULT; - if (copy_to_user(argp, &chip, sizeof chip)) - goto out; - r = 0; - break; - } - case KVM_SET_IRQCHIP: { - /* 0: PIC master, 1: PIC slave, 2: IOAPIC */ - struct kvm_irqchip chip; - - r = -EFAULT; - if (copy_from_user(&chip, argp, sizeof chip)) - goto out; - r = -ENXIO; - if (!irqchip_in_kernel(kvm)) - goto out; - r = kvm_vm_ioctl_set_irqchip(kvm, &chip); - if (r) - goto out; - r = 0; - break; - } - default: - ; - } -out: - return r; -} - -static struct page *kvm_vm_nopage(struct vm_area_struct *vma, - unsigned long address, - int *type) -{ - struct kvm *kvm = vma->vm_file->private_data; - unsigned long pgoff; - struct page *page; - - pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - page = gfn_to_page(kvm, pgoff); - if (!page) - return NOPAGE_SIGBUS; - get_page(page); - if (type != NULL) - *type = VM_FAULT_MINOR; - - return page; -} - -static struct vm_operations_struct kvm_vm_vm_ops = { - .nopage = kvm_vm_nopage, -}; - -static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_ops = &kvm_vm_vm_ops; - return 0; -} - -static struct file_operations kvm_vm_fops = { - .release = kvm_vm_release, - .unlocked_ioctl = kvm_vm_ioctl, - .compat_ioctl = kvm_vm_ioctl, - .mmap = kvm_vm_mmap, -}; - -static int kvm_dev_ioctl_create_vm(void) -{ - int fd, r; - struct inode *inode; - struct file *file; - struct kvm *kvm; - - kvm = kvm_create_vm(); - if (IS_ERR(kvm)) - return PTR_ERR(kvm); - r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm); - if (r) { - kvm_destroy_vm(kvm); - return r; - } - - kvm->filp = file; - - return fd; -} - -static long kvm_dev_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - long r = -EINVAL; - - switch (ioctl) { - case KVM_GET_API_VERSION: - r = -EINVAL; - if (arg) - goto out; - r = KVM_API_VERSION; - break; - case KVM_CREATE_VM: - r = -EINVAL; - if (arg) - goto out; - r = kvm_dev_ioctl_create_vm(); - break; - case KVM_GET_MSR_INDEX_LIST: { - struct kvm_msr_list __user *user_msr_list = argp; - struct kvm_msr_list msr_list; - unsigned n; - - r = -EFAULT; - if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) - goto out; - n = msr_list.nmsrs; - msr_list.nmsrs = num_msrs_to_save + ARRAY_SIZE(emulated_msrs); - if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) - goto out; - r = -E2BIG; - if (n < num_msrs_to_save) - goto out; - r = -EFAULT; - if (copy_to_user(user_msr_list->indices, &msrs_to_save, - num_msrs_to_save * sizeof(u32))) - goto out; - if (copy_to_user(user_msr_list->indices - + num_msrs_to_save * sizeof(u32), - &emulated_msrs, - ARRAY_SIZE(emulated_msrs) * sizeof(u32))) - goto out; - r = 0; - break; - } - case KVM_CHECK_EXTENSION: { - int ext = (long)argp; - - switch (ext) { - case KVM_CAP_IRQCHIP: - case KVM_CAP_HLT: - r = 1; - break; - default: - r = 0; - break; - } - break; - } - case KVM_GET_VCPU_MMAP_SIZE: - r = -EINVAL; - if (arg) - goto out; - r = 2 * PAGE_SIZE; - break; - default: - ; - } -out: - return r; -} - -static struct file_operations kvm_chardev_ops = { - .unlocked_ioctl = kvm_dev_ioctl, - .compat_ioctl = kvm_dev_ioctl, -}; - -static struct miscdevice kvm_dev = { - KVM_MINOR, - "kvm", - &kvm_chardev_ops, -}; - -/* - * Make sure that a cpu that is being hot-unplugged does not have any vcpus - * cached on it. - */ -static void decache_vcpus_on_cpu(int cpu) -{ - struct kvm *vm; - struct kvm_vcpu *vcpu; - int i; - - spin_lock(&kvm_lock); - list_for_each_entry(vm, &vm_list, vm_list) - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = vm->vcpus[i]; - if (!vcpu) - continue; - /* - * If the vcpu is locked, then it is running on some - * other cpu and therefore it is not cached on the - * cpu in question. - * - * If it's not locked, check the last cpu it executed - * on. - */ - if (mutex_trylock(&vcpu->mutex)) { - if (vcpu->cpu == cpu) { - kvm_x86_ops->vcpu_decache(vcpu); - vcpu->cpu = -1; - } - mutex_unlock(&vcpu->mutex); - } - } - spin_unlock(&kvm_lock); -} - -static void hardware_enable(void *junk) -{ - int cpu = raw_smp_processor_id(); - - if (cpu_isset(cpu, cpus_hardware_enabled)) - return; - cpu_set(cpu, cpus_hardware_enabled); - kvm_x86_ops->hardware_enable(NULL); -} - -static void hardware_disable(void *junk) -{ - int cpu = raw_smp_processor_id(); - - if (!cpu_isset(cpu, cpus_hardware_enabled)) - return; - cpu_clear(cpu, cpus_hardware_enabled); - decache_vcpus_on_cpu(cpu); - kvm_x86_ops->hardware_disable(NULL); -} - -static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, - void *v) -{ - int cpu = (long)v; - - switch (val) { - case CPU_DYING: - case CPU_DYING_FROZEN: - printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", - cpu); - hardware_disable(NULL); - break; - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", - cpu); - smp_call_function_single(cpu, hardware_disable, NULL, 0, 1); - break; - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", - cpu); - smp_call_function_single(cpu, hardware_enable, NULL, 0, 1); - break; - } - return NOTIFY_OK; -} - -static int kvm_reboot(struct notifier_block *notifier, unsigned long val, - void *v) -{ - if (val == SYS_RESTART) { - /* - * Some (well, at least mine) BIOSes hang on reboot if - * in vmx root mode. - */ - printk(KERN_INFO "kvm: exiting hardware virtualization\n"); - on_each_cpu(hardware_disable, NULL, 0, 1); - } - return NOTIFY_OK; -} - -static struct notifier_block kvm_reboot_notifier = { - .notifier_call = kvm_reboot, - .priority = 0, -}; - -void kvm_io_bus_init(struct kvm_io_bus *bus) -{ - memset(bus, 0, sizeof(*bus)); -} - -void kvm_io_bus_destroy(struct kvm_io_bus *bus) -{ - int i; - - for (i = 0; i < bus->dev_count; i++) { - struct kvm_io_device *pos = bus->devs[i]; - - kvm_iodevice_destructor(pos); - } -} - -struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr) -{ - int i; - - for (i = 0; i < bus->dev_count; i++) { - struct kvm_io_device *pos = bus->devs[i]; - - if (pos->in_range(pos, addr)) - return pos; - } - - return NULL; -} - -void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev) -{ - BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1)); - - bus->devs[bus->dev_count++] = dev; -} - -static struct notifier_block kvm_cpu_notifier = { - .notifier_call = kvm_cpu_hotplug, - .priority = 20, /* must be > scheduler priority */ -}; - -static u64 stat_get(void *_offset) -{ - unsigned offset = (long)_offset; - u64 total = 0; - struct kvm *kvm; - struct kvm_vcpu *vcpu; - int i; - - spin_lock(&kvm_lock); - list_for_each_entry(kvm, &vm_list, vm_list) - for (i = 0; i < KVM_MAX_VCPUS; ++i) { - vcpu = kvm->vcpus[i]; - if (vcpu) - total += *(u32 *)((void *)vcpu + offset); - } - spin_unlock(&kvm_lock); - return total; -} - -DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, NULL, "%llu\n"); - -static __init void kvm_init_debug(void) -{ - struct kvm_stats_debugfs_item *p; - - debugfs_dir = debugfs_create_dir("kvm", NULL); - for (p = debugfs_entries; p->name; ++p) - p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir, - (void *)(long)p->offset, - &stat_fops); -} - -static void kvm_exit_debug(void) -{ - struct kvm_stats_debugfs_item *p; - - for (p = debugfs_entries; p->name; ++p) - debugfs_remove(p->dentry); - debugfs_remove(debugfs_dir); -} - -static int kvm_suspend(struct sys_device *dev, pm_message_t state) -{ - hardware_disable(NULL); - return 0; -} - -static int kvm_resume(struct sys_device *dev) -{ - hardware_enable(NULL); - return 0; -} - -static struct sysdev_class kvm_sysdev_class = { - set_kset_name("kvm"), - .suspend = kvm_suspend, - .resume = kvm_resume, -}; - -static struct sys_device kvm_sysdev = { - .id = 0, - .cls = &kvm_sysdev_class, -}; - -hpa_t bad_page_address; - -static inline -struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn) -{ - return container_of(pn, struct kvm_vcpu, preempt_notifier); -} - -static void kvm_sched_in(struct preempt_notifier *pn, int cpu) -{ - struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); - - kvm_x86_ops->vcpu_load(vcpu, cpu); -} - -static void kvm_sched_out(struct preempt_notifier *pn, - struct task_struct *next) -{ - struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn); - - kvm_x86_ops->vcpu_put(vcpu); -} - -int kvm_init_x86(struct kvm_x86_ops *ops, unsigned int vcpu_size, - struct module *module) -{ - int r; - int cpu; - - if (kvm_x86_ops) { - printk(KERN_ERR "kvm: already loaded the other module\n"); - return -EEXIST; - } - - if (!ops->cpu_has_kvm_support()) { - printk(KERN_ERR "kvm: no hardware support\n"); - return -EOPNOTSUPP; - } - if (ops->disabled_by_bios()) { - printk(KERN_ERR "kvm: disabled by bios\n"); - return -EOPNOTSUPP; - } - - kvm_x86_ops = ops; - - r = kvm_x86_ops->hardware_setup(); - if (r < 0) - goto out; - - for_each_online_cpu(cpu) { - smp_call_function_single(cpu, - kvm_x86_ops->check_processor_compatibility, - &r, 0, 1); - if (r < 0) - goto out_free_0; - } - - on_each_cpu(hardware_enable, NULL, 0, 1); - r = register_cpu_notifier(&kvm_cpu_notifier); - if (r) - goto out_free_1; - register_reboot_notifier(&kvm_reboot_notifier); - - r = sysdev_class_register(&kvm_sysdev_class); - if (r) - goto out_free_2; - - r = sysdev_register(&kvm_sysdev); - if (r) - goto out_free_3; - - /* A kmem cache lets us meet the alignment requirements of fx_save. */ - kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, - __alignof__(struct kvm_vcpu), 0, 0); - if (!kvm_vcpu_cache) { - r = -ENOMEM; - goto out_free_4; - } - - kvm_chardev_ops.owner = module; - - r = misc_register(&kvm_dev); - if (r) { - printk (KERN_ERR "kvm: misc device register failed\n"); - goto out_free; - } - - kvm_preempt_ops.sched_in = kvm_sched_in; - kvm_preempt_ops.sched_out = kvm_sched_out; - - return r; - -out_free: - kmem_cache_destroy(kvm_vcpu_cache); -out_free_4: - sysdev_unregister(&kvm_sysdev); -out_free_3: - sysdev_class_unregister(&kvm_sysdev_class); -out_free_2: - unregister_reboot_notifier(&kvm_reboot_notifier); - unregister_cpu_notifier(&kvm_cpu_notifier); -out_free_1: - on_each_cpu(hardware_disable, NULL, 0, 1); -out_free_0: - kvm_x86_ops->hardware_unsetup(); -out: - kvm_x86_ops = NULL; - return r; -} - -void kvm_exit_x86(void) -{ - misc_deregister(&kvm_dev); - kmem_cache_destroy(kvm_vcpu_cache); - sysdev_unregister(&kvm_sysdev); - sysdev_class_unregister(&kvm_sysdev_class); - unregister_reboot_notifier(&kvm_reboot_notifier); - unregister_cpu_notifier(&kvm_cpu_notifier); - on_each_cpu(hardware_disable, NULL, 0, 1); - kvm_x86_ops->hardware_unsetup(); - kvm_x86_ops = NULL; -} - -static __init int kvm_init(void) -{ - static struct page *bad_page; - int r; - - r = kvm_mmu_module_init(); - if (r) - goto out4; - - kvm_init_debug(); - - kvm_init_msr_list(); - - if ((bad_page = alloc_page(GFP_KERNEL)) == NULL) { - r = -ENOMEM; - goto out; - } - - bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT; - memset(__va(bad_page_address), 0, PAGE_SIZE); - - return 0; - -out: - kvm_exit_debug(); - kvm_mmu_module_exit(); -out4: - return r; -} - -static __exit void kvm_exit(void) -{ - kvm_exit_debug(); - __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT)); - kvm_mmu_module_exit(); -} - -module_init(kvm_init) -module_exit(kvm_exit) - -EXPORT_SYMBOL_GPL(kvm_init_x86); -EXPORT_SYMBOL_GPL(kvm_exit_x86); diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h deleted file mode 100644 index a0e415daef5b..000000000000 --- a/drivers/kvm/kvm_svm.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __KVM_SVM_H -#define __KVM_SVM_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/list.h> -#include <asm/msr.h> - -#include "svm.h" -#include "kvm.h" - -static const u32 host_save_user_msrs[] = { -#ifdef CONFIG_X86_64 - MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE, - MSR_FS_BASE, -#endif - MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, -}; - -#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs) -#define NUM_DB_REGS 4 - -struct kvm_vcpu; - -struct vcpu_svm { - struct kvm_vcpu vcpu; - struct vmcb *vmcb; - unsigned long vmcb_pa; - struct svm_cpu_data *svm_data; - uint64_t asid_generation; - - unsigned long db_regs[NUM_DB_REGS]; - - u64 next_rip; - - u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS]; - u64 host_gs_base; - unsigned long host_cr2; - unsigned long host_db_regs[NUM_DB_REGS]; - unsigned long host_dr6; - unsigned long host_dr7; -}; - -#endif - diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c deleted file mode 100644 index 238fcad3cece..000000000000 --- a/drivers/kvm/lapic.c +++ /dev/null @@ -1,1080 +0,0 @@ - -/* - * Local APIC virtualization - * - * Copyright (C) 2006 Qumranet, Inc. - * Copyright (C) 2007 Novell - * Copyright (C) 2007 Intel - * - * Authors: - * Dor Laor <dor.laor@qumranet.com> - * Gregory Haskins <ghaskins@novell.com> - * Yaozu (Eddie) Dong <eddie.dong@intel.com> - * - * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation. - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - */ - -#include "kvm.h" -#include <linux/kvm.h> -#include <linux/mm.h> -#include <linux/highmem.h> -#include <linux/smp.h> -#include <linux/hrtimer.h> -#include <linux/io.h> -#include <linux/module.h> -#include <asm/processor.h> -#include <asm/msr.h> -#include <asm/page.h> -#include <asm/current.h> -#include <asm/apicdef.h> -#include <asm/atomic.h> -#include <asm/div64.h> -#include "irq.h" - -#define PRId64 "d" -#define PRIx64 "llx" -#define PRIu64 "u" -#define PRIo64 "o" - -#define APIC_BUS_CYCLE_NS 1 - -/* #define apic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg) */ -#define apic_debug(fmt, arg...) - -#define APIC_LVT_NUM 6 -/* 14 is the version for Xeon and Pentium 8.4.8*/ -#define APIC_VERSION (0x14UL | ((APIC_LVT_NUM - 1) << 16)) -#define LAPIC_MMIO_LENGTH (1 << 12) -/* followed define is not in apicdef.h */ -#define APIC_SHORT_MASK 0xc0000 -#define APIC_DEST_NOSHORT 0x0 -#define APIC_DEST_MASK 0x800 -#define MAX_APIC_VECTOR 256 - -#define VEC_POS(v) ((v) & (32 - 1)) -#define REG_POS(v) (((v) >> 5) << 4) -static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off) -{ - return *((u32 *) (apic->regs + reg_off)); -} - -static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val) -{ - *((u32 *) (apic->regs + reg_off)) = val; -} - -static inline int apic_test_and_set_vector(int vec, void *bitmap) -{ - return test_and_set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); -} - -static inline int apic_test_and_clear_vector(int vec, void *bitmap) -{ - return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); -} - -static inline void apic_set_vector(int vec, void *bitmap) -{ - set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); -} - -static inline void apic_clear_vector(int vec, void *bitmap) -{ - clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); -} - -static inline int apic_hw_enabled(struct kvm_lapic *apic) -{ - return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE; -} - -static inline int apic_sw_enabled(struct kvm_lapic *apic) -{ - return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED; -} - -static inline int apic_enabled(struct kvm_lapic *apic) -{ - return apic_sw_enabled(apic) && apic_hw_enabled(apic); -} - -#define LVT_MASK \ - (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) - -#define LINT_MASK \ - (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \ - APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) - -static inline int kvm_apic_id(struct kvm_lapic *apic) -{ - return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff; -} - -static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type) -{ - return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED); -} - -static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type) -{ - return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK; -} - -static inline int apic_lvtt_period(struct kvm_lapic *apic) -{ - return apic_get_reg(apic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC; -} - -static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { - LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ - LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ - LVT_MASK | APIC_MODE_MASK, /* LVTPC */ - LINT_MASK, LINT_MASK, /* LVT0-1 */ - LVT_MASK /* LVTERR */ -}; - -static int find_highest_vector(void *bitmap) -{ - u32 *word = bitmap; - int word_offset = MAX_APIC_VECTOR >> 5; - - while ((word_offset != 0) && (word[(--word_offset) << 2] == 0)) - continue; - - if (likely(!word_offset && !word[0])) - return -1; - else - return fls(word[word_offset << 2]) - 1 + (word_offset << 5); -} - -static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) -{ - return apic_test_and_set_vector(vec, apic->regs + APIC_IRR); -} - -static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) -{ - apic_clear_vector(vec, apic->regs + APIC_IRR); -} - -static inline int apic_find_highest_irr(struct kvm_lapic *apic) -{ - int result; - - result = find_highest_vector(apic->regs + APIC_IRR); - ASSERT(result == -1 || result >= 16); - - return result; -} - -int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; - int highest_irr; - - if (!apic) - return 0; - highest_irr = apic_find_highest_irr(apic); - - return highest_irr; -} -EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); - -int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig) -{ - if (!apic_test_and_set_irr(vec, apic)) { - /* a new pending irq is set in IRR */ - if (trig) - apic_set_vector(vec, apic->regs + APIC_TMR); - else - apic_clear_vector(vec, apic->regs + APIC_TMR); - kvm_vcpu_kick(apic->vcpu); - return 1; - } - return 0; -} - -static inline int apic_find_highest_isr(struct kvm_lapic *apic) -{ - int result; - - result = find_highest_vector(apic->regs + APIC_ISR); - ASSERT(result == -1 || result >= 16); - - return result; -} - -static void apic_update_ppr(struct kvm_lapic *apic) -{ - u32 tpr, isrv, ppr; - int isr; - - tpr = apic_get_reg(apic, APIC_TASKPRI); - isr = apic_find_highest_isr(apic); - isrv = (isr != -1) ? isr : 0; - - if ((tpr & 0xf0) >= (isrv & 0xf0)) - ppr = tpr & 0xff; - else - ppr = isrv & 0xf0; - - apic_debug("vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x", - apic, ppr, isr, isrv); - - apic_set_reg(apic, APIC_PROCPRI, ppr); -} - -static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr) -{ - apic_set_reg(apic, APIC_TASKPRI, tpr); - apic_update_ppr(apic); -} - -int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) -{ - return kvm_apic_id(apic) == dest; -} - -int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) -{ - int result = 0; - u8 logical_id; - - logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR)); - - switch (apic_get_reg(apic, APIC_DFR)) { - case APIC_DFR_FLAT: - if (logical_id & mda) - result = 1; - break; - case APIC_DFR_CLUSTER: - if (((logical_id >> 4) == (mda >> 0x4)) - && (logical_id & mda & 0xf)) - result = 1; - break; - default: - printk(KERN_WARNING "Bad DFR vcpu %d: %08x\n", - apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR)); - break; - } - - return result; -} - -static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, - int short_hand, int dest, int dest_mode) -{ - int result = 0; - struct kvm_lapic *target = vcpu->apic; - - apic_debug("target %p, source %p, dest 0x%x, " - "dest_mode 0x%x, short_hand 0x%x", - target, source, dest, dest_mode, short_hand); - - ASSERT(!target); - switch (short_hand) { - case APIC_DEST_NOSHORT: - if (dest_mode == 0) { - /* Physical mode. */ - if ((dest == 0xFF) || (dest == kvm_apic_id(target))) - result = 1; - } else - /* Logical mode. */ - result = kvm_apic_match_logical_addr(target, dest); - break; - case APIC_DEST_SELF: - if (target == source) - result = 1; - break; - case APIC_DEST_ALLINC: - result = 1; - break; - case APIC_DEST_ALLBUT: - if (target != source) - result = 1; - break; - default: - printk(KERN_WARNING "Bad dest shorthand value %x\n", - short_hand); - break; - } - - return result; -} - -/* - * Add a pending IRQ into lapic. - * Return 1 if successfully added and 0 if discarded. - */ -static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, - int vector, int level, int trig_mode) -{ - int orig_irr, result = 0; - struct kvm_vcpu *vcpu = apic->vcpu; - - switch (delivery_mode) { - case APIC_DM_FIXED: - case APIC_DM_LOWEST: - /* FIXME add logic for vcpu on reset */ - if (unlikely(!apic_enabled(apic))) - break; - - orig_irr = apic_test_and_set_irr(vector, apic); - if (orig_irr && trig_mode) { - apic_debug("level trig mode repeatedly for vector %d", - vector); - break; - } - - if (trig_mode) { - apic_debug("level trig mode for vector %d", vector); - apic_set_vector(vector, apic->regs + APIC_TMR); - } else - apic_clear_vector(vector, apic->regs + APIC_TMR); - - if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) - kvm_vcpu_kick(vcpu); - else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) { - vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; - if (waitqueue_active(&vcpu->wq)) - wake_up_interruptible(&vcpu->wq); - } - - result = (orig_irr == 0); - break; - - case APIC_DM_REMRD: - printk(KERN_DEBUG "Ignoring delivery mode 3\n"); - break; - - case APIC_DM_SMI: - printk(KERN_DEBUG "Ignoring guest SMI\n"); - break; - case APIC_DM_NMI: - printk(KERN_DEBUG "Ignoring guest NMI\n"); - break; - - case APIC_DM_INIT: - if (level) { - if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) - printk(KERN_DEBUG - "INIT on a runnable vcpu %d\n", - vcpu->vcpu_id); - vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED; - kvm_vcpu_kick(vcpu); - } else { - printk(KERN_DEBUG - "Ignoring de-assert INIT to vcpu %d\n", - vcpu->vcpu_id); - } - - break; - - case APIC_DM_STARTUP: - printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", - vcpu->vcpu_id, vector); - if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) { - vcpu->sipi_vector = vector; - vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED; - if (waitqueue_active(&vcpu->wq)) - wake_up_interruptible(&vcpu->wq); - } - break; - - default: - printk(KERN_ERR "TODO: unsupported delivery mode %x\n", - delivery_mode); - break; - } - return result; -} - -struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector, - unsigned long bitmap) -{ - int vcpu_id; - int last; - int next; - struct kvm_lapic *apic; - - last = kvm->round_robin_prev_vcpu; - next = last; - - do { - if (++next == KVM_MAX_VCPUS) - next = 0; - if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap)) - continue; - apic = kvm->vcpus[next]->apic; - if (apic && apic_enabled(apic)) - break; - apic = NULL; - } while (next != last); - kvm->round_robin_prev_vcpu = next; - - if (!apic) { - vcpu_id = ffs(bitmap) - 1; - if (vcpu_id < 0) { - vcpu_id = 0; - printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n"); - } - apic = kvm->vcpus[vcpu_id]->apic; - } - - return apic; -} - -static void apic_set_eoi(struct kvm_lapic *apic) -{ - int vector = apic_find_highest_isr(apic); - - /* - * Not every write EOI will has corresponding ISR, - * one example is when Kernel check timer on setup_IO_APIC - */ - if (vector == -1) - return; - - apic_clear_vector(vector, apic->regs + APIC_ISR); - apic_update_ppr(apic); - - if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR)) - kvm_ioapic_update_eoi(apic->vcpu->kvm, vector); -} - -static void apic_send_ipi(struct kvm_lapic *apic) -{ - u32 icr_low = apic_get_reg(apic, APIC_ICR); - u32 icr_high = apic_get_reg(apic, APIC_ICR2); - - unsigned int dest = GET_APIC_DEST_FIELD(icr_high); - unsigned int short_hand = icr_low & APIC_SHORT_MASK; - unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; - unsigned int level = icr_low & APIC_INT_ASSERT; - unsigned int dest_mode = icr_low & APIC_DEST_MASK; - unsigned int delivery_mode = icr_low & APIC_MODE_MASK; - unsigned int vector = icr_low & APIC_VECTOR_MASK; - - struct kvm_lapic *target; - struct kvm_vcpu *vcpu; - unsigned long lpr_map = 0; - int i; - - apic_debug("icr_high 0x%x, icr_low 0x%x, " - "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " - "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", - icr_high, icr_low, short_hand, dest, - trig_mode, level, dest_mode, delivery_mode, vector); - - for (i = 0; i < KVM_MAX_VCPUS; i++) { - vcpu = apic->vcpu->kvm->vcpus[i]; - if (!vcpu) - continue; - - if (vcpu->apic && - apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { - if (delivery_mode == APIC_DM_LOWEST) - set_bit(vcpu->vcpu_id, &lpr_map); - else - __apic_accept_irq(vcpu->apic, delivery_mode, - vector, level, trig_mode); - } - } - - if (delivery_mode == APIC_DM_LOWEST) { - target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map); - if (target != NULL) - __apic_accept_irq(target, delivery_mode, - vector, level, trig_mode); - } -} - -static u32 apic_get_tmcct(struct kvm_lapic *apic) -{ - u64 counter_passed; - ktime_t passed, now; - u32 tmcct; - - ASSERT(apic != NULL); - - now = apic->timer.dev.base->get_time(); - tmcct = apic_get_reg(apic, APIC_TMICT); - - /* if initial count is 0, current count should also be 0 */ - if (tmcct == 0) - return 0; - - if (unlikely(ktime_to_ns(now) <= - ktime_to_ns(apic->timer.last_update))) { - /* Wrap around */ - passed = ktime_add(( { - (ktime_t) { - .tv64 = KTIME_MAX - - (apic->timer.last_update).tv64}; } - ), now); - apic_debug("time elapsed\n"); - } else - passed = ktime_sub(now, apic->timer.last_update); - - counter_passed = div64_64(ktime_to_ns(passed), - (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); - - if (counter_passed > tmcct) { - if (unlikely(!apic_lvtt_period(apic))) { - /* one-shot timers stick at 0 until reset */ - tmcct = 0; - } else { - /* - * periodic timers reset to APIC_TMICT when they - * hit 0. The while loop simulates this happening N - * times. (counter_passed %= tmcct) would also work, - * but might be slower or not work on 32-bit?? - */ - while (counter_passed > tmcct) - counter_passed -= tmcct; - tmcct -= counter_passed; - } - } else { - tmcct -= counter_passed; - } - - return tmcct; -} - -static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset) -{ - u32 val = 0; - - if (offset >= LAPIC_MMIO_LENGTH) - return 0; - - switch (offset) { - case APIC_ARBPRI: - printk(KERN_WARNING "Access APIC ARBPRI register " - "which is for P6\n"); - break; - - case APIC_TMCCT: /* Timer CCR */ - val = apic_get_tmcct(apic); - break; - - default: - apic_update_ppr(apic); - val = apic_get_reg(apic, offset); - break; - } - - return val; -} - -static void apic_mmio_read(struct kvm_io_device *this, - gpa_t address, int len, void *data) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)this->private; - unsigned int offset = address - apic->base_address; - unsigned char alignment = offset & 0xf; - u32 result; - - if ((alignment + len) > 4) { - printk(KERN_ERR "KVM_APIC_READ: alignment error %lx %d", - (unsigned long)address, len); - return; - } - result = __apic_read(apic, offset & ~0xf); - - switch (len) { - case 1: - case 2: - case 4: - memcpy(data, (char *)&result + alignment, len); - break; - default: - printk(KERN_ERR "Local APIC read with len = %x, " - "should be 1,2, or 4 instead\n", len); - break; - } -} - -static void update_divide_count(struct kvm_lapic *apic) -{ - u32 tmp1, tmp2, tdcr; - - tdcr = apic_get_reg(apic, APIC_TDCR); - tmp1 = tdcr & 0xf; - tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; - apic->timer.divide_count = 0x1 << (tmp2 & 0x7); - - apic_debug("timer divide count is 0x%x\n", - apic->timer.divide_count); -} - -static void start_apic_timer(struct kvm_lapic *apic) -{ - ktime_t now = apic->timer.dev.base->get_time(); - - apic->timer.last_update = now; - - apic->timer.period = apic_get_reg(apic, APIC_TMICT) * - APIC_BUS_CYCLE_NS * apic->timer.divide_count; - atomic_set(&apic->timer.pending, 0); - hrtimer_start(&apic->timer.dev, - ktime_add_ns(now, apic->timer.period), - HRTIMER_MODE_ABS); - - apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" - PRIx64 ", " - "timer initial count 0x%x, period %lldns, " - "expire @ 0x%016" PRIx64 ".\n", __FUNCTION__, - APIC_BUS_CYCLE_NS, ktime_to_ns(now), - apic_get_reg(apic, APIC_TMICT), - apic->timer.period, - ktime_to_ns(ktime_add_ns(now, - apic->timer.period))); -} - -static void apic_mmio_write(struct kvm_io_device *this, - gpa_t address, int len, const void *data) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)this->private; - unsigned int offset = address - apic->base_address; - unsigned char alignment = offset & 0xf; - u32 val; - - /* - * APIC register must be aligned on 128-bits boundary. - * 32/64/128 bits registers must be accessed thru 32 bits. - * Refer SDM 8.4.1 - */ - if (len != 4 || alignment) { - if (printk_ratelimit()) - printk(KERN_ERR "apic write: bad size=%d %lx\n", - len, (long)address); - return; - } - - val = *(u32 *) data; - - /* too common printing */ - if (offset != APIC_EOI) - apic_debug("%s: offset 0x%x with length 0x%x, and value is " - "0x%x\n", __FUNCTION__, offset, len, val); - - offset &= 0xff0; - - switch (offset) { - case APIC_ID: /* Local APIC ID */ - apic_set_reg(apic, APIC_ID, val); - break; - - case APIC_TASKPRI: - apic_set_tpr(apic, val & 0xff); - break; - - case APIC_EOI: - apic_set_eoi(apic); - break; - - case APIC_LDR: - apic_set_reg(apic, APIC_LDR, val & APIC_LDR_MASK); - break; - - case APIC_DFR: - apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); - break; - - case APIC_SPIV: - apic_set_reg(apic, APIC_SPIV, val & 0x3ff); - if (!(val & APIC_SPIV_APIC_ENABLED)) { - int i; - u32 lvt_val; - - for (i = 0; i < APIC_LVT_NUM; i++) { - lvt_val = apic_get_reg(apic, - APIC_LVTT + 0x10 * i); - apic_set_reg(apic, APIC_LVTT + 0x10 * i, - lvt_val | APIC_LVT_MASKED); - } - atomic_set(&apic->timer.pending, 0); - - } - break; - - case APIC_ICR: - /* No delay here, so we always clear the pending bit */ - apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); - apic_send_ipi(apic); - break; - - case APIC_ICR2: - apic_set_reg(apic, APIC_ICR2, val & 0xff000000); - break; - - case APIC_LVTT: - case APIC_LVTTHMR: - case APIC_LVTPC: - case APIC_LVT0: - case APIC_LVT1: - case APIC_LVTERR: - /* TODO: Check vector */ - if (!apic_sw_enabled(apic)) - val |= APIC_LVT_MASKED; - - val &= apic_lvt_mask[(offset - APIC_LVTT) >> 4]; - apic_set_reg(apic, offset, val); - - break; - - case APIC_TMICT: - hrtimer_cancel(&apic->timer.dev); - apic_set_reg(apic, APIC_TMICT, val); - start_apic_timer(apic); - return; - - case APIC_TDCR: - if (val & 4) - printk(KERN_ERR "KVM_WRITE:TDCR %x\n", val); - apic_set_reg(apic, APIC_TDCR, val); - update_divide_count(apic); - break; - - default: - apic_debug("Local APIC Write to read-only register %x\n", - offset); - break; - } - -} - -static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)this->private; - int ret = 0; - - - if (apic_hw_enabled(apic) && - (addr >= apic->base_address) && - (addr < (apic->base_address + LAPIC_MMIO_LENGTH))) - ret = 1; - - return ret; -} - -void kvm_free_apic(struct kvm_lapic *apic) -{ - if (!apic) - return; - - hrtimer_cancel(&apic->timer.dev); - - if (apic->regs_page) { - __free_page(apic->regs_page); - apic->regs_page = 0; - } - - kfree(apic); -} - -/* - *---------------------------------------------------------------------- - * LAPIC interface - *---------------------------------------------------------------------- - */ - -void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; - - if (!apic) - return; - apic_set_tpr(apic, ((cr8 & 0x0f) << 4)); -} - -u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; - u64 tpr; - - if (!apic) - return 0; - tpr = (u64) apic_get_reg(apic, APIC_TASKPRI); - - return (tpr & 0xf0) >> 4; -} -EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8); - -void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; - - if (!apic) { - value |= MSR_IA32_APICBASE_BSP; - vcpu->apic_base = value; - return; - } - if (apic->vcpu->vcpu_id) - value &= ~MSR_IA32_APICBASE_BSP; - - vcpu->apic_base = value; - apic->base_address = apic->vcpu->apic_base & - MSR_IA32_APICBASE_BASE; - - /* with FSB delivery interrupt, we can restart APIC functionality */ - apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is " - "0x%lx.\n", apic->apic_base, apic->base_address); - -} - -u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu) -{ - return vcpu->apic_base; -} -EXPORT_SYMBOL_GPL(kvm_lapic_get_base); - -void kvm_lapic_reset(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic; - int i; - - apic_debug("%s\n", __FUNCTION__); - - ASSERT(vcpu); - apic = vcpu->apic; - ASSERT(apic != NULL); - - /* Stop the timer in case it's a reset to an active apic */ - hrtimer_cancel(&apic->timer.dev); - - apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); - apic_set_reg(apic, APIC_LVR, APIC_VERSION); - - for (i = 0; i < APIC_LVT_NUM; i++) - apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); - apic_set_reg(apic, APIC_LVT0, - SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT)); - - apic_set_reg(apic, APIC_DFR, 0xffffffffU); - apic_set_reg(apic, APIC_SPIV, 0xff); - apic_set_reg(apic, APIC_TASKPRI, 0); - apic_set_reg(apic, APIC_LDR, 0); - apic_set_reg(apic, APIC_ESR, 0); - apic_set_reg(apic, APIC_ICR, 0); - apic_set_reg(apic, APIC_ICR2, 0); - apic_set_reg(apic, APIC_TDCR, 0); - apic_set_reg(apic, APIC_TMICT, 0); - for (i = 0; i < 8; i++) { - apic_set_reg(apic, APIC_IRR + 0x10 * i, 0); - apic_set_reg(apic, APIC_ISR + 0x10 * i, 0); - apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); - } - update_divide_count(apic); - atomic_set(&apic->timer.pending, 0); - if (vcpu->vcpu_id == 0) - vcpu->apic_base |= MSR_IA32_APICBASE_BSP; - apic_update_ppr(apic); - - apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" - "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__, - vcpu, kvm_apic_id(apic), - vcpu->apic_base, apic->base_address); -} -EXPORT_SYMBOL_GPL(kvm_lapic_reset); - -int kvm_lapic_enabled(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic; - int ret = 0; - - if (!apic) - return 0; - ret = apic_enabled(apic); - - return ret; -} -EXPORT_SYMBOL_GPL(kvm_lapic_enabled); - -/* - *---------------------------------------------------------------------- - * timer interface - *---------------------------------------------------------------------- - */ - -/* TODO: make sure __apic_timer_fn runs in current pCPU */ -static int __apic_timer_fn(struct kvm_lapic *apic) -{ - int result = 0; - wait_queue_head_t *q = &apic->vcpu->wq; - - atomic_inc(&apic->timer.pending); - if (waitqueue_active(q)) - { - apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; - wake_up_interruptible(q); - } - if (apic_lvtt_period(apic)) { - result = 1; - apic->timer.dev.expires = ktime_add_ns( - apic->timer.dev.expires, - apic->timer.period); - } - return result; -} - -static int __inject_apic_timer_irq(struct kvm_lapic *apic) -{ - int vector; - - vector = apic_lvt_vector(apic, APIC_LVTT); - return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); -} - -static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) -{ - struct kvm_lapic *apic; - int restart_timer = 0; - - apic = container_of(data, struct kvm_lapic, timer.dev); - - restart_timer = __apic_timer_fn(apic); - - if (restart_timer) - return HRTIMER_RESTART; - else - return HRTIMER_NORESTART; -} - -int kvm_create_lapic(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic; - - ASSERT(vcpu != NULL); - apic_debug("apic_init %d\n", vcpu->vcpu_id); - - apic = kzalloc(sizeof(*apic), GFP_KERNEL); - if (!apic) - goto nomem; - - vcpu->apic = apic; - - apic->regs_page = alloc_page(GFP_KERNEL); - if (apic->regs_page == NULL) { - printk(KERN_ERR "malloc apic regs error for vcpu %x\n", - vcpu->vcpu_id); - goto nomem; - } - apic->regs = page_address(apic->regs_page); - memset(apic->regs, 0, PAGE_SIZE); - apic->vcpu = vcpu; - - hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - apic->timer.dev.function = apic_timer_fn; - apic->base_address = APIC_DEFAULT_PHYS_BASE; - vcpu->apic_base = APIC_DEFAULT_PHYS_BASE; - - kvm_lapic_reset(vcpu); - apic->dev.read = apic_mmio_read; - apic->dev.write = apic_mmio_write; - apic->dev.in_range = apic_mmio_range; - apic->dev.private = apic; - - return 0; -nomem: - kvm_free_apic(apic); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(kvm_create_lapic); - -int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = vcpu->apic; - int highest_irr; - - if (!apic || !apic_enabled(apic)) - return -1; - - apic_update_ppr(apic); - highest_irr = apic_find_highest_irr(apic); - if ((highest_irr == -1) || - ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) - return -1; - return highest_irr; -} - -int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu) -{ - u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0); - int r = 0; - - if (vcpu->vcpu_id == 0) { - if (!apic_hw_enabled(vcpu->apic)) - r = 1; - if ((lvt0 & APIC_LVT_MASKED) == 0 && - GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT) - r = 1; - } - return r; -} - -void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = vcpu->apic; - - if (apic && apic_lvt_enabled(apic, APIC_LVTT) && - atomic_read(&apic->timer.pending) > 0) { - if (__inject_apic_timer_irq(apic)) - atomic_dec(&apic->timer.pending); - } -} - -void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec) -{ - struct kvm_lapic *apic = vcpu->apic; - - if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec) - apic->timer.last_update = ktime_add_ns( - apic->timer.last_update, - apic->timer.period); -} - -int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) -{ - int vector = kvm_apic_has_interrupt(vcpu); - struct kvm_lapic *apic = vcpu->apic; - - if (vector == -1) - return -1; - - apic_set_vector(vector, apic->regs + APIC_ISR); - apic_update_ppr(apic); - apic_clear_irr(vector, apic); - return vector; -} - -void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = vcpu->apic; - - apic->base_address = vcpu->apic_base & - MSR_IA32_APICBASE_BASE; - apic_set_reg(apic, APIC_LVR, APIC_VERSION); - apic_update_ppr(apic); - hrtimer_cancel(&apic->timer.dev); - update_divide_count(apic); - start_apic_timer(apic); -} - -void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = vcpu->apic; - struct hrtimer *timer; - - if (!apic) - return; - - timer = &apic->timer.dev; - if (hrtimer_cancel(timer)) - hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); -} -EXPORT_SYMBOL_GPL(kvm_migrate_apic_timer); diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c deleted file mode 100644 index feb5ac986c5d..000000000000 --- a/drivers/kvm/mmu.c +++ /dev/null @@ -1,1498 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. - * - * MMU support - * - * Copyright (C) 2006 Qumranet, Inc. - * - * Authors: - * Yaniv Kamay <yaniv@qumranet.com> - * Avi Kivity <avi@qumranet.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "vmx.h" -#include "kvm.h" - -#include <linux/types.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/highmem.h> -#include <linux/module.h> - -#include <asm/page.h> -#include <asm/cmpxchg.h> - -#undef MMU_DEBUG - -#undef AUDIT - -#ifdef AUDIT -static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg); -#else -static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} -#endif - -#ifdef MMU_DEBUG - -#define pgprintk(x...) do { if (dbg) printk(x); } while (0) -#define rmap_printk(x...) do { if (dbg) printk(x); } while (0) - -#else - -#define pgprintk(x...) do { } while (0) -#define rmap_printk(x...) do { } while (0) - -#endif - -#if defined(MMU_DEBUG) || defined(AUDIT) -static int dbg = 1; -#endif - -#ifndef MMU_DEBUG -#define ASSERT(x) do { } while (0) -#else -#define ASSERT(x) \ - if (!(x)) { \ - printk(KERN_WARNING "assertion failed %s:%d: %s\n", \ - __FILE__, __LINE__, #x); \ - } -#endif - -#define PT64_PT_BITS 9 -#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS) -#define PT32_PT_BITS 10 -#define PT32_ENT_PER_PAGE (1 << PT32_PT_BITS) - -#define PT_WRITABLE_SHIFT 1 - -#define PT_PRESENT_MASK (1ULL << 0) -#define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) -#define PT_USER_MASK (1ULL << 2) -#define PT_PWT_MASK (1ULL << 3) -#define PT_PCD_MASK (1ULL << 4) -#define PT_ACCESSED_MASK (1ULL << 5) -#define PT_DIRTY_MASK (1ULL << 6) -#define PT_PAGE_SIZE_MASK (1ULL << 7) -#define PT_PAT_MASK (1ULL << 7) -#define PT_GLOBAL_MASK (1ULL << 8) -#define PT64_NX_MASK (1ULL << 63) - -#define PT_PAT_SHIFT 7 -#define PT_DIR_PAT_SHIFT 12 -#define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT) - -#define PT32_DIR_PSE36_SIZE 4 -#define PT32_DIR_PSE36_SHIFT 13 -#define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT) - - -#define PT_FIRST_AVAIL_BITS_SHIFT 9 -#define PT64_SECOND_AVAIL_BITS_SHIFT 52 - -#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) - -#define VALID_PAGE(x) ((x) != INVALID_PAGE) - -#define PT64_LEVEL_BITS 9 - -#define PT64_LEVEL_SHIFT(level) \ - ( PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS ) - -#define PT64_LEVEL_MASK(level) \ - (((1ULL << PT64_LEVEL_BITS) - 1) << PT64_LEVEL_SHIFT(level)) - -#define PT64_INDEX(address, level)\ - (((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1)) - - -#define PT32_LEVEL_BITS 10 - -#define PT32_LEVEL_SHIFT(level) \ - ( PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS ) - -#define PT32_LEVEL_MASK(level) \ - (((1ULL << PT32_LEVEL_BITS) - 1) << PT32_LEVEL_SHIFT(level)) - -#define PT32_INDEX(address, level)\ - (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1)) - - -#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) -#define PT64_DIR_BASE_ADDR_MASK \ - (PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + PT64_LEVEL_BITS)) - 1)) - -#define PT32_BASE_ADDR_MASK PAGE_MASK -#define PT32_DIR_BASE_ADDR_MASK \ - (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1)) - - -#define PFERR_PRESENT_MASK (1U << 0) -#define PFERR_WRITE_MASK (1U << 1) -#define PFERR_USER_MASK (1U << 2) -#define PFERR_FETCH_MASK (1U << 4) - -#define PT64_ROOT_LEVEL 4 -#define PT32_ROOT_LEVEL 2 -#define PT32E_ROOT_LEVEL 3 - -#define PT_DIRECTORY_LEVEL 2 -#define PT_PAGE_TABLE_LEVEL 1 - -#define RMAP_EXT 4 - -struct kvm_rmap_desc { - u64 *shadow_ptes[RMAP_EXT]; - struct kvm_rmap_desc *more; -}; - -static struct kmem_cache *pte_chain_cache; -static struct kmem_cache *rmap_desc_cache; -static struct kmem_cache *mmu_page_header_cache; - -static int is_write_protection(struct kvm_vcpu *vcpu) -{ - return vcpu->cr0 & X86_CR0_WP; -} - -static int is_cpuid_PSE36(void) -{ - return 1; -} - -static int is_nx(struct kvm_vcpu *vcpu) -{ - return vcpu->shadow_efer & EFER_NX; -} - -static int is_present_pte(unsigned long pte) -{ - return pte & PT_PRESENT_MASK; -} - -static int is_writeble_pte(unsigned long pte) -{ - return pte & PT_WRITABLE_MASK; -} - -static int is_io_pte(unsigned long pte) -{ - return pte & PT_SHADOW_IO_MARK; -} - -static int is_rmap_pte(u64 pte) -{ - return (pte & (PT_WRITABLE_MASK | PT_PRESENT_MASK)) - == (PT_WRITABLE_MASK | PT_PRESENT_MASK); -} - -static void set_shadow_pte(u64 *sptep, u64 spte) -{ -#ifdef CONFIG_X86_64 - set_64bit((unsigned long *)sptep, spte); -#else - set_64bit((unsigned long long *)sptep, spte); -#endif -} - -static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache, - struct kmem_cache *base_cache, int min) -{ - void *obj; - - if (cache->nobjs >= min) - return 0; - while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - obj = kmem_cache_zalloc(base_cache, GFP_KERNEL); - if (!obj) - return -ENOMEM; - cache->objects[cache->nobjs++] = obj; - } - return 0; -} - -static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) -{ - while (mc->nobjs) - kfree(mc->objects[--mc->nobjs]); -} - -static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache, - int min) -{ - struct page *page; - - if (cache->nobjs >= min) - return 0; - while (cache->nobjs < ARRAY_SIZE(cache->objects)) { - page = alloc_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - set_page_private(page, 0); - cache->objects[cache->nobjs++] = page_address(page); - } - return 0; -} - -static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc) -{ - while (mc->nobjs) - free_page((unsigned long)mc->objects[--mc->nobjs]); -} - -static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu) -{ - int r; - - kvm_mmu_free_some_pages(vcpu); - r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache, - pte_chain_cache, 4); - if (r) - goto out; - r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache, - rmap_desc_cache, 1); - if (r) - goto out; - r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4); - if (r) - goto out; - r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache, - mmu_page_header_cache, 4); -out: - return r; -} - -static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) -{ - mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache); - mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache); - mmu_free_memory_cache_page(&vcpu->mmu_page_cache); - mmu_free_memory_cache(&vcpu->mmu_page_header_cache); -} - -static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc, - size_t size) -{ - void *p; - - BUG_ON(!mc->nobjs); - p = mc->objects[--mc->nobjs]; - memset(p, 0, size); - return p; -} - -static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu) -{ - return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache, - sizeof(struct kvm_pte_chain)); -} - -static void mmu_free_pte_chain(struct kvm_pte_chain *pc) -{ - kfree(pc); -} - -static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu) -{ - return mmu_memory_cache_alloc(&vcpu->mmu_rmap_desc_cache, - sizeof(struct kvm_rmap_desc)); -} - -static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd) -{ - kfree(rd); -} - -/* - * Reverse mapping data structures: - * - * If page->private bit zero is zero, then page->private points to the - * shadow page table entry that points to page_address(page). - * - * If page->private bit zero is one, (then page->private & ~1) points - * to a struct kvm_rmap_desc containing more mappings. - */ -static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte) -{ - struct page *page; - struct kvm_rmap_desc *desc; - int i; - - if (!is_rmap_pte(*spte)) - return; - page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); - if (!page_private(page)) { - rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); - set_page_private(page,(unsigned long)spte); - } else if (!(page_private(page) & 1)) { - rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); - desc = mmu_alloc_rmap_desc(vcpu); - desc->shadow_ptes[0] = (u64 *)page_private(page); - desc->shadow_ptes[1] = spte; - set_page_private(page,(unsigned long)desc | 1); - } else { - rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); - desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul); - while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) - desc = desc->more; - if (desc->shadow_ptes[RMAP_EXT-1]) { - desc->more = mmu_alloc_rmap_desc(vcpu); - desc = desc->more; - } - for (i = 0; desc->shadow_ptes[i]; ++i) - ; - desc->shadow_ptes[i] = spte; - } -} - -static void rmap_desc_remove_entry(struct page *page, - struct kvm_rmap_desc *desc, - int i, - struct kvm_rmap_desc *prev_desc) -{ - int j; - - for (j = RMAP_EXT - 1; !desc->shadow_ptes[j] && j > i; --j) - ; - desc->shadow_ptes[i] = desc->shadow_ptes[j]; - desc->shadow_ptes[j] = NULL; - if (j != 0) - return; - if (!prev_desc && !desc->more) - set_page_private(page,(unsigned long)desc->shadow_ptes[0]); - else - if (prev_desc) - prev_desc->more = desc->more; - else - set_page_private(page,(unsigned long)desc->more | 1); - mmu_free_rmap_desc(desc); -} - -static void rmap_remove(u64 *spte) -{ - struct page *page; - struct kvm_rmap_desc *desc; - struct kvm_rmap_desc *prev_desc; - int i; - - if (!is_rmap_pte(*spte)) - return; - page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); - if (!page_private(page)) { - printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); - BUG(); - } else if (!(page_private(page) & 1)) { - rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte); - if ((u64 *)page_private(page) != spte) { - printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n", - spte, *spte); - BUG(); - } - set_page_private(page,0); - } else { - rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte); - desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul); - prev_desc = NULL; - while (desc) { - for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) - if (desc->shadow_ptes[i] == spte) { - rmap_desc_remove_entry(page, - desc, i, - prev_desc); - return; - } - prev_desc = desc; - desc = desc->more; - } - BUG(); - } -} - -static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) -{ - struct kvm *kvm = vcpu->kvm; - struct page *page; - struct kvm_rmap_desc *desc; - u64 *spte; - - page = gfn_to_page(kvm, gfn); - BUG_ON(!page); - - while (page_private(page)) { - if (!(page_private(page) & 1)) - spte = (u64 *)page_private(page); - else { - desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul); - spte = desc->shadow_ptes[0]; - } - BUG_ON(!spte); - BUG_ON((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT - != page_to_pfn(page)); - BUG_ON(!(*spte & PT_PRESENT_MASK)); - BUG_ON(!(*spte & PT_WRITABLE_MASK)); - rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte); - rmap_remove(spte); - set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK); - kvm_flush_remote_tlbs(vcpu->kvm); - } -} - -#ifdef MMU_DEBUG -static int is_empty_shadow_page(u64 *spt) -{ - u64 *pos; - u64 *end; - - for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++) - if (*pos != 0) { - printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__, - pos, *pos); - return 0; - } - return 1; -} -#endif - -static void kvm_mmu_free_page(struct kvm *kvm, - struct kvm_mmu_page *page_head) -{ - ASSERT(is_empty_shadow_page(page_head->spt)); - list_del(&page_head->link); - __free_page(virt_to_page(page_head->spt)); - kfree(page_head); - ++kvm->n_free_mmu_pages; -} - -static unsigned kvm_page_table_hashfn(gfn_t gfn) -{ - return gfn; -} - -static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, - u64 *parent_pte) -{ - struct kvm_mmu_page *page; - - if (!vcpu->kvm->n_free_mmu_pages) - return NULL; - - page = mmu_memory_cache_alloc(&vcpu->mmu_page_header_cache, - sizeof *page); - page->spt = mmu_memory_cache_alloc(&vcpu->mmu_page_cache, PAGE_SIZE); - set_page_private(virt_to_page(page->spt), (unsigned long)page); - list_add(&page->link, &vcpu->kvm->active_mmu_pages); - ASSERT(is_empty_shadow_page(page->spt)); - page->slot_bitmap = 0; - page->multimapped = 0; - page->parent_pte = parent_pte; - --vcpu->kvm->n_free_mmu_pages; - return page; -} - -static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *page, u64 *parent_pte) -{ - struct kvm_pte_chain *pte_chain; - struct hlist_node *node; - int i; - - if (!parent_pte) - return; - if (!page->multimapped) { - u64 *old = page->parent_pte; - - if (!old) { - page->parent_pte = parent_pte; - return; - } - page->multimapped = 1; - pte_chain = mmu_alloc_pte_chain(vcpu); - INIT_HLIST_HEAD(&page->parent_ptes); - hlist_add_head(&pte_chain->link, &page->parent_ptes); - pte_chain->parent_ptes[0] = old; - } - hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link) { - if (pte_chain->parent_ptes[NR_PTE_CHAIN_ENTRIES-1]) - continue; - for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) - if (!pte_chain->parent_ptes[i]) { - pte_chain->parent_ptes[i] = parent_pte; - return; - } - } - pte_chain = mmu_alloc_pte_chain(vcpu); - BUG_ON(!pte_chain); - hlist_add_head(&pte_chain->link, &page->parent_ptes); - pte_chain->parent_ptes[0] = parent_pte; -} - -static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page, - u64 *parent_pte) -{ - struct kvm_pte_chain *pte_chain; - struct hlist_node *node; - int i; - - if (!page->multimapped) { - BUG_ON(page->parent_pte != parent_pte); - page->parent_pte = NULL; - return; - } - hlist_for_each_entry(pte_chain, node, &page->parent_ptes, link) - for (i = 0; i < NR_PTE_CHAIN_ENTRIES; ++i) { - if (!pte_chain->parent_ptes[i]) - break; - if (pte_chain->parent_ptes[i] != parent_pte) - continue; - while (i + 1 < NR_PTE_CHAIN_ENTRIES - && pte_chain->parent_ptes[i + 1]) { - pte_chain->parent_ptes[i] - = pte_chain->parent_ptes[i + 1]; - ++i; - } - pte_chain->parent_ptes[i] = NULL; - if (i == 0) { - hlist_del(&pte_chain->link); - mmu_free_pte_chain(pte_chain); - if (hlist_empty(&page->parent_ptes)) { - page->multimapped = 0; - page->parent_pte = NULL; - } - } - return; - } - BUG(); -} - -static struct kvm_mmu_page *kvm_mmu_lookup_page(struct kvm_vcpu *vcpu, - gfn_t gfn) -{ - unsigned index; - struct hlist_head *bucket; - struct kvm_mmu_page *page; - struct hlist_node *node; - - pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); - index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; - bucket = &vcpu->kvm->mmu_page_hash[index]; - hlist_for_each_entry(page, node, bucket, hash_link) - if (page->gfn == gfn && !page->role.metaphysical) { - pgprintk("%s: found role %x\n", - __FUNCTION__, page->role.word); - return page; - } - return NULL; -} - -static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, - gfn_t gfn, - gva_t gaddr, - unsigned level, - int metaphysical, - unsigned hugepage_access, - u64 *parent_pte) -{ - union kvm_mmu_page_role role; - unsigned index; - unsigned quadrant; - struct hlist_head *bucket; - struct kvm_mmu_page *page; - struct hlist_node *node; - - role.word = 0; - role.glevels = vcpu->mmu.root_level; - role.level = level; - role.metaphysical = metaphysical; - role.hugepage_access = hugepage_access; - if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) { - quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); - quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; - role.quadrant = quadrant; - } - pgprintk("%s: looking gfn %lx role %x\n", __FUNCTION__, - gfn, role.word); - index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; - bucket = &vcpu->kvm->mmu_page_hash[index]; - hlist_for_each_entry(page, node, bucket, hash_link) - if (page->gfn == gfn && page->role.word == role.word) { - mmu_page_add_parent_pte(vcpu, page, parent_pte); - pgprintk("%s: found\n", __FUNCTION__); - return page; - } - page = kvm_mmu_alloc_page(vcpu, parent_pte); - if (!page) - return page; - pgprintk("%s: adding gfn %lx role %x\n", __FUNCTION__, gfn, role.word); - page->gfn = gfn; - page->role = role; - hlist_add_head(&page->hash_link, bucket); - if (!metaphysical) - rmap_write_protect(vcpu, gfn); - return page; -} - -static void kvm_mmu_page_unlink_children(struct kvm *kvm, - struct kvm_mmu_page *page) -{ - unsigned i; - u64 *pt; - u64 ent; - - pt = page->spt; - - if (page->role.level == PT_PAGE_TABLE_LEVEL) { - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { - if (pt[i] & PT_PRESENT_MASK) - rmap_remove(&pt[i]); - pt[i] = 0; - } - kvm_flush_remote_tlbs(kvm); - return; - } - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { - ent = pt[i]; - - pt[i] = 0; - if (!(ent & PT_PRESENT_MASK)) - continue; - ent &= PT64_BASE_ADDR_MASK; - mmu_page_remove_parent_pte(page_header(ent), &pt[i]); - } - kvm_flush_remote_tlbs(kvm); -} - -static void kvm_mmu_put_page(struct kvm_mmu_page *page, - u64 *parent_pte) -{ - mmu_page_remove_parent_pte(page, parent_pte); -} - -static void kvm_mmu_zap_page(struct kvm *kvm, - struct kvm_mmu_page *page) -{ - u64 *parent_pte; - - while (page->multimapped || page->parent_pte) { - if (!page->multimapped) - parent_pte = page->parent_pte; - else { - struct kvm_pte_chain *chain; - - chain = container_of(page->parent_ptes.first, - struct kvm_pte_chain, link); - parent_pte = chain->parent_ptes[0]; - } - BUG_ON(!parent_pte); - kvm_mmu_put_page(page, parent_pte); - set_shadow_pte(parent_pte, 0); - } - kvm_mmu_page_unlink_children(kvm, page); - if (!page->root_count) { - hlist_del(&page->hash_link); - kvm_mmu_free_page(kvm, page); - } else - list_move(&page->link, &kvm->active_mmu_pages); -} - -static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - unsigned index; - struct hlist_head *bucket; - struct kvm_mmu_page *page; - struct hlist_node *node, *n; - int r; - - pgprintk("%s: looking for gfn %lx\n", __FUNCTION__, gfn); - r = 0; - index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; - bucket = &vcpu->kvm->mmu_page_hash[index]; - hlist_for_each_entry_safe(page, node, n, bucket, hash_link) - if (page->gfn == gfn && !page->role.metaphysical) { - pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn, - page->role.word); - kvm_mmu_zap_page(vcpu->kvm, page); - r = 1; - } - return r; -} - -static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - struct kvm_mmu_page *page; - - while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) { - pgprintk("%s: zap %lx %x\n", - __FUNCTION__, gfn, page->role.word); - kvm_mmu_zap_page(vcpu->kvm, page); - } -} - -static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa) -{ - int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT)); - struct kvm_mmu_page *page_head = page_header(__pa(pte)); - - __set_bit(slot, &page_head->slot_bitmap); -} - -hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa) -{ - hpa_t hpa = gpa_to_hpa(vcpu, gpa); - - return is_error_hpa(hpa) ? bad_page_address | (gpa & ~PAGE_MASK): hpa; -} - -hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa) -{ - struct page *page; - - ASSERT((gpa & HPA_ERR_MASK) == 0); - page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT); - if (!page) - return gpa | HPA_ERR_MASK; - return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT) - | (gpa & (PAGE_SIZE-1)); -} - -hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva) -{ - gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); - - if (gpa == UNMAPPED_GVA) - return UNMAPPED_GVA; - return gpa_to_hpa(vcpu, gpa); -} - -struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva) -{ - gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); - - if (gpa == UNMAPPED_GVA) - return NULL; - return pfn_to_page(gpa_to_hpa(vcpu, gpa) >> PAGE_SHIFT); -} - -static void nonpaging_new_cr3(struct kvm_vcpu *vcpu) -{ -} - -static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p) -{ - int level = PT32E_ROOT_LEVEL; - hpa_t table_addr = vcpu->mmu.root_hpa; - - for (; ; level--) { - u32 index = PT64_INDEX(v, level); - u64 *table; - u64 pte; - - ASSERT(VALID_PAGE(table_addr)); - table = __va(table_addr); - - if (level == 1) { - pte = table[index]; - if (is_present_pte(pte) && is_writeble_pte(pte)) - return 0; - mark_page_dirty(vcpu->kvm, v >> PAGE_SHIFT); - page_header_update_slot(vcpu->kvm, table, v); - table[index] = p | PT_PRESENT_MASK | PT_WRITABLE_MASK | - PT_USER_MASK; - rmap_add(vcpu, &table[index]); - return 0; - } - - if (table[index] == 0) { - struct kvm_mmu_page *new_table; - gfn_t pseudo_gfn; - - pseudo_gfn = (v & PT64_DIR_BASE_ADDR_MASK) - >> PAGE_SHIFT; - new_table = kvm_mmu_get_page(vcpu, pseudo_gfn, - v, level - 1, - 1, 0, &table[index]); - if (!new_table) { - pgprintk("nonpaging_map: ENOMEM\n"); - return -ENOMEM; - } - - table[index] = __pa(new_table->spt) | PT_PRESENT_MASK - | PT_WRITABLE_MASK | PT_USER_MASK; - } - table_addr = table[index] & PT64_BASE_ADDR_MASK; - } -} - -static void mmu_free_roots(struct kvm_vcpu *vcpu) -{ - int i; - struct kvm_mmu_page *page; - - if (!VALID_PAGE(vcpu->mmu.root_hpa)) - return; -#ifdef CONFIG_X86_64 - if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) { - hpa_t root = vcpu->mmu.root_hpa; - - page = page_header(root); - --page->root_count; - vcpu->mmu.root_hpa = INVALID_PAGE; - return; - } -#endif - for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->mmu.pae_root[i]; - - if (root) { - root &= PT64_BASE_ADDR_MASK; - page = page_header(root); - --page->root_count; - } - vcpu->mmu.pae_root[i] = INVALID_PAGE; - } - vcpu->mmu.root_hpa = INVALID_PAGE; -} - -static void mmu_alloc_roots(struct kvm_vcpu *vcpu) -{ - int i; - gfn_t root_gfn; - struct kvm_mmu_page *page; - - root_gfn = vcpu->cr3 >> PAGE_SHIFT; - -#ifdef CONFIG_X86_64 - if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) { - hpa_t root = vcpu->mmu.root_hpa; - - ASSERT(!VALID_PAGE(root)); - page = kvm_mmu_get_page(vcpu, root_gfn, 0, - PT64_ROOT_LEVEL, 0, 0, NULL); - root = __pa(page->spt); - ++page->root_count; - vcpu->mmu.root_hpa = root; - return; - } -#endif - for (i = 0; i < 4; ++i) { - hpa_t root = vcpu->mmu.pae_root[i]; - - ASSERT(!VALID_PAGE(root)); - if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) { - if (!is_present_pte(vcpu->pdptrs[i])) { - vcpu->mmu.pae_root[i] = 0; - continue; - } - root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT; - } else if (vcpu->mmu.root_level == 0) - root_gfn = 0; - page = kvm_mmu_get_page(vcpu, root_gfn, i << 30, - PT32_ROOT_LEVEL, !is_paging(vcpu), - 0, NULL); - root = __pa(page->spt); - ++page->root_count; - vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK; - } - vcpu->mmu.root_hpa = __pa(vcpu->mmu.pae_root); -} - -static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t vaddr) -{ - return vaddr; -} - -static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva, - u32 error_code) -{ - gpa_t addr = gva; - hpa_t paddr; - int r; - - r = mmu_topup_memory_caches(vcpu); - if (r) - return r; - - ASSERT(vcpu); - ASSERT(VALID_PAGE(vcpu->mmu.root_hpa)); - - - paddr = gpa_to_hpa(vcpu , addr & PT64_BASE_ADDR_MASK); - - if (is_error_hpa(paddr)) - return 1; - - return nonpaging_map(vcpu, addr & PAGE_MASK, paddr); -} - -static void nonpaging_free(struct kvm_vcpu *vcpu) -{ - mmu_free_roots(vcpu); -} - -static int nonpaging_init_context(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu *context = &vcpu->mmu; - - context->new_cr3 = nonpaging_new_cr3; - context->page_fault = nonpaging_page_fault; - context->gva_to_gpa = nonpaging_gva_to_gpa; - context->free = nonpaging_free; - context->root_level = 0; - context->shadow_root_level = PT32E_ROOT_LEVEL; - context->root_hpa = INVALID_PAGE; - return 0; -} - -static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu) -{ - ++vcpu->stat.tlb_flush; - kvm_x86_ops->tlb_flush(vcpu); -} - -static void paging_new_cr3(struct kvm_vcpu *vcpu) -{ - pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3); - mmu_free_roots(vcpu); -} - -static void inject_page_fault(struct kvm_vcpu *vcpu, - u64 addr, - u32 err_code) -{ - kvm_x86_ops->inject_page_fault(vcpu, addr, err_code); -} - -static void paging_free(struct kvm_vcpu *vcpu) -{ - nonpaging_free(vcpu); -} - -#define PTTYPE 64 -#include "paging_tmpl.h" -#undef PTTYPE - -#define PTTYPE 32 -#include "paging_tmpl.h" -#undef PTTYPE - -static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level) -{ - struct kvm_mmu *context = &vcpu->mmu; - - ASSERT(is_pae(vcpu)); - context->new_cr3 = paging_new_cr3; - context->page_fault = paging64_page_fault; - context->gva_to_gpa = paging64_gva_to_gpa; - context->free = paging_free; - context->root_level = level; - context->shadow_root_level = level; - context->root_hpa = INVALID_PAGE; - return 0; -} - -static int paging64_init_context(struct kvm_vcpu *vcpu) -{ - return paging64_init_context_common(vcpu, PT64_ROOT_LEVEL); -} - -static int paging32_init_context(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu *context = &vcpu->mmu; - - context->new_cr3 = paging_new_cr3; - context->page_fault = paging32_page_fault; - context->gva_to_gpa = paging32_gva_to_gpa; - context->free = paging_free; - context->root_level = PT32_ROOT_LEVEL; - context->shadow_root_level = PT32E_ROOT_LEVEL; - context->root_hpa = INVALID_PAGE; - return 0; -} - -static int paging32E_init_context(struct kvm_vcpu *vcpu) -{ - return paging64_init_context_common(vcpu, PT32E_ROOT_LEVEL); -} - -static int init_kvm_mmu(struct kvm_vcpu *vcpu) -{ - ASSERT(vcpu); - ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); - - if (!is_paging(vcpu)) - return nonpaging_init_context(vcpu); - else if (is_long_mode(vcpu)) - return paging64_init_context(vcpu); - else if (is_pae(vcpu)) - return paging32E_init_context(vcpu); - else - return paging32_init_context(vcpu); -} - -static void destroy_kvm_mmu(struct kvm_vcpu *vcpu) -{ - ASSERT(vcpu); - if (VALID_PAGE(vcpu->mmu.root_hpa)) { - vcpu->mmu.free(vcpu); - vcpu->mmu.root_hpa = INVALID_PAGE; - } -} - -int kvm_mmu_reset_context(struct kvm_vcpu *vcpu) -{ - destroy_kvm_mmu(vcpu); - return init_kvm_mmu(vcpu); -} -EXPORT_SYMBOL_GPL(kvm_mmu_reset_context); - -int kvm_mmu_load(struct kvm_vcpu *vcpu) -{ - int r; - - mutex_lock(&vcpu->kvm->lock); - r = mmu_topup_memory_caches(vcpu); - if (r) - goto out; - mmu_alloc_roots(vcpu); - kvm_x86_ops->set_cr3(vcpu, vcpu->mmu.root_hpa); - kvm_mmu_flush_tlb(vcpu); -out: - mutex_unlock(&vcpu->kvm->lock); - return r; -} -EXPORT_SYMBOL_GPL(kvm_mmu_load); - -void kvm_mmu_unload(struct kvm_vcpu *vcpu) -{ - mmu_free_roots(vcpu); -} - -static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *page, - u64 *spte) -{ - u64 pte; - struct kvm_mmu_page *child; - - pte = *spte; - if (is_present_pte(pte)) { - if (page->role.level == PT_PAGE_TABLE_LEVEL) - rmap_remove(spte); - else { - child = page_header(pte & PT64_BASE_ADDR_MASK); - mmu_page_remove_parent_pte(child, spte); - } - } - set_shadow_pte(spte, 0); - kvm_flush_remote_tlbs(vcpu->kvm); -} - -static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu, - struct kvm_mmu_page *page, - u64 *spte, - const void *new, int bytes) -{ - if (page->role.level != PT_PAGE_TABLE_LEVEL) - return; - - if (page->role.glevels == PT32_ROOT_LEVEL) - paging32_update_pte(vcpu, page, spte, new, bytes); - else - paging64_update_pte(vcpu, page, spte, new, bytes); -} - -void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, - const u8 *new, int bytes) -{ - gfn_t gfn = gpa >> PAGE_SHIFT; - struct kvm_mmu_page *page; - struct hlist_node *node, *n; - struct hlist_head *bucket; - unsigned index; - u64 *spte; - unsigned offset = offset_in_page(gpa); - unsigned pte_size; - unsigned page_offset; - unsigned misaligned; - unsigned quadrant; - int level; - int flooded = 0; - int npte; - - pgprintk("%s: gpa %llx bytes %d\n", __FUNCTION__, gpa, bytes); - if (gfn == vcpu->last_pt_write_gfn) { - ++vcpu->last_pt_write_count; - if (vcpu->last_pt_write_count >= 3) - flooded = 1; - } else { - vcpu->last_pt_write_gfn = gfn; - vcpu->last_pt_write_count = 1; - } - index = kvm_page_table_hashfn(gfn) % KVM_NUM_MMU_PAGES; - bucket = &vcpu->kvm->mmu_page_hash[index]; - hlist_for_each_entry_safe(page, node, n, bucket, hash_link) { - if (page->gfn != gfn || page->role.metaphysical) - continue; - pte_size = page->role.glevels == PT32_ROOT_LEVEL ? 4 : 8; - misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1); - misaligned |= bytes < 4; - if (misaligned || flooded) { - /* - * Misaligned accesses are too much trouble to fix - * up; also, they usually indicate a page is not used - * as a page table. - * - * If we're seeing too many writes to a page, - * it may no longer be a page table, or we may be - * forking, in which case it is better to unmap the - * page. - */ - pgprintk("misaligned: gpa %llx bytes %d role %x\n", - gpa, bytes, page->role.word); - kvm_mmu_zap_page(vcpu->kvm, page); - continue; - } - page_offset = offset; - level = page->role.level; - npte = 1; - if (page->role.glevels == PT32_ROOT_LEVEL) { - page_offset <<= 1; /* 32->64 */ - /* - * A 32-bit pde maps 4MB while the shadow pdes map - * only 2MB. So we need to double the offset again - * and zap two pdes instead of one. - */ - if (level == PT32_ROOT_LEVEL) { - page_offset &= ~7; /* kill rounding error */ - page_offset <<= 1; - npte = 2; - } - quadrant = page_offset >> PAGE_SHIFT; - page_offset &= ~PAGE_MASK; - if (quadrant != page->role.quadrant) - continue; - } - spte = &page->spt[page_offset / sizeof(*spte)]; - while (npte--) { - mmu_pte_write_zap_pte(vcpu, page, spte); - mmu_pte_write_new_pte(vcpu, page, spte, new, bytes); - ++spte; - } - } -} - -int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva) -{ - gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva); - - return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT); -} - -void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) -{ - while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) { - struct kvm_mmu_page *page; - - page = container_of(vcpu->kvm->active_mmu_pages.prev, - struct kvm_mmu_page, link); - kvm_mmu_zap_page(vcpu->kvm, page); - } -} - -static void free_mmu_pages(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu_page *page; - - while (!list_empty(&vcpu->kvm->active_mmu_pages)) { - page = container_of(vcpu->kvm->active_mmu_pages.next, - struct kvm_mmu_page, link); - kvm_mmu_zap_page(vcpu->kvm, page); - } - free_page((unsigned long)vcpu->mmu.pae_root); -} - -static int alloc_mmu_pages(struct kvm_vcpu *vcpu) -{ - struct page *page; - int i; - - ASSERT(vcpu); - - vcpu->kvm->n_free_mmu_pages = KVM_NUM_MMU_PAGES; - - /* - * When emulating 32-bit mode, cr3 is only 32 bits even on x86_64. - * Therefore we need to allocate shadow page tables in the first - * 4GB of memory, which happens to fit the DMA32 zone. - */ - page = alloc_page(GFP_KERNEL | __GFP_DMA32); - if (!page) - goto error_1; - vcpu->mmu.pae_root = page_address(page); - for (i = 0; i < 4; ++i) - vcpu->mmu.pae_root[i] = INVALID_PAGE; - - return 0; - -error_1: - free_mmu_pages(vcpu); - return -ENOMEM; -} - -int kvm_mmu_create(struct kvm_vcpu *vcpu) -{ - ASSERT(vcpu); - ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); - - return alloc_mmu_pages(vcpu); -} - -int kvm_mmu_setup(struct kvm_vcpu *vcpu) -{ - ASSERT(vcpu); - ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa)); - - return init_kvm_mmu(vcpu); -} - -void kvm_mmu_destroy(struct kvm_vcpu *vcpu) -{ - ASSERT(vcpu); - - destroy_kvm_mmu(vcpu); - free_mmu_pages(vcpu); - mmu_free_memory_caches(vcpu); -} - -void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot) -{ - struct kvm_mmu_page *page; - - list_for_each_entry(page, &kvm->active_mmu_pages, link) { - int i; - u64 *pt; - - if (!test_bit(slot, &page->slot_bitmap)) - continue; - - pt = page->spt; - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) - /* avoid RMW */ - if (pt[i] & PT_WRITABLE_MASK) { - rmap_remove(&pt[i]); - pt[i] &= ~PT_WRITABLE_MASK; - } - } -} - -void kvm_mmu_zap_all(struct kvm *kvm) -{ - struct kvm_mmu_page *page, *node; - - list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link) - kvm_mmu_zap_page(kvm, page); - - kvm_flush_remote_tlbs(kvm); -} - -void kvm_mmu_module_exit(void) -{ - if (pte_chain_cache) - kmem_cache_destroy(pte_chain_cache); - if (rmap_desc_cache) - kmem_cache_destroy(rmap_desc_cache); - if (mmu_page_header_cache) - kmem_cache_destroy(mmu_page_header_cache); -} - -int kvm_mmu_module_init(void) -{ - pte_chain_cache = kmem_cache_create("kvm_pte_chain", - sizeof(struct kvm_pte_chain), - 0, 0, NULL); - if (!pte_chain_cache) - goto nomem; - rmap_desc_cache = kmem_cache_create("kvm_rmap_desc", - sizeof(struct kvm_rmap_desc), - 0, 0, NULL); - if (!rmap_desc_cache) - goto nomem; - - mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header", - sizeof(struct kvm_mmu_page), - 0, 0, NULL); - if (!mmu_page_header_cache) - goto nomem; - - return 0; - -nomem: - kvm_mmu_module_exit(); - return -ENOMEM; -} - -#ifdef AUDIT - -static const char *audit_msg; - -static gva_t canonicalize(gva_t gva) -{ -#ifdef CONFIG_X86_64 - gva = (long long)(gva << 16) >> 16; -#endif - return gva; -} - -static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte, - gva_t va, int level) -{ - u64 *pt = __va(page_pte & PT64_BASE_ADDR_MASK); - int i; - gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { - u64 ent = pt[i]; - - if (!(ent & PT_PRESENT_MASK)) - continue; - - va = canonicalize(va); - if (level > 1) - audit_mappings_page(vcpu, ent, va, level - 1); - else { - gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, va); - hpa_t hpa = gpa_to_hpa(vcpu, gpa); - - if ((ent & PT_PRESENT_MASK) - && (ent & PT64_BASE_ADDR_MASK) != hpa) - printk(KERN_ERR "audit error: (%s) levels %d" - " gva %lx gpa %llx hpa %llx ent %llx\n", - audit_msg, vcpu->mmu.root_level, - va, gpa, hpa, ent); - } - } -} - -static void audit_mappings(struct kvm_vcpu *vcpu) -{ - unsigned i; - - if (vcpu->mmu.root_level == 4) - audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4); - else - for (i = 0; i < 4; ++i) - if (vcpu->mmu.pae_root[i] & PT_PRESENT_MASK) - audit_mappings_page(vcpu, - vcpu->mmu.pae_root[i], - i << 30, - 2); -} - -static int count_rmaps(struct kvm_vcpu *vcpu) -{ - int nmaps = 0; - int i, j, k; - - for (i = 0; i < KVM_MEMORY_SLOTS; ++i) { - struct kvm_memory_slot *m = &vcpu->kvm->memslots[i]; - struct kvm_rmap_desc *d; - - for (j = 0; j < m->npages; ++j) { - struct page *page = m->phys_mem[j]; - - if (!page->private) - continue; - if (!(page->private & 1)) { - ++nmaps; - continue; - } - d = (struct kvm_rmap_desc *)(page->private & ~1ul); - while (d) { - for (k = 0; k < RMAP_EXT; ++k) - if (d->shadow_ptes[k]) - ++nmaps; - else - break; - d = d->more; - } - } - } - return nmaps; -} - -static int count_writable_mappings(struct kvm_vcpu *vcpu) -{ - int nmaps = 0; - struct kvm_mmu_page *page; - int i; - - list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) { - u64 *pt = page->spt; - - if (page->role.level != PT_PAGE_TABLE_LEVEL) - continue; - - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { - u64 ent = pt[i]; - - if (!(ent & PT_PRESENT_MASK)) - continue; - if (!(ent & PT_WRITABLE_MASK)) - continue; - ++nmaps; - } - } - return nmaps; -} - -static void audit_rmap(struct kvm_vcpu *vcpu) -{ - int n_rmap = count_rmaps(vcpu); - int n_actual = count_writable_mappings(vcpu); - - if (n_rmap != n_actual) - printk(KERN_ERR "%s: (%s) rmap %d actual %d\n", - __FUNCTION__, audit_msg, n_rmap, n_actual); -} - -static void audit_write_protection(struct kvm_vcpu *vcpu) -{ - struct kvm_mmu_page *page; - - list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) { - hfn_t hfn; - struct page *pg; - - if (page->role.metaphysical) - continue; - - hfn = gpa_to_hpa(vcpu, (gpa_t)page->gfn << PAGE_SHIFT) - >> PAGE_SHIFT; - pg = pfn_to_page(hfn); - if (pg->private) - printk(KERN_ERR "%s: (%s) shadow page has writable" - " mappings: gfn %lx role %x\n", - __FUNCTION__, audit_msg, page->gfn, - page->role.word); - } -} - -static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) -{ - int olddbg = dbg; - - dbg = 0; - audit_msg = msg; - audit_rmap(vcpu); - audit_write_protection(vcpu); - audit_mappings(vcpu); - dbg = olddbg; -} - -#endif diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h deleted file mode 100644 index 6b094b44f8fb..000000000000 --- a/drivers/kvm/paging_tmpl.h +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. - * - * MMU support - * - * Copyright (C) 2006 Qumranet, Inc. - * - * Authors: - * Yaniv Kamay <yaniv@qumranet.com> - * Avi Kivity <avi@qumranet.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -/* - * We need the mmu code to access both 32-bit and 64-bit guest ptes, - * so the code in this file is compiled twice, once per pte size. - */ - -#if PTTYPE == 64 - #define pt_element_t u64 - #define guest_walker guest_walker64 - #define FNAME(name) paging##64_##name - #define PT_BASE_ADDR_MASK PT64_BASE_ADDR_MASK - #define PT_DIR_BASE_ADDR_MASK PT64_DIR_BASE_ADDR_MASK - #define PT_INDEX(addr, level) PT64_INDEX(addr, level) - #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) - #define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level) - #ifdef CONFIG_X86_64 - #define PT_MAX_FULL_LEVELS 4 - #else - #define PT_MAX_FULL_LEVELS 2 - #endif -#elif PTTYPE == 32 - #define pt_element_t u32 - #define guest_walker guest_walker32 - #define FNAME(name) paging##32_##name - #define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK - #define PT_DIR_BASE_ADDR_MASK PT32_DIR_BASE_ADDR_MASK - #define PT_INDEX(addr, level) PT32_INDEX(addr, level) - #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) - #define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level) - #define PT_MAX_FULL_LEVELS 2 -#else - #error Invalid PTTYPE value -#endif - -/* - * The guest_walker structure emulates the behavior of the hardware page - * table walker. - */ -struct guest_walker { - int level; - gfn_t table_gfn[PT_MAX_FULL_LEVELS]; - pt_element_t *table; - pt_element_t pte; - pt_element_t *ptep; - struct page *page; - int index; - pt_element_t inherited_ar; - gfn_t gfn; - u32 error_code; -}; - -/* - * Fetch a guest pte for a guest virtual address - */ -static int FNAME(walk_addr)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, gva_t addr, - int write_fault, int user_fault, int fetch_fault) -{ - hpa_t hpa; - struct kvm_memory_slot *slot; - pt_element_t *ptep; - pt_element_t root; - gfn_t table_gfn; - - pgprintk("%s: addr %lx\n", __FUNCTION__, addr); - walker->level = vcpu->mmu.root_level; - walker->table = NULL; - walker->page = NULL; - walker->ptep = NULL; - root = vcpu->cr3; -#if PTTYPE == 64 - if (!is_long_mode(vcpu)) { - walker->ptep = &vcpu->pdptrs[(addr >> 30) & 3]; - root = *walker->ptep; - walker->pte = root; - if (!(root & PT_PRESENT_MASK)) - goto not_present; - --walker->level; - } -#endif - table_gfn = (root & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; - walker->table_gfn[walker->level - 1] = table_gfn; - pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, - walker->level - 1, table_gfn); - slot = gfn_to_memslot(vcpu->kvm, table_gfn); - hpa = safe_gpa_to_hpa(vcpu, root & PT64_BASE_ADDR_MASK); - walker->page = pfn_to_page(hpa >> PAGE_SHIFT); - walker->table = kmap_atomic(walker->page, KM_USER0); - - ASSERT((!is_long_mode(vcpu) && is_pae(vcpu)) || - (vcpu->cr3 & CR3_NONPAE_RESERVED_BITS) == 0); - - walker->inherited_ar = PT_USER_MASK | PT_WRITABLE_MASK; - - for (;;) { - int index = PT_INDEX(addr, walker->level); - hpa_t paddr; - - ptep = &walker->table[index]; - walker->index = index; - ASSERT(((unsigned long)walker->table & PAGE_MASK) == - ((unsigned long)ptep & PAGE_MASK)); - - if (!is_present_pte(*ptep)) - goto not_present; - - if (write_fault && !is_writeble_pte(*ptep)) - if (user_fault || is_write_protection(vcpu)) - goto access_error; - - if (user_fault && !(*ptep & PT_USER_MASK)) - goto access_error; - -#if PTTYPE == 64 - if (fetch_fault && is_nx(vcpu) && (*ptep & PT64_NX_MASK)) - goto access_error; -#endif - - if (!(*ptep & PT_ACCESSED_MASK)) { - mark_page_dirty(vcpu->kvm, table_gfn); - *ptep |= PT_ACCESSED_MASK; - } - - if (walker->level == PT_PAGE_TABLE_LEVEL) { - walker->gfn = (*ptep & PT_BASE_ADDR_MASK) - >> PAGE_SHIFT; - break; - } - - if (walker->level == PT_DIRECTORY_LEVEL - && (*ptep & PT_PAGE_SIZE_MASK) - && (PTTYPE == 64 || is_pse(vcpu))) { - walker->gfn = (*ptep & PT_DIR_BASE_ADDR_MASK) - >> PAGE_SHIFT; - walker->gfn += PT_INDEX(addr, PT_PAGE_TABLE_LEVEL); - break; - } - - walker->inherited_ar &= walker->table[index]; - table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT; - kunmap_atomic(walker->table, KM_USER0); - paddr = safe_gpa_to_hpa(vcpu, table_gfn << PAGE_SHIFT); - walker->page = pfn_to_page(paddr >> PAGE_SHIFT); - walker->table = kmap_atomic(walker->page, KM_USER0); - --walker->level; - walker->table_gfn[walker->level - 1 ] = table_gfn; - pgprintk("%s: table_gfn[%d] %lx\n", __FUNCTION__, - walker->level - 1, table_gfn); - } - walker->pte = *ptep; - if (walker->page) - walker->ptep = NULL; - if (walker->table) - kunmap_atomic(walker->table, KM_USER0); - pgprintk("%s: pte %llx\n", __FUNCTION__, (u64)*ptep); - return 1; - -not_present: - walker->error_code = 0; - goto err; - -access_error: - walker->error_code = PFERR_PRESENT_MASK; - -err: - if (write_fault) - walker->error_code |= PFERR_WRITE_MASK; - if (user_fault) - walker->error_code |= PFERR_USER_MASK; - if (fetch_fault) - walker->error_code |= PFERR_FETCH_MASK; - if (walker->table) - kunmap_atomic(walker->table, KM_USER0); - return 0; -} - -static void FNAME(mark_pagetable_dirty)(struct kvm *kvm, - struct guest_walker *walker) -{ - mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]); -} - -static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu, - u64 *shadow_pte, - gpa_t gaddr, - pt_element_t gpte, - u64 access_bits, - int user_fault, - int write_fault, - int *ptwrite, - struct guest_walker *walker, - gfn_t gfn) -{ - hpa_t paddr; - int dirty = gpte & PT_DIRTY_MASK; - u64 spte = *shadow_pte; - int was_rmapped = is_rmap_pte(spte); - - pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d" - " user_fault %d gfn %lx\n", - __FUNCTION__, spte, (u64)gpte, access_bits, - write_fault, user_fault, gfn); - - if (write_fault && !dirty) { - pt_element_t *guest_ent, *tmp = NULL; - - if (walker->ptep) - guest_ent = walker->ptep; - else { - tmp = kmap_atomic(walker->page, KM_USER0); - guest_ent = &tmp[walker->index]; - } - - *guest_ent |= PT_DIRTY_MASK; - if (!walker->ptep) - kunmap_atomic(tmp, KM_USER0); - dirty = 1; - FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); - } - - spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK; - spte |= gpte & PT64_NX_MASK; - if (!dirty) - access_bits &= ~PT_WRITABLE_MASK; - - paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK); - - spte |= PT_PRESENT_MASK; - if (access_bits & PT_USER_MASK) - spte |= PT_USER_MASK; - - if (is_error_hpa(paddr)) { - spte |= gaddr; - spte |= PT_SHADOW_IO_MARK; - spte &= ~PT_PRESENT_MASK; - set_shadow_pte(shadow_pte, spte); - return; - } - - spte |= paddr; - - if ((access_bits & PT_WRITABLE_MASK) - || (write_fault && !is_write_protection(vcpu) && !user_fault)) { - struct kvm_mmu_page *shadow; - - spte |= PT_WRITABLE_MASK; - if (user_fault) { - mmu_unshadow(vcpu, gfn); - goto unshadowed; - } - - shadow = kvm_mmu_lookup_page(vcpu, gfn); - if (shadow) { - pgprintk("%s: found shadow page for %lx, marking ro\n", - __FUNCTION__, gfn); - access_bits &= ~PT_WRITABLE_MASK; - if (is_writeble_pte(spte)) { - spte &= ~PT_WRITABLE_MASK; - kvm_x86_ops->tlb_flush(vcpu); - } - if (write_fault) - *ptwrite = 1; - } - } - -unshadowed: - - if (access_bits & PT_WRITABLE_MASK) - mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT); - - set_shadow_pte(shadow_pte, spte); - page_header_update_slot(vcpu->kvm, shadow_pte, gaddr); - if (!was_rmapped) - rmap_add(vcpu, shadow_pte); -} - -static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t gpte, - u64 *shadow_pte, u64 access_bits, - int user_fault, int write_fault, int *ptwrite, - struct guest_walker *walker, gfn_t gfn) -{ - access_bits &= gpte; - FNAME(set_pte_common)(vcpu, shadow_pte, gpte & PT_BASE_ADDR_MASK, - gpte, access_bits, user_fault, write_fault, - ptwrite, walker, gfn); -} - -static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, - u64 *spte, const void *pte, int bytes) -{ - pt_element_t gpte; - - if (bytes < sizeof(pt_element_t)) - return; - gpte = *(const pt_element_t *)pte; - if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK)) - return; - pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte); - FNAME(set_pte)(vcpu, gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0, - 0, NULL, NULL, - (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT); -} - -static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t gpde, - u64 *shadow_pte, u64 access_bits, - int user_fault, int write_fault, int *ptwrite, - struct guest_walker *walker, gfn_t gfn) -{ - gpa_t gaddr; - - access_bits &= gpde; - gaddr = (gpa_t)gfn << PAGE_SHIFT; - if (PTTYPE == 32 && is_cpuid_PSE36()) - gaddr |= (gpde & PT32_DIR_PSE36_MASK) << - (32 - PT32_DIR_PSE36_SHIFT); - FNAME(set_pte_common)(vcpu, shadow_pte, gaddr, - gpde, access_bits, user_fault, write_fault, - ptwrite, walker, gfn); -} - -/* - * Fetch a shadow pte for a specific level in the paging hierarchy. - */ -static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, - struct guest_walker *walker, - int user_fault, int write_fault, int *ptwrite) -{ - hpa_t shadow_addr; - int level; - u64 *shadow_ent; - u64 *prev_shadow_ent = NULL; - - if (!is_present_pte(walker->pte)) - return NULL; - - shadow_addr = vcpu->mmu.root_hpa; - level = vcpu->mmu.shadow_root_level; - if (level == PT32E_ROOT_LEVEL) { - shadow_addr = vcpu->mmu.pae_root[(addr >> 30) & 3]; - shadow_addr &= PT64_BASE_ADDR_MASK; - --level; - } - - for (; ; level--) { - u32 index = SHADOW_PT_INDEX(addr, level); - struct kvm_mmu_page *shadow_page; - u64 shadow_pte; - int metaphysical; - gfn_t table_gfn; - unsigned hugepage_access = 0; - - shadow_ent = ((u64 *)__va(shadow_addr)) + index; - if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) { - if (level == PT_PAGE_TABLE_LEVEL) - break; - shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK; - prev_shadow_ent = shadow_ent; - continue; - } - - if (level == PT_PAGE_TABLE_LEVEL) - break; - - if (level - 1 == PT_PAGE_TABLE_LEVEL - && walker->level == PT_DIRECTORY_LEVEL) { - metaphysical = 1; - hugepage_access = walker->pte; - hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK; - if (walker->pte & PT64_NX_MASK) - hugepage_access |= (1 << 2); - hugepage_access >>= PT_WRITABLE_SHIFT; - table_gfn = (walker->pte & PT_BASE_ADDR_MASK) - >> PAGE_SHIFT; - } else { - metaphysical = 0; - table_gfn = walker->table_gfn[level - 2]; - } - shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1, - metaphysical, hugepage_access, - shadow_ent); - shadow_addr = __pa(shadow_page->spt); - shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK - | PT_WRITABLE_MASK | PT_USER_MASK; - *shadow_ent = shadow_pte; - prev_shadow_ent = shadow_ent; - } - - if (walker->level == PT_DIRECTORY_LEVEL) { - FNAME(set_pde)(vcpu, walker->pte, shadow_ent, - walker->inherited_ar, user_fault, write_fault, - ptwrite, walker, walker->gfn); - } else { - ASSERT(walker->level == PT_PAGE_TABLE_LEVEL); - FNAME(set_pte)(vcpu, walker->pte, shadow_ent, - walker->inherited_ar, user_fault, write_fault, - ptwrite, walker, walker->gfn); - } - return shadow_ent; -} - -/* - * Page fault handler. There are several causes for a page fault: - * - there is no shadow pte for the guest pte - * - write access through a shadow pte marked read only so that we can set - * the dirty bit - * - write access to a shadow pte marked read only so we can update the page - * dirty bitmap, when userspace requests it - * - mmio access; in this case we will never install a present shadow pte - * - normal guest page fault due to the guest pte marked not present, not - * writable, or not executable - * - * Returns: 1 if we need to emulate the instruction, 0 otherwise, or - * a negative value on error. - */ -static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, - u32 error_code) -{ - int write_fault = error_code & PFERR_WRITE_MASK; - int user_fault = error_code & PFERR_USER_MASK; - int fetch_fault = error_code & PFERR_FETCH_MASK; - struct guest_walker walker; - u64 *shadow_pte; - int write_pt = 0; - int r; - - pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code); - kvm_mmu_audit(vcpu, "pre page fault"); - - r = mmu_topup_memory_caches(vcpu); - if (r) - return r; - - /* - * Look up the shadow pte for the faulting address. - */ - r = FNAME(walk_addr)(&walker, vcpu, addr, write_fault, user_fault, - fetch_fault); - - /* - * The page is not mapped by the guest. Let the guest handle it. - */ - if (!r) { - pgprintk("%s: guest page fault\n", __FUNCTION__); - inject_page_fault(vcpu, addr, walker.error_code); - vcpu->last_pt_write_count = 0; /* reset fork detector */ - return 0; - } - - shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault, - &write_pt); - pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__, - shadow_pte, *shadow_pte, write_pt); - - if (!write_pt) - vcpu->last_pt_write_count = 0; /* reset fork detector */ - - /* - * mmio: emulate if accessible, otherwise its a guest fault. - */ - if (is_io_pte(*shadow_pte)) - return 1; - - ++vcpu->stat.pf_fixed; - kvm_mmu_audit(vcpu, "post page fault (fixed)"); - - return write_pt; -} - -static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr) -{ - struct guest_walker walker; - gpa_t gpa = UNMAPPED_GVA; - int r; - - r = FNAME(walk_addr)(&walker, vcpu, vaddr, 0, 0, 0); - - if (r) { - gpa = (gpa_t)walker.gfn << PAGE_SHIFT; - gpa |= vaddr & ~PAGE_MASK; - } - - return gpa; -} - -#undef pt_element_t -#undef guest_walker -#undef FNAME -#undef PT_BASE_ADDR_MASK -#undef PT_INDEX -#undef SHADOW_PT_INDEX -#undef PT_LEVEL_MASK -#undef PT_DIR_BASE_ADDR_MASK -#undef PT_MAX_FULL_LEVELS diff --git a/drivers/kvm/segment_descriptor.h b/drivers/kvm/segment_descriptor.h deleted file mode 100644 index 71fdf458619a..000000000000 --- a/drivers/kvm/segment_descriptor.h +++ /dev/null @@ -1,17 +0,0 @@ -struct segment_descriptor { - u16 limit_low; - u16 base_low; - u8 base_mid; - u8 type : 4; - u8 system : 1; - u8 dpl : 2; - u8 present : 1; - u8 limit_high : 4; - u8 avl : 1; - u8 long_mode : 1; - u8 default_op : 1; - u8 granularity : 1; - u8 base_high; -} __attribute__((packed)); - - diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c deleted file mode 100644 index 4e04e49a2f1c..000000000000 --- a/drivers/kvm/svm.c +++ /dev/null @@ -1,1754 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * AMD SVM support - * - * Copyright (C) 2006 Qumranet, Inc. - * - * Authors: - * Yaniv Kamay <yaniv@qumranet.com> - * Avi Kivity <avi@qumranet.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "kvm_svm.h" -#include "x86_emulate.h" -#include "irq.h" - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/vmalloc.h> -#include <linux/highmem.h> -#include <linux/sched.h> - -#include <asm/desc.h> - -MODULE_AUTHOR("Qumranet"); -MODULE_LICENSE("GPL"); - -#define IOPM_ALLOC_ORDER 2 -#define MSRPM_ALLOC_ORDER 1 - -#define DB_VECTOR 1 -#define UD_VECTOR 6 -#define GP_VECTOR 13 - -#define DR7_GD_MASK (1 << 13) -#define DR6_BD_MASK (1 << 13) - -#define SEG_TYPE_LDT 2 -#define SEG_TYPE_BUSY_TSS16 3 - -#define KVM_EFER_LMA (1 << 10) -#define KVM_EFER_LME (1 << 8) - -#define SVM_FEATURE_NPT (1 << 0) -#define SVM_FEATURE_LBRV (1 << 1) -#define SVM_DEATURE_SVML (1 << 2) - -static void kvm_reput_irq(struct vcpu_svm *svm); - -static inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu) -{ - return container_of(vcpu, struct vcpu_svm, vcpu); -} - -unsigned long iopm_base; -unsigned long msrpm_base; - -struct kvm_ldttss_desc { - u16 limit0; - u16 base0; - unsigned base1 : 8, type : 5, dpl : 2, p : 1; - unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8; - u32 base3; - u32 zero1; -} __attribute__((packed)); - -struct svm_cpu_data { - int cpu; - - u64 asid_generation; - u32 max_asid; - u32 next_asid; - struct kvm_ldttss_desc *tss_desc; - - struct page *save_area; -}; - -static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data); -static uint32_t svm_features; - -struct svm_init_data { - int cpu; - int r; -}; - -static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; - -#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges) -#define MSRS_RANGE_SIZE 2048 -#define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2) - -#define MAX_INST_SIZE 15 - -static inline u32 svm_has(u32 feat) -{ - return svm_features & feat; -} - -static inline u8 pop_irq(struct kvm_vcpu *vcpu) -{ - int word_index = __ffs(vcpu->irq_summary); - int bit_index = __ffs(vcpu->irq_pending[word_index]); - int irq = word_index * BITS_PER_LONG + bit_index; - - clear_bit(bit_index, &vcpu->irq_pending[word_index]); - if (!vcpu->irq_pending[word_index]) - clear_bit(word_index, &vcpu->irq_summary); - return irq; -} - -static inline void push_irq(struct kvm_vcpu *vcpu, u8 irq) -{ - set_bit(irq, vcpu->irq_pending); - set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); -} - -static inline void clgi(void) -{ - asm volatile (SVM_CLGI); -} - -static inline void stgi(void) -{ - asm volatile (SVM_STGI); -} - -static inline void invlpga(unsigned long addr, u32 asid) -{ - asm volatile (SVM_INVLPGA :: "a"(addr), "c"(asid)); -} - -static inline unsigned long kvm_read_cr2(void) -{ - unsigned long cr2; - - asm volatile ("mov %%cr2, %0" : "=r" (cr2)); - return cr2; -} - -static inline void kvm_write_cr2(unsigned long val) -{ - asm volatile ("mov %0, %%cr2" :: "r" (val)); -} - -static inline unsigned long read_dr6(void) -{ - unsigned long dr6; - - asm volatile ("mov %%dr6, %0" : "=r" (dr6)); - return dr6; -} - -static inline void write_dr6(unsigned long val) -{ - asm volatile ("mov %0, %%dr6" :: "r" (val)); -} - -static inline unsigned long read_dr7(void) -{ - unsigned long dr7; - - asm volatile ("mov %%dr7, %0" : "=r" (dr7)); - return dr7; -} - -static inline void write_dr7(unsigned long val) -{ - asm volatile ("mov %0, %%dr7" :: "r" (val)); -} - -static inline void force_new_asid(struct kvm_vcpu *vcpu) -{ - to_svm(vcpu)->asid_generation--; -} - -static inline void flush_guest_tlb(struct kvm_vcpu *vcpu) -{ - force_new_asid(vcpu); -} - -static void svm_set_efer(struct kvm_vcpu *vcpu, u64 efer) -{ - if (!(efer & KVM_EFER_LMA)) - efer &= ~KVM_EFER_LME; - - to_svm(vcpu)->vmcb->save.efer = efer | MSR_EFER_SVME_MASK; - vcpu->shadow_efer = efer; -} - -static void svm_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - GP_VECTOR; - svm->vmcb->control.event_inj_err = error_code; -} - -static void inject_ud(struct kvm_vcpu *vcpu) -{ - to_svm(vcpu)->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_TYPE_EXEPT | - UD_VECTOR; -} - -static int is_page_fault(uint32_t info) -{ - info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; - return info == (PF_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT); -} - -static int is_external_interrupt(u32 info) -{ - info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID; - return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR); -} - -static void skip_emulated_instruction(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - if (!svm->next_rip) { - printk(KERN_DEBUG "%s: NOP\n", __FUNCTION__); - return; - } - if (svm->next_rip - svm->vmcb->save.rip > MAX_INST_SIZE) { - printk(KERN_ERR "%s: ip 0x%llx next 0x%llx\n", - __FUNCTION__, - svm->vmcb->save.rip, - svm->next_rip); - } - - vcpu->rip = svm->vmcb->save.rip = svm->next_rip; - svm->vmcb->control.int_state &= ~SVM_INTERRUPT_SHADOW_MASK; - - vcpu->interrupt_window_open = 1; -} - -static int has_svm(void) -{ - uint32_t eax, ebx, ecx, edx; - - if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { - printk(KERN_INFO "has_svm: not amd\n"); - return 0; - } - - cpuid(0x80000000, &eax, &ebx, &ecx, &edx); - if (eax < SVM_CPUID_FUNC) { - printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n"); - return 0; - } - - cpuid(0x80000001, &eax, &ebx, &ecx, &edx); - if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) { - printk(KERN_DEBUG "has_svm: svm not available\n"); - return 0; - } - return 1; -} - -static void svm_hardware_disable(void *garbage) -{ - struct svm_cpu_data *svm_data - = per_cpu(svm_data, raw_smp_processor_id()); - - if (svm_data) { - uint64_t efer; - - wrmsrl(MSR_VM_HSAVE_PA, 0); - rdmsrl(MSR_EFER, efer); - wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK); - per_cpu(svm_data, raw_smp_processor_id()) = NULL; - __free_page(svm_data->save_area); - kfree(svm_data); - } -} - -static void svm_hardware_enable(void *garbage) -{ - - struct svm_cpu_data *svm_data; - uint64_t efer; -#ifdef CONFIG_X86_64 - struct desc_ptr gdt_descr; -#else - struct Xgt_desc_struct gdt_descr; -#endif - struct desc_struct *gdt; - int me = raw_smp_processor_id(); - - if (!has_svm()) { - printk(KERN_ERR "svm_cpu_init: err EOPNOTSUPP on %d\n", me); - return; - } - svm_data = per_cpu(svm_data, me); - - if (!svm_data) { - printk(KERN_ERR "svm_cpu_init: svm_data is NULL on %d\n", - me); - return; - } - - svm_data->asid_generation = 1; - svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1; - svm_data->next_asid = svm_data->max_asid + 1; - svm_features = cpuid_edx(SVM_CPUID_FUNC); - - asm volatile ( "sgdt %0" : "=m"(gdt_descr) ); - gdt = (struct desc_struct *)gdt_descr.address; - svm_data->tss_desc = (struct kvm_ldttss_desc *)(gdt + GDT_ENTRY_TSS); - - rdmsrl(MSR_EFER, efer); - wrmsrl(MSR_EFER, efer | MSR_EFER_SVME_MASK); - - wrmsrl(MSR_VM_HSAVE_PA, - page_to_pfn(svm_data->save_area) << PAGE_SHIFT); -} - -static int svm_cpu_init(int cpu) -{ - struct svm_cpu_data *svm_data; - int r; - - svm_data = kzalloc(sizeof(struct svm_cpu_data), GFP_KERNEL); - if (!svm_data) - return -ENOMEM; - svm_data->cpu = cpu; - svm_data->save_area = alloc_page(GFP_KERNEL); - r = -ENOMEM; - if (!svm_data->save_area) - goto err_1; - - per_cpu(svm_data, cpu) = svm_data; - - return 0; - -err_1: - kfree(svm_data); - return r; - -} - -static void set_msr_interception(u32 *msrpm, unsigned msr, - int read, int write) -{ - int i; - - for (i = 0; i < NUM_MSR_MAPS; i++) { - if (msr >= msrpm_ranges[i] && - msr < msrpm_ranges[i] + MSRS_IN_RANGE) { - u32 msr_offset = (i * MSRS_IN_RANGE + msr - - msrpm_ranges[i]) * 2; - - u32 *base = msrpm + (msr_offset / 32); - u32 msr_shift = msr_offset % 32; - u32 mask = ((write) ? 0 : 2) | ((read) ? 0 : 1); - *base = (*base & ~(0x3 << msr_shift)) | - (mask << msr_shift); - return; - } - } - BUG(); -} - -static __init int svm_hardware_setup(void) -{ - int cpu; - struct page *iopm_pages; - struct page *msrpm_pages; - void *iopm_va, *msrpm_va; - int r; - - iopm_pages = alloc_pages(GFP_KERNEL, IOPM_ALLOC_ORDER); - - if (!iopm_pages) - return -ENOMEM; - - iopm_va = page_address(iopm_pages); - memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER)); - clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */ - iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; - - - msrpm_pages = alloc_pages(GFP_KERNEL, MSRPM_ALLOC_ORDER); - - r = -ENOMEM; - if (!msrpm_pages) - goto err_1; - - msrpm_va = page_address(msrpm_pages); - memset(msrpm_va, 0xff, PAGE_SIZE * (1 << MSRPM_ALLOC_ORDER)); - msrpm_base = page_to_pfn(msrpm_pages) << PAGE_SHIFT; - -#ifdef CONFIG_X86_64 - set_msr_interception(msrpm_va, MSR_GS_BASE, 1, 1); - set_msr_interception(msrpm_va, MSR_FS_BASE, 1, 1); - set_msr_interception(msrpm_va, MSR_KERNEL_GS_BASE, 1, 1); - set_msr_interception(msrpm_va, MSR_LSTAR, 1, 1); - set_msr_interception(msrpm_va, MSR_CSTAR, 1, 1); - set_msr_interception(msrpm_va, MSR_SYSCALL_MASK, 1, 1); -#endif - set_msr_interception(msrpm_va, MSR_K6_STAR, 1, 1); - set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_CS, 1, 1); - set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_ESP, 1, 1); - set_msr_interception(msrpm_va, MSR_IA32_SYSENTER_EIP, 1, 1); - - for_each_online_cpu(cpu) { - r = svm_cpu_init(cpu); - if (r) - goto err_2; - } - return 0; - -err_2: - __free_pages(msrpm_pages, MSRPM_ALLOC_ORDER); - msrpm_base = 0; -err_1: - __free_pages(iopm_pages, IOPM_ALLOC_ORDER); - iopm_base = 0; - return r; -} - -static __exit void svm_hardware_unsetup(void) -{ - __free_pages(pfn_to_page(msrpm_base >> PAGE_SHIFT), MSRPM_ALLOC_ORDER); - __free_pages(pfn_to_page(iopm_base >> PAGE_SHIFT), IOPM_ALLOC_ORDER); - iopm_base = msrpm_base = 0; -} - -static void init_seg(struct vmcb_seg *seg) -{ - seg->selector = 0; - seg->attrib = SVM_SELECTOR_P_MASK | SVM_SELECTOR_S_MASK | - SVM_SELECTOR_WRITE_MASK; /* Read/Write Data Segment */ - seg->limit = 0xffff; - seg->base = 0; -} - -static void init_sys_seg(struct vmcb_seg *seg, uint32_t type) -{ - seg->selector = 0; - seg->attrib = SVM_SELECTOR_P_MASK | type; - seg->limit = 0xffff; - seg->base = 0; -} - -static void init_vmcb(struct vmcb *vmcb) -{ - struct vmcb_control_area *control = &vmcb->control; - struct vmcb_save_area *save = &vmcb->save; - - control->intercept_cr_read = INTERCEPT_CR0_MASK | - INTERCEPT_CR3_MASK | - INTERCEPT_CR4_MASK; - - control->intercept_cr_write = INTERCEPT_CR0_MASK | - INTERCEPT_CR3_MASK | - INTERCEPT_CR4_MASK; - - control->intercept_dr_read = INTERCEPT_DR0_MASK | - INTERCEPT_DR1_MASK | - INTERCEPT_DR2_MASK | - INTERCEPT_DR3_MASK; - - control->intercept_dr_write = INTERCEPT_DR0_MASK | - INTERCEPT_DR1_MASK | - INTERCEPT_DR2_MASK | - INTERCEPT_DR3_MASK | - INTERCEPT_DR5_MASK | - INTERCEPT_DR7_MASK; - - control->intercept_exceptions = 1 << PF_VECTOR; - - - control->intercept = (1ULL << INTERCEPT_INTR) | - (1ULL << INTERCEPT_NMI) | - (1ULL << INTERCEPT_SMI) | - /* - * selective cr0 intercept bug? - * 0: 0f 22 d8 mov %eax,%cr3 - * 3: 0f 20 c0 mov %cr0,%eax - * 6: 0d 00 00 00 80 or $0x80000000,%eax - * b: 0f 22 c0 mov %eax,%cr0 - * set cr3 ->interception - * get cr0 ->interception - * set cr0 -> no interception - */ - /* (1ULL << INTERCEPT_SELECTIVE_CR0) | */ - (1ULL << INTERCEPT_CPUID) | - (1ULL << INTERCEPT_INVD) | - (1ULL << INTERCEPT_HLT) | - (1ULL << INTERCEPT_INVLPGA) | - (1ULL << INTERCEPT_IOIO_PROT) | - (1ULL << INTERCEPT_MSR_PROT) | - (1ULL << INTERCEPT_TASK_SWITCH) | - (1ULL << INTERCEPT_SHUTDOWN) | - (1ULL << INTERCEPT_VMRUN) | - (1ULL << INTERCEPT_VMMCALL) | - (1ULL << INTERCEPT_VMLOAD) | - (1ULL << INTERCEPT_VMSAVE) | - (1ULL << INTERCEPT_STGI) | - (1ULL << INTERCEPT_CLGI) | - (1ULL << INTERCEPT_SKINIT) | - (1ULL << INTERCEPT_WBINVD) | - (1ULL << INTERCEPT_MONITOR) | - (1ULL << INTERCEPT_MWAIT); - - control->iopm_base_pa = iopm_base; - control->msrpm_base_pa = msrpm_base; - control->tsc_offset = 0; - control->int_ctl = V_INTR_MASKING_MASK; - - init_seg(&save->es); - init_seg(&save->ss); - init_seg(&save->ds); - init_seg(&save->fs); - init_seg(&save->gs); - - save->cs.selector = 0xf000; - /* Executable/Readable Code Segment */ - save->cs.attrib = SVM_SELECTOR_READ_MASK | SVM_SELECTOR_P_MASK | - SVM_SELECTOR_S_MASK | SVM_SELECTOR_CODE_MASK; - save->cs.limit = 0xffff; - /* - * cs.base should really be 0xffff0000, but vmx can't handle that, so - * be consistent with it. - * - * Replace when we have real mode working for vmx. - */ - save->cs.base = 0xf0000; - - save->gdtr.limit = 0xffff; - save->idtr.limit = 0xffff; - - init_sys_seg(&save->ldtr, SEG_TYPE_LDT); - init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); - - save->efer = MSR_EFER_SVME_MASK; - - save->dr6 = 0xffff0ff0; - save->dr7 = 0x400; - save->rflags = 2; - save->rip = 0x0000fff0; - - /* - * cr0 val on cpu init should be 0x60000010, we enable cpu - * cache by default. the orderly way is to enable cache in bios. - */ - save->cr0 = 0x00000010 | X86_CR0_PG | X86_CR0_WP; - save->cr4 = X86_CR4_PAE; - /* rdx = ?? */ -} - -static void svm_vcpu_reset(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - init_vmcb(svm->vmcb); - - if (vcpu->vcpu_id != 0) { - svm->vmcb->save.rip = 0; - svm->vmcb->save.cs.base = svm->vcpu.sipi_vector << 12; - svm->vmcb->save.cs.selector = svm->vcpu.sipi_vector << 8; - } -} - -static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id) -{ - struct vcpu_svm *svm; - struct page *page; - int err; - - svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); - if (!svm) { - err = -ENOMEM; - goto out; - } - - err = kvm_vcpu_init(&svm->vcpu, kvm, id); - if (err) - goto free_svm; - - if (irqchip_in_kernel(kvm)) { - err = kvm_create_lapic(&svm->vcpu); - if (err < 0) - goto free_svm; - } - - page = alloc_page(GFP_KERNEL); - if (!page) { - err = -ENOMEM; - goto uninit; - } - - svm->vmcb = page_address(page); - clear_page(svm->vmcb); - svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; - svm->asid_generation = 0; - memset(svm->db_regs, 0, sizeof(svm->db_regs)); - init_vmcb(svm->vmcb); - - fx_init(&svm->vcpu); - svm->vcpu.fpu_active = 1; - svm->vcpu.apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; - if (svm->vcpu.vcpu_id == 0) - svm->vcpu.apic_base |= MSR_IA32_APICBASE_BSP; - - return &svm->vcpu; - -uninit: - kvm_vcpu_uninit(&svm->vcpu); -free_svm: - kmem_cache_free(kvm_vcpu_cache, svm); -out: - return ERR_PTR(err); -} - -static void svm_free_vcpu(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT)); - kvm_vcpu_uninit(vcpu); - kmem_cache_free(kvm_vcpu_cache, svm); -} - -static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - int i; - - if (unlikely(cpu != vcpu->cpu)) { - u64 tsc_this, delta; - - /* - * Make sure that the guest sees a monotonically - * increasing TSC. - */ - rdtscll(tsc_this); - delta = vcpu->host_tsc - tsc_this; - svm->vmcb->control.tsc_offset += delta; - vcpu->cpu = cpu; - kvm_migrate_apic_timer(vcpu); - } - - for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) - rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); -} - -static void svm_vcpu_put(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - int i; - - for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) - wrmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]); - - rdtscll(vcpu->host_tsc); - kvm_put_guest_fpu(vcpu); -} - -static void svm_vcpu_decache(struct kvm_vcpu *vcpu) -{ -} - -static void svm_cache_regs(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - vcpu->regs[VCPU_REGS_RAX] = svm->vmcb->save.rax; - vcpu->regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp; - vcpu->rip = svm->vmcb->save.rip; -} - -static void svm_decache_regs(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - svm->vmcb->save.rax = vcpu->regs[VCPU_REGS_RAX]; - svm->vmcb->save.rsp = vcpu->regs[VCPU_REGS_RSP]; - svm->vmcb->save.rip = vcpu->rip; -} - -static unsigned long svm_get_rflags(struct kvm_vcpu *vcpu) -{ - return to_svm(vcpu)->vmcb->save.rflags; -} - -static void svm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) -{ - to_svm(vcpu)->vmcb->save.rflags = rflags; -} - -static struct vmcb_seg *svm_seg(struct kvm_vcpu *vcpu, int seg) -{ - struct vmcb_save_area *save = &to_svm(vcpu)->vmcb->save; - - switch (seg) { - case VCPU_SREG_CS: return &save->cs; - case VCPU_SREG_DS: return &save->ds; - case VCPU_SREG_ES: return &save->es; - case VCPU_SREG_FS: return &save->fs; - case VCPU_SREG_GS: return &save->gs; - case VCPU_SREG_SS: return &save->ss; - case VCPU_SREG_TR: return &save->tr; - case VCPU_SREG_LDTR: return &save->ldtr; - } - BUG(); - return NULL; -} - -static u64 svm_get_segment_base(struct kvm_vcpu *vcpu, int seg) -{ - struct vmcb_seg *s = svm_seg(vcpu, seg); - - return s->base; -} - -static void svm_get_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) -{ - struct vmcb_seg *s = svm_seg(vcpu, seg); - - var->base = s->base; - var->limit = s->limit; - var->selector = s->selector; - var->type = s->attrib & SVM_SELECTOR_TYPE_MASK; - var->s = (s->attrib >> SVM_SELECTOR_S_SHIFT) & 1; - var->dpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; - var->present = (s->attrib >> SVM_SELECTOR_P_SHIFT) & 1; - var->avl = (s->attrib >> SVM_SELECTOR_AVL_SHIFT) & 1; - var->l = (s->attrib >> SVM_SELECTOR_L_SHIFT) & 1; - var->db = (s->attrib >> SVM_SELECTOR_DB_SHIFT) & 1; - var->g = (s->attrib >> SVM_SELECTOR_G_SHIFT) & 1; - var->unusable = !var->present; -} - -static void svm_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - dt->limit = svm->vmcb->save.idtr.limit; - dt->base = svm->vmcb->save.idtr.base; -} - -static void svm_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->save.idtr.limit = dt->limit; - svm->vmcb->save.idtr.base = dt->base ; -} - -static void svm_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - dt->limit = svm->vmcb->save.gdtr.limit; - dt->base = svm->vmcb->save.gdtr.base; -} - -static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->save.gdtr.limit = dt->limit; - svm->vmcb->save.gdtr.base = dt->base ; -} - -static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) -{ -} - -static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) -{ - struct vcpu_svm *svm = to_svm(vcpu); - -#ifdef CONFIG_X86_64 - if (vcpu->shadow_efer & KVM_EFER_LME) { - if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) { - vcpu->shadow_efer |= KVM_EFER_LMA; - svm->vmcb->save.efer |= KVM_EFER_LMA | KVM_EFER_LME; - } - - if (is_paging(vcpu) && !(cr0 & X86_CR0_PG) ) { - vcpu->shadow_efer &= ~KVM_EFER_LMA; - svm->vmcb->save.efer &= ~(KVM_EFER_LMA | KVM_EFER_LME); - } - } -#endif - if ((vcpu->cr0 & X86_CR0_TS) && !(cr0 & X86_CR0_TS)) { - svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); - vcpu->fpu_active = 1; - } - - vcpu->cr0 = cr0; - cr0 |= X86_CR0_PG | X86_CR0_WP; - cr0 &= ~(X86_CR0_CD | X86_CR0_NW); - svm->vmcb->save.cr0 = cr0; -} - -static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) -{ - vcpu->cr4 = cr4; - to_svm(vcpu)->vmcb->save.cr4 = cr4 | X86_CR4_PAE; -} - -static void svm_set_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) -{ - struct vcpu_svm *svm = to_svm(vcpu); - struct vmcb_seg *s = svm_seg(vcpu, seg); - - s->base = var->base; - s->limit = var->limit; - s->selector = var->selector; - if (var->unusable) - s->attrib = 0; - else { - s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); - s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; - s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; - s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT; - s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; - s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; - s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; - s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; - } - if (seg == VCPU_SREG_CS) - svm->vmcb->save.cpl - = (svm->vmcb->save.cs.attrib - >> SVM_SELECTOR_DPL_SHIFT) & 3; - -} - -/* FIXME: - - svm(vcpu)->vmcb->control.int_ctl &= ~V_TPR_MASK; - svm(vcpu)->vmcb->control.int_ctl |= (sregs->cr8 & V_TPR_MASK); - -*/ - -static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) -{ - return -EOPNOTSUPP; -} - -static int svm_get_irq(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - u32 exit_int_info = svm->vmcb->control.exit_int_info; - - if (is_external_interrupt(exit_int_info)) - return exit_int_info & SVM_EVTINJ_VEC_MASK; - return -1; -} - -static void load_host_msrs(struct kvm_vcpu *vcpu) -{ -#ifdef CONFIG_X86_64 - wrmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); -#endif -} - -static void save_host_msrs(struct kvm_vcpu *vcpu) -{ -#ifdef CONFIG_X86_64 - rdmsrl(MSR_GS_BASE, to_svm(vcpu)->host_gs_base); -#endif -} - -static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) -{ - if (svm_data->next_asid > svm_data->max_asid) { - ++svm_data->asid_generation; - svm_data->next_asid = 1; - svm->vmcb->control.tlb_ctl = TLB_CONTROL_FLUSH_ALL_ASID; - } - - svm->vcpu.cpu = svm_data->cpu; - svm->asid_generation = svm_data->asid_generation; - svm->vmcb->control.asid = svm_data->next_asid++; -} - -static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) -{ - return to_svm(vcpu)->db_regs[dr]; -} - -static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, - int *exception) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - *exception = 0; - - if (svm->vmcb->save.dr7 & DR7_GD_MASK) { - svm->vmcb->save.dr7 &= ~DR7_GD_MASK; - svm->vmcb->save.dr6 |= DR6_BD_MASK; - *exception = DB_VECTOR; - return; - } - - switch (dr) { - case 0 ... 3: - svm->db_regs[dr] = value; - return; - case 4 ... 5: - if (vcpu->cr4 & X86_CR4_DE) { - *exception = UD_VECTOR; - return; - } - case 7: { - if (value & ~((1ULL << 32) - 1)) { - *exception = GP_VECTOR; - return; - } - svm->vmcb->save.dr7 = value; - return; - } - default: - printk(KERN_DEBUG "%s: unexpected dr %u\n", - __FUNCTION__, dr); - *exception = UD_VECTOR; - return; - } -} - -static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - u32 exit_int_info = svm->vmcb->control.exit_int_info; - struct kvm *kvm = svm->vcpu.kvm; - u64 fault_address; - u32 error_code; - enum emulation_result er; - int r; - - if (!irqchip_in_kernel(kvm) && - is_external_interrupt(exit_int_info)) - push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); - - mutex_lock(&kvm->lock); - - fault_address = svm->vmcb->control.exit_info_2; - error_code = svm->vmcb->control.exit_info_1; - r = kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); - if (r < 0) { - mutex_unlock(&kvm->lock); - return r; - } - if (!r) { - mutex_unlock(&kvm->lock); - return 1; - } - er = emulate_instruction(&svm->vcpu, kvm_run, fault_address, - error_code); - mutex_unlock(&kvm->lock); - - switch (er) { - case EMULATE_DONE: - return 1; - case EMULATE_DO_MMIO: - ++svm->vcpu.stat.mmio_exits; - return 0; - case EMULATE_FAIL: - kvm_report_emulation_failure(&svm->vcpu, "pagetable"); - break; - default: - BUG(); - } - - kvm_run->exit_reason = KVM_EXIT_UNKNOWN; - return 0; -} - -static int nm_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR); - if (!(svm->vcpu.cr0 & X86_CR0_TS)) - svm->vmcb->save.cr0 &= ~X86_CR0_TS; - svm->vcpu.fpu_active = 1; - - return 1; -} - -static int shutdown_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - /* - * VMCB is undefined after a SHUTDOWN intercept - * so reinitialize it. - */ - clear_page(svm->vmcb); - init_vmcb(svm->vmcb); - - kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; - return 0; -} - -static int io_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - u32 io_info = svm->vmcb->control.exit_info_1; //address size bug? - int size, down, in, string, rep; - unsigned port; - - ++svm->vcpu.stat.io_exits; - - svm->next_rip = svm->vmcb->control.exit_info_2; - - string = (io_info & SVM_IOIO_STR_MASK) != 0; - - if (string) { - if (emulate_instruction(&svm->vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) - return 0; - return 1; - } - - in = (io_info & SVM_IOIO_TYPE_MASK) != 0; - port = io_info >> 16; - size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT; - rep = (io_info & SVM_IOIO_REP_MASK) != 0; - down = (svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; - - return kvm_emulate_pio(&svm->vcpu, kvm_run, in, size, port); -} - -static int nop_on_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - return 1; -} - -static int halt_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - svm->next_rip = svm->vmcb->save.rip + 1; - skip_emulated_instruction(&svm->vcpu); - return kvm_emulate_halt(&svm->vcpu); -} - -static int vmmcall_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - svm->next_rip = svm->vmcb->save.rip + 3; - skip_emulated_instruction(&svm->vcpu); - return kvm_hypercall(&svm->vcpu, kvm_run); -} - -static int invalid_op_interception(struct vcpu_svm *svm, - struct kvm_run *kvm_run) -{ - inject_ud(&svm->vcpu); - return 1; -} - -static int task_switch_interception(struct vcpu_svm *svm, - struct kvm_run *kvm_run) -{ - pr_unimpl(&svm->vcpu, "%s: task switch is unsupported\n", __FUNCTION__); - kvm_run->exit_reason = KVM_EXIT_UNKNOWN; - return 0; -} - -static int cpuid_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - svm->next_rip = svm->vmcb->save.rip + 2; - kvm_emulate_cpuid(&svm->vcpu); - return 1; -} - -static int emulate_on_interception(struct vcpu_svm *svm, - struct kvm_run *kvm_run) -{ - if (emulate_instruction(&svm->vcpu, NULL, 0, 0) != EMULATE_DONE) - pr_unimpl(&svm->vcpu, "%s: failed\n", __FUNCTION__); - return 1; -} - -static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - switch (ecx) { - case MSR_IA32_TIME_STAMP_COUNTER: { - u64 tsc; - - rdtscll(tsc); - *data = svm->vmcb->control.tsc_offset + tsc; - break; - } - case MSR_K6_STAR: - *data = svm->vmcb->save.star; - break; -#ifdef CONFIG_X86_64 - case MSR_LSTAR: - *data = svm->vmcb->save.lstar; - break; - case MSR_CSTAR: - *data = svm->vmcb->save.cstar; - break; - case MSR_KERNEL_GS_BASE: - *data = svm->vmcb->save.kernel_gs_base; - break; - case MSR_SYSCALL_MASK: - *data = svm->vmcb->save.sfmask; - break; -#endif - case MSR_IA32_SYSENTER_CS: - *data = svm->vmcb->save.sysenter_cs; - break; - case MSR_IA32_SYSENTER_EIP: - *data = svm->vmcb->save.sysenter_eip; - break; - case MSR_IA32_SYSENTER_ESP: - *data = svm->vmcb->save.sysenter_esp; - break; - default: - return kvm_get_msr_common(vcpu, ecx, data); - } - return 0; -} - -static int rdmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX]; - u64 data; - - if (svm_get_msr(&svm->vcpu, ecx, &data)) - svm_inject_gp(&svm->vcpu, 0); - else { - svm->vmcb->save.rax = data & 0xffffffff; - svm->vcpu.regs[VCPU_REGS_RDX] = data >> 32; - svm->next_rip = svm->vmcb->save.rip + 2; - skip_emulated_instruction(&svm->vcpu); - } - return 1; -} - -static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - switch (ecx) { - case MSR_IA32_TIME_STAMP_COUNTER: { - u64 tsc; - - rdtscll(tsc); - svm->vmcb->control.tsc_offset = data - tsc; - break; - } - case MSR_K6_STAR: - svm->vmcb->save.star = data; - break; -#ifdef CONFIG_X86_64 - case MSR_LSTAR: - svm->vmcb->save.lstar = data; - break; - case MSR_CSTAR: - svm->vmcb->save.cstar = data; - break; - case MSR_KERNEL_GS_BASE: - svm->vmcb->save.kernel_gs_base = data; - break; - case MSR_SYSCALL_MASK: - svm->vmcb->save.sfmask = data; - break; -#endif - case MSR_IA32_SYSENTER_CS: - svm->vmcb->save.sysenter_cs = data; - break; - case MSR_IA32_SYSENTER_EIP: - svm->vmcb->save.sysenter_eip = data; - break; - case MSR_IA32_SYSENTER_ESP: - svm->vmcb->save.sysenter_esp = data; - break; - default: - return kvm_set_msr_common(vcpu, ecx, data); - } - return 0; -} - -static int wrmsr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - u32 ecx = svm->vcpu.regs[VCPU_REGS_RCX]; - u64 data = (svm->vmcb->save.rax & -1u) - | ((u64)(svm->vcpu.regs[VCPU_REGS_RDX] & -1u) << 32); - svm->next_rip = svm->vmcb->save.rip + 2; - if (svm_set_msr(&svm->vcpu, ecx, data)) - svm_inject_gp(&svm->vcpu, 0); - else - skip_emulated_instruction(&svm->vcpu); - return 1; -} - -static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) -{ - if (svm->vmcb->control.exit_info_1) - return wrmsr_interception(svm, kvm_run); - else - return rdmsr_interception(svm, kvm_run); -} - -static int interrupt_window_interception(struct vcpu_svm *svm, - struct kvm_run *kvm_run) -{ - svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR); - svm->vmcb->control.int_ctl &= ~V_IRQ_MASK; - /* - * If the user space waits to inject interrupts, exit as soon as - * possible - */ - if (kvm_run->request_interrupt_window && - !svm->vcpu.irq_summary) { - ++svm->vcpu.stat.irq_window_exits; - kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; - return 0; - } - - return 1; -} - -static int (*svm_exit_handlers[])(struct vcpu_svm *svm, - struct kvm_run *kvm_run) = { - [SVM_EXIT_READ_CR0] = emulate_on_interception, - [SVM_EXIT_READ_CR3] = emulate_on_interception, - [SVM_EXIT_READ_CR4] = emulate_on_interception, - /* for now: */ - [SVM_EXIT_WRITE_CR0] = emulate_on_interception, - [SVM_EXIT_WRITE_CR3] = emulate_on_interception, - [SVM_EXIT_WRITE_CR4] = emulate_on_interception, - [SVM_EXIT_READ_DR0] = emulate_on_interception, - [SVM_EXIT_READ_DR1] = emulate_on_interception, - [SVM_EXIT_READ_DR2] = emulate_on_interception, - [SVM_EXIT_READ_DR3] = emulate_on_interception, - [SVM_EXIT_WRITE_DR0] = emulate_on_interception, - [SVM_EXIT_WRITE_DR1] = emulate_on_interception, - [SVM_EXIT_WRITE_DR2] = emulate_on_interception, - [SVM_EXIT_WRITE_DR3] = emulate_on_interception, - [SVM_EXIT_WRITE_DR5] = emulate_on_interception, - [SVM_EXIT_WRITE_DR7] = emulate_on_interception, - [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, - [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, - [SVM_EXIT_INTR] = nop_on_interception, - [SVM_EXIT_NMI] = nop_on_interception, - [SVM_EXIT_SMI] = nop_on_interception, - [SVM_EXIT_INIT] = nop_on_interception, - [SVM_EXIT_VINTR] = interrupt_window_interception, - /* [SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception, */ - [SVM_EXIT_CPUID] = cpuid_interception, - [SVM_EXIT_INVD] = emulate_on_interception, - [SVM_EXIT_HLT] = halt_interception, - [SVM_EXIT_INVLPG] = emulate_on_interception, - [SVM_EXIT_INVLPGA] = invalid_op_interception, - [SVM_EXIT_IOIO] = io_interception, - [SVM_EXIT_MSR] = msr_interception, - [SVM_EXIT_TASK_SWITCH] = task_switch_interception, - [SVM_EXIT_SHUTDOWN] = shutdown_interception, - [SVM_EXIT_VMRUN] = invalid_op_interception, - [SVM_EXIT_VMMCALL] = vmmcall_interception, - [SVM_EXIT_VMLOAD] = invalid_op_interception, - [SVM_EXIT_VMSAVE] = invalid_op_interception, - [SVM_EXIT_STGI] = invalid_op_interception, - [SVM_EXIT_CLGI] = invalid_op_interception, - [SVM_EXIT_SKINIT] = invalid_op_interception, - [SVM_EXIT_WBINVD] = emulate_on_interception, - [SVM_EXIT_MONITOR] = invalid_op_interception, - [SVM_EXIT_MWAIT] = invalid_op_interception, -}; - - -static int handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - u32 exit_code = svm->vmcb->control.exit_code; - - kvm_reput_irq(svm); - - if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = svm->vmcb->control.exit_code; - return 0; - } - - if (is_external_interrupt(svm->vmcb->control.exit_int_info) && - exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR) - printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x " - "exit_code 0x%x\n", - __FUNCTION__, svm->vmcb->control.exit_int_info, - exit_code); - - if (exit_code >= ARRAY_SIZE(svm_exit_handlers) - || svm_exit_handlers[exit_code] == 0) { - kvm_run->exit_reason = KVM_EXIT_UNKNOWN; - kvm_run->hw.hardware_exit_reason = exit_code; - return 0; - } - - return svm_exit_handlers[exit_code](svm, kvm_run); -} - -static void reload_tss(struct kvm_vcpu *vcpu) -{ - int cpu = raw_smp_processor_id(); - - struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); - svm_data->tss_desc->type = 9; //available 32/64-bit TSS - load_TR_desc(); -} - -static void pre_svm_run(struct vcpu_svm *svm) -{ - int cpu = raw_smp_processor_id(); - - struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); - - svm->vmcb->control.tlb_ctl = TLB_CONTROL_DO_NOTHING; - if (svm->vcpu.cpu != cpu || - svm->asid_generation != svm_data->asid_generation) - new_asid(svm, svm_data); -} - - -static inline void svm_inject_irq(struct vcpu_svm *svm, int irq) -{ - struct vmcb_control_area *control; - - control = &svm->vmcb->control; - control->int_vector = irq; - control->int_ctl &= ~V_INTR_PRIO_MASK; - control->int_ctl |= V_IRQ_MASK | - ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); -} - -static void svm_set_irq(struct kvm_vcpu *vcpu, int irq) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm_inject_irq(svm, irq); -} - -static void svm_intr_assist(struct kvm_vcpu *vcpu) -{ - struct vcpu_svm *svm = to_svm(vcpu); - struct vmcb *vmcb = svm->vmcb; - int intr_vector = -1; - - kvm_inject_pending_timer_irqs(vcpu); - if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && - ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { - intr_vector = vmcb->control.exit_int_info & - SVM_EVTINJ_VEC_MASK; - vmcb->control.exit_int_info = 0; - svm_inject_irq(svm, intr_vector); - return; - } - - if (vmcb->control.int_ctl & V_IRQ_MASK) - return; - - if (!kvm_cpu_has_interrupt(vcpu)) - return; - - if (!(vmcb->save.rflags & X86_EFLAGS_IF) || - (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) || - (vmcb->control.event_inj & SVM_EVTINJ_VALID)) { - /* unable to deliver irq, set pending irq */ - vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR); - svm_inject_irq(svm, 0x0); - return; - } - /* Okay, we can deliver the interrupt: grab it and update PIC state. */ - intr_vector = kvm_cpu_get_interrupt(vcpu); - svm_inject_irq(svm, intr_vector); - kvm_timer_intr_post(vcpu, intr_vector); -} - -static void kvm_reput_irq(struct vcpu_svm *svm) -{ - struct vmcb_control_area *control = &svm->vmcb->control; - - if ((control->int_ctl & V_IRQ_MASK) - && !irqchip_in_kernel(svm->vcpu.kvm)) { - control->int_ctl &= ~V_IRQ_MASK; - push_irq(&svm->vcpu, control->int_vector); - } - - svm->vcpu.interrupt_window_open = - !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); -} - -static void svm_do_inject_vector(struct vcpu_svm *svm) -{ - struct kvm_vcpu *vcpu = &svm->vcpu; - int word_index = __ffs(vcpu->irq_summary); - int bit_index = __ffs(vcpu->irq_pending[word_index]); - int irq = word_index * BITS_PER_LONG + bit_index; - - clear_bit(bit_index, &vcpu->irq_pending[word_index]); - if (!vcpu->irq_pending[word_index]) - clear_bit(word_index, &vcpu->irq_summary); - svm_inject_irq(svm, irq); -} - -static void do_interrupt_requests(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - struct vcpu_svm *svm = to_svm(vcpu); - struct vmcb_control_area *control = &svm->vmcb->control; - - svm->vcpu.interrupt_window_open = - (!(control->int_state & SVM_INTERRUPT_SHADOW_MASK) && - (svm->vmcb->save.rflags & X86_EFLAGS_IF)); - - if (svm->vcpu.interrupt_window_open && svm->vcpu.irq_summary) - /* - * If interrupts enabled, and not blocked by sti or mov ss. Good. - */ - svm_do_inject_vector(svm); - - /* - * Interrupts blocked. Wait for unblock. - */ - if (!svm->vcpu.interrupt_window_open && - (svm->vcpu.irq_summary || kvm_run->request_interrupt_window)) { - control->intercept |= 1ULL << INTERCEPT_VINTR; - } else - control->intercept &= ~(1ULL << INTERCEPT_VINTR); -} - -static void save_db_regs(unsigned long *db_regs) -{ - asm volatile ("mov %%dr0, %0" : "=r"(db_regs[0])); - asm volatile ("mov %%dr1, %0" : "=r"(db_regs[1])); - asm volatile ("mov %%dr2, %0" : "=r"(db_regs[2])); - asm volatile ("mov %%dr3, %0" : "=r"(db_regs[3])); -} - -static void load_db_regs(unsigned long *db_regs) -{ - asm volatile ("mov %0, %%dr0" : : "r"(db_regs[0])); - asm volatile ("mov %0, %%dr1" : : "r"(db_regs[1])); - asm volatile ("mov %0, %%dr2" : : "r"(db_regs[2])); - asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3])); -} - -static void svm_flush_tlb(struct kvm_vcpu *vcpu) -{ - force_new_asid(vcpu); -} - -static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu) -{ -} - -static void svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - struct vcpu_svm *svm = to_svm(vcpu); - u16 fs_selector; - u16 gs_selector; - u16 ldt_selector; - - pre_svm_run(svm); - - save_host_msrs(vcpu); - fs_selector = read_fs(); - gs_selector = read_gs(); - ldt_selector = read_ldt(); - svm->host_cr2 = kvm_read_cr2(); - svm->host_dr6 = read_dr6(); - svm->host_dr7 = read_dr7(); - svm->vmcb->save.cr2 = vcpu->cr2; - - if (svm->vmcb->save.dr7 & 0xff) { - write_dr7(0); - save_db_regs(svm->host_db_regs); - load_db_regs(svm->db_regs); - } - - clgi(); - - local_irq_enable(); - - asm volatile ( -#ifdef CONFIG_X86_64 - "push %%rbx; push %%rcx; push %%rdx;" - "push %%rsi; push %%rdi; push %%rbp;" - "push %%r8; push %%r9; push %%r10; push %%r11;" - "push %%r12; push %%r13; push %%r14; push %%r15;" -#else - "push %%ebx; push %%ecx; push %%edx;" - "push %%esi; push %%edi; push %%ebp;" -#endif - -#ifdef CONFIG_X86_64 - "mov %c[rbx](%[svm]), %%rbx \n\t" - "mov %c[rcx](%[svm]), %%rcx \n\t" - "mov %c[rdx](%[svm]), %%rdx \n\t" - "mov %c[rsi](%[svm]), %%rsi \n\t" - "mov %c[rdi](%[svm]), %%rdi \n\t" - "mov %c[rbp](%[svm]), %%rbp \n\t" - "mov %c[r8](%[svm]), %%r8 \n\t" - "mov %c[r9](%[svm]), %%r9 \n\t" - "mov %c[r10](%[svm]), %%r10 \n\t" - "mov %c[r11](%[svm]), %%r11 \n\t" - "mov %c[r12](%[svm]), %%r12 \n\t" - "mov %c[r13](%[svm]), %%r13 \n\t" - "mov %c[r14](%[svm]), %%r14 \n\t" - "mov %c[r15](%[svm]), %%r15 \n\t" -#else - "mov %c[rbx](%[svm]), %%ebx \n\t" - "mov %c[rcx](%[svm]), %%ecx \n\t" - "mov %c[rdx](%[svm]), %%edx \n\t" - "mov %c[rsi](%[svm]), %%esi \n\t" - "mov %c[rdi](%[svm]), %%edi \n\t" - "mov %c[rbp](%[svm]), %%ebp \n\t" -#endif - -#ifdef CONFIG_X86_64 - /* Enter guest mode */ - "push %%rax \n\t" - "mov %c[vmcb](%[svm]), %%rax \n\t" - SVM_VMLOAD "\n\t" - SVM_VMRUN "\n\t" - SVM_VMSAVE "\n\t" - "pop %%rax \n\t" -#else - /* Enter guest mode */ - "push %%eax \n\t" - "mov %c[vmcb](%[svm]), %%eax \n\t" - SVM_VMLOAD "\n\t" - SVM_VMRUN "\n\t" - SVM_VMSAVE "\n\t" - "pop %%eax \n\t" -#endif - - /* Save guest registers, load host registers */ -#ifdef CONFIG_X86_64 - "mov %%rbx, %c[rbx](%[svm]) \n\t" - "mov %%rcx, %c[rcx](%[svm]) \n\t" - "mov %%rdx, %c[rdx](%[svm]) \n\t" - "mov %%rsi, %c[rsi](%[svm]) \n\t" - "mov %%rdi, %c[rdi](%[svm]) \n\t" - "mov %%rbp, %c[rbp](%[svm]) \n\t" - "mov %%r8, %c[r8](%[svm]) \n\t" - "mov %%r9, %c[r9](%[svm]) \n\t" - "mov %%r10, %c[r10](%[svm]) \n\t" - "mov %%r11, %c[r11](%[svm]) \n\t" - "mov %%r12, %c[r12](%[svm]) \n\t" - "mov %%r13, %c[r13](%[svm]) \n\t" - "mov %%r14, %c[r14](%[svm]) \n\t" - "mov %%r15, %c[r15](%[svm]) \n\t" - - "pop %%r15; pop %%r14; pop %%r13; pop %%r12;" - "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" - "pop %%rbp; pop %%rdi; pop %%rsi;" - "pop %%rdx; pop %%rcx; pop %%rbx; \n\t" -#else - "mov %%ebx, %c[rbx](%[svm]) \n\t" - "mov %%ecx, %c[rcx](%[svm]) \n\t" - "mov %%edx, %c[rdx](%[svm]) \n\t" - "mov %%esi, %c[rsi](%[svm]) \n\t" - "mov %%edi, %c[rdi](%[svm]) \n\t" - "mov %%ebp, %c[rbp](%[svm]) \n\t" - - "pop %%ebp; pop %%edi; pop %%esi;" - "pop %%edx; pop %%ecx; pop %%ebx; \n\t" -#endif - : - : [svm]"a"(svm), - [vmcb]"i"(offsetof(struct vcpu_svm, vmcb_pa)), - [rbx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBX])), - [rcx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RCX])), - [rdx]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDX])), - [rsi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RSI])), - [rdi]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RDI])), - [rbp]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_RBP])) -#ifdef CONFIG_X86_64 - ,[r8 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R8])), - [r9 ]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R9 ])), - [r10]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R10])), - [r11]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R11])), - [r12]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R12])), - [r13]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R13])), - [r14]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R14])), - [r15]"i"(offsetof(struct vcpu_svm,vcpu.regs[VCPU_REGS_R15])) -#endif - : "cc", "memory" ); - - if ((svm->vmcb->save.dr7 & 0xff)) - load_db_regs(svm->host_db_regs); - - vcpu->cr2 = svm->vmcb->save.cr2; - - write_dr6(svm->host_dr6); - write_dr7(svm->host_dr7); - kvm_write_cr2(svm->host_cr2); - - load_fs(fs_selector); - load_gs(gs_selector); - load_ldt(ldt_selector); - load_host_msrs(vcpu); - - reload_tss(vcpu); - - local_irq_disable(); - - stgi(); - - svm->next_rip = 0; -} - -static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) -{ - struct vcpu_svm *svm = to_svm(vcpu); - - svm->vmcb->save.cr3 = root; - force_new_asid(vcpu); - - if (vcpu->fpu_active) { - svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR); - svm->vmcb->save.cr0 |= X86_CR0_TS; - vcpu->fpu_active = 0; - } -} - -static void svm_inject_page_fault(struct kvm_vcpu *vcpu, - unsigned long addr, - uint32_t err_code) -{ - struct vcpu_svm *svm = to_svm(vcpu); - uint32_t exit_int_info = svm->vmcb->control.exit_int_info; - - ++vcpu->stat.pf_guest; - - if (is_page_fault(exit_int_info)) { - - svm->vmcb->control.event_inj_err = 0; - svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - DF_VECTOR; - return; - } - vcpu->cr2 = addr; - svm->vmcb->save.cr2 = addr; - svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | - SVM_EVTINJ_VALID_ERR | - SVM_EVTINJ_TYPE_EXEPT | - PF_VECTOR; - svm->vmcb->control.event_inj_err = err_code; -} - - -static int is_disabled(void) -{ - u64 vm_cr; - - rdmsrl(MSR_VM_CR, vm_cr); - if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) - return 1; - - return 0; -} - -static void -svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) -{ - /* - * Patch in the VMMCALL instruction: - */ - hypercall[0] = 0x0f; - hypercall[1] = 0x01; - hypercall[2] = 0xd9; - hypercall[3] = 0xc3; -} - -static void svm_check_processor_compat(void *rtn) -{ - *(int *)rtn = 0; -} - -static struct kvm_x86_ops svm_x86_ops = { - .cpu_has_kvm_support = has_svm, - .disabled_by_bios = is_disabled, - .hardware_setup = svm_hardware_setup, - .hardware_unsetup = svm_hardware_unsetup, - .check_processor_compatibility = svm_check_processor_compat, - .hardware_enable = svm_hardware_enable, - .hardware_disable = svm_hardware_disable, - - .vcpu_create = svm_create_vcpu, - .vcpu_free = svm_free_vcpu, - .vcpu_reset = svm_vcpu_reset, - - .prepare_guest_switch = svm_prepare_guest_switch, - .vcpu_load = svm_vcpu_load, - .vcpu_put = svm_vcpu_put, - .vcpu_decache = svm_vcpu_decache, - - .set_guest_debug = svm_guest_debug, - .get_msr = svm_get_msr, - .set_msr = svm_set_msr, - .get_segment_base = svm_get_segment_base, - .get_segment = svm_get_segment, - .set_segment = svm_set_segment, - .get_cs_db_l_bits = kvm_get_cs_db_l_bits, - .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, - .set_cr0 = svm_set_cr0, - .set_cr3 = svm_set_cr3, - .set_cr4 = svm_set_cr4, - .set_efer = svm_set_efer, - .get_idt = svm_get_idt, - .set_idt = svm_set_idt, - .get_gdt = svm_get_gdt, - .set_gdt = svm_set_gdt, - .get_dr = svm_get_dr, - .set_dr = svm_set_dr, - .cache_regs = svm_cache_regs, - .decache_regs = svm_decache_regs, - .get_rflags = svm_get_rflags, - .set_rflags = svm_set_rflags, - - .tlb_flush = svm_flush_tlb, - .inject_page_fault = svm_inject_page_fault, - - .inject_gp = svm_inject_gp, - - .run = svm_vcpu_run, - .handle_exit = handle_exit, - .skip_emulated_instruction = skip_emulated_instruction, - .patch_hypercall = svm_patch_hypercall, - .get_irq = svm_get_irq, - .set_irq = svm_set_irq, - .inject_pending_irq = svm_intr_assist, - .inject_pending_vectors = do_interrupt_requests, -}; - -static int __init svm_init(void) -{ - return kvm_init_x86(&svm_x86_ops, sizeof(struct vcpu_svm), - THIS_MODULE); -} - -static void __exit svm_exit(void) -{ - kvm_exit_x86(); -} - -module_init(svm_init) -module_exit(svm_exit) diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h deleted file mode 100644 index 3b1b0f35b6cb..000000000000 --- a/drivers/kvm/svm.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef __SVM_H -#define __SVM_H - -enum { - INTERCEPT_INTR, - INTERCEPT_NMI, - INTERCEPT_SMI, - INTERCEPT_INIT, - INTERCEPT_VINTR, - INTERCEPT_SELECTIVE_CR0, - INTERCEPT_STORE_IDTR, - INTERCEPT_STORE_GDTR, - INTERCEPT_STORE_LDTR, - INTERCEPT_STORE_TR, - INTERCEPT_LOAD_IDTR, - INTERCEPT_LOAD_GDTR, - INTERCEPT_LOAD_LDTR, - INTERCEPT_LOAD_TR, - INTERCEPT_RDTSC, - INTERCEPT_RDPMC, - INTERCEPT_PUSHF, - INTERCEPT_POPF, - INTERCEPT_CPUID, - INTERCEPT_RSM, - INTERCEPT_IRET, - INTERCEPT_INTn, - INTERCEPT_INVD, - INTERCEPT_PAUSE, - INTERCEPT_HLT, - INTERCEPT_INVLPG, - INTERCEPT_INVLPGA, - INTERCEPT_IOIO_PROT, - INTERCEPT_MSR_PROT, - INTERCEPT_TASK_SWITCH, - INTERCEPT_FERR_FREEZE, - INTERCEPT_SHUTDOWN, - INTERCEPT_VMRUN, - INTERCEPT_VMMCALL, - INTERCEPT_VMLOAD, - INTERCEPT_VMSAVE, - INTERCEPT_STGI, - INTERCEPT_CLGI, - INTERCEPT_SKINIT, - INTERCEPT_RDTSCP, - INTERCEPT_ICEBP, - INTERCEPT_WBINVD, - INTERCEPT_MONITOR, - INTERCEPT_MWAIT, - INTERCEPT_MWAIT_COND, -}; - - -struct __attribute__ ((__packed__)) vmcb_control_area { - u16 intercept_cr_read; - u16 intercept_cr_write; - u16 intercept_dr_read; - u16 intercept_dr_write; - u32 intercept_exceptions; - u64 intercept; - u8 reserved_1[44]; - u64 iopm_base_pa; - u64 msrpm_base_pa; - u64 tsc_offset; - u32 asid; - u8 tlb_ctl; - u8 reserved_2[3]; - u32 int_ctl; - u32 int_vector; - u32 int_state; - u8 reserved_3[4]; - u32 exit_code; - u32 exit_code_hi; - u64 exit_info_1; - u64 exit_info_2; - u32 exit_int_info; - u32 exit_int_info_err; - u64 nested_ctl; - u8 reserved_4[16]; - u32 event_inj; - u32 event_inj_err; - u64 nested_cr3; - u64 lbr_ctl; - u8 reserved_5[832]; -}; - - -#define TLB_CONTROL_DO_NOTHING 0 -#define TLB_CONTROL_FLUSH_ALL_ASID 1 - -#define V_TPR_MASK 0x0f - -#define V_IRQ_SHIFT 8 -#define V_IRQ_MASK (1 << V_IRQ_SHIFT) - -#define V_INTR_PRIO_SHIFT 16 -#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT) - -#define V_IGN_TPR_SHIFT 20 -#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT) - -#define V_INTR_MASKING_SHIFT 24 -#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT) - -#define SVM_INTERRUPT_SHADOW_MASK 1 - -#define SVM_IOIO_STR_SHIFT 2 -#define SVM_IOIO_REP_SHIFT 3 -#define SVM_IOIO_SIZE_SHIFT 4 -#define SVM_IOIO_ASIZE_SHIFT 7 - -#define SVM_IOIO_TYPE_MASK 1 -#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT) -#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT) -#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT) -#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT) - -struct __attribute__ ((__packed__)) vmcb_seg { - u16 selector; - u16 attrib; - u32 limit; - u64 base; -}; - -struct __attribute__ ((__packed__)) vmcb_save_area { - struct vmcb_seg es; - struct vmcb_seg cs; - struct vmcb_seg ss; - struct vmcb_seg ds; - struct vmcb_seg fs; - struct vmcb_seg gs; - struct vmcb_seg gdtr; - struct vmcb_seg ldtr; - struct vmcb_seg idtr; - struct vmcb_seg tr; - u8 reserved_1[43]; - u8 cpl; - u8 reserved_2[4]; - u64 efer; - u8 reserved_3[112]; - u64 cr4; - u64 cr3; - u64 cr0; - u64 dr7; - u64 dr6; - u64 rflags; - u64 rip; - u8 reserved_4[88]; - u64 rsp; - u8 reserved_5[24]; - u64 rax; - u64 star; - u64 lstar; - u64 cstar; - u64 sfmask; - u64 kernel_gs_base; - u64 sysenter_cs; - u64 sysenter_esp; - u64 sysenter_eip; - u64 cr2; - u8 reserved_6[32]; - u64 g_pat; - u64 dbgctl; - u64 br_from; - u64 br_to; - u64 last_excp_from; - u64 last_excp_to; -}; - -struct __attribute__ ((__packed__)) vmcb { - struct vmcb_control_area control; - struct vmcb_save_area save; -}; - -#define SVM_CPUID_FEATURE_SHIFT 2 -#define SVM_CPUID_FUNC 0x8000000a - -#define MSR_EFER_SVME_MASK (1ULL << 12) -#define MSR_VM_CR 0xc0010114 -#define MSR_VM_HSAVE_PA 0xc0010117ULL - -#define SVM_VM_CR_SVM_DISABLE 4 - -#define SVM_SELECTOR_S_SHIFT 4 -#define SVM_SELECTOR_DPL_SHIFT 5 -#define SVM_SELECTOR_P_SHIFT 7 -#define SVM_SELECTOR_AVL_SHIFT 8 -#define SVM_SELECTOR_L_SHIFT 9 -#define SVM_SELECTOR_DB_SHIFT 10 -#define SVM_SELECTOR_G_SHIFT 11 - -#define SVM_SELECTOR_TYPE_MASK (0xf) -#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT) -#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT) -#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT) -#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT) -#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT) -#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT) -#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT) - -#define SVM_SELECTOR_WRITE_MASK (1 << 1) -#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK -#define SVM_SELECTOR_CODE_MASK (1 << 3) - -#define INTERCEPT_CR0_MASK 1 -#define INTERCEPT_CR3_MASK (1 << 3) -#define INTERCEPT_CR4_MASK (1 << 4) - -#define INTERCEPT_DR0_MASK 1 -#define INTERCEPT_DR1_MASK (1 << 1) -#define INTERCEPT_DR2_MASK (1 << 2) -#define INTERCEPT_DR3_MASK (1 << 3) -#define INTERCEPT_DR4_MASK (1 << 4) -#define INTERCEPT_DR5_MASK (1 << 5) -#define INTERCEPT_DR6_MASK (1 << 6) -#define INTERCEPT_DR7_MASK (1 << 7) - -#define SVM_EVTINJ_VEC_MASK 0xff - -#define SVM_EVTINJ_TYPE_SHIFT 8 -#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT) - -#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) -#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) -#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) -#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) - -#define SVM_EVTINJ_VALID (1 << 31) -#define SVM_EVTINJ_VALID_ERR (1 << 11) - -#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK - -#define SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR -#define SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI -#define SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT -#define SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT - -#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID -#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR - -#define SVM_EXIT_READ_CR0 0x000 -#define SVM_EXIT_READ_CR3 0x003 -#define SVM_EXIT_READ_CR4 0x004 -#define SVM_EXIT_READ_CR8 0x008 -#define SVM_EXIT_WRITE_CR0 0x010 -#define SVM_EXIT_WRITE_CR3 0x013 -#define SVM_EXIT_WRITE_CR4 0x014 -#define SVM_EXIT_WRITE_CR8 0x018 -#define SVM_EXIT_READ_DR0 0x020 -#define SVM_EXIT_READ_DR1 0x021 -#define SVM_EXIT_READ_DR2 0x022 -#define SVM_EXIT_READ_DR3 0x023 -#define SVM_EXIT_READ_DR4 0x024 -#define SVM_EXIT_READ_DR5 0x025 -#define SVM_EXIT_READ_DR6 0x026 -#define SVM_EXIT_READ_DR7 0x027 -#define SVM_EXIT_WRITE_DR0 0x030 -#define SVM_EXIT_WRITE_DR1 0x031 -#define SVM_EXIT_WRITE_DR2 0x032 -#define SVM_EXIT_WRITE_DR3 0x033 -#define SVM_EXIT_WRITE_DR4 0x034 -#define SVM_EXIT_WRITE_DR5 0x035 -#define SVM_EXIT_WRITE_DR6 0x036 -#define SVM_EXIT_WRITE_DR7 0x037 -#define SVM_EXIT_EXCP_BASE 0x040 -#define SVM_EXIT_INTR 0x060 -#define SVM_EXIT_NMI 0x061 -#define SVM_EXIT_SMI 0x062 -#define SVM_EXIT_INIT 0x063 -#define SVM_EXIT_VINTR 0x064 -#define SVM_EXIT_CR0_SEL_WRITE 0x065 -#define SVM_EXIT_IDTR_READ 0x066 -#define SVM_EXIT_GDTR_READ 0x067 -#define SVM_EXIT_LDTR_READ 0x068 -#define SVM_EXIT_TR_READ 0x069 -#define SVM_EXIT_IDTR_WRITE 0x06a -#define SVM_EXIT_GDTR_WRITE 0x06b -#define SVM_EXIT_LDTR_WRITE 0x06c -#define SVM_EXIT_TR_WRITE 0x06d -#define SVM_EXIT_RDTSC 0x06e -#define SVM_EXIT_RDPMC 0x06f -#define SVM_EXIT_PUSHF 0x070 -#define SVM_EXIT_POPF 0x071 -#define SVM_EXIT_CPUID 0x072 -#define SVM_EXIT_RSM 0x073 -#define SVM_EXIT_IRET 0x074 -#define SVM_EXIT_SWINT 0x075 -#define SVM_EXIT_INVD 0x076 -#define SVM_EXIT_PAUSE 0x077 -#define SVM_EXIT_HLT 0x078 -#define SVM_EXIT_INVLPG 0x079 -#define SVM_EXIT_INVLPGA 0x07a -#define SVM_EXIT_IOIO 0x07b -#define SVM_EXIT_MSR 0x07c -#define SVM_EXIT_TASK_SWITCH 0x07d -#define SVM_EXIT_FERR_FREEZE 0x07e -#define SVM_EXIT_SHUTDOWN 0x07f -#define SVM_EXIT_VMRUN 0x080 -#define SVM_EXIT_VMMCALL 0x081 -#define SVM_EXIT_VMLOAD 0x082 -#define SVM_EXIT_VMSAVE 0x083 -#define SVM_EXIT_STGI 0x084 -#define SVM_EXIT_CLGI 0x085 -#define SVM_EXIT_SKINIT 0x086 -#define SVM_EXIT_RDTSCP 0x087 -#define SVM_EXIT_ICEBP 0x088 -#define SVM_EXIT_WBINVD 0x089 -#define SVM_EXIT_MONITOR 0x08a -#define SVM_EXIT_MWAIT 0x08b -#define SVM_EXIT_MWAIT_COND 0x08c -#define SVM_EXIT_NPF 0x400 - -#define SVM_EXIT_ERR -1 - -#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) // TS and MP - -#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" -#define SVM_VMRUN ".byte 0x0f, 0x01, 0xd8" -#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb" -#define SVM_CLGI ".byte 0x0f, 0x01, 0xdd" -#define SVM_STGI ".byte 0x0f, 0x01, 0xdc" -#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf" - -#endif - diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c deleted file mode 100644 index bb56ae3f89b6..000000000000 --- a/drivers/kvm/vmx.c +++ /dev/null @@ -1,2566 +0,0 @@ -/* - * Kernel-based Virtual Machine driver for Linux - * - * This module enables machines with Intel VT-x extensions to run virtual - * machines without emulation or binary translation. - * - * Copyright (C) 2006 Qumranet, Inc. - * - * Authors: - * Avi Kivity <avi@qumranet.com> - * Yaniv Kamay <yaniv@qumranet.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "kvm.h" -#include "x86_emulate.h" -#include "irq.h" -#include "vmx.h" -#include "segment_descriptor.h" - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/highmem.h> -#include <linux/sched.h> - -#include <asm/io.h> -#include <asm/desc.h> - -MODULE_AUTHOR("Qumranet"); -MODULE_LICENSE("GPL"); - -struct vmcs { - u32 revision_id; - u32 abort; - char data[0]; -}; - -struct vcpu_vmx { - struct kvm_vcpu vcpu; - int launched; - u8 fail; - struct kvm_msr_entry *guest_msrs; - struct kvm_msr_entry *host_msrs; - int nmsrs; - int save_nmsrs; - int msr_offset_efer; -#ifdef CONFIG_X86_64 - int msr_offset_kernel_gs_base; -#endif - struct vmcs *vmcs; - struct { - int loaded; - u16 fs_sel, gs_sel, ldt_sel; - int gs_ldt_reload_needed; - int fs_reload_needed; - }host_state; - -}; - -static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) -{ - return container_of(vcpu, struct vcpu_vmx, vcpu); -} - -static int init_rmode_tss(struct kvm *kvm); - -static DEFINE_PER_CPU(struct vmcs *, vmxarea); -static DEFINE_PER_CPU(struct vmcs *, current_vmcs); - -static struct page *vmx_io_bitmap_a; -static struct page *vmx_io_bitmap_b; - -#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE) - -static struct vmcs_config { - int size; - int order; - u32 revision_id; - u32 pin_based_exec_ctrl; - u32 cpu_based_exec_ctrl; - u32 vmexit_ctrl; - u32 vmentry_ctrl; -} vmcs_config; - -#define VMX_SEGMENT_FIELD(seg) \ - [VCPU_SREG_##seg] = { \ - .selector = GUEST_##seg##_SELECTOR, \ - .base = GUEST_##seg##_BASE, \ - .limit = GUEST_##seg##_LIMIT, \ - .ar_bytes = GUEST_##seg##_AR_BYTES, \ - } - -static struct kvm_vmx_segment_field { - unsigned selector; - unsigned base; - unsigned limit; - unsigned ar_bytes; -} kvm_vmx_segment_fields[] = { - VMX_SEGMENT_FIELD(CS), - VMX_SEGMENT_FIELD(DS), - VMX_SEGMENT_FIELD(ES), - VMX_SEGMENT_FIELD(FS), - VMX_SEGMENT_FIELD(GS), - VMX_SEGMENT_FIELD(SS), - VMX_SEGMENT_FIELD(TR), - VMX_SEGMENT_FIELD(LDTR), -}; - -/* - * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it - * away by decrementing the array size. - */ -static const u32 vmx_msr_index[] = { -#ifdef CONFIG_X86_64 - MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE, -#endif - MSR_EFER, MSR_K6_STAR, -}; -#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) - -static void load_msrs(struct kvm_msr_entry *e, int n) -{ - int i; - - for (i = 0; i < n; ++i) - wrmsrl(e[i].index, e[i].data); -} - -static void save_msrs(struct kvm_msr_entry *e, int n) -{ - int i; - - for (i = 0; i < n; ++i) - rdmsrl(e[i].index, e[i].data); -} - -static inline u64 msr_efer_save_restore_bits(struct kvm_msr_entry msr) -{ - return (u64)msr.data & EFER_SAVE_RESTORE_BITS; -} - -static inline int msr_efer_need_save_restore(struct vcpu_vmx *vmx) -{ - int efer_offset = vmx->msr_offset_efer; - return msr_efer_save_restore_bits(vmx->host_msrs[efer_offset]) != - msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]); -} - -static inline int is_page_fault(u32 intr_info) -{ - return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | - INTR_INFO_VALID_MASK)) == - (INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK); -} - -static inline int is_no_device(u32 intr_info) -{ - return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | - INTR_INFO_VALID_MASK)) == - (INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK); -} - -static inline int is_external_interrupt(u32 intr_info) -{ - return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) - == (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); -} - -static inline int cpu_has_vmx_tpr_shadow(void) -{ - return (vmcs_config.cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW); -} - -static inline int vm_need_tpr_shadow(struct kvm *kvm) -{ - return ((cpu_has_vmx_tpr_shadow()) && (irqchip_in_kernel(kvm))); -} - -static int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) -{ - int i; - - for (i = 0; i < vmx->nmsrs; ++i) - if (vmx->guest_msrs[i].index == msr) - return i; - return -1; -} - -static struct kvm_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) -{ - int i; - - i = __find_msr_index(vmx, msr); - if (i >= 0) - return &vmx->guest_msrs[i]; - return NULL; -} - -static void vmcs_clear(struct vmcs *vmcs) -{ - u64 phys_addr = __pa(vmcs); - u8 error; - - asm volatile (ASM_VMX_VMCLEAR_RAX "; setna %0" - : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) - : "cc", "memory"); - if (error) - printk(KERN_ERR "kvm: vmclear fail: %p/%llx\n", - vmcs, phys_addr); -} - -static void __vcpu_clear(void *arg) -{ - struct vcpu_vmx *vmx = arg; - int cpu = raw_smp_processor_id(); - - if (vmx->vcpu.cpu == cpu) - vmcs_clear(vmx->vmcs); - if (per_cpu(current_vmcs, cpu) == vmx->vmcs) - per_cpu(current_vmcs, cpu) = NULL; - rdtscll(vmx->vcpu.host_tsc); -} - -static void vcpu_clear(struct vcpu_vmx *vmx) -{ - if (vmx->vcpu.cpu != raw_smp_processor_id() && vmx->vcpu.cpu != -1) - smp_call_function_single(vmx->vcpu.cpu, __vcpu_clear, - vmx, 0, 1); - else - __vcpu_clear(vmx); - vmx->launched = 0; -} - -static unsigned long vmcs_readl(unsigned long field) -{ - unsigned long value; - - asm volatile (ASM_VMX_VMREAD_RDX_RAX - : "=a"(value) : "d"(field) : "cc"); - return value; -} - -static u16 vmcs_read16(unsigned long field) -{ - return vmcs_readl(field); -} - -static u32 vmcs_read32(unsigned long field) -{ - return vmcs_readl(field); -} - -static u64 vmcs_read64(unsigned long field) -{ -#ifdef CONFIG_X86_64 - return vmcs_readl(field); -#else - return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32); -#endif -} - -static noinline void vmwrite_error(unsigned long field, unsigned long value) -{ - printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n", - field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); - dump_stack(); -} - -static void vmcs_writel(unsigned long field, unsigned long value) -{ - u8 error; - - asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0" - : "=q"(error) : "a"(value), "d"(field) : "cc" ); - if (unlikely(error)) - vmwrite_error(field, value); -} - -static void vmcs_write16(unsigned long field, u16 value) -{ - vmcs_writel(field, value); -} - -static void vmcs_write32(unsigned long field, u32 value) -{ - vmcs_writel(field, value); -} - -static void vmcs_write64(unsigned long field, u64 value) -{ -#ifdef CONFIG_X86_64 - vmcs_writel(field, value); -#else - vmcs_writel(field, value); - asm volatile (""); - vmcs_writel(field+1, value >> 32); -#endif -} - -static void vmcs_clear_bits(unsigned long field, u32 mask) -{ - vmcs_writel(field, vmcs_readl(field) & ~mask); -} - -static void vmcs_set_bits(unsigned long field, u32 mask) -{ - vmcs_writel(field, vmcs_readl(field) | mask); -} - -static void update_exception_bitmap(struct kvm_vcpu *vcpu) -{ - u32 eb; - - eb = 1u << PF_VECTOR; - if (!vcpu->fpu_active) - eb |= 1u << NM_VECTOR; - if (vcpu->guest_debug.enabled) - eb |= 1u << 1; - if (vcpu->rmode.active) - eb = ~0; - vmcs_write32(EXCEPTION_BITMAP, eb); -} - -static void reload_tss(void) -{ -#ifndef CONFIG_X86_64 - - /* - * VT restores TR but not its size. Useless. - */ - struct descriptor_table gdt; - struct segment_descriptor *descs; - - get_gdt(&gdt); - descs = (void *)gdt.base; - descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ - load_TR_desc(); -#endif -} - -static void load_transition_efer(struct vcpu_vmx *vmx) -{ - u64 trans_efer; - int efer_offset = vmx->msr_offset_efer; - - trans_efer = vmx->host_msrs[efer_offset].data; - trans_efer &= ~EFER_SAVE_RESTORE_BITS; - trans_efer |= msr_efer_save_restore_bits(vmx->guest_msrs[efer_offset]); - wrmsrl(MSR_EFER, trans_efer); - vmx->vcpu.stat.efer_reload++; -} - -static void vmx_save_host_state(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - - if (vmx->host_state.loaded) - return; - - vmx->host_state.loaded = 1; - /* - * Set host fs and gs selectors. Unfortunately, 22.2.3 does not - * allow segment selectors with cpl > 0 or ti == 1. - */ - vmx->host_state.ldt_sel = read_ldt(); - vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel; - vmx->host_state.fs_sel = read_fs(); - if (!(vmx->host_state.fs_sel & 7)) { - vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel); - vmx->host_state.fs_reload_needed = 0; - } else { - vmcs_write16(HOST_FS_SELECTOR, 0); - vmx->host_state.fs_reload_needed = 1; - } - vmx->host_state.gs_sel = read_gs(); - if (!(vmx->host_state.gs_sel & 7)) - vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel); - else { - vmcs_write16(HOST_GS_SELECTOR, 0); - vmx->host_state.gs_ldt_reload_needed = 1; - } - -#ifdef CONFIG_X86_64 - vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE)); - vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE)); -#else - vmcs_writel(HOST_FS_BASE, segment_base(vmx->host_state.fs_sel)); - vmcs_writel(HOST_GS_BASE, segment_base(vmx->host_state.gs_sel)); -#endif - -#ifdef CONFIG_X86_64 - if (is_long_mode(&vmx->vcpu)) { - save_msrs(vmx->host_msrs + - vmx->msr_offset_kernel_gs_base, 1); - } -#endif - load_msrs(vmx->guest_msrs, vmx->save_nmsrs); - if (msr_efer_need_save_restore(vmx)) - load_transition_efer(vmx); -} - -static void vmx_load_host_state(struct vcpu_vmx *vmx) -{ - unsigned long flags; - - if (!vmx->host_state.loaded) - return; - - vmx->host_state.loaded = 0; - if (vmx->host_state.fs_reload_needed) - load_fs(vmx->host_state.fs_sel); - if (vmx->host_state.gs_ldt_reload_needed) { - load_ldt(vmx->host_state.ldt_sel); - /* - * If we have to reload gs, we must take care to - * preserve our gs base. - */ - local_irq_save(flags); - load_gs(vmx->host_state.gs_sel); -#ifdef CONFIG_X86_64 - wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE)); -#endif - local_irq_restore(flags); - } - reload_tss(); - save_msrs(vmx->guest_msrs, vmx->save_nmsrs); - load_msrs(vmx->host_msrs, vmx->save_nmsrs); - if (msr_efer_need_save_restore(vmx)) - load_msrs(vmx->host_msrs + vmx->msr_offset_efer, 1); -} - -/* - * Switches to specified vcpu, until a matching vcpu_put(), but assumes - * vcpu mutex is already taken. - */ -static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - u64 phys_addr = __pa(vmx->vmcs); - u64 tsc_this, delta; - - if (vcpu->cpu != cpu) { - vcpu_clear(vmx); - kvm_migrate_apic_timer(vcpu); - } - - if (per_cpu(current_vmcs, cpu) != vmx->vmcs) { - u8 error; - - per_cpu(current_vmcs, cpu) = vmx->vmcs; - asm volatile (ASM_VMX_VMPTRLD_RAX "; setna %0" - : "=g"(error) : "a"(&phys_addr), "m"(phys_addr) - : "cc"); - if (error) - printk(KERN_ERR "kvm: vmptrld %p/%llx fail\n", - vmx->vmcs, phys_addr); - } - - if (vcpu->cpu != cpu) { - struct descriptor_table dt; - unsigned long sysenter_esp; - - vcpu->cpu = cpu; - /* - * Linux uses per-cpu TSS and GDT, so set these when switching - * processors. - */ - vmcs_writel(HOST_TR_BASE, read_tr_base()); /* 22.2.4 */ - get_gdt(&dt); - vmcs_writel(HOST_GDTR_BASE, dt.base); /* 22.2.4 */ - - rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); - vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ - - /* - * Make sure the time stamp counter is monotonous. - */ - rdtscll(tsc_this); - delta = vcpu->host_tsc - tsc_this; - vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta); - } -} - -static void vmx_vcpu_put(struct kvm_vcpu *vcpu) -{ - vmx_load_host_state(to_vmx(vcpu)); - kvm_put_guest_fpu(vcpu); -} - -static void vmx_fpu_activate(struct kvm_vcpu *vcpu) -{ - if (vcpu->fpu_active) - return; - vcpu->fpu_active = 1; - vmcs_clear_bits(GUEST_CR0, X86_CR0_TS); - if (vcpu->cr0 & X86_CR0_TS) - vmcs_set_bits(GUEST_CR0, X86_CR0_TS); - update_exception_bitmap(vcpu); -} - -static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu) -{ - if (!vcpu->fpu_active) - return; - vcpu->fpu_active = 0; - vmcs_set_bits(GUEST_CR0, X86_CR0_TS); - update_exception_bitmap(vcpu); -} - -static void vmx_vcpu_decache(struct kvm_vcpu *vcpu) -{ - vcpu_clear(to_vmx(vcpu)); -} - -static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) -{ - return vmcs_readl(GUEST_RFLAGS); -} - -static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) -{ - if (vcpu->rmode.active) - rflags |= IOPL_MASK | X86_EFLAGS_VM; - vmcs_writel(GUEST_RFLAGS, rflags); -} - -static void skip_emulated_instruction(struct kvm_vcpu *vcpu) -{ - unsigned long rip; - u32 interruptibility; - - rip = vmcs_readl(GUEST_RIP); - rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); - vmcs_writel(GUEST_RIP, rip); - - /* - * We emulated an instruction, so temporary interrupt blocking - * should be removed, if set. - */ - interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); - if (interruptibility & 3) - vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, - interruptibility & ~3); - vcpu->interrupt_window_open = 1; -} - -static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code) -{ - printk(KERN_DEBUG "inject_general_protection: rip 0x%lx\n", - vmcs_readl(GUEST_RIP)); - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - GP_VECTOR | - INTR_TYPE_EXCEPTION | - INTR_INFO_DELIEVER_CODE_MASK | - INTR_INFO_VALID_MASK); -} - -/* - * Swap MSR entry in host/guest MSR entry array. - */ -#ifdef CONFIG_X86_64 -static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) -{ - struct kvm_msr_entry tmp; - - tmp = vmx->guest_msrs[to]; - vmx->guest_msrs[to] = vmx->guest_msrs[from]; - vmx->guest_msrs[from] = tmp; - tmp = vmx->host_msrs[to]; - vmx->host_msrs[to] = vmx->host_msrs[from]; - vmx->host_msrs[from] = tmp; -} -#endif - -/* - * Set up the vmcs to automatically save and restore system - * msrs. Don't touch the 64-bit msrs if the guest is in legacy - * mode, as fiddling with msrs is very expensive. - */ -static void setup_msrs(struct vcpu_vmx *vmx) -{ - int save_nmsrs; - - save_nmsrs = 0; -#ifdef CONFIG_X86_64 - if (is_long_mode(&vmx->vcpu)) { - int index; - - index = __find_msr_index(vmx, MSR_SYSCALL_MASK); - if (index >= 0) - move_msr_up(vmx, index, save_nmsrs++); - index = __find_msr_index(vmx, MSR_LSTAR); - if (index >= 0) - move_msr_up(vmx, index, save_nmsrs++); - index = __find_msr_index(vmx, MSR_CSTAR); - if (index >= 0) - move_msr_up(vmx, index, save_nmsrs++); - index = __find_msr_index(vmx, MSR_KERNEL_GS_BASE); - if (index >= 0) - move_msr_up(vmx, index, save_nmsrs++); - /* - * MSR_K6_STAR is only needed on long mode guests, and only - * if efer.sce is enabled. - */ - index = __find_msr_index(vmx, MSR_K6_STAR); - if ((index >= 0) && (vmx->vcpu.shadow_efer & EFER_SCE)) - move_msr_up(vmx, index, save_nmsrs++); - } -#endif - vmx->save_nmsrs = save_nmsrs; - -#ifdef CONFIG_X86_64 - vmx->msr_offset_kernel_gs_base = - __find_msr_index(vmx, MSR_KERNEL_GS_BASE); -#endif - vmx->msr_offset_efer = __find_msr_index(vmx, MSR_EFER); -} - -/* - * reads and returns guest's timestamp counter "register" - * guest_tsc = host_tsc + tsc_offset -- 21.3 - */ -static u64 guest_read_tsc(void) -{ - u64 host_tsc, tsc_offset; - - rdtscll(host_tsc); - tsc_offset = vmcs_read64(TSC_OFFSET); - return host_tsc + tsc_offset; -} - -/* - * writes 'guest_tsc' into guest's timestamp counter "register" - * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc - */ -static void guest_write_tsc(u64 guest_tsc) -{ - u64 host_tsc; - - rdtscll(host_tsc); - vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc); -} - -/* - * Reads an msr value (of 'msr_index') into 'pdata'. - * Returns 0 on success, non-0 otherwise. - * Assumes vcpu_load() was already called. - */ -static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata) -{ - u64 data; - struct kvm_msr_entry *msr; - - if (!pdata) { - printk(KERN_ERR "BUG: get_msr called with NULL pdata\n"); - return -EINVAL; - } - - switch (msr_index) { -#ifdef CONFIG_X86_64 - case MSR_FS_BASE: - data = vmcs_readl(GUEST_FS_BASE); - break; - case MSR_GS_BASE: - data = vmcs_readl(GUEST_GS_BASE); - break; - case MSR_EFER: - return kvm_get_msr_common(vcpu, msr_index, pdata); -#endif - case MSR_IA32_TIME_STAMP_COUNTER: - data = guest_read_tsc(); - break; - case MSR_IA32_SYSENTER_CS: - data = vmcs_read32(GUEST_SYSENTER_CS); - break; - case MSR_IA32_SYSENTER_EIP: - data = vmcs_readl(GUEST_SYSENTER_EIP); - break; - case MSR_IA32_SYSENTER_ESP: - data = vmcs_readl(GUEST_SYSENTER_ESP); - break; - default: - msr = find_msr_entry(to_vmx(vcpu), msr_index); - if (msr) { - data = msr->data; - break; - } - return kvm_get_msr_common(vcpu, msr_index, pdata); - } - - *pdata = data; - return 0; -} - -/* - * Writes msr value into into the appropriate "register". - * Returns 0 on success, non-0 otherwise. - * Assumes vcpu_load() was already called. - */ -static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - struct kvm_msr_entry *msr; - int ret = 0; - - switch (msr_index) { -#ifdef CONFIG_X86_64 - case MSR_EFER: - ret = kvm_set_msr_common(vcpu, msr_index, data); - if (vmx->host_state.loaded) - load_transition_efer(vmx); - break; - case MSR_FS_BASE: - vmcs_writel(GUEST_FS_BASE, data); - break; - case MSR_GS_BASE: - vmcs_writel(GUEST_GS_BASE, data); - break; -#endif - case MSR_IA32_SYSENTER_CS: - vmcs_write32(GUEST_SYSENTER_CS, data); - break; - case MSR_IA32_SYSENTER_EIP: - vmcs_writel(GUEST_SYSENTER_EIP, data); - break; - case MSR_IA32_SYSENTER_ESP: - vmcs_writel(GUEST_SYSENTER_ESP, data); - break; - case MSR_IA32_TIME_STAMP_COUNTER: - guest_write_tsc(data); - break; - default: - msr = find_msr_entry(vmx, msr_index); - if (msr) { - msr->data = data; - if (vmx->host_state.loaded) - load_msrs(vmx->guest_msrs, vmx->save_nmsrs); - break; - } - ret = kvm_set_msr_common(vcpu, msr_index, data); - } - - return ret; -} - -/* - * Sync the rsp and rip registers into the vcpu structure. This allows - * registers to be accessed by indexing vcpu->regs. - */ -static void vcpu_load_rsp_rip(struct kvm_vcpu *vcpu) -{ - vcpu->regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP); - vcpu->rip = vmcs_readl(GUEST_RIP); -} - -/* - * Syncs rsp and rip back into the vmcs. Should be called after possible - * modification. - */ -static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu) -{ - vmcs_writel(GUEST_RSP, vcpu->regs[VCPU_REGS_RSP]); - vmcs_writel(GUEST_RIP, vcpu->rip); -} - -static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) -{ - unsigned long dr7 = 0x400; - int old_singlestep; - - old_singlestep = vcpu->guest_debug.singlestep; - - vcpu->guest_debug.enabled = dbg->enabled; - if (vcpu->guest_debug.enabled) { - int i; - - dr7 |= 0x200; /* exact */ - for (i = 0; i < 4; ++i) { - if (!dbg->breakpoints[i].enabled) - continue; - vcpu->guest_debug.bp[i] = dbg->breakpoints[i].address; - dr7 |= 2 << (i*2); /* global enable */ - dr7 |= 0 << (i*4+16); /* execution breakpoint */ - } - - vcpu->guest_debug.singlestep = dbg->singlestep; - } else - vcpu->guest_debug.singlestep = 0; - - if (old_singlestep && !vcpu->guest_debug.singlestep) { - unsigned long flags; - - flags = vmcs_readl(GUEST_RFLAGS); - flags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); - vmcs_writel(GUEST_RFLAGS, flags); - } - - update_exception_bitmap(vcpu); - vmcs_writel(GUEST_DR7, dr7); - - return 0; -} - -static int vmx_get_irq(struct kvm_vcpu *vcpu) -{ - u32 idtv_info_field; - - idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); - if (idtv_info_field & INTR_INFO_VALID_MASK) { - if (is_external_interrupt(idtv_info_field)) - return idtv_info_field & VECTORING_INFO_VECTOR_MASK; - else - printk("pending exception: not handled yet\n"); - } - return -1; -} - -static __init int cpu_has_kvm_support(void) -{ - unsigned long ecx = cpuid_ecx(1); - return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */ -} - -static __init int vmx_disabled_by_bios(void) -{ - u64 msr; - - rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); - return (msr & (MSR_IA32_FEATURE_CONTROL_LOCKED | - MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) - == MSR_IA32_FEATURE_CONTROL_LOCKED; - /* locked but not enabled */ -} - -static void hardware_enable(void *garbage) -{ - int cpu = raw_smp_processor_id(); - u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); - u64 old; - - rdmsrl(MSR_IA32_FEATURE_CONTROL, old); - if ((old & (MSR_IA32_FEATURE_CONTROL_LOCKED | - MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) - != (MSR_IA32_FEATURE_CONTROL_LOCKED | - MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED)) - /* enable and lock */ - wrmsrl(MSR_IA32_FEATURE_CONTROL, old | - MSR_IA32_FEATURE_CONTROL_LOCKED | - MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED); - write_cr4(read_cr4() | X86_CR4_VMXE); /* FIXME: not cpu hotplug safe */ - asm volatile (ASM_VMX_VMXON_RAX : : "a"(&phys_addr), "m"(phys_addr) - : "memory", "cc"); -} - -static void hardware_disable(void *garbage) -{ - asm volatile (ASM_VMX_VMXOFF : : : "cc"); -} - -static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, - u32 msr, u32* result) -{ - u32 vmx_msr_low, vmx_msr_high; - u32 ctl = ctl_min | ctl_opt; - - rdmsr(msr, vmx_msr_low, vmx_msr_high); - - ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ - ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ - - /* Ensure minimum (required) set of control bits are supported. */ - if (ctl_min & ~ctl) - return -EIO; - - *result = ctl; - return 0; -} - -static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf) -{ - u32 vmx_msr_low, vmx_msr_high; - u32 min, opt; - u32 _pin_based_exec_control = 0; - u32 _cpu_based_exec_control = 0; - u32 _vmexit_control = 0; - u32 _vmentry_control = 0; - - min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; - opt = 0; - if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, - &_pin_based_exec_control) < 0) - return -EIO; - - min = CPU_BASED_HLT_EXITING | -#ifdef CONFIG_X86_64 - CPU_BASED_CR8_LOAD_EXITING | - CPU_BASED_CR8_STORE_EXITING | -#endif - CPU_BASED_USE_IO_BITMAPS | - CPU_BASED_MOV_DR_EXITING | - CPU_BASED_USE_TSC_OFFSETING; -#ifdef CONFIG_X86_64 - opt = CPU_BASED_TPR_SHADOW; -#else - opt = 0; -#endif - if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, - &_cpu_based_exec_control) < 0) - return -EIO; -#ifdef CONFIG_X86_64 - if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)) - _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & - ~CPU_BASED_CR8_STORE_EXITING; -#endif - - min = 0; -#ifdef CONFIG_X86_64 - min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; -#endif - opt = 0; - if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, - &_vmexit_control) < 0) - return -EIO; - - min = opt = 0; - if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, - &_vmentry_control) < 0) - return -EIO; - - rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); - - /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ - if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) - return -EIO; - -#ifdef CONFIG_X86_64 - /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ - if (vmx_msr_high & (1u<<16)) - return -EIO; -#endif - - /* Require Write-Back (WB) memory type for VMCS accesses. */ - if (((vmx_msr_high >> 18) & 15) != 6) - return -EIO; - - vmcs_conf->size = vmx_msr_high & 0x1fff; - vmcs_conf->order = get_order(vmcs_config.size); - vmcs_conf->revision_id = vmx_msr_low; - - vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; - vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; - vmcs_conf->vmexit_ctrl = _vmexit_control; - vmcs_conf->vmentry_ctrl = _vmentry_control; - - return 0; -} - -static struct vmcs *alloc_vmcs_cpu(int cpu) -{ - int node = cpu_to_node(cpu); - struct page *pages; - struct vmcs *vmcs; - - pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); - if (!pages) - return NULL; - vmcs = page_address(pages); - memset(vmcs, 0, vmcs_config.size); - vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */ - return vmcs; -} - -static struct vmcs *alloc_vmcs(void) -{ - return alloc_vmcs_cpu(raw_smp_processor_id()); -} - -static void free_vmcs(struct vmcs *vmcs) -{ - free_pages((unsigned long)vmcs, vmcs_config.order); -} - -static void free_kvm_area(void) -{ - int cpu; - - for_each_online_cpu(cpu) - free_vmcs(per_cpu(vmxarea, cpu)); -} - -static __init int alloc_kvm_area(void) -{ - int cpu; - - for_each_online_cpu(cpu) { - struct vmcs *vmcs; - - vmcs = alloc_vmcs_cpu(cpu); - if (!vmcs) { - free_kvm_area(); - return -ENOMEM; - } - - per_cpu(vmxarea, cpu) = vmcs; - } - return 0; -} - -static __init int hardware_setup(void) -{ - if (setup_vmcs_config(&vmcs_config) < 0) - return -EIO; - return alloc_kvm_area(); -} - -static __exit void hardware_unsetup(void) -{ - free_kvm_area(); -} - -static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save) -{ - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - - if (vmcs_readl(sf->base) == save->base && (save->base & AR_S_MASK)) { - vmcs_write16(sf->selector, save->selector); - vmcs_writel(sf->base, save->base); - vmcs_write32(sf->limit, save->limit); - vmcs_write32(sf->ar_bytes, save->ar); - } else { - u32 dpl = (vmcs_read16(sf->selector) & SELECTOR_RPL_MASK) - << AR_DPL_SHIFT; - vmcs_write32(sf->ar_bytes, 0x93 | dpl); - } -} - -static void enter_pmode(struct kvm_vcpu *vcpu) -{ - unsigned long flags; - - vcpu->rmode.active = 0; - - vmcs_writel(GUEST_TR_BASE, vcpu->rmode.tr.base); - vmcs_write32(GUEST_TR_LIMIT, vcpu->rmode.tr.limit); - vmcs_write32(GUEST_TR_AR_BYTES, vcpu->rmode.tr.ar); - - flags = vmcs_readl(GUEST_RFLAGS); - flags &= ~(IOPL_MASK | X86_EFLAGS_VM); - flags |= (vcpu->rmode.save_iopl << IOPL_SHIFT); - vmcs_writel(GUEST_RFLAGS, flags); - - vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | - (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME)); - - update_exception_bitmap(vcpu); - - fix_pmode_dataseg(VCPU_SREG_ES, &vcpu->rmode.es); - fix_pmode_dataseg(VCPU_SREG_DS, &vcpu->rmode.ds); - fix_pmode_dataseg(VCPU_SREG_GS, &vcpu->rmode.gs); - fix_pmode_dataseg(VCPU_SREG_FS, &vcpu->rmode.fs); - - vmcs_write16(GUEST_SS_SELECTOR, 0); - vmcs_write32(GUEST_SS_AR_BYTES, 0x93); - - vmcs_write16(GUEST_CS_SELECTOR, - vmcs_read16(GUEST_CS_SELECTOR) & ~SELECTOR_RPL_MASK); - vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); -} - -static gva_t rmode_tss_base(struct kvm* kvm) -{ - gfn_t base_gfn = kvm->memslots[0].base_gfn + kvm->memslots[0].npages - 3; - return base_gfn << PAGE_SHIFT; -} - -static void fix_rmode_seg(int seg, struct kvm_save_segment *save) -{ - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - - save->selector = vmcs_read16(sf->selector); - save->base = vmcs_readl(sf->base); - save->limit = vmcs_read32(sf->limit); - save->ar = vmcs_read32(sf->ar_bytes); - vmcs_write16(sf->selector, vmcs_readl(sf->base) >> 4); - vmcs_write32(sf->limit, 0xffff); - vmcs_write32(sf->ar_bytes, 0xf3); -} - -static void enter_rmode(struct kvm_vcpu *vcpu) -{ - unsigned long flags; - - vcpu->rmode.active = 1; - - vcpu->rmode.tr.base = vmcs_readl(GUEST_TR_BASE); - vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm)); - - vcpu->rmode.tr.limit = vmcs_read32(GUEST_TR_LIMIT); - vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); - - vcpu->rmode.tr.ar = vmcs_read32(GUEST_TR_AR_BYTES); - vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); - - flags = vmcs_readl(GUEST_RFLAGS); - vcpu->rmode.save_iopl = (flags & IOPL_MASK) >> IOPL_SHIFT; - - flags |= IOPL_MASK | X86_EFLAGS_VM; - - vmcs_writel(GUEST_RFLAGS, flags); - vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME); - update_exception_bitmap(vcpu); - - vmcs_write16(GUEST_SS_SELECTOR, vmcs_readl(GUEST_SS_BASE) >> 4); - vmcs_write32(GUEST_SS_LIMIT, 0xffff); - vmcs_write32(GUEST_SS_AR_BYTES, 0xf3); - - vmcs_write32(GUEST_CS_AR_BYTES, 0xf3); - vmcs_write32(GUEST_CS_LIMIT, 0xffff); - if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000) - vmcs_writel(GUEST_CS_BASE, 0xf0000); - vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4); - - fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es); - fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds); - fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs); - fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs); - - kvm_mmu_reset_context(vcpu); - init_rmode_tss(vcpu->kvm); -} - -#ifdef CONFIG_X86_64 - -static void enter_lmode(struct kvm_vcpu *vcpu) -{ - u32 guest_tr_ar; - - guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); - if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) { - printk(KERN_DEBUG "%s: tss fixup for long mode. \n", - __FUNCTION__); - vmcs_write32(GUEST_TR_AR_BYTES, - (guest_tr_ar & ~AR_TYPE_MASK) - | AR_TYPE_BUSY_64_TSS); - } - - vcpu->shadow_efer |= EFER_LMA; - - find_msr_entry(to_vmx(vcpu), MSR_EFER)->data |= EFER_LMA | EFER_LME; - vmcs_write32(VM_ENTRY_CONTROLS, - vmcs_read32(VM_ENTRY_CONTROLS) - | VM_ENTRY_IA32E_MODE); -} - -static void exit_lmode(struct kvm_vcpu *vcpu) -{ - vcpu->shadow_efer &= ~EFER_LMA; - - vmcs_write32(VM_ENTRY_CONTROLS, - vmcs_read32(VM_ENTRY_CONTROLS) - & ~VM_ENTRY_IA32E_MODE); -} - -#endif - -static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) -{ - vcpu->cr4 &= KVM_GUEST_CR4_MASK; - vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK; -} - -static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) -{ - vmx_fpu_deactivate(vcpu); - - if (vcpu->rmode.active && (cr0 & X86_CR0_PE)) - enter_pmode(vcpu); - - if (!vcpu->rmode.active && !(cr0 & X86_CR0_PE)) - enter_rmode(vcpu); - -#ifdef CONFIG_X86_64 - if (vcpu->shadow_efer & EFER_LME) { - if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) - enter_lmode(vcpu); - if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) - exit_lmode(vcpu); - } -#endif - - vmcs_writel(CR0_READ_SHADOW, cr0); - vmcs_writel(GUEST_CR0, - (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON); - vcpu->cr0 = cr0; - - if (!(cr0 & X86_CR0_TS) || !(cr0 & X86_CR0_PE)) - vmx_fpu_activate(vcpu); -} - -static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) -{ - vmcs_writel(GUEST_CR3, cr3); - if (vcpu->cr0 & X86_CR0_PE) - vmx_fpu_deactivate(vcpu); -} - -static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) -{ - vmcs_writel(CR4_READ_SHADOW, cr4); - vmcs_writel(GUEST_CR4, cr4 | (vcpu->rmode.active ? - KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON)); - vcpu->cr4 = cr4; -} - -#ifdef CONFIG_X86_64 - -static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - struct kvm_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); - - vcpu->shadow_efer = efer; - if (efer & EFER_LMA) { - vmcs_write32(VM_ENTRY_CONTROLS, - vmcs_read32(VM_ENTRY_CONTROLS) | - VM_ENTRY_IA32E_MODE); - msr->data = efer; - - } else { - vmcs_write32(VM_ENTRY_CONTROLS, - vmcs_read32(VM_ENTRY_CONTROLS) & - ~VM_ENTRY_IA32E_MODE); - - msr->data = efer & ~EFER_LME; - } - setup_msrs(vmx); -} - -#endif - -static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg) -{ - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - - return vmcs_readl(sf->base); -} - -static void vmx_get_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) -{ - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - u32 ar; - - var->base = vmcs_readl(sf->base); - var->limit = vmcs_read32(sf->limit); - var->selector = vmcs_read16(sf->selector); - ar = vmcs_read32(sf->ar_bytes); - if (ar & AR_UNUSABLE_MASK) - ar = 0; - var->type = ar & 15; - var->s = (ar >> 4) & 1; - var->dpl = (ar >> 5) & 3; - var->present = (ar >> 7) & 1; - var->avl = (ar >> 12) & 1; - var->l = (ar >> 13) & 1; - var->db = (ar >> 14) & 1; - var->g = (ar >> 15) & 1; - var->unusable = (ar >> 16) & 1; -} - -static u32 vmx_segment_access_rights(struct kvm_segment *var) -{ - u32 ar; - - if (var->unusable) - ar = 1 << 16; - else { - ar = var->type & 15; - ar |= (var->s & 1) << 4; - ar |= (var->dpl & 3) << 5; - ar |= (var->present & 1) << 7; - ar |= (var->avl & 1) << 12; - ar |= (var->l & 1) << 13; - ar |= (var->db & 1) << 14; - ar |= (var->g & 1) << 15; - } - if (ar == 0) /* a 0 value means unusable */ - ar = AR_UNUSABLE_MASK; - - return ar; -} - -static void vmx_set_segment(struct kvm_vcpu *vcpu, - struct kvm_segment *var, int seg) -{ - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - u32 ar; - - if (vcpu->rmode.active && seg == VCPU_SREG_TR) { - vcpu->rmode.tr.selector = var->selector; - vcpu->rmode.tr.base = var->base; - vcpu->rmode.tr.limit = var->limit; - vcpu->rmode.tr.ar = vmx_segment_access_rights(var); - return; - } - vmcs_writel(sf->base, var->base); - vmcs_write32(sf->limit, var->limit); - vmcs_write16(sf->selector, var->selector); - if (vcpu->rmode.active && var->s) { - /* - * Hack real-mode segments into vm86 compatibility. - */ - if (var->base == 0xffff0000 && var->selector == 0xf000) - vmcs_writel(sf->base, 0xf0000); - ar = 0xf3; - } else - ar = vmx_segment_access_rights(var); - vmcs_write32(sf->ar_bytes, ar); -} - -static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l) -{ - u32 ar = vmcs_read32(GUEST_CS_AR_BYTES); - - *db = (ar >> 14) & 1; - *l = (ar >> 13) & 1; -} - -static void vmx_get_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - dt->limit = vmcs_read32(GUEST_IDTR_LIMIT); - dt->base = vmcs_readl(GUEST_IDTR_BASE); -} - -static void vmx_set_idt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - vmcs_write32(GUEST_IDTR_LIMIT, dt->limit); - vmcs_writel(GUEST_IDTR_BASE, dt->base); -} - -static void vmx_get_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - dt->limit = vmcs_read32(GUEST_GDTR_LIMIT); - dt->base = vmcs_readl(GUEST_GDTR_BASE); -} - -static void vmx_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt) -{ - vmcs_write32(GUEST_GDTR_LIMIT, dt->limit); - vmcs_writel(GUEST_GDTR_BASE, dt->base); -} - -static int init_rmode_tss(struct kvm* kvm) -{ - struct page *p1, *p2, *p3; - gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT; - char *page; - - p1 = gfn_to_page(kvm, fn++); - p2 = gfn_to_page(kvm, fn++); - p3 = gfn_to_page(kvm, fn); - - if (!p1 || !p2 || !p3) { - kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__); - return 0; - } - - page = kmap_atomic(p1, KM_USER0); - clear_page(page); - *(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE; - kunmap_atomic(page, KM_USER0); - - page = kmap_atomic(p2, KM_USER0); - clear_page(page); - kunmap_atomic(page, KM_USER0); - - page = kmap_atomic(p3, KM_USER0); - clear_page(page); - *(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0; - kunmap_atomic(page, KM_USER0); - - return 1; -} - -static void seg_setup(int seg) -{ - struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; - - vmcs_write16(sf->selector, 0); - vmcs_writel(sf->base, 0); - vmcs_write32(sf->limit, 0xffff); - vmcs_write32(sf->ar_bytes, 0x93); -} - -/* - * Sets up the vmcs for emulated real mode. - */ -static int vmx_vcpu_setup(struct vcpu_vmx *vmx) -{ - u32 host_sysenter_cs; - u32 junk; - unsigned long a; - struct descriptor_table dt; - int i; - int ret = 0; - unsigned long kvm_vmx_return; - u64 msr; - u32 exec_control; - - if (!init_rmode_tss(vmx->vcpu.kvm)) { - ret = -ENOMEM; - goto out; - } - - vmx->vcpu.rmode.active = 0; - - vmx->vcpu.regs[VCPU_REGS_RDX] = get_rdx_init_val(); - set_cr8(&vmx->vcpu, 0); - msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; - if (vmx->vcpu.vcpu_id == 0) - msr |= MSR_IA32_APICBASE_BSP; - kvm_set_apic_base(&vmx->vcpu, msr); - - fx_init(&vmx->vcpu); - - /* - * GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode - * insists on having GUEST_CS_BASE == GUEST_CS_SELECTOR << 4. Sigh. - */ - if (vmx->vcpu.vcpu_id == 0) { - vmcs_write16(GUEST_CS_SELECTOR, 0xf000); - vmcs_writel(GUEST_CS_BASE, 0x000f0000); - } else { - vmcs_write16(GUEST_CS_SELECTOR, vmx->vcpu.sipi_vector << 8); - vmcs_writel(GUEST_CS_BASE, vmx->vcpu.sipi_vector << 12); - } - vmcs_write32(GUEST_CS_LIMIT, 0xffff); - vmcs_write32(GUEST_CS_AR_BYTES, 0x9b); - - seg_setup(VCPU_SREG_DS); - seg_setup(VCPU_SREG_ES); - seg_setup(VCPU_SREG_FS); - seg_setup(VCPU_SREG_GS); - seg_setup(VCPU_SREG_SS); - - vmcs_write16(GUEST_TR_SELECTOR, 0); - vmcs_writel(GUEST_TR_BASE, 0); - vmcs_write32(GUEST_TR_LIMIT, 0xffff); - vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); - - vmcs_write16(GUEST_LDTR_SELECTOR, 0); - vmcs_writel(GUEST_LDTR_BASE, 0); - vmcs_write32(GUEST_LDTR_LIMIT, 0xffff); - vmcs_write32(GUEST_LDTR_AR_BYTES, 0x00082); - - vmcs_write32(GUEST_SYSENTER_CS, 0); - vmcs_writel(GUEST_SYSENTER_ESP, 0); - vmcs_writel(GUEST_SYSENTER_EIP, 0); - - vmcs_writel(GUEST_RFLAGS, 0x02); - if (vmx->vcpu.vcpu_id == 0) - vmcs_writel(GUEST_RIP, 0xfff0); - else - vmcs_writel(GUEST_RIP, 0); - vmcs_writel(GUEST_RSP, 0); - - //todo: dr0 = dr1 = dr2 = dr3 = 0; dr6 = 0xffff0ff0 - vmcs_writel(GUEST_DR7, 0x400); - - vmcs_writel(GUEST_GDTR_BASE, 0); - vmcs_write32(GUEST_GDTR_LIMIT, 0xffff); - - vmcs_writel(GUEST_IDTR_BASE, 0); - vmcs_write32(GUEST_IDTR_LIMIT, 0xffff); - - vmcs_write32(GUEST_ACTIVITY_STATE, 0); - vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); - vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0); - - /* I/O */ - vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a)); - vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b)); - - guest_write_tsc(0); - - vmcs_write64(VMCS_LINK_POINTER, -1ull); /* 22.3.1.5 */ - - /* Special registers */ - vmcs_write64(GUEST_IA32_DEBUGCTL, 0); - - /* Control */ - vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, - vmcs_config.pin_based_exec_ctrl); - - exec_control = vmcs_config.cpu_based_exec_ctrl; - if (!vm_need_tpr_shadow(vmx->vcpu.kvm)) { - exec_control &= ~CPU_BASED_TPR_SHADOW; -#ifdef CONFIG_X86_64 - exec_control |= CPU_BASED_CR8_STORE_EXITING | - CPU_BASED_CR8_LOAD_EXITING; -#endif - } - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, exec_control); - - vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); - vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); - vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ - - vmcs_writel(HOST_CR0, read_cr0()); /* 22.2.3 */ - vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */ - vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */ - - vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS); /* 22.2.4 */ - vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ - vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS); /* 22.2.4 */ - vmcs_write16(HOST_FS_SELECTOR, read_fs()); /* 22.2.4 */ - vmcs_write16(HOST_GS_SELECTOR, read_gs()); /* 22.2.4 */ - vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS); /* 22.2.4 */ -#ifdef CONFIG_X86_64 - rdmsrl(MSR_FS_BASE, a); - vmcs_writel(HOST_FS_BASE, a); /* 22.2.4 */ - rdmsrl(MSR_GS_BASE, a); - vmcs_writel(HOST_GS_BASE, a); /* 22.2.4 */ -#else - vmcs_writel(HOST_FS_BASE, 0); /* 22.2.4 */ - vmcs_writel(HOST_GS_BASE, 0); /* 22.2.4 */ -#endif - - vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8); /* 22.2.4 */ - - get_idt(&dt); - vmcs_writel(HOST_IDTR_BASE, dt.base); /* 22.2.4 */ - - asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return)); - vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ - vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); - vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); - vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); - - rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); - vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); - rdmsrl(MSR_IA32_SYSENTER_ESP, a); - vmcs_writel(HOST_IA32_SYSENTER_ESP, a); /* 22.2.3 */ - rdmsrl(MSR_IA32_SYSENTER_EIP, a); - vmcs_writel(HOST_IA32_SYSENTER_EIP, a); /* 22.2.3 */ - - for (i = 0; i < NR_VMX_MSR; ++i) { - u32 index = vmx_msr_index[i]; - u32 data_low, data_high; - u64 data; - int j = vmx->nmsrs; - - if (rdmsr_safe(index, &data_low, &data_high) < 0) - continue; - if (wrmsr_safe(index, data_low, data_high) < 0) - continue; - data = data_low | ((u64)data_high << 32); - vmx->host_msrs[j].index = index; - vmx->host_msrs[j].reserved = 0; - vmx->host_msrs[j].data = data; - vmx->guest_msrs[j] = vmx->host_msrs[j]; - ++vmx->nmsrs; - } - - setup_msrs(vmx); - - vmcs_write32(VM_EXIT_CONTROLS, vmcs_config.vmexit_ctrl); - - /* 22.2.1, 20.8.1 */ - vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl); - - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); /* 22.2.1 */ - -#ifdef CONFIG_X86_64 - vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, 0); - if (vm_need_tpr_shadow(vmx->vcpu.kvm)) - vmcs_write64(VIRTUAL_APIC_PAGE_ADDR, - page_to_phys(vmx->vcpu.apic->regs_page)); - vmcs_write32(TPR_THRESHOLD, 0); -#endif - - vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); - vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); - - vmx->vcpu.cr0 = 0x60000010; - vmx_set_cr0(&vmx->vcpu, vmx->vcpu.cr0); // enter rmode - vmx_set_cr4(&vmx->vcpu, 0); -#ifdef CONFIG_X86_64 - vmx_set_efer(&vmx->vcpu, 0); -#endif - vmx_fpu_activate(&vmx->vcpu); - update_exception_bitmap(&vmx->vcpu); - - return 0; - -out: - return ret; -} - -static void vmx_vcpu_reset(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - - vmx_vcpu_setup(vmx); -} - -static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq) -{ - u16 ent[2]; - u16 cs; - u16 ip; - unsigned long flags; - unsigned long ss_base = vmcs_readl(GUEST_SS_BASE); - u16 sp = vmcs_readl(GUEST_RSP); - u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT); - - if (sp > ss_limit || sp < 6 ) { - vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n", - __FUNCTION__, - vmcs_readl(GUEST_RSP), - vmcs_readl(GUEST_SS_BASE), - vmcs_read32(GUEST_SS_LIMIT)); - return; - } - - if (emulator_read_std(irq * sizeof(ent), &ent, sizeof(ent), vcpu) != - X86EMUL_CONTINUE) { - vcpu_printf(vcpu, "%s: read guest err\n", __FUNCTION__); - return; - } - - flags = vmcs_readl(GUEST_RFLAGS); - cs = vmcs_readl(GUEST_CS_BASE) >> 4; - ip = vmcs_readl(GUEST_RIP); - - - if (emulator_write_emulated(ss_base + sp - 2, &flags, 2, vcpu) != X86EMUL_CONTINUE || - emulator_write_emulated(ss_base + sp - 4, &cs, 2, vcpu) != X86EMUL_CONTINUE || - emulator_write_emulated(ss_base + sp - 6, &ip, 2, vcpu) != X86EMUL_CONTINUE) { - vcpu_printf(vcpu, "%s: write guest err\n", __FUNCTION__); - return; - } - - vmcs_writel(GUEST_RFLAGS, flags & - ~( X86_EFLAGS_IF | X86_EFLAGS_AC | X86_EFLAGS_TF)); - vmcs_write16(GUEST_CS_SELECTOR, ent[1]) ; - vmcs_writel(GUEST_CS_BASE, ent[1] << 4); - vmcs_writel(GUEST_RIP, ent[0]); - vmcs_writel(GUEST_RSP, (vmcs_readl(GUEST_RSP) & ~0xffff) | (sp - 6)); -} - -static void vmx_inject_irq(struct kvm_vcpu *vcpu, int irq) -{ - if (vcpu->rmode.active) { - inject_rmode_irq(vcpu, irq); - return; - } - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - irq | INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK); -} - -static void kvm_do_inject_irq(struct kvm_vcpu *vcpu) -{ - int word_index = __ffs(vcpu->irq_summary); - int bit_index = __ffs(vcpu->irq_pending[word_index]); - int irq = word_index * BITS_PER_LONG + bit_index; - - clear_bit(bit_index, &vcpu->irq_pending[word_index]); - if (!vcpu->irq_pending[word_index]) - clear_bit(word_index, &vcpu->irq_summary); - vmx_inject_irq(vcpu, irq); -} - - -static void do_interrupt_requests(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - u32 cpu_based_vm_exec_control; - - vcpu->interrupt_window_open = - ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && - (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); - - if (vcpu->interrupt_window_open && - vcpu->irq_summary && - !(vmcs_read32(VM_ENTRY_INTR_INFO_FIELD) & INTR_INFO_VALID_MASK)) - /* - * If interrupts enabled, and not blocked by sti or mov ss. Good. - */ - kvm_do_inject_irq(vcpu); - - cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); - if (!vcpu->interrupt_window_open && - (vcpu->irq_summary || kvm_run->request_interrupt_window)) - /* - * Interrupts blocked. Wait for unblock. - */ - cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; - else - cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); -} - -static void kvm_guest_debug_pre(struct kvm_vcpu *vcpu) -{ - struct kvm_guest_debug *dbg = &vcpu->guest_debug; - - set_debugreg(dbg->bp[0], 0); - set_debugreg(dbg->bp[1], 1); - set_debugreg(dbg->bp[2], 2); - set_debugreg(dbg->bp[3], 3); - - if (dbg->singlestep) { - unsigned long flags; - - flags = vmcs_readl(GUEST_RFLAGS); - flags |= X86_EFLAGS_TF | X86_EFLAGS_RF; - vmcs_writel(GUEST_RFLAGS, flags); - } -} - -static int handle_rmode_exception(struct kvm_vcpu *vcpu, - int vec, u32 err_code) -{ - if (!vcpu->rmode.active) - return 0; - - /* - * Instruction with address size override prefix opcode 0x67 - * Cause the #SS fault with 0 error code in VM86 mode. - */ - if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0) - if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE) - return 1; - return 0; -} - -static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - u32 intr_info, error_code; - unsigned long cr2, rip; - u32 vect_info; - enum emulation_result er; - int r; - - vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); - intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - - if ((vect_info & VECTORING_INFO_VALID_MASK) && - !is_page_fault(intr_info)) { - printk(KERN_ERR "%s: unexpected, vectoring info 0x%x " - "intr info 0x%x\n", __FUNCTION__, vect_info, intr_info); - } - - if (!irqchip_in_kernel(vcpu->kvm) && is_external_interrupt(vect_info)) { - int irq = vect_info & VECTORING_INFO_VECTOR_MASK; - set_bit(irq, vcpu->irq_pending); - set_bit(irq / BITS_PER_LONG, &vcpu->irq_summary); - } - - if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ - return 1; /* already handled by vmx_vcpu_run() */ - - if (is_no_device(intr_info)) { - vmx_fpu_activate(vcpu); - return 1; - } - - error_code = 0; - rip = vmcs_readl(GUEST_RIP); - if (intr_info & INTR_INFO_DELIEVER_CODE_MASK) - error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); - if (is_page_fault(intr_info)) { - cr2 = vmcs_readl(EXIT_QUALIFICATION); - - mutex_lock(&vcpu->kvm->lock); - r = kvm_mmu_page_fault(vcpu, cr2, error_code); - if (r < 0) { - mutex_unlock(&vcpu->kvm->lock); - return r; - } - if (!r) { - mutex_unlock(&vcpu->kvm->lock); - return 1; - } - - er = emulate_instruction(vcpu, kvm_run, cr2, error_code); - mutex_unlock(&vcpu->kvm->lock); - - switch (er) { - case EMULATE_DONE: - return 1; - case EMULATE_DO_MMIO: - ++vcpu->stat.mmio_exits; - return 0; - case EMULATE_FAIL: - kvm_report_emulation_failure(vcpu, "pagetable"); - break; - default: - BUG(); - } - } - - if (vcpu->rmode.active && - handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK, - error_code)) { - if (vcpu->halt_request) { - vcpu->halt_request = 0; - return kvm_emulate_halt(vcpu); - } - return 1; - } - - if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) { - kvm_run->exit_reason = KVM_EXIT_DEBUG; - return 0; - } - kvm_run->exit_reason = KVM_EXIT_EXCEPTION; - kvm_run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK; - kvm_run->ex.error_code = error_code; - return 0; -} - -static int handle_external_interrupt(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - ++vcpu->stat.irq_exits; - return 1; -} - -static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; - return 0; -} - -static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - unsigned long exit_qualification; - int size, down, in, string, rep; - unsigned port; - - ++vcpu->stat.io_exits; - exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - string = (exit_qualification & 16) != 0; - - if (string) { - if (emulate_instruction(vcpu, kvm_run, 0, 0) == EMULATE_DO_MMIO) - return 0; - return 1; - } - - size = (exit_qualification & 7) + 1; - in = (exit_qualification & 8) != 0; - down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0; - rep = (exit_qualification & 32) != 0; - port = exit_qualification >> 16; - - return kvm_emulate_pio(vcpu, kvm_run, in, size, port); -} - -static void -vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) -{ - /* - * Patch in the VMCALL instruction: - */ - hypercall[0] = 0x0f; - hypercall[1] = 0x01; - hypercall[2] = 0xc1; - hypercall[3] = 0xc3; -} - -static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - unsigned long exit_qualification; - int cr; - int reg; - - exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - cr = exit_qualification & 15; - reg = (exit_qualification >> 8) & 15; - switch ((exit_qualification >> 4) & 3) { - case 0: /* mov to cr */ - switch (cr) { - case 0: - vcpu_load_rsp_rip(vcpu); - set_cr0(vcpu, vcpu->regs[reg]); - skip_emulated_instruction(vcpu); - return 1; - case 3: - vcpu_load_rsp_rip(vcpu); - set_cr3(vcpu, vcpu->regs[reg]); - skip_emulated_instruction(vcpu); - return 1; - case 4: - vcpu_load_rsp_rip(vcpu); - set_cr4(vcpu, vcpu->regs[reg]); - skip_emulated_instruction(vcpu); - return 1; - case 8: - vcpu_load_rsp_rip(vcpu); - set_cr8(vcpu, vcpu->regs[reg]); - skip_emulated_instruction(vcpu); - kvm_run->exit_reason = KVM_EXIT_SET_TPR; - return 0; - }; - break; - case 2: /* clts */ - vcpu_load_rsp_rip(vcpu); - vmx_fpu_deactivate(vcpu); - vcpu->cr0 &= ~X86_CR0_TS; - vmcs_writel(CR0_READ_SHADOW, vcpu->cr0); - vmx_fpu_activate(vcpu); - skip_emulated_instruction(vcpu); - return 1; - case 1: /*mov from cr*/ - switch (cr) { - case 3: - vcpu_load_rsp_rip(vcpu); - vcpu->regs[reg] = vcpu->cr3; - vcpu_put_rsp_rip(vcpu); - skip_emulated_instruction(vcpu); - return 1; - case 8: - vcpu_load_rsp_rip(vcpu); - vcpu->regs[reg] = get_cr8(vcpu); - vcpu_put_rsp_rip(vcpu); - skip_emulated_instruction(vcpu); - return 1; - } - break; - case 3: /* lmsw */ - lmsw(vcpu, (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f); - - skip_emulated_instruction(vcpu); - return 1; - default: - break; - } - kvm_run->exit_reason = 0; - pr_unimpl(vcpu, "unhandled control register: op %d cr %d\n", - (int)(exit_qualification >> 4) & 3, cr); - return 0; -} - -static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - unsigned long exit_qualification; - unsigned long val; - int dr, reg; - - /* - * FIXME: this code assumes the host is debugging the guest. - * need to deal with guest debugging itself too. - */ - exit_qualification = vmcs_readl(EXIT_QUALIFICATION); - dr = exit_qualification & 7; - reg = (exit_qualification >> 8) & 15; - vcpu_load_rsp_rip(vcpu); - if (exit_qualification & 16) { - /* mov from dr */ - switch (dr) { - case 6: - val = 0xffff0ff0; - break; - case 7: - val = 0x400; - break; - default: - val = 0; - } - vcpu->regs[reg] = val; - } else { - /* mov to dr */ - } - vcpu_put_rsp_rip(vcpu); - skip_emulated_instruction(vcpu); - return 1; -} - -static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - kvm_emulate_cpuid(vcpu); - return 1; -} - -static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - u32 ecx = vcpu->regs[VCPU_REGS_RCX]; - u64 data; - - if (vmx_get_msr(vcpu, ecx, &data)) { - vmx_inject_gp(vcpu, 0); - return 1; - } - - /* FIXME: handling of bits 32:63 of rax, rdx */ - vcpu->regs[VCPU_REGS_RAX] = data & -1u; - vcpu->regs[VCPU_REGS_RDX] = (data >> 32) & -1u; - skip_emulated_instruction(vcpu); - return 1; -} - -static int handle_wrmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - u32 ecx = vcpu->regs[VCPU_REGS_RCX]; - u64 data = (vcpu->regs[VCPU_REGS_RAX] & -1u) - | ((u64)(vcpu->regs[VCPU_REGS_RDX] & -1u) << 32); - - if (vmx_set_msr(vcpu, ecx, data) != 0) { - vmx_inject_gp(vcpu, 0); - return 1; - } - - skip_emulated_instruction(vcpu); - return 1; -} - -static int handle_tpr_below_threshold(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - return 1; -} - -static int handle_interrupt_window(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) -{ - u32 cpu_based_vm_exec_control; - - /* clear pending irq */ - cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); - cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); - /* - * If the user space waits to inject interrupts, exit as soon as - * possible - */ - if (kvm_run->request_interrupt_window && - !vcpu->irq_summary) { - kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; - ++vcpu->stat.irq_window_exits; - return 0; - } - return 1; -} - -static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - skip_emulated_instruction(vcpu); - return kvm_emulate_halt(vcpu); -} - -static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - skip_emulated_instruction(vcpu); - return kvm_hypercall(vcpu, kvm_run); -} - -/* - * The exit handlers return 1 if the exit was handled fully and guest execution - * may resume. Otherwise they set the kvm_run parameter to indicate what needs - * to be done to userspace and return 0. - */ -static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, - struct kvm_run *kvm_run) = { - [EXIT_REASON_EXCEPTION_NMI] = handle_exception, - [EXIT_REASON_EXTERNAL_INTERRUPT] = handle_external_interrupt, - [EXIT_REASON_TRIPLE_FAULT] = handle_triple_fault, - [EXIT_REASON_IO_INSTRUCTION] = handle_io, - [EXIT_REASON_CR_ACCESS] = handle_cr, - [EXIT_REASON_DR_ACCESS] = handle_dr, - [EXIT_REASON_CPUID] = handle_cpuid, - [EXIT_REASON_MSR_READ] = handle_rdmsr, - [EXIT_REASON_MSR_WRITE] = handle_wrmsr, - [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, - [EXIT_REASON_HLT] = handle_halt, - [EXIT_REASON_VMCALL] = handle_vmcall, - [EXIT_REASON_TPR_BELOW_THRESHOLD] = handle_tpr_below_threshold -}; - -static const int kvm_vmx_max_exit_handlers = - ARRAY_SIZE(kvm_vmx_exit_handlers); - -/* - * The guest has exited. See if we can fix it or if we need userspace - * assistance. - */ -static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) -{ - u32 vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); - u32 exit_reason = vmcs_read32(VM_EXIT_REASON); - struct vcpu_vmx *vmx = to_vmx(vcpu); - - if (unlikely(vmx->fail)) { - kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; - kvm_run->fail_entry.hardware_entry_failure_reason - = vmcs_read32(VM_INSTRUCTION_ERROR); - return 0; - } - - if ( (vectoring_info & VECTORING_INFO_VALID_MASK) && - exit_reason != EXIT_REASON_EXCEPTION_NMI ) - printk(KERN_WARNING "%s: unexpected, valid vectoring info and " - "exit reason is 0x%x\n", __FUNCTION__, exit_reason); - if (exit_reason < kvm_vmx_max_exit_handlers - && kvm_vmx_exit_handlers[exit_reason]) - return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run); - else { - kvm_run->exit_reason = KVM_EXIT_UNKNOWN; - kvm_run->hw.hardware_exit_reason = exit_reason; - } - return 0; -} - -static void vmx_flush_tlb(struct kvm_vcpu *vcpu) -{ -} - -static void update_tpr_threshold(struct kvm_vcpu *vcpu) -{ - int max_irr, tpr; - - if (!vm_need_tpr_shadow(vcpu->kvm)) - return; - - if (!kvm_lapic_enabled(vcpu) || - ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) { - vmcs_write32(TPR_THRESHOLD, 0); - return; - } - - tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4; - vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4); -} - -static void enable_irq_window(struct kvm_vcpu *vcpu) -{ - u32 cpu_based_vm_exec_control; - - cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); - cpu_based_vm_exec_control |= CPU_BASED_VIRTUAL_INTR_PENDING; - vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); -} - -static void vmx_intr_assist(struct kvm_vcpu *vcpu) -{ - u32 idtv_info_field, intr_info_field; - int has_ext_irq, interrupt_window_open; - int vector; - - kvm_inject_pending_timer_irqs(vcpu); - update_tpr_threshold(vcpu); - - has_ext_irq = kvm_cpu_has_interrupt(vcpu); - intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); - idtv_info_field = vmcs_read32(IDT_VECTORING_INFO_FIELD); - if (intr_info_field & INTR_INFO_VALID_MASK) { - if (idtv_info_field & INTR_INFO_VALID_MASK) { - /* TODO: fault when IDT_Vectoring */ - printk(KERN_ERR "Fault when IDT_Vectoring\n"); - } - if (has_ext_irq) - enable_irq_window(vcpu); - return; - } - if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) { - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); - vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, - vmcs_read32(VM_EXIT_INSTRUCTION_LEN)); - - if (unlikely(idtv_info_field & INTR_INFO_DELIEVER_CODE_MASK)) - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, - vmcs_read32(IDT_VECTORING_ERROR_CODE)); - if (unlikely(has_ext_irq)) - enable_irq_window(vcpu); - return; - } - if (!has_ext_irq) - return; - interrupt_window_open = - ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && - (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); - if (interrupt_window_open) { - vector = kvm_cpu_get_interrupt(vcpu); - vmx_inject_irq(vcpu, vector); - kvm_timer_intr_post(vcpu, vector); - } else - enable_irq_window(vcpu); -} - -static void vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - u32 intr_info; - - /* - * Loading guest fpu may have cleared host cr0.ts - */ - vmcs_writel(HOST_CR0, read_cr0()); - - asm ( - /* Store host registers */ -#ifdef CONFIG_X86_64 - "push %%rax; push %%rbx; push %%rdx;" - "push %%rsi; push %%rdi; push %%rbp;" - "push %%r8; push %%r9; push %%r10; push %%r11;" - "push %%r12; push %%r13; push %%r14; push %%r15;" - "push %%rcx \n\t" - ASM_VMX_VMWRITE_RSP_RDX "\n\t" -#else - "pusha; push %%ecx \n\t" - ASM_VMX_VMWRITE_RSP_RDX "\n\t" -#endif - /* Check if vmlaunch of vmresume is needed */ - "cmp $0, %1 \n\t" - /* Load guest registers. Don't clobber flags. */ -#ifdef CONFIG_X86_64 - "mov %c[cr2](%3), %%rax \n\t" - "mov %%rax, %%cr2 \n\t" - "mov %c[rax](%3), %%rax \n\t" - "mov %c[rbx](%3), %%rbx \n\t" - "mov %c[rdx](%3), %%rdx \n\t" - "mov %c[rsi](%3), %%rsi \n\t" - "mov %c[rdi](%3), %%rdi \n\t" - "mov %c[rbp](%3), %%rbp \n\t" - "mov %c[r8](%3), %%r8 \n\t" - "mov %c[r9](%3), %%r9 \n\t" - "mov %c[r10](%3), %%r10 \n\t" - "mov %c[r11](%3), %%r11 \n\t" - "mov %c[r12](%3), %%r12 \n\t" - "mov %c[r13](%3), %%r13 \n\t" - "mov %c[r14](%3), %%r14 \n\t" - "mov %c[r15](%3), %%r15 \n\t" - "mov %c[rcx](%3), %%rcx \n\t" /* kills %3 (rcx) */ -#else - "mov %c[cr2](%3), %%eax \n\t" - "mov %%eax, %%cr2 \n\t" - "mov %c[rax](%3), %%eax \n\t" - "mov %c[rbx](%3), %%ebx \n\t" - "mov %c[rdx](%3), %%edx \n\t" - "mov %c[rsi](%3), %%esi \n\t" - "mov %c[rdi](%3), %%edi \n\t" - "mov %c[rbp](%3), %%ebp \n\t" - "mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */ -#endif - /* Enter guest mode */ - "jne .Llaunched \n\t" - ASM_VMX_VMLAUNCH "\n\t" - "jmp .Lkvm_vmx_return \n\t" - ".Llaunched: " ASM_VMX_VMRESUME "\n\t" - ".Lkvm_vmx_return: " - /* Save guest registers, load host registers, keep flags */ -#ifdef CONFIG_X86_64 - "xchg %3, (%%rsp) \n\t" - "mov %%rax, %c[rax](%3) \n\t" - "mov %%rbx, %c[rbx](%3) \n\t" - "pushq (%%rsp); popq %c[rcx](%3) \n\t" - "mov %%rdx, %c[rdx](%3) \n\t" - "mov %%rsi, %c[rsi](%3) \n\t" - "mov %%rdi, %c[rdi](%3) \n\t" - "mov %%rbp, %c[rbp](%3) \n\t" - "mov %%r8, %c[r8](%3) \n\t" - "mov %%r9, %c[r9](%3) \n\t" - "mov %%r10, %c[r10](%3) \n\t" - "mov %%r11, %c[r11](%3) \n\t" - "mov %%r12, %c[r12](%3) \n\t" - "mov %%r13, %c[r13](%3) \n\t" - "mov %%r14, %c[r14](%3) \n\t" - "mov %%r15, %c[r15](%3) \n\t" - "mov %%cr2, %%rax \n\t" - "mov %%rax, %c[cr2](%3) \n\t" - "mov (%%rsp), %3 \n\t" - - "pop %%rcx; pop %%r15; pop %%r14; pop %%r13; pop %%r12;" - "pop %%r11; pop %%r10; pop %%r9; pop %%r8;" - "pop %%rbp; pop %%rdi; pop %%rsi;" - "pop %%rdx; pop %%rbx; pop %%rax \n\t" -#else - "xchg %3, (%%esp) \n\t" - "mov %%eax, %c[rax](%3) \n\t" - "mov %%ebx, %c[rbx](%3) \n\t" - "pushl (%%esp); popl %c[rcx](%3) \n\t" - "mov %%edx, %c[rdx](%3) \n\t" - "mov %%esi, %c[rsi](%3) \n\t" - "mov %%edi, %c[rdi](%3) \n\t" - "mov %%ebp, %c[rbp](%3) \n\t" - "mov %%cr2, %%eax \n\t" - "mov %%eax, %c[cr2](%3) \n\t" - "mov (%%esp), %3 \n\t" - - "pop %%ecx; popa \n\t" -#endif - "setbe %0 \n\t" - : "=q" (vmx->fail) - : "r"(vmx->launched), "d"((unsigned long)HOST_RSP), - "c"(vcpu), - [rax]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RAX])), - [rbx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBX])), - [rcx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RCX])), - [rdx]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDX])), - [rsi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RSI])), - [rdi]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RDI])), - [rbp]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_RBP])), -#ifdef CONFIG_X86_64 - [r8 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R8 ])), - [r9 ]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R9 ])), - [r10]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R10])), - [r11]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R11])), - [r12]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R12])), - [r13]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R13])), - [r14]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R14])), - [r15]"i"(offsetof(struct kvm_vcpu, regs[VCPU_REGS_R15])), -#endif - [cr2]"i"(offsetof(struct kvm_vcpu, cr2)) - : "cc", "memory" ); - - vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0; - - asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); - vmx->launched = 1; - - intr_info = vmcs_read32(VM_EXIT_INTR_INFO); - - /* We need to handle NMIs before interrupts are enabled */ - if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ - asm("int $2"); -} - -static void vmx_inject_page_fault(struct kvm_vcpu *vcpu, - unsigned long addr, - u32 err_code) -{ - u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); - - ++vcpu->stat.pf_guest; - - if (is_page_fault(vect_info)) { - printk(KERN_DEBUG "inject_page_fault: " - "double fault 0x%lx @ 0x%lx\n", - addr, vmcs_readl(GUEST_RIP)); - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, 0); - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - DF_VECTOR | - INTR_TYPE_EXCEPTION | - INTR_INFO_DELIEVER_CODE_MASK | - INTR_INFO_VALID_MASK); - return; - } - vcpu->cr2 = addr; - vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, err_code); - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, - PF_VECTOR | - INTR_TYPE_EXCEPTION | - INTR_INFO_DELIEVER_CODE_MASK | - INTR_INFO_VALID_MASK); - -} - -static void vmx_free_vmcs(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - - if (vmx->vmcs) { - on_each_cpu(__vcpu_clear, vmx, 0, 1); - free_vmcs(vmx->vmcs); - vmx->vmcs = NULL; - } -} - -static void vmx_free_vcpu(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - - vmx_free_vmcs(vcpu); - kfree(vmx->host_msrs); - kfree(vmx->guest_msrs); - kvm_vcpu_uninit(vcpu); - kmem_cache_free(kvm_vcpu_cache, vmx); -} - -static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) -{ - int err; - struct vcpu_vmx *vmx = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); - int cpu; - - if (!vmx) - return ERR_PTR(-ENOMEM); - - err = kvm_vcpu_init(&vmx->vcpu, kvm, id); - if (err) - goto free_vcpu; - - if (irqchip_in_kernel(kvm)) { - err = kvm_create_lapic(&vmx->vcpu); - if (err < 0) - goto free_vcpu; - } - - vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vmx->guest_msrs) { - err = -ENOMEM; - goto uninit_vcpu; - } - - vmx->host_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!vmx->host_msrs) - goto free_guest_msrs; - - vmx->vmcs = alloc_vmcs(); - if (!vmx->vmcs) - goto free_msrs; - - vmcs_clear(vmx->vmcs); - - cpu = get_cpu(); - vmx_vcpu_load(&vmx->vcpu, cpu); - err = vmx_vcpu_setup(vmx); - vmx_vcpu_put(&vmx->vcpu); - put_cpu(); - if (err) - goto free_vmcs; - - return &vmx->vcpu; - -free_vmcs: - free_vmcs(vmx->vmcs); -free_msrs: - kfree(vmx->host_msrs); -free_guest_msrs: - kfree(vmx->guest_msrs); -uninit_vcpu: - kvm_vcpu_uninit(&vmx->vcpu); -free_vcpu: - kmem_cache_free(kvm_vcpu_cache, vmx); - return ERR_PTR(err); -} - -static void __init vmx_check_processor_compat(void *rtn) -{ - struct vmcs_config vmcs_conf; - - *(int *)rtn = 0; - if (setup_vmcs_config(&vmcs_conf) < 0) - *(int *)rtn = -EIO; - if (memcmp(&vmcs_config, &vmcs_conf, sizeof(struct vmcs_config)) != 0) { - printk(KERN_ERR "kvm: CPU %d feature inconsistency!\n", - smp_processor_id()); - *(int *)rtn = -EIO; - } -} - -static struct kvm_x86_ops vmx_x86_ops = { - .cpu_has_kvm_support = cpu_has_kvm_support, - .disabled_by_bios = vmx_disabled_by_bios, - .hardware_setup = hardware_setup, - .hardware_unsetup = hardware_unsetup, - .check_processor_compatibility = vmx_check_processor_compat, - .hardware_enable = hardware_enable, - .hardware_disable = hardware_disable, - - .vcpu_create = vmx_create_vcpu, - .vcpu_free = vmx_free_vcpu, - .vcpu_reset = vmx_vcpu_reset, - - .prepare_guest_switch = vmx_save_host_state, - .vcpu_load = vmx_vcpu_load, - .vcpu_put = vmx_vcpu_put, - .vcpu_decache = vmx_vcpu_decache, - - .set_guest_debug = set_guest_debug, - .guest_debug_pre = kvm_guest_debug_pre, - .get_msr = vmx_get_msr, - .set_msr = vmx_set_msr, - .get_segment_base = vmx_get_segment_base, - .get_segment = vmx_get_segment, - .set_segment = vmx_set_segment, - .get_cs_db_l_bits = vmx_get_cs_db_l_bits, - .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, - .set_cr0 = vmx_set_cr0, - .set_cr3 = vmx_set_cr3, - .set_cr4 = vmx_set_cr4, -#ifdef CONFIG_X86_64 - .set_efer = vmx_set_efer, -#endif - .get_idt = vmx_get_idt, - .set_idt = vmx_set_idt, - .get_gdt = vmx_get_gdt, - .set_gdt = vmx_set_gdt, - .cache_regs = vcpu_load_rsp_rip, - .decache_regs = vcpu_put_rsp_rip, - .get_rflags = vmx_get_rflags, - .set_rflags = vmx_set_rflags, - - .tlb_flush = vmx_flush_tlb, - .inject_page_fault = vmx_inject_page_fault, - - .inject_gp = vmx_inject_gp, - - .run = vmx_vcpu_run, - .handle_exit = kvm_handle_exit, - .skip_emulated_instruction = skip_emulated_instruction, - .patch_hypercall = vmx_patch_hypercall, - .get_irq = vmx_get_irq, - .set_irq = vmx_inject_irq, - .inject_pending_irq = vmx_intr_assist, - .inject_pending_vectors = do_interrupt_requests, -}; - -static int __init vmx_init(void) -{ - void *iova; - int r; - - vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!vmx_io_bitmap_a) - return -ENOMEM; - - vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!vmx_io_bitmap_b) { - r = -ENOMEM; - goto out; - } - - /* - * Allow direct access to the PC debug port (it is often used for I/O - * delays, but the vmexits simply slow things down). - */ - iova = kmap(vmx_io_bitmap_a); - memset(iova, 0xff, PAGE_SIZE); - clear_bit(0x80, iova); - kunmap(vmx_io_bitmap_a); - - iova = kmap(vmx_io_bitmap_b); - memset(iova, 0xff, PAGE_SIZE); - kunmap(vmx_io_bitmap_b); - - r = kvm_init_x86(&vmx_x86_ops, sizeof(struct vcpu_vmx), THIS_MODULE); - if (r) - goto out1; - - return 0; - -out1: - __free_page(vmx_io_bitmap_b); -out: - __free_page(vmx_io_bitmap_a); - return r; -} - -static void __exit vmx_exit(void) -{ - __free_page(vmx_io_bitmap_b); - __free_page(vmx_io_bitmap_a); - - kvm_exit_x86(); -} - -module_init(vmx_init) -module_exit(vmx_exit) diff --git a/drivers/kvm/vmx.h b/drivers/kvm/vmx.h deleted file mode 100644 index fd4e14666088..000000000000 --- a/drivers/kvm/vmx.h +++ /dev/null @@ -1,310 +0,0 @@ -#ifndef VMX_H -#define VMX_H - -/* - * vmx.h: VMX Architecture related definitions - * Copyright (c) 2004, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope 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. - * - * A few random additions are: - * Copyright (C) 2006 Qumranet - * Avi Kivity <avi@qumranet.com> - * Yaniv Kamay <yaniv@qumranet.com> - * - */ - -#define CPU_BASED_VIRTUAL_INTR_PENDING 0x00000004 -#define CPU_BASED_USE_TSC_OFFSETING 0x00000008 -#define CPU_BASED_HLT_EXITING 0x00000080 -#define CPU_BASED_INVLPG_EXITING 0x00000200 -#define CPU_BASED_MWAIT_EXITING 0x00000400 -#define CPU_BASED_RDPMC_EXITING 0x00000800 -#define CPU_BASED_RDTSC_EXITING 0x00001000 -#define CPU_BASED_CR8_LOAD_EXITING 0x00080000 -#define CPU_BASED_CR8_STORE_EXITING 0x00100000 -#define CPU_BASED_TPR_SHADOW 0x00200000 -#define CPU_BASED_MOV_DR_EXITING 0x00800000 -#define CPU_BASED_UNCOND_IO_EXITING 0x01000000 -#define CPU_BASED_USE_IO_BITMAPS 0x02000000 -#define CPU_BASED_USE_MSR_BITMAPS 0x10000000 -#define CPU_BASED_MONITOR_EXITING 0x20000000 -#define CPU_BASED_PAUSE_EXITING 0x40000000 -#define CPU_BASED_ACTIVATE_SECONDARY_CONTROLS 0x80000000 - -#define PIN_BASED_EXT_INTR_MASK 0x00000001 -#define PIN_BASED_NMI_EXITING 0x00000008 -#define PIN_BASED_VIRTUAL_NMIS 0x00000020 - -#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200 -#define VM_EXIT_ACK_INTR_ON_EXIT 0x00008000 - -#define VM_ENTRY_IA32E_MODE 0x00000200 -#define VM_ENTRY_SMM 0x00000400 -#define VM_ENTRY_DEACT_DUAL_MONITOR 0x00000800 - -#define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001 - -/* VMCS Encodings */ -enum vmcs_field { - GUEST_ES_SELECTOR = 0x00000800, - GUEST_CS_SELECTOR = 0x00000802, - GUEST_SS_SELECTOR = 0x00000804, - GUEST_DS_SELECTOR = 0x00000806, - GUEST_FS_SELECTOR = 0x00000808, - GUEST_GS_SELECTOR = 0x0000080a, - GUEST_LDTR_SELECTOR = 0x0000080c, - GUEST_TR_SELECTOR = 0x0000080e, - HOST_ES_SELECTOR = 0x00000c00, - HOST_CS_SELECTOR = 0x00000c02, - HOST_SS_SELECTOR = 0x00000c04, - HOST_DS_SELECTOR = 0x00000c06, - HOST_FS_SELECTOR = 0x00000c08, - HOST_GS_SELECTOR = 0x00000c0a, - HOST_TR_SELECTOR = 0x00000c0c, - IO_BITMAP_A = 0x00002000, - IO_BITMAP_A_HIGH = 0x00002001, - IO_BITMAP_B = 0x00002002, - IO_BITMAP_B_HIGH = 0x00002003, - MSR_BITMAP = 0x00002004, - MSR_BITMAP_HIGH = 0x00002005, - VM_EXIT_MSR_STORE_ADDR = 0x00002006, - VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007, - VM_EXIT_MSR_LOAD_ADDR = 0x00002008, - VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009, - VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a, - VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b, - TSC_OFFSET = 0x00002010, - TSC_OFFSET_HIGH = 0x00002011, - VIRTUAL_APIC_PAGE_ADDR = 0x00002012, - VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013, - VMCS_LINK_POINTER = 0x00002800, - VMCS_LINK_POINTER_HIGH = 0x00002801, - GUEST_IA32_DEBUGCTL = 0x00002802, - GUEST_IA32_DEBUGCTL_HIGH = 0x00002803, - PIN_BASED_VM_EXEC_CONTROL = 0x00004000, - CPU_BASED_VM_EXEC_CONTROL = 0x00004002, - EXCEPTION_BITMAP = 0x00004004, - PAGE_FAULT_ERROR_CODE_MASK = 0x00004006, - PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008, - CR3_TARGET_COUNT = 0x0000400a, - VM_EXIT_CONTROLS = 0x0000400c, - VM_EXIT_MSR_STORE_COUNT = 0x0000400e, - VM_EXIT_MSR_LOAD_COUNT = 0x00004010, - VM_ENTRY_CONTROLS = 0x00004012, - VM_ENTRY_MSR_LOAD_COUNT = 0x00004014, - VM_ENTRY_INTR_INFO_FIELD = 0x00004016, - VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018, - VM_ENTRY_INSTRUCTION_LEN = 0x0000401a, - TPR_THRESHOLD = 0x0000401c, - SECONDARY_VM_EXEC_CONTROL = 0x0000401e, - VM_INSTRUCTION_ERROR = 0x00004400, - VM_EXIT_REASON = 0x00004402, - VM_EXIT_INTR_INFO = 0x00004404, - VM_EXIT_INTR_ERROR_CODE = 0x00004406, - IDT_VECTORING_INFO_FIELD = 0x00004408, - IDT_VECTORING_ERROR_CODE = 0x0000440a, - VM_EXIT_INSTRUCTION_LEN = 0x0000440c, - VMX_INSTRUCTION_INFO = 0x0000440e, - GUEST_ES_LIMIT = 0x00004800, - GUEST_CS_LIMIT = 0x00004802, - GUEST_SS_LIMIT = 0x00004804, - GUEST_DS_LIMIT = 0x00004806, - GUEST_FS_LIMIT = 0x00004808, - GUEST_GS_LIMIT = 0x0000480a, - GUEST_LDTR_LIMIT = 0x0000480c, - GUEST_TR_LIMIT = 0x0000480e, - GUEST_GDTR_LIMIT = 0x00004810, - GUEST_IDTR_LIMIT = 0x00004812, - GUEST_ES_AR_BYTES = 0x00004814, - GUEST_CS_AR_BYTES = 0x00004816, - GUEST_SS_AR_BYTES = 0x00004818, - GUEST_DS_AR_BYTES = 0x0000481a, - GUEST_FS_AR_BYTES = 0x0000481c, - GUEST_GS_AR_BYTES = 0x0000481e, - GUEST_LDTR_AR_BYTES = 0x00004820, - GUEST_TR_AR_BYTES = 0x00004822, - GUEST_INTERRUPTIBILITY_INFO = 0x00004824, - GUEST_ACTIVITY_STATE = 0X00004826, - GUEST_SYSENTER_CS = 0x0000482A, - HOST_IA32_SYSENTER_CS = 0x00004c00, - CR0_GUEST_HOST_MASK = 0x00006000, - CR4_GUEST_HOST_MASK = 0x00006002, - CR0_READ_SHADOW = 0x00006004, - CR4_READ_SHADOW = 0x00006006, - CR3_TARGET_VALUE0 = 0x00006008, - CR3_TARGET_VALUE1 = 0x0000600a, - CR3_TARGET_VALUE2 = 0x0000600c, - CR3_TARGET_VALUE3 = 0x0000600e, - EXIT_QUALIFICATION = 0x00006400, - GUEST_LINEAR_ADDRESS = 0x0000640a, - GUEST_CR0 = 0x00006800, - GUEST_CR3 = 0x00006802, - GUEST_CR4 = 0x00006804, - GUEST_ES_BASE = 0x00006806, - GUEST_CS_BASE = 0x00006808, - GUEST_SS_BASE = 0x0000680a, - GUEST_DS_BASE = 0x0000680c, - GUEST_FS_BASE = 0x0000680e, - GUEST_GS_BASE = 0x00006810, - GUEST_LDTR_BASE = 0x00006812, - GUEST_TR_BASE = 0x00006814, - GUEST_GDTR_BASE = 0x00006816, - GUEST_IDTR_BASE = 0x00006818, - GUEST_DR7 = 0x0000681a, - GUEST_RSP = 0x0000681c, - GUEST_RIP = 0x0000681e, - GUEST_RFLAGS = 0x00006820, - GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822, - GUEST_SYSENTER_ESP = 0x00006824, - GUEST_SYSENTER_EIP = 0x00006826, - HOST_CR0 = 0x00006c00, - HOST_CR3 = 0x00006c02, - HOST_CR4 = 0x00006c04, - HOST_FS_BASE = 0x00006c06, - HOST_GS_BASE = 0x00006c08, - HOST_TR_BASE = 0x00006c0a, - HOST_GDTR_BASE = 0x00006c0c, - HOST_IDTR_BASE = 0x00006c0e, - HOST_IA32_SYSENTER_ESP = 0x00006c10, - HOST_IA32_SYSENTER_EIP = 0x00006c12, - HOST_RSP = 0x00006c14, - HOST_RIP = 0x00006c16, -}; - -#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 - -#define EXIT_REASON_EXCEPTION_NMI 0 -#define EXIT_REASON_EXTERNAL_INTERRUPT 1 -#define EXIT_REASON_TRIPLE_FAULT 2 - -#define EXIT_REASON_PENDING_INTERRUPT 7 - -#define EXIT_REASON_TASK_SWITCH 9 -#define EXIT_REASON_CPUID 10 -#define EXIT_REASON_HLT 12 -#define EXIT_REASON_INVLPG 14 -#define EXIT_REASON_RDPMC 15 -#define EXIT_REASON_RDTSC 16 -#define EXIT_REASON_VMCALL 18 -#define EXIT_REASON_VMCLEAR 19 -#define EXIT_REASON_VMLAUNCH 20 -#define EXIT_REASON_VMPTRLD 21 -#define EXIT_REASON_VMPTRST 22 -#define EXIT_REASON_VMREAD 23 -#define EXIT_REASON_VMRESUME 24 -#define EXIT_REASON_VMWRITE 25 -#define EXIT_REASON_VMOFF 26 -#define EXIT_REASON_VMON 27 -#define EXIT_REASON_CR_ACCESS 28 -#define EXIT_REASON_DR_ACCESS 29 -#define EXIT_REASON_IO_INSTRUCTION 30 -#define EXIT_REASON_MSR_READ 31 -#define EXIT_REASON_MSR_WRITE 32 -#define EXIT_REASON_MWAIT_INSTRUCTION 36 -#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 - -/* - * Interruption-information format - */ -#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ -#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ -#define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */ -#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ - -#define VECTORING_INFO_VECTOR_MASK INTR_INFO_VECTOR_MASK -#define VECTORING_INFO_TYPE_MASK INTR_INFO_INTR_TYPE_MASK -#define VECTORING_INFO_DELIEVER_CODE_MASK INTR_INFO_DELIEVER_CODE_MASK -#define VECTORING_INFO_VALID_MASK INTR_INFO_VALID_MASK - -#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ -#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ - -/* - * Exit Qualifications for MOV for Control Register Access - */ -#define CONTROL_REG_ACCESS_NUM 0x7 /* 2:0, number of control register */ -#define CONTROL_REG_ACCESS_TYPE 0x30 /* 5:4, access type */ -#define CONTROL_REG_ACCESS_REG 0xf00 /* 10:8, general purpose register */ -#define LMSW_SOURCE_DATA_SHIFT 16 -#define LMSW_SOURCE_DATA (0xFFFF << LMSW_SOURCE_DATA_SHIFT) /* 16:31 lmsw source */ -#define REG_EAX (0 << 8) -#define REG_ECX (1 << 8) -#define REG_EDX (2 << 8) -#define REG_EBX (3 << 8) -#define REG_ESP (4 << 8) -#define REG_EBP (5 << 8) -#define REG_ESI (6 << 8) -#define REG_EDI (7 << 8) -#define REG_R8 (8 << 8) -#define REG_R9 (9 << 8) -#define REG_R10 (10 << 8) -#define REG_R11 (11 << 8) -#define REG_R12 (12 << 8) -#define REG_R13 (13 << 8) -#define REG_R14 (14 << 8) -#define REG_R15 (15 << 8) - -/* - * Exit Qualifications for MOV for Debug Register Access - */ -#define DEBUG_REG_ACCESS_NUM 0x7 /* 2:0, number of debug register */ -#define DEBUG_REG_ACCESS_TYPE 0x10 /* 4, direction of access */ -#define TYPE_MOV_TO_DR (0 << 4) -#define TYPE_MOV_FROM_DR (1 << 4) -#define DEBUG_REG_ACCESS_REG 0xf00 /* 11:8, general purpose register */ - - -/* segment AR */ -#define SEGMENT_AR_L_MASK (1 << 13) - -#define AR_TYPE_ACCESSES_MASK 1 -#define AR_TYPE_READABLE_MASK (1 << 1) -#define AR_TYPE_WRITEABLE_MASK (1 << 2) -#define AR_TYPE_CODE_MASK (1 << 3) -#define AR_TYPE_MASK 0x0f -#define AR_TYPE_BUSY_64_TSS 11 -#define AR_TYPE_BUSY_32_TSS 11 -#define AR_TYPE_BUSY_16_TSS 3 -#define AR_TYPE_LDT 2 - -#define AR_UNUSABLE_MASK (1 << 16) -#define AR_S_MASK (1 << 4) -#define AR_P_MASK (1 << 7) -#define AR_L_MASK (1 << 13) -#define AR_DB_MASK (1 << 14) -#define AR_G_MASK (1 << 15) -#define AR_DPL_SHIFT 5 -#define AR_DPL(ar) (((ar) >> AR_DPL_SHIFT) & 3) - -#define AR_RESERVD_MASK 0xfffe0f00 - -#define MSR_IA32_VMX_BASIC 0x480 -#define MSR_IA32_VMX_PINBASED_CTLS 0x481 -#define MSR_IA32_VMX_PROCBASED_CTLS 0x482 -#define MSR_IA32_VMX_EXIT_CTLS 0x483 -#define MSR_IA32_VMX_ENTRY_CTLS 0x484 -#define MSR_IA32_VMX_MISC 0x485 -#define MSR_IA32_VMX_CR0_FIXED0 0x486 -#define MSR_IA32_VMX_CR0_FIXED1 0x487 -#define MSR_IA32_VMX_CR4_FIXED0 0x488 -#define MSR_IA32_VMX_CR4_FIXED1 0x489 -#define MSR_IA32_VMX_VMCS_ENUM 0x48a -#define MSR_IA32_VMX_PROCBASED_CTLS2 0x48b - -#define MSR_IA32_FEATURE_CONTROL 0x3a -#define MSR_IA32_FEATURE_CONTROL_LOCKED 0x1 -#define MSR_IA32_FEATURE_CONTROL_VMXON_ENABLED 0x4 - -#endif diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c deleted file mode 100644 index bd46de6bf891..000000000000 --- a/drivers/kvm/x86_emulate.c +++ /dev/null @@ -1,1662 +0,0 @@ -/****************************************************************************** - * x86_emulate.c - * - * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. - * - * Copyright (c) 2005 Keir Fraser - * - * Linux coding style, mod r/m decoder, segment base fixes, real-mode - * privileged instructions: - * - * Copyright (C) 2006 Qumranet - * - * Avi Kivity <avi@qumranet.com> - * Yaniv Kamay <yaniv@qumranet.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 - */ - -#ifndef __KERNEL__ -#include <stdio.h> -#include <stdint.h> -#include <public/xen.h> -#define DPRINTF(_f, _a ...) printf( _f , ## _a ) -#else -#include "kvm.h" -#define DPRINTF(x...) do {} while (0) -#endif -#include "x86_emulate.h" -#include <linux/module.h> - -/* - * Opcode effective-address decode tables. - * Note that we only emulate instructions that have at least one memory - * operand (excluding implicit stack references). We assume that stack - * references and instruction fetches will never occur in special memory - * areas that require emulation. So, for example, 'mov <imm>,<reg>' need - * not be handled. - */ - -/* Operand sizes: 8-bit operands or specified/overridden size. */ -#define ByteOp (1<<0) /* 8-bit operands. */ -/* Destination operand type. */ -#define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ -#define DstReg (2<<1) /* Register operand. */ -#define DstMem (3<<1) /* Memory operand. */ -#define DstMask (3<<1) -/* Source operand type. */ -#define SrcNone (0<<3) /* No source operand. */ -#define SrcImplicit (0<<3) /* Source operand is implicit in the opcode. */ -#define SrcReg (1<<3) /* Register operand. */ -#define SrcMem (2<<3) /* Memory operand. */ -#define SrcMem16 (3<<3) /* Memory operand (16-bit). */ -#define SrcMem32 (4<<3) /* Memory operand (32-bit). */ -#define SrcImm (5<<3) /* Immediate operand. */ -#define SrcImmByte (6<<3) /* 8-bit sign-extended immediate operand. */ -#define SrcMask (7<<3) -/* Generic ModRM decode. */ -#define ModRM (1<<6) -/* Destination is only written; never read. */ -#define Mov (1<<7) -#define BitOp (1<<8) - -static u8 opcode_table[256] = { - /* 0x00 - 0x07 */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x08 - 0x0F */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x10 - 0x17 */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x18 - 0x1F */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x20 - 0x27 */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - SrcImmByte, SrcImm, 0, 0, - /* 0x28 - 0x2F */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x30 - 0x37 */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x38 - 0x3F */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM, - 0, 0, 0, 0, - /* 0x40 - 0x4F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x50 - 0x57 */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x58 - 0x5F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x60 - 0x67 */ - 0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ , - 0, 0, 0, 0, - /* 0x68 - 0x6F */ - 0, 0, ImplicitOps|Mov, 0, - SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* insb, insw/insd */ - SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps, /* outsb, outsw/outsd */ - /* 0x70 - 0x77 */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x78 - 0x7F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x80 - 0x87 */ - ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM, - ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, - /* 0x88 - 0x8F */ - ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov, - ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - 0, ModRM | DstReg, 0, DstMem | SrcNone | ModRM | Mov, - /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps, ImplicitOps, 0, 0, - /* 0xA0 - 0xA7 */ - ByteOp | DstReg | SrcMem | Mov, DstReg | SrcMem | Mov, - ByteOp | DstMem | SrcReg | Mov, DstMem | SrcReg | Mov, - ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, - ByteOp | ImplicitOps, ImplicitOps, - /* 0xA8 - 0xAF */ - 0, 0, ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, - ByteOp | ImplicitOps | Mov, ImplicitOps | Mov, - ByteOp | ImplicitOps, ImplicitOps, - /* 0xB0 - 0xBF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xC0 - 0xC7 */ - ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, - 0, ImplicitOps, 0, 0, - ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov, - /* 0xC8 - 0xCF */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xD0 - 0xD7 */ - ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, - ByteOp | DstMem | SrcImplicit | ModRM, DstMem | SrcImplicit | ModRM, - 0, 0, 0, 0, - /* 0xD8 - 0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE0 - 0xE7 */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE8 - 0xEF */ - ImplicitOps, SrcImm|ImplicitOps, 0, SrcImmByte|ImplicitOps, 0, 0, 0, 0, - /* 0xF0 - 0xF7 */ - 0, 0, 0, 0, - ImplicitOps, 0, - ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM, - /* 0xF8 - 0xFF */ - 0, 0, 0, 0, - 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM -}; - -static u16 twobyte_table[256] = { - /* 0x00 - 0x0F */ - 0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0, - ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0, - /* 0x10 - 0x1F */ - 0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0, - /* 0x20 - 0x2F */ - ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x30 - 0x3F */ - ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x40 - 0x47 */ - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - /* 0x48 - 0x4F */ - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov, - /* 0x50 - 0x5F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x60 - 0x6F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 - 0x7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x80 - 0x8F */ - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, - /* 0x90 - 0x9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xA0 - 0xA7 */ - 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, - /* 0xA8 - 0xAF */ - 0, 0, 0, DstMem | SrcReg | ModRM | BitOp, 0, 0, 0, 0, - /* 0xB0 - 0xB7 */ - ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0, - DstMem | SrcReg | ModRM | BitOp, - 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem16 | ModRM | Mov, - /* 0xB8 - 0xBF */ - 0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp, - 0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov, - DstReg | SrcMem16 | ModRM | Mov, - /* 0xC0 - 0xCF */ - 0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xD0 - 0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xE0 - 0xEF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xF0 - 0xFF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -/* Type, address-of, and value of an instruction's operand. */ -struct operand { - enum { OP_REG, OP_MEM, OP_IMM } type; - unsigned int bytes; - unsigned long val, orig_val, *ptr; -}; - -/* EFLAGS bit definitions. */ -#define EFLG_OF (1<<11) -#define EFLG_DF (1<<10) -#define EFLG_SF (1<<7) -#define EFLG_ZF (1<<6) -#define EFLG_AF (1<<4) -#define EFLG_PF (1<<2) -#define EFLG_CF (1<<0) - -/* - * Instruction emulation: - * Most instructions are emulated directly via a fragment of inline assembly - * code. This allows us to save/restore EFLAGS and thus very easily pick up - * any modified flags. - */ - -#if defined(CONFIG_X86_64) -#define _LO32 "k" /* force 32-bit operand */ -#define _STK "%%rsp" /* stack pointer */ -#elif defined(__i386__) -#define _LO32 "" /* force 32-bit operand */ -#define _STK "%%esp" /* stack pointer */ -#endif - -/* - * These EFLAGS bits are restored from saved value during emulation, and - * any changes are written back to the saved value after emulation. - */ -#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF) - -/* Before executing instruction: restore necessary bits in EFLAGS. */ -#define _PRE_EFLAGS(_sav, _msk, _tmp) \ - /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); */ \ - "push %"_sav"; " \ - "movl %"_msk",%"_LO32 _tmp"; " \ - "andl %"_LO32 _tmp",("_STK"); " \ - "pushf; " \ - "notl %"_LO32 _tmp"; " \ - "andl %"_LO32 _tmp",("_STK"); " \ - "pop %"_tmp"; " \ - "orl %"_LO32 _tmp",("_STK"); " \ - "popf; " \ - /* _sav &= ~msk; */ \ - "movl %"_msk",%"_LO32 _tmp"; " \ - "notl %"_LO32 _tmp"; " \ - "andl %"_LO32 _tmp",%"_sav"; " - -/* After executing instruction: write-back necessary bits in EFLAGS. */ -#define _POST_EFLAGS(_sav, _msk, _tmp) \ - /* _sav |= EFLAGS & _msk; */ \ - "pushf; " \ - "pop %"_tmp"; " \ - "andl %"_msk",%"_LO32 _tmp"; " \ - "orl %"_LO32 _tmp",%"_sav"; " - -/* Raw emulation: instruction has two explicit operands. */ -#define __emulate_2op_nobyte(_op,_src,_dst,_eflags,_wx,_wy,_lx,_ly,_qx,_qy) \ - do { \ - unsigned long _tmp; \ - \ - switch ((_dst).bytes) { \ - case 2: \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","4","2") \ - _op"w %"_wx"3,%1; " \ - _POST_EFLAGS("0","4","2") \ - : "=m" (_eflags), "=m" ((_dst).val), \ - "=&r" (_tmp) \ - : _wy ((_src).val), "i" (EFLAGS_MASK) ); \ - break; \ - case 4: \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","4","2") \ - _op"l %"_lx"3,%1; " \ - _POST_EFLAGS("0","4","2") \ - : "=m" (_eflags), "=m" ((_dst).val), \ - "=&r" (_tmp) \ - : _ly ((_src).val), "i" (EFLAGS_MASK) ); \ - break; \ - case 8: \ - __emulate_2op_8byte(_op, _src, _dst, \ - _eflags, _qx, _qy); \ - break; \ - } \ - } while (0) - -#define __emulate_2op(_op,_src,_dst,_eflags,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \ - do { \ - unsigned long _tmp; \ - switch ( (_dst).bytes ) \ - { \ - case 1: \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","4","2") \ - _op"b %"_bx"3,%1; " \ - _POST_EFLAGS("0","4","2") \ - : "=m" (_eflags), "=m" ((_dst).val), \ - "=&r" (_tmp) \ - : _by ((_src).val), "i" (EFLAGS_MASK) ); \ - break; \ - default: \ - __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ - _wx, _wy, _lx, _ly, _qx, _qy); \ - break; \ - } \ - } while (0) - -/* Source operand is byte-sized and may be restricted to just %cl. */ -#define emulate_2op_SrcB(_op, _src, _dst, _eflags) \ - __emulate_2op(_op, _src, _dst, _eflags, \ - "b", "c", "b", "c", "b", "c", "b", "c") - -/* Source operand is byte, word, long or quad sized. */ -#define emulate_2op_SrcV(_op, _src, _dst, _eflags) \ - __emulate_2op(_op, _src, _dst, _eflags, \ - "b", "q", "w", "r", _LO32, "r", "", "r") - -/* Source operand is word, long or quad sized. */ -#define emulate_2op_SrcV_nobyte(_op, _src, _dst, _eflags) \ - __emulate_2op_nobyte(_op, _src, _dst, _eflags, \ - "w", "r", _LO32, "r", "", "r") - -/* Instruction has only one explicit operand (no source operand). */ -#define emulate_1op(_op, _dst, _eflags) \ - do { \ - unsigned long _tmp; \ - \ - switch ( (_dst).bytes ) \ - { \ - case 1: \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","3","2") \ - _op"b %1; " \ - _POST_EFLAGS("0","3","2") \ - : "=m" (_eflags), "=m" ((_dst).val), \ - "=&r" (_tmp) \ - : "i" (EFLAGS_MASK) ); \ - break; \ - case 2: \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","3","2") \ - _op"w %1; " \ - _POST_EFLAGS("0","3","2") \ - : "=m" (_eflags), "=m" ((_dst).val), \ - "=&r" (_tmp) \ - : "i" (EFLAGS_MASK) ); \ - break; \ - case 4: \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","3","2") \ - _op"l %1; " \ - _POST_EFLAGS("0","3","2") \ - : "=m" (_eflags), "=m" ((_dst).val), \ - "=&r" (_tmp) \ - : "i" (EFLAGS_MASK) ); \ - break; \ - case 8: \ - __emulate_1op_8byte(_op, _dst, _eflags); \ - break; \ - } \ - } while (0) - -/* Emulate an instruction with quadword operands (x86/64 only). */ -#if defined(CONFIG_X86_64) -#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) \ - do { \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","4","2") \ - _op"q %"_qx"3,%1; " \ - _POST_EFLAGS("0","4","2") \ - : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ - : _qy ((_src).val), "i" (EFLAGS_MASK) ); \ - } while (0) - -#define __emulate_1op_8byte(_op, _dst, _eflags) \ - do { \ - __asm__ __volatile__ ( \ - _PRE_EFLAGS("0","3","2") \ - _op"q %1; " \ - _POST_EFLAGS("0","3","2") \ - : "=m" (_eflags), "=m" ((_dst).val), "=&r" (_tmp) \ - : "i" (EFLAGS_MASK) ); \ - } while (0) - -#elif defined(__i386__) -#define __emulate_2op_8byte(_op, _src, _dst, _eflags, _qx, _qy) -#define __emulate_1op_8byte(_op, _dst, _eflags) -#endif /* __i386__ */ - -/* Fetch next part of the instruction being emulated. */ -#define insn_fetch(_type, _size, _eip) \ -({ unsigned long _x; \ - rc = ops->read_std((unsigned long)(_eip) + ctxt->cs_base, &_x, \ - (_size), ctxt->vcpu); \ - if ( rc != 0 ) \ - goto done; \ - (_eip) += (_size); \ - (_type)_x; \ -}) - -/* Access/update address held in a register, based on addressing mode. */ -#define address_mask(reg) \ - ((ad_bytes == sizeof(unsigned long)) ? \ - (reg) : ((reg) & ((1UL << (ad_bytes << 3)) - 1))) -#define register_address(base, reg) \ - ((base) + address_mask(reg)) -#define register_address_increment(reg, inc) \ - do { \ - /* signed type ensures sign extension to long */ \ - int _inc = (inc); \ - if ( ad_bytes == sizeof(unsigned long) ) \ - (reg) += _inc; \ - else \ - (reg) = ((reg) & ~((1UL << (ad_bytes << 3)) - 1)) | \ - (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \ - } while (0) - -#define JMP_REL(rel) \ - do { \ - register_address_increment(_eip, rel); \ - } while (0) - -/* - * Given the 'reg' portion of a ModRM byte, and a register block, return a - * pointer into the block that addresses the relevant register. - * @highbyte_regs specifies whether to decode AH,CH,DH,BH. - */ -static void *decode_register(u8 modrm_reg, unsigned long *regs, - int highbyte_regs) -{ - void *p; - - p = ®s[modrm_reg]; - if (highbyte_regs && modrm_reg >= 4 && modrm_reg < 8) - p = (unsigned char *)®s[modrm_reg & 3] + 1; - return p; -} - -static int read_descriptor(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops, - void *ptr, - u16 *size, unsigned long *address, int op_bytes) -{ - int rc; - - if (op_bytes == 2) - op_bytes = 3; - *address = 0; - rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2, - ctxt->vcpu); - if (rc) - return rc; - rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes, - ctxt->vcpu); - return rc; -} - -static int test_cc(unsigned int condition, unsigned int flags) -{ - int rc = 0; - - switch ((condition & 15) >> 1) { - case 0: /* o */ - rc |= (flags & EFLG_OF); - break; - case 1: /* b/c/nae */ - rc |= (flags & EFLG_CF); - break; - case 2: /* z/e */ - rc |= (flags & EFLG_ZF); - break; - case 3: /* be/na */ - rc |= (flags & (EFLG_CF|EFLG_ZF)); - break; - case 4: /* s */ - rc |= (flags & EFLG_SF); - break; - case 5: /* p/pe */ - rc |= (flags & EFLG_PF); - break; - case 7: /* le/ng */ - rc |= (flags & EFLG_ZF); - /* fall through */ - case 6: /* l/nge */ - rc |= (!(flags & EFLG_SF) != !(flags & EFLG_OF)); - break; - } - - /* Odd condition identifiers (lsb == 1) have inverted sense. */ - return (!!rc ^ (condition & 1)); -} - -int -x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops) -{ - unsigned d; - u8 b, sib, twobyte = 0, rex_prefix = 0; - u8 modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; - unsigned long *override_base = NULL; - unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; - int rc = 0; - struct operand src, dst; - unsigned long cr2 = ctxt->cr2; - int mode = ctxt->mode; - unsigned long modrm_ea; - int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0; - int no_wb = 0; - u64 msr_data; - - /* Shadow copy of register state. Committed on successful emulation. */ - unsigned long _regs[NR_VCPU_REGS]; - unsigned long _eip = ctxt->vcpu->rip, _eflags = ctxt->eflags; - unsigned long modrm_val = 0; - - memcpy(_regs, ctxt->vcpu->regs, sizeof _regs); - - switch (mode) { - case X86EMUL_MODE_REAL: - case X86EMUL_MODE_PROT16: - op_bytes = ad_bytes = 2; - break; - case X86EMUL_MODE_PROT32: - op_bytes = ad_bytes = 4; - break; -#ifdef CONFIG_X86_64 - case X86EMUL_MODE_PROT64: - op_bytes = 4; - ad_bytes = 8; - break; -#endif - default: - return -1; - } - - /* Legacy prefixes. */ - for (i = 0; i < 8; i++) { - switch (b = insn_fetch(u8, 1, _eip)) { - case 0x66: /* operand-size override */ - op_bytes ^= 6; /* switch between 2/4 bytes */ - break; - case 0x67: /* address-size override */ - if (mode == X86EMUL_MODE_PROT64) - ad_bytes ^= 12; /* switch between 4/8 bytes */ - else - ad_bytes ^= 6; /* switch between 2/4 bytes */ - break; - case 0x2e: /* CS override */ - override_base = &ctxt->cs_base; - break; - case 0x3e: /* DS override */ - override_base = &ctxt->ds_base; - break; - case 0x26: /* ES override */ - override_base = &ctxt->es_base; - break; - case 0x64: /* FS override */ - override_base = &ctxt->fs_base; - break; - case 0x65: /* GS override */ - override_base = &ctxt->gs_base; - break; - case 0x36: /* SS override */ - override_base = &ctxt->ss_base; - break; - case 0xf0: /* LOCK */ - lock_prefix = 1; - break; - case 0xf2: /* REPNE/REPNZ */ - case 0xf3: /* REP/REPE/REPZ */ - rep_prefix = 1; - break; - default: - goto done_prefixes; - } - } - -done_prefixes: - - /* REX prefix. */ - if ((mode == X86EMUL_MODE_PROT64) && ((b & 0xf0) == 0x40)) { - rex_prefix = b; - if (b & 8) - op_bytes = 8; /* REX.W */ - modrm_reg = (b & 4) << 1; /* REX.R */ - index_reg = (b & 2) << 2; /* REX.X */ - modrm_rm = base_reg = (b & 1) << 3; /* REG.B */ - b = insn_fetch(u8, 1, _eip); - } - - /* Opcode byte(s). */ - d = opcode_table[b]; - if (d == 0) { - /* Two-byte opcode? */ - if (b == 0x0f) { - twobyte = 1; - b = insn_fetch(u8, 1, _eip); - d = twobyte_table[b]; - } - - /* Unrecognised? */ - if (d == 0) - goto cannot_emulate; - } - - /* ModRM and SIB bytes. */ - if (d & ModRM) { - modrm = insn_fetch(u8, 1, _eip); - modrm_mod |= (modrm & 0xc0) >> 6; - modrm_reg |= (modrm & 0x38) >> 3; - modrm_rm |= (modrm & 0x07); - modrm_ea = 0; - use_modrm_ea = 1; - - if (modrm_mod == 3) { - modrm_val = *(unsigned long *) - decode_register(modrm_rm, _regs, d & ByteOp); - goto modrm_done; - } - - if (ad_bytes == 2) { - unsigned bx = _regs[VCPU_REGS_RBX]; - unsigned bp = _regs[VCPU_REGS_RBP]; - unsigned si = _regs[VCPU_REGS_RSI]; - unsigned di = _regs[VCPU_REGS_RDI]; - - /* 16-bit ModR/M decode. */ - switch (modrm_mod) { - case 0: - if (modrm_rm == 6) - modrm_ea += insn_fetch(u16, 2, _eip); - break; - case 1: - modrm_ea += insn_fetch(s8, 1, _eip); - break; - case 2: - modrm_ea += insn_fetch(u16, 2, _eip); - break; - } - switch (modrm_rm) { - case 0: - modrm_ea += bx + si; - break; - case 1: - modrm_ea += bx + di; - break; - case 2: - modrm_ea += bp + si; - break; - case 3: - modrm_ea += bp + di; - break; - case 4: - modrm_ea += si; - break; - case 5: - modrm_ea += di; - break; - case 6: - if (modrm_mod != 0) - modrm_ea += bp; - break; - case 7: - modrm_ea += bx; - break; - } - if (modrm_rm == 2 || modrm_rm == 3 || - (modrm_rm == 6 && modrm_mod != 0)) - if (!override_base) - override_base = &ctxt->ss_base; - modrm_ea = (u16)modrm_ea; - } else { - /* 32/64-bit ModR/M decode. */ - switch (modrm_rm) { - case 4: - case 12: - sib = insn_fetch(u8, 1, _eip); - index_reg |= (sib >> 3) & 7; - base_reg |= sib & 7; - scale = sib >> 6; - - switch (base_reg) { - case 5: - if (modrm_mod != 0) - modrm_ea += _regs[base_reg]; - else - modrm_ea += insn_fetch(s32, 4, _eip); - break; - default: - modrm_ea += _regs[base_reg]; - } - switch (index_reg) { - case 4: - break; - default: - modrm_ea += _regs[index_reg] << scale; - - } - break; - case 5: - if (modrm_mod != 0) - modrm_ea += _regs[modrm_rm]; - else if (mode == X86EMUL_MODE_PROT64) - rip_relative = 1; - break; - default: - modrm_ea += _regs[modrm_rm]; - break; - } - switch (modrm_mod) { - case 0: - if (modrm_rm == 5) - modrm_ea += insn_fetch(s32, 4, _eip); - break; - case 1: - modrm_ea += insn_fetch(s8, 1, _eip); - break; - case 2: - modrm_ea += insn_fetch(s32, 4, _eip); - break; - } - } - if (!override_base) - override_base = &ctxt->ds_base; - if (mode == X86EMUL_MODE_PROT64 && - override_base != &ctxt->fs_base && - override_base != &ctxt->gs_base) - override_base = NULL; - - if (override_base) - modrm_ea += *override_base; - - if (rip_relative) { - modrm_ea += _eip; - switch (d & SrcMask) { - case SrcImmByte: - modrm_ea += 1; - break; - case SrcImm: - if (d & ByteOp) - modrm_ea += 1; - else - if (op_bytes == 8) - modrm_ea += 4; - else - modrm_ea += op_bytes; - } - } - if (ad_bytes != 8) - modrm_ea = (u32)modrm_ea; - cr2 = modrm_ea; - modrm_done: - ; - } - - /* - * Decode and fetch the source operand: register, memory - * or immediate. - */ - switch (d & SrcMask) { - case SrcNone: - break; - case SrcReg: - src.type = OP_REG; - if (d & ByteOp) { - src.ptr = decode_register(modrm_reg, _regs, - (rex_prefix == 0)); - src.val = src.orig_val = *(u8 *) src.ptr; - src.bytes = 1; - } else { - src.ptr = decode_register(modrm_reg, _regs, 0); - switch ((src.bytes = op_bytes)) { - case 2: - src.val = src.orig_val = *(u16 *) src.ptr; - break; - case 4: - src.val = src.orig_val = *(u32 *) src.ptr; - break; - case 8: - src.val = src.orig_val = *(u64 *) src.ptr; - break; - } - } - break; - case SrcMem16: - src.bytes = 2; - goto srcmem_common; - case SrcMem32: - src.bytes = 4; - goto srcmem_common; - case SrcMem: - src.bytes = (d & ByteOp) ? 1 : op_bytes; - /* Don't fetch the address for invlpg: it could be unmapped. */ - if (twobyte && b == 0x01 && modrm_reg == 7) - break; - srcmem_common: - /* - * For instructions with a ModR/M byte, switch to register - * access if Mod = 3. - */ - if ((d & ModRM) && modrm_mod == 3) { - src.type = OP_REG; - break; - } - src.type = OP_MEM; - src.ptr = (unsigned long *)cr2; - src.val = 0; - if ((rc = ops->read_emulated((unsigned long)src.ptr, - &src.val, src.bytes, ctxt->vcpu)) != 0) - goto done; - src.orig_val = src.val; - break; - case SrcImm: - src.type = OP_IMM; - src.ptr = (unsigned long *)_eip; - src.bytes = (d & ByteOp) ? 1 : op_bytes; - if (src.bytes == 8) - src.bytes = 4; - /* NB. Immediates are sign-extended as necessary. */ - switch (src.bytes) { - case 1: - src.val = insn_fetch(s8, 1, _eip); - break; - case 2: - src.val = insn_fetch(s16, 2, _eip); - break; - case 4: - src.val = insn_fetch(s32, 4, _eip); - break; - } - break; - case SrcImmByte: - src.type = OP_IMM; - src.ptr = (unsigned long *)_eip; - src.bytes = 1; - src.val = insn_fetch(s8, 1, _eip); - break; - } - - /* Decode and fetch the destination operand: register or memory. */ - switch (d & DstMask) { - case ImplicitOps: - /* Special instructions do their own operand decoding. */ - goto special_insn; - case DstReg: - dst.type = OP_REG; - if ((d & ByteOp) - && !(twobyte && (b == 0xb6 || b == 0xb7))) { - dst.ptr = decode_register(modrm_reg, _regs, - (rex_prefix == 0)); - dst.val = *(u8 *) dst.ptr; - dst.bytes = 1; - } else { - dst.ptr = decode_register(modrm_reg, _regs, 0); - switch ((dst.bytes = op_bytes)) { - case 2: - dst.val = *(u16 *)dst.ptr; - break; - case 4: - dst.val = *(u32 *)dst.ptr; - break; - case 8: - dst.val = *(u64 *)dst.ptr; - break; - } - } - break; - case DstMem: - dst.type = OP_MEM; - dst.ptr = (unsigned long *)cr2; - dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.val = 0; - /* - * For instructions with a ModR/M byte, switch to register - * access if Mod = 3. - */ - if ((d & ModRM) && modrm_mod == 3) { - dst.type = OP_REG; - break; - } - if (d & BitOp) { - unsigned long mask = ~(dst.bytes * 8 - 1); - - dst.ptr = (void *)dst.ptr + (src.val & mask) / 8; - } - if (!(d & Mov) && /* optimisation - avoid slow emulated read */ - ((rc = ops->read_emulated((unsigned long)dst.ptr, - &dst.val, dst.bytes, ctxt->vcpu)) != 0)) - goto done; - break; - } - dst.orig_val = dst.val; - - if (twobyte) - goto twobyte_insn; - - switch (b) { - case 0x00 ... 0x05: - add: /* add */ - emulate_2op_SrcV("add", src, dst, _eflags); - break; - case 0x08 ... 0x0d: - or: /* or */ - emulate_2op_SrcV("or", src, dst, _eflags); - break; - case 0x10 ... 0x15: - adc: /* adc */ - emulate_2op_SrcV("adc", src, dst, _eflags); - break; - case 0x18 ... 0x1d: - sbb: /* sbb */ - emulate_2op_SrcV("sbb", src, dst, _eflags); - break; - case 0x20 ... 0x23: - and: /* and */ - emulate_2op_SrcV("and", src, dst, _eflags); - break; - case 0x24: /* and al imm8 */ - dst.type = OP_REG; - dst.ptr = &_regs[VCPU_REGS_RAX]; - dst.val = *(u8 *)dst.ptr; - dst.bytes = 1; - dst.orig_val = dst.val; - goto and; - case 0x25: /* and ax imm16, or eax imm32 */ - dst.type = OP_REG; - dst.bytes = op_bytes; - dst.ptr = &_regs[VCPU_REGS_RAX]; - if (op_bytes == 2) - dst.val = *(u16 *)dst.ptr; - else - dst.val = *(u32 *)dst.ptr; - dst.orig_val = dst.val; - goto and; - case 0x28 ... 0x2d: - sub: /* sub */ - emulate_2op_SrcV("sub", src, dst, _eflags); - break; - case 0x30 ... 0x35: - xor: /* xor */ - emulate_2op_SrcV("xor", src, dst, _eflags); - break; - case 0x38 ... 0x3d: - cmp: /* cmp */ - emulate_2op_SrcV("cmp", src, dst, _eflags); - break; - case 0x63: /* movsxd */ - if (mode != X86EMUL_MODE_PROT64) - goto cannot_emulate; - dst.val = (s32) src.val; - break; - case 0x80 ... 0x83: /* Grp1 */ - switch (modrm_reg) { - case 0: - goto add; - case 1: - goto or; - case 2: - goto adc; - case 3: - goto sbb; - case 4: - goto and; - case 5: - goto sub; - case 6: - goto xor; - case 7: - goto cmp; - } - break; - case 0x84 ... 0x85: - test: /* test */ - emulate_2op_SrcV("test", src, dst, _eflags); - break; - case 0x86 ... 0x87: /* xchg */ - /* Write back the register source. */ - switch (dst.bytes) { - case 1: - *(u8 *) src.ptr = (u8) dst.val; - break; - case 2: - *(u16 *) src.ptr = (u16) dst.val; - break; - case 4: - *src.ptr = (u32) dst.val; - break; /* 64b reg: zero-extend */ - case 8: - *src.ptr = dst.val; - break; - } - /* - * Write back the memory destination with implicit LOCK - * prefix. - */ - dst.val = src.val; - lock_prefix = 1; - break; - case 0x88 ... 0x8b: /* mov */ - goto mov; - case 0x8d: /* lea r16/r32, m */ - dst.val = modrm_val; - break; - case 0x8f: /* pop (sole member of Grp1a) */ - /* 64-bit mode: POP always pops a 64-bit operand. */ - if (mode == X86EMUL_MODE_PROT64) - dst.bytes = 8; - if ((rc = ops->read_std(register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]), - &dst.val, dst.bytes, ctxt->vcpu)) != 0) - goto done; - register_address_increment(_regs[VCPU_REGS_RSP], dst.bytes); - break; - case 0xa0 ... 0xa1: /* mov */ - dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - dst.val = src.val; - _eip += ad_bytes; /* skip src displacement */ - break; - case 0xa2 ... 0xa3: /* mov */ - dst.val = (unsigned long)_regs[VCPU_REGS_RAX]; - _eip += ad_bytes; /* skip dst displacement */ - break; - case 0xc0 ... 0xc1: - grp2: /* Grp2 */ - switch (modrm_reg) { - case 0: /* rol */ - emulate_2op_SrcB("rol", src, dst, _eflags); - break; - case 1: /* ror */ - emulate_2op_SrcB("ror", src, dst, _eflags); - break; - case 2: /* rcl */ - emulate_2op_SrcB("rcl", src, dst, _eflags); - break; - case 3: /* rcr */ - emulate_2op_SrcB("rcr", src, dst, _eflags); - break; - case 4: /* sal/shl */ - case 6: /* sal/shl */ - emulate_2op_SrcB("sal", src, dst, _eflags); - break; - case 5: /* shr */ - emulate_2op_SrcB("shr", src, dst, _eflags); - break; - case 7: /* sar */ - emulate_2op_SrcB("sar", src, dst, _eflags); - break; - } - break; - case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ - mov: - dst.val = src.val; - break; - case 0xd0 ... 0xd1: /* Grp2 */ - src.val = 1; - goto grp2; - case 0xd2 ... 0xd3: /* Grp2 */ - src.val = _regs[VCPU_REGS_RCX]; - goto grp2; - case 0xf6 ... 0xf7: /* Grp3 */ - switch (modrm_reg) { - case 0 ... 1: /* test */ - /* - * Special case in Grp3: test has an immediate - * source operand. - */ - src.type = OP_IMM; - src.ptr = (unsigned long *)_eip; - src.bytes = (d & ByteOp) ? 1 : op_bytes; - if (src.bytes == 8) - src.bytes = 4; - switch (src.bytes) { - case 1: - src.val = insn_fetch(s8, 1, _eip); - break; - case 2: - src.val = insn_fetch(s16, 2, _eip); - break; - case 4: - src.val = insn_fetch(s32, 4, _eip); - break; - } - goto test; - case 2: /* not */ - dst.val = ~dst.val; - break; - case 3: /* neg */ - emulate_1op("neg", dst, _eflags); - break; - default: - goto cannot_emulate; - } - break; - case 0xfe ... 0xff: /* Grp4/Grp5 */ - switch (modrm_reg) { - case 0: /* inc */ - emulate_1op("inc", dst, _eflags); - break; - case 1: /* dec */ - emulate_1op("dec", dst, _eflags); - break; - case 4: /* jmp abs */ - if (b == 0xff) - _eip = dst.val; - else - goto cannot_emulate; - break; - case 6: /* push */ - /* 64-bit mode: PUSH always pushes a 64-bit operand. */ - if (mode == X86EMUL_MODE_PROT64) { - dst.bytes = 8; - if ((rc = ops->read_std((unsigned long)dst.ptr, - &dst.val, 8, - ctxt->vcpu)) != 0) - goto done; - } - register_address_increment(_regs[VCPU_REGS_RSP], - -dst.bytes); - if ((rc = ops->write_emulated( - register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]), - &dst.val, dst.bytes, ctxt->vcpu)) != 0) - goto done; - no_wb = 1; - break; - default: - goto cannot_emulate; - } - break; - } - -writeback: - if (!no_wb) { - switch (dst.type) { - case OP_REG: - /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ - switch (dst.bytes) { - case 1: - *(u8 *)dst.ptr = (u8)dst.val; - break; - case 2: - *(u16 *)dst.ptr = (u16)dst.val; - break; - case 4: - *dst.ptr = (u32)dst.val; - break; /* 64b: zero-ext */ - case 8: - *dst.ptr = dst.val; - break; - } - break; - case OP_MEM: - if (lock_prefix) - rc = ops->cmpxchg_emulated((unsigned long)dst. - ptr, &dst.orig_val, - &dst.val, dst.bytes, - ctxt->vcpu); - else - rc = ops->write_emulated((unsigned long)dst.ptr, - &dst.val, dst.bytes, - ctxt->vcpu); - if (rc != 0) - goto done; - default: - break; - } - } - - /* Commit shadow register state. */ - memcpy(ctxt->vcpu->regs, _regs, sizeof _regs); - ctxt->eflags = _eflags; - ctxt->vcpu->rip = _eip; - -done: - return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; - -special_insn: - if (twobyte) - goto twobyte_special_insn; - switch(b) { - case 0x50 ... 0x57: /* push reg */ - if (op_bytes == 2) - src.val = (u16) _regs[b & 0x7]; - else - src.val = (u32) _regs[b & 0x7]; - dst.type = OP_MEM; - dst.bytes = op_bytes; - dst.val = src.val; - register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); - dst.ptr = (void *) register_address( - ctxt->ss_base, _regs[VCPU_REGS_RSP]); - break; - case 0x58 ... 0x5f: /* pop reg */ - dst.ptr = (unsigned long *)&_regs[b & 0x7]; - pop_instruction: - if ((rc = ops->read_std(register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt->vcpu)) - != 0) - goto done; - - register_address_increment(_regs[VCPU_REGS_RSP], op_bytes); - no_wb = 1; /* Disable writeback. */ - break; - case 0x6a: /* push imm8 */ - src.val = 0L; - src.val = insn_fetch(s8, 1, _eip); - push: - dst.type = OP_MEM; - dst.bytes = op_bytes; - dst.val = src.val; - register_address_increment(_regs[VCPU_REGS_RSP], -op_bytes); - dst.ptr = (void *) register_address(ctxt->ss_base, - _regs[VCPU_REGS_RSP]); - break; - case 0x6c: /* insb */ - case 0x6d: /* insw/insd */ - if (kvm_emulate_pio_string(ctxt->vcpu, NULL, - 1, /* in */ - (d & ByteOp) ? 1 : op_bytes, /* size */ - rep_prefix ? - address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ - (_eflags & EFLG_DF), /* down */ - register_address(ctxt->es_base, - _regs[VCPU_REGS_RDI]), /* address */ - rep_prefix, - _regs[VCPU_REGS_RDX] /* port */ - ) == 0) - return -1; - return 0; - case 0x6e: /* outsb */ - case 0x6f: /* outsw/outsd */ - if (kvm_emulate_pio_string(ctxt->vcpu, NULL, - 0, /* in */ - (d & ByteOp) ? 1 : op_bytes, /* size */ - rep_prefix ? - address_mask(_regs[VCPU_REGS_RCX]) : 1, /* count */ - (_eflags & EFLG_DF), /* down */ - register_address(override_base ? - *override_base : ctxt->ds_base, - _regs[VCPU_REGS_RSI]), /* address */ - rep_prefix, - _regs[VCPU_REGS_RDX] /* port */ - ) == 0) - return -1; - return 0; - case 0x70 ... 0x7f: /* jcc (short) */ { - int rel = insn_fetch(s8, 1, _eip); - - if (test_cc(b, _eflags)) - JMP_REL(rel); - break; - } - case 0x9c: /* pushf */ - src.val = (unsigned long) _eflags; - goto push; - case 0x9d: /* popf */ - dst.ptr = (unsigned long *) &_eflags; - goto pop_instruction; - case 0xc3: /* ret */ - dst.ptr = &_eip; - goto pop_instruction; - case 0xf4: /* hlt */ - ctxt->vcpu->halt_request = 1; - goto done; - } - if (rep_prefix) { - if (_regs[VCPU_REGS_RCX] == 0) { - ctxt->vcpu->rip = _eip; - goto done; - } - _regs[VCPU_REGS_RCX]--; - _eip = ctxt->vcpu->rip; - } - switch (b) { - case 0xa4 ... 0xa5: /* movs */ - dst.type = OP_MEM; - dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.ptr = (unsigned long *)register_address(ctxt->es_base, - _regs[VCPU_REGS_RDI]); - if ((rc = ops->read_emulated(register_address( - override_base ? *override_base : ctxt->ds_base, - _regs[VCPU_REGS_RSI]), &dst.val, dst.bytes, ctxt->vcpu)) != 0) - goto done; - register_address_increment(_regs[VCPU_REGS_RSI], - (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); - register_address_increment(_regs[VCPU_REGS_RDI], - (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); - break; - case 0xa6 ... 0xa7: /* cmps */ - DPRINTF("Urk! I don't handle CMPS.\n"); - goto cannot_emulate; - case 0xaa ... 0xab: /* stos */ - dst.type = OP_MEM; - dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.ptr = (unsigned long *)cr2; - dst.val = _regs[VCPU_REGS_RAX]; - register_address_increment(_regs[VCPU_REGS_RDI], - (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); - break; - case 0xac ... 0xad: /* lods */ - dst.type = OP_REG; - dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - if ((rc = ops->read_emulated(cr2, &dst.val, dst.bytes, - ctxt->vcpu)) != 0) - goto done; - register_address_increment(_regs[VCPU_REGS_RSI], - (_eflags & EFLG_DF) ? -dst.bytes : dst.bytes); - break; - case 0xae ... 0xaf: /* scas */ - DPRINTF("Urk! I don't handle SCAS.\n"); - goto cannot_emulate; - case 0xe8: /* call (near) */ { - long int rel; - switch (op_bytes) { - case 2: - rel = insn_fetch(s16, 2, _eip); - break; - case 4: - rel = insn_fetch(s32, 4, _eip); - break; - case 8: - rel = insn_fetch(s64, 8, _eip); - break; - default: - DPRINTF("Call: Invalid op_bytes\n"); - goto cannot_emulate; - } - src.val = (unsigned long) _eip; - JMP_REL(rel); - op_bytes = ad_bytes; - goto push; - } - case 0xe9: /* jmp rel */ - case 0xeb: /* jmp rel short */ - JMP_REL(src.val); - no_wb = 1; /* Disable writeback. */ - break; - - - } - goto writeback; - -twobyte_insn: - switch (b) { - case 0x01: /* lgdt, lidt, lmsw */ - /* Disable writeback. */ - no_wb = 1; - switch (modrm_reg) { - u16 size; - unsigned long address; - - case 2: /* lgdt */ - rc = read_descriptor(ctxt, ops, src.ptr, - &size, &address, op_bytes); - if (rc) - goto done; - realmode_lgdt(ctxt->vcpu, size, address); - break; - case 3: /* lidt */ - rc = read_descriptor(ctxt, ops, src.ptr, - &size, &address, op_bytes); - if (rc) - goto done; - realmode_lidt(ctxt->vcpu, size, address); - break; - case 4: /* smsw */ - if (modrm_mod != 3) - goto cannot_emulate; - *(u16 *)&_regs[modrm_rm] - = realmode_get_cr(ctxt->vcpu, 0); - break; - case 6: /* lmsw */ - if (modrm_mod != 3) - goto cannot_emulate; - realmode_lmsw(ctxt->vcpu, (u16)modrm_val, &_eflags); - break; - case 7: /* invlpg*/ - emulate_invlpg(ctxt->vcpu, cr2); - break; - default: - goto cannot_emulate; - } - break; - case 0x21: /* mov from dr to reg */ - no_wb = 1; - if (modrm_mod != 3) - goto cannot_emulate; - rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]); - break; - case 0x23: /* mov from reg to dr */ - no_wb = 1; - if (modrm_mod != 3) - goto cannot_emulate; - rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]); - break; - case 0x40 ... 0x4f: /* cmov */ - dst.val = dst.orig_val = src.val; - no_wb = 1; - /* - * First, assume we're decoding an even cmov opcode - * (lsb == 0). - */ - switch ((b & 15) >> 1) { - case 0: /* cmovo */ - no_wb = (_eflags & EFLG_OF) ? 0 : 1; - break; - case 1: /* cmovb/cmovc/cmovnae */ - no_wb = (_eflags & EFLG_CF) ? 0 : 1; - break; - case 2: /* cmovz/cmove */ - no_wb = (_eflags & EFLG_ZF) ? 0 : 1; - break; - case 3: /* cmovbe/cmovna */ - no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1; - break; - case 4: /* cmovs */ - no_wb = (_eflags & EFLG_SF) ? 0 : 1; - break; - case 5: /* cmovp/cmovpe */ - no_wb = (_eflags & EFLG_PF) ? 0 : 1; - break; - case 7: /* cmovle/cmovng */ - no_wb = (_eflags & EFLG_ZF) ? 0 : 1; - /* fall through */ - case 6: /* cmovl/cmovnge */ - no_wb &= (!(_eflags & EFLG_SF) != - !(_eflags & EFLG_OF)) ? 0 : 1; - break; - } - /* Odd cmov opcodes (lsb == 1) have inverted sense. */ - no_wb ^= b & 1; - break; - case 0xa3: - bt: /* bt */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("bt", src, dst, _eflags); - break; - case 0xab: - bts: /* bts */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("bts", src, dst, _eflags); - break; - case 0xb0 ... 0xb1: /* cmpxchg */ - /* - * Save real source value, then compare EAX against - * destination. - */ - src.orig_val = src.val; - src.val = _regs[VCPU_REGS_RAX]; - emulate_2op_SrcV("cmp", src, dst, _eflags); - if (_eflags & EFLG_ZF) { - /* Success: write back to memory. */ - dst.val = src.orig_val; - } else { - /* Failure: write the value we saw to EAX. */ - dst.type = OP_REG; - dst.ptr = (unsigned long *)&_regs[VCPU_REGS_RAX]; - } - break; - case 0xb3: - btr: /* btr */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("btr", src, dst, _eflags); - break; - case 0xb6 ... 0xb7: /* movzx */ - dst.bytes = op_bytes; - dst.val = (d & ByteOp) ? (u8) src.val : (u16) src.val; - break; - case 0xba: /* Grp8 */ - switch (modrm_reg & 3) { - case 0: - goto bt; - case 1: - goto bts; - case 2: - goto btr; - case 3: - goto btc; - } - break; - case 0xbb: - btc: /* btc */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ - emulate_2op_SrcV_nobyte("btc", src, dst, _eflags); - break; - case 0xbe ... 0xbf: /* movsx */ - dst.bytes = op_bytes; - dst.val = (d & ByteOp) ? (s8) src.val : (s16) src.val; - break; - case 0xc3: /* movnti */ - dst.bytes = op_bytes; - dst.val = (op_bytes == 4) ? (u32) src.val : (u64) src.val; - break; - } - goto writeback; - -twobyte_special_insn: - /* Disable writeback. */ - no_wb = 1; - switch (b) { - case 0x06: - emulate_clts(ctxt->vcpu); - break; - case 0x08: /* invd */ - break; - case 0x09: /* wbinvd */ - break; - case 0x0d: /* GrpP (prefetch) */ - case 0x18: /* Grp16 (prefetch/nop) */ - break; - case 0x20: /* mov cr, reg */ - if (modrm_mod != 3) - goto cannot_emulate; - _regs[modrm_rm] = realmode_get_cr(ctxt->vcpu, modrm_reg); - break; - case 0x22: /* mov reg, cr */ - if (modrm_mod != 3) - goto cannot_emulate; - realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags); - break; - case 0x30: - /* wrmsr */ - msr_data = (u32)_regs[VCPU_REGS_RAX] - | ((u64)_regs[VCPU_REGS_RDX] << 32); - rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data); - if (rc) { - kvm_x86_ops->inject_gp(ctxt->vcpu, 0); - _eip = ctxt->vcpu->rip; - } - rc = X86EMUL_CONTINUE; - break; - case 0x32: - /* rdmsr */ - rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data); - if (rc) { - kvm_x86_ops->inject_gp(ctxt->vcpu, 0); - _eip = ctxt->vcpu->rip; - } else { - _regs[VCPU_REGS_RAX] = (u32)msr_data; - _regs[VCPU_REGS_RDX] = msr_data >> 32; - } - rc = X86EMUL_CONTINUE; - break; - case 0x80 ... 0x8f: /* jnz rel, etc*/ { - long int rel; - - switch (op_bytes) { - case 2: - rel = insn_fetch(s16, 2, _eip); - break; - case 4: - rel = insn_fetch(s32, 4, _eip); - break; - case 8: - rel = insn_fetch(s64, 8, _eip); - break; - default: - DPRINTF("jnz: Invalid op_bytes\n"); - goto cannot_emulate; - } - if (test_cc(b, _eflags)) - JMP_REL(rel); - break; - } - case 0xc7: /* Grp9 (cmpxchg8b) */ - { - u64 old, new; - if ((rc = ops->read_emulated(cr2, &old, 8, ctxt->vcpu)) - != 0) - goto done; - if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) || - ((u32) (old >> 32) != (u32) _regs[VCPU_REGS_RDX])) { - _regs[VCPU_REGS_RAX] = (u32) (old >> 0); - _regs[VCPU_REGS_RDX] = (u32) (old >> 32); - _eflags &= ~EFLG_ZF; - } else { - new = ((u64)_regs[VCPU_REGS_RCX] << 32) - | (u32) _regs[VCPU_REGS_RBX]; - if ((rc = ops->cmpxchg_emulated(cr2, &old, - &new, 8, ctxt->vcpu)) != 0) - goto done; - _eflags |= EFLG_ZF; - } - break; - } - } - goto writeback; - -cannot_emulate: - DPRINTF("Cannot emulate %02x\n", b); - return -1; -} - -#ifdef __XEN__ - -#include <asm/mm.h> -#include <asm/uaccess.h> - -int -x86_emulate_read_std(unsigned long addr, - unsigned long *val, - unsigned int bytes, struct x86_emulate_ctxt *ctxt) -{ - unsigned int rc; - - *val = 0; - - if ((rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0) { - propagate_page_fault(addr + bytes - rc, 0); /* read fault */ - return X86EMUL_PROPAGATE_FAULT; - } - - return X86EMUL_CONTINUE; -} - -int -x86_emulate_write_std(unsigned long addr, - unsigned long val, - unsigned int bytes, struct x86_emulate_ctxt *ctxt) -{ - unsigned int rc; - - if ((rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0) { - propagate_page_fault(addr + bytes - rc, PGERR_write_access); - return X86EMUL_PROPAGATE_FAULT; - } - - return X86EMUL_CONTINUE; -} - -#endif diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h deleted file mode 100644 index 92c73aa7f9ac..000000000000 --- a/drivers/kvm/x86_emulate.h +++ /dev/null @@ -1,155 +0,0 @@ -/****************************************************************************** - * x86_emulate.h - * - * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. - * - * Copyright (c) 2005 Keir Fraser - * - * From: xen-unstable 10676:af9809f51f81a3c43f276f00c81a52ef558afda4 - */ - -#ifndef __X86_EMULATE_H__ -#define __X86_EMULATE_H__ - -struct x86_emulate_ctxt; - -/* - * x86_emulate_ops: - * - * These operations represent the instruction emulator's interface to memory. - * There are two categories of operation: those that act on ordinary memory - * regions (*_std), and those that act on memory regions known to require - * special treatment or emulation (*_emulated). - * - * The emulator assumes that an instruction accesses only one 'emulated memory' - * location, that this location is the given linear faulting address (cr2), and - * that this is one of the instruction's data operands. Instruction fetches and - * stack operations are assumed never to access emulated memory. The emulator - * automatically deduces which operand of a string-move operation is accessing - * emulated memory, and assumes that the other operand accesses normal memory. - * - * NOTES: - * 1. The emulator isn't very smart about emulated vs. standard memory. - * 'Emulated memory' access addresses should be checked for sanity. - * 'Normal memory' accesses may fault, and the caller must arrange to - * detect and handle reentrancy into the emulator via recursive faults. - * Accesses may be unaligned and may cross page boundaries. - * 2. If the access fails (cannot emulate, or a standard access faults) then - * it is up to the memop to propagate the fault to the guest VM via - * some out-of-band mechanism, unknown to the emulator. The memop signals - * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will - * then immediately bail. - * 3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only - * cmpxchg8b_emulated need support 8-byte accesses. - * 4. The emulator cannot handle 64-bit mode emulation on an x86/32 system. - */ -/* Access completed successfully: continue emulation as normal. */ -#define X86EMUL_CONTINUE 0 -/* Access is unhandleable: bail from emulation and return error to caller. */ -#define X86EMUL_UNHANDLEABLE 1 -/* Terminate emulation but return success to the caller. */ -#define X86EMUL_PROPAGATE_FAULT 2 /* propagate a generated fault to guest */ -#define X86EMUL_RETRY_INSTR 2 /* retry the instruction for some reason */ -#define X86EMUL_CMPXCHG_FAILED 2 /* cmpxchg did not see expected value */ -struct x86_emulate_ops { - /* - * read_std: Read bytes of standard (non-emulated/special) memory. - * Used for instruction fetch, stack operations, and others. - * @addr: [IN ] Linear address from which to read. - * @val: [OUT] Value read from memory, zero-extended to 'u_long'. - * @bytes: [IN ] Number of bytes to read from memory. - */ - int (*read_std)(unsigned long addr, void *val, - unsigned int bytes, struct kvm_vcpu *vcpu); - - /* - * write_std: Write bytes of standard (non-emulated/special) memory. - * Used for stack operations, and others. - * @addr: [IN ] Linear address to which to write. - * @val: [IN ] Value to write to memory (low-order bytes used as - * required). - * @bytes: [IN ] Number of bytes to write to memory. - */ - int (*write_std)(unsigned long addr, const void *val, - unsigned int bytes, struct kvm_vcpu *vcpu); - - /* - * read_emulated: Read bytes from emulated/special memory area. - * @addr: [IN ] Linear address from which to read. - * @val: [OUT] Value read from memory, zero-extended to 'u_long'. - * @bytes: [IN ] Number of bytes to read from memory. - */ - int (*read_emulated) (unsigned long addr, - void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu); - - /* - * write_emulated: Read bytes from emulated/special memory area. - * @addr: [IN ] Linear address to which to write. - * @val: [IN ] Value to write to memory (low-order bytes used as - * required). - * @bytes: [IN ] Number of bytes to write to memory. - */ - int (*write_emulated) (unsigned long addr, - const void *val, - unsigned int bytes, - struct kvm_vcpu *vcpu); - - /* - * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an - * emulated/special memory area. - * @addr: [IN ] Linear address to access. - * @old: [IN ] Value expected to be current at @addr. - * @new: [IN ] Value to write to @addr. - * @bytes: [IN ] Number of bytes to access using CMPXCHG. - */ - int (*cmpxchg_emulated) (unsigned long addr, - const void *old, - const void *new, - unsigned int bytes, - struct kvm_vcpu *vcpu); - -}; - -struct x86_emulate_ctxt { - /* Register state before/after emulation. */ - struct kvm_vcpu *vcpu; - - /* Linear faulting address (if emulating a page-faulting instruction). */ - unsigned long eflags; - unsigned long cr2; - - /* Emulated execution mode, represented by an X86EMUL_MODE value. */ - int mode; - - unsigned long cs_base; - unsigned long ds_base; - unsigned long es_base; - unsigned long ss_base; - unsigned long gs_base; - unsigned long fs_base; -}; - -/* Execution mode, passed to the emulator. */ -#define X86EMUL_MODE_REAL 0 /* Real mode. */ -#define X86EMUL_MODE_PROT16 2 /* 16-bit protected mode. */ -#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */ -#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */ - -/* Host execution mode. */ -#if defined(__i386__) -#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32 -#elif defined(CONFIG_X86_64) -#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 -#endif - -/* - * x86_emulate_memop: Emulate an instruction that faulted attempting to - * read/write a 'special' memory area. - * Returns -1 on failure, 0 on success. - */ -int x86_emulate_memop(struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops); - -#endif /* __X86_EMULATE_H__ */ diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index cb4c67025d52..7743d73768df 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -151,43 +151,43 @@ int lguest_address_ok(const struct lguest *lg, /* This routine copies memory from the Guest. Here we can see how useful the * kill_lguest() routine we met in the Launcher can be: we return a random * value (all zeroes) instead of needing to return an error. */ -void __lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes) +void __lgread(struct lg_cpu *cpu, void *b, unsigned long addr, unsigned bytes) { - if (!lguest_address_ok(lg, addr, bytes) - || copy_from_user(b, lg->mem_base + addr, bytes) != 0) { + if (!lguest_address_ok(cpu->lg, addr, bytes) + || copy_from_user(b, cpu->lg->mem_base + addr, bytes) != 0) { /* copy_from_user should do this, but as we rely on it... */ memset(b, 0, bytes); - kill_guest(lg, "bad read address %#lx len %u", addr, bytes); + kill_guest(cpu, "bad read address %#lx len %u", addr, bytes); } } /* This is the write (copy into guest) version. */ -void __lgwrite(struct lguest *lg, unsigned long addr, const void *b, +void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b, unsigned bytes) { - if (!lguest_address_ok(lg, addr, bytes) - || copy_to_user(lg->mem_base + addr, b, bytes) != 0) - kill_guest(lg, "bad write address %#lx len %u", addr, bytes); + if (!lguest_address_ok(cpu->lg, addr, bytes) + || copy_to_user(cpu->lg->mem_base + addr, b, bytes) != 0) + kill_guest(cpu, "bad write address %#lx len %u", addr, bytes); } /*:*/ /*H:030 Let's jump straight to the the main loop which runs the Guest. * Remember, this is called by the Launcher reading /dev/lguest, and we keep * going around and around until something interesting happens. */ -int run_guest(struct lguest *lg, unsigned long __user *user) +int run_guest(struct lg_cpu *cpu, unsigned long __user *user) { /* We stop running once the Guest is dead. */ - while (!lg->dead) { + while (!cpu->lg->dead) { /* First we run any hypercalls the Guest wants done. */ - if (lg->hcall) - do_hypercalls(lg); + if (cpu->hcall) + do_hypercalls(cpu); /* It's possible the Guest did a NOTIFY hypercall to the * Launcher, in which case we return from the read() now. */ - if (lg->pending_notify) { - if (put_user(lg->pending_notify, user)) + if (cpu->pending_notify) { + if (put_user(cpu->pending_notify, user)) return -EFAULT; - return sizeof(lg->pending_notify); + return sizeof(cpu->pending_notify); } /* Check for signals */ @@ -195,13 +195,13 @@ int run_guest(struct lguest *lg, unsigned long __user *user) return -ERESTARTSYS; /* If Waker set break_out, return to Launcher. */ - if (lg->break_out) + if (cpu->break_out) return -EAGAIN; /* Check if there are any interrupts which can be delivered * now: if so, this sets up the hander to be executed when we * next run the Guest. */ - maybe_do_interrupt(lg); + maybe_do_interrupt(cpu); /* All long-lived kernel loops need to check with this horrible * thing called the freezer. If the Host is trying to suspend, @@ -210,12 +210,12 @@ int run_guest(struct lguest *lg, unsigned long __user *user) /* Just make absolutely sure the Guest is still alive. One of * those hypercalls could have been fatal, for example. */ - if (lg->dead) + if (cpu->lg->dead) break; /* If the Guest asked to be stopped, we sleep. The Guest's * clock timer or LHCALL_BREAK from the Waker will wake us. */ - if (lg->halted) { + if (cpu->halted) { set_current_state(TASK_INTERRUPTIBLE); schedule(); continue; @@ -226,15 +226,17 @@ int run_guest(struct lguest *lg, unsigned long __user *user) local_irq_disable(); /* Actually run the Guest until something happens. */ - lguest_arch_run_guest(lg); + lguest_arch_run_guest(cpu); /* Now we're ready to be interrupted or moved to other CPUs */ local_irq_enable(); /* Now we deal with whatever happened to the Guest. */ - lguest_arch_handle_trap(lg); + lguest_arch_handle_trap(cpu); } + if (cpu->lg->dead == ERR_PTR(-ERESTART)) + return -ERESTART; /* The Guest is dead => "No such file or directory" */ return -ENOENT; } @@ -253,7 +255,7 @@ static int __init init(void) /* Lguest can't run under Xen, VMI or itself. It does Tricky Stuff. */ if (paravirt_enabled()) { - printk("lguest is afraid of %s\n", pv_info.name); + printk("lguest is afraid of being a guest\n"); return -EPERM; } diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index b478affe8f91..0f2cb4fd7c69 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c @@ -23,13 +23,14 @@ #include <linux/uaccess.h> #include <linux/syscalls.h> #include <linux/mm.h> +#include <linux/ktime.h> #include <asm/page.h> #include <asm/pgtable.h> #include "lg.h" /*H:120 This is the core hypercall routine: where the Guest gets what it wants. * Or gets killed. Or, in the case of LHCALL_CRASH, both. */ -static void do_hcall(struct lguest *lg, struct hcall_args *args) +static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args) { switch (args->arg0) { case LHCALL_FLUSH_ASYNC: @@ -39,60 +40,62 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) case LHCALL_LGUEST_INIT: /* You can't get here unless you're already initialized. Don't * do that. */ - kill_guest(lg, "already have lguest_data"); + kill_guest(cpu, "already have lguest_data"); break; - case LHCALL_CRASH: { - /* Crash is such a trivial hypercall that we do it in four + case LHCALL_SHUTDOWN: { + /* Shutdown is such a trivial hypercall that we do it in four * lines right here. */ char msg[128]; /* If the lgread fails, it will call kill_guest() itself; the * kill_guest() with the message will be ignored. */ - __lgread(lg, msg, args->arg1, sizeof(msg)); + __lgread(cpu, msg, args->arg1, sizeof(msg)); msg[sizeof(msg)-1] = '\0'; - kill_guest(lg, "CRASH: %s", msg); + kill_guest(cpu, "CRASH: %s", msg); + if (args->arg2 == LGUEST_SHUTDOWN_RESTART) + cpu->lg->dead = ERR_PTR(-ERESTART); break; } case LHCALL_FLUSH_TLB: /* FLUSH_TLB comes in two flavors, depending on the * argument: */ if (args->arg1) - guest_pagetable_clear_all(lg); + guest_pagetable_clear_all(cpu); else - guest_pagetable_flush_user(lg); + guest_pagetable_flush_user(cpu); break; /* All these calls simply pass the arguments through to the right * routines. */ case LHCALL_NEW_PGTABLE: - guest_new_pagetable(lg, args->arg1); + guest_new_pagetable(cpu, args->arg1); break; case LHCALL_SET_STACK: - guest_set_stack(lg, args->arg1, args->arg2, args->arg3); + guest_set_stack(cpu, args->arg1, args->arg2, args->arg3); break; case LHCALL_SET_PTE: - guest_set_pte(lg, args->arg1, args->arg2, __pte(args->arg3)); + guest_set_pte(cpu, args->arg1, args->arg2, __pte(args->arg3)); break; case LHCALL_SET_PMD: - guest_set_pmd(lg, args->arg1, args->arg2); + guest_set_pmd(cpu->lg, args->arg1, args->arg2); break; case LHCALL_SET_CLOCKEVENT: - guest_set_clockevent(lg, args->arg1); + guest_set_clockevent(cpu, args->arg1); break; case LHCALL_TS: /* This sets the TS flag, as we saw used in run_guest(). */ - lg->ts = args->arg1; + cpu->ts = args->arg1; break; case LHCALL_HALT: /* Similarly, this sets the halted flag for run_guest(). */ - lg->halted = 1; + cpu->halted = 1; break; case LHCALL_NOTIFY: - lg->pending_notify = args->arg1; + cpu->pending_notify = args->arg1; break; default: /* It should be an architecture-specific hypercall. */ - if (lguest_arch_do_hcall(lg, args)) - kill_guest(lg, "Bad hypercall %li\n", args->arg0); + if (lguest_arch_do_hcall(cpu, args)) + kill_guest(cpu, "Bad hypercall %li\n", args->arg0); } } /*:*/ @@ -104,13 +107,13 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) * Guest put them in the ring, but we also promise the Guest that they will * happen before any normal hypercall (which is why we check this before * checking for a normal hcall). */ -static void do_async_hcalls(struct lguest *lg) +static void do_async_hcalls(struct lg_cpu *cpu) { unsigned int i; u8 st[LHCALL_RING_SIZE]; /* For simplicity, we copy the entire call status array in at once. */ - if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st))) + if (copy_from_user(&st, &cpu->lg->lguest_data->hcall_status, sizeof(st))) return; /* We process "struct lguest_data"s hcalls[] ring once. */ @@ -119,7 +122,7 @@ static void do_async_hcalls(struct lguest *lg) /* We remember where we were up to from last time. This makes * sure that the hypercalls are done in the order the Guest * places them in the ring. */ - unsigned int n = lg->next_hcall; + unsigned int n = cpu->next_hcall; /* 0xFF means there's no call here (yet). */ if (st[n] == 0xFF) @@ -127,65 +130,65 @@ static void do_async_hcalls(struct lguest *lg) /* OK, we have hypercall. Increment the "next_hcall" cursor, * and wrap back to 0 if we reach the end. */ - if (++lg->next_hcall == LHCALL_RING_SIZE) - lg->next_hcall = 0; + if (++cpu->next_hcall == LHCALL_RING_SIZE) + cpu->next_hcall = 0; /* Copy the hypercall arguments into a local copy of * the hcall_args struct. */ - if (copy_from_user(&args, &lg->lguest_data->hcalls[n], + if (copy_from_user(&args, &cpu->lg->lguest_data->hcalls[n], sizeof(struct hcall_args))) { - kill_guest(lg, "Fetching async hypercalls"); + kill_guest(cpu, "Fetching async hypercalls"); break; } /* Do the hypercall, same as a normal one. */ - do_hcall(lg, &args); + do_hcall(cpu, &args); /* Mark the hypercall done. */ - if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) { - kill_guest(lg, "Writing result for async hypercall"); + if (put_user(0xFF, &cpu->lg->lguest_data->hcall_status[n])) { + kill_guest(cpu, "Writing result for async hypercall"); break; } /* Stop doing hypercalls if they want to notify the Launcher: * it needs to service this first. */ - if (lg->pending_notify) + if (cpu->pending_notify) break; } } /* Last of all, we look at what happens first of all. The very first time the * Guest makes a hypercall, we end up here to set things up: */ -static void initialize(struct lguest *lg) +static void initialize(struct lg_cpu *cpu) { /* You can't do anything until you're initialized. The Guest knows the * rules, so we're unforgiving here. */ - if (lg->hcall->arg0 != LHCALL_LGUEST_INIT) { - kill_guest(lg, "hypercall %li before INIT", lg->hcall->arg0); + if (cpu->hcall->arg0 != LHCALL_LGUEST_INIT) { + kill_guest(cpu, "hypercall %li before INIT", cpu->hcall->arg0); return; } - if (lguest_arch_init_hypercalls(lg)) - kill_guest(lg, "bad guest page %p", lg->lguest_data); + if (lguest_arch_init_hypercalls(cpu)) + kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); /* The Guest tells us where we're not to deliver interrupts by putting * the range of addresses into "struct lguest_data". */ - if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start) - || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)) - kill_guest(lg, "bad guest page %p", lg->lguest_data); + if (get_user(cpu->lg->noirq_start, &cpu->lg->lguest_data->noirq_start) + || get_user(cpu->lg->noirq_end, &cpu->lg->lguest_data->noirq_end)) + kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); /* We write the current time into the Guest's data page once so it can * set its clock. */ - write_timestamp(lg); + write_timestamp(cpu); /* page_tables.c will also do some setup. */ - page_table_guest_data_init(lg); + page_table_guest_data_init(cpu); /* This is the one case where the above accesses might have been the * first write to a Guest page. This may have caused a copy-on-write * fault, but the old page might be (read-only) in the Guest * pagetable. */ - guest_pagetable_clear_all(lg); + guest_pagetable_clear_all(cpu); } /*H:100 @@ -194,27 +197,27 @@ static void initialize(struct lguest *lg) * Remember from the Guest, hypercalls come in two flavors: normal and * asynchronous. This file handles both of types. */ -void do_hypercalls(struct lguest *lg) +void do_hypercalls(struct lg_cpu *cpu) { /* Not initialized yet? This hypercall must do it. */ - if (unlikely(!lg->lguest_data)) { + if (unlikely(!cpu->lg->lguest_data)) { /* Set up the "struct lguest_data" */ - initialize(lg); + initialize(cpu); /* Hcall is done. */ - lg->hcall = NULL; + cpu->hcall = NULL; return; } /* The Guest has initialized. * * Look in the hypercall ring for the async hypercalls: */ - do_async_hcalls(lg); + do_async_hcalls(cpu); /* If we stopped reading the hypercall ring because the Guest did a * NOTIFY to the Launcher, we want to return now. Otherwise we do * the hypercall. */ - if (!lg->pending_notify) { - do_hcall(lg, lg->hcall); + if (!cpu->pending_notify) { + do_hcall(cpu, cpu->hcall); /* Tricky point: we reset the hcall pointer to mark the * hypercall as "done". We use the hcall pointer rather than * the trap number to indicate a hypercall is pending. @@ -225,16 +228,17 @@ void do_hypercalls(struct lguest *lg) * Launcher, the run_guest() loop will exit without running the * Guest. When it comes back it would try to re-run the * hypercall. */ - lg->hcall = NULL; + cpu->hcall = NULL; } } /* This routine supplies the Guest with time: it's used for wallclock time at * initial boot and as a rough time source if the TSC isn't available. */ -void write_timestamp(struct lguest *lg) +void write_timestamp(struct lg_cpu *cpu) { struct timespec now; ktime_get_real_ts(&now); - if (copy_to_user(&lg->lguest_data->time, &now, sizeof(struct timespec))) - kill_guest(lg, "Writing timestamp"); + if (copy_to_user(&cpu->lg->lguest_data->time, + &now, sizeof(struct timespec))) + kill_guest(cpu, "Writing timestamp"); } diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c index 2b66f79c208b..32e97c1858e5 100644 --- a/drivers/lguest/interrupts_and_traps.c +++ b/drivers/lguest/interrupts_and_traps.c @@ -41,11 +41,11 @@ static int idt_present(u32 lo, u32 hi) /* We need a helper to "push" a value onto the Guest's stack, since that's a * big part of what delivering an interrupt does. */ -static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) +static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val) { /* Stack grows upwards: move stack then write value. */ *gstack -= 4; - lgwrite(lg, *gstack, u32, val); + lgwrite(cpu, *gstack, u32, val); } /*H:210 The set_guest_interrupt() routine actually delivers the interrupt or @@ -60,7 +60,7 @@ static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val) * We set up the stack just like the CPU does for a real interrupt, so it's * identical for the Guest (and the standard "iret" instruction will undo * it). */ -static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) +static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi, int has_err) { unsigned long gstack, origstack; u32 eflags, ss, irq_enable; @@ -69,59 +69,59 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) /* There are two cases for interrupts: one where the Guest is already * in the kernel, and a more complex one where the Guest is in * userspace. We check the privilege level to find out. */ - if ((lg->regs->ss&0x3) != GUEST_PL) { + if ((cpu->regs->ss&0x3) != GUEST_PL) { /* The Guest told us their kernel stack with the SET_STACK * hypercall: both the virtual address and the segment */ - virtstack = lg->esp1; - ss = lg->ss1; + virtstack = cpu->esp1; + ss = cpu->ss1; - origstack = gstack = guest_pa(lg, virtstack); + origstack = gstack = guest_pa(cpu, virtstack); /* We push the old stack segment and pointer onto the new * stack: when the Guest does an "iret" back from the interrupt * handler the CPU will notice they're dropping privilege * levels and expect these here. */ - push_guest_stack(lg, &gstack, lg->regs->ss); - push_guest_stack(lg, &gstack, lg->regs->esp); + push_guest_stack(cpu, &gstack, cpu->regs->ss); + push_guest_stack(cpu, &gstack, cpu->regs->esp); } else { /* We're staying on the same Guest (kernel) stack. */ - virtstack = lg->regs->esp; - ss = lg->regs->ss; + virtstack = cpu->regs->esp; + ss = cpu->regs->ss; - origstack = gstack = guest_pa(lg, virtstack); + origstack = gstack = guest_pa(cpu, virtstack); } /* Remember that we never let the Guest actually disable interrupts, so * the "Interrupt Flag" bit is always set. We copy that bit from the * Guest's "irq_enabled" field into the eflags word: we saw the Guest * copy it back in "lguest_iret". */ - eflags = lg->regs->eflags; - if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0 + eflags = cpu->regs->eflags; + if (get_user(irq_enable, &cpu->lg->lguest_data->irq_enabled) == 0 && !(irq_enable & X86_EFLAGS_IF)) eflags &= ~X86_EFLAGS_IF; /* An interrupt is expected to push three things on the stack: the old * "eflags" word, the old code segment, and the old instruction * pointer. */ - push_guest_stack(lg, &gstack, eflags); - push_guest_stack(lg, &gstack, lg->regs->cs); - push_guest_stack(lg, &gstack, lg->regs->eip); + push_guest_stack(cpu, &gstack, eflags); + push_guest_stack(cpu, &gstack, cpu->regs->cs); + push_guest_stack(cpu, &gstack, cpu->regs->eip); /* For the six traps which supply an error code, we push that, too. */ if (has_err) - push_guest_stack(lg, &gstack, lg->regs->errcode); + push_guest_stack(cpu, &gstack, cpu->regs->errcode); /* Now we've pushed all the old state, we change the stack, the code * segment and the address to execute. */ - lg->regs->ss = ss; - lg->regs->esp = virtstack + (gstack - origstack); - lg->regs->cs = (__KERNEL_CS|GUEST_PL); - lg->regs->eip = idt_address(lo, hi); + cpu->regs->ss = ss; + cpu->regs->esp = virtstack + (gstack - origstack); + cpu->regs->cs = (__KERNEL_CS|GUEST_PL); + cpu->regs->eip = idt_address(lo, hi); /* There are two kinds of interrupt handlers: 0xE is an "interrupt * gate" which expects interrupts to be disabled on entry. */ if (idt_type(lo, hi) == 0xE) - if (put_user(0, &lg->lguest_data->irq_enabled)) - kill_guest(lg, "Disabling interrupts"); + if (put_user(0, &cpu->lg->lguest_data->irq_enabled)) + kill_guest(cpu, "Disabling interrupts"); } /*H:205 @@ -129,23 +129,23 @@ static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err) * * maybe_do_interrupt() gets called before every entry to the Guest, to see if * we should divert the Guest to running an interrupt handler. */ -void maybe_do_interrupt(struct lguest *lg) +void maybe_do_interrupt(struct lg_cpu *cpu) { unsigned int irq; DECLARE_BITMAP(blk, LGUEST_IRQS); struct desc_struct *idt; /* If the Guest hasn't even initialized yet, we can do nothing. */ - if (!lg->lguest_data) + if (!cpu->lg->lguest_data) return; /* Take our "irqs_pending" array and remove any interrupts the Guest * wants blocked: the result ends up in "blk". */ - if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts, + if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts, sizeof(blk))) return; - bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS); + bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS); /* Find the first interrupt. */ irq = find_first_bit(blk, LGUEST_IRQS); @@ -155,19 +155,20 @@ void maybe_do_interrupt(struct lguest *lg) /* They may be in the middle of an iret, where they asked us never to * deliver interrupts. */ - if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end) + if (cpu->regs->eip >= cpu->lg->noirq_start && + (cpu->regs->eip < cpu->lg->noirq_end)) return; /* If they're halted, interrupts restart them. */ - if (lg->halted) { + if (cpu->halted) { /* Re-enable interrupts. */ - if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled)) - kill_guest(lg, "Re-enabling interrupts"); - lg->halted = 0; + if (put_user(X86_EFLAGS_IF, &cpu->lg->lguest_data->irq_enabled)) + kill_guest(cpu, "Re-enabling interrupts"); + cpu->halted = 0; } else { /* Otherwise we check if they have interrupts disabled. */ u32 irq_enabled; - if (get_user(irq_enabled, &lg->lguest_data->irq_enabled)) + if (get_user(irq_enabled, &cpu->lg->lguest_data->irq_enabled)) irq_enabled = 0; if (!irq_enabled) return; @@ -176,15 +177,15 @@ void maybe_do_interrupt(struct lguest *lg) /* Look at the IDT entry the Guest gave us for this interrupt. The * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip * over them. */ - idt = &lg->arch.idt[FIRST_EXTERNAL_VECTOR+irq]; + idt = &cpu->arch.idt[FIRST_EXTERNAL_VECTOR+irq]; /* If they don't have a handler (yet?), we just ignore it */ if (idt_present(idt->a, idt->b)) { /* OK, mark it no longer pending and deliver it. */ - clear_bit(irq, lg->irqs_pending); + clear_bit(irq, cpu->irqs_pending); /* set_guest_interrupt() takes the interrupt descriptor and a * flag to say whether this interrupt pushes an error code onto * the stack as well: virtual interrupts never do. */ - set_guest_interrupt(lg, idt->a, idt->b, 0); + set_guest_interrupt(cpu, idt->a, idt->b, 0); } /* Every time we deliver an interrupt, we update the timestamp in the @@ -192,7 +193,7 @@ void maybe_do_interrupt(struct lguest *lg) * did this more often, but it can actually be quite slow: doing it * here is a compromise which means at least it gets updated every * timer interrupt. */ - write_timestamp(lg); + write_timestamp(cpu); } /*:*/ @@ -245,19 +246,19 @@ static int has_err(unsigned int trap) } /* deliver_trap() returns true if it could deliver the trap. */ -int deliver_trap(struct lguest *lg, unsigned int num) +int deliver_trap(struct lg_cpu *cpu, unsigned int num) { /* Trap numbers are always 8 bit, but we set an impossible trap number * for traps inside the Switcher, so check that here. */ - if (num >= ARRAY_SIZE(lg->arch.idt)) + if (num >= ARRAY_SIZE(cpu->arch.idt)) return 0; /* Early on the Guest hasn't set the IDT entries (or maybe it put a * bogus one in): if we fail here, the Guest will be killed. */ - if (!idt_present(lg->arch.idt[num].a, lg->arch.idt[num].b)) + if (!idt_present(cpu->arch.idt[num].a, cpu->arch.idt[num].b)) return 0; - set_guest_interrupt(lg, lg->arch.idt[num].a, lg->arch.idt[num].b, - has_err(num)); + set_guest_interrupt(cpu, cpu->arch.idt[num].a, + cpu->arch.idt[num].b, has_err(num)); return 1; } @@ -309,18 +310,18 @@ static int direct_trap(unsigned int num) * the Guest. * * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */ -void pin_stack_pages(struct lguest *lg) +void pin_stack_pages(struct lg_cpu *cpu) { unsigned int i; /* Depending on the CONFIG_4KSTACKS option, the Guest can have one or * two pages of stack space. */ - for (i = 0; i < lg->stack_pages; i++) + for (i = 0; i < cpu->lg->stack_pages; i++) /* The stack grows *upwards*, so the address we're given is the * start of the page after the kernel stack. Subtract one to * get back onto the first stack page, and keep subtracting to * get to the rest of the stack pages. */ - pin_page(lg, lg->esp1 - 1 - i * PAGE_SIZE); + pin_page(cpu, cpu->esp1 - 1 - i * PAGE_SIZE); } /* Direct traps also mean that we need to know whenever the Guest wants to use @@ -331,21 +332,21 @@ void pin_stack_pages(struct lguest *lg) * * In Linux each process has its own kernel stack, so this happens a lot: we * change stacks on each context switch. */ -void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) +void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages) { /* You are not allowed have a stack segment with privilege level 0: bad * Guest! */ if ((seg & 0x3) != GUEST_PL) - kill_guest(lg, "bad stack segment %i", seg); + kill_guest(cpu, "bad stack segment %i", seg); /* We only expect one or two stack pages. */ if (pages > 2) - kill_guest(lg, "bad stack pages %u", pages); + kill_guest(cpu, "bad stack pages %u", pages); /* Save where the stack is, and how many pages */ - lg->ss1 = seg; - lg->esp1 = esp; - lg->stack_pages = pages; + cpu->ss1 = seg; + cpu->esp1 = esp; + cpu->lg->stack_pages = pages; /* Make sure the new stack pages are mapped */ - pin_stack_pages(lg); + pin_stack_pages(cpu); } /* All this reference to mapping stacks leads us neatly into the other complex @@ -353,7 +354,7 @@ void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages) /*H:235 This is the routine which actually checks the Guest's IDT entry and * transfers it into the entry in "struct lguest": */ -static void set_trap(struct lguest *lg, struct desc_struct *trap, +static void set_trap(struct lg_cpu *cpu, struct desc_struct *trap, unsigned int num, u32 lo, u32 hi) { u8 type = idt_type(lo, hi); @@ -366,7 +367,7 @@ static void set_trap(struct lguest *lg, struct desc_struct *trap, /* We only support interrupt and trap gates. */ if (type != 0xE && type != 0xF) - kill_guest(lg, "bad IDT type %i", type); + kill_guest(cpu, "bad IDT type %i", type); /* We only copy the handler address, present bit, privilege level and * type. The privilege level controls where the trap can be triggered @@ -383,7 +384,7 @@ static void set_trap(struct lguest *lg, struct desc_struct *trap, * * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */ -void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) +void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int num, u32 lo, u32 hi) { /* Guest never handles: NMI, doublefault, spurious interrupt or * hypercall. We ignore when it tries to set them. */ @@ -392,13 +393,13 @@ void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi) /* Mark the IDT as changed: next time the Guest runs we'll know we have * to copy this again. */ - lg->changed |= CHANGED_IDT; + cpu->changed |= CHANGED_IDT; /* Check that the Guest doesn't try to step outside the bounds. */ - if (num >= ARRAY_SIZE(lg->arch.idt)) - kill_guest(lg, "Setting idt entry %u", num); + if (num >= ARRAY_SIZE(cpu->arch.idt)) + kill_guest(cpu, "Setting idt entry %u", num); else - set_trap(lg, &lg->arch.idt[num], num, lo, hi); + set_trap(cpu, &cpu->arch.idt[num], num, lo, hi); } /* The default entry for each interrupt points into the Switcher routines which @@ -434,14 +435,14 @@ void setup_default_idt_entries(struct lguest_ro_state *state, /*H:240 We don't use the IDT entries in the "struct lguest" directly, instead * we copy them into the IDT which we've set up for Guests on this CPU, just * before we run the Guest. This routine does that copy. */ -void copy_traps(const struct lguest *lg, struct desc_struct *idt, +void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, const unsigned long *def) { unsigned int i; /* 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(lg->arch.idt); i++) { + for (i = 0; i < ARRAY_SIZE(cpu->arch.idt); i++) { /* If no Guest can ever override this trap, leave it alone. */ if (!direct_trap(i)) continue; @@ -450,8 +451,8 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt, * 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(lg->arch.idt[i].a, lg->arch.idt[i].b) == 0xF) - idt[i] = lg->arch.idt[i]; + if (idt_type(cpu->arch.idt[i].a, cpu->arch.idt[i].b) == 0xF) + idt[i] = cpu->arch.idt[i]; else /* Reset it to the default. */ default_idt_entry(&idt[i], i, def[i]); @@ -470,13 +471,13 @@ void copy_traps(const struct lguest *lg, struct desc_struct *idt, * infrastructure to set a callback at that time. * * 0 means "turn off the clock". */ -void guest_set_clockevent(struct lguest *lg, unsigned long delta) +void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta) { ktime_t expires; if (unlikely(delta == 0)) { /* Clock event device is shutting down. */ - hrtimer_cancel(&lg->hrt); + hrtimer_cancel(&cpu->hrt); return; } @@ -484,25 +485,25 @@ void guest_set_clockevent(struct lguest *lg, unsigned long delta) * all the time between now and the timer interrupt it asked for. This * is almost always the right thing to do. */ expires = ktime_add_ns(ktime_get_real(), delta); - hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS); + hrtimer_start(&cpu->hrt, expires, HRTIMER_MODE_ABS); } /* This is the function called when the Guest's timer expires. */ static enum hrtimer_restart clockdev_fn(struct hrtimer *timer) { - struct lguest *lg = container_of(timer, struct lguest, hrt); + struct lg_cpu *cpu = container_of(timer, struct lg_cpu, hrt); /* Remember the first interrupt is the timer interrupt. */ - set_bit(0, lg->irqs_pending); + set_bit(0, cpu->irqs_pending); /* If the Guest is actually stopped, we need to wake it up. */ - if (lg->halted) - wake_up_process(lg->tsk); + if (cpu->halted) + wake_up_process(cpu->tsk); return HRTIMER_NORESTART; } /* This sets up the timer for this Guest. */ -void init_clockdev(struct lguest *lg) +void init_clockdev(struct lg_cpu *cpu) { - hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); - lg->hrt.function = clockdev_fn; + hrtimer_init(&cpu->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS); + cpu->hrt.function = clockdev_fn; } diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 86924891b5eb..2337e1a06f02 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -8,6 +8,7 @@ #include <linux/lguest.h> #include <linux/lguest_launcher.h> #include <linux/wait.h> +#include <linux/hrtimer.h> #include <linux/err.h> #include <asm/semaphore.h> @@ -38,58 +39,72 @@ struct lguest_pages #define CHANGED_GDT_TLS 4 /* Actually a subset of CHANGED_GDT */ #define CHANGED_ALL 3 -/* The private info the thread maintains about the guest. */ -struct lguest -{ - /* At end of a page shared mapped over lguest_pages in guest. */ - unsigned long regs_page; - struct lguest_regs *regs; - struct lguest_data __user *lguest_data; +struct lguest; + +struct lg_cpu { + unsigned int id; + struct lguest *lg; struct task_struct *tsk; struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */ - u32 pfn_limit; - /* This provides the offset to the base of guest-physical - * memory in the Launcher. */ - void __user *mem_base; - unsigned long kernel_address; + u32 cr2; - int halted; int ts; - u32 next_hcall; u32 esp1; u8 ss1; + /* Bitmap of what has changed: see CHANGED_* above. */ + int changed; + + unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */ + + /* At end of a page shared mapped over lguest_pages in guest. */ + unsigned long regs_page; + struct lguest_regs *regs; + + struct lguest_pages *last_pages; + + int cpu_pgd; /* which pgd this cpu is currently using */ + /* If a hypercall was asked for, this points to the arguments. */ struct hcall_args *hcall; + u32 next_hcall; + + /* Virtual clock device */ + struct hrtimer hrt; /* Do we need to stop what we're doing and return to userspace? */ int break_out; wait_queue_head_t break_wq; + int halted; - /* Bitmap of what has changed: see CHANGED_* above. */ - int changed; - struct lguest_pages *last_pages; + /* Pending virtual interrupts */ + DECLARE_BITMAP(irqs_pending, LGUEST_IRQS); + + struct lg_cpu_arch arch; +}; + +/* The private info the thread maintains about the guest. */ +struct lguest +{ + struct lguest_data __user *lguest_data; + struct lg_cpu cpus[NR_CPUS]; + unsigned int nr_cpus; + + u32 pfn_limit; + /* This provides the offset to the base of guest-physical + * memory in the Launcher. */ + void __user *mem_base; + unsigned long kernel_address; - /* We keep a small number of these. */ - u32 pgdidx; struct pgdir pgdirs[4]; unsigned long noirq_start, noirq_end; - unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */ unsigned int stack_pages; u32 tsc_khz; /* Dead? */ const char *dead; - - struct lguest_arch arch; - - /* Virtual clock device */ - struct hrtimer hrt; - - /* Pending virtual interrupts */ - DECLARE_BITMAP(irqs_pending, LGUEST_IRQS); }; extern struct mutex lguest_lock; @@ -97,26 +112,26 @@ extern struct mutex lguest_lock; /* core.c: */ int lguest_address_ok(const struct lguest *lg, unsigned long addr, unsigned long len); -void __lgread(struct lguest *, void *, unsigned long, unsigned); -void __lgwrite(struct lguest *, unsigned long, const void *, unsigned); +void __lgread(struct lg_cpu *, void *, unsigned long, unsigned); +void __lgwrite(struct lg_cpu *, unsigned long, const void *, unsigned); /*H:035 Using memory-copy operations like that is usually inconvient, so we * have the following helper macros which read and write a specific type (often * an unsigned long). * * This reads into a variable of the given type then returns that. */ -#define lgread(lg, addr, type) \ - ({ type _v; __lgread((lg), &_v, (addr), sizeof(_v)); _v; }) +#define lgread(cpu, addr, type) \ + ({ type _v; __lgread((cpu), &_v, (addr), sizeof(_v)); _v; }) /* This checks that the variable is of the given type, then writes it out. */ -#define lgwrite(lg, addr, type, val) \ +#define lgwrite(cpu, addr, type, val) \ do { \ typecheck(type, val); \ - __lgwrite((lg), (addr), &(val), sizeof(val)); \ + __lgwrite((cpu), (addr), &(val), sizeof(val)); \ } while(0) /* (end of memory access helper routines) :*/ -int run_guest(struct lguest *lg, unsigned long __user *user); +int run_guest(struct lg_cpu *cpu, unsigned long __user *user); /* Helper macros to obtain the first 12 or the last 20 bits, this is only the * first step in the migration to the kernel types. pte_pfn is already defined @@ -126,52 +141,53 @@ int run_guest(struct lguest *lg, unsigned long __user *user); #define pgd_pfn(x) (pgd_val(x) >> PAGE_SHIFT) /* interrupts_and_traps.c: */ -void maybe_do_interrupt(struct lguest *lg); -int deliver_trap(struct lguest *lg, unsigned int num); -void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi); -void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages); -void pin_stack_pages(struct lguest *lg); +void maybe_do_interrupt(struct lg_cpu *cpu); +int deliver_trap(struct lg_cpu *cpu, unsigned int num); +void load_guest_idt_entry(struct lg_cpu *cpu, unsigned int i, + u32 low, u32 hi); +void guest_set_stack(struct lg_cpu *cpu, u32 seg, u32 esp, unsigned int pages); +void pin_stack_pages(struct lg_cpu *cpu); void setup_default_idt_entries(struct lguest_ro_state *state, const unsigned long *def); -void copy_traps(const struct lguest *lg, struct desc_struct *idt, +void copy_traps(const struct lg_cpu *cpu, struct desc_struct *idt, const unsigned long *def); -void guest_set_clockevent(struct lguest *lg, unsigned long delta); -void init_clockdev(struct lguest *lg); +void guest_set_clockevent(struct lg_cpu *cpu, unsigned long delta); +void init_clockdev(struct lg_cpu *cpu); bool check_syscall_vector(struct lguest *lg); int init_interrupts(void); void free_interrupts(void); /* segments.c: */ void setup_default_gdt_entries(struct lguest_ro_state *state); -void setup_guest_gdt(struct lguest *lg); -void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num); -void guest_load_tls(struct lguest *lg, unsigned long tls_array); -void copy_gdt(const struct lguest *lg, struct desc_struct *gdt); -void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt); +void setup_guest_gdt(struct lg_cpu *cpu); +void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num); +void guest_load_tls(struct lg_cpu *cpu, unsigned long tls_array); +void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt); +void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt); /* page_tables.c: */ int init_guest_pagetable(struct lguest *lg, unsigned long pgtable); void free_guest_pagetable(struct lguest *lg); -void guest_new_pagetable(struct lguest *lg, unsigned long pgtable); +void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable); void guest_set_pmd(struct lguest *lg, unsigned long gpgdir, u32 i); -void guest_pagetable_clear_all(struct lguest *lg); -void guest_pagetable_flush_user(struct lguest *lg); -void guest_set_pte(struct lguest *lg, unsigned long gpgdir, +void guest_pagetable_clear_all(struct lg_cpu *cpu); +void guest_pagetable_flush_user(struct lg_cpu *cpu); +void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir, unsigned long vaddr, pte_t val); -void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages); -int demand_page(struct lguest *info, unsigned long cr2, int errcode); -void pin_page(struct lguest *lg, unsigned long vaddr); -unsigned long guest_pa(struct lguest *lg, unsigned long vaddr); -void page_table_guest_data_init(struct lguest *lg); +void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages); +int demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode); +void pin_page(struct lg_cpu *cpu, unsigned long vaddr); +unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr); +void page_table_guest_data_init(struct lg_cpu *cpu); /* <arch>/core.c: */ void lguest_arch_host_init(void); void lguest_arch_host_fini(void); -void lguest_arch_run_guest(struct lguest *lg); -void lguest_arch_handle_trap(struct lguest *lg); -int lguest_arch_init_hypercalls(struct lguest *lg); -int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args); -void lguest_arch_setup_regs(struct lguest *lg, unsigned long start); +void lguest_arch_run_guest(struct lg_cpu *cpu); +void lguest_arch_handle_trap(struct lg_cpu *cpu); +int lguest_arch_init_hypercalls(struct lg_cpu *cpu); +int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args); +void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start); /* <arch>/switcher.S: */ extern char start_switcher_text[], end_switcher_text[], switch_to_guest[]; @@ -181,8 +197,8 @@ int lguest_device_init(void); void lguest_device_remove(void); /* hypercalls.c: */ -void do_hypercalls(struct lguest *lg); -void write_timestamp(struct lguest *lg); +void do_hypercalls(struct lg_cpu *cpu); +void write_timestamp(struct lg_cpu *cpu); /*L:035 * Let's step aside for the moment, to study one important routine that's used @@ -208,12 +224,12 @@ void write_timestamp(struct lguest *lg); * Like any macro which uses an "if", it is safely wrapped in a run-once "do { * } while(0)". */ -#define kill_guest(lg, fmt...) \ +#define kill_guest(cpu, fmt...) \ do { \ - if (!(lg)->dead) { \ - (lg)->dead = kasprintf(GFP_ATOMIC, fmt); \ - if (!(lg)->dead) \ - (lg)->dead = ERR_PTR(-ENOMEM); \ + if (!(cpu)->lg->dead) { \ + (cpu)->lg->dead = kasprintf(GFP_ATOMIC, fmt); \ + if (!(cpu)->lg->dead) \ + (cpu)->lg->dead = ERR_PTR(-ENOMEM); \ } \ } while(0) /* (End of aside) :*/ diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c index 3b92a61ba8d2..85d42d3d01a9 100644 --- a/drivers/lguest/lguest_user.c +++ b/drivers/lguest/lguest_user.c @@ -6,6 +6,7 @@ #include <linux/uaccess.h> #include <linux/miscdevice.h> #include <linux/fs.h> +#include <linux/sched.h> #include "lg.h" /*L:055 When something happens, the Waker process needs a way to stop the @@ -13,7 +14,7 @@ * LHREQ_BREAK and the value "1" to /dev/lguest to do this. Once the Launcher * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release * the Waker. */ -static int break_guest_out(struct lguest *lg, const unsigned long __user *input) +static int break_guest_out(struct lg_cpu *cpu, const unsigned long __user*input) { unsigned long on; @@ -22,21 +23,21 @@ static int break_guest_out(struct lguest *lg, const unsigned long __user *input) return -EFAULT; if (on) { - lg->break_out = 1; + cpu->break_out = 1; /* Pop it out of the Guest (may be running on different CPU) */ - wake_up_process(lg->tsk); + wake_up_process(cpu->tsk); /* Wait for them to reset it */ - return wait_event_interruptible(lg->break_wq, !lg->break_out); + return wait_event_interruptible(cpu->break_wq, !cpu->break_out); } else { - lg->break_out = 0; - wake_up(&lg->break_wq); + cpu->break_out = 0; + wake_up(&cpu->break_wq); return 0; } } /*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt * number to /dev/lguest. */ -static int user_send_irq(struct lguest *lg, const unsigned long __user *input) +static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input) { unsigned long irq; @@ -46,7 +47,7 @@ static int user_send_irq(struct lguest *lg, const unsigned long __user *input) return -EINVAL; /* Next time the Guest runs, the core code will see if it can deliver * this interrupt. */ - set_bit(irq, lg->irqs_pending); + set_bit(irq, cpu->irqs_pending); return 0; } @@ -55,13 +56,21 @@ static int user_send_irq(struct lguest *lg, const unsigned long __user *input) static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) { struct lguest *lg = file->private_data; + struct lg_cpu *cpu; + unsigned int cpu_id = *o; /* You must write LHREQ_INITIALIZE first! */ if (!lg) return -EINVAL; + /* Watch out for arbitrary vcpu indexes! */ + if (cpu_id >= lg->nr_cpus) + return -EINVAL; + + cpu = &lg->cpus[cpu_id]; + /* If you're not the task which owns the Guest, go away. */ - if (current != lg->tsk) + if (current != cpu->tsk) return -EPERM; /* If the guest is already dead, we indicate why */ @@ -81,11 +90,53 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o) /* If we returned from read() last time because the Guest notified, * clear the flag. */ - if (lg->pending_notify) - lg->pending_notify = 0; + if (cpu->pending_notify) + cpu->pending_notify = 0; /* Run the Guest until something interesting happens. */ - return run_guest(lg, (unsigned long __user *)user); + return run_guest(cpu, (unsigned long __user *)user); +} + +static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip) +{ + if (id >= NR_CPUS) + return -EINVAL; + + cpu->id = id; + cpu->lg = container_of((cpu - id), struct lguest, cpus[0]); + cpu->lg->nr_cpus++; + init_clockdev(cpu); + + /* We need a complete page for the Guest registers: they are accessible + * to the Guest and we can only grant it access to whole pages. */ + cpu->regs_page = get_zeroed_page(GFP_KERNEL); + if (!cpu->regs_page) + return -ENOMEM; + + /* We actually put the registers at the bottom of the page. */ + cpu->regs = (void *)cpu->regs_page + PAGE_SIZE - sizeof(*cpu->regs); + + /* Now we initialize the Guest's registers, handing it the start + * address. */ + lguest_arch_setup_regs(cpu, start_ip); + + /* Initialize the queue for the waker to wait on */ + init_waitqueue_head(&cpu->break_wq); + + /* We keep a pointer to the Launcher task (ie. current task) for when + * other Guests want to wake this one (inter-Guest I/O). */ + cpu->tsk = current; + + /* We need to keep a pointer to the Launcher's memory map, because if + * the Launcher dies we need to clean it up. If we don't keep a + * reference, it is destroyed before close() is called. */ + cpu->mm = get_task_mm(cpu->tsk); + + /* We remember which CPU's pages this Guest used last, for optimization + * when the same Guest runs on the same CPU twice. */ + cpu->last_pages = NULL; + + return 0; } /*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit) @@ -134,15 +185,10 @@ static int initialize(struct file *file, const unsigned long __user *input) lg->mem_base = (void __user *)(long)args[0]; lg->pfn_limit = args[1]; - /* We need a complete page for the Guest registers: they are accessible - * to the Guest and we can only grant it access to whole pages. */ - lg->regs_page = get_zeroed_page(GFP_KERNEL); - if (!lg->regs_page) { - err = -ENOMEM; + /* This is the first cpu */ + err = lg_cpu_start(&lg->cpus[0], 0, args[3]); + if (err) goto release_guest; - } - /* We actually put the registers at the bottom of the page. */ - lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs); /* Initialize the Guest's shadow page tables, using the toplevel * address the Launcher gave us. This allocates memory, so can @@ -151,28 +197,6 @@ static int initialize(struct file *file, const unsigned long __user *input) if (err) goto free_regs; - /* Now we initialize the Guest's registers, handing it the start - * address. */ - lguest_arch_setup_regs(lg, args[3]); - - /* The timer for lguest's clock needs initialization. */ - init_clockdev(lg); - - /* We keep a pointer to the Launcher task (ie. current task) for when - * other Guests want to wake this one (inter-Guest I/O). */ - lg->tsk = current; - /* We need to keep a pointer to the Launcher's memory map, because if - * the Launcher dies we need to clean it up. If we don't keep a - * reference, it is destroyed before close() is called. */ - lg->mm = get_task_mm(lg->tsk); - - /* Initialize the queue for the waker to wait on */ - init_waitqueue_head(&lg->break_wq); - - /* We remember which CPU's pages this Guest used last, for optimization - * when the same Guest runs on the same CPU twice. */ - lg->last_pages = NULL; - /* We keep our "struct lguest" in the file's private_data. */ file->private_data = lg; @@ -182,7 +206,8 @@ static int initialize(struct file *file, const unsigned long __user *input) return sizeof(args); free_regs: - free_page(lg->regs_page); + /* FIXME: This should be in free_vcpu */ + free_page(lg->cpus[0].regs_page); release_guest: kfree(lg); unlock: @@ -202,30 +227,37 @@ static ssize_t write(struct file *file, const char __user *in, struct lguest *lg = file->private_data; const unsigned long __user *input = (const unsigned long __user *)in; unsigned long req; + struct lg_cpu *uninitialized_var(cpu); + unsigned int cpu_id = *off; if (get_user(req, input) != 0) return -EFAULT; input++; /* If you haven't initialized, you must do that first. */ - if (req != LHREQ_INITIALIZE && !lg) - return -EINVAL; + if (req != LHREQ_INITIALIZE) { + if (!lg || (cpu_id >= lg->nr_cpus)) + return -EINVAL; + cpu = &lg->cpus[cpu_id]; + if (!cpu) + return -EINVAL; + } /* Once the Guest is dead, all you can do is read() why it died. */ if (lg && lg->dead) return -ENOENT; /* If you're not the task which owns the Guest, you can only break */ - if (lg && current != lg->tsk && req != LHREQ_BREAK) + if (lg && current != cpu->tsk && req != LHREQ_BREAK) return -EPERM; switch (req) { case LHREQ_INITIALIZE: return initialize(file, input); case LHREQ_IRQ: - return user_send_irq(lg, input); + return user_send_irq(cpu, input); case LHREQ_BREAK: - return break_guest_out(lg, input); + return break_guest_out(cpu, input); default: return -EINVAL; } @@ -241,6 +273,7 @@ static ssize_t write(struct file *file, const char __user *in, static int close(struct inode *inode, struct file *file) { struct lguest *lg = file->private_data; + unsigned int i; /* If we never successfully initialized, there's nothing to clean up */ if (!lg) @@ -249,19 +282,23 @@ static int close(struct inode *inode, struct file *file) /* We need the big lock, to protect from inter-guest I/O and other * Launchers initializing guests. */ mutex_lock(&lguest_lock); - /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ - hrtimer_cancel(&lg->hrt); + /* Free up the shadow page tables for the Guest. */ free_guest_pagetable(lg); - /* Now all the memory cleanups are done, it's safe to release the - * Launcher's memory management structure. */ - mmput(lg->mm); + + for (i = 0; i < lg->nr_cpus; i++) { + /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ + hrtimer_cancel(&lg->cpus[i].hrt); + /* We can free up the register page we allocated. */ + free_page(lg->cpus[i].regs_page); + /* Now all the memory cleanups are done, it's safe to release + * the Launcher's memory management structure. */ + mmput(lg->cpus[i].mm); + } /* If lg->dead doesn't contain an error code it will be NULL or a * kmalloc()ed string, either of which is ok to hand to kfree(). */ if (!IS_ERR(lg->dead)) kfree(lg->dead); - /* We can free up the register page we allocated. */ - free_page(lg->regs_page); /* We clear the entire structure, which also marks it as free for the * next user. */ memset(lg, 0, sizeof(*lg)); diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index fffabb327157..74b4cf2a6c41 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -68,23 +68,23 @@ static DEFINE_PER_CPU(pte_t *, switcher_pte_pages); * page directory entry (PGD) for that address. Since we keep track of several * page tables, the "i" argument tells us which one we're interested in (it's * usually the current one). */ -static pgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr) +static pgd_t *spgd_addr(struct lg_cpu *cpu, u32 i, unsigned long vaddr) { unsigned int index = pgd_index(vaddr); /* We kill any Guest trying to touch the Switcher addresses. */ if (index >= SWITCHER_PGD_INDEX) { - kill_guest(lg, "attempt to access switcher pages"); + kill_guest(cpu, "attempt to access switcher pages"); index = 0; } /* Return a pointer index'th pgd entry for the i'th page table. */ - return &lg->pgdirs[i].pgdir[index]; + return &cpu->lg->pgdirs[i].pgdir[index]; } /* This routine then takes the page directory entry returned above, which * contains the address of the page table entry (PTE) page. It then returns a * pointer to the PTE entry for the given address. */ -static pte_t *spte_addr(struct lguest *lg, pgd_t spgd, unsigned long vaddr) +static pte_t *spte_addr(pgd_t spgd, unsigned long vaddr) { pte_t *page = __va(pgd_pfn(spgd) << PAGE_SHIFT); /* You should never call this if the PGD entry wasn't valid */ @@ -94,14 +94,13 @@ static pte_t *spte_addr(struct lguest *lg, pgd_t spgd, unsigned long vaddr) /* These two functions just like the above two, except they access the Guest * page tables. Hence they return a Guest address. */ -static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr) +static unsigned long gpgd_addr(struct lg_cpu *cpu, unsigned long vaddr) { unsigned int index = vaddr >> (PGDIR_SHIFT); - return lg->pgdirs[lg->pgdidx].gpgdir + index * sizeof(pgd_t); + return cpu->lg->pgdirs[cpu->cpu_pgd].gpgdir + index * sizeof(pgd_t); } -static unsigned long gpte_addr(struct lguest *lg, - pgd_t gpgd, unsigned long vaddr) +static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr) { unsigned long gpage = pgd_pfn(gpgd) << PAGE_SHIFT; BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT)); @@ -138,7 +137,7 @@ static unsigned long get_pfn(unsigned long virtpfn, int write) * entry can be a little tricky. The flags are (almost) the same, but the * Guest PTE contains a virtual page number: the CPU needs the real page * number. */ -static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write) +static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write) { unsigned long pfn, base, flags; @@ -149,7 +148,7 @@ static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write) flags = (pte_flags(gpte) & ~_PAGE_GLOBAL); /* The Guest's pages are offset inside the Launcher. */ - base = (unsigned long)lg->mem_base / PAGE_SIZE; + base = (unsigned long)cpu->lg->mem_base / PAGE_SIZE; /* We need a temporary "unsigned long" variable to hold the answer from * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't @@ -157,7 +156,7 @@ static pte_t gpte_to_spte(struct lguest *lg, pte_t gpte, int write) * page, given the virtual number. */ pfn = get_pfn(base + pte_pfn(gpte), write); if (pfn == -1UL) { - kill_guest(lg, "failed to get page %lu", pte_pfn(gpte)); + kill_guest(cpu, "failed to get page %lu", pte_pfn(gpte)); /* When we destroy the Guest, we'll go through the shadow page * tables and release_pte() them. Make sure we don't think * this one is valid! */ @@ -177,17 +176,18 @@ static void release_pte(pte_t pte) } /*:*/ -static void check_gpte(struct lguest *lg, pte_t gpte) +static void check_gpte(struct lg_cpu *cpu, pte_t gpte) { if ((pte_flags(gpte) & (_PAGE_PWT|_PAGE_PSE)) - || pte_pfn(gpte) >= lg->pfn_limit) - kill_guest(lg, "bad page table entry"); + || pte_pfn(gpte) >= cpu->lg->pfn_limit) + kill_guest(cpu, "bad page table entry"); } -static void check_gpgd(struct lguest *lg, pgd_t gpgd) +static void check_gpgd(struct lg_cpu *cpu, pgd_t gpgd) { - if ((pgd_flags(gpgd) & ~_PAGE_TABLE) || pgd_pfn(gpgd) >= lg->pfn_limit) - kill_guest(lg, "bad page directory entry"); + if ((pgd_flags(gpgd) & ~_PAGE_TABLE) || + (pgd_pfn(gpgd) >= cpu->lg->pfn_limit)) + kill_guest(cpu, "bad page directory entry"); } /*H:330 @@ -200,7 +200,7 @@ static void check_gpgd(struct lguest *lg, pgd_t gpgd) * * If we fixed up the fault (ie. we mapped the address), this routine returns * true. Otherwise, it was a real fault and we need to tell the Guest. */ -int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) +int demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode) { pgd_t gpgd; pgd_t *spgd; @@ -209,24 +209,24 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) pte_t *spte; /* First step: get the top-level Guest page table entry. */ - gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t); + gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t); /* Toplevel not present? We can't map it in. */ if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) return 0; /* Now look at the matching shadow entry. */ - spgd = spgd_addr(lg, lg->pgdidx, vaddr); + spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) { /* No shadow entry: allocate a new shadow PTE page. */ unsigned long ptepage = get_zeroed_page(GFP_KERNEL); /* This is not really the Guest's fault, but killing it is * simple for this corner case. */ if (!ptepage) { - kill_guest(lg, "out of memory allocating pte page"); + kill_guest(cpu, "out of memory allocating pte page"); return 0; } /* We check that the Guest pgd is OK. */ - check_gpgd(lg, gpgd); + check_gpgd(cpu, gpgd); /* And we copy the flags to the shadow PGD entry. The page * number in the shadow PGD is the page we just allocated. */ *spgd = __pgd(__pa(ptepage) | pgd_flags(gpgd)); @@ -234,8 +234,8 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) /* OK, now we look at the lower level in the Guest page table: keep its * address, because we might update it later. */ - gpte_ptr = gpte_addr(lg, gpgd, vaddr); - gpte = lgread(lg, gpte_ptr, pte_t); + gpte_ptr = gpte_addr(gpgd, vaddr); + gpte = lgread(cpu, gpte_ptr, pte_t); /* If this page isn't in the Guest page tables, we can't page it in. */ if (!(pte_flags(gpte) & _PAGE_PRESENT)) @@ -252,7 +252,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) /* Check that the Guest PTE flags are OK, and the page number is below * the pfn_limit (ie. not mapping the Launcher binary). */ - check_gpte(lg, gpte); + check_gpte(cpu, gpte); /* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */ gpte = pte_mkyoung(gpte); @@ -260,7 +260,7 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) gpte = pte_mkdirty(gpte); /* Get the pointer to the shadow PTE entry we're going to set. */ - spte = spte_addr(lg, *spgd, vaddr); + spte = spte_addr(*spgd, vaddr); /* If there was a valid shadow PTE entry here before, we release it. * This can happen with a write to a previously read-only entry. */ release_pte(*spte); @@ -268,17 +268,17 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) /* If this is a write, we insist that the Guest page is writable (the * final arg to gpte_to_spte()). */ if (pte_dirty(gpte)) - *spte = gpte_to_spte(lg, gpte, 1); + *spte = gpte_to_spte(cpu, gpte, 1); else /* If this is a read, don't set the "writable" bit in the page * table entry, even if the Guest says it's writable. That way * we will come back here when a write does actually occur, so * we can update the Guest's _PAGE_DIRTY flag. */ - *spte = gpte_to_spte(lg, pte_wrprotect(gpte), 0); + *spte = gpte_to_spte(cpu, pte_wrprotect(gpte), 0); /* Finally, we write the Guest PTE entry back: we've set the * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */ - lgwrite(lg, gpte_ptr, pte_t, gpte); + lgwrite(cpu, gpte_ptr, pte_t, gpte); /* The fault is fixed, the page table is populated, the mapping * manipulated, the result returned and the code complete. A small @@ -297,19 +297,19 @@ int demand_page(struct lguest *lg, unsigned long vaddr, int errcode) * * This is a quick version which answers the question: is this virtual address * mapped by the shadow page tables, and is it writable? */ -static int page_writable(struct lguest *lg, unsigned long vaddr) +static int page_writable(struct lg_cpu *cpu, unsigned long vaddr) { pgd_t *spgd; unsigned long flags; /* Look at the current top level entry: is it present? */ - spgd = spgd_addr(lg, lg->pgdidx, vaddr); + spgd = spgd_addr(cpu, cpu->cpu_pgd, vaddr); if (!(pgd_flags(*spgd) & _PAGE_PRESENT)) return 0; /* Check the flags on the pte entry itself: it must be present and * writable. */ - flags = pte_flags(*(spte_addr(lg, *spgd, vaddr))); + flags = pte_flags(*(spte_addr(*spgd, vaddr))); return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW); } @@ -317,10 +317,10 @@ static int page_writable(struct lguest *lg, unsigned long vaddr) /* So, when pin_stack_pages() asks us to pin a page, we check if it's already * in the page tables, and if not, we call demand_page() with error code 2 * (meaning "write"). */ -void pin_page(struct lguest *lg, unsigned long vaddr) +void pin_page(struct lg_cpu *cpu, unsigned long vaddr) { - if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2)) - kill_guest(lg, "bad stack page %#lx", vaddr); + if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2)) + kill_guest(cpu, "bad stack page %#lx", vaddr); } /*H:450 If we chase down the release_pgd() code, it looks like this: */ @@ -358,28 +358,28 @@ static void flush_user_mappings(struct lguest *lg, int idx) * * The Guest has a hypercall to throw away the page tables: it's used when a * large number of mappings have been changed. */ -void guest_pagetable_flush_user(struct lguest *lg) +void guest_pagetable_flush_user(struct lg_cpu *cpu) { /* Drop the userspace part of the current page table. */ - flush_user_mappings(lg, lg->pgdidx); + flush_user_mappings(cpu->lg, cpu->cpu_pgd); } /*:*/ /* We walk down the guest page tables to get a guest-physical address */ -unsigned long guest_pa(struct lguest *lg, unsigned long vaddr) +unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr) { pgd_t gpgd; pte_t gpte; /* First step: get the top-level Guest page table entry. */ - gpgd = lgread(lg, gpgd_addr(lg, vaddr), pgd_t); + gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t); /* Toplevel not present? We can't map it in. */ if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) - kill_guest(lg, "Bad address %#lx", vaddr); + kill_guest(cpu, "Bad address %#lx", vaddr); - gpte = lgread(lg, gpte_addr(lg, gpgd, vaddr), pte_t); + gpte = lgread(cpu, gpte_addr(gpgd, vaddr), pte_t); if (!(pte_flags(gpte) & _PAGE_PRESENT)) - kill_guest(lg, "Bad address %#lx", vaddr); + kill_guest(cpu, "Bad address %#lx", vaddr); return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK); } @@ -399,7 +399,7 @@ static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable) /*H:435 And this is us, creating the new page directory. If we really do * allocate a new one (and so the kernel parts are not there), we set * blank_pgdir. */ -static unsigned int new_pgdir(struct lguest *lg, +static unsigned int new_pgdir(struct lg_cpu *cpu, unsigned long gpgdir, int *blank_pgdir) { @@ -407,22 +407,23 @@ static unsigned int new_pgdir(struct lguest *lg, /* We pick one entry at random to throw out. Choosing the Least * Recently Used might be better, but this is easy. */ - next = random32() % ARRAY_SIZE(lg->pgdirs); + next = random32() % ARRAY_SIZE(cpu->lg->pgdirs); /* If it's never been allocated at all before, try now. */ - if (!lg->pgdirs[next].pgdir) { - lg->pgdirs[next].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); + if (!cpu->lg->pgdirs[next].pgdir) { + cpu->lg->pgdirs[next].pgdir = + (pgd_t *)get_zeroed_page(GFP_KERNEL); /* If the allocation fails, just keep using the one we have */ - if (!lg->pgdirs[next].pgdir) - next = lg->pgdidx; + if (!cpu->lg->pgdirs[next].pgdir) + next = cpu->cpu_pgd; else /* This is a blank page, so there are no kernel * mappings: caller must map the stack! */ *blank_pgdir = 1; } /* Record which Guest toplevel this shadows. */ - lg->pgdirs[next].gpgdir = gpgdir; + cpu->lg->pgdirs[next].gpgdir = gpgdir; /* Release all the non-kernel mappings. */ - flush_user_mappings(lg, next); + flush_user_mappings(cpu->lg, next); return next; } @@ -432,21 +433,21 @@ static unsigned int new_pgdir(struct lguest *lg, * Now we've seen all the page table setting and manipulation, let's see what * what happens when the Guest changes page tables (ie. changes the top-level * pgdir). This occurs on almost every context switch. */ -void guest_new_pagetable(struct lguest *lg, unsigned long pgtable) +void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable) { int newpgdir, repin = 0; /* Look to see if we have this one already. */ - newpgdir = find_pgdir(lg, pgtable); + newpgdir = find_pgdir(cpu->lg, pgtable); /* If not, we allocate or mug an existing one: if it's a fresh one, * repin gets set to 1. */ - if (newpgdir == ARRAY_SIZE(lg->pgdirs)) - newpgdir = new_pgdir(lg, pgtable, &repin); + if (newpgdir == ARRAY_SIZE(cpu->lg->pgdirs)) + newpgdir = new_pgdir(cpu, pgtable, &repin); /* Change the current pgd index to the new one. */ - lg->pgdidx = newpgdir; + cpu->cpu_pgd = newpgdir; /* If it was completely blank, we map in the Guest kernel stack */ if (repin) - pin_stack_pages(lg); + pin_stack_pages(cpu); } /*H:470 Finally, a routine which throws away everything: all PGD entries in all @@ -468,11 +469,11 @@ static void release_all_pagetables(struct lguest *lg) * mapping. Since kernel mappings are in every page table, it's easiest to * throw them all away. This traps the Guest in amber for a while as * everything faults back in, but it's rare. */ -void guest_pagetable_clear_all(struct lguest *lg) +void guest_pagetable_clear_all(struct lg_cpu *cpu) { - release_all_pagetables(lg); + release_all_pagetables(cpu->lg); /* We need the Guest kernel stack mapped again. */ - pin_stack_pages(lg); + pin_stack_pages(cpu); } /*:*/ /*M:009 Since we throw away all mappings when a kernel mapping changes, our @@ -497,24 +498,24 @@ void guest_pagetable_clear_all(struct lguest *lg) * _PAGE_ACCESSED then we can put a read-only PTE entry in immediately, and if * they set _PAGE_DIRTY then we can put a writable PTE entry in immediately. */ -static void do_set_pte(struct lguest *lg, int idx, +static void do_set_pte(struct lg_cpu *cpu, int idx, unsigned long vaddr, pte_t gpte) { /* Look up the matching shadow page directory entry. */ - pgd_t *spgd = spgd_addr(lg, idx, vaddr); + pgd_t *spgd = spgd_addr(cpu, idx, vaddr); /* If the top level isn't present, there's no entry to update. */ if (pgd_flags(*spgd) & _PAGE_PRESENT) { /* Otherwise, we start by releasing the existing entry. */ - pte_t *spte = spte_addr(lg, *spgd, vaddr); + pte_t *spte = spte_addr(*spgd, vaddr); release_pte(*spte); /* If they're setting this entry as dirty or accessed, we might * as well put that entry they've given us in now. This shaves * 10% off a copy-on-write micro-benchmark. */ if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) { - check_gpte(lg, gpte); - *spte = gpte_to_spte(lg, gpte, + check_gpte(cpu, gpte); + *spte = gpte_to_spte(cpu, gpte, pte_flags(gpte) & _PAGE_DIRTY); } else /* Otherwise kill it and we can demand_page() it in @@ -533,22 +534,22 @@ static void do_set_pte(struct lguest *lg, int idx, * * The benefit is that when we have to track a new page table, we can copy keep * all the kernel mappings. This speeds up context switch immensely. */ -void guest_set_pte(struct lguest *lg, +void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir, unsigned long vaddr, pte_t gpte) { /* Kernel mappings must be changed on all top levels. Slow, but * doesn't happen often. */ - if (vaddr >= lg->kernel_address) { + if (vaddr >= cpu->lg->kernel_address) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++) - if (lg->pgdirs[i].pgdir) - do_set_pte(lg, i, vaddr, gpte); + for (i = 0; i < ARRAY_SIZE(cpu->lg->pgdirs); i++) + if (cpu->lg->pgdirs[i].pgdir) + do_set_pte(cpu, i, vaddr, gpte); } else { /* Is this page table one we have a shadow for? */ - int pgdir = find_pgdir(lg, gpgdir); - if (pgdir != ARRAY_SIZE(lg->pgdirs)) + int pgdir = find_pgdir(cpu->lg, gpgdir); + if (pgdir != ARRAY_SIZE(cpu->lg->pgdirs)) /* If so, do the update. */ - do_set_pte(lg, pgdir, vaddr, gpte); + do_set_pte(cpu, pgdir, vaddr, gpte); } } @@ -590,30 +591,32 @@ int init_guest_pagetable(struct lguest *lg, unsigned long pgtable) { /* We start on the first shadow page table, and give it a blank PGD * page. */ - lg->pgdidx = 0; - lg->pgdirs[lg->pgdidx].gpgdir = pgtable; - lg->pgdirs[lg->pgdidx].pgdir = (pgd_t*)get_zeroed_page(GFP_KERNEL); - if (!lg->pgdirs[lg->pgdidx].pgdir) + lg->pgdirs[0].gpgdir = pgtable; + lg->pgdirs[0].pgdir = (pgd_t *)get_zeroed_page(GFP_KERNEL); + if (!lg->pgdirs[0].pgdir) return -ENOMEM; + lg->cpus[0].cpu_pgd = 0; return 0; } /* When the Guest calls LHCALL_LGUEST_INIT we do more setup. */ -void page_table_guest_data_init(struct lguest *lg) +void page_table_guest_data_init(struct lg_cpu *cpu) { /* We get the kernel address: above this is all kernel memory. */ - if (get_user(lg->kernel_address, &lg->lguest_data->kernel_address) + if (get_user(cpu->lg->kernel_address, + &cpu->lg->lguest_data->kernel_address) /* We tell the Guest that it can't use the top 4MB of virtual * addresses used by the Switcher. */ - || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem) - || put_user(lg->pgdirs[lg->pgdidx].gpgdir,&lg->lguest_data->pgdir)) - kill_guest(lg, "bad guest page %p", lg->lguest_data); + || put_user(4U*1024*1024, &cpu->lg->lguest_data->reserve_mem) + || put_user(cpu->lg->pgdirs[0].gpgdir, &cpu->lg->lguest_data->pgdir)) + kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); /* In flush_user_mappings() we loop from 0 to * "pgd_index(lg->kernel_address)". This assumes it won't hit the * Switcher mappings, so check that now. */ - if (pgd_index(lg->kernel_address) >= SWITCHER_PGD_INDEX) - kill_guest(lg, "bad kernel address %#lx", lg->kernel_address); + if (pgd_index(cpu->lg->kernel_address) >= SWITCHER_PGD_INDEX) + kill_guest(cpu, "bad kernel address %#lx", + cpu->lg->kernel_address); } /* When a Guest dies, our cleanup is fairly simple. */ @@ -634,17 +637,18 @@ void free_guest_pagetable(struct lguest *lg) * Guest (and not the pages for other CPUs). We have the appropriate PTE pages * for each CPU already set up, we just need to hook them in now we know which * Guest is about to run on this CPU. */ -void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages) +void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages) { pte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages); pgd_t switcher_pgd; pte_t regs_pte; + unsigned long pfn; /* Make the last PGD entry for this Guest point to the Switcher's PTE * page for this CPU (with appropriate flags). */ - switcher_pgd = __pgd(__pa(switcher_pte_page) | _PAGE_KERNEL); + switcher_pgd = __pgd(__pa(switcher_pte_page) | __PAGE_KERNEL); - lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd; + cpu->lg->pgdirs[cpu->cpu_pgd].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd; /* We also change the Switcher PTE page. When we're running the Guest, * we want the Guest's "regs" page to appear where the first Switcher @@ -653,7 +657,8 @@ void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages) * CPU's "struct lguest_pages": if we make sure the Guest's register * page is already mapped there, we don't have to copy them out * again. */ - regs_pte = pfn_pte (__pa(lg->regs_page) >> PAGE_SHIFT, __pgprot(_PAGE_KERNEL)); + pfn = __pa(cpu->regs_page) >> PAGE_SHIFT; + regs_pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL)); switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTRS_PER_PTE] = regs_pte; } /*:*/ diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c index 9e189cbec7dd..ec6aa3f1c36b 100644 --- a/drivers/lguest/segments.c +++ b/drivers/lguest/segments.c @@ -58,7 +58,7 @@ static int ignored_gdt(unsigned int num) * Protection Fault in the Switcher when it restores a Guest segment register * which tries to use that entry. Then we kill the Guest for causing such a * mess: the message will be "unhandled trap 256". */ -static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) +static void fixup_gdt_table(struct lg_cpu *cpu, unsigned start, unsigned end) { unsigned int i; @@ -71,14 +71,14 @@ static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end) /* Segment descriptors contain a privilege level: the Guest is * sometimes careless and leaves this as 0, even though it's * running at privilege level 1. If so, we fix it here. */ - if ((lg->arch.gdt[i].b & 0x00006000) == 0) - lg->arch.gdt[i].b |= (GUEST_PL << 13); + if ((cpu->arch.gdt[i].b & 0x00006000) == 0) + cpu->arch.gdt[i].b |= (GUEST_PL << 13); /* Each descriptor has an "accessed" bit. If we don't set it * now, the CPU will try to set it when the Guest first loads * that entry into a segment register. But the GDT isn't * writable by the Guest, so bad things can happen. */ - lg->arch.gdt[i].b |= 0x00000100; + cpu->arch.gdt[i].b |= 0x00000100; } } @@ -109,31 +109,31 @@ void setup_default_gdt_entries(struct lguest_ro_state *state) /* This routine sets up the initial Guest GDT for booting. All entries start * as 0 (unusable). */ -void setup_guest_gdt(struct lguest *lg) +void setup_guest_gdt(struct lg_cpu *cpu) { /* Start with full 0-4G segments... */ - lg->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; - lg->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; + cpu->arch.gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT; + cpu->arch.gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT; /* ...except the Guest is allowed to use them, so set the privilege * level appropriately in the flags. */ - lg->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); - lg->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); + cpu->arch.gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13); + cpu->arch.gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13); } /*H:650 An optimization of copy_gdt(), for just the three "thead-local storage" * entries. */ -void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt) +void copy_gdt_tls(const struct lg_cpu *cpu, struct desc_struct *gdt) { unsigned int i; for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++) - gdt[i] = lg->arch.gdt[i]; + gdt[i] = cpu->arch.gdt[i]; } /*H:640 When the Guest is run on a different CPU, or the GDT entries have * changed, copy_gdt() is called to copy the Guest's GDT entries across to this * CPU's GDT. */ -void copy_gdt(const struct lguest *lg, struct desc_struct *gdt) +void copy_gdt(const struct lg_cpu *cpu, struct desc_struct *gdt) { unsigned int i; @@ -141,38 +141,38 @@ void copy_gdt(const struct lguest *lg, struct desc_struct *gdt) * replaced. See ignored_gdt() above. */ for (i = 0; i < GDT_ENTRIES; i++) if (!ignored_gdt(i)) - gdt[i] = lg->arch.gdt[i]; + gdt[i] = cpu->arch.gdt[i]; } /*H:620 This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). * We copy it from the Guest and tweak the entries. */ -void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num) +void load_guest_gdt(struct lg_cpu *cpu, unsigned long table, u32 num) { /* We assume the Guest has the same number of GDT entries as the * Host, otherwise we'd have to dynamically allocate the Guest GDT. */ - if (num > ARRAY_SIZE(lg->arch.gdt)) - kill_guest(lg, "too many gdt entries %i", num); + if (num > ARRAY_SIZE(cpu->arch.gdt)) + kill_guest(cpu, "too many gdt entries %i", num); /* We read the whole thing in, then fix it up. */ - __lgread(lg, lg->arch.gdt, table, num * sizeof(lg->arch.gdt[0])); - fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->arch.gdt)); + __lgread(cpu, cpu->arch.gdt, table, num * sizeof(cpu->arch.gdt[0])); + fixup_gdt_table(cpu, 0, ARRAY_SIZE(cpu->arch.gdt)); /* Mark that the GDT changed so the core knows it has to copy it again, * even if the Guest is run on the same CPU. */ - lg->changed |= CHANGED_GDT; + cpu->changed |= CHANGED_GDT; } /* This is the fast-track version for just changing the three TLS entries. * Remember that this happens on every context switch, so it's worth * optimizing. But wouldn't it be neater to have a single hypercall to cover * both cases? */ -void guest_load_tls(struct lguest *lg, unsigned long gtls) +void guest_load_tls(struct lg_cpu *cpu, unsigned long gtls) { - struct desc_struct *tls = &lg->arch.gdt[GDT_ENTRY_TLS_MIN]; + struct desc_struct *tls = &cpu->arch.gdt[GDT_ENTRY_TLS_MIN]; - __lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); - fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); + __lgread(cpu, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES); + fixup_gdt_table(cpu, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1); /* Note that just the TLS entries have changed. */ - lg->changed |= CHANGED_GDT_TLS; + cpu->changed |= CHANGED_GDT_TLS; } /*:*/ diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 482aec2a9631..61f2f8eb8cad 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -60,7 +60,7 @@ static struct lguest_pages *lguest_pages(unsigned int cpu) (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]); } -static DEFINE_PER_CPU(struct lguest *, last_guest); +static DEFINE_PER_CPU(struct lg_cpu *, last_cpu); /*S:010 * We approach the Switcher. @@ -73,16 +73,16 @@ static DEFINE_PER_CPU(struct lguest *, last_guest); * since it last ran. We saw this set in interrupts_and_traps.c and * segments.c. */ -static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages) +static void copy_in_guest_info(struct lg_cpu *cpu, struct lguest_pages *pages) { /* Copying all this data can be quite expensive. We usually run the * same Guest we ran last time (and that Guest hasn't run anywhere else * meanwhile). If that's not the case, we pretend everything in the * Guest has changed. */ - if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) { - __get_cpu_var(last_guest) = lg; - lg->last_pages = pages; - lg->changed = CHANGED_ALL; + if (__get_cpu_var(last_cpu) != cpu || cpu->last_pages != pages) { + __get_cpu_var(last_cpu) = cpu; + cpu->last_pages = pages; + cpu->changed = CHANGED_ALL; } /* These copies are pretty cheap, so we do them unconditionally: */ @@ -90,42 +90,42 @@ static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages) pages->state.host_cr3 = __pa(current->mm->pgd); /* Set up the Guest's page tables to see this CPU's pages (and no * other CPU's pages). */ - map_switcher_in_guest(lg, pages); + map_switcher_in_guest(cpu, pages); /* Set up the two "TSS" members which tell the CPU what stack to use * for traps which do directly into the Guest (ie. traps at privilege * level 1). */ - pages->state.guest_tss.esp1 = lg->esp1; - pages->state.guest_tss.ss1 = lg->ss1; + pages->state.guest_tss.esp1 = cpu->esp1; + pages->state.guest_tss.ss1 = cpu->ss1; /* Copy direct-to-Guest trap entries. */ - if (lg->changed & CHANGED_IDT) - copy_traps(lg, pages->state.guest_idt, default_idt_entries); + if (cpu->changed & CHANGED_IDT) + copy_traps(cpu, pages->state.guest_idt, default_idt_entries); /* Copy all GDT entries which the Guest can change. */ - if (lg->changed & CHANGED_GDT) - copy_gdt(lg, pages->state.guest_gdt); + if (cpu->changed & CHANGED_GDT) + copy_gdt(cpu, pages->state.guest_gdt); /* If only the TLS entries have changed, copy them. */ - else if (lg->changed & CHANGED_GDT_TLS) - copy_gdt_tls(lg, pages->state.guest_gdt); + else if (cpu->changed & CHANGED_GDT_TLS) + copy_gdt_tls(cpu, pages->state.guest_gdt); /* Mark the Guest as unchanged for next time. */ - lg->changed = 0; + cpu->changed = 0; } /* Finally: the code to actually call into the Switcher to run the Guest. */ -static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) +static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages) { /* This is a dummy value we need for GCC's sake. */ unsigned int clobber; /* Copy the guest-specific information into this CPU's "struct * lguest_pages". */ - copy_in_guest_info(lg, pages); + copy_in_guest_info(cpu, pages); /* Set the trap number to 256 (impossible value). If we fault while * switching to the Guest (bad segment registers or bug), this will * cause us to abort the Guest. */ - lg->regs->trapnum = 256; + cpu->regs->trapnum = 256; /* Now: we push the "eflags" register on the stack, then do an "lcall". * This is how we change from using the kernel code segment to using @@ -143,7 +143,7 @@ static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) * 0-th argument above, ie "a"). %ebx contains the * physical address of the Guest's top-level page * directory. */ - : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir)) + : "0"(pages), "1"(__pa(cpu->lg->pgdirs[cpu->cpu_pgd].pgdir)) /* We tell gcc that all these registers could change, * which means we don't have to save and restore them in * the Switcher. */ @@ -161,12 +161,12 @@ static void run_guest_once(struct lguest *lg, struct lguest_pages *pages) /*H:040 This is the i386-specific code to setup and run the Guest. Interrupts * are disabled: we own the CPU. */ -void lguest_arch_run_guest(struct lguest *lg) +void lguest_arch_run_guest(struct lg_cpu *cpu) { /* Remember the awfully-named TS bit? If the Guest has asked to set it * we set it now, so we can trap and pass that trap to the Guest if it * uses the FPU. */ - if (lg->ts) + if (cpu->ts) lguest_set_ts(); /* SYSENTER is an optimized way of doing system calls. We can't allow @@ -180,7 +180,7 @@ void lguest_arch_run_guest(struct lguest *lg) /* Now we actually run the Guest. It will return when something * interesting happens, and we can examine its registers to see what it * was doing. */ - run_guest_once(lg, lguest_pages(raw_smp_processor_id())); + run_guest_once(cpu, lguest_pages(raw_smp_processor_id())); /* Note that the "regs" pointer contains two extra entries which are * not really registers: a trap number which says what interrupt or @@ -191,11 +191,11 @@ void lguest_arch_run_guest(struct lguest *lg) * bad virtual address. We have to grab this now, because once we * re-enable interrupts an interrupt could fault and thus overwrite * cr2, or we could even move off to a different CPU. */ - if (lg->regs->trapnum == 14) - lg->arch.last_pagefault = read_cr2(); + if (cpu->regs->trapnum == 14) + cpu->arch.last_pagefault = read_cr2(); /* Similarly, if we took a trap because the Guest used the FPU, * we have to restore the FPU it expects to see. */ - else if (lg->regs->trapnum == 7) + else if (cpu->regs->trapnum == 7) math_state_restore(); /* Restore SYSENTER if it's supposed to be on. */ @@ -214,22 +214,22 @@ void lguest_arch_run_guest(struct lguest *lg) * When the Guest uses one of these instructions, we get a trap (General * Protection Fault) and come here. We see if it's one of those troublesome * instructions and skip over it. We return true if we did. */ -static int emulate_insn(struct lguest *lg) +static int emulate_insn(struct lg_cpu *cpu) { u8 insn; unsigned int insnlen = 0, in = 0, shift = 0; /* The eip contains the *virtual* address of the Guest's instruction: * guest_pa just subtracts the Guest's page_offset. */ - unsigned long physaddr = guest_pa(lg, lg->regs->eip); + unsigned long physaddr = guest_pa(cpu, cpu->regs->eip); /* This must be the Guest kernel trying to do something, not userspace! * The bottom two bits of the CS segment register are the privilege * level. */ - if ((lg->regs->cs & 3) != GUEST_PL) + if ((cpu->regs->cs & 3) != GUEST_PL) return 0; /* Decoding x86 instructions is icky. */ - insn = lgread(lg, physaddr, u8); + insn = lgread(cpu, physaddr, u8); /* 0x66 is an "operand prefix". It means it's using the upper 16 bits of the eax register. */ @@ -237,7 +237,7 @@ static int emulate_insn(struct lguest *lg) shift = 16; /* The instruction is 1 byte so far, read the next byte. */ insnlen = 1; - insn = lgread(lg, physaddr + insnlen, u8); + insn = lgread(cpu, physaddr + insnlen, u8); } /* We can ignore the lower bit for the moment and decode the 4 opcodes @@ -268,26 +268,26 @@ static int emulate_insn(struct lguest *lg) if (in) { /* Lower bit tells is whether it's a 16 or 32 bit access */ if (insn & 0x1) - lg->regs->eax = 0xFFFFFFFF; + cpu->regs->eax = 0xFFFFFFFF; else - lg->regs->eax |= (0xFFFF << shift); + cpu->regs->eax |= (0xFFFF << shift); } /* Finally, we've "done" the instruction, so move past it. */ - lg->regs->eip += insnlen; + cpu->regs->eip += insnlen; /* Success! */ return 1; } /*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */ -void lguest_arch_handle_trap(struct lguest *lg) +void lguest_arch_handle_trap(struct lg_cpu *cpu) { - switch (lg->regs->trapnum) { + switch (cpu->regs->trapnum) { case 13: /* We've intercepted a General Protection Fault. */ /* Check if this was one of those annoying IN or OUT * instructions which we need to emulate. If so, we just go * back into the Guest after we've done it. */ - if (lg->regs->errcode == 0) { - if (emulate_insn(lg)) + if (cpu->regs->errcode == 0) { + if (emulate_insn(cpu)) return; } break; @@ -301,7 +301,8 @@ void lguest_arch_handle_trap(struct lguest *lg) * * The errcode tells whether this was a read or a write, and * whether kernel or userspace code. */ - if (demand_page(lg, lg->arch.last_pagefault, lg->regs->errcode)) + if (demand_page(cpu, cpu->arch.last_pagefault, + cpu->regs->errcode)) return; /* OK, it's really not there (or not OK): the Guest needs to @@ -311,15 +312,16 @@ void lguest_arch_handle_trap(struct lguest *lg) * Note that if the Guest were really messed up, this could * happen before it's done the LHCALL_LGUEST_INIT hypercall, so * lg->lguest_data could be NULL */ - if (lg->lguest_data && - put_user(lg->arch.last_pagefault, &lg->lguest_data->cr2)) - kill_guest(lg, "Writing cr2"); + if (cpu->lg->lguest_data && + put_user(cpu->arch.last_pagefault, + &cpu->lg->lguest_data->cr2)) + kill_guest(cpu, "Writing cr2"); break; case 7: /* We've intercepted a Device Not Available fault. */ /* If the Guest doesn't want to know, we already restored the * Floating Point Unit, so we just continue without telling * it. */ - if (!lg->ts) + if (!cpu->ts) return; break; case 32 ... 255: @@ -332,19 +334,19 @@ void lguest_arch_handle_trap(struct lguest *lg) case LGUEST_TRAP_ENTRY: /* Our 'struct hcall_args' maps directly over our regs: we set * up the pointer now to indicate a hypercall is pending. */ - lg->hcall = (struct hcall_args *)lg->regs; + cpu->hcall = (struct hcall_args *)cpu->regs; return; } /* We didn't handle the trap, so it needs to go to the Guest. */ - if (!deliver_trap(lg, lg->regs->trapnum)) + if (!deliver_trap(cpu, cpu->regs->trapnum)) /* If the Guest doesn't have a handler (either it hasn't * registered any yet, or it's one of the faults we don't let * it handle), it dies with a cryptic error message. */ - kill_guest(lg, "unhandled trap %li at %#lx (%#lx)", - lg->regs->trapnum, lg->regs->eip, - lg->regs->trapnum == 14 ? lg->arch.last_pagefault - : lg->regs->errcode); + kill_guest(cpu, "unhandled trap %li at %#lx (%#lx)", + cpu->regs->trapnum, cpu->regs->eip, + cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault + : cpu->regs->errcode); } /* Now we can look at each of the routines this calls, in increasing order of @@ -416,7 +418,7 @@ void __init lguest_arch_host_init(void) /* We know where we want the stack to be when the Guest enters * the switcher: in pages->regs. The stack grows upwards, so * we start it at the end of that structure. */ - state->guest_tss.esp0 = (long)(&pages->regs + 1); + state->guest_tss.sp0 = (long)(&pages->regs + 1); /* And this is the GDT entry to use for the stack: we keep a * couple of special LGUEST entries. */ state->guest_tss.ss0 = LGUEST_DS; @@ -459,7 +461,7 @@ void __init lguest_arch_host_init(void) /* We don't need the complexity of CPUs coming and going while we're * doing this. */ - lock_cpu_hotplug(); + get_online_cpus(); if (cpu_has_pge) { /* We have a broader idea of "global". */ /* Remember that this was originally set (for cleanup). */ cpu_had_pge = 1; @@ -469,35 +471,35 @@ void __init lguest_arch_host_init(void) /* Turn off the feature in the global feature set. */ clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); } - unlock_cpu_hotplug(); + put_online_cpus(); }; /*:*/ void __exit lguest_arch_host_fini(void) { /* If we had PGE before we started, turn it back on now. */ - lock_cpu_hotplug(); + get_online_cpus(); if (cpu_had_pge) { set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability); /* adjust_pge's argument "1" means set PGE. */ on_each_cpu(adjust_pge, (void *)1, 0, 1); } - unlock_cpu_hotplug(); + put_online_cpus(); } /*H:122 The i386-specific hypercalls simply farm out to the right functions. */ -int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args) +int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args) { switch (args->arg0) { case LHCALL_LOAD_GDT: - load_guest_gdt(lg, args->arg1, args->arg2); + load_guest_gdt(cpu, args->arg1, args->arg2); break; case LHCALL_LOAD_IDT_ENTRY: - load_guest_idt_entry(lg, args->arg1, args->arg2, args->arg3); + load_guest_idt_entry(cpu, args->arg1, args->arg2, args->arg3); break; case LHCALL_LOAD_TLS: - guest_load_tls(lg, args->arg1); + guest_load_tls(cpu, args->arg1); break; default: /* Bad Guest. Bad! */ @@ -507,13 +509,14 @@ int lguest_arch_do_hcall(struct lguest *lg, struct hcall_args *args) } /*H:126 i386-specific hypercall initialization: */ -int lguest_arch_init_hypercalls(struct lguest *lg) +int lguest_arch_init_hypercalls(struct lg_cpu *cpu) { u32 tsc_speed; /* The pointer to the Guest's "struct lguest_data" is the only * argument. We check that address now. */ - if (!lguest_address_ok(lg, lg->hcall->arg1, sizeof(*lg->lguest_data))) + if (!lguest_address_ok(cpu->lg, cpu->hcall->arg1, + sizeof(*cpu->lg->lguest_data))) return -EFAULT; /* Having checked it, we simply set lg->lguest_data to point straight @@ -521,7 +524,7 @@ int lguest_arch_init_hypercalls(struct lguest *lg) * copy_to_user/from_user from now on, instead of lgread/write. I put * this in to show that I'm not immune to writing stupid * optimizations. */ - lg->lguest_data = lg->mem_base + lg->hcall->arg1; + cpu->lg->lguest_data = cpu->lg->mem_base + cpu->hcall->arg1; /* We insist that the Time Stamp Counter exist and doesn't change with * cpu frequency. Some devious chip manufacturers decided that TSC @@ -534,12 +537,12 @@ int lguest_arch_init_hypercalls(struct lguest *lg) tsc_speed = tsc_khz; else tsc_speed = 0; - if (put_user(tsc_speed, &lg->lguest_data->tsc_khz)) + if (put_user(tsc_speed, &cpu->lg->lguest_data->tsc_khz)) return -EFAULT; /* The interrupt code might not like the system call vector. */ - if (!check_syscall_vector(lg)) - kill_guest(lg, "bad syscall vector"); + if (!check_syscall_vector(cpu->lg)) + kill_guest(cpu, "bad syscall vector"); return 0; } @@ -548,9 +551,9 @@ int lguest_arch_init_hypercalls(struct lguest *lg) * * Most of the Guest's registers are left alone: we used get_zeroed_page() to * allocate the structure, so they will be 0. */ -void lguest_arch_setup_regs(struct lguest *lg, unsigned long start) +void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start) { - struct lguest_regs *regs = lg->regs; + struct lguest_regs *regs = cpu->regs; /* There are four "segment" registers which the Guest needs to boot: * The "code segment" register (cs) refers to the kernel code segment @@ -577,5 +580,5 @@ void lguest_arch_setup_regs(struct lguest *lg, unsigned long start) /* There are a couple of GDT entries the Guest expects when first * booting. */ - setup_guest_gdt(lg); + setup_guest_gdt(cpu); } diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index 5ae28f076d25..7ce0ea64465c 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -854,7 +854,7 @@ adbdev_init(void) adb_dev_class = class_create(THIS_MODULE, "adb"); if (IS_ERR(adb_dev_class)) return; - class_device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), NULL, "adb"); + device_create(adb_dev_class, NULL, MKDEV(ADB_MAJOR, 0), "adb"); platform_device_register(&adb_pfdev); platform_driver_probe(&adb_pfdrv, adb_dummy_probe); diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 192bef5c20b3..18dde2a27209 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -563,7 +563,8 @@ static void media_bay_step(int i) ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); hw.irq = bay->cd_irq; hw.chipset = ide_pmac; - bay->cd_index = ide_register_hw(&hw, NULL, 0, NULL); + bay->cd_index = + ide_register_hw(&hw, NULL, NULL); pmu_resume(); } if (bay->cd_index == -1) { diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 63ef1f6faaed..d11821af3b8d 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -48,12 +48,10 @@ #define LOG_TEMP 0 /* continously log temperature */ -#define I2C_DRIVERID_G4FAN 0x9001 /* fixme */ - static int do_probe( struct i2c_adapter *adapter, int addr, int kind); /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, +static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; @@ -361,7 +359,6 @@ static struct i2c_driver g4fan_driver = { .driver = { .name = "therm_windtunnel", }, - .id = I2C_DRIVERID_G4FAN, .attach_adapter = do_attach, .detach_client = do_detach, }; diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 82ec12e0edd2..ebec663d5d37 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2482,7 +2482,7 @@ static int pmu_sys_resume(struct sys_device *sysdev) #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */ static struct sysdev_class pmu_sysclass = { - set_kset_name("pmu"), + .name = "pmu", }; static struct sys_device device_pmu = { diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 88c0fd657825..f2d24eb3208c 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1109,7 +1109,7 @@ static void event_callback(void *context) list_splice_init(&md->uevent_list, &uevents); spin_unlock_irqrestore(&md->uevent_lock, flags); - dm_send_uevents(&uevents, &md->disk->kobj); + dm_send_uevents(&uevents, &md->disk->dev.kobj); atomic_inc(&md->event_nr); wake_up(&md->eventq); @@ -1530,7 +1530,7 @@ out: *---------------------------------------------------------------*/ void dm_kobject_uevent(struct mapped_device *md) { - kobject_uevent(&md->disk->kobj, KOBJ_CHANGE); + kobject_uevent(&md->disk->dev.kobj, KOBJ_CHANGE); } uint32_t dm_next_uevent_seq(struct mapped_device *md) diff --git a/drivers/md/md.c b/drivers/md/md.c index cef9ebd5a046..c28a120b4161 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -231,7 +231,7 @@ static void mddev_put(mddev_t *mddev) list_del(&mddev->all_mddevs); spin_unlock(&all_mddevs_lock); blk_cleanup_queue(mddev->queue); - kobject_unregister(&mddev->kobj); + kobject_put(&mddev->kobj); } else spin_unlock(&all_mddevs_lock); } @@ -1383,22 +1383,19 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) return -EBUSY; } bdevname(rdev->bdev,b); - if (kobject_set_name(&rdev->kobj, "dev-%s", b) < 0) - return -ENOMEM; - while ( (s=strchr(rdev->kobj.k_name, '/')) != NULL) + while ( (s=strchr(b, '/')) != NULL) *s = '!'; - + rdev->mddev = mddev; printk(KERN_INFO "md: bind<%s>\n", b); - rdev->kobj.parent = &mddev->kobj; - if ((err = kobject_add(&rdev->kobj))) + if ((err = kobject_add(&rdev->kobj, &mddev->kobj, "dev-%s", b))) goto fail; if (rdev->bdev->bd_part) - ko = &rdev->bdev->bd_part->kobj; + ko = &rdev->bdev->bd_part->dev.kobj; else - ko = &rdev->bdev->bd_disk->kobj; + ko = &rdev->bdev->bd_disk->dev.kobj; if ((err = sysfs_create_link(&rdev->kobj, ko, "block"))) { kobject_del(&rdev->kobj); goto fail; @@ -2036,9 +2033,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi if (err) goto abort_free; - rdev->kobj.parent = NULL; - rdev->kobj.ktype = &rdev_ktype; - kobject_init(&rdev->kobj); + kobject_init(&rdev->kobj, &rdev_ktype); rdev->desc_nr = -1; rdev->saved_raid_disk = -1; @@ -3054,6 +3049,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) int partitioned = (MAJOR(dev) != MD_MAJOR); int shift = partitioned ? MdpMinorShift : 0; int unit = MINOR(dev) >> shift; + int error; if (!mddev) return NULL; @@ -3082,12 +3078,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) add_disk(disk); mddev->gendisk = disk; mutex_unlock(&disks_mutex); - mddev->kobj.parent = &disk->kobj; - kobject_set_name(&mddev->kobj, "%s", "md"); - mddev->kobj.ktype = &md_ktype; - if (kobject_register(&mddev->kobj)) + error = kobject_init_and_add(&mddev->kobj, &md_ktype, &disk->dev.kobj, + "%s", "md"); + if (error) printk(KERN_WARNING "md: cannot register %s/md - name in use\n", disk->disk_name); + else + kobject_uevent(&mddev->kobj, KOBJ_ADD); return NULL; } @@ -3359,7 +3356,7 @@ static int do_md_run(mddev_t * mddev) mddev->changed = 1; md_new_event(mddev); - kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE); + kobject_uevent(&mddev->gendisk->dev.kobj, KOBJ_CHANGE); return 0; } diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 1604f0490404..8f4a45346de7 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -69,11 +69,13 @@ source "drivers/media/common/Kconfig" config VIDEO_TUNER tristate depends on I2C + select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE + select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE menuconfig VIDEO_TUNER_CUSTOMIZE bool "Customize analog tuner modules to build" @@ -89,6 +91,13 @@ menuconfig VIDEO_TUNER_CUSTOMIZE if VIDEO_TUNER_CUSTOMIZE +config TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for the xc2028/xc3028 tuners. + config TUNER_MT20XX tristate "Microtune 2032 / 2050 tuners" depends on I2C @@ -97,8 +106,10 @@ config TUNER_MT20XX Say Y here to include support for the MT2032 / MT2050 tuner. config TUNER_TDA8290 - tristate "TDA 8290+8275(a) tuner combo" + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" depends on I2C + select DVB_TDA827X + select DVB_TDA18271 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for Philips TDA8290+8275(a) tuner. @@ -120,10 +131,19 @@ config TUNER_TEA5767 config TUNER_SIMPLE tristate "Simple tuner support" depends on I2C + select TUNER_TDA9887 default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for various simple tuners. +config TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on I2C + default m if VIDEO_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + endif # VIDEO_TUNER_CUSTOMIZE config VIDEOBUF_GEN diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index c5092ef1082f..06ca75911b7f 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -1,6 +1,6 @@ config VIDEO_SAA7146 tristate - depends on I2C + depends on I2C && PCI config VIDEO_SAA7146_VV tristate diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c index e7c3ab951a44..bb2a027b9483 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/common/ir-functions.c @@ -258,7 +258,7 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high) * saa7134 */ /* decode raw bit pattern to RC5 code */ -u32 ir_rc5_decode(unsigned int code) +static u32 ir_rc5_decode(unsigned int code) { unsigned int org_code = code; unsigned int pair; @@ -371,7 +371,6 @@ EXPORT_SYMBOL_GPL(ir_dump_samples); EXPORT_SYMBOL_GPL(ir_decode_biphase); EXPORT_SYMBOL_GPL(ir_decode_pulsedistance); -EXPORT_SYMBOL_GPL(ir_rc5_decode); EXPORT_SYMBOL_GPL(ir_rc5_timer_end); EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup); diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 185e8a860c1a..a4a937c90534 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1331,7 +1331,12 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = { [ 0x35 ] = KEY_FASTFORWARD, [ 0x36 ] = KEY_TV, [ 0x37 ] = KEY_RADIO, /* FM */ - [ 0x38 ] = KEY_DVD + [ 0x38 ] = KEY_DVD, + + [ 0x3e ] = KEY_F21, /* MCE +VOL, on Y04G0033 */ + [ 0x3a ] = KEY_F22, /* MCE -VOL, on Y04G0033 */ + [ 0x3b ] = KEY_F23, /* MCE +CH, on Y04G0033 */ + [ 0x3f ] = KEY_F24 /* MCE -CH, on Y04G0033 */ }; EXPORT_SYMBOL_GPL(ir_codes_winfast); @@ -1843,3 +1848,142 @@ IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce); + +/* Pinnacle PCTV HD 800i mini remote */ +IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE] = { + + [0x0f] = KEY_1, + [0x15] = KEY_2, + [0x10] = KEY_3, + [0x18] = KEY_4, + [0x1b] = KEY_5, + [0x1e] = KEY_6, + [0x11] = KEY_7, + [0x21] = KEY_8, + [0x12] = KEY_9, + [0x27] = KEY_0, + + [0x24] = KEY_ZOOM, + [0x2a] = KEY_SUBTITLE, + + [0x00] = KEY_MUTE, + [0x01] = KEY_ENTER, /* Pinnacle Logo */ + [0x39] = KEY_POWER, + + [0x03] = KEY_VOLUMEUP, + [0x09] = KEY_VOLUMEDOWN, + [0x06] = KEY_CHANNELUP, + [0x0c] = KEY_CHANNELDOWN, + + [0x2d] = KEY_REWIND, + [0x30] = KEY_PLAYPAUSE, + [0x33] = KEY_FASTFORWARD, + [0x3c] = KEY_STOP, + [0x36] = KEY_RECORD, + [0x3f] = KEY_EPG, /* Labeled "?" */ +}; +EXPORT_SYMBOL_GPL(ir_codes_pinnacle_pctv_hd); + +/* + * Igor Kuznetsov <igk72@ya.ru> + * Andrey J. Melnikov <temnota@kmv.ru> + * + * Keytable is used by BeholdTV 60x series, M6 series at + * least, and probably other cards too. + * The "ascii-art picture" below (in comments, first row + * is the keycode in hex, and subsequent row(s) shows + * the button labels (several variants when appropriate) + * helps to descide which keycodes to assign to the buttons. + */ +IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = { + + /* 0x1c 0x12 * + * TV/FM POWER * + * */ + [ 0x1c ] = KEY_TUNER, /*XXX KEY_TV KEY_RADIO */ + [ 0x12 ] = KEY_POWER, + + /* 0x01 0x02 0x03 * + * 1 2 3 * + * * + * 0x04 0x05 0x06 * + * 4 5 6 * + * * + * 0x07 0x08 0x09 * + * 7 8 9 * + * */ + [ 0x01 ] = KEY_1, + [ 0x02 ] = KEY_2, + [ 0x03 ] = KEY_3, + [ 0x04 ] = KEY_4, + [ 0x05 ] = KEY_5, + [ 0x06 ] = KEY_6, + [ 0x07 ] = KEY_7, + [ 0x08 ] = KEY_8, + [ 0x09 ] = KEY_9, + + /* 0x0a 0x00 0x17 * + * RECALL 0 MODE * + * */ + [ 0x0a ] = KEY_AGAIN, + [ 0x00 ] = KEY_0, + [ 0x17 ] = KEY_MODE, + + /* 0x14 0x10 * + * ASPECT FULLSCREEN * + * */ + [ 0x14 ] = KEY_SCREEN, + [ 0x10 ] = KEY_ZOOM, + + /* 0x0b * + * Up * + * * + * 0x18 0x16 0x0c * + * Left Ok Right * + * * + * 0x015 * + * Down * + * */ + [ 0x0b ] = KEY_CHANNELUP, /*XXX KEY_UP */ + [ 0x18 ] = KEY_VOLUMEDOWN, /*XXX KEY_LEFT */ + [ 0x16 ] = KEY_OK, /*XXX KEY_ENTER */ + [ 0x0c ] = KEY_VOLUMEUP, /*XXX KEY_RIGHT */ + [ 0x15 ] = KEY_CHANNELDOWN, /*XXX KEY_DOWN */ + + /* 0x11 0x0d * + * MUTE INFO * + * */ + [ 0x11 ] = KEY_MUTE, + [ 0x0d ] = KEY_INFO, + + /* 0x0f 0x1b 0x1a * + * RECORD PLAY/PAUSE STOP * + * * + * 0x0e 0x1f 0x1e * + *TELETEXT AUDIO SOURCE * + * RED YELLOW * + * */ + [ 0x0f ] = KEY_RECORD, + [ 0x1b ] = KEY_PLAYPAUSE, + [ 0x1a ] = KEY_STOP, + [ 0x0e ] = KEY_TEXT, + [ 0x1f ] = KEY_RED, /*XXX KEY_AUDIO */ + [ 0x1e ] = KEY_YELLOW, /*XXX KEY_SOURCE */ + + /* 0x1d 0x13 0x19 * + * SLEEP PREVIEW DVB * + * GREEN BLUE * + * */ + [ 0x1d ] = KEY_SLEEP, + [ 0x13 ] = KEY_GREEN, + [ 0x19 ] = KEY_BLUE, /*XXX KEY_SAT */ + + /* 0x58 0x5c * + * FREEZE SNAPSHOT * + * */ + [ 0x58 ] = KEY_SLOW, + [ 0x5c ] = KEY_SAVE, + +}; + +EXPORT_SYMBOL_GPL(ir_codes_behold); diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 67d1b1b1b254..f0703d8bc3e8 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -61,7 +61,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q, videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } @@ -83,7 +83,7 @@ int saa7146_buffer_queue(struct saa7146_dev *dev, buf->activate(dev,buf,NULL); } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; DEB_D(("adding buffer %p to queue. (active buffer present)\n", buf)); } return 0; @@ -174,7 +174,7 @@ void saa7146_buffer_timeout(unsigned long data) spin_lock_irqsave(&dev->slock,flags); if (q->curr) { DEB_D(("timeout on %p\n", q->curr)); - saa7146_buffer_finish(dev,q,STATE_ERROR); + saa7146_buffer_finish(dev,q,VIDEOBUF_ERROR); } /* we don't restart the transfer here like other drivers do. when @@ -366,7 +366,7 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait) } poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || buf->state == STATE_ERROR) { + if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) { DEB_D(("poll succeeded!\n")); return POLLIN|POLLRDNORM; } @@ -538,6 +538,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); if (video_register_device(vfd, type, -1) < 0) { ERR(("cannot register v4l2 device. skipping.\n")); + video_device_release(vfd); return -1; } diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index 6103484e4442..c32dda973e92 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -205,7 +205,7 @@ static int buffer_activate(struct saa7146_dev *dev, struct saa7146_buf *next) { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; DEB_VBI(("dev:%p, buf:%p, next:%p\n",dev,buf,next)); saa7146_set_vbi_capture(dev,buf,next); @@ -238,7 +238,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (buf->vb.size != size) saa7146_dma_free(dev,q,buf); - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -257,7 +257,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,e if (0 != err) return err; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -335,7 +335,7 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) saa7146_write(dev, MC1, MASK_20); if (vv->vbi_q.curr) { - saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } videobuf_queue_cancel(&fh->vbi_q); @@ -458,7 +458,7 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status) /* this must be += 2, one count for each field */ vv->vbi_fieldcount+=2; vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount; - saa7146_buffer_finish(dev,&vv->vbi_q,STATE_DONE); + saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE); } else { DEB_VBI(("dev:%p\n",dev)); } diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index ae36d101006b..c31ab480d8e1 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1235,7 +1235,7 @@ static int buffer_activate (struct saa7146_dev *dev, { struct saa7146_vv *vv = dev->vv_data; - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; saa7146_set_capture(dev,buf,next); mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); @@ -1281,7 +1281,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7146_dma_free(dev,q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct saa7146_format *sfmt; buf->vb.bytesperline = fh->video_fmt.bytesperline; @@ -1314,7 +1314,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -1453,7 +1453,7 @@ static void video_irq_done(struct saa7146_dev *dev, unsigned long st) /* only finish the buffer if we have one... */ if( NULL != q->curr ) { - saa7146_buffer_finish(dev,q,STATE_DONE); + saa7146_buffer_finish(dev,q,VIDEOBUF_DONE); } saa7146_buffer_next(dev,q,0); diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 29ec4183118e..2ddafd071c97 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -212,7 +212,6 @@ void flexcop_reset_block_300(struct flexcop_device *fc) fc->write_ibi_reg(fc,ctrl_208,v208_save); } -EXPORT_SYMBOL(flexcop_reset_block_300); struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) { diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 85e36a1d6d78..c7bbb40223f5 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -378,23 +378,37 @@ bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet * EXPORT_SYMBOL(bt878_device_control); +#define BROOKTREE_878_DEVICE(vend, dev, name) \ + { \ + .vendor = PCI_VENDOR_ID_BROOKTREE, \ + .device = PCI_DEVICE_ID_BROOKTREE_878, \ + .subvendor = (vend), .subdevice = (dev), \ + .driver_data = (unsigned long) name \ + } -static struct cards card_list[] __devinitdata = { - - { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, - { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, - { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, - { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, - { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, - { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, - { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, - { 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" }, - { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, - { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, - { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" } +static struct pci_device_id bt878_pci_tbl[] __devinitdata = { + BROOKTREE_878_DEVICE(0x0071, 0x0101, "Nebula Electronics DigiTV"), + BROOKTREE_878_DEVICE(0x1461, 0x0761, "AverMedia AverTV DVB-T 761"), + BROOKTREE_878_DEVICE(0x11bd, 0x001c, "Pinnacle PCTV Sat"), + BROOKTREE_878_DEVICE(0x11bd, 0x0026, "Pinnacle PCTV SAT CI"), + BROOKTREE_878_DEVICE(0x1822, 0x0001, "Twinhan VisionPlus DVB"), + BROOKTREE_878_DEVICE(0x270f, 0xfc00, + "ChainTech digitop DST-1000 DVB-S"), + BROOKTREE_878_DEVICE(0x1461, 0x0771, "AVermedia AverTV DVB-T 771"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb10, "DViCO FusionHDTV DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xdb11, "Ultraview DVB-T Lite"), + BROOKTREE_878_DEVICE(0x18ac, 0xd500, "DViCO FusionHDTV 5 Lite"), + BROOKTREE_878_DEVICE(0x7063, 0x2000, "pcHDTV HD-2000 TV"), + BROOKTREE_878_DEVICE(0x1822, 0x0026, "DNTV Live! Mini"), + { } }; +MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); + +static const char * __devinit card_name(const struct pci_device_id *id) +{ + return id->driver_data ? (const char *)id->driver_data : "Unknown"; +} /***********************/ /* PCI device handling */ @@ -403,15 +417,13 @@ static struct cards card_list[] __devinitdata = { static int __devinit bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { - int result = 0, has_dvb = 0, i; + int result = 0; unsigned char lat; struct bt878 *bt; #if defined(__powerpc__) unsigned int cmd; #endif unsigned int cardid; - unsigned short id; - struct cards *dvb_cards; printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); @@ -423,25 +435,11 @@ static int __devinit bt878_probe(struct pci_dev *dev, if (pci_enable_device(dev)) return -EIO; - pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &id); - cardid = id << 16; - pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &id); - cardid |= id; - - for (i = 0, dvb_cards = card_list; i < ARRAY_SIZE(card_list); i++, dvb_cards++) { - if (cardid == dvb_cards->pci_id) { - printk("%s: card id=[0x%x],[ %s ] has DVB functions.\n", - __func__, cardid, dvb_cards->name); - has_dvb = 1; - } - } + cardid = dev->subsystem_device << 16; + cardid |= dev->subsystem_vendor; - if (!has_dvb) { - printk("%s: card id=[0x%x], Unknown card.\nExiting..\n", __func__, cardid); - result = -EINVAL; - - goto fail0; - } + printk(KERN_INFO "%s: card id=[0x%x],[ %s ] has DVB functions.\n", + __func__, cardid, card_name(pci_id)); bt = &bt878[bt878_num]; bt->dev = dev; @@ -572,14 +570,6 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) return; } -static struct pci_device_id bt878_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); - static struct pci_driver bt878_pci_driver = { .name = "bt878", .id_table = bt878_pci_tbl, diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h index d593bc145628..375fd2892a11 100644 --- a/drivers/media/dvb/bt8xx/bt878.h +++ b/drivers/media/dvb/bt8xx/bt878.h @@ -101,12 +101,6 @@ #define BTTV_BOARD_DVICO_DVBT_LITE 0x80 #define BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE 0x87 -struct cards { - __u32 pci_id; - __u16 card_id; - char *name; -}; - extern int bt878_num; struct bt878 { diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index b7a17e69ca4d..307ff35bdf13 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -71,6 +71,7 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); } \ } while(0) +static int dst_command(struct dst_state *state, u8 *data, u8 len); static void dst_packsize(struct dst_state *state, int psize) { @@ -80,7 +81,8 @@ static void dst_packsize(struct dst_state *state, int psize) bt878_device_control(state->bt, DST_IG_TS, &bits); } -int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int delay) +static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, + u32 outhigh, int delay) { union dst_gpio_packet enb; union dst_gpio_packet bits; @@ -109,9 +111,8 @@ int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, u32 outhigh, int return 0; } -EXPORT_SYMBOL(dst_gpio_outb); -int dst_gpio_inb(struct dst_state *state, u8 *result) +static int dst_gpio_inb(struct dst_state *state, u8 *result) { union dst_gpio_packet rd_packet; int err; @@ -125,7 +126,6 @@ int dst_gpio_inb(struct dst_state *state, u8 *result) return 0; } -EXPORT_SYMBOL(dst_gpio_inb); int rdc_reset_state(struct dst_state *state) { @@ -145,7 +145,7 @@ int rdc_reset_state(struct dst_state *state) } EXPORT_SYMBOL(rdc_reset_state); -int rdc_8820_reset(struct dst_state *state) +static int rdc_8820_reset(struct dst_state *state) { dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { @@ -160,9 +160,8 @@ int rdc_8820_reset(struct dst_state *state) return 0; } -EXPORT_SYMBOL(rdc_8820_reset); -int dst_pio_enable(struct dst_state *state) +static int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); @@ -172,7 +171,6 @@ int dst_pio_enable(struct dst_state *state) return 0; } -EXPORT_SYMBOL(dst_pio_enable); int dst_pio_disable(struct dst_state *state) { @@ -611,7 +609,7 @@ static int dst_type_print(struct dst_state *state, u8 type) return 0; } -struct tuner_types tuner_list[] = { +static struct tuner_types tuner_list[] = { { .tuner_type = TUNER_TYPE_L64724, .tuner_name = "L 64724", @@ -1224,7 +1222,7 @@ static int dst_probe(struct dst_state *state) return 0; } -int dst_command(struct dst_state *state, u8 *data, u8 len) +static int dst_command(struct dst_state *state, u8 *data, u8 len) { u8 reply; @@ -1287,7 +1285,6 @@ error: return -EIO; } -EXPORT_SYMBOL(dst_command); static int dst_get_signal(struct dst_state *state) { diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 87623d203a89..d88cf2add82b 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -165,10 +165,8 @@ struct dst_config }; int rdc_reset_state(struct dst_state *state); -int rdc_8820_reset(struct dst_state *state); int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode); -int dst_pio_enable(struct dst_state *state); int dst_pio_disable(struct dst_state *state); int dst_error_recovery(struct dst_state* state); int dst_error_bailout(struct dst_state *state); @@ -179,9 +177,6 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len); u8 dst_check_sum(u8 * buf, u32 len); struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter); struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter); -int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay); - -int dst_command(struct dst_state* state, u8 * data, u8 len); #endif // DST_COMMON_H diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 445f02665577..925cfa6221ad 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1202,6 +1202,10 @@ void dvb_frontend_detach(struct dvb_frontend* fe) fe->ops.tuner_ops.release(fe); symbol_put_addr(fe->ops.tuner_ops.release); } + if (fe->ops.analog_ops.release) { + fe->ops.analog_ops.release(fe); + symbol_put_addr(fe->ops.analog_ops.release); + } ptr = (void*)fe->ops.release; if (ptr) { fe->ops.release(fe); @@ -1215,6 +1219,8 @@ void dvb_frontend_detach(struct dvb_frontend* fe) fe->ops.release_sec(fe); if (fe->ops.tuner_ops.release) fe->ops.tuner_ops.release(fe); + if (fe->ops.analog_ops.release) + fe->ops.analog_ops.release(fe); if (fe->ops.release) fe->ops.release(fe); } diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index a5262e852c82..aa4133f0bd19 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -84,6 +84,9 @@ struct dvb_tuner_ops { /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + /** This is to allow setting tuner-specific configs */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); + int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); @@ -98,6 +101,28 @@ struct dvb_tuner_ops { int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); }; +struct analog_demod_info { + char *name; +}; + +struct analog_demod_ops { + + struct analog_demod_info info; + + void (*set_params)(struct dvb_frontend *fe, + struct analog_parameters *params); + int (*has_signal)(struct dvb_frontend *fe); + int (*is_stereo)(struct dvb_frontend *fe); + int (*get_afc)(struct dvb_frontend *fe); + void (*tuner_status)(struct dvb_frontend *fe); + void (*standby)(struct dvb_frontend *fe); + void (*release)(struct dvb_frontend *fe); + int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); + + /** This is to allow setting tuner-specific configuration */ + int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); +}; + struct dvb_frontend_ops { struct dvb_frontend_info info; @@ -143,6 +168,7 @@ struct dvb_frontend_ops { int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); struct dvb_tuner_ops tuner_ops; + struct analog_demod_ops analog_ops; }; #define MAX_EVENT 8 @@ -159,18 +185,19 @@ struct dvb_fe_events { struct dvb_frontend { struct dvb_frontend_ops ops; struct dvb_adapter *dvb; - void* demodulator_priv; - void* tuner_priv; - void* frontend_priv; - void* sec_priv; + void *demodulator_priv; + void *tuner_priv; + void *frontend_priv; + void *sec_priv; + void *analog_demod_priv; }; -extern int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe); +extern int dvb_register_frontend(struct dvb_adapter *dvb, + struct dvb_frontend *fe); -extern int dvb_unregister_frontend(struct dvb_frontend* fe); +extern int dvb_unregister_frontend(struct dvb_frontend *fe); -extern void dvb_frontend_detach(struct dvb_frontend* fe); +extern void dvb_frontend_detach(struct dvb_frontend *fe); extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c index 9878183ba3f0..ac9d93cf83c6 100644 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c @@ -261,11 +261,6 @@ EXPORT_SYMBOL(dvb_ringbuffer_init); EXPORT_SYMBOL(dvb_ringbuffer_empty); EXPORT_SYMBOL(dvb_ringbuffer_free); EXPORT_SYMBOL(dvb_ringbuffer_avail); -EXPORT_SYMBOL(dvb_ringbuffer_flush); EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index 7db6eee50e39..e7f76f515b4f 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -1026,6 +1026,7 @@ static int af9005_usb_probe(struct usb_interface *intf, static struct usb_device_id af9005_usb_table[] = { {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)}, {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)}, + {USB_DEVICE(USB_VID_ANSONIC, USB_PID_ANSONIC_DVBT_USB)}, {0}, }; @@ -1075,7 +1076,7 @@ static struct dvb_usb_device_properties af9005_properties = { .rc_key_map_size = 0, .rc_query = af9005_rc_query, - .num_device_descs = 2, + .num_device_descs = 3, .devices = { {.name = "Afatech DVB-T USB1.1 stick", .cold_ids = {&af9005_usb_table[0], NULL}, @@ -1085,6 +1086,10 @@ static struct dvb_usb_device_properties af9005_properties = { .cold_ids = {&af9005_usb_table[1], NULL}, .warm_ids = {NULL}, }, + {.name = "Ansonic DVB-T USB1.1 stick", + .cold_ids = {&af9005_usb_table[2], NULL}, + .warm_ids = {NULL}, + }, {NULL}, } }; diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 18e0b16fb2a9..f3ff81314696 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -79,12 +79,12 @@ static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - if (num > 2) return -EINVAL; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 04e31cf7d530..c58365005ac1 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -15,7 +15,7 @@ * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de) * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) - * Copyright (C) 2006 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) * * 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 @@ -30,11 +30,16 @@ #include "mt352.h" #include "mt352_priv.h" #include "zl10353.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" /* debug */ -int dvb_usb_cxusb_debug; +static int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) +#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ + dprintk(dvb_usb_cxusb_debug,0x01,args) static int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen) @@ -46,11 +51,9 @@ static int cxusb_ctrl_msg(struct dvb_usb_device *d, sndbuf[0] = cmd; memcpy(&sndbuf[1], wbuf, wlen); if (wo) - dvb_usb_generic_write(d, sndbuf, 1+wlen); + return dvb_usb_generic_write(d, sndbuf, 1+wlen); else - dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); - - return 0; + return dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0); } /* GPIO */ @@ -72,6 +75,34 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) st->gpio_write_state[GPIO_TUNER] = onoff; } +static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, + u8 newval) +{ + u8 o[2], gpio_state; + int rc; + + o[0] = 0xff & ~changemask; /* mask of bits to keep */ + o[1] = newval & changemask; /* new values for bits */ + + rc = cxusb_ctrl_msg(d, CMD_BLUEBIRD_GPIO_RW, o, 2, &gpio_state, 1); + if (rc < 0 || (gpio_state & changemask) != (newval & changemask)) + deb_info("bluebird_gpio_write failed.\n"); + + return rc < 0 ? rc : gpio_state; +} + +static void cxusb_bluebird_gpio_pulse(struct dvb_usb_device *d, u8 pin, int low) +{ + cxusb_bluebird_gpio_rw(d, pin, low ? 0 : pin); + msleep(5); + cxusb_bluebird_gpio_rw(d, pin, low ? pin : 0); +} + +static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) +{ + cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -82,9 +113,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - if (num > 2) - warn("more than two i2c messages at a time is not handled yet. TODO."); - for (i = 0; i < num; i++) { if (d->udev->descriptor.idVendor == USB_VID_MEDION) @@ -97,8 +125,22 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], break; } - /* read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { + if (msg[i].flags & I2C_M_RD) { + /* read only */ + u8 obuf[3], ibuf[1+msg[i].len]; + obuf[0] = 0; + obuf[1] = msg[i].len; + obuf[2] = msg[i].addr; + if (cxusb_ctrl_msg(d, CMD_I2C_READ, + obuf, 3, + ibuf, 1+msg[i].len) < 0) { + warn("i2c read failed"); + break; + } + memcpy(msg[i].buf, &ibuf[1], msg[i].len); + } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && + msg[i].addr == msg[i+1].addr) { + /* write to then read from same address */ u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len]; obuf[0] = msg[i].len; obuf[1] = msg[i+1].len; @@ -116,7 +158,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); i++; - } else { /* write */ + } else { + /* write only */ u8 obuf[2+msg[i].len], ibuf; obuf[0] = msg[i].addr; obuf[1] = msg[i].len; @@ -131,7 +174,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], } mutex_unlock(&d->i2c_mutex); - return i; + return i == num ? num : -EREMOTEIO; } static u32 cxusb_i2c_func(struct i2c_adapter *adapter) @@ -162,6 +205,17 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } +static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int rc = 0; + + rc = cxusb_power_ctrl(d, onoff); + if (!onoff) + cxusb_nano2_led(d, 0); + + return rc; +} + static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -197,6 +251,34 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } +static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) + return 0; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[1] && + keymap[i].data == ircode[2]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x02, KEY_TV }, { 0xfe, 0x0e, KEY_MP3 }, @@ -351,6 +433,20 @@ static struct mt352_config cxusb_mt352_config = { .demod_init = cxusb_mt352_demod_init, }; +static struct zl10353_config cxusb_zl10353_xc3028_config = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, + .parallel_ts = 1, +}; + +static struct mt352_config cxusb_mt352_xc3028_config = { + .demod_address = 0x0f, + .if2 = 4560, + .no_tuner = 1, + .demod_init = cxusb_mt352_demod_init, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -386,6 +482,51 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) +{ + struct dvb_usb_device *d = ptr; + + switch (command) { + case XC2028_TUNER_RESET: + deb_info("%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); + cxusb_bluebird_gpio_pulse(d, 0x01, 1); + break; + case XC2028_RESET_CLK: + deb_info("%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); + break; + default: + deb_info("%s: unknown command %d, arg %d\n", __FUNCTION__, + command, arg); + return -EINVAL; + } + + return 0; +} + +static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &adap->dev->i2c_adap, + .i2c_addr = 0x61, + .video_dev = adap->dev, + .callback = dvico_bluebird_xc2028_callback, + }; + static struct xc2028_ctrl ctl = { + .fname = "xc3028-dvico-au-01.fw", + .max_len = 64, + .scode_table = ZARLINK456, + }; + + fe = dvb_attach(xc2028_attach, adap->fe, &cfg); + if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) + return -EIO; + + fe->ops.tuner_ops.set_config(fe, &ctl); + + return 0; +} + static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -447,27 +588,120 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } +static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) +{ + u8 ircode[4]; + int i; + struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, + .buf = ircode, .len = 4 }; + + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap)) == NULL) + return -EIO; + + /* try to determine if there is no IR decoder on the I2C bus */ + for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) { + msleep(20); + if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1) + goto no_IR; + if (ircode[0] == 0 && ircode[1] == 0) + continue; + if (ircode[2] + ircode[3] != 0xff) { +no_IR: + adap->dev->props.rc_key_map = NULL; + info("No IR receiver detected on this device."); + break; + } + } + + return 0; +} + +static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + /* reset the tuner and demodulator */ + cxusb_bluebird_gpio_rw(adap->dev, 0x04, 0); + cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + if ((adap->fe = dvb_attach(zl10353_attach, + &cxusb_zl10353_xc3028_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + if ((adap->fe = dvb_attach(mt352_attach, + &cxusb_mt352_xc3028_config, + &adap->dev->i2c_adap)) != NULL) + return 0; + + return -EIO; +} + +/* + * DViCO has shipped two devices with the same USB ID, but only one of them + * needs a firmware download. Check the device class details to see if they + * have non-default values to decide whether the device is actually cold or + * not, and forget a match if it turns out we selected the wrong device. + */ +static int bluebird_fx2_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) +{ + int wascold = *cold; + + *cold = udev->descriptor.bDeviceClass == 0xff && + udev->descriptor.bDeviceSubClass == 0xff && + udev->descriptor.bDeviceProtocol == 0xff; + + if (*cold && !wascold) + *desc = NULL; + + return 0; +} + /* * DViCO bluebird firmware needs the "warm" product ID to be patched into the * firmware file before download. */ -#define BLUEBIRD_01_ID_OFFSET 6638 +static const int dvico_firmware_id_offsets[] = { 6638, 3204 }; static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const struct firmware *fw) { - if (fw->size < BLUEBIRD_01_ID_OFFSET + 4) - return -EINVAL; + int pos; + + for (pos = 0; pos < ARRAY_SIZE(dvico_firmware_id_offsets); pos++) { + int idoff = dvico_firmware_id_offsets[pos]; - if (fw->data[BLUEBIRD_01_ID_OFFSET] == (USB_VID_DVICO & 0xff) && - fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { + if (fw->size < idoff + 4) + continue; - fw->data[BLUEBIRD_01_ID_OFFSET + 2] = - le16_to_cpu(udev->descriptor.idProduct) + 1; - fw->data[BLUEBIRD_01_ID_OFFSET + 3] = - le16_to_cpu(udev->descriptor.idProduct) >> 8; + if (fw->data[idoff] == (USB_VID_DVICO & 0xff) && + fw->data[idoff + 1] == USB_VID_DVICO >> 8) { + fw->data[idoff + 2] = + le16_to_cpu(udev->descriptor.idProduct) + 1; + fw->data[idoff + 3] = + le16_to_cpu(udev->descriptor.idProduct) >> 8; - return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); + return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); + } } return -EINVAL; @@ -479,6 +713,9 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -487,7 +724,10 @@ static int cxusb_probe(struct usb_interface *intf, dvb_usb_device_init(intf,&cxusb_bluebird_lgh064f_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_dee1601_properties,THIS_MODULE,NULL) == 0 || dvb_usb_device_init(intf,&cxusb_bluebird_lgz201_properties,THIS_MODULE,NULL) == 0 || - dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0) { + dvb_usb_device_init(intf,&cxusb_bluebird_dtt7579_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_dualdig4_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_nano2_properties,THIS_MODULE,NULL) == 0 || + dvb_usb_device_init(intf,&cxusb_bluebird_nano2_needsfirmware_properties,THIS_MODULE,NULL) == 0) { return 0; } @@ -508,6 +748,9 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -766,6 +1009,151 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { } }; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_mce_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), + .rc_query = cxusb_bluebird2_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4", + { NULL }, + { &cxusb_table[13], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_bluebird2_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2", + { NULL }, + { &cxusb_table[14], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = DEVICE_SPECIFIC, + .firmware = "dvb-usb-bluebird-02.fw", + .download_firmware = bluebird_patch_dvico_firmware_download, + .identify_state = bluebird_fx2_identify_state, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_nano2_frontend_attach, + .tuner_attach = cxusb_dvico_xc3028_tuner_attach, + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_nano2_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_portable_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys), + .rc_query = cxusb_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", + { &cxusb_table[14], NULL }, + { &cxusb_table[15], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h index c8ef77554b00..4768a2c35517 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.h +++ b/drivers/media/dvb/dvb-usb/cxusb.h @@ -4,12 +4,9 @@ #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" -extern int dvb_usb_cxusb_debug; -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args) -#define deb_i2c(args...) if (d->udev->descriptor.idVendor == USB_VID_MEDION) \ - dprintk(dvb_usb_cxusb_debug,0x01,args) - /* usb commands - some of it are guesses, don't have a reference yet */ +#define CMD_BLUEBIRD_GPIO_RW 0x05 + #define CMD_I2C_WRITE 0x08 #define CMD_I2C_READ 0x09 diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 3ea294eb96bd..c9857d5c6982 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -243,7 +243,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) u8 b[4]; b[0] = REQUEST_ENABLE_VIDEO; - b[1] = 0x00; + b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ b[2] = (0x01 << 4); /* Master mode */ b[3] = 0x00; @@ -256,9 +256,6 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) b[2] |= st->channel_state; - if (st->channel_state) /* if at least one channel is active */ - b[1] = (0x01 << 4) | 0x00; - deb_info("data for streaming: %x %x\n",b[1],b[2]); return dib0700_ctrl_wr(adap->dev, b, 4); diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 58452b52002c..e7093826e975 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -94,12 +94,28 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } +static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) +{ + struct i2c_msg msg[2] = { + { .addr = 0x50, .flags = 0, .buf = &adrs, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = pval, .len = 1 }, + }; + if (i2c_transfer(adap, msg, 2) != 2) return -EREMOTEIO; + return 0; +} + static int bristol_tuner_attach(struct dvb_usb_adapter *adap) { - struct dib0700_state *st = adap->dev->priv; + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id], - st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE && + adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_500_2) { + if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; + } + return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], + if1) == NULL ? -ENODEV : 0; } /* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */ @@ -230,6 +246,27 @@ static struct mt2266_config stk7700d_mt2266_config[2] = { } }; +static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (adap->id == 0) { + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib7000p_i2c_enumeration(&adap->dev->i2c_adap,1,18,stk7700d_dib7000p_mt2266_config); + } + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + &stk7700d_dib7000p_mt2266_config[adap->id]); + + return adap->fe == NULL ? -ENODEV : 0; +} + static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) { if (adap->id == 0) { @@ -415,6 +452,35 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { { 0x1e, 0x38, KEY_YELLOW }, { 0x1e, 0x3b, KEY_GOTO }, { 0x1e, 0x3d, KEY_POWER }, + + /* Key codes for the Leadtek Winfast DTV Dongle */ + { 0x00, 0x42, KEY_POWER }, + { 0x07, 0x7c, KEY_TUNER }, + { 0x0f, 0x4e, KEY_PRINT }, /* PREVIEW */ + { 0x08, 0x40, KEY_SCREEN }, /* full screen toggle*/ + { 0x0f, 0x71, KEY_DOT }, /* frequency */ + { 0x07, 0x43, KEY_0 }, + { 0x0c, 0x41, KEY_1 }, + { 0x04, 0x43, KEY_2 }, + { 0x0b, 0x7f, KEY_3 }, + { 0x0e, 0x41, KEY_4 }, + { 0x06, 0x43, KEY_5 }, + { 0x09, 0x7f, KEY_6 }, + { 0x0d, 0x7e, KEY_7 }, + { 0x05, 0x7c, KEY_8 }, + { 0x0a, 0x40, KEY_9 }, + { 0x0e, 0x4e, KEY_CLEAR }, + { 0x04, 0x7c, KEY_CHANNEL }, /* show channel number */ + { 0x0f, 0x41, KEY_LAST }, /* recall */ + { 0x03, 0x42, KEY_MUTE }, + { 0x06, 0x4c, KEY_RESERVED }, /* PIP button*/ + { 0x01, 0x72, KEY_SHUFFLE }, /* SNAPSHOT */ + { 0x0c, 0x4e, KEY_PLAYPAUSE }, /* TIMESHIFT */ + { 0x0b, 0x70, KEY_RECORD }, + { 0x03, 0x7d, KEY_VOLUMEUP }, + { 0x01, 0x7d, KEY_VOLUMEDOWN }, + { 0x02, 0x42, KEY_CHANNELUP }, + { 0x00, 0x7d, KEY_CHANNELDOWN }, }; /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ @@ -578,16 +644,22 @@ static struct mt2060_config stk7700p_mt2060_config = { static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) { + struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; struct dib0700_state *st = adap->dev->priv; struct i2c_adapter *tun_i2c; - + s8 a; + int if1=1220; + if (adap->dev->udev->descriptor.idVendor == USB_VID_HAUPPAUGE && + adap->dev->udev->descriptor.idProduct == USB_PID_HAUPPAUGE_NOVA_T_STICK) { + if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; + } if (st->is_dib7000pc) tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); else tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, - st->mt2060_if1[0]) == NULL ? -ENODEV : 0; + if1) == NULL ? -ENODEV : 0; } /* DIB7070 generic */ @@ -709,6 +781,8 @@ static struct dib7000p_config dib7070p_dib7000p_config = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -748,6 +822,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -760,6 +836,8 @@ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { .agc_config_count = 1, .agc = &dib7070_agc_config, .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, @@ -821,6 +899,12 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, /* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, + { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, + { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, + { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, +/* 25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -862,7 +946,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 7, + .num_device_descs = 8, .devices = { { "DiBcom STK7700P reference design", { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, @@ -891,6 +975,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "AVerMedia AVerTV DVB-T Express", { &dib0700_usb_id_table[20] }, { NULL }, + }, + { "Gigabyte U7000", + { &dib0700_usb_id_table[21], NULL }, + { NULL }, } }, @@ -961,7 +1049,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "DiBcom STK7700D reference design", { &dib0700_usb_id_table[14], NULL }, { NULL }, - }, + } }, .rc_interval = DEFAULT_RC_INTERVAL, @@ -974,6 +1062,25 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_adapters = 1, .adapter = { { + .frontend_attach = stk7700P2_frontend_attach, + .tuner_attach = stk7700d_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + }, + }, + + .num_device_descs = 1, + .devices = { + { "ASUS My Cinema U3000 Mini DVBT Tuner", + { &dib0700_usb_id_table[23], NULL }, + { NULL }, + }, + } + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + + .num_adapters = 1, + .adapter = { + { .frontend_attach = stk7070p_frontend_attach, .tuner_attach = dib7070p_tuner_attach, @@ -983,7 +1090,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { }, }, - .num_device_descs = 2, + .num_device_descs = 6, .devices = { { "DiBcom STK7070P reference design", { &dib0700_usb_id_table[15], NULL }, @@ -993,7 +1100,29 @@ struct dvb_usb_device_properties dib0700_devices[] = { { &dib0700_usb_id_table[16], NULL }, { NULL }, }, - } + { "Artec T14BR DVB-T", + { &dib0700_usb_id_table[22], NULL }, + { NULL }, + }, + { "ASUS My Cinema U3100 Mini DVBT Tuner", + { &dib0700_usb_id_table[24], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T Stick", + { &dib0700_usb_id_table[25], NULL }, + { NULL }, + }, + { "Hauppauge Nova-T MyTV.t", + { &dib0700_usb_id_table[26], NULL }, + { NULL }, + }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, .num_adapters = 2, @@ -1024,7 +1153,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Pinnacle PCTV Dual DVB-T Diversity Stick", { &dib0700_usb_id_table[18], NULL }, { NULL }, - }, + } } }, }; diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index bca1e0905739..3acbda4aa27e 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -17,9 +17,10 @@ #include "nxt6000.h" /* debug */ -int dvb_usb_digitv_debug; +static int dvb_usb_digitv_debug; module_param_named(debug,dvb_usb_digitv_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) static int digitv_ctrl_msg(struct dvb_usb_device *d, u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen) diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h index 8b43e3db8691..908c09f4966b 100644 --- a/drivers/media/dvb/dvb-usb/digitv.h +++ b/drivers/media/dvb/dvb-usb/digitv.h @@ -8,9 +8,6 @@ struct digitv_state { int is_nxt6000; }; -extern int dvb_usb_digitv_debug; -#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args) - /* protocol (from usblogging and the SDK: * * Always 7 bytes bulk message(s) for controlling diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 4fa3e895028a..aa4844ef875e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -15,7 +15,9 @@ #define USB_VID_ALCOR_MICRO 0x058f #define USB_VID_ALINK 0x05e3 #define USB_VID_ANCHOR 0x0547 +#define USB_VID_ANSONIC 0x10b9 #define USB_VID_ANUBIS_ELECTRONIC 0x10fd +#define USB_VID_ASUS 0x0b05 #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f @@ -44,12 +46,16 @@ #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 #define USB_VID_UNIWILL 0x1584 #define USB_VID_WIDEVIEW 0x14aa +/* dom : pour gigabyte u7000 */ +#define USB_VID_GIGABYTE 0x1044 + /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 #define USB_PID_ADSTECH_USB2_WARM 0xa334 #define USB_PID_AFATECH_AF9005 0x9020 #define USB_VID_ALINK_DTU 0xf170 +#define USB_PID_ANSONIC_DVBT_USB 0x6000 #define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001 #define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800 @@ -69,6 +75,7 @@ #define USB_PID_DIBCOM_STK7700P 0x1e14 #define USB_PID_DIBCOM_STK7700P_PC 0x1e78 #define USB_PID_DIBCOM_STK7700D 0x1ef0 +#define USB_PID_DIBCOM_STK7700_U7000 0x7001 #define USB_PID_DIBCOM_STK7070P 0x1ebc #define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 @@ -99,6 +106,7 @@ #define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a #define USB_PID_ARTEC_T14_COLD 0x810b #define USB_PID_ARTEC_T14_WARM 0x810c +#define USB_PID_ARTEC_T14BR 0x810f #define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613 #define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002 #define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e @@ -120,6 +128,8 @@ #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 +#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 +#define USB_PID_HAUPPAUGE_MYTV_T 0x7080 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK 0x9580 #define USB_PID_AVERMEDIA_EXPRESS 0xb568 #define USB_PID_AVERMEDIA_VOLAR 0xa807 @@ -143,6 +153,9 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 +#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 +#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55 #define USB_PID_MEDION_MD95700 0x0932 @@ -170,6 +183,9 @@ #define USB_PID_OPERA1_WARM 0x3829 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514 #define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513 - +/* dom pour gigabyte u7000 */ +#define USB_PID_GIGABYTE_U7000 0x7001 +#define USB_PID_ASUS_U3000 0x171f +#define USB_PID_ASUS_U3100 0x173f #endif diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index f01d99c1c43c..6b99d9f4d5b3 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -56,12 +56,12 @@ static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], struct dvb_usb_device *d = i2c_get_adapdata(adap); int i; - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - if (num > 2) return -EINVAL; + if (mutex_lock_interruptible(&d->i2c_mutex) < 0) + return -EAGAIN; + for (i = 0; i < num; i++) { /* write/read request */ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 92147ee3e14f..83e8535014c6 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -171,22 +171,6 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) return 0; } -int gp8psk_bcm4500_reload(struct dvb_usb_device *d) -{ - u8 buf; - int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); - /* Turn off 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) - return -EINVAL; - /* Turn On 8psk power */ - if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) - return -EINVAL; - /* load BCM4500 firmware */ - if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) - if (gp8psk_load_bcm4500fw(d)) - return EINVAL; - return 0; -} static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h index e83a57506cfa..e5cd8149c23d 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.h +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -92,6 +92,5 @@ extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); #endif diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index d7c04951ceab..21935bf7059e 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -10,7 +10,9 @@ * see Documentation/dvb/README.dvb-usb for more information */ -#include "opera1.h" +#define DVB_USB_LOG_PREFIX "opera" + +#include "dvb-usb.h" #include "stv0299.h" #define OPERA_READ_MSG 0 @@ -38,7 +40,7 @@ struct opera_rc_keys { u32 event; }; -int dvb_usb_opera1_debug; +static int dvb_usb_opera1_debug; module_param_named(debug, dvb_usb_opera1_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." diff --git a/drivers/media/dvb/dvb-usb/opera1.h b/drivers/media/dvb/dvb-usb/opera1.h deleted file mode 100644 index 53174427902d..000000000000 --- a/drivers/media/dvb/dvb-usb/opera1.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _OPERA1_H_ -#define _OPERA1_H_ - -#define DVB_USB_LOG_PREFIX "opera" -#include "dvb-usb.h" - -extern int dvb_usb_opera1_debug; -#define deb_xfer(args...) dprintk(dvb_usb_opera1_debug,0x02,args) -#endif diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 16533b31a82d..e553c139ac44 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -56,7 +56,7 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 return ret; } -int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { int ret; @@ -204,19 +204,6 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) return 0; } -int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff) -{ - struct vp702x_device_state *st = d->priv; - - if (st->power_state == 0 && onoff) - vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); - else if (st->power_state == 1 && onoff == 0) - vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0); - - st->power_state = onoff; - - return 0; -} static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h index 25a9dee4c824..c2f97f96c21f 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.h +++ b/drivers/media/dvb/dvb-usb/vp702x.h @@ -102,7 +102,5 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d); extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec); extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); -extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff); #endif diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 5bbd2d5192f0..c172babf59bb 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -15,9 +15,12 @@ #include "vp7045.h" /* debug */ -int dvb_usb_vp7045_debug; +static int dvb_usb_vp7045_debug; module_param_named(debug,dvb_usb_vp7045_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); +#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec) { diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h index 9ce21a20fa86..969688f85267 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.h +++ b/drivers/media/dvb/dvb-usb/vp7045.h @@ -17,11 +17,6 @@ #define DVB_USB_LOG_PREFIX "vp7045" #include "dvb-usb.h" -extern int dvb_usb_vp7045_debug; -#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args) -#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args) -#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args) - /* vp7045 commands */ /* Twinhan Vendor requests */ diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 59b9ed1f1aec..9ad86ce4a4e5 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -316,6 +316,13 @@ config DVB_TDA827X help A DVB-T silicon tuner module. Say Y when you want to support this tuner. +config DVB_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + config DVB_TUNER_QT1010 tristate "Quantek QT1010 silicon tuner" depends on DVB_CORE && I2C @@ -353,6 +360,15 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called togther with a demodulator for now. +config DVB_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called togther with a + demodulator for now. + comment "Miscellaneous devices" depends on DVB_CORE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 4b8ad1f132aa..16bd107ebd32 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -3,6 +3,9 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ +EXTRA_CFLAGS += -Idrivers/media/video/ + +tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -39,6 +42,7 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA827X) += tda827x.o +obj-$(CONFIG_DVB_TDA18271) += tda18271.o obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o @@ -46,3 +50,4 @@ obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o +obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 481eaa684157..fe895bf7b18f 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -434,9 +434,14 @@ static u16 dib0070_p1f_defaults[] = 0, }; -static void dib0070_wbd_calibration(struct dib0070_state *state) +static void dib0070_wbd_calibration(struct dvb_frontend *fe) { u16 wbd_offs; + struct dib0070_state *state = fe->tuner_priv; + + if (state->cfg->sleep) + state->cfg->sleep(fe, 0); + dib0070_write_reg(state, 0x0f, 0x6d81); dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); msleep(9); @@ -444,6 +449,10 @@ static void dib0070_wbd_calibration(struct dib0070_state *state) dib0070_write_reg(state, 0x20, 0); state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2); dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset); + + if (state->cfg->sleep) + state->cfg->sleep(fe, 1); + } u16 dib0070_wbd_offset(struct dvb_frontend *fe) @@ -560,7 +569,7 @@ struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter if (dib0070_reset(state) != 0) goto free_mem; - dib0070_wbd_calibration(state); + dib0070_wbd_calibration(fe); printk(KERN_INFO "DiB0070: successfully identified\n"); memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index edae0be063f5..fa851601e7d4 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -684,6 +684,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib3000mc_state *state = fe->demodulator_priv; + int ret; + + dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -700,7 +703,7 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO || fep->u.ofdm.constellation == QAM_AUTO || fep->u.ofdm.code_rate_HP == FEC_AUTO) { - int i = 100, found; + int i = 1000, found; dib3000mc_autosearch_start(fe, fep); do { @@ -715,10 +718,11 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, dib3000mc_get_frontend(fe, fep); } + ret = dib3000mc_tune(fe, fep); + /* make this a config parameter */ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO); - - return dib3000mc_tune(fe, fep); + return ret; } static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index fb18441a8c57..5f1375e30dfc 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -1171,7 +1171,9 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000m_state *state = fe->demodulator_priv; - int time; + int time, ret; + + dib7000m_set_output_mode(state, OUTMODE_HIGH_Z); state->current_bandwidth = fep->u.ofdm.bandwidth; dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); @@ -1206,10 +1208,11 @@ static int dib7000m_set_frontend(struct dvb_frontend* fe, dib7000m_get_frontend(fe, fep); } + ret = dib7000m_tune(fe, fep); + /* make this a config parameter */ dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO); - - return dib7000m_tune(fe, fep); + return ret; } static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index f45bcfc51cf8..47c23e29753e 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -35,8 +35,8 @@ struct dib7000p_state { u16 wbd_ref; - u8 current_band; - fe_bandwidth_t current_bandwidth; + u8 current_band; + u32 current_bandwidth; struct dibx000_agc_config *current_agc; u32 timf; @@ -1074,7 +1074,7 @@ static int dib7000p_get_frontend(struct dvb_frontend* fe, fep->inversion = INVERSION_AUTO; - fep->u.ofdm.bandwidth = state->current_bandwidth; + fep->u.ofdm.bandwidth = BANDWIDTH_TO_INDEX(state->current_bandwidth); switch ((tps >> 8) & 0x3) { case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break; @@ -1128,12 +1128,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep) { struct dib7000p_state *state = fe->demodulator_priv; - int time; + int time, ret; - state->current_bandwidth = fep->u.ofdm.bandwidth; - dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth)); + dib7000p_set_output_mode(state, OUTMODE_HIGH_Z); - /* maybe the parameter has been changed */ + /* maybe the parameter has been changed */ state->sfn_workaround_active = buggy_sfn_workaround; if (fe->ops.tuner_ops.set_params) @@ -1166,10 +1165,11 @@ static int dib7000p_set_frontend(struct dvb_frontend* fe, dib7000p_get_frontend(fe, fep); } + ret = dib7000p_tune(fe, fep); + /* make this a config parameter */ dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO); - - return dib7000p_tune(fe, fep); + return ret; } static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat) diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5e17275afd25..84e4d5362922 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -128,6 +128,11 @@ enum dibx000_adc_states { (v) == BANDWIDTH_7_MHZ ? 7000 : \ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 ) +#define BANDWIDTH_TO_INDEX(v) ( \ + (v) == 8000 ? BANDWIDTH_8_MHZ : \ + (v) == 7000 ? BANDWIDTH_7_MHZ : \ + (v) == 6000 ? BANDWIDTH_6_MHZ : BANDWIDTH_8_MHZ ) + /* Chip output mode. */ #define OUTMODE_HIGH_Z 0 #define OUTMODE_MPEG2_PAR_GATED_CLK 1 diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c index 03fe8265745f..54b18f94b14b 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/dvb/frontends/mt2266.c @@ -38,8 +38,12 @@ struct mt2266_priv { u32 frequency; u32 bandwidth; + u8 band; }; +#define MT2266_VHF 1 +#define MT2266_UHF 0 + /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ static int debug; @@ -90,26 +94,30 @@ static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) } // Initialisation sequences -static u8 mt2266_init1[] = { - REG_TUNE, - 0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f }; +static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, + 0x00, 0x52, 0x99, 0x3f }; static u8 mt2266_init2[] = { - 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, - 0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d }; + 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, + 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, + 0xff, 0x00, 0x77, 0x0f, 0x2d +}; + +static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22 }; -static u8 mt2266_init_8mhz[] = { - REG_BANDWIDTH, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }; +static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32 }; -static u8 mt2266_init_7mhz[] = { - REG_BANDWIDTH, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 }; +static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7 }; -static u8 mt2266_init_6mhz[] = { - REG_BANDWIDTH, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 }; +static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, + 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; + +static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, + 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; #define FREF 30000 // Quartz oscillator 30 MHz @@ -122,35 +130,78 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame u8 lnaband; u8 b[10]; int i; + u8 band; priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); - freq = params->frequency / 1000; // Hz -> kHz + if (freq < 470000 && freq > 230000) + return -EINVAL; /* Gap between VHF and UHF bands */ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0; priv->frequency = freq * 1000; - tune=2 * freq * (8192/16) / (FREF/16); - - if (freq <= 495000) lnaband = 0xEE; else - if (freq <= 525000) lnaband = 0xDD; else - if (freq <= 550000) lnaband = 0xCC; else - if (freq <= 580000) lnaband = 0xBB; else - if (freq <= 605000) lnaband = 0xAA; else - if (freq <= 630000) lnaband = 0x99; else - if (freq <= 655000) lnaband = 0x88; else - if (freq <= 685000) lnaband = 0x77; else - if (freq <= 710000) lnaband = 0x66; else - if (freq <= 735000) lnaband = 0x55; else - if (freq <= 765000) lnaband = 0x44; else - if (freq <= 802000) lnaband = 0x33; else - if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11; - - msleep(100); - mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz: - (params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz: - mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); + + tune = 2 * freq * (8192/16) / (FREF/16); + band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; + if (band == MT2266_VHF) + tune *= 2; + + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + mt2266_writeregs(priv, mt2266_init_6mhz, + sizeof(mt2266_init_6mhz)); + break; + case BANDWIDTH_7_MHZ: + mt2266_writeregs(priv, mt2266_init_7mhz, + sizeof(mt2266_init_7mhz)); + break; + case BANDWIDTH_8_MHZ: + default: + mt2266_writeregs(priv, mt2266_init_8mhz, + sizeof(mt2266_init_8mhz)); + break; + } + + if (band == MT2266_VHF && priv->band == MT2266_UHF) { + dprintk("Switch from UHF to VHF"); + mt2266_writereg(priv, 0x05, 0x04); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); + } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { + dprintk("Switch from VHF to UHF"); + mt2266_writereg(priv, 0x05, 0x52); + mt2266_writereg(priv, 0x19, 0x61); + mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); + } + msleep(10); + + if (freq <= 495000) + lnaband = 0xEE; + else if (freq <= 525000) + lnaband = 0xDD; + else if (freq <= 550000) + lnaband = 0xCC; + else if (freq <= 580000) + lnaband = 0xBB; + else if (freq <= 605000) + lnaband = 0xAA; + else if (freq <= 630000) + lnaband = 0x99; + else if (freq <= 655000) + lnaband = 0x88; + else if (freq <= 685000) + lnaband = 0x77; + else if (freq <= 710000) + lnaband = 0x66; + else if (freq <= 735000) + lnaband = 0x55; + else if (freq <= 765000) + lnaband = 0x44; + else if (freq <= 802000) + lnaband = 0x33; + else if (freq <= 840000) + lnaband = 0x22; + else + lnaband = 0x11; b[0] = REG_TUNE; b[1] = (tune >> 8) & 0x1F; @@ -158,47 +209,54 @@ static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parame b[3] = tune >> 13; mt2266_writeregs(priv,b,4); - dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband); - dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]); - - b[0] = 0x05; - b[1] = 0x62; - b[2] = lnaband; - mt2266_writeregs(priv,b,3); + dprintk("set_parms: tune=%d band=%d %s", + (int) tune, (int) lnaband, + (band == MT2266_UHF) ? "UHF" : "VHF"); + dprintk("set_parms: [1..3]: %2x %2x %2x", + (int) b[1], (int) b[2], (int)b[3]); + + if (band == MT2266_UHF) { + b[0] = 0x05; + b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; + b[2] = lnaband; + mt2266_writeregs(priv, b, 3); + } - //Waits for pll lock or timeout + /* Wait for pll lock or timeout */ i = 0; do { mt2266_readreg(priv,REG_LOCK,b); - if ((b[0] & 0x40)==0x40) + if (b[0] & 0x40) break; msleep(10); i++; } while (i<10); dprintk("Lock when i=%i",(int)i); + + if (band == MT2266_UHF && priv->band == MT2266_VHF) + mt2266_writereg(priv, 0x05, 0x62); + + priv->band = band; + return ret; } static void mt2266_calibrate(struct mt2266_priv *priv) { - mt2266_writereg(priv,0x11,0x03); - mt2266_writereg(priv,0x11,0x01); - - mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1)); - mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2)); - - mt2266_writereg(priv,0x33,0x5e); - mt2266_writereg(priv,0x10,0x10); - mt2266_writereg(priv,0x10,0x00); - - mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz)); - + mt2266_writereg(priv, 0x11, 0x03); + mt2266_writereg(priv, 0x11, 0x01); + mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); + mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); + mt2266_writereg(priv, 0x33, 0x5e); + mt2266_writereg(priv, 0x10, 0x10); + mt2266_writereg(priv, 0x10, 0x00); + mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); msleep(25); - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0x00); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); msleep(75); - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0xff); } static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) @@ -217,17 +275,22 @@ static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static int mt2266_init(struct dvb_frontend *fe) { + int ret; struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0xff); + ret = mt2266_writereg(priv, 0x17, 0x6d); + if (ret < 0) + return ret; + ret = mt2266_writereg(priv, 0x1c, 0xff); + if (ret < 0) + return ret; return 0; } static int mt2266_sleep(struct dvb_frontend *fe) { struct mt2266_priv *priv = fe->tuner_priv; - mt2266_writereg(priv,0x17,0x6d); - mt2266_writereg(priv,0x1c,0x00); + mt2266_writereg(priv, 0x17, 0x6d); + mt2266_writereg(priv, 0x1c, 0x00); return 0; } @@ -241,8 +304,8 @@ static int mt2266_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops mt2266_tuner_ops = { .info = { .name = "Microtune MT2266", - .frequency_min = 470000000, - .frequency_max = 860000000, + .frequency_min = 174000000, + .frequency_max = 862000000, .frequency_step = 50000, }, .release = mt2266_release, @@ -264,8 +327,9 @@ struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter priv->cfg = cfg; priv->i2c = i2c; + priv->band = MT2266_UHF; - if (mt2266_readreg(priv,0,&id) != 0) { + if (mt2266_readreg(priv, 0, &id)) { kfree(priv); return NULL; } diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index 0606b9a5b616..1638301fbd6e 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -37,9 +37,9 @@ struct mt312_state { - struct i2c_adapter* i2c; + struct i2c_adapter *i2c; /* configuration settings */ - const struct mt312_config* config; + const struct mt312_config *config; struct dvb_frontend frontend; u8 id; @@ -49,14 +49,15 @@ struct mt312_state { static int debug; #define dprintk(args...) \ do { \ - if (debug) printk(KERN_DEBUG "mt312: " args); \ + if (debug) \ + printk(KERN_DEBUG "mt312: " args); \ } while (0) #define MT312_SYS_CLK 90000000UL /* 90 MHz */ #define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */ #define MT312_PLL_CLK 10000000UL /* 10 MHz */ -static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, +static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg, void *buf, const size_t count) { int ret; @@ -79,7 +80,7 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, return -EREMOTEIO; } - if(debug) { + if (debug) { int i; dprintk("R(%d):", reg & 0x7f); for (i = 0; i < count; i++) @@ -90,14 +91,14 @@ static int mt312_read(struct mt312_state* state, const enum mt312_reg_addr reg, return 0; } -static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg, +static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, const void *src, const size_t count) { int ret; u8 buf[count + 1]; struct i2c_msg msg; - if(debug) { + if (debug) { int i; dprintk("W(%d):", reg & 0x7f); for (i = 0; i < count; i++) @@ -123,13 +124,13 @@ static int mt312_write(struct mt312_state* state, const enum mt312_reg_addr reg, return 0; } -static inline int mt312_readreg(struct mt312_state* state, +static inline int mt312_readreg(struct mt312_state *state, const enum mt312_reg_addr reg, u8 *val) { return mt312_read(state, reg, val, 1); } -static inline int mt312_writereg(struct mt312_state* state, +static inline int mt312_writereg(struct mt312_state *state, const enum mt312_reg_addr reg, const u8 val) { return mt312_write(state, reg, &val, 1); @@ -140,18 +141,19 @@ static inline u32 mt312_div(u32 a, u32 b) return (a + (b / 2)) / b; } -static int mt312_reset(struct mt312_state* state, const u8 full) +static int mt312_reset(struct mt312_state *state, const u8 full) { return mt312_writereg(state, RESET, full ? 0x80 : 0x40); } -static int mt312_get_inversion(struct mt312_state* state, +static int mt312_get_inversion(struct mt312_state *state, fe_spectral_inversion_t *i) { int ret; u8 vit_mode; - if ((ret = mt312_readreg(state, VIT_MODE, &vit_mode)) < 0) + ret = mt312_readreg(state, VIT_MODE, &vit_mode); + if (ret < 0) return ret; if (vit_mode & 0x80) /* auto inversion was used */ @@ -160,7 +162,7 @@ static int mt312_get_inversion(struct mt312_state* state, return 0; } -static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) +static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) { int ret; u8 sym_rate_h; @@ -169,37 +171,44 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) u16 monitor; u8 buf[2]; - if ((ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h)) < 0) + ret = mt312_readreg(state, SYM_RATE_H, &sym_rate_h); + if (ret < 0) return ret; - if (sym_rate_h & 0x80) { /* symbol rate search was used */ - if ((ret = mt312_writereg(state, MON_CTRL, 0x03)) < 0) + if (sym_rate_h & 0x80) { + /* symbol rate search was used */ + ret = mt312_writereg(state, MON_CTRL, 0x03); + if (ret < 0) return ret; - if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); + if (ret < 0) return ret; monitor = (buf[0] << 8) | buf[1]; - dprintk(KERN_DEBUG "sr(auto) = %u\n", + dprintk("sr(auto) = %u\n", mt312_div(monitor * 15625, 4)); } else { - if ((ret = mt312_writereg(state, MON_CTRL, 0x05)) < 0) + ret = mt312_writereg(state, MON_CTRL, 0x05); + if (ret < 0) return ret; - if ((ret = mt312_read(state, MONITOR_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, MONITOR_H, buf, sizeof(buf)); + if (ret < 0) return ret; dec_ratio = ((buf[0] >> 5) & 0x07) * 32; - if ((ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, SYM_RAT_OP_H, buf, sizeof(buf)); + if (ret < 0) return ret; sym_rat_op = (buf[0] << 8) | buf[1]; - dprintk(KERN_DEBUG "sym_rat_op=%d dec_ratio=%d\n", + dprintk("sym_rat_op=%d dec_ratio=%d\n", sym_rat_op, dec_ratio); - dprintk(KERN_DEBUG "*sr(manual) = %lu\n", + dprintk("*sr(manual) = %lu\n", (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) * 2) - dec_ratio); } @@ -207,7 +216,7 @@ static int mt312_get_symbol_rate(struct mt312_state* state, u32 *sr) return 0; } -static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) +static int mt312_get_code_rate(struct mt312_state *state, fe_code_rate_t *cr) { const fe_code_rate_t fec_tab[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_6_7, FEC_7_8, @@ -216,7 +225,8 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) int ret; u8 fec_status; - if ((ret = mt312_readreg(state, FEC_STATUS, &fec_status)) < 0) + ret = mt312_readreg(state, FEC_STATUS, &fec_status); + if (ret < 0) return ret; *cr = fec_tab[(fec_status >> 4) & 0x07]; @@ -224,61 +234,72 @@ static int mt312_get_code_rate(struct mt312_state* state, fe_code_rate_t *cr) return 0; } -static int mt312_initfe(struct dvb_frontend* fe) +static int mt312_initfe(struct dvb_frontend *fe) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; /* wake up */ - if ((ret = mt312_writereg(state, CONFIG, (state->frequency == 60 ? 0x88 : 0x8c))) < 0) + ret = mt312_writereg(state, CONFIG, + (state->frequency == 60 ? 0x88 : 0x8c)); + if (ret < 0) return ret; /* wait at least 150 usec */ udelay(150); /* full reset */ - if ((ret = mt312_reset(state, 1)) < 0) + ret = mt312_reset(state, 1); + if (ret < 0) return ret; -// Per datasheet, write correct values. 09/28/03 ACCJr. -// If we don't do this, we won't get FE_HAS_VITERBI in the VP310. +/* Per datasheet, write correct values. 09/28/03 ACCJr. + * If we don't do this, we won't get FE_HAS_VITERBI in the VP310. */ { - u8 buf_def[8]={0x14, 0x12, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00}; + u8 buf_def[8] = { 0x14, 0x12, 0x03, 0x02, + 0x01, 0x00, 0x00, 0x00 }; - if ((ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def))) < 0) + ret = mt312_write(state, VIT_SETUP, buf_def, sizeof(buf_def)); + if (ret < 0) return ret; } /* SYS_CLK */ - buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : MT312_SYS_CLK) * 2, 1000000); + buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK : + MT312_SYS_CLK) * 2, 1000000); /* DISEQC_RATIO */ buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4); - if ((ret = mt312_write(state, SYS_CLK, buf, sizeof(buf))) < 0) + ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); + if (ret < 0) return ret; - if ((ret = mt312_writereg(state, SNR_THS_HIGH, 0x32)) < 0) + ret = mt312_writereg(state, SNR_THS_HIGH, 0x32); + if (ret < 0) return ret; - if ((ret = mt312_writereg(state, OP_CTRL, 0x53)) < 0) + ret = mt312_writereg(state, OP_CTRL, 0x53); + if (ret < 0) return ret; /* TS_SW_LIM */ buf[0] = 0x8c; buf[1] = 0x98; - if ((ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf))) < 0) + ret = mt312_write(state, TS_SW_LIM_L, buf, sizeof(buf)); + if (ret < 0) return ret; - if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0) + ret = mt312_writereg(state, CS_SW_LIM, 0x69); + if (ret < 0) return ret; return 0; } -static int mt312_send_master_cmd(struct dvb_frontend* fe, +static int mt312_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *c) { struct mt312_state *state = fe->demodulator_priv; @@ -288,29 +309,31 @@ static int mt312_send_master_cmd(struct dvb_frontend* fe, if ((c->msg_len == 0) || (c->msg_len > sizeof(c->msg))) return -EINVAL; - if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) return ret; - if ((ret = - mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len)) < 0) + ret = mt312_write(state, (0x80 | DISEQC_INSTR), c->msg, c->msg_len); + if (ret < 0) return ret; - if ((ret = - mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) - | 0x04)) < 0) + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | ((c->msg_len - 1) << 3) + | 0x04); + if (ret < 0) return ret; /* set DISEQC_MODE[2:0] to zero if a return message is expected */ - if (c->msg[0] & 0x02) - if ((ret = - mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40))) < 0) + if (c->msg[0] & 0x02) { + ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40)); + if (ret < 0) return ret; + } return 0; } -static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) +static int mt312_send_burst(struct dvb_frontend *fe, const fe_sec_mini_cmd_t c) { struct mt312_state *state = fe->demodulator_priv; const u8 mini_tab[2] = { 0x02, 0x03 }; @@ -321,18 +344,19 @@ static int mt312_send_burst(struct dvb_frontend* fe, const fe_sec_mini_cmd_t c) if (c > SEC_MINI_B) return -EINVAL; - if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) return ret; - if ((ret = - mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | mini_tab[c])) < 0) + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | mini_tab[c]); + if (ret < 0) return ret; return 0; } -static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) +static int mt312_set_tone(struct dvb_frontend *fe, const fe_sec_tone_mode_t t) { struct mt312_state *state = fe->demodulator_priv; const u8 tone_tab[2] = { 0x01, 0x00 }; @@ -343,18 +367,19 @@ static int mt312_set_tone(struct dvb_frontend* fe, const fe_sec_tone_mode_t t) if (t > SEC_TONE_OFF) return -EINVAL; - if ((ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode)) < 0) + ret = mt312_readreg(state, DISEQC_MODE, &diseqc_mode); + if (ret < 0) return ret; - if ((ret = - mt312_writereg(state, DISEQC_MODE, - (diseqc_mode & 0x40) | tone_tab[t])) < 0) + ret = mt312_writereg(state, DISEQC_MODE, + (diseqc_mode & 0x40) | tone_tab[t]); + if (ret < 0) return ret; return 0; } -static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) +static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v) { struct mt312_state *state = fe->demodulator_priv; const u8 volt_tab[3] = { 0x00, 0x40, 0x00 }; @@ -365,7 +390,7 @@ static int mt312_set_voltage(struct dvb_frontend* fe, const fe_sec_voltage_t v) return mt312_writereg(state, DISEQC_MODE, volt_tab[v]); } -static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) +static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -373,10 +398,12 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) *s = 0; - if ((ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status))) < 0) + ret = mt312_read(state, QPSK_STAT_H, status, sizeof(status)); + if (ret < 0) return ret; - dprintk(KERN_DEBUG "QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); + dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," + " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); if (status[0] & 0xc0) *s |= FE_HAS_SIGNAL; /* signal noise ratio */ @@ -392,13 +419,14 @@ static int mt312_read_status(struct dvb_frontend* fe, fe_status_t *s) return 0; } -static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) +static int mt312_read_ber(struct dvb_frontend *fe, u32 *ber) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[3]; - if ((ret = mt312_read(state, RS_BERCNT_H, buf, 3)) < 0) + ret = mt312_read(state, RS_BERCNT_H, buf, 3); + if (ret < 0) return ret; *ber = ((buf[0] << 16) | (buf[1] << 8) | buf[2]) * 64; @@ -406,7 +434,8 @@ static int mt312_read_ber(struct dvb_frontend* fe, u32 *ber) return 0; } -static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_strength) +static int mt312_read_signal_strength(struct dvb_frontend *fe, + u16 *signal_strength) { struct mt312_state *state = fe->demodulator_priv; int ret; @@ -414,7 +443,8 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren u16 agc; s16 err_db; - if ((ret = mt312_read(state, AGC_H, buf, sizeof(buf))) < 0) + ret = mt312_read(state, AGC_H, buf, sizeof(buf)); + if (ret < 0) return ret; agc = (buf[0] << 6) | (buf[1] >> 2); @@ -422,18 +452,19 @@ static int mt312_read_signal_strength(struct dvb_frontend* fe, u16 *signal_stren *signal_strength = agc; - dprintk(KERN_DEBUG "agc=%08x err_db=%hd\n", agc, err_db); + dprintk("agc=%08x err_db=%hd\n", agc, err_db); return 0; } -static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) +static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; - if ((ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf))) < 0) + ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf)); + if (ret < 0) return ret; *snr = 0xFFFF - ((((buf[0] & 0x7f) << 8) | buf[1]) << 1); @@ -441,13 +472,14 @@ static int mt312_read_snr(struct dvb_frontend* fe, u16 *snr) return 0; } -static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) +static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 buf[2]; - if ((ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf))) < 0) + ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf)); + if (ret < 0) return ret; *ubc = (buf[0] << 8) | buf[1]; @@ -455,7 +487,7 @@ static int mt312_read_ucblocks(struct dvb_frontend* fe, u32 *ubc) return 0; } -static int mt312_set_frontend(struct dvb_frontend* fe, +static int mt312_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct mt312_state *state = fe->demodulator_priv; @@ -491,24 +523,28 @@ static int mt312_set_frontend(struct dvb_frontend* fe, switch (state->id) { case ID_VP310: - // For now we will do this only for the VP310. - // It should be better for the mt312 as well, but tunning will be slower. ACCJr 09/29/03 + /* For now we will do this only for the VP310. + * It should be better for the mt312 as well, + * but tuning will be slower. ACCJr 09/29/03 + */ ret = mt312_readreg(state, CONFIG, &config_val); if (ret < 0) return ret; - if (p->u.qpsk.symbol_rate >= 30000000) //Note that 30MS/s should use 90MHz - { - if ((config_val & 0x0c) == 0x08) { //We are running 60MHz + if (p->u.qpsk.symbol_rate >= 30000000) { + /* Note that 30MS/s should use 90MHz */ + if ((config_val & 0x0c) == 0x08) { + /* We are running 60MHz */ state->frequency = 90; - if ((ret = mt312_initfe(fe)) < 0) + ret = mt312_initfe(fe); + if (ret < 0) return ret; } - } - else - { - if ((config_val & 0x0c) == 0x0C) { //We are running 90MHz + } else { + if ((config_val & 0x0c) == 0x0C) { + /* We are running 90MHz */ state->frequency = 60; - if ((ret = mt312_initfe(fe)) < 0) + ret = mt312_initfe(fe); + if (ret < 0) return ret; } } @@ -523,7 +559,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe, if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, p); - if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); } /* sr = (u16)(sr * 256.0 / 1000000.0) */ @@ -545,7 +582,8 @@ static int mt312_set_frontend(struct dvb_frontend* fe, /* GO */ buf[4] = 0x01; - if ((ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf))) < 0) + ret = mt312_write(state, SYM_RATE_H, buf, sizeof(buf)); + if (ret < 0) return ret; mt312_reset(state, 0); @@ -553,27 +591,30 @@ static int mt312_set_frontend(struct dvb_frontend* fe, return 0; } -static int mt312_get_frontend(struct dvb_frontend* fe, +static int mt312_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct mt312_state *state = fe->demodulator_priv; int ret; - if ((ret = mt312_get_inversion(state, &p->inversion)) < 0) + ret = mt312_get_inversion(state, &p->inversion); + if (ret < 0) return ret; - if ((ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate)) < 0) + ret = mt312_get_symbol_rate(state, &p->u.qpsk.symbol_rate); + if (ret < 0) return ret; - if ((ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner)) < 0) + ret = mt312_get_code_rate(state, &p->u.qpsk.fec_inner); + if (ret < 0) return ret; return 0; } -static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct mt312_state* state = fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; if (enable) { return mt312_writereg(state, GPP_CTRL, 0x40); @@ -582,27 +623,31 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) } } -static int mt312_sleep(struct dvb_frontend* fe) +static int mt312_sleep(struct dvb_frontend *fe) { struct mt312_state *state = fe->demodulator_priv; int ret; u8 config; /* reset all registers to defaults */ - if ((ret = mt312_reset(state, 1)) < 0) + ret = mt312_reset(state, 1); + if (ret < 0) return ret; - if ((ret = mt312_readreg(state, CONFIG, &config)) < 0) + ret = mt312_readreg(state, CONFIG, &config); + if (ret < 0) return ret; /* enter standby */ - if ((ret = mt312_writereg(state, CONFIG, config & 0x7f)) < 0) + ret = mt312_writereg(state, CONFIG, config & 0x7f); + if (ret < 0) return ret; return 0; } -static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) +static int mt312_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) { fesettings->min_delay_ms = 50; fesettings->step_size = 0; @@ -610,9 +655,9 @@ static int mt312_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_ return 0; } -static void mt312_release(struct dvb_frontend* fe) +static void mt312_release(struct dvb_frontend *fe) { - struct mt312_state* state = fe->demodulator_priv; + struct mt312_state *state = fe->demodulator_priv; kfree(state); } @@ -655,10 +700,10 @@ static struct dvb_frontend_ops vp310_mt312_ops = { .set_voltage = mt312_set_voltage, }; -struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, - struct i2c_adapter* i2c) +struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, + struct i2c_adapter *i2c) { - struct mt312_state* state = NULL; + struct mt312_state *state = NULL; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct mt312_state), GFP_KERNEL); @@ -674,7 +719,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, goto error; /* create dvb_frontend */ - memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &vp310_mt312_ops, + sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; switch (state->id) { @@ -687,7 +733,8 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, state->frequency = 60; break; default: - printk (KERN_WARNING "Only Zarlink VP310/MT312 are supported chips.\n"); + printk(KERN_WARNING "Only Zarlink VP310/MT312" + " are supported chips.\n"); goto error; } @@ -697,6 +744,7 @@ error: kfree(state); return NULL; } +EXPORT_SYMBOL(vp310_mt312_attach); module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); @@ -705,4 +753,3 @@ MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver"); MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(vp310_mt312_attach); diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h index cf9a1505ad4b..f17cb93ba9ba 100644 --- a/drivers/media/dvb/frontends/mt312.h +++ b/drivers/media/dvb/frontends/mt312.h @@ -28,22 +28,21 @@ #include <linux/dvb/frontend.h> -struct mt312_config -{ +struct mt312_config { /* the demodulator's i2c address */ u8 demod_address; }; #if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE)) -struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, - struct i2c_adapter* i2c); +struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config, + struct i2c_adapter *i2c); #else -static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, - struct i2c_adapter* i2c) +static inline struct dvb_frontend *vp310_mt312_attach( + const struct mt312_config *config, struct i2c_adapter *i2c) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_MT312 +#endif /* CONFIG_DVB_MT312 */ -#endif // MT312_H +#endif /* MT312_H */ diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index 5dd9b731f6f2..7cd190b6f015 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -152,7 +152,13 @@ static void mt352_calc_input_freq(struct mt352_state* state, if (state->config.if2) if2 = state->config.if2; - ife = (2*adc_clock - if2); + if (adc_clock >= if2 * 2) + ife = if2; + else { + ife = adc_clock - (if2 % adc_clock); + if (ife > adc_clock / 2) + ife = adc_clock - ife; + } value = -16374 * ife / adc_clock; dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", __FUNCTION__, if2, ife, adc_clock, value, value & 0x3fff); diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index b314a1f2deed..1d2d28ce823d 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -564,7 +564,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, /* Allocate memory for the internal state */ state = kmalloc(sizeof(struct or51132_state), GFP_KERNEL); if (state == NULL) - goto error; + return NULL; /* Setup the state */ state->config = config; @@ -576,10 +576,6 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops or51132_ops = { diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index f02bd9445955..6a6b0d727c6f 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -529,7 +529,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, /* Allocate memory for the internal state */ state = kmalloc(sizeof(struct or51211_state), GFP_KERNEL); if (state == NULL) - goto error; + return NULL; /* Setup the state */ state->config = config; @@ -541,10 +541,6 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops or51211_ops = { diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c index 562d9208857a..819433485d3b 100644 --- a/drivers/media/dvb/frontends/s5h1409.c +++ b/drivers/media/dvb/frontends/s5h1409.c @@ -42,6 +42,7 @@ struct s5h1409_state { fe_modulation_t current_modulation; u32 current_frequency; + int if_freq; u32 is_qam_locked; u32 qam_state; @@ -97,7 +98,7 @@ static struct init_tab { { 0xac, 0x1003, }, { 0xad, 0x103f, }, { 0xe2, 0x0100, }, - { 0xe3, 0x0000, }, + { 0xe3, 0x1000, }, { 0x28, 0x1010, }, { 0xb1, 0x000e, }, }; @@ -348,28 +349,32 @@ static int s5h1409_softreset(struct dvb_frontend* fe) return 0; } +#define S5H1409_VSB_IF_FREQ 5380 +#define S5H1409_QAM_IF_FREQ state->config->qam_if + static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz) { struct s5h1409_state* state = fe->demodulator_priv; - int ret = 0; dprintk("%s(%d KHz)\n", __FUNCTION__, KHz); - if( (KHz == 44000) || (KHz == 5380) ) { - s5h1409_writereg(state, 0x87, 0x01be); - s5h1409_writereg(state, 0x88, 0x0436); - s5h1409_writereg(state, 0x89, 0x054d); - } else - if (KHz == 4000) { + switch (KHz) { + case 4000: s5h1409_writereg(state, 0x87, 0x014b); s5h1409_writereg(state, 0x88, 0x0cb5); s5h1409_writereg(state, 0x89, 0x03e2); - } else { - printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz); - ret = -1; + break; + case 5380: + case 44000: + default: + s5h1409_writereg(state, 0x87, 0x01be); + s5h1409_writereg(state, 0x88, 0x0436); + s5h1409_writereg(state, 0x89, 0x054d); + break; } + state->if_freq = KHz; - return ret; + return 0; } static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted) @@ -394,11 +399,15 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, switch(m) { case VSB_8: dprintk("%s() VSB_8\n", __FUNCTION__); + if (state->if_freq != S5H1409_VSB_IF_FREQ) + s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ); s5h1409_writereg(state, 0xf4, 0); break; case QAM_64: case QAM_256: dprintk("%s() QAM_AUTO (64/256)\n", __FUNCTION__); + if (state->if_freq != S5H1409_QAM_IF_FREQ) + s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); s5h1409_writereg(state, 0xf4, 1); s5h1409_writereg(state, 0x85, 0x110); break; @@ -432,9 +441,11 @@ static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable) dprintk("%s(%d)\n", __FUNCTION__, enable); if (enable) - return s5h1409_writereg(state, 0xe3, 0x1100); + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) | 0x1100); else - return s5h1409_writereg(state, 0xe3, 0x1000); + return s5h1409_writereg(state, 0xe3, + s5h1409_readreg(state, 0xe3) & 0xeeff); } static int s5h1409_sleep(struct dvb_frontend* fe, int enable) @@ -504,13 +515,15 @@ static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe) s5h1409_writereg(state, 0x96, 0x20); s5h1409_writereg(state, 0xad, ( ((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)) ); - s5h1409_writereg(state, 0xab, 0x1100); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xeffe); } } else { if (state->qam_state != 1) { state->qam_state = 1; s5h1409_writereg(state, 0x96, 0x08); - s5h1409_writereg(state, 0xab, 0x1101); + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x1001); } } } @@ -547,6 +560,36 @@ static int s5h1409_set_frontend (struct dvb_frontend* fe, return 0; } +static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode) +{ + struct s5h1409_state *state = fe->demodulator_priv; + u16 val; + + dprintk("%s(%d)\n", __FUNCTION__, mode); + + val = s5h1409_readreg(state, 0xac) & 0xcfff; + switch (mode) { + case S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK: + val |= 0x0000; + break; + case S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK: + dprintk("%s(%d) Mode1 or Defaulting\n", __FUNCTION__, mode); + val |= 0x1000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK: + val |= 0x2000; + break; + case S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK: + val |= 0x3000; + break; + default: + return -EINVAL; + } + + /* Configure MPEG Signal Timing charactistics */ + return s5h1409_writereg(state, 0xac, val); +} + /* Reset the demod hardware and reset all of the configuration registers to a default state. */ static int s5h1409_init (struct dvb_frontend* fe) @@ -566,13 +609,16 @@ static int s5h1409_init (struct dvb_frontend* fe) state->current_modulation = VSB_8; if (state->config->output_mode == S5H1409_SERIAL_OUTPUT) - s5h1409_writereg(state, 0xab, 0x100); /* Serial */ + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) | 0x100); /* Serial */ else - s5h1409_writereg(state, 0xab, 0x0); /* Parallel */ + s5h1409_writereg(state, 0xab, + s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */ s5h1409_set_spectralinversion(fe, state->config->inversion); - s5h1409_set_if_freq(fe, state->config->if_freq); + s5h1409_set_if_freq(fe, state->if_freq); s5h1409_set_gpio(fe, state->config->gpio); + s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing); s5h1409_softreset(fe); /* Note: Leaving the I2C gate closed. */ @@ -741,6 +787,7 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, struct i2c_adapter* i2c) { struct s5h1409_state* state = NULL; + u16 reg; /* allocate memory for the internal state */ state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL); @@ -751,9 +798,11 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, state->config = config; state->i2c = i2c; state->current_modulation = 0; + state->if_freq = S5H1409_VSB_IF_FREQ; /* check if the demod exists */ - if (s5h1409_readreg(state, 0x04) != 0x0066) + reg = s5h1409_readreg(state, 0x04); + if ((reg != 0x0066) && (reg != 0x007f)) goto error; /* create dvb_frontend */ @@ -761,8 +810,14 @@ struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; + if (s5h1409_init(&state->frontend) != 0) { + printk(KERN_ERR "%s: Failed to initialize correctly\n", + __FUNCTION__); + goto error; + } + /* Note: Leaving the I2C gate open here. */ - s5h1409_writereg(state, 0xf3, 1); + s5h1409_i2c_gate_ctrl(&state->frontend, 1); return &state->frontend; diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h index 20f9af1af445..f0bb13fe808b 100644 --- a/drivers/media/dvb/frontends/s5h1409.h +++ b/drivers/media/dvb/frontends/s5h1409.h @@ -39,8 +39,8 @@ struct s5h1409_config #define S5H1409_GPIO_ON 1 u8 gpio; - /* IF Freq in KHz */ - u16 if_freq; + /* IF Freq for QAM in KHz, VSB is hardcoded to 5380 */ + u16 qam_if; /* Spectral Inversion */ #define S5H1409_INVERSION_OFF 0 @@ -51,6 +51,13 @@ struct s5h1409_config #define S5H1409_TUNERLOCKING 0 #define S5H1409_DEMODLOCKING 1 u8 status_mode; + + /* MPEG signal timing */ +#define S5H1409_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0 +#define S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1 +#define S5H1409_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2 +#define S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3 + u16 mpeg_timing; }; #if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE)) diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c new file mode 100644 index 000000000000..cebb6b90b7e0 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-common.c @@ -0,0 +1,653 @@ +/* + tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tda18271-priv.h" + +static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) +{ + struct tda18271_priv *priv = fe->tuner_priv; + enum tda18271_i2c_gate gate; + int ret = 0; + + switch (priv->gate) { + case TDA18271_GATE_DIGITAL: + case TDA18271_GATE_ANALOG: + gate = priv->gate; + break; + case TDA18271_GATE_AUTO: + default: + switch (priv->mode) { + case TDA18271_DIGITAL: + gate = TDA18271_GATE_DIGITAL; + break; + case TDA18271_ANALOG: + default: + gate = TDA18271_GATE_ANALOG; + break; + } + } + + switch (gate) { + case TDA18271_GATE_ANALOG: + if (fe->ops.analog_ops.i2c_gate_ctrl) + ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); + break; + case TDA18271_GATE_DIGITAL: + if (fe->ops.i2c_gate_ctrl) + ret = fe->ops.i2c_gate_ctrl(fe, enable); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +}; + +/*---------------------------------------------------------------------*/ + +static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_reg("=== TDA18271 REG DUMP ===\n"); + tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); + tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); + tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); + tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); + tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); + tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); + tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); + tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); + tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); + tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); + tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); + tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); + tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); + tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); + tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); + tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); + + /* only dump extended regs if DBG_ADV is set */ + if (!(tda18271_debug & DBG_ADV)) + return; + + /* W indicates write-only registers. + * Register dump for write-only registers shows last value written. */ + + tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); + tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); + tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); + tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); + tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); + tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); + tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); + tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); + tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); + tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); + tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); + tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); + tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); + tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); + tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); + tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); + tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); + tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); + tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); + tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); + tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); + tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); + tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); +} + +int tda18271_read_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf = 0x00; + int ret; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regs, .len = 16 } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 0); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_read_extended(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char regdump[TDA18271_NUM_REGS]; + unsigned char buf = 0x00; + int ret, i; + struct i2c_msg msg[] = { + { .addr = priv->i2c_addr, .flags = 0, + .buf = &buf, .len = 1 }, + { .addr = priv->i2c_addr, .flags = I2C_M_RD, + .buf = regdump, .len = TDA18271_NUM_REGS } + }; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* read all registers */ + ret = i2c_transfer(priv->i2c_adap, msg, 2); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 2) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + for (i = 0; i <= TDA18271_NUM_REGS; i++) { + /* don't update write-only registers */ + if ((i != R_EB9) && + (i != R_EB16) && + (i != R_EB17) && + (i != R_EB19) && + (i != R_EB20)) + regs[i] = regdump[i]; + } + + if (tda18271_debug & DBG_REG) + tda18271_dump_regs(fe, 1); + + return (ret == 2 ? 0 : ret); +} + +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + unsigned char buf[TDA18271_NUM_REGS + 1]; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = len + 1 }; + int i, ret; + + BUG_ON((len == 0) || (idx + len > sizeof(buf))); + + buf[0] = idx; + for (i = 1; i <= len; i++) + buf[i] = regs[idx - 1 + i]; + + tda18271_i2c_gate_ctrl(fe, 1); + + /* write registers */ + ret = i2c_transfer(priv->i2c_adap, &msg, 1); + + tda18271_i2c_gate_ctrl(fe, 0); + + if (ret != 1) + tda_err("ERROR: i2c_transfer returned: %d\n", ret); + + return (ret == 1 ? 0 : ret); +} + +/*---------------------------------------------------------------------*/ + +int tda18271_init_regs(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_dbg("initializing registers for device @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), priv->i2c_addr); + + /* initialize registers */ + switch (priv->id) { + case TDA18271HDC1: + regs[R_ID] = 0x83; + break; + case TDA18271HDC2: + regs[R_ID] = 0x84; + break; + }; + + regs[R_TM] = 0x08; + regs[R_PL] = 0x80; + regs[R_EP1] = 0xc6; + regs[R_EP2] = 0xdf; + regs[R_EP3] = 0x16; + regs[R_EP4] = 0x60; + regs[R_EP5] = 0x80; + regs[R_CPD] = 0x80; + regs[R_CD1] = 0x00; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0x00; + regs[R_MD1] = 0x00; + regs[R_MD2] = 0x00; + regs[R_MD3] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB1] = 0xff; + break; + case TDA18271HDC2: + regs[R_EB1] = 0xfc; + break; + }; + + regs[R_EB2] = 0x01; + regs[R_EB3] = 0x84; + regs[R_EB4] = 0x41; + regs[R_EB5] = 0x01; + regs[R_EB6] = 0x84; + regs[R_EB7] = 0x40; + regs[R_EB8] = 0x07; + regs[R_EB9] = 0x00; + regs[R_EB10] = 0x00; + regs[R_EB11] = 0x96; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB12] = 0x0f; + break; + case TDA18271HDC2: + regs[R_EB12] = 0x33; + break; + }; + + regs[R_EB13] = 0xc1; + regs[R_EB14] = 0x00; + regs[R_EB15] = 0x8f; + regs[R_EB16] = 0x00; + regs[R_EB17] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB18] = 0x00; + break; + case TDA18271HDC2: + regs[R_EB18] = 0x8c; + break; + }; + + regs[R_EB19] = 0x00; + regs[R_EB20] = 0x20; + + switch (priv->id) { + case TDA18271HDC1: + regs[R_EB21] = 0x33; + break; + case TDA18271HDC2: + regs[R_EB21] = 0xb3; + break; + }; + + regs[R_EB22] = 0x48; + regs[R_EB23] = 0xb0; + + tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + + /* setup agc1 gain */ + regs[R_EB17] = 0x00; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x03; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x43; + tda18271_write_regs(fe, R_EB17, 1); + regs[R_EB17] = 0x4c; + tda18271_write_regs(fe, R_EB17, 1); + + /* setup agc2 gain */ + if ((priv->id) == TDA18271HDC1) { + regs[R_EB20] = 0xa0; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xa7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xe7; + tda18271_write_regs(fe, R_EB20, 1); + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + } + + /* image rejection calibration */ + + /* low-band */ + regs[R_EP3] = 0x1f; + regs[R_EP4] = 0x66; + regs[R_EP5] = 0x81; + regs[R_CPD] = 0xcc; + regs[R_CD1] = 0x6c; + regs[R_CD2] = 0x00; + regs[R_CD3] = 0x00; + regs[R_MPD] = 0xcd; + regs[R_MD1] = 0x77; + regs[R_MD2] = 0x08; + regs[R_MD3] = 0x00; + + switch (priv->id) { + case TDA18271HDC1: + tda18271_write_regs(fe, R_EP3, 11); + break; + case TDA18271HDC2: + tda18271_write_regs(fe, R_EP3, 12); + break; + }; + + if ((priv->id) == TDA18271HDC2) { + /* main pll cp source on */ + regs[R_EB4] = 0x61; + tda18271_write_regs(fe, R_EB4, 1); + msleep(1); + + /* main pll cp source off */ + regs[R_EB4] = 0x41; + tda18271_write_regs(fe, R_EB4, 1); + } + + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted low measurement */ + + regs[R_EP5] = 0x85; + regs[R_CPD] = 0xcb; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0x70; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image low optimization completion */ + + /* mid-band */ + regs[R_EP5] = 0x82; + regs[R_CPD] = 0xa8; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0xa9; + regs[R_MD1] = 0x73; + regs[R_MD2] = 0x1a; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted mid measurement */ + + regs[R_EP5] = 0x86; + regs[R_CPD] = 0xa8; + regs[R_CD1] = 0x66; + regs[R_CD2] = 0xa0; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image mid optimization completion */ + + /* high-band */ + regs[R_EP5] = 0x83; + regs[R_CPD] = 0x98; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x00; + regs[R_MPD] = 0x99; + regs[R_MD1] = 0x71; + regs[R_MD2] = 0xcd; + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* pll locking */ + + /* launch detector */ + tda18271_write_regs(fe, R_EP1, 1); + msleep(5); /* wanted high measurement */ + + regs[R_EP5] = 0x87; + regs[R_CD1] = 0x65; + regs[R_CD2] = 0x50; + + tda18271_write_regs(fe, R_EP3, 7); + msleep(5); /* pll locking */ + + /* launch optimization algorithm */ + tda18271_write_regs(fe, R_EP2, 1); + msleep(30); /* image high optimization completion */ + + /* return to normal mode */ + regs[R_EP4] = 0x64; + tda18271_write_regs(fe, R_EP4, 1); + + /* synchronize */ + tda18271_write_regs(fe, R_EP1, 1); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +/* + * Standby modes, EP3 [7:5] + * + * | SM || SM_LT || SM_XT || mode description + * |=====\\=======\\=======\\=================================== + * | 0 || 0 || 0 || normal mode + * |-----||-------||-------||----------------------------------- + * | || || || standby mode w/ slave tuner output + * | 1 || 0 || 0 || & loop thru & xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 0 || standby mode w/ xtal oscillator on + * |-----||-------||-------||----------------------------------- + * | 1 || 1 || 1 || power off + * + */ + +int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); + + regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ + regs[R_EP3] |= sm ? (1 << 7) : 0 | + sm_lt ? (1 << 6) : 0 | + sm_xt ? (1 << 5) : 0; + + tda18271_write_regs(fe, R_EP3, 1); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets main post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); + if (ret < 0) + goto fail; + + regs[R_MPD] = (0x77 & pd); + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x08; + break; + case TDA18271_DIGITAL: + regs[R_MPD] |= 0x08; + break; + } + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_MD1] = 0x7f & (div >> 16); + regs[R_MD2] = 0xff & (div >> 8); + regs[R_MD3] = 0xff & div; +fail: + return ret; +} + +int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) +{ + /* sets cal post divider & divider bytes, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 d, pd; + u32 div; + + int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); + if (ret < 0) + goto fail; + + regs[R_CPD] = pd; + + div = ((d * (freq / 1000)) << 7) / 125; + + regs[R_CD1] = 0x7f & (div >> 16); + regs[R_CD2] = 0xff & (div >> 8); + regs[R_CD3] = 0xff & div; +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) +{ + /* sets bp filter bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP1] &= ~0x07; /* clear bp filter bits */ + regs[R_EP1] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) +{ + /* sets K & M bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EB13] &= ~0x7c; /* clear k & m bits */ + regs[R_EB13] |= (0x7c & val); +fail: + return ret; +} + +int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf band bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP2] &= ~0xe0; /* clear rf band bits */ + regs[R_EP2] |= (0xe0 & (val << 5)); +fail: + return ret; +} + +int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) +{ + /* sets gain taper bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ + regs[R_EP2] |= (0x1f & val); +fail: + return ret; +} + +int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) +{ + /* sets IR Meas bits, but does not write them */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); + if (ret < 0) + goto fail; + + regs[R_EP5] &= ~0x07; + regs[R_EP5] |= (0x07 & val); +fail: + return ret; +} + +int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) +{ + /* sets rf cal byte (RFC_Cprog), but does not write it */ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u8 val; + + tda18271_lookup_map(fe, RF_CAL, freq, &val); + + regs[R_EB14] = val; + + return 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c new file mode 100644 index 000000000000..dfe72aaec380 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-fe.c @@ -0,0 +1,1225 @@ +/* + tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <linux/delay.h> +#include <linux/videodev2.h> +#include "tda18271-priv.h" + +int tda18271_debug; +module_param_named(debug, tda18271_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level " + "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); + +static int tda18271_cal_on_startup; +module_param_named(cal, tda18271_cal_on_startup, int, 0644); +MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); + +static LIST_HEAD(tda18271_list); +static DEFINE_MUTEX(tda18271_list_mutex); + +/*---------------------------------------------------------------------*/ + +static int tda18271_ir_cal_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + tda18271_read_regs(fe); + + /* test IR_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x08) == 0) + tda18271_init_regs(fe); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_channel_configuration(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std, + int radio) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N; + + /* update TV broadcast parameters */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= std; + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level & IF notch frequency */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_EP4] |= 0x04; /* IF level = 1 */ + regs[R_MPD] |= 0x80; /* IF notch = 1 */ + break; + } + + if (radio) + regs[R_EP4] |= 0x80; + else + regs[R_EP4] &= ~0x80; + + /* update RF_TOP / IF_TOP */ + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_EB22] = 0x2c; + break; + case TDA18271_DIGITAL: + regs[R_EB22] = 0x37; + break; + } + tda18271_write_regs(fe, R_EB22, 1); + + /* --------------------------------------------------------------- */ + + /* disable Power Level Indicator */ + regs[R_EP1] |= 0x40; + + /* frequency dependent parameters */ + + tda18271_calc_ir_measure(fe, &freq); + + tda18271_calc_bp_filter(fe, &freq); + + tda18271_calc_rf_band(fe, &freq); + + tda18271_calc_gain_taper(fe, &freq); + + /* --------------------------------------------------------------- */ + + /* dual tuner and agc1 extra configuration */ + + /* main vco when Master, cal vco when slave */ + regs[R_EB1] |= 0x04; /* FIXME: assumes master */ + + /* agc1 always active */ + regs[R_EB1] &= ~0x02; + + /* agc1 has priority on agc2 */ + regs[R_EB1] &= ~0x01; + + tda18271_write_regs(fe, R_EB1, 1); + + /* --------------------------------------------------------------- */ + + N = freq + ifc; + + /* FIXME: assumes master */ + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + tda18271_write_regs(fe, R_TM, 7); + + /* main pll charge pump source */ + regs[R_EB4] |= 0x20; + tda18271_write_regs(fe, R_EB4, 1); + + msleep(1); + + /* normal operation for the main pll */ + regs[R_EB4] &= ~0x20; + tda18271_write_regs(fe, R_EB4, 1); + + msleep(5); + + return 0; +} + +static int tda18271_read_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int tm; + + /* switch thermometer on */ + regs[R_TM] |= 0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* read thermometer info */ + tda18271_read_regs(fe); + + if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || + (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { + + if ((regs[R_TM] & 0x20) == 0x20) + regs[R_TM] &= ~0x20; + else + regs[R_TM] |= 0x20; + + tda18271_write_regs(fe, R_TM, 1); + + msleep(10); /* temperature sensing */ + + /* read thermometer info */ + tda18271_read_regs(fe); + } + + tm = tda18271_lookup_thermometer(fe); + + /* switch thermometer off */ + regs[R_TM] &= ~0x10; + tda18271_write_regs(fe, R_TM, 1); + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + return tm; +} + +static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe, + u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int tm_current, rfcal_comp, approx, i; + u8 dc_over_dt, rf_tab; + + /* power up */ + tda18271_set_standby_mode(fe, 0, 0, 0); + + /* read die current temperature */ + tm_current = tda18271_read_thermometer(fe); + + /* frequency dependent parameters */ + + tda18271_calc_rf_cal(fe, &freq); + rf_tab = regs[R_EB14]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + if (i < 0) + return -EINVAL; + + if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { + approx = map[i].rf_a1 * + (freq / 1000 - map[i].rf1) + map[i].rf_b1 + rf_tab; + } else { + approx = map[i].rf_a2 * + (freq / 1000 - map[i].rf2) + map[i].rf_b2 + rf_tab; + } + + if (approx < 0) + approx = 0; + if (approx > 255) + approx = 255; + + tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); + + /* calculate temperature compensation */ + rfcal_comp = dc_over_dt * (tm_current - priv->tm_rfcal); + + regs[R_EB14] = approx + rfcal_comp; + tda18271_write_regs(fe, R_EB14, 1); + + return 0; +} + +static int tda18271_por(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + /* power up detector 1 */ + regs[R_EB12] &= ~0x20; + tda18271_write_regs(fe, R_EB12, 1); + + regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ + + /* POR mode */ + tda18271_set_standby_mode(fe, 1, 0, 0); + + /* disable 1.5 MHz low pass filter */ + regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ + regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ + tda18271_write_regs(fe, R_EB21, 3); + + return 0; +} + +static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N; + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + tda18271_write_regs(fe, R_EP4, 1); + + /* switch off agc1 */ + regs[R_EP3] |= 0x40; /* sm_lt = 1 */ + + regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + /* frequency dependent parameters */ + + tda18271_calc_bp_filter(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_km(fe, &freq); + + tda18271_write_regs(fe, R_EP1, 3); + tda18271_write_regs(fe, R_EB13, 1); + + /* main pll charge pump source */ + regs[R_EB4] |= 0x20; + tda18271_write_regs(fe, R_EB4, 1); + + /* cal pll charge pump source */ + regs[R_EB7] |= 0x20; + tda18271_write_regs(fe, R_EB7, 1); + + /* force dcdc converter to 0 V */ + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + /* disable plls lock */ + regs[R_EB20] &= ~0x20; + tda18271_write_regs(fe, R_EB20, 1); + + /* set CAL mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + tda18271_write_regs(fe, R_EP4, 2); + + /* --------------------------------------------------------------- */ + + /* set the internal calibration signal */ + N = freq; + + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + /* downconvert internal calibration */ + N += 1000000; + + tda18271_calc_main_pll(fe, N); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + /* --------------------------------------------------------------- */ + + /* normal operation for the main pll */ + regs[R_EB4] &= ~0x20; + tda18271_write_regs(fe, R_EB4, 1); + + /* normal operation for the cal pll */ + regs[R_EB7] &= ~0x20; + tda18271_write_regs(fe, R_EB7, 1); + + msleep(5); /* plls locking */ + + /* launch the rf tracking filters calibration */ + regs[R_EB20] |= 0x20; + tda18271_write_regs(fe, R_EB20, 1); + + msleep(60); /* calibration */ + + /* --------------------------------------------------------------- */ + + /* set CAL mode to normal */ + regs[R_EP4] &= ~0x03; + + /* switch on agc1 */ + regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + tda18271_write_regs(fe, R_EP3, 2); + + /* synchronization */ + tda18271_write_regs(fe, R_EP1, 1); + + /* get calibration result */ + tda18271_read_extended(fe); + + return regs[R_EB14]; +} + +static int tda18271_powerscan(struct dvb_frontend *fe, + u32 *freq_in, u32 *freq_out) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int sgn, bcal, count, wait; + u8 cid_target; + u16 count_limit; + u32 freq; + + freq = *freq_in; + + tda18271_calc_rf_band(fe, &freq); + tda18271_calc_rf_cal(fe, &freq); + tda18271_calc_gain_taper(fe, &freq); + tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EB14, 1); + + /* downconvert frequency */ + freq += 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + msleep(5); /* pll locking */ + + /* detection mode */ + regs[R_EP4] &= ~0x03; + regs[R_EP4] |= 0x01; + tda18271_write_regs(fe, R_EP4, 1); + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + tda18271_read_extended(fe); + + /* algorithm initialization */ + sgn = 1; + *freq_out = *freq_in; + bcal = 0; + count = 0; + wait = false; + + while ((regs[R_EB10] & 0x3f) < cid_target) { + /* downconvert updated freq to 1 MHz */ + freq = *freq_in + (sgn * count) + 1000000; + + tda18271_calc_main_pll(fe, freq); + tda18271_write_regs(fe, R_MPD, 4); + + if (wait) { + msleep(5); /* pll locking */ + wait = false; + } else + udelay(100); /* pll locking */ + + /* launch power detection measurement */ + tda18271_write_regs(fe, R_EP2, 1); + + /* read power detection info, stored in EB10 */ + tda18271_read_extended(fe); + + count += 200; + + if (count < count_limit) + continue; + + if (sgn <= 0) + break; + + sgn = -1 * sgn; + count = 200; + wait = true; + } + + if ((regs[R_EB10] & 0x3f) >= cid_target) { + bcal = 1; + *freq_out = freq - 1000000; + } else + bcal = 0; + + tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", + bcal, *freq_in, *freq_out, freq); + + return bcal; +} + +static int tda18271_powerscan_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + /* set standard to digital */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + regs[R_EP3] |= 0x12; + + /* set cal mode to normal */ + regs[R_EP4] &= ~0x03; + + /* update IF output level & IF notch frequency */ + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + + tda18271_write_regs(fe, R_EP3, 2); + + regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ + tda18271_write_regs(fe, R_EB18, 1); + + regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ + + /* 1.5 MHz low pass filter */ + regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ + regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ + + tda18271_write_regs(fe, R_EB21, 3); + + return 0; +} + +static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + unsigned char *regs = priv->tda18271_regs; + int bcal, rf, i; +#define RF1 0 +#define RF2 1 +#define RF3 2 + u32 rf_default[3]; + u32 rf_freq[3]; + u8 prog_cal[3]; + u8 prog_tab[3]; + + i = tda18271_lookup_rf_band(fe, &freq, NULL); + + if (i < 0) + return i; + + rf_default[RF1] = 1000 * map[i].rf1_def; + rf_default[RF2] = 1000 * map[i].rf2_def; + rf_default[RF3] = 1000 * map[i].rf3_def; + + for (rf = RF1; rf <= RF3; rf++) { + if (0 == rf_default[rf]) + return 0; + tda_cal("freq = %d, rf = %d\n", freq, rf); + + /* look for optimized calibration frequency */ + bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); + + tda18271_calc_rf_cal(fe, &rf_freq[rf]); + prog_tab[rf] = regs[R_EB14]; + + if (1 == bcal) + prog_cal[rf] = tda18271_calibrate_rf(fe, rf_freq[rf]); + else + prog_cal[rf] = prog_tab[rf]; + + switch (rf) { + case RF1: + map[i].rf_a1 = 0; + map[i].rf_b1 = prog_cal[RF1] - prog_tab[RF1]; + map[i].rf1 = rf_freq[RF1] / 1000; + break; + case RF2: + map[i].rf_a1 = (prog_cal[RF2] - prog_tab[RF2] - + prog_cal[RF1] + prog_tab[RF1]) / + ((rf_freq[RF2] - rf_freq[RF1]) / 1000); + map[i].rf2 = rf_freq[RF2] / 1000; + break; + case RF3: + map[i].rf_a2 = (prog_cal[RF3] - prog_tab[RF3] - + prog_cal[RF2] + prog_tab[RF2]) / + ((rf_freq[RF3] - rf_freq[RF2]) / 1000); + map[i].rf_b2 = prog_cal[RF2] - prog_tab[RF2]; + map[i].rf3 = rf_freq[RF3] / 1000; + break; + default: + BUG(); + } + } + + return 0; +} + +static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned int i; + + tda_info("tda18271: performing RF tracking filter calibration\n"); + + /* wait for die temperature stabilization */ + msleep(200); + + tda18271_powerscan_init(fe); + + /* rf band calibration */ + for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) + tda18271_rf_tracking_filters_init(fe, 1000 * + priv->rf_cal_state[i].rfmax); + + priv->tm_rfcal = tda18271_read_thermometer(fe); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_rf_cal_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + + /* test RF_CAL_OK to see if we need init */ + if ((regs[R_EP1] & 0x10) == 0) + priv->cal_initialized = false; + + if (priv->cal_initialized) + return 0; + + tda18271_calc_rf_filter_curve(fe); + + tda18271_por(fe); + + tda_info("tda18271: RF tracking filter calibration complete\n"); + + priv->cal_initialized = true; + + return 0; +} + +static int tda18271_init(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&priv->lock); + + /* power up */ + tda18271_set_standby_mode(fe, 0, 0, 0); + + /* initialization */ + tda18271_ir_cal_init(fe); + + if (priv->id == TDA18271HDC2) + tda18271_rf_cal_init(fe); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int tda18271c2_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std, int radio) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + tda_dbg("freq = %d, ifc = %d\n", freq, ifc); + + tda18271_init(fe); + + mutex_lock(&priv->lock); + + tda18271_rf_tracking_filters_correction(fe, freq); + + tda18271_channel_configuration(fe, ifc, freq, bw, std, radio); + + mutex_unlock(&priv->lock); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271c1_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std, int radio) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + u32 N = 0; + + tda18271_init(fe); + + mutex_lock(&priv->lock); + + tda_dbg("freq = %d, ifc = %d\n", freq, ifc); + + /* RF tracking filter calibration */ + + /* calculate bp filter */ + tda18271_calc_bp_filter(fe, &freq); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x60; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x60; + tda18271_write_regs(fe, R_EB7, 1); + + regs[R_EB14] = 0x00; + tda18271_write_regs(fe, R_EB14, 1); + + regs[R_EB20] = 0xcc; + tda18271_write_regs(fe, R_EB20, 1); + + /* set cal mode to RF tracking filter calibration */ + regs[R_EP4] |= 0x03; + + /* calculate cal pll */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 1250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2; + break; + } + + tda18271_calc_cal_pll(fe, N); + + /* calculate main pll */ + + switch (priv->mode) { + case TDA18271_ANALOG: + N = freq - 250000; + break; + case TDA18271_DIGITAL: + N = freq + bw / 2 + 1000000; + break; + } + + tda18271_calc_main_pll(fe, N); + + tda18271_write_regs(fe, R_EP3, 11); + msleep(5); /* RF tracking filter calibration initialization */ + + /* search for K,M,CO for RF calibration */ + tda18271_calc_km(fe, &freq); + tda18271_write_regs(fe, R_EB13, 1); + + /* search for rf band */ + tda18271_calc_rf_band(fe, &freq); + + /* search for gain taper */ + tda18271_calc_gain_taper(fe, &freq); + + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + tda18271_write_regs(fe, R_EP2, 1); + tda18271_write_regs(fe, R_EP1, 1); + + regs[R_EB4] &= 0x07; + regs[R_EB4] |= 0x40; + tda18271_write_regs(fe, R_EB4, 1); + + regs[R_EB7] = 0x40; + tda18271_write_regs(fe, R_EB7, 1); + msleep(10); + + regs[R_EB20] = 0xec; + tda18271_write_regs(fe, R_EB20, 1); + msleep(60); /* RF tracking filter calibration completion */ + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + tda18271_write_regs(fe, R_EP4, 1); + + tda18271_write_regs(fe, R_EP1, 1); + + /* RF tracking filter correction for VHF_Low band */ + if (0 == tda18271_calc_rf_cal(fe, &freq)) + tda18271_write_regs(fe, R_EB14, 1); + + /* Channel Configuration */ + + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_EB22] = 0x2c; + break; + case TDA18271_DIGITAL: + regs[R_EB22] = 0x37; + break; + } + tda18271_write_regs(fe, R_EB22, 1); + + regs[R_EP1] |= 0x40; /* set dis power level on */ + + /* set standard */ + regs[R_EP3] &= ~0x1f; /* clear std bits */ + + /* see table 22 */ + regs[R_EP3] |= std; + + regs[R_EP4] &= ~0x03; /* set cal mode to normal */ + + regs[R_EP4] &= ~0x1c; /* clear if level bits */ + switch (priv->mode) { + case TDA18271_ANALOG: + regs[R_MPD] &= ~0x80; /* IF notch = 0 */ + break; + case TDA18271_DIGITAL: + regs[R_EP4] |= 0x04; + regs[R_MPD] |= 0x80; + break; + } + + if (radio) + regs[R_EP4] |= 0x80; + else + regs[R_EP4] &= ~0x80; + + /* image rejection validity */ + tda18271_calc_ir_measure(fe, &freq); + + /* calculate MAIN PLL */ + N = freq + ifc; + + tda18271_calc_main_pll(fe, N); + + tda18271_write_regs(fe, R_TM, 15); + msleep(5); + mutex_unlock(&priv->lock); + + return 0; +} + +static inline int tda18271_tune(struct dvb_frontend *fe, + u32 ifc, u32 freq, u32 bw, u8 std, int radio) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = -EINVAL; + + switch (priv->id) { + case TDA18271HDC1: + ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio); + break; + case TDA18271HDC2: + ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio); + break; + } + return ret; +} + +/* ------------------------------------------------------------------ */ + +static int tda18271_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = &priv->std; + int ret; + u8 std; + u16 sgIF; + u32 bw, freq = params->frequency; + + priv->mode = TDA18271_DIGITAL; + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + std = std_map->atsc_6.std_bits; + sgIF = std_map->atsc_6.if_freq; + break; + case QAM_64: + case QAM_256: + std = std_map->qam_6.std_bits; + sgIF = std_map->qam_6.if_freq; + break; + default: + tda_warn("modulation not set!\n"); + return -EINVAL; + } +#if 0 + /* userspace request is already center adjusted */ + freq += 1750000; /* Adjust to center (+1.75MHZ) */ +#endif + bw = 6000000; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + bw = 6000000; + std = std_map->dvbt_6.std_bits; + sgIF = std_map->dvbt_6.if_freq; + break; + case BANDWIDTH_7_MHZ: + bw = 7000000; + std = std_map->dvbt_7.std_bits; + sgIF = std_map->dvbt_7.if_freq; + break; + case BANDWIDTH_8_MHZ: + bw = 8000000; + std = std_map->dvbt_8.std_bits; + sgIF = std_map->dvbt_8.if_freq; + break; + default: + tda_warn("bandwidth not set!\n"); + return -EINVAL; + } + } else { + tda_warn("modulation type not supported!\n"); + return -EINVAL; + } + + /* When tuning digital, the analog demod must be tri-stated */ + if (fe->ops.analog_ops.standby) + fe->ops.analog_ops.standby(fe); + + ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0); + + if (ret < 0) + goto fail; + + priv->frequency = freq; + priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + return ret; +} + +static int tda18271_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std_map = &priv->std; + char *mode; + int ret, radio = 0; + u8 std; + u16 sgIF; + u32 freq = params->frequency * 62500; + + priv->mode = TDA18271_ANALOG; + + if (params->mode == V4L2_TUNER_RADIO) { + radio = 1; + freq = freq / 1000; + std = std_map->fm_radio.std_bits; + sgIF = std_map->fm_radio.if_freq; + mode = "fm"; + } else if (params->std & V4L2_STD_MN) { + std = std_map->atv_mn.std_bits; + sgIF = std_map->atv_mn.if_freq; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + std = std_map->atv_b.std_bits; + sgIF = std_map->atv_b.if_freq; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + std = std_map->atv_gh.std_bits; + sgIF = std_map->atv_gh.if_freq; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + std = std_map->atv_i.std_bits; + sgIF = std_map->atv_i.if_freq; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + std = std_map->atv_dk.std_bits; + sgIF = std_map->atv_dk.if_freq; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + std = std_map->atv_l.std_bits; + sgIF = std_map->atv_l.if_freq; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + std = std_map->atv_lc.std_bits; + sgIF = std_map->atv_lc.if_freq; + mode = "L'"; + } else { + std = std_map->atv_i.std_bits; + sgIF = std_map->atv_i.if_freq; + mode = "xx"; + } + + tda_dbg("setting tda18271 to system %s\n", mode); + + ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio); + + if (ret < 0) + goto fail; + + priv->frequency = freq; + priv->bandwidth = 0; +fail: + return ret; +} + +static int tda18271_sleep(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&priv->lock); + + /* standby mode w/ slave tuner output + * & loop thru & xtal oscillator on */ + tda18271_set_standby_mode(fe, 1, 0, 0); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int tda18271_release(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + + mutex_lock(&tda18271_list_mutex); + + priv->count--; + + if (!priv->count) { + tda_dbg("destroying instance @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), + priv->i2c_addr); + list_del(&priv->tda18271_list); + + kfree(priv); + } + mutex_unlock(&tda18271_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct tda18271_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +/* ------------------------------------------------------------------ */ + +#define tda18271_update_std(std_cfg, name) do { \ + if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) { \ + tda_dbg("Using custom std config for %s\n", name); \ + memcpy(&std->std_cfg, &map->std_cfg, \ + sizeof(struct tda18271_std_map_item)); \ + } } while (0) + +#define tda18271_dump_std_item(std_cfg, name) do { \ + tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n", \ + name, std->std_cfg.if_freq, std->std_cfg.std_bits); \ + } while (0) + +static int tda18271_dump_std_map(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); + tda18271_dump_std_item(fm_radio, "fm"); + tda18271_dump_std_item(atv_b, "pal b"); + tda18271_dump_std_item(atv_dk, "pal dk"); + tda18271_dump_std_item(atv_gh, "pal gh"); + tda18271_dump_std_item(atv_i, "pal i"); + tda18271_dump_std_item(atv_l, "pal l"); + tda18271_dump_std_item(atv_lc, "pal l'"); + tda18271_dump_std_item(atv_mn, "atv mn"); + tda18271_dump_std_item(atsc_6, "atsc 6"); + tda18271_dump_std_item(dvbt_6, "dvbt 6"); + tda18271_dump_std_item(dvbt_7, "dvbt 7"); + tda18271_dump_std_item(dvbt_8, "dvbt 8"); + tda18271_dump_std_item(qam_6, "qam 6"); + tda18271_dump_std_item(qam_8, "qam 8"); + + return 0; +} + +static int tda18271_update_std_map(struct dvb_frontend *fe, + struct tda18271_std_map *map) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_std_map *std = &priv->std; + + if (!map) + return -EINVAL; + + tda18271_update_std(fm_radio, "fm"); + tda18271_update_std(atv_b, "atv b"); + tda18271_update_std(atv_dk, "atv dk"); + tda18271_update_std(atv_gh, "atv gh"); + tda18271_update_std(atv_i, "atv i"); + tda18271_update_std(atv_l, "atv l"); + tda18271_update_std(atv_lc, "atv l'"); + tda18271_update_std(atv_mn, "atv mn"); + tda18271_update_std(atsc_6, "atsc 6"); + tda18271_update_std(dvbt_6, "dvbt 6"); + tda18271_update_std(dvbt_7, "dvbt 7"); + tda18271_update_std(dvbt_8, "dvbt 8"); + tda18271_update_std(qam_6, "qam 6"); + tda18271_update_std(qam_8, "qam 8"); + + return 0; +} + +static int tda18271_get_id(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + char *name; + int ret = 0; + + mutex_lock(&priv->lock); + tda18271_read_regs(fe); + mutex_unlock(&priv->lock); + + switch (regs[R_ID] & 0x7f) { + case 3: + name = "TDA18271HD/C1"; + priv->id = TDA18271HDC1; + break; + case 4: + name = "TDA18271HD/C2"; + priv->id = TDA18271HDC2; + break; + default: + name = "Unknown device"; + ret = -EINVAL; + break; + } + + tda_info("%s detected @ %d-%04x%s\n", name, + i2c_adapter_id(priv->i2c_adap), priv->i2c_addr, + (0 == ret) ? "" : ", device not supported."); + + return ret; +} + +static struct dvb_tuner_ops tda18271_tuner_ops = { + .info = { + .name = "NXP TDA18271HD", + .frequency_min = 45000000, + .frequency_max = 864000000, + .frequency_step = 62500 + }, + .init = tda18271_init, + .sleep = tda18271_sleep, + .set_params = tda18271_set_params, + .set_analog_params = tda18271_set_analog_params, + .release = tda18271_release, + .get_frequency = tda18271_get_frequency, + .get_bandwidth = tda18271_get_bandwidth, +}; + +struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg) +{ + struct tda18271_priv *priv = NULL; + int state_found = 0; + + mutex_lock(&tda18271_list_mutex); + + list_for_each_entry(priv, &tda18271_list, tda18271_list) { + if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) && + (priv->i2c_addr == addr)) { + tda_dbg("attaching existing tuner @ %d-%04x\n", + i2c_adapter_id(priv->i2c_adap), + priv->i2c_addr); + priv->count++; + fe->tuner_priv = priv; + state_found = 1; + /* allow dvb driver to override i2c gate setting */ + if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG)) + priv->gate = cfg->gate; + break; + } + } + if (state_found == 0) { + tda_dbg("creating new tuner instance @ %d-%04x\n", + i2c_adapter_id(i2c), addr); + + priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL); + if (priv == NULL) { + mutex_unlock(&tda18271_list_mutex); + return NULL; + } + + priv->i2c_addr = addr; + priv->i2c_adap = i2c; + priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; + priv->cal_initialized = false; + mutex_init(&priv->lock); + priv->count++; + + fe->tuner_priv = priv; + + list_add_tail(&priv->tda18271_list, &tda18271_list); + + if (tda18271_get_id(fe) < 0) + goto fail; + + if (tda18271_assign_map_layout(fe) < 0) + goto fail; + + mutex_lock(&priv->lock); + tda18271_init_regs(fe); + + if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2)) + tda18271_rf_cal_init(fe); + + mutex_unlock(&priv->lock); + } + + /* override default std map with values in config struct */ + if ((cfg) && (cfg->std_map)) + tda18271_update_std_map(fe, cfg->std_map); + + mutex_unlock(&tda18271_list_mutex); + + memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (tda18271_debug & DBG_MAP) + tda18271_dump_std_map(fe); + + return fe; +fail: + mutex_unlock(&tda18271_list_mutex); + + tda18271_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(tda18271_attach); +MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h new file mode 100644 index 000000000000..7b939a5325fb --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-priv.h @@ -0,0 +1,212 @@ +/* + tda18271-priv.h - private header for the NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_PRIV_H__ +#define __TDA18271_PRIV_H__ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include "tda18271.h" + +#define R_ID 0x00 /* ID byte */ +#define R_TM 0x01 /* Thermo byte */ +#define R_PL 0x02 /* Power level byte */ +#define R_EP1 0x03 /* Easy Prog byte 1 */ +#define R_EP2 0x04 /* Easy Prog byte 2 */ +#define R_EP3 0x05 /* Easy Prog byte 3 */ +#define R_EP4 0x06 /* Easy Prog byte 4 */ +#define R_EP5 0x07 /* Easy Prog byte 5 */ +#define R_CPD 0x08 /* Cal Post-Divider byte */ +#define R_CD1 0x09 /* Cal Divider byte 1 */ +#define R_CD2 0x0a /* Cal Divider byte 2 */ +#define R_CD3 0x0b /* Cal Divider byte 3 */ +#define R_MPD 0x0c /* Main Post-Divider byte */ +#define R_MD1 0x0d /* Main Divider byte 1 */ +#define R_MD2 0x0e /* Main Divider byte 2 */ +#define R_MD3 0x0f /* Main Divider byte 3 */ +#define R_EB1 0x10 /* Extended byte 1 */ +#define R_EB2 0x11 /* Extended byte 2 */ +#define R_EB3 0x12 /* Extended byte 3 */ +#define R_EB4 0x13 /* Extended byte 4 */ +#define R_EB5 0x14 /* Extended byte 5 */ +#define R_EB6 0x15 /* Extended byte 6 */ +#define R_EB7 0x16 /* Extended byte 7 */ +#define R_EB8 0x17 /* Extended byte 8 */ +#define R_EB9 0x18 /* Extended byte 9 */ +#define R_EB10 0x19 /* Extended byte 10 */ +#define R_EB11 0x1a /* Extended byte 11 */ +#define R_EB12 0x1b /* Extended byte 12 */ +#define R_EB13 0x1c /* Extended byte 13 */ +#define R_EB14 0x1d /* Extended byte 14 */ +#define R_EB15 0x1e /* Extended byte 15 */ +#define R_EB16 0x1f /* Extended byte 16 */ +#define R_EB17 0x20 /* Extended byte 17 */ +#define R_EB18 0x21 /* Extended byte 18 */ +#define R_EB19 0x22 /* Extended byte 19 */ +#define R_EB20 0x23 /* Extended byte 20 */ +#define R_EB21 0x24 /* Extended byte 21 */ +#define R_EB22 0x25 /* Extended byte 22 */ +#define R_EB23 0x26 /* Extended byte 23 */ + +#define TDA18271_NUM_REGS 39 + +/*---------------------------------------------------------------------*/ + +struct tda18271_rf_tracking_filter_cal { + u32 rfmax; + u8 rfband; + u32 rf1_def; + u32 rf2_def; + u32 rf3_def; + u32 rf1; + u32 rf2; + u32 rf3; + int rf_a1; + int rf_b1; + int rf_a2; + int rf_b2; +}; + +enum tda18271_mode { + TDA18271_ANALOG, + TDA18271_DIGITAL, +}; + +struct tda18271_map_layout; + +enum tda18271_ver { + TDA18271HDC1, + TDA18271HDC2, +}; + +struct tda18271_priv { + u8 i2c_addr; + struct i2c_adapter *i2c_adap; + unsigned char tda18271_regs[TDA18271_NUM_REGS]; + + struct list_head tda18271_list; + + enum tda18271_mode mode; + enum tda18271_i2c_gate gate; + enum tda18271_ver id; + + unsigned int count; + unsigned int tm_rfcal; + unsigned int cal_initialized:1; + + struct tda18271_map_layout *maps; + struct tda18271_std_map std; + struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; + + struct mutex lock; + + u32 frequency; + u32 bandwidth; +}; + +/*---------------------------------------------------------------------*/ + +extern int tda18271_debug; + +#define DBG_INFO 1 +#define DBG_MAP 2 +#define DBG_REG 4 +#define DBG_ADV 8 +#define DBG_CAL 16 + +#define tda_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt, __FUNCTION__, ##arg) + +#define dprintk(kern, lvl, fmt, arg...) do {\ + if (tda18271_debug & lvl) \ + tda_printk(kern, fmt, ##arg); } while (0) + +#define tda_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) +#define tda_warn(fmt, arg...) tda_printk(KERN_WARNING, fmt, ##arg) +#define tda_err(fmt, arg...) tda_printk(KERN_ERR, fmt, ##arg) +#define tda_dbg(fmt, arg...) dprintk(KERN_DEBUG, DBG_INFO, fmt, ##arg) +#define tda_map(fmt, arg...) dprintk(KERN_DEBUG, DBG_MAP, fmt, ##arg) +#define tda_reg(fmt, arg...) dprintk(KERN_DEBUG, DBG_REG, fmt, ##arg) +#define tda_cal(fmt, arg...) dprintk(KERN_DEBUG, DBG_CAL, fmt, ##arg) + +/*---------------------------------------------------------------------*/ + +enum tda18271_map_type { + /* tda18271_pll_map */ + MAIN_PLL, + CAL_PLL, + /* tda18271_map */ + RF_CAL, + RF_CAL_KMCO, + RF_CAL_DC_OVER_DT, + BP_FILTER, + RF_BAND, + GAIN_TAPER, + IR_MEASURE, +}; + +extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div); +extern int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val); + +extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); + +extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, + u32 *freq, u8 *rf_band); + +extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, + u16 *count_limit); + +extern int tda18271_assign_map_layout(struct dvb_frontend *fe); + +/*---------------------------------------------------------------------*/ + +extern int tda18271_read_regs(struct dvb_frontend *fe); +extern int tda18271_read_extended(struct dvb_frontend *fe); +extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); +extern int tda18271_init_regs(struct dvb_frontend *fe); + +extern int tda18271_set_standby_mode(struct dvb_frontend *fe, + int sm, int sm_lt, int sm_xt); + +extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); +extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); + +extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); +extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); + +#endif /* __TDA18271_PRIV_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c new file mode 100644 index 000000000000..e94afcfdc5bc --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271-tables.c @@ -0,0 +1,1285 @@ +/* + tda18271-tables.c - driver for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "tda18271-priv.h" + +struct tda18271_pll_map { + u32 lomax; + u8 pd; /* post div */ + u8 d; /* div */ +}; + +struct tda18271_map { + u32 rfmax; + u8 val; +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_pll_map tda18271c1_main_pll[] = { + { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, + { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, + { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, + { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, + { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, + { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, + { .lomax = 54000, .pd = 0x59, .d = 0x90 }, + { .lomax = 61000, .pd = 0x58, .d = 0x80 }, + { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, + { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, + { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, + { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, + { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, + { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, + { .lomax = 109000, .pd = 0x49, .d = 0x48 }, + { .lomax = 123000, .pd = 0x48, .d = 0x40 }, + { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, + { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, + { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, + { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, + { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, + { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, + { .lomax = 219000, .pd = 0x39, .d = 0x24 }, + { .lomax = 246000, .pd = 0x38, .d = 0x20 }, + { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, + { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, + { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, + { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, + { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, + { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, + { .lomax = 438000, .pd = 0x29, .d = 0x12 }, + { .lomax = 493000, .pd = 0x28, .d = 0x10 }, + { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, + { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, + { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, + { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, + { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, + { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, + { .lomax = 877000, .pd = 0x19, .d = 0x09 }, + { .lomax = 987000, .pd = 0x18, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c2_main_pll[] = { + { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, + { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, + { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, + { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, + { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, + { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, + { .lomax = 55188, .pd = 0x51, .d = 0x90 }, + { .lomax = 62125, .pd = 0x50, .d = 0x80 }, + { .lomax = 66250, .pd = 0x47, .d = 0x78 }, + { .lomax = 71000, .pd = 0x46, .d = 0x70 }, + { .lomax = 76375, .pd = 0x45, .d = 0x68 }, + { .lomax = 82750, .pd = 0x44, .d = 0x60 }, + { .lomax = 90250, .pd = 0x43, .d = 0x58 }, + { .lomax = 99375, .pd = 0x42, .d = 0x50 }, + { .lomax = 110375, .pd = 0x41, .d = 0x48 }, + { .lomax = 124250, .pd = 0x40, .d = 0x40 }, + { .lomax = 132500, .pd = 0x37, .d = 0x3c }, + { .lomax = 142000, .pd = 0x36, .d = 0x38 }, + { .lomax = 152750, .pd = 0x35, .d = 0x34 }, + { .lomax = 165500, .pd = 0x34, .d = 0x30 }, + { .lomax = 180500, .pd = 0x33, .d = 0x2c }, + { .lomax = 198750, .pd = 0x32, .d = 0x28 }, + { .lomax = 220750, .pd = 0x31, .d = 0x24 }, + { .lomax = 248500, .pd = 0x30, .d = 0x20 }, + { .lomax = 265000, .pd = 0x27, .d = 0x1e }, + { .lomax = 284000, .pd = 0x26, .d = 0x1c }, + { .lomax = 305500, .pd = 0x25, .d = 0x1a }, + { .lomax = 331000, .pd = 0x24, .d = 0x18 }, + { .lomax = 361000, .pd = 0x23, .d = 0x16 }, + { .lomax = 397500, .pd = 0x22, .d = 0x14 }, + { .lomax = 441500, .pd = 0x21, .d = 0x12 }, + { .lomax = 497000, .pd = 0x20, .d = 0x10 }, + { .lomax = 530000, .pd = 0x17, .d = 0x0f }, + { .lomax = 568000, .pd = 0x16, .d = 0x0e }, + { .lomax = 611000, .pd = 0x15, .d = 0x0d }, + { .lomax = 662000, .pd = 0x14, .d = 0x0c }, + { .lomax = 722000, .pd = 0x13, .d = 0x0b }, + { .lomax = 795000, .pd = 0x12, .d = 0x0a }, + { .lomax = 883000, .pd = 0x11, .d = 0x09 }, + { .lomax = 994000, .pd = 0x10, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c1_cal_pll[] = { + { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, + { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, + { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, + { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, + { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, + { .lomax = 88000, .pd = 0xca, .d = 0x50 }, + { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, + { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, + { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, + { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, + { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, + { .lomax = 176000, .pd = 0xba, .d = 0x28 }, + { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, + { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, + { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, + { .lomax = 271000, .pd = 0xad, .d = 0x1a }, + { .lomax = 294000, .pd = 0xac, .d = 0x18 }, + { .lomax = 321000, .pd = 0xab, .d = 0x16 }, + { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, + { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, + { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, + { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, + { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 785000, .pd = 0x99, .d = 0x09 }, + { .lomax = 883000, .pd = 0x98, .d = 0x08 }, + { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_pll_map tda18271c2_cal_pll[] = { + { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, + { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, + { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, + { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, + { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, + { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, + { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, + { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, + { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, + { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, + { .lomax = 87875, .pd = 0xca, .d = 0x50 }, + { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, + { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, + { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, + { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, + { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, + { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, + { .lomax = 175750, .pd = 0xba, .d = 0x28 }, + { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, + { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, + { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, + { .lomax = 270500, .pd = 0xad, .d = 0x1a }, + { .lomax = 293000, .pd = 0xac, .d = 0x18 }, + { .lomax = 319500, .pd = 0xab, .d = 0x16 }, + { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, + { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, + { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, + { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, + { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, + { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, + { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, + { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, + { .lomax = 781000, .pd = 0x99, .d = 0x09 }, + { .lomax = 879000, .pd = 0x98, .d = 0x08 }, + { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_bp_filter[] = { + { .rfmax = 62000, .val = 0x00 }, + { .rfmax = 84000, .val = 0x01 }, + { .rfmax = 100000, .val = 0x02 }, + { .rfmax = 140000, .val = 0x03 }, + { .rfmax = 170000, .val = 0x04 }, + { .rfmax = 180000, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c1_km[] = { + { .rfmax = 61100, .val = 0x74 }, + { .rfmax = 350000, .val = 0x40 }, + { .rfmax = 720000, .val = 0x30 }, + { .rfmax = 865000, .val = 0x40 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c2_km[] = { + { .rfmax = 47900, .val = 0x38 }, + { .rfmax = 61100, .val = 0x44 }, + { .rfmax = 350000, .val = 0x30 }, + { .rfmax = 720000, .val = 0x24 }, + { .rfmax = 865000, .val = 0x3c }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_band[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 61100, .val = 0x01 }, +/* { .rfmax = 152600, .val = 0x02 }, */ + { .rfmax = 121200, .val = 0x02 }, + { .rfmax = 164700, .val = 0x03 }, + { .rfmax = 203500, .val = 0x04 }, + { .rfmax = 457800, .val = 0x05 }, + { .rfmax = 865000, .val = 0x06 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_gain_taper[] = { + { .rfmax = 45400, .val = 0x1f }, + { .rfmax = 45800, .val = 0x1e }, + { .rfmax = 46200, .val = 0x1d }, + { .rfmax = 46700, .val = 0x1c }, + { .rfmax = 47100, .val = 0x1b }, + { .rfmax = 47500, .val = 0x1a }, + { .rfmax = 47900, .val = 0x19 }, + { .rfmax = 49600, .val = 0x17 }, + { .rfmax = 51200, .val = 0x16 }, + { .rfmax = 52900, .val = 0x15 }, + { .rfmax = 54500, .val = 0x14 }, + { .rfmax = 56200, .val = 0x13 }, + { .rfmax = 57800, .val = 0x12 }, + { .rfmax = 59500, .val = 0x11 }, + { .rfmax = 61100, .val = 0x10 }, + { .rfmax = 67600, .val = 0x0d }, + { .rfmax = 74200, .val = 0x0c }, + { .rfmax = 80700, .val = 0x0b }, + { .rfmax = 87200, .val = 0x0a }, + { .rfmax = 93800, .val = 0x09 }, + { .rfmax = 100300, .val = 0x08 }, + { .rfmax = 106900, .val = 0x07 }, + { .rfmax = 113400, .val = 0x06 }, + { .rfmax = 119900, .val = 0x05 }, + { .rfmax = 126500, .val = 0x04 }, + { .rfmax = 133000, .val = 0x03 }, + { .rfmax = 139500, .val = 0x02 }, + { .rfmax = 146100, .val = 0x01 }, + { .rfmax = 152600, .val = 0x00 }, + { .rfmax = 154300, .val = 0x1f }, + { .rfmax = 156100, .val = 0x1e }, + { .rfmax = 157800, .val = 0x1d }, + { .rfmax = 159500, .val = 0x1c }, + { .rfmax = 161200, .val = 0x1b }, + { .rfmax = 163000, .val = 0x1a }, + { .rfmax = 164700, .val = 0x19 }, + { .rfmax = 170200, .val = 0x17 }, + { .rfmax = 175800, .val = 0x16 }, + { .rfmax = 181300, .val = 0x15 }, + { .rfmax = 186900, .val = 0x14 }, + { .rfmax = 192400, .val = 0x13 }, + { .rfmax = 198000, .val = 0x12 }, + { .rfmax = 203500, .val = 0x11 }, + { .rfmax = 216200, .val = 0x14 }, + { .rfmax = 228900, .val = 0x13 }, + { .rfmax = 241600, .val = 0x12 }, + { .rfmax = 254400, .val = 0x11 }, + { .rfmax = 267100, .val = 0x10 }, + { .rfmax = 279800, .val = 0x0f }, + { .rfmax = 292500, .val = 0x0e }, + { .rfmax = 305200, .val = 0x0d }, + { .rfmax = 317900, .val = 0x0c }, + { .rfmax = 330700, .val = 0x0b }, + { .rfmax = 343400, .val = 0x0a }, + { .rfmax = 356100, .val = 0x09 }, + { .rfmax = 368800, .val = 0x08 }, + { .rfmax = 381500, .val = 0x07 }, + { .rfmax = 394200, .val = 0x06 }, + { .rfmax = 406900, .val = 0x05 }, + { .rfmax = 419700, .val = 0x04 }, + { .rfmax = 432400, .val = 0x03 }, + { .rfmax = 445100, .val = 0x02 }, + { .rfmax = 457800, .val = 0x01 }, + { .rfmax = 476300, .val = 0x19 }, + { .rfmax = 494800, .val = 0x18 }, + { .rfmax = 513300, .val = 0x17 }, + { .rfmax = 531800, .val = 0x16 }, + { .rfmax = 550300, .val = 0x15 }, + { .rfmax = 568900, .val = 0x14 }, + { .rfmax = 587400, .val = 0x13 }, + { .rfmax = 605900, .val = 0x12 }, + { .rfmax = 624400, .val = 0x11 }, + { .rfmax = 642900, .val = 0x10 }, + { .rfmax = 661400, .val = 0x0f }, + { .rfmax = 679900, .val = 0x0e }, + { .rfmax = 698400, .val = 0x0d }, + { .rfmax = 716900, .val = 0x0c }, + { .rfmax = 735400, .val = 0x0b }, + { .rfmax = 753900, .val = 0x0a }, + { .rfmax = 772500, .val = 0x09 }, + { .rfmax = 791000, .val = 0x08 }, + { .rfmax = 809500, .val = 0x07 }, + { .rfmax = 828000, .val = 0x06 }, + { .rfmax = 846500, .val = 0x05 }, + { .rfmax = 865000, .val = 0x04 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c1_rf_cal[] = { + { .rfmax = 41000, .val = 0x1e }, + { .rfmax = 43000, .val = 0x30 }, + { .rfmax = 45000, .val = 0x43 }, + { .rfmax = 46000, .val = 0x4d }, + { .rfmax = 47000, .val = 0x54 }, + { .rfmax = 47900, .val = 0x64 }, + { .rfmax = 49100, .val = 0x20 }, + { .rfmax = 50000, .val = 0x22 }, + { .rfmax = 51000, .val = 0x2a }, + { .rfmax = 53000, .val = 0x32 }, + { .rfmax = 55000, .val = 0x35 }, + { .rfmax = 56000, .val = 0x3c }, + { .rfmax = 57000, .val = 0x3f }, + { .rfmax = 58000, .val = 0x48 }, + { .rfmax = 59000, .val = 0x4d }, + { .rfmax = 60000, .val = 0x58 }, + { .rfmax = 61100, .val = 0x5f }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271c2_rf_cal[] = { + { .rfmax = 41000, .val = 0x0f }, + { .rfmax = 43000, .val = 0x1c }, + { .rfmax = 45000, .val = 0x2f }, + { .rfmax = 46000, .val = 0x39 }, + { .rfmax = 47000, .val = 0x40 }, + { .rfmax = 47900, .val = 0x50 }, + { .rfmax = 49100, .val = 0x16 }, + { .rfmax = 50000, .val = 0x18 }, + { .rfmax = 51000, .val = 0x20 }, + { .rfmax = 53000, .val = 0x28 }, + { .rfmax = 55000, .val = 0x2b }, + { .rfmax = 56000, .val = 0x32 }, + { .rfmax = 57000, .val = 0x35 }, + { .rfmax = 58000, .val = 0x3e }, + { .rfmax = 59000, .val = 0x43 }, + { .rfmax = 60000, .val = 0x4e }, + { .rfmax = 61100, .val = 0x55 }, + { .rfmax = 63000, .val = 0x0f }, + { .rfmax = 64000, .val = 0x11 }, + { .rfmax = 65000, .val = 0x12 }, + { .rfmax = 66000, .val = 0x15 }, + { .rfmax = 67000, .val = 0x16 }, + { .rfmax = 68000, .val = 0x17 }, + { .rfmax = 70000, .val = 0x19 }, + { .rfmax = 71000, .val = 0x1c }, + { .rfmax = 72000, .val = 0x1d }, + { .rfmax = 73000, .val = 0x1f }, + { .rfmax = 74000, .val = 0x20 }, + { .rfmax = 75000, .val = 0x21 }, + { .rfmax = 76000, .val = 0x24 }, + { .rfmax = 77000, .val = 0x25 }, + { .rfmax = 78000, .val = 0x27 }, + { .rfmax = 80000, .val = 0x28 }, + { .rfmax = 81000, .val = 0x29 }, + { .rfmax = 82000, .val = 0x2d }, + { .rfmax = 83000, .val = 0x2e }, + { .rfmax = 84000, .val = 0x2f }, + { .rfmax = 85000, .val = 0x31 }, + { .rfmax = 86000, .val = 0x33 }, + { .rfmax = 87000, .val = 0x34 }, + { .rfmax = 88000, .val = 0x35 }, + { .rfmax = 89000, .val = 0x37 }, + { .rfmax = 90000, .val = 0x38 }, + { .rfmax = 91000, .val = 0x39 }, + { .rfmax = 93000, .val = 0x3c }, + { .rfmax = 94000, .val = 0x3e }, + { .rfmax = 95000, .val = 0x3f }, + { .rfmax = 96000, .val = 0x40 }, + { .rfmax = 97000, .val = 0x42 }, + { .rfmax = 99000, .val = 0x45 }, + { .rfmax = 100000, .val = 0x46 }, + { .rfmax = 102000, .val = 0x48 }, + { .rfmax = 103000, .val = 0x4a }, + { .rfmax = 105000, .val = 0x4d }, + { .rfmax = 106000, .val = 0x4e }, + { .rfmax = 107000, .val = 0x50 }, + { .rfmax = 108000, .val = 0x51 }, + { .rfmax = 110000, .val = 0x54 }, + { .rfmax = 111000, .val = 0x56 }, + { .rfmax = 112000, .val = 0x57 }, + { .rfmax = 113000, .val = 0x58 }, + { .rfmax = 114000, .val = 0x59 }, + { .rfmax = 115000, .val = 0x5c }, + { .rfmax = 116000, .val = 0x5d }, + { .rfmax = 117000, .val = 0x5f }, + { .rfmax = 119000, .val = 0x60 }, + { .rfmax = 120000, .val = 0x64 }, + { .rfmax = 121000, .val = 0x65 }, + { .rfmax = 122000, .val = 0x66 }, + { .rfmax = 123000, .val = 0x68 }, + { .rfmax = 124000, .val = 0x69 }, + { .rfmax = 125000, .val = 0x6c }, + { .rfmax = 126000, .val = 0x6d }, + { .rfmax = 127000, .val = 0x6e }, + { .rfmax = 128000, .val = 0x70 }, + { .rfmax = 129000, .val = 0x71 }, + { .rfmax = 130000, .val = 0x75 }, + { .rfmax = 131000, .val = 0x77 }, + { .rfmax = 132000, .val = 0x78 }, + { .rfmax = 133000, .val = 0x7b }, + { .rfmax = 134000, .val = 0x7e }, + { .rfmax = 135000, .val = 0x81 }, + { .rfmax = 136000, .val = 0x82 }, + { .rfmax = 137000, .val = 0x87 }, + { .rfmax = 138000, .val = 0x88 }, + { .rfmax = 139000, .val = 0x8d }, + { .rfmax = 140000, .val = 0x8e }, + { .rfmax = 141000, .val = 0x91 }, + { .rfmax = 142000, .val = 0x95 }, + { .rfmax = 143000, .val = 0x9a }, + { .rfmax = 144000, .val = 0x9d }, + { .rfmax = 145000, .val = 0xa1 }, + { .rfmax = 146000, .val = 0xa2 }, + { .rfmax = 147000, .val = 0xa4 }, + { .rfmax = 148000, .val = 0xa9 }, + { .rfmax = 149000, .val = 0xae }, + { .rfmax = 150000, .val = 0xb0 }, + { .rfmax = 151000, .val = 0xb1 }, + { .rfmax = 152000, .val = 0xb7 }, + { .rfmax = 153000, .val = 0xbd }, + { .rfmax = 154000, .val = 0x20 }, + { .rfmax = 155000, .val = 0x22 }, + { .rfmax = 156000, .val = 0x24 }, + { .rfmax = 157000, .val = 0x25 }, + { .rfmax = 158000, .val = 0x27 }, + { .rfmax = 159000, .val = 0x29 }, + { .rfmax = 160000, .val = 0x2c }, + { .rfmax = 161000, .val = 0x2d }, + { .rfmax = 163000, .val = 0x2e }, + { .rfmax = 164000, .val = 0x2f }, + { .rfmax = 165000, .val = 0x30 }, + { .rfmax = 166000, .val = 0x11 }, + { .rfmax = 167000, .val = 0x12 }, + { .rfmax = 168000, .val = 0x13 }, + { .rfmax = 169000, .val = 0x14 }, + { .rfmax = 170000, .val = 0x15 }, + { .rfmax = 172000, .val = 0x16 }, + { .rfmax = 173000, .val = 0x17 }, + { .rfmax = 174000, .val = 0x18 }, + { .rfmax = 175000, .val = 0x1a }, + { .rfmax = 176000, .val = 0x1b }, + { .rfmax = 178000, .val = 0x1d }, + { .rfmax = 179000, .val = 0x1e }, + { .rfmax = 180000, .val = 0x1f }, + { .rfmax = 181000, .val = 0x20 }, + { .rfmax = 182000, .val = 0x21 }, + { .rfmax = 183000, .val = 0x22 }, + { .rfmax = 184000, .val = 0x24 }, + { .rfmax = 185000, .val = 0x25 }, + { .rfmax = 186000, .val = 0x26 }, + { .rfmax = 187000, .val = 0x27 }, + { .rfmax = 188000, .val = 0x29 }, + { .rfmax = 189000, .val = 0x2a }, + { .rfmax = 190000, .val = 0x2c }, + { .rfmax = 191000, .val = 0x2d }, + { .rfmax = 192000, .val = 0x2e }, + { .rfmax = 193000, .val = 0x2f }, + { .rfmax = 194000, .val = 0x30 }, + { .rfmax = 195000, .val = 0x33 }, + { .rfmax = 196000, .val = 0x35 }, + { .rfmax = 198000, .val = 0x36 }, + { .rfmax = 200000, .val = 0x38 }, + { .rfmax = 201000, .val = 0x3c }, + { .rfmax = 202000, .val = 0x3d }, + { .rfmax = 203500, .val = 0x3e }, + { .rfmax = 206000, .val = 0x0e }, + { .rfmax = 208000, .val = 0x0f }, + { .rfmax = 212000, .val = 0x10 }, + { .rfmax = 216000, .val = 0x11 }, + { .rfmax = 217000, .val = 0x12 }, + { .rfmax = 218000, .val = 0x13 }, + { .rfmax = 220000, .val = 0x14 }, + { .rfmax = 222000, .val = 0x15 }, + { .rfmax = 225000, .val = 0x16 }, + { .rfmax = 228000, .val = 0x17 }, + { .rfmax = 231000, .val = 0x18 }, + { .rfmax = 234000, .val = 0x19 }, + { .rfmax = 235000, .val = 0x1a }, + { .rfmax = 236000, .val = 0x1b }, + { .rfmax = 237000, .val = 0x1c }, + { .rfmax = 240000, .val = 0x1d }, + { .rfmax = 242000, .val = 0x1f }, + { .rfmax = 247000, .val = 0x20 }, + { .rfmax = 249000, .val = 0x21 }, + { .rfmax = 252000, .val = 0x22 }, + { .rfmax = 253000, .val = 0x23 }, + { .rfmax = 254000, .val = 0x24 }, + { .rfmax = 256000, .val = 0x25 }, + { .rfmax = 259000, .val = 0x26 }, + { .rfmax = 262000, .val = 0x27 }, + { .rfmax = 264000, .val = 0x28 }, + { .rfmax = 267000, .val = 0x29 }, + { .rfmax = 269000, .val = 0x2a }, + { .rfmax = 271000, .val = 0x2b }, + { .rfmax = 273000, .val = 0x2c }, + { .rfmax = 275000, .val = 0x2d }, + { .rfmax = 277000, .val = 0x2e }, + { .rfmax = 279000, .val = 0x2f }, + { .rfmax = 282000, .val = 0x30 }, + { .rfmax = 284000, .val = 0x31 }, + { .rfmax = 286000, .val = 0x32 }, + { .rfmax = 287000, .val = 0x33 }, + { .rfmax = 290000, .val = 0x34 }, + { .rfmax = 293000, .val = 0x35 }, + { .rfmax = 295000, .val = 0x36 }, + { .rfmax = 297000, .val = 0x37 }, + { .rfmax = 300000, .val = 0x38 }, + { .rfmax = 303000, .val = 0x39 }, + { .rfmax = 305000, .val = 0x3a }, + { .rfmax = 306000, .val = 0x3b }, + { .rfmax = 307000, .val = 0x3c }, + { .rfmax = 310000, .val = 0x3d }, + { .rfmax = 312000, .val = 0x3e }, + { .rfmax = 315000, .val = 0x3f }, + { .rfmax = 318000, .val = 0x40 }, + { .rfmax = 320000, .val = 0x41 }, + { .rfmax = 323000, .val = 0x42 }, + { .rfmax = 324000, .val = 0x43 }, + { .rfmax = 325000, .val = 0x44 }, + { .rfmax = 327000, .val = 0x45 }, + { .rfmax = 331000, .val = 0x46 }, + { .rfmax = 334000, .val = 0x47 }, + { .rfmax = 337000, .val = 0x48 }, + { .rfmax = 339000, .val = 0x49 }, + { .rfmax = 340000, .val = 0x4a }, + { .rfmax = 341000, .val = 0x4b }, + { .rfmax = 343000, .val = 0x4c }, + { .rfmax = 345000, .val = 0x4d }, + { .rfmax = 349000, .val = 0x4e }, + { .rfmax = 352000, .val = 0x4f }, + { .rfmax = 353000, .val = 0x50 }, + { .rfmax = 355000, .val = 0x51 }, + { .rfmax = 357000, .val = 0x52 }, + { .rfmax = 359000, .val = 0x53 }, + { .rfmax = 361000, .val = 0x54 }, + { .rfmax = 362000, .val = 0x55 }, + { .rfmax = 364000, .val = 0x56 }, + { .rfmax = 368000, .val = 0x57 }, + { .rfmax = 370000, .val = 0x58 }, + { .rfmax = 372000, .val = 0x59 }, + { .rfmax = 375000, .val = 0x5a }, + { .rfmax = 376000, .val = 0x5b }, + { .rfmax = 377000, .val = 0x5c }, + { .rfmax = 379000, .val = 0x5d }, + { .rfmax = 382000, .val = 0x5e }, + { .rfmax = 384000, .val = 0x5f }, + { .rfmax = 385000, .val = 0x60 }, + { .rfmax = 386000, .val = 0x61 }, + { .rfmax = 388000, .val = 0x62 }, + { .rfmax = 390000, .val = 0x63 }, + { .rfmax = 393000, .val = 0x64 }, + { .rfmax = 394000, .val = 0x65 }, + { .rfmax = 396000, .val = 0x66 }, + { .rfmax = 397000, .val = 0x67 }, + { .rfmax = 398000, .val = 0x68 }, + { .rfmax = 400000, .val = 0x69 }, + { .rfmax = 402000, .val = 0x6a }, + { .rfmax = 403000, .val = 0x6b }, + { .rfmax = 407000, .val = 0x6c }, + { .rfmax = 408000, .val = 0x6d }, + { .rfmax = 409000, .val = 0x6e }, + { .rfmax = 410000, .val = 0x6f }, + { .rfmax = 411000, .val = 0x70 }, + { .rfmax = 412000, .val = 0x71 }, + { .rfmax = 413000, .val = 0x72 }, + { .rfmax = 414000, .val = 0x73 }, + { .rfmax = 417000, .val = 0x74 }, + { .rfmax = 418000, .val = 0x75 }, + { .rfmax = 420000, .val = 0x76 }, + { .rfmax = 422000, .val = 0x77 }, + { .rfmax = 423000, .val = 0x78 }, + { .rfmax = 424000, .val = 0x79 }, + { .rfmax = 427000, .val = 0x7a }, + { .rfmax = 428000, .val = 0x7b }, + { .rfmax = 429000, .val = 0x7d }, + { .rfmax = 432000, .val = 0x7f }, + { .rfmax = 434000, .val = 0x80 }, + { .rfmax = 435000, .val = 0x81 }, + { .rfmax = 436000, .val = 0x83 }, + { .rfmax = 437000, .val = 0x84 }, + { .rfmax = 438000, .val = 0x85 }, + { .rfmax = 439000, .val = 0x86 }, + { .rfmax = 440000, .val = 0x87 }, + { .rfmax = 441000, .val = 0x88 }, + { .rfmax = 442000, .val = 0x89 }, + { .rfmax = 445000, .val = 0x8a }, + { .rfmax = 446000, .val = 0x8b }, + { .rfmax = 447000, .val = 0x8c }, + { .rfmax = 448000, .val = 0x8e }, + { .rfmax = 449000, .val = 0x8f }, + { .rfmax = 450000, .val = 0x90 }, + { .rfmax = 452000, .val = 0x91 }, + { .rfmax = 453000, .val = 0x93 }, + { .rfmax = 454000, .val = 0x94 }, + { .rfmax = 456000, .val = 0x96 }, + { .rfmax = 457000, .val = 0x98 }, + { .rfmax = 461000, .val = 0x11 }, + { .rfmax = 468000, .val = 0x12 }, + { .rfmax = 472000, .val = 0x13 }, + { .rfmax = 473000, .val = 0x14 }, + { .rfmax = 474000, .val = 0x15 }, + { .rfmax = 481000, .val = 0x16 }, + { .rfmax = 486000, .val = 0x17 }, + { .rfmax = 491000, .val = 0x18 }, + { .rfmax = 498000, .val = 0x19 }, + { .rfmax = 499000, .val = 0x1a }, + { .rfmax = 501000, .val = 0x1b }, + { .rfmax = 506000, .val = 0x1c }, + { .rfmax = 511000, .val = 0x1d }, + { .rfmax = 516000, .val = 0x1e }, + { .rfmax = 520000, .val = 0x1f }, + { .rfmax = 521000, .val = 0x20 }, + { .rfmax = 525000, .val = 0x21 }, + { .rfmax = 529000, .val = 0x22 }, + { .rfmax = 533000, .val = 0x23 }, + { .rfmax = 539000, .val = 0x24 }, + { .rfmax = 541000, .val = 0x25 }, + { .rfmax = 547000, .val = 0x26 }, + { .rfmax = 549000, .val = 0x27 }, + { .rfmax = 551000, .val = 0x28 }, + { .rfmax = 556000, .val = 0x29 }, + { .rfmax = 561000, .val = 0x2a }, + { .rfmax = 563000, .val = 0x2b }, + { .rfmax = 565000, .val = 0x2c }, + { .rfmax = 569000, .val = 0x2d }, + { .rfmax = 571000, .val = 0x2e }, + { .rfmax = 577000, .val = 0x2f }, + { .rfmax = 580000, .val = 0x30 }, + { .rfmax = 582000, .val = 0x31 }, + { .rfmax = 584000, .val = 0x32 }, + { .rfmax = 588000, .val = 0x33 }, + { .rfmax = 591000, .val = 0x34 }, + { .rfmax = 596000, .val = 0x35 }, + { .rfmax = 598000, .val = 0x36 }, + { .rfmax = 603000, .val = 0x37 }, + { .rfmax = 604000, .val = 0x38 }, + { .rfmax = 606000, .val = 0x39 }, + { .rfmax = 612000, .val = 0x3a }, + { .rfmax = 615000, .val = 0x3b }, + { .rfmax = 617000, .val = 0x3c }, + { .rfmax = 621000, .val = 0x3d }, + { .rfmax = 622000, .val = 0x3e }, + { .rfmax = 625000, .val = 0x3f }, + { .rfmax = 632000, .val = 0x40 }, + { .rfmax = 633000, .val = 0x41 }, + { .rfmax = 634000, .val = 0x42 }, + { .rfmax = 642000, .val = 0x43 }, + { .rfmax = 643000, .val = 0x44 }, + { .rfmax = 647000, .val = 0x45 }, + { .rfmax = 650000, .val = 0x46 }, + { .rfmax = 652000, .val = 0x47 }, + { .rfmax = 657000, .val = 0x48 }, + { .rfmax = 661000, .val = 0x49 }, + { .rfmax = 662000, .val = 0x4a }, + { .rfmax = 665000, .val = 0x4b }, + { .rfmax = 667000, .val = 0x4c }, + { .rfmax = 670000, .val = 0x4d }, + { .rfmax = 673000, .val = 0x4e }, + { .rfmax = 676000, .val = 0x4f }, + { .rfmax = 677000, .val = 0x50 }, + { .rfmax = 681000, .val = 0x51 }, + { .rfmax = 683000, .val = 0x52 }, + { .rfmax = 686000, .val = 0x53 }, + { .rfmax = 688000, .val = 0x54 }, + { .rfmax = 689000, .val = 0x55 }, + { .rfmax = 691000, .val = 0x56 }, + { .rfmax = 695000, .val = 0x57 }, + { .rfmax = 698000, .val = 0x58 }, + { .rfmax = 703000, .val = 0x59 }, + { .rfmax = 704000, .val = 0x5a }, + { .rfmax = 705000, .val = 0x5b }, + { .rfmax = 707000, .val = 0x5c }, + { .rfmax = 710000, .val = 0x5d }, + { .rfmax = 712000, .val = 0x5e }, + { .rfmax = 717000, .val = 0x5f }, + { .rfmax = 718000, .val = 0x60 }, + { .rfmax = 721000, .val = 0x61 }, + { .rfmax = 722000, .val = 0x62 }, + { .rfmax = 723000, .val = 0x63 }, + { .rfmax = 725000, .val = 0x64 }, + { .rfmax = 727000, .val = 0x65 }, + { .rfmax = 730000, .val = 0x66 }, + { .rfmax = 732000, .val = 0x67 }, + { .rfmax = 735000, .val = 0x68 }, + { .rfmax = 740000, .val = 0x69 }, + { .rfmax = 741000, .val = 0x6a }, + { .rfmax = 742000, .val = 0x6b }, + { .rfmax = 743000, .val = 0x6c }, + { .rfmax = 745000, .val = 0x6d }, + { .rfmax = 747000, .val = 0x6e }, + { .rfmax = 748000, .val = 0x6f }, + { .rfmax = 750000, .val = 0x70 }, + { .rfmax = 752000, .val = 0x71 }, + { .rfmax = 754000, .val = 0x72 }, + { .rfmax = 757000, .val = 0x73 }, + { .rfmax = 758000, .val = 0x74 }, + { .rfmax = 760000, .val = 0x75 }, + { .rfmax = 763000, .val = 0x76 }, + { .rfmax = 764000, .val = 0x77 }, + { .rfmax = 766000, .val = 0x78 }, + { .rfmax = 767000, .val = 0x79 }, + { .rfmax = 768000, .val = 0x7a }, + { .rfmax = 773000, .val = 0x7b }, + { .rfmax = 774000, .val = 0x7c }, + { .rfmax = 776000, .val = 0x7d }, + { .rfmax = 777000, .val = 0x7e }, + { .rfmax = 778000, .val = 0x7f }, + { .rfmax = 779000, .val = 0x80 }, + { .rfmax = 781000, .val = 0x81 }, + { .rfmax = 783000, .val = 0x82 }, + { .rfmax = 784000, .val = 0x83 }, + { .rfmax = 785000, .val = 0x84 }, + { .rfmax = 786000, .val = 0x85 }, + { .rfmax = 793000, .val = 0x86 }, + { .rfmax = 794000, .val = 0x87 }, + { .rfmax = 795000, .val = 0x88 }, + { .rfmax = 797000, .val = 0x89 }, + { .rfmax = 799000, .val = 0x8a }, + { .rfmax = 801000, .val = 0x8b }, + { .rfmax = 802000, .val = 0x8c }, + { .rfmax = 803000, .val = 0x8d }, + { .rfmax = 804000, .val = 0x8e }, + { .rfmax = 810000, .val = 0x90 }, + { .rfmax = 811000, .val = 0x91 }, + { .rfmax = 812000, .val = 0x92 }, + { .rfmax = 814000, .val = 0x93 }, + { .rfmax = 816000, .val = 0x94 }, + { .rfmax = 817000, .val = 0x96 }, + { .rfmax = 818000, .val = 0x97 }, + { .rfmax = 820000, .val = 0x98 }, + { .rfmax = 821000, .val = 0x99 }, + { .rfmax = 822000, .val = 0x9a }, + { .rfmax = 828000, .val = 0x9b }, + { .rfmax = 829000, .val = 0x9d }, + { .rfmax = 830000, .val = 0x9f }, + { .rfmax = 831000, .val = 0xa0 }, + { .rfmax = 833000, .val = 0xa1 }, + { .rfmax = 835000, .val = 0xa2 }, + { .rfmax = 836000, .val = 0xa3 }, + { .rfmax = 837000, .val = 0xa4 }, + { .rfmax = 838000, .val = 0xa6 }, + { .rfmax = 840000, .val = 0xa8 }, + { .rfmax = 842000, .val = 0xa9 }, + { .rfmax = 845000, .val = 0xaa }, + { .rfmax = 846000, .val = 0xab }, + { .rfmax = 847000, .val = 0xad }, + { .rfmax = 848000, .val = 0xae }, + { .rfmax = 852000, .val = 0xaf }, + { .rfmax = 853000, .val = 0xb0 }, + { .rfmax = 858000, .val = 0xb1 }, + { .rfmax = 860000, .val = 0xb2 }, + { .rfmax = 861000, .val = 0xb3 }, + { .rfmax = 862000, .val = 0xb4 }, + { .rfmax = 863000, .val = 0xb6 }, + { .rfmax = 864000, .val = 0xb8 }, + { .rfmax = 865000, .val = 0xb9 }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +static struct tda18271_map tda18271_ir_measure[] = { + { .rfmax = 30000, .val = 4 }, + { .rfmax = 200000, .val = 5 }, + { .rfmax = 600000, .val = 6 }, + { .rfmax = 865000, .val = 7 }, + { .rfmax = 0, .val = 0 }, /* end */ +}; + +static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { + { .rfmax = 47900, .val = 0x00 }, + { .rfmax = 55000, .val = 0x00 }, + { .rfmax = 61100, .val = 0x0a }, + { .rfmax = 64000, .val = 0x0a }, + { .rfmax = 82000, .val = 0x14 }, + { .rfmax = 84000, .val = 0x19 }, + { .rfmax = 119000, .val = 0x1c }, + { .rfmax = 124000, .val = 0x20 }, + { .rfmax = 129000, .val = 0x2a }, + { .rfmax = 134000, .val = 0x32 }, + { .rfmax = 139000, .val = 0x39 }, + { .rfmax = 144000, .val = 0x3e }, + { .rfmax = 149000, .val = 0x3f }, + { .rfmax = 152600, .val = 0x40 }, + { .rfmax = 154000, .val = 0x40 }, + { .rfmax = 164700, .val = 0x41 }, + { .rfmax = 203500, .val = 0x32 }, + { .rfmax = 353000, .val = 0x19 }, + { .rfmax = 356000, .val = 0x1a }, + { .rfmax = 359000, .val = 0x1b }, + { .rfmax = 363000, .val = 0x1c }, + { .rfmax = 366000, .val = 0x1d }, + { .rfmax = 369000, .val = 0x1e }, + { .rfmax = 373000, .val = 0x1f }, + { .rfmax = 376000, .val = 0x20 }, + { .rfmax = 379000, .val = 0x21 }, + { .rfmax = 383000, .val = 0x22 }, + { .rfmax = 386000, .val = 0x23 }, + { .rfmax = 389000, .val = 0x24 }, + { .rfmax = 393000, .val = 0x25 }, + { .rfmax = 396000, .val = 0x26 }, + { .rfmax = 399000, .val = 0x27 }, + { .rfmax = 402000, .val = 0x28 }, + { .rfmax = 404000, .val = 0x29 }, + { .rfmax = 407000, .val = 0x2a }, + { .rfmax = 409000, .val = 0x2b }, + { .rfmax = 412000, .val = 0x2c }, + { .rfmax = 414000, .val = 0x2d }, + { .rfmax = 417000, .val = 0x2e }, + { .rfmax = 419000, .val = 0x2f }, + { .rfmax = 422000, .val = 0x30 }, + { .rfmax = 424000, .val = 0x31 }, + { .rfmax = 427000, .val = 0x32 }, + { .rfmax = 429000, .val = 0x33 }, + { .rfmax = 432000, .val = 0x34 }, + { .rfmax = 434000, .val = 0x35 }, + { .rfmax = 437000, .val = 0x36 }, + { .rfmax = 439000, .val = 0x37 }, + { .rfmax = 442000, .val = 0x38 }, + { .rfmax = 444000, .val = 0x39 }, + { .rfmax = 447000, .val = 0x3a }, + { .rfmax = 449000, .val = 0x3b }, + { .rfmax = 457800, .val = 0x3c }, + { .rfmax = 465000, .val = 0x0f }, + { .rfmax = 477000, .val = 0x12 }, + { .rfmax = 483000, .val = 0x14 }, + { .rfmax = 502000, .val = 0x19 }, + { .rfmax = 508000, .val = 0x1b }, + { .rfmax = 519000, .val = 0x1c }, + { .rfmax = 522000, .val = 0x1d }, + { .rfmax = 524000, .val = 0x1e }, + { .rfmax = 534000, .val = 0x1f }, + { .rfmax = 549000, .val = 0x20 }, + { .rfmax = 554000, .val = 0x22 }, + { .rfmax = 584000, .val = 0x24 }, + { .rfmax = 589000, .val = 0x26 }, + { .rfmax = 658000, .val = 0x27 }, + { .rfmax = 664000, .val = 0x2c }, + { .rfmax = 669000, .val = 0x2d }, + { .rfmax = 699000, .val = 0x2e }, + { .rfmax = 704000, .val = 0x30 }, + { .rfmax = 709000, .val = 0x31 }, + { .rfmax = 714000, .val = 0x32 }, + { .rfmax = 724000, .val = 0x33 }, + { .rfmax = 729000, .val = 0x36 }, + { .rfmax = 739000, .val = 0x38 }, + { .rfmax = 744000, .val = 0x39 }, + { .rfmax = 749000, .val = 0x3b }, + { .rfmax = 754000, .val = 0x3c }, + { .rfmax = 759000, .val = 0x3d }, + { .rfmax = 764000, .val = 0x3e }, + { .rfmax = 769000, .val = 0x3f }, + { .rfmax = 774000, .val = 0x40 }, + { .rfmax = 779000, .val = 0x41 }, + { .rfmax = 784000, .val = 0x43 }, + { .rfmax = 789000, .val = 0x46 }, + { .rfmax = 794000, .val = 0x48 }, + { .rfmax = 799000, .val = 0x4b }, + { .rfmax = 804000, .val = 0x4f }, + { .rfmax = 809000, .val = 0x54 }, + { .rfmax = 814000, .val = 0x59 }, + { .rfmax = 819000, .val = 0x5d }, + { .rfmax = 824000, .val = 0x61 }, + { .rfmax = 829000, .val = 0x68 }, + { .rfmax = 834000, .val = 0x6e }, + { .rfmax = 839000, .val = 0x75 }, + { .rfmax = 844000, .val = 0x7e }, + { .rfmax = 849000, .val = 0x82 }, + { .rfmax = 854000, .val = 0x84 }, + { .rfmax = 859000, .val = 0x8f }, + { .rfmax = 865000, .val = 0x9a }, + { .rfmax = 0, .val = 0x00 }, /* end */ +}; + +/*---------------------------------------------------------------------*/ + +struct tda18271_thermo_map { + u8 d; + u8 r0; + u8 r1; +}; + +static struct tda18271_thermo_map tda18271_thermometer[] = { + { .d = 0x00, .r0 = 60, .r1 = 92 }, + { .d = 0x01, .r0 = 62, .r1 = 94 }, + { .d = 0x02, .r0 = 66, .r1 = 98 }, + { .d = 0x03, .r0 = 64, .r1 = 96 }, + { .d = 0x04, .r0 = 74, .r1 = 106 }, + { .d = 0x05, .r0 = 72, .r1 = 104 }, + { .d = 0x06, .r0 = 68, .r1 = 100 }, + { .d = 0x07, .r0 = 70, .r1 = 102 }, + { .d = 0x08, .r0 = 90, .r1 = 122 }, + { .d = 0x09, .r0 = 88, .r1 = 120 }, + { .d = 0x0a, .r0 = 84, .r1 = 116 }, + { .d = 0x0b, .r0 = 86, .r1 = 118 }, + { .d = 0x0c, .r0 = 76, .r1 = 108 }, + { .d = 0x0d, .r0 = 78, .r1 = 110 }, + { .d = 0x0e, .r0 = 82, .r1 = 114 }, + { .d = 0x0f, .r0 = 80, .r1 = 112 }, + { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ +}; + +int tda18271_lookup_thermometer(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + unsigned char *regs = priv->tda18271_regs; + int val, i = 0; + + while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { + if (tda18271_thermometer[i + 1].d == 0) + break; + i++; + } + + if ((regs[R_TM] & 0x20) == 0x20) + val = tda18271_thermometer[i].r1; + else + val = tda18271_thermometer[i].r0; + + tda_map("(%d) tm = %d\n", i, val); + + return val; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_cid_target_map { + u32 rfmax; + u8 target; + u16 limit; +}; + +static struct tda18271_cid_target_map tda18271_cid_target[] = { + { .rfmax = 46000, .target = 0x04, .limit = 1800 }, + { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, + { .rfmax = 79100, .target = 0x01, .limit = 4000 }, + { .rfmax = 136800, .target = 0x18, .limit = 4000 }, + { .rfmax = 156700, .target = 0x18, .limit = 4000 }, + { .rfmax = 156700, .target = 0x18, .limit = 4000 }, + { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, + { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, + { .rfmax = 345000, .target = 0x18, .limit = 4000 }, + { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, + { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, + { .rfmax = 697500, .target = 0x32, .limit = 4000 }, + { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, + { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ +}; + +int tda18271_lookup_cid_target(struct dvb_frontend *fe, + u32 *freq, u8 *cid_target, u16 *count_limit) +{ + int i = 0; + + while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { + if (tda18271_cid_target[i + 1].rfmax == 0) + break; + i++; + } + *cid_target = tda18271_cid_target[i].target; + *count_limit = tda18271_cid_target[i].limit; + + tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, + tda18271_cid_target[i].target, tda18271_cid_target[i].limit); + + return 0; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { + { .rfmax = 47900, .rfband = 0x00, + .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 61100, .rfband = 0x01, + .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 152600, .rfband = 0x02, + .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, + { .rfmax = 164700, .rfband = 0x03, + .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 203500, .rfband = 0x04, + .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, + { .rfmax = 457800, .rfband = 0x05, + .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, + { .rfmax = 865000, .rfband = 0x06, + .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, + { .rfmax = 0, .rfband = 0x00, + .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ +}; + +int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; + int i = 0; + + while ((map[i].rfmax * 1000) < *freq) { + if (tda18271_debug & DBG_ADV) + tda_map("(%d) rfmax = %d < freq = %d, " + "rf1_def = %d, rf2_def = %d, rf3_def = %d, " + "rf1 = %d, rf2 = %d, rf3 = %d, " + "rf_a1 = %d, rf_a2 = %d, " + "rf_b1 = %d, rf_b2 = %d\n", + i, map[i].rfmax * 1000, *freq, + map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, + map[i].rf1, map[i].rf2, map[i].rf3, + map[i].rf_a1, map[i].rf_a2, + map[i].rf_b1, map[i].rf_b2); + if (map[i].rfmax == 0) + return -EINVAL; + i++; + } + if (rf_band) + *rf_band = map[i].rfband; + + tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); + + return i; +} + +/*---------------------------------------------------------------------*/ + +struct tda18271_map_layout { + struct tda18271_pll_map *main_pll; + struct tda18271_pll_map *cal_pll; + + struct tda18271_map *rf_cal; + struct tda18271_map *rf_cal_kmco; + struct tda18271_map *rf_cal_dc_over_dt; + + struct tda18271_map *bp_filter; + struct tda18271_map *rf_band; + struct tda18271_map *gain_taper; + struct tda18271_map *ir_measure; +}; + +/*---------------------------------------------------------------------*/ + +int tda18271_lookup_pll_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *post_div, u8 *div) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_pll_map *map = NULL; + unsigned int i = 0; + char *map_name; + int ret = 0; + + BUG_ON(!priv->maps); + + switch (map_type) { + case MAIN_PLL: + map = priv->maps->main_pll; + map_name = "main_pll"; + break; + case CAL_PLL: + map = priv->maps->cal_pll; + map_name = "cal_pll"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + tda_warn("%s map is not set!\n", map_name); + ret = -EINVAL; + goto fail; + } + + while ((map[i].lomax * 1000) < *freq) { + if (map[i + 1].lomax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; + break; + } + i++; + } + *post_div = map[i].pd; + *div = map[i].d; + + tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", + i, map_name, *post_div, *div); +fail: + return ret; +} + +int tda18271_lookup_map(struct dvb_frontend *fe, + enum tda18271_map_type map_type, + u32 *freq, u8 *val) +{ + struct tda18271_priv *priv = fe->tuner_priv; + struct tda18271_map *map = NULL; + unsigned int i = 0; + char *map_name; + int ret = 0; + + BUG_ON(!priv->maps); + + switch (map_type) { + case BP_FILTER: + map = priv->maps->bp_filter; + map_name = "bp_filter"; + break; + case RF_CAL_KMCO: + map = priv->maps->rf_cal_kmco; + map_name = "km"; + break; + case RF_BAND: + map = priv->maps->rf_band; + map_name = "rf_band"; + break; + case GAIN_TAPER: + map = priv->maps->gain_taper; + map_name = "gain_taper"; + break; + case RF_CAL: + map = priv->maps->rf_cal; + map_name = "rf_cal"; + break; + case IR_MEASURE: + map = priv->maps->ir_measure; + map_name = "ir_measure"; + break; + case RF_CAL_DC_OVER_DT: + map = priv->maps->rf_cal_dc_over_dt; + map_name = "rf_cal_dc_over_dt"; + break; + default: + /* we should never get here */ + map_name = "undefined"; + break; + } + + if (!map) { + tda_warn("%s map is not set!\n", map_name); + ret = -EINVAL; + goto fail; + } + + while ((map[i].rfmax * 1000) < *freq) { + if (map[i + 1].rfmax == 0) { + tda_map("%s: frequency (%d) out of range\n", + map_name, *freq); + ret = -ERANGE; + break; + } + i++; + } + *val = map[i].val; + + tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); +fail: + return ret; +} + +/*---------------------------------------------------------------------*/ + +static struct tda18271_std_map tda18271c1_std_map = { + .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, + .atv_b = { .if_freq = 6750, .std_bits = 0x0e }, + .atv_dk = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_gh = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_i = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_l = { .if_freq = 7750, .std_bits = 0x0f }, + .atv_lc = { .if_freq = 1250, .std_bits = 0x0f }, + .atv_mn = { .if_freq = 5750, .std_bits = 0x0d }, + .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c }, + .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c }, + .dvbt_7 = { .if_freq = 3800, .std_bits = 0x1d }, + .dvbt_8 = { .if_freq = 4300, .std_bits = 0x1e }, + .qam_6 = { .if_freq = 4000, .std_bits = 0x1d }, + .qam_8 = { .if_freq = 5000, .std_bits = 0x1f }, +}; + +static struct tda18271_std_map tda18271c2_std_map = { + .fm_radio = { .if_freq = 1250, .std_bits = 0x18 }, + .atv_b = { .if_freq = 6000, .std_bits = 0x0d }, + .atv_dk = { .if_freq = 6900, .std_bits = 0x0e }, + .atv_gh = { .if_freq = 7100, .std_bits = 0x0e }, + .atv_i = { .if_freq = 7250, .std_bits = 0x0e }, + .atv_l = { .if_freq = 6900, .std_bits = 0x0e }, + .atv_lc = { .if_freq = 1250, .std_bits = 0x0e }, + .atv_mn = { .if_freq = 5400, .std_bits = 0x0c }, + .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c }, + .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c }, + .dvbt_7 = { .if_freq = 3500, .std_bits = 0x1c }, + .dvbt_8 = { .if_freq = 4000, .std_bits = 0x1d }, + .qam_6 = { .if_freq = 4000, .std_bits = 0x1d }, + .qam_8 = { .if_freq = 5000, .std_bits = 0x1f }, +}; + +/*---------------------------------------------------------------------*/ + +static struct tda18271_map_layout tda18271c1_map_layout = { + .main_pll = tda18271c1_main_pll, + .cal_pll = tda18271c1_cal_pll, + + .rf_cal = tda18271c1_rf_cal, + .rf_cal_kmco = tda18271c1_km, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +static struct tda18271_map_layout tda18271c2_map_layout = { + .main_pll = tda18271c2_main_pll, + .cal_pll = tda18271c2_cal_pll, + + .rf_cal = tda18271c2_rf_cal, + .rf_cal_kmco = tda18271c2_km, + + .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, + + .bp_filter = tda18271_bp_filter, + .rf_band = tda18271_rf_band, + .gain_taper = tda18271_gain_taper, + .ir_measure = tda18271_ir_measure, +}; + +int tda18271_assign_map_layout(struct dvb_frontend *fe) +{ + struct tda18271_priv *priv = fe->tuner_priv; + int ret = 0; + + switch (priv->id) { + case TDA18271HDC1: + priv->maps = &tda18271c1_map_layout; + memcpy(&priv->std, &tda18271c1_std_map, + sizeof(struct tda18271_std_map)); + break; + case TDA18271HDC2: + priv->maps = &tda18271c2_map_layout; + memcpy(&priv->std, &tda18271c2_std_map, + sizeof(struct tda18271_std_map)); + break; + default: + ret = -EINVAL; + break; + } + memcpy(priv->rf_cal_state, &tda18271_rf_band_template, + sizeof(tda18271_rf_band_template)); + + return ret; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h new file mode 100644 index 000000000000..24b0e35a2ab3 --- /dev/null +++ b/drivers/media/dvb/frontends/tda18271.h @@ -0,0 +1,78 @@ +/* + tda18271.h - header for the Philips / NXP TDA18271 silicon tuner + + Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __TDA18271_H__ +#define __TDA18271_H__ + +#include <linux/i2c.h> +#include "dvb_frontend.h" + +struct tda18271_std_map_item { + u16 if_freq; + u8 std_bits; +}; + +struct tda18271_std_map { + struct tda18271_std_map_item fm_radio; + struct tda18271_std_map_item atv_b; + struct tda18271_std_map_item atv_dk; + struct tda18271_std_map_item atv_gh; + struct tda18271_std_map_item atv_i; + struct tda18271_std_map_item atv_l; + struct tda18271_std_map_item atv_lc; + struct tda18271_std_map_item atv_mn; + struct tda18271_std_map_item atsc_6; + struct tda18271_std_map_item dvbt_6; + struct tda18271_std_map_item dvbt_7; + struct tda18271_std_map_item dvbt_8; + struct tda18271_std_map_item qam_6; + struct tda18271_std_map_item qam_8; +}; + +enum tda18271_i2c_gate { + TDA18271_GATE_AUTO = 0, + TDA18271_GATE_ANALOG, + TDA18271_GATE_DIGITAL, +}; + +struct tda18271_config { + /* override default if freq / std settings (optional) */ + struct tda18271_std_map *std_map; + + /* use i2c gate provided by analog or digital demod */ + enum tda18271_i2c_gate gate; +}; + +#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg); +#else +static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, + u8 addr, + struct i2c_adapter *i2c, + struct tda18271_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif + +#endif /* __TDA18271_H__ */ diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c index 256fc4bf500b..229b11987a58 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/dvb/frontends/tda827x.c @@ -19,12 +19,16 @@ */ #include <linux/module.h> -#include <linux/dvb/frontend.h> #include <asm/types.h> +#include <linux/dvb/frontend.h> +#include <linux/videodev2.h> #include "tda827x.h" static int debug = 0; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + #define dprintk(args...) \ do { \ if (debug) printk(KERN_DEBUG "tda827x: " args); \ @@ -34,10 +38,57 @@ struct tda827x_priv { int i2c_addr; struct i2c_adapter *i2c_adap; struct tda827x_config *cfg; + + unsigned int sgIF; + unsigned char lpsel; + u32 frequency; u32 bandwidth; }; +static void tda827x_set_std(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + char *mode; + + priv->lpsel = 0; + if (params->std & V4L2_STD_MN) { + priv->sgIF = 92; + priv->lpsel = 1; + mode = "MN"; + } else if (params->std & V4L2_STD_B) { + priv->sgIF = 108; + mode = "B"; + } else if (params->std & V4L2_STD_GH) { + priv->sgIF = 124; + mode = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + priv->sgIF = 124; + mode = "I"; + } else if (params->std & V4L2_STD_DK) { + priv->sgIF = 124; + mode = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + priv->sgIF = 124; + mode = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + priv->sgIF = 20; + mode = "LC"; + } else { + priv->sgIF = 124; + mode = "xx"; + } + + if (params->mode == V4L2_TUNER_RADIO) + priv->sgIF = 88; /* if frequency is 5.5 MHz */ + + dprintk("setting tda827x to system %s\n", mode); +} + + +/* ------------------------------------------------------------------ */ + struct tda827x_data { u32 lomax; u8 spd; @@ -48,7 +99,7 @@ struct tda827x_data { u8 div1p5; }; -static const struct tda827x_data tda827x_dvbt[] = { +static const struct tda827x_data tda827x_table[] = { { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, @@ -106,21 +157,22 @@ static int tda827xo_set_params(struct dvb_frontend *fe, tuner_freq = params->frequency + if_freq; i = 0; - while (tda827x_dvbt[i].lomax < tuner_freq) { - if(tda827x_dvbt[i + 1].lomax == 0) + while (tda827x_table[i].lomax < tuner_freq) { + if (tda827x_table[i + 1].lomax == 0) break; i++; } - N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2); + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); buf[0] = 0; buf[1] = (N>>8) | 0x40; buf[2] = N & 0xff; buf[3] = 0; buf[4] = 0x52; - buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) + - (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp; - buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f; + buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + + tda827x_table[i].bp; + buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; buf[7] = 0xbf; buf[8] = 0x2a; buf[9] = 0x05; @@ -140,7 +192,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe, msleep(500); /* correct CP value */ buf[0] = 0x30; - buf[1] = 0x50 + tda827x_dvbt[i].cp; + buf[1] = 0x50 + tda827x_table[i].cp; msg.len = 2; if (fe->ops.i2c_gate_ctrl) @@ -173,6 +225,102 @@ static int tda827xo_sleep(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ +static int tda827xo_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[8]; + unsigned char reg2[2]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827x_table[i].lomax < N * 62500) { + if (tda827x_table[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827x_table[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0x40; + tuner_reg[4] = 0x52 + (priv->lpsel << 5); + tuner_reg[5] = (tda827x_table[i].spd << 6) + + (tda827x_table[i].div1p5 << 5) + + (tda827x_table[i].bs << 3) + tda827x_table[i].bp; + tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); + tuner_reg[7] = 0x8f; + + msg.buf = tuner_reg; + msg.len = 8; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msg.buf = reg2; + msg.len = 2; + reg2[0] = 0x80; + reg2[1] = 0; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0xbf; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 0x80; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4] + 4; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(1); + reg2[0] = 0x30; + reg2[1] = tuner_reg[4]; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(550); + reg2[0] = 0x30; + reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x60; + reg2[1] = 0x3f; + i2c_transfer(priv->i2c_adap, &msg, 1); + + reg2[0] = 0x80; + reg2[1] = 0x08; /* Vsync en */ + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = freq * 62500; + + return 0; +} + +static void tda827xo_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = { 0x80, 0x0c }; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + + i2c_transfer(priv->i2c_adap, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + struct tda827xa_data { u32 lomax; u8 svco; @@ -212,6 +360,35 @@ static const struct tda827xa_data tda827xa_dvbt[] = { { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} }; +static struct tda827xa_data tda827xa_analog[] = { + { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, + { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, + { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, + { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, + { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, + { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, + { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, + { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, + { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, + { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, + { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} +}; + static int tda827xa_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { @@ -368,6 +545,163 @@ static int tda827xa_sleep(struct dvb_frontend *fe) return 0; } +/* ------------------------------------------------------------------ */ + +static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, + struct analog_parameters *params) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char buf[] = {0x22, 0x01}; + int arg; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + + if (NULL == priv->cfg) { + dprintk("tda827x_config not defined, cannot set LNA gain!\n"); + return; + } + + if (priv->cfg->config) { + if (high) + dprintk("setting LNA to high gain\n"); + else + dprintk("setting LNA to low gain\n"); + } + switch (*priv->cfg->config) { + case 0: /* no LNA */ + break; + case 1: /* switch is GPIO 0 of tda8290 */ + case 2: + /* turn Vsync on */ + if (params->std & V4L2_STD_MN) + arg = 1; + else + arg = 0; + if (priv->cfg->tuner_callback) + priv->cfg->tuner_callback(priv->i2c_adap->algo_data, + 1, arg); + buf[1] = high ? 0 : 1; + if (*priv->cfg->config == 2) + buf[1] = high ? 1 : 0; + i2c_transfer(priv->i2c_adap, &msg, 1); + break; + case 3: /* switch with GPIO of saa713x */ + if (priv->cfg->tuner_callback) + priv->cfg->tuner_callback(priv->i2c_adap->algo_data, + 0, high); + break; + } +} + +static int tda827xa_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + unsigned char tuner_reg[11]; + u32 N; + int i; + struct tda827x_priv *priv = fe->tuner_priv; + struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, + .buf = tuner_reg, .len = sizeof(tuner_reg) }; + unsigned int freq = params->frequency; + + tda827x_set_std(fe, params); + + tda827xa_lna_gain(fe, 1, params); + msleep(10); + + if (params->mode == V4L2_TUNER_RADIO) + freq = freq / 1000; + + N = freq + priv->sgIF; + + i = 0; + while (tda827xa_analog[i].lomax < N * 62500) { + if (tda827xa_analog[i + 1].lomax == 0) + break; + i++; + } + + N = N << tda827xa_analog[i].spd; + + tuner_reg[0] = 0; + tuner_reg[1] = (unsigned char)(N>>8); + tuner_reg[2] = (unsigned char) N; + tuner_reg[3] = 0; + tuner_reg[4] = 0x16; + tuner_reg[5] = (tda827xa_analog[i].spd << 5) + + (tda827xa_analog[i].svco << 3) + + tda827xa_analog[i].sbs; + tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); + tuner_reg[7] = 0x1c; + tuner_reg[8] = 4; + tuner_reg[9] = 0x20; + tuner_reg[10] = 0x00; + msg.len = 11; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x90; + tuner_reg[1] = 0xff; + tuner_reg[2] = 0xe0; + tuner_reg[3] = 0; + tuner_reg[4] = 0x99 + (priv->lpsel << 1); + msg.len = 5; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xa0; + tuner_reg[1] = 0xc0; + msg.len = 2; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x30; + tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msg.flags = I2C_M_RD; + i2c_transfer(priv->i2c_adap, &msg, 1); + msg.flags = 0; + tuner_reg[1] >>= 4; + dprintk("AGC2 gain is: %d\n", tuner_reg[1]); + if (tuner_reg[1] < 1) + tda827xa_lna_gain(fe, 0, params); + + msleep(100); + tuner_reg[0] = 0x60; + tuner_reg[1] = 0x3c; + i2c_transfer(priv->i2c_adap, &msg, 1); + + msleep(163); + tuner_reg[0] = 0x50; + tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0x80; + tuner_reg[1] = 0x28; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xb0; + tuner_reg[1] = 0x01; + i2c_transfer(priv->i2c_adap, &msg, 1); + + tuner_reg[0] = 0xc0; + tuner_reg[1] = 0x19 + (priv->lpsel << 1); + i2c_transfer(priv->i2c_adap, &msg, 1); + + priv->frequency = freq * 62500; + + return 0; +} + +static void tda827xa_agcf(struct dvb_frontend *fe) +{ + struct tda827x_priv *priv = fe->tuner_priv; + unsigned char data[] = {0x80, 0x2c}; + struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, + .buf = data, .len = 2}; + i2c_transfer(priv->i2c_adap, &msg, 1); +} + +/* ------------------------------------------------------------------ */ + static int tda827x_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -430,6 +764,7 @@ static struct dvb_tuner_ops tda827xo_tuner_ops = { .init = tda827x_initial_init, .sleep = tda827x_initial_sleep, .set_params = tda827xo_set_params, + .set_analog_params = tda827xo_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -445,6 +780,7 @@ static struct dvb_tuner_ops tda827xa_tuner_ops = { .init = tda827x_init, .sleep = tda827xa_sleep, .set_params = tda827xa_set_params, + .set_analog_params = tda827xa_set_analog_params, .get_frequency = tda827x_get_frequency, .get_bandwidth = tda827x_get_bandwidth, }; @@ -465,9 +801,13 @@ static int tda827x_probe_version(struct dvb_frontend *fe) dprintk("tda827x tuner found\n"); fe->ops.tuner_ops.init = tda827x_init; fe->ops.tuner_ops.sleep = tda827xo_sleep; + if (priv->cfg) + priv->cfg->agcf = tda827xo_agcf; } else { dprintk("tda827xa tuner found\n"); memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); + if (priv->cfg) + priv->cfg->agcf = tda827xa_agcf; } return 0; } @@ -487,16 +827,13 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, priv->i2c_adap = i2c; priv->cfg = cfg; memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; + dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); + return fe; } - -EXPORT_SYMBOL(tda827x_attach); - -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); +EXPORT_SYMBOL_GPL(tda827x_attach); MODULE_DESCRIPTION("DVB TDA827x driver"); MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h index 69e8263d6d59..92eb65b4012b 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/dvb/frontends/tda827x.h @@ -29,9 +29,16 @@ struct tda827x_config { + /* saa7134 - provided callbacks */ void (*lna_gain) (struct dvb_frontend *fe, int high); int (*init) (struct dvb_frontend *fe); int (*sleep) (struct dvb_frontend *fe); + + /* interface to tda829x driver */ + unsigned int *config; + int (*tuner_callback) (void *dev, int command, int arg); + + void (*agcf)(struct dvb_frontend *fe); }; diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index 60433b5011fd..8791701c8f25 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -65,7 +65,7 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("ves1820: %s(): writereg error (reg == 0x%02x," + printk("ves1820: %s(): writereg error (reg == 0x%02x, " "val == 0x%02x, ret == %i)\n", __FUNCTION__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; @@ -84,7 +84,7 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("ves1820: %s(): readreg error (reg == 0x%02x," + printk("ves1820: %s(): readreg error (reg == 0x%02x, " "ret == %i)\n", __FUNCTION__, reg, ret); return b1[0]; diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c new file mode 100644 index 000000000000..f642ca200b59 --- /dev/null +++ b/drivers/media/dvb/frontends/xc5000.c @@ -0,0 +1,964 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Xceive Corporation + * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/videodev2.h> +#include <linux/delay.h> +#include <linux/dvb/frontend.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +#include "xc5000.h" +#include "xc5000_priv.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); + +#define dprintk(level,fmt, arg...) if (debug >= level) \ + printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) + +#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw" +#define XC5000_DEFAULT_FIRMWARE_SIZE 12332 + +/* Misc Defines */ +#define MAX_TV_STANDARD 23 +#define XC_MAX_I2C_WRITE_LENGTH 64 + +/* Signal Types */ +#define XC_RF_MODE_AIR 0 +#define XC_RF_MODE_CABLE 1 + +/* Result codes */ +#define XC_RESULT_SUCCESS 0 +#define XC_RESULT_RESET_FAILURE 1 +#define XC_RESULT_I2C_WRITE_FAILURE 2 +#define XC_RESULT_I2C_READ_FAILURE 3 +#define XC_RESULT_OUT_OF_RANGE 5 + +/* Product id */ +#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 +#define XC_PRODUCT_ID_FW_LOADED 0x1388 + +/* Registers */ +#define XREG_INIT 0x00 +#define XREG_VIDEO_MODE 0x01 +#define XREG_AUDIO_MODE 0x02 +#define XREG_RF_FREQ 0x03 +#define XREG_D_CODE 0x04 +#define XREG_IF_OUT 0x05 +#define XREG_SEEK_MODE 0x07 +#define XREG_POWER_DOWN 0x0A +#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ +#define XREG_SMOOTHEDCVBS 0x0E +#define XREG_XTALFREQ 0x0F +#define XREG_FINERFFREQ 0x10 +#define XREG_DDIMODE 0x11 + +#define XREG_ADC_ENV 0x00 +#define XREG_QUALITY 0x01 +#define XREG_FRAME_LINES 0x02 +#define XREG_HSYNC_FREQ 0x03 +#define XREG_LOCK 0x04 +#define XREG_FREQ_ERROR 0x05 +#define XREG_SNR 0x06 +#define XREG_VERSION 0x07 +#define XREG_PRODUCT_ID 0x08 +#define XREG_BUSY 0x09 + +/* + Basic firmware description. This will remain with + the driver for documentation purposes. + + This represents an I2C firmware file encoded as a + string of unsigned char. Format is as follows: + + char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB + char[1 ]=len0_LSB -> length of first write transaction + char[2 ]=data0 -> first byte to be sent + char[3 ]=data1 + char[4 ]=data2 + char[ ]=... + char[M ]=dataN -> last byte to be sent + char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB + char[M+2]=len1_LSB -> length of second write transaction + char[M+3]=data0 + char[M+4]=data1 + ... + etc. + + The [len] value should be interpreted as follows: + + len= len_MSB _ len_LSB + len=1111_1111_1111_1111 : End of I2C_SEQUENCE + len=0000_0000_0000_0000 : Reset command: Do hardware reset + len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) + len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms + + For the RESET and WAIT commands, the two following bytes will contain + immediately the length of the following transaction. + +*/ +typedef struct { + char *Name; + u16 AudioMode; + u16 VideoMode; +} XC_TV_STANDARD; + +/* Tuner standards */ +#define MN_NTSC_PAL_BTSC 0 +#define MN_NTSC_PAL_A2 1 +#define MN_NTSC_PAL_EIAJ 2 +#define MN_NTSC_PAL_Mono 3 +#define BG_PAL_A2 4 +#define BG_PAL_NICAM 5 +#define BG_PAL_MONO 6 +#define I_PAL_NICAM 7 +#define I_PAL_NICAM_MONO 8 +#define DK_PAL_A2 9 +#define DK_PAL_NICAM 10 +#define DK_PAL_MONO 11 +#define DK_SECAM_A2DK1 12 +#define DK_SECAM_A2LDK3 13 +#define DK_SECAM_A2MONO 14 +#define L_SECAM_NICAM 15 +#define LC_SECAM_NICAM 16 +#define DTV6 17 +#define DTV8 18 +#define DTV7_8 19 +#define DTV7 20 +#define FM_Radio_INPUT2 21 +#define FM_Radio_INPUT1 22 + +XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { + {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, + {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, + {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, + {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, + {"B/G-PAL-A2", 0x0A00, 0x8049}, + {"B/G-PAL-NICAM", 0x0C04, 0x8049}, + {"B/G-PAL-MONO", 0x0878, 0x8059}, + {"I-PAL-NICAM", 0x1080, 0x8009}, + {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, + {"D/K-PAL-A2", 0x1600, 0x8009}, + {"D/K-PAL-NICAM", 0x0E80, 0x8009}, + {"D/K-PAL-MONO", 0x1478, 0x8009}, + {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, + {"D/K-SECAM-A2 L/DK3",0x0E00, 0x8009}, + {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, + {"L-SECAM-NICAM", 0x8E82, 0x0009}, + {"L'-SECAM-NICAM", 0x8E82, 0x4009}, + {"DTV6", 0x00C0, 0x8002}, + {"DTV8", 0x00C0, 0x800B}, + {"DTV7/8", 0x00C0, 0x801B}, + {"DTV7", 0x00C0, 0x8007}, + {"FM Radio-INPUT2", 0x9802, 0x9002}, + {"FM Radio-INPUT1", 0x0208, 0x9002} +}; + +static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len); +static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len); +static void xc5000_TunerReset(struct dvb_frontend *fe); + +static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) +{ + return xc5000_writeregs(priv, buf, len) + ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS; +} + +static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) +{ + return xc5000_readregs(priv, buf, len) + ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS; +} + +static int xc_reset(struct dvb_frontend *fe) +{ + xc5000_TunerReset(fe); + return XC_RESULT_SUCCESS; +} + +static void xc_wait(int wait_ms) +{ + msleep(wait_ms); +} + +static void xc5000_TunerReset(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __FUNCTION__); + + if (priv->cfg->tuner_callback) { + ret = priv->cfg->tuner_callback(priv->cfg->priv, + XC5000_TUNER_RESET, 0); + if (ret) + printk(KERN_ERR "xc5000: reset failed\n"); + } else + printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); +} + +static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) +{ + u8 buf[4]; + int WatchDogTimer = 5; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + buf[2] = (i2cData >> 8) & 0xFF; + buf[3] = i2cData & 0xFF; + result = xc_send_i2c_data(priv, buf, 4); + if (result == XC_RESULT_SUCCESS) { + /* wait for busy flag to clear */ + while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { + buf[0] = 0; + buf[1] = XREG_BUSY; + + result = xc_send_i2c_data(priv, buf, 2); + if (result == XC_RESULT_SUCCESS) { + result = xc_read_i2c_data(priv, buf, 2); + if (result == XC_RESULT_SUCCESS) { + if ((buf[0] == 0) && (buf[1] == 0)) { + /* busy flag cleared */ + break; + } else { + xc_wait(100); /* wait 5 ms */ + WatchDogTimer--; + } + } + } + } + } + if (WatchDogTimer < 0) + result = XC_RESULT_I2C_WRITE_FAILURE; + + return result; +} + +static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData) +{ + u8 buf[2]; + int result; + + buf[0] = (regAddr >> 8) & 0xFF; + buf[1] = regAddr & 0xFF; + result = xc_send_i2c_data(priv, buf, 2); + if (result != XC_RESULT_SUCCESS) + return result; + + result = xc_read_i2c_data(priv, buf, 2); + if (result != XC_RESULT_SUCCESS) + return result; + + *i2cData = buf[0] * 256 + buf[1]; + return result; +} + +static int xc_load_i2c_sequence(struct dvb_frontend *fe, u8 i2c_sequence[]) +{ + struct xc5000_priv *priv = fe->tuner_priv; + + int i, nbytes_to_send, result; + unsigned int len, pos, index; + u8 buf[XC_MAX_I2C_WRITE_LENGTH]; + + index=0; + while ((i2c_sequence[index]!=0xFF) || (i2c_sequence[index+1]!=0xFF)) { + len = i2c_sequence[index]* 256 + i2c_sequence[index+1]; + if (len == 0x0000) { + /* RESET command */ + result = xc_reset(fe); + index += 2; + if (result != XC_RESULT_SUCCESS) + return result; + } else if (len & 0x8000) { + /* WAIT command */ + xc_wait(len & 0x7FFF); + index += 2; + } else { + /* Send i2c data whilst ensuring individual transactions + * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. + */ + index += 2; + buf[0] = i2c_sequence[index]; + buf[1] = i2c_sequence[index + 1]; + pos = 2; + while (pos < len) { + if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) { + nbytes_to_send = XC_MAX_I2C_WRITE_LENGTH; + } else { + nbytes_to_send = (len - pos + 2); + } + for (i=2; i<nbytes_to_send; i++) { + buf[i] = i2c_sequence[index + pos + i - 2]; + } + result = xc_send_i2c_data(priv, buf, nbytes_to_send); + + if (result != XC_RESULT_SUCCESS) + return result; + + pos += nbytes_to_send - 2; + } + index += len; + } + } + return XC_RESULT_SUCCESS; +} + +static int xc_initialize(struct xc5000_priv *priv) +{ + dprintk(1, "%s()\n", __FUNCTION__); + return xc_write_reg(priv, XREG_INIT, 0); +} + +static int xc_SetTVStandard(struct xc5000_priv *priv, + u16 VideoMode, u16 AudioMode) +{ + int ret; + dprintk(1, "%s(0x%04x,0x%04x)\n", __FUNCTION__, VideoMode, AudioMode); + dprintk(1, "%s() Standard = %s\n", + __FUNCTION__, + XC5000_Standard[priv->video_standard].Name); + + ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); + if (ret == XC_RESULT_SUCCESS) + ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); + + return ret; +} + +static int xc_shutdown(struct xc5000_priv *priv) +{ + return 0; + /* Fixme: cannot bring tuner back alive once shutdown + * without reloading the driver modules. + * return xc_write_reg(priv, XREG_POWER_DOWN, 0); + */ +} + +static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) +{ + dprintk(1, "%s(%d) Source = %s\n", __FUNCTION__, rf_mode, + rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); + + if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) + { + rf_mode = XC_RF_MODE_CABLE; + printk(KERN_ERR + "%s(), Invalid mode, defaulting to CABLE", + __FUNCTION__); + } + return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); +} + +static const struct dvb_tuner_ops xc5000_tuner_ops; + +static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) +{ + u16 freq_code; + + dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); + + if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || + (freq_hz < xc5000_tuner_ops.info.frequency_min)) + return XC_RESULT_OUT_OF_RANGE; + + freq_code = (u16)(freq_hz / 15625); + + return xc_write_reg(priv, XREG_RF_FREQ, freq_code); +} + + +static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) +{ + u32 freq_code = (freq_khz * 1024)/1000; + dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", + __FUNCTION__, freq_khz, freq_code); + + return xc_write_reg(priv, XREG_IF_OUT, freq_code); +} + + +static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) +{ + return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope); +} + +static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) +{ + int result; + u16 regData; + u32 tmp; + + result = xc_read_reg(priv, XREG_FREQ_ERROR, ®Data); + if (result) + return result; + + tmp = (u32)regData; + (*freq_error_hz) = (tmp * 15625) / 1000; + return result; +} + +static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) +{ + return xc_read_reg(priv, XREG_LOCK, lock_status); +} + +static int xc_get_version(struct xc5000_priv *priv, + u8 *hw_majorversion, u8 *hw_minorversion, + u8 *fw_majorversion, u8 *fw_minorversion) +{ + u16 data; + int result; + + result = xc_read_reg(priv, XREG_VERSION, &data); + if (result) + return result; + + (*hw_majorversion) = (data >> 12) & 0x0F; + (*hw_minorversion) = (data >> 8) & 0x0F; + (*fw_majorversion) = (data >> 4) & 0x0F; + (*fw_minorversion) = data & 0x0F; + + return 0; +} + +static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) +{ + u16 regData; + int result; + + result = xc_read_reg(priv, XREG_HSYNC_FREQ, ®Data); + if (result) + return result; + + (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; + return result; +} + +static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) +{ + return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines); +} + +static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) +{ + return xc_read_reg(priv, XREG_QUALITY, quality); +} + +static u16 WaitForLock(struct xc5000_priv *priv) +{ + u16 lockState = 0; + int watchDogCount = 40; + + while ((lockState == 0) && (watchDogCount > 0)) { + xc_get_lock_status(priv, &lockState); + if (lockState != 1) { + xc_wait(5); + watchDogCount--; + } + } + return lockState; +} + +static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz) +{ + int found = 0; + + dprintk(1, "%s(%u)\n", __FUNCTION__, freq_hz); + + if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) + return 0; + + if (WaitForLock(priv) == 1) + found = 1; + + return found; +} + +static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) +{ + u8 buf[2] = { reg >> 8, reg & 0xff }; + u8 bval[2] = { 0, 0 }; + struct i2c_msg msg[2] = { + { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = &buf[0], .len = 2 }, + { .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, + }; + + if (i2c_transfer(priv->i2c, msg, 2) != 2) { + printk(KERN_WARNING "xc5000: I2C read failed\n"); + return -EREMOTEIO; + } + + *val = (bval[0] << 8) | bval[1]; + return 0; +} + +static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = 0, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", + (int)len); + return -EREMOTEIO; + } + return 0; +} + +static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len) +{ + struct i2c_msg msg = { .addr = priv->cfg->i2c_address, + .flags = I2C_M_RD, .buf = buf, .len = len }; + + if (i2c_transfer(priv->i2c, &msg, 1) != 1) { + printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n",(int)len); + return -EREMOTEIO; + } + return 0; +} + +static int xc5000_fwupload(struct dvb_frontend* fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + const struct firmware *fw; + int ret; + + /* request the firmware, this will block and timeout */ + printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", + XC5000_DEFAULT_FIRMWARE); + + ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE, &priv->i2c->dev); + if (ret) { + printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); + ret = XC_RESULT_RESET_FAILURE; + goto out; + } else { + printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n", + fw->size); + ret = XC_RESULT_SUCCESS; + } + + if (fw->size != XC5000_DEFAULT_FIRMWARE_SIZE) { + printk(KERN_ERR "xc5000: firmware incorrect size\n"); + ret = XC_RESULT_RESET_FAILURE; + } else { + printk(KERN_INFO "xc5000: firmware upload\n"); + ret = xc_load_i2c_sequence(fe, fw->data ); + } + +out: + release_firmware(fw); + return ret; +} + +static void xc_debug_dump(struct xc5000_priv *priv) +{ + u16 adc_envelope; + u32 freq_error_hz = 0; + u16 lock_status; + u32 hsync_freq_hz = 0; + u16 frame_lines; + u16 quality; + u8 hw_majorversion = 0, hw_minorversion = 0; + u8 fw_majorversion = 0, fw_minorversion = 0; + + /* Wait for stats to stabilize. + * Frame Lines needs two frame times after initial lock + * before it is valid. + */ + xc_wait(100); + + xc_get_ADC_Envelope(priv, &adc_envelope); + dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); + + xc_get_frequency_error(priv, &freq_error_hz); + dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); + + xc_get_lock_status(priv, &lock_status); + dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", + lock_status); + + xc_get_version(priv, &hw_majorversion, &hw_minorversion, + &fw_majorversion, &fw_minorversion); + dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", + hw_majorversion, hw_minorversion, + fw_majorversion, fw_minorversion); + + xc_get_hsync_freq(priv, &hsync_freq_hz); + dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); + + xc_get_frame_lines(priv, &frame_lines); + dprintk(1, "*** Frame lines = %d\n", frame_lines); + + xc_get_quality(priv, &quality); + dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); +} + +static int xc5000_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s() frequency=%d (Hz)\n", __FUNCTION__, params->frequency); + + switch(params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + dprintk(1, "%s() VSB modulation\n", __FUNCTION__); + priv->rf_mode = XC_RF_MODE_AIR; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + case QAM_64: + case QAM_256: + case QAM_AUTO: + dprintk(1, "%s() QAM modulation\n", __FUNCTION__); + priv->rf_mode = XC_RF_MODE_CABLE; + priv->freq_hz = params->frequency - 1750000; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->video_standard = DTV6; + break; + default: + return -EINVAL; + } + + dprintk(1, "%s() frequency=%d (compensated)\n", + __FUNCTION__, priv->freq_hz); + + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + ret = xc_set_IF_frequency(priv, priv->cfg->if_khz); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", + priv->cfg->if_khz); + return -EIO; + } + + xc_tune_channel(priv, priv->freq_hz); + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe); + +static int xc5000_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + if(priv->fwloaded == 0) + xc_load_fw_and_init_tuner(fe); + + dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", + __FUNCTION__, params->frequency); + + priv->rf_mode = XC_RF_MODE_CABLE; /* Fix me: it could be air. */ + + /* params->frequency is in units of 62.5khz */ + priv->freq_hz = params->frequency * 62500; + + /* FIX ME: Some video standards may have several possible audio + standards. We simply default to one of them here. + */ + if(params->std & V4L2_STD_MN) { + /* default to BTSC audio standard */ + priv->video_standard = MN_NTSC_PAL_BTSC; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_BG) { + /* default to NICAM audio standard */ + priv->video_standard = BG_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_I) { + /* default to NICAM audio standard */ + priv->video_standard = I_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_PAL_DK) { + /* default to NICAM audio standard */ + priv->video_standard = DK_PAL_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_DK) { + /* default to A2 DK1 audio standard */ + priv->video_standard = DK_SECAM_A2DK1; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_L) { + priv->video_standard = L_SECAM_NICAM; + goto tune_channel; + } + + if(params->std & V4L2_STD_SECAM_LC) { + priv->video_standard = LC_SECAM_NICAM; + goto tune_channel; + } + +tune_channel: + ret = xc_SetSignalSource(priv, priv->rf_mode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: xc_SetSignalSource(%d) failed\n", + priv->rf_mode); + return -EREMOTEIO; + } + + ret = xc_SetTVStandard(priv, + XC5000_Standard[priv->video_standard].VideoMode, + XC5000_Standard[priv->video_standard].AudioMode); + if (ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); + return -EREMOTEIO; + } + + xc_tune_channel(priv, priv->freq_hz); + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + *freq = priv->freq_hz; + return 0; +} + +static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + + *bw = priv->bandwidth; + return 0; +} + +static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct xc5000_priv *priv = fe->tuner_priv; + u16 lock_status = 0; + + xc_get_lock_status(priv, &lock_status); + + dprintk(1, "%s() lock_status = 0x%08x\n", __FUNCTION__, lock_status); + + *status = lock_status; + + return 0; +} + +static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret = 0; + + if (priv->fwloaded == 0) { + ret = xc5000_fwupload(fe); + if (ret != XC_RESULT_SUCCESS) + return ret; + priv->fwloaded = 1; + } + + /* Start the tuner self-calibration process */ + ret |= xc_initialize(priv); + + /* Wait for calibration to complete. + * We could continue but XC5000 will clock stretch subsequent + * I2C transactions until calibration is complete. This way we + * don't have to rely on clock stretching working. + */ + xc_wait( 100 ); + + /* Default to "CABLE" mode */ + ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); + + return ret; +} + +static int xc5000_sleep(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + int ret; + + dprintk(1, "%s()\n", __FUNCTION__); + + /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized + * once shutdown without reloading the driver. Maybe I am not + * doing something right. + * + */ + + ret = xc_shutdown(priv); + if(ret != XC_RESULT_SUCCESS) { + printk(KERN_ERR + "xc5000: %s() unable to shutdown tuner\n", + __FUNCTION__); + return -EREMOTEIO; + } + else { + /* priv->fwloaded = 0; */ + return XC_RESULT_SUCCESS; + } +} + +static int xc5000_init(struct dvb_frontend *fe) +{ + struct xc5000_priv *priv = fe->tuner_priv; + dprintk(1, "%s()\n", __FUNCTION__); + + if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) { + printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); + return -EREMOTEIO; + } + + if (debug) + xc_debug_dump(priv); + + return 0; +} + +static int xc5000_release(struct dvb_frontend *fe) +{ + dprintk(1, "%s()\n", __FUNCTION__); + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static const struct dvb_tuner_ops xc5000_tuner_ops = { + .info = { + .name = "Xceive XC5000", + .frequency_min = 1000000, + .frequency_max = 1023000000, + .frequency_step = 50000, + }, + + .release = xc5000_release, + .init = xc5000_init, + .sleep = xc5000_sleep, + + .set_params = xc5000_set_params, + .set_analog_params = xc5000_set_analog_params, + .get_frequency = xc5000_get_frequency, + .get_bandwidth = xc5000_get_bandwidth, + .get_status = xc5000_get_status +}; + +struct dvb_frontend * xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc5000_config *cfg) +{ + struct xc5000_priv *priv = NULL; + u16 id = 0; + + dprintk(1, "%s()\n", __FUNCTION__); + + priv = kzalloc(sizeof(struct xc5000_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + + priv->cfg = cfg; + priv->bandwidth = BANDWIDTH_6_MHZ; + priv->i2c = i2c; + + /* Check if firmware has been loaded. It is possible that another + instance of the driver has loaded the firmware. + */ + if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) { + kfree(priv); + return NULL; + } + + switch(id) { + case XC_PRODUCT_ID_FW_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has been loaded previously\n"); + priv->fwloaded = 1; + break; + case XC_PRODUCT_ID_FW_NOT_LOADED: + printk(KERN_INFO + "xc5000: Successfully identified at address 0x%02x\n", + cfg->i2c_address); + printk(KERN_INFO + "xc5000: Firmware has not been loaded previously\n"); + priv->fwloaded = 0; + break; + default: + printk(KERN_ERR + "xc5000: Device not found at addr 0x%02x (0x%x)\n", + cfg->i2c_address, id); + kfree(priv); + return NULL; + } + + memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + fe->tuner_priv = priv; + + return fe; +} +EXPORT_SYMBOL(xc5000_attach); + +MODULE_AUTHOR("Steven Toth"); +MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h new file mode 100644 index 000000000000..e0e84562aed1 --- /dev/null +++ b/drivers/media/dvb/frontends/xc5000.h @@ -0,0 +1,62 @@ +/* + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 __XC5000_H__ +#define __XC5000_H__ + +#include <linux/firmware.h> + +struct dvb_frontend; +struct i2c_adapter; + +struct xc5000_config { + u8 i2c_address; + u32 if_khz; + + /* For each bridge framework, when it attaches either analog or digital, + * it has to store a reference back to its _core equivalent structure, + * so that it can service the hardware by steering gpio's etc. + * Each bridge implementation is different so cast priv accordingly. + * The xc5000 driver cares not for this value, other than ensuring + * it's passed back to a bridge during tuner_callback(). + */ + void *priv; + int (*tuner_callback) (void *priv, int command, int arg); +}; + +/* xc5000 callback command */ +#define XC5000_TUNER_RESET 0 + +#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) +extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc5000_config *cfg); +#else +static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + struct xc5000_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif // CONFIG_DVB_TUNER_XC5000 + +#endif // __XC5000_H__ diff --git a/drivers/i2c/busses/i2c-au1550.h b/drivers/media/dvb/frontends/xc5000_priv.h index fce15d161ae7..13b2d19341da 100644 --- a/drivers/i2c/busses/i2c-au1550.h +++ b/drivers/media/dvb/frontends/xc5000_priv.h @@ -1,6 +1,7 @@ /* - * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com> - * 2.6 port by Matt Porter <mporter@kernel.crashing.org> + * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" + * + * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -10,6 +11,7 @@ * 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 @@ -17,16 +19,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef I2C_AU1550_H -#define I2C_AU1550_H +#ifndef XC5000_PRIV_H +#define XC5000_PRIV_H -struct i2c_au1550_data { - u32 psc_base; - int xfer_timeout; - int ack_timeout; -}; +struct xc5000_priv { + struct xc5000_config *cfg; + struct i2c_adapter *i2c; -int i2c_au1550_add_bus(struct i2c_adapter *); -int i2c_au1550_del_bus(struct i2c_adapter *); + u32 freq_hz; + u32 bandwidth; + u8 video_standard; + u8 rf_mode; + u8 fwloaded; +}; -#endif /* I2C_AU1550_H */ +#endif diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index 0106df4c55e8..276e3b631dc2 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au> + * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au> * * 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 @@ -16,7 +16,7 @@ * * 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.= + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> @@ -25,6 +25,7 @@ #include <linux/delay.h> #include <linux/string.h> #include <linux/slab.h> +#include <asm/div64.h> #include "dvb_frontend.h" #include "zl10353_priv.h" @@ -35,6 +36,8 @@ struct zl10353_state { struct dvb_frontend frontend; struct zl10353_config config; + + enum fe_bandwidth bandwidth; }; static int debug; @@ -122,9 +125,10 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, enum fe_bandwidth bandwidth, u16 *nominal_rate) { - u32 adc_clock = 45056; /* 45.056 MHz */ - u8 bw; struct zl10353_state *state = fe->demodulator_priv; + u32 adc_clock = 450560; /* 45.056 MHz */ + u64 value; + u8 bw; if (state->config.adc_clock) adc_clock = state->config.adc_clock; @@ -142,12 +146,44 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe, break; } - *nominal_rate = (bw * (1 << 23) / 7 * 125 + adc_clock / 2) / adc_clock; + value = (u64)10 * (1 << 23) / 7 * 125; + value = (bw * value) + adc_clock / 2; + do_div(value, adc_clock); + *nominal_rate = value; dprintk("%s: bw %d, adc_clock %d => 0x%x\n", __FUNCTION__, bw, adc_clock, *nominal_rate); } +static void zl10353_calc_input_freq(struct dvb_frontend *fe, + u16 *input_freq) +{ + struct zl10353_state *state = fe->demodulator_priv; + u32 adc_clock = 450560; /* 45.056 MHz */ + int if2 = 361667; /* 36.1667 MHz */ + int ife; + u64 value; + + if (state->config.adc_clock) + adc_clock = state->config.adc_clock; + if (state->config.if2) + if2 = state->config.if2; + + if (adc_clock >= if2 * 2) + ife = if2; + else { + ife = adc_clock - (if2 % adc_clock); + if (ife > adc_clock / 2) + ife = adc_clock - ife; + } + value = (u64)65536 * ife + adc_clock / 2; + do_div(value, adc_clock); + *input_freq = -value; + + dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n", + __FUNCTION__, if2, ife, adc_clock, -(int)value, *input_freq); +} + static int zl10353_sleep(struct dvb_frontend *fe) { static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 }; @@ -160,64 +196,276 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { struct zl10353_state *state = fe->demodulator_priv; - u16 nominal_rate; - u8 pllbuf[6] = { 0x67 }; + u16 nominal_rate, input_freq; + u8 pllbuf[6] = { 0x67 }, acq_ctl = 0; + u16 tps = 0; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; - /* These settings set "auto-everything" and start the FSM. */ - zl10353_single_write(fe, 0x55, 0x80); + zl10353_single_write(fe, RESET, 0x80); udelay(200); zl10353_single_write(fe, 0xEA, 0x01); udelay(200); zl10353_single_write(fe, 0xEA, 0x00); - zl10353_single_write(fe, 0x56, 0x28); - zl10353_single_write(fe, 0x89, 0x20); - zl10353_single_write(fe, 0x5E, 0x00); + zl10353_single_write(fe, AGC_TARGET, 0x28); + + if (op->transmission_mode != TRANSMISSION_MODE_AUTO) + acq_ctl |= (1 << 0); + if (op->guard_interval != GUARD_INTERVAL_AUTO) + acq_ctl |= (1 << 1); + zl10353_single_write(fe, ACQ_CTL, acq_ctl); - zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate); + switch (op->bandwidth) { + case BANDWIDTH_6_MHZ: + /* These are extrapolated from the 7 and 8MHz values */ + zl10353_single_write(fe, MCLK_RATIO, 0x97); + zl10353_single_write(fe, 0x64, 0x34); + break; + case BANDWIDTH_7_MHZ: + zl10353_single_write(fe, MCLK_RATIO, 0x86); + zl10353_single_write(fe, 0x64, 0x35); + break; + case BANDWIDTH_8_MHZ: + default: + zl10353_single_write(fe, MCLK_RATIO, 0x75); + zl10353_single_write(fe, 0x64, 0x36); + } + + zl10353_calc_nominal_rate(fe, op->bandwidth, &nominal_rate); zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate)); zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate)); + state->bandwidth = op->bandwidth; + + zl10353_calc_input_freq(fe, &input_freq); + zl10353_single_write(fe, INPUT_FREQ_1, msb(input_freq)); + zl10353_single_write(fe, INPUT_FREQ_0, lsb(input_freq)); + + /* Hint at TPS settings */ + switch (op->code_rate_HP) { + case FEC_2_3: + tps |= (1 << 7); + break; + case FEC_3_4: + tps |= (2 << 7); + break; + case FEC_5_6: + tps |= (3 << 7); + break; + case FEC_7_8: + tps |= (4 << 7); + break; + case FEC_1_2: + case FEC_AUTO: + break; + default: + return -EINVAL; + } + + switch (op->code_rate_LP) { + case FEC_2_3: + tps |= (1 << 4); + break; + case FEC_3_4: + tps |= (2 << 4); + break; + case FEC_5_6: + tps |= (3 << 4); + break; + case FEC_7_8: + tps |= (4 << 4); + break; + case FEC_1_2: + case FEC_AUTO: + break; + case FEC_NONE: + if (op->hierarchy_information == HIERARCHY_AUTO || + op->hierarchy_information == HIERARCHY_NONE) + break; + default: + return -EINVAL; + } + + switch (op->constellation) { + case QPSK: + break; + case QAM_AUTO: + case QAM_16: + tps |= (1 << 13); + break; + case QAM_64: + tps |= (2 << 13); + break; + default: + return -EINVAL; + } + + switch (op->transmission_mode) { + case TRANSMISSION_MODE_2K: + case TRANSMISSION_MODE_AUTO: + break; + case TRANSMISSION_MODE_8K: + tps |= (1 << 0); + break; + default: + return -EINVAL; + } + + switch (op->guard_interval) { + case GUARD_INTERVAL_1_32: + case GUARD_INTERVAL_AUTO: + break; + case GUARD_INTERVAL_1_16: + tps |= (1 << 2); + break; + case GUARD_INTERVAL_1_8: + tps |= (2 << 2); + break; + case GUARD_INTERVAL_1_4: + tps |= (3 << 2); + break; + default: + return -EINVAL; + } + + switch (op->hierarchy_information) { + case HIERARCHY_AUTO: + case HIERARCHY_NONE: + break; + case HIERARCHY_1: + tps |= (1 << 10); + break; + case HIERARCHY_2: + tps |= (2 << 10); + break; + case HIERARCHY_4: + tps |= (3 << 10); + break; + default: + return -EINVAL; + } + + zl10353_single_write(fe, TPS_GIVEN_1, msb(tps)); + zl10353_single_write(fe, TPS_GIVEN_0, lsb(tps)); - zl10353_single_write(fe, 0x6C, 0xCD); - zl10353_single_write(fe, 0x6D, 0x7E); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - // if there is no attached secondary tuner, we call set_params to program - // a potential tuner attached somewhere else + /* + * If there is no tuner attached to the secondary I2C bus, we call + * set_params to program a potential tuner attached somewhere else. + * Otherwise, we update the PLL registers via calc_regs. + */ if (state->config.no_tuner) { if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe, param); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } + } else if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, pllbuf + 1, 5); + pllbuf[1] <<= 1; + zl10353_write(fe, pllbuf, sizeof(pllbuf)); } - // if pllbuf is defined, retrieve the settings - if (fe->ops.tuner_ops.calc_regs) { - fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5); - pllbuf[1] <<= 1; - } else { - // fake pllbuf settings - pllbuf[1] = 0x61 << 1; - pllbuf[2] = 0; - pllbuf[3] = 0; - pllbuf[3] = 0; - pllbuf[4] = 0; + zl10353_single_write(fe, 0x5F, 0x13); + + /* If no attached tuner or invalid PLL registers, just start the FSM. */ + if (state->config.no_tuner || fe->ops.tuner_ops.calc_regs == NULL) + zl10353_single_write(fe, FSM_GO, 0x01); + else + zl10353_single_write(fe, TUNER_GO, 0x01); + + return 0; +} + +static int zl10353_get_parameters(struct dvb_frontend *fe, + struct dvb_frontend_parameters *param) +{ + struct zl10353_state *state = fe->demodulator_priv; + struct dvb_ofdm_parameters *op = ¶m->u.ofdm; + int s6, s9; + u16 tps; + static const u8 tps_fec_to_api[8] = { + FEC_1_2, + FEC_2_3, + FEC_3_4, + FEC_5_6, + FEC_7_8, + FEC_AUTO, + FEC_AUTO, + FEC_AUTO + }; + + s6 = zl10353_read_register(state, STATUS_6); + s9 = zl10353_read_register(state, STATUS_9); + if (s6 < 0 || s9 < 0) + return -EREMOTEIO; + if ((s6 & (1 << 5)) == 0 || (s9 & (1 << 4)) == 0) + return -EINVAL; /* no FE or TPS lock */ + + tps = zl10353_read_register(state, TPS_RECEIVED_1) << 8 | + zl10353_read_register(state, TPS_RECEIVED_0); + + op->code_rate_HP = tps_fec_to_api[(tps >> 7) & 7]; + op->code_rate_LP = tps_fec_to_api[(tps >> 4) & 7]; + + switch ((tps >> 13) & 3) { + case 0: + op->constellation = QPSK; + break; + case 1: + op->constellation = QAM_16; + break; + case 2: + op->constellation = QAM_64; + break; + default: + op->constellation = QAM_AUTO; + break; } - // there is no call to _just_ start decoding, so we send the pllbuf anyway - // even if there isn't a PLL attached to the secondary bus - zl10353_write(fe, pllbuf, sizeof(pllbuf)); + op->transmission_mode = (tps & 0x01) ? TRANSMISSION_MODE_8K : + TRANSMISSION_MODE_2K; - zl10353_single_write(fe, 0x5F, 0x13); - zl10353_single_write(fe, 0x70, 0x01); - udelay(250); - zl10353_single_write(fe, 0xE4, 0x00); - zl10353_single_write(fe, 0xE5, 0x2A); - zl10353_single_write(fe, 0xE9, 0x02); - zl10353_single_write(fe, 0xE7, 0x40); - zl10353_single_write(fe, 0xE8, 0x10); + switch ((tps >> 2) & 3) { + case 0: + op->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + op->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + op->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + op->guard_interval = GUARD_INTERVAL_1_4; + break; + default: + op->guard_interval = GUARD_INTERVAL_AUTO; + break; + } + + switch ((tps >> 10) & 7) { + case 0: + op->hierarchy_information = HIERARCHY_NONE; + break; + case 1: + op->hierarchy_information = HIERARCHY_1; + break; + case 2: + op->hierarchy_information = HIERARCHY_2; + break; + case 3: + op->hierarchy_information = HIERARCHY_4; + break; + default: + op->hierarchy_information = HIERARCHY_AUTO; + break; + } + + param->frequency = 0; + op->bandwidth = state->bandwidth; + param->inversion = INVERSION_AUTO; return 0; } @@ -406,6 +654,7 @@ static struct dvb_frontend_ops zl10353_ops = { .write = zl10353_write, .set_frontend = zl10353_set_parameters, + .get_frontend = zl10353_get_parameters, .get_tune_settings = zl10353_get_tune_settings, .read_status = zl10353_read_status, diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h index 1c3d494a6da9..fc734c22b5fa 100644 --- a/drivers/media/dvb/frontends/zl10353.h +++ b/drivers/media/dvb/frontends/zl10353.h @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au> + * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au> * * 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 @@ -29,8 +29,9 @@ struct zl10353_config /* demodulator's I2C address */ u8 demod_address; - /* frequencies in kHz */ - int adc_clock; /* default: 45056 */ + /* frequencies in units of 0.1kHz */ + int adc_clock; /* default: 450560 (45.056 MHz) */ + int if2; /* default: 361667 (36.1667 MHz) */ /* set if no pll is connected to the secondary i2c bus */ int no_tuner; @@ -49,6 +50,6 @@ static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *c printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return NULL; } -#endif // CONFIG_DVB_ZL10353 +#endif /* CONFIG_DVB_ZL10353 */ #endif /* ZL10353_H */ diff --git a/drivers/media/dvb/frontends/zl10353_priv.h b/drivers/media/dvb/frontends/zl10353_priv.h index 4962434b35e7..055ff1f7e349 100644 --- a/drivers/media/dvb/frontends/zl10353_priv.h +++ b/drivers/media/dvb/frontends/zl10353_priv.h @@ -1,7 +1,7 @@ /* * Driver for Zarlink DVB-T ZL10353 demodulator * - * Copyright (C) 2006 Christopher Pascoe <c.pascoe@itee.uq.edu.au> + * Copyright (C) 2006, 2007 Christopher Pascoe <c.pascoe@itee.uq.edu.au> * * 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 @@ -16,7 +16,7 @@ * * 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.= + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _ZL10353_PRIV_ @@ -46,9 +46,28 @@ enum zl10353_reg_addr { RS_ERR_CNT_0 = 0x13, RS_UBC_1 = 0x14, RS_UBC_0 = 0x15, + TPS_RECEIVED_1 = 0x1D, + TPS_RECEIVED_0 = 0x1E, + TPS_CURRENT_1 = 0x1F, + TPS_CURRENT_0 = 0x20, + RESET = 0x55, + AGC_TARGET = 0x56, + MCLK_RATIO = 0x5C, + ACQ_CTL = 0x5E, TRL_NOMINAL_RATE_1 = 0x65, TRL_NOMINAL_RATE_0 = 0x66, + INPUT_FREQ_1 = 0x6C, + INPUT_FREQ_0 = 0x6D, + TPS_GIVEN_1 = 0x6E, + TPS_GIVEN_0 = 0x6F, + TUNER_GO = 0x70, + FSM_GO = 0x71, CHIP_ID = 0x7F, + CHAN_STEP_1 = 0xE4, + CHAN_STEP_0 = 0xE5, + OFDM_LOCK_TIME = 0xE7, + FEC_LOCK_TIME = 0xE8, + ACQ_DELAY = 0xE9, }; #endif /* _ZL10353_PRIV_ */ diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 54b91f26ca63..ae882432dd3d 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -1,8 +1,14 @@ +config TTPCI_EEPROM + tristate + default n + config DVB_AV7110 tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_CORE && PCI && I2C select FW_LOADER if !DVB_AV7110_FIRMWARE + select TTPCI_EEPROM select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE @@ -57,10 +63,19 @@ config DVB_AV7110_OSD All other people say N. +config DVB_BUDGET_CORE + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" + depends on DVB_CORE && PCI && I2C + select VIDEO_SAA7146 + select TTPCI_EEPROM + help + Support for simple SAA7146 based DVB cards + (so called Budget- or Nova-PCI cards) without onboard + MPEG2 decoder. + config DVB_BUDGET tristate "Budget cards" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 - select VIDEO_SAA7146 + depends on DVB_BUDGET_CORE && I2C select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_VES1820 if !DVB_FE_CUSTOMISE @@ -73,9 +88,9 @@ config DVB_BUDGET select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. + Support for simple SAA7146 based DVB cards (so called Budget- + or Nova-PCI cards) without onboard MPEG2 decoder, and without + analog inputs or an onboard Common Interface connector. Say Y if you own such a card and want to use it. @@ -84,8 +99,7 @@ config DVB_BUDGET config DVB_BUDGET_CI tristate "Budget cards with onboard CI connector" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 && INPUT - select VIDEO_SAA7146 + depends on DVB_BUDGET_CORE && I2C select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -106,8 +120,9 @@ config DVB_BUDGET_CI config DVB_BUDGET_AV tristate "Budget cards with analog video inputs" - depends on DVB_CORE && PCI && I2C && VIDEO_V4L1 + depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV + depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE @@ -127,8 +142,8 @@ config DVB_BUDGET_AV config DVB_BUDGET_PATCH tristate "AV7110 cards with Budget Patch" - depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1 - select DVB_AV7110 + depends on DVB_BUDGET_CORE && I2C + depends on DVB_AV7110 select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_VES1X93 if !DVB_FE_CUSTOMISE select DVB_TDA8083 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index 2c1145236ee6..d7483f1a9b3f 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -5,11 +5,13 @@ dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o av7110_ir.o -obj-$(CONFIG_DVB_BUDGET) += budget-core.o budget.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-core.o budget-av.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o +obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o +obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o +obj-$(CONFIG_DVB_BUDGET) += budget.o +obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o +obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o +obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o +obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index 0d36c155695b..0e5701bdff19 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -2595,7 +2595,8 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, mutex_init(&av7110->osd_mutex); /* TV standard */ - av7110->vidmode = tv_standard == 1 ? VIDEO_MODE_NTSC : VIDEO_MODE_PAL; + av7110->vidmode = tv_standard == 1 ? AV7110_VIDEO_MODE_NTSC + : AV7110_VIDEO_MODE_PAL; /* ARM "watchdog" */ init_waitqueue_head(&av7110->arm_wait); diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h index 0cb439527498..39fbf7d5cffb 100644 --- a/drivers/media/dvb/ttpci/av7110.h +++ b/drivers/media/dvb/ttpci/av7110.h @@ -46,6 +46,11 @@ extern int av7110_debug; enum {AV_PES_STREAM, PS_STREAM, TS_STREAM, PES_STREAM}; +enum av7110_video_mode { + AV7110_VIDEO_MODE_PAL = 0, + AV7110_VIDEO_MODE_NTSC = 1 +}; + struct av7110_p2t { u8 pes[TS_SIZE]; u8 counter; @@ -170,7 +175,7 @@ struct av7110 { ca_slot_info_t ci_slot[2]; - int vidmode; + enum av7110_video_mode vidmode; struct dmxdev dmxdev; struct dvb_demux demux; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index d75e7e48addc..aef6e36d7c5c 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -329,7 +329,7 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) return 0; } -int av7110_set_vidmode(struct av7110 *av7110, int mode) +int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode) { int ret; dprintk(2, "av7110:%p, \n", av7110); @@ -348,11 +348,15 @@ int av7110_set_vidmode(struct av7110 *av7110, int mode) } -static int sw2mode[16] = { - VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, - VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, - VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, - VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, +static enum av7110_video_mode sw2mode[16] = { + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, + AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL, }; static int get_video_format(struct av7110 *av7110, u8 *buf, int count) diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h index 45dc144b8b43..5f02ef85e47d 100644 --- a/drivers/media/dvb/ttpci/av7110_av.h +++ b/drivers/media/dvb/ttpci/av7110_av.h @@ -3,7 +3,8 @@ struct av7110; -extern int av7110_set_vidmode(struct av7110 *av7110, int mode); +extern int av7110_set_vidmode(struct av7110 *av7110, + enum av7110_video_mode mode); extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len); extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen); diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 76cca003252f..e2f066fb7967 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -876,11 +876,11 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) struct av7110 *av7110 = (struct av7110*) dev->ext_priv; if (std->id & V4L2_STD_PAL) { - av7110->vidmode = VIDEO_MODE_PAL; + av7110->vidmode = AV7110_VIDEO_MODE_PAL; av7110_set_vidmode(av7110, av7110->vidmode); } else if (std->id & V4L2_STD_NTSC) { - av7110->vidmode = VIDEO_MODE_NTSC; + av7110->vidmode = AV7110_VIDEO_MODE_NTSC; av7110_set_vidmode(av7110, av7110->vidmode); } else diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 11e962f1a97f..8d5214f18cf0 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -351,4 +351,14 @@ config USB_DSBR To compile this driver as a module, choose M here: the module will be called dsbr100. +config USB_SI470X + tristate "Silicon Labs Si470x FM Radio Receiver support" + depends on USB && VIDEO_V4L2 + ---help--- + Say Y here if you want to connect this type of radio to your + computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called radio-silabs. + endif # RADIO_ADAPTERS diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index cf55a18e3ddf..a30159f6fa42 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -21,5 +21,6 @@ obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o obj-$(CONFIG_USB_DSBR) += dsbr100.o +obj-$(CONFIG_USB_SI470X) += radio-si470x.o EXTRA_CFLAGS += -Isound diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 3bd07f7e3774..36c0e3651502 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -33,6 +33,9 @@ History: + Version 0.43: + Oliver Neukum: avoided DMA coherency issue + Version 0.42: Converted dsbr100 to use video_ioctl2 by Douglas Landgraf <dougsland@gmail.com> @@ -135,7 +138,7 @@ module_param(radio_nr, int, 0); struct dsbr100_device { struct usb_device *usbdev; struct video_device *videodev; - unsigned char transfer_buffer[TB_LEN]; + u8 *transfer_buffer; int curfreq; int stereo; int users; @@ -237,10 +240,7 @@ static void dsbr100_getstat(struct dsbr100_device *radio) /* handle unplugging of the device, release data structures if nothing keeps us from doing it. If something is still keeping us busy, the release callback of v4l will take care -of releasing it. stv680.c does not relase its private -data, so I don't do this here either. Checking out the -code I'd expect I better did that, but if there's a memory -leak here it's tiny (~50 bytes per disconnect) */ +of releasing it. */ static void usb_dsbr100_disconnect(struct usb_interface *intf) { struct dsbr100_device *radio = usb_get_intfdata(intf); @@ -250,6 +250,7 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf) video_unregister_device(radio->videodev); radio->videodev = NULL; if (radio->users) { + kfree(radio->transfer_buffer); kfree(radio); } else { radio->removed = 1; @@ -425,6 +426,7 @@ static int usb_dsbr100_close(struct inode *inode, struct file *file) return -ENODEV; radio->users = 0; if (radio->removed) { + kfree(radio->transfer_buffer); kfree(radio); } return 0; @@ -471,7 +473,12 @@ static int usb_dsbr100_probe(struct usb_interface *intf, if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL))) return -ENOMEM; + if (!(radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL))) { + kfree(radio); + return -ENOMEM; + } if (!(radio->videodev = video_device_alloc())) { + kfree(radio->transfer_buffer); kfree(radio); return -ENOMEM; } @@ -485,6 +492,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) { warn("Could not register video device"); video_device_release(radio->videodev); + kfree(radio->transfer_buffer); kfree(radio); return -EIO; } diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 5e4b9ddb23c0..246422b49267 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -58,10 +58,10 @@ static int initmute = 1; static int radio_nr = -1; module_param(io, int, 0444); -MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic" +MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " "probing is disabled or fails. The most common I/O ports are: 0x20c " "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " - " work for the combined sound/radiocard)."); + "work for the combined sound/radiocard)."); module_param(probe, bool, 0444); MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most " @@ -392,7 +392,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; -static struct file_operations gemtek_fops = { +static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, .open = video_exclusive_open, .release = video_exclusive_release, diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 8e33a19a22a3..bc51f4d23a5a 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -423,7 +423,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev, errunr: video_unregister_device(maestro_radio_inst); errfr1: - kfree(maestro_radio_inst); + video_device_release(maestro_radio_inst); errfr: kfree(radio_unit); err: diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 395165367f37..3118bdab3183 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -321,7 +321,7 @@ static struct isapnp_device_id id_table[] __devinitdata = { MODULE_DEVICE_TABLE(isapnp, id_table); -static int isapnp_fmi_probe(void) +static int __init isapnp_fmi_probe(void) { int i = 0; diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index c432c44bd634..f7c8b000404f 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -476,8 +476,7 @@ static int __init fmr2_init(void) return -EBUSY; } - if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c new file mode 100644 index 000000000000..8e4bd4769048 --- /dev/null +++ b/drivers/media/radio/radio-si470x.c @@ -0,0 +1,1432 @@ +/* + * drivers/media/radio/radio-si470x.c + * + * Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers: + * - Silicon Labs USB FM Radio Reference Design + * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) + * + * Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net> + * + * 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 + */ + + +/* + * History: + * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.0 + * - First working version + * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.1 + * - Improved error handling, every function now returns errno + * - Improved multi user access (start/mute/stop) + * - Channel doesn't get lost anymore after start/mute/stop + * - RDS support added (polling mode via interrupt EP 1) + * - marked default module parameters with *value* + * - switched from bit structs to bit masks + * - header file cleaned and integrated + * 2008-01-14 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.2 + * - hex values are now lower case + * - commented USB ID for ADS/Tech moved on todo list + * - blacklisted si470x in hid-quirks.c + * - rds buffer handling functions integrated into *_work, *_read + * - rds_command in si470x_poll exchanged against simple retval + * - check for firmware version 15 + * - code order and prototypes still remain the same + * - spacing and bottom of band codes remain the same + * 2008-01-16 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.3 + * - code reordered to avoid function prototypes + * - switch/case defaults are now more user-friendly + * - unified comment style + * - applied all checkpatch.pl v1.12 suggestions + * except the warning about the too long lines with bit comments + * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) + * 2008-01-22 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.4 + * - avoid poss. locking when doing copy_to_user which may sleep + * - RDS is automatically activated on read now + * - code cleaned of unnecessary rds_commands + * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified + * (thanks to Guillaume RAMOUSSE) + * + * ToDo: + * - add seeking support + * - add firmware download/update support + * - RDS support: interrupt mode, instead of polling + * - add LED status output (check if that's not already done in firmware) + */ + + +/* driver definitions */ +#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" +#define DRIVER_NAME "radio-si470x" +#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4) +#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" +#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" + + +/* kernel includes */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/usb.h> +#include <linux/hid.h> +#include <linux/version.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <media/rds.h> + + +/* USB Device ID List */ +static struct usb_device_id si470x_usb_driver_id_table[] = { + /* Silicon Labs USB FM Radio Reference Design */ + { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, + /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, + /* Terminating entry */ + { } +}; +MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); + + + +/************************************************************************** + * Module Parameters + **************************************************************************/ + +/* Radio Nr */ +static int radio_nr = -1; +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(radio_nr, "Radio Nr"); + +/* Spacing (kHz) */ +/* 0: 200 kHz (USA, Australia) */ +/* 1: 100 kHz (Europe, Japan) */ +/* 2: 50 kHz */ +static int space = 2; +module_param(space, int, 0); +MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); + +/* Bottom of Band (MHz) */ +/* 0: 87.5 - 108 MHz (USA, Europe)*/ +/* 1: 76 - 108 MHz (Japan wide band) */ +/* 2: 76 - 90 MHz (Japan) */ +static int band = 1; +module_param(band, int, 0); +MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); + +/* De-emphasis */ +/* 0: 75 us (USA) */ +/* 1: 50 us (Europe, Australia, Japan) */ +static int de = 1; +module_param(de, int, 0); +MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*"); + +/* USB timeout */ +static int usb_timeout = 500; +module_param(usb_timeout, int, 0); +MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); + +/* Seek retries */ +static int seek_retries = 100; +module_param(seek_retries, int, 0); +MODULE_PARM_DESC(seek_retries, "Seek retries: *100*"); + +/* RDS buffer blocks */ +static int rds_buf = 100; +module_param(rds_buf, int, 0); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +/* RDS maximum block errors */ +static int max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, int, 0); +MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); + +/* RDS poll frequency */ +static int rds_poll_time = 40; +/* 40 is used by the original USBRadio.exe */ +/* 50 is used by radio-cadet */ +/* 75 should be okay */ +/* 80 is the usual RDS receive interval */ +module_param(rds_poll_time, int, 0); +MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); + + + +/************************************************************************** + * Register Definitions + **************************************************************************/ +#define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ +#define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ +#define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ + +#define DEVICEID 0 /* Device ID */ +#define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ +#define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ + +#define CHIPID 1 /* Chip ID */ +#define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ +#define CHIPID_DEV 0x0200 /* bits 09..09: Device */ +#define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ + +#define POWERCFG 2 /* Power Configuration */ +#define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ +#define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */ +#define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */ +#define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */ +#define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */ +#define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */ +#define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */ +#define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */ +#define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */ + +#define CHANNEL 3 /* Channel */ +#define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */ +#define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */ + +#define SYSCONFIG1 4 /* System Configuration 1 */ +#define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */ +#define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */ +#define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */ +#define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */ +#define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */ +#define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ +#define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ +#define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ +#define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ + +#define SYSCONFIG2 5 /* System Configuration 2 */ +#define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ +#define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ +#define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ +#define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ + +#define SYSCONFIG3 6 /* System Configuration 3 */ +#define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */ +#define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */ +#define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */ +#define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */ + +#define TEST1 7 /* Test 1 */ +#define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */ + +#define TEST2 8 /* Test 2 */ +/* TEST2 only contains reserved bits */ + +#define BOOTCONFIG 9 /* Boot Configuration */ +/* BOOTCONFIG only contains reserved bits */ + +#define STATUSRSSI 10 /* Status RSSI */ +#define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */ +#define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */ +#define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */ +#define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */ +#define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */ +#define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */ +#define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */ +#define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */ + +#define READCHAN 11 /* Read Channel */ +#define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */ +#define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */ +#define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */ +#define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */ + +#define RDSA 12 /* RDSA */ +#define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */ + +#define RDSB 13 /* RDSB */ +#define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */ + +#define RDSC 14 /* RDSC */ +#define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */ + +#define RDSD 15 /* RDSD */ +#define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */ + + + +/************************************************************************** + * USB HID Reports + **************************************************************************/ + +/* Reports 1-16 give direct read/write access to the 16 Si470x registers */ +/* with the (REPORT_ID - 1) corresponding to the register address across USB */ +/* endpoint 0 using GET_REPORT and SET_REPORT */ +#define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) +#define REGISTER_REPORT(reg) ((reg) + 1) + +/* Report 17 gives direct read/write access to the entire Si470x register */ +/* map across endpoint 0 using GET_REPORT and SET_REPORT */ +#define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) +#define ENTIRE_REPORT 17 + +/* Report 18 is used to send the lowest 6 Si470x registers up the HID */ +/* interrupt endpoint 1 to Windows every 20 milliseconds for status */ +#define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) +#define RDS_REPORT 18 + +/* Report 19: LED state */ +#define LED_REPORT_SIZE 3 +#define LED_REPORT 19 + +/* Report 19: stream */ +#define STREAM_REPORT_SIZE 3 +#define STREAM_REPORT 19 + +/* Report 20: scratch */ +#define SCRATCH_PAGE_SIZE 63 +#define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1) +#define SCRATCH_REPORT 20 + +/* Reports 19-22: flash upgrade of the C8051F321 */ +#define WRITE_REPORT 19 +#define FLASH_REPORT 20 +#define CRC_REPORT 21 +#define RESPONSE_REPORT 22 + +/* Report 23: currently unused, but can accept 60 byte reports on the HID */ +/* interrupt out endpoint 2 every 1 millisecond */ +#define UNUSED_REPORT 23 + + + +/************************************************************************** + * Software/Hardware Versions + **************************************************************************/ +#define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 +#define RADIO_SW_VERSION 7 +#define RADIO_SW_VERSION_CURRENT 15 +#define RADIO_HW_VERSION 1 + +#define SCRATCH_PAGE_SW_VERSION 1 +#define SCRATCH_PAGE_HW_VERSION 2 + + + +/************************************************************************** + * LED State Definitions + **************************************************************************/ +#define LED_COMMAND 0x35 + +#define NO_CHANGE_LED 0x00 +#define ALL_COLOR_LED 0x01 /* streaming state */ +#define BLINK_GREEN_LED 0x02 /* connect state */ +#define BLINK_RED_LED 0x04 +#define BLINK_ORANGE_LED 0x10 /* disconnect state */ +#define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ +#define SOLID_RED_LED 0x40 /* bootload state */ +#define SOLID_ORANGE_LED 0x80 + + + +/************************************************************************** + * Stream State Definitions + **************************************************************************/ +#define STREAM_COMMAND 0x36 +#define STREAM_VIDPID 0x00 +#define STREAM_AUDIO 0xff + + + +/************************************************************************** + * Bootloader / Flash Commands + **************************************************************************/ + +/* unique id sent to bootloader and required to put into a bootload state */ +#define UNIQUE_BL_ID 0x34 + +/* mask for the flash data */ +#define FLASH_DATA_MASK 0x55 + +/* bootloader commands */ +#define GET_SW_VERSION_COMMAND 0x00 +#define SET_PAGE_COMMAND 0x01 +#define ERASE_PAGE_COMMAND 0x02 +#define WRITE_PAGE_COMMAND 0x03 +#define CRC_ON_PAGE_COMMAND 0x04 +#define READ_FLASH_BYTE_COMMAND 0x05 +#define RESET_DEVICE_COMMAND 0x06 +#define GET_HW_VERSION_COMMAND 0x07 +#define BLANK 0xff + +/* bootloader command responses */ +#define COMMAND_OK 0x01 +#define COMMAND_FAILED 0x02 +#define COMMAND_PENDING 0x03 + +/* buffer sizes */ +#define COMMAND_BUFFER_SIZE 4 +#define RESPONSE_BUFFER_SIZE 2 +#define FLASH_BUFFER_SIZE 64 +#define CRC_BUFFER_SIZE 3 + + + +/************************************************************************** + * General Driver Definitions + **************************************************************************/ + +/* + * si470x_device - private data + */ +struct si470x_device { + /* reference to USB and video device */ + struct usb_device *usbdev; + struct video_device *videodev; + + /* are these really necessary ? */ + int users; + + /* report buffer (maximum 64 bytes) */ + unsigned char buf[64]; + + /* Silabs internal registers (0..15) */ + unsigned short registers[RADIO_REGISTER_NUM]; + + /* RDS receive buffer */ + struct work_struct work; + wait_queue_head_t read_queue; + struct timer_list timer; + spinlock_t lock; /* buffer locking */ + unsigned char *buffer; /* size is always multiple of three */ + unsigned int buf_size; + unsigned int rd_index; + unsigned int wr_index; +}; + + +/* + * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, + * 62.5 kHz otherwise. + * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. + * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW + * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 + */ +#define FREQ_MUL (1000000 / 62.5) + + + +/************************************************************************** + * General Driver Functions + **************************************************************************/ + +/* + * si470x_get_report - receive a HID report + */ +static int si470x_get_report(struct si470x_device *radio, int size) +{ + return usb_control_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 0), + HID_REQ_GET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, + radio->buf[0], 2, + radio->buf, size, usb_timeout); +} + + +/* + * si470x_set_report - send a HID report + */ +static int si470x_set_report(struct si470x_device *radio, int size) +{ + return usb_control_msg(radio->usbdev, + usb_sndctrlpipe(radio->usbdev, 0), + HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, + radio->buf[0], 2, + radio->buf, size, usb_timeout); +} + + +/* + * si470x_get_register - read register + */ +static int si470x_get_register(struct si470x_device *radio, int regnr) +{ + int retval; + + radio->buf[0] = REGISTER_REPORT(regnr); + + retval = si470x_get_report(radio, REGISTER_REPORT_SIZE); + if (retval >= 0) + radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2]; + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_set_register - write register + */ +static int si470x_set_register(struct si470x_device *radio, int regnr) +{ + int retval; + + radio->buf[0] = REGISTER_REPORT(regnr); + radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8; + radio->buf[2] = (radio->registers[regnr] & 0x00ff); + + retval = si470x_set_report(radio, REGISTER_REPORT_SIZE); + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_get_all_registers - read entire registers + */ +static int si470x_get_all_registers(struct si470x_device *radio) +{ + int retval; + int regnr; + + radio->buf[0] = ENTIRE_REPORT; + + retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); + + if (retval >= 0) + for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) + radio->registers[regnr] = + (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | + radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_get_rds_registers - read rds registers + */ +static int si470x_get_rds_registers(struct si470x_device *radio) +{ + int retval; + int regnr; + int size; + + radio->buf[0] = RDS_REPORT; + + retval = usb_interrupt_msg(radio->usbdev, + usb_rcvctrlpipe(radio->usbdev, 1), + radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); + + if (retval >= 0) + for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) + radio->registers[STATUSRSSI + regnr] = + (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | + radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; + + return (retval < 0) ? -EINVAL : 0; +} + + +/* + * si470x_set_chan - set the channel + */ +static int si470x_set_chan(struct si470x_device *radio, int chan) +{ + int retval, i; + + /* start tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_CHAN; + radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; + retval = si470x_set_register(radio, CHANNEL); + if (retval < 0) + return retval; + + /* wait till seek operation has completed */ + i = 0; + do { + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + return retval; + } while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) && + (++i < seek_retries)); + if (i >= seek_retries) + printk(KERN_WARNING DRIVER_NAME + ": seek does not finish after %d tries\n", i); + + /* stop tuning */ + radio->registers[CHANNEL] &= ~CHANNEL_TUNE; + return si470x_set_register(radio, CHANNEL); +} + + +/* + * si470x_get_freq - get the frequency + */ +static int si470x_get_freq(struct si470x_device *radio) +{ + int spacing, band_bottom, chan, freq; + int retval; + + /* Spacing (kHz) */ + switch (space) { + /* 0: 200 kHz (USA, Australia) */ + case 0 : spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1 : spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch (band) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0 : band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : band_bottom = 76 * FREQ_MUL; break; + }; + + /* read channel */ + retval = si470x_get_register(radio, READCHAN); + if (retval < 0) + return retval; + chan = radio->registers[READCHAN] & READCHAN_READCHAN; + + /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ + freq = chan * spacing + band_bottom; + + return freq; +} + + +/* + * si470x_set_freq - set the frequency + */ +static int si470x_set_freq(struct si470x_device *radio, int freq) +{ + int spacing, band_bottom, chan; + + /* Spacing (kHz) */ + switch (space) { + /* 0: 200 kHz (USA, Australia) */ + case 0 : spacing = 0.200 * FREQ_MUL; break; + /* 1: 100 kHz (Europe, Japan) */ + case 1 : spacing = 0.100 * FREQ_MUL; break; + /* 2: 50 kHz */ + default: spacing = 0.050 * FREQ_MUL; break; + }; + + /* Bottom of Band (MHz) */ + switch (band) { + /* 0: 87.5 - 108 MHz (USA, Europe) */ + case 0 : band_bottom = 87.5 * FREQ_MUL; break; + /* 1: 76 - 108 MHz (Japan wide band) */ + default: band_bottom = 76 * FREQ_MUL; break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : band_bottom = 76 * FREQ_MUL; break; + }; + + /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ + chan = (freq - band_bottom) / spacing; + + return si470x_set_chan(radio, chan); +} + + +/* + * si470x_start - switch on radio + */ +static int si470x_start(struct si470x_device *radio) +{ + int retval; + + /* powercfg */ + radio->registers[POWERCFG] = + POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + return retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + return retval; + + /* sysconfig 2 */ + radio->registers[SYSCONFIG2] = + (0x3f << 8) | /* SEEKTH */ + (band << 6) | /* BAND */ + (space << 4) | /* SPACE */ + 15; /* VOLUME (max) */ + retval = si470x_set_register(radio, SYSCONFIG2); + if (retval < 0) + return retval; + + /* reset last channel */ + return si470x_set_chan(radio, + radio->registers[CHANNEL] & CHANNEL_CHAN); +} + + +/* + * si470x_stop - switch off radio + */ +static int si470x_stop(struct si470x_device *radio) +{ + int retval; + + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + return retval; + + /* powercfg */ + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + /* POWERCFG_ENABLE has to automatically go low */ + radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; + return si470x_set_register(radio, POWERCFG); +} + + +/* + * si470x_rds_on - switch on rds reception + */ +static int si470x_rds_on(struct si470x_device *radio) +{ + /* sysconfig 1 */ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; + return si470x_set_register(radio, SYSCONFIG1); +} + + + +/************************************************************************** + * RDS Driver Functions + **************************************************************************/ + +/* + * si470x_rds - rds processing function + */ +static void si470x_rds(struct si470x_device *radio) +{ + unsigned char tmpbuf[3]; + unsigned char blocknum; + unsigned char bler; /* rds block errors */ + unsigned short rds; + unsigned int i; + + /* get rds blocks */ + if (si470x_get_rds_registers(radio) < 0) + return; + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { + /* No RDS group ready */ + return; + } + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) { + /* RDS decoder not synchronized */ + return; + } + + /* copy four RDS blocks to internal buffer */ + if (spin_trylock(&radio->lock)) { + /* process each rds block */ + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + tmpbuf[0] = rds & 0x00ff; /* LSB */ + tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + /* copy RDS block to internal buffer */ + for (i = 0; i < 3; i++) { + radio->buffer[radio->wr_index] = tmpbuf[i]; + radio->wr_index++; + } + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } + } + spin_unlock(&radio->lock); + } + + /* wake up read queue */ + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); +} + + +/* + * si470x_timer - rds timer function + */ +static void si470x_timer(unsigned long data) +{ + struct si470x_device *radio = (struct si470x_device *) data; + + schedule_work(&radio->work); +} + + +/* + * si470x_work - rds work function + */ +static void si470x_work(struct work_struct *work) +{ + struct si470x_device *radio = container_of(work, struct si470x_device, + work); + + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + return; + + si470x_rds(radio); + mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time)); +} + + + +/************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * si470x_fops_read - read RDS data + */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval = 0; + unsigned int block_count = 0; + + /* switch on rds reception */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { + si470x_rds_on(radio); + schedule_work(&radio->work); + } + + /* block if no new data available */ + while (radio->wr_index == radio->rd_index) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + interruptible_sleep_on(&radio->read_queue); + } + + /* calculate block count from byte count */ + count /= 3; + + /* copy RDS block out of internal buffer and to user buffer */ + if (spin_trylock(&radio->lock)) { + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; + + /* always transfer rds complete blocks */ + if (copy_to_user(buf, + &radio->buffer[radio->rd_index], 3)) + /* retval = -EFAULT; */ + break; + + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + } + + spin_unlock(&radio->lock); + } + + return retval; +} + + +/* + * si470x_fops_poll - poll RDS data + */ +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + /* switch on rds reception */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { + si470x_rds_on(radio); + schedule_work(&radio->work); + } + + poll_wait(file, &radio->read_queue, pts); + + if (radio->rd_index != radio->wr_index) + return POLLIN | POLLRDNORM; + + return 0; +} + + +/* + * si470x_fops_open - file open + */ +static int si470x_fops_open(struct inode *inode, struct file *file) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + radio->users++; + if (radio->users == 1) + return si470x_start(radio); + + return 0; +} + + +/* + * si470x_fops_release - file release + */ +static int si470x_fops_release(struct inode *inode, struct file *file) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (!radio) + return -ENODEV; + + radio->users--; + if (radio->users == 0) { + /* stop rds reception */ + del_timer_sync(&radio->timer); + flush_scheduled_work(); + + /* cancel read processes */ + wake_up_interruptible(&radio->read_queue); + + return si470x_stop(radio); + } + + return 0; +} + + +/* + * si470x_fops - file operations interface + */ +static const struct file_operations si470x_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .open = si470x_fops_open, + .release = si470x_fops_release, +}; + + + +/************************************************************************** + * Video4Linux Interface + **************************************************************************/ + +/* + * si470x_v4l2_queryctrl - query control + */ +static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = { +/* HINT: the disabled controls are only here to satify kradio and such apps */ + { + .id = V4L2_CID_AUDIO_VOLUME, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Volume", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 15, + }, + { + .id = V4L2_CID_AUDIO_BALANCE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_BASS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_TREBLE, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, + { + .id = V4L2_CID_AUDIO_MUTE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_AUDIO_LOUDNESS, + .flags = V4L2_CTRL_FLAG_DISABLED, + }, +}; + + +/* + * si470x_vidioc_querycap - query device capabilities + */ +static int si470x_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + sprintf(capability->bus_info, "USB"); + capability->version = DRIVER_VERSION; + capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + + return 0; +} + + +/* + * si470x_vidioc_g_input - get input + */ +static int si470x_vidioc_g_input(struct file *filp, void *priv, + unsigned int *i) +{ + *i = 0; + + return 0; +} + + +/* + * si470x_vidioc_s_input - set input + */ +static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + + return 0; +} + + +/* + * si470x_vidioc_queryctrl - enumerate control items + */ +static int si470x_vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { + if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) { + memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); + return 0; + } + } + + return -EINVAL; +} + + +/* + * si470x_vidioc_g_ctrl - get the value of a control + */ +static int si470x_vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = radio->registers[SYSCONFIG2] & + SYSCONFIG2_VOLUME; + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = ((radio->registers[POWERCFG] & + POWERCFG_DMUTE) == 0) ? 1 : 0; + break; + } + + return 0; +} + + +/* + * si470x_vidioc_s_ctrl - set the value of a control + */ +static int si470x_vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; + radio->registers[SYSCONFIG2] |= ctrl->value; + return si470x_set_register(radio, SYSCONFIG2); + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value == 1) + radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; + else + radio->registers[POWERCFG] |= POWERCFG_DMUTE; + return si470x_set_register(radio, POWERCFG); + } + + return -EINVAL; +} + + +/* + * si470x_vidioc_g_audio - get audio attributes + */ +static int si470x_vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index > 1) + return -EINVAL; + + strcpy(audio->name, "Radio"); + audio->capability = V4L2_AUDCAP_STEREO; + + return 0; +} + + +/* + * si470x_vidioc_s_audio - set audio attributes + */ +static int si470x_vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index != 0) + return -EINVAL; + + return 0; +} + + +/* + * si470x_vidioc_g_tuner - get tuner attributes + */ +static int si470x_vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + int retval; + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (tuner->index > 0) + return -EINVAL; + + /* read status rssi */ + retval = si470x_get_register(radio, STATUSRSSI); + if (retval < 0) + return retval; + + strcpy(tuner->name, "FM"); + tuner->type = V4L2_TUNER_RADIO; + switch (band) { + /* 0: 87.5 - 108 MHz (USA, Europe, default) */ + default: + tuner->rangelow = 87.5 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 1: 76 - 108 MHz (Japan wide band) */ + case 1 : + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 108 * FREQ_MUL; + break; + /* 2: 76 - 90 MHz (Japan) */ + case 2 : + tuner->rangelow = 76 * FREQ_MUL; + tuner->rangehigh = 90 * FREQ_MUL; + break; + }; + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + tuner->capability = V4L2_TUNER_CAP_LOW; + + /* Stereo indicator == Stereo (instead of Mono) */ + if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1) + tuner->audmode = V4L2_TUNER_MODE_STEREO; + else + tuner->audmode = V4L2_TUNER_MODE_MONO; + + /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ + tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI) + * 0x0101; + + /* automatic frequency control: -1: freq to low, 1 freq to high */ + tuner->afc = 0; + + return 0; +} + + +/* + * si470x_vidioc_s_tuner - set tuner attributes + */ +static int si470x_vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (tuner->index > 0) + return -EINVAL; + + if (tuner->audmode == V4L2_TUNER_MODE_MONO) + radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ + else + radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ + + return si470x_set_register(radio, POWERCFG); +} + + +/* + * si470x_vidioc_g_frequency - get tuner or modulator radio frequency + */ +static int si470x_vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + freq->type = V4L2_TUNER_RADIO; + freq->frequency = si470x_get_freq(radio); + + return 0; +} + + +/* + * si470x_vidioc_s_frequency - set tuner or modulator radio frequency + */ +static int si470x_vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *freq) +{ + struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + + if (freq->type != V4L2_TUNER_RADIO) + return -EINVAL; + + return si470x_set_freq(radio, freq->frequency); +} + + +/* + * 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, + .vidioc_querycap = si470x_vidioc_querycap, + .vidioc_g_input = si470x_vidioc_g_input, + .vidioc_s_input = si470x_vidioc_s_input, + .vidioc_queryctrl = si470x_vidioc_queryctrl, + .vidioc_g_ctrl = si470x_vidioc_g_ctrl, + .vidioc_s_ctrl = si470x_vidioc_s_ctrl, + .vidioc_g_audio = si470x_vidioc_g_audio, + .vidioc_s_audio = si470x_vidioc_s_audio, + .vidioc_g_tuner = si470x_vidioc_g_tuner, + .vidioc_s_tuner = si470x_vidioc_s_tuner, + .vidioc_g_frequency = si470x_vidioc_g_frequency, + .vidioc_s_frequency = si470x_vidioc_s_frequency, + .owner = THIS_MODULE, +}; + + + +/************************************************************************** + * USB Interface + **************************************************************************/ + +/* + * si470x_usb_driver_probe - probe for the device + */ +static int si470x_usb_driver_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct si470x_device *radio; + + /* memory and interface allocations */ + radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL); + if (!radio) + return -ENOMEM; + radio->videodev = video_device_alloc(); + if (!radio->videodev) { + kfree(radio); + return -ENOMEM; + } + memcpy(radio->videodev, &si470x_viddev_template, + sizeof(si470x_viddev_template)); + radio->users = 0; + radio->usbdev = interface_to_usbdev(intf); + video_set_drvdata(radio->videodev, radio); + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { + printk(KERN_WARNING DRIVER_NAME + ": Could not register video device\n"); + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + usb_set_intfdata(intf, radio); + + /* show some infos about the specific device */ + if (si470x_get_all_registers(radio) < 0) { + video_device_release(radio->videodev); + kfree(radio); + return -EIO; + } + printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", + radio->registers[DEVICEID], radio->registers[CHIPID]); + + /* check if firmware is current */ + if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) + < RADIO_SW_VERSION_CURRENT) + printk(KERN_WARNING DRIVER_NAME + ": This driver is known to work with chip version %d, " + "but the device has firmware %d.\n" + DRIVER_NAME + "If you have some trouble using this driver, please " + "report to V4L ML at video4linux-list@redhat.com\n", + radio->registers[CHIPID] & CHIPID_FIRMWARE, + RADIO_SW_VERSION_CURRENT); + + /* set initial frequency */ + si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + + /* rds initialization */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + video_device_release(radio->videodev); + kfree(radio); + return -ENOMEM; + } + radio->wr_index = 0; + radio->rd_index = 0; + init_waitqueue_head(&radio->read_queue); + + /* prepare polling via eventd */ + INIT_WORK(&radio->work, si470x_work); + init_timer(&radio->timer); + radio->timer.function = si470x_timer; + radio->timer.data = (unsigned long) radio; + + return 0; +} + + +/* + * si470x_usb_driver_disconnect - disconnect the device + */ +static void si470x_usb_driver_disconnect(struct usb_interface *intf) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + del_timer_sync(&radio->timer); + flush_scheduled_work(); + + usb_set_intfdata(intf, NULL); + if (radio) { + video_unregister_device(radio->videodev); + kfree(radio->buffer); + kfree(radio); + } +} + + +/* + * si470x_usb_driver - usb driver interface + */ +static struct usb_driver si470x_usb_driver = { + .name = DRIVER_NAME, + .probe = si470x_usb_driver_probe, + .disconnect = si470x_usb_driver_disconnect, + .id_table = si470x_usb_driver_id_table, +}; + + + +/************************************************************************** + * Module Interface + **************************************************************************/ + +/* + * si470x_module_init - module init + */ +static int __init si470x_module_init(void) +{ + printk(KERN_INFO DRIVER_DESC "\n"); + return usb_register(&si470x_usb_driver); +} + + +/* + * si470x_module_exit - module exit + */ +static void __exit si470x_module_exit(void) +{ + usb_deregister(&si470x_usb_driver); +} + + +module_init(si470x_module_init); +module_exit(si470x_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION("1.0.4"); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index c9f14bfc8544..a2e8987a6195 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -45,7 +45,7 @@ comment "Audio decoders" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, @@ -57,7 +57,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for tda7432 audio decoder chip found on some bt8xx boards. @@ -75,7 +75,7 @@ config VIDEO_TDA9840 config VIDEO_TDA9875 tristate "Philips TDA9875 audio processor" - depends on VIDEO_V4L1 && I2C + depends on VIDEO_V4L2 && I2C ---help--- Support for tda9875 audio decoder chip found on some bt8xx boards. @@ -109,9 +109,19 @@ config VIDEO_MSP3400 To compile this driver as a module, choose M here: the module will be called msp3400. +config VIDEO_CS5345 + tristate "Cirrus Logic CS5345 audio ADC" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the Cirrus Logic CS5345 24-bit, 192 kHz + stereo A/D converter. + + To compile this driver as a module, choose M here: the + module will be called cs5345. + config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -119,6 +129,15 @@ config VIDEO_CS53L32A To compile this driver as a module, choose M here: the module will be called cs53l32a. +config VIDEO_M52790 + tristate "Mitsubishi M52790 A/V switch" + depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + ---help--- + Support for the Mitsubishi M52790 A/V switch. + + To compile this driver as a module, choose M here: the + module will be called m52790. + config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL @@ -130,7 +149,7 @@ config VIDEO_TLV320AIC23B config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -140,7 +159,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -244,7 +263,7 @@ config VIDEO_SAA7114 config VIDEO_SAA711X tristate "Philips SAA7113/4/5 video decoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Philips SAA7113/4/5 video decoders. @@ -300,7 +319,7 @@ comment "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the Philips SAA7127/9 digital video encoders. @@ -338,7 +357,7 @@ comment "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the NEC Electronics uPD64031A Ghost Reduction video chip. It is most often found in NTSC TV cards made for @@ -350,7 +369,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C ---help--- Support for the NEC Electronics uPD64083 3-Dimensional Y/C separation video chip. It is used to improve the quality of @@ -802,6 +821,19 @@ config USB_ZR364XX To compile this driver as a module, choose M here: the module will be called zr364xx. +config USB_STKWEBCAM + tristate "USB Syntek DC1125 Camera support" + depends on VIDEO_V4L2 && EXPERIMENTAL + ---help--- + Say Y here if you want to use this type of camera. + Supported devices are typically found in some Asus laptops, + with USB id 174f:a311 and 05e1:0501. Other Syntek cameras + may be supported by the stk11xx driver, from which this is + derived, see http://stk11xx.sourceforge.net + + To compile this driver as a module, choose M here: the + module will be called stkwebcam. + endif # V4L_USB_DRIVERS endif # VIDEO_CAPTURE_DRIVERS diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b5a064163e03..28ddd146c1c5 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -4,10 +4,12 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ zoran_driver.o zoran_card.o -tuner-objs := tuner-core.o tuner-types.o tda9887.o +tuner-objs := tuner-core.o tuner-types.o msp3400-objs := msp3400-driver.o msp3400-kthreads.o +stkwebcam-objs := stk-webcam.o stk-sensor.o + obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ v4l2-int-device.o @@ -66,7 +68,9 @@ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o +obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o @@ -81,11 +85,13 @@ obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o +obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o obj-$(CONFIG_TUNER_TDA8290) += tda8290.o obj-$(CONFIG_TUNER_TEA5767) += tea5767.o obj-$(CONFIG_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_TUNER_TDA9887) += tda9887.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o @@ -112,6 +118,7 @@ obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o obj-$(CONFIG_USB_ZR364XX) += zr364xx.o +obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o obj-$(CONFIG_USB_SN9C102) += sn9c102/ obj-$(CONFIG_USB_ET61X251) += et61x251/ @@ -129,3 +136,4 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index 2ca162b390a2..cfc822bb502a 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1 + depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index a096a03418aa..924d216d9570 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -4,7 +4,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \ - bttv-input.o + bttv-input.o bttv-audio-hook.o obj-$(CONFIG_VIDEO_BT848) += bttv.o diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.c b/drivers/media/video/bt8xx/bttv-audio-hook.c new file mode 100644 index 000000000000..2364d16586b3 --- /dev/null +++ b/drivers/media/video/bt8xx/bttv-audio-hook.c @@ -0,0 +1,382 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttv-audio-hook.h" + +#include <linux/delay.h> + +/* ----------------------------------------------------------------------- */ +/* winview */ + +void winview_volume(struct bttv *btv, __u16 volume) +{ + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; + data = gpio_read(); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<<loops)) + data |= WINVIEW_PT2254_DATA; + else + data &= ~WINVIEW_PT2254_DATA; + gpio_write(data); + udelay(5); + data |= WINVIEW_PT2254_CLK; + gpio_write(data); + udelay(5); + data &= ~WINVIEW_PT2254_CLK; + gpio_write(data); + } + data |= WINVIEW_PT2254_STROBE; + data &= ~WINVIEW_PT2254_DATA; + gpio_write(data); + udelay(10); + data &= ~WINVIEW_PT2254_STROBE; + gpio_write(data); +} + +/* ----------------------------------------------------------------------- */ +/* mono/stereo control for various cards (which don't use i2c chips but */ +/* connect something to the GPIO pins */ + +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x300, 0x300); + if (t->audmode & V4L2_TUNER_MODE_LANG1) + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x300; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x200; +/* if (t->audmode & V4L2_TUNER_MODE_MONO) + * con = 0x100; */ + gpio_bits(0x300, con); + } else { + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val, con; + + if (btv->radio_user) + return; + + val = gpio_read(); + if (set) { + con = 0x000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) { + if (t->audmode & V4L2_TUNER_MODE_LANG1) { + /* LANG1 + LANG2 */ + con = 0x100; + } + else { + /* LANG2 */ + con = 0x300; + } + } + if (con != (val & 0x300)) { + gpio_bits(0x300, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"gvbctv5pci"); + } + } else { + switch (val & 0x70) { + case 0x10: + t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 0x30: + t->rxsubchans = V4L2_TUNER_SUB_LANG2; + break; + case 0x50: + t->rxsubchans = V4L2_TUNER_SUB_LANG1; + break; + case 0x60: + t->rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 0x70: + t->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + default: + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + } + t->audmode = V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Mario Medina Nussbaum <medisoft@alohabbs.org.mx> + * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, + * 0xdde enables mono and 0xccd enables sap + * + * Petr Vandrovec <VANDROVE@vc.cvut.cz> + * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select + * input/output sound connection, so both must be set for output mode. + * + * Looks like it's needed only for the "tvphone", the "tvphone 98" + * handles this with a tda9840 + * + */ + +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x02; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0x01; + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1; + return; + } +} + + +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x01; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ + val = 0x02; + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv,"avermedia"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* Lifetec 9415 handling */ + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + int val = 0; + + if (gpio_read() & 0x4000) { + t->audmode = V4L2_TUNER_MODE_MONO; + return; + } + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ + val = 0x0080; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ + val = 0x0880; + if ((t->audmode & V4L2_TUNER_MODE_LANG1) || + (t->audmode & V4L2_TUNER_MODE_MONO)) + val = 0; + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"lt9415"); + } else { + /* autodetect doesn't work with this card :-( */ + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + return; + } +} + +/* TDA9821 on TerraTV+ Bt848, Bt878 */ +void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0; + + if (set) { + gpio_inout(0x180000,0x180000); + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x080000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x180000; + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv,"terratv"); + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + + +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ + val = 0x420000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ + val = 0x410000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ + val = 0x020000; + if (val) { + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"winfast2000"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski <darekk@automex.pl> + * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM + * revision 9B has on-board TDA9874A sound decoder). + * + * Note: There are card variants without tda9874a. Forcing the "stereo sound route" + * will mute this cards. + */ +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x01; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x02; + } + if (val) { + gpio_bits(0x03,val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"pvbt878p9b"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * Dariusz Kowalewski <darekk@automex.pl> + * sound control for FlyVideo 2000S (with tda9874 decoder) + * based on pvbt878p9b_audio() - this is not tested, please fix!!! + */ +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int val = 0xffff; + + if (btv->radio_user) + return; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) { + val = 0x0000; + } + if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) + || (t->audmode & V4L2_TUNER_MODE_STEREO)) { + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + } + if (val != 0xffff) { + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"fv2000s"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for Canopus WinDVR PCI + * Masaki Suzuki <masaki@btree.org> + */ +void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned long val = 0; + + if (set) { + if (t->audmode & V4L2_TUNER_MODE_MONO) + val = 0x040000; + if (t->audmode & V4L2_TUNER_MODE_LANG1) + val = 0; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + val = 0x100000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + val = 0; + if (val) { + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv,"windvr"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} + +/* + * sound control for AD-TVK503 + * Hiroshi Takekawa <sian@big.or.jp> + */ +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) +{ + unsigned int con = 0xffffff; + + /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ + + if (set) { + /* btor(***, BT848_GPIO_OUT_EN); */ + if (t->audmode & V4L2_TUNER_MODE_LANG1) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_LANG2) + con = 0x00180000; + if (t->audmode & V4L2_TUNER_MODE_STEREO) + con = 0x00000000; + if (t->audmode & V4L2_TUNER_MODE_MONO) + con = 0x00060000; + if (con != 0xffffff) { + gpio_bits(0x1e0000,con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); + } + } else { + t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | + V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + } +} diff --git a/drivers/media/video/bt8xx/bttv-audio-hook.h b/drivers/media/video/bt8xx/bttv-audio-hook.h new file mode 100644 index 000000000000..159d07adeff8 --- /dev/null +++ b/drivers/media/video/bt8xx/bttv-audio-hook.h @@ -0,0 +1,23 @@ +/* + * Handlers for board audio hooks, splitted from bttv-cards + * + * Copyright (c) 2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License + */ + +#include "bttvp.h" + +void winview_volume (struct bttv *btv, __u16 volume); + +void lt9415_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void terratv_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void windvr_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); +void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *tuner, int set); + diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c index 585d1ef95afd..63a47cd4c161 100644 --- a/drivers/media/video/bt8xx/bttv-cards.c +++ b/drivers/media/video/bt8xx/bttv-cards.c @@ -39,6 +39,7 @@ #include "bttvp.h" #include <media/v4l2-common.h> #include <media/tvaudio.h> +#include "bttv-audio-hook.h" /* fwd decl */ static void boot_msp34xx(struct bttv *btv, int pin); @@ -50,20 +51,6 @@ static void modtec_eeprom(struct bttv *btv); static void init_PXC200(struct bttv *btv); static void init_RTV24(struct bttv *btv); -static void winview_audio(struct bttv *btv, struct video_audio *v, int set); -static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set); -static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, - int set); -static void avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, - int set); -static void terratv_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set); -static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set); -static void pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set); -static void fv2000s_audio(struct bttv *btv, struct video_audio *v, int set); -static void windvr_audio(struct bttv *btv, struct video_audio *v, int set); -static void adtvk503_audio(struct bttv *btv, struct video_audio *v, int set); static void rv605_muxsel(struct bttv *btv, unsigned int input); static void eagle_muxsel(struct bttv *btv, unsigned int input); static void xguard_muxsel(struct bttv *btv, unsigned int input); @@ -427,7 +414,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = avermedia_tvphone_audio, + .audio_mode_gpio= avermedia_tvphone_audio, .has_remote = 1, }, [BTTV_BOARD_MATRIX_VISION] = { @@ -539,7 +526,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = avermedia_tv_stereo_audio, + .audio_mode_gpio= avermedia_tv_stereo_audio, .no_gpioirq = 1, }, [BTTV_BOARD_VHX] = { @@ -604,7 +591,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = winview_audio, + .volume_gpio = winview_volume, .has_radio = 1, }, [BTTV_BOARD_AVEC_INTERCAP] = { @@ -728,7 +715,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = terratv_audio, + .audio_mode_gpio= terratv_audio, }, [BTTV_BOARD_HAUPPAUG_WCAM] = { .name = "Hauppauge WinCam newer (bt878)", @@ -776,7 +763,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = terratv_audio, + .audio_mode_gpio= terratv_audio, /* GPIO wiring: External 20 pin connector (for Active Radio Upgrade board) gpio00: i2c-sda @@ -915,7 +902,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */ .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = winfast2000_audio, + .audio_mode_gpio= winfast2000_audio, .has_remote = 1, }, [BTTV_BOARD_CHRONOS_VS2] = { @@ -1035,7 +1022,7 @@ struct tvcard bttv_tvcards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .has_radio = 1, - .audio_hook = avermedia_tvphone_audio, + .audio_mode_gpio= avermedia_tvphone_audio, }, [BTTV_BOARD_PV951] = { .name = "ProVideo PV951", /* pic16c54 */ @@ -1167,7 +1154,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_ALPS_TSHC6_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv3pci_audio, + .audio_mode_gpio= gvbctv3pci_audio, }, [BTTV_BOARD_PXELVWPLTVPAK] = { .name = "Prolink PV-BT878P+4E / PixelView PlayTV PAK / Lenco MXTV-9578 CP", @@ -1472,7 +1459,7 @@ struct tvcard bttv_tvcards[] = { /* -dk-???: set mute=0x1800 for tda9874h daughterboard */ .gpiomux = { 0x0000,0x0800,0x1000,0x1000 }, .gpiomute = 0x1800, - .audio_hook = fv2000s_audio, + .audio_mode_gpio= fv2000s_audio, .no_msp34xx = 1, .no_tda9875 = 1, .needs_tvaudio = 1, @@ -1513,7 +1500,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_SHARP_2U5JF5540_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv3pci_audio, + .audio_mode_gpio= gvbctv3pci_audio, }, /* ---- card 0x44 ---------------------------------- */ @@ -1632,7 +1619,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_PAL, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */ + .audio_mode_gpio= pvbt878p9b_audio, /* Note: not all cards have stereo */ .has_radio = 1, /* Note: not all cards have radio */ .has_remote = 1, /* GPIO wiring: @@ -1710,7 +1697,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = windvr_audio, + .audio_mode_gpio= windvr_audio, }, [BTTV_BOARD_GRANDTEC_MULTI] = { .name = "GrandTec Multi Capture Card (Bt878)", @@ -1807,7 +1794,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC_M, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = gvbctv5pci_audio, + .audio_mode_gpio= gvbctv5pci_audio, .has_radio = 1, }, [BTTV_BOARD_OSPREY1x0] = { @@ -2106,7 +2093,7 @@ struct tvcard bttv_tvcards[] = { .tuner_type = TUNER_PHILIPS_NTSC, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .audio_hook = adtvk503_audio, + .audio_mode_gpio= adtvk503_audio, }, /* ---- card 0x64 ---------------------------------- */ @@ -3173,8 +3160,8 @@ static void flyvideo_gpio(struct bttv *btv) /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if(has_tda9820_tda9821) btv->audio_hook = lt9415_audio; - /* todo: if(has_tda9874) btv->audio_hook = fv2000s_audio; */ + if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio; + /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ } static int miro_tunermap[] = { 0,6,2,3, 4,5,6,0, 3,0,4,5, 5,2,16,1, @@ -3574,8 +3561,12 @@ void __devinit bttv_init_card2(struct bttv *btv) } if (btv->tda9887_conf) { - bttv_call_i2c_clients(btv, TDA9887_SET_CONFIG, - &btv->tda9887_conf); + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &btv->tda9887_conf; + + bttv_call_i2c_clients(btv, TUNER_SET_CONFIG, &tda9887_cfg); } btv->svhs = bttv_tvcards[btv->c.type].svhs; @@ -3590,8 +3581,10 @@ void __devinit bttv_init_card2(struct bttv *btv) btv->has_remote=1; if (!bttv_tvcards[btv->c.type].no_gpioirq) btv->gpioirq=1; - if (bttv_tvcards[btv->c.type].audio_hook) - btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; + if (bttv_tvcards[btv->c.type].volume_gpio) + btv->volume_gpio=bttv_tvcards[btv->c.type].volume_gpio; + if (bttv_tvcards[btv->c.type].audio_mode_gpio) + btv->audio_mode_gpio=bttv_tvcards[btv->c.type].audio_mode_gpio; if (bttv_tvcards[btv->c.type].digital_mode == DIGITAL_MODE_CAMERA) { /* detect Bt832 chip for quartzsight digital camera */ @@ -3950,7 +3943,7 @@ static void __devinit avermedia_eeprom(struct bttv *btv) void bttv_tda9880_setnorm(struct bttv *btv, int norm) { /* fix up our card entry */ - if(norm==VIDEO_MODE_NTSC) { + if(norm==V4L2_STD_NTSC) { bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff; bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff; @@ -4319,387 +4312,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq) tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */ } - -/* ----------------------------------------------------------------------- */ -/* winview */ - -static void winview_audio(struct bttv *btv, struct video_audio *v, int set) -{ - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - int bits_out, loops, vol, data; - - if (!set) { - /* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */ - v->flags |= VIDEO_AUDIO_VOLUME; - return; - } - - /* 32 levels logarithmic */ - vol = 32 - ((v->volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANNEL | PT2254_R_CHANNEL; - data = gpio_read(); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<<loops)) - data |= WINVIEW_PT2254_DATA; - else - data &= ~WINVIEW_PT2254_DATA; - gpio_write(data); - udelay(5); - data |= WINVIEW_PT2254_CLK; - gpio_write(data); - udelay(5); - data &= ~WINVIEW_PT2254_CLK; - gpio_write(data); - } - data |= WINVIEW_PT2254_STROBE; - data &= ~WINVIEW_PT2254_DATA; - gpio_write(data); - udelay(10); - data &= ~WINVIEW_PT2254_STROBE; - gpio_write(data); -} - -/* ----------------------------------------------------------------------- */ -/* mono/stereo control for various cards (which don't use i2c chips but */ -/* connect something to the GPIO pins */ - -static void -gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x300, 0x300); - if (v->mode & VIDEO_SOUND_LANG1) - con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x300; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x200; -/* if (v->mode & VIDEO_SOUND_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - v->mode = VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -static void -gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val, con; - - if (btv->radio_user) - return; - - val = gpio_read(); - if (set) { - con = 0x000; - if (v->mode & VIDEO_SOUND_LANG2) { - if (v->mode & VIDEO_SOUND_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } - } - if (con != (val & 0x300)) { - gpio_bits(0x300, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); - } - } else { - switch (val & 0x70) { - case 0x10: - v->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - break; - case 0x30: - v->mode = VIDEO_SOUND_LANG2; - break; - case 0x50: - v->mode = VIDEO_SOUND_LANG1; - break; - case 0x60: - v->mode = VIDEO_SOUND_STEREO; - break; - case 0x70: - v->mode = VIDEO_SOUND_MONO; - break; - default: - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } - } -} - -/* - * Mario Medina Nussbaum <medisoft@alohabbs.org.mx> - * I discover that on BT848_GPIO_DATA address a byte 0xcce enable stereo, - * 0xdde enables mono and 0xccd enables sap - * - * Petr Vandrovec <VANDROVE@vc.cvut.cz> - * P.S.: At least mask in line above is wrong - GPIO pins 3,2 select - * input/output sound connection, so both must be set for output mode. - * - * Looks like it's needed only for the "tvphone", the "tvphone 98" - * handles this with a tda9840 - * - */ -static void -avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x02; - if (v->mode & VIDEO_SOUND_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1; - return; - } -} - -static void -avermedia_tv_stereo_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x01; - if (v->mode & VIDEO_SOUND_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - return; - } -} - -/* Lifetec 9415 handling */ -static void -lt9415_audio(struct bttv *btv, struct video_audio *v, int set) -{ - int val = 0; - - if (gpio_read() & 0x4000) { - v->mode = VIDEO_SOUND_MONO; - return; - } - - if (set) { - if (v->mode & VIDEO_SOUND_LANG2) /* A2 SAP */ - val = 0x0080; - if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */ - val = 0x0880; - if ((v->mode & VIDEO_SOUND_LANG1) || - (v->mode & VIDEO_SOUND_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - return; - } -} - -/* TDA9821 on TerraTV+ Bt848, Bt878 */ -static void -terratv_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0; - - if (set) { - gpio_inout(0x180000,0x180000); - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x080000; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -static void -winfast2000_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned long val = 0; - - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (v->mode & VIDEO_SOUND_MONO) /* Mono */ - val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG1) /* Mono */ - val = 0x420000; - if (v->mode & VIDEO_SOUND_LANG2) /* SAP */ - val = 0x410000; - if (v->mode & VIDEO_SOUND_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * Dariusz Kowalewski <darekk@automex.pl> - * sound control for Prolink PV-BT878P+9B (PixelView PlayTV Pro FM+NICAM - * revision 9B has on-board TDA9874A sound decoder). - * - * Note: There are card variants without tda9874a. Forcing the "stereo sound route" - * will mute this cards. - */ -static void -pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val = 0; - - if (btv->radio_user) - return; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) { - val = 0x01; - } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * Dariusz Kowalewski <darekk@automex.pl> - * sound control for FlyVideo 2000S (with tda9874 decoder) - * based on pvbt878p9b_audio() - this is not tested, please fix!!! - */ -static void -fv2000s_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int val = 0xffff; - - if (btv->radio_user) - return; - if (set) { - if (v->mode & VIDEO_SOUND_MONO) { - val = 0x0000; - } - if ((v->mode & (VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2)) - || (v->mode & VIDEO_SOUND_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * sound control for Canopus WinDVR PCI - * Masaki Suzuki <masaki@btree.org> - */ -static void -windvr_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned long val = 0; - - if (set) { - if (v->mode & VIDEO_SOUND_MONO) - val = 0x040000; - if (v->mode & VIDEO_SOUND_LANG1) - val = 0; - if (v->mode & VIDEO_SOUND_LANG2) - val = 0x100000; - if (v->mode & VIDEO_SOUND_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - -/* - * sound control for AD-TVK503 - * Hiroshi Takekawa <sian@big.or.jp> - */ -static void -adtvk503_audio(struct bttv *btv, struct video_audio *v, int set) -{ - unsigned int con = 0xffffff; - - /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (v->mode & VIDEO_SOUND_LANG1) - con = 0x00000000; - if (v->mode & VIDEO_SOUND_LANG2) - con = 0x00180000; - if (v->mode & VIDEO_SOUND_STEREO) - con = 0x00000000; - if (v->mode & VIDEO_SOUND_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO | - VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - } -} - /* RemoteVision MX (rv605) muxsel helper [Miguel Freitas] * * This is needed because rv605 don't use a normal multiplex, but a crosspoint diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 581a3c955739..907dc62c1783 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -9,6 +9,12 @@ some v4l2 code lines are taken from Justin's bttv2 driver which is (c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za> + V4L1 removal from: + (c) 2005-2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru> + + Fixes to be fully V4L2 compliant by + (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org> + Cropping and overscan support Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at> Sponsored by OPQ Systems AB @@ -157,7 +163,7 @@ MODULE_LICENSE("GPL"); static ssize_t show_card(struct device *cd, struct device_attribute *attr, char *buf) { - struct video_device *vfd = to_video_device(cd); + struct video_device *vfd = container_of(cd, struct video_device, class_dev); struct bttv *btv = dev_get_drvdata(vfd->dev); return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET); } @@ -470,31 +476,27 @@ static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms); /* ----------------------------------------------------------------------- */ /* bttv format list packed pixel formats must come first */ -static const struct bttv_format bttv_formats[] = { +static const struct bttv_format formats[] = { { .name = "8 bpp, gray", - .palette = VIDEO_PALETTE_GREY, .fourcc = V4L2_PIX_FMT_GREY, .btformat = BT848_COLOR_FMT_Y8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, },{ .name = "8 bpp, dithered color", - .palette = VIDEO_PALETTE_HI240, .fourcc = V4L2_PIX_FMT_HI240, .btformat = BT848_COLOR_FMT_RGB8, .depth = 8, .flags = FORMAT_FLAGS_PACKED | FORMAT_FLAGS_DITHER, },{ .name = "15 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB555, .fourcc = V4L2_PIX_FMT_RGB555, .btformat = BT848_COLOR_FMT_RGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "15 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB555X, .btformat = BT848_COLOR_FMT_RGB15, .btswap = 0x03, /* byteswap */ @@ -502,14 +504,12 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB565, .fourcc = V4L2_PIX_FMT_RGB565, .btformat = BT848_COLOR_FMT_RGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "16 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB565X, .btformat = BT848_COLOR_FMT_RGB16, .btswap = 0x03, /* byteswap */ @@ -517,21 +517,18 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "24 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB24, .fourcc = V4L2_PIX_FMT_BGR24, .btformat = BT848_COLOR_FMT_RGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, le", - .palette = VIDEO_PALETTE_RGB32, .fourcc = V4L2_PIX_FMT_BGR32, .btformat = BT848_COLOR_FMT_RGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, },{ .name = "32 bpp RGB, be", - .palette = -1, .fourcc = V4L2_PIX_FMT_RGB32, .btformat = BT848_COLOR_FMT_RGB32, .btswap = 0x0f, /* byte+word swap */ @@ -539,21 +536,18 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", - .palette = VIDEO_PALETTE_YUV422, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, YUYV", - .palette = VIDEO_PALETTE_YUYV, .fourcc = V4L2_PIX_FMT_YUYV, .btformat = BT848_COLOR_FMT_YUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, packed, UYVY", - .palette = VIDEO_PALETTE_UYVY, .fourcc = V4L2_PIX_FMT_UYVY, .btformat = BT848_COLOR_FMT_YUY2, .btswap = 0x03, /* byteswap */ @@ -561,7 +555,6 @@ static const struct bttv_format bttv_formats[] = { .flags = FORMAT_FLAGS_PACKED, },{ .name = "4:2:2, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV422P, .fourcc = V4L2_PIX_FMT_YUV422P, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 16, @@ -570,7 +563,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 0, },{ .name = "4:2:0, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV420P, .fourcc = V4L2_PIX_FMT_YUV420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -579,7 +571,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 1, },{ .name = "4:2:0, planar, Y-Cr-Cb", - .palette = -1, .fourcc = V4L2_PIX_FMT_YVU420, .btformat = BT848_COLOR_FMT_YCrCb422, .depth = 12, @@ -588,7 +579,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 1, },{ .name = "4:1:1, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV411P, .fourcc = V4L2_PIX_FMT_YUV411P, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 12, @@ -597,7 +587,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 0, },{ .name = "4:1:0, planar, Y-Cb-Cr", - .palette = VIDEO_PALETTE_YUV410P, .fourcc = V4L2_PIX_FMT_YUV410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -606,7 +595,6 @@ static const struct bttv_format bttv_formats[] = { .vshift = 2, },{ .name = "4:1:0, planar, Y-Cr-Cb", - .palette = -1, .fourcc = V4L2_PIX_FMT_YVU410, .btformat = BT848_COLOR_FMT_YCrCb411, .depth = 9, @@ -615,14 +603,13 @@ static const struct bttv_format bttv_formats[] = { .vshift = 2, },{ .name = "raw scanlines", - .palette = VIDEO_PALETTE_RAW, .fourcc = -1, .btformat = BT848_COLOR_FMT_RAW, .depth = 8, .flags = FORMAT_FLAGS_RAW, } }; -static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats); +static const unsigned int FORMATS = ARRAY_SIZE(formats); /* ----------------------------------------------------------------------- */ @@ -798,7 +785,17 @@ static const struct v4l2_queryctrl bttv_ctls[] = { }; -static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls); + +static const struct v4l2_queryctrl *ctrl_by_id(int id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) + if (bttv_ctls[i].id == id) + return bttv_ctls+i; + + return NULL; +} /* ----------------------------------------------------------------------- */ /* resource management */ @@ -1255,16 +1252,6 @@ audio_input(struct bttv *btv, int input) } static void -i2c_vidiocschan(struct bttv *btv) -{ - v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; - - bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); - if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200) - bttv_tda9880_setnorm(btv,btv->tvnorm); -} - -static void bttv_crop_calc_limits(struct bttv_crop *c) { /* Scale factor min. 1:1, max. 16:1. Min. image size @@ -1298,6 +1285,7 @@ static int set_tvnorm(struct bttv *btv, unsigned int norm) { const struct bttv_tvnorm *tvnorm; + v4l2_std_id id; if (norm < 0 || norm >= BTTV_TVNORMS) return -EINVAL; @@ -1334,6 +1322,9 @@ set_tvnorm(struct bttv *btv, unsigned int norm) bttv_tda9880_setnorm(btv,norm); break; } + id = tvnorm->v4l2_id; + bttv_call_i2c_clients(btv, VIDIOC_S_STD, &id); + return 0; } @@ -1359,7 +1350,6 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ? TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN)); set_tvnorm(btv, norm); - i2c_vidiocschan(btv); } static void init_irqreg(struct bttv *btv) @@ -1452,38 +1442,12 @@ static void bttv_reinit_bt848(struct bttv *btv) set_input(btv, btv->input, btv->tvnorm); } -static int get_control(struct bttv *btv, struct v4l2_control *c) +static int bttv_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) { - struct video_audio va; - int i; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) - return -EINVAL; - if (btv->audio_hook && i >= 4 && i <= 8) { - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (c->id) { - case V4L2_CID_AUDIO_MUTE: - c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; - break; - case V4L2_CID_AUDIO_VOLUME: - c->value = va.volume; - break; - case V4L2_CID_AUDIO_BALANCE: - c->value = va.balance; - break; - case V4L2_CID_AUDIO_BASS: - c->value = va.bass; - break; - case V4L2_CID_AUDIO_TREBLE: - c->value = va.treble; - break; - } - return 0; - } switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = btv->bright; @@ -1503,7 +1467,7 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c); + bttv_call_i2c_clients(btv, VIDIOC_G_CTRL, c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: @@ -1545,67 +1509,44 @@ static int get_control(struct bttv *btv, struct v4l2_control *c) return 0; } -static int set_control(struct bttv *btv, struct v4l2_control *c) +static int bttv_s_ctrl(struct file *file, void *f, + struct v4l2_control *c) { - struct video_audio va; - int i,val; + int err; + int val; + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) - return -EINVAL; - if (btv->audio_hook && i >= 4 && i <= 8) { - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (c->id) { - case V4L2_CID_AUDIO_MUTE: - if (c->value) { - va.flags |= VIDEO_AUDIO_MUTE; - audio_mute(btv, 1); - } else { - va.flags &= ~VIDEO_AUDIO_MUTE; - audio_mute(btv, 0); - } - break; + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; - case V4L2_CID_AUDIO_VOLUME: - va.volume = c->value; - break; - case V4L2_CID_AUDIO_BALANCE: - va.balance = c->value; - break; - case V4L2_CID_AUDIO_BASS: - va.bass = c->value; - break; - case V4L2_CID_AUDIO_TREBLE: - va.treble = c->value; - break; - } - btv->audio_hook(btv,&va,1); - return 0; - } switch (c->id) { case V4L2_CID_BRIGHTNESS: - bt848_bright(btv,c->value); + bt848_bright(btv, c->value); break; case V4L2_CID_HUE: - bt848_hue(btv,c->value); + bt848_hue(btv, c->value); break; case V4L2_CID_CONTRAST: - bt848_contrast(btv,c->value); + bt848_contrast(btv, c->value); break; case V4L2_CID_SATURATION: - bt848_sat(btv,c->value); + bt848_sat(btv, c->value); break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->value); /* fall through */ case V4L2_CID_AUDIO_VOLUME: + if (btv->volume_gpio) + btv->volume_gpio(btv, c->value); + + bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); + break; case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: - bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); + bttv_call_i2c_clients(btv, VIDIOC_S_CTRL, c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: @@ -1632,8 +1573,9 @@ static int set_control(struct bttv *btv, struct v4l2_control *c) break; case V4L2_CID_PRIVATE_AGC_CRUSH: btv->opt_adc_crush = c->value; - btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); + btwrite(BT848_ADC_RESERVED | + (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + BT848_ADC); break; case V4L2_CID_PRIVATE_VCR_HACK: btv->opt_vcr_hack = c->value; @@ -1693,29 +1635,15 @@ static void bttv_field_count(struct bttv *btv) } static const struct bttv_format* -format_by_palette(int palette) -{ - unsigned int i; - - for (i = 0; i < BTTV_FORMATS; i++) { - if (-1 == bttv_formats[i].palette) - continue; - if (bttv_formats[i].palette == palette) - return bttv_formats+i; - } - return NULL; -} - -static const struct bttv_format* format_by_fourcc(int fourcc) { unsigned int i; - for (i = 0; i < BTTV_FORMATS; i++) { - if (-1 == bttv_formats[i].fourcc) + for (i = 0; i < FORMATS; i++) { + if (-1 == formats[i].fourcc) continue; - if (bttv_formats[i].fourcc == fourcc) - return bttv_formats+i; + if (formats[i].fourcc == fourcc) + return formats+i; } return NULL; } @@ -1733,7 +1661,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, dprintk("switch_overlay: enter [new=%p]\n",new); if (new) - new->vb.state = STATE_DONE; + new->vb.state = VIDEOBUF_DONE; spin_lock_irqsave(&btv->s_lock,flags); old = btv->screen; btv->screen = new; @@ -1844,7 +1772,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, } /* alloc risc memory */ - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,&btv->fbuf))) goto fail; @@ -1854,7 +1782,7 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, if (0 != (rc = bttv_buffer_risc(btv,buf))) goto fail; - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -1893,7 +1821,7 @@ buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_fh *fh = q->priv_data; struct bttv *btv = fh->btv; - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue,&btv->capture); if (!btv->curr.frame_irq) { btv->loop_irq |= 1; @@ -1916,374 +1844,234 @@ static struct videobuf_queue_ops bttv_video_qops = { .buf_release = buffer_release, }; -static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg) +static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) { - switch (cmd) { - case BTTV_VERSION: - return BTTV_VERSION_CODE; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + unsigned int i; + int err; - /* *** v4l1 *** ************************************************ */ - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - *freq = btv->freq; - return 0; - } - case VIDIOCSFREQ: - { - struct v4l2_frequency freq; + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; - memset(&freq, 0, sizeof(freq)); - freq.frequency = *(unsigned long *)arg; - mutex_lock(&btv->lock); - freq.type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - btv->freq = *(unsigned long *)arg; - bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,&freq); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv,*(unsigned long *)arg); - mutex_unlock(&btv->lock); - return 0; - } + for (i = 0; i < BTTV_TVNORMS; i++) + if (*id & bttv_tvnorms[i].v4l2_id) + break; + if (i == BTTV_TVNORMS) + return -EINVAL; - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; + mutex_lock(&btv->lock); + set_tvnorm(btv, i); + mutex_unlock(&btv->lock); - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; - strcpy(v->name, "Television"); - v->rangelow = 0; - v->rangehigh = 0x7FFFFFFF; - v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - v->mode = btv->tvnorm; - v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - bttv_call_i2c_clients(btv,cmd,v); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; + return 0; +} - if (v->tuner) /* Only tuner 0 */ - return -EINVAL; - if (v->mode >= BTTV_TVNORMS) - return -EINVAL; +static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); - set_tvnorm(btv,v->mode); - bttv_call_i2c_clients(btv,cmd,v); - mutex_unlock(&btv->lock); - return 0; - } + if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) + *id = V4L2_STD_625_50; + else + *id = V4L2_STD_525_60; + return 0; +} - case VIDIOCGCHAN: - { - struct video_channel *v = arg; - unsigned int channel = v->channel; +static int bttv_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + unsigned int n; - if (channel >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - v->tuners=0; - v->flags = VIDEO_VC_AUDIO; - v->type = VIDEO_TYPE_CAMERA; - v->norm = btv->tvnorm; - if (channel == bttv_tvcards[btv->c.type].tuner) { - strcpy(v->name,"Television"); - v->flags|=VIDEO_VC_TUNER; - v->type=VIDEO_TYPE_TV; - v->tuners=1; - } else if (channel == btv->svhs) { - strcpy(v->name,"S-Video"); - } else { - sprintf(v->name,"Composite%d",channel); - } - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - unsigned int channel = v->channel; + n = i->index; - if (channel >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - if (v->norm >= BTTV_TVNORMS) - return -EINVAL; + if (n >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; - mutex_lock(&btv->lock); - if (channel == btv->input && - v->norm == btv->tvnorm) { - /* nothing to do */ - mutex_unlock(&btv->lock); - return 0; - } + memset(i, 0, sizeof(*i)); - set_input(btv, v->channel, v->norm); - mutex_unlock(&btv->lock); - return 0; + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + i->audioset = 1; + + if (i->index == bttv_tvcards[btv->c.type].tuner) { + sprintf(i->name, "Television"); + i->type = V4L2_INPUT_TYPE_TUNER; + i->tuner = 0; + } else if (i->index == btv->svhs) { + sprintf(i->name, "S-Video"); + } else { + sprintf(i->name, "Composite%d", i->index); } - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; + if (i->index == btv->input) { + __u32 dstatus = btread(BT848_DSTATUS); + if (0 == (dstatus & BT848_DSTATUS_PRES)) + i->status |= V4L2_IN_ST_NO_SIGNAL; + if (0 == (dstatus & BT848_DSTATUS_HLOC)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + } - memset(v,0,sizeof(*v)); - strcpy(v->name,"Television"); - v->flags |= VIDEO_AUDIO_MUTABLE; - v->mode = VIDEO_SOUND_MONO; + for (n = 0; n < BTTV_TVNORMS; n++) + i->std |= bttv_tvnorms[n].v4l2_id; - mutex_lock(&btv->lock); - bttv_call_i2c_clients(btv,cmd,v); + return 0; +} - /* card specific hooks */ - if (btv->audio_hook) - btv->audio_hook(btv,v,0); +static int bttv_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *v = arg; - unsigned int audio = v->audio; + *i = btv->input; + return 0; +} - if (audio >= bttv_tvcards[btv->c.type].audio_inputs) - return -EINVAL; +static int bttv_s_input(struct file *file, void *priv, unsigned int i) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - mutex_lock(&btv->lock); - audio_mute(btv, (v->flags&VIDEO_AUDIO_MUTE) ? 1 : 0); - bttv_call_i2c_clients(btv,cmd,v); + int err; - /* card specific hooks */ - if (btv->audio_hook) - btv->audio_hook(btv,v,1); + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; - mutex_unlock(&btv->lock); - return 0; - } + if (i > bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; - /* *** v4l2 *** ************************************************ */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int index = e->index; + mutex_lock(&btv->lock); + set_input(btv, i, btv->tvnorm); + mutex_unlock(&btv->lock); + return 0; +} - if (index >= BTTV_TVNORMS) - return -EINVAL; - v4l2_video_std_construct(e, bttv_tvnorms[e->index].v4l2_id, - bttv_tvnorms[e->index].name); - e->index = index; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - *id = bttv_tvnorms[btv->tvnorm].v4l2_id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; +static int bttv_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; - for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) - break; - if (i == BTTV_TVNORMS) - return -EINVAL; + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; - mutex_lock(&btv->lock); - set_tvnorm(btv,i); - i2c_vidiocschan(btv); - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *id = arg; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; - if (btread(BT848_DSTATUS) & BT848_DSTATUS_NUML) - *id = V4L2_STD_625_50; - else - *id = V4L2_STD_525_60; - return 0; - } + if (0 != t->index) + return -EINVAL; - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; + mutex_lock(&btv->lock); + bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); - n = i->index; - if (n >= bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - memset(i,0,sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; - if (i->index == bttv_tvcards[btv->c.type].tuner) { - sprintf(i->name, "Television"); - i->type = V4L2_INPUT_TYPE_TUNER; - i->tuner = 0; - } else if (i->index == btv->svhs) { - sprintf(i->name, "S-Video"); - } else { - sprintf(i->name,"Composite%d",i->index); - } - if (i->index == btv->input) { - __u32 dstatus = btread(BT848_DSTATUS); - if (0 == (dstatus & BT848_DSTATUS_PRES)) - i->status |= V4L2_IN_ST_NO_SIGNAL; - if (0 == (dstatus & BT848_DSTATUS_HLOC)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - } - for (n = 0; n < BTTV_TVNORMS; n++) - i->std |= bttv_tvnorms[n].v4l2_id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = btv->input; - return 0; - } - case VIDIOC_S_INPUT: - { - unsigned int *i = arg; + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 1); - if (*i > bttv_tvcards[btv->c.type].video_inputs) - return -EINVAL; - mutex_lock(&btv->lock); - set_input(btv, *i, btv->tvnorm); - mutex_unlock(&btv->lock); - return 0; - } + mutex_unlock(&btv->lock); - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; + return 0; +} - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - memset(t,0,sizeof(*t)); - t->rxsubchans = V4L2_TUNER_SUB_MONO; - bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); - strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; - t->type = V4L2_TUNER_ANALOG_TV; - if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) - t->signal = 0xffff; - - if (btv->audio_hook) { - /* Hmmm ... */ - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - btv->audio_hook(btv,&va,0); - t->audmode = V4L2_TUNER_MODE_MONO; - t->rxsubchans = V4L2_TUNER_SUB_MONO; - if(va.mode & VIDEO_SOUND_STEREO) { - t->audmode = V4L2_TUNER_MODE_STEREO; - t->rxsubchans = V4L2_TUNER_SUB_STEREO; - } - if(va.mode & VIDEO_SOUND_LANG2) { - t->audmode = V4L2_TUNER_MODE_LANG1; - t->rxsubchans = V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; - } - } - /* FIXME: fill capability+audmode */ - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; +static int bttv_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; - if (UNSET == bttv_tvcards[btv->c.type].tuner) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - mutex_lock(&btv->lock); - bttv_call_i2c_clients(btv, VIDIOC_S_TUNER, t); - if (btv->audio_hook) { - struct video_audio va; - memset(&va, 0, sizeof(struct video_audio)); - if (t->audmode == V4L2_TUNER_MODE_MONO) - va.mode = VIDEO_SOUND_MONO; - else if (t->audmode == V4L2_TUNER_MODE_STEREO || - t->audmode == V4L2_TUNER_MODE_LANG1_LANG2) - va.mode = VIDEO_SOUND_STEREO; - else if (t->audmode == V4L2_TUNER_MODE_LANG1) - va.mode = VIDEO_SOUND_LANG1; - else if (t->audmode == V4L2_TUNER_MODE_LANG2) - va.mode = VIDEO_SOUND_LANG2; - btv->audio_hook(btv,&va,1); - } - mutex_unlock(&btv->lock); - return 0; - } + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = btv->freq; - memset(f,0,sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = btv->freq; - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; + return 0; +} + +static int bttv_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int err; + + err = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != err) + return err; + + if (unlikely(f->tuner != 0)) + return -EINVAL; + if (unlikely(f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + mutex_lock(&btv->lock); + btv->freq = f->frequency; + bttv_call_i2c_clients(btv, VIDIOC_S_FREQUENCY, f); + if (btv->has_matchbox && btv->radio_user) + tea5757_set_freq(btv, btv->freq); + mutex_unlock(&btv->lock); + return 0; +} + +static int bttv_log_status(struct file *file, void *f) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + printk(KERN_INFO "bttv%d: ======== START STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); + bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); + printk(KERN_INFO "bttv%d: ======== END STATUS CARD #%d ========\n", + btv->c.nr, btv->c.nr); + return 0; +} - if (unlikely(f->tuner != 0)) - return -EINVAL; - if (unlikely (f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - mutex_lock(&btv->lock); - btv->freq = f->frequency; - bttv_call_i2c_clients(btv,VIDIOC_S_FREQUENCY,f); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv,btv->freq); - mutex_unlock(&btv->lock); - return 0; - } - case VIDIOC_LOG_STATUS: - { - printk(KERN_INFO "bttv%d: ================= START STATUS CARD #%d =================\n", btv->c.nr, btv->c.nr); - bttv_call_i2c_clients(btv, VIDIOC_LOG_STATUS, NULL); - printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr); - return 0; - } #ifdef CONFIG_VIDEO_ADV_DEBUG - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - { - struct v4l2_register *reg = arg; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - if (cmd == VIDIOC_DBG_G_REGISTER) - reg->val = btread(reg->reg); - else - btwrite(reg->val, reg->reg); - return 0; - } -#endif +static int bttv_g_register(struct file *file, void *f, + struct v4l2_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - default: - return -ENOIOCTLCMD; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + reg->val = btread(reg->reg); + + return 0; +} + +static int bttv_s_register(struct file *file, void *f, + struct v4l2_register *reg) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + /* bt848 has a 12-bit register space */ + reg->reg &= 0xfff; + btwrite(reg->val, reg->reg); - } return 0; } +#endif /* Given cropping boundaries b and the scaled width and height of a single field or frame, which must not exceed hardware limits, this @@ -2659,983 +2447,681 @@ pix_format_set_size (struct v4l2_pix_format * f, } } -static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f) +static int bttv_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - memset(&f->fmt.pix,0,sizeof(struct v4l2_pix_format)); - pix_format_set_size (&f->fmt.pix, fh->fmt, - fh->width, fh->height); - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - memset(&f->fmt.win,0,sizeof(struct v4l2_window)); - f->fmt.win.w = fh->ov.w; - f->fmt.win.field = fh->ov.field; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - bttv_vbi_get_fmt(fh, &f->fmt.vbi); - return 0; - default: - return -EINVAL; - } + struct bttv_fh *fh = priv; + + pix_format_set_size(&f->fmt.pix, fh->fmt, + fh->width, fh->height); + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + + return 0; } -static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv, - struct v4l2_format *f, int adjust_crop) +static int bttv_g_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - const struct bttv_format *fmt; - enum v4l2_field field; - __s32 width, height; - int rc; + struct bttv_fh *fh = priv; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; + f->fmt.win.w = fh->ov.w; + f->fmt.win.field = fh->ov.field; - field = f->fmt.pix.field; - if (V4L2_FIELD_ANY == field) { - __s32 height2; + return 0; +} - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (f->fmt.pix.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - if (V4L2_FIELD_SEQ_BT == field) - field = V4L2_FIELD_SEQ_TB; - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - case V4L2_FIELD_INTERLACED: - break; - case V4L2_FIELD_SEQ_TB: - if (fmt->flags & FORMAT_FLAGS_PLANAR) - return -EINVAL; - break; - default: - return -EINVAL; - } +static int bttv_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + enum v4l2_field field; + __s32 width, height; + int rc; - width = f->fmt.pix.width; - height = f->fmt.pix.height; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - rc = limit_scaled_size(fh, &width, &height, field, - /* width_mask: 4 pixels */ ~3, - /* width_bias: nearest */ 2, - /* adjust_size */ 1, - adjust_crop); - if (0 != rc) - return rc; + field = f->fmt.pix.field; - /* update data for the application */ - f->fmt.pix.field = field; - pix_format_set_size(&f->fmt.pix, fmt, width, height); + if (V4L2_FIELD_ANY == field) { + __s32 height2; - return 0; + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (f->fmt.pix.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - return verify_window(fh, &f->fmt.win, - /* adjust_size */ 1, - /* adjust_crop */ 0); - case V4L2_BUF_TYPE_VBI_CAPTURE: - return bttv_vbi_try_fmt(fh, &f->fmt.vbi); + + if (V4L2_FIELD_SEQ_BT == field) + field = V4L2_FIELD_SEQ_TB; + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_SEQ_TB: + if (fmt->flags & FORMAT_FLAGS_PLANAR) + return -EINVAL; + break; default: return -EINVAL; } + + width = f->fmt.pix.width; + height = f->fmt.pix.height; + + rc = limit_scaled_size(fh, &width, &height, field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 0); + if (0 != rc) + return rc; + + /* update data for the application */ + f->fmt.pix.field = field; + pix_format_set_size(&f->fmt.pix, fmt, width, height); + + return 0; } -static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, - struct v4l2_format *f) +static int bttv_try_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + + return verify_window(fh, &f->fmt.win, + /* adjust_size */ 1, + /* adjust_crop */ 0); +} + +static int bttv_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { int retval; + const struct bttv_format *fmt; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + __s32 width, height; + enum v4l2_field field; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - const struct bttv_format *fmt; + retval = bttv_switch_type(fh, f->type); + if (0 != retval) + return retval; - retval = bttv_switch_type(fh,f->type); - if (0 != retval) - return retval; - retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1); - if (0 != retval) - return retval; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); + retval = bttv_try_fmt_cap(file, priv, f); + if (0 != retval) + return retval; - /* update our state informations */ - mutex_lock(&fh->cap.lock); - fh->fmt = fmt; - fh->cap.field = f->fmt.pix.field; - fh->cap.last = V4L2_FIELD_NONE; - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - btv->init.fmt = fmt; - btv->init.width = f->fmt.pix.width; - btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.lock); + width = f->fmt.pix.width; + height = f->fmt.pix.height; + field = f->fmt.pix.field; - return 0; - } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - return setup_window(fh, btv, &f->fmt.win, 1); - case V4L2_BUF_TYPE_VBI_CAPTURE: - retval = bttv_switch_type(fh,f->type); - if (0 != retval) - return retval; - return bttv_vbi_set_fmt(fh, &f->fmt.vbi); - default: - return -EINVAL; - } -} + retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field, + /* width_mask: 4 pixels */ ~3, + /* width_bias: nearest */ 2, + /* adjust_size */ 1, + /* adjust_crop */ 1); + if (0 != retval) + return retval; -static int bttv_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct bttv_fh *fh = file->private_data; - struct bttv *btv = fh->btv; - unsigned long flags; - int retval = 0; + f->fmt.pix.field = field; - if (bttv_debug > 1) - v4l_print_ioctl(btv->c.name, cmd); - - if (btv->errors) - bttv_reinit_bt848(btv); - - switch (cmd) { - case VIDIOCSFREQ: - case VIDIOCSTUNER: - case VIDIOCSCHAN: - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - retval = v4l2_prio_check(&btv->prio,&fh->prio); - if (0 != retval) - return retval; - }; + fmt = format_by_fourcc(f->fmt.pix.pixelformat); - switch (cmd) { + /* update our state informations */ + mutex_lock(&fh->cap.lock); + fh->fmt = fmt; + fh->cap.field = f->fmt.pix.field; + fh->cap.last = V4L2_FIELD_NONE; + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + btv->init.fmt = fmt; + btv->init.width = f->fmt.pix.width; + btv->init.height = f->fmt.pix.height; + mutex_unlock(&fh->cap.lock); - /* *** v4l1 *** ************************************************ */ - case VIDIOCGCAP: - { - struct video_capability *cap = arg; + return 0; +} - memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->video_dev->name); - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - /* vbi */ - cap->type = VID_TYPE_TUNER|VID_TYPE_TELETEXT; - } else { - /* others */ - cap->type = VID_TYPE_CAPTURE| - VID_TYPE_TUNER| - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - if (no_overlay <= 0) - cap->type |= VID_TYPE_OVERLAY; - - cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth; - cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight; - cap->minwidth = 48; - cap->minheight = 32; - } - cap->channels = bttv_tvcards[btv->c.type].video_inputs; - cap->audios = bttv_tvcards[btv->c.type].audio_inputs; - return 0; - } +static int bttv_s_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - case VIDIOCGPICT: - { - struct video_picture *pic = arg; - - memset(pic,0,sizeof(*pic)); - pic->brightness = btv->bright; - pic->contrast = btv->contrast; - pic->hue = btv->hue; - pic->colour = btv->saturation; - if (fh->fmt) { - pic->depth = fh->fmt->depth; - pic->palette = fh->fmt->palette; - } - return 0; + if (no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; } - case VIDIOCSPICT: - { - struct video_picture *pic = arg; - const struct bttv_format *fmt; - fmt = format_by_palette(pic->palette); - if (NULL == fmt) - return -EINVAL; - mutex_lock(&fh->cap.lock); - if (fmt->flags & FORMAT_FLAGS_RAW) { - /* VIDIOCMCAPTURE uses gbufsize, not RAW_BPL * - RAW_LINES * 2. F1 is stored at offset 0, F2 - at buffer size / 2. */ - fh->width = RAW_BPL; - fh->height = gbufsize / RAW_BPL; - btv->init.width = RAW_BPL; - btv->init.height = gbufsize / RAW_BPL; - } - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - if (bigendian) { - /* dirty hack time: swap bytes for overlay if the - display adaptor is big endian (insmod option) */ - if (fmt->palette == VIDEO_PALETTE_RGB555 || - fmt->palette == VIDEO_PALETTE_RGB565 || - fmt->palette == VIDEO_PALETTE_RGB32) { - fh->ovfmt = fmt+1; - } - } - bt848_bright(btv,pic->brightness); - bt848_contrast(btv,pic->contrast); - bt848_hue(btv,pic->hue); - bt848_sat(btv,pic->colour); + return setup_window(fh, btv, &f->fmt.win, 1); +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + int retval; + unsigned int i; + struct bttv_fh *fh = priv; + + mutex_lock(&fh->cap.lock); + retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, + V4L2_MEMORY_MMAP); + if (retval < 0) { mutex_unlock(&fh->cap.lock); - return 0; + return retval; } - case VIDIOCGWIN: - { - struct video_window *win = arg; + gbuffers = retval; + memset(mbuf, 0, sizeof(*mbuf)); + mbuf->frames = gbuffers; + mbuf->size = gbuffers * gbufsize; - memset(win,0,sizeof(*win)); - win->x = fh->ov.w.left; - win->y = fh->ov.w.top; - win->width = fh->ov.w.width; - win->height = fh->ov.w.height; - return 0; - } - case VIDIOCSWIN: - { - struct video_window *win = arg; - struct v4l2_window w2; + for (i = 0; i < gbuffers; i++) + mbuf->offsets[i] = i * gbufsize; - if (no_overlay > 0) { - printk ("VIDIOCSWIN: no_overlay\n"); - return -EINVAL; - } + mutex_unlock(&fh->cap.lock); + return 0; +} +#endif - w2.field = V4L2_FIELD_ANY; - w2.w.left = win->x; - w2.w.top = win->y; - w2.w.width = win->width; - w2.w.height = win->height; - w2.clipcount = win->clipcount; - w2.clips = (struct v4l2_clip __user *)win->clips; - retval = setup_window(fh, btv, &w2, 0); - if (0 == retval) { - /* on v4l1 this ioctl affects the read() size too */ - fh->width = fh->ov.w.width; - fh->height = fh->ov.w.height; - btv->init.width = fh->ov.w.width; - btv->init.height = fh->ov.w.height; - } - return retval; - } +static int bttv_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - case VIDIOCGFBUF: - { - struct video_buffer *fbuf = arg; - - fbuf->base = btv->fbuf.base; - fbuf->width = btv->fbuf.fmt.width; - fbuf->height = btv->fbuf.fmt.height; - fbuf->bytesperline = btv->fbuf.fmt.bytesperline; - if (fh->ovfmt) - fbuf->depth = fh->ovfmt->depth; - else { - if (fbuf->width) - fbuf->depth = ((fbuf->bytesperline<<3) - + (fbuf->width-1) ) - /fbuf->width; - else - fbuf->depth = 0; - } - return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer *fbuf = arg; - const struct bttv_format *fmt; - unsigned long end; - - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; - end = (unsigned long)fbuf->base + - fbuf->height * fbuf->bytesperline; - mutex_lock(&fh->cap.lock); - retval = -EINVAL; + if (0 == v4l2) + return -EINVAL; - switch (fbuf->depth) { - case 8: - fmt = format_by_palette(VIDEO_PALETTE_HI240); - break; - case 16: - fmt = format_by_palette(VIDEO_PALETTE_RGB565); - break; - case 24: - fmt = format_by_palette(VIDEO_PALETTE_RGB24); - break; - case 32: - fmt = format_by_palette(VIDEO_PALETTE_RGB32); - break; - case 15: - fbuf->depth = 16; - fmt = format_by_palette(VIDEO_PALETTE_RGB555); - break; - default: - fmt = NULL; - break; - } - if (NULL == fmt) - goto fh_unlock_and_return; - - fh->ovfmt = fmt; - fh->fmt = fmt; - btv->init.ovfmt = fmt; - btv->init.fmt = fmt; - btv->fbuf.base = fbuf->base; - btv->fbuf.fmt.width = fbuf->width; - btv->fbuf.fmt.height = fbuf->height; - if (fbuf->bytesperline) - btv->fbuf.fmt.bytesperline = fbuf->bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8; - mutex_unlock(&fh->cap.lock); - return 0; - } + strlcpy(cap->driver, "bttv", sizeof(cap->driver)); + strlcpy(cap->card, btv->video_dev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + if (bttv_tvcards[btv->c.type].tuner != UNSET && + bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} - case VIDIOCCAPTURE: - case VIDIOC_OVERLAY: - { - struct bttv_buffer *new; - int *on = arg; +static int bttv_enum_fmt_vbi(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (0 != f->index) + return -EINVAL; - if (*on) { - /* verify args */ - if (NULL == btv->fbuf.base) - return -EINVAL; - if (!fh->ov.setup_ok) { - dprintk("bttv%d: overlay: !setup_ok\n",btv->c.nr); - return -EINVAL; - } - } + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); - if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) - return -EBUSY; + return 0; +} - mutex_lock(&fh->cap.lock); - if (*on) { - fh->ov.tvnorm = btv->tvnorm; - new = videobuf_pci_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); - } else { - new = NULL; - } +static int bttv_enum_fmt_cap_ovr(struct v4l2_fmtdesc *f) +{ + int index = -1, i; - /* switch over */ - retval = bttv_switch_overlay(btv,fh,new); - mutex_unlock(&fh->cap.lock); - return retval; + for (i = 0; i < FORMATS; i++) { + if (formats[i].fourcc != -1) + index++; + if ((unsigned int)index == f->index) + break; } + if (FORMATS == i) + return -EINVAL; - case VIDIOCGMBUF: - { - struct video_mbuf *mbuf = arg; - unsigned int i; + f->pixelformat = formats[i].fourcc; + strlcpy(f->description, formats[i].name, sizeof(f->description)); - retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize, - V4L2_MEMORY_MMAP); - if (retval < 0) - return retval; + return i; +} - gbuffers = retval; - memset(mbuf,0,sizeof(*mbuf)); - mbuf->frames = gbuffers; - mbuf->size = gbuffers * gbufsize; - for (i = 0; i < gbuffers; i++) - mbuf->offsets[i] = i * gbufsize; - return 0; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - struct bttv_buffer *buf; - enum v4l2_field field; - __s32 height2; - int res; +static int bttv_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int rc = bttv_enum_fmt_cap_ovr(f); - if (vm->frame >= VIDEO_MAX_FRAME) - return -EINVAL; + if (rc < 0) + return rc; - res = bttv_resource(fh); - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; + return 0; +} - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; - if (NULL == buf) - goto fh_unlock_and_return; - if (0 == buf->vb.baddr) - goto fh_unlock_and_return; - if (buf->vb.state == STATE_QUEUED || - buf->vb.state == STATE_ACTIVE) - goto fh_unlock_and_return; +static int bttv_enum_fmt_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int rc; - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (vm->height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - retval = bttv_prepare_buffer(&fh->cap,btv,buf, - format_by_palette(vm->format), - vm->width,vm->height,field); - if (0 != retval) - goto fh_unlock_and_return; - btv->init.width = vm->width; - btv->init.height = vm->height; - spin_lock_irqsave(&btv->s_lock,flags); - buffer_queue(&fh->cap,&buf->vb); - spin_unlock_irqrestore(&btv->s_lock,flags); - mutex_unlock(&fh->cap.lock); - return 0; + if (no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; } - case VIDIOCSYNC: - { - int *frame = arg; - struct bttv_buffer *buf; - if (*frame >= VIDEO_MAX_FRAME) - return -EINVAL; + rc = bttv_enum_fmt_cap_ovr(f); - mutex_lock(&fh->cap.lock); - retval = -EINVAL; - buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; - if (NULL == buf) - goto fh_unlock_and_return; - retval = videobuf_waiton(&buf->vb,0,1); - if (0 != retval) - goto fh_unlock_and_return; - switch (buf->vb.state) { - case STATE_ERROR: - retval = -EIO; - /* fall through */ - case STATE_DONE: - { - struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); - videobuf_dma_sync(&fh->cap,dma); - bttv_dma_free(&fh->cap,btv,buf); - break; - } - default: - retval = -EINVAL; - break; - } - mutex_unlock(&fh->cap.lock); - return retval; - } + if (rc < 0) + return rc; - case VIDIOCGVBIFMT: - if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) { - retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); - if (0 != retval) - return retval; - } + if (!(formats[rc].flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; - /* fall through */ + return 0; +} - case VIDIOCSVBIFMT: - return v4l_compat_translate_ioctl(inode, file, cmd, - arg, bttv_do_ioctl); - - case BTTV_VERSION: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGCHAN: - case VIDIOCSCHAN: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - return bttv_common_ioctls(btv,cmd,arg); - - /* *** v4l2 *** ************************************************ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; +static int bttv_g_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - if (0 == v4l2) - return -EINVAL; - memset(cap, 0, sizeof (*cap)); - strlcpy(cap->driver, "bttv", sizeof (cap->driver)); - strlcpy(cap->card, btv->video_dev->name, sizeof (cap->card)); - snprintf(cap->bus_info, sizeof (cap->bus_info), - "PCI:%s", pci_name(btv->c.pci)); - cap->version = BTTV_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - - if (bttv_tvcards[btv->c.type].tuner != UNSET && - bttv_tvcards[btv->c.type].tuner != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; - } + *fb = btv->fbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + if (fh->ovfmt) + fb->fmt.pixelformat = fh->ovfmt->fourcc; + return 0; +} - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int i; - int index; - - type = f->type; - if (V4L2_BUF_TYPE_VBI_CAPTURE == type) { - /* vbi */ - index = f->index; - if (0 != index) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description,"vbi data"); - return 0; - } +static int bttv_overlay(struct file *file, void *f, unsigned int on) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + struct bttv_buffer *new; + int retval; - /* video capture + overlay */ - index = -1; - for (i = 0; i < BTTV_FORMATS; i++) { - if (bttv_formats[i].fourcc != -1) - index++; - if ((unsigned int)index == f->index) - break; - } - if (BTTV_FORMATS == i) + if (on) { + /* verify args */ + if (NULL == btv->fbuf.base) return -EINVAL; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - break; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (!(bttv_formats[i].flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; - break; - default: + if (!fh->ov.setup_ok) { + dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr); return -EINVAL; } - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = bttv_formats[i].fourcc; - strlcpy(f->description,bttv_formats[i].name,sizeof(f->description)); - return 0; } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0); - } - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return bttv_g_fmt(fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return bttv_s_fmt(fh,btv,f); + if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY)) + return -EBUSY; + + mutex_lock(&fh->cap.lock); + if (on) { + fh->ov.tvnorm = btv->tvnorm; + new = videobuf_pci_alloc(sizeof(*new)); + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + } else { + new = NULL; } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *fb = arg; + /* switch over */ + retval = bttv_switch_overlay(btv, fh, new); + mutex_unlock(&fh->cap.lock); + return retval; +} - *fb = btv->fbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - if (fh->ovfmt) - fb->fmt.pixelformat = fh->ovfmt->fourcc; - return 0; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *fb = arg; - const struct bttv_format *fmt; +static int bttv_s_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct bttv_format *fmt; + int retval; - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; + if (!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; - if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) - return -EINVAL; + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) + return -EINVAL; - retval = -EINVAL; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - __s32 width = fb->fmt.width; - __s32 height = fb->fmt.height; - - retval = limit_scaled_size(fh, &width, &height, - V4L2_FIELD_INTERLACED, - /* width_mask */ ~3, - /* width_bias */ 2, - /* adjust_size */ 0, - /* adjust_crop */ 0); - if (0 != retval) - return retval; - } + retval = -EINVAL; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + __s32 width = fb->fmt.width; + __s32 height = fb->fmt.height; + + retval = limit_scaled_size(fh, &width, &height, + V4L2_FIELD_INTERLACED, + /* width_mask */ ~3, + /* width_bias */ 2, + /* adjust_size */ 0, + /* adjust_crop */ 0); + if (0 != retval) + return retval; + } - /* ok, accept it */ - mutex_lock(&fh->cap.lock); - btv->fbuf.base = fb->base; - btv->fbuf.fmt.width = fb->fmt.width; - btv->fbuf.fmt.height = fb->fmt.height; - if (0 != fb->fmt.bytesperline) - btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; - else - btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; - - retval = 0; - fh->ovfmt = fmt; - btv->init.ovfmt = fmt; - if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { - fh->ov.w.left = 0; - fh->ov.w.top = 0; - fh->ov.w.width = fb->fmt.width; - fh->ov.w.height = fb->fmt.height; - btv->init.ov.w.width = fb->fmt.width; - btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); - fh->ov.clips = NULL; - fh->ov.nclips = 0; - - if (check_btres(fh, RESOURCE_OVERLAY)) { - struct bttv_buffer *new; - - new = videobuf_pci_alloc(sizeof(*new)); - new->crop = btv->crop[!!fh->do_crop].rect; - bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new); - retval = bttv_switch_overlay(btv,fh,new); - } + /* ok, accept it */ + mutex_lock(&fh->cap.lock); + btv->fbuf.base = fb->base; + btv->fbuf.fmt.width = fb->fmt.width; + btv->fbuf.fmt.height = fb->fmt.height; + if (0 != fb->fmt.bytesperline) + btv->fbuf.fmt.bytesperline = fb->fmt.bytesperline; + else + btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fmt->depth/8; + + retval = 0; + fh->ovfmt = fmt; + btv->init.ovfmt = fmt; + if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { + fh->ov.w.left = 0; + fh->ov.w.top = 0; + fh->ov.w.width = fb->fmt.width; + fh->ov.w.height = fb->fmt.height; + btv->init.ov.w.width = fb->fmt.width; + btv->init.ov.w.height = fb->fmt.height; + kfree(fh->ov.clips); + fh->ov.clips = NULL; + fh->ov.nclips = 0; + + if (check_btres(fh, RESOURCE_OVERLAY)) { + struct bttv_buffer *new; + + new = videobuf_pci_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; + bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); + retval = bttv_switch_overlay(btv, fh, new); } - mutex_unlock(&fh->cap.lock); - return retval; } + mutex_unlock(&fh->cap.lock); + return retval; +} - case VIDIOC_REQBUFS: - return videobuf_reqbufs(bttv_queue(fh),arg); +static int bttv_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct bttv_fh *fh = priv; + return videobuf_reqbufs(bttv_queue(fh), p); +} - case VIDIOC_QUERYBUF: - return videobuf_querybuf(bttv_queue(fh),arg); +static int bttv_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_querybuf(bttv_queue(fh), b); +} - case VIDIOC_QBUF: - { - int res = bttv_resource(fh); +static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); - if (!check_alloc_btres(btv, fh, res)) - return -EBUSY; - return videobuf_qbuf(bttv_queue(fh),arg); - } + if (!check_alloc_btres(btv, fh, res)) + return -EBUSY; - case VIDIOC_DQBUF: - return videobuf_dqbuf(bttv_queue(fh),arg, - file->f_flags & O_NONBLOCK); + return videobuf_qbuf(bttv_queue(fh), b); +} - case VIDIOC_STREAMON: - { - int res = bttv_resource(fh); +static int bttv_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct bttv_fh *fh = priv; + return videobuf_dqbuf(bttv_queue(fh), b, + file->f_flags & O_NONBLOCK); +} - if (!check_alloc_btres(btv,fh,res)) - return -EBUSY; - return videobuf_streamon(bttv_queue(fh)); - } - case VIDIOC_STREAMOFF: - { - int res = bttv_resource(fh); +static int bttv_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int res = bttv_resource(fh); - retval = videobuf_streamoff(bttv_queue(fh)); - if (retval < 0) - return retval; - free_btres(btv,fh,res); - return 0; - } + if (!check_alloc_btres(btv, fh, res)) + return -EBUSY; + return videobuf_streamon(bttv_queue(fh)); +} - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *c = arg; - int i; - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - for (i = 0; i < BTTV_CTLS; i++) - if (bttv_ctls[i].id == c->id) - break; - if (i == BTTV_CTLS) { - *c = no_ctl; - return 0; - } - *c = bttv_ctls[i]; - if (btv->audio_hook && i >= 4 && i <= 8) { - struct video_audio va; - memset(&va,0,sizeof(va)); - btv->audio_hook(btv,&va,0); - switch (bttv_ctls[i].id) { - case V4L2_CID_AUDIO_VOLUME: - if (!(va.flags & VIDEO_AUDIO_VOLUME)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_BALANCE: - if (!(va.flags & VIDEO_AUDIO_BALANCE)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_BASS: - if (!(va.flags & VIDEO_AUDIO_BASS)) - *c = no_ctl; - break; - case V4L2_CID_AUDIO_TREBLE: - if (!(va.flags & VIDEO_AUDIO_TREBLE)) - *c = no_ctl; - break; - } - } - return 0; - } - case VIDIOC_G_CTRL: - return get_control(btv,arg); - case VIDIOC_S_CTRL: - return set_control(btv,arg); - case VIDIOC_G_PARM: - { - struct v4l2_streamparm *parm = arg; - struct v4l2_standard s; - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - memset(parm,0,sizeof(*parm)); - v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, - bttv_tvnorms[btv->tvnorm].name); - parm->parm.capture.timeperframe = s.frameperiod; - return 0; - } +static int bttv_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + int retval; + int res = bttv_resource(fh); - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; - *p = v4l2_prio_max(&btv->prio); - return 0; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; + retval = videobuf_streamoff(bttv_queue(fh)); + if (retval < 0) + return retval; + free_btres(btv, fh, res); + return 0; +} - return v4l2_prio_change(&btv->prio, &fh->prio, *prio); - } +static int bttv_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + const struct v4l2_queryctrl *ctrl; - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cap = arg; - enum v4l2_buf_type type; + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; - type = cap->type; + if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) + *c = no_ctl; + else { + ctrl = ctrl_by_id(c->id); - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + *c = (NULL != ctrl) ? *ctrl : no_ctl; + } - *cap = bttv_tvnorms[btv->tvnorm].cropcap; - cap->type = type; + return 0; +} - return 0; - } - case VIDIOC_G_CROP: - { - struct v4l2_crop * crop = arg; +static int bttv_g_parm(struct file *file, void *f, + struct v4l2_streamparm *parm) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + struct v4l2_standard s; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + v4l2_video_std_construct(&s, bttv_tvnorms[btv->tvnorm].v4l2_id, + bttv_tvnorms[btv->tvnorm].name); + parm->parm.capture.timeperframe = s.frameperiod; + return 0; +} - /* No fh->do_crop = 1; because btv->crop[1] may be - inconsistent with fh->width or fh->height and apps - do not expect a change here. */ +static int bttv_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - crop->c = btv->crop[!!fh->do_crop].rect; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; - return 0; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *crop = arg; - const struct v4l2_rect *b; - struct bttv_crop c; - __s32 b_left; - __s32 b_top; - __s32 b_right; - __s32 b_bottom; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; + mutex_lock(&btv->lock); + memset(t, 0, sizeof(*t)); + t->rxsubchans = V4L2_TUNER_SUB_MONO; + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + strcpy(t->name, "Television"); + t->capability = V4L2_TUNER_CAP_NORM; + t->type = V4L2_TUNER_ANALOG_TV; + if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) + t->signal = 0xffff; + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); - retval = v4l2_prio_check(&btv->prio,&fh->prio); - if (0 != retval) - return retval; + mutex_unlock(&btv->lock); + return 0; +} - /* Make sure tvnorm, vbi_end and the current cropping - parameters remain consistent until we're done. Note - read() may change vbi_end in check_alloc_btres(). */ - mutex_lock(&btv->lock); +static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - retval = -EBUSY; + *p = v4l2_prio_max(&btv->prio); - if (locked_btres(fh->btv, VIDEO_RESOURCES)) - goto btv_unlock_and_return; + return 0; +} - b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; +static int bttv_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - b_left = b->left; - b_right = b_left + b->width; - b_bottom = b->top + b->height; + return v4l2_prio_change(&btv->prio, &fh->prio, prio); +} - b_top = max(b->top, btv->vbi_end); - if (b_top + 32 >= b_bottom) - goto btv_unlock_and_return; +static int bttv_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - /* Min. scaled size 48 x 32. */ - c.rect.left = clamp(crop->c.left, b_left, b_right - 48); - c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - c.rect.width = clamp(crop->c.width, - 48, b_right - c.rect.left); + *cap = bttv_tvnorms[btv->tvnorm].cropcap; - c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); - /* Top and height must be a multiple of two. */ - c.rect.top = (c.rect.top + 1) & ~1; + return 0; +} - c.rect.height = clamp(crop->c.height, - 32, b_bottom - c.rect.top); - c.rect.height = (c.rect.height + 1) & ~1; +static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; - bttv_crop_calc_limits(&c); + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - btv->crop[1] = c; + /* No fh->do_crop = 1; because btv->crop[1] may be + inconsistent with fh->width or fh->height and apps + do not expect a change here. */ - mutex_unlock(&btv->lock); + crop->c = btv->crop[!!fh->do_crop].rect; - fh->do_crop = 1; + return 0; +} - mutex_lock(&fh->cap.lock); +static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + const struct v4l2_rect *b; + int retval; + struct bttv_crop c; + __s32 b_left; + __s32 b_top; + __s32 b_right; + __s32 b_bottom; - if (fh->width < c.min_scaled_width) { - fh->width = c.min_scaled_width; - btv->init.width = c.min_scaled_width; - } else if (fh->width > c.max_scaled_width) { - fh->width = c.max_scaled_width; - btv->init.width = c.max_scaled_width; - } + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; - if (fh->height < c.min_scaled_height) { - fh->height = c.min_scaled_height; - btv->init.height = c.min_scaled_height; - } else if (fh->height > c.max_scaled_height) { - fh->height = c.max_scaled_height; - btv->init.height = c.max_scaled_height; - } + retval = v4l2_prio_check(&btv->prio, &fh->prio); + if (0 != retval) + return retval; - mutex_unlock(&fh->cap.lock); + /* Make sure tvnorm, vbi_end and the current cropping + parameters remain consistent until we're done. Note + read() may change vbi_end in check_alloc_btres(). */ + mutex_lock(&btv->lock); - return 0; + retval = -EBUSY; + + if (locked_btres(fh->btv, VIDEO_RESOURCES)) { + mutex_unlock(&btv->lock); + return retval; } - case VIDIOC_ENUMSTD: - case VIDIOC_G_STD: - case VIDIOC_S_STD: - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_G_TUNER: - case VIDIOC_S_TUNER: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - case VIDIOC_LOG_STATUS: - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - return bttv_common_ioctls(btv,cmd,arg); + b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds; - default: - return -ENOIOCTLCMD; + b_left = b->left; + b_right = b_left + b->width; + b_bottom = b->top + b->height; + + b_top = max(b->top, btv->vbi_end); + if (b_top + 32 >= b_bottom) { + mutex_unlock(&btv->lock); + return retval; } - return 0; - fh_unlock_and_return: - mutex_unlock(&fh->cap.lock); - return retval; + /* Min. scaled size 48 x 32. */ + c.rect.left = clamp(crop->c.left, b_left, b_right - 48); + c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY); - btv_unlock_and_return: - mutex_unlock(&btv->lock); - return retval; -} + c.rect.width = clamp(crop->c.width, + 48, b_right - c.rect.left); -static int bttv_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct bttv_fh *fh = file->private_data; + c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32); + /* Top and height must be a multiple of two. */ + c.rect.top = (c.rect.top + 1) & ~1; - switch (cmd) { - case BTTV_VBISIZE: - { - const struct bttv_tvnorm *tvnorm; + c.rect.height = clamp(crop->c.height, + 32, b_bottom - c.rect.top); + c.rect.height = (c.rect.height + 1) & ~1; - tvnorm = fh->vbi_fmt.tvnorm; + bttv_crop_calc_limits(&c); - if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] || - fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] || - fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) { - /* BTTV_VBISIZE cannot express these parameters, - however open() resets the paramters to defaults - and apps shouldn't call BTTV_VBISIZE after - VIDIOC_S_FMT. */ - return -EINVAL; - } + btv->crop[1] = c; + + mutex_unlock(&btv->lock); + + fh->do_crop = 1; - bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE); - return (fh->vbi_fmt.fmt.count[0] * 2 - * fh->vbi_fmt.fmt.samples_per_line); + mutex_lock(&fh->cap.lock); + + if (fh->width < c.min_scaled_width) { + fh->width = c.min_scaled_width; + btv->init.width = c.min_scaled_width; + } else if (fh->width > c.max_scaled_width) { + fh->width = c.max_scaled_width; + btv->init.width = c.max_scaled_width; } - default: - return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl); + if (fh->height < c.min_scaled_height) { + fh->height = c.min_scaled_height; + btv->init.height = c.min_scaled_height; + } else if (fh->height > c.max_scaled_height) { + fh->height = c.max_scaled_height; + btv->init.height = c.max_scaled_height; } + + mutex_unlock(&fh->cap.lock); + + return 0; +} + +static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + strcpy(a->name, "audio"); + return 0; +} + +static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + return 0; } static ssize_t bttv_read(struct file *file, char __user *data, @@ -3719,8 +3205,8 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -3777,7 +3263,7 @@ static int bttv_open(struct inode *inode, struct file *file) V4L2_FIELD_SEQ_TB, sizeof(struct bttv_buffer), fh); - i2c_vidiocschan(btv); + set_tvnorm(btv,btv->tvnorm); btv->users++; @@ -3857,7 +3343,7 @@ static const struct file_operations bttv_fops = .owner = THIS_MODULE, .open = bttv_open, .release = bttv_release, - .ioctl = bttv_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, .read = bttv_read, @@ -3867,19 +3353,61 @@ static const struct file_operations bttv_fops = static struct video_device bttv_video_template = { - .name = "UNSET", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| - VID_TYPE_CLIPPING|VID_TYPE_SCALES, - .fops = &bttv_fops, - .minor = -1, -}; - -static struct video_device bttv_vbi_template = -{ - .name = "bt848/878 vbi", - .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, .fops = &bttv_fops, .minor = -1, + .vidioc_querycap = bttv_querycap, + .vidioc_enum_fmt_cap = bttv_enum_fmt_cap, + .vidioc_g_fmt_cap = bttv_g_fmt_cap, + .vidioc_try_fmt_cap = bttv_try_fmt_cap, + .vidioc_s_fmt_cap = bttv_s_fmt_cap, + .vidioc_enum_fmt_overlay = bttv_enum_fmt_overlay, + .vidioc_g_fmt_overlay = bttv_g_fmt_overlay, + .vidioc_try_fmt_overlay = bttv_try_fmt_overlay, + .vidioc_s_fmt_overlay = bttv_s_fmt_overlay, + .vidioc_enum_fmt_vbi = bttv_enum_fmt_vbi, + .vidioc_g_fmt_vbi = bttv_g_fmt_vbi, + .vidioc_try_fmt_vbi = bttv_try_fmt_vbi, + .vidioc_s_fmt_vbi = bttv_s_fmt_vbi, + .vidioc_g_audio = bttv_g_audio, + .vidioc_s_audio = bttv_s_audio, + .vidioc_cropcap = bttv_cropcap, + .vidioc_reqbufs = bttv_reqbufs, + .vidioc_querybuf = bttv_querybuf, + .vidioc_qbuf = bttv_qbuf, + .vidioc_dqbuf = bttv_dqbuf, + .vidioc_s_std = bttv_s_std, + .vidioc_enum_input = bttv_enum_input, + .vidioc_g_input = bttv_g_input, + .vidioc_s_input = bttv_s_input, + .vidioc_queryctrl = bttv_queryctrl, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_streamon = bttv_streamon, + .vidioc_streamoff = bttv_streamoff, + .vidioc_g_tuner = bttv_g_tuner, + .vidioc_s_tuner = bttv_s_tuner, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_crop = bttv_g_crop, + .vidioc_g_crop = bttv_g_crop, + .vidioc_s_crop = bttv_s_crop, + .vidioc_g_fbuf = bttv_g_fbuf, + .vidioc_s_fbuf = bttv_s_fbuf, + .vidioc_overlay = bttv_overlay, + .vidioc_g_priority = bttv_g_priority, + .vidioc_s_priority = bttv_s_priority, + .vidioc_g_parm = bttv_g_parm, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, + .vidioc_log_status = bttv_log_status, + .vidioc_querystd = bttv_querystd, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = bttv_g_register, + .vidioc_s_register = bttv_s_register, +#endif + .tvnorms = BTTV_NORMS, + .current_norm = V4L2_STD_PAL, }; /* ----------------------------------------------------------------------- */ @@ -3918,7 +3446,7 @@ static int radio_open(struct inode *inode, struct file *file) static int radio_release(struct inode *inode, struct file *file) { - struct bttv *btv = file->private_data; + struct bttv *btv = file->private_data; struct rds_command cmd; btv->radio_user--; @@ -3928,59 +3456,116 @@ static int radio_release(struct inode *inode, struct file *file) return 0; } -static int radio_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { - struct bttv *btv = file->private_data; + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *cap = arg; + strcpy(cap->driver, "bttv"); + strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); + cap->version = BTTV_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; - memset(cap,0,sizeof(*cap)); - strcpy(cap->name,btv->radio_dev->name); - cap->type = VID_TYPE_TUNER; - cap->channels = 1; - cap->audios = 1; - return 0; - } + return 0; +} - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; +static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; - if(v->tuner) - return -EINVAL; - memset(v,0,sizeof(*v)); - strcpy(v->name, "Radio"); - bttv_call_i2c_clients(btv,cmd,v); - return 0; - } - case VIDIOCSTUNER: - /* nothing to do */ - return 0; + if (UNSET == bttv_tvcards[btv->c.type].tuner) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + mutex_lock(&btv->lock); + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; - case BTTV_VERSION: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOC_LOG_STATUS: - case VIDIOC_DBG_G_REGISTER: - case VIDIOC_DBG_S_REGISTER: - return bttv_common_ioctls(btv,cmd,arg); + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + + if (btv->audio_mode_gpio) + btv->audio_mode_gpio(btv, t, 0); + + mutex_unlock(&btv->lock); + + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + if (0 != t->index) + return -EINVAL; + + bttv_call_i2c_clients(btv, VIDIOC_G_TUNER, t); + return 0; +} + +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ + return 0; +} + +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctl; - default: - return -ENOIOCTLCMD; - } return 0; } -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) { - return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); + *i = 0; + return 0; } static ssize_t radio_read(struct file *file, char __user *data, @@ -4016,17 +3601,29 @@ static const struct file_operations radio_fops = .open = radio_open, .read = radio_read, .release = radio_release, - .ioctl = radio_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, .poll = radio_poll, }; static struct video_device radio_template = { - .name = "bt848/878 radio", - .type = VID_TYPE_TUNER, .fops = &radio_fops, .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = bttv_g_ctrl, + .vidioc_s_ctrl = bttv_s_ctrl, + .vidioc_g_frequency = bttv_g_frequency, + .vidioc_s_frequency = bttv_s_frequency, }; /* ----------------------------------------------------------------------- */ @@ -4308,20 +3905,20 @@ static void bttv_irq_timeout(unsigned long data) bttv_set_dma(btv, 0); /* wake up */ - bttv_irq_wakeup_video(btv, &old, &new, STATE_ERROR); - bttv_irq_wakeup_vbi(btv, ovbi, STATE_ERROR); + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_ERROR); + bttv_irq_wakeup_vbi(btv, ovbi, VIDEOBUF_ERROR); /* cancel all outstanding capture / vbi requests */ while (!list_empty(&btv->capture)) { item = list_entry(btv->capture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = STATE_ERROR; + item->vb.state = VIDEOBUF_ERROR; wake_up(&item->vb.done); } while (!list_empty(&btv->vcapture)) { item = list_entry(btv->vcapture.next, struct bttv_buffer, vb.queue); list_del(&item->vb.queue); - item->vb.state = STATE_ERROR; + item->vb.state = VIDEOBUF_ERROR; wake_up(&item->vb.done); } @@ -4344,7 +3941,7 @@ bttv_irq_wakeup_top(struct bttv *btv) do_gettimeofday(&wakeup->vb.ts); wakeup->vb.field_count = btv->field_count; - wakeup->vb.state = STATE_DONE; + wakeup->vb.state = VIDEOBUF_DONE; wake_up(&wakeup->vb.done); spin_unlock(&btv->s_lock); } @@ -4393,7 +3990,7 @@ bttv_irq_switch_video(struct bttv *btv) } /* wake up finished buffers */ - bttv_irq_wakeup_video(btv, &old, &new, STATE_DONE); + bttv_irq_wakeup_video(btv, &old, &new, VIDEOBUF_DONE); spin_unlock(&btv->s_lock); } @@ -4426,7 +4023,7 @@ bttv_irq_switch_vbi(struct bttv *btv) bttv_buffer_activate_vbi(btv, new); bttv_set_dma(btv, 0); - bttv_irq_wakeup_vbi(btv, old, STATE_DONE); + bttv_irq_wakeup_vbi(btv, old, VIDEOBUF_DONE); spin_unlock(&btv->s_lock); } @@ -4548,8 +4145,9 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) /* initialitation */ static struct video_device *vdev_init(struct bttv *btv, - struct video_device *template, - char *type) + const struct video_device *template, + const char *type_name, + const int type) { struct video_device *vfd; @@ -4560,9 +4158,10 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->minor = -1; vfd->dev = &btv->c.pci->dev; vfd->release = video_device_release; + vfd->type = type; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", - type, bttv_tvcards[btv->c.type].name); + type_name, bttv_tvcards[btv->c.type].name); return vfd; } @@ -4594,6 +4193,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 { @@ -4601,7 +4205,9 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); + btv->video_dev = vdev_init(btv, &bttv_video_template, + "video", video_type); + if (NULL == btv->video_dev) goto err; if (video_register_device(btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0) @@ -4616,7 +4222,9 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi"); + btv->vbi_dev = vdev_init(btv, &bttv_video_template, + "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT); + if (NULL == btv->vbi_dev) goto err; if (video_register_device(btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) @@ -4627,7 +4235,8 @@ 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"); + btv->radio_dev = vdev_init(btv, &radio_template, + "radio", VID_TYPE_TUNER); if (NULL == btv->radio_dev) goto err; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) @@ -4768,7 +4377,7 @@ static int __devinit bttv_probe(struct pci_dev *dev, btv->init.btv = btv; btv->init.ov.w.width = 320; btv->init.ov.w.height = 240; - btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24); + btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); btv->init.width = 320; btv->init.height = 240; btv->input = 0; @@ -5013,14 +4622,17 @@ static int __init bttv_init_module(void) printk(KERN_WARNING "bttv: bus_register error: %d\n", ret); return ret; } - return pci_register_driver(&bttv_pci_driver); + ret = pci_register_driver(&bttv_pci_driver); + if (ret < 0) + bus_unregister(&bttv_sub_bus_type); + + return ret; } static void __exit bttv_cleanup_module(void) { pci_unregister_driver(&bttv_pci_driver); bus_unregister(&bttv_sub_bus_type); - return; } module_init(bttv_init_module); diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index e7c521b8444a..fc9ecb21eec6 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -69,6 +69,11 @@ static void ir_handle_key(struct bttv *btv) (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { ir_input_keydown(ir->dev,&ir->ir,data,data); } else { + /* HACK: Probably, ir->mask_keydown is missing + for this board */ + if (btv->c.type == BTTV_BOARD_WINFAST2000) + ir_input_keydown(ir->dev, &ir->ir, data, data); + ir_input_nokey(ir->dev,&ir->ir); } diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c index 58986f1a5f1a..e5979f77504c 100644 --- a/drivers/media/video/bt8xx/bttv-risc.c +++ b/drivers/media/video/bt8xx/bttv-risc.c @@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf videobuf_dma_free(dma); btcx_riscmem_free(btv->c.pci,&buf->bottom); btcx_riscmem_free(btv->c.pci,&buf->top); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } int @@ -602,7 +602,7 @@ bttv_buffer_activate_vbi(struct bttv *btv, if (vbi) { unsigned int crop, vdelay; - vbi->vb.state = STATE_ACTIVE; + vbi->vb.state = VIDEOBUF_ACTIVE; list_del(&vbi->vb.queue); /* VDELAY is start of video, end of VBI capturing. */ @@ -644,12 +644,12 @@ bttv_buffer_activate_video(struct bttv *btv, /* video capture */ if (NULL != set->top && NULL != set->bottom) { if (set->top == set->bottom) { - set->top->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); } else { - set->top->vb.state = STATE_ACTIVE; - set->bottom->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); if (set->bottom->vb.queue.next) @@ -666,7 +666,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor((set->top->btswap & 0x0a) | (set->bottom->btswap & 0x05), ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->top) { - set->top->vb.state = STATE_ACTIVE; + set->top->vb.state = VIDEOBUF_ACTIVE; if (set->top->vb.queue.next) list_del(&set->top->vb.queue); bttv_apply_geo(btv, &set->top->geo,1); @@ -677,7 +677,7 @@ bttv_buffer_activate_video(struct bttv *btv, btaor(set->top->btformat & 0xff, ~0xff, BT848_COLOR_FMT); btaor(set->top->btswap & 0x0f, ~0x0f, BT848_COLOR_CTL); } else if (NULL != set->bottom) { - set->bottom->vb.state = STATE_ACTIVE; + set->bottom->vb.state = VIDEOBUF_ACTIVE; if (set->bottom->vb.queue.next) list_del(&set->bottom->vb.queue); bttv_apply_geo(btv, &set->bottom->geo,1); diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 346ce019bdcb..1f0cc79e2a33 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -142,7 +142,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, redo_dma_risc = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL))) goto fail; @@ -189,7 +189,7 @@ static int vbi_buffer_prepare(struct videobuf_queue *q, /* For bttv_buffer_activate_vbi(). */ buf->geo.vdelay = min_vdelay; - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->vb.field = field; dprintk("buf prepare %p: top=%p bottom=%p field=%s\n", vb, &buf->top, &buf->bottom, @@ -209,7 +209,7 @@ vbi_buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); dprintk("queue %p\n",vb); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue,&btv->vcapture); if (NULL == btv->cvbi) { fh->btv->loop_irq |= 4; @@ -236,10 +236,8 @@ struct videobuf_queue_ops bttv_vbi_qops = { /* ----------------------------------------------------------------------- */ -static int -try_fmt (struct v4l2_vbi_format * f, - const struct bttv_tvnorm * tvnorm, - __s32 crop_start) +static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, + __s32 crop_start) { __s32 min_start, max_start, max_end, f2_offset; unsigned int i; @@ -305,10 +303,9 @@ try_fmt (struct v4l2_vbi_format * f, return 0; } -int -bttv_vbi_try_fmt (struct bttv_fh * fh, - struct v4l2_vbi_format * f) +int bttv_try_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { + struct bttv_fh *fh = f; struct bttv *btv = fh->btv; const struct bttv_tvnorm *tvnorm; __s32 crop_start; @@ -320,13 +317,13 @@ bttv_vbi_try_fmt (struct bttv_fh * fh, mutex_unlock(&btv->lock); - return try_fmt(f, tvnorm, crop_start); + return try_fmt(&frt->fmt.vbi, tvnorm, crop_start); } -int -bttv_vbi_set_fmt (struct bttv_fh * fh, - struct v4l2_vbi_format * f) + +int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { + struct bttv_fh *fh = f; struct bttv *btv = fh->btv; const struct bttv_tvnorm *tvnorm; __s32 start1, end; @@ -340,11 +337,12 @@ bttv_vbi_set_fmt (struct bttv_fh * fh, tvnorm = &bttv_tvnorms[btv->tvnorm]; - rc = try_fmt(f, tvnorm, btv->crop_start); + rc = try_fmt(&frt->fmt.vbi, tvnorm, btv->crop_start); if (0 != rc) goto fail; - start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0]; + start1 = frt->fmt.vbi.start[1] - tvnorm->vbistart[1] + + tvnorm->vbistart[0]; /* First possible line of video capturing. Should be max(f->start[0] + f->count[0], start1 + f->count[1]) * 2 @@ -352,11 +350,11 @@ bttv_vbi_set_fmt (struct bttv_fh * fh, pretend the VBI and video capture window may overlap, so end = start + 1, the lowest possible value, times two because vbi_fmt.end counts field lines times two. */ - end = max(f->start[0], start1) * 2 + 2; + end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; mutex_lock(&fh->vbi.lock); - fh->vbi_fmt.fmt = *f; + fh->vbi_fmt.fmt = frt->fmt.vbi; fh->vbi_fmt.tvnorm = tvnorm; fh->vbi_fmt.end = end; @@ -370,13 +368,13 @@ bttv_vbi_set_fmt (struct bttv_fh * fh, return rc; } -void -bttv_vbi_get_fmt (struct bttv_fh * fh, - struct v4l2_vbi_format * f) + +int bttv_g_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) { + struct bttv_fh *fh = f; const struct bttv_tvnorm *tvnorm; - *f = fh->vbi_fmt.fmt; + frt->fmt.vbi = fh->vbi_fmt.fmt; tvnorm = &bttv_tvnorms[fh->btv->tvnorm]; @@ -391,28 +389,28 @@ bttv_vbi_get_fmt (struct bttv_fh * fh, max_end = (tvnorm->cropcap.bounds.top + tvnorm->cropcap.bounds.height) >> 1; - f->sampling_rate = tvnorm->Fsc; + frt->fmt.vbi.sampling_rate = tvnorm->Fsc; for (i = 0; i < 2; ++i) { __s32 new_start; - new_start = f->start[i] + new_start = frt->fmt.vbi.start[i] + tvnorm->vbistart[i] - fh->vbi_fmt.tvnorm->vbistart[i]; - f->start[i] = min(new_start, max_end - 1); - f->count[i] = min((__s32) f->count[i], - max_end - f->start[i]); + frt->fmt.vbi.start[i] = min(new_start, max_end - 1); + frt->fmt.vbi.count[i] = + min((__s32) frt->fmt.vbi.count[i], + max_end - frt->fmt.vbi.start[i]); max_end += tvnorm->vbistart[1] - tvnorm->vbistart[0]; } } + return 0; } -void -bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f, - int norm) +void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm) { const struct bttv_tvnorm *tvnorm; unsigned int real_samples_per_line; diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h index 19e75d50a107..bf4c339a520c 100644 --- a/drivers/media/video/bt8xx/bttv.h +++ b/drivers/media/video/bt8xx/bttv.h @@ -241,7 +241,10 @@ struct tvcard unsigned int radio_addr; unsigned int has_radio; - void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); + void (*muxsel_hook)(struct bttv *btv, unsigned int input); }; diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index d4ac4c4b49b4..1305d315cfc5 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -84,6 +84,11 @@ #define clamp(x, low, high) min (max (low, x), high) +#define BTTV_NORMS (\ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60) /* ---------------------------------------------------------- */ struct bttv_tvnorm { @@ -112,7 +117,6 @@ extern const struct bttv_tvnorm bttv_tvnorms[]; struct bttv_format { char *name; - int palette; /* video4linux 1 */ int fourcc; /* video4linux 2 */ int btformat; /* BT848_COLOR_FMT_* */ int btswap; /* BT848_COLOR_CTL_* */ @@ -253,9 +257,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov, /* ---------------------------------------------------------- */ /* bttv-vbi.c */ -int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); -void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); -int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f); +int bttv_try_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_g_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); +int bttv_s_fmt_vbi(struct file *file, void *fh, struct v4l2_format *f); extern struct videobuf_queue_ops bttv_vbi_qops; @@ -337,7 +341,9 @@ struct bttv { /* old gpio interface */ wait_queue_head_t gpioq; int shutdown; - void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set); + + void (*volume_gpio)(struct bttv *btv, __u16 volume); + void (*audio_mode_gpio)(struct bttv *btv, struct v4l2_tuner *tuner, int set); /* new gpio interface */ spinlock_t gpio_lock; @@ -458,10 +464,6 @@ struct bttv { extern unsigned int bttv_num; extern struct bttv bttvs[BTTV_MAX]; -/* private ioctls */ -#define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) -#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) - #endif #define btwrite(dat,adr) writel((dat), btv->bt848_mmio+(adr)) diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 58423525591f..032265383df2 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -82,11 +82,16 @@ OTHER DEALINGS IN THE SOFTWARE. static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */ static unsigned int yieldlines=4; /* Yield after this many during capture */ static int video_nr = -1; +static unsigned int force_init; /* Whether to probe aggressively */ module_param(maxpoll, int, 0); module_param(yieldlines, int, 0); module_param(video_nr, int, 0); +/* Set force_init=1 to avoid detection by polling status register and + * immediately attempt to initialize qcam */ +module_param(force_init, int, 0); + static inline int read_lpstatus(struct qcam_device *q) { return parport_read_status(q->pport); @@ -331,6 +336,9 @@ static int qc_detect(struct qcam_device *q) int count = 0; int i; + if (force_init) + return 1; + lastreg = reg = read_lpstatus(q) & 0xf0; for (i = 0; i < 500; i++) @@ -354,12 +362,12 @@ static int qc_detect(struct qcam_device *q) /* Be (even more) liberal in what you accept... */ -/* if (count > 30 && count < 200) */ if (count > 20 && count < 400) { return 1; /* found */ } else { printk(KERN_ERR "No Quickcam found on port %s\n", q->pport->name); + printk(KERN_DEBUG "Quickcam detection counter: %u\n", count); return 0; /* not found */ } } diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c new file mode 100644 index 000000000000..fae469ce16f5 --- /dev/null +++ b/drivers/media/video/cs5345.c @@ -0,0 +1,168 @@ +/* + * cs5345 Cirrus Logic 24-bit, 192 kHz Stereo Audio ADC + * Copyright (C) 2007 Hans Verkuil + * + * 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 <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/i2c.h> +#include <linux/videodev2.h> +#include <media/v4l2-i2c-drv.h> +#include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> + +MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static int debug; + +module_param(debug, bool, 0644); + +MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); + + +/* ----------------------------------------------------------------------- */ + +static inline int cs5345_write(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +static inline int cs5345_read(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) +{ + struct v4l2_routing *route = arg; + struct v4l2_control *ctrl = arg; + + switch (cmd) { + case VIDIOC_INT_G_AUDIO_ROUTING: + route->input = cs5345_read(client, 0x09) & 7; + route->input |= cs5345_read(client, 0x05) & 0x70; + route->output = 0; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + if ((route->input & 0xf) > 6) { + v4l_err(client, "Invalid input %d.\n", route->input); + return -EINVAL; + } + cs5345_write(client, 0x09, route->input & 0xf); + cs5345_write(client, 0x05, route->input & 0xf0); + break; + + case VIDIOC_G_CTRL: + if (ctrl->id == V4L2_CID_AUDIO_MUTE) { + ctrl->value = (cs5345_read(client, 0x04) & 0x08) != 0; + break; + } + if (ctrl->id != V4L2_CID_AUDIO_VOLUME) + return -EINVAL; + ctrl->value = cs5345_read(client, 0x07) & 0x3f; + if (ctrl->value >= 32) + ctrl->value = ctrl->value - 64; + break; + + case VIDIOC_S_CTRL: + break; + if (ctrl->id == V4L2_CID_AUDIO_MUTE) { + cs5345_write(client, 0x04, ctrl->value ? 0x80 : 0); + break; + } + if (ctrl->id != V4L2_CID_AUDIO_VOLUME) + return -EINVAL; + if (ctrl->value > 24 || ctrl->value < -24) + return -EINVAL; + cs5345_write(client, 0x07, ((u8)ctrl->value) & 0x3f); + cs5345_write(client, 0x08, ((u8)ctrl->value) & 0x3f); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = cs5345_read(client, reg->reg & 0x1f); + else + cs5345_write(client, reg->reg & 0x1f, reg->val & 0x1f); + break; + } +#endif + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_CS5345, 0); + + case VIDIOC_LOG_STATUS: + { + u8 v = cs5345_read(client, 0x09) & 7; + u8 m = cs5345_read(client, 0x04); + int vol = cs5345_read(client, 0x08) & 0x3f; + + v4l_info(client, "Input: %d%s\n", v, + (m & 0x80) ? " (muted)" : ""); + if (vol >= 32) + vol = vol - 64; + v4l_info(client, "Volume: %d dB\n", vol); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int cs5345_probe(struct i2c_client *client) +{ + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + cs5345_write(client, 0x02, 0x00); + cs5345_write(client, 0x04, 0x01); + cs5345_write(client, 0x09, 0x01); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cs5345", + .driverid = I2C_DRIVERID_CS5345, + .command = cs5345_command, + .probe = cs5345_probe, +}; + diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index a73e285af730..f41bfde045fe 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -29,12 +29,13 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv-legacy.h> MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC"); MODULE_AUTHOR("Martin Vaughan"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, bool, 0644); @@ -57,8 +58,7 @@ static int cs53l32a_read(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) { struct v4l2_routing *route = arg; struct v4l2_control *ctrl = arg; @@ -105,7 +105,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_CS53l32A, 0); + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_CS53l32A, 0); case VIDIOC_LOG_STATUS: { @@ -134,27 +135,18 @@ static int cs53l32a_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) +static int cs53l32a_probe(struct i2c_client *client) { - struct i2c_client *client; int i; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "cs53l32a"); - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); for (i = 1; i <= 7; i++) { u8 v = cs53l32a_read(client, i); @@ -179,55 +171,13 @@ static int cs53l32a_attach(struct i2c_adapter *adapter, int address, int kind) v4l_dbg(1, debug, client, "Read Reg %d %02x\n", i, v); } - - i2c_attach_client(client); - return 0; } -static int cs53l32a_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, cs53l32a_attach); - return 0; -} - -static int cs53l32a_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "cs53l32a", - }, - .id = I2C_DRIVERID_CS53L32A, - .attach_adapter = cs53l32a_probe, - .detach_client = cs53l32a_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cs53l32a", + .driverid = I2C_DRIVERID_CS53L32A, .command = cs53l32a_command, + .probe = cs53l32a_probe, }; - -static int __init cs53l32a_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit cs53l32a_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(cs53l32a_init_module); -module_exit(cs53l32a_cleanup_module); diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 62304255dcae..c592899a2317 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -34,7 +34,7 @@ MODULE_DESCRIPTION("cx23415/6 driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); @@ -75,6 +75,7 @@ const u32 cx2341x_mpeg_ctrls[] = { V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS, 0 }; +EXPORT_SYMBOL(cx2341x_mpeg_ctrls); /* Map the control ID to the correct field in the cx2341x_mpeg_params @@ -281,13 +282,14 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return -EBUSY; params->stream_type = ctrl->value; params->video_encoding = - (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || - params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? - V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) { + (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS || + params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ? + V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : + V4L2_MPEG_VIDEO_ENCODING_MPEG_2; + if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) /* MPEG-1 implies CBR */ - params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; - } + params->video_bitrate_mode = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; break; case V4L2_CID_MPEG_STREAM_VBI_FMT: params->stream_vbi_fmt = ctrl->value; @@ -334,7 +336,8 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy, return 0; } -static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) +static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, + s32 min, s32 max, s32 step, s32 def) { const char *name; @@ -417,7 +420,8 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 ma return 0; } -int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl) +int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, + struct v4l2_queryctrl *qctrl) { int err; @@ -440,7 +444,8 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + if (err == 0 && + params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; @@ -455,13 +460,16 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) + if (err == 0 && + params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: err = v4l2_ctrl_query_fill_std(qctrl); - if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + if (err == 0 && + params->video_bitrate_mode == + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return err; @@ -476,80 +484,90 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl /* CX23415/6 specific */ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1, + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL); case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1, - V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); - if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, + 1, + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1, - V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); - if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + 1, + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF); + if (params->video_spatial_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, - V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1, + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL); case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_temporal_filter_mode == + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: return cx2341x_ctrl_query_fill(qctrl, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, - V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1, + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF); case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0); qctrl->flags |= V4L2_CTRL_FLAG_SLIDER; - if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; + if (params->video_median_filter_type == + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF) + qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; return 0; case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: @@ -560,6 +578,7 @@ int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl } } +EXPORT_SYMBOL(cx2341x_ctrl_query); const char **cx2341x_ctrl_get_menu(u32 id) { @@ -629,6 +648,7 @@ const char **cx2341x_ctrl_get_menu(u32 id) return v4l2_ctrl_get_menu(id); } } +EXPORT_SYMBOL(cx2341x_ctrl_get_menu); static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) { @@ -637,9 +657,8 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params) ((1 + params->audio_l2_bitrate) << 4) | (params->audio_mode << 8) | (params->audio_mode_extension << 10) | - (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ? - 3 : - params->audio_emphasis) << 12) | + (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) + ? 3 : params->audio_emphasis) << 12) | (params->audio_crc << 14); } @@ -679,19 +698,19 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy, if (err) break; } - if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - params->video_bitrate_peak < params->video_bitrate) { + if (err == 0 && + params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + params->video_bitrate_peak < params->video_bitrate) { err = -ERANGE; ctrls->error_idx = ctrls->count; } - if (err) { + if (err) ctrls->error_idx = i; - } - else { + else cx2341x_calc_audio_properties(params); - } return err; } +EXPORT_SYMBOL(cx2341x_ext_ctrls); void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) { @@ -732,13 +751,18 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) .video_mute_yuv = 0x008080, /* YCbCr value for black */ /* encoding filters */ - .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, + .video_spatial_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL, .video_spatial_filter = 0, - .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, - .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, + .video_luma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_chroma_spatial_filter_type = + V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, + .video_temporal_filter_mode = + V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL, .video_temporal_filter = 8, - .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, + .video_median_filter_type = + V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF, .video_luma_median_filter_top = 255, .video_luma_median_filter_bottom = 0, .video_chroma_median_filter_top = 255, @@ -748,8 +772,10 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p) *p = default_params; cx2341x_calc_audio_properties(p); } +EXPORT_SYMBOL(cx2341x_fill_defaults); -static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...) +static int cx2341x_api(void *priv, cx2341x_mbox_func func, + u32 cmd, int args, ...) { u32 data[CX2341X_MBOX_MAX_DATA]; va_list vargs; @@ -757,15 +783,17 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, .. va_start(vargs, args); - for (i = 0; i < args; i++) { + for (i = 0; i < args; i++) data[i] = va_arg(vargs, int); - } va_end(vargs); return func(priv, cmd, args, 0, data); } +#define NEQ(field) (old->field != new->field) + int cx2341x_update(void *priv, cx2341x_mbox_func func, - const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new) + const struct cx2341x_mpeg_params *old, + const struct cx2341x_mpeg_params *new) { static int mpeg_stream_type[] = { 0, /* MPEG-2 PS */ @@ -777,17 +805,18 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, }; int err = 0; + int force = (old == NULL); u16 temporal = new->video_temporal_filter; cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); - if (old == NULL || old->is_50hz != new->is_50hz) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz); + if (force || NEQ(is_50hz)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, + new->is_50hz); if (err) return err; } - if (old == NULL || old->width != new->width || old->height != new->height || - old->video_encoding != new->video_encoding) { + if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { u16 w = new->width; u16 h = new->height; @@ -795,69 +824,74 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, w /= 2; h /= 2; } - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, + h, w); if (err) return err; } if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) { - /* Adjust temporal filter if necessary. The problem with the temporal - filter is that it works well with full resolution capturing, but - not when the capture window is scaled (the filter introduces - a ghosting effect). So if the capture window is scaled, then - force the filter to 0. + /* Adjust temporal filter if necessary. The problem with the + temporal filter is that it works well with full resolution + capturing, but not when the capture window is scaled (the + filter introduces a ghosting effect). So if the capture + window is scaled, then force the filter to 0. For full resolution the filter really improves the video - quality, especially if the original video quality is suboptimal. */ + quality, especially if the original video quality is + suboptimal. */ temporal = 0; } - if (old == NULL || old->stream_type != new->stream_type) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]); + if (force || NEQ(stream_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, + mpeg_stream_type[new->stream_type]); if (err) return err; } - if (old == NULL || old->video_aspect != new->video_aspect) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect); + if (force || NEQ(video_aspect)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, + 1 + new->video_aspect); if (err) return err; } - if (old == NULL || old->video_b_frames != new->video_b_frames || - old->video_gop_size != new->video_gop_size) { + if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, new->video_gop_size, new->video_b_frames + 1); if (err) return err; } - if (old == NULL || old->video_gop_closure != new->video_gop_closure) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure); + if (force || NEQ(video_gop_closure)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, + new->video_gop_closure); if (err) return err; } - if (old == NULL || old->audio_properties != new->audio_properties) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); + if (force || NEQ(audio_properties)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, + 1, new->audio_properties); if (err) return err; } - if (old == NULL || old->audio_mute != new->audio_mute) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); + if (force || NEQ(audio_mute)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, + new->audio_mute); if (err) return err; } - if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode || - old->video_bitrate != new->video_bitrate || - old->video_bitrate_peak != new->video_bitrate_peak) { + if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || + NEQ(video_bitrate_peak)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, new->video_bitrate_mode, new->video_bitrate, new->video_bitrate_peak / 400, 0, 0); if (err) return err; } - if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode || - old->video_temporal_filter_mode != new->video_temporal_filter_mode || - old->video_median_filter_type != new->video_median_filter_type) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, - new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1), + if (force || NEQ(video_spatial_filter_mode) || + NEQ(video_temporal_filter_mode) || + NEQ(video_median_filter_type)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, + 2, new->video_spatial_filter_mode | + (new->video_temporal_filter_mode << 1), new->video_median_filter_type); if (err) return err; } - if (old == NULL || - old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom || - old->video_luma_median_filter_top != new->video_luma_median_filter_top || - old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom || - old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) { + if (force || NEQ(video_luma_median_filter_bottom) || + NEQ(video_luma_median_filter_top) || + NEQ(video_chroma_median_filter_bottom) || + NEQ(video_chroma_median_filter_top)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, new->video_luma_median_filter_bottom, new->video_luma_median_filter_top, @@ -865,36 +899,39 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, new->video_chroma_median_filter_top); if (err) return err; } - if (old == NULL || - old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type || - old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, - new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type); + if (force || NEQ(video_luma_spatial_filter_type) || + NEQ(video_chroma_spatial_filter_type)) { + err = cx2341x_api(priv, func, + CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, + 2, new->video_luma_spatial_filter_type, + new->video_chroma_spatial_filter_type); if (err) return err; } - if (old == NULL || - old->video_spatial_filter != new->video_spatial_filter || - old->video_temporal_filter != temporal) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2, - new->video_spatial_filter, temporal); + if (force || NEQ(video_spatial_filter) || + old->video_temporal_filter != temporal) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, + 2, new->video_spatial_filter, temporal); if (err) return err; } - if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) { - err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1, - new->video_temporal_decimation); + if (force || NEQ(video_temporal_decimation)) { + err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, + 1, new->video_temporal_decimation); if (err) return err; } - if (old == NULL || old->video_mute != new->video_mute || - (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) { - err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8)); + if (force || NEQ(video_mute) || + (new->video_mute && NEQ(video_mute_yuv))) { + err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, + new->video_mute | (new->video_mute_yuv << 8)); if (err) return err; } - if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) { - err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets); + if (force || NEQ(stream_insert_nav_packets)) { + err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, + 7, new->stream_insert_nav_packets); if (err) return err; } return 0; } +EXPORT_SYMBOL(cx2341x_update); static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id) { @@ -943,18 +980,17 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT), cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), p->video_bitrate); - if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { + if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) printk(", Peak %d", p->video_bitrate_peak); - } printk("\n"); - printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", + printk(KERN_INFO + "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", prefix, p->video_gop_size, p->video_b_frames, p->video_gop_closure ? "" : "No "); - if (p->video_temporal_decimation) { + if (p->video_temporal_decimation) printk(KERN_INFO "%s: Video: Temporal Decimation %d\n", prefix, p->video_temporal_decimation); - } /* Audio */ printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s", @@ -964,10 +1000,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), p->audio_mute ? " (muted)" : ""); - if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) { - printk(", %s", - cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); - } + if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) + printk(", %s", cx2341x_menu_item(p, + V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); printk(", %s, %s\n", cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); @@ -975,33 +1010,33 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix) /* Encoding filters */ printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n", prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE), p->video_spatial_filter); - if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) { + + if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) temporal = 0; - } + printk(KERN_INFO "%s: Temporal Filter: %s, %d\n", prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE), temporal); - printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", + printk(KERN_INFO + "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n", prefix, - cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), + cx2341x_menu_item(p, + V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE), p->video_luma_median_filter_bottom, p->video_luma_median_filter_top, p->video_chroma_median_filter_bottom, p->video_chroma_median_filter_top); } - -EXPORT_SYMBOL(cx2341x_fill_defaults); -EXPORT_SYMBOL(cx2341x_ctrl_query); -EXPORT_SYMBOL(cx2341x_ctrl_get_menu); -EXPORT_SYMBOL(cx2341x_ext_ctrls); -EXPORT_SYMBOL(cx2341x_update); EXPORT_SYMBOL(cx2341x_log_status); -EXPORT_SYMBOL(cx2341x_mpeg_ctrls); /* * Local variables: diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index 081ee6e1536f..1fd326fe4113 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -12,6 +12,10 @@ config VIDEO_CX23885 select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE + select TUNER_XC2028 if !DVB_FE_CUSTOMIZE + select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select DVB_TDA18271 if !DVB_FE_CUSTOMIZE + select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based TV cards. diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index 665067022d2a..32c90be50602 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -1,4 +1,4 @@ -cx23885-objs := cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o +cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o obj-$(CONFIG_VIDEO_CX23885) += cx23885.o diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index b9012acabb2f..2d414dad5c31 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> +#include <media/cx25840.h> #include "cx23885.h" @@ -32,6 +33,8 @@ struct cx23885_board cx23885_boards[] = { [CX23885_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", + /* Ensure safe default for unknown boards */ + .clk_freq = 0, .input = {{ .type = CX23885_VMUX_COMPOSITE1, .vmux = 0, @@ -69,23 +72,29 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_HAUPPAUGE_HVR1800] = { .name = "Hauppauge WinTV-HVR1800", + .porta = CX23885_ANALOG_VIDEO, .portc = CX23885_MPEG_DVB, + .tuner_type = TUNER_PHILIPS_TDA8290, + .tuner_addr = 0x42, /* 0x84 >> 1 */ .input = {{ .type = CX23885_VMUX_TELEVISION, - .vmux = 0, - .gpio0 = 0xff00, - },{ - .type = CX23885_VMUX_DEBUG, - .vmux = 0, - .gpio0 = 0xff01, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN5_CH2 | + CX25840_VIN2_CH1, + .gpio0 = 0, },{ .type = CX23885_VMUX_COMPOSITE1, - .vmux = 1, - .gpio0 = 0xff02, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN6_CH1, + .gpio0 = 0, },{ .type = CX23885_VMUX_SVIDEO, - .vmux = 2, - .gpio0 = 0xff02, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN4_CH2 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .gpio0 = 0, }}, }, [CX23885_BOARD_HAUPPAUGE_HVR1250] = { @@ -113,6 +122,14 @@ struct cx23885_board cx23885_boards[] = { .name = "DViCO FusionHDTV5 Express", .portb = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1500Q] = { + .name = "Hauppauge WinTV-HVR1500Q", + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_HAUPPAUGE_HVR1500] = { + .name = "Hauppauge WinTV-HVR1500", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -138,12 +155,32 @@ struct cx23885_subid cx23885_subids[] = { .card = CX23885_BOARD_HAUPPAUGE_HVR1800, },{ .subvendor = 0x0070, + .subdevice = 0x7809, + .card = CX23885_BOARD_HAUPPAUGE_HVR1800, + },{ + .subvendor = 0x0070, .subdevice = 0x7911, .card = CX23885_BOARD_HAUPPAUGE_HVR1250, },{ .subvendor = 0x18ac, .subdevice = 0xd500, .card = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP, + },{ + .subvendor = 0x0070, + .subdevice = 0x7790, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, + },{ + .subvendor = 0x0070, + .subdevice = 0x7797, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500Q, + },{ + .subvendor = 0x0070, + .subdevice = 0x7710, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500, + },{ + .subvendor = 0x0070, + .subdevice = 0x7717, + .card = CX23885_BOARD_HAUPPAUGE_HVR1500, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -184,9 +221,19 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) switch (tv.model) { case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */ - case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ - case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ - case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */ + case 77001: /* WinTV-HVR1500 (Express Card, OEM, No IR, ATSC and Basic analog */ + case 77011: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */ + case 77041: /* WinTV-HVR1500Q (Express Card, OEM, No IR, ATSC/QAM and Basic analog */ + case 77051: /* WinTV-HVR1500Q (Express Card, Retail, No IR, ATSC/QAM and Basic analog */ + case 78011: /* WinTV-HVR1800 (PCIe, Retail, 3.5mm in, IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78501: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78521: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78531: /* WinTV-HVR1800 (PCIe, OEM, RCA in, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 78631: /* WinTV-HVR1800 (PCIe, OEM, No IR, No FM, Dual channel ATSC and MPEG2 HW Encoder */ + case 79001: /* WinTV-HVR1250 (PCIe, Retail, IR, full height, ATSC and Basic analog */ + case 79101: /* WinTV-HVR1250 (PCIe, Retail, IR, half height, ATSC and Basic analog */ + case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */ + case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */ break; default: printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); @@ -197,6 +244,34 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } +/* Tuner callback function for cx23885 boards. Currently only needed + * for HVR1500Q, which has an xc5000 tuner. + */ +int cx23885_tuner_callback(void *priv, int command, int arg) +{ + struct cx23885_i2c *bus = priv; + struct cx23885_dev *dev = bus->dev; + + 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", __FUNCTION__); + return -EINVAL; + } + break; + } + + return 0; /* Should never be here */ +} + void cx23885_gpio_setup(struct cx23885_dev *dev) { switch(dev->board) { @@ -204,6 +279,23 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-0 cx24227 demodulator reset */ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */ break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + /* GPIO-0 cx24227 demodulator */ + /* GPIO-2 xc3028 tuner */ + + /* Put the parts into reset */ + cx_set(GP0_IO, 0x00050000); + cx_clear(GP0_IO, 0x00000005); + msleep(5); + + /* Bring the parts out of reset */ + cx_set(GP0_IO, 0x00050005); + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + /* GPIO-0 cx24227 demodulator reset */ + /* GPIO-2 xc5000 tuner reset */ + cx_set(GP0_IO, 0x00050005); /* Bring the part out of reset */ + break; case CX23885_BOARD_HAUPPAUGE_HVR1800: /* GPIO-0 656_CLK */ /* GPIO-1 656_D0 */ @@ -212,7 +304,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) /* GPIO-11-14 cx23417 addr0-3 */ /* GPIO-15-18 cx23417 READY, CS, RD, WR */ /* GPIO-19 IR_RX */ - // FIXME: Analog requires the tuner is brought out of reset + + /* Force the TDA8295A into reset and back */ + cx_set(GP0_IO, 0x00040004); + mdelay(20); + cx_clear(GP0_IO, 0x00000004); + mdelay(20); + cx_set(GP0_IO, 0x00040004); + mdelay(20); break; } } @@ -221,6 +320,8 @@ int cx23885_ir_init(struct cx23885_dev *dev) { switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: /* FIXME: Implement me */ break; @@ -244,6 +345,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: if (dev->i2c_bus[0].i2c_rc == 0) @@ -258,6 +361,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_HAUPPAUGE_HVR1250: + case CX23885_BOARD_HAUPPAUGE_HVR1500: + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: default: @@ -270,8 +375,6 @@ void cx23885_card_setup(struct cx23885_dev *dev) /* ------------------------------------------------------------------ */ -EXPORT_SYMBOL(cx23885_boards); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 3cdd136477e5..8e40c7bcc06d 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -36,7 +36,7 @@ MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); MODULE_LICENSE("GPL"); -static unsigned int debug = 0; +static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages"); @@ -44,13 +44,15 @@ static unsigned int card[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card,"card type"); -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg) +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) static unsigned int cx23885_devcount; static DEFINE_MUTEX(devlist); -static LIST_HEAD(cx23885_devlist); +LIST_HEAD(cx23885_devlist); #define NO_SYNC_LINE (-1U) @@ -73,14 +75,14 @@ static LIST_HEAD(cx23885_devlist); * 0x00010ea0 0x00010xxx Free */ -struct sram_channel cx23885_sram_channels[] = { +static struct sram_channel cx23885_sram_channels[] = { [SRAM_CH01] = { - .name = "test ch1", + .name = "VID A", .cmds_start = 0x10000, - .ctrl_start = 0x10500, - .cdt = 0x10900, - .fifo_start = 0x3000, - .fifo_size = 0x1000, + .ctrl_start = 0x105b0, + .cdt = 0x107b0, + .fifo_start = 0x40, + .fifo_size = 0x2800, .ptr1_reg = DMA1_PTR1, .ptr2_reg = DMA1_PTR2, .cnt1_reg = DMA1_CNT1, @@ -102,8 +104,8 @@ struct sram_channel cx23885_sram_channels[] = { [SRAM_CH03] = { .name = "TS1 B", .cmds_start = 0x100A0, - .ctrl_start = 0x10780, - .cdt = 0x10400, + .ctrl_start = 0x10630, + .cdt = 0x10870, .fifo_start = 0x5000, .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, @@ -139,7 +141,7 @@ struct sram_channel cx23885_sram_channels[] = { .name = "TS2 C", .cmds_start = 0x10140, .ctrl_start = 0x10680, - .cdt = 0x10480, + .cdt = 0x108d0, .fifo_start = 0x6000, .fifo_size = 0x1000, .ptr1_reg = DMA5_PTR1, @@ -205,14 +207,14 @@ struct sram_channel cx23885_sram_channels[] = { * 0x00010ea0 0x00010xxx Free */ -struct sram_channel cx23887_sram_channels[] = { +static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { - .name = "test ch1", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .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, @@ -231,12 +233,12 @@ struct sram_channel cx23887_sram_channels[] = { .cnt2_reg = DMA2_CNT2, }, [SRAM_CH03] = { - .name = "ch3", - .cmds_start = 0x0, - .ctrl_start = 0x0, - .cdt = 0x0, - .fifo_start = 0x0, - .fifo_size = 0x0, + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10780, + .cdt = 0x10400, + .fifo_start = 0x5000, + .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, .ptr2_reg = DMA3_PTR2, .cnt1_reg = DMA3_CNT1, @@ -357,7 +359,7 @@ static int cx23885_risc_decode(u32 risc) } void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count) + struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; @@ -378,7 +380,7 @@ void cx23885_wakeup(struct cx23885_tsport *port, do_gettimeofday(&buf->vb.ts); dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, count, buf->count); - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } @@ -391,12 +393,10 @@ void cx23885_wakeup(struct cx23885_tsport *port, printk("%s: %d buffers handled (should be 1)\n", __FUNCTION__, bc); } -void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch); int cx23885_sram_channel_setup(struct cx23885_dev *dev, - struct sram_channel *ch, - unsigned int bpl, u32 risc) + struct sram_channel *ch, + unsigned int bpl, u32 risc) { unsigned int i, lines; u32 cdt; @@ -468,7 +468,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, } void cx23885_sram_channel_dump(struct cx23885_dev *dev, - struct sram_channel *ch) + struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -529,8 +529,8 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, dev->name, cx_read(ch->cnt2_reg)); } -void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) +static void cx23885_risc_disasm(struct cx23885_tsport *port, + struct btcx_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -548,7 +548,7 @@ void cx23885_risc_disasm(struct cx23885_tsport *port, } } -void cx23885_shutdown(struct cx23885_dev *dev) +static void cx23885_shutdown(struct cx23885_dev *dev) { /* disable RISC controller */ cx_write(DEV_CNTRL2, 0); @@ -578,7 +578,7 @@ void cx23885_shutdown(struct cx23885_dev *dev) } -void cx23885_reset(struct cx23885_dev *dev) +static void cx23885_reset(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __FUNCTION__); @@ -594,15 +594,18 @@ void cx23885_reset(struct cx23885_dev *dev) mdelay(100); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0); - cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], + 720*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH03], + 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH04], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH05], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH06], + 188*4, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH07], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH08], 128, 0); + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0); cx23885_gpio_setup(dev); } @@ -637,7 +640,7 @@ static int get_resources(struct cx23885_dev *dev) static void cx23885_timeout(unsigned long data); int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); + u32 reg, u32 mask, u32 value); static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -704,6 +707,44 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p return 0; } +static void cx23885_dev_checkrevision(struct cx23885_dev *dev) +{ + switch (cx_read(RDR_CFG2) & 0xff) { + case 0x00: + /* cx23885 */ + dev->hwrevision = 0xa0; + break; + case 0x01: + /* CX23885-12Z */ + dev->hwrevision = 0xa1; + break; + case 0x02: + /* CX23885-13Z */ + dev->hwrevision = 0xb0; + break; + case 0x03: + /* CX23888-22Z */ + dev->hwrevision = 0xc0; + break; + case 0x0e: + /* CX23887-15Z */ + dev->hwrevision = 0xc0; + case 0x0f: + /* CX23887-14Z */ + dev->hwrevision = 0xb1; + break; + default: + printk(KERN_ERR "%s() New hardware revision found 0x%x\n", + __FUNCTION__, dev->hwrevision); + } + if (dev->hwrevision) + printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", + __FUNCTION__, dev->hwrevision); + else + printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", + __FUNCTION__, dev->hwrevision); +} + static int cx23885_dev_setup(struct cx23885_dev *dev) { int i; @@ -723,10 +764,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if(dev->pci->device == 0x8880) { dev->bridge = CX23885_BRIDGE_887; dev->sram_channels = cx23887_sram_channels; + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 25000000; } else if(dev->pci->device == 0x8852) { dev->bridge = CX23885_BRIDGE_885; dev->sram_channels = cx23885_sram_channels; + /* Apply a sensible clock frequency for the PCIe bridge */ + dev->clk_freq = 28000000; } else BUG(); @@ -746,6 +791,10 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_list(dev); } + /* If the user specific a clk freq override, apply it */ + if (cx23885_boards[dev->board].clk_freq > 0) + dev->clk_freq = cx23885_boards[dev->board].clk_freq; + dev->pci_bus = dev->pci->bus->number; dev->pci_slot = PCI_SLOT(dev->pci->devfn); dev->pci_irqmask = 0x001f00; @@ -810,6 +859,17 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_pci_quirks(dev); + /* Assume some sensible defaults */ + dev->tuner_type = cx23885_boards[dev->board].tuner_type; + dev->tuner_addr = cx23885_boards[dev->board].tuner_addr; + dev->radio_type = cx23885_boards[dev->board].radio_type; + dev->radio_addr = cx23885_boards[dev->board].radio_addr; + + dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n", + __FUNCTION__, dev->tuner_type, dev->tuner_addr); + dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n", + __FUNCTION__, dev->radio_type, dev->radio_addr); + /* init hardware */ cx23885_reset(dev); @@ -820,24 +880,33 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_card_setup(dev); cx23885_ir_init(dev); - if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { + if (cx23885_video_register(dev) < 0) { + printk(KERN_ERR "%s() Failed to register analog " + "video adapters on VID_A\n", __FUNCTION__); + } + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { if (cx23885_dvb_register(&dev->ts1) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", __FUNCTION__); } } - if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { if (cx23885_dvb_register(&dev->ts2) < 0) { printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n", __FUNCTION__); } } + cx23885_dev_checkrevision(dev); + return 0; } -void cx23885_dev_unregister(struct cx23885_dev *dev) +static void cx23885_dev_unregister(struct cx23885_dev *dev) { release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); @@ -845,6 +914,9 @@ void cx23885_dev_unregister(struct cx23885_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; + if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) + cx23885_video_unregister(dev); + if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) cx23885_dvb_unregister(&dev->ts1); @@ -952,9 +1024,11 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, return 0; } -int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, - struct scatterlist *sglist, unsigned int bpl, - unsigned int lines) +static int cx23885_risc_databuffer(struct pci_dev *pci, + struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int bpl, + unsigned int lines) { u32 instructions; u32 *rp; @@ -982,7 +1056,7 @@ int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) + u32 reg, u32 mask, u32 value) { u32 *rp; int rc; @@ -1011,7 +1085,58 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; +} + +static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) +{ + struct cx23885_dev *dev = port->dev; + + dprintk(1, "%s() Register Dump\n", __FUNCTION__); + dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __FUNCTION__, + cx_read(DEV_CNTRL2)); + dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __FUNCTION__, + cx_read(PCI_INT_MSK)); + dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __FUNCTION__, + cx_read(AUDIO_INT_INT_MSK)); + dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __FUNCTION__, + cx_read(AUD_INT_DMA_CTL)); + dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __FUNCTION__, + cx_read(AUDIO_EXT_INT_MSK)); + dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __FUNCTION__, + cx_read(AUD_EXT_DMA_CTL)); + dprintk(1, "%s() PAD_CTRL 0x%08X\n", __FUNCTION__, + cx_read(PAD_CTRL)); + dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __FUNCTION__, + cx_read(ALT_PIN_OUT_SEL)); + dprintk(1, "%s() GPIO2 0x%08X\n", __FUNCTION__, + cx_read(GPIO2)); + dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __FUNCTION__, + port->reg_gpcnt, cx_read(port->reg_gpcnt)); + dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); + dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); + dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_src_sel, cx_read(port->reg_src_sel)); + dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_lngth, cx_read(port->reg_lngth)); + dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl)); + dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl)); + dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status)); + dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_sop_status, cx_read(port->reg_sop_status)); + dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat)); + dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_vld_misc, cx_read(port->reg_vld_misc)); + dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en)); + dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __FUNCTION__, + port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); } static int cx23885_start_dma(struct cx23885_tsport *port, @@ -1076,6 +1201,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */ + if (debug > 4) + cx23885_tsport_reg_dump(port); + return 0; } @@ -1091,7 +1219,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) return 0; } -static int cx23885_restart_queue(struct cx23885_tsport *port, +int cx23885_restart_queue(struct cx23885_tsport *port, struct cx23885_dmaqueue *q) { struct cx23885_dev *dev = port->dev; @@ -1114,7 +1242,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); cx23885_start_dma(port, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(5, "[%p/%d] restart_queue - first active\n", @@ -1125,7 +1253,7 @@ static int cx23885_restart_queue(struct cx23885_tsport *port, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1162,7 +1290,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = port->ts_packet_size; buf->vb.height = port->ts_packet_count; buf->vb.size = size; @@ -1174,7 +1302,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, videobuf_to_dma(&buf->vb)->sglist, buf->vb.width, buf->vb.height); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -1197,7 +1325,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue, &cx88q->active); cx23885_start_dma(port, cx88q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); dprintk(1, "[%p/%d] %s - first active\n", @@ -1207,7 +1335,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) prev = list_entry(cx88q->active.prev, struct cx23885_buffer, vb.queue); list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ @@ -1231,7 +1359,7 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); @@ -1243,16 +1371,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_unlock_irqrestore(&port->slock, flags); } -void cx23885_cancel_buffers(struct cx23885_tsport *port) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __FUNCTION__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} static void cx23885_timeout(unsigned long data) { @@ -1325,12 +1443,15 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) struct cx23885_tsport *ts1 = &dev->ts1; struct cx23885_tsport *ts2 = &dev->ts2; u32 pci_status, pci_mask; + u32 vida_status, vida_mask; u32 ts1_status, ts1_mask; u32 ts2_status, ts2_mask; - int ts1_count = 0, ts2_count = 0, handled = 0; + int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0; pci_status = cx_read(PCI_INT_STAT); pci_mask = cx_read(PCI_INT_MSK); + vida_status = cx_read(VID_A_INT_STAT); + vida_mask = cx_read(VID_A_INT_MSK); ts1_status = cx_read(VID_B_INT_STAT); ts1_mask = cx_read(VID_B_INT_MSK); ts2_status = cx_read(VID_C_INT_STAT); @@ -1339,11 +1460,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) ) goto out; + vida_count = cx_read(VID_A_GPCNT); ts1_count = cx_read(ts1->reg_gpcnt); ts2_count = cx_read(ts2->reg_gpcnt); - dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", pci_status, pci_mask ); - dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count ); - dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count ); + dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n", + pci_status, pci_mask); + dprintk(7, "vida_status: 0x%08x vida_mask: 0x%08x count: 0x%x\n", + vida_status, vida_mask, vida_count); + dprintk(7, "ts1_status: 0x%08x ts1_mask: 0x%08x count: 0x%x\n", + ts1_status, ts1_mask, ts1_count); + dprintk(7, "ts2_status: 0x%08x ts2_mask: 0x%08x count: 0x%x\n", + ts2_status, ts2_mask, ts2_count); if ( (pci_status & PCI_MSK_RISC_RD) || (pci_status & PCI_MSK_RISC_WR) || @@ -1380,11 +1507,18 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id) } - if (ts1_status) - handled += cx23885_irq_ts(ts1, ts1_status); + if (ts1_status) { + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts1, ts1_status); + } + + if (ts2_status) { + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) + handled += cx23885_irq_ts(ts2, ts2_status); + } - if (ts2_status) - handled += cx23885_irq_ts(ts2, ts2_status); + if (vida_status) + handled += cx23885_video_irq(dev, vida_status); if (handled) cx_write(PCI_INT_STAT, pci_status); diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index eda8c05d0931..ed465c007cea 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -32,13 +32,26 @@ #include "s5h1409.h" #include "mt2131.h" +#include "tda8290.h" +#include "tda18271.h" #include "lgdt330x.h" +#include "xc5000.h" #include "dvb-pll.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" -static unsigned int debug = 0; +static unsigned int debug; -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg) +#define dprintk(level, fmt, arg...)\ + do { if (debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +/* ------------------------------------------------------------------ */ + +static unsigned int alt_tuner; +module_param(alt_tuner, int, 0644); +MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration"); /* ------------------------------------------------------------------ */ @@ -85,18 +98,39 @@ static struct s5h1409_config hauppauge_generic_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_ON, - .if_freq = 44000, + .qam_if = 44000, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1409_config hauppauge_ezqam_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, + .qam_if = 4000, + .inversion = S5H1409_INVERSION_ON, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct s5h1409_config hauppauge_hvr1800lp_config = { .demod_address = 0x32 >> 1, .output_mode = S5H1409_SERIAL_OUTPUT, .gpio = S5H1409_GPIO_OFF, - .if_freq = 44000, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct s5h1409_config hauppauge_hvr1500_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_OFF, .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; static struct mt2131_config hauppauge_generic_tunerconfig = { @@ -109,6 +143,66 @@ static struct lgdt330x_config fusionhdtv_5_express = { .serial_mpeg = 0x40, }; +static struct s5h1409_config hauppauge_hvr1500q_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, +}; + +static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { + .i2c_address = 0x61, + .if_khz = 5380, + .tuner_callback = cx23885_tuner_callback +}; + +static struct tda829x_config tda829x_no_probe = { + .probe_tuner = TDA829X_DONT_PROBE, +}; + +static struct tda18271_std_map hauppauge_tda18271_std_map = { + .atsc_6 = { .if_freq = 5380, .std_bits = 0x1b }, + .qam_6 = { .if_freq = 4000, .std_bits = 0x18 }, +}; + +static struct tda18271_config hauppauge_tda18271_config = { + .std_map = &hauppauge_tda18271_std_map, + .gate = TDA18271_GATE_ANALOG, +}; + +static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) +{ + struct cx23885_tsport *port = ptr; + struct cx23885_dev *dev = port->dev; + + switch (command) { + case XC2028_TUNER_RESET: + /* Send the tuner in then out of reset */ + /* GPIO-2 xc3028 tuner */ + dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg); + + cx_set(GP0_IO, 0x00040000); + cx_clear(GP0_IO, 0x00000004); + msleep(5); + + cx_set(GP0_IO, 0x00040004); + msleep(5); + break; + case XC2028_RESET_CLK: + dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg); + break; + default: + dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__, + command, arg); + return -EINVAL; + } + + return 0; +} + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -120,7 +214,6 @@ static int dvb_register(struct cx23885_tsport *port) /* init frontend */ switch (dev->board) { case CX23885_BOARD_HAUPPAUGE_HVR1250: - case CX23885_BOARD_HAUPPAUGE_HVR1800: i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, &hauppauge_generic_config, @@ -131,6 +224,36 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_generic_tunerconfig, 0); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1800: + i2c_bus = &dev->i2c_bus[0]; + switch (alt_tuner) { + case 1: + port->dvb.frontend = + dvb_attach(s5h1409_attach, + &hauppauge_ezqam_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) { + dvb_attach(tda829x_attach, port->dvb.frontend, + &dev->i2c_bus[1].i2c_adap, 0x42, + &tda829x_no_probe); + dvb_attach(tda18271_attach, port->dvb.frontend, + 0x60, &dev->i2c_bus[1].i2c_adap, + &hauppauge_tda18271_config); + } + break; + case 0: + default: + port->dvb.frontend = + dvb_attach(s5h1409_attach, + &hauppauge_generic_config, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) + dvb_attach(mt2131_attach, port->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_generic_tunerconfig, 0); + break; + } + break; case CX23885_BOARD_HAUPPAUGE_HVR1800lp: i2c_bus = &dev->i2c_bus[0]; port->dvb.frontend = dvb_attach(s5h1409_attach, @@ -152,6 +275,43 @@ static int dvb_register(struct cx23885_tsport *port) &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + i2c_bus = &dev->i2c_bus[1]; + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1500q_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + hauppauge_hvr1500q_tunerconfig.priv = i2c_bus; + dvb_attach(xc5000_attach, port->dvb.frontend, + &i2c_bus->i2c_adap, + &hauppauge_hvr1500q_tunerconfig); + } + break; + case CX23885_BOARD_HAUPPAUGE_HVR1500: + i2c_bus = &dev->i2c_bus[1]; + port->dvb.frontend = dvb_attach(s5h1409_attach, + &hauppauge_hvr1500_config, + &dev->i2c_bus[0].i2c_adap); + if (port->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &i2c_bus->i2c_adap, + .i2c_addr = 0x61, + .video_dev = port, + .callback = cx23885_hvr1500_xc3028_callback, + }; + static struct xc2028_ctrl ctl = { + .fname = "xc3028-v27.fw", + .max_len = 64, + .scode_table = OREN538, + }; + + fe = dvb_attach(xc2028_attach, + port->dvb.frontend, &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); @@ -165,6 +325,9 @@ static int dvb_register(struct cx23885_tsport *port) /* Put the analog decoder in standby to keep it quiet */ cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL); + if (port->dvb.frontend->ops.analog_ops.standby) + port->dvb.frontend->ops.analog_ops.standby(port->dvb.frontend); + /* register everything */ return videobuf_dvb_register(&port->dvb, THIS_MODULE, port, &dev->pci->dev); diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c index 71da528932df..92fe0bd37c84 100644 --- a/drivers/media/video/cx23885/cx23885-i2c.c +++ b/drivers/media/video/cx23885/cx23885-i2c.c @@ -29,7 +29,7 @@ #include <media/v4l2-common.h> -static unsigned int i2c_debug = 0; +static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); @@ -37,8 +37,10 @@ static unsigned int i2c_scan = 0; module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); -#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) +#define dprintk(level, fmt, arg...)\ + do { if (i2c_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) #define I2C_WAIT_DELAY 32 #define I2C_WAIT_RETRY 64 @@ -77,14 +79,19 @@ static int i2c_wait_done(struct i2c_adapter *i2c_adap) } static int i2c_sendbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int last) + const struct i2c_msg *msg, int joined_rlen) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; u32 wdata, addr, ctrl; int retval, cnt; - dprintk(1, "%s()\n", __FUNCTION__); + if (joined_rlen) + dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__, + msg->len, joined_rlen); + else + dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); + /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { cx_write(bus->reg_addr, msg->addr << 25); @@ -106,6 +113,8 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (msg->len > 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); @@ -127,8 +136,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, wdata = msg->buf[cnt]; ctrl = bus->i2c_period | (1 << 12) | (1 << 2); - if (cnt < msg->len-1 || !last) + if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; + else if (joined_rlen) + ctrl |= I2C_NOSTOP; cx_write(bus->reg_addr, addr); cx_write(bus->reg_wdata, wdata); @@ -150,19 +161,22 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; err: - printk(" ERR: %d\n", retval); + if (i2c_debug) + printk(" ERR: %d\n", retval); return retval; } static int i2c_readbytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg, int last) + const struct i2c_msg *msg, int joined) { struct cx23885_i2c *bus = i2c_adap->algo_data; struct cx23885_dev *dev = bus->dev; u32 ctrl, cnt; int retval; - dprintk(1, "%s()\n", __FUNCTION__); + + if (i2c_debug && !joined) + dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len); /* Deal with i2c probe functions with zero payload */ if (msg->len == 0) { @@ -178,11 +192,18 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, return 0; } + if (i2c_debug) { + if (joined) + printk(" R"); + else + printk(" <R %02x", (msg->addr << 1) + 1); + } + for(cnt = 0; cnt < msg->len; cnt++) { ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1; - if (cnt < msg->len-1 || !last) + if (cnt < msg->len - 1) ctrl |= I2C_NOSTOP | I2C_EXTEND; cx_write(bus->reg_addr, msg->addr << 25); @@ -195,9 +216,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, goto eio; msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff; if (i2c_debug) { - if (!(ctrl & I2C_NOSTOP)) - printk(" <R %02x", (msg->addr << 1) +1); - printk(" =%02x", msg->buf[cnt]); + printk(" %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) printk(" >\n"); } @@ -207,7 +226,8 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; err: - printk(" ERR: %d\n", retval); + if (i2c_debug) + printk(" ERR: %d\n", retval); return retval; } @@ -225,15 +245,22 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, __FUNCTION__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { /* read */ - retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num); + retval = i2c_readbytes(i2c_adap, &msgs[i], 0); + } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && + msgs[i].addr == msgs[i + 1].addr) { + /* write then read from same address */ + retval = i2c_sendbytes(i2c_adap, &msgs[i], + msgs[i + 1].len); if (retval < 0) goto err; + i++; + retval = i2c_readbytes(i2c_adap, &msgs[i], 1); } else { /* write */ - retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num); - if (retval < 0) - goto err; + retval = i2c_sendbytes(i2c_adap, &msgs[i], 0); } + if (retval < 0) + goto err; } return num; @@ -243,7 +270,9 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, static int attach_inform(struct i2c_client *client) { - struct cx23885_dev *dev = i2c_get_adapdata(client->adapter); + struct cx23885_i2c *bus = i2c_get_adapdata(client->adapter); + struct cx23885_dev *dev = bus->dev; + struct tuner_setup tun_setup; dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -251,6 +280,31 @@ static int attach_inform(struct i2c_client *client) if (!client->driver->command) return 0; + if (dev->tuner_type != UNSET) { + + dprintk(1, "%s (tuner) i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, client->addr, + client->name); + + if ((dev->tuner_addr == ADDR_UNSET) || + (dev->tuner_addr == client->addr)) { + + dprintk(1, "%s (tuner || addr UNSET)\n", + client->driver->driver.name); + + dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", + client->driver->driver.name, + client->addr, client->name); + + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + + client->driver->command(client, TUNER_SET_TYPE_ADDR, + &tun_setup); + } + } + return 0; } @@ -289,6 +343,7 @@ static struct i2c_adapter cx23885_i2c_adap_template = { .owner = THIS_MODULE, .id = I2C_HW_B_CX23885, .algo = &cx23885_i2c_algo_template, + .class = I2C_CLASS_TV_ANALOG, .client_register = attach_inform, .client_unregister = detach_inform, }; @@ -305,7 +360,7 @@ static char *i2c_devs[128] = { [ 0x84 >> 1 ] = "tda8295", [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner/mt2131/tda8275", - [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275", + [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000", }; static void do_i2c_scan(char *name, struct i2c_client *c) @@ -344,6 +399,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) bus->i2c_algo.data = bus; bus->i2c_adap.algo_data = bus; + i2c_set_adapdata(&bus->i2c_adap, bus); i2c_add_adapter(&bus->i2c_adap); bus->i2c_client.adapter = &bus->i2c_adap; @@ -366,8 +422,6 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus) /* ----------------------------------------------------------------------- */ -EXPORT_SYMBOL(cx23885_call_i2c_clients); - /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h index 162169f9091b..bdd11bc513ad 100644 --- a/drivers/media/video/cx23885/cx23885-reg.h +++ b/drivers/media/video/cx23885/cx23885-reg.h @@ -233,6 +233,17 @@ Channel manager Data Structure entry = 20 DWORD #define VID_A_INT_SSTAT 0x0004002C #define VID_B_INT_MSK 0x00040030 +#define VID_B_MSK_BAD_PKT (1 << 20) +#define VID_B_MSK_VBI_OPC_ERR (1 << 17) +#define VID_B_MSK_OPC_ERR (1 << 16) +#define VID_B_MSK_VBI_SYNC (1 << 13) +#define VID_B_MSK_SYNC (1 << 12) +#define VID_B_MSK_VBI_OF (1 << 9) +#define VID_B_MSK_OF (1 << 8) +#define VID_B_MSK_VBI_RISCI2 (1 << 5) +#define VID_B_MSK_RISCI2 (1 << 4) +#define VID_B_MSK_VBI_RISCI1 (1 << 1) +#define VID_B_MSK_RISCI1 1 #define VID_B_INT_STAT 0x00040034 #define VID_B_INT_MSTAT 0x00040038 #define VID_B_INT_SSTAT 0x0004003C @@ -276,6 +287,7 @@ Channel manager Data Structure entry = 20 DWORD #define RDR_CFG0 0x00050000 #define RDR_CFG1 0x00050004 +#define RDR_CFG2 0x00050008 #define RDR_TLCTL0 0x00050318 /* APB DMAC Current Buffer Pointer */ @@ -335,6 +347,7 @@ Channel manager Data Structure entry = 20 DWORD /* GPIO (417 Microsoftcontroller) Output Enable, Low Active */ #define MC417_OEN 0x00110024 #define MC417_CTL 0x00110028 +#define ALT_PIN_OUT_SEL 0x0011002C #define CLK_DELAY 0x00110048 #define PAD_CTRL 0x0011004C diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c new file mode 100644 index 000000000000..e36e3fcae2fb --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-vbi.c @@ -0,0 +1,258 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/slab.h> + +#include "cx23885.h" + +static unsigned int vbibufs = 4; +module_param(vbibufs, int, 0644); +MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); + +static unsigned int vbi_debug; +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); + +#define dprintk(level, fmt, arg...)\ + do { if (vbi_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +/* ------------------------------------------------------------------ */ + +int cx23885_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (dev->tvnorm & V4L2_STD_525_60) { + /* ntsc */ + f->fmt.vbi.sampling_rate = 28636363; + f->fmt.vbi.start[0] = 10; + f->fmt.vbi.start[1] = 273; + + } else if (dev->tvnorm & V4L2_STD_625_50) { + /* pal */ + f->fmt.vbi.sampling_rate = 35468950; + f->fmt.vbi.start[0] = 7 - 1; + f->fmt.vbi.start[1] = 319 - 1; + } + return 0; +} + +static int cx23885_start_vbi_dma(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], + buf->vb.width, buf->risc.dma); + + /* reset counter */ + q->count = 1; + + /* enable irqs */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); + cx_set(VID_A_INT_MSK, 0x000022); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); + cx_set(VID_A_DMA_CTL, 0x00000022); + + return 0; +} + +int cx23885_stop_vbi_dma(struct cx23885_dev *dev) +{ + /* stop dma */ + cx_clear(VID_A_DMA_CTL, 0x00000022); + + /* disable irqs */ + cx_clear(PCI_INT_MSK, 0x000001); + cx_clear(VID_A_INT_MSK, 0x00000022); + return 0; +} + +int cx23885_restart_vbi_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q) +{ + struct cx23885_buffer *buf; + struct list_head *item; + + if (list_empty(&q->active)) + return 0; + + buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_vbi_dma(dev, q, buf); + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx23885_buffer, vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; +} + +void cx23885_vbi_timeout(unsigned long data) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)data; + struct cx23885_dmaqueue *q = &dev->vbiq; + struct cx23885_buffer *buf; + unsigned long flags; + + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH02]); + + cx_clear(VID_A_DMA_CTL, 0x22); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, + buf, buf->vb.i, (unsigned long)buf->risc.dma); + } + cx23885_restart_vbi_queue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +/* ------------------------------------------------------------------ */ +#define VBI_LINE_LENGTH 2048 +#define VBI_LINE_COUNT 17 + +static int +vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) +{ + *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 == *count) + *count = vbibufs; + if (*count < 2) + *count = 2; + if (*count > 32) + *count = 32; + return 0; +} + +static int +vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + unsigned int size; + int rc; + + size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; + if (0 != buf->vb.baddr && buf->vb.bsize < size) + return -EINVAL; + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + buf->vb.width = VBI_LINE_LENGTH; + buf->vb.height = VBI_LINE_COUNT; + buf->vb.size = size; + buf->vb.field = V4L2_FIELD_SEQ_TB; + + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->vb.width * buf->vb.height, + buf->vb.width, 0, + buf->vb.height); + } + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +static void +vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_fh *fh = vq->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_dmaqueue *q = &dev->vbiq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_vbi_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] vbi_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx23885_buffer, + vb.queue); + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + } +} + +static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + cx23885_free_buffer(q, buf); +} + +struct videobuf_queue_ops cx23885_vbi_qops = { + .buf_setup = vbi_setup, + .buf_prepare = vbi_prepare, + .buf_queue = vbi_queue, + .buf_release = vbi_release, +}; + +/* ------------------------------------------------------------------ */ +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c new file mode 100644 index 000000000000..d3c4d2c5cbe0 --- /dev/null +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -0,0 +1,1557 @@ +/* + * Driver for the Conexant CX23885 PCIe bridge + * + * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 <linux/init.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kmod.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <asm/div64.h> + +#include "cx23885.h" +#include <media/v4l2-common.h> + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +/* Include V4L1 specific functions. Should be removed soon */ +#include <linux/videodev.h> +#endif + +MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); +MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_LICENSE("GPL"); + +/* ------------------------------------------------------------------ */ + +static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; + +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_nr, int, NULL, 0444); +module_param_array(radio_nr, int, NULL, 0444); + +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); + +static unsigned int video_debug; +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); + +static unsigned int irq_debug; +module_param(irq_debug, int, 0644); +MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); + +static unsigned int vid_limit = 16; +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); + +#define dprintk(level, fmt, arg...)\ + do { if (video_debug >= level)\ + printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + } while (0) + +/* ------------------------------------------------------------------- */ +/* static data */ + +#define FORMAT_FLAGS_PACKED 0x01 + +static struct cx23885_fmt formats[] = { + { + .name = "8 bpp, gray", + .fourcc = V4L2_PIX_FMT_GREY, + .depth = 8, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "15 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "15 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB555X, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "16 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "16 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "24 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "32 bpp RGB, le", + .fourcc = V4L2_PIX_FMT_BGR32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "32 bpp RGB, be", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, YUYV", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, { + .name = "4:2:2, packed, UYVY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = 16, + .flags = FORMAT_FLAGS_PACKED, + }, +}; + +static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) + if (formats[i].fourcc == fourcc) + return formats+i; + + printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc); + return NULL; +} + +/* ------------------------------------------------------------------- */ + +static const struct v4l2_queryctrl no_ctl = { + .name = "42", + .flags = V4L2_CTRL_FLAG_DISABLED, +}; + +static struct cx23885_ctrl cx23885_ctls[] = { + /* --- video --- */ + { + .v = { + .id = V4L2_CID_BRIGHTNESS, + .name = "Brightness", + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = LUMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + .v = { + .id = V4L2_CID_CONTRAST, + .name = "Contrast", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = LUMA_CTRL, + .mask = 0xff00, + .shift = 8, + }, { + .v = { + .id = V4L2_CID_HUE, + .name = "Hue", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 128, + .reg = CHROMA_CTRL, + .mask = 0xff0000, + .shift = 16, + }, { + /* strictly, this only describes only U saturation. + * V saturation is handled specially through code. + */ + .v = { + .id = V4L2_CID_SATURATION, + .name = "Saturation", + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .off = 0, + .reg = CHROMA_CTRL, + .mask = 0x00ff, + .shift = 0, + }, { + /* --- audio --- */ + .v = { + .id = V4L2_CID_AUDIO_MUTE, + .name = "Mute", + .minimum = 0, + .maximum = 1, + .default_value = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, + .reg = PATH1_CTL1, + .mask = (0x1f << 24), + .shift = 24, + }, { + .v = { + .id = V4L2_CID_AUDIO_VOLUME, + .name = "Volume", + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .type = V4L2_CTRL_TYPE_INTEGER, + }, + .reg = PATH1_VOL_CTL, + .mask = 0xff, + .shift = 0, + } +}; +static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); + +const u32 cx23885_user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_MUTE, + 0 +}; +EXPORT_SYMBOL(cx23885_user_ctrls); + +static const u32 *ctrl_classes[] = { + cx23885_user_ctrls, + NULL +}; + +void cx23885_video_wakeup(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, u32 count) +{ + struct cx23885_buffer *buf; + int bc; + + for (bc = 0;; bc++) { + if (list_empty(&q->active)) + break; + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + + /* count comes from the hw and is is 16bit wide -- + * this trick handles wrap-arounds correctly for + * up to 32767 buffers in flight... */ + if ((s16) (count - buf->count) < 0) + break; + + do_gettimeofday(&buf->vb.ts); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, + count, buf->count); + buf->vb.state = VIDEOBUF_DONE; + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); + } + if (list_empty(&q->active)) { + del_timer(&q->timeout); + } else { + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + } + if (bc != 1) + printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); +} + +int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +{ + dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", + __FUNCTION__, + (unsigned int)norm, + v4l2_norm_to_name(norm)); + + dev->tvnorm = norm; + + /* Tell the analog tuner/demods */ + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_STD, &norm); + + /* Tell the internal A/V decoder */ + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_STD, &norm); + + return 0; +} + +struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, + struct pci_dev *pci, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + dprintk(1, "%s()\n", __FUNCTION__); + + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + vfd->dev = &pci->dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + dev->name, type, cx23885_boards[dev->board].name); + return vfd; +} + +int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) +{ + int i; + + if (qctrl->id < V4L2_CID_BASE || + qctrl->id >= V4L2_CID_LASTP1) + return -EINVAL; + for (i = 0; i < CX23885_CTLS; i++) + if (cx23885_ctls[i].v.id == qctrl->id) + break; + if (i == CX23885_CTLS) { + *qctrl = no_ctl; + return 0; + } + *qctrl = cx23885_ctls[i].v; + return 0; +} +EXPORT_SYMBOL(cx23885_ctrl_query); + +/* ------------------------------------------------------------------- */ +/* resource management */ + +static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, + unsigned int bit) +{ + dprintk(1, "%s()\n", __FUNCTION__); + if (fh->resources & bit) + /* have it already allocated */ + return 1; + + /* is it free? */ + mutex_lock(&dev->lock); + if (dev->resources & bit) { + /* no, someone else uses it */ + mutex_unlock(&dev->lock); + return 0; + } + /* it's free, grab it */ + fh->resources |= bit; + dev->resources |= bit; + dprintk(1, "res: get %d\n", bit); + mutex_unlock(&dev->lock); + return 1; +} + +static int res_check(struct cx23885_fh *fh, unsigned int bit) +{ + return (fh->resources & bit); +} + +static int res_locked(struct cx23885_dev *dev, unsigned int bit) +{ + return (dev->resources & bit); +} + +static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, + unsigned int bits) +{ + BUG_ON((fh->resources & bits) != bits); + dprintk(1, "%s()\n", __FUNCTION__); + + mutex_lock(&dev->lock); + fh->resources &= ~bits; + dev->resources &= ~bits; + dprintk(1, "res: put %d\n", bits); + mutex_unlock(&dev->lock); +} + +int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) +{ + struct v4l2_routing route; + memset(&route, 0, sizeof(route)); + + dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", + __FUNCTION__, + input, INPUT(input)->vmux, + INPUT(input)->gpio0, INPUT(input)->gpio1, + INPUT(input)->gpio2, INPUT(input)->gpio3); + dev->input = input; + + route.input = INPUT(input)->vmux; + + /* Tell the internal A/V decoder */ + cx23885_call_i2c_clients(&dev->i2c_bus[2], + VIDIOC_INT_S_VIDEO_ROUTING, &route); + + return 0; +} +EXPORT_SYMBOL(cx23885_video_mux); + +/* ------------------------------------------------------------------ */ +int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, + unsigned int height, enum v4l2_field field) +{ + dprintk(1, "%s()\n", __FUNCTION__); + return 0; +} + +static int cx23885_start_video_dma(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf) +{ + dprintk(1, "%s()\n", __FUNCTION__); + + /* setup fifo + format */ + cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01], + buf->bpl, buf->risc.dma); + cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field); + + /* reset counter */ + cx_write(VID_A_GPCNT_CTL, 3); + q->count = 1; + + /* enable irq */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01); + cx_set(VID_A_INT_MSK, 0x000011); + + /* start dma */ + cx_set(DEV_CNTRL2, (1<<5)); + cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */ + + return 0; +} + + +static int cx23885_restart_video_queue(struct cx23885_dev *dev, + struct cx23885_dmaqueue *q) +{ + struct cx23885_buffer *buf, *prev; + struct list_head *item; + dprintk(1, "%s()\n", __FUNCTION__); + + if (!list_empty(&q->active)) { + buf = list_entry(q->active.next, struct cx23885_buffer, + vb.queue); + dprintk(2, "restart_queue [%p/%d]: restart dma\n", + buf, buf->vb.i); + cx23885_start_video_dma(dev, q, buf); + list_for_each(item, &q->active) { + buf = list_entry(item, struct cx23885_buffer, + vb.queue); + buf->count = q->count++; + } + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + return 0; + } + + prev = NULL; + for (;;) { + if (list_empty(&q->queued)) + return 0; + buf = list_entry(q->queued.next, struct cx23885_buffer, + vb.queue); + if (NULL == prev) { + list_move_tail(&buf->vb.queue, &q->active); + cx23885_start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); + + } else if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_move_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ + dprintk(2, "[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); + } else { + return 0; + } + prev = buf; + } +} + +static int buffer_setup(struct videobuf_queue *q, unsigned int *count, + unsigned int *size) +{ + struct cx23885_fh *fh = q->priv_data; + + *size = fh->fmt->depth*fh->width*fh->height >> 3; + if (0 == *count) + *count = 32; + while (*size * *count > vid_limit * 1024 * 1024) + (*count)--; + return 0; +} + +static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, + enum v4l2_field field) +{ + struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + int rc, init_buffer = 0; + u32 line0_offset, line1_offset; + struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + + BUG_ON(NULL == fh->fmt); + if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || + fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) + return -EINVAL; + buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + return -EINVAL; + + if (buf->fmt != fh->fmt || + buf->vb.width != fh->width || + buf->vb.height != fh->height || + buf->vb.field != field) { + buf->fmt = fh->fmt; + buf->vb.width = fh->width; + buf->vb.height = fh->height; + buf->vb.field = field; + init_buffer = 1; + } + + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + init_buffer = 1; + rc = videobuf_iolock(q, &buf->vb, NULL); + if (0 != rc) + goto fail; + } + + if (init_buffer) { + buf->bpl = buf->vb.width * buf->fmt->depth >> 3; + switch (buf->vb.field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, 0, UNSET, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, UNSET, 0, + buf->bpl, 0, buf->vb.height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_NTSC) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating NTSC risc\n", + __FUNCTION__); + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating PAL/SECAM risc\n", + __FUNCTION__); + line0_offset = 0; + line1_offset = buf->bpl; + } + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + 0, buf->bpl * (buf->vb.height >> 1), + buf->bpl, 0, + buf->vb.height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + dma->sglist, + buf->bpl * (buf->vb.height >> 1), 0, + buf->bpl, 0, + buf->vb.height >> 1); + break; + default: + BUG(); + } + } + dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.i, + fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + (unsigned long)buf->risc.dma); + + buf->vb.state = VIDEOBUF_PREPARED; + return 0; + + fail: + cx23885_free_buffer(q, buf); + return rc; +} + +static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_fh *fh = vq->priv_data; + struct cx23885_dev *dev = fh->dev; + struct cx23885_dmaqueue *q = &dev->vidq; + + /* add jump to stopper */ + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + + if (!list_empty(&q->queued)) { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - append to queued\n", + buf, buf->vb.i); + + } else if (list_empty(&q->active)) { + list_add_tail(&buf->vb.queue, &q->active); + cx23885_start_video_dma(dev, q, buf); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + dprintk(2, "[%p/%d] buffer_queue - first active\n", + buf, buf->vb.i); + + } else { + prev = list_entry(q->active.prev, struct cx23885_buffer, + vb.queue); + if (prev->vb.width == buf->vb.width && + prev->vb.height == buf->vb.height && + prev->fmt == buf->fmt) { + list_add_tail(&buf->vb.queue, &q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + buf->count = q->count++; + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + /* 64 bit bits 63-32 */ + prev->risc.jmp[2] = cpu_to_le32(0); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.i); + + } else { + list_add_tail(&buf->vb.queue, &q->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(2, "[%p/%d] buffer_queue - first queued\n", + buf, buf->vb.i); + } + } +} + +static void buffer_release(struct videobuf_queue *q, + struct videobuf_buffer *vb) +{ + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_free_buffer(q, buf); +} + +static struct videobuf_queue_ops cx23885_video_qops = { + .buf_setup = buffer_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .buf_release = buffer_release, +}; + +static struct videobuf_queue *get_queue(struct cx23885_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &fh->vidq; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return &fh->vbiq; + default: + BUG(); + return NULL; + } +} + +static int get_resource(struct cx23885_fh *fh) +{ + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return RESOURCE_VIDEO; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return RESOURCE_VBI; + default: + BUG(); + return 0; + } +} + +static int video_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + struct cx23885_dev *h, *dev = NULL; + struct cx23885_fh *fh; + struct list_head *list; + enum v4l2_buf_type type = 0; + int radio = 0; + + list_for_each(list, &cx23885_devlist) { + h = list_entry(list, struct cx23885_dev, devlist); + if (h->video_dev->minor == minor) { + dev = h; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + if (h->vbi_dev && + h->vbi_dev->minor == minor) { + dev = h; + type = V4L2_BUF_TYPE_VBI_CAPTURE; + } + if (h->radio_dev && + h->radio_dev->minor == minor) { + radio = 1; + dev = h; + } + } + if (NULL == dev) + return -ENODEV; + + dprintk(1, "open minor=%d radio=%d type=%s\n", + minor, radio, v4l2_type_names[type]); + + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + file->private_data = fh; + fh->dev = dev; + fh->radio = radio; + fh->type = type; + fh->width = 320; + fh->height = 240; + fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + + videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops, + dev->pci, &dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct cx23885_buffer), + fh); + + dprintk(1, "post videobuf_queue_init()\n"); + + + return 0; +} + +static ssize_t video_read(struct file *file, char __user *data, + size_t count, loff_t *ppos) +{ + struct cx23885_fh *fh = file->private_data; + + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + return videobuf_read_one(&fh->vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VBI_CAPTURE: + if (!res_get(fh->dev, fh, RESOURCE_VBI)) + return -EBUSY; + return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, + file->f_flags & O_NONBLOCK); + default: + BUG(); + return 0; + } +} + +static unsigned int video_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_buffer *buf; + + if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (!res_get(fh->dev, fh, RESOURCE_VBI)) + return POLLERR; + return videobuf_poll_stream(file, &fh->vbiq, wait); + } + + if (res_check(fh, RESOURCE_VIDEO)) { + /* streaming capture */ + if (list_empty(&fh->vidq.stream)) + return POLLERR; + buf = list_entry(fh->vidq.stream.next, + struct cx23885_buffer, vb.stream); + } else { + /* read() capture */ + buf = (struct cx23885_buffer *)fh->vidq.read_buf; + if (NULL == buf) + return POLLERR; + } + poll_wait(file, &buf->vb.done, wait); + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) + return POLLIN|POLLRDNORM; + return 0; +} + +static int video_release(struct inode *inode, struct file *file) +{ + struct cx23885_fh *fh = file->private_data; + struct cx23885_dev *dev = fh->dev; + + /* turn off overlay */ + if (res_check(fh, RESOURCE_OVERLAY)) { + /* FIXME */ + res_free(dev, fh, RESOURCE_OVERLAY); + } + + /* stop video capture */ + if (res_check(fh, RESOURCE_VIDEO)) { + videobuf_queue_cancel(&fh->vidq); + res_free(dev, fh, RESOURCE_VIDEO); + } + if (fh->vidq.read_buf) { + buffer_release(&fh->vidq, fh->vidq.read_buf); + kfree(fh->vidq.read_buf); + } + + /* stop vbi capture */ + if (res_check(fh, RESOURCE_VBI)) { + if (fh->vbiq.streaming) + videobuf_streamoff(&fh->vbiq); + if (fh->vbiq.reading) + videobuf_read_stop(&fh->vbiq); + res_free(dev, fh, RESOURCE_VBI); + } + + videobuf_mmap_free(&fh->vidq); + file->private_data = NULL; + kfree(fh); + + /* We are not putting the tuner to sleep here on exit, because + * we want to use the mpeg encoder in another session to capture + * tuner video. Closing this will result in no video to the encoder. + */ + + return 0; +} + +static int video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cx23885_fh *fh = file->private_data; + + return videobuf_mmap_mapper(get_queue(fh), vma); +} + +/* ------------------------------------------------------------------ */ +/* VIDEO CTRL IOCTLS */ + +int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +{ + dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__); + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); + return 0; +} +EXPORT_SYMBOL(cx23885_get_control); + +int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +{ + dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" + " (disabled - no action)\n", __FUNCTION__); + return 0; +} +EXPORT_SYMBOL(cx23885_set_control); + +static void init_controls(struct cx23885_dev *dev) +{ + struct v4l2_control ctrl; + int i; + + for (i = 0; i < CX23885_CTLS; i++) { + ctrl.id = cx23885_ctls[i].v.id; + ctrl.value = cx23885_ctls[i].v.default_value; + + cx23885_set_control(dev, &ctrl); + } +} + +/* ------------------------------------------------------------------ */ +/* VIDEO IOCTLS */ + +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = norm_maxw(dev->tvnorm); + maxh = norm_maxh(dev->tvnorm); + + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; + } + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + int err; + + dprintk(2, "%s()\n", __FUNCTION__); + err = vidioc_try_fmt_cap(file, priv, f); + + if (0 != err) + return err; + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->vidq.field = f->fmt.pix.field; + dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__, + fh->width, fh->height, fh->vidq.field); + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + strcpy(cap->driver, "cx23885"); + strlcpy(cap->card, cx23885_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); + cap->version = CX23885_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (UNSET != dev->tuner_type) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; +} + +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static int vidiocgmbuf(struct file *file, void *priv, + struct video_mbuf *mbuf) +{ + struct cx23885_fh *fh = priv; + struct videobuf_queue *q; + struct v4l2_requestbuffers req; + unsigned int i; + int err; + + q = get_queue(fh); + memset(&req, 0, sizeof(req)); + req.type = q->type; + req.count = 8; + req.memory = V4L2_MEMORY_MMAP; + err = videobuf_reqbufs(q, &req); + if (err < 0) + return err; + + mbuf->frames = req.count; + mbuf->size = 0; + for (i = 0; i < mbuf->frames; i++) { + mbuf->offsets[i] = q->bufs[i]->boff; + mbuf->size += q->bufs[i]->bsize; + } + return 0; +} +#endif + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_reqbufs(get_queue(fh), p)); +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_querybuf(get_queue(fh), p)); +} + +static int vidioc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_qbuf(get_queue(fh), p)); +} + +static int vidioc_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *p) +{ + struct cx23885_fh *fh = priv; + return (videobuf_dqbuf(get_queue(fh), p, + file->f_flags & O_NONBLOCK)); +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + if (unlikely(i != fh->type)) + return -EINVAL; + + if (unlikely(!res_get(dev, fh, get_resource(fh)))) + return -EBUSY; + return videobuf_streamon(get_queue(fh)); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + int err, res; + dprintk(1, "%s()\n", __FUNCTION__); + + if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (i != fh->type) + return -EINVAL; + + res = get_resource(fh); + err = videobuf_streamoff(get_queue(fh)); + if (err < 0) + return err; + res_free(dev, fh, res); + return 0; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __FUNCTION__); + + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, *tvnorms); + mutex_unlock(&dev->lock); + + return 0; +} + +int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +{ + static const char *iname[] = { + [CX23885_VMUX_COMPOSITE1] = "Composite1", + [CX23885_VMUX_COMPOSITE2] = "Composite2", + [CX23885_VMUX_COMPOSITE3] = "Composite3", + [CX23885_VMUX_COMPOSITE4] = "Composite4", + [CX23885_VMUX_SVIDEO] = "S-Video", + [CX23885_VMUX_TELEVISION] = "Television", + [CX23885_VMUX_CABLE] = "Cable TV", + [CX23885_VMUX_DVB] = "DVB", + [CX23885_VMUX_DEBUG] = "for debug only", + }; + unsigned int n; + dprintk(1, "%s()\n", __FUNCTION__); + + n = i->index; + if (n >= 4) + return -EINVAL; + + if (0 == INPUT(n)->type) + return -EINVAL; + + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, iname[INPUT(n)->type]); + if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || + (CX23885_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + i->std = CX23885_NORMS; + return 0; +} +EXPORT_SYMBOL(cx23885_enum_input); + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + dprintk(1, "%s()\n", __FUNCTION__); + return cx23885_enum_input(dev, i); +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + *i = dev->input; + dprintk(1, "%s() returns %d\n", __FUNCTION__, *i); + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + dprintk(1, "%s(%d)\n", __FUNCTION__, i); + + if (i >= 4) { + dprintk(1, "%s() -EINVAL\n", __FUNCTION__); + return -EINVAL; + } + + mutex_lock(&dev->lock); + cx23885_video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qctrl) +{ + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (unlikely(qctrl->id == 0)) + return -EINVAL; + return cx23885_ctrl_query(qctrl); +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + return cx23885_get_control(dev, ctl); +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + return cx23885_set_control(dev, ctl); +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; + t->signal = 0xffff ; /* LOCKED */ + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + + if (UNSET == dev->tuner_type) + return -EINVAL; + if (0 != t->index) + return -EINVAL; + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + + /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->freq; + + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_FREQUENCY, f); + + return 0; +} + +int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) +{ + if (unlikely(UNSET == dev->tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; + + mutex_lock(&dev->lock); + dev->freq = f->frequency; + + cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_S_FREQUENCY, f); + + /* When changing channels it is required to reset TVAUDIO */ + msleep(10); + + mutex_unlock(&dev->lock); + + return 0; +} +EXPORT_SYMBOL(cx23885_set_freq); + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = fh->dev; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + return + cx23885_set_freq(dev, f); +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int vidioc_g_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_G_REGISTER, reg); + + return 0; +} + +static int vidioc_s_register(struct file *file, void *fh, + struct v4l2_register *reg) +{ + struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_DBG_S_REGISTER, reg); + + return 0; +} +#endif + +/* ----------------------------------------------------------- */ + +static void cx23885_vid_timeout(unsigned long data) +{ + struct cx23885_dev *dev = (struct cx23885_dev *)data; + struct cx23885_dmaqueue *q = &dev->vidq; + struct cx23885_buffer *buf; + unsigned long flags; + + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + + cx_clear(VID_A_DMA_CTL, 0x11); + + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&q->active)) { + buf = list_entry(q->active.next, + struct cx23885_buffer, vb.queue); + list_del(&buf->vb.queue); + buf->vb.state = VIDEOBUF_ERROR; + wake_up(&buf->vb.done); + printk(KERN_ERR "%s/0: [%p/%d] timeout - dma=0x%08lx\n", + dev->name, buf, buf->vb.i, + (unsigned long)buf->risc.dma); + } + cx23885_restart_video_queue(dev, q); + spin_unlock_irqrestore(&dev->slock, flags); +} + +int cx23885_video_irq(struct cx23885_dev *dev, u32 status) +{ + u32 mask, count; + int handled = 0; + + mask = cx_read(VID_A_INT_MSK); + if (0 == (status & mask)) + return handled; + cx_write(VID_A_INT_STAT, status); + + dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status); + /* risc op code error */ + if (status & (1 << 16)) { + printk(KERN_WARNING "%s/0: video risc op code error\n", + dev->name); + cx_clear(VID_A_DMA_CTL, 0x11); + cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); + } + + /* risc1 y */ + if (status & 0x01) { + spin_lock(&dev->slock); + count = cx_read(VID_A_GPCNT); + cx23885_video_wakeup(dev, &dev->vidq, count); + spin_unlock(&dev->slock); + handled++; + } + /* risc2 y */ + if (status & 0x10) { + dprintk(2, "stopper video\n"); + spin_lock(&dev->slock); + cx23885_restart_video_queue(dev, &dev->vidq); + spin_unlock(&dev->slock); + handled++; + } + + return handled; +} + +/* ----------------------------------------------------------- */ +/* exported stuff */ + +static const struct file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .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, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_fmt_vbi = cx23885_vbi_fmt, + .vidioc_try_fmt_vbi = cx23885_vbi_fmt, + .vidioc_s_fmt_vbi = cx23885_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif + .tvnorms = CX23885_NORMS, + .current_norm = V4L2_STD_NTSC_M, +}; + +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, +}; + + +void cx23885_video_unregister(struct cx23885_dev *dev) +{ + dprintk(1, "%s()\n", __FUNCTION__); + cx_clear(PCI_INT_MSK, 1); + + if (dev->video_dev) { + if (-1 != dev->video_dev->minor) + video_unregister_device(dev->video_dev); + else + video_device_release(dev->video_dev); + dev->video_dev = NULL; + + btcx_riscmem_free(dev->pci, &dev->vidq.stopper); + } +} + +int cx23885_video_register(struct cx23885_dev *dev) +{ + int err; + + dprintk(1, "%s()\n", __FUNCTION__); + spin_lock_init(&dev->slock); + + /* Initialize VBI template */ + 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; + + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + dev->vidq.timeout.function = cx23885_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); + cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, + VID_A_DMA_CTL, 0x11, 0x00); + + /* Don't enable VBI yet */ + cx_set(PCI_INT_MSK, 1); + + + /* register v4l devices */ + dev->video_dev = cx23885_vdev_init(dev, dev->pci, + &cx23885_video_template, "video"); + err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, + video_nr[dev->nr]); + if (err < 0) { + printk(KERN_INFO "%s: can't register video device\n", + dev->name); + goto fail_unreg; + } + printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", + dev->name, dev->video_dev->minor & 0x1f); + /* initial device configuration */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, dev->tvnorm); + init_controls(dev); + cx23885_video_mux(dev, 0); + mutex_unlock(&dev->lock); + + return 0; + +fail_unreg: + cx23885_video_unregister(dev); + return err; +} + diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index dec4dc2fcbb4..7cb2179f2622 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -44,6 +44,10 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 +#define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) +#define RESOURCE_OVERLAY 1 +#define RESOURCE_VIDEO 2 +#define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -53,6 +57,62 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1800 2 #define CX23885_BOARD_HAUPPAUGE_HVR1250 3 #define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4 +#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5 +#define CX23885_BOARD_HAUPPAUGE_HVR1500 6 + +/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ +#define CX23885_NORMS (\ + V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \ + V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \ + V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \ + V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK) + +struct cx23885_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + int depth; + int flags; + u32 cxformat; +}; + +struct cx23885_ctrl { + struct v4l2_queryctrl v; + u32 off; + u32 reg; + u32 mask; + u32 shift; +}; + +struct cx23885_tvnorm { + char *name; + v4l2_std_id id; + u32 cxiformat; + u32 cxoformat; +}; + +struct cx23885_fh { + struct cx23885_dev *dev; + enum v4l2_buf_type type; + int radio; + u32 resources; + + /* video overlay */ + struct v4l2_window win; + struct v4l2_clip *clips; + unsigned int nclips; + + /* video capture */ + struct cx23885_fmt *fmt; + unsigned int width, height; + + /* vbi capture */ + struct videobuf_queue vidq; + struct videobuf_queue vbiq; + + /* MPEG Encoder specifics ONLY */ + struct videobuf_queue mpegq; + atomic_t v4l_reading; +}; enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, @@ -92,12 +152,28 @@ struct cx23885_input { typedef enum { CX23885_MPEG_UNDEFINED = 0, - CX23885_MPEG_DVB + CX23885_MPEG_DVB, + CX23885_ANALOG_VIDEO, } port_t; struct cx23885_board { char *name; - port_t portb, portc; + port_t porta, portb, portc; + unsigned int tuner_type; + unsigned int radio_type; + unsigned char tuner_addr; + unsigned char radio_addr; + + /* Vendors can and do run the PCIe bridge at different + * clock rates, driven physically by crystals on the PCBs. + * The core has to accomodate this. This allows the user + * to add new boards with new frequencys. The value is + * expressed in Hz. + * + * The core framework will default this value based on + * current designs, but it can vary. + */ + u32 clk_freq; struct cx23885_input input[MAX_CX23885_INPUT]; }; @@ -189,6 +265,11 @@ struct cx23885_dev { u32 __iomem *lmmio; u8 __iomem *bmmio; int pci_irqmask; + int hwrevision; + + /* This valud is board specific and is used to configure the + * AV core so we see nice clean and stable video and audio. */ + u32 clk_freq; /* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */ struct cx23885_i2c i2c_bus[3]; @@ -210,8 +291,31 @@ struct cx23885_dev { CX23885_BRIDGE_885 = 885, CX23885_BRIDGE_887 = 887, } bridge; + + /* Analog video */ + u32 resources; + unsigned int input; + u32 tvaudio; + v4l2_std_id tvnorm; + unsigned int tuner_type; + unsigned char tuner_addr; + unsigned int radio_type; + unsigned char radio_addr; + unsigned int has_radio; + + /* V4l */ + u32 freq; + struct video_device *video_dev; + struct video_device *vbi_dev; + struct video_device *radio_dev; + + struct cx23885_dmaqueue vidq; + struct cx23885_dmaqueue vbiq; + spinlock_t slock; }; +extern struct list_head cx23885_devlist; + #define SRAM_CH01 0 /* Video A */ #define SRAM_CH02 1 /* VBI A */ #define SRAM_CH03 2 /* Video B */ @@ -254,19 +358,42 @@ struct sram_channel { #define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) #define cx_clear(reg,bit) cx_andor((reg),(bit),0) +/* ----------------------------------------------------------- */ +/* cx23885-core.c */ + extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc); -/* ----------------------------------------------------------- */ -/* cx23885-cards.c */ +extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, + struct sram_channel *ch); +extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, + u32 reg, u32 mask, u32 value); + +extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, + struct scatterlist *sglist, + unsigned int top_offset, unsigned int bottom_offset, + unsigned int bpl, unsigned int padding, unsigned int lines); + +void cx23885_cancel_buffers(struct cx23885_tsport *port); + +extern int cx23885_restart_queue(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q); + +extern void cx23885_wakeup(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, u32 count); + + +/* ----------------------------------------------------------- */ +/* cx23885-cards.c */ extern struct cx23885_board cx23885_boards[]; extern const unsigned int cx23885_bcount; extern struct cx23885_subid cx23885_subids[]; extern const unsigned int cx23885_idcount; +extern int cx23885_tuner_callback(void *priv, int command, int arg); extern void cx23885_card_list(struct cx23885_dev *dev); extern int cx23885_ir_init(struct cx23885_dev *dev); extern void cx23885_gpio_setup(struct cx23885_dev *dev); @@ -280,19 +407,50 @@ extern int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, struct cx23885_buffer *buf, enum v4l2_field field); - extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); extern void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ +/* cx23885-video.c */ +/* Video */ +extern int cx23885_video_register(struct cx23885_dev *dev); +extern void cx23885_video_unregister(struct cx23885_dev *dev); +extern int cx23885_video_irq(struct cx23885_dev *dev, u32 status); + +/* ----------------------------------------------------------- */ +/* cx23885-vbi.c */ +extern int cx23885_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f); +extern void cx23885_vbi_timeout(unsigned long data); +extern struct videobuf_queue_ops cx23885_vbi_qops; + /* cx23885-i2c.c */ extern int cx23885_i2c_register(struct cx23885_i2c *bus); extern int cx23885_i2c_unregister(struct cx23885_i2c *bus); extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd, void *arg); +/* ----------------------------------------------------------- */ +/* tv norms */ + +static inline unsigned int norm_maxw(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; +} + +static inline unsigned int norm_maxh(v4l2_std_id norm) +{ + return (norm & V4L2_STD_625_50) ? 576 : 480; +} + +static inline unsigned int norm_swidth(v4l2_std_id norm) +{ + return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; +} + + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 3d46a776df36..d6421e1e8f6a 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c @@ -32,118 +32,156 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) /* common for all inputs and rates */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ - cx25840_write(client, 0x127, 0x50); + if (!state->is_cx23885) + cx25840_write(client, 0x127, 0x50); if (state->aud_input != CX25840_AUDIO_SERIAL) { switch (freq) { case 32000: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040610); + cx25840_write4(client, 0x108, 0x1006040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xee39bb01); + cx25840_write4(client, 0x110, 0x01bb39ee); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x0801f77f */ - cx25840_write4(client, 0x900, 0x7ff70108); - cx25840_write4(client, 0x904, 0x7ff70108); - cx25840_write4(client, 0x90c, 0x7ff70108); + cx25840_write4(client, 0x900, 0x0801f77f); + cx25840_write4(client, 0x904, 0x0801f77f); + cx25840_write4(client, 0x90c, 0x0801f77f); break; case 44100: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040910); + cx25840_write4(client, 0x108, 0x1009040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xd66bec00); + cx25840_write4(client, 0x110, 0x00ec6bd6); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x08016d59 */ - cx25840_write4(client, 0x900, 0x596d0108); - cx25840_write4(client, 0x904, 0x596d0108); - cx25840_write4(client, 0x90c, 0x596d0108); + cx25840_write4(client, 0x900, 0x08016d59); + cx25840_write4(client, 0x904, 0x08016d59); + cx25840_write4(client, 0x90c, 0x08016d59); break; case 48000: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040a10); + cx25840_write4(client, 0x108, 0x100a040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xe5d69800); + cx25840_write4(client, 0x110, 0x0098d6e5); if (state->is_cx25836) break; /* src3/4/6_ctl = 0x08014faa */ - cx25840_write4(client, 0x900, 0xaa4f0108); - cx25840_write4(client, 0x904, 0xaa4f0108); - cx25840_write4(client, 0x90c, 0xaa4f0108); + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); break; } } else { switch (freq) { case 32000: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f04081e); + cx25840_write4(client, 0x108, 0x1e08040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0x69082a01); + cx25840_write4(client, 0x110, 0x012a0869); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x00000108); + cx25840_write4(client, 0x8f8, 0x08010000); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x00000208); - cx25840_write4(client, 0x904, 0x00000208); - cx25840_write4(client, 0x90c, 0x00000208); + cx25840_write4(client, 0x900, 0x08020000); + cx25840_write4(client, 0x904, 0x08020000); + cx25840_write4(client, 0x90c, 0x08020000); /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ cx25840_write(client, 0x127, 0x54); break; case 44100: + if (state->is_cx23885) { + /* We don't have register values + * so avoid destroying registers. */ + break; + } + /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040918); + cx25840_write4(client, 0x108, 0x1809040f); /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xd66bec00); + cx25840_write4(client, 0x110, 0x00ec6bd6); if (state->is_cx25836) break; /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0xcd600108); + cx25840_write4(client, 0x8f8, 0x080160cd); /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x85730108); - cx25840_write4(client, 0x904, 0x85730108); - cx25840_write4(client, 0x90c, 0x85730108); + cx25840_write4(client, 0x900, 0x08017385); + cx25840_write4(client, 0x904, 0x08017385); + cx25840_write4(client, 0x90c, 0x08017385); break; case 48000: - /* VID_PLL and AUX_PLL */ - cx25840_write4(client, 0x108, 0x0f040a18); + if (!state->is_cx23885) { + /* VID_PLL and AUX_PLL */ + cx25840_write4(client, 0x108, 0x180a040f); - /* AUX_PLL_FRAC */ - cx25840_write4(client, 0x110, 0xe5d69800); + /* AUX_PLL_FRAC */ + cx25840_write4(client, 0x110, 0x0098d6e5); + } if (state->is_cx25836) break; - /* src1_ctl = 0x08010000 */ - cx25840_write4(client, 0x8f8, 0x00800108); + if (!state->is_cx23885) { + /* src1_ctl */ + cx25840_write4(client, 0x8f8, 0x08018000); - /* src3/4/6_ctl = 0x08020000 */ - cx25840_write4(client, 0x900, 0x55550108); - cx25840_write4(client, 0x904, 0x55550108); - cx25840_write4(client, 0x90c, 0x55550108); + /* src3/4/6_ctl */ + cx25840_write4(client, 0x900, 0x08015555); + cx25840_write4(client, 0x904, 0x08015555); + cx25840_write4(client, 0x90c, 0x08015555); + } else { + + cx25840_write4(client, 0x8f8, 0x0801867c); + + cx25840_write4(client, 0x900, 0x08014faa); + cx25840_write4(client, 0x904, 0x08014faa); + cx25840_write4(client, 0x90c, 0x08014faa); + } break; } } @@ -168,14 +206,14 @@ void cx25840_audio_set_path(struct i2c_client *client) if (state->aud_input == CX25840_AUDIO_SERIAL) { /* Set Path1 to Serial Audio Input */ - cx25840_write4(client, 0x8d0, 0x12100101); + cx25840_write4(client, 0x8d0, 0x01011012); /* The microcontroller should not be started for the * non-tuner inputs: autodetection is specific for * TV audio. */ } else { /* Set Path1 to Analog Demod Main Channel */ - cx25840_write4(client, 0x8d0, 0x7038061f); + cx25840_write4(client, 0x8d0, 0x1f063870); } set_audclk_freq(client, state->audclk_freq); @@ -188,6 +226,11 @@ void cx25840_audio_set_path(struct i2c_client *client) /* deassert soft reset */ cx25840_and_or(client, 0x810, ~0x1, 0x00); + + if (state->is_cx23885) { + /* Ensure the controller is running when we exit */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); + } } static int get_volume(struct i2c_client *client) diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 15f191e170d2..756a1eeb274e 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -13,6 +13,8 @@ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. * + * CX23885 support by Steven Toth <stoth@hauppauge.com>. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -37,6 +39,7 @@ #include <linux/delay.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv-legacy.h> #include <media/cx25840.h> #include "cx25840-core.h" @@ -72,10 +75,10 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) u8 buffer[6]; buffer[0] = addr >> 8; buffer[1] = addr & 0xff; - buffer[2] = value >> 24; - buffer[3] = (value >> 16) & 0xff; - buffer[4] = (value >> 8) & 0xff; - buffer[5] = value & 0xff; + buffer[2] = value & 0xff; + buffer[3] = (value >> 8) & 0xff; + buffer[4] = (value >> 16) & 0xff; + buffer[5] = value >> 24; return i2c_master_send(client, buffer, 6); } @@ -122,8 +125,6 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, enum cx25840_audio_input aud_input); -static void log_audio_status(struct i2c_client *client); -static void log_video_status(struct i2c_client *client); /* ----------------------------------------------------------------------- */ @@ -256,6 +257,96 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_and_or(client, 0x803, ~0x10, 0x10); } +static void cx23885_initialize(struct i2c_client *client) +{ + DEFINE_WAIT(wait); + struct cx25840_state *state = i2c_get_clientdata(client); + struct workqueue_struct *q; + + /* Internal Reset */ + cx25840_and_or(client, 0x102, ~0x01, 0x01); + cx25840_and_or(client, 0x102, ~0x01, 0x00); + + /* Stop microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x00); + + /* DIF in reset? */ + cx25840_write(client, 0x398, 0); + + /* Trust the default xtal, no division */ + /* This changes for the cx23888 products */ + cx25840_write(client, 0x2, 0x76); + + /* Bring down the regulator for AUX clk */ + cx25840_write(client, 0x1, 0x40); + + /* Sys PLL frac */ + cx25840_write4(client, 0x11c, 0x01d1744c); + + /* Sys PLL int */ + cx25840_write4(client, 0x118, 0x00000416); + + /* Disable DIF bypass */ + cx25840_write4(client, 0x33c, 0x00000001); + + /* DIF Src phase inc */ + cx25840_write4(client, 0x340, 0x0df7df83); + + /* Vid PLL frac */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + + /* Vid PLL int */ + cx25840_write4(client, 0x108, 0x00000512); + + /* Luma */ + cx25840_write4(client, 0x414, 0x00107d12); + + /* Chroma */ + cx25840_write4(client, 0x420, 0x3d008282); + + /* Aux PLL frac */ + cx25840_write4(client, 0x114, 0x017dbf48); + + /* Aux PLL int */ + cx25840_write4(client, 0x110, 0x000a030e); + + /* ADC2 input select */ + cx25840_write(client, 0x102, 0x10); + + /* VIN1 & VIN5 */ + cx25840_write(client, 0x103, 0x11); + + /* Enable format auto detect */ + cx25840_write(client, 0x400, 0); + /* Fast subchroma lock */ + /* White crush, Chroma AGC & Chroma Killer enabled */ + cx25840_write(client, 0x401, 0xe8); + + /* Select AFE clock pad output source */ + cx25840_write(client, 0x144, 0x05); + + /* Do the firmware load in a work handler to prevent. + Otherwise the kernel is blocked waiting for the + bit-banging i2c interface to finish uploading the + firmware. */ + INIT_WORK(&state->fw_work, cx25840_work_handler); + init_waitqueue_head(&state->fw_wait); + q = create_singlethread_workqueue("cx25840_fw"); + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + + cx25840_vbi_setup(client); + + /* (re)set input */ + set_input(client, state->vid_input, state->aud_input); + + /* start microcontroller */ + cx25840_and_or(client, 0x803, ~0x10, 0x10); +} + /* ----------------------------------------------------------------------- */ static void input_change(struct i2c_client *client) @@ -319,9 +410,22 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input <= CX25840_COMPOSITE8); u8 reg; - v4l_dbg(1, cx25840_debug, client, "decoder set video input %d, audio input %d\n", - vid_input, aud_input); + v4l_dbg(1, cx25840_debug, client, + "decoder set video input %d, audio input %d\n", + vid_input, aud_input); + + if (vid_input >= CX25840_VIN1_CH1) { + v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", + vid_input); + reg = vid_input & 0xff; + if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) + is_composite = 0; + else + is_composite = 1; + v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", + reg, is_composite); + } else if (is_composite) { reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); } else { @@ -331,7 +435,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp if ((vid_input & ~0xff0) || luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA4 || chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { - v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); + v4l_err(client, "0x%04x is not a valid video input!\n", + vid_input); return -EINVAL; } reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); @@ -344,31 +449,49 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp } } - switch (aud_input) { - case CX25840_AUDIO_SERIAL: - /* do nothing, use serial audio input */ - break; - case CX25840_AUDIO4: reg &= ~0x30; break; - case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX25840_AUDIO7: reg &= ~0xc0; break; - case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + /* The caller has previously prepared the correct routing + * configuration in reg (for the cx23885) so we have no + * need to attempt to flip bits for earlier av decoders. + */ + if (!state->is_cx23885) { + switch (aud_input) { + case CX25840_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX25840_AUDIO4: reg &= ~0x30; break; + case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX25840_AUDIO7: reg &= ~0xc0; break; + case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; - default: - v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); - return -EINVAL; + default: + v4l_err(client, "0x%04x is not a valid audio input!\n", + aud_input); + return -EINVAL; + } } cx25840_write(client, 0x103, reg); + /* Set INPUT_MODE to Composite (0) or S-Video (1) */ cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); - /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ - if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) - cx25840_and_or(client, 0x102, ~0x4, 4); - else - cx25840_and_or(client, 0x102, ~0x4, 0); + + if (!state->is_cx23885) { + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx25840_and_or(client, 0x102, ~0x4, 4); + else + cx25840_and_or(client, 0x102, ~0x4, 0); + } else { + if (is_composite) + /* ADC2 input select channel 2 */ + cx25840_and_or(client, 0x102, ~0x2, 0); + else + /* ADC2 input select channel 3 */ + cx25840_and_or(client, 0x102, ~0x2, 2); + } state->vid_input = vid_input; state->aud_input = aud_input; @@ -376,6 +499,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_audio_set_path(client); input_change(client); } + + if (state->is_cx23885) { + /* Audio channel 1 src : Parallel 1 */ + cx25840_write(client, 0x124, 0x03); + + /* Select AFE clock pad output source */ + cx25840_write(client, 0x144, 0x05); + + /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ + cx25840_write(client, 0x914, 0xa0); + + /* I2S_OUT_CTL: + * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 + * I2S_OUT_MASTER_MODE = Master + */ + cx25840_write(client, 0x918, 0xa0); + cx25840_write(client, 0x919, 0x01); + } + return 0; } @@ -641,6 +783,200 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) /* ----------------------------------------------------------------------- */ +static void log_video_status(struct i2c_client *client) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx25840_state *state = i2c_get_clientdata(client); + u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; + u8 gen_stat1 = cx25840_read(client, 0x40d); + u8 gen_stat2 = cx25840_read(client, 0x40e); + int vid_input = state->vid_input; + + v4l_info(client, "Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + v4l_info(client, "Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + v4l_info(client, "Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX25840_COMPOSITE1 && + vid_input <= CX25840_COMPOSITE8) { + v4l_info(client, "Specified video input: Composite %d\n", + vid_input - CX25840_COMPOSITE1 + 1); + } else { + v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct i2c_client *client) +{ + struct cx25840_state *state = i2c_get_clientdata(client); + u8 download_ctl = cx25840_read(client, 0x803); + u8 mod_det_stat0 = cx25840_read(client, 0x804); + u8 mod_det_stat1 = cx25840_read(client, 0x805); + u8 audio_config = cx25840_read(client, 0x808); + u8 pref_mode = cx25840_read(client, 0x809); + u8 afc0 = cx25840_read(client, 0x80b); + u8 mute_ctl = cx25840_read(client, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "not defined"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0x0e: p = "IF FM Radio"; break; + case 0x0f: p = "BTSC"; break; + case 0x10: p = "high-deviation FM"; break; + case 0x11: p = "very high-deviation FM"; break; + case 0xfd: p = "unknown audio standard"; break; + case 0xfe: p = "forced audio standard"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + v4l_info(client, "Detected audio standard: %s\n", p); + v4l_info(client, "Audio muted: %s\n", + (state->unmute_volume >= 0) ? "yes" : "no"); + v4l_info(client, "Audio microcontroller: %s\n", + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "undefined"; break; + case 0x01: p = "BTSC"; break; + case 0x02: p = "EIAJ"; break; + case 0x03: p = "A2-M"; break; + case 0x04: p = "A2-BG"; break; + case 0x05: p = "A2-DK1"; break; + case 0x06: p = "A2-DK2"; break; + case 0x07: p = "A2-DK3"; break; + case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x09: p = "AM-L"; break; + case 0x0a: p = "NICAM-BG"; break; + case 0x0b: p = "NICAM-DK"; break; + case 0x0c: p = "NICAM-I"; break; + case 0x0d: p = "NICAM-L"; break; + case 0x0e: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + v4l_info(client, "Configured audio system: %s\n", p); + } + + if (aud_input) { + v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + } else { + v4l_info(client, "Specified audio input: External\n"); + } + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + v4l_info(client, "Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 3) & 0x3) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + case 2: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x7) { + case 0: p = "chroma"; break; + case 1: p = "BTSC"; break; + case 2: p = "EIAJ"; break; + case 3: p = "A2-M"; break; + case 4: p = "autodetect"; break; + default: p = "undefined"; + } + v4l_info(client, "Selected 45 MHz format: %s\n", p); + } +} + +/* ----------------------------------------------------------------------- */ + static int cx25840_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -660,6 +996,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, state->is_initialized = 1; if (state->is_cx25836) cx25836_initialize(client); + else if (state->is_cx23885) + cx23885_initialize(client); else cx25840_initialize(client); } @@ -677,6 +1015,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (cmd == VIDIOC_DBG_G_REGISTER) reg->val = cx25840_read(client, reg->reg & 0x0fff); else @@ -693,14 +1032,26 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_STREAMON: v4l_dbg(1, cx25840_debug, client, "enable output\n"); - cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c); - cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07); + if (state->is_cx23885) { + u8 v = (cx25840_read(client, 0x421) | 0x0b); + cx25840_write(client, 0x421, v); + } else { + cx25840_write(client, 0x115, + state->is_cx25836 ? 0x0c : 0x8c); + cx25840_write(client, 0x116, + state->is_cx25836 ? 0x04 : 0x07); + } break; case VIDIOC_STREAMOFF: v4l_dbg(1, cx25840_debug, client, "disable output\n"); - cx25840_write(client, 0x115, 0x00); - cx25840_write(client, 0x116, 0x00); + if (state->is_cx23885) { + u8 v = cx25840_read(client, 0x421) & ~(0x0b); + cx25840_write(client, 0x421, v); + } else { + cx25840_write(client, 0x115, 0x00); + cx25840_write(client, 0x116, 0x00); + } break; case VIDIOC_LOG_STATUS: @@ -863,6 +1214,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_INT_RESET: if (state->is_cx25836) cx25836_initialize(client); + else if (state->is_cx23885) + cx23885_initialize(client); else cx25840_initialize(client); break; @@ -879,35 +1232,21 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_cx25840; - -static int cx25840_detect_client(struct i2c_adapter *adapter, int address, - int kind) +static int cx25840_probe(struct i2c_client *client) { - struct i2c_client *client; struct cx25840_state *state; u32 id; u16 device_id; - /* Check if the adapter supports the needed features - * Not until kernel version 2.6.11 did the bit-algo - * correctly report that it would do an I2C-level xfer */ - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_cx25840; - snprintf(client->name, sizeof(client->name) - 1, "cx25840"); + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); + v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); /* The high byte of the device ID should be * 0x83 for the cx2583x and 0x84 for the cx2584x */ @@ -916,16 +1255,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, } else if ((device_id & 0xff00) == 0x8400) { id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); + } else if (device_id == 0x0000) { + id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; + } else if (device_id == 0x1313) { + id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); if (state == NULL) { - kfree(client); return -ENOMEM; } @@ -939,6 +1280,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, i2c_set_clientdata(client, state); state->c = client; state->is_cx25836 = ((device_id & 0xff00) == 0x8300); + state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); state->vid_input = CX25840_COMPOSITE7; state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; @@ -949,250 +1291,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->id = id; state->rev = device_id; - i2c_attach_client(client); - - return 0; -} - -static int cx25840_attach_adapter(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, &cx25840_detect_client); return 0; } -static int cx25840_detach_client(struct i2c_client *client) +static int cx25840_remove(struct i2c_client *client) { - struct cx25840_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver i2c_driver_cx25840 = { - .driver = { - .name = "cx25840", - }, - .id = I2C_DRIVERID_CX25840, - .attach_adapter = cx25840_attach_adapter, - .detach_client = cx25840_detach_client, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "cx25840", + .driverid = I2C_DRIVERID_CX25840, .command = cx25840_command, + .probe = cx25840_probe, + .remove = cx25840_remove, }; - - -static int __init m__init(void) -{ - return i2c_add_driver(&i2c_driver_cx25840); -} - -static void __exit m__exit(void) -{ - i2c_del_driver(&i2c_driver_cx25840); -} - -module_init(m__init); -module_exit(m__exit); - -/* ----------------------------------------------------------------------- */ - -static void log_video_status(struct i2c_client *client) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx25840_state *state = i2c_get_clientdata(client); - u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; - u8 gen_stat1 = cx25840_read(client, 0x40d); - u8 gen_stat2 = cx25840_read(client, 0x40e); - int vid_input = state->vid_input; - - v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); - - if (vid_input >= CX25840_COMPOSITE1 && - vid_input <= CX25840_COMPOSITE8) { - v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); - } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); - } - - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); -} - -/* ----------------------------------------------------------------------- */ - -static void log_audio_status(struct i2c_client *client) -{ - struct cx25840_state *state = i2c_get_clientdata(client); - u8 download_ctl = cx25840_read(client, 0x803); - u8 mod_det_stat0 = cx25840_read(client, 0x804); - u8 mod_det_stat1 = cx25840_read(client, 0x805); - u8 audio_config = cx25840_read(client, 0x808); - u8 pref_mode = cx25840_read(client, 0x809); - u8 afc0 = cx25840_read(client, 0x80b); - u8 mute_ctl = cx25840_read(client, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; - } - v4l_info(client, "Detected audio standard: %s\n", p); - v4l_info(client, "Audio muted: %s\n", - (state->unmute_volume >= 0) ? "yes" : "no"); - v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; - } - v4l_info(client, "Configured audio system: %s\n", p); - } - - if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); - } else { - v4l_info(client, "Specified audio input: External\n"); - } - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; - } - v4l_info(client, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; - } - v4l_info(client, "Selected 45 MHz format: %s\n", p); - } -} diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index ea669b1f084d..95093edc9186 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h @@ -47,6 +47,7 @@ struct cx25840_state { u32 id; u32 rev; int is_cx25836; + int is_cx23885; int is_initialized; wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ struct work_struct fw_work; /* work entry for fw load */ diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index e852024a5ea3..1ddf724a2c74 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -24,6 +24,7 @@ #include "cx25840-core.h" #define FWFILE "v4l-cx25840.fw" +#define FWFILE_CX23885 "v4l-cx23885-avcore-01.fw" /* * Mike Isely <isely@pobox.com> - The FWSEND parameter controls the @@ -92,10 +93,14 @@ static int fw_write(struct i2c_client *client, u8 * data, int size) int cx25840_loadfw(struct i2c_client *client) { + struct cx25840_state *state = i2c_get_clientdata(client); const struct firmware *fw = NULL; u8 buffer[4], *ptr; int size, send, retval; + if (state->is_cx23885) + firmware = FWFILE_CX23885; + if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { v4l_err(client, "unable to open firmware %s\n", firmware); return -EINVAL; diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index ced13febed89..6828f59b9d83 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -180,7 +180,7 @@ void cx25840_vbi_setup(struct i2c_client *client) fsc/1000000,fsc%1000000); v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i , vactive %i, vblank656 %i, src_dec %i," + "vblank %i, vactive %i, vblank656 %i, src_dec %i, " "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," " sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index ceb31d4a2512..49d3813a9b48 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -8,6 +8,7 @@ config VIDEO_CX88 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO ---help--- This is a video4linux driver for Conexant 2388x based TV cards. diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 40ffd7a5579a..8735227f7e47 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -417,7 +417,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; chip->buf = buf; chip->dma_risc = dma; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index f802b5653569..a99e9d5950aa 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -307,7 +307,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value) /* ------------------------------------------------------------------ */ -static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { struct cx8802_dev *dev = priv; unsigned long timeout; @@ -536,11 +536,12 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) dprintk(1,"Initialize codec\n"); retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ if (retval < 0) { + + dev->mpeg_active = 0; + /* ping was not successful, reset and upload firmware */ cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ - msleep(1); cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */ - msleep(1); retval = blackbird_load_firmware(dev); if (retval < 0) return retval; @@ -562,7 +563,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) } dprintk(0, "Firmware version is 0x%08x\n", version); } - msleep(1); cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */ cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */ @@ -570,40 +570,68 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ blackbird_codec_settings(dev); - msleep(1); - /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef); - blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0); - blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */ blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, BLACKBIRD_FIELD1_SAA7115, BLACKBIRD_FIELD2_SAA7115 ); - /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */ blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - /* initialize the video input */ - blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + return 0; +} - msleep(1); +static int blackbird_start_codec(struct file *file, void *priv) +{ + struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; + struct cx88_core *core = dev->core; + /* start capturing to the host interface */ + u32 reg; - blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE); - msleep(1); - blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE); - msleep(1); + int i; + int lastchange = -1; + int lastval = 0; + + for (i = 0; (i < 10) && (i < (lastchange + 4)); i++) { + reg = cx_read(AUD_STATUS); + + dprintk(1, "AUD_STATUS:%dL: 0x%x\n", i, reg); + if ((reg & 0x0F) != lastval) { + lastval = reg & 0x0F; + lastchange = i; + } + msleep(100); + } + + /* unmute audio source */ + cx_clear(AUD_VOL_CTL, (1 << 6)); + + blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0, 0); + + /* initialize the video input */ + blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); /* start capturing to the host interface */ - /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE ); - msleep(10); - blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0); + dev->mpeg_active = 1; + return 0; +} + +static int blackbird_stop_codec(struct cx8802_dev *dev) +{ + blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + BLACKBIRD_END_NOW, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE + ); + + dev->mpeg_active = 0; return 0; } @@ -833,6 +861,10 @@ static int vidioc_s_ext_ctrls (struct file *file, void *priv, if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; + + if (dev->mpeg_active) + blackbird_stop_codec(dev); + p = dev->params; err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); if (!err) { @@ -864,10 +896,9 @@ static int vidioc_s_frequency (struct file *file, void *priv, struct cx8802_dev *dev = fh->dev; struct cx88_core *core = dev->core; - blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE); + if (dev->mpeg_active) + blackbird_stop_codec(dev); + cx88_set_freq (core,f); blackbird_initialize_codec(dev); cx88_set_scale(dev->core, dev->width, dev->height, @@ -1073,15 +1104,11 @@ static int mpeg_open(struct inode *inode, struct file *file) static int mpeg_release(struct inode *inode, struct file *file) { struct cx8802_fh *fh = file->private_data; - struct cx8802_dev *dev = NULL; + struct cx8802_dev *dev = fh->dev; struct cx8802_driver *drv = NULL; - /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */ - blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); + if (dev->mpeg_active) + blackbird_stop_codec(dev); cx8802_cancel_buffers(fh->dev); /* stop mpeg capture */ @@ -1107,6 +1134,10 @@ static ssize_t mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct cx8802_fh *fh = file->private_data; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); @@ -1282,6 +1313,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) core->name); host_setup(dev->core); + blackbird_initialize_codec(dev); blackbird_register_video(dev); /* initial device configuration: needed ? */ diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index a4eb6a87a761..e6b7f518c56e 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include "cx88.h" +#include "tea5767.h" static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -245,6 +246,10 @@ static const struct cx88_board cx88_boards[] = { }}, .radio = { .type = CX88_RADIO, + .vmux = 3, + .gpio0 = 0x000040bf, + .gpio1 = 0x000080c0, + .gpio2 = 0x0000ff20, }, }, [CX88_BOARD_WINFAST_DV2000] = { @@ -297,22 +302,22 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, - .extadc = 1, + .audioroute = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -373,7 +378,7 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, @@ -544,7 +549,7 @@ static const struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .extadc = 1, + .audioroute = 1, }}, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -667,22 +672,22 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, - .extadc = 1, + .audioroute = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -821,23 +826,23 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, .vmux = 2, .gpio0 = 0x0000cdf3, - .extadc = 1, + .audioroute = 1, }, .mpeg = CX88_MPEG_BLACKBIRD, }, @@ -1105,12 +1110,12 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, - .extadc = 1, + .audioroute = 1, }}, .radio = { .type = CX88_RADIO, @@ -1335,17 +1340,17 @@ static const struct cx88_board cx88_boards[] = { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xe780, - .extadc = 1, + .audioroute = 1, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xe780, - .extadc = 1, + .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xe780, - .extadc = 1, + .audioroute = 2, }}, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD, @@ -1370,6 +1375,32 @@ static const struct cx88_board cx88_boards[] = { .gpio0 = 0x07fa, }}, }, + [CX88_BOARD_PINNACLE_PCTV_HD_800i] = { + .name = "Pinnacle PCTV HD 800i", + .tuner_type = TUNER_XC5000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x04fb, + .gpio1 = 0x10ff, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x04fb, + .gpio1 = 0x10ef, + .audioroute = 1, + }}, + .mpeg = CX88_MPEG_DVB, + }, }; /* ------------------------------------------------------------------ */ @@ -1679,6 +1710,10 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x1421, .subdevice = 0x0390, .card = CX88_BOARD_ADSTECH_PTV_390, + },{ + .subvendor = 0x11bd, + .subdevice = 0x0051, + .card = CX88_BOARD_PINNACLE_PCTV_HD_800i, }, }; @@ -1846,6 +1881,36 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) } /* ----------------------------------------------------------------------- */ +/* Tuner callback function. Currently only needed for the Pinnacle * + * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * + * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ + +int cx88_tuner_callback(void *priv, int command, int arg) +{ + struct i2c_algo_bit_data *i2c_algo = priv; + struct cx88_core *core = i2c_algo->data; + + switch(core->boardnr) { + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + if(command == 0) { /* This is the reset command from xc5000 */ + /* Reset XC5000 tuner via SYS_RSTO_pin */ + cx_write(MO_SRST_IO, 0); + msleep(10); + cx_write(MO_SRST_IO, 1); + return 0; + } + else { + printk(KERN_ERR + "xc5000: unknown tuner callback command.\n"); + return -EINVAL; + } + break; + } + return 0; /* Should never be here */ +} +EXPORT_SYMBOL(cx88_tuner_callback); + +/* ----------------------------------------------------------------------- */ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { @@ -1979,6 +2044,23 @@ static void cx88_card_setup(struct cx88_core *core) core->name, i); } break; + case CX88_BOARD_MSI_TVANYWHERE_MASTER: + { + struct v4l2_priv_tun_config tea5767_cfg; + struct tea5767_ctrl ctl; + + memset(&ctl, 0, sizeof(ctl)); + + ctl.high_cut = 1; + ctl.st_noise = 1; + ctl.deemph_75 = 1; + ctl.xtal_freq = TEA5767_HIGH_LO_13MHz; + + tea5767_cfg.tuner = TUNER_TEA5767; + tea5767_cfg.priv = &ctl; + + cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); + } } } diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 62e8dd24c5f5..01e2ac98970b 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -220,7 +220,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -538,7 +538,7 @@ void cx88_wakeup(struct cx88_core *core, do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index fce19caf9d04..f7b41eb1bb5a 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -40,6 +40,8 @@ #include "cx22702.h" #include "or51132.h" #include "lgdt330x.h" +#include "s5h1409.h" +#include "xc5000.h" #include "nxt200x.h" #include "cx24123.h" #include "isl6421.h" @@ -371,6 +373,22 @@ static struct cx24123_config kworld_dvbs_100_config = { .lnb_polarity = 1, }; +static struct s5h1409_config pinnacle_pctv_hd_800i_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_PARALLEL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK, +}; + +static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = { + .i2c_address = 0x64, + .if_khz = 5380, + .tuner_callback = cx88_tuner_callback, +}; + static int dvb_register(struct cx8802_dev *dev) { /* init struct videobuf_dvb */ @@ -625,6 +643,21 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage; } break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + dev->dvb.frontend = dvb_attach(s5h1409_attach, + &pinnacle_pctv_hd_800i_config, + &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) { + /* tuner_config.video_dev must point to + * i2c_adap.algo_data + */ + pinnacle_pctv_hd_800i_tuner_config.priv = + dev->core->i2c_adap.algo_data; + dvb_attach(xc5000_attach, dev->dvb.frontend, + &dev->core->i2c_adap, + &pinnacle_pctv_hd_800i_tuner_config); + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", dev->core->name); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c8b1c50625f4..566b26af523e 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -109,26 +109,32 @@ static int attach_inform(struct i2c_client *client) if (core->board.radio_type != UNSET) { if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); } } if (core->board.tuner_type != UNSET) { if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - + tun_setup.mode_mask = T_ANALOG_TV; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); } } - if (core->board.tda9887_conf) - client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf); + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); + } return 0; } @@ -176,6 +182,7 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0xc2 >> 1 ] = "tuner (analog/dvb)", + [ 0xc8 >> 1 ] = "xc5000", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index e52de3968c63..bb0911b4d2f6 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -305,6 +305,11 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keycode = 0xfa; ir->polling = 50; /* ms */ break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + ir_codes = ir_codes_pinnacle_pctv_hd; + ir_type = IR_TYPE_RC5; + ir->sampling = 1; + break; } if (NULL == ir_codes) { @@ -443,6 +448,7 @@ void cx88_ir_irq(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_PINNACLE_PCTV_HD_800i: ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7); ir_dprintk("biphase decoded: %x\n", ircode); if ((ircode & 0xfffff000) != 0x3000) diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 448c67380945..0aedbeaf94cd 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -102,7 +102,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01); + cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: @@ -117,6 +117,15 @@ static int cx8802_start_dma(struct cx8802_dev *dev, break; case CX88_BOARD_HAUPPAUGE_HVR1300: break; + case CX88_BOARD_PINNACLE_PCTV_HD_800i: + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); + cx_write(TS_HW_SOP_CNTRL, (0x47 << 16) | (188 << 4)); + dev->ts_gen_cntrl = 5; + cx_write(TS_SOP_STAT, 0); + cx_write(TS_VALERR_CNTRL, 0); + udelay(100); + break; default: cx_write(TS_SOP_STAT, 0x00); break; @@ -195,7 +204,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); cx8802_start_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] restart_queue - first active\n", @@ -206,7 +215,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, prev->fmt == buf->fmt) { list_del(&buf->vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(1,"[%p/%d] restart_queue - move to active\n", @@ -242,7 +251,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { buf->vb.width = dev->ts_packet_size; buf->vb.height = dev->ts_packet_count; buf->vb.size = size; @@ -254,7 +263,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev, dma->sglist, buf->vb.width, buf->vb.height, 0); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -276,7 +285,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->vb.queue,&cx88q->active); cx8802_start_dma(dev, cx88q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(1,"[%p/%d] %s - first active\n", @@ -286,7 +295,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&cx88q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", @@ -306,7 +315,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); dprintk(1,"[%p/%d] %s - dma=0x%08lx\n", buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); @@ -437,10 +446,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) return IRQ_RETVAL(handled); } -/* ----------------------------------------------------------- */ -/* exported stuff */ - -int cx8802_init_common(struct cx8802_dev *dev) +static int cx8802_init_common(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; int err; @@ -488,7 +494,7 @@ int cx8802_init_common(struct cx8802_dev *dev) return 0; } -void cx8802_fini_common(struct cx8802_dev *dev) +static void cx8802_fini_common(struct cx8802_dev *dev) { dprintk( 2, "cx8802_fini_common\n" ); cx8802_stop_dma(dev); @@ -504,7 +510,7 @@ void cx8802_fini_common(struct cx8802_dev *dev) /* ----------------------------------------------------------- */ -int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) +static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -530,7 +536,7 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) return 0; } -int cx8802_resume_common(struct pci_dev *pci_dev) +static int cx8802_resume_common(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; @@ -874,9 +880,6 @@ EXPORT_SYMBOL(cx8802_buf_prepare); EXPORT_SYMBOL(cx8802_buf_queue); EXPORT_SYMBOL(cx8802_cancel_buffers); -EXPORT_SYMBOL(cx8802_init_common); -EXPORT_SYMBOL(cx8802_fini_common); - EXPORT_SYMBOL(cx8802_register_driver); EXPORT_SYMBOL(cx8802_unregister_driver); EXPORT_SYMBOL(cx8802_get_driver); diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c index babb08556406..d96ecfcf393a 100644 --- a/drivers/media/video/cx88/cx88-vbi.c +++ b/drivers/media/video/cx88/cx88-vbi.c @@ -130,7 +130,7 @@ void cx8800_vbi_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); @@ -168,7 +168,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = VBI_LINE_LENGTH; buf->vb.height = VBI_LINE_COUNT; @@ -183,7 +183,7 @@ vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, buf->vb.width, 0, buf->vb.height); } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -207,7 +207,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); cx8800_start_vbi_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] vbi_queue - first active\n", @@ -216,7 +216,7 @@ vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue); list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index c84dafbdb991..7f1931aed207 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -392,13 +392,41 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { - /* sets sound input from external adc */ - if (INPUT(input).extadc) + /* if there are audioroutes defined, we have an external + ADC to deal with audio */ + + if (INPUT(input).audioroute) { + + /* cx2388's C-ADC is connected to the tuner only. + When used with S-Video, that ADC is busy dealing with + chroma, so an external must be used for baseband audio */ + + if (INPUT(input).type != CX88_VMUX_TELEVISION && + INPUT(input).type != CX88_RADIO) { + /* "ADC mode" */ + cx_write(AUD_I2SCNTL, 0x1); cx_set(AUD_CTL, EN_I2SIN_ENABLE); - else + } else { + /* Normal mode */ + cx_write(AUD_I2SCNTL, 0x0); cx_clear(AUD_CTL, EN_I2SIN_ENABLE); + } + + /* The wm8775 module has the "2" route hardwired into + 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) { + struct v4l2_routing route; + + route.input = INPUT(input).audioroute; + cx88_call_i2c_clients(core, + VIDIOC_INT_S_AUDIO_ROUTING, &route); + + } + } + return 0; } EXPORT_SYMBOL(cx88_video_mux); @@ -486,7 +514,7 @@ static int restart_video_queue(struct cx8800_dev *dev, if (NULL == prev) { list_move_tail(&buf->vb.queue, &q->active); start_video_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] restart_queue - first active\n", @@ -496,7 +524,7 @@ static int restart_video_queue(struct cx8800_dev *dev, prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_move_tail(&buf->vb.queue, &q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] restart_queue - move to active\n", @@ -553,7 +581,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, init_buffer = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { init_buffer = 1; if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL))) goto fail; @@ -601,7 +629,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, fh->width, fh->height, fh->fmt->depth, fh->fmt->name, (unsigned long)buf->risc.dma); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: @@ -625,14 +653,14 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) if (!list_empty(&q->queued)) { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue,&q->active); start_video_dma(dev, q, buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); dprintk(2,"[%p/%d] buffer_queue - first active\n", @@ -644,7 +672,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_add_tail(&buf->vb.queue,&q->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", @@ -652,7 +680,7 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else { list_add_tail(&buf->vb.queue,&q->queued); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; dprintk(2,"[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } @@ -822,8 +850,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; } poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == STATE_DONE || - buf->vb.state == STATE_ERROR) + if (buf->vb.state == VIDEOBUF_DONE || + buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -1496,7 +1524,7 @@ static void cx8800_vid_timeout(unsigned long data) while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index eb296bdecb1e..4e823f2a539a 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -210,6 +210,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TE_DTV_250_OEM_SWANN 55 #define CX88_BOARD_HAUPPAUGE_HVR1300 56 #define CX88_BOARD_ADSTECH_PTV_390 57 +#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -228,7 +229,7 @@ struct cx88_input { enum cx88_itype type; u32 gpio0, gpio1, gpio2, gpio3; unsigned int vmux:2; - unsigned int extadc:1; + unsigned int audioroute:2; }; struct cx88_board { @@ -461,6 +462,7 @@ struct cx8802_dev { u32 mailbox; int width; int height; + unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ /* mpeg params */ struct cx2341x_mpeg_params params; @@ -588,6 +590,7 @@ extern void cx88_call_i2c_clients(struct cx88_core *core, /* ----------------------------------------------------------- */ /* cx88-cards.c */ +extern int cx88_tuner_callback(void *dev, int command, int arg); extern int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci); extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); @@ -633,12 +636,6 @@ int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev, void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); void cx8802_cancel_buffers(struct cx8802_dev *dev); -int cx8802_init_common(struct cx8802_dev *dev); -void cx8802_fini_common(struct cx8802_dev *dev); - -int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state); -int cx8802_resume_common(struct pci_dev *pci_dev); - /* ----------------------------------------------------------- */ /* cx88-video.c*/ extern const u32 cx88_user_ctrls[]; diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c index 255dae303708..566e479e2629 100644 --- a/drivers/media/video/dpc7146.c +++ b/drivers/media/video/dpc7146.c @@ -87,11 +87,24 @@ struct dpc int cur_input; /* current input */ }; +static int dpc_check_clients(struct device *dev, void *data) +{ + struct dpc* dpc = data; + struct i2c_client *client = i2c_verify_client(dev); + + if( !client ) + return 0; + + if( I2C_SAA7111A == client->addr ) + dpc->saa7111a = client; + + return 0; +} + /* fixme: add vbi stuff here */ static int dpc_probe(struct saa7146_dev* dev) { struct dpc* dpc = NULL; - struct i2c_client *client; dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL); if( NULL == dpc ) { @@ -115,9 +128,7 @@ static int dpc_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each_entry(client, &dpc->i2c_adapter.clients, list) - if( I2C_SAA7111A == client->addr ) - dpc->saa7111a = client; + device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients); /* check if all devices are present */ if( 0 == dpc->saa7111a ) { diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index c1127802ad9c..abbd38c1ebba 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,6 +1,6 @@ config VIDEO_EM28XX tristate "Empia EM2800/2820/2840 USB video capture support" - depends on VIDEO_V4L1 && I2C && INPUT + depends on VIDEO_DEV && I2C && INPUT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR @@ -11,3 +11,18 @@ config VIDEO_EM28XX To compile this driver as a module, choose M here: the module will be called em28xx + +config VIDEO_EM28XX_ALSA + depends on VIDEO_EM28XX + tristate "Empia EM28xx ALSA audio module" + ---help--- + This is an ALSA driver for some Empia 28xx based TV cards. + + This is not required for em2800/em2820/em2821 boards. However, + newer em28xx devices uses Vendor Class for audio, instead of + implementing the USB Audio Class. For those chips, this module + will enable digital audio. + + To compile this driver as a module, choose M here: the + module will be called em28xx-alsa + diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 826d0e340753..0924550992d0 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -1,6 +1,12 @@ em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ em28xx-input.o +em28xx-alsa-objs := em28xx-audio.o + obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o +obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c new file mode 100644 index 000000000000..941357c4f3f5 --- /dev/null +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -0,0 +1,489 @@ +/* + * Empiatech em28x1 audio extension + * + * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> + * + * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org> + * - Port to work with the in-kernel driver + * - Several cleanups + * + * This driver is based on my previous au600 usb pstn audio driver + * and inherits all the copyrights + * + * 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 <linux/kernel.h> +#include <linux/usb.h> +#include <linux/init.h> +#include <linux/sound.h> +#include <linux/spinlock.h> +#include <linux/soundcard.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/proc_fs.h> +#include <linux/module.h> +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/info.h> +#include <sound/initval.h> +#include <sound/control.h> +#include <media/v4l2-common.h> +#include "em28xx.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_INFO "em28xx-audio %s: " fmt, \ + __FUNCTION__, ##arg); \ + } while (0) + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; + +static int em28xx_isoc_audio_deinit(struct em28xx *dev) +{ + int i; + + dprintk("Stopping isoc\n"); + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + usb_kill_urb(dev->adev->urb[i]); + usb_free_urb(dev->adev->urb[i]); + dev->adev->urb[i] = NULL; + } + + return 0; +} + +static void em28xx_audio_isocirq(struct urb *urb) +{ + struct em28xx *dev = urb->context; + int i; + unsigned int oldptr; + unsigned long flags; + int period_elapsed = 0; + int status; + unsigned char *cp; + unsigned int stride; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + if (dev->adev->capture_pcm_substream) { + substream = dev->adev->capture_pcm_substream; + runtime = substream->runtime; + stride = runtime->frame_bits >> 3; + + for (i = 0; i < urb->number_of_packets; i++) { + int length = + urb->iso_frame_desc[i].actual_length / stride; + cp = (unsigned char *)urb->transfer_buffer + + urb->iso_frame_desc[i].offset; + + if (!length) + continue; + + spin_lock_irqsave(&dev->adev->slock, flags); + + oldptr = dev->adev->hwptr_done_capture; + dev->adev->hwptr_done_capture += length; + if (dev->adev->hwptr_done_capture >= + runtime->buffer_size) + dev->adev->hwptr_done_capture -= + runtime->buffer_size; + + dev->adev->capture_transfer_done += length; + if (dev->adev->capture_transfer_done >= + runtime->period_size) { + dev->adev->capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + + spin_unlock_irqrestore(&dev->adev->slock, flags); + + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = + runtime->buffer_size - oldptr - 1; + memcpy(runtime->dma_area + oldptr * stride, cp, + cnt * stride); + memcpy(runtime->dma_area, cp + cnt, + length * stride - cnt * stride); + } else { + memcpy(runtime->dma_area + oldptr * stride, cp, + length * stride); + } + } + if (period_elapsed) + snd_pcm_period_elapsed(substream); + } + urb->status = 0; + + if (dev->adev->shutdown) + return; + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + em28xx_errdev("resubmit of audio urb failed (error=%i)\n", + status); + } + return; +} + +static int em28xx_init_audio_isoc(struct em28xx *dev) +{ + int i, errCode; + const int sb_size = EM28XX_NUM_AUDIO_PACKETS * + EM28XX_AUDIO_MAX_PACKET_SIZE; + + dprintk("Starting isoc transfers\n"); + + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + struct urb *urb; + int j, k; + + dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); + if (!dev->adev->transfer_buffer[i]) + return -ENOMEM; + + memset(dev->adev->transfer_buffer[i], 0x80, sb_size); + urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + + urb->dev = dev->udev; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->adev->transfer_buffer[i]; + urb->interval = 1; + urb->complete = em28xx_audio_isocirq; + urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; + urb->transfer_buffer_length = sb_size; + + for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; + j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { + urb->iso_frame_desc[j].offset = k; + urb->iso_frame_desc[j].length = + EM28XX_AUDIO_MAX_PACKET_SIZE; + } + dev->adev->urb[i] = urb; + } + + for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { + errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC); + if (errCode) { + em28xx_isoc_audio_deinit(dev); + + return errCode; + } + } + + return 0; +} + +static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) +{ + dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)? + "stop" : "start"); + + switch (cmd) { + case EM28XX_CAPTURE_STREAM_EN: + if (dev->adev->capture_stream == STREAM_OFF && arg == 1) { + dev->adev->capture_stream = STREAM_ON; + em28xx_init_audio_isoc(dev); + } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) { + dev->adev->capture_stream = STREAM_OFF; + em28xx_isoc_audio_deinit(dev); + } else { + printk(KERN_ERR "An underrun very likely occurred. " + "Ignoring it.\n"); + } + return 0; + default: + return -EINVAL; + } +} + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Alocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static struct snd_pcm_hardware snd_em28xx_hw_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ + .period_bytes_min = 64, /* 12544/2, */ + .period_bytes_max = 12544, + .periods_min = 2, + .periods_max = 98, /* 12544, */ +}; + +static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret = 0; + + dprintk("opening device and trying to acquire exclusive lock\n"); + + /* Sets volume, mute, etc */ + dev->mute = 0; + ret = em28xx_audio_analog_set(dev); + if (ret < 0) + goto err; + + runtime->hw = snd_em28xx_hw_capture; + if (dev->alt == 0 && dev->adev->users == 0) { + int errCode; + dev->alt = 7; + errCode = usb_set_interface(dev->udev, 0, 7); + dprintk("changing alternate number to 7\n"); + } + + dev->adev->users++; + + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + dev->adev->capture_pcm_substream = substream; + runtime->private_data = dev; + + return 0; +err: + printk(KERN_ERR "Error while configuring em28xx mixer\n"); + return ret; +} + +static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + dev->adev->users--; + + dprintk("closing device\n"); + + dev->mute = 1; + em28xx_audio_analog_set(dev); + + if (dev->adev->users == 0 && dev->adev->shutdown == 1) { + dprintk("audio users: %d\n", dev->adev->users); + dprintk("disabling audio stream!\n"); + dev->adev->shutdown = 0; + dprintk("released lock\n"); + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); + } + return 0; +} + +static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + unsigned int channels, rate, format; + int ret; + + dprintk("Setting capture parameters\n"); + + ret = snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + format = params_format(hw_params); + rate = params_rate(hw_params); + channels = params_channels(hw_params); + + /* TODO: set up em28xx audio chip to deliver the correct audio format, + current default is 48000hz multiplexed => 96000hz mono + which shouldn't matter since analogue TV only supports mono */ + return 0; +} + +static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dprintk("Stop capture, if needed\n"); + + if (dev->adev->capture_stream == STREAM_ON) + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); + + return 0; +} + +static int snd_em28xx_prepare(struct snd_pcm_substream *substream) +{ + return 0; +} + +static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct em28xx *dev = snd_pcm_substream_chip(substream); + + dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)? + "start": "stop"); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); + return 0; + case SNDRV_PCM_TRIGGER_STOP: + dev->adev->shutdown = 1; + return 0; + default: + return -EINVAL; + } +} + +static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream + *substream) +{ + struct em28xx *dev; + + snd_pcm_uframes_t hwptr_done; + dev = snd_pcm_substream_chip(substream); + hwptr_done = dev->adev->hwptr_done_capture; + + return hwptr_done; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +static struct snd_pcm_ops snd_em28xx_pcm_capture = { + .open = snd_em28xx_capture_open, + .close = snd_em28xx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_em28xx_hw_capture_params, + .hw_free = snd_em28xx_hw_capture_free, + .prepare = snd_em28xx_prepare, + .trigger = snd_em28xx_capture_trigger, + .pointer = snd_em28xx_capture_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static int em28xx_audio_init(struct em28xx *dev) +{ + struct em28xx_audio *adev; + struct snd_pcm *pcm; + struct snd_card *card; + static int devnr; + int ret, err; + + printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " + "non standard usbaudio\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " + "Rechberger\n"); + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) { + printk(KERN_ERR "em28xx-audio.c: out of memory\n"); + return -1; + } + card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0); + if (card == NULL) { + kfree(adev); + return -ENOMEM; + } + + spin_lock_init(&adev->slock); + ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); + pcm->info_flags = 0; + pcm->private_data = dev; + strcpy(pcm->name, "Empia 28xx Capture"); + strcpy(card->driver, "Empia Em28xx Audio"); + strcpy(card->shortname, "Em28xx Audio"); + strcpy(card->longname, "Empia Em28xx Audio"); + + err = snd_card_register(card); + if (err < 0) { + snd_card_free(card); + return -ENOMEM; + } + adev->sndcard = card; + adev->udev = dev->udev; + dev->adev = adev; + + return 0; +} + +static int em28xx_audio_fini(struct em28xx *dev) +{ + if (dev == NULL) + return 0; + + if (dev->adev) { + snd_card_free(dev->adev->sndcard); + kfree(dev->adev); + dev->adev = NULL; + } + + return 0; +} + +static struct em28xx_ops audio_ops = { + .id = EM28XX_AUDIO, + .name = "Em28xx Audio Extension", + .init = em28xx_audio_init, + .fini = em28xx_audio_fini, +}; + +static int __init em28xx_alsa_register(void) +{ + return em28xx_register_extension(&audio_ops); +} + +static void __exit em28xx_alsa_unregister(void) +{ + em28xx_unregister_extension(&audio_ops); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); +MODULE_DESCRIPTION("Em28xx Audio driver"); + +module_init(em28xx_alsa_register); +module_exit(em28xx_alsa_unregister); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 418ea8b7f85a..2159d0160df2 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1,5 +1,6 @@ /* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB video capture devices + em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB + video capture devices Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> Markus Rechberger <mrechberger@gmail.com> @@ -35,294 +36,735 @@ #include <media/v4l2-common.h> #include "em28xx.h" +#include "tuner-xc2028.h" + +static int tuner = -1; +module_param(tuner, int, 0444); +MODULE_PARM_DESC(tuner, "tuner type"); + +static unsigned int disable_ir; +module_param(disable_ir, int, 0444); +MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); + +struct em28xx_hash_table { + unsigned long hash; + unsigned int model; + unsigned int tuner; +}; + +/* Boards supported by driver */ + +#define EM2800_BOARD_UNKNOWN 0 +#define EM2820_BOARD_UNKNOWN 1 +#define EM2820_BOARD_TERRATEC_CINERGY_250 2 +#define EM2820_BOARD_PINNACLE_USB_2 3 +#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 +#define EM2820_BOARD_MSI_VOX_USB_2 5 +#define EM2800_BOARD_TERRATEC_CINERGY_200 6 +#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 +#define EM2800_BOARD_KWORLD_USB2800 8 +#define EM2820_BOARD_PINNACLE_DVC_90 9 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 +#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 +#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 +#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 struct em28xx_board em28xx_boards[] = { [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", .is_em2800 = 1, .vchannels = 2, - .norm = VIDEO_MODE_PAL, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2820/2840 video grabber", + .name = "Unknown EM2750/28xx video grabber", .is_em2800 = 0, - .vchannels = 2, - .norm = VIDEO_MODE_PAL, - .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, - .decoder = EM28XX_SAA7113, - .input = {{ - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - },{ - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - }}, + .tuner_type = TUNER_ABSENT, }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, .vchannels = 2, - .norm = VIDEO_MODE_PAL, + .tuner_type = TUNER_TEMIC_PAL, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .input = { { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, .amux = 1, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, .amux = 1, - }}, + } }, }, [EM2820_BOARD_TERRATEC_CINERGY_250] = { .name = "Terratec Cinergy 250 USB", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .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] = { .name = "Pinnacle PCTV USB 2", .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .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_HAUPPAUGE_WINTV_USB_2] = { .name = "Hauppauge WinTV USB 2", .vchannels = 3, - .norm = VIDEO_MODE_NTSC, .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, - .has_tuner = 1, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE| + TDA9887_PORT2_ACTIVE, .decoder = EM28XX_TVP5150, .has_msp34xx = 1, /*FIXME: S-Video not tested */ - .input = {{ + .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, .amux = MSP_INPUT_DEFAULT, - },{ + }, { .type = EM28XX_VMUX_SVIDEO, .vmux = TVP5150_SVIDEO, .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), - }}, + } }, }, - [EM2820_BOARD_MSI_VOX_USB_2] = { - .name = "MSI VOX USB 2.0", - .vchannels = 3, - .norm = VIDEO_MODE_PAL, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT|TDA9887_PORT1_ACTIVE|TDA9887_PORT2_ACTIVE, - .has_tuner = 1, - .decoder = EM28XX_SAA7114, - .input = {{ + [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { + .name = "Hauppauge WinTV HVR 900", + .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, + .decoder = EM28XX_TVP5150, + .input = { { .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, + .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, - }}, + } }, + + /* gpio's 4, 1, 0 */ + .analog_gpio = 0x003d2d, + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid 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, + } }, + }, + /* 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, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .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_LEADTEK_WINFAST_USBII] = { .name = "Leadtek Winfast USB II", .is_em2800 = 1, .vchannels = 3, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_LG_PAL_NEW_TAPC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .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, - .norm = VIDEO_MODE_PAL, .tuner_type = TUNER_PHILIPS_ATSC, .tda9887_conf = TDA9887_PRESENT, - .has_tuner = 1, .decoder = EM28XX_SAA7113, - .input = {{ + .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", + .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, - .norm = VIDEO_MODE_PAL, - .has_tuner = 0, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_YMEC_TVF_5533MF, .decoder = EM28XX_SAA7113, - .input = {{ + .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, - }}, + } }, }, }; 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, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), .driver_info = EM2820_BOARD_MSI_VOX_USB_2 }, - { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x2304, 0x0208), .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, - { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2304, 0x0207), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0xeb1a, 0x2750), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2800), + .driver_info = EM2800_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2820), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2821), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2860), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2861), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2870), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2881), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2883), + .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0x0ccd, 0x0036), + .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, + { USB_DEVICE(0x2304, 0x0208), + .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { 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(0x2040, 0x6500), + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6513), + .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 }, { }, }; +MODULE_DEVICE_TABLE(usb, em28xx_id_table); + +/* EEPROM hash table for devices with generic USB IDs */ +static struct em28xx_hash_table em28xx_eeprom_hash [] = { + /* P/N: SA 60002070465 Tuner: TVF7533-MF */ + {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, +}; + +/* I2C devicelist hash table for devices with generic USB IDs */ +static struct em28xx_hash_table em28xx_i2c_hash[] = { + {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, + {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, +}; +/* Since em28xx_pre_card_setup() requires a proper dev->model, + * this won't work for boards with generic PCI IDs + */ void em28xx_pre_card_setup(struct em28xx *dev) { /* request some modules */ - switch(dev->model){ - case EM2880_BOARD_TERRATEC_PRODIGY_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - { - em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? - break; + switch (dev->model) { + case EM2880_BOARD_TERRATEC_PRODIGY_XS: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + em28xx_write_regs(dev, XCLK_REG, "\x27", 1); + em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1); + em28xx_write_regs(dev, 0x08, "\xff", 1); + em28xx_write_regs(dev, 0x04, "\x00", 1); + msleep(100); + em28xx_write_regs(dev, 0x04, "\x08", 1); + msleep(100); + em28xx_write_regs(dev, 0x08, "\xff", 1); + msleep(50); + em28xx_write_regs(dev, 0x08, "\x2d", 1); + msleep(50); + em28xx_write_regs(dev, 0x08, "\x3d", 1); + break; + } +} + +static int em28xx_tuner_callback(void *ptr, int command, int arg) +{ + int rc = 0; + struct em28xx *dev = ptr; + + if (dev->tuner_type != TUNER_XC2028) + return 0; + + switch (command) { + case XC2028_TUNER_RESET: + { + /* GPIO and initialization codes for analog TV and radio + This code should be complemented for DTV, since reset + codes are different. + */ + + dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); + dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); + + if (dev->analog_gpio) { + char gpio0 = dev->analog_gpio & 0xff; + char gpio1 = (dev->analog_gpio >> 8) & 0xff; + char gpio4 = dev->analog_gpio >> 24; + + if (gpio4) { + dev->em28xx_write_regs(dev, 0x04, &gpio4, 1); + msleep(140); } + + msleep(6); + dev->em28xx_write_regs(dev, 0x08, &gpio0, 1); + msleep(10); + dev->em28xx_write_regs(dev, 0x08, &gpio1, 1); + msleep(5); + } + + break; + } + } + return rc; +} + +static void em28xx_config_tuner(struct em28xx *dev) +{ + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + struct tuner_setup tun_setup; + struct v4l2_frequency f; + + if (dev->tuner_type == TUNER_ABSENT) + return; + + tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.tuner_callback = em28xx_tuner_callback; + + em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + + if (dev->tuner_type == TUNER_XC2028) { + memset(&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + ctl.mts = em28xx_boards[dev->model].mts_firmware; + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } + + /* configure tuner */ + f.tuner = 0; + f.type = V4L2_TUNER_ANALOG_TV; + f.frequency = 9076; /* just a magic number */ + dev->ctl_freq = f.frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); +} + +static int em28xx_hint_board(struct em28xx *dev) +{ + int i; + + /* HINT method: EEPROM + * + * This method works only for boards with eeprom. + * Uses a hash of all eeprom bytes. The hash should be + * unique for a vendor/tuner pair. + * There are a high chance that tuners for different + * video standards produce different hashes. + */ + for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { + if (dev->hash == em28xx_eeprom_hash[i].hash) { + dev->model = em28xx_eeprom_hash[i].model; + dev->tuner_type = em28xx_eeprom_hash[i].tuner; + + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on eeprom hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " <video4linux-list@redhat.com>\n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + + /* HINT method: I2C attached devices + * + * This method works for all boards. + * Uses a hash of i2c scanned devices. + * Devices with the same i2c attached chips will + * be considered equal. + * This method is less precise than the eeprom one. + */ + + /* user did not request i2c scanning => do it now */ + if (!dev->i2c_hash) + em28xx_do_i2c_scan(dev); + + for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { + if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { + dev->model = em28xx_i2c_hash[i].model; + dev->tuner_type = em28xx_i2c_hash[i].tuner; + em28xx_errdev("Your board has no unique USB ID.\n"); + em28xx_errdev("A hint were successfully done, " + "based on i2c devicelist hash.\n"); + em28xx_errdev("This method is not 100%% failproof.\n"); + em28xx_errdev("If the board were missdetected, " + "please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List " + " <video4linux-list@redhat.com>\n"); + em28xx_errdev("Board detected as %s\n", + em28xx_boards[dev->model].name); + + return 0; + } + } + + em28xx_errdev("Your board has no unique USB ID and thus need a " + "hint to be detected.\n"); + em28xx_errdev("You may try to use card=<n> insmod option to " + "workaround that.\n"); + em28xx_errdev("Please send an email with this log to:\n"); + em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n"); + em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); + em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); + + em28xx_errdev("Here is a list of valid choices for the card=<n>" + " insmod option:\n"); + for (i = 0; i < em28xx_bcount; i++) { + em28xx_errdev(" card=%d -> %s\n", + i, em28xx_boards[i].name); + } + return -1; +} + + +static void em28xx_set_model(struct em28xx *dev) +{ + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; + dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; + dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; + dev->decoder = em28xx_boards[dev->model].decoder; + dev->video_inputs = em28xx_boards[dev->model].vchannels; + dev->analog_gpio = em28xx_boards[dev->model].analog_gpio; + dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; + dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; +} + +/* ----------------------------------------------------------------------- */ +void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) +{ + if (disable_ir) { + ir->get_key = NULL; + return ; + } + + /* detect & configure */ + switch (dev->model) { + case (EM2800_BOARD_UNKNOWN): + break; + case (EM2820_BOARD_UNKNOWN): + break; + case (EM2800_BOARD_TERRATEC_CINERGY_200): + case (EM2820_BOARD_TERRATEC_CINERGY_250): + ir->ir_codes = ir_codes_em_terratec; + ir->get_key = em28xx_get_key_terratec; + snprintf(ir->c.name, sizeof(ir->c.name), + "i2c IR (EM28XX Terratec)"); + break; + case (EM2820_BOARD_PINNACLE_USB_2): + ir->ir_codes = ir_codes_pinnacle_grey; + ir->get_key = em28xx_get_key_pinnacle_usb_grey; + snprintf(ir->c.name, sizeof(ir->c.name), + "i2c IR (EM28XX Pinnacle PCTV)"); + break; + case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): + ir->ir_codes = ir_codes_hauppauge_new; + ir->get_key = em28xx_get_key_em_haup; + snprintf(ir->c.name, sizeof(ir->c.name), + "i2c IR (EM2840 Hauppauge)"); + break; + case (EM2820_BOARD_MSI_VOX_USB_2): + break; + case (EM2800_BOARD_LEADTEK_WINFAST_USBII): + break; + case (EM2800_BOARD_KWORLD_USB2800): + break; } } void em28xx_card_setup(struct em28xx *dev) { + em28xx_set_model(dev); + + dev->tuner_type = em28xx_boards[dev->model].tuner_type; + /* request some modules */ - switch(dev->model){ - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - { - struct tveeprom tv; + switch (dev->model) { + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + { + struct tveeprom tv; #ifdef CONFIG_MODULES - request_module("tveeprom"); - request_module("ir-kbd-i2c"); - request_module("msp3400"); + request_module("tveeprom"); #endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type= tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { - dev->i2s_speed=2048000; - dev->has_msp34xx=1; - } else - dev->has_msp34xx=0; - break; - } - case EM2820_BOARD_KWORLD_PVRTV2800RF: - { - em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF - break; - } + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + dev->tuner_type = tv.tuner_type; + + if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed = 2048000; + dev->has_msp34xx = 1; + } +#ifdef CONFIG_MODULES + if (tv.has_ir) + request_module("ir-kbd-i2c"); +#endif + break; + } + case EM2820_BOARD_KWORLD_PVRTV2800RF: + /* GPIO enables sound on KWORLD PVR TV 2800RF */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); + break; + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: + if (!em28xx_hint_board(dev)) + em28xx_set_model(dev); } -} -MODULE_DEVICE_TABLE (usb, em28xx_id_table); + /* Allow override tuner type by a module parameter */ + if (tuner >= 0) + dev->tuner_type = tuner; + +#ifdef CONFIG_MODULES + /* request some modules */ + if (dev->has_msp34xx) + request_module("msp3400"); + if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) + request_module("saa7115"); + if (dev->decoder == EM28XX_TVP5150) + request_module("tvp5150"); + if (dev->tuner_type != TUNER_ABSENT) + request_module("tuner"); +#endif + + em28xx_config_tuner(dev); +} diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index d56484f20467..f6b78357f0e5 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -252,7 +252,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, * em28xx_write_ac97() * write a 16 bit value to the specified AC97 address (LSB first!) */ -int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val) +static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) { int ret; u8 addr = reg & 0x7f; @@ -268,16 +268,98 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val) return 0; } +int em28xx_set_audio_source(struct em28xx *dev) +{ + static char *enable = "\x08\x08"; + static char *disable = "\x08\x88"; + char *video = enable, *line = disable; + int ret, no_ac97; + u8 input; + + if (dev->is_em2800) { + if (dev->ctl_ainput) + input = EM2800_AUDIO_SRC_LINE; + else + input = EM2800_AUDIO_SRC_TUNER; + + ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1); + if (ret < 0) + return ret; + } + + if (dev->has_msp34xx) + input = EM28XX_AUDIO_SRC_TUNER; + else { + switch (dev->ctl_ainput) { + case EM28XX_AMUX_VIDEO: + input = EM28XX_AUDIO_SRC_TUNER; + no_ac97 = 1; + break; + case EM28XX_AMUX_LINE_IN: + input = EM28XX_AUDIO_SRC_LINE; + no_ac97 = 1; + break; + case EM28XX_AMUX_AC97_VIDEO: + input = EM28XX_AUDIO_SRC_LINE; + break; + case EM28XX_AMUX_AC97_LINE_IN: + input = EM28XX_AUDIO_SRC_LINE; + video = disable; + line = enable; + break; + } + } + + ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); + if (ret < 0) + return ret; + + if (no_ac97) + return 0; + + /* Sets AC97 mixer registers */ + + ret = em28xx_write_ac97(dev, VIDEO_AC97, video); + if (ret < 0) + return ret; + + ret = em28xx_write_ac97(dev, LINE_IN_AC97, line); + + return ret; +} + int em28xx_audio_analog_set(struct em28xx *dev) { + int ret; char s[2] = { 0x00, 0x00 }; + u8 xclk = 0x07; + s[0] |= 0x1f - dev->volume; s[1] |= 0x1f - dev->volume; + if (dev->mute) s[1] |= 0x80; - return em28xx_write_ac97(dev, MASTER_AC97, s); -} + ret = em28xx_write_ac97(dev, MASTER_AC97, s); + if (ret < 0) + return ret; + + if (dev->has_12mhz_i2s) + xclk |= 0x20; + + if (!dev->mute) + xclk |= 0x80; + ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7); + if (ret < 0) + return ret; + msleep(10); + + /* Selects the proper audio input */ + ret = em28xx_set_audio_source(dev); + + return ret; +} +EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); int em28xx_colorlevels_set_default(struct em28xx *dev) { diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index e3a4aa7a9df4..cacd04d46e99 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -25,9 +25,9 @@ #include <linux/kernel.h> #include <linux/usb.h> #include <linux/i2c.h> -#include <linux/video_decoder.h> #include "em28xx.h" +#include "tuner-xc2028.h" #include <media/v4l2-common.h> #include <media/tuner.h> @@ -291,6 +291,31 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return rc; } +/* based on linux/sunrpc/svcauth.h and linux/hash.h + * The original hash function returns a different value, if arch is x86_64 + * or i386. + */ +static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) +{ + unsigned long hash = 0; + unsigned long l = 0; + int len = 0; + unsigned char c; + do { + if (len == length) { + c = (char)len; + len = -1; + } else + c = *buf++; + l = (l << 8) | c; + len++; + if ((len & (32 / 8 - 1)) == 0) + hash = ((hash^l) * 0x9e370001UL); + } while (len); + + return (hash >> (32 - bits)) & 0xffffffffUL; +} + static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { unsigned char buf, *p = eedata; @@ -334,7 +359,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) printk("\n"); } - printk(KERN_INFO "EEPROM ID= 0x%08x\n", em_eeprom->id); + if (em_eeprom->id == 0x9567eb1a) + dev->hash = em28xx_hash_mem(eedata, len, 32); + + printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n", + em_eeprom->id, dev->hash); printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, em_eeprom->product_ID); @@ -391,21 +420,6 @@ static u32 functionality(struct i2c_adapter *adap) } -static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - struct tuner_setup tun_setup; - - if (dev->has_tuner) { - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - } - - return (0); -} - /* * attach_inform() * gets called when a device attaches to the i2c bus @@ -421,6 +435,8 @@ static int attach_inform(struct i2c_client *client) case 0x96: case 0x94: { + struct v4l2_priv_tun_config tda9887_cfg; + struct tuner_setup tun_setup; tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; @@ -428,7 +444,11 @@ static int attach_inform(struct i2c_client *client) tun_setup.addr = client->addr; em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf); + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); break; } case 0x42: @@ -458,9 +478,11 @@ static int attach_inform(struct i2c_client *client) break; default: + if (!dev->tuner_addr) + dev->tuner_addr = client->addr; + dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1); - dev->tuner_addr = client->addr; - em28xx_set_tuner(-1, client); + } return 0; @@ -510,19 +532,26 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -static void do_i2c_scan(char *name, struct i2c_client *c) +void em28xx_do_i2c_scan(struct em28xx *dev) { + u8 i2c_devicelist[128]; unsigned char buf; int i, rc; + memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); + for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - c->addr = i; - rc = i2c_master_recv(c, &buf, 0); + dev->i2c_client.addr = i; + rc = i2c_master_recv(&dev->i2c_client, &buf, 0); if (rc < 0) continue; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", name, - i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + i2c_devicelist[i] = i; + printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", + dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } + + dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, + ARRAY_SIZE(i2c_devicelist), 32); } /* @@ -555,7 +584,7 @@ int em28xx_i2c_register(struct em28xx *dev) em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); if (i2c_scan) - do_i2c_scan(dev->name, &dev->i2c_client); + em28xx_do_i2c_scan(dev); return 0; } diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index e3894b68c4ee..10da2fd8d987 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -30,11 +30,7 @@ #include "em28xx.h" -static unsigned int disable_ir = 0; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir,"disable infrared remote support"); - -static unsigned int ir_debug = 0; +static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); @@ -43,7 +39,7 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); /* ----------------------------------------------------------------------- */ -static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char b; @@ -72,7 +68,7 @@ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) } -static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[2]; unsigned char code; @@ -103,7 +99,8 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } -static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw) { unsigned char buf[3]; @@ -125,45 +122,6 @@ static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw return 1; } -/* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir) -{ - if (disable_ir) { - ir->get_key=NULL; - return ; - } - - /* detect & configure */ - switch (dev->model) { - case (EM2800_BOARD_UNKNOWN): - break; - case (EM2820_BOARD_UNKNOWN): - break; - case (EM2800_BOARD_TERRATEC_CINERGY_200): - case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)"); - break; - case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)"); - break; - case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM2840 Hauppauge)"); - break; - case (EM2820_BOARD_MSI_VOX_USB_2): - break; - case (EM2800_BOARD_LEADTEK_WINFAST_USBII): - break; - case (EM2800_BOARD_KWORLD_USB2800): - break; - } -} - /* ---------------------------------------------------------------------- * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 0906bc5766cc..a0c334672488 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -33,13 +33,12 @@ #include <linux/i2c.h> #include <linux/version.h> #include <linux/mm.h> -#include <linux/video_decoder.h> #include <linux/mutex.h> #include "em28xx.h" -#include <media/tuner.h> #include <media/v4l2-common.h> #include <media/msp3400.h> +#include <media/tuner.h> #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ "Markus Rechberger <mrechberger@gmail.com>, " \ @@ -48,7 +47,7 @@ #define DRIVER_NAME "em28xx" #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 0, 1) +#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0) #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ @@ -63,17 +62,17 @@ static LIST_HEAD(em28xx_devlist); static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; + module_param_array(card, int, NULL, 0444); module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -MODULE_PARM_DESC(card,"card type"); -MODULE_PARM_DESC(video_nr,"video device numbers"); -MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); - -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); +module_param_array(radio_nr, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug = 0; module_param(video_debug,int,0644); @@ -82,29 +81,6 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ static unsigned long em28xx_devused; -/* supported tv norms */ -static struct em28xx_tvnorm tvnorms[] = { - { - .name = "PAL", - .id = V4L2_STD_PAL, - .mode = VIDEO_MODE_PAL, - }, { - .name = "NTSC", - .id = V4L2_STD_NTSC, - .mode = VIDEO_MODE_NTSC, - }, { - .name = "SECAM", - .id = V4L2_STD_SECAM, - .mode = VIDEO_MODE_SECAM, - }, { - .name = "PAL-M", - .id = V4L2_STD_PAL_M, - .mode = VIDEO_MODE_PAL, - } -}; - -#define TVNORMS ARRAY_SIZE(tvnorms) - /* supported controls */ /* Common to all boards */ static struct v4l2_queryctrl em28xx_qctrl[] = { @@ -131,8 +107,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { static struct usb_driver em28xx_usb_driver; -static DEFINE_MUTEX(em28xx_sysfs_lock); -static DECLARE_RWSEM(em28xx_disconnect); /********************* v4l2 interface ******************************************/ @@ -153,11 +127,9 @@ static int em28xx_config(struct em28xx *dev) /* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */ em28xx_write_regs_req(dev,0x00,0x11,"\x51",1); - em28xx_audio_usb_mute(dev, 1); dev->mute = 1; /* maybe not the right place... */ dev->volume = 0x1f; - em28xx_audio_analog_set(dev); - em28xx_audio_analog_setup(dev); + em28xx_outfmt_set_yuv422(dev); em28xx_colorlevels_set_default(dev); em28xx_compression_disable(dev); @@ -171,7 +143,6 @@ static int em28xx_config(struct em28xx *dev) */ static void em28xx_config_i2c(struct em28xx *dev) { - struct v4l2_frequency f; struct v4l2_routing route; route.input = INPUT(dev->ctl_input)->vmux; @@ -179,18 +150,6 @@ static void em28xx_config_i2c(struct em28xx *dev) em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* FIXME:remove magic number */ - dev->ctl_freq = f.frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); - - /* configure tda9887 */ - - -/* em28xx_i2c_call_clients(dev,VIDIOC_S_STD,&dev->tvnorm->id); */ } /* @@ -212,7 +171,6 @@ static void em28xx_empty_framequeues(struct em28xx *dev) static void video_mux(struct em28xx *dev, int index) { - int ainput; struct v4l2_routing route; route.input = INPUT(index)->vmux; @@ -222,8 +180,6 @@ static void video_mux(struct em28xx *dev, int index) em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); - em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput); - if (dev->has_msp34xx) { if (dev->i2s_speed) em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); @@ -231,18 +187,1068 @@ static void video_mux(struct em28xx *dev, int index) route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); /* Note: this is msp3400 specific */ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route); - ainput = EM28XX_AUDIO_SRC_TUNER; - em28xx_audio_source(dev, ainput); + } + + em28xx_set_audio_source(dev); +} + +/* Usage lock check functions */ +static int res_get(struct em28xx_fh *fh) +{ + struct em28xx *dev = fh->dev; + int rc = 0; + + /* This instance already has stream_on */ + if (fh->stream_on) + return rc; + + mutex_lock(&dev->lock); + + if (dev->stream_on) + rc = -EINVAL; + else { + dev->stream_on = 1; + fh->stream_on = 1; + } + + mutex_unlock(&dev->lock); + return rc; +} + +static int res_check(struct em28xx_fh *fh) +{ + return (fh->stream_on); +} + +static void res_free(struct em28xx_fh *fh) +{ + struct em28xx *dev = fh->dev; + + mutex_lock(&dev->lock); + fh->stream_on = 0; + dev->stream_on = 0; + mutex_unlock(&dev->lock); +} + +/* + * em28xx_vm_open() + */ +static void em28xx_vm_open(struct vm_area_struct *vma) +{ + struct em28xx_frame_t *f = vma->vm_private_data; + f->vma_use_count++; +} + +/* + * em28xx_vm_close() + */ +static void em28xx_vm_close(struct vm_area_struct *vma) +{ + /* NOTE: buffers are not freed here */ + struct em28xx_frame_t *f = vma->vm_private_data; + + if (f->vma_use_count) + f->vma_use_count--; +} + +static struct vm_operations_struct em28xx_vm_ops = { + .open = em28xx_vm_open, + .close = em28xx_vm_close, +}; + + +/* + * em28xx_get_ctrl() + * return the current saturation, brightness or contrast, mute state + */ +static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->mute; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = dev->volume; + return 0; + default: + return -EINVAL; + } +} + +/* + * em28xx_set_ctrl() + * mute or set new saturation, brightness or contrast + */ +static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value != dev->mute) { + dev->mute = ctrl->value; + return em28xx_audio_analog_set(dev); + } + return 0; + case V4L2_CID_AUDIO_VOLUME: + dev->volume = ctrl->value; + return em28xx_audio_analog_set(dev); + default: + return -EINVAL; + } +} + +/* + * em28xx_stream_interrupt() + * stops streaming + */ +static int em28xx_stream_interrupt(struct em28xx *dev) +{ + int rc = 0; + + /* stop reading from the device */ + + dev->stream = STREAM_INTERRUPT; + rc = wait_event_timeout(dev->wait_stream, + (dev->stream == STREAM_OFF) || + (dev->state & DEV_DISCONNECTED), + EM28XX_URB_TIMEOUT); + + if (rc) { + dev->state |= DEV_MISCONFIGURED; + em28xx_videodbg("device is misconfigured; close and " + "open /dev/video%d again\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); + return rc; + } + + return 0; +} + + +static int check_dev(struct em28xx *dev) +{ + if (dev->state & DEV_DISCONNECTED) { + em28xx_errdev("v4l2 ioctl: device not present\n"); + return -ENODEV; + } + + if (dev->state & DEV_MISCONFIGURED) { + em28xx_errdev("v4l2 ioctl: device is misconfigured; " + "close and open it again\n"); + return -EIO; + } + return 0; +} + +static void get_scale(struct em28xx *dev, + unsigned int width, unsigned int height, + unsigned int *hscale, unsigned int *vscale) +{ + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + + *hscale = (((unsigned long)maxw) << 12) / width - 4096L; + if (*hscale >= 0x4000) + *hscale = 0x3fff; + + *vscale = (((unsigned long)maxh) << 12) / height - 4096L; + if (*vscale >= 0x4000) + *vscale = 0x3fff; +} + +/* ------------------------------------------------------------------ + IOCTL vidioc handling + ------------------------------------------------------------------*/ + +static int vidioc_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + mutex_lock(&dev->lock); + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + f->fmt.pix.bytesperline = dev->bytesperline; + f->fmt.pix.sizeimage = dev->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ + f->fmt.pix.field = dev->interlaced ? + V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int width = f->fmt.pix.width; + int height = f->fmt.pix.height; + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + unsigned int hscale, vscale; + + /* width must even because of the YUYV format + height must be even because of interlacing */ + height &= 0xfffe; + width &= 0xfffe; + + if (height < 32) + height = 32; + if (height > maxh) + height = maxh; + if (width < 48) + width = 48; + if (width > maxw) + width = maxw; + + mutex_lock(&dev->lock); + + if (dev->is_em2800) { + /* the em2800 can only scale down to 50% */ + if (height % (maxh / 2)) + height = maxh; + if (width % (maxw / 2)) + width = maxw; + /* according to empiatech support */ + /* the MaxPacketSize is to small to support */ + /* framesizes larger than 640x480 @ 30 fps */ + /* or 640x576 @ 25 fps. As this would cut */ + /* of a part of the image we prefer */ + /* 360x576 or 360x480 for now */ + if (width == maxw && height == maxh) + width /= 2; + } + + get_scale(dev, width, height, &hscale, &vscale); + + width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + + f->fmt.pix.width = width; + f->fmt.pix.height = height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + f->fmt.pix.bytesperline = width * 2; + f->fmt.pix.sizeimage = width * 2 * height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc, i; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + vidioc_try_fmt_cap(file, priv, f); + + mutex_lock(&dev->lock); + + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_S_FMT failed. " + "Unmap the buffers first.\n"); + rc = -EINVAL; + goto err; + } + + /* stop io in case it is already in progress */ + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) + goto err; + } + + em28xx_release_buffers(dev); + dev->io = IO_NONE; + + /* set new image size */ + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + + /* FIXME: This is really weird! Why capture is starting with + this ioctl ??? + */ + em28xx_uninit_isoc(dev); + em28xx_set_alternate(dev); + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + em28xx_init_isoc(dev); + rc = 0; + +err: + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + struct v4l2_format f; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + dev->norm = *norm; + mutex_unlock(&dev->lock); + + /* Adjusts width/height, if needed */ + f.fmt.pix.width = dev->width; + f.fmt.pix.height = dev->height; + vidioc_try_fmt_cap(file, priv, &f); + + mutex_lock(&dev->lock); + + /* set new image size */ + dev->width = f.fmt.pix.width; + dev->height = f.fmt.pix.height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + + em28xx_resolution_set(dev); + em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm); + + mutex_unlock(&dev->lock); + return 0; +} + +static const char *iname[] = { + [EM28XX_VMUX_COMPOSITE1] = "Composite1", + [EM28XX_VMUX_COMPOSITE2] = "Composite2", + [EM28XX_VMUX_COMPOSITE3] = "Composite3", + [EM28XX_VMUX_COMPOSITE4] = "Composite4", + [EM28XX_VMUX_SVIDEO] = "S-Video", + [EM28XX_VMUX_TELEVISION] = "Television", + [EM28XX_VMUX_CABLE] = "Cable TV", + [EM28XX_VMUX_DVB] = "DVB", + [EM28XX_VMUX_DEBUG] = "for debug only", +}; + +static int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int n; + + n = i->index; + if (n >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; + + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + + strcpy(i->name, iname[INPUT(n)->type]); + + if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || + (EM28XX_VMUX_CABLE == INPUT(n)->type)) + i->type = V4L2_INPUT_TYPE_TUNER; + + i->std = dev->vdev->tvnorms; + + return 0; +} + +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + *i = dev->ctl_input; + + return 0; +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (i >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(i)->type) + return -EINVAL; + + mutex_lock(&dev->lock); + + video_mux(dev, i); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned int index = a->index; + + if (a->index > 1) + return -EINVAL; + + index = dev->ctl_ainput; + + if (index == 0) { + strcpy(a->name, "Television"); } else { - switch (dev->ctl_ainput) { - case 0: - ainput = EM28XX_AUDIO_SRC_TUNER; + strcpy(a->name, "Line In"); + } + a->capability = V4L2_AUDCAP_STEREO; + a->index = index; + + return 0; +} + +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (a->index != dev->ctl_ainput) + return -EINVAL; + + return 0; +} + +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int id = qc->id; + int i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + memset(qc, 0, sizeof(*qc)); + + qc->id = id; + + if (!dev->has_msp34xx) { + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); + return 0; + } + } + } + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc); + mutex_unlock(&dev->lock); + + if (qc->type) + return 0; + else + return -EINVAL; +} + +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + mutex_lock(&dev->lock); + + if (!dev->has_msp34xx) + rc = em28xx_get_ctrl(dev, ctrl); + else + rc = -EINVAL; + + if (rc == -EINVAL) { + em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl); + rc = 0; + } + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u8 i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + + if (dev->has_msp34xx) + em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); + else { + rc = 1; + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (ctrl->id == em28xx_qctrl[i].id) { + if (ctrl->value < em28xx_qctrl[i].minimum || + ctrl->value > em28xx_qctrl[i].maximum) { + rc = -ERANGE; + break; + } + + rc = em28xx_set_ctrl(dev, ctrl); break; - default: - ainput = EM28XX_AUDIO_SRC_LINE; + } + } + } + + /* Control not found - try to send it to the attached devices */ + if (rc == 1) { + em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); + rc = 0; + } + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + strcpy(t->name, "Tuner"); + + mutex_lock(&dev->lock); + + em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != t->index) + return -EINVAL; + + mutex_lock(&dev->lock); + + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; + + return 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (0 != f->tuner) + return -EINVAL; + + if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) + return -EINVAL; + if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) + return -EINVAL; + + mutex_lock(&dev->lock); + + dev->ctl_freq = f->frequency; + em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cc) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cc->bounds.left = 0; + cc->bounds.top = 0; + cc->bounds.width = dev->width; + cc->bounds.height = dev->height; + cc->defrect = cc->bounds; + cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ + cc->pixelaspect.denominator = 59; + + return 0; +} + +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&dev->inqueue)) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (unlikely(res_get(fh) < 0)) { + mutex_unlock(&dev->lock); + return -EBUSY; + } + + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + mutex_lock(&dev->lock); + + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) { + mutex_unlock(&dev->lock); + return rc; + } + } + + em28xx_empty_framequeues(dev); + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); + + cap->version = EM28XX_VERSION_CODE; + + cap->capabilities = + V4L2_CAP_SLICED_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + + if (dev->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; + + return 0; +} + +static int vidioc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *fmtd) +{ + if (fmtd->index != 0) + return -EINVAL; + + fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + strcpy(fmtd->description, "Packed YUY2"); + fmtd->pixelformat = V4L2_PIX_FMT_YUYV; + memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); + + return 0; +} + +/* Sliced VBI ioctls */ +static int vidioc_g_fmt_vbi_capture(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + + f->fmt.sliced.service_set = 0; + + em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); + + if (f->fmt.sliced.service_set == 0) + rc = -EINVAL; + + mutex_unlock(&dev->lock); + return rc; +} + +static int vidioc_try_set_vbi_capture(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); + mutex_unlock(&dev->lock); + + if (f->fmt.sliced.service_set == 0) + return -EINVAL; + + return 0; +} + + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u32 i; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (dev->io == IO_READ) { + em28xx_videodbg("method is set to read;" + " close and open the device again to" + " choose the mmap I/O method\n"); + return -EINVAL; + } + + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_REQBUFS failed; " + "previous buffers are still mapped\n"); + return -EINVAL; + } + + mutex_lock(&dev->lock); + + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); + rc = em28xx_stream_interrupt(dev); + if (rc < 0) { + mutex_unlock(&dev->lock); + return rc; } - em28xx_audio_source(dev, ainput); } + + em28xx_empty_framequeues(dev); + + em28xx_release_buffers(dev); + if (rb->count) + rb->count = em28xx_request_buffers(dev, rb->count); + + dev->frame_current = NULL; + dev->io = rb->count ? IO_MMAP : IO_NONE; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) + return -EINVAL; + + mutex_lock(&dev->lock); + + memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); + + if (dev->frame[b->index].vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + if (dev->frame[b->index].state == F_DONE) + b->flags |= V4L2_BUF_FLAG_DONE; + else if (dev->frame[b->index].state != F_UNUSED) + b->flags |= V4L2_BUF_FLAG_QUEUED; + + mutex_unlock(&dev->lock); + return 0; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + unsigned long lock_flags; + int rc; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP || + b->index >= dev->num_frames) + return -EINVAL; + + if (dev->frame[b->index].state != F_UNUSED) + return -EAGAIN; + + dev->frame[b->index].state = F_QUEUED; + + /* add frame to fifo */ + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_add_tail(&dev->frame[b->index].frame, &dev->inqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + + return 0; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int rc; + struct em28xx_frame_t *f; + unsigned long lock_flags; + + rc = check_dev(dev); + if (rc < 0) + return rc; + + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP) + return -EINVAL; + + if (list_empty(&dev->outqueue)) { + if (dev->stream == STREAM_OFF) + return -EINVAL; + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + rc = wait_event_interruptible(dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (rc) + return rc; + + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + } + + spin_lock_irqsave(&dev->queue_lock, lock_flags); + f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame); + list_del(dev->outqueue.next); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + + f->state = F_UNUSED; + memcpy(b, &f->buf, sizeof(*b)); + + if (f->vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; + + return 0; +} + +/* ----------------------------------------------------------- */ +/* RADIO ESPECIFIC IOCTLS */ +/* ----------------------------------------------------------- */ + +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); + strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); + strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); + + cap->version = EM28XX_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} + +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + if (unlikely(t->index > 0)) + return -EINVAL; + + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + return 0; +} + +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; + + return 0; +} + +static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (unlikely(a->index)) + return -EINVAL; + + strcpy(a->name, "Radio"); + return 0; +} + +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; + + if (0 != t->index) + return -EINVAL; + + em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + + return 0; +} + +static int radio_s_audio(struct file *file, void *fh, + struct v4l2_audio *a) +{ + return 0; +} + +static int radio_s_input(struct file *file, void *fh, unsigned int i) +{ + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) +{ + int i; + + if (qc->id < V4L2_CID_BASE || + qc->id >= V4L2_CID_LASTP1) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { + if (qc->id && qc->id == em28xx_qctrl[i].id) { + memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); + return 0; + } + } + + return -EINVAL; } /* @@ -252,8 +1258,9 @@ static void video_mux(struct em28xx *dev, int index) static int em28xx_v4l2_open(struct inode *inode, struct file *filp) { int minor = iminor(inode); - int errCode = 0; + int errCode = 0, radio = 0; struct em28xx *h,*dev = NULL; + struct em28xx_fh *fh; list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { @@ -264,6 +1271,11 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev = h; dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; } + if (h->radio_dev && + h->radio_dev->minor == minor) { + radio = 1; + dev = h; + } } if (NULL == dev) return -ENODEV; @@ -271,23 +1283,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_videodbg("open minor=%d type=%s users=%d\n", minor,v4l2_type_names[dev->type],dev->users); - if (!down_read_trylock(&em28xx_disconnect)) - return -ERESTARTSYS; + fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); - if (dev->users) { - em28xx_warn("this driver can be opened only once\n"); - up_read(&em28xx_disconnect); - return -EBUSY; + if (!fh) { + em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + return -ENOMEM; } - - mutex_init(&dev->fileop_lock); /* to 1 == available */ - spin_lock_init(&dev->queue_lock); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); - mutex_lock(&dev->lock); + fh->dev = dev; + fh->radio = radio; + filp->private_data = fh; - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { em28xx_set_alternate(dev); dev->width = norm_maxw(dev); @@ -301,30 +1308,23 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); - /* device needs to be initialized before isoc transfer */ - video_mux(dev, 0); /* start the transfer */ errCode = em28xx_init_isoc(dev); if (errCode) goto err; + em28xx_empty_framequeues(dev); + } + if (fh->radio) { + em28xx_videodbg("video_open: setting radio device\n"); + em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL); } dev->users++; - filp->private_data = dev; - dev->io = IO_NONE; - dev->stream = STREAM_OFF; - dev->num_frames = 0; - - /* prepare queues */ - em28xx_empty_framequeues(dev); - - dev->state |= DEV_INITIALIZED; err: mutex_unlock(&dev->lock); - up_read(&em28xx_disconnect); return errCode; } @@ -335,7 +1335,6 @@ err: */ static void em28xx_release_resources(struct em28xx *dev) { - mutex_lock(&em28xx_sysfs_lock); /*FIXME: I2C IR should be disconnected */ @@ -343,12 +1342,29 @@ static void em28xx_release_resources(struct em28xx *dev) dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); list_del(&dev->devlist); - video_unregister_device(dev->vdev); - video_unregister_device(dev->vbi_dev); + if (dev->radio_dev) { + if (-1 != dev->radio_dev->minor) + video_unregister_device(dev->radio_dev); + else + video_device_release(dev->radio_dev); + dev->radio_dev = NULL; + } + if (dev->vbi_dev) { + if (-1 != dev->vbi_dev->minor) + video_unregister_device(dev->vbi_dev); + else + video_device_release(dev->vbi_dev); + dev->vbi_dev = NULL; + } + if (dev->vdev) { + if (-1 != dev->vdev->minor) + video_unregister_device(dev->vdev); + else + video_device_release(dev->vdev); + dev->vdev = NULL; + } em28xx_i2c_unregister(dev); usb_put_dev(dev->udev); - mutex_unlock(&em28xx_sysfs_lock); - /* Mark device as unused */ em28xx_devused&=~(1<<dev->devno); @@ -360,34 +1376,42 @@ static void em28xx_release_resources(struct em28xx *dev) */ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) { - int errCode; - struct em28xx *dev=filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + int errCode; em28xx_videodbg("users=%d\n", dev->users); - mutex_lock(&dev->lock); - em28xx_uninit_isoc(dev); + if (res_check(fh)) + res_free(fh); - em28xx_release_buffers(dev); + mutex_lock(&dev->lock); - /* the device is already disconnect, free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; - } + if (dev->users == 1) { + em28xx_uninit_isoc(dev); + em28xx_release_buffers(dev); + dev->io = IO_NONE; - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev ("cannot change alternate number to 0 (error=%i)\n", - errCode); - } + /* the device is already disconnect, + free the remaining resources */ + if (dev->state & DEV_DISCONNECTED) { + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); + return 0; + } + /* set alternate 0 */ + dev->alt = 0; + em28xx_videodbg("setting alternate 0\n"); + errCode = usb_set_interface(dev->udev, 0, 0); + if (errCode < 0) { + em28xx_errdev("cannot change alternate number to " + "0 (error=%i)\n", errCode); + } + } + kfree(fh); dev->users--; wake_up_interruptible_nr(&dev->open, 1); mutex_unlock(&dev->lock); @@ -405,56 +1429,65 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, struct em28xx_frame_t *f, *i; unsigned long lock_flags; int ret = 0; - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; - if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + /* FIXME: read() is not prepared to allow changing the video + resolution while streaming. Seems a bug at em28xx_set_fmt + */ + + if (unlikely(res_get(fh) < 0)) + return -EBUSY; + + mutex_lock(&dev->lock); + + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); - } + if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EFAULT; } + mutex_unlock(&dev->lock); return (1); } if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); em28xx_videodbg("not supported yet! ...\n"); if (copy_to_user(buf, "", 1)) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EFAULT; } + mutex_unlock(&dev->lock); return (1); } - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; - if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("device not present\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_videodbg("device misconfigured; close and open it again\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EIO; } if (dev->io == IO_MMAP) { em28xx_videodbg ("IO method is set to mmap; close and open" " the device again to choose the read method\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EINVAL; } if (dev->io == IO_NONE) { if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { em28xx_errdev("read failed, not enough memory\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENOMEM; } dev->io = IO_READ; @@ -463,13 +1496,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, } if (!count) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return 0; } if (list_empty(&dev->outqueue)) { if (filp->f_flags & O_NONBLOCK) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EAGAIN; } ret = wait_event_interruptible @@ -477,35 +1510,46 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, (!list_empty(&dev->outqueue)) || (dev->state & DEV_DISCONNECTED)); if (ret) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return ret; } if (dev->state & DEV_DISCONNECTED) { - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENODEV; } + dev->video_bytesread = 0; } f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame); - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_for_each_entry(i, &dev->outqueue, frame) - i->state = F_UNUSED; - INIT_LIST_HEAD(&dev->outqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - em28xx_queue_unusedframes(dev); if (count > f->buf.length) count = f->buf.length; - if (copy_to_user(buf, f->bufmem, count)) { - mutex_unlock(&dev->fileop_lock); + if ((dev->video_bytesread + count) > dev->frame_size) + count = dev->frame_size - dev->video_bytesread; + + if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) { + em28xx_err("Error while copying to user\n"); return -EFAULT; } + dev->video_bytesread += count; + + if (dev->video_bytesread == dev->frame_size) { + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_for_each_entry(i, &dev->outqueue, frame) + i->state = F_UNUSED; + INIT_LIST_HEAD(&dev->outqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + + em28xx_queue_unusedframes(dev); + dev->video_bytesread = 0; + } + *f_pos += count; - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return count; } @@ -517,11 +1561,14 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) { unsigned int mask = 0; - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; - if (mutex_lock_interruptible(&dev->fileop_lock)) + if (unlikely(res_get(fh) < 0)) return POLLERR; + mutex_lock(&dev->lock); + if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("device not present\n"); } else if (dev->state & DEV_MISCONFIGURED) { @@ -545,83 +1592,61 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) if (!list_empty(&dev->outqueue)) mask |= POLLIN | POLLRDNORM; - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return mask; } } - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return POLLERR; } /* - * em28xx_vm_open() - */ -static void em28xx_vm_open(struct vm_area_struct *vma) -{ - struct em28xx_frame_t *f = vma->vm_private_data; - f->vma_use_count++; -} - -/* - * em28xx_vm_close() - */ -static void em28xx_vm_close(struct vm_area_struct *vma) -{ - /* NOTE: buffers are not freed here */ - struct em28xx_frame_t *f = vma->vm_private_data; - - if (f->vma_use_count) - f->vma_use_count--; -} - -static struct vm_operations_struct em28xx_vm_ops = { - .open = em28xx_vm_open, - .close = em28xx_vm_close, -}; - -/* * em28xx_v4l2_mmap() */ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) { - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; - u32 i; - - struct em28xx *dev = filp->private_data; + struct em28xx_fh *fh = filp->private_data; + struct em28xx *dev = fh->dev; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long start = vma->vm_start; + void *pos; + u32 i; + + if (unlikely(res_get(fh) < 0)) + return -EBUSY; - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; + mutex_lock(&dev->lock); if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("mmap: device not present\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_videodbg ("mmap: Device is misconfigured; close and " "open it again\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EIO; } - if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || - size != PAGE_ALIGN(dev->frame[0].buf.length)) { - mutex_unlock(&dev->fileop_lock); + if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) { + mutex_unlock(&dev->lock); return -EINVAL; } + if (size > PAGE_ALIGN(dev->frame[0].buf.length)) + size = PAGE_ALIGN(dev->frame[0].buf.length); + for (i = 0; i < dev->num_frames; i++) { if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff) break; } if (i == dev->num_frames) { em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EINVAL; } @@ -633,7 +1658,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->fileop_lock); + mutex_unlock(&dev->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -645,900 +1670,210 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = &dev->frame[i]; em28xx_vm_open(vma); - mutex_unlock(&dev->fileop_lock); - return 0; -} - -/* - * em28xx_get_ctrl() - * return the current saturation, brightness or contrast, mute state - */ -static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->volume; - return 0; - default: - return -EINVAL; - } -} - -/* - * em28xx_set_ctrl() - * mute or set new saturation, brightness or contrast - */ -static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value != dev->mute) { - dev->mute = ctrl->value; - em28xx_audio_usb_mute(dev, ctrl->value); - return em28xx_audio_analog_set(dev); - } - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - return em28xx_audio_analog_set(dev); - default: - return -EINVAL; - } -} - -/* - * em28xx_stream_interrupt() - * stops streaming - */ -static int em28xx_stream_interrupt(struct em28xx *dev) -{ - int ret = 0; - - /* stop reading from the device */ - - dev->stream = STREAM_INTERRUPT; - ret = wait_event_timeout(dev->wait_stream, - (dev->stream == STREAM_OFF) || - (dev->state & DEV_DISCONNECTED), - EM28XX_URB_TIMEOUT); - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - else if (ret) { - dev->state |= DEV_MISCONFIGURED; - em28xx_videodbg("device is misconfigured; close and " - "open /dev/video%d again\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); - return ret; - } - - return 0; -} - -static int em28xx_set_norm(struct em28xx *dev, int width, int height) -{ - unsigned int hscale, vscale; - unsigned int maxh, maxw; - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - /* width must even because of the YUYV format */ - /* height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; - - if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) - hscale = 0x3fff; - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - - if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) - vscale = 0x3fff; - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - - /* set new image size */ - dev->width = width; - dev->height = height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; - - em28xx_resolution_set(dev); - + mutex_unlock(&dev->lock); return 0; } -static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format) -{ - em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", - (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : - (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ? - "V4L2_BUF_TYPE_VBI_CAPTURE" : - (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ? - "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " : - "not supported"); - - switch (format->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - format->fmt.pix.width = dev->width; - format->fmt.pix.height = dev->height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = dev->bytesperline; - format->fmt.pix.sizeimage = dev->frame_size; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ +static const struct file_operations em28xx_v4l_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .read = em28xx_v4l2_read, + .poll = em28xx_v4l2_poll, + .mmap = em28xx_v4l2_mmap, + .ioctl = video_ioctl2, + .llseek = no_llseek, + .compat_ioctl = v4l_compat_ioctl32, +}; - em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, - dev->height); - break; - } +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, +}; - case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - { - format->fmt.sliced.service_set=0; +static const struct video_device em28xx_video_template = { + .fops = &em28xx_v4l_fops, + .release = video_device_release, + + .minor = -1, + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, + .vidioc_g_fmt_cap = vidioc_g_fmt_cap, + .vidioc_try_fmt_cap = vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = vidioc_s_fmt_cap, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_cropcap = vidioc_cropcap, + + .vidioc_g_fmt_vbi_capture = vidioc_g_fmt_vbi_capture, + .vidioc_try_fmt_vbi_capture = vidioc_try_set_vbi_capture, + .vidioc_s_fmt_vbi_capture = vidioc_try_set_vbi_capture, + + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + + .tvnorms = V4L2_STD_ALL, + .current_norm = V4L2_STD_PAL, +}; - em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); +static struct video_device em28xx_radio_template = { + .name = "em28xx-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +}; - if (format->fmt.sliced.service_set==0) - return -EINVAL; +/******************************** usb interface *****************************************/ - break; - } - default: - return -EINVAL; - } - return (0); -} +static LIST_HEAD(em28xx_extension_devlist); +static DEFINE_MUTEX(em28xx_extension_devlist_lock); -static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format) +int em28xx_register_extension(struct em28xx_ops *ops) { - u32 i; - int ret = 0; - int width = format->fmt.pix.width; - int height = format->fmt.pix.height; - unsigned int hscale, vscale; - unsigned int maxh, maxw; + struct em28xx *h, *dev = NULL; - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - em28xx_videodbg("%s: type=%s\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", - format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : - format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? - "V4L2_BUF_TYPE_VBI_CAPTURE " : - "not supported"); - - if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { - em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); - - if (format->fmt.sliced.service_set==0) - return -EINVAL; + list_for_each_entry(h, &em28xx_devlist, devlist) + dev = h; - return 0; - } + mutex_lock(&em28xx_extension_devlist_lock); + list_add_tail(&ops->next, &em28xx_extension_devlist); + if (dev) + ops->init(dev); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - em28xx_videodbg("%s: requested %dx%d\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", - format->fmt.pix.width, format->fmt.pix.height); - - /* FIXME: Move some code away from here */ - /* width must even because of the YUYV format */ - /* height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; - - if(dev->is_em2800){ - /* the em2800 can only scale down to 50% */ - if(height % (maxh / 2)) - height=maxh; - if(width % (maxw / 2)) - width=maxw; - /* according to empiatech support */ - /* the MaxPacketSize is to small to support */ - /* framesizes larger than 640x480 @ 30 fps */ - /* or 640x576 @ 25 fps. As this would cut */ - /* of a part of the image we prefer */ - /* 360x576 or 360x480 for now */ - if(width == maxw && height == maxh) - width /= 2; - } - - if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) - hscale = 0x3fff; - - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - - if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) - vscale = 0x3fff; - - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - - format->fmt.pix.width = width; - format->fmt.pix.height = height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = width * 2; - format->fmt.pix.sizeimage = width * 2 * height; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = V4L2_FIELD_INTERLACED; - - em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", - cmd == VIDIOC_TRY_FMT ? - "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT", - format->fmt.pix.width, format->fmt.pix.height, hscale, vscale); - - if (cmd == VIDIOC_TRY_FMT) - return 0; - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_S_FMT failed. " - "Unmap the buffers first.\n"); - return -EINVAL; - } - - /* stop io in case it is already in progress */ - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - - em28xx_release_buffers(dev); - dev->io = IO_NONE; - - /* set new image size */ - dev->width = width; - dev->height = height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; - dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; - em28xx_uninit_isoc(dev); - em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); - em28xx_init_isoc(dev); + printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); + mutex_unlock(&em28xx_extension_devlist_lock); return 0; } +EXPORT_SYMBOL(em28xx_register_extension); -/* - * em28xx_v4l2_do_ioctl() - * This function is _not_ called directly, but from - * em28xx_v4l2_ioctl. Userspace - * copying is done already, arg is a kernel pointer. - */ -static int em28xx_do_ioctl(struct inode *inode, struct file *filp, - struct em28xx *dev, unsigned int cmd, void *arg, - v4l2_kioctl driver_ioctl) +void em28xx_unregister_extension(struct em28xx_ops *ops) { - int ret; + struct em28xx *h, *dev = NULL; - switch (cmd) { - /* ---------- tv norms ---------- */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; + list_for_each_entry(h, &em28xx_devlist, devlist) + dev = h; - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - ret = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (ret < 0) - return ret; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + if (dev) + ops->fini(dev); - *id = dev->tvnorm->id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; - - for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) - break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - - mutex_lock(&dev->lock); - dev->tvnorm = &tvnorms[i]; - - em28xx_set_norm(dev, dev->width, dev->height); - - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, - &dev->tvnorm->id); - - mutex_unlock(&dev->lock); - - return 0; - } - - /* ------ input switching ---------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; - static const char *iname[] = { - [EM28XX_VMUX_COMPOSITE1] = "Composite1", - [EM28XX_VMUX_COMPOSITE2] = "Composite2", - [EM28XX_VMUX_COMPOSITE3] = "Composite3", - [EM28XX_VMUX_COMPOSITE4] = "Composite4", - [EM28XX_VMUX_SVIDEO] = "S-Video", - [EM28XX_VMUX_TELEVISION] = "Television", - [EM28XX_VMUX_CABLE] = "Cable TV", - [EM28XX_VMUX_DVB] = "DVB", - [EM28XX_VMUX_DEBUG] = "for debug only", - }; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - memset(i, 0, sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || - (EM28XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - for (n = 0; n < ARRAY_SIZE(tvnorms); n++) - i->std |= tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = dev->ctl_input; - - return 0; - } - case VIDIOC_S_INPUT: - { - int *index = arg; - - if (*index >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(*index)->type) - return -EINVAL; - - mutex_lock(&dev->lock); - video_mux(dev, *index); - mutex_unlock(&dev->lock); - - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int index = a->index; - - if (a->index > 1) - return -EINVAL; - memset(a, 0, sizeof(*a)); - index = dev->ctl_ainput; - - if (index == 0) { - strcpy(a->name, "Television"); - } else { - strcpy(a->name, "Line In"); - } - a->capability = V4L2_AUDCAP_STEREO; - a->index = index; - return 0; - } - case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; - - if (a->index != dev->ctl_ainput) - return -EINVAL; - - return 0; - } - - /* --- controls ---------------------------------------------- */ - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i, id=qc->id; - - memset(qc,0,sizeof(*qc)); - qc->id=id; - - if (!dev->has_msp34xx) { - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), - sizeof(*qc)); - return 0; - } - } - } - em28xx_i2c_call_clients(dev,cmd,qc); - if (qc->type) - return 0; - else - return -EINVAL; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - int retval=-EINVAL; - - if (!dev->has_msp34xx) - retval=em28xx_get_ctrl(dev, ctrl); - if (retval==-EINVAL) { - em28xx_i2c_call_clients(dev,cmd,arg); - return 0; - } else return retval; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - u8 i; - - if (!dev->has_msp34xx){ - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (ctrl->id == em28xx_qctrl[i].id) { - if (ctrl->value < - em28xx_qctrl[i].minimum - || ctrl->value > - em28xx_qctrl[i].maximum) - return -ERANGE; - return em28xx_set_ctrl(dev, ctrl); - } - } - } - - em28xx_i2c_call_clients(dev,cmd,arg); - return 0; - } - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - - if (0 != t->index) - return -EINVAL; - - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Tuner"); - mutex_lock(&dev->lock); - /* let clients fill in the remainder of this struct */ - em28xx_i2c_call_clients(dev, cmd, t); - mutex_unlock(&dev->lock); - em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, - t->afc); - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; - - if (0 != t->index) - return -EINVAL; - mutex_lock(&dev->lock); - /* let clients handle this */ - em28xx_i2c_call_clients(dev, cmd, t); - mutex_unlock(&dev->lock); - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - if (0 != f->tuner) - return -EINVAL; - - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - mutex_unlock(&dev->lock); - return 0; - } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cc = arg; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - return 0; - } - case VIDIOC_STREAMON: - { - int *type = arg; - - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->inqueue)) - return -EINVAL; - - dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ - - em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); - - return 0; - } - case VIDIOC_STREAMOFF: - { - int *type = arg; - int ret; - - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; - - if (dev->stream == STREAM_ON) { - em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - em28xx_empty_framequeues(dev); - - return 0; - } - default: - return v4l_compat_translate_ioctl(inode, filp, cmd, arg, - driver_ioctl); - } - return 0; -} - -/* - * em28xx_v4l2_do_ioctl() - * This function is _not_ called directly, but from - * em28xx_v4l2_ioctl. Userspace - * copying is done already, arg is a kernel pointer. - */ -static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, void *arg) -{ - struct em28xx *dev = filp->private_data; - - if (!dev) - return -ENODEV; - - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); - - switch (cmd) { - - /* --- capabilities ------------------------------------------ */ - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof(*cap)); - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, - sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, - sizeof(cap->bus_info)); - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = - V4L2_CAP_SLICED_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (dev->has_tuner) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; - } - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *fmtd = arg; - - if (fmtd->index != 0) - return -EINVAL; - memset(fmtd, 0, sizeof(*fmtd)); - fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmtd->description, "Packed YUY2"); - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); - return 0; - } - case VIDIOC_G_FMT: - return em28xx_get_fmt(dev, (struct v4l2_format *) arg); - - case VIDIOC_TRY_FMT: - case VIDIOC_S_FMT: - return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); - - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - u32 i; - int ret; - - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (dev->io == IO_READ) { - em28xx_videodbg ("method is set to read;" - " close and open the device again to" - " choose the mmap I/O method\n"); - return -EINVAL; - } - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); - return -EINVAL; - } - - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - - em28xx_empty_framequeues(dev); - - em28xx_release_buffers(dev); - if (rb->count) - rb->count = - em28xx_request_buffers(dev, rb->count); - - dev->frame_current = NULL; - - em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", - rb->count); - dev->io = rb->count ? IO_MMAP : IO_NONE; - return 0; - } - case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *b = arg; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) - return -EINVAL; - - memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); - - if (dev->frame[b->index].vma_use_count) { - b->flags |= V4L2_BUF_FLAG_MAPPED; - } - if (dev->frame[b->index].state == F_DONE) - b->flags |= V4L2_BUF_FLAG_DONE; - else if (dev->frame[b->index].state != F_UNUSED) - b->flags |= V4L2_BUF_FLAG_QUEUED; - return 0; - } - case VIDIOC_QBUF: - { - struct v4l2_buffer *b = arg; - unsigned long lock_flags; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) { - return -EINVAL; - } - - if (dev->frame[b->index].state != F_UNUSED) { - return -EAGAIN; - } - dev->frame[b->index].state = F_QUEUED; - - /* add frame to fifo */ - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[b->index].frame, - &dev->inqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - return 0; - } - case VIDIOC_DQBUF: - { - struct v4l2_buffer *b = arg; - struct em28xx_frame_t *f; - unsigned long lock_flags; - int ret = 0; - - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; - - if (list_empty(&dev->outqueue)) { - if (dev->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) - return ret; - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - } - - spin_lock_irqsave(&dev->queue_lock, lock_flags); - f = list_entry(dev->outqueue.next, - struct em28xx_frame_t, frame); - list_del(dev->outqueue.next); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - - f->state = F_UNUSED; - memcpy(b, &f->buf, sizeof(*b)); - - if (f->vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; - - return 0; - } - default: - return em28xx_do_ioctl(inode, filp, dev, cmd, arg, - em28xx_video_do_ioctl); - } - return 0; + mutex_lock(&em28xx_extension_devlist_lock); + printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); + list_del(&ops->next); + mutex_unlock(&em28xx_extension_devlist_lock); } +EXPORT_SYMBOL(em28xx_unregister_extension); -/* - * em28xx_v4l2_ioctl() - * handle v4l2 ioctl the main action happens in em28xx_v4l2_do_ioctl() - */ -static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) +struct video_device *em28xx_vdev_init(struct em28xx *dev, + const struct video_device *template, + const int type, + const char *type_name) { - int ret = 0; - struct em28xx *dev = filp->private_data; - - if (mutex_lock_interruptible(&dev->fileop_lock)) - return -ERESTARTSYS; - - if (dev->state & DEV_DISCONNECTED) { - em28xx_errdev("v4l2 ioctl: device not present\n"); - mutex_unlock(&dev->fileop_lock); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_errdev - ("v4l2 ioctl: device is misconfigured; close and open it again\n"); - mutex_unlock(&dev->fileop_lock); - return -EIO; - } + struct video_device *vfd; - ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); + vfd = video_device_alloc(); + if (NULL == vfd) + return NULL; + *vfd = *template; + vfd->minor = -1; + vfd->dev = &dev->udev->dev; + vfd->release = video_device_release; + vfd->type = type; - mutex_unlock(&dev->fileop_lock); + snprintf(vfd->name, sizeof(vfd->name), "%s %s", + dev->name, type_name); - return ret; + return vfd; } -static const struct file_operations em28xx_v4l_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = em28xx_v4l2_ioctl, - .read = em28xx_v4l2_read, - .poll = em28xx_v4l2_poll, - .mmap = em28xx_v4l2_mmap, - .llseek = no_llseek, - .compat_ioctl = v4l_compat_ioctl32, - -}; - -/******************************** usb interface *****************************************/ /* * em28xx_init_dev() * allocates and inits the device structs, registers i2c bus and v4l device */ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - int minor, int model) + int minor) { + struct em28xx_ops *ops = NULL; struct em28xx *dev = *devhandle; int retval = -ENOMEM; - int errCode, i; + int errCode; unsigned int maxh, maxw; dev->udev = udev; - dev->model = model; mutex_init(&dev->lock); + spin_lock_init(&dev->queue_lock); init_waitqueue_head(&dev->open); + init_waitqueue_head(&dev->wait_frame); + init_waitqueue_head(&dev->wait_stream); dev->em28xx_write_regs = em28xx_write_regs; dev->em28xx_read_reg = em28xx_read_reg; dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; dev->em28xx_write_regs_req = em28xx_write_regs_req; dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->is_em2800 = em28xx_boards[model].is_em2800; - dev->has_tuner = em28xx_boards[model].has_tuner; - dev->has_msp34xx = em28xx_boards[model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[model].tda9887_conf; - dev->decoder = em28xx_boards[model].decoder; - - if (tuner >= 0) - dev->tuner_type = tuner; - else - dev->tuner_type = em28xx_boards[model].tuner_type; + dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->video_inputs = em28xx_boards[model].vchannels; + errCode = em28xx_read_reg(dev, CHIPID_REG); + if (errCode >= 0) + em28xx_info("em28xx chip ID = %d\n", errCode); - for (i = 0; i < TVNORMS; i++) - if (em28xx_boards[model].norm == tvnorms[i].mode) - break; - if (i == TVNORMS) - i = 0; + em28xx_pre_card_setup(dev); + + errCode = em28xx_config(dev); + if (errCode) { + em28xx_errdev("error configuring device\n"); + em28xx_devused &= ~(1<<dev->devno); + kfree(dev); + return -ENOMEM; + } + + /* register i2c bus */ + em28xx_i2c_register(dev); - dev->tvnorm = &tvnorms[i]; /* set default norm */ + /* Do board specific init and eeprom reading */ + em28xx_card_setup(dev); - em28xx_videodbg("tvnorm=%s\n", dev->tvnorm->name); + /* Configure audio */ + em28xx_audio_analog_set(dev); + + /* configure the device */ + em28xx_config_i2c(dev); + + /* set default norm */ + dev->norm = em28xx_video_template.current_norm; maxw = norm_maxw(dev); maxh = norm_maxh(dev); @@ -1555,138 +1890,110 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vscale = 0; dev->ctl_input = 2; - /* setup video picture settings for saa7113h */ - memset(&dev->vpic, 0, sizeof(dev->vpic)); - dev->vpic.colour = 128 << 8; - dev->vpic.hue = 128 << 8; - dev->vpic.brightness = 128 << 8; - dev->vpic.contrast = 192 << 8; - dev->vpic.whiteness = 128 << 8; /* This one isn't used */ - dev->vpic.depth = 16; - dev->vpic.palette = VIDEO_PALETTE_YUV422; - - em28xx_pre_card_setup(dev); -#ifdef CONFIG_MODULES - /* request some modules */ - if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) - request_module("saa7115"); - if (dev->decoder == EM28XX_TVP5150) - request_module("tvp5150"); - if (dev->has_tuner) - request_module("tuner"); -#endif errCode = em28xx_config(dev); - if (errCode) { - em28xx_errdev("error configuring device\n"); - em28xx_devused&=~(1<<dev->devno); - kfree(dev); - return -ENOMEM; - } - - mutex_lock(&dev->lock); - /* register i2c bus */ - em28xx_i2c_register(dev); - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); + list_add_tail(&dev->devlist, &em28xx_devlist); - /* configure the device */ - em28xx_config_i2c(dev); - - mutex_unlock(&dev->lock); - - errCode = em28xx_config(dev); - -#ifdef CONFIG_MODULES - if (dev->has_msp34xx) - request_module("msp3400"); -#endif - /* allocate and fill v4l2 device struct */ - dev->vdev = video_device_alloc(); + /* allocate and fill video video_device struct */ + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, + VID_TYPE_CAPTURE, "video"); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); - em28xx_devused&=~(1<<dev->devno); - kfree(dev); - return -ENOMEM; - } - - dev->vbi_dev = video_device_alloc(); - if (NULL == dev->vbi_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - kfree(dev->vdev); - em28xx_devused&=~(1<<dev->devno); - kfree(dev); - return -ENOMEM; + goto fail_unreg; } - - /* Fills VBI device info */ - dev->vbi_dev->type = VFL_TYPE_VBI; - dev->vbi_dev->fops = &em28xx_v4l_fops; - dev->vbi_dev->minor = -1; - dev->vbi_dev->dev = &dev->udev->dev; - dev->vbi_dev->release = video_device_release; - snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", - "em28xx",dev->devno,"vbi"); - - /* Fills CAPTURE device info */ - dev->vdev->type = VID_TYPE_CAPTURE; - if (dev->has_tuner) + if (dev->tuner_type != TUNER_ABSENT) dev->vdev->type |= VID_TYPE_TUNER; - dev->vdev->fops = &em28xx_v4l_fops; - dev->vdev->minor = -1; - dev->vdev->dev = &dev->udev->dev; - dev->vdev->release = video_device_release; - snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", - "em28xx",dev->devno,"video"); - - list_add_tail(&dev->devlist,&em28xx_devlist); - /* register v4l2 device */ - mutex_lock(&dev->lock); - if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]))) { + /* register v4l2 video video_device */ + retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]); + if (retval) { em28xx_errdev("unable to register video device (error=%i).\n", retval); - mutex_unlock(&dev->lock); - list_del(&dev->devlist); - video_device_release(dev->vdev); - em28xx_devused&=~(1<<dev->devno); - kfree(dev); - return -ENODEV; + goto fail_unreg; } + /* Allocate and fill vbi video_device struct */ + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, + VFL_TYPE_VBI, "vbi"); + /* register v4l2 vbi video_device */ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { - printk("unable to register vbi device\n"); - mutex_unlock(&dev->lock); - list_del(&dev->devlist); - video_device_release(dev->vbi_dev); - video_device_release(dev->vdev); - em28xx_devused&=~(1<<dev->devno); - kfree(dev); - return -ENODEV; - } else { - printk("registered VBI\n"); + em28xx_errdev("unable to register vbi device\n"); + retval = -ENODEV; + goto fail_unreg; } + if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, + VFL_TYPE_RADIO, "radio"); + if (NULL == dev->radio_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + goto fail_unreg; + } + retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, + radio_nr[dev->devno]); + if (retval < 0) { + em28xx_errdev("can't register radio device\n"); + goto fail_unreg; + } + em28xx_info("Registered radio device as /dev/radio%d\n", + dev->radio_dev->minor & 0x1f); + } + + if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); msleep(3); em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); msleep(3); - } - video_mux(dev, 0); - mutex_unlock(&dev->lock); + video_mux(dev, 0); em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); + mutex_lock(&em28xx_extension_devlist_lock); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + if (ops->id) + ops->init(dev); + } + } + mutex_unlock(&em28xx_extension_devlist_lock); + return 0; + +fail_unreg: + em28xx_release_resources(dev); + mutex_unlock(&dev->lock); + kfree(dev); + return retval; +} + +#if defined(CONFIG_MODULES) && defined(MODULE) +static void request_module_async(struct work_struct *work) +{ + struct em28xx *dev = container_of(work, + struct em28xx, request_module_wk); + + if (dev->has_audio_class) + request_module("snd-usb-audio"); + else + request_module("em28xx-alsa"); +} + +static void request_modules(struct em28xx *dev) +{ + INIT_WORK(&dev->request_module_wk, request_module_async); + schedule_work(&dev->request_module_wk); } +#else +#define request_modules(dev) +#endif /* CONFIG_MODULES */ /* * em28xx_usb_probe() @@ -1700,7 +2007,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, struct usb_interface *uif; struct em28xx *dev = NULL; int retval = -ENODEV; - int model,i,nr,ifnum; + int i, nr, ifnum; udev = usb_get_dev(interface_to_usbdev(interface)); ifnum = interface->altsetting[0].desc.bInterfaceNumber; @@ -1740,8 +2047,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, return -ENODEV; } - model=id->driver_info; - if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); em28xx_devused&=~(1<<nr); @@ -1757,7 +2062,20 @@ static int em28xx_usb_probe(struct usb_interface *interface, } snprintf(dev->name, 29, "em28xx #%d", nr); - dev->devno=nr; + dev->devno = nr; + dev->model = id->driver_info; + + /* Checks if audio is provided by some interface */ + for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { + uif = udev->config->interface[i]; + if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { + dev->has_audio_class = 1; + break; + } + } + + printk(KERN_INFO DRIVER_NAME " %s usb audio class\n", + dev->has_audio_class ? "Has" : "Doesn't have"); /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; @@ -1784,33 +2102,20 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if ((card[nr]>=0)&&(card[nr]<em28xx_bcount)) - model=card[nr]; - - if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) { - em28xx_errdev( "Your board has no eeprom inside it and thus can't\n" - "%s: be autodetected. Please pass card=<n> insmod option to\n" - "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Generic type will be used." - "%s: Best regards,\n" - "%s: -- tux\n", - dev->name,dev->name,dev->name,dev->name,dev->name); - em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n", - dev->name); - for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", i, - em28xx_boards[i].name); - } - } + dev->model = card[nr]; /* allocate device struct */ - retval = em28xx_init_dev(&dev, udev, nr, model); + retval = em28xx_init_dev(&dev, udev, nr); if (retval) return retval; - em28xx_info("Found %s\n", em28xx_boards[model].name); + em28xx_info("Found %s\n", em28xx_boards[dev->model].name); /* save our data pointer in this interface device */ usb_set_intfdata(interface, dev); + + request_modules(dev); + return 0; } @@ -1821,18 +2126,20 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ static void em28xx_usb_disconnect(struct usb_interface *interface) { - struct em28xx *dev = usb_get_intfdata(interface); + struct em28xx *dev; + struct em28xx_ops *ops = NULL; + + dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); if (!dev) return; - down_write(&em28xx_disconnect); + em28xx_info("disconnecting %s\n", dev->vdev->name); + /* wait until all current v4l2 io is finished then deallocate resources */ mutex_lock(&dev->lock); - em28xx_info("disconnecting %s\n", dev->vdev->name); - wake_up_interruptible_all(&dev->open); if (dev->users) { @@ -1850,15 +2157,20 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->state |= DEV_DISCONNECTED; em28xx_release_resources(dev); } - mutex_unlock(&dev->lock); + mutex_lock(&em28xx_extension_devlist_lock); + if (!list_empty(&em28xx_extension_devlist)) { + list_for_each_entry(ops, &em28xx_extension_devlist, next) { + ops->fini(dev); + } + } + mutex_unlock(&em28xx_extension_devlist_lock); + if (!dev->users) { kfree(dev->alt_max_pkt_size); kfree(dev); } - - up_write(&em28xx_disconnect); } static struct usb_driver em28xx_usb_driver = { diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index d8fcc9e17ac0..f3bad0c1c517 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -25,28 +25,11 @@ #ifndef _EM28XX_H #define _EM28XX_H -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/i2c.h> #include <linux/mutex.h> #include <media/ir-kbd-i2c.h> -/* Boards supported by driver */ - -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 - #define UNSET -1 /* maximum number of em28xx boards */ @@ -148,10 +131,17 @@ enum enum28xx_itype { EM28XX_RADIO, }; +enum em28xx_amux { + EM28XX_AMUX_VIDEO, + EM28XX_AMUX_LINE_IN, + EM28XX_AMUX_AC97_VIDEO, + EM28XX_AMUX_AC97_LINE_IN, +}; + struct em28xx_input { enum enum28xx_itype type; unsigned int vmux; - unsigned int amux; + enum em28xx_amux amux; }; #define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) @@ -165,19 +155,23 @@ enum em28xx_decoder { struct em28xx_board { char *name; int vchannels; - int norm; int tuner_type; /* i2c flags */ - unsigned int is_em2800; unsigned int tda9887_conf; - unsigned int has_tuner:1; + unsigned int is_em2800:1; unsigned int has_msp34xx:1; + unsigned int mts_firmware:1; + unsigned int has_12mhz_i2s:1; + unsigned int max_range_640_480:1; + + unsigned int analog_gpio; enum em28xx_decoder decoder; struct em28xx_input input[MAX_EM28XX_INPUT]; + struct em28xx_input radio; }; struct em28xx_eeprom { @@ -201,12 +195,26 @@ enum em28xx_dev_state { DEV_MISCONFIGURED = 0x04, }; -/* tvnorms */ -struct em28xx_tvnorm { - char *name; - v4l2_std_id id; - /* mode for saa7113h */ - int mode; +#define EM28XX_AUDIO_BUFS 5 +#define EM28XX_NUM_AUDIO_PACKETS 64 +#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ +#define EM28XX_CAPTURE_STREAM_EN 1 +#define EM28XX_AUDIO 0x10 + +struct em28xx_audio { + char name[50]; + char *transfer_buffer[EM28XX_AUDIO_BUFS]; + struct urb *urb[EM28XX_AUDIO_BUFS]; + struct usb_device *udev; + unsigned int capture_transfer_done; + struct snd_pcm_substream *capture_pcm_substream; + + unsigned int hwptr_done_capture; + struct snd_card *sndcard; + + int users, shutdown; + enum em28xx_stream_state capture_stream; + spinlock_t slock; }; /* main device struct */ @@ -215,12 +223,17 @@ struct em28xx { char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ - unsigned int is_em2800; - int video_inputs; /* number of video inputs */ - struct list_head devlist; - unsigned int has_tuner:1; + unsigned int analog_gpio; + unsigned int is_em2800:1; unsigned int has_msp34xx:1; unsigned int has_tda9887:1; + unsigned int stream_on:1; /* Locks streams */ + unsigned int has_audio_class:1; + unsigned int has_12mhz_i2s:1; + unsigned int max_range_640_480:1; + + int video_inputs; /* number of video inputs */ + struct list_head devlist; u32 i2s_speed; /* I2S speed for audio digital stream */ @@ -235,8 +248,7 @@ struct em28xx { /* video for linux */ int users; /* user count for exclusive use */ struct video_device *vdev; /* video for linux device struct */ - struct video_picture vpic; /* picture settings only used to init saa7113h */ - struct em28xx_tvnorm *tvnorm; /* selected tv norm */ + 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 */ @@ -256,17 +268,27 @@ struct em28xx { int vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ int type; + unsigned int video_bytesread; /* Number of bytes read */ + + unsigned long hash; /* eeprom hash - for boards with generic ID */ + unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */ + + struct em28xx_audio *adev; /* states */ enum em28xx_dev_state state; enum em28xx_stream_state stream; enum em28xx_io_method io; + + struct work_struct request_module_wk; + /* locks */ - struct mutex lock, fileop_lock; + struct mutex lock; spinlock_t queue_lock; struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; struct video_device *vbi_dev; + struct video_device *radio_dev; unsigned char eedata[256]; @@ -289,16 +311,27 @@ struct em28xx { int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg); }; +struct em28xx_fh { + struct em28xx *dev; + unsigned int stream_on:1; /* Locks streams */ + int radio; +}; + +struct em28xx_ops { + struct list_head next; + char *name; + int id; + int (*init)(struct em28xx *); + int (*fini)(struct em28xx *); +}; + /* Provided by em28xx-i2c.c */ void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg); +void em28xx_do_i2c_scan(struct em28xx *dev); int em28xx_i2c_register(struct em28xx *dev); int em28xx_i2c_unregister(struct em28xx *dev); -/* Provided by em28xx-input.c */ - -void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir); - /* Provided by em28xx-core.c */ u32 em28xx_request_buffers(struct em28xx *dev, u32 count); @@ -314,8 +347,9 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 bitmask); -int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 * val); +int em28xx_set_audio_source(struct em28xx *dev); int em28xx_audio_analog_set(struct em28xx *dev); + int em28xx_colorlevels_set_default(struct em28xx *dev); int em28xx_capture_start(struct em28xx *dev, int start); int em28xx_outfmt_set_yuv422(struct em28xx *dev); @@ -324,6 +358,10 @@ int em28xx_init_isoc(struct em28xx *dev); void em28xx_uninit_isoc(struct em28xx *dev); int em28xx_set_alternate(struct em28xx *dev); +/* Provided by em28xx-video.c */ +int em28xx_register_extension(struct em28xx_ops *dev); +void em28xx_unregister_extension(struct em28xx_ops *dev); + /* Provided by em28xx-cards.c */ extern int em2800_variant_detect(struct usb_device* udev,int model); extern void em28xx_pre_card_setup(struct em28xx *dev); @@ -331,8 +369,20 @@ extern void em28xx_card_setup(struct em28xx *dev); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; extern const unsigned int em28xx_bcount; +void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); + +/* Provided by em28xx-input.c */ +/* TODO: Check if the standard get_key handlers on ir-common can be used */ +int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); +int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, + u32 *ir_raw); + +/* em2800 registers */ +#define EM2800_AUDIOSRC_REG 0x08 /* em28xx registers */ +#define I2C_CLK_REG 0x06 #define CHIPID_REG 0x0a #define USBSUSP_REG 0x0c /* */ @@ -384,9 +434,12 @@ extern const unsigned int em28xx_bcount; /* em202 registers */ #define MASTER_AC97 0x02 +#define LINE_IN_AC97 0x10 #define VIDEO_AC97 0x14 /* register settings */ +#define EM2800_AUDIO_SRC_TUNER 0x0d +#define EM2800_AUDIO_SRC_LINE 0x0c #define EM28XX_AUDIO_SRC_TUNER 0xc0 #define EM28XX_AUDIO_SRC_LINE 0x80 @@ -406,22 +459,6 @@ extern const unsigned int em28xx_bcount; printk(KERN_WARNING "%s: "fmt,\ dev->name , ##arg); } while (0) -inline static int em28xx_audio_source(struct em28xx *dev, int input) -{ - return em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); -} - -inline static int em28xx_audio_usb_mute(struct em28xx *dev, int mute) -{ - return em28xx_write_reg_bits(dev, XCLK_REG, mute ? 0x00 : 0x80, 0x80); -} - -inline static int em28xx_audio_analog_setup(struct em28xx *dev) -{ - /* unmute video mixer with default volume level */ - return em28xx_write_ac97(dev, VIDEO_AC97, "\x08\x08"); -} - inline static int em28xx_compression_disable(struct em28xx *dev) { /* side effect of disabling scaler and mixer */ @@ -497,18 +534,17 @@ inline static int em28xx_gamma_set(struct em28xx *dev, s32 val) /*FIXME: maxw should be dependent of alt mode */ inline static unsigned int norm_maxw(struct em28xx *dev) { - switch(dev->model){ - case (EM2820_BOARD_MSI_VOX_USB_2): return(640); - default: return(720); - } + if (dev->max_range_640_480) + return 640; + else + return 720; } inline static unsigned int norm_maxh(struct em28xx *dev) { - switch(dev->model){ - case (EM2820_BOARD_MSI_VOX_USB_2): return(480); - default: return (dev->tvnorm->id & V4L2_STD_625_50) ? 576 : 480; - } + if (dev->max_range_640_480) + return 480; + else + return (dev->norm & V4L2_STD_625_50) ? 576 : 480; } - #endif diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index d19d73b81ede..06b6a3ae06c4 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -227,7 +227,7 @@ int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index) } -int et61x251_read_reg(struct et61x251_device* cam, u16 index) +static int et61x251_read_reg(struct et61x251_device* cam, u16 index) { struct usb_device* udev = cam->usbdev; u8* buff = cam->control_buffer; @@ -269,73 +269,6 @@ et61x251_i2c_wait(struct et61x251_device* cam, int -et61x251_i2c_try_read(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, u8 address) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x10; - data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, - 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - if (err) - DBG(3, "I2C read failed for %s image sensor", sensor->name); - - PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); - - return err ? -1 : (int)data[0]; -} - - -int -et61x251_i2c_try_write(struct et61x251_device* cam, - const struct et61x251_sensor* sensor, u8 address, - u8 value) -{ - struct usb_device* udev = cam->usbdev; - u8* data = cam->control_buffer; - int err = 0, res; - - data[0] = address; - data[1] = cam->sensor.i2c_slave_id; - data[2] = cam->sensor.rsta | 0x12; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - data[0] = value; - res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, - 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); - if (res < 0) - err += res; - - err += et61x251_i2c_wait(cam, sensor); - - if (err) - DBG(3, "I2C write failed for %s image sensor", sensor->name); - - PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); - - return err ? -1 : 0; -} - - -int et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, u8 data8, u8 address) @@ -387,17 +320,6 @@ et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2, } -int et61x251_i2c_read(struct et61x251_device* cam, u8 address) -{ - return et61x251_i2c_try_read(cam, &cam->sensor, address); -} - - -int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value) -{ - return et61x251_i2c_try_write(cam, &cam->sensor, address, value); -} - /*****************************************************************************/ static void et61x251_urb_complete(struct urb *urb) @@ -675,6 +597,83 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam) /*****************************************************************************/ #ifdef CONFIG_VIDEO_ADV_DEBUG + +static int et61x251_i2c_try_read(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x10; + data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02); + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, sensor); + + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1, + 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + if (err) + DBG(3, "I2C read failed for %s image sensor", sensor->name); + + PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]); + + return err ? -1 : (int)data[0]; +} + + +static int et61x251_i2c_try_write(struct et61x251_device* cam, + const struct et61x251_sensor* sensor, + u8 address, u8 value) +{ + struct usb_device* udev = cam->usbdev; + u8* data = cam->control_buffer; + int err = 0, res; + + data[0] = address; + data[1] = cam->sensor.i2c_slave_id; + data[2] = cam->sensor.rsta | 0x12; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + data[0] = value; + res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41, + 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT); + if (res < 0) + err += res; + + err += et61x251_i2c_wait(cam, sensor); + + if (err) + DBG(3, "I2C write failed for %s image sensor", sensor->name); + + PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value); + + return err ? -1 : 0; +} + +static int et61x251_i2c_read(struct et61x251_device* cam, u8 address) +{ + return et61x251_i2c_try_read(cam, &cam->sensor, address); +} + +static int et61x251_i2c_write(struct et61x251_device* cam, + u8 address, u8 value) +{ + return et61x251_i2c_try_write(cam, &cam->sensor, address, value); +} + static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count) { char str[5]; diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h index e14586330623..71a03148cb09 100644 --- a/drivers/media/video/et61x251/et61x251_sensor.h +++ b/drivers/media/video/et61x251/et61x251_sensor.h @@ -52,14 +52,6 @@ et61x251_attach_sensor(struct et61x251_device* cam, /*****************************************************************************/ extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index); -extern int et61x251_read_reg(struct et61x251_device*, u16 index); -extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value); -extern int et61x251_i2c_read(struct et61x251_device*, u8 address); -extern int et61x251_i2c_try_write(struct et61x251_device*, - const struct et61x251_sensor*, u8 address, - u8 value); -extern int et61x251_i2c_try_read(struct et61x251_device*, - const struct et61x251_sensor*, u8 address); extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1, u8 data2, u8 data3, u8 data4, u8 data5, u8 data6, u8 data7, u8 data8, u8 address); diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 29779d8bf7fb..9851987b95fb 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -398,6 +398,7 @@ static int ir_attach(struct i2c_adapter *adap, int addr, case 0x7a: case 0x47: case 0x71: + case 0x2d: if (adap->id == I2C_HW_B_CX2388x) { /* Handled by cx88-input */ name = "CX2388x remote"; @@ -504,7 +505,7 @@ static int ir_probe(struct i2c_adapter *adap) */ static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1}; - static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 }; + static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 }; static const int probe_em28XX[] = { 0x30, 0x47, -1 }; static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 }; static const int probe_cx23885[] = { 0x6b, -1 }; diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index 854cc9c30ca9..270906fc3146 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -3,6 +3,7 @@ config VIDEO_IVTV depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL select I2C_ALGOBIT select FW_LOADER + select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X @@ -12,6 +13,7 @@ config VIDEO_IVTV select VIDEO_SAA7127 select VIDEO_TVAUDIO select VIDEO_CS53L32A + select VIDEO_M52790 select VIDEO_WM8775 select VIDEO_WM8739 select VIDEO_VP27SMPX diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index e8eefd96d897..a0389014fa88 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -6,3 +6,8 @@ ivtv-objs := ivtv-routing.o ivtv-cards.o ivtv-controls.o \ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o + +EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends + diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index b6a8be622d3c..f23c6b8d6911 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -23,6 +23,7 @@ #include "ivtv-i2c.h" #include <media/msp3400.h> +#include <media/m52790.h> #include <media/wm8775.h> #include <media/cs53l32a.h> #include <media/cx25840.h> @@ -39,6 +40,27 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +/* usual i2c tuner addresses to probe */ +static struct ivtv_card_tuner_i2c ivtv_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* as above, but with possible radio tuner */ +static struct ivtv_card_tuner_i2c ivtv_i2c_radio = { + .radio = { 0x60, I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, I2C_CLIENT_END }, +}; + +/* using the tda8290+75a combo */ +static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = { + .radio = { I2C_CLIENT_END }, + .demod = { I2C_CLIENT_END }, + .tv = { 0x4b, I2C_CLIENT_END }, +}; + /********************** card configuration *******************************/ /* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii @@ -72,6 +94,7 @@ static const struct ivtv_card ivtv_card_pvr250 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -126,6 +149,7 @@ static const struct ivtv_card ivtv_card_pvr350 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, }; /* PVR-350 V1 boards have a different audio tuner input and use a @@ -157,6 +181,7 @@ static const struct ivtv_card ivtv_card_pvr350_v1 = { { IVTV_CARD_INPUT_LINE_IN2, MSP_SCART3 }, }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, MSP_SCART2 }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -192,6 +217,7 @@ static const struct ivtv_card ivtv_card_pvr150 = { CX25840_AUDIO_SERIAL, WM8775_AIN4 }, /* apparently needed for the IR blaster */ .gpio_init = { .direction = 0x1f01, .initial_value = 0x26f3 }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -234,6 +260,7 @@ static const struct ivtv_card ivtv_card_m179 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_NTSC }, }, .pci_list = ivtv_pci_m179, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -275,6 +302,7 @@ static const struct ivtv_card ivtv_card_mpg600 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -315,6 +343,7 @@ static const struct ivtv_card ivtv_card_mpg160 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -350,6 +379,7 @@ static const struct ivtv_card ivtv_card_pg600 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -393,6 +423,7 @@ static const struct ivtv_card ivtv_card_avc2410 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_avc2410, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -463,6 +494,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -493,6 +525,7 @@ static const struct ivtv_card ivtv_card_va2000 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -537,6 +570,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, + .i2c = &ivtv_i2c_std, }; static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { @@ -567,6 +601,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, + .i2c = &ivtv_i2c_std, }; static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { @@ -596,6 +631,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -635,6 +671,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -671,6 +708,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -705,6 +743,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -743,6 +782,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -778,6 +818,7 @@ static const struct ivtv_card ivtv_card_yuan_mpc622 = { { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_TDA8290 }, }, .pci_list = ivtv_pci_yuan_mpc622, + .i2c = &ivtv_i2c_tda8290, }; /* ------------------------------------------------------------------------- */ @@ -819,6 +860,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -838,7 +880,7 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .hw_all = IVTV_HW_CX25840, .video_inputs = { { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, @@ -847,10 +889,8 @@ static const struct ivtv_card ivtv_card_pg600v2 = { .audio_inputs = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, - }, .pci_list = ivtv_pci_pg600v2, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -871,17 +911,22 @@ static const struct ivtv_card ivtv_card_club3d = { .hw_audio_ctrl = IVTV_HW_CX25840, .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE3 }, }, .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, + .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, .pci_list = ivtv_pci_club3d, + .i2c = &ivtv_i2c_std, }; /* ------------------------------------------------------------------------- */ @@ -900,7 +945,7 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, .video_inputs = { { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, @@ -909,10 +954,115 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + .pci_list = ivtv_pci_avertv_mce116, + .i2c = &ivtv_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia PVR-150 Plus (M113) card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_pvr150[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc035 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_pvr150 = { + .type = IVTV_CARD_AVER_PVR150PLUS, + .name = "AVerMedia PVR-150 Plus", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_GPIO, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, + CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, 0 }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + .gpio_init = { .direction = 0x0800, .initial_value = 0 }, + .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 }, + /* This card has a Partsnic PTI-5NF05 tuner */ + { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, }, - .pci_list = ivtv_pci_avertv_mce116, + .pci_list = ivtv_pci_aver_pvr150, + .i2c = &ivtv_i2c_radio, +}; + +/* ------------------------------------------------------------------------- */ + +/* AVerMedia EZMaker PCI Deluxe card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_ezmaker[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc03f }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_ezmaker = { + .type = IVTV_CARD_AVER_EZMAKER, + .name = "AVerMedia EZMaker PCI Deluxe", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 0 }, + }, + .gpio_init = { .direction = 0x4000, .initial_value = 0x4000 }, + /* Does not have a tuner */ + .pci_list = ivtv_pci_aver_ezmaker, +}; + +/* ------------------------------------------------------------------------- */ + +/* ASUS Falcon2 */ + +static const struct ivtv_card_pci_info ivtv_pci_asus_falcon2[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b66 }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x462e }, + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_ASUSTEK, 0x4b2e }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_asus_falcon2 = { + .type = IVTV_CARD_ASUS_FALCON2, + .name = "ASUS Falcon2", + .v4l2_capabilities = IVTV_CAP_ENCODER, + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_muxer = IVTV_HW_M52790, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_M52790 | IVTV_HW_TUNER, + .video_inputs = { + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 2, CX25840_COMPOSITE2 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5, M52790_IN_TUNER }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, + M52790_IN_V2 | M52790_SW1_YCMIX | M52790_SW2_YCMIX }, + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, M52790_IN_V2 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, + .tuners = { + { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + }, + .pci_list = ivtv_pci_asus_falcon2, + .i2c = &ivtv_i2c_std, }; static const struct ivtv_card *ivtv_card_list[] = { @@ -937,6 +1087,9 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pg600v2, &ivtv_card_club3d, &ivtv_card_avertv_mce116, + &ivtv_card_asus_falcon2, + &ivtv_card_aver_pvr150, + &ivtv_card_aver_ezmaker, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index ff46e5ae8653..191aafdd9968 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -45,7 +45,10 @@ #define IVTV_CARD_PG600V2 18 /* Yuan PG600V2/GotView PCI DVD Lite */ #define IVTV_CARD_CLUB3D 19 /* Club3D ZAP-TV1x01 */ #define IVTV_CARD_AVERTV_MCE116 20 /* AVerTV MCE 116 Plus */ -#define IVTV_CARD_LAST 20 +#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ +#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ +#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ +#define IVTV_CARD_LAST 23 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -69,6 +72,7 @@ #define IVTV_PCI_ID_HAUPPAUGE_ALT1 0x0270 #define IVTV_PCI_ID_HAUPPAUGE_ALT2 0x4070 #define IVTV_PCI_ID_ADAPTEC 0x9005 +#define IVTV_PCI_ID_ASUSTEK 0x1043 #define IVTV_PCI_ID_AVERMEDIA 0x1461 #define IVTV_PCI_ID_YUAN1 0x12ab #define IVTV_PCI_ID_YUAN2 0xff01 @@ -80,7 +84,7 @@ #define IVTV_PCI_ID_GOTVIEW1 0xffac #define IVTV_PCI_ID_GOTVIEW2 0xffad -/* hardware flags */ +/* hardware flags, no gaps allowed, IVTV_HW_GPIO must always be last */ #define IVTV_HW_CX25840 (1 << 0) #define IVTV_HW_SAA7115 (1 << 1) #define IVTV_HW_SAA7127 (1 << 2) @@ -90,12 +94,12 @@ #define IVTV_HW_CS53L32A (1 << 6) #define IVTV_HW_TVEEPROM (1 << 7) #define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_TVAUDIO (1 << 9) -#define IVTV_HW_UPD64031A (1 << 10) -#define IVTV_HW_UPD6408X (1 << 11) -#define IVTV_HW_SAA717X (1 << 12) -#define IVTV_HW_WM8739 (1 << 13) -#define IVTV_HW_VP27SMPX (1 << 14) +#define IVTV_HW_UPD64031A (1 << 9) +#define IVTV_HW_UPD6408X (1 << 10) +#define IVTV_HW_SAA717X (1 << 11) +#define IVTV_HW_WM8739 (1 << 12) +#define IVTV_HW_VP27SMPX (1 << 13) +#define IVTV_HW_M52790 (1 << 14) #define IVTV_HW_GPIO (1 << 15) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) @@ -230,6 +234,12 @@ struct ivtv_card_tuner { int tuner; /* tuner ID (from tuner.h) */ }; +struct ivtv_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[2];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + /* for card information/parameters */ struct ivtv_card { int type; @@ -257,6 +267,7 @@ struct ivtv_card { struct ivtv_gpio_audio_detect gpio_audio_detect; struct ivtv_card_tuner tuners[IVTV_CARD_MAX_TUNERS]; + struct ivtv_card_tuner_i2c *i2c; /* list of device and subsystem vendor/devices that correspond to this card type. */ diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 6d2dd8764f81..d42f120354e5 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -59,6 +59,7 @@ #include <media/tveeprom.h> #include <media/saa7115.h> #include <media/v4l2-chip-ident.h> +#include "tuner-xc2028.h" /* var to keep track of the number of array elements in use */ int ivtv_cards_active = 0; @@ -185,6 +186,9 @@ MODULE_PARM_DESC(cardtype, "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n" "\t\t\t20 = Club3D ZAP-TV1x01\n" "\t\t\t21 = AverTV MCE 116 Plus\n" + "\t\t\t22 = ASUS Falcon2\n" + "\t\t\t23 = AverMedia PVR-150 Plus\n" + "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); @@ -397,6 +401,7 @@ static void ivtv_process_eeprom(struct ivtv *itv) itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; + itv->card_i2c = itv->card->i2c; /* If this is a PVR500 then it should be possible to detect whether it is the first or second unit by looking at the subsystem device ID: is bit 4 is @@ -414,7 +419,14 @@ static void ivtv_process_eeprom(struct ivtv *itv) This detection is needed since the eeprom reports incorrectly that a radio is present on the second unit. */ if (tv.model / 1000 == 23) { + static const struct ivtv_card_tuner_i2c ivtv_i2c_radio = { + .radio = { 0x60, I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, I2C_CLIENT_END }, + }; + itv->card_name = "WinTV PVR 500"; + itv->card_i2c = &ivtv_i2c_radio; if (pci_slot == 8 || pci_slot == 9) { int is_first = (pci_slot & 1) == 0; @@ -628,10 +640,11 @@ done: IVTV_ERR("Defaulting to %s card\n", itv->card->name); IVTV_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); IVTV_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - IVTV_ERR("Prefix your subject line with [UNKNOWN CARD].\n"); + IVTV_ERR("Prefix your subject line with [UNKNOWN IVTV CARD].\n"); } itv->v4l2_cap = itv->card->v4l2_capabilities; itv->card_name = itv->card->name; + itv->card_i2c = itv->card->i2c; } /* Precondition: the ivtv structure has been memset to 0. Only @@ -695,6 +708,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) atomic_set(&itv->yuv_info.next_dma_frame, -1); itv->yuv_info.lace_mode = ivtv_yuv_mode; itv->yuv_info.lace_threshold = ivtv_yuv_threshold; + itv->yuv_info.max_frames_buffered = 3; return 0; } @@ -812,75 +826,61 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *dev, return 0; } -static void ivtv_request_module(struct ivtv *itv, const char *name) +static u32 ivtv_request_module(struct ivtv *itv, u32 hw, + const char *name, u32 id) { + if ((hw & id) == 0) + return hw; if (request_module(name) != 0) { IVTV_ERR("Failed to load module %s\n", name); - } else { - IVTV_DEBUG_INFO("Loaded module %s\n", name); + return hw & ~id; } + IVTV_DEBUG_INFO("Loaded module %s\n", name); + return hw; } static void ivtv_load_and_init_modules(struct ivtv *itv) { u32 hw = itv->card->hw_all; - int i; + unsigned i; /* load modules */ #ifndef CONFIG_VIDEO_TUNER - if (hw & IVTV_HW_TUNER) { - if (itv->options.tuner == TUNER_XCEIVE_XC3028) { - IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n"); - itv->tunerid = 1; - } - else { - ivtv_request_module(itv, "tuner"); - } - } + hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif #ifndef CONFIG_VIDEO_CX25840 - if (hw & IVTV_HW_CX25840) - ivtv_request_module(itv, "cx25840"); + hw = ivtv_request_module(itv, hw, "cx25840", IVTV_HW_CX25840); #endif #ifndef CONFIG_VIDEO_SAA711X - if (hw & IVTV_HW_SAA711X) - ivtv_request_module(itv, "saa7115"); + hw = ivtv_request_module(itv, hw, "saa7115", IVTV_HW_SAA711X); #endif #ifndef CONFIG_VIDEO_SAA7127 - if (hw & IVTV_HW_SAA7127) - ivtv_request_module(itv, "saa7127"); + hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127); #endif - if (hw & IVTV_HW_SAA717X) - ivtv_request_module(itv, "saa717x"); + hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X); #ifndef CONFIG_VIDEO_UPD64031A - if (hw & IVTV_HW_UPD64031A) - ivtv_request_module(itv, "upd64031a"); + hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A); #endif #ifndef CONFIG_VIDEO_UPD64083 - if (hw & IVTV_HW_UPD6408X) - ivtv_request_module(itv, "upd64083"); + hw = ivtv_request_module(itv, hw, "upd64083", IVTV_HW_UPD6408X); #endif #ifndef CONFIG_VIDEO_MSP3400 - if (hw & IVTV_HW_MSP34XX) - ivtv_request_module(itv, "msp3400"); + hw = ivtv_request_module(itv, hw, "msp3400", IVTV_HW_MSP34XX); #endif #ifndef CONFIG_VIDEO_VP27SMPX - if (hw & IVTV_HW_VP27SMPX) - ivtv_request_module(itv, "vp27smpx"); + hw = ivtv_request_module(itv, hw, "vp27smpx", IVTV_HW_VP27SMPX); #endif - if (hw & IVTV_HW_TVAUDIO) - ivtv_request_module(itv, "tvaudio"); #ifndef CONFIG_VIDEO_WM8775 - if (hw & IVTV_HW_WM8775) - ivtv_request_module(itv, "wm8775"); + hw = ivtv_request_module(itv, hw, "wm8775", IVTV_HW_WM8775); #endif #ifndef CONFIG_VIDEO_WM8739 - if (hw & IVTV_HW_WM8739) - ivtv_request_module(itv, "wm8739"); + hw = ivtv_request_module(itv, hw, "wm8739", IVTV_HW_WM8739); #endif #ifndef CONFIG_VIDEO_CS53L32A - if (hw & IVTV_HW_CS53L32A) - ivtv_request_module(itv, "cs53l32a"); + hw = ivtv_request_module(itv, hw, "cs53l32a", IVTV_HW_CS53L32A); +#endif +#ifndef CONFIG_VIDEO_M52790 + hw = ivtv_request_module(itv, hw, "m52790", IVTV_HW_M52790); #endif /* check which i2c devices are actually found */ @@ -889,11 +889,12 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) if (!(device & hw)) continue; - if (device == IVTV_HW_GPIO) { - /* GPIO is always available */ - itv->hw_flags |= IVTV_HW_GPIO; + if (device == IVTV_HW_GPIO || device == IVTV_HW_TVEEPROM) { + /* GPIO and TVEEPROM do not use i2c probing */ + itv->hw_flags |= device; continue; } + ivtv_i2c_register(itv, i); if (ivtv_i2c_hw_addr(itv, device) > 0) itv->hw_flags |= device; } @@ -964,7 +965,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { int retval = 0; - int yuv_buf_size; int vbi_buf_size; struct ivtv *itv; @@ -979,7 +979,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, } itv = kzalloc(sizeof(struct ivtv), GFP_ATOMIC); - if (itv == 0) { + if (itv == NULL) { spin_unlock(&ivtv_cards_lock); return -ENOMEM; } @@ -1068,9 +1068,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DEBUG_INFO("Active card count: %d.\n", ivtv_cards_active); if (itv->card->hw_all & IVTV_HW_TVEEPROM) { -#ifdef CONFIG_VIDEO_TVEEPROM_MODULE - ivtv_request_module(itv, "tveeprom"); -#endif /* Based on the model number the cardtype may be changed. The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); @@ -1111,16 +1108,19 @@ static int __devinit ivtv_probe(struct pci_dev *dev, itv->is_50hz = 1; itv->is_out_50hz = 1; } + + itv->yuv_info.osd_full_w = 720; + itv->yuv_info.osd_full_h = itv->is_out_50hz ? 576 : 480; + itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w; + itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h; + itv->params.video_gop_size = itv->is_60hz ? 15 : 12; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000; itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200; itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_MPG] = 0x10000; - - /* 0x15180 == 720 * 480 / 4, 0x19500 == 720 * 576 / 4 */ - yuv_buf_size = itv->is_60hz ? 0x15180 : 0x19500; - itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = yuv_buf_size / 2; - itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = yuv_buf_size / 8; + itv->stream_buf_size[IVTV_DEC_STREAM_TYPE_YUV] = 0x10000; + itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_YUV] = 0x08000; /* Setup VBI Raw Size. Should be big enough to hold PAL. It is possible to switch between PAL and NTSC, so we need to @@ -1140,13 +1140,26 @@ static int __devinit ivtv_probe(struct pci_dev *dev, if (itv->options.radio > 0) itv->v4l2_cap |= V4L2_CAP_RADIO; - if (itv->options.tuner > -1 && itv->tunerid == 0) { + if (itv->options.tuner > -1) { struct tuner_setup setup; setup.addr = ADDR_UNSET; setup.type = itv->options.tuner; setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + ivtv_reset_tuner_gpio : NULL; ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = itv->options.tuner, + .priv = &ctrl, + }; + ivtv_call_i2c_clients(itv, TUNER_SET_CONFIG, &cfg); + } } /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 49ce14d14a54..536140f0c19e 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h @@ -65,7 +65,6 @@ #include <linux/ivtv.h> - /* Memory layout */ #define IVTV_ENCODER_OFFSET 0x00000000 #define IVTV_ENCODER_SIZE 0x00800000 /* Total size is 0x01000000, but only first half is used */ @@ -392,6 +391,9 @@ struct yuv_frame_info u32 tru_h; u32 offset_y; s32 lace_mode; + u32 sync_field; + u32 delay; + u32 interlaced; }; #define IVTV_YUV_MODE_INTERLACED 0x00 @@ -403,6 +405,8 @@ struct yuv_frame_info #define IVTV_YUV_SYNC_ODD 0x04 #define IVTV_YUV_SYNC_MASK 0x04 +#define IVTV_YUV_BUFFERS 8 + struct yuv_playback_info { u32 reg_2834; @@ -461,9 +465,10 @@ struct yuv_playback_info u32 osd_vis_w; u32 osd_vis_h; - int decode_height; + u32 osd_full_w; + u32 osd_full_h; - int frame_interlaced; + int decode_height; int lace_mode; int lace_threshold; @@ -475,16 +480,23 @@ struct yuv_playback_info u32 yuv_forced_update; int update_frame; - int sync_field[4]; /* Field to sync on */ - int field_delay[4]; /* Flag to extend duration of previous frame */ u8 fields_lapsed; /* Counter used when delaying a frame */ - struct yuv_frame_info new_frame_info[4]; + struct yuv_frame_info new_frame_info[IVTV_YUV_BUFFERS]; struct yuv_frame_info old_frame_info; struct yuv_frame_info old_frame_info_args; void *blanking_ptr; dma_addr_t blanking_dmaptr; + + int stream_size; + + u8 draw_frame; /* PVR350 buffer to draw into */ + u8 max_frames_buffered; /* Maximum number of frames to buffer */ + + struct v4l2_rect main_rect; + u32 v4l2_src_w; + u32 v4l2_src_h; }; #define IVTV_VBI_FRAMES 32 @@ -577,13 +589,13 @@ struct ivtv { struct pci_dev *dev; /* PCI device */ const struct ivtv_card *card; /* card information */ const char *card_name; /* full name of the card */ + const struct ivtv_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ u8 has_cx23415; /* 1 if it is a cx23415 based card, 0 for cx23416 */ u8 pvr150_workaround; /* 1 if the cx25840 needs to workaround a PVR150 bug */ u8 nof_inputs; /* number of video inputs */ u8 nof_audio_inputs; /* number of audio inputs */ u32 v4l2_cap; /* V4L2 capabilities of card */ u32 hw_flags; /* hardware description of the board */ - int tunerid; /* userspace tuner ID for experimental Xceive tuner support */ v4l2_std_id tuner_std; /* the norm of the card's tuner (fixed) */ /* controlling video decoder function */ int (*video_dec_func)(struct ivtv *, unsigned int, void *); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index a200a8a95a2d..6fb96f19a866 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -542,6 +542,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c struct ivtv_open_id *id = filp->private_data; struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; + struct yuv_playback_info *yi = &itv->yuv_info; struct ivtv_buffer *buf; struct ivtv_queue q; int bytes_written = 0; @@ -580,6 +581,24 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c set_bit(IVTV_F_S_APPL_IO, &s->s_flags); retry: + /* If possible, just DMA the entire frame - Check the data transfer size + since we may get here before the stream has been fully set-up */ + if (mode == OUT_YUV && s->q_full.length == 0 && itv->dma_data_req_size) { + while (count >= itv->dma_data_req_size) { + if (!ivtv_yuv_udma_stream_frame (itv, (void *)user_buf)) { + bytes_written += itv->dma_data_req_size; + user_buf += itv->dma_data_req_size; + count -= itv->dma_data_req_size; + } else { + break; + } + } + if (count == 0) { + IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused); + return bytes_written; + } + } + for (;;) { /* Gather buffers */ while (q.length - q.bytesused < count && (buf = ivtv_dequeue(s, &s->q_io))) @@ -604,9 +623,16 @@ retry: /* copy user data into buffers */ while ((buf = ivtv_dequeue(s, &q))) { - /* Make sure we really got all the user data */ - rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); + /* yuv is a pain. Don't copy more data than needed for a single + frame, otherwise we lose sync with the incoming stream */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && + yi->stream_size + count > itv->dma_data_req_size) + rc = ivtv_buf_copy_from_user(s, buf, user_buf, + itv->dma_data_req_size - yi->stream_size); + else + rc = ivtv_buf_copy_from_user(s, buf, user_buf, count); + /* Make sure we really got all the user data */ if (rc < 0) { ivtv_queue_move(s, &q, NULL, &s->q_free, 0); return rc; @@ -615,6 +641,16 @@ retry: count -= rc; bytes_written += rc; + if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { + yi->stream_size += rc; + /* If we have a complete yuv frame, break loop now */ + if (yi->stream_size == itv->dma_data_req_size) { + ivtv_enqueue(s, buf, &s->q_full); + yi->stream_size = 0; + break; + } + } + if (buf->bytesused != s->buf_size) { /* incomplete, leave in q_io for next time */ ivtv_enqueue(s, buf, &s->q_io); @@ -642,6 +678,9 @@ retry: if (s->q_full.length >= itv->dma_data_req_size) { int got_sig; + if (mode == OUT_YUV) + ivtv_yuv_setup_stream_frame(itv); + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); while (!(got_sig = signal_pending(current)) && test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { @@ -922,10 +961,15 @@ static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp) } /* YUV or MPG Decoding Mode? */ - if (s->type == IVTV_DEC_STREAM_TYPE_MPG) + if (s->type == IVTV_DEC_STREAM_TYPE_MPG) { clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); - else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) + } else if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags); + /* For yuv, we need to know the dma size before we start */ + itv->dma_data_req_size = + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); + itv->yuv_info.stream_size = 0; + } return 0; } diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 132fb5f71366..688cd3856685 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -22,6 +22,7 @@ #include "ivtv-driver.h" #include "ivtv-cards.h" #include "ivtv-gpio.h" +#include "tuner-xc2028.h" #include <media/tuner.h> /* @@ -122,6 +123,29 @@ void ivtv_reset_ir_gpio(struct ivtv *itv) write_reg(curdir, IVTV_REG_GPIO_DIR); } +/* Xceive tuner reset function */ +int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct ivtv *itv = algo->data; + int curdir, curout; + + if (cmd != XC2028_TUNER_RESET) + return 0; + IVTV_DEBUG_INFO("Resetting tuner\n"); + curout = read_reg(IVTV_REG_GPIO_OUT); + curdir = read_reg(IVTV_REG_GPIO_DIR); + curdir |= (1 << 12); /* GPIO bit 12 */ + + curout &= ~(1 << 12); + write_reg(curout, IVTV_REG_GPIO_OUT); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + + curout |= (1 << 12); + write_reg(curout, IVTV_REG_GPIO_OUT); + schedule_timeout_interruptible(msecs_to_jiffies(1)); + return 0; +} void ivtv_gpio_init(struct ivtv *itv) { diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 36e54f78aa2a..fa5ab1eb1800 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -80,6 +80,7 @@ #endif /* I2C_ADAP_CLASS_TV_ANALOG */ #define IVTV_CS53L32A_I2C_ADDR 0x11 +#define IVTV_M52790_I2C_ADDR 0x48 #define IVTV_CX25840_I2C_ADDR 0x44 #define IVTV_SAA7115_I2C_ADDR 0x21 #define IVTV_SAA7127_I2C_ADDR 0x44 @@ -91,7 +92,8 @@ #define IVTV_TEA5767_I2C_ADDR 0x60 #define IVTV_UPD64031A_I2C_ADDR 0x12 #define IVTV_UPD64083_I2C_ADDR 0x5c -#define IVTV_TDA985X_I2C_ADDR 0x5b +#define IVTV_VP27SMPX_I2C_ADDR 0x5b +#define IVTV_M52790_I2C_ADDR 0x48 /* This array should match the IVTV_HW_ defines */ static const u8 hw_driverids[] = { @@ -104,18 +106,38 @@ static const u8 hw_driverids[] = { I2C_DRIVERID_CS53L32A, I2C_DRIVERID_TVEEPROM, I2C_DRIVERID_SAA711X, - I2C_DRIVERID_TVAUDIO, I2C_DRIVERID_UPD64031A, I2C_DRIVERID_UPD64083, I2C_DRIVERID_SAA717X, I2C_DRIVERID_WM8739, I2C_DRIVERID_VP27SMPX, + I2C_DRIVERID_M52790, + 0 /* IVTV_HW_GPIO dummy driver ID */ +}; + +/* This array should match the IVTV_HW_ defines */ +static const u8 hw_addrs[] = { + IVTV_CX25840_I2C_ADDR, + IVTV_SAA7115_I2C_ADDR, + IVTV_SAA7127_I2C_ADDR, + IVTV_MSP3400_I2C_ADDR, + 0, + IVTV_WM8775_I2C_ADDR, + IVTV_CS53L32A_I2C_ADDR, + 0, + IVTV_SAA7115_I2C_ADDR, + IVTV_UPD64031A_I2C_ADDR, + IVTV_UPD64083_I2C_ADDR, + IVTV_SAA717x_I2C_ADDR, + IVTV_WM8739_I2C_ADDR, + IVTV_VP27SMPX_I2C_ADDR, + IVTV_M52790_I2C_ADDR, 0 /* IVTV_HW_GPIO dummy driver ID */ }; /* This array should match the IVTV_HW_ defines */ static const char * const hw_drivernames[] = { - "cx2584x", + "cx25840", "saa7115", "saa7127", "msp3400", @@ -123,31 +145,67 @@ static const char * const hw_drivernames[] = { "wm8775", "cs53l32a", "tveeprom", - "saa7114", - "tvaudio", + "saa7115", "upd64031a", "upd64083", "saa717x", "wm8739", "vp27smpx", + "m52790", "gpio", }; -static int attach_inform(struct i2c_client *client) +int ivtv_i2c_register(struct ivtv *itv, unsigned idx) { - struct ivtv *itv = (struct ivtv *)i2c_get_adapdata(client->adapter); + struct i2c_board_info info; + struct i2c_client *c; + u8 id; int i; - IVTV_DEBUG_I2C("i2c client attach\n"); - for (i = 0; i < I2C_CLIENTS_MAX; i++) { - if (itv->i2c_clients[i] == NULL) { - itv->i2c_clients[i] = client; - break; - } - } + IVTV_DEBUG_I2C("i2c client register\n"); + if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) + return -1; + id = hw_driverids[idx]; + memset(&info, 0, sizeof(info)); + strcpy(info.driver_name, hw_drivernames[idx]); + info.addr = hw_addrs[idx]; + for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} + if (i == I2C_CLIENTS_MAX) { - IVTV_ERR("Insufficient room for new I2C client\n"); + IVTV_ERR("insufficient room for new I2C client!\n"); + return -ENOMEM; } + + if (id != I2C_DRIVERID_TUNER) { + c = i2c_new_device(&itv->i2c_adap, &info); + if (c->driver == NULL) + i2c_unregister_device(c); + else + itv->i2c_clients[i] = c; + return itv->i2c_clients[i] ? 0 : -ENODEV; + } + + /* special tuner handling */ + c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->radio); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + itv->i2c_clients[i++] = c; + c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->demod); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + itv->i2c_clients[i++] = c; + c = i2c_new_probed_device(&itv->i2c_adap, &info, itv->card_i2c->tv); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + itv->i2c_clients[i++] = c; + return 0; +} + +static int attach_inform(struct i2c_client *client) +{ return 0; } @@ -475,9 +533,6 @@ static struct i2c_adapter ivtv_i2c_adap_hw_template = { .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif }; static void ivtv_setscl_old(void *data, int state) @@ -525,15 +580,12 @@ static int ivtv_getsda_old(void *data) /* template for i2c-bit-algo */ static struct i2c_adapter ivtv_i2c_adap_template = { .name = "ivtv i2c driver", - .id = I2C_HW_B_CX2341X, /* algo-bit is OR'd with this */ + .id = I2C_HW_B_CX2341X, .algo = NULL, /* set by i2c-algo-bit */ .algo_data = NULL, /* filled from template */ .client_register = attach_inform, .client_unregister = detach_inform, .owner = THIS_MODULE, -#ifdef I2C_ADAP_CLASS_TV_ANALOG - .class = I2C_ADAP_CLASS_TV_ANALOG, -#endif }; static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { @@ -558,12 +610,9 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg IVTV_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; - if (client == NULL) { - continue; - } - if (client->driver->command == NULL) { + if (client == NULL || client->driver == NULL || + client->driver->command == NULL) continue; - } if (addr == client->addr) { retval = client->driver->command(client, cmd, arg); return retval; @@ -584,7 +633,7 @@ static int ivtv_i2c_id_addr(struct ivtv *itv, u32 id) for (i = 0; i < I2C_CLIENTS_MAX; i++) { client = itv->i2c_clients[i]; - if (client == NULL) + if (client == NULL || client->driver == NULL) continue; if (id == client->driver->id) { retval = client->addr; @@ -710,6 +759,16 @@ int init_ivtv_i2c(struct ivtv *itv) { IVTV_DEBUG_I2C("i2c init\n"); + /* Sanity checks for the I2C hardware arrays. They must be the + * same size and GPIO must be the last entry. + */ + if (ARRAY_SIZE(hw_driverids) != ARRAY_SIZE(hw_addrs) || + ARRAY_SIZE(hw_drivernames) != ARRAY_SIZE(hw_addrs) || + IVTV_HW_GPIO != (1 << (ARRAY_SIZE(hw_addrs) - 1)) || + hw_driverids[ARRAY_SIZE(hw_addrs) - 1]) { + IVTV_ERR("Mismatched I2C hardware arrays\n"); + return -ENODEV; + } if (itv->options.newi2c > 0) { memcpy(&itv->i2c_adap, &ivtv_i2c_adap_hw_template, sizeof(struct i2c_adapter)); @@ -718,9 +777,9 @@ int init_ivtv_i2c(struct ivtv *itv) sizeof(struct i2c_adapter)); memcpy(&itv->i2c_algo, &ivtv_i2c_algo_template, sizeof(struct i2c_algo_bit_data)); - itv->i2c_algo.data = itv; - itv->i2c_adap.algo_data = &itv->i2c_algo; } + itv->i2c_algo.data = itv; + itv->i2c_adap.algo_data = &itv->i2c_algo; sprintf(itv->i2c_adap.name + strlen(itv->i2c_adap.name), " #%d", itv->num); diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h index 987042c09b64..022978cf533d 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.h +++ b/drivers/media/video/ivtv/ivtv-i2c.h @@ -33,6 +33,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg); int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg); int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg); void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg); +int ivtv_i2c_register(struct ivtv *itv, unsigned idx); /* init + register i2c algo-bit adapter */ int init_ivtv_i2c(struct ivtv *itv); diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index fd6826f472e3..edef2a579617 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -372,7 +372,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm fmt->fmt.pix.height = itv->main_rect.height; fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - if (itv->output_mode == OUT_UDMA_YUV) { + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) { case IVTV_YUV_MODE_INTERLACED: fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ? @@ -386,14 +386,13 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm break; } fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; + fmt->fmt.pix.bytesperline = 720; + fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w; + fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ fmt->fmt.pix.sizeimage = - fmt->fmt.pix.height * fmt->fmt.pix.width + - fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); - } - else if (itv->output_mode == OUT_YUV || - streamtype == IVTV_ENC_STREAM_TYPE_YUV || - streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + 1080 * ((fmt->fmt.pix.height + 31) & ~31); + } else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) { fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ fmt->fmt.pix.sizeimage = @@ -490,6 +489,7 @@ static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fm static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt, int set_fmt) { + struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; u16 set; @@ -505,39 +505,52 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype, r.width = fmt->fmt.pix.width; r.height = fmt->fmt.pix.height; ivtv_get_fmt(itv, streamtype, fmt); - if (itv->output_mode != OUT_UDMA_YUV) { - /* TODO: would setting the rect also be valid for this mode? */ - fmt->fmt.pix.width = r.width; - fmt->fmt.pix.height = r.height; - } - if (itv->output_mode == OUT_UDMA_YUV) { - /* TODO: add checks for validity */ + fmt->fmt.pix.width = r.width; + fmt->fmt.pix.height = r.height; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { fmt->fmt.pix.field = field; + if (fmt->fmt.pix.width < 2) + fmt->fmt.pix.width = 2; + if (fmt->fmt.pix.width > 720) + fmt->fmt.pix.width = 720; + if (fmt->fmt.pix.height < 2) + fmt->fmt.pix.height = 2; + if (fmt->fmt.pix.height > 576) + fmt->fmt.pix.height = 576; } - if (set_fmt) { - if (itv->output_mode == OUT_UDMA_YUV) { - switch (field) { - case V4L2_FIELD_NONE: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_PROGRESSIVE; - break; - case V4L2_FIELD_ANY: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_AUTO; - break; - case V4L2_FIELD_INTERLACED_BT: - itv->yuv_info.lace_mode = - IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; - break; - case V4L2_FIELD_INTERLACED_TB: - default: - itv->yuv_info.lace_mode = IVTV_YUV_MODE_INTERLACED; - break; - } - itv->yuv_info.lace_sync_field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + /* Return now if we already have some frame data */ + if (yi->stream_size) + return -EBUSY; - /* Force update of yuv registers */ - itv->yuv_info.yuv_forced_update = 1; - return 0; + yi->v4l2_src_w = r.width; + yi->v4l2_src_h = r.height; + + switch (field) { + case V4L2_FIELD_NONE: + yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE; + break; + case V4L2_FIELD_ANY: + yi->lace_mode = IVTV_YUV_MODE_AUTO; + break; + case V4L2_FIELD_INTERLACED_BT: + yi->lace_mode = + IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD; + break; + case V4L2_FIELD_INTERLACED_TB: + default: + yi->lace_mode = IVTV_YUV_MODE_INTERLACED; + break; } + yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1; + + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + itv->dma_data_req_size = + 1080 * ((yi->v4l2_src_h + 31) & ~31); + + /* Force update of yuv registers */ + yi->yuv_forced_update = 1; + return 0; } return 0; } @@ -660,11 +673,8 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) chip->ident = V4L2_IDENT_NONE; chip->revision = 0; if (reg->match_type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { - struct v4l2_chip_ident *chip = arg; - + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416; - } return 0; } if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) @@ -688,7 +698,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) ivtv_reset_ir_gpio(itv); } if (val & 0x02) { - itv->video_dec_func(itv, cmd, 0); + itv->video_dec_func(itv, cmd, NULL); } break; } @@ -703,8 +713,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void { struct ivtv_open_id *id = NULL; u32 data[CX2341X_MBOX_MAX_DATA]; + int streamtype = 0; - if (filp) id = (struct ivtv_open_id *)filp->private_data; + if (filp) { + id = (struct ivtv_open_id *)filp->private_data; + streamtype = id->type; + } switch (cmd) { case VIDIOC_G_PRIORITY: @@ -822,6 +836,11 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void cropcap->bounds.height = itv->is_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10; cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11; + } else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + cropcap->bounds.width = itv->yuv_info.osd_full_w; + cropcap->bounds.height = itv->yuv_info.osd_full_h; + cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11; } else { cropcap->bounds.height = itv->is_out_50hz ? 576 : 480; cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10; @@ -836,10 +855,15 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, - crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { - itv->main_rect = crop->c; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) { + itv->yuv_info.main_rect = crop->c; return 0; + } else { + if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, + crop->c.width, crop->c.height, crop->c.left, crop->c.top)) { + itv->main_rect = crop->c; + return 0; + } } return -EINVAL; } @@ -853,7 +877,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) { - crop->c = itv->main_rect; + if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) + crop->c = itv->yuv_info.main_rect; + else + crop->c = itv->main_rect; return 0; } if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -864,7 +891,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void case VIDIOC_ENUM_FMT: { static struct v4l2_fmtdesc formats[] = { { 0, 0, 0, - "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, + "HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } }, { 1, 0, V4L2_FMT_FLAG_COMPRESSED, @@ -1043,6 +1070,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void itv->main_rect.height = itv->params.height; ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4, 720, itv->main_rect.height, 0, 0); + itv->yuv_info.main_rect = itv->main_rect; + if (!itv->osd_info) { + itv->yuv_info.osd_full_w = 720; + itv->yuv_info.osd_full_h = + itv->is_out_50hz ? 576 : 480; + } } break; } diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index fd1688e4757d..65604dde9726 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -204,7 +204,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA s->sg_pending[idx].dst = buf->dma_handle; s->sg_pending[idx].src = offset; s->sg_pending[idx].size = s->buf_size; - buf->bytesused = (size < s->buf_size) ? size : s->buf_size; + buf->bytesused = min(size, s->buf_size); buf->dma_xfer_cnt = s->dma_xfer_cnt; s->q_predma.bytesused += buf->bytesused; @@ -302,8 +302,11 @@ static void dma_post(struct ivtv_stream *s) void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) { struct ivtv *itv = s->itv; + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + struct yuv_frame_info *f = &yi->new_frame_info[frame]; struct ivtv_buffer *buf; - u32 y_size = itv->params.height * itv->params.width; + u32 y_size = 720 * ((f->src_h + 31) & ~31); u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET; int y_done = 0; int bytes_written = 0; @@ -311,17 +314,42 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) int idx = 0; IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset); + + /* Insert buffer block for YUV if needed */ + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { + if (yi->blanking_dmaptr) { + s->sg_pending[idx].src = yi->blanking_dmaptr; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = 720 * 16; + } + offset += 720 * 16; + idx++; + } + list_for_each_entry(buf, &s->q_predma.list, list) { /* YUV UV Offset from Y Buffer */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) { + if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && + (bytes_written + buf->bytesused) >= y_size) { + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = y_size - bytes_written; offset = uv_offset; + if (s->sg_pending[idx].size != buf->bytesused) { + idx++; + s->sg_pending[idx].src = + buf->dma_handle + s->sg_pending[idx - 1].size; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = + buf->bytesused - s->sg_pending[idx - 1].size; + offset += s->sg_pending[idx].size; + } y_done = 1; + } else { + s->sg_pending[idx].src = buf->dma_handle; + s->sg_pending[idx].dst = offset; + s->sg_pending[idx].size = buf->bytesused; + offset += buf->bytesused; } - s->sg_pending[idx].src = buf->dma_handle; - s->sg_pending[idx].dst = offset; - s->sg_pending[idx].size = buf->bytesused; - - offset += buf->bytesused; bytes_written += buf->bytesused; /* Sync SG buffers */ @@ -408,7 +436,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s) s_vbi->sg_pending_size = 0; s_vbi->dma_xfer_cnt++; set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags); - IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name); + IVTV_DEBUG_HI_DMA("include DMA for %s\n", s_vbi->name); } s->dma_xfer_cnt++; @@ -700,12 +728,15 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) ivtv_api_get_data(&itv->dec_mbox, IVTV_MBOX_DMA, data); if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) { - itv->dma_data_req_size = itv->params.width * itv->params.height * 3 / 2; - itv->dma_data_req_offset = data[1] ? data[1] : yuv_offset[0]; + itv->dma_data_req_size = + 1080 * ((itv->yuv_info.v4l2_src_h + 31) & ~31); + itv->dma_data_req_offset = data[1]; + if (atomic_read(&itv->yuv_info.next_dma_frame) >= 0) + ivtv_yuv_frame_complete(itv); s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV]; } else { - itv->dma_data_req_size = data[2] >= 0x10000 ? 0x10000 : data[2]; + itv->dma_data_req_size = min_t(u32, data[2], 0x10000); itv->dma_data_req_offset = data[1]; s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG]; } @@ -715,6 +746,8 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv) set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); } else { + if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) + ivtv_yuv_setup_stream_frame(itv); clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags); ivtv_queue_move(s, &s->q_full, NULL, &s->q_predma, itv->dma_data_req_size); ivtv_dma_stream_dec_prepare(s, itv->dma_data_req_offset + IVTV_DECODER_OFFSET, 0); @@ -731,24 +764,26 @@ static void ivtv_irq_vsync(struct ivtv *itv) * one vsync per frame. */ unsigned int frame = read_reg(0x28c0) & 1; + struct yuv_playback_info *yi = &itv->yuv_info; int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); + struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); - if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 && - ((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) || - (frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) { + if (((frame ^ f->sync_field) == 0 && + ((itv->last_vsync_field & 1) ^ f->sync_field)) || + (frame != (itv->last_vsync_field & 1) && !f->interlaced)) { int next_dma_frame = last_dma_frame; - if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) { - if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) { + if (!(f->interlaced && f->delay && yi->fields_lapsed < 1)) { + if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&yi->next_fill_frame)) { write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); write_reg(yuv_offset[next_dma_frame] >> 4, 0x834); write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - next_dma_frame = (next_dma_frame + 1) & 0x3; - atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame); - itv->yuv_info.fields_lapsed = -1; + next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; + atomic_set(&yi->next_dma_frame, next_dma_frame); + yi->fields_lapsed = -1; } } } @@ -781,20 +816,22 @@ static void ivtv_irq_vsync(struct ivtv *itv) } /* Check if we need to update the yuv registers */ - if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) { - if (!itv->yuv_info.new_frame_info[last_dma_frame].update) - last_dma_frame = (last_dma_frame - 1) & 3; - - if (itv->yuv_info.new_frame_info[last_dma_frame].src_w) { - itv->yuv_info.update_frame = last_dma_frame; - itv->yuv_info.new_frame_info[last_dma_frame].update = 0; - itv->yuv_info.yuv_forced_update = 0; + if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) { + if (!f->update) { + last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS; + f = &yi->new_frame_info[last_dma_frame]; + } + + if (f->src_w) { + yi->update_frame = last_dma_frame; + f->update = 0; + yi->yuv_forced_update = 0; set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags); set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } } - itv->yuv_info.fields_lapsed ++; + yi->fields_lapsed++; } } diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c index b05436da7136..13a6c374d2db 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.c +++ b/drivers/media/video/ivtv/ivtv-mailbox.c @@ -333,7 +333,7 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]) return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res; } -int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { return ivtv_api(priv, cmd, in, data); } diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h index 71a54eef8fc7..6ef12091e3f3 100644 --- a/drivers/media/video/ivtv/ivtv-mailbox.h +++ b/drivers/media/video/ivtv/ivtv-mailbox.h @@ -28,6 +28,6 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]); int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]); int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...); int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...); -int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); +int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]); #endif diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c index 398bd33033ed..05564919b57f 100644 --- a/drivers/media/video/ivtv/ivtv-routing.c +++ b/drivers/media/video/ivtv/ivtv-routing.c @@ -25,6 +25,7 @@ #include "ivtv-routing.h" #include <media/msp3400.h> +#include <media/m52790.h> #include <media/upd64031a.h> #include <media/upd64083.h> @@ -32,28 +33,26 @@ settings. */ void ivtv_audio_set_io(struct ivtv *itv) { + const struct ivtv_card_audio_input *in; struct v4l2_routing route; - u32 audio_input; - int mux_input; /* Determine which input to use */ - if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - audio_input = itv->card->radio_input.audio_input; - mux_input = itv->card->radio_input.muxer_input; - } else { - audio_input = itv->card->audio_inputs[itv->audio_input].audio_input; - mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input; - } + if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) + in = &itv->card->radio_input; + else + in = &itv->card->audio_inputs[itv->audio_input]; /* handle muxer chips */ - route.input = mux_input; + route.input = in->muxer_input; route.output = 0; + if (itv->card->hw_muxer & IVTV_HW_M52790) + route.output = M52790_OUT_STEREO; ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); - route.input = audio_input; - if (itv->card->hw_audio & IVTV_HW_MSP34XX) { + route.input = in->audio_input; + route.output = 0; + if (itv->card->hw_audio & IVTV_HW_MSP34XX) route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - } ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route); } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 74fb0e021979..24d98ecf35ad 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -43,7 +43,7 @@ #include "ivtv-cards.h" #include "ivtv-streams.h" -static struct file_operations ivtv_v4l2_enc_fops = { +static const struct file_operations ivtv_v4l2_enc_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -53,7 +53,7 @@ static struct file_operations ivtv_v4l2_enc_fops = { .poll = ivtv_v4l2_enc_poll, }; -static struct file_operations ivtv_v4l2_dec_fops = { +static const struct file_operations ivtv_v4l2_dec_fops = { .owner = THIS_MODULE, .read = ivtv_v4l2_read, .write = ivtv_v4l2_write, @@ -572,10 +572,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) clear_bit(IVTV_F_I_EOS, &itv->i_flags); /* Initialize Digitizer for Capture */ - itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0); + itv->video_dec_func(itv, VIDIOC_STREAMOFF, NULL); ivtv_msleep_timeout(300, 1); ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0); - itv->video_dec_func(itv, VIDIOC_STREAMON, 0); + itv->video_dec_func(itv, VIDIOC_STREAMON, NULL); } /* begin_capture */ @@ -661,27 +661,12 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset) IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset); - /* Clear Streamoff */ - if (s->type == IVTV_DEC_STREAM_TYPE_YUV) { - /* Initialize Decoder */ - /* Reprogram Decoder YUV Buffers for YUV */ - write_reg(yuv_offset[0] >> 4, 0x82c); - write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830); - write_reg(yuv_offset[0] >> 4, 0x834); - write_reg((yuv_offset[0] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838); - - write_reg_sync(0x00000000 | (0x0c << 16) | (0x0b << 8), 0x2d24); - - write_reg_sync(0x00108080, 0x2898); - /* Enable YUV decoder output */ - write_reg_sync(0x01, IVTV_REG_VDM); - } - ivtv_setup_v4l2_decode_stream(s); /* set dma size to 65536 bytes */ ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536); + /* Clear Streamoff */ clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags); /* Zero out decoder counters */ diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index d050de2a7229..0f1d4cc4b4d9 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -22,7 +22,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 1 +#define IVTV_DRIVER_VERSION_MINOR 2 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c index 9091c4837bbc..85183480a225 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.c +++ b/drivers/media/video/ivtv/ivtv-yuv.c @@ -22,32 +22,37 @@ #include "ivtv-udma.h" #include "ivtv-yuv.h" -const u32 yuv_offset[4] = { - IVTV_YUV_BUFFER_OFFSET, - IVTV_YUV_BUFFER_OFFSET_1, - IVTV_YUV_BUFFER_OFFSET_2, - IVTV_YUV_BUFFER_OFFSET_3 +/* YUV buffer offsets */ +const u32 yuv_offset[IVTV_YUV_BUFFERS] = { + 0x001a8600, + 0x00240400, + 0x002d8200, + 0x00370000, + 0x00029000, + 0x000C0E00, + 0x006B0400, + 0x00748200 }; static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, - struct ivtv_dma_frame *args) + struct ivtv_dma_frame *args) { struct ivtv_dma_page_info y_dma; struct ivtv_dma_page_info uv_dma; - + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + struct yuv_frame_info *f = &yi->new_frame_info[frame]; int i; int y_pages, uv_pages; - unsigned long y_buffer_offset, uv_buffer_offset; int y_decode_height, uv_decode_height, y_size; - int frame = atomic_read(&itv->yuv_info.next_fill_frame); y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame]; uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET; - y_decode_height = uv_decode_height = args->src.height + args->src.top; + y_decode_height = uv_decode_height = f->src_h + f->src_y; - if (y_decode_height < 512-16) + if (f->offset_y) y_buffer_offset += 720 * 16; if (y_decode_height & 15) @@ -60,8 +65,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* Still in USE */ if (dma->SG_length || dma->page_count) { - IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n", - dma->SG_length, dma->page_count); + IVTV_DEBUG_WARN + ("prep_user_dma: SG_length %d page_count %d still full?\n", + dma->SG_length, dma->page_count); return -EBUSY; } @@ -77,8 +83,9 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->page_count = y_dma.page_count + uv_dma.page_count; if (y_pages + uv_pages != dma->page_count) { - IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n", - y_pages + uv_pages, dma->page_count); + IVTV_DEBUG_WARN + ("failed to map user pages, returned %d instead of %d\n", + y_pages + uv_pages, dma->page_count); for (i = 0; i < dma->page_count; i++) { put_page(dma->map[i]); @@ -99,16 +106,14 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE); /* Fill SG Array with new values */ - ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size); + ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); /* If we've offset the y plane, ensure top area is blanked */ - if (args->src.height + args->src.top < 512-16) { - if (itv->yuv_info.blanking_dmaptr) { - dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); - dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr); - dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); - dma->SG_length++; - } + if (f->offset_y && yi->blanking_dmaptr) { + dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); + dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); + dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); + dma->SG_length++; } /* Tag SG Array with Interrupt Bit */ @@ -121,11 +126,11 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, /* We rely on a table held in the firmware - Quick check. */ int ivtv_yuv_filter_check(struct ivtv *itv) { - int i, offset_y, offset_uv; + int i, y, uv; - for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) { - if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) || - (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) { + for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) { + if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) || + (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) { IVTV_WARN ("YUV filter table not found in firmware.\n"); return -1; } @@ -135,69 +140,67 @@ int ivtv_yuv_filter_check(struct ivtv *itv) static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2) { - int filter_index, filter_line; + u32 i, line; /* If any filter is -1, then don't update it */ if (h_filter > -1) { - if (h_filter > 4) h_filter = 4; - filter_index = h_filter * 384; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814); - write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c); - filter_index += 8; + if (h_filter > 4) + h_filter = 4; + i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x02804); + write_reg(read_dec(i), 0x0281c); + i += 4; + write_reg(read_dec(i), 0x02808); + write_reg(read_dec(i), 0x02820); + i += 4; + write_reg(read_dec(i), 0x0280c); + write_reg(read_dec(i), 0x02824); + i += 4; + write_reg(read_dec(i), 0x02810); + write_reg(read_dec(i), 0x02828); + i += 4; + write_reg(read_dec(i), 0x02814); + write_reg(read_dec(i), 0x0282c); + i += 8; write_reg(0, 0x02818); write_reg(0, 0x02830); - filter_line ++; } - IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter); + IVTV_DEBUG_YUV("h_filter -> %d\n", h_filter); } if (v_filter_1 > -1) { - if (v_filter_1 > 4) v_filter_1 = 4; - filter_index = v_filter_1 * 192; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904); - filter_index += 8; + if (v_filter_1 > 4) + v_filter_1 = 4; + i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_1 * 192); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x02900); + i += 4; + write_reg(read_dec(i), 0x02904); + i += 8; write_reg(0, 0x02908); - filter_line ++; } - IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1); + IVTV_DEBUG_YUV("v_filter_1 -> %d\n", v_filter_1); } if (v_filter_2 > -1) { - if (v_filter_2 > 4) v_filter_2 = 4; - filter_index = v_filter_2 * 192; - filter_line = 0; - while (filter_line < 16) { - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c); - filter_index += 4; - write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910); - filter_index += 8; + if (v_filter_2 > 4) + v_filter_2 = 4; + i = IVTV_YUV_VERTICAL_FILTER_OFFSET + (v_filter_2 * 192); + for (line = 0; line < 16; line++) { + write_reg(read_dec(i), 0x0290c); + i += 4; + write_reg(read_dec(i), 0x02910); + i += 8; write_reg(0, 0x02914); - filter_line ++; } - IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2); + IVTV_DEBUG_YUV("v_filter_2 -> %d\n", v_filter_2); } } -static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window) +static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *f) { + struct yuv_playback_info *yi = &itv->yuv_info; u32 reg_2834, reg_2838, reg_283c; u32 reg_2844, reg_2854, reg_285c; u32 reg_2864, reg_2874, reg_2890; @@ -206,18 +209,19 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * int h_filter; u32 master_width; - IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", - window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x); + IVTV_DEBUG_WARN + ("Adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n", + f->tru_w, f->src_w, f->dst_w, f->src_x, f->dst_x); /* How wide is the src image */ - x_cutoff = window->src_w + window->src_x; + x_cutoff = f->src_w + f->src_x; /* Set the display width */ - reg_2834 = window->dst_w; + reg_2834 = f->dst_w; reg_2838 = reg_2834; /* Set the display position */ - reg_2890 = window->dst_x; + reg_2890 = f->dst_x; /* Index into the image horizontally */ reg_2870 = 0; @@ -228,32 +232,31 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * Gradually adjust the offset to avoid the video 'snapping' left/right if it gets dragged through this region. Only do this if osd is full width. */ - if (window->vis_w == 720) { - if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){ - reg_2870 = 10 - (window->tru_x - window->pan_x) / 4; - } - else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) { - reg_2870 = (10 + (window->tru_x - window->pan_x) / 2); - } + if (f->vis_w == 720) { + if ((f->tru_x - f->pan_x > -1) && (f->tru_x - f->pan_x <= 40) && (f->dst_w >= 680)) + reg_2870 = 10 - (f->tru_x - f->pan_x) / 4; + else if ((f->tru_x - f->pan_x < 0) && (f->tru_x - f->pan_x >= -20) && (f->dst_w >= 660)) + reg_2870 = (10 + (f->tru_x - f->pan_x) / 2); - if (window->dst_w >= window->src_w) + if (f->dst_w >= f->src_w) reg_2870 = reg_2870 << 16 | reg_2870; else reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1); } - if (window->dst_w < window->src_w) + if (f->dst_w < f->src_w) reg_2870 = 0x000d000e - reg_2870; else reg_2870 = 0x0012000e - reg_2870; /* We're also using 2870 to shift the image left (src_x & negative dst_x) */ - reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19; + reg_2870_offset = (f->src_x * ((f->dst_w << 21) / f->src_w)) >> 19; - if (window->dst_w >= window->src_w) { + if (f->dst_w >= f->src_w) { x_cutoff &= ~1; - master_width = (window->src_w * 0x00200000) / (window->dst_w); - if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++; + master_width = (f->src_w * 0x00200000) / (f->dst_w); + if (master_width * f->dst_w != f->src_w * 0x00200000) + master_width++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -264,17 +267,17 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * /* We also need to factor in the scaling (src_w - dst_w) / (src_w / 4) */ - if (window->dst_w > window->src_w) - reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14); + if (f->dst_w > f->src_w) + reg_2870_base = ((f->dst_w - f->src_w)<<16) / (f->src_w <<14); else reg_2870_base = 0; reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base); reg_2874 = 0; - } - else if (window->dst_w < window->src_w / 2) { - master_width = (window->src_w * 0x00080000) / window->dst_w; - if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++; + } else if (f->dst_w < f->src_w / 2) { + master_width = (f->src_w * 0x00080000) / f->dst_w; + if (master_width * f->dst_w != f->src_w * 0x00080000) + master_width++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -282,13 +285,13 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * reg_2854 = master_width; reg_285c = master_width >> 1; reg_2864 = master_width >> 1; - reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset); - reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16; + reg_2870 += ((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset; + reg_2870 += (5 - (((f->src_w + f->src_w / 2) - 1) / f->dst_w)) << 16; reg_2874 = 0x00000012; - } - else { - master_width = (window->src_w * 0x00100000) / window->dst_w; - if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++; + } else { + master_width = (f->src_w * 0x00100000) / f->dst_w; + if (master_width * f->dst_w != f->src_w * 0x00100000) + master_width++; reg_2834 = (reg_2834 << 16) | x_cutoff; reg_2838 = (reg_2838 << 16) | x_cutoff; reg_283c = master_width >> 2; @@ -296,62 +299,70 @@ static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info * reg_2854 = master_width; reg_285c = master_width >> 1; reg_2864 = master_width >> 1; - reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1); - reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16; + reg_2870 += ((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1; + reg_2870 += (5 - (((f->src_w * 3) - 1) / f->dst_w)) << 16; reg_2874 = 0x00000001; } /* Select the horizontal filter */ - if (window->src_w == window->dst_w) { + if (f->src_w == f->dst_w) { /* An exact size match uses filter 0 */ h_filter = 0; - } - else { + } else { /* Figure out which filter to use */ - h_filter = ((window->src_w << 16) / window->dst_w) >> 15; + h_filter = ((f->src_w << 16) / f->dst_w) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0 */ - if (h_filter == 0) h_filter = 1; + h_filter += !h_filter; } write_reg(reg_2834, 0x02834); write_reg(reg_2838, 0x02838); - IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838); + IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n", + yi->reg_2834, reg_2834, yi->reg_2838, reg_2838); write_reg(reg_283c, 0x0283c); write_reg(reg_2844, 0x02844); - IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844); + IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n", + yi->reg_283c, reg_283c, yi->reg_2844, reg_2844); write_reg(0x00080514, 0x02840); write_reg(0x00100514, 0x02848); - IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514); + IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n", + yi->reg_2840, 0x00080514, yi->reg_2848, 0x00100514); write_reg(reg_2854, 0x02854); - IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854); + IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n", + yi->reg_2854, reg_2854); write_reg(reg_285c, 0x0285c); write_reg(reg_2864, 0x02864); - IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864); + IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n", + yi->reg_285c, reg_285c, yi->reg_2864, reg_2864); write_reg(reg_2874, 0x02874); - IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874); + IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n", + yi->reg_2874, reg_2874); write_reg(reg_2870, 0x02870); - IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870); + IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n", + yi->reg_2870, reg_2870); - write_reg( reg_2890,0x02890); - IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890); + write_reg(reg_2890, 0x02890); + IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n", + yi->reg_2890, reg_2890); /* Only update the filter if we really need to */ - if (h_filter != itv->yuv_info.h_filter) { - ivtv_yuv_filter (itv,h_filter,-1,-1); - itv->yuv_info.h_filter = h_filter; + if (h_filter != yi->h_filter) { + ivtv_yuv_filter(itv, h_filter, -1, -1); + yi->h_filter = h_filter; } } -static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window) +static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) { + struct yuv_playback_info *yi = &itv->yuv_info; u32 master_height; u32 reg_2918, reg_291c, reg_2920, reg_2928; u32 reg_2930, reg_2934, reg_293c; @@ -359,69 +370,59 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi u32 reg_2950, reg_2954, reg_2958, reg_295c; u32 reg_2960, reg_2964, reg_2968, reg_296c; u32 reg_289c; - u32 src_y_major_y, src_y_minor_y; - u32 src_y_major_uv, src_y_minor_uv; + u32 src_major_y, src_minor_y; + u32 src_major_uv, src_minor_uv; u32 reg_2964_base, reg_2968_base; int v_filter_1, v_filter_2; - IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", - window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y); + IVTV_DEBUG_WARN + ("Adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n", + f->tru_h, f->src_h, f->dst_h, f->src_y, f->dst_y); /* What scaling mode is being used... */ - if (window->interlaced_y) { - IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n"); - } - else { - IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n"); - } + IVTV_DEBUG_YUV("Scaling mode Y: %s\n", + f->interlaced_y ? "Interlaced" : "Progressive"); - if (window->interlaced_uv) { - IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n"); - } - else { - IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n"); - } + IVTV_DEBUG_YUV("Scaling mode UV: %s\n", + f->interlaced_uv ? "Interlaced" : "Progressive"); /* What is the source video being treated as... */ - if (itv->yuv_info.frame_interlaced) { - IVTV_DEBUG_WARN("Source video: Interlaced\n"); - } - else { - IVTV_DEBUG_WARN("Source video: Non-interlaced\n"); - } + IVTV_DEBUG_WARN("Source video: %s\n", + f->interlaced ? "Interlaced" : "Progressive"); /* We offset into the image using two different index methods, so split the y source coord into two parts. */ - if (window->src_y < 8) { - src_y_minor_uv = window->src_y; - src_y_major_uv = 0; - } - else { - src_y_minor_uv = 8; - src_y_major_uv = window->src_y - 8; + if (f->src_y < 8) { + src_minor_uv = f->src_y; + src_major_uv = 0; + } else { + src_minor_uv = 8; + src_major_uv = f->src_y - 8; } - src_y_minor_y = src_y_minor_uv; - src_y_major_y = src_y_major_uv; + src_minor_y = src_minor_uv; + src_major_y = src_major_uv; - if (window->offset_y) src_y_minor_y += 16; + if (f->offset_y) + src_minor_y += 16; - if (window->interlaced_y) - reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y); + if (f->interlaced_y) + reg_2918 = (f->dst_h << 16) | (f->src_h + src_minor_y); else - reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1); + reg_2918 = (f->dst_h << 16) | ((f->src_h + src_minor_y) << 1); - if (window->interlaced_uv) - reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1); + if (f->interlaced_uv) + reg_291c = (f->dst_h << 16) | ((f->src_h + src_minor_uv) >> 1); else - reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv); + reg_291c = (f->dst_h << 16) | (f->src_h + src_minor_uv); - reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14; - reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14; + reg_2964_base = (src_minor_y * ((f->dst_h << 16) / f->src_h)) >> 14; + reg_2968_base = (src_minor_uv * ((f->dst_h << 16) / f->src_h)) >> 14; - if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) { - master_height = (window->src_h * 0x00400000) / window->dst_h; - if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++; + if (f->dst_h / 2 >= f->src_h && !f->interlaced_y) { + master_height = (f->src_h * 0x00400000) / f->dst_h; + if ((f->src_h * 0x00400000) - (master_height * f->dst_h) >= f->dst_h / 2) + master_height++; reg_2920 = master_height >> 2; reg_2928 = master_height >> 3; reg_2930 = master_height; @@ -429,45 +430,42 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi reg_2964_base >>= 3; reg_2968_base >>= 3; reg_296c = 0x00000000; - } - else if (window->dst_h >= window->src_h) { - master_height = (window->src_h * 0x00400000) / window->dst_h; + } else if (f->dst_h >= f->src_h) { + master_height = (f->src_h * 0x00400000) / f->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; reg_2930 = master_height; reg_2940 = master_height >> 1; reg_296c = 0x00000000; - if (window->interlaced_y) { + if (f->interlaced_y) { reg_2964_base >>= 3; - } - else { - reg_296c ++; + } else { + reg_296c++; reg_2964_base >>= 2; } - if (window->interlaced_uv) reg_2928 >>= 1; + if (f->interlaced_uv) + reg_2928 >>= 1; reg_2968_base >>= 3; - } - else if (window->dst_h >= window->src_h / 2) { - master_height = (window->src_h * 0x00200000) / window->dst_h; + } else if (f->dst_h >= f->src_h / 2) { + master_height = (f->src_h * 0x00200000) / f->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; reg_2930 = master_height; reg_2940 = master_height; reg_296c = 0x00000101; - if (window->interlaced_y) { + if (f->interlaced_y) { reg_2964_base >>= 2; - } - else { - reg_296c ++; + } else { + reg_296c++; reg_2964_base >>= 1; } - if (window->interlaced_uv) reg_2928 >>= 1; + if (f->interlaced_uv) + reg_2928 >>= 1; reg_2968_base >>= 2; - } - else { - master_height = (window->src_h * 0x00100000) / window->dst_h; + } else { + master_height = (f->src_h * 0x00100000) / f->dst_h; master_height = (master_height >> 1) + (master_height & 1); reg_2920 = master_height >> 2; reg_2928 = master_height >> 2; @@ -480,13 +478,12 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi /* FIXME These registers change depending on scaled / unscaled output We really need to work out what they should be */ - if (window->src_h == window->dst_h){ + if (f->src_h == f->dst_h) { reg_2934 = 0x00020000; reg_293c = 0x00100000; reg_2944 = 0x00040000; reg_294c = 0x000b0000; - } - else { + } else { reg_2934 = 0x00000FF0; reg_293c = 0x00000FF0; reg_2944 = 0x00000FF0; @@ -494,34 +491,36 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi } /* The first line to be displayed */ - reg_2950 = 0x00010000 + src_y_major_y; - if (window->interlaced_y) reg_2950 += 0x00010000; + reg_2950 = 0x00010000 + src_major_y; + if (f->interlaced_y) + reg_2950 += 0x00010000; reg_2954 = reg_2950 + 1; - reg_2958 = 0x00010000 + (src_y_major_y >> 1); - if (window->interlaced_uv) reg_2958 += 0x00010000; + reg_2958 = 0x00010000 + (src_major_y >> 1); + if (f->interlaced_uv) + reg_2958 += 0x00010000; reg_295c = reg_2958 + 1; - if (itv->yuv_info.decode_height == 480) + if (yi->decode_height == 480) reg_289c = 0x011e0017; else reg_289c = 0x01500017; - if (window->dst_y < 0) - reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1); + if (f->dst_y < 0) + reg_289c = (reg_289c - ((f->dst_y & ~1)<<15))-(f->dst_y >>1); else - reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1); + reg_289c = (reg_289c + ((f->dst_y & ~1)<<15))+(f->dst_y >>1); /* How much of the source to decode. Take into account the source offset */ - reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) | - ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15); + reg_2960 = ((src_minor_y + f->src_h + src_major_y) - 1) | + (((src_minor_uv + f->src_h + src_major_uv - 1) & ~1) << 15); /* Calculate correct value for register 2964 */ - if (window->src_h == window->dst_h) + if (f->src_h == f->dst_h) { reg_2964 = 1; - else { - reg_2964 = 2 + ((window->dst_h << 1) / window->src_h); + } else { + reg_2964 = 2 + ((f->dst_h << 1) / f->src_h); reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1); } reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1); @@ -536,283 +535,246 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *wi /* Deviate further from what it should be. I find the flicker headache inducing so try to reduce it slightly. Leave 2968 as-is otherwise colours foul. */ - if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h)) - reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2); + if ((reg_2964 != 0x00010001) && (f->dst_h / 2 <= f->src_h)) + reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF) / 2); - if (!window->interlaced_y) reg_2964 -= 0x00010001; - if (!window->interlaced_uv) reg_2968 -= 0x00010001; + if (!f->interlaced_y) + reg_2964 -= 0x00010001; + if (!f->interlaced_uv) + reg_2968 -= 0x00010001; reg_2964 += ((reg_2964_base << 16) | reg_2964_base); reg_2968 += ((reg_2968_base << 16) | reg_2968_base); /* Select the vertical filter */ - if (window->src_h == window->dst_h) { + if (f->src_h == f->dst_h) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; - } - else { + } else { /* Figure out which filter to use */ - v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15; + v_filter_1 = ((f->src_h << 16) / f->dst_h) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ - if (v_filter_1 == 0) v_filter_1 = 1; + v_filter_1 += !v_filter_1; v_filter_2 = v_filter_1; } write_reg(reg_2934, 0x02934); write_reg(reg_293c, 0x0293c); - IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c); + IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n", + yi->reg_2934, reg_2934, yi->reg_293c, reg_293c); write_reg(reg_2944, 0x02944); write_reg(reg_294c, 0x0294c); - IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c); + IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n", + yi->reg_2944, reg_2944, yi->reg_294c, reg_294c); /* Ensure 2970 is 0 (does it ever change ?) */ /* write_reg(0,0x02970); */ -/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */ +/* IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n", yi->reg_2970, 0); */ write_reg(reg_2930, 0x02938); write_reg(reg_2930, 0x02930); - IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930); + IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n", + yi->reg_2930, reg_2930, yi->reg_2938, reg_2930); write_reg(reg_2928, 0x02928); - write_reg(reg_2928+0x514, 0x0292C); - IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514); + write_reg(reg_2928 + 0x514, 0x0292C); + IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n", + yi->reg_2928, reg_2928, yi->reg_292c, reg_2928 + 0x514); write_reg(reg_2920, 0x02920); - write_reg(reg_2920+0x514, 0x02924); - IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920); + write_reg(reg_2920 + 0x514, 0x02924); + IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n", + yi->reg_2920, reg_2920, yi->reg_2924, reg_2920 + 0x514); - write_reg (reg_2918,0x02918); - write_reg (reg_291c,0x0291C); - IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c); + write_reg(reg_2918, 0x02918); + write_reg(reg_291c, 0x0291C); + IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n", + yi->reg_2918, reg_2918, yi->reg_291c, reg_291c); write_reg(reg_296c, 0x0296c); - IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c); + IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n", + yi->reg_296c, reg_296c); write_reg(reg_2940, 0x02948); write_reg(reg_2940, 0x02940); - IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940); + IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n", + yi->reg_2940, reg_2940, yi->reg_2948, reg_2940); write_reg(reg_2950, 0x02950); write_reg(reg_2954, 0x02954); - IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954); + IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n", + yi->reg_2950, reg_2950, yi->reg_2954, reg_2954); write_reg(reg_2958, 0x02958); write_reg(reg_295c, 0x0295C); - IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c); + IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n", + yi->reg_2958, reg_2958, yi->reg_295c, reg_295c); write_reg(reg_2960, 0x02960); - IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960); + IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n", + yi->reg_2960, reg_2960); write_reg(reg_2964, 0x02964); write_reg(reg_2968, 0x02968); - IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968); + IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n", + yi->reg_2964, reg_2964, yi->reg_2968, reg_2968); - write_reg( reg_289c,0x0289c); - IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c); + write_reg(reg_289c, 0x0289c); + IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n", + yi->reg_289c, reg_289c); /* Only update filter 1 if we really need to */ - if (v_filter_1 != itv->yuv_info.v_filter_1) { - ivtv_yuv_filter (itv,-1,v_filter_1,-1); - itv->yuv_info.v_filter_1 = v_filter_1; + if (v_filter_1 != yi->v_filter_1) { + ivtv_yuv_filter(itv, -1, v_filter_1, -1); + yi->v_filter_1 = v_filter_1; } /* Only update filter 2 if we really need to */ - if (v_filter_2 != itv->yuv_info.v_filter_2) { - ivtv_yuv_filter (itv,-1,-1,v_filter_2); - itv->yuv_info.v_filter_2 = v_filter_2; + if (v_filter_2 != yi->v_filter_2) { + ivtv_yuv_filter(itv, -1, -1, v_filter_2); + yi->v_filter_2 = v_filter_2; } - } /* Modify the supplied coordinate information to fit the visible osd area */ -static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window) +static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f) { - int osd_crop, lace_threshold; + struct yuv_frame_info *of = &itv->yuv_info.old_frame_info; + int osd_crop; u32 osd_scale; u32 yuv_update = 0; - lace_threshold = itv->yuv_info.lace_threshold; - if (lace_threshold < 0) - lace_threshold = itv->yuv_info.decode_height - 1; - - /* Work out the lace settings */ - switch (itv->yuv_info.lace_mode) { - case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ - itv->yuv_info.frame_interlaced = 0; - if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021)) - window->interlaced_y = 0; - else - window->interlaced_y = 1; - - if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) - window->interlaced_uv = 0; - else - window->interlaced_uv = 1; - break; - - case IVTV_YUV_MODE_AUTO: - if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){ - itv->yuv_info.frame_interlaced = 0; - if ((window->tru_h < 512) || - (window->tru_h > 576 && window->tru_h < 1021) || - (window->tru_w > 720 && window->tru_h < 1021)) - window->interlaced_y = 0; - else - window->interlaced_y = 1; - - if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2)) - window->interlaced_uv = 0; - else - window->interlaced_uv = 1; - } - else { - itv->yuv_info.frame_interlaced = 1; - window->interlaced_y = 1; - window->interlaced_uv = 1; - } - break; - - case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ - default: - itv->yuv_info.frame_interlaced = 1; - window->interlaced_y = 1; - window->interlaced_uv = 1; - break; - } - /* Sorry, but no negative coords for src */ - if (window->src_x < 0) window->src_x = 0; - if (window->src_y < 0) window->src_y = 0; + if (f->src_x < 0) + f->src_x = 0; + if (f->src_y < 0) + f->src_y = 0; /* Can only reduce width down to 1/4 original size */ - if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) { - window->src_x += osd_crop / 2; - window->src_w = (window->src_w - osd_crop) & ~3; - window->dst_w = window->src_w / 4; - window->dst_w += window->dst_w & 1; + if ((osd_crop = f->src_w - 4 * f->dst_w) > 0) { + f->src_x += osd_crop / 2; + f->src_w = (f->src_w - osd_crop) & ~3; + f->dst_w = f->src_w / 4; + f->dst_w += f->dst_w & 1; } /* Can only reduce height down to 1/4 original size */ - if (window->src_h / window->dst_h >= 2) { - /* Overflow may be because we're running progressive, so force mode switch */ - window->interlaced_y = 1; + if (f->src_h / f->dst_h >= 2) { + /* Overflow may be because we're running progressive, + so force mode switch */ + f->interlaced_y = 1; /* Make sure we're still within limits for interlace */ - if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) { + if ((osd_crop = f->src_h - 4 * f->dst_h) > 0) { /* If we reach here we'll have to force the height. */ - window->src_y += osd_crop / 2; - window->src_h = (window->src_h - osd_crop) & ~3; - window->dst_h = window->src_h / 4; - window->dst_h += window->dst_h & 1; + f->src_y += osd_crop / 2; + f->src_h = (f->src_h - osd_crop) & ~3; + f->dst_h = f->src_h / 4; + f->dst_h += f->dst_h & 1; } } /* If there's nothing to safe to display, we may as well stop now */ - if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { + if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || + (int)f->src_w <= 2 || (int)f->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Ensure video remains inside OSD area */ - osd_scale = (window->src_h << 16) / window->dst_h; + osd_scale = (f->src_h << 16) / f->dst_h; - if ((osd_crop = window->pan_y - window->dst_y) > 0) { + if ((osd_crop = f->pan_y - f->dst_y) > 0) { /* Falls off the upper edge - crop */ - window->src_y += (osd_scale * osd_crop) >> 16; - window->src_h -= (osd_scale * osd_crop) >> 16; - window->dst_h -= osd_crop; - window->dst_y = 0; - } - else { - window->dst_y -= window->pan_y; + f->src_y += (osd_scale * osd_crop) >> 16; + f->src_h -= (osd_scale * osd_crop) >> 16; + f->dst_h -= osd_crop; + f->dst_y = 0; + } else { + f->dst_y -= f->pan_y; } - if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) { + if ((osd_crop = f->dst_h + f->dst_y - f->vis_h) > 0) { /* Falls off the lower edge - crop */ - window->dst_h -= osd_crop; - window->src_h -= (osd_scale * osd_crop) >> 16; + f->dst_h -= osd_crop; + f->src_h -= (osd_scale * osd_crop) >> 16; } - osd_scale = (window->src_w << 16) / window->dst_w; + osd_scale = (f->src_w << 16) / f->dst_w; - if ((osd_crop = window->pan_x - window->dst_x) > 0) { + if ((osd_crop = f->pan_x - f->dst_x) > 0) { /* Fall off the left edge - crop */ - window->src_x += (osd_scale * osd_crop) >> 16; - window->src_w -= (osd_scale * osd_crop) >> 16; - window->dst_w -= osd_crop; - window->dst_x = 0; - } - else { - window->dst_x -= window->pan_x; + f->src_x += (osd_scale * osd_crop) >> 16; + f->src_w -= (osd_scale * osd_crop) >> 16; + f->dst_w -= osd_crop; + f->dst_x = 0; + } else { + f->dst_x -= f->pan_x; } - if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) { + if ((osd_crop = f->dst_w + f->dst_x - f->vis_w) > 0) { /* Falls off the right edge - crop */ - window->dst_w -= osd_crop; - window->src_w -= (osd_scale * osd_crop) >> 16; + f->dst_w -= osd_crop; + f->src_w -= (osd_scale * osd_crop) >> 16; } /* The OSD can be moved. Track to it */ - window->dst_x += itv->yuv_info.osd_x_offset; - window->dst_y += itv->yuv_info.osd_y_offset; + f->dst_x += itv->yuv_info.osd_x_offset; + f->dst_y += itv->yuv_info.osd_y_offset; /* Width & height for both src & dst must be even. Same for coordinates. */ - window->dst_w &= ~1; - window->dst_x &= ~1; + f->dst_w &= ~1; + f->dst_x &= ~1; - window->src_w += window->src_x & 1; - window->src_x &= ~1; + f->src_w += f->src_x & 1; + f->src_x &= ~1; - window->src_w &= ~1; - window->dst_w &= ~1; + f->src_w &= ~1; + f->dst_w &= ~1; - window->dst_h &= ~1; - window->dst_y &= ~1; + f->dst_h &= ~1; + f->dst_y &= ~1; - window->src_h += window->src_y & 1; - window->src_y &= ~1; + f->src_h += f->src_y & 1; + f->src_y &= ~1; - window->src_h &= ~1; - window->dst_h &= ~1; + f->src_h &= ~1; + f->dst_h &= ~1; - /* Due to rounding, we may have reduced the output size to <1/4 of the source - Check again, but this time just resize. Don't change source coordinates */ - if (window->dst_w < window->src_w / 4) { - window->src_w &= ~3; - window->dst_w = window->src_w / 4; - window->dst_w += window->dst_w & 1; + /* Due to rounding, we may have reduced the output size to <1/4 of + the source. Check again, but this time just resize. Don't change + source coordinates */ + if (f->dst_w < f->src_w / 4) { + f->src_w &= ~3; + f->dst_w = f->src_w / 4; + f->dst_w += f->dst_w & 1; } - if (window->dst_h < window->src_h / 4) { - window->src_h &= ~3; - window->dst_h = window->src_h / 4; - window->dst_h += window->dst_h & 1; + if (f->dst_h < f->src_h / 4) { + f->src_h &= ~3; + f->dst_h = f->src_h / 4; + f->dst_h += f->dst_h & 1; } /* Check again. If there's nothing to safe to display, stop now */ - if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) { + if ((int)f->dst_w <= 2 || (int)f->dst_h <= 2 || + (int)f->src_w <= 2 || (int)f->src_h <= 2) { return IVTV_YUV_UPDATE_INVALID; } /* Both x offset & width are linked, so they have to be done together */ - if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) || - (itv->yuv_info.old_frame_info.src_w != window->src_w) || - (itv->yuv_info.old_frame_info.dst_x != window->dst_x) || - (itv->yuv_info.old_frame_info.src_x != window->src_x) || - (itv->yuv_info.old_frame_info.pan_x != window->pan_x) || - (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) { + if ((of->dst_w != f->dst_w) || (of->src_w != f->src_w) || + (of->dst_x != f->dst_x) || (of->src_x != f->src_x) || + (of->pan_x != f->pan_x) || (of->vis_w != f->vis_w)) { yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL; } - if ((itv->yuv_info.old_frame_info.src_h != window->src_h) || - (itv->yuv_info.old_frame_info.dst_h != window->dst_h) || - (itv->yuv_info.old_frame_info.dst_y != window->dst_y) || - (itv->yuv_info.old_frame_info.src_y != window->src_y) || - (itv->yuv_info.old_frame_info.pan_y != window->pan_y) || - (itv->yuv_info.old_frame_info.vis_h != window->vis_h) || - (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) || - (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) || - (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) { + if ((of->src_h != f->src_h) || (of->dst_h != f->dst_h) || + (of->dst_y != f->dst_y) || (of->src_y != f->src_y) || + (of->pan_y != f->pan_y) || (of->vis_h != f->vis_h) || + (of->lace_mode != f->lace_mode) || + (of->interlaced_y != f->interlaced_y) || + (of->interlaced_uv != f->interlaced_uv)) { yuv_update |= IVTV_YUV_UPDATE_VERTICAL; } @@ -820,24 +782,24 @@ static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *windo } /* Update the scaling register to the requested value */ -void ivtv_yuv_work_handler (struct ivtv *itv) +void ivtv_yuv_work_handler(struct ivtv *itv) { - struct yuv_frame_info window; + struct yuv_playback_info *yi = &itv->yuv_info; + struct yuv_frame_info f; + int frame = yi->update_frame; u32 yuv_update; - int frame = itv->yuv_info.update_frame; - -/* IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */ - memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window)); + IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame); + f = yi->new_frame_info[frame]; /* Update the osd pan info */ - window.pan_x = itv->yuv_info.osd_x_pan; - window.pan_y = itv->yuv_info.osd_y_pan; - window.vis_w = itv->yuv_info.osd_vis_w; - window.vis_h = itv->yuv_info.osd_vis_h; + f.pan_x = yi->osd_x_pan; + f.pan_y = yi->osd_y_pan; + f.vis_w = yi->osd_vis_w; + f.vis_h = yi->osd_vis_h; /* Calculate the display window coordinates. Exit if nothing left */ - if (!(yuv_update = ivtv_yuv_window_setup (itv, &window))) + if (!(yuv_update = ivtv_yuv_window_setup(itv, &f))) return; if (yuv_update & IVTV_YUV_UPDATE_INVALID) { @@ -846,16 +808,15 @@ void ivtv_yuv_work_handler (struct ivtv *itv) write_reg(0x00108080, 0x2898); if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL) - ivtv_yuv_handle_horizontal(itv, &window); + ivtv_yuv_handle_horizontal(itv, &f); if (yuv_update & IVTV_YUV_UPDATE_VERTICAL) - ivtv_yuv_handle_vertical(itv, &window); + ivtv_yuv_handle_vertical(itv, &f); } - - memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info)); + yi->old_frame_info = f; } -static void ivtv_yuv_init (struct ivtv *itv) +static void ivtv_yuv_init(struct ivtv *itv) { struct yuv_playback_info *yi = &itv->yuv_info; @@ -924,25 +885,23 @@ static void ivtv_yuv_init (struct ivtv *itv) if (!yi->osd_vis_w) yi->osd_vis_w = 720 - yi->osd_x_offset; - if (!yi->osd_vis_h) + if (!yi->osd_vis_h) { yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - else { + } else if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { /* If output video standard has changed, requested height may - not be legal */ - if (yi->osd_vis_h + yi->osd_y_offset > yi->decode_height) { - IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", - yi->osd_vis_h + yi->osd_y_offset, - yi->decode_height); - yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; - } + not be legal */ + IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n", + yi->osd_vis_h + yi->osd_y_offset, + yi->decode_height); + yi->osd_vis_h = yi->decode_height - yi->osd_y_offset; } } /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */ - yi->blanking_ptr = kzalloc(720*16, GFP_KERNEL); - if (yi->blanking_ptr) + yi->blanking_ptr = kzalloc(720 * 16, GFP_KERNEL); + if (yi->blanking_ptr) { yi->blanking_dmaptr = pci_map_single(itv->dev, yi->blanking_ptr, 720*16, PCI_DMA_TODEVICE); - else { + } else { yi->blanking_dmaptr = 0; IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); } @@ -954,77 +913,140 @@ static void ivtv_yuv_init (struct ivtv *itv) atomic_set(&yi->next_dma_frame, 0); } -int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +/* Get next available yuv buffer on PVR350 */ +void ivtv_yuv_next_free(struct ivtv *itv) { - DEFINE_WAIT(wait); - int rc = 0; - int got_sig = 0; - int frame, next_fill_frame, last_fill_frame; - int register_update = 0; + int draw, display; + struct yuv_playback_info *yi = &itv->yuv_info; - IVTV_DEBUG_INFO("yuv_prep_frame\n"); + if (atomic_read(&yi->next_dma_frame) == -1) + ivtv_yuv_init(itv); - if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv); + draw = atomic_read(&yi->next_fill_frame); + display = atomic_read(&yi->next_dma_frame); - frame = atomic_read(&itv->yuv_info.next_fill_frame); - next_fill_frame = (frame + 1) & 0x3; - last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3; + if (display > draw) + display -= IVTV_YUV_BUFFERS; - if (next_fill_frame != last_fill_frame && last_fill_frame != frame) { - /* Buffers are full - Overwrite the last frame */ - next_fill_frame = frame; - frame = (frame - 1) & 3; - register_update = itv->yuv_info.new_frame_info[frame].update; - } + if (draw - display >= yi->max_frames_buffered) + draw = (u8)(draw - 1) % IVTV_YUV_BUFFERS; + else + yi->new_frame_info[draw].update = 0; + + yi->draw_frame = draw; +} + +/* Set up frame according to ivtv_dma_frame parameters */ +void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + u8 frame = yi->draw_frame; + u8 last_frame = (u8)(frame - 1) % IVTV_YUV_BUFFERS; + struct yuv_frame_info *nf = &yi->new_frame_info[frame]; + struct yuv_frame_info *of = &yi->new_frame_info[last_frame]; + int lace_threshold = yi->lace_threshold; + + /* Preserve old update flag in case we're overwriting a queued frame */ + int update = nf->update; /* Take a snapshot of the yuv coordinate information */ - itv->yuv_info.new_frame_info[frame].src_x = args->src.left; - itv->yuv_info.new_frame_info[frame].src_y = args->src.top; - itv->yuv_info.new_frame_info[frame].src_w = args->src.width; - itv->yuv_info.new_frame_info[frame].src_h = args->src.height; - itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top; - itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width; - itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height; - itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left; - itv->yuv_info.new_frame_info[frame].tru_w = args->src_width; - itv->yuv_info.new_frame_info[frame].tru_h = args->src_height; - - /* Snapshot field order */ - itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field; + nf->src_x = args->src.left; + nf->src_y = args->src.top; + nf->src_w = args->src.width; + nf->src_h = args->src.height; + nf->dst_x = args->dst.left; + nf->dst_y = args->dst.top; + nf->dst_w = args->dst.width; + nf->dst_h = args->dst.height; + nf->tru_x = args->dst.left; + nf->tru_w = args->src_width; + nf->tru_h = args->src_height; /* Are we going to offset the Y plane */ - if (args->src.height + args->src.top < 512-16) - itv->yuv_info.new_frame_info[frame].offset_y = 1; - else - itv->yuv_info.new_frame_info[frame].offset_y = 0; + nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0; /* Snapshot the osd pan info */ - itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan; - itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan; - itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w; - itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h; - - itv->yuv_info.new_frame_info[frame].update = 0; - itv->yuv_info.new_frame_info[frame].interlaced_y = 0; - itv->yuv_info.new_frame_info[frame].interlaced_uv = 0; - itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode; - - if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], - sizeof (itv->yuv_info.new_frame_info[frame]))) { - memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args)); - itv->yuv_info.new_frame_info[frame].update = 1; -/* IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */ + nf->pan_x = yi->osd_x_pan; + nf->pan_y = yi->osd_y_pan; + nf->vis_w = yi->osd_vis_w; + nf->vis_h = yi->osd_vis_h; + + nf->update = 0; + nf->interlaced_y = 0; + nf->interlaced_uv = 0; + nf->delay = 0; + nf->sync_field = 0; + nf->lace_mode = yi->lace_mode & IVTV_YUV_MODE_MASK; + + if (lace_threshold < 0) + lace_threshold = yi->decode_height - 1; + + /* Work out the lace settings */ + switch (nf->lace_mode) { + case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */ + nf->interlaced = 0; + if (nf->tru_h < 512 || (nf->tru_h > 576 && nf->tru_h < 1021)) + nf->interlaced_y = 0; + else + nf->interlaced_y = 1; + + if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) + nf->interlaced_uv = 0; + else + nf->interlaced_uv = 1; + break; + + case IVTV_YUV_MODE_AUTO: + if (nf->tru_h <= lace_threshold || nf->tru_h > 576 || nf->tru_w > 720) { + nf->interlaced = 0; + if ((nf->tru_h < 512) || + (nf->tru_h > 576 && nf->tru_h < 1021) || + (nf->tru_w > 720 && nf->tru_h < 1021)) + nf->interlaced_y = 0; + else + nf->interlaced_y = 1; + if (nf->tru_h < 1021 && (nf->dst_h >= nf->src_h / 2)) + nf->interlaced_uv = 0; + else + nf->interlaced_uv = 1; + } else { + nf->interlaced = 1; + nf->interlaced_y = 1; + nf->interlaced_uv = 1; + } + break; + + case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */ + default: + nf->interlaced = 1; + nf->interlaced_y = 1; + nf->interlaced_uv = 1; + break; } - itv->yuv_info.new_frame_info[frame].update |= register_update; + if (memcmp(&yi->old_frame_info_args, nf, sizeof(*nf))) { + yi->old_frame_info_args = *nf; + nf->update = 1; + IVTV_DEBUG_YUV("Requesting reg update for frame %d\n", frame); + } - /* Should this frame be delayed ? */ - if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3]) - itv->yuv_info.field_delay[frame] = 1; - else - itv->yuv_info.field_delay[frame] = 0; + nf->update |= update; + nf->sync_field = yi->lace_sync_field; + nf->delay = nf->sync_field != of->sync_field; +} +/* Frame is complete & ready for display */ +void ivtv_yuv_frame_complete(struct ivtv *itv) +{ + atomic_set(&itv->yuv_info.next_fill_frame, + (itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS); +} + +int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ + DEFINE_WAIT(wait); + int rc = 0; + int got_sig = 0; /* DMA the frame */ mutex_lock(&itv->udma.lock); @@ -1036,10 +1058,10 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) ivtv_udma_prepare(itv); prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); /* if no UDMA is pending and no UDMA is in progress, then the DMA - is finished */ + is finished */ while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) { /* don't interrupt if the DMA is in progress but break off - a still pending DMA. */ + a still pending DMA. */ got_sig = signal_pending(current); if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) break; @@ -1057,99 +1079,148 @@ int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) return -EINTR; } - atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame); + ivtv_yuv_frame_complete(itv); mutex_unlock(&itv->udma.lock); return rc; } +/* Setup frame according to V4L2 parameters */ +void ivtv_yuv_setup_stream_frame(struct ivtv *itv) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_dma_frame dma_args; + + ivtv_yuv_next_free(itv); + + /* Copy V4L2 parameters to an ivtv_dma_frame struct... */ + dma_args.y_source = 0L; + dma_args.uv_source = 0L; + dma_args.src.left = 0; + dma_args.src.top = 0; + dma_args.src.width = yi->v4l2_src_w; + dma_args.src.height = yi->v4l2_src_h; + dma_args.dst = yi->main_rect; + dma_args.src_width = yi->v4l2_src_w; + dma_args.src_height = yi->v4l2_src_h; + + /* ... and use the same setup routine as ivtv_yuv_prep_frame */ + ivtv_yuv_setup_frame(itv, &dma_args); + + if (!itv->dma_data_req_offset) + itv->dma_data_req_offset = yuv_offset[yi->draw_frame]; +} + +/* Attempt to dma a frame from a user buffer */ +int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src) +{ + struct yuv_playback_info *yi = &itv->yuv_info; + struct ivtv_dma_frame dma_args; + + ivtv_yuv_setup_stream_frame(itv); + + /* We only need to supply source addresses for this */ + dma_args.y_source = src; + dma_args.uv_source = src + 720 * ((yi->v4l2_src_h + 31) & ~31); + return ivtv_yuv_udma_frame(itv, &dma_args); +} + +/* IVTV_IOC_DMA_FRAME ioctl handler */ +int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args) +{ +/* IVTV_DEBUG_INFO("yuv_prep_frame\n"); */ + + ivtv_yuv_next_free(itv); + ivtv_yuv_setup_frame(itv, args); + return ivtv_yuv_udma_frame(itv, args); +} + void ivtv_yuv_close(struct ivtv *itv) { + struct yuv_playback_info *yi = &itv->yuv_info; int h_filter, v_filter_1, v_filter_2; IVTV_DEBUG_YUV("ivtv_yuv_close\n"); ivtv_waitq(&itv->vsync_waitq); - atomic_set(&itv->yuv_info.next_dma_frame, -1); - atomic_set(&itv->yuv_info.next_fill_frame, 0); + atomic_set(&yi->next_dma_frame, -1); + atomic_set(&yi->next_fill_frame, 0); /* Reset registers we have changed so mpeg playback works */ /* If we fully restore this register, the display may remain active. Restore, but set one bit to blank the video. Firmware will always clear this bit when needed, so not a problem. */ - write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898); - - write_reg(itv->yuv_info.reg_2834, 0x02834); - write_reg(itv->yuv_info.reg_2838, 0x02838); - write_reg(itv->yuv_info.reg_283c, 0x0283c); - write_reg(itv->yuv_info.reg_2840, 0x02840); - write_reg(itv->yuv_info.reg_2844, 0x02844); - write_reg(itv->yuv_info.reg_2848, 0x02848); - write_reg(itv->yuv_info.reg_2854, 0x02854); - write_reg(itv->yuv_info.reg_285c, 0x0285c); - write_reg(itv->yuv_info.reg_2864, 0x02864); - write_reg(itv->yuv_info.reg_2870, 0x02870); - write_reg(itv->yuv_info.reg_2874, 0x02874); - write_reg(itv->yuv_info.reg_2890, 0x02890); - write_reg(itv->yuv_info.reg_289c, 0x0289c); - - write_reg(itv->yuv_info.reg_2918, 0x02918); - write_reg(itv->yuv_info.reg_291c, 0x0291c); - write_reg(itv->yuv_info.reg_2920, 0x02920); - write_reg(itv->yuv_info.reg_2924, 0x02924); - write_reg(itv->yuv_info.reg_2928, 0x02928); - write_reg(itv->yuv_info.reg_292c, 0x0292c); - write_reg(itv->yuv_info.reg_2930, 0x02930); - write_reg(itv->yuv_info.reg_2934, 0x02934); - write_reg(itv->yuv_info.reg_2938, 0x02938); - write_reg(itv->yuv_info.reg_293c, 0x0293c); - write_reg(itv->yuv_info.reg_2940, 0x02940); - write_reg(itv->yuv_info.reg_2944, 0x02944); - write_reg(itv->yuv_info.reg_2948, 0x02948); - write_reg(itv->yuv_info.reg_294c, 0x0294c); - write_reg(itv->yuv_info.reg_2950, 0x02950); - write_reg(itv->yuv_info.reg_2954, 0x02954); - write_reg(itv->yuv_info.reg_2958, 0x02958); - write_reg(itv->yuv_info.reg_295c, 0x0295c); - write_reg(itv->yuv_info.reg_2960, 0x02960); - write_reg(itv->yuv_info.reg_2964, 0x02964); - write_reg(itv->yuv_info.reg_2968, 0x02968); - write_reg(itv->yuv_info.reg_296c, 0x0296c); - write_reg(itv->yuv_info.reg_2970, 0x02970); + write_reg(yi->reg_2898 | 0x01000000, 0x2898); + + write_reg(yi->reg_2834, 0x02834); + write_reg(yi->reg_2838, 0x02838); + write_reg(yi->reg_283c, 0x0283c); + write_reg(yi->reg_2840, 0x02840); + write_reg(yi->reg_2844, 0x02844); + write_reg(yi->reg_2848, 0x02848); + write_reg(yi->reg_2854, 0x02854); + write_reg(yi->reg_285c, 0x0285c); + write_reg(yi->reg_2864, 0x02864); + write_reg(yi->reg_2870, 0x02870); + write_reg(yi->reg_2874, 0x02874); + write_reg(yi->reg_2890, 0x02890); + write_reg(yi->reg_289c, 0x0289c); + + write_reg(yi->reg_2918, 0x02918); + write_reg(yi->reg_291c, 0x0291c); + write_reg(yi->reg_2920, 0x02920); + write_reg(yi->reg_2924, 0x02924); + write_reg(yi->reg_2928, 0x02928); + write_reg(yi->reg_292c, 0x0292c); + write_reg(yi->reg_2930, 0x02930); + write_reg(yi->reg_2934, 0x02934); + write_reg(yi->reg_2938, 0x02938); + write_reg(yi->reg_293c, 0x0293c); + write_reg(yi->reg_2940, 0x02940); + write_reg(yi->reg_2944, 0x02944); + write_reg(yi->reg_2948, 0x02948); + write_reg(yi->reg_294c, 0x0294c); + write_reg(yi->reg_2950, 0x02950); + write_reg(yi->reg_2954, 0x02954); + write_reg(yi->reg_2958, 0x02958); + write_reg(yi->reg_295c, 0x0295c); + write_reg(yi->reg_2960, 0x02960); + write_reg(yi->reg_2964, 0x02964); + write_reg(yi->reg_2968, 0x02968); + write_reg(yi->reg_296c, 0x0296c); + write_reg(yi->reg_2970, 0x02970); /* Prepare to restore filters */ /* First the horizontal filter */ - if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) { + if ((yi->reg_2834 & 0x0000FFFF) == (yi->reg_2834 >> 16)) { /* An exact size match uses filter 0 */ h_filter = 0; - } - else { + } else { /* Figure out which filter to use */ - h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15; + h_filter = ((yi->reg_2834 << 16) / (yi->reg_2834 >> 16)) >> 15; h_filter = (h_filter >> 1) + (h_filter & 1); /* Only an exact size match can use filter 0. */ - if (h_filter < 1) h_filter = 1; + h_filter += !h_filter; } /* Now the vertical filter */ - if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) { + if ((yi->reg_2918 & 0x0000FFFF) == (yi->reg_2918 >> 16)) { /* An exact size match uses filter 0/1 */ v_filter_1 = 0; v_filter_2 = 1; - } - else { + } else { /* Figure out which filter to use */ - v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15; + v_filter_1 = ((yi->reg_2918 << 16) / (yi->reg_2918 >> 16)) >> 15; v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1); /* Only an exact size match can use filter 0 */ - if (v_filter_1 == 0) v_filter_1 = 1; + v_filter_1 += !v_filter_1; v_filter_2 = v_filter_1; } /* Now restore the filters */ - ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2); + ivtv_yuv_filter(itv, h_filter, v_filter_1, v_filter_2); /* and clear a few registers */ write_reg(0, 0x02814); @@ -1158,19 +1229,18 @@ void ivtv_yuv_close(struct ivtv *itv) write_reg(0, 0x02910); /* Release the blanking buffer */ - if (itv->yuv_info.blanking_ptr) { - kfree (itv->yuv_info.blanking_ptr); - itv->yuv_info.blanking_ptr = NULL; - pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); + if (yi->blanking_ptr) { + kfree(yi->blanking_ptr); + yi->blanking_ptr = NULL; + pci_unmap_single(itv->dev, yi->blanking_dmaptr, 720*16, PCI_DMA_TODEVICE); } /* Invalidate the old dimension information */ - itv->yuv_info.old_frame_info.src_w = 0; - itv->yuv_info.old_frame_info.src_h = 0; - itv->yuv_info.old_frame_info_args.src_w = 0; - itv->yuv_info.old_frame_info_args.src_h = 0; + yi->old_frame_info.src_w = 0; + yi->old_frame_info.src_h = 0; + yi->old_frame_info_args.src_w = 0; + yi->old_frame_info_args.src_h = 0; /* All done. */ clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags); } - diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h index 3b966f0a204a..2fe5f1250762 100644 --- a/drivers/media/video/ivtv/ivtv-yuv.h +++ b/drivers/media/video/ivtv/ivtv-yuv.h @@ -21,11 +21,6 @@ #ifndef IVTV_YUV_H #define IVTV_YUV_H -/* Buffers on hardware offsets */ -#define IVTV_YUV_BUFFER_OFFSET 0x001a8600 /* First YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_1 0x00240400 /* Second YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_2 0x002d8200 /* Third YUV Buffer */ -#define IVTV_YUV_BUFFER_OFFSET_3 0x00370000 /* Fourth YUV Buffer */ #define IVTV_YUV_BUFFER_UV_OFFSET 0x65400 /* Offset to UV Buffer */ /* Offset to filter table in firmware */ @@ -36,11 +31,14 @@ #define IVTV_YUV_UPDATE_VERTICAL 0x02 #define IVTV_YUV_UPDATE_INVALID 0x04 -extern const u32 yuv_offset[4]; +extern const u32 yuv_offset[IVTV_YUV_BUFFERS]; int ivtv_yuv_filter_check(struct ivtv *itv); +void ivtv_yuv_setup_stream_frame(struct ivtv *itv); +int ivtv_yuv_udma_stream_frame(struct ivtv *itv, void *src); +void ivtv_yuv_frame_complete(struct ivtv *itv); int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args); void ivtv_yuv_close(struct ivtv *itv); -void ivtv_yuv_work_handler (struct ivtv *itv); +void ivtv_yuv_work_handler(struct ivtv *itv); #endif diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 52ffd154a3d8..3b23fc05f7c4 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -504,6 +504,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var) ivtvfb_set_display_window(itv, &ivtv_window); + /* Pass screen size back to yuv handler */ + itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride; + itv->yuv_info.osd_full_h = ivtv_osd.lines; + /* Force update of yuv registers */ itv->yuv_info.yuv_forced_update = 1; @@ -1053,7 +1057,7 @@ static int ivtvfb_init_card(struct ivtv *itv) } itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC); - if (itv->osd_info == 0) { + if (itv->osd_info == NULL) { IVTVFB_ERR("Failed to allocate memory for osd_info\n"); return -ENOMEM; } diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c index b6cd21e6dab9..4895540be195 100644 --- a/drivers/media/video/ks0127.c +++ b/drivers/media/video/ks0127.c @@ -764,7 +764,6 @@ static struct i2c_client ks0127_client_tmpl = .addr = 0, .adapter = NULL, .driver = &i2c_driver_ks0127, - .usage_count = 0 }; static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind) diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c new file mode 100644 index 000000000000..d4bf14c284ef --- /dev/null +++ b/drivers/media/video/m52790.c @@ -0,0 +1,168 @@ +/* + * m52790 i2c ivtv driver. + * Copyright (C) 2007 Hans Verkuil + * + * A/V source switching Mitsubishi M52790SP/FP + * + * 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 <linux/module.h> +#include <linux/types.h> +#include <linux/ioctl.h> +#include <asm/uaccess.h> +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/videodev.h> +#include <media/m52790.h> +#include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> + +MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + + +struct m52790_state { + u16 input; + u16 output; +}; + +/* ----------------------------------------------------------------------- */ + +static int m52790_write(struct i2c_client *client) +{ + struct m52790_state *state = i2c_get_clientdata(client); + u8 sw1 = (state->input | state->output) & 0xff; + u8 sw2 = (state->input | state->output) >> 8; + + return i2c_smbus_write_byte_data(client, sw1, sw2); +} + +static int m52790_command(struct i2c_client *client, unsigned int cmd, + void *arg) +{ + struct m52790_state *state = i2c_get_clientdata(client); + struct v4l2_routing *route = arg; + + /* Note: audio and video are linked and cannot be switched separately. + So audio and video routing commands are identical for this chip. + In theory the video amplifier and audio modes could be handled + separately for the output, but that seems to be overkill right now. + The same holds for implementing an audio mute control, this is now + part of the audio output routing. The normal case is that another + chip takes care of the actual muting so making it part of the + output routing seems to be the right thing to do for now. */ + switch (cmd) { + case VIDIOC_INT_G_AUDIO_ROUTING: + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->input; + route->output = state->output; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_S_VIDEO_ROUTING: + state->input = route->input; + state->output = route->output; + m52790_write(client); + break; + +#ifdef CONFIG_VIDEO_ADV_DEBUG + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + { + struct v4l2_register *reg = arg; + + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (reg->reg != 0) + return -EINVAL; + if (cmd == VIDIOC_DBG_G_REGISTER) + reg->val = state->input | state->output; + else { + state->input = reg->val & 0x0303; + state->output = reg->val & ~0x0303; + m52790_write(client); + } + break; + } +#endif + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_M52790, 0); + + case VIDIOC_LOG_STATUS: + v4l_info(client, "Switch 1: %02x\n", + (state->input | state->output) & 0xff); + v4l_info(client, "Switch 2: %02x\n", + (state->input | state->output) >> 8); + break; + + default: + return -EINVAL; + } + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* i2c implementation */ + +static int m52790_probe(struct i2c_client *client) +{ + struct m52790_state *state; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + snprintf(client->name, sizeof(client->name) - 1, "m52790"); + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = kmalloc(sizeof(struct m52790_state), GFP_KERNEL); + if (state == NULL) + return -ENOMEM; + + state->input = M52790_IN_TUNER; + state->output = M52790_OUT_STEREO; + i2c_set_clientdata(client, state); + m52790_write(client); + return 0; +} + +static int m52790_remove(struct i2c_client *client) +{ + kfree(i2c_get_clientdata(client)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "m52790", + .driverid = I2C_DRIVERID_M52790, + .command = m52790_command, + .probe = m52790_probe, + .remove = m52790_remove, +}; + diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index c31163290432..3d51fa0a52b6 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -2023,7 +2023,7 @@ static int __init meye_init(void) if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total)" + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " "for capture\n", gbuffers, gbufsize / 1024, gbuffers * gbufsize / 1024); diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index c0c87e06259b..7a11f3159e32 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -42,7 +42,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ @@ -53,6 +54,7 @@ #include <linux/videodev.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-i2c-drv-legacy.h> #include <media/tvaudio.h> #include <media/msp3400.h> #include <linux/kthread.h> @@ -71,7 +73,8 @@ int msp_debug; /* msp_debug output */ int msp_once; /* no continous stereo monitoring */ int msp_amsound; /* hard-wire AM sound at 6.5 Hz (france), the autoscan seems work well only with FM... */ -int msp_standard = 1; /* Override auto detect of audio msp_standard, if needed. */ +int msp_standard = 1; /* Override auto detect of audio msp_standard, + if needed. */ int msp_dolby; int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual @@ -81,12 +84,12 @@ int msp_stereo_thresh = 0x190; /* a2 threshold for stereo/bilingual module_param(opmode, int, 0444); /* read-write */ -module_param_named(once,msp_once, bool, 0644); -module_param_named(debug,msp_debug, int, 0644); -module_param_named(stereo_threshold,msp_stereo_thresh, int, 0644); -module_param_named(standard,msp_standard, int, 0644); -module_param_named(amsound,msp_amsound, bool, 0644); -module_param_named(dolby,msp_dolby, bool, 0644); +module_param_named(once, msp_once, bool, 0644); +module_param_named(debug, msp_debug, int, 0644); +module_param_named(stereo_threshold, msp_stereo_thresh, int, 0644); +module_param_named(standard, msp_standard, int, 0644); +module_param_named(amsound, msp_amsound, bool, 0644); +module_param_named(dolby, msp_dolby, bool, 0644); MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); MODULE_PARM_DESC(once, "No continuous stereo monitoring"); @@ -160,12 +163,13 @@ static int msp_read(struct i2c_client *client, int dev, int addr) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); + v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", + dev, addr, retval); return retval; } @@ -190,7 +194,8 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); + v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", + dev, addr, val); for (err = 0; err < 3; err++) { if (i2c_master_send(client, buffer, 5) == 5) break; @@ -199,7 +204,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n"); + v4l_warn(client, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } @@ -273,7 +278,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) state->acb = 0xf60; /* Mute Input and SCART 1 Output */ v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", - scart_names[in], out, state->acb); + scart_names[in], out, state->acb); msp_write_dsp(client, 0x13, state->acb); /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ @@ -292,7 +297,8 @@ void msp_set_audio(struct i2c_client *client) val = (state->volume * 0x7f / 65535) << 8; v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", - state->muted ? "on" : "off", state->scan_in_progress ? "yes" : "no", + state->muted ? "on" : "off", + state->scan_in_progress ? "yes" : "no", state->volume); msp_write_dsp(client, 0x0000, val); @@ -681,14 +687,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", *a); switch (*a) { - case 1024000: - state->i2s_mode = 0; - break; - case 2048000: - state->i2s_mode = 1; - break; - default: - return -EINVAL; + case 1024000: + state->i2s_mode = 0; + break; + case 2048000: + state->i2s_mode = 1; + break; + default: + return -EINVAL; } break; } @@ -698,22 +704,22 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) struct v4l2_queryctrl *qc = arg; switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill_std(qc); - default: - break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; } if (!state->has_sound_processing) return -EINVAL; switch (qc->id) { - case V4L2_CID_AUDIO_LOUDNESS: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill_std(qc); - default: - return -EINVAL; + case V4L2_CID_AUDIO_LOUDNESS: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; } } @@ -735,13 +741,14 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) state->volume, state->muted ? " (muted)" : ""); if (state->has_sound_processing) { v4l_info(client, "Audio: balance %d bass %d treble %d loudness %s\n", - state->balance, state->bass, state->treble, + state->balance, state->bass, + state->treble, state->loudness ? "on" : "off"); } switch (state->mode) { case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break; case MSP_MODE_FM_RADIO: p = "FM Radio"; break; - case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono + FM-stereo"; break; + case MSP_MODE_FM_TERRA: p = "Terrestial FM-mono/stereo"; break; case MSP_MODE_FM_SAT: p = "Satellite FM-mono"; break; case MSP_MODE_FM_NICAM1: p = "NICAM/FM (B/G, D/K)"; break; case MSP_MODE_FM_NICAM2: p = "NICAM/FM (I)"; break; @@ -772,7 +779,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, state->ident, (state->rev1 << 16) | state->rev2); + return v4l2_chip_ident_i2c_client(client, arg, state->ident, + (state->rev1 << 16) | state->rev2); default: /* unknown */ @@ -783,7 +791,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) static int msp_suspend(struct i2c_client *client, pm_message_t state) { - v4l_dbg(1, msp_debug, client, "suspend\n"); msp_reset(client); return 0; @@ -791,7 +798,6 @@ static int msp_suspend(struct i2c_client *client, pm_message_t state) static int msp_resume(struct i2c_client *client) { - v4l_dbg(1, msp_debug, client, "resume\n"); msp_wake_thread(client); return 0; @@ -799,11 +805,8 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver; - -static int msp_attach(struct i2c_adapter *adapter, int address, int kind) +static int msp_probe(struct i2c_client *client) { - struct i2c_client *client; struct msp_state *state; int (*thread_func)(void *data) = NULL; int msp_hard; @@ -812,26 +815,16 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) int msp_product, msp_prod_hi, msp_prod_lo; int msp_rom; - client = kzalloc(sizeof(*client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "msp3400"); if (msp_reset(client) == -1) { v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) { - kfree(client); + if (!state) return -ENOMEM; - } i2c_set_clientdata(client, state); @@ -853,12 +846,13 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) state->rev1 = msp_read_dsp(client, 0x1e); if (state->rev1 != -1) state->rev2 = msp_read_dsp(client, 0x1f); - v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); + v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", + state->rev1, state->rev2); if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - v4l_dbg(1, msp_debug, client, "not an msp3400 (cannot read chip version)\n"); + v4l_dbg(1, msp_debug, client, + "not an msp3400 (cannot read chip version)\n"); kfree(state); - kfree(client); - return 0; + return -ENODEV; } msp_set_audio(client); @@ -874,37 +868,55 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) msp_family, msp_product, msp_revision, msp_hard, msp_rom); /* Rev B=2, C=3, D=4, G=7 */ - state->ident = msp_family * 10000 + 4000 + msp_product * 10 + msp_revision - '@'; + state->ident = msp_family * 10000 + 4000 + msp_product * 10 + + msp_revision - '@'; /* Has NICAM support: all mspx41x and mspx45x products have NICAM */ - state->has_nicam = msp_prod_hi == 1 || msp_prod_hi == 5; + state->has_nicam = + msp_prod_hi == 1 || msp_prod_hi == 5; /* Has radio support: was added with revision G */ - state->has_radio = msp_revision >= 'G'; + state->has_radio = + msp_revision >= 'G'; /* Has headphones output: not for stripped down products */ - state->has_headphones = msp_prod_lo < 5; + state->has_headphones = + msp_prod_lo < 5; /* Has scart2 input: not in stripped down products of the '3' family */ - state->has_scart2 = msp_family >= 4 || msp_prod_lo < 7; + state->has_scart2 = + msp_family >= 4 || msp_prod_lo < 7; /* Has scart3 input: not in stripped down products of the '3' family */ - state->has_scart3 = msp_family >= 4 || msp_prod_lo < 5; + state->has_scart3 = + msp_family >= 4 || msp_prod_lo < 5; /* Has scart4 input: not in pre D revisions, not in stripped D revs */ - state->has_scart4 = msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); - /* Has scart2 output: not in stripped down products of the '3' family */ - state->has_scart2_out = msp_family >= 4 || msp_prod_lo < 5; + state->has_scart4 = + msp_family >= 4 || (msp_revision >= 'D' && msp_prod_lo < 5); + /* Has scart2 output: not in stripped down products of + * the '3' family */ + state->has_scart2_out = + msp_family >= 4 || msp_prod_lo < 5; /* Has scart2 a volume control? Not in pre-D revisions. */ - state->has_scart2_out_volume = msp_revision > 'C' && state->has_scart2_out; + state->has_scart2_out_volume = + msp_revision > 'C' && state->has_scart2_out; /* Has a configurable i2s out? */ - state->has_i2s_conf = msp_revision >= 'G' && msp_prod_lo < 7; - /* Has subwoofer output: not in pre-D revs and not in stripped down products */ - state->has_subwoofer = msp_revision >= 'D' && msp_prod_lo < 5; - /* Has soundprocessing (bass/treble/balance/loudness/equalizer): not in - stripped down products */ - state->has_sound_processing = msp_prod_lo < 7; + state->has_i2s_conf = + msp_revision >= 'G' && msp_prod_lo < 7; + /* Has subwoofer output: not in pre-D revs and not in stripped down + * products */ + state->has_subwoofer = + msp_revision >= 'D' && msp_prod_lo < 5; + /* Has soundprocessing (bass/treble/balance/loudness/equalizer): + * not in stripped down products */ + state->has_sound_processing = + msp_prod_lo < 7; /* Has Virtual Dolby Surround: only in msp34x1 */ - state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1; + state->has_virtual_dolby_surround = + msp_revision == 'G' && msp_prod_lo == 1; /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */ - state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2; - /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */ - state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; + state->has_dolby_pro_logic = + msp_revision == 'G' && msp_prod_lo == 2; + /* The msp343xG supports BTSC only and cannot do Automatic Standard + * Detection. */ + state->force_btsc = + msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; state->opmode = opmode; if (state->opmode == OPMODE_AUTO) { @@ -919,32 +931,33 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) } /* hello world :-) */ - v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); v4l_info(client, "%s ", client->name); if (state->has_nicam && state->has_radio) - printk("supports nicam and radio, "); + printk(KERN_CONT "supports nicam and radio, "); else if (state->has_nicam) - printk("supports nicam, "); + printk(KERN_CONT "supports nicam, "); else if (state->has_radio) - printk("supports radio, "); - printk("mode is "); + printk(KERN_CONT "supports radio, "); + printk(KERN_CONT "mode is "); /* version-specific initialization */ switch (state->opmode) { case OPMODE_MANUAL: - printk("manual"); + printk(KERN_CONT "manual"); thread_func = msp3400c_thread; break; case OPMODE_AUTODETECT: - printk("autodetect"); + printk(KERN_CONT "autodetect"); thread_func = msp3410d_thread; break; case OPMODE_AUTOSELECT: - printk("autodetect and autoselect"); + printk(KERN_CONT "autodetect and autoselect"); thread_func = msp34xxg_thread; break; } - printk("\n"); + printk(KERN_CONT "\n"); /* startup control thread if needed */ if (thread_func) { @@ -954,24 +967,12 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) v4l_warn(client, "kernel_thread() failed\n"); msp_wake_thread(client); } - - /* done */ - i2c_attach_client(client); - return 0; } -static int msp_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, msp_attach); - return 0; -} - -static int msp_detach(struct i2c_client *client) +static int msp_remove(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - int err; /* shutdown control thread */ if (state->kthread) { @@ -980,43 +981,22 @@ static int msp_detach(struct i2c_client *client) } msp_reset(client); - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .id = I2C_DRIVERID_MSP3400, - .attach_adapter = msp_probe, - .detach_client = msp_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "msp3400", + .driverid = I2C_DRIVERID_MSP3400, + .command = msp_command, + .probe = msp_probe, + .remove = msp_remove, .suspend = msp_suspend, - .resume = msp_resume, - .command = msp_command, - .driver = { - .name = "msp3400", - }, + .resume = msp_resume, }; -static int __init msp3400_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit msp3400_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(msp3400_init_module); -module_exit(msp3400_cleanup_module); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index d5ee2629121e..61ec794a737e 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ @@ -78,37 +79,37 @@ static struct msp3400c_init_data_dem { {75, 19, 36, 35, 39, 40}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0500, 0x0020, 0x3000 - },{ /* AM (for carrier detect / msp3410) */ + }, { /* AM (for carrier detect / msp3410) */ {-1, -1, -8, 2, 59, 126}, {-1, -1, -8, 2, 59, 126}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0100, 0x0020, 0x3000 - },{ /* FM Radio */ + }, { /* FM Radio */ {-8, -8, 4, 6, 78, 107}, {-8, -8, 4, 6, 78, 107}, MSP_CARRIER(10.7), MSP_CARRIER(10.7), 0x00d0, 0x0480, 0x0020, 0x3000 - },{ /* Terrestial FM-mono + FM-stereo */ + }, { /* Terrestial FM-mono + FM-stereo */ {3, 18, 27, 48, 66, 72}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0480, 0x0030, 0x3000 - },{ /* Sat FM-mono */ + }, { /* Sat FM-mono */ { 1, 9, 14, 24, 33, 37}, { 3, 18, 27, 48, 66, 72}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000 - },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ + }, { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ {-2, -8, -10, 10, 50, 86}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000 - },{ /* NICAM/FM -- I (6.0/6.552) */ + }, { /* NICAM/FM -- I (6.0/6.552) */ {2, 4, -6, -4, 40, 94}, {3, 18, 27, 48, 66, 72}, MSP_CARRIER(6.0), MSP_CARRIER(6.0), 0x00d0, 0x0040, 0x0120, 0x3000 - },{ /* NICAM/AM -- L (6.5/5.85) */ + }, { /* NICAM/AM -- L (6.5/5.85) */ {-2, -8, -10, 10, 50, 86}, {-4, -12, -9, 23, 79, 126}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), @@ -224,7 +225,9 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) nor do they support stereo BTSC. */ static void msp3400c_set_audmode(struct i2c_client *client) { - static char *strmode[] = { "mono", "stereo", "lang2", "lang1", "lang1+lang2" }; + static char *strmode[] = { + "mono", "stereo", "lang2", "lang1", "lang1+lang2" + }; struct msp_state *state = i2c_get_clientdata(client); char *modestr = (state->audmode >= 0 && state->audmode < 5) ? strmode[state->audmode] : "unknown"; @@ -298,19 +301,23 @@ static void msp3400c_set_audmode(struct i2c_client *client) case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "NICAM set_audmode: %s\n", modestr); if (state->nicam_on) src = 0x0100; /* NICAM */ break; case MSP_MODE_BTSC: - v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "BTSC set_audmode: %s\n", modestr); break; case MSP_MODE_EXTERN: - v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "extern set_audmode: %s\n", modestr); src = 0x0200; /* SCART */ break; case MSP_MODE_FM_RADIO: - v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr); + v4l_dbg(1, msp_debug, client, + "FM-Radio set_audmode: %s\n", modestr); break; default: v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); @@ -342,7 +349,8 @@ static void msp3400c_set_audmode(struct i2c_client *client) src |= 0x0010; break; } - v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src); + v4l_dbg(1, msp_debug, client, + "set_audmode final source/matrix = 0x%x\n", src); msp_set_source(client, src); } @@ -351,22 +359,26 @@ static void msp3400c_print_mode(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (state->main == state->second) { - v4l_dbg(1, msp_debug, client, "mono sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - } else { - v4l_dbg(1, msp_debug, client, "main sound carrier: %d.%03d MHz\n", - state->main / 910000, (state->main / 910) % 1000); - } + if (state->main == state->second) + v4l_dbg(1, msp_debug, client, + "mono sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); + else + v4l_dbg(1, msp_debug, client, + "main sound carrier: %d.%03d MHz\n", + state->main / 910000, (state->main / 910) % 1000); if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) - v4l_dbg(1, msp_debug, client, "NICAM/FM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second/910) % 1000); + v4l_dbg(1, msp_debug, client, + "NICAM/FM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second/910) % 1000); if (state->mode == MSP_MODE_AM_NICAM) - v4l_dbg(1, msp_debug, client, "NICAM/AM carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); + v4l_dbg(1, msp_debug, client, + "NICAM/AM carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { - v4l_dbg(1, msp_debug, client, "FM-stereo carrier : %d.%03d MHz\n", - state->second / 910000, (state->second / 910) % 1000); + v4l_dbg(1, msp_debug, client, + "FM-stereo carrier : %d.%03d MHz\n", + state->second / 910000, (state->second / 910) % 1000); } } @@ -385,7 +397,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client) val = msp_read_dsp(client, 0x18); if (val > 32767) val -= 65536; - v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val); + v4l_dbg(2, msp_debug, client, + "stereo detect register: %d\n", val); if (val > 8192) { rxsubchans = V4L2_TUNER_SUB_STEREO; } else if (val < -4096) { @@ -430,7 +443,8 @@ static int msp3400c_detect_stereo(struct i2c_client *client) } if (rxsubchans != state->rxsubchans) { update = 1; - v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n", + v4l_dbg(1, msp_debug, client, + "watch: rxsubchans %02x => %02x\n", state->rxsubchans, rxsubchans); state->rxsubchans = rxsubchans; } @@ -452,9 +466,8 @@ static void watch_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (msp_detect_stereo(client)) { + if (msp_detect_stereo(client)) msp_set_audmode(client); - } if (msp_once) state->watch_stereo = 0; @@ -465,7 +478,7 @@ int msp3400c_thread(void *data) struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); struct msp3400c_carrier_detect *cd; - int count, max1, max2, val1, val2, val, this; + int count, max1, max2, val1, val2, val, i; v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); @@ -475,7 +488,7 @@ int msp3400c_thread(void *data) msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); - restart: +restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -483,7 +496,8 @@ int msp3400c_thread(void *data) if (state->radio || MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ - v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -514,16 +528,17 @@ int msp3400c_thread(void *data) v4l_dbg(1, msp_debug, client, "AM sound override\n"); } - for (this = 0; this < count; this++) { - msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); - if (msp_sleep(state,100)) + for (i = 0; i < count; i++) { + msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); + if (msp_sleep(state, 100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val1 < val) - val1 = val, max1 = this; - v4l_dbg(1, msp_debug, client, "carrier1 val: %5d / %s\n", val,cd[this].name); + val1 = val, max1 = i; + v4l_dbg(1, msp_debug, client, + "carrier1 val: %5d / %s\n", val, cd[i].name); } /* carrier detect pass #2 -- second (stereo) carrier */ @@ -550,16 +565,17 @@ int msp3400c_thread(void *data) count = 0; max2 = 0; } - for (this = 0; this < count; this++) { - msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); - if (msp_sleep(state,100)) + for (i = 0; i < count; i++) { + msp3400c_set_carrier(client, cd[i].cdo, cd[i].cdo); + if (msp_sleep(state, 100)) goto restart; val = msp_read_dsp(client, 0x1b); if (val > 32767) val -= 65536; if (val2 < val) - val2 = val, max2 = this; - v4l_dbg(1, msp_debug, client, "carrier2 val: %5d / %s\n", val,cd[this].name); + val2 = val, max2 = i; + v4l_dbg(1, msp_debug, client, + "carrier2 val: %5d / %s\n", val, cd[i].name); } /* program the msp3400 according to the results */ @@ -611,7 +627,7 @@ int msp3400c_thread(void *data) break; case 0: /* 4.5 */ default: - no_second: +no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; msp3400c_set_mode(client, MSP_MODE_FM_TERRA); break; @@ -632,7 +648,8 @@ int msp3400c_thread(void *data) while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; - if (count) count--; + if (count) + count--; watch_stereo(client); } } @@ -651,10 +668,10 @@ int msp3410d_thread(void *data) set_freezable(); for (;;) { v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); - msp_sleep(state,-1); + msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); - restart: +restart: v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -662,7 +679,8 @@ int msp3410d_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -673,7 +691,8 @@ int msp3410d_thread(void *data) msp_set_audio(client); /* start autodetect. Note: autodetect is not supported for - NTSC-M and radio, hence we force the standard in those cases. */ + NTSC-M and radio, hence we force the standard in those + cases. */ if (state->radio) std = 0x40; else @@ -686,8 +705,9 @@ int msp3410d_thread(void *data) goto restart; if (msp_debug) - v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n", - msp_standard_std_name(std), std); + v4l_dbg(2, msp_debug, client, + "setting standard: %s (0x%04x)\n", + msp_standard_std_name(std), std); if (std != 1) { /* programmed some specific mode */ @@ -703,7 +723,8 @@ int msp3410d_thread(void *data) val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; - v4l_dbg(2, msp_debug, client, "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, + "detection still in progress\n"); } } for (i = 0; msp_stdlist[i].name != NULL; i++) @@ -716,12 +737,13 @@ int msp3410d_thread(void *data) state->std = val; state->rxsubchans = V4L2_TUNER_SUB_MONO; - if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && - (val != 0x0009)) { + if (msp_amsound && !state->radio && + (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { /* autodetection has failed, let backup */ v4l_dbg(1, msp_debug, client, "autodetection failed," " switching to backup standard: %s (0x%04x)\n", - msp_stdlist[8].name ? msp_stdlist[8].name : "unknown",val); + msp_stdlist[8].name ? + msp_stdlist[8].name : "unknown", val); state->std = val = 0x0009; msp_write_dem(client, 0x20, val); } @@ -786,7 +808,8 @@ int msp3410d_thread(void *data) while (state->watch_stereo) { if (msp_sleep(state, count ? 1000 : 5000)) goto restart; - if (count) count--; + if (count) + count--; watch_stereo(client); } } @@ -872,8 +895,8 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) else source = (in << 8) | matrix; - v4l_dbg(1, msp_debug, client, "set source to %d (0x%x) for output %02x\n", - in, source, reg); + v4l_dbg(1, msp_debug, client, + "set source to %d (0x%x) for output %02x\n", in, source, reg); msp_write_dsp(client, reg, source); } @@ -948,7 +971,7 @@ int msp34xxg_thread(void *data) msp_sleep(state, -1); v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); - restart: +restart: v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) @@ -956,7 +979,8 @@ int msp34xxg_thread(void *data) if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n"); + v4l_dbg(1, msp_debug, client, + "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_set_audio(client); continue; @@ -972,7 +996,8 @@ int msp34xxg_thread(void *data) goto unmute; /* watch autodetect */ - v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n"); + v4l_dbg(1, msp_debug, client, + "started autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { if (msp_sleep(state, 100)) goto restart; @@ -983,15 +1008,18 @@ int msp34xxg_thread(void *data) state->std = val; break; } - v4l_dbg(2, msp_debug, client, "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, + "detection still in progress\n"); } if (state->std == 1) { - v4l_dbg(1, msp_debug, client, "detection still in progress after 10 tries. giving up.\n"); + v4l_dbg(1, msp_debug, client, + "detection still in progress after 10 tries. giving up.\n"); continue; } - unmute: - v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n", +unmute: + v4l_dbg(1, msp_debug, client, + "detected standard: %s (0x%04x)\n", msp_standard_std_name(state->std), state->std); if (state->std == 9) { @@ -1046,9 +1074,11 @@ static int msp34xxg_detect_stereo(struct i2c_client *client) if (state->std == 0x20) state->rxsubchans |= V4L2_TUNER_SUB_SAP; else - state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + state->rxsubchans = + V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } - v4l_dbg(1, msp_debug, client, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", + v4l_dbg(1, msp_debug, client, + "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", status, is_stereo, is_bilingual, state->rxsubchans); return (oldrx != state->rxsubchans); } diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c index f49d1f4c40db..b630c26cfe85 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/video/mt20xx.c @@ -14,7 +14,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "mt20xx " +#define PREFIX "mt20xx" /* ---------------------------------------------------------------------- */ diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 98ad3092a079..add6d0d680be 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -149,10 +149,33 @@ struct mxb static struct saa7146_extension extension; +static int mxb_check_clients(struct device *dev, void *data) +{ + struct mxb* mxb = data; + struct i2c_client *client = i2c_verify_client(dev); + + if( !client ) + return 0; + + if( I2C_ADDR_TEA6420_1 == client->addr ) + mxb->tea6420_1 = client; + if( I2C_ADDR_TEA6420_2 == client->addr ) + mxb->tea6420_2 = client; + if( I2C_TEA6415C_2 == client->addr ) + mxb->tea6415c = client; + if( I2C_ADDR_TDA9840 == client->addr ) + mxb->tda9840 = client; + if( I2C_SAA7111 == client->addr ) + mxb->saa7111a = client; + if( 0x60 == client->addr ) + mxb->tuner = client; + + return 0; +} + static int mxb_probe(struct saa7146_dev* dev) { struct mxb* mxb = NULL; - struct i2c_client *client; int result; if ((result = request_module("saa7111")) < 0) { @@ -195,20 +218,7 @@ static int mxb_probe(struct saa7146_dev* dev) } /* loop through all i2c-devices on the bus and look who is there */ - list_for_each_entry(client, &mxb->i2c_adapter.clients, list) { - if( I2C_ADDR_TEA6420_1 == client->addr ) - mxb->tea6420_1 = client; - if( I2C_ADDR_TEA6420_2 == client->addr ) - mxb->tea6420_2 = client; - if( I2C_TEA6415C_2 == client->addr ) - mxb->tea6415c = client; - if( I2C_ADDR_TDA9840 == client->addr ) - mxb->tda9840 = client; - if( I2C_SAA7111 == client->addr ) - mxb->saa7111a = client; - if( 0x60 == client->addr ) - mxb->tuner = client; - } + device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients); /* check if all devices are present */ if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index d0c2cd785430..6fc1b8be1a1f 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -5,6 +5,10 @@ config VIDEO_PVRUSB2 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X + select VIDEO_SAA711X + select VIDEO_CX25840 + select VIDEO_MSP3400 + select VIDEO_WM8775 ---help--- This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -12,32 +16,29 @@ config VIDEO_PVRUSB2 To compile this driver as a module, choose M here: the module will be called pvrusb2 -config VIDEO_PVRUSB2_29XXX - bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series" +config VIDEO_PVRUSB2_ONAIR_CREATOR + bool "pvrusb2 driver support for OnAir Creator model" depends on VIDEO_PVRUSB2 && EXPERIMENTAL select VIDEO_SAA711X - select VIDEO_MSP3400 + select VIDEO_CS53L32A ---help--- - This option enables support for WinTV-PVR USB2 devices whose - model number is of the form "29xxx" (leading prefix of "29" - followed by 3 digits). - To see if you may need this option, examine the white - sticker on the underside of your device. + + This option enables support for the OnAir Creator USB tuner + device. This is a hybrid device, however currently only + analog mode is supported. If you are in doubt, say Y. -config VIDEO_PVRUSB2_24XXX - bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series" +config VIDEO_PVRUSB2_ONAIR_USB2 + bool "pvrusb2 driver support for OnAir USB2 model" depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_CX25840 - select VIDEO_WM8775 + select VIDEO_SAA711X + select VIDEO_CS53L32A ---help--- - This option enables inclusion of additional logic to operate - newer WinTV-PVR USB2 devices whose model number is of the - form "24xxx" (leading prefix of "24" followed by 3 digits). - To see if you may need this option, examine the white - sticker on the underside of your device. Enabling this - option will not harm support for older devices. + + This option enables support for the OnAir USB2 tuner device + (also known as the Sasem tuner). This is a hybrid device, + however currently only analog mode is supported. If you are in doubt, say Y. diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index 69b3e43cd0eb..47284e558648 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -6,7 +6,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ pvrusb2-encoder.o pvrusb2-video-v4l.o \ pvrusb2-eeprom.o pvrusb2-tuner.o \ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \ - pvrusb2-ctrl.o pvrusb2-std.o \ + pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y) diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c index 379645e481c6..9a7c8e9c3e8b 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c @@ -35,34 +35,58 @@ struct pvr2_msp3400_handler { }; + +struct routing_scheme { + const int *def; + unsigned int cnt; +}; + +static const int routing_scheme0[] = { + [PVR2_CVAL_INPUT_TV] = MSP_INPUT_DEFAULT, + [PVR2_CVAL_INPUT_RADIO] = MSP_INPUT(MSP_IN_SCART2, + MSP_IN_TUNER1, + MSP_DSP_IN_SCART, + MSP_DSP_IN_SCART), + [PVR2_CVAL_INPUT_COMPOSITE] = MSP_INPUT(MSP_IN_SCART1, + MSP_IN_TUNER1, + MSP_DSP_IN_SCART, + MSP_DSP_IN_SCART), + [PVR2_CVAL_INPUT_SVIDEO] = MSP_INPUT(MSP_IN_SCART1, + MSP_IN_TUNER1, + MSP_DSP_IN_SCART, + MSP_DSP_IN_SCART), +}; + +static const struct routing_scheme routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), + }, +}; + /* This function selects the correct audio input source */ static void set_stereo(struct pvr2_msp3400_handler *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; + const struct routing_scheme *sp; + unsigned int sid = hdw->hdw_desc->signal_routing_scheme; pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo"); - route.input = MSP_INPUT_DEFAULT; - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - switch (hdw->input_val) { - case PVR2_CVAL_INPUT_TV: - break; - case PVR2_CVAL_INPUT_RADIO: - /* Assume that msp34xx also handle FM decoding, in which case - we're still using the tuner. */ - /* HV: actually it is more likely to be the SCART2 input if - the ivtv experience is any indication. */ - route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; - case PVR2_CVAL_INPUT_SVIDEO: - case PVR2_CVAL_INPUT_COMPOSITE: - /* SCART 1 input */ - route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART); - break; + if ((sid < ARRAY_SIZE(routing_schemes)) && + ((sp = routing_schemes + sid) != 0) && + (hdw->input_val >= 0) && + (hdw->input_val < sp->cnt)) { + route.input = sp->def[hdw->input_val]; + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "*** WARNING *** i2c msp3400 v4l2 set_stereo:" + " Invalid routing scheme (%u) and/or input (%d)", + sid,hdw->input_val); + return; } + route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index 22719ba861ac..9d94aed2e12d 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c @@ -31,52 +31,32 @@ static void pvr2_context_destroy(struct pvr2_context *mp) { - if (mp->hdw) pvr2_hdw_destroy(mp->hdw); pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); - if (mp->workqueue) { - flush_workqueue(mp->workqueue); - destroy_workqueue(mp->workqueue); - } + if (mp->hdw) pvr2_hdw_destroy(mp->hdw); kfree(mp); } -static void pvr2_context_trigger_poll(struct pvr2_context *mp) -{ - queue_work(mp->workqueue,&mp->workpoll); -} - - -static void pvr2_context_poll(struct work_struct *work) -{ - struct pvr2_context *mp = - container_of(work, struct pvr2_context, workpoll); - pvr2_context_enter(mp); do { - pvr2_hdw_poll(mp->hdw); - } while (0); pvr2_context_exit(mp); -} - - -static void pvr2_context_setup(struct work_struct *work) +static void pvr2_context_state_check(struct pvr2_context *mp) { - struct pvr2_context *mp = - container_of(work, struct pvr2_context, workinit); + if (mp->init_flag) return; + + switch (pvr2_hdw_get_state(mp->hdw)) { + case PVR2_STATE_WARM: break; + case PVR2_STATE_ERROR: break; + case PVR2_STATE_READY: break; + case PVR2_STATE_RUN: break; + default: return; + } pvr2_context_enter(mp); do { - if (!pvr2_hdw_dev_ok(mp->hdw)) break; - pvr2_hdw_setup(mp->hdw); - pvr2_hdw_setup_poll_trigger( - mp->hdw, - (void (*)(void *))pvr2_context_trigger_poll, - mp); - if (!pvr2_hdw_dev_ok(mp->hdw)) break; - if (!pvr2_hdw_init_ok(mp->hdw)) break; + mp->init_flag = !0; mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); if (mp->setup_func) { mp->setup_func(mp); } } while (0); pvr2_context_exit(mp); -} + } struct pvr2_context *pvr2_context_create( @@ -96,11 +76,10 @@ struct pvr2_context *pvr2_context_create( mp = NULL; goto done; } - - mp->workqueue = create_singlethread_workqueue("pvrusb2"); - INIT_WORK(&mp->workinit, pvr2_context_setup); - INIT_WORK(&mp->workpoll, pvr2_context_poll); - queue_work(mp->workqueue,&mp->workinit); + pvr2_hdw_set_state_callback(mp->hdw, + (void (*)(void *))pvr2_context_state_check, + mp); + pvr2_context_state_check(mp); done: return mp; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 6327fa1f7e4f..a04187a93225 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -45,14 +45,11 @@ struct pvr2_context { struct pvr2_context_stream video_stream; struct mutex mutex; int disconnect_flag; + int init_flag; /* Called after pvr2_context initialization is complete */ void (*setup_func)(struct pvr2_context *); - /* Work queue overhead for out-of-line processing */ - struct workqueue_struct *workqueue; - struct work_struct workinit; - struct work_struct workpoll; }; struct pvr2_channel { diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index e8a9252c7df6..ffdc45c324e5 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -49,34 +49,89 @@ struct pvr2_v4l_cx2584x { }; +struct routing_scheme_item { + int vid; + int aud; +}; + +struct routing_scheme { + const struct routing_scheme_item *def; + unsigned int cnt; +}; + +static const struct routing_scheme_item routing_scheme0[] = { + [PVR2_CVAL_INPUT_TV] = { + .vid = CX25840_COMPOSITE7, + .aud = CX25840_AUDIO8, + }, + [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ + .vid = CX25840_COMPOSITE3, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE3, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = CX25840_SVIDEO1, + .aud = CX25840_AUDIO_SERIAL, + }, +}; + +/* Specific to gotview device */ +static const struct routing_scheme_item routing_schemegv[] = { + [PVR2_CVAL_INPUT_TV] = { + .vid = CX25840_COMPOSITE2, + .aud = CX25840_AUDIO5, + }, + [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */ + .vid = CX25840_COMPOSITE1, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE1, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = (CX25840_SVIDEO_LUMA3|CX25840_SVIDEO_CHROMA4), + .aud = CX25840_AUDIO_SERIAL, + }, +}; + +static const struct routing_scheme routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), + }, + [PVR2_ROUTING_SCHEME_GOTVIEW] = { + .def = routing_schemegv, + .cnt = ARRAY_SIZE(routing_schemegv), + }, +}; + static void set_input(struct pvr2_v4l_cx2584x *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; enum cx25840_video_input vid_input; enum cx25840_audio_input aud_input; + const struct routing_scheme *sp; + unsigned int sid = hdw->hdw_desc->signal_routing_scheme; memset(&route,0,sizeof(route)); - switch(hdw->input_val) { - case PVR2_CVAL_INPUT_TV: - vid_input = CX25840_COMPOSITE7; - aud_input = CX25840_AUDIO8; - break; - case PVR2_CVAL_INPUT_RADIO: // Treat same as composite - case PVR2_CVAL_INPUT_COMPOSITE: - vid_input = CX25840_COMPOSITE3; - aud_input = CX25840_AUDIO_SERIAL; - break; - case PVR2_CVAL_INPUT_SVIDEO: - vid_input = CX25840_SVIDEO1; - aud_input = CX25840_AUDIO_SERIAL; - break; - default: - // Just set it to be composite input for now... - vid_input = CX25840_COMPOSITE3; - aud_input = CX25840_AUDIO_SERIAL; - break; + if ((sid < ARRAY_SIZE(routing_schemes)) && + ((sp = routing_schemes + sid) != 0) && + (hdw->input_val >= 0) && + (hdw->input_val < sp->cnt)) { + vid_input = sp->def[hdw->input_val].vid; + aud_input = sp->def[hdw->input_val].aud; + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "*** WARNING *** i2c cx2584x set_input:" + " Invalid routing scheme (%u) and/or input (%d)", + sid,hdw->input_val); + return; } pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x", @@ -140,7 +195,7 @@ static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = { static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt) { ctxt->client->handler = NULL; - ctxt->hdw->decoder_ctrl = NULL; + pvr2_hdw_set_decoder(ctxt->hdw,NULL); kfree(ctxt); } @@ -241,7 +296,7 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw, ctxt->client = cp; ctxt->hdw = hdw; ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1; - hdw->decoder_ctrl = &ctxt->ctrl; + pvr2_hdw_set_decoder(hdw,&ctxt->ctrl); cp->handler = &ctxt->handler; { /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index da6441b88f31..fca49d8a9311 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -34,25 +34,26 @@ extern int pvrusb2_debug; #define PVR2_TRACE_INIT (1 << 5) /* misc initialization steps */ #define PVR2_TRACE_START_STOP (1 << 6) /* Streaming start / stop */ #define PVR2_TRACE_CTL (1 << 7) /* commit of control changes */ -#define PVR2_TRACE_DEBUG (1 << 8) /* Temporary debug code */ -#define PVR2_TRACE_EEPROM (1 << 9) /* eeprom parsing / report */ -#define PVR2_TRACE_STRUCT (1 << 10) /* internal struct creation */ -#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */ -#define PVR2_TRACE_CREG (1 << 12) /* Main critical region entry / exit */ -#define PVR2_TRACE_SYSFS (1 << 13) /* Sysfs driven I/O */ -#define PVR2_TRACE_FIRMWARE (1 << 14) /* firmware upload actions */ -#define PVR2_TRACE_CHIPS (1 << 15) /* chip broadcast operation */ -#define PVR2_TRACE_I2C (1 << 16) /* I2C related stuff */ -#define PVR2_TRACE_I2C_CMD (1 << 17) /* Software commands to I2C modules */ -#define PVR2_TRACE_I2C_CORE (1 << 18) /* I2C core debugging */ -#define PVR2_TRACE_I2C_TRAF (1 << 19) /* I2C traffic through the adapter */ -#define PVR2_TRACE_V4LIOCTL (1 << 20) /* v4l ioctl details */ -#define PVR2_TRACE_ENCODER (1 << 21) /* mpeg2 encoder operation */ -#define PVR2_TRACE_BUF_POOL (1 << 22) /* Track buffer pool management */ -#define PVR2_TRACE_BUF_FLOW (1 << 23) /* Track buffer flow in system */ -#define PVR2_TRACE_DATA_FLOW (1 << 24) /* Track data flow */ -#define PVR2_TRACE_DEBUGIFC (1 << 25) /* Debug interface actions */ -#define PVR2_TRACE_GPIO (1 << 26) /* GPIO state bit changes */ +#define PVR2_TRACE_STATE (1 << 8) /* Device state changes */ +#define PVR2_TRACE_STBITS (1 << 9) /* Individual bit state changes */ +#define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */ +#define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */ +#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */ +#define PVR2_TRACE_CREG (1 << 13) /* Main critical region entry / exit */ +#define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */ +#define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */ +#define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */ +#define PVR2_TRACE_I2C (1 << 17) /* I2C related stuff */ +#define PVR2_TRACE_I2C_CMD (1 << 18) /* Software commands to I2C modules */ +#define PVR2_TRACE_I2C_CORE (1 << 19) /* I2C core debugging */ +#define PVR2_TRACE_I2C_TRAF (1 << 20) /* I2C traffic through the adapter */ +#define PVR2_TRACE_V4LIOCTL (1 << 21) /* v4l ioctl details */ +#define PVR2_TRACE_ENCODER (1 << 22) /* mpeg2 encoder operation */ +#define PVR2_TRACE_BUF_POOL (1 << 23) /* Track buffer pool management */ +#define PVR2_TRACE_BUF_FLOW (1 << 24) /* Track buffer flow in system */ +#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ +#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ +#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c index 6f135f4a2497..b0687430fdd4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c @@ -31,14 +31,6 @@ struct debugifc_mask_item { unsigned long msk; }; -static struct debugifc_mask_item mask_items[] = { - {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)}, - {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)}, - {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)}, - {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)}, - {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)}, -}; - static unsigned int debugifc_count_whitespace(const char *buf, unsigned int count) @@ -148,134 +140,14 @@ static int debugifc_match_keyword(const char *buf,unsigned int count, } -static unsigned long debugifc_find_mask(const char *buf,unsigned int count) -{ - struct debugifc_mask_item *mip; - unsigned int idx; - for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) { - mip = mask_items + idx; - if (debugifc_match_keyword(buf,count,mip->name)) { - return mip->msk; - } - } - return 0; -} - - -static int debugifc_print_mask(char *buf,unsigned int sz, - unsigned long msk,unsigned long val) -{ - struct debugifc_mask_item *mip; - unsigned int idx; - int bcnt = 0; - int ccnt; - for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) { - mip = mask_items + idx; - if (!(mip->msk & msk)) continue; - ccnt = scnprintf(buf,sz,"%s%c%s", - (bcnt ? " " : ""), - ((mip->msk & val) ? '+' : '-'), - mip->name); - sz -= ccnt; - buf += ccnt; - bcnt += ccnt; - } - return bcnt; -} - -static unsigned int debugifc_parse_subsys_mask(const char *buf, - unsigned int count, - unsigned long *mskPtr, - unsigned long *valPtr) -{ - const char *wptr; - unsigned int consume_cnt = 0; - unsigned int scnt; - unsigned int wlen; - int mode; - unsigned long m1,msk,val; - - msk = 0; - val = 0; - - while (count) { - scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); - if (!scnt) break; - consume_cnt += scnt; count -= scnt; buf += scnt; - if (!wptr) break; - - mode = 0; - if (wlen) switch (wptr[0]) { - case '+': - wptr++; - wlen--; - break; - case '-': - mode = 1; - wptr++; - wlen--; - break; - } - if (!wlen) continue; - m1 = debugifc_find_mask(wptr,wlen); - if (!m1) break; - msk |= m1; - if (!mode) val |= m1; - } - *mskPtr = msk; - *valPtr = val; - return consume_cnt; -} - - int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt) { int bcnt = 0; int ccnt; - struct pvr2_hdw_debug_info dbg; - - pvr2_hdw_get_debug_info(hdw,&dbg); - - ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s", - (dbg.big_lock_held ? "held" : "free"), - (dbg.ctl_lock_held ? "held" : "free")); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - if (dbg.ctl_lock_held) { - ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d" - " cmd_wlen=%d cmd_rlen=%d" - " wpend=%d rpend=%d tmout=%d rstatus=%d" - " wstatus=%d", - dbg.cmd_debug_state,dbg.cmd_code, - dbg.cmd_debug_write_len, - dbg.cmd_debug_read_len, - dbg.cmd_debug_write_pend, - dbg.cmd_debug_read_pend, - dbg.cmd_debug_timeout, - dbg.cmd_debug_rstatus, - dbg.cmd_debug_wstatus); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - } - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf( - buf,acnt,"driver flags: %s %s %s\n", - (dbg.flag_init_ok ? "initialized" : "uninitialized"), - (dbg.flag_ok ? "ok" : "fail"), - (dbg.flag_disconnected ? "disconnected" : "connected")); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); + ccnt = scnprintf(buf,acnt,"Driver state info:\n"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags); + ccnt = pvr2_hdw_state_report(hdw,buf,acnt); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; ccnt = pvr2_i2c_report(hdw,buf,acnt); @@ -290,7 +162,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, { int bcnt = 0; int ccnt; - unsigned long msk; int ret; u32 gpio_dir,gpio_in,gpio_out; @@ -311,28 +182,6 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, pvr2_hdw_get_streaming(hdw) ? "on" : "off"); bcnt += ccnt; acnt -= ccnt; buf += ccnt; - msk = pvr2_hdw_subsys_get(hdw); - ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,msk,msk); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,~msk,msk); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - - msk = pvr2_hdw_subsys_stream_get(hdw); - ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: "); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = debugifc_print_mask(buf,acnt,msk,msk); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - ccnt = scnprintf(buf,acnt,"\n"); - bcnt += ccnt; acnt -= ccnt; buf += ccnt; - return bcnt; } @@ -369,28 +218,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf, return pvr2_upload_firmware2(hdw); } else if (debugifc_match_keyword(wptr,wlen,"decoder")) { return pvr2_hdw_cmd_decoder_reset(hdw); + } else if (debugifc_match_keyword(wptr,wlen,"worker")) { + return pvr2_hdw_untrip(hdw); } return -EINVAL; - } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) { - unsigned long msk = 0; - unsigned long val = 0; - if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { - pvr2_trace(PVR2_TRACE_DEBUGIFC, - "debugifc parse error on subsys mask"); - return -EINVAL; - } - pvr2_hdw_subsys_bit_chg(hdw,msk,val); - return 0; - } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) { - unsigned long msk = 0; - unsigned long val = 0; - if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) { - pvr2_trace(PVR2_TRACE_DEBUGIFC, - "debugifc parse error on stream mask"); - return -EINVAL; - } - pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val); - return 0; } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) { scnt = debugifc_isolate_word(buf,count,&wptr,&wlen); if (!scnt) return -EINVAL; diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c new file mode 100644 index 000000000000..4df6d6d936fc --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -0,0 +1,217 @@ +/* + * + * $Id$ + * + * Copyright (C) 2007 Mike Isely <isely@pobox.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * 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 + * + */ + +/* + +This source file should encompass ALL per-device type information for the +driver. To define a new device, add elements to the pvr2_device_table and +pvr2_device_desc structures. + +*/ + +#include "pvrusb2-devattr.h" +#include <linux/usb.h> +/* This is needed in order to pull in tuner type ids... */ +#include <linux/i2c.h> +#include <media/tuner.h> + + + +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 29xxx */ + +static const char *pvr2_client_29xxx[] = { + "msp3400", + "saa7115", + "tuner", +}; + +static const char *pvr2_fw1_names_29xxx[] = { + "v4l-pvrusb2-29xxx-01.fw", +}; + +static const struct pvr2_device_desc pvr2_device_29xxx = { + .description = "WinTV PVR USB2 Model Category 29xxxx", + .shortname = "29xxx", + .client_modules.lst = pvr2_client_29xxx, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_29xxx), + .fx2_firmware.lst = pvr2_fw1_names_29xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx), + .flag_has_hauppauge_rom = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, +}; + + + +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 24xxx */ + +static const char *pvr2_client_24xxx[] = { + "cx25840", + "tuner", + "wm8775", +}; + +static const char *pvr2_fw1_names_24xxx[] = { + "v4l-pvrusb2-24xxx-01.fw", +}; + +static const struct pvr2_device_desc pvr2_device_24xxx = { + .description = "WinTV PVR USB2 Model Category 24xxxx", + .shortname = "24xxx", + .client_modules.lst = pvr2_client_24xxx, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx), + .fx2_firmware.lst = pvr2_fw1_names_24xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_24xxx), + .flag_has_cx25840 = !0, + .flag_has_wm8775 = !0, + .flag_has_hauppauge_rom = !0, + .flag_has_hauppauge_custom_ir = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, +}; + + + +/*------------------------------------------------------------------------*/ +/* GOTVIEW USB2.0 DVD2 */ + +static const char *pvr2_client_gotview_2[] = { + "cx25840", + "tuner", +}; + +static const struct pvr2_device_desc pvr2_device_gotview_2 = { + .description = "Gotview USB 2.0 DVD 2", + .shortname = "gv2", + .client_modules.lst = pvr2_client_gotview_2, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2), + .flag_has_cx25840 = !0, + .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW, +}; + + + +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR +/*------------------------------------------------------------------------*/ +/* OnAir Creator */ + +static const char *pvr2_client_onair_creator[] = { + "saa7115", + "tuner", + "cs53l32a", +}; + +static const struct pvr2_device_desc pvr2_device_onair_creator = { + .description = "OnAir Creator Hybrid USB tuner", + .shortname = "oac", + .client_modules.lst = pvr2_client_onair_creator, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator), + .default_tuner_type = TUNER_LG_TDVS_H06XF, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, +}; +#endif + + + +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 +/*------------------------------------------------------------------------*/ +/* OnAir USB 2.0 */ + +static const char *pvr2_client_onair_usb2[] = { + "saa7115", + "tuner", + "cs53l32a", +}; + +static const struct pvr2_device_desc pvr2_device_onair_usb2 = { + .description = "OnAir USB2 Hybrid USB tuner", + .shortname = "oa2", + .client_modules.lst = pvr2_client_onair_usb2, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2), + .default_tuner_type = TUNER_PHILIPS_ATSC, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, +}; +#endif + + + +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 75xxx */ + +static const char *pvr2_client_75xxx[] = { + "cx25840", + "tuner", +}; + +static const char *pvr2_fw1_names_75xxx[] = { + "v4l-pvrusb2-73xxx-01.fw", +}; + +static const struct pvr2_device_desc pvr2_device_75xxx = { + .description = "WinTV PVR USB2 Model Category 75xxxx", + .shortname = "75xxx", + .client_modules.lst = pvr2_client_75xxx, + .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), + .fx2_firmware.lst = pvr2_fw1_names_75xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx), + .flag_has_cx25840 = !0, + .flag_has_hauppauge_rom = !0, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + .default_std_mask = V4L2_STD_NTSC_M, +}; + + + +/*------------------------------------------------------------------------*/ + +struct usb_device_id pvr2_device_table[] = { + { USB_DEVICE(0x2040, 0x2900), + .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, + { USB_DEVICE(0x2040, 0x2400), + .driver_info = (kernel_ulong_t)&pvr2_device_24xxx}, + { USB_DEVICE(0x1164, 0x0622), + .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR + { USB_DEVICE(0x11ba, 0x1003), + .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, +#endif +#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 + { USB_DEVICE(0x11ba, 0x1001), + .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, +#endif + { USB_DEVICE(0x2040, 0x7500), + .driver_info = (kernel_ulong_t)&pvr2_device_75xxx}, + { } +}; + +MODULE_DEVICE_TABLE(usb, pvr2_device_table); + + +/* + Stuff for Emacs to see, in order to encourage consistent editing style: + *** Local Variables: *** + *** mode: c *** + *** fill-column: 75 *** + *** tab-width: 8 *** + *** c-basic-offset: 8 *** + *** End: *** + */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h new file mode 100644 index 000000000000..64b467f0637f --- /dev/null +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -0,0 +1,119 @@ +/* + * + * $Id$ + * + * Copyright (C) 2005 Mike Isely <isely@pobox.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * 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 __PVRUSB2_DEVATTR_H +#define __PVRUSB2_DEVATTR_H + +#include <linux/mod_devicetable.h> +#include <linux/videodev2.h> + +/* + + This header defines structures used to describe attributes of a device. + +*/ + + +struct pvr2_string_table { + const char **lst; + unsigned int cnt; +}; + +#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0 +#define PVR2_ROUTING_SCHEME_GOTVIEW 1 + +/* 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 + instantiated. */ +struct pvr2_device_desc { + /* Single line text description of hardware */ + const char *description; + + /* Single token identifier for hardware */ + const char *shortname; + + /* List of additional client modules we need to load */ + struct pvr2_string_table client_modules; + + /* List of FX2 firmware file names we should search; if empty then + FX2 firmware check / load is skipped and we assume the device + was initialized from internal ROM. */ + struct pvr2_string_table fx2_firmware; + + /* Signal routing scheme used by device, contains one of + PVR2_ROUTING_SCHEME_XXX. Schemes have to be defined as we + encounter them. This is an arbitrary integer scheme id; its + meaning is contained entirely within the driver and is + interpreted by logic which must send commands to the chip-level + drivers (search for things which touch this field). */ + unsigned int signal_routing_scheme; + + /* V4L tuner type ID to use with this device (only used if the + driver could not discover the type any other way). */ + int default_tuner_type; + + /* Initial standard bits to use for this device, if not zero. + Anything set here is also implied as an available standard. + Note: This is ignored if overridden on the module load line via + the video_std module option. */ + v4l2_std_id default_std_mask; + + /* If set, we don't bother trying to load cx23416 firmware. */ + char flag_skip_cx23416_firmware; + + /* Device has a hauppauge eeprom which we can interrogate. */ + char flag_has_hauppauge_rom; + + /* Device does not require a powerup command to be issued. */ + char flag_no_powerup; + + /* Device has a cx25840 - this enables special additional logic to + handle it. */ + char flag_has_cx25840; + + /* Device has a wm8775 - this enables special additional logic to + ensure that it is found. */ + char flag_has_wm8775; + + /* 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. */ + char flag_has_hauppauge_custom_ir; +}; + +extern struct usb_device_id pvr2_device_table[]; + +#endif /* __PVRUSB2_HDW_INTERNAL_H */ + +/* + Stuff for Emacs to see, in order to encourage consistent editing style: + *** Local Variables: *** + *** mode: c *** + *** fill-column: 75 *** + *** tab-width: 8 *** + *** c-basic-offset: 8 *** + *** End: *** + */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c index 45cbca0143ca..5ef005947b04 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c @@ -144,6 +144,7 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw) trace_eeprom("serial_number=%d",tvdata.serial_number); trace_eeprom("rev_str=%s",tvdata.rev_str); hdw->tuner_type = tvdata.tuner_type; + hdw->tuner_updated = !0; hdw->serial_number = tvdata.serial_number; hdw->std_mask_eeprom = tvdata.tuner_formats; diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 205087a3e136..64062879981e 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -140,7 +140,7 @@ static int pvr2_encoder_read_words(struct pvr2_hdw *hdw, cx2341x.ko to write to our encoder (by handing it a pointer to this function). For earlier kernels this doesn't really matter. */ static int pvr2_encoder_cmd(void *ctxt, - int cmd, + u32 cmd, int arg_cnt_send, int arg_cnt_recv, u32 *argp) @@ -209,7 +209,7 @@ static int pvr2_encoder_cmd(void *ctxt, LOCK_TAKE(hdw->ctl_lock); do { - if (!hdw->flag_encoder_ok) { + if (!hdw->state_encoder_ok) { ret = -EIO; break; } @@ -278,12 +278,15 @@ static int pvr2_encoder_cmd(void *ctxt, ret = -EBUSY; } if (ret) { - hdw->flag_encoder_ok = 0; + hdw->state_encoder_ok = 0; + pvr2_trace(PVR2_TRACE_STBITS, + "State bit %s <-- %s", + "state_encoder_ok", + (hdw->state_encoder_ok ? "true" : "false")); pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Giving up on command." - " It is likely that" - " this is a bad idea..."); + " This is normally recovered by the driver."); break; } wrData[0] = 0x7; @@ -366,13 +369,13 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) /* This ENC_MISC(3,encMisc3Arg) command is critical - without it there will eventually be video corruption. Also, the - 29xxx case is strange - the Windows driver is passing 1 - regardless of device type but if we have 1 for 29xxx device - the video turns sluggish. */ - switch (hdw->hdw_type) { - case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break; - case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break; - default: break; + saa7115 case is strange - the Windows driver is passing 1 + regardless of device type but if we have 1 for saa7115 + devices the video turns sluggish. */ + if (hdw->hdw_desc->flag_has_cx25840) { + encMisc3Arg = 1; + } else { + encMisc3Arg = 0; } ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3, encMisc3Arg,0,0); @@ -394,6 +397,24 @@ static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw) return ret; } +int pvr2_encoder_adjust(struct pvr2_hdw *hdw) +{ + int ret; + ret = cx2341x_update(hdw,pvr2_encoder_cmd, + (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), + &hdw->enc_ctl_state); + if (ret) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Error from cx2341x module code=%d",ret); + } else { + memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state, + sizeof(struct cx2341x_mpeg_params)); + hdw->enc_cur_valid = !0; + } + return ret; +} + + int pvr2_encoder_configure(struct pvr2_hdw *hdw) { int ret; @@ -412,7 +433,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) /* saa7115: 0xf0 */ val = 0xf0; - if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { + if (hdw->hdw_desc->flag_has_cx25840) { /* ivtv cx25840: 0x140 */ val = 0x140; } @@ -436,18 +457,10 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) return ret; } - ret = cx2341x_update(hdw,pvr2_encoder_cmd, - (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL), - &hdw->enc_ctl_state); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error from cx2341x module code=%d",ret); - return ret; - } - - ret = 0; + ret = pvr2_encoder_adjust(hdw); + if (ret) return ret; - if (!ret) ret = pvr2_encoder_vcmd( + ret = pvr2_encoder_vcmd( hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); if (ret) { @@ -456,10 +469,6 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) return ret; } - hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); - memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state, - sizeof(struct cx2341x_mpeg_params)); - hdw->enc_cur_valid = !0; return 0; } @@ -478,7 +487,7 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw) pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1, hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0); - switch (hdw->config) { + switch (hdw->active_stream_type) { case pvr2_config_vbi: status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, 0x01,0x14); @@ -492,9 +501,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw) 0,0x13); break; } - if (!status) { - hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN); - } return status; } @@ -505,7 +511,7 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw) /* mask all interrupts */ pvr2_write_register(hdw, 0x0048, 0xffffffff); - switch (hdw->config) { + switch (hdw->active_stream_type) { case pvr2_config_vbi: status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, 0x01,0x01,0x14); @@ -526,9 +532,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw) pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401); pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); - if (!status) { - hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN); - } return status; } diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h index 01b5a0b89c03..54caf2e3c428 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.h +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h @@ -25,6 +25,7 @@ struct pvr2_hdw; +int pvr2_encoder_adjust(struct pvr2_hdw *); int pvr2_encoder_configure(struct pvr2_hdw *); int pvr2_encoder_start(struct pvr2_hdw *); int pvr2_encoder_stop(struct pvr2_hdw *); diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index f873994b088c..d7a216b41b72 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -35,10 +35,12 @@ #include <linux/videodev2.h> #include <linux/i2c.h> +#include <linux/workqueue.h> #include <linux/mutex.h> #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" #include <media/cx2341x.h> +#include "pvrusb2-devattr.h" /* Legal values for PVR2_CID_HSM */ #define PVR2_CVAL_HSM_FAIL 0 @@ -161,10 +163,6 @@ struct pvr2_decoder_ctrl { #define FW1_STATE_RELOAD 3 #define FW1_STATE_OK 4 -/* Known major hardware variants, keyed from device ID */ -#define PVR2_HDW_TYPE_29XXX 0 -#define PVR2_HDW_TYPE_24XXX 1 - typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16); #define PVR2_I2C_FUNC_CNT 128 @@ -176,8 +174,15 @@ struct pvr2_hdw { struct usb_device *usb_dev; struct usb_interface *usb_intf; - /* Device type, one of PVR2_HDW_TYPE_xxxxx */ - unsigned int hdw_type; + /* Device description, anything that must adjust behavior based on + device specific info will use information held here. */ + const struct pvr2_device_desc *hdw_desc; + + /* Kernel worker thread handling */ + struct workqueue_struct *workqueue; + struct work_struct workpoll; /* Update driver state */ + struct work_struct worki2csync; /* Update i2c clients */ + struct work_struct workinit; /* Driver initialization sequence */ /* Video spigot */ struct pvr2_stream *vid_stream; @@ -186,9 +191,6 @@ struct pvr2_hdw { struct mutex big_lock_mutex; int big_lock_held; /* For debugging */ - void (*poll_trigger_func)(void *); - void *poll_trigger_data; - char name[32]; /* I2C stuff */ @@ -215,9 +217,9 @@ struct pvr2_hdw { struct urb *ctl_read_urb; unsigned char *ctl_write_buffer; unsigned char *ctl_read_buffer; - volatile int ctl_write_pend_flag; - volatile int ctl_read_pend_flag; - volatile int ctl_timeout_flag; + int ctl_write_pend_flag; + int ctl_read_pend_flag; + int ctl_timeout_flag; struct completion ctl_done; unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE]; int cmd_debug_state; // Low level command debugging info @@ -225,14 +227,48 @@ struct pvr2_hdw { unsigned int cmd_debug_write_len; // unsigned int cmd_debug_read_len; // + /* Bits of state that describe what is going on with various parts + of the driver. */ + int state_encoder_ok; /* Encoder is operational */ + int state_encoder_run; /* Encoder is running */ + int state_encoder_config; /* Encoder is configured */ + int state_encoder_waitok; /* Encoder pre-wait done */ + int state_decoder_run; /* Decoder is running */ + int state_usbstream_run; /* FX2 is streaming */ + int state_decoder_quiescent; /* Decoder idle for > 50msec */ + int state_pipeline_config; /* Pipeline is configured */ + int state_pipeline_req; /* Somebody wants to stream */ + int state_pipeline_pause; /* Pipeline must be paused */ + int state_pipeline_idle; /* Pipeline not running */ + + /* This is the master state of the driver. It is the combined + result of other bits of state. Examining this will indicate the + overall state of the driver. Values here are one of + PVR2_STATE_xxxx */ + unsigned int master_state; + + /* True if states must be re-evaluated */ + int state_stale; + + void (*state_func)(void *); + void *state_data; + + /* Timer for measuring decoder settling time */ + struct timer_list quiescent_timer; + + /* Timer for measuring encoder pre-wait time */ + struct timer_list encoder_wait_timer; + + /* Place to block while waiting for state changes */ + wait_queue_head_t state_wait_data; + + int flag_ok; /* device in known good state */ int flag_disconnected; /* flag_ok == 0 due to disconnect */ int flag_init_ok; /* true if structure is fully initialized */ - int flag_streaming_enabled; /* true if streaming should be on */ int fw1_state; /* current situation with fw1 */ - int flag_encoder_ok; /* True if encoder is healthy */ - - int flag_decoder_is_tuned; + int flag_decoder_missed;/* We've noticed missing decoder */ + int flag_tripped; /* Indicates overall failure to start */ struct pvr2_decoder_ctrl *decoder_ctrl; @@ -241,12 +277,6 @@ struct pvr2_hdw { unsigned int fw_size; int fw_cpu_flag; /* True if we are dealing with the CPU */ - // Which subsystem pieces have been enabled / configured - unsigned long subsys_enabled_mask; - - // Which subsystems are manipulated to enable streaming - unsigned long subsys_stream_mask; - // True if there is a request to trigger logging of state in each // module. int log_requested; @@ -296,13 +326,16 @@ struct pvr2_hdw { /* Location of eeprom or a negative number if none */ int eeprom_addr; - enum pvr2_config config; + enum pvr2_config active_stream_type; + enum pvr2_config desired_stream_type; /* Control state needed for cx2341x module */ struct cx2341x_mpeg_params enc_cur_state; struct cx2341x_mpeg_params enc_ctl_state; /* True if an encoder attribute has changed */ int enc_stale; + /* True if an unsafe encoder attribute has changed */ + int enc_unsafe_stale; /* True if enc_cur_state is valid */ int enc_cur_valid; @@ -332,6 +365,7 @@ struct pvr2_hdw { /* This function gets the current frequency */ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *); +void pvr2_hdw_set_decoder(struct pvr2_hdw *,struct pvr2_decoder_ctrl *); #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 402c59488253..41ae980405ed 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -41,47 +41,6 @@ #define TV_MIN_FREQ 55250000L #define TV_MAX_FREQ 850000000L -struct usb_device_id pvr2_device_table[] = { - [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) }, - [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) }, - { } -}; - -MODULE_DEVICE_TABLE(usb, pvr2_device_table); - -static const char *pvr2_device_names[] = { - [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx", - [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx", -}; - -struct pvr2_string_table { - const char **lst; - unsigned int cnt; -}; - -// Names of other client modules to request for 24xxx model hardware -static const char *pvr2_client_24xxx[] = { - "cx25840", - "tuner", - "wm8775", -}; - -// Names of other client modules to request for 29xxx model hardware -static const char *pvr2_client_29xxx[] = { - "msp3400", - "saa7115", - "tuner", -}; - -static struct pvr2_string_table pvr2_client_lists[] = { - [PVR2_HDW_TYPE_29XXX] = { - pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx) - }, - [PVR2_HDW_TYPE_24XXX] = { - pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx) - }, -}; - static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL}; static DEFINE_MUTEX(pvr2_unit_mtx); @@ -246,32 +205,46 @@ static const char *control_values_hsm[] = { }; -static const char *control_values_subsystem[] = { - [PVR2_SUBSYS_B_ENC_FIRMWARE] = "enc_firmware", - [PVR2_SUBSYS_B_ENC_CFG] = "enc_config", - [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run", - [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run", - [PVR2_SUBSYS_B_ENC_RUN] = "enc_run", +static const char *pvr2_state_names[] = { + [PVR2_STATE_NONE] = "none", + [PVR2_STATE_DEAD] = "dead", + [PVR2_STATE_COLD] = "cold", + [PVR2_STATE_WARM] = "warm", + [PVR2_STATE_ERROR] = "error", + [PVR2_STATE_READY] = "ready", + [PVR2_STATE_RUN] = "run", }; + +static void pvr2_hdw_state_sched(struct pvr2_hdw *); +static int pvr2_hdw_state_eval(struct pvr2_hdw *); static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); +static void pvr2_hdw_worker_i2c(struct work_struct *work); +static void pvr2_hdw_worker_poll(struct work_struct *work); +static void pvr2_hdw_worker_init(struct work_struct *work); +static int pvr2_hdw_wait(struct pvr2_hdw *,int state); +static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *); +static void pvr2_hdw_state_log_state(struct pvr2_hdw *); static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl); -static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw); +static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw); static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw); static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw); static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw); -static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw); -static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val); -static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val); +static void pvr2_hdw_quiescent_timeout(unsigned long); +static void pvr2_hdw_encoder_wait_timeout(unsigned long); static int pvr2_send_request_ex(struct pvr2_hdw *hdw, unsigned int timeout,int probe_fl, void *write_data,unsigned int write_len, void *read_data,unsigned int read_len); + +static void trace_stbit(const char *name,int val) +{ + pvr2_trace(PVR2_TRACE_STBITS, + "State bit %s <-- %s", + name,(val ? "true" : "false")); +} + static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp) { struct pvr2_hdw *hdw = cptr->hdw; @@ -380,8 +353,8 @@ static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp) { - /* Actual minimum depends on device type. */ - if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { + /* Actual minimum depends on device digitizer type. */ + if (cptr->hdw->hdw_desc->flag_has_cx25840) { *vp = 75; } else { *vp = 17; @@ -480,6 +453,7 @@ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) { cptr->hdw->enc_stale = 0; + cptr->hdw->enc_unsafe_stale = 0; } static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) @@ -502,6 +476,7 @@ static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) { int ret; + struct pvr2_hdw *hdw = cptr->hdw; struct v4l2_ext_controls cs; struct v4l2_ext_control c1; memset(&cs,0,sizeof(cs)); @@ -510,10 +485,22 @@ static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) cs.count = 1; c1.id = cptr->info->v4l_id; c1.value = v; - ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs, + ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, + hdw->state_encoder_run, &cs, VIDIOC_S_EXT_CTRLS); + if (ret == -EBUSY) { + /* Oops. cx2341x is telling us it's not safe to change + this control while we're capturing. Make a note of this + fact so that the pipeline will be stopped the next time + controls are committed. Then go on ahead and store this + change anyway. */ + ret = cx2341x_ext_ctrls(&hdw->enc_ctl_state, + 0, &cs, + VIDIOC_S_EXT_CTRLS); + if (!ret) hdw->enc_unsafe_stale = !0; + } if (ret) return ret; - cptr->hdw->enc_stale = !0; + hdw->enc_stale = !0; return 0; } @@ -544,7 +531,13 @@ static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) { - *vp = cptr->hdw->flag_streaming_enabled; + *vp = cptr->hdw->state_pipeline_req; + return 0; +} + +static int ctrl_masterstate_get(struct pvr2_ctrl *cptr,int *vp) +{ + *vp = cptr->hdw->master_state; return 0; } @@ -657,29 +650,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp) return 0; } -static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->subsys_enabled_mask; - return 0; -} - -static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v) -{ - pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v); - return 0; -} - -static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp) -{ - *vp = cptr->hdw->subsys_stream_mask; - return 0; -} - -static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v) -{ - pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v); - return 0; -} static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v) { @@ -915,6 +885,11 @@ static const struct pvr2_ctl_info control_defs[] = { .get_value = ctrl_hsm_get, DEFENUM(control_values_hsm), },{ + .desc = "Master State", + .name = "master_state", + .get_value = ctrl_masterstate_get, + DEFENUM(pvr2_state_names), + },{ .desc = "Signal Present", .name = "signal_present", .get_value = ctrl_signal_get, @@ -955,20 +930,6 @@ static const struct pvr2_ctl_info control_defs[] = { .sym_to_val = ctrl_std_sym_to_val, .type = pvr2_ctl_bitmask, },{ - .desc = "Subsystem enabled mask", - .name = "debug_subsys_mask", - .skip_init = !0, - .get_value = ctrl_subsys_get, - .set_value = ctrl_subsys_set, - DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), - },{ - .desc = "Subsystem stream mask", - .name = "debug_subsys_stream_mask", - .skip_init = !0, - .get_value = ctrl_subsys_stream_get, - .set_value = ctrl_subsys_stream_set, - DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem), - },{ .desc = "Video Standard Name", .name = "video_standard", .internal_id = PVR2_CID_STDENUM, @@ -1129,25 +1090,13 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) unsigned int pipe; int ret; u16 address; - static const char *fw_files_29xxx[] = { - "v4l-pvrusb2-29xxx-01.fw", - }; - static const char *fw_files_24xxx[] = { - "v4l-pvrusb2-24xxx-01.fw", - }; - static const struct pvr2_string_table fw_file_defs[] = { - [PVR2_HDW_TYPE_29XXX] = { - fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx) - }, - [PVR2_HDW_TYPE_24XXX] = { - fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx) - }, - }; - if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) || - (!fw_file_defs[hdw->hdw_type].lst)) { + if (!hdw->hdw_desc->fx2_firmware.cnt) { hdw->fw1_state = FW1_STATE_OK; - return 0; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Connected device type defines" + " no firmware to upload; ignoring firmware"); + return -ENOTTY; } hdw->fw1_state = FW1_STATE_FAILED; // default result @@ -1155,8 +1104,8 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) trace_firmware("pvr2_upload_firmware1"); ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller", - fw_file_defs[hdw->hdw_type].cnt, - fw_file_defs[hdw->hdw_type].lst); + hdw->hdw_desc->fx2_firmware.cnt, + hdw->hdw_desc->fx2_firmware.lst); if (ret < 0) { if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING; return ret; @@ -1231,8 +1180,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) CX2341X_FIRM_ENC_FILENAME, }; - if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) && - (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) { + if (hdw->hdw_desc->flag_skip_cx23416_firmware) { return 0; } @@ -1248,8 +1196,6 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) time we configure the encoder, then we'll fully configure it. */ hdw->enc_cur_valid = 0; - hdw->flag_encoder_ok = 0; - /* First prepare firmware loading */ ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/ @@ -1347,293 +1293,129 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (ret) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "firmware2 upload post-proc failure"); - } else { - hdw->flag_encoder_ok = !0; - hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE); } return ret; } -#define FIRMWARE_RECOVERY_BITS \ - ((1<<PVR2_SUBSYS_B_ENC_CFG) | \ - (1<<PVR2_SUBSYS_B_ENC_RUN) | \ - (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \ - (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) - -/* - - This single function is key to pretty much everything. The pvrusb2 - device can logically be viewed as a series of subsystems which can be - stopped / started or unconfigured / configured. To get things streaming, - one must configure everything and start everything, but there may be - various reasons over time to deconfigure something or stop something. - This function handles all of this activity. Everything EVERYWHERE that - must affect a subsystem eventually comes here to do the work. - - The current state of all subsystems is represented by a single bit mask, - known as subsys_enabled_mask. The bit positions are defined by the - PVR2_SUBSYS_xxxx macros, with one subsystem per bit position. At any - time the set of configured or active subsystems can be queried just by - looking at that mask. To change bits in that mask, this function here - must be called. The "msk" argument indicates which bit positions to - change, and the "val" argument defines the new values for the positions - defined by "msk". - - There is a priority ordering of starting / stopping things, and for - multiple requested changes, this function implements that ordering. - (Thus we will act on a request to load encoder firmware before we - configure the encoder.) In addition to priority ordering, there is a - recovery strategy implemented here. If a particular step fails and we - detect that failure, this function will clear the affected subsystem bits - and restart. Thus we have a means for recovering from a dead encoder: - Clear all bits that correspond to subsystems that we need to restart / - reconfigure and start over. - -*/ -static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) -{ - unsigned long nmsk; - unsigned long vmsk; - int ret; - unsigned int tryCount = 0; - - if (!hdw->flag_ok) return; - - msk &= PVR2_SUBSYS_ALL; - nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk); - nmsk &= PVR2_SUBSYS_ALL; - - for (;;) { - tryCount++; - if (!((nmsk ^ hdw->subsys_enabled_mask) & - PVR2_SUBSYS_ALL)) break; - if (tryCount > 4) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Too many retries when configuring device;" - " giving up"); - pvr2_hdw_render_useless(hdw); - break; - } - if (tryCount > 1) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Retrying device reconfiguration"); - } - pvr2_trace(PVR2_TRACE_INIT, - "subsys mask changing 0x%lx:0x%lx" - " from 0x%lx to 0x%lx", - msk,val,hdw->subsys_enabled_mask,nmsk); - - vmsk = (nmsk ^ hdw->subsys_enabled_mask) & - hdw->subsys_enabled_mask; - if (vmsk) { - if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " pvr2_encoder_stop"); - ret = pvr2_encoder_stop(hdw); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error recovery initiated"); - hdw->subsys_enabled_mask &= - ~FIRMWARE_RECOVERY_BITS; - continue; - } - } - if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " pvr2_hdw_cmd_usbstream(0)"); - pvr2_hdw_cmd_usbstream(hdw,0); - } - if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " decoder disable"); - if (hdw->decoder_ctrl) { - hdw->decoder_ctrl->enable( - hdw->decoder_ctrl->ctxt,0); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING:" - " No decoder present"); - } - hdw->subsys_enabled_mask &= - ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN); - } - if (vmsk & PVR2_SUBSYS_CFG_ALL) { - hdw->subsys_enabled_mask &= - ~(vmsk & PVR2_SUBSYS_CFG_ALL); - } - } - vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk; - if (vmsk) { - if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " pvr2_upload_firmware2"); - ret = pvr2_upload_firmware2(hdw); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failure uploading encoder" - " firmware"); - pvr2_hdw_render_useless(hdw); - break; - } - } - if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " pvr2_encoder_configure"); - ret = pvr2_encoder_configure(hdw); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error recovery initiated"); - hdw->subsys_enabled_mask &= - ~FIRMWARE_RECOVERY_BITS; - continue; - } - } - if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " decoder enable"); - if (hdw->decoder_ctrl) { - hdw->decoder_ctrl->enable( - hdw->decoder_ctrl->ctxt,!0); - } else { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING:" - " No decoder present"); - } - hdw->subsys_enabled_mask |= - (1<<PVR2_SUBSYS_B_DIGITIZER_RUN); - } - if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " pvr2_hdw_cmd_usbstream(1)"); - pvr2_hdw_cmd_usbstream(hdw,!0); - } - if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) { - pvr2_trace(PVR2_TRACE_CTL, - "/*---TRACE_CTL----*/" - " pvr2_encoder_start"); - ret = pvr2_encoder_start(hdw); - if (ret) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Error recovery initiated"); - hdw->subsys_enabled_mask &= - ~FIRMWARE_RECOVERY_BITS; - continue; - } - } - } +static const char *pvr2_get_state_name(unsigned int st) +{ + if (st < ARRAY_SIZE(pvr2_state_names)) { + return pvr2_state_names[st]; } + return "???"; } - -void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val) +static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) { - LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val); - } while (0); LOCK_GIVE(hdw->big_lock); + if (!hdw->decoder_ctrl) { + if (!hdw->flag_decoder_missed) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "WARNING: No decoder present"); + hdw->flag_decoder_missed = !0; + trace_stbit("flag_decoder_missed", + hdw->flag_decoder_missed); + } + return -EIO; + } + hdw->decoder_ctrl->enable(hdw->decoder_ctrl->ctxt,enablefl); + return 0; } -unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw) +void pvr2_hdw_set_decoder(struct pvr2_hdw *hdw,struct pvr2_decoder_ctrl *ptr) { - return hdw->subsys_enabled_mask; + if (hdw->decoder_ctrl == ptr) return; + hdw->decoder_ctrl = ptr; + if (hdw->decoder_ctrl && hdw->flag_decoder_missed) { + hdw->flag_decoder_missed = 0; + trace_stbit("flag_decoder_missed", + hdw->flag_decoder_missed); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Decoder has appeared"); + pvr2_hdw_state_sched(hdw); + } } -unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw) +int pvr2_hdw_get_state(struct pvr2_hdw *hdw) { - return hdw->subsys_stream_mask; + return hdw->master_state; } -static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) +static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *hdw) { - unsigned long val2; - msk &= PVR2_SUBSYS_ALL; - val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk)); - pvr2_trace(PVR2_TRACE_INIT, - "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx", - msk,val,hdw->subsys_stream_mask,val2); - hdw->subsys_stream_mask = val2; + if (!hdw->flag_tripped) return 0; + hdw->flag_tripped = 0; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Clearing driver error statuss"); + return !0; } -void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk, - unsigned long val) +int pvr2_hdw_untrip(struct pvr2_hdw *hdw) { + int fl; LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val); + fl = pvr2_hdw_untrip_unlocked(hdw); } while (0); LOCK_GIVE(hdw->big_lock); + if (fl) pvr2_hdw_state_sched(hdw); + return 0; } -static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl) +const char *pvr2_hdw_get_state_name(unsigned int id) { - if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0; - if (enableFl) { - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ enable"); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0); - } else { - pvr2_trace(PVR2_TRACE_START_STOP, - "/*--TRACE_STREAM--*/ disable"); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); - } - if (!hdw->flag_ok) return -EIO; - hdw->flag_streaming_enabled = enableFl != 0; - return 0; + if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL; + return pvr2_state_names[id]; } int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw) { - return hdw->flag_streaming_enabled != 0; + return hdw->state_pipeline_req != 0; } int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag) { - int ret; + int ret,st; LOCK_TAKE(hdw->big_lock); do { - ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag); + pvr2_hdw_untrip_unlocked(hdw); + if ((!enable_flag) != !(hdw->state_pipeline_req)) { + hdw->state_pipeline_req = enable_flag != 0; + pvr2_trace(PVR2_TRACE_START_STOP, + "/*--TRACE_STREAM--*/ %s", + enable_flag ? "enable" : "disable"); + } + pvr2_hdw_state_sched(hdw); } while (0); LOCK_GIVE(hdw->big_lock); - return ret; -} - - -static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw, - enum pvr2_config config) -{ - unsigned long sm = hdw->subsys_enabled_mask; - if (!hdw->flag_ok) return -EIO; - pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0); - hdw->config = config; - pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm); + if ((ret = pvr2_hdw_wait(hdw,0)) < 0) return ret; + if (enable_flag) { + while ((st = hdw->master_state) != PVR2_STATE_RUN) { + if (st != PVR2_STATE_READY) return -EIO; + if ((ret = pvr2_hdw_wait(hdw,st)) < 0) return ret; + } + } return 0; } int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config) { - int ret; - if (!hdw->flag_ok) return -EIO; + int fl; LOCK_TAKE(hdw->big_lock); - ret = pvr2_hdw_set_stream_type_no_lock(hdw,config); + if ((fl = (hdw->desired_stream_type != config)) != 0) { + hdw->desired_stream_type = config; + hdw->state_pipeline_config = 0; + trace_stbit("state_pipeline_config", + hdw->state_pipeline_config); + pvr2_hdw_state_sched(hdw); + } LOCK_GIVE(hdw->big_lock); - return ret; + if (fl) return 0; + return pvr2_hdw_wait(hdw,0); } @@ -1646,6 +1428,7 @@ static int get_default_tuner_type(struct pvr2_hdw *hdw) } if (tp < 0) return -EINVAL; hdw->tuner_type = tp; + hdw->tuner_updated = !0; return 0; } @@ -1656,8 +1439,9 @@ static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw) int tp = 0; if ((unit_number >= 0) && (unit_number < PVR_NUM)) { tp = video_std[unit_number]; + if (tp) return tp; } - return tp; + return 0; } @@ -1731,7 +1515,7 @@ const static struct pvr2_std_hack std_eeprom_maps[] = { }, { /* PAL(D/D1/K) */ .pat = V4L2_STD_DK, - .std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K, + .std = V4L2_STD_PAL_D|V4L2_STD_PAL_D1|V4L2_STD_PAL_K, }, }; @@ -1739,18 +1523,20 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) { char buf[40]; unsigned int bcnt; - v4l2_std_id std1,std2; + v4l2_std_id std1,std2,std3; std1 = get_default_standard(hdw); + std3 = std1 ? 0 : hdw->hdw_desc->default_std_mask; bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); pvr2_trace(PVR2_TRACE_STD, - "Supported video standard(s) reported by eeprom: %.*s", + "Supported video standard(s) reported available" + " in hardware: %.*s", bcnt,buf); hdw->std_mask_avail = hdw->std_mask_eeprom; - std2 = std1 & ~hdw->std_mask_avail; + std2 = (std1|std3) & ~hdw->std_mask_avail; if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); pvr2_trace(PVR2_TRACE_STD, @@ -1772,6 +1558,16 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) pvr2_hdw_internal_find_stdenum(hdw); return; } + if (std3) { + bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); + pvr2_trace(PVR2_TRACE_STD, + "Initial video standard" + " (determined by device type): %.*s",bcnt,buf); + hdw->std_mask_cur = std3; + hdw->std_dirty = !0; + pvr2_hdw_internal_find_stdenum(hdw); + return; + } { unsigned int idx; @@ -1816,8 +1612,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) unsigned int idx; struct pvr2_ctrl *cptr; int reloadFl = 0; - if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || - (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (hdw->hdw_desc->fx2_firmware.cnt) { if (!reloadFl) { reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints @@ -1853,25 +1648,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) } if (!pvr2_hdw_dev_ok(hdw)) return; - if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) { - for (idx = 0; - idx < pvr2_client_lists[hdw->hdw_type].cnt; - idx++) { - request_module( - pvr2_client_lists[hdw->hdw_type].lst[idx]); - } + for (idx = 0; idx < hdw->hdw_desc->client_modules.cnt; idx++) { + request_module(hdw->hdw_desc->client_modules.lst[idx]); } - if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) || - (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) { + if (!hdw->hdw_desc->flag_no_powerup) { pvr2_hdw_cmd_powerup(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; - - if (pvr2_upload_firmware2(hdw)){ - pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!"); - pvr2_hdw_render_useless(hdw); - return; - } } // This step MUST happen after the earlier powerup step. @@ -1899,15 +1682,22 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) // thread-safe against the normal pvr2_send_request() mechanism. // (We should make it thread safe). - ret = pvr2_hdw_get_eeprom_addr(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; - if (ret < 0) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to determine location of eeprom, skipping"); - } else { - hdw->eeprom_addr = ret; - pvr2_eeprom_analyze(hdw); + if (hdw->hdw_desc->flag_has_hauppauge_rom) { + ret = pvr2_hdw_get_eeprom_addr(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; + if (ret < 0) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Unable to determine location of eeprom," + " skipping"); + } else { + hdw->eeprom_addr = ret; + pvr2_eeprom_analyze(hdw); + if (!pvr2_hdw_dev_ok(hdw)) return; + } + } else { + hdw->tuner_type = hdw->hdw_desc->default_tuner_type; + hdw->tuner_updated = !0; + hdw->std_mask_eeprom = V4L2_STD_ALL; } pvr2_hdw_setup_std(hdw); @@ -1918,14 +1708,12 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) hdw->tuner_type); } - hdw->tuner_updated = !0; pvr2_i2c_core_check_stale(hdw); hdw->tuner_updated = 0; if (!pvr2_hdw_dev_ok(hdw)) return; - pvr2_hdw_commit_ctl_internal(hdw); - if (!pvr2_hdw_dev_ok(hdw)) return; + pvr2_hdw_commit_setup(hdw); hdw->vid_stream = pvr2_stream_create(); if (!pvr2_hdw_dev_ok(hdw)) return; @@ -1945,25 +1733,25 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; - /* Make sure everything is up to date */ - pvr2_i2c_core_sync(hdw); - - if (!pvr2_hdw_dev_ok(hdw)) return; - hdw->flag_init_ok = !0; + + pvr2_hdw_state_sched(hdw); } -int pvr2_hdw_setup(struct pvr2_hdw *hdw) +/* Set up the structure and attempt to put the device into a usable state. + This can be a time-consuming operation, which is why it is not done + internally as part of the create() step. */ +static void pvr2_hdw_setup(struct pvr2_hdw *hdw) { pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw); - LOCK_TAKE(hdw->big_lock); do { + do { pvr2_hdw_setup_low(hdw); pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d", - hdw,hdw->flag_ok,hdw->flag_init_ok); + hdw,pvr2_hdw_dev_ok(hdw),hdw->flag_init_ok); if (pvr2_hdw_dev_ok(hdw)) { - if (pvr2_hdw_init_ok(hdw)) { + if (hdw->flag_init_ok) { pvr2_trace( PVR2_TRACE_INFO, "Device initialization" @@ -2013,9 +1801,8 @@ int pvr2_hdw_setup(struct pvr2_hdw *hdw) " the pvrusb2 device" " in order to recover."); } - } while (0); LOCK_GIVE(hdw->big_lock); + } while (0); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); - return hdw->flag_init_ok; } @@ -2026,24 +1813,32 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, { unsigned int idx,cnt1,cnt2; struct pvr2_hdw *hdw; - unsigned int hdw_type; int valid_std_mask; struct pvr2_ctrl *cptr; + const struct pvr2_device_desc *hdw_desc; __u8 ifnum; struct v4l2_queryctrl qctrl; struct pvr2_ctl_info *ciptr; - hdw_type = devid - pvr2_device_table; - if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) { - pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Bogus device type of %u reported",hdw_type); - return NULL; - } + hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", - hdw,pvr2_device_names[hdw_type]); + hdw,hdw_desc->description); if (!hdw) goto fail; + + init_timer(&hdw->quiescent_timer); + hdw->quiescent_timer.data = (unsigned long)hdw; + hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout; + + init_timer(&hdw->encoder_wait_timer); + hdw->encoder_wait_timer.data = (unsigned long)hdw; + hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout; + + hdw->master_state = PVR2_STATE_DEAD; + + init_waitqueue_head(&hdw->state_wait_data); + hdw->tuner_signal_stale = !0; cx2341x_fill_defaults(&hdw->enc_ctl_state); @@ -2052,7 +1847,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, GFP_KERNEL); if (!hdw->controls) goto fail; - hdw->hdw_type = hdw_type; + hdw->hdw_desc = hdw_desc; for (idx = 0; idx < hdw->control_cnt; idx++) { cptr = hdw->controls + idx; cptr->hdw = hdw; @@ -2184,18 +1979,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; hdw->name[cnt1] = 0; + hdw->workqueue = create_singlethread_workqueue(hdw->name); + INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); + INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c); + INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init); + pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", hdw->unit_number,hdw->name); hdw->tuner_type = -1; hdw->flag_ok = !0; - /* Initialize the mask of subsystems that we will shut down when we - stop streaming. */ - hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL; - hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); - - pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx", - hdw->subsys_stream_mask); hdw->usb_intf = intf; hdw->usb_dev = interface_to_usbdev(intf); @@ -2211,15 +2004,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, mutex_init(&hdw->ctl_lock_mutex); mutex_init(&hdw->big_lock_mutex); + queue_work(hdw->workqueue,&hdw->workinit); return hdw; fail: if (hdw) { + del_timer_sync(&hdw->quiescent_timer); + del_timer_sync(&hdw->encoder_wait_timer); + if (hdw->workqueue) { + flush_workqueue(hdw->workqueue); + destroy_workqueue(hdw->workqueue); + hdw->workqueue = NULL; + } usb_free_urb(hdw->ctl_read_urb); usb_free_urb(hdw->ctl_write_urb); kfree(hdw->ctl_read_buffer); kfree(hdw->ctl_write_buffer); kfree(hdw->controls); kfree(hdw->mpeg_ctrl_info); + kfree(hdw->std_defs); + kfree(hdw->std_enum_names); kfree(hdw); } return NULL; @@ -2250,10 +2053,10 @@ static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw) kfree(hdw->ctl_write_buffer); hdw->ctl_write_buffer = NULL; } - pvr2_hdw_render_useless_unlocked(hdw); hdw->flag_disconnected = !0; hdw->usb_dev = NULL; hdw->usb_intf = NULL; + pvr2_hdw_render_useless(hdw); } @@ -2262,6 +2065,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) { if (!hdw) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw); + del_timer_sync(&hdw->quiescent_timer); + del_timer_sync(&hdw->encoder_wait_timer); + if (hdw->workqueue) { + flush_workqueue(hdw->workqueue); + destroy_workqueue(hdw->workqueue); + hdw->workqueue = NULL; + } if (hdw->fw_buffer) { kfree(hdw->fw_buffer); hdw->fw_buffer = NULL; @@ -2290,12 +2100,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) } -int pvr2_hdw_init_ok(struct pvr2_hdw *hdw) -{ - return hdw->flag_init_ok; -} - - int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw) { return (hdw && hdw->flag_ok); @@ -2473,17 +2277,11 @@ static const char *get_ctrl_typename(enum pvr2_ctl_type tp) } -/* Commit all control changes made up to this point. Subsystems can be - indirectly affected by these changes. For a given set of things being - committed, we'll clear the affected subsystem bits and then once we're - done committing everything we'll make a request to restore the subsystem - state(s) back to their previous value before this function was called. - Thus we can automatically reconfigure affected pieces of the driver as - controls are changed. */ -static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) +/* Figure out if we need to commit control changes. If so, mark internal + state flags to indicate this fact and return true. Otherwise do nothing + else and return false. */ +static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw) { - unsigned long saved_subsys_mask = hdw->subsys_enabled_mask; - unsigned long stale_subsys_mask = 0; unsigned int idx; struct pvr2_ctrl *cptr; int value; @@ -2518,6 +2316,25 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) return 0; } + hdw->state_pipeline_config = 0; + trace_stbit("state_pipeline_config",hdw->state_pipeline_config); + pvr2_hdw_state_sched(hdw); + + return !0; +} + + +/* Perform all operations needed to commit all control changes. This must + be performed in synchronization with the pipeline state and is thus + expected to be called as part of the driver's worker thread. Return + true if commit successful, otherwise return false to indicate that + commit isn't possible at this time. */ +static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) +{ + unsigned int idx; + struct pvr2_ctrl *cptr; + int disruptive_change; + /* When video standard changes, reset the hres and vres values - but if the user has pending changes there, then let the changes take priority. */ @@ -2536,24 +2353,26 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) } } - if (hdw->std_dirty || - hdw->enc_stale || - hdw->srate_dirty || - hdw->res_ver_dirty || - hdw->res_hor_dirty || - 0) { - /* If any of this changes, then the encoder needs to be - reconfigured, and we need to reset the stream. */ - stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG); - } - - if (hdw->input_dirty) { - /* pk: If input changes to or from radio, then the encoder - needs to be restarted (for ENC_MUTE_VIDEO to work) */ - stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN); + /* If any of the below has changed, then we can't do the update + while the pipeline is running. Pipeline must be paused first + and decoder -> encoder connection be made quiescent before we + can proceed. */ + disruptive_change = + (hdw->std_dirty || + hdw->enc_unsafe_stale || + hdw->srate_dirty || + hdw->res_ver_dirty || + hdw->res_hor_dirty || + hdw->input_dirty || + (hdw->active_stream_type != hdw->desired_stream_type)); + if (disruptive_change && !hdw->state_pipeline_idle) { + /* Pipeline is not idle; we can't proceed. Arrange to + cause pipeline to stop so that we can try this again + later.... */ + hdw->state_pipeline_pause = !0; + return 0; } - if (hdw->srate_dirty) { /* Write new sample rate into control structure since * the master copy is stale. We must track srate @@ -2582,51 +2401,88 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) cptr->info->clear_dirty(cptr); } + if (hdw->active_stream_type != hdw->desired_stream_type) { + /* Handle any side effects of stream config here */ + hdw->active_stream_type = hdw->desired_stream_type; + } + /* Now execute i2c core update */ pvr2_i2c_core_sync(hdw); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0); - pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask); + if (hdw->state_encoder_run) { + /* If encoder isn't running, then this will get worked out + later when we start the encoder. */ + if (pvr2_encoder_adjust(hdw) < 0) return !0; + } - return 0; + hdw->state_pipeline_config = !0; + trace_stbit("state_pipeline_config",hdw->state_pipeline_config); + return !0; } int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw) { + int fl; + LOCK_TAKE(hdw->big_lock); + fl = pvr2_hdw_commit_setup(hdw); + LOCK_GIVE(hdw->big_lock); + if (!fl) return 0; + return pvr2_hdw_wait(hdw,0); +} + + +static void pvr2_hdw_worker_i2c(struct work_struct *work) +{ + struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,worki2csync); LOCK_TAKE(hdw->big_lock); do { - pvr2_hdw_commit_ctl_internal(hdw); + pvr2_i2c_core_sync(hdw); } while (0); LOCK_GIVE(hdw->big_lock); - return 0; } -void pvr2_hdw_poll(struct pvr2_hdw *hdw) +static void pvr2_hdw_worker_poll(struct work_struct *work) { + int fl = 0; + struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workpoll); LOCK_TAKE(hdw->big_lock); do { - pvr2_i2c_core_sync(hdw); + fl = pvr2_hdw_state_eval(hdw); } while (0); LOCK_GIVE(hdw->big_lock); + if (fl && hdw->state_func) { + hdw->state_func(hdw->state_data); + } } -void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw, - void (*func)(void *), - void *data) +static void pvr2_hdw_worker_init(struct work_struct *work) { + struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit); LOCK_TAKE(hdw->big_lock); do { - hdw->poll_trigger_func = func; - hdw->poll_trigger_data = data; + pvr2_hdw_setup(hdw); } while (0); LOCK_GIVE(hdw->big_lock); } -void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw) +static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state) { - if (hdw->poll_trigger_func) { - hdw->poll_trigger_func(hdw->poll_trigger_data); - } + return wait_event_interruptible( + hdw->state_wait_data, + (hdw->state_stale == 0) && + (!state || (hdw->master_state != state))); } + +void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw, + void (*callback_func)(void *), + void *callback_data) +{ + LOCK_TAKE(hdw->big_lock); do { + hdw->state_data = callback_data; + hdw->state_func = callback_func; + } while (0); LOCK_GIVE(hdw->big_lock); +} + + /* Return name for this driver instance */ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) { @@ -2634,6 +2490,18 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw) } +const char *pvr2_hdw_get_desc(struct pvr2_hdw *hdw) +{ + return hdw->hdw_desc->description; +} + + +const char *pvr2_hdw_get_type(struct pvr2_hdw *hdw) +{ + return hdw->hdw_desc->shortname; +} + + int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw) { int result; @@ -2689,6 +2557,7 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) pvr2_i2c_core_sync(hdw); pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2"); + pvr2_hdw_state_log_state(hdw); printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); } while (0); LOCK_GIVE(hdw->big_lock); } @@ -2959,7 +2828,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, " without lock!!"); return -EDEADLK; } - if ((!hdw->flag_ok) && !probe_fl) { + if (!hdw->flag_ok && !probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "Attempted to execute control transfer" " when device not ok"); @@ -3167,7 +3036,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, hdw->cmd_debug_state = 0; if ((status < 0) && (!probe_fl)) { - pvr2_hdw_render_useless_unlocked(hdw); + pvr2_hdw_render_useless(hdw); } return status; } @@ -3227,24 +3096,17 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data) } -static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw) +void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) { if (!hdw->flag_ok) return; - pvr2_trace(PVR2_TRACE_INIT,"render_useless"); - hdw->flag_ok = 0; + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Device being rendered inoperable"); if (hdw->vid_stream) { pvr2_stream_setup(hdw->vid_stream,NULL,0,0); } - hdw->flag_streaming_enabled = 0; - hdw->subsys_enabled_mask = 0; -} - - -void pvr2_hdw_render_useless(struct pvr2_hdw *hdw) -{ - LOCK_TAKE(hdw->ctl_lock); - pvr2_hdw_render_useless_unlocked(hdw); - LOCK_GIVE(hdw->ctl_lock); + hdw->flag_ok = 0; + trace_stbit("flag_ok",hdw->flag_ok); + pvr2_hdw_state_sched(hdw); } @@ -3299,7 +3161,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw) int status; LOCK_TAKE(hdw->ctl_lock); do { pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset"); - hdw->flag_ok = !0; hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET; status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0); } while (0); LOCK_GIVE(hdw->ctl_lock); @@ -3349,26 +3210,473 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl) (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF); status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0); } while (0); LOCK_GIVE(hdw->ctl_lock); - if (!status) { - hdw->subsys_enabled_mask = - ((hdw->subsys_enabled_mask & - ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) | - (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0)); - } return status; } -void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *ptr) +/* Evaluate whether or not state_encoder_ok can change */ +static int state_eval_encoder_ok(struct pvr2_hdw *hdw) +{ + if (hdw->state_encoder_ok) return 0; + if (hdw->flag_tripped) return 0; + if (hdw->state_encoder_run) return 0; + if (hdw->state_encoder_config) return 0; + if (hdw->state_decoder_run) return 0; + if (hdw->state_usbstream_run) return 0; + if (pvr2_upload_firmware2(hdw) < 0) { + hdw->flag_tripped = !0; + trace_stbit("flag_tripped",hdw->flag_tripped); + return !0; + } + hdw->state_encoder_ok = !0; + trace_stbit("state_encoder_ok",hdw->state_encoder_ok); + return !0; +} + + +/* Evaluate whether or not state_encoder_config can change */ +static int state_eval_encoder_config(struct pvr2_hdw *hdw) +{ + if (hdw->state_encoder_config) { + if (hdw->state_encoder_ok) { + if (hdw->state_pipeline_req && + !hdw->state_pipeline_pause) return 0; + } + hdw->state_encoder_config = 0; + hdw->state_encoder_waitok = 0; + trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); + /* paranoia - solve race if timer just completed */ + del_timer_sync(&hdw->encoder_wait_timer); + } else { + if (!hdw->state_encoder_ok || + !hdw->state_pipeline_idle || + hdw->state_pipeline_pause || + !hdw->state_pipeline_req || + !hdw->state_pipeline_config) { + /* We must reset the enforced wait interval if + anything has happened that might have disturbed + the encoder. This should be a rare case. */ + if (timer_pending(&hdw->encoder_wait_timer)) { + del_timer_sync(&hdw->encoder_wait_timer); + } + if (hdw->state_encoder_waitok) { + /* Must clear the state - therefore we did + something to a state bit and must also + return true. */ + hdw->state_encoder_waitok = 0; + trace_stbit("state_encoder_waitok", + hdw->state_encoder_waitok); + return !0; + } + return 0; + } + if (!hdw->state_encoder_waitok) { + if (!timer_pending(&hdw->encoder_wait_timer)) { + /* waitok flag wasn't set and timer isn't + running. Check flag once more to avoid + a race then start the timer. This is + the point when we measure out a minimal + quiet interval before doing something to + the encoder. */ + if (!hdw->state_encoder_waitok) { + hdw->encoder_wait_timer.expires = + jiffies + (HZ*50/1000); + add_timer(&hdw->encoder_wait_timer); + } + } + /* We can't continue until we know we have been + quiet for the interval measured by this + timer. */ + return 0; + } + pvr2_encoder_configure(hdw); + if (hdw->state_encoder_ok) hdw->state_encoder_config = !0; + } + trace_stbit("state_encoder_config",hdw->state_encoder_config); + return !0; +} + + +/* Evaluate whether or not state_encoder_run can change */ +static int state_eval_encoder_run(struct pvr2_hdw *hdw) +{ + if (hdw->state_encoder_run) { + if (hdw->state_encoder_ok) { + if (hdw->state_decoder_run) return 0; + if (pvr2_encoder_stop(hdw) < 0) return !0; + } + hdw->state_encoder_run = 0; + } else { + if (!hdw->state_encoder_ok) return 0; + if (!hdw->state_decoder_run) return 0; + if (pvr2_encoder_start(hdw) < 0) return !0; + hdw->state_encoder_run = !0; + } + trace_stbit("state_encoder_run",hdw->state_encoder_run); + return !0; +} + + +/* Timeout function for quiescent timer. */ +static void pvr2_hdw_quiescent_timeout(unsigned long data) +{ + struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; + hdw->state_decoder_quiescent = !0; + trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); + hdw->state_stale = !0; + queue_work(hdw->workqueue,&hdw->workpoll); +} + + +/* Timeout function for encoder wait timer. */ +static void pvr2_hdw_encoder_wait_timeout(unsigned long data) +{ + struct pvr2_hdw *hdw = (struct pvr2_hdw *)data; + hdw->state_encoder_waitok = !0; + trace_stbit("state_encoder_waitok",hdw->state_encoder_waitok); + hdw->state_stale = !0; + queue_work(hdw->workqueue,&hdw->workpoll); +} + + +/* Evaluate whether or not state_decoder_run can change */ +static int state_eval_decoder_run(struct pvr2_hdw *hdw) +{ + if (hdw->state_decoder_run) { + if (hdw->state_encoder_ok) { + if (hdw->state_pipeline_req && + !hdw->state_pipeline_pause) return 0; + } + if (!hdw->flag_decoder_missed) { + pvr2_decoder_enable(hdw,0); + } + hdw->state_decoder_quiescent = 0; + hdw->state_decoder_run = 0; + /* paranoia - solve race if timer just completed */ + del_timer_sync(&hdw->quiescent_timer); + } else { + if (!hdw->state_decoder_quiescent) { + if (!timer_pending(&hdw->quiescent_timer)) { + /* We don't do something about the + quiescent timer until right here because + we also want to catch cases where the + decoder was already not running (like + after initialization) as opposed to + knowing that we had just stopped it. + The second flag check is here to cover a + race - the timer could have run and set + this flag just after the previous check + but before we did the pending check. */ + if (!hdw->state_decoder_quiescent) { + hdw->quiescent_timer.expires = + jiffies + (HZ*50/1000); + add_timer(&hdw->quiescent_timer); + } + } + /* Don't allow decoder to start again until it has + been quiesced first. This little detail should + hopefully further stabilize the encoder. */ + return 0; + } + if (!hdw->state_pipeline_req || + hdw->state_pipeline_pause || + !hdw->state_pipeline_config || + !hdw->state_encoder_config || + !hdw->state_encoder_ok) return 0; + del_timer_sync(&hdw->quiescent_timer); + if (hdw->flag_decoder_missed) return 0; + if (pvr2_decoder_enable(hdw,!0) < 0) return 0; + hdw->state_decoder_quiescent = 0; + hdw->state_decoder_run = !0; + } + trace_stbit("state_decoder_quiescent",hdw->state_decoder_quiescent); + trace_stbit("state_decoder_run",hdw->state_decoder_run); + return !0; +} + + +/* Evaluate whether or not state_usbstream_run can change */ +static int state_eval_usbstream_run(struct pvr2_hdw *hdw) +{ + if (hdw->state_usbstream_run) { + if (hdw->state_encoder_ok) { + if (hdw->state_encoder_run) return 0; + } + pvr2_hdw_cmd_usbstream(hdw,0); + hdw->state_usbstream_run = 0; + } else { + if (!hdw->state_encoder_ok || + !hdw->state_encoder_run || + !hdw->state_pipeline_req || + hdw->state_pipeline_pause) return 0; + if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0; + hdw->state_usbstream_run = !0; + } + trace_stbit("state_usbstream_run",hdw->state_usbstream_run); + return !0; +} + + +/* Attempt to configure pipeline, if needed */ +static int state_eval_pipeline_config(struct pvr2_hdw *hdw) +{ + if (hdw->state_pipeline_config || + hdw->state_pipeline_pause) return 0; + pvr2_hdw_commit_execute(hdw); + return !0; +} + + +/* Update pipeline idle and pipeline pause tracking states based on other + inputs. This must be called whenever the other relevant inputs have + changed. */ +static int state_update_pipeline_state(struct pvr2_hdw *hdw) +{ + unsigned int st; + int updatedFl = 0; + /* Update pipeline state */ + st = !(hdw->state_encoder_run || + hdw->state_decoder_run || + hdw->state_usbstream_run || + (!hdw->state_decoder_quiescent)); + if (!st != !hdw->state_pipeline_idle) { + hdw->state_pipeline_idle = st; + updatedFl = !0; + } + if (hdw->state_pipeline_idle && hdw->state_pipeline_pause) { + hdw->state_pipeline_pause = 0; + updatedFl = !0; + } + return updatedFl; +} + + +typedef int (*state_eval_func)(struct pvr2_hdw *); + +/* Set of functions to be run to evaluate various states in the driver. */ +const static state_eval_func eval_funcs[] = { + state_eval_pipeline_config, + state_eval_encoder_ok, + state_eval_encoder_config, + state_eval_decoder_run, + state_eval_encoder_run, + state_eval_usbstream_run, +}; + + +/* Process various states and return true if we did anything interesting. */ +static int pvr2_hdw_state_update(struct pvr2_hdw *hdw) +{ + unsigned int i; + int state_updated = 0; + int check_flag; + + if (!hdw->state_stale) return 0; + if ((hdw->fw1_state != FW1_STATE_OK) || + !hdw->flag_ok) { + hdw->state_stale = 0; + return !0; + } + /* This loop is the heart of the entire driver. It keeps trying to + evaluate various bits of driver state until nothing changes for + one full iteration. Each "bit of state" tracks some global + aspect of the driver, e.g. whether decoder should run, if + pipeline is configured, usb streaming is on, etc. We separately + evaluate each of those questions based on other driver state to + arrive at the correct running configuration. */ + do { + check_flag = 0; + state_update_pipeline_state(hdw); + /* Iterate over each bit of state */ + for (i = 0; (i<ARRAY_SIZE(eval_funcs)) && hdw->flag_ok; i++) { + if ((*eval_funcs[i])(hdw)) { + check_flag = !0; + state_updated = !0; + state_update_pipeline_state(hdw); + } + } + } while (check_flag && hdw->flag_ok); + hdw->state_stale = 0; + trace_stbit("state_stale",hdw->state_stale); + return state_updated; +} + + +static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, + char *buf,unsigned int acnt) +{ + switch (which) { + case 0: + return scnprintf( + buf,acnt, + "driver:%s%s%s%s%s", + (hdw->flag_ok ? " <ok>" : " <fail>"), + (hdw->flag_init_ok ? " <init>" : " <uninitialized>"), + (hdw->flag_disconnected ? " <disconnected>" : + " <connected>"), + (hdw->flag_tripped ? " <tripped>" : ""), + (hdw->flag_decoder_missed ? " <no decoder>" : "")); + case 1: + return scnprintf( + buf,acnt, + "pipeline:%s%s%s%s", + (hdw->state_pipeline_idle ? " <idle>" : ""), + (hdw->state_pipeline_config ? + " <configok>" : " <stale>"), + (hdw->state_pipeline_req ? " <req>" : ""), + (hdw->state_pipeline_pause ? " <pause>" : "")); + case 2: + return scnprintf( + buf,acnt, + "worker:%s%s%s%s%s%s", + (hdw->state_decoder_run ? + " <decode:run>" : + (hdw->state_decoder_quiescent ? + "" : " <decode:stop>")), + (hdw->state_decoder_quiescent ? + " <decode:quiescent>" : ""), + (hdw->state_encoder_ok ? + "" : " <encode:init>"), + (hdw->state_encoder_run ? + " <encode:run>" : " <encode:stop>"), + (hdw->state_encoder_config ? + " <encode:configok>" : + (hdw->state_encoder_waitok ? + "" : " <encode:wait>")), + (hdw->state_usbstream_run ? + " <usb:run>" : " <usb:stop>")); + break; + case 3: + return scnprintf( + buf,acnt, + "state: %s", + pvr2_get_state_name(hdw->master_state)); + break; + default: break; + } + return 0; +} + + +unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, + char *buf,unsigned int acnt) +{ + unsigned int bcnt,ccnt,idx; + bcnt = 0; + LOCK_TAKE(hdw->big_lock); + for (idx = 0; ; idx++) { + ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,acnt); + if (!ccnt) break; + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + if (!acnt) break; + buf[0] = '\n'; ccnt = 1; + bcnt += ccnt; acnt -= ccnt; buf += ccnt; + } + LOCK_GIVE(hdw->big_lock); + return bcnt; +} + + +static void pvr2_hdw_state_log_state(struct pvr2_hdw *hdw) +{ + char buf[128]; + unsigned int idx,ccnt; + + for (idx = 0; ; idx++) { + ccnt = pvr2_hdw_report_unlocked(hdw,idx,buf,sizeof(buf)); + if (!ccnt) break; + printk(KERN_INFO "%s %.*s\n",hdw->name,ccnt,buf); + } +} + + +/* Evaluate and update the driver's current state, taking various actions + as appropriate for the update. */ +static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw) +{ + unsigned int st; + int state_updated = 0; + int callback_flag = 0; + + pvr2_trace(PVR2_TRACE_STBITS, + "Drive state check START"); + if (pvrusb2_debug & PVR2_TRACE_STBITS) { + pvr2_hdw_state_log_state(hdw); + } + + /* Process all state and get back over disposition */ + state_updated = pvr2_hdw_state_update(hdw); + + /* Update master state based upon all other states. */ + if (!hdw->flag_ok) { + st = PVR2_STATE_DEAD; + } else if (hdw->fw1_state != FW1_STATE_OK) { + st = PVR2_STATE_COLD; + } else if (!hdw->state_encoder_ok) { + st = PVR2_STATE_WARM; + } else if (hdw->flag_tripped || hdw->flag_decoder_missed) { + st = PVR2_STATE_ERROR; + } else if (hdw->state_encoder_run && + hdw->state_decoder_run && + hdw->state_usbstream_run) { + st = PVR2_STATE_RUN; + } else { + st = PVR2_STATE_READY; + } + if (hdw->master_state != st) { + pvr2_trace(PVR2_TRACE_STATE, + "Device state change from %s to %s", + pvr2_get_state_name(hdw->master_state), + pvr2_get_state_name(st)); + hdw->master_state = st; + state_updated = !0; + callback_flag = !0; + } + if (state_updated) { + /* Trigger anyone waiting on any state changes here. */ + wake_up(&hdw->state_wait_data); + } + + if (pvrusb2_debug & PVR2_TRACE_STBITS) { + pvr2_hdw_state_log_state(hdw); + } + pvr2_trace(PVR2_TRACE_STBITS, + "Drive state check DONE callback=%d",callback_flag); + + return callback_flag; +} + + +/* Cause kernel thread to check / update driver state */ +static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw) +{ + if (hdw->state_stale) return; + hdw->state_stale = !0; + trace_stbit("state_stale",hdw->state_stale); + queue_work(hdw->workqueue,&hdw->workpoll); +} + + +void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *ptr) { ptr->big_lock_held = hdw->big_lock_held; ptr->ctl_lock_held = hdw->ctl_lock_held; - ptr->flag_ok = hdw->flag_ok; ptr->flag_disconnected = hdw->flag_disconnected; ptr->flag_init_ok = hdw->flag_init_ok; - ptr->flag_streaming_enabled = hdw->flag_streaming_enabled; - ptr->subsys_flags = hdw->subsys_enabled_mask; + ptr->flag_ok = hdw->flag_ok; + ptr->fw1_state = hdw->fw1_state; + ptr->flag_decoder_missed = hdw->flag_decoder_missed; + ptr->flag_tripped = hdw->flag_tripped; + ptr->state_encoder_ok = hdw->state_encoder_ok; + ptr->state_encoder_run = hdw->state_encoder_run; + ptr->state_decoder_run = hdw->state_decoder_run; + ptr->state_usbstream_run = hdw->state_usbstream_run; + ptr->state_decoder_quiescent = hdw->state_decoder_quiescent; + ptr->state_pipeline_config = hdw->state_pipeline_config; + ptr->state_pipeline_req = hdw->state_pipeline_req; + ptr->state_pipeline_pause = hdw->state_pipeline_pause; + ptr->state_pipeline_idle = hdw->state_pipeline_idle; ptr->cmd_debug_state = hdw->cmd_debug_state; ptr->cmd_code = hdw->cmd_debug_code; ptr->cmd_debug_write_len = hdw->cmd_debug_write_len; @@ -3381,6 +3689,15 @@ void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, } +void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *ptr) +{ + LOCK_TAKE(hdw->ctl_lock); do { + pvr2_hdw_get_debug_info_unlocked(hdw,ptr); + } while(0); LOCK_GIVE(hdw->ctl_lock); +} + + int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp) { return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp); diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index e2f9d5e4cb65..3ad7a13d6c39 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -44,27 +44,6 @@ #define PVR2_CVAL_INPUT_COMPOSITE 2 #define PVR2_CVAL_INPUT_RADIO 3 -/* Subsystem definitions - these are various pieces that can be - independently stopped / started. Usually you don't want to mess with - this directly (let the driver handle things itself), but it is useful - for debugging. */ -#define PVR2_SUBSYS_B_ENC_FIRMWARE 0 -#define PVR2_SUBSYS_B_ENC_CFG 1 -#define PVR2_SUBSYS_B_DIGITIZER_RUN 2 -#define PVR2_SUBSYS_B_USBSTREAM_RUN 3 -#define PVR2_SUBSYS_B_ENC_RUN 4 - -#define PVR2_SUBSYS_CFG_ALL ( \ - (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \ - (1 << PVR2_SUBSYS_B_ENC_CFG) ) -#define PVR2_SUBSYS_RUN_ALL ( \ - (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \ - (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \ - (1 << PVR2_SUBSYS_B_ENC_RUN) ) -#define PVR2_SUBSYS_ALL ( \ - PVR2_SUBSYS_CFG_ALL | \ - PVR2_SUBSYS_RUN_ALL ) - enum pvr2_config { pvr2_config_empty, /* No configuration */ pvr2_config_mpeg, /* Encoded / compressed video */ @@ -79,8 +58,41 @@ enum pvr2_v4l_type { pvr2_v4l_type_radio, }; +/* Major states that we can be in: + * + * DEAD - Device is in an unusable state and cannot be recovered. This + * can happen if we completely lose the ability to communicate with it + * (but it might still on the bus). In this state there's nothing we can + * do; it must be replugged in order to recover. + * + * COLD - Device is in an unusuable state, needs microcontroller firmware. + * + * WARM - We can communicate with the device and the proper + * microcontroller firmware is running, but other device initialization is + * still needed (e.g. encoder firmware). + * + * ERROR - A problem prevents capture operation (e.g. encoder firmware + * missing). + * + * READY - Device is operational, but not streaming. + * + * RUN - Device is streaming. + * + */ +#define PVR2_STATE_NONE 0 +#define PVR2_STATE_DEAD 1 +#define PVR2_STATE_COLD 2 +#define PVR2_STATE_WARM 3 +#define PVR2_STATE_ERROR 4 +#define PVR2_STATE_READY 5 +#define PVR2_STATE_RUN 6 + +/* Translate configuration enum to a string label */ const char *pvr2_config_get_name(enum pvr2_config); +/* Translate a master state enum to a string label */ +const char *pvr2_hdw_get_state_name(unsigned int); + struct pvr2_hdw; /* Create and return a structure for interacting with the underlying @@ -88,28 +100,13 @@ struct pvr2_hdw; struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, const struct usb_device_id *devid); -/* Poll for background activity (if any) */ -void pvr2_hdw_poll(struct pvr2_hdw *); - -/* Trigger a poll to take place later at a convenient time */ -void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *); - -/* Register a callback used to trigger a future poll */ -void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *, - void (*func)(void *), - void *data); - /* Destroy hardware interaction structure */ void pvr2_hdw_destroy(struct pvr2_hdw *); -/* Set up the structure and attempt to put the device into a usable state. - This can be a time-consuming operation, which is why it is not done - internally as part of the create() step. Return value is exactly the - same as pvr2_hdw_init_ok(). */ -int pvr2_hdw_setup(struct pvr2_hdw *); - -/* Initialization succeeded */ -int pvr2_hdw_init_ok(struct pvr2_hdw *); +/* Register a function to be called whenever the master state changes. */ +void pvr2_hdw_set_state_callback(struct pvr2_hdw *, + void (*callback_func)(void *), + void *callback_data); /* Return true if in the ready (normal) state */ int pvr2_hdw_dev_ok(struct pvr2_hdw *); @@ -161,12 +158,21 @@ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *); /* Query device and see if it thinks it is on a high-speed USB link */ int pvr2_hdw_is_hsm(struct pvr2_hdw *); +/* Return a string token representative of the hardware type */ +const char *pvr2_hdw_get_type(struct pvr2_hdw *); + +/* Return a single line description of the hardware type */ +const char *pvr2_hdw_get_desc(struct pvr2_hdw *); + /* Turn streaming on/off */ int pvr2_hdw_set_streaming(struct pvr2_hdw *,int); /* Find out if streaming is on */ int pvr2_hdw_get_streaming(struct pvr2_hdw *); +/* Retrieve driver overall state */ +int pvr2_hdw_get_state(struct pvr2_hdw *); + /* Configure the type of stream to generate */ int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config); @@ -177,26 +183,6 @@ struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *); int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std, unsigned int idx); -/* Enable / disable various pieces of hardware. Items to change are - identified by bit positions within msk, and new state for each item is - identified by corresponding bit positions within val. */ -void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val); - -/* Retrieve mask indicating which pieces of hardware are currently enabled - / configured. */ -unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *); - -/* Adjust mask of what get shut down when streaming is stopped. This is a - debugging aid. */ -void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw, - unsigned long msk,unsigned long val); - -/* Retrieve mask indicating which pieces of hardware are disabled when - streaming is turned off. */ -unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *); - - /* Enable / disable retrieval of CPU firmware or prom contents. This must be enabled before pvr2_hdw_cpufw_get() will function. Note that doing this may prevent the device from running (and leaving this mode may @@ -253,6 +239,9 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int); /* Execute a USB-commanded device reset */ void pvr2_hdw_device_reset(struct pvr2_hdw *); +/* Reset worker's error trapping circuit breaker */ +int pvr2_hdw_untrip(struct pvr2_hdw *); + /* Execute hard reset command (after this point it's likely that the encoder will have to be reconfigured). This also clears the "useless" state. */ @@ -275,11 +264,21 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val); struct pvr2_hdw_debug_info { int big_lock_held; int ctl_lock_held; - int flag_ok; int flag_disconnected; int flag_init_ok; - int flag_streaming_enabled; - unsigned long subsys_flags; + int flag_ok; + int fw1_state; + int flag_decoder_missed; + int flag_tripped; + int state_encoder_ok; + int state_encoder_run; + int state_decoder_run; + int state_usbstream_run; + int state_decoder_quiescent; + int state_pipeline_config; + int state_pipeline_req; + int state_pipeline_pause; + int state_pipeline_idle; int cmd_debug_state; int cmd_debug_write_len; int cmd_debug_read_len; @@ -295,8 +294,20 @@ struct pvr2_hdw_debug_info { diagnosing lockups. Note that this operation is completed without any kind of locking and so it is not atomic and may yield inconsistent results. This is *purely* a debugging aid. */ -void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw, - struct pvr2_hdw_debug_info *); +void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *); + +/* Intrusively retrieve internal state info - this is useful for + diagnosing overall driver state. This operation synchronizes against + the overall driver mutex - so if there are locking problems this will + likely hang! This is *purely* a debugging aid. */ +void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw, + struct pvr2_hdw_debug_info *); + +/* Report out several lines of text that describes driver internal state. + Results are written into the passed-in buffer. */ +unsigned int pvr2_hdw_state_report(struct pvr2_hdw *hdw, + char *buf_ptr,unsigned int buf_size); /* Cause modules to log their state once */ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); @@ -306,9 +317,6 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw); a debugging aid. */ int pvr2_upload_firmware2(struct pvr2_hdw *hdw); -/* List of device types that we can match */ -extern struct usb_device_id pvr2_device_table[]; - #endif /* __PVRUSB2_HDW_H */ /* diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index c817c864e6a0..62867fa3517a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -895,7 +895,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) list_add_tail(&cp->list,&hdw->i2c_clients); hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT; } while (0); mutex_unlock(&hdw->i2c_list_lock); - if (fl) pvr2_hdw_poll_trigger_unlocked(hdw); + if (fl) queue_work(hdw->workqueue,&hdw->worki2csync); return 0; } @@ -980,14 +980,16 @@ 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_type == PVR2_HDW_TYPE_24XXX) { + if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) { hdw->i2c_func[0x18] = i2c_24xxx_ir; } } - if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) { - hdw->i2c_func[0x1b] = i2c_hack_wm8775; + if (hdw->hdw_desc->flag_has_cx25840) { hdw->i2c_func[0x44] = i2c_hack_cx25840; } + if (hdw->hdw_desc->flag_has_wm8775) { + hdw->i2c_func[0x1b] = i2c_hack_wm8775; + } // Configure the adapter and set up everything else related to it. memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap)); diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c index 11b3b2e84b90..b63b2265503a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-main.c +++ b/drivers/media/video/pvrusb2/pvrusb2-main.c @@ -28,6 +28,7 @@ #include <linux/videodev2.h> #include "pvrusb2-hdw.h" +#include "pvrusb2-devattr.h" #include "pvrusb2-context.h" #include "pvrusb2-debug.h" #include "pvrusb2-v4l2.h" @@ -148,11 +149,6 @@ static void __exit pvr_exit(void) module_init(pvr_init); module_exit(pvr_exit); -/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for - MODULE_DEVICE_TABLE(). We have to declare that attribute there - because that's where the device table actually is now and it seems - that certain gcc configurations get angry if MODULE_DEVICE_TABLE() - is used on what ends up being an external symbol. */ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c index 63e55bb59fcb..da309288daa4 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-std.c +++ b/drivers/media/video/pvrusb2/pvrusb2-std.c @@ -50,6 +50,10 @@ struct std_name { V4L2_STD_NTSC_M_KR| \ V4L2_STD_NTSC_443) +#define CSTD_ATSC \ + (V4L2_STD_ATSC_8_VSB| \ + V4L2_STD_ATSC_16_VSB) + #define CSTD_SECAM \ (V4L2_STD_SECAM_B| \ V4L2_STD_SECAM_D| \ @@ -82,6 +86,7 @@ static const struct std_name std_groups[] = { {"PAL",CSTD_PAL}, {"NTSC",CSTD_NTSC}, {"SECAM",CSTD_SECAM}, + {"ATSC",CSTD_ATSC}, }; /* Mapping of standard bits to modulation system */ @@ -104,6 +109,8 @@ static const struct std_name std_items[] = { {"N",TSTD_N}, {"Nc",TSTD_Nc}, {"60",TSTD_60}, + {"8VSB",V4L2_STD_ATSC_8_VSB}, + {"16VSB",V4L2_STD_ATSC_16_VSB}, }; diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 3c57a7d8200b..7a1cd878e31a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -43,10 +43,14 @@ struct pvr2_sysfs { struct device_attribute attr_v4l_radio_minor_number; struct device_attribute attr_unit_number; struct device_attribute attr_bus_info; + struct device_attribute attr_hdw_name; + struct device_attribute attr_hdw_desc; int v4l_minor_number_created_ok; int v4l_radio_minor_number_created_ok; int unit_number_created_ok; int bus_info_created_ok; + int hdw_name_created_ok; + int hdw_desc_created_ok; }; #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC @@ -712,6 +716,14 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp) pvr2_sysfs_tear_down_debugifc(sfp); #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */ pvr2_sysfs_tear_down_controls(sfp); + if (sfp->hdw_desc_created_ok) { + device_remove_file(sfp->class_dev, + &sfp->attr_hdw_desc); + } + if (sfp->hdw_name_created_ok) { + device_remove_file(sfp->class_dev, + &sfp->attr_hdw_name); + } if (sfp->bus_info_created_ok) { device_remove_file(sfp->class_dev, &sfp->attr_bus_info); @@ -758,6 +770,28 @@ static ssize_t bus_info_show(struct device *class_dev, } +static ssize_t hdw_name_show(struct device *class_dev, + struct device_attribute *attr, char *buf) +{ + struct pvr2_sysfs *sfp; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; + if (!sfp) return -EINVAL; + return scnprintf(buf,PAGE_SIZE,"%s\n", + pvr2_hdw_get_type(sfp->channel.hdw)); +} + + +static ssize_t hdw_desc_show(struct device *class_dev, + struct device_attribute *attr, char *buf) +{ + struct pvr2_sysfs *sfp; + sfp = (struct pvr2_sysfs *)class_dev->driver_data; + if (!sfp) return -EINVAL; + return scnprintf(buf,PAGE_SIZE,"%s\n", + pvr2_hdw_get_desc(sfp->channel.hdw)); +} + + static ssize_t v4l_radio_minor_number_show(struct device *class_dev, struct device_attribute *attr, char *buf) @@ -871,6 +905,32 @@ static void class_dev_create(struct pvr2_sysfs *sfp, sfp->bus_info_created_ok = !0; } + sfp->attr_hdw_name.attr.name = "device_hardware_type"; + sfp->attr_hdw_name.attr.mode = S_IRUGO; + sfp->attr_hdw_name.show = hdw_name_show; + sfp->attr_hdw_name.store = NULL; + ret = device_create_file(sfp->class_dev, + &sfp->attr_hdw_name); + if (ret < 0) { + printk(KERN_WARNING "%s: device_create_file error: %d\n", + __FUNCTION__, ret); + } else { + sfp->hdw_name_created_ok = !0; + } + + sfp->attr_hdw_desc.attr.name = "device_hardware_description"; + sfp->attr_hdw_desc.attr.mode = S_IRUGO; + sfp->attr_hdw_desc.show = hdw_desc_show; + sfp->attr_hdw_desc.store = NULL; + ret = device_create_file(sfp->class_dev, + &sfp->attr_hdw_desc); + if (ret < 0) { + printk(KERN_WARNING "%s: device_create_file error: %d\n", + __FUNCTION__, ret); + } else { + sfp->hdw_desc_created_ok = !0; + } + pvr2_sysfs_add_controls(sfp); #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC pvr2_sysfs_add_debugifc(sfp); diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 7a596ea7cfe6..8f0587ebd4bd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -205,6 +205,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw), sizeof(cap->bus_info)); + strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card)); ret = 0; break; @@ -1015,10 +1016,8 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) sp = fh->dev_info->stream->stream; pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh); pvr2_hdw_set_stream_type(hdw,fh->dev_info->config); - pvr2_hdw_set_streaming(hdw,!0); - ret = pvr2_ioread_set_enabled(fh->rhp,!0); - - return ret; + if ((ret = pvr2_hdw_set_streaming(hdw,!0)) < 0) return ret; + return pvr2_ioread_set_enabled(fh->rhp,!0); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 61efa6f02200..7c47345501b6 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -49,29 +49,50 @@ struct pvr2_v4l_decoder { }; +struct routing_scheme { + const int *def; + unsigned int cnt; +}; + + +static const int routing_scheme0[] = { + [PVR2_CVAL_INPUT_TV] = SAA7115_COMPOSITE4, + /* In radio mode, we mute the video, but point at one + spot just to stay consistent */ + [PVR2_CVAL_INPUT_RADIO] = SAA7115_COMPOSITE5, + [PVR2_CVAL_INPUT_COMPOSITE] = SAA7115_COMPOSITE5, + [PVR2_CVAL_INPUT_SVIDEO] = SAA7115_SVIDEO2, +}; + +static const struct routing_scheme routing_schemes[] = { + [PVR2_ROUTING_SCHEME_HAUPPAUGE] = { + .def = routing_scheme0, + .cnt = ARRAY_SIZE(routing_scheme0), + }, +}; + static void set_input(struct pvr2_v4l_decoder *ctxt) { struct pvr2_hdw *hdw = ctxt->hdw; struct v4l2_routing route; + const struct routing_scheme *sp; + unsigned int sid = hdw->hdw_desc->signal_routing_scheme; pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val); - switch(hdw->input_val) { - case PVR2_CVAL_INPUT_TV: - route.input = SAA7115_COMPOSITE4; - break; - case PVR2_CVAL_INPUT_COMPOSITE: - route.input = SAA7115_COMPOSITE5; - break; - case PVR2_CVAL_INPUT_SVIDEO: - route.input = SAA7115_SVIDEO2; - break; - case PVR2_CVAL_INPUT_RADIO: - // In radio mode, we mute the video, but point at one - // spot just to stay consistent - route.input = SAA7115_COMPOSITE5; - default: + + if ((sid < ARRAY_SIZE(routing_schemes)) && + ((sp = routing_schemes + sid) != 0) && + (hdw->input_val >= 0) && + (hdw->input_val < sp->cnt)) { + route.input = sp->def[hdw->input_val]; + } else { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "*** WARNING *** i2c v4l2 set_input:" + " Invalid routing scheme (%u) and/or input (%d)", + sid,hdw->input_val); return; } + route.output = 0; pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route); } @@ -129,7 +150,7 @@ static const struct pvr2_v4l_decoder_ops decoder_ops[] = { static void decoder_detach(struct pvr2_v4l_decoder *ctxt) { ctxt->client->handler = NULL; - ctxt->hdw->decoder_ctrl = NULL; + pvr2_hdw_set_decoder(ctxt->hdw,NULL); kfree(ctxt); } @@ -217,7 +238,7 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw, ctxt->client = cp; ctxt->hdw = hdw; ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1; - hdw->decoder_ctrl = &ctxt->ctrl; + pvr2_hdw_set_decoder(hdw,&ctxt->ctrl); cp->handler = &ctxt->handler; pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up", cp->client->addr); diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 2d18f0069821..41e5e518a47e 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -46,6 +46,7 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv-legacy.h> #include <media/saa7115.h> #include <asm/div64.h> @@ -1230,7 +1231,7 @@ static void saa711x_decode_vbi_line(struct i2c_client *client, /* ============ SAA7115 AUDIO settings (end) ============= */ -static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct saa711x_state *state = i2c_get_clientdata(client); @@ -1449,26 +1450,17 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa711x; - -static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) +static int saa7115_probe(struct i2c_client *client) { - struct i2c_client *client; struct saa711x_state *state; int i; char name[17]; u8 chip_id; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa711x; snprintf(client->name, sizeof(client->name) - 1, "saa7115"); for (i = 0; i < 0x0f; i++) { @@ -1485,18 +1477,16 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) /* Check whether this chip is part of the saa711x series */ if (memcmp(name, "1f711", 5)) { v4l_dbg(1, debug, client, "chip found @ 0x%x (ID %s) does not match a known saa711x chip.\n", - address << 1, name); - kfree(client); - return 0; + client->addr << 1, name); + return -ENODEV; } snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); - v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name); + v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); i2c_set_clientdata(client, state); if (state == NULL) { - kfree(client); return -ENOMEM; } state->input = -1; @@ -1549,59 +1539,25 @@ static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind) saa711x_writeregs(client, saa7115_init_misc); saa711x_set_v4lstd(client, V4L2_STD_NTSC); - i2c_attach_client(client); - v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n", saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC)); - return 0; } -static int saa711x_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG || adapter->class & I2C_CLASS_TV_DIGITAL) - return i2c_probe(adapter, &addr_data, &saa711x_attach); - return 0; -} +/* ----------------------------------------------------------------------- */ -static int saa711x_detach(struct i2c_client *client) +static int saa7115_remove(struct i2c_client *client) { - struct saa711x_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver_saa711x = { - .driver = { - .name = "saa7115", - }, - .id = I2C_DRIVERID_SAA711X, - .attach_adapter = saa711x_probe, - .detach_client = saa711x_detach, - .command = saa711x_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa7115", + .driverid = I2C_DRIVERID_SAA711X, + .command = saa7115_command, + .probe = saa7115_probe, + .remove = saa7115_remove, + .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL, }; - -static int __init saa711x_init_module(void) -{ - return i2c_add_driver(&i2c_driver_saa711x); -} - -static void __exit saa711x_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver_saa711x); -} - -module_init(saa711x_init_module); -module_exit(saa711x_cleanup_module); diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index e35ef321ec71..06c88db656b4 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -55,10 +55,11 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> #include <media/saa7127.h> -static int debug = 0; -static int test_image = 0; +static int debug; +static int test_image; MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver"); MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); @@ -68,10 +69,6 @@ module_param(test_image, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_PARM_DESC(test_image, "test_image (0-1)"); -static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; /* * SAA7127 registers @@ -360,9 +357,10 @@ static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data if (enable && (data->field != 0 || data->line != 21)) return -EINVAL; if (state->cc_enable != enable) { - v4l_dbg(1, debug, client, "Turn CC %s\n", enable ? "on" : "off"); + v4l_dbg(1, debug, client, + "Turn CC %s\n", enable ? "on" : "off"); saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, - (state->xds_enable << 7) | (enable << 6) | 0x11); + (state->xds_enable << 7) | (enable << 6) | 0x11); state->cc_enable = enable; } if (!enable) @@ -420,7 +418,8 @@ static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_dat saa7127_write(client, 0x26, data->data[0]); saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f)); - v4l_dbg(1, debug, client, "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); + v4l_dbg(1, debug, client, + "WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; return 0; } @@ -507,7 +506,8 @@ static int saa7127_set_output_type(struct i2c_client *client, int output) default: return -EINVAL; } - v4l_dbg(1, debug, client, "Selecting %s output type\n", output_strs[output]); + v4l_dbg(1, debug, client, + "Selecting %s output type\n", output_strs[output]); /* Configure Encoder */ saa7127_write(client, 0x2d, state->reg_2d); @@ -569,12 +569,10 @@ static int saa7127_command(struct i2c_client *client, { int rc = 0; - if (state->input_type != route->input) { + if (state->input_type != route->input) rc = saa7127_set_input_type(client, route->input); - } - if (rc == 0 && state->output_type != route->output) { + if (rc == 0 && state->output_type != route->output) rc = saa7127_set_output_type(client, route->output); - } return rc; } @@ -620,7 +618,8 @@ static int saa7127_command(struct i2c_client *client, { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -637,16 +636,16 @@ static int saa7127_command(struct i2c_client *client, struct v4l2_sliced_vbi_data *data = arg; switch (data->id) { - case V4L2_SLICED_WSS_625: - return saa7127_set_wss(client, data); - case V4L2_SLICED_VPS: - return saa7127_set_vps(client, data); - case V4L2_SLICED_CAPTION_525: - if (data->field == 0) - return saa7127_set_cc(client, data); - return saa7127_set_xds(client, data); - default: - return -EINVAL; + case V4L2_SLICED_WSS_625: + return saa7127_set_wss(client, data); + case V4L2_SLICED_VPS: + return saa7127_set_vps(client, data); + case V4L2_SLICED_CAPTION_525: + if (data->field == 0) + return saa7127_set_cc(client, data); + return saa7127_set_xds(client, data); + default: + return -EINVAL; } break; } @@ -662,31 +661,20 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa7127; - -/* ----------------------------------------------------------------------- */ - -static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) +static int saa7127_probe(struct i2c_client *client) { - struct i2c_client *client; struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ int read_result = 0; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver_saa7127; snprintf(client->name, sizeof(client->name) - 1, "saa7127"); - v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", address << 1); + v4l_dbg(1, debug, client, "detecting saa7127 client on address 0x%x\n", + client->addr << 1); /* First test register 0: Bits 5-7 are a version ID (should be 0), and bit 2 should also be 0. @@ -696,15 +684,12 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) if ((saa7127_read(client, 0) & 0xe4) != 0 || (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { v4l_dbg(1, debug, client, "saa7127 not found\n"); - kfree(client); - return 0; + return -ENODEV; } state = kzalloc(sizeof(struct saa7127_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); - return (-ENOMEM); - } + if (state == NULL) + return -ENOMEM; i2c_set_clientdata(client, state); @@ -718,91 +703,48 @@ static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) saa7127_set_wss(client, &vbi); saa7127_set_cc(client, &vbi); saa7127_set_xds(client, &vbi); - if (test_image == 1) { + if (test_image == 1) /* The Encoder has an internal Colorbar generator */ /* This can be used for debugging */ saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE); - } else { + else saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL); - } saa7127_set_video_enable(client, 1); /* Detect if it's an saa7129 */ read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { - v4l_info(client, "saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7129 found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); saa7127_write_inittab(client, saa7129_init_config_extra); state->ident = V4L2_IDENT_SAA7129; } else { - v4l_info(client, "saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "saa7127 found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state->ident = V4L2_IDENT_SAA7127; } - - i2c_attach_client(client); - return 0; } /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_adapter *adapter) +static int saa7127_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, saa7127_attach); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int saa7127_detach(struct i2c_client *client) -{ - struct saa7127_state *state = i2c_get_clientdata(client); - int err; - /* Turn off TV output */ saa7127_set_video_enable(client, 0); - - err = i2c_detach_client(client); - - if (err) { - return err; - } - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -static struct i2c_driver i2c_driver_saa7127 = { - .driver = { - .name = "saa7127", - }, - .id = I2C_DRIVERID_SAA7127, - .attach_adapter = saa7127_probe, - .detach_client = saa7127_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa7127", + .driverid = I2C_DRIVERID_SAA7127, .command = saa7127_command, + .probe = saa7127_probe, + .remove = saa7127_remove, }; - -/* ----------------------------------------------------------------------- */ - -static int __init saa7127_init_module(void) -{ - return i2c_add_driver(&i2c_driver_saa7127); -} - -/* ----------------------------------------------------------------------- */ - -static void __exit saa7127_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver_saa7127); -} - -/* ----------------------------------------------------------------------- */ - -module_init(saa7127_init_module); -module_exit(saa7127_cleanup_module); diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 3aa8cb2b860a..96bc3b1298a2 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -4,6 +4,7 @@ config VIDEO_SAA7134 select VIDEOBUF_DMA_SG select VIDEO_IR select VIDEO_TUNER + select VIDEO_TVEEPROM select CRC32 ---help--- This is a video4linux driver for Philips SAA713x based @@ -23,18 +24,6 @@ config VIDEO_SAA7134_ALSA To compile this driver as a module, choose M here: the module will be called saa7134-alsa. -config VIDEO_SAA7134_OSS - tristate "Philips SAA7134 DMA audio support (OSS, DEPRECATED)" - depends on VIDEO_SAA7134 && SOUND_PRIME && !VIDEO_SAA7134_ALSA - ---help--- - This is a video4linux driver for direct (DMA) audio in - Philips SAA713x based TV cards using OSS - - This is deprecated in favor of the ALSA module - - To compile this driver as a module, choose M here: the - module will be called saa7134-oss. - config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index c85c8a8ec361..9aff937ba7a5 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ saa6752hs.o obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o -obj-$(CONFIG_VIDEO_SAA7134_OSS) += saa7134-oss.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 4878f3067787..ba2531034a91 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -1077,24 +1077,14 @@ static int saa7134_alsa_init(void) struct saa7134_dev *dev = NULL; struct list_head *list; - if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { - saa7134_dmasound_init = alsa_device_init; - saa7134_dmasound_exit = alsa_device_exit; - } else { - printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n"); - return -EBUSY; - } + saa7134_dmasound_init = alsa_device_init; + saa7134_dmasound_exit = alsa_device_exit; printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); - if (dev->dmasound.priv_data == NULL) { - alsa_device_init(dev); - } else { - printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name); - return -EBUSY; - } + alsa_device_init(dev); } if (dev == NULL) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 98c1b084a716..7d7f383b404f 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -26,6 +26,7 @@ #include "saa7134-reg.h" #include "saa7134.h" #include <media/v4l2-common.h> +#include <media/tveeprom.h> /* commly used strings */ static char name_mute[] = "mute"; @@ -349,6 +350,10 @@ struct saa7134_board saa7134_boards[] = { .name = name_radio, .amux = LINE2, }, + .mute = { + .name = name_mute, + .amux = TV, + }, }, [SAA7134_BOARD_TVSTATION_RDS] = { /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ @@ -565,6 +570,10 @@ struct saa7134_board saa7134_boards[] = { .radio = { .name = name_radio, .amux = LINE2, + }, + .mute = { + .name = name_mute, + .amux = TV, }, }, [SAA7134_BOARD_TYPHOON_90031] = { @@ -3553,6 +3562,356 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, }}, }, + [SAA7134_BOARD_BEHOLD_401] = { + .name = "Beholder BeholdTV 401", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_BEHOLD_403] = { + .name = "Beholder BeholdTV 403", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + }, + [SAA7134_BOARD_BEHOLD_403FM] = { + .name = "Beholder BeholdTV 403 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_405] = { + .name = "Beholder BeholdTV 405", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + }, + [SAA7134_BOARD_BEHOLD_405FM] = { + /* Sergey <skiv@orel.ru> */ + .name = "Beholder BeholdTV 405 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_407] = { + .name = "Beholder BeholdTV 407", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xc0c000, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + .gpio = 0xc0c000, + }}, + }, + [SAA7134_BOARD_BEHOLD_407FM] = { + .name = "Beholder BeholdTV 407 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xc0c000, + .inputs = {{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + .gpio = 0xc0c000, + },{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + .gpio = 0xc0c000, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0xc0c000, + }, + }, + [SAA7134_BOARD_BEHOLD_409] = { + .name = "Beholder BeholdTV 409", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_BEHOLD_505FM] = { + .name = "Beholder BeholdTV 505 FM/RDS", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_507_9FM] = { + .name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = { + .name = "Beholder BeholdTV Columbus TVFM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_ALPS_TSBE5_PAL, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_607_9FM] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 607 / BeholdTV 609", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_M6] = { + /* Igor Kuznetsov <igk@igk.ru> */ + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV M6 / BeholdTV M6 Extra", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mpeg = SAA7134_MPEG_EMPRESS, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4033,7 +4392,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1462, - .subdevice = 0x6231, + .subdevice = 0x6231, /* tda8275a, ks003 IR */ + .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1462, + .subdevice = 0x8624, /* tda8275, ks003 IR */ .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4207,11 +4572,41 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0070, + .subdevice = 0x6700, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, .subdevice = 0x6701, .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6702, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6703, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6704, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0070, + .subdevice = 0x6705, + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x153b, .subdevice = 0x1172, .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, @@ -4289,6 +4684,162 @@ struct pci_device_id saa7134_pci_tbl[] = { .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x4016, + .driver_data = SAA7134_BOARD_BEHOLD_401, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4036, + .driver_data = SAA7134_BOARD_BEHOLD_403, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4037, + .driver_data = SAA7134_BOARD_BEHOLD_403FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x4050, + .driver_data = SAA7134_BOARD_BEHOLD_405, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x4051, + .driver_data = SAA7134_BOARD_BEHOLD_405FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4070, + .driver_data = SAA7134_BOARD_BEHOLD_407, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x0000, + .subdevice = 0x4071, + .driver_data = SAA7134_BOARD_BEHOLD_407FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x4090, + .driver_data = SAA7134_BOARD_BEHOLD_409, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x5051, + .driver_data = SAA7134_BOARD_BEHOLD_505FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x0000, + .subdevice = 0x505B, + .driver_data = SAA7134_BOARD_BEHOLD_505FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x5ace, + .subdevice = 0x5050, + .driver_data = SAA7134_BOARD_BEHOLD_505FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x5071, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x507B, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x5070, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x5090, + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0000, + .subdevice = 0x5201, + .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6070, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6071, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6072, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5ace, + .subdevice = 0x6073, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6090, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6091, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6092, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6093, + .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6190, + .driver_data = SAA7134_BOARD_BEHOLD_M6, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6193, + .driver_data = SAA7134_BOARD_BEHOLD_M6, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x4e42, .subdevice = 0x3502, @@ -4351,6 +4902,34 @@ static void board_flyvideo(struct saa7134_dev *dev) /* ----------------------------------------------------------- */ +static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) +{ + struct tveeprom tv; + + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data); + + /* Make sure we support the board model */ + switch (tv.model) { + case 67019: /* WinTV-HVR1110 (Retail, IR Blaster, hybrid, FM, SVid/Comp, 3.5mm audio in) */ + case 67109: /* WinTV-HVR1000 (Retail, IR Receive, analog, no FM, SVid/Comp, 3.5mm audio in) */ + case 67559: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ + case 67569: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM) */ + case 67579: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM) */ + case 67589: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + case 67599: /* WinTV-HVR1110 (OEM, no IR, hybrid, no FM, SVid/Comp, RCA aud) */ + break; + default: + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", dev->name, tv.model); + break; + } + + printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); +} + +/* ----------------------------------------------------------- */ + int saa7134_board_init1(struct saa7134_dev *dev) { /* Always print gpio, often manufacturers encode tuner type and other info. */ @@ -4406,6 +4985,16 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_ENCORE_ENLTV: case SAA7134_BOARD_ENCORE_ENLTV_FM: case SAA7134_BOARD_10MOONSTVMASTER3: + case SAA7134_BOARD_BEHOLD_401: + case SAA7134_BOARD_BEHOLD_403: + case SAA7134_BOARD_BEHOLD_403FM: + case SAA7134_BOARD_BEHOLD_405: + case SAA7134_BOARD_BEHOLD_405FM: + case SAA7134_BOARD_BEHOLD_407: + case SAA7134_BOARD_BEHOLD_407FM: + case SAA7134_BOARD_BEHOLD_409: + case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_507_9FM: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -4445,6 +5034,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000); break; case SAA7134_BOARD_AVERMEDIA_CARDBUS: + case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff); @@ -4466,6 +5056,8 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_UPMOST_PURPLE_TV: case SAA7134_BOARD_HAUPPAUGE_HVR1110: + case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_M6: dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: @@ -4477,6 +5069,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) break; case SAA7134_BOARD_AVERMEDIA_M102: /* enable tuner */ + dev->has_remote = SAA7134_REMOTE_GPIO; saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd); break; @@ -4570,8 +5163,17 @@ int saa7134_board_init2(struct saa7134_dev *dev) printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE; - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf); + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + dev->tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); } tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; @@ -4601,7 +5203,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: - case SAA7134_BOARD_AVERMEDIA_SUPER_007: { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; @@ -4622,13 +5223,16 @@ int saa7134_board_init2(struct saa7134_dev *dev) i2c_transfer(&dev->i2c_adap, &msg, 1); } break; + case SAA7134_BOARD_HAUPPAUGE_HVR1110: + hauppauge_eeprom(dev, dev->eedata+0x80); + /* break intentionally omitted */ case SAA7134_BOARD_PINNACLE_PCTV_310i: case SAA7134_BOARD_KWORLD_DVBT_210: case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: - case SAA7134_BOARD_HAUPPAUGE_HVR1110: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 4f0a9157ecb1..52baa4f7f7dd 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -294,7 +294,7 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) videobuf_waiton(&buf->vb,0,0); videobuf_dma_unmap(q, dma); videobuf_dma_free(dma); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } /* ------------------------------------------------------------------ */ @@ -313,7 +313,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, buf->activate(dev,buf,NULL); } else if (list_empty(&q->queue)) { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; } else { next = list_entry(q->queue.next,struct saa7134_buf, vb.queue); @@ -322,7 +322,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, } } else { list_add_tail(&buf->vb.queue,&q->queue); - buf->vb.state = STATE_QUEUED; + buf->vb.state = VIDEOBUF_QUEUED; } return 0; } @@ -387,7 +387,7 @@ void saa7134_buffer_timeout(unsigned long data) try to start over with the next one. */ if (q->curr) { dprintk("timeout on %p\n",q->curr); - saa7134_buffer_finish(dev,q,STATE_ERROR); + saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR); } saa7134_buffer_next(dev,q); spin_unlock_irqrestore(&dev->slock,flags); @@ -395,8 +395,8 @@ void saa7134_buffer_timeout(unsigned long data) /* resends a current buffer in queue after resume */ -int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) +static int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) { struct saa7134_buf *buf, *next; @@ -834,6 +834,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, vfd->minor = -1; vfd->dev = &dev->pci->dev; vfd->release = video_device_release; + vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, saa7134_boards[dev->board].name); return vfd; @@ -1052,7 +1053,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s: registered device video%d [v4l2]\n", dev->name,dev->video_dev->minor & 0x1f); - dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi"); + 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]); if (err < 0) @@ -1181,8 +1184,13 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) saa_writel(SAA7134_IRQ2, 0); saa_writel(SAA7134_MAIN_CTRL, 0); - synchronize_irq(pci_dev->irq); dev->insuspend = 1; + synchronize_irq(pci_dev->irq); + + /* ACK interrupts once more, just in case, + since the IRQ handler won't ack them anymore*/ + + saa_writel(SAA7134_IRQ_REPORT, saa_readl(SAA7134_IRQ_REPORT)); /* Disable timeout timers - if we have active buffers, we will fill them on resume*/ @@ -1194,10 +1202,10 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) if (dev->remote) saa7134_ir_stop(dev); - pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); pci_save_state(pci_dev); + pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); - return 0; + return 0; } static int saa7134_resume(struct pci_dev *pci_dev) @@ -1205,8 +1213,8 @@ static int saa7134_resume(struct pci_dev *pci_dev) struct saa7134_dev *dev = pci_get_drvdata(pci_dev); unsigned long flags; - pci_restore_state(pci_dev); pci_set_power_state(pci_dev, PCI_D0); + pci_restore_state(pci_dev); /* Do things that are done in saa7134_initdev , except of initializing memory structures.*/ @@ -1222,6 +1230,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_ir_start(dev, dev->remote); saa7134_hw_enable1(dev); + msleep(100); saa7134_board_init2(dev); @@ -1229,10 +1238,13 @@ static int saa7134_resume(struct pci_dev *pci_dev) saa7134_set_tvnorm_hw(dev); saa7134_tvaudio_setmute(dev); saa7134_tvaudio_setvolume(dev, dev->ctl_volume); + saa7134_tvaudio_init(dev); saa7134_tvaudio_do_scan(dev); saa7134_enable_i2s(dev); saa7134_hw_enable2(dev); + saa7134_irq_video_signalchange(dev); + /*resume unfinished buffer(s)*/ spin_lock_irqsave(&dev->slock, flags); saa7134_buffer_requeue(dev, &dev->video_q); @@ -1246,6 +1258,7 @@ static int saa7134_resume(struct pci_dev *pci_dev) /* start DMA now*/ dev->insuspend = 0; + smp_wmb(); saa7134_set_dmabits(dev); spin_unlock_irqrestore(&dev->slock, flags); diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index e1ab099ec4c6..a9ca5730826f 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -1073,14 +1073,21 @@ static int dvb_init(struct saa7134_dev *dev) static int dvb_fini(struct saa7134_dev *dev) { - static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + /* FIXME: I suspect that this code is bogus, since the entry for + Pinnacle 300I DVB-T PAL already defines the proper init to allow + the detection of mt2032 (TDA9887_PORT2_INACTIVE) + */ + if (dev->board == SAA7134_BOARD_PINNACLE_300I_DVBT_PAL) { + struct v4l2_priv_tun_config tda9887_cfg; + static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &on; - switch (dev->board) { - case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: /* otherwise we don't detect the tuner on next insmod */ - saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); - break; - }; + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg); + } + videobuf_dvb_unregister(&dev->dvb); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 9322f44865b8..b1b01fa86720 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -161,152 +161,176 @@ ts_mmap(struct file *file, struct vm_area_struct * vma) * video_generic_ioctl (and maybe others). userspace * copying is done already, arg is a kernel pointer. */ -static int ts_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) + +static int empress_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { - struct saa7134_dev *dev = file->private_data; - struct v4l2_ext_controls *ctrls = arg; - - if (debug > 1) - v4l_print_ioctl(dev->name,cmd); - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - return 0; - } + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + return 0; +} - /* --- input switching --------------------------------------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; +static int empress_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; - if (i->index != 0) - return -EINVAL; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,"CCIR656"); - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = 0; - return 0; - } - case VIDIOC_S_INPUT: - { - int *i = arg; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, "CCIR656"); - if (*i != 0) - return -EINVAL; - return 0; - } - /* --- capture ioctls ---------------------------------------- */ - - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - int index; - - index = f->index; - if (index != 0) - return -EINVAL; - - memset(f,0,sizeof(*f)); - f->index = index; - strlcpy(f->description, "MPEG TS", sizeof(f->description)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - f->pixelformat = V4L2_PIX_FMT_MPEG; - return 0; - } + return 0; +} - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; +static int empress_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} - memset(f,0,sizeof(*f)); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +static int empress_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; - saa7134_i2c_call_clients(dev, cmd, arg); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - return 0; - } + return 0; +} - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; +static int empress_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + strlcpy(f->description, "MPEG TS", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_MPEG; - saa7134_i2c_call_clients(dev, cmd, arg); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.sizeimage = TS_PACKET_SIZE* dev->ts.nr_packets; - return 0; - } + return 0; +} - case VIDIOC_REQBUFS: - return videobuf_reqbufs(&dev->empress_tsq,arg); +static int empress_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - case VIDIOC_QUERYBUF: - return videobuf_querybuf(&dev->empress_tsq,arg); + saa7134_i2c_call_clients(dev, VIDIOC_G_FMT, f); - case VIDIOC_QBUF: - return videobuf_qbuf(&dev->empress_tsq,arg); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - case VIDIOC_DQBUF: - return videobuf_dqbuf(&dev->empress_tsq,arg, - file->f_flags & O_NONBLOCK); + return 0; +} - case VIDIOC_STREAMON: - return videobuf_streamon(&dev->empress_tsq); +static int empress_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - case VIDIOC_STREAMOFF: - return videobuf_streamoff(&dev->empress_tsq); + saa7134_i2c_call_clients(dev, VIDIOC_S_FMT, f); - case VIDIOC_QUERYCTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - return saa7134_common_ioctl(dev, cmd, arg); + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; - case VIDIOC_S_EXT_CTRLS: - /* count == 0 is abused in saa6752hs.c, so that special - case is handled here explicitly. */ - if (ctrls->count == 0) - return 0; - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg); - ts_init_encoder(dev); - return 0; - case VIDIOC_G_EXT_CTRLS: - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg); + return 0; +} + + +static int empress_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_reqbufs(&dev->empress_tsq, p); +} + +static int empress_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_querybuf(&dev->empress_tsq, b); +} + +static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_qbuf(&dev->empress_tsq, b); +} + +static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_dqbuf(&dev->empress_tsq, b, + file->f_flags & O_NONBLOCK); +} + +static int empress_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_streamon(&dev->empress_tsq); +} + +static int empress_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + return videobuf_streamoff(&dev->empress_tsq); +} + +static int empress_s_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + /* count == 0 is abused in saa6752hs.c, so that special + case is handled here explicitly. */ + if (ctrls->count == 0) return 0; - default: - return -ENOIOCTLCMD; - } + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + + saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls); + ts_init_encoder(dev); + return 0; } -static int ts_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int empress_g_ext_ctrls(struct file *file, void *priv, + struct v4l2_ext_controls *ctrls) { - return video_usercopy(inode, file, cmd, arg, ts_do_ioctl); + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) + return -EINVAL; + saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls); + + return 0; } static const struct file_operations ts_fops = @@ -317,7 +341,7 @@ static const struct file_operations ts_fops = .read = ts_read, .poll = ts_poll, .mmap = ts_mmap, - .ioctl = ts_ioctl, + .ioctl = video_ioctl2, .llseek = no_llseek, }; @@ -330,6 +354,29 @@ static struct video_device saa7134_empress_template = .type2 = 0 /* FIXME */, .fops = &ts_fops, .minor = -1, + + .vidioc_querycap = empress_querycap, + .vidioc_enum_fmt_cap = empress_enum_fmt_cap, + .vidioc_s_fmt_cap = empress_s_fmt_cap, + .vidioc_g_fmt_cap = empress_g_fmt_cap, + .vidioc_reqbufs = empress_reqbufs, + .vidioc_querybuf = empress_querybuf, + .vidioc_qbuf = empress_qbuf, + .vidioc_dqbuf = empress_dqbuf, + .vidioc_streamon = empress_streamon, + .vidioc_streamoff = empress_streamoff, + .vidioc_s_ext_ctrls = empress_s_ext_ctrls, + .vidioc_g_ext_ctrls = empress_g_ext_ctrls, + .vidioc_enum_input = empress_enum_input, + .vidioc_g_input = empress_g_input, + .vidioc_s_input = empress_s_input, + + .vidioc_queryctrl = saa7134_queryctrl, + .vidioc_g_ctrl = saa7134_g_ctrl, + .vidioc_s_ctrl = saa7134_s_ctrl, + + .tvnorms = SAA7134_NORMS, + .current_norm = V4L2_STD_PAL, }; static void empress_signal_update(struct work_struct *work) diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 6deaad1a5480..d3322c3018f2 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -323,7 +323,6 @@ static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; int tuner = dev->tuner_type; - int conf = dev->tda9887_conf; struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", @@ -335,6 +334,7 @@ static int attach_inform(struct i2c_client *client) case 0x7a: case 0x47: case 0x71: + case 0x2d: { struct IR_i2c *ir = i2c_get_clientdata(client); d1printk("%s i2c IR detected (%s).\n", @@ -360,7 +360,6 @@ static int attach_inform(struct i2c_client *client) } if (tuner != UNSET) { - tun_setup.type = tuner; tun_setup.addr = saa7134_boards[dev->board].tuner_addr; tun_setup.config = saa7134_boards[dev->board].tuner_config; @@ -372,9 +371,18 @@ static int attach_inform(struct i2c_client *client) client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); } + + if (tuner == TUNER_TDA9887) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + client->driver->command(client, TUNER_SET_CONFIG, + &tda9887_cfg); + } } - client->driver->command(client, TDA9887_SET_CONFIG, &conf); return 0; } @@ -432,6 +440,7 @@ static char *i2c_devs[128] = { [ 0xa0 >> 1 ] = "eeprom", [ 0xc0 >> 1 ] = "tuner (analog)", [ 0x86 >> 1 ] = "tda9887", + [ 0x5a >> 1 ] = "remote control", }; static void do_i2c_scan(char *name, struct i2c_client *c) diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 3abaa1b8ac9d..0db955c2d9b9 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -49,9 +49,14 @@ module_param(repeat_delay, int, 0644); MODULE_PARM_DESC(repeat_delay, "delay before key repeat started"); static int repeat_period = 33; module_param(repeat_period, int, 0644); -MODULE_PARM_DESC(repeat_period, "repeat period between" +MODULE_PARM_DESC(repeat_period, "repeat period between " "keypresses when key is down"); +static unsigned int disable_other_ir; +module_param(disable_other_ir, int, 0644); +MODULE_PARM_DESC(disable_other_ir, "disable full codes of " + "alternative remotes from other manufacturers"); + #define dprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) #define i2cdprintk(fmt, arg...) if (ir_debug) \ @@ -154,6 +159,45 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) return 1; } + +static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + unsigned char data[12]; + u32 gpio; + + struct saa7134_dev *dev = ir->c.adapter->algo_data; + + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); + + if (0x400000 & ~gpio) + return 0; /* No button press */ + + ir->c.addr = 0x5a >> 1; + + if (12 != i2c_master_recv(&ir->c, data, 12)) { + i2cdprintk("read error\n"); + return -EIO; + } + /* IR of this card normally decode signals NEC-standard from + * - Sven IHOO MT 5.1R remote. xxyye718 + * - Sven DVD HD-10xx remote. xxyyf708 + * - BBK ... + * - mayby others + * So, skip not our, if disable full codes mode. + */ + if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir) + return 0; + + *ir_key = data[9]; + *ir_raw = data[9]; + + return 1; +} + void saa7134_input_irq(struct saa7134_dev *dev) { struct card_ir *ir = dev->remote; @@ -260,6 +304,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: + case SAA7134_BOARD_AVERMEDIA_M102: ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; mask_keydown = 0x000010; @@ -287,6 +332,16 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: + case SAA7134_BOARD_BEHOLD_401: + case SAA7134_BOARD_BEHOLD_403: + case SAA7134_BOARD_BEHOLD_403FM: + case SAA7134_BOARD_BEHOLD_405: + case SAA7134_BOARD_BEHOLD_405FM: + case SAA7134_BOARD_BEHOLD_407: + case SAA7134_BOARD_BEHOLD_407FM: + case SAA7134_BOARD_BEHOLD_409: + case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_507_9FM: ir_codes = ir_codes_manli; mask_keycode = 0x001f00; mask_keyup = 0x004000; @@ -457,6 +512,12 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) ir->get_key = get_key_hvr1110; ir->ir_codes = ir_codes_hauppauge_new; break; + case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_M6: + snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); + ir->get_key = get_key_beholdm6xx; + ir->ir_codes = ir_codes_behold; + break; default: dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board); break; diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c deleted file mode 100644 index aedf04653e0e..000000000000 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ /dev/null @@ -1,1046 +0,0 @@ -/* - * - * device driver for philips saa7134 based TV cards - * oss dsp interface - * - * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] - * 2005 conversion to standalone module: - * Ricardo Cerqueira <v4l@cerqueira.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/init.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/sound.h> -#include <linux/soundcard.h> - -#include "saa7134-reg.h" -#include "saa7134.h" - -/* ------------------------------------------------------------------ */ - -static unsigned int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [oss]"); - -static unsigned int rate = 0; -module_param(rate, int, 0444); -MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)"); - -static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s)."); -module_param_array(dsp_nr, int, NULL, 0444); - -static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s)."); -module_param_array(mixer_nr, int, NULL, 0444); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) - - -/* ------------------------------------------------------------------ */ - -static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) -{ - if (blksize < 0x100) - blksize = 0x100; - if (blksize > 0x10000) - blksize = 0x10000; - - if (blocks < 2) - blocks = 2; - if ((blksize * blocks) > 1024*1024) - blocks = 1024*1024 / blksize; - - dev->dmasound.blocks = blocks; - dev->dmasound.blksize = blksize; - dev->dmasound.bufsize = blksize * blocks; - - dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", - blocks,blksize,blksize * blocks / 1024); - return 0; -} - -static int dsp_buffer_init(struct saa7134_dev *dev) -{ - int err; - - BUG_ON(!dev->dmasound.bufsize); - videobuf_dma_init(&dev->dmasound.dma); - err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, - (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); - if (0 != err) - return err; - return 0; -} - -static int dsp_buffer_free(struct saa7134_dev *dev) -{ - BUG_ON(!dev->dmasound.blksize); - videobuf_dma_free(&dev->dmasound.dma); - dev->dmasound.blocks = 0; - dev->dmasound.blksize = 0; - dev->dmasound.bufsize = 0; - return 0; -} - -static void dsp_dma_start(struct saa7134_dev *dev) -{ - dev->dmasound.dma_blk = 0; - dev->dmasound.dma_running = 1; - saa7134_set_dmabits(dev); -} - -static void dsp_dma_stop(struct saa7134_dev *dev) -{ - dev->dmasound.dma_blk = -1; - dev->dmasound.dma_running = 0; - saa7134_set_dmabits(dev); -} - -static int dsp_rec_start(struct saa7134_dev *dev) -{ - int err, bswap, sign; - u32 fmt, control; - unsigned long flags; - - /* prepare buffer */ - if (0 != (err = videobuf_pci_dma_map(dev->pci,&dev->dmasound.dma))) - return err; - if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) - goto fail1; - if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, - dev->dmasound.dma.sglist, - dev->dmasound.dma.sglen, - 0))) - goto fail2; - - /* sample format */ - switch (dev->dmasound.afmt) { - case AFMT_U8: - case AFMT_S8: fmt = 0x00; break; - case AFMT_U16_LE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_S16_BE: fmt = 0x01; break; - default: - err = -EINVAL; - goto fail2; - } - - switch (dev->dmasound.afmt) { - case AFMT_S8: - case AFMT_S16_LE: - case AFMT_S16_BE: sign = 1; break; - default: sign = 0; break; - } - - switch (dev->dmasound.afmt) { - case AFMT_U16_BE: - case AFMT_S16_BE: bswap = 1; break; - default: bswap = 0; break; - } - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - if (1 == dev->dmasound.channels) - fmt |= (1 << 3); - if (2 == dev->dmasound.channels) - fmt |= (3 << 3); - if (sign) - fmt |= 0x04; - fmt |= (TV == dev->dmasound.input) ? 0xc0 : 0x80; - - saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); - saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); - saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); - saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); - - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (1 == dev->dmasound.channels) - fmt |= (1 << 4); - if (2 == dev->dmasound.channels) - fmt |= (2 << 4); - if (!sign) - fmt |= 0x04; - saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -4); - saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); - break; - } - dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", - dev->dmasound.afmt, dev->dmasound.channels, fmt, - bswap ? 'b' : '-'); - - /* dma: setup channel 6 (= AUDIO) */ - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (dev->dmasound.pt.dma >> 12); - if (bswap) - control |= SAA7134_RS_CONTROL_BSWAP; - saa_writel(SAA7134_RS_BA1(6),0); - saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); - saa_writel(SAA7134_RS_PITCH(6),0); - saa_writel(SAA7134_RS_CONTROL(6),control); - - /* start dma */ - dev->dmasound.recording_on = 1; - spin_lock_irqsave(&dev->slock,flags); - dsp_dma_start(dev); - spin_unlock_irqrestore(&dev->slock,flags); - return 0; - - fail2: - saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); - fail1: - videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma); - return err; -} - -static int dsp_rec_stop(struct saa7134_dev *dev) -{ - unsigned long flags; - - dprintk("rec_stop dma_blk=%d\n",dev->dmasound.dma_blk); - - /* stop dma */ - dev->dmasound.recording_on = 0; - spin_lock_irqsave(&dev->slock,flags); - dsp_dma_stop(dev); - spin_unlock_irqrestore(&dev->slock,flags); - - /* unlock buffer */ - saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); - videobuf_pci_dma_unmap(dev->pci,&dev->dmasound.dma); - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int dsp_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct saa7134_dev *dev; - int err; - - list_for_each_entry(dev, &saa7134_devlist, devlist) - if (dev->dmasound.minor_dsp == minor) - goto found; - return -ENODEV; - found: - - mutex_lock(&dev->dmasound.lock); - err = -EBUSY; - if (dev->dmasound.users_dsp) - goto fail1; - dev->dmasound.users_dsp++; - file->private_data = dev; - - dev->dmasound.afmt = AFMT_U8; - dev->dmasound.channels = 1; - dev->dmasound.read_count = 0; - dev->dmasound.read_offset = 0; - dsp_buffer_conf(dev,PAGE_SIZE,64); - err = dsp_buffer_init(dev); - if (0 != err) - goto fail2; - - mutex_unlock(&dev->dmasound.lock); - return 0; - - fail2: - dev->dmasound.users_dsp--; - fail1: - mutex_unlock(&dev->dmasound.lock); - return err; -} - -static int dsp_release(struct inode *inode, struct file *file) -{ - struct saa7134_dev *dev = file->private_data; - - mutex_lock(&dev->dmasound.lock); - if (dev->dmasound.recording_on) - dsp_rec_stop(dev); - dsp_buffer_free(dev); - dev->dmasound.users_dsp--; - file->private_data = NULL; - mutex_unlock(&dev->dmasound.lock); - return 0; -} - -static ssize_t dsp_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct saa7134_dev *dev = file->private_data; - DECLARE_WAITQUEUE(wait, current); - unsigned int bytes; - unsigned long flags; - int err,ret = 0; - - add_wait_queue(&dev->dmasound.wq, &wait); - mutex_lock(&dev->dmasound.lock); - while (count > 0) { - /* wait for data if needed */ - if (0 == dev->dmasound.read_count) { - if (!dev->dmasound.recording_on) { - err = dsp_rec_start(dev); - if (err < 0) { - if (0 == ret) - ret = err; - break; - } - } - if (dev->dmasound.recording_on && - !dev->dmasound.dma_running) { - /* recover from overruns */ - spin_lock_irqsave(&dev->slock,flags); - dsp_dma_start(dev); - spin_unlock_irqrestore(&dev->slock,flags); - } - if (file->f_flags & O_NONBLOCK) { - if (0 == ret) - ret = -EAGAIN; - break; - } - mutex_unlock(&dev->dmasound.lock); - set_current_state(TASK_INTERRUPTIBLE); - if (0 == dev->dmasound.read_count) - schedule(); - set_current_state(TASK_RUNNING); - mutex_lock(&dev->dmasound.lock); - if (signal_pending(current)) { - if (0 == ret) - ret = -EINTR; - break; - } - } - - /* copy data to userspace */ - bytes = count; - if (bytes > dev->dmasound.read_count) - bytes = dev->dmasound.read_count; - if (bytes > dev->dmasound.bufsize - dev->dmasound.read_offset) - bytes = dev->dmasound.bufsize - dev->dmasound.read_offset; - if (copy_to_user(buffer + ret, - dev->dmasound.dma.vmalloc + dev->dmasound.read_offset, - bytes)) { - if (0 == ret) - ret = -EFAULT; - break; - } - - ret += bytes; - count -= bytes; - dev->dmasound.read_count -= bytes; - dev->dmasound.read_offset += bytes; - if (dev->dmasound.read_offset == dev->dmasound.bufsize) - dev->dmasound.read_offset = 0; - } - mutex_unlock(&dev->dmasound.lock); - remove_wait_queue(&dev->dmasound.wq, &wait); - return ret; -} - -static ssize_t dsp_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static const char *osspcm_ioctls[] = { - "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", - "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", - "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", - "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", - "SETDUPLEX", "GETODELAY" -}; -#define OSSPCM_IOCTLS ARRAY_SIZE(osspcm_ioctls) - -static void saa7134_oss_print_ioctl(char *name, unsigned int cmd) -{ - char *dir; - - 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 = "??"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'P': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? - osspcm_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'M': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - break; - default: - printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - } -} - -static int dsp_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct saa7134_dev *dev = file->private_data; - void __user *argp = (void __user *) arg; - int __user *p = argp; - int val = 0; - - if (debug > 1) - saa7134_oss_print_ioctl(dev->name,cmd); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - case SNDCTL_DSP_GETCAPS: - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - /* fall through */ - case SOUND_PCM_READ_RATE: - return put_user(dev->dmasound.rate, p); - - case SNDCTL_DSP_STEREO: - if (get_user(val, p)) - return -EFAULT; - mutex_lock(&dev->dmasound.lock); - dev->dmasound.channels = val ? 2 : 1; - if (dev->dmasound.recording_on) { - dsp_rec_stop(dev); - dsp_rec_start(dev); - } - mutex_unlock(&dev->dmasound.lock); - return put_user(dev->dmasound.channels-1, p); - - case SNDCTL_DSP_CHANNELS: - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2) - return -EINVAL; - mutex_lock(&dev->dmasound.lock); - dev->dmasound.channels = val; - if (dev->dmasound.recording_on) { - dsp_rec_stop(dev); - dsp_rec_start(dev); - } - mutex_unlock(&dev->dmasound.lock); - /* fall through */ - case SOUND_PCM_READ_CHANNELS: - return put_user(dev->dmasound.channels, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - return put_user(AFMT_U8 | AFMT_S8 | - AFMT_U16_LE | AFMT_U16_BE | - AFMT_S16_LE | AFMT_S16_BE, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ - if (get_user(val, p)) - return -EFAULT; - switch (val) { - case AFMT_QUERY: - /* nothing to do */ - break; - case AFMT_U8: - case AFMT_S8: - case AFMT_U16_LE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_S16_BE: - mutex_lock(&dev->dmasound.lock); - dev->dmasound.afmt = val; - if (dev->dmasound.recording_on) { - dsp_rec_stop(dev); - dsp_rec_start(dev); - } - mutex_unlock(&dev->dmasound.lock); - return put_user(dev->dmasound.afmt, p); - default: - return -EINVAL; - } - - case SOUND_PCM_READ_BITS: - switch (dev->dmasound.afmt) { - case AFMT_U8: - case AFMT_S8: - return put_user(8, p); - case AFMT_U16_LE: - case AFMT_U16_BE: - case AFMT_S16_LE: - case AFMT_S16_BE: - return put_user(16, p); - default: - return -EINVAL; - } - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_RESET: - mutex_lock(&dev->dmasound.lock); - if (dev->dmasound.recording_on) - dsp_rec_stop(dev); - mutex_unlock(&dev->dmasound.lock); - return 0; - case SNDCTL_DSP_GETBLKSIZE: - return put_user(dev->dmasound.blksize, p); - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - if (dev->dmasound.recording_on) - return -EBUSY; - dsp_buffer_free(dev); - /* used to be arg >> 16 instead of val >> 16; fixed */ - dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff); - dsp_buffer_init(dev); - return 0; - - case SNDCTL_DSP_SYNC: - /* NOP */ - return 0; - - case SNDCTL_DSP_GETISPACE: - { - audio_buf_info info; - info.fragsize = dev->dmasound.blksize; - info.fragstotal = dev->dmasound.blocks; - info.bytes = dev->dmasound.read_count; - info.fragments = info.bytes / info.fragsize; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - default: - return -EINVAL; - } -} - -static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) -{ - struct saa7134_dev *dev = file->private_data; - unsigned int mask = 0; - - poll_wait(file, &dev->dmasound.wq, wait); - - if (0 == dev->dmasound.read_count) { - mutex_lock(&dev->dmasound.lock); - if (!dev->dmasound.recording_on) - dsp_rec_start(dev); - mutex_unlock(&dev->dmasound.lock); - } else - mask |= (POLLIN | POLLRDNORM); - return mask; -} - -const struct file_operations saa7134_dsp_fops = { - .owner = THIS_MODULE, - .open = dsp_open, - .release = dsp_release, - .read = dsp_read, - .write = dsp_write, - .ioctl = dsp_ioctl, - .poll = dsp_poll, - .llseek = no_llseek, -}; - -/* ------------------------------------------------------------------ */ - -static int -mixer_recsrc_7134(struct saa7134_dev *dev) -{ - int analog_io,rate; - - switch (dev->dmasound.input) { - case TV: - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); - break; - case LINE1: - case LINE2: - case LINE2_LEFT: - analog_io = (LINE1 == dev->dmasound.input) ? 0x00 : 0x08; - rate = (32000 == dev->dmasound.rate) ? 0x01 : 0x03; - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); - saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); - saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); - break; - } - return 0; -} - -static int -mixer_recsrc_7133(struct saa7134_dev *dev) -{ - u32 anabar, xbarin; - - xbarin = 0x03; // adc - anabar = 0; - switch (dev->dmasound.input) { - case TV: - xbarin = 0; // Demodulator - anabar = 2; // DACs - break; - case LINE1: - anabar = 0; // aux1, aux1 - break; - case LINE2: - case LINE2_LEFT: - anabar = 9; // aux2, aux2 - break; - } - /* output xbar always main channel */ - saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10); - saa_dsp_writel(dev, 0x464 >> 2, xbarin); - saa_writel(0x594 >> 2, anabar); - - return 0; -} - -static int -mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src) -{ - static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" }; - - dev->dmasound.count++; - dev->dmasound.input = src; - dprintk("mixer input = %s\n",iname[dev->dmasound.input]); - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - mixer_recsrc_7134(dev); - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - mixer_recsrc_7133(dev); - break; - } - return 0; -} - -static int -mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) -{ - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - switch (src) { - case TV: - /* nothing */ - break; - case LINE1: - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, - (100 == level) ? 0x00 : 0x10); - break; - case LINE2: - case LINE2_LEFT: - saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, - (100 == level) ? 0x00 : 0x20); - break; - } - break; - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - /* nothing */ - break; - } - return 0; -} - -/* ------------------------------------------------------------------ */ - -static int mixer_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct saa7134_dev *dev; - - list_for_each_entry(dev, &saa7134_devlist, devlist) - if (dev->dmasound.minor_mixer == minor) { - file->private_data = dev; - return 0; - } - return -ENODEV; -} - -static int mixer_release(struct inode *inode, struct file *file) -{ - file->private_data = NULL; - return 0; -} - -static int mixer_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct saa7134_dev *dev = file->private_data; - enum saa7134_audio_in input; - int val,ret; - void __user *argp = (void __user *) arg; - int __user *p = argp; - - if (debug > 1) - saa7134_oss_print_ioctl(dev->name,cmd); - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - case SOUND_MIXER_INFO: - { - mixer_info info; - memset(&info,0,sizeof(info)); - strlcpy(info.id, "TV audio", sizeof(info.id)); - strlcpy(info.name, dev->name, sizeof(info.name)); - info.modify_counter = dev->dmasound.count; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - case SOUND_OLD_MIXER_INFO: - { - _old_mixer_info info; - memset(&info,0,sizeof(info)); - strlcpy(info.id, "TV audio", sizeof(info.id)); - strlcpy(info.name, dev->name, sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - case MIXER_READ(SOUND_MIXER_CAPS): - return put_user(SOUND_CAP_EXCL_INPUT, p); - case MIXER_READ(SOUND_MIXER_STEREODEVS): - return put_user(0, p); - case MIXER_READ(SOUND_MIXER_RECMASK): - case MIXER_READ(SOUND_MIXER_DEVMASK): - val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; - if (32000 == dev->dmasound.rate) - val |= SOUND_MASK_VIDEO; - return put_user(val, p); - - case MIXER_WRITE(SOUND_MIXER_RECSRC): - if (get_user(val, p)) - return -EFAULT; - input = dev->dmasound.input; - if (32000 == dev->dmasound.rate && - val & SOUND_MASK_VIDEO && dev->dmasound.input != TV) - input = TV; - if (val & SOUND_MASK_LINE1 && dev->dmasound.input != LINE1) - input = LINE1; - if (val & SOUND_MASK_LINE2 && dev->dmasound.input != LINE2) - input = LINE2; - if (input != dev->dmasound.input) - mixer_recsrc(dev,input); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_RECSRC): - switch (dev->dmasound.input) { - case TV: ret = SOUND_MASK_VIDEO; break; - case LINE1: ret = SOUND_MASK_LINE1; break; - case LINE2: ret = SOUND_MASK_LINE2; break; - default: ret = 0; - } - return put_user(ret, p); - - case MIXER_WRITE(SOUND_MIXER_VIDEO): - case MIXER_READ(SOUND_MIXER_VIDEO): - if (32000 != dev->dmasound.rate) - return -EINVAL; - return put_user(100 | 100 << 8, p); - - case MIXER_WRITE(SOUND_MIXER_LINE1): - if (get_user(val, p)) - return -EFAULT; - val &= 0xff; - val = (val <= 50) ? 50 : 100; - dev->dmasound.line1 = val; - mixer_level(dev,LINE1,dev->dmasound.line1); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_LINE1): - return put_user(dev->dmasound.line1 | dev->dmasound.line1 << 8, p); - - case MIXER_WRITE(SOUND_MIXER_LINE2): - if (get_user(val, p)) - return -EFAULT; - val &= 0xff; - val = (val <= 50) ? 50 : 100; - dev->dmasound.line2 = val; - mixer_level(dev,LINE2,dev->dmasound.line2); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_LINE2): - return put_user(dev->dmasound.line2 | dev->dmasound.line2 << 8, p); - - default: - return -EINVAL; - } -} - -const struct file_operations saa7134_mixer_fops = { - .owner = THIS_MODULE, - .open = mixer_open, - .release = mixer_release, - .ioctl = mixer_ioctl, - .llseek = no_llseek, -}; - -/* ------------------------------------------------------------------ */ - -static irqreturn_t saa7134_oss_irq(int irq, void *dev_id) -{ - struct saa7134_dmasound *dmasound = dev_id; - struct saa7134_dev *dev = dmasound->priv_data; - unsigned long report, status; - int loop, handled = 0; - - for (loop = 0; loop < 10; loop++) { - report = saa_readl(SAA7134_IRQ_REPORT); - status = saa_readl(SAA7134_IRQ_STATUS); - - if (report & SAA7134_IRQ_REPORT_DONE_RA3) { - handled = 1; - saa_writel(SAA7134_IRQ_REPORT,report); - saa7134_irq_oss_done(dev, status); - } else { - goto out; - } - } - - if (loop == 10) { - dprintk("error! looping IRQ!"); - } -out: - return IRQ_RETVAL(handled); -} - -int saa7134_oss_init1(struct saa7134_dev *dev) -{ - - if ((request_irq(dev->pci->irq, saa7134_oss_irq, - IRQF_SHARED | IRQF_DISABLED, dev->name, - (void*) &dev->dmasound)) < 0) - return -1; - - /* general */ - mutex_init(&dev->dmasound.lock); - init_waitqueue_head(&dev->dmasound.wq); - - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa_writel(0x588 >> 2, 0x00000fff); - saa_writel(0x58c >> 2, 0x00543210); - saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb); - break; - } - - /* dsp */ - dev->dmasound.rate = 32000; - if (rate) - dev->dmasound.rate = rate; - dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000; - - /* mixer */ - dev->dmasound.line1 = 50; - dev->dmasound.line2 = 50; - mixer_level(dev,LINE1,dev->dmasound.line1); - mixer_level(dev,LINE2,dev->dmasound.line2); - mixer_recsrc(dev, (dev->dmasound.rate == 32000) ? TV : LINE2); - - return 0; -} - -int saa7134_oss_fini(struct saa7134_dev *dev) -{ - /* nothing */ - return 0; -} - -void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) -{ - int next_blk, reg = 0; - - spin_lock(&dev->slock); - if (UNSET == dev->dmasound.dma_blk) { - dprintk("irq: recording stopped\n"); - goto done; - } - if (0 != (status & 0x0f000000)) - dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); - if (0 == (status & 0x10000000)) { - /* odd */ - if (0 == (dev->dmasound.dma_blk & 0x01)) - reg = SAA7134_RS_BA1(6); - } else { - /* even */ - if (1 == (dev->dmasound.dma_blk & 0x01)) - reg = SAA7134_RS_BA2(6); - } - if (0 == reg) { - dprintk("irq: field oops [%s]\n", - (status & 0x10000000) ? "even" : "odd"); - goto done; - } - if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { - dprintk("irq: overrun [full=%d/%d]\n",dev->dmasound.read_count, - dev->dmasound.bufsize); - dsp_dma_stop(dev); - goto done; - } - - /* next block addr */ - next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; - saa_writel(reg,next_blk * dev->dmasound.blksize); - if (debug > 2) - dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", - (status & 0x10000000) ? "even" : "odd ", next_blk, - next_blk * dev->dmasound.blksize); - - /* update status & wake waiting readers */ - dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; - dev->dmasound.read_count += dev->dmasound.blksize; - wake_up(&dev->dmasound.wq); - - done: - spin_unlock(&dev->slock); -} - -static int saa7134_dsp_create(struct saa7134_dev *dev) -{ - int err; - - err = dev->dmasound.minor_dsp = - register_sound_dsp(&saa7134_dsp_fops, - dsp_nr[dev->nr]); - if (err < 0) { - goto fail; - } - printk(KERN_INFO "%s: registered device dsp%d\n", - dev->name,dev->dmasound.minor_dsp >> 4); - - err = dev->dmasound.minor_mixer = - register_sound_mixer(&saa7134_mixer_fops, - mixer_nr[dev->nr]); - if (err < 0) - goto fail; - printk(KERN_INFO "%s: registered device mixer%d\n", - dev->name,dev->dmasound.minor_mixer >> 4); - - return 0; - -fail: - unregister_sound_dsp(dev->dmasound.minor_dsp); - return 0; - - -} - -static int oss_device_init(struct saa7134_dev *dev) -{ - dev->dmasound.priv_data = dev; - saa7134_oss_init1(dev); - saa7134_dsp_create(dev); - return 1; -} - -static int oss_device_exit(struct saa7134_dev *dev) -{ - - unregister_sound_mixer(dev->dmasound.minor_mixer); - unregister_sound_dsp(dev->dmasound.minor_dsp); - - saa7134_oss_fini(dev); - - if (dev->pci->irq > 0) { - synchronize_irq(dev->pci->irq); - free_irq(dev->pci->irq,&dev->dmasound); - } - - dev->dmasound.priv_data = NULL; - return 1; -} - -static int saa7134_oss_init(void) -{ - struct saa7134_dev *dev = NULL; - struct list_head *list; - - if (!saa7134_dmasound_init && !saa7134_dmasound_exit) { - saa7134_dmasound_init = oss_device_init; - saa7134_dmasound_exit = oss_device_exit; - } else { - printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n"); - return -EBUSY; - } - - printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n"); - - - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); - if (dev->dmasound.priv_data == NULL) { - oss_device_init(dev); - } else { - printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name); - return -EBUSY; - } - } - - if (dev == NULL) - printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n"); - - return 0; - -} - -static void saa7134_oss_exit(void) -{ - struct saa7134_dev *dev; - - list_for_each_entry(dev, &saa7134_devlist, devlist) { - /* Device isn't registered by OSS, probably ALSA's */ - if (!dev->dmasound.minor_dsp) - continue; - - oss_device_exit(dev); - } - - saa7134_dmasound_init = NULL; - saa7134_dmasound_exit = NULL; - - printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); - - return; -} - -/* We initialize this late, to make sure the sound system is up and running */ -late_initcall(saa7134_oss_init); -module_exit(saa7134_oss_exit); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 4b63ad3e8466..f1b8fcaeb43a 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -47,7 +47,7 @@ static int buffer_activate(struct saa7134_dev *dev, { dprintk("buffer_activate [%p]",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; if (NULL == next) @@ -91,7 +91,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa7134_dma_free(q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -121,7 +121,7 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); saa_writel(SAA7134_RS_CONTROL(5),control); - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -242,7 +242,7 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) if ((status & 0x100000) != 0x100000) goto done; } - saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->ts_q); diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index f8e304c76232..4e9810469ae3 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -163,32 +163,6 @@ static struct saa7134_tvaudio tvaudio[] = { /* ------------------------------------------------------------------ */ -static void tvaudio_init(struct saa7134_dev *dev) -{ - int clock = saa7134_boards[dev->board].audio_clock; - - if (UNSET != audio_clock_override) - clock = audio_clock_override; - - /* init all audio registers */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); - if (need_resched()) - schedule(); - else - udelay(10); - - saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); - saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); - /* frame locked audio is mandatory for NICAM */ - saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); - - saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); - saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); - saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); - saa_writeb(SAA7134_FM_DEMATRIX, 0x80); -} - static u32 tvaudio_carr2reg(u32 carrier) { u64 a = carrier; @@ -517,9 +491,13 @@ static int tvaudio_thread(void *data) dev->thread.scan1 = dev->thread.scan2; dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); dev->tvaudio = NULL; - tvaudio_init(dev); + + saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); + saa_writeb(SAA7134_FM_DEMATRIX, 0x80); + if (dev->ctl_automute) dev->automute = 1; + mute_input_7134(dev); /* give the tuner some time */ @@ -784,27 +762,15 @@ static int mute_input_7133(struct saa7134_dev *dev) static int tvaudio_thread_ddep(void *data) { struct saa7134_dev *dev = data; - u32 value, norms, clock; + u32 value, norms; set_freezable(); - - clock = saa7134_boards[dev->board].audio_clock; - if (UNSET != audio_clock_override) - clock = audio_clock_override; - saa_writel(0x598 >> 2, clock); - - /* unmute */ - saa_dsp_writel(dev, 0x474 >> 2, 0x00); - saa_dsp_writel(dev, 0x450 >> 2, 0x00); - for (;;) { tvaudio_sleep(dev,-1); if (kthread_should_stop()) goto done; - restart: - try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; @@ -978,6 +944,38 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev) return retval; } +void saa7134_tvaudio_init(struct saa7134_dev *dev) +{ + int clock = saa7134_boards[dev->board].audio_clock; + + if (UNSET != audio_clock_override) + clock = audio_clock_override; + + switch (dev->pci->device) { + case PCI_DEVICE_ID_PHILIPS_SAA7134: + /* init all audio registers */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); + if (need_resched()) + schedule(); + else + udelay(10); + + saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); + saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); + /* frame locked audio is mandatory for NICAM */ + saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); + saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); + saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); + break; + case PCI_DEVICE_ID_PHILIPS_SAA7133: + case PCI_DEVICE_ID_PHILIPS_SAA7135: + saa_writel(0x598 >> 2, clock); + saa_dsp_writel(dev, 0x474 >> 2, 0x00); + saa_dsp_writel(dev, 0x450 >> 2, 0x00); + } +} + int saa7134_tvaudio_init2(struct saa7134_dev *dev) { int (*my_thread)(void *data) = NULL; @@ -994,6 +992,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) dev->thread.thread = NULL; if (my_thread) { + saa7134_tvaudio_init(dev); /* start tvaudio thread */ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); if (IS_ERR(dev->thread.thread)) { diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c index 81a2aedeff5c..f0d5ed9c2b06 100644 --- a/drivers/media/video/saa7134/saa7134-vbi.c +++ b/drivers/media/video/saa7134/saa7134-vbi.c @@ -85,7 +85,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long control,base; dprintk("buffer_activate [%p]\n",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; task_init(dev,buf,TASK_A); @@ -136,7 +136,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (buf->vb.size != size) saa7134_dma_free(q,buf); - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = llength; @@ -154,7 +154,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; buf->vb.field = field; return 0; @@ -240,7 +240,7 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) goto done; dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; - saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->vbi_q); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 6396d9b5c063..1184d359e848 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -38,7 +38,7 @@ /* ------------------------------------------------------------------ */ -static unsigned int video_debug = 0; +unsigned int video_debug; static unsigned int gbuffers = 8; static unsigned int noninterlaced = 0; static unsigned int gbufsize = 720*576*4; @@ -54,7 +54,7 @@ module_param_string(secam, secam, sizeof(secam), 0644); MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); -#define dprintk(fmt, arg...) if (video_debug) \ +#define dprintk(fmt, arg...) if (video_debug&0x04) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) /* ------------------------------------------------------------------ */ @@ -540,9 +540,8 @@ void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) /* ------------------------------------------------------------------ */ -void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) +static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - dprintk("set tv norm = %s\n",norm->name); dev->tvnorm = norm; @@ -561,7 +560,6 @@ void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) dev->crop_current = dev->crop_defrect; saa7134_set_tvnorm_hw(dev); - } static void video_mux(struct saa7134_dev *dev, int input) @@ -945,7 +943,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ dprintk("buffer_activate buf=%p\n",buf); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; buf->top_seen = 0; set_size(dev,TASK_A,buf->vb.width,buf->vb.height, @@ -1054,7 +1052,7 @@ static int buffer_prepare(struct videobuf_queue *q, saa7134_dma_free(q,buf); } - if (STATE_NEEDS_INIT == buf->vb.state) { + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); buf->vb.width = fh->width; @@ -1074,7 +1072,7 @@ static int buffer_prepare(struct videobuf_queue *q, if (err) goto oops; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; return 0; @@ -1119,8 +1117,10 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) +int saa7134_g_ctrl(struct file *file, void *priv, 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); @@ -1165,17 +1165,27 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) } return 0; } +EXPORT_SYMBOL_GPL(saa7134_g_ctrl); -static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_control *c) +int saa7134_s_ctrl(struct file *file, void *f, 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; + + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; + + mutex_lock(&dev->lock); ctrl = ctrl_by_id(c->id); if (NULL == ctrl) - return -EINVAL; + goto error; + dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); switch (ctrl->type) { case V4L2_CTRL_TYPE_BOOLEAN: @@ -1236,18 +1246,26 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, restart_overlay = 1; break; case V4L2_CID_PRIVATE_AUTOMUTE: + { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + dev->ctl_automute = c->value; if (dev->tda9887_conf) { if (dev->ctl_automute) dev->tda9887_conf |= TDA9887_AUTOMUTE; else dev->tda9887_conf &= ~TDA9887_AUTOMUTE; - saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, - &dev->tda9887_conf); + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); } break; + } default: - return -EINVAL; + goto error; } if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); @@ -1255,8 +1273,13 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } - return 0; + err = 0; + +error: + mutex_unlock(&dev->lock); + return err; } +EXPORT_SYMBOL_GPL(saa7134_s_ctrl); /* ------------------------------------------------------------------ */ @@ -1413,8 +1436,8 @@ video_poll(struct file *file, struct poll_table_struct *wait) return POLLERR; poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; } @@ -1478,8 +1501,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma) /* ------------------------------------------------------------------ */ -static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) +static int saa7134_try_get_set_fmt_vbi(struct file *file, void *priv, + struct v4l2_format *f) { + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; struct saa7134_tvnorm *norm = dev->tvnorm; f->fmt.vbi.sampling_rate = 6750000 * 4; @@ -1492,837 +1518,805 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ + return 0; } -static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int saa7134_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->cap.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - f->fmt.win = fh->win; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - saa7134_vbi_fmt(dev,f); - return 0; - default: - return -EINVAL; - } + struct saa7134_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->cap.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; } -static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int saa7134_g_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) { - int err; + struct saa7134_fh *fh = priv; - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - { - struct saa7134_format *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } + f->fmt.win = fh->win; - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; + return 0; +} - field = f->fmt.pix.field; - maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); - maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); +static int saa7134_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + struct saa7134_format *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; - if (V4L2_FIELD_ANY == field) { - field = (f->fmt.pix.height > maxh/2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } + fmt = format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; - f->fmt.pix.field = field; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = - (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = - f->fmt.pix.height * f->fmt.pix.bytesperline; + field = f->fmt.pix.field; + maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); + maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); - return 0; + if (V4L2_FIELD_ANY == field) { + field = (f->fmt.pix.height > maxh/2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; } - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - err = verify_preview(dev,&f->fmt.win); - if (0 != err) - return err; - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - saa7134_vbi_fmt(dev,f); - return 0; + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; default: return -EINVAL; } + + f->fmt.pix.field = field; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = + (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = + f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; } -static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, - struct v4l2_format *f) +static int saa7134_try_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) { - unsigned long flags; - int err; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - err = saa7134_try_fmt(dev,fh,f); - if (0 != err) - return err; - - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->cap.field = f->fmt.pix.field; - return 0; - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - err = verify_preview(dev,&f->fmt.win); - if (0 != err) - return err; - - mutex_lock(&dev->lock); - fh->win = f->fmt.win; - fh->nclips = f->fmt.win.clipcount; - if (fh->nclips > 8) - fh->nclips = 8; - if (copy_from_user(fh->clips,f->fmt.win.clips, - sizeof(struct v4l2_clip)*fh->nclips)) { - mutex_unlock(&dev->lock); - return -EFAULT; - } + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } - mutex_unlock(&dev->lock); - return 0; - case V4L2_BUF_TYPE_VBI_CAPTURE: - saa7134_vbi_fmt(dev,f); - return 0; - default: + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } + + return verify_preview(dev, &f->fmt.win); } -int saa7134_common_ioctl(struct saa7134_dev *dev, - unsigned int cmd, void *arg) +static int saa7134_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) { + struct saa7134_fh *fh = priv; int err; - switch (cmd) { - case VIDIOC_QUERYCTRL: - { - const struct v4l2_queryctrl *ctrl; - struct v4l2_queryctrl *c = arg; + err = saa7134_try_fmt_cap(file, priv, f); + if (0 != err) + return err; - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - ctrl = ctrl_by_id(c->id); - *c = (NULL != ctrl) ? *ctrl : no_ctrl; - return 0; + fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + fh->width = f->fmt.pix.width; + fh->height = f->fmt.pix.height; + fh->cap.field = f->fmt.pix.field; + return 0; +} + +static int saa7134_s_fmt_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int err; + unsigned int flags; + + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; } - case VIDIOC_G_CTRL: - return get_control(dev,arg); - case VIDIOC_S_CTRL: - { - mutex_lock(&dev->lock); - err = set_control(dev,NULL,arg); - mutex_unlock(&dev->lock); + err = verify_preview(dev, &f->fmt.win); + if (0 != err) return err; - } - /* --- input switching --------------------------------------- */ - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; - n = i->index; - if (n >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev,i->index).name) - return -EINVAL; - memset(i,0,sizeof(*i)); - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,card_in(dev,n).name); - if (card_in(dev,n).tv) - i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; - if (n == dev->ctl_input) { - int v1 = saa_readb(SAA7134_STATUS_VIDEO1); - int v2 = saa_readb(SAA7134_STATUS_VIDEO2); - - if (0 != (v1 & 0x40)) - i->status |= V4L2_IN_ST_NO_H_LOCK; - if (0 != (v2 & 0x40)) - i->status |= V4L2_IN_ST_NO_SYNC; - if (0 != (v2 & 0x0e)) - i->status |= V4L2_IN_ST_MACROVISION; - } - for (n = 0; n < TVNORMS; n++) - i->std |= tvnorms[n].id; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = dev->ctl_input; - return 0; - } - case VIDIOC_S_INPUT: - { - int *i = arg; + mutex_lock(&dev->lock); - if (*i < 0 || *i >= SAA7134_INPUT_MAX) - return -EINVAL; - if (NULL == card_in(dev,*i).name) - return -EINVAL; - mutex_lock(&dev->lock); - video_mux(dev,*i); + fh->win = f->fmt.win; + fh->nclips = f->fmt.win.clipcount; + + if (fh->nclips > 8) + fh->nclips = 8; + + if (copy_from_user(fh->clips, f->fmt.win.clips, + sizeof(struct v4l2_clip)*fh->nclips)) { mutex_unlock(&dev->lock); - return 0; + return -EFAULT; } + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock, flags); + stop_preview(dev, fh); + start_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); } + + mutex_unlock(&dev->lock); return 0; } -EXPORT_SYMBOL(saa7134_common_ioctl); -/* - * This function is _not_ called directly, but from - * video_generic_ioctl (and maybe others). userspace - * copying is done already, arg is a kernel pointer. - */ -static int video_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { - struct saa7134_fh *fh = file->private_data; + const struct v4l2_queryctrl *ctrl; + + if ((c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) && + (c->id < V4L2_CID_PRIVATE_BASE || + c->id >= V4L2_CID_PRIVATE_LASTP1)) + return -EINVAL; + ctrl = ctrl_by_id(c->id); + *c = (NULL != ctrl) ? *ctrl : no_ctrl; + return 0; +} +EXPORT_SYMBOL_GPL(saa7134_queryctrl); + +static int saa7134_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + unsigned int n; + + n = i->index; + if (n >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i->index).name) + return -EINVAL; + memset(i, 0, sizeof(*i)); + i->index = n; + i->type = V4L2_INPUT_TYPE_CAMERA; + strcpy(i->name, card_in(dev, n).name); + if (card_in(dev, n).tv) + i->type = V4L2_INPUT_TYPE_TUNER; + i->audioset = 1; + if (n == dev->ctl_input) { + int v1 = saa_readb(SAA7134_STATUS_VIDEO1); + int v2 = saa_readb(SAA7134_STATUS_VIDEO2); + + if (0 != (v1 & 0x40)) + i->status |= V4L2_IN_ST_NO_H_LOCK; + if (0 != (v2 & 0x40)) + i->status |= V4L2_IN_ST_NO_SYNC; + if (0 != (v2 & 0x0e)) + i->status |= V4L2_IN_ST_MACROVISION; + } + i->std = SAA7134_NORMS; + return 0; +} + +static int saa7134_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + + *i = dev->ctl_input; + return 0; +} + +static int saa7134_s_input(struct file *file, void *priv, unsigned int i) +{ + struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - unsigned long flags; int err; - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); - - switch (cmd) { - case VIDIOC_S_CTRL: - case VIDIOC_S_STD: - case VIDIOC_S_INPUT: - case VIDIOC_S_TUNER: - case VIDIOC_S_FREQUENCY: - err = v4l2_prio_check(&dev->prio,&fh->prio); - if (0 != err) - return err; - } + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - unsigned int tuner_type = dev->tuner_type; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - if (saa7134_no_overlay <= 0) { - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; - } + if (i < 0 || i >= SAA7134_INPUT_MAX) + return -EINVAL; + if (NULL == card_in(dev, i).name) + return -EINVAL; + mutex_lock(&dev->lock); + video_mux(dev, i); + mutex_unlock(&dev->lock); + return 0; +} - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; +static int saa7134_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + unsigned int tuner_type = dev->tuner_type; + + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, + sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = + V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER; + if (saa7134_no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + + if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) + cap->capabilities &= ~V4L2_CAP_TUNER; return 0; - } +} - /* --- tv standards ------------------------------------------ */ - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; +static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + unsigned long flags; + unsigned int i; + v4l2_std_id fixup; + int err; - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - err = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (err < 0) - return err; - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; - *id = dev->tvnorm->id; - return 0; - } - case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; - v4l2_std_id fixup; + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) + if (*id & tvnorms[i].id) break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { - if (secam[0] == 'L' || secam[0] == 'l') { - if (secam[1] == 'C' || secam[1] == 'c') - fixup = V4L2_STD_SECAM_LC; - else - fixup = V4L2_STD_SECAM_L; - } else { - if (secam[0] == 'D' || secam[0] == 'd') - fixup = V4L2_STD_SECAM_DK; - else - fixup = V4L2_STD_SECAM; - } - for (i = 0; i < TVNORMS; i++) - if (fixup == tvnorms[i].id) - break; + if (i == TVNORMS) + return -EINVAL; + + if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if (secam[0] == 'L' || secam[0] == 'l') { + if (secam[1] == 'C' || secam[1] == 'c') + fixup = V4L2_STD_SECAM_LC; + else + fixup = V4L2_STD_SECAM_L; + } else { + if (secam[0] == 'D' || secam[0] == 'd') + fixup = V4L2_STD_SECAM_DK; + else + fixup = V4L2_STD_SECAM; } - mutex_lock(&dev->lock); - if (res_check(fh, RESOURCE_OVERLAY)) { - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock, flags); - - set_tvnorm(dev,&tvnorms[i]); - - spin_lock_irqsave(&dev->slock, flags); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } else - set_tvnorm(dev,&tvnorms[i]); - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; + for (i = 0; i < TVNORMS; i++) + if (fixup == tvnorms[i].id) + break; } - case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cap = arg; + *id = tvnorms[i].id; - if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - cap->bounds = dev->crop_bounds; - cap->defrect = dev->crop_defrect; - cap->pixelaspect.numerator = 1; - cap->pixelaspect.denominator = 1; - if (dev->tvnorm->id & V4L2_STD_525_60) { - cap->pixelaspect.numerator = 11; - cap->pixelaspect.denominator = 10; - } - if (dev->tvnorm->id & V4L2_STD_625_50) { - cap->pixelaspect.numerator = 54; - cap->pixelaspect.denominator = 59; - } - return 0; - } + mutex_lock(&dev->lock); + if (res_check(fh, RESOURCE_OVERLAY)) { + spin_lock_irqsave(&dev->slock, flags); + stop_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); - case VIDIOC_G_CROP: - { - struct v4l2_crop * crop = arg; + set_tvnorm(dev, &tvnorms[i]); - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - crop->c = dev->crop_current; - return 0; - } - case VIDIOC_S_CROP: - { - struct v4l2_crop *crop = arg; - struct v4l2_rect *b = &dev->crop_bounds; + spin_lock_irqsave(&dev->slock, flags); + start_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + } else + set_tvnorm(dev, &tvnorms[i]); - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) - return -EINVAL; - if (crop->c.height < 0) - return -EINVAL; - if (crop->c.width < 0) - return -EINVAL; + saa7134_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} - if (res_locked(fh->dev,RESOURCE_OVERLAY)) - return -EBUSY; - if (res_locked(fh->dev,RESOURCE_VIDEO)) - return -EBUSY; +static int saa7134_cropcap(struct file *file, void *priv, + struct v4l2_cropcap *cap) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - if (crop->c.top < b->top) - crop->c.top = b->top; - if (crop->c.top > b->top + b->height) - crop->c.top = b->top + b->height; - if (crop->c.height > b->top - crop->c.top + b->height) - crop->c.height = b->top - crop->c.top + b->height; - - if (crop->c.left < b->left) - crop->c.left = b->left; - if (crop->c.left > b->left + b->width) - crop->c.left = b->left + b->width; - if (crop->c.width > b->left - crop->c.left + b->width) - crop->c.width = b->left - crop->c.left + b->width; - - dev->crop_current = crop->c; - return 0; + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + cap->bounds = dev->crop_bounds; + cap->defrect = dev->crop_defrect; + cap->pixelaspect.numerator = 1; + cap->pixelaspect.denominator = 1; + if (dev->tvnorm->id & V4L2_STD_525_60) { + cap->pixelaspect.numerator = 11; + cap->pixelaspect.denominator = 10; + } + if (dev->tvnorm->id & V4L2_STD_625_50) { + cap->pixelaspect.numerator = 54; + cap->pixelaspect.denominator = 59; } + return 0; +} - /* --- tuner ioctls ------------------------------------------ */ - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - int n; +static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; - if (0 != t->index) - return -EINVAL; - memset(t,0,sizeof(*t)); - for (n = 0; n < SAA7134_INPUT_MAX; n++) - if (card_in(dev,n).tv) - break; - if (NULL != card_in(dev,n).name) { - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; - t->rxsubchans = saa7134_tvaudio_getstereo(dev); - t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) - t->signal = 0xffff; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; - int rx,mode; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + crop->c = dev->crop_current; + return 0; +} - mode = dev->thread.mode; - if (UNSET == mode) { - rx = saa7134_tvaudio_getstereo(dev); - mode = saa7134_tvaudio_rx2mode(t->rxsubchans); - } - if (mode != t->audmode) { - dev->thread.mode = t->audmode; - } - return 0; - } - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; +static int saa7134_s_crop(struct file *file, void *f, struct v4l2_crop *crop) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + struct v4l2_rect *b = &dev->crop_bounds; - memset(f,0,sizeof(*f)); - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - return 0; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) + return -EINVAL; + if (crop->c.height < 0) + return -EINVAL; + if (crop->c.width < 0) + return -EINVAL; - if (0 != f->tuner) - return -EINVAL; - if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; - if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) - return -EINVAL; - mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; + if (res_locked(fh->dev, RESOURCE_OVERLAY)) + return -EBUSY; + if (res_locked(fh->dev, RESOURCE_VIDEO)) + return -EBUSY; + + if (crop->c.top < b->top) + crop->c.top = b->top; + if (crop->c.top > b->top + b->height) + crop->c.top = b->top + b->height; + if (crop->c.height > b->top - crop->c.top + b->height) + crop->c.height = b->top - crop->c.top + b->height; + + if (crop->c.left < b->left) + crop->c.left = b->left; + if (crop->c.left > b->left + b->width) + crop->c.left = b->left + b->width; + if (crop->c.width > b->left - crop->c.left + b->width) + crop->c.width = b->left - crop->c.left + b->width; + + dev->crop_current = crop->c; + return 0; +} - saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); +static int saa7134_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int n; - saa7134_tvaudio_do_scan(dev); - mutex_unlock(&dev->lock); - return 0; - } + if (0 != t->index) + return -EINVAL; + memset(t, 0, sizeof(*t)); + for (n = 0; n < SAA7134_INPUT_MAX; n++) + if (card_in(dev, n).tv) + break; + if (NULL != card_in(dev, n).name) { + strcpy(t->name, "Television"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + t->rangehigh = 0xffffffffUL; + t->rxsubchans = saa7134_tvaudio_getstereo(dev); + t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); + } + if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) + t->signal = 0xffff; + return 0; +} - /* --- control ioctls ---------------------------------------- */ - case VIDIOC_ENUMINPUT: - case VIDIOC_G_INPUT: - case VIDIOC_S_INPUT: - case VIDIOC_QUERYCTRL: - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - return saa7134_common_ioctl(dev, cmd, arg); +static int saa7134_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int rx, mode, err; - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; - memset(a,0,sizeof(*a)); - strcpy(a->name,"audio"); - return 0; - } - case VIDIOC_S_AUDIO: - return 0; - case VIDIOC_G_PARM: - { - struct v4l2_captureparm *parm = arg; - memset(parm,0,sizeof(*parm)); - return 0; + mode = dev->thread.mode; + if (UNSET == mode) { + rx = saa7134_tvaudio_getstereo(dev); + mode = saa7134_tvaudio_rx2mode(t->rxsubchans); } + if (mode != t->audmode) + dev->thread.mode = t->audmode; - case VIDIOC_G_PRIORITY: - { - enum v4l2_priority *p = arg; + return 0; +} - *p = v4l2_prio_max(&dev->prio); - return 0; - } - case VIDIOC_S_PRIORITY: - { - enum v4l2_priority *prio = arg; +static int saa7134_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; - return v4l2_prio_change(&dev->prio, &fh->prio, *prio); - } + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; - /* --- preview ioctls ---------------------------------------- */ - case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *f = arg; - enum v4l2_buf_type type; - unsigned int index; - - index = f->index; - type = f->type; - switch (type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (saa7134_no_overlay > 0) { - printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); - return -EINVAL; - } - if (index >= FORMATS) - return -EINVAL; - if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && - formats[index].planar) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - strlcpy(f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].fourcc; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (0 != index) - return -EINVAL; - memset(f,0,sizeof(*f)); - f->index = index; - f->type = type; - f->pixelformat = V4L2_PIX_FMT_GREY; - strcpy(f->description,"vbi data"); - break; - default: - return -EINVAL; - } - return 0; - } - case VIDIOC_G_FBUF: - { - struct v4l2_framebuffer *fb = arg; + return 0; +} - *fb = dev->ovbuf; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - return 0; - } - case VIDIOC_S_FBUF: - { - struct v4l2_framebuffer *fb = arg; - struct saa7134_format *fmt; +static int saa7134_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int err; - if(!capable(CAP_SYS_ADMIN) && - !capable(CAP_SYS_RAWIO)) - return -EPERM; + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; - /* check args */ - fmt = format_by_fourcc(fb->fmt.pixelformat); - if (NULL == fmt) - return -EINVAL; + if (0 != f->tuner) + return -EINVAL; + if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) + return -EINVAL; + if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) + return -EINVAL; + mutex_lock(&dev->lock); + dev->ctl_freq = f->frequency; - /* ok, accept it */ - dev->ovbuf = *fb; - dev->ovfmt = fmt; - if (0 == dev->ovbuf.fmt.bytesperline) - dev->ovbuf.fmt.bytesperline = - dev->ovbuf.fmt.width*fmt->depth/8; - return 0; + saa7134_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); + + saa7134_tvaudio_do_scan(dev); + mutex_unlock(&dev->lock); + return 0; +} + +static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + strcpy(a->name, "audio"); + return 0; +} + +static int saa7134_s_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + return 0; +} + +static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + + *p = v4l2_prio_max(&dev->prio); + return 0; +} + +static int saa7134_s_priority(struct file *file, void *f, + enum v4l2_priority prio) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + + return v4l2_prio_change(&dev->prio, &fh->prio, prio); +} + +static int saa7134_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >= FORMATS) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int saa7134_enum_fmt_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (saa7134_no_overlay > 0) { + printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; } - case VIDIOC_OVERLAY: - { - int *on = arg; - if (*on) { - if (saa7134_no_overlay > 0) { - printk ("no_overlay\n"); - return -EINVAL; - } + if ((f->index >= FORMATS) || formats[f->index].planar) + return -EINVAL; - if (!res_get(dev,fh,RESOURCE_OVERLAY)) - return -EBUSY; - spin_lock_irqsave(&dev->slock,flags); - start_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - } - if (!*on) { - if (!res_check(fh, RESOURCE_OVERLAY)) - return -EINVAL; - spin_lock_irqsave(&dev->slock,flags); - stop_preview(dev,fh); - spin_unlock_irqrestore(&dev->slock,flags); - res_free(dev,fh,RESOURCE_OVERLAY); + strlcpy(f->description, formats[f->index].name, + sizeof(f->description)); + + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int saa7134_enum_fmt_vbi(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (0 != f->index) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "vbi data"); + + return 0; +} + +static int saa7134_g_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + + *fb = dev->ovbuf; + fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + + return 0; +} + +static int saa7134_s_fbuf(struct file *file, void *f, + struct v4l2_framebuffer *fb) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + struct saa7134_format *fmt; + + if (!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + + /* check args */ + fmt = format_by_fourcc(fb->fmt.pixelformat); + if (NULL == fmt) + return -EINVAL; + + /* ok, accept it */ + dev->ovbuf = *fb; + dev->ovfmt = fmt; + if (0 == dev->ovbuf.fmt.bytesperline) + dev->ovbuf.fmt.bytesperline = + dev->ovbuf.fmt.width*fmt->depth/8; + return 0; +} + +static int saa7134_overlay(struct file *file, void *f, unsigned int on) +{ + struct saa7134_fh *fh = f; + struct saa7134_dev *dev = fh->dev; + unsigned long flags; + + if (on) { + if (saa7134_no_overlay > 0) { + dprintk("no_overlay\n"); + return -EINVAL; } - return 0; - } - /* --- capture ioctls ---------------------------------------- */ - case VIDIOC_G_FMT: - { - struct v4l2_format *f = arg; - return saa7134_g_fmt(dev,fh,f); - } - case VIDIOC_S_FMT: - { - struct v4l2_format *f = arg; - return saa7134_s_fmt(dev,fh,f); + if (!res_get(dev, fh, RESOURCE_OVERLAY)) + return -EBUSY; + spin_lock_irqsave(&dev->slock, flags); + start_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); } - case VIDIOC_TRY_FMT: - { - struct v4l2_format *f = arg; - return saa7134_try_fmt(dev,fh,f); + if (!on) { + if (!res_check(fh, RESOURCE_OVERLAY)) + return -EINVAL; + spin_lock_irqsave(&dev->slock, flags); + stop_preview(dev, fh); + spin_unlock_irqrestore(&dev->slock, flags); + res_free(dev, fh, RESOURCE_OVERLAY); } + return 0; +} + #ifdef CONFIG_VIDEO_V4L1_COMPAT - case VIDIOCGMBUF: - return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers); +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) +{ + struct saa7134_fh *fh = file->private_data; + return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8); +} #endif - case VIDIOC_REQBUFS: - return videobuf_reqbufs(saa7134_queue(fh),arg); - case VIDIOC_QUERYBUF: - return videobuf_querybuf(saa7134_queue(fh),arg); +static int saa7134_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) +{ + struct saa7134_fh *fh = priv; + return videobuf_reqbufs(saa7134_queue(fh), p); +} - case VIDIOC_QBUF: - return videobuf_qbuf(saa7134_queue(fh),arg); +static int saa7134_querybuf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_querybuf(saa7134_queue(fh), b); +} - case VIDIOC_DQBUF: - return videobuf_dqbuf(saa7134_queue(fh),arg, - file->f_flags & O_NONBLOCK); +static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_qbuf(saa7134_queue(fh), b); +} - case VIDIOC_STREAMON: - { - int res = saa7134_resource(fh); +static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) +{ + struct saa7134_fh *fh = priv; + return videobuf_dqbuf(saa7134_queue(fh), b, + file->f_flags & O_NONBLOCK); +} - if (!res_get(dev,fh,res)) - return -EBUSY; - return videobuf_streamon(saa7134_queue(fh)); - } - case VIDIOC_STREAMOFF: - { - int res = saa7134_resource(fh); +static int saa7134_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int res = saa7134_resource(fh); - err = videobuf_streamoff(saa7134_queue(fh)); - if (err < 0) - return err; - res_free(dev,fh,res); - return 0; - } + if (!res_get(dev, fh, res)) + return -EBUSY; - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - video_do_ioctl); - } + return videobuf_streamon(saa7134_queue(fh)); +} + +static int saa7134_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + int err; + struct saa7134_fh *fh = priv; + struct saa7134_dev *dev = fh->dev; + int res = saa7134_resource(fh); + + err = videobuf_streamoff(saa7134_queue(fh)); + if (err < 0) + return err; + res_free(dev, fh, res); return 0; } -static int video_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int saa7134_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) { - return video_usercopy(inode, file, cmd, arg, video_do_ioctl); + return 0; } -static int radio_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +static int radio_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; - if (video_debug > 1) - v4l_print_ioctl(dev->name,cmd); - switch (cmd) { - case VIDIOC_QUERYCAP: - { - struct v4l2_capability *cap = arg; - - memset(cap,0,sizeof(*cap)); - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->version = SAA7134_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; + strcpy(cap->driver, "saa7134"); + strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cap->version = SAA7134_VERSION_CODE; + cap->capabilities = V4L2_CAP_TUNER; + return 0; +} - if (0 != t->index) - return -EINVAL; +static int radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; - memset(t,0,sizeof(*t)); - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; + if (0 != t->index) + return -EINVAL; - saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - if (dev->input->amux == TV) { - t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); - t->rxsubchans = (saa_readb(0x529) & 0x08) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; - } - return 0; + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Radio"); + t->type = V4L2_TUNER_RADIO; + + saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t); + if (dev->input->amux == TV) { + t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); + t->rxsubchans = (saa_readb(0x529) & 0x08) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; + return 0; +} +static int radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *t) +{ + struct saa7134_fh *fh = file->private_data; + struct saa7134_dev *dev = fh->dev; - if (0 != t->index) - return -EINVAL; + if (0 != t->index) + return -EINVAL; - saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t); + saa7134_i2c_call_clients(dev, VIDIOC_S_TUNER, t); + return 0; +} - return 0; - } - case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; +static int radio_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + if (i->index != 0) + return -EINVAL; - if (i->index != 0) - return -EINVAL; - strcpy(i->name,"Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - return 0; - } - case VIDIOC_G_INPUT: - { - int *i = arg; - *i = 0; - return 0; - } - case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; + strcpy(i->name, "Radio"); + i->type = V4L2_INPUT_TYPE_TUNER; - memset(a,0,sizeof(*a)); - strcpy(a->name,"Radio"); - return 0; - } - case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; - *id = 0; - return 0; - } - case VIDIOC_S_AUDIO: - case VIDIOC_S_INPUT: - case VIDIOC_S_STD: - return 0; + return 0; +} - case VIDIOC_QUERYCTRL: - { - const struct v4l2_queryctrl *ctrl; - struct v4l2_queryctrl *c = arg; +static int radio_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctrl; - return 0; - } +static int radio_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + memset(a, 0, sizeof(*a)); + strcpy(a->name, "Radio"); + return 0; +} - case VIDIOC_G_CTRL: - case VIDIOC_S_CTRL: - case VIDIOC_G_FREQUENCY: - case VIDIOC_S_FREQUENCY: - return video_do_ioctl(inode,file,cmd,arg); +static int radio_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return 0; +} - default: - return v4l_compat_translate_ioctl(inode,file,cmd,arg, - radio_do_ioctl); - } +static int radio_s_input(struct file *filp, void *priv, unsigned int i) +{ return 0; } -static int radio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) { - return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); + return 0; +} + +static int radio_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *c) +{ + const struct v4l2_queryctrl *ctrl; + + if (c->id < V4L2_CID_BASE || + c->id >= V4L2_CID_LASTP1) + return -EINVAL; + if (c->id == V4L2_CID_AUDIO_MUTE) { + ctrl = ctrl_by_id(c->id); + *c = *ctrl; + } else + *c = no_ctrl; + return 0; } static const struct file_operations video_fops = @@ -2333,7 +2327,7 @@ static const struct file_operations video_fops = .read = video_read, .poll = video_poll, .mmap = video_mmap, - .ioctl = video_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2343,7 +2337,7 @@ static const struct file_operations radio_fops = .owner = THIS_MODULE, .open = video_open, .release = video_release, - .ioctl = radio_ioctl, + .ioctl = video_ioctl2, .compat_ioctl = v4l_compat_ioctl32, .llseek = no_llseek, }; @@ -2353,27 +2347,79 @@ static const struct file_operations radio_fops = 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, -}; - -struct video_device saa7134_vbi_template = -{ - .name = "saa7134-vbi", - .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, - .fops = &video_fops, - .minor = -1, + .name = "saa7134-video", + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | + VID_TYPE_CLIPPING|VID_TYPE_SCALES, + .fops = &video_fops, + .minor = -1, + .vidioc_querycap = saa7134_querycap, + .vidioc_enum_fmt_cap = saa7134_enum_fmt_cap, + .vidioc_g_fmt_cap = saa7134_g_fmt_cap, + .vidioc_try_fmt_cap = saa7134_try_fmt_cap, + .vidioc_s_fmt_cap = saa7134_s_fmt_cap, + .vidioc_enum_fmt_overlay = saa7134_enum_fmt_overlay, + .vidioc_g_fmt_overlay = saa7134_g_fmt_overlay, + .vidioc_try_fmt_overlay = saa7134_try_fmt_overlay, + .vidioc_s_fmt_overlay = saa7134_s_fmt_overlay, + .vidioc_enum_fmt_vbi = saa7134_enum_fmt_vbi, + .vidioc_g_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_try_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_s_fmt_vbi = saa7134_try_get_set_fmt_vbi, + .vidioc_g_audio = saa7134_g_audio, + .vidioc_s_audio = saa7134_s_audio, + .vidioc_cropcap = saa7134_cropcap, + .vidioc_reqbufs = saa7134_reqbufs, + .vidioc_querybuf = saa7134_querybuf, + .vidioc_qbuf = saa7134_qbuf, + .vidioc_dqbuf = saa7134_dqbuf, + .vidioc_s_std = saa7134_s_std, + .vidioc_enum_input = saa7134_enum_input, + .vidioc_g_input = saa7134_g_input, + .vidioc_s_input = saa7134_s_input, + .vidioc_queryctrl = saa7134_queryctrl, + .vidioc_g_ctrl = saa7134_g_ctrl, + .vidioc_s_ctrl = saa7134_s_ctrl, + .vidioc_streamon = saa7134_streamon, + .vidioc_streamoff = saa7134_streamoff, + .vidioc_g_tuner = saa7134_g_tuner, + .vidioc_s_tuner = saa7134_s_tuner, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_crop = saa7134_g_crop, + .vidioc_s_crop = saa7134_s_crop, + .vidioc_g_fbuf = saa7134_g_fbuf, + .vidioc_s_fbuf = saa7134_s_fbuf, + .vidioc_overlay = saa7134_overlay, + .vidioc_g_priority = saa7134_g_priority, + .vidioc_s_priority = saa7134_s_priority, + .vidioc_g_parm = saa7134_g_parm, + .vidioc_g_frequency = saa7134_g_frequency, + .vidioc_s_frequency = saa7134_s_frequency, + .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, + .name = "saa7134-radio", + .type = VID_TYPE_TUNER, + .fops = &radio_fops, + .minor = -1, + .vidioc_querycap = radio_querycap, + .vidioc_g_tuner = radio_g_tuner, + .vidioc_enum_input = radio_enum_input, + .vidioc_g_audio = radio_g_audio, + .vidioc_s_tuner = radio_s_tuner, + .vidioc_s_audio = radio_s_audio, + .vidioc_s_input = radio_s_input, + .vidioc_s_std = radio_s_std, + .vidioc_queryctrl = radio_queryctrl, + .vidioc_g_input = radio_g_input, + .vidioc_g_ctrl = saa7134_g_ctrl, + .vidioc_s_ctrl = saa7134_s_ctrl, + .vidioc_g_frequency = saa7134_g_frequency, + .vidioc_s_frequency = saa7134_s_frequency, }; int saa7134_video_init1(struct saa7134_dev *dev) @@ -2511,7 +2557,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) goto done; } dev->video_q.curr->vb.field_count = dev->video_fieldcount; - saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); + saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE); } saa7134_buffer_next(dev,&dev->video_q); diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 66a390c321a7..ce450304fb53 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -240,6 +240,19 @@ struct saa7134_format { #define SAA7134_BOARD_SABRENT_TV_PCB05 115 #define SAA7134_BOARD_10MOONSTVMASTER3 116 #define SAA7134_BOARD_AVERMEDIA_SUPER_007 117 +#define SAA7134_BOARD_BEHOLD_401 118 +#define SAA7134_BOARD_BEHOLD_403 119 +#define SAA7134_BOARD_BEHOLD_403FM 120 +#define SAA7134_BOARD_BEHOLD_405 121 +#define SAA7134_BOARD_BEHOLD_405FM 122 +#define SAA7134_BOARD_BEHOLD_407 123 +#define SAA7134_BOARD_BEHOLD_407FM 124 +#define SAA7134_BOARD_BEHOLD_409 125 +#define SAA7134_BOARD_BEHOLD_505FM 126 +#define SAA7134_BOARD_BEHOLD_507_9FM 127 +#define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 +#define SAA7134_BOARD_BEHOLD_607_9FM 129 +#define SAA7134_BOARD_BEHOLD_M6 130 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -481,7 +494,7 @@ struct saa7134_dev { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; - unsigned char eedata[128]; + unsigned char eedata[256]; /* video overlay */ struct v4l2_framebuffer ovbuf; @@ -566,6 +579,12 @@ struct saa7134_dev { #define saa_wait(us) { udelay(us); } +#define SAA7134_NORMS (\ + V4L2_STD_PAL | V4L2_STD_PAL_N | \ + V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ + V4L2_STD_NTSC | V4L2_STD_PAL_M | \ + V4L2_STD_PAL_60) + /* ----------------------------------------------------------- */ /* saa7134-core.c */ @@ -596,9 +615,6 @@ void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); void saa7134_buffer_timeout(unsigned long data); void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf); -int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q); - int saa7134_set_dmabits(struct saa7134_dev *dev); extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev); @@ -628,16 +644,17 @@ void saa7134_i2c_call_clients(struct saa7134_dev *dev, /* ----------------------------------------------------------- */ /* saa7134-video.c */ +extern unsigned int video_debug; extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm); +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_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); + int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); -int saa7134_common_ioctl(struct saa7134_dev *dev, - unsigned int cmd, void *arg); - int saa7134_video_init1(struct saa7134_dev *dev); int saa7134_video_init2(struct saa7134_dev *dev); void saa7134_irq_video_signalchange(struct saa7134_dev *dev); @@ -682,6 +699,7 @@ void saa7134_tvaudio_setinput(struct saa7134_dev *dev, void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level); int saa7134_tvaudio_getstereo(struct saa7134_dev *dev); +void saa7134_tvaudio_init(struct saa7134_dev *dev); int saa7134_tvaudio_init2(struct saa7134_dev *dev); int saa7134_tvaudio_fini(struct saa7134_dev *dev); int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); diff --git a/drivers/media/video/sn9c102/Makefile b/drivers/media/video/sn9c102/Makefile index a56d16f69c71..7ecd5a90c7c9 100644 --- a/drivers/media/video/sn9c102/Makefile +++ b/drivers/media/video/sn9c102/Makefile @@ -3,6 +3,7 @@ sn9c102-objs := sn9c102_core.o \ sn9c102_hv7131r.o \ sn9c102_mi0343.o \ sn9c102_mi0360.o \ + sn9c102_mt9v111.o \ sn9c102_ov7630.o \ sn9c102_ov7660.o \ sn9c102_pas106b.o \ diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 511847912c48..c40ba3adab21 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -47,7 +47,7 @@ #define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia" #define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>" #define SN9C102_MODULE_LICENSE "GPL" -#define SN9C102_MODULE_VERSION "1:1.47" +#define SN9C102_MODULE_VERSION "1:1.47pre49" #define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47) /*****************************************************************************/ @@ -3322,7 +3322,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; - video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); @@ -3340,6 +3339,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor); + video_set_drvdata(cam->v4ldev, cam); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h index 916054faf9be..35223e0d7e49 100644 --- a/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -126,6 +126,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam); extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam); extern int sn9c102_probe_mi0343(struct sn9c102_device* cam); extern int sn9c102_probe_mi0360(struct sn9c102_device* cam); +extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam); extern int sn9c102_probe_ov7630(struct sn9c102_device* cam); extern int sn9c102_probe_ov7660(struct sn9c102_device* cam); extern int sn9c102_probe_pas106b(struct sn9c102_device* cam); @@ -144,6 +145,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ diff --git a/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/drivers/media/video/sn9c102/sn9c102_mt9v111.c new file mode 100644 index 000000000000..3b98ac3bbc38 --- /dev/null +++ b/drivers/media/video/sn9c102/sn9c102_mt9v111.c @@ -0,0 +1,259 @@ +/*************************************************************************** + * Plug-in for MT9V111 image sensor connected to the SN9C1xx PC Camera * + * Controllers * + * * + * Copyright (C) 2007 by Luca Risolia <luca.risolia@studio.unibo.it> * + * * + * 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 "sn9c102_sensor.h" + + +static int mt9v111_init(struct sn9c102_device *cam) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + + err = sn9c102_write_const_regs(cam, {0x44, 0x01}, {0x40, 0x02}, + {0x00, 0x03}, {0x1a, 0x04}, + {0x1f, 0x05}, {0x20, 0x06}, + {0x1f, 0x07}, {0x81, 0x08}, + {0x5c, 0x09}, {0x00, 0x0a}, + {0x00, 0x0b}, {0x00, 0x0c}, + {0x00, 0x0d}, {0x00, 0x0e}, + {0x00, 0x0f}, {0x03, 0x10}, + {0x00, 0x11}, {0x00, 0x12}, + {0x02, 0x13}, {0x14, 0x14}, + {0x28, 0x15}, {0x1e, 0x16}, + {0xe2, 0x17}, {0x06, 0x18}, + {0x00, 0x19}, {0x00, 0x1a}, + {0x00, 0x1b}, {0x08, 0x20}, + {0x39, 0x21}, {0x51, 0x22}, + {0x63, 0x23}, {0x73, 0x24}, + {0x82, 0x25}, {0x8f, 0x26}, + {0x9b, 0x27}, {0xa7, 0x28}, + {0xb1, 0x29}, {0xbc, 0x2a}, + {0xc6, 0x2b}, {0xcf, 0x2c}, + {0xd8, 0x2d}, {0xe1, 0x2e}, + {0xea, 0x2f}, {0xf2, 0x30}, + {0x13, 0x84}, {0x00, 0x85}, + {0x25, 0x86}, {0x00, 0x87}, + {0x07, 0x88}, {0x00, 0x89}, + {0xee, 0x8a}, {0x0f, 0x8b}, + {0xe5, 0x8c}, {0x0f, 0x8d}, + {0x2e, 0x8e}, {0x00, 0x8f}, + {0x30, 0x90}, {0x00, 0x91}, + {0xd4, 0x92}, {0x0f, 0x93}, + {0xfc, 0x94}, {0x0f, 0x95}, + {0x14, 0x96}, {0x00, 0x97}, + {0x00, 0x98}, {0x60, 0x99}, + {0x07, 0x9a}, {0x40, 0x9b}, + {0x20, 0x9c}, {0x00, 0x9d}, + {0x00, 0x9e}, {0x00, 0x9f}, + {0x2d, 0xc0}, {0x2d, 0xc1}, + {0x3a, 0xc2}, {0x05, 0xc3}, + {0x04, 0xc4}, {0x3f, 0xc5}, + {0x00, 0xc6}, {0x00, 0xc7}, + {0x50, 0xc8}, {0x3c, 0xc9}, + {0x28, 0xca}, {0xd8, 0xcb}, + {0x14, 0xcc}, {0xec, 0xcd}, + {0x32, 0xce}, {0xdd, 0xcf}, + {0x2d, 0xd0}, {0xdd, 0xd1}, + {0x6a, 0xd2}, {0x50, 0xd3}, + {0x60, 0xd4}, {0x00, 0xd5}, + {0x00, 0xd6}); + + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x01, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0d, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, + 0x04, 0x80, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x04, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x08, + 0x00, 0x08, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x02, + 0x00, 0x16, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x03, + 0x01, 0xe7, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x04, + 0x02, 0x87, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x06, + 0x00, 0x40, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x05, + 0x00, 0x09, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x07, + 0x30, 0x02, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x0c, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x12, + 0x00, 0xb0, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x13, + 0x00, 0x7c, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x1e, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x20, + 0x00, 0x00, 0, 0); + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, 0x01, + 0x00, 0x04, 0, 0); + + return err; +} + +static int mt9v111_get_ctrl(struct sn9c102_device *cam, + struct v4l2_control *ctrl) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + u8 data[2]; + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (sn9c102_i2c_try_raw_read(cam, s, s->i2c_slave_id, 0x20, 2, + data) < 0) + return -EIO; + ctrl->value = data[1] & 0x80 ? 1 : 0; + return 0; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + +static int mt9v111_set_ctrl(struct sn9c102_device *cam, + const struct v4l2_control *ctrl) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + err += sn9c102_i2c_try_raw_write(cam, s, 4, s->i2c_slave_id, + 0x20, + ctrl->value ? 0x80 : 0x00, + ctrl->value ? 0x80 : 0x00, 0, + 0); + break; + default: + return -EINVAL; + } + + return err ? -EIO : 0; +} + +static int mt9v111_set_crop(struct sn9c102_device *cam, + const struct v4l2_rect *rect) +{ + struct sn9c102_sensor *s = sn9c102_get_sensor(cam); + int err = 0; + u8 v_start = (u8) (rect->top - s->cropcap.bounds.top) + 2; + + err += sn9c102_write_reg(cam, v_start, 0x13); + + return err; +} + +static int mt9v111_set_pix_format(struct sn9c102_device *cam, + const struct v4l2_pix_format *pix) +{ + int err = 0; + + if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) { + err += sn9c102_write_reg(cam, 0xb4, 0x17); + } else { + err += sn9c102_write_reg(cam, 0xe2, 0x17); + } + + return err; +} + + +static const struct sn9c102_sensor mt9v111 = { + .name = "MT9V111", + .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>", + .supported_bridge = BRIDGE_SN9C105 | BRIDGE_SN9C120, + .frequency = SN9C102_I2C_100KHZ, + .interface = SN9C102_I2C_2WIRES, + .i2c_slave_id = 0x5c, + .init = &mt9v111_init, + .qctrl = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "vertical mirror", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + .flags = 0, + }, + }, + .get_ctrl = &mt9v111_get_ctrl, + .set_ctrl = &mt9v111_set_ctrl, + .cropcap = { + .bounds = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + .defrect = { + .left = 0, + .top = 0, + .width = 640, + .height = 480, + }, + }, + .set_crop = &mt9v111_set_crop, + .pix_format = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .priv = 8, + }, + .set_pix_format = &mt9v111_set_pix_format +}; + + +int sn9c102_probe_mt9v111(struct sn9c102_device *cam) +{ + u8 data[2]; + int err = 0; + + err += sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1}, + {0x29, 0x01}, {0x42, 0x17}, + {0x62, 0x17}, {0x08, 0x01}); + err += sn9c102_i2c_try_raw_write(cam, &mt9v111, 4, + mt9v111.i2c_slave_id, 0x01, 0x00, + 0x04, 0, 0); + if (err || sn9c102_i2c_try_raw_read(cam, &mt9v111, + mt9v111.i2c_slave_id, 0x36, 2, + data) < 0) + return -EIO; + + if (data[0] != 0x82 || data[1] != 0x3a) + return -ENODEV; + + sn9c102_attach_sensor(cam, &mt9v111); + + return 0; +} diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c new file mode 100644 index 000000000000..4a9a0b62efa3 --- /dev/null +++ b/drivers/media/video/stk-sensor.c @@ -0,0 +1,578 @@ +/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams) + * + * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> + * + * Some parts derived from ov7670.c: + * Copyright 2006 One Laptop Per Child Association, Inc. Written + * by Jonathan Corbet with substantial inspiration from Mark + * McClelland's ovcamchip code. + * + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> + * + * This file may be distributed under the terms of the GNU General + * 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. + */ + +/* Controlling the sensor via the STK1125 vendor specific control interface: + * The camera uses an OmniVision sensor and the stk1125 provides an + * SCCB(i2c)-USB bridge which let us program the sensor. + * In my case the sensor id is 0x9652, it can be read from sensor's register + * 0x0A and 0x0B as follows: + * - read register #R: + * output #R to index 0x0208 + * output 0x0070 to index 0x0200 + * input 1 byte from index 0x0201 (some kind of status register) + * until its value is 0x01 + * input 1 byte from index 0x0209. This is the value of #R + * - write value V to register #R + * output #R to index 0x0204 + * output V to index 0x0205 + * output 0x0005 to index 0x0200 + * input 1 byte from index 0x0201 until its value becomes 0x04 + */ + +/* It seems the i2c bus is controlled with these registers */ + +#include "stk-webcam.h" + +#define STK_IIC_BASE (0x0200) +# define STK_IIC_OP (STK_IIC_BASE) +# define STK_IIC_OP_TX (0x05) +# define STK_IIC_OP_RX (0x70) +# define STK_IIC_STAT (STK_IIC_BASE+1) +# define STK_IIC_STAT_TX_OK (0x04) +# define STK_IIC_STAT_RX_OK (0x01) +/* I don't know what does this register. + * when it is 0x00 or 0x01, we cannot talk to the sensor, + * other values work */ +# define STK_IIC_ENABLE (STK_IIC_BASE+2) +# define STK_IIC_ENABLE_NO (0x00) +/* This is what the driver writes in windows */ +# define STK_IIC_ENABLE_YES (0x1e) +/* + * Address of the slave. Seems like the binary driver look for the + * sensor in multiple places, attempting a reset sequence. + * We only know about the ov9650 + */ +# define STK_IIC_ADDR (STK_IIC_BASE+3) +# define STK_IIC_TX_INDEX (STK_IIC_BASE+4) +# define STK_IIC_TX_VALUE (STK_IIC_BASE+5) +# define STK_IIC_RX_INDEX (STK_IIC_BASE+8) +# define STK_IIC_RX_VALUE (STK_IIC_BASE+9) + +#define MAX_RETRIES (50) + +#define SENSOR_ADDRESS (0x60) + +/* From ov7670.c (These registers aren't fully accurate) */ + +/* Registers */ +#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ +#define REG_BLUE 0x01 /* blue gain */ +#define REG_RED 0x02 /* red gain */ +#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */ +#define REG_COM1 0x04 /* Control 1 */ +#define COM1_CCIR656 0x40 /* CCIR656 enable */ +#define COM1_QFMT 0x20 /* QVGA/QCIF format */ +#define COM1_SKIP_0 0x00 /* Do not skip any row */ +#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */ +#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */ +#define REG_BAVE 0x05 /* U/B Average level */ +#define REG_GbAVE 0x06 /* Y/Gb Average level */ +#define REG_AECHH 0x07 /* AEC MS 5 bits */ +#define REG_RAVE 0x08 /* V/R Average level */ +#define REG_COM2 0x09 /* Control 2 */ +#define COM2_SSLEEP 0x10 /* Soft sleep mode */ +#define REG_PID 0x0a /* Product ID MSB */ +#define REG_VER 0x0b /* Product ID LSB */ +#define REG_COM3 0x0c /* Control 3 */ +#define COM3_SWAP 0x40 /* Byte swap */ +#define COM3_SCALEEN 0x08 /* Enable scaling */ +#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */ +#define REG_COM4 0x0d /* Control 4 */ +#define REG_COM5 0x0e /* All "reserved" */ +#define REG_COM6 0x0f /* Control 6 */ +#define REG_AECH 0x10 /* More bits of AEC value */ +#define REG_CLKRC 0x11 /* Clock control */ +#define CLK_PLL 0x80 /* Enable internal PLL */ +#define CLK_EXT 0x40 /* Use external clock directly */ +#define CLK_SCALE 0x3f /* Mask for internal clock scale */ +#define REG_COM7 0x12 /* Control 7 */ +#define COM7_RESET 0x80 /* Register reset */ +#define COM7_FMT_MASK 0x38 +#define COM7_FMT_SXGA 0x00 +#define COM7_FMT_VGA 0x40 +#define COM7_FMT_CIF 0x20 /* CIF format */ +#define COM7_FMT_QVGA 0x10 /* QVGA format */ +#define COM7_FMT_QCIF 0x08 /* QCIF format */ +#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */ +#define COM7_YUV 0x00 /* YUV */ +#define COM7_BAYER 0x01 /* Bayer format */ +#define COM7_PBAYER 0x05 /* "Processed bayer" */ +#define REG_COM8 0x13 /* Control 8 */ +#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */ +#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */ +#define COM8_BFILT 0x20 /* Band filter enable */ +#define COM8_AGC 0x04 /* Auto gain enable */ +#define COM8_AWB 0x02 /* White balance enable */ +#define COM8_AEC 0x01 /* Auto exposure enable */ +#define REG_COM9 0x14 /* Control 9 - gain ceiling */ +#define REG_COM10 0x15 /* Control 10 */ +#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */ +#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */ +#define COM10_HREF_REV 0x08 /* Reverse HREF */ +#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */ +#define COM10_VS_NEG 0x02 /* VSYNC negative */ +#define COM10_HS_NEG 0x01 /* HSYNC negative */ +#define REG_HSTART 0x17 /* Horiz start high bits */ +#define REG_HSTOP 0x18 /* Horiz stop high bits */ +#define REG_VSTART 0x19 /* Vert start high bits */ +#define REG_VSTOP 0x1a /* Vert stop high bits */ +#define REG_PSHFT 0x1b /* Pixel delay after HREF */ +#define REG_MIDH 0x1c /* Manuf. ID high */ +#define REG_MIDL 0x1d /* Manuf. ID low */ +#define REG_MVFP 0x1e /* Mirror / vflip */ +#define MVFP_MIRROR 0x20 /* Mirror image */ +#define MVFP_FLIP 0x10 /* Vertical flip */ + +#define REG_AEW 0x24 /* AGC upper limit */ +#define REG_AEB 0x25 /* AGC lower limit */ +#define REG_VPT 0x26 /* AGC/AEC fast mode op region */ +#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */ +#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */ +#define REG_HSYST 0x30 /* HSYNC rising edge delay */ +#define REG_HSYEN 0x31 /* HSYNC falling edge delay */ +#define REG_HREF 0x32 /* HREF pieces */ +#define REG_TSLB 0x3a /* lots of stuff */ +#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */ +#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */ +#define REG_COM11 0x3b /* Control 11 */ +#define COM11_NIGHT 0x80 /* NIght mode enable */ +#define COM11_NMFR 0x60 /* Two bit NM frame rate */ +#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */ +#define COM11_50HZ 0x08 /* Manual 50Hz select */ +#define COM11_EXP 0x02 +#define REG_COM12 0x3c /* Control 12 */ +#define COM12_HREF 0x80 /* HREF always */ +#define REG_COM13 0x3d /* Control 13 */ +#define COM13_GAMMA 0x80 /* Gamma enable */ +#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */ +#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */ +#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */ +#define REG_COM14 0x3e /* Control 14 */ +#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */ +#define REG_EDGE 0x3f /* Edge enhancement factor */ +#define REG_COM15 0x40 /* Control 15 */ +#define COM15_R10F0 0x00 /* Data range 10 to F0 */ +#define COM15_R01FE 0x80 /* 01 to FE */ +#define COM15_R00FF 0xc0 /* 00 to FF */ +#define COM15_RGB565 0x10 /* RGB565 output */ +#define COM15_RGBFIXME 0x20 /* FIXME */ +#define COM15_RGB555 0x30 /* RGB555 output */ +#define REG_COM16 0x41 /* Control 16 */ +#define COM16_AWBGAIN 0x08 /* AWB gain enable */ +#define REG_COM17 0x42 /* Control 17 */ +#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ +#define COM17_CBAR 0x08 /* DSP Color bar */ + +/* + * This matrix defines how the colors are generated, must be + * tweaked to adjust hue and saturation. + * + * Order: v-red, v-green, v-blue, u-red, u-green, u-blue + * + * They are nine-bit signed quantities, with the sign bit + * stored in 0x58. Sign for v-red is bit 0, and up from there. + */ +#define REG_CMATRIX_BASE 0x4f +#define CMATRIX_LEN 6 +#define REG_CMATRIX_SIGN 0x58 + + +#define REG_BRIGHT 0x55 /* Brightness */ +#define REG_CONTRAS 0x56 /* Contrast control */ + +#define REG_GFIX 0x69 /* Fix gain control */ + +#define REG_RGB444 0x8c /* RGB 444 control */ +#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */ +#define R444_RGBX 0x01 /* Empty nibble at end */ + +#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */ +#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */ + +#define REG_BD50MAX 0xa5 /* 50hz banding step limit */ +#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */ +#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */ +#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */ +#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */ +#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ +#define REG_BD60MAX 0xab /* 60hz banding step limit */ + + + + +/* Returns 0 if OK */ +int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) +{ + int i = 0; + int tmpval = 0; + + if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) + return 1; + if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val)) + return 1; + if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX)) + return 1; + do { + if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) + return 1; + i++; + } while (tmpval == 0 && i < MAX_RETRIES); + if (tmpval != STK_IIC_STAT_TX_OK) { + if (tmpval) + STK_ERROR("stk_sensor_outb failed, status=0x%02x\n", + tmpval); + return 1; + } else + return 0; +} + +int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) +{ + int i = 0; + int tmpval = 0; + + if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) + return 1; + if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX)) + return 1; + do { + if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval)) + return 1; + i++; + } while (tmpval == 0 && i < MAX_RETRIES); + if (tmpval != STK_IIC_STAT_RX_OK) { + if (tmpval) + STK_ERROR("stk_sensor_inb failed, status=0x%02x\n", + tmpval); + return 1; + } + + if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) + return 1; + + *val = (u8) tmpval; + return 0; +} + +static int stk_sensor_write_regvals(struct stk_camera *dev, + struct regval *rv) +{ + int ret; + if (rv == NULL) + return 0; + while (rv->reg != 0xff || rv->val != 0xff) { + ret = stk_sensor_outb(dev, rv->reg, rv->val); + if (ret != 0) + return ret; + rv++; + } + return 0; +} + +int stk_sensor_sleep(struct stk_camera *dev) +{ + u8 tmp; + return stk_sensor_inb(dev, REG_COM2, &tmp) + || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP); +} + +int stk_sensor_wakeup(struct stk_camera *dev) +{ + u8 tmp; + return stk_sensor_inb(dev, REG_COM2, &tmp) + || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP); +} + +static struct regval ov_initvals[] = { + {REG_CLKRC, CLK_PLL}, + {REG_COM11, 0x01}, + {0x6a, 0x7d}, + {REG_AECH, 0x40}, + {REG_GAIN, 0x00}, + {REG_BLUE, 0x80}, + {REG_RED, 0x80}, + /* Do not enable fast AEC for now */ + /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/ + {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC}, + {0x39, 0x50}, {0x38, 0x93}, + {0x37, 0x00}, {0x35, 0x81}, + {REG_COM5, 0x20}, + {REG_COM1, 0x00}, + {REG_COM3, 0x00}, + {REG_COM4, 0x00}, + {REG_PSHFT, 0x00}, + {0x16, 0x07}, + {0x33, 0xe2}, {0x34, 0xbf}, + {REG_COM16, 0x00}, + {0x96, 0x04}, + /* Gamma curve values */ +/* { 0x7a, 0x20 }, { 0x7b, 0x10 }, + { 0x7c, 0x1e }, { 0x7d, 0x35 }, + { 0x7e, 0x5a }, { 0x7f, 0x69 }, + { 0x80, 0x76 }, { 0x81, 0x80 }, + { 0x82, 0x88 }, { 0x83, 0x8f }, + { 0x84, 0x96 }, { 0x85, 0xa3 }, + { 0x86, 0xaf }, { 0x87, 0xc4 }, + { 0x88, 0xd7 }, { 0x89, 0xe8 }, +*/ + {REG_GFIX, 0x40}, + {0x8e, 0x00}, + {REG_COM12, 0x73}, + {0x8f, 0xdf}, {0x8b, 0x06}, + {0x8c, 0x20}, + {0x94, 0x88}, {0x95, 0x88}, +/* {REG_COM15, 0xc1}, TODO */ + {0x29, 0x3f}, + {REG_COM6, 0x42}, + {REG_BD50MAX, 0x80}, + {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92}, + {REG_BD60MAX, 0x0a}, + {0x90, 0x00}, {0x91, 0x00}, + {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00}, + {REG_AEW, 0x68}, {REG_AEB, 0x5c}, + {REG_VPT, 0xc3}, + {REG_COM9, 0x2e}, + {0x2a, 0x00}, {0x2b, 0x00}, + + {0xff, 0xff}, /* END MARKER */ +}; + +/* Probe the I2C bus and initialise the sensor chip */ +int stk_sensor_init(struct stk_camera *dev) +{ + u8 idl = 0; + u8 idh = 0; + + if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES) + || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS) + || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) { + STK_ERROR("Sensor resetting failed\n"); + return -ENODEV; + } + msleep(10); + /* Read the manufacturer ID: ov = 0x7FA2 */ + if (stk_sensor_inb(dev, REG_MIDH, &idh) + || stk_sensor_inb(dev, REG_MIDL, &idl)) { + STK_ERROR("Strange error reading sensor ID\n"); + return -ENODEV; + } + if (idh != 0x7F || idl != 0xA2) { + STK_ERROR("Huh? you don't have a sensor from ovt\n"); + return -ENODEV; + } + if (stk_sensor_inb(dev, REG_PID, &idh) + || stk_sensor_inb(dev, REG_VER, &idl)) { + STK_ERROR("Could not read sensor model\n"); + return -ENODEV; + } + stk_sensor_write_regvals(dev, ov_initvals); + msleep(10); + STK_INFO("OmniVision sensor detected, id %02X%02X" + " at address %x\n", idh, idl, SENSOR_ADDRESS); + return 0; +} + +/* V4L2_PIX_FMT_UYVY */ +static struct regval ov_fmt_uyvy[] = { + {REG_TSLB, TSLB_YLAST|0x08 }, + { 0x4f, 0x80 }, /* "matrix coefficient 1" */ + { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x22 }, /* "matrix coefficient 4" */ + { 0x53, 0x5e }, /* "matrix coefficient 5" */ + { 0x54, 0x80 }, /* "matrix coefficient 6" */ + {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, + {REG_COM15, COM15_R00FF }, + {0xff, 0xff}, /* END MARKER */ +}; + +/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */ +static struct regval ov_fmt_rgbr[] = { + { REG_RGB444, 0 }, /* No RGB444 please */ + {REG_TSLB, 0x00}, + { REG_COM1, 0x0 }, + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { REG_COM13, COM13_GAMMA }, + { REG_COM15, COM15_RGB565|COM15_R00FF }, + { 0xff, 0xff }, +}; + +/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */ +static struct regval ov_fmt_rgbp[] = { + { REG_RGB444, 0 }, /* No RGB444 please */ + {REG_TSLB, TSLB_BYTEORD }, + { REG_COM1, 0x0 }, + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { REG_COM13, COM13_GAMMA }, + { REG_COM15, COM15_RGB565|COM15_R00FF }, + { 0xff, 0xff }, +}; + +/* V4L2_PIX_FMT_SRGGB8 */ +static struct regval ov_fmt_bayer[] = { + /* This changes color order */ + {REG_TSLB, 0x40}, /* BGGR */ + /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */ + {REG_COM15, COM15_R00FF }, + {0xff, 0xff}, /* END MARKER */ +}; +/* + * Store a set of start/stop values into the camera. + */ +static int stk_sensor_set_hw(struct stk_camera *dev, + int hstart, int hstop, int vstart, int vstop) +{ + int ret; + unsigned char v; +/* + * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of + * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is + * a mystery "edge offset" value in the top two bits of href. + */ + ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff); + ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff); + ret += stk_sensor_inb(dev, REG_HREF, &v); + v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); + msleep(10); + ret += stk_sensor_outb(dev, REG_HREF, v); +/* + * Vertical: similar arrangement (note: this is different from ov7670.c) + */ + ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff); + ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff); + ret += stk_sensor_inb(dev, REG_VREF, &v); + v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7); + msleep(10); + ret += stk_sensor_outb(dev, REG_VREF, v); + return ret; +} + + +int stk_sensor_configure(struct stk_camera *dev) +{ + int com7; + /* + * We setup the sensor to output dummy lines in low-res modes, + * so we don't get absurdly hight framerates. + */ + unsigned dummylines; + int flip; + struct regval *rv; + + switch (dev->vsettings.mode) { + case MODE_QCIF: com7 = COM7_FMT_QCIF; + dummylines = 604; + break; + case MODE_QVGA: com7 = COM7_FMT_QVGA; + dummylines = 267; + break; + case MODE_CIF: com7 = COM7_FMT_CIF; + dummylines = 412; + break; + case MODE_VGA: com7 = COM7_FMT_VGA; + dummylines = 11; + break; + case MODE_SXGA: com7 = COM7_FMT_SXGA; + dummylines = 0; + break; + default: STK_ERROR("Unsupported mode %d\n", dev->vsettings.mode); + return -EFAULT; + } + switch (dev->vsettings.palette) { + case V4L2_PIX_FMT_UYVY: + com7 |= COM7_YUV; + rv = ov_fmt_uyvy; + break; + case V4L2_PIX_FMT_RGB565: + com7 |= COM7_RGB; + rv = ov_fmt_rgbp; + break; + case V4L2_PIX_FMT_RGB565X: + com7 |= COM7_RGB; + rv = ov_fmt_rgbr; + break; + case V4L2_PIX_FMT_SBGGR8: + com7 |= COM7_PBAYER; + rv = ov_fmt_bayer; + break; + default: STK_ERROR("Unsupported colorspace\n"); + return -EFAULT; + } + /*FIXME sometimes the sensor go to a bad state + stk_sensor_write_regvals(dev, ov_initvals); */ + stk_sensor_outb(dev, REG_COM7, com7); + msleep(50); + stk_sensor_write_regvals(dev, rv); + flip = (dev->vsettings.vflip?MVFP_FLIP:0) + | (dev->vsettings.hflip?MVFP_MIRROR:0); + stk_sensor_outb(dev, REG_MVFP, flip); + if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8 + && !dev->vsettings.vflip) + stk_sensor_outb(dev, REG_TSLB, 0x08); + stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8); + stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff); + msleep(50); + switch (dev->vsettings.mode) { + case MODE_VGA: + if (stk_sensor_set_hw(dev, 302, 1582, 6, 486)) + STK_ERROR("stk_sensor_set_hw failed (VGA)\n"); + break; + case MODE_SXGA: + case MODE_CIF: + case MODE_QVGA: + case MODE_QCIF: + /*FIXME These settings seem ignored by the sensor + if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034)) + STK_ERROR("stk_sensor_set_hw failed (SXGA)\n"); + */ + break; + } + msleep(10); + return 0; +} + +int stk_sensor_set_brightness(struct stk_camera *dev, int br) +{ + if (br < 0 || br > 0xff) + return -EINVAL; + stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6)); + stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6)); + return 0; +} + diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c new file mode 100644 index 000000000000..d37e5e2594b4 --- /dev/null +++ b/drivers/media/video/stk-webcam.c @@ -0,0 +1,1465 @@ +/* + * stk-webcam.c : Driver for Syntek 1125 USB webcam controller + * + * Copyright (C) 2006 Nicolas VIVIEN + * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> + * + * Some parts are inspired from cafe_ccic.c + * Copyright 2006-2007 Jonathan Corbet + * + * 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 + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/kref.h> + +#include <linux/usb.h> +#include <linux/vmalloc.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> + +#include "stk-webcam.h" + + +static int hflip = 1; +module_param(hflip, bool, 0444); +MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1"); + +static int vflip = 1; +module_param(vflip, bool, 0444); +MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1"); + +static int debug; +module_param(debug, int, 0444); +MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN"); +MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); + + + +/* Some cameras have audio interfaces, we aren't interested in those */ +static struct usb_device_id stkwebcam_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) }, + { } +}; +MODULE_DEVICE_TABLE(usb, stkwebcam_table); + +void stk_camera_cleanup(struct kref *kref) +{ + struct stk_camera *dev = to_stk_camera(kref); + + STK_INFO("Syntek USB2.0 Camera release resources" + " video device /dev/video%d\n", dev->vdev.minor); + video_unregister_device(&dev->vdev); + dev->vdev.priv = NULL; + + if (dev->sio_bufs != NULL || dev->isobufs != NULL) + STK_ERROR("We are leaking memory\n"); + usb_put_intf(dev->interface); + kfree(dev); +} + + +/* + * Basic stuff + */ +int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) +{ + struct usb_device *udev = dev->udev; + int ret; + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x01, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, + index, + NULL, + 0, + 500); + if (ret < 0) + return ret; + else + return 0; +} + +int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) +{ + struct usb_device *udev = dev->udev; + int ret; + + ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x00, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0x00, + index, + (u8 *) value, + sizeof(u8), + 500); + if (ret < 0) + return ret; + else + return 0; +} + +static int stk_start_stream(struct stk_camera *dev) +{ + int value; + int i, ret; + int value_116, value_117; + + if (!is_present(dev)) + return -ENODEV; + if (!is_memallocd(dev) || !is_initialised(dev)) { + STK_ERROR("FIXME: Buffers are not allocated\n"); + return -EFAULT; + } + ret = usb_set_interface(dev->udev, 0, 5); + + if (ret < 0) + STK_ERROR("usb_set_interface failed !\n"); + if (stk_sensor_wakeup(dev)) + STK_ERROR("error awaking the sensor\n"); + + stk_camera_read_reg(dev, 0x0116, &value_116); + stk_camera_read_reg(dev, 0x0117, &value_117); + + stk_camera_write_reg(dev, 0x0116, 0x0000); + stk_camera_write_reg(dev, 0x0117, 0x0000); + + stk_camera_read_reg(dev, 0x0100, &value); + stk_camera_write_reg(dev, 0x0100, value | 0x80); + + stk_camera_write_reg(dev, 0x0116, value_116); + stk_camera_write_reg(dev, 0x0117, value_117); + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (dev->isobufs[i].urb) { + ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL); + atomic_inc(&dev->urbs_used); + if (ret) + return ret; + } + } + set_streaming(dev); + return 0; +} + +static int stk_stop_stream(struct stk_camera *dev) +{ + int value; + int i; + if (is_present(dev)) { + stk_camera_read_reg(dev, 0x0100, &value); + stk_camera_write_reg(dev, 0x0100, value & ~0x80); + if (dev->isobufs != NULL) { + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (dev->isobufs[i].urb) + usb_kill_urb(dev->isobufs[i].urb); + } + } + unset_streaming(dev); + + if (usb_set_interface(dev->udev, 0, 0)) + STK_ERROR("usb_set_interface failed !\n"); + if (stk_sensor_sleep(dev)) + STK_ERROR("error suspending the sensor\n"); + } + return 0; +} + +/* + * This seems to be the shortest init sequence we + * must do in order to find the sensor + * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor + * is also reset. Maybe powers down it? + * Rest of values don't make a difference + */ + +static struct regval stk1125_initvals[] = { + /*TODO: What means this sequence? */ + {0x0000, 0x24}, + {0x0100, 0x21}, + {0x0002, 0x68}, + {0x0003, 0x80}, + {0x0005, 0x00}, + {0x0007, 0x03}, + {0x000d, 0x00}, + {0x000f, 0x02}, + {0x0300, 0x12}, + {0x0350, 0x41}, + {0x0351, 0x00}, + {0x0352, 0x00}, + {0x0353, 0x00}, + {0x0018, 0x10}, + {0x0019, 0x00}, + {0x001b, 0x0e}, + {0x001c, 0x46}, + {0x0300, 0x80}, + {0x001a, 0x04}, + {0x0110, 0x00}, + {0x0111, 0x00}, + {0x0112, 0x00}, + {0x0113, 0x00}, + + {0xffff, 0xff}, +}; + + +static int stk_initialise(struct stk_camera *dev) +{ + struct regval *rv; + int ret; + if (!is_present(dev)) + return -ENODEV; + if (is_initialised(dev)) + return 0; + rv = stk1125_initvals; + while (rv->reg != 0xffff) { + ret = stk_camera_write_reg(dev, rv->reg, rv->val); + if (ret) + return ret; + rv++; + } + if (stk_sensor_init(dev) == 0) { + set_initialised(dev); + return 0; + } else + return -1; +} + +/* sysfs functions */ +/*FIXME cleanup this */ + +static ssize_t show_brightness(struct device *class, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + return sprintf(buf, "%X\n", dev->vsettings.brightness); +} + +static ssize_t store_brightness(struct device *class, + struct device_attribute *attr, const char *buf, size_t count) +{ + char *endp; + unsigned long value; + int ret; + + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + value = simple_strtoul(buf, &endp, 16); + + dev->vsettings.brightness = (int) value; + + ret = stk_sensor_set_brightness(dev, value >> 8); + if (ret) + return ret; + else + return count; +} + +static ssize_t show_hflip(struct device *class, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + return sprintf(buf, "%d\n", dev->vsettings.hflip); +} + +static ssize_t store_hflip(struct device *class, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + if (strncmp(buf, "1", 1) == 0) + dev->vsettings.hflip = 1; + else if (strncmp(buf, "0", 1) == 0) + dev->vsettings.hflip = 0; + else + return -EINVAL; + + return strlen(buf); +} + +static ssize_t show_vflip(struct device *class, + struct device_attribute *attr, char *buf) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + return sprintf(buf, "%d\n", dev->vsettings.vflip); +} + +static ssize_t store_vflip(struct device *class, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct video_device *vdev = to_video_device(class); + struct stk_camera *dev = vdev_to_camera(vdev); + + if (strncmp(buf, "1", 1) == 0) + dev->vsettings.vflip = 1; + else if (strncmp(buf, "0", 1) == 0) + dev->vsettings.vflip = 0; + else + return -EINVAL; + + return strlen(buf); +} + +static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO, + show_brightness, store_brightness); +static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip); +static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip); + +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); + 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); +} + + +/* *********************************************** */ +/* + * This function is called as an URB transfert is complete (Isochronous pipe). + * So, the traitement is done in interrupt time, so it has be fast, not crash, + * and not stall. Neat. + */ +static void stk_isoc_handler(struct urb *urb) +{ + int i; + int ret; + int framelen; + unsigned long flags; + + unsigned char *fill = NULL; + unsigned char *iso_buf = NULL; + + struct stk_camera *dev; + struct stk_sio_buffer *fb; + + dev = (struct stk_camera *) urb->context; + + if (dev == NULL) { + STK_ERROR("isoc_handler called with NULL device !\n"); + return; + } + + if (urb->status == -ENOENT || urb->status == -ECONNRESET + || urb->status == -ESHUTDOWN) { + atomic_dec(&dev->urbs_used); + return; + } + + spin_lock_irqsave(&dev->spinlock, flags); + + if (urb->status != -EINPROGRESS && urb->status != 0) { + STK_ERROR("isoc_handler: urb->status == %d\n", urb->status); + goto resubmit; + } + + if (list_empty(&dev->sio_avail)) { + /*FIXME Stop streaming after a while */ + (void) (printk_ratelimit() && + STK_ERROR("isoc_handler without available buffer!\n")); + goto resubmit; + } + fb = list_first_entry(&dev->sio_avail, + struct stk_sio_buffer, list); + fill = fb->buffer + fb->v4lbuf.bytesused; + + for (i = 0; i < urb->number_of_packets; i++) { + if (urb->iso_frame_desc[i].status != 0) { + if (urb->iso_frame_desc[i].status != -EXDEV) + STK_ERROR("Frame %d has error %d\n", i, + urb->iso_frame_desc[i].status); + continue; + } + framelen = urb->iso_frame_desc[i].actual_length; + iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (framelen <= 4) + continue; /* no data */ + + /* + * we found something informational from there + * the isoc frames have to type of headers + * type1: 00 xx 00 00 or 20 xx 00 00 + * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00 + * xx is a sequencer which has never been seen over 0x3f + * imho data written down looks like bayer, i see similarities + * after every 640 bytes + */ + if (*iso_buf & 0x80) { + framelen -= 8; + iso_buf += 8; + /* This marks a new frame */ + if (fb->v4lbuf.bytesused != 0 + && fb->v4lbuf.bytesused != dev->frame_size) { + (void) (printk_ratelimit() && + STK_ERROR("frame %d, " + "bytesused=%d, skipping\n", + i, fb->v4lbuf.bytesused)); + 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; + } + fb = list_first_entry(&dev->sio_avail, + struct stk_sio_buffer, list); + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; + } + } else { + framelen -= 4; + iso_buf += 4; + } + + /* Our buffer is full !!! */ + if (framelen + fb->v4lbuf.bytesused > dev->frame_size) { + (void) (printk_ratelimit() && + STK_ERROR("Frame buffer overflow, lost sync\n")); + /*FIXME Do something here? */ + continue; + } + spin_unlock_irqrestore(&dev->spinlock, flags); + memcpy(fill, iso_buf, framelen); + spin_lock_irqsave(&dev->spinlock, flags); + fill += framelen; + + /* New size of our buffer */ + fb->v4lbuf.bytesused += framelen; + } + +resubmit: + spin_unlock_irqrestore(&dev->spinlock, flags); + urb->dev = dev->udev; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret != 0) { + STK_ERROR("Error (%d) re-submitting urb in stk_isoc_handler.\n", + ret); + } +} + +/* -------------------------------------------- */ + +static int stk_prepare_iso(struct stk_camera *dev) +{ + void *kbuf; + int i, j; + struct urb *urb; + struct usb_device *udev; + + if (dev == NULL) + return -ENXIO; + udev = dev->udev; + + if (dev->isobufs) + STK_ERROR("isobufs already allocated. Bad\n"); + else + dev->isobufs = kzalloc(MAX_ISO_BUFS * sizeof(*dev->isobufs), + GFP_KERNEL); + if (dev->isobufs == NULL) { + STK_ERROR("Unable to allocate iso buffers\n"); + return -ENOMEM; + } + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (dev->isobufs[i].data == NULL) { + kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); + if (kbuf == NULL) { + STK_ERROR("Failed to allocate iso buffer %d\n", + i); + goto isobufs_out; + } + dev->isobufs[i].data = kbuf; + } else + STK_ERROR("isobuf data already allocated\n"); + if (dev->isobufs[i].urb == NULL) { + urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); + if (urb == NULL) { + STK_ERROR("Failed to allocate URB %d\n", i); + goto isobufs_out; + } + dev->isobufs[i].urb = urb; + } else { + STK_ERROR("Killing URB\n"); + usb_kill_urb(dev->isobufs[i].urb); + urb = dev->isobufs[i].urb; + } + urb->interval = 1; + urb->dev = udev; + urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = dev->isobufs[i].data; + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = stk_isoc_handler; + urb->context = dev; + urb->start_frame = 0; + urb->number_of_packets = ISO_FRAMES_PER_DESC; + + for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; + } + } + set_memallocd(dev); + return 0; + +isobufs_out: + for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++) + kfree(dev->isobufs[i].data); + for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++) + usb_free_urb(dev->isobufs[i].urb); + kfree(dev->isobufs); + dev->isobufs = NULL; + return -ENOMEM; +} + +static void stk_clean_iso(struct stk_camera *dev) +{ + int i; + + if (dev == NULL || dev->isobufs == NULL) + return; + + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = dev->isobufs[i].urb; + if (urb) { + if (atomic_read(&dev->urbs_used)) + usb_kill_urb(urb); + usb_free_urb(urb); + } + kfree(dev->isobufs[i].data); + } + kfree(dev->isobufs); + dev->isobufs = NULL; + unset_memallocd(dev); +} + +static int stk_setup_siobuf(struct stk_camera *dev, int index) +{ + struct stk_sio_buffer *buf = dev->sio_bufs + index; + INIT_LIST_HEAD(&buf->list); + buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size); + buf->buffer = vmalloc_user(buf->v4lbuf.length); + if (buf->buffer == NULL) + return -ENOMEM; + buf->mapcount = 0; + buf->dev = dev; + buf->v4lbuf.index = index; + buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf->v4lbuf.field = V4L2_FIELD_NONE; + buf->v4lbuf.memory = V4L2_MEMORY_MMAP; + buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length; + return 0; +} + +static int stk_free_sio_buffers(struct stk_camera *dev) +{ + int i; + int nbufs; + unsigned long flags; + if (dev->n_sbufs == 0 || dev->sio_bufs == NULL) + return 0; + /* + * If any buffers are mapped, we cannot free them at all. + */ + for (i = 0; i < dev->n_sbufs; i++) { + if (dev->sio_bufs[i].mapcount > 0) + return -EBUSY; + } + /* + * OK, let's do it. + */ + spin_lock_irqsave(&dev->spinlock, flags); + INIT_LIST_HEAD(&dev->sio_avail); + INIT_LIST_HEAD(&dev->sio_full); + nbufs = dev->n_sbufs; + dev->n_sbufs = 0; + spin_unlock_irqrestore(&dev->spinlock, flags); + for (i = 0; i < nbufs; i++) { + if (dev->sio_bufs[i].buffer != NULL) + vfree(dev->sio_bufs[i].buffer); + } + kfree(dev->sio_bufs); + dev->sio_bufs = NULL; + return 0; +} + +static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs) +{ + int i; + if (dev->sio_bufs != NULL) + STK_ERROR("sio_bufs already allocated\n"); + else { + dev->sio_bufs = kzalloc(n_sbufs * sizeof(struct stk_sio_buffer), + GFP_KERNEL); + if (dev->sio_bufs == NULL) + return -ENOMEM; + for (i = 0; i < n_sbufs; i++) { + if (stk_setup_siobuf(dev, i)) + return (dev->n_sbufs > 1)? 0 : -ENOMEM; + dev->n_sbufs = i+1; + } + } + return 0; +} + +static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs) +{ + int err; + err = stk_prepare_iso(dev); + if (err) { + stk_clean_iso(dev); + return err; + } + err = stk_prepare_sio_buffers(dev, n_sbufs); + if (err) { + stk_free_sio_buffers(dev); + return err; + } + return 0; +} + +static void stk_free_buffers(struct stk_camera *dev) +{ + stk_clean_iso(dev); + stk_free_sio_buffers(dev); +} +/* -------------------------------------------- */ + +/* v4l file operations */ + +static int v4l_stk_open(struct inode *inode, struct file *fp) +{ + struct stk_camera *dev; + struct video_device *vdev; + + vdev = video_devdata(fp); + dev = vdev_to_camera(vdev); + + if (dev == NULL || !is_present(dev)) + return -ENXIO; + fp->private_data = vdev; + kref_get(&dev->kref); + + return 0; +} + +static int v4l_stk_release(struct inode *inode, struct file *fp) +{ + struct stk_camera *dev; + struct video_device *vdev; + + vdev = video_devdata(fp); + if (vdev == NULL) { + STK_ERROR("v4l_release called w/o video devdata\n"); + return -EFAULT; + } + dev = vdev_to_camera(vdev); + if (dev == NULL) { + STK_ERROR("v4l_release called on removed device\n"); + return -ENODEV; + } + + if (dev->owner != fp) { + kref_put(&dev->kref, stk_camera_cleanup); + return 0; + } + + stk_stop_stream(dev); + + stk_free_buffers(dev); + + dev->owner = NULL; + + kref_put(&dev->kref, stk_camera_cleanup); + + return 0; +} + +static ssize_t v4l_stk_read(struct file *fp, char __user *buf, + size_t count, loff_t *f_pos) +{ + int i; + int ret; + unsigned long flags; + struct stk_camera *dev; + struct video_device *vdev; + struct stk_sio_buffer *sbuf; + + vdev = video_devdata(fp); + if (vdev == NULL) + return -EFAULT; + dev = vdev_to_camera(vdev); + + if (dev == NULL) + return -EIO; + + if (!is_present(dev)) + return -EIO; + if (dev->owner && dev->owner != fp) + return -EBUSY; + dev->owner = fp; + if (!is_streaming(dev)) { + if (stk_initialise(dev) + || stk_allocate_buffers(dev, 3) + || stk_start_stream(dev)) + return -ENOMEM; + spin_lock_irqsave(&dev->spinlock, flags); + for (i = 0; i < dev->n_sbufs; i++) { + list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); + dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED; + } + spin_unlock_irqrestore(&dev->spinlock, flags); + } + if (*f_pos == 0) { + if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) + return -EWOULDBLOCK; + ret = wait_event_interruptible(dev->wait_frame, + !list_empty(&dev->sio_full) || !is_present(dev)); + if (ret) + return ret; + if (!is_present(dev)) + return -EIO; + } + if (count + *f_pos > dev->frame_size) + count = dev->frame_size - *f_pos; + spin_lock_irqsave(&dev->spinlock, flags); + if (list_empty(&dev->sio_full)) { + spin_unlock_irqrestore(&dev->spinlock, flags); + STK_ERROR("BUG: No siobufs ready\n"); + return 0; + } + sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); + spin_unlock_irqrestore(&dev->spinlock, flags); + + if (copy_to_user(buf, sbuf->buffer + *f_pos, count)) + return -EFAULT; + + *f_pos += count; + + if (*f_pos >= dev->frame_size) { + *f_pos = 0; + spin_lock_irqsave(&dev->spinlock, flags); + list_move_tail(&sbuf->list, &dev->sio_avail); + spin_unlock_irqrestore(&dev->spinlock, flags); + } + return count; +} + +static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) +{ + struct stk_camera *dev; + struct video_device *vdev; + + vdev = video_devdata(fp); + + if (vdev == NULL) + return -EFAULT; + + dev = vdev_to_camera(vdev); + if (dev == NULL) + return -ENODEV; + + poll_wait(fp, &dev->wait_frame, wait); + + if (!is_present(dev)) + return POLLERR; + + if (!list_empty(&dev->sio_full)) + return (POLLIN | POLLRDNORM); + + return 0; +} + + +static void stk_v4l_vm_open(struct vm_area_struct *vma) +{ + struct stk_sio_buffer *sbuf = vma->vm_private_data; + sbuf->mapcount++; +} +static void stk_v4l_vm_close(struct vm_area_struct *vma) +{ + struct stk_sio_buffer *sbuf = vma->vm_private_data; + sbuf->mapcount--; + if (sbuf->mapcount == 0) + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED; +} +static struct vm_operations_struct stk_v4l_vm_ops = { + .open = stk_v4l_vm_open, + .close = stk_v4l_vm_close +}; + +static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) +{ + unsigned int i; + int ret; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + struct stk_camera *dev; + struct video_device *vdev; + struct stk_sio_buffer *sbuf = NULL; + + if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) + return -EINVAL; + + vdev = video_devdata(fp); + dev = vdev_to_camera(vdev); + + for (i = 0; i < dev->n_sbufs; i++) { + if (dev->sio_bufs[i].v4lbuf.m.offset == offset) { + sbuf = dev->sio_bufs + i; + break; + } + } + if (sbuf == NULL) + return -EINVAL; + ret = remap_vmalloc_range(vma, sbuf->buffer, 0); + if (ret) + return ret; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = sbuf; + vma->vm_ops = &stk_v4l_vm_ops; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED; + stk_v4l_vm_open(vma); + return 0; +} + +/* v4l ioctl handlers */ + +static int stk_vidioc_querycap(struct file *filp, + void *priv, struct v4l2_capability *cap) +{ + strcpy(cap->driver, "stk"); + strcpy(cap->card, "stk"); + cap->version = DRIVER_VERSION_NUM; + + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + return 0; +} + +static int stk_vidioc_enum_input(struct file *filp, + void *priv, struct v4l2_input *input) +{ + if (input->index != 0) + return -EINVAL; + + strcpy(input->name, "Syntek USB Camera"); + input->type = V4L2_INPUT_TYPE_CAMERA; + return 0; +} + + +static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) +{ + if (i != 0) + return -EINVAL; + else + return 0; +} + +/* from vivi.c */ +static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) +{ + return 0; +} + +/* List of all V4Lv2 controls supported by the driver */ +static struct v4l2_queryctrl stk_controls[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 0xffff, + .step = 0x0100, + .default_value = 0x6000, + }, + /*TODO: get more controls to work */ +}; + +static int stk_vidioc_queryctrl(struct file *filp, + void *priv, struct v4l2_queryctrl *c) +{ + int i; + int nbr; + nbr = ARRAY_SIZE(stk_controls); + + for (i = 0; i < nbr; i++) { + if (stk_controls[i].id == c->id) { + memcpy(c, &stk_controls[i], + sizeof(struct v4l2_queryctrl)); + return 0; + } + } + return -EINVAL; +} + +static int stk_vidioc_g_ctrl(struct file *filp, + void *priv, struct v4l2_control *c) +{ + struct stk_camera *dev = priv; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + c->value = dev->vsettings.brightness; + break; + default: + return -EINVAL; + } + return 0; +} + +static int stk_vidioc_s_ctrl(struct file *filp, + void *priv, struct v4l2_control *c) +{ + struct stk_camera *dev = priv; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + dev->vsettings.brightness = c->value; + return stk_sensor_set_brightness(dev, c->value >> 8); + default: + return -EINVAL; + } + return 0; +} + + +static int stk_vidioc_enum_fmt_cap(struct file *filp, + void *priv, struct v4l2_fmtdesc *fmtd) +{ + fmtd->flags = 0; + + switch (fmtd->index) { + case 0: + fmtd->pixelformat = V4L2_PIX_FMT_RGB565; + strcpy(fmtd->description, "r5g6b5"); + break; + case 1: + fmtd->pixelformat = V4L2_PIX_FMT_RGB565X; + strcpy(fmtd->description, "r5g6b5BE"); + break; + case 2: + fmtd->pixelformat = V4L2_PIX_FMT_UYVY; + strcpy(fmtd->description, "yuv4:2:2"); + break; + case 3: + fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; + strcpy(fmtd->description, "Raw bayer"); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct stk_size { + unsigned w; + unsigned h; + enum stk_mode m; +} stk_sizes[] = { + { .w = 1280, .h = 1024, .m = MODE_SXGA, }, + { .w = 640, .h = 480, .m = MODE_VGA, }, + { .w = 352, .h = 288, .m = MODE_CIF, }, + { .w = 320, .h = 240, .m = MODE_QVGA, }, + { .w = 176, .h = 144, .m = MODE_QCIF, }, +}; + +static int stk_vidioc_g_fmt_cap(struct file *filp, + void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format *pix_format = &f->fmt.pix; + struct stk_camera *dev = priv; + int i; + + for (i = 0; i < ARRAY_SIZE(stk_sizes) + && stk_sizes[i].m != dev->vsettings.mode; + i++); + if (i == ARRAY_SIZE(stk_sizes)) { + STK_ERROR("ERROR: mode invalid\n"); + return -EINVAL; + } + pix_format->width = stk_sizes[i].w; + pix_format->height = stk_sizes[i].h; + pix_format->field = V4L2_FIELD_NONE; + pix_format->colorspace = V4L2_COLORSPACE_SRGB; + pix_format->priv = 0; + pix_format->pixelformat = dev->vsettings.palette; + if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) + pix_format->bytesperline = pix_format->width; + else + pix_format->bytesperline = 2 * pix_format->width; + pix_format->sizeimage = pix_format->bytesperline + * pix_format->height; + return 0; +} + +static int stk_vidioc_try_fmt_cap(struct file *filp, + void *priv, struct v4l2_format *fmtd) +{ + int i; + switch (fmtd->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_RGB565X: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_SBGGR8: + break; + default: + return -EINVAL; + } + for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) { + if (fmtd->fmt.pix.width > stk_sizes[i].w) + break; + } + if (i == ARRAY_SIZE(stk_sizes) + || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w) + < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { + fmtd->fmt.pix.height = stk_sizes[i-1].h; + fmtd->fmt.pix.width = stk_sizes[i-1].w; + fmtd->fmt.pix.priv = i - 1; + } else { + fmtd->fmt.pix.height = stk_sizes[i].h; + fmtd->fmt.pix.width = stk_sizes[i].w; + fmtd->fmt.pix.priv = i; + } + + fmtd->fmt.pix.field = V4L2_FIELD_NONE; + fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8) + fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width; + else + fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; + fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline + * fmtd->fmt.pix.height; + return 0; +} + +static int stk_vidioc_s_fmt_cap(struct file *filp, + void *priv, struct v4l2_format *fmtd) +{ + int ret; + struct stk_camera *dev = priv; + + if (dev == NULL) + return -ENODEV; + if (!is_present(dev)) + return -ENODEV; + if (is_streaming(dev)) + return -EBUSY; + if (dev->owner && dev->owner != filp) + return -EBUSY; + dev->owner = filp; + ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd); + if (ret) + return ret; + + dev->vsettings.palette = fmtd->fmt.pix.pixelformat; + stk_free_buffers(dev); + dev->frame_size = fmtd->fmt.pix.sizeimage; + dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; + + stk_initialise(dev); + /* This registers controls some timings, not sure of what. */ + stk_camera_write_reg(dev, 0x001b, 0x0e); + if (dev->vsettings.mode == MODE_SXGA) + stk_camera_write_reg(dev, 0x001c, 0x0e); + else + stk_camera_write_reg(dev, 0x001c, 0x46); + /* + * Registers 0x0115 0x0114 are the size of each line (bytes), + * regs 0x0117 0x0116 are the heigth of the image. + */ + stk_camera_write_reg(dev, 0x0115, + (fmtd->fmt.pix.bytesperline >> 8) & 0xff); + stk_camera_write_reg(dev, 0x0114, + fmtd->fmt.pix.bytesperline & 0xff); + stk_camera_write_reg(dev, 0x0117, + (fmtd->fmt.pix.height >> 8) & 0xff); + stk_camera_write_reg(dev, 0x0116, + fmtd->fmt.pix.height & 0xff); + return stk_sensor_configure(dev); +} + +static int stk_vidioc_reqbufs(struct file *filp, + void *priv, struct v4l2_requestbuffers *rb) +{ + struct stk_camera *dev = priv; + + if (dev == NULL) + return -ENODEV; + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + if (is_streaming(dev) + || (dev->owner && dev->owner != filp)) + return -EBUSY; + dev->owner = filp; + + /*FIXME If they ask for zero, we must stop streaming and free */ + if (rb->count < 3) + rb->count = 3; + /* Arbitrary limit */ + else if (rb->count > 5) + rb->count = 5; + + stk_allocate_buffers(dev, rb->count); + rb->count = dev->n_sbufs; + return 0; +} + +static int stk_vidioc_querybuf(struct file *filp, + void *priv, struct v4l2_buffer *buf) +{ + int index; + struct stk_camera *dev = priv; + struct stk_sio_buffer *sbuf; + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + index = buf->index; + + if (index < 0 || index >= dev->n_sbufs) + return -EINVAL; + sbuf = dev->sio_bufs + buf->index; + *buf = sbuf->v4lbuf; + return 0; +} + +static int stk_vidioc_qbuf(struct file *filp, + void *priv, struct v4l2_buffer *buf) +{ + struct stk_camera *dev = priv; + struct stk_sio_buffer *sbuf; + unsigned long flags; + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + if (buf->index < 0 || buf->index >= dev->n_sbufs) + return -EINVAL; + sbuf = dev->sio_bufs + buf->index; + if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED) + return 0; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE; + spin_lock_irqsave(&dev->spinlock, flags); + list_add_tail(&sbuf->list, &dev->sio_avail); + *buf = sbuf->v4lbuf; + spin_unlock_irqrestore(&dev->spinlock, flags); + return 0; +} + +static int stk_vidioc_dqbuf(struct file *filp, + void *priv, struct v4l2_buffer *buf) +{ + struct stk_camera *dev = priv; + struct stk_sio_buffer *sbuf; + unsigned long flags; + int ret; + + if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || !is_streaming(dev)) + return -EINVAL; + + if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full)) + return -EWOULDBLOCK; + ret = wait_event_interruptible(dev->wait_frame, + !list_empty(&dev->sio_full) || !is_present(dev)); + if (ret) + return ret; + if (!is_present(dev)) + return -EIO; + + spin_lock_irqsave(&dev->spinlock, flags); + sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list); + list_del_init(&sbuf->list); + spin_unlock_irqrestore(&dev->spinlock, flags); + sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED; + sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE; + sbuf->v4lbuf.sequence = ++dev->sequence; + do_gettimeofday(&sbuf->v4lbuf.timestamp); + + *buf = sbuf->v4lbuf; + return 0; +} + +static int stk_vidioc_streamon(struct file *filp, + void *priv, enum v4l2_buf_type type) +{ + struct stk_camera *dev = priv; + if (is_streaming(dev)) + return 0; + if (dev->sio_bufs == NULL) + return -EINVAL; + dev->sequence = 0; + return stk_start_stream(dev); +} + +static int stk_vidioc_streamoff(struct file *filp, + void *priv, enum v4l2_buf_type type) +{ + struct stk_camera *dev = priv; + unsigned long flags; + int i; + stk_stop_stream(dev); + spin_lock_irqsave(&dev->spinlock, flags); + INIT_LIST_HEAD(&dev->sio_avail); + INIT_LIST_HEAD(&dev->sio_full); + for (i = 0; i < dev->n_sbufs; i++) { + INIT_LIST_HEAD(&dev->sio_bufs[i].list); + dev->sio_bufs[i].v4lbuf.flags = 0; + } + spin_unlock_irqrestore(&dev->spinlock, flags); + return 0; +} + + +static int stk_vidioc_g_parm(struct file *filp, + void *priv, struct v4l2_streamparm *sp) +{ + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + sp->parm.capture.capability = 0; + sp->parm.capture.capturemode = 0; + /*FIXME This is not correct */ + sp->parm.capture.timeperframe.numerator = 1; + sp->parm.capture.timeperframe.denominator = 30; + sp->parm.capture.readbuffers = 2; + sp->parm.capture.extendedmode = 0; + return 0; +} + +static struct file_operations v4l_stk_fops = { + .owner = THIS_MODULE, + .open = v4l_stk_open, + .release = v4l_stk_release, + .read = v4l_stk_read, + .poll = v4l_stk_poll, + .mmap = v4l_stk_mmap, + .ioctl = video_ioctl2, + .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, + + .vidioc_querycap = stk_vidioc_querycap, + .vidioc_enum_fmt_cap = stk_vidioc_enum_fmt_cap, + .vidioc_try_fmt_cap = stk_vidioc_try_fmt_cap, + .vidioc_s_fmt_cap = stk_vidioc_s_fmt_cap, + .vidioc_g_fmt_cap = stk_vidioc_g_fmt_cap, + .vidioc_enum_input = stk_vidioc_enum_input, + .vidioc_s_input = stk_vidioc_s_input, + .vidioc_g_input = stk_vidioc_g_input, + .vidioc_s_std = stk_vidioc_s_std, + .vidioc_reqbufs = stk_vidioc_reqbufs, + .vidioc_querybuf = stk_vidioc_querybuf, + .vidioc_qbuf = stk_vidioc_qbuf, + .vidioc_dqbuf = stk_vidioc_dqbuf, + .vidioc_streamon = stk_vidioc_streamon, + .vidioc_streamoff = stk_vidioc_streamoff, + .vidioc_queryctrl = stk_vidioc_queryctrl, + .vidioc_g_ctrl = stk_vidioc_g_ctrl, + .vidioc_s_ctrl = stk_vidioc_s_ctrl, + .vidioc_g_parm = stk_vidioc_g_parm, +}; + + +static int stk_register_video_device(struct stk_camera *dev) +{ + int err; + + dev->vdev = stk_v4l_data; + dev->vdev.debug = debug; + dev->vdev.dev = &dev->interface->dev; + dev->vdev.priv = dev; + err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); + if (err) + STK_ERROR("v4l registration failed\n"); + else + STK_INFO("Syntek USB2.0 Camera is now controlling video device" + " /dev/video%d\n", dev->vdev.minor); + return err; +} + + +/* USB Stuff */ + +static int stk_camera_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + int i; + int err; + + struct stk_camera *dev = NULL; + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + + dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL); + if (dev == NULL) { + STK_ERROR("Out of memory !\n"); + return -ENOMEM; + } + + kref_init(&dev->kref); + spin_lock_init(&dev->spinlock); + init_waitqueue_head(&dev->wait_frame); + + dev->udev = udev; + dev->interface = interface; + usb_get_intf(interface); + + dev->vsettings.vflip = vflip; + dev->vsettings.hflip = hflip; + dev->n_sbufs = 0; + set_present(dev); + + /* Set up the endpoint information + * use only the first isoc-in endpoint + * for the current alternate setting */ + iface_desc = interface->cur_altsetting; + + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (!dev->isoc_ep + && ((endpoint->bEndpointAddress + & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) + && ((endpoint->bmAttributes + & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) { + /* we found an isoc in endpoint */ + dev->isoc_ep = (endpoint->bEndpointAddress & 0xF); + break; + } + } + if (!dev->isoc_ep) { + STK_ERROR("Could not find isoc-in endpoint"); + kref_put(&dev->kref, stk_camera_cleanup); + return -ENODEV; + } + dev->vsettings.brightness = 0x7fff; + dev->vsettings.palette = V4L2_PIX_FMT_RGB565; + dev->vsettings.mode = MODE_VGA; + dev->frame_size = 640*480*2; + + INIT_LIST_HEAD(&dev->sio_avail); + INIT_LIST_HEAD(&dev->sio_full); + + usb_set_intfdata(interface, dev); + + err = stk_register_video_device(dev); + if (err) { + kref_put(&dev->kref, stk_camera_cleanup); + return err; + } + + stk_create_sysfs_files(&dev->vdev); + + return 0; +} + +static void stk_camera_disconnect(struct usb_interface *interface) +{ + struct stk_camera *dev = usb_get_intfdata(interface); + + usb_set_intfdata(interface, NULL); + unset_present(dev); + + wake_up_interruptible(&dev->wait_frame); + stk_remove_sysfs_files(&dev->vdev); + + kref_put(&dev->kref, stk_camera_cleanup); +} + +static struct usb_driver stk_camera_driver = { + .name = "stkwebcam", + .probe = stk_camera_probe, + .disconnect = stk_camera_disconnect, + .id_table = stkwebcam_table, +}; + + +static int __init stk_camera_init(void) +{ + int result; + + result = usb_register(&stk_camera_driver); + if (result) + STK_ERROR("usb_register failed ! Error number %d\n", result); + + + return result; +} + +static void __exit stk_camera_exit(void) +{ + usb_deregister(&stk_camera_driver); +} + +module_init(stk_camera_init); +module_exit(stk_camera_exit); + + diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h new file mode 100644 index 000000000000..7e989d1ac1e0 --- /dev/null +++ b/drivers/media/video/stk-webcam.h @@ -0,0 +1,138 @@ +/* + * stk-webcam.h : Driver for Syntek 1125 USB webcam controller + * + * Copyright (C) 2006 Nicolas VIVIEN + * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * 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 STKWEBCAM_H +#define STKWEBCAM_H + +#include <linux/usb.h> +#include <media/v4l2-common.h> + +#define DRIVER_VERSION "v0.0.1" +#define DRIVER_VERSION_NUM 0x000001 + +#define MAX_ISO_BUFS 3 +#define ISO_FRAMES_PER_DESC 16 +#define ISO_MAX_FRAME_SIZE 3 * 1024 +#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) + + +#define PREFIX "stkwebcam: " +#define STK_INFO(str, args...) printk(KERN_INFO PREFIX str, ##args) +#define STK_ERROR(str, args...) printk(KERN_ERR PREFIX str, ##args) +#define STK_WARNING(str, args...) printk(KERN_WARNING PREFIX str, ##args) + +struct stk_iso_buf { + void *data; + int length; + int read; + struct urb *urb; +}; + +/* Streaming IO buffers */ +struct stk_sio_buffer { + struct v4l2_buffer v4lbuf; + char *buffer; + int mapcount; + struct stk_camera *dev; + struct list_head list; +}; + +enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF}; + +struct stk_video { + enum stk_mode mode; + int brightness; + __u32 palette; + int hflip; + int vflip; +}; + +enum stk_status { + S_PRESENT = 1, + S_INITIALISED = 2, + S_MEMALLOCD = 4, + S_STREAMING = 8, +}; +#define is_present(dev) ((dev)->status & S_PRESENT) +#define is_initialised(dev) ((dev)->status & S_INITIALISED) +#define is_streaming(dev) ((dev)->status & S_STREAMING) +#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD) +#define set_present(dev) ((dev)->status = S_PRESENT) +#define unset_present(dev) ((dev)->status &= \ + ~(S_PRESENT|S_INITIALISED|S_STREAMING)) +#define set_initialised(dev) ((dev)->status |= S_INITIALISED) +#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD) +#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD) +#define set_streaming(dev) ((dev)->status |= S_STREAMING) +#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING) + +struct regval { + unsigned reg; + unsigned val; +}; + +struct stk_camera { + struct video_device vdev; + struct usb_device *udev; + struct usb_interface *interface; + int webcam_model; + struct file *owner; + + u8 isoc_ep; + + struct kref kref; + /* Not sure if this is right */ + atomic_t urbs_used; + + struct stk_video vsettings; + + enum stk_status status; + + spinlock_t spinlock; + wait_queue_head_t wait_frame; + + struct stk_iso_buf *isobufs; + + int frame_size; + /* Streaming buffers */ + unsigned int n_sbufs; + struct stk_sio_buffer *sio_bufs; + struct list_head sio_avail; + struct list_head sio_full; + unsigned sequence; +}; + +#define to_stk_camera(d) container_of(d, struct stk_camera, kref) +#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) + +void stk_camera_delete(struct kref *); +int stk_camera_write_reg(struct stk_camera *, u16, u8); +int stk_camera_read_reg(struct stk_camera *, u16, int *); + +int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val); +int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val); +int stk_sensor_init(struct stk_camera *); +int stk_sensor_configure(struct stk_camera *); +int stk_sensor_sleep(struct stk_camera *dev); +int stk_sensor_wakeup(struct stk_camera *dev); +int stk_sensor_set_brightness(struct stk_camera *dev, int br); + +#endif diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c index 43225802a551..b4d10f7a4e57 100644 --- a/drivers/media/video/tda7432.c +++ b/drivers/media/video/tda7432.c @@ -8,6 +8,7 @@ * Muting and tone control by Jonathan Isom <jisom@ematic.com> * * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com> + * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org> * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -276,7 +277,7 @@ static void do_tda7432_init(struct i2c_client *client) t->volume = 0x3b ; /* -27dB Volume */ if (loudness) /* Turn loudness on? */ t->volume |= TDA7432_LD_ON; - t->muted = VIDEO_AUDIO_MUTE; + t->muted = 1; t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ @@ -332,151 +333,160 @@ static int tda7432_detach(struct i2c_client *client) return 0; } -static int tda7432_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tda7432_get_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) { struct tda7432 *t = i2c_get_clientdata(client); - v4l_dbg(2, debug,client,"In tda7432_command\n"); - if (debug>1) - v4l_i2c_print_ioctl(client,cmd); - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - - /* Query card - scale from TDA7432 settings to V4L settings */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE | - VIDEO_AUDIO_MUTABLE; - if (t->muted) - va->flags |= VIDEO_AUDIO_MUTE; - va->mode |= VIDEO_SOUND_STEREO; - /* Master volume control - * V4L volume is min 0, max 65535 - * TDA7432 Volume: - * Min (-79dB) is 0x6f - * Max (+20dB) is 0x07 (630) - * Max (0dB) is 0x20 (829) - * (Mask out bit 7 of vol - it's for the loudness setting) - */ + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=t->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: if (!maxvol){ /* max +20db */ - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 630; + ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; } else { /* max 0db */ - va->volume = ( 0x6f - (t->volume & 0x7F) ) * 829; + ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; } - - /* Balance depends on L,R attenuation - * V4L balance is 0 to 65535, middle is 32768 - * TDA7432 attenuation: min (0dB) is 0, max (-37.5dB) is 0x1f - * to scale up to V4L numbers, mult by 1057 - * attenuation exists for lf, lr, rf, rr - * we use only lf and rf (front channels) - */ - + return 0; + case V4L2_CID_AUDIO_BALANCE: + { if ( (t->lf) < (t->rf) ) /* right is attenuated, balance shifted left */ - va->balance = (32768 - 1057*(t->rf)); + ctrl->value = (32768 - 1057*(t->rf)); else /* left is attenuated, balance shifted right */ - va->balance = (32768 + 1057*(t->lf)); - + ctrl->value = (32768 + 1057*(t->lf)); + return 0; + } + case V4L2_CID_AUDIO_BASS: + { /* Bass/treble 4 bits each */ - va->bass=t->bass; - if(va->bass >= 0x8) - va->bass = ~(va->bass - 0x8) & 0xf; - va->bass = (va->bass << 12)+(va->bass << 8)+(va->bass << 4)+(va->bass); - va->treble=t->treble; - if(va->treble >= 0x8) - va->treble = ~(va->treble - 0x8) & 0xf; - va->treble = (va->treble << 12)+(va->treble << 8)+(va->treble << 4)+(va->treble); - - break; /* VIDIOCGAUDIO case */ + int bass=t->bass; + if(bass >= 0x8) + bass = ~(bass - 0x8) & 0xf; + ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); + return 0; } - - /* Set card - scale from V4L settings to TDA7432 settings */ - case VIDIOCSAUDIO: + case V4L2_CID_AUDIO_TREBLE: { - struct video_audio *va = arg; + int treble=t->treble; + if(treble >= 0x8) + treble = ~(treble - 0x8) & 0xf; + ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); + return 0; + } + } + return -EINVAL; +} - if(va->flags & VIDEO_AUDIO_VOLUME){ - if(!maxvol){ /* max +20db */ - t->volume = 0x6f - ((va->volume)/630); - } else { /* max 0db */ - t->volume = 0x6f - ((va->volume)/829); - } +static int tda7432_set_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) +{ + struct tda7432 *t = i2c_get_clientdata(client); + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + t->muted=ctrl->value; + break; + case V4L2_CID_AUDIO_VOLUME: + if(!maxvol){ /* max +20db */ + t->volume = 0x6f - ((ctrl->value)/630); + } else { /* max 0db */ + t->volume = 0x6f - ((ctrl->value)/829); + } if (loudness) /* Turn on the loudness bit */ t->volume |= TDA7432_LD_ON; - tda7432_write(client,TDA7432_VL, t->volume); - } - - if(va->flags & VIDEO_AUDIO_BASS) - { - t->bass = va->bass >> 12; - if(t->bass>= 0x8) - t->bass = (~t->bass & 0xf) + 0x8 ; - } - if(va->flags & VIDEO_AUDIO_TREBLE) - { - t->treble= va->treble >> 12; - if(t->treble>= 0x8) - t->treble = (~t->treble & 0xf) + 0x8 ; - } - if(va->flags & (VIDEO_AUDIO_TREBLE| VIDEO_AUDIO_BASS)) - tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); - - if(va->flags & VIDEO_AUDIO_BALANCE) { - if (va->balance < 32768) - { + tda7432_write(client,TDA7432_VL, t->volume); + return 0; + case V4L2_CID_AUDIO_BALANCE: + if (ctrl->value < 32768) { /* shifted to left, attenuate right */ - t->rr = (32768 - va->balance)/1057; + t->rr = (32768 - ctrl->value)/1057; t->rf = t->rr; t->lr = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; - } - else if(va->balance > 32769) - { + } else if(ctrl->value > 32769) { /* shifted to right, attenuate left */ - t->lf = (va->balance - 32768)/1057; + t->lf = (ctrl->value - 32768)/1057; t->lr = t->lf; t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; - } - else - { + } else { /* centered */ t->rr = TDA7432_ATTEN_0DB; t->rf = TDA7432_ATTEN_0DB; t->lf = TDA7432_ATTEN_0DB; t->lr = TDA7432_ATTEN_0DB; } - } + break; + case V4L2_CID_AUDIO_BASS: + t->bass = ctrl->value >> 12; + if(t->bass>= 0x8) + t->bass = (~t->bass & 0xf) + 0x8 ; + + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + return 0; + case V4L2_CID_AUDIO_TREBLE: + t->treble= ctrl->value >> 12; + if(t->treble>= 0x8) + t->treble = (~t->treble & 0xf) + 0x8 ; + + tda7432_write(client,TDA7432_TN, 0x10 | (t->bass << 4) | t->treble ); + return 0; + default: + return -EINVAL; + } - t->muted=(va->flags & VIDEO_AUDIO_MUTE); - if (t->muted) - { - /* Mute & update balance*/ - tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); - tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); - tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); - tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); - } else { - tda7432_write(client,TDA7432_LF, t->lf); - tda7432_write(client,TDA7432_LR, t->lr); - tda7432_write(client,TDA7432_RF, t->rf); - tda7432_write(client,TDA7432_RR, t->rr); - } + /* Used for both mute and balance changes */ + if (t->muted) + { + /* Mute & update balance*/ + tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE); + tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE); + tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE); + tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE); + } else { + tda7432_write(client,TDA7432_LF, t->lf); + tda7432_write(client,TDA7432_LR, t->lr); + tda7432_write(client,TDA7432_RF, t->rf); + tda7432_write(client,TDA7432_RR, t->rr); + } + return 0; +} - break; +static int tda7432_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + v4l_dbg(2, debug,client,"In tda7432_command\n"); + if (debug>1) + v4l_i2c_print_ioctl(client,cmd); + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + default: + return -EINVAL; + } + return v4l2_ctrl_query_fill_std(qc); + } + case VIDIOC_S_CTRL: + return tda7432_set_ctrl(client, arg); - } /* end of VIDEOCSAUDIO case */ + case VIDIOC_G_CTRL: + return tda7432_get_ctrl(client, arg); } /* end of (cmd) switch */ diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index 0e5cf459d3ed..55bc89a6f069 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -25,12 +25,14 @@ #include <linux/videodev.h> #include "tuner-i2c.h" #include "tda8290.h" +#include "tda827x.h" +#include "tda18271.h" -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tda8290 " +#define PREFIX "tda8290" /* ---------------------------------------------------------------------- */ @@ -38,345 +40,71 @@ struct tda8290_priv { struct tuner_i2c_props i2c_props; unsigned char tda8290_easy_mode; - unsigned char tda827x_lpsel; - unsigned char tda827x_addr; - unsigned char tda827x_ver; - unsigned int sgIF; - - u32 frequency; - - unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command,int arg); -}; - -/* ---------------------------------------------------------------------- */ - -struct tda827x_data { - u32 lomax; - u8 spd; - u8 bs; - u8 bp; - u8 cp; - u8 gc3; - u8 div1p5; -}; - - /* Note lomax entry is lo / 62500 */ - -static struct tda827x_data tda827x_analog[] = { - { .lomax = 992, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 62 MHz */ - { .lomax = 1056, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, /* 66 MHz */ - { .lomax = 1216, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 76 MHz */ - { .lomax = 1344, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, /* 84 MHz */ - { .lomax = 1488, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 93 MHz */ - { .lomax = 1568, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 98 MHz */ - { .lomax = 1744, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 109 MHz */ - { .lomax = 1968, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 123 MHz */ - { .lomax = 2128, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 133 MHz */ - { .lomax = 2416, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 151 MHz */ - { .lomax = 2464, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 154 MHz */ - { .lomax = 2896, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 181 MHz */ - { .lomax = 2960, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 185 MHz */ - { .lomax = 3472, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 217 MHz */ - { .lomax = 3904, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 244 MHz */ - { .lomax = 4240, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 265 MHz */ - { .lomax = 4832, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 302 MHz */ - { .lomax = 5184, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 324 MHz */ - { .lomax = 5920, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 370 MHz */ - { .lomax = 7264, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 454 MHz */ - { .lomax = 7888, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 493 MHz */ - { .lomax = 8480, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, /* 530 MHz */ - { .lomax = 8864, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, /* 554 MHz */ - { .lomax = 9664, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 604 MHz */ - { .lomax = 11088, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 696 MHz */ - { .lomax = 11840, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 740 MHz */ - { .lomax = 13120, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, /* 820 MHz */ - { .lomax = 13840, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, /* 865 MHz */ - { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} /* End */ -}; - -static void tda827x_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) -{ - unsigned char tuner_reg[8]; - unsigned char reg2[2]; - u32 N; - int i; - struct tda8290_priv *priv = fe->tuner_priv; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0}; - unsigned int freq = params->frequency; - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; - - N = freq + priv->sgIF; - i = 0; - while (tda827x_analog[i].lomax < N) { - if(tda827x_analog[i + 1].lomax == 0) - break; - i++; - } - - N = N << tda827x_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0x40; - tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5); - tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) + - (tda827x_analog[i].bs <<3) + tda827x_analog[i].bp; - tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4); - tuner_reg[7] = 0x8f; - - msg.buf = tuner_reg; - msg.len = 8; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msg.buf= reg2; - msg.len = 2; - reg2[0] = 0x80; - reg2[1] = 0; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0xbf; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 0x80; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4] + 4; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(1); - reg2[0] = 0x30; - reg2[1] = tuner_reg[4]; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(550); - reg2[0] = 0x30; - reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x60; - reg2[1] = 0x3f; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - reg2[0] = 0x80; - reg2[1] = 0x08; // Vsync en - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} -static void tda827x_agcf(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x0c}; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, - .flags = 0, .len = 2}; - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -/* ---------------------------------------------------------------------- */ + unsigned char tda827x_addr; -struct tda827xa_data { - u32 lomax; - u8 svco; - u8 spd; - u8 scr; - u8 sbs; - u8 gc3; -}; + unsigned char ver; +#define TDA8290 1 +#define TDA8295 2 +#define TDA8275 4 +#define TDA8275A 8 +#define TDA18271 16 -static struct tda827xa_data tda827xa_analog[] = { - { .lomax = 910, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, /* 56.875 MHz */ - { .lomax = 1076, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 67.25 MHz */ - { .lomax = 1300, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 81.25 MHz */ - { .lomax = 1560, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, /* 97.5 MHz */ - { .lomax = 1820, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, /* 113.75 MHz */ - { .lomax = 2152, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 134.5 MHz */ - { .lomax = 2464, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 154 MHz */ - { .lomax = 2600, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 162.5 MHz */ - { .lomax = 2928, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, /* 183 MHz */ - { .lomax = 3120, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, /* 195 MHz */ - { .lomax = 3640, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, /* 227.5 MHz */ - { .lomax = 4304, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, /* 269 MHz */ - { .lomax = 5200, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, /* 325 MHz */ - { .lomax = 6240, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 390 MHz */ - { .lomax = 7280, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, /* 455 MHz */ - { .lomax = 8320, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 520 MHz */ - { .lomax = 8608, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, /* 538 MHz */ - { .lomax = 8864, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, /* 554 MHz */ - { .lomax = 9920, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 620 MHz */ - { .lomax = 10400, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 650 MHz */ - { .lomax = 11200, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 700 MHz */ - { .lomax = 12480, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 780 MHz */ - { .lomax = 13120, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, /* 820 MHz */ - { .lomax = 13920, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, /* 870 MHz */ - { .lomax = 14576, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, /* 911 MHz */ - { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} /* End */ + struct tda827x_config cfg; }; -static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, - struct analog_parameters *params) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char buf[] = {0x22, 0x01}; - int arg; - struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)}; - - if ((priv->lna_cfg == NULL) || (priv->tuner_callback == NULL)) - return; - - if (*priv->lna_cfg) { - if (high) - tuner_dbg("setting LNA to high gain\n"); - else - tuner_dbg("setting LNA to low gain\n"); - } - switch (*priv->lna_cfg) { - case 0: /* no LNA */ - break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: - /* turn Vsync on */ - if (params->std & V4L2_STD_MN) - arg = 1; - else - arg = 0; - if (priv->tuner_callback) - priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg); - buf[1] = high ? 0 : 1; - if (*priv->lna_cfg == 2) - buf[1] = high ? 1 : 0; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - break; - case 3: /* switch with GPIO of saa713x */ - if (priv->tuner_callback) - priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high); - break; - } -} +/*---------------------------------------------------------------------*/ -static void tda827xa_set_analog_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) { - unsigned char tuner_reg[11]; - u32 N; - int i; - struct tda8290_priv *priv = fe->tuner_priv; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg}; - unsigned int freq = params->frequency; + struct tda8290_priv *priv = fe->analog_demod_priv; - tda827xa_lna_gain(fe, 1, params); - msleep(10); - - if (params->mode == V4L2_TUNER_RADIO) - freq = freq / 1000; + unsigned char enable[2] = { 0x21, 0xC0 }; + unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char *msg; - N = freq + priv->sgIF; - i = 0; - while (tda827xa_analog[i].lomax < N) { - if(tda827xa_analog[i + 1].lomax == 0) - break; - i++; + if (close) { + msg = enable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); + /* let the bridge stabilize */ + msleep(20); + } else { + msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } - N = N << tda827xa_analog[i].spd; - - tuner_reg[0] = 0; - tuner_reg[1] = (unsigned char)(N>>8); - tuner_reg[2] = (unsigned char) N; - tuner_reg[3] = 0; - tuner_reg[4] = 0x16; - tuner_reg[5] = (tda827xa_analog[i].spd << 5) + (tda827xa_analog[i].svco << 3) + - tda827xa_analog[i].sbs; - tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); - tuner_reg[7] = 0x1c; - tuner_reg[8] = 4; - tuner_reg[9] = 0x20; - tuner_reg[10] = 0x00; - msg.len = 11; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x90; - tuner_reg[1] = 0xff; - tuner_reg[2] = 0xe0; - tuner_reg[3] = 0; - tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1); - msg.len = 5; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xa0; - tuner_reg[1] = 0xc0; - msg.len = 2; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x30; - tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msg.flags = I2C_M_RD; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - msg.flags = 0; - tuner_reg[1] >>= 4; - tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]); - if (tuner_reg[1] < 1) - tda827xa_lna_gain(fe, 0, params); - - msleep(100); - tuner_reg[0] = 0x60; - tuner_reg[1] = 0x3c; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - msleep(163); - tuner_reg[0] = 0x50; - tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0x80; - tuner_reg[1] = 0x28; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xb0; - tuner_reg[1] = 0x01; - i2c_transfer(priv->i2c_props.adap, &msg, 1); - - tuner_reg[0] = 0xc0; - tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1); - i2c_transfer(priv->i2c_props.adap, &msg, 1); -} - -static void tda827xa_agcf(struct dvb_frontend *fe) -{ - struct tda8290_priv *priv = fe->tuner_priv; - unsigned char data[] = {0x80, 0x2c}; - struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data, - .flags = 0, .len = 2}; - i2c_transfer(priv->i2c_props.adap, &msg, 1); + return 0; } -/*---------------------------------------------------------------------*/ - -static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) +static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; - unsigned char enable[2] = { 0x21, 0xC0 }; - unsigned char disable[2] = { 0x21, 0x00 }; + unsigned char enable[2] = { 0x45, 0xc1 }; + unsigned char disable[2] = { 0x46, 0x00 }; + unsigned char buf[3] = { 0x45, 0x01, 0x00 }; unsigned char *msg; - if(close) { + + if (close) { msg = enable; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); /* let the bridge stabilize */ msleep(20); } else { msg = disable; + tuner_i2c_xfer_send(&priv->i2c_props, msg, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1); + + buf[2] = msg[1]; + buf[2] &= ~0x04; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); + msleep(5); + + msg[1] |= 0x04; tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); } + + return 0; } /*---------------------------------------------------------------------*/ @@ -384,55 +112,43 @@ static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close) static void set_audio(struct dvb_frontend *fe, struct analog_parameters *params) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; char* mode; - priv->tda827x_lpsel = 0; if (params->std & V4L2_STD_MN) { - priv->sgIF = 92; priv->tda8290_easy_mode = 0x01; - priv->tda827x_lpsel = 1; mode = "MN"; } else if (params->std & V4L2_STD_B) { - priv->sgIF = 108; priv->tda8290_easy_mode = 0x02; mode = "B"; } else if (params->std & V4L2_STD_GH) { - priv->sgIF = 124; priv->tda8290_easy_mode = 0x04; mode = "GH"; } else if (params->std & V4L2_STD_PAL_I) { - priv->sgIF = 124; priv->tda8290_easy_mode = 0x08; mode = "I"; } else if (params->std & V4L2_STD_DK) { - priv->sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "DK"; } else if (params->std & V4L2_STD_SECAM_L) { - priv->sgIF = 124; priv->tda8290_easy_mode = 0x20; mode = "L"; } else if (params->std & V4L2_STD_SECAM_LC) { - priv->sgIF = 20; priv->tda8290_easy_mode = 0x40; mode = "LC"; } else { - priv->sgIF = 124; priv->tda8290_easy_mode = 0x10; mode = "xx"; } - if (params->mode == V4L2_TUNER_RADIO) - priv->sgIF = 88; /* if frequency is 5.5 MHz */ - - tuner_dbg("setting tda8290 to system %s\n", mode); + tuner_dbg("setting tda829x to system %s\n", mode); } -static int tda8290_set_params(struct dvb_frontend *fe, - struct analog_parameters *params) +static void tda8290_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; @@ -457,8 +173,8 @@ static int tda8290_set_params(struct dvb_frontend *fe, set_audio(fe, params); - if (priv->lna_cfg) - tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg); + if (priv->cfg.config) + tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config); tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); @@ -475,10 +191,10 @@ static int tda8290_set_params(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); tda8290_i2c_bridge(fe, 1); - if (priv->tda827x_ver != 0) - tda827xa_set_analog_params(fe, params); - else - tda827x_set_analog_params(fe, params); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, params); + for (i = 0; i < 3; i++) { tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1); @@ -507,10 +223,8 @@ static int tda8290_set_params(struct dvb_frontend *fe, if ((agc_stat > 115) || !(pll_stat & 0x80)) { tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", agc_stat, pll_stat & 0x80); - if (priv->tda827x_ver != 0) - tda827xa_agcf(fe); - else - tda827x_agcf(fe); + if (priv->cfg.agcf) + priv->cfg.agcf(fe); msleep(100); tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1); tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1); @@ -541,99 +255,242 @@ static int tda8290_set_params(struct dvb_frontend *fe, tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); +} + +/*---------------------------------------------------------------------*/ + +static void tda8295_power(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ - priv->frequency = (V4L2_TUNER_RADIO == params->mode) ? - params->frequency * 125 / 2 : params->frequency * 62500; + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); - return 0; + if (enable) + buf[1] = 0x01; + else + buf[1] = 0x03; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x01, 0x00 }; + + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); + + if (enable) + buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ + else + buf[1] = 0x00; /* reset active bit */ + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_set_video_std(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; + + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); + + tda8295_set_easy_mode(fe, 1); + msleep(20); + tda8295_set_easy_mode(fe, 0); } /*---------------------------------------------------------------------*/ -static int tda8290_has_signal(struct dvb_frontend *fe) +static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) { - struct tda8290_priv *priv = fe->tuner_priv; - int ret; + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ - unsigned char i2c_get_afc[1] = { 0x1B }; - unsigned char afc = 0; + tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1); - /* for now, report based on afc status */ - tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); - tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); + if (enable) + buf[1] &= ~0x40; + else + buf[1] |= 0x40; - ret = (afc & 0x80) ? 65535 : 0; + tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); +} + +static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char set_gpio_cf[] = { 0x44, 0x00 }; + unsigned char set_gpio_val[] = { 0x46, 0x00 }; + + tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1); + tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1); - tuner_dbg("AFC status: %d\n", ret); + set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ - return ret; + if (enable) { + set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ + set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ + } + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); } -static int tda8290_get_status(struct dvb_frontend *fe, u32 *status) +static int tda8295_has_signal(struct dvb_frontend *fe) { - *status = 0; + struct tda8290_priv *priv = fe->analog_demod_priv; - if (tda8290_has_signal(fe)) - *status = TUNER_STATUS_LOCKED; + unsigned char hvpll_stat = 0x26; + unsigned char ret; - return 0; + tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1); + return (ret & 0x01) ? 65535 : 0; } -static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength) +/*---------------------------------------------------------------------*/ + +static void tda8295_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - *strength = tda8290_has_signal(fe); + struct tda8290_priv *priv = fe->analog_demod_priv; - return 0; + unsigned char blanking_mode[] = { 0x1d, 0x00 }; + + set_audio(fe, params); + + tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency); + + tda8295_power(fe, 1); + tda8295_agc1_out(fe, 1); + + tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1); + tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1); + + tda8295_set_video_std(fe); + + blanking_mode[1] = 0x03; + tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); + msleep(20); + + tda8295_i2c_bridge(fe, 1); + + if (fe->ops.tuner_ops.set_analog_params) + fe->ops.tuner_ops.set_analog_params(fe, params); + + if (priv->cfg.agcf) + priv->cfg.agcf(fe); + + if (tda8295_has_signal(fe)) + tuner_dbg("tda8295 is locked\n"); + else + tuner_dbg("tda8295 not locked, no signal?\n"); + + tda8295_i2c_bridge(fe, 0); +} + +/*---------------------------------------------------------------------*/ + +static int tda8290_has_signal(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + unsigned char i2c_get_afc[1] = { 0x1B }; + unsigned char afc = 0; + + tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc)); + tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1); + return (afc & 0x80)? 65535:0; } /*---------------------------------------------------------------------*/ -static int tda8290_standby(struct dvb_frontend *fe) +static void tda8290_standby(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; + unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; tda8290_i2c_bridge(fe, 1); - if (priv->tda827x_ver != 0) + if (priv->ver & TDA8275A) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); tda8290_i2c_bridge(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); - - return 0; } +static void tda8295_standby(struct dvb_frontend *fe) +{ + tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ + + tda8295_power(fe, 0); +} static void tda8290_init_if(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char set_VS[] = { 0x30, 0x6F }; unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((priv->lna_cfg) && - ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2))) + if ((priv->cfg.config) && + ((*priv->cfg.config == 1) || (*priv->cfg.config == 2))) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); } +static void tda8295_init_if(struct dvb_frontend *fe) +{ + struct tda8290_priv *priv = fe->analog_demod_priv; + + static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; + static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; + static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; + static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; + static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; + static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; + static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; + + tda8295_power(fe, 1); + + tda8295_set_easy_mode(fe, 0); + tda8295_set_video_std(fe); + + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); + tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); + + tda8295_agc1_out(fe, 0); + tda8295_agc2_out(fe, 0); +} + static void tda8290_init_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = fe->tuner_priv; + struct tda8290_priv *priv = fe->analog_demod_priv; unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=tda8275_init, .len = 14}; - if (priv->tda827x_ver != 0) + if (priv->ver & TDA8275A) msg.buf = tda8275a_init; tda8290_i2c_bridge(fe, 1); @@ -643,58 +500,42 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) /*---------------------------------------------------------------------*/ -static int tda8290_release(struct dvb_frontend *fe) +static void tda829x_release(struct dvb_frontend *fe) { - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; + struct tda8290_priv *priv = fe->analog_demod_priv; - return 0; -} + /* only try to release the tuner if we've + * attached it from within this module */ + if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); -static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency) -{ - struct tda8290_priv *priv = fe->tuner_priv; - *frequency = priv->frequency; - return 0; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } -static struct dvb_tuner_ops tda8290_tuner_ops = { - .sleep = tda8290_standby, - .set_analog_params = tda8290_set_params, - .release = tda8290_release, - .get_frequency = tda8290_get_frequency, - .get_status = tda8290_get_status, - .get_rf_strength = tda8290_get_rf_strength, +static struct tda18271_config tda829x_tda18271_config = { + .gate = TDA18271_GATE_ANALOG, }; -struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, - u8 i2c_addr, - struct tda8290_config *cfg) +static int tda829x_find_tuner(struct dvb_frontend *fe) { - struct tda8290_priv *priv = NULL; - u8 data; + struct tda8290_priv *priv = fe->analog_demod_priv; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; int i, ret, tuners_found; u32 tuner_addrs; - struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1}; + u8 data; + struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); - if (priv == NULL) - return NULL; - fe->tuner_priv = priv; + if (NULL == analog_ops->i2c_gate_ctrl) + return -EINVAL; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; - if (cfg) { - priv->lna_cfg = cfg->lna_cfg; - priv->tuner_callback = cfg->tuner_callback; - } + analog_ops->i2c_gate_ctrl(fe, 1); - tda8290_i2c_bridge(fe, 1); /* probe for tuner chip */ tuners_found = 0; tuner_addrs = 0; - for (i=0x60; i<= 0x63; i++) { + for (i = 0x60; i <= 0x63; i++) { msg.addr = i; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret == 1) { @@ -706,20 +547,23 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, behind the bridge and we choose the highest address that doesn't give a response now */ - tda8290_i2c_bridge(fe, 0); - if(tuners_found > 1) + + analog_ops->i2c_gate_ctrl(fe, 0); + + if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { msg.addr = tuner_addrs & 0xff; ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if(ret == 1) + if (ret == 1) tuner_addrs = tuner_addrs >> 8; else break; } + if (tuner_addrs == 0) { - tuner_addrs = 0x61; - tuner_info("could not clearly identify tuner address, defaulting to %x\n", - tuner_addrs); + tuner_addrs = 0x60; + tuner_info("could not clearly identify tuner address, " + "defaulting to %x\n", tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; tuner_info("setting tuner address to %x\n", tuner_addrs); @@ -727,42 +571,181 @@ struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - tda8290_i2c_bridge(fe, 1); + analog_ops->i2c_gate_ctrl(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); - if( ret != 1) - tuner_warn("TDA827x access failed!\n"); - - memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - if ((data & 0x3c) == 0) { - strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75", - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = 55000000; - fe->ops.tuner_ops.info.frequency_max = 860000000; - fe->ops.tuner_ops.info.frequency_step = 250000; - priv->tda827x_ver = 0; + + if (ret != 1) { + tuner_warn("tuner access failed!\n"); + return -EREMOTEIO; + } + + if ((data == 0x83) || (data == 0x84)) { + priv->ver |= TDA18271; + tda18271_attach(fe, priv->tda827x_addr, + priv->i2c_props.adap, + &tda829x_tda18271_config); } else { - strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a", - sizeof(fe->ops.tuner_ops.info.name)); - fe->ops.tuner_ops.info.frequency_min = 44000000; - fe->ops.tuner_ops.info.frequency_max = 906000000; - fe->ops.tuner_ops.info.frequency_step = 62500; - priv->tda827x_ver = 2; + if ((data & 0x3c) == 0) + priv->ver |= TDA8275; + else + priv->ver |= TDA8275A; + + tda827x_attach(fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); + } + if (fe->ops.tuner_ops.init) + fe->ops.tuner_ops.init(fe); + + if (fe->ops.tuner_ops.sleep) + fe->ops.tuner_ops.sleep(fe); + + analog_ops->i2c_gate_ctrl(fe, 0); + + return 0; +} + +static int tda8290_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8290_ID 0x89 + unsigned char tda8290_id[] = { 0x1f, 0x00 }; + + /* detect tda8290 */ + tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1); + tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1); + + if (tda8290_id[1] == TDA8290_ID) { + if (debug) + printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", + __FUNCTION__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; + } + + return -ENODEV; +} + +static int tda8295_probe(struct tuner_i2c_props *i2c_props) +{ +#define TDA8295_ID 0x8a + unsigned char tda8295_id[] = { 0x2f, 0x00 }; + + /* detect tda8295 */ + tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1); + tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); + + if (tda8295_id[1] == TDA8295_ID) { + if (debug) + printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n", + __FUNCTION__, i2c_adapter_id(i2c_props->adap), + i2c_props->addr); + return 0; } - priv->tda827x_lpsel = 0; + return -ENODEV; +} + +static struct analog_demod_ops tda8290_ops = { + .set_params = tda8290_set_params, + .has_signal = tda8290_has_signal, + .standby = tda8290_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8290_i2c_bridge, +}; + +static struct analog_demod_ops tda8295_ops = { + .set_params = tda8295_set_params, + .has_signal = tda8295_has_signal, + .standby = tda8295_standby, + .release = tda829x_release, + .i2c_gate_ctrl = tda8295_i2c_bridge, +}; + +struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, + struct tda829x_config *cfg) +{ + struct tda8290_priv *priv = NULL; + char *name; + + priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); + if (priv == NULL) + return NULL; + fe->analog_demod_priv = priv; + + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + if (cfg) { + priv->cfg.config = cfg->lna_cfg; + priv->cfg.tuner_callback = cfg->tuner_callback; + } + + if (tda8290_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8290; + memcpy(&fe->ops.analog_ops, &tda8290_ops, + sizeof(struct analog_demod_ops)); + } + + if (tda8295_probe(&priv->i2c_props) == 0) { + priv->ver = TDA8295; + memcpy(&fe->ops.analog_ops, &tda8295_ops, + sizeof(struct analog_demod_ops)); + } + + if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) && + (tda829x_find_tuner(fe) < 0)) + goto fail; + + switch (priv->ver) { + case TDA8290: + name = "tda8290"; + break; + case TDA8295: + name = "tda8295"; + break; + case TDA8290 | TDA8275: + name = "tda8290+75"; + break; + case TDA8295 | TDA8275: + name = "tda8295+75"; + break; + case TDA8290 | TDA8275A: + name = "tda8290+75a"; + break; + case TDA8295 | TDA8275A: + name = "tda8295+75a"; + break; + case TDA8290 | TDA18271: + name = "tda8290+18271"; + break; + case TDA8295 | TDA18271: + name = "tda8295+18271"; + break; + default: + goto fail; + } + tuner_info("type set to %s\n", name); + + fe->ops.analog_ops.info.name = name; + + if (priv->ver & TDA8290) { + tda8290_init_tuner(fe); + tda8290_init_if(fe); + } else if (priv->ver & TDA8295) + tda8295_init_if(fe); - tda8290_init_tuner(fe); - tda8290_init_if(fe); return fe; + +fail: + tda829x_release(fe); + return NULL; } +EXPORT_SYMBOL_GPL(tda829x_attach); -int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) { struct tuner_i2c_props i2c_props = { .adap = i2c_adap, - .addr = i2c_addr + .addr = i2c_addr, }; unsigned char soft_reset[] = { 0x00, 0x00 }; @@ -771,7 +754,27 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; unsigned char addr_dto_lsb = 0x07; unsigned char data; +#define PROBE_BUFFER_SIZE 8 + unsigned char buf[PROBE_BUFFER_SIZE]; + int i; + + /* rule out tda9887, which would return the same byte repeatedly */ + tuner_i2c_xfer_send(&i2c_props, soft_reset, 1); + tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE); + for (i = 1; i < PROBE_BUFFER_SIZE; i++) { + if (buf[i] != buf[0]) + break; + } + /* all bytes are equal, not a tda829x - probably a tda9887 */ + if (i == PROBE_BUFFER_SIZE) + return -ENODEV; + + if ((tda8290_probe(&i2c_props) == 0) || + (tda8295_probe(&i2c_props) == 0)) + return 0; + + /* fall back to old probing method */ tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1); @@ -786,14 +789,12 @@ int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) } } tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); - return -1; + return -ENODEV; } +EXPORT_SYMBOL_GPL(tda829x_probe); -EXPORT_SYMBOL_GPL(tda8290_probe); -EXPORT_SYMBOL_GPL(tda8290_attach); - -MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver"); -MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann"); +MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); +MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); MODULE_LICENSE("GPL"); /* diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h index 107b24b05aa1..dc8ef310b7b2 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/video/tda8290.h @@ -20,33 +20,36 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -struct tda8290_config -{ +struct tda829x_config { unsigned int *lna_cfg; - int (*tuner_callback) (void *dev, int command,int arg); + int (*tuner_callback) (void *dev, int command, int arg); + + unsigned int probe_tuner:1; +#define TDA829X_PROBE_TUNER 0 +#define TDA829X_DONT_PROBE 1 }; #if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) -extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr); +extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); -extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, +extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct tda8290_config *cfg); + struct tda829x_config *cfg); #else -static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr) +static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) { - printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", - __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); return -EINVAL; } -static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe, - struct i2c_adapter* i2c_adap, +static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, - struct tda8290_config *cfg) + struct tda829x_config *cfg) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); return NULL; } #endif diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c index d11044170872..3c0557130a70 100644 --- a/drivers/media/video/tda9875.c +++ b/drivers/media/video/tda9875.c @@ -7,6 +7,7 @@ * * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and * Eric Sandeen + * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org> * This code is placed under the terms of the GNU General Public License * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 @@ -268,87 +269,143 @@ static int tda9875_detach(struct i2c_client *client) return 0; } -static int tda9875_command(struct i2c_client *client, - unsigned int cmd, void *arg) +static int tda9875_get_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) { struct tda9875 *t = i2c_get_clientdata(client); - dprintk("In tda9875_command...\n"); + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + { + int left = (t->lvol+84)*606; + int right = (t->rvol+84)*606; - switch (cmd) { - /* --- v4l ioctls --- */ - /* take care: bttv does userspace copying, we'll get a - kernel pointer here... */ - case VIDIOCGAUDIO: + ctrl->value=max(left,right); + return 0; + } + case V4L2_CID_AUDIO_BALANCE: { - struct video_audio *va = arg; - int left,right; + int left = (t->lvol+84)*606; + int right = (t->rvol+84)*606; + int volume = max(left,right); + int balance = (32768*min(left,right))/ + (volume ? volume : 1); + ctrl->value=(left<right)? + (65535-balance) : balance; + return 0; + } + case V4L2_CID_AUDIO_BASS: + ctrl->value = (t->bass+12)*2427; /* min -12 max +15 */ + return 0; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */ + return 0; + } + return -EINVAL; +} - dprintk("VIDIOCGAUDIO\n"); +static int tda9875_set_ctrl(struct i2c_client *client, + struct v4l2_control *ctrl) +{ + struct tda9875 *t = i2c_get_clientdata(client); + int chvol=0, volume, balance, left, right; - va->flags |= VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + left = (t->lvol+84)*606; + right = (t->rvol+84)*606; + + volume = max(left,right); + balance = (32768*min(left,right))/ + (volume ? volume : 1); + balance =(left<right)? + (65535-balance) : balance; + + volume = ctrl->value; - /* min is -84 max is 24 */ + chvol=1; + break; + case V4L2_CID_AUDIO_BALANCE: left = (t->lvol+84)*606; right = (t->rvol+84)*606; - va->volume=max(left,right); - va->balance=(32768*min(left,right))/ - (va->volume ? va->volume : 1); - va->balance=(left<right)? - (65535-va->balance) : va->balance; - va->bass = (t->bass+12)*2427; /* min -12 max +15 */ - va->treble = (t->treble+12)*2730;/* min -12 max +12 */ - va->mode |= VIDEO_SOUND_MONO; - - break; /* VIDIOCGAUDIO case */ + + volume=max(left,right); + + balance = ctrl->value; + + chvol=1; + break; + case V4L2_CID_AUDIO_BASS: + t->bass = ((ctrl->value/2400)-12) & 0xff; + if (t->bass > 15) + t->bass = 15; + if (t->bass < -12) + t->bass = -12 & 0xff; + break; + case V4L2_CID_AUDIO_TREBLE: + t->treble = ((ctrl->value/2700)-12) & 0xff; + if (t->treble > 12) + t->treble = 12; + if (t->treble < -12) + t->treble = -12 & 0xff; + break; + default: + return -EINVAL; } - case VIDIOCSAUDIO: - { - struct video_audio *va = arg; - int left,right; - - dprintk("VIDEOCSAUDIO...\n"); - left = (min(65536 - va->balance,32768) * - va->volume) / 32768; - right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; + if (chvol) { + left = (min(65536 - balance,32768) * + volume) / 32768; + right = (min(balance,32768) * + volume) / 32768; t->lvol = ((left/606)-84) & 0xff; if (t->lvol > 24) - t->lvol = 24; + t->lvol = 24; if (t->lvol < -84) - t->lvol = -84 & 0xff; + t->lvol = -84 & 0xff; t->rvol = ((right/606)-84) & 0xff; if (t->rvol > 24) - t->rvol = 24; + t->rvol = 24; if (t->rvol < -84) - t->rvol = -84 & 0xff; - - t->bass = ((va->bass/2400)-12) & 0xff; - if (t->bass > 15) - t->bass = 15; - if (t->bass < -12) - t->bass = -12 & 0xff; - - t->treble = ((va->treble/2700)-12) & 0xff; - if (t->treble > 12) - t->treble = 12; - if (t->treble < -12) - t->treble = -12 & 0xff; + t->rvol = -84 & 0xff; + } +//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + tda9875_set(client); -//printk("tda9875 bal:%04x vol:%04x bass:%04x treble:%04x\n",va->balance,va->volume,va->bass,va->treble); + return 0; +} - tda9875_set(client); +static int tda9875_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + dprintk("In tda9875_command...\n"); - break; + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + default: + return -EINVAL; + } + return v4l2_ctrl_query_fill_std(qc); + } + case VIDIOC_S_CTRL: + return tda9875_set_ctrl(client, arg); - } /* end of VIDEOCSAUDIO case */ + case VIDIOC_G_CTRL: + return tda9875_get_ctrl(client, arg); default: /* Not VIDEOCGAUDIO or VIDEOCSAUDIO */ diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c index be5387f11afb..106c93b8203f 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/video/tda9887.c @@ -9,7 +9,8 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/tuner.h> -#include "tuner-driver.h" +#include "tuner-i2c.h" +#include "tda9887.h" /* Chips: @@ -20,18 +21,20 @@ Used as part of several tuners */ -#define tda9887_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#define tda9887_dbg(fmt, arg...) do {\ - if (tuner_debug) \ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +#define PREFIX "tda9887" struct tda9887_priv { struct tuner_i2c_props i2c_props; unsigned char data[4]; + unsigned int config; + unsigned int mode; + unsigned int audmode; + v4l2_std_id std; }; /* ---------------------------------------------------------------------- */ @@ -262,8 +265,10 @@ static struct tvnorm radio_mono = { /* ---------------------------------------------------------------------- */ -static void dump_read_message(struct tuner *t, unsigned char *buf) +static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *afc[16] = { "- 12.5 kHz", "- 37.5 kHz", @@ -282,16 +287,18 @@ static void dump_read_message(struct tuner *t, unsigned char *buf) "+ 37.5 kHz", "+ 12.5 kHz", }; - tda9887_info("read: 0x%2x\n", buf[0]); - tda9887_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); - tda9887_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); - tda9887_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); - tda9887_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); - tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); + tuner_info("read: 0x%2x\n", buf[0]); + tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); + tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); + tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); + tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); + tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); } -static void dump_write_message(struct tuner *t, unsigned char *buf) +static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) { + struct tda9887_priv *priv = fe->analog_demod_priv; + static char *sound[4] = { "AM/TV", "FM/radio", @@ -330,86 +337,90 @@ static void dump_write_message(struct tuner *t, unsigned char *buf) "44 MHz", }; - tda9887_info("write: byte B 0x%02x\n",buf[1]); - tda9887_info(" B0 video mode : %s\n", - (buf[1] & 0x01) ? "video trap" : "sound trap"); - tda9887_info(" B1 auto mute fm : %s\n", - (buf[1] & 0x02) ? "yes" : "no"); - tda9887_info(" B2 carrier mode : %s\n", - (buf[1] & 0x04) ? "QSS" : "Intercarrier"); - tda9887_info(" B3-4 tv sound/radio : %s\n", - sound[(buf[1] & 0x18) >> 3]); - tda9887_info(" B5 force mute audio: %s\n", - (buf[1] & 0x20) ? "yes" : "no"); - tda9887_info(" B6 output port 1 : %s\n", - (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); - tda9887_info(" B7 output port 2 : %s\n", - (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); - - tda9887_info("write: byte C 0x%02x\n",buf[2]); - tda9887_info(" C0-4 top adjustment : %s dB\n", adjust[buf[2] & 0x1f]); - tda9887_info(" C5-6 de-emphasis : %s\n", deemph[(buf[2] & 0x60) >> 5]); - tda9887_info(" C7 audio gain : %s\n", - (buf[2] & 0x80) ? "-6" : "0"); - - tda9887_info("write: byte E 0x%02x\n",buf[3]); - tda9887_info(" E0-1 sound carrier : %s\n", - carrier[(buf[3] & 0x03)]); - tda9887_info(" E6 l pll gating : %s\n", - (buf[3] & 0x40) ? "36" : "13"); + tuner_info("write: byte B 0x%02x\n", buf[1]); + tuner_info(" B0 video mode : %s\n", + (buf[1] & 0x01) ? "video trap" : "sound trap"); + tuner_info(" B1 auto mute fm : %s\n", + (buf[1] & 0x02) ? "yes" : "no"); + tuner_info(" B2 carrier mode : %s\n", + (buf[1] & 0x04) ? "QSS" : "Intercarrier"); + tuner_info(" B3-4 tv sound/radio : %s\n", + sound[(buf[1] & 0x18) >> 3]); + tuner_info(" B5 force mute audio: %s\n", + (buf[1] & 0x20) ? "yes" : "no"); + tuner_info(" B6 output port 1 : %s\n", + (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); + tuner_info(" B7 output port 2 : %s\n", + (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); + + tuner_info("write: byte C 0x%02x\n", buf[2]); + tuner_info(" C0-4 top adjustment : %s dB\n", + adjust[buf[2] & 0x1f]); + tuner_info(" C5-6 de-emphasis : %s\n", + deemph[(buf[2] & 0x60) >> 5]); + tuner_info(" C7 audio gain : %s\n", + (buf[2] & 0x80) ? "-6" : "0"); + + tuner_info("write: byte E 0x%02x\n", buf[3]); + tuner_info(" E0-1 sound carrier : %s\n", + carrier[(buf[3] & 0x03)]); + tuner_info(" E6 l pll gating : %s\n", + (buf[3] & 0x40) ? "36" : "13"); if (buf[1] & 0x08) { /* radio */ - tda9887_info(" E2-4 video if : %s\n", - rif[(buf[3] & 0x0c) >> 2]); - tda9887_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x10) ? "fm-agc radio" : "sif-agc radio") - : "fm radio carrier afc"); + tuner_info(" E2-4 video if : %s\n", + rif[(buf[3] & 0x0c) >> 2]); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x10) ? "fm-agc radio" : + "sif-agc radio") + : "fm radio carrier afc"); } else { /* video */ - tda9887_info(" E2-4 video if : %s\n", - vif[(buf[3] & 0x1c) >> 2]); - tda9887_info(" E5 tuner gain : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) ? "external" : "normal") - : ((buf[3] & 0x20) ? "minimum" : "normal")); - tda9887_info(" E7 vif agc output : %s\n", - (buf[3] & 0x80) - ? ((buf[3] & 0x20) - ? "pin3 port, pin22 vif agc out" - : "pin22 port, pin3 vif acg ext in") - : "pin3+pin22 port"); + tuner_info(" E2-4 video if : %s\n", + vif[(buf[3] & 0x1c) >> 2]); + tuner_info(" E5 tuner gain : %s\n", + (buf[3] & 0x80) + ? ((buf[3] & 0x20) ? "external" : "normal") + : ((buf[3] & 0x20) ? "minimum" : "normal")); + tuner_info(" E7 vif agc output : %s\n", + (buf[3] & 0x80) ? ((buf[3] & 0x20) + ? "pin3 port, pin22 vif agc out" + : "pin22 port, pin3 vif acg ext in") + : "pin3+pin22 port"); } - tda9887_info("--\n"); + tuner_info("--\n"); } /* ---------------------------------------------------------------------- */ -static int tda9887_set_tvnorm(struct tuner *t, char *buf) +static int tda9887_set_tvnorm(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; struct tvnorm *norm = NULL; + char *buf = priv->data; int i; - if (t->mode == V4L2_TUNER_RADIO) { - if (t->audmode == V4L2_TUNER_MODE_MONO) + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->audmode == V4L2_TUNER_MODE_MONO) norm = &radio_mono; else norm = &radio_stereo; } else { for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { - if (tvnorms[i].std & t->std) { + if (tvnorms[i].std & priv->std) { norm = tvnorms+i; break; } } } if (NULL == norm) { - tda9887_dbg("Unsupported tvnorm entry - audio muted\n"); + tuner_dbg("Unsupported tvnorm entry - audio muted\n"); return -1; } - tda9887_dbg("configure for: %s\n",norm->name); + tuner_dbg("configure for: %s\n", norm->name); buf[1] = norm->b; buf[2] = norm->c; buf[3] = norm->e; @@ -426,8 +437,11 @@ module_param(port2, int, 0644); module_param(qss, int, 0644); module_param(adjust, int, 0644); -static int tda9887_set_insmod(struct tuner *t, char *buf) +static int tda9887_set_insmod(struct dvb_frontend *fe) { + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + if (UNSET != port1) { if (port1) buf[1] |= cOutputPort1Inactive; @@ -455,27 +469,30 @@ static int tda9887_set_insmod(struct tuner *t, char *buf) return 0; } -static int tda9887_set_config(struct tuner *t, char *buf) +static int tda9887_do_config(struct dvb_frontend *fe) { - if (t->tda9887_config & TDA9887_PORT1_ACTIVE) + struct tda9887_priv *priv = fe->analog_demod_priv; + char *buf = priv->data; + + if (priv->config & TDA9887_PORT1_ACTIVE) buf[1] &= ~cOutputPort1Inactive; - if (t->tda9887_config & TDA9887_PORT1_INACTIVE) + if (priv->config & TDA9887_PORT1_INACTIVE) buf[1] |= cOutputPort1Inactive; - if (t->tda9887_config & TDA9887_PORT2_ACTIVE) + if (priv->config & TDA9887_PORT2_ACTIVE) buf[1] &= ~cOutputPort2Inactive; - if (t->tda9887_config & TDA9887_PORT2_INACTIVE) + if (priv->config & TDA9887_PORT2_INACTIVE) buf[1] |= cOutputPort2Inactive; - if (t->tda9887_config & TDA9887_QSS) + if (priv->config & TDA9887_QSS) buf[1] |= cQSS; - if (t->tda9887_config & TDA9887_INTERCARRIER) + if (priv->config & TDA9887_INTERCARRIER) buf[1] &= ~cQSS; - if (t->tda9887_config & TDA9887_AUTOMUTE) + if (priv->config & TDA9887_AUTOMUTE) buf[1] |= cAutoMuteFmActive; - if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { + if (priv->config & TDA9887_DEEMPHASIS_MASK) { buf[2] &= ~0x60; - switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) { + switch (priv->config & TDA9887_DEEMPHASIS_MASK) { case TDA9887_DEEMPHASIS_NONE: buf[2] |= cDeemphasisOFF; break; @@ -487,21 +504,22 @@ static int tda9887_set_config(struct tuner *t, char *buf) break; } } - if (t->tda9887_config & TDA9887_TOP_SET) { + if (priv->config & TDA9887_TOP_SET) { buf[2] &= ~cTopMask; - buf[2] |= (t->tda9887_config >> 8) & cTopMask; + buf[2] |= (priv->config >> 8) & cTopMask; } - if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC)) + if ((priv->config & TDA9887_INTERCARRIER_NTSC) && + (priv->std & V4L2_STD_NTSC)) buf[1] &= ~cQSS; - if (t->tda9887_config & TDA9887_GATING_18) + if (priv->config & TDA9887_GATING_18) buf[3] &= ~cGating_36; - if (t->mode == V4L2_TUNER_RADIO) { - if (t->tda9887_config & TDA9887_RIF_41_3) { + if (priv->mode == V4L2_TUNER_RADIO) { + if (priv->config & TDA9887_RIF_41_3) { buf[3] &= ~cVideoIFMask; buf[3] |= cRadioIF_41_30; } - if (t->tda9887_config & TDA9887_GAIN_NORMAL) + if (priv->config & TDA9887_GAIN_NORMAL) buf[3] &= ~cTunerGainLow; } @@ -510,26 +528,26 @@ static int tda9887_set_config(struct tuner *t, char *buf) /* ---------------------------------------------------------------------- */ -static int tda9887_status(struct tuner *t) +static int tda9887_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; unsigned char buf[1]; int rc; memset(buf,0,sizeof(buf)); if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) - tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc); - dump_read_message(t, buf); + tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); + dump_read_message(fe, buf); return 0; } -static void tda9887_configure(struct tuner *t) +static void tda9887_configure(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; int rc; memset(priv->data,0,sizeof(priv->data)); - tda9887_set_tvnorm(t,priv->data); + tda9887_set_tvnorm(fe); /* A note on the port settings: These settings tend to depend on the specifics of the board. @@ -547,38 +565,38 @@ static void tda9887_configure(struct tuner *t) priv->data[1] |= cOutputPort1Inactive; priv->data[1] |= cOutputPort2Inactive; - tda9887_set_config(t,priv->data); - tda9887_set_insmod(t,priv->data); + tda9887_do_config(fe); + tda9887_set_insmod(fe); - if (t->mode == T_STANDBY) { + if (priv->mode == T_STANDBY) priv->data[1] |= cForcedMuteAudioON; - } - tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", - priv->data[1],priv->data[2],priv->data[3]); - if (tuner_debug > 1) - dump_write_message(t, priv->data); + tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); + if (debug > 1) + dump_write_message(fe, priv->data); if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) - tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc); + tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); - if (tuner_debug > 2) { + if (debug > 2) { msleep_interruptible(1000); - tda9887_status(t); + tda9887_status(fe); } } /* ---------------------------------------------------------------------- */ -static void tda9887_tuner_status(struct tuner *t) +static void tda9887_tuner_status(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; - tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]); + struct tda9887_priv *priv = fe->analog_demod_priv; + tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", + priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct tuner *t) +static int tda9887_get_afc(struct dvb_frontend *fe) { - struct tda9887_priv *priv = t->priv; + struct tda9887_priv *priv = fe->analog_demod_priv; static int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, @@ -594,52 +612,79 @@ static int tda9887_get_afc(struct tuner *t) return afc; } -static void tda9887_standby(struct tuner *t) +static void tda9887_standby(struct dvb_frontend *fe) +{ + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->mode = T_STANDBY; + + tda9887_configure(fe); +} + +static void tda9887_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - tda9887_configure(t); + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->mode = params->mode; + priv->audmode = params->audmode; + priv->std = params->std; + tda9887_configure(fe); } -static void tda9887_set_freq(struct tuner *t, unsigned int freq) +static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) { - tda9887_configure(t); + struct tda9887_priv *priv = fe->analog_demod_priv; + + priv->config = *(unsigned int *)priv_cfg; + tda9887_configure(fe); + + return 0; } -static void tda9887_release(struct tuner *t) +static void tda9887_release(struct dvb_frontend *fe) { - kfree(t->priv); - t->priv = NULL; + kfree(fe->analog_demod_priv); + fe->analog_demod_priv = NULL; } -static struct tuner_operations tda9887_tuner_ops = { - .set_tv_freq = tda9887_set_freq, - .set_radio_freq = tda9887_set_freq, +static struct analog_demod_ops tda9887_ops = { + .info = { + .name = "tda9887", + }, + .set_params = tda9887_set_params, .standby = tda9887_standby, .tuner_status = tda9887_tuner_status, .get_afc = tda9887_get_afc, .release = tda9887_release, + .set_config = tda9887_set_config, }; -int tda9887_tuner_init(struct tuner *t) +struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) { struct tda9887_priv *priv = NULL; priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; - t->priv = priv; - - priv->i2c_props.addr = t->i2c.addr; - priv->i2c_props.adap = t->i2c.adapter; + return NULL; + fe->analog_demod_priv = priv; - strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name)); + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->mode = T_STANDBY; - tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr, - t->i2c.driver->driver.name); + tuner_info("tda988[5/6/7] found\n"); - memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations)); + memcpy(&fe->ops.analog_ops, &tda9887_ops, + sizeof(struct analog_demod_ops)); - return 0; + return fe; } +EXPORT_SYMBOL_GPL(tda9887_attach); + +MODULE_LICENSE("GPL"); /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/tda9887.h b/drivers/media/video/tda9887.h new file mode 100644 index 000000000000..8f873a8e6ed2 --- /dev/null +++ b/drivers/media/video/tda9887.h @@ -0,0 +1,38 @@ +/* + 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 __TDA9887_H__ +#define __TDA9887_H__ + +#include <linux/i2c.h> +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------ */ +#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) +extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr); +#else +static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + return NULL; +} +#endif + +#endif /* __TDA9887_H__ */ diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c index 2150222a3860..5326eeceaacd 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/video/tea5761.c @@ -18,7 +18,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5761 " +#define PREFIX "tea5761" struct tea5761_priv { struct tuner_i2c_props i2c_props; diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c index 71df419df7bc..e1b48d87e7b7 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/video/tea5767.c @@ -20,12 +20,14 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tea5767 " +#define PREFIX "tea5767" -struct tea5767_priv { - struct tuner_i2c_props i2c_props; +/*****************************************************************************/ - u32 frequency; +struct tea5767_priv { + struct tuner_i2c_props i2c_props; + u32 frequency; + struct tea5767_ctrl ctrl; }; /*****************************************************************************/ @@ -127,17 +129,10 @@ struct tea5767_priv { /* Reserved for future extensions */ #define TEA5767_RESERVED_MASK 0xff -enum tea5767_xtal_freq { - TEA5767_LOW_LO_32768 = 0, - TEA5767_HIGH_LO_32768 = 1, - TEA5767_LOW_LO_13MHz = 2, - TEA5767_HIGH_LO_13MHz = 3, -}; - - /*****************************************************************************/ -static void tea5767_status_dump(unsigned char *buffer) +static void tea5767_status_dump(struct tea5767_priv *priv, + unsigned char *buffer) { unsigned int div, frq; @@ -153,7 +148,7 @@ static void tea5767_status_dump(unsigned char *buffer) div = ((buffer[0] & 0x3f) << 8) | buffer[1]; - switch (TEA5767_HIGH_LO_32768) { + switch (priv->ctrl.xtal_freq) { case TEA5767_HIGH_LO_13MHz: frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ break; @@ -202,13 +197,10 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); - /* Rounds freq to next decimal value - for 62.5 KHz step */ - /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + buffer[2] = 0; - buffer[2] = TEA5767_PORT1_HIGH; - buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | - TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND; - buffer[4] = 0; + if (priv->ctrl.port1) + buffer[2] |= TEA5767_PORT1_HIGH; if (params->audmode == V4L2_TUNER_MODE_MONO) { tuner_dbg("TEA5767 set to mono\n"); @@ -217,18 +209,45 @@ static int set_radio_freq(struct dvb_frontend *fe, tuner_dbg("TEA5767 set to stereo\n"); } - /* Should be replaced */ - switch (TEA5767_HIGH_LO_32768) { + + buffer[3] = 0; + + if (priv->ctrl.port2) + buffer[3] |= TEA5767_PORT2_HIGH; + + if (priv->ctrl.high_cut) + buffer[3] |= TEA5767_HIGH_CUT_CTRL; + + if (priv->ctrl.st_noise) + buffer[3] |= TEA5767_ST_NOISE_CTL; + + if (priv->ctrl.soft_mute) + buffer[3] |= TEA5767_SOFT_MUTE; + + if (priv->ctrl.japan_band) + buffer[3] |= TEA5767_JAPAN_BAND; + + buffer[4] = 0; + + if (priv->ctrl.deemph_75) + buffer[4] |= TEA5767_DEEMPH_75; + + if (priv->ctrl.pllref) + buffer[4] |= TEA5767_PLLREF_ENABLE; + + + /* Rounds freq to next decimal value - for 62.5 KHz step */ + /* frq = 20*(frq/16)+radio_frq[frq%16]; */ + + switch (priv->ctrl.xtal_freq) { case TEA5767_HIGH_LO_13MHz: tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); buffer[2] |= TEA5767_HIGH_LO_INJECT; - buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_13MHz: tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); - buffer[4] |= TEA5767_PLLREF_ENABLE; div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; break; case TEA5767_LOW_LO_32768: @@ -256,7 +275,7 @@ static int set_radio_freq(struct dvb_frontend *fe, if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); else - tea5767_status_dump(buffer); + tea5767_status_dump(priv, buffer); } priv->frequency = frq * 125 / 2; @@ -382,7 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return EINVAL; } - printk(KERN_WARNING "TEA5767 detected.\n"); return 0; } @@ -398,6 +416,16 @@ static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5767_priv *priv = fe->tuner_priv; *frequency = priv->frequency; + + return 0; +} + +static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) +{ + struct tea5767_priv *priv = fe->tuner_priv; + + memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); + return 0; } @@ -407,6 +435,7 @@ static struct dvb_tuner_ops tea5767_tuner_ops = { }, .set_analog_params = set_radio_freq, + .set_config = tea5767_set_config, .sleep = tea5767_standby, .release = tea5767_release, .get_frequency = tea5767_get_frequency, @@ -425,8 +454,14 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return NULL; fe->tuner_priv = priv; - priv->i2c_props.addr = i2c_addr; - priv->i2c_props.adap = i2c_adap; + priv->i2c_props.addr = i2c_addr; + priv->i2c_props.adap = i2c_adap; + priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; + priv->ctrl.port1 = 1; + priv->ctrl.port2 = 1; + priv->ctrl.high_cut = 1; + priv->ctrl.st_noise = 1; + priv->ctrl.japan_band = 1; memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, sizeof(struct dvb_tuner_ops)); @@ -436,7 +471,6 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, return fe; } - EXPORT_SYMBOL_GPL(tea5767_attach); EXPORT_SYMBOL_GPL(tea5767_autodetection); diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h index 5d78281adcc2..a44451f61145 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/video/tea5767.h @@ -20,6 +20,25 @@ #include <linux/i2c.h> #include "dvb_frontend.h" +enum tea5767_xtal { + TEA5767_LOW_LO_32768 = 0, + TEA5767_HIGH_LO_32768 = 1, + TEA5767_LOW_LO_13MHz = 2, + TEA5767_HIGH_LO_13MHz = 3, +}; + +struct tea5767_ctrl { + unsigned int port1:1; + unsigned int port2:1; + unsigned int high_cut:1; + unsigned int st_noise:1; + unsigned int soft_mute:1; + unsigned int japan_band:1; + unsigned int deemph_75:1; + unsigned int pllref:1; + enum tea5767_xtal xtal_freq; +}; + #if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index 76b2e96429d9..dc7b9c220b90 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -31,6 +31,7 @@ #include <linux/i2c-id.h> #include <linux/videodev.h> #include <media/v4l2-common.h> +#include <media/v4l2-i2c-drv-legacy.h> MODULE_DESCRIPTION("tlv320aic23b driver"); MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil"); @@ -56,37 +57,35 @@ static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val) return -1; } - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, (reg << 1) | - (val >> 8), val & 0xff) == 0) { + for (i = 0; i < 3; i++) + if (i2c_smbus_write_byte_data(client, + (reg << 1) | (val >> 8), val & 0xff) == 0) return 0; - } - } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } -static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int tlv320aic23b_command(struct i2c_client *client, + unsigned int cmd, void *arg) { struct tlv320aic23b_state *state = i2c_get_clientdata(client); struct v4l2_control *ctrl = arg; - u32* freq = arg; + u32 *freq = arg; switch (cmd) { case VIDIOC_INT_AUDIO_CLOCK_FREQ: switch (*freq) { - case 32000: /* set sample rate to 32 kHz */ - tlv320aic23b_write(client, 8, 0x018); - break; - case 44100: /* set sample rate to 44.1 kHz */ - tlv320aic23b_write(client, 8, 0x022); - break; - case 48000: /* set sample rate to 48 kHz */ - tlv320aic23b_write(client, 8, 0x000); - break; - default: - return -EINVAL; + case 32000: /* set sample rate to 32 kHz */ + tlv320aic23b_write(client, 8, 0x018); + break; + case 44100: /* set sample rate to 44.1 kHz */ + tlv320aic23b_write(client, 8, 0x022); + break; + case 48000: /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 8, 0x000); + break; + default: + return -EINVAL; } break; @@ -126,92 +125,53 @@ static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind) +static int tlv320aic23b_probe(struct i2c_client *client) { - struct i2c_client *client; struct tlv320aic23b_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); + if (state == NULL) return -ENOMEM; - } state->muted = 0; i2c_set_clientdata(client, state); - /* initialize tlv320aic23b */ - tlv320aic23b_write(client, 15, 0x000); /* RESET */ - tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */ - tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */ - tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */ - tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */ - tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */ - - i2c_attach_client(client); - + /* Initialize tlv320aic23b */ + + /* RESET */ + tlv320aic23b_write(client, 15, 0x000); + /* turn off DAC & mic input */ + tlv320aic23b_write(client, 6, 0x00A); + /* left-justified, 24-bit, master mode */ + tlv320aic23b_write(client, 7, 0x049); + /* set gain on both channels to +3.0 dB */ + tlv320aic23b_write(client, 0, 0x119); + /* set sample rate to 48 kHz */ + tlv320aic23b_write(client, 8, 0x000); + /* activate digital interface */ + tlv320aic23b_write(client, 9, 0x001); return 0; } -static int tlv320aic23b_probe(struct i2c_adapter *adapter) +static int tlv320aic23b_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, tlv320aic23b_attach); - return 0; -} - -static int tlv320aic23b_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "tlv320aic23b", - }, - .id = I2C_DRIVERID_TLV320AIC23B, - .attach_adapter = tlv320aic23b_probe, - .detach_client = tlv320aic23b_detach, - .command = tlv320aic23b_command, -}; - -static int __init tlv320aic23b_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit tlv320aic23b_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(tlv320aic23b_init_module); -module_exit(tlv320aic23b_cleanup_module); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tlv320aic23b", + .driverid = I2C_DRIVERID_TLV320AIC23B, + .command = tlv320aic23b_command, + .probe = tlv320aic23b_probe, + .remove = tlv320aic23b_remove, +}; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 9e99f3636d3d..ba538f6fbcc3 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -19,15 +19,41 @@ #include <media/tuner.h> #include <media/tuner-types.h> #include <media/v4l2-common.h> -#include "tuner-driver.h" +#include <media/v4l2-i2c-drv-legacy.h> #include "mt20xx.h" #include "tda8290.h" #include "tea5761.h" #include "tea5767.h" +#include "tuner-xc2028.h" #include "tuner-simple.h" +#include "tda9887.h" +#include "xc5000.h" #define UNSET (-1U) +#define PREFIX t->i2c->driver->driver.name + +struct tuner { + /* device */ + struct dvb_frontend fe; + struct i2c_client *i2c; + struct list_head list; + unsigned int using_v4l2:1; + + /* keep track of the current settings */ + v4l2_std_id std; + unsigned int tv_freq; + unsigned int radio_freq; + unsigned int audmode; + + unsigned int mode; + unsigned int mode_mask; /* Combination of allowable modes */ + + unsigned int type; /* chip type id */ + unsigned int config; + int (*tuner_callback) (void *dev, int command, int arg); +}; + /* standard i2c insmod options */ static unsigned short normal_i2c[] = { #if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) @@ -47,7 +73,34 @@ static unsigned int no_autodetect = 0; static unsigned int show_i2c = 0; /* insmod options used at runtime => read/write */ -int tuner_debug = 0; +static int tuner_debug; + +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + if (tuner_debug) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(t->i2c->adapter), \ + t->i2c->addr, ##arg); \ + } while (0) + +/* ------------------------------------------------------------------------ */ static unsigned int tv_range[2] = { 44, 958 }; static unsigned int radio_range[2] = { 65, 108 }; @@ -71,66 +124,96 @@ MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners"); MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); MODULE_LICENSE("GPL"); -static struct i2c_driver driver; -static struct i2c_client client_template; - /* ---------------------------------------------------------------------- */ -static void fe_set_freq(struct tuner *t, unsigned int freq) +static void fe_set_params(struct dvb_frontend *fe, + struct analog_parameters *params) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - - struct analog_parameters params = { - .frequency = freq, - .mode = t->mode, - .audmode = t->audmode, - .std = t->std - }; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct tuner *t = fe->analog_demod_priv; if (NULL == fe_tuner_ops->set_analog_params) { tuner_warn("Tuner frontend module has no way to set freq\n"); return; } - fe_tuner_ops->set_analog_params(&t->fe, ¶ms); + fe_tuner_ops->set_analog_params(fe, params); } -static void fe_release(struct tuner *t) +static void fe_release(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - - if (fe_tuner_ops->release) - fe_tuner_ops->release(&t->fe); + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + + /* DO NOT kfree(fe->analog_demod_priv) + * + * If we are in this function, analog_demod_priv contains a pointer + * to struct tuner *t. This will be kfree'd in tuner_detach(). + * + * Otherwise, fe->ops.analog_demod_ops->release will + * handle the cleanup for analog demodulator modules. + */ + fe->analog_demod_priv = NULL; } -static void fe_standby(struct tuner *t) +static void fe_standby(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; if (fe_tuner_ops->sleep) - fe_tuner_ops->sleep(&t->fe); + fe_tuner_ops->sleep(fe); } -static int fe_has_signal(struct tuner *t) +static int fe_has_signal(struct dvb_frontend *fe) { - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; u16 strength = 0; - if (fe_tuner_ops->get_rf_strength) - fe_tuner_ops->get_rf_strength(&t->fe, &strength); + if (fe->ops.tuner_ops.get_rf_strength) + fe->ops.tuner_ops.get_rf_strength(fe, &strength); return strength; } +static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct tuner *t = fe->analog_demod_priv; + + if (fe_tuner_ops->set_config) + return fe_tuner_ops->set_config(fe, priv_cfg); + + tuner_warn("Tuner frontend module has no way to set config\n"); + + return 0; +} + +static void tuner_status(struct dvb_frontend *fe); + +static struct analog_demod_ops tuner_core_ops = { + .set_params = fe_set_params, + .standby = fe_standby, + .release = fe_release, + .has_signal = fe_has_signal, + .set_config = fe_set_config, + .tuner_status = tuner_status +}; + /* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */ static void set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + struct analog_parameters params = { + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->ops.set_tv_freq) { + if (NULL == analog_ops->set_params) { tuner_warn ("Tuner has no way to set tv freq\n"); return; } @@ -145,18 +228,27 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) else freq = tv_range[1] * 16; } - t->ops.set_tv_freq(t, freq); + params.frequency = freq; + + analog_ops->set_params(&t->fe, ¶ms); } static void set_radio_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + struct analog_parameters params = { + .mode = t->mode, + .audmode = t->audmode, + .std = t->std + }; if (t->type == UNSET) { tuner_warn ("tuner type not set\n"); return; } - if (NULL == t->ops.set_radio_freq) { + if (NULL == analog_ops->set_params) { tuner_warn ("tuner has no way to set radio frequency\n"); return; } @@ -171,8 +263,9 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) else freq = radio_range[1] * 16000; } + params.frequency = freq; - t->ops.set_radio_freq(t, freq); + analog_ops->set_params(&t->fe, ¶ms); } static void set_freq(struct i2c_client *c, unsigned long freq) @@ -193,54 +286,65 @@ static void set_freq(struct i2c_client *c, unsigned long freq) set_tv_freq(c, freq); t->tv_freq = freq; break; + default: + tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); } } static void tuner_i2c_address_check(struct tuner *t) { if ((t->type == UNSET || t->type == TUNER_ABSENT) || - ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f))) + ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f))) + return; + + /* We already know that the XC5000 can only be located at + * i2c address 0x61, 0x62, 0x63 or 0x64 */ + if ((t->type == TUNER_XC5000) && + ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61)) return; tuner_warn("====================== WARNING! ======================\n"); tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n"); tuner_warn("will soon be dropped. This message indicates that your\n"); tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n", - t->i2c.name, t->i2c.addr); + t->i2c->name, t->i2c->addr); tuner_warn("To ensure continued support for your device, please\n"); tuner_warn("send a copy of this message, along with full dmesg\n"); tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n"); tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n"); tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n", - t->i2c.adapter->name, t->i2c.addr, t->type, + t->i2c->adapter->name, t->i2c->addr, t->type, tuners[t->type].name); tuner_warn("====================== WARNING! ======================\n"); } -static void attach_tda8290(struct tuner *t) -{ - struct tda8290_config cfg = { - .lna_cfg = &t->config, - .tuner_callback = t->tuner_callback - }; - tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); -} - static void attach_simple_tuner(struct tuner *t) { struct simple_tuner_config cfg = { .type = t->type, .tun = &tuners[t->type] }; - simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg); + simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } +static void attach_tda829x(struct tuner *t) +{ + struct tda829x_config cfg = { + .lna_cfg = &t->config, + .tuner_callback = t->tuner_callback, + }; + tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); +} + +static struct xc5000_config xc5000_cfg; + static void set_type(struct i2c_client *c, unsigned int type, unsigned int new_mode_mask, unsigned int new_config, int (*tuner_callback) (void *dev, int command,int arg)) { struct tuner *t = i2c_get_clientdata(c); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; unsigned char buffer[4]; if (type == UNSET || type == TUNER_ABSENT) { @@ -260,32 +364,27 @@ static void set_type(struct i2c_client *c, unsigned int type, t->tuner_callback = tuner_callback; } - /* This code detects calls by card attach_inform */ - if (NULL == t->i2c.dev.driver) { + if (t->mode == T_UNINITIALIZED) { tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr); return; } /* discard private data, in case set_type() was previously called */ - if (t->ops.release) - t->ops.release(t); - else { - kfree(t->priv); - t->priv = NULL; - } + if (analog_ops->release) + analog_ops->release(&t->fe); switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr); + microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_PHILIPS_TDA8290: { - attach_tda8290(t); + attach_tda829x(t); break; } case TUNER_TEA5767: - if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { + if (tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -293,7 +392,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) { + if (tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr) == NULL) { t->type = TUNER_ABSENT; t->mode_mask = T_UNINITIALIZED; return; @@ -320,25 +419,60 @@ static void set_type(struct i2c_client *c, unsigned int type, i2c_master_send(c,buffer,4); attach_simple_tuner(t); break; + case TUNER_XC2028: + { + struct xc2028_config cfg = { + .i2c_adap = t->i2c->adapter, + .i2c_addr = t->i2c->addr, + .video_dev = c->adapter->algo_data, + .callback = t->tuner_callback, + }; + if (!xc2028_attach(&t->fe, &cfg)) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + break; + } case TUNER_TDA9887: - tda9887_tuner_init(t); + tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + break; + case TUNER_XC5000: + xc5000_cfg.i2c_address = t->i2c->addr; + xc5000_cfg.if_khz = 5380; + xc5000_cfg.priv = c->adapter->algo_data; + xc5000_cfg.tuner_callback = t->tuner_callback; + if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) { + t->type = TUNER_ABSENT; + t->mode_mask = T_UNINITIALIZED; + return; + } + { + struct dvb_tuner_ops *xc_tuner_ops; + xc_tuner_ops = &t->fe.ops.tuner_ops; + if(xc_tuner_ops->init != NULL) + xc_tuner_ops->init(&t->fe); + } break; default: attach_simple_tuner(t); break; } - if (fe_tuner_ops->set_analog_params) { - strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name)); + if ((NULL == analog_ops->set_params) && + (fe_tuner_ops->set_analog_params)) { + strlcpy(t->i2c->name, fe_tuner_ops->info.name, + sizeof(t->i2c->name)); - t->ops.set_tv_freq = fe_set_freq; - t->ops.set_radio_freq = fe_set_freq; - t->ops.standby = fe_standby; - t->ops.release = fe_release; - t->ops.has_signal = fe_has_signal; + t->fe.analog_demod_priv = t; + memcpy(analog_ops, &tuner_core_ops, + sizeof(struct analog_demod_ops)); + } else { + strlcpy(t->i2c->name, analog_ops->info.name, + sizeof(t->i2c->name)); } - tuner_info("type set to %s\n", t->i2c.name); + tuner_dbg("type set to %s\n", t->i2c->name); if (t->mode_mask == T_UNINITIALIZED) t->mode_mask = new_mode_mask; @@ -508,10 +642,12 @@ static int tuner_fixup_std(struct tuner *t) return 0; } -static void tuner_status(struct tuner *t) +static void tuner_status(struct dvb_frontend *fe) { + struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; const char *p; switch (t->mode) { @@ -541,172 +677,16 @@ static void tuner_status(struct tuner *t) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if (t->ops.has_signal) { - tuner_info("Signal strength: %d\n", t->ops.has_signal(t)); - } - if (t->ops.is_stereo) { - tuner_info("Stereo: %s\n", t->ops.is_stereo(t) ? "yes" : "no"); - } + if (analog_ops->has_signal) + tuner_info("Signal strength: %d\n", + analog_ops->has_signal(fe)); + if (analog_ops->is_stereo) + tuner_info("Stereo: %s\n", + analog_ops->is_stereo(fe) ? "yes" : "no"); } /* ---------------------------------------------------------------------- */ -/* static vars: used only in tuner_attach and tuner_probe */ -static unsigned default_mode_mask; - -/* During client attach, set_type is called by adapter's attach_inform callback. - set_type must then be completed by tuner_attach. - */ -static int tuner_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct tuner *t; - - client_template.adapter = adap; - client_template.addr = addr; - - t = kzalloc(sizeof(struct tuner), GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - memcpy(&t->i2c, &client_template, sizeof(struct i2c_client)); - i2c_set_clientdata(&t->i2c, t); - t->type = UNSET; - t->audmode = V4L2_TUNER_MODE_STEREO; - t->mode_mask = T_UNINITIALIZED; - t->ops.tuner_status = tuner_status; - - if (show_i2c) { - unsigned char buffer[16]; - int i,rc; - - memset(buffer, 0, sizeof(buffer)); - rc = i2c_master_recv(&t->i2c, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i=0;i<rc;i++) - printk("%02x ",buffer[i]); - printk("\n"); - } - /* HACK: This test were added to avoid tuner to probe tda9840 and tea6415c on the MXB card */ - if (adap->id == I2C_HW_SAA7146 && addr < 0x4a) - return -ENODEV; - - /* autodetection code based on the i2c addr */ - if (!no_autodetect) { - switch (addr) { - case 0x10: - if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { - t->type = TUNER_TEA5761; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - case 0x42: - case 0x43: - case 0x4a: - case 0x4b: - /* If chip is not tda8290, don't register. - since it can be tda9887*/ - if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) { - tuner_dbg("chip at addr %x is a tda8290\n", addr); - } else { - /* Default is being tda9887 */ - t->type = TUNER_TDA9887; - t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - t->mode = T_STANDBY; - goto register_client; - } - break; - case 0x60: - if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) { - t->type = TUNER_TEA5767; - t->mode_mask = T_RADIO; - t->mode = T_STANDBY; - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask &= ~T_RADIO; - - goto register_client; - } - break; - } - } - - /* Initializes only the first adapter found */ - if (default_mode_mask != T_UNINITIALIZED) { - tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask); - t->mode_mask = default_mode_mask; - t->tv_freq = 400 * 16; /* Sets freq to VHF High */ - t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ - default_mode_mask = T_UNINITIALIZED; - } - - /* Should be just before return */ -register_client: - tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name); - i2c_attach_client (&t->i2c); - set_type (&t->i2c,t->type, t->mode_mask, t->config, t->tuner_callback); - return 0; -} - -static int tuner_probe(struct i2c_adapter *adap) -{ - if (0 != addr) { - normal_i2c[0] = addr; - normal_i2c[1] = I2C_CLIENT_END; - } - - /* HACK: Ignore 0x6b and 0x6f on cx88 boards. - * FusionHDTV5 RT Gold has an ir receiver at 0x6b - * and an RTC at 0x6f which can get corrupted if probed. - */ - if ((adap->id == I2C_HW_B_CX2388x) || - (adap->id == I2C_HW_B_CX23885)) { - unsigned int i = 0; - - while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) - i += 2; - if (i + 4 < I2C_CLIENT_MAX_OPTS) { - ignore[i+0] = adap->nr; - ignore[i+1] = 0x6b; - ignore[i+2] = adap->nr; - ignore[i+3] = 0x6f; - ignore[i+4] = I2C_CLIENT_END; - } else - printk(KERN_WARNING "tuner: " - "too many options specified " - "in i2c probe ignore list!\n"); - } - - default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV; - - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; -} - -static int tuner_detach(struct i2c_client *client) -{ - struct tuner *t = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(&t->i2c); - if (err) { - tuner_warn - ("Client deregistration failed, client not detached.\n"); - return err; - } - - if (t->ops.release) - t->ops.release(t); - else { - kfree(t->priv); - } - kfree(t); - return 0; -} - /* * Switch tuner to other mode. If tuner support both tv and radio, * set another frequency to some value (This is needed for some pal @@ -716,6 +696,8 @@ static int tuner_detach(struct i2c_client *client) static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd) { + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + if (mode == t->mode) return 0; @@ -723,8 +705,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, if (check_mode(t, cmd) == EINVAL) { t->mode = T_STANDBY; - if (t->ops.standby) - t->ops.standby(t); + if (analog_ops->standby) + analog_ops->standby(&t->fe); return EINVAL; } return 0; @@ -747,9 +729,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct tuner *t = i2c_get_clientdata(client); struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; if (tuner_debug>1) - v4l_i2c_print_ioctl(&(t->i2c),cmd); + v4l_i2c_print_ioctl(client,cmd); switch (cmd) { /* --- configuration --- */ @@ -773,8 +756,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL) return 0; t->mode = T_STANDBY; - if (t->ops.standby) - t->ops.standby(t); + if (analog_ops->standby) + analog_ops->standby(&t->fe); break; #ifdef CONFIG_VIDEO_V4L1 case VIDIOCSAUDIO: @@ -842,8 +825,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) else vt->flags &= ~VIDEO_TUNER_STEREO_ON; } else { - if (t->ops.is_stereo) { - if (t->ops.is_stereo(t)) + if (analog_ops->is_stereo) { + if (analog_ops->is_stereo(&t->fe)) vt->flags |= VIDEO_TUNER_STEREO_ON; else @@ -851,8 +834,9 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) ~VIDEO_TUNER_STEREO_ON; } } - if (t->ops.has_signal) - vt->signal = t->ops.has_signal(t); + if (analog_ops->has_signal) + vt->signal = + analog_ops->has_signal(&t->fe); vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */ @@ -882,21 +866,28 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) fe_tuner_ops->get_status(&t->fe, &tuner_status); va->mode = (tuner_status & TUNER_STATUS_STEREO) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; - } else if (t->ops.is_stereo) - va->mode = t->ops.is_stereo(t) + } else if (analog_ops->is_stereo) + va->mode = analog_ops->is_stereo(&t->fe) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO; } return 0; } #endif - case TDA9887_SET_CONFIG: - if (t->type == TUNER_TDA9887) { - int *i = arg; + case TUNER_SET_CONFIG: + { + struct v4l2_priv_tun_config *cfg = arg; - t->tda9887_config = *i; - set_freq(client, t->tv_freq); + if (t->type != cfg->tuner) + break; + + if (analog_ops->set_config) { + analog_ops->set_config(&t->fe, cfg->priv); + break; } + + tuner_dbg("Tuner frontend module has no way to set config\n"); break; + } /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ @@ -958,8 +949,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); tuner->type = t->mode; - if (t->ops.get_afc) - tuner->afc=t->ops.get_afc(t); + if (analog_ops->get_afc) + tuner->afc = analog_ops->get_afc(&t->fe); if (t->mode == V4L2_TUNER_ANALOG_TV) tuner->capability |= V4L2_TUNER_CAP_NORM; if (t->mode != V4L2_TUNER_RADIO) { @@ -975,16 +966,20 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) u32 tuner_status; fe_tuner_ops->get_status(&t->fe, &tuner_status); - tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + tuner->rxsubchans = + (tuner_status & TUNER_STATUS_STEREO) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; } else { - if (t->ops.is_stereo) { - tuner->rxsubchans = t->ops.is_stereo(t) ? - V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + if (analog_ops->is_stereo) { + tuner->rxsubchans = + analog_ops->is_stereo(&t->fe) ? + V4L2_TUNER_SUB_STEREO : + V4L2_TUNER_SUB_MONO; } } - if (t->ops.has_signal) - tuner->signal = t->ops.has_signal(t); + if (analog_ops->has_signal) + tuner->signal = analog_ops->has_signal(&t->fe); tuner->capability |= V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; tuner->audmode = t->audmode; @@ -1009,8 +1004,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) break; } case VIDIOC_LOG_STATUS: - if (t->ops.tuner_status) - t->ops.tuner_status(t); + if (analog_ops->tuner_status) + analog_ops->tuner_status(&t->fe); break; } @@ -1019,18 +1014,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) static int tuner_suspend(struct i2c_client *c, pm_message_t state) { - struct tuner *t = i2c_get_clientdata (c); + struct tuner *t = i2c_get_clientdata(c); - tuner_dbg ("suspend\n"); + tuner_dbg("suspend\n"); /* FIXME: power down ??? */ return 0; } static int tuner_resume(struct i2c_client *c) { - struct tuner *t = i2c_get_clientdata (c); + struct tuner *t = i2c_get_clientdata(c); - tuner_dbg ("resume\n"); + tuner_dbg("resume\n"); if (V4L2_TUNER_RADIO == t->mode) { if (t->radio_freq) set_freq(c, t->radio_freq); @@ -1041,36 +1036,227 @@ static int tuner_resume(struct i2c_client *c) return 0; } -/* ----------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- */ -static struct i2c_driver driver = { - .id = I2C_DRIVERID_TUNER, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, - .command = tuner_command, - .suspend = tuner_suspend, - .resume = tuner_resume, - .driver = { - .name = "tuner", - }, -}; -static struct i2c_client client_template = { - .name = "(tuner unset)", - .driver = &driver, -}; +LIST_HEAD(tuner_list); -static int __init tuner_init_module(void) +/* Search for existing radio and/or TV tuners on the given I2C adapter. + Note that when this function is called from tuner_probe you can be + certain no other devices will be added/deleted at the same time, I2C + core protects against that. */ +static void tuner_lookup(struct i2c_adapter *adap, + struct tuner **radio, struct tuner **tv) { - return i2c_add_driver(&driver); + struct tuner *pos; + + *radio = NULL; + *tv = NULL; + + list_for_each_entry(pos, &tuner_list, list) { + int mode_mask; + + if (pos->i2c->adapter != adap || + pos->i2c->driver->id != I2C_DRIVERID_TUNER) + continue; + + mode_mask = pos->mode_mask & ~T_STANDBY; + if (*radio == NULL && mode_mask == T_RADIO) + *radio = pos; + /* Note: currently TDA9887 is the only demod-only + device. If other devices appear then we need to + make this test more general. */ + else if (*tv == NULL && pos->type != TUNER_TDA9887 && + (pos->mode_mask & (T_ANALOG_TV | T_DIGITAL_TV))) + *tv = pos; + } } -static void __exit tuner_cleanup_module(void) +/* During client attach, set_type is called by adapter's attach_inform callback. + set_type must then be completed by tuner_probe. + */ +static int tuner_probe(struct i2c_client *client) { - i2c_del_driver(&driver); + struct tuner *t; + struct tuner *radio; + struct tuner *tv; + + t = kzalloc(sizeof(struct tuner), GFP_KERNEL); + if (NULL == t) + return -ENOMEM; + t->i2c = client; + strlcpy(client->name, "(tuner unset)", sizeof(client->name)); + i2c_set_clientdata(client, t); + t->type = UNSET; + t->audmode = V4L2_TUNER_MODE_STEREO; + t->mode_mask = T_UNINITIALIZED; + + if (show_i2c) { + unsigned char buffer[16]; + int i, rc; + + memset(buffer, 0, sizeof(buffer)); + rc = i2c_master_recv(client, buffer, sizeof(buffer)); + tuner_info("I2C RECV = "); + for (i = 0; i < rc; i++) + printk(KERN_CONT "%02x ", buffer[i]); + printk("\n"); + } + /* HACK: This test was added to avoid tuner to probe tda9840 and + tea6415c on the MXB card */ + if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) { + kfree(t); + return -ENODEV; + } + + /* autodetection code based on the i2c addr */ + if (!no_autodetect) { + switch (client->addr) { + case 0x10: + if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr) + != EINVAL) { + t->type = TUNER_TEA5761; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + case 0x42: + case 0x43: + case 0x4a: + case 0x4b: + /* If chip is not tda8290, don't register. + since it can be tda9887*/ + if (tda829x_probe(t->i2c->adapter, + t->i2c->addr) == 0) { + tuner_dbg("tda829x detected\n"); + } else { + /* Default is being tda9887 */ + t->type = TUNER_TDA9887; + t->mode_mask = T_RADIO | T_ANALOG_TV | + T_DIGITAL_TV; + t->mode = T_STANDBY; + goto register_client; + } + break; + case 0x60: + if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) + != EINVAL) { + t->type = TUNER_TEA5767; + t->mode_mask = T_RADIO; + t->mode = T_STANDBY; + /* Sets freq to FM range */ + t->radio_freq = 87.5 * 16000; + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv) + tv->mode_mask &= ~T_RADIO; + + goto register_client; + } + break; + } + } + + /* Initializes only the first TV tuner on this adapter. Why only the + first? Because there are some devices (notably the ones with TI + tuners) that have more than one i2c address for the *same* device. + Experience shows that, except for just one case, the first + address is the right one. The exception is a Russian tuner + (ACORP_Y878F). So, the desired behavior is just to enable the + first found TV tuner. */ + tuner_lookup(t->i2c->adapter, &radio, &tv); + if (tv == NULL) { + t->mode_mask = T_ANALOG_TV | T_DIGITAL_TV; + if (radio == NULL) + t->mode_mask |= T_RADIO; + tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); + t->tv_freq = 400 * 16; /* Sets freq to VHF High */ + t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */ + } + + /* Should be just before return */ +register_client: + tuner_info("chip found @ 0x%x (%s)\n", client->addr << 1, + client->adapter->name); + + /* Sets a default mode */ + if (t->mode_mask & T_ANALOG_TV) { + t->mode = V4L2_TUNER_ANALOG_TV; + } else if (t->mode_mask & T_RADIO) { + t->mode = V4L2_TUNER_RADIO; + } else { + t->mode = V4L2_TUNER_DIGITAL_TV; + } + set_type(client, t->type, t->mode_mask, t->config, t->tuner_callback); + list_add_tail(&t->list, &tuner_list); + return 0; +} + +static int tuner_legacy_probe(struct i2c_adapter *adap) +{ + if (0 != addr) { + normal_i2c[0] = addr; + normal_i2c[1] = I2C_CLIENT_END; + } + + if ((adap->class & I2C_CLASS_TV_ANALOG) == 0) + return 0; + + /* HACK: Ignore 0x6b and 0x6f on cx88 boards. + * FusionHDTV5 RT Gold has an ir receiver at 0x6b + * and an RTC at 0x6f which can get corrupted if probed. + */ + if ((adap->id == I2C_HW_B_CX2388x) || + (adap->id == I2C_HW_B_CX23885)) { + unsigned int i = 0; + + while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END) + i += 2; + if (i + 4 < I2C_CLIENT_MAX_OPTS) { + ignore[i+0] = adap->nr; + ignore[i+1] = 0x6b; + ignore[i+2] = adap->nr; + ignore[i+3] = 0x6f; + ignore[i+4] = I2C_CLIENT_END; + } else + printk(KERN_WARNING "tuner: " + "too many options specified " + "in i2c probe ignore list!\n"); + } + return 1; } -module_init(tuner_init_module); -module_exit(tuner_cleanup_module); +static int tuner_remove(struct i2c_client *client) +{ + struct tuner *t = i2c_get_clientdata(client); + struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + + if (analog_ops->release) + analog_ops->release(&t->fe); + + list_del(&t->list); + kfree(t); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tuner", + .driverid = I2C_DRIVERID_TUNER, + .command = tuner_command, + .probe = tuner_probe, + .remove = tuner_remove, + .suspend = tuner_suspend, + .resume = tuner_resume, + .legacy_probe = tuner_legacy_probe, +}; + /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h deleted file mode 100644 index 28a10da76d12..000000000000 --- a/drivers/media/video/tuner-driver.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - tuner-driver.h - interface for different tuners - - Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) - minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de) - - 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 __TUNER_DRIVER_H__ -#define __TUNER_DRIVER_H__ - -#include <linux/videodev2.h> -#include <linux/i2c.h> -#include "tuner-i2c.h" -#include "dvb_frontend.h" - -extern unsigned const int tuner_count; - -struct tuner; - -struct tuner_operations { - void (*set_tv_freq)(struct tuner *t, unsigned int freq); - void (*set_radio_freq)(struct tuner *t, unsigned int freq); - int (*has_signal)(struct tuner *t); - int (*is_stereo)(struct tuner *t); - int (*get_afc)(struct tuner *t); - void (*tuner_status)(struct tuner *t); - void (*standby)(struct tuner *t); - void (*release)(struct tuner *t); -}; - -struct tuner { - /* device */ - struct i2c_client i2c; - - unsigned int type; /* chip type */ - - unsigned int mode; - unsigned int mode_mask; /* Combination of allowable modes */ - - unsigned int tv_freq; /* keep track of the current settings */ - unsigned int radio_freq; - unsigned int audmode; - v4l2_std_id std; - - int using_v4l2; - void *priv; - - struct dvb_frontend fe; - - /* used by tda9887 */ - unsigned int tda9887_config; - - unsigned int config; - int (*tuner_callback) (void *dev, int command,int arg); - - struct tuner_operations ops; -}; - -/* ------------------------------------------------------------------------ */ - -extern int tda9887_tuner_init(struct tuner *t); - -/* ------------------------------------------------------------------------ */ - -#define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) -#define tuner_dbg(fmt, arg...) do {\ - extern int tuner_debug; \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \ - i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0) - -#endif /* __TUNER_DRIVER_H__ */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h index 159019ec3373..de52e8ffd347 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/video/tuner-i2c.h @@ -46,25 +46,42 @@ static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, return (ret == 1) ? len : ret; } -#ifndef __TUNER_DRIVER_H__ -#define tuner_warn(fmt, arg...) do {\ - printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#define tuner_info(fmt, arg...) do {\ - printk(KERN_INFO PREFIX "%d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#define tuner_dbg(fmt, arg...) do {\ - if ((debug)) \ - printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \ - i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0) -#endif /* __TUNER_DRIVER_H__ */ +static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, + char *obuf, int olen, + char *ibuf, int ilen) +{ + struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, + .buf = obuf, .len = olen }, + { .addr = props->addr, .flags = I2C_M_RD, + .buf = ibuf, .len = ilen } }; + int ret = i2c_transfer(props->adap, msg, 2); -#endif /* __TUNER_I2C_H__ */ + return (ret == 2) ? ilen : ret; +} -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ +#define tuner_warn(fmt, arg...) do { \ + printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr, ##arg); \ + } while (0) + +#define tuner_info(fmt, arg...) do { \ + printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#define tuner_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#define tuner_dbg(fmt, arg...) do { \ + if ((debug)) \ + printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ + i2c_adapter_id(priv->i2c_props.adap), \ + priv->i2c_props.addr , ##arg); \ + } while (0) + +#endif /* __TUNER_I2C_H__ */ diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 7b93d3b1f4c6..c1db576696c6 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -17,7 +17,7 @@ static int debug = 0; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -#define PREFIX "tuner-simple " +#define PREFIX "tuner-simple" static int offset = 0; module_param(offset, int, 0664); @@ -355,10 +355,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } priv->last_div = div; if (t_params->has_tda9887) { + struct v4l2_priv_tun_config tda9887_cfg; int config = 0; int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + if (params->std == V4L2_STD_SECAM_LC) { if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) config |= TDA9887_PORT1_ACTIVE; @@ -391,7 +395,8 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, } if (t_params->default_pll_gating_18) config |= TDA9887_GATING_18; - i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); } tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); @@ -534,6 +539,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, if (t_params->has_tda9887) { int config = 0; + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &config; + if (t_params->port1_active && !t_params->port1_fm_high_sensitivity) config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active && !t_params->port2_fm_high_sensitivity) @@ -546,7 +556,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe, config |= TDA9887_GAIN_NORMAL; if (t_params->radio_if == 2) config |= TDA9887_RIF_41_3; - i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config); + i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, + &tda9887_cfg); } if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4))) tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc); diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index c6a7934bd5a6..883047f9c28c 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -1366,7 +1366,7 @@ struct tunertype tuners[] = { .count = ARRAY_SIZE(tuner_philips_fq1286_params), }, [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ - .name = "tda8290+75", + .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", /* see tda8290.c for details */ }, [TUNER_TCL_2002MB] = { /* TCL PAL */ .name = "TCL 2002MB", @@ -1452,9 +1452,9 @@ struct tunertype tuners[] = { .params = tuner_samsung_tcpn_2121p30a_params, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), }, - [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */ - .name = "Xceive xc3028", - /* see xc3028.c for details */ + [TUNER_XC2028] = { /* Xceive 2028 */ + .name = "Xceive xc2028/xc3028 tuner", + /* see tuner-xc2028.c for details */ }, [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ .name = "Thomson FE6600", @@ -1475,6 +1475,10 @@ struct tunertype tuners[] = { .name = "Philips TEA5761 FM Radio", /* see tea5767.c for details */ }, + [TUNER_XC5000] = { /* Xceive 5000 */ + .name = "Xceive 5000 tuner", + /* see xc5000.c for details */ + }, }; unsigned const int tuner_count = ARRAY_SIZE(tuners); diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h new file mode 100644 index 000000000000..d0057fbf0ec7 --- /dev/null +++ b/drivers/media/video/tuner-xc2028-types.h @@ -0,0 +1,128 @@ +/* tuner-xc2028_types + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +/* xc3028 firmware types */ + +/* BASE firmware should be loaded before any other firmware */ +#define BASE (1<<0) +#define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) + +/* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ +#define F8MHZ (1<<1) + +/* Multichannel Television Sound (MTS) + Those firmwares are capable of using xc2038 DSP to decode audio and + produce a baseband audio output on some pins of the chip. + There are MTS firmwares for the most used video standards. It should be + required to use MTS firmwares, depending on the way audio is routed into + the bridge chip + */ +#define MTS (1<<2) + +/* FIXME: I have no idea what's the difference between + D2620 and D2633 firmwares + */ +#define D2620 (1<<3) +#define D2633 (1<<4) + +/* DTV firmwares for 6, 7 and 8 MHz + DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS + DTV8 - 8MHz - DVB-C/DVB-T + */ +#define DTV6 (1 << 5) +#define QAM (1 << 6) +#define DTV7 (1<<7) +#define DTV78 (1<<8) +#define DTV8 (1<<9) + +#define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) + +/* There's a FM | BASE firmware + FM specific firmware (std=0) */ +#define FM (1<<10) + +#define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) + +/* Applies only for FM firmware + Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) + */ +#define INPUT1 (1<<11) + + +/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + There are variants both with and without NOGD + */ +#define LCD (1<<12) + +/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) + and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) + */ +#define NOGD (1<<13) + +/* Old firmwares were broken into init0 and init1 */ +#define INIT1 (1<<14) + +/* SCODE firmware selects particular behaviours */ +#define MONO (1 << 15) +#define ATSC (1 << 16) +#define IF (1 << 17) +#define LG60 (1 << 18) +#define ATI638 (1 << 19) +#define OREN538 (1 << 20) +#define OREN36 (1 << 21) +#define TOYOTA388 (1 << 22) +#define TOYOTA794 (1 << 23) +#define DIBCOM52 (1 << 24) +#define ZARLINK456 (1 << 25) +#define CHINA (1 << 26) +#define F6MHZ (1 << 27) +#define INPUT2 (1 << 28) +#define SCODE (1 << 29) + +/* This flag identifies that the scode table has a new format */ +#define HAS_IF (1 << 30) + +#define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \ + LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \ + DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE) + +/* Newer types to be moved to videodev2.h */ + +#define V4L2_STD_SECAM_K3 (0x04000000) + +/* Audio types */ + +#define V4L2_STD_A2_A (1LL<<32) +#define V4L2_STD_A2_B (1LL<<33) +#define V4L2_STD_NICAM_A (1LL<<34) +#define V4L2_STD_NICAM_B (1LL<<35) +#define V4L2_STD_AM (1LL<<36) +#define V4L2_STD_BTSC (1LL<<37) +#define V4L2_STD_EIAJ (1LL<<38) + +#define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) +#define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) + +/* To preserve backward compatibilty, + (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported + */ + +#define V4L2_STD_AUDIO (V4L2_STD_A2 | \ + V4L2_STD_NICAM | \ + V4L2_STD_AM | \ + V4L2_STD_BTSC | \ + V4L2_STD_EIAJ) + +/* Used standards with audio restrictions */ + +#define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) +#define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) +#define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) +#define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) +#define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) +#define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) +#define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c new file mode 100644 index 000000000000..f191f6a48070 --- /dev/null +++ b/drivers/media/video/tuner-xc2028.c @@ -0,0 +1,1213 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * + * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) + * - frontend interface + * + * This code is placed under the terms of the GNU General Public License v2 + */ + +#include <linux/i2c.h> +#include <asm/div64.h> +#include <linux/firmware.h> +#include <linux/videodev2.h> +#include <linux/delay.h> +#include <media/tuner.h> +#include <linux/mutex.h> +#include "tuner-i2c.h" +#include "tuner-xc2028.h" +#include "tuner-xc2028-types.h" + +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + + +#define PREFIX "xc2028" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +static char audio_std[8]; +module_param_string(audio_std, audio_std, sizeof(audio_std), 0); +MODULE_PARM_DESC(audio_std, + "Audio standard. XC3028 audio decoder explicitly " + "needs to know what audio\n" + "standard is needed for some video standards with audio A2 or NICAM.\n" + "The valid values are:\n" + "A2\n" + "A2/A\n" + "A2/B\n" + "NICAM\n" + "NICAM/A\n" + "NICAM/B\n"); + +static LIST_HEAD(xc2028_list); +static DEFINE_MUTEX(xc2028_list_mutex); + +/* struct for storing firmware table */ +struct firmware_description { + unsigned int type; + v4l2_std_id id; + __u16 int_freq; + unsigned char *ptr; + unsigned int size; +}; + +struct firmware_properties { + unsigned int type; + v4l2_std_id id; + v4l2_std_id std_req; + __u16 int_freq; + unsigned int scode_table; + int scode_nr; +}; + +struct xc2028_data { + struct list_head xc2028_list; + struct tuner_i2c_props i2c_props; + int (*tuner_callback) (void *dev, + int command, int arg); + void *video_dev; + int count; + __u32 frequency; + + struct firmware_description *firm; + int firm_size; + __u16 firm_version; + + __u16 hwmodel; + __u16 hwvers; + + struct xc2028_ctrl ctrl; + + struct firmware_properties cur_fw; + + struct mutex lock; +}; + +#define i2c_send(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_info("i2c output error: rc = %d (should be %d)\n",\ + _rc, (int)size); \ + _rc; \ +}) + +#define i2c_rcv(priv, buf, size) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ + if (size != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)size); \ + _rc; \ +}) + +#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ + int _rc; \ + _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ + ibuf, isize); \ + if (isize != _rc) \ + tuner_err("i2c input error: rc = %d (should be %d)\n", \ + _rc, (int)isize); \ + _rc; \ +}) + +#define send_seq(priv, data...) ({ \ + static u8 _val[] = data; \ + int _rc; \ + if (sizeof(_val) != \ + (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ + _val, sizeof(_val)))) { \ + tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ + } else \ + msleep(10); \ + _rc; \ +}) + +static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) +{ + unsigned char buf[2]; + unsigned char ibuf[2]; + + tuner_dbg("%s %04x called\n", __FUNCTION__, reg); + + buf[0] = reg >> 8; + buf[1] = (unsigned char) reg; + + if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) + return -EIO; + + *val = (ibuf[1]) | (ibuf[0] << 8); + return 0; +} + +#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) +void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) +{ + if (type & BASE) + printk("BASE "); + if (type & INIT1) + printk("INIT1 "); + if (type & F8MHZ) + printk("F8MHZ "); + if (type & MTS) + printk("MTS "); + if (type & D2620) + printk("D2620 "); + if (type & D2633) + printk("D2633 "); + if (type & DTV6) + printk("DTV6 "); + if (type & QAM) + printk("QAM "); + if (type & DTV7) + printk("DTV7 "); + if (type & DTV78) + printk("DTV78 "); + if (type & DTV8) + printk("DTV8 "); + if (type & FM) + printk("FM "); + if (type & INPUT1) + printk("INPUT1 "); + if (type & LCD) + printk("LCD "); + if (type & NOGD) + printk("NOGD "); + if (type & MONO) + printk("MONO "); + if (type & ATSC) + printk("ATSC "); + if (type & IF) + printk("IF "); + if (type & LG60) + printk("LG60 "); + if (type & ATI638) + printk("ATI638 "); + if (type & OREN538) + printk("OREN538 "); + if (type & OREN36) + printk("OREN36 "); + if (type & TOYOTA388) + printk("TOYOTA388 "); + if (type & TOYOTA794) + printk("TOYOTA794 "); + if (type & DIBCOM52) + printk("DIBCOM52 "); + if (type & ZARLINK456) + printk("ZARLINK456 "); + if (type & CHINA) + printk("CHINA "); + if (type & F6MHZ) + printk("F6MHZ "); + if (type & INPUT2) + printk("INPUT2 "); + if (type & SCODE) + printk("SCODE "); + if (type & HAS_IF) + printk("HAS_IF_%d ", int_freq); +} + +static v4l2_std_id parse_audio_std_option(void) +{ + if (strcasecmp(audio_std, "A2") == 0) + return V4L2_STD_A2; + if (strcasecmp(audio_std, "A2/A") == 0) + return V4L2_STD_A2_A; + if (strcasecmp(audio_std, "A2/B") == 0) + return V4L2_STD_A2_B; + if (strcasecmp(audio_std, "NICAM") == 0) + return V4L2_STD_NICAM; + if (strcasecmp(audio_std, "NICAM/A") == 0) + return V4L2_STD_NICAM_A; + if (strcasecmp(audio_std, "NICAM/B") == 0) + return V4L2_STD_NICAM_B; + + return 0; +} + +static void free_firmware(struct xc2028_data *priv) +{ + int i; + + if (!priv->firm) + return; + + for (i = 0; i < priv->firm_size; i++) + kfree(priv->firm[i].ptr); + + kfree(priv->firm); + + priv->firm = NULL; + priv->firm_size = 0; + + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); +} + +static int load_all_firmwares(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + const struct firmware *fw = NULL; + unsigned char *p, *endp; + int rc = 0; + int n, n_array; + char name[33]; + + tuner_dbg("%s called\n", __FUNCTION__); + + tuner_dbg("Reading firmware %s\n", priv->ctrl.fname); + rc = request_firmware(&fw, priv->ctrl.fname, + &priv->i2c_props.adap->dev); + if (rc < 0) { + if (rc == -ENOENT) + tuner_err("Error: firmware %s not found.\n", + priv->ctrl.fname); + else + tuner_err("Error %d while requesting firmware %s \n", + rc, priv->ctrl.fname); + + return rc; + } + p = fw->data; + endp = p + fw->size; + + if (fw->size < sizeof(name) - 1 + 2 + 2) { + tuner_err("Error: firmware file %s has invalid size!\n", + priv->ctrl.fname); + goto corrupt; + } + + memcpy(name, p, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + p += sizeof(name) - 1; + + priv->firm_version = le16_to_cpu(*(__u16 *) p); + p += 2; + + n_array = le16_to_cpu(*(__u16 *) p); + p += 2; + + tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", + n_array, priv->ctrl.fname, name, + priv->firm_version >> 8, priv->firm_version & 0xff); + + priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL); + if (priv->firm == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto err; + } + priv->firm_size = n_array; + + n = -1; + while (p < endp) { + __u32 type, size; + v4l2_std_id id; + __u16 int_freq = 0; + + n++; + if (n >= n_array) { + tuner_err("More firmware images in file than " + "were expected!\n"); + goto corrupt; + } + + /* Checks if there's enough bytes to read */ + if (p + sizeof(type) + sizeof(id) + sizeof(size) > endp) { + tuner_err("Firmware header is incomplete!\n"); + goto corrupt; + } + + type = le32_to_cpu(*(__u32 *) p); + p += sizeof(type); + + id = le64_to_cpu(*(v4l2_std_id *) p); + p += sizeof(id); + + if (type & HAS_IF) { + int_freq = le16_to_cpu(*(__u16 *) p); + p += sizeof(int_freq); + } + + size = le32_to_cpu(*(__u32 *) p); + p += sizeof(size); + + if ((!size) || (size + p > endp)) { + tuner_err("Firmware type "); + dump_firm_type(type); + printk("(%x), id %llx is corrupted " + "(size=%d, expected %d)\n", + type, (unsigned long long)id, + (unsigned)(endp - p), size); + goto corrupt; + } + + priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); + if (priv->firm[n].ptr == NULL) { + tuner_err("Not enough memory to load firmware file.\n"); + rc = -ENOMEM; + goto err; + } + tuner_dbg("Reading firmware type "); + if (debug) { + dump_firm_type_and_int_freq(type, int_freq); + printk("(%x), id %llx, size=%d.\n", + type, (unsigned long long)id, size); + } + + memcpy(priv->firm[n].ptr, p, size); + priv->firm[n].type = type; + priv->firm[n].id = id; + priv->firm[n].size = size; + priv->firm[n].int_freq = int_freq; + + p += size; + } + + if (n + 1 != priv->firm_size) { + tuner_err("Firmware file is incomplete!\n"); + goto corrupt; + } + + goto done; + +corrupt: + rc = -EINVAL; + tuner_err("Error: firmware file is corrupted!\n"); + +err: + tuner_info("Releasing partially loaded firmware file.\n"); + free_firmware(priv); + +done: + release_firmware(fw); + if (rc == 0) + tuner_dbg("Firmware files loaded.\n"); + + return rc; +} + +static int seek_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int i, best_i = -1, best_nr_matches = 0; + unsigned int ign_firm_type_mask = 0; + + tuner_dbg("%s called, want type=", __FUNCTION__); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } + + if (!priv->firm) { + tuner_err("Error! firmware not loaded\n"); + return -EINVAL; + } + + if (((type & ~SCODE) == 0) && (*id == 0)) + *id = V4L2_STD_PAL; + + if (type & BASE) + type &= BASE_TYPES; + else if (type & SCODE) { + type &= SCODE_TYPES; + ign_firm_type_mask = HAS_IF; + } else if (type & DTV_TYPES) + type &= DTV_TYPES; + else if (type & STD_SPECIFIC_TYPES) + type &= STD_SPECIFIC_TYPES; + + /* Seek for exact match */ + for (i = 0; i < priv->firm_size; i++) { + if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) && + (*id == priv->firm[i].id)) + goto found; + } + + /* Seek for generic video standard match */ + for (i = 0; i < priv->firm_size; i++) { + v4l2_std_id match_mask; + int nr_matches; + + if (type != (priv->firm[i].type & ~ign_firm_type_mask)) + continue; + + match_mask = *id & priv->firm[i].id; + if (!match_mask) + continue; + + if ((*id & match_mask) == *id) + goto found; /* Supports all the requested standards */ + + nr_matches = hweight64(match_mask); + if (nr_matches > best_nr_matches) { + best_nr_matches = nr_matches; + best_i = i; + } + } + + if (best_nr_matches > 0) { + tuner_dbg("Selecting best matching firmware (%d bits) for " + "type=", best_nr_matches); + dump_firm_type(type); + printk("(%x), id %016llx:\n", type, (unsigned long long)*id); + i = best_i; + goto found; + } + + /*FIXME: Would make sense to seek for type "hint" match ? */ + + i = -ENOENT; + goto ret; + +found: + *id = priv->firm[i].id; + +ret: + tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); + if (debug) { + dump_firm_type(type); + printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + } + return i; +} + +static int load_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p, *endp, buf[priv->ctrl.max_len]; + + tuner_dbg("%s called\n", __FUNCTION__); + + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + + tuner_info("Loading firmware for type="); + dump_firm_type(priv->firm[pos].type); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + + p = priv->firm[pos].ptr; + endp = p + priv->firm[pos].size; + + while (p < endp) { + __u16 size; + + /* Checks if there's enough bytes to read */ + if (p + sizeof(size) > endp) { + tuner_err("Firmware chunk size is wrong\n"); + return -EINVAL; + } + + size = le16_to_cpu(*(__u16 *) p); + p += sizeof(size); + + if (size == 0xffff) + return 0; + + if (!size) { + /* Special callback command received */ + rc = priv->tuner_callback(priv->video_dev, + XC2028_TUNER_RESET, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + continue; + } + if (size >= 0xff00) { + switch (size) { + case 0xff00: + rc = priv->tuner_callback(priv->video_dev, + XC2028_RESET_CLK, 0); + if (rc < 0) { + tuner_err("Error at RESET code %d\n", + (*p) & 0x7f); + return -EINVAL; + } + break; + default: + tuner_info("Invalid RESET code %d\n", + size & 0x7f); + return -EINVAL; + + } + continue; + } + + /* Checks for a sleep command */ + if (size & 0x8000) { + msleep(size & 0x7fff); + continue; + } + + if ((size + p > endp)) { + tuner_err("missing bytes: need %d, have %d\n", + size, (int)(endp - p)); + return -EINVAL; + } + + buf[0] = *p; + p++; + size--; + + /* Sends message chunks */ + while (size > 0) { + int len = (size < priv->ctrl.max_len - 1) ? + size : priv->ctrl.max_len - 1; + + memcpy(buf + 1, p, len); + + rc = i2c_send(priv, buf, len + 1); + if (rc < 0) { + tuner_err("%d returned from send\n", rc); + return -EINVAL; + } + + p += len; + size -= len; + } + } + return 0; +} + +static int load_scode(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id *id, __u16 int_freq, int scode) +{ + struct xc2028_data *priv = fe->tuner_priv; + int pos, rc; + unsigned char *p; + + tuner_dbg("%s called\n", __FUNCTION__); + + if (!int_freq) { + pos = seek_firmware(fe, type, id); + if (pos < 0) + return pos; + } else { + for (pos = 0; pos < priv->firm_size; pos++) { + if ((priv->firm[pos].int_freq == int_freq) && + (priv->firm[pos].type & HAS_IF)) + break; + } + if (pos == priv->firm_size) + return -ENOENT; + } + + p = priv->firm[pos].ptr; + + if (priv->firm[pos].type & HAS_IF) { + if (priv->firm[pos].size != 12 * 16 || scode >= 16) + return -EINVAL; + p += 12 * scode; + } else { + /* 16 SCODE entries per file; each SCODE entry is 12 bytes and + * has a 2-byte size header in the firmware format. */ + if (priv->firm[pos].size != 14 * 16 || scode >= 16 || + le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) + return -EINVAL; + p += 14 * scode + 2; + } + + tuner_info("Loading SCODE for type="); + dump_firm_type_and_int_freq(priv->firm[pos].type, + priv->firm[pos].int_freq); + printk("(%x), id %016llx.\n", priv->firm[pos].type, + (unsigned long long)*id); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); + else + rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); + if (rc < 0) + return -EIO; + + rc = i2c_send(priv, p, 12); + if (rc < 0) + return -EIO; + + rc = send_seq(priv, {0x00, 0x8c}); + if (rc < 0) + return -EIO; + + return 0; +} + +static int check_firmware(struct dvb_frontend *fe, unsigned int type, + v4l2_std_id std, __u16 int_freq) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct firmware_properties new_fw; + int rc = 0, is_retry = 0; + u16 version, hwmodel; + v4l2_std_id std0; + + tuner_dbg("%s called\n", __FUNCTION__); + + if (!priv->firm) { + if (!priv->ctrl.fname) { + tuner_info("xc2028/3028 firmware name not set!\n"); + return -EINVAL; + } + + rc = load_all_firmwares(fe); + if (rc < 0) + return rc; + } + + if (priv->ctrl.mts && !(type & FM)) + type |= MTS; + +retry: + new_fw.type = type; + new_fw.id = std; + new_fw.std_req = std; + new_fw.scode_table = SCODE | priv->ctrl.scode_table; + new_fw.scode_nr = 0; + new_fw.int_freq = int_freq; + + tuner_dbg("checking firmware, user requested type="); + if (debug) { + dump_firm_type(new_fw.type); + printk("(%x), id %016llx, ", new_fw.type, + (unsigned long long)new_fw.std_req); + if (!int_freq) { + printk("scode_tbl "); + dump_firm_type(priv->ctrl.scode_table); + printk("(%x), ", priv->ctrl.scode_table); + } else + printk("int_freq %d, ", new_fw.int_freq); + printk("scode_nr %d\n", new_fw.scode_nr); + } + + /* No need to reload base firmware if it matches */ + if (((BASE | new_fw.type) & BASE_TYPES) == + (priv->cur_fw.type & BASE_TYPES)) { + tuner_dbg("BASE firmware not changed.\n"); + goto skip_base; + } + + /* Updating BASE - forget about all currently loaded firmware */ + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + + /* Reset is needed before loading firmware */ + rc = priv->tuner_callback(priv->video_dev, + XC2028_TUNER_RESET, 0); + if (rc < 0) + goto fail; + + /* BASE firmwares are all std0 */ + std0 = 0; + rc = load_firmware(fe, BASE | new_fw.type, &std0); + if (rc < 0) { + tuner_err("Error %d while loading base firmware\n", + rc); + goto fail; + } + + /* Load INIT1, if needed */ + tuner_dbg("Load init1 firmware, if exists\n"); + + rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); + if (rc == -ENOENT) + rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, + &std0); + if (rc < 0 && rc != -ENOENT) { + tuner_err("Error %d while loading init1 firmware\n", + rc); + goto fail; + } + +skip_base: + /* + * No need to reload standard specific firmware if base firmware + * was not reloaded and requested video standards have not changed. + */ + if (priv->cur_fw.type == (BASE | new_fw.type) && + priv->cur_fw.std_req == std) { + tuner_dbg("Std-specific firmware already loaded.\n"); + goto skip_std_specific; + } + + /* Reloading std-specific firmware forces a SCODE update */ + priv->cur_fw.scode_table = 0; + + rc = load_firmware(fe, new_fw.type, &new_fw.id); + if (rc == -ENOENT) + rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); + + if (rc < 0) + goto fail; + +skip_std_specific: + if (priv->cur_fw.scode_table == new_fw.scode_table && + priv->cur_fw.scode_nr == new_fw.scode_nr) { + tuner_dbg("SCODE firmware already loaded.\n"); + goto check_device; + } + + /* Load SCODE firmware, if exists */ + tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); + + rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, + new_fw.int_freq, new_fw.scode_nr); + +check_device: + if (xc2028_get_reg(priv, 0x0004, &version) < 0 || + xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { + tuner_err("Unable to read tuner registers.\n"); + goto fail; + } + + tuner_info("Device is Xceive %d version %d.%d, " + "firmware version %d.%d\n", + hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, + (version & 0xf0) >> 4, version & 0xf); + + /* Check firmware version against what we downloaded. */ + if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { + tuner_err("Incorrect readback of firmware version.\n"); + goto fail; + } + + /* Check that the tuner hardware model remains consistent over time. */ + if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { + priv->hwmodel = hwmodel; + priv->hwvers = version & 0xff00; + } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || + priv->hwvers != (version & 0xff00)) { + tuner_err("Read invalid device hardware information - tuner " + "hung?\n"); + goto fail; + } + + memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); + + /* + * By setting BASE in cur_fw.type only after successfully loading all + * firmwares, we can: + * 1. Identify that BASE firmware with type=0 has been loaded; + * 2. Tell whether BASE firmware was just changed the next time through. + */ + priv->cur_fw.type |= BASE; + + return 0; + +fail: + memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); + if (!is_retry) { + msleep(50); + is_retry = 1; + tuner_dbg("Retrying firmware load\n"); + goto retry; + } + + if (rc == -ENOENT) + rc = -EINVAL; + return rc; +} + +static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct xc2028_data *priv = fe->tuner_priv; + u16 frq_lock, signal = 0; + int rc; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + /* Sync Lock Indicator */ + rc = xc2028_get_reg(priv, 0x0002, &frq_lock); + if (rc < 0 || frq_lock == 0) + goto ret; + + /* Frequency is locked. Return signal quality */ + + /* Get SNR of the video signal */ + rc = xc2028_get_reg(priv, 0x0040, &signal); + if (rc < 0) + signal = -frq_lock; + +ret: + mutex_unlock(&priv->lock); + + *strength = signal; + + return rc; +} + +#define DIV 15625 + +static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, + enum tuner_mode new_mode, + unsigned int type, + v4l2_std_id std, + u16 int_freq) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = -EINVAL; + unsigned char buf[4]; + u32 div, offset = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + tuner_dbg("should set frequency %d kHz\n", freq / 1000); + + if (check_firmware(fe, type, std, int_freq) < 0) + goto ret; + + /* On some cases xc2028 can disable video output, if + * very weak signals are received. By sending a soft + * reset, this is re-enabled. So, it is better to always + * send a soft reset before changing channels, to be sure + * that xc2028 will be in a safe state. + * Maybe this might also be needed for DTV. + */ + if (new_mode == T_ANALOG_TV) { + rc = send_seq(priv, {0x00, 0x00}); + } else if (priv->cur_fw.type & ATSC) { + offset = 1750000; + } else { + offset = 2750000; + /* + * We must adjust the offset by 500kHz in two cases in order + * to correctly center the IF output: + * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly + * selected and a 7MHz channel is tuned; + * 2) When tuning a VHF channel with DTV78 firmware. + */ + if (((priv->cur_fw.type & DTV7) && + (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) || + ((priv->cur_fw.type & DTV78) && freq < 470000000)) + offset -= 500000; + } + + div = (freq - offset + DIV / 2) / DIV; + + /* CMD= Set frequency */ + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, 0x02, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, 0x02, 0x00, 0x00}); + if (rc < 0) + goto ret; + + rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); + if (rc < 0) + goto ret; + + msleep(10); + + buf[0] = 0xff & (div >> 24); + buf[1] = 0xff & (div >> 16); + buf[2] = 0xff & (div >> 8); + buf[3] = 0xff & (div); + + rc = i2c_send(priv, buf, sizeof(buf)); + if (rc < 0) + goto ret; + msleep(100); + + priv->frequency = freq; + + tuner_dbg("divisor= %02x %02x %02x %02x (freq=%d.%03d)\n", + buf[0], buf[1], buf[2], buf[3], + freq / 1000000, (freq % 1000000) / 1000); + + rc = 0; + +ret: + mutex_unlock(&priv->lock); + + return rc; +} + +static int xc2028_set_analog_freq(struct dvb_frontend *fe, + struct analog_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + unsigned int type=0; + + tuner_dbg("%s called\n", __FUNCTION__); + + if (p->mode == V4L2_TUNER_RADIO) { + type |= FM; + if (priv->ctrl.input1) + type |= INPUT1; + return generic_set_freq(fe, (625l * p->frequency) / 10, + T_ANALOG_TV, type, 0, 0); + } + + /* if std is not defined, choose one */ + if (!p->std) + p->std = V4L2_STD_MN; + + /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ + if (!(p->std & V4L2_STD_MN)) + type |= F8MHZ; + + /* Add audio hack to std mask */ + p->std |= parse_audio_std_option(); + + return generic_set_freq(fe, 62500l * p->frequency, + T_ANALOG_TV, type, p->std, 0); +} + +static int xc2028_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct xc2028_data *priv = fe->tuner_priv; + unsigned int type=0; + fe_bandwidth_t bw = BANDWIDTH_8_MHZ; + u16 demod = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + if (priv->ctrl.d2633) + type |= D2633; + else + type |= D2620; + + switch(fe->ops.info.type) { + case FE_OFDM: + bw = p->u.ofdm.bandwidth; + break; + case FE_QAM: + tuner_info("WARN: There are some reports that " + "QAM 6 MHz doesn't work.\n" + "If this works for you, please report by " + "e-mail to: v4l-dvb-maintainer@linuxtv.org\n"); + bw = BANDWIDTH_6_MHZ; + type |= QAM; + break; + case FE_ATSC: + bw = BANDWIDTH_6_MHZ; + /* The only ATSC firmware (at least on v2.7) is D2633, + so overrides ctrl->d2633 */ + type |= ATSC| D2633; + type &= ~D2620; + break; + /* DVB-S is not supported */ + default: + return -EINVAL; + } + + switch (bw) { + case BANDWIDTH_8_MHZ: + if (p->frequency < 470000000) + priv->ctrl.vhfbw7 = 0; + else + priv->ctrl.uhfbw8 = 1; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; + type |= F8MHZ; + break; + case BANDWIDTH_7_MHZ: + if (p->frequency < 470000000) + priv->ctrl.vhfbw7 = 1; + else + priv->ctrl.uhfbw8 = 0; + type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; + type |= F8MHZ; + break; + case BANDWIDTH_6_MHZ: + type |= DTV6; + priv->ctrl.vhfbw7 = 0; + priv->ctrl.uhfbw8 = 0; + break; + default: + tuner_err("error: bandwidth not supported.\n"); + }; + + /* All S-code tables need a 200kHz shift */ + if (priv->ctrl.demod) + demod = priv->ctrl.demod + 200; + + return generic_set_freq(fe, p->frequency, + T_DIGITAL_TV, type, 0, demod); +} + +static int xc2028_sleep(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + int rc = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + if (priv->firm_version < 0x0202) + rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00}); + else + rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00}); + + priv->cur_fw.type = 0; /* need firmware reload */ + + mutex_unlock(&priv->lock); + + return rc; +} + + +static int xc2028_dvb_release(struct dvb_frontend *fe) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&xc2028_list_mutex); + + priv->count--; + + if (!priv->count) { + list_del(&priv->xc2028_list); + + kfree(priv->ctrl.fname); + + free_firmware(priv); + kfree(priv); + fe->tuner_priv = NULL; + } + + mutex_unlock(&xc2028_list_mutex); + + return 0; +} + +static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct xc2028_data *priv = fe->tuner_priv; + + tuner_dbg("%s called\n", __FUNCTION__); + + *frequency = priv->frequency; + + return 0; +} + +static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) +{ + struct xc2028_data *priv = fe->tuner_priv; + struct xc2028_ctrl *p = priv_cfg; + int rc = 0; + + tuner_dbg("%s called\n", __FUNCTION__); + + mutex_lock(&priv->lock); + + kfree(priv->ctrl.fname); + free_firmware(priv); + + memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + priv->ctrl.fname = NULL; + + if (p->fname) { + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) + rc = -ENOMEM; + } + + if (priv->ctrl.max_len < 9) + priv->ctrl.max_len = 13; + + mutex_unlock(&priv->lock); + + return rc; +} + +static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { + .info = { + .name = "Xceive XC3028", + .frequency_min = 42000000, + .frequency_max = 864000000, + .frequency_step = 50000, + }, + + .set_config = xc2028_set_config, + .set_analog_params = xc2028_set_analog_freq, + .release = xc2028_dvb_release, + .get_frequency = xc2028_get_frequency, + .get_rf_strength = xc2028_signal, + .set_params = xc2028_set_params, + .sleep = xc2028_sleep, + +}; + +struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + struct xc2028_data *priv; + void *video_dev; + + if (debug) + printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n"); + + if (NULL == cfg || NULL == cfg->video_dev) + return NULL; + + if (!fe) { + printk(KERN_ERR PREFIX ": No frontend!\n"); + return NULL; + } + + video_dev = cfg->video_dev; + + mutex_lock(&xc2028_list_mutex); + + list_for_each_entry(priv, &xc2028_list, xc2028_list) { + if (priv->video_dev == cfg->video_dev) { + video_dev = NULL; + break; + } + } + + if (video_dev) { + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) { + mutex_unlock(&xc2028_list_mutex); + return NULL; + } + + priv->i2c_props.addr = cfg->i2c_addr; + priv->i2c_props.adap = cfg->i2c_adap; + priv->video_dev = video_dev; + priv->tuner_callback = cfg->callback; + priv->ctrl.max_len = 13; + + mutex_init(&priv->lock); + + list_add_tail(&priv->xc2028_list, &xc2028_list); + } + + fe->tuner_priv = priv; + priv->count++; + + memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, + sizeof(xc2028_dvb_tuner_ops)); + + tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); + + if (cfg->ctrl) + xc2028_set_config(fe, cfg->ctrl); + + mutex_unlock(&xc2028_list_mutex); + + return fe; +} + +EXPORT_SYMBOL(xc2028_attach); + +MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); +MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>"); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h new file mode 100644 index 000000000000..3eb8420379a4 --- /dev/null +++ b/drivers/media/video/tuner-xc2028.h @@ -0,0 +1,63 @@ +/* tuner-xc2028 + * + * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + +#ifndef __TUNER_XC2028_H__ +#define __TUNER_XC2028_H__ + +#include "dvb_frontend.h" + +#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" + +/* Dmoduler IF (kHz) */ +#define XC3028_FE_DEFAULT 0 +#define XC3028_FE_LG60 6000 +#define XC3028_FE_ATI638 6380 +#define XC3028_FE_OREN538 5380 +#define XC3028_FE_OREN36 3600 +#define XC3028_FE_TOYOTA388 3880 +#define XC3028_FE_TOYOTA794 7940 +#define XC3028_FE_DIBCOM52 5200 +#define XC3028_FE_ZARLINK456 4560 +#define XC3028_FE_CHINA 5200 + +struct xc2028_ctrl { + char *fname; + int max_len; + unsigned int scode_table; + unsigned int mts :1; + unsigned int d2633 :1; + unsigned int input1:1; + unsigned int vhfbw7:1; + unsigned int uhfbw8:1; + unsigned int demod; +}; + +struct xc2028_config { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + void *video_dev; + struct xc2028_ctrl *ctrl; + int (*callback) (void *dev, int command, int arg); +}; + +/* xc2028 commands for callback */ +#define XC2028_TUNER_RESET 0 +#define XC2028_RESET_CLK 1 + +#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) +extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg); +#else +static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, + struct xc2028_config *cfg) +{ + printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", + __FUNCTION__); + return NULL; +} +#endif + +#endif /* __TUNER_XC2028_H__ */ diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index a19cdcc17ef7..a75560540e79 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -31,6 +31,7 @@ #include <media/tvaudio.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv-legacy.h> #include <media/i2c-addr.h> @@ -109,7 +110,7 @@ static struct CHIPDESC chiplist[]; /* current state of the chip */ struct CHIPSTATE { - struct i2c_client c; + struct i2c_client *c; /* index into CHIPDESC array */ int type; @@ -145,10 +146,6 @@ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; I2C_CLIENT_INSMOD; -static struct i2c_driver driver; -static struct i2c_client client_template; - - /* ---------------------------------------------------------------------- */ /* i2c I/O functions */ @@ -157,24 +154,24 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val) unsigned char buffer[2]; if (-1 == subaddr) { - v4l_dbg(1, debug, &chip->c, "%s: chip_write: 0x%x\n", - chip->c.name, val); + v4l_dbg(1, debug, chip->c, "%s: chip_write: 0x%x\n", + chip->c->name, val); chip->shadow.bytes[1] = val; buffer[0] = val; - if (1 != i2c_master_send(&chip->c,buffer,1)) { - v4l_warn(&chip->c, "%s: I/O error (write 0x%x)\n", - chip->c.name, val); + if (1 != i2c_master_send(chip->c,buffer,1)) { + v4l_warn(chip->c, "%s: I/O error (write 0x%x)\n", + chip->c->name, val); return -1; } } else { - v4l_dbg(1, debug, &chip->c, "%s: chip_write: reg%d=0x%x\n", - chip->c.name, subaddr, val); + v4l_dbg(1, debug, chip->c, "%s: chip_write: reg%d=0x%x\n", + chip->c->name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; - if (2 != i2c_master_send(&chip->c,buffer,2)) { - v4l_warn(&chip->c, "%s: I/O error (write reg%d=0x%x)\n", - chip->c.name, subaddr, val); + if (2 != i2c_master_send(chip->c,buffer,2)) { + v4l_warn(chip->c, "%s: I/O error (write reg%d=0x%x)\n", + chip->c->name, subaddr, val); return -1; } } @@ -197,12 +194,12 @@ static int chip_read(struct CHIPSTATE *chip) { unsigned char buffer; - if (1 != i2c_master_recv(&chip->c,&buffer,1)) { - v4l_warn(&chip->c, "%s: I/O error (read)\n", - chip->c.name); + if (1 != i2c_master_recv(chip->c,&buffer,1)) { + v4l_warn(chip->c, "%s: I/O error (read)\n", + chip->c->name); return -1; } - v4l_dbg(1, debug, &chip->c, "%s: chip_read: 0x%x\n",chip->c.name, buffer); + v4l_dbg(1, debug, chip->c, "%s: chip_read: 0x%x\n",chip->c->name, buffer); return buffer; } @@ -211,17 +208,17 @@ static int chip_read2(struct CHIPSTATE *chip, int subaddr) unsigned char write[1]; unsigned char read[1]; struct i2c_msg msgs[2] = { - { chip->c.addr, 0, 1, write }, - { chip->c.addr, I2C_M_RD, 1, read } + { chip->c->addr, 0, 1, write }, + { chip->c->addr, I2C_M_RD, 1, read } }; write[0] = subaddr; - if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { - v4l_warn(&chip->c, "%s: I/O error (read2)\n", chip->c.name); + if (2 != i2c_transfer(chip->c->adapter,msgs,2)) { + v4l_warn(chip->c, "%s: I/O error (read2)\n", chip->c->name); return -1; } - v4l_dbg(1, debug, &chip->c, "%s: chip_read2: reg%d=0x%x\n", - chip->c.name, subaddr,read[0]); + v4l_dbg(1, debug, chip->c, "%s: chip_read2: reg%d=0x%x\n", + chip->c->name, subaddr,read[0]); return read[0]; } @@ -233,8 +230,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) return 0; /* update our shadow register set; print bytes if (debug > 0) */ - v4l_dbg(1, debug, &chip->c, "%s: chip_cmd(%s): reg=%d, data:", - chip->c.name, name,cmd->bytes[0]); + v4l_dbg(1, debug, chip->c, "%s: chip_cmd(%s): reg=%d, data:", + chip->c->name, name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { if (debug) printk(" 0x%x",cmd->bytes[i]); @@ -244,8 +241,8 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) printk("\n"); /* send data to the chip */ - if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - v4l_warn(&chip->c, "%s: I/O error (%s)\n", chip->c.name, name); + if (cmd->count != i2c_master_send(chip->c,cmd->bytes,cmd->count)) { + v4l_warn(chip->c, "%s: I/O error (%s)\n", chip->c->name, name); return -1; } return 0; @@ -269,7 +266,7 @@ static int chip_thread(void *data) struct CHIPSTATE *chip = data; struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread started\n", chip->c->name); set_freezable(); for (;;) { set_current_state(TASK_INTERRUPTIBLE); @@ -279,7 +276,7 @@ static int chip_thread(void *data) try_to_freeze(); if (kthread_should_stop()) break; - v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread wakeup\n", chip->c->name); /* don't do anything for radio or if mode != auto */ if (chip->radio || chip->mode != 0) @@ -292,7 +289,7 @@ static int chip_thread(void *data) mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); } - v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread exiting\n", chip->c->name); return 0; } @@ -304,17 +301,19 @@ static void generic_checkmode(struct CHIPSTATE *chip) if (mode == chip->prevmode) return; - v4l_dbg(1, debug, &chip->c, "%s: thread checkmode\n", chip->c.name); + v4l_dbg(1, debug, chip->c, "%s: thread checkmode\n", chip->c->name); chip->prevmode = mode; - if (mode & VIDEO_SOUND_STEREO) - desc->setmode(chip,VIDEO_SOUND_STEREO); - else if (mode & VIDEO_SOUND_LANG1) - desc->setmode(chip,VIDEO_SOUND_LANG1); - else if (mode & VIDEO_SOUND_LANG2) - desc->setmode(chip,VIDEO_SOUND_LANG2); + if (mode & V4L2_TUNER_MODE_STEREO) + desc->setmode(chip,V4L2_TUNER_MODE_STEREO); + if (mode & V4L2_TUNER_MODE_LANG1_LANG2) + desc->setmode(chip,V4L2_TUNER_MODE_STEREO); + else if (mode & V4L2_TUNER_MODE_LANG1) + desc->setmode(chip,V4L2_TUNER_MODE_LANG1); + else if (mode & V4L2_TUNER_MODE_LANG2) + desc->setmode(chip,V4L2_TUNER_MODE_LANG2); else - desc->setmode(chip,VIDEO_SOUND_MONO); + desc->setmode(chip,V4L2_TUNER_MODE_MONO); } /* ---------------------------------------------------------------------- */ @@ -345,13 +344,13 @@ static int tda9840_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TDA9840_DS_DUAL) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; if (val & TDA9840_ST_STEREO) - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; - v4l_dbg(1, debug, &chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", + v4l_dbg(1, debug, chip->c, "tda9840_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -362,16 +361,16 @@ static void tda9840_setmode(struct CHIPSTATE *chip, int mode) int t = chip->shadow.bytes[TDA9840_SW + 1] & ~0x7e; switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: t |= TDA9840_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: t |= TDA9840_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: t |= TDA9840_DUALA; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: t |= TDA9840_DUALB; break; default: @@ -502,7 +501,7 @@ static int tda985x_getmode(struct CHIPSTATE *chip) chip_read(chip)) >> 4; /* Add mono mode regardless of SAP and stereo */ /* Allows forced mono */ - return mode | VIDEO_SOUND_MONO; + return mode | V4L2_TUNER_MODE_MONO; } static void tda985x_setmode(struct CHIPSTATE *chip, int mode) @@ -511,13 +510,13 @@ static void tda985x_setmode(struct CHIPSTATE *chip, int mode) int c6 = chip->shadow.bytes[TDA985x_C6+1] & 0x3f; switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: c6 |= TDA985x_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: c6 |= TDA985x_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: c6 |= TDA985x_SAP; break; default: @@ -650,12 +649,12 @@ static int tda9873_getmode(struct CHIPSTATE *chip) int val,mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TDA9873_STEREO) - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if (val & TDA9873_DUAL) - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; - v4l_dbg(1, debug, &chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + v4l_dbg(1, debug, chip->c, "tda9873_getmode(): raw chip read: %d, return: %d\n", val, mode); return mode; } @@ -666,24 +665,24 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) /* int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */ if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) { - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): external input\n"); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): external input\n"); return; } - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): chip->shadow.bytes[%d] = %d\n", TDA9873_SW+1, chip->shadow.bytes[TDA9873_SW+1]); + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): sw_data = %d\n", sw_data); switch (mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: sw_data |= TDA9873_TR_MONO; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: sw_data |= TDA9873_TR_STEREO; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: sw_data |= TDA9873_TR_DUALA; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: sw_data |= TDA9873_TR_DUALB; break; default: @@ -692,7 +691,7 @@ static void tda9873_setmode(struct CHIPSTATE *chip, int mode) } chip_write(chip, TDA9873_SW, sw_data); - v4l_dbg(1, debug, &chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", + v4l_dbg(1, debug, chip->c, "tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data); } @@ -831,7 +830,7 @@ static int tda9874a_setup(struct CHIPSTATE *chip) chip_write(chip, TDA9874A_SDACOSR, (tda9874a_mode) ? 0x81:0x80); chip_write(chip, TDA9874A_AOSR, 0x00); /* or 0x10 */ } - v4l_dbg(1, debug, &chip->c, "tda9874a_setup(): %s [0x%02X].\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setup(): %s [0x%02X].\n", tda9874a_modelist[tda9874a_STD].name,tda9874a_STD); return 1; } @@ -841,7 +840,7 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) int dsr,nsr,mode; int necr; /* just for debugging */ - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if(-1 == (dsr = chip_read2(chip,TDA9874A_DSR))) return mode; @@ -860,21 +859,21 @@ static int tda9874a_getmode(struct CHIPSTATE *chip) * that sound has (temporarily) switched from NICAM to * mono FM (or AM) on 1st sound carrier due to high NICAM bit * error count. So in fact there is no stereo in this case :-( - * But changing the mode to VIDEO_SOUND_MONO would switch + * But changing the mode to V4L2_TUNER_MODE_MONO would switch * external 4052 multiplexer in audio_hook(). */ if(nsr & 0x02) /* NSR.S/MB=1 */ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if(nsr & 0x01) /* NSR.D/SB=1 */ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } else { if(dsr & 0x02) /* DSR.IDSTE=1 */ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; if(dsr & 0x04) /* DSR.IDDUA=1 */ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } - v4l_dbg(1, debug, &chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_getmode(): DSR=0x%X, NSR=0x%X, NECR=0x%X, return: %d.\n", dsr, nsr, necr, mode); return mode; } @@ -902,14 +901,14 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) int mdacosr = (tda9874a_mode) ? 0x82:0x80; switch(mode) { - case VIDEO_SOUND_MONO: - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_STEREO: break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: aosr = 0x80; /* auto-select, dual A/A */ mdacosr = (tda9874a_mode) ? 0x82:0x80; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: aosr = 0xa0; /* auto-select, dual B/B */ mdacosr = (tda9874a_mode) ? 0x83:0x81; break; @@ -920,18 +919,18 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_AOSR, aosr); chip_write(chip, TDA9874A_MDACOSR, mdacosr); - v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; AOSR=0x%X, MDACOSR=0x%X.\n", mode, aosr, mdacosr); } else { /* dic == 0x07 */ int fmmr,aosr; switch(mode) { - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: fmmr = 0x00; /* mono */ aosr = 0x10; /* A/A */ break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: if(tda9874a_mode) { fmmr = 0x00; aosr = 0x00; /* handled by NICAM auto-mute */ @@ -940,11 +939,11 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) aosr = 0x00; } break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: fmmr = 0x02; /* dual */ aosr = 0x10; /* dual A/A */ break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: fmmr = 0x02; /* dual */ aosr = 0x20; /* dual B/B */ break; @@ -955,7 +954,7 @@ static void tda9874a_setmode(struct CHIPSTATE *chip, int mode) chip_write(chip, TDA9874A_FMMR, fmmr); chip_write(chip, TDA9874A_AOSR, aosr); - v4l_dbg(1, debug, &chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", + v4l_dbg(1, debug, chip->c, "tda9874a_setmode(): req. mode %d; FMMR=0x%X, AOSR=0x%X.\n", mode, fmmr, aosr); } } @@ -969,10 +968,10 @@ static int tda9874a_checkit(struct CHIPSTATE *chip) if(-1 == (sic = chip_read2(chip,TDA9874A_SIC))) return 0; - v4l_dbg(1, debug, &chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); + v4l_dbg(1, debug, chip->c, "tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic); if((dic == 0x11)||(dic == 0x07)) { - v4l_info(&chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); + v4l_info(chip->c, "found tda9874%s.\n", (dic == 0x11) ? "a":"h"); tda9874a_dic = dic; /* remember device id. */ return 1; } @@ -1095,7 +1094,7 @@ static int tda8425_initialize(struct CHIPSTATE *chip) int inputmap[4] = { /* tuner */ TDA8425_S1_CH2, /* radio */ TDA8425_S1_CH1, /* extern */ TDA8425_S1_CH1, /* intern */ TDA8425_S1_OFF}; - if (chip->c.adapter->id == I2C_HW_B_RIVA) { + if (chip->c->adapter->id == I2C_HW_B_RIVA) { memcpy (desc->inputmap, inputmap, sizeof (inputmap)); } return 0; @@ -1105,20 +1104,20 @@ static void tda8425_setmode(struct CHIPSTATE *chip, int mode) { int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1; - if (mode & VIDEO_SOUND_LANG1) { + if (mode & V4L2_TUNER_MODE_LANG1) { s1 |= TDA8425_S1_ML_SOUND_A; s1 |= TDA8425_S1_STEREO_PSEUDO; - } else if (mode & VIDEO_SOUND_LANG2) { + } else if (mode & V4L2_TUNER_MODE_LANG2) { s1 |= TDA8425_S1_ML_SOUND_B; s1 |= TDA8425_S1_STEREO_PSEUDO; } else { s1 |= TDA8425_S1_ML_STEREO; - if (mode & VIDEO_SOUND_MONO) + if (mode & V4L2_TUNER_MODE_MONO) s1 |= TDA8425_S1_STEREO_MONO; - if (mode & VIDEO_SOUND_STEREO) + if (mode & V4L2_TUNER_MODE_STEREO) s1 |= TDA8425_S1_STEREO_SPATIAL; } chip_write(chip,TDA8425_S1,s1); @@ -1177,13 +1176,13 @@ static int ta8874z_getmode(struct CHIPSTATE *chip) int val, mode; val = chip_read(chip); - mode = VIDEO_SOUND_MONO; + mode = V4L2_TUNER_MODE_MONO; if (val & TA8874Z_B1){ - mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2; + mode |= V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; }else if (!(val & TA8874Z_B0)){ - mode |= VIDEO_SOUND_STEREO; + mode |= V4L2_TUNER_MODE_STEREO; } - /* v4l_dbg(1, debug, &chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ + /* v4l_dbg(1, debug, chip->c, "ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode); */ return mode; } @@ -1196,19 +1195,19 @@ static void ta8874z_setmode(struct CHIPSTATE *chip, int mode) { int update = 1; audiocmd *t = NULL; - v4l_dbg(1, debug, &chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); + v4l_dbg(1, debug, chip->c, "ta8874z_setmode(): mode: 0x%02x\n", mode); switch(mode){ - case VIDEO_SOUND_MONO: + case V4L2_TUNER_MODE_MONO: t = &ta8874z_mono; break; - case VIDEO_SOUND_STEREO: + case V4L2_TUNER_MODE_STEREO: t = &ta8874z_stereo; break; - case VIDEO_SOUND_LANG1: + case V4L2_TUNER_MODE_LANG1: t = &ta8874z_main; break; - case VIDEO_SOUND_LANG2: + case V4L2_TUNER_MODE_LANG2: t = &ta8874z_sub; break; default: @@ -1462,51 +1461,55 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_attach(struct i2c_adapter *adap, int addr, int kind) +static int chip_probe(struct i2c_client *client) { struct CHIPSTATE *chip; struct CHIPDESC *desc; + if (debug) { + printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); + printk(KERN_INFO "tvaudio: known chips: "); + for (desc = chiplist; desc->name != NULL; desc++) + printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); + printk("\n"); + } + chip = kzalloc(sizeof(*chip),GFP_KERNEL); if (!chip) return -ENOMEM; - memcpy(&chip->c,&client_template,sizeof(struct i2c_client)); - chip->c.adapter = adap; - chip->c.addr = addr; - i2c_set_clientdata(&chip->c, chip); + chip->c = client; + i2c_set_clientdata(client, chip); /* find description for the chip */ - v4l_dbg(1, debug, &chip->c, "chip found @ 0x%x\n", addr<<1); + v4l_dbg(1, debug, client, "chip found @ 0x%x\n", client->addr<<1); for (desc = chiplist; desc->name != NULL; desc++) { if (0 == *(desc->insmodopt)) continue; - if (addr < desc->addr_lo || - addr > desc->addr_hi) + if (client->addr < desc->addr_lo || + client->addr > desc->addr_hi) continue; if (desc->checkit && !desc->checkit(chip)) continue; break; } if (desc->name == NULL) { - v4l_dbg(1, debug, &chip->c, "no matching chip description found\n"); + v4l_dbg(1, debug, client, "no matching chip description found\n"); return -EIO; } - v4l_info(&chip->c, "%s found @ 0x%x (%s)\n", desc->name, addr<<1, adap->name); + v4l_info(client, "%s found @ 0x%x (%s)\n", desc->name, client->addr<<1, client->adapter->name); if (desc->flags) { - v4l_dbg(1, debug, &chip->c, "matches:%s%s%s.\n", + v4l_dbg(1, debug, client, "matches:%s%s%s.\n", (desc->flags & CHIP_HAS_VOLUME) ? " volume" : "", (desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "", (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); } /* fill required data structures */ - strcpy(chip->c.name, desc->name); + strcpy(client->name, desc->name); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; chip->audmode = V4L2_TUNER_MODE_LANG1; - /* register */ - i2c_attach_client(&chip->c); /* initialization */ if (desc->initialize != NULL) @@ -1533,28 +1536,17 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) init_timer(&chip->wt); chip->wt.function = chip_thread_wake; chip->wt.data = (unsigned long)chip; - chip->thread = kthread_run(chip_thread, chip, chip->c.name); + chip->thread = kthread_run(chip_thread, chip, chip->c->name); if (IS_ERR(chip->thread)) { - v4l_warn(&chip->c, "%s: failed to create kthread\n", - chip->c.name); + v4l_warn(chip->c, "%s: failed to create kthread\n", + chip->c->name); chip->thread = NULL; } } return 0; } -static int chip_probe(struct i2c_adapter *adap) -{ - /* don't attach on saa7146 based cards, - because dedicated drivers are used */ - if ((adap->id == I2C_HW_SAA7146)) - return 0; - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, chip_attach); - return 0; -} - -static int chip_detach(struct i2c_client *client) +static int chip_remove(struct i2c_client *client) { struct CHIPSTATE *chip = i2c_get_clientdata(client); @@ -1565,12 +1557,52 @@ static int chip_detach(struct i2c_client *client) chip->thread = NULL; } - i2c_detach_client(&chip->c); kfree(chip); return 0; } -static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) +static int tvaudio_get_ctrl(struct CHIPSTATE *chip, + struct v4l2_control *ctrl) +{ + struct CHIPDESC *desc = chiplist + chip->type; + + switch (ctrl->id) { + case V4L2_CID_AUDIO_MUTE: + ctrl->value=chip->muted; + return 0; + case V4L2_CID_AUDIO_VOLUME: + if (!desc->flags & CHIP_HAS_VOLUME) + break; + ctrl->value = max(chip->left,chip->right); + return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume; + if (!desc->flags & CHIP_HAS_VOLUME) + break; + volume = max(chip->left,chip->right); + if (volume) + ctrl->value=(32768*min(chip->left,chip->right))/volume; + else + ctrl->value=32768; + return 0; + } + case V4L2_CID_AUDIO_BASS: + if (desc->flags & CHIP_HAS_BASSTREBLE) + break; + ctrl->value = chip->bass; + return 0; + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + ctrl->value = chip->treble; + return 0; + } + return -EINVAL; +} + +static int tvaudio_set_ctrl(struct CHIPSTATE *chip, + struct v4l2_control *ctrl) { struct CHIPDESC *desc = chiplist + chip->type; @@ -1584,11 +1616,60 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, struct v4l2_control *ctrl) else chip_write_masked(chip,desc->inputreg, desc->inputmap[chip->input],desc->inputmask); - break; - default: - return -EINVAL; + return 0; + case V4L2_CID_AUDIO_VOLUME: + { + int volume,balance; + + if (!desc->flags & CHIP_HAS_VOLUME) + break; + + volume = max(chip->left,chip->right); + if (volume) + balance=(32768*min(chip->left,chip->right))/volume; + else + balance=32768; + + volume=ctrl->value; + chip->left = (min(65536 - balance,32768) * volume) / 32768; + chip->right = (min(balance,volume *(__u16)32768)) / 32768; + + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + + return 0; } - return 0; + case V4L2_CID_AUDIO_BALANCE: + { + int volume, balance; + if (!desc->flags & CHIP_HAS_VOLUME) + break; + + volume = max(chip->left,chip->right); + balance = ctrl->value; + + chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); + chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); + + return 0; + } + case V4L2_CID_AUDIO_BASS: + if (desc->flags & CHIP_HAS_BASSTREBLE) + break; + chip->bass = ctrl->value; + chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); + + return 0; + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + + chip->treble = ctrl->value; + chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); + + return 0; + } + return -EINVAL; } @@ -1601,7 +1682,7 @@ static int chip_command(struct i2c_client *client, struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - v4l_dbg(1, debug, &chip->c, "%s: chip_command 0x%x\n", chip->c.name, cmd); + v4l_dbg(1, debug, chip->c, "%s: chip_command 0x%x\n", chip->c->name, cmd); switch (cmd) { case AUDC_SET_RADIO: @@ -1609,67 +1690,36 @@ static int chip_command(struct i2c_client *client, chip->watch_stereo = 0; /* del_timer(&chip->wt); */ break; - /* --- v4l ioctls --- */ /* take care: bttv does userspace copying, we'll get a kernel pointer here... */ - case VIDIOCGAUDIO: - { - struct video_audio *va = arg; - - if (desc->flags & CHIP_HAS_VOLUME) { - va->flags |= VIDEO_AUDIO_VOLUME; - va->volume = max(chip->left,chip->right); - if (va->volume) - va->balance = (32768*min(chip->left,chip->right))/ - va->volume; - else - va->balance = 32768; - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - va->flags |= VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; - va->bass = chip->bass; - va->treble = chip->treble; - } - if (!chip->radio) { - if (desc->getmode) - va->mode = desc->getmode(chip); - else - va->mode = VIDEO_SOUND_MONO; - } - break; - } - - case VIDIOCSAUDIO: + case VIDIOC_QUERYCTRL: { - struct video_audio *va = arg; - - if (desc->flags & CHIP_HAS_VOLUME) { - chip->left = (min(65536 - va->balance,32768) * - va->volume) / 32768; - chip->right = (min(va->balance,(__u16)32768) * - va->volume) / 32768; - chip_write(chip,desc->leftreg,desc->volfunc(chip->left)); - chip_write(chip,desc->rightreg,desc->volfunc(chip->right)); - } - if (desc->flags & CHIP_HAS_BASSTREBLE) { - chip->bass = va->bass; - chip->treble = va->treble; - chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass)); - chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble)); - } - if (desc->setmode && va->mode) { - chip->watch_stereo = 0; - /* del_timer(&chip->wt); */ - chip->mode = va->mode; - desc->setmode(chip,va->mode); + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BALANCE: + if (!desc->flags & CHIP_HAS_VOLUME) + return -EINVAL; + break; + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + if (desc->flags & CHIP_HAS_BASSTREBLE) + return -EINVAL; + break; + default: + return -EINVAL; } - break; + return v4l2_ctrl_query_fill_std(qc); } - case VIDIOC_S_CTRL: return tvaudio_set_ctrl(chip, arg); + case VIDIOC_G_CTRL: + return tvaudio_get_ctrl(chip, arg); case VIDIOC_INT_G_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1678,7 +1728,6 @@ static int chip_command(struct i2c_client *client, rt->output = 0; break; } - case VIDIOC_INT_S_AUDIO_ROUTING: { struct v4l2_routing *rt = arg; @@ -1693,7 +1742,6 @@ static int chip_command(struct i2c_client *client, desc->inputmap[chip->input], desc->inputmask); break; } - case VIDIOC_S_TUNER: { struct v4l2_tuner *vt = arg; @@ -1703,17 +1751,13 @@ static int chip_command(struct i2c_client *client, break; switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: - mode = VIDEO_SOUND_MONO; - break; case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - mode = VIDEO_SOUND_STEREO; - break; case V4L2_TUNER_MODE_LANG1: - mode = VIDEO_SOUND_LANG1; - break; case V4L2_TUNER_MODE_LANG2: - mode = VIDEO_SOUND_LANG2; + mode = vt->audmode; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + mode = V4L2_TUNER_MODE_STEREO; break; default: return -EINVAL; @@ -1728,11 +1772,10 @@ static int chip_command(struct i2c_client *client, } break; } - case VIDIOC_G_TUNER: { struct v4l2_tuner *vt = arg; - int mode = VIDEO_SOUND_MONO; + int mode = V4L2_TUNER_MODE_MONO; if (chip->radio) break; @@ -1744,30 +1787,26 @@ static int chip_command(struct i2c_client *client, if (desc->getmode) mode = desc->getmode(chip); - if (mode & VIDEO_SOUND_MONO) + if (mode & V4L2_TUNER_MODE_MONO) vt->rxsubchans |= V4L2_TUNER_SUB_MONO; - if (mode & VIDEO_SOUND_STEREO) + if (mode & V4L2_TUNER_MODE_STEREO) vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; /* Note: for SAP it should be mono/lang2 or stereo/lang2. When this module is converted fully to v4l2, then this should change for those chips that can detect SAP. */ - if (mode & VIDEO_SOUND_LANG1) + if (mode & V4L2_TUNER_MODE_LANG1) vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; } - - case VIDIOCSCHAN: case VIDIOC_S_STD: chip->radio = 0; break; - - case VIDIOCSFREQ: case VIDIOC_S_FREQUENCY: chip->mode = 0; /* automatic */ if (desc->checkmode) { - desc->setmode(chip,VIDEO_SOUND_MONO); - if (chip->prevmode != VIDEO_SOUND_MONO) + desc->setmode(chip,V4L2_TUNER_MODE_MONO); + if (chip->prevmode != V4L2_TUNER_MODE_MONO) chip->prevmode = -1; /* reset previous mode */ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000)); /* the thread will call checkmode() later */ @@ -1780,44 +1819,25 @@ static int chip_command(struct i2c_client *client, return 0; } -static struct i2c_driver driver = { - .driver = { - .name = "tvaudio", - }, - .id = I2C_DRIVERID_TVAUDIO, - .attach_adapter = chip_probe, - .detach_client = chip_detach, - .command = chip_command, -}; - -static struct i2c_client client_template = +static int chip_legacy_probe(struct i2c_adapter *adap) { - .name = "(unset)", - .driver = &driver, -}; - -static int __init audiochip_init_module(void) -{ - struct CHIPDESC *desc; - - if (debug) { - printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); - printk(KERN_INFO "tvaudio: known chips: "); - for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); - printk("\n"); - } - - return i2c_add_driver(&driver); -} - -static void __exit audiochip_cleanup_module(void) -{ - i2c_del_driver(&driver); + /* don't attach on saa7146 based cards, + because dedicated drivers are used */ + if ((adap->id == I2C_HW_SAA7146)) + return 0; + if (adap->class & I2C_CLASS_TV_ANALOG) + return 1; + return 0; } -module_init(audiochip_init_module); -module_exit(audiochip_cleanup_module); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tvaudio", + .driverid = I2C_DRIVERID_TVAUDIO, + .command = chip_command, + .probe = chip_probe, + .remove = chip_remove, + .legacy_probe = chip_legacy_probe, +}; /* * Local variables: diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 4b2c4034f5b3..0b8fbad3c721 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -46,11 +46,12 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); MODULE_AUTHOR("John Klar"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -#define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown") +#define STRM(array, i) \ + (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") #define tveeprom_info(fmt, arg...) \ v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) @@ -58,7 +59,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) #define tveeprom_dbg(fmt, arg...) do { \ if (debug) \ - v4l_printk(KERN_DEBUG, "tveeprom", c->adapter, c->addr, fmt , ## arg); \ + v4l_printk(KERN_DEBUG, "tveeprom", \ + c->adapter, c->addr, fmt , ## arg); \ } while (0) /* @@ -94,170 +96,172 @@ static struct HAUPPAUGE_TUNER hauppauge_tuner[] = { /* 0-9 */ - { TUNER_ABSENT, "None" }, - { TUNER_ABSENT, "External" }, - { TUNER_ABSENT, "Unspecified" }, - { TUNER_PHILIPS_PAL, "Philips FI1216" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FI1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256" }, - { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, + { TUNER_ABSENT, "None" }, + { TUNER_ABSENT, "External" }, + { TUNER_ABSENT, "Unspecified" }, + { TUNER_PHILIPS_PAL, "Philips FI1216" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246" }, + { TUNER_PHILIPS_PAL_DK, "Philips FI1256" }, + { TUNER_PHILIPS_PAL, "Philips FI1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" }, /* 10-19 */ - { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, - { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" }, - { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, - { TUNER_TEMIC_PAL, "Temic 4002FH5" }, - { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, - { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, - { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, - { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, - { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FI1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" }, + { TUNER_PHILIPS_PAL_DK, "Philips FI1256 MK2" }, + { TUNER_TEMIC_NTSC, "Temic 4032FY5" }, + { TUNER_TEMIC_PAL, "Temic 4002FH5" }, + { TUNER_TEMIC_PAL_I, "Temic 4062FY5" }, + { TUNER_PHILIPS_PAL, "Philips FR1216 MK2" }, + { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" }, + { TUNER_PHILIPS_NTSC, "Philips FR1236 MK2" }, + { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" }, /* 20-29 */ - { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" }, - { TUNER_PHILIPS_PAL, "Philips FM1216" }, - { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, - { TUNER_PHILIPS_NTSC, "Philips FM1236" }, - { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, - { TUNER_PHILIPS_PAL_DK,"Philips FM1256" }, - { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, - { TUNER_ABSENT, "Samsung TCPN9082D" }, - { TUNER_ABSENT, "Samsung TCPM9092P" }, - { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, + { TUNER_PHILIPS_PAL_DK, "Philips FR1256 MK2" }, + { TUNER_PHILIPS_PAL, "Philips FM1216" }, + { TUNER_PHILIPS_SECAM, "Philips FM1216MF" }, + { TUNER_PHILIPS_NTSC, "Philips FM1236" }, + { TUNER_PHILIPS_PAL_I, "Philips FM1246" }, + { TUNER_PHILIPS_PAL_DK, "Philips FM1256" }, + { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" }, + { TUNER_ABSENT, "Samsung TCPN9082D" }, + { TUNER_ABSENT, "Samsung TCPM9092P" }, + { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" }, /* 30-39 */ - { TUNER_ABSENT, "Samsung TCPN9085D" }, - { TUNER_ABSENT, "Samsung TCPB9085P" }, - { TUNER_ABSENT, "Samsung TCPL9091P" }, - { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, - { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, - { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536" }, - { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, - { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ - { TUNER_ABSENT, "Philips FI1256MP" }, + { TUNER_ABSENT, "Samsung TCPN9085D" }, + { TUNER_ABSENT, "Samsung TCPB9085P" }, + { TUNER_ABSENT, "Samsung TCPL9091P" }, + { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" }, + { TUNER_PHILIPS_FQ1216ME, "Philips FQ1216 ME" }, + { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536" }, + { TUNER_PHILIPS_NTSC, "Philips TD1536D" }, + { TUNER_PHILIPS_NTSC, "Philips FMR1236" }, /* mono radio */ + { TUNER_ABSENT, "Philips FI1256MP" }, /* 40-49 */ - { TUNER_ABSENT, "Samsung TCPQ9091P" }, + { TUNER_ABSENT, "Samsung TCPQ9091P" }, { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" }, - { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, - { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, + { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" }, + { TUNER_TEMIC_4046FM5, "Temic 4046FM5" }, { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" }, - { TUNER_ABSENT, "Philips TD1536D FH 44"}, - { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, - { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, - { TUNER_LG_PAL, "LG TP18PSB11D"}, - { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, + { TUNER_ABSENT, "Philips TD1536D FH 44"}, + { TUNER_LG_NTSC_FM, "LG TP18NSR01F"}, + { TUNER_LG_PAL_FM, "LG TP18PSB01D"}, + { TUNER_LG_PAL, "LG TP18PSB11D"}, + { TUNER_LG_PAL_I_FM, "LG TAPC-I001D"}, /* 50-59 */ - { TUNER_LG_PAL_I, "LG TAPC-I701D"}, - { TUNER_ABSENT, "Temic 4042FI5"}, - { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, - { TUNER_ABSENT, "LG TPI8NSR11F"}, - { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, - { TUNER_ABSENT, "Philips FI1236 MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, - { TUNER_ABSENT, "Philips FM1216MP MK3"}, + { TUNER_LG_PAL_I, "LG TAPC-I701D"}, + { TUNER_ABSENT, "Temic 4042FI5"}, + { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"}, + { TUNER_ABSENT, "LG TPI8NSR11F"}, + { TUNER_ABSENT, "Microtune 4049 FM5 Alt I2C"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216ME MK3"}, + { TUNER_ABSENT, "Philips FI1236 MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK3"}, + { TUNER_ABSENT, "Philips FM1216MP MK3"}, /* 60-69 */ - { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, - { TUNER_ABSENT, "LG M001D MK3"}, - { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, - { TUNER_ABSENT, "LG M701D MK3"}, - { TUNER_ABSENT, "Temic 4146FM5"}, - { TUNER_ABSENT, "Temic 4136FY5"}, - { TUNER_ABSENT, "Temic 4106FH5"}, - { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, - { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S001D MK3"}, + { TUNER_ABSENT, "LG M001D MK3"}, + { TUNER_PHILIPS_FM1216ME_MK3, "LG S701D MK3"}, + { TUNER_ABSENT, "LG M701D MK3"}, + { TUNER_ABSENT, "Temic 4146FM5"}, + { TUNER_ABSENT, "Temic 4136FY5"}, + { TUNER_ABSENT, "Temic 4106FH5"}, + { TUNER_ABSENT, "Philips FQ1216LMP MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H001F MK3"}, + { TUNER_LG_NTSC_TAPE, "LG TAPE H701F MK3"}, /* 70-79 */ - { TUNER_ABSENT, "LG TALN H200T"}, - { TUNER_ABSENT, "LG TALN H250T"}, - { TUNER_ABSENT, "LG TALN M200T"}, - { TUNER_ABSENT, "LG TALN Z200T"}, - { TUNER_ABSENT, "LG TALN S200T"}, - { TUNER_ABSENT, "Thompson DTT7595"}, - { TUNER_ABSENT, "Thompson DTT7592"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, - { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, - { TUNER_ABSENT, "Thompson DTT757"}, + { TUNER_ABSENT, "LG TALN H200T"}, + { TUNER_ABSENT, "LG TALN H250T"}, + { TUNER_ABSENT, "LG TALN M200T"}, + { TUNER_ABSENT, "LG TALN Z200T"}, + { TUNER_ABSENT, "LG TALN S200T"}, + { TUNER_ABSENT, "Thompson DTT7595"}, + { TUNER_ABSENT, "Thompson DTT7592"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290"}, + { TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"}, + { TUNER_ABSENT, "Thompson DTT757"}, /* 80-89 */ - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, - { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, - { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, - { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, - { TUNER_TCL_2002N, "TCL 2002N 6A"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, - { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, - { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"}, + { TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"}, + { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"}, + { TUNER_LG_PAL_NEW_TAPC, "TCL 2002MI 3"}, + { TUNER_TCL_2002N, "TCL 2002N 6A"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FQ1236 MK3"}, + { TUNER_SAMSUNG_TCPN_2121P30A, "Samsung TCPN 2121P30A"}, + { TUNER_ABSENT, "Samsung TCPE 4121P30A"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"}, /* 90-99 */ - { TUNER_ABSENT, "LG TALN H202T"}, - { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, - { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, - { TUNER_ABSENT, "Philips FQ1286A MK4"}, - { TUNER_ABSENT, "Philips FQ1216ME MK5"}, - { TUNER_ABSENT, "Philips FQ1236 MK5"}, - { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, - { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, - { TUNER_ABSENT, "TCL 2002MI_3H"}, - { TUNER_TCL_2002N, "TCL 2002N 5H"}, + { TUNER_ABSENT, "LG TALN H202T"}, + { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"}, + { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"}, + { TUNER_ABSENT, "Philips FQ1286A MK4"}, + { TUNER_ABSENT, "Philips FQ1216ME MK5"}, + { TUNER_ABSENT, "Philips FQ1236 MK5"}, + { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"}, + { TUNER_TCL_2002MB, "TCL 2002MB_3H"}, + { TUNER_ABSENT, "TCL 2002MI_3H"}, + { TUNER_TCL_2002N, "TCL 2002N 5H"}, /* 100-109 */ - { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, - { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, - { TUNER_ABSENT, "Panasonic ENV57H12D5"}, - { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, - { TUNER_ABSENT, "TCL MNM05-4"}, - { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, - { TUNER_ABSENT, "TCL MQNM05-4"}, - { TUNER_ABSENT, "LG TAPC-W701D"}, - { TUNER_ABSENT, "TCL 9886P-WM"}, - { TUNER_ABSENT, "TCL 1676NM-WM"}, + { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216ME"}, + { TUNER_TEA5767, "Philips TEA5768HL FM Radio"}, + { TUNER_ABSENT, "Panasonic ENV57H12D5"}, + { TUNER_PHILIPS_FM1236_MK3, "TCL MFNM05-4"}, + { TUNER_ABSENT, "TCL MNM05-4"}, + { TUNER_PHILIPS_FM1216ME_MK3, "TCL MPE05-2"}, + { TUNER_ABSENT, "TCL MQNM05-4"}, + { TUNER_ABSENT, "LG TAPC-W701D"}, + { TUNER_ABSENT, "TCL 9886P-WM"}, + { TUNER_ABSENT, "TCL 1676NM-WM"}, /* 110-119 */ - { TUNER_ABSENT, "Thompson DTT75105"}, - { TUNER_ABSENT, "Conexant_CX24109"}, - { TUNER_TCL_2002N, "TCL M2523_5N_E"}, - { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, - { TUNER_ABSENT, "Philips 8275A"}, - { TUNER_ABSENT, "Microtune MT2060"}, - { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, - { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, - { TUNER_ABSENT, "TCL M2523_3DI_E"}, - { TUNER_ABSENT, "Samsung THPD5222FG30A"}, + { TUNER_ABSENT, "Thompson DTT75105"}, + { TUNER_ABSENT, "Conexant_CX24109"}, + { TUNER_TCL_2002N, "TCL M2523_5N_E"}, + { TUNER_TCL_2002MB, "TCL M2523_3DB_E"}, + { TUNER_ABSENT, "Philips 8275A"}, + { TUNER_ABSENT, "Microtune MT2060"}, + { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"}, + { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"}, + { TUNER_ABSENT, "TCL M2523_3DI_E"}, + { TUNER_ABSENT, "Samsung THPD5222FG30A"}, /* 120-129 */ - { TUNER_ABSENT, "Xceive XC3028"}, - { TUNER_ABSENT, "Philips FQ1216LME MK5"}, - { TUNER_ABSENT, "Philips FQD1216LME"}, - { TUNER_ABSENT, "Conexant CX24118A"}, - { TUNER_ABSENT, "TCL DMF11WIP"}, - { TUNER_ABSENT, "TCL MFNM05_4H_E"}, - { TUNER_ABSENT, "TCL MNM05_4H_E"}, - { TUNER_ABSENT, "TCL MPE05_2H_E"}, - { TUNER_ABSENT, "TCL MQNM05_4_U"}, - { TUNER_ABSENT, "TCL M2523_5NH_E"}, + { TUNER_XC2028, "Xceive XC3028"}, + { TUNER_ABSENT, "Philips FQ1216LME MK5"}, + { TUNER_ABSENT, "Philips FQD1216LME"}, + { TUNER_ABSENT, "Conexant CX24118A"}, + { TUNER_ABSENT, "TCL DMF11WIP"}, + { TUNER_ABSENT, "TCL MFNM05_4H_E"}, + { TUNER_ABSENT, "TCL MNM05_4H_E"}, + { TUNER_ABSENT, "TCL MPE05_2H_E"}, + { TUNER_ABSENT, "TCL MQNM05_4_U"}, + { TUNER_ABSENT, "TCL M2523_5NH_E"}, /* 130-139 */ - { TUNER_ABSENT, "TCL M2523_3DBH_E"}, - { TUNER_ABSENT, "TCL M2523_3DIH_E"}, - { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_ABSENT, "Philips FMD1216MEX"}, - { TUNER_ABSENT, "Philips FRH2036B"}, - { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, - { TUNER_ABSENT, "MaxLinear MXL5005"}, - { TUNER_ABSENT, "MaxLinear MXL5003"}, - { TUNER_ABSENT, "Xceive XC2028"}, - { TUNER_ABSENT, "Microtune MT2131"}, + { TUNER_ABSENT, "TCL M2523_3DBH_E"}, + { TUNER_ABSENT, "TCL M2523_3DIH_E"}, + { TUNER_ABSENT, "TCL MFPE05_2_U"}, + { TUNER_ABSENT, "Philips FMD1216MEX"}, + { TUNER_ABSENT, "Philips FRH2036B"}, + { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, + { TUNER_ABSENT, "MaxLinear MXL5005"}, + { TUNER_ABSENT, "MaxLinear MXL5003"}, + { TUNER_ABSENT, "Xceive XC2028"}, + { TUNER_ABSENT, "Microtune MT2131"}, /* 140-149 */ - { TUNER_ABSENT, "Philips 8275A_8295"}, - { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, - { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, - { TUNER_ABSENT, "Microtune MT2266"}, - { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, - { TUNER_ABSENT, "LG TAPQ_H702F"}, - { TUNER_ABSENT, "TCL M09WPP_4N_E"}, - { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, - { TUNER_ABSENT, "Philips 18271_8295"}, + { TUNER_ABSENT, "Philips 8275A_8295"}, + { TUNER_ABSENT, "TCL MF02GIP_5N_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DB_E"}, + { TUNER_ABSENT, "TCL MF02GIP_3DI_E"}, + { TUNER_ABSENT, "Microtune MT2266"}, + { TUNER_ABSENT, "TCL MF10WPP_4N_E"}, + { TUNER_ABSENT, "LG TAPQ_H702F"}, + { TUNER_ABSENT, "TCL M09WPP_4N_E"}, + { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, + { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, + /* 150-159 */ + { TUNER_ABSENT, "Xceive XC5000"}, }; static struct HAUPPAUGE_AUDIOIC @@ -344,37 +348,37 @@ static const char *decoderIC[] = { static int hasRadioTuner(int tunerType) { switch (tunerType) { - case 18: //PNPEnv_TUNER_FR1236_MK2: - case 23: //PNPEnv_TUNER_FM1236: - case 38: //PNPEnv_TUNER_FMR1236: - case 16: //PNPEnv_TUNER_FR1216_MK2: - case 19: //PNPEnv_TUNER_FR1246_MK2: - case 21: //PNPEnv_TUNER_FM1216: - case 24: //PNPEnv_TUNER_FM1246: - case 17: //PNPEnv_TUNER_FR1216MF_MK2: - case 22: //PNPEnv_TUNER_FM1216MF: - case 20: //PNPEnv_TUNER_FR1256_MK2: - case 25: //PNPEnv_TUNER_FM1256: - case 33: //PNPEnv_TUNER_4039FR5: - case 42: //PNPEnv_TUNER_4009FR5: - case 52: //PNPEnv_TUNER_4049FM5: - case 54: //PNPEnv_TUNER_4049FM5_AltI2C: - case 44: //PNPEnv_TUNER_4009FN5: - case 31: //PNPEnv_TUNER_TCPB9085P: - case 30: //PNPEnv_TUNER_TCPN9085D: - case 46: //PNPEnv_TUNER_TP18NSR01F: - case 47: //PNPEnv_TUNER_TP18PSB01D: - case 49: //PNPEnv_TUNER_TAPC_I001D: - case 60: //PNPEnv_TUNER_TAPE_S001D_MK3: - case 57: //PNPEnv_TUNER_FM1216ME_MK3: - case 59: //PNPEnv_TUNER_FM1216MP_MK3: - case 58: //PNPEnv_TUNER_FM1236_MK3: - case 68: //PNPEnv_TUNER_TAPE_H001F_MK3: - case 61: //PNPEnv_TUNER_TAPE_M001D_MK3: - case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM: - case 89: //PNPEnv_TUNER_TCL_MFPE05_2: - case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4: - case 105: + case 18: /* PNPEnv_TUNER_FR1236_MK2 */ + case 23: /* PNPEnv_TUNER_FM1236 */ + case 38: /* PNPEnv_TUNER_FMR1236 */ + case 16: /* PNPEnv_TUNER_FR1216_MK2 */ + case 19: /* PNPEnv_TUNER_FR1246_MK2 */ + case 21: /* PNPEnv_TUNER_FM1216 */ + case 24: /* PNPEnv_TUNER_FM1246 */ + case 17: /* PNPEnv_TUNER_FR1216MF_MK2 */ + case 22: /* PNPEnv_TUNER_FM1216MF */ + case 20: /* PNPEnv_TUNER_FR1256_MK2 */ + case 25: /* PNPEnv_TUNER_FM1256 */ + case 33: /* PNPEnv_TUNER_4039FR5 */ + case 42: /* PNPEnv_TUNER_4009FR5 */ + case 52: /* PNPEnv_TUNER_4049FM5 */ + case 54: /* PNPEnv_TUNER_4049FM5_AltI2C */ + case 44: /* PNPEnv_TUNER_4009FN5 */ + case 31: /* PNPEnv_TUNER_TCPB9085P */ + case 30: /* PNPEnv_TUNER_TCPN9085D */ + case 46: /* PNPEnv_TUNER_TP18NSR01F */ + case 47: /* PNPEnv_TUNER_TP18PSB01D */ + case 49: /* PNPEnv_TUNER_TAPC_I001D */ + case 60: /* PNPEnv_TUNER_TAPE_S001D_MK3 */ + case 57: /* PNPEnv_TUNER_FM1216ME_MK3 */ + case 59: /* PNPEnv_TUNER_FM1216MP_MK3 */ + case 58: /* PNPEnv_TUNER_FM1236_MK3 */ + case 68: /* PNPEnv_TUNER_TAPE_H001F_MK3 */ + case 61: /* PNPEnv_TUNER_TAPE_M001D_MK3 */ + case 78: /* PNPEnv_TUNER_TDA8275C1_8290_FM */ + case 89: /* PNPEnv_TUNER_TCL_MFPE05_2 */ + case 92: /* PNPEnv_TUNER_PHILIPS_FQ1236A_MK4 */ + case 105: return 1; } return 0; @@ -392,7 +396,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ** ** In our (ivtv) case we're interested in the following: ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner) - ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt) + ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into + ** hauppauge_tuner_fmt) ** radio: tag [00].{last} or [0e].00 (bitmask. bit2=FM) ** audio proc: tag [02].01 or [05].00 (mask with 0x7f) ** decoder proc: tag [09].01) @@ -405,9 +410,9 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ** # of inputs/outputs ??? */ - int i, j, len, done, beenhere, tag,start; + int i, j, len, done, beenhere, tag, start; - int tuner1 = 0, t_format1 = 0, audioic=-1; + int tuner1 = 0, t_format1 = 0, audioic = -1; char *t_name1 = NULL; const char *t_fmt_name1[8] = { " none", "", "", "", "", "", "", "" }; @@ -418,17 +423,24 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, memset(tvee, 0, sizeof(*tvee)); done = len = beenhere = 0; - /* Hack for processing eeprom for em28xx and cx 2388x*/ - if ((eeprom_data[0] == 0x1a) && (eeprom_data[1] == 0xeb) && - (eeprom_data[2] == 0x67) && (eeprom_data[3] == 0x95)) - start=0xa0; /* Generic em28xx offset */ - else if (((eeprom_data[0] & 0xe1) == 0x01) && - (eeprom_data[1] == 0x00) && - (eeprom_data[2] == 0x00) && - (eeprom_data[8] == 0x84)) - start=8; /* Generic cx2388x offset */ + /* Different eeprom start offsets for em28xx, cx2388x and cx23418 */ + if (eeprom_data[0] == 0x1a && + eeprom_data[1] == 0xeb && + eeprom_data[2] == 0x67 && + eeprom_data[3] == 0x95) + start = 0xa0; /* Generic em28xx offset */ + else if ((eeprom_data[0] & 0xe1) == 0x01 && + eeprom_data[1] == 0x00 && + eeprom_data[2] == 0x00 && + eeprom_data[8] == 0x84) + start = 8; /* Generic cx2388x offset */ + else if (eeprom_data[1] == 0x70 && + eeprom_data[2] == 0x00 && + eeprom_data[4] == 0x74 && + eeprom_data[8] == 0x84) + start = 8; /* Generic cx23418 offset (models 74xxx) */ else - start=0; + start = 0; for (i = start; !done && i < 256; i += len) { if (eeprom_data[i] == 0x84) { @@ -444,16 +456,17 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, ++i; } else { tveeprom_warn("Encountered bad packet header [%02x]. " - "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); + "Corrupt or not a Hauppauge eeprom.\n", + eeprom_data[i]); return; } if (debug) { - tveeprom_info("Tag [%02x] + %d bytes:", eeprom_data[i], len - 1); - for(j = 1; j < len; j++) { - printk(" %02x", eeprom_data[i + j]); - } - printk("\n"); + tveeprom_info("Tag [%02x] + %d bytes:", + eeprom_data[i], len - 1); + for (j = 1; j < len; j++) + printk(KERN_CONT " %02x", eeprom_data[i + j]); + printk(KERN_CONT "\n"); } /* process by tag */ @@ -504,16 +517,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i+6] << 8) + (eeprom_data[i+7] << 16); - if ( (eeprom_data[i + 8] & 0xf0) && - (tvee->serial_number < 0xffffff) ) { - tvee->MAC_address[0] = 0x00; - tvee->MAC_address[1] = 0x0D; - tvee->MAC_address[2] = 0xFE; - tvee->MAC_address[3] = eeprom_data[i + 7]; - tvee->MAC_address[4] = eeprom_data[i + 6]; - tvee->MAC_address[5] = eeprom_data[i + 5]; - tvee->has_MAC_address = 1; - } + if ((eeprom_data[i + 8] & 0xf0) && + (tvee->serial_number < 0xffffff)) { + tvee->MAC_address[0] = 0x00; + tvee->MAC_address[1] = 0x0D; + tvee->MAC_address[2] = 0xFE; + tvee->MAC_address[3] = eeprom_data[i + 7]; + tvee->MAC_address[4] = eeprom_data[i + 6]; + tvee->MAC_address[5] = eeprom_data[i + 5]; + tvee->has_MAC_address = 1; + } break; case 0x05: @@ -537,7 +550,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, (eeprom_data[i + 3] << 16) + (eeprom_data[i + 4] << 24); tvee->revision = - eeprom_data[i +5 ] + + eeprom_data[i + 5] + (eeprom_data[i + 6] << 8) + (eeprom_data[i + 7] << 16); break; @@ -557,16 +570,16 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, case 0x0a: /* tag 'Tuner' */ if (beenhere == 0) { - tuner1 = eeprom_data[i+2]; - t_format1 = eeprom_data[i+1]; + tuner1 = eeprom_data[i + 2]; + t_format1 = eeprom_data[i + 1]; beenhere = 1; } else { /* a second (radio) tuner may be present */ - tuner2 = eeprom_data[i+2]; - t_format2 = eeprom_data[i+1]; - if (t_format2 == 0) { /* not a TV tuner? */ + tuner2 = eeprom_data[i + 2]; + t_format2 = eeprom_data[i + 1]; + /* not a TV tuner? */ + if (t_format2 == 0) tvee->has_radio = 1; /* must be radio */ - } } break; @@ -594,7 +607,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, /* case 0x12: tag 'InfoBits' */ default: - tveeprom_dbg("Not sure what to do with tag [%02x]\n", tag); + tveeprom_dbg("Not sure what to do with tag [%02x]\n", + tag); /* dump the rest of the packet? */ } } @@ -608,7 +622,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f); tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f); tvee->rev_str[2] = 32 + ((tvee->revision >> 6) & 0x3f); - tvee->rev_str[3] = 32 + ( tvee->revision & 0x3f); + tvee->rev_str[3] = 32 + (tvee->revision & 0x3f); tvee->rev_str[4] = 0; } @@ -651,44 +665,40 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n", tvee->model, tvee->rev_str, tvee->serial_number); - if (tvee->has_MAC_address == 1) { + if (tvee->has_MAC_address == 1) tveeprom_info("MAC address is %02X-%02X-%02X-%02X-%02X-%02X\n", tvee->MAC_address[0], tvee->MAC_address[1], tvee->MAC_address[2], tvee->MAC_address[3], tvee->MAC_address[4], tvee->MAC_address[5]); - } tveeprom_info("tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], - t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], - t_format1); - if (tuner2) { + t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], + t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], + t_fmt_name1[6], t_fmt_name1[7], t_format1); + if (tuner2) tveeprom_info("second tuner model is %s (idx %d, type %d)\n", t_name2, tuner2, tvee->tuner2_type); - } - if (t_format2) { + if (t_format2) tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", - t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], - t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], - t_format2); - } - if (audioic<0) { + t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], + t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], + 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 = AUDIO_CHIP_UNKNOWN; } else { if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", - audioIC[audioic].name,audioic); + audioIC[audioic].name, audioic); else tveeprom_info("audio processor is unknown (idx %d)\n", audioic); } - if (tvee->decoder_processor) { + if (tvee->decoder_processor) 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 "); @@ -709,11 +719,13 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) int err; buf = 0; - if (1 != (err = i2c_master_send(c, &buf, 1))) { + err = i2c_master_send(c, &buf, 1); + if (err != 1) { tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } - if (len != (err = i2c_master_recv(c, eedata, len))) { + err = i2c_master_recv(c, eedata, len); + if (err != len) { tveeprom_warn("i2c eeprom read error (err=%d)\n", err); return -1; } @@ -724,9 +736,9 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) for (i = 0; i < len; i++) { if (0 == (i % 16)) tveeprom_info("%02x:", i); - printk(" %02x", eedata[i]); + printk(KERN_CONT " %02x", eedata[i]); if (15 == (i % 16)) - printk("\n"); + printk(KERN_CONT "\n"); } } return 0; @@ -758,9 +770,9 @@ tveeprom_command(struct i2c_client *client, switch (cmd) { case 0: - buf = kzalloc(256,GFP_KERNEL); - tveeprom_read(client,buf,256); - tveeprom_hauppauge_analog(client, &eeprom,buf); + buf = kzalloc(256, GFP_KERNEL); + tveeprom_read(client, buf, 256); + tveeprom_hauppauge_analog(client, &eeprom, buf); kfree(buf); eeprom_props[0] = eeprom.tuner_type; eeprom_props[1] = eeprom.tuner_formats; @@ -794,7 +806,7 @@ tveeprom_detect_client(struct i2c_adapter *adapter, } static int -tveeprom_attach_adapter (struct i2c_adapter *adapter) +tveeprom_attach_adapter(struct i2c_adapter *adapter) { if (adapter->class & I2C_CLASS_TV_ANALOG) return i2c_probe(adapter, &addr_data, tveeprom_detect_client); @@ -802,7 +814,7 @@ tveeprom_attach_adapter (struct i2c_adapter *adapter) } static int -tveeprom_detach_client (struct i2c_client *client) +tveeprom_detach_client(struct i2c_client *client) { int err; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index 0b2a961efd22..bd201397a2ac 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -28,30 +28,27 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> #include <media/upd64031a.h> -// --------------------- read registers functions define ----------------------- +/* --------------------- read registers functions define -------------------- */ /* bit masks */ #define GR_MODE_MASK 0xc0 #define DIRECT_3DYCS_CONNECT_MASK 0xc0 #define SYNC_CIRCUIT_MASK 0xa0 -// ----------------------------------------------------------------------------- +/* -------------------------------------------------------------------------- */ MODULE_DESCRIPTION("uPD64031A driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -static unsigned short normal_i2c[] = { 0x24 >> 1, 0x26 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; enum { R00 = 0, R01, R02, R03, R04, @@ -99,7 +96,7 @@ static void upd64031a_write(struct i2c_client *client, u8 reg, u8 val) buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "writing reg addr: %02X val: %02X\n", reg, val); + v4l_dbg(1, debug, client, "write reg: %02X val: %02X\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); } @@ -119,7 +116,7 @@ static void upd64031a_change(struct i2c_client *client) /* ------------------------------------------------------------------------ */ -static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) { struct upd64031a_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -143,8 +140,10 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * state->gr_mode = (route->input & 3) << 6; state->direct_3dycs_connect = (route->input & 0xc) << 4; - state->ext_comp_sync = (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; - state->ext_vert_sync = (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; + state->ext_comp_sync = + (route->input & UPD64031A_COMPOSITE_EXTERNAL) << 1; + state->ext_vert_sync = + (route->input & UPD64031A_VERTICAL_EXTERNAL) << 2; r00 = (state->regs[R00] & ~GR_MODE_MASK) | state->gr_mode; r05 = (state->regs[R00] & ~SYNC_CIRCUIT_MASK) | state->ext_comp_sync | state->ext_vert_sync; @@ -168,20 +167,23 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) + if (cmd == VIDIOC_DBG_G_REGISTER) { reg->val = upd64031a_read(client, reg->reg & 0xff); - else - upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff); + break; + } + upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff); break; } #endif case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64031A, 0); + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_UPD64031A, 0); default: break; @@ -193,90 +195,43 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int upd64031a_attach(struct i2c_adapter *adapter, int address, int kind) +static int upd64031a_probe(struct i2c_client *client) { - struct i2c_client *client; struct upd64031a_state *state; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { - return -ENOMEM; - } - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "uPD64031A"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64031a_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); + if (state == NULL) return -ENOMEM; - } i2c_set_clientdata(client, state); memcpy(state->regs, upd64031a_init, sizeof(state->regs)); state->gr_mode = UPD64031A_GR_ON << 6; state->direct_3dycs_connect = UPD64031A_3DYCS_COMPOSITE << 4; state->ext_comp_sync = state->ext_vert_sync = 0; - for (i = 0; i < TOT_REGS; i++) { + for (i = 0; i < TOT_REGS; i++) upd64031a_write(client, i, state->regs[i]); - } - - i2c_attach_client(client); - return 0; } -static int upd64031a_probe(struct i2c_adapter *adapter) +static int upd64031a_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, upd64031a_attach); - return 0; -} - -static int upd64031a_detach(struct i2c_client *client) -{ - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "upd64031a", - }, - .id = I2C_DRIVERID_UPD64031A, - .attach_adapter = upd64031a_probe, - .detach_client = upd64031a_detach, + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "upd64031a", + .driverid = I2C_DRIVERID_UPD64031A, .command = upd64031a_command, + .probe = upd64031a_probe, + .remove = upd64031a_remove, }; - - -static int __init upd64031a_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit upd64031a_exit_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(upd64031a_init_module); -module_exit(upd64031a_exit_module); diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 401bd21f46eb..2d9a88f70c85 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -17,7 +17,8 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ #include <linux/version.h> @@ -27,21 +28,18 @@ #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> #include <media/upd64083.h> MODULE_DESCRIPTION("uPD64083 driver"); MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; +static int debug; module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; enum { R00 = 0, R01, R02, R03, R04, @@ -88,7 +86,7 @@ static void upd64083_write(struct i2c_client *client, u8 reg, u8 val) buf[0] = reg; buf[1] = val; - v4l_dbg(1, debug, client, "writing reg addr: %02x val: %02x\n", reg, val); + v4l_dbg(1, debug, client, "write reg: %02x val: %02x\n", reg, val); if (i2c_master_send(client, buf, 2) != 2) v4l_err(client, "I/O error write 0x%02x/0x%02x\n", reg, val); } @@ -109,7 +107,7 @@ static u8 upd64083_read(struct i2c_client *client, u8 reg) /* ------------------------------------------------------------------------ */ -static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) { struct upd64083_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -145,20 +143,23 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a { struct v4l2_register *reg = arg; - if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) + if (!v4l2_chip_match_i2c_client(client, + reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (cmd == VIDIOC_DBG_G_REGISTER) + if (cmd == VIDIOC_DBG_G_REGISTER) { reg->val = upd64083_read(client, reg->reg & 0xff); - else - upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); + break; + } + upd64083_write(client, reg->reg & 0xff, reg->val & 0xff); break; } #endif case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_UPD64083, 0); + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_UPD64083, 0); default: break; @@ -171,89 +172,43 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int upd64083_attach(struct i2c_adapter *adapter, int address, int kind) +static int upd64083_probe(struct i2c_client *client) { - struct i2c_client *client; struct upd64083_state *state; int i; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) { - return -ENOMEM; - } - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "uPD64083"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct upd64083_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); + if (state == NULL) return -ENOMEM; - } i2c_set_clientdata(client, state); /* Initially assume that a ghost reduction chip is present */ state->mode = 0; /* YCS mode */ state->ext_y_adc = (1 << 5); memcpy(state->regs, upd64083_init, TOT_REGS); - for (i = 0; i < TOT_REGS; i++) { + for (i = 0; i < TOT_REGS; i++) upd64083_write(client, i, state->regs[i]); - } - i2c_attach_client(client); - - return 0; -} - -static int upd64083_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, upd64083_attach); return 0; } -static int upd64083_detach(struct i2c_client *client) +static int upd64083_remove(struct i2c_client *client) { - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "upd64083", - }, - .id = I2C_DRIVERID_UPD64083, - .attach_adapter = upd64083_probe, - .detach_client = upd64083_detach, + +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "upd64083", + .driverid = I2C_DRIVERID_UPD64083, .command = upd64083_command, + .probe = upd64083_probe, + .remove = upd64083_remove, }; - - -static int __init upd64083_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit upd64083_exit_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(upd64083_init_module); -module_exit(upd64083_exit_module); diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index f09eb102731b..503b13beb922 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -901,6 +901,20 @@ struct usbvision_device_data_st usbvision_device_data[] = { .Y_Offset = -1, .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM", }, + [PINNA_PCTV_USB_NTSC_FM_V3] = { + .Interface = -1, + .Codec = CODEC_SAA7111, + .VideoChannels = 3, + .VideoNorm = V4L2_STD_NTSC, + .AudioChannels = 1, + .Radio = 1, + .vbi = 1, + .Tuner = 1, + .TunerType = TUNER_PHILIPS_NTSC_M, + .X_Offset = -1, + .Y_Offset = -1, + .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V3", + }, [PINNA_PCTV_USB_PAL_FM_V2] = { .Interface = -1, .Codec = CODEC_SAA7113, @@ -1044,7 +1058,7 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN }, { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 }, { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL }, - { USB_DEVICE(0x0573, 0x4d20), .driver_info=HPG_WINTV_PRO_NTSC_MN_V3 }, + { USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 }, { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG }, { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I }, { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L }, @@ -1074,6 +1088,8 @@ struct usb_device_id usbvision_table [] = { { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM }, { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB }, { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM }, + { USB_DEVICE(0x2304, 0x0113), + .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 }, { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 }, { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 }, { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 }, diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h index 512c5cee4145..9c6ad22960d8 100644 --- a/drivers/media/video/usbvision/usbvision-cards.h +++ b/drivers/media/video/usbvision/usbvision-cards.h @@ -62,5 +62,6 @@ #define PINNA_LINX_VD_IN_CAB_PAL 61 #define PINNA_PCTV_BUNGEE_PAL_FM 62 #define HPG_WINTV 63 +#define PINNA_PCTV_USB_NTSC_FM_V3 64 extern const int usbvision_device_data_size; diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c index c7d5f9ed22d7..56775ab8b75d 100644 --- a/drivers/media/video/usbvision/usbvision-core.c +++ b/drivers/media/video/usbvision/usbvision-core.c @@ -69,6 +69,15 @@ static int SwitchSVideoInput = 0; // To help people with Black and White outpu module_param(SwitchSVideoInput, int, 0444); MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)"); +static unsigned int adjust_X_Offset = -1; +module_param(adjust_X_Offset, int, 0644); +MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]"); + +static unsigned int adjust_Y_Offset = -1; +module_param(adjust_Y_Offset, int, 0644); +MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]"); + + #define ENABLE_HEXDUMP 0 /* Enable if you need it */ @@ -624,25 +633,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv); switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); - *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = bv; - *f++ = gv; - *f++ = rv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = bv; - *f++ = gv; - *f++ = rv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); - *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x07 & (gv >> 3)) | + (0xF8 & bv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = rv; + *f++ = gv; + *f++ = bv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = rv; + *f++ = gv; + *f++ = bv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x03 & (gv >> 3)) | + (0x7C & (bv << 2)); + break; } } clipmask_index += clipmask_add; @@ -656,25 +669,29 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv); switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); - *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); - break; - case V4L2_PIX_FMT_RGB24: - *f++ = bv; - *f++ = gv; - *f++ = rv; - break; - case V4L2_PIX_FMT_RGB32: - *f++ = bv; - *f++ = gv; - *f++ = rv; - f++; - break; - case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); - *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x07 & (gv >> 3)) | + (0xF8 & bv); + break; + case V4L2_PIX_FMT_RGB24: + *f++ = rv; + *f++ = gv; + *f++ = bv; + break; + case V4L2_PIX_FMT_RGB32: + *f++ = rv; + *f++ = gv; + *f++ = bv; + f++; + break; + case V4L2_PIX_FMT_RGB555: + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x03 & (gv >> 3)) | + (0x7C & (bv << 2)); + break; } } clipmask_index += clipmask_add; @@ -942,22 +959,26 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision, *f++ = Y[Idx]; break; case V4L2_PIX_FMT_RGB555: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 2)); - *f++ = (0x03 & (gv >> 6)) | (0x7C & (rv >> 1)); + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x03 & (gv >> 3)) | + (0x7C & (bv << 2)); break; case V4L2_PIX_FMT_RGB565: - *f++ = (0x1F & (bv >> 3)) | (0xE0 & (gv << 3)); - *f++ = (0x07 & (gv >> 5)) | (0xF8 & rv); + *f++ = (0x1F & rv) | + (0xE0 & (gv << 5)); + *f++ = (0x07 & (gv >> 3)) | + (0xF8 & bv); break; case V4L2_PIX_FMT_RGB24: - *f++ = bv; - *f++ = gv; *f++ = rv; + *f++ = gv; + *f++ = bv; break; case V4L2_PIX_FMT_RGB32: - *f++ = bv; - *f++ = gv; *f++ = rv; + *f++ = gv; + *f++ = bv; f++; break; } @@ -1071,28 +1092,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_even++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_even_index += clipmask_add; @@ -1110,28 +1136,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_even++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_even++ = LIMIT_RGB(b_); - *f_even++ = LIMIT_RGB(g_); - *f_even++ = LIMIT_RGB(r_); - f_even++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_even++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_even++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_even++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_even++ = LIMIT_RGB(r_); + *f_even++ = LIMIT_RGB(g_); + *f_even++ = LIMIT_RGB(b_); + f_even++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_even++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_even++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_even_index += clipmask_add; @@ -1151,28 +1182,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_odd++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_odd_index += clipmask_add; @@ -1190,28 +1226,33 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision r_ = (y_ + ur) >> 16; switch (frame->v4l2_format.format) { - case V4L2_PIX_FMT_RGB565: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 3)); - *f_odd++ = (0x07 & ( g >> 5)) | (0xF8 & LIMIT_RGB(r_)); - break; - case V4L2_PIX_FMT_RGB24: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - break; - case V4L2_PIX_FMT_RGB32: - *f_odd++ = LIMIT_RGB(b_); - *f_odd++ = LIMIT_RGB(g_); - *f_odd++ = LIMIT_RGB(r_); - f_odd++; - break; - case V4L2_PIX_FMT_RGB555: - g = LIMIT_RGB(g_); - *f_odd++ = (0x1F & (LIMIT_RGB(b_) >> 3)) | (0xE0 & (g << 2)); - *f_odd++ = (0x03 & ( g >> 6)) | - (0x7C & (LIMIT_RGB(r_) >> 1)); - break; + case V4L2_PIX_FMT_RGB565: + g = LIMIT_RGB(g_); + *f_odd++ = + (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = + (0x07 & (g >> 3)) | + (0xF8 & LIMIT_RGB(b_)); + break; + case V4L2_PIX_FMT_RGB24: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + break; + case V4L2_PIX_FMT_RGB32: + *f_odd++ = LIMIT_RGB(r_); + *f_odd++ = LIMIT_RGB(g_); + *f_odd++ = LIMIT_RGB(b_); + f_odd++; + break; + case V4L2_PIX_FMT_RGB555: + g = LIMIT_RGB(g_); + *f_odd++ = (0x1F & LIMIT_RGB(r_)) | + (0xE0 & (g << 5)); + *f_odd++ = (0x03 & (g >> 3)) | + (0x7C & (LIMIT_RGB(b_) << 2)); + break; } } clipmask_odd_index += clipmask_add; @@ -1561,13 +1602,10 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address, if (len > 8) { return -EFAULT; } -// down(&usbvision->ctrlUrbLock); if (usbvision->ctrlUrbBusy) { -// up(&usbvision->ctrlUrbLock); return -EBUSY; } usbvision->ctrlUrbBusy = 1; -// up(&usbvision->ctrlUrbLock); usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT; usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE; @@ -2100,11 +2138,21 @@ int usbvision_set_input(struct usb_usbvision *usbvision) value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8; } + if (adjust_X_Offset != -1) { + value[4] = adjust_X_Offset & 0xff; + value[5] = (adjust_X_Offset & 0x0300) >> 8; + } + if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) { value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff; value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8; } + if (adjust_Y_Offset != -1) { + value[6] = adjust_Y_Offset & 0xff; + value[7] = (adjust_Y_Offset & 0x0300) >> 8; + } + rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1), USBVISION_OP_CODE, /* USBVISION specific code */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0, @@ -2242,14 +2290,18 @@ static void call_usbvision_power_off(struct work_struct *work) struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork); PDEBUG(DBG_FUNC, ""); - down_interruptible(&usbvision->lock); + if(mutex_lock_interruptible(&usbvision->lock)) { + return; + } + + if(usbvision->user == 0) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); } static void usbvision_powerOffTimer(unsigned long data) diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index 36e689fa16c0..b52b826a30be 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -410,7 +410,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) /* If so far no errors then we shall start the camera */ if (!errCode) { - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (usbvision->power == 0) { usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); @@ -439,7 +439,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); } if (errCode) { @@ -467,7 +467,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) (struct usb_usbvision *) video_get_drvdata(dev); PDEBUG(DBG_IO, "close"); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_audio_off(usbvision); usbvision_restart_isoc(usbvision); @@ -487,7 +487,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -647,13 +647,13 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input) if ((input >= usbvision->video_inputs) || (input < 0) ) return -EINVAL; - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_muxsel(usbvision, input); usbvision_set_input(usbvision); usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -664,10 +664,10 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) (struct usb_usbvision *) video_get_drvdata(dev); usbvision->tvnormId=*id; - down(&usbvision->lock); + mutex_lock(&usbvision->lock); call_i2c_clients(usbvision, VIDIOC_S_STD, &usbvision->tvnormId); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); /* propagate the change to the decoder */ usbvision_muxsel(usbvision, usbvision->ctl_input); @@ -1083,9 +1083,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, usbvision->curFrame = NULL; /* by now we are committed to the new data... */ - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -1211,16 +1211,16 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) PDEBUG(DBG_MMAP, "mmap"); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (!USBVISION_IS_OPERATIONAL(usbvision)) { - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EFAULT; } if (!(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(usbvision->max_frame_size)) { - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EINVAL; } @@ -1232,7 +1232,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (i == usbvision->num_frames) { PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EINVAL; } @@ -1245,7 +1245,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1253,7 +1253,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) size -= PAGE_SIZE; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); return 0; } @@ -1271,7 +1271,7 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) PDEBUG(DBG_IO, "%s:", __FUNCTION__); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); if (usbvision->user) { err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__); @@ -1290,7 +1290,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) errCode = usbvision_set_alternate(usbvision); if (errCode < 0) { usbvision->last_error = errCode; - return -EBUSY; + errCode = -EBUSY; + goto out; } // If so far no errors then we shall start the radio @@ -1307,7 +1308,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file) usbvision->initialized = 0; } } - up(&usbvision->lock); +out: + mutex_unlock(&usbvision->lock); return errCode; } @@ -1321,7 +1323,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) PDEBUG(DBG_IO, ""); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); /* Set packet size to 0 */ usbvision->ifaceAlt=0; @@ -1337,7 +1339,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file) usbvision->initialized = 0; } - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__); @@ -1641,7 +1643,7 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) usbvision->dev = dev; - init_MUTEX(&usbvision->lock); /* to 1 == available */ + mutex_init(&usbvision->lock); /* available */ // prepare control urb for control messages during interrupts usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL); @@ -1649,7 +1651,6 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev) goto err_exit; } init_waitqueue_head(&usbvision->ctrlUrb_wq); - init_MUTEX(&usbvision->ctrlUrbLock); /* to 1 == available */ usbvision_init_powerOffTimer(usbvision); @@ -1676,13 +1677,13 @@ static void usbvision_release(struct usb_usbvision *usbvision) { PDEBUG(DBG_PROBE, ""); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); usbvision_reset_powerOffTimer(usbvision); usbvision->initialized = 0; - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); usbvision_remove_sysfs(usbvision->vdev); usbvision_unregister_video(usbvision); @@ -1796,7 +1797,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, } PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); /* compute alternate max packet sizes */ uif = dev->actconfig->interface[0]; @@ -1807,6 +1808,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->num_alt,GFP_KERNEL); if (usbvision->alt_max_pkt_size == NULL) { err("usbvision: out of memory!\n"); + mutex_unlock(&usbvision->lock); return -ENOMEM; } @@ -1840,7 +1842,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf, usbvision->streaming = Stream_Off; usbvision_register_video(usbvision); usbvision_configure_video(usbvision); - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); usb_set_intfdata (intf, usbvision); @@ -1871,7 +1873,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) } usb_set_intfdata (intf, NULL); - down(&usbvision->lock); + mutex_lock(&usbvision->lock); // At this time we ask to cancel outstanding URBs usbvision_stop_isoc(usbvision); @@ -1885,7 +1887,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf) usb_put_dev(usbvision->dev); usbvision->dev = NULL; // USB device is no more - up(&usbvision->lock); + mutex_unlock(&usbvision->lock); if (usbvision->user) { printk(KERN_INFO "%s: In use, disconnect pending\n", diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h index c5b6c501c869..20d7ec624999 100644 --- a/drivers/media/video/usbvision/usbvision.h +++ b/drivers/media/video/usbvision/usbvision.h @@ -34,16 +34,13 @@ #include <linux/list.h> #include <linux/usb.h> #include <linux/i2c.h> +#include <linux/mutex.h> #include <media/v4l2-common.h> #include <media/tuner.h> #include <linux/videodev2.h> #define USBVISION_DEBUG /* Turn on debug messages */ -#ifndef VID_HARDWARE_USBVISION - #define VID_HARDWARE_USBVISION 34 /* USBVision Video Grabber */ -#endif - #define USBVISION_PWR_REG 0x00 #define USBVISION_SSPND_EN (1 << 1) #define USBVISION_RES2 (1 << 2) @@ -373,7 +370,6 @@ struct usb_usbvision { int ctrlUrbBusy; struct usb_ctrlrequest ctrlUrbSetup; wait_queue_head_t ctrlUrb_wq; // Processes waiting - struct semaphore ctrlUrbLock; /* configuration part */ int have_tuner; @@ -396,7 +392,7 @@ struct usb_usbvision { unsigned char iface; /* Video interface number */ unsigned char ifaceAlt; /* Alt settings */ unsigned char Vin_Reg2_Preset; - struct semaphore lock; + struct mutex lock; struct timer_list powerOffTimer; struct work_struct powerOffWork; int power; /* is the device powered on? */ diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 1141b4bf41ce..c056ff6d810c 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -400,7 +400,7 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", - [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", + [_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", @@ -1013,6 +1013,34 @@ int v4l2_chip_match_host(u32 match_type, u32 match_chip) /* ----------------------------------------------------------------- */ +/* Helper function for I2C legacy drivers */ + +int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, + const char *name, int (*probe)(struct i2c_client *)) +{ + struct i2c_client *client; + int err; + + client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (client == 0) + return -ENOMEM; + + client->addr = address; + client->adapter = adapter; + client->driver = driver; + strlcpy(client->name, name, sizeof(client->name)); + + err = probe(client); + if (err == 0) { + i2c_attach_client(client); + } else { + kfree(client); + } + return err != -ENOMEM ? 0 : err; +} + +/* ----------------------------------------------------------------- */ + EXPORT_SYMBOL(v4l2_norm_to_name); EXPORT_SYMBOL(v4l2_video_std_construct); @@ -1038,6 +1066,8 @@ EXPORT_SYMBOL(v4l2_chip_match_i2c_client); EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); EXPORT_SYMBOL(v4l2_chip_match_host); +EXPORT_SYMBOL(v4l2_i2c_attach); + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c index 8b4ef530a3a8..a545dcaf857f 100644 --- a/drivers/media/video/v4l2-int-device.c +++ b/drivers/media/video/v4l2-int-device.c @@ -57,12 +57,12 @@ static void v4l2_int_device_try_attach_all(void) if (!try_module_get(m->module)) continue; - if (m->u.master->attach(m, s)) { + s->u.slave->master = m; + if (m->u.master->attach(s)) { + s->u.slave->master = NULL; module_put(m->module); continue; } - - s->u.slave->master = m; } } } diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index c8a5cb57963b..80a14da9acef 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -22,29 +22,32 @@ #include <media/videobuf-core.h> #define MAGIC_BUFFER 0x20070728 -#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ - { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } +#define MAGIC_CHECK(is, should) do { \ + if (unlikely((is) != (should))) { \ + printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \ + BUG(); } } while (0) -static int debug = 0; +static int debug; module_param(debug, int, 0644); MODULE_DESCRIPTION("helper module to manage video4linux buffers"); MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); MODULE_LICENSE("GPL"); -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf: " fmt , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0) /* --------------------------------------------------------------------- */ #define CALL(q, f, arg...) \ - ( (q->int_ops->f)? q->int_ops->f(arg) : 0) + ((q->int_ops->f) ? q->int_ops->f(arg) : 0) -void* videobuf_alloc(struct videobuf_queue* q) +void *videobuf_alloc(struct videobuf_queue *q) { struct videobuf_buffer *vb; - BUG_ON (q->msize<sizeof(*vb)); + BUG_ON(q->msize < sizeof(*vb)); if (!q->int_ops || !q->int_ops->alloc) { printk(KERN_ERR "No specific ops defined!\n"); @@ -66,20 +69,21 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) int retval = 0; DECLARE_WAITQUEUE(wait, current); - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); add_wait_queue(&vb->done, &wait); - while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) { + while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) { if (non_blocking) { retval = -EAGAIN; break; } set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) + if (vb->state == VIDEOBUF_ACTIVE || + vb->state == VIDEOBUF_QUEUED) schedule(); set_current_state(TASK_RUNNING); if (intr && signal_pending(current)) { - dprintk(1,"buffer waiton: -EINTR\n"); + dprintk(1, "buffer waiton: -EINTR\n"); retval = -EINTR; break; } @@ -88,27 +92,33 @@ int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) return retval; } -int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb, +int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf) { - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - /* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper() - method should be called before _iolock. + /* This is required to avoid OOPS on some cases, + since mmap_mapper() method should be called before _iolock. On some cases, the mmap_mapper() is called only after scheduling. - - However, this way is just too dirty! Better to wait for some event. */ - schedule_timeout(HZ); + if (vb->memory == V4L2_MEMORY_MMAP) { + wait_event_timeout(vb->done, q->is_mmapped, + msecs_to_jiffies(100)); + if (!q->is_mmapped) { + printk(KERN_ERR + "Error: mmap_mapper() never called!\n"); + return -EINVAL; + } + } - return CALL(q,iolock,q,vb,fbuf); + return CALL(q, iolock, q, vb, fbuf); } /* --------------------------------------------------------------------- */ -void videobuf_queue_core_init(struct videobuf_queue* q, +void videobuf_queue_core_init(struct videobuf_queue *q, struct videobuf_queue_ops *ops, void *dev, spinlock_t *irqlock, @@ -118,7 +128,7 @@ void videobuf_queue_core_init(struct videobuf_queue* q, void *priv, struct videobuf_qtype_ops *int_ops) { - memset(q,0,sizeof(*q)); + memset(q, 0, sizeof(*q)); q->irqlock = irqlock; q->dev = dev; q->type = type; @@ -129,13 +139,13 @@ void videobuf_queue_core_init(struct videobuf_queue* q, q->int_ops = int_ops; /* All buffer operations are mandatory */ - BUG_ON (!q->ops->buf_setup); - BUG_ON (!q->ops->buf_prepare); - BUG_ON (!q->ops->buf_queue); - BUG_ON (!q->ops->buf_release); + BUG_ON(!q->ops->buf_setup); + BUG_ON(!q->ops->buf_prepare); + BUG_ON(!q->ops->buf_queue); + BUG_ON(!q->ops->buf_release); /* Having implementations for abstract methods are mandatory */ - BUG_ON (!q->int_ops); + BUG_ON(!q->int_ops); mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); @@ -146,33 +156,33 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) { int i; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); if (q->streaming) { - dprintk(1,"busy: streaming active\n"); + dprintk(1, "busy: streaming active\n"); return 1; } if (q->reading) { - dprintk(1,"busy: pending read #1\n"); + dprintk(1, "busy: pending read #1\n"); return 1; } if (q->read_buf) { - dprintk(1,"busy: pending read #2\n"); + dprintk(1, "busy: pending read #2\n"); return 1; } for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; if (q->bufs[i]->map) { - dprintk(1,"busy: buffer #%d mapped\n",i); + dprintk(1, "busy: buffer #%d mapped\n", i); return 1; } - if (q->bufs[i]->state == STATE_QUEUED) { - dprintk(1,"busy: buffer #%d queued\n",i); + if (q->bufs[i]->state == VIDEOBUF_QUEUED) { + dprintk(1, "busy: buffer #%d queued\n", i); return 1; } - if (q->bufs[i]->state == STATE_ACTIVE) { - dprintk(1,"busy: buffer #%d avtive\n",i); + if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { + dprintk(1, "busy: buffer #%d avtive\n", i); return 1; } } @@ -182,28 +192,28 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) /* Locking: Caller holds q->lock */ void videobuf_queue_cancel(struct videobuf_queue *q) { - unsigned long flags=0; + unsigned long flags = 0; int i; /* remove queued buffers from list */ if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - if (q->bufs[i]->state == STATE_QUEUED) { + if (q->bufs[i]->state == VIDEOBUF_QUEUED) { list_del(&q->bufs[i]->queue); - q->bufs[i]->state = STATE_ERROR; + q->bufs[i]->state = VIDEOBUF_ERROR; } } if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); /* free all buffers + clear queue */ for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(q,q->bufs[i]); + q->ops->buf_release(q, q->bufs[i]); } INIT_LIST_HEAD(&q->stream); } @@ -233,8 +243,8 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, struct videobuf_buffer *vb, enum v4l2_buf_type type) { - MAGIC_CHECK(vb->magic,MAGIC_BUFFER); - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(vb->magic, MAGIC_BUFFER); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); b->index = vb->i; b->type = type; @@ -259,17 +269,17 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, b->flags |= V4L2_BUF_FLAG_MAPPED; switch (vb->state) { - case STATE_PREPARED: - case STATE_QUEUED: - case STATE_ACTIVE: + case VIDEOBUF_PREPARED: + case VIDEOBUF_QUEUED: + case VIDEOBUF_ACTIVE: b->flags |= V4L2_BUF_FLAG_QUEUED; break; - case STATE_DONE: - case STATE_ERROR: + case VIDEOBUF_DONE: + case VIDEOBUF_ERROR: b->flags |= V4L2_BUF_FLAG_DONE; break; - case STATE_NEEDS_INIT: - case STATE_IDLE: + case VIDEOBUF_NEEDS_INIT: + case VIDEOBUF_IDLE: /* nothing */ break; } @@ -294,16 +304,20 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) if (!q) return 0; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); + + + rc = CALL(q, mmap_free, q); + + q->is_mmapped = 0; - rc = CALL(q,mmap_free,q); - if (rc<0) + if (rc < 0) return rc; for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; - q->ops->buf_release(q,q->bufs[i]); + q->ops->buf_release(q, q->bufs[i]); kfree(q->bufs[i]); q->bufs[i] = NULL; } @@ -328,7 +342,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int i; int err; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); err = __videobuf_mmap_free(q); if (0 != err) @@ -359,7 +373,7 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q, if (!i) return -ENOMEM; - dprintk(1,"mmap setup: %d buffers, %d bytes each\n", + dprintk(1, "mmap setup: %d buffers, %d bytes each\n", i, bsize); return i; @@ -379,35 +393,35 @@ int videobuf_mmap_setup(struct videobuf_queue *q, int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) { - unsigned int size,count; + unsigned int size, count; int retval; if (req->count < 1) { - dprintk(1,"reqbufs: count invalid (%d)\n",req->count); + dprintk(1, "reqbufs: count invalid (%d)\n", req->count); return -EINVAL; } if (req->memory != V4L2_MEMORY_MMAP && req->memory != V4L2_MEMORY_USERPTR && req->memory != V4L2_MEMORY_OVERLAY) { - dprintk(1,"reqbufs: memory type invalid\n"); + dprintk(1, "reqbufs: memory type invalid\n"); return -EINVAL; } mutex_lock(&q->lock); if (req->type != q->type) { - dprintk(1,"reqbufs: queue type invalid\n"); + dprintk(1, "reqbufs: queue type invalid\n"); retval = -EINVAL; goto done; } if (q->streaming) { - dprintk(1,"reqbufs: streaming already exists\n"); + dprintk(1, "reqbufs: streaming already exists\n"); retval = -EBUSY; goto done; } if (!list_empty(&q->stream)) { - dprintk(1,"reqbufs: stream running\n"); + dprintk(1, "reqbufs: stream running\n"); retval = -EBUSY; goto done; } @@ -416,14 +430,14 @@ int videobuf_reqbufs(struct videobuf_queue *q, if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; size = 0; - q->ops->buf_setup(q,&count,&size); + q->ops->buf_setup(q, &count, &size); size = PAGE_ALIGN(size); - dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n", + dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n", count, size, (count*size)>>PAGE_SHIFT); - retval = __videobuf_mmap_setup(q,count,size,req->memory); + retval = __videobuf_mmap_setup(q, count, size, req->memory); if (retval < 0) { - dprintk(1,"reqbufs: mmap setup returned %d\n",retval); + dprintk(1, "reqbufs: mmap setup returned %d\n", retval); goto done; } @@ -440,19 +454,19 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) mutex_lock(&q->lock); if (unlikely(b->type != q->type)) { - dprintk(1,"querybuf: Wrong type.\n"); + dprintk(1, "querybuf: Wrong type.\n"); goto done; } if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) { - dprintk(1,"querybuf: index out of range.\n"); + dprintk(1, "querybuf: index out of range.\n"); goto done; } if (unlikely(NULL == q->bufs[b->index])) { - dprintk(1,"querybuf: buffer is null.\n"); + dprintk(1, "querybuf: buffer is null.\n"); goto done; } - videobuf_status(q,b,q->bufs[b->index],q->type); + videobuf_status(q, b, q->bufs[b->index], q->type); ret = 0; done: @@ -465,10 +479,10 @@ int videobuf_qbuf(struct videobuf_queue *q, { struct videobuf_buffer *buf; enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); if (b->memory == V4L2_MEMORY_MMAP) down_read(¤t->mm->mmap_sem); @@ -476,36 +490,36 @@ int videobuf_qbuf(struct videobuf_queue *q, mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { - dprintk(1,"qbuf: Reading running...\n"); + dprintk(1, "qbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { - dprintk(1,"qbuf: Wrong type.\n"); + dprintk(1, "qbuf: Wrong type.\n"); goto done; } if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) { - dprintk(1,"qbuf: index out of range.\n"); + dprintk(1, "qbuf: index out of range.\n"); goto done; } buf = q->bufs[b->index]; if (NULL == buf) { - dprintk(1,"qbuf: buffer is null.\n"); + dprintk(1, "qbuf: buffer is null.\n"); goto done; } - MAGIC_CHECK(buf->magic,MAGIC_BUFFER); + MAGIC_CHECK(buf->magic, MAGIC_BUFFER); if (buf->memory != b->memory) { - dprintk(1,"qbuf: memory type is wrong.\n"); + dprintk(1, "qbuf: memory type is wrong.\n"); goto done; } - if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) { - dprintk(1,"qbuf: buffer is already queued or active.\n"); + if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { + dprintk(1, "qbuf: buffer is already queued or active.\n"); goto done; } if (b->flags & V4L2_BUF_FLAG_INPUT) { if (b->input >= q->inputs) { - dprintk(1,"qbuf: wrong input.\n"); + dprintk(1, "qbuf: wrong input.\n"); goto done; } buf->input = b->input; @@ -516,44 +530,46 @@ int videobuf_qbuf(struct videobuf_queue *q, switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { - dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n"); + dprintk(1, "qbuf: mmap requested " + "but buffer addr is zero!\n"); goto done; } break; case V4L2_MEMORY_USERPTR: if (b->length < buf->bsize) { - dprintk(1,"qbuf: buffer length is not enough\n"); + dprintk(1, "qbuf: buffer length is not enough\n"); goto done; } - if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr) - q->ops->buf_release(q,buf); + if (VIDEOBUF_NEEDS_INIT != buf->state && + buf->baddr != b->m.userptr) + q->ops->buf_release(q, buf); buf->baddr = b->m.userptr; break; case V4L2_MEMORY_OVERLAY: buf->boff = b->m.offset; break; default: - dprintk(1,"qbuf: wrong memory type\n"); + dprintk(1, "qbuf: wrong memory type\n"); goto done; } - dprintk(1,"qbuf: requesting next field\n"); + dprintk(1, "qbuf: requesting next field\n"); field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,buf,field); + retval = q->ops->buf_prepare(q, buf, field); if (0 != retval) { - dprintk(1,"qbuf: buffer_prepare returned %d\n",retval); + dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); goto done; } - list_add_tail(&buf->stream,&q->stream); + list_add_tail(&buf->stream, &q->stream); if (q->streaming) { if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,buf); + spin_lock_irqsave(q->irqlock, flags); + q->ops->buf_queue(q, buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); } - dprintk(1,"qbuf: succeded\n"); + dprintk(1, "qbuf: succeded\n"); retval = 0; done: @@ -571,49 +587,49 @@ int videobuf_dqbuf(struct videobuf_queue *q, struct videobuf_buffer *buf; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) { - dprintk(1,"dqbuf: Reading running...\n"); + dprintk(1, "dqbuf: Reading running...\n"); goto done; } retval = -EINVAL; if (b->type != q->type) { - dprintk(1,"dqbuf: Wrong type.\n"); + dprintk(1, "dqbuf: Wrong type.\n"); goto done; } if (list_empty(&q->stream)) { - dprintk(1,"dqbuf: stream running\n"); + dprintk(1, "dqbuf: stream running\n"); goto done; } buf = list_entry(q->stream.next, struct videobuf_buffer, stream); retval = videobuf_waiton(buf, nonblocking, 1); if (retval < 0) { - dprintk(1,"dqbuf: waiton returned %d\n",retval); + dprintk(1, "dqbuf: waiton returned %d\n", retval); goto done; } switch (buf->state) { - case STATE_ERROR: - dprintk(1,"dqbuf: state is error\n"); + case VIDEOBUF_ERROR: + dprintk(1, "dqbuf: state is error\n"); retval = -EIO; - CALL(q,sync,q, buf); - buf->state = STATE_IDLE; + CALL(q, sync, q, buf); + buf->state = VIDEOBUF_IDLE; break; - case STATE_DONE: - dprintk(1,"dqbuf: state is done\n"); - CALL(q,sync,q, buf); - buf->state = STATE_IDLE; + case VIDEOBUF_DONE: + dprintk(1, "dqbuf: state is done\n"); + CALL(q, sync, q, buf); + buf->state = VIDEOBUF_IDLE; break; default: - dprintk(1,"dqbuf: state invalid\n"); + dprintk(1, "dqbuf: state invalid\n"); retval = -EINVAL; goto done; } list_del(&buf->stream); - memset(b,0,sizeof(*b)); - videobuf_status(q,b,buf,q->type); + memset(b, 0, sizeof(*b)); + videobuf_status(q, b, buf, q->type); done: mutex_unlock(&q->lock); @@ -623,7 +639,7 @@ int videobuf_dqbuf(struct videobuf_queue *q, int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; - unsigned long flags=0; + unsigned long flags = 0; int retval; mutex_lock(&q->lock); @@ -635,12 +651,12 @@ int videobuf_streamon(struct videobuf_queue *q) goto done; q->streaming = 1; if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); list_for_each_entry(buf, &q->stream, stream) - if (buf->state == STATE_PREPARED) - q->ops->buf_queue(q,buf); + if (buf->state == VIDEOBUF_PREPARED) + q->ops->buf_queue(q, buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); done: mutex_unlock(&q->lock); @@ -676,10 +692,10 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, size_t count, loff_t *ppos) { enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); /* setup stuff */ q->read_buf = videobuf_alloc(q); @@ -691,20 +707,20 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, q->read_buf->bsize = count; field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); + retval = q->ops->buf_prepare(q, q->read_buf, field); if (0 != retval) goto done; /* start capture & wait */ if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); + spin_lock_irqsave(q->irqlock, flags); + q->ops->buf_queue(q, q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); - retval = videobuf_waiton(q->read_buf,0,0); + spin_unlock_irqrestore(q->irqlock, flags); + retval = videobuf_waiton(q->read_buf, 0, 0); if (0 == retval) { - CALL(q,sync,q,q->read_buf); - if (STATE_ERROR == q->read_buf->state) + CALL(q, sync, q, q->read_buf); + if (VIDEOBUF_ERROR == q->read_buf->state) retval = -EIO; else retval = q->read_buf->size; @@ -712,7 +728,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, done: /* cleanup */ - q->ops->buf_release(q,q->read_buf); + q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; return retval; @@ -723,21 +739,21 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, int nonblocking) { enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; unsigned size, nbufs; int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); mutex_lock(&q->lock); nbufs = 1; size = 0; - q->ops->buf_setup(q,&nbufs,&size); + q->ops->buf_setup(q, &nbufs, &size); if (NULL == q->read_buf && count >= size && !nonblocking) { - retval = videobuf_read_zerocopy(q,data,count,ppos); + retval = videobuf_read_zerocopy(q, data, count, ppos); if (retval >= 0 || retval == -EIO) /* ok, all done */ goto done; @@ -749,25 +765,25 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, retval = -ENOMEM; q->read_buf = videobuf_alloc(q); - dprintk(1,"video alloc=0x%p\n", q->read_buf); + dprintk(1, "video alloc=0x%p\n", q->read_buf); if (NULL == q->read_buf) goto done; q->read_buf->memory = V4L2_MEMORY_USERPTR; q->read_buf->bsize = count; /* preferred size */ field = videobuf_next_field(q); - retval = q->ops->buf_prepare(q,q->read_buf,field); + retval = q->ops->buf_prepare(q, q->read_buf, field); if (0 != retval) { - kfree (q->read_buf); + kfree(q->read_buf); q->read_buf = NULL; goto done; } if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); - q->ops->buf_queue(q,q->read_buf); + q->ops->buf_queue(q, q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); q->read_off = 0; } @@ -776,11 +792,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, if (0 != retval) goto done; - CALL(q,sync,q,q->read_buf); + CALL(q, sync, q, q->read_buf); - if (STATE_ERROR == q->read_buf->state) { + if (VIDEOBUF_ERROR == q->read_buf->state) { /* catch I/O errors */ - q->ops->buf_release(q,q->read_buf); + q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; retval = -EIO; @@ -788,14 +804,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Copy to userspace */ - retval=CALL(q,video_copy_to_user,q,data,count,nonblocking); - if (retval<0) + retval = CALL(q, video_copy_to_user, q, data, count, nonblocking); + if (retval < 0) goto done; q->read_off += retval; if (q->read_off == q->read_buf->size) { /* all data copied, cleanup */ - q->ops->buf_release(q,q->read_buf); + q->ops->buf_release(q, q->read_buf); kfree(q->read_buf); q->read_buf = NULL; } @@ -806,14 +822,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } /* Locking: Caller holds q->lock */ -int __videobuf_read_start(struct videobuf_queue *q) +static int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; - unsigned long flags=0; + unsigned long flags = 0; unsigned int count = 0, size = 0; int err, i; - q->ops->buf_setup(q,&count,&size); + q->ops->buf_setup(q, &count, &size); if (count < 2) count = 2; if (count > VIDEO_MAX_FRAME) @@ -828,17 +844,17 @@ int __videobuf_read_start(struct videobuf_queue *q) for (i = 0; i < count; i++) { field = videobuf_next_field(q); - err = q->ops->buf_prepare(q,q->bufs[i],field); + err = q->ops->buf_prepare(q, q->bufs[i], field); if (err) return err; list_add_tail(&q->bufs[i]->stream, &q->stream); } if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); + spin_lock_irqsave(q->irqlock, flags); for (i = 0; i < count; i++) - q->ops->buf_queue(q,q->bufs[i]); + q->ops->buf_queue(q, q->bufs[i]); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); q->reading = 1; return 0; } @@ -859,7 +875,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q) } q->read_buf = NULL; q->reading = 0; - + } int videobuf_read_start(struct videobuf_queue *q) @@ -899,11 +915,11 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, int vbihack, int nonblocking) { int rc, retval; - unsigned long flags=0; + unsigned long flags = 0; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - dprintk(2,"%s\n",__FUNCTION__); + dprintk(2, "%s\n", __FUNCTION__); mutex_lock(&q->lock); retval = -EBUSY; if (q->streaming) @@ -931,8 +947,8 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, break; } - if (q->read_buf->state == STATE_DONE) { - rc = CALL (q,copy_stream, q, data + retval, count, + if (q->read_buf->state == VIDEOBUF_DONE) { + rc = CALL(q, copy_stream, q, data + retval, count, retval, vbihack, nonblocking); if (rc < 0) { retval = rc; @@ -953,10 +969,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, list_add_tail(&q->read_buf->stream, &q->stream); if (q->irqlock) - spin_lock_irqsave(q->irqlock,flags); - q->ops->buf_queue(q,q->read_buf); + spin_lock_irqsave(q->irqlock, flags); + q->ops->buf_queue(q, q->read_buf); if (q->irqlock) - spin_unlock_irqrestore(q->irqlock,flags); + spin_unlock_irqrestore(q->irqlock, flags); q->read_buf = NULL; } if (retval < 0) @@ -999,8 +1015,8 @@ unsigned int videobuf_poll_stream(struct file *file, if (0 == rc) { poll_wait(file, &buf->done, wait); - if (buf->state == STATE_DONE || - buf->state == STATE_ERROR) + if (buf->state == VIDEOBUF_DONE || + buf->state == VIDEOBUF_ERROR) rc = POLLIN|POLLRDNORM; } mutex_unlock(&q->lock); @@ -1012,10 +1028,11 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, { int retval; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); mutex_lock(&q->lock); - retval=CALL(q,mmap_mapper,q,vma); + retval = CALL(q, mmap_mapper, q, vma); + q->is_mmapped = 1; mutex_unlock(&q->lock); return retval; @@ -1026,15 +1043,15 @@ int videobuf_cgmbuf(struct videobuf_queue *q, struct video_mbuf *mbuf, int count) { struct v4l2_requestbuffers req; - int rc,i; + int rc, i; - MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS); + MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - memset(&req,0,sizeof(req)); + memset(&req, 0, sizeof(req)); req.type = q->type; req.count = count; req.memory = V4L2_MEMORY_MMAP; - rc = videobuf_reqbufs(q,&req); + rc = videobuf_reqbufs(q, &req); if (rc < 0) return rc; @@ -1079,9 +1096,3 @@ EXPORT_SYMBOL_GPL(videobuf_poll_stream); EXPORT_SYMBOL_GPL(videobuf_mmap_setup); EXPORT_SYMBOL_GPL(videobuf_mmap_free); EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 44ee408e145f..98efd7ab1f50 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -385,30 +385,27 @@ videobuf_vm_close(struct vm_area_struct *vma) * now ...). Bounce buffers don't work very well for the data rates * video capture has. */ -static struct page* -videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr, - int *type) +static int +videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *page; - dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n", - vaddr,vma->vm_start,vma->vm_end); - if (vaddr > vma->vm_end) - return NOPAGE_SIGBUS; + dprintk(3,"fault: fault @ %08lx [vma %08lx-%08lx]\n", + (unsigned long)vmf->virtual_address,vma->vm_start,vma->vm_end); page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) - return NOPAGE_OOM; - clear_user_page(page_address(page), vaddr, page); - if (type) - *type = VM_FAULT_MINOR; - return page; + return VM_FAULT_OOM; + clear_user_page(page_address(page), (unsigned long)vmf->virtual_address, + page); + vmf->page = page; + return 0; } static struct vm_operations_struct videobuf_vm_ops = { .open = videobuf_vm_open, .close = videobuf_vm_close, - .nopage = videobuf_vm_nopage, + .fault = videobuf_vm_fault, }; /* --------------------------------------------------------------------- diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c index 880317e04a02..b73aba65d21d 100644 --- a/drivers/media/video/videobuf-dvb.c +++ b/drivers/media/video/videobuf-dvb.c @@ -67,7 +67,7 @@ static int videobuf_dvb_thread(void *data) /* feed buffer data to demux */ dma=videobuf_to_dma(buf); - if (buf->state == STATE_DONE) + if (buf->state == VIDEOBUF_DONE) dvb_dmx_swfilter(&dvb->demux, dma->vmalloc, buf->size); diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index e01259438bb2..9b3898347ca5 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -41,7 +41,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); MODULE_LICENSE("GPL"); #define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg) + printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) /***************************************************************************/ diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 9611c3990285..28655f8983c6 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -973,7 +973,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, *id = vfd->current_norm; - dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); + dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); ret=0; break; @@ -982,7 +982,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *id = arg,norm; - dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id); + dbgarg (cmd, "value=%08Lx\n", (long long unsigned) *id); norm = (*id) & vfd->tvnorms; if ( vfd->tvnorms && !norm) /* Check if std is supported */ @@ -1008,7 +1008,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; ret=vfd->vidioc_querystd(file, fh, arg); if (!ret) - dbgarg (cmd, "detected std=%Lu\n", + dbgarg (cmd, "detected std=%08Lx\n", (unsigned long long)*p); break; } @@ -1028,7 +1028,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!ret) dbgarg (cmd, "index=%d, name=%s, type=%d, " "audioset=%d, " - "tuner=%d, std=%Ld, status=%d\n", + "tuner=%d, std=%08Lx, status=%d\n", p->index,p->name,p->type,p->audioset, p->tuner, (unsigned long long)p->std, diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index 9a03dc82c6ca..5bb75294b5aa 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -2589,11 +2589,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs) /* First try D1 and then SAA7191 */ if (vino_drvdata->camera.driver && (vino_drvdata->camera.owner == VINO_NO_CHANNEL)) { - if (i2c_use_client(vino_drvdata->camera.driver)) { - ret = -ENODEV; - goto out; - } - + i2c_use_client(vino_drvdata->camera.driver); vino_drvdata->camera.owner = vcs->channel; vcs->input = VINO_INPUT_D1; vcs->data_norm = VINO_DATA_NORM_D1; @@ -2602,11 +2598,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs) int input, data_norm; int saa7191_input; - if (i2c_use_client(vino_drvdata->decoder.driver)) { - ret = -ENODEV; - goto out; - } - + i2c_use_client(vino_drvdata->decoder.driver); input = VINO_INPUT_COMPOSITE; saa7191_input = vino_get_saa7191_input(input); @@ -2688,10 +2680,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input) } if (vino_drvdata->decoder.owner == VINO_NO_CHANNEL) { - if (i2c_use_client(vino_drvdata->decoder.driver)) { - ret = -ENODEV; - goto out; - } + i2c_use_client(vino_drvdata->decoder.driver); vino_drvdata->decoder.owner = vcs->channel; } @@ -2759,10 +2748,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input) } if (vino_drvdata->camera.owner == VINO_NO_CHANNEL) { - if (i2c_use_client(vino_drvdata->camera.driver)) { - ret = -ENODEV; - goto out; - } + i2c_use_client(vino_drvdata->camera.driver); vino_drvdata->camera.owner = vcs->channel; } diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 9b54ff9d2e36..1db067c02815 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -44,21 +44,18 @@ #define WAKE_DENOMINATOR 1001 #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ -/* These timers are for 1 fps - used only for testing */ -//#define WAKE_DENOMINATOR 30 /* hack for testing purposes */ -//#define BUFFER_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */ - #include "font.h" #define VIVI_MAJOR_VERSION 0 #define VIVI_MINOR_VERSION 4 #define VIVI_RELEASE 0 -#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) +#define VIVI_VERSION \ + KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) /* Declare static vars that will be used as parameters */ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ -static struct video_device vivi; /* Video device */ static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ +static int n_devs = 1; /* Number of virtual devices */ /* supported controls */ static struct v4l2_queryctrl vivi_qctrl[] = { @@ -71,7 +68,7 @@ static struct v4l2_queryctrl vivi_qctrl[] = { .default_value = 65535, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, - },{ + }, { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", @@ -112,9 +109,9 @@ static struct v4l2_queryctrl vivi_qctrl[] = { static int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; -#define dprintk(level,fmt, arg...) \ +#define dprintk(dev, level, fmt, arg...) \ do { \ - if (vivi.debug >= (level)) \ + if (dev->vfd->debug >= (level)) \ printk(KERN_DEBUG "vivi: " fmt , ## arg); \ } while (0) @@ -166,17 +163,21 @@ struct vivi_dev { struct list_head vivi_devlist; struct mutex lock; + spinlock_t slock; int users; /* various device info */ - struct video_device vfd; + struct video_device *vfd; struct vivi_dmaqueue vidq; /* Several counters */ - int h,m,s,us,jiffies; + int h, m, s, ms; + unsigned long jiffies; char timestr[13]; + + int mv_count; /* Controls bars movement */ }; struct vivi_fh { @@ -184,7 +185,7 @@ struct vivi_fh { /* video capture */ struct vivi_fmt *fmt; - unsigned int width,height; + unsigned int width, height; struct videobuf_queue vb_vidq; enum v4l2_buf_type type; @@ -203,109 +204,113 @@ enum colors { GREEN, MAGENTA, RED, - BLUE + BLUE, + BLACK, }; static u8 bars[8][3] = { /* R G B */ - {204,204,204}, /* white */ - {208,208, 0}, /* ambar */ - { 0,206,206}, /* cyan */ - { 0,239, 0}, /* green */ - {239, 0,239}, /* magenta */ - {205, 0, 0}, /* red */ - { 0, 0,255}, /* blue */ - { 0, 0, 0} + {204, 204, 204}, /* white */ + {208, 208, 0}, /* ambar */ + { 0, 206, 206}, /* cyan */ + { 0, 239, 0}, /* green */ + {239, 0, 239}, /* magenta */ + {205, 0, 0}, /* red */ + { 0, 0, 255}, /* blue */ + { 0, 0, 0}, /* black */ }; -#define TO_Y(r,g,b) (((16829*r +33039*g +6416*b + 32768)>>16)+16) +#define TO_Y(r, g, b) \ + (((16829 * r + 33039 * g + 6416 * b + 32768) >> 16) + 16) /* RGB to V(Cr) Color transform */ -#define TO_V(r,g,b) (((28784*r -24103*g -4681*b + 32768)>>16)+128) +#define TO_V(r, g, b) \ + (((28784 * r - 24103 * g - 4681 * b + 32768) >> 16) + 128) /* RGB to U(Cb) Color transform */ -#define TO_U(r,g,b) (((-9714*r -19070*g +28784*b + 32768)>>16)+128) +#define TO_U(r, g, b) \ + (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) #define TSTAMP_MIN_Y 24 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15 #define TSTAMP_MIN_X 64 -static void gen_line(char *basep,int inipos,int wmax, - int hmax, int line, int count, char *timestr) +static void gen_line(char *basep, int inipos, int wmax, + int hmax, int line, int count, char *timestr) { - int w,i,j,pos=inipos,y; - char *p,*s; - u8 chr,r,g,b,color; + int w, i, j, y; + int pos = inipos; + char *p, *s; + u8 chr, r, g, b, color; /* We will just duplicate the second pixel at the packet */ - wmax/=2; + wmax /= 2; /* Generate a standard color bar pattern */ - for (w=0;w<wmax;w++) { - int colorpos=((w+count)*8/(wmax+1)) % 8; - r=bars[colorpos][0]; - g=bars[colorpos][1]; - b=bars[colorpos][2]; + for (w = 0; w < wmax; w++) { + int colorpos = ((w + count) * 8/(wmax + 1)) % 8; + r = bars[colorpos][0]; + g = bars[colorpos][1]; + b = bars[colorpos][2]; - for (color=0;color<4;color++) { - p=basep+pos; + for (color = 0; color < 4; color++) { + p = basep + pos; switch (color) { - case 0: - case 2: - *p=TO_Y(r,g,b); /* Luminance */ - break; - case 1: - *p=TO_U(r,g,b); /* Cb */ - break; - case 3: - *p=TO_V(r,g,b); /* Cr */ - break; + case 0: + case 2: + *p = TO_Y(r, g, b); /* Luma */ + break; + case 1: + *p = TO_U(r, g, b); /* Cb */ + break; + case 3: + *p = TO_V(r, g, b); /* Cr */ + break; } pos++; } } /* Checks if it is possible to show timestamp */ - if (TSTAMP_MAX_Y>=hmax) + if (TSTAMP_MAX_Y >= hmax) goto end; - if (TSTAMP_MIN_X+strlen(timestr)>=wmax) + if (TSTAMP_MIN_X + strlen(timestr) >= wmax) goto end; /* Print stream time */ - if (line>=TSTAMP_MIN_Y && line<=TSTAMP_MAX_Y) { - j=TSTAMP_MIN_X; - for (s=timestr;*s;s++) { - chr=rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; - for (i=0;i<7;i++) { - if (chr&1<<(7-i)) { /* Font color*/ - r=bars[BLUE][0]; - g=bars[BLUE][1]; - b=bars[BLUE][2]; - r=g=b=0; - g=198; - } else { /* Background color */ - r=bars[WHITE][0]; - g=bars[WHITE][1]; - b=bars[WHITE][2]; - r=g=b=0; + if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { + j = TSTAMP_MIN_X; + for (s = timestr; *s; s++) { + chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y]; + for (i = 0; i < 7; i++) { + if (chr & 1 << (7 - i)) { + /* Font color*/ + r = 0; + g = 198; + b = 0; + } else { + /* Background color */ + r = bars[BLACK][0]; + g = bars[BLACK][1]; + b = bars[BLACK][2]; } - pos=inipos+j*2; - for (color=0;color<4;color++) { - p=basep+pos; + pos = inipos + j * 2; + for (color = 0; color < 4; color++) { + p = basep + pos; - y=TO_Y(r,g,b); + y = TO_Y(r, g, b); switch (color) { - case 0: - case 2: - *p=TO_Y(r,g,b); /* Luminance */ - break; - case 1: - *p=TO_U(r,g,b); /* Cb */ - break; - case 3: - *p=TO_V(r,g,b); /* Cr */ - break; + case 0: + case 2: + *p = TO_Y(r, g, b); /* Luma */ + break; + case 1: + *p = TO_U(r, g, b); /* Cb */ + break; + case 3: + *p = TO_V(r, g, b); /* Cr */ + break; } pos++; } @@ -314,63 +319,60 @@ static void gen_line(char *basep,int inipos,int wmax, } } - end: return; } -static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf) +static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) { - int h,pos=0; + int h , pos = 0; int hmax = buf->vb.height; int wmax = buf->vb.width; struct timeval ts; - char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL); - void *vbuf=videobuf_to_vmalloc (&buf->vb); - /* FIXME: move to dev struct */ - static int mv_count=0; + char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL); + void *vbuf = videobuf_to_vmalloc(&buf->vb); if (!tmpbuf) return; - for (h=0;h<hmax;h++) { - gen_line(tmpbuf,0,wmax,hmax,h,mv_count, + for (h = 0; h < hmax; h++) { + gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count, dev->timestr); /* FIXME: replacing to __copy_to_user */ - if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0) - dprintk(2,"vivifill copy_to_user failed.\n"); + if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0) + dprintk(dev, 2, "vivifill copy_to_user failed.\n"); pos += wmax*2; } - mv_count++; + dev->mv_count++; kfree(tmpbuf); /* Updates stream time */ - dev->us+=jiffies_to_usecs(jiffies-dev->jiffies); - dev->jiffies=jiffies; - if (dev->us>=1000000) { - dev->us-=1000000; + dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); + dev->jiffies = jiffies; + if (dev->ms >= 1000) { + dev->ms -= 1000; dev->s++; - if (dev->s>=60) { - dev->s-=60; + if (dev->s >= 60) { + dev->s -= 60; dev->m++; - if (dev->m>60) { - dev->m-=60; + if (dev->m > 60) { + dev->m -= 60; dev->h++; - if (dev->h>24) - dev->h-=24; + if (dev->h > 24) + dev->h -= 24; } } } - sprintf(dev->timestr,"%02d:%02d:%02d:%03d", - dev->h,dev->m,dev->s,(dev->us+500)/1000); + sprintf(dev->timestr, "%02d:%02d:%02d:%03d", + dev->h, dev->m, dev->s, dev->ms); - dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr, - (unsigned long)tmpbuf,pos); + dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", + dev->timestr, (unsigned long)tmpbuf, pos); /* Advice that buffer was filled */ - buf->vb.state = STATE_DONE; + buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; do_gettimeofday(&ts); buf->vb.ts = ts; @@ -384,14 +386,15 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q); static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) { struct vivi_buffer *buf; - struct vivi_dev *dev= container_of(dma_q,struct vivi_dev,vidq); + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); int bc; + spin_lock(&dev->slock); /* Announces videobuf that all went ok */ for (bc = 0;; bc++) { if (list_empty(&dma_q->active)) { - dprintk(1,"No active queue to serve\n"); + dprintk(dev, 1, "No active queue to serve\n"); break; } @@ -401,65 +404,89 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) /* Nobody is waiting something to be done, just return */ if (!waitqueue_active(&buf->vb.done)) { mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); + spin_unlock(&dev->slock); return; } do_gettimeofday(&buf->vb.ts); - dprintk(2,"[%p/%d] wakeup\n",buf,buf->vb.i); + dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); /* Fill buffer */ - vivi_fillbuff(dev,buf); + vivi_fillbuff(dev, buf); if (list_empty(&dma_q->active)) { del_timer(&dma_q->timeout); } else { - mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); + mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT); } } if (bc != 1) - dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc); + dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n", + __FUNCTION__, bc); + spin_unlock(&dev->slock); } +#define frames_to_ms(frames) \ + ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) + static void vivi_sleep(struct vivi_dmaqueue *dma_q) { - int timeout; + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + int timeout, running_time; DECLARE_WAITQUEUE(wait, current); - dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); + dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, + (unsigned long)dma_q); add_wait_queue(&dma_q->wq, &wait); - if (!kthread_should_stop()) { - dma_q->frame++; + if (kthread_should_stop()) + goto stop_task; - /* Calculate time to wake up */ - timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; + running_time = jiffies - dma_q->ini_jiffies; + dma_q->frame++; - if (timeout <= 0) { - int old=dma_q->frame; - dma_q->frame=(jiffies_to_msecs(jiffies-dma_q->ini_jiffies)*WAKE_DENOMINATOR)/(WAKE_NUMERATOR*1000)+1; + /* Calculate time to wake up */ + timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time; - timeout=dma_q->ini_jiffies+msecs_to_jiffies((dma_q->frame*WAKE_NUMERATOR*1000)/WAKE_DENOMINATOR)-jiffies; + if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) { + int old = dma_q->frame; + int nframes; - dprintk(1,"underrun, losed %d frames. " - "Now, frame is %d. Waking on %d jiffies\n", - dma_q->frame-old,dma_q->frame,timeout); - } else - dprintk(1,"will sleep for %i jiffies\n",timeout); + dma_q->frame = (jiffies_to_msecs(running_time) / + frames_to_ms(1)) + 1; - vivi_thread_tick(dma_q); + timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) + - running_time; - schedule_timeout_interruptible (timeout); - } + if (unlikely (timeout <= 0)) + timeout = 1; + + nframes = (dma_q->frame > old)? + dma_q->frame - old : old - dma_q->frame; + + dprintk(dev, 1, "%ld: %s %d frames. " + "Current frame is %d. Will sleep for %d jiffies\n", + jiffies, + (dma_q->frame > old)? "Underrun, losed" : "Overrun of", + nframes, dma_q->frame, timeout); + } else + dprintk(dev, 1, "will sleep for %d jiffies\n", timeout); + vivi_thread_tick(dma_q); + + schedule_timeout_interruptible(timeout); + +stop_task: remove_wait_queue(&dma_q->wq, &wait); try_to_freeze(); } static int vivi_thread(void *data) { - struct vivi_dmaqueue *dma_q=data; + struct vivi_dmaqueue *dma_q = data; + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); - dprintk(1,"thread started\n"); + dprintk(dev, 1, "thread started\n"); mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); set_freezable(); @@ -470,16 +497,18 @@ static int vivi_thread(void *data) if (kthread_should_stop()) break; } - dprintk(1, "thread: exit\n"); + dprintk(dev, 1, "thread: exit\n"); return 0; } static int vivi_start_thread(struct vivi_dmaqueue *dma_q) { - dma_q->frame=0; - dma_q->ini_jiffies=jiffies; + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); - dprintk(1,"%s\n",__FUNCTION__); + dma_q->frame = 0; + dma_q->ini_jiffies = jiffies; + + dprintk(dev, 1, "%s\n", __FUNCTION__); dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); @@ -490,39 +519,43 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q) /* Wakes thread */ wake_up_interruptible(&dma_q->wq); - dprintk(1,"returning from %s\n",__FUNCTION__); + dprintk(dev, 1, "returning from %s\n", __FUNCTION__); return 0; } static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) { - dprintk(1,"%s\n",__FUNCTION__); + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); + + dprintk(dev, 1, "%s\n", __FUNCTION__); /* shutdown control thread */ if (dma_q->kthread) { kthread_stop(dma_q->kthread); - dma_q->kthread=NULL; + dma_q->kthread = NULL; } } static int restart_video_queue(struct vivi_dmaqueue *dma_q) { + struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); struct vivi_buffer *buf, *prev; - dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q); + dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, + (unsigned long)dma_q); if (!list_empty(&dma_q->active)) { - buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + buf = list_entry(dma_q->active.next, + struct vivi_buffer, vb.queue); + dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.i); - dprintk(1,"Restarting video dma\n"); + dprintk(dev, 1, "Restarting video dma\n"); vivi_stop_thread(dma_q); -// vivi_start_thread(dma_q); /* cancel all outstanding capture / vbi requests */ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); } mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); @@ -534,28 +567,31 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) for (;;) { if (list_empty(&dma_q->queued)) return 0; - buf = list_entry(dma_q->queued.next, struct vivi_buffer, vb.queue); + buf = list_entry(dma_q->queued.next, + struct vivi_buffer, vb.queue); if (NULL == prev) { list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&dma_q->active); + list_add_tail(&buf->vb.queue, &dma_q->active); - dprintk(1,"Restarting video dma\n"); + dprintk(dev, 1, "Restarting video dma\n"); vivi_stop_thread(dma_q); vivi_start_thread(dma_q); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] restart_queue - first active\n", - buf,buf->vb.i); + dprintk(dev, 2, + "[%p/%d] restart_queue - first active\n", + buf, buf->vb.i); } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&dma_q->active); - buf->vb.state = STATE_ACTIVE; - dprintk(2,"[%p/%d] restart_queue - move to active\n", - buf,buf->vb.i); + list_add_tail(&buf->vb.queue, &dma_q->active); + buf->vb.state = VIDEOBUF_ACTIVE; + dprintk(dev, 2, + "[%p/%d] restart_queue - move to active\n", + buf, buf->vb.i); } else { return 0; } @@ -565,19 +601,23 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q) static void vivi_vid_timeout(unsigned long data) { - struct vivi_dev *dev = (struct vivi_dev*)data; + struct vivi_dev *dev = (struct vivi_dev *)data; struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *buf; + spin_lock(&dev->slock); + while (!list_empty(&vidq->active)) { - buf = list_entry(vidq->active.next, struct vivi_buffer, vb.queue); + buf = list_entry(vidq->active.next, + struct vivi_buffer, vb.queue); list_del(&buf->vb.queue); - buf->vb.state = STATE_ERROR; + buf->vb.state = VIDEOBUF_ERROR; wake_up(&buf->vb.done); - printk("vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); + printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); } - restart_video_queue(vidq); + + spin_unlock(&dev->slock); } /* ------------------------------------------------------------------ @@ -586,7 +626,8 @@ static void vivi_vid_timeout(unsigned long data) static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { - struct vivi_fh *fh = vq->priv_data; + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; *size = fh->width*fh->height*2; @@ -596,21 +637,25 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) while (*size * *count > vid_limit * 1024 * 1024) (*count)--; - dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size); + dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__, + *count, *size); return 0; } static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) { - dprintk(1,"%s\n",__FUNCTION__); + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; + + dprintk(dev, 1, "%s\n", __FUNCTION__); if (in_interrupt()) BUG(); - videobuf_waiton(&buf->vb,0,0); + videobuf_waiton(&buf->vb, 0, 0); videobuf_vmalloc_free(&buf->vb); - buf->vb.state = STATE_NEEDS_INIT; + buf->vb.state = VIDEOBUF_NEEDS_INIT; } #define norm_maxw() 1024 @@ -620,10 +665,11 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { struct vivi_fh *fh = vq->priv_data; - struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); + struct vivi_dev *dev = fh->dev; + struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); int rc, init_buffer = 0; - dprintk(1,"%s, field=%d\n",__FUNCTION__,field); + dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || @@ -644,75 +690,81 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, init_buffer = 1; } - if (STATE_NEEDS_INIT == buf->vb.state) { - if (0 != (rc = videobuf_iolock(vq,&buf->vb,NULL))) + if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { + rc = videobuf_iolock(vq, &buf->vb, NULL); + if (rc < 0) goto fail; } - buf->vb.state = STATE_PREPARED; + buf->vb.state = VIDEOBUF_PREPARED; return 0; fail: - free_buffer(vq,buf); + free_buffer(vq, buf); return rc; } static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); - struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = fh->dev; - struct vivi_dmaqueue *vidq = &dev->vidq; + struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); + struct vivi_fh *fh = vq->priv_data; + struct vivi_dev *dev = fh->dev; + struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_buffer *prev; if (!list_empty(&vidq->queued)) { - dprintk(1,"adding vb queue=0x%08lx\n",(unsigned long)&buf->vb.queue); - list_add_tail(&buf->vb.queue,&vidq->queued); - buf->vb.state = STATE_QUEUED; - dprintk(2,"[%p/%d] buffer_queue - append to queued\n", + dprintk(dev, 1, "adding vb queue=0x%08lx\n", + (unsigned long)&buf->vb.queue); + list_add_tail(&buf->vb.queue, &vidq->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n", buf, buf->vb.i); } else if (list_empty(&vidq->active)) { - list_add_tail(&buf->vb.queue,&vidq->active); + list_add_tail(&buf->vb.queue, &vidq->active); - buf->vb.state = STATE_ACTIVE; + buf->vb.state = VIDEOBUF_ACTIVE; mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2,"[%p/%d] buffer_queue - first active\n", + dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n", buf, buf->vb.i); vivi_start_thread(vidq); } else { - prev = list_entry(vidq->active.prev, struct vivi_buffer, vb.queue); + prev = list_entry(vidq->active.prev, + struct vivi_buffer, vb.queue); if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { - list_add_tail(&buf->vb.queue,&vidq->active); - buf->vb.state = STATE_ACTIVE; - dprintk(2,"[%p/%d] buffer_queue - append to active\n", + list_add_tail(&buf->vb.queue, &vidq->active); + buf->vb.state = VIDEOBUF_ACTIVE; + dprintk(dev, 2, + "[%p/%d] buffer_queue - append to active\n", buf, buf->vb.i); } else { - list_add_tail(&buf->vb.queue,&vidq->queued); - buf->vb.state = STATE_QUEUED; - dprintk(2,"[%p/%d] buffer_queue - first queued\n", + list_add_tail(&buf->vb.queue, &vidq->queued); + buf->vb.state = VIDEOBUF_QUEUED; + dprintk(dev, 2, + "[%p/%d] buffer_queue - first queued\n", buf, buf->vb.i); } } } -static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void buffer_release(struct videobuf_queue *vq, + struct videobuf_buffer *vb) { - struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb); + struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_fh *fh = vq->priv_data; - struct vivi_dev *dev = (struct vivi_dev*)fh->dev; + struct vivi_dev *dev = (struct vivi_dev *)fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; - dprintk(1,"%s\n",__FUNCTION__); + dprintk(dev, 1, "%s\n", __FUNCTION__); vivi_stop_thread(vidq); - free_buffer(vq,buf); + free_buffer(vq, buf); } static struct videobuf_queue_ops vivi_video_qops = { @@ -725,7 +777,7 @@ static struct videobuf_queue_ops vivi_video_qops = { /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ -static int vidioc_querycap (struct file *file, void *priv, +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { strcpy(cap->driver, "vivi"); @@ -737,21 +789,21 @@ static int vidioc_querycap (struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index > 0) return -EINVAL; - strlcpy(f->description,format.name,sizeof(f->description)); + strlcpy(f->description, format.name, sizeof(f->description)); f->pixelformat = format.fourcc; return 0; } -static int vidioc_g_fmt_cap (struct file *file, void *priv, +static int vidioc_g_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; f->fmt.pix.width = fh->width; f->fmt.pix.height = fh->height; @@ -765,26 +817,29 @@ static int vidioc_g_fmt_cap (struct file *file, void *priv, return (0); } -static int vidioc_try_fmt_cap (struct file *file, void *priv, +static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct vivi_fh *fh = priv; + struct vivi_dev *dev = fh->dev; struct vivi_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; if (format.fourcc != f->fmt.pix.pixelformat) { - dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts " - "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc); + dprintk(dev, 1, "Fourcc format (0x%08x) invalid. " + "Driver accepts only 0x%08x\n", + f->fmt.pix.pixelformat, format.fourcc); return -EINVAL; } - fmt=&format; + fmt = &format; field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { - field=V4L2_FIELD_INTERLACED; + field = V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { - dprintk(1,"Field type invalid.\n"); + dprintk(dev, 1, "Field type invalid.\n"); return -EINVAL; } @@ -810,11 +865,11 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv, } /*FIXME: This seems to be generic enough to be at videodev2 */ -static int vidioc_s_fmt_cap (struct file *file, void *priv, +static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct vivi_fh *fh=priv; - int ret = vidioc_try_fmt_cap(file,fh,f); + struct vivi_fh *fh = priv; + int ret = vidioc_try_fmt_cap(file, fh, f); if (ret < 0) return (ret); @@ -827,47 +882,48 @@ static int vidioc_s_fmt_cap (struct file *file, void *priv, return (0); } -static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_reqbufs(&fh->vb_vidq, p)); } -static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_querybuf(&fh->vb_vidq, p)); } -static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_qbuf(&fh->vb_vidq, p)); } -static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK)); } #ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) +static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; - return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8); + return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); } #endif static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -879,7 +935,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct vivi_fh *fh=priv; + struct vivi_fh *fh = priv; if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -889,32 +945,32 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->vb_vidq); } -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) { return 0; } /* only one input in this sample driver */ -static int vidioc_enum_input (struct file *file, void *priv, +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { if (inp->index != 0) return -EINVAL; inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_NTSC_M; - strcpy(inp->name,"Camera"); + inp->std = V4L2_STD_525_60; + strcpy(inp->name, "Camera"); return (0); } -static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { *i = 0; return (0); } -static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { if (i > 0) return -EINVAL; @@ -923,8 +979,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) } /* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int vidioc_queryctrl(struct file *file, void *priv, + struct v4l2_queryctrl *qc) { int i; @@ -938,33 +994,31 @@ static int vidioc_queryctrl (struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctrl) +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) { int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { - ctrl->value=qctl_regs[i]; + ctrl->value = qctl_regs[i]; return (0); } return -EINVAL; } -static int vidioc_s_ctrl (struct file *file, void *priv, +static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { int i; for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) if (ctrl->id == vivi_qctrl[i].id) { - if (ctrl->value < - vivi_qctrl[i].minimum - || ctrl->value > - vivi_qctrl[i].maximum) { + if (ctrl->value < vivi_qctrl[i].minimum + || ctrl->value > vivi_qctrl[i].maximum) { return (-ERANGE); } - qctl_regs[i]=ctrl->value; + qctl_regs[i] = ctrl->value; return (0); } return -EINVAL; @@ -983,24 +1037,22 @@ static int vivi_open(struct inode *inode, struct file *file) struct vivi_fh *fh; int i; - printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor); + printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) - if (dev->vfd.minor == minor) + if (dev->vfd->minor == minor) goto found; return -ENODEV; -found: - - +found: /* If more than one user, mutex should be added */ dev->users++; - dprintk(1, "open minor=%d type=%s users=%d\n", minor, + dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor, v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh),GFP_KERNEL); + fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { dev->users--; return -ENOMEM; @@ -1016,27 +1068,21 @@ found: /* Put all controls at a sane state */ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) - qctl_regs[i] =vivi_qctrl[i].default_value; - - dprintk(1,"Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", - (unsigned long)fh,(unsigned long)dev,(unsigned long)&dev->vidq); - dprintk(1,"Open: list_empty queued=%d\n",list_empty(&dev->vidq.queued)); - dprintk(1,"Open: list_empty active=%d\n",list_empty(&dev->vidq.active)); + qctl_regs[i] = vivi_qctrl[i].default_value; /* Resets frame counters */ - dev->h=0; - dev->m=0; - dev->s=0; - dev->us=0; - dev->jiffies=jiffies; - sprintf(dev->timestr,"%02d:%02d:%02d:%03d", - dev->h,dev->m,dev->s,(dev->us+500)/1000); + dev->h = 0; + dev->m = 0; + dev->s = 0; + dev->ms = 0; + dev->mv_count = 0; + dev->jiffies = jiffies; + sprintf(dev->timestr, "%02d:%02d:%02d:%03d", + dev->h, dev->m, dev->s, dev->ms); videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops, - NULL, NULL, - fh->type, - V4L2_FIELD_INTERLACED, - sizeof(struct vivi_buffer),fh); + NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, + sizeof(struct vivi_buffer), fh); return 0; } @@ -1044,9 +1090,9 @@ found: static ssize_t vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct vivi_fh *fh = file->private_data; + struct vivi_fh *fh = file->private_data; - if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } @@ -1057,9 +1103,10 @@ static unsigned int vivi_poll(struct file *file, struct poll_table_struct *wait) { struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; struct videobuf_queue *q = &fh->vb_vidq; - dprintk(1,"%s\n",__FUNCTION__); + dprintk(dev, 1, "%s\n", __FUNCTION__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; @@ -1067,7 +1114,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait) return videobuf_poll_stream(file, q, wait); } -static int vivi_release(struct inode *inode, struct file *file) +static int vivi_close(struct inode *inode, struct file *file) { struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; @@ -1079,26 +1126,48 @@ static int vivi_release(struct inode *inode, struct file *file) videobuf_stop(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vidq); - kfree (fh); + kfree(fh); dev->users--; - printk(KERN_DEBUG "vivi: close called (minor=%d, users=%d)\n",minor,dev->users); + dprintk(dev, 1, "close called (minor=%d, users=%d)\n", + minor, dev->users); return 0; } -static int -vivi_mmap(struct file *file, struct vm_area_struct * vma) +static int vivi_release(void) { - struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev; + struct list_head *list; + + while (!list_empty(&vivi_devlist)) { + list = vivi_devlist.next; + list_del(list); + dev = list_entry(list, struct vivi_dev, vivi_devlist); + + if (-1 != dev->vfd->minor) + video_unregister_device(dev->vfd); + else + video_device_release(dev->vfd); + + kfree(dev); + } + + return 0; +} + +static int vivi_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct vivi_fh *fh = file->private_data; + struct vivi_dev *dev = fh->dev; int ret; - dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma); + dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); - ret=videobuf_mmap_mapper(&fh->vb_vidq, vma); + ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); - dprintk (1,"vma start=0x%08lx, size=%ld, ret=%d\n", + dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", (unsigned long)vma->vm_start, (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, ret); @@ -1109,7 +1178,7 @@ vivi_mmap(struct file *file, struct vm_area_struct * vma) static const struct file_operations vivi_fops = { .owner = THIS_MODULE, .open = vivi_open, - .release = vivi_release, + .release = vivi_close, .read = vivi_read, .poll = vivi_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ @@ -1117,12 +1186,12 @@ static const struct file_operations vivi_fops = { .llseek = no_llseek, }; -static struct video_device vivi = { +static struct video_device vivi_template = { .name = "vivi", .type = VID_TYPE_CAPTURE, .fops = &vivi_fops, .minor = -1, -// .release = video_device_release, + .release = video_device_release, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, @@ -1145,7 +1214,7 @@ static struct video_device vivi = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif - .tvnorms = V4L2_STD_NTSC_M, + .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M, }; /* ----------------------------------------------------------------- @@ -1154,43 +1223,61 @@ static struct video_device vivi = { static int __init vivi_init(void) { - int ret; + int ret = -ENOMEM, i; struct vivi_dev *dev; + struct video_device *vfd; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) - return -ENOMEM; - list_add_tail(&dev->vivi_devlist,&vivi_devlist); + for (i = 0; i < n_devs; i++) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (NULL == dev) + break; - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - init_waitqueue_head(&dev->vidq.wq); + list_add_tail(&dev->vivi_devlist, &vivi_devlist); - /* initialize locks */ - mutex_init(&dev->lock); + /* init video dma queues */ + INIT_LIST_HEAD(&dev->vidq.active); + INIT_LIST_HEAD(&dev->vidq.queued); + init_waitqueue_head(&dev->vidq.wq); - dev->vidq.timeout.function = vivi_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); + /* initialize locks */ + mutex_init(&dev->lock); + spin_lock_init(&dev->slock); - ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr); - printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret); + dev->vidq.timeout.function = vivi_vid_timeout; + dev->vidq.timeout.data = (unsigned long)dev; + init_timer(&dev->vidq.timeout); + + vfd = video_device_alloc(); + if (NULL == vfd) + break; + + *vfd = vivi_template; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); + if (ret < 0) + break; + + snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", + vivi_template.name, vfd->minor); + + if (video_nr >= 0) + video_nr++; + + dev->vfd = vfd; + } + + if (ret < 0) { + vivi_release(); + printk(KERN_INFO "Error %d while loading vivi driver\n", ret); + } else + printk(KERN_INFO "Video Technology Magazine Virtual Video " + "Capture Board successfully loaded.\n"); return ret; } static void __exit vivi_exit(void) { - struct vivi_dev *h; - struct list_head *list; - - while (!list_empty(&vivi_devlist)) { - list = vivi_devlist.next; - list_del(list); - h = list_entry(list, struct vivi_dev, vivi_devlist); - kfree (h); - } - video_unregister_device(&vivi); + vivi_release(); } module_init(vivi_init); @@ -1201,10 +1288,13 @@ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); MODULE_LICENSE("Dual BSD/GPL"); module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr, "video iminor start number"); -module_param_named(debug,vivi.debug, int, 0644); -MODULE_PARM_DESC(debug,"activates debug info"); +module_param(n_devs, int, 0); +MODULE_PARM_DESC(n_devs, "number of video devices to create"); -module_param(vid_limit,int,0644); -MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); +module_param_named(debug, vivi_template.debug, int, 0444); +MODULE_PARM_DESC(debug, "activates debug info"); +module_param(vid_limit, int, 0644); +MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 63002e0ac764..282c81403c97 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -30,15 +30,12 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> MODULE_DESCRIPTION("vp27smpx driver"); MODULE_AUTHOR("Hans Verkuil"); MODULE_LICENSE("GPL"); -static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END }; - - -I2C_CLIENT_INSMOD; /* ----------------------------------------------------------------------- */ @@ -53,28 +50,26 @@ static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode) u8 data[3] = { 0x00, 0x00, 0x04 }; switch (audmode) { - case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1_LANG2: - data[1] = 0x01; - break; - case V4L2_TUNER_MODE_LANG2: - data[1] = 0x02; - break; + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1_LANG2: + data[1] = 0x01; + break; + case V4L2_TUNER_MODE_LANG2: + data[1] = 0x02; + break; } - if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) { - v4l_err(client, "%s: I/O error setting audmode\n", client->name); - } - else { + if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) + v4l_err(client, "%s: I/O error setting audmode\n", + client->name); + else state->audmode = audmode; - } } -static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) { struct vp27smpx_state *state = i2c_get_clientdata(client); struct v4l2_tuner *vt = arg; @@ -103,7 +98,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0); + return v4l2_chip_ident_i2c_client(client, arg, + V4L2_IDENT_VP27SMPX, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Audio Mode: %u%s\n", state->audmode, @@ -125,88 +121,43 @@ static int vp27smpx_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind) +static int vp27smpx_probe(struct i2c_client *client) { - struct i2c_client *client; struct vp27smpx_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; snprintf(client->name, sizeof(client->name) - 1, "vp27smpx"); - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); + if (state == NULL) return -ENOMEM; - } state->audmode = V4L2_TUNER_MODE_STEREO; i2c_set_clientdata(client, state); /* initialize vp27smpx */ vp27smpx_set_audmode(client, state->audmode); - i2c_attach_client(client); - return 0; } -static int vp27smpx_probe(struct i2c_adapter *adapter) +static int vp27smpx_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, vp27smpx_attach); - return 0; -} - -static int vp27smpx_detach(struct i2c_client *client) -{ - struct vp27smpx_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); - + kfree(i2c_get_clientdata(client)); return 0; } /* ----------------------------------------------------------------------- */ -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "vp27smpx", - }, - .id = I2C_DRIVERID_VP27SMPX, - .attach_adapter = vp27smpx_probe, - .detach_client = vp27smpx_detach, - .command = vp27smpx_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "vp27smpx", + .driverid = I2C_DRIVERID_VP27SMPX, + .command = vp27smpx_command, + .probe = vp27smpx_probe, + .remove = vp27smpx_remove, }; - -static int __init vp27smpx_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit vp27smpx_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(vp27smpx_init_module); -module_exit(vp27smpx_cleanup_module); diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 1bf4cbec6a87..31795b4f8b63 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -30,21 +30,19 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv.h> MODULE_DESCRIPTION("wm8739 driver"); MODULE_AUTHOR("T. Adachi, Hans Verkuil"); MODULE_LICENSE("GPL"); -static int debug = 0; -static unsigned short normal_i2c[] = { 0x34 >> 1, 0x36 >> 1, I2C_CLIENT_END }; +static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -I2C_CLIENT_INSMOD; - /* ------------------------------------------------------------------------ */ enum { @@ -75,12 +73,10 @@ static int wm8739_write(struct i2c_client *client, int reg, u16 val) v4l_dbg(1, debug, client, "write: %02x %02x\n", reg, val); - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, (reg << 1) | - (val >> 8), val & 0xff) == 0) { + for (i = 0; i < 3; i++) + if (i2c_smbus_write_byte_data(client, + (reg << 1) | (val >> 8), val & 0xff) == 0) return 0; - } - } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } @@ -167,7 +163,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { .default_value = 58880, .flags = 0, .type = V4L2_CTRL_TYPE_INTEGER, - },{ + }, { .id = V4L2_CID_AUDIO_MUTE, .name = "Mute", .minimum = 0, @@ -176,7 +172,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { .default_value = 1, .flags = 0, .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ + }, { .id = V4L2_CID_AUDIO_BALANCE, .name = "Balance", .minimum = 0, @@ -190,7 +186,7 @@ static struct v4l2_queryctrl wm8739_qctrl[] = { /* ------------------------------------------------------------------------ */ -static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg) +static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) { struct wm8739_state *state = i2c_get_clientdata(client); @@ -200,21 +196,26 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg u32 audiofreq = *(u32 *)arg; state->clock_freq = audiofreq; - wm8739_write(client, R9, 0x000); /* de-activate */ + /* de-activate */ + wm8739_write(client, R9, 0x000); switch (audiofreq) { case 44100: - wm8739_write(client, R8, 0x020); /* 256fps, fs=44.1k */ + /* 256fps, fs=44.1k */ + wm8739_write(client, R8, 0x020); break; case 48000: - wm8739_write(client, R8, 0x000); /* 256fps, fs=48k */ + /* 256fps, fs=48k */ + wm8739_write(client, R8, 0x000); break; case 32000: - wm8739_write(client, R8, 0x018); /* 256fps, fs=32k */ + /* 256fps, fs=32k */ + wm8739_write(client, R8, 0x018); break; default: break; } - wm8739_write(client, R9, 0x001); /* activate */ + /* activate */ + wm8739_write(client, R9, 0x001); break; } @@ -238,7 +239,8 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg } case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8739, 0); + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_WM8739, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Frequency: %u Hz\n", state->clock_freq); @@ -259,27 +261,16 @@ static int wm8739_command(struct i2c_client *client, unsigned int cmd, void *arg /* i2c implementation */ -static struct i2c_driver i2c_driver; - -static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) +static int wm8739_probe(struct i2c_client *client) { - struct i2c_client *client; struct wm8739_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "wm8739"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); if (state == NULL) { @@ -295,67 +286,37 @@ static int wm8739_attach(struct i2c_adapter *adapter, int address, int kind) state->clock_freq = 48000; i2c_set_clientdata(client, state); - /* initialize wm8739 */ - wm8739_write(client, R15, 0x00); /* reset */ - wm8739_write(client, R5, 0x000); /* filter setting, high path, offet clear */ - wm8739_write(client, R6, 0x000); /* ADC, OSC, Power Off mode Disable */ - wm8739_write(client, R7, 0x049); /* Digital Audio interface format */ - /* Enable Master mode */ - /* 24 bit, MSB first/left justified */ - wm8739_write(client, R8, 0x000); /* sampling control */ - /* normal, 256fs, 48KHz sampling rate */ - wm8739_write(client, R9, 0x001); /* activate */ - wm8739_set_audio(client); /* set volume/mute */ - - i2c_attach_client(client); - - return 0; -} - -static int wm8739_probe(struct i2c_adapter *adapter) -{ - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, wm8739_attach); + /* Initialize wm8739 */ + + /* reset */ + wm8739_write(client, R15, 0x00); + /* filter setting, high path, offet clear */ + wm8739_write(client, R5, 0x000); + /* ADC, OSC, Power Off mode Disable */ + wm8739_write(client, R6, 0x000); + /* Digital Audio interface format: + Enable Master mode, 24 bit, MSB first/left justified */ + wm8739_write(client, R7, 0x049); + /* sampling control: normal, 256fs, 48KHz sampling rate */ + wm8739_write(client, R8, 0x000); + /* activate */ + wm8739_write(client, R9, 0x001); + /* set volume/mute */ + wm8739_set_audio(client); return 0; } -static int wm8739_detach(struct i2c_client *client) +static int wm8739_remove(struct i2c_client *client) { - struct wm8739_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) - return err; - - kfree(state); - kfree(client); + kfree(i2c_get_clientdata(client)); return 0; } -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "wm8739", - }, - .id = I2C_DRIVERID_WM8739, - .attach_adapter = wm8739_probe, - .detach_client = wm8739_detach, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "wm8739", + .driverid = I2C_DRIVERID_WM8739, .command = wm8739_command, + .probe = wm8739_probe, + .remove = wm8739_remove, }; - -static int __init wm8739_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit wm8739_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(wm8739_init_module); -module_exit(wm8739_cleanup_module); diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 9f7e894ef962..869f9e7946b6 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -34,6 +34,7 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv-legacy.h> MODULE_DESCRIPTION("wm8775 driver"); MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); @@ -44,6 +45,7 @@ static unsigned short normal_i2c[] = { 0x36 >> 1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; + /* ----------------------------------------------------------------------- */ enum { @@ -66,18 +68,15 @@ static int wm8775_write(struct i2c_client *client, int reg, u16 val) return -1; } - for (i = 0; i < 3; i++) { - if (i2c_smbus_write_byte_data(client, (reg << 1) | - (val >> 8), val & 0xff) == 0) { + for (i = 0; i < 3; i++) + if (i2c_smbus_write_byte_data(client, + (reg << 1) | (val >> 8), val & 0xff) == 0) return 0; - } - } v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg); return -1; } -static int wm8775_command(struct i2c_client *client, unsigned int cmd, - void *arg) +static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) { struct wm8775_state *state = i2c_get_clientdata(client); struct v4l2_routing *route = arg; @@ -126,7 +125,8 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, break; case VIDIOC_G_CHIP_IDENT: - return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_WM8775, 0); + return v4l2_chip_ident_i2c_client(client, + arg, V4L2_IDENT_WM8775, 0); case VIDIOC_LOG_STATUS: v4l_info(client, "Input: %d%s\n", state->input, @@ -159,105 +159,67 @@ static int wm8775_command(struct i2c_client *client, unsigned int cmd, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static struct i2c_driver i2c_driver; - -static int wm8775_attach(struct i2c_adapter *adapter, int address, int kind) +static int wm8775_probe(struct i2c_client *client) { - struct i2c_client *client; struct wm8775_state *state; /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return 0; - - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == 0) - return -ENOMEM; - - client->addr = address; - client->adapter = adapter; - client->driver = &i2c_driver; - snprintf(client->name, sizeof(client->name) - 1, "wm8775"); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; - v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name); + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); + if (state == NULL) return -ENOMEM; - } state->input = 2; state->muted = 0; i2c_set_clientdata(client, state); - /* initialize wm8775 */ - wm8775_write(client, R23, 0x000); /* RESET */ - wm8775_write(client, R7, 0x000); /* Disable zero cross detect timeout */ - wm8775_write(client, R11, 0x021); /* Left justified, 24-bit mode */ - wm8775_write(client, R12, 0x102); /* Master mode, clock ratio 256fs */ - wm8775_write(client, R13, 0x000); /* Powered up */ - wm8775_write(client, R14, 0x1d4); /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(client, R15, 0x1d4); /* ADC gain +2.5dB, enable zero cross */ - wm8775_write(client, R16, 0x1bf); /* ALC Stereo, ALC target level -1dB FS */ - /* max gain +8dB */ - wm8775_write(client, R17, 0x185); /* Enable gain control, use zero cross */ - /* detection, ALC hold time 42.6 ms */ - wm8775_write(client, R18, 0x0a2); /* ALC gain ramp up delay 34 s, */ - /* ALC gain ramp down delay 33 ms */ - wm8775_write(client, R19, 0x005); /* Enable noise gate, threshold -72dBfs */ - wm8775_write(client, R20, 0x07a); /* Transient window 4ms, lower PGA gain */ - /* limit -1dB */ - wm8775_write(client, R21, 0x102); /* LRBOTH = 1, use input 2. */ - i2c_attach_client(client); - + /* Initialize wm8775 */ + + /* RESET */ + wm8775_write(client, R23, 0x000); + /* Disable zero cross detect timeout */ + wm8775_write(client, R7, 0x000); + /* Left justified, 24-bit mode */ + wm8775_write(client, R11, 0x021); + /* Master mode, clock ratio 256fs */ + wm8775_write(client, R12, 0x102); + /* Powered up */ + wm8775_write(client, R13, 0x000); + /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(client, R14, 0x1d4); + /* ADC gain +2.5dB, enable zero cross */ + wm8775_write(client, R15, 0x1d4); + /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ + wm8775_write(client, R16, 0x1bf); + /* Enable gain control, use zero cross detection, + ALC hold time 42.6 ms */ + wm8775_write(client, R17, 0x185); + /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ + wm8775_write(client, R18, 0x0a2); + /* Enable noise gate, threshold -72dBfs */ + wm8775_write(client, R19, 0x005); + /* Transient window 4ms, lower PGA gain limit -1dB */ + wm8775_write(client, R20, 0x07a); + /* LRBOTH = 1, use input 2. */ + wm8775_write(client, R21, 0x102); return 0; } -static int wm8775_probe(struct i2c_adapter *adapter) +static int wm8775_remove(struct i2c_client *client) { - if (adapter->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adapter, &addr_data, wm8775_attach); + kfree(i2c_get_clientdata(client)); return 0; } -static int wm8775_detach(struct i2c_client *client) -{ - struct wm8775_state *state = i2c_get_clientdata(client); - int err; - - err = i2c_detach_client(client); - if (err) { - return err; - } - kfree(state); - kfree(client); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -/* i2c implementation */ -static struct i2c_driver i2c_driver = { - .driver = { - .name = "wm8775", - }, - .id = I2C_DRIVERID_WM8775, - .attach_adapter = wm8775_probe, - .detach_client = wm8775_detach, - .command = wm8775_command, +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "wm8775", + .driverid = I2C_DRIVERID_WM8775, + .command = wm8775_command, + .probe = wm8775_probe, + .remove = wm8775_remove, }; - -static int __init wm8775_init_module(void) -{ - return i2c_add_driver(&i2c_driver); -} - -static void __exit wm8775_cleanup_module(void) -{ - i2c_del_driver(&i2c_driver); -} - -module_init(wm8775_init_module); -module_exit(wm8775_cleanup_module); diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 6f1892585cbb..1fdbb46de7f3 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -749,7 +749,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) } -static struct file_operations zr364xx_fops = { +static const struct file_operations zr364xx_fops = { .owner = THIS_MODULE, .open = zr364xx_open, .release = zr364xx_release, diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 52fb216dfe74..425f60c21fdd 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -2056,7 +2056,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_upload: alt_%s has cached_fw=%p \n", ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); - ioc->alt_ioc->cached_fw = NULL; + ioc->cached_fw = NULL; } } else { printk(MYIOC_s_WARN_FMT @@ -2262,10 +2262,12 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) int ret; if (ioc->cached_fw != NULL) { - ddlprintk(ioc, printk(MYIOC_s_INFO_FMT - "mpt_adapter_disable: Pushing FW onto adapter\n", ioc->name)); - if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) { - printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n", + ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: Pushing FW onto " + "adapter\n", __FUNCTION__, ioc->name)); + if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *) + ioc->cached_fw, CAN_SLEEP)) < 0) { + printk(MYIOC_s_WARN_FMT + ": firmware downloadboot failure (%d)!\n", ioc->name, ret); } } @@ -2303,13 +2305,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) ioc->alloc_total -= sz; } - if (ioc->cached_fw != NULL) { - sz = ioc->facts.FWImageSize; - pci_free_consistent(ioc->pcidev, sz, - ioc->cached_fw, ioc->cached_fw_dma); - ioc->cached_fw = NULL; - ioc->alloc_total -= sz; - } + mpt_free_fw_memory(ioc); kfree(ioc->spi_data.nvram); mpt_inactive_raid_list_free(ioc); @@ -3047,44 +3043,62 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) * * If memory has already been allocated, the same (cached) value * is returned. - */ -void + * + * Return 0 if successfull, or non-zero for failure + **/ +int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size) { - if (ioc->cached_fw) - return; /* use already allocated memory */ - if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + int rc; + + if (ioc->cached_fw) { + rc = 0; /* use already allocated memory */ + goto out; + } + else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */ ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma; - ioc->alloc_total += size; - ioc->alt_ioc->alloc_total -= size; + rc = 0; + goto out; + } + ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma); + if (!ioc->cached_fw) { + printk(MYIOC_s_ERR_FMT "Unable to allocate memory for the cached firmware image!\n", + ioc->name); + rc = -1; } else { - if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) ) - ioc->alloc_total += size; + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, size, size)); + ioc->alloc_total += size; + rc = 0; } + out: + return rc; } + /** * mpt_free_fw_memory - free firmware memory * @ioc: Pointer to MPT_ADAPTER structure * * If alt_img is NULL, delete from ioc structure. * Else, delete a secondary image in same format. - */ + **/ void mpt_free_fw_memory(MPT_ADAPTER *ioc) { int sz; + if (!ioc->cached_fw) + return; + sz = ioc->facts.FWImageSize; - dinitprintk(ioc, printk(MYIOC_s_INFO_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", - ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); + dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); + ioc->alloc_total -= sz; ioc->cached_fw = NULL; - - return; } - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mpt_do_upload - Construct and Send FWUpload request to MPT adapter port. @@ -3116,17 +3130,12 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) if ((sz = ioc->facts.FWImageSize) == 0) return 0; - mpt_alloc_fw_memory(ioc, sz); + if (mpt_alloc_fw_memory(ioc, ioc->facts.FWImageSize) != 0) + return -ENOMEM; dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": FW Image @ %p[%p], sz=%d[%x] bytes\n", ioc->name, ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); - if (ioc->cached_fw == NULL) { - /* Major Failure. - */ - return -ENOMEM; - } - prequest = (sleepFlag == NO_SLEEP) ? kzalloc(ioc->req_sz, GFP_ATOMIC) : kzalloc(ioc->req_sz, GFP_KERNEL); if (!prequest) { @@ -3498,12 +3507,12 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag) static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) { - MPT_ADAPTER *iocp=NULL; u32 diag0val; u32 doorbell; int hard_reset_done = 0; int count = 0; u32 diag1val = 0; + MpiFwHeader_t *cached_fw; /* Pointer to FW */ /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -3635,22 +3644,24 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) } if (ioc->cached_fw) - iocp = ioc; + cached_fw = (MpiFwHeader_t *)ioc->cached_fw; else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) - iocp = ioc->alt_ioc; - if (iocp) { + cached_fw = (MpiFwHeader_t *)ioc->alt_ioc->cached_fw; + else + cached_fw = NULL; + if (cached_fw) { /* If the DownloadBoot operation fails, the * IOC will be left unusable. This is a fatal error * case. _diag_reset will return < 0 */ for (count = 0; count < 30; count ++) { - diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic); + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) { break; } dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n", - iocp->name, diag0val, count)); + ioc->name, diag0val, count)); /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { msleep (1000); @@ -3658,8 +3669,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) mdelay (1000); } } - if ((count = mpt_downloadboot(ioc, - (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) { + if ((count = mpt_downloadboot(ioc, cached_fw, sleepFlag)) < 0) { printk(MYIOC_s_WARN_FMT "firmware downloadboot failure (%d)!\n", ioc->name, count); } diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index d7682e083f59..b49b706c0020 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -907,7 +907,7 @@ extern u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); -extern void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size); +extern int mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size); extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index e4c94f93de16..f77b329f6923 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1343,6 +1343,8 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; memcpy(req->sense, smprep, sizeof(*smprep)); req->sense_len = sizeof(*smprep); + req->data_len = 0; + rsp->data_len -= smprep->ResponseDataLength; } else { printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", ioc->name, __FUNCTION__); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 626bb3c9af2b..5c614ec38cc4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -111,7 +111,7 @@ int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state); int mptscsih_resume(struct pci_dev *pdev); #endif -#define SNS_LEN(scp) sizeof((scp)->sense_buffer) +#define SNS_LEN(scp) SCSI_SENSE_BUFFERSIZE /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index e4ad7a1c4fbd..a95314897402 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -412,13 +412,13 @@ static void i2o_block_delayed_request_fn(struct work_struct *work) /** * i2o_block_end_request - Post-processing of completed commands * @req: request which should be completed - * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error + * @error: 0 for success, < 0 for error * @nr_bytes: number of bytes to complete * * Mark the request as complete. The lock must not be held when entering. * */ -static void i2o_block_end_request(struct request *req, int uptodate, +static void i2o_block_end_request(struct request *req, int error, int nr_bytes) { struct i2o_block_request *ireq = req->special; @@ -426,22 +426,18 @@ static void i2o_block_end_request(struct request *req, int uptodate, struct request_queue *q = req->q; unsigned long flags; - if (end_that_request_chunk(req, uptodate, nr_bytes)) { + if (blk_end_request(req, error, nr_bytes)) { int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT); if (blk_pc_request(req)) leftover = req->data_len; - if (end_io_error(uptodate)) - end_that_request_chunk(req, 0, leftover); + if (error) + blk_end_request(req, -EIO, leftover); } - add_disk_randomness(req->rq_disk); - spin_lock_irqsave(q->queue_lock, flags); - end_that_request_last(req, uptodate); - if (likely(dev)) { dev->open_queue_depth--; list_del(&ireq->queue); @@ -468,7 +464,7 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m, struct i2o_message *msg) { struct request *req; - int uptodate = 1; + int error = 0; req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt)); if (unlikely(!req)) { @@ -501,10 +497,10 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m, req->errors++; - uptodate = 0; + error = -EIO; } - i2o_block_end_request(req, uptodate, le32_to_cpu(msg->body[1])); + i2o_block_end_request(req, error, le32_to_cpu(msg->body[1])); return 1; }; diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index aa6fb9429d58..1bcdbbb9e7d3 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -370,7 +370,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m, */ if (cmd->result) memcpy(cmd->sense_buffer, &msg->body[3], - min(sizeof(cmd->sense_buffer), (size_t) 40)); + min(SCSI_SENSE_BUFFERSIZE, 40)); /* only output error code if AdapterStatus is not HBA_SUCCESS */ if ((error >> 8) & 0xff) diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c index e325fa71f38b..61aeaf79640d 100644 --- a/drivers/mfd/ucb1x00-assabet.c +++ b/drivers/mfd/ucb1x00-assabet.c @@ -20,7 +20,8 @@ #include "ucb1x00.h" #define UCB1X00_ATTR(name,input)\ -static ssize_t name##_show(struct class_device *dev, char *buf) \ +static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ { \ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); \ int val; \ @@ -29,7 +30,7 @@ static ssize_t name##_show(struct class_device *dev, char *buf) \ ucb1x00_adc_disable(ucb); \ return sprintf(buf, "%d\n", val); \ } \ -static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL) +static DEVICE_ATTR(name,0444,name##_show,NULL) UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1); UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0); @@ -37,17 +38,17 @@ UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2); static int ucb1x00_assabet_add(struct ucb1x00_dev *dev) { - class_device_create_file(&dev->ucb->cdev, &class_device_attr_vbatt); - class_device_create_file(&dev->ucb->cdev, &class_device_attr_vcharger); - class_device_create_file(&dev->ucb->cdev, &class_device_attr_batt_temp); + device_create_file(&dev->ucb->dev, &dev_attr_vbatt); + device_create_file(&dev->ucb->dev, &dev_attr_vcharger); + device_create_file(&dev->ucb->dev, &dev_attr_batt_temp); return 0; } static void ucb1x00_assabet_remove(struct ucb1x00_dev *dev) { - class_device_remove_file(&dev->ucb->cdev, &class_device_attr_batt_temp); - class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vcharger); - class_device_remove_file(&dev->ucb->cdev, &class_device_attr_vbatt); + device_remove_file(&dev->ucb->dev, &dev_attr_batt_temp); + device_remove_file(&dev->ucb->dev, &dev_attr_vcharger); + device_remove_file(&dev->ucb->dev, &dev_attr_vbatt); } static struct ucb1x00_driver ucb1x00_assabet_driver = { diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index e03f1bcd4f9f..f6b10dda31fd 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -458,7 +458,7 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb) return probe_irq_off(mask); } -static void ucb1x00_release(struct class_device *dev) +static void ucb1x00_release(struct device *dev) { struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); kfree(ucb); @@ -466,7 +466,7 @@ static void ucb1x00_release(struct class_device *dev) static struct class ucb1x00_class = { .name = "ucb1x00", - .release = ucb1x00_release, + .dev_release = ucb1x00_release, }; static int ucb1x00_probe(struct mcp *mcp) @@ -490,9 +490,9 @@ static int ucb1x00_probe(struct mcp *mcp) goto err_disable; - ucb->cdev.class = &ucb1x00_class; - ucb->cdev.dev = &mcp->attached_device; - strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id)); + ucb->dev.class = &ucb1x00_class; + ucb->dev.parent = &mcp->attached_device; + strlcpy(ucb->dev.bus_id, "ucb1x00", sizeof(ucb->dev.bus_id)); spin_lock_init(&ucb->lock); spin_lock_init(&ucb->io_lock); @@ -517,7 +517,7 @@ static int ucb1x00_probe(struct mcp *mcp) mcp_set_drvdata(mcp, ucb); - ret = class_device_register(&ucb->cdev); + ret = device_register(&ucb->dev); if (ret) goto err_irq; @@ -554,7 +554,7 @@ static void ucb1x00_remove(struct mcp *mcp) mutex_unlock(&ucb1x00_mutex); free_irq(ucb->irq, ucb); - class_device_unregister(&ucb->cdev); + device_unregister(&ucb->dev); } int ucb1x00_register_driver(struct ucb1x00_driver *drv) diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h index ca8df8072d43..a8ad8a0ed5db 100644 --- a/drivers/mfd/ucb1x00.h +++ b/drivers/mfd/ucb1x00.h @@ -120,7 +120,7 @@ struct ucb1x00 { u16 irq_fal_enbl; u16 irq_ris_enbl; struct ucb1x00_irq irq_handler[16]; - struct class_device cdev; + struct device dev; struct list_head node; struct list_head devs; }; @@ -144,7 +144,7 @@ struct ucb1x00_driver { int (*resume)(struct ucb1x00_dev *dev); }; -#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, cdev) +#define classdev_to_ucb1x00(cd) container_of(cd, struct ucb1x00, dev) int ucb1x00_register_driver(struct ucb1x00_driver *); void ucb1x00_unregister_driver(struct ucb1x00_driver *); diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 6497872df524..1a0e7978226a 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -26,11 +26,6 @@ #include "lowlevel.h" static void exec_next_command(struct service_processor *sp); -static void free_command(struct kobject *kobj); - -static struct kobj_type ibmasm_cmd_kobj_type = { - .release = free_command, -}; static atomic_t command_count = ATOMIC_INIT(0); @@ -53,8 +48,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s } cmd->buffer_size = buffer_size; - kobject_init(&cmd->kobj); - cmd->kobj.ktype = &ibmasm_cmd_kobj_type; + kref_init(&cmd->kref); cmd->lock = &sp->lock; cmd->status = IBMASM_CMD_PENDING; @@ -67,9 +61,9 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s return cmd; } -static void free_command(struct kobject *kobj) +void ibmasm_free_command(struct kref *kref) { - struct command *cmd = to_command(kobj); + struct command *cmd = to_command(kref); list_del(&cmd->queue_node); atomic_dec(&command_count); diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h index de860bc6d3f5..4d8a4e248b34 100644 --- a/drivers/misc/ibmasm/ibmasm.h +++ b/drivers/misc/ibmasm/ibmasm.h @@ -31,6 +31,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/interrupt.h> +#include <linux/kref.h> #include <linux/device.h> #include <linux/input.h> @@ -92,24 +93,25 @@ struct command { unsigned char *buffer; size_t buffer_size; int status; - struct kobject kobj; + struct kref kref; spinlock_t *lock; }; -#define to_command(c) container_of(c, struct command, kobj) +#define to_command(c) container_of(c, struct command, kref) +void ibmasm_free_command(struct kref *kref); static inline void command_put(struct command *cmd) { unsigned long flags; spinlock_t *lock = cmd->lock; spin_lock_irqsave(lock, flags); - kobject_put(&cmd->kobj); + kref_put(&cmd->kref, ibmasm_free_command); spin_unlock_irqrestore(lock, flags); } static inline void command_get(struct command *cmd) { - kobject_get(&cmd->kobj); + kref_get(&cmd->kref); } diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c index 2d1b3df95c5b..54380da343a5 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c @@ -149,7 +149,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) socket_change_set = fm->socket_change_set; fm->socket_change_set = 0; - dev_dbg(fm->cdev.dev, "checking media set %x\n", + dev_dbg(fm->dev.parent, "checking media set %x\n", socket_change_set); if (!socket_change_set) { @@ -164,7 +164,7 @@ static void tifm_7xx1_switch_media(struct work_struct *work) if (sock) { printk(KERN_INFO "%s : demand removing card from socket %u:%u\n", - fm->cdev.class_id, fm->id, cnt); + fm->dev.bus_id, fm->id, cnt); fm->sockets[cnt] = NULL; sock_addr = sock->addr; spin_unlock_irqrestore(&fm->lock, flags); diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 8f77949f93dd..97544052e768 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c @@ -160,16 +160,16 @@ static struct bus_type tifm_bus_type = { .resume = tifm_device_resume }; -static void tifm_free(struct class_device *cdev) +static void tifm_free(struct device *dev) { - struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev); + struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev); kfree(fm); } static struct class tifm_adapter_class = { .name = "tifm_adapter", - .release = tifm_free + .dev_release = tifm_free }; struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets, @@ -180,9 +180,9 @@ struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets, fm = kzalloc(sizeof(struct tifm_adapter) + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL); if (fm) { - fm->cdev.class = &tifm_adapter_class; - fm->cdev.dev = dev; - class_device_initialize(&fm->cdev); + fm->dev.class = &tifm_adapter_class; + fm->dev.parent = dev; + device_initialize(&fm->dev); spin_lock_init(&fm->lock); fm->num_sockets = num_sockets; } @@ -203,8 +203,8 @@ int tifm_add_adapter(struct tifm_adapter *fm) if (rc) return rc; - snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id); - rc = class_device_add(&fm->cdev); + snprintf(fm->dev.bus_id, BUS_ID_SIZE, "tifm%u", fm->id); + rc = device_add(&fm->dev); if (rc) { spin_lock(&tifm_adapter_lock); idr_remove(&tifm_adapter_idr, fm->id); @@ -228,13 +228,13 @@ void tifm_remove_adapter(struct tifm_adapter *fm) spin_lock(&tifm_adapter_lock); idr_remove(&tifm_adapter_idr, fm->id); spin_unlock(&tifm_adapter_lock); - class_device_del(&fm->cdev); + device_del(&fm->dev); } EXPORT_SYMBOL(tifm_remove_adapter); void tifm_free_adapter(struct tifm_adapter *fm) { - class_device_put(&fm->cdev); + put_device(&fm->dev); } EXPORT_SYMBOL(tifm_free_adapter); @@ -261,9 +261,9 @@ struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id, sock->card_event = tifm_dummy_event; sock->data_event = tifm_dummy_event; - sock->dev.parent = fm->cdev.dev; + sock->dev.parent = fm->dev.parent; sock->dev.bus = &tifm_bus_type; - sock->dev.dma_mask = fm->cdev.dev->dma_mask; + sock->dev.dma_mask = fm->dev.parent->dma_mask; sock->dev.release = tifm_free_device; snprintf(sock->dev.bus_id, BUS_ID_SIZE, diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index aeb32a93f6a0..91ded3e82401 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -348,15 +348,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) * A block was successfully transferred. */ spin_lock_irq(&md->lock); - ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); - if (!ret) { - /* - * The whole request completed successfully. - */ - add_disk_randomness(req->rq_disk); - blkdev_dequeue_request(req); - end_that_request_last(req, 1); - } + ret = __blk_end_request(req, 0, brq.data.bytes_xfered); spin_unlock_irq(&md->lock); } while (ret); @@ -386,27 +378,21 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) else bytes = blocks << 9; spin_lock_irq(&md->lock); - ret = end_that_request_chunk(req, 1, bytes); + ret = __blk_end_request(req, 0, bytes); spin_unlock_irq(&md->lock); } } else if (rq_data_dir(req) != READ && (card->host->caps & MMC_CAP_MULTIWRITE)) { spin_lock_irq(&md->lock); - ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); + ret = __blk_end_request(req, 0, brq.data.bytes_xfered); spin_unlock_irq(&md->lock); } mmc_release_host(card->host); spin_lock_irq(&md->lock); - while (ret) { - ret = end_that_request_chunk(req, 0, - req->current_nr_sectors << 9); - } - - add_disk_randomness(req->rq_disk); - blkdev_dequeue_request(req); - end_that_request_last(req, 0); + while (ret) + ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req)); spin_unlock_irq(&md->lock); return 0; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 30cd13b13ac3..7731ddefdc1b 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -94,8 +94,8 @@ static void mmc_request(struct request_queue *q) printk(KERN_ERR "MMC: killing requests for dead queue\n"); while ((req = elv_next_request(q)) != NULL) { do { - ret = end_that_request_chunk(req, 0, - req->current_nr_sectors << 9); + ret = __blk_end_request(req, -EIO, + blk_rq_cur_bytes(req)); } while (ret); } return; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 971e18b91f4a..c9dfeb15b487 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -25,6 +25,7 @@ #include <linux/mmc/card.h> #include <linux/clk.h> #include <linux/scatterlist.h> +#include <linux/i2c/tps65010.h> #include <asm/io.h> #include <asm/irq.h> @@ -35,7 +36,6 @@ #include <asm/arch/dma.h> #include <asm/arch/mux.h> #include <asm/arch/fpga.h> -#include <asm/arch/tps65010.h> #define OMAP_MMC_REG_CMD 0x00 #define OMAP_MMC_REG_ARGL 0x04 diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 1654a3330340..1ea8482037bb 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -65,6 +65,8 @@ struct pxamci_host { unsigned int dma_len; unsigned int dma_dir; + unsigned int dma_drcmrrx; + unsigned int dma_drcmrtx; }; static void pxamci_stop_clock(struct pxamci_host *host) @@ -131,13 +133,13 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) { host->dma_dir = DMA_FROM_DEVICE; dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; - DRCMRTXMMC = 0; - DRCMRRXMMC = host->dma | DRCMR_MAPVLD; + DRCMR(host->dma_drcmrtx) = 0; + DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; } else { host->dma_dir = DMA_TO_DEVICE; dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; - DRCMRRXMMC = 0; - DRCMRTXMMC = host->dma | DRCMR_MAPVLD; + DRCMR(host->dma_drcmrrx) = 0; + DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; } dcmd |= DCMD_BURST32 | DCMD_WIDTH1; @@ -375,14 +377,23 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->clkrt == CLKRT_OFF) clk_enable(host->clk); - /* - * clk might result in a lower divisor than we - * desire. check for that condition and adjust - * as appropriate. - */ - if (rate / clk > ios->clock) - clk <<= 1; - host->clkrt = fls(clk) - 1; + if (ios->clock == 26000000) { + /* to support 26MHz on pxa300/pxa310 */ + host->clkrt = 7; + } else { + /* to handle (19.5MHz, 26MHz) */ + if (!clk) + clk = 1; + + /* + * clk might result in a lower divisor than we + * desire. check for that condition and adjust + * as appropriate. + */ + if (rate / clk > ios->clock) + clk <<= 1; + host->clkrt = fls(clk) - 1; + } /* * we write clkrt on the next command @@ -459,7 +470,7 @@ static int pxamci_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct pxamci_host *host = NULL; - struct resource *r; + struct resource *r, *dmarx, *dmatx; int ret, irq; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -519,7 +530,8 @@ static int pxamci_probe(struct platform_device *pdev) * Calculate minimum clock rate, rounding up. */ mmc->f_min = (host->clkrate + 63) / 64; - mmc->f_max = host->clkrate; + mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 + : host->clkrate; mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : @@ -529,6 +541,9 @@ static int pxamci_probe(struct platform_device *pdev) if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; host->cmdat |= CMDAT_SDIO_INT_EN; + if (cpu_is_pxa300() || cpu_is_pxa310()) + mmc->caps |= MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SD_HIGHSPEED; } host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); @@ -570,6 +585,20 @@ static int pxamci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); + dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmarx) { + ret = -ENXIO; + goto out; + } + host->dma_drcmrrx = dmarx->start; + + dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!dmatx) { + ret = -ENXIO; + goto out; + } + host->dma_drcmrtx = dmatx->start; + if (host->pdata && host->pdata->init) host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); @@ -613,8 +642,8 @@ static int pxamci_remove(struct platform_device *pdev) END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, host->base + MMC_I_MASK); - DRCMRRXMMC = 0; - DRCMRTXMMC = 0; + DRCMR(host->dma_drcmrrx) = 0; + DRCMR(host->dma_drcmrtx) = 0; free_irq(host->irq, host); pxa_free_dma(host->dma); diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h index 748c7706f237..f6c2e2fcce37 100644 --- a/drivers/mmc/host/pxamci.h +++ b/drivers/mmc/host/pxamci.h @@ -68,7 +68,7 @@ #define PRG_DONE (1 << 1) #define DATA_TRAN_DONE (1 << 0) -#ifdef CONFIG_PXA27x +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) #define MMC_I_MASK_ALL 0x00001fff #else #define MMC_I_MASK_ALL 0x0000007f diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 22ed96c4b7bd..a0cee86464ca 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -27,12 +27,10 @@ static void mtd_notify_add(struct mtd_info* mtd) if (!mtd) return; - class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), - NULL, "mtd%d", mtd->index); + device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), "mtd%d", mtd->index); - class_device_create(mtd_class, NULL, - MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), - NULL, "mtd%dro", mtd->index); + device_create(mtd_class, NULL, + MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), "mtd%dro", mtd->index); } static void mtd_notify_remove(struct mtd_info* mtd) @@ -40,8 +38,8 @@ static void mtd_notify_remove(struct mtd_info* mtd) if (!mtd) return; - class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); - class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); + device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); + device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); } static struct mtd_notifier notifier = { diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index be71868d1513..7d253686ed0d 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -17,7 +17,7 @@ Annapolis MD 21403 Fixed (again!) the missing interrupt locking on TX/RX shifting. - Alan Cox <Alan.Cox@linux.org> + Alan Cox <Alan.Cox@linux.org> Removed calls to init_etherdev since they are no longer needed, and cleaned up modularization just a bit. The driver still allows only @@ -29,16 +29,16 @@ the board. Now getting 150K/second FTP with a 3c501 card. Still playing with a TX-TX optimisation to see if we can touch 180-200K/second as seems theoretically maximum. - 19950402 Alan Cox <Alan.Cox@linux.org> + 19950402 Alan Cox <Alan.Cox@linux.org> Cleaned up for 2.3.x because we broke SMP now. - 20000208 Alan Cox <alan@redhat.com> + 20000208 Alan Cox <alan@redhat.com> Check up pass for 2.5. Nothing significant changed - 20021009 Alan Cox <alan@redhat.com> + 20021009 Alan Cox <alan@redhat.com> Fixed zero fill corner case - 20030104 Alan Cox <alan@redhat.com> + 20030104 Alan Cox <alan@redhat.com> For the avoidance of doubt the "preferred form" of this code is one which @@ -139,8 +139,8 @@ static const char version[] = * The boilerplate probe code. */ -static int io=0x280; -static int irq=5; +static int io = 0x280; +static int irq = 5; static int mem_start; /** @@ -229,8 +229,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) * Read the station address PROM data from the special port. */ - for (i = 0; i < 6; i++) - { + for (i = 0; i < 6; i++) { outw(i, ioaddr + EL1_DATAPTR); station_addr[i] = inb(ioaddr + EL1_SAPROM); } @@ -240,28 +239,24 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) */ if (station_addr[0] == 0x02 && station_addr[1] == 0x60 - && station_addr[2] == 0x8c) - { + && station_addr[2] == 0x8c) mname = "3c501"; - } else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 - && station_addr[2] == 0xC8) - { + else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 + && station_addr[2] == 0xC8) mname = "NP943"; - } - else { + else { release_region(ioaddr, EL1_IO_EXTENT); return -ENODEV; } /* - * We auto-IRQ by shutting off the interrupt line and letting it float - * high. + * We auto-IRQ by shutting off the interrupt line and letting it + * float high. */ dev->irq = irq; - if (dev->irq < 2) - { + if (dev->irq < 2) { unsigned long irq_mask; irq_mask = probe_irq_on(); @@ -274,8 +269,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) mdelay(20); autoirq = probe_irq_off(irq_mask); - if (autoirq == 0) - { + if (autoirq == 0) { printk(KERN_WARNING "%s probe at %#x failed to detect IRQ line.\n", mname, ioaddr); release_region(ioaddr, EL1_IO_EXTENT); @@ -292,7 +286,8 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) if (autoirq) dev->irq = autoirq; - printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n", dev->name, mname, dev->base_addr, + printk(KERN_INFO "%s: %s EtherLink at %#lx, using %sIRQ %d.\n", + dev->name, mname, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq); #ifdef CONFIG_IP_MULTICAST @@ -343,7 +338,8 @@ static int el_open(struct net_device *dev) if (el_debug > 2) printk(KERN_DEBUG "%s: Doing el_open()...", dev->name); - if ((retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev))) + retval = request_irq(dev->irq, &el_interrupt, 0, dev->name, dev); + if (retval) return retval; spin_lock_irqsave(&lp->lock, flags); @@ -371,8 +367,9 @@ static void el_timeout(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug) - printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", - dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS)); + printk(KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n", + dev->name, inb(TX_STATUS), + inb(AX_STATUS), inb(RX_STATUS)); dev->stats.tx_errors++; outb(TX_NORM, TX_CMD); outb(RX_NORM, RX_CMD); @@ -425,8 +422,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); - do - { + do { int len = skb->len; int pad = 0; int gp_start; @@ -435,10 +431,10 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) if (len < ETH_ZLEN) pad = ETH_ZLEN - len; - gp_start = 0x800 - ( len + pad ); + gp_start = 0x800 - (len + pad); lp->tx_pkt_start = gp_start; - lp->collisions = 0; + lp->collisions = 0; dev->stats.tx_bytes += skb->len; @@ -455,37 +451,42 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->txing = 1; /* - * Turn interrupts back on while we spend a pleasant afternoon - * loading bytes into the board + * Turn interrupts back on while we spend a pleasant + * afternoon loading bytes into the board */ spin_unlock_irqrestore(&lp->lock, flags); - outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ - outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ - outsb(DATAPORT,buf,len); /* load buffer (usual thing each byte increments the pointer) */ + /* Set rx packet area to 0. */ + outw(0x00, RX_BUF_CLR); + /* aim - packet will be loaded into buffer start */ + outw(gp_start, GP_LOW); + /* load buffer (usual thing each byte increments the pointer) */ + outsb(DATAPORT, buf, len); if (pad) { - while(pad--) /* Zero fill buffer tail */ + while (pad--) /* Zero fill buffer tail */ outb(0, DATAPORT); } - outw(gp_start, GP_LOW); /* the board reuses the same register */ + /* the board reuses the same register */ + outw(gp_start, GP_LOW); - if(lp->loading != 2) - { - outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ - lp->loading=0; + if (lp->loading != 2) { + /* fire ... Trigger xmit. */ + outb(AX_XMIT, AX_CMD); + lp->loading = 0; dev->trans_start = jiffies; if (el_debug > 2) printk(KERN_DEBUG " queued xmit.\n"); - dev_kfree_skb (skb); + dev_kfree_skb(skb); return 0; } /* A receive upset our load, despite our best efforts */ - if(el_debug>2) - printk(KERN_DEBUG "%s: burped during tx load.\n", dev->name); + if (el_debug > 2) + printk(KERN_DEBUG "%s: burped during tx load.\n", + dev->name); spin_lock_irqsave(&lp->lock, flags); } - while(1); + while (1); } @@ -534,64 +535,59 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) */ if (el_debug > 3) - printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", dev->name, axsr); - - if(lp->loading==1 && !lp->txing) - printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n", - dev->name); - - if (lp->txing) - { + printk(KERN_DEBUG "%s: el_interrupt() aux=%#02x", + dev->name, axsr); - /* - * Board in transmit mode. May be loading. If we are - * loading we shouldn't have got this. - */ + if (lp->loading == 1 && !lp->txing) + printk(KERN_WARNING "%s: Inconsistent state loading while not in tx\n", + dev->name); + if (lp->txing) { + /* + * Board in transmit mode. May be loading. If we are + * loading we shouldn't have got this. + */ int txsr = inb(TX_STATUS); - if(lp->loading==1) - { - if(el_debug > 2) - { - printk(KERN_DEBUG "%s: Interrupt while loading [", dev->name); - printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW)); + if (lp->loading == 1) { + if (el_debug > 2) { + printk(KERN_DEBUG "%s: Interrupt while loading [", + dev->name); + printk(" txsr=%02x gp=%04x rp=%04x]\n", + txsr, inw(GP_LOW), inw(RX_LOW)); } - lp->loading=2; /* Force a reload */ + /* Force a reload */ + lp->loading = 2; spin_unlock(&lp->lock); goto out; } - if (el_debug > 6) - printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW)); + printk(KERN_DEBUG " txsr=%02x gp=%04x rp=%04x", + txsr, inw(GP_LOW), inw(RX_LOW)); - if ((axsr & 0x80) && (txsr & TX_READY) == 0) - { + if ((axsr & 0x80) && (txsr & TX_READY) == 0) { /* - * FIXME: is there a logic to whether to keep on trying or - * reset immediately ? + * FIXME: is there a logic to whether to keep + * on trying or reset immediately ? */ - if(el_debug>1) - printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x" - " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, - inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); + if (el_debug > 1) + printk(KERN_DEBUG "%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x gp=%03x rp=%03x.\n", + dev->name, txsr, axsr, + inw(ioaddr + EL1_DATAPTR), + inw(ioaddr + EL1_RXPTR)); lp->txing = 0; netif_wake_queue(dev); - } - else if (txsr & TX_16COLLISIONS) - { + } else if (txsr & TX_16COLLISIONS) { /* * Timed out */ if (el_debug) - printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name); + printk(KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n", dev->name); outb(AX_SYS, AX_CMD); lp->txing = 0; dev->stats.tx_aborted_errors++; netif_wake_queue(dev); - } - else if (txsr & TX_COLLISION) - { + } else if (txsr & TX_COLLISION) { /* * Retrigger xmit. */ @@ -599,7 +595,8 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) if (el_debug > 6) printk(KERN_DEBUG " retransmitting after a collision.\n"); /* - * Poor little chip can't reset its own start pointer + * Poor little chip can't reset its own start + * pointer */ outb(AX_SYS, AX_CMD); @@ -608,53 +605,45 @@ static irqreturn_t el_interrupt(int irq, void *dev_id) dev->stats.collisions++; spin_unlock(&lp->lock); goto out; - } - else - { + } else { /* * It worked.. we will now fall through and receive */ dev->stats.tx_packets++; if (el_debug > 6) printk(KERN_DEBUG " Tx succeeded %s\n", - (txsr & TX_RDY) ? "." : "but tx is busy!"); + (txsr & TX_RDY) ? "." : "but tx is busy!"); /* * This is safe the interrupt is atomic WRT itself. */ - lp->txing = 0; - netif_wake_queue(dev); /* In case more to transmit */ + /* In case more to transmit */ + netif_wake_queue(dev); } - } - else - { - /* - * In receive mode. - */ + } else { + /* + * In receive mode. + */ int rxsr = inb(RX_STATUS); if (el_debug > 5) - printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW)); + printk(KERN_DEBUG " rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS), inw(RX_LOW)); /* * Just reading rx_status fixes most errors. */ if (rxsr & RX_MISSED) dev->stats.rx_missed_errors++; - else if (rxsr & RX_RUNT) - { /* Handled to avoid board lock-up. */ + else if (rxsr & RX_RUNT) { + /* Handled to avoid board lock-up. */ dev->stats.rx_length_errors++; if (el_debug > 5) printk(KERN_DEBUG " runt.\n"); - } - else if (rxsr & RX_GOOD) - { + } else if (rxsr & RX_GOOD) { /* * Receive worked. */ el_receive(dev); - } - else - { + } else { /* * Nothing? Something is broken! */ @@ -702,8 +691,7 @@ static void el_receive(struct net_device *dev) if (el_debug > 4) printk(KERN_DEBUG " el_receive %d.\n", pkt_len); - if ((pkt_len < 60) || (pkt_len > 1536)) - { + if (pkt_len < 60 || pkt_len > 1536) { if (el_debug) printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len); dev->stats.rx_over_errors++; @@ -722,26 +710,23 @@ static void el_receive(struct net_device *dev) */ outw(0x00, GP_LOW); - if (skb == NULL) - { + if (skb == NULL) { printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; return; - } - else - { - skb_reserve(skb,2); /* Force 16 byte alignment */ + } else { + skb_reserve(skb, 2); /* Force 16 byte alignment */ /* * The read increments through the bytes. The interrupt * handler will fix the pointer when it returns to * receive mode. */ - insb(DATAPORT, skb_put(skb,pkt_len), pkt_len); - skb->protocol=eth_type_trans(skb,dev); + insb(DATAPORT, skb_put(skb, pkt_len), pkt_len); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; dev->stats.rx_packets++; - dev->stats.rx_bytes+=pkt_len; + dev->stats.rx_bytes += pkt_len; } return; } @@ -760,7 +745,7 @@ static void el_reset(struct net_device *dev) struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; - if (el_debug> 2) + if (el_debug > 2) printk(KERN_INFO "3c501 reset..."); outb(AX_RESET, AX_CMD); /* Reset the chip */ outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */ @@ -794,7 +779,8 @@ static int el1_close(struct net_device *dev) int ioaddr = dev->base_addr; if (el_debug > 2) - printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr); + printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", + dev->name, ioaddr); netif_stop_queue(dev); @@ -822,18 +808,14 @@ static void set_multicast_list(struct net_device *dev) { int ioaddr = dev->base_addr; - if(dev->flags&IFF_PROMISC) - { + if (dev->flags & IFF_PROMISC) { outb(RX_PROM, RX_CMD); inb(RX_STATUS); - } - else if (dev->mc_list || dev->flags&IFF_ALLMULTI) - { - outb(RX_MULT, RX_CMD); /* Multicast or all multicast is the same */ + } else if (dev->mc_list || dev->flags & IFF_ALLMULTI) { + /* Multicast or all multicast is the same */ + outb(RX_MULT, RX_CMD); inb(RX_STATUS); /* Clear status. */ - } - else - { + } else { outb(RX_NORM, RX_CMD); inb(RX_STATUS); } diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 964d31ac9449..030c147211ba 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -747,7 +747,7 @@ static void init_82586_mem(struct net_device *dev) int boguscnt = 50; while (readw(shmem+iSCB_STATUS) == 0) if (--boguscnt == 0) { - printk("%s: i82586 initialization timed out with status %04x," + printk("%s: i82586 initialization timed out with status %04x, " "cmd %04x.\n", dev->name, readw(shmem+iSCB_STATUS), readw(shmem+iSCB_CMD)); break; @@ -832,10 +832,11 @@ static void el16_rx(struct net_device *dev) if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 || (pkt_len & 0xC000) != 0xC000) { - printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x" - "next %04x data-buf @%04x %04x.\n", dev->name, rx_head, - frame_status, rfd_cmd, next_rx_frame, data_buffer_addr, - pkt_len); + printk(KERN_ERR "%s: Rx frame at %#x corrupted, " + "status %04x cmd %04x next %04x " + "data-buf @%04x %04x.\n", + dev->name, rx_head, frame_status, rfd_cmd, + next_rx_frame, data_buffer_addr, pkt_len); } else if ((frame_status & 0x2000) == 0) { /* Frame Rxed, but with error. */ dev->stats.rx_errors++; @@ -851,7 +852,9 @@ static void el16_rx(struct net_device *dev) pkt_len &= 0x3fff; skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); + printk(KERN_ERR "%s: Memory squeeze, " + "dropping packet.\n", + dev->name); dev->stats.rx_dropped++; break; } diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 684bab781015..6ab84b661d70 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -1361,7 +1361,7 @@ static int boomerang_rx(struct net_device *dev) /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 4)) != 0) { + && (skb = dev_alloc_skb(pkt_len + 4)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 224e0bff1ae0..750a46f4bc58 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -277,8 +277,6 @@ static int lance_rx (struct net_device *dev) volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; unsigned char bits; - int len = 0; /* XXX shut up gcc warnings */ - struct sk_buff *skb = 0; /* XXX shut up gcc warnings */ #ifdef TEST_HITS int i; #endif @@ -318,10 +316,10 @@ static int lance_rx (struct net_device *dev) if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { - len = (rd->mblength & 0xfff) - 4; - skb = dev_alloc_skb (len+2); + int len = (rd->mblength & 0xfff) - 4; + struct sk_buff *skb = dev_alloc_skb (len+2); - if (skb == 0) { + if (!skb) { printk ("%s: Memory squeeze, deferring packet.\n", dev->name); dev->stats.rx_dropped++; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8f3f04d4f34b..389980f0e59e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -212,7 +212,7 @@ config MII config MACB tristate "Atmel MACB support" - depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 + depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91CAP9 select PHYLIB help The Atmel MACB ethernet interface is found on many AT32 and AT91 @@ -912,6 +912,24 @@ config DM9000 To compile this driver as a module, choose M here. The module will be called dm9000. +config ENC28J60 + tristate "ENC28J60 support" + depends on EXPERIMENTAL && SPI && NET_ETHERNET + select CRC32 + ---help--- + Support for the Microchip EN28J60 ethernet chip. + + To compile this driver as a module, choose M here and read + <file:Documentation/networking/net-modules.txt>. The module will be + called enc28j60. + +config ENC28J60_WRITEVERIFY + bool "Enable write verify" + depends on ENC28J60 + ---help--- + Enable the verify after the buffer write useful for debugging purpose. + If unsure, say N. + config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 @@ -1584,6 +1602,18 @@ config 8139_OLD_RX_RESET experience problems, you can enable this option to restore the old RX-reset behavior. If unsure, say N. +config R6040 + tristate "RDC R6040 Fast Ethernet Adapter support (EXPERIMENTAL)" + depends on NET_PCI && PCI + select CRC32 + select MII + help + This is a driver for the R6040 Fast Ethernet MACs found in the + the RDC R-321x System-on-chips. + + To compile this driver as a module, choose M here: the module + will be called r6040. This is recommended. + config SIS900 tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" depends on NET_PCI && PCI @@ -1785,7 +1815,7 @@ config DE620 config SGISEEQ tristate "SGI Seeq ethernet controller support" - depends on SGI_IP22 + depends on SGI_HAS_SEEQ help Say Y here if you have an Seeq based Ethernet network card. This is used in many Silicon Graphics machines. @@ -1979,6 +2009,9 @@ config E1000E To compile this driver as a module, choose M here. The module will be called e1000e. +config E1000E_ENABLED + def_bool E1000E != n + config IP1000 tristate "IP1000 Gigabit Ethernet support" depends on PCI && EXPERIMENTAL @@ -1989,6 +2022,28 @@ config IP1000 To compile this driver as a module, choose M here: the module will be called ipg. This is recommended. +config IGB + tristate "Intel(R) 82575 PCI-Express Gigabit Ethernet support" + depends on PCI + ---help--- + This driver supports Intel(R) 82575 gigabit ethernet family of + adapters. For more information on how to identify your adapter, go + to the Adapter & Driver ID Guide at: + + <http://support.intel.com/support/network/adapter/pro100/21397.htm> + + For general information and support, go to the Intel support + website at: + + <http://support.intel.com> + + More specific information on configuring the driver is in + <file:Documentation/networking/e1000.txt>. + + To compile this driver as a module, choose M here and read + <file:Documentation/networking/net-modules.txt>. The module + will be called igb. + source "drivers/net/ixp2000/Kconfig" config MYRI_SBUS @@ -2560,6 +2615,7 @@ config PASEMI_MAC tristate "PA Semi 1/10Gbit MAC" depends on PPC64 && PCI select PHYLIB + select INET_LRO help This driver supports the on-chip 1/10Gbit Ethernet controller on PA Semi's PWRficient line of chips. @@ -2585,6 +2641,16 @@ config TEHUTI help Tehuti Networks 10G Ethernet NIC +config BNX2X + tristate "Broadcom NetXtremeII 10Gb support" + depends on PCI + select ZLIB_INFLATE + help + This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards. + To compile this driver as a module, choose M here: the module + will be called bnx2x. This is recommended. + + endif # NETDEV_10000 source "drivers/net/tokenring/Kconfig" @@ -3015,23 +3081,6 @@ config NET_FC adaptor below. You also should have said Y to "SCSI support" and "SCSI generic support". -config SHAPER - tristate "Traffic Shaper (OBSOLETE)" - depends on EXPERIMENTAL - ---help--- - The traffic shaper is a virtual network device that allows you to - limit the rate of outgoing data flow over some other network device. - The traffic that you want to slow down can then be routed through - these virtual devices. See - <file:Documentation/networking/shaper.txt> for more information. - - An alternative to this traffic shaper are traffic schedulers which - you'll get if you say Y to "QoS and/or fair queuing" in - "Networking options". - - To compile this driver as a module, choose M here: the module - will be called shaper. If unsure, say N. - config NETCONSOLE tristate "Network console logging support (EXPERIMENTAL)" depends on EXPERIMENTAL diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 0e5fde4a1b2c..9fc7794e88ea 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -6,12 +6,14 @@ obj-$(CONFIG_E1000) += e1000/ obj-$(CONFIG_E1000E) += e1000e/ obj-$(CONFIG_IBM_EMAC) += ibm_emac/ obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ +obj-$(CONFIG_IGB) += igb/ obj-$(CONFIG_IXGBE) += ixgbe/ obj-$(CONFIG_IXGB) += ixgb/ obj-$(CONFIG_IP1000) += ipg.o obj-$(CONFIG_CHELSIO_T1) += chelsio/ obj-$(CONFIG_CHELSIO_T3) += cxgb3/ obj-$(CONFIG_EHEA) += ehea/ +obj-$(CONFIG_CAN) += can/ obj-$(CONFIG_BONDING) += bonding/ obj-$(CONFIG_ATL1) += atl1/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o @@ -54,6 +56,7 @@ obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o obj-$(CONFIG_SIS190) += sis190.o obj-$(CONFIG_SIS900) += sis900.o +obj-$(CONFIG_R6040) += r6040.o obj-$(CONFIG_YELLOWFIN) += yellowfin.o obj-$(CONFIG_ACENIC) += acenic.o obj-$(CONFIG_ISERIES_VETH) += iseries_veth.o @@ -63,6 +66,7 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o +obj-$(CONFIG_BNX2X) += bnx2x.o spidernet-y += spider_net.o spider_net_ethtool.o obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o obj-$(CONFIG_GELIC_NET) += ps3_gelic.o @@ -92,7 +96,6 @@ obj-$(CONFIG_NET_SB1000) += sb1000.o obj-$(CONFIG_MAC8390) += mac8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o -obj-$(CONFIG_SHAPER) += shaper.o obj-$(CONFIG_HP100) += hp100.o obj-$(CONFIG_SMC9194) += smc9194.o obj-$(CONFIG_FEC) += fec.o @@ -216,6 +219,7 @@ obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_FEC_8XX) += fec_8xx/ obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o obj-$(CONFIG_MLX4_CORE) += mlx4/ +obj-$(CONFIG_ENC28J60) += enc28j60.o obj-$(CONFIG_MACB) += macb.o diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 18f7f815f66e..6c5719ae8cca 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -269,8 +269,6 @@ static int lance_rx (struct net_device *dev) volatile struct lance_regs *ll = lp->ll; volatile struct lance_rx_desc *rd; unsigned char bits; - int len = 0; /* XXX shut up gcc warnings */ - struct sk_buff *skb = 0; /* XXX shut up gcc warnings */ #ifdef TEST_HITS int i; @@ -306,10 +304,10 @@ static int lance_rx (struct net_device *dev) if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++; if (bits & LE_R1_EOP) dev->stats.rx_errors++; } else { - len = (rd->mblength & 0xfff) - 4; - skb = dev_alloc_skb (len+2); + int len = (rd->mblength & 0xfff) - 4; + struct sk_buff *skb = dev_alloc_skb (len+2); - if (skb == 0) { + if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, " "deferring packet.\n", dev->name); dev->stats.rx_dropped++; @@ -477,7 +475,7 @@ static irqreturn_t lance_interrupt (int irq, void *dev_id) return IRQ_HANDLED; } -struct net_device *last_dev = 0; +struct net_device *last_dev; static int lance_open (struct net_device *dev) { diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index e7fdd81919bd..85f7276aaba5 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1945,13 +1945,13 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, err = pci_enable_device(pdev); if(err){ - printk(KERN_ERR "amd8111e: Cannot enable new PCI device," + printk(KERN_ERR "amd8111e: Cannot enable new PCI device, " "exiting.\n"); return err; } if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)){ - printk(KERN_ERR "amd8111e: Cannot find PCI base address" + printk(KERN_ERR "amd8111e: Cannot find PCI base address, " "exiting.\n"); err = -ENODEV; goto err_disable_pdev; diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index b032c1bf492f..24d81f922533 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -465,8 +465,9 @@ found: /* Snarf the interrupt vector now. */ ret = request_irq(irq, &net_interrupt, 0, DRV_NAME, dev); if (ret) { - printk (" AT1700 at %#3x is unusable due to a conflict on" - "IRQ %d.\n", ioaddr, irq); + printk(KERN_ERR "AT1700 at %#3x is unusable due to a " + "conflict on IRQ %d.\n", + ioaddr, irq); goto err_mca; } diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 3d247f3f4a3c..ea2a2b548e3c 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -128,6 +128,8 @@ static void b44_init_rings(struct b44 *); #define B44_FULL_RESET 1 #define B44_FULL_RESET_SKIP_PHY 2 #define B44_PARTIAL_RESET 3 +#define B44_CHIP_RESET_FULL 4 +#define B44_CHIP_RESET_PARTIAL 5 static void b44_init_hw(struct b44 *, int); @@ -1259,7 +1261,7 @@ static void b44_clear_stats(struct b44 *bp) } /* bp->lock is held. */ -static void b44_chip_reset(struct b44 *bp) +static void b44_chip_reset(struct b44 *bp, int reset_kind) { struct ssb_device *sdev = bp->sdev; @@ -1281,6 +1283,13 @@ static void b44_chip_reset(struct b44 *bp) ssb_device_enable(bp->sdev, 0); b44_clear_stats(bp); + /* + * Don't enable PHY if we are doing a partial reset + * we are probably going to power down + */ + if (reset_kind == B44_CHIP_RESET_PARTIAL) + return; + switch (sdev->bus->bustype) { case SSB_BUSTYPE_SSB: bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE | @@ -1316,7 +1325,14 @@ static void b44_chip_reset(struct b44 *bp) static void b44_halt(struct b44 *bp) { b44_disable_ints(bp); - b44_chip_reset(bp); + /* reset PHY */ + b44_phy_reset(bp); + /* power down PHY */ + printk(KERN_INFO PFX "%s: powering down PHY\n", bp->dev->name); + bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN); + /* now reset the chip, but without enabling the MAC&PHY + * part of it. This has to be done _after_ we shut down the PHY */ + b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL); } /* bp->lock is held. */ @@ -1365,7 +1381,7 @@ static void b44_init_hw(struct b44 *bp, int reset_kind) { u32 val; - b44_chip_reset(bp); + b44_chip_reset(bp, B44_CHIP_RESET_FULL); if (reset_kind == B44_FULL_RESET) { b44_phy_reset(bp); b44_setup_phy(bp); @@ -1422,7 +1438,7 @@ static int b44_open(struct net_device *dev) err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev); if (unlikely(err < 0)) { napi_disable(&bp->napi); - b44_chip_reset(bp); + b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL); b44_free_rings(bp); b44_free_consistent(bp); goto out; @@ -2060,11 +2076,11 @@ static int __devinit b44_get_invariants(struct b44 *bp) if (sdev->bus->bustype == SSB_BUSTYPE_SSB && instance > 1) { - addr = sdev->bus->sprom.r1.et1mac; - bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr; + addr = sdev->bus->sprom.et1mac; + bp->phy_addr = sdev->bus->sprom.et1phyaddr; } else { - addr = sdev->bus->sprom.r1.et0mac; - bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr; + addr = sdev->bus->sprom.et0mac; + bp->phy_addr = sdev->bus->sprom.et0phyaddr; } memcpy(bp->dev->dev_addr, addr, 6); @@ -2188,7 +2204,7 @@ static int __devinit b44_init_one(struct ssb_device *sdev, /* Chip reset provides power to the b44 MAC & PCI cores, which * is necessary for MAC register access. */ - b44_chip_reset(bp); + b44_chip_reset(bp, B44_CHIP_RESET_FULL); printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n", dev->name, print_mac(mac, dev->dev_addr)); @@ -2212,6 +2228,7 @@ static void __devexit b44_remove_one(struct ssb_device *sdev) unregister_netdev(dev); ssb_bus_may_powerdown(sdev->bus); free_netdev(dev); + ssb_pcihost_set_power_state(sdev, PCI_D3hot); ssb_set_drvdata(sdev, NULL); } @@ -2240,6 +2257,7 @@ static int b44_suspend(struct ssb_device *sdev, pm_message_t state) b44_setup_wol(bp); } + ssb_pcihost_set_power_state(sdev, PCI_D3hot); return 0; } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4e7b46e44874..34aebc6e7589 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1,6 +1,6 @@ /* bnx2.c: Broadcom NX2 network driver. * - * Copyright (c) 2004-2007 Broadcom Corporation + * Copyright (c) 2004-2008 Broadcom Corporation * * 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 @@ -52,12 +52,12 @@ #include "bnx2_fw.h" #include "bnx2_fw2.h" -#define FW_BUF_SIZE 0x8000 +#define FW_BUF_SIZE 0x10000 #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.9" -#define DRV_MODULE_RELDATE "December 8, 2007" +#define DRV_MODULE_VERSION "1.7.2" +#define DRV_MODULE_RELDATE "January 21, 2008" #define RUN_AT(x) (jiffies + (x)) @@ -226,7 +226,7 @@ static struct flash_spec flash_5709 = { MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); -static inline u32 bnx2_tx_avail(struct bnx2 *bp) +static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_napi *bnapi) { u32 diff; @@ -235,7 +235,7 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp) /* The ring uses 256 indices for 255 entries, one of them * needs to be skipped. */ - diff = bp->tx_prod - bp->tx_cons; + diff = bp->tx_prod - bnapi->tx_cons; if (unlikely(diff >= TX_DESC_CNT)) { diff &= 0xffff; if (diff == TX_DESC_CNT) @@ -296,7 +296,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) u32 val1; int i, ret; - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE); val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL; @@ -334,7 +334,7 @@ bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) ret = 0; } - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE); val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL; @@ -353,7 +353,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val) u32 val1; int i, ret; - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE); val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL; @@ -383,7 +383,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val) else ret = 0; - if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE); val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL; @@ -399,30 +399,65 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val) static void bnx2_disable_int(struct bnx2 *bp) { - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_MASK_INT); + int i; + struct bnx2_napi *bnapi; + + for (i = 0; i < bp->irq_nvecs; i++) { + bnapi = &bp->bnx2_napi[i]; + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | + BNX2_PCICFG_INT_ACK_CMD_MASK_INT); + } REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD); } static void bnx2_enable_int(struct bnx2 *bp) { - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx); + int i; + struct bnx2_napi *bnapi; - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); + for (i = 0; i < bp->irq_nvecs; i++) { + bnapi = &bp->bnx2_napi[i]; + + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + BNX2_PCICFG_INT_ACK_CMD_MASK_INT | + bnapi->last_status_idx); + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + bnapi->last_status_idx); + } REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW); } static void bnx2_disable_int_sync(struct bnx2 *bp) { + int i; + atomic_inc(&bp->intr_sem); bnx2_disable_int(bp); - synchronize_irq(bp->pdev->irq); + for (i = 0; i < bp->irq_nvecs; i++) + synchronize_irq(bp->irq_tbl[i].vector); +} + +static void +bnx2_napi_disable(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->irq_nvecs; i++) + napi_disable(&bp->bnx2_napi[i].napi); +} + +static void +bnx2_napi_enable(struct bnx2 *bp) +{ + int i; + + for (i = 0; i < bp->irq_nvecs; i++) + napi_enable(&bp->bnx2_napi[i].napi); } static void @@ -430,7 +465,7 @@ bnx2_netif_stop(struct bnx2 *bp) { bnx2_disable_int_sync(bp); if (netif_running(bp->dev)) { - napi_disable(&bp->napi); + bnx2_napi_disable(bp); netif_tx_disable(bp->dev); bp->dev->trans_start = jiffies; /* prevent tx timeout */ } @@ -442,7 +477,7 @@ bnx2_netif_start(struct bnx2 *bp) if (atomic_dec_and_test(&bp->intr_sem)) { if (netif_running(bp->dev)) { netif_wake_queue(bp->dev); - napi_enable(&bp->napi); + bnx2_napi_enable(bp); bnx2_enable_int(bp); } } @@ -468,8 +503,7 @@ bnx2_free_mem(struct bnx2 *bp) bp->stats_blk = NULL; } if (bp->tx_desc_ring) { - pci_free_consistent(bp->pdev, - sizeof(struct tx_bd) * TX_DESC_CNT, + pci_free_consistent(bp->pdev, TXBD_RING_SIZE, bp->tx_desc_ring, bp->tx_desc_mapping); bp->tx_desc_ring = NULL; } @@ -477,14 +511,23 @@ bnx2_free_mem(struct bnx2 *bp) bp->tx_buf_ring = NULL; for (i = 0; i < bp->rx_max_ring; i++) { if (bp->rx_desc_ring[i]) - pci_free_consistent(bp->pdev, - sizeof(struct rx_bd) * RX_DESC_CNT, + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, bp->rx_desc_ring[i], bp->rx_desc_mapping[i]); bp->rx_desc_ring[i] = NULL; } vfree(bp->rx_buf_ring); bp->rx_buf_ring = NULL; + for (i = 0; i < bp->rx_max_pg_ring; i++) { + if (bp->rx_pg_desc_ring[i]) + pci_free_consistent(bp->pdev, RXBD_RING_SIZE, + bp->rx_pg_desc_ring[i], + bp->rx_pg_desc_mapping[i]); + bp->rx_pg_desc_ring[i] = NULL; + } + if (bp->rx_pg_ring) + vfree(bp->rx_pg_ring); + bp->rx_pg_ring = NULL; } static int @@ -492,38 +535,54 @@ bnx2_alloc_mem(struct bnx2 *bp) { int i, status_blk_size; - bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT, - GFP_KERNEL); + bp->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL); if (bp->tx_buf_ring == NULL) return -ENOMEM; - bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, - sizeof(struct tx_bd) * - TX_DESC_CNT, + bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, TXBD_RING_SIZE, &bp->tx_desc_mapping); if (bp->tx_desc_ring == NULL) goto alloc_mem_err; - bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT * - bp->rx_max_ring); + bp->rx_buf_ring = vmalloc(SW_RXBD_RING_SIZE * bp->rx_max_ring); if (bp->rx_buf_ring == NULL) goto alloc_mem_err; - memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT * - bp->rx_max_ring); + memset(bp->rx_buf_ring, 0, SW_RXBD_RING_SIZE * bp->rx_max_ring); for (i = 0; i < bp->rx_max_ring; i++) { bp->rx_desc_ring[i] = - pci_alloc_consistent(bp->pdev, - sizeof(struct rx_bd) * RX_DESC_CNT, + pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, &bp->rx_desc_mapping[i]); if (bp->rx_desc_ring[i] == NULL) goto alloc_mem_err; } + if (bp->rx_pg_ring_size) { + bp->rx_pg_ring = vmalloc(SW_RXPG_RING_SIZE * + bp->rx_max_pg_ring); + if (bp->rx_pg_ring == NULL) + goto alloc_mem_err; + + memset(bp->rx_pg_ring, 0, SW_RXPG_RING_SIZE * + bp->rx_max_pg_ring); + } + + for (i = 0; i < bp->rx_max_pg_ring; i++) { + bp->rx_pg_desc_ring[i] = + pci_alloc_consistent(bp->pdev, RXBD_RING_SIZE, + &bp->rx_pg_desc_mapping[i]); + if (bp->rx_pg_desc_ring[i] == NULL) + goto alloc_mem_err; + + } + /* Combine status and statistics blocks into one allocation. */ status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); + if (bp->flags & BNX2_FLAG_MSIX_CAP) + status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC * + BNX2_SBLK_MSIX_ALIGN_SIZE); bp->status_stats_size = status_blk_size + sizeof(struct statistics_block); @@ -534,6 +593,18 @@ bnx2_alloc_mem(struct bnx2 *bp) memset(bp->status_blk, 0, bp->status_stats_size); + bp->bnx2_napi[0].status_blk = bp->status_blk; + if (bp->flags & BNX2_FLAG_MSIX_CAP) { + for (i = 1; i < BNX2_MAX_MSIX_VEC; i++) { + struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; + + bnapi->status_blk_msix = (void *) + ((unsigned long) bp->status_blk + + BNX2_SBLK_MSIX_ALIGN_SIZE * i); + bnapi->int_num = i << 24; + } + } + bp->stats_blk = (void *) ((unsigned long) bp->status_blk + status_blk_size); @@ -563,7 +634,7 @@ bnx2_report_fw_link(struct bnx2 *bp) { u32 fw_link_status = 0; - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return; if (bp->link_up) { @@ -605,7 +676,7 @@ bnx2_report_fw_link(struct bnx2 *bp) bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); if (!(bmsr & BMSR_ANEGCOMPLETE) || - bp->phy_flags & PHY_PARALLEL_DETECT_FLAG) + bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET; else fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE; @@ -621,7 +692,7 @@ static char * bnx2_xceiver_str(struct bnx2 *bp) { return ((bp->phy_port == PORT_FIBRE) ? "SerDes" : - ((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" : + ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" : "Copper")); } @@ -681,7 +752,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) return; } - if ((bp->phy_flags & PHY_SERDES_FLAG) && + if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && (CHIP_NUM(bp) == CHIP_NUM_5708)) { u32 val; @@ -696,7 +767,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp) bnx2_read_phy(bp, bp->mii_adv, &local_adv); bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { u32 new_local_adv = 0; u32 new_remote_adv = 0; @@ -979,7 +1050,7 @@ bnx2_set_mac_link(struct bnx2 *bp) static void bnx2_enable_bmsr1(struct bnx2 *bp) { - if ((bp->phy_flags & PHY_SERDES_FLAG) && + if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && (CHIP_NUM(bp) == CHIP_NUM_5709)) bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS); @@ -988,7 +1059,7 @@ bnx2_enable_bmsr1(struct bnx2 *bp) static void bnx2_disable_bmsr1(struct bnx2 *bp) { - if ((bp->phy_flags & PHY_SERDES_FLAG) && + if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && (CHIP_NUM(bp) == CHIP_NUM_5709)) bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); @@ -1000,7 +1071,7 @@ bnx2_test_and_enable_2g5(struct bnx2 *bp) u32 up1; int ret = 1; - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) return 0; if (bp->autoneg & AUTONEG_SPEED) @@ -1029,7 +1100,7 @@ bnx2_test_and_disable_2g5(struct bnx2 *bp) u32 up1; int ret = 0; - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) return 0; if (CHIP_NUM(bp) == CHIP_NUM_5709) @@ -1054,7 +1125,7 @@ bnx2_enable_forced_2g5(struct bnx2 *bp) { u32 bmcr; - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) return; if (CHIP_NUM(bp) == CHIP_NUM_5709) { @@ -1089,7 +1160,7 @@ bnx2_disable_forced_2g5(struct bnx2 *bp) { u32 bmcr; - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) return; if (CHIP_NUM(bp) == CHIP_NUM_5709) { @@ -1115,6 +1186,19 @@ bnx2_disable_forced_2g5(struct bnx2 *bp) bnx2_write_phy(bp, bp->mii_bmcr, bmcr); } +static void +bnx2_5706s_force_link_dn(struct bnx2 *bp, int start) +{ + u32 val; + + bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL); + bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val); + if (start) + bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f); + else + bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0); +} + static int bnx2_set_link(struct bnx2 *bp) { @@ -1126,7 +1210,7 @@ bnx2_set_link(struct bnx2 *bp) return 0; } - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return 0; link_up = bp->link_up; @@ -1136,10 +1220,14 @@ bnx2_set_link(struct bnx2 *bp) bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); bnx2_disable_bmsr1(bp); - if ((bp->phy_flags & PHY_SERDES_FLAG) && + if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && (CHIP_NUM(bp) == CHIP_NUM_5706)) { u32 val; + if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) { + bnx2_5706s_force_link_dn(bp, 0); + bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN; + } val = REG_RD(bp, BNX2_EMAC_STATUS); if (val & BNX2_EMAC_STATUS_LINK) bmsr |= BMSR_LSTATUS; @@ -1150,7 +1238,7 @@ bnx2_set_link(struct bnx2 *bp) if (bmsr & BMSR_LSTATUS) { bp->link_up = 1; - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { if (CHIP_NUM(bp) == CHIP_NUM_5706) bnx2_5706s_linkup(bp); else if (CHIP_NUM(bp) == CHIP_NUM_5708) @@ -1164,11 +1252,19 @@ bnx2_set_link(struct bnx2 *bp) bnx2_resolve_flow_ctrl(bp); } else { - if ((bp->phy_flags & PHY_SERDES_FLAG) && + if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && (bp->autoneg & AUTONEG_SPEED)) bnx2_disable_forced_2g5(bp); - bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; + if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) { + u32 bmcr; + + bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); + bmcr |= BMCR_ANENABLE; + bnx2_write_phy(bp, bp->mii_bmcr, bmcr); + + bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; + } bp->link_up = 0; } @@ -1213,7 +1309,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) == (FLOW_CTRL_RX | FLOW_CTRL_TX)) { - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { adv = ADVERTISE_1000XPAUSE; } else { @@ -1221,7 +1317,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) } } else if (bp->req_flow_ctrl & FLOW_CTRL_TX) { - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { adv = ADVERTISE_1000XPSE_ASYM; } else { @@ -1229,7 +1325,7 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp) } } else if (bp->req_flow_ctrl & FLOW_CTRL_RX) { - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; } else { @@ -1304,7 +1400,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port) u32 adv, bmcr; u32 new_adv = 0; - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return (bnx2_setup_remote_phy(bp, port)); if (!(bp->autoneg & AUTONEG_SPEED)) { @@ -1414,7 +1510,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port) } #define ETHTOOL_ALL_FIBRE_SPEED \ - (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ? \ + (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \ (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\ (ADVERTISED_1000baseT_Full) @@ -1478,12 +1574,12 @@ bnx2_set_default_remote_link(struct bnx2 *bp) static void bnx2_set_default_link(struct bnx2 *bp) { - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return bnx2_set_default_remote_link(bp); bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL; bp->req_line_speed = 0; - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { u32 reg; bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg; @@ -1713,7 +1809,7 @@ bnx2_setup_phy(struct bnx2 *bp, u8 port) if (bp->loopback == MAC_LOOPBACK) return 0; - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { return (bnx2_setup_serdes_phy(bp, port)); } else { @@ -1748,7 +1844,7 @@ bnx2_init_5709s_phy(struct bnx2 *bp) bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val); - if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) val |= BCM5708S_UP1_2G5; else val &= ~BCM5708S_UP1_2G5; @@ -1791,7 +1887,7 @@ bnx2_init_5708s_phy(struct bnx2 *bp) val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN; bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val); - if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) { bnx2_read_phy(bp, BCM5708S_UP1, &val); val |= BCM5708S_UP1_2G5; bnx2_write_phy(bp, BCM5708S_UP1, val); @@ -1833,7 +1929,7 @@ bnx2_init_5706s_phy(struct bnx2 *bp) { bnx2_reset_phy(bp); - bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; + bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; if (CHIP_NUM(bp) == CHIP_NUM_5706) REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300); @@ -1872,7 +1968,7 @@ bnx2_init_copper_phy(struct bnx2 *bp) bnx2_reset_phy(bp); - if (bp->phy_flags & PHY_CRC_FIX_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) { bnx2_write_phy(bp, 0x18, 0x0c00); bnx2_write_phy(bp, 0x17, 0x000a); bnx2_write_phy(bp, 0x15, 0x310b); @@ -1883,7 +1979,7 @@ bnx2_init_copper_phy(struct bnx2 *bp) bnx2_write_phy(bp, 0x18, 0x0400); } - if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) { bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_BNX2_DSP_EXPAND_REG | 0x8); bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val); @@ -1923,8 +2019,8 @@ bnx2_init_phy(struct bnx2 *bp) u32 val; int rc = 0; - bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG; - bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG; + bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK; + bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY; bp->mii_bmcr = MII_BMCR; bp->mii_bmsr = MII_BMSR; @@ -1934,7 +2030,7 @@ bnx2_init_phy(struct bnx2 *bp) REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK); - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) goto setup_phy; bnx2_read_phy(bp, MII_PHYSID1, &val); @@ -1942,7 +2038,7 @@ bnx2_init_phy(struct bnx2 *bp) bnx2_read_phy(bp, MII_PHYSID2, &val); bp->phy_id |= val & 0xffff; - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { if (CHIP_NUM(bp) == CHIP_NUM_5706) rc = bnx2_init_5706s_phy(bp); else if (CHIP_NUM(bp) == CHIP_NUM_5708) @@ -2125,15 +2221,12 @@ bnx2_init_context(struct bnx2 *bp) vcid_addr += (i << PHY_CTX_SHIFT); pcid_addr += (i << PHY_CTX_SHIFT); - REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00); + REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr); REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); /* Zero out the context. */ for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) - CTX_WR(bp, 0x00, offset, 0); - - REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr); - REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); + CTX_WR(bp, vcid_addr, offset, 0); } } } @@ -2206,7 +2299,43 @@ bnx2_set_mac_addr(struct bnx2 *bp) } static inline int -bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) +bnx2_alloc_rx_page(struct bnx2 *bp, u16 index) +{ + dma_addr_t mapping; + struct sw_pg *rx_pg = &bp->rx_pg_ring[index]; + struct rx_bd *rxbd = + &bp->rx_pg_desc_ring[RX_RING(index)][RX_IDX(index)]; + struct page *page = alloc_page(GFP_ATOMIC); + + if (!page) + return -ENOMEM; + mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + rx_pg->page = page; + pci_unmap_addr_set(rx_pg, mapping, mapping); + rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; + rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff; + return 0; +} + +static void +bnx2_free_rx_page(struct bnx2 *bp, u16 index) +{ + struct sw_pg *rx_pg = &bp->rx_pg_ring[index]; + struct page *page = rx_pg->page; + + if (!page) + return; + + pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), PAGE_SIZE, + PCI_DMA_FROMDEVICE); + + __free_page(page); + rx_pg->page = NULL; +} + +static inline int +bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, u16 index) { struct sk_buff *skb; struct sw_bd *rx_buf = &bp->rx_buf_ring[index]; @@ -2231,15 +2360,15 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff; - bp->rx_prod_bseq += bp->rx_buf_use_size; + bnapi->rx_prod_bseq += bp->rx_buf_use_size; return 0; } static int -bnx2_phy_event_is_set(struct bnx2 *bp, u32 event) +bnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event) { - struct status_block *sblk = bp->status_blk; + struct status_block *sblk = bnapi->status_blk; u32 new_link_state, old_link_state; int is_set = 1; @@ -2257,30 +2386,41 @@ bnx2_phy_event_is_set(struct bnx2 *bp, u32 event) } static void -bnx2_phy_int(struct bnx2 *bp) +bnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi) { - if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) { + if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE)) { spin_lock(&bp->phy_lock); bnx2_set_link(bp); spin_unlock(&bp->phy_lock); } - if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_TIMER_ABORT)) + if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT)) bnx2_set_remote_link(bp); } -static void -bnx2_tx_int(struct bnx2 *bp) +static inline u16 +bnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) +{ + u16 cons; + + if (bnapi->int_num == 0) + cons = bnapi->status_blk->status_tx_quick_consumer_index0; + else + cons = bnapi->status_blk_msix->status_tx_quick_consumer_index; + + if (unlikely((cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT)) + cons++; + return cons; +} + +static int +bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) { - struct status_block *sblk = bp->status_blk; u16 hw_cons, sw_cons, sw_ring_cons; - int tx_free_bd = 0; + int tx_pkt = 0; - hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0; - if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { - hw_cons++; - } - sw_cons = bp->tx_cons; + hw_cons = bnx2_get_hw_tx_cons(bnapi); + sw_cons = bnapi->tx_cons; while (sw_cons != hw_cons) { struct sw_bd *tx_buf; @@ -2327,19 +2467,16 @@ bnx2_tx_int(struct bnx2 *bp) sw_cons = NEXT_TX_BD(sw_cons); - tx_free_bd += last + 1; - dev_kfree_skb(skb); + tx_pkt++; + if (tx_pkt == budget) + break; - hw_cons = bp->hw_tx_cons = - sblk->status_tx_quick_consumer_index0; - - if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { - hw_cons++; - } + hw_cons = bnx2_get_hw_tx_cons(bnapi); } - bp->tx_cons = sw_cons; + bnapi->hw_tx_cons = hw_cons; + bnapi->tx_cons = sw_cons; /* Need to make the tx_cons update visible to bnx2_start_xmit() * before checking for netif_queue_stopped(). Without the * memory barrier, there is a small possibility that bnx2_start_xmit() @@ -2348,17 +2485,68 @@ bnx2_tx_int(struct bnx2 *bp) smp_mb(); if (unlikely(netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) { + (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) { netif_tx_lock(bp->dev); if ((netif_queue_stopped(bp->dev)) && - (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) + (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh)) netif_wake_queue(bp->dev); netif_tx_unlock(bp->dev); } + return tx_pkt; +} + +static void +bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_napi *bnapi, + struct sk_buff *skb, int count) +{ + struct sw_pg *cons_rx_pg, *prod_rx_pg; + struct rx_bd *cons_bd, *prod_bd; + dma_addr_t mapping; + int i; + u16 hw_prod = bnapi->rx_pg_prod, prod; + u16 cons = bnapi->rx_pg_cons; + + for (i = 0; i < count; i++) { + prod = RX_PG_RING_IDX(hw_prod); + + prod_rx_pg = &bp->rx_pg_ring[prod]; + cons_rx_pg = &bp->rx_pg_ring[cons]; + cons_bd = &bp->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &bp->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)]; + + if (i == 0 && skb) { + struct page *page; + struct skb_shared_info *shinfo; + + shinfo = skb_shinfo(skb); + shinfo->nr_frags--; + page = shinfo->frags[shinfo->nr_frags].page; + shinfo->frags[shinfo->nr_frags].page = NULL; + mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + cons_rx_pg->page = page; + pci_unmap_addr_set(cons_rx_pg, mapping, mapping); + dev_kfree_skb(skb); + } + if (prod != cons) { + prod_rx_pg->page = cons_rx_pg->page; + cons_rx_pg->page = NULL; + pci_unmap_addr_set(prod_rx_pg, mapping, + pci_unmap_addr(cons_rx_pg, mapping)); + + prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; + prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; + + } + cons = RX_PG_RING_IDX(NEXT_RX_BD(cons)); + hw_prod = NEXT_RX_BD(hw_prod); + } + bnapi->rx_pg_prod = hw_prod; + bnapi->rx_pg_cons = cons; } static inline void -bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, +bnx2_reuse_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, u16 cons, u16 prod) { struct sw_bd *cons_rx_buf, *prod_rx_buf; @@ -2371,7 +2559,7 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, pci_unmap_addr(cons_rx_buf, mapping), bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); - bp->rx_prod_bseq += bp->rx_buf_use_size; + bnapi->rx_prod_bseq += bp->rx_buf_use_size; prod_rx_buf->skb = skb; @@ -2387,10 +2575,102 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; } +static int +bnx2_rx_skb(struct bnx2 *bp, struct bnx2_napi *bnapi, struct sk_buff *skb, + unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr, + u32 ring_idx) +{ + int err; + u16 prod = ring_idx & 0xffff; + + err = bnx2_alloc_rx_skb(bp, bnapi, prod); + if (unlikely(err)) { + bnx2_reuse_rx_skb(bp, bnapi, skb, (u16) (ring_idx >> 16), prod); + if (hdr_len) { + unsigned int raw_len = len + 4; + int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT; + + bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, pages); + } + return err; + } + + skb_reserve(skb, bp->rx_offset); + pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + + if (hdr_len == 0) { + skb_put(skb, len); + return 0; + } else { + unsigned int i, frag_len, frag_size, pages; + struct sw_pg *rx_pg; + u16 pg_cons = bnapi->rx_pg_cons; + u16 pg_prod = bnapi->rx_pg_prod; + + frag_size = len + 4 - hdr_len; + pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT; + skb_put(skb, hdr_len); + + for (i = 0; i < pages; i++) { + frag_len = min(frag_size, (unsigned int) PAGE_SIZE); + if (unlikely(frag_len <= 4)) { + unsigned int tail = 4 - frag_len; + + bnapi->rx_pg_cons = pg_cons; + bnapi->rx_pg_prod = pg_prod; + bnx2_reuse_rx_skb_pages(bp, bnapi, NULL, + pages - i); + skb->len -= tail; + if (i == 0) { + skb->tail -= tail; + } else { + skb_frag_t *frag = + &skb_shinfo(skb)->frags[i - 1]; + frag->size -= tail; + skb->data_len -= tail; + skb->truesize -= tail; + } + return 0; + } + rx_pg = &bp->rx_pg_ring[pg_cons]; + + pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping), + PAGE_SIZE, PCI_DMA_FROMDEVICE); + + if (i == pages - 1) + frag_len -= 4; + + skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len); + rx_pg->page = NULL; + + err = bnx2_alloc_rx_page(bp, RX_PG_RING_IDX(pg_prod)); + if (unlikely(err)) { + bnapi->rx_pg_cons = pg_cons; + bnapi->rx_pg_prod = pg_prod; + bnx2_reuse_rx_skb_pages(bp, bnapi, skb, + pages - i); + return err; + } + + frag_size -= frag_len; + skb->data_len += frag_len; + skb->truesize += frag_len; + skb->len += frag_len; + + pg_prod = NEXT_RX_BD(pg_prod); + pg_cons = RX_PG_RING_IDX(NEXT_RX_BD(pg_cons)); + } + bnapi->rx_pg_prod = pg_prod; + bnapi->rx_pg_cons = pg_cons; + } + return 0; +} + static inline u16 -bnx2_get_hw_rx_cons(struct bnx2 *bp) +bnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) { - u16 cons = bp->status_blk->status_rx_quick_consumer_index0; + u16 cons = bnapi->status_blk->status_rx_quick_consumer_index0; if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)) cons++; @@ -2398,22 +2678,22 @@ bnx2_get_hw_rx_cons(struct bnx2 *bp) } static int -bnx2_rx_int(struct bnx2 *bp, int budget) +bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) { u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; struct l2_fhdr *rx_hdr; - int rx_pkt = 0; + int rx_pkt = 0, pg_ring_used = 0; - hw_cons = bnx2_get_hw_rx_cons(bp); - sw_cons = bp->rx_cons; - sw_prod = bp->rx_prod; + hw_cons = bnx2_get_hw_rx_cons(bnapi); + sw_cons = bnapi->rx_cons; + sw_prod = bnapi->rx_prod; /* Memory barrier necessary as speculative reads of the rx * buffer can be ahead of the index in the status block */ rmb(); while (sw_cons != hw_cons) { - unsigned int len; + unsigned int len, hdr_len; u32 status; struct sw_bd *rx_buf; struct sk_buff *skb; @@ -2433,7 +2713,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget) bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); rx_hdr = (struct l2_fhdr *) skb->data; - len = rx_hdr->l2_fhdr_pkt_len - 4; + len = rx_hdr->l2_fhdr_pkt_len; if ((status = rx_hdr->l2_fhdr_status) & (L2_FHDR_ERRORS_BAD_CRC | @@ -2442,18 +2722,30 @@ bnx2_rx_int(struct bnx2 *bp, int budget) L2_FHDR_ERRORS_TOO_SHORT | L2_FHDR_ERRORS_GIANT_FRAME)) { - goto reuse_rx; + bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, + sw_ring_prod); + goto next_rx; + } + hdr_len = 0; + if (status & L2_FHDR_STATUS_SPLIT) { + hdr_len = rx_hdr->l2_fhdr_ip_xsum; + pg_ring_used = 1; + } else if (len > bp->rx_jumbo_thresh) { + hdr_len = bp->rx_jumbo_thresh; + pg_ring_used = 1; } - /* Since we don't have a jumbo ring, copy small packets - * if mtu > 1500 - */ - if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) { + len -= 4; + + if (len <= bp->rx_copy_thresh) { struct sk_buff *new_skb; new_skb = netdev_alloc_skb(bp->dev, len + 2); - if (new_skb == NULL) - goto reuse_rx; + if (new_skb == NULL) { + bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, + sw_ring_prod); + goto next_rx; + } /* aligned copy */ skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2, @@ -2461,24 +2753,13 @@ bnx2_rx_int(struct bnx2 *bp, int budget) skb_reserve(new_skb, 2); skb_put(new_skb, len); - bnx2_reuse_rx_skb(bp, skb, + bnx2_reuse_rx_skb(bp, bnapi, skb, sw_ring_cons, sw_ring_prod); skb = new_skb; - } - else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) { - pci_unmap_single(bp->pdev, dma_addr, - bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); - - skb_reserve(skb, bp->rx_offset); - skb_put(skb, len); - } - else { -reuse_rx: - bnx2_reuse_rx_skb(bp, skb, - sw_ring_cons, sw_ring_prod); + } else if (unlikely(bnx2_rx_skb(bp, bnapi, skb, len, hdr_len, + dma_addr, (sw_ring_cons << 16) | sw_ring_prod))) goto next_rx; - } skb->protocol = eth_type_trans(skb, bp->dev); @@ -2501,7 +2782,7 @@ reuse_rx: } #ifdef BCM_VLAN - if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) { + if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && bp->vlgrp) { vlan_hwaccel_receive_skb(skb, bp->vlgrp, rx_hdr->l2_fhdr_vlan_tag); } @@ -2521,16 +2802,20 @@ next_rx: /* Refresh hw_cons to see if there is new work */ if (sw_cons == hw_cons) { - hw_cons = bnx2_get_hw_rx_cons(bp); + hw_cons = bnx2_get_hw_rx_cons(bnapi); rmb(); } } - bp->rx_cons = sw_cons; - bp->rx_prod = sw_prod; + bnapi->rx_cons = sw_cons; + bnapi->rx_prod = sw_prod; + + if (pg_ring_used) + REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX, + bnapi->rx_pg_prod); REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod); - REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq); + REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq); mmiowb(); @@ -2546,8 +2831,9 @@ bnx2_msi(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct bnx2 *bp = netdev_priv(dev); + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; - prefetch(bp->status_blk); + prefetch(bnapi->status_blk); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | BNX2_PCICFG_INT_ACK_CMD_MASK_INT); @@ -2556,7 +2842,7 @@ bnx2_msi(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev, &bp->napi); + netif_rx_schedule(dev, &bnapi->napi); return IRQ_HANDLED; } @@ -2566,14 +2852,15 @@ bnx2_msi_1shot(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct bnx2 *bp = netdev_priv(dev); + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; - prefetch(bp->status_blk); + prefetch(bnapi->status_blk); /* Return here if interrupt is disabled. */ if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev, &bp->napi); + netif_rx_schedule(dev, &bnapi->napi); return IRQ_HANDLED; } @@ -2583,7 +2870,8 @@ bnx2_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; struct bnx2 *bp = netdev_priv(dev); - struct status_block *sblk = bp->status_blk; + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + struct status_block *sblk = bnapi->status_blk; /* When using INTx, it is possible for the interrupt to arrive * at the CPU before the status block posted prior to the @@ -2591,7 +2879,7 @@ bnx2_interrupt(int irq, void *dev_instance) * When using MSI, the MSI message will always complete after * the status block write. */ - if ((sblk->status_idx == bp->last_status_idx) && + if ((sblk->status_idx == bnapi->last_status_idx) && (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) & BNX2_PCICFG_MISC_STATUS_INTA_VALUE)) return IRQ_NONE; @@ -2609,24 +2897,41 @@ bnx2_interrupt(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - if (netif_rx_schedule_prep(dev, &bp->napi)) { - bp->last_status_idx = sblk->status_idx; - __netif_rx_schedule(dev, &bp->napi); + if (netif_rx_schedule_prep(dev, &bnapi->napi)) { + bnapi->last_status_idx = sblk->status_idx; + __netif_rx_schedule(dev, &bnapi->napi); } return IRQ_HANDLED; } +static irqreturn_t +bnx2_tx_msix(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct bnx2 *bp = netdev_priv(dev); + struct bnx2_napi *bnapi = &bp->bnx2_napi[BNX2_TX_VEC]; + + prefetch(bnapi->status_blk_msix); + + /* Return here if interrupt is disabled. */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) + return IRQ_HANDLED; + + netif_rx_schedule(dev, &bnapi->napi); + return IRQ_HANDLED; +} + #define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ STATUS_ATTN_BITS_TIMER_ABORT) static inline int -bnx2_has_work(struct bnx2 *bp) +bnx2_has_work(struct bnx2_napi *bnapi) { - struct status_block *sblk = bp->status_blk; + struct status_block *sblk = bnapi->status_blk; - if ((bnx2_get_hw_rx_cons(bp) != bp->rx_cons) || - (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)) + if ((bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) || + (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons)) return 1; if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != @@ -2636,16 +2941,40 @@ bnx2_has_work(struct bnx2 *bp) return 0; } -static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) +static int bnx2_tx_poll(struct napi_struct *napi, int budget) +{ + struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); + struct bnx2 *bp = bnapi->bp; + int work_done = 0; + struct status_block_msix *sblk = bnapi->status_blk_msix; + + do { + work_done += bnx2_tx_int(bp, bnapi, budget - work_done); + if (unlikely(work_done >= budget)) + return work_done; + + bnapi->last_status_idx = sblk->status_idx; + rmb(); + } while (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons); + + netif_rx_complete(bp->dev, napi); + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | + bnapi->last_status_idx); + return work_done; +} + +static int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, + int work_done, int budget) { - struct status_block *sblk = bp->status_blk; + struct status_block *sblk = bnapi->status_blk; u32 status_attn_bits = sblk->status_attn_bits; u32 status_attn_bits_ack = sblk->status_attn_bits_ack; if ((status_attn_bits & STATUS_ATTN_EVENTS) != (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { - bnx2_phy_int(bp); + bnx2_phy_int(bp, bnapi); /* This is needed to take care of transient status * during link changes. @@ -2655,49 +2984,50 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) REG_RD(bp, BNX2_HC_COMMAND); } - if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) - bnx2_tx_int(bp); + if (bnx2_get_hw_tx_cons(bnapi) != bnapi->hw_tx_cons) + bnx2_tx_int(bp, bnapi, 0); - if (bnx2_get_hw_rx_cons(bp) != bp->rx_cons) - work_done += bnx2_rx_int(bp, budget - work_done); + if (bnx2_get_hw_rx_cons(bnapi) != bnapi->rx_cons) + work_done += bnx2_rx_int(bp, bnapi, budget - work_done); return work_done; } static int bnx2_poll(struct napi_struct *napi, int budget) { - struct bnx2 *bp = container_of(napi, struct bnx2, napi); + struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); + struct bnx2 *bp = bnapi->bp; int work_done = 0; - struct status_block *sblk = bp->status_blk; + struct status_block *sblk = bnapi->status_blk; while (1) { - work_done = bnx2_poll_work(bp, work_done, budget); + work_done = bnx2_poll_work(bp, bnapi, work_done, budget); if (unlikely(work_done >= budget)) break; - /* bp->last_status_idx is used below to tell the hw how + /* bnapi->last_status_idx is used below to tell the hw how * much work has been processed, so we must read it before * checking for more work. */ - bp->last_status_idx = sblk->status_idx; + bnapi->last_status_idx = sblk->status_idx; rmb(); - if (likely(!bnx2_has_work(bp))) { + if (likely(!bnx2_has_work(bnapi))) { netif_rx_complete(bp->dev, napi); - if (likely(bp->flags & USING_MSI_FLAG)) { + if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - bp->last_status_idx); + bnapi->last_status_idx); break; } REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | BNX2_PCICFG_INT_ACK_CMD_MASK_INT | - bp->last_status_idx); + bnapi->last_status_idx); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | - bp->last_status_idx); + bnapi->last_status_idx); break; } } @@ -2721,10 +3051,10 @@ bnx2_set_rx_mode(struct net_device *dev) BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG); sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN; #ifdef BCM_VLAN - if (!bp->vlgrp && !(bp->flags & ASF_ENABLE_FLAG)) + if (!bp->vlgrp && !(bp->flags & BNX2_FLAG_ASF_ENABLE)) rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG; #else - if (!(bp->flags & ASF_ENABLE_FLAG)) + if (!(bp->flags & BNX2_FLAG_ASF_ENABLE)) rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG; #endif if (dev->flags & IFF_PROMISC) { @@ -2781,7 +3111,7 @@ bnx2_set_rx_mode(struct net_device *dev) } static void -load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, +load_rv2p_fw(struct bnx2 *bp, __le32 *rv2p_code, u32 rv2p_code_len, u32 rv2p_proc) { int i; @@ -2789,9 +3119,9 @@ load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len, for (i = 0; i < rv2p_code_len; i += 8) { - REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code)); + REG_WR(bp, BNX2_RV2P_INSTR_HIGH, le32_to_cpu(*rv2p_code)); rv2p_code++; - REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code)); + REG_WR(bp, BNX2_RV2P_INSTR_LOW, le32_to_cpu(*rv2p_code)); rv2p_code++; if (rv2p_proc == RV2P_PROC1) { @@ -2837,7 +3167,7 @@ load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw) return rc; for (j = 0; j < (fw->text_len / 4); j++, offset += 4) { - REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j])); + REG_WR_IND(bp, offset, le32_to_cpu(fw->text[j])); } } @@ -2900,20 +3230,34 @@ bnx2_init_cpus(struct bnx2 *bp) { struct cpu_reg cpu_reg; struct fw_info *fw; - int rc; - void *text; + int rc, rv2p_len; + void *text, *rv2p; /* Initialize the RV2P processor. */ text = vmalloc(FW_BUF_SIZE); if (!text) return -ENOMEM; - rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1)); + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + rv2p = bnx2_xi_rv2p_proc1; + rv2p_len = sizeof(bnx2_xi_rv2p_proc1); + } else { + rv2p = bnx2_rv2p_proc1; + rv2p_len = sizeof(bnx2_rv2p_proc1); + } + rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len); if (rc < 0) goto init_cpu_err; load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1); - rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2)); + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + rv2p = bnx2_xi_rv2p_proc2; + rv2p_len = sizeof(bnx2_xi_rv2p_proc2); + } else { + rv2p = bnx2_rv2p_proc2; + rv2p_len = sizeof(bnx2_rv2p_proc2); + } + rc = zlib_inflate_blob(text, FW_BUF_SIZE, rv2p, rv2p_len); if (rc < 0) goto init_cpu_err; @@ -3029,14 +3373,14 @@ bnx2_init_cpus(struct bnx2 *bp) cpu_reg.spad_base = BNX2_CP_SCRATCH; cpu_reg.mips_view_base = 0x8000000; - if (CHIP_NUM(bp) == CHIP_NUM_5709) { + if (CHIP_NUM(bp) == CHIP_NUM_5709) fw = &bnx2_cp_fw_09; + else + fw = &bnx2_cp_fw_06; + + fw->text = text; + rc = load_cpu_fw(bp, &cpu_reg, fw); - fw->text = text; - rc = load_cpu_fw(bp, &cpu_reg, fw); - if (rc) - goto init_cpu_err; - } init_cpu_err: vfree(text); return rc; @@ -3148,7 +3492,7 @@ bnx2_set_power_state(struct bnx2 *bp, pci_power_t state) wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; } - if (!(bp->flags & NO_WOL_FLAG)) + if (!(bp->flags & BNX2_FLAG_NO_WOL)) bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0); pmcsr &= ~PCI_PM_CTRL_STATE_MASK; @@ -3360,10 +3704,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags) val = REG_RD(bp, BNX2_NVM_COMMAND); if (val & BNX2_NVM_COMMAND_DONE) { - val = REG_RD(bp, BNX2_NVM_READ); - - val = be32_to_cpu(val); - memcpy(ret_val, &val, 4); + __be32 v = cpu_to_be32(REG_RD(bp, BNX2_NVM_READ)); + memcpy(ret_val, &v, 4); break; } } @@ -3377,7 +3719,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags) static int bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags) { - u32 cmd, val32; + u32 cmd; + __be32 val32; int j; /* Build the command word. */ @@ -3394,10 +3737,9 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags) REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE); memcpy(&val32, val, 4); - val32 = cpu_to_be32(val32); /* Write the data. */ - REG_WR(bp, BNX2_NVM_WRITE, val32); + REG_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32)); /* Address of the NVRAM to write to. */ REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE); @@ -3796,8 +4138,8 @@ bnx2_init_remote_phy(struct bnx2 *bp) { u32 val; - bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG; - if (!(bp->phy_flags & PHY_SERDES_FLAG)) + bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP; + if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) return; val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB); @@ -3805,7 +4147,7 @@ bnx2_init_remote_phy(struct bnx2 *bp) return; if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) { - bp->phy_flags |= REMOTE_PHY_CAP_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP; val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS); if (val & BNX2_LINK_STATUS_SERDES_LINK) @@ -3831,6 +4173,15 @@ bnx2_init_remote_phy(struct bnx2 *bp) } } +static void +bnx2_setup_msix_tbl(struct bnx2 *bp) +{ + REG_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN); + + REG_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR); + REG_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR); +} + static int bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) { @@ -3917,7 +4268,8 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) spin_lock_bh(&bp->phy_lock); old_port = bp->phy_port; bnx2_init_remote_phy(bp); - if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port) + if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) && + old_port != bp->phy_port) bnx2_set_default_remote_link(bp); spin_unlock_bh(&bp->phy_lock); @@ -3930,6 +4282,9 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) rc = bnx2_alloc_bad_rbuf(bp); } + if (bp->flags & BNX2_FLAG_USING_MSIX) + bnx2_setup_msix_tbl(bp); + return rc; } @@ -3937,7 +4292,7 @@ static int bnx2_init_chip(struct bnx2 *bp) { u32 val; - int rc; + int rc, i; /* Make sure the interrupt is not active. */ REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT); @@ -3953,11 +4308,11 @@ bnx2_init_chip(struct bnx2 *bp) val |= (0x2 << 20) | (1 << 11); - if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133)) + if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133)) val |= (1 << 23); if ((CHIP_NUM(bp) == CHIP_NUM_5706) && - (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG)) + (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & BNX2_FLAG_PCIX)) val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA; REG_WR(bp, BNX2_DMA_CONFIG, val); @@ -3968,7 +4323,7 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_TDMA_CONFIG, val); } - if (bp->flags & PCIX_FLAG) { + if (bp->flags & BNX2_FLAG_PCIX) { u16 val16; pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD, @@ -4033,7 +4388,9 @@ bnx2_init_chip(struct bnx2 *bp) val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA; REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val); - bp->last_status_idx = 0; + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) + bp->bnx2_napi[i].last_status_idx = 0; + bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE; /* Set up how to generate a link change interrupt. */ @@ -4080,7 +4437,25 @@ bnx2_init_chip(struct bnx2 *bp) BNX2_HC_CONFIG_COLLECT_STATS; } - if (bp->flags & ONE_SHOT_MSI_FLAG) + if (bp->flags & BNX2_FLAG_USING_MSIX) { + REG_WR(bp, BNX2_HC_MSIX_BIT_VECTOR, + BNX2_HC_MSIX_BIT_VECTOR_VAL); + + REG_WR(bp, BNX2_HC_SB_CONFIG_1, + BNX2_HC_SB_CONFIG_1_TX_TMR_MODE | + BNX2_HC_SB_CONFIG_1_ONE_SHOT); + + REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP_1, + (bp->tx_quick_cons_trip_int << 16) | + bp->tx_quick_cons_trip); + + REG_WR(bp, BNX2_HC_TX_TICKS_1, + (bp->tx_ticks_int << 16) | bp->tx_ticks); + + val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B; + } + + if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI) val |= BNX2_HC_CONFIG_ONE_SHOT; REG_WR(bp, BNX2_HC_CONFIG, val); @@ -4112,6 +4487,25 @@ bnx2_init_chip(struct bnx2 *bp) } static void +bnx2_clear_ring_states(struct bnx2 *bp) +{ + struct bnx2_napi *bnapi; + int i; + + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { + bnapi = &bp->bnx2_napi[i]; + + bnapi->tx_cons = 0; + bnapi->hw_tx_cons = 0; + bnapi->rx_prod_bseq = 0; + bnapi->rx_prod = 0; + bnapi->rx_cons = 0; + bnapi->rx_pg_prod = 0; + bnapi->rx_pg_cons = 0; + } +} + +static void bnx2_init_tx_context(struct bnx2 *bp, u32 cid) { u32 val, offset0, offset1, offset2, offset3; @@ -4144,7 +4538,17 @@ static void bnx2_init_tx_ring(struct bnx2 *bp) { struct tx_bd *txbd; - u32 cid; + u32 cid = TX_CID; + struct bnx2_napi *bnapi; + + bp->tx_vec = 0; + if (bp->flags & BNX2_FLAG_USING_MSIX) { + cid = TX_TSS_CID; + bp->tx_vec = BNX2_TX_VEC; + REG_WR(bp, BNX2_TSCH_TSS_CFG, BNX2_TX_INT_NUM | + (TX_TSS_CID << 7)); + } + bnapi = &bp->bnx2_napi[bp->tx_vec]; bp->tx_wake_thresh = bp->tx_ring_size / 2; @@ -4154,11 +4558,8 @@ bnx2_init_tx_ring(struct bnx2 *bp) txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff; bp->tx_prod = 0; - bp->tx_cons = 0; - bp->hw_tx_cons = 0; bp->tx_prod_bseq = 0; - cid = TX_CID; bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX; bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ; @@ -4166,84 +4567,152 @@ bnx2_init_tx_ring(struct bnx2 *bp) } static void -bnx2_init_rx_ring(struct bnx2 *bp) +bnx2_init_rxbd_rings(struct rx_bd *rx_ring[], dma_addr_t dma[], u32 buf_size, + int num_rings) { - struct rx_bd *rxbd; int i; - u16 prod, ring_prod; - u32 val; - - /* 8 for CRC and VLAN */ - bp->rx_buf_use_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8; - /* hw alignment */ - bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN; - - ring_prod = prod = bp->rx_prod = 0; - bp->rx_cons = 0; - bp->rx_prod_bseq = 0; + struct rx_bd *rxbd; - for (i = 0; i < bp->rx_max_ring; i++) { + for (i = 0; i < num_rings; i++) { int j; - rxbd = &bp->rx_desc_ring[i][0]; + rxbd = &rx_ring[i][0]; for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) { - rxbd->rx_bd_len = bp->rx_buf_use_size; + rxbd->rx_bd_len = buf_size; rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END; } - if (i == (bp->rx_max_ring - 1)) + if (i == (num_rings - 1)) j = 0; else j = i + 1; - rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32; - rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] & - 0xffffffff; + rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32; + rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff; + } +} + +static void +bnx2_init_rx_ring(struct bnx2 *bp) +{ + int i; + u16 prod, ring_prod; + u32 val, rx_cid_addr = GET_CID_ADDR(RX_CID); + struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; + + bnx2_init_rxbd_rings(bp->rx_desc_ring, bp->rx_desc_mapping, + bp->rx_buf_use_size, bp->rx_max_ring); + + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0); + if (bp->rx_pg_ring_size) { + bnx2_init_rxbd_rings(bp->rx_pg_desc_ring, + bp->rx_pg_desc_mapping, + PAGE_SIZE, bp->rx_max_pg_ring); + val = (bp->rx_buf_use_size << 16) | PAGE_SIZE; + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val); + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY, + BNX2_L2CTX_RBDC_JUMBO_KEY); + + val = (u64) bp->rx_pg_desc_mapping[0] >> 32; + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val); + + val = (u64) bp->rx_pg_desc_mapping[0] & 0xffffffff; + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val); + + if (CHIP_NUM(bp) == CHIP_NUM_5709) + REG_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT); } val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE; val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2; val |= 0x02 << 8; - CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val); + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val); val = (u64) bp->rx_desc_mapping[0] >> 32; - CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val); + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val); val = (u64) bp->rx_desc_mapping[0] & 0xffffffff; - CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val); + CTX_WR(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val); + ring_prod = prod = bnapi->rx_pg_prod; + for (i = 0; i < bp->rx_pg_ring_size; i++) { + if (bnx2_alloc_rx_page(bp, ring_prod) < 0) + break; + prod = NEXT_RX_BD(prod); + ring_prod = RX_PG_RING_IDX(prod); + } + bnapi->rx_pg_prod = prod; + + ring_prod = prod = bnapi->rx_prod; for (i = 0; i < bp->rx_ring_size; i++) { - if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) { + if (bnx2_alloc_rx_skb(bp, bnapi, ring_prod) < 0) { break; } prod = NEXT_RX_BD(prod); ring_prod = RX_RING_IDX(prod); } - bp->rx_prod = prod; + bnapi->rx_prod = prod; + REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_PG_BDIDX, + bnapi->rx_pg_prod); REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod); - REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq); + REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bnapi->rx_prod_bseq); } -static void -bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) +static u32 bnx2_find_max_ring(u32 ring_size, u32 max_size) { - u32 num_rings, max; + u32 max, num_rings = 1; - bp->rx_ring_size = size; - num_rings = 1; - while (size > MAX_RX_DESC_CNT) { - size -= MAX_RX_DESC_CNT; + while (ring_size > MAX_RX_DESC_CNT) { + ring_size -= MAX_RX_DESC_CNT; num_rings++; } /* round to next power of 2 */ - max = MAX_RX_RINGS; + max = max_size; while ((max & num_rings) == 0) max >>= 1; if (num_rings != max) max <<= 1; - bp->rx_max_ring = max; + return max; +} + +static void +bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) +{ + u32 rx_size, rx_space, jumbo_size; + + /* 8 for CRC and VLAN */ + rx_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8; + + rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD + + sizeof(struct skb_shared_info); + + bp->rx_copy_thresh = RX_COPY_THRESH; + bp->rx_pg_ring_size = 0; + bp->rx_max_pg_ring = 0; + bp->rx_max_pg_ring_idx = 0; + if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) { + int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT; + + jumbo_size = size * pages; + if (jumbo_size > MAX_TOTAL_RX_PG_DESC_CNT) + jumbo_size = MAX_TOTAL_RX_PG_DESC_CNT; + + bp->rx_pg_ring_size = jumbo_size; + bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size, + MAX_RX_PG_RINGS); + bp->rx_max_pg_ring_idx = (bp->rx_max_pg_ring * RX_DESC_CNT) - 1; + rx_size = RX_COPY_THRESH + bp->rx_offset; + bp->rx_copy_thresh = 0; + } + + bp->rx_buf_use_size = rx_size; + /* hw alignment */ + bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN; + bp->rx_jumbo_thresh = rx_size - bp->rx_offset; + bp->rx_ring_size = size; + bp->rx_max_ring = bnx2_find_max_ring(size, MAX_RX_RINGS); bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1; } @@ -4306,6 +4775,8 @@ bnx2_free_rx_skbs(struct bnx2 *bp) dev_kfree_skb(skb); } + for (i = 0; i < bp->rx_max_pg_ring_idx; i++) + bnx2_free_rx_page(bp, i); } static void @@ -4328,6 +4799,7 @@ bnx2_reset_nic(struct bnx2 *bp, u32 reset_code) if ((rc = bnx2_init_chip(bp)) != 0) return rc; + bnx2_clear_ring_states(bp); bnx2_init_tx_ring(bp); bnx2_init_rx_ring(bp); return 0; @@ -4599,13 +5071,18 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) struct sw_bd *rx_buf; struct l2_fhdr *rx_hdr; int ret = -ENODEV; + struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi; + + tx_napi = bnapi; + if (bp->flags & BNX2_FLAG_USING_MSIX) + tx_napi = &bp->bnx2_napi[BNX2_TX_VEC]; if (loopback_mode == BNX2_MAC_LOOPBACK) { bp->loopback = MAC_LOOPBACK; bnx2_set_mac_loopback(bp); } else if (loopback_mode == BNX2_PHY_LOOPBACK) { - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return 0; bp->loopback = PHY_LOOPBACK; @@ -4614,7 +5091,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) else return -EINVAL; - pkt_size = 1514; + pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4); skb = netdev_alloc_skb(bp->dev, pkt_size); if (!skb) return -ENOMEM; @@ -4633,7 +5110,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) REG_RD(bp, BNX2_HC_COMMAND); udelay(5); - rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0; + rx_start_idx = bnx2_get_hw_rx_cons(bnapi); num_pkts = 0; @@ -4663,11 +5140,10 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); dev_kfree_skb(skb); - if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) { + if (bnx2_get_hw_tx_cons(tx_napi) != bp->tx_prod) goto loopback_test_done; - } - rx_idx = bp->status_blk->status_rx_quick_consumer_index0; + rx_idx = bnx2_get_hw_rx_cons(bnapi); if (rx_idx != rx_start_idx + num_pkts) { goto loopback_test_done; } @@ -4739,7 +5215,7 @@ bnx2_test_loopback(struct bnx2 *bp) static int bnx2_test_nvram(struct bnx2 *bp) { - u32 buf[NVRAM_SIZE / 4]; + __be32 buf[NVRAM_SIZE / 4]; u8 *data = (u8 *) buf; int rc = 0; u32 magic, csum; @@ -4776,7 +5252,7 @@ bnx2_test_link(struct bnx2 *bp) { u32 bmsr; - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { if (bp->link_up) return 0; return -ENODEV; @@ -4824,13 +5300,51 @@ bnx2_test_intr(struct bnx2 *bp) return -ENODEV; } +static int +bnx2_5706_serdes_has_link(struct bnx2 *bp) +{ + u32 mode_ctl, an_dbg, exp; + + bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl); + + if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET)) + return 0; + + bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); + + if (an_dbg & MISC_SHDW_AN_DBG_NOSYNC) + return 0; + + bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1); + bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp); + bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp); + + if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */ + return 0; + + return 1; +} + static void bnx2_5706_serdes_timer(struct bnx2 *bp) { + int check_link = 1; + spin_lock(&bp->phy_lock); - if (bp->serdes_an_pending) + if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) { + bnx2_5706s_force_link_dn(bp, 0); + bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN; + spin_unlock(&bp->phy_lock); + return; + } + + if (bp->serdes_an_pending) { bp->serdes_an_pending--; - else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { + check_link = 0; + } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { u32 bmcr; bp->current_interval = bp->timer_interval; @@ -4838,30 +5352,19 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_ANENABLE) { - u32 phy1, phy2; - - bnx2_write_phy(bp, 0x1c, 0x7c00); - bnx2_read_phy(bp, 0x1c, &phy1); - - bnx2_write_phy(bp, 0x17, 0x0f01); - bnx2_read_phy(bp, 0x15, &phy2); - bnx2_write_phy(bp, 0x17, 0x0f01); - bnx2_read_phy(bp, 0x15, &phy2); - - if ((phy1 & 0x10) && /* SIGNAL DETECT */ - !(phy2 & 0x20)) { /* no CONFIG */ - + if (bnx2_5706_serdes_has_link(bp)) { bmcr &= ~BMCR_ANENABLE; bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX; bnx2_write_phy(bp, bp->mii_bmcr, bmcr); - bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT; } } } else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) && - (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) { + (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) { u32 phy2; + check_link = 0; bnx2_write_phy(bp, 0x17, 0x0f01); bnx2_read_phy(bp, 0x15, &phy2); if (phy2 & 0x20) { @@ -4871,21 +5374,33 @@ bnx2_5706_serdes_timer(struct bnx2 *bp) bmcr |= BMCR_ANENABLE; bnx2_write_phy(bp, bp->mii_bmcr, bmcr); - bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG; + bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; } } else bp->current_interval = bp->timer_interval; + if (bp->link_up && (bp->autoneg & AUTONEG_SPEED) && check_link) { + u32 val; + + bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val); + bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val); + + if (val & MISC_SHDW_AN_DBG_NOSYNC) { + bnx2_5706s_force_link_dn(bp, 1); + bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN; + } + } spin_unlock(&bp->phy_lock); } static void bnx2_5708_serdes_timer(struct bnx2 *bp) { - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return; - if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) { + if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) { bp->serdes_an_pending = 0; return; } @@ -4932,7 +5447,7 @@ bnx2_timer(unsigned long data) REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_STATS_NOW); - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { if (CHIP_NUM(bp) == CHIP_NUM_5706) bnx2_5706_serdes_timer(bp); else @@ -4947,18 +5462,23 @@ static int bnx2_request_irq(struct bnx2 *bp) { struct net_device *dev = bp->dev; - int rc = 0; + unsigned long flags; + struct bnx2_irq *irq; + int rc = 0, i; - if (bp->flags & USING_MSI_FLAG) { - irq_handler_t fn = bnx2_msi; - - if (bp->flags & ONE_SHOT_MSI_FLAG) - fn = bnx2_msi_1shot; + if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX) + flags = 0; + else + flags = IRQF_SHARED; - rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev); - } else - rc = request_irq(bp->pdev->irq, bnx2_interrupt, - IRQF_SHARED, dev->name, dev); + for (i = 0; i < bp->irq_nvecs; i++) { + irq = &bp->irq_tbl[i]; + rc = request_irq(irq->vector, irq->handler, flags, irq->name, + dev); + if (rc) + break; + irq->requested = 1; + } return rc; } @@ -4966,13 +5486,81 @@ static void bnx2_free_irq(struct bnx2 *bp) { struct net_device *dev = bp->dev; + struct bnx2_irq *irq; + int i; - if (bp->flags & USING_MSI_FLAG) { - free_irq(bp->pdev->irq, dev); + for (i = 0; i < bp->irq_nvecs; i++) { + irq = &bp->irq_tbl[i]; + if (irq->requested) + free_irq(irq->vector, dev); + irq->requested = 0; + } + if (bp->flags & BNX2_FLAG_USING_MSI) pci_disable_msi(bp->pdev); - bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG); - } else - free_irq(bp->pdev->irq, dev); + else if (bp->flags & BNX2_FLAG_USING_MSIX) + pci_disable_msix(bp->pdev); + + bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI); +} + +static void +bnx2_enable_msix(struct bnx2 *bp) +{ + int i, rc; + struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; + + bnx2_setup_msix_tbl(bp); + REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1); + REG_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE); + REG_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE); + + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { + msix_ent[i].entry = i; + msix_ent[i].vector = 0; + } + + rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC); + if (rc != 0) + return; + + bp->irq_tbl[BNX2_BASE_VEC].handler = bnx2_msi_1shot; + bp->irq_tbl[BNX2_TX_VEC].handler = bnx2_tx_msix; + + strcpy(bp->irq_tbl[BNX2_BASE_VEC].name, bp->dev->name); + strcat(bp->irq_tbl[BNX2_BASE_VEC].name, "-base"); + strcpy(bp->irq_tbl[BNX2_TX_VEC].name, bp->dev->name); + strcat(bp->irq_tbl[BNX2_TX_VEC].name, "-tx"); + + bp->irq_nvecs = BNX2_MAX_MSIX_VEC; + bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI; + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) + bp->irq_tbl[i].vector = msix_ent[i].vector; +} + +static void +bnx2_setup_int_mode(struct bnx2 *bp, int dis_msi) +{ + bp->irq_tbl[0].handler = bnx2_interrupt; + strcpy(bp->irq_tbl[0].name, bp->dev->name); + bp->irq_nvecs = 1; + bp->irq_tbl[0].vector = bp->pdev->irq; + + if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi) + bnx2_enable_msix(bp); + + if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi && + !(bp->flags & BNX2_FLAG_USING_MSIX)) { + if (pci_enable_msi(bp->pdev) == 0) { + bp->flags |= BNX2_FLAG_USING_MSI; + if (CHIP_NUM(bp) == CHIP_NUM_5709) { + bp->flags |= BNX2_FLAG_ONE_SHOT_MSI; + bp->irq_tbl[0].handler = bnx2_msi_1shot; + } else + bp->irq_tbl[0].handler = bnx2_msi; + + bp->irq_tbl[0].vector = bp->pdev->irq; + } + } } /* Called with rtnl_lock */ @@ -4991,19 +5579,12 @@ bnx2_open(struct net_device *dev) if (rc) return rc; - napi_enable(&bp->napi); - - if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) { - if (pci_enable_msi(bp->pdev) == 0) { - bp->flags |= USING_MSI_FLAG; - if (CHIP_NUM(bp) == CHIP_NUM_5709) - bp->flags |= ONE_SHOT_MSI_FLAG; - } - } + bnx2_setup_int_mode(bp, disable_msi); + bnx2_napi_enable(bp); rc = bnx2_request_irq(bp); if (rc) { - napi_disable(&bp->napi); + bnx2_napi_disable(bp); bnx2_free_mem(bp); return rc; } @@ -5011,7 +5592,7 @@ bnx2_open(struct net_device *dev) rc = bnx2_init_nic(bp); if (rc) { - napi_disable(&bp->napi); + bnx2_napi_disable(bp); bnx2_free_irq(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); @@ -5024,7 +5605,7 @@ bnx2_open(struct net_device *dev) bnx2_enable_int(bp); - if (bp->flags & USING_MSI_FLAG) { + if (bp->flags & BNX2_FLAG_USING_MSI) { /* Test MSI to make sure it is working * If MSI test fails, go back to INTx mode */ @@ -5038,13 +5619,15 @@ bnx2_open(struct net_device *dev) bnx2_disable_int(bp); bnx2_free_irq(bp); + bnx2_setup_int_mode(bp, 1); + rc = bnx2_init_nic(bp); if (!rc) rc = bnx2_request_irq(bp); if (rc) { - napi_disable(&bp->napi); + bnx2_napi_disable(bp); bnx2_free_skbs(bp); bnx2_free_mem(bp); del_timer_sync(&bp->timer); @@ -5053,9 +5636,10 @@ bnx2_open(struct net_device *dev) bnx2_enable_int(bp); } } - if (bp->flags & USING_MSI_FLAG) { + if (bp->flags & BNX2_FLAG_USING_MSI) printk(KERN_INFO PFX "%s: using MSI\n", dev->name); - } + else if (bp->flags & BNX2_FLAG_USING_MSIX) + printk(KERN_INFO PFX "%s: using MSIX\n", dev->name); netif_start_queue(dev); @@ -5119,8 +5703,10 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 len, vlan_tag_flags, last_frag, mss; u16 prod, ring_prod; int i; + struct bnx2_napi *bnapi = &bp->bnx2_napi[bp->tx_vec]; - if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) { + if (unlikely(bnx2_tx_avail(bp, bnapi) < + (skb_shinfo(skb)->nr_frags + 1))) { netif_stop_queue(dev); printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n", dev->name); @@ -5136,7 +5722,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; } - if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) { + if (bp->vlgrp && vlan_tx_tag_present(skb)) { vlan_tag_flags |= (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16)); } @@ -5235,9 +5821,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) bp->tx_prod = prod; dev->trans_start = jiffies; - if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) { + if (unlikely(bnx2_tx_avail(bp, bnapi) <= MAX_SKB_FRAGS)) { netif_stop_queue(dev); - if (bnx2_tx_avail(bp) > bp->tx_wake_thresh) + if (bnx2_tx_avail(bp, bnapi) > bp->tx_wake_thresh) netif_wake_queue(dev); } @@ -5259,9 +5845,9 @@ bnx2_close(struct net_device *dev) msleep(1); bnx2_disable_int_sync(bp); - napi_disable(&bp->napi); + bnx2_napi_disable(bp); del_timer_sync(&bp->timer); - if (bp->flags & NO_WOL_FLAG) + if (bp->flags & BNX2_FLAG_NO_WOL) reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; else if (bp->wol) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; @@ -5375,7 +5961,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) int support_serdes = 0, support_copper = 0; cmd->supported = SUPPORTED_Autoneg; - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { support_serdes = 1; support_copper = 1; } else if (bp->phy_port == PORT_FIBRE) @@ -5386,7 +5972,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (support_serdes) { cmd->supported |= SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE; - if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) cmd->supported |= SUPPORTED_2500baseX_Full; } @@ -5442,7 +6028,8 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE) goto err_out_unlock; - if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG)) + if (cmd->port != bp->phy_port && + !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)) goto err_out_unlock; if (cmd->autoneg == AUTONEG_ENABLE) { @@ -5462,7 +6049,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) advertising = cmd->advertising; } else if (cmd->advertising == ADVERTISED_2500baseX_Full) { - if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) || + if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) || (cmd->port == PORT_TP)) goto err_out_unlock; } else if (cmd->advertising == ADVERTISED_1000baseT_Full) @@ -5485,7 +6072,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) goto err_out_unlock; if (cmd->speed == SPEED_2500 && - !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)) + !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) goto err_out_unlock; } else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500) @@ -5584,7 +6171,7 @@ bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct bnx2 *bp = netdev_priv(dev); - if (bp->flags & NO_WOL_FLAG) { + if (bp->flags & BNX2_FLAG_NO_WOL) { wol->supported = 0; wol->wolopts = 0; } @@ -5607,7 +6194,7 @@ bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) return -EINVAL; if (wol->wolopts & WAKE_MAGIC) { - if (bp->flags & NO_WOL_FLAG) + if (bp->flags & BNX2_FLAG_NO_WOL) return -EINVAL; bp->wol = 1; @@ -5630,7 +6217,7 @@ bnx2_nway_reset(struct net_device *dev) spin_lock_bh(&bp->phy_lock); - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { int rc; rc = bnx2_setup_remote_phy(bp, bp->phy_port); @@ -5639,7 +6226,7 @@ bnx2_nway_reset(struct net_device *dev) } /* Force a link down visible on the other side */ - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); spin_unlock_bh(&bp->phy_lock); @@ -5778,27 +6365,19 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT; ering->rx_mini_max_pending = 0; - ering->rx_jumbo_max_pending = 0; + ering->rx_jumbo_max_pending = MAX_TOTAL_RX_PG_DESC_CNT; ering->rx_pending = bp->rx_ring_size; ering->rx_mini_pending = 0; - ering->rx_jumbo_pending = 0; + ering->rx_jumbo_pending = bp->rx_pg_ring_size; ering->tx_max_pending = MAX_TX_DESC_CNT; ering->tx_pending = bp->tx_ring_size; } static int -bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +bnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx) { - struct bnx2 *bp = netdev_priv(dev); - - if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) || - (ering->tx_pending > MAX_TX_DESC_CNT) || - (ering->tx_pending <= MAX_SKB_FRAGS)) { - - return -EINVAL; - } if (netif_running(bp->dev)) { bnx2_netif_stop(bp); bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); @@ -5806,8 +6385,8 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) bnx2_free_mem(bp); } - bnx2_set_rx_ring_size(bp, ering->rx_pending); - bp->tx_ring_size = ering->tx_pending; + bnx2_set_rx_ring_size(bp, rx); + bp->tx_ring_size = tx; if (netif_running(bp->dev)) { int rc; @@ -5818,10 +6397,25 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) bnx2_init_nic(bp); bnx2_netif_start(bp); } - return 0; } +static int +bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +{ + struct bnx2 *bp = netdev_priv(dev); + int rc; + + if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) || + (ering->tx_pending > MAX_TX_DESC_CNT) || + (ering->tx_pending <= MAX_SKB_FRAGS)) { + + return -EINVAL; + } + rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending); + return rc; +} + static void bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { @@ -6244,7 +6838,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIREG: { u32 mii_regval; - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return -EOPNOTSUPP; if (!netif_running(dev)) @@ -6263,7 +6857,7 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) + if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) return -EOPNOTSUPP; if (!netif_running(dev)) @@ -6310,14 +6904,7 @@ bnx2_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; dev->mtu = new_mtu; - if (netif_running(dev)) { - bnx2_netif_stop(bp); - - bnx2_init_nic(bp); - - bnx2_netif_start(bp); - } - return 0; + return (bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size)); } #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) @@ -6342,7 +6929,7 @@ bnx2_get_5709_media(struct bnx2 *bp) if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) return; else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) { - bp->phy_flags |= PHY_SERDES_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_SERDES; return; } @@ -6356,7 +6943,7 @@ bnx2_get_5709_media(struct bnx2 *bp) case 0x4: case 0x5: case 0x6: - bp->phy_flags |= PHY_SERDES_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_SERDES; return; } } else { @@ -6364,7 +6951,7 @@ bnx2_get_5709_media(struct bnx2 *bp) case 0x1: case 0x2: case 0x4: - bp->phy_flags |= PHY_SERDES_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_SERDES; return; } } @@ -6379,7 +6966,7 @@ bnx2_get_pci_speed(struct bnx2 *bp) if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) { u32 clkreg; - bp->flags |= PCIX_FLAG; + bp->flags |= BNX2_FLAG_PCIX; clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS); @@ -6418,7 +7005,7 @@ bnx2_get_pci_speed(struct bnx2 *bp) } if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET) - bp->flags |= PCI_32BIT_FLAG; + bp->flags |= BNX2_FLAG_PCI_32BIT; } @@ -6506,7 +7093,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) rc = -EIO; goto err_out_unmap; } - bp->flags |= PCIE_FLAG; + bp->flags |= BNX2_FLAG_PCIE; + if (CHIP_REV(bp) == CHIP_REV_Ax) + bp->flags |= BNX2_FLAG_JUMBO_BROKEN; } else { bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX); if (bp->pcix_cap == 0) { @@ -6517,9 +7106,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } } + if (CHIP_NUM(bp) == CHIP_NUM_5709 && CHIP_REV(bp) != CHIP_REV_Ax) { + if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) + bp->flags |= BNX2_FLAG_MSIX_CAP; + } + if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) { if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) - bp->flags |= MSI_CAP_FLAG; + bp->flags |= BNX2_FLAG_MSI_CAP; } /* 5708 cannot support DMA addresses > 40-bit. */ @@ -6542,7 +7136,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) goto err_out_unmap; } - if (!(bp->flags & PCIE_FLAG)) + if (!(bp->flags & BNX2_FLAG_PCIE)) bnx2_get_pci_speed(bp); /* 5706A0 may falsely detect SERR and PERR. */ @@ -6552,7 +7146,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) REG_WR(bp, PCI_COMMAND, reg); } else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) && - !(bp->flags & PCIX_FLAG)) { + !(bp->flags & BNX2_FLAG_PCIX)) { dev_err(&pdev->dev, "5706 A1 can only be used in a PCIX bus, aborting.\n"); @@ -6602,7 +7196,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->wol = 1; if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) { - bp->flags |= ASF_ENABLE_FLAG; + bp->flags |= BNX2_FLAG_ASF_ENABLE; for (i = 0; i < 30; i++) { reg = REG_RD_IND(bp, bp->shmem_base + @@ -6638,13 +7232,13 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->mac_addr[4] = (u8) (reg >> 8); bp->mac_addr[5] = (u8) reg; + bp->rx_offset = sizeof(struct l2_fhdr) + 2; + bp->tx_ring_size = MAX_TX_DESC_CNT; bnx2_set_rx_ring_size(bp, 255); bp->rx_csum = 1; - bp->rx_offset = sizeof(struct l2_fhdr) + 2; - bp->tx_quick_cons_trip_int = 20; bp->tx_quick_cons_trip = 20; bp->tx_ticks_int = 80; @@ -6666,36 +7260,36 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if (CHIP_NUM(bp) == CHIP_NUM_5709) bnx2_get_5709_media(bp); else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) - bp->phy_flags |= PHY_SERDES_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_SERDES; bp->phy_port = PORT_TP; - if (bp->phy_flags & PHY_SERDES_FLAG) { + if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { bp->phy_port = PORT_FIBRE; reg = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG); if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) { - bp->flags |= NO_WOL_FLAG; + bp->flags |= BNX2_FLAG_NO_WOL; bp->wol = 0; } if (CHIP_NUM(bp) != CHIP_NUM_5706) { bp->phy_addr = 2; if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) - bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE; } bnx2_init_remote_phy(bp); } else if (CHIP_NUM(bp) == CHIP_NUM_5706 || CHIP_NUM(bp) == CHIP_NUM_5708) - bp->phy_flags |= PHY_CRC_FIX_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX; else if (CHIP_NUM(bp) == CHIP_NUM_5709 && (CHIP_REV(bp) == CHIP_REV_Ax || CHIP_REV(bp) == CHIP_REV_Bx)) - bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG; + bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC; if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || (CHIP_ID(bp) == CHIP_ID_5708_B1)) { - bp->flags |= NO_WOL_FLAG; + bp->flags |= BNX2_FLAG_NO_WOL; bp->wol = 0; } @@ -6769,13 +7363,13 @@ bnx2_bus_string(struct bnx2 *bp, char *str) { char *s = str; - if (bp->flags & PCIE_FLAG) { + if (bp->flags & BNX2_FLAG_PCIE) { s += sprintf(s, "PCI Express"); } else { s += sprintf(s, "PCI"); - if (bp->flags & PCIX_FLAG) + if (bp->flags & BNX2_FLAG_PCIX) s += sprintf(s, "-X"); - if (bp->flags & PCI_32BIT_FLAG) + if (bp->flags & BNX2_FLAG_PCI_32BIT) s += sprintf(s, " 32-bit"); else s += sprintf(s, " 64-bit"); @@ -6784,6 +7378,21 @@ bnx2_bus_string(struct bnx2 *bp, char *str) return str; } +static void __devinit +bnx2_init_napi(struct bnx2 *bp) +{ + int i; + struct bnx2_napi *bnapi; + + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { + bnapi = &bp->bnx2_napi[i]; + bnapi->bp = bp; + } + netif_napi_add(bp->dev, &bp->bnx2_napi[0].napi, bnx2_poll, 64); + netif_napi_add(bp->dev, &bp->bnx2_napi[BNX2_TX_VEC].napi, bnx2_tx_poll, + 64); +} + static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -6825,7 +7434,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->ethtool_ops = &bnx2_ethtool_ops; bp = netdev_priv(dev); - netif_napi_add(dev, &bp->napi, bnx2_poll, 64); + bnx2_init_napi(bp); #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) dev->poll_controller = poll_bnx2; @@ -6910,7 +7519,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) bnx2_netif_stop(bp); netif_device_detach(dev); del_timer_sync(&bp->timer); - if (bp->flags & NO_WOL_FLAG) + if (bp->flags & BNX2_FLAG_NO_WOL) reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; else if (bp->wol) reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 30ba366608b0..d8e034700c36 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -154,6 +154,33 @@ struct status_block { #endif }; +/* + * status_block definition + */ +struct status_block_msix { +#if defined(__BIG_ENDIAN) + u16 status_tx_quick_consumer_index; + u16 status_rx_quick_consumer_index; + u16 status_completion_producer_index; + u16 status_cmd_consumer_index; + u32 status_unused; + u16 status_idx; + u8 status_unused2; + u8 status_blk_num; +#elif defined(__LITTLE_ENDIAN) + u16 status_rx_quick_consumer_index; + u16 status_tx_quick_consumer_index; + u16 status_cmd_consumer_index; + u16 status_completion_producer_index; + u32 status_unused; + u8 status_blk_num; + u8 status_unused2; + u16 status_idx; +#endif +}; + +#define BNX2_SBLK_MSIX_ALIGN_SIZE 128 + /* * statistics_block definition @@ -259,6 +286,7 @@ struct l2_fhdr { #define L2_FHDR_STATUS_TCP_SEGMENT (1<<14) #define L2_FHDR_STATUS_UDP_DATAGRAM (1<<15) + #define L2_FHDR_STATUS_SPLIT (1<<16) #define L2_FHDR_ERRORS_BAD_CRC (1<<17) #define L2_FHDR_ERRORS_PHY_DECODE (1<<18) #define L2_FHDR_ERRORS_ALIGNMENT (1<<19) @@ -332,6 +360,12 @@ struct l2_fhdr { #define BNX2_L2CTX_NX_BDHADDR_LO 0x00000014 #define BNX2_L2CTX_NX_BDIDX 0x00000018 +#define BNX2_L2CTX_HOST_PG_BDIDX 0x00000044 +#define BNX2_L2CTX_PG_BUF_SIZE 0x00000048 +#define BNX2_L2CTX_RBDC_KEY 0x0000004c +#define BNX2_L2CTX_RBDC_JUMBO_KEY 0x3ffe +#define BNX2_L2CTX_NX_PG_BDHADDR_HI 0x00000050 +#define BNX2_L2CTX_NX_PG_BDHADDR_LO 0x00000054 /* * pci_config_l definition @@ -406,6 +440,7 @@ struct l2_fhdr { #define BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM (1L<<17) #define BNX2_PCICFG_INT_ACK_CMD_MASK_INT (1L<<18) #define BNX2_PCICFG_INT_ACK_CMD_INTERRUPT_NUM (0xfL<<24) +#define BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT 24 #define BNX2_PCICFG_STATUS_BIT_SET_CMD 0x00000088 #define BNX2_PCICFG_STATUS_BIT_CLEAR_CMD 0x0000008c @@ -421,6 +456,9 @@ struct l2_fhdr { #define BNX2_PCI_GRC_WINDOW_ADDR_VALUE (0x1ffL<<13) #define BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN (1L<<31) +#define BNX2_PCI_GRC_WINDOW2_BASE 0xc000 +#define BNX2_PCI_GRC_WINDOW3_BASE 0xe000 + #define BNX2_PCI_CONFIG_1 0x00000404 #define BNX2_PCI_CONFIG_1_RESERVED0 (0xffL<<0) #define BNX2_PCI_CONFIG_1_READ_BOUNDARY (0x7L<<8) @@ -693,6 +731,8 @@ struct l2_fhdr { #define BNX2_PCI_GRC_WINDOW3_ADDR 0x00000618 #define BNX2_PCI_GRC_WINDOW3_ADDR_VALUE (0x1ffL<<13) +#define BNX2_MSIX_TABLE_ADDR 0x318000 +#define BNX2_MSIX_PBA_ADDR 0x31c000 /* * misc_reg definition @@ -4445,6 +4485,14 @@ struct l2_fhdr { #define BNX2_MQ_MEM_RD_DATA2_VALUE (0x3fffffffL<<0) #define BNX2_MQ_MEM_RD_DATA2_VALUE_XI (0x7fffffffL<<0) +#define BNX2_MQ_MAP_L2_3 0x00003d2c +#define BNX2_MQ_MAP_L2_3_MQ_OFFSET (0xffL<<0) +#define BNX2_MQ_MAP_L2_3_SZ (0x3L<<8) +#define BNX2_MQ_MAP_L2_3_CTX_OFFSET (0x2ffL<<10) +#define BNX2_MQ_MAP_L2_3_BIN_OFFSET (0x7L<<23) +#define BNX2_MQ_MAP_L2_3_ARM (0x3L<<26) +#define BNX2_MQ_MAP_L2_3_ENA (0x1L<<31) +#define BNX2_MQ_MAP_L2_3_DEFAULT 0x82004646 /* * tsch_reg definition @@ -6296,6 +6344,15 @@ struct l2_fhdr { #define MII_BNX2_DSP_RW_PORT 0x15 #define MII_BNX2_DSP_ADDRESS 0x17 #define MII_BNX2_DSP_EXPAND_REG 0x0f00 +#define MII_EXPAND_REG1 (MII_BNX2_DSP_EXPAND_REG | 1) +#define MII_EXPAND_REG1_RUDI_C 0x20 +#define MII_EXPAND_SERDES_CTL (MII_BNX2_DSP_EXPAND_REG | 2) + +#define MII_BNX2_MISC_SHADOW 0x1c +#define MISC_SHDW_AN_DBG 0x6800 +#define MISC_SHDW_AN_DBG_NOSYNC 0x0002 +#define MISC_SHDW_MODE_CTL 0x7c00 +#define MISC_SHDW_MODE_CTL_SIG_DET 0x0010 #define MII_BNX2_BLK_ADDR 0x1f #define MII_BNX2_BLK_ADDR_IEEE0 0x0000 @@ -6336,7 +6393,7 @@ struct l2_fhdr { #define MAX_ETHERNET_PACKET_SIZE 1514 #define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014 -#define RX_COPY_THRESH 92 +#define RX_COPY_THRESH 128 #define BNX2_MISC_ENABLE_DEFAULT 0x7ffffff @@ -6355,9 +6412,11 @@ struct l2_fhdr { #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) #define MAX_RX_RINGS 4 +#define MAX_RX_PG_RINGS 16 #define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct rx_bd)) #define MAX_RX_DESC_CNT (RX_DESC_CNT - 1) #define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS) +#define MAX_TOTAL_RX_PG_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_PG_RINGS) #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) == \ (MAX_TX_DESC_CNT - 1)) ? \ @@ -6370,6 +6429,7 @@ struct l2_fhdr { (x) + 2 : (x) + 1 #define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx) +#define RX_PG_RING_IDX(x) ((x) & bp->rx_max_pg_ring_idx) #define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> (BCM_PAGE_BITS - 4)) #define RX_IDX(x) ((x) & MAX_RX_DESC_CNT) @@ -6408,6 +6468,17 @@ struct sw_bd { DECLARE_PCI_UNMAP_ADDR(mapping) }; +struct sw_pg { + struct page *page; + DECLARE_PCI_UNMAP_ADDR(mapping) +}; + +#define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT) +#define SW_RXPG_RING_SIZE (sizeof(struct sw_pg) * RX_DESC_CNT) +#define RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT) +#define SW_TXBD_RING_SIZE (sizeof(struct sw_bd) * TX_DESC_CNT) +#define TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT) + /* Buffered flash (Atmel: AT45DB011B) specific information */ #define SEEPROM_PAGE_BITS 2 #define SEEPROM_PHY_PAGE_SIZE (1 << SEEPROM_PAGE_BITS) @@ -6465,6 +6536,39 @@ struct flash_spec { u8 *name; }; +#define BNX2_MAX_MSIX_HW_VEC 9 +#define BNX2_MAX_MSIX_VEC 2 +#define BNX2_BASE_VEC 0 +#define BNX2_TX_VEC 1 +#define BNX2_TX_INT_NUM (BNX2_TX_VEC << BNX2_PCICFG_INT_ACK_CMD_INT_NUM_SHIFT) + +struct bnx2_irq { + irq_handler_t handler; + u16 vector; + u8 requested; + char name[16]; +}; + +struct bnx2_napi { + struct napi_struct napi ____cacheline_aligned; + struct bnx2 *bp; + struct status_block *status_blk; + struct status_block_msix *status_blk_msix; + u32 last_status_idx; + u32 int_num; + + u16 tx_cons; + u16 hw_tx_cons; + + u32 rx_prod_bseq; + u16 rx_prod; + u16 rx_cons; + + u16 rx_pg_prod; + u16 rx_pg_cons; + +}; + struct bnx2 { /* Fields used in the tx and intr/napi performance paths are grouped */ /* together in the beginning of the structure. */ @@ -6473,33 +6577,32 @@ struct bnx2 { struct net_device *dev; struct pci_dev *pdev; - struct napi_struct napi; - atomic_t intr_sem; - struct status_block *status_blk; - u32 last_status_idx; - u32 flags; -#define PCIX_FLAG 0x00000001 -#define PCI_32BIT_FLAG 0x00000002 -#define ONE_TDMA_FLAG 0x00000004 /* no longer used */ -#define NO_WOL_FLAG 0x00000008 -#define USING_MSI_FLAG 0x00000020 -#define ASF_ENABLE_FLAG 0x00000040 -#define MSI_CAP_FLAG 0x00000080 -#define ONE_SHOT_MSI_FLAG 0x00000100 -#define PCIE_FLAG 0x00000200 +#define BNX2_FLAG_PCIX 0x00000001 +#define BNX2_FLAG_PCI_32BIT 0x00000002 +#define BNX2_FLAG_MSIX_CAP 0x00000004 +#define BNX2_FLAG_NO_WOL 0x00000008 +#define BNX2_FLAG_USING_MSI 0x00000020 +#define BNX2_FLAG_ASF_ENABLE 0x00000040 +#define BNX2_FLAG_MSI_CAP 0x00000080 +#define BNX2_FLAG_ONE_SHOT_MSI 0x00000100 +#define BNX2_FLAG_PCIE 0x00000200 +#define BNX2_FLAG_USING_MSIX 0x00000400 +#define BNX2_FLAG_USING_MSI_OR_MSIX (BNX2_FLAG_USING_MSI | \ + BNX2_FLAG_USING_MSIX) +#define BNX2_FLAG_JUMBO_BROKEN 0x00000800 /* Put tx producer and consumer fields in separate cache lines. */ u32 tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES))); u16 tx_prod; + u8 tx_vec; u32 tx_bidx_addr; u32 tx_bseq_addr; - u16 tx_cons __attribute__((aligned(L1_CACHE_BYTES))); - u16 hw_tx_cons; + struct bnx2_napi bnx2_napi[BNX2_MAX_MSIX_VEC]; #ifdef BCM_VLAN struct vlan_group *vlgrp; @@ -6508,16 +6611,17 @@ struct bnx2 { u32 rx_offset; u32 rx_buf_use_size; /* useable size */ u32 rx_buf_size; /* with alignment */ + u32 rx_copy_thresh; + u32 rx_jumbo_thresh; u32 rx_max_ring_idx; - - u32 rx_prod_bseq; - u16 rx_prod; - u16 rx_cons; + u32 rx_max_pg_ring_idx; u32 rx_csum; struct sw_bd *rx_buf_ring; struct rx_bd *rx_desc_ring[MAX_RX_RINGS]; + struct sw_pg *rx_pg_ring; + struct rx_bd *rx_pg_desc_ring[MAX_RX_PG_RINGS]; /* TX constants */ struct tx_bd *tx_desc_ring; @@ -6540,15 +6644,16 @@ struct bnx2 { spinlock_t indirect_lock; u32 phy_flags; -#define PHY_SERDES_FLAG 1 -#define PHY_CRC_FIX_FLAG 2 -#define PHY_PARALLEL_DETECT_FLAG 4 -#define PHY_2_5G_CAPABLE_FLAG 8 -#define PHY_INT_MODE_MASK_FLAG 0x300 -#define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100 -#define PHY_INT_MODE_LINK_READY_FLAG 0x200 -#define PHY_DIS_EARLY_DAC_FLAG 0x400 -#define REMOTE_PHY_CAP_FLAG 0x800 +#define BNX2_PHY_FLAG_SERDES 0x00000001 +#define BNX2_PHY_FLAG_CRC_FIX 0x00000002 +#define BNX2_PHY_FLAG_PARALLEL_DETECT 0x00000004 +#define BNX2_PHY_FLAG_2_5G_CAPABLE 0x00000008 +#define BNX2_PHY_FLAG_INT_MODE_MASK 0x00000300 +#define BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING 0x00000100 +#define BNX2_PHY_FLAG_INT_MODE_LINK_READY 0x00000200 +#define BNX2_PHY_FLAG_DIS_EARLY_DAC 0x00000400 +#define BNX2_PHY_FLAG_REMOTE_PHY_CAP 0x00000800 +#define BNX2_PHY_FLAG_FORCED_DOWN 0x00001000 u32 mii_bmcr; u32 mii_bmsr; @@ -6605,6 +6710,10 @@ struct bnx2 { int rx_ring_size; dma_addr_t rx_desc_mapping[MAX_RX_RINGS]; + int rx_max_pg_ring; + int rx_pg_ring_size; + dma_addr_t rx_pg_desc_mapping[MAX_RX_PG_RINGS]; + u16 tx_quick_cons_trip; u16 tx_quick_cons_trip_int; u16 rx_quick_cons_trip; @@ -6622,6 +6731,7 @@ struct bnx2 { u32 stats_ticks; + struct status_block *status_blk; dma_addr_t status_blk_mapping; struct statistics_block *stats_blk; @@ -6680,6 +6790,9 @@ struct bnx2 { u32 flash_size; int status_stats_size; + + struct bnx2_irq irq_tbl[BNX2_MAX_MSIX_VEC]; + int irq_nvecs; }; static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset); @@ -6737,7 +6850,7 @@ struct fw_info { const u32 text_addr; const u32 text_len; const u32 text_index; - u32 *text; + __le32 *text; u8 *gz_text; const u32 gz_text_len; diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index a6d78243163b..c1ad4dd38c32 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -1,13 +1,13 @@ /* bnx2_fw.h: Broadcom NX2 network driver. * - * Copyright (c) 2004, 2005, 2006 Broadcom Corporation + * Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation * * 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, except as noted below. * * This file contains firmware data derived from proprietary unpublished - * source code, Copyright (c) 2004, 2005, 2006 Broadcom Corporation. + * source code, Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation. * * Permission is hereby granted for the distribution of this firmware data * in hexadecimal or equivalent format, provided this copyright notice is @@ -15,2264 +15,3633 @@ */ static u8 bnx2_COM_b06FwText[] = { -/* 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */ - 0xdc, 0x5a, - 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15, - 0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96, - 0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1, - 0x65, 0x6b, 0x4a, 0xa2, 0x6d, 0x05, 0x11, 0x02, 0x62, 0x49, 0xa9, 0x46, - 0x50, 0xb7, 0x92, 0xab, 0xb6, 0x81, 0x6b, 0x4b, 0x6b, 0x92, 0x6a, 0x09, - 0x84, 0xe6, 0x08, 0x11, 0x43, 0x19, 0xa9, 0x11, 0x10, 0xa4, 0x1c, 0xbb, - 0xc0, 0xb6, 0x2b, 0xbf, 0x05, 0x34, 0x2e, 0x15, 0x4a, 0x6e, 0xd4, 0x34, - 0x30, 0xfc, 0xa7, 0xa8, 0x51, 0x38, 0xad, 0xe1, 0x04, 0xa8, 0x9b, 0x16, - 0x45, 0xd0, 0xfc, 0x88, 0x0a, 0xdb, 0xd9, 0x7e, 0xdf, 0x9d, 0x3b, 0xcb, - 0xe1, 0x92, 0xd4, 0xc3, 0x8f, 0xfe, 0x28, 0x81, 0xe5, 0xcc, 0xbd, 0x73, - 0xe7, 0xde, 0x73, 0xcf, 0xe3, 0x3b, 0x8f, 0xb9, 0x77, 0x8a, 0x34, 0x88, - 0xfe, 0x5b, 0x8f, 0x5f, 0xf2, 0xd1, 0x3f, 0x18, 0xbe, 0xab, 0xe7, 0xae, - 0xbb, 0x71, 0x7b, 0xb7, 0x19, 0xb1, 0x22, 0xec, 0xe7, 0x3f, 0x07, 0xbf, - 0x6e, 0x7d, 0xbf, 0xda, 0x9f, 0x8d, 0xdf, 0x65, 0xfc, 0x86, 0x7e, 0x2e, - 0x62, 0xac, 0x31, 0x26, 0xfc, 0x57, 0xa9, 0x5c, 0xfd, 0xb9, 0x49, 0x5a, - 0xae, 0xf2, 0x3c, 0xe2, 0x2f, 0xa9, 0x68, 0xe6, 0x4f, 0x62, 0x66, 0x46, - 0x8e, 0xe7, 0x5c, 0x89, 0x45, 0x32, 0x1f, 0x1c, 0x1f, 0x76, 0x45, 0xb2, - 0xa5, 0x6d, 0xc9, 0xbc, 0x7c, 0x5c, 0x29, 0x3a, 0x96, 0xb0, 0xff, 0xd6, - 0xcc, 0x47, 0x27, 0xde, 0xd8, 0x91, 0xfa, 0xc5, 0x6c, 0x44, 0x62, 0x76, - 0xe6, 0x15, 0xb1, 0xb7, 0x4a, 0xac, 0x15, 0xef, 0x3c, 0xdb, 0x99, 0x33, - 0xa4, 0x29, 0x98, 0xeb, 0x83, 0xca, 0x1b, 0x9d, 0x52, 0xdc, 0x9c, 0x89, - 0x89, 0x99, 0xe9, 0x78, 0x27, 0x17, 0xb1, 0x87, 0x22, 0x19, 0x5b, 0x16, - 0xca, 0x32, 0x30, 0x32, 0x29, 0xb1, 0x58, 0x66, 0x22, 0x56, 0xdf, 0x21, - 0xb1, 0x68, 0x66, 0xe8, 0xf8, 0xf7, 0xdc, 0x13, 0x15, 0xd3, 0x75, 0x93, - 0xa3, 0x12, 0xef, 0x1d, 0xef, 0xc1, 0xf3, 0x52, 0x0a, 0x04, 0xef, 0x10, - 0xd3, 0x2d, 0xc6, 0x23, 0x6e, 0x4c, 0x72, 0x65, 0x57, 0xf2, 0x65, 0x91, - 0x1f, 0x96, 0x0c, 0x19, 0x77, 0x5b, 0x64, 0x74, 0xfb, 0x47, 0x95, 0x2c, - 0x68, 0xf9, 0x3b, 0x77, 0xe8, 0xf8, 0x73, 0x2e, 0xe9, 0x9d, 0x8e, 0xf9, - 0xf4, 0x8e, 0xd7, 0x0f, 0xbb, 0x96, 0xcc, 0x95, 0xd8, 0x77, 0xd0, 0x64, - 0x9f, 0x95, 0xf9, 0x7e, 0xc3, 0xb8, 0x1b, 0xd7, 0x7d, 0x13, 0xd9, 0x1c, - 0xe6, 0x9b, 0x2f, 0x71, 0xec, 0xbb, 0x5f, 0x18, 0x76, 0x1d, 0xdd, 0x9f, - 0xdd, 0x91, 0x73, 0x13, 0xe8, 0x6f, 0xd5, 0xcf, 0x9e, 0x79, 0x74, 0xd8, - 0x75, 0xf5, 0x33, 0xcb, 0xca, 0xb9, 0x5d, 0xba, 0xbf, 0xb4, 0x6b, 0xd8, - 0xdd, 0xae, 0xfb, 0x7f, 0xbc, 0x2b, 0xe7, 0xa6, 0x75, 0x7f, 0xef, 0x57, - 0x86, 0xdd, 0x1e, 0xdd, 0xff, 0xf6, 0xce, 0x9c, 0xdb, 0xab, 0xfb, 0x4f, - 0xf5, 0x0e, 0xbb, 0xb6, 0x9c, 0x2d, 0x25, 0xf1, 0x9b, 0x88, 0x59, 0x1d, - 0x19, 0x3d, 0xe6, 0x59, 0xd0, 0x9b, 0xc5, 0x98, 0x3e, 0xf4, 0xef, 0xc1, - 0xaf, 0x1f, 0xbf, 0xf2, 0x06, 0x69, 0x1a, 0xc0, 0xf3, 0x0f, 0xb7, 0xf8, - 0x3c, 0x04, 0xaf, 0xbc, 0x98, 0xbc, 0x17, 0x49, 0xc8, 0x1b, 0x9d, 0xef, - 0x81, 0x97, 0xb6, 0x9c, 0x2b, 0x8b, 0x31, 0xd0, 0x99, 0x00, 0x0f, 0x1d, - 0x79, 0xb1, 0xdc, 0x28, 0x91, 0x6f, 0x45, 0xc0, 0xa3, 0xaf, 0x4a, 0xc1, - 0x89, 0xc9, 0xc6, 0x19, 0x43, 0xda, 0xba, 0xd7, 0x49, 0xd6, 0x2e, 0x4a, - 0xbe, 0x13, 0x52, 0x9f, 0x72, 0xc4, 0x9a, 0x59, 0xdc, 0x68, 0xa2, 0xc7, - 0x94, 0x54, 0xa2, 0x80, 0x19, 0x47, 0xce, 0xbe, 0x4b, 0x1d, 0xa5, 0x7c, - 0xf1, 0x4b, 0x4a, 0x7e, 0xf2, 0x0e, 0x19, 0xb2, 0x49, 0xe7, 0x9f, 0xdd, - 0xea, 0xaf, 0x19, 0x33, 0x72, 0x67, 0x06, 0xe5, 0xa4, 0x17, 0x37, 0xf2, - 0x67, 0x76, 0x4a, 0x2e, 0x2d, 0x8e, 0x29, 0x1d, 0xea, 0xdd, 0xf9, 0xd2, - 0xa0, 0x8c, 0x7b, 0x62, 0xe4, 0x3c, 0x4b, 0x46, 0x4b, 0x2d, 0x78, 0xde, - 0xa4, 0xc6, 0xa2, 0xaf, 0x35, 0x22, 0x1d, 0x76, 0x5e, 0x62, 0xe8, 0xb7, - 0xd1, 0xdf, 0x6c, 0xf4, 0xa9, 0x39, 0x54, 0x7f, 0x72, 0x4c, 0xe2, 0xd8, - 0x9b, 0xa3, 0xc7, 0x56, 0x2a, 0xb9, 0xb4, 0x8d, 0x71, 0x83, 0x32, 0xe6, - 0x39, 0x32, 0x84, 0xeb, 0xa8, 0xc7, 0xf5, 0x13, 0xd0, 0xb1, 0xb7, 0x8e, - 0x17, 0xa6, 0xd5, 0x7c, 0xc9, 0x48, 0x86, 0xf3, 0xb5, 0x62, 0xdc, 0x05, - 0xd0, 0x65, 0x88, 0xa5, 0x64, 0x9b, 0x95, 0xc2, 0xa4, 0x21, 0xe4, 0x5b, - 0x41, 0xf1, 0xb0, 0x0f, 0xf4, 0x5b, 0xe2, 0x76, 0x1b, 0x32, 0xec, 0xde, - 0x2c, 0x45, 0x1b, 0xed, 0xd2, 0x79, 0x33, 0xe7, 0xd5, 0x4b, 0xde, 0x4a, - 0x62, 0xff, 0x94, 0xfd, 0x90, 0x8c, 0xe1, 0x1d, 0xd3, 0xe5, 0x98, 0x8f, - 0xb0, 0x77, 0xb4, 0xf1, 0x6e, 0x5d, 0xe6, 0xa0, 0x5c, 0x9a, 0x2c, 0x9a, - 0xb9, 0x72, 0x8b, 0x44, 0x66, 0x52, 0xd0, 0xfe, 0x71, 0x33, 0xff, 0xbc, - 0x25, 0xd1, 0x29, 0xea, 0x97, 0xd8, 0x91, 0xcc, 0x84, 0xb9, 0xbb, 0x7c, - 0xde, 0xcc, 0x97, 0xf9, 0x0e, 0xc6, 0x96, 0x4c, 0xf0, 0x96, 0xf7, 0xdb, - 0xc0, 0x4b, 0xea, 0x36, 0xdf, 0x81, 0x1c, 0xb0, 0x87, 0x17, 0x3d, 0xc8, - 0x45, 0xc9, 0x29, 0x09, 0x39, 0x89, 0xd1, 0xd7, 0x19, 0x93, 0xb1, 0x69, - 0x4b, 0x0a, 0xe9, 0x9b, 0x15, 0xe7, 0x0b, 0xe9, 0x25, 0x9a, 0x46, 0x27, - 0x6b, 0x69, 0xe2, 0x7b, 0xa4, 0xc9, 0xa7, 0x65, 0x6c, 0x9a, 0xb4, 0xf9, - 0xb4, 0x9c, 0x9c, 0x24, 0x8d, 0x5c, 0x87, 0xf4, 0x90, 0xae, 0x80, 0x26, - 0xbe, 0x43, 0x9a, 0x36, 0x61, 0x7e, 0x65, 0xc0, 0x46, 0x1f, 0x68, 0x18, - 0xf3, 0x2c, 0xc8, 0x26, 0x2e, 0x05, 0xbb, 0x68, 0x8c, 0xf5, 0x6e, 0x4b, - 0xc0, 0xaa, 0x8d, 0xd1, 0x5e, 0xd2, 0xeb, 0x42, 0x7e, 0x75, 0x4a, 0xce, - 0x66, 0x66, 0x9c, 0x3c, 0xc3, 0x78, 0xae, 0x8d, 0xfb, 0x92, 0x2d, 0xe3, - 0x6a, 0x3e, 0xd2, 0xf3, 0x59, 0xcc, 0x43, 0x7a, 0x2f, 0x43, 0x57, 0x7b, - 0xa0, 0xa3, 0x69, 0xf9, 0xdb, 0xf2, 0x76, 0x79, 0xbd, 0xdc, 0x25, 0xaf, - 0xc1, 0x7e, 0x5f, 0x2d, 0x27, 0xe5, 0x95, 0x72, 0xab, 0xbc, 0x5c, 0x4e, - 0xc8, 0x4b, 0x4a, 0x7f, 0xfb, 0x44, 0x9a, 0x94, 0x4e, 0xc7, 0x6e, 0x86, - 0x3e, 0xb6, 0x40, 0x1f, 0x9b, 0x61, 0x4f, 0x1b, 0x61, 0xab, 0xdf, 0x06, - 0x0f, 0xa7, 0x3b, 0x25, 0xbb, 0x09, 0xfd, 0xb7, 0x65, 0x2c, 0xa5, 0x23, - 0x16, 0x9e, 0x8f, 0x4d, 0x46, 0x25, 0x6f, 0x9f, 0x95, 0xf7, 0xa7, 0x2c, - 0x19, 0x2b, 0x3f, 0x79, 0x9b, 0xaf, 0xb3, 0x6c, 0xcf, 0xca, 0x45, 0xf4, - 0xe5, 0xed, 0x59, 0xb9, 0xb4, 0xd5, 0x94, 0xd1, 0xe9, 0xef, 0x4a, 0xee, - 0xf9, 0xb3, 0xf2, 0xd3, 0xbf, 0x16, 0x19, 0x00, 0xef, 0xcd, 0xee, 0xff, - 0xaa, 0x64, 0x6d, 0xec, 0xb1, 0x7b, 0xbb, 0x92, 0x89, 0xd9, 0x4d, 0x3d, - 0x4e, 0x02, 0x57, 0x2c, 0x23, 0xef, 0xbd, 0x00, 0x6c, 0x69, 0x34, 0x72, - 0xa7, 0x45, 0x86, 0x4f, 0x57, 0x64, 0x38, 0x1d, 0x95, 0xc7, 0xec, 0x8a, - 0xf4, 0xa5, 0xeb, 0xe4, 0xa8, 0x4d, 0xac, 0x39, 0x6e, 0x04, 0xb8, 0xfe, - 0xed, 0xf2, 0x09, 0xdc, 0xb3, 0x4f, 0x64, 0x5a, 0xdd, 0xfb, 0xfd, 0xc5, - 0x72, 0x54, 0xb2, 0x4e, 0x31, 0x61, 0x49, 0x9b, 0xe9, 0xd3, 0xf4, 0xcd, - 0xe0, 0x19, 0x78, 0x35, 0x04, 0x2c, 0xf5, 0xed, 0xaf, 0x30, 0xb9, 0xee, - 0x4a, 0x56, 0x75, 0x47, 0x29, 0x3b, 0xe8, 0x34, 0x79, 0x9d, 0x1c, 0x32, - 0x32, 0x8e, 0xb4, 0x29, 0xbc, 0xe8, 0xc1, 0x98, 0x5e, 0x63, 0x7f, 0x99, - 0x7a, 0x8e, 0xfb, 0x12, 0x69, 0xdd, 0x8c, 0xb1, 0x16, 0xae, 0x59, 0x4d, - 0x73, 0x98, 0x4e, 0xce, 0x45, 0x3a, 0x79, 0x7d, 0x21, 0x44, 0xe7, 0x5f, - 0x56, 0xef, 0xa7, 0x43, 0xf7, 0xc5, 0xf2, 0x0f, 0x1a, 0x7c, 0xfa, 0xc8, - 0xcf, 0x5e, 0xe8, 0xe3, 0x37, 0xf4, 0x5a, 0xb8, 0x2f, 0x71, 0x8d, 0xb3, - 0x15, 0x5f, 0xa7, 0x8a, 0xd7, 0x58, 0xeb, 0x62, 0x68, 0xad, 0x4b, 0xa1, - 0xb5, 0x2e, 0x85, 0xd6, 0x2a, 0x82, 0xb7, 0xb2, 0xc1, 0x74, 0xa3, 0xc0, - 0x27, 0xf6, 0x4c, 0x60, 0xce, 0x67, 0x21, 0x97, 0x9f, 0x60, 0x4c, 0x46, - 0x16, 0x3d, 0xf0, 0xe3, 0x74, 0x54, 0xf6, 0xa9, 0x67, 0xbd, 0x9a, 0xae, - 0xf0, 0xb3, 0x98, 0xec, 0x75, 0x78, 0x1f, 0x3c, 0xb3, 0xc0, 0x63, 0xb6, - 0xff, 0xe1, 0x16, 0xbf, 0xcd, 0xfb, 0xf3, 0x9a, 0xfe, 0x87, 0xfc, 0xf7, - 0xca, 0x1f, 0x28, 0x9c, 0x5c, 0x28, 0x13, 0xc7, 0x24, 0x1d, 0x71, 0xe5, - 0x48, 0x5f, 0x1a, 0x76, 0x65, 0x1b, 0xe9, 0xd1, 0xae, 0x7a, 0xf2, 0x3c, - 0x6b, 0xba, 0x8d, 0xc0, 0x0a, 0x49, 0x9a, 0xd0, 0xb3, 0x51, 0xb5, 0x97, - 0x75, 0xa6, 0x4f, 0xb3, 0xcd, 0xf6, 0x80, 0xe9, 0x36, 0xd7, 0xf4, 0xd3, - 0xde, 0x1b, 0x71, 0x4f, 0xdd, 0x7e, 0x4c, 0xcb, 0x37, 0x8e, 0x36, 0xf1, - 0xb9, 0x5f, 0xb7, 0x83, 0xe7, 0x39, 0x6b, 0x79, 0xfb, 0xed, 0x2d, 0xcb, - 0xdb, 0x01, 0x76, 0x84, 0xb1, 0x9d, 0x7b, 0x4d, 0x4a, 0xc4, 0xa5, 0xce, - 0x45, 0x41, 0x6b, 0x1a, 0xb6, 0x58, 0xaf, 0x69, 0xb8, 0x5d, 0xd3, 0x00, - 0x5a, 0x31, 0x6e, 0x54, 0xd9, 0x98, 0x12, 0x5f, 0x4d, 0x9b, 0xfc, 0x0e, - 0xee, 0xd7, 0xab, 0xe7, 0xbe, 0x2d, 0x06, 0x57, 0x31, 0x76, 0x77, 0x52, - 0xe6, 0x13, 0x90, 0x79, 0x5c, 0xe6, 0xa7, 0xc9, 0xb3, 0x54, 0xe2, 0x71, - 0x41, 0xbb, 0x94, 0x90, 0xb3, 0x93, 0x92, 0x3d, 0x7c, 0xaa, 0x57, 0xfa, - 0x60, 0x9f, 0x73, 0x93, 0x57, 0x2a, 0xe0, 0xdb, 0xbd, 0x75, 0xe2, 0x02, - 0x83, 0xe1, 0xef, 0x7b, 0xa2, 0x12, 0xc9, 0x64, 0xa0, 0x0b, 0x69, 0xe5, - 0x83, 0x97, 0xfe, 0x2c, 0xeb, 0xfe, 0x65, 0xed, 0x3a, 0xf8, 0x79, 0xcc, - 0xdb, 0x93, 0x56, 0x7a, 0x13, 0xfe, 0xcb, 0x01, 0x57, 0x72, 0xe9, 0x8f, - 0xa1, 0x5b, 0x01, 0x4d, 0x81, 0x6d, 0xd0, 0x07, 0x7d, 0x10, 0xf2, 0x6d, - 0xad, 0xc0, 0x17, 0x07, 0xf2, 0x0b, 0xfc, 0x11, 0xfd, 0x44, 0x82, 0x58, - 0x0e, 0x5b, 0xa0, 0x6f, 0x88, 0x8b, 0x39, 0x63, 0x69, 0xff, 0x11, 0xd3, - 0xfe, 0x23, 0x0e, 0xdf, 0xc1, 0xb6, 0xad, 0xdb, 0x8e, 0x6e, 0x27, 0xd0, - 0x46, 0xec, 0x31, 0x43, 0xbb, 0x7a, 0xeb, 0xf8, 0xc8, 0xb4, 0xf2, 0x49, - 0xf4, 0x67, 0xf0, 0x14, 0xf4, 0x29, 0xf4, 0x2d, 0xd8, 0x6f, 0x09, 0xeb, - 0x55, 0x31, 0x9c, 0xf2, 0x08, 0xd3, 0x43, 0x5a, 0xd6, 0x89, 0x09, 0x3f, - 0x9b, 0x75, 0x48, 0xef, 0x77, 0x20, 0x0f, 0x62, 0x25, 0xe9, 0xbe, 0x15, - 0xb4, 0x72, 0x3f, 0xff, 0x97, 0xb4, 0x72, 0xbd, 0x5a, 0x7a, 0x3f, 0x2d, - 0x66, 0x2b, 0xec, 0xc0, 0x9e, 0x33, 0xc0, 0x66, 0x31, 0xf6, 0x77, 0x0e, - 0x62, 0xcf, 0x03, 0xc0, 0xee, 0x7e, 0x60, 0xf7, 0x1e, 0x60, 0x77, 0x1f, - 0xb0, 0x3b, 0x0b, 0xec, 0xee, 0x05, 0x6e, 0xf7, 0x00, 0xb7, 0xd3, 0xe0, - 0x8d, 0x23, 0xb3, 0xc0, 0xf1, 0x59, 0xe8, 0xcb, 0x2c, 0xe6, 0x28, 0xcc, - 0x88, 0xf1, 0x35, 0xec, 0xe1, 0xe8, 0x54, 0x6a, 0x16, 0xfa, 0x9d, 0x18, - 0x32, 0xa1, 0x07, 0xe9, 0xbb, 0x61, 0x6f, 0x88, 0x9b, 0xca, 0x83, 0x32, - 0x0c, 0xbf, 0xdf, 0xb6, 0xb5, 0x1d, 0xfa, 0x84, 0x68, 0x24, 0x11, 0xe8, - 0x68, 0xbf, 0x14, 0xbc, 0x76, 0xbb, 0xcd, 0xec, 0x42, 0x5f, 0x2a, 0x89, - 0x18, 0xd5, 0x38, 0x74, 0x3a, 0x65, 0x8c, 0x9c, 0x26, 0x0f, 0x26, 0x81, - 0x83, 0x15, 0x19, 0x4f, 0x53, 0x4f, 0x2b, 0xf2, 0x5c, 0x3a, 0xd5, 0x5b, - 0x94, 0x46, 0x39, 0xe9, 0x4c, 0x2a, 0xdf, 0x6f, 0x65, 0x4e, 0x29, 0x1f, - 0x3a, 0xec, 0xe2, 0x5a, 0x6a, 0x33, 0x0a, 0xa7, 0xb9, 0xd7, 0x76, 0xfc, - 0xa2, 0x58, 0xf7, 0x57, 0x90, 0x91, 0x25, 0x7d, 0x3d, 0x62, 0x1c, 0xee, - 0x2c, 0x02, 0x39, 0x53, 0xf6, 0x22, 0x56, 0xcb, 0x4f, 0xb6, 0x27, 0xda, - 0x4d, 0x4b, 0x86, 0x2c, 0x43, 0x46, 0x61, 0x5f, 0x7d, 0xe9, 0xff, 0xa9, - 0x9c, 0x74, 0xf8, 0xbc, 0x5e, 0xfe, 0x5c, 0x61, 0x31, 0xd6, 0x9e, 0x9f, - 0xc6, 0xba, 0x51, 0xf0, 0x9b, 0xeb, 0x72, 0x1e, 0xb4, 0x81, 0x8b, 0x96, - 0x9b, 0x9a, 0x2d, 0xca, 0x2e, 0xd8, 0xe9, 0x06, 0xc9, 0x6d, 0xaf, 0x93, - 0xec, 0x40, 0x52, 0x0a, 0x53, 0xbb, 0x80, 0x8d, 0x31, 0x65, 0xab, 0x85, - 0xc1, 0xa4, 0x3c, 0x36, 0xc5, 0xbe, 0x2c, 0xf6, 0x9a, 0x3a, 0x95, 0x15, - 0xee, 0xd5, 0x90, 0xec, 0xc1, 0xac, 0x3c, 0xe6, 0x65, 0x65, 0x04, 0xf2, - 0x3a, 0x0b, 0x5e, 0x1e, 0xf2, 0x5c, 0x79, 0x0e, 0xbe, 0x26, 0x7f, 0x1a, - 0x58, 0xeb, 0xae, 0x07, 0x2e, 0xa6, 0xce, 0x31, 0xc6, 0x37, 0x19, 0x87, - 0x82, 0x97, 0x7f, 0x34, 0x45, 0x5e, 0x9a, 0x32, 0x7d, 0xaf, 0x01, 0x3c, - 0x48, 0x82, 0x77, 0xae, 0xfc, 0xb1, 0x97, 0x3a, 0x9f, 0x35, 0x81, 0xc5, - 0xe9, 0xde, 0x88, 0x34, 0x24, 0x30, 0xce, 0x1f, 0x93, 0x4f, 0x47, 0x20, - 0xd7, 0x22, 0xc6, 0xa6, 0xd0, 0xcf, 0x77, 0x1d, 0xfc, 0xb2, 0x18, 0x07, - 0x5d, 0xb5, 0x53, 0xe7, 0x67, 0x4d, 0x8e, 0x4f, 0x42, 0x3e, 0x36, 0xc6, - 0x03, 0xf8, 0x6c, 0xde, 0xa7, 0x8d, 0x02, 0x69, 0xf0, 0xa8, 0x53, 0x88, - 0x49, 0xcb, 0xc4, 0xd4, 0xf6, 0x73, 0xaf, 0x0b, 0xd7, 0xf9, 0x22, 0xc6, - 0x7f, 0x88, 0x38, 0xdc, 0x96, 0x79, 0xc8, 0xe5, 0xa7, 0xe0, 0x55, 0x36, - 0xe1, 0xb7, 0x0b, 0x33, 0xa9, 0x73, 0x8b, 0x26, 0xef, 0xdd, 0xe2, 0xa8, - 0xd9, 0x23, 0xd2, 0x4c, 0x7e, 0xa5, 0xc1, 0x2b, 0xd7, 0x36, 0xcd, 0xb4, - 0xf2, 0x65, 0xbe, 0x2d, 0xdf, 0x05, 0x9a, 0xa0, 0xf3, 0xdd, 0x61, 0x9b, - 0xa0, 0xaf, 0x0d, 0x6c, 0x22, 0x95, 0x98, 0x35, 0xe1, 0x9f, 0xbb, 0x2d, - 0x39, 0xa5, 0xda, 0xe0, 0xd1, 0x60, 0x2a, 0x91, 0x35, 0x11, 0x33, 0x95, - 0xba, 0xe4, 0xac, 0xc7, 0xf1, 0x49, 0x85, 0x51, 0xfe, 0x78, 0xc4, 0x7a, - 0x1e, 0xe3, 0xc5, 0x2e, 0xd0, 0xec, 0xdb, 0xc9, 0xdc, 0xa4, 0xa3, 0x9e, - 0x9d, 0xf4, 0xfc, 0xb8, 0xd0, 0x44, 0xec, 0x38, 0x8b, 0xd8, 0x31, 0xaf, - 0x6c, 0xc6, 0xce, 0x22, 0xd7, 0x80, 0xce, 0xfb, 0xf6, 0x32, 0x5f, 0xba, - 0x4f, 0x86, 0xcf, 0x7c, 0x3f, 0x6e, 0x22, 0xce, 0x2a, 0x38, 0xa4, 0x8b, - 0xe3, 0xcf, 0x81, 0x4e, 0xf2, 0x4e, 0x86, 0x18, 0x57, 0x21, 0x16, 0x7e, - 0x84, 0x32, 0x1e, 0xed, 0x7e, 0x88, 0x7c, 0x2b, 0x82, 0xe8, 0x53, 0x3e, - 0x8e, 0x49, 0x91, 0x71, 0xe8, 0x62, 0xe4, 0x09, 0x19, 0x9a, 0xa7, 0x2f, - 0xc4, 0xcf, 0x23, 0x26, 0x02, 0xc7, 0x94, 0xcf, 0x6a, 0x87, 0x3e, 0x14, - 0xc1, 0xef, 0x8d, 0x3a, 0x0e, 0x3b, 0x08, 0xf9, 0xf6, 0x43, 0xfe, 0x19, - 0x19, 0x39, 0x33, 0x42, 0xdd, 0xee, 0x9a, 0x97, 0x54, 0xd7, 0x49, 0xd9, - 0x66, 0xcf, 0xc1, 0x06, 0xb3, 0x83, 0x95, 0x5d, 0x66, 0x86, 0xef, 0x9c, - 0xc0, 0x3b, 0xb8, 0xce, 0x8f, 0xc8, 0xd1, 0x32, 0xfb, 0x9e, 0x05, 0xdf, - 0x11, 0x17, 0xf7, 0x1c, 0xd4, 0xf6, 0x80, 0xf9, 0xac, 0x60, 0xbe, 0x11, - 0x3d, 0x1f, 0xc7, 0x71, 0x0c, 0xdf, 0x59, 0x9a, 0x77, 0x37, 0x7d, 0x22, - 0x30, 0xa8, 0xc3, 0xac, 0xec, 0x8a, 0xe2, 0xf9, 0x73, 0x3d, 0xbc, 0xc7, - 0x3c, 0xf0, 0x89, 0xb6, 0xdb, 0x8f, 0xb1, 0x83, 0x98, 0x73, 0x9d, 0xb4, - 0xb5, 0x04, 0xf4, 0x52, 0x3f, 0x18, 0xab, 0xb0, 0x3d, 0xb2, 0xc9, 0x97, - 0xd1, 0xab, 0x11, 0xdf, 0xc7, 0xcc, 0xa2, 0x4d, 0x3b, 0x3c, 0x26, 0x79, - 0x2f, 0x85, 0x7d, 0x42, 0x06, 0xe5, 0x51, 0xbd, 0x47, 0xc8, 0x69, 0xe0, - 0x29, 0xf0, 0x41, 0x8a, 0x3e, 0x6f, 0xc8, 0x17, 0xf2, 0xe4, 0x38, 0x6c, - 0xe0, 0x71, 0x8c, 0x41, 0xbc, 0xab, 0x78, 0x60, 0x6f, 0xf2, 0xe3, 0xf5, - 0x54, 0x31, 0xcb, 0xbc, 0xb3, 0x99, 0xba, 0x0d, 0xdc, 0x2a, 0x0f, 0xd8, - 0x9c, 0x7b, 0xd6, 0x64, 0x7e, 0x92, 0x4a, 0x5e, 0x88, 0xec, 0x67, 0xbb, - 0x6b, 0xd6, 0x84, 0x8c, 0x20, 0xc7, 0xdc, 0xf6, 0x76, 0x8d, 0x55, 0xef, - 0x28, 0x5d, 0xa6, 0xde, 0x17, 0xbc, 0x6d, 0xf6, 0x43, 0x42, 0x5d, 0x76, - 0xa0, 0x17, 0xc4, 0x0b, 0x5e, 0x2d, 0xf8, 0xee, 0x04, 0x74, 0x61, 0xbd, - 0xa6, 0x9d, 0xf7, 0x96, 0xcc, 0xda, 0x58, 0xc3, 0xfb, 0x8f, 0x0d, 0x7e, - 0x1f, 0xef, 0x19, 0x33, 0x05, 0x72, 0x0c, 0x68, 0xa5, 0x3c, 0x6b, 0x65, - 0xf8, 0x24, 0x68, 0x67, 0x3f, 0xae, 0xf3, 0xc7, 0x60, 0xa7, 0xc0, 0x94, - 0x9e, 0x8e, 0xc4, 0x45, 0x8c, 0xcf, 0x03, 0xf7, 0x8b, 0x16, 0x9f, 0x5d, - 0x31, 0x96, 0xde, 0x31, 0x19, 0x27, 0x23, 0x1e, 0xbf, 0x60, 0x7c, 0x0d, - 0xb1, 0x4e, 0x6e, 0xfe, 0x8a, 0x91, 0x87, 0x5e, 0xcc, 0x7b, 0x77, 0x43, - 0x9f, 0x68, 0x57, 0x36, 0xd6, 0x4e, 0x25, 0xfe, 0xc9, 0x6c, 0x4f, 0xce, - 0x01, 0x03, 0x0e, 0x81, 0xb1, 0xbe, 0x2c, 0x5d, 0x25, 0xdb, 0x45, 0x33, - 0xaa, 0xf1, 0x8f, 0xed, 0x94, 0xfd, 0xb0, 0xc0, 0x58, 0x1a, 0xf6, 0x80, - 0xcf, 0x7b, 0x64, 0xb8, 0x9c, 0x91, 0xc2, 0x99, 0x6d, 0xf6, 0x28, 0x72, - 0xf5, 0x25, 0xda, 0x89, 0x75, 0x45, 0x60, 0x1d, 0xfc, 0xb7, 0x27, 0xc5, - 0xba, 0x0c, 0x31, 0xaf, 0x03, 0xfa, 0x84, 0xbe, 0xd2, 0x92, 0x4e, 0xde, - 0xbf, 0x62, 0x3f, 0xf4, 0xdb, 0xcb, 0xf7, 0x34, 0x2f, 0xd7, 0xde, 0xd3, - 0xee, 0xea, 0x9e, 0x88, 0x31, 0xf0, 0x03, 0x1e, 0xfc, 0x00, 0x74, 0xfa, - 0x75, 0x0f, 0x7e, 0xc0, 0x83, 0x1f, 0x80, 0x3d, 0xbe, 0x02, 0x7d, 0x7c, - 0xd9, 0x83, 0x2f, 0xf0, 0xe0, 0x0b, 0x3c, 0xf8, 0x02, 0x2f, 0x07, 0xd9, - 0x11, 0xef, 0xe9, 0x4b, 0x0e, 0x54, 0xfd, 0xa7, 0x1f, 0x83, 0xdd, 0xa2, - 0xe3, 0x1a, 0xd8, 0xae, 0xbd, 0x59, 0x46, 0xbb, 0x98, 0x13, 0x35, 0xe0, - 0xda, 0x88, 0x2b, 0x62, 0x98, 0xae, 0x2f, 0x69, 0xdb, 0x79, 0x1c, 0x74, - 0x01, 0x17, 0xba, 0xbe, 0x08, 0xdd, 0x44, 0x1c, 0xe1, 0xfe, 0x86, 0x8e, - 0x7f, 0x7e, 0x64, 0xf9, 0xba, 0xd9, 0x88, 0xbe, 0xfb, 0xd0, 0xd7, 0x88, - 0x31, 0x47, 0x31, 0x86, 0xf1, 0x53, 0x93, 0xee, 0x0b, 0x8f, 0x63, 0x1c, - 0xf5, 0x00, 0xd6, 0x4a, 0x61, 0x5c, 0x13, 0xe6, 0x6e, 0xc5, 0x98, 0x9d, - 0x18, 0x73, 0x2b, 0xda, 0x8c, 0xb9, 0xb7, 0xa0, 0x7d, 0x4f, 0xcd, 0x3b, - 0xb7, 0xa3, 0xef, 0x4b, 0x35, 0x7d, 0x8b, 0xe8, 0xeb, 0x41, 0xdf, 0x45, - 0xfd, 0x5e, 0x11, 0xed, 0x96, 0x9a, 0x31, 0x97, 0xd1, 0x87, 0xb8, 0xd9, - 0xfe, 0x7b, 0x5c, 0xfb, 0x71, 0x25, 0x4d, 0xc1, 0x33, 0xc6, 0xcd, 0xc8, - 0x41, 0xab, 0xb1, 0xef, 0x5b, 0x8c, 0x0b, 0xe1, 0x7b, 0x7f, 0x6c, 0xf9, - 0x71, 0xe3, 0x77, 0x6d, 0x5f, 0x57, 0x83, 0xf6, 0x8f, 0x6a, 0xda, 0x1c, - 0xfb, 0xdf, 0x35, 0x7d, 0x3b, 0x36, 0x2e, 0x6f, 0xdf, 0x59, 0xb7, 0xf2, - 0x9d, 0x89, 0x9a, 0x31, 0x2f, 0x37, 0x2f, 0x6f, 0xff, 0xe9, 0x2a, 0xef, - 0xec, 0xd9, 0xb0, 0xbc, 0xef, 0xd1, 0x4d, 0x35, 0x63, 0xa0, 0x53, 0x0e, - 0x72, 0xab, 0x60, 0xfc, 0x03, 0x37, 0xf9, 0xcf, 0xc9, 0xdf, 0x5a, 0x5d, - 0x52, 0x5b, 0x47, 0xdb, 0x84, 0x1c, 0x2e, 0x18, 0xb0, 0x39, 0xdb, 0xcc, - 0x5c, 0x32, 0xf2, 0xd0, 0xa9, 0x5c, 0x39, 0x98, 0x8f, 0xb6, 0x5c, 0x5b, - 0xdb, 0x08, 0x6a, 0x1a, 0x8c, 0xbb, 0xe2, 0xd0, 0x9b, 0xfd, 0x90, 0x71, - 0x6a, 0xa2, 0x28, 0x4b, 0x36, 0xdc, 0x66, 0xae, 0x65, 0xc3, 0x4f, 0x6b, - 0xdc, 0x7a, 0x0a, 0x74, 0x56, 0x64, 0x20, 0x5d, 0x4f, 0xff, 0xa4, 0xf1, - 0x8c, 0x58, 0x54, 0xa9, 0x44, 0xb6, 0x56, 0xe4, 0x48, 0xfa, 0xc3, 0x8a, - 0x28, 0x1c, 0x9c, 0x50, 0x58, 0x94, 0x34, 0xdb, 0x21, 0x23, 0x1b, 0xb9, - 0x8d, 0x23, 0x43, 0x0e, 0xfd, 0xd9, 0x31, 0xc6, 0x29, 0x27, 0x7c, 0x9c, - 0x25, 0x16, 0xa1, 0x8d, 0xbc, 0xae, 0x70, 0xda, 0x50, 0x31, 0x70, 0x61, - 0x9e, 0xd8, 0x4e, 0x3c, 0x85, 0xdf, 0xb6, 0x39, 0xef, 0x6a, 0x78, 0x19, - 0x8b, 0x32, 0x3e, 0xb4, 0xdc, 0x17, 0xe0, 0x1b, 0xf9, 0x8c, 0x71, 0x04, - 0xee, 0x4b, 0xaa, 0xae, 0x56, 0x5c, 0xbe, 0x97, 0xcd, 0xcc, 0x43, 0xae, - 0x63, 0x7f, 0xab, 0x63, 0x54, 0xbb, 0x79, 0x6d, 0x7b, 0xde, 0x5b, 0xb5, - 0xe7, 0x40, 0xdf, 0x56, 0xab, 0x59, 0xbc, 0xa3, 0xf8, 0xff, 0x52, 0x39, - 0x75, 0xaa, 0x08, 0xfb, 0x59, 0x50, 0x39, 0x7a, 0x20, 0x0b, 0xc6, 0x3c, - 0xa9, 0x67, 0x66, 0xe9, 0x2d, 0x54, 0x8e, 0xc2, 0xfc, 0xa4, 0x22, 0xbb, - 0xd3, 0xff, 0xa6, 0xf6, 0x9e, 0x35, 0x3b, 0xeb, 0x18, 0x63, 0x2c, 0x78, - 0xe4, 0x53, 0x1a, 0xcf, 0x11, 0xfb, 0xa7, 0x7f, 0x26, 0x79, 0x87, 0x7d, - 0xbf, 0xac, 0xcc, 0x21, 0x36, 0x52, 0xf1, 0x92, 0x8a, 0x0f, 0x18, 0xef, - 0x1d, 0x01, 0x8f, 0xc8, 0xc7, 0x01, 0xf0, 0x36, 0x88, 0x19, 0xfe, 0x91, - 0xbe, 0x58, 0x96, 0xc7, 0xd1, 0xc8, 0xb4, 0x4a, 0x97, 0x30, 0xa7, 0x89, - 0xf9, 0xe8, 0xe3, 0xe8, 0x47, 0xd8, 0x5f, 0x88, 0x32, 0xb6, 0xf3, 0x63, - 0x83, 0x08, 0xd6, 0xb3, 0x80, 0x83, 0xef, 0x0a, 0x63, 0x9a, 0x61, 0x25, - 0x03, 0x62, 0x29, 0x9f, 0xb1, 0x2f, 0xa6, 0x63, 0xef, 0xb8, 0x8e, 0xb5, - 0x6d, 0x1d, 0x6b, 0x93, 0x0e, 0xd6, 0x2d, 0x83, 0x38, 0x82, 0x72, 0xba, - 0x70, 0xdc, 0xdc, 0xca, 0x38, 0xa2, 0x49, 0x56, 0x8f, 0x23, 0x02, 0x9a, - 0x76, 0x82, 0x26, 0xc6, 0x7d, 0xaa, 0x4e, 0xd5, 0xec, 0xd7, 0xc6, 0x48, - 0x43, 0xe0, 0x27, 0x95, 0x3f, 0x9e, 0x80, 0xeb, 0xc3, 0xde, 0x10, 0x48, - 0x02, 0xdb, 0x73, 0x93, 0x3b, 0xb5, 0xdf, 0x65, 0x0e, 0xc1, 0xf8, 0xdd, - 0xd7, 0xd3, 0x5c, 0x7a, 0x34, 0x98, 0xa7, 0x05, 0x9e, 0x32, 0x54, 0x43, - 0xe3, 0x5a, 0x8c, 0x7b, 0x82, 0x18, 0x68, 0x8f, 0x8e, 0x81, 0xfa, 0xe5, - 0x88, 0xe7, 0xe7, 0x0c, 0x03, 0xa5, 0x01, 0xf4, 0x29, 0xda, 0x13, 0x8c, - 0x35, 0x4d, 0x93, 0xb1, 0x66, 0x0a, 0xc9, 0x87, 0xbf, 0x97, 0xb6, 0xad, - 0xac, 0x65, 0x06, 0x7b, 0x69, 0xbc, 0xb0, 0x7c, 0x2f, 0xbb, 0x94, 0xde, - 0x9b, 0xe0, 0x9d, 0x8f, 0x4d, 0x9c, 0xf3, 0x7c, 0x94, 0xb8, 0x35, 0x50, - 0x1a, 0x54, 0xf3, 0x8e, 0xaf, 0x98, 0x57, 0xb0, 0xc7, 0x03, 0x6b, 0x3c, - 0xe3, 0xfe, 0x19, 0x5b, 0xd8, 0x7a, 0xff, 0x81, 0x0c, 0x2f, 0x63, 0xce, - 0x2e, 0xa3, 0xa0, 0xe2, 0xb6, 0x83, 0x4a, 0x1e, 0x85, 0xd2, 0x10, 0xae, - 0xb4, 0x17, 0x35, 0x8f, 0xb2, 0x99, 0x51, 0x25, 0x83, 0x11, 0xb5, 0xc7, - 0xb9, 0xd2, 0x23, 0x88, 0xd7, 0xbe, 0x0e, 0x3f, 0x18, 0xae, 0x2b, 0x3a, - 0x18, 0x43, 0x5e, 0x15, 0x43, 0x78, 0x4a, 0x9a, 0x59, 0x33, 0xbc, 0x82, - 0x35, 0xb8, 0xe7, 0x38, 0xe4, 0x6f, 0xf8, 0xcf, 0xd5, 0xfa, 0x01, 0xcf, - 0xeb, 0x42, 0xf4, 0x54, 0x10, 0xbf, 0x26, 0x40, 0x43, 0xf8, 0x9d, 0x63, - 0xd2, 0xe7, 0x51, 0x56, 0xed, 0x89, 0x11, 0xe4, 0xbb, 0x05, 0x09, 0x62, - 0x11, 0xae, 0x4f, 0x0c, 0xc8, 0x23, 0x97, 0x4a, 0x60, 0x7f, 0x01, 0x5f, - 0x03, 0x9e, 0xc6, 0x2f, 0xd4, 0xea, 0xc7, 0x38, 0xe8, 0x19, 0xf6, 0xc8, - 0xa7, 0x40, 0x6f, 0x83, 0xb5, 0x2f, 0xab, 0xfd, 0x8c, 0xa9, 0xda, 0xe7, - 0xfa, 0xba, 0x40, 0x7f, 0x47, 0x11, 0xb7, 0xf8, 0xfa, 0xf8, 0x7b, 0x9a, - 0x37, 0x81, 0xde, 0xc6, 0xb5, 0x0e, 0x30, 0x47, 0xa4, 0x5d, 0x05, 0x3a, - 0xd2, 0x61, 0xef, 0x57, 0xbc, 0xe0, 0x33, 0x95, 0x13, 0x2a, 0x39, 0x0f, - 0x55, 0xe5, 0xbc, 0xbe, 0x46, 0x67, 0x3b, 0x6d, 0xdf, 0x46, 0x69, 0x8b, - 0xb0, 0x69, 0xd0, 0xf7, 0xd2, 0x32, 0xdb, 0xef, 0x5a, 0xa3, 0xae, 0x1c, - 0x97, 0xc8, 0xcc, 0x0f, 0xc0, 0xcb, 0xdb, 0x91, 0xd7, 0x20, 0xcb, 0x9f, - 0x22, 0x46, 0x31, 0xfe, 0x58, 0x8a, 0x89, 0xe7, 0x64, 0xb5, 0x78, 0xf8, - 0x5a, 0xb1, 0xc7, 0x9d, 0xd7, 0x19, 0x7b, 0xfc, 0x49, 0x1d, 0xf3, 0x9c, - 0x05, 0xd8, 0xe9, 0x21, 0xbc, 0x5f, 0xe7, 0xfe, 0x10, 0x3e, 0xed, 0xaf, - 0xac, 0x7a, 0x37, 0xc0, 0x8b, 0xb8, 0x6c, 0x9c, 0xd9, 0xac, 0x30, 0xc3, - 0x9e, 0x5a, 0xc2, 0x8c, 0x51, 0xcf, 0xd7, 0x5f, 0xf0, 0xca, 0xd9, 0x28, - 0xd7, 0x9b, 0x77, 0x2f, 0xe5, 0x10, 0x43, 0xd5, 0x1c, 0xe2, 0x96, 0x1a, - 0x3e, 0xae, 0x86, 0x99, 0xe7, 0x54, 0xbe, 0xfc, 0x6a, 0x39, 0xf5, 0x82, - 0x48, 0x1f, 0xf2, 0xe4, 0xd4, 0x79, 0x91, 0x2c, 0x72, 0x65, 0xe6, 0x73, - 0x7b, 0x90, 0x3b, 0xa7, 0x7e, 0x21, 0xd2, 0x8b, 0x9c, 0x99, 0xf9, 0x70, - 0x3f, 0xf8, 0xda, 0x03, 0x4c, 0x4d, 0x03, 0x63, 0xb7, 0x83, 0xbf, 0x5d, - 0x0a, 0x57, 0x0f, 0x9d, 0x46, 0xae, 0xad, 0xea, 0xec, 0xb4, 0x75, 0x07, - 0x7e, 0xb5, 0x52, 0x79, 0x2c, 0xdd, 0x8e, 0x7c, 0x3f, 0x29, 0x5f, 0xb6, - 0x98, 0xf3, 0x1a, 0x56, 0xae, 0x7b, 0x26, 0x12, 0x8e, 0x63, 0x0b, 0xd7, - 0xf4, 0x11, 0x2b, 0x79, 0x3f, 0xac, 0xfc, 0xc4, 0x78, 0xe4, 0x6a, 0xbc, - 0xdf, 0x5f, 0xe5, 0xfd, 0x9d, 0x0d, 0xd2, 0xd0, 0xaf, 0xea, 0x0b, 0xb9, - 0xee, 0xaf, 0x13, 0xcb, 0xd2, 0xf0, 0xf3, 0xf0, 0xc7, 0x15, 0xb9, 0x3f, - 0x7d, 0xa5, 0x72, 0xd1, 0xdd, 0x20, 0x85, 0xed, 0x07, 0x34, 0x9e, 0x1f, - 0x78, 0x32, 0xe7, 0x16, 0x61, 0x1f, 0xfa, 0xdb, 0xc2, 0x64, 0x0c, 0x51, - 0x29, 0xff, 0x9a, 0x65, 0xae, 0xf7, 0xf6, 0x7a, 0x69, 0xd8, 0xf6, 0x02, - 0x8b, 0x63, 0xc4, 0x99, 0x39, 0x27, 0xae, 0xea, 0xdd, 0x37, 0xb9, 0xec, - 0xb7, 0x21, 0xd3, 0xdf, 0x92, 0x39, 0xc4, 0x13, 0xf3, 0xbd, 0xa0, 0x71, - 0x7b, 0x0b, 0xc6, 0xd3, 0xee, 0xc8, 0xf3, 0xdf, 0x96, 0xa1, 0x41, 0xf2, - 0xd4, 0xc1, 0xf8, 0xfb, 0x31, 0xa6, 0x19, 0xd7, 0x07, 0x23, 0x73, 0x76, - 0xcc, 0x6f, 0x0f, 0x70, 0x0e, 0xfa, 0x52, 0xce, 0xc3, 0xb5, 0x5a, 0x94, - 0xcd, 0x2f, 0xcd, 0xcf, 0xb9, 0xf9, 0xec, 0xe3, 0xca, 0xbe, 0xee, 0xee, - 0xd0, 0x1a, 0x4d, 0xa1, 0x35, 0x7a, 0x42, 0x6b, 0x90, 0xb6, 0xe6, 0x10, - 0x6d, 0xcd, 0x78, 0xff, 0x3e, 0xac, 0xd7, 0xaf, 0xe3, 0x94, 0x60, 0x9d, - 0x60, 0x1f, 0x2d, 0xa1, 0xb1, 0x1f, 0x62, 0x0d, 0xf6, 0x39, 0xa1, 0x3e, - 0xae, 0x0b, 0x1c, 0x73, 0xd8, 0x6e, 0x0e, 0xd1, 0x42, 0xfa, 0x1a, 0xd0, - 0xaf, 0xe6, 0x02, 0x3f, 0x1b, 0xe0, 0xbb, 0x4c, 0xf8, 0x8f, 0x08, 0xe2, - 0xaa, 0x60, 0x4f, 0xc1, 0x1c, 0x0e, 0xde, 0xe3, 0x18, 0xff, 0xb9, 0xff, - 0x0e, 0xfb, 0xf9, 0x3c, 0x22, 0xdf, 0x53, 0xf4, 0xb2, 0xcd, 0x3d, 0x34, - 0x81, 0x56, 0x5e, 0x53, 0x32, 0xdb, 0x0c, 0xd9, 0x77, 0x33, 0x9f, 0x36, - 0xe4, 0x36, 0xd7, 0x34, 0xf2, 0xdd, 0x94, 0xef, 0x06, 0x8d, 0x97, 0x0d, - 0x46, 0xee, 0x34, 0x6b, 0x08, 0x8d, 0x3a, 0xf7, 0x43, 0xbe, 0xa1, 0x7c, - 0x4c, 0xe0, 0x03, 0xe8, 0x63, 0x18, 0xab, 0xd0, 0x7f, 0x66, 0xf5, 0x3d, - 0xae, 0xd0, 0xd3, 0xc3, 0xf3, 0xcd, 0x72, 0x51, 0xf1, 0xd0, 0x96, 0xc5, - 0x2a, 0x0f, 0xa3, 0xfa, 0xbb, 0xd1, 0x31, 0xfd, 0x4d, 0x66, 0x3f, 0xe2, - 0x01, 0xdc, 0x97, 0x80, 0xb9, 0xdd, 0xd0, 0xb7, 0x6e, 0xe6, 0x70, 0x45, - 0x5c, 0x59, 0xc3, 0x30, 0x70, 0x75, 0x70, 0x8d, 0xe1, 0x0a, 0xbf, 0x04, - 0xac, 0xc9, 0x77, 0xbf, 0x0d, 0x1d, 0x82, 0x6c, 0xca, 0xb6, 0x71, 0xbf, - 0xe7, 0xd7, 0x87, 0x16, 0xdd, 0xd5, 0xeb, 0x43, 0x8b, 0xa2, 0xea, 0x43, - 0x13, 0xd7, 0xa8, 0x0f, 0x65, 0xaf, 0xbf, 0x3e, 0x74, 0xa2, 0x9e, 0x18, - 0xbc, 0xb7, 0x47, 0x8c, 0xdf, 0xd5, 0xf5, 0xa1, 0xf7, 0xc5, 0xaf, 0x0f, - 0x5d, 0x94, 0xd5, 0xeb, 0x43, 0x13, 0x35, 0xf5, 0xa1, 0x8d, 0xaa, 0x3e, - 0xc4, 0x79, 0xfc, 0xfa, 0x10, 0xdb, 0x6d, 0xdd, 0xbd, 0xa1, 0x3a, 0x08, - 0xf0, 0x54, 0xe5, 0x84, 0xb6, 0x31, 0xe8, 0x05, 0x18, 0x45, 0x2c, 0xbf, - 0xb9, 0xea, 0x8f, 0x96, 0xf0, 0xca, 0x50, 0xba, 0x75, 0x2d, 0xbc, 0x1a, - 0xf4, 0x63, 0x90, 0x65, 0x58, 0x35, 0x5e, 0x8d, 0x53, 0x5e, 0xab, 0x67, - 0xde, 0x3c, 0x56, 0x5a, 0x9a, 0x77, 0x0c, 0xb2, 0x1d, 0xaa, 0xd6, 0x50, - 0xd6, 0x8a, 0x85, 0x1c, 0x39, 0xb6, 0xea, 0x37, 0xb8, 0x44, 0x76, 0xe5, - 0x37, 0x38, 0x43, 0x1c, 0xd0, 0xd9, 0xd6, 0x5d, 0x50, 0x79, 0xd5, 0x9c, - 0xf7, 0x55, 0xb9, 0xf0, 0xb0, 0x0d, 0x3c, 0x09, 0x6a, 0x26, 0x94, 0xe5, - 0x92, 0x8f, 0x28, 0x98, 0x9f, 0x5f, 0xdd, 0xe4, 0xb0, 0xaa, 0x9b, 0xfc, - 0xbc, 0x3e, 0x5c, 0x37, 0x59, 0x94, 0xab, 0xd7, 0x4d, 0x0e, 0xaf, 0x52, - 0x37, 0x79, 0x53, 0x96, 0xea, 0x26, 0x6f, 0x4a, 0x50, 0x37, 0x89, 0xc8, - 0x85, 0x4d, 0x9c, 0xe7, 0x08, 0xde, 0x19, 0xc0, 0xaf, 0x1f, 0x3f, 0xbf, - 0x8e, 0xb2, 0x58, 0xa5, 0x7f, 0xb5, 0x3a, 0x4a, 0x7d, 0xec, 0x93, 0xd4, - 0x51, 0x7c, 0x4c, 0x0f, 0xea, 0x28, 0x0d, 0x88, 0x5f, 0xe0, 0x43, 0xcc, - 0x70, 0x1d, 0xa5, 0x15, 0xf3, 0xb2, 0x8f, 0x6d, 0xf6, 0xc3, 0x2e, 0xe0, - 0x67, 0xb2, 0xaa, 0xce, 0xf1, 0x9b, 0x9a, 0x87, 0x07, 0xb0, 0xe7, 0x24, - 0x64, 0x41, 0x3e, 0xb6, 0xab, 0x38, 0x32, 0x6b, 0x25, 0x8c, 0x5c, 0x27, - 0xbc, 0xd3, 0x24, 0xbf, 0xd9, 0x27, 0x64, 0xa4, 0x4c, 0x1d, 0x6f, 0x45, - 0xdc, 0x6d, 0xa1, 0xef, 0x00, 0xda, 0x41, 0x8c, 0xd4, 0x5d, 0x9d, 0x83, - 0x76, 0x38, 0xc7, 0x7a, 0x9f, 0x73, 0x3d, 0x3e, 0x67, 0x27, 0x68, 0x0e, - 0xef, 0xa3, 0x08, 0x7f, 0x83, 0x3e, 0x25, 0x73, 0xc6, 0x8a, 0x01, 0x2d, - 0x49, 0xda, 0xf4, 0x75, 0xcc, 0xc7, 0xbe, 0x9d, 0x2a, 0xdf, 0x1a, 0xee, - 0xe1, 0x5e, 0xe9, 0xbb, 0x16, 0x40, 0x1f, 0xfa, 0xe6, 0x99, 0xe3, 0xd1, - 0x8f, 0x05, 0x39, 0x58, 0x5c, 0xe5, 0x60, 0x2d, 0x8a, 0x1f, 0xe4, 0xf5, - 0x23, 0x31, 0xe2, 0x63, 0x8b, 0xcb, 0x3d, 0xf4, 0x6b, 0x5c, 0x63, 0xdb, - 0xcf, 0xf5, 0x58, 0x8f, 0x6e, 0x71, 0x9f, 0x80, 0x5c, 0x59, 0xab, 0x09, - 0xe4, 0xf7, 0x0d, 0xbd, 0xef, 0x5e, 0x29, 0xb6, 0x48, 0x6c, 0x23, 0xe8, - 0x69, 0x9b, 0x62, 0x8c, 0x7d, 0x8f, 0xca, 0x37, 0x1c, 0x77, 0x6d, 0xbb, - 0xdd, 0x7f, 0x03, 0x76, 0x3b, 0x70, 0x55, 0xbb, 0x3d, 0x1b, 0x0b, 0xdb, - 0xed, 0xfe, 0x1b, 0xb0, 0xdb, 0x23, 0x37, 0x64, 0xb7, 0xdc, 0x1b, 0x31, - 0x29, 0xa8, 0x8b, 0xad, 0x8c, 0x9b, 0x82, 0x75, 0x47, 0xb1, 0x66, 0x76, - 0x8d, 0x35, 0x87, 0xd6, 0xac, 0xbb, 0xd6, 0xc6, 0x4c, 0xd7, 0x23, 0x6f, - 0xe6, 0x21, 0xf4, 0xab, 0x71, 0xed, 0x83, 0x9e, 0xd6, 0x3a, 0x1f, 0xe4, - 0xed, 0x61, 0xfb, 0xa1, 0x5e, 0x50, 0x17, 0x7e, 0x02, 0x7e, 0x51, 0x1f, - 0x02, 0x9b, 0x6b, 0xaf, 0xd1, 0xc1, 0x05, 0xe4, 0xf3, 0xed, 0x5a, 0x07, - 0x29, 0xeb, 0x4e, 0xf5, 0x3d, 0x69, 0xde, 0x7b, 0xc2, 0xcf, 0xe3, 0xa1, - 0x03, 0x85, 0xf9, 0xc0, 0xd6, 0x92, 0x58, 0x37, 0x78, 0x46, 0x3e, 0xba, - 0x88, 0x61, 0xb6, 0x21, 0xfe, 0x02, 0x8f, 0x54, 0xff, 0xf2, 0x3a, 0xf0, - 0xd5, 0xf1, 0x4c, 0x8a, 0x51, 0x8c, 0x7d, 0xae, 0x07, 0x36, 0xde, 0x43, - 0x8c, 0xca, 0x20, 0x8f, 0xa1, 0x1e, 0x52, 0x37, 0x3b, 0xba, 0x0e, 0x99, - 0x8c, 0x91, 0x0e, 0xc2, 0xf6, 0x6c, 0xa5, 0xc7, 0xbb, 0xcb, 0x1d, 0xe7, - 0x16, 0x4d, 0xae, 0x51, 0xa9, 0x14, 0x54, 0xbd, 0x5e, 0xcc, 0x5c, 0xf7, - 0x4d, 0xeb, 0xe8, 0x97, 0x6e, 0x76, 0x23, 0x5a, 0xd7, 0xb2, 0xb8, 0xa7, - 0xde, 0xfe, 0x2b, 0x7c, 0x3b, 0xf2, 0x89, 0xee, 0x7f, 0x41, 0x7f, 0x02, - 0x36, 0x4f, 0x5f, 0xce, 0xfc, 0x62, 0x87, 0x1e, 0xd7, 0xae, 0xbe, 0x95, - 0xaa, 0xef, 0x2d, 0x4e, 0xe0, 0x7f, 0x52, 0xf4, 0xcf, 0xcb, 0xe4, 0xcc, - 0xb3, 0x1b, 0x79, 0x95, 0x9f, 0xf0, 0x7d, 0xa5, 0x93, 0xc8, 0x29, 0xac, - 0x50, 0x9d, 0x3d, 0xa6, 0x73, 0x31, 0xda, 0x58, 0x5c, 0xe5, 0x89, 0x7e, - 0xee, 0xc1, 0x5c, 0x75, 0xf9, 0x99, 0x8d, 0xd5, 0x75, 0x60, 0xf3, 0x27, - 0xd0, 0x81, 0x5a, 0xf9, 0xc5, 0x60, 0xfb, 0x81, 0xfc, 0x82, 0x98, 0x65, - 0x56, 0xef, 0xbb, 0xdd, 0x97, 0xe1, 0xff, 0x8b, 0x7d, 0x1a, 0xa1, 0x7d, - 0x06, 0x78, 0x74, 0x58, 0xef, 0x73, 0x47, 0x0d, 0x1e, 0x0d, 0xd4, 0xd8, - 0xec, 0xe7, 0x89, 0x47, 0x97, 0xd7, 0x7d, 0xfe, 0x78, 0xc4, 0x7d, 0x6d, - 0x59, 0x15, 0x87, 0xfc, 0x7d, 0x3c, 0x2d, 0x66, 0xe6, 0xb3, 0xcc, 0xdf, - 0x3e, 0x89, 0x7c, 0xc2, 0x38, 0x42, 0x99, 0x34, 0xa9, 0x78, 0xd5, 0xb7, - 0x3d, 0xf8, 0xf2, 0xf9, 0xa8, 0xbc, 0xf7, 0x50, 0x4c, 0x7e, 0x75, 0x2f, - 0xbf, 0x95, 0x59, 0xba, 0x7e, 0xc5, 0x76, 0xb4, 0xc1, 0xf7, 0x43, 0x48, - 0x24, 0x94, 0xdf, 0xe1, 0x3b, 0x81, 0x3d, 0xdb, 0x78, 0xce, 0x67, 0x5b, - 0xe4, 0x42, 0xf3, 0x8d, 0xe4, 0x74, 0x1d, 0xf6, 0xfb, 0xe6, 0x6a, 0x39, - 0xdd, 0xd5, 0x6b, 0x7f, 0x4b, 0x39, 0x1d, 0x71, 0xb6, 0x59, 0xd7, 0x7b, - 0x98, 0xd7, 0xec, 0xd7, 0xd8, 0xc9, 0x7b, 0xe4, 0xaa, 0x1e, 0xf2, 0x57, - 0xc8, 0xf6, 0x35, 0xc4, 0x4b, 0xaf, 0x7a, 0xc8, 0x59, 0x3d, 0xe4, 0xaa, - 0x1e, 0x72, 0x55, 0x0f, 0xb9, 0xaa, 0xd7, 0xa5, 0x73, 0xde, 0x01, 0x5d, - 0xd7, 0xe7, 0xf7, 0x70, 0xd6, 0x0b, 0x8a, 0xf0, 0x25, 0xe3, 0x3c, 0x63, - 0x61, 0xe6, 0xd2, 0xeb, 0x82, 0x73, 0x48, 0xba, 0xe6, 0xdd, 0xaa, 0x6b, - 0x30, 0x75, 0x37, 0x29, 0xdf, 0x6c, 0xbe, 0xd1, 0xe0, 0x7f, 0x33, 0xe7, - 0xf9, 0x8f, 0x3f, 0x44, 0x5c, 0xc2, 0x1a, 0xd8, 0x04, 0x6d, 0xb4, 0x62, - 0x66, 0x58, 0x63, 0x11, 0xd3, 0xcc, 0x7c, 0x01, 0xef, 0x6c, 0xc3, 0x1e, - 0xea, 0x69, 0xdb, 0x11, 0x33, 0xd3, 0x48, 0x9e, 0x1a, 0x66, 0x66, 0xbd, - 0x9e, 0xeb, 0x6f, 0x1a, 0xfc, 0xd8, 0xaa, 0x93, 0x6d, 0xcb, 0x64, 0x9c, - 0xa0, 0x62, 0xed, 0xa0, 0x7f, 0x4f, 0xf3, 0xf2, 0xb5, 0xa2, 0x0a, 0xdf, - 0x73, 0xe9, 0x87, 0x31, 0x9f, 0x3a, 0xdb, 0x54, 0xe5, 0xb7, 0xb9, 0x26, - 0xbf, 0xa3, 0x9a, 0xdf, 0x3e, 0x8f, 0x23, 0x1c, 0xa7, 0xea, 0xbe, 0xe4, - 0x75, 0x30, 0x9f, 0xaa, 0xe1, 0x61, 0x1d, 0x75, 0x8e, 0x03, 0xd7, 0xbb, - 0xa2, 0xd2, 0x34, 0x78, 0x20, 0xea, 0x86, 0xd7, 0x25, 0x46, 0xf5, 0x2e, - 0xfb, 0xfe, 0xb4, 0xf6, 0x9a, 0xed, 0xea, 0xdb, 0x99, 0xef, 0x33, 0xa2, - 0x4a, 0x07, 0x2d, 0x75, 0x36, 0xef, 0xd7, 0xea, 0xcc, 0x0d, 0xf5, 0x2f, - 0x8f, 0x3c, 0x66, 0xbc, 0xa7, 0x23, 0x69, 0x99, 0x7f, 0xd1, 0xc0, 0x5a, - 0x6b, 0x5f, 0x39, 0xc0, 0x3d, 0xae, 0x57, 0xeb, 0xc7, 0x59, 0x27, 0x0b, - 0xf0, 0x4c, 0x36, 0xfb, 0xf5, 0xb3, 0x4f, 0x63, 0x4b, 0x0d, 0x35, 0xb6, - 0x14, 0xec, 0xd3, 0xcf, 0x57, 0xf9, 0xdd, 0x7a, 0xb5, 0xb3, 0x13, 0x0b, - 0xe5, 0xd0, 0xf7, 0x8f, 0xaa, 0x6e, 0xf0, 0x5c, 0xcb, 0x83, 0xd0, 0x41, - 0xd6, 0xfe, 0xf7, 0xc0, 0x8e, 0x2a, 0x95, 0x3e, 0xd6, 0x93, 0xb7, 0x3f, - 0xa0, 0xcf, 0x27, 0x3c, 0xa3, 0xea, 0x09, 0xd6, 0x8a, 0x7a, 0x42, 0x1f, - 0x74, 0x05, 0x31, 0x00, 0x6c, 0xb0, 0xa0, 0x64, 0xc9, 0x78, 0xa0, 0xf6, - 0xfb, 0xca, 0xf9, 0x46, 0x9f, 0x0f, 0xb7, 0x37, 0xfa, 0xdf, 0x18, 0x7e, - 0xe9, 0x2c, 0x6f, 0xf3, 0xfd, 0x44, 0x63, 0x70, 0xce, 0x67, 0xf8, 0x4c, - 0x1f, 0x74, 0xb1, 0x4e, 0xf2, 0x6a, 0x3e, 0xc4, 0xbb, 0xcf, 0xff, 0xac, - 0x79, 0xf9, 0x78, 0xf4, 0x9d, 0x09, 0xc6, 0x37, 0xd7, 0x8c, 0x6f, 0xc6, - 0xf8, 0x7f, 0xaf, 0x19, 0xdf, 0x1c, 0x1a, 0xef, 0xd4, 0x8c, 0x77, 0x30, - 0xbe, 0x7e, 0xd3, 0xf2, 0xf1, 0x4e, 0x68, 0x7c, 0x4b, 0xcd, 0xf8, 0x16, - 0x8c, 0x6f, 0xa8, 0x19, 0x8f, 0xbe, 0x33, 0x75, 0xfa, 0xbb, 0x17, 0x31, - 0xf6, 0x88, 0xce, 0xbb, 0x71, 0x2d, 0xd5, 0x7e, 0x4b, 0xa1, 0xde, 0xb5, - 0x42, 0x06, 0xc1, 0x39, 0x3b, 0xda, 0x6b, 0x16, 0xf6, 0xba, 0x14, 0xcb, - 0xf8, 0xfa, 0x18, 0xd6, 0x45, 0xe2, 0x43, 0x51, 0x22, 0x2e, 0x74, 0x67, - 0x1e, 0x3a, 0x34, 0x1f, 0xf8, 0x24, 0x9e, 0x99, 0x4a, 0x75, 0xf9, 0x7a, - 0x6a, 0x48, 0xd4, 0x5d, 0xd0, 0x39, 0xd8, 0x4e, 0xd2, 0x0e, 0xbc, 0x0c, - 0x30, 0x53, 0x4e, 0xf9, 0x76, 0x43, 0xfd, 0xe5, 0xfc, 0xda, 0x7e, 0xa8, - 0xab, 0x7a, 0x9d, 0xbe, 0x15, 0xb8, 0x96, 0x5c, 0x51, 0xab, 0x8a, 0x5c, - 0x07, 0xae, 0x0d, 0x54, 0x71, 0xed, 0x41, 0x99, 0xad, 0xe6, 0xdb, 0xfd, - 0x72, 0xd4, 0xdb, 0xcb, 0xf3, 0x38, 0xa7, 0xb2, 0xf2, 0xd9, 0xe4, 0xdb, - 0x7b, 0xab, 0x7e, 0x32, 0x35, 0x91, 0x95, 0x0b, 0xc7, 0x99, 0x43, 0x05, - 0xb5, 0xd6, 0x71, 0xef, 0x5b, 0x94, 0x0b, 0x6c, 0xe3, 0x46, 0xf3, 0x6d, - 0xce, 0xe7, 0xc8, 0x51, 0xff, 0x2c, 0x44, 0x75, 0xde, 0x62, 0x75, 0xde, - 0x84, 0xb6, 0x37, 0xfa, 0xe0, 0x25, 0x7f, 0x99, 0x87, 0xbf, 0x1c, 0x42, - 0xce, 0xbd, 0xe0, 0xad, 0x56, 0xef, 0xbc, 0x51, 0x7f, 0x59, 0x5b, 0x37, - 0xae, 0xf5, 0x97, 0x5c, 0xa7, 0xb6, 0x56, 0x9c, 0xac, 0xc1, 0x7f, 0xea, - 0xd3, 0x53, 0x3a, 0xa6, 0xc6, 0x75, 0xfe, 0x29, 0xd8, 0xa3, 0x29, 0x43, - 0x4a, 0x7f, 0xd9, 0x0e, 0x72, 0xcb, 0x03, 0xd5, 0xdc, 0x72, 0x29, 0x1f, - 0x44, 0xec, 0xda, 0x75, 0x9f, 0xc6, 0x47, 0xc6, 0xc8, 0xe3, 0xe8, 0x3f, - 0x05, 0x1d, 0xe0, 0x33, 0xd6, 0x3f, 0xef, 0x90, 0x2f, 0x5b, 0xbe, 0x7f, - 0xf2, 0xeb, 0x50, 0x07, 0x54, 0xfc, 0xcf, 0xfa, 0xff, 0x70, 0x7a, 0xa3, - 0x8e, 0xf7, 0xae, 0x85, 0xab, 0xcb, 0x73, 0x53, 0xd3, 0x3c, 0x81, 0x77, - 0x99, 0x9b, 0x3e, 0x10, 0x27, 0x86, 0xe6, 0xca, 0x57, 0x7d, 0xbf, 0x48, - 0xff, 0x32, 0xac, 0xbe, 0xfb, 0xa9, 0x3c, 0x14, 0xe3, 0x16, 0xf4, 0xfb, - 0x7e, 0x1e, 0x9a, 0x2b, 0x6f, 0x89, 0xfb, 0x38, 0x78, 0xb5, 0x9c, 0xe5, - 0x58, 0x9c, 0xb5, 0xbc, 0x05, 0xef, 0x5a, 0xb4, 0xae, 0xcc, 0x7b, 0x23, - 0x2b, 0xf2, 0xde, 0x41, 0x9d, 0xd7, 0x7e, 0x45, 0xe5, 0xbd, 0x3e, 0x8f, - 0xb9, 0x97, 0x70, 0x1e, 0xe5, 0x02, 0x0b, 0xf9, 0x8d, 0x84, 0xf8, 0x30, - 0xaa, 0xfc, 0x56, 0x61, 0xf2, 0x77, 0xd4, 0xf9, 0x89, 0x95, 0x7a, 0xf3, - 0x79, 0xfb, 0x89, 0x60, 0xef, 0x4f, 0x89, 0x5f, 0xaf, 0xdb, 0x03, 0x5a, - 0x98, 0x5b, 0x45, 0xb5, 0x3e, 0xa4, 0x34, 0x5e, 0x07, 0xe3, 0x82, 0x3c, - 0xbe, 0xfa, 0x5d, 0xb5, 0x98, 0x5d, 0x56, 0x3f, 0xd9, 0x42, 0x18, 0x86, - 0xdc, 0xb3, 0x37, 0xf0, 0x1d, 0xe2, 0xd3, 0x9c, 0x7f, 0xa8, 0xf5, 0x6b, - 0xfc, 0x46, 0xda, 0xaa, 0xcf, 0xc7, 0xb9, 0xb0, 0x01, 0x9e, 0x65, 0x0e, - 0xe3, 0xab, 0x3a, 0x03, 0x17, 0x73, 0x32, 0x62, 0xec, 0x23, 0x7d, 0xe9, - 0x7f, 0xd6, 0xfb, 0x4c, 0xc8, 0x91, 0x29, 0xbf, 0xbe, 0x69, 0xae, 0x71, - 0xfe, 0xcd, 0x34, 0xaf, 0xab, 0xbe, 0x79, 0x03, 0xe7, 0xdf, 0x5e, 0x8f, - 0x07, 0xf5, 0xcd, 0xda, 0xf3, 0x6f, 0x91, 0xeb, 0x3c, 0xff, 0xe6, 0xd7, - 0x37, 0x39, 0x4f, 0xb8, 0xbe, 0x79, 0x8f, 0x3a, 0x43, 0x36, 0x3a, 0xd5, - 0xa3, 0xce, 0x23, 0xb7, 0x75, 0xaf, 0x8d, 0xb3, 0xfb, 0x3e, 0xb3, 0x7c, - 0xe4, 0x3f, 0xe3, 0xe1, 0x7c, 0x64, 0xdf, 0xe7, 0x92, 0x8f, 0x70, 0x2f, - 0xbf, 0xef, 0x7f, 0xb7, 0xad, 0x39, 0xfb, 0x95, 0xfb, 0x1c, 0x6b, 0x98, - 0x47, 0x54, 0x0d, 0x73, 0xcb, 0xfa, 0x70, 0x0d, 0xd3, 0xbc, 0xc6, 0xd9, - 0xaf, 0x23, 0xab, 0xd4, 0x30, 0xa3, 0xa1, 0xb3, 0x5f, 0x51, 0x7d, 0xf6, - 0x6b, 0xa3, 0x8b, 0xbc, 0x51, 0xd7, 0x2c, 0xcd, 0xab, 0x9e, 0xfd, 0xea, - 0x59, 0xff, 0x49, 0x6a, 0x96, 0xb9, 0x65, 0x35, 0xcb, 0x15, 0x67, 0xbf, - 0xe0, 0xd7, 0x36, 0x4b, 0x32, 0x94, 0xe3, 0xe4, 0x6e, 0xf0, 0x6c, 0x43, - 0xfe, 0x3a, 0xe2, 0x80, 0x7d, 0x55, 0x5b, 0xe5, 0xd9, 0xfd, 0x3a, 0xec, - 0x39, 0x2a, 0x7b, 0x1d, 0xea, 0x27, 0xcf, 0x38, 0x76, 0xc2, 0x16, 0x70, - 0x2d, 0xb3, 0xdd, 0x45, 0x19, 0x19, 0x03, 0x9d, 0xcb, 0xcf, 0x17, 0x2c, - 0x9d, 0xd3, 0x8d, 0x55, 0xcf, 0xe9, 0x9e, 0x84, 0xde, 0x98, 0x53, 0x31, - 0x99, 0x0b, 0xe9, 0xd4, 0x38, 0x62, 0x3b, 0x73, 0xc6, 0xd6, 0xcf, 0x93, - 0x12, 0x99, 0x72, 0x80, 0x6f, 0x3c, 0xdb, 0xdb, 0x24, 0x91, 0x19, 0xff, - 0x7b, 0xa3, 0xa9, 0xf0, 0x33, 0x81, 0x31, 0x3c, 0xdb, 0x19, 0x95, 0xa3, - 0xaa, 0x3e, 0x11, 0xe8, 0xf2, 0x37, 0xc1, 0xe3, 0x4d, 0xd9, 0xa5, 0xb6, - 0xb3, 0x8a, 0x8f, 0x47, 0xcc, 0x38, 0x45, 0x7d, 0xbe, 0x5b, 0xf2, 0xba, - 0xf6, 0x33, 0x5c, 0xde, 0xa9, 0x73, 0x09, 0xf5, 0xcd, 0x06, 0xbc, 0x6c, - 0xd3, 0xfe, 0x16, 0xd7, 0xf9, 0x36, 0xfa, 0x37, 0xc6, 0xcc, 0xd2, 0x37, - 0xb9, 0x2d, 0x31, 0x02, 0x6c, 0x1b, 0x52, 0x6b, 0xde, 0x08, 0xcf, 0x8d, - 0x15, 0xf1, 0xd7, 0x8d, 0xf1, 0x3d, 0x88, 0x85, 0xdf, 0xc4, 0xfe, 0xda, - 0xa0, 0x1f, 0x8f, 0x4b, 0xfe, 0xcc, 0x1d, 0xd2, 0x37, 0x9d, 0x02, 0x3d, - 0xbf, 0xae, 0x0c, 0xa7, 0x11, 0x37, 0x3f, 0xcf, 0x33, 0x60, 0xc0, 0x4b, - 0xf0, 0xed, 0x95, 0x15, 0xdf, 0xa0, 0xc3, 0xe7, 0xc6, 0xba, 0xaa, 0xe7, - 0x80, 0x5e, 0x2a, 0x4b, 0xac, 0x99, 0x34, 0x4f, 0x2d, 0x9d, 0x09, 0x5f, - 0x28, 0xef, 0x56, 0x7e, 0xec, 0xc5, 0xf2, 0xff, 0x52, 0x77, 0x6d, 0xb1, - 0x6d, 0x9d, 0xf7, 0xfd, 0xcf, 0x43, 0xea, 0x12, 0xdd, 0x7c, 0x24, 0xd3, - 0x32, 0x2d, 0xd1, 0xf2, 0x39, 0xd2, 0xb1, 0xc5, 0xd8, 0x5a, 0xc7, 0x6a, - 0xca, 0x26, 0xac, 0x5a, 0xc2, 0x52, 0xf4, 0x65, 0x59, 0x36, 0xd0, 0x97, - 0x76, 0x1e, 0x16, 0xa0, 0x0e, 0x65, 0x3b, 0x1d, 0xd0, 0x07, 0xb7, 0xd9, - 0x80, 0xa4, 0x03, 0x6c, 0x96, 0xb2, 0x1c, 0xaf, 0x53, 0x4d, 0x36, 0x66, - 0xd5, 0xac, 0x1b, 0x50, 0x4e, 0x92, 0x9d, 0xb4, 0x50, 0xc0, 0x64, 0xbd, - 0x60, 0xd8, 0x43, 0xad, 0xc9, 0xf6, 0xf6, 0xb2, 0x87, 0x6c, 0xd8, 0x83, - 0x81, 0x0d, 0x98, 0x63, 0x05, 0x68, 0x96, 0x02, 0x49, 0x87, 0x15, 0x43, - 0x1e, 0x36, 0x70, 0xff, 0xdf, 0x77, 0x21, 0x0f, 0x0f, 0x0f, 0x75, 0x89, - 0x9d, 0x01, 0x33, 0x60, 0x88, 0xe7, 0x9c, 0xef, 0x9c, 0xf3, 0x7d, 0xff, - 0xef, 0x7f, 0xbf, 0x9d, 0x3a, 0x3f, 0x8f, 0xd8, 0xc3, 0xdc, 0xca, 0x5b, - 0x0c, 0x8b, 0xbb, 0x42, 0x96, 0xcd, 0xe5, 0x69, 0x28, 0x48, 0xd8, 0x0f, - 0x0a, 0x30, 0x0c, 0x44, 0x6e, 0x86, 0x8c, 0xcd, 0x47, 0xc5, 0xbe, 0x4a, - 0x5e, 0x71, 0xcc, 0x95, 0x5b, 0x51, 0xdb, 0x5b, 0x99, 0x73, 0x21, 0xf7, - 0x42, 0xe6, 0x85, 0x00, 0x9e, 0xab, 0x17, 0x8f, 0x3b, 0x32, 0x2f, 0x64, - 0x64, 0x01, 0xe7, 0xfa, 0x3d, 0x72, 0xae, 0x9d, 0x71, 0x00, 0x39, 0x44, - 0xc8, 0x05, 0xc7, 0x9c, 0x85, 0x5f, 0xc3, 0x37, 0x2e, 0xbd, 0x3d, 0xff, - 0xaa, 0x7c, 0xe7, 0xb0, 0x78, 0xe7, 0x2e, 0xc5, 0xb3, 0x74, 0x0e, 0x78, - 0x3c, 0x30, 0x93, 0x1f, 0x8d, 0x04, 0x19, 0xbf, 0x67, 0xca, 0xb0, 0xa5, - 0x9b, 0xe9, 0x6b, 0x1b, 0xc1, 0x33, 0xd1, 0x00, 0xcf, 0x7a, 0x9a, 0x60, - 0xdb, 0xbb, 0xca, 0xbb, 0x25, 0xec, 0xe4, 0x79, 0xe4, 0xb7, 0xeb, 0xfc, - 0x04, 0x09, 0xbb, 0x2a, 0x0d, 0x5d, 0x73, 0xe7, 0x26, 0xd4, 0x60, 0x77, - 0xa6, 0x0a, 0xbb, 0xdd, 0xff, 0x8f, 0x60, 0x77, 0x4f, 0xe8, 0xba, 0x6f, - 0x95, 0x91, 0x83, 0xa6, 0xe5, 0xbd, 0xae, 0x5d, 0x02, 0x1c, 0xc1, 0x4f, - 0xed, 0xd2, 0x2a, 0x81, 0xa7, 0x22, 0x6f, 0xb8, 0x52, 0xf9, 0x41, 0xbc, - 0xea, 0x93, 0x64, 0x1b, 0x04, 0xb6, 0x08, 0x7c, 0x77, 0xcd, 0x65, 0xe4, - 0xf1, 0x8f, 0x25, 0x23, 0xa1, 0x17, 0x79, 0x6d, 0x91, 0x1f, 0xf5, 0xb8, - 0x6d, 0x91, 0xe3, 0xdb, 0xb4, 0x45, 0x2e, 0x48, 0x5b, 0x24, 0xbb, 0x75, - 0x5b, 0x64, 0xa0, 0x21, 0x5f, 0xab, 0xb6, 0x9e, 0xed, 0xdb, 0x22, 0xc6, - 0x86, 0xb6, 0xc8, 0x88, 0xcb, 0xef, 0x82, 0xf9, 0xfe, 0x2e, 0x65, 0x4f, - 0x80, 0xc7, 0x69, 0x38, 0x03, 0xc6, 0x27, 0x3c, 0x3e, 0xe0, 0x4f, 0x12, - 0xd6, 0xe6, 0x8e, 0xff, 0x5b, 0x58, 0x0f, 0x36, 0xf8, 0xb7, 0x6b, 0xeb, - 0xa1, 0xf0, 0xce, 0x6d, 0xe9, 0xec, 0x5e, 0x58, 0x0f, 0x36, 0xf5, 0x93, - 0x36, 0xcf, 0x45, 0xac, 0xf7, 0x93, 0x0e, 0x1b, 0xcd, 0x78, 0xfb, 0x77, - 0x5d, 0xfe, 0x53, 0x37, 0x7f, 0x07, 0x4d, 0x51, 0xe0, 0xf8, 0xa8, 0x7e, - 0x17, 0x68, 0xc9, 0xce, 0x66, 0x09, 0xf6, 0x11, 0xde, 0x17, 0x11, 0xb4, - 0xe6, 0xd1, 0xb7, 0xf8, 0x7d, 0xbc, 0xbe, 0xd7, 0x9e, 0x15, 0x72, 0x4a, - 0xfa, 0x1a, 0x30, 0x3e, 0x16, 0x38, 0x2b, 0xc6, 0xca, 0xdc, 0x24, 0xe5, - 0x7b, 0x50, 0x7a, 0x7e, 0x33, 0x9f, 0x43, 0xa3, 0xcc, 0xdb, 0x9e, 0x5d, - 0xa0, 0x69, 0x7c, 0x1f, 0xef, 0x4b, 0xa4, 0xce, 0xae, 0x02, 0xff, 0xbc, - 0xc0, 0x7a, 0xc1, 0x70, 0x55, 0x27, 0xa8, 0xdf, 0x9b, 0xcb, 0xc2, 0x7e, - 0xd3, 0xbc, 0x33, 0x2d, 0xf2, 0xdd, 0x24, 0xef, 0x84, 0x9e, 0xa6, 0x79, - 0xa7, 0x57, 0x0f, 0xde, 0xe7, 0x83, 0x17, 0xbe, 0x75, 0xa7, 0x7a, 0xef, - 0x2c, 0xe4, 0x8f, 0xa7, 0x7c, 0xf7, 0xae, 0x5a, 0x77, 0x95, 0xad, 0x8d, - 0x95, 0xf7, 0xa7, 0xc4, 0xba, 0xa2, 0x4f, 0x27, 0x51, 0x13, 0x57, 0xad, - 0x09, 0xf2, 0xd6, 0x41, 0x41, 0x0e, 0x68, 0x3a, 0xd4, 0x75, 0xe2, 0x80, - 0x45, 0xcc, 0xa7, 0x0e, 0xca, 0x2d, 0x4b, 0x70, 0x9f, 0x17, 0x16, 0x35, - 0x39, 0x32, 0xa7, 0xe4, 0xc8, 0xa2, 0x8b, 0x8f, 0x37, 0xea, 0xed, 0x7d, - 0x3e, 0x7a, 0xbb, 0xbb, 0xb6, 0x43, 0xd4, 0xb8, 0x35, 0xa9, 0xed, 0xf0, - 0xab, 0x99, 0xc2, 0xd8, 0x17, 0x59, 0x5f, 0xf9, 0x14, 0xf4, 0x15, 0x13, - 0x35, 0x4b, 0x52, 0x67, 0xc1, 0x75, 0x96, 0x49, 0xaf, 0x45, 0x18, 0xa7, - 0x8e, 0xd1, 0x79, 0xd6, 0xc9, 0x6f, 0xd2, 0xe3, 0xca, 0x66, 0x4b, 0xb8, - 0xf2, 0x4c, 0x91, 0xdf, 0x1f, 0xa0, 0xec, 0xb3, 0x76, 0x2c, 0x41, 0xc7, - 0xe8, 0x9c, 0xc8, 0x99, 0x41, 0xcc, 0x0f, 0x79, 0x08, 0x07, 0xc5, 0x3c, - 0xa5, 0x7f, 0xe3, 0x51, 0xe4, 0xcd, 0x6d, 0x3d, 0x67, 0x5f, 0xd7, 0xfa, - 0x25, 0xc5, 0x3b, 0x97, 0x15, 0xed, 0x89, 0x73, 0x7c, 0xff, 0x8b, 0x46, - 0xe3, 0xfd, 0x09, 0x23, 0x55, 0x4e, 0x19, 0xc9, 0x25, 0x8c, 0x7b, 0xd1, - 0x98, 0x2e, 0xc3, 0xd6, 0xd4, 0xb8, 0x64, 0xc7, 0x41, 0x97, 0x6b, 0xb4, - 0x79, 0x7c, 0x62, 0x91, 0x3c, 0xf5, 0x13, 0x5b, 0x98, 0xf7, 0x91, 0xba, - 0x79, 0x6b, 0xf8, 0xe2, 0x37, 0x7c, 0x40, 0x09, 0x86, 0xa9, 0xd6, 0x7f, - 0x3b, 0xe0, 0x73, 0x8f, 0x65, 0x69, 0x23, 0xfd, 0xd7, 0x6e, 0xd0, 0x7f, - 0x17, 0x37, 0x9d, 0xf7, 0xc3, 0xf2, 0x02, 0x59, 0xc3, 0x1d, 0x74, 0x84, - 0x9e, 0xcb, 0xf3, 0xae, 0xd3, 0x81, 0x3d, 0x38, 0x85, 0x31, 0xda, 0x37, - 0xae, 0x7d, 0x63, 0x3d, 0x2a, 0x1f, 0x58, 0xe7, 0x2c, 0x74, 0x28, 0x3c, - 0xc6, 0x75, 0xd8, 0x62, 0xab, 0x3c, 0x3f, 0xd8, 0x65, 0x4f, 0x8a, 0x39, - 0xb2, 0x5d, 0x66, 0x4d, 0x93, 0xf4, 0x7f, 0x9f, 0x2d, 0xd7, 0xd5, 0x8f, - 0xfa, 0xd4, 0x51, 0x0e, 0xfb, 0xd4, 0x51, 0xba, 0x69, 0x32, 0xe4, 0xa2, - 0xc9, 0x88, 0x4b, 0xbf, 0x8b, 0xb2, 0x7d, 0xd3, 0xc5, 0xbc, 0x06, 0xf6, - 0x4d, 0x07, 0x05, 0x5f, 0x71, 0xdb, 0x37, 0xde, 0xba, 0x7d, 0xd0, 0x27, - 0x74, 0x38, 0x69, 0xeb, 0xa4, 0x8a, 0xd5, 0x9a, 0x7f, 0x5e, 0x77, 0xad, - 0x66, 0x71, 0xa9, 0xa1, 0xbe, 0xd2, 0x6f, 0xbe, 0x43, 0x0d, 0xf3, 0x85, - 0x9c, 0x4b, 0x34, 0xd5, 0xfd, 0xfc, 0xec, 0xaf, 0x47, 0x35, 0x3f, 0x2f, - 0xdf, 0xc3, 0xbb, 0x86, 0x85, 0x1f, 0x3c, 0x5b, 0xe5, 0x79, 0x93, 0x72, - 0xbe, 0xf9, 0x7a, 0x7b, 0x24, 0x78, 0x8d, 0x14, 0xec, 0xfc, 0x65, 0xc0, - 0xf6, 0x7c, 0x6a, 0x9d, 0x1e, 0xf9, 0x3c, 0xd1, 0x2b, 0x7d, 0x65, 0x2d, - 0x2a, 0xd7, 0x7a, 0x97, 0xb2, 0x0b, 0x37, 0xc3, 0x77, 0x9c, 0x6b, 0x51, - 0xfe, 0x45, 0xdb, 0x2a, 0x11, 0xf0, 0xfc, 0xc4, 0xe9, 0x16, 0xc7, 0x54, - 0xf1, 0x2d, 0xc4, 0xb0, 0x80, 0xf7, 0xfa, 0xf9, 0xb2, 0xd6, 0x6a, 0xf3, - 0x3d, 0xb3, 0x1a, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x32, 0xe4, 0x10, 0x8f, - 0x79, 0xf2, 0xb8, 0x1f, 0x06, 0x16, 0x3d, 0x3e, 0xb9, 0xcd, 0xc8, 0x4d, - 0x6e, 0x36, 0xcf, 0xfb, 0x2e, 0xfd, 0x1d, 0xf3, 0xad, 0x54, 0xde, 0x8c, - 0x0f, 0x48, 0x99, 0x5d, 0xf6, 0xd7, 0xa5, 0xcc, 0x2d, 0xcf, 0xcf, 0x2b, - 0xa3, 0xf7, 0x6c, 0x51, 0x46, 0x8b, 0x7e, 0x28, 0x81, 0xc3, 0x82, 0x07, - 0xa0, 0x06, 0x1b, 0x39, 0xd6, 0x9f, 0x06, 0xcd, 0x33, 0x9f, 0x75, 0xd5, - 0xaa, 0xf9, 0xef, 0x63, 0x35, 0xce, 0x12, 0x42, 0x2f, 0x88, 0x09, 0xe4, - 0x9b, 0xf4, 0x31, 0xef, 0xc1, 0xf8, 0xfd, 0xd6, 0x1d, 0xf8, 0x80, 0x95, - 0x9f, 0x2a, 0xa5, 0xe4, 0xcb, 0xe1, 0x2d, 0xc4, 0x5b, 0xb6, 0xc7, 0xa7, - 0x6d, 0x6b, 0x95, 0x10, 0x0b, 0x42, 0x4e, 0xf0, 0x0b, 0x3d, 0xd4, 0x73, - 0xaa, 0xad, 0xcd, 0xb9, 0xdb, 0x2b, 0xe3, 0x53, 0xb8, 0xd6, 0x45, 0x37, - 0x8a, 0xc8, 0xd7, 0xc6, 0xb5, 0xdf, 0xe3, 0x6b, 0x7e, 0x3c, 0x4a, 0xe7, - 0x9b, 0x43, 0xe7, 0x93, 0xfb, 0x53, 0x22, 0xd8, 0x54, 0x15, 0xfa, 0xa7, - 0xf8, 0xaf, 0xc8, 0x18, 0x47, 0xf9, 0x51, 0xc7, 0x6f, 0xfc, 0xfc, 0x8a, - 0x46, 0xdf, 0xc7, 0xcd, 0x97, 0xfc, 0xf2, 0x96, 0xfc, 0x8a, 0xc8, 0xbb, - 0xdf, 0x4a, 0x1c, 0x45, 0xc7, 0x8b, 0x27, 0x44, 0xed, 0xa9, 0x1b, 0x0f, - 0x1e, 0x4d, 0xcc, 0x18, 0xf8, 0x30, 0xd4, 0xc0, 0xab, 0x1e, 0x3e, 0x06, - 0xe0, 0x85, 0x6b, 0x87, 0xaf, 0x4f, 0xcb, 0x3f, 0x36, 0x8c, 0x3c, 0x00, - 0xf8, 0xb3, 0x9f, 0xa2, 0xb3, 0xd7, 0x81, 0xc3, 0x06, 0x63, 0xdb, 0x08, - 0xcd, 0x86, 0x51, 0x57, 0x24, 0x6a, 0x73, 0x54, 0x2c, 0x51, 0xd6, 0x0a, - 0x9d, 0x15, 0x75, 0x8f, 0xfb, 0x23, 0xeb, 0x94, 0x66, 0xb9, 0x97, 0xa5, - 0x73, 0x2c, 0x63, 0xcf, 0x2d, 0xd5, 0x74, 0xfc, 0xc6, 0xda, 0xc7, 0x7a, - 0x1c, 0x5f, 0x17, 0x38, 0x1e, 0xdd, 0x10, 0xc7, 0x8f, 0x56, 0x71, 0x7c, - 0xae, 0x4f, 0xe2, 0xf3, 0x45, 0x7e, 0x56, 0x0f, 0x1d, 0x16, 0xcf, 0xcd, - 0xf2, 0xef, 0x4e, 0x3a, 0x2c, 0xfb, 0x62, 0xf0, 0xbb, 0x99, 0xc7, 0xe7, - 0xb3, 0x74, 0xfe, 0x7a, 0x36, 0x90, 0x12, 0x35, 0x0a, 0xee, 0xbe, 0x1e, - 0xfa, 0x7e, 0x8c, 0x6b, 0x86, 0xff, 0x9a, 0x2f, 0xc9, 0x9a, 0xab, 0x92, - 0xe4, 0x4f, 0xf4, 0x76, 0x7c, 0xd0, 0x83, 0xff, 0xf5, 0x36, 0xe6, 0x05, - 0x25, 0x03, 0x4f, 0x6c, 0xe0, 0xff, 0x68, 0xc4, 0xcb, 0x5e, 0x1f, 0xbd, - 0xf9, 0x8d, 0x3e, 0x19, 0xbb, 0xda, 0xc8, 0xff, 0xe1, 0xc6, 0xd1, 0xba, - 0x58, 0x3e, 0xf3, 0xfd, 0x84, 0xaa, 0xff, 0x7b, 0xa7, 0x4f, 0xca, 0x0b, - 0xd4, 0x04, 0xa6, 0x19, 0x0e, 0x6f, 0xb2, 0xae, 0x32, 0x48, 0xad, 0xaf, - 0xe8, 0xb5, 0x0e, 0x0a, 0x7e, 0xeb, 0xf6, 0xe7, 0x5c, 0x56, 0xb5, 0xe0, - 0x39, 0xd7, 0x9a, 0x2e, 0x0b, 0x5b, 0xa8, 0x39, 0xbd, 0x35, 0xcf, 0xc3, - 0x8a, 0x7a, 0x64, 0x82, 0x17, 0xdf, 0xd0, 0x2f, 0x05, 0xfb, 0x4b, 0x86, - 0xd4, 0x83, 0x27, 0x59, 0xbf, 0xdd, 0x6e, 0x0c, 0xe9, 0x61, 0x75, 0x44, - 0x6f, 0x4f, 0x0e, 0xef, 0x6f, 0xec, 0x83, 0xb4, 0x39, 0x32, 0xaf, 0x3d, - 0x25, 0x78, 0xc1, 0xe5, 0xb1, 0x0a, 0x4d, 0xc7, 0xbb, 0x29, 0x33, 0xc6, - 0xef, 0x9e, 0x44, 0x4f, 0xac, 0x20, 0x65, 0x99, 0x7e, 0x33, 0x63, 0x8f, - 0x29, 0x7d, 0x51, 0xfb, 0xdd, 0xdb, 0x54, 0xee, 0xc3, 0x45, 0x11, 0xab, - 0x94, 0xfd, 0x84, 0xf8, 0xf7, 0x92, 0x7e, 0xf6, 0x45, 0x11, 0x33, 0xcd, - 0x5c, 0x6f, 0x55, 0xe3, 0x3a, 0x5d, 0xe3, 0x30, 0xa6, 0x53, 0x8d, 0xc5, - 0x33, 0xb5, 0x4e, 0xd1, 0xae, 0xf8, 0x2d, 0xe8, 0x30, 0xad, 0x6a, 0xf5, - 0x70, 0xfd, 0x02, 0xcd, 0x54, 0xd7, 0xd2, 0xc9, 0x63, 0xff, 0x5b, 0xf5, - 0xf2, 0xe8, 0x64, 0x9d, 0x17, 0xf3, 0x6e, 0x9c, 0x13, 0xd6, 0x12, 0x14, - 0x71, 0x24, 0xfe, 0xad, 0xde, 0x73, 0xa6, 0x3a, 0x27, 0xe4, 0x6d, 0xd8, - 0x11, 0xf9, 0x2c, 0x3d, 0xae, 0xd3, 0x35, 0x4e, 0xf3, 0x0a, 0x1d, 0xa7, - 0xf8, 0x57, 0x9e, 0xc7, 0x3f, 0xa8, 0xbc, 0x5e, 0x53, 0xc4, 0x54, 0x65, - 0xde, 0x86, 0xfe, 0x0d, 0x3f, 0x34, 0xf2, 0x2c, 0x90, 0x3b, 0xe1, 0xe6, - 0x37, 0x72, 0xbd, 0x21, 0xc8, 0xa2, 0x32, 0x62, 0xa9, 0x88, 0x6b, 0x34, - 0xd3, 0x9d, 0xf7, 0x20, 0x5f, 0x7f, 0x1b, 0x3a, 0xe8, 0x56, 0xe8, 0xcf, - 0xf2, 0xa1, 0x3f, 0xf7, 0xfb, 0x51, 0xeb, 0x86, 0x9a, 0xb7, 0x6c, 0xcc, - 0xa0, 0x0a, 0xdb, 0x0a, 0x06, 0x95, 0xcc, 0x00, 0x9d, 0x77, 0xec, 0xf8, - 0x12, 0xc9, 0x9a, 0xc9, 0xe9, 0x79, 0x3b, 0xb6, 0x4a, 0x87, 0xcc, 0x73, - 0x24, 0x7b, 0x25, 0x94, 0x58, 0x06, 0x9f, 0xa1, 0x18, 0xdb, 0x47, 0x6c, - 0x7f, 0x9e, 0x42, 0x5c, 0x46, 0xef, 0x0b, 0x6a, 0xe3, 0xf1, 0x37, 0xc6, - 0x70, 0xba, 0xb9, 0x93, 0x3a, 0x12, 0xfc, 0xcc, 0x18, 0xf8, 0x13, 0x3f, - 0x27, 0x4d, 0x49, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x39, 0x65, 0x9b, 0x25, - 0x32, 0x78, 0x2c, 0x6c, 0x57, 0x3c, 0x07, 0xf7, 0x27, 0xcc, 0x16, 0xf2, - 0xd6, 0xe1, 0x5e, 0x14, 0x75, 0x8a, 0x6f, 0xc7, 0x0f, 0x92, 0xd1, 0x0f, - 0x7e, 0x85, 0x7d, 0x1b, 0x55, 0xf1, 0xa4, 0x4b, 0xfc, 0xdb, 0x51, 0xbf, - 0xbf, 0x2a, 0xea, 0xdd, 0xe4, 0x6f, 0xe0, 0xf6, 0x2f, 0xab, 0x3d, 0xab, - 0xcb, 0x09, 0x89, 0x8c, 0x18, 0x5f, 0xa5, 0x0b, 0x4b, 0x1b, 0xf9, 0x66, - 0xfc, 0xea, 0x5b, 0xbb, 0xb6, 0x58, 0xdf, 0xba, 0xbe, 0x53, 0xd6, 0x8c, - 0xe1, 0xfd, 0x7e, 0xba, 0x97, 0x77, 0x6d, 0xee, 0x7a, 0xd5, 0xef, 0xd0, - 0xb4, 0xac, 0x35, 0x56, 0xb8, 0x70, 0xbd, 0x89, 0x7f, 0xf3, 0x49, 0x21, - 0x2f, 0xcf, 0xca, 0x38, 0xc3, 0x80, 0xec, 0x6d, 0x16, 0xa2, 0xe5, 0x6a, - 0xed, 0x67, 0x50, 0xd5, 0x7f, 0x30, 0x53, 0x7c, 0xa4, 0x75, 0x9f, 0x3a, - 0x57, 0x15, 0x71, 0xa7, 0xb4, 0x2b, 0x8f, 0x22, 0xa4, 0xf2, 0x24, 0x70, - 0xdf, 0x48, 0x18, 0x75, 0x5b, 0xb2, 0xd6, 0x12, 0x63, 0x50, 0xe7, 0x08, - 0x1b, 0x12, 0x75, 0xae, 0xf0, 0xfb, 0x35, 0xab, 0x05, 0xc5, 0x78, 0xf8, - 0x9f, 0xb4, 0x5d, 0x78, 0x5a, 0xd0, 0x98, 0x7c, 0xa7, 0xac, 0xd9, 0x5c, - 0x5c, 0x39, 0x23, 0xea, 0x24, 0x93, 0xaa, 0xf6, 0x33, 0x43, 0x5d, 0x42, - 0x6f, 0xfa, 0xf8, 0x35, 0x9b, 0xe7, 0xc2, 0xdb, 0xaf, 0xd9, 0x74, 0xdf, - 0xb3, 0xbd, 0x9a, 0x4d, 0x93, 0xd7, 0x6e, 0x2c, 0xc8, 0x9a, 0xcd, 0xfa, - 0x58, 0x80, 0xf4, 0x43, 0x65, 0x5c, 0xf2, 0x48, 0xea, 0x7f, 0x5f, 0x72, - 0xe5, 0x08, 0xcb, 0x7a, 0xcc, 0xc5, 0xaa, 0x0e, 0x24, 0xeb, 0x31, 0x65, - 0x4e, 0xb1, 0xbb, 0x0f, 0x89, 0x8c, 0x39, 0xc8, 0xf7, 0x74, 0x7b, 0x62, - 0x0e, 0x2d, 0x4c, 0xa3, 0xa3, 0xaa, 0xe6, 0xbc, 0x19, 0x6e, 0xd6, 0xd9, - 0x2a, 0x4c, 0x73, 0x15, 0xfa, 0x69, 0xfc, 0xd3, 0x74, 0x3f, 0x1c, 0x51, - 0xb9, 0x74, 0xc8, 0x9d, 0x3b, 0xa8, 0xe0, 0xa8, 0xf5, 0x0f, 0xf2, 0xd1, - 0x3f, 0x7e, 0x5b, 0xe4, 0x10, 0x4b, 0xfd, 0x65, 0x50, 0xd1, 0x24, 0xe8, - 0x36, 0xe2, 0xa2, 0xdb, 0x5d, 0x4d, 0xe8, 0x16, 0xf4, 0xf9, 0xdd, 0x1d, - 0xb2, 0x4f, 0x01, 0xe2, 0xde, 0xdf, 0x57, 0xbf, 0x37, 0xa3, 0xbf, 0xf7, - 0x78, 0x6f, 0x40, 0x83, 0x78, 0xc6, 0x87, 0xe1, 0x1a, 0x1d, 0xea, 0xdf, - 0x98, 0xcb, 0x7e, 0xd7, 0x5c, 0x86, 0x5d, 0x73, 0xd9, 0xd7, 0x64, 0x2e, - 0xac, 0x4f, 0x94, 0x2f, 0xf0, 0xff, 0x8f, 0x3b, 0x27, 0xe1, 0xab, 0x65, - 0x5a, 0x8d, 0x0b, 0xf9, 0x9a, 0x03, 0x1c, 0x85, 0x9e, 0x32, 0xaa, 0xea, - 0xe0, 0xdd, 0xf3, 0x6c, 0x66, 0xab, 0x41, 0x16, 0xa0, 0xd7, 0x41, 0x82, - 0xef, 0xeb, 0x6c, 0xd2, 0xeb, 0x00, 0x3a, 0x86, 0x5f, 0xaf, 0x03, 0x37, - 0x8f, 0x77, 0xeb, 0x52, 0xd0, 0x7d, 0x21, 0x03, 0xa1, 0xf3, 0xa2, 0x57, - 0xc1, 0x2f, 0xd1, 0x85, 0xaa, 0x8e, 0x79, 0x90, 0xd2, 0x4a, 0xc7, 0xbc, - 0xb0, 0xa4, 0xf7, 0x7c, 0xd8, 0xb3, 0xe7, 0x7e, 0x3a, 0xe7, 0x90, 0xca, - 0xf1, 0xd1, 0xb0, 0xca, 0xba, 0x60, 0x95, 0xf5, 0x81, 0x95, 0x78, 0x47, - 0x93, 0x79, 0x03, 0x3e, 0xb8, 0x07, 0xff, 0xbf, 0x13, 0x41, 0x8f, 0x16, - 0xa2, 0xdf, 0xd8, 0x55, 0xf3, 0x0b, 0xe8, 0xdf, 0x98, 0x63, 0xd3, 0xdc, - 0x4f, 0xa5, 0x0f, 0x0e, 0x06, 0x8e, 0x5c, 0x67, 0x03, 0x9d, 0x65, 0x5e, - 0xbd, 0x2d, 0xa8, 0x75, 0x85, 0x03, 0x82, 0xef, 0xdd, 0x0f, 0x22, 0x77, - 0x45, 0x9f, 0xeb, 0xd6, 0xbe, 0x5c, 0xb5, 0xfe, 0xd6, 0x3a, 0x7d, 0xa2, - 0xa6, 0x4b, 0xe8, 0x1c, 0x54, 0xfd, 0x5b, 0xcb, 0xc0, 0x7b, 0x75, 0xfe, - 0x89, 0x5b, 0x75, 0xfd, 0x06, 0xe1, 0x0b, 0xea, 0x4e, 0x1b, 0x4e, 0x4a, - 0xe4, 0x91, 0xf6, 0x3a, 0xf0, 0x7b, 0x25, 0x99, 0x37, 0xf7, 0xa6, 0x91, - 0xb3, 0xdc, 0x7b, 0xcd, 0xa2, 0x93, 0xf9, 0x2f, 0xed, 0x95, 0x74, 0x7a, - 0x89, 0x86, 0xc7, 0x79, 0xfc, 0x14, 0x7c, 0xbd, 0x76, 0x2c, 0xc9, 0x4a, - 0xe4, 0x5c, 0xb9, 0x8d, 0x16, 0x59, 0x5b, 0x0f, 0x3a, 0x25, 0xe1, 0xbb, - 0x63, 0x99, 0x51, 0x40, 0x6f, 0x55, 0x63, 0xa1, 0x95, 0x9f, 0xdb, 0x4f, - 0xcb, 0x45, 0xd0, 0x7c, 0x8b, 0xea, 0x11, 0x82, 0xb1, 0x01, 0xea, 0x73, - 0xfe, 0x84, 0xe1, 0xf5, 0x05, 0x91, 0x47, 0xb9, 0x58, 0xb8, 0x24, 0xff, - 0x96, 0x5e, 0x52, 0xef, 0xe0, 0xf7, 0x95, 0xff, 0x86, 0x12, 0x7d, 0x96, - 0xcb, 0x36, 0x73, 0xff, 0xf3, 0xd7, 0x3f, 0x8e, 0x6f, 0x4b, 0xff, 0xc8, - 0xa6, 0x6b, 0xfa, 0x87, 0xfb, 0xd9, 0x5a, 0x17, 0x39, 0xd6, 0x2f, 0xfb, - 0x37, 0x00, 0x06, 0x9d, 0xd0, 0xad, 0xd2, 0x80, 0xa5, 0x31, 0x65, 0x47, - 0x92, 0xc1, 0x49, 0x9a, 0x2d, 0x47, 0x8d, 0x4c, 0x01, 0x3a, 0x30, 0xff, - 0x2d, 0x5d, 0xd9, 0x2d, 0x7d, 0x2e, 0xfa, 0x1e, 0xf0, 0xf5, 0x9d, 0x3c, - 0xfe, 0x3f, 0xfa, 0x65, 0xee, 0xb5, 0xfb, 0x7c, 0x0f, 0x9f, 0x7f, 0x2e, - 0x52, 0x7f, 0xfe, 0x31, 0x3e, 0xdf, 0xc7, 0xe7, 0xe1, 0x87, 0x84, 0x9f, - 0x31, 0x46, 0x39, 0xde, 0x9f, 0xd9, 0x32, 0xf3, 0xa9, 0x57, 0x58, 0x5e, - 0x2c, 0xe9, 0x71, 0xbb, 0x50, 0x97, 0x23, 0xf6, 0xc4, 0xe0, 0x31, 0x97, - 0xf3, 0x63, 0x3c, 0x6e, 0x90, 0x82, 0xaf, 0x58, 0x34, 0xbb, 0xa4, 0x71, - 0x52, 0xe7, 0xd4, 0xbf, 0xc3, 0xf0, 0x45, 0xde, 0xce, 0x47, 0xbb, 0x25, - 0xfc, 0x62, 0xc2, 0x87, 0x89, 0x3c, 0x8e, 0x2b, 0x02, 0xf7, 0xec, 0x49, - 0xab, 0xfa, 0x7e, 0xe0, 0x96, 0x88, 0x73, 0xf0, 0x1a, 0x58, 0x2e, 0x4d, - 0x39, 0x66, 0xae, 0x9a, 0x8f, 0xf6, 0xe7, 0x03, 0xf2, 0xfe, 0xff, 0xda, - 0x25, 0xfb, 0xa3, 0xbe, 0x3f, 0xa0, 0xfb, 0x24, 0x4a, 0x9d, 0x00, 0x39, - 0xca, 0x01, 0x01, 0x9b, 0xe0, 0x02, 0xe4, 0x95, 0xc1, 0xbf, 0x79, 0x3d, - 0x69, 0xcc, 0xb1, 0xad, 0x5f, 0xf7, 0x7c, 0x91, 0xeb, 0x3a, 0xc6, 0xf3, - 0x4d, 0xf1, 0xba, 0xf4, 0xf9, 0x04, 0x1f, 0xfb, 0xed, 0x2f, 0x9e, 0xd5, - 0x91, 0x46, 0x5d, 0x70, 0xe6, 0x54, 0x47, 0x3a, 0x13, 0x93, 0xfb, 0x5c, - 0xf3, 0xd1, 0x46, 0xaa, 0x3e, 0xda, 0xb9, 0xfc, 0x78, 0x3f, 0xfc, 0x15, - 0xc6, 0x35, 0xde, 0xef, 0xf0, 0x15, 0x1e, 0x8b, 0x7a, 0x84, 0x1c, 0xff, - 0xed, 0x52, 0xf9, 0x3c, 0x8d, 0xb8, 0x22, 0xf3, 0x23, 0xb4, 0x5e, 0x81, - 0x7b, 0x9f, 0xe0, 0x67, 0x48, 0xdd, 0xa2, 0xf9, 0x7b, 0xa8, 0x21, 0xff, - 0xa5, 0x11, 0xc7, 0x36, 0xf2, 0xab, 0x8a, 0x38, 0xa2, 0x0f, 0x9e, 0x6d, - 0xd4, 0x83, 0xe0, 0x9e, 0xf0, 0x8b, 0x4d, 0x37, 0xd0, 0x2b, 0xe8, 0x38, - 0x44, 0x2f, 0xcc, 0x67, 0xe9, 0x31, 0xde, 0xab, 0x3f, 0x30, 0x3e, 0x83, - 0x38, 0x3b, 0xc9, 0x5c, 0x27, 0x86, 0x71, 0xde, 0x89, 0x9d, 0x33, 0x52, - 0xe0, 0x8b, 0x95, 0x90, 0xd3, 0x45, 0xad, 0x4c, 0xab, 0xbf, 0x49, 0x23, - 0x6c, 0xcf, 0x81, 0x66, 0x9d, 0x48, 0x8a, 0x40, 0x6f, 0xb6, 0x79, 0x84, - 0x71, 0x62, 0xba, 0x0c, 0x7c, 0x36, 0xe8, 0x8b, 0x45, 0xa2, 0xe7, 0x8b, - 0x23, 0xe6, 0xf7, 0xc8, 0xb1, 0x6a, 0xd7, 0x6d, 0x33, 0xc9, 0xf3, 0x48, - 0x95, 0x5f, 0xa2, 0xf7, 0x44, 0xdf, 0x12, 0xc0, 0x51, 0xef, 0xfb, 0x1f, - 0xd1, 0x99, 0x34, 0xe6, 0xbd, 0x75, 0xfa, 0x3c, 0xb9, 0x2d, 0xfa, 0xec, - 0xf0, 0xa1, 0xcf, 0x7f, 0x54, 0x78, 0x53, 0x61, 0x1c, 0xed, 0xa0, 0x99, - 0x02, 0x72, 0xbf, 0x3e, 0x8b, 0xfe, 0x52, 0x85, 0x0c, 0xf3, 0xa5, 0x4c, - 0x8d, 0x2f, 0x5d, 0x4d, 0x06, 0x13, 0xa0, 0x71, 0xf4, 0x65, 0x53, 0xf9, - 0x3e, 0x58, 0xc7, 0x00, 0x8d, 0x2c, 0x74, 0x22, 0xf6, 0xb5, 0x9a, 0x9c, - 0x48, 0xa8, 0xfa, 0x7c, 0xdb, 0x9a, 0x66, 0xfe, 0x38, 0xc7, 0xb4, 0x9c, - 0x2b, 0x1c, 0xa4, 0xc5, 0x70, 0x94, 0x86, 0x17, 0x74, 0xbf, 0x12, 0x11, - 0x37, 0x89, 0x4a, 0x9e, 0xa4, 0xd7, 0xfd, 0x84, 0xf0, 0x45, 0x58, 0x37, - 0x3f, 0xa9, 0x75, 0x77, 0x6e, 0xc2, 0x97, 0xde, 0x57, 0x34, 0x5b, 0xb9, - 0x95, 0x8c, 0x53, 0x36, 0x39, 0xf1, 0xef, 0x02, 0xff, 0x87, 0x6f, 0xc2, - 0xaf, 0x06, 0x1e, 0x6d, 0x51, 0x3a, 0xef, 0x85, 0x45, 0x94, 0xd7, 0x8d, - 0xeb, 0x95, 0x0f, 0x67, 0xe2, 0x2f, 0x09, 0xdd, 0x6b, 0xe4, 0x26, 0x8f, - 0x13, 0xf2, 0x48, 0xf3, 0x0d, 0x3f, 0x3c, 0xd4, 0x3d, 0x29, 0x35, 0x2e, - 0xca, 0x7c, 0x4e, 0x93, 0x9f, 0x9b, 0x0e, 0x7a, 0x71, 0xf2, 0x5e, 0xe0, - 0xf8, 0xbc, 0x45, 0x27, 0xf2, 0xf6, 0xab, 0x59, 0x9a, 0x64, 0xba, 0x76, - 0xcb, 0x0b, 0x1e, 0x4f, 0xc0, 0xb3, 0x29, 0xd0, 0x3e, 0x65, 0x0a, 0x96, - 0xcc, 0xb7, 0x13, 0x3d, 0xe5, 0x70, 0x8c, 0xda, 0xe2, 0xee, 0xdd, 0x5a, - 0x1e, 0x64, 0x0a, 0xa8, 0x15, 0xe4, 0xbf, 0x25, 0x1e, 0x8f, 0xfc, 0xfe, - 0x22, 0x9e, 0x03, 0x19, 0x87, 0xb9, 0xf3, 0xf1, 0xb2, 0xdc, 0xd7, 0x61, - 0x7e, 0xf6, 0xc8, 0x38, 0xbf, 0xb3, 0x3c, 0xc6, 0xfb, 0xdb, 0x23, 0x78, - 0xb3, 0xdc, 0xcf, 0x29, 0xba, 0xec, 0xcb, 0x57, 0xe4, 0xbe, 0x64, 0x5c, - 0xf4, 0x9d, 0x11, 0xf4, 0x3d, 0x25, 0xf6, 0x23, 0x53, 0x34, 0x58, 0x5f, - 0xd6, 0xbe, 0x04, 0xb6, 0x9b, 0x8b, 0x21, 0xc5, 0x43, 0x70, 0xed, 0x89, - 0xdd, 0x22, 0x1f, 0x11, 0xf6, 0x74, 0x11, 0x7f, 0xa7, 0xe8, 0x0a, 0xeb, - 0xfd, 0x2f, 0xe7, 0xdb, 0xe8, 0x4e, 0xa1, 0x8d, 0xee, 0x16, 0xa2, 0x74, - 0x7b, 0x7e, 0x07, 0x5d, 0x66, 0x9b, 0xe6, 0xb2, 0x13, 0xb2, 0x72, 0xb4, - 0x03, 0xf1, 0x42, 0xe4, 0x0a, 0x31, 0xdd, 0x61, 0x3c, 0xf4, 0xef, 0xe4, - 0x1e, 0xc6, 0x39, 0xb6, 0x8d, 0xda, 0xe9, 0x5d, 0x7e, 0x67, 0x2e, 0xaf, - 0x73, 0x1c, 0xe0, 0x63, 0xdf, 0x5f, 0xb5, 0x1f, 0x36, 0xc7, 0x11, 0x73, - 0x13, 0x1c, 0x99, 0x12, 0xbc, 0x7e, 0x76, 0x3e, 0x8a, 0xbe, 0xca, 0xd9, - 0x16, 0xf8, 0x49, 0x99, 0x3f, 0x3f, 0x17, 0xc2, 0x78, 0x9c, 0x73, 0x64, - 0x8e, 0xa4, 0x58, 0x5b, 0x84, 0x8f, 0x03, 0xa2, 0x0e, 0x5a, 0xc2, 0xa1, - 0x9d, 0xd7, 0x17, 0x10, 0xe3, 0x33, 0xcb, 0xed, 0x74, 0xb6, 0x68, 0xf2, - 0x71, 0x90, 0xf5, 0x44, 0x8c, 0xed, 0xdd, 0xa7, 0xfb, 0xcb, 0x5e, 0xe6, - 0xb9, 0xe7, 0xc4, 0x38, 0xfe, 0xbb, 0xdc, 0x43, 0xb3, 0xc5, 0x2e, 0x75, - 0x7c, 0x50, 0xe6, 0xf2, 0x8a, 0x5c, 0x6c, 0x5c, 0xdb, 0x88, 0xbf, 0xbd, - 0xcd, 0x38, 0x05, 0x99, 0x2a, 0x75, 0x7c, 0xf0, 0x9a, 0x5b, 0x0d, 0xfd, - 0x90, 0x81, 0x73, 0x93, 0xf4, 0x4d, 0x96, 0xb7, 0xc3, 0xaf, 0xc0, 0x1f, - 0xfc, 0xfb, 0xc0, 0x9b, 0x52, 0x96, 0x06, 0xf9, 0x18, 0x7d, 0x8e, 0x82, - 0xa2, 0x96, 0x69, 0x3a, 0x1c, 0x13, 0xf5, 0x1f, 0x92, 0x46, 0x4f, 0x89, - 0x9e, 0x73, 0x3f, 0x12, 0xbc, 0xc9, 0xce, 0x5a, 0x06, 0xf4, 0x11, 0xf8, - 0x54, 0x64, 0xee, 0xd5, 0x49, 0xa7, 0xf7, 0xed, 0x5d, 0x53, 0xa3, 0x94, - 0xe8, 0x07, 0xde, 0x4b, 0x9a, 0x55, 0x3d, 0x04, 0x04, 0xbf, 0x37, 0x0f, - 0xe8, 0x9a, 0x48, 0x7d, 0xac, 0x65, 0x85, 0x3e, 0xee, 0xf2, 0x5c, 0x37, - 0x3d, 0xd7, 0xab, 0x79, 0x72, 0x2c, 0xf3, 0x58, 0xce, 0x93, 0xec, 0x39, - 0x84, 0xbe, 0x71, 0xc0, 0x3f, 0xf3, 0xc0, 0x7e, 0xf3, 0x73, 0xca, 0x06, - 0xca, 0xac, 0x8c, 0x44, 0x7a, 0x8d, 0x98, 0x91, 0x19, 0xfb, 0x97, 0x4a, - 0x22, 0x0d, 0xbd, 0xe8, 0xc6, 0x6e, 0xc9, 0xe3, 0x30, 0xaf, 0x6c, 0x1c, - 0xaa, 0xdb, 0xa9, 0x95, 0x2e, 0x5a, 0x15, 0x7d, 0xb5, 0xa0, 0x63, 0xe0, - 0x7e, 0x3c, 0x27, 0x6b, 0xb6, 0xb0, 0x7d, 0x77, 0xc3, 0x01, 0x8d, 0x1f, - 0x8a, 0xdc, 0xe4, 0xfd, 0x4c, 0xad, 0x7c, 0x54, 0x39, 0x23, 0xfa, 0xd2, - 0x60, 0x6c, 0x0f, 0xcd, 0x08, 0x9b, 0x8b, 0xf5, 0x97, 0x3a, 0xbb, 0x76, - 0x12, 0xf3, 0xcc, 0x22, 0x56, 0x62, 0x38, 0xdf, 0x0e, 0x64, 0x4a, 0x32, - 0xf6, 0x9d, 0xf2, 0xc4, 0xbe, 0x4f, 0x89, 0xd8, 0x37, 0xe2, 0xde, 0x80, - 0x2b, 0x60, 0xe9, 0x97, 0xcb, 0x82, 0x7d, 0x8c, 0xf3, 0x3e, 0x5a, 0x34, - 0x77, 0x5d, 0xf0, 0x9b, 0xc9, 0xe9, 0x60, 0xa2, 0xb7, 0x85, 0xac, 0x40, - 0xd2, 0xb1, 0xe3, 0x0f, 0x58, 0x87, 0xb8, 0x5d, 0xc0, 0x3c, 0x5f, 0xa2, - 0xf5, 0x52, 0x0b, 0xd3, 0x89, 0xcd, 0x78, 0xb7, 0xca, 0x3a, 0xed, 0x2c, - 0xbd, 0x5b, 0x22, 0xba, 0x5d, 0xbc, 0x8a, 0x5e, 0xbb, 0xb1, 0x07, 0x4c, - 0x2b, 0x88, 0x05, 0x67, 0x62, 0xf0, 0xb1, 0xb1, 0x5e, 0x1b, 0x6b, 0x55, - 0xb8, 0xd9, 0xc5, 0xb6, 0xa3, 0xc9, 0xff, 0x1d, 0xfe, 0x1f, 0x89, 0x00, - 0x2e, 0x6b, 0xc5, 0x31, 0xc1, 0x4b, 0x97, 0xf8, 0xfc, 0x12, 0x9f, 0x87, - 0x4c, 0x5d, 0x2b, 0x56, 0xde, 0x49, 0xc6, 0x13, 0x56, 0x72, 0xe2, 0xa4, - 0x1c, 0xc3, 0x38, 0x77, 0xf9, 0x7a, 0x62, 0x4f, 0x88, 0xe7, 0x31, 0xc3, - 0xf3, 0x58, 0x27, 0x99, 0xeb, 0x9d, 0x12, 0xef, 0x26, 0xba, 0x23, 0xde, - 0xcb, 0x3a, 0x53, 0xfc, 0x71, 0x3a, 0x13, 0x96, 0xef, 0xcf, 0xc5, 0x51, - 0x73, 0xd5, 0x49, 0xb3, 0x63, 0xa3, 0xaa, 0xe6, 0xea, 0xcd, 0x26, 0x35, - 0x57, 0xed, 0xb4, 0x36, 0x0f, 0xbb, 0xb7, 0x9d, 0xe9, 0xdd, 0x14, 0xb9, - 0x7a, 0x6b, 0xf3, 0xa2, 0x1f, 0x3e, 0xaf, 0xa7, 0xb2, 0x3e, 0xc3, 0xaa, - 0x79, 0x26, 0xde, 0x2d, 0x74, 0xa7, 0xdb, 0xcb, 0xbf, 0xc5, 0xf3, 0x49, - 0x58, 0x99, 0x09, 0xf7, 0x3a, 0xc4, 0x7c, 0xd7, 0xa7, 0xc5, 0xb8, 0xa0, - 0x67, 0x5c, 0x82, 0x32, 0x13, 0x98, 0xbf, 0x18, 0xf3, 0x3f, 0xc9, 0xb8, - 0x5e, 0x8f, 0xfb, 0x7e, 0x8b, 0x72, 0x42, 0xdf, 0xe7, 0xbf, 0x4b, 0x3d, - 0x81, 0xf5, 0x02, 0xfc, 0x26, 0x06, 0xe3, 0x3f, 0xe6, 0x66, 0x51, 0x76, - 0x89, 0xd7, 0x75, 0xbd, 0x2b, 0xf0, 0xa0, 0xf0, 0x93, 0x4a, 0xa6, 0x2e, - 0xb7, 0xa5, 0xde, 0xbf, 0x2e, 0x6d, 0xae, 0x28, 0x39, 0xd7, 0x20, 0x4b, - 0x21, 0x47, 0xb3, 0x95, 0xa0, 0x03, 0xbd, 0x0f, 0xb6, 0xd0, 0x25, 0xe6, - 0x63, 0x32, 0x3f, 0x89, 0x79, 0x2a, 0xf3, 0x32, 0x49, 0x47, 0xa9, 0xba, - 0xcf, 0x32, 0x48, 0x5c, 0x1e, 0xae, 0xe5, 0x45, 0xba, 0xe2, 0xe6, 0x21, - 0x57, 0xdc, 0xdc, 0x74, 0xe5, 0x45, 0x86, 0x85, 0x9e, 0x56, 0xd3, 0xad, - 0xc2, 0x4a, 0xb7, 0x8a, 0x8a, 0x9e, 0xf4, 0xe0, 0x71, 0x8b, 0x55, 0x1e, - 0xb7, 0x73, 0x13, 0x1e, 0xe7, 0x67, 0x9b, 0xae, 0x2a, 0x7e, 0x62, 0xc7, - 0x21, 0x6b, 0x6e, 0x31, 0xdf, 0xf8, 0x71, 0x79, 0x82, 0xf9, 0x49, 0x9c, - 0xf9, 0xc9, 0x18, 0xf3, 0x93, 0x18, 0xf3, 0x13, 0x87, 0x61, 0x60, 0xf1, - 0xda, 0xef, 0x05, 0x6e, 0xcf, 0x43, 0x8e, 0x4c, 0xd2, 0x95, 0x32, 0x78, - 0xf3, 0x18, 0xeb, 0x42, 0xf7, 0x02, 0x6b, 0xf3, 0x3d, 0x8c, 0xc7, 0x52, - 0xff, 0xa9, 0xb7, 0x6f, 0xec, 0x57, 0x51, 0x1f, 0x97, 0x8c, 0xaf, 0x81, - 0xff, 0xbc, 0x99, 0xa5, 0xee, 0xc0, 0xed, 0x42, 0x57, 0x60, 0xad, 0xf0, - 0x13, 0xf4, 0xa5, 0x78, 0x1d, 0x34, 0x8e, 0xbe, 0xbf, 0x3f, 0x1c, 0x9d, - 0xe4, 0xb9, 0x77, 0x07, 0x66, 0x79, 0x5f, 0xbe, 0x12, 0x4f, 0xf4, 0xf6, - 0x49, 0x5a, 0xc8, 0xe6, 0xc0, 0x3d, 0x17, 0x76, 0xd0, 0xfe, 0xf1, 0xe4, - 0x9e, 0x5e, 0xa6, 0x5b, 0xe0, 0x7b, 0xad, 0xef, 0x4e, 0x90, 0xf1, 0xb0, - 0x43, 0xf5, 0xeb, 0xb1, 0x58, 0x5e, 0x7e, 0xc8, 0xf7, 0x7f, 0x10, 0xc8, - 0x15, 0x5e, 0xe3, 0x67, 0xe3, 0xf8, 0x4f, 0xe1, 0xdf, 0x64, 0x7b, 0x01, - 0xbd, 0x7e, 0x3a, 0x79, 0x0c, 0xc6, 0xe2, 0xd8, 0x8e, 0x31, 0x6f, 0x8b, - 0xaf, 0x1a, 0xf6, 0x64, 0xc2, 0x78, 0x3e, 0x8a, 0x9e, 0xf1, 0x3f, 0x2c, - 0x3f, 0x15, 0x95, 0x31, 0xb6, 0xe7, 0xf6, 0x48, 0x3e, 0xc2, 0xb8, 0x19, - 0x4e, 0x08, 0x9b, 0xad, 0xe5, 0x9a, 0x94, 0x9b, 0x8b, 0xbc, 0xbf, 0x4b, - 0xf1, 0x18, 0xef, 0x6f, 0x97, 0x92, 0x99, 0x59, 0xbe, 0x2e, 0xe4, 0x31, - 0xcb, 0x4e, 0x86, 0x77, 0x91, 0x4c, 0xd1, 0x03, 0xe2, 0x14, 0xfa, 0xea, - 0x3c, 0x83, 0xe7, 0x31, 0xb6, 0x82, 0x6f, 0x7c, 0x18, 0xc8, 0x14, 0xf0, - 0x5e, 0xe0, 0x1f, 0xff, 0x2e, 0x4d, 0xd2, 0xd5, 0xbc, 0x9e, 0xc3, 0x80, - 0x61, 0x7c, 0x13, 0xf3, 0x08, 0xd0, 0x4e, 0xe7, 0xdf, 0x18, 0x4e, 0x7c, - 0xfc, 0x97, 0xde, 0x39, 0x9d, 0x57, 0x73, 0x42, 0x9f, 0xca, 0x36, 0x5e, - 0xc3, 0x4e, 0x42, 0xff, 0xa2, 0x45, 0xd1, 0x47, 0xb2, 0x55, 0xd8, 0xaa, - 0x8b, 0xc2, 0xe6, 0x38, 0xba, 0xa7, 0xd6, 0xdb, 0xf2, 0x71, 0xcf, 0xb9, - 0x9f, 0x07, 0x72, 0xf3, 0x87, 0x85, 0x6e, 0x36, 0x3c, 0xbe, 0x47, 0xd5, - 0x9c, 0x7e, 0x5e, 0x5c, 0x33, 0x16, 0x70, 0xed, 0x49, 0x75, 0xed, 0xd7, - 0x84, 0x4e, 0x8c, 0xfc, 0xb8, 0xd0, 0x35, 0x81, 0xdf, 0xbc, 0xaf, 0x4e, - 0x8c, 0xf1, 0x3b, 0xb2, 0x04, 0xdf, 0xbc, 0x80, 0xa7, 0x86, 0x07, 0x60, - 0x01, 0x9c, 0xef, 0x52, 0xf8, 0x6e, 0x5b, 0xa9, 0xa0, 0x5e, 0x77, 0x33, - 0x38, 0xb3, 0x8e, 0x93, 0xc7, 0x5a, 0xb1, 0xa6, 0xdd, 0x81, 0x44, 0xc9, - 0x32, 0x72, 0xf3, 0xb0, 0x71, 0xe0, 0x7f, 0xdc, 0x8b, 0xbc, 0x28, 0x9e, - 0xc3, 0x6e, 0x4a, 0xa4, 0x31, 0x2f, 0x8c, 0xd3, 0x30, 0x18, 0xf7, 0xc0, - 0xc2, 0x7d, 0xdf, 0x0e, 0x75, 0x5f, 0xbb, 0xd8, 0x0b, 0x32, 0xf0, 0x1e, - 0xfd, 0x6e, 0xbc, 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x2e, - 0xe6, 0xd7, 0xc9, 0x09, 0xf9, 0x2c, 0xe3, 0xa6, 0xbc, 0xb6, 0xcb, 0xf1, - 0x9f, 0xaf, 0xdc, 0x3f, 0xdc, 0xab, 0xf7, 0x6f, 0x07, 0x95, 0x84, 0x5f, - 0x09, 0xd7, 0xba, 0xc5, 0xb5, 0xa4, 0xd3, 0x2d, 0xf6, 0x75, 0x8e, 0x8f, - 0xcf, 0x16, 0x7a, 0x02, 0xb0, 0xd5, 0x73, 0xe9, 0xee, 0x40, 0xa9, 0x84, - 0xf5, 0x76, 0x07, 0x52, 0x8c, 0xf3, 0xd3, 0x85, 0x23, 0x95, 0x59, 0xc1, - 0x5b, 0x58, 0xc7, 0xed, 0xb3, 0xcd, 0x33, 0xc6, 0xcf, 0xc4, 0x9a, 0xf8, - 0x7d, 0xfc, 0x9b, 0xe9, 0x2e, 0xcf, 0x74, 0x97, 0x67, 0xba, 0xcb, 0x33, - 0xdd, 0xb1, 0x8d, 0xfa, 0x83, 0x3c, 0xd3, 0x1d, 0xcb, 0x90, 0xb7, 0x58, - 0x86, 0x48, 0x5a, 0x4d, 0x28, 0xdf, 0x9e, 0xa6, 0x55, 0x6f, 0x4d, 0xa6, - 0xa6, 0x4d, 0xc8, 0x6d, 0x0a, 0x1c, 0x1d, 0xad, 0xa7, 0xd1, 0x3b, 0x4c, - 0xa3, 0x2d, 0x53, 0xfd, 0xf4, 0xa0, 0x88, 0x3d, 0xb3, 0xad, 0x39, 0xe6, - 0xd1, 0xa9, 0x20, 0x74, 0xac, 0x10, 0xd3, 0x13, 0x74, 0x4c, 0x9b, 0xe1, - 0xde, 0x4f, 0xeb, 0xc5, 0x76, 0x1e, 0x03, 0x9a, 0xdd, 0xab, 0x8e, 0xf3, - 0x4c, 0xb3, 0x90, 0x7b, 0xd7, 0x02, 0x77, 0x0a, 0x06, 0xeb, 0x62, 0x21, - 0x33, 0x43, 0xe0, 0x9f, 0x42, 0x3f, 0xe3, 0x7d, 0x5f, 0x65, 0x7e, 0x0f, - 0xdf, 0x29, 0x7a, 0x77, 0x95, 0x20, 0x3b, 0x22, 0xb7, 0x99, 0x7f, 0x5e, - 0x28, 0x5e, 0x63, 0x3a, 0xef, 0xa3, 0x2f, 0x17, 0x21, 0x9f, 0x01, 0x23, - 0x3e, 0x2e, 0x91, 0xf0, 0x7d, 0x19, 0x53, 0x58, 0xfb, 0xfe, 0xac, 0x21, - 0xf0, 0xe4, 0xaf, 0x01, 0x07, 0x86, 0xfd, 0xdd, 0x3d, 0xe8, 0x69, 0x9f, - 0x30, 0x5a, 0x95, 0x8f, 0x17, 0xbf, 0x31, 0x1e, 0x63, 0x01, 0x37, 0x1c, - 0x37, 0x8b, 0x2f, 0xe2, 0x1b, 0x11, 0x71, 0x86, 0x87, 0x97, 0x5f, 0x5d, - 0xe5, 0xfb, 0x05, 0xbc, 0x26, 0x93, 0x41, 0xd4, 0x87, 0xd3, 0xd7, 0x82, - 0x53, 0x93, 0xf4, 0x72, 0x19, 0xf3, 0xbe, 0x42, 0xb3, 0x61, 0xf0, 0x1f, - 0x3b, 0x7e, 0x9f, 0x24, 0xec, 0xda, 0x59, 0xdf, 0xfc, 0xa2, 0x3f, 0x4f, - 0xb3, 0x92, 0x42, 0x3f, 0x6e, 0x63, 0x7b, 0x07, 0xb0, 0x79, 0x83, 0x71, - 0x2d, 0x0e, 0x1f, 0x80, 0xe2, 0x67, 0xdf, 0x67, 0x9e, 0x83, 0x3d, 0xc3, - 0x71, 0x3d, 0x0f, 0x5b, 0x53, 0x3c, 0xcc, 0x71, 0xf1, 0xb0, 0x5c, 0x95, - 0x87, 0x31, 0x2e, 0x08, 0xde, 0x05, 0xde, 0x74, 0x82, 0xf5, 0x45, 0xf9, - 0x1b, 0x7a, 0xe0, 0x4e, 0xc1, 0xab, 0x98, 0xb7, 0xb3, 0xfd, 0xb0, 0x58, - 0xce, 0x06, 0x8e, 0x08, 0x9e, 0xa1, 0xf1, 0xf9, 0xa9, 0x01, 0x49, 0x07, - 0xed, 0xd2, 0x1f, 0x79, 0x0a, 0x7c, 0xca, 0x6f, 0xfc, 0x67, 0x78, 0x1c, - 0xc6, 0x3b, 0x91, 0xd7, 0x99, 0x7f, 0x2d, 0xc6, 0x63, 0x22, 0x06, 0x22, - 0x6d, 0x9c, 0x2c, 0xdb, 0x01, 0xbb, 0x90, 0x6b, 0x69, 0x25, 0xab, 0xfc, - 0x4b, 0xd7, 0x1f, 0xc1, 0xaf, 0x88, 0x3d, 0x4e, 0xf4, 0x1a, 0x72, 0x1d, - 0x16, 0xd6, 0x31, 0x5b, 0xa4, 0xd0, 0x4c, 0x1c, 0xb9, 0x71, 0xe0, 0xeb, - 0x1f, 0xf0, 0xba, 0xb1, 0xaf, 0x1f, 0x60, 0x5f, 0xe5, 0xb5, 0x89, 0x63, - 0x62, 0x5e, 0xb3, 0xcb, 0x35, 0xfe, 0x37, 0x97, 0x1f, 0x30, 0x16, 0x0b, - 0x72, 0x6e, 0x4b, 0xa3, 0x92, 0xc7, 0x2d, 0x96, 0xd0, 0xab, 0x4b, 0xcc, - 0x91, 0xe7, 0xa6, 0xd7, 0x85, 0xf7, 0x6a, 0x7a, 0xdf, 0x0a, 0x6d, 0x3d, - 0xc3, 0x74, 0x84, 0x3d, 0xc8, 0xba, 0x70, 0xe4, 0x5b, 0xfc, 0x7e, 0x9c, - 0x6b, 0x9c, 0xff, 0x83, 0xea, 0xfc, 0x9f, 0xe4, 0xf9, 0x63, 0xcc, 0x07, - 0x2c, 0xef, 0xe5, 0xfc, 0x1f, 0x54, 0xe7, 0x5f, 0x54, 0xf3, 0xa7, 0x9c, - 0x31, 0xd5, 0xab, 0xf4, 0xf7, 0xa6, 0xcf, 0x6a, 0x9f, 0x99, 0x10, 0x63, - 0xcd, 0x19, 0xe8, 0x44, 0xa6, 0x9e, 0x8b, 0xb6, 0x0d, 0xdd, 0x73, 0xb1, - 0x63, 0xf7, 0xe9, 0x8f, 0x49, 0xea, 0x1d, 0x43, 0xac, 0x77, 0xe0, 0x3c, - 0xcd, 0x82, 0xcf, 0xe6, 0xc2, 0xe8, 0x11, 0x3b, 0xc8, 0x30, 0x62, 0x3b, - 0x6a, 0x82, 0xff, 0x0a, 0xbf, 0x18, 0x9e, 0xa3, 0xef, 0xff, 0x43, 0x5a, - 0x9f, 0x07, 0x2f, 0x86, 0xfe, 0x29, 0xfb, 0xc8, 0xae, 0xaf, 0x48, 0xff, - 0x6b, 0xca, 0xd7, 0xff, 0x0a, 0xdf, 0xeb, 0x04, 0xf4, 0x73, 0x13, 0x7e, - 0xda, 0x69, 0xf5, 0xed, 0x8f, 0x5c, 0x19, 0xcf, 0xf2, 0xe3, 0x2b, 0x93, - 0xae, 0x1c, 0x35, 0xe4, 0x8c, 0x64, 0x99, 0x4f, 0x38, 0x66, 0x8b, 0x21, - 0x6b, 0x64, 0x6e, 0x95, 0xb5, 0xae, 0x73, 0x8c, 0xf7, 0xc4, 0x89, 0x1b, - 0x46, 0x4a, 0xf8, 0x08, 0xda, 0x9d, 0x2e, 0x6a, 0x63, 0x39, 0x78, 0x8e, - 0xd0, 0xe7, 0xcc, 0xb6, 0x10, 0x3b, 0xb9, 0xca, 0x38, 0x36, 0x1b, 0xb7, - 0x23, 0xcf, 0x0b, 0x7b, 0x12, 0xf2, 0x01, 0xdf, 0x4e, 0x01, 0xac, 0x30, - 0x07, 0xfe, 0xbd, 0x8c, 0x9e, 0x95, 0x71, 0x5e, 0x3f, 0x7c, 0xbd, 0x23, - 0xd6, 0x5d, 0x96, 0x2b, 0x57, 0x85, 0x3f, 0xe5, 0x12, 0xeb, 0x92, 0xb6, - 0x79, 0x54, 0xd0, 0x99, 0x31, 0xc4, 0x54, 0xc1, 0x74, 0x82, 0x1c, 0x81, - 0xfd, 0xa2, 0xa7, 0x8e, 0xb4, 0x51, 0x78, 0x95, 0x2b, 0xaa, 0x57, 0x41, - 0x1a, 0xb4, 0xbf, 0x75, 0x5f, 0x42, 0xfa, 0xa1, 0x7d, 0x28, 0x6e, 0x1d, - 0xca, 0xeb, 0xa7, 0x86, 0x3d, 0x66, 0x89, 0xde, 0x8c, 0x80, 0x9d, 0xf0, - 0x03, 0x1a, 0x63, 0x0c, 0x37, 0xfd, 0x9d, 0x1a, 0xb7, 0xbd, 0x7f, 0x5e, - 0xd4, 0xdc, 0xbf, 0x59, 0x96, 0x32, 0x34, 0xc7, 0xb6, 0xf8, 0xec, 0xb8, - 0x5b, 0xa7, 0xb0, 0x0b, 0xd3, 0xc2, 0x07, 0x33, 0x40, 0xc9, 0x85, 0x31, - 0xfa, 0x7c, 0x1e, 0x3c, 0x88, 0xee, 0x27, 0x1d, 0xf1, 0xcd, 0x25, 0x9e, - 0xd3, 0x18, 0xa5, 0xca, 0x80, 0x51, 0x80, 0x66, 0x99, 0xcb, 0xe7, 0x0a, - 0x88, 0xbd, 0xf3, 0xef, 0x12, 0xbe, 0xa9, 0xf2, 0x3b, 0xca, 0xb7, 0x1d, - 0xa5, 0xe9, 0x05, 0xca, 0x66, 0xe2, 0x4f, 0x8b, 0x3e, 0xd3, 0x99, 0xf8, - 0xa8, 0xf2, 0xc9, 0x44, 0xf8, 0x3c, 0xfc, 0x5c, 0x16, 0x7d, 0x2e, 0x6f, - 0x67, 0x33, 0x24, 0x7d, 0x0d, 0xc4, 0x73, 0x30, 0x58, 0x76, 0xee, 0x64, - 0x9e, 0x70, 0x52, 0xf8, 0x1b, 0x58, 0xd3, 0x98, 0xc7, 0x78, 0xf8, 0x0a, - 0xfa, 0x08, 0xf6, 0x55, 0xa6, 0xf0, 0x92, 0x1a, 0x5b, 0x21, 0x93, 0x71, - 0xc1, 0xfc, 0x55, 0x27, 0x1b, 0x37, 0x6a, 0xf7, 0xc3, 0x57, 0x71, 0x52, - 0xe8, 0x7d, 0x43, 0xb4, 0x24, 0x68, 0xbd, 0x52, 0x99, 0x11, 0x7e, 0x07, - 0x3e, 0x2e, 0x4d, 0x0e, 0x4a, 0x5e, 0x25, 0xcf, 0x4b, 0x7f, 0x04, 0x3f, - 0xb3, 0xc4, 0xf3, 0xa8, 0xcb, 0x7f, 0x8f, 0x52, 0x62, 0x1b, 0xfe, 0xa1, - 0x53, 0x8f, 0xd4, 0x3f, 0xc4, 0xb0, 0x66, 0xd9, 0x71, 0x8b, 0x69, 0xe3, - 0xc7, 0x9b, 0xda, 0x6d, 0xef, 0x69, 0x19, 0xcc, 0xb0, 0x32, 0xc5, 0xb7, - 0x2b, 0xa0, 0x33, 0xcf, 0x96, 0xe7, 0xf0, 0x1d, 0x99, 0x40, 0x5a, 0xe8, - 0xb2, 0x11, 0xd6, 0x4d, 0xa0, 0xa3, 0x8c, 0x88, 0x78, 0x62, 0xe2, 0x59, - 0xcb, 0x98, 0x5d, 0xc1, 0xb7, 0xa1, 0xa0, 0x9b, 0xe9, 0x9c, 0x86, 0x76, - 0x91, 0xa7, 0x2e, 0xe3, 0xbc, 0x90, 0xaf, 0xe0, 0x79, 0x3f, 0x0f, 0x64, - 0x56, 0x9e, 0xde, 0xa5, 0xf3, 0xd5, 0x12, 0x61, 0x9d, 0x0f, 0xa3, 0x79, - 0x8a, 0xc6, 0x3d, 0x1d, 0xa3, 0x70, 0x7f, 0xcb, 0x0b, 0xb4, 0xeb, 0xd6, - 0x09, 0xe0, 0x57, 0x12, 0x7b, 0x74, 0x15, 0xb1, 0x31, 0xa3, 0x2e, 0xfe, - 0xd0, 0xc6, 0xfb, 0x64, 0x31, 0x6e, 0xc0, 0x5f, 0xf7, 0x05, 0xfe, 0x8b, - 0x38, 0x42, 0x69, 0x10, 0x7a, 0x50, 0xaf, 0xc3, 0x38, 0x33, 0x81, 0xe3, - 0x7e, 0x5a, 0x2c, 0x6a, 0xbd, 0x55, 0xfa, 0x90, 0x16, 0x97, 0xf5, 0x7e, - 0xc1, 0x7f, 0x34, 0xac, 0x7a, 0x08, 0xd8, 0x64, 0xf5, 0x01, 0x4e, 0x9f, - 0x14, 0x3d, 0x6e, 0x16, 0x73, 0xd8, 0x4a, 0xce, 0x11, 0xbe, 0x2f, 0x86, - 0x9e, 0x99, 0xfb, 0x00, 0x7b, 0xde, 0x23, 0x77, 0x4c, 0x62, 0x4e, 0x7d, - 0xff, 0xe7, 0x51, 0xed, 0xdb, 0x63, 0x3e, 0xfb, 0xf6, 0xd1, 0xa0, 0x8c, - 0x73, 0x3d, 0xa7, 0xc6, 0xf8, 0xe5, 0x99, 0xfe, 0xf3, 0x0b, 0xf0, 0x1f, - 0xd5, 0xea, 0x25, 0xee, 0x09, 0xbe, 0xd2, 0xe8, 0xc3, 0x8e, 0x30, 0x3f, - 0x95, 0x74, 0x7c, 0xd2, 0x87, 0x8e, 0xfb, 0x78, 0x8f, 0x4f, 0x3c, 0x04, - 0x1d, 0x9f, 0x68, 0x4a, 0xc7, 0x87, 0xa2, 0xd2, 0x87, 0xda, 0x48, 0xc7, - 0xa8, 0xd9, 0x39, 0x59, 0x6e, 0xe6, 0xaf, 0xc2, 0x3e, 0xa0, 0xf6, 0x1c, - 0xfe, 0x04, 0xc0, 0x4a, 0xfb, 0x14, 0x10, 0xdb, 0x03, 0x3e, 0x22, 0x56, - 0xf2, 0x17, 0x94, 0x9a, 0xf7, 0xc6, 0x38, 0x37, 0xba, 0xe7, 0x7d, 0x9f, - 0x7b, 0xa0, 0x6b, 0x83, 0x16, 0xec, 0x88, 0xb4, 0xd5, 0x35, 0xbc, 0xde, - 0x0d, 0x1c, 0x29, 0xda, 0xd9, 0x12, 0x18, 0x63, 0x4f, 0x98, 0xce, 0x23, - 0x8e, 0xaf, 0x7c, 0xbe, 0xc7, 0xf3, 0x72, 0xdd, 0xe6, 0xb8, 0xc0, 0x07, - 0xe8, 0xa3, 0x91, 0x74, 0x30, 0xcd, 0x7b, 0x2a, 0xfd, 0xbd, 0x99, 0xe5, - 0x88, 0xda, 0x27, 0x1e, 0x8b, 0xe7, 0xf9, 0xd6, 0xf3, 0x61, 0x7f, 0xec, - 0x57, 0x57, 0xab, 0x79, 0xc1, 0x90, 0x05, 0x15, 0xfa, 0x05, 0xcb, 0xb9, - 0xe0, 0xb8, 0x29, 0xfa, 0x28, 0xdc, 0x2a, 0x8f, 0xb3, 0x7e, 0x88, 0x3d, - 0x84, 0xaf, 0x50, 0xfb, 0x72, 0x7f, 0x31, 0x44, 0x3d, 0x87, 0x58, 0xea, - 0x1b, 0xe4, 0xb0, 0x7e, 0x68, 0x8c, 0x23, 0xbf, 0xdb, 0xe2, 0x7b, 0xd0, - 0xff, 0x69, 0xbf, 0x95, 0xa2, 0x2e, 0xf8, 0x09, 0xd0, 0xa7, 0xd9, 0xca, - 0xd5, 0xd1, 0xd4, 0x69, 0x41, 0x53, 0xa9, 0x95, 0xd3, 0x8a, 0xa6, 0x4e, - 0x2b, 0x7f, 0xf9, 0x69, 0x45, 0x53, 0xa7, 0x15, 0x4d, 0x9d, 0x56, 0x34, - 0x75, 0x9a, 0xf1, 0x7a, 0xc4, 0xec, 0x13, 0x3a, 0xbb, 0xf6, 0x57, 0xf6, - 0x50, 0xa6, 0x88, 0xf3, 0x90, 0xc7, 0x5e, 0xba, 0x7a, 0x75, 0x48, 0xd2, - 0xd5, 0x24, 0x2d, 0xca, 0x3c, 0x39, 0x7e, 0x17, 0xf6, 0xe0, 0xeb, 0x83, - 0xd4, 0x73, 0x2f, 0x70, 0x76, 0x1e, 0x73, 0x0d, 0xd0, 0xb4, 0xe8, 0xe1, - 0xda, 0x42, 0x49, 0xb7, 0x2e, 0x6b, 0xa2, 0x7e, 0x4b, 0xda, 0x6a, 0xd9, - 0xa6, 0xb5, 0x5c, 0x1a, 0x2f, 0xa6, 0xd4, 0x7e, 0x79, 0xed, 0x98, 0x36, - 0x4a, 0x17, 0x00, 0x57, 0xe4, 0x32, 0x5a, 0xbc, 0x37, 0x02, 0x4e, 0x59, - 0xd3, 0x07, 0x06, 0xc7, 0x15, 0x0c, 0xbe, 0x22, 0xd6, 0x88, 0x5c, 0x40, - 0xf8, 0x1c, 0x9b, 0xc3, 0x21, 0x97, 0x1f, 0xe1, 0xe7, 0x30, 0xee, 0x8f, - 0x47, 0x98, 0x07, 0x6d, 0x1d, 0x0e, 0xb5, 0xb5, 0x37, 0xe3, 0x35, 0x5b, - 0xad, 0x87, 0xb9, 0xef, 0x92, 0x1d, 0x11, 0x25, 0x37, 0xa4, 0x9e, 0xfb, - 0x98, 0x63, 0xa7, 0xb3, 0x3c, 0xb7, 0xbf, 0x8f, 0xb7, 0xef, 0xa5, 0x8e, - 0x0a, 0x1d, 0x8b, 0x03, 0x9f, 0x7b, 0xd8, 0x6e, 0xe4, 0x39, 0xec, 0xaf, - 0xd0, 0xd5, 0xf8, 0x01, 0xb6, 0x4d, 0xf0, 0x2d, 0xa6, 0x11, 0xfe, 0xef, - 0x24, 0x82, 0x01, 0xcc, 0xab, 0x8b, 0xef, 0x0d, 0x93, 0xd1, 0x9b, 0xe8, - 0x6d, 0x57, 0xba, 0x29, 0xfc, 0x6e, 0xac, 0x9b, 0x1a, 0x33, 0xf1, 0x1d, - 0xaa, 0xa6, 0x0c, 0xbe, 0x6a, 0xc4, 0xb1, 0x7e, 0x56, 0x91, 0xbd, 0x00, - 0xa2, 0xea, 0xf8, 0xa7, 0x95, 0x44, 0x14, 0xc7, 0x26, 0xdd, 0x60, 0x7b, - 0x39, 0x11, 0x18, 0xd9, 0x2b, 0x74, 0xf6, 0x80, 0x7d, 0x4c, 0xe6, 0x30, - 0xd8, 0xa6, 0x15, 0xf0, 0xc3, 0x77, 0xa9, 0xeb, 0xd4, 0xf2, 0x4c, 0x81, - 0xff, 0x15, 0xfa, 0x4f, 0xa6, 0x55, 0x93, 0x10, 0xb3, 0x98, 0x14, 0xb5, - 0xce, 0xc8, 0x33, 0x3e, 0x3b, 0x0f, 0x9a, 0x85, 0xdf, 0xd0, 0x51, 0x7b, - 0xfc, 0x29, 0xe4, 0x89, 0x15, 0x16, 0x69, 0x63, 0x59, 0x01, 0xbf, 0xd8, - 0xc8, 0xc2, 0x5a, 0x6f, 0x58, 0xd4, 0x5e, 0xc3, 0xcf, 0xa9, 0xf3, 0x89, - 0xf7, 0xf3, 0xf3, 0x43, 0xe2, 0xdb, 0x72, 0xd3, 0xd7, 0x30, 0xae, 0x95, - 0x86, 0x17, 0x2a, 0x4f, 0xf1, 0x75, 0x11, 0x2f, 0xcc, 0x50, 0xbb, 0x8a, - 0x05, 0x74, 0xa9, 0xf8, 0x51, 0x84, 0x69, 0xa8, 0x56, 0x53, 0x3c, 0x5c, - 0xf5, 0x9d, 0x01, 0xb7, 0xbd, 0xbe, 0xb3, 0xaf, 0x6d, 0x22, 0x67, 0x36, - 0xc3, 0x67, 0xe4, 0x82, 0xb6, 0x91, 0xf2, 0x09, 0x5a, 0xb3, 0xb4, 0xd5, - 0xda, 0xb9, 0x6d, 0xdf, 0xd3, 0xde, 0x3a, 0xb5, 0x7a, 0xf1, 0xae, 0xd3, - 0xa1, 0xf0, 0xa8, 0x95, 0xce, 0x16, 0x3b, 0x58, 0x56, 0xa3, 0xce, 0x09, - 0xf0, 0x0a, 0x46, 0x51, 0x27, 0xf2, 0x5c, 0xa8, 0x95, 0x96, 0x97, 0x91, - 0xd3, 0xf0, 0x67, 0x7b, 0x65, 0x7e, 0x6e, 0x9a, 0xe1, 0x72, 0x88, 0xe5, - 0x9a, 0xa1, 0x62, 0x35, 0x38, 0x07, 0x9e, 0x20, 0x7a, 0x78, 0x86, 0x9e, - 0x1e, 0xed, 0x60, 0x7d, 0x5e, 0xfa, 0xfa, 0x0f, 0xf3, 0xb3, 0xbf, 0x57, - 0x4c, 0xc3, 0x4f, 0x65, 0x1e, 0xe5, 0xe7, 0x4f, 0xb3, 0x1e, 0x90, 0xa0, - 0x56, 0x5a, 0x5a, 0x6e, 0x65, 0x7d, 0xbe, 0x95, 0xf5, 0x80, 0x11, 0x73, - 0x38, 0x20, 0xde, 0x25, 0x6a, 0x52, 0x3e, 0x1b, 0x3a, 0x64, 0x1e, 0x13, - 0x79, 0x36, 0x7f, 0xa5, 0xde, 0xe5, 0x7d, 0xc7, 0x07, 0x15, 0x1c, 0x1f, - 0x0d, 0xae, 0x5e, 0xbc, 0xe3, 0x98, 0x8c, 0x7f, 0x93, 0xac, 0xf3, 0x86, - 0xc5, 0xf7, 0x17, 0x8d, 0xa9, 0x29, 0xd6, 0xff, 0xf1, 0x8d, 0xb7, 0x67, - 0x28, 0x5b, 0x3e, 0x45, 0x5f, 0x2f, 0xbb, 0x7d, 0xaf, 0xcf, 0xf0, 0x9c, - 0x65, 0xed, 0x7c, 0x1b, 0xcf, 0xeb, 0x3d, 0xc7, 0xcb, 0x2b, 0x3a, 0x28, - 0xf8, 0xad, 0x30, 0xb5, 0x7e, 0x03, 0x3e, 0x8f, 0x0a, 0x15, 0xe2, 0xf6, - 0xd5, 0xfb, 0x24, 0xfd, 0xbc, 0x37, 0x44, 0x5e, 0x2a, 0xdf, 0xcf, 0xcf, - 0x9c, 0xc3, 0xb8, 0x1b, 0x16, 0xdd, 0x76, 0x24, 0xbc, 0xff, 0x36, 0x14, - 0xa6, 0xe0, 0x1b, 0xc8, 0xf5, 0x82, 0x8e, 0xb5, 0x7a, 0xd1, 0x39, 0xc0, - 0x7c, 0xfa, 0x1b, 0xb8, 0x8f, 0xff, 0xbe, 0x81, 0xe3, 0x0e, 0x5e, 0x27, - 0xe4, 0x2c, 0x72, 0x4a, 0xc0, 0xdf, 0x0e, 0x45, 0x4c, 0x81, 0x7f, 0xcf, - 0x30, 0x4e, 0xb5, 0x08, 0x1f, 0x5f, 0x1f, 0xc6, 0x3a, 0x83, 0xac, 0x13, - 0xac, 0x5e, 0x1c, 0x3d, 0x80, 0xe3, 0x44, 0x6f, 0x90, 0x61, 0x24, 0x71, - 0xa8, 0xe1, 0x9b, 0x75, 0xa1, 0xc3, 0xa3, 0xe4, 0xfa, 0x6e, 0x1d, 0x7a, - 0x26, 0x75, 0x50, 0x8a, 0xdf, 0x31, 0x5d, 0x94, 0xeb, 0x9e, 0x2b, 0x07, - 0x49, 0xfa, 0x87, 0x52, 0x43, 0xfa, 0xfb, 0x84, 0xd4, 0x8f, 0x67, 0x6b, - 0x5a, 0xc1, 0xef, 0x1e, 0x7a, 0x50, 0xec, 0xa2, 0x75, 0x15, 0x43, 0x7a, - 0x20, 0xec, 0x29, 0xe6, 0xc5, 0xe9, 0x1e, 0xba, 0xbf, 0xdc, 0x42, 0xd4, - 0xd7, 0x21, 0x62, 0xbc, 0x0f, 0x8a, 0x8b, 0x94, 0x7c, 0xed, 0xc9, 0x21, - 0xe9, 0x4f, 0xa9, 0xe1, 0xc8, 0x03, 0x1f, 0x1c, 0x79, 0x57, 0xe0, 0xc8, - 0xf0, 0xd0, 0xc6, 0x38, 0xb2, 0x47, 0xe7, 0x22, 0x52, 0xab, 0xc2, 0x8f, - 0xd7, 0x19, 0x3f, 0x5e, 0x66, 0xfc, 0x38, 0xd2, 0x04, 0x3f, 0x0c, 0x0f, - 0x7e, 0x1c, 0x15, 0xf8, 0xf1, 0xeb, 0x43, 0x1b, 0xe1, 0xc7, 0x91, 0xe0, - 0x46, 0x3e, 0x1e, 0x8d, 0x9b, 0x03, 0xb4, 0x54, 0x74, 0x68, 0x79, 0xde, - 0x8e, 0x27, 0x68, 0x35, 0x22, 0x63, 0x83, 0x53, 0xa2, 0x4e, 0x65, 0x51, - 0xe0, 0x55, 0x5a, 0xf8, 0x2f, 0xfd, 0xbf, 0x1b, 0x68, 0x29, 0xf8, 0xcb, - 0x3d, 0x99, 0xce, 0xaf, 0x5e, 0xfc, 0x3b, 0xde, 0xc7, 0xdb, 0x2b, 0xa1, - 0x10, 0xae, 0x05, 0xa7, 0xc2, 0xb4, 0xb6, 0x82, 0xef, 0x12, 0x46, 0xe8, - 0x4e, 0x31, 0x4a, 0xb7, 0x8b, 0x03, 0xb4, 0x56, 0x1c, 0xa2, 0xbb, 0x45, - 0xbc, 0x03, 0x30, 0xe7, 0x63, 0x01, 0x73, 0x83, 0x0e, 0x87, 0x79, 0xcc, - 0xf2, 0x00, 0xad, 0x2e, 0x6b, 0x7c, 0x05, 0xae, 0x62, 0xff, 0xe1, 0x27, - 0xf0, 0xc7, 0x81, 0xe9, 0x3a, 0x1c, 0x90, 0xf7, 0x60, 0xef, 0x67, 0x1b, - 0x6b, 0x64, 0x45, 0x9e, 0xa5, 0xc9, 0x38, 0xd2, 0x32, 0x65, 0x0b, 0x5f, - 0xea, 0xe1, 0x20, 0x74, 0xd9, 0xc4, 0x3e, 0xea, 0xe1, 0x3d, 0x70, 0x90, - 0x27, 0x34, 0xc4, 0x7a, 0xe9, 0x0e, 0xa1, 0x87, 0x26, 0x9d, 0x50, 0x64, - 0x9a, 0x2a, 0x97, 0x0c, 0x07, 0x3d, 0x0f, 0xd3, 0xfc, 0x3c, 0x43, 0xf9, - 0x71, 0xba, 0x5d, 0xf8, 0xe4, 0xd5, 0x39, 0x11, 0x8b, 0x7d, 0x96, 0xe7, - 0x0c, 0xf9, 0x58, 0x8b, 0x73, 0x50, 0x35, 0xce, 0xd1, 0xce, 0xeb, 0x96, - 0xb4, 0x34, 0xe3, 0xf0, 0xb8, 0x32, 0x8f, 0x2b, 0x23, 0x76, 0xc6, 0xe7, - 0x97, 0x11, 0xb7, 0x8d, 0xd2, 0xda, 0x3c, 0x68, 0x0e, 0x7e, 0x89, 0x5a, - 0xac, 0x74, 0x6d, 0x05, 0xe7, 0xe1, 0x9b, 0xa8, 0xc5, 0x4a, 0xd7, 0x54, - 0xac, 0x74, 0x6d, 0x65, 0x4a, 0xf0, 0xe1, 0xd9, 0xff, 0xdd, 0x14, 0x60, - 0x19, 0x30, 0x85, 0x19, 0xba, 0x4e, 0x53, 0x0d, 0x7a, 0xbf, 0x4e, 0x0c, - 0x78, 0x6c, 0x58, 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d, - 0xb8, 0xfd, 0xe3, 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23, - 0x80, 0x79, 0x49, 0x18, 0x9a, 0x97, 0x60, 0x73, 0xaf, 0xfc, 0x0c, 0x90, - 0xbb, 0x7a, 0x6c, 0xc0, 0x6d, 0x7c, 0x48, 0xf9, 0x23, 0x83, 0x56, 0xfe, - 0x30, 0xb0, 0x38, 0xa9, 0x43, 0xf4, 0x37, 0xad, 0x7f, 0x2c, 0x07, 0x1b, - 0x5f, 0x6b, 0x02, 0x9a, 0xdb, 0x3c, 0x85, 0x94, 0xb9, 0x5b, 0x60, 0xbd, - 0x89, 0x75, 0x5d, 0x26, 0xb1, 0x76, 0xc3, 0xd2, 0x42, 0x0c, 0x19, 0xe9, - 0x09, 0x62, 0x06, 0x22, 0x3d, 0xd9, 0x00, 0xcb, 0x4e, 0x16, 0x60, 0x5e, - 0x11, 0x02, 0xd6, 0x0f, 0x0c, 0xd0, 0x3a, 0xe6, 0x00, 0x78, 0x2c, 0xa1, - 0x89, 0x01, 0x74, 0x07, 0x27, 0xd0, 0xfe, 0x7e, 0x65, 0xf0, 0xba, 0xe3, - 0x06, 0x09, 0x88, 0xa1, 0x8b, 0x7a, 0x14, 0xe5, 0x41, 0x79, 0xd4, 0x49, - 0x85, 0x81, 0xc4, 0xfc, 0x04, 0xf2, 0x1f, 0xd0, 0x1f, 0x20, 0x3f, 0x02, - 0xf3, 0x93, 0x33, 0x50, 0x0e, 0xb4, 0x36, 0xaa, 0x79, 0x0d, 0x48, 0x1f, - 0x28, 0x0c, 0x41, 0x65, 0x2a, 0x68, 0x8c, 0x03, 0xc8, 0x5e, 0x22, 0x04, - 0x0d, 0x3b, 0x20, 0x0d, 0x64, 0x37, 0x4f, 0x11, 0x01, 0xf3, 0x93, 0x02, - 0x84, 0x18, 0x1a, 0xe0, 0xf9, 0x89, 0x1d, 0xe8, 0x52, 0x98, 0x9b, 0xfe, - 0xff, 0x3f, 0xa6, 0xc2, 0x02, 0x4c, 0x7b, 0xa0, 0xb5, 0xb5, 0xbf, 0xff, - 0x1f, 0x10, 0x61, 0x61, 0x68, 0x81, 0xaf, 0xd1, 0x0b, 0x94, 0x07, 0x95, - 0x73, 0x0b, 0x80, 0xac, 0x36, 0x78, 0xbd, 0x0d, 0x92, 0x07, 0x89, 0xfd, - 0x02, 0x96, 0x2b, 0xff, 0xff, 0x2f, 0x85, 0xab, 0x05, 0x01, 0x00, 0xb3, - 0x28, 0x79, 0xae, 0x58, 0x7d, 0x00, 0x00, 0x00 }; + 0xcd, 0x7c, 0x0d, 0x70, 0x5c, 0xd5, 0x95, 0xe6, 0xe9, 0xd7, 0xdd, 0x52, + 0x4b, 0x96, 0xe5, 0x27, 0xb9, 0x51, 0x1a, 0xa2, 0x24, 0xef, 0xa9, 0x9f, + 0xa4, 0x06, 0x29, 0xe4, 0xd9, 0x08, 0x10, 0x49, 0x0f, 0x34, 0xdd, 0x92, + 0x11, 0x89, 0x77, 0x24, 0x40, 0x61, 0xbc, 0x3b, 0xae, 0xac, 0xa6, 0x2d, + 0x13, 0x42, 0x31, 0x35, 0xae, 0x0a, 0x3b, 0x71, 0xb2, 0x04, 0x37, 0x2d, + 0x99, 0x38, 0x8c, 0xec, 0x56, 0x64, 0x59, 0x66, 0x67, 0xd8, 0xd9, 0x4e, + 0x4b, 0xb2, 0x19, 0xa6, 0xed, 0xc6, 0x90, 0x1f, 0xa6, 0x92, 0x0c, 0x5a, + 0xe3, 0x00, 0x93, 0xcd, 0x56, 0x41, 0x2a, 0xb5, 0xcb, 0x6c, 0x51, 0xbb, + 0x5e, 0x27, 0x4c, 0xb2, 0xa9, 0xda, 0x0a, 0x3b, 0x93, 0xda, 0x65, 0xf2, + 0x33, 0x6f, 0xbf, 0xef, 0xbe, 0xfb, 0xa4, 0x96, 0xac, 0x38, 0x4c, 0xa6, + 0x52, 0x35, 0xaa, 0xea, 0xba, 0xef, 0xde, 0x77, 0x7f, 0xce, 0x3d, 0xf7, + 0xdc, 0x73, 0xbe, 0x73, 0xee, 0x7d, 0xba, 0x55, 0xa4, 0x59, 0xf4, 0xdf, + 0x56, 0xfc, 0x06, 0x7e, 0xff, 0x0f, 0xf6, 0xdd, 0x78, 0xbd, 0x7b, 0x3d, + 0xf3, 0x46, 0x54, 0x22, 0x4c, 0xc3, 0xf8, 0xc5, 0xf1, 0xdb, 0xa9, 0x9f, + 0x37, 0xfb, 0x33, 0xf1, 0xbb, 0x29, 0x24, 0x32, 0xf1, 0x23, 0x91, 0xd0, + 0x86, 0x77, 0xb1, 0x4d, 0xea, 0x7b, 0xde, 0x2f, 0xe9, 0x48, 0xff, 0x19, + 0xf8, 0x59, 0x57, 0xae, 0xb2, 0x3a, 0xee, 0xaf, 0xfb, 0x17, 0xd6, 0xcd, + 0xb7, 0xea, 0x9f, 0xc4, 0x8c, 0xf4, 0xc5, 0xdf, 0xce, 0x3a, 0x12, 0x0b, + 0xa7, 0xbf, 0x3b, 0xba, 0xcf, 0x11, 0xc9, 0x54, 0xfb, 0xac, 0x9c, 0xfc, + 0xc2, 0x2b, 0xc4, 0x23, 0xc2, 0xf2, 0xf7, 0xa4, 0x7f, 0x7e, 0xe8, 0x1b, + 0x37, 0xdb, 0x6f, 0x95, 0xc3, 0x12, 0x33, 0xd3, 0x6f, 0x8b, 0xd9, 0x23, + 0xb1, 0x4e, 0xb4, 0x79, 0xb2, 0xf7, 0x29, 0x43, 0x5a, 0x83, 0xbe, 0xcc, + 0x89, 0x70, 0x5a, 0xc6, 0x26, 0x67, 0x0e, 0x79, 0x86, 0x23, 0x85, 0x6b, + 0xd2, 0x8e, 0x55, 0x94, 0x96, 0xc1, 0xe9, 0x81, 0x9b, 0x05, 0xf9, 0xb1, + 0xc9, 0x6a, 0x4c, 0xb2, 0xb5, 0x42, 0x8b, 0xe1, 0x38, 0x48, 0x63, 0x85, + 0x77, 0xa7, 0x25, 0xd6, 0x90, 0x9e, 0x6f, 0x7c, 0xc9, 0xe1, 0xf8, 0x89, + 0xd1, 0xac, 0xf3, 0x6e, 0x89, 0x38, 0x9e, 0x37, 0x8d, 0xf1, 0x77, 0x55, + 0x7f, 0xe1, 0x3d, 0x1a, 0xf1, 0xc7, 0x36, 0xd2, 0x07, 0xc3, 0x4c, 0x43, + 0x69, 0x6b, 0xb4, 0xab, 0xaa, 0xf2, 0x0d, 0x7e, 0xde, 0xd1, 0xf9, 0x58, + 0xb3, 0x4f, 0xbb, 0x34, 0x81, 0xf6, 0x58, 0x24, 0x9d, 0x6e, 0x42, 0x1f, + 0xb1, 0x68, 0xfa, 0x99, 0xdf, 0x5a, 0x56, 0xf5, 0xee, 0xd7, 0xf5, 0xee, + 0x8f, 0xfa, 0xed, 0x26, 0x47, 0x7b, 0xaa, 0x4c, 0x1f, 0x1a, 0xed, 0x56, + 0xe9, 0xc3, 0xa3, 0x49, 0x95, 0x16, 0x54, 0xbd, 0x50, 0x7a, 0x7a, 0xd4, + 0x51, 0x69, 0xa7, 0x2e, 0x4f, 0x8d, 0x5a, 0x2a, 0xed, 0xd7, 0xa9, 0xab, + 0xd3, 0x01, 0x9d, 0x0e, 0xea, 0x34, 0xad, 0xd3, 0x8c, 0x4e, 0x87, 0x74, + 0x3f, 0x23, 0x3a, 0xbf, 0x5b, 0xa7, 0x63, 0x3a, 0x1d, 0xd7, 0xe9, 0x1e, + 0x9d, 0xee, 0xd5, 0x74, 0x4d, 0xe8, 0xf4, 0x41, 0x5d, 0x7e, 0x40, 0xd3, + 0x79, 0x10, 0xf4, 0x7c, 0xa6, 0x51, 0xcb, 0x2d, 0xe6, 0x6b, 0xc9, 0xbe, + 0x99, 0x98, 0x14, 0x4b, 0x61, 0xc9, 0xa9, 0xf5, 0xfc, 0x7c, 0x54, 0x9a, + 0x63, 0x32, 0x55, 0x8b, 0xc9, 0x45, 0x25, 0xae, 0x3f, 0xf4, 0xbe, 0xd1, + 0x6b, 0xca, 0x33, 0xb5, 0xb8, 0xbc, 0x50, 0x93, 0xd0, 0x58, 0x6f, 0x93, + 0x18, 0x73, 0xd7, 0x48, 0xc6, 0x0c, 0x49, 0x58, 0xf1, 0xd5, 0x92, 0xec, + 0x4c, 0x07, 0xf2, 0x76, 0x42, 0xe4, 0xe5, 0xa8, 0xbf, 0x8e, 0x31, 0x09, + 0x2f, 0x70, 0x5d, 0x16, 0x46, 0x5f, 0x9a, 0x4f, 0x48, 0xe4, 0x98, 0x85, + 0xfe, 0x5b, 0x24, 0xba, 0x20, 0x9d, 0x61, 0xe9, 0x4e, 0xdc, 0x87, 0x1a, + 0x43, 0xd5, 0x88, 0x0c, 0x57, 0x43, 0x58, 0xab, 0x18, 0xe4, 0xa4, 0x05, + 0x3f, 0x13, 0xbf, 0x38, 0x7e, 0x09, 0xfc, 0x3c, 0xf4, 0xd3, 0x29, 0xb9, + 0x2a, 0xfb, 0xc4, 0xb8, 0x25, 0x8c, 0x5f, 0xb2, 0xcd, 0x09, 0x21, 0x4d, + 0x09, 0xf9, 0x46, 0xaf, 0x4f, 0xd3, 0x0b, 0xb5, 0x58, 0x28, 0x7b, 0x52, + 0x0e, 0xe4, 0x5c, 0xb1, 0x0c, 0xa7, 0x59, 0xf2, 0x66, 0xc8, 0x9a, 0x4c, + 0xb5, 0x4b, 0x61, 0x1c, 0xef, 0x4a, 0x92, 0x31, 0xd0, 0x77, 0xde, 0x94, + 0x09, 0xff, 0x1d, 0xcb, 0xfe, 0x1e, 0xfb, 0xd5, 0x36, 0x29, 0xb8, 0x2f, + 0x94, 0xfe, 0x02, 0xcf, 0xec, 0xeb, 0xcd, 0x88, 0x4f, 0xf3, 0xdb, 0xc8, + 0xb3, 0xfc, 0x67, 0xdb, 0xfc, 0x3c, 0x9f, 0x59, 0x37, 0x18, 0x33, 0x98, + 0x2b, 0xc7, 0xee, 0xc5, 0x7c, 0x39, 0xfe, 0xea, 0x7c, 0x41, 0x47, 0x4b, + 0x28, 0x77, 0xd2, 0x92, 0xc3, 0xa5, 0x5b, 0x25, 0xeb, 0x7a, 0xde, 0x3e, + 0x57, 0xe2, 0x86, 0x74, 0x9b, 0x39, 0xbc, 0xad, 0x54, 0x25, 0x94, 0x2d, + 0x05, 0xfc, 0x60, 0xbf, 0x11, 0x94, 0x75, 0xa0, 0x7e, 0x6b, 0x68, 0xe8, + 0x24, 0x68, 0x4f, 0x93, 0x2f, 0x90, 0x59, 0xb7, 0x3b, 0x31, 0x89, 0xf1, + 0x16, 0xab, 0xdd, 0xee, 0x79, 0x31, 0xd1, 0x67, 0x3b, 0xea, 0x90, 0x47, + 0xec, 0x8b, 0x7d, 0xb2, 0xbf, 0x16, 0xb4, 0x8d, 0xe3, 0x1d, 0x69, 0xf2, + 0xbc, 0xac, 0x6b, 0x32, 0x2f, 0x65, 0xf0, 0xad, 0x4c, 0xbe, 0x35, 0x77, + 0xca, 0xa9, 0x2a, 0xc7, 0xd8, 0x8c, 0xee, 0xeb, 0xfe, 0x99, 0xd1, 0x9d, + 0x40, 0xff, 0x71, 0xa4, 0x5b, 0x42, 0xd9, 0xe3, 0x1e, 0xc6, 0x4f, 0xe0, + 0x79, 0xb3, 0x39, 0x5c, 0xd4, 0x32, 0x98, 0x00, 0xed, 0x71, 0x39, 0xa7, + 0xe4, 0x70, 0x8b, 0x84, 0x21, 0x87, 0x5c, 0xe3, 0xb6, 0x85, 0x1b, 0x25, + 0x1f, 0xb7, 0x2d, 0xea, 0xce, 0xae, 0x9d, 0x4d, 0x98, 0xa3, 0xd6, 0x82, + 0xc7, 0xe2, 0x90, 0xc3, 0xf3, 0x6d, 0x06, 0x4a, 0x0c, 0xb1, 0xcd, 0x7f, + 0x25, 0x05, 0xc9, 0x2d, 0x7d, 0x2a, 0x24, 0xcd, 0x06, 0xea, 0x5d, 0x1b, + 0xf2, 0x79, 0x40, 0xfe, 0x64, 0xc0, 0x9f, 0x90, 0xf8, 0xfb, 0x3a, 0x23, + 0x5d, 0x55, 0xbe, 0xef, 0xb3, 0x0c, 0xf5, 0x6e, 0x08, 0xef, 0x22, 0x92, + 0xdc, 0x19, 0xbc, 0x1f, 0xc2, 0xfb, 0x6b, 0x64, 0xc2, 0x04, 0x2d, 0xa5, + 0xe7, 0x8d, 0x2c, 0x68, 0xbc, 0x3d, 0xa2, 0xe6, 0x8a, 0xba, 0x13, 0x75, + 0xfd, 0x4c, 0xa0, 0xde, 0x1f, 0x63, 0x2c, 0xd0, 0x5b, 0xb2, 0x40, 0x4b, + 0x07, 0x68, 0x21, 0x8d, 0x05, 0x23, 0x5b, 0x8b, 0x20, 0x3f, 0x6d, 0xe4, + 0x4e, 0x1f, 0xc1, 0xb3, 0x98, 0x46, 0xfa, 0x79, 0xa6, 0x68, 0xbf, 0xb7, + 0xae, 0xfd, 0x5e, 0xb4, 0xe7, 0x18, 0x6c, 0xef, 0xcb, 0x7f, 0x41, 0xc9, + 0xa2, 0x75, 0x05, 0x7e, 0x84, 0x7f, 0x0d, 0x7e, 0x7c, 0x4d, 0xf3, 0xe3, + 0x67, 0xf2, 0x9b, 0xe7, 0xc7, 0x7f, 0xff, 0x0d, 0xf1, 0x43, 0x24, 0x7f, + 0x9c, 0xcf, 0x11, 0x29, 0x28, 0xbd, 0xc5, 0x7d, 0x4b, 0x79, 0xa7, 0xce, + 0x22, 0x9f, 0x28, 0xc7, 0xd8, 0x03, 0xb5, 0x08, 0xd2, 0xa7, 0x90, 0x6e, + 0x09, 0x8d, 0x1d, 0xbf, 0x84, 0xf5, 0xf7, 0xc4, 0xdc, 0x19, 0xd8, 0x8d, + 0x42, 0xc2, 0x94, 0x4e, 0x31, 0xaf, 0x87, 0xd1, 0xee, 0xb0, 0xcd, 0xbc, + 0xbc, 0x89, 0xf7, 0xbf, 0x08, 0x05, 0xf6, 0x3d, 0x3b, 0xd3, 0xf4, 0x76, + 0x46, 0x3d, 0x45, 0xc9, 0xcf, 0x8c, 0x91, 0x8e, 0x84, 0x72, 0x25, 0x6b, + 0xc2, 0x48, 0xc7, 0xa1, 0xa7, 0x98, 0x1f, 0x0c, 0xf9, 0x34, 0x0f, 0xa0, + 0x6e, 0xa0, 0xb3, 0x02, 0xda, 0x07, 0x40, 0xfb, 0x46, 0xdd, 0x95, 0x01, + 0x2d, 0xa4, 0x81, 0x74, 0x55, 0xc2, 0x9a, 0xf7, 0xe8, 0xe7, 0xa0, 0xea, + 0x27, 0x9c, 0x1e, 0x14, 0xda, 0xd0, 0xfc, 0x0c, 0xf7, 0x01, 0xdb, 0xb1, + 0x2f, 0x5f, 0x27, 0xe7, 0xab, 0x41, 0x1f, 0x85, 0xba, 0x3e, 0x0a, 0xa0, + 0x47, 0xb6, 0x19, 0x4e, 0x14, 0x6b, 0xcf, 0xae, 0x8e, 0xe0, 0xdd, 0x93, + 0x92, 0x3d, 0x7d, 0xb3, 0x81, 0x39, 0xa0, 0x5f, 0xf2, 0x68, 0x0c, 0x3a, + 0x9b, 0xfb, 0x2c, 0x26, 0xb9, 0x38, 0xcb, 0x3e, 0xa6, 0xc7, 0x8d, 0x48, + 0x46, 0xe5, 0x5f, 0x69, 0x5d, 0xa3, 0xe3, 0x79, 0x3d, 0x9f, 0x34, 0xe6, + 0x43, 0x1a, 0x82, 0xb9, 0xa4, 0xeb, 0xe6, 0x12, 0xf0, 0x9a, 0xbc, 0x30, + 0xa1, 0xe3, 0x63, 0xda, 0x86, 0xb0, 0xdd, 0x74, 0xdd, 0xda, 0x4d, 0xa3, + 0x0d, 0x79, 0x8f, 0x3a, 0x1b, 0xec, 0x0a, 0x6d, 0xca, 0x10, 0xfa, 0x29, + 0xce, 0x1b, 0x92, 0x73, 0x61, 0xab, 0xdd, 0x77, 0x6b, 0x79, 0x5d, 0x93, + 0xa5, 0xe8, 0xa6, 0xb2, 0x74, 0xc8, 0xf0, 0xf5, 0x35, 0x6c, 0x0b, 0xec, + 0xcf, 0xd4, 0xbc, 0x9d, 0x0a, 0x64, 0xa9, 0x38, 0xf3, 0x4e, 0x64, 0x29, + 0x68, 0x1f, 0x83, 0xec, 0x06, 0x63, 0x6c, 0xa4, 0x39, 0xa8, 0x03, 0x1a, + 0x4b, 0x59, 0x8d, 0x51, 0x38, 0x8e, 0x6f, 0x1b, 0xca, 0xeb, 0x6c, 0xc3, + 0x11, 0xb4, 0x95, 0x50, 0xae, 0xb7, 0x45, 0xf6, 0xcf, 0x07, 0x7d, 0x1c, + 0x51, 0x32, 0x3b, 0x39, 0x63, 0x9b, 0xc3, 0x61, 0xc9, 0x0c, 0xcf, 0x0e, + 0xca, 0x50, 0xad, 0x13, 0x6b, 0xfa, 0xb6, 0x07, 0xdb, 0x79, 0x7d, 0x54, + 0x1c, 0xe8, 0x45, 0xcc, 0x79, 0x00, 0x3c, 0xae, 0x45, 0xc5, 0x48, 0xbb, + 0x48, 0xeb, 0x31, 0x56, 0x24, 0x32, 0xbc, 0x2e, 0xdf, 0x80, 0x3a, 0xe8, + 0x7b, 0x60, 0x63, 0x3d, 0xc8, 0x27, 0x78, 0x9b, 0x75, 0x7f, 0xe1, 0xc1, + 0x0e, 0x6b, 0x9b, 0xc5, 0x52, 0xea, 0x89, 0x40, 0x47, 0x7c, 0x14, 0xfb, + 0x5b, 0xed, 0x85, 0x82, 0x91, 0x3e, 0x80, 0x3e, 0x44, 0xc9, 0x69, 0xb1, + 0xf6, 0x4c, 0xb0, 0xef, 0x55, 0xf9, 0xae, 0x01, 0xca, 0x5e, 0x19, 0x98, + 0x80, 0x73, 0x5a, 0x52, 0x7b, 0x3d, 0x67, 0xc6, 0x65, 0xba, 0xc4, 0xf9, + 0x2c, 0x49, 0xb2, 0xfa, 0xa7, 0x92, 0x3b, 0x2d, 0xf2, 0xad, 0x19, 0xd6, + 0xfb, 0xba, 0xae, 0xf7, 0x3c, 0xea, 0x25, 0xad, 0xa1, 0x90, 0x0d, 0x3b, + 0x60, 0x63, 0x9b, 0xf4, 0x59, 0x48, 0xcd, 0x11, 0xfc, 0x86, 0x68, 0x64, + 0x50, 0xcf, 0xc7, 0x40, 0xcf, 0x83, 0x1f, 0x22, 0x77, 0x95, 0x1a, 0xa1, + 0x4f, 0xfe, 0x27, 0x68, 0x8d, 0xcb, 0xe3, 0x98, 0xc7, 0x4b, 0x33, 0xc4, + 0x59, 0x5f, 0x97, 0xe5, 0x19, 0xe2, 0xae, 0xe7, 0x65, 0x7a, 0x26, 0xe9, + 0x7e, 0x0b, 0x7c, 0x3e, 0x25, 0x9c, 0x4b, 0x9f, 0x8b, 0x14, 0x18, 0xd0, + 0xb6, 0x1e, 0x83, 0x3e, 0xeb, 0xdd, 0xe9, 0xf7, 0xd7, 0xad, 0xfb, 0x73, + 0xaa, 0xb6, 0x5c, 0x34, 0xa9, 0x9f, 0x2e, 0xdf, 0xe3, 0x59, 0xbd, 0xc7, + 0xc7, 0xdc, 0x4e, 0x31, 0xb0, 0xaf, 0x33, 0xe3, 0x05, 0x58, 0x3f, 0xee, + 0xeb, 0xff, 0x6b, 0xac, 0xe1, 0x9f, 0x04, 0xb0, 0xaa, 0xad, 0xec, 0xdd, + 0x3f, 0x6e, 0x8f, 0xd7, 0xef, 0x6d, 0x8e, 0xdf, 0x8a, 0x36, 0x11, 0xa4, + 0x57, 0xde, 0xd7, 0xe8, 0xa3, 0xae, 0xed, 0x20, 0xf7, 0x05, 0xda, 0xfc, + 0x09, 0x78, 0x41, 0xfe, 0xbf, 0x93, 0xfd, 0xdc, 0x17, 0x7e, 0x47, 0xfb, + 0x79, 0xfc, 0x4a, 0xfb, 0xb9, 0x7e, 0x2f, 0x9f, 0x25, 0x2f, 0x30, 0xb6, + 0xcc, 0xfa, 0xb2, 0xd5, 0x0d, 0x5e, 0x5b, 0x90, 0x53, 0xd0, 0x50, 0xfa, + 0x07, 0x2f, 0x13, 0xf1, 0xf1, 0x9c, 0x2f, 0x4f, 0xac, 0x17, 0xd4, 0xf1, + 0x75, 0xef, 0x50, 0xed, 0xa2, 0xd2, 0xb3, 0xe7, 0x94, 0x9e, 0xb5, 0x8f, + 0x14, 0x84, 0xf2, 0x76, 0x43, 0x98, 0x7c, 0x7f, 0xc6, 0xfd, 0x2c, 0x68, + 0xb4, 0x2d, 0xcb, 0xe8, 0x2e, 0x18, 0xc6, 0x67, 0xe5, 0xc0, 0xe2, 0x43, + 0x72, 0xa0, 0xc4, 0x3e, 0xd2, 0x78, 0xef, 0xa0, 0xac, 0x09, 0xba, 0x96, + 0x3a, 0xfd, 0xed, 0x90, 0x3f, 0x96, 0x01, 0xfb, 0xb5, 0x12, 0xba, 0xab, + 0x76, 0x21, 0x94, 0x5d, 0xe4, 0xde, 0x45, 0x79, 0xad, 0x5e, 0xe7, 0x07, + 0xfa, 0xbe, 0x5e, 0xb7, 0x17, 0x42, 0x63, 0xa5, 0x69, 0xe2, 0x40, 0x23, + 0xeb, 0x46, 0xb5, 0xee, 0xf8, 0x9a, 0x29, 0xad, 0xb0, 0x2d, 0xc6, 0x3c, + 0x78, 0x45, 0x9c, 0x4a, 0xde, 0xa5, 0x24, 0x13, 0x21, 0x9e, 0xe4, 0xb3, + 0x78, 0xe1, 0x34, 0xf7, 0x9e, 0x44, 0xc2, 0xe9, 0x2e, 0xf0, 0x8e, 0x75, + 0x6e, 0x05, 0xad, 0xb0, 0x7b, 0xee, 0xfb, 0x84, 0x72, 0xf9, 0x42, 0xe9, + 0x36, 0xe4, 0x23, 0x9a, 0xbf, 0x51, 0xd4, 0x61, 0x7f, 0x3f, 0x6d, 0x90, + 0xd6, 0xe3, 0xd0, 0x15, 0x41, 0xbf, 0xac, 0x93, 0xd0, 0x75, 0x5a, 0x74, + 0x9d, 0x5b, 0xf0, 0x7e, 0x0e, 0xf5, 0x6c, 0x57, 0x84, 0x7c, 0x60, 0x59, + 0x3b, 0xe6, 0x85, 0xba, 0x8b, 0xe9, 0xf0, 0x7a, 0xba, 0x6e, 0xaa, 0xab, + 0xcb, 0xfc, 0x66, 0x58, 0x97, 0xf2, 0x24, 0x5a, 0x97, 0xb1, 0x6c, 0x10, + 0xcf, 0x5d, 0x32, 0xb1, 0x98, 0x81, 0x4e, 0xba, 0x5d, 0xf5, 0x13, 0x75, + 0xd6, 0xd9, 0x3a, 0xd0, 0x64, 0x69, 0x9a, 0xb6, 0x04, 0xfa, 0x18, 0x65, + 0xae, 0x2e, 0x6b, 0xa8, 0x2b, 0x0b, 0xe4, 0xe7, 0x5f, 0x83, 0x76, 0x8e, + 0x3d, 0xa2, 0x71, 0x98, 0xe7, 0xe5, 0x28, 0x77, 0xfd, 0xff, 0x52, 0xf3, + 0xa2, 0x60, 0x86, 0xd5, 0x5e, 0xa9, 0xfe, 0xf6, 0xda, 0x5e, 0x01, 0x6e, + 0x57, 0xbd, 0x70, 0x8e, 0xa4, 0xa5, 0x05, 0x6b, 0x3b, 0x04, 0x5a, 0xb1, + 0x86, 0x1d, 0x21, 0xcc, 0xb7, 0x45, 0xf2, 0xb5, 0xb4, 0x7e, 0xc7, 0xf2, + 0x88, 0x8c, 0xc5, 0x83, 0xf9, 0x7d, 0xc0, 0xf4, 0xb1, 0x37, 0xea, 0x94, + 0xb6, 0x44, 0xfc, 0xbd, 0x68, 0x4a, 0xfe, 0xe4, 0x10, 0x64, 0x9e, 0xd8, + 0xb0, 0x01, 0x32, 0x1f, 0x57, 0x36, 0xc7, 0x70, 0x58, 0x1f, 0xef, 0x4e, + 0xff, 0xbb, 0xb0, 0xdf, 0x86, 0xf5, 0x82, 0x36, 0xc1, 0xd8, 0xed, 0xab, + 0x6d, 0xc7, 0x5c, 0x43, 0xc2, 0x6a, 0x7c, 0x94, 0x9d, 0x5e, 0x3f, 0xbe, + 0xd1, 0x11, 0x8c, 0xff, 0xa7, 0xba, 0xaf, 0xf6, 0xba, 0xbe, 0xe2, 0x57, + 0x18, 0x1f, 0xef, 0x4e, 0xff, 0xee, 0x76, 0xbf, 0x4d, 0xbc, 0xae, 0x4d, + 0xc7, 0x86, 0x36, 0xac, 0x1f, 0x8c, 0x81, 0x77, 0xa7, 0xef, 0x6b, 0xf1, + 0xdb, 0xb0, 0x5e, 0x03, 0x6c, 0x2c, 0xdf, 0x71, 0x0f, 0x1e, 0xa8, 0xdb, + 0x83, 0x07, 0xb0, 0x07, 0x03, 0xd9, 0xde, 0x88, 0xd7, 0x03, 0xbf, 0x8b, + 0xfe, 0x16, 0x31, 0xde, 0x9a, 0x7f, 0x15, 0x59, 0x68, 0x01, 0x7e, 0x6a, + 0xa5, 0x4f, 0xa5, 0xf1, 0x39, 0x7d, 0x2c, 0xe2, 0x71, 0x71, 0x22, 0xd2, + 0x0d, 0x5d, 0xd9, 0x9d, 0xd8, 0xcf, 0x8d, 0x5f, 0x8d, 0x2b, 0xdc, 0x9e, + 0xd1, 0x63, 0xd0, 0xbf, 0x22, 0xdf, 0x99, 0xcf, 0xad, 0xfa, 0x5b, 0x9d, + 0xf0, 0xc7, 0x88, 0xbb, 0x89, 0xdb, 0x02, 0xfa, 0x03, 0x7a, 0x0e, 0x1a, + 0x6b, 0x7b, 0x33, 0x63, 0x0c, 0xd5, 0x86, 0x0c, 0x7f, 0x6f, 0xf2, 0xfd, + 0x41, 0x6d, 0x5b, 0x37, 0xd2, 0xfb, 0x9e, 0x0d, 0xf4, 0x12, 0xdf, 0x59, + 0x32, 0x05, 0x19, 0x89, 0x2c, 0x50, 0xd7, 0x2f, 0x8c, 0x2e, 0xcf, 0x13, + 0xc7, 0xf4, 0x83, 0x2f, 0xa4, 0x97, 0xfc, 0xa3, 0x4e, 0x69, 0x85, 0x9e, + 0xea, 0x4e, 0x55, 0x50, 0x9f, 0x7e, 0xfe, 0x84, 0xf2, 0x0f, 0x5b, 0x90, + 0xc2, 0x89, 0x03, 0xad, 0x13, 0xa0, 0x75, 0x42, 0xfb, 0x86, 0xfb, 0x61, + 0x47, 0x22, 0xc7, 0x02, 0x5a, 0x6f, 0x89, 0x04, 0x6b, 0xb3, 0x9e, 0xf6, + 0x7a, 0xfb, 0xe7, 0xe3, 0xc0, 0xbb, 0x7a, 0xd5, 0x9e, 0x2c, 0x10, 0x3b, + 0x4e, 0x9c, 0x0e, 0xf6, 0xa3, 0xf8, 0x7b, 0xa9, 0x35, 0xc0, 0x01, 0x9c, + 0x0f, 0x71, 0x08, 0x75, 0x4f, 0x30, 0x87, 0x16, 0xe9, 0x5a, 0xe0, 0x1c, + 0x56, 0xe9, 0x8f, 0x33, 0xca, 0x72, 0x00, 0xfa, 0x3b, 0xaf, 0x68, 0xdd, + 0x2d, 0x93, 0xa5, 0xf7, 0x69, 0xfa, 0x5b, 0x40, 0xff, 0x18, 0x64, 0x7b, + 0x4d, 0x77, 0xe5, 0xab, 0xe3, 0xc8, 0xfb, 0x98, 0x90, 0x3c, 0xce, 0x57, + 0xa9, 0xc7, 0xf4, 0x7c, 0x9a, 0x39, 0x9f, 0x8d, 0x3a, 0x6e, 0x33, 0xbe, + 0xbe, 0x77, 0x03, 0x5f, 0x45, 0xf3, 0x35, 0x26, 0x0d, 0x0b, 0xca, 0xbf, + 0x46, 0xbf, 0xe4, 0x35, 0xed, 0xe8, 0xc2, 0xe8, 0xf4, 0xbc, 0xf4, 0x33, + 0x08, 0x95, 0x07, 0xdf, 0x50, 0x36, 0xd0, 0x20, 0xdd, 0xee, 0x05, 0xcc, + 0x3b, 0x8f, 0xf5, 0x36, 0x8e, 0xf9, 0xf2, 0x4d, 0xfe, 0xe6, 0xab, 0xcd, + 0xf0, 0xe9, 0x39, 0x36, 0x79, 0x46, 0xfa, 0x4d, 0x45, 0xcf, 0x2a, 0xbf, + 0x41, 0xdf, 0x7d, 0xd5, 0x8d, 0xbc, 0xad, 0xd7, 0x33, 0x41, 0xec, 0xe0, + 0x35, 0xd3, 0xdf, 0x17, 0x9b, 0xc5, 0x0e, 0x5a, 0xa0, 0xa3, 0x23, 0x8c, + 0x13, 0x80, 0xf7, 0x8c, 0xf3, 0x5c, 0x8a, 0xd0, 0x17, 0x78, 0xa1, 0x04, + 0x3d, 0x73, 0x9c, 0xd8, 0xa5, 0x55, 0xef, 0x8f, 0x1b, 0xb4, 0x0d, 0x8b, + 0x2a, 0xdb, 0x21, 0x86, 0x49, 0x7c, 0x84, 0x32, 0xe4, 0x17, 0x99, 0x0f, + 0xe8, 0xb8, 0x7b, 0x4f, 0xd4, 0x79, 0x21, 0x12, 0xe8, 0x84, 0x35, 0xba, + 0xea, 0x63, 0x03, 0x1e, 0x30, 0xe5, 0xfb, 0x20, 0xb7, 0xb7, 0xc3, 0xff, + 0xb7, 0x24, 0x9f, 0xe2, 0x3e, 0x1a, 0x54, 0x3e, 0x92, 0xe1, 0xec, 0x47, + 0x59, 0x13, 0xca, 0x60, 0x4c, 0x4d, 0xcc, 0xdf, 0xf9, 0x3d, 0x99, 0x80, + 0x8c, 0xe7, 0x53, 0x7d, 0xa0, 0x83, 0xf8, 0x0e, 0x58, 0xcb, 0x49, 0x31, + 0x7e, 0x80, 0xbf, 0x7b, 0xa3, 0xfe, 0xbc, 0xf6, 0x20, 0xdf, 0x8c, 0x3a, + 0x5d, 0xba, 0xce, 0x16, 0x61, 0x1c, 0x2a, 0x6f, 0xb6, 0x22, 0xed, 0xd9, + 0x50, 0xf7, 0x43, 0xc8, 0xdf, 0xa2, 0xfb, 0x2f, 0xe0, 0xfd, 0x4d, 0xf8, + 0x0d, 0xa1, 0xec, 0x66, 0x94, 0xb9, 0x28, 0xbb, 0x11, 0xf9, 0x0f, 0xe9, + 0xb8, 0x44, 0xd0, 0xa6, 0x15, 0xf9, 0x47, 0xf1, 0x1e, 0xba, 0xc2, 0x7c, + 0x05, 0xef, 0x6f, 0xc1, 0xef, 0xfa, 0x0d, 0x75, 0xda, 0x37, 0xe4, 0x4f, + 0xae, 0xf2, 0xe0, 0x85, 0xd2, 0x55, 0xfa, 0x99, 0xf2, 0xcc, 0xfc, 0x2b, + 0x3a, 0x7f, 0xfb, 0x86, 0xf2, 0xfb, 0x83, 0x7c, 0xdd, 0x1a, 0xc2, 0x0e, + 0x9a, 0x01, 0xd6, 0xbd, 0xda, 0xf4, 0xd7, 0xe0, 0x3d, 0x7e, 0xbc, 0xa0, + 0x14, 0xb4, 0x23, 0xf6, 0xbd, 0x3d, 0xbc, 0xbe, 0xaf, 0xff, 0xd6, 0xb0, + 0x96, 0x6f, 0x09, 0x0d, 0x9f, 0x64, 0xd9, 0x4f, 0x1b, 0xd6, 0xd7, 0x79, + 0x5f, 0xe3, 0x5a, 0x7e, 0x6b, 0x68, 0xf8, 0x38, 0xcb, 0xee, 0x6b, 0x5c, + 0x5f, 0x67, 0xb8, 0x71, 0x6d, 0x1e, 0x6b, 0xba, 0x30, 0x92, 0xae, 0x50, + 0x8e, 0xb1, 0x17, 0xaa, 0xa3, 0xd9, 0x19, 0xcf, 0x9b, 0x72, 0x57, 0x12, + 0x61, 0xa1, 0x0d, 0x22, 0x66, 0x66, 0xf9, 0x53, 0x28, 0x07, 0xa6, 0xaa, + 0x8d, 0x09, 0x75, 0xd2, 0xe6, 0xd8, 0xd8, 0xd2, 0xd8, 0x58, 0x65, 0x23, + 0x59, 0x85, 0x65, 0x9f, 0x18, 0x05, 0xf6, 0xd2, 0xcf, 0x4f, 0xe2, 0xd9, + 0xaa, 0xc7, 0xdf, 0xe8, 0xb7, 0x3c, 0x9a, 0x9d, 0xa7, 0xcd, 0x5b, 0x1a, + 0xdd, 0x37, 0xcf, 0x3d, 0x7f, 0x0a, 0x7b, 0x3e, 0x24, 0xd3, 0xca, 0xfe, + 0x91, 0x0e, 0xb6, 0x2b, 0x8f, 0x76, 0x2d, 0x31, 0xad, 0x8c, 0x3a, 0x4b, + 0x61, 0xd9, 0x1f, 0xf7, 0xdb, 0x32, 0x6f, 0x2d, 0x05, 0x7b, 0xa0, 0x59, + 0xa2, 0x69, 0xca, 0xa4, 0x9d, 0x82, 0x0f, 0x80, 0xf9, 0x1c, 0x19, 0x9d, + 0x76, 0x28, 0x9f, 0x9f, 0x82, 0xdd, 0x6f, 0x96, 0x06, 0xa5, 0x6f, 0x1e, + 0xd7, 0x63, 0x9d, 0xc2, 0x58, 0xdb, 0xd4, 0x7e, 0xca, 0x3a, 0x91, 0x04, + 0xc6, 0x39, 0x64, 0x38, 0x7d, 0x18, 0x8f, 0x1e, 0x7b, 0xa7, 0x4c, 0xd5, + 0xb8, 0x6f, 0xf6, 0x44, 0xd7, 0xfc, 0xf4, 0x39, 0xb4, 0x0b, 0xfc, 0x43, + 0x8e, 0x57, 0x01, 0x3e, 0x84, 0x2c, 0xa7, 0x6d, 0x33, 0x1b, 0x86, 0x9d, + 0x9f, 0x0f, 0xea, 0x90, 0xa6, 0x63, 0xa3, 0xc9, 0xa5, 0x24, 0xfa, 0xea, + 0xa4, 0x0e, 0x83, 0xee, 0x0a, 0xe3, 0xc7, 0xbe, 0xd9, 0x0e, 0xb6, 0x68, + 0x90, 0x76, 0x64, 0x0e, 0x76, 0xa4, 0x53, 0x0e, 0x97, 0x54, 0x1f, 0x16, + 0xfb, 0x28, 0xea, 0xb6, 0x5d, 0x4b, 0x0d, 0xf0, 0xb1, 0x92, 0xe6, 0x8b, + 0xb2, 0xd6, 0x76, 0x58, 0xfc, 0x76, 0x7e, 0xdf, 0x3f, 0xf1, 0x32, 0xf1, + 0xfa, 0xbd, 0xdf, 0x2c, 0x61, 0xd0, 0x91, 0x43, 0x1f, 0x1c, 0x7f, 0xad, + 0xef, 0xa0, 0xbf, 0xa4, 0x79, 0xfe, 0xb2, 0xbe, 0xb6, 0x69, 0xfc, 0x66, + 0x5b, 0xb9, 0x5f, 0x6b, 0x6c, 0xce, 0xf7, 0x09, 0xc8, 0x83, 0x44, 0x72, + 0xbd, 0xd0, 0x8b, 0xb5, 0x41, 0x2d, 0x23, 0x4f, 0xa2, 0xac, 0xde, 0xc7, + 0xf2, 0xe5, 0xab, 0x00, 0x6c, 0x59, 0xc4, 0x3e, 0x0f, 0xa7, 0x33, 0x6d, + 0x7e, 0xcc, 0xeb, 0x4a, 0x7e, 0x15, 0xe4, 0x06, 0x7d, 0x16, 0x57, 0xdb, + 0x72, 0x4e, 0x4f, 0x8e, 0xbe, 0x34, 0x93, 0xc0, 0x9c, 0x7c, 0xbb, 0xe0, + 0xf3, 0x9a, 0x36, 0x27, 0x24, 0xcb, 0x8e, 0x05, 0xff, 0x9d, 0x36, 0xde, + 0x92, 0x97, 0x9d, 0xc0, 0xfe, 0xd0, 0x16, 0xa1, 0x7e, 0x8d, 0xb4, 0x91, + 0xf6, 0x39, 0xcc, 0xcd, 0x93, 0x59, 0xd7, 0x97, 0xc1, 0x5e, 0xd8, 0x91, + 0xff, 0x18, 0xb1, 0x8f, 0xd0, 0xcf, 0xbb, 0x18, 0xa9, 0x9f, 0x4f, 0x80, + 0x15, 0x9e, 0xd0, 0x31, 0xe8, 0x39, 0x2d, 0x2f, 0x65, 0xc8, 0x4b, 0x9f, + 0x65, 0x4a, 0x0f, 0x68, 0x47, 0x9d, 0xfe, 0x6e, 0xf8, 0x5b, 0xf4, 0xe5, + 0x13, 0xa0, 0xc7, 0x84, 0xee, 0xd8, 0xa6, 0x7d, 0x87, 0xb7, 0xa2, 0xb4, + 0x6d, 0x6d, 0x2a, 0xbe, 0x3d, 0xa7, 0xe4, 0xd9, 0x97, 0xef, 0xb0, 0x7e, + 0x1f, 0xc8, 0x54, 0x98, 0x90, 0x46, 0xd6, 0xe2, 0xb8, 0xac, 0xbf, 0xa0, + 0xeb, 0xcf, 0xa3, 0x7e, 0x08, 0x73, 0xf2, 0xbc, 0x49, 0x45, 0xef, 0x02, + 0xf8, 0x1e, 0x96, 0xe2, 0xaa, 0xcc, 0x2f, 0x40, 0xe6, 0x29, 0xdf, 0x73, + 0xd8, 0xaf, 0x20, 0xfe, 0x6e, 0xca, 0x7d, 0x45, 0x86, 0x4e, 0xef, 0x6f, + 0x60, 0xcc, 0xd5, 0x32, 0xe8, 0x03, 0x53, 0x26, 0x3b, 0xe5, 0xb1, 0x52, + 0xd2, 0x9c, 0xaa, 0x5b, 0xcb, 0x5d, 0xeb, 0xd6, 0x92, 0x32, 0xa0, 0xea, + 0xa7, 0x58, 0xbf, 0x52, 0x27, 0x03, 0x8b, 0xf3, 0x57, 0x6a, 0x47, 0x19, + 0x60, 0xbb, 0xcd, 0xfc, 0x05, 0xc6, 0x28, 0x3d, 0x6f, 0xd9, 0x25, 0xfe, + 0x6f, 0x94, 0x82, 0x92, 0xb1, 0x90, 0x14, 0x5d, 0xee, 0xab, 0xac, 0x15, + 0x11, 0x1b, 0x58, 0xe9, 0xf7, 0x41, 0x67, 0x26, 0x15, 0x15, 0x3f, 0xa6, + 0x31, 0x81, 0x35, 0x58, 0x31, 0x3d, 0xef, 0x25, 0x47, 0xa4, 0x02, 0x1f, + 0x78, 0x19, 0x69, 0xb1, 0x8a, 0x3d, 0xdb, 0x1c, 0x81, 0x0e, 0x08, 0x64, + 0x3c, 0x26, 0x65, 0xd4, 0x59, 0xc4, 0xbb, 0xc7, 0xaa, 0x81, 0xc4, 0x78, + 0x9e, 0x01, 0x1e, 0xed, 0x73, 0x7e, 0xea, 0xe5, 0xe3, 0xf5, 0x75, 0x03, + 0x4c, 0x4c, 0x2c, 0x4b, 0x6c, 0x4a, 0x4c, 0xc9, 0x77, 0xc4, 0x89, 0x87, + 0x40, 0x0b, 0xf7, 0x6c, 0xab, 0xc4, 0xd2, 0x76, 0x62, 0x44, 0x02, 0xdb, + 0xff, 0x3a, 0x64, 0xa9, 0xe0, 0x35, 0x3a, 0x9d, 0xf2, 0x1c, 0xe4, 0xe6, + 0xd9, 0x55, 0x1c, 0x63, 0x41, 0x8e, 0x68, 0x47, 0x3d, 0x39, 0xe7, 0x3a, + 0xd6, 0xe7, 0x90, 0x7e, 0xc7, 0xfd, 0x00, 0xf9, 0xf6, 0x84, 0x48, 0x3f, + 0x7c, 0x32, 0xe8, 0xf5, 0xd9, 0x00, 0xdb, 0xb7, 0xd2, 0x37, 0xd4, 0xb2, + 0x74, 0x11, 0x7d, 0xda, 0xa6, 0x01, 0x50, 0x7b, 0x07, 0xea, 0xf9, 0x7b, + 0x23, 0x28, 0x3b, 0x84, 0xba, 0xa4, 0x81, 0x7e, 0xfb, 0x77, 0xb1, 0x67, + 0x3d, 0xef, 0x1e, 0xf7, 0xe5, 0x3a, 0x5d, 0xb3, 0x80, 0xf5, 0x57, 0x72, + 0x3e, 0xd0, 0x26, 0x8c, 0xf3, 0x4a, 0x7f, 0xbb, 0xf2, 0x2b, 0xf9, 0x0c, + 0x79, 0x1f, 0x20, 0x16, 0xb2, 0x14, 0xd6, 0x24, 0x6e, 0x78, 0x16, 0xbc, + 0xff, 0xa4, 0xc2, 0x34, 0xc4, 0x6f, 0xa0, 0xbf, 0x44, 0x4c, 0xe1, 0x63, + 0x69, 0x1f, 0xd7, 0x11, 0x5b, 0xa4, 0xb8, 0x36, 0x1a, 0x5f, 0xb0, 0x2d, + 0xeb, 0xb1, 0x6d, 0xfd, 0xfa, 0xb1, 0xce, 0xb6, 0x50, 0xee, 0x38, 0xe5, + 0x99, 0xf6, 0xb1, 0x4d, 0xf6, 0xa7, 0x1a, 0xc1, 0xf7, 0x76, 0x6d, 0xc7, + 0x3f, 0x08, 0xcc, 0x06, 0xec, 0x6d, 0xd2, 0x87, 0x0a, 0x78, 0x7d, 0x23, + 0xca, 0x7e, 0x0e, 0xfe, 0xb3, 0x0c, 0xfe, 0x95, 0xb2, 0x93, 0x0f, 0x61, + 0x2f, 0x97, 0xb7, 0xf9, 0x31, 0x34, 0xae, 0x43, 0x80, 0x13, 0x02, 0xdc, + 0x67, 0x6a, 0xbc, 0xcf, 0xb5, 0xf1, 0xe3, 0x6d, 0x86, 0xaa, 0x4b, 0x5f, + 0xab, 0xde, 0xc7, 0xe5, 0x1e, 0xf6, 0xbc, 0x73, 0x6e, 0x80, 0x23, 0xeb, + 0xfd, 0xc4, 0xc0, 0x07, 0x8c, 0x89, 0xd5, 0x4e, 0x4c, 0xf1, 0x47, 0x0d, + 0x6b, 0x58, 0xe6, 0x1f, 0xbc, 0xb0, 0x43, 0x9f, 0x93, 0x38, 0x26, 0xf0, + 0x07, 0x59, 0x97, 0xd8, 0xe6, 0x51, 0x8c, 0x11, 0x16, 0xab, 0x83, 0xf9, + 0x1f, 0xeb, 0x36, 0x7c, 0xf6, 0xa4, 0x67, 0x67, 0xbd, 0x3c, 0x0f, 0xfa, + 0xfe, 0x62, 0x73, 0x10, 0x03, 0xee, 0x54, 0xfa, 0x64, 0x4d, 0x2e, 0x02, + 0x9a, 0x82, 0x71, 0x7d, 0xff, 0xb4, 0x1d, 0xb4, 0xdd, 0x05, 0x9b, 0xb2, + 0xb3, 0xdd, 0xae, 0xf3, 0x45, 0xeb, 0x69, 0xaa, 0xc7, 0x57, 0x16, 0xc6, + 0x68, 0x94, 0x9d, 0x1d, 0xe4, 0x5d, 0xa7, 0xb2, 0x2d, 0x6b, 0xeb, 0x41, + 0xdb, 0xcf, 0xb1, 0x37, 0x96, 0xdf, 0x52, 0x47, 0xd7, 0x46, 0xcc, 0x47, + 0x1f, 0xd7, 0xc7, 0x7c, 0x99, 0xb8, 0x27, 0xbb, 0xdc, 0x00, 0xdf, 0xd5, + 0xd3, 0x41, 0x8c, 0x47, 0x9a, 0xa3, 0x75, 0x3e, 0xf2, 0xef, 0xea, 0x33, + 0xaa, 0x39, 0x3d, 0x97, 0xc0, 0x97, 0x4e, 0xa2, 0xfe, 0x7f, 0x00, 0xdd, + 0x7c, 0x26, 0xed, 0x01, 0x1e, 0x4c, 0xfa, 0x6d, 0x9b, 0x37, 0xc3, 0xfd, + 0xdc, 0x27, 0x01, 0x6f, 0xda, 0xf5, 0xba, 0xd4, 0xfb, 0xe3, 0xea, 0xe7, + 0xae, 0xd7, 0x1d, 0x37, 0xd6, 0xcd, 0xa9, 0x5f, 0x0a, 0x8b, 0x94, 0x85, + 0xf7, 0x23, 0x0d, 0xfc, 0xa1, 0x01, 0xd8, 0x8e, 0x0c, 0xfc, 0x1f, 0xfa, + 0x45, 0x97, 0xf9, 0x44, 0x3c, 0xc3, 0x1c, 0xcf, 0xc3, 0x47, 0x56, 0xb6, + 0xc3, 0xb7, 0x8b, 0xc8, 0x43, 0x87, 0xd4, 0xee, 0xa6, 0x5c, 0x8d, 0x4f, + 0x54, 0xdd, 0xf1, 0xc9, 0xea, 0xc0, 0x38, 0x7d, 0x07, 0x5f, 0xce, 0x50, + 0xbf, 0x2a, 0x13, 0x06, 0xda, 0x65, 0x55, 0x3b, 0x15, 0xcb, 0xd8, 0xa4, + 0x1f, 0xe1, 0x1e, 0x9c, 0xf0, 0xc7, 0x8a, 0x8d, 0xe7, 0xa0, 0x77, 0x16, + 0x67, 0x61, 0xd7, 0x1c, 0x3b, 0x43, 0x59, 0xdc, 0xe7, 0xda, 0x23, 0x4a, + 0xde, 0xe2, 0xf6, 0x18, 0xd7, 0xaf, 0x32, 0xfb, 0x5e, 0xe8, 0x4d, 0x4f, + 0xee, 0x84, 0xfe, 0x7b, 0x00, 0xf2, 0x29, 0x67, 0xa0, 0xfc, 0xce, 0x40, + 0x61, 0x9d, 0x89, 0x8b, 0x71, 0xa2, 0x53, 0xa2, 0x47, 0x13, 0x12, 0x39, + 0x4a, 0xff, 0x2b, 0x69, 0xde, 0x29, 0x02, 0x3b, 0xf8, 0xe2, 0xcd, 0x86, + 0xd8, 0x83, 0x19, 0x49, 0xc2, 0x87, 0xec, 0x33, 0x2b, 0x48, 0x8b, 0x92, + 0x4c, 0x9d, 0x46, 0x5f, 0xd1, 0x33, 0xa8, 0x8b, 0x76, 0x4d, 0xcb, 0x16, + 0x7e, 0x1d, 0xd2, 0xbc, 0xec, 0xef, 0x8f, 0xe6, 0xe5, 0xf5, 0xf1, 0x9b, + 0xa1, 0xd5, 0xf8, 0x0d, 0xdf, 0xbf, 0xad, 0xe3, 0x4e, 0x5f, 0xd2, 0xbe, + 0x0c, 0xe5, 0x82, 0xf6, 0x4c, 0xf9, 0x63, 0xd0, 0xdd, 0x5f, 0x82, 0xff, + 0xeb, 0x48, 0xae, 0x04, 0x9c, 0x9e, 0xf6, 0xe4, 0x69, 0xb7, 0xe0, 0x65, + 0x07, 0x3c, 0x79, 0xdd, 0x75, 0x0a, 0x79, 0xb1, 0xdf, 0xa6, 0x8e, 0xfb, + 0xb1, 0xfb, 0x21, 0xd9, 0xd3, 0x66, 0xef, 0xc9, 0x84, 0x0a, 0x5e, 0x8b, + 0xd3, 0x2c, 0x57, 0xa7, 0x0f, 0xc9, 0xbe, 0x1d, 0x2b, 0x66, 0x58, 0x32, + 0x57, 0x03, 0x0b, 0x26, 0xf2, 0x4a, 0x3f, 0xbd, 0xa1, 0x7c, 0xea, 0xfb, + 0xbb, 0x0f, 0xc9, 0xd6, 0x1d, 0xb6, 0x79, 0x29, 0x4c, 0x9c, 0x76, 0x08, + 0xf8, 0xdf, 0x4e, 0xe4, 0xc2, 0x8e, 0xb9, 0x5b, 0xec, 0x91, 0x4f, 0x0b, + 0xcf, 0x8c, 0x1d, 0xe9, 0x3a, 0xea, 0x24, 0x1e, 0x0c, 0xf5, 0x1c, 0x78, + 0x90, 0x3e, 0xdd, 0x19, 0xe6, 0x3d, 0x89, 0xed, 0x30, 0xf1, 0x1c, 0x97, + 0xae, 0x13, 0x96, 0x24, 0xc1, 0x97, 0x5e, 0xc5, 0x13, 0x9e, 0x5d, 0x25, + 0xa4, 0xe7, 0x28, 0x71, 0x93, 0xe2, 0x4d, 0x2f, 0x78, 0x93, 0x02, 0x6f, + 0xe0, 0x47, 0xf5, 0x99, 0x97, 0x90, 0x9e, 0x97, 0xe4, 0xe0, 0x9b, 0xe0, + 0x4d, 0x2f, 0x78, 0xd3, 0x73, 0xc6, 0x42, 0x7b, 0xf4, 0xb1, 0xdc, 0x85, + 0xb4, 0x59, 0x3e, 0x72, 0x55, 0x07, 0x9e, 0x1d, 0x49, 0x1e, 0x8d, 0x61, + 0x8c, 0x90, 0xec, 0xea, 0x2e, 0xc8, 0xf0, 0x0e, 0xf8, 0x63, 0xf1, 0x43, + 0x72, 0x01, 0xb6, 0xa7, 0x04, 0xbf, 0xe0, 0xe9, 0x41, 0x7b, 0x6c, 0x05, + 0xfa, 0xb3, 0x76, 0x97, 0x27, 0xaf, 0xec, 0xf8, 0x2b, 0x2f, 0x71, 0x95, + 0xbd, 0x47, 0x42, 0x03, 0x32, 0x5d, 0x52, 0x36, 0x21, 0x91, 0x0d, 0x2b, + 0x2c, 0x86, 0x39, 0x16, 0x60, 0x57, 0x78, 0x16, 0xee, 0x40, 0xbf, 0x7f, + 0x5a, 0x1e, 0x28, 0x4f, 0xe1, 0x07, 0x1f, 0x73, 0x86, 0x75, 0x0f, 0xc0, + 0x87, 0x7b, 0x48, 0xf6, 0xcf, 0x00, 0x2f, 0xa6, 0x41, 0xf7, 0x80, 0x03, + 0x1f, 0xee, 0x7c, 0xa3, 0xb4, 0xa2, 0x0c, 0xbc, 0x1d, 0xab, 0x6d, 0xf4, + 0xdd, 0x56, 0xb0, 0x0e, 0x83, 0xf2, 0x97, 0xb5, 0x01, 0xf9, 0x6a, 0xad, + 0x5f, 0xbe, 0x0c, 0x7b, 0xf2, 0x6c, 0xad, 0x13, 0x7b, 0x25, 0x81, 0x35, + 0x49, 0x63, 0x7d, 0x5c, 0xf9, 0x4a, 0x2d, 0x25, 0x5f, 0x02, 0xaf, 0x9e, + 0xc3, 0x6f, 0xb8, 0x94, 0x92, 0x5d, 0xa5, 0x7e, 0xbd, 0x46, 0x5c, 0x1f, + 0x07, 0xf4, 0x38, 0x98, 0xbb, 0xfd, 0x54, 0x01, 0xfb, 0x6f, 0xb1, 0xe6, + 0xbc, 0x55, 0x91, 0xc7, 0x1a, 0x19, 0x5f, 0x3e, 0xb5, 0x6a, 0x53, 0x0a, + 0x9e, 0xe9, 0xd8, 0x47, 0x26, 0xb0, 0x0e, 0x15, 0xec, 0xd3, 0x31, 0xc5, + 0xfb, 0x35, 0x7b, 0x53, 0xf1, 0xed, 0x4d, 0x30, 0xbf, 0xd9, 0xbc, 0x7c, + 0x47, 0xb2, 0x73, 0xd3, 0xb2, 0xef, 0xb8, 0x27, 0xbf, 0xe3, 0x7a, 0x90, + 0x63, 0xea, 0xdf, 0x01, 0xea, 0x75, 0x6b, 0x22, 0x6c, 0x28, 0xff, 0xc9, + 0xc7, 0x2a, 0xbd, 0xdb, 0xb1, 0x67, 0x53, 0x19, 0x63, 0x4a, 0x92, 0x73, + 0x53, 0xd2, 0x35, 0x07, 0x59, 0x70, 0xd9, 0xd7, 0x8a, 0x69, 0x5c, 0x26, + 0x0f, 0x1c, 0xc7, 0x1e, 0xcc, 0x89, 0x63, 0xbe, 0x25, 0x29, 0x8c, 0x7f, + 0x50, 0xba, 0xd1, 0xc6, 0x41, 0x9b, 0x4b, 0x6a, 0xec, 0x16, 0x8c, 0xdd, + 0x28, 0x87, 0xe3, 0x36, 0x64, 0x8d, 0x76, 0xfb, 0xff, 0x48, 0xb6, 0xc2, + 0xf4, 0x6f, 0x25, 0x7b, 0xea, 0x91, 0x98, 0x34, 0xf3, 0x19, 0xaa, 0x61, + 0x81, 0xe5, 0x5d, 0x48, 0x59, 0xee, 0xc0, 0x77, 0xfe, 0x89, 0x64, 0xcf, + 0x72, 0xec, 0xb7, 0x50, 0xfe, 0x8a, 0x64, 0x8f, 0xfd, 0x1c, 0xf9, 0x0b, + 0x48, 0xdf, 0x46, 0x3a, 0x26, 0x5d, 0xc7, 0x24, 0x94, 0x3d, 0xfb, 0x6d, + 0xe4, 0x23, 0x48, 0x0f, 0xa3, 0xde, 0x6d, 0xa0, 0xef, 0xaf, 0xd1, 0x5f, + 0x06, 0x7a, 0xee, 0xc3, 0x9a, 0x7e, 0x96, 0xb3, 0x8c, 0xef, 0x0e, 0x43, + 0xa7, 0xfd, 0x0f, 0x8f, 0xf1, 0x44, 0xf5, 0xbc, 0xc8, 0x3c, 0x75, 0x1b, + 0x9f, 0xa7, 0xc0, 0x93, 0x83, 0xc8, 0x7b, 0xf2, 0x90, 0x4b, 0x1b, 0x73, + 0x93, 0x8c, 0x9b, 0x05, 0xaf, 0x19, 0x58, 0xa2, 0x05, 0xfb, 0x60, 0x6a, + 0xe7, 0xe6, 0xfb, 0xe0, 0x48, 0xcf, 0x21, 0x69, 0xda, 0x11, 0xcc, 0x3f, + 0x98, 0xaf, 0x63, 0xfe, 0x48, 0xf1, 0xc1, 0x2e, 0x3c, 0x28, 0x9c, 0x87, + 0x93, 0x78, 0xdc, 0xe8, 0xd9, 0xf3, 0x00, 0xf6, 0x81, 0x71, 0x96, 0x79, + 0x7f, 0x1f, 0x18, 0x67, 0xa1, 0x1b, 0x16, 0xe0, 0x17, 0x2e, 0x74, 0x4a, + 0xe3, 0xb1, 0xb5, 0x7d, 0xd0, 0x70, 0xec, 0x57, 0xef, 0x83, 0xc6, 0xb3, + 0xa8, 0x77, 0x96, 0x3c, 0x43, 0x1f, 0xa7, 0xc8, 0xb3, 0x0e, 0xa4, 0x9f, + 0xc6, 0x5c, 0x49, 0x7b, 0x23, 0x68, 0xf7, 0xb1, 0xd0, 0xcd, 0x90, 0xf7, + 0xfb, 0x77, 0x1c, 0xd4, 0xe5, 0xff, 0xd9, 0x1b, 0x89, 0xdb, 0x65, 0x09, + 0x91, 0xa7, 0xa8, 0x5b, 0x21, 0x0f, 0x6f, 0x69, 0x92, 0xe6, 0x03, 0xd2, + 0x45, 0xfe, 0x55, 0x76, 0x23, 0x5f, 0xf0, 0xa2, 0x4e, 0x8b, 0xe6, 0x27, + 0xb0, 0xd1, 0x00, 0xcb, 0x5f, 0x83, 0xcc, 0x10, 0xa3, 0xbe, 0x21, 0xfb, + 0x66, 0x3c, 0x19, 0x77, 0x39, 0xff, 0xef, 0x63, 0xfe, 0x99, 0x1d, 0x71, + 0x59, 0xb1, 0xe2, 0xe0, 0xc9, 0x22, 0x74, 0xfb, 0x05, 0xf1, 0xf9, 0xc0, + 0x33, 0x89, 0x5d, 0xe2, 0x24, 0x86, 0xc5, 0x49, 0xbd, 0x09, 0x3e, 0x0c, + 0x43, 0xf6, 0x73, 0x35, 0xca, 0xce, 0xab, 0x32, 0x04, 0x99, 0xf8, 0x9e, + 0x6b, 0xa7, 0x80, 0x7f, 0xa0, 0x2f, 0x28, 0x17, 0x94, 0x89, 0x56, 0xa5, + 0x93, 0x16, 0x5c, 0xfb, 0x89, 0x8a, 0x5c, 0x27, 0x0b, 0xed, 0xa4, 0x1d, + 0xef, 0x8e, 0x29, 0x7b, 0x91, 0x9a, 0x30, 0xba, 0xa1, 0xa3, 0x53, 0x62, + 0xf6, 0x7c, 0xb1, 0x31, 0xb8, 0xbf, 0x92, 0x9f, 0x0b, 0xc9, 0x54, 0x0f, + 0xd7, 0x8a, 0xfd, 0x22, 0x5f, 0x29, 0x78, 0x11, 0xe7, 0x2d, 0xef, 0x64, + 0x87, 0x25, 0x9f, 0xec, 0x59, 0x95, 0xcb, 0xb2, 0x88, 0xbf, 0x2f, 0x86, + 0xd4, 0x7a, 0x04, 0x74, 0x07, 0x73, 0x09, 0xde, 0xf5, 0xd7, 0xbd, 0xe3, + 0x5c, 0x28, 0xeb, 0xab, 0x7b, 0xc7, 0xba, 0x9c, 0xd6, 0x9f, 0x41, 0x9e, + 0xec, 0x27, 0x8a, 0xf2, 0x3a, 0x64, 0x0f, 0x3c, 0x3c, 0xcb, 0x94, 0x3c, + 0x9c, 0x82, 0xdc, 0xbf, 0x26, 0xbb, 0xe6, 0xb8, 0x67, 0x5e, 0xc3, 0x5c, + 0x95, 0x2e, 0x81, 0x8e, 0x60, 0x7f, 0x9e, 0x4c, 0xbb, 0xdd, 0xa9, 0x53, + 0x72, 0x5d, 0x62, 0x12, 0x7e, 0xe6, 0x84, 0xe9, 0xc9, 0xb2, 0x5b, 0x90, + 0xe5, 0x41, 0xb4, 0xa9, 0x7c, 0x1a, 0xbf, 0x79, 0x3d, 0xb7, 0x47, 0xc0, + 0x77, 0xdb, 0x2a, 0x1b, 0x9f, 0x01, 0xdf, 0x1f, 0x92, 0xe4, 0xb1, 0x55, + 0x5d, 0x03, 0xb9, 0xf3, 0x75, 0x4d, 0xf2, 0xac, 0x29, 0x95, 0x92, 0x23, + 0x1f, 0xa3, 0x0e, 0x29, 0x71, 0x5e, 0xd0, 0x31, 0x3c, 0xdf, 0x2f, 0x41, + 0xcf, 0x94, 0xa0, 0x53, 0xa0, 0x43, 0xbe, 0x8c, 0xf2, 0x2f, 0xa1, 0xce, + 0x73, 0xf0, 0x99, 0x9e, 0x05, 0xde, 0x3b, 0x07, 0x1c, 0xf1, 0x4c, 0x29, + 0xa3, 0xfd, 0x57, 0x35, 0x5f, 0xd8, 0x2c, 0xe5, 0xef, 0x48, 0xa5, 0x4c, + 0x7e, 0xfc, 0x44, 0xad, 0x6d, 0xd6, 0xdd, 0x46, 0x6c, 0x05, 0xca, 0x44, + 0xca, 0xe5, 0x80, 0x27, 0xd4, 0x7d, 0x3c, 0x1b, 0x0a, 0x74, 0x65, 0xcb, + 0x06, 0x5d, 0x29, 0xf2, 0x62, 0xd5, 0xc7, 0x90, 0xc4, 0xc4, 0xc5, 0x19, + 0x6b, 0xf5, 0x0c, 0xb5, 0x08, 0xbb, 0x79, 0x1e, 0xbe, 0x45, 0x2c, 0xfd, + 0x2d, 0x89, 0x9d, 0xf0, 0xbc, 0x1f, 0xc0, 0x6e, 0x16, 0xb0, 0x26, 0x46, + 0x08, 0xe5, 0x4b, 0x7c, 0x47, 0xb9, 0xa7, 0x6c, 0x87, 0x78, 0x96, 0x22, + 0x2f, 0xa3, 0xac, 0xa2, 0x7c, 0xae, 0x6f, 0x83, 0x1e, 0x4d, 0x9f, 0x2a, + 0x63, 0xbd, 0x46, 0xc9, 0x8d, 0xa7, 0xe0, 0xd7, 0xf4, 0x99, 0x8d, 0x68, + 0x5f, 0x5e, 0x62, 0x1b, 0x7b, 0x90, 0x57, 0xb9, 0x5e, 0x5e, 0x62, 0x79, + 0xa7, 0x5c, 0x80, 0xff, 0x49, 0x1a, 0x2a, 0xf3, 0x69, 0xf1, 0xe3, 0xc5, + 0xd4, 0x57, 0xa4, 0x15, 0x79, 0xf0, 0x2b, 0x5b, 0xa2, 0x9d, 0x8d, 0x48, + 0x21, 0x41, 0x5e, 0x27, 0xe4, 0xfc, 0xcc, 0x1f, 0x37, 0x31, 0x1e, 0x9b, + 0x75, 0xf8, 0x1c, 0xc4, 0x37, 0xcc, 0x77, 0x10, 0xdf, 0x60, 0x4c, 0x23, + 0x02, 0x5b, 0xa6, 0xe2, 0x1c, 0x48, 0xad, 0x3a, 0x9f, 0x97, 0xef, 0x7d, + 0x6c, 0xb4, 0x86, 0x19, 0x89, 0x21, 0x39, 0x5f, 0xbb, 0xb0, 0x02, 0xfd, + 0xd1, 0x9e, 0x7e, 0x49, 0xee, 0x5e, 0xf0, 0xe7, 0x67, 0x9c, 0x12, 0xde, + 0xe3, 0x91, 0x4b, 0xf3, 0xb6, 0x7b, 0x51, 0x78, 0x06, 0xe2, 0x62, 0xbd, + 0xfe, 0xa0, 0x09, 0xfa, 0x6b, 0x30, 0x63, 0x7c, 0xbb, 0xc9, 0xc7, 0x67, + 0x11, 0x99, 0x9a, 0xe1, 0x99, 0x2b, 0x74, 0x1b, 0x70, 0xe3, 0xef, 0x45, + 0xf0, 0x5c, 0x65, 0x1e, 0x7e, 0xa8, 0xef, 0xc3, 0xe2, 0xd9, 0xef, 0x8f, + 0x3c, 0x37, 0x16, 0x38, 0xf7, 0x90, 0xdc, 0x0d, 0x74, 0x22, 0xe8, 0xbf, + 0x4b, 0x8f, 0xd5, 0x75, 0x2a, 0xc5, 0xf8, 0xb5, 0x24, 0xa1, 0x2f, 0xb2, + 0xf0, 0x1f, 0x73, 0xf1, 0x4e, 0x8d, 0xc7, 0xf9, 0x6e, 0x23, 0xde, 0x0c, + 0xfc, 0xba, 0x94, 0x7c, 0xbe, 0x14, 0x60, 0xbd, 0x14, 0x6c, 0xac, 0x44, + 0x46, 0x7a, 0x3d, 0xf9, 0x81, 0x4b, 0x7e, 0xf5, 0x23, 0xef, 0xca, 0x91, + 0xda, 0x2f, 0x3b, 0x5b, 0xad, 0xff, 0x6b, 0x01, 0x8d, 0xfc, 0x81, 0x3e, + 0xe0, 0x23, 0xd2, 0x6e, 0xc0, 0x9e, 0x17, 0x81, 0xbb, 0x8c, 0x33, 0x9d, + 0xea, 0x9d, 0x01, 0x6c, 0x50, 0x99, 0x81, 0x6e, 0x3c, 0xc3, 0xf3, 0x66, + 0xe8, 0xb6, 0x33, 0x51, 0x29, 0xce, 0x52, 0x2e, 0xa5, 0xdd, 0xc0, 0x7a, + 0xb1, 0x7e, 0x65, 0xa6, 0x13, 0x69, 0x0b, 0x52, 0x4b, 0xf5, 0x53, 0x99, + 0x71, 0x54, 0xfb, 0xca, 0x4c, 0x4a, 0xb5, 0xab, 0xcc, 0xf4, 0x23, 0x75, + 0xa5, 0xe1, 0x0c, 0x9c, 0xa5, 0x33, 0x3d, 0x32, 0x75, 0x12, 0xf6, 0x65, + 0xc0, 0x50, 0x77, 0x35, 0x26, 0x60, 0x7f, 0x22, 0xf0, 0xac, 0x2e, 0x9a, + 0x83, 0xc0, 0x58, 0x37, 0x01, 0x83, 0xdc, 0x24, 0xce, 0x09, 0xce, 0x9f, + 0xba, 0xf7, 0x3c, 0x63, 0x5e, 0x89, 0x4f, 0x48, 0x46, 0xf6, 0xcf, 0x36, + 0x62, 0xbf, 0x46, 0xcc, 0xa2, 0x74, 0x9b, 0xc3, 0xc8, 0xe7, 0xcb, 0xe4, + 0xdb, 0xbd, 0xca, 0x5f, 0xcb, 0xba, 0x37, 0x34, 0x4b, 0x73, 0x1a, 0x63, + 0xbc, 0x93, 0xf6, 0xbd, 0x90, 0x3f, 0x47, 0xf7, 0x91, 0x06, 0x3d, 0xf5, + 0xfc, 0xe0, 0x39, 0x73, 0xe6, 0x57, 0x9c, 0x33, 0x53, 0xae, 0xc9, 0xdf, + 0x7b, 0xe5, 0xbc, 0x93, 0x96, 0x97, 0x9d, 0x94, 0x5c, 0x70, 0x76, 0xca, + 0x37, 0x61, 0xa7, 0x5f, 0x72, 0xce, 0x34, 0x11, 0x0b, 0x54, 0xd4, 0xd9, + 0x5d, 0xb0, 0x56, 0x8e, 0x8e, 0x9d, 0xff, 0x50, 0x96, 0x67, 0x88, 0x9d, + 0xbd, 0xdb, 0xf6, 0xb9, 0x05, 0xda, 0x2d, 0xd0, 0x40, 0xac, 0x56, 0x80, + 0xfd, 0x3b, 0x24, 0xc3, 0x2e, 0xed, 0x9e, 0xb2, 0x51, 0x89, 0x61, 0x7f, + 0x3f, 0xbb, 0x79, 0xe8, 0xd5, 0xf3, 0xb3, 0xd8, 0x4f, 0x42, 0xf9, 0xc7, + 0x73, 0x99, 0xeb, 0xee, 0xc8, 0xe3, 0x25, 0xce, 0xb3, 0xb8, 0xbd, 0x59, + 0xc2, 0x32, 0xa2, 0xf0, 0x42, 0xab, 0xbc, 0xb8, 0xb4, 0x45, 0x0c, 0x58, + 0x28, 0xe3, 0xda, 0xa8, 0xba, 0xe5, 0x42, 0x9f, 0x5b, 0xda, 0x78, 0xb6, + 0xf6, 0x87, 0xe0, 0x0d, 0xfd, 0x7f, 0xcc, 0xad, 0x8d, 0x33, 0x09, 0xf2, + 0xfd, 0xd8, 0x5f, 0x7c, 0x0e, 0x49, 0xce, 0x89, 0xe3, 0x99, 0x29, 0xf7, + 0x1c, 0x63, 0x63, 0x61, 0xf1, 0x31, 0xf7, 0x21, 0xf5, 0xbe, 0xd1, 0xb9, + 0x15, 0xb8, 0x8e, 0xf2, 0x8a, 0x74, 0xd9, 0x1f, 0x37, 0x07, 0x1c, 0x97, + 0xef, 0xe7, 0x1d, 0x1b, 0x3b, 0x55, 0xc0, 0x5e, 0x98, 0x50, 0xf5, 0x07, + 0xe4, 0xa5, 0x99, 0x52, 0xb3, 0xbf, 0x3f, 0x06, 0xf5, 0x33, 0xdf, 0xd3, + 0xa7, 0x62, 0x8c, 0xe4, 0x99, 0xd1, 0x69, 0xe7, 0xa2, 0xde, 0x3f, 0x12, + 0xba, 0xb3, 0x17, 0x38, 0xf4, 0x68, 0x03, 0xe6, 0x62, 0x5b, 0x56, 0xc8, + 0xe8, 0x30, 0x80, 0xe3, 0x87, 0x95, 0xcd, 0xed, 0x55, 0x31, 0xe8, 0x53, + 0xa9, 0x56, 0xa9, 0x98, 0x8e, 0xba, 0x93, 0xb7, 0x62, 0xee, 0x20, 0xd6, + 0xc7, 0xaf, 0x09, 0x65, 0xdd, 0x48, 0x1b, 0x91, 0xbe, 0x5f, 0x8a, 0xc7, + 0xcf, 0xe8, 0xf1, 0xa2, 0x1b, 0xf2, 0x1f, 0xd1, 0xe9, 0x67, 0xb5, 0x3f, + 0xc5, 0x71, 0xa2, 0xe2, 0x7c, 0xa1, 0x45, 0xba, 0x8f, 0x9a, 0xc0, 0xb6, + 0x09, 0x60, 0xdd, 0x4e, 0x49, 0x1d, 0xb5, 0xe4, 0xda, 0xa3, 0x41, 0x9c, + 0xe9, 0x2b, 0xa3, 0x49, 0x15, 0xd7, 0xfc, 0xf2, 0xa8, 0x53, 0x56, 0xe7, + 0xed, 0xfa, 0xee, 0xe0, 0x8a, 0xbe, 0x53, 0xf8, 0xca, 0x68, 0xaf, 0x4a, + 0xbf, 0x3d, 0x9a, 0x52, 0xe9, 0xab, 0xa3, 0xd7, 0x56, 0x7d, 0xff, 0xa8, + 0xb8, 0x98, 0x92, 0xcf, 0x95, 0x88, 0x2f, 0x07, 0x80, 0x1d, 0x5d, 0xe8, + 0x99, 0x7e, 0xe8, 0x99, 0x14, 0xf4, 0xcc, 0x20, 0xf5, 0x0c, 0xf4, 0xf6, + 0xab, 0xd0, 0xdb, 0xae, 0x7c, 0x0f, 0xf2, 0xfa, 0x8c, 0xdb, 0x08, 0x5c, + 0xe8, 0x79, 0xfe, 0x5c, 0xed, 0x27, 0x56, 0xb0, 0xbe, 0x95, 0xd3, 0x12, + 0x6b, 0x83, 0x0e, 0xda, 0xb1, 0xd0, 0x20, 0x8b, 0x71, 0xcf, 0x9b, 0x73, + 0x1d, 0xb9, 0x84, 0xfa, 0x59, 0x87, 0xfb, 0xf8, 0x6f, 0x9a, 0xe9, 0x8f, + 0x5d, 0x9a, 0xd9, 0x09, 0x9d, 0x44, 0x79, 0x8f, 0x49, 0x65, 0x3c, 0x21, + 0x4b, 0xf0, 0xcf, 0xd6, 0xea, 0xa4, 0xf0, 0xcc, 0xfd, 0xff, 0x13, 0xd4, + 0x4d, 0xc1, 0x3e, 0x98, 0xb2, 0xdc, 0x6b, 0xc9, 0xa9, 0x5e, 0x7b, 0xd0, + 0x32, 0xa8, 0xbb, 0x2c, 0x29, 0xc3, 0xbf, 0xaf, 0x94, 0x58, 0x9f, 0xf5, + 0xb0, 0x3f, 0x4b, 0x7e, 0xbb, 0xe9, 0x52, 0xa0, 0x27, 0x06, 0x18, 0x7b, + 0x8c, 0xe4, 0x7a, 0x7d, 0x1b, 0x60, 0x18, 0x8d, 0x90, 0x03, 0x17, 0xfc, + 0x1f, 0x47, 0xf9, 0x00, 0xef, 0x9a, 0xa0, 0x8c, 0x58, 0x28, 0xb6, 0x85, + 0x18, 0x31, 0xe7, 0x8e, 0xa3, 0x8c, 0x6d, 0xec, 0x44, 0x12, 0xe5, 0x63, + 0x92, 0x4c, 0xe4, 0xd5, 0xbd, 0xb7, 0x0e, 0x94, 0xb1, 0x8f, 0xb0, 0x8e, + 0xc1, 0x74, 0x6c, 0xf1, 0xcf, 0x7d, 0x83, 0xf2, 0x3e, 0x15, 0x0f, 0xc8, + 0x98, 0x2e, 0xf6, 0x03, 0xcb, 0x92, 0x26, 0xdb, 0xe5, 0x5c, 0x57, 0xe9, + 0xc2, 0x7b, 0xaa, 0x3c, 0xb7, 0x8b, 0xc9, 0xdd, 0xd5, 0x16, 0xc9, 0x55, + 0x1b, 0xae, 0xa0, 0xff, 0x83, 0x3d, 0x79, 0x3e, 0x61, 0x0a, 0xef, 0x60, + 0xf8, 0xfb, 0x3c, 0xb2, 0x93, 0x7b, 0x02, 0x7c, 0x87, 0xfd, 0x7d, 0x0e, + 0xf3, 0x7d, 0x16, 0xf6, 0xf7, 0x1c, 0xec, 0xef, 0x33, 0xa5, 0x35, 0xfd, + 0xe1, 0xdb, 0x5d, 0xea, 0x80, 0xa7, 0xb0, 0x66, 0x63, 0xc0, 0xfd, 0xbb, + 0xe1, 0x0f, 0x8c, 0x00, 0xfb, 0x0f, 0x61, 0xfd, 0xd2, 0x58, 0xbb, 0x71, + 0xde, 0x55, 0xc2, 0x3a, 0x0e, 0xaa, 0xb3, 0xe5, 0x59, 0x75, 0xdf, 0xe3, + 0x87, 0xca, 0xf6, 0x3e, 0x56, 0x32, 0x60, 0x1f, 0x0a, 0xde, 0x76, 0xc7, + 0x06, 0xfe, 0x5b, 0xdd, 0xcf, 0x83, 0x2f, 0x42, 0xaf, 0xfc, 0x1d, 0xe8, + 0x7a, 0x76, 0x96, 0xf6, 0x1c, 0x75, 0x7c, 0xbc, 0xed, 0x32, 0xbe, 0x85, + 0xfd, 0x7c, 0xe4, 0xbc, 0xac, 0x00, 0x77, 0x64, 0x28, 0xc7, 0xf0, 0x1f, + 0xec, 0x67, 0xca, 0xd2, 0x43, 0x1d, 0x58, 0xe6, 0x5e, 0x19, 0x38, 0x96, + 0x00, 0xd6, 0x03, 0x92, 0x57, 0x67, 0xa9, 0x78, 0x3e, 0xbb, 0x55, 0x0c, + 0xe2, 0x3d, 0xf7, 0x2a, 0x94, 0x51, 0x6f, 0x04, 0x18, 0x69, 0x65, 0xb0, + 0x5d, 0x32, 0x3b, 0xda, 0x95, 0xee, 0xb0, 0xdd, 0x97, 0x31, 0xee, 0x2e, + 0x69, 0x04, 0x86, 0x2b, 0x60, 0x8c, 0x83, 0xf2, 0x37, 0x2e, 0xe3, 0x52, + 0xbe, 0xef, 0x07, 0x5a, 0x62, 0xe0, 0x59, 0xd3, 0x3e, 0xc7, 0x8c, 0xed, + 0xaa, 0xb1, 0xff, 0x98, 0xc2, 0x58, 0x39, 0x61, 0xff, 0xb0, 0x13, 0x18, + 0x33, 0x79, 0x8c, 0xb2, 0xdf, 0x87, 0x75, 0xfb, 0x2d, 0x60, 0x20, 0x72, + 0xf5, 0x5b, 0x5b, 0xfc, 0xfd, 0x42, 0xfa, 0x57, 0x88, 0x27, 0x18, 0xf7, + 0xf7, 0xfd, 0xf2, 0x55, 0xda, 0x06, 0x40, 0xef, 0x73, 0x5b, 0x82, 0xf3, + 0xe3, 0xae, 0x63, 0xbe, 0xbd, 0xee, 0x3a, 0x8b, 0x56, 0x73, 0xd2, 0xc1, + 0x93, 0x68, 0x43, 0xae, 0x95, 0xdb, 0x23, 0x7e, 0x3f, 0xc6, 0x82, 0x09, + 0x59, 0xa5, 0x1e, 0xe8, 0x80, 0x9c, 0x33, 0x4f, 0x9d, 0x42, 0x9d, 0x40, + 0x59, 0x70, 0xa4, 0x58, 0x83, 0x4e, 0x68, 0xed, 0x94, 0x32, 0x79, 0xb6, + 0x40, 0x3d, 0xf1, 0x43, 0x99, 0xde, 0xa0, 0x2b, 0x87, 0x24, 0xf0, 0x6b, + 0x5b, 0x24, 0x9a, 0x76, 0xcc, 0x7b, 0xd4, 0x1c, 0x7d, 0x7d, 0xb9, 0x9f, + 0xf8, 0x73, 0x36, 0x63, 0xb7, 0x8b, 0xc6, 0x9e, 0x0a, 0x3f, 0x7d, 0x1f, + 0x73, 0x65, 0x1f, 0x8a, 0x4f, 0x83, 0x43, 0xbe, 0x2f, 0xa0, 0xe2, 0x7c, + 0xc0, 0xc1, 0x89, 0xbf, 0x83, 0xae, 0xcd, 0x11, 0x97, 0x80, 0xcf, 0x5d, + 0x73, 0x94, 0xa3, 0xed, 0xd4, 0x65, 0xc0, 0x79, 0x29, 0xea, 0x6b, 0x59, + 0x3a, 0x06, 0xcc, 0x65, 0xdc, 0x2a, 0x79, 0xca, 0x2b, 0xef, 0x48, 0x2c, + 0x19, 0x32, 0x3d, 0xdf, 0x2a, 0xdd, 0x0b, 0x8c, 0xa9, 0x7e, 0xb3, 0x59, + 0x5a, 0x19, 0x57, 0xa5, 0x0d, 0x1a, 0x90, 0x1c, 0xca, 0xbb, 0x16, 0xc2, + 0x2a, 0x06, 0x56, 0x36, 0xc8, 0xa3, 0x7e, 0xe8, 0x03, 0x3b, 0xb5, 0x62, + 0x7c, 0xb4, 0xc9, 0xc7, 0x90, 0x90, 0xa5, 0x12, 0x64, 0xac, 0x04, 0x19, + 0x2b, 0x41, 0xc6, 0x4a, 0x90, 0x31, 0x60, 0xbf, 0x67, 0xb1, 0xff, 0xce, + 0x95, 0x06, 0xb5, 0x5d, 0xdf, 0xa3, 0xec, 0xfa, 0xe1, 0xd2, 0xab, 0x1e, + 0xd3, 0x2f, 0x29, 0xdf, 0xb4, 0x1f, 0x32, 0x48, 0x5f, 0x34, 0xf0, 0x51, + 0x5f, 0x95, 0xa7, 0x66, 0x5f, 0x93, 0x53, 0xb3, 0x6b, 0x38, 0x70, 0xaa, + 0xe4, 0xc9, 0xcb, 0x2e, 0xfc, 0xcf, 0x45, 0x62, 0xaa, 0x4c, 0x5b, 0xa3, + 0xc2, 0x56, 0x87, 0x24, 0xaf, 0x70, 0xb2, 0xb2, 0x23, 0xc0, 0x57, 0x0a, + 0x17, 0x72, 0x6f, 0x4a, 0xfb, 0x8e, 0xd7, 0xe5, 0x1c, 0xec, 0xf8, 0x52, + 0xed, 0x0d, 0x79, 0x4e, 0xe1, 0x71, 0xf2, 0xe1, 0x7d, 0xf2, 0xb7, 0xa6, + 0x7f, 0x86, 0x7f, 0x0a, 0x58, 0x63, 0xa9, 0x97, 0xba, 0x23, 0x02, 0x5b, + 0x60, 0x17, 0xba, 0xb0, 0xaf, 0x0f, 0x18, 0xef, 0x02, 0xa6, 0xe1, 0xfb, + 0xad, 0xf2, 0xe2, 0x6c, 0xa1, 0x4e, 0x26, 0xa8, 0x1f, 0xec, 0x23, 0x62, + 0xd0, 0x4e, 0xd1, 0x6e, 0x72, 0xbe, 0xb4, 0x53, 0x6d, 0x2d, 0xbc, 0x3f, + 0x56, 0x39, 0x7e, 0xc3, 0x16, 0xc6, 0x18, 0xe3, 0x0e, 0x79, 0xfa, 0xba, + 0x1c, 0xa8, 0xb2, 0xec, 0x35, 0xac, 0x0f, 0xd3, 0x37, 0xbd, 0xbb, 0xe3, + 0x1c, 0x8f, 0xfd, 0x02, 0x37, 0x75, 0x60, 0xae, 0xa5, 0xcf, 0x6a, 0xcc, + 0xdd, 0xaf, 0x70, 0xf4, 0xe5, 0x78, 0x99, 0x7c, 0x72, 0xc1, 0xa7, 0xd7, + 0x55, 0x0c, 0x70, 0x93, 0xd8, 0xf0, 0x13, 0xd8, 0x57, 0x85, 0x8b, 0xc2, + 0x38, 0x25, 0x63, 0xb8, 0x8c, 0x0f, 0xd7, 0x6b, 0x0c, 0x75, 0x57, 0x40, + 0xee, 0x82, 0x7e, 0xb9, 0x1b, 0xfa, 0xe5, 0x9e, 0xcb, 0xee, 0x5f, 0x07, + 0x71, 0xff, 0xee, 0x42, 0xd8, 0xe8, 0x94, 0xb1, 0x6a, 0x7d, 0x5b, 0xc6, + 0x6e, 0x37, 0x8b, 0xd5, 0x32, 0x8e, 0x9b, 0xda, 0x10, 0xff, 0xa3, 0x6c, + 0x78, 0xf2, 0x92, 0xcb, 0xb8, 0x5b, 0x70, 0x67, 0x7f, 0x33, 0xfc, 0x65, + 0xb5, 0x04, 0x71, 0xe6, 0x48, 0xfa, 0xa2, 0xf0, 0xee, 0x7e, 0x71, 0x86, + 0x78, 0x20, 0xae, 0xee, 0xd9, 0x19, 0x2a, 0xce, 0xe7, 0xb7, 0x2d, 0xce, + 0xa8, 0x73, 0xa5, 0x02, 0xe3, 0xd5, 0xe6, 0x4e, 0xdb, 0x1c, 0x0b, 0xfb, + 0xf7, 0x65, 0xb8, 0x97, 0x7d, 0x5d, 0x06, 0x59, 0xac, 0xad, 0xdd, 0xb1, + 0x1c, 0x52, 0xfa, 0xe2, 0x22, 0xf6, 0x00, 0xd7, 0x0b, 0xfe, 0x02, 0xf6, + 0xc9, 0x14, 0xf4, 0x53, 0x5e, 0xf5, 0x17, 0xa3, 0x5c, 0x64, 0xb2, 0x61, + 0x43, 0xa2, 0x27, 0xe8, 0x0b, 0xf9, 0xb1, 0x96, 0x5c, 0xd8, 0x56, 0xfa, + 0x1b, 0xb4, 0x03, 0x9f, 0x71, 0x7f, 0x5a, 0x13, 0x8d, 0xe9, 0x06, 0xd8, + 0x55, 0xac, 0x5f, 0x8d, 0x31, 0x01, 0xec, 0xdd, 0xe5, 0xef, 0xca, 0xfe, + 0xf9, 0xe1, 0x16, 0x5f, 0xfe, 0x19, 0x3b, 0xe6, 0xfc, 0x02, 0x1a, 0xd6, + 0xf7, 0x6d, 0x9c, 0x90, 0x58, 0x33, 0x6c, 0xda, 0x87, 0xe1, 0x67, 0xec, + 0x82, 0xac, 0xac, 0xc4, 0xd9, 0xaf, 0xbf, 0x67, 0xa6, 0x4b, 0xec, 0xfb, + 0xbb, 0x32, 0x3c, 0x7f, 0xb6, 0x85, 0xb6, 0x64, 0x19, 0x7a, 0xe0, 0xbc, + 0x49, 0x1b, 0x3a, 0x0e, 0x1b, 0xd7, 0x21, 0xdf, 0x9f, 0xa7, 0x7d, 0x4c, + 0x9a, 0xa7, 0xa4, 0x2f, 0x71, 0x0a, 0x34, 0x7d, 0xde, 0x8d, 0xd0, 0x47, + 0xf3, 0x86, 0x50, 0xf6, 0x4d, 0x49, 0x9a, 0x5d, 0x21, 0x3e, 0xf7, 0x99, + 0x8f, 0x03, 0xc3, 0x66, 0xcc, 0xa4, 0x79, 0x5d, 0x88, 0x72, 0x04, 0x9f, + 0x7b, 0x79, 0x8d, 0xce, 0x37, 0xe7, 0x95, 0x9f, 0xa4, 0xf4, 0xcc, 0xb2, + 0xcb, 0xf1, 0x40, 0xb7, 0xd2, 0x59, 0xd7, 0x41, 0x9f, 0xc4, 0xf4, 0x99, + 0x1b, 0xda, 0x10, 0xdb, 0xb8, 0x11, 0x9d, 0x7f, 0x44, 0xb2, 0x27, 0xe3, + 0xd0, 0x67, 0xec, 0x2b, 0xf0, 0x1d, 0x68, 0x23, 0x03, 0xbc, 0x4d, 0x7b, + 0x77, 0x2b, 0xec, 0xde, 0x35, 0x8a, 0x9e, 0x11, 0xb7, 0x5f, 0xa6, 0x8e, + 0x73, 0xec, 0x5e, 0xe8, 0xf2, 0x84, 0x92, 0xdb, 0x62, 0xe9, 0x7c, 0x22, + 0x06, 0x9d, 0x1c, 0xdb, 0x41, 0x7e, 0x7e, 0x50, 0xee, 0x70, 0xc6, 0xe5, + 0x4e, 0xc8, 0xce, 0x90, 0xe3, 0xca, 0x30, 0xd6, 0x62, 0x97, 0x03, 0xbb, + 0xa3, 0x30, 0x74, 0x23, 0xfc, 0x2e, 0x8e, 0xdd, 0xa1, 0xef, 0x5c, 0xf8, + 0xf8, 0xf1, 0xcf, 0x6a, 0x3e, 0x8f, 0xb2, 0xf3, 0x2f, 0x2b, 0xde, 0x8c, + 0xb8, 0x37, 0x69, 0x3b, 0xdb, 0x2a, 0x39, 0x55, 0xef, 0x26, 0x65, 0x8f, + 0x8b, 0x4b, 0xf7, 0x22, 0x85, 0x6d, 0x5e, 0x82, 0xbe, 0x01, 0xe6, 0x2e, + 0x56, 0x77, 0x22, 0x0f, 0x1b, 0xba, 0x94, 0x46, 0xfa, 0x41, 0xa4, 0xac, + 0xfb, 0xb9, 0x16, 0x3f, 0x96, 0x5b, 0x7f, 0x87, 0xcc, 0xbf, 0x7f, 0xfa, + 0x61, 0x85, 0x4b, 0x2f, 0xaa, 0xfb, 0x87, 0x06, 0xb0, 0x4e, 0x16, 0x7a, + 0xa5, 0x05, 0x18, 0x68, 0xe6, 0x84, 0x9d, 0x1a, 0x0e, 0xdd, 0x26, 0x1f, + 0x81, 0x2f, 0x5f, 0x71, 0xb9, 0x96, 0x3b, 0xe5, 0x13, 0xb7, 0x50, 0x46, + 0x6e, 0x93, 0x7d, 0xb7, 0x84, 0x64, 0x5f, 0xbf, 0x9d, 0x21, 0xdd, 0xd7, + 0xbe, 0x3f, 0xf0, 0xa7, 0xbb, 0x47, 0x92, 0xa1, 0x01, 0x79, 0x1c, 0x32, + 0x56, 0x80, 0x7c, 0x0d, 0xd7, 0xc8, 0x73, 0xea, 0x7b, 0xea, 0xf9, 0x14, + 0xb0, 0x72, 0x80, 0xfd, 0x1c, 0x99, 0xa9, 0x35, 0x88, 0x75, 0x15, 0xe3, + 0xc9, 0x96, 0x7f, 0xae, 0x71, 0x15, 0x65, 0x02, 0x3e, 0xc8, 0x55, 0xfe, + 0xfe, 0x54, 0xf7, 0xfe, 0xae, 0xf2, 0xed, 0x0a, 0xfc, 0x5f, 0x8f, 0x38, + 0xcf, 0xbf, 0x5f, 0x70, 0x51, 0xeb, 0xd2, 0xe4, 0xd6, 0x55, 0x7c, 0xd7, + 0x4a, 0xff, 0xe1, 0xeb, 0x2d, 0x6b, 0xdf, 0x2d, 0x6c, 0x94, 0xc5, 0x20, + 0xee, 0x56, 0xc6, 0x9c, 0x69, 0xd3, 0x6d, 0x93, 0xba, 0xb0, 0xcd, 0xd9, + 0x23, 0x7f, 0x09, 0xfb, 0xfe, 0xd5, 0x55, 0xfb, 0xbe, 0x17, 0xfc, 0xd8, + 0x88, 0x01, 0x1c, 0xf3, 0x2e, 0xcc, 0x65, 0x04, 0xeb, 0x79, 0x27, 0x7e, + 0x77, 0x94, 0xd6, 0xc5, 0xf1, 0x66, 0x0b, 0xc0, 0x93, 0x0d, 0x0e, 0xfb, + 0x5b, 0x17, 0xcf, 0x2b, 0xe4, 0x65, 0x35, 0x56, 0x38, 0x78, 0x49, 0x68, + 0xf7, 0xde, 0x92, 0x68, 0x8f, 0xf3, 0x56, 0x57, 0xc8, 0x79, 0xde, 0x08, + 0xf1, 0xec, 0xdb, 0x95, 0xd3, 0x35, 0xe2, 0xb0, 0x0b, 0x62, 0x9c, 0x25, + 0x06, 0x7b, 0x45, 0xc5, 0xa0, 0x2a, 0xa5, 0x6f, 0x23, 0x45, 0x7d, 0xe8, + 0xc7, 0xb0, 0x1f, 0xa7, 0x50, 0x58, 0x85, 0x7a, 0xf6, 0x4e, 0xac, 0xc3, + 0x14, 0x7e, 0x5d, 0x3b, 0xae, 0xc3, 0xfe, 0xa5, 0x9c, 0x32, 0xf6, 0xd5, + 0x63, 0xee, 0x08, 0xf1, 0xdd, 0x66, 0x71, 0xb0, 0xef, 0x48, 0x64, 0x0e, + 0xb6, 0xce, 0xa0, 0x7e, 0xe0, 0x3c, 0x68, 0x27, 0x4d, 0x59, 0x3c, 0xce, + 0xbd, 0xbe, 0x59, 0xfd, 0xa0, 0x6e, 0x30, 0x17, 0x65, 0x37, 0x32, 0x79, + 0xc6, 0x38, 0x4b, 0x5c, 0x03, 0x17, 0x6b, 0xe0, 0xc9, 0x09, 0xb7, 0x0d, + 0x7a, 0x3b, 0x2e, 0xe1, 0x13, 0x9e, 0x0c, 0x29, 0xec, 0xda, 0x07, 0xcc, + 0xb5, 0x55, 0xe3, 0x86, 0xb8, 0x44, 0x4e, 0x74, 0x4a, 0x23, 0x70, 0x75, + 0xc3, 0x51, 0xda, 0xc8, 0xa4, 0x35, 0x04, 0x21, 0x88, 0xa8, 0xbb, 0xac, + 0xf6, 0xe0, 0xf7, 0xa5, 0xcf, 0xfa, 0xbe, 0x10, 0x2f, 0xfd, 0x7b, 0xac, + 0x9f, 0xed, 0x5e, 0xd8, 0xa4, 0x7e, 0x71, 0xad, 0x3e, 0xe4, 0x88, 0xb1, + 0x35, 0xb6, 0x61, 0xac, 0x2d, 0x39, 0xf8, 0x3d, 0xc6, 0xd8, 0xe0, 0x6b, + 0x36, 0x9c, 0xf1, 0x69, 0x30, 0x96, 0xdb, 0xa5, 0x72, 0x92, 0x7b, 0x94, + 0x71, 0x16, 0xd3, 0xf7, 0x53, 0x4b, 0xf4, 0x57, 0xf9, 0xde, 0xd2, 0xef, + 0xbb, 0xf4, 0x7b, 0xfa, 0xa3, 0x05, 0xaf, 0x01, 0x3c, 0xdd, 0x05, 0xfd, + 0x79, 0xef, 0x4e, 0x47, 0xe1, 0x86, 0x7b, 0x57, 0xd7, 0x6c, 0xb7, 0xba, + 0x4f, 0x54, 0x29, 0x1d, 0x12, 0x67, 0xc7, 0x4a, 0x2a, 0x22, 0x63, 0x58, + 0x0b, 0xe6, 0x33, 0xa4, 0x27, 0x75, 0x58, 0x0e, 0xa8, 0xb5, 0xa9, 0x1c, + 0xb7, 0x8f, 0x58, 0xa1, 0x29, 0x31, 0x2a, 0x7c, 0xfe, 0x34, 0xd2, 0xc3, + 0xc0, 0x3b, 0x7e, 0xec, 0xd2, 0xa8, 0xac, 0xe7, 0x25, 0x30, 0x86, 0xb9, + 0x6b, 0x5d, 0x1c, 0x6b, 0x2d, 0xc6, 0xc5, 0xf7, 0x43, 0xea, 0x7d, 0x6a, + 0x5d, 0x9c, 0x2b, 0x67, 0x10, 0xcb, 0x04, 0xef, 0xb9, 0x16, 0x5c, 0x2f, + 0xd8, 0xe2, 0xe3, 0x41, 0xcc, 0xab, 0x55, 0xaf, 0x0b, 0xd7, 0x67, 0x46, + 0xce, 0x99, 0xf6, 0x08, 0xe5, 0xef, 0x86, 0x9d, 0x57, 0xcb, 0x44, 0x07, + 0xe3, 0x6d, 0xf5, 0x34, 0x6c, 0x8c, 0xa3, 0xd5, 0x8f, 0xbf, 0x31, 0xfe, + 0xc6, 0xb1, 0xfd, 0x18, 0x5b, 0x76, 0x5d, 0x8c, 0xad, 0x7e, 0x3c, 0x8e, + 0xb5, 0x15, 0xfe, 0x53, 0xc1, 0x8b, 0x3b, 0x5c, 0xa3, 0x6e, 0x6b, 0x9e, + 0xf9, 0x2f, 0x1a, 0x58, 0xc7, 0x38, 0xec, 0x08, 0xd7, 0x32, 0x38, 0x6f, + 0xe6, 0x9a, 0x26, 0xad, 0xc3, 0xfe, 0x7a, 0x0e, 0xfa, 0xeb, 0xee, 0xaf, + 0xff, 0x85, 0xd5, 0x75, 0xa4, 0x7d, 0xe0, 0x3a, 0x76, 0x88, 0x40, 0xcf, + 0x1a, 0x47, 0xb9, 0x86, 0x4c, 0xb9, 0x86, 0x7c, 0xc7, 0x35, 0xec, 0xd2, + 0xef, 0xb8, 0x7e, 0xc0, 0x69, 0x5f, 0xe0, 0x3d, 0xd5, 0xac, 0xfa, 0x06, + 0xab, 0xab, 0x27, 0xd8, 0x8b, 0x29, 0x79, 0x6e, 0xb1, 0x59, 0xcc, 0xb4, + 0x3f, 0xaf, 0xf1, 0x75, 0xf1, 0x76, 0x9e, 0x5f, 0xf5, 0x13, 0x7b, 0x06, + 0xf3, 0x4a, 0x70, 0x5e, 0x07, 0xe4, 0x75, 0xc9, 0xcf, 0x44, 0xe0, 0x03, + 0xa6, 0x80, 0x73, 0xfa, 0xa1, 0x6f, 0x19, 0x1f, 0x45, 0x59, 0x95, 0x78, + 0x85, 0xb6, 0x2e, 0x85, 0xbd, 0x42, 0x1d, 0x4c, 0x3c, 0xf2, 0x9a, 0xe4, + 0xca, 0x81, 0x8e, 0x41, 0xff, 0x46, 0xd0, 0x3f, 0xf9, 0x9c, 0xb9, 0x76, + 0xbb, 0xac, 0x58, 0xdb, 0xc5, 0xb6, 0x96, 0x64, 0x6d, 0x5d, 0xc7, 0x37, + 0xe7, 0xbb, 0x7b, 0x6f, 0x78, 0x4d, 0x36, 0xc6, 0x37, 0x59, 0xfb, 0x49, + 0x09, 0xde, 0x07, 0x6b, 0xbf, 0xe9, 0x3a, 0x14, 0x5e, 0x15, 0xae, 0x05, + 0x79, 0x40, 0x3c, 0x1c, 0x95, 0x7f, 0x13, 0xe7, 0x7e, 0x2c, 0xa8, 0x33, + 0xcd, 0xa4, 0xd1, 0xa3, 0x74, 0xc6, 0x90, 0xeb, 0xcb, 0x6b, 0x01, 0xe3, + 0xc4, 0xba, 0xff, 0xd0, 0x1b, 0x8a, 0xc3, 0xcf, 0xed, 0xa6, 0x7e, 0x09, + 0xf6, 0x74, 0xb3, 0xda, 0xd3, 0x9f, 0x77, 0x43, 0x52, 0x74, 0x42, 0x32, + 0xe5, 0x1c, 0x52, 0x18, 0xff, 0xa3, 0xe8, 0xeb, 0x13, 0xba, 0xaf, 0x29, + 0xe9, 0xd1, 0xfa, 0xe7, 0x20, 0xe4, 0xdc, 0x93, 0x7b, 0xdc, 0x9d, 0x72, + 0x43, 0x1b, 0xf7, 0x40, 0x30, 0xff, 0x43, 0xd2, 0xbd, 0x73, 0xc5, 0x82, + 0x67, 0x70, 0x6d, 0x74, 0x95, 0x07, 0xdc, 0x67, 0x81, 0x7c, 0xfb, 0x7c, + 0xf0, 0xe7, 0xbf, 0x6e, 0xae, 0x7a, 0x9e, 0x9c, 0x33, 0xeb, 0x71, 0xae, + 0x3e, 0x96, 0x5f, 0x9b, 0x6b, 0x50, 0xbf, 0x05, 0xb2, 0x64, 0x5b, 0x12, + 0xaa, 0xe7, 0xcd, 0xaa, 0x8e, 0x1a, 0x61, 0x8c, 0x64, 0xc5, 0xb4, 0x53, + 0x56, 0x28, 0x88, 0x45, 0xfb, 0x58, 0xb7, 0x0b, 0x38, 0xdc, 0xe9, 0xe9, + 0x49, 0xe5, 0x55, 0x8c, 0xd4, 0x50, 0xf3, 0x9a, 0x02, 0x26, 0x5b, 0x74, + 0x5f, 0xf5, 0x3e, 0x09, 0xcc, 0x3a, 0x21, 0x0f, 0x49, 0x78, 0x5d, 0x2c, + 0x17, 0xf9, 0xb3, 0x8c, 0xe7, 0xda, 0x56, 0x06, 0x6b, 0xfc, 0x3b, 0xf0, + 0xe1, 0x2b, 0xd0, 0xfb, 0x1f, 0xa3, 0x6d, 0x28, 0xc1, 0x5e, 0x00, 0x97, + 0x7c, 0xf5, 0x8a, 0x18, 0x7e, 0xa2, 0x2e, 0x96, 0xeb, 0xe3, 0xd3, 0x73, + 0x0a, 0x93, 0x12, 0xb7, 0x1f, 0x09, 0xdd, 0xd5, 0x1b, 0x86, 0x9f, 0x51, + 0xf0, 0x62, 0x0e, 0x71, 0xdc, 0x21, 0xb9, 0x03, 0xeb, 0x73, 0x7a, 0xb1, + 0x10, 0xda, 0x55, 0x0a, 0x64, 0x15, 0x7e, 0x65, 0xcd, 0x4e, 0x9d, 0x07, + 0x3f, 0x9e, 0xd2, 0x98, 0x8f, 0xe7, 0x35, 0x15, 0xed, 0xb3, 0x30, 0x36, + 0x54, 0xac, 0x1d, 0x92, 0x69, 0x97, 0xb1, 0x9d, 0x6e, 0x29, 0xc6, 0x33, + 0x57, 0x37, 0xae, 0xf2, 0xc8, 0x36, 0xe1, 0xf3, 0xa5, 0xa8, 0xbf, 0x2b, + 0xfa, 0xbc, 0xe3, 0x29, 0x25, 0x5f, 0x41, 0x5c, 0x98, 0xfe, 0x11, 0xcf, + 0xab, 0xba, 0xcd, 0x11, 0x3e, 0x97, 0x29, 0x03, 0xca, 0x67, 0x02, 0x2f, + 0xef, 0x90, 0xcc, 0x98, 0xa5, 0x70, 0xcb, 0x63, 0x25, 0xee, 0x17, 0xe2, + 0xff, 0xd7, 0x81, 0xfd, 0x23, 0x58, 0x33, 0xfa, 0x01, 0x1c, 0x9b, 0xfb, + 0x02, 0x65, 0x55, 0xf3, 0x97, 0xec, 0x8b, 0x0f, 0x6d, 0x23, 0xc6, 0x78, + 0xa1, 0xf4, 0x98, 0xe2, 0xdf, 0x8a, 0x04, 0xb1, 0x73, 0x85, 0x05, 0x0b, + 0xd9, 0x70, 0x48, 0x92, 0x73, 0xff, 0x16, 0x32, 0xd4, 0x0f, 0x1f, 0x89, + 0xf5, 0x44, 0x9d, 0x5f, 0x0d, 0x01, 0x73, 0x19, 0xce, 0xbb, 0xa4, 0x68, + 0x46, 0xa5, 0xa8, 0xee, 0xfe, 0xf1, 0x3c, 0x37, 0xac, 0x62, 0x3b, 0x45, + 0x93, 0x98, 0x3f, 0xbd, 0x2d, 0xb8, 0xfb, 0x57, 0x34, 0xd9, 0x8e, 0x79, + 0x96, 0x4f, 0x49, 0x74, 0xee, 0xa0, 0x34, 0xcc, 0x3d, 0x24, 0x8d, 0xc7, + 0x88, 0xf1, 0x18, 0xbb, 0x37, 0x6e, 0x6d, 0x14, 0x62, 0xee, 0x6f, 0x61, + 0xec, 0x43, 0xf2, 0x03, 0x37, 0xa0, 0xe9, 0xba, 0xad, 0xd2, 0xca, 0x3a, + 0x41, 0x9e, 0xcf, 0xc4, 0x09, 0x3c, 0x17, 0x77, 0xfc, 0x18, 0xa9, 0x3a, + 0x57, 0x41, 0x5a, 0xe1, 0xb9, 0x38, 0xdf, 0xbf, 0x66, 0xfa, 0xa9, 0x8f, + 0xf7, 0x7d, 0xdf, 0x83, 0x6d, 0x52, 0x75, 0xd8, 0x62, 0xfd, 0xf7, 0xa1, + 0x39, 0x94, 0xe7, 0xe7, 0x83, 0x3b, 0x3a, 0x06, 0x7c, 0x5f, 0xbb, 0x40, + 0x9f, 0xc1, 0xe4, 0xb7, 0x98, 0xf3, 0x05, 0xf0, 0xf9, 0x1a, 0x75, 0xbf, + 0x87, 0x77, 0x24, 0x50, 0xcf, 0xf2, 0x31, 0x1f, 0xf3, 0x09, 0xf0, 0xf9, + 0xfd, 0x9d, 0x46, 0xfa, 0x7f, 0x5f, 0x9d, 0x1d, 0x20, 0xa6, 0xd8, 0xc6, + 0xb3, 0x3f, 0x60, 0x55, 0xae, 0xed, 0x77, 0xb1, 0xb6, 0x8d, 0xea, 0xac, + 0xa5, 0x58, 0xa2, 0x0f, 0x95, 0xc7, 0x9a, 0xf1, 0x9e, 0x1c, 0x7d, 0xad, + 0xbc, 0x8e, 0x81, 0x92, 0x4e, 0xe2, 0xe8, 0x00, 0x93, 0xb3, 0xcf, 0xcd, + 0xee, 0x03, 0x07, 0x7e, 0x12, 0xd7, 0x38, 0xa1, 0x68, 0x1e, 0xde, 0xe0, + 0x23, 0x1c, 0xc6, 0xfe, 0x5b, 0x84, 0x0c, 0x4d, 0x42, 0xef, 0x0c, 0x85, + 0xb9, 0x27, 0x9a, 0xb5, 0xff, 0xe8, 0xd0, 0x57, 0x0e, 0x8d, 0xa1, 0x0f, + 0xe3, 0xd8, 0x1b, 0x32, 0x05, 0x9d, 0x3b, 0x5d, 0x4b, 0xaa, 0x6f, 0x78, + 0x32, 0x09, 0xde, 0xdb, 0x62, 0xf9, 0x7f, 0x81, 0x8c, 0xbc, 0x01, 0x0c, + 0xba, 0x05, 0xfc, 0x34, 0xf4, 0xbd, 0x90, 0x0f, 0xe8, 0xf8, 0x4f, 0x8c, + 0xf1, 0x6f, 0xe8, 0xaa, 0xa2, 0x8f, 0xef, 0xe2, 0xd3, 0x48, 0xbf, 0xd0, + 0xec, 0xcb, 0xc8, 0xcb, 0x7a, 0x8d, 0x9b, 0x50, 0xfe, 0xa8, 0x8a, 0xfb, + 0xf9, 0x73, 0xb2, 0xb5, 0x7f, 0x10, 0xc5, 0x3a, 0x73, 0x5e, 0x5f, 0x41, + 0x3d, 0xae, 0x6f, 0xaf, 0x3e, 0x0f, 0x6d, 0x56, 0x3a, 0x29, 0xe7, 0x5a, + 0xf0, 0x75, 0x89, 0x89, 0x80, 0xa9, 0x5d, 0xb6, 0x7b, 0x76, 0x1b, 0xcf, + 0x1b, 0x1b, 0x1c, 0x85, 0xe7, 0x3b, 0xc2, 0x12, 0x94, 0xdd, 0x8e, 0x32, + 0xc6, 0x25, 0xde, 0x85, 0xb5, 0x61, 0x59, 0x16, 0x79, 0x8e, 0x75, 0xb5, + 0x1e, 0x87, 0x63, 0x0c, 0xb7, 0xac, 0xa7, 0x89, 0x73, 0xe9, 0xd8, 0xf0, + 0xfd, 0x00, 0xcb, 0xde, 0xa5, 0xcb, 0x22, 0x7a, 0x7e, 0xb7, 0xeb, 0x6f, + 0x67, 0xed, 0x23, 0x99, 0x55, 0x3c, 0x4a, 0xfa, 0x62, 0xaa, 0x5d, 0xc6, + 0xf4, 0x65, 0xe7, 0x30, 0xd6, 0x23, 0x92, 0xf6, 0xda, 0xb9, 0x47, 0x86, + 0xc2, 0x81, 0x5f, 0x98, 0x50, 0xbe, 0x9e, 0x65, 0xf8, 0x77, 0x84, 0xce, + 0x5d, 0x76, 0x0f, 0xda, 0xbf, 0x53, 0x3e, 0xdc, 0xdb, 0x24, 0x8b, 0xb3, + 0x31, 0x7d, 0x3f, 0x31, 0xa1, 0xf6, 0x49, 0x7e, 0x9c, 0xf9, 0x1f, 0x6d, + 0xe3, 0x77, 0xcb, 0x86, 0xc3, 0xf2, 0x0e, 0xcd, 0xdf, 0x77, 0xa9, 0xfb, + 0x3c, 0xbc, 0x67, 0x52, 0x2c, 0xff, 0x44, 0xbd, 0x3f, 0x3d, 0xdf, 0xa0, + 0xea, 0x9f, 0x9e, 0xdf, 0x78, 0x27, 0x87, 0x65, 0xef, 0x66, 0x4c, 0x41, + 0x96, 0x66, 0x1a, 0x64, 0x79, 0xde, 0xa2, 0x8f, 0x94, 0x6e, 0x5c, 0xfb, + 0xf6, 0x45, 0x7f, 0xa7, 0xe6, 0xc9, 0x30, 0xd6, 0x6f, 0x71, 0x70, 0x5a, + 0x2a, 0x83, 0xf4, 0x01, 0xd4, 0xbd, 0x3b, 0xc8, 0x48, 0x03, 0xf0, 0x5f, + 0xc1, 0xab, 0x38, 0x8c, 0xbd, 0xb6, 0x6a, 0x1f, 0xea, 0xc7, 0xda, 0xcf, + 0x22, 0x8f, 0x0c, 0xc9, 0xf5, 0x4f, 0x29, 0xba, 0x2a, 0x8a, 0x57, 0xc1, + 0xb7, 0x45, 0xec, 0x9f, 0xdf, 0x17, 0x85, 0x35, 0x7e, 0x7c, 0x50, 0xf3, + 0xfc, 0xaf, 0x75, 0xfa, 0x88, 0xec, 0x3b, 0xfe, 0x19, 0xd0, 0xda, 0xe4, + 0xdf, 0x2d, 0x92, 0xfa, 0xef, 0x36, 0x22, 0xea, 0xdb, 0x95, 0x88, 0xf3, + 0x08, 0xca, 0x18, 0x7b, 0x7a, 0x44, 0xcd, 0x83, 0xf7, 0xd7, 0x0a, 0xf2, + 0xab, 0xee, 0x64, 0x04, 0xfe, 0x0f, 0xef, 0x08, 0x35, 0xeb, 0xfe, 0x76, + 0xe9, 0x75, 0x1c, 0x97, 0x7d, 0xd0, 0xef, 0x79, 0xe0, 0x40, 0xde, 0xab, + 0x9a, 0x08, 0xd7, 0x8f, 0x19, 0xc8, 0xb2, 0xef, 0x5b, 0x07, 0x67, 0xfd, + 0x61, 0xe5, 0x03, 0xac, 0xfa, 0xe9, 0xba, 0x7c, 0x5c, 0xf6, 0x97, 0x94, + 0xbf, 0xae, 0xce, 0xe8, 0xa6, 0xb1, 0x27, 0x87, 0x94, 0x0e, 0x8f, 0x85, + 0x86, 0xab, 0x69, 0xc9, 0x9f, 0xdc, 0x8d, 0x71, 0x18, 0xfb, 0xca, 0xe8, + 0xb3, 0xb0, 0xbd, 0xb2, 0xaf, 0xe6, 0x8f, 0x3d, 0x59, 0xe2, 0xfb, 0x24, + 0xec, 0x22, 0xdf, 0xe7, 0x12, 0x61, 0x15, 0xcd, 0xbf, 0x0e, 0x6d, 0x1b, + 0x34, 0x6f, 0x79, 0x9f, 0x9e, 0xed, 0xb9, 0xff, 0x3e, 0x6e, 0x4a, 0x73, + 0x0e, 0xef, 0xd9, 0x26, 0xe8, 0x6f, 0x12, 0x7a, 0x9a, 0xfe, 0xe8, 0xc3, + 0xb2, 0x52, 0x9e, 0x96, 0xf3, 0xe5, 0x40, 0xce, 0x78, 0xb7, 0x99, 0xb4, + 0xdf, 0xa9, 0xef, 0x36, 0x67, 0xb0, 0x0e, 0xeb, 0x79, 0x95, 0x5b, 0xf7, + 0xfd, 0xd1, 0x5f, 0x98, 0xfe, 0x37, 0x80, 0xb7, 0xa9, 0x7b, 0x4a, 0xeb, + 0xe5, 0x9d, 0xfd, 0x2c, 0x9b, 0x8c, 0xed, 0xfb, 0x77, 0xad, 0x3a, 0xea, + 0xde, 0xc7, 0xf5, 0xfd, 0xa6, 0xe7, 0xf4, 0x9d, 0x78, 0xf2, 0x73, 0x4c, + 0xd3, 0x7b, 0x1d, 0xf6, 0x1e, 0xfb, 0x7c, 0x54, 0xaf, 0x1b, 0xd2, 0x45, + 0x3e, 0x53, 0x0f, 0xad, 0xe8, 0xf3, 0x4e, 0x53, 0x8f, 0x51, 0x7f, 0xbf, + 0xac, 0xa1, 0x6e, 0x5c, 0xb6, 0xe7, 0xb7, 0x48, 0xc1, 0x5d, 0x6b, 0x96, + 0x1d, 0xd7, 0xf7, 0xd8, 0x82, 0xbb, 0xd5, 0x2c, 0x0b, 0xee, 0x5b, 0x91, + 0x5f, 0x8c, 0xe1, 0x21, 0xad, 0x8d, 0xe9, 0xe7, 0xb1, 0xba, 0x6f, 0x74, + 0x82, 0x3e, 0x23, 0xe8, 0xe3, 0xf6, 0xf0, 0xe5, 0x77, 0xb1, 0xf9, 0xdd, + 0x14, 0x65, 0xd1, 0xe0, 0x37, 0xdd, 0xf4, 0x7b, 0x80, 0x55, 0xb6, 0xca, + 0xa4, 0xa2, 0xa7, 0xa0, 0xee, 0x27, 0x64, 0xdd, 0x26, 0x19, 0x32, 0xfd, + 0xfc, 0xe4, 0xe2, 0x46, 0x39, 0x65, 0xf9, 0xf5, 0x31, 0x69, 0x2e, 0x60, + 0x1c, 0xbe, 0xdf, 0xec, 0x1b, 0x81, 0xa8, 0xfe, 0x4e, 0xc9, 0x45, 0x9b, + 0xcf, 0x53, 0xde, 0x0b, 0x85, 0xd5, 0xbb, 0x90, 0x05, 0x15, 0x97, 0x14, + 0x23, 0xb8, 0x93, 0xc8, 0x6f, 0xd6, 0x45, 0x9e, 0xa9, 0xf2, 0xbb, 0xad, + 0xdb, 0xd4, 0xbd, 0x11, 0xff, 0x2c, 0x8e, 0x74, 0x75, 0x2b, 0x9d, 0x5c, + 0xa9, 0x16, 0xc9, 0x53, 0x1d, 0x87, 0x8d, 0xea, 0x38, 0x2c, 0x79, 0x3c, + 0x02, 0x1e, 0xff, 0x3f, 0xbd, 0x2e, 0xc1, 0x77, 0x5f, 0x3c, 0xeb, 0xe1, + 0x79, 0xd0, 0xa3, 0x6a, 0x2e, 0xd4, 0xd1, 0x68, 0xfb, 0xde, 0xb0, 0xda, + 0xbb, 0xea, 0x9b, 0x78, 0xc8, 0x27, 0xbf, 0x71, 0x87, 0x7e, 0x2d, 0xf1, + 0x5b, 0xf6, 0x11, 0xf5, 0x3d, 0x47, 0xa5, 0xca, 0x75, 0xe5, 0x37, 0xec, + 0x63, 0x75, 0xf2, 0x18, 0xd6, 0x63, 0x6d, 0x69, 0x93, 0x66, 0x7f, 0xdd, + 0xf9, 0x2d, 0x48, 0xa5, 0x1a, 0xdc, 0xa3, 0xdc, 0xb2, 0xc2, 0x3d, 0x21, + 0xbe, 0x5f, 0xab, 0xbe, 0x67, 0xa9, 0xa8, 0xef, 0x43, 0x2c, 0x7e, 0x67, + 0x09, 0xdb, 0xb1, 0x07, 0xcf, 0x3c, 0x47, 0xdd, 0x8b, 0x14, 0x3a, 0xa7, + 0x3a, 0x81, 0xf4, 0x21, 0xc9, 0xa9, 0x38, 0x57, 0x0b, 0xf2, 0x93, 0x6a, + 0xec, 0x62, 0xf5, 0x7e, 0xd9, 0x77, 0xf2, 0x01, 0x7e, 0x43, 0xa3, 0xbe, + 0xc3, 0xcf, 0xba, 0xa4, 0x31, 0x2e, 0x53, 0x6a, 0xde, 0x85, 0xb5, 0x6f, + 0x33, 0x7c, 0x39, 0x6a, 0xe3, 0x9a, 0x16, 0xaa, 0x2d, 0xa0, 0x31, 0xa4, + 0xef, 0x52, 0x12, 0xff, 0x06, 0xf3, 0x6f, 0xe6, 0xfd, 0x3c, 0x8f, 0xe7, + 0x65, 0xfb, 0x4a, 0xbc, 0x2b, 0x99, 0xd4, 0x7e, 0x31, 0x63, 0x65, 0x8c, + 0xc7, 0x53, 0xc6, 0xed, 0xd4, 0x04, 0xb4, 0x7f, 0x54, 0x12, 0x3c, 0xcb, + 0xd5, 0x73, 0x69, 0xa9, 0x9b, 0x0b, 0xef, 0x87, 0xfa, 0xf3, 0xe1, 0x37, + 0x27, 0xf9, 0x52, 0xfd, 0xf7, 0x32, 0xea, 0x9b, 0x70, 0xf5, 0x7d, 0xca, + 0x44, 0xf5, 0x41, 0xb9, 0xaf, 0xb4, 0x55, 0x7f, 0x2b, 0x13, 0x93, 0xfb, + 0xaa, 0x6f, 0x28, 0x9e, 0xe6, 0xd5, 0x77, 0x3e, 0x51, 0xbd, 0x66, 0x71, + 0xd5, 0xc7, 0xda, 0xf7, 0x3e, 0x76, 0xdd, 0xb7, 0x1f, 0x51, 0x99, 0x58, + 0xfc, 0x65, 0xdf, 0xfc, 0x3c, 0x2c, 0xfc, 0xee, 0xe3, 0x25, 0x77, 0x5a, + 0x1e, 0x2b, 0x7b, 0xde, 0x1d, 0x2e, 0xb1, 0xd4, 0x16, 0x39, 0x1f, 0xcf, + 0x0c, 0x7e, 0xcf, 0x69, 0x0f, 0x55, 0x66, 0x1b, 0xa1, 0xaf, 0x1b, 0x95, + 0x2d, 0x61, 0x7e, 0x71, 0x96, 0x7b, 0x3e, 0x82, 0x39, 0xda, 0xe6, 0x25, + 0xf9, 0x54, 0x1b, 0xe3, 0x4c, 0x77, 0xc0, 0x77, 0xfb, 0xb8, 0xeb, 0xeb, + 0xe5, 0xcf, 0x2d, 0xed, 0x96, 0xcf, 0x55, 0x63, 0xa1, 0xca, 0x0c, 0xef, + 0xd7, 0xd9, 0x23, 0x65, 0x49, 0xa2, 0x1e, 0xfb, 0x87, 0xbc, 0x24, 0xb6, + 0xcb, 0xd3, 0xc7, 0x7f, 0xee, 0x5d, 0x72, 0xf0, 0x1e, 0xba, 0xe6, 0xbc, + 0x1b, 0xc4, 0xd2, 0xe0, 0x37, 0x1f, 0x65, 0xbd, 0xed, 0x90, 0x03, 0xd8, + 0x6d, 0xec, 0x39, 0xfa, 0x75, 0x97, 0xb4, 0xde, 0x32, 0x8e, 0x5e, 0x23, + 0x97, 0x56, 0xef, 0xe4, 0xbe, 0x0e, 0xd9, 0xb6, 0x7c, 0xfe, 0xab, 0xd8, + 0xf3, 0x41, 0x09, 0x7f, 0x01, 0x76, 0xe2, 0x0b, 0x0d, 0x4a, 0xb7, 0xd3, + 0x9e, 0x01, 0xf3, 0x03, 0xd7, 0x47, 0xd0, 0xcf, 0xfe, 0x36, 0x5f, 0x66, + 0xa7, 0x45, 0xbe, 0xd8, 0x24, 0x99, 0x36, 0xfa, 0x8d, 0xf2, 0x2b, 0xf4, + 0x57, 0xfd, 0x3e, 0x4b, 0xc9, 0x9f, 0x71, 0x8f, 0xd7, 0x38, 0x97, 0x64, + 0xe2, 0x7f, 0xc9, 0x27, 0x65, 0x22, 0xc1, 0xb9, 0x3c, 0x2c, 0x85, 0xf2, + 0xa3, 0xf8, 0x71, 0x9e, 0xa4, 0xfb, 0x5f, 0xe8, 0xb3, 0xfb, 0x31, 0x29, + 0xce, 0xa4, 0x65, 0x6a, 0x7e, 0x92, 0xdf, 0xe4, 0x8e, 0xdc, 0xa1, 0xce, + 0xb4, 0xec, 0x44, 0x32, 0xd4, 0x67, 0x4d, 0xf1, 0xae, 0x82, 0x9a, 0xcf, + 0x24, 0xe6, 0xf3, 0x4a, 0x1b, 0xef, 0x78, 0x5f, 0x82, 0xfe, 0x35, 0x4e, + 0x50, 0x0e, 0x6d, 0xb3, 0x2b, 0xc4, 0xfc, 0x5e, 0xf8, 0xab, 0x2c, 0xdb, + 0x2b, 0xe1, 0xa3, 0xab, 0x7a, 0x1e, 0xe5, 0xfa, 0x6c, 0x55, 0xb5, 0xff, + 0xaf, 0x68, 0x8b, 0x7a, 0x47, 0x83, 0xb6, 0x41, 0x1d, 0xb6, 0xe5, 0x3c, + 0x77, 0xc3, 0x4f, 0x0e, 0xe8, 0x82, 0x1c, 0x26, 0xea, 0xf9, 0xdd, 0xbc, + 0x81, 0xdf, 0x11, 0xe2, 0x4d, 0xf0, 0x8b, 0x3c, 0x0e, 0x6b, 0x1e, 0xff, + 0x3d, 0xfa, 0x0f, 0xd6, 0xe0, 0x0e, 0x94, 0x99, 0xfa, 0x1b, 0xbc, 0x77, + 0xc2, 0x77, 0xf2, 0x9c, 0xf5, 0xf7, 0xb7, 0xf9, 0xb2, 0x46, 0x7a, 0x36, + 0xe3, 0xf9, 0x7b, 0xdb, 0xfd, 0x75, 0xd9, 0x0b, 0x7e, 0xf1, 0x1e, 0x65, + 0x9f, 0xba, 0x8f, 0x9f, 0x19, 0xdf, 0x0b, 0xd9, 0x09, 0xe6, 0xd5, 0x07, + 0x19, 0xe3, 0x39, 0x01, 0xeb, 0xd7, 0xf3, 0xc4, 0xb7, 0x7b, 0x61, 0xfa, + 0xfa, 0x0e, 0xe7, 0x0a, 0x4c, 0xf8, 0x45, 0xf5, 0xfd, 0x0d, 0xf4, 0xe4, + 0xbb, 0x57, 0xbf, 0xbf, 0xb9, 0xf2, 0x1a, 0x0f, 0xb4, 0xfb, 0x36, 0xca, + 0x04, 0x4f, 0x5a, 0x75, 0x9b, 0xbd, 0xc0, 0xa7, 0x8c, 0x7f, 0x26, 0x13, + 0x9f, 0x90, 0x60, 0x1c, 0xef, 0x36, 0xfa, 0x79, 0x43, 0x03, 0x7d, 0xf0, + 0x69, 0xd5, 0x1d, 0x95, 0x04, 0xef, 0xbc, 0x24, 0x43, 0x7b, 0xd5, 0x7d, + 0x85, 0x17, 0xd6, 0x7d, 0x43, 0x95, 0x92, 0xa7, 0xd7, 0x64, 0x65, 0xe4, + 0x47, 0x62, 0x8b, 0x75, 0x35, 0x65, 0x85, 0xfd, 0x4e, 0x72, 0x9e, 0x89, + 0x07, 0xd4, 0x3c, 0x4d, 0xf8, 0x4d, 0xbc, 0x5b, 0x60, 0x86, 0x2a, 0xf3, + 0x5c, 0x77, 0xa4, 0x4b, 0x7c, 0x0e, 0xce, 0x37, 0x95, 0x5e, 0xc1, 0xb8, + 0x2c, 0xa3, 0x6e, 0xe4, 0xfb, 0xb4, 0x3e, 0xff, 0xbc, 0xa7, 0x9d, 0x67, + 0xf0, 0x79, 0x94, 0x95, 0x97, 0x36, 0xa7, 0xed, 0xe3, 0x4a, 0x0e, 0x1e, + 0x06, 0xdf, 0xff, 0x04, 0x75, 0x1f, 0x45, 0xca, 0x39, 0xa6, 0x57, 0xd7, + 0x9d, 0xfc, 0xfe, 0xb0, 0x0c, 0x42, 0x2e, 0x98, 0x7f, 0x58, 0x8a, 0xea, + 0xee, 0x10, 0xd2, 0x32, 0x9f, 0xa9, 0xeb, 0x1d, 0x6d, 0x4f, 0x49, 0xcb, + 0x5e, 0xfd, 0xdd, 0x56, 0x20, 0x4f, 0x7b, 0x74, 0xbb, 0xf1, 0x55, 0x5e, + 0x3d, 0x70, 0x19, 0xde, 0x88, 0xae, 0xe2, 0x0d, 0x7f, 0xac, 0x62, 0x7b, + 0x80, 0x35, 0xfc, 0x39, 0xf8, 0x58, 0xc3, 0x97, 0xf3, 0x49, 0x89, 0x40, + 0x8e, 0xc3, 0x6b, 0x72, 0x0c, 0xdc, 0xe3, 0xef, 0x99, 0x29, 0x9e, 0xdb, + 0x29, 0x3e, 0x53, 0x0e, 0x29, 0xbf, 0x5c, 0xc7, 0xfa, 0xb5, 0xbe, 0xf1, + 0x97, 0xac, 0xf5, 0x85, 0xf6, 0x00, 0x3f, 0xfc, 0xd3, 0xf6, 0xc1, 0xd7, + 0xda, 0xd7, 0xf6, 0xc1, 0x35, 0xbf, 0xa1, 0x7d, 0xb0, 0x51, 0x2e, 0xeb, + 0x65, 0xca, 0x84, 0x3c, 0x71, 0xbd, 0x28, 0x4f, 0x94, 0x23, 0xf2, 0x92, + 0xfa, 0xb4, 0x91, 0xbe, 0x53, 0xe2, 0xa2, 0xfa, 0x3e, 0x62, 0x1a, 0x3a, + 0xa8, 0x3d, 0x54, 0x86, 0x5f, 0x5e, 0x5c, 0xba, 0x49, 0xc9, 0xf4, 0xd3, + 0x35, 0xea, 0xa5, 0x2b, 0xcd, 0x7d, 0xbd, 0xce, 0xcd, 0x6f, 0xd0, 0xb9, + 0xf9, 0x55, 0x9d, 0xdb, 0xa6, 0xfd, 0xa5, 0x7f, 0x8a, 0xce, 0x8d, 0xd7, + 0x9d, 0x85, 0x04, 0xe7, 0x20, 0x12, 0xca, 0xf6, 0x36, 0xcb, 0xae, 0xd9, + 0xb8, 0x8c, 0xcc, 0xec, 0x96, 0x3f, 0x9a, 0x99, 0x56, 0xf7, 0x82, 0xfe, + 0xca, 0x4d, 0x26, 0xee, 0x0f, 0x79, 0xf2, 0x61, 0xf8, 0xbb, 0x13, 0x9d, + 0x0d, 0xb2, 0xeb, 0xfd, 0xea, 0x7c, 0xcf, 0xcc, 0x86, 0x3a, 0x84, 0x91, + 0xe7, 0x9c, 0x6b, 0xbb, 0x56, 0x88, 0x77, 0xc4, 0x1a, 0x65, 0x22, 0xde, + 0x22, 0xbb, 0x81, 0x9d, 0x0a, 0x57, 0xb9, 0xea, 0x9b, 0xed, 0x8c, 0x3a, + 0x3f, 0xe9, 0xde, 0xee, 0x8f, 0x0b, 0x3e, 0xb4, 0x9a, 0xf2, 0xe7, 0xb5, + 0x6e, 0xf5, 0xfd, 0xf1, 0x0b, 0xa5, 0x3f, 0x6f, 0x5b, 0x9f, 0xe7, 0xf3, + 0x7f, 0x42, 0x9d, 0x38, 0x78, 0x55, 0x7f, 0xdf, 0x26, 0xac, 0xf8, 0x59, + 0x2c, 0x8f, 0xab, 0x7b, 0x4c, 0x17, 0xc3, 0xe4, 0x97, 0xf2, 0x9b, 0x12, + 0xd9, 0x30, 0x30, 0xce, 0x2c, 0x90, 0xb4, 0x43, 0x9f, 0x4f, 0xe3, 0x4f, + 0xe8, 0xff, 0x7d, 0xea, 0x3c, 0x75, 0x05, 0xbc, 0xf1, 0x54, 0xbc, 0x35, + 0x1f, 0x27, 0xae, 0x5f, 0xbb, 0xb3, 0x7b, 0x39, 0xbe, 0xf7, 0xbf, 0xf1, + 0xd2, 0xb1, 0x7f, 0x1d, 0x9f, 0xd1, 0x3e, 0xb8, 0x3a, 0xcb, 0xda, 0xec, + 0xff, 0x50, 0xf8, 0xdf, 0xec, 0x67, 0x4b, 0xc4, 0x76, 0xf6, 0x91, 0xb2, + 0xf4, 0x6f, 0x57, 0xb1, 0x26, 0xf2, 0xb7, 0x82, 0x75, 0x3a, 0x96, 0x08, + 0xec, 0x79, 0xa8, 0xeb, 0x6c, 0xbd, 0x1f, 0xc8, 0x3e, 0x62, 0xea, 0x0e, + 0xc4, 0xda, 0xff, 0xbd, 0x61, 0x4c, 0x25, 0x13, 0xba, 0xab, 0x34, 0x2d, + 0xe1, 0xb9, 0x31, 0x89, 0x1c, 0x63, 0xfc, 0x3a, 0x23, 0xc5, 0xb8, 0x27, + 0xf7, 0xb9, 0xeb, 0x7d, 0x93, 0x2e, 0x63, 0x23, 0xed, 0x0f, 0xcb, 0xd0, + 0xc9, 0x47, 0x25, 0x3a, 0xc7, 0x77, 0xeb, 0xce, 0x2e, 0xa0, 0x8f, 0xb6, + 0x48, 0x39, 0xce, 0x18, 0x6e, 0x54, 0x9d, 0x05, 0x9f, 0x1f, 0x5f, 0x90, + 0x22, 0xb0, 0x42, 0x5e, 0xe9, 0x16, 0xa4, 0xab, 0xbe, 0xc4, 0xf4, 0x76, + 0xee, 0x29, 0xf8, 0x98, 0xa1, 0x89, 0x72, 0x54, 0xdd, 0xc9, 0x39, 0x1f, + 0x67, 0x5d, 0xf8, 0xef, 0x73, 0xc4, 0x19, 0xd0, 0x1d, 0x63, 0x12, 0x62, + 0x3e, 0x3c, 0xb7, 0x86, 0x33, 0xa8, 0x13, 0x86, 0xdc, 0xb8, 0x44, 0x4e, + 0xf9, 0x73, 0xe7, 0x3f, 0x52, 0x32, 0x16, 0x76, 0x4b, 0xf8, 0x18, 0x9f, + 0xeb, 0xfd, 0x21, 0x62, 0x77, 0xd8, 0x86, 0xb3, 0x9f, 0x45, 0x7f, 0x7c, + 0x97, 0xd1, 0xdf, 0xc2, 0x22, 0x5f, 0xf9, 0xc7, 0xfe, 0xcf, 0x04, 0xca, + 0xfe, 0xff, 0x07, 0x3b, 0x97, 0x22, 0x9a, 0xb0, 0x4e, 0x00, 0x00, 0x00 }; static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = { - 0x08001c1c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, - 0x08001b74, 0x08001c4c, 0x08001bdc, 0x08001c4c, 0x08001b08, 0x08001c4c, - 0x08001c4c, 0x08001c4c, 0x08001b14, 0x00000000, 0x08002b58, 0x08002ba8, - 0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc, - 0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140, - 0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 }; +static const u32 bnx2_COM_b06FwRodata[(0x14/4) + 1] = { + 0x08000f04, 0x08000f4c, 0x08000f80, 0x08000fcc, 0x08001000, 0x00000000 +}; static struct fw_info bnx2_com_fw_06 = { - .ver_major = 0x3, - .ver_minor = 0x4, - .ver_fix = 0x3, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x080000b4, + .start_addr = 0x080000f8, .text_addr = 0x08000000, - .text_len = 0x7d54, + .text_len = 0x4eac, .text_index = 0x0, .gz_text = bnx2_COM_b06FwText, .gz_text_len = sizeof(bnx2_COM_b06FwText), - .data_addr = 0x08007e00, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_COM_b06FwData, - .sbss_addr = 0x08007e00, - .sbss_len = 0x60, + .sbss_addr = 0x08004ee0, + .sbss_len = 0x38, .sbss_index = 0x0, - .bss_addr = 0x08007e60, - .bss_len = 0x88, + .bss_addr = 0x08004f18, + .bss_len = 0xbc, .bss_index = 0x0, - .rodata_addr = 0x08007d58, - .rodata_len = 0x88, + .rodata_addr = 0x08004eac, + .rodata_len = 0x14, .rodata_index = 0x0, .rodata = bnx2_COM_b06FwRodata, }; +static u8 bnx2_CP_b06FwText[] = { + 0x9d, 0xbc, 0x0d, 0x78, 0x13, 0xe7, 0x99, 0x2e, 0x7c, 0xcf, 0x48, 0xb2, + 0x65, 0x5b, 0xb6, 0xc7, 0xb6, 0x0c, 0x22, 0x65, 0x41, 0x83, 0x47, 0x20, + 0x62, 0x27, 0x1d, 0x81, 0x49, 0x94, 0xac, 0x36, 0xa8, 0xc6, 0x01, 0x93, + 0x90, 0xc6, 0x34, 0xb4, 0x75, 0x7a, 0xd2, 0x8d, 0x62, 0x0c, 0x21, 0x84, + 0x10, 0x67, 0x9b, 0x9e, 0xe3, 0x7c, 0x5f, 0xce, 0x5a, 0x35, 0x06, 0x0c, + 0xc8, 0x96, 0x31, 0x0e, 0x90, 0xfd, 0x7a, 0x9d, 0x18, 0x6c, 0x30, 0x49, + 0x65, 0x8b, 0x34, 0x74, 0x97, 0xf4, 0xa3, 0x45, 0x07, 0xf2, 0xe3, 0xfc, + 0x35, 0xa4, 0xed, 0x76, 0xdb, 0x3d, 0x39, 0x89, 0x0f, 0x25, 0x84, 0xb4, + 0xdd, 0xfc, 0xb4, 0xdd, 0x2d, 0x69, 0x9b, 0xcc, 0x77, 0x3f, 0x23, 0x09, + 0x0c, 0x4d, 0x7f, 0xf6, 0xf3, 0x75, 0xcd, 0x65, 0xcd, 0xcc, 0xfb, 0xf3, + 0xbc, 0xcf, 0xfb, 0x3c, 0xf7, 0x73, 0x3f, 0xef, 0xbc, 0x33, 0xb3, 0x80, + 0x62, 0xe4, 0xfe, 0x4a, 0x79, 0x5c, 0x5d, 0xdf, 0xbe, 0x1a, 0x8b, 0xae, + 0x36, 0xe5, 0xdc, 0xe9, 0x82, 0x13, 0x7f, 0xe1, 0x9f, 0xff, 0x2f, 0x2d, + 0x38, 0xe5, 0xcf, 0x01, 0x68, 0xf9, 0x7e, 0xe5, 0x80, 0x5b, 0x8d, 0x3c, + 0xf3, 0x5f, 0x1a, 0x0c, 0xb8, 0x1d, 0x91, 0x9e, 0xd6, 0xd5, 0x06, 0x10, + 0x4d, 0xd5, 0xfa, 0x97, 0xe0, 0x23, 0x2b, 0xee, 0x75, 0x42, 0xae, 0xff, + 0x55, 0xe4, 0xf7, 0x9d, 0xdf, 0xb9, 0x56, 0x7f, 0x7f, 0xc8, 0x01, 0xb7, + 0x16, 0xe9, 0x80, 0x36, 0x17, 0xee, 0x99, 0xac, 0xf3, 0xf5, 0x79, 0xdb, + 0x15, 0x94, 0xe5, 0xdb, 0x3a, 0x67, 0x7d, 0x67, 0x9e, 0x2f, 0x56, 0x14, + 0xd1, 0x70, 0x3c, 0x8d, 0xe6, 0xba, 0xde, 0x4e, 0xab, 0xd4, 0x08, 0xc1, + 0x6d, 0x18, 0x2d, 0xbd, 0x8a, 0x27, 0xbc, 0x7e, 0x11, 0x3c, 0x85, 0x06, + 0xe2, 0x57, 0x44, 0xd0, 0x7c, 0xe5, 0x58, 0x71, 0xdc, 0x19, 0x71, 0xa3, + 0x29, 0xed, 0x8e, 0x7f, 0x2a, 0x62, 0x60, 0x59, 0xfa, 0xfa, 0x62, 0x94, + 0xb9, 0xd1, 0x9d, 0xfe, 0xa8, 0x28, 0xdb, 0x5e, 0x73, 0xee, 0xff, 0xec, + 0xaa, 0xec, 0xff, 0x69, 0x31, 0x67, 0x04, 0xd8, 0x9c, 0xb0, 0xac, 0x82, + 0xc8, 0x6d, 0xb7, 0xa9, 0x11, 0xc3, 0x77, 0x10, 0x8b, 0xd1, 0xaa, 0xe1, + 0xe1, 0x2d, 0xf5, 0xbf, 0x54, 0x4e, 0x0c, 0xb2, 0xe1, 0x51, 0x07, 0xa2, + 0xda, 0x33, 0xfc, 0x3f, 0x6b, 0x56, 0x4b, 0xd8, 0xc0, 0xde, 0xd1, 0xf3, + 0xbc, 0xee, 0xb4, 0xaf, 0x6d, 0xda, 0x33, 0x6b, 0xd6, 0xed, 0xe1, 0x67, + 0xf0, 0xe8, 0xa8, 0xfc, 0xbe, 0x1b, 0x9d, 0x75, 0x0a, 0x26, 0x6f, 0x5b, + 0x0b, 0x87, 0x61, 0xa0, 0x7b, 0x8f, 0xe2, 0xec, 0xaa, 0x53, 0x11, 0xf5, + 0xea, 0xc1, 0x18, 0x95, 0xef, 0x34, 0x10, 0x2b, 0x8c, 0x84, 0x9d, 0xef, + 0x24, 0x22, 0x9a, 0xc3, 0xb0, 0xac, 0x60, 0x68, 0x3a, 0x1c, 0x15, 0x96, + 0xf5, 0xb4, 0xe9, 0x81, 0xff, 0x8b, 0xcf, 0x21, 0x3e, 0xdc, 0x0c, 0xd5, + 0x78, 0x0e, 0x5d, 0xc3, 0xcf, 0xe1, 0xb1, 0x5d, 0xc5, 0x98, 0xac, 0xe2, + 0x78, 0x93, 0x3e, 0x7c, 0x67, 0x9e, 0xf4, 0x2d, 0x72, 0xd4, 0xf1, 0x70, + 0x63, 0xd2, 0xf1, 0x06, 0xff, 0x4b, 0x99, 0xf3, 0xd6, 0xe4, 0xf4, 0x8b, + 0x65, 0x36, 0xb3, 0x4c, 0xf7, 0x65, 0x65, 0xe2, 0xc3, 0x11, 0xbc, 0x94, + 0x50, 0xb0, 0x3e, 0x54, 0x86, 0x68, 0x85, 0x8c, 0xd7, 0xb2, 0x46, 0xcd, + 0xb3, 0xd6, 0xa4, 0x26, 0x7d, 0x4d, 0xe0, 0x65, 0xde, 0xdb, 0x12, 0x3a, + 0x63, 0x65, 0xbc, 0xd2, 0x5e, 0x3b, 0x6d, 0x67, 0x25, 0xaf, 0x3b, 0x91, + 0x4c, 0x20, 0x56, 0x16, 0xb9, 0x8d, 0xe7, 0xba, 0xf9, 0xae, 0xe2, 0x76, + 0xbf, 0x97, 0x70, 0x7f, 0xb1, 0xd4, 0x50, 0x1f, 0x2c, 0xa7, 0x01, 0xbd, + 0x42, 0x99, 0x8f, 0x9a, 0x6b, 0xe1, 0x32, 0x1e, 0x10, 0x5b, 0xe3, 0xb8, + 0x7e, 0x68, 0x61, 0x7a, 0xbe, 0xbe, 0xb4, 0xeb, 0xc6, 0x96, 0xa4, 0x65, + 0x6d, 0x33, 0xa3, 0xd7, 0x15, 0xd1, 0x20, 0x4e, 0x26, 0x9a, 0xe1, 0x8e, + 0x04, 0xfc, 0xe7, 0x10, 0xc6, 0x92, 0xb4, 0x17, 0xcf, 0x26, 0xe0, 0x6c, + 0x98, 0xe7, 0x45, 0x57, 0x3a, 0x82, 0x1b, 0xd3, 0x26, 0x1a, 0xd3, 0x7f, + 0xde, 0xb2, 0x6e, 0x4e, 0xfa, 0x39, 0x86, 0x8f, 0xac, 0xec, 0x18, 0x64, + 0x7c, 0xd9, 0xff, 0xdd, 0xc9, 0x2b, 0xb0, 0x9d, 0x73, 0xb4, 0x95, 0xf3, + 0xb7, 0x3c, 0x94, 0x89, 0x16, 0x41, 0x37, 0xcf, 0x21, 0x82, 0xa5, 0x69, + 0x83, 0x73, 0x1a, 0xc1, 0x92, 0x64, 0x8d, 0x36, 0x8c, 0xf9, 0x88, 0xfa, + 0xb2, 0x36, 0xbd, 0x83, 0xe3, 0x6d, 0x0d, 0x34, 0xa3, 0x94, 0x36, 0x92, + 0x5a, 0x14, 0x46, 0x03, 0xfb, 0x5f, 0xf1, 0x17, 0xf4, 0x7f, 0x2b, 0xfb, + 0x7f, 0x97, 0xfd, 0x67, 0xec, 0xfe, 0xe1, 0xbc, 0x89, 0xe7, 0x6e, 0xda, + 0xe3, 0xf6, 0x94, 0xd3, 0xb9, 0x3c, 0xe9, 0xc5, 0xb6, 0x94, 0x49, 0x9b, + 0x93, 0x5b, 0x3e, 0x6c, 0x19, 0x9c, 0x89, 0xad, 0x83, 0xba, 0xef, 0x79, + 0xfe, 0xde, 0x34, 0x72, 0x05, 0x36, 0x0f, 0x2a, 0xd8, 0x6f, 0x5c, 0x81, + 0x2e, 0xfe, 0xde, 0x3b, 0x38, 0x0b, 0x8f, 0x0e, 0x3a, 0x10, 0xae, 0xba, + 0x74, 0x1c, 0x93, 0x8e, 0x2b, 0x10, 0x1f, 0xf1, 0xa3, 0x2b, 0xf1, 0xa2, + 0xad, 0xc3, 0xd2, 0xc8, 0xff, 0x9b, 0xf7, 0x63, 0xfa, 0x8e, 0x1f, 0xab, + 0x13, 0x1a, 0xba, 0x92, 0x0e, 0xb1, 0x4b, 0xfe, 0xfd, 0x92, 0xf7, 0x34, + 0x6c, 0x4a, 0xe7, 0xeb, 0x8b, 0x9f, 0xf9, 0xd1, 0x90, 0x98, 0xa0, 0x9f, + 0xd4, 0xd3, 0x47, 0x4c, 0x7c, 0x37, 0x5d, 0x87, 0x7f, 0x4a, 0x07, 0xf1, + 0x8f, 0xd4, 0xc3, 0xb7, 0xd2, 0x7e, 0x1c, 0x49, 0xcf, 0xc4, 0x53, 0x69, + 0x1f, 0xbe, 0x49, 0xfd, 0x3f, 0x99, 0x6e, 0xa6, 0xed, 0x6a, 0x38, 0x9c, + 0x16, 0xfd, 0x15, 0x50, 0xde, 0x62, 0x6c, 0x1a, 0xac, 0x09, 0x9e, 0xa4, + 0x6d, 0xfc, 0xa3, 0x79, 0x13, 0x32, 0x95, 0xf5, 0xb6, 0x4d, 0x6d, 0xe3, + 0xf5, 0xed, 0x83, 0x35, 0xd1, 0x2b, 0x15, 0xcb, 0x52, 0x43, 0xb5, 0xe1, + 0x13, 0xaa, 0x8a, 0x49, 0xaf, 0xee, 0xcf, 0xa8, 0xba, 0x3f, 0x0a, 0x17, + 0x12, 0xb4, 0xed, 0x78, 0xb5, 0x3e, 0x14, 0xa7, 0x4d, 0x78, 0x8d, 0x7d, + 0x40, 0x99, 0xee, 0x8f, 0xab, 0x6e, 0x6c, 0x4d, 0xea, 0x7b, 0xe3, 0xaa, + 0x07, 0xf1, 0x74, 0x31, 0xfe, 0x6d, 0x50, 0xef, 0x89, 0xab, 0x9f, 0x45, + 0xbc, 0xd2, 0xb2, 0xbe, 0x19, 0x42, 0xfb, 0xf4, 0x08, 0xa2, 0xd5, 0x11, + 0xc4, 0x66, 0x45, 0xbc, 0x48, 0x26, 0x81, 0x77, 0x7b, 0x0d, 0xdf, 0xbf, + 0x28, 0xcd, 0xf8, 0x6a, 0xb3, 0xee, 0xf7, 0xab, 0xb5, 0xf1, 0x61, 0x75, + 0x11, 0x5d, 0x12, 0x7e, 0x5f, 0x64, 0x19, 0x3a, 0xec, 0x6b, 0x0a, 0x34, + 0xc3, 0x83, 0x4d, 0xc9, 0xeb, 0x10, 0xf3, 0xd6, 0xb4, 0xec, 0x54, 0x6b, + 0xce, 0x9b, 0xaa, 0x3e, 0xd1, 0xac, 0x5a, 0xd6, 0x07, 0x0b, 0xdf, 0xb5, + 0xfc, 0xd3, 0x2c, 0x6b, 0xc1, 0x42, 0xe9, 0xd3, 0x8f, 0x8a, 0x88, 0x89, + 0x95, 0xf6, 0x1c, 0x14, 0xe3, 0xec, 0x60, 0x25, 0xfb, 0xd0, 0xf0, 0xcf, + 0xd7, 0xea, 0xc1, 0xb5, 0x6a, 0x31, 0xde, 0x1a, 0x29, 0xc6, 0x69, 0x8e, + 0xe7, 0x97, 0x83, 0x3e, 0xfc, 0x7a, 0xd0, 0xb2, 0xbe, 0x68, 0xfe, 0x35, + 0x06, 0x2a, 0xfb, 0xf1, 0x4f, 0xe3, 0x5e, 0xfc, 0x1b, 0x75, 0x7b, 0x26, + 0x11, 0x7d, 0xa0, 0x0a, 0x7a, 0x74, 0x5c, 0x39, 0x79, 0x67, 0x19, 0x6a, + 0x9b, 0xcb, 0x14, 0xbd, 0x69, 0x07, 0x74, 0xdf, 0x95, 0x8a, 0x17, 0xe7, + 0x52, 0x1a, 0x7e, 0x9a, 0xaa, 0x09, 0xff, 0x80, 0x7d, 0xfe, 0x87, 0xf9, + 0xb4, 0x95, 0x99, 0x26, 0x7a, 0x13, 0x1d, 0x51, 0xcf, 0x49, 0xea, 0x39, + 0x49, 0x3d, 0x27, 0xa9, 0x67, 0xca, 0x70, 0x24, 0x49, 0x3d, 0x53, 0x77, + 0xdf, 0xa4, 0x4d, 0x3c, 0x99, 0xa4, 0x8e, 0x93, 0x32, 0x47, 0x61, 0xfa, + 0xe7, 0xa7, 0xf0, 0xf7, 0xf6, 0xdc, 0xbd, 0x6c, 0xfd, 0x37, 0xaf, 0x8c, + 0xe9, 0xfe, 0x69, 0x59, 0xfc, 0x91, 0xb1, 0xbd, 0x64, 0xc5, 0x34, 0x19, + 0x97, 0x8c, 0xcf, 0xd6, 0x9f, 0xbf, 0x5d, 0xf9, 0xaa, 0x82, 0x62, 0xcb, + 0xda, 0x65, 0xe6, 0xee, 0x7b, 0xf3, 0xe3, 0xfb, 0x8c, 0x92, 0xb5, 0x8b, + 0x7f, 0x72, 0x53, 0xdf, 0xc1, 0xa8, 0xba, 0x88, 0xe7, 0x7a, 0x3c, 0x8a, + 0x9b, 0x0a, 0x2f, 0x3d, 0xbf, 0xb6, 0x5a, 0xe6, 0xc3, 0x7f, 0xe1, 0x9c, + 0xf6, 0x64, 0xf7, 0xf7, 0x45, 0x9e, 0xcb, 0x58, 0x04, 0x53, 0xc5, 0x06, + 0xbc, 0xb4, 0x97, 0x45, 0xb9, 0x7b, 0x88, 0xab, 0x91, 0x76, 0x34, 0xd7, + 0xef, 0xb5, 0xfb, 0x28, 0xe8, 0x13, 0xbb, 0x57, 0xf0, 0xee, 0x75, 0x0a, + 0x4e, 0x84, 0x0c, 0xda, 0xcc, 0x10, 0xfd, 0x1a, 0x28, 0xec, 0x83, 0xdb, + 0x13, 0x89, 0x20, 0xd1, 0x0b, 0x77, 0x51, 0x24, 0x8c, 0xf9, 0xbd, 0x35, + 0xeb, 0xce, 0x42, 0x0f, 0xf6, 0x2a, 0x7a, 0x33, 0x50, 0x6b, 0x8e, 0x51, + 0x8f, 0x57, 0x2a, 0xba, 0xbf, 0x40, 0x81, 0x5b, 0x61, 0xb9, 0x40, 0x6a, + 0x08, 0x5b, 0xd3, 0xf2, 0x3b, 0x0c, 0x23, 0xf5, 0xeb, 0x7c, 0x5f, 0xb4, + 0xeb, 0x76, 0xda, 0xf5, 0x59, 0x8e, 0x5d, 0xf7, 0x13, 0x1f, 0xdd, 0xae, + 0xc8, 0x3a, 0x1c, 0x48, 0xc0, 0x5d, 0x10, 0xd9, 0x80, 0xe7, 0x12, 0x1f, + 0x57, 0xe7, 0xcb, 0x29, 0x2c, 0xe7, 0x4f, 0x4d, 0x95, 0xe5, 0x0d, 0x2b, + 0xea, 0xcd, 0xca, 0x52, 0xdc, 0x37, 0x84, 0x1d, 0x49, 0xa9, 0x1b, 0xb1, + 0xeb, 0x3a, 0xd9, 0x47, 0x77, 0xa2, 0xa6, 0xe9, 0x66, 0x45, 0x0f, 0x3f, + 0x8e, 0xda, 0xe8, 0x3b, 0x9c, 0xc3, 0x2e, 0xe8, 0xe7, 0xd7, 0x21, 0x2b, + 0xcb, 0xbc, 0x54, 0x56, 0x8e, 0xc5, 0x29, 0x28, 0xb7, 0x27, 0xe1, 0xf1, + 0x19, 0x55, 0x39, 0x5f, 0x84, 0x72, 0x0b, 0xe7, 0x4f, 0x35, 0xfc, 0xb8, + 0x85, 0x36, 0xb4, 0x61, 0x97, 0x85, 0x4d, 0xa1, 0x4a, 0xfa, 0x5b, 0x33, + 0xca, 0x88, 0x87, 0x1b, 0x35, 0x44, 0xcb, 0x23, 0x61, 0xe5, 0xd6, 0xf4, + 0xce, 0x9c, 0xfe, 0x9f, 0xae, 0xa4, 0x7c, 0x4a, 0x63, 0xf2, 0xf2, 0xeb, + 0x1f, 0xe5, 0xc7, 0x77, 0xd9, 0xf5, 0xb9, 0x05, 0x9f, 0x5c, 0xbe, 0x56, + 0x1b, 0x81, 0xc2, 0x78, 0x51, 0x44, 0xfd, 0xea, 0x8c, 0xd2, 0xd1, 0xa0, + 0xcb, 0xbe, 0xe6, 0xc0, 0x90, 0x33, 0xea, 0x73, 0xe0, 0xf7, 0x56, 0x74, + 0x95, 0x5c, 0x2b, 0x46, 0xac, 0xb9, 0xd6, 0xe7, 0x44, 0x6d, 0x78, 0x33, + 0xfd, 0x6d, 0x72, 0x55, 0x03, 0xef, 0x05, 0xcc, 0x93, 0xa8, 0xf1, 0x6f, + 0x86, 0xfc, 0xfe, 0x90, 0x36, 0xd2, 0x20, 0x75, 0x59, 0x46, 0x6c, 0x4e, + 0xd7, 0x4e, 0xc2, 0x8b, 0xcd, 0xb4, 0xbf, 0xc2, 0x88, 0x6e, 0x2e, 0x73, + 0x38, 0x71, 0x88, 0x38, 0xec, 0x30, 0x7a, 0x50, 0xc8, 0x31, 0x32, 0x3e, + 0xe2, 0xf1, 0x04, 0xf0, 0x62, 0xbf, 0x85, 0x86, 0x90, 0x07, 0x4b, 0x6c, + 0xdb, 0x3c, 0xaa, 0xdc, 0x98, 0xfc, 0xd8, 0x1a, 0x72, 0x16, 0x45, 0xd5, + 0x48, 0xc0, 0x77, 0x9a, 0xd1, 0xbc, 0x20, 0x52, 0xab, 0x39, 0x11, 0x57, + 0x9a, 0xd2, 0xdd, 0xca, 0xf2, 0x74, 0x8f, 0xb2, 0xc4, 0xc6, 0x9c, 0xa3, + 0xca, 0xd2, 0xb4, 0x07, 0xa9, 0x7e, 0x05, 0x3b, 0x42, 0x94, 0xab, 0x3a, + 0x6b, 0xc7, 0xe9, 0x7e, 0x95, 0x18, 0xf9, 0x2e, 0x31, 0x52, 0x0f, 0x83, + 0x7d, 0x3f, 0x9d, 0xa8, 0xc4, 0x51, 0x62, 0xe1, 0x4f, 0x52, 0xe5, 0x2a, + 0x8a, 0xaf, 0xc0, 0x8f, 0x47, 0xca, 0x30, 0x36, 0x38, 0x8b, 0xbf, 0xeb, + 0xf0, 0xca, 0x88, 0x65, 0x75, 0x9b, 0x96, 0x75, 0xc0, 0x3c, 0xaa, 0x34, + 0xb0, 0xcf, 0xa8, 0x33, 0x1e, 0x2d, 0x8c, 0x04, 0xcc, 0xad, 0xec, 0xd3, + 0x11, 0x89, 0x2b, 0x51, 0xf6, 0x77, 0x23, 0xfb, 0x5b, 0x9a, 0xeb, 0x2f, + 0xdb, 0xaf, 0xc8, 0x22, 0xf5, 0xf2, 0x75, 0xc2, 0xac, 0x03, 0x1c, 0x4c, + 0x04, 0x82, 0xf9, 0x7a, 0x4b, 0x59, 0xe7, 0xc6, 0x0b, 0x75, 0x80, 0xe1, + 0x44, 0x90, 0x73, 0x2a, 0xb6, 0xee, 0x67, 0xec, 0xf9, 0x1a, 0x9c, 0x46, + 0x3d, 0x5a, 0x87, 0x85, 0x47, 0x84, 0xd5, 0xec, 0x3c, 0x49, 0xfc, 0x74, + 0xdb, 0x31, 0x6b, 0xd2, 0x21, 0x71, 0x34, 0x88, 0x5e, 0xfa, 0x75, 0x57, + 0x52, 0x6c, 0xbc, 0xfe, 0xcb, 0x89, 0x80, 0x82, 0x6f, 0x04, 0x32, 0xcd, + 0xa5, 0x28, 0xc7, 0xba, 0x90, 0xd8, 0xa6, 0xf9, 0xe5, 0xe7, 0x0c, 0x3d, + 0xbc, 0x42, 0xe1, 0x9c, 0x05, 0xf4, 0xa6, 0xa5, 0x0a, 0x10, 0x18, 0x03, + 0xce, 0xa4, 0xca, 0xb1, 0xda, 0x74, 0x40, 0xad, 0x08, 0xa2, 0x27, 0x3d, + 0x15, 0xd7, 0x4d, 0xe2, 0xb4, 0xb4, 0x17, 0xa4, 0x5f, 0x97, 0x60, 0x99, + 0x96, 0xb5, 0x69, 0x37, 0xdb, 0x76, 0x07, 0x32, 0x41, 0x95, 0xf1, 0xea, + 0x10, 0x2f, 0x9c, 0x64, 0x5c, 0x6a, 0x30, 0x5c, 0x68, 0xd3, 0xca, 0xd1, + 0x60, 0xfe, 0xd6, 0x5a, 0xb6, 0x4a, 0xee, 0x5d, 0xc4, 0xf7, 0x42, 0xf6, + 0xfb, 0xb6, 0xa1, 0xfb, 0x47, 0x79, 0x92, 0x49, 0x65, 0xaf, 0xc7, 0x19, + 0x73, 0x36, 0xb1, 0xdd, 0x2d, 0x6c, 0x77, 0xad, 0xa6, 0x47, 0xe3, 0x17, + 0xca, 0x65, 0x82, 0x0e, 0xe8, 0x9a, 0x94, 0x6d, 0x64, 0xbb, 0xab, 0xd9, + 0x6e, 0x8f, 0x26, 0xf2, 0xfd, 0xd6, 0x5a, 0xbb, 0x4a, 0xee, 0x65, 0xed, + 0x23, 0xdb, 0x6e, 0xbd, 0xb4, 0x6b, 0x8e, 0xe6, 0xfa, 0x3a, 0x91, 0x40, + 0xbf, 0x23, 0xc2, 0x18, 0x59, 0x1f, 0xf0, 0x77, 0x31, 0x5e, 0x36, 0x32, + 0x76, 0x64, 0x6d, 0x62, 0x6a, 0xbc, 0x42, 0xfc, 0x62, 0x19, 0xb9, 0x26, + 0xe5, 0xc4, 0xd6, 0x26, 0xa9, 0x67, 0x89, 0x2f, 0x3e, 0xea, 0x57, 0xb0, + 0xc5, 0x89, 0xc3, 0x09, 0xe2, 0x3f, 0xbe, 0x46, 0xbb, 0xf3, 0xa3, 0x39, + 0x5d, 0x83, 0xb6, 0x5d, 0x8c, 0x63, 0x66, 0x05, 0x6d, 0x3d, 0x6b, 0x6f, + 0xcb, 0xd8, 0xf6, 0xa4, 0xdd, 0x76, 0x5c, 0x69, 0x4e, 0xd7, 0x6a, 0x15, + 0x8c, 0x99, 0xc7, 0x2f, 0x60, 0xe7, 0xec, 0x68, 0x71, 0x24, 0xd0, 0xb4, + 0x9e, 0x93, 0xe4, 0x66, 0x7c, 0xfb, 0xce, 0xbc, 0x6e, 0xda, 0x45, 0x0f, + 0xed, 0x30, 0x3b, 0xbf, 0x4d, 0x62, 0x70, 0xc4, 0x38, 0xa8, 0x35, 0x58, + 0xbb, 0x4b, 0xfe, 0x93, 0x6b, 0xd4, 0x3f, 0xca, 0x6b, 0x35, 0x58, 0x3d, + 0xfc, 0x0d, 0xda, 0x99, 0xee, 0x13, 0x3b, 0xec, 0xba, 0x20, 0x97, 0xc8, + 0x24, 0xb2, 0x89, 0x4c, 0xff, 0x37, 0xcb, 0xcd, 0xa4, 0x7e, 0x04, 0x1b, + 0x2b, 0x29, 0xcf, 0x36, 0xf2, 0x99, 0xa3, 0xca, 0x67, 0x29, 0x4f, 0xc6, + 0xe5, 0xc5, 0x63, 0x49, 0x91, 0x47, 0x89, 0xce, 0x88, 0xcc, 0xc4, 0xf9, + 0x64, 0x20, 0xfe, 0x34, 0x44, 0xb6, 0x6e, 0xa5, 0x45, 0xea, 0x27, 0x7b, + 0x78, 0x2f, 0x2f, 0x23, 0xb4, 0x72, 0x5b, 0xb6, 0xac, 0x4c, 0xb7, 0x72, + 0xae, 0x5d, 0xc6, 0xfd, 0xa5, 0x28, 0x73, 0xd2, 0xd6, 0xa4, 0xed, 0x9f, + 0x59, 0x51, 0x6d, 0x13, 0xaf, 0x79, 0x39, 0x4f, 0x6e, 0xc6, 0x75, 0x3d, + 0x78, 0x8b, 0x43, 0x69, 0xf6, 0x48, 0xbc, 0xa6, 0x7d, 0xa6, 0x52, 0x4e, + 0x3c, 0x93, 0x58, 0xba, 0xb4, 0xc4, 0xb8, 0x1a, 0xdf, 0x18, 0xf1, 0x61, + 0x84, 0x73, 0xfb, 0x62, 0x42, 0xe2, 0xeb, 0x4c, 0x3c, 0x91, 0xf2, 0xe0, + 0x85, 0x84, 0x1f, 0x8f, 0x33, 0xfe, 0x4c, 0x24, 0x0c, 0x1c, 0x4a, 0x79, + 0xf1, 0x3c, 0xed, 0x79, 0x34, 0xe5, 0xa3, 0xbd, 0xd4, 0x61, 0x38, 0xd5, + 0x6c, 0x8f, 0xe1, 0xd9, 0xc4, 0xab, 0x32, 0xd6, 0xa0, 0x8c, 0x75, 0x8b, + 0x3d, 0xd6, 0x7c, 0x9c, 0x9f, 0x79, 0x61, 0x1e, 0x4e, 0x25, 0x6c, 0x1c, + 0xe8, 0x59, 0xe6, 0x90, 0x79, 0xa0, 0xcd, 0x0e, 0x08, 0x16, 0xe8, 0xfd, + 0x71, 0x58, 0xd8, 0x6f, 0xce, 0xa0, 0xff, 0xf7, 0x50, 0x5e, 0xea, 0x94, + 0xe3, 0x87, 0xab, 0x2c, 0x5a, 0x1a, 0x09, 0xc4, 0x7a, 0xa9, 0x77, 0x67, + 0x44, 0xf4, 0x90, 0xd5, 0xfb, 0x8a, 0xf4, 0x51, 0x45, 0xb8, 0xda, 0x95, + 0x03, 0x71, 0xab, 0xc4, 0x10, 0x7d, 0x07, 0x88, 0xb3, 0xc0, 0xfc, 0xfd, + 0x4e, 0x8e, 0x6f, 0x25, 0xc7, 0x6c, 0xa2, 0xc0, 0xa8, 0xd5, 0x2a, 0x29, + 0xfb, 0xf1, 0x3f, 0x88, 0x81, 0xa2, 0xa3, 0x35, 0xb9, 0xf9, 0x2a, 0x77, + 0x50, 0x5e, 0x3f, 0x90, 0x9f, 0x17, 0xcb, 0xda, 0x69, 0xe6, 0xe7, 0xa6, + 0x1a, 0xfe, 0x4a, 0x3d, 0x3e, 0x44, 0x8b, 0x18, 0x49, 0x54, 0x21, 0xae, + 0xa9, 0xb9, 0xb6, 0xa3, 0x4a, 0x01, 0xf3, 0x07, 0x8c, 0x8b, 0xef, 0x97, + 0x22, 0xea, 0x94, 0xfa, 0x88, 0x16, 0x44, 0x02, 0xc1, 0xb9, 0xea, 0x54, + 0x9b, 0x11, 0x1c, 0x90, 0xbe, 0xe2, 0x94, 0xf5, 0x52, 0x2c, 0x18, 0x49, + 0xe4, 0x71, 0xe3, 0x3f, 0x53, 0xcf, 0x4b, 0x1f, 0x9b, 0xaa, 0x53, 0x91, + 0x53, 0xf4, 0xaa, 0xa2, 0x75, 0x50, 0xf4, 0xe7, 0xc4, 0x4a, 0x73, 0x51, + 0x4e, 0xe6, 0x99, 0x68, 0x4b, 0xa8, 0xd8, 0x30, 0xc8, 0xbe, 0x52, 0x0a, + 0x36, 0x87, 0x96, 0x60, 0xc8, 0x6b, 0xd3, 0x45, 0xb4, 0x26, 0x1a, 0x69, + 0x63, 0xc4, 0x99, 0x71, 0x3b, 0x7e, 0xda, 0xfe, 0x33, 0x9b, 0x3e, 0xb1, + 0x2c, 0xfd, 0x20, 0xd6, 0x26, 0x03, 0xfe, 0x93, 0x78, 0x10, 0x6d, 0x69, + 0x17, 0x62, 0xc3, 0x1e, 0x74, 0xb2, 0x6f, 0xb5, 0x4f, 0xfc, 0x49, 0x43, + 0xe7, 0xe8, 0x89, 0x17, 0x54, 0xda, 0x67, 0xe7, 0xa8, 0x97, 0xc7, 0x34, + 0x1e, 0x6e, 0x3c, 0xc4, 0xe3, 0x28, 0xe7, 0xbf, 0x83, 0x18, 0x9c, 0x4e, + 0x98, 0xb8, 0x9f, 0x32, 0x8d, 0x27, 0xea, 0xb1, 0x91, 0xf2, 0x8d, 0x25, + 0x1c, 0xf0, 0x4f, 0x0b, 0xe3, 0x3e, 0xea, 0xf2, 0xc9, 0x44, 0x58, 0x79, + 0x80, 0xff, 0x0f, 0x51, 0x26, 0xc9, 0x47, 0xd6, 0xd1, 0x0e, 0xa2, 0xd3, + 0x68, 0x27, 0x6a, 0xad, 0xc3, 0x9e, 0x07, 0x88, 0x7f, 0x5c, 0x3e, 0x57, + 0xba, 0x16, 0x43, 0x7e, 0xbe, 0x80, 0xa1, 0x14, 0x62, 0xee, 0x48, 0x5d, + 0x63, 0x41, 0x6f, 0xeb, 0x86, 0xc2, 0x48, 0xfb, 0x43, 0x3f, 0xad, 0x9f, + 0x85, 0x93, 0x9c, 0x13, 0xa7, 0x6d, 0xe3, 0x51, 0xc5, 0x65, 0x18, 0xb6, + 0x2f, 0xab, 0xe3, 0xed, 0xb9, 0xbc, 0x4a, 0x97, 0x38, 0xc6, 0x3e, 0x44, + 0x6f, 0xa2, 0x0b, 0xd1, 0xc3, 0x71, 0x6b, 0xc8, 0xf6, 0x77, 0xf1, 0x39, + 0x27, 0x75, 0xf4, 0x5d, 0xc6, 0x6f, 0xd1, 0x85, 0x94, 0xdb, 0xca, 0xb6, + 0x44, 0x1e, 0x3b, 0x16, 0xfa, 0xfe, 0xd0, 0x76, 0xa6, 0xca, 0x53, 0x87, + 0xed, 0x7b, 0x0c, 0xec, 0xd8, 0x53, 0x4b, 0xbb, 0xfb, 0xa5, 0xe5, 0xaf, + 0x18, 0x60, 0xdd, 0xa9, 0xb2, 0x08, 0x2f, 0x40, 0xae, 0x5d, 0x69, 0x73, + 0x13, 0xef, 0x1d, 0xa6, 0xad, 0x49, 0xbb, 0x96, 0xb5, 0xe5, 0x42, 0xdc, + 0x28, 0x88, 0x16, 0x31, 0x6e, 0x1c, 0x4a, 0x04, 0xc2, 0x2f, 0xd8, 0xb1, + 0xcd, 0x49, 0xdb, 0x90, 0xf9, 0xef, 0xb6, 0xe7, 0x7e, 0xd9, 0x85, 0xb9, + 0x9f, 0xbc, 0xc0, 0x91, 0xfa, 0x93, 0x53, 0x7d, 0x2a, 0x3b, 0xef, 0xce, + 0x3e, 0xbd, 0xc7, 0xb6, 0xd3, 0x94, 0xe0, 0x9f, 0x03, 0x8e, 0x01, 0xce, + 0xb3, 0x79, 0x15, 0xc7, 0x5f, 0xc9, 0x78, 0x52, 0xc0, 0x83, 0x79, 0xe4, + 0xf0, 0xa7, 0x50, 0x3c, 0x90, 0xb1, 0x8a, 0xf8, 0xbb, 0x29, 0x14, 0x08, + 0x17, 0x29, 0x37, 0xe0, 0xee, 0x61, 0x07, 0x0a, 0x06, 0x14, 0x3c, 0x6b, + 0xd6, 0xe5, 0xec, 0x43, 0xe6, 0xfb, 0x2a, 0xdb, 0x3e, 0xe6, 0x8c, 0xcb, + 0x7c, 0xcb, 0x1c, 0x7b, 0xe0, 0xeb, 0x53, 0xe0, 0x21, 0x6e, 0x94, 0x18, + 0x32, 0xd7, 0x1a, 0xca, 0xfb, 0x64, 0xae, 0x49, 0x1b, 0x77, 0x87, 0xb1, + 0x91, 0xf6, 0x50, 0xba, 0xfb, 0x7a, 0xdc, 0xc7, 0x72, 0x1b, 0x78, 0x6f, + 0xc3, 0x68, 0x25, 0x0f, 0x2f, 0x8f, 0x69, 0x3c, 0xea, 0x71, 0xef, 0x70, + 0x0d, 0xa2, 0x95, 0x7a, 0xd0, 0xaf, 0x3a, 0x50, 0x39, 0x20, 0x3a, 0x55, + 0xb1, 0x72, 0x81, 0x02, 0xf3, 0xea, 0x42, 0xa8, 0x73, 0x3f, 0xc9, 0x37, + 0xff, 0x9c, 0xac, 0x3f, 0x9a, 0x32, 0x87, 0x6e, 0x8e, 0xfd, 0x9f, 0xed, + 0x39, 0x9c, 0x33, 0x2e, 0x7d, 0x48, 0x2c, 0xb5, 0xe7, 0xf1, 0x4f, 0xf8, + 0xfe, 0x73, 0x9c, 0x8f, 0x2e, 0x96, 0xf9, 0xc3, 0xf9, 0xc5, 0x85, 0xf9, + 0x9d, 0xca, 0x49, 0x25, 0xae, 0xeb, 0xe1, 0x21, 0x9b, 0xc3, 0xf8, 0x99, + 0xcf, 0xe9, 0x71, 0xd1, 0x39, 0x39, 0x8b, 0x5b, 0x35, 0xe0, 0x2f, 0x30, + 0xee, 0xc0, 0x3d, 0x9c, 0xa7, 0x03, 0x09, 0x75, 0xa9, 0x0b, 0xea, 0x4c, + 0x17, 0x13, 0xdb, 0x11, 0x53, 0xc7, 0xba, 0x61, 0xe6, 0x4a, 0xc3, 0xa5, + 0xe8, 0xd2, 0x14, 0xf7, 0xf6, 0xba, 0x45, 0x92, 0xf3, 0xfa, 0xcb, 0x0d, + 0xa8, 0x25, 0x8c, 0xef, 0x3b, 0x34, 0x38, 0x0b, 0x0c, 0x45, 0x4d, 0xd4, + 0x35, 0x22, 0x5e, 0x01, 0x67, 0x99, 0x01, 0x85, 0x39, 0x2d, 0x7a, 0x35, + 0x08, 0xb6, 0x44, 0x0b, 0x8c, 0x07, 0x71, 0x4f, 0x12, 0x56, 0x71, 0x84, + 0xf9, 0x4e, 0xc4, 0x20, 0x87, 0x0d, 0xf8, 0x0a, 0x94, 0x07, 0xb1, 0x9a, + 0xbc, 0x61, 0xcd, 0xb0, 0xc8, 0xe1, 0x21, 0x9f, 0x30, 0xfc, 0xad, 0x60, + 0x8e, 0xdd, 0xac, 0x07, 0x27, 0x99, 0x67, 0xae, 0xa6, 0xee, 0x47, 0x12, + 0x0f, 0xa2, 0x21, 0x79, 0xdc, 0xf2, 0x90, 0x27, 0x16, 0x18, 0x35, 0xe7, + 0xbb, 0x10, 0xa3, 0x0f, 0x0b, 0xff, 0x69, 0xc3, 0x43, 0xf4, 0xbf, 0x74, + 0x42, 0x7d, 0x86, 0xec, 0x01, 0x1d, 0xa3, 0xeb, 0x71, 0xff, 0xe8, 0x4c, + 0xfa, 0xea, 0x06, 0xfa, 0x2a, 0xb9, 0x50, 0xff, 0x0d, 0xb8, 0x6f, 0xf8, + 0x06, 0xdc, 0xbb, 0xcb, 0x08, 0x6e, 0xa0, 0xae, 0xd7, 0x0c, 0x33, 0x10, + 0x4e, 0x93, 0x76, 0xf3, 0xba, 0x12, 0x3e, 0x48, 0x5d, 0xe4, 0xf4, 0x94, + 0x41, 0x9e, 0xa3, 0xfc, 0xb3, 0xc5, 0x4b, 0xf1, 0x82, 0x7a, 0xc5, 0xbf, + 0xb7, 0xee, 0xfb, 0xcc, 0xbd, 0x45, 0x76, 0x44, 0x67, 0x18, 0xaf, 0x5a, + 0x8f, 0x6a, 0x0a, 0x0a, 0x22, 0x88, 0xcf, 0xae, 0x7f, 0xd9, 0x7a, 0x6c, + 0x95, 0x5c, 0xbf, 0xd5, 0x89, 0x62, 0x95, 0xd7, 0xa4, 0xcd, 0x1d, 0x32, + 0x47, 0x44, 0xda, 0x4f, 0x6a, 0x33, 0x63, 0xf5, 0x5d, 0x28, 0x4f, 0xde, + 0x47, 0xac, 0x7d, 0x3a, 0xe1, 0x45, 0x4f, 0x32, 0xcb, 0x9d, 0x6e, 0x4f, + 0x0b, 0x67, 0x72, 0xa3, 0xb8, 0x57, 0xe2, 0x46, 0x14, 0xeb, 0xf9, 0xbb, + 0xa8, 0x57, 0x6f, 0x8e, 0x83, 0xc9, 0xbc, 0xd1, 0xc8, 0xb9, 0xa0, 0xbd, + 0xf6, 0x3a, 0x50, 0x64, 0x34, 0x65, 0x6d, 0xb5, 0x77, 0x85, 0x8d, 0x4b, + 0x65, 0xbd, 0xdd, 0x36, 0x2e, 0x95, 0xb2, 0x9e, 0x60, 0x92, 0xa7, 0x77, + 0x15, 0xed, 0x75, 0x26, 0x4a, 0x7a, 0x5b, 0x70, 0x2f, 0xe7, 0x78, 0x2d, + 0x79, 0xf6, 0x09, 0xb3, 0x3c, 0xc7, 0x3f, 0x9b, 0x70, 0x77, 0x32, 0x8a, + 0xd6, 0x64, 0x4d, 0xf4, 0xb4, 0xac, 0x25, 0xb9, 0xb2, 0xd8, 0x19, 0xad, + 0x16, 0x5d, 0x3c, 0x97, 0xc3, 0x08, 0xbd, 0x29, 0xcb, 0xd9, 0x74, 0xcd, + 0xaf, 0xe4, 0x65, 0xef, 0x46, 0x8c, 0xf9, 0xc5, 0xec, 0x48, 0x33, 0xac, + 0xa4, 0xc8, 0x1d, 0xb7, 0x7c, 0xcc, 0x19, 0x3d, 0x11, 0xbd, 0x7d, 0xb1, + 0xc3, 0xe8, 0xf8, 0xb1, 0x12, 0xc4, 0xad, 0x94, 0xa1, 0xa4, 0xb7, 0x13, + 0xaf, 0x84, 0x74, 0xdf, 0xb7, 0x15, 0xfd, 0xfc, 0x06, 0xfc, 0x18, 0x3f, + 0xe7, 0xb5, 0x82, 0xde, 0x09, 0x3c, 0x96, 0x7e, 0x1d, 0x67, 0x29, 0xab, + 0xda, 0xfb, 0xb1, 0xb5, 0xcc, 0x20, 0x18, 0x14, 0xbb, 0x95, 0xb7, 0xd3, + 0x53, 0x6d, 0xf1, 0x06, 0xac, 0xde, 0x25, 0xf6, 0xa7, 0x07, 0xe3, 0xa0, + 0x7c, 0x66, 0x99, 0x60, 0x9c, 0xc4, 0x1f, 0xca, 0xdf, 0x4c, 0xd9, 0x2c, + 0xfa, 0x07, 0xed, 0xc0, 0x1e, 0xc3, 0x43, 0x36, 0x0e, 0x3a, 0xfb, 0xe4, + 0xc8, 0xeb, 0x39, 0xa2, 0xb4, 0x8e, 0x5e, 0x53, 0x8c, 0x62, 0x5f, 0xce, + 0x0f, 0xb2, 0x6b, 0x0a, 0x17, 0xeb, 0xfe, 0xd2, 0x1a, 0xf1, 0x5e, 0x5a, + 0xb7, 0x8c, 0x39, 0x56, 0x39, 0xc7, 0xf3, 0x5e, 0x6f, 0xdc, 0x2a, 0xce, + 0x8e, 0xa5, 0xe9, 0x55, 0x45, 0x6c, 0x32, 0x48, 0xee, 0xde, 0x89, 0xab, + 0x42, 0x7a, 0xcb, 0xb7, 0x15, 0x29, 0xab, 0x87, 0x37, 0x28, 0xf9, 0x7e, + 0x7e, 0x84, 0xd3, 0x23, 0xd2, 0x87, 0xf4, 0x35, 0xc1, 0x9c, 0xeb, 0x52, + 0x7f, 0x4a, 0xd9, 0xf3, 0xa9, 0x9b, 0x43, 0xe4, 0x75, 0x2b, 0x38, 0xcc, + 0x92, 0x5e, 0x19, 0x93, 0xa9, 0xdc, 0x3b, 0x2a, 0xf3, 0xba, 0x40, 0x59, + 0x4f, 0x2c, 0x29, 0xea, 0xad, 0x57, 0xee, 0x21, 0x96, 0x14, 0xee, 0xac, + 0x51, 0xee, 0xb6, 0x6d, 0xbe, 0x0a, 0x23, 0xfd, 0xd7, 0x28, 0x6d, 0xc3, + 0xa2, 0x03, 0x37, 0xc7, 0x3e, 0x8d, 0x63, 0xf7, 0xa2, 0x8f, 0xfe, 0xfb, + 0x4a, 0x6f, 0x9d, 0x72, 0x1f, 0x7d, 0xa3, 0x73, 0x97, 0x8a, 0xc9, 0x2a, + 0x85, 0x78, 0x47, 0xfe, 0x6b, 0xf8, 0x94, 0xd6, 0xe1, 0xef, 0x3b, 0x25, + 0xbe, 0x64, 0x70, 0x03, 0x5a, 0x79, 0x6f, 0xa9, 0xe9, 0x42, 0x46, 0xab, + 0xd5, 0x34, 0xac, 0xc0, 0xea, 0xe4, 0x2a, 0xb4, 0x25, 0x8b, 0xc9, 0x73, + 0x65, 0xbc, 0x79, 0xb9, 0xf3, 0xf3, 0xf8, 0x20, 0x5a, 0x92, 0x88, 0xcf, + 0x88, 0x04, 0x3a, 0x66, 0x38, 0xe8, 0xd2, 0xc5, 0x75, 0xca, 0xfd, 0xe9, + 0x1a, 0x65, 0xcd, 0xae, 0x72, 0x64, 0xb1, 0xe7, 0x61, 0x34, 0xed, 0xa9, + 0x57, 0xee, 0xde, 0x53, 0x85, 0x49, 0xcd, 0xb2, 0x9c, 0xa1, 0x7a, 0xa5, + 0x75, 0x8f, 0x65, 0xdd, 0x64, 0x46, 0x9b, 0x8a, 0xc9, 0x77, 0xb7, 0xb1, + 0xbd, 0xd6, 0x51, 0xe9, 0xe7, 0xf2, 0x76, 0x4d, 0x65, 0xe3, 0x9e, 0x87, + 0xb1, 0x82, 0x65, 0x5f, 0x09, 0x45, 0x5b, 0x4a, 0x59, 0x56, 0x74, 0xd6, + 0x3a, 0xfa, 0x19, 0xf6, 0x21, 0xe5, 0x17, 0x4c, 0x69, 0x67, 0x31, 0xaf, + 0x49, 0x5b, 0x59, 0xdd, 0x89, 0xde, 0x1e, 0xcf, 0xea, 0x2d, 0x2c, 0x7a, + 0x5b, 0x4e, 0x5d, 0xba, 0x7a, 0x7d, 0x3c, 0x5c, 0xf4, 0x75, 0x1f, 0xd6, + 0xa4, 0x65, 0x4c, 0x33, 0x89, 0x03, 0xcd, 0xb4, 0xdb, 0x76, 0xb4, 0x52, + 0xaf, 0x71, 0x2d, 0x6b, 0x9f, 0x17, 0x7d, 0x4b, 0xf7, 0x4f, 0x72, 0xec, + 0xad, 0x49, 0xd1, 0x4b, 0x33, 0xcb, 0xdb, 0xf7, 0xe9, 0xdb, 0x53, 0xcb, + 0x5c, 0x3a, 0x57, 0xfb, 0x13, 0xc2, 0x27, 0x0a, 0xc8, 0x7d, 0x0a, 0xd8, + 0x5e, 0x96, 0x2b, 0x8a, 0xbd, 0x38, 0x68, 0x2f, 0xcf, 0x98, 0xc5, 0xd8, + 0xe4, 0x95, 0x31, 0x66, 0xf5, 0x0c, 0x15, 0x58, 0xc7, 0x7b, 0x2e, 0xde, + 0x2b, 0x0c, 0x15, 0xe2, 0x2d, 0x5b, 0x57, 0x59, 0x3e, 0x98, 0xf7, 0xf3, + 0xa1, 0x0b, 0xfd, 0x1c, 0xab, 0xce, 0xda, 0xd8, 0x26, 0x57, 0x96, 0x33, + 0xe6, 0xb9, 0x8d, 0x65, 0x0d, 0x98, 0x79, 0x6e, 0x23, 0x71, 0xee, 0x53, + 0xc2, 0x15, 0x6c, 0x1e, 0xd6, 0x96, 0xeb, 0xb7, 0xcb, 0x0c, 0xd0, 0x4f, + 0x85, 0xfb, 0x45, 0x94, 0xb6, 0x3d, 0xa7, 0x68, 0xab, 0x92, 0x8b, 0x01, + 0x1b, 0x79, 0xbf, 0x94, 0xf7, 0x5f, 0x0b, 0xb9, 0x70, 0xd5, 0x34, 0xe9, + 0xfb, 0x06, 0x74, 0xec, 0x8a, 0xa2, 0x7c, 0x61, 0x00, 0x93, 0xf6, 0x7a, + 0x59, 0x9e, 0xa7, 0xbb, 0x70, 0xdf, 0xae, 0x8f, 0xad, 0x32, 0x9b, 0x3b, + 0x1a, 0xb1, 0x71, 0x45, 0xc5, 0x8e, 0x45, 0xc2, 0xd7, 0x5d, 0x8c, 0x57, + 0xe4, 0xce, 0x92, 0x0b, 0xb8, 0x4a, 0xc8, 0xb9, 0x85, 0x73, 0x06, 0x32, + 0xb7, 0xab, 0xd0, 0xb4, 0x88, 0x70, 0xcf, 0x99, 0x36, 0xe7, 0x16, 0xee, + 0xfd, 0xcd, 0xe4, 0xd1, 0x29, 0xdc, 0xfb, 0x02, 0x4f, 0x61, 0xae, 0xd6, + 0x8c, 0x44, 0xaf, 0x07, 0xee, 0x88, 0xde, 0xbc, 0x59, 0xe9, 0xc4, 0xf2, + 0x90, 0x61, 0xca, 0x1a, 0xc0, 0xf5, 0x8a, 0x1e, 0x3c, 0x87, 0x20, 0xe3, + 0xc7, 0x8f, 0x30, 0x32, 0xf8, 0x0f, 0x2e, 0xf1, 0x8b, 0xcd, 0xe9, 0x8b, + 0xf2, 0xdc, 0x4d, 0x79, 0xdc, 0x59, 0x79, 0xcc, 0x73, 0x54, 0xe4, 0xb3, + 0xf5, 0x2e, 0xe2, 0xf0, 0x7f, 0xb7, 0xed, 0x76, 0x89, 0x9d, 0x4b, 0xfc, + 0x77, 0xc6, 0x93, 0x70, 0x71, 0x5e, 0xcf, 0x9d, 0xc4, 0xab, 0x0f, 0x17, + 0x16, 0x21, 0x44, 0x7b, 0xaf, 0x30, 0x3a, 0x98, 0xcf, 0x7f, 0x6c, 0xc5, + 0x9d, 0xa4, 0xdf, 0x06, 0xb4, 0xa2, 0x48, 0x94, 0xb2, 0x35, 0x2a, 0x37, + 0x0d, 0x8f, 0xb3, 0x9f, 0x0e, 0xe6, 0x29, 0x1e, 0x3c, 0x40, 0x5c, 0x79, + 0x80, 0xfe, 0xf4, 0x00, 0x63, 0xf3, 0x03, 0xa3, 0xff, 0x8b, 0xd7, 0xa7, + 0xd9, 0xbf, 0x37, 0x27, 0xf3, 0xf6, 0xe5, 0x64, 0x9c, 0x13, 0xfd, 0x6e, + 0x21, 0x16, 0x48, 0x9c, 0x03, 0x65, 0xb2, 0x70, 0xda, 0x2c, 0xa4, 0xae, + 0xf5, 0x60, 0x06, 0x09, 0xd7, 0xc5, 0x3c, 0x35, 0x1f, 0x2b, 0x65, 0x1e, + 0x5d, 0xb8, 0x87, 0x32, 0x06, 0x43, 0xbf, 0xb1, 0x50, 0x21, 0x58, 0x74, + 0xf9, 0xfd, 0xec, 0xbc, 0x1e, 0xbf, 0xc0, 0x59, 0x15, 0xc9, 0x91, 0xe8, + 0xef, 0xfd, 0x36, 0x07, 0x7b, 0x8d, 0x3e, 0xd9, 0xb6, 0xeb, 0xc4, 0x7c, + 0x31, 0x95, 0x35, 0xa3, 0x51, 0x6c, 0xe2, 0xb8, 0x57, 0x0f, 0x3f, 0x9a, + 0xd3, 0x4b, 0x7e, 0xbc, 0xe2, 0xd3, 0x1e, 0xda, 0x74, 0x36, 0xb7, 0x6a, + 0x1d, 0x15, 0x2e, 0x5e, 0xc9, 0xff, 0xc2, 0xc5, 0xc5, 0x7f, 0x84, 0x97, + 0x4f, 0xe3, 0x7f, 0x27, 0x39, 0xa7, 0x70, 0xe9, 0x3a, 0xf4, 0xd0, 0x8f, + 0x0a, 0x03, 0x75, 0xd8, 0x3a, 0x7a, 0xf9, 0x1c, 0x5d, 0x2e, 0x8f, 0x3d, + 0x07, 0xcc, 0xc3, 0x5c, 0x82, 0xad, 0x7e, 0xbf, 0x2a, 0x7d, 0x5b, 0x68, + 0x37, 0x6f, 0xc8, 0x72, 0xa7, 0x4a, 0xb9, 0x36, 0x95, 0x9f, 0xe7, 0xdb, + 0x99, 0x7a, 0x4d, 0x2d, 0x40, 0x71, 0x9e, 0x37, 0x78, 0x73, 0xb9, 0x0e, + 0xf3, 0x9b, 0xa4, 0xe8, 0x4b, 0xc6, 0x90, 0xcd, 0x5f, 0xc5, 0x5e, 0x2e, + 0xc5, 0x83, 0xf8, 0xb4, 0x22, 0x43, 0x6c, 0x25, 0x48, 0x7f, 0xd6, 0xc3, + 0x4d, 0x0c, 0x35, 0x67, 0x13, 0x88, 0x39, 0x22, 0x4d, 0x8d, 0x6b, 0x12, + 0x73, 0xb5, 0x67, 0x72, 0xf9, 0xf1, 0x7e, 0xc6, 0x1e, 0xd5, 0x90, 0xb5, + 0x19, 0xda, 0xc3, 0xb0, 0xe8, 0xa7, 0x43, 0xb9, 0x98, 0x0b, 0x47, 0xc9, + 0x15, 0x19, 0x57, 0x0d, 0xc9, 0x91, 0x1a, 0x95, 0xa5, 0xc3, 0x52, 0x87, + 0xf6, 0x70, 0x19, 0x67, 0xcc, 0x8e, 0xb7, 0x0c, 0x9e, 0x01, 0xe1, 0x8a, + 0x3a, 0x36, 0x90, 0x9b, 0x94, 0x0c, 0xf8, 0x69, 0xef, 0x95, 0x28, 0xde, + 0x1d, 0xc1, 0xfa, 0x51, 0x0d, 0x45, 0xbb, 0x2d, 0x6b, 0x6e, 0xa8, 0x1b, + 0x6b, 0xd3, 0xcb, 0x0b, 0x24, 0x9f, 0x73, 0xf6, 0x11, 0x2b, 0x88, 0x2b, + 0xeb, 0x92, 0x0a, 0x6e, 0x24, 0x07, 0x88, 0xa2, 0x99, 0xdc, 0x5d, 0xf0, + 0xc5, 0xea, 0x9c, 0x1d, 0x71, 0xd1, 0x4e, 0x56, 0xf1, 0x7e, 0x0b, 0xb1, + 0xa7, 0x85, 0x58, 0x62, 0x59, 0x1f, 0x5e, 0x8b, 0xce, 0x92, 0xc8, 0x1d, + 0xc4, 0xa0, 0x1a, 0xe6, 0x0f, 0xc2, 0x39, 0xae, 0x45, 0x1b, 0xb1, 0xbb, + 0xb0, 0xcf, 0xce, 0xf1, 0xa8, 0x47, 0xc6, 0xd5, 0x34, 0xe3, 0x32, 0x65, + 0x7f, 0x9e, 0x7c, 0xbd, 0x83, 0x7e, 0x54, 0xde, 0xb7, 0x81, 0xf1, 0xd9, + 0x83, 0xb2, 0x81, 0x6b, 0xb0, 0x91, 0xd8, 0x7e, 0xdf, 0x2e, 0x3f, 0x52, + 0x8b, 0x6e, 0xa0, 0x7c, 0x0f, 0x62, 0x7d, 0xd2, 0x90, 0xbc, 0x2e, 0x1a, + 0x5c, 0xf4, 0x20, 0xfb, 0xa5, 0x7d, 0xec, 0x92, 0x1c, 0xb1, 0x04, 0x4b, + 0x9a, 0x81, 0x60, 0x9f, 0x60, 0x8e, 0x8c, 0xff, 0x36, 0x59, 0xcf, 0x82, + 0xd1, 0x37, 0x75, 0x3e, 0xa6, 0x72, 0x39, 0x59, 0x1b, 0x6c, 0xc6, 0x7c, + 0xc6, 0x2f, 0xb1, 0x21, 0x8d, 0x79, 0x6f, 0x91, 0x62, 0xf8, 0xf6, 0xd3, + 0x17, 0x25, 0x17, 0xbb, 0xae, 0x2f, 0x1f, 0xaf, 0xf5, 0xcc, 0x62, 0x47, + 0x27, 0xb1, 0x42, 0x6f, 0xff, 0xad, 0xa2, 0xaf, 0x3b, 0xa5, 0xfc, 0x18, + 0x07, 0xc7, 0x5e, 0xc7, 0xd0, 0x98, 0x5b, 0x19, 0x1d, 0x93, 0xbe, 0x26, + 0xd0, 0x9b, 0xfe, 0x73, 0x7d, 0x4d, 0x5d, 0x13, 0x5a, 0x74, 0xc9, 0x3a, + 0xd2, 0x8d, 0xb9, 0xdc, 0x75, 0xe9, 0x25, 0x9c, 0x5e, 0xe6, 0x44, 0x6c, + 0xcf, 0x8b, 0xee, 0xe4, 0xc5, 0xb5, 0x8a, 0xfe, 0xc4, 0x76, 0xdb, 0x07, + 0x9b, 0xd3, 0x62, 0x93, 0xcc, 0xef, 0xcc, 0x39, 0xf6, 0xb3, 0x1b, 0x59, + 0x5f, 0x58, 0xb3, 0xab, 0xd7, 0xbe, 0x77, 0xd0, 0xfc, 0x2b, 0x64, 0xec, + 0x6b, 0x8b, 0xe9, 0x7f, 0x8c, 0x93, 0xc4, 0xbd, 0x60, 0xc8, 0x87, 0xc2, + 0x0a, 0x59, 0x5b, 0xba, 0xb8, 0x1e, 0xb1, 0x61, 0x17, 0x69, 0x84, 0x8d, + 0x2b, 0x0d, 0xc4, 0xb8, 0x1a, 0xce, 0x77, 0x16, 0x4b, 0xd6, 0xd3, 0x86, + 0x6e, 0x11, 0x1b, 0x72, 0x65, 0x6d, 0xe8, 0x0f, 0xd7, 0x3c, 0x54, 0x90, + 0xaf, 0x6a, 0x65, 0x76, 0x2e, 0xda, 0xa8, 0xdc, 0x9a, 0xb3, 0xab, 0xcf, + 0xa6, 0xbf, 0x53, 0x90, 0xcb, 0x91, 0x2e, 0x2b, 0xff, 0x49, 0x3a, 0xb8, + 0xe6, 0x2f, 0xd0, 0x81, 0x60, 0xbe, 0xe4, 0x31, 0xa2, 0x83, 0x99, 0x53, + 0xfc, 0xf2, 0x93, 0xf4, 0x50, 0x9b, 0xd3, 0xc3, 0x62, 0x62, 0x48, 0x25, + 0x71, 0x4f, 0x38, 0x4b, 0x00, 0x4f, 0x6a, 0x79, 0x3d, 0x38, 0x73, 0x7a, + 0xd0, 0xff, 0x40, 0x0f, 0xf7, 0x13, 0x5f, 0x4b, 0xd9, 0x56, 0x31, 0x8f, + 0x77, 0xa9, 0x87, 0x8d, 0xc3, 0x8b, 0xf1, 0x00, 0x7d, 0x69, 0x83, 0xbd, + 0x5e, 0x23, 0xcf, 0xef, 0x5c, 0x97, 0xe8, 0x66, 0x25, 0xe5, 0xf7, 0x17, + 0xa8, 0x98, 0x41, 0x1d, 0xf8, 0x6c, 0x3c, 0x95, 0x3e, 0x1a, 0x95, 0xdb, + 0x87, 0x05, 0xe3, 0x3e, 0xa6, 0x0e, 0x3a, 0x18, 0x07, 0xfe, 0x54, 0x9e, + 0x21, 0xfd, 0x7f, 0x7c, 0x41, 0x57, 0x7f, 0xbc, 0xdc, 0x8f, 0xa9, 0x03, + 0x79, 0x26, 0x22, 0x6b, 0xec, 0xf2, 0x7c, 0x44, 0xf4, 0x61, 0x4c, 0xd1, + 0x83, 0x65, 0x1d, 0x31, 0xe7, 0x21, 0x56, 0xa9, 0xf7, 0x4b, 0x1c, 0xed, + 0x27, 0xa6, 0x38, 0x98, 0xb7, 0x17, 0x44, 0xa2, 0x14, 0x5b, 0xbd, 0x81, + 0x4c, 0xa7, 0xce, 0x81, 0x4e, 0x9c, 0x31, 0x8d, 0x9e, 0xb5, 0xf8, 0x2b, + 0x74, 0x79, 0x2d, 0x1c, 0x60, 0x3b, 0x9b, 0x92, 0x45, 0x58, 0x57, 0x47, + 0xd3, 0x5c, 0xe9, 0xc1, 0xce, 0x64, 0xbc, 0x85, 0xd0, 0xc2, 0xd8, 0x74, + 0xe6, 0xf6, 0x44, 0x40, 0x6f, 0xde, 0x40, 0xbe, 0xb6, 0xbc, 0xd7, 0x0d, + 0xbf, 0x92, 0x8d, 0xcf, 0x03, 0xaa, 0xac, 0x7f, 0x5e, 0xc9, 0xb1, 0x77, + 0xdb, 0x79, 0xac, 0x7f, 0x9a, 0xf4, 0xe3, 0x47, 0x3c, 0x2d, 0x75, 0xa9, + 0xb3, 0xb9, 0x0a, 0x96, 0xcf, 0xd5, 0xe3, 0x51, 0xc5, 0xb2, 0x16, 0x84, + 0x9c, 0xf6, 0xfd, 0xed, 0xe9, 0xda, 0x96, 0xdb, 0xd4, 0xd7, 0xad, 0xec, + 0x9a, 0xab, 0xae, 0x45, 0x99, 0x0c, 0x1d, 0xff, 0xa3, 0xcf, 0x1d, 0x82, + 0x90, 0xe7, 0x41, 0x6e, 0x63, 0x25, 0x0e, 0xe5, 0xd6, 0x1d, 0x5d, 0x91, + 0xc3, 0x5f, 0x3e, 0x60, 0x48, 0xbe, 0x26, 0x7a, 0x92, 0xfe, 0xc4, 0x9e, + 0x1e, 0x28, 0x14, 0x1c, 0xed, 0x4a, 0x2f, 0xe4, 0x3c, 0xfe, 0x87, 0x35, + 0xea, 0x9d, 0x5a, 0x76, 0x89, 0x9a, 0x7d, 0x8e, 0x20, 0x65, 0xf3, 0xe5, + 0xe6, 0x10, 0x57, 0x1a, 0x30, 0x7c, 0x49, 0x9b, 0x92, 0x6f, 0xe7, 0xdb, + 0xec, 0x2d, 0x14, 0x5e, 0x55, 0x81, 0x42, 0xe2, 0xe3, 0x6f, 0xac, 0x83, + 0x97, 0xb4, 0xb7, 0xd1, 0x95, 0x6d, 0x6f, 0x0f, 0xcb, 0x48, 0xd9, 0x02, + 0xd6, 0x79, 0x37, 0xc7, 0x7f, 0xf3, 0x65, 0x3e, 0x77, 0x59, 0x19, 0x66, + 0x78, 0xc6, 0x5b, 0xd6, 0xfe, 0x4b, 0xca, 0x7c, 0xda, 0x79, 0x69, 0x19, + 0x27, 0x66, 0x1b, 0xaf, 0x5b, 0xc7, 0x2f, 0x29, 0x33, 0x70, 0x59, 0x99, + 0x6b, 0x31, 0x56, 0xf7, 0xb8, 0x35, 0x94, 0x9d, 0x9b, 0x0c, 0x5d, 0xd0, + 0x3d, 0x23, 0xe2, 0xfe, 0xd2, 0x75, 0xf3, 0x74, 0xf2, 0x4d, 0x79, 0x16, + 0xe5, 0x46, 0x26, 0x3b, 0x37, 0x71, 0x99, 0x1b, 0xd7, 0x82, 0xfc, 0xdc, + 0x3c, 0x90, 0xab, 0x9f, 0x6f, 0x37, 0x56, 0x70, 0x69, 0xbb, 0xf9, 0xeb, + 0x8e, 0xcb, 0xe4, 0x9e, 0xb8, 0xac, 0x5c, 0x51, 0xe1, 0x27, 0xd7, 0xfb, + 0x81, 0xe3, 0xd2, 0xeb, 0xff, 0x43, 0xbd, 0xf4, 0xfc, 0x9a, 0xdc, 0x79, + 0x5e, 0xff, 0xd6, 0x65, 0xf7, 0x1d, 0x97, 0x9d, 0x3f, 0xa3, 0x7e, 0x72, + 0x3f, 0xab, 0x2e, 0xeb, 0xc7, 0x5e, 0x83, 0xc7, 0x73, 0x17, 0x70, 0x03, + 0x8d, 0x05, 0x08, 0x98, 0x4e, 0x05, 0x7e, 0xe2, 0x87, 0xff, 0xf9, 0xcb, + 0xd6, 0xe2, 0x1b, 0x2f, 0xe0, 0xc7, 0x25, 0x5c, 0x35, 0x56, 0x18, 0x91, + 0x38, 0x28, 0x3c, 0x55, 0xf8, 0xe2, 0x27, 0xf1, 0xef, 0xb2, 0x58, 0x51, + 0xa4, 0x1e, 0xfe, 0xb1, 0x99, 0xfe, 0xb7, 0x12, 0xb2, 0x1e, 0xfb, 0x7b, + 0x72, 0x2e, 0xc3, 0x77, 0x08, 0x33, 0xfd, 0x3f, 0x4d, 0x95, 0xb8, 0x51, + 0xe6, 0xc1, 0x8d, 0x89, 0x4f, 0xae, 0xa7, 0x46, 0xa0, 0x2c, 0xab, 0xf7, + 0x31, 0xaf, 0x84, 0xf3, 0xa6, 0x79, 0x98, 0xf2, 0xd7, 0x2c, 0x79, 0xae, + 0x7a, 0xb2, 0x3e, 0xcc, 0x18, 0x9f, 0x7d, 0x8e, 0xbc, 0x24, 0xad, 0xfb, + 0xa2, 0x4a, 0xf6, 0x59, 0xf1, 0xba, 0xd0, 0x47, 0xe4, 0x45, 0x9d, 0x94, + 0xcb, 0x62, 0x5f, 0xc0, 0x86, 0x84, 0x65, 0x3d, 0xc7, 0xfc, 0x5c, 0xf6, + 0x20, 0xfc, 0x22, 0xf5, 0x3b, 0x6b, 0xc2, 0xeb, 0xc4, 0xdb, 0xc6, 0xd4, + 0xf6, 0xfc, 0x28, 0x8f, 0x98, 0xcc, 0x13, 0xed, 0x13, 0x75, 0xcc, 0xa8, + 0x6d, 0x3f, 0x40, 0xbf, 0x9b, 0x1f, 0xd0, 0xfd, 0x7d, 0xf8, 0x3f, 0x96, + 0xbf, 0x5a, 0x0f, 0x0e, 0x29, 0xf9, 0xf5, 0xef, 0xcb, 0xd7, 0xb9, 0xcb, + 0x62, 0x2e, 0x8e, 0x6f, 0xbf, 0xbd, 0xd6, 0x5d, 0x40, 0xac, 0x44, 0xcc, + 0x19, 0x99, 0xe9, 0xdf, 0x9a, 0xb0, 0xc7, 0x49, 0x5e, 0xa9, 0xe0, 0x64, + 0xfd, 0x4c, 0xff, 0xa6, 0x94, 0x17, 0x3b, 0x18, 0xd3, 0x8b, 0x8c, 0x7a, + 0x3c, 0x9e, 0x52, 0x71, 0xcf, 0x23, 0x5e, 0xac, 0x21, 0x67, 0x6d, 0xef, + 0xfd, 0x1a, 0x8c, 0xab, 0x9c, 0xb8, 0x9b, 0xf6, 0xb7, 0x96, 0xae, 0x23, + 0xf9, 0xc3, 0xfa, 0x5e, 0x27, 0xea, 0xae, 0x2a, 0x43, 0xbc, 0xba, 0x10, + 0xdf, 0x33, 0x1d, 0xcc, 0xf7, 0x4a, 0x30, 0x64, 0x73, 0x69, 0xc9, 0xe1, + 0x05, 0x13, 0x45, 0x6f, 0x0e, 0x7b, 0xbd, 0xf5, 0x93, 0xe3, 0xc1, 0x7f, + 0x58, 0x99, 0xea, 0x1d, 0x36, 0x8e, 0x3b, 0x22, 0xa6, 0x1d, 0x73, 0x81, + 0x2c, 0x9f, 0xeb, 0xba, 0xe4, 0x79, 0x77, 0xb3, 0x32, 0x3b, 0x12, 0x98, + 0x58, 0xac, 0x38, 0x10, 0x0e, 0x94, 0xc5, 0xca, 0x23, 0x61, 0x2c, 0x4b, + 0x77, 0xf9, 0x7c, 0xf6, 0x33, 0xf4, 0x08, 0xce, 0x2d, 0x32, 0x99, 0xfb, + 0xc3, 0xb9, 0x8c, 0xba, 0x6f, 0xa4, 0x5e, 0xb7, 0x98, 0x1f, 0x59, 0x19, + 0xdb, 0xef, 0xdd, 0x88, 0x31, 0x07, 0x5b, 0x4b, 0xfd, 0x3a, 0xa8, 0xc7, + 0x9f, 0xe7, 0xf4, 0x2b, 0x3a, 0x2d, 0x19, 0xfb, 0x9d, 0x75, 0x92, 0xfa, + 0x75, 0xb3, 0x3d, 0x37, 0xdb, 0x2b, 0x1a, 0xbb, 0x54, 0xcf, 0x85, 0x94, + 0x67, 0x99, 0x2d, 0xc3, 0x42, 0x79, 0x86, 0xe9, 0x8f, 0x2a, 0x32, 0x1e, + 0xc1, 0xf7, 0x3f, 0x37, 0xa6, 0x1f, 0x4f, 0xc9, 0x55, 0x44, 0xff, 0x7e, + 0xea, 0x5f, 0x30, 0x5c, 0xe6, 0xa0, 0x4e, 0xd6, 0xbb, 0x7a, 0x80, 0x97, + 0x98, 0xcc, 0x2a, 0xa8, 0x32, 0x22, 0x78, 0xaa, 0xd9, 0x83, 0xb7, 0x12, + 0xa5, 0xf6, 0xb8, 0xaf, 0x9a, 0x6b, 0x59, 0x4f, 0x86, 0xfc, 0xf8, 0x85, + 0x51, 0x1b, 0x5e, 0xa0, 0xea, 0xcc, 0x1f, 0xbd, 0x48, 0x10, 0x67, 0xbb, + 0x92, 0xb3, 0x38, 0x5f, 0x5e, 0x6c, 0x4d, 0xa2, 0x9d, 0xf6, 0xe4, 0x77, + 0x44, 0x80, 0x33, 0x09, 0x23, 0xb8, 0x85, 0xfd, 0x0f, 0x7b, 0xeb, 0xc9, + 0xd3, 0xd5, 0x46, 0xd2, 0xbd, 0x78, 0x51, 0xc4, 0x88, 0x6f, 0xc3, 0xcf, + 0xac, 0x21, 0xe2, 0x7c, 0x41, 0x48, 0xd6, 0x1c, 0x67, 0xe3, 0x19, 0xcd, + 0x81, 0x17, 0x83, 0xcc, 0x87, 0x2b, 0x1c, 0x28, 0x31, 0xde, 0xb6, 0x7e, + 0xe0, 0x95, 0x7e, 0x64, 0x2c, 0x33, 0x38, 0x0e, 0xc5, 0xc6, 0xc2, 0xad, + 0xc9, 0x7a, 0xea, 0xfb, 0xf2, 0xfe, 0xff, 0x8f, 0x35, 0xe9, 0x95, 0xfe, + 0x75, 0xcd, 0xaf, 0x72, 0x0c, 0x7f, 0x14, 0xbb, 0xbf, 0x6f, 0xbd, 0x64, + 0xb7, 0x79, 0xbb, 0x3b, 0x1b, 0x4f, 0xa5, 0xbd, 0xb7, 0x38, 0x3e, 0x69, + 0x33, 0xdf, 0x8f, 0xe8, 0xed, 0x8c, 0x5b, 0xfc, 0x79, 0x6b, 0x52, 0xf4, + 0x27, 0x78, 0x75, 0xd2, 0xc2, 0x34, 0x39, 0x7f, 0xd6, 0x2e, 0x1b, 0xa7, + 0xbe, 0xba, 0x68, 0x43, 0x8c, 0xe1, 0x3e, 0xd8, 0xbb, 0x3b, 0x34, 0x3b, + 0x9f, 0xdb, 0xcc, 0x1c, 0x60, 0xc8, 0x5b, 0x8e, 0xad, 0x26, 0xed, 0xce, + 0x50, 0xe7, 0x38, 0x61, 0xe1, 0xa4, 0x29, 0xe7, 0x2e, 0x4c, 0x7a, 0x1d, + 0xd8, 0x66, 0x3a, 0xb1, 0xce, 0x50, 0x75, 0xb9, 0xee, 0x08, 0xc9, 0xb9, + 0x0b, 0xfe, 0x6a, 0x05, 0x3b, 0x18, 0x3e, 0xd6, 0x1b, 0x5d, 0x7e, 0xb9, + 0xbe, 0x24, 0x24, 0xe7, 0x0a, 0xda, 0xa8, 0x93, 0xb8, 0xa6, 0x60, 0x83, + 0x21, 0xcf, 0x4d, 0xb3, 0xfc, 0x39, 0x06, 0xcb, 0xda, 0x61, 0x36, 0x5c, + 0x57, 0xc2, 0x72, 0x67, 0x4d, 0xe1, 0x83, 0x87, 0xef, 0x98, 0x1f, 0x88, + 0x47, 0x0b, 0xa0, 0xc7, 0x8a, 0xe8, 0xa7, 0x5b, 0x7b, 0x67, 0xb3, 0x9e, + 0x42, 0x6e, 0xe0, 0xf4, 0x6d, 0x87, 0xc4, 0xcf, 0x80, 0xff, 0xa7, 0x4c, + 0xb2, 0x86, 0xbc, 0xf3, 0xa8, 0x59, 0xc3, 0x7f, 0x9a, 0xf3, 0x56, 0x6e, + 0x38, 0xdb, 0x5f, 0x85, 0xbe, 0xae, 0x48, 0x99, 0x17, 0x2c, 0x63, 0xae, + 0x10, 0x27, 0xbe, 0x8f, 0x8c, 0x39, 0xb1, 0x25, 0x69, 0x68, 0x07, 0x6d, + 0xfe, 0xe7, 0xa4, 0x2e, 0x9c, 0xcc, 0xcf, 0x03, 0xda, 0x84, 0x92, 0x3f, + 0x9f, 0x2d, 0xd8, 0x40, 0x3e, 0x2f, 0xf8, 0x16, 0xb7, 0x9e, 0xad, 0x17, + 0xaa, 0xe1, 0xf6, 0xc7, 0x52, 0x1e, 0x1e, 0x1a, 0x0f, 0xaf, 0x7f, 0x4d, + 0xca, 0xe7, 0x6f, 0x4b, 0xc1, 0xdf, 0x9a, 0xca, 0xdb, 0x65, 0xde, 0xb7, + 0x05, 0xdb, 0x2c, 0x72, 0xd6, 0x6c, 0x6e, 0xd6, 0x25, 0xb9, 0x0f, 0xe4, + 0xb9, 0xdf, 0xe1, 0x3b, 0x9e, 0xa3, 0xad, 0xbb, 0x98, 0x0f, 0x6c, 0x33, + 0xe2, 0x51, 0x79, 0x0e, 0x69, 0x84, 0x74, 0x5f, 0x81, 0xe2, 0xc7, 0xd6, + 0xba, 0xdf, 0x72, 0x3e, 0xc9, 0x93, 0x53, 0x9f, 0x29, 0xca, 0xce, 0x87, + 0xf8, 0x99, 0x60, 0x80, 0x9f, 0xf9, 0x92, 0xcf, 0xdf, 0xc5, 0x7e, 0x36, + 0xa7, 0xa6, 0xfa, 0x80, 0x82, 0x9b, 0xd8, 0x56, 0x43, 0x08, 0xce, 0xa5, + 0x75, 0xbf, 0xb1, 0x32, 0xde, 0xec, 0x33, 0xc8, 0x2c, 0xe6, 0x81, 0x36, + 0x67, 0xf7, 0xe9, 0xdc, 0x5f, 0x27, 0xfb, 0x8e, 0x14, 0x0c, 0xd3, 0xa7, + 0x36, 0xa5, 0xc5, 0x9e, 0xb2, 0x7a, 0x8d, 0xff, 0x01, 0xfe, 0x98, 0xb8, + 0x37, 0x89, 0x58, 0x41, 0x44, 0xf0, 0xc7, 0xed, 0x7f, 0x29, 0x55, 0x47, + 0x0e, 0x2f, 0xcf, 0xf2, 0xdd, 0x9c, 0x67, 0x8f, 0xff, 0xc5, 0xd4, 0xf5, + 0xb8, 0x67, 0x4f, 0x18, 0xeb, 0xf6, 0xa0, 0xae, 0x88, 0x72, 0x17, 0x86, + 0x02, 0xfe, 0x51, 0x68, 0xfe, 0x67, 0xa8, 0x87, 0x13, 0x94, 0xed, 0xe4, + 0x25, 0xb2, 0x89, 0xde, 0xe0, 0xbf, 0x2f, 0xe1, 0x46, 0x2a, 0xf4, 0xa1, + 0x15, 0xb7, 0x79, 0x86, 0xd7, 0xbf, 0x31, 0xe1, 0x47, 0xc6, 0xe6, 0xac, + 0xae, 0x22, 0xc9, 0x1f, 0xbb, 0x93, 0xf1, 0x28, 0xd3, 0xe1, 0xdc, 0x9c, + 0xea, 0x61, 0x99, 0xcf, 0x33, 0x09, 0xb9, 0x17, 0xfd, 0x9a, 0x0a, 0xdd, + 0xaf, 0x32, 0x7e, 0xf6, 0x9b, 0x62, 0xb3, 0x35, 0xa2, 0x93, 0x20, 0x2b, + 0xc6, 0x3d, 0x91, 0x40, 0x4b, 0x1d, 0xaf, 0x6b, 0x0b, 0x10, 0xab, 0x88, + 0x08, 0x27, 0xf4, 0xfa, 0x6b, 0xc7, 0x7d, 0x7e, 0x73, 0x1c, 0xfe, 0x2b, + 0xc7, 0xa7, 0x8a, 0x40, 0x6e, 0xff, 0x89, 0xb9, 0x9f, 0xd7, 0xbf, 0x36, + 0x31, 0x1b, 0x6a, 0x24, 0x6e, 0x2d, 0xa9, 0x3f, 0x67, 0xcd, 0x8e, 0x18, + 0x99, 0x93, 0x94, 0xe1, 0xc3, 0x6b, 0xf5, 0xf8, 0x0c, 0xc7, 0x89, 0x87, + 0xb4, 0x29, 0x7d, 0xbc, 0x1f, 0xfa, 0xff, 0xdb, 0x47, 0x3e, 0xb6, 0x89, + 0xfc, 0x12, 0xdf, 0x72, 0x73, 0xaa, 0xe6, 0xc7, 0xa2, 0x70, 0x4e, 0x39, + 0x1f, 0xc9, 0x7c, 0xac, 0xb2, 0xac, 0x56, 0xc3, 0x97, 0x7b, 0xfe, 0x07, + 0xda, 0xcb, 0x89, 0xeb, 0x9c, 0x58, 0x4c, 0x7b, 0x6f, 0xf8, 0x6b, 0x27, + 0xa2, 0xbe, 0x42, 0xc6, 0x50, 0xd9, 0x53, 0xf0, 0x4c, 0xdd, 0xa4, 0x35, + 0x61, 0xd4, 0xa1, 0x21, 0x2d, 0xcf, 0x63, 0x1d, 0xb4, 0x63, 0x0b, 0x8f, + 0x9b, 0x72, 0x5f, 0xf0, 0x24, 0x1e, 0x73, 0xd0, 0x26, 0xdc, 0x86, 0xde, + 0xf2, 0x0f, 0x4a, 0x19, 0x8a, 0x23, 0xce, 0xe0, 0x04, 0xf4, 0xf0, 0x7a, + 0x72, 0x63, 0x7f, 0xc5, 0x3c, 0x53, 0xd4, 0xfe, 0x4e, 0x22, 0x60, 0x06, + 0x72, 0xf1, 0xe7, 0x2c, 0xe7, 0xeb, 0xdd, 0x84, 0xb1, 0xee, 0xb9, 0xdc, + 0xf9, 0xbf, 0xa5, 0xa6, 0xe6, 0xbf, 0x62, 0x77, 0x6e, 0xf7, 0xe6, 0x04, + 0xde, 0x77, 0xd4, 0xe3, 0xfd, 0xfd, 0x66, 0x01, 0xf3, 0x36, 0xb1, 0x47, + 0xb7, 0x7b, 0x6b, 0x02, 0x93, 0x4e, 0x5e, 0x3b, 0x6b, 0xce, 0x22, 0x76, + 0xa9, 0xbc, 0x16, 0x96, 0x58, 0x10, 0xd3, 0x18, 0x47, 0x8b, 0x23, 0x5e, + 0x77, 0xf1, 0x38, 0xb4, 0x22, 0xa3, 0x8c, 0x79, 0x31, 0x1a, 0x1d, 0x7d, + 0xba, 0xbf, 0xc9, 0x51, 0xc7, 0xfc, 0xd8, 0xaf, 0xb8, 0x8c, 0x6f, 0x31, + 0xcf, 0x97, 0xf5, 0xaa, 0x30, 0xc7, 0xed, 0x64, 0x85, 0x9d, 0xd3, 0xd4, + 0x88, 0x42, 0xcc, 0x2b, 0xc3, 0xbd, 0xda, 0x86, 0xc5, 0x6a, 0xa4, 0x1f, + 0xb7, 0xd6, 0xbb, 0x1b, 0xcb, 0xc7, 0xf3, 0x3a, 0x41, 0xcc, 0x13, 0x61, + 0x0e, 0x63, 0x40, 0x2d, 0x8d, 0x88, 0x6e, 0xfc, 0x8d, 0x7d, 0x63, 0x22, + 0xab, 0xe6, 0xee, 0x1d, 0xf3, 0x14, 0xa3, 0x38, 0x4c, 0x4c, 0xfa, 0x57, + 0xdf, 0x7f, 0xae, 0xde, 0x64, 0x91, 0xe0, 0xba, 0xcb, 0x90, 0xff, 0xb6, + 0x3d, 0xb9, 0xdd, 0x91, 0x63, 0x31, 0x77, 0xc0, 0xb2, 0x18, 0x0f, 0x7d, + 0x50, 0x66, 0x71, 0x3c, 0xf4, 0x29, 0xce, 0x4d, 0x5b, 0xea, 0x23, 0xeb, + 0x33, 0x4e, 0x3b, 0xd6, 0xbb, 0x0b, 0x23, 0xe1, 0xbb, 0xde, 0x36, 0x7e, + 0x6f, 0xbd, 0x95, 0x60, 0x5e, 0x4d, 0xdf, 0x2d, 0x20, 0x6e, 0x6f, 0x37, + 0x9d, 0x4d, 0x4b, 0x15, 0x05, 0xdd, 0xc6, 0x3c, 0xad, 0x88, 0xf1, 0x68, + 0x13, 0xfd, 0x37, 0xe6, 0x35, 0x82, 0xfb, 0xc1, 0x72, 0xa9, 0xb5, 0x6b, + 0x5d, 0x91, 0x8d, 0x77, 0x8d, 0xd4, 0x8b, 0xcf, 0x9f, 0xbf, 0xeb, 0x39, + 0xa3, 0x19, 0xdd, 0xe9, 0x41, 0xf4, 0xa4, 0xb3, 0xfd, 0x64, 0x30, 0xfb, + 0x13, 0xfa, 0x59, 0xbb, 0xb6, 0x30, 0x22, 0x1c, 0xeb, 0xe8, 0x5d, 0x07, + 0x8c, 0x28, 0xb6, 0xa4, 0x37, 0xde, 0x75, 0xb6, 0xbe, 0x9f, 0xff, 0xb3, + 0x75, 0x86, 0x50, 0xfe, 0x89, 0x75, 0x4a, 0x22, 0xd2, 0x47, 0x98, 0x7d, + 0x6c, 0xbc, 0x6b, 0xdd, 0xa2, 0xaf, 0x63, 0x73, 0x7a, 0xdd, 0x9f, 0xed, + 0xa7, 0x94, 0x75, 0x8a, 0x23, 0x1d, 0xad, 0x37, 0x05, 0x36, 0xde, 0x95, + 0x5a, 0xd4, 0xc3, 0x3e, 0x56, 0x31, 0x8e, 0x64, 0xeb, 0x44, 0x15, 0xc7, + 0x27, 0xea, 0xa0, 0x28, 0xd2, 0xd3, 0x3a, 0x3f, 0xf0, 0x7b, 0x6b, 0x5e, + 0x6f, 0x81, 0xad, 0x03, 0x17, 0x75, 0xf0, 0xa8, 0xe9, 0xcc, 0x04, 0x1c, + 0xb6, 0x0e, 0x3a, 0x7c, 0xd4, 0x41, 0x1f, 0x75, 0x90, 0xa9, 0x36, 0xc2, + 0xef, 0x51, 0x07, 0xf3, 0xc6, 0xd6, 0xae, 0x2d, 0x8a, 0xc0, 0xe9, 0x30, + 0x5e, 0x77, 0x38, 0x39, 0x17, 0x2e, 0x63, 0x2d, 0xf5, 0xb6, 0xf1, 0xae, + 0x39, 0x8b, 0x6c, 0x9d, 0x7f, 0xd9, 0x1d, 0xd8, 0x60, 0xef, 0xdd, 0xdb, + 0x94, 0x6e, 0xe3, 0xd1, 0xc4, 0xe3, 0x61, 0x1e, 0xdd, 0xcc, 0x4d, 0xee, + 0xa0, 0xae, 0x1a, 0x39, 0x8e, 0x15, 0x94, 0xab, 0x9d, 0xbf, 0x5b, 0xf8, + 0xbb, 0x83, 0xbf, 0x65, 0x7e, 0xd4, 0x0b, 0xb2, 0xc5, 0x2e, 0xc8, 0xe6, + 0xa0, 0x3c, 0x1e, 0x62, 0x94, 0x8c, 0x69, 0xe2, 0xcb, 0x37, 0x05, 0x62, + 0x6c, 0xe3, 0xa9, 0x62, 0xd9, 0xf7, 0xe4, 0x32, 0xe2, 0x3e, 0x27, 0x44, + 0x3e, 0xbd, 0x65, 0x1d, 0x32, 0xc4, 0xd8, 0xdf, 0x65, 0x31, 0x96, 0xb2, + 0x95, 0x71, 0x7e, 0x5e, 0x59, 0x34, 0x34, 0xdd, 0x63, 0xc0, 0xe7, 0x36, + 0xe2, 0xe8, 0x4d, 0x27, 0xa8, 0x03, 0xb1, 0x93, 0x07, 0xa9, 0xbf, 0x4e, + 0x74, 0x19, 0x27, 0xf4, 0xec, 0xde, 0x89, 0xbd, 0x94, 0x21, 0x48, 0x7e, + 0xe8, 0x81, 0x33, 0xa2, 0xfb, 0x1b, 0x1d, 0x5d, 0x41, 0x17, 0x68, 0xcb, + 0xc5, 0x62, 0xcb, 0x71, 0xc6, 0x35, 0xc1, 0x3a, 0xb7, 0xd6, 0x66, 0xe3, + 0x5f, 0x7c, 0xbe, 0x0b, 0x1e, 0x6d, 0x4d, 0x2a, 0x1f, 0x0b, 0x3c, 0x5a, + 0x6b, 0x42, 0xfc, 0x4a, 0xd6, 0xfc, 0xc3, 0x76, 0x2c, 0x3f, 0x9e, 0x7e, + 0xb1, 0x18, 0x65, 0xb6, 0x8f, 0x95, 0x39, 0x8d, 0x6c, 0xbb, 0x1a, 0xdb, + 0x6d, 0x76, 0x68, 0xb8, 0xe8, 0x23, 0xba, 0xd6, 0xec, 0x90, 0x7d, 0xae, + 0xf4, 0xfe, 0x54, 0xae, 0x5e, 0x16, 0x27, 0x16, 0xbb, 0x6c, 0x9c, 0x60, + 0x1b, 0xc5, 0xc0, 0x92, 0xc4, 0xe5, 0xfd, 0x4b, 0x7f, 0xd2, 0x6f, 0x57, + 0x85, 0x8a, 0x09, 0xfb, 0x99, 0xcb, 0x91, 0x74, 0x0c, 0x83, 0xc9, 0xa9, + 0x7b, 0xf9, 0xf4, 0xa3, 0x6c, 0xff, 0x70, 0x9c, 0xfa, 0x98, 0x65, 0xc8, + 0x3e, 0x3f, 0xd9, 0xdb, 0x37, 0x75, 0x5f, 0x9f, 0xc8, 0x56, 0x58, 0x42, + 0x00, 0xc1, 0x01, 0xe2, 0x4c, 0xb4, 0x59, 0xea, 0x5b, 0xd6, 0x1b, 0xf3, + 0x82, 0xc8, 0x54, 0x39, 0x31, 0x38, 0x17, 0x18, 0xe8, 0x93, 0x7d, 0x57, + 0x47, 0x63, 0xab, 0x99, 0x97, 0x45, 0x2b, 0x6b, 0xb5, 0x4d, 0xaa, 0xec, + 0x99, 0x3a, 0xf6, 0xe5, 0x6e, 0xa3, 0x46, 0xeb, 0x56, 0x33, 0x87, 0x88, + 0xdd, 0x7b, 0x81, 0x69, 0x25, 0xe2, 0x6b, 0x15, 0x46, 0xb4, 0xa7, 0x02, + 0x73, 0xe1, 0xaf, 0xb4, 0xf1, 0x32, 0xfe, 0x94, 0x6a, 0x04, 0x57, 0xda, + 0x38, 0xf8, 0xa1, 0x35, 0xc4, 0xb8, 0xf4, 0x95, 0xb9, 0x3f, 0x28, 0xce, + 0xe6, 0xd9, 0xd1, 0x75, 0xd3, 0x38, 0x57, 0xbf, 0x58, 0xa0, 0xfb, 0x53, + 0x8a, 0xe8, 0x48, 0xb8, 0x49, 0x02, 0xdb, 0xc8, 0x75, 0x7f, 0x33, 0x37, + 0x82, 0x83, 0xfc, 0xff, 0xf3, 0xeb, 0x65, 0x0f, 0xaa, 0x65, 0x05, 0x03, + 0xf3, 0xc2, 0x15, 0x1c, 0xc3, 0x8b, 0xbc, 0xdf, 0x93, 0x7e, 0xdb, 0x3a, + 0x3b, 0xcd, 0xe8, 0x5f, 0xc6, 0x40, 0x32, 0x30, 0xae, 0x6b, 0x93, 0xea, + 0x7f, 0x76, 0x4f, 0x1d, 0xdc, 0x65, 0x1c, 0xcb, 0xf7, 0x02, 0xb5, 0x5a, + 0x9f, 0xaa, 0x96, 0x88, 0x5e, 0x07, 0xc6, 0x7f, 0x3c, 0x65, 0xaf, 0x47, + 0x9e, 0x1f, 0xda, 0x6b, 0x1d, 0x3d, 0x43, 0xf4, 0xa9, 0x21, 0x2d, 0x1a, + 0xa7, 0xde, 0xdd, 0x55, 0x1c, 0xf3, 0x57, 0xe6, 0xde, 0x6a, 0x8f, 0xb3, + 0xd2, 0x98, 0xc1, 0x31, 0x2a, 0xd0, 0xe6, 0xfe, 0x2c, 0xb7, 0xee, 0xd9, + 0x40, 0x36, 0x33, 0x64, 0x35, 0xd2, 0x06, 0x0b, 0x58, 0xe7, 0x46, 0x73, + 0xdf, 0xf4, 0xae, 0x3a, 0xdd, 0xf7, 0x15, 0xc6, 0xce, 0xd0, 0xdc, 0x5f, + 0x5b, 0x51, 0xcd, 0x69, 0x7e, 0x93, 0xa3, 0xbe, 0x27, 0x21, 0x65, 0x65, + 0x5e, 0x8d, 0xe8, 0x5c, 0xe5, 0x5d, 0x0b, 0xd5, 0x81, 0xf0, 0x5c, 0x7b, + 0xfc, 0xc0, 0xdd, 0xa9, 0x04, 0xb6, 0x27, 0xa5, 0x4d, 0x05, 0xcb, 0x02, + 0xef, 0x58, 0xfe, 0x69, 0x09, 0x6c, 0x4d, 0xff, 0x29, 0xae, 0x37, 0x28, + 0x71, 0xbf, 0x25, 0x0e, 0x3d, 0x9a, 0x7d, 0xc6, 0x35, 0x5b, 0xd6, 0x94, + 0x65, 0x0f, 0xd2, 0x5d, 0x89, 0x00, 0xdc, 0xa5, 0xc4, 0xba, 0xb1, 0x80, + 0x3c, 0x13, 0xf5, 0x22, 0xd3, 0x2c, 0x65, 0x6a, 0xb4, 0x31, 0x64, 0xc8, + 0xc4, 0x64, 0x7d, 0xb2, 0xa7, 0x24, 0xbb, 0x9f, 0x82, 0x86, 0x57, 0xad, + 0x6b, 0x67, 0xc8, 0x9d, 0x9a, 0x0c, 0x69, 0x43, 0xc1, 0xfc, 0x40, 0x15, + 0x6a, 0x57, 0xbe, 0xfe, 0x66, 0x41, 0xa0, 0x80, 0xb8, 0x2d, 0xfe, 0x64, + 0xb4, 0x9f, 0xc4, 0xbf, 0xd3, 0xd7, 0x65, 0x6f, 0xd9, 0x16, 0xa9, 0xc7, + 0xb6, 0xe6, 0x22, 0xa5, 0x39, 0xc9, 0x33, 0x64, 0x9f, 0xb2, 0x65, 0xdd, + 0x14, 0x78, 0xcb, 0x8a, 0x56, 0x53, 0x1e, 0xf2, 0x9f, 0x6c, 0x5d, 0x29, + 0x93, 0xdb, 0x33, 0xa4, 0x34, 0xdc, 0x25, 0x3a, 0x79, 0xd6, 0x8c, 0x93, + 0x5d, 0x0b, 0xbe, 0x1e, 0x8b, 0xbd, 0x6d, 0x28, 0xf6, 0xb3, 0xca, 0x65, + 0x4a, 0x39, 0xe3, 0x95, 0xd3, 0x3f, 0x62, 0xe7, 0xdf, 0x61, 0x62, 0xa1, + 0xf0, 0x35, 0xc9, 0xa1, 0x9c, 0x78, 0xce, 0xa8, 0xc0, 0xb3, 0x5a, 0x96, + 0xfb, 0x10, 0x53, 0xf0, 0x6a, 0x62, 0x5e, 0x86, 0x1e, 0x42, 0x0e, 0x69, + 0xac, 0x3b, 0xaf, 0xfc, 0x3b, 0xf3, 0x2b, 0xe0, 0x95, 0x54, 0x3b, 0x1e, + 0x95, 0x75, 0x3d, 0xa5, 0xa6, 0xa9, 0xd6, 0x21, 0xfd, 0xb5, 0x63, 0x5b, + 0x5a, 0xda, 0x3a, 0x16, 0x3b, 0x60, 0xf4, 0xe7, 0x64, 0x15, 0xcc, 0x3c, + 0x16, 0x7b, 0xce, 0x78, 0xdc, 0x9e, 0x3b, 0x79, 0x7e, 0xd6, 0x63, 0x0a, + 0xb6, 0x14, 0x43, 0x25, 0x0f, 0x77, 0x18, 0x77, 0xc0, 0x51, 0xf1, 0x75, + 0xda, 0x9e, 0xec, 0xbf, 0xb9, 0x13, 0xce, 0x0a, 0x17, 0x7d, 0xf3, 0x6e, + 0xb8, 0x2a, 0x84, 0xfb, 0xe6, 0x79, 0x69, 0x94, 0xf7, 0x45, 0xb7, 0xe7, + 0x6d, 0xdd, 0x3a, 0x89, 0xa7, 0xdd, 0x92, 0x27, 0x19, 0xe5, 0xd4, 0x91, + 0xde, 0x42, 0x8e, 0x8c, 0x52, 0x62, 0x13, 0xe3, 0x90, 0xbb, 0x9c, 0x65, + 0xde, 0xa3, 0xde, 0xe7, 0xf5, 0x96, 0x90, 0x13, 0x5b, 0xd6, 0x87, 0xe4, + 0xc4, 0xf3, 0x03, 0xb5, 0x19, 0x83, 0xf1, 0x03, 0xb7, 0xe9, 0x4d, 0x71, + 0xe6, 0x88, 0xab, 0x8d, 0xf3, 0x56, 0x6c, 0x95, 0x94, 0xd1, 0x7d, 0x31, + 0x25, 0xdf, 0xc7, 0x02, 0xf8, 0xab, 0x2c, 0xb8, 0x22, 0xb2, 0x96, 0x2f, + 0x6b, 0xb8, 0x0d, 0xf2, 0xcc, 0xb0, 0x59, 0xc6, 0xef, 0x92, 0x75, 0x41, + 0x44, 0x27, 0x5c, 0x30, 0x32, 0x07, 0x65, 0xce, 0xa6, 0x5b, 0x08, 0x2c, + 0xfc, 0x1d, 0x73, 0x0b, 0x99, 0x9f, 0x9a, 0x4c, 0x9d, 0x92, 0x09, 0xfa, + 0xc8, 0x91, 0x9f, 0x80, 0xde, 0x9c, 0xa0, 0xae, 0x1b, 0x43, 0xb2, 0x0f, + 0xc0, 0xe9, 0x4b, 0xc0, 0xe6, 0xc5, 0xe6, 0x69, 0x7c, 0x06, 0xa5, 0xcc, + 0x05, 0xe7, 0x8e, 0xad, 0x40, 0x59, 0x45, 0xd4, 0x57, 0x8c, 0x6b, 0x78, + 0xde, 0x46, 0xbe, 0xff, 0x05, 0x94, 0xad, 0x6c, 0x41, 0x82, 0x63, 0x2f, + 0x35, 0xbe, 0xc4, 0x6b, 0x0f, 0xa3, 0x2f, 0xe9, 0xe2, 0x38, 0xfe, 0xd5, + 0x2a, 0xab, 0x16, 0xd9, 0x4c, 0x6f, 0x09, 0xf3, 0xf4, 0xa8, 0xad, 0x0b, + 0x62, 0x63, 0x52, 0xb8, 0x48, 0x6d, 0x74, 0x3d, 0x98, 0x2b, 0x57, 0xeb, + 0x2d, 0x6d, 0x4a, 0x07, 0x6d, 0xb6, 0x9b, 0x3a, 0x97, 0xb2, 0x96, 0xb5, + 0x3c, 0x30, 0x49, 0x1d, 0x77, 0xf0, 0xdc, 0xf0, 0xbf, 0x05, 0xf5, 0x9a, + 0x42, 0x9c, 0xb2, 0xe2, 0x9a, 0x8f, 0x76, 0xa9, 0xae, 0x12, 0xde, 0xb2, + 0x34, 0x74, 0xae, 0x44, 0xf6, 0x21, 0x67, 0xed, 0xf4, 0x68, 0x4e, 0x97, + 0xe7, 0xef, 0xea, 0x36, 0x5e, 0xb5, 0xaf, 0x3b, 0xec, 0xeb, 0xe1, 0xdc, + 0xf5, 0xa3, 0xbc, 0xfe, 0x3d, 0x5e, 0xef, 0xa1, 0xee, 0xd5, 0x2b, 0xa4, + 0xfe, 0x5a, 0x53, 0xea, 0x33, 0x45, 0x31, 0xba, 0x73, 0xf3, 0xd1, 0xd1, + 0x9a, 0x2d, 0xdb, 0xd3, 0x9a, 0x6d, 0xc3, 0xc9, 0x36, 0xe2, 0xd1, 0x62, + 0x98, 0x28, 0x61, 0x9c, 0x3f, 0x6b, 0x88, 0x5c, 0x9c, 0xbb, 0xb4, 0xc8, + 0xd5, 0xc6, 0xb8, 0xd2, 0xf5, 0x42, 0x31, 0xe2, 0x1d, 0x33, 0x6c, 0x3b, + 0x3c, 0x7a, 0x97, 0xec, 0x8f, 0x7b, 0x5b, 0x69, 0xf0, 0xc9, 0xb6, 0xca, + 0x24, 0x79, 0xe2, 0x43, 0xa6, 0x33, 0x5c, 0xe7, 0x98, 0x97, 0x29, 0x84, + 0x11, 0x3b, 0xaf, 0x7c, 0x64, 0xe3, 0x43, 0x22, 0xd5, 0xc0, 0x4c, 0x26, + 0x1e, 0x64, 0x0e, 0x12, 0x4c, 0x53, 0xb7, 0xad, 0x44, 0xec, 0xa3, 0xf6, + 0x1e, 0x39, 0xe7, 0xc4, 0x0a, 0x34, 0xe8, 0x0e, 0xcc, 0x0b, 0xcf, 0x60, + 0x26, 0x43, 0xbb, 0x34, 0x0b, 0x1d, 0xba, 0xff, 0x56, 0x7c, 0xc6, 0x23, + 0xf5, 0x0e, 0xa6, 0x32, 0xeb, 0x8a, 0x39, 0xa7, 0xdf, 0xa0, 0x1c, 0xdb, + 0x03, 0x22, 0xc7, 0xd7, 0x73, 0x72, 0xb4, 0x30, 0x66, 0x99, 0xda, 0xcd, + 0x81, 0x9e, 0x0b, 0x7a, 0x7b, 0xc1, 0xd6, 0xdb, 0xc3, 0x3c, 0x2f, 0x64, + 0xbe, 0x5c, 0x80, 0x13, 0x75, 0xde, 0xdc, 0x7e, 0x37, 0xc9, 0x7d, 0x04, + 0x7f, 0xcf, 0x7c, 0x69, 0xb5, 0xa1, 0x87, 0x1d, 0x36, 0x67, 0x76, 0x23, + 0x6e, 0xf3, 0x51, 0x79, 0x76, 0x5e, 0x86, 0xc7, 0xed, 0x72, 0x2e, 0xea, + 0xa4, 0x04, 0x4f, 0xe4, 0xfc, 0x45, 0xf6, 0x2e, 0x7c, 0xc3, 0xfe, 0xbd, + 0x97, 0x73, 0xeb, 0xa2, 0xaf, 0xe6, 0x63, 0x94, 0xac, 0x81, 0x6f, 0xb4, + 0x7d, 0x7f, 0x08, 0xc7, 0xec, 0xff, 0x99, 0x6c, 0xfe, 0x82, 0x6e, 0x53, + 0xf6, 0xfc, 0x94, 0x60, 0x93, 0x3c, 0x8b, 0x4c, 0x4b, 0x4e, 0x7d, 0x3d, + 0xb6, 0x70, 0x54, 0x6e, 0x83, 0x1c, 0x43, 0x13, 0x9b, 0xe8, 0x44, 0x9f, + 0x66, 0x7a, 0xd3, 0x75, 0x53, 0x73, 0x0f, 0x13, 0xfb, 0xeb, 0x7e, 0x6f, + 0x45, 0xed, 0x7c, 0xe4, 0x94, 0x75, 0xc0, 0x38, 0x11, 0xa2, 0x07, 0xaf, + 0x2b, 0xb0, 0xf5, 0x7b, 0xfe, 0x2e, 0x7b, 0x9f, 0x20, 0x65, 0x7e, 0x21, + 0x21, 0x71, 0x74, 0x36, 0x52, 0xa6, 0xc8, 0xe6, 0x6c, 0xde, 0xc1, 0x39, + 0xe9, 0x4e, 0x06, 0xa2, 0x57, 0xf2, 0xde, 0x04, 0x63, 0xd9, 0x26, 0xea, + 0x33, 0xd6, 0x2c, 0x3c, 0xa8, 0x0d, 0x7b, 0x69, 0x63, 0xe3, 0xa6, 0x65, + 0x1d, 0x24, 0x46, 0x94, 0xcf, 0x53, 0x91, 0xa9, 0x6e, 0x43, 0x92, 0xb1, + 0xe9, 0xa0, 0xd1, 0xf0, 0x99, 0x02, 0xc4, 0xfd, 0x6e, 0xe8, 0xbe, 0xad, + 0x1c, 0xcd, 0x43, 0x9c, 0xaf, 0x13, 0xa6, 0xf0, 0x33, 0xe7, 0xf9, 0xa5, + 0x30, 0xc2, 0x8b, 0x1d, 0xff, 0x6a, 0x4d, 0xda, 0xcf, 0x51, 0xbb, 0xfe, + 0x27, 0x65, 0x68, 0x17, 0xe7, 0x2d, 0xe7, 0x1c, 0xbf, 0x17, 0x90, 0xe7, + 0xe0, 0x40, 0x6d, 0x6f, 0xc3, 0x3a, 0x91, 0xe1, 0x40, 0xc8, 0x19, 0x3b, + 0x88, 0x40, 0xf3, 0x06, 0xe5, 0x22, 0x07, 0xbf, 0x72, 0xcc, 0xc4, 0x68, + 0xdd, 0x8b, 0xe4, 0x0b, 0x52, 0xbf, 0x10, 0x4f, 0x9b, 0xcf, 0x5b, 0x35, + 0xd3, 0xbf, 0x67, 0x1d, 0x32, 0xd4, 0xf5, 0xd4, 0x76, 0xac, 0x94, 0x6d, + 0x95, 0xb0, 0xad, 0x7b, 0x03, 0xba, 0xb9, 0x83, 0x6d, 0x3d, 0x93, 0x38, + 0x11, 0x74, 0xb3, 0xad, 0x27, 0x4c, 0xe1, 0xe0, 0xce, 0xa6, 0x26, 0xce, + 0x6d, 0x57, 0x32, 0xe0, 0xdb, 0x46, 0xb9, 0x24, 0x37, 0xba, 0x33, 0x21, + 0xef, 0x74, 0x7c, 0x9d, 0xe3, 0x89, 0xb6, 0xbb, 0xd0, 0xf0, 0x50, 0x19, + 0xed, 0xa7, 0x1c, 0x79, 0x5b, 0xd7, 0x7d, 0xc4, 0x3b, 0xdc, 0xcb, 0x32, + 0x6f, 0x06, 0x66, 0xe3, 0x95, 0x50, 0xc3, 0xca, 0xd9, 0x70, 0xc6, 0x0e, + 0x29, 0x81, 0xa6, 0x0d, 0x4a, 0x5c, 0x13, 0x5b, 0xbc, 0x27, 0xa5, 0x07, + 0x1b, 0x21, 0xd8, 0xdd, 0x42, 0x7d, 0xcc, 0xc6, 0x87, 0x0b, 0x45, 0x2e, + 0x67, 0x38, 0xe8, 0x08, 0x74, 0x3c, 0xcf, 0xf9, 0x2d, 0x9b, 0x97, 0xcd, + 0xfb, 0xd2, 0xf6, 0xbe, 0xce, 0x16, 0xf4, 0xa5, 0x4f, 0xbd, 0x77, 0xc0, + 0x80, 0xf3, 0x68, 0xdd, 0xa3, 0x16, 0xec, 0x77, 0x40, 0x1a, 0x64, 0x1e, + 0x5a, 0x64, 0x1e, 0x8a, 0xe9, 0x4f, 0x37, 0x51, 0xee, 0xf5, 0xb6, 0xdc, + 0xb3, 0x31, 0x6c, 0xca, 0x7a, 0x92, 0x53, 0xbb, 0x07, 0x3d, 0xc4, 0xce, + 0xc0, 0xf9, 0x2e, 0xf6, 0xf3, 0x26, 0x65, 0x9e, 0x47, 0xbd, 0x4f, 0x36, + 0x0b, 0x3f, 0x7c, 0x18, 0xbd, 0xc9, 0xfc, 0x3b, 0x22, 0x0a, 0x52, 0x01, + 0xe9, 0xe3, 0x61, 0xf2, 0xa5, 0x2e, 0x6b, 0xb2, 0x5a, 0xae, 0xef, 0x65, + 0x2e, 0x1d, 0xd5, 0xe8, 0x0f, 0xd4, 0x3b, 0xf4, 0xd9, 0xd0, 0x27, 0xce, + 0x38, 0xa2, 0xf4, 0x01, 0xd3, 0x7b, 0x9e, 0xd8, 0x70, 0x14, 0x1d, 0x16, + 0x2a, 0x6c, 0x7b, 0xf8, 0xf9, 0x88, 0xf1, 0x0b, 0x45, 0x62, 0x7b, 0x86, + 0x3a, 0x60, 0xb6, 0xdf, 0x2e, 0x3a, 0x28, 0xa5, 0xcf, 0x8e, 0x05, 0x74, + 0xff, 0x2b, 0x94, 0x67, 0x07, 0xe5, 0x59, 0x91, 0x9d, 0x43, 0xdf, 0x16, + 0x45, 0x7c, 0x3a, 0xd0, 0xbc, 0x9a, 0xd7, 0xb7, 0x53, 0x9e, 0x40, 0xaf, + 0x82, 0xa1, 0xe6, 0x6e, 0xf2, 0xb1, 0x0e, 0xea, 0xe0, 0xa2, 0x3c, 0x6e, + 0x7b, 0xce, 0x3a, 0xc8, 0x05, 0x0a, 0x99, 0xff, 0x0b, 0x7e, 0x6b, 0x18, + 0xa6, 0x9d, 0xee, 0xe7, 0x8c, 0x44, 0xbd, 0x2a, 0x0a, 0x0d, 0xc1, 0x80, + 0x6a, 0x5e, 0x73, 0x71, 0x6e, 0xca, 0x71, 0x48, 0xdb, 0x6b, 0xef, 0x69, + 0xce, 0xe6, 0xea, 0x1f, 0x59, 0xa3, 0x5e, 0xe1, 0x67, 0xb2, 0xde, 0x24, + 0x6b, 0x32, 0x71, 0x4f, 0x76, 0x4f, 0xb5, 0x8b, 0x3a, 0xc9, 0x5e, 0x7f, + 0x41, 0x73, 0xe4, 0xf2, 0x66, 0xb9, 0xfe, 0x81, 0xf5, 0xac, 0x5d, 0x5e, + 0xca, 0xb9, 0x6c, 0x2e, 0x5c, 0x6c, 0x97, 0xfb, 0xc0, 0x7a, 0x51, 0x73, + 0x4e, 0x29, 0x97, 0x7f, 0x86, 0x77, 0xe2, 0x6b, 0x4e, 0x62, 0x5e, 0xe1, + 0xdc, 0xc5, 0x38, 0x69, 0x9c, 0xaa, 0x39, 0x5d, 0xd7, 0xc9, 0x38, 0x36, + 0x75, 0x1f, 0x98, 0x85, 0x27, 0xed, 0x1c, 0xb7, 0x6b, 0xbe, 0x03, 0x27, + 0x76, 0x16, 0xd0, 0x27, 0xa3, 0x9a, 0xac, 0x87, 0x45, 0x4b, 0x72, 0x7b, + 0x55, 0x24, 0x6f, 0x0c, 0xfa, 0xd5, 0xab, 0x6d, 0x6e, 0x18, 0x55, 0xff, + 0xdc, 0x7e, 0x3b, 0xe1, 0x2e, 0x9d, 0xd8, 0x6f, 0xe4, 0x39, 0xcb, 0x89, + 0x47, 0x55, 0xe2, 0xe4, 0x80, 0xb9, 0x58, 0x62, 0xb3, 0x9f, 0xf5, 0x83, + 0x31, 0x75, 0x2a, 0xb7, 0x59, 0xed, 0x41, 0x59, 0xd7, 0x36, 0x07, 0x64, + 0x9f, 0xa9, 0xec, 0x19, 0x95, 0xbe, 0x8a, 0x72, 0xeb, 0x3c, 0x9f, 0xc4, + 0x35, 0xf2, 0x7d, 0x09, 0xdf, 0xf8, 0x20, 0xc7, 0xdd, 0xf4, 0x60, 0xd4, + 0x96, 0xf3, 0x57, 0xd6, 0x4a, 0x2d, 0x33, 0x43, 0xc3, 0xa5, 0xb2, 0x47, + 0x73, 0xb2, 0xc7, 0x3e, 0x71, 0x9d, 0x4a, 0xfa, 0x99, 0xda, 0x66, 0x7e, + 0x4f, 0xb7, 0xac, 0x61, 0xca, 0x3d, 0x05, 0x5d, 0xc4, 0xa1, 0xa8, 0xd6, + 0xc0, 0x38, 0xaf, 0xfb, 0xd6, 0x70, 0x3e, 0xe2, 0x5e, 0xd9, 0xcb, 0x9e, + 0x8f, 0x91, 0x85, 0xc8, 0xae, 0x25, 0xca, 0x7e, 0x87, 0xec, 0xfa, 0x21, + 0xed, 0x1e, 0x5d, 0xa9, 0xdf, 0x59, 0x19, 0xaf, 0x93, 0xb1, 0xf0, 0xe2, + 0x3e, 0xea, 0x21, 0xea, 0x55, 0xd6, 0x41, 0xb6, 0x5c, 0x58, 0xab, 0x90, + 0x35, 0x1a, 0x89, 0xbd, 0xbf, 0xb5, 0x5a, 0x2f, 0x29, 0x3b, 0x75, 0x4f, + 0x79, 0x75, 0x4c, 0x9e, 0x83, 0x8d, 0xe6, 0xd6, 0xb1, 0x1b, 0xff, 0xe0, + 0x39, 0xd8, 0x04, 0x6d, 0x09, 0xd1, 0x2d, 0xe4, 0x76, 0x71, 0x74, 0x63, + 0x34, 0x51, 0xab, 0x6d, 0x85, 0x26, 0xeb, 0xb7, 0xfc, 0xeb, 0xc6, 0xa1, + 0x04, 0xa2, 0x05, 0x57, 0x95, 0x93, 0x6f, 0x21, 0xea, 0x60, 0x8c, 0x7a, + 0x22, 0x51, 0xdb, 0xb4, 0x9d, 0x63, 0xf2, 0xaf, 0xec, 0xc6, 0x70, 0xa2, + 0xe1, 0x4b, 0x8c, 0x23, 0xfe, 0x12, 0x9b, 0xeb, 0x44, 0xff, 0xcb, 0x01, + 0xe2, 0xc0, 0xe6, 0xdc, 0x1a, 0x52, 0x6b, 0xe2, 0xd7, 0x94, 0xdf, 0x16, + 0x92, 0xf5, 0xfe, 0x54, 0xb9, 0x09, 0xe6, 0xd3, 0xa7, 0xb0, 0xb6, 0x5f, + 0xc1, 0xb3, 0xc6, 0x29, 0xac, 0x19, 0x12, 0x79, 0x4e, 0xa1, 0xad, 0xff, + 0xfb, 0xd8, 0xdf, 0x3f, 0x1d, 0x8d, 0xb6, 0x6e, 0x3a, 0xb0, 0x61, 0xd7, + 0x11, 0xec, 0x48, 0x5a, 0xd8, 0x1e, 0xf2, 0x60, 0xfd, 0x3e, 0x05, 0xcb, + 0x03, 0xc7, 0xb0, 0x75, 0x97, 0x85, 0x39, 0xa1, 0x4e, 0x34, 0x99, 0x25, + 0x28, 0xac, 0x98, 0xb7, 0x4e, 0x65, 0xb9, 0xd6, 0xe1, 0x8e, 0xdc, 0xfe, + 0xe5, 0x43, 0xc4, 0x02, 0x15, 0x3e, 0x43, 0xf6, 0x26, 0x47, 0x95, 0xdb, + 0xd3, 0x8d, 0x4a, 0x4b, 0xee, 0x39, 0xe2, 0xad, 0xe9, 0x8f, 0x99, 0xff, + 0xc4, 0xb1, 0x3f, 0x74, 0x0a, 0x43, 0x43, 0xbf, 0x2e, 0xcd, 0xfa, 0xcb, + 0x04, 0xb9, 0x83, 0xe4, 0x1c, 0x26, 0x6d, 0xea, 0x4f, 0xbd, 0x37, 0x24, + 0x76, 0x37, 0x89, 0x9f, 0x0e, 0x9e, 0xc6, 0xe9, 0xc1, 0x7f, 0xc1, 0x12, + 0x4d, 0xf2, 0x34, 0xab, 0xd3, 0x19, 0xb1, 0xac, 0x3d, 0xf5, 0x71, 0xab, + 0xda, 0x78, 0xab, 0x0c, 0xc5, 0x65, 0x98, 0x16, 0x79, 0x0d, 0xdb, 0x35, + 0xb6, 0x95, 0x3c, 0x84, 0x9d, 0x8c, 0xeb, 0xbe, 0xc8, 0x1d, 0xf0, 0x25, + 0x33, 0x66, 0x25, 0xa2, 0x3b, 0x2b, 0xa1, 0xb7, 0x57, 0x38, 0x8c, 0x8e, + 0x7f, 0x56, 0xea, 0x70, 0x6b, 0xfa, 0x34, 0x7e, 0x31, 0x68, 0xef, 0xc9, + 0x6a, 0xf9, 0xb6, 0x62, 0x75, 0x6e, 0x0f, 0xe9, 0x4d, 0xff, 0x55, 0x89, + 0xc6, 0x65, 0x2f, 0x4f, 0x11, 0x73, 0x82, 0xdb, 0x06, 0x25, 0xdf, 0x6c, + 0x81, 0xbb, 0x57, 0xcf, 0x2c, 0x25, 0xcf, 0xfe, 0xca, 0x82, 0xf8, 0x8c, + 0x2a, 0xda, 0xa5, 0x43, 0xd1, 0x83, 0x86, 0xda, 0x89, 0xe3, 0xa6, 0x3e, + 0xf1, 0x5b, 0x87, 0x31, 0xf4, 0x2d, 0xd4, 0x61, 0x55, 0x5a, 0x1f, 0xba, + 0x86, 0x79, 0xd8, 0xd6, 0x3e, 0x13, 0xc9, 0x3e, 0xbd, 0xa5, 0xc3, 0xd1, + 0x83, 0xfb, 0x02, 0x35, 0xed, 0xef, 0x91, 0xcb, 0x79, 0x88, 0x29, 0x7d, + 0xe3, 0x23, 0xcc, 0x13, 0x7b, 0xb0, 0x61, 0x5f, 0x04, 0xeb, 0xf7, 0x98, + 0xe8, 0xee, 0x1b, 0xa1, 0x6c, 0x2f, 0x95, 0xca, 0x1e, 0x96, 0xe6, 0x50, + 0xfc, 0x66, 0x15, 0x81, 0x28, 0xfb, 0x6c, 0x50, 0x23, 0x01, 0xbf, 0xaa, + 0x30, 0xfa, 0x8f, 0x3b, 0xb1, 0x89, 0x65, 0x7a, 0x93, 0xb4, 0xb9, 0x3e, + 0x37, 0xe3, 0xe5, 0x4c, 0x0c, 0x8f, 0xf9, 0x70, 0x70, 0xcc, 0x83, 0xa1, + 0x31, 0x8d, 0x47, 0x31, 0x1e, 0x1b, 0x90, 0xbd, 0x20, 0x5e, 0x3c, 0x7d, + 0xc0, 0x8d, 0xcd, 0xbb, 0x3d, 0x98, 0x1d, 0x99, 0x86, 0x03, 0x07, 0x8a, + 0xb1, 0x97, 0xd7, 0x2b, 0x16, 0xfa, 0xf1, 0x24, 0xaf, 0xf7, 0xef, 0x76, + 0x71, 0x1e, 0xe6, 0xe0, 0x30, 0x0d, 0x7b, 0x68, 0xac, 0x04, 0xc9, 0x01, + 0x9a, 0x3c, 0x39, 0xeb, 0xdb, 0xcc, 0x30, 0x46, 0x0f, 0x30, 0x36, 0xee, + 0x33, 0x91, 0x60, 0x3f, 0x3b, 0xa8, 0xab, 0x6e, 0xe2, 0xda, 0x86, 0x31, + 0xc1, 0xf8, 0x55, 0xb8, 0xa9, 0x57, 0x6f, 0x6a, 0x54, 0x8c, 0xe8, 0x22, + 0x7b, 0xbf, 0x97, 0xbc, 0xdf, 0xb5, 0x0a, 0x0d, 0x09, 0xdd, 0x6c, 0x44, + 0x27, 0x4e, 0x72, 0xdc, 0xff, 0x17, 0xfd, 0x76, 0xb1, 0x43, 0xef, 0xb9, + 0x51, 0x3d, 0x82, 0x9d, 0xe9, 0xa3, 0xe4, 0xea, 0x40, 0x78, 0xff, 0x11, + 0xf2, 0xb7, 0xe3, 0xc4, 0x9f, 0x37, 0x2d, 0x9f, 0xa1, 0xe2, 0xd6, 0x47, + 0x8c, 0xf0, 0xfb, 0x4a, 0xa0, 0xfd, 0x57, 0xd4, 0xc1, 0x67, 0x0f, 0xa8, + 0xb8, 0x65, 0xe7, 0x62, 0xa4, 0x42, 0x51, 0xec, 0x58, 0xa4, 0xe2, 0xe6, + 0x7d, 0x47, 0x88, 0xfb, 0x13, 0x36, 0x4f, 0xce, 0xa4, 0x1e, 0x46, 0xb0, + 0x57, 0xd6, 0xb8, 0xdd, 0x8c, 0xdf, 0xa5, 0x78, 0xa6, 0x9f, 0x39, 0xb4, + 0x59, 0x8a, 0x13, 0x43, 0x47, 0x68, 0x8f, 0xa5, 0x38, 0xde, 0x6f, 0x4c, + 0xfc, 0xd4, 0x51, 0x8a, 0xa7, 0x79, 0xbe, 0x93, 0xe7, 0x0b, 0x07, 0x8c, + 0xfe, 0x0e, 0xb5, 0x14, 0x0b, 0xf6, 0xd7, 0xa3, 0xbf, 0x4f, 0x6c, 0x53, + 0x43, 0xfb, 0x58, 0x5d, 0x4e, 0xf7, 0xa2, 0x73, 0x2f, 0x36, 0x52, 0x57, + 0xf7, 0xed, 0xec, 0x64, 0x7f, 0x3e, 0xea, 0xfc, 0x08, 0x1e, 0x63, 0x5e, + 0xb7, 0xbd, 0xcf, 0x87, 0x73, 0x49, 0xc3, 0xff, 0x45, 0xc5, 0x30, 0x8b, + 0x94, 0x80, 0xf6, 0x0c, 0x7c, 0x38, 0x9d, 0x2e, 0xc6, 0xa6, 0x81, 0x99, + 0xf8, 0x29, 0xed, 0xf3, 0xd1, 0xdd, 0xd2, 0xdf, 0x04, 0xe3, 0xc3, 0x2c, + 0x3c, 0x3d, 0x62, 0xb2, 0x6d, 0x99, 0x27, 0x89, 0x39, 0xdd, 0x70, 0x25, + 0xc5, 0x37, 0xa2, 0x3b, 0x69, 0x16, 0xc4, 0xc4, 0x63, 0x48, 0xf7, 0xeb, + 0x3d, 0xb7, 0xa9, 0xc2, 0xab, 0x55, 0xea, 0xd2, 0x81, 0x49, 0x4d, 0x8f, + 0x57, 0xa8, 0xf1, 0x7e, 0xe6, 0xaf, 0xf1, 0x4a, 0xf5, 0x18, 0x9e, 0xee, + 0x77, 0x62, 0xde, 0x42, 0x95, 0xd7, 0xe3, 0xe7, 0x19, 0xdb, 0xe2, 0xb3, + 0x55, 0x13, 0x7b, 0x6d, 0x59, 0x11, 0x2f, 0x20, 0xb7, 0x2f, 0x5f, 0x58, + 0xc3, 0xf8, 0xe5, 0x10, 0xdb, 0x8b, 0x95, 0xaa, 0x4e, 0xea, 0xfd, 0x34, + 0x46, 0x68, 0xd7, 0x4f, 0xf0, 0x38, 0x3c, 0x68, 0x75, 0x2e, 0x27, 0xe7, + 0x9e, 0x13, 0xb0, 0x3a, 0x6f, 0x33, 0x0d, 0x5f, 0x81, 0x1a, 0x88, 0x7e, + 0x05, 0xa7, 0x71, 0x68, 0x44, 0xca, 0xc0, 0xed, 0x8d, 0x30, 0xaf, 0xee, + 0xb3, 0x3a, 0x77, 0x9a, 0x73, 0x50, 0x6f, 0xe7, 0xc6, 0x3f, 0x2f, 0xcd, + 0x62, 0xa6, 0xf8, 0x91, 0xbd, 0xa7, 0x0a, 0xbf, 0x62, 0x3b, 0xef, 0x0f, + 0x96, 0xa3, 0xaa, 0x52, 0xfc, 0xe0, 0x14, 0xde, 0xe9, 0x7f, 0x0d, 0xe7, + 0xfa, 0x2d, 0x2c, 0x08, 0x59, 0x70, 0x86, 0x6a, 0xcd, 0x46, 0xf5, 0x1a, + 0x62, 0x84, 0x82, 0x9b, 0xe6, 0x7e, 0x1f, 0xef, 0xd2, 0xff, 0x6f, 0x9e, + 0x6b, 0xd9, 0xb2, 0xf4, 0x62, 0xa1, 0xb5, 0xa3, 0x5a, 0xfc, 0xc6, 0xb4, + 0xf7, 0xd3, 0xfc, 0xe9, 0x3c, 0x38, 0xbf, 0xaf, 0x4b, 0x72, 0xe1, 0xd3, + 0x18, 0x1e, 0x34, 0xa2, 0x6b, 0xf3, 0x72, 0xf6, 0x9f, 0xa6, 0x0e, 0x2c, + 0xec, 0x34, 0x4f, 0xec, 0xab, 0xc0, 0xbc, 0xf3, 0xcc, 0x1a, 0xaf, 0x9b, + 0x4d, 0xdb, 0x59, 0xb0, 0x30, 0x60, 0x2e, 0x53, 0xff, 0x37, 0xfd, 0xf4, + 0x34, 0x0e, 0x0e, 0xe5, 0xf1, 0xda, 0x87, 0x46, 0xfa, 0x79, 0x76, 0xcf, + 0xbb, 0x17, 0x0d, 0xc9, 0xa3, 0xf6, 0xfa, 0xc3, 0x61, 0xe2, 0x63, 0xf6, + 0x19, 0xa1, 0x86, 0x91, 0x74, 0x23, 0xb1, 0x21, 0x8a, 0xef, 0xa6, 0x23, + 0xc4, 0x87, 0x30, 0xf1, 0xa1, 0x9e, 0xf8, 0x60, 0x12, 0x1f, 0xea, 0x88, + 0x0f, 0x41, 0xfb, 0xd9, 0xb9, 0xac, 0x47, 0x0f, 0x8d, 0xbe, 0x86, 0x82, + 0x81, 0x53, 0x70, 0x0d, 0xc8, 0x3e, 0x35, 0x8b, 0xfc, 0xa4, 0x56, 0x6b, + 0xc3, 0x1c, 0x45, 0xf6, 0x0c, 0x0e, 0xa5, 0x4f, 0xa1, 0x68, 0x40, 0xe3, + 0x58, 0x64, 0xaf, 0x40, 0x4d, 0xb8, 0x87, 0x58, 0xfd, 0x6b, 0xa3, 0xb6, + 0xc7, 0x8b, 0xda, 0xbd, 0xd5, 0x30, 0xfa, 0x17, 0xaa, 0x73, 0x95, 0xe8, + 0xe7, 0xbc, 0x1c, 0x67, 0x25, 0x66, 0xed, 0xd6, 0x30, 0x9b, 0xc7, 0x3f, + 0x25, 0x6b, 0x26, 0xde, 0x74, 0xc0, 0x3b, 0x9d, 0x74, 0x67, 0x06, 0x99, + 0x00, 0x59, 0xad, 0xd7, 0x87, 0x2b, 0x0f, 0x9f, 0x56, 0x15, 0x64, 0x3e, + 0x27, 0x31, 0xaf, 0x36, 0xd8, 0xad, 0x32, 0x5b, 0xd7, 0x04, 0xc3, 0x79, + 0xa8, 0x88, 0x90, 0x45, 0xcc, 0x64, 0x7e, 0x61, 0xb5, 0x99, 0x45, 0xd8, + 0x52, 0xa7, 0xca, 0x7e, 0x8d, 0xa3, 0x12, 0xa3, 0xa6, 0x33, 0x46, 0x14, + 0xf7, 0xc5, 0xef, 0x99, 0x0e, 0x0f, 0x8a, 0xfa, 0x2c, 0xeb, 0x1b, 0x21, + 0x0d, 0x9e, 0x48, 0x20, 0xba, 0x81, 0x69, 0xe4, 0xe7, 0xe6, 0x85, 0x71, + 0x53, 0xfa, 0x30, 0x06, 0x38, 0xbe, 0xe5, 0xe9, 0xfc, 0xbb, 0x9c, 0x7f, + 0xfa, 0xef, 0xe2, 0x3b, 0xa1, 0x57, 0xee, 0x9d, 0x0e, 0x43, 0x7b, 0x40, + 0xed, 0x28, 0x27, 0x07, 0x3f, 0xcc, 0xb8, 0xa7, 0x4c, 0x7e, 0x5e, 0x41, + 0xcb, 0x40, 0x1c, 0x55, 0xa1, 0x53, 0x4a, 0x4c, 0xf6, 0x32, 0x29, 0x95, + 0xf8, 0xfc, 0x6e, 0xea, 0x7a, 0x41, 0x86, 0xb6, 0xe2, 0xc3, 0xb7, 0x46, + 0x45, 0xb7, 0x35, 0x43, 0x3b, 0x39, 0x8e, 0x37, 0xe6, 0x1e, 0x16, 0x9c, + 0x3c, 0x32, 0x0b, 0x8e, 0x23, 0xd3, 0x98, 0x9b, 0xd6, 0xcc, 0xbd, 0xf2, + 0xfc, 0xbf, 0xa8, 0xa2, 0x17, 0x85, 0xd8, 0xa1, 0xf7, 0xc7, 0xd8, 0xf6, + 0x07, 0x8e, 0xc3, 0xd8, 0x44, 0x0c, 0x3e, 0x9a, 0xfe, 0x0e, 0x75, 0x79, + 0x28, 0x97, 0x2f, 0xad, 0x42, 0xa2, 0x57, 0xf6, 0xe3, 0x9d, 0xc2, 0xac, + 0x01, 0xbd, 0x79, 0x9b, 0x62, 0x04, 0x6f, 0x56, 0x4e, 0x61, 0xc6, 0x40, + 0x90, 0x73, 0xa9, 0x61, 0x59, 0x5f, 0x1e, 0x3f, 0x05, 0x83, 0x57, 0x11, + 0x83, 0xad, 0xc5, 0x3f, 0x35, 0xe3, 0xcc, 0x71, 0x74, 0xd3, 0xa9, 0xe8, + 0x2d, 0x73, 0x15, 0xd9, 0x9b, 0x63, 0x9c, 0x6f, 0x65, 0x1d, 0xcf, 0x40, + 0x1d, 0xee, 0xe4, 0x98, 0x9b, 0x38, 0x6f, 0xaf, 0x2d, 0xb4, 0xb0, 0x68, + 0xa1, 0xbe, 0xb7, 0xc8, 0x11, 0x7d, 0xa0, 0x02, 0x99, 0x8e, 0x6a, 0xda, + 0xcd, 0x7d, 0x0b, 0xf4, 0xf0, 0xab, 0xc4, 0x5d, 0xe2, 0x34, 0x36, 0x31, + 0xee, 0xb4, 0x31, 0x16, 0x15, 0x47, 0xf4, 0x1e, 0xe6, 0xa8, 0xef, 0xdf, + 0xed, 0x88, 0x86, 0xe4, 0x7d, 0xa3, 0x7f, 0xc0, 0x62, 0xb8, 0x43, 0x65, + 0xc4, 0x41, 0x3d, 0xf3, 0x1a, 0xf4, 0xbd, 0x77, 0x92, 0x93, 0xfe, 0x84, + 0xfc, 0xae, 0xfa, 0xaa, 0xa3, 0xc4, 0xa8, 0x11, 0x3c, 0x9a, 0x3e, 0x82, + 0xbd, 0xe9, 0x14, 0x76, 0xa5, 0x77, 0x28, 0x43, 0xf6, 0xb3, 0x3a, 0x45, + 0xde, 0xad, 0x8b, 0x96, 0x29, 0x5f, 0x46, 0x69, 0xe8, 0x9b, 0xd6, 0x50, + 0x85, 0x8a, 0xf2, 0x50, 0x10, 0x37, 0xf5, 0xc5, 0xe1, 0x88, 0xbc, 0x67, + 0xc9, 0x7b, 0xd9, 0xeb, 0xc7, 0x0d, 0xdc, 0xd8, 0x57, 0x8c, 0xd8, 0x7e, + 0xcb, 0xea, 0xa9, 0x77, 0x62, 0xcd, 0x78, 0x1d, 0x96, 0x0d, 0x3c, 0x66, + 0xcd, 0x66, 0xcc, 0xf9, 0xf8, 0x5a, 0x0f, 0xee, 0xde, 0xef, 0x41, 0x6b, + 0x5f, 0x14, 0xbe, 0x48, 0x09, 0x7f, 0x07, 0xcc, 0x25, 0x30, 0x26, 0x26, + 0x60, 0xf4, 0xdc, 0xe0, 0x08, 0x1c, 0x0a, 0xab, 0x1e, 0x7c, 0x95, 0x38, + 0xbe, 0x9c, 0xb8, 0x13, 0x1b, 0xb7, 0x50, 0x1e, 0xf1, 0xe2, 0x1e, 0xd6, + 0xbf, 0x85, 0x73, 0xff, 0xee, 0xa2, 0x43, 0xc4, 0x02, 0xd9, 0x83, 0xa8, + 0x61, 0xc3, 0xb8, 0x9b, 0xba, 0x72, 0x23, 0x76, 0xb0, 0x12, 0x37, 0xee, + 0xf6, 0xe3, 0xee, 0x71, 0x0f, 0x1a, 0xfa, 0xac, 0xc5, 0x87, 0xcd, 0xf8, + 0x4a, 0x0d, 0x06, 0x5a, 0xc7, 0xbd, 0xf8, 0xdb, 0x3e, 0xdd, 0x77, 0x33, + 0x73, 0xfe, 0x11, 0x33, 0x88, 0xbf, 0x1f, 0xf7, 0xe1, 0xf6, 0xbe, 0x13, + 0x92, 0x47, 0x2e, 0x71, 0x32, 0xf6, 0x3c, 0x34, 0x3e, 0x13, 0x2b, 0xfb, + 0xf4, 0xf3, 0x13, 0xe4, 0x76, 0x9d, 0x07, 0x4d, 0x3c, 0x30, 0xae, 0xa2, + 0x85, 0xed, 0x7c, 0xbe, 0x6f, 0x16, 0x3a, 0x0e, 0xd6, 0x53, 0x86, 0x85, + 0x58, 0x3e, 0xe0, 0x84, 0x49, 0x16, 0x8f, 0x2f, 0x00, 0xcd, 0x03, 0x13, + 0xcc, 0xe3, 0x1e, 0xc6, 0x8e, 0x5e, 0x13, 0xf7, 0x8e, 0xcb, 0xf9, 0x11, + 0xfb, 0x5d, 0xd8, 0xf7, 0xf7, 0x2d, 0xc4, 0x67, 0x07, 0x54, 0xe2, 0x40, + 0x21, 0x86, 0x56, 0x2a, 0xf8, 0x5b, 0x5e, 0xdf, 0x96, 0x94, 0xbd, 0xcc, + 0x40, 0x68, 0x67, 0xe0, 0x50, 0x05, 0x39, 0xc3, 0xa2, 0x7d, 0xd9, 0xeb, + 0x8f, 0x12, 0xe7, 0x8b, 0x88, 0xf3, 0x25, 0xe4, 0xb0, 0x37, 0x0c, 0x1f, + 0xc1, 0x23, 0xc4, 0xe5, 0xa3, 0x03, 0x9d, 0x8c, 0x3b, 0xa5, 0x78, 0x92, + 0x71, 0xa0, 0x8f, 0xe7, 0xa7, 0x76, 0x1a, 0x1d, 0x45, 0xc4, 0xe9, 0x57, + 0x89, 0xbf, 0x3d, 0xc4, 0x8c, 0xfb, 0xfa, 0x18, 0xee, 0x77, 0x32, 0x07, + 0xb8, 0x2a, 0x3a, 0xdf, 0xc3, 0x1c, 0xeb, 0x66, 0x25, 0xe0, 0x7b, 0x0b, + 0xa5, 0x70, 0xec, 0xab, 0x44, 0xc3, 0x6e, 0x29, 0x23, 0xf8, 0xa5, 0x42, + 0x3d, 0xe0, 0xa4, 0xce, 0x8f, 0xc1, 0xea, 0x77, 0x70, 0xbc, 0x35, 0x26, + 0x19, 0x38, 0xde, 0x30, 0x75, 0xed, 0xbb, 0xc4, 0xda, 0x0f, 0x89, 0xa9, + 0xfe, 0xe9, 0xf5, 0x68, 0x34, 0x4c, 0x1e, 0xc7, 0x70, 0xba, 0xdf, 0x30, + 0x65, 0x9f, 0xdc, 0x9b, 0xe4, 0x79, 0x93, 0xd3, 0x19, 0x33, 0x0d, 0xf1, + 0xc3, 0x11, 0x8e, 0x47, 0x95, 0xbc, 0x04, 0x8e, 0x31, 0xe0, 0x9d, 0x7d, + 0x8b, 0x39, 0x2e, 0x89, 0xa5, 0x12, 0xef, 0x46, 0x28, 0xeb, 0x62, 0xac, + 0xa0, 0x3e, 0x1a, 0xfb, 0x54, 0xa4, 0x0e, 0x46, 0x70, 0xef, 0x9e, 0x6c, + 0x1c, 0x6e, 0x0f, 0xc5, 0x6f, 0x63, 0x1c, 0x0e, 0x17, 0x33, 0x0e, 0xbb, + 0x22, 0x22, 0x9b, 0x13, 0xc3, 0x8c, 0xdb, 0x5b, 0x92, 0x61, 0x34, 0x71, + 0x0e, 0x27, 0x52, 0xec, 0xb7, 0x6f, 0x26, 0x9e, 0x49, 0x79, 0x18, 0xb3, + 0x34, 0x1e, 0x44, 0xb5, 0x91, 0x69, 0x3c, 0xfc, 0x3c, 0xe6, 0xf0, 0x30, + 0xec, 0x6b, 0x6d, 0x7d, 0x0a, 0xe2, 0xcd, 0xd9, 0xe7, 0x65, 0xcf, 0xa4, + 0x04, 0x9b, 0x65, 0x2d, 0xf3, 0xde, 0x72, 0xd9, 0xfb, 0xd9, 0x9f, 0xfc, + 0x3e, 0xca, 0x89, 0x4f, 0x65, 0x39, 0x1c, 0xfa, 0x79, 0x48, 0x70, 0xb7, + 0x86, 0xb8, 0x2b, 0xfb, 0x73, 0x2c, 0x6b, 0x55, 0x60, 0x2a, 0x1e, 0xfd, + 0xef, 0x8f, 0xa3, 0xf6, 0x7e, 0x56, 0xc1, 0x24, 0xe2, 0x5f, 0x92, 0xf8, + 0xc7, 0x31, 0x74, 0x5d, 0x4f, 0x0c, 0xa4, 0x4c, 0xff, 0x98, 0x24, 0x06, + 0x12, 0xa7, 0x8f, 0x10, 0xa7, 0x9f, 0x22, 0x4e, 0x7f, 0x93, 0x38, 0xfd, + 0x24, 0x31, 0x21, 0xbb, 0xa6, 0xd7, 0x24, 0xcf, 0x2f, 0x38, 0x1f, 0xef, + 0xd9, 0x6b, 0x8b, 0xd5, 0xd4, 0xd5, 0xac, 0x01, 0x79, 0xe7, 0x47, 0x3f, + 0x24, 0x76, 0xff, 0x13, 0xce, 0x93, 0xbf, 0x2a, 0xbb, 0xef, 0xaa, 0xb1, + 0xaf, 0x1b, 0xee, 0xbe, 0x5a, 0xad, 0x07, 0xf6, 0xb7, 0x02, 0x4c, 0xe1, + 0xa2, 0x05, 0x7d, 0x6d, 0x70, 0xf4, 0xd5, 0x1e, 0x3a, 0x29, 0xcf, 0x43, + 0xa7, 0x49, 0x5e, 0xdf, 0x26, 0x7b, 0xbd, 0x0f, 0xc9, 0x7e, 0xad, 0x65, + 0xbc, 0xe7, 0xea, 0xab, 0x35, 0xdf, 0x82, 0x8d, 0x6d, 0xfe, 0x49, 0xfb, + 0x5e, 0xcd, 0xfb, 0x8f, 0x50, 0x5f, 0x19, 0xb6, 0x99, 0x4a, 0xca, 0x7e, + 0xd4, 0x99, 0x78, 0x22, 0x2d, 0xbf, 0x6b, 0x5b, 0x12, 0xea, 0xe3, 0x88, + 0x55, 0x0b, 0x1f, 0x0f, 0xe3, 0xd6, 0x3e, 0x0f, 0xed, 0x20, 0x8e, 0x32, + 0xfa, 0xd6, 0xfd, 0xe3, 0xf5, 0xf4, 0xb5, 0xc7, 0x2c, 0x2d, 0x12, 0x68, + 0x19, 0x27, 0xe7, 0x59, 0x3f, 0xbe, 0x18, 0x4b, 0x07, 0x2c, 0xcb, 0x73, + 0x8d, 0x11, 0xde, 0xa0, 0xf8, 0xe1, 0xa2, 0x0f, 0x3a, 0xe8, 0x57, 0x6b, + 0xf7, 0x07, 0xb4, 0xb7, 0x88, 0xa7, 0xeb, 0xea, 0x0f, 0xd3, 0x3e, 0x8c, + 0xf3, 0x4d, 0xc4, 0x52, 0x67, 0x24, 0xc0, 0x3c, 0xd1, 0x43, 0xdb, 0xf7, + 0xe2, 0x7c, 0x42, 0xfc, 0x4b, 0xef, 0xf8, 0x2e, 0x73, 0x93, 0x0e, 0xfa, + 0xc6, 0x07, 0x89, 0xeb, 0xe9, 0x4b, 0x61, 0x1e, 0x33, 0xe9, 0x0b, 0x6e, + 0xbc, 0x93, 0x30, 0xe8, 0x77, 0x1e, 0xbc, 0x9b, 0xa8, 0x63, 0x9f, 0x41, + 0x96, 0xf5, 0x63, 0xa3, 0xfd, 0xde, 0x75, 0x4d, 0xfc, 0x5b, 0x4a, 0x4d, + 0xff, 0x2c, 0xb5, 0x02, 0xd1, 0x4a, 0x0d, 0x7f, 0x37, 0xfe, 0x37, 0xf8, + 0x19, 0xe3, 0xf6, 0x9a, 0x3e, 0x70, 0x0e, 0x11, 0x22, 0x0f, 0x9c, 0x38, + 0x28, 0xcf, 0xe9, 0x50, 0x1b, 0x9d, 0xeb, 0xd0, 0x99, 0xdb, 0xea, 0x99, + 0x73, 0x0e, 0x27, 0xfb, 0x24, 0x2b, 0x66, 0xd9, 0x0f, 0xfa, 0x8b, 0xf1, + 0xc0, 0xfe, 0xc3, 0xf4, 0x91, 0x02, 0x2c, 0x78, 0xc4, 0x8d, 0xbf, 0x3b, + 0x38, 0x22, 0x6b, 0x4b, 0x82, 0x99, 0xfe, 0x21, 0x12, 0x85, 0x30, 0xb9, + 0xde, 0xfd, 0x7b, 0x46, 0x30, 0x90, 0xe3, 0x79, 0x1f, 0x84, 0xe2, 0x5f, + 0x51, 0x71, 0x98, 0x3c, 0x22, 0x10, 0xbf, 0x9a, 0x36, 0x26, 0xef, 0xb8, + 0x49, 0xec, 0x5f, 0x41, 0x1b, 0xeb, 0xe6, 0x7c, 0x7e, 0x83, 0xe3, 0xd8, + 0x41, 0x1b, 0x1b, 0x4d, 0xcc, 0xc4, 0x56, 0xda, 0x58, 0x9c, 0x36, 0x16, + 0xa7, 0x3d, 0xc5, 0x69, 0x63, 0xf2, 0x6e, 0x7e, 0x9c, 0x36, 0x16, 0xa7, + 0x8d, 0xc5, 0x53, 0x8b, 0xf1, 0x14, 0x99, 0xc6, 0xae, 0x91, 0x45, 0xc4, + 0x31, 0x79, 0xb6, 0xc6, 0x79, 0xb8, 0xed, 0x6f, 0xc8, 0xd9, 0x6f, 0xe0, + 0xa1, 0xe0, 0x4e, 0xfa, 0xe4, 0x63, 0x43, 0xc4, 0x3b, 0xda, 0xc1, 0xa2, + 0xb4, 0x70, 0xfc, 0x7a, 0xe6, 0xb1, 0xc7, 0xc8, 0xf3, 0x55, 0x3c, 0x6b, + 0x4a, 0x1e, 0x6c, 0xf2, 0x9c, 0xb1, 0x26, 0x29, 0x1c, 0xec, 0x18, 0x36, + 0xf4, 0x03, 0x37, 0x91, 0x17, 0x56, 0x92, 0x97, 0x8c, 0x2c, 0x00, 0x5e, + 0x1c, 0x12, 0x19, 0xc5, 0xc7, 0xb3, 0xfb, 0x4f, 0x8f, 0xf7, 0xd7, 0x44, + 0x1b, 0x65, 0x7d, 0x88, 0x9c, 0x64, 0xf1, 0xb0, 0x70, 0xbc, 0xc3, 0xe4, + 0x48, 0x7a, 0xf8, 0xdf, 0x21, 0x1c, 0xaf, 0x12, 0x65, 0x7b, 0xf4, 0xf0, + 0x3b, 0x30, 0xd6, 0xfd, 0x52, 0xb1, 0x16, 0xbf, 0x16, 0x0a, 0xc4, 0x9f, + 0x54, 0x54, 0x34, 0x93, 0xef, 0xdd, 0xbc, 0xd3, 0x89, 0x9e, 0xd0, 0x62, + 0x7c, 0x85, 0x9c, 0x6f, 0xf5, 0x35, 0x2a, 0x96, 0xec, 0xa3, 0x2d, 0x55, + 0x0a, 0xc7, 0xd2, 0xc3, 0xe7, 0x30, 0x61, 0xaf, 0x13, 0x8e, 0xa6, 0x8e, + 0x5b, 0x55, 0x86, 0x60, 0x11, 0xb1, 0xed, 0xea, 0x37, 0x2d, 0xb7, 0xac, + 0x35, 0x91, 0x03, 0x0e, 0xf7, 0x47, 0x5f, 0x70, 0x12, 0xf7, 0xd7, 0x93, + 0x07, 0x3e, 0x91, 0xe3, 0x81, 0x07, 0xfb, 0x0d, 0xed, 0x07, 0xc4, 0x8b, + 0xfd, 0x3c, 0xdf, 0xca, 0x73, 0xab, 0xdf, 0xe0, 0x7c, 0x04, 0x9a, 0x66, + 0x90, 0x1b, 0xbe, 0x43, 0x99, 0x7b, 0x29, 0x73, 0x82, 0xf6, 0x9f, 0xee, + 0xd5, 0x90, 0x1c, 0x33, 0x30, 0xde, 0xeb, 0x45, 0xdf, 0x58, 0x10, 0x4f, + 0xf6, 0xfa, 0xb0, 0x93, 0xfc, 0xf0, 0x70, 0xaf, 0xf8, 0xe2, 0x4c, 0xf4, + 0x8f, 0xcd, 0xc4, 0x37, 0x92, 0xb2, 0x3e, 0xf5, 0x2e, 0x56, 0x57, 0x88, + 0x7e, 0xc4, 0x2f, 0xc9, 0xaf, 0x93, 0x7a, 0x4f, 0x8c, 0x63, 0x8a, 0x79, + 0xf5, 0x43, 0x31, 0xe8, 0x43, 0x9c, 0xc1, 0x8f, 0x87, 0xbe, 0x20, 0x31, + 0x52, 0x7c, 0x52, 0xc3, 0x13, 0xe4, 0x3c, 0xa5, 0xc4, 0xd5, 0x92, 0x48, + 0x4d, 0xf4, 0x0b, 0x8a, 0x1e, 0x7b, 0x45, 0xb5, 0xac, 0x4a, 0x89, 0xe1, + 0x07, 0x35, 0xf2, 0x0f, 0x13, 0x37, 0xdb, 0x31, 0x5b, 0xc3, 0xf4, 0xdd, + 0x95, 0xa8, 0xda, 0xdd, 0x87, 0xff, 0x56, 0x19, 0xff, 0x60, 0x1a, 0x63, + 0xfd, 0x34, 0x62, 0xfb, 0xec, 0xbe, 0x93, 0xd3, 0x67, 0x91, 0x33, 0xbf, + 0xa1, 0xd6, 0x66, 0xbe, 0x0b, 0xfd, 0xd0, 0x69, 0x87, 0x3e, 0x71, 0x94, + 0xf1, 0xc1, 0x45, 0xfb, 0x9c, 0x31, 0xae, 0xd1, 0x7f, 0x6b, 0x8f, 0x56, + 0xc1, 0x88, 0x5f, 0xab, 0x3a, 0x2d, 0x54, 0x8a, 0x3c, 0xa1, 0xf2, 0x6c, + 0x6e, 0x14, 0x26, 0xf6, 0x4b, 0x6c, 0x70, 0x40, 0x23, 0x0e, 0xff, 0x3d, + 0x7d, 0xe6, 0x4e, 0x3b, 0x1e, 0x1d, 0xb6, 0x9f, 0x85, 0x76, 0x8e, 0xc7, + 0xe9, 0x27, 0x8b, 0xd1, 0xd1, 0xef, 0x41, 0xbb, 0x1d, 0x8b, 0x1e, 0xb3, + 0x2a, 0xe8, 0x33, 0x1d, 0xfb, 0x03, 0x4d, 0x37, 0xd2, 0x67, 0xae, 0xbb, + 0x46, 0xe2, 0xd8, 0x61, 0xf2, 0x5f, 0xc3, 0xbc, 0x8e, 0xf8, 0xb2, 0xb5, + 0xde, 0xe8, 0x78, 0x9e, 0x32, 0xdd, 0x4f, 0xfb, 0x7f, 0x97, 0x3c, 0xe7, + 0xdc, 0x9e, 0x43, 0xd4, 0x99, 0x66, 0xfb, 0xc3, 0xcf, 0x92, 0x3e, 0xdb, + 0x37, 0x62, 0xfc, 0x2d, 0x71, 0x2f, 0x46, 0x5f, 0xfa, 0x37, 0xc6, 0xec, + 0xe2, 0x50, 0xfc, 0xf6, 0x62, 0x04, 0x71, 0x1f, 0x65, 0xfd, 0x38, 0xa9, + 0xf7, 0x6f, 0x90, 0x77, 0x8f, 0x43, 0x26, 0x65, 0xf1, 0xe0, 0x83, 0xa4, + 0xd8, 0xd9, 0x89, 0xff, 0x59, 0x89, 0xf8, 0x26, 0xc6, 0xe0, 0xa0, 0xe6, + 0x90, 0xb5, 0xf0, 0x99, 0x58, 0x73, 0xf0, 0x1a, 0xca, 0x5c, 0x47, 0xff, + 0x03, 0xe6, 0x0c, 0x47, 0x70, 0xcf, 0x1e, 0xc9, 0x31, 0xd0, 0x20, 0xb9, + 0xda, 0xbc, 0x50, 0xc0, 0x3c, 0x43, 0xac, 0x58, 0x3b, 0x76, 0x98, 0x71, + 0x42, 0xd6, 0x96, 0x91, 0xf1, 0x19, 0x61, 0xbc, 0xda, 0x5b, 0x6f, 0xbf, + 0xd3, 0x70, 0xff, 0x58, 0x3d, 0x5e, 0xe9, 0x9d, 0x89, 0xfb, 0x98, 0xeb, + 0xc4, 0x98, 0xeb, 0xc4, 0xc6, 0xbc, 0x88, 0x1d, 0x98, 0xc6, 0x83, 0xb2, + 0x1d, 0x98, 0xc3, 0x83, 0xb2, 0x8d, 0xa9, 0xf8, 0x2a, 0xf3, 0x97, 0x0d, + 0xc4, 0xf3, 0x1e, 0xda, 0xe3, 0xff, 0xe0, 0xdc, 0x0f, 0xd0, 0xde, 0xab, + 0x89, 0xf7, 0x6f, 0xee, 0x02, 0xee, 0xb4, 0xf5, 0x73, 0x84, 0x7a, 0x54, + 0xf0, 0x15, 0xfa, 0x44, 0x15, 0x63, 0x52, 0x37, 0xe7, 0x7c, 0xe7, 0xa0, + 0x11, 0x0c, 0xab, 0x01, 0xed, 0x09, 0xce, 0x73, 0xd7, 0x88, 0x8a, 0x47, + 0xfb, 0x17, 0x63, 0x3e, 0x63, 0xca, 0xb6, 0xa1, 0x09, 0xbb, 0x7c, 0x37, + 0xfd, 0xe1, 0x6e, 0xfa, 0xc9, 0x7b, 0xf4, 0x93, 0xc9, 0x95, 0xf2, 0x3e, + 0xa9, 0x93, 0x39, 0xff, 0xc3, 0x58, 0x93, 0x90, 0x78, 0xa7, 0xf7, 0x0c, + 0xa9, 0xcc, 0xb5, 0x68, 0x9f, 0x5d, 0xcc, 0x51, 0x6e, 0xa7, 0x6d, 0x3e, + 0x3a, 0x24, 0x3e, 0x24, 0x39, 0x8b, 0x11, 0xde, 0x46, 0xdb, 0x7c, 0x7e, + 0x48, 0xfc, 0xa3, 0x14, 0xb7, 0xee, 0x94, 0xfd, 0xa6, 0xa5, 0xf8, 0xec, + 0xbe, 0xc3, 0x94, 0xef, 0x08, 0x76, 0xd1, 0x2e, 0x4b, 0x69, 0x97, 0xf7, + 0x51, 0xaf, 0x1e, 0xda, 0xe5, 0x06, 0xe2, 0x50, 0x09, 0xed, 0xf2, 0x5e, + 0xf2, 0x81, 0xca, 0x9c, 0x5d, 0xfe, 0xdd, 0xf8, 0xc2, 0x8a, 0x6c, 0x8c, + 0xf0, 0x42, 0xdd, 0x2d, 0xef, 0xf7, 0x59, 0xd6, 0xed, 0x66, 0xa6, 0x69, + 0x06, 0x74, 0xb6, 0x1d, 0xc1, 0xb2, 0xb4, 0x13, 0xe5, 0x7d, 0x11, 0x2c, + 0x4d, 0xd6, 0xb4, 0x9f, 0x55, 0x22, 0xc8, 0xcc, 0xc8, 0xf2, 0x40, 0x57, + 0x9f, 0x7c, 0xdf, 0x43, 0x23, 0x07, 0xe1, 0xf8, 0xaf, 0xcd, 0x7e, 0x53, + 0xe4, 0xf3, 0x7f, 0x01, 0x7f, 0x5c, 0x42, 0x99, 0x3a, 0xcd, 0x8f, 0xac, + 0xc9, 0xec, 0xf7, 0x07, 0x9c, 0xb7, 0xf1, 0x7c, 0x16, 0xdb, 0xa8, 0x1a, + 0x77, 0x3a, 0xbf, 0x98, 0xf4, 0x60, 0xfa, 0xb8, 0x89, 0xbf, 0xcd, 0xb6, + 0xe3, 0x2e, 0x88, 0x34, 0xe2, 0xb9, 0x84, 0x82, 0x69, 0xc6, 0xd3, 0xf8, + 0x91, 0xbd, 0x2e, 0x50, 0x89, 0xf2, 0xdd, 0xf6, 0x9a, 0x02, 0x0e, 0x24, + 0xf4, 0xf6, 0x34, 0xcf, 0xcb, 0x0e, 0x7a, 0x51, 0xbc, 0x5b, 0xc1, 0x2d, + 0x01, 0x2f, 0x4a, 0xf9, 0xdb, 0x43, 0xbe, 0xd9, 0x1d, 0x5a, 0x6e, 0x6d, + 0x59, 0x25, 0xf6, 0xed, 0x05, 0x0e, 0x96, 0x94, 0x0b, 0x0e, 0x1e, 0x30, + 0x65, 0xed, 0xd2, 0x40, 0x77, 0xa2, 0x12, 0x85, 0xbb, 0x6b, 0x9a, 0x1a, + 0x51, 0x63, 0xbe, 0xc3, 0xfa, 0x05, 0x07, 0x3f, 0x5b, 0x21, 0xeb, 0xf6, + 0x4f, 0x49, 0x8c, 0x1b, 0x92, 0x79, 0xcd, 0xc6, 0x50, 0xe7, 0xd8, 0x5b, + 0x9a, 0xe8, 0x65, 0x13, 0x39, 0x8a, 0xda, 0xf7, 0xa6, 0x5d, 0xc6, 0x17, + 0x39, 0x4a, 0x0c, 0x90, 0xf8, 0x72, 0x0a, 0xed, 0xfd, 0xa7, 0x68, 0xff, + 0xb2, 0x8e, 0xc1, 0xbc, 0x77, 0x81, 0x85, 0xe2, 0x85, 0x99, 0x60, 0x31, + 0xa2, 0x15, 0x15, 0xc4, 0x6f, 0xfa, 0x00, 0x5e, 0x30, 0xf5, 0x96, 0x87, + 0x1c, 0xd1, 0x87, 0x8a, 0xa0, 0xaf, 0x7b, 0x5b, 0xe9, 0xc1, 0xc6, 0xc0, + 0x08, 0xfa, 0xc8, 0x05, 0xf3, 0xf9, 0xf8, 0xba, 0x3d, 0x8c, 0x6f, 0x8e, + 0x8b, 0xf9, 0xb8, 0x16, 0x8a, 0xff, 0x8e, 0x3c, 0xc0, 0x3f, 0x9b, 0x18, + 0xed, 0xb0, 0x7d, 0x27, 0x90, 0xd9, 0x44, 0x7b, 0x0d, 0x8f, 0x87, 0xe9, + 0x23, 0x23, 0x82, 0x7d, 0xf2, 0x35, 0xa3, 0x17, 0x0a, 0x98, 0x3f, 0x16, + 0x33, 0x0f, 0x39, 0x9d, 0xb4, 0x3a, 0xdd, 0xb4, 0x6b, 0xe7, 0xa2, 0x99, + 0x50, 0xd3, 0x37, 0xe0, 0x9d, 0x5d, 0x33, 0x51, 0x48, 0x5f, 0xaa, 0x48, + 0xca, 0x0b, 0x55, 0xea, 0xa7, 0xd9, 0x6f, 0xec, 0x3d, 0x04, 0xda, 0x03, + 0x8e, 0xda, 0x75, 0x49, 0x45, 0x27, 0xf6, 0xeb, 0x2d, 0xa5, 0xea, 0x4c, + 0x78, 0x98, 0xaf, 0x94, 0xa4, 0x3d, 0x00, 0xb9, 0x32, 0x58, 0xef, 0xa7, + 0xbb, 0x5c, 0x28, 0x37, 0x8c, 0xe8, 0x33, 0xcc, 0x81, 0x1c, 0xa3, 0x4e, + 0xfc, 0xcc, 0x96, 0x6b, 0x1a, 0x8a, 0x47, 0x6f, 0xc0, 0xe9, 0x5d, 0x7e, + 0xa8, 0xbc, 0x76, 0x76, 0xcf, 0x1c, 0x14, 0x8c, 0x12, 0x08, 0xd2, 0x8b, + 0xf1, 0xd6, 0x2e, 0x15, 0xae, 0xd1, 0xbf, 0xc1, 0x87, 0xbb, 0x14, 0xcc, + 0x9f, 0xa7, 0xa0, 0x68, 0x78, 0x84, 0x3a, 0x11, 0xee, 0x45, 0x3f, 0x4d, + 0xc1, 0xe6, 0x5d, 0x5b, 0x92, 0xc2, 0xed, 0xc9, 0xe9, 0x06, 0x2b, 0x61, + 0xee, 0x7e, 0xd3, 0xaa, 0x30, 0x8c, 0xd8, 0x2d, 0xaa, 0xb5, 0xb8, 0x72, + 0x41, 0xa0, 0x65, 0x80, 0x38, 0xfd, 0x12, 0x7d, 0xe0, 0x64, 0x7f, 0xdc, + 0xf2, 0x18, 0x8b, 0x89, 0xb5, 0x51, 0x34, 0x30, 0x37, 0x97, 0xbc, 0x7b, + 0x9b, 0x9d, 0xef, 0xca, 0x7e, 0x63, 0x27, 0xfc, 0x63, 0x0f, 0xe3, 0x78, + 0xc2, 0x8d, 0xc5, 0x63, 0xa5, 0xb8, 0x8e, 0x39, 0x75, 0x98, 0xdc, 0x21, + 0xbc, 0x2f, 0xcb, 0xf1, 0x9e, 0x27, 0xc7, 0xfb, 0x15, 0xb2, 0x1c, 0x6f, + 0x80, 0xb9, 0x5a, 0x95, 0x51, 0x8a, 0x5b, 0x06, 0x0c, 0xc6, 0x80, 0x52, + 0x34, 0xdb, 0xeb, 0x01, 0x1a, 0x6e, 0xa3, 0xff, 0x7e, 0x9e, 0xf9, 0xf8, + 0xcd, 0x3b, 0x03, 0xbe, 0x1d, 0x8a, 0x8f, 0x71, 0x40, 0xda, 0x3f, 0x4c, + 0xdc, 0xf0, 0x61, 0x4e, 0xaf, 0x11, 0x5c, 0x8a, 0xc0, 0xf9, 0x43, 0xd4, + 0xe5, 0xe2, 0xb1, 0x1b, 0x10, 0xa6, 0xee, 0xc2, 0xfb, 0x0e, 0xe7, 0xc6, + 0x31, 0x41, 0xd9, 0x9d, 0x78, 0x6f, 0x70, 0x16, 0x5e, 0x3d, 0x90, 0xcd, + 0xc3, 0x03, 0x7d, 0x13, 0xb2, 0x5e, 0xfc, 0x35, 0x86, 0xd7, 0x7b, 0x24, + 0x0f, 0xff, 0x41, 0xbf, 0xde, 0x5f, 0x2a, 0xeb, 0x84, 0xf4, 0xe7, 0xaf, + 0x2e, 0x70, 0x30, 0xbe, 0xe8, 0xfe, 0xef, 0x3b, 0xe2, 0xf2, 0x1c, 0xd9, + 0xff, 0x08, 0xef, 0x7f, 0x9f, 0xf1, 0xfc, 0x36, 0x5e, 0x8f, 0x55, 0x32, + 0xd7, 0x5e, 0x18, 0x3f, 0xef, 0xe2, 0xf5, 0xc7, 0x38, 0x97, 0x65, 0x46, + 0x4d, 0xec, 0x15, 0xe5, 0x08, 0x71, 0xc3, 0x81, 0x1d, 0x21, 0x3d, 0xba, + 0xc3, 0xce, 0xa1, 0x9d, 0x98, 0x48, 0x5f, 0x9d, 0xf3, 0xc1, 0x4a, 0x94, + 0xec, 0x96, 0xfc, 0xc5, 0x90, 0xf5, 0x9f, 0xfe, 0x12, 0xe6, 0x4f, 0x95, + 0x17, 0xec, 0x33, 0xbf, 0xff, 0x09, 0xee, 0x8a, 0x48, 0x33, 0x42, 0x7d, + 0xf9, 0x7d, 0x50, 0x87, 0xd0, 0x9d, 0x7e, 0x10, 0xed, 0xbb, 0xf4, 0x76, + 0x59, 0x1f, 0x7a, 0x25, 0x14, 0xb7, 0xca, 0x8d, 0x4e, 0xb8, 0x16, 0x18, + 0xcd, 0xcc, 0x5d, 0x62, 0xdf, 0x56, 0x8a, 0x19, 0x3b, 0x8e, 0x61, 0xf3, + 0xb0, 0x1e, 0xdc, 0xa1, 0x18, 0xcc, 0xf7, 0x34, 0x1c, 0x1a, 0x2c, 0xc0, + 0xdd, 0x7b, 0x5a, 0x19, 0xdb, 0x4c, 0xe2, 0x66, 0x8d, 0xff, 0x1c, 0xde, + 0xc7, 0x49, 0x53, 0xde, 0x11, 0x2a, 0x42, 0xab, 0x26, 0x7b, 0x80, 0x98, + 0x79, 0x4e, 0xbb, 0xe4, 0x3d, 0x71, 0x4f, 0x91, 0x91, 0x7f, 0xdf, 0xdf, + 0x60, 0xae, 0x38, 0x89, 0xfd, 0x83, 0xb2, 0x2e, 0x50, 0xa5, 0x1c, 0xef, + 0x9f, 0xeb, 0xeb, 0x22, 0xe6, 0x3f, 0x64, 0x66, 0x70, 0x7e, 0x61, 0x25, + 0x30, 0x5d, 0x41, 0xe8, 0xd3, 0x01, 0xf9, 0x9e, 0x0d, 0xff, 0xde, 0xb3, + 0xfc, 0x5f, 0x90, 0x76, 0x4a, 0xcb, 0xb2, 0x6b, 0x05, 0x3f, 0xaa, 0x94, + 0xf7, 0x01, 0x8f, 0x27, 0x2b, 0xca, 0xb3, 0xcf, 0x9c, 0xff, 0x54, 0x1f, + 0x6f, 0x58, 0x7e, 0xbb, 0x8d, 0x7c, 0xdd, 0xd7, 0xad, 0xa8, 0x57, 0xca, + 0x17, 0xb0, 0x6d, 0xf1, 0xcb, 0x2a, 0x65, 0x1d, 0x71, 0x54, 0x0d, 0x55, + 0x29, 0xad, 0x43, 0x97, 0xb7, 0xfb, 0x9a, 0x15, 0x6d, 0x96, 0xf3, 0x7c, + 0x39, 0x8b, 0xf7, 0xa5, 0x6c, 0xfe, 0xfe, 0x0b, 0xb9, 0xb6, 0x0a, 0xc9, + 0x53, 0xb3, 0x65, 0xee, 0xee, 0x97, 0xfd, 0x4b, 0x51, 0x9c, 0xa8, 0x9f, + 0xda, 0x5e, 0xbe, 0xef, 0xef, 0x5c, 0xd2, 0x5e, 0xb6, 0x6c, 0x55, 0x15, + 0x8a, 0xa5, 0x7c, 0x06, 0xff, 0x8f, 0xbd, 0x86, 0x70, 0xc6, 0xde, 0x73, + 0xb8, 0xcd, 0x6c, 0x88, 0x16, 0xe1, 0x33, 0x50, 0xaf, 0x8a, 0xcf, 0x2f, + 0xb2, 0xb9, 0x6d, 0xb4, 0xb9, 0x88, 0xf9, 0xad, 0xdb, 0x88, 0x3e, 0xe4, + 0x46, 0x26, 0xe3, 0x86, 0xde, 0x72, 0x5e, 0x39, 0xa4, 0xdc, 0x1d, 0xd0, + 0xdb, 0xdf, 0x23, 0xd7, 0x78, 0x39, 0x10, 0xb7, 0x4a, 0x0d, 0xc3, 0xd7, + 0xab, 0xe8, 0xe6, 0x1a, 0xc6, 0xb2, 0x17, 0x99, 0x3f, 0xb6, 0x05, 0x7a, + 0xec, 0xe7, 0x8b, 0x4a, 0x64, 0x05, 0xae, 0xb4, 0xbf, 0xdd, 0xd2, 0x0c, + 0x23, 0xf5, 0xb2, 0xac, 0x77, 0xf1, 0x77, 0x0c, 0xf3, 0xed, 0x6b, 0x6d, + 0x08, 0xda, 0xff, 0x57, 0xe5, 0xbe, 0xef, 0xd2, 0x82, 0x1a, 0xfb, 0xff, + 0x1d, 0x98, 0x9b, 0xba, 0xb0, 0x2e, 0x8c, 0x4d, 0xa6, 0x65, 0x3d, 0x67, + 0x5a, 0x38, 0x73, 0x71, 0xbf, 0xf3, 0x0a, 0x07, 0xf3, 0x0d, 0x52, 0xac, + 0x58, 0xf6, 0xfb, 0x54, 0x17, 0xdf, 0x97, 0x58, 0x7a, 0xc9, 0x7e, 0x67, + 0xf9, 0xae, 0x42, 0xa5, 0xfd, 0xfd, 0xb1, 0x79, 0x8b, 0x9c, 0x78, 0x29, + 0x51, 0x16, 0xf3, 0xf0, 0xf7, 0xe6, 0x45, 0x05, 0x58, 0x4f, 0x4e, 0xd6, + 0x74, 0xd5, 0x33, 0x38, 0x67, 0x7f, 0xc7, 0x21, 0x1e, 0x92, 0xef, 0x37, + 0x9c, 0x48, 0xd0, 0xa7, 0x07, 0xbb, 0x43, 0xfb, 0xed, 0xbe, 0x5f, 0xc7, + 0xa6, 0x51, 0x79, 0xe6, 0xd7, 0x8c, 0xd5, 0x89, 0x49, 0xc6, 0x37, 0x69, + 0x4b, 0xf2, 0x6e, 0x3d, 0xd3, 0xc6, 0x5c, 0x55, 0x75, 0x04, 0x71, 0x3b, + 0xe3, 0xca, 0x2b, 0x09, 0xda, 0xe9, 0x42, 0xbd, 0xe3, 0xdb, 0xe4, 0x06, + 0x65, 0x11, 0x3d, 0xf8, 0xae, 0xd2, 0x82, 0x31, 0xd6, 0x9f, 0x48, 0x88, + 0x2d, 0x56, 0xc6, 0x0a, 0x39, 0x96, 0x43, 0xe4, 0xa3, 0x2f, 0x27, 0x34, + 0x9c, 0xab, 0xf7, 0x20, 0x45, 0x7e, 0xfa, 0x52, 0x42, 0xb8, 0x9a, 0x17, + 0x4f, 0x0c, 0xca, 0xfa, 0x60, 0x23, 0x1a, 0x12, 0xb2, 0x36, 0xec, 0xc5, + 0xe3, 0x23, 0x5e, 0xda, 0xa3, 0x65, 0x6d, 0xa2, 0xed, 0xb6, 0x6a, 0x13, + 0xec, 0x53, 0xd6, 0x14, 0xa3, 0xb8, 0xa9, 0xb7, 0x12, 0x4f, 0x8c, 0xf8, + 0xf0, 0x3d, 0xf2, 0xf1, 0x3e, 0xd6, 0x7b, 0x25, 0xe1, 0x47, 0x6f, 0xca, + 0x87, 0xe7, 0xc9, 0xcb, 0xb7, 0xf2, 0x5c, 0xbe, 0x05, 0x56, 0x60, 0x04, + 0x91, 0x48, 0x1d, 0x63, 0x6c, 0xbc, 0x02, 0x6b, 0x57, 0x1e, 0x81, 0xda, + 0x7b, 0x94, 0xc7, 0xf5, 0x8c, 0xd5, 0xd7, 0x23, 0x39, 0x18, 0x41, 0x72, + 0xe4, 0x87, 0xe8, 0x19, 0x94, 0x71, 0xc9, 0x37, 0xa1, 0x64, 0x6f, 0x91, + 0x81, 0xf9, 0x8c, 0xa7, 0x43, 0x23, 0xd2, 0x4f, 0x25, 0xfb, 0xfe, 0x4b, + 0xdb, 0xff, 0x99, 0xb5, 0xf6, 0xf3, 0xd2, 0xf6, 0x91, 0x3f, 0xd1, 0xbe, + 0xe8, 0x2a, 0xff, 0x6e, 0x9f, 0xac, 0x73, 0xb8, 0xd9, 0xa6, 0x07, 0x8e, + 0x48, 0x66, 0x65, 0x29, 0xf4, 0xe8, 0x76, 0xc5, 0x68, 0x2a, 0x51, 0x26, + 0xb1, 0x3d, 0x2d, 0xef, 0x71, 0x15, 0xe2, 0x79, 0x72, 0x02, 0x57, 0x48, + 0xd7, 0xbe, 0x4d, 0xdb, 0x59, 0x42, 0x8c, 0x39, 0x63, 0x7e, 0x1a, 0x71, + 0x4d, 0xf4, 0x57, 0x88, 0x57, 0xfb, 0xdd, 0x78, 0x37, 0xc4, 0x98, 0x6d, + 0xef, 0xa1, 0xf6, 0xe0, 0x27, 0x09, 0x2f, 0xe7, 0xab, 0x36, 0x63, 0x38, + 0xe6, 0x02, 0x55, 0xd9, 0x6b, 0x27, 0x12, 0x6d, 0xd8, 0x4f, 0x79, 0x5f, + 0x49, 0x9c, 0xe7, 0xfc, 0xac, 0xa3, 0xfe, 0x45, 0xdf, 0xf1, 0x9c, 0xae, + 0xbb, 0xa9, 0xeb, 0x99, 0x78, 0x31, 0xf1, 0x30, 0x9e, 0xa0, 0xfc, 0x8f, + 0xf7, 0x1b, 0xd1, 0x39, 0xca, 0x31, 0x1c, 0x1a, 0x2a, 0x24, 0x7e, 0xbb, + 0x71, 0x37, 0xb3, 0xe4, 0x49, 0xe9, 0x2b, 0x29, 0x6b, 0x93, 0x0a, 0xb9, + 0xc7, 0x31, 0x8c, 0xf3, 0xde, 0x4f, 0xf8, 0x3b, 0xbc, 0xb0, 0x9c, 0x7d, + 0x88, 0x7e, 0xfc, 0x76, 0x1e, 0xd0, 0x45, 0x7e, 0xb3, 0xbc, 0xfe, 0x98, + 0xcd, 0x79, 0xba, 0x93, 0xad, 0xe8, 0xe9, 0x7f, 0x9f, 0x7c, 0x8e, 0x38, + 0xe4, 0xad, 0xa7, 0xad, 0x67, 0xb0, 0x3d, 0xf5, 0xef, 0x55, 0x59, 0xee, + 0xf9, 0x6a, 0x95, 0xec, 0xeb, 0x3d, 0x91, 0x28, 0xc4, 0x4b, 0xac, 0xb3, + 0x36, 0xe4, 0xca, 0x3d, 0x2f, 0x39, 0x86, 0x5e, 0xe2, 0x6a, 0x8a, 0x7d, + 0x24, 0xec, 0x36, 0xaa, 0x94, 0xbd, 0xf4, 0xc3, 0xf2, 0x85, 0x55, 0x4a, + 0x92, 0xe7, 0x7d, 0xc9, 0x1f, 0xe2, 0xd9, 0x47, 0xb2, 0x3a, 0xdc, 0x6f, + 0xb6, 0x61, 0x28, 0x75, 0x2a, 0xd7, 0xde, 0x8f, 0xa7, 0xbc, 0x9b, 0x26, + 0xef, 0xba, 0xe4, 0xdf, 0x7b, 0xc9, 0x3e, 0xcf, 0x7a, 0x2a, 0x5d, 0x46, + 0xde, 0x5c, 0x4c, 0x5b, 0x2b, 0x88, 0x79, 0x19, 0x4f, 0xdb, 0x16, 0x68, + 0xd8, 0x75, 0xcd, 0x9c, 0x2a, 0x94, 0x69, 0xee, 0x5f, 0xd7, 0xbf, 0xcc, + 0x7e, 0xca, 0x62, 0x15, 0x91, 0x8c, 0xbd, 0x07, 0x2a, 0x74, 0x4d, 0x35, + 0x73, 0x68, 0x79, 0x2e, 0x1c, 0xc3, 0xdb, 0x89, 0xca, 0x58, 0x65, 0xa4, + 0x9c, 0x78, 0x7b, 0x0e, 0xbd, 0xc3, 0xc4, 0x76, 0xf2, 0xe5, 0xd2, 0xbe, + 0x4a, 0xb8, 0xed, 0x35, 0xbc, 0x2b, 0x30, 0x63, 0xf7, 0x2c, 0xf8, 0x76, + 0xcf, 0x24, 0x5f, 0x61, 0x6e, 0x19, 0xb2, 0xac, 0x9f, 0x2f, 0xb4, 0xac, + 0x2b, 0x79, 0x14, 0xf1, 0x38, 0x1b, 0x12, 0x3f, 0x8d, 0xa2, 0xd6, 0xf6, + 0x57, 0x03, 0x75, 0xf6, 0xff, 0x46, 0xfa, 0x7a, 0x47, 0x68, 0xfe, 0xf8, + 0xc3, 0xa1, 0xb9, 0xe3, 0xd5, 0x50, 0x07, 0xa6, 0xc1, 0xc1, 0xb6, 0x3e, + 0x77, 0x8d, 0x85, 0x46, 0xfa, 0xf0, 0x1a, 0x53, 0xf8, 0x50, 0x1b, 0xf9, + 0x50, 0x4f, 0xc8, 0x18, 0x3f, 0x82, 0x1b, 0xc9, 0x97, 0xdd, 0x03, 0x3e, + 0xf6, 0x23, 0xf9, 0xb5, 0x33, 0x33, 0x9b, 0x3c, 0xfb, 0xd3, 0x0b, 0x85, + 0x1b, 0xb5, 0x90, 0x1b, 0x1d, 0x45, 0xcb, 0xf8, 0x31, 0xdc, 0xca, 0x32, + 0x1e, 0xe6, 0xfd, 0x7d, 0xe9, 0x1f, 0x92, 0x77, 0x58, 0x8c, 0x39, 0x19, + 0xdc, 0xcc, 0xb6, 0x8b, 0x07, 0x9a, 0x70, 0xf7, 0xf8, 0x0a, 0xac, 0x1d, + 0xb7, 0xb0, 0x3c, 0x34, 0x81, 0xe5, 0xe3, 0xe4, 0x9a, 0xe3, 0x79, 0x7f, + 0x15, 0x9e, 0xb4, 0x82, 0x3c, 0x49, 0xe2, 0xd0, 0x2a, 0x7b, 0x1d, 0x4d, + 0xa5, 0x1f, 0x36, 0x24, 0xe4, 0x9d, 0x9b, 0x38, 0x56, 0x8f, 0x0b, 0x56, + 0x3f, 0x88, 0x4d, 0xe3, 0xb2, 0x2e, 0xfb, 0xf5, 0xd0, 0x9c, 0xf1, 0xd7, + 0xd1, 0x30, 0x3e, 0x14, 0x9a, 0x37, 0x3e, 0x42, 0xb9, 0x13, 0x94, 0xad, + 0x3f, 0x54, 0x33, 0x3e, 0x18, 0x0a, 0x8e, 0xef, 0x0d, 0x05, 0xc6, 0x9b, + 0xb1, 0x75, 0x7c, 0x15, 0xb6, 0x8c, 0xb7, 0x63, 0xf3, 0xb8, 0xe0, 0xfc, + 0x24, 0x96, 0x8d, 0x9f, 0xc1, 0xd2, 0xf1, 0x97, 0xd1, 0x38, 0x7e, 0x0a, + 0x4b, 0xc6, 0x7f, 0x88, 0xa6, 0xf1, 0x1f, 0x73, 0x2c, 0xb2, 0xce, 0x2b, + 0x6b, 0xbc, 0xf9, 0x67, 0x6a, 0xf9, 0xf7, 0x44, 0xf3, 0xdf, 0xd7, 0x70, + 0x21, 0xaa, 0xbd, 0x81, 0xee, 0x3d, 0xf2, 0xbd, 0xc1, 0x5a, 0x6d, 0x93, + 0xfd, 0xbe, 0xc1, 0xcb, 0xb2, 0x4f, 0x1d, 0x45, 0xc6, 0xe5, 0xef, 0xc5, + 0xcb, 0x77, 0x31, 0xe4, 0x39, 0xe7, 0x24, 0xba, 0xd2, 0xe7, 0xad, 0xa8, + 0x26, 0x65, 0xde, 0xc0, 0xe6, 0x3d, 0xf2, 0x3e, 0x71, 0x06, 0x5d, 0x49, + 0x79, 0x0e, 0x2f, 0xef, 0xa0, 0xbf, 0x81, 0x2d, 0xa3, 0xb6, 0xaf, 0xa1, + 0x71, 0x48, 0xde, 0x89, 0x69, 0xc3, 0x75, 0xc9, 0x8c, 0xbd, 0x56, 0x5e, + 0x66, 0xe0, 0xef, 0x67, 0xe0, 0x41, 0xe6, 0x04, 0x05, 0xe4, 0xfd, 0xc5, + 0xe8, 0x7c, 0x24, 0x6e, 0x15, 0x1a, 0x1e, 0xcc, 0x88, 0x18, 0x99, 0x77, + 0x1d, 0xc5, 0xe8, 0xe0, 0xb5, 0xfb, 0x76, 0xc2, 0xef, 0x33, 0x44, 0xf7, + 0x81, 0xd8, 0x28, 0x63, 0xec, 0x86, 0x7d, 0x19, 0xf2, 0x8b, 0x0e, 0xf8, + 0xf9, 0x7f, 0x7b, 0x52, 0xf6, 0x21, 0x6d, 0x42, 0x74, 0x9f, 0xe8, 0xb0, + 0x99, 0x3a, 0x9c, 0x64, 0xdc, 0x90, 0x67, 0x38, 0x46, 0x70, 0x2b, 0x64, + 0x9d, 0x52, 0xc5, 0xf7, 0x06, 0xe5, 0x79, 0x83, 0xde, 0xf1, 0x25, 0xfa, + 0xf4, 0x87, 0xca, 0x0f, 0x51, 0x76, 0x40, 0xf8, 0xd2, 0x04, 0x7a, 0x84, + 0x6f, 0x47, 0x14, 0x23, 0x15, 0x38, 0x0b, 0xcf, 0x01, 0xc1, 0x5d, 0x27, + 0x4a, 0xc6, 0xe4, 0xfb, 0x38, 0x40, 0x31, 0xf3, 0x12, 0x1c, 0x20, 0xa7, + 0x3d, 0x70, 0x0a, 0xd8, 0x27, 0xeb, 0x56, 0xaf, 0x61, 0x72, 0x48, 0xe6, + 0xad, 0x8d, 0xf3, 0x26, 0x7e, 0xf8, 0x7d, 0x0c, 0x0f, 0x79, 0xe8, 0xe3, + 0x13, 0x1c, 0xc7, 0xeb, 0x78, 0x74, 0x8f, 0x3c, 0x17, 0x99, 0x89, 0x36, + 0xd6, 0x3b, 0xc1, 0x3c, 0xbf, 0x75, 0xcc, 0xe4, 0x78, 0x56, 0xa1, 0xf3, + 0xc0, 0x17, 0x78, 0x4c, 0xc3, 0x43, 0x07, 0xd6, 0x71, 0x8c, 0x71, 0x74, + 0x8c, 0x75, 0xf3, 0x68, 0xc5, 0xc6, 0x9d, 0x26, 0xb9, 0xa0, 0xd8, 0xb4, + 0x46, 0x3f, 0x6b, 0xe5, 0x98, 0xa4, 0x8f, 0xd5, 0xf8, 0x19, 0x31, 0xa6, + 0x29, 0xb4, 0x1a, 0xe7, 0x6c, 0xbf, 0x5b, 0x8d, 0x2d, 0xfd, 0x46, 0xf0, + 0x24, 0x56, 0x63, 0x33, 0xcf, 0x1f, 0xa5, 0xef, 0xcf, 0x21, 0x17, 0xbc, + 0x93, 0xbe, 0xbd, 0x78, 0x78, 0x42, 0xbe, 0x9d, 0x80, 0xbe, 0x5d, 0x32, + 0x1f, 0x6d, 0xf0, 0x8d, 0x65, 0x50, 0x3e, 0xc6, 0xec, 0x79, 0x27, 0xee, + 0x2a, 0x43, 0x39, 0xbe, 0x11, 0x92, 0x3d, 0x0b, 0x3f, 0x40, 0xf1, 0x3e, + 0x91, 0xf5, 0x87, 0x6c, 0xfb, 0x1c, 0x73, 0xf1, 0x53, 0x9c, 0x83, 0xfc, + 0xb3, 0xf1, 0x5f, 0xe0, 0x60, 0x6a, 0x92, 0xb8, 0x7a, 0x9a, 0xc7, 0xe5, + 0xcf, 0xa5, 0xbd, 0x76, 0x8e, 0x92, 0xdd, 0xff, 0xed, 0xc4, 0x8c, 0x3e, + 0x59, 0xdf, 0x6d, 0x86, 0x2f, 0x29, 0x7c, 0x27, 0xb3, 0x8d, 0xf9, 0x4a, + 0x7b, 0xd8, 0xe6, 0x3f, 0x46, 0x8c, 0xbc, 0xa7, 0xf9, 0xdb, 0x8a, 0x87, + 0xbc, 0x27, 0x88, 0x15, 0x69, 0x3d, 0x7a, 0x33, 0xf5, 0x5b, 0xf4, 0xc8, + 0x8f, 0xe0, 0x7c, 0xc4, 0x89, 0x42, 0xe6, 0x37, 0xa1, 0x90, 0xe8, 0x59, + 0xde, 0x95, 0xcd, 0xe8, 0x85, 0xc4, 0xcc, 0x82, 0xbe, 0x0c, 0xe7, 0x27, + 0x33, 0xbf, 0x00, 0x7e, 0xce, 0xcd, 0x0d, 0x68, 0xeb, 0x8f, 0x72, 0x6e, + 0x3e, 0x45, 0x1b, 0x9b, 0xa0, 0xbd, 0x48, 0x4e, 0xf4, 0x32, 0x65, 0x74, + 0xe5, 0xbe, 0xc9, 0x93, 0xd1, 0x9d, 0xd0, 0x4d, 0xbf, 0x5a, 0x95, 0x7d, + 0x27, 0x05, 0xf6, 0xb3, 0xe7, 0x30, 0xf0, 0x06, 0x6d, 0x33, 0xcf, 0x67, + 0x2c, 0xab, 0x9d, 0xf6, 0xd5, 0x3f, 0x2a, 0xbe, 0xb2, 0xb4, 0x2a, 0xfb, + 0xbe, 0xee, 0x54, 0xae, 0x93, 0xaf, 0xeb, 0x20, 0x36, 0xe6, 0xef, 0xff, + 0x08, 0x77, 0x32, 0x7e, 0x9d, 0x59, 0x78, 0x2a, 0x67, 0xf3, 0xd3, 0xab, + 0xb3, 0xf8, 0xf5, 0x49, 0xdf, 0x0b, 0xfa, 0x2b, 0xfb, 0xdb, 0x3b, 0xd9, + 0x6f, 0x1f, 0x01, 0xcf, 0x26, 0x0a, 0xe4, 0x29, 0xc1, 0x62, 0x17, 0x54, + 0xaf, 0x0b, 0x85, 0x8c, 0x01, 0xd5, 0xd8, 0xe4, 0xb5, 0x70, 0xa3, 0x59, + 0x80, 0x43, 0x75, 0xb7, 0x00, 0x15, 0xf1, 0x16, 0x97, 0xfd, 0x4e, 0xde, + 0xef, 0xbf, 0xf4, 0x87, 0xef, 0xe4, 0x9d, 0xb1, 0xf3, 0xe1, 0x52, 0xe3, + 0x76, 0xbc, 0x62, 0xc7, 0x09, 0x05, 0x25, 0x73, 0x65, 0x5d, 0xd2, 0x8f, + 0x17, 0x8d, 0x5a, 0x7f, 0x85, 0x3c, 0x6f, 0x52, 0xce, 0x5a, 0x71, 0xaf, + 0xbc, 0x87, 0xf7, 0xc7, 0xf6, 0x8f, 0x3f, 0x87, 0xad, 0xbb, 0xc2, 0x90, + 0xf7, 0x3b, 0x9c, 0x46, 0xa1, 0x37, 0x2b, 0xbf, 0xc8, 0x26, 0xeb, 0x44, + 0xb7, 0x71, 0x1c, 0x67, 0xe8, 0x8b, 0x67, 0xec, 0x75, 0x2a, 0xb7, 0xf1, + 0xd7, 0x08, 0x56, 0xe4, 0xc7, 0x2f, 0x39, 0x8d, 0x92, 0xd5, 0x41, 0xf6, + 0xfd, 0xda, 0x6a, 0xc1, 0xfe, 0x2d, 0xc9, 0x33, 0xf6, 0x9a, 0xac, 0xcb, + 0xf8, 0x0f, 0xeb, 0x2d, 0x6f, 0x25, 0xcb, 0x3e, 0x95, 0xbb, 0x3f, 0x29, + 0xeb, 0x38, 0xa6, 0x7c, 0xbb, 0xca, 0x69, 0xd7, 0x11, 0xbd, 0x5f, 0xac, + 0xb3, 0x89, 0xbc, 0x7a, 0xb6, 0x71, 0xca, 0xea, 0xf4, 0xca, 0x18, 0xd6, + 0x5c, 0x56, 0x47, 0xd6, 0x08, 0x34, 0xe9, 0x37, 0x2c, 0x63, 0xee, 0x4a, + 0xff, 0x61, 0x9f, 0xb2, 0x7e, 0x5b, 0x60, 0x94, 0xe0, 0x6c, 0x45, 0x76, + 0x4d, 0xe5, 0xa2, 0x8c, 0xed, 0xd5, 0xb2, 0xef, 0xae, 0xd0, 0x3e, 0xb7, + 0xfb, 0x35, 0x2f, 0xd6, 0x7b, 0x30, 0x37, 0xde, 0x4a, 0xfb, 0x9d, 0x9a, + 0x47, 0x6d, 0xae, 0xe3, 0x98, 0x32, 0xee, 0xdf, 0x78, 0x2f, 0xed, 0xe7, + 0xf3, 0xb9, 0x7e, 0x45, 0x1e, 0xef, 0x94, 0x3e, 0x44, 0xae, 0xde, 0x5c, + 0x1d, 0x3d, 0x1c, 0xb5, 0xfb, 0x57, 0x11, 0xde, 0x93, 0xef, 0xd3, 0xb2, + 0x0a, 0x16, 0xe6, 0xdb, 0xc8, 0xd0, 0x0f, 0xad, 0xce, 0x42, 0xc6, 0xab, + 0xb3, 0xf5, 0x0f, 0x62, 0x73, 0x42, 0xf4, 0x2c, 0xdf, 0x70, 0x25, 0x2e, + 0xdb, 0xfc, 0xcb, 0xc5, 0x5c, 0xf6, 0x1a, 0x0c, 0x69, 0x71, 0xec, 0xaf, + 0x93, 0x77, 0xc8, 0x5c, 0xf4, 0x85, 0x38, 0x71, 0xb0, 0x90, 0x38, 0x1a, + 0xb7, 0xf7, 0x94, 0x1c, 0x34, 0xf5, 0xe8, 0xb3, 0xf2, 0x8d, 0xb2, 0xab, + 0xec, 0xb5, 0xa7, 0xa6, 0x21, 0xc8, 0xf5, 0xfc, 0x7a, 0x52, 0xfe, 0xaf, + 0x88, 0xb6, 0x23, 0x72, 0x89, 0x0d, 0x50, 0xba, 0x84, 0xbc, 0xeb, 0x54, + 0x1b, 0x23, 0x67, 0xc4, 0x2b, 0x29, 0xd9, 0x7f, 0xf0, 0x5b, 0x2b, 0x5e, + 0x2d, 0xfb, 0x1c, 0xa7, 0xd6, 0x29, 0x20, 0x97, 0x0b, 0x84, 0xcb, 0x94, + 0xfc, 0xfb, 0x4e, 0x17, 0xff, 0x6e, 0xa5, 0xcd, 0x9c, 0xb3, 0xdf, 0x51, + 0x93, 0xb3, 0x08, 0x1a, 0x92, 0xf2, 0xad, 0x52, 0x7d, 0x62, 0x39, 0x6a, + 0x33, 0x35, 0x0e, 0x67, 0x8e, 0x93, 0x84, 0xb1, 0x82, 0x76, 0xb3, 0x25, + 0x10, 0xb6, 0xdf, 0xc5, 0x5a, 0x96, 0xac, 0x09, 0x3e, 0xce, 0x1c, 0xfa, + 0x1d, 0x96, 0xbf, 0x25, 0xfd, 0x3d, 0x6b, 0xc8, 0x2b, 0x63, 0xca, 0x63, + 0xc3, 0x29, 0xfa, 0x06, 0xf5, 0x18, 0x11, 0xff, 0xf0, 0xa0, 0x22, 0x12, + 0xa6, 0xff, 0x4a, 0x4c, 0x97, 0xf7, 0xb8, 0xf4, 0xbd, 0x71, 0x98, 0xc4, + 0xfc, 0x1e, 0xda, 0x91, 0xec, 0x5b, 0xd6, 0xfd, 0x2b, 0x19, 0x5b, 0x8e, + 0x5f, 0x78, 0xc6, 0x2f, 0x1c, 0xe0, 0xd9, 0xea, 0xdc, 0xde, 0x66, 0xf7, + 0x6c, 0xc6, 0x3c, 0xcb, 0x7e, 0x6e, 0xdf, 0x66, 0x63, 0x8a, 0x66, 0xe8, + 0x87, 0x7e, 0xe5, 0xe8, 0xc4, 0xd3, 0x0b, 0x8c, 0x8e, 0xc3, 0x6a, 0x66, + 0xc8, 0x47, 0x7c, 0xb9, 0xde, 0x11, 0xdd, 0xc9, 0xff, 0xfe, 0xd7, 0xec, + 0x6f, 0xab, 0x48, 0x5d, 0x3d, 0xb8, 0x4a, 0x95, 0xfd, 0x40, 0xcd, 0x18, + 0xeb, 0x95, 0x77, 0x06, 0xf4, 0x96, 0xa7, 0x94, 0x4e, 0x6c, 0x08, 0x19, + 0xcd, 0xed, 0x8a, 0xde, 0xf4, 0x0f, 0x8a, 0xee, 0x0f, 0x29, 0x52, 0x2e, + 0xc8, 0xbc, 0xeb, 0x62, 0x3c, 0x75, 0xb1, 0x8f, 0x03, 0x09, 0x3d, 0x5c, + 0xc5, 0xb2, 0x67, 0x4d, 0xc3, 0xf7, 0x3e, 0xdb, 0xfc, 0x57, 0x1e, 0x3b, + 0xed, 0xf7, 0xc4, 0xa5, 0x7c, 0x74, 0xbe, 0xcb, 0xfe, 0xbe, 0x69, 0x0b, + 0xe3, 0xae, 0x7c, 0x23, 0x38, 0x06, 0xad, 0x6f, 0x26, 0x4d, 0x4c, 0xef, + 0xb9, 0x0d, 0xb2, 0xe7, 0xa0, 0x89, 0x09, 0xba, 0x07, 0xde, 0x48, 0x27, + 0xe6, 0x2e, 0x30, 0x7c, 0x8b, 0x54, 0xbb, 0x7e, 0x30, 0xaa, 0x4a, 0x7d, + 0xdd, 0x3f, 0x08, 0x69, 0x23, 0x63, 0x69, 0x73, 0xcb, 0xed, 0x3a, 0x0b, + 0xd4, 0xcf, 0xc0, 0x75, 0xf5, 0xaf, 0xe5, 0x5b, 0x46, 0x5a, 0xa5, 0x21, + 0x75, 0xe2, 0x3b, 0x35, 0xfc, 0xb1, 0x7a, 0x82, 0x2b, 0xbf, 0xb2, 0x30, + 0x4d, 0xea, 0xc9, 0x9e, 0xb1, 0x3b, 0x70, 0xaf, 0xfd, 0x3d, 0x16, 0xf1, + 0x47, 0x3d, 0xfa, 0x15, 0xf2, 0xcf, 0x62, 0x45, 0xb8, 0xa7, 0xf0, 0x84, + 0x56, 0x74, 0x33, 0x8e, 0x69, 0x21, 0xbd, 0xe7, 0x0a, 0xd5, 0x83, 0xc2, + 0xc8, 0x63, 0xb2, 0x6f, 0x66, 0xef, 0x3c, 0x35, 0xbb, 0xbf, 0x26, 0xc6, + 0x76, 0x8f, 0xff, 0xd1, 0xe7, 0xb8, 0xec, 0xab, 0xd8, 0x94, 0xf7, 0x5b, + 0xec, 0x35, 0xc5, 0xd6, 0x84, 0x23, 0xb7, 0x5f, 0x30, 0x3f, 0xb7, 0x1a, + 0xda, 0xc8, 0xf5, 0xd7, 0xc8, 0x37, 0x31, 0x39, 0xd6, 0xb5, 0x09, 0x59, + 0x4d, 0xfa, 0xff, 0x00, 0x85, 0x57, 0x0f, 0xe7, 0xe8, 0x59, 0x00, 0x00, + 0x00 }; + +static const u32 bnx2_CP_b06FwData[(0x84/4) + 1] = { + 0x00000000, 0x0000001b, 0x0000000f, 0x0000000a, 0x00000008, 0x00000006, + 0x00000005, 0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000003, + 0x00000003, 0x00000003, 0x00000003, 0x00000002, 0x00000002, 0x00000002, + 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x00000001, 0x00000001, 0x00000001, 0x00000000 }; +static const u32 bnx2_CP_b06FwRodata[(0x130/4) + 1] = { + 0x08001f1c, 0x08001da8, 0x08001ef8, 0x08001ed4, 0x08001eb0, 0x08001e8c, + 0x08001e64, 0x08001e3c, 0x08001e10, 0x08002014, 0x08002004, 0x08001dc4, + 0x08001dc4, 0x08001dc4, 0x08001f44, 0x08001f44, 0x08001dc4, 0x08001dc4, + 0x08001ff4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fe4, + 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, + 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, + 0x08001dc4, 0x08001dc4, 0x08001fd4, 0x08001dc4, 0x08001dc4, 0x08001fc4, + 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, + 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, + 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001dc4, 0x08001fac, + 0x08001dc4, 0x08001dc4, 0x08001f9c, 0x08001f8c, 0x080031e8, 0x080031f0, + 0x080031b8, 0x080031c4, 0x080031d0, 0x080031dc, 0x08005644, 0x08005604, + 0x080055d0, 0x080055a4, 0x08005580, 0x0800553c, 0x00000000 }; + +static struct fw_info bnx2_cp_fw_06 = { + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, + + .start_addr = 0x08000078, + + .text_addr = 0x08000000, + .text_len = 0x59e4, + .text_index = 0x0, + .gz_text = bnx2_CP_b06FwText, + .gz_text_len = sizeof(bnx2_CP_b06FwText), + + .data_addr = 0x08005b40, + .data_len = 0x84, + .data_index = 0x0, + .data = bnx2_CP_b06FwData, + + .sbss_addr = 0x08005bc4, + .sbss_len = 0xe9, + .sbss_index = 0x0, + + .bss_addr = 0x08005cb0, + .bss_len = 0x5d8, + .bss_index = 0x0, + + .rodata_addr = 0x080059e4, + .rodata_len = 0x130, + .rodata_index = 0x0, + .rodata = bnx2_CP_b06FwRodata, +}; + static u8 bnx2_RXP_b06FwText[] = { -/* 0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ - 0xec, 0x5c, 0x6f, 0x6c, - 0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e, - 0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d, - 0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a, - 0x51, 0x0d, 0x1d, 0x1b, 0x85, 0x6b, 0xb0, 0x47, 0x39, 0xae, 0xdb, 0x7e, - 0x90, 0x65, 0x1b, 0x30, 0xda, 0x10, 0xbe, 0x1c, 0xe9, 0x46, 0x75, 0x2f, - 0xdc, 0x8b, 0xc4, 0x98, 0x06, 0xfa, 0x07, 0x57, 0x92, 0xfa, 0x83, 0xe0, - 0xa0, 0x93, 0xe2, 0x26, 0xf5, 0x17, 0x57, 0x84, 0x2a, 0xc7, 0xf9, 0xe0, - 0x02, 0x4e, 0x63, 0x20, 0x06, 0xea, 0x16, 0xaa, 0xec, 0xd8, 0x46, 0x81, - 0xa2, 0x42, 0x1c, 0xd8, 0x46, 0xfc, 0x67, 0xfb, 0x7b, 0x33, 0xbb, 0xd4, - 0x91, 0x96, 0x6d, 0xa0, 0x1f, 0xfa, 0xa5, 0x3b, 0xc0, 0x61, 0x67, 0x66, - 0xe7, 0xbd, 0x79, 0xf3, 0xfe, 0xbf, 0x59, 0x4a, 0x7f, 0x90, 0xa4, 0x2e, - 0x0a, 0x5b, 0x37, 0x7e, 0xd6, 0x91, 0xc7, 0x8f, 0xde, 0x3c, 0x76, 0xf3, - 0x28, 0xd1, 0x97, 0x47, 0xf5, 0x1b, 0x12, 0x22, 0x9a, 0x8f, 0x5b, 0xdc, - 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, - 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, - 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, - 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, - 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, - 0x2d, 0x6e, 0x71, 0xfb, 0xff, 0xde, 0x74, 0x22, 0x93, 0x9f, 0xdd, 0xe1, - 0x8f, 0x12, 0x22, 0xbf, 0xfa, 0x90, 0xe7, 0x50, 0x42, 0xcf, 0xbf, 0x34, - 0x33, 0xed, 0x10, 0x15, 0x9a, 0x7b, 0xac, 0x22, 0x7d, 0x14, 0x54, 0xd2, - 0x06, 0xf1, 0xfc, 0x17, 0xf2, 0x1f, 0x3e, 0xf1, 0xfc, 0xad, 0xf6, 0xd5, - 0x86, 0x4e, 0x09, 0x33, 0x3f, 0xb7, 0xd7, 0xdc, 0x4d, 0x89, 0x41, 0xc0, - 0xfc, 0xf5, 0xf0, 0x7f, 0xf4, 0x50, 0x0f, 0x5d, 0xc3, 0xe3, 0x24, 0xe8, - 0xb2, 0xfe, 0x9c, 0xe6, 0xb5, 0x82, 0xe0, 0xa4, 0x1b, 0x04, 0x3f, 0xc6, - 0xef, 0x2d, 0x17, 0x63, 0xff, 0xe3, 0xa0, 0x60, 0xe8, 0x24, 0x9c, 0xbf, - 0xd4, 0xbc, 0xe5, 0x2e, 0xaa, 0x2e, 0x1a, 0x34, 0xeb, 0xa7, 0xe9, 0x98, - 0x5f, 0xd1, 0x4a, 0xad, 0x9a, 0xb6, 0xef, 0xf4, 0xbc, 0x76, 0xe7, 0xe9, - 0x63, 0xda, 0xfe, 0xd3, 0x75, 0xcd, 0x3b, 0x4d, 0x15, 0xb1, 0x37, 0x49, - 0x05, 0xf3, 0x8c, 0x56, 0x6c, 0x0d, 0x68, 0xde, 0x89, 0x0f, 0xc9, 0x73, - 0x6d, 0xf3, 0xf7, 0xc8, 0x28, 0x80, 0x16, 0xf2, 0x6a, 0x41, 0xe0, 0xb9, - 0x06, 0x15, 0xd2, 0x41, 0x20, 0xf2, 0xc1, 0x13, 0x5e, 0xce, 0x31, 0x85, - 0x96, 0xa6, 0x6a, 0x6b, 0x00, 0x78, 0x93, 0x5a, 0x71, 0xd1, 0xd0, 0x4a, - 0x7e, 0x70, 0xc1, 0x73, 0x69, 0x50, 0xa7, 0x20, 0x98, 0x73, 0x77, 0x65, - 0x0e, 0xd3, 0x29, 0xe0, 0x6d, 0x02, 0x1f, 0x99, 0x22, 0xcf, 0xf4, 0x31, - 0x9d, 0x4c, 0x72, 0x45, 0x2b, 0x0e, 0x47, 0xf4, 0x91, 0xc5, 0xf4, 0x97, - 0x57, 0x04, 0xe8, 0xdc, 0x42, 0xe5, 0x86, 0x49, 0x53, 0x2b, 0x1b, 0xd7, - 0x5f, 0x0e, 0x9e, 0x1f, 0x36, 0xe9, 0x5c, 0xcb, 0xae, 0x54, 0x28, 0x41, - 0x73, 0xbe, 0x45, 0x22, 0x4f, 0x05, 0x2f, 0x37, 0x48, 0x17, 0x5a, 0x19, - 0xfa, 0x41, 0xcb, 0xc9, 0x54, 0x69, 0x13, 0x95, 0xd3, 0x69, 0x3a, 0xdf, - 0x4a, 0xe3, 0x8c, 0xc1, 0x05, 0xe1, 0x38, 0x66, 0x15, 0x6b, 0xab, 0xad, - 0x97, 0xf8, 0xdf, 0xbf, 0x98, 0xd3, 0x39, 0x09, 0x53, 0x01, 0xdd, 0xe1, - 0x5a, 0x3e, 0x87, 0x5c, 0x2b, 0xcf, 0xa2, 0xd6, 0x52, 0x65, 0x3a, 0x87, - 0xb9, 0xd6, 0x1d, 0x6b, 0xfc, 0x2d, 0xa4, 0xf9, 0x69, 0x52, 0xd5, 0xef, - 0x00, 0x6f, 0xb8, 0x3f, 0x88, 0xb3, 0xee, 0xd0, 0xbc, 0xc5, 0x7f, 0x65, - 0xbc, 0x69, 0x41, 0x3b, 0x30, 0x1e, 0xc4, 0x98, 0xfb, 0xbb, 0x32, 0x65, - 0x02, 0x8f, 0x5b, 0x49, 0x8c, 0x99, 0xce, 0x20, 0xd8, 0xef, 0x92, 0x59, - 0x75, 0x7b, 0x01, 0x6b, 0x51, 0xd5, 0xed, 0x01, 0xbe, 0x0e, 0xea, 0x73, - 0xf8, 0x7c, 0xbc, 0xe7, 0x66, 0xcc, 0x07, 0xdd, 0x7a, 0x3e, 0x08, 0xa6, - 0x73, 0xd4, 0xa3, 0xe6, 0xf6, 0x48, 0x1c, 0x53, 0x13, 0x1a, 0xd6, 0xbd, - 0xc3, 0x7b, 0x24, 0x52, 0x79, 0xee, 0xf3, 0x33, 0x47, 0xde, 0xfc, 0x8e, - 0x90, 0xa6, 0x0c, 0x68, 0xba, 0x31, 0xec, 0x43, 0x0e, 0x3e, 0xf8, 0xe1, - 0xde, 0x80, 0xb1, 0xf6, 0x45, 0xe0, 0xc9, 0x56, 0x89, 0xf7, 0xe8, 0xa7, - 0xa5, 0x34, 0x89, 0x2b, 0x6e, 0x5f, 0xb8, 0xae, 0x07, 0xb4, 0x46, 0xfa, - 0x30, 0x40, 0x73, 0x8b, 0xcc, 0xf3, 0x1a, 0x64, 0x24, 0x68, 0xe7, 0x2d, - 0x15, 0xad, 0xd0, 0x3a, 0x86, 0xbe, 0x41, 0xd3, 0x4e, 0x70, 0x61, 0xce, - 0x9d, 0xd7, 0x8a, 0xa7, 0x4f, 0x69, 0xa5, 0xd3, 0xcf, 0x69, 0xfb, 0x5a, - 0x2f, 0x76, 0x53, 0x97, 0x8d, 0xd3, 0x27, 0xe8, 0x49, 0x5f, 0x23, 0xa6, - 0x73, 0x09, 0x3c, 0x2c, 0x98, 0x15, 0x32, 0x9c, 0x1e, 0xed, 0x4e, 0xe0, - 0xe9, 0x70, 0xfe, 0x2c, 0x49, 0x3d, 0x3a, 0x6d, 0x72, 0xa2, 0xb5, 0x69, - 0xfa, 0x73, 0xd0, 0x74, 0xd1, 0xdd, 0xca, 0x7c, 0xeb, 0x55, 0x30, 0xa9, - 0x90, 0x0e, 0xd6, 0x2f, 0x96, 0x9f, 0x6d, 0x7a, 0xba, 0xa0, 0xd2, 0xc2, - 0x5f, 0xf4, 0x57, 0x47, 0xb6, 0xf0, 0x3a, 0xd8, 0xc2, 0xd5, 0x87, 0xa6, - 0x1d, 0xaf, 0xcf, 0xa0, 0x8a, 0x29, 0xc8, 0x36, 0x8b, 0xf4, 0x45, 0x9a, - 0x73, 0x89, 0x8a, 0x35, 0xec, 0xeb, 0x18, 0xe0, 0x8f, 0x03, 0xfe, 0xec, - 0xaa, 0xe8, 0xe2, 0x1e, 0xa0, 0xa9, 0x68, 0x46, 0xc8, 0xcb, 0x25, 0xba, - 0x4b, 0xc2, 0x8b, 0xbc, 0x0b, 0x5d, 0xed, 0xe2, 0x3e, 0xf6, 0x4e, 0xc8, - 0xbd, 0xf5, 0xbc, 0x93, 0x59, 0x26, 0xd2, 0x44, 0x7e, 0x0f, 0xf0, 0xb1, - 0x0e, 0xf3, 0xba, 0x79, 0xd0, 0xc9, 0xf4, 0x73, 0xdf, 0x01, 0x4c, 0x02, - 0xfa, 0xde, 0xdd, 0x46, 0x2b, 0xe8, 0x49, 0x33, 0xbf, 0x99, 0x7f, 0xf2, - 0xac, 0xda, 0xb5, 0xb3, 0x7e, 0x10, 0x0c, 0x8f, 0x1a, 0xf4, 0x63, 0x79, - 0x66, 0xb6, 0x37, 0x5e, 0x97, 0x0e, 0xf5, 0x23, 0x01, 0x9d, 0x22, 0xad, - 0xec, 0x9a, 0x6b, 0xb8, 0xca, 0x44, 0x42, 0xcf, 0x27, 0xa9, 0x28, 0xe9, - 0x1b, 0xc3, 0x5e, 0x6c, 0x87, 0xb0, 0x27, 0x87, 0xcf, 0xc2, 0x73, 0x79, - 0xd8, 0xbb, 0xcd, 0x7d, 0x2a, 0xd7, 0xd9, 0xf6, 0x99, 0xb6, 0x55, 0x5b, - 0xfe, 0xd3, 0x2c, 0x89, 0x4f, 0x0c, 0xe8, 0xd4, 0x4b, 0x13, 0xee, 0x87, - 0x81, 0xd8, 0x8d, 0xf7, 0x23, 0x19, 0xd0, 0x66, 0x5b, 0xb0, 0xca, 0x94, - 0x4e, 0x1a, 0xe8, 0xde, 0x93, 0x31, 0xc9, 0xc1, 0xd9, 0xc0, 0xdf, 0x89, - 0x55, 0x30, 0xff, 0xd3, 0xe8, 0x54, 0x78, 0x41, 0x66, 0xc1, 0x03, 0x8d, - 0x9e, 0xfb, 0x65, 0xc9, 0x33, 0x13, 0xe7, 0xd7, 0xe7, 0x99, 0xbf, 0x5d, - 0xb0, 0x0b, 0x8d, 0xca, 0x2e, 0xe3, 0x8e, 0x70, 0x08, 0x1a, 0xbe, 0xa5, - 0x1d, 0x47, 0x24, 0x5f, 0xd6, 0x5d, 0x83, 0x46, 0x47, 0x79, 0x2d, 0xaf, - 0xe3, 0xf5, 0xf6, 0x98, 0x25, 0x3e, 0x08, 0xf6, 0xae, 0xdb, 0xd3, 0x21, - 0x31, 0x0f, 0x9a, 0x95, 0x2c, 0xc0, 0xc3, 0xcf, 0x5b, 0xcb, 0x72, 0xd8, - 0xc8, 0x6f, 0x5e, 0xdb, 0xbe, 0x0e, 0xfa, 0x3c, 0xc0, 0x34, 0x9c, 0x4c, - 0x2a, 0x3b, 0x8d, 0x68, 0x8a, 0x64, 0xa9, 0x85, 0x38, 0x3e, 0xeb, 0x1c, - 0xbc, 0x1e, 0xfe, 0xc3, 0x87, 0xff, 0x80, 0x4f, 0x3c, 0xef, 0xc3, 0xbf, - 0xf8, 0xec, 0x6f, 0x2c, 0x7a, 0x7e, 0x18, 0xfe, 0xf1, 0x9a, 0x7f, 0x42, - 0x1b, 0x47, 0x5f, 0x90, 0x0e, 0xff, 0x34, 0xdb, 0x10, 0xb0, 0x73, 0xf8, - 0x8a, 0x15, 0x9e, 0x83, 0x5f, 0x58, 0x29, 0xe1, 0xe9, 0x50, 0xb5, 0xc9, - 0x7a, 0x18, 0xf9, 0x61, 0xf6, 0x57, 0x19, 0xf8, 0x26, 0xf6, 0x47, 0xec, - 0xb7, 0x78, 0x6d, 0x10, 0x94, 0x5c, 0x86, 0x0d, 0x20, 0x47, 0xb6, 0xbb, - 0x24, 0x89, 0x54, 0x45, 0x3b, 0x34, 0x0c, 0x7b, 0xbc, 0x89, 0x7d, 0x0b, - 0xdb, 0xe5, 0x8d, 0x44, 0x9d, 0xbc, 0xdf, 0xaf, 0xbb, 0xd5, 0xbf, 0xd9, - 0xdb, 0x84, 0x35, 0xf2, 0xd9, 0xa3, 0xc6, 0x66, 0xe8, 0x97, 0xf8, 0xbd, - 0x6d, 0x15, 0x68, 0x57, 0x38, 0xe6, 0xfe, 0x1a, 0xbd, 0xae, 0xb8, 0x25, - 0x41, 0x3b, 0x4f, 0x29, 0x7f, 0xba, 0x73, 0x09, 0x9a, 0x71, 0x4a, 0xd1, - 0xb8, 0xf3, 0x6c, 0xe4, 0x57, 0x93, 0xc0, 0x07, 0xfa, 0xfc, 0xb5, 0x18, - 0x82, 0xf6, 0x9e, 0x06, 0xd3, 0xc2, 0xdc, 0x46, 0x5e, 0xb0, 0x2f, 0x67, - 0xfb, 0x34, 0xdb, 0xed, 0x73, 0x2f, 0xec, 0xd3, 0xed, 0x24, 0xdb, 0xfd, - 0x27, 0xd8, 0xe7, 0xb7, 0x5d, 0x0d, 0xbc, 0x21, 0xba, 0x54, 0xcb, 0xc0, - 0x3f, 0x18, 0x99, 0xd7, 0x69, 0x97, 0x35, 0x0b, 0xbd, 0x3c, 0xc9, 0x73, - 0x4d, 0xcc, 0x49, 0x3f, 0xae, 0xfc, 0xc7, 0x65, 0xfd, 0xbb, 0xa0, 0x2b, - 0x08, 0x66, 0x81, 0xb3, 0x3c, 0xa2, 0x87, 0xb6, 0x18, 0xcd, 0x5f, 0x45, - 0x3c, 0xf4, 0x7e, 0x43, 0xa7, 0x4a, 0xb6, 0x83, 0xec, 0xec, 0x12, 0x70, - 0x4f, 0xbb, 0xca, 0xee, 0xd9, 0x36, 0x96, 0x81, 0x7f, 0xce, 0x1f, 0x86, - 0x5f, 0x60, 0xbb, 0x01, 0x5d, 0xc0, 0xbf, 0x0c, 0xfc, 0x73, 0xad, 0x0e, - 0xfa, 0x96, 0x11, 0xc5, 0xd9, 0xe8, 0x3c, 0xdb, 0xb0, 0x2c, 0xda, 0xf7, - 0x08, 0xdd, 0xe5, 0xa7, 0xe0, 0x73, 0xd8, 0x27, 0x57, 0xb3, 0xb0, 0x2b, - 0xad, 0xea, 0xf2, 0xde, 0x3a, 0x2d, 0xaf, 0xad, 0xa1, 0x42, 0x55, 0xd9, - 0x6c, 0xc1, 0x1b, 0xae, 0x64, 0x74, 0xe9, 0x7b, 0x88, 0xee, 0x84, 0xad, - 0x2e, 0x3b, 0x3c, 0xe6, 0x79, 0x35, 0x37, 0x5e, 0x1b, 0xd0, 0x8a, 0xec, - 0xbf, 0x86, 0x3f, 0x04, 0x7d, 0x6a, 0xee, 0xb7, 0x6b, 0x0f, 0xb1, 0x8c, - 0x70, 0x16, 0xb2, 0xaa, 0xee, 0x7f, 0x06, 0xd0, 0xdf, 0x75, 0x30, 0xd7, - 0xc7, 0x63, 0x8f, 0x2b, 0x9d, 0x25, 0x6d, 0xbf, 0x23, 0x06, 0x3a, 0x43, - 0x9f, 0xb7, 0x1f, 0x93, 0xfb, 0x6a, 0xd5, 0xfe, 0x4e, 0xfa, 0x50, 0xe7, - 0x18, 0x7c, 0x85, 0xc8, 0xf0, 0x6a, 0xbb, 0xc1, 0x8f, 0x6a, 0x5f, 0xdb, - 0x5c, 0xa2, 0x54, 0x0b, 0xe8, 0xa2, 0xab, 0x60, 0x30, 0x4e, 0x16, 0x6b, - 0x62, 0x20, 0x41, 0x6b, 0x63, 0x93, 0x61, 0x56, 0x68, 0x77, 0x76, 0x99, - 0x24, 0x6c, 0x7f, 0xe2, 0x1a, 0x6c, 0xba, 0x54, 0xab, 0xf6, 0xb5, 0x8d, - 0x33, 0x45, 0xe0, 0x12, 0x7b, 0xd7, 0x60, 0x07, 0xaf, 0xc1, 0x6e, 0x25, - 0xab, 0x8f, 0xe1, 0xc5, 0xc0, 0xe6, 0x6b, 0xb8, 0xad, 0x90, 0x9e, 0xfe, - 0xcd, 0xd7, 0x70, 0x38, 0x8c, 0xb3, 0x6d, 0x9c, 0x65, 0x9c, 0x3b, 0xaf, - 0xe1, 0x1c, 0x59, 0x4f, 0xcf, 0x11, 0x82, 0x0f, 0x4a, 0x74, 0xe6, 0x69, - 0xef, 0xa5, 0xda, 0xd0, 0xc4, 0x5d, 0x84, 0xf8, 0x38, 0xb2, 0x29, 0xf4, - 0xe1, 0xc6, 0x5e, 0x0f, 0xbc, 0x32, 0x88, 0x7d, 0xa2, 0x46, 0x55, 0xc8, - 0xf9, 0x8f, 0x9a, 0xb4, 0xf7, 0x62, 0xd3, 0x08, 0x75, 0x89, 0x75, 0xe2, - 0x6d, 0xd8, 0x58, 0x72, 0xca, 0x40, 0x0c, 0xbf, 0x20, 0x6d, 0x8c, 0x26, - 0xaa, 0x35, 0xaa, 0x6c, 0xcf, 0x3f, 0x11, 0x40, 0x17, 0xa7, 0xe0, 0xd3, - 0xc0, 0xe3, 0xe4, 0x98, 0x97, 0xc3, 0x7c, 0x93, 0x6d, 0x0b, 0x7e, 0x05, - 0xb0, 0xd0, 0xb5, 0x84, 0x3e, 0xbf, 0xeb, 0x55, 0x4f, 0xe7, 0x7d, 0x2c, - 0xe4, 0x5c, 0x89, 0x84, 0x98, 0xbf, 0x1a, 0xb0, 0x9e, 0x4d, 0x8f, 0x5c, - 0x45, 0x8e, 0x63, 0x92, 0x37, 0x06, 0xff, 0x01, 0x7d, 0x9f, 0x6d, 0x11, - 0x72, 0x82, 0x3f, 0xed, 0x55, 0x36, 0xf6, 0x9d, 0xad, 0xea, 0x49, 0x06, - 0xfb, 0xf2, 0xe9, 0x1c, 0xe7, 0x0f, 0x9d, 0x09, 0x2f, 0x37, 0xbe, 0x4d, - 0x3f, 0x7b, 0x60, 0x9b, 0x38, 0x5b, 0xd9, 0x26, 0x10, 0x03, 0x60, 0x53, - 0xc2, 0xcb, 0xa1, 0x7f, 0x36, 0xb2, 0xa1, 0x0c, 0x6c, 0x88, 0x69, 0x65, - 0x3a, 0x7f, 0x04, 0x7b, 0x95, 0xb4, 0xd2, 0x84, 0x0f, 0x9a, 0x46, 0x3f, - 0x82, 0x9e, 0xe0, 0x2c, 0xf0, 0x81, 0x05, 0x70, 0x49, 0x8c, 0xfe, 0x2a, - 0xb4, 0x67, 0xee, 0xbf, 0x1b, 0xa8, 0x78, 0x72, 0x30, 0xdc, 0xff, 0x17, - 0xa1, 0x0f, 0x88, 0x70, 0x31, 0x9e, 0xac, 0x36, 0x81, 0x5c, 0x68, 0xa2, - 0x65, 0x68, 0xec, 0xcf, 0x8b, 0x3e, 0xe7, 0x30, 0x9c, 0xbf, 0x3c, 0x1e, - 0xfa, 0x45, 0xce, 0x5b, 0x92, 0x21, 0x4f, 0x73, 0x51, 0x5c, 0x94, 0xf6, - 0x86, 0x18, 0x65, 0x95, 0x5d, 0x99, 0xd3, 0x68, 0xd3, 0xb9, 0x24, 0xd6, - 0x61, 0xae, 0x85, 0x73, 0xc3, 0x2f, 0x21, 0x0f, 0xe2, 0xdc, 0x14, 0xeb, - 0x3b, 0x43, 0x9b, 0xbf, 0x44, 0x65, 0xf8, 0x54, 0xc3, 0xe1, 0xf7, 0x5e, - 0x2f, 0x75, 0x61, 0xdc, 0xc4, 0x5e, 0xf0, 0x13, 0xba, 0xe4, 0x33, 0x62, - 0x41, 0xfa, 0x06, 0xce, 0xaf, 0xb0, 0xd6, 0xc2, 0x5a, 0xf6, 0xbb, 0xbc, - 0xf6, 0x3c, 0xe8, 0xc0, 0xb8, 0xc9, 0x30, 0xec, 0xa3, 0x82, 0xf7, 0xbc, - 0xdc, 0x1e, 0x73, 0x82, 0x12, 0x21, 0x5e, 0xab, 0x0d, 0xef, 0xc6, 0xb5, - 0x9c, 0xd3, 0x04, 0x17, 0x74, 0x87, 0xf1, 0x47, 0x79, 0x18, 0xd1, 0xf4, - 0x09, 0xe4, 0x71, 0x4e, 0x07, 0xe2, 0x14, 0x8f, 0x86, 0x4c, 0x75, 0xce, - 0x08, 0xe6, 0x81, 0xfe, 0xf5, 0xe3, 0xbb, 0x53, 0xd7, 0xfc, 0x23, 0x5b, - 0x17, 0x15, 0x10, 0x1f, 0xc0, 0x27, 0x6b, 0x8a, 0x73, 0xbf, 0x62, 0x53, - 0xa2, 0xc4, 0xdc, 0x18, 0x7c, 0xa2, 0xca, 0xa3, 0x2e, 0xf8, 0x1b, 0xe5, - 0x66, 0x82, 0xd7, 0x05, 0xf0, 0xd7, 0x82, 0xfe, 0x8c, 0x03, 0x96, 0x8e, - 0x00, 0x07, 0xc7, 0x6a, 0x57, 0xe4, 0x53, 0x54, 0x36, 0x39, 0xa7, 0xe8, - 0x64, 0xfa, 0x0a, 0x6c, 0xfb, 0x22, 0xbf, 0x19, 0x73, 0xdc, 0x7f, 0xac, - 0x57, 0xc9, 0xab, 0x9b, 0xc7, 0x13, 0x22, 0xdf, 0xbb, 0x61, 0xfe, 0x9f, - 0xbb, 0x15, 0x6d, 0x72, 0x8c, 0xf9, 0x7f, 0xdb, 0x30, 0xfe, 0xe3, 0xd4, - 0xfa, 0xf1, 0xdd, 0xdb, 0x42, 0xfd, 0x43, 0xff, 0xf1, 0x90, 0x5e, 0xd0, - 0xb6, 0x46, 0x6b, 0x94, 0x2b, 0x53, 0x5d, 0x20, 0x5f, 0xf4, 0x72, 0xbb, - 0xac, 0x2a, 0x6c, 0xaa, 0xd4, 0x02, 0xdd, 0x6b, 0x71, 0x6c, 0x6d, 0x4d, - 0xe5, 0xda, 0x1a, 0xe5, 0xe7, 0x4b, 0xad, 0x00, 0x79, 0x56, 0x7b, 0xcc, - 0xcb, 0xa2, 0x5f, 0xc1, 0x3e, 0x05, 0x9a, 0xf6, 0x2f, 0x16, 0x84, 0x73, - 0x4c, 0xe6, 0x89, 0xc2, 0x79, 0x4a, 0x2b, 0x2d, 0x73, 0xfe, 0x08, 0x5b, - 0x72, 0x64, 0xdd, 0x80, 0x98, 0x72, 0x5c, 0x2b, 0x9c, 0x5e, 0x40, 0xfe, - 0xb8, 0x82, 0xdf, 0x19, 0xfc, 0x9a, 0xf8, 0x45, 0xf9, 0xfb, 0x33, 0xc8, - 0xff, 0xa5, 0x7f, 0x45, 0x2c, 0x50, 0xfb, 0xff, 0x62, 0x05, 0x3a, 0xb6, - 0x90, 0xa6, 0x6f, 0x3b, 0xa2, 0x5f, 0x28, 0x9f, 0x52, 0x40, 0xde, 0x6b, - 0xbe, 0x4d, 0xbf, 0x13, 0xe6, 0x50, 0x44, 0xaf, 0xd7, 0xc1, 0xc7, 0x91, - 0xfd, 0xa1, 0xbe, 0x66, 0x1f, 0xf4, 0xa4, 0xef, 0x0c, 0x73, 0x24, 0xe4, - 0x6a, 0x05, 0xb9, 0xea, 0xfb, 0xe0, 0x8d, 0x46, 0x6f, 0x41, 0x7f, 0x5e, - 0xaf, 0x77, 0x81, 0x1e, 0x87, 0xca, 0x93, 0xf6, 0x18, 0x69, 0x43, 0xe6, - 0x26, 0xad, 0x0b, 0x36, 0x0c, 0xfb, 0x96, 0x63, 0x4a, 0x74, 0xe4, 0xcf, - 0xcd, 0x2c, 0xd5, 0x04, 0xd6, 0x22, 0xef, 0xc9, 0xa1, 0x0f, 0xd9, 0x5f, - 0xa9, 0x33, 0x9c, 0xa0, 0x37, 0xea, 0x3a, 0xbd, 0x89, 0xbc, 0xeb, 0x2d, - 0xe7, 0xdc, 0x0c, 0x62, 0xd6, 0x00, 0xe2, 0x03, 0x6a, 0x98, 0x5d, 0xec, - 0xa3, 0x77, 0x1a, 0x78, 0x96, 0xf0, 0xbb, 0x13, 0x79, 0xe3, 0xf5, 0x61, - 0x3e, 0x6d, 0x3d, 0xd3, 0x96, 0x00, 0x0c, 0xaf, 0x37, 0x40, 0x5b, 0x0f, - 0xe4, 0x6f, 0x9b, 0x53, 0xf4, 0xcb, 0x5e, 0x99, 0xab, 0x68, 0x3c, 0xaf, - 0xfc, 0xd2, 0x27, 0xe7, 0x99, 0xcf, 0x3a, 0x74, 0x9c, 0xc7, 0xfc, 0x8e, - 0xfd, 0x27, 0xe3, 0xb3, 0xc7, 0x0a, 0x38, 0xcc, 0x95, 0xba, 0xea, 0x47, - 0x73, 0xa4, 0x45, 0x31, 0x8c, 0xfd, 0x62, 0x89, 0x0a, 0x92, 0xef, 0x13, - 0x24, 0x65, 0xb0, 0x4e, 0x9e, 0x94, 0x30, 0xf2, 0xf5, 0x99, 0x39, 0x87, - 0xe5, 0x0a, 0xff, 0x56, 0x8b, 0xe4, 0xca, 0x32, 0xea, 0xa4, 0x6a, 0xfd, - 0x29, 0xc8, 0x55, 0x84, 0xf5, 0x01, 0xec, 0x7b, 0x81, 0xe5, 0x8b, 0xba, - 0xb1, 0x8e, 0xbc, 0xa7, 0x4e, 0x29, 0x55, 0xdf, 0x1c, 0x47, 0x5d, 0x00, - 0xf9, 0xd5, 0x16, 0x80, 0x03, 0x36, 0x5a, 0x5b, 0xc1, 0x13, 0xb5, 0x48, - 0xed, 0x0c, 0x9e, 0x83, 0x78, 0x36, 0x59, 0x37, 0xc3, 0x3c, 0xe3, 0x13, - 0xf4, 0xc0, 0x9e, 0x4a, 0x6c, 0x4f, 0xf4, 0x8f, 0xad, 0x3c, 0xfd, 0x43, - 0x6b, 0x8c, 0x7e, 0xd4, 0xca, 0xd1, 0x0f, 0x5b, 0x2e, 0xfd, 0x7d, 0x6b, - 0x84, 0x9e, 0x6d, 0x65, 0xb9, 0x96, 0x43, 0xce, 0x64, 0x71, 0xce, 0x44, - 0x0f, 0xfa, 0xb7, 0xc3, 0xde, 0x59, 0xfe, 0xe7, 0x66, 0x0a, 0xcd, 0x21, - 0x2a, 0x9f, 0x80, 0x6f, 0x76, 0x6f, 0xe3, 0x1a, 0x94, 0x1e, 0x73, 0xb9, - 0x86, 0xe8, 0xe0, 0xf7, 0xa8, 0x23, 0xe0, 0xbb, 0xe1, 0xcb, 0xa6, 0xd2, - 0xf6, 0x39, 0x4f, 0x1f, 0x08, 0x7d, 0xc0, 0x5d, 0x29, 0xea, 0xc2, 0x5e, - 0xf0, 0x7f, 0x17, 0x9f, 0x86, 0x0d, 0xc8, 0x1a, 0x28, 0x01, 0x5f, 0xc3, - 0x79, 0x80, 0xc1, 0x76, 0xcc, 0xf5, 0x87, 0xe5, 0xe9, 0x5c, 0x17, 0xb2, - 0x3d, 0xeb, 0x08, 0x1a, 0x0c, 0x37, 0x69, 0xb2, 0xdc, 0x0c, 0x87, 0x7d, - 0x6a, 0x21, 0xf4, 0x6f, 0x89, 0x50, 0x2f, 0x4d, 0xcc, 0x3f, 0x15, 0xfa, - 0xe3, 0x8d, 0xfb, 0x20, 0x56, 0x20, 0x97, 0x54, 0xeb, 0x18, 0x56, 0x0b, - 0x61, 0xfb, 0xc3, 0xb9, 0x24, 0xf8, 0xed, 0x52, 0xd9, 0x7f, 0x43, 0xe3, - 0x1c, 0x5b, 0x38, 0xcc, 0xff, 0x11, 0x8c, 0x2f, 0x87, 0xe3, 0xaf, 0xd0, - 0xf4, 0x22, 0x81, 0xd6, 0xd7, 0xb4, 0xa2, 0x1c, 0x8f, 0x61, 0x2c, 0x30, - 0xd6, 0xb9, 0x6e, 0xe0, 0x0c, 0x23, 0xc5, 0xba, 0x2e, 0x9c, 0x71, 0xf0, - 0x71, 0x12, 0xbf, 0x82, 0xfc, 0x3d, 0xe2, 0x0f, 0x15, 0xde, 0x41, 0xbc, - 0xd0, 0x3a, 0xa2, 0xdc, 0x67, 0x3b, 0x6a, 0xcf, 0x20, 0x38, 0x84, 0x5a, - 0xdd, 0x4a, 0x19, 0xf4, 0x2f, 0xf3, 0xb6, 0x79, 0x48, 0xcc, 0xe1, 0x4c, - 0x41, 0x30, 0xe1, 0xd8, 0x95, 0x82, 0xe8, 0xa6, 0x9f, 0x1f, 0xe7, 0xb8, - 0x5b, 0x9f, 0x79, 0x01, 0xba, 0xd7, 0x58, 0xe9, 0xa4, 0x46, 0xc3, 0xa0, - 0x2b, 0xa3, 0x43, 0xa0, 0xd3, 0xa4, 0x46, 0x33, 0x85, 0x5c, 0x6e, 0x33, - 0xa1, 0x3c, 0x94, 0x0e, 0x43, 0xcf, 0x67, 0xa5, 0x8f, 0xf6, 0x1c, 0x3c, - 0x9b, 0x1f, 0xf4, 0xae, 0x3f, 0x73, 0x09, 0xf4, 0xf7, 0xa0, 0x0a, 0xd9, - 0x2e, 0xe5, 0x5c, 0xf6, 0x87, 0x4c, 0x4f, 0x20, 0x6e, 0x19, 0x43, 0xe6, - 0x7e, 0xf1, 0xab, 0xe0, 0x0e, 0x83, 0x65, 0xf7, 0xaa, 0xac, 0x77, 0x64, - 0x9c, 0xc3, 0x7e, 0x4b, 0x2b, 0xaf, 0x81, 0x16, 0x93, 0x9e, 0x6d, 0x6e, - 0x0f, 0xc7, 0x96, 0xe4, 0xc5, 0xb3, 0xcd, 0x2e, 0xfa, 0x61, 0x63, 0x0b, - 0x2d, 0x37, 0xf8, 0x7d, 0x27, 0x2d, 0x35, 0x86, 0xae, 0x1e, 0x15, 0x03, - 0xb4, 0x7a, 0xe3, 0x4d, 0xe6, 0x57, 0x05, 0xf2, 0x82, 0xc9, 0x8f, 0xe9, - 0xbd, 0xd1, 0x5e, 0xfa, 0xe9, 0x3d, 0x76, 0xfd, 0x7e, 0x01, 0x1b, 0x18, - 0x4d, 0xb2, 0x6d, 0xa3, 0xcf, 0xf3, 0xf6, 0x55, 0x4b, 0xb0, 0x6e, 0xff, - 0x04, 0x3c, 0xb5, 0x8f, 0x29, 0x3b, 0x60, 0xdc, 0x8c, 0x17, 0xba, 0xe1, - 0xbc, 0x08, 0x9c, 0x78, 0xd7, 0x1c, 0x02, 0xae, 0x17, 0x25, 0x2f, 0x0e, - 0xb9, 0xf6, 0x55, 0x42, 0x0e, 0x79, 0xc5, 0x19, 0xca, 0x0a, 0xb1, 0x9d, - 0x1a, 0x99, 0x9b, 0xcc, 0xf3, 0xf0, 0xff, 0xa8, 0xab, 0x2a, 0x97, 0xa9, - 0x3e, 0x73, 0xc9, 0x61, 0xfd, 0x67, 0xbf, 0xf1, 0x12, 0xf2, 0x4e, 0x93, - 0x4e, 0x34, 0xd9, 0x5f, 0x32, 0x2e, 0xce, 0xfd, 0x77, 0x9b, 0x5f, 0x13, - 0x9c, 0x23, 0xe0, 0x1d, 0xe6, 0xf5, 0x2f, 0xb1, 0x9c, 0x3b, 0x18, 0x36, - 0x6b, 0x89, 0x60, 0x03, 0x8f, 0x86, 0xcc, 0x5d, 0x82, 0xf7, 0xfb, 0x6f, - 0xec, 0xfb, 0x2e, 0x68, 0x1d, 0x02, 0x2c, 0xe2, 0x65, 0xa6, 0x7d, 0x8f, - 0x57, 0xe4, 0x1e, 0xc7, 0x9b, 0xc8, 0xf3, 0xd6, 0xf6, 0xc0, 0x5c, 0x53, - 0xe0, 0x9c, 0x86, 0x94, 0xcb, 0x95, 0x51, 0xe6, 0xef, 0x6d, 0x7d, 0x9c, - 0x63, 0xea, 0xf9, 0xbf, 0x09, 0xa2, 0x5a, 0xf3, 0x95, 0xf9, 0x49, 0xf8, - 0xe7, 0x20, 0xa8, 0xee, 0x1e, 0x52, 0x71, 0x68, 0x90, 0xdf, 0x1f, 0x90, - 0xb2, 0xa8, 0x8a, 0x4e, 0xba, 0xc3, 0xb0, 0x00, 0xcb, 0x73, 0x2f, 0x87, - 0x72, 0x84, 0x11, 0x75, 0xa1, 0xdf, 0x8c, 0xf4, 0x32, 0x05, 0x1d, 0xdb, - 0x63, 0x1e, 0x0a, 0x63, 0x32, 0xc7, 0xb4, 0x9f, 0x42, 0xe7, 0xac, 0x14, - 0xeb, 0x4d, 0xaa, 0xef, 0x9a, 0xde, 0xf0, 0xbb, 0xfa, 0x8c, 0x07, 0xda, - 0x8a, 0x0b, 0x9d, 0x54, 0xaa, 0x27, 0x90, 0x03, 0x19, 0x34, 0x97, 0xc3, - 0x18, 0x3a, 0x54, 0x6a, 0xb0, 0xce, 0x57, 0x42, 0x9d, 0x4f, 0x86, 0xb8, - 0x4f, 0x82, 0x17, 0xb6, 0xb5, 0x2a, 0xb8, 0x76, 0xda, 0x26, 0xeb, 0x5f, - 0x1d, 0xb6, 0x5c, 0xae, 0x71, 0xed, 0x89, 0xfc, 0xdb, 0x3c, 0x37, 0x33, - 0xed, 0x18, 0xa0, 0x6b, 0x44, 0x2b, 0xb7, 0x1c, 0xad, 0xec, 0x33, 0x7d, - 0xbb, 0x41, 0xb7, 0x26, 0x6b, 0xdc, 0xa5, 0xd6, 0x7b, 0xc1, 0xd2, 0xee, - 0x4d, 0xe8, 0x43, 0xe7, 0x27, 0x58, 0xae, 0x5f, 0x60, 0xba, 0xac, 0x82, - 0x60, 0x3e, 0xa7, 0xe9, 0xd4, 0xf0, 0xdf, 0xf5, 0x72, 0x3e, 0x75, 0x7a, - 0x98, 0xf1, 0x83, 0x8e, 0x74, 0x9a, 0x96, 0x7d, 0xde, 0xa3, 0x3e, 0xc3, - 0x3c, 0x2c, 0x2f, 0x98, 0xf4, 0x88, 0x94, 0xdb, 0x6b, 0xd2, 0xa6, 0xcb, - 0x2b, 0xb0, 0xa5, 0xd4, 0x90, 0x79, 0x94, 0xec, 0xab, 0x17, 0x75, 0xbb, - 0x3e, 0x05, 0x7b, 0x5e, 0x5a, 0xd4, 0x69, 0xa7, 0xac, 0xb1, 0x58, 0x36, - 0xf6, 0x31, 0x58, 0x7c, 0x78, 0xf6, 0x43, 0x6d, 0x67, 0xef, 0xa1, 0x4b, - 0x4f, 0xff, 0x16, 0x7c, 0x0d, 0xf3, 0xd5, 0xb0, 0x0e, 0x23, 0x9f, 0x58, - 0x40, 0xee, 0x51, 0x45, 0x6e, 0x5c, 0xc8, 0x30, 0x6c, 0xc4, 0xef, 0xad, - 0x92, 0xff, 0x42, 0xf2, 0x7f, 0x07, 0x55, 0xa5, 0x0d, 0x65, 0xe4, 0x3b, - 0x01, 0x1c, 0xea, 0x1d, 0x8f, 0x91, 0x2b, 0xc9, 0x77, 0xf7, 0x2a, 0x38, - 0xf6, 0x11, 0x19, 0x7e, 0x77, 0x14, 0x7b, 0x32, 0x8f, 0xa3, 0xf9, 0x6e, - 0x52, 0x36, 0x14, 0xf1, 0x1d, 0x89, 0x44, 0x33, 0x4d, 0xbf, 0x8b, 0x9a, - 0x67, 0xb2, 0x39, 0x48, 0xa5, 0xa6, 0x05, 0x19, 0xcc, 0xf4, 0xf1, 0xd9, - 0x8a, 0x2b, 0x38, 0x8f, 0x60, 0x5a, 0xef, 0xa5, 0xc3, 0x7e, 0x44, 0x4f, - 0x32, 0xa4, 0x6f, 0x32, 0x1c, 0x27, 0x42, 0x1a, 0xda, 0xf1, 0x25, 0x81, - 0x0b, 0x31, 0x3e, 0xf7, 0x57, 0x21, 0x1e, 0xf6, 0x1f, 0xa0, 0x75, 0x32, - 0x43, 0x2b, 0x3e, 0xd3, 0xb1, 0x85, 0xaa, 0x69, 0xee, 0x1f, 0x80, 0x9e, - 0x31, 0x9e, 0x4d, 0x9c, 0xc7, 0xac, 0xe3, 0xf1, 0x91, 0x66, 0x05, 0x3c, - 0x66, 0xfe, 0xf2, 0xba, 0x24, 0x2d, 0x7d, 0x85, 0xe5, 0xb7, 0x07, 0xf9, - 0x3b, 0xeb, 0xc2, 0x96, 0x50, 0xaf, 0xd4, 0x9e, 0xa5, 0x85, 0x1e, 0xc8, - 0x8a, 0xf7, 0xed, 0xa2, 0xbb, 0x61, 0xef, 0xc5, 0x06, 0xef, 0x3f, 0x09, - 0x3d, 0x7a, 0x59, 0xee, 0x5f, 0x5a, 0x19, 0x08, 0xe1, 0x19, 0xb6, 0x67, - 0x03, 0x6c, 0x27, 0xed, 0xab, 0x9b, 0xd7, 0x81, 0xff, 0x7d, 0xc0, 0x0b, - 0x3a, 0x99, 0x63, 0x78, 0xc6, 0x83, 0x75, 0x8d, 0xf4, 0x67, 0xe0, 0x49, - 0xc9, 0x5a, 0xbe, 0xd8, 0xe8, 0xa4, 0x62, 0x3d, 0xc2, 0xc5, 0x78, 0x3e, - 0x46, 0xad, 0x7b, 0x9f, 0xc4, 0x35, 0x2d, 0x71, 0xe1, 0x7d, 0x83, 0x7d, - 0xcd, 0xad, 0x80, 0x47, 0xbd, 0xee, 0x80, 0xb6, 0x54, 0x37, 0x2d, 0xc9, - 0x7a, 0xbd, 0x4b, 0xf9, 0x98, 0xd4, 0x66, 0xbc, 0xdf, 0x02, 0x5b, 0xdf, - 0x83, 0x3c, 0xa6, 0x07, 0x73, 0xd6, 0x86, 0xb9, 0x8d, 0xf4, 0x27, 0x36, - 0xd0, 0xdf, 0x89, 0x75, 0xfd, 0xd8, 0x53, 0xad, 0x2b, 0x61, 0xdd, 0xec, - 0x02, 0x6c, 0x82, 0x73, 0xf3, 0x34, 0xc7, 0xe4, 0x1b, 0x25, 0x2d, 0xb3, - 0x2b, 0xef, 0xe1, 0x5c, 0x03, 0x80, 0x8d, 0xc6, 0x8a, 0x0f, 0x75, 0xe0, - 0xf9, 0x5e, 0x43, 0xde, 0x4b, 0x40, 0x06, 0x9b, 0x53, 0x7c, 0xf6, 0x6a, - 0xe3, 0xf3, 0x78, 0x76, 0x63, 0x1b, 0xbf, 0x98, 0x57, 0x4c, 0x2f, 0xd3, - 0x0a, 0x3d, 0x25, 0xd8, 0x9b, 0x8b, 0x9a, 0x2f, 0xa5, 0x53, 0x29, 0x87, - 0x78, 0xee, 0xf3, 0x5d, 0x2d, 0xdb, 0xe5, 0xa0, 0xaa, 0x0b, 0x1c, 0x8e, - 0xeb, 0x86, 0x3c, 0xfb, 0xe1, 0x15, 0xbe, 0xaf, 0xb5, 0x10, 0x4f, 0xed, - 0x2c, 0xe1, 0xec, 0x0f, 0xaf, 0x38, 0xf4, 0x68, 0x33, 0x4b, 0x47, 0x9b, - 0xb6, 0x79, 0x3f, 0x7c, 0x40, 0x79, 0xed, 0x1e, 0x77, 0x57, 0x8a, 0xfd, - 0x96, 0x81, 0x9c, 0xb3, 0xc3, 0x51, 0x39, 0x48, 0x95, 0xeb, 0xb1, 0x05, - 0x9b, 0xef, 0x68, 0xcc, 0x06, 0x6d, 0xcc, 0x53, 0xfe, 0x2f, 0x73, 0x14, - 0xde, 0x9f, 0xfd, 0x34, 0x72, 0x12, 0x1f, 0x39, 0x89, 0x8f, 0x9c, 0xc4, - 0x47, 0x4e, 0xe2, 0x23, 0x27, 0xf1, 0x91, 0x93, 0xf8, 0xc8, 0x49, 0x7c, - 0xe4, 0x24, 0xc8, 0xff, 0x55, 0x5d, 0x30, 0x8e, 0x5c, 0x1b, 0xfe, 0xcb, - 0xff, 0x6a, 0x98, 0x53, 0x44, 0x31, 0x99, 0xe7, 0x56, 0x37, 0x79, 0x6e, - 0x74, 0x4f, 0x7c, 0x00, 0x73, 0x13, 0x61, 0xee, 0xc3, 0x6b, 0xa2, 0x98, - 0xcd, 0xeb, 0x68, 0xcc, 0x43, 0xbd, 0x59, 0x98, 0xe4, 0xdc, 0x48, 0xc5, - 0x2a, 0x95, 0x97, 0xbf, 0x8a, 0xfc, 0xc8, 0x42, 0x7e, 0x34, 0x88, 0x5c, - 0x88, 0xef, 0xb5, 0xa3, 0xfb, 0xa3, 0x82, 0x76, 0xc8, 0x1f, 0xd7, 0xbe, - 0xe6, 0x73, 0xde, 0xee, 0x58, 0x65, 0x21, 0x16, 0xfa, 0x29, 0xa0, 0xe2, - 0xe8, 0xb7, 0x90, 0x23, 0x7f, 0x4f, 0xde, 0x95, 0x4d, 0x0c, 0xb3, 0xcc, - 0x27, 0x3e, 0x25, 0x4f, 0x8e, 0xf8, 0xab, 0xee, 0xf8, 0xc4, 0x12, 0xf3, - 0x8f, 0xa8, 0xef, 0x2c, 0x18, 0x7e, 0x36, 0x41, 0xa9, 0x53, 0x5b, 0x30, - 0x67, 0x52, 0xbf, 0xbc, 0x27, 0x82, 0x28, 0xcf, 0xfe, 0x1a, 0xf2, 0x72, - 0x48, 0x9c, 0xe5, 0xdb, 0x04, 0xc6, 0xcb, 0xfe, 0xb5, 0x32, 0x53, 0x6c, - 0x54, 0xa4, 0x4e, 0x1d, 0x6a, 0x96, 0x90, 0x3f, 0xf5, 0xf6, 0x53, 0x97, - 0x81, 0x1a, 0x2a, 0xc2, 0xcd, 0x38, 0x7f, 0x99, 0x92, 0xb5, 0xcd, 0xd9, - 0x35, 0x79, 0x42, 0xd6, 0xbc, 0x4f, 0x65, 0xa6, 0x5a, 0xb7, 0x33, 0x5c, - 0xd7, 0x82, 0xd6, 0x99, 0x27, 0x81, 0x63, 0x19, 0x39, 0x81, 0x2e, 0xf7, - 0xae, 0xcc, 0xcc, 0xd6, 0xd5, 0x5d, 0x95, 0xa2, 0x01, 0xf1, 0x2f, 0xd7, - 0x45, 0xfa, 0x92, 0xba, 0xb3, 0x12, 0x12, 0x96, 0xe1, 0x18, 0xde, 0x00, - 0x1c, 0xcb, 0x2d, 0x0b, 0x58, 0x96, 0x1d, 0xd3, 0x50, 0x99, 0xa9, 0x34, - 0xda, 0x69, 0x60, 0x3c, 0x8c, 0x37, 0x3a, 0x0f, 0x9f, 0x25, 0x45, 0xe2, - 0x54, 0x10, 0x94, 0x47, 0x07, 0xc3, 0x3a, 0x12, 0xf5, 0xe3, 0x09, 0x43, - 0xea, 0xb9, 0x1a, 0x7f, 0x53, 0xc6, 0x29, 0x4b, 0xf0, 0x3c, 0x3f, 0xf1, - 0x2e, 0xf7, 0x24, 0xe6, 0x30, 0x5e, 0x8e, 0xd6, 0x8a, 0x70, 0x6d, 0x77, - 0x1b, 0x3f, 0x3b, 0xc2, 0xfd, 0x98, 0x26, 0x3e, 0xe7, 0x65, 0xec, 0xc5, - 0x74, 0xf1, 0x1a, 0x13, 0xb4, 0x41, 0x96, 0xfe, 0xff, 0x96, 0xf7, 0xed, - 0x67, 0x62, 0x9e, 0x1a, 0x80, 0xe1, 0xf5, 0x8c, 0x23, 0x82, 0xc1, 0x8b, - 0xb3, 0x0a, 0x4e, 0xac, 0xdd, 0xed, 0x7d, 0xd6, 0xbe, 0xed, 0xb4, 0x46, - 0xfb, 0x47, 0x78, 0xb2, 0x4a, 0x6e, 0x6b, 0xf0, 0xf2, 0xff, 0x0a, 0xc3, - 0x13, 0xba, 0xf8, 0x89, 0x3b, 0xd2, 0x6c, 0x5b, 0x6d, 0x1c, 0xdd, 0x35, - 0x70, 0xcd, 0xcf, 0x35, 0x3c, 0x7f, 0x47, 0x68, 0xaf, 0x4b, 0x4b, 0x61, - 0x2c, 0x83, 0x2e, 0xaa, 0xbb, 0xd4, 0x70, 0x6c, 0x70, 0x6c, 0x43, 0xe3, - 0x1c, 0x3f, 0xb2, 0x91, 0xf6, 0x7b, 0x42, 0x95, 0x9b, 0x9c, 0x59, 0x8c, - 0x7c, 0x0e, 0xfc, 0xc1, 0xb0, 0x11, 0xfa, 0xed, 0x24, 0xfc, 0x56, 0x0f, - 0xed, 0x83, 0xbf, 0xb9, 0x13, 0xfe, 0x66, 0x3f, 0xea, 0xca, 0xf1, 0x95, - 0xf6, 0xfb, 0x57, 0xae, 0x65, 0xab, 0x74, 0x58, 0xca, 0xae, 0x12, 0xe8, - 0xce, 0xc7, 0x90, 0xdf, 0x2e, 0x99, 0xa3, 0x29, 0x79, 0xc2, 0x57, 0xba, - 0xfc, 0x2d, 0x62, 0xe3, 0x3d, 0x6f, 0x16, 0x7a, 0xdd, 0x55, 0x10, 0x32, - 0xff, 0x52, 0x7c, 0xab, 0x36, 0x14, 0xdf, 0xe0, 0x53, 0x81, 0xdf, 0xa0, - 0x4a, 0xd3, 0xa4, 0x0a, 0xf6, 0xad, 0x60, 0xdf, 0x0a, 0xea, 0xc1, 0xd9, - 0x66, 0xfb, 0x77, 0xaa, 0xee, 0xb0, 0xc6, 0x66, 0xd8, 0xa8, 0x6f, 0x86, - 0xe7, 0xd2, 0xda, 0x9e, 0xc7, 0xc0, 0xbb, 0x47, 0xc1, 0xbb, 0x23, 0xa8, - 0x83, 0xfe, 0x04, 0x75, 0xd0, 0x1f, 0xa2, 0x0e, 0x3a, 0x8c, 0x3a, 0x68, - 0x0a, 0x75, 0xd0, 0x7d, 0xb0, 0xfd, 0x7b, 0x61, 0xfb, 0x93, 0xb0, 0xfd, - 0x09, 0x79, 0xc7, 0x73, 0xc8, 0xdf, 0x78, 0xef, 0x11, 0xed, 0xc5, 0xed, - 0x4d, 0x22, 0x88, 0xaf, 0x7c, 0x62, 0x9c, 0x1a, 0x2d, 0xae, 0x87, 0x5c, - 0x79, 0x7f, 0x35, 0xed, 0x4e, 0x6a, 0x53, 0xc8, 0xb9, 0xef, 0x1f, 0xe1, - 0x3a, 0x29, 0xa5, 0xee, 0x2b, 0x73, 0xf6, 0x73, 0x1e, 0xd2, 0x2e, 0xe4, - 0x6d, 0x38, 0xb3, 0x7d, 0xa6, 0xa8, 0x47, 0x35, 0x4a, 0xdf, 0x5a, 0x8d, - 0xb2, 0x3c, 0xcf, 0x35, 0xca, 0xab, 0x6b, 0x35, 0xca, 0xf2, 0x3c, 0xd7, - 0x28, 0xaf, 0xac, 0xab, 0x51, 0xae, 0x3c, 0xfd, 0xf2, 0xba, 0x1a, 0xe5, - 0xca, 0xd3, 0x2f, 0x85, 0x63, 0xa6, 0x03, 0x7e, 0xc9, 0x0d, 0x69, 0x35, - 0x5d, 0x3c, 0x7b, 0xc3, 0x7c, 0xe1, 0xfb, 0xfd, 0xeb, 0xff, 0x1f, 0x3a, - 0x6e, 0x9d, 0x1a, 0x39, 0xdf, 0xd8, 0xaa, 0xea, 0x9a, 0xf6, 0xf9, 0xde, - 0xb6, 0xf9, 0x55, 0xf9, 0x6d, 0xb4, 0x5c, 0xdb, 0xfc, 0x3e, 0xbc, 0x27, - 0xad, 0x0c, 0xdb, 0xf5, 0x02, 0x7d, 0x1c, 0xf0, 0xf7, 0x3d, 0x4f, 0x74, - 0xc9, 0xef, 0x6a, 0x9e, 0xcc, 0x91, 0x61, 0xa3, 0xa3, 0x47, 0xb7, 0x2a, - 0x3b, 0xe6, 0x7e, 0x5a, 0x53, 0xbe, 0xf9, 0x41, 0xe0, 0x01, 0xaf, 0x7d, - 0x43, 0xde, 0xe1, 0xa8, 0xf3, 0xaa, 0xbb, 0x6c, 0x23, 0xbf, 0x8a, 0x38, - 0x03, 0x59, 0x4b, 0xdc, 0x5c, 0xf3, 0x71, 0x9d, 0x18, 0xf9, 0xef, 0x08, - 0xd7, 0xcf, 0xd2, 0x8a, 0xee, 0xdb, 0x50, 0xef, 0xf1, 0x9a, 0x68, 0xdc, - 0x5e, 0x1f, 0x26, 0xc3, 0xfb, 0xac, 0x55, 0x95, 0x13, 0x49, 0x7c, 0x46, - 0x88, 0xef, 0xbf, 0x02, 0xe5, 0x37, 0x18, 0xde, 0x6c, 0x83, 0x1f, 0x47, - 0x9e, 0xc6, 0x77, 0x2b, 0x9c, 0x6f, 0x19, 0xf4, 0xee, 0x7c, 0x37, 0xbd, - 0x73, 0x1c, 0xf9, 0xa6, 0x6b, 0x67, 0x5f, 0x46, 0xbd, 0x70, 0x8a, 0xf3, - 0xe2, 0x51, 0xa6, 0x73, 0xc8, 0x9a, 0x25, 0xab, 0x5f, 0xe5, 0xd1, 0x47, - 0xb4, 0x4f, 0xd2, 0x2d, 0xc2, 0x7d, 0x7e, 0xd6, 0xb6, 0x8f, 0xd5, 0xb6, - 0x4f, 0x81, 0xed, 0xad, 0xf1, 0x75, 0x9c, 0xb9, 0xb2, 0xfd, 0x26, 0x33, - 0x1d, 0xd6, 0x52, 0x8f, 0x8c, 0x6e, 0xa6, 0xfa, 0x80, 0x7d, 0xee, 0x15, - 0xe4, 0xda, 0xe5, 0x51, 0xcc, 0xa5, 0x87, 0xf0, 0x8e, 0xe7, 0xed, 0x06, - 0x09, 0xfb, 0x5c, 0x83, 0x90, 0x4c, 0x77, 0xd9, 0x15, 0xbe, 0x63, 0x4b, - 0x0b, 0xee, 0x4b, 0xda, 0x1a, 0xa1, 0xfd, 0x66, 0x2e, 0xe2, 0xcc, 0x53, - 0xa8, 0x99, 0x8e, 0xa8, 0xbb, 0xaf, 0x70, 0x9f, 0x5b, 0xb4, 0x8b, 0x32, - 0xaf, 0xcd, 0x69, 0x95, 0xb4, 0x3a, 0xe3, 0x37, 0x60, 0xeb, 0xba, 0x60, - 0xd8, 0x77, 0x81, 0x5b, 0xa3, 0xa5, 0xe3, 0xba, 0xbc, 0xeb, 0x2c, 0x8f, - 0xb2, 0xac, 0xf9, 0x79, 0x3d, 0xde, 0x45, 0x67, 0xfa, 0xdb, 0xf0, 0x4c, - 0x5f, 0x0a, 0x6b, 0xed, 0xe8, 0x4c, 0x09, 0x7a, 0x63, 0xde, 0x04, 0xec, - 0x08, 0xf8, 0x51, 0xa2, 0x95, 0x96, 0xf5, 0x39, 0x78, 0x6a, 0x6d, 0xbc, - 0x31, 0x36, 0xc8, 0x30, 0xaa, 0x59, 0xc0, 0x83, 0x89, 0x0c, 0xec, 0x70, - 0xba, 0x3f, 0xba, 0x83, 0xd5, 0x1d, 0xa1, 0xa9, 0xda, 0x9b, 0xe7, 0x07, - 0x61, 0x8b, 0x16, 0xec, 0x93, 0xf3, 0x9d, 0x12, 0xd7, 0x19, 0xe1, 0xf7, - 0x4b, 0xdb, 0x9c, 0xa4, 0x2c, 0x6a, 0x15, 0x3e, 0x7f, 0x9e, 0x96, 0x5b, - 0x11, 0x0d, 0x39, 0xd8, 0xe3, 0x18, 0x7e, 0x23, 0x78, 0xe7, 0xe2, 0xc7, - 0x75, 0x4e, 0x81, 0x1e, 0x93, 0x79, 0x34, 0xf2, 0xe4, 0x61, 0xa6, 0xef, - 0x00, 0xd6, 0xb3, 0x3e, 0xb3, 0x9e, 0x1e, 0x20, 0x6f, 0x80, 0x7d, 0x45, - 0x06, 0xb8, 0x01, 0xe3, 0xbf, 0x0e, 0x5b, 0x1f, 0xc4, 0xd3, 0x36, 0xcb, - 0xcc, 0x5b, 0x89, 0x3f, 0x08, 0xf4, 0x1c, 0x7f, 0x3b, 0x18, 0x0f, 0xc7, - 0x43, 0xe6, 0xdd, 0xac, 0x7b, 0x99, 0x1d, 0x74, 0x6e, 0x31, 0x8a, 0x61, - 0x33, 0xb0, 0x41, 0xbe, 0x53, 0x1d, 0x07, 0x5f, 0x78, 0xac, 0x85, 0xb1, - 0x0c, 0xf3, 0xcb, 0x0b, 0x38, 0x77, 0x9e, 0x4e, 0xa1, 0x66, 0xa7, 0x01, - 0x7e, 0x22, 0x57, 0xf5, 0xb7, 0x84, 0xfa, 0xbe, 0x1e, 0x5e, 0x77, 0xb8, - 0x3f, 0x0e, 0xfa, 0x8c, 0x36, 0x78, 0x86, 0x51, 0xb5, 0xc5, 0x45, 0x42, - 0x2c, 0xcd, 0x04, 0xb7, 0x8b, 0xfc, 0x7d, 0xf4, 0x80, 0x3c, 0x53, 0x9e, - 0x0e, 0x2f, 0x06, 0x81, 0x97, 0x1b, 0xca, 0x2e, 0x93, 0x9d, 0x7d, 0x92, - 0xf6, 0x98, 0xfb, 0x48, 0x97, 0xdf, 0xe0, 0x50, 0x13, 0xdf, 0xde, 0x91, - 0x0f, 0x82, 0x93, 0xa0, 0xfd, 0x05, 0xb9, 0xcf, 0x7d, 0xa0, 0x1f, 0xbc, - 0x92, 0xf5, 0x04, 0xd3, 0x0a, 0xde, 0xa4, 0x99, 0xde, 0x24, 0x1d, 0x6e, - 0x9d, 0x0f, 0x65, 0xf3, 0x28, 0x79, 0xfe, 0xdb, 0x3a, 0xdf, 0x47, 0x97, - 0x5b, 0x4f, 0x86, 0xb4, 0xe5, 0x41, 0x2f, 0xf6, 0x6f, 0xbd, 0x90, 0x66, - 0xdf, 0xc0, 0x32, 0xf7, 0x90, 0xf1, 0x79, 0xa3, 0xcf, 0x40, 0x07, 0x3f, - 0xcd, 0x0f, 0xa4, 0x68, 0xbd, 0x1f, 0x60, 0xb8, 0xd4, 0x75, 0x74, 0x85, - 0xe9, 0x20, 0xe9, 0x3f, 0x85, 0xb3, 0x19, 0xf4, 0x30, 0x3e, 0x7d, 0x83, - 0x2f, 0xa8, 0xc8, 0xe7, 0xaa, 0xce, 0xbe, 0x89, 0xe3, 0x14, 0xeb, 0x70, - 0x0f, 0xfc, 0x1f, 0x74, 0x10, 0x76, 0x5c, 0x5c, 0xe4, 0x3b, 0x85, 0x61, - 0xbe, 0x87, 0x3a, 0x53, 0x82, 0x6c, 0x97, 0xf8, 0xbb, 0x60, 0x5a, 0xe5, - 0x82, 0xaa, 0x76, 0xb2, 0xd8, 0x17, 0x32, 0xaf, 0xa5, 0x9f, 0x2c, 0xc9, - 0xef, 0x80, 0x29, 0xac, 0x09, 0xf0, 0x6c, 0xff, 0x9b, 0x88, 0x9f, 0x14, - 0xd4, 0xdf, 0x44, 0x84, 0xdf, 0x64, 0x1b, 0x2a, 0x07, 0x78, 0xb8, 0x69, - 0xd0, 0x54, 0x33, 0xfa, 0x1b, 0x09, 0x96, 0x83, 0x83, 0x3a, 0x3e, 0x8a, - 0xfb, 0x81, 0x8c, 0x2f, 0xd5, 0x75, 0xb2, 0xfc, 0x66, 0x98, 0xcf, 0x70, - 0xfe, 0xce, 0x3c, 0xc4, 0x78, 0x59, 0xc9, 0x6f, 0x49, 0xec, 0x84, 0xfc, - 0xc0, 0x73, 0xdf, 0x80, 0x2d, 0x65, 0xc2, 0x98, 0x6c, 0x72, 0x7d, 0x18, - 0xd6, 0xac, 0xdb, 0xa9, 0x3a, 0xc9, 0xef, 0x13, 0xf4, 0xfa, 0xfc, 0xa0, - 0x7c, 0x5f, 0xa6, 0x44, 0xf8, 0x9e, 0xc7, 0x29, 0x2a, 0xcb, 0xf7, 0xf7, - 0x86, 0xf8, 0x50, 0x63, 0xdd, 0x1b, 0x8d, 0x33, 0x90, 0xa3, 0x82, 0x9b, - 0x46, 0x2c, 0x7b, 0x0c, 0x71, 0x6c, 0x1a, 0x7c, 0x2f, 0x4e, 0x54, 0x68, - 0x87, 0xc3, 0x3a, 0x0e, 0x99, 0xa5, 0x58, 0xc7, 0x58, 0xbf, 0x18, 0xa6, - 0x17, 0x79, 0x26, 0xce, 0x3b, 0x4a, 0x53, 0x7a, 0xfe, 0xfd, 0x83, 0xe5, - 0x9a, 0x6d, 0x16, 0xe8, 0xa3, 0xc0, 0x33, 0x78, 0xbc, 0x7a, 0xf0, 0x61, - 0x75, 0x4f, 0x2f, 0x44, 0xfe, 0xd2, 0xc1, 0xb2, 0xea, 0xe3, 0xcc, 0xef, - 0x87, 0x7d, 0x86, 0xd3, 0xe5, 0xf7, 0xd3, 0x7f, 0xbf, 0xd5, 0xa0, 0x8b, - 0xb7, 0x06, 0xc1, 0xfd, 0xfc, 0x0d, 0x27, 0xac, 0x41, 0xd5, 0x77, 0x71, - 0x8e, 0x13, 0xa8, 0x37, 0x46, 0x2d, 0xad, 0x04, 0xdb, 0x3d, 0xe5, 0xa3, - 0x5e, 0x11, 0xf6, 0xd8, 0xaa, 0x30, 0x11, 0x7f, 0xb9, 0x96, 0xff, 0xcd, - 0x7e, 0xfe, 0x26, 0x3c, 0xe7, 0xf2, 0x9a, 0x6d, 0xea, 0xae, 0xea, 0xe6, - 0xdb, 0xa4, 0xcf, 0x25, 0x0a, 0xe3, 0xd0, 0xcd, 0xed, 0xf6, 0xd1, 0x9e, - 0x23, 0xb2, 0x5d, 0xd0, 0x94, 0x01, 0x7a, 0xaa, 0xb5, 0x28, 0xdf, 0xe2, - 0xef, 0xfd, 0xab, 0x07, 0xbf, 0xdb, 0xbc, 0x74, 0x70, 0x16, 0xf2, 0xe1, - 0x33, 0xcd, 0x36, 0x23, 0xfd, 0x8b, 0x72, 0x7e, 0xee, 0x23, 0xfe, 0xfb, - 0x88, 0xff, 0x3e, 0xe2, 0xbf, 0x8f, 0xf8, 0xef, 0x23, 0xfe, 0xfb, 0x88, - 0xff, 0xe0, 0xe1, 0x0f, 0xa0, 0x2f, 0xe7, 0xfd, 0x89, 0x30, 0xdf, 0x7a, - 0x7c, 0x2d, 0xdf, 0x3a, 0xd7, 0xe2, 0x6f, 0x3f, 0x92, 0x96, 0x4a, 0x85, - 0x54, 0xbe, 0x4a, 0x82, 0xf3, 0x9b, 0x28, 0x5f, 0xbd, 0xfe, 0x37, 0x0c, - 0x05, 0xc7, 0xb9, 0x1a, 0xc3, 0x55, 0x34, 0xe1, 0x30, 0x9c, 0xca, 0xd7, - 0xb8, 0x46, 0x5a, 0x0f, 0xc3, 0xdf, 0xc9, 0xd8, 0xb7, 0xa9, 0x6f, 0x34, - 0xea, 0x7b, 0xd0, 0xe3, 0x5f, 0xf7, 0x10, 0x8b, 0xcb, 0x4d, 0x19, 0x8f, - 0x31, 0x7e, 0x06, 0x63, 0x83, 0xf5, 0x8f, 0xdf, 0xdd, 0xc3, 0x75, 0x41, - 0xb9, 0x89, 0xbc, 0x68, 0x39, 0xca, 0x85, 0x00, 0xe7, 0xbf, 0xa9, 0x95, - 0xea, 0x2c, 0x67, 0x41, 0xb3, 0x69, 0x30, 0xc5, 0x69, 0xaf, 0x75, 0x5e, - 0x96, 0xb5, 0x8e, 0xfa, 0x9b, 0x9e, 0x11, 0xd0, 0x16, 0xdd, 0xfd, 0x12, - 0xe9, 0xf3, 0x69, 0xf9, 0x77, 0x00, 0x29, 0x67, 0x58, 0xfe, 0x3d, 0x42, - 0x1f, 0xf6, 0x11, 0xf3, 0x3b, 0xdb, 0xee, 0x56, 0xa9, 0xa0, 0x7c, 0x76, - 0xa7, 0xfa, 0x3b, 0x08, 0x91, 0x86, 0xed, 0xde, 0xb6, 0x0d, 0x67, 0x83, - 0x5c, 0x5f, 0xdd, 0x2a, 0xf3, 0x67, 0xf8, 0xd1, 0x93, 0xc3, 0x7d, 0x03, - 0xd4, 0xb3, 0x9d, 0x4e, 0x0d, 0x73, 0xad, 0xb5, 0x19, 0xf8, 0x78, 0xad, - 0x9d, 0x2d, 0x88, 0xed, 0x74, 0x7a, 0x11, 0x7e, 0x76, 0xd1, 0x76, 0x59, - 0x97, 0x97, 0x86, 0xd3, 0xf0, 0xcf, 0x63, 0x03, 0x1c, 0x9f, 0x97, 0x5b, - 0xac, 0x2b, 0x7d, 0x80, 0x1f, 0x84, 0x5e, 0x6e, 0x82, 0x3d, 0x09, 0xec, - 0x1f, 0xe1, 0xfe, 0xb9, 0xc4, 0xdd, 0xe7, 0xec, 0xd9, 0x26, 0x75, 0x43, - 0xd8, 0xa6, 0x25, 0x40, 0xfb, 0x27, 0x6a, 0x44, 0x97, 0xf8, 0x6c, 0xb3, - 0x7e, 0xfb, 0xb7, 0xba, 0x37, 0xb5, 0x72, 0x9d, 0xff, 0x0e, 0x61, 0x98, - 0xf6, 0x41, 0xbf, 0x4c, 0xe7, 0x4d, 0xed, 0x81, 0xc6, 0xff, 0x14, 0x6e, - 0x75, 0xb1, 0x71, 0x5c, 0x55, 0xf8, 0xdc, 0x59, 0xaf, 0xed, 0x38, 0x6b, - 0x67, 0xe2, 0x6c, 0xec, 0xb5, 0x15, 0xc4, 0xce, 0x7a, 0x12, 0x4f, 0xb5, - 0x8e, 0x3a, 0xb6, 0x12, 0xb4, 0x42, 0x96, 0x58, 0xed, 0x7a, 0x5d, 0x87, - 0x92, 0xb2, 0x85, 0x50, 0x05, 0x09, 0x55, 0x96, 0x9d, 0xd2, 0x54, 0x80, - 0x90, 0xfa, 0x80, 0x78, 0xcb, 0x6a, 0x6d, 0x87, 0xa4, 0xec, 0x76, 0x6d, - 0x62, 0xd7, 0x2f, 0x3c, 0x2c, 0xeb, 0x75, 0x6a, 0xbb, 0x9b, 0xac, 0x42, - 0xfb, 0x50, 0x9e, 0x62, 0x99, 0x92, 0xc2, 0x4b, 0x85, 0xc4, 0x03, 0x02, - 0x54, 0xa9, 0x4a, 0xda, 0x34, 0x0f, 0x25, 0x11, 0xbc, 0x50, 0x0a, 0xd2, - 0xf0, 0x7d, 0x77, 0x66, 0x1d, 0x27, 0x50, 0x61, 0x69, 0x35, 0x77, 0xee, - 0xdc, 0x3b, 0x73, 0x7f, 0xce, 0xf9, 0xce, 0x77, 0xce, 0x3d, 0x66, 0x1b, - 0x1b, 0x65, 0xfa, 0xd3, 0xab, 0x6a, 0xa6, 0xda, 0x2b, 0x0b, 0x90, 0xe3, - 0xe2, 0x48, 0x38, 0x88, 0x97, 0x76, 0x05, 0xfa, 0x0c, 0xc7, 0xdf, 0xb7, - 0x57, 0x9a, 0x57, 0x16, 0xcd, 0x4e, 0xcd, 0xab, 0x1e, 0x7d, 0x76, 0x0a, - 0x63, 0x8a, 0x61, 0x1d, 0xba, 0xfb, 0x34, 0x36, 0x19, 0xbc, 0xef, 0x7f, - 0xec, 0xbe, 0xef, 0xb1, 0xfb, 0xc3, 0xff, 0xa3, 0x3d, 0xcb, 0x8f, 0xcb, - 0x03, 0xc7, 0x69, 0xa5, 0xf8, 0x95, 0x62, 0xc9, 0x36, 0x66, 0x4b, 0x56, - 0x9a, 0xbc, 0x20, 0x2b, 0x9e, 0xca, 0xba, 0xed, 0xc0, 0xbb, 0x76, 0x99, - 0x5f, 0x86, 0xcc, 0x63, 0x1e, 0x1d, 0x36, 0xcf, 0xb4, 0x13, 0x7d, 0xd4, - 0x99, 0x4e, 0x6c, 0x83, 0x61, 0x0f, 0xc5, 0xd0, 0xce, 0x7b, 0xc9, 0x4d, - 0x9a, 0xe7, 0x74, 0x1c, 0x86, 0x7c, 0xc6, 0x53, 0x45, 0x9d, 0x9f, 0xc1, - 0x36, 0x6d, 0x72, 0xc7, 0xce, 0xf4, 0x06, 0xf9, 0x3e, 0xf0, 0x5b, 0xc7, - 0xfa, 0xc8, 0x35, 0x5e, 0x74, 0x77, 0xeb, 0xcc, 0xdb, 0xc2, 0x3c, 0x2a, - 0x08, 0xcd, 0xb3, 0x22, 0xd5, 0xba, 0xc8, 0xeb, 0xf8, 0xfd, 0xae, 0x1e, - 0xf8, 0x0a, 0x8a, 0x3e, 0xf3, 0xb8, 0x6c, 0x55, 0xbe, 0x2c, 0x0d, 0xd8, - 0x9f, 0x4d, 0xd7, 0xf3, 0xee, 0xb9, 0x71, 0xbd, 0xe6, 0x3f, 0x29, 0x29, - 0x49, 0x8c, 0xd2, 0xbe, 0xb5, 0xcb, 0x4f, 0x97, 0xdb, 0x64, 0xdb, 0xb4, - 0xcc, 0x7b, 0xc2, 0x5c, 0xb6, 0x98, 0x4c, 0x45, 0x43, 0x9a, 0xa3, 0xca, - 0xb7, 0xc0, 0xa0, 0xf1, 0xec, 0xee, 0xf2, 0x33, 0x7d, 0x8c, 0x9d, 0x7c, - 0xb4, 0xcc, 0x7b, 0x03, 0x57, 0x43, 0x76, 0xec, 0x10, 0xb8, 0x2c, 0x40, - 0xc8, 0xe4, 0xba, 0x73, 0xbe, 0xcf, 0x71, 0x6c, 0xa8, 0xa3, 0x2f, 0xda, - 0x2e, 0xc5, 0xa3, 0xc0, 0x44, 0x35, 0xa4, 0x73, 0x8a, 0x76, 0xa2, 0x1a, - 0xa3, 0x43, 0x35, 0xe6, 0xc8, 0x99, 0xfb, 0x35, 0x5e, 0x67, 0xae, 0x7d, - 0x5f, 0xcf, 0x05, 0xe5, 0x42, 0xcd, 0xa5, 0xac, 0x9a, 0xb2, 0x09, 0x5d, - 0xdb, 0x68, 0x2e, 0xf5, 0x73, 0xaf, 0xb6, 0x9a, 0x3f, 0xe8, 0xf3, 0x7d, - 0x2d, 0xd6, 0xfd, 0xb0, 0xcf, 0xaf, 0x8b, 0x07, 0xbe, 0x13, 0x7d, 0xac, - 0x2a, 0xe6, 0xf6, 0xb2, 0x34, 0x57, 0x7f, 0x2c, 0x6f, 0x57, 0x7e, 0x24, - 0xbf, 0x5a, 0x3d, 0x0b, 0xfe, 0x61, 0x55, 0x0b, 0xb0, 0x27, 0x37, 0x9a, - 0x9e, 0x77, 0xc3, 0x3d, 0x03, 0x5f, 0xc1, 0xf3, 0xfe, 0xe0, 0x6e, 0x4b, - 0x62, 0xec, 0x3b, 0x98, 0x73, 0x1e, 0x3a, 0x44, 0x2c, 0x9c, 0x82, 0xbc, - 0x25, 0xfb, 0xa5, 0x2b, 0xa2, 0xe5, 0x64, 0x68, 0x2c, 0x8c, 0x39, 0x18, - 0x01, 0x27, 0xe7, 0x5c, 0x46, 0xfa, 0x29, 0x33, 0x46, 0xf3, 0x15, 0x7c, - 0x3f, 0x0c, 0xbd, 0xd8, 0x8f, 0x9f, 0x92, 0x7b, 0xa3, 0x18, 0xeb, 0x28, - 0x65, 0x2f, 0x2c, 0x89, 0x27, 0x31, 0x8f, 0x7c, 0x9b, 0xdc, 0x2f, 0x5d, - 0xe9, 0x63, 0x5c, 0xee, 0x7e, 0x89, 0x65, 0xe3, 0x4b, 0x3d, 0xe2, 0x49, - 0x1b, 0x6c, 0xf9, 0xfc, 0x09, 0x9f, 0x37, 0xfd, 0x5a, 0x0d, 0xa3, 0xbd, - 0x5d, 0x78, 0x47, 0x91, 0xe7, 0x15, 0xbc, 0x30, 0x78, 0x79, 0x0e, 0x7c, - 0x28, 0xd3, 0xbc, 0x20, 0x3b, 0xa3, 0x11, 0xb4, 0x21, 0x5f, 0xd1, 0x58, - 0x22, 0xd9, 0x12, 0x73, 0xb0, 0x98, 0x0f, 0x85, 0x31, 0x9e, 0x21, 0x6e, - 0x70, 0x8c, 0xed, 0x3c, 0xb7, 0x0b, 0xea, 0x6c, 0xc8, 0x08, 0xeb, 0x28, - 0xdf, 0x69, 0xcd, 0xa9, 0x60, 0x43, 0xf1, 0xbe, 0x11, 0xc9, 0xe8, 0x72, - 0x0f, 0xde, 0x77, 0x41, 0xe7, 0x25, 0xfa, 0xef, 0x4c, 0xa1, 0x0d, 0x71, - 0x26, 0x05, 0x2e, 0xf1, 0xa1, 0x9a, 0x00, 0xbd, 0x99, 0x29, 0xf5, 0xc9, - 0x84, 0xb9, 0x6f, 0xcf, 0x1c, 0x0b, 0xda, 0x57, 0x30, 0x8c, 0x91, 0x60, - 0x4c, 0x3d, 0x7b, 0xc6, 0xc4, 0xfe, 0xf8, 0xc1, 0xc7, 0xcd, 0x2c, 0x2f, - 0x02, 0xa7, 0x16, 0x7f, 0x9b, 0x71, 0x9f, 0x97, 0x6c, 0xb4, 0x5d, 0xfb, - 0x36, 0x35, 0xec, 0x4b, 0xb6, 0xc4, 0x78, 0xd4, 0xb7, 0x81, 0x43, 0xfb, - 0x82, 0x3a, 0xb6, 0x15, 0x23, 0x83, 0xb5, 0x4f, 0x6b, 0x3d, 0x64, 0xdd, - 0x17, 0x25, 0xb3, 0x98, 0x97, 0x49, 0xdd, 0x8f, 0x6b, 0x38, 0xa8, 0x79, - 0x08, 0x75, 0x35, 0x71, 0x08, 0x6b, 0x99, 0x0c, 0x07, 0x6d, 0xf7, 0x91, - 0xc9, 0xe3, 0xef, 0xd3, 0x40, 0x67, 0xf1, 0xec, 0x10, 0xf7, 0xa8, 0x5d, - 0x12, 0xdf, 0x84, 0xbd, 0x2c, 0xb5, 0xea, 0x23, 0xf2, 0x49, 0xe9, 0xb3, - 0x3e, 0x9e, 0x93, 0xfc, 0xb5, 0x64, 0xca, 0x47, 0x25, 0x7d, 0x7e, 0x3a, - 0x1d, 0x12, 0xeb, 0xbc, 0xef, 0x67, 0x1f, 0x9d, 0x9e, 0x57, 0x7c, 0x7e, - 0xf4, 0xfc, 0xba, 0xea, 0x44, 0xdb, 0x08, 0xda, 0x71, 0x1c, 0xa6, 0xe4, - 0x4a, 0x7f, 0xf7, 0x66, 0x8e, 0x79, 0xde, 0xa4, 0xce, 0xe1, 0x4a, 0x9a, - 0xf3, 0xaa, 0xc5, 0xcf, 0x1d, 0x29, 0x45, 0x3b, 0xf0, 0xad, 0xa4, 0xb9, - 0xae, 0x8e, 0x62, 0x3c, 0x2c, 0x1f, 0xa2, 0x4e, 0xc4, 0xb6, 0x85, 0xef, - 0xb7, 0xa6, 0xd6, 0x54, 0x32, 0x3e, 0xa4, 0xac, 0x74, 0x11, 0xbf, 0x36, - 0xa5, 0xcf, 0x1e, 0x63, 0x71, 0x05, 0xdd, 0xc5, 0x9c, 0xec, 0xe3, 0x9e, - 0x37, 0x65, 0xb3, 0x3e, 0x69, 0x46, 0x14, 0xe3, 0x26, 0x5d, 0xfa, 0x8c, - 0xf2, 0xd2, 0xe1, 0xa4, 0x79, 0x5c, 0x1d, 0x0c, 0xee, 0x53, 0xc0, 0xcc, - 0xdd, 0xf7, 0x9d, 0x5d, 0x53, 0xa6, 0x5c, 0x2e, 0x25, 0xe3, 0xb3, 0xca, - 0xca, 0xe3, 0x9d, 0xf9, 0x09, 0x45, 0xdc, 0x48, 0x9a, 0x5d, 0x8a, 0xb1, - 0xcd, 0x0e, 0x3d, 0xef, 0x29, 0xf4, 0x4f, 0xaa, 0xb6, 0x60, 0x3c, 0xdc, - 0xaf, 0xcb, 0xfd, 0xbe, 0xce, 0x10, 0x73, 0x06, 0x8c, 0x99, 0x45, 0xe6, - 0x83, 0xe9, 0x3c, 0x84, 0x74, 0x62, 0x8c, 0xf7, 0x86, 0x3c, 0x38, 0xf9, - 0x0f, 0xd4, 0xa1, 0x5c, 0x65, 0x9d, 0x13, 0xe8, 0xdb, 0x31, 0xcd, 0x9f, - 0x1f, 0x9c, 0x2c, 0xe8, 0xfc, 0xc4, 0x1d, 0x95, 0x08, 0xe6, 0xbd, 0xbb, - 0x67, 0xf1, 0x8c, 0xfb, 0x05, 0xbe, 0x67, 0x31, 0x34, 0xde, 0x21, 0xcc, - 0x07, 0xcd, 0x55, 0x5a, 0xb2, 0xc1, 0xd8, 0x00, 0xcf, 0xf7, 0x5b, 0x67, - 0xe5, 0x17, 0xc4, 0x18, 0xeb, 0xdc, 0x23, 0x27, 0xe0, 0x9d, 0xe0, 0xab, - 0x75, 0xbc, 0xa7, 0xb8, 0x2c, 0x05, 0xbf, 0xbf, 0x74, 0x32, 0xff, 0xb4, - 0x58, 0xff, 0xbc, 0x77, 0xf8, 0x36, 0x30, 0x87, 0xfb, 0x07, 0x27, 0x29, - 0x9f, 0x5c, 0x9b, 0xb8, 0x9a, 0xbc, 0xc2, 0xf1, 0x0c, 0x4a, 0x6e, 0x19, - 0xdc, 0x08, 0xbf, 0xf9, 0x65, 0x7f, 0xdf, 0xd6, 0xc1, 0xb3, 0x73, 0x25, - 0x53, 0xeb, 0xeb, 0xac, 0xcb, 0xb3, 0x0f, 0xe8, 0x8a, 0xce, 0x7b, 0x62, - 0x5f, 0xe6, 0x0a, 0x1e, 0xa1, 0x7d, 0x74, 0x6a, 0x12, 0x45, 0x5b, 0x72, - 0x56, 0xd6, 0x83, 0xbf, 0xc3, 0x66, 0x16, 0x5f, 0x8d, 0x08, 0x30, 0x39, - 0x15, 0x0f, 0x1d, 0x90, 0x79, 0xd7, 0x95, 0x46, 0xf3, 0x84, 0x5c, 0x6b, - 0x3a, 0xfa, 0x19, 0xed, 0xd9, 0xc2, 0x6b, 0xfa, 0x5c, 0x3a, 0xfe, 0xa1, - 0xb2, 0x9c, 0xab, 0xf0, 0x6b, 0xbe, 0x7b, 0x8c, 0x79, 0xc2, 0xe1, 0x81, - 0x87, 0x79, 0x70, 0xc0, 0x0e, 0x70, 0x8e, 0xb7, 0xc0, 0x39, 0xde, 0x04, - 0xe7, 0xf8, 0x25, 0x38, 0xf6, 0x8d, 0xca, 0x54, 0x80, 0xff, 0xd3, 0xc0, - 0x21, 0xda, 0x6a, 0xeb, 0x2c, 0xf6, 0x74, 0xba, 0x00, 0x19, 0xfc, 0x00, - 0xfe, 0xc7, 0x56, 0x25, 0x23, 0x1b, 0xab, 0x93, 0xb2, 0xb9, 0xea, 0xe7, - 0x1c, 0xbf, 0xcb, 0x3c, 0xad, 0x51, 0xee, 0x93, 0x03, 0x1c, 0xda, 0x27, - 0x89, 0xe3, 0xc4, 0x8f, 0x4e, 0x59, 0x2b, 0xaf, 0x69, 0x1c, 0x5a, 0x2b, - 0xb3, 0x1c, 0x12, 0x9d, 0xf3, 0x75, 0x66, 0x5b, 0x6a, 0xee, 0x16, 0xea, - 0xbb, 0x99, 0xdb, 0x15, 0xc4, 0xd6, 0x89, 0x97, 0x7f, 0x0e, 0xf6, 0x5e, - 0xe9, 0x5c, 0xb8, 0x19, 0xf3, 0x00, 0xda, 0xb5, 0xb0, 0x6b, 0xc8, 0x3f, - 0x27, 0x57, 0x7f, 0x41, 0x1b, 0x7c, 0x03, 0x9c, 0xf1, 0x2a, 0x6c, 0xc8, - 0x8e, 0x73, 0x40, 0x73, 0xbf, 0x1d, 0xe7, 0x88, 0xce, 0xad, 0xe5, 0x7b, - 0x8a, 0x65, 0x5b, 0xe6, 0xca, 0x56, 0xbc, 0x00, 0xf9, 0xbb, 0x06, 0xbf, - 0x6d, 0x03, 0x7b, 0xb0, 0x89, 0xb5, 0xd8, 0x6a, 0xd2, 0xce, 0xbf, 0xaf, - 0xb1, 0x77, 0xad, 0xf9, 0x27, 0xbc, 0xc7, 0x3a, 0x9b, 0x96, 0x3f, 0xf6, - 0x13, 0x03, 0x99, 0x8f, 0x97, 0xd5, 0xfd, 0xfd, 0x7e, 0x1b, 0x68, 0xbb, - 0xd9, 0x24, 0x1e, 0x8b, 0x5c, 0x2c, 0xd9, 0xb0, 0x25, 0x17, 0x63, 0xe4, - 0x00, 0x55, 0xd5, 0xea, 0xe7, 0x05, 0x63, 0xf6, 0xbc, 0xfd, 0x36, 0xc7, - 0xe5, 0x04, 0xb8, 0x4d, 0xdb, 0xbf, 0xad, 0xb9, 0x4d, 0xa9, 0xf2, 0xbc, - 0x5c, 0x5f, 0x4d, 0x05, 0x1c, 0x27, 0x2f, 0x6f, 0x80, 0xe3, 0x35, 0x2b, - 0xad, 0x1c, 0xed, 0x71, 0xac, 0x53, 0x45, 0xcd, 0x2d, 0x75, 0xc9, 0xa5, - 0x95, 0xa2, 0xba, 0xbc, 0x52, 0x52, 0xaf, 0x2c, 0x95, 0x55, 0x71, 0xc9, - 0xf3, 0xfe, 0xe9, 0xce, 0xc8, 0xdb, 0xab, 0x9e, 0x9c, 0x76, 0x8d, 0x81, - 0x90, 0xb4, 0xf2, 0xdf, 0x3c, 0xaf, 0x13, 0xd8, 0xbc, 0x75, 0xd8, 0xf3, - 0x9e, 0x18, 0x1d, 0x15, 0xe7, 0x30, 0x39, 0xca, 0x70, 0x8c, 0x39, 0xac, - 0xc4, 0x9c, 0x8c, 0x6d, 0x9f, 0xaf, 0x29, 0x05, 0x7c, 0x3b, 0xe0, 0xf3, - 0x97, 0x27, 0xbb, 0x83, 0x33, 0x8f, 0xb3, 0x2f, 0x31, 0x26, 0x1c, 0xfb, - 0xaf, 0x98, 0xb0, 0x29, 0xe7, 0xca, 0x58, 0x88, 0xae, 0xa8, 0x7c, 0xaf, - 0x1c, 0x79, 0xac, 0x6c, 0xe2, 0xea, 0x18, 0xc5, 0xf2, 0x7d, 0x6f, 0x48, - 0xc7, 0xfe, 0xc1, 0x49, 0x4c, 0xcf, 0x9b, 0x75, 0xf9, 0xbd, 0x03, 0x8c, - 0xc9, 0x98, 0xdd, 0xb0, 0xff, 0xa7, 0xb5, 0x7d, 0xae, 0xaa, 0x8c, 0x4d, - 0xfd, 0x8e, 0xca, 0x44, 0x19, 0x36, 0x5e, 0x31, 0x2f, 0x94, 0x5c, 0xc1, - 0x8a, 0xcd, 0x02, 0x3b, 0x66, 0x80, 0x37, 0x4f, 0xeb, 0xb3, 0xd1, 0x43, - 0x1a, 0x7b, 0xe6, 0x58, 0xce, 0x4b, 0xba, 0xe6, 0xf6, 0xea, 0xf5, 0xbb, - 0x7d, 0xad, 0x18, 0xf3, 0xf7, 0x1c, 0x7a, 0x9c, 0xe7, 0xf9, 0x40, 0xaf, - 0x64, 0xd7, 0xcf, 0x40, 0x27, 0x62, 0x58, 0xdb, 0xb0, 0xd6, 0x87, 0x1d, - 0xd8, 0xef, 0x1d, 0x27, 0x1c, 0x60, 0x6a, 0x27, 0xee, 0xd9, 0x6e, 0x12, - 0xfd, 0x3a, 0x24, 0xb3, 0xd4, 0xae, 0x71, 0xf5, 0xd1, 0xba, 0x34, 0x78, - 0x48, 0x0e, 0xe5, 0x10, 0xea, 0xe2, 0x41, 0x99, 0xdc, 0x6b, 0x1a, 0xe5, - 0x36, 0x5c, 0xd9, 0xe6, 0x28, 0x78, 0x05, 0xae, 0xbf, 0xc0, 0xfb, 0x46, - 0x31, 0xe6, 0xbc, 0x29, 0xef, 0x9d, 0xa4, 0x2d, 0x71, 0x0c, 0xe6, 0x1a, - 0xcf, 0xda, 0xb8, 0x36, 0xca, 0x2a, 0xbb, 0xc8, 0x32, 0xae, 0x55, 0xff, - 0xf9, 0x23, 0x98, 0x84, 0x3e, 0x99, 0x15, 0x1f, 0x93, 0xde, 0xdb, 0xc5, - 0x24, 0xd6, 0x75, 0xc8, 0xc4, 0x52, 0x5c, 0x9d, 0xba, 0x62, 0x42, 0xde, - 0xba, 0x24, 0xbb, 0x12, 0xd5, 0x7c, 0xb4, 0x06, 0x59, 0x5c, 0x87, 0x5c, - 0xad, 0x41, 0xa6, 0x32, 0x65, 0x2b, 0x35, 0xad, 0xe2, 0x3a, 0x2e, 0x30, - 0x05, 0x79, 0x0d, 0xbf, 0x4a, 0x2e, 0x4a, 0xfd, 0x75, 0xd0, 0x46, 0x68, - 0x47, 0xd3, 0x61, 0x65, 0x43, 0x0e, 0x21, 0x97, 0x65, 0x5f, 0x7f, 0xdf, - 0x51, 0x1a, 0x57, 0x53, 0x77, 0x24, 0xe9, 0xdc, 0x11, 0xcb, 0xdd, 0xc1, - 0xef, 0x37, 0xe2, 0xca, 0x55, 0xe8, 0xfb, 0xeb, 0xf8, 0x4e, 0xf8, 0x35, - 0x43, 0x8e, 0x0d, 0x6b, 0x9d, 0x4e, 0x49, 0xc8, 0x72, 0x36, 0xc5, 0xd7, - 0xf1, 0x75, 0xad, 0xe3, 0x90, 0x37, 0x60, 0x90, 0xaf, 0xd3, 0xe9, 0x40, - 0x46, 0xbf, 0x01, 0xfd, 0xb5, 0xe0, 0x95, 0xc5, 0x65, 0x1e, 0xfa, 0x7f, - 0x15, 0xcf, 0x6f, 0x36, 0x3f, 0x56, 0x73, 0x8b, 0x2a, 0xc8, 0x3f, 0x79, - 0x0e, 0x3c, 0xf9, 0xf7, 0x58, 0xbb, 0x1e, 0xcd, 0xdd, 0x13, 0xa3, 0x3c, - 0x07, 0xfb, 0xb7, 0xba, 0x64, 0x1f, 0x97, 0xdb, 0x23, 0x27, 0x50, 0xee, - 0xc6, 0xd5, 0xc0, 0x3a, 0x44, 0xf4, 0xf9, 0xf5, 0x5a, 0x69, 0xc4, 0x28, - 0xea, 0x33, 0xe6, 0x31, 0xf4, 0x25, 0x96, 0x1d, 0xc6, 0x73, 0xc6, 0x65, - 0x38, 0x37, 0x70, 0x26, 0x15, 0xd3, 0x39, 0xa1, 0x35, 0x70, 0x89, 0x75, - 0xbc, 0xef, 0x16, 0xe3, 0x7a, 0x0d, 0xe8, 0xf0, 0xc8, 0x67, 0x5e, 0x3a, - 0xca, 0xbc, 0xf3, 0xf7, 0x63, 0xbe, 0xfd, 0xfb, 0xc4, 0xbb, 0x6d, 0xcf, - 0xa5, 0x0c, 0xdc, 0x7c, 0x60, 0x02, 0xef, 0xc8, 0xdb, 0x61, 0x8b, 0xaa, - 0x5a, 0x7e, 0xd9, 0xce, 0xef, 0x5b, 0x6c, 0x24, 0xcd, 0x77, 0xc5, 0xef, - 0x3b, 0x6f, 0xd3, 0xee, 0x74, 0x00, 0x5f, 0xe2, 0x9a, 0x57, 0xde, 0xb2, - 0x0b, 0x40, 0x05, 0x2b, 0x3e, 0x05, 0x19, 0x6d, 0x17, 0xcb, 0xc9, 0xc9, - 0xc3, 0xef, 0xce, 0xea, 0xbe, 0x6c, 0xdb, 0xea, 0xdb, 0xfa, 0x2e, 0xc7, - 0xcf, 0xb9, 0x70, 0x0e, 0xf0, 0x6d, 0x4c, 0x53, 0xcb, 0xe8, 0x4e, 0xc3, - 0x18, 0xf0, 0x65, 0xb4, 0x35, 0x8f, 0xe8, 0xff, 0x99, 0x07, 0xe5, 0x64, - 0xc4, 0xf0, 0xcf, 0xdb, 0x71, 0x6d, 0x70, 0x3d, 0x3f, 0x06, 0xbf, 0xdf, - 0x2b, 0x3f, 0xad, 0x38, 0xa3, 0x2f, 0x3f, 0x4f, 0xec, 0xca, 0x0f, 0x7d, - 0xd4, 0x2e, 0xc9, 0xad, 0xd8, 0x32, 0x59, 0xd6, 0xfb, 0x0d, 0xae, 0xc9, - 0xf8, 0xd1, 0x09, 0xc8, 0x0d, 0x65, 0x9d, 0xba, 0x65, 0x4a, 0x15, 0x72, - 0x54, 0x05, 0x3e, 0x55, 0x21, 0x53, 0xe4, 0x40, 0x55, 0xe0, 0x5b, 0xb5, - 0x69, 0x39, 0x75, 0xcc, 0x99, 0x36, 0x7b, 0x1d, 0x72, 0x74, 0xb5, 0xc9, - 0xfd, 0xd7, 0x63, 0x36, 0x69, 0x07, 0x6f, 0xee, 0xee, 0xfd, 0xa7, 0xd8, - 0xfb, 0x23, 0x72, 0x0d, 0x7e, 0xcb, 0xf5, 0xca, 0x08, 0x30, 0x49, 0x80, - 0x51, 0x2e, 0x64, 0x23, 0x25, 0x1b, 0x95, 0x71, 0xd9, 0x84, 0x7d, 0xda, - 0x5a, 0x4d, 0x80, 0x4f, 0x03, 0x47, 0xaf, 0x1c, 0x93, 0x37, 0x56, 0x95, - 0xcc, 0xd8, 0xb0, 0x33, 0x6b, 0x8c, 0xc1, 0x43, 0x9e, 0xab, 0x5d, 0xfa, - 0xbc, 0x7d, 0xa2, 0xee, 0xc7, 0xe2, 0x73, 0xf5, 0x1e, 0x99, 0xac, 0x9b, - 0xf2, 0x54, 0xbd, 0x57, 0xbe, 0x5a, 0x8f, 0xca, 0xe9, 0x46, 0x4c, 0xbe, - 0x56, 0x1f, 0x94, 0xa7, 0xeb, 0x47, 0xe4, 0x99, 0x46, 0x5c, 0xbe, 0x0e, - 0xbf, 0x30, 0xdf, 0x70, 0x64, 0xaa, 0x31, 0x22, 0xa7, 0x1a, 0x8c, 0xb1, - 0xe3, 0x7b, 0xf8, 0x65, 0x77, 0x63, 0x17, 0x1c, 0x57, 0x27, 0xc6, 0xe5, - 0xa8, 0x9c, 0x3e, 0x6f, 0x94, 0xbc, 0x1f, 0xff, 0x10, 0x79, 0x01, 0x7d, - 0x17, 0xae, 0x28, 0xa9, 0xe9, 0xef, 0xb7, 0xfe, 0x47, 0x24, 0xa2, 0x7d, - 0xa3, 0x17, 0xaa, 0x83, 0x68, 0x63, 0xd3, 0x27, 0x09, 0xe2, 0x20, 0xad, - 0xf8, 0x7f, 0xcb, 0xf7, 0x32, 0x74, 0x0c, 0xfb, 0x26, 0x7d, 0x2f, 0xbd, - 0xf6, 0xc4, 0x0f, 0xfa, 0x39, 0xf4, 0xb5, 0xf6, 0x9e, 0x51, 0xb4, 0xbe, - 0xbb, 0x90, 0x7f, 0xf4, 0x7f, 0x51, 0xfc, 0xb3, 0xa6, 0x73, 0x8d, 0x41, - 0xfe, 0x4f, 0x0a, 0xc6, 0xf2, 0xf9, 0xf9, 0xdd, 0x93, 0x95, 0x09, 0xf5, - 0x54, 0x85, 0x8c, 0xc6, 0x93, 0x85, 0xdd, 0x3c, 0xba, 0xaf, 0xc8, 0x9a, - 0x1b, 0xd1, 0x63, 0xf0, 0xe3, 0xf6, 0x69, 0x9d, 0x53, 0x37, 0x31, 0x4c, - 0xf9, 0xe3, 0x19, 0x5a, 0x4f, 0x70, 0xb6, 0x00, 0x6e, 0xeb, 0x9a, 0x72, - 0xb1, 0xee, 0xc7, 0xaf, 0xe6, 0xb4, 0xbc, 0x5c, 0x87, 0xcc, 0xf1, 0xfc, - 0xc1, 0xbf, 0x16, 0xaa, 0x7e, 0xdf, 0xec, 0xb0, 0x43, 0x7f, 0x1c, 0xf3, - 0x35, 0x7a, 0xf9, 0x2d, 0xfe, 0x4f, 0x0e, 0xca, 0xc1, 0x78, 0x99, 0x0f, - 0x6c, 0x6b, 0x59, 0xf4, 0xcf, 0x67, 0x1d, 0x79, 0x11, 0x7b, 0x51, 0x33, - 0x39, 0xfe, 0x4e, 0xa9, 0x39, 0xf4, 0x6d, 0x89, 0xdf, 0xc3, 0x52, 0xc5, - 0x77, 0x6a, 0x4e, 0x2b, 0x36, 0xe6, 0xe3, 0x6c, 0xcd, 0x7c, 0xf8, 0xdd, - 0xe9, 0xea, 0x41, 0xdc, 0xa3, 0xce, 0x01, 0x67, 0x3a, 0xc3, 0xfb, 0x05, - 0x94, 0x19, 0x1b, 0x99, 0xc3, 0x35, 0x16, 0xd4, 0xfd, 0x7c, 0x40, 0x73, - 0xf5, 0xf1, 0x87, 0xfd, 0x66, 0xaa, 0x56, 0x21, 0x13, 0xba, 0xab, 0x8c, - 0x9f, 0xad, 0x0f, 0x10, 0x73, 0x0f, 0xda, 0xfc, 0x45, 0xe4, 0x6f, 0xa6, - 0x8e, 0x29, 0x04, 0xcf, 0xf6, 0xc9, 0xb3, 0x26, 0x73, 0xcd, 0xd3, 0x6a, - 0xa2, 0xf2, 0x72, 0x90, 0x57, 0x7b, 0x57, 0x1d, 0xac, 0x35, 0x07, 0xfc, - 0xbc, 0x74, 0xbe, 0x7b, 0x6f, 0x2e, 0xfa, 0x5e, 0x39, 0x61, 0x4e, 0x7a, - 0x07, 0x78, 0xab, 0x36, 0x62, 0xd0, 0x41, 0xe0, 0x9d, 0xdd, 0xa6, 0xf5, - 0xb1, 0xd8, 0xf8, 0x97, 0xb7, 0xad, 0xf5, 0xb9, 0x15, 0x63, 0xb8, 0x35, - 0x40, 0xdf, 0x96, 0xb8, 0x71, 0xd1, 0x8f, 0x1b, 0x69, 0x1f, 0x1a, 0x58, - 0x81, 0x3a, 0xea, 0x2a, 0xf4, 0x64, 0xb7, 0x2d, 0xff, 0xfe, 0x03, 0x7d, - 0xe7, 0x95, 0xf0, 0x2c, 0x67, 0x00, 0x00, 0x00 }; + 0xec, 0x5b, 0x6d, 0x6c, 0x5c, 0x57, 0x5a, 0x7e, 0xef, 0x99, 0xb1, 0x3d, + 0x76, 0x6c, 0xe7, 0xda, 0x99, 0xa6, 0x93, 0xe2, 0x6e, 0x67, 0xec, 0x6b, + 0x7b, 0xba, 0x36, 0xe5, 0x3a, 0x4c, 0x5b, 0xaf, 0x18, 0xb6, 0xc3, 0x1d, + 0x27, 0x75, 0x77, 0x83, 0xe4, 0xb6, 0x61, 0x37, 0x82, 0xae, 0xb0, 0x66, + 0x12, 0x51, 0x84, 0x10, 0x21, 0x82, 0xaa, 0x2c, 0x5d, 0x65, 0x34, 0x76, + 0x53, 0xb7, 0x3b, 0xf1, 0x0c, 0x89, 0x4b, 0xf8, 0xd8, 0x1f, 0xee, 0xd8, + 0x4e, 0x0a, 0x9a, 0x78, 0xba, 0xcb, 0x8f, 0x5d, 0x56, 0x4d, 0x63, 0xd2, + 0x12, 0xfa, 0x03, 0x89, 0x16, 0x56, 0x50, 0x89, 0x85, 0x86, 0x24, 0xdb, + 0x14, 0x09, 0x41, 0x77, 0x01, 0x6d, 0xa1, 0x69, 0x2f, 0xcf, 0x73, 0xee, + 0xbd, 0xc9, 0xc4, 0x35, 0x6c, 0x7f, 0xf0, 0xf3, 0x1e, 0xc9, 0xba, 0xf7, + 0x9e, 0xf3, 0x9e, 0xf7, 0xbc, 0xdf, 0x1f, 0x67, 0x92, 0xdf, 0xe8, 0x96, + 0x2e, 0xf1, 0x47, 0x0f, 0xfe, 0x32, 0x87, 0x9f, 0x3c, 0x72, 0xef, 0x3d, + 0xf6, 0x3d, 0xfc, 0x8e, 0xb4, 0x49, 0x94, 0x4f, 0x43, 0xc2, 0x11, 0x8e, + 0x70, 0x84, 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, + 0x84, 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, + 0x23, 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, + 0x1c, 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, 0x1c, + 0xe1, 0x08, 0x47, 0x38, 0xc2, 0x11, 0x8e, 0x70, 0x84, 0x23, 0x1c, 0xe1, + 0x08, 0x47, 0x38, 0xc2, 0xf1, 0xff, 0x39, 0x22, 0x22, 0x26, 0x9f, 0x3d, + 0xfe, 0x9f, 0xc4, 0x54, 0x56, 0x8e, 0x38, 0x96, 0xc4, 0x22, 0xd9, 0xd5, + 0x27, 0x8a, 0x96, 0x48, 0xae, 0x31, 0x96, 0xcc, 0xcb, 0x87, 0x6e, 0x29, + 0x1e, 0x15, 0xce, 0xdf, 0x99, 0xbd, 0x7e, 0xf4, 0xdc, 0xfd, 0xa9, 0xf7, + 0x96, 0x23, 0x12, 0x33, 0xb3, 0x6f, 0x4c, 0x98, 0x23, 0x12, 0x1b, 0xc0, + 0x9e, 0xaf, 0x8d, 0xbe, 0xbc, 0x5d, 0x7a, 0x03, 0x5c, 0x22, 0xf5, 0x4a, + 0xca, 0xde, 0x2b, 0x63, 0xe6, 0x05, 0x89, 0x4a, 0x0e, 0x67, 0x9c, 0x6e, + 0x88, 0x94, 0x2b, 0x06, 0x71, 0x48, 0xb9, 0x11, 0x93, 0x4b, 0x11, 0x42, + 0x7d, 0xcb, 0x70, 0xaa, 0x1f, 0xb9, 0xb9, 0x28, 0xce, 0xb5, 0xf0, 0xde, + 0x0c, 0xe6, 0x63, 0xa2, 0xb2, 0xa9, 0x84, 0x13, 0x99, 0x96, 0xc2, 0x92, + 0xeb, 0xce, 0xdb, 0xb7, 0x03, 0x47, 0xbf, 0xcc, 0x5b, 0xde, 0xb7, 0x63, + 0x7f, 0xda, 0x9c, 0x92, 0x1d, 0x98, 0x8b, 0x88, 0xb2, 0xee, 0xc0, 0xdf, + 0x57, 0x0d, 0x67, 0xa5, 0x5b, 0xca, 0x55, 0xc9, 0x39, 0x76, 0x0c, 0xf3, + 0x09, 0x99, 0xab, 0x26, 0x0d, 0xe7, 0xa4, 0x21, 0xc5, 0x0c, 0xde, 0x9b, + 0xae, 0x38, 0xf6, 0x47, 0xae, 0x63, 0x11, 0xff, 0x92, 0xe1, 0x9c, 0xf9, + 0xc8, 0x55, 0x96, 0x65, 0x16, 0x84, 0xdf, 0x09, 0x29, 0x37, 0x89, 0x87, + 0xef, 0xc4, 0x73, 0xc9, 0x3d, 0x37, 0x9a, 0x90, 0x6f, 0x34, 0xe3, 0xf2, + 0xf5, 0xa6, 0x29, 0x2f, 0x35, 0x07, 0xe4, 0x7c, 0xd3, 0x75, 0xbf, 0x6e, + 0xbb, 0xee, 0x1b, 0xf8, 0xfb, 0x81, 0x7d, 0x83, 0x66, 0x8c, 0x92, 0x31, + 0xd5, 0xfc, 0xc3, 0x6e, 0xe9, 0x4d, 0x25, 0x45, 0x75, 0xe3, 0xcc, 0x84, + 0xcc, 0x57, 0x2b, 0xc6, 0xc3, 0x67, 0x16, 0x8d, 0x99, 0x33, 0x35, 0x23, + 0x7f, 0x26, 0x8a, 0x39, 0x29, 0x95, 0xed, 0x17, 0x8d, 0x7c, 0x73, 0xc1, + 0x78, 0xe4, 0x4c, 0xaf, 0xa6, 0xad, 0x5c, 0xdd, 0x09, 0xda, 0xae, 0x83, + 0x26, 0xca, 0x34, 0x65, 0xfe, 0x3c, 0xc4, 0xec, 0x54, 0xc8, 0x57, 0xbb, + 0xe4, 0xe2, 0x5c, 0x77, 0x5d, 0x95, 0x75, 0x8f, 0x3a, 0x19, 0xcb, 0x2c, + 0x0b, 0xe9, 0xd3, 0x73, 0xe7, 0x23, 0xa0, 0x39, 0x2f, 0xa7, 0x41, 0x7f, + 0xb7, 0x91, 0x3f, 0x15, 0x05, 0x1d, 0x32, 0x10, 0x11, 0xee, 0x1b, 0x4e, + 0x14, 0xa4, 0x81, 0x33, 0xc4, 0x54, 0x59, 0xca, 0x11, 0x34, 0x83, 0x96, + 0x6f, 0x54, 0xc1, 0x43, 0x15, 0x3c, 0x54, 0xc9, 0x5b, 0x52, 0xce, 0x8d, + 0x06, 0xbc, 0xb9, 0xee, 0x5f, 0xdb, 0xa4, 0x3d, 0x95, 0xcc, 0xa9, 0x80, + 0x4f, 0xd7, 0xfd, 0xbe, 0x4d, 0x5e, 0xc9, 0x8f, 0xeb, 0xbe, 0x64, 0x53, + 0x86, 0xee, 0x79, 0x65, 0x55, 0xc0, 0x8b, 0x05, 0xfc, 0x94, 0xef, 0x22, + 0x78, 0x58, 0x00, 0x7f, 0xa7, 0xc1, 0x5b, 0x0d, 0x74, 0xfc, 0xa8, 0xf3, + 0x4a, 0x46, 0x7e, 0xf4, 0x86, 0xbc, 0x92, 0x94, 0x71, 0x61, 0x55, 0x41, + 0xd6, 0xdb, 0xa4, 0xb0, 0x6c, 0xca, 0xec, 0x6a, 0xb0, 0x3f, 0xd0, 0xfb, + 0x61, 0xd9, 0x57, 0xed, 0x87, 0x6c, 0x28, 0xcb, 0x94, 0x2d, 0x42, 0xbd, + 0x95, 0xd3, 0x4a, 0xc4, 0x28, 0xd8, 0x47, 0xb5, 0xbe, 0x57, 0x2d, 0xc9, + 0x15, 0x6c, 0xca, 0x51, 0x92, 0x05, 0xbb, 0x94, 0x88, 0xc2, 0xbe, 0x56, + 0xad, 0x92, 0x19, 0x15, 0xca, 0x31, 0x95, 0xf8, 0x32, 0x64, 0x79, 0xa8, + 0x22, 0xb9, 0xcf, 0x55, 0x02, 0x19, 0x7b, 0xf2, 0xfd, 0x7c, 0xe5, 0xa7, + 0x7b, 0xa4, 0x4b, 0x7d, 0xaa, 0x4d, 0x7e, 0x15, 0x7b, 0x89, 0xfb, 0x96, + 0xbd, 0xd8, 0xe7, 0xc1, 0x79, 0x7b, 0x53, 0x07, 0x44, 0x08, 0x5b, 0x1e, + 0x6a, 0xf3, 0x7c, 0xc2, 0x70, 0xac, 0x52, 0x22, 0x02, 0xb8, 0x82, 0x94, + 0x27, 0xfc, 0xb9, 0x36, 0xc7, 0xba, 0x1e, 0x99, 0xb7, 0x53, 0xc9, 0xb2, + 0x5c, 0x8f, 0x5c, 0xb4, 0xf5, 0x5c, 0xa7, 0x63, 0xb9, 0xb2, 0x06, 0xec, + 0xcf, 0xc0, 0xfe, 0x2f, 0x80, 0xa3, 0x5f, 0xae, 0xe8, 0xf9, 0x1e, 0xec, + 0x4f, 0xb7, 0x01, 0x67, 0x97, 0xa4, 0xd2, 0x75, 0xcc, 0x5f, 0xf4, 0xe6, + 0xfb, 0x3c, 0xbc, 0xe5, 0xa1, 0x2e, 0x8d, 0x5b, 0xe4, 0x45, 0x6f, 0xfe, + 0x36, 0x0f, 0x77, 0xf9, 0x6e, 0xcc, 0x03, 0xff, 0xc8, 0xf4, 0xa8, 0xa1, + 0xe7, 0x77, 0xd1, 0x7f, 0x7e, 0xa9, 0x72, 0x3d, 0xb2, 0x66, 0xbb, 0x92, + 0x9f, 0x18, 0x99, 0x1e, 0x31, 0x3c, 0x7c, 0xc7, 0xbc, 0x7d, 0x77, 0x7a, + 0xf8, 0x46, 0xa6, 0xd3, 0x86, 0x87, 0x6f, 0xb5, 0xa2, 0xf7, 0x4a, 0xa1, + 0x42, 0xd8, 0x91, 0x69, 0xcb, 0xb8, 0x53, 0x66, 0xfb, 0x46, 0xa6, 0x07, + 0x0d, 0xf5, 0xa9, 0x6d, 0x1e, 0x1f, 0xa9, 0x80, 0x86, 0x6d, 0x9a, 0x06, + 0x9e, 0xab, 0xe7, 0x87, 0x1d, 0xab, 0x7c, 0xf7, 0x36, 0x7d, 0x3e, 0xcf, + 0xd4, 0x73, 0x77, 0x93, 0x2e, 0x9e, 0x5d, 0x9c, 0xb8, 0xe5, 0xdc, 0x1f, + 0xbf, 0x29, 0x9f, 0xad, 0xce, 0xe4, 0x79, 0x12, 0x8b, 0x66, 0xa3, 0x13, + 0xf3, 0x95, 0xc3, 0xe2, 0x54, 0x93, 0x32, 0x37, 0xde, 0x29, 0xb3, 0xe6, + 0xd0, 0xec, 0x3e, 0x61, 0xac, 0x89, 0x4d, 0x14, 0x7d, 0x1d, 0xe6, 0xc5, + 0x90, 0x39, 0xf0, 0xb8, 0xaf, 0x21, 0x31, 0x03, 0xf0, 0x43, 0x8d, 0xa8, + 0x3c, 0xdb, 0x34, 0xa4, 0x5d, 0xfb, 0x67, 0xca, 0xdc, 0x80, 0x1d, 0x3e, + 0x5d, 0xa5, 0x1d, 0xd3, 0x66, 0x25, 0x57, 0x87, 0x9d, 0x9e, 0xd7, 0xbe, + 0xda, 0x45, 0xbd, 0x96, 0x4a, 0x02, 0x57, 0xcc, 0x5a, 0x66, 0x5d, 0x3a, + 0x24, 0x37, 0x23, 0x25, 0xae, 0xfb, 0xbe, 0x93, 0x58, 0x91, 0x73, 0xb0, + 0x01, 0x31, 0x9d, 0x0c, 0xe7, 0x09, 0xdf, 0x02, 0x6b, 0x7a, 0x7e, 0x17, + 0x81, 0xdf, 0x15, 0x33, 0x84, 0x95, 0x92, 0x93, 0xa1, 0xef, 0xc1, 0x16, + 0x9b, 0xbb, 0x7a, 0xbc, 0xd8, 0x86, 0xd8, 0x12, 0xef, 0x86, 0x8f, 0x7f, + 0x0a, 0xfe, 0x37, 0x60, 0x38, 0xa7, 0x5c, 0xb7, 0x68, 0x4b, 0x5c, 0x09, + 0xfd, 0x0f, 0xbe, 0xde, 0xe4, 0x5a, 0x37, 0xe6, 0xc5, 0x9c, 0xb3, 0xfb, + 0xc0, 0x9f, 0xeb, 0x4e, 0xdb, 0x49, 0x29, 0xdb, 0xdb, 0xb1, 0xaf, 0x4d, + 0xfa, 0x2c, 0xda, 0x3b, 0x7d, 0x7a, 0x1b, 0xce, 0x33, 0xf8, 0xdd, 0x8b, + 0xf3, 0x7a, 0x30, 0x97, 0x98, 0xa3, 0x1f, 0x67, 0xc6, 0xc0, 0xbf, 0x17, + 0x2f, 0x45, 0xde, 0x06, 0xad, 0xdc, 0xa3, 0xe1, 0x62, 0x1d, 0xd9, 0x8c, + 0x5c, 0xab, 0xec, 0x92, 0x4b, 0x71, 0xf2, 0x0f, 0x9c, 0x55, 0xc4, 0xc4, + 0xb8, 0x01, 0xfa, 0x13, 0x7e, 0xdc, 0xdb, 0xe1, 0x7f, 0x1b, 0x77, 0x79, + 0x67, 0x88, 0x19, 0xc9, 0xf6, 0x4a, 0x5e, 0xcf, 0x89, 0x52, 0x13, 0xdb, + 0xfc, 0xf5, 0x5e, 0x63, 0xef, 0x29, 0x25, 0xa3, 0xf7, 0x21, 0x66, 0xe1, + 0xac, 0x8b, 0x96, 0xeb, 0x5e, 0xb4, 0xbf, 0x0f, 0x9f, 0x57, 0xd2, 0x66, + 0xfd, 0x63, 0xaf, 0x74, 0x41, 0x9e, 0x55, 0xa3, 0x45, 0x86, 0x09, 0x39, + 0x56, 0xe5, 0x9e, 0x92, 0x44, 0x2d, 0xc2, 0x10, 0xfe, 0xef, 0x01, 0x17, + 0x91, 0x0e, 0xf8, 0xe2, 0x05, 0x3b, 0x4e, 0x7a, 0xb7, 0x7b, 0xf0, 0x7d, + 0x38, 0x83, 0xb4, 0xd3, 0xf7, 0x5c, 0xed, 0x7b, 0x4e, 0x44, 0xe5, 0xa6, + 0x96, 0xe0, 0x49, 0xe3, 0x94, 0xb7, 0xd3, 0x87, 0x50, 0x2f, 0x73, 0xa3, + 0x25, 0x53, 0x69, 0x5d, 0x8b, 0xe4, 0x2b, 0x77, 0xc9, 0xbc, 0x8d, 0xf3, + 0xac, 0x28, 0x68, 0x66, 0x9c, 0x19, 0x2e, 0x45, 0x14, 0x3c, 0xac, 0x9f, + 0xb2, 0x0a, 0x68, 0x7d, 0x0b, 0xe7, 0x95, 0x8c, 0xa8, 0xc5, 0x33, 0xbe, + 0xe4, 0xcb, 0x87, 0x76, 0x67, 0x8b, 0x53, 0xe9, 0xe6, 0x37, 0xe8, 0xe8, + 0xd2, 0x74, 0x44, 0xb2, 0x5a, 0x77, 0x86, 0xca, 0x52, 0x96, 0x6d, 0x3e, + 0x3d, 0xb7, 0xe0, 0x01, 0x1f, 0xdc, 0x6b, 0x61, 0x6f, 0x0c, 0x34, 0xf6, + 0xb4, 0xd0, 0xdf, 0x45, 0x78, 0xc8, 0x2a, 0xe6, 0x9f, 0xa1, 0xf9, 0x36, + 0x3c, 0xbe, 0x03, 0x59, 0x7d, 0x1b, 0xb2, 0xfa, 0xc0, 0x1d, 0xdd, 0x4d, + 0x1c, 0x19, 0xe0, 0x60, 0x1e, 0x62, 0xbc, 0x62, 0x8c, 0x32, 0x6f, 0xe0, + 0x82, 0x1f, 0xa8, 0x48, 0xb6, 0x5b, 0xf2, 0xa6, 0xce, 0x01, 0x80, 0x9d, + 0x14, 0x1d, 0xe3, 0x2d, 0xf2, 0xe8, 0x7f, 0x5b, 0x29, 0x6d, 0x37, 0x85, + 0x1a, 0xf3, 0xc0, 0x57, 0x40, 0xdb, 0x46, 0x4a, 0x69, 0xd6, 0xba, 0x21, + 0x73, 0x89, 0xb5, 0x65, 0xdf, 0x90, 0xb5, 0x8a, 0xda, 0xd9, 0x2e, 0xdb, + 0x65, 0x06, 0x32, 0xaa, 0x4f, 0x22, 0x7f, 0x8e, 0x77, 0x4b, 0xe4, 0x1e, + 0xe6, 0x81, 0x04, 0x68, 0xdd, 0x48, 0x99, 0x72, 0xdd, 0x55, 0x23, 0xd8, + 0x3f, 0x0e, 0x3d, 0xec, 0xa7, 0x4e, 0x95, 0x0f, 0x47, 0x98, 0x08, 0x65, + 0xde, 0xdf, 0x2e, 0xc4, 0xcd, 0xb5, 0xb1, 0x84, 0x29, 0x9c, 0xef, 0x84, + 0x5e, 0xb9, 0x97, 0xfc, 0x79, 0x7b, 0x3e, 0xce, 0x5f, 0xb0, 0x4e, 0x99, + 0x51, 0x76, 0xb0, 0x31, 0xf0, 0xe8, 0xd8, 0x3f, 0xeb, 0xcb, 0xe6, 0x76, + 0xb9, 0x64, 0x8a, 0x51, 0xb7, 0x6f, 0x6b, 0x91, 0x1f, 0x79, 0xee, 0xdb, + 0xc4, 0x33, 0x71, 0x6c, 0xcd, 0xf7, 0xc1, 0x1a, 0xcf, 0xf4, 0xce, 0x9e, + 0xb7, 0x36, 0x52, 0x51, 0xb9, 0x55, 0xbe, 0xd0, 0xa5, 0x14, 0x2b, 0xb4, + 0x8d, 0x76, 0x29, 0xa0, 0xfe, 0xb0, 0x77, 0x23, 0xa8, 0x3c, 0xa2, 0x64, + 0xe2, 0x3e, 0xe2, 0xfc, 0x3b, 0xf2, 0x34, 0x99, 0x54, 0x86, 0x14, 0xec, + 0xce, 0x16, 0x7d, 0x71, 0xae, 0xd5, 0xb6, 0xbf, 0xed, 0xdb, 0xf6, 0x07, + 0xee, 0xc4, 0xee, 0x40, 0xef, 0x90, 0xd7, 0xc7, 0xf6, 0x08, 0xf4, 0xfc, + 0x7f, 0xed, 0xa1, 0xad, 0xc4, 0x36, 0xed, 0x29, 0x6d, 0xb1, 0x67, 0x87, + 0xc8, 0x17, 0xe8, 0x43, 0x3d, 0x7e, 0xcc, 0x08, 0x7c, 0x2a, 0xc0, 0x03, + 0xdd, 0x68, 0x5b, 0xe5, 0xdc, 0x56, 0xbe, 0x48, 0x1c, 0xc4, 0xc5, 0xbd, + 0x84, 0x09, 0x72, 0x2a, 0xd4, 0x21, 0x5b, 0xe6, 0x55, 0x8c, 0x69, 0xbc, + 0x2b, 0xc4, 0xa1, 0xd6, 0xfc, 0xca, 0x39, 0x13, 0xdf, 0x53, 0x78, 0x5a, + 0x52, 0x68, 0xd0, 0x9f, 0xb8, 0x9f, 0xf9, 0xf6, 0x5d, 0x3f, 0x7e, 0x76, + 0xcf, 0x46, 0xb3, 0x71, 0xc4, 0x4f, 0x99, 0x29, 0x57, 0x8e, 0xba, 0x11, + 0x4b, 0x4a, 0x77, 0x64, 0x69, 0x1f, 0xdd, 0x93, 0x88, 0x91, 0x33, 0xe5, + 0x06, 0xeb, 0x22, 0x84, 0x31, 0xec, 0x43, 0x8e, 0x8e, 0xa9, 0xc5, 0x58, + 0xe9, 0xc7, 0xb2, 0x8c, 0xcb, 0x49, 0x49, 0x36, 0xde, 0x43, 0xdd, 0x61, + 0x8a, 0xa3, 0x6d, 0xed, 0xf9, 0x5d, 0xa4, 0xb7, 0x8c, 0x1a, 0x22, 0x9a, + 0x95, 0xa8, 0xca, 0xb6, 0xc7, 0xe6, 0x32, 0xdd, 0xe2, 0x64, 0xa6, 0x77, + 0xa9, 0xf5, 0x7d, 0xbb, 0x22, 0xeb, 0x3b, 0x67, 0xdb, 0xb2, 0xa5, 0x5d, + 0x6a, 0x51, 0x64, 0xa5, 0x22, 0x0a, 0x75, 0x4d, 0xe2, 0xa0, 0xe0, 0x7b, + 0xfd, 0xd1, 0x47, 0x55, 0x36, 0x02, 0xdd, 0xca, 0x53, 0xab, 0x99, 0x28, + 0x6b, 0xc6, 0xe4, 0x8c, 0x3c, 0x85, 0x3a, 0xf1, 0x49, 0x99, 0xab, 0x80, + 0x2e, 0xcd, 0x77, 0x02, 0xfc, 0x0e, 0x00, 0x37, 0x69, 0x8f, 0x23, 0xc6, + 0x7a, 0xb4, 0x83, 0xe6, 0x5c, 0x9e, 0x75, 0x52, 0x86, 0x79, 0xe5, 0x3d, + 0xd8, 0x0f, 0xfd, 0xe5, 0x5f, 0x64, 0xcd, 0xea, 0x94, 0x82, 0x17, 0x1f, + 0x68, 0xaf, 0x58, 0x7b, 0xd7, 0x5f, 0xbb, 0x8a, 0x35, 0xda, 0xef, 0xb6, + 0x16, 0x1d, 0x7e, 0x55, 0xd7, 0x3a, 0x17, 0x6d, 0xbe, 0x13, 0xf6, 0x2f, + 0x27, 0x3c, 0xd8, 0xd7, 0x27, 0xd6, 0xac, 0x47, 0xb7, 0x4b, 0x97, 0x49, + 0xbd, 0xe1, 0x9c, 0x38, 0x63, 0x2c, 0xd6, 0x2f, 0xf9, 0xb8, 0xbe, 0x0b, + 0x5c, 0xdd, 0xa4, 0x1b, 0x23, 0x8a, 0x75, 0xd0, 0x87, 0x9a, 0xa7, 0x70, + 0x23, 0xd6, 0x10, 0xf6, 0x65, 0x1f, 0xd7, 0xb7, 0x5a, 0x70, 0x71, 0x8d, + 0x4f, 0x9e, 0x89, 0xb3, 0xbb, 0xc8, 0x1b, 0xf9, 0xa1, 0x0e, 0xa8, 0x8f, + 0xb4, 0x31, 0x83, 0xd8, 0x3e, 0xd3, 0xd4, 0xb5, 0x9d, 0x91, 0xaf, 0xa2, + 0xe6, 0x6a, 0x3e, 0x0f, 0x1a, 0x59, 0xc3, 0x0e, 0xfa, 0xf5, 0x35, 0xed, + 0x68, 0x43, 0xdb, 0x23, 0xe3, 0x4e, 0x59, 0xdb, 0xd5, 0x6b, 0x9e, 0x5d, + 0x59, 0xd4, 0xcd, 0x6b, 0x32, 0xd8, 0xa8, 0x6c, 0xf7, 0xfe, 0xaf, 0xb6, + 0x29, 0x11, 0xad, 0x4f, 0xe6, 0x37, 0xda, 0xd8, 0xed, 0x88, 0xeb, 0xee, + 0x0f, 0x99, 0x67, 0x66, 0x98, 0x83, 0x66, 0x98, 0x3b, 0x0c, 0x3f, 0x1e, + 0x26, 0x5b, 0x70, 0x24, 0x81, 0xa3, 0xee, 0xdb, 0xef, 0x73, 0x3e, 0xae, + 0xa0, 0xfe, 0x0c, 0x62, 0xea, 0xef, 0xdf, 0x71, 0xeb, 0xfa, 0x47, 0x3e, + 0x7d, 0xed, 0x3a, 0x1e, 0xc3, 0xd6, 0x41, 0x7f, 0x72, 0x56, 0xc1, 0xbe, + 0xf2, 0x0d, 0x4f, 0x1f, 0xf0, 0x7d, 0xd8, 0x1e, 0x5f, 0x03, 0xdd, 0x7a, + 0xf5, 0xb7, 0x27, 0x03, 0xea, 0x34, 0x47, 0xbe, 0x73, 0x51, 0xd2, 0xd2, + 0x9c, 0xc6, 0x7e, 0x39, 0xcc, 0xdc, 0x58, 0x00, 0x1f, 0x07, 0xcd, 0x31, + 0x73, 0x8e, 0xb8, 0xe3, 0x02, 0x9c, 0xa8, 0x25, 0xb3, 0x1d, 0xbe, 0x9e, + 0xbf, 0xc9, 0xf3, 0x81, 0x7b, 0x1b, 0xbf, 0xf1, 0xfc, 0xa6, 0x4f, 0xcf, + 0x95, 0x5e, 0x8f, 0x9e, 0x60, 0x7d, 0xd0, 0xbc, 0xf5, 0xbb, 0xbe, 0xcb, + 0x97, 0x27, 0xde, 0x9f, 0xf4, 0xe9, 0xa2, 0x6e, 0x5a, 0x69, 0xa2, 0x5e, + 0xfe, 0x1d, 0x78, 0x74, 0xad, 0x51, 0x52, 0x59, 0xd4, 0x2e, 0x19, 0xe6, + 0xac, 0xd4, 0x64, 0x4e, 0x2c, 0xe8, 0x24, 0x65, 0xcf, 0x62, 0xd7, 0xbb, + 0x15, 0xea, 0xf9, 0x3a, 0x62, 0x35, 0xf5, 0xfe, 0xbe, 0xcc, 0x57, 0x86, + 0xec, 0x76, 0x83, 0xfe, 0x9a, 0x4a, 0x9f, 0x96, 0x31, 0xfb, 0xb4, 0xae, + 0xa1, 0x52, 0xc9, 0x63, 0x42, 0xd9, 0x5e, 0x97, 0x61, 0x5d, 0xdb, 0xbc, + 0x2f, 0x16, 0xe4, 0x32, 0x53, 0x85, 0x8f, 0xed, 0xfe, 0x57, 0x57, 0xd7, + 0xa4, 0x08, 0x6f, 0xef, 0x6c, 0x81, 0xeb, 0x75, 0x8d, 0x87, 0xf8, 0x5a, + 0x71, 0x19, 0xd2, 0xb1, 0x3b, 0xc0, 0x67, 0xc9, 0x42, 0x33, 0xc0, 0x19, + 0x45, 0x5c, 0x46, 0x0c, 0xd8, 0xfd, 0x05, 0x5f, 0x1f, 0x7c, 0x7f, 0xd3, + 0x65, 0x2d, 0xa4, 0xb2, 0xa7, 0xfc, 0xb9, 0x3f, 0xa3, 0x0c, 0xf0, 0x1d, + 0xc8, 0xfd, 0x79, 0x3f, 0xde, 0x94, 0x8c, 0x5c, 0x93, 0x32, 0xa0, 0xad, + 0x40, 0xff, 0xda, 0x3e, 0xe1, 0x33, 0xd5, 0xcf, 0x22, 0x66, 0xf5, 0x79, + 0xf5, 0x03, 0x7a, 0xb0, 0x5c, 0x93, 0x73, 0x1b, 0x1d, 0x8e, 0xdd, 0xe6, + 0xfb, 0xd2, 0x3e, 0xcc, 0xcd, 0xe0, 0x8f, 0xb2, 0x23, 0xcc, 0x7e, 0xbc, + 0xe7, 0x7c, 0x38, 0x99, 0x74, 0x90, 0xbb, 0x72, 0xfb, 0xa7, 0xf0, 0x6d, + 0xf8, 0x7d, 0x96, 0x96, 0x7b, 0x0d, 0xb5, 0x0a, 0xe4, 0x39, 0x0c, 0x7e, + 0x92, 0x32, 0xd5, 0x84, 0xce, 0x6f, 0xc4, 0xb3, 0x1b, 0x30, 0xa5, 0x9b, + 0x30, 0x5e, 0xec, 0x9b, 0x6a, 0xbe, 0xe5, 0x32, 0x1e, 0xfc, 0x89, 0xf6, + 0x97, 0x24, 0x68, 0x0f, 0x7a, 0xb5, 0x9c, 0xf1, 0x70, 0x75, 0xda, 0x78, + 0xa4, 0xca, 0x3d, 0xea, 0x6b, 0xfd, 0x62, 0x25, 0x1d, 0x85, 0x3a, 0x75, + 0x77, 0x2f, 0xce, 0x3c, 0x06, 0xdb, 0x28, 0x19, 0x33, 0xa3, 0xdb, 0xa5, + 0x90, 0xee, 0x07, 0xcd, 0xf7, 0xe3, 0xd9, 0x8e, 0xf9, 0x9f, 0xc2, 0x3c, + 0xec, 0x28, 0x4d, 0xff, 0xe8, 0xd4, 0xbd, 0xe4, 0xac, 0x49, 0x1a, 0x87, + 0x7d, 0xdb, 0xfa, 0x8e, 0xe9, 0xd9, 0xd2, 0x13, 0xf8, 0xde, 0x86, 0xf9, + 0x5f, 0xc0, 0x13, 0xb9, 0x6c, 0x77, 0x30, 0x4f, 0x1f, 0x9c, 0xc4, 0xfc, + 0xbd, 0xc0, 0xf1, 0xdb, 0x78, 0xbf, 0x0b, 0xef, 0xbf, 0xb5, 0x69, 0xef, + 0x6f, 0xf2, 0x6c, 0xcc, 0x3b, 0x9b, 0xe6, 0x83, 0xf8, 0xcd, 0xf3, 0x44, + 0xfa, 0xd6, 0xc1, 0xf8, 0x7a, 0x4c, 0x76, 0x9c, 0xee, 0x12, 0x55, 0xf7, + 0x62, 0xb8, 0xaa, 0x9b, 0xd2, 0x7f, 0x9a, 0xf1, 0xfb, 0xaf, 0xb0, 0xc7, + 0x12, 0xb5, 0x0e, 0xa5, 0x51, 0xb7, 0xda, 0x47, 0x0f, 0x1c, 0x19, 0x5c, + 0xe6, 0x73, 0xf6, 0xc8, 0x44, 0x83, 0x30, 0x7c, 0x7f, 0xec, 0xc8, 0x60, + 0xe3, 0x6f, 0x01, 0x0b, 0xb9, 0x54, 0x03, 0xfc, 0x84, 0xff, 0xd3, 0x4d, + 0x67, 0x6a, 0xd9, 0xe2, 0x4c, 0xfa, 0xfd, 0x81, 0x23, 0x4e, 0x8d, 0x75, + 0x42, 0x2a, 0x21, 0xba, 0x16, 0x9f, 0x3d, 0x52, 0x44, 0x7e, 0x8c, 0x68, + 0x5a, 0x82, 0x75, 0xae, 0x51, 0x0f, 0x5b, 0xd1, 0x46, 0xba, 0x5a, 0xf1, + 0x30, 0xcf, 0x10, 0xcf, 0x63, 0xc0, 0x93, 0x06, 0x1e, 0xe6, 0x1b, 0x8f, + 0xde, 0xe4, 0xf2, 0x56, 0xb4, 0x11, 0x17, 0xcf, 0x0a, 0xf0, 0xf5, 0x8b, + 0x3a, 0xfd, 0x26, 0xe9, 0x35, 0x59, 0xdb, 0x7a, 0xb1, 0xa6, 0x4d, 0x0a, + 0x27, 0x99, 0xb3, 0x77, 0xfb, 0xdf, 0x71, 0x93, 0x3d, 0x77, 0x52, 0x71, + 0x9e, 0x4f, 0xac, 0x65, 0xee, 0xc4, 0x1c, 0xbe, 0x57, 0x02, 0x58, 0xe5, + 0xc3, 0xf6, 0xb4, 0xf0, 0xdd, 0xe6, 0xcb, 0x9a, 0x67, 0x06, 0xbd, 0x67, + 0x2b, 0x2d, 0x00, 0x85, 0x1e, 0xfa, 0x6e, 0xe8, 0x21, 0xe0, 0x13, 0x0b, + 0xeb, 0xa4, 0x2d, 0x0d, 0x5e, 0x03, 0xda, 0x3e, 0xa9, 0xfe, 0xb8, 0x37, + 0x8d, 0xbf, 0xe0, 0xbc, 0x40, 0x06, 0xa4, 0x8b, 0x4f, 0xd8, 0xf2, 0xc7, + 0x7a, 0xe7, 0x34, 0xfc, 0x8e, 0xf7, 0x1e, 0xae, 0xbb, 0x66, 0x53, 0xf6, + 0x1d, 0xd0, 0x3b, 0x79, 0x31, 0xd0, 0x4b, 0x28, 0xd6, 0x74, 0x49, 0xf6, + 0xac, 0x87, 0xe4, 0x6d, 0xe0, 0xca, 0xa1, 0xaf, 0xf4, 0x7a, 0xa3, 0x59, + 0xc4, 0xc7, 0x0d, 0xd8, 0xe7, 0x45, 0x8b, 0xf7, 0x2f, 0x51, 0xe6, 0x3b, + 0x29, 0x37, 0xfe, 0x19, 0x30, 0xac, 0xaf, 0x6e, 0xde, 0xad, 0x2c, 0x03, + 0x66, 0x05, 0x6b, 0xc7, 0xbc, 0xb8, 0xcc, 0xd8, 0xee, 0x2a, 0xd4, 0x1e, + 0x45, 0xeb, 0xbf, 0x5d, 0xd6, 0x59, 0x37, 0x61, 0xb7, 0xba, 0x0b, 0x41, + 0xce, 0x59, 0x4a, 0x2d, 0x2c, 0x23, 0x86, 0xd7, 0x2c, 0xb5, 0x43, 0x69, + 0x8b, 0x4c, 0xd5, 0x10, 0x93, 0xd0, 0xf5, 0xa6, 0x92, 0xcb, 0xf2, 0x03, + 0xad, 0x87, 0x36, 0x6b, 0xcc, 0xec, 0x57, 0x5f, 0xa4, 0x5d, 0x69, 0xca, + 0x23, 0x27, 0x90, 0x97, 0xc7, 0x1f, 0x46, 0xce, 0x81, 0xbc, 0x4e, 0x94, + 0xd0, 0xc9, 0xd3, 0x46, 0x36, 0x7e, 0xbd, 0x68, 0x79, 0x7d, 0x80, 0xce, + 0x67, 0xe2, 0xf1, 0x18, 0x39, 0xd1, 0xad, 0xe3, 0x4c, 0x41, 0xc7, 0x9b, + 0x21, 0x73, 0x46, 0x75, 0xa1, 0xc6, 0x40, 0x01, 0x8a, 0x0a, 0xc7, 0x1c, + 0x11, 0x19, 0x5c, 0x44, 0x5c, 0x41, 0x1c, 0x1e, 0x5c, 0x47, 0x74, 0x3b, + 0x41, 0x78, 0x25, 0xd1, 0x13, 0x11, 0x69, 0x3b, 0xc1, 0xfb, 0x10, 0xd9, + 0x89, 0x7e, 0x8c, 0x38, 0x07, 0xa3, 0x78, 0x4e, 0xe1, 0x6f, 0x0f, 0x6a, + 0x2b, 0x13, 0x35, 0xf2, 0x16, 0xf0, 0x80, 0xe5, 0x9e, 0xad, 0xe0, 0xbb, + 0xfb, 0xa4, 0x2b, 0x86, 0x3d, 0x84, 0x8f, 0x82, 0x8e, 0x9d, 0xa0, 0xc7, + 0x3b, 0x9f, 0x38, 0xa2, 0x27, 0x44, 0x86, 0x16, 0xa5, 0x5f, 0xe9, 0x3d, + 0x51, 0x29, 0x66, 0xb8, 0xd6, 0x0d, 0x78, 0xee, 0xc3, 0x9a, 0xde, 0xe7, + 0xdd, 0x2b, 0x15, 0x6e, 0xd2, 0x8d, 0x39, 0x03, 0xef, 0xa8, 0xa7, 0x32, + 0xa6, 0x0c, 0xd5, 0x3d, 0xd8, 0xc1, 0xf5, 0x43, 0x78, 0x92, 0x57, 0x8f, + 0x36, 0x85, 0x9a, 0xb8, 0x00, 0xa9, 0x46, 0x47, 0x78, 0x3f, 0x43, 0x18, + 0xf6, 0xb5, 0xdd, 0x1a, 0xc6, 0x1c, 0xa1, 0xfc, 0xbc, 0x39, 0xa5, 0xfe, + 0xb7, 0x7b, 0x97, 0xd6, 0x9a, 0x42, 0xfb, 0x0a, 0xf6, 0x7f, 0x45, 0xfb, + 0x8a, 0xa8, 0xa4, 0xef, 0x2b, 0xf8, 0x5e, 0xe1, 0x77, 0x90, 0x8b, 0x7f, + 0xed, 0x0e, 0x2f, 0xde, 0xbb, 0x32, 0x67, 0xf3, 0x0e, 0xc3, 0x95, 0x8b, + 0x76, 0xc9, 0x78, 0xf0, 0x96, 0x3a, 0x33, 0xad, 0xf3, 0x73, 0x11, 0xb2, + 0xbf, 0xdc, 0xd0, 0x3d, 0x9b, 0x5c, 0x6a, 0xc4, 0xe4, 0xca, 0x6a, 0x97, + 0x5c, 0x5e, 0xf6, 0x6c, 0xfe, 0xf2, 0x32, 0xed, 0xdc, 0x94, 0xef, 0xad, + 0x5a, 0x58, 0x4b, 0xe3, 0xaf, 0x5f, 0xde, 0x59, 0xbd, 0xb5, 0xee, 0x3c, + 0xdf, 0x7c, 0x00, 0xb4, 0xf4, 0x4b, 0xc4, 0x72, 0x75, 0xff, 0x95, 0x47, + 0xee, 0x2b, 0xc9, 0x94, 0x14, 0xaa, 0x43, 0xe8, 0x01, 0x91, 0x9c, 0xa3, + 0xcc, 0x41, 0xd0, 0x7f, 0xf5, 0x33, 0xa8, 0x4d, 0x52, 0x70, 0x9e, 0x21, + 0x7d, 0x8f, 0xf8, 0x33, 0xd1, 0x7e, 0x69, 0xb7, 0xbe, 0xdc, 0xe7, 0xe5, + 0x2a, 0xd3, 0xeb, 0x53, 0xad, 0x20, 0x5f, 0xbf, 0x0e, 0xdc, 0xe3, 0xb0, + 0x53, 0xda, 0xa6, 0x0d, 0x9b, 0x35, 0x65, 0x6d, 0x34, 0x55, 0x2b, 0x09, + 0xe3, 0x43, 0x06, 0x67, 0x7e, 0x08, 0x9e, 0xd3, 0x90, 0x47, 0xa7, 0xae, + 0x85, 0x72, 0x0a, 0xba, 0x5d, 0x9c, 0x97, 0x42, 0xf3, 0x57, 0x80, 0x2f, + 0x27, 0xb3, 0xcd, 0x49, 0x9c, 0x75, 0x1c, 0x76, 0x3b, 0xda, 0x2f, 0x5d, + 0x3c, 0x27, 0x03, 0x1a, 0xef, 0x97, 0xe2, 0xc9, 0x79, 0x39, 0x58, 0x25, + 0x9d, 0xc8, 0x25, 0x76, 0x2a, 0x9d, 0x97, 0xb1, 0xe4, 0x2a, 0x6a, 0x27, + 0xcf, 0x1f, 0xb3, 0x52, 0x3c, 0x05, 0x1c, 0x55, 0xde, 0x03, 0x0c, 0xc1, + 0x6e, 0xc6, 0x74, 0x5f, 0x33, 0xab, 0xe3, 0x0e, 0xe7, 0xdf, 0x84, 0x9e, + 0x86, 0x4a, 0x7b, 0x00, 0x57, 0x40, 0x0f, 0x34, 0x83, 0x7a, 0x79, 0xa5, + 0x8a, 0x7e, 0xcf, 0x8e, 0xb0, 0xf6, 0x52, 0xea, 0x9e, 0x01, 0xa9, 0x57, + 0xc7, 0x4c, 0xa5, 0x58, 0x53, 0x51, 0x17, 0x5c, 0xa3, 0x7f, 0x27, 0x54, + 0xd4, 0x1a, 0x90, 0xd5, 0x6a, 0x09, 0x7d, 0xb3, 0xf2, 0xef, 0x35, 0x4a, + 0x62, 0x5a, 0x5e, 0xdc, 0xcb, 0x29, 0xf2, 0x8d, 0xfa, 0xb3, 0xf9, 0x59, + 0xd0, 0x98, 0x4b, 0x9a, 0x72, 0x14, 0xf4, 0xe1, 0x7d, 0x05, 0x36, 0xbe, + 0xc8, 0x1a, 0x2e, 0x87, 0xb5, 0xac, 0x1c, 0x3e, 0x33, 0x03, 0x1a, 0x7a, + 0x65, 0xe8, 0x77, 0xe9, 0x63, 0x07, 0x30, 0xc7, 0xef, 0x14, 0xec, 0xf5, + 0x31, 0xbc, 0x13, 0x36, 0x81, 0x27, 0xe5, 0x30, 0x80, 0xa7, 0x09, 0x5a, + 0x62, 0x5e, 0x6f, 0xb2, 0x3f, 0x29, 0xf5, 0x93, 0xf7, 0xc9, 0xec, 0xca, + 0x7d, 0xc0, 0xff, 0x36, 0xfa, 0x02, 0xe4, 0xb7, 0x15, 0x9e, 0xc5, 0xfa, + 0x8f, 0xe7, 0x74, 0xf4, 0x6b, 0xdf, 0x58, 0xe4, 0x3c, 0x9f, 0xfb, 0xb0, + 0x1f, 0x3d, 0x46, 0x35, 0x27, 0xc5, 0x2a, 0xcf, 0x82, 0xee, 0x50, 0x4f, + 0x15, 0x4e, 0xce, 0xf8, 0x3a, 0xee, 0x97, 0x7c, 0xbc, 0xc4, 0xfe, 0x02, + 0x79, 0x62, 0x79, 0xc2, 0xa9, 0xa4, 0x4c, 0x47, 0x11, 0x57, 0x5a, 0x98, + 0x1b, 0xbc, 0xb9, 0x98, 0x58, 0x8b, 0xe8, 0x6d, 0xb3, 0x5c, 0x3b, 0xea, + 0xdf, 0x1d, 0x10, 0xd7, 0x5b, 0x32, 0x05, 0x1b, 0x1b, 0x5a, 0x1c, 0x47, + 0x2d, 0xfc, 0x5d, 0xd4, 0x92, 0x77, 0xfa, 0x32, 0x98, 0xf4, 0x6d, 0xa3, + 0xab, 0xc5, 0x26, 0xa0, 0xe7, 0x2a, 0x74, 0x5f, 0x85, 0x1d, 0x20, 0x56, + 0xbf, 0x74, 0xc3, 0x3e, 0x26, 0x5b, 0x6a, 0xcc, 0x1e, 0xf9, 0x8b, 0x5a, + 0x2a, 0xbd, 0x01, 0xfb, 0x79, 0x07, 0xbd, 0xc0, 0x06, 0x7a, 0xd5, 0xcb, + 0xe8, 0xeb, 0x56, 0x2a, 0xfb, 0x41, 0x3f, 0x6b, 0x4a, 0x7e, 0x27, 0x74, + 0xad, 0xd3, 0x61, 0x1d, 0xbb, 0x43, 0xdf, 0xed, 0xca, 0xfe, 0x7e, 0xf6, + 0x9a, 0xec, 0xcb, 0x79, 0x0f, 0x7d, 0x05, 0x7a, 0xdc, 0x30, 0xb9, 0x1e, + 0xec, 0x63, 0x2f, 0x10, 0xd8, 0x0f, 0x69, 0xa1, 0xfd, 0x70, 0x0f, 0x61, + 0xfa, 0xb5, 0x9f, 0x14, 0x34, 0x3e, 0xda, 0xec, 0x8b, 0x7d, 0x9e, 0x9f, + 0xe9, 0x3a, 0xcb, 0xbc, 0x24, 0x81, 0xfd, 0xbe, 0xef, 0xb2, 0xaf, 0x73, + 0x46, 0x11, 0xbb, 0x9b, 0xae, 0x3c, 0x67, 0xdf, 0xea, 0x77, 0x7b, 0xab, + 0x81, 0x9c, 0x28, 0xc7, 0xfd, 0x72, 0xac, 0x99, 0x82, 0x4f, 0x50, 0x86, + 0x56, 0x8b, 0x0c, 0x45, 0xfe, 0xa8, 0x2a, 0xf2, 0x62, 0x95, 0x6b, 0x5a, + 0x86, 0x09, 0x27, 0xd2, 0xa5, 0xef, 0xd2, 0x0b, 0xf2, 0x1d, 0x39, 0xb8, + 0x24, 0x72, 0x06, 0xeb, 0x6b, 0x55, 0xfa, 0xea, 0x38, 0xea, 0xd7, 0x6d, + 0x52, 0x5f, 0x46, 0x4f, 0x56, 0x95, 0x59, 0xe7, 0x5e, 0xe6, 0x9b, 0x98, + 0x5c, 0xd6, 0x77, 0xb2, 0x22, 0x23, 0x67, 0xa3, 0x12, 0x3d, 0x8b, 0xe6, + 0x0f, 0xb2, 0x3f, 0x37, 0x1a, 0xdc, 0xd1, 0x7a, 0x3e, 0x5f, 0xae, 0x60, + 0x6f, 0x75, 0x48, 0xc7, 0xc9, 0x72, 0xa3, 0x28, 0x85, 0x1a, 0xcf, 0xc2, + 0x73, 0x39, 0x89, 0xb5, 0x8c, 0xcc, 0x9d, 0x1c, 0x97, 0xa7, 0x71, 0x06, + 0xfa, 0x3f, 0x9c, 0x31, 0x25, 0xa5, 0x33, 0x98, 0x6f, 0x5c, 0x95, 0xe5, + 0xd5, 0xa2, 0xd4, 0x6b, 0xe7, 0x5d, 0xaf, 0x8f, 0x20, 0x3e, 0x7c, 0x2f, + 0xb7, 0xf6, 0xb2, 0xfb, 0xd9, 0xcf, 0xa0, 0x57, 0xb5, 0xf0, 0x0d, 0x99, + 0x35, 0xe6, 0x66, 0x6f, 0xbd, 0x33, 0x6e, 0xed, 0x61, 0xa7, 0x65, 0xa1, + 0x9a, 0x91, 0xf2, 0xc9, 0x71, 0x7d, 0xd7, 0xd0, 0x91, 0x3d, 0xfc, 0xc4, + 0x35, 0xe4, 0x8a, 0x69, 0x7d, 0x67, 0x7c, 0x5d, 0x1e, 0xb2, 0x17, 0xe4, + 0x90, 0xb5, 0x4f, 0x8e, 0xa1, 0xbe, 0xfe, 0x1c, 0x7a, 0xfd, 0x64, 0x1f, + 0xf5, 0x08, 0x7a, 0x2d, 0xf6, 0xa0, 0xae, 0x4c, 0xd9, 0x9f, 0x36, 0x9f, + 0x65, 0x97, 0xd0, 0x60, 0x9e, 0xfc, 0x2f, 0x37, 0x87, 0xbc, 0x77, 0x0d, + 0xbd, 0x63, 0x4e, 0xc3, 0x19, 0x1e, 0x5c, 0x8d, 0x70, 0x63, 0xe6, 0x73, + 0x84, 0x5b, 0x36, 0x7c, 0x38, 0x03, 0x70, 0x11, 0xb9, 0x60, 0x47, 0x61, + 0x23, 0xd3, 0xe0, 0x13, 0x31, 0x7e, 0xa2, 0xc7, 0xaf, 0x83, 0x3b, 0x91, + 0x5b, 0x6f, 0xee, 0x7f, 0xd5, 0xdf, 0xff, 0xb4, 0xbf, 0xff, 0xe2, 0x8d, + 0xfd, 0x41, 0x7e, 0xfd, 0xd0, 0x95, 0x16, 0xba, 0x5e, 0xad, 0x78, 0xf0, + 0x0b, 0x3e, 0x5d, 0x17, 0x6f, 0xd0, 0x15, 0xc0, 0x43, 0x9e, 0x9a, 0x67, + 0xc6, 0x66, 0xc6, 0xe8, 0x21, 0xc8, 0xd1, 0x95, 0xbc, 0x0d, 0xdf, 0xa8, + 0xa6, 0x26, 0x4b, 0xfa, 0x4e, 0x4d, 0xc9, 0x46, 0x7c, 0x41, 0xa6, 0xad, + 0xd4, 0xe4, 0x9c, 0x44, 0x60, 0xcb, 0x8c, 0x2d, 0x11, 0xa9, 0x33, 0xe6, + 0xe0, 0x59, 0xb0, 0xb7, 0xa6, 0xf5, 0x4a, 0x0b, 0xad, 0x91, 0x17, 0x48, + 0xa3, 0x47, 0x6b, 0x6c, 0xf8, 0x26, 0xad, 0x1e, 0xbc, 0x47, 0xeb, 0x95, + 0x4a, 0x0b, 0xfc, 0xd9, 0xa8, 0x0f, 0x1f, 0x6d, 0x81, 0xa7, 0x3d, 0xb3, + 0xae, 0xa0, 0x3d, 0x93, 0xb6, 0x9f, 0x80, 0x6f, 0x48, 0xac, 0x33, 0x7b, + 0xf8, 0xc8, 0xdd, 0xc3, 0xae, 0xc4, 0x50, 0x6f, 0xb4, 0x63, 0xed, 0x72, + 0x8d, 0xb5, 0x88, 0x1a, 0x6c, 0x97, 0x11, 0xd8, 0x2c, 0x75, 0xe7, 0xdd, + 0x0d, 0x3e, 0xa4, 0x6b, 0x02, 0x57, 0x0e, 0xd9, 0xa4, 0xe5, 0x3f, 0xdd, + 0x17, 0xe3, 0x23, 0x76, 0x59, 0x46, 0xcd, 0x76, 0x9c, 0x5f, 0x6f, 0x6a, + 0x9c, 0x69, 0xd2, 0x72, 0x7a, 0x74, 0xc8, 0xfc, 0x73, 0xf0, 0x39, 0x55, + 0x33, 0xa4, 0x6e, 0xa5, 0x12, 0xe7, 0x80, 0x63, 0x0f, 0x74, 0x53, 0x1f, + 0x27, 0x3d, 0x22, 0x07, 0x61, 0xdf, 0x75, 0x9d, 0x17, 0x69, 0xc7, 0xa9, + 0xe9, 0x12, 0x6a, 0x9d, 0x3f, 0xd6, 0xb9, 0xcd, 0x75, 0xaf, 0x21, 0xbf, + 0x4d, 0x6f, 0xb2, 0x3d, 0x75, 0xd6, 0xb3, 0x3d, 0x75, 0x16, 0x3d, 0xf0, + 0xf1, 0x98, 0x74, 0xac, 0xc1, 0x7f, 0x5e, 0xd8, 0xe9, 0xd5, 0x73, 0x2f, + 0x24, 0x8d, 0xfc, 0x49, 0xc4, 0xbb, 0xe3, 0x51, 0xb1, 0x8e, 0xeb, 0x7c, + 0x00, 0x79, 0x4f, 0xc9, 0xdc, 0x29, 0xc6, 0x54, 0x4b, 0x86, 0x8f, 0x53, + 0x1f, 0xac, 0x6b, 0x96, 0x27, 0x8a, 0xf0, 0x91, 0x79, 0xc4, 0x05, 0xb5, + 0xf6, 0xae, 0x14, 0x2d, 0xca, 0xa1, 0x57, 0xba, 0xd6, 0xd0, 0x8f, 0xaf, + 0x21, 0x36, 0xac, 0x25, 0xa4, 0x0d, 0xbe, 0xa5, 0xce, 0xc6, 0x8d, 0xf2, + 0xd2, 0x0f, 0xe1, 0x0f, 0xfc, 0x0d, 0x07, 0xb5, 0xe5, 0xd9, 0x84, 0x41, + 0xdf, 0x52, 0x67, 0x69, 0xe7, 0x28, 0xa7, 0xce, 0xd2, 0xce, 0x49, 0x47, + 0xe0, 0x2f, 0x78, 0x3f, 0x3b, 0xae, 0xef, 0xa9, 0xaf, 0xd9, 0xe4, 0xe5, + 0x6f, 0xc4, 0xa9, 0xb1, 0x46, 0x24, 0x3f, 0xd2, 0x87, 0x5a, 0x66, 0xbb, + 0x63, 0x0f, 0x4f, 0x5e, 0x96, 0x4f, 0xca, 0xd7, 0xed, 0x9f, 0x80, 0x2f, + 0xf2, 0xd1, 0xca, 0x17, 0x79, 0xea, 0x95, 0x36, 0xcd, 0x57, 0xc0, 0x0f, + 0x04, 0x0d, 0x7e, 0x06, 0x8f, 0x27, 0x80, 0xff, 0x31, 0xc4, 0x80, 0x01, + 0x3c, 0x0f, 0xe0, 0x89, 0x94, 0x76, 0x96, 0xbc, 0x93, 0xd7, 0x77, 0x50, + 0x37, 0x06, 0x7c, 0xce, 0xe2, 0xfd, 0x15, 0x99, 0x5b, 0x72, 0x8f, 0x22, + 0xaf, 0xf2, 0x0e, 0xbd, 0xdf, 0xbb, 0x0f, 0xde, 0xcc, 0xfb, 0x2b, 0xe2, + 0xc9, 0x27, 0x65, 0xd6, 0x05, 0xef, 0xab, 0x9b, 0x65, 0xd1, 0x1a, 0x3b, + 0x12, 0xba, 0x0e, 0x3f, 0xd8, 0x60, 0x9c, 0xa0, 0x8c, 0xde, 0x11, 0x67, + 0x89, 0xf7, 0x5f, 0x1e, 0xbe, 0xd9, 0x46, 0x10, 0x37, 0x5a, 0xf7, 0xd8, + 0x80, 0x1b, 0x00, 0x1c, 0xe9, 0xda, 0xa0, 0xfc, 0x10, 0x73, 0x76, 0xb5, + 0xc4, 0x9a, 0xd6, 0x7d, 0x93, 0xf2, 0x0c, 0xea, 0x80, 0x57, 0xed, 0x5b, + 0xe4, 0x3a, 0xcb, 0x5a, 0xa8, 0xde, 0x98, 0x81, 0x4f, 0xb6, 0x21, 0x96, + 0x99, 0x72, 0xb9, 0xd2, 0x2e, 0x75, 0xd4, 0x3b, 0x2b, 0xab, 0x8c, 0x85, + 0xa4, 0xbd, 0x0b, 0xf3, 0x5e, 0xfc, 0x62, 0xac, 0xbd, 0x5c, 0x41, 0x9e, + 0x85, 0x6f, 0x5f, 0xae, 0xc4, 0xf1, 0x1c, 0xc0, 0xd3, 0xc2, 0x33, 0x89, + 0x67, 0x1a, 0xcf, 0x71, 0x3c, 0xc7, 0xf1, 0xb4, 0xb0, 0x37, 0x81, 0x67, + 0xd0, 0x33, 0x10, 0xd7, 0x4d, 0xbe, 0xcb, 0xfa, 0x3c, 0xd4, 0x8a, 0x16, + 0x73, 0x5a, 0xd4, 0xce, 0xa3, 0x8f, 0x70, 0xc6, 0x75, 0xad, 0x87, 0xfc, + 0xf6, 0x91, 0x6b, 0x5a, 0xec, 0xcb, 0x4b, 0xc6, 0x9e, 0x51, 0xe6, 0x85, + 0x1a, 0xf2, 0xc2, 0x7f, 0xec, 0x40, 0xff, 0x68, 0xee, 0xd5, 0x77, 0x47, + 0x4b, 0xf8, 0xe6, 0x3b, 0x7a, 0xde, 0xf8, 0x3c, 0xf2, 0x14, 0xe3, 0xa7, + 0x8b, 0x3d, 0x05, 0xc4, 0xf1, 0xed, 0xf0, 0xbf, 0x1c, 0xe2, 0x36, 0xde, + 0x97, 0x37, 0x76, 0x78, 0x39, 0x15, 0xf5, 0xbb, 0xda, 0x7c, 0x5f, 0x63, + 0x63, 0xcf, 0x56, 0xbd, 0x41, 0x0f, 0x70, 0xa4, 0x6a, 0xcb, 0xf0, 0xc1, + 0x37, 0xed, 0xa3, 0xba, 0xb6, 0xa3, 0x2e, 0x9e, 0x46, 0x8d, 0x9a, 0x5f, + 0x64, 0x0d, 0xf3, 0x14, 0xfa, 0x12, 0xf4, 0x67, 0x71, 0xf6, 0xe4, 0xcc, + 0x05, 0xba, 0x16, 0x8d, 0x4b, 0x17, 0xf3, 0xc0, 0x15, 0x9c, 0x07, 0xbe, + 0x56, 0x5c, 0xc8, 0xec, 0x41, 0xd4, 0x84, 0xae, 0x1b, 0xb5, 0xf6, 0x48, + 0xf2, 0x11, 0xc6, 0x1c, 0xc1, 0x7e, 0x53, 0xbc, 0x7b, 0x75, 0xc4, 0xdd, + 0x19, 0xfd, 0xfb, 0x30, 0x8c, 0x6b, 0x1c, 0x7b, 0x6f, 0x13, 0xef, 0xb7, + 0x5c, 0xde, 0x69, 0x8b, 0xec, 0x59, 0xf4, 0x6a, 0x5a, 0x65, 0xb5, 0xe2, + 0xfb, 0x49, 0x1f, 0x1f, 0xd7, 0x95, 0xff, 0xdb, 0xc6, 0x4e, 0xc8, 0x08, + 0xfe, 0x00, 0x1d, 0x1f, 0x43, 0xfd, 0x7c, 0x01, 0x7a, 0x79, 0x15, 0x3a, + 0x79, 0xad, 0x42, 0x5b, 0x1f, 0x83, 0xdd, 0x43, 0x86, 0x33, 0xfa, 0x0c, + 0x7d, 0xf6, 0x85, 0x0a, 0x62, 0x27, 0xe3, 0x9f, 0xfa, 0x52, 0x9c, 0xf5, + 0x21, 0xf3, 0xa0, 0x87, 0x67, 0xc0, 0x83, 0x93, 0x60, 0x6d, 0x87, 0xa6, + 0xa7, 0xae, 0xef, 0xc1, 0x28, 0x27, 0xd8, 0x20, 0x7f, 0x23, 0xd0, 0x30, + 0x5f, 0x8c, 0xeb, 0x7b, 0x78, 0xc5, 0x39, 0xf2, 0x31, 0x2e, 0xce, 0x62, + 0xb0, 0xaf, 0x0f, 0xfb, 0x3a, 0x5b, 0x70, 0xdd, 0xbe, 0x89, 0x07, 0xe5, + 0xf3, 0xc0, 0xf5, 0xcd, 0x75, 0x7f, 0xca, 0x2c, 0xdd, 0xb8, 0x1b, 0x66, + 0xfe, 0xa5, 0x6e, 0x32, 0xd8, 0x1f, 0xe8, 0x67, 0xc0, 0xef, 0x05, 0x52, + 0x0b, 0xe8, 0x23, 0x20, 0x7f, 0xea, 0x68, 0x92, 0xf1, 0x09, 0xf8, 0x6d, + 0xa9, 0x55, 0x3a, 0x44, 0xf5, 0xb3, 0x37, 0x66, 0xad, 0xdc, 0x7a, 0xe6, + 0x2f, 0xfa, 0x67, 0xa2, 0x9f, 0x3e, 0xc1, 0xba, 0x59, 0xe7, 0x19, 0xc0, + 0x74, 0x6f, 0xa2, 0xed, 0xe7, 0x7c, 0x38, 0xae, 0xa7, 0xa5, 0x84, 0x3a, + 0x34, 0xbf, 0x88, 0x8a, 0x1e, 0xf1, 0x5b, 0x65, 0xf9, 0xbb, 0x16, 0xef, + 0xf0, 0xc6, 0x92, 0x73, 0xa0, 0xb1, 0x64, 0xe6, 0x78, 0x6f, 0x06, 0x1c, + 0xbb, 0x36, 0xe1, 0x98, 0xf2, 0x71, 0x4c, 0x49, 0xf9, 0xd4, 0x34, 0x7c, + 0x2d, 0x87, 0xfc, 0x3e, 0x64, 0x3e, 0x28, 0x9f, 0x41, 0x73, 0x8d, 0xb9, + 0x33, 0xe3, 0xd0, 0x93, 0xeb, 0xee, 0xb1, 0xf7, 0x83, 0xee, 0x97, 0x91, + 0x5b, 0x83, 0x9a, 0xa7, 0x9c, 0x88, 0x20, 0x87, 0x1d, 0xd6, 0xbf, 0xc3, + 0x96, 0x4c, 0x13, 0xf6, 0xaa, 0x8c, 0xb1, 0x34, 0xda, 0x7b, 0xe4, 0xb7, + 0x05, 0xe4, 0x2a, 0xf2, 0xd9, 0x23, 0x65, 0xd3, 0x78, 0x20, 0x82, 0xba, + 0xc6, 0x59, 0xa4, 0x1f, 0xc9, 0x70, 0x24, 0xdb, 0x8e, 0x9a, 0xd4, 0x95, + 0xef, 0xd9, 0xfc, 0x77, 0x09, 0x0b, 0x72, 0xa1, 0x61, 0xe2, 0x79, 0x0e, + 0x7a, 0xf8, 0x3d, 0xbc, 0xff, 0x53, 0x3f, 0xea, 0x3e, 0xac, 0xe4, 0x60, + 0xbb, 0x69, 0x5d, 0xcf, 0xb0, 0x8e, 0xa8, 0x23, 0xdf, 0x2a, 0xe4, 0x1a, + 0xd4, 0x55, 0x93, 0xac, 0x5d, 0x9f, 0x59, 0xb9, 0x2a, 0xaf, 0x2d, 0xf1, + 0x77, 0x50, 0xe6, 0xe5, 0x7d, 0x8c, 0x07, 0xe6, 0x7c, 0x06, 0x73, 0xab, + 0x8c, 0x65, 0xf8, 0x6e, 0xc2, 0x81, 0xfa, 0x51, 0x23, 0xa0, 0xd6, 0xbe, + 0x6c, 0xa5, 0xc1, 0xe7, 0x55, 0xb9, 0xb0, 0x14, 0x95, 0x15, 0x8b, 0x75, + 0x91, 0x24, 0x1d, 0xc0, 0x5e, 0x58, 0xfd, 0x07, 0xcf, 0x26, 0x08, 0x8f, + 0x9e, 0xa7, 0x84, 0xba, 0xee, 0x41, 0xbd, 0xf7, 0x47, 0xe9, 0x99, 0x34, + 0xb5, 0xf6, 0x79, 0x45, 0xb9, 0x40, 0x7f, 0xd2, 0xbf, 0x51, 0xb0, 0x36, + 0x78, 0x0a, 0x36, 0xcb, 0xda, 0x9d, 0xfd, 0x00, 0xde, 0x1b, 0x5c, 0x27, + 0xef, 0x78, 0x2e, 0x0f, 0x41, 0x36, 0xf4, 0x7b, 0xde, 0x89, 0x21, 0x8f, + 0x2a, 0xfa, 0x7a, 0x59, 0xc7, 0x82, 0x72, 0xb5, 0x88, 0x9c, 0x82, 0x18, + 0x60, 0xef, 0x82, 0x2d, 0xce, 0x40, 0x97, 0x93, 0x80, 0xdb, 0x94, 0x4b, + 0xd6, 0xcb, 0xba, 0x2e, 0x53, 0xa7, 0x6f, 0xde, 0xdf, 0x14, 0xe0, 0x3f, + 0x6a, 0x1d, 0xb6, 0x05, 0x1f, 0x52, 0xeb, 0x71, 0x3c, 0x11, 0x8f, 0xd7, + 0xd1, 0x5f, 0x54, 0x78, 0x3f, 0x84, 0xde, 0xa0, 0xc2, 0xbb, 0x93, 0x34, + 0x9e, 0xe3, 0xbc, 0x2f, 0xf2, 0xe3, 0x1a, 0xf1, 0x93, 0x8e, 0x20, 0xbe, + 0xb0, 0x96, 0x64, 0x7c, 0x09, 0xea, 0x49, 0xcf, 0x16, 0x8e, 0x55, 0x19, + 0x43, 0x68, 0xd7, 0x43, 0x88, 0x5b, 0xb4, 0x05, 0xaf, 0x96, 0x5c, 0xad, + 0x79, 0x32, 0x9b, 0x6b, 0x9e, 0xd7, 0x39, 0x62, 0xaf, 0x58, 0xb0, 0x31, + 0xca, 0x0e, 0x6b, 0x3a, 0x07, 0x9c, 0x93, 0x9c, 0x7e, 0x52, 0x66, 0xaf, + 0x48, 0x6e, 0x75, 0x5c, 0x9e, 0xd3, 0x71, 0x2b, 0x88, 0x59, 0xac, 0x21, + 0xf9, 0xfb, 0x71, 0x5a, 0x9e, 0x3d, 0x79, 0x55, 0x9c, 0xe7, 0x19, 0xb7, + 0xc6, 0x12, 0x9d, 0x06, 0x63, 0x95, 0x2b, 0x0d, 0xe4, 0xa6, 0x07, 0x6d, + 0xfe, 0x5b, 0x80, 0x08, 0x7a, 0x3a, 0x57, 0xda, 0x27, 0x52, 0x76, 0xd2, + 0x18, 0x3a, 0xd0, 0x69, 0x30, 0x37, 0x8e, 0x99, 0x8f, 0x4b, 0x70, 0x1f, + 0xd5, 0x21, 0x8f, 0xeb, 0xbb, 0x0a, 0xb8, 0xed, 0xe2, 0x07, 0xfa, 0x77, + 0x94, 0x6b, 0x19, 0xca, 0x1a, 0xdf, 0xeb, 0x9c, 0x2f, 0xc5, 0xae, 0x65, + 0xda, 0xa4, 0x7c, 0x9b, 0xeb, 0x1e, 0x9a, 0x98, 0xd8, 0xe1, 0xfd, 0x7b, + 0x91, 0x23, 0xb7, 0x79, 0xb1, 0xa0, 0xe0, 0x7f, 0xaf, 0xe1, 0x49, 0xdb, + 0x66, 0xbe, 0x65, 0x7e, 0xa4, 0xde, 0xf0, 0x5c, 0xe5, 0x3b, 0x73, 0xef, + 0x02, 0x72, 0x2f, 0xf3, 0xe5, 0x76, 0xc9, 0xf3, 0x77, 0x3e, 0xa5, 0xe7, + 0x4b, 0x5e, 0x2d, 0xed, 0xc3, 0xd5, 0x66, 0x65, 0xae, 0xc6, 0x1a, 0xea, + 0x02, 0x72, 0xd9, 0x28, 0x6c, 0x95, 0x39, 0xed, 0x28, 0xf2, 0x39, 0x7f, + 0x9f, 0xc6, 0xda, 0x32, 0xf7, 0xa5, 0xd2, 0x49, 0xd5, 0xfa, 0xbb, 0xd2, + 0xd5, 0x38, 0xef, 0xa3, 0xce, 0x8d, 0x42, 0xef, 0xbf, 0xc3, 0xde, 0x62, + 0x58, 0xdb, 0x88, 0xf3, 0x02, 0x65, 0xef, 0xfd, 0x7e, 0x2d, 0x7d, 0x9e, + 0x0f, 0xb0, 0x0e, 0xf8, 0x3c, 0xe4, 0xb2, 0xd7, 0xbe, 0xca, 0xdc, 0xfd, + 0x6f, 0xca, 0x1a, 0x4b, 0x3f, 0x6e, 0xd0, 0xb7, 0xf1, 0xbd, 0x1a, 0x91, + 0xe5, 0x38, 0xf9, 0x87, 0xbc, 0x0c, 0xfa, 0xce, 0x56, 0x72, 0xd8, 0x2c, + 0x83, 0x3f, 0x80, 0x0c, 0x28, 0xcb, 0x40, 0x06, 0x7c, 0x9f, 0x86, 0xbe, + 0xd8, 0x33, 0x0c, 0xe9, 0x3e, 0xb2, 0xdc, 0xf4, 0xce, 0x2e, 0x57, 0x5b, + 0x69, 0x26, 0xbd, 0xd4, 0xe9, 0x39, 0xc9, 0x6b, 0xfd, 0x2e, 0x48, 0xbe, + 0x76, 0x4e, 0xf6, 0xd4, 0x16, 0xe4, 0x21, 0xeb, 0x01, 0xf0, 0x7b, 0xc9, + 0x2d, 0x5a, 0xba, 0x57, 0x99, 0x2c, 0xe0, 0xec, 0xe2, 0xff, 0x74, 0x6e, + 0xb5, 0xbf, 0x6d, 0x55, 0x67, 0xfc, 0xf1, 0xb5, 0x9d, 0xa4, 0xa1, 0x09, + 0xb7, 0xae, 0x93, 0xb8, 0x69, 0x0a, 0x76, 0x7c, 0xdb, 0x46, 0x24, 0xad, + 0x6e, 0x43, 0x46, 0xa3, 0x2e, 0x53, 0x4c, 0x12, 0xba, 0x74, 0xeb, 0x44, + 0xda, 0x75, 0x5d, 0x37, 0xd0, 0x64, 0x9c, 0xb4, 0x14, 0x98, 0x54, 0x28, + 0xac, 0x43, 0x08, 0xa9, 0xc6, 0x6d, 0x35, 0xa6, 0xa5, 0x71, 0xfa, 0x46, + 0x10, 0x5f, 0xb0, 0x92, 0xb4, 0x65, 0x52, 0x84, 0x5b, 0x04, 0xdb, 0x3e, + 0xb0, 0xd1, 0xa5, 0x8c, 0x3f, 0x60, 0xfb, 0x30, 0x26, 0xb1, 0x29, 0x2b, + 0xb0, 0xb1, 0x7d, 0xea, 0x07, 0x26, 0x75, 0xda, 0x8a, 0xf7, 0xfb, 0x3d, + 0xe7, 0x5e, 0xc7, 0x36, 0x41, 0x48, 0x8b, 0x14, 0xf9, 0x9e, 0x97, 0x7b, + 0xee, 0xb9, 0xe7, 0x79, 0x7f, 0x9e, 0xdf, 0xed, 0x59, 0x27, 0x9f, 0xc0, + 0xef, 0x38, 0x35, 0x67, 0x4b, 0xda, 0xee, 0x97, 0x9f, 0x6a, 0x2e, 0x9f, + 0xf1, 0x49, 0x00, 0x3e, 0xa9, 0xc1, 0x16, 0x48, 0x8b, 0x13, 0xbb, 0x21, + 0xf4, 0x29, 0xc3, 0xa0, 0x75, 0xdc, 0xf8, 0xcd, 0xb6, 0x19, 0xdf, 0x74, + 0x06, 0xbe, 0xbb, 0xbb, 0xad, 0xc5, 0xcf, 0xf9, 0x1a, 0xff, 0xf6, 0x7d, + 0xaf, 0x86, 0xd6, 0x2f, 0xd3, 0xd8, 0xcf, 0x9b, 0xaa, 0x67, 0x1d, 0xf0, + 0x12, 0x73, 0xd3, 0x31, 0xcd, 0x3f, 0x84, 0xa7, 0xa8, 0xa3, 0xae, 0x40, + 0x47, 0x0d, 0x50, 0x77, 0x0d, 0xce, 0xb9, 0xcc, 0x0f, 0x44, 0xe5, 0x0f, + 0x93, 0xd4, 0xc3, 0x71, 0xf9, 0xfd, 0xe4, 0xb3, 0xd8, 0x4f, 0xa2, 0xc0, + 0x1c, 0xe5, 0xf5, 0xe9, 0xac, 0x62, 0x92, 0x86, 0xd5, 0x07, 0x7e, 0x5a, + 0xed, 0x40, 0xdc, 0xca, 0xad, 0x0d, 0xab, 0xbe, 0x39, 0xa2, 0xb5, 0xdd, + 0xb8, 0xd5, 0x21, 0xd7, 0xcf, 0x1b, 0x1d, 0x1b, 0x9e, 0x8a, 0x06, 0x86, + 0xe7, 0x69, 0x97, 0x92, 0xb1, 0x8c, 0x55, 0x2f, 0x07, 0xa3, 0xcc, 0x3d, + 0xa7, 0xa8, 0x9f, 0x61, 0x0b, 0xbb, 0xed, 0x8c, 0xd5, 0xe0, 0xd9, 0x9f, + 0x58, 0x8d, 0x9e, 0x3d, 0xe2, 0xe9, 0x59, 0x8e, 0xa5, 0x40, 0x53, 0xda, + 0xa2, 0xc4, 0xf4, 0x88, 0x95, 0x84, 0xcd, 0xc3, 0xf5, 0x02, 0xd7, 0x8f, + 0xcb, 0xd1, 0x85, 0xc3, 0xf0, 0xbf, 0xbb, 0xed, 0xbd, 0xb4, 0xab, 0xf6, + 0x00, 0xf1, 0x38, 0x78, 0xfe, 0x86, 0x9a, 0xb5, 0x1e, 0xf6, 0xd6, 0xe2, + 0x38, 0xe4, 0x7c, 0x8a, 0xf5, 0xda, 0x7a, 0xe6, 0x73, 0x74, 0xaf, 0xd5, + 0x73, 0xf7, 0x94, 0x9f, 0x7b, 0x32, 0xef, 0x78, 0x58, 0x30, 0xfc, 0xc2, + 0x17, 0xfa, 0x76, 0x84, 0xcf, 0xe4, 0xf3, 0x9a, 0x65, 0x68, 0x3f, 0xf4, + 0xcb, 0x14, 0xff, 0xb3, 0x5e, 0xed, 0x0a, 0xf1, 0x4a, 0xb4, 0x7d, 0x05, + 0xdb, 0xf4, 0x35, 0x6f, 0xbd, 0xad, 0xad, 0xd2, 0x18, 0xad, 0x98, 0xcf, + 0xdc, 0x0a, 0xdb, 0x71, 0xc9, 0x2e, 0xf0, 0xb7, 0x54, 0x8a, 0x38, 0x75, + 0xb2, 0xd7, 0x5e, 0x5f, 0xb3, 0xc6, 0x16, 0xf4, 0x19, 0x9f, 0x20, 0x38, + 0x15, 0xf0, 0x7c, 0x8b, 0xbb, 0xe9, 0x37, 0x79, 0xd7, 0x0d, 0x9a, 0x93, + 0x89, 0x5b, 0xed, 0x35, 0xef, 0x71, 0x77, 0xd9, 0x0e, 0xc7, 0x2d, 0xea, + 0xce, 0x60, 0x54, 0x9a, 0xc9, 0x43, 0x25, 0xf5, 0xe3, 0x43, 0x8e, 0xc1, + 0x5c, 0x44, 0x9d, 0xf1, 0x56, 0xe6, 0xec, 0xdf, 0xd1, 0x73, 0x6b, 0xa2, + 0x4f, 0x80, 0x6b, 0xf0, 0xc9, 0xe7, 0xf2, 0xbd, 0xcc, 0xf5, 0x62, 0xfd, + 0x46, 0xae, 0xef, 0x7a, 0xe7, 0x9c, 0x70, 0xb3, 0xd6, 0x7d, 0x92, 0x39, + 0x6f, 0xf8, 0x6f, 0xc8, 0x01, 0xef, 0x35, 0xa3, 0x3d, 0x4f, 0x9b, 0xf0, + 0x45, 0xeb, 0xf8, 0xb6, 0xa1, 0x4b, 0x6d, 0xc3, 0x89, 0x3c, 0xf9, 0x93, + 0x7c, 0xe9, 0xf3, 0xa3, 0xaf, 0xf3, 0xc8, 0xa3, 0xd4, 0xb3, 0xfd, 0x72, + 0x26, 0xcf, 0xb3, 0x49, 0x69, 0x4d, 0x6b, 0xe3, 0xd9, 0x71, 0xc5, 0x64, + 0x75, 0x4e, 0x25, 0x5e, 0xce, 0xca, 0xa0, 0x5c, 0x71, 0x79, 0x66, 0x89, + 0x42, 0x3a, 0xd8, 0x54, 0xf1, 0xfe, 0xfb, 0xf5, 0xcc, 0xc2, 0xea, 0x33, + 0xc6, 0x30, 0xf7, 0x79, 0x8f, 0xde, 0xcd, 0x7a, 0xb6, 0xe9, 0x2a, 0xfa, + 0x7c, 0x53, 0xcf, 0x29, 0x0c, 0x9d, 0xc8, 0xfa, 0x7e, 0x38, 0xc2, 0x7b, + 0xf8, 0x5c, 0xfa, 0x7c, 0x7c, 0x16, 0x79, 0xaf, 0x13, 0x16, 0xbb, 0x57, + 0x82, 0x3b, 0x20, 0xfa, 0x3b, 0x58, 0x47, 0x0e, 0x40, 0x56, 0x37, 0x1a, + 0x0c, 0xcc, 0x98, 0xf1, 0x35, 0xd2, 0xd6, 0x55, 0x9c, 0x23, 0x62, 0x15, + 0xf8, 0xd1, 0x27, 0x5e, 0xba, 0x8d, 0xf5, 0xd2, 0x9e, 0xbf, 0xde, 0x87, + 0xf5, 0x1d, 0xaf, 0xae, 0x3e, 0xb9, 0x8d, 0xbc, 0x3a, 0xa2, 0xf5, 0x41, + 0xde, 0x43, 0x39, 0xe6, 0x99, 0x91, 0x2e, 0xef, 0xe3, 0x7e, 0xb6, 0xb7, + 0xd4, 0xd0, 0x31, 0xe9, 0xed, 0xcf, 0x1f, 0x0f, 0x4b, 0xb8, 0x95, 0x3a, + 0x2e, 0x2a, 0xc9, 0x29, 0xc6, 0x2c, 0xb0, 0x5d, 0x63, 0x5c, 0xeb, 0xcb, + 0x75, 0x71, 0xfa, 0xff, 0xd4, 0xc5, 0x69, 0xeb, 0x23, 0xe5, 0x9d, 0xb0, + 0xe6, 0xb1, 0xbe, 0x98, 0xae, 0x85, 0x2a, 0xba, 0xfa, 0xb5, 0xfb, 0x68, + 0x99, 0x8e, 0x3f, 0xc9, 0xd3, 0x5e, 0xa5, 0x34, 0xa7, 0xfc, 0xb7, 0x49, + 0x9e, 0x2d, 0xf7, 0x78, 0x85, 0x7b, 0x1c, 0x5c, 0x74, 0x89, 0x83, 0xf9, + 0x96, 0xca, 0xf0, 0xa9, 0x3c, 0x75, 0x4c, 0x93, 0xcc, 0x4d, 0xfb, 0x7a, + 0x66, 0xd4, 0xf3, 0x71, 0x73, 0x6b, 0xeb, 0x54, 0xcf, 0xc0, 0xbb, 0x71, + 0x86, 0x3d, 0xfb, 0xd2, 0x21, 0xb3, 0xe7, 0x69, 0x77, 0x93, 0xe8, 0x8b, + 0x06, 0x66, 0xe7, 0x59, 0x9b, 0x24, 0x16, 0x65, 0x50, 0x58, 0xf7, 0x1f, + 0xb6, 0x4f, 0x40, 0xde, 0x62, 0xf2, 0xe1, 0x24, 0x7d, 0xfa, 0x3a, 0xf8, + 0xc6, 0xcd, 0x35, 0xe7, 0xbb, 0xbd, 0xec, 0x13, 0x56, 0xd3, 0xbd, 0xa3, + 0x4d, 0x1a, 0xc9, 0xe7, 0x8e, 0x7d, 0x5d, 0xe8, 0x83, 0xf1, 0x3a, 0x83, + 0x58, 0x80, 0xb1, 0x47, 0x5c, 0x63, 0x8f, 0xd9, 0x02, 0xfb, 0x9a, 0xbc, + 0xbc, 0x52, 0x93, 0xf2, 0x0a, 0xf9, 0x2d, 0xad, 0xfe, 0xf7, 0x80, 0xea, + 0xac, 0xdc, 0x64, 0xb7, 0xc1, 0xb1, 0xd8, 0x31, 0xe5, 0x3d, 0xa9, 0xe2, + 0xbd, 0x98, 0xef, 0x4b, 0xb6, 0x19, 0xdf, 0xca, 0x56, 0x7d, 0x13, 0xd6, + 0x79, 0xb4, 0x2b, 0x5c, 0x9f, 0xbc, 0x41, 0x1e, 0xa1, 0xce, 0xf3, 0xe7, + 0xf9, 0xf4, 0xf0, 0xdb, 0x9c, 0x4f, 0xfe, 0xaf, 0xc4, 0x22, 0xf8, 0xb2, + 0xea, 0xf7, 0xf9, 0x72, 0xc7, 0xb1, 0x4a, 0x9b, 0x40, 0xb9, 0xab, 0xac, + 0x4f, 0xda, 0x12, 0x99, 0x5a, 0xa6, 0xcb, 0x50, 0x2f, 0xf7, 0xff, 0x3c, + 0x73, 0xbb, 0x90, 0xb7, 0x95, 0x68, 0x73, 0x4c, 0x69, 0x93, 0x06, 0x6d, + 0x22, 0x4a, 0x1b, 0xc6, 0x7b, 0x4f, 0x79, 0xfc, 0xd6, 0x84, 0xf3, 0x62, + 0xae, 0x16, 0xba, 0x6e, 0x1f, 0x75, 0xfe, 0x33, 0x6d, 0x5a, 0x1f, 0x74, + 0xa8, 0xfb, 0x56, 0x43, 0x9f, 0xb1, 0xbd, 0x59, 0xfd, 0x11, 0x13, 0x6f, + 0xc5, 0x35, 0x0f, 0x1a, 0x84, 0x7e, 0x9e, 0x9d, 0x84, 0xaf, 0x46, 0xdc, + 0x5b, 0x15, 0xad, 0x1e, 0xf7, 0xce, 0xeb, 0x55, 0xa5, 0x0d, 0x65, 0x80, + 0x7a, 0x73, 0x0d, 0xd6, 0xdb, 0x13, 0xed, 0x01, 0x7f, 0xbd, 0x82, 0xfe, + 0x8d, 0x1a, 0x4f, 0x04, 0x21, 0xf3, 0x37, 0x26, 0x5b, 0xbd, 0x18, 0xce, + 0x41, 0x1b, 0x71, 0xeb, 0x64, 0x84, 0x31, 0x05, 0xda, 0x5d, 0x52, 0x37, + 0x85, 0xf8, 0x15, 0x7a, 0x7c, 0x51, 0xed, 0x51, 0x0f, 0xc6, 0xef, 0x20, + 0xce, 0x0f, 0xd7, 0x87, 0x71, 0x5f, 0xb7, 0xc1, 0x22, 0x44, 0x37, 0xe9, + 0x99, 0xce, 0x4e, 0x26, 0x62, 0x87, 0xc4, 0xeb, 0x1b, 0x73, 0x55, 0x1f, + 0x2c, 0xef, 0xeb, 0x01, 0xd9, 0x53, 0xb6, 0x17, 0x8c, 0xa3, 0xe1, 0xc3, + 0x4f, 0x1b, 0x7b, 0x90, 0x2b, 0xf4, 0x28, 0x3e, 0x2a, 0x38, 0xb0, 0x80, + 0xb3, 0xa4, 0x4f, 0xba, 0x04, 0x3f, 0xdc, 0xc5, 0x19, 0xd2, 0xef, 0x2e, + 0x1d, 0x3f, 0xe9, 0xa6, 0x58, 0x1f, 0x83, 0x3e, 0x38, 0x2e, 0xc3, 0x88, + 0x0b, 0x86, 0x83, 0xcd, 0xcc, 0x2b, 0xc3, 0x37, 0xcc, 0x7a, 0xb9, 0xc7, + 0x1e, 0xe6, 0x4c, 0xe5, 0xec, 0x3c, 0xf7, 0x4e, 0xd9, 0x36, 0xb1, 0xf7, + 0xec, 0x24, 0xf7, 0x6b, 0xf2, 0x10, 0x6c, 0x5b, 0x53, 0x2e, 0x7e, 0x79, + 0x16, 0x7d, 0xf8, 0xed, 0x87, 0x3c, 0x70, 0x2e, 0x7e, 0xe7, 0x97, 0xe4, + 0xbd, 0xf3, 0xbe, 0x6d, 0x0f, 0xc8, 0xbb, 0x4e, 0xe9, 0xf8, 0x09, 0x77, + 0x2d, 0xcf, 0xc0, 0xcd, 0xb2, 0x66, 0xed, 0x38, 0x6e, 0x4e, 0x4a, 0xa5, + 0x45, 0x77, 0x71, 0xad, 0xa5, 0xb4, 0xa4, 0xfc, 0x7f, 0x80, 0x33, 0xbc, + 0x76, 0xaf, 0x25, 0x86, 0x7e, 0xa4, 0xcd, 0xe7, 0x6b, 0x7f, 0x95, 0xb6, + 0xc0, 0xd7, 0x7f, 0xe4, 0x47, 0xf2, 0xe5, 0x92, 0xec, 0x54, 0xfd, 0xbf, + 0xd2, 0x7d, 0x95, 0xba, 0xdf, 0xf7, 0x6f, 0xa9, 0xdf, 0xc9, 0x8b, 0x31, + 0x8d, 0x0f, 0x36, 0x4d, 0xd5, 0xea, 0x84, 0x1f, 0x78, 0x75, 0x85, 0x95, + 0x78, 0xef, 0x80, 0xa7, 0x17, 0x52, 0xea, 0x3b, 0xa7, 0x6c, 0xea, 0x07, + 0xee, 0xa7, 0x51, 0xc6, 0x67, 0x6e, 0x83, 0x26, 0xbe, 0x0e, 0x66, 0xdc, + 0xe7, 0xeb, 0x8e, 0x66, 0xcf, 0x17, 0xb6, 0xa4, 0xf3, 0x2c, 0x7d, 0x27, + 0x07, 0x7a, 0xb4, 0x45, 0xd2, 0x63, 0x41, 0x49, 0x9e, 0x6d, 0x89, 0x19, + 0x5f, 0x97, 0xfc, 0x07, 0x79, 0xd3, 0x3e, 0xb6, 0x37, 0xa0, 0xff, 0x4e, + 0xe1, 0xb3, 0x0d, 0x3f, 0x43, 0x9e, 0xf7, 0xf9, 0x63, 0x76, 0x0d, 0x8f, + 0xee, 0xf0, 0x78, 0x94, 0xe3, 0x96, 0xa9, 0x7f, 0x60, 0x6e, 0xe7, 0x59, + 0xee, 0xd1, 0xdc, 0xd7, 0x79, 0xd6, 0xc4, 0xeb, 0xd5, 0xf7, 0xf5, 0x94, + 0xef, 0xc3, 0x78, 0x97, 0x62, 0xc3, 0xb0, 0xf6, 0xce, 0x7e, 0xf8, 0x74, + 0x3d, 0xb4, 0x39, 0xb4, 0xdf, 0x1b, 0xdd, 0x9d, 0x42, 0x7e, 0x4f, 0x78, + 0x3c, 0x47, 0x7d, 0x13, 0xf1, 0xf4, 0xcd, 0xb2, 0x7d, 0x19, 0x36, 0xf8, + 0x13, 0xe6, 0x44, 0x2a, 0xec, 0xcb, 0x43, 0xe6, 0xdd, 0xaa, 0xec, 0xcb, + 0x9d, 0xde, 0x3a, 0xfe, 0x98, 0xaf, 0x57, 0xfc, 0xb6, 0xaf, 0x57, 0x6a, + 0x7d, 0x5a, 0x9f, 0xf6, 0xd5, 0xb8, 0xaf, 0xca, 0x98, 0x2f, 0xb7, 0x62, + 0xde, 0x25, 0x83, 0x98, 0x8d, 0x3e, 0x65, 0x22, 0x6b, 0x30, 0xd3, 0xd6, + 0x19, 0x8b, 0xb8, 0x0f, 0xe7, 0x67, 0x32, 0x14, 0xb9, 0xad, 0xb1, 0xf5, + 0xa9, 0x99, 0x51, 0xcd, 0xf3, 0xcc, 0xba, 0x9e, 0xde, 0x89, 0xee, 0x86, + 0x5c, 0xcd, 0x47, 0x96, 0x31, 0x45, 0x4f, 0x1e, 0x1b, 0x82, 0x1d, 0x4a, + 0x69, 0xbd, 0xec, 0x71, 0xec, 0xb7, 0x5f, 0xf1, 0x5c, 0xab, 0x9c, 0xe7, + 0x64, 0x97, 0x5d, 0xd2, 0xda, 0x4d, 0xc3, 0x40, 0xf6, 0x58, 0xc3, 0x69, + 0x9f, 0xef, 0xc9, 0x4f, 0x4f, 0x1e, 0x1b, 0x9f, 0x2e, 0x0d, 0x86, 0xb6, + 0x75, 0xdb, 0x39, 0x59, 0x0f, 0x9a, 0x0f, 0xca, 0xa3, 0x8a, 0x1d, 0x7e, + 0x0d, 0xe3, 0xfb, 0x18, 0x5f, 0x26, 0x42, 0x8a, 0x09, 0x4e, 0xc4, 0x26, + 0x20, 0x8b, 0x19, 0x37, 0xd1, 0x35, 0x14, 0x5c, 0xcd, 0xdc, 0x0d, 0x62, + 0x66, 0xfa, 0x59, 0xc4, 0x14, 0x3c, 0x2b, 0x87, 0xdc, 0x8d, 0xee, 0xa2, + 0x64, 0x3d, 0x4c, 0x3e, 0x6b, 0x42, 0xf5, 0x32, 0xe1, 0x86, 0x1a, 0x86, + 0x8a, 0x46, 0x06, 0x46, 0x82, 0xa9, 0x55, 0x27, 0x9d, 0x68, 0xc3, 0xce, + 0x22, 0x64, 0xbc, 0x08, 0xfd, 0x5f, 0x8c, 0x05, 0x86, 0x15, 0x9b, 0xf6, + 0x55, 0x19, 0x6a, 0xa5, 0x9f, 0x4f, 0x7d, 0xf2, 0x35, 0xb9, 0x61, 0x6f, + 0x96, 0x1b, 0x5d, 0xc4, 0x63, 0xf6, 0xa2, 0x4d, 0x5d, 0xd2, 0x8f, 0xbe, + 0x24, 0xfa, 0x1a, 0x94, 0x1f, 0x35, 0x3e, 0x83, 0xce, 0xba, 0x61, 0x53, + 0x57, 0xdd, 0xc5, 0x5f, 0xbc, 0xeb, 0x9f, 0x41, 0x13, 0x62, 0x3b, 0xb6, + 0xa0, 0x4d, 0x1d, 0x67, 0xd7, 0xf4, 0xb7, 0xa3, 0x7d, 0x2f, 0xd6, 0xa8, + 0xd3, 0xf7, 0xb3, 0x9c, 0x6d, 0xa6, 0xce, 0x59, 0x35, 0x67, 0x4d, 0x4d, + 0xfb, 0xdd, 0x16, 0x83, 0x4f, 0xb8, 0x45, 0x7a, 0x67, 0x53, 0xb2, 0xab, + 0xad, 0xba, 0xfd, 0xcf, 0x9a, 0x76, 0xb3, 0xac, 0x6a, 0x21, 0x19, 0x9e, + 0x68, 0xad, 0xee, 0xf7, 0xf9, 0xc9, 0x6f, 0xb7, 0xe1, 0x7d, 0x13, 0x30, + 0x78, 0x49, 0x8d, 0xa5, 0x6e, 0x44, 0xf9, 0xac, 0xbf, 0xd6, 0xdc, 0xc3, + 0x6b, 0xde, 0xc3, 0x7b, 0x99, 0xd7, 0xfb, 0x37, 0xfb, 0x71, 0x0f, 0x73, + 0x02, 0xcc, 0x6b, 0x90, 0x67, 0x57, 0x8a, 0xb3, 0x38, 0xe7, 0xf3, 0xf9, + 0x86, 0x74, 0x99, 0xf7, 0x7c, 0xbd, 0x12, 0x2b, 0x63, 0xd5, 0x76, 0xe6, + 0xfd, 0x9c, 0x30, 0x69, 0xa7, 0x35, 0xa9, 0xd8, 0x75, 0xd0, 0xf9, 0x20, + 0xe8, 0xfc, 0x40, 0x90, 0x71, 0x61, 0xa3, 0x47, 0x6b, 0x47, 0x86, 0x8b, + 0x6f, 0x43, 0xc6, 0xc9, 0xa3, 0xf0, 0x29, 0x8a, 0x96, 0x87, 0xcf, 0xe8, + 0x83, 0x4d, 0x73, 0x25, 0xa8, 0x79, 0x07, 0xc4, 0xf7, 0x73, 0xd7, 0x64, + 0x78, 0x92, 0x39, 0x01, 0xf2, 0x33, 0xe3, 0xfa, 0x14, 0xc6, 0x6e, 0x62, + 0xae, 0x0b, 0x19, 0x1e, 0x05, 0xbf, 0x86, 0xc4, 0x99, 0xda, 0x22, 0xd9, + 0xb1, 0x51, 0xf5, 0x01, 0x3a, 0x61, 0xa3, 0x4e, 0xb8, 0x23, 0x72, 0xf2, + 0xf2, 0xdd, 0x90, 0x55, 0xc6, 0xfd, 0x9a, 0xd3, 0x28, 0x85, 0xd5, 0x37, + 0xa7, 0xcf, 0xc1, 0x3c, 0x9c, 0xa9, 0x31, 0x1b, 0xb9, 0x7d, 0x24, 0x26, + 0xcd, 0x23, 0x32, 0x3d, 0x63, 0x2b, 0xde, 0x25, 0x25, 0xb7, 0x4b, 0xa4, + 0x5d, 0x66, 0x5f, 0x1c, 0xba, 0x8a, 0xbe, 0x7c, 0x2e, 0x62, 0xce, 0x72, + 0x74, 0x1d, 0x63, 0xe2, 0xe4, 0x54, 0xe5, 0x1a, 0x8a, 0x91, 0xc1, 0xd8, + 0xa5, 0x16, 0x23, 0x33, 0x8c, 0x8f, 0x3f, 0x2a, 0xa5, 0xa2, 0x7c, 0x26, + 0xe7, 0xb2, 0x76, 0x4b, 0x1e, 0xe1, 0xde, 0xfe, 0xe3, 0xf1, 0xf2, 0x4b, + 0x58, 0x2f, 0x2e, 0x9d, 0xaf, 0x8f, 0x6a, 0x5c, 0x7f, 0xa2, 0x2a, 0x86, + 0x35, 0xf9, 0x02, 0x13, 0xc7, 0x5e, 0x93, 0x89, 0x05, 0xd2, 0x87, 0x36, + 0x3e, 0x20, 0x3f, 0x77, 0xba, 0xed, 0xc7, 0xb4, 0xd6, 0x98, 0x48, 0xb1, + 0x3e, 0xd3, 0xe8, 0x24, 0xed, 0x39, 0x09, 0xf5, 0x7f, 0x03, 0xd7, 0x8c, + 0x6b, 0x73, 0x6e, 0xb7, 0xfb, 0x98, 0xf8, 0x38, 0x90, 0x8d, 0xa9, 0xfa, + 0xc0, 0xad, 0xd2, 0xb5, 0x7d, 0x9c, 0x63, 0x70, 0x20, 0x12, 0x20, 0xad, + 0x3e, 0xb8, 0x8b, 0xf8, 0x99, 0xea, 0xfc, 0xdf, 0xfd, 0x47, 0xf6, 0xf6, + 0x25, 0x5e, 0x64, 0x0c, 0x1b, 0x76, 0x0e, 0xac, 0x33, 0xef, 0x9a, 0xcd, + 0xae, 0x11, 0xad, 0x9f, 0x1d, 0xfd, 0xbb, 0x43, 0x3c, 0x44, 0x22, 0x56, + 0x6f, 0x31, 0x0f, 0x4e, 0x1d, 0xc7, 0x9a, 0x0a, 0x73, 0x6e, 0xc4, 0xf2, + 0x37, 0xc8, 0xa5, 0x1e, 0x4b, 0xee, 0x0f, 0xa5, 0xe2, 0x96, 0x6c, 0x8a, + 0x9f, 0x15, 0x3c, 0x93, 0xf5, 0x95, 0x85, 0x44, 0x96, 0xf3, 0x43, 0x53, + 0x5c, 0x2f, 0xae, 0xf1, 0x4a, 0x72, 0x53, 0xa9, 0xf4, 0x94, 0x2b, 0x81, + 0xe4, 0xd6, 0x8f, 0x4b, 0xac, 0x85, 0x5b, 0xaf, 0x7f, 0x11, 0x4e, 0x41, + 0xbf, 0x1d, 0x98, 0x30, 0x98, 0xc3, 0x89, 0xa3, 0x9d, 0x0b, 0x6c, 0xa7, + 0x77, 0x99, 0xf6, 0x61, 0xb4, 0xeb, 0x3c, 0xac, 0xd3, 0x0f, 0x8f, 0x76, + 0x16, 0x9e, 0x58, 0x67, 0xe2, 0xef, 0x25, 0xc5, 0x7f, 0xbd, 0x53, 0x15, + 0xd3, 0xa4, 0x02, 0x63, 0xf9, 0xd1, 0xc0, 0x68, 0xde, 0xea, 0x69, 0x00, + 0xad, 0xe6, 0x5d, 0xe6, 0x6a, 0xfc, 0x9c, 0x15, 0xf3, 0xfd, 0x22, 0x4f, + 0x2a, 0x46, 0x8a, 0x35, 0x45, 0x4b, 0x7d, 0xa1, 0x83, 0xf3, 0xcc, 0xf1, + 0x47, 0x54, 0x1f, 0x1c, 0x5a, 0x68, 0x96, 0x9c, 0xbd, 0x56, 0x72, 0x2a, + 0xe3, 0x51, 0xd5, 0x01, 0x96, 0xb3, 0x15, 0x7d, 0xdc, 0xf7, 0x43, 0x8a, + 0x8b, 0x78, 0x23, 0xdf, 0x8e, 0x36, 0x73, 0xcd, 0xdb, 0x6b, 0xfa, 0x2b, + 0xeb, 0xb2, 0x09, 0xdb, 0xb2, 0x6a, 0x6b, 0xb2, 0xec, 0xab, 0xad, 0xc5, + 0x9e, 0x92, 0x6b, 0xe4, 0x9b, 0xa2, 0x9f, 0x73, 0x77, 0xbd, 0x9c, 0xfb, + 0xf7, 0xb1, 0x26, 0xd7, 0x96, 0x74, 0x68, 0xa0, 0xa1, 0xe7, 0xc4, 0x64, + 0xf0, 0xe6, 0x72, 0xfe, 0x14, 0xed, 0x85, 0x72, 0xad, 0x1c, 0x63, 0xcf, + 0xc0, 0x17, 0xc9, 0xc1, 0xaf, 0xc8, 0x7a, 0xdf, 0x1f, 0x70, 0xbc, 0x7c, + 0xff, 0x97, 0xec, 0xa9, 0x51, 0xeb, 0xec, 0x56, 0x55, 0x9d, 0xfd, 0x7b, + 0xb8, 0x97, 0x35, 0xf6, 0x6c, 0xa9, 0x0e, 0xbc, 0x5b, 0x47, 0x9c, 0x48, + 0x79, 0x3e, 0x75, 0xbc, 0xea, 0x72, 0x5d, 0x6b, 0xa7, 0xb7, 0x56, 0x10, + 0x7a, 0x7e, 0x7c, 0xd2, 0x9f, 0x73, 0x5c, 0xea, 0x7b, 0x13, 0xb1, 0xa0, + 0xc5, 0x39, 0x46, 0xdf, 0x0f, 0xb9, 0xc7, 0xa1, 0xc7, 0xa9, 0xf3, 0xf9, + 0xde, 0x0e, 0x7c, 0x3d, 0xea, 0x02, 0xea, 0x73, 0xb5, 0x01, 0xf1, 0x1c, + 0x74, 0xfd, 0x70, 0xd1, 0x7c, 0xeb, 0xf5, 0xf5, 0x60, 0x62, 0x3a, 0xa3, + 0xba, 0x01, 0xfe, 0x5e, 0xf1, 0x0d, 0xe6, 0x83, 0x5e, 0x94, 0x40, 0x65, + 0x9d, 0x86, 0xb1, 0x19, 0x6b, 0x1a, 0x4d, 0xd0, 0x0d, 0x22, 0x57, 0xc0, + 0x1b, 0x57, 0xe7, 0xc9, 0xaf, 0xc1, 0x56, 0x13, 0x5f, 0x2d, 0x6e, 0xb7, + 0xa4, 0x55, 0x6b, 0x9f, 0x39, 0x27, 0x42, 0xff, 0x64, 0x30, 0xd9, 0x0b, + 0x3f, 0x5b, 0xb1, 0x07, 0xcc, 0x57, 0x8e, 0x23, 0x1e, 0xab, 0xcc, 0xb1, + 0x40, 0xbe, 0xc6, 0xd8, 0x9f, 0x81, 0x5f, 0xb9, 0x5c, 0xf7, 0xc8, 0x15, + 0x4e, 0x6a, 0x6e, 0x73, 0x76, 0xbe, 0x49, 0x75, 0xec, 0x6c, 0x61, 0x04, + 0xe7, 0x22, 0x9b, 0xad, 0x81, 0x9c, 0xd7, 0x1f, 0x96, 0x42, 0x81, 0x6d, + 0xe9, 0xa8, 0xd3, 0x73, 0xf7, 0x6b, 0x3b, 0xb6, 0xcc, 0xc1, 0x57, 0x2c, + 0x2c, 0x38, 0xf8, 0xef, 0xc2, 0x7f, 0x0f, 0xfe, 0x77, 0xcb, 0xd0, 0x14, + 0xfd, 0x57, 0xd6, 0x72, 0x9a, 0x6a, 0x9e, 0x4f, 0x1f, 0xa9, 0x43, 0x71, + 0x60, 0x39, 0x2f, 0xce, 0xc9, 0x15, 0x6a, 0xe5, 0x84, 0x79, 0x52, 0x5f, + 0x47, 0x30, 0x5f, 0xea, 0xd7, 0xfa, 0x2a, 0x6b, 0x58, 0x96, 0x57, 0xf7, + 0x22, 0x4f, 0x37, 0xca, 0xa1, 0x82, 0x5f, 0xbb, 0x8a, 0xc9, 0xa3, 0xe5, + 0xda, 0x95, 0xa4, 0x83, 0x03, 0xb7, 0x1e, 0xcc, 0x4c, 0x2a, 0x9e, 0xc0, + 0xb2, 0x06, 0xae, 0x3d, 0x38, 0xb1, 0xf0, 0xee, 0x83, 0xcb, 0x98, 0x70, + 0x8c, 0x2d, 0xac, 0x84, 0x19, 0x22, 0x96, 0xee, 0x33, 0xf2, 0x10, 0x0d, + 0x27, 0xf6, 0xed, 0xc7, 0x3c, 0xc4, 0xd9, 0x6d, 0xb0, 0x97, 0xf1, 0xcb, + 0x7e, 0x3c, 0x4a, 0x1c, 0x29, 0xef, 0xab, 0xc4, 0x7e, 0x84, 0x70, 0xfe, + 0x12, 0xb0, 0x9c, 0x2c, 0xf6, 0x71, 0xa1, 0xdd, 0xf8, 0x81, 0xc4, 0x99, + 0x26, 0x2a, 0xb0, 0x47, 0x3e, 0xd6, 0xf4, 0x65, 0xac, 0x95, 0x96, 0xdf, + 0x14, 0x1f, 0x96, 0x5f, 0x16, 0x47, 0x21, 0xdf, 0x13, 0x58, 0xf3, 0x80, + 0xfc, 0xa2, 0xb8, 0x4f, 0xde, 0x2a, 0x8e, 0xc9, 0x9b, 0xc5, 0xdd, 0x88, + 0xa9, 0x46, 0x88, 0xf5, 0xf4, 0xb0, 0xd2, 0x83, 0x32, 0x7e, 0x4e, 0x31, + 0x80, 0x37, 0xe9, 0xf7, 0x1c, 0x55, 0x3f, 0x9b, 0xf8, 0xfa, 0xc4, 0xaf, + 0x18, 0xcf, 0x13, 0x9b, 0x59, 0x28, 0xfa, 0x18, 0x8e, 0x89, 0x0e, 0x3c, + 0xdb, 0xe6, 0xb7, 0x29, 0xc3, 0xe7, 0x22, 0x81, 0x91, 0x73, 0xa1, 0xc0, + 0x03, 0xfa, 0x9d, 0x0b, 0xeb, 0x9d, 0x25, 0x39, 0xe9, 0x3a, 0xe4, 0xcd, + 0xfe, 0x61, 0xc8, 0xc2, 0x08, 0x54, 0xfd, 0x2e, 0x67, 0xad, 0x80, 0xa4, + 0xa9, 0x4f, 0xe0, 0x67, 0x26, 0x4f, 0xbb, 0x92, 0xc9, 0xcf, 0x05, 0x0c, + 0x1e, 0xcd, 0x46, 0xbb, 0x07, 0xed, 0x57, 0xbd, 0xf6, 0x0e, 0xc9, 0xcc, + 0x48, 0xea, 0x43, 0xf5, 0x87, 0x5f, 0xf1, 0xfa, 0xfa, 0xd1, 0x07, 0xce, + 0xbc, 0xc0, 0xbe, 0x0b, 0x5e, 0x1f, 0xcf, 0x84, 0xb5, 0xfa, 0xb8, 0xf2, + 0x55, 0xc6, 0x1e, 0x13, 0xfd, 0xae, 0x41, 0x6b, 0xf1, 0x4b, 0xed, 0x46, + 0xb7, 0x11, 0x13, 0xf8, 0x8f, 0x76, 0xc6, 0x60, 0x05, 0xc8, 0xd7, 0x5d, + 0xd0, 0x89, 0x7f, 0xd9, 0xbc, 0xdc, 0xb6, 0x06, 0x3e, 0xad, 0xc0, 0x68, + 0x7f, 0x2a, 0x9d, 0x0b, 0xff, 0xf2, 0xf0, 0xbc, 0x07, 0xf1, 0x6e, 0x38, + 0xab, 0x3c, 0x71, 0xe3, 0x71, 0xc8, 0x76, 0x93, 0xac, 0x3d, 0x43, 0x7a, + 0x75, 0x43, 0x57, 0xa7, 0x20, 0xb7, 0xae, 0xcc, 0x17, 0x43, 0x81, 0xe1, + 0x7c, 0x4a, 0x0c, 0x9e, 0xda, 0x92, 0x74, 0x34, 0x25, 0xa7, 0xfa, 0x12, + 0x5d, 0xcc, 0x43, 0x66, 0x7a, 0x5d, 0xb9, 0x58, 0xa4, 0x3d, 0xce, 0xca, + 0xa5, 0xbe, 0x84, 0x5b, 0x10, 0xe2, 0x62, 0x5c, 0xb9, 0x04, 0xd9, 0xfc, + 0xdd, 0xb9, 0xdd, 0xf2, 0x68, 0x5e, 0xfd, 0xe0, 0xee, 0xb0, 0xbc, 0x20, + 0x17, 0xfb, 0x5e, 0xb8, 0x79, 0xd1, 0x7d, 0x04, 0x67, 0x4a, 0x3e, 0xcc, + 0x74, 0x98, 0x7d, 0x2b, 0x0e, 0x49, 0x98, 0x0f, 0xd1, 0x9a, 0x9a, 0x53, + 0x2f, 0x43, 0xfb, 0x23, 0x5e, 0x5c, 0x0e, 0x9f, 0x3b, 0xe0, 0x9a, 0x7a, + 0x4a, 0xc0, 0xdf, 0x67, 0x18, 0x7e, 0x0c, 0xef, 0xf3, 0x69, 0xe3, 0xaf, + 0xd3, 0x1e, 0x18, 0x9a, 0x69, 0x96, 0xd0, 0x85, 0xaf, 0x80, 0xae, 0x21, + 0x39, 0xd8, 0x5b, 0x2a, 0x7d, 0xc7, 0x0d, 0xc5, 0x27, 0x10, 0xa3, 0x60, + 0xff, 0xb2, 0xe6, 0x74, 0x0b, 0x68, 0xd2, 0x20, 0xd1, 0xd3, 0xfe, 0xf3, + 0xea, 0x3d, 0x2c, 0xc3, 0x99, 0x35, 0xc6, 0x96, 0xf9, 0xd8, 0x06, 0x7f, + 0x3d, 0x83, 0x29, 0xeb, 0xb4, 0x7a, 0x03, 0xde, 0x77, 0x12, 0x5e, 0x7b, + 0x6b, 0xe0, 0xfe, 0x50, 0xab, 0x84, 0x9c, 0x67, 0xd7, 0x13, 0x1b, 0xb9, + 0x98, 0xf7, 0xfb, 0xe1, 0x27, 0x86, 0x7c, 0x7f, 0x58, 0xb6, 0x2d, 0x9f, + 0xb5, 0x6c, 0xeb, 0x5c, 0xf8, 0xae, 0xb7, 0x66, 0xca, 0x9b, 0x8b, 0x98, + 0x23, 0xb6, 0x5a, 0xed, 0x93, 0x99, 0xfb, 0x5f, 0x79, 0xba, 0x37, 0xf1, + 0x9a, 0xe2, 0x64, 0xcb, 0xf7, 0x70, 0x1c, 0x31, 0x64, 0x51, 0xef, 0x89, + 0xed, 0x01, 0x7d, 0xd3, 0xb1, 0x7b, 0xec, 0x39, 0x2b, 0x18, 0x30, 0xfe, + 0x48, 0x9d, 0xfc, 0x28, 0x0a, 0xbb, 0xcd, 0x6f, 0x58, 0x98, 0xff, 0x72, + 0x6f, 0x7b, 0x7e, 0x0a, 0xfb, 0x12, 0x2f, 0x26, 0xad, 0x34, 0xf6, 0xc7, + 0x33, 0x20, 0x06, 0xd4, 0x02, 0x9d, 0xda, 0xf1, 0x7e, 0x88, 0x9f, 0x7a, + 0xfd, 0xf7, 0x5f, 0x03, 0x1d, 0xc6, 0xfd, 0x1b, 0x5c, 0x98, 0x58, 0xcc, + 0x85, 0x0c, 0x7a, 0x18, 0xd8, 0x4a, 0xb9, 0xf5, 0xb1, 0xb1, 0x3e, 0x9e, + 0x8e, 0x18, 0xa5, 0x18, 0xfc, 0x40, 0xca, 0x04, 0x79, 0xb3, 0x0d, 0xfd, + 0xab, 0x6e, 0xa5, 0xf4, 0xd5, 0xfd, 0xbe, 0x8f, 0xcb, 0xd8, 0xee, 0x89, + 0xfc, 0x3e, 0x83, 0xcd, 0xb3, 0x96, 0x24, 0xd5, 0x91, 0xb4, 0x4f, 0x62, + 0xbf, 0x43, 0xa1, 0x44, 0x21, 0x2b, 0x31, 0x99, 0x83, 0xbe, 0xb8, 0x0a, + 0xd9, 0x7f, 0xab, 0xc8, 0xef, 0x6d, 0x53, 0x72, 0x28, 0x0f, 0x83, 0x3e, + 0xa3, 0xdf, 0x7e, 0x41, 0xef, 0x0f, 0xc8, 0x6c, 0x3e, 0xd1, 0x35, 0x07, + 0xfe, 0x9b, 0xcb, 0x13, 0x5f, 0xd4, 0x1d, 0x1f, 0xc1, 0x8a, 0x8b, 0xf9, + 0x8d, 0xb0, 0x0f, 0x92, 0xba, 0x08, 0xff, 0xe7, 0x62, 0xb1, 0x0b, 0x7c, + 0x86, 0xf1, 0xa2, 0x83, 0x5f, 0xe8, 0xcc, 0x62, 0x1f, 0xe4, 0x9c, 0x7b, + 0xb1, 0x65, 0x7e, 0x33, 0xce, 0x8e, 0x38, 0x22, 0xc5, 0x8f, 0x7f, 0x86, + 0xf3, 0xf5, 0xdf, 0x7b, 0xbb, 0xda, 0xe9, 0x39, 0xdd, 0x17, 0xec, 0x32, + 0x62, 0x80, 0x4c, 0xaf, 0xb1, 0xdb, 0x43, 0x91, 0x16, 0x19, 0xba, 0x87, + 0x76, 0xbc, 0x55, 0x63, 0x44, 0xe5, 0xc5, 0x08, 0xc7, 0x7f, 0xbb, 0xde, + 0xd0, 0x2f, 0x5c, 0xd3, 0x7e, 0x1b, 0xbf, 0xcd, 0xd2, 0xe6, 0xf0, 0xd7, + 0xc6, 0xef, 0xb5, 0xf5, 0xac, 0xef, 0xb6, 0x39, 0x49, 0x3c, 0xeb, 0xd7, + 0x5e, 0xbe, 0x00, 0xd7, 0x73, 0xbc, 0x67, 0x9d, 0xf7, 0x5c, 0xae, 0xdb, + 0x8c, 0x75, 0x9a, 0xbc, 0x67, 0x35, 0x6b, 0x7e, 0xd2, 0x3c, 0x0b, 0x31, + 0x6e, 0xfe, 0x4f, 0xeb, 0x79, 0x86, 0xfc, 0xde, 0xb8, 0xba, 0xfd, 0xc7, + 0xf5, 0xc4, 0xcd, 0xb5, 0x39, 0xcd, 0x8a, 0xf1, 0xbc, 0xd1, 0xda, 0x8a, + 0x6b, 0x3e, 0x93, 0x73, 0x4c, 0x3e, 0x7c, 0xb6, 0xc8, 0xf5, 0xd9, 0x4e, + 0xc9, 0x31, 0xcd, 0x67, 0x18, 0x2c, 0xdf, 0x6c, 0xfe, 0x3e, 0x99, 0x38, + 0xa7, 0xf8, 0xba, 0xe9, 0x9c, 0xc5, 0xef, 0x5e, 0xf8, 0xbd, 0x1c, 0x7d, + 0x89, 0x51, 0x19, 0xc7, 0xf9, 0x5d, 0x82, 0x4f, 0xb5, 0x68, 0xbe, 0x8b, + 0xc5, 0xdf, 0x01, 0x9c, 0x4b, 0x08, 0x32, 0x46, 0x19, 0xa5, 0x4c, 0xe1, + 0xfc, 0xc6, 0x6c, 0x79, 0xaf, 0x8f, 0xf2, 0xdc, 0x27, 0x97, 0xcb, 0xf2, + 0x9c, 0x85, 0x3c, 0x53, 0x96, 0xb3, 0x90, 0x69, 0xc3, 0xd7, 0xfb, 0x11, + 0x63, 0xa4, 0x62, 0xb0, 0x57, 0xea, 0x43, 0xbc, 0x0c, 0xbe, 0xb6, 0xbd, + 0x6f, 0xa5, 0x02, 0x9a, 0xc3, 0xc9, 0xcc, 0xd4, 0x79, 0xdf, 0x01, 0xe0, + 0xfa, 0xf2, 0x73, 0x32, 0x34, 0xd3, 0x88, 0x7d, 0x6f, 0xe8, 0xe0, 0x99, + 0x65, 0x2e, 0xf3, 0xdf, 0xe7, 0x45, 0xe2, 0x4d, 0xe9, 0xcf, 0xf2, 0x9a, + 0x71, 0xde, 0x7a, 0xcc, 0xe9, 0x07, 0x9d, 0x1b, 0xb1, 0x3e, 0xf7, 0xb8, + 0xd2, 0x3c, 0x8e, 0x87, 0x2a, 0xf0, 0xa9, 0x3e, 0xbd, 0x57, 0xeb, 0x33, + 0x33, 0xbd, 0x8d, 0xde, 0xfb, 0xf1, 0x1c, 0xc8, 0xf7, 0x31, 0xf0, 0x2d, + 0x7d, 0x62, 0xf2, 0x4b, 0x4a, 0xcf, 0x61, 0x36, 0x4f, 0xfe, 0x0d, 0x69, + 0x0e, 0x23, 0x03, 0xdb, 0xb2, 0x57, 0xe7, 0xc7, 0x96, 0xe5, 0xbb, 0x23, + 0xa0, 0x71, 0x77, 0x26, 0xbf, 0x4a, 0x3a, 0x55, 0x07, 0x75, 0x78, 0xbc, + 0x0d, 0x7b, 0xa1, 0x58, 0xee, 0x03, 0x72, 0xb4, 0xd8, 0x0f, 0x3a, 0xc4, + 0xe4, 0x29, 0xf8, 0xcd, 0xcf, 0x14, 0xef, 0x90, 0xa5, 0x08, 0xf6, 0x55, + 0x96, 0xb1, 0x41, 0xf9, 0xf1, 0xdc, 0x06, 0xef, 0x3a, 0xe1, 0x2e, 0x59, + 0xdb, 0xb1, 0x07, 0xca, 0x13, 0xe5, 0x8a, 0xf3, 0x82, 0x88, 0x45, 0xb8, + 0xee, 0x11, 0xa3, 0xdb, 0xb0, 0x6e, 0x21, 0x42, 0xf9, 0xe5, 0xde, 0x42, + 0x9e, 0xcc, 0x32, 0xae, 0xe2, 0x3b, 0x1b, 0x9b, 0x94, 0xae, 0x3a, 0x8b, + 0x84, 0xe2, 0x40, 0x97, 0xcf, 0xc0, 0x5f, 0xc7, 0x97, 0x4b, 0xff, 0x3b, + 0x0a, 0xea, 0x51, 0xd8, 0xca, 0x3c, 0x6c, 0x65, 0x1e, 0x36, 0x12, 0xb2, + 0xf0, 0x56, 0x1e, 0x36, 0x32, 0x0f, 0x1b, 0x09, 0x7d, 0xf6, 0x06, 0x62, + 0xbb, 0xab, 0xe0, 0x21, 0xe3, 0x6b, 0x1f, 0xa6, 0xaf, 0x8d, 0xbf, 0xff, + 0x01, 0x88, 0x97, 0xee, 0xe9, 0xc4, 0x71, 0x00, 0x00, 0x00 }; -static u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_RXP_b06FwRodata[(0x278/4) + 1] = { - 0x08003fdc, 0x08003edc, 0x08003f80, 0x08003f98, 0x08003fb0, 0x08003fd0, - 0x08003fdc, 0x08003fdc, 0x08003ee4, 0x00000000, 0x08004a04, 0x08004a3c, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004a74, 0x08004c38, - 0x08004b80, 0x08004bb8, 0x08004c38, 0x08004b08, 0x08004c38, 0x08004c38, - 0x08004bb8, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004bf8, - 0x08004c38, 0x08004bf8, 0x08004b80, 0x08004c38, 0x08004c38, 0x08004bf8, - 0x08004bf8, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, 0x08004c38, - 0x08004ae4, 0x00000000, 0x08006018, 0x08006030, 0x08006030, 0x08006030, - 0x08006018, 0x08006030, 0x08006030, 0x08006030, 0x08006018, 0x08006030, - 0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030, - 0x08006024, 0x00000000, 0x00000000 }; +static const u32 bnx2_RXP_b06FwData[(0x0/4) + 1] = { 0x0 }; +static const u32 bnx2_RXP_b06FwRodata[(0x24/4) + 1] = { + 0x08004580, 0x08004580, 0x080044f8, 0x08004530, 0x08004564, 0x08004588, + 0x08004588, 0x08004588, 0x08004468, 0x00000000 }; static struct fw_info bnx2_rxp_fw_06 = { - .ver_major = 0x2, - .ver_minor = 0x8, - .ver_fix = 0x17, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x08003184, + .start_addr = 0x080031d0, .text_addr = 0x08000000, - .text_len = 0x6728, + .text_len = 0x71c0, .text_index = 0x0, .gz_text = bnx2_RXP_b06FwText, .gz_text_len = sizeof(bnx2_RXP_b06FwText), - .data_addr = 0x080069c0, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_RXP_b06FwData, - .sbss_addr = 0x080069c0, - .sbss_len = 0x2c, + .sbss_addr = 0x08007200, + .sbss_len = 0x58, .sbss_index = 0x0, - .bss_addr = 0x080069f0, - .bss_len = 0x13dc, + .bss_addr = 0x08007258, + .bss_len = 0x44c, .bss_index = 0x0, - .rodata_addr = 0x08006728, - .rodata_len = 0x278, + .rodata_addr = 0x080071c0, + .rodata_len = 0x24, .rodata_index = 0x0, .rodata = bnx2_RXP_b06FwRodata, }; static u8 bnx2_rv2p_proc1[] = { -/* 0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ - 0xc5, 0x56, 0xcf, 0x6b, - 0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b, - 0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82, - 0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a, - 0xfe, 0x1b, 0xa1, 0x3f, 0xd2, 0x4b, 0x10, 0x7a, 0xb0, 0x58, 0xf1, 0x50, - 0x10, 0x2a, 0x68, 0x0f, 0xc9, 0xa1, 0x20, 0x52, 0x11, 0xda, 0x8b, 0x07, - 0x2f, 0x42, 0x0f, 0x7a, 0x69, 0xbd, 0xa8, 0xff, 0x82, 0x08, 0x4d, 0x7c, - 0x6f, 0x66, 0x9e, 0xee, 0x6e, 0xb2, 0x4d, 0x15, 0xc1, 0x85, 0xf6, 0xe3, - 0xbd, 0x9d, 0x79, 0x33, 0xf3, 0xcd, 0x37, 0xfb, 0x62, 0x01, 0x40, 0x04, - 0x60, 0xcd, 0x46, 0x2c, 0x8d, 0x26, 0x04, 0x1a, 0x30, 0x7e, 0x52, 0x62, - 0x16, 0xde, 0xa6, 0x25, 0x4e, 0x44, 0xc6, 0xd3, 0x49, 0x81, 0x7b, 0x0d, - 0x28, 0xc9, 0x75, 0x4f, 0xf5, 0x55, 0xad, 0x53, 0xa0, 0x06, 0xbb, 0xa3, - 0x80, 0xcf, 0x47, 0x9d, 0xf0, 0x7c, 0xd6, 0x42, 0x2c, 0x31, 0xc2, 0x48, - 0x02, 0x61, 0x7b, 0x51, 0xae, 0xad, 0x48, 0x69, 0xc4, 0x42, 0x3f, 0xd0, - 0x68, 0x7f, 0x67, 0xd1, 0x15, 0xff, 0x53, 0xf0, 0x39, 0x2f, 0xd7, 0x56, - 0x7c, 0x0e, 0xed, 0xaa, 0xec, 0x2f, 0xfe, 0xd0, 0xfe, 0xba, 0xf0, 0x03, - 0x7e, 0x94, 0x5f, 0x02, 0xcf, 0x29, 0x66, 0x65, 0x5e, 0xdd, 0x22, 0xa0, - 0xca, 0xc7, 0x46, 0x2c, 0xf5, 0x91, 0xb5, 0x89, 0xef, 0xbf, 0x8a, 0xbc, - 0x55, 0xdc, 0x76, 0xf1, 0x82, 0xf9, 0x06, 0xe3, 0x26, 0x91, 0x1f, 0x28, - 0xf9, 0xe3, 0x00, 0xc8, 0xfd, 0x4f, 0x8d, 0x5f, 0xfb, 0x83, 0xfe, 0xf7, - 0xbb, 0x43, 0xf2, 0xbc, 0x28, 0xc0, 0x90, 0xb4, 0xdb, 0xe6, 0x7c, 0xc6, - 0xe0, 0xb4, 0x96, 0xc4, 0xf7, 0x06, 0xfa, 0x1f, 0x11, 0xe7, 0x4a, 0xec, - 0x61, 0x3c, 0xce, 0x78, 0x95, 0xb1, 0xc2, 0xe8, 0x32, 0x3a, 0x8c, 0x5d, - 0x8c, 0x36, 0xe3, 0x26, 0x63, 0x9c, 0xb1, 0x83, 0xd1, 0x62, 0xdc, 0x63, - 0x8c, 0x31, 0x46, 0x19, 0x1b, 0x8c, 0x46, 0x84, 0x50, 0xe3, 0xf5, 0x63, - 0x46, 0xe0, 0xba, 0x23, 0x81, 0xba, 0x5f, 0xb3, 0x2e, 0x24, 0x6f, 0xfc, - 0x7e, 0x50, 0xd9, 0x31, 0xef, 0x58, 0xf7, 0x3a, 0xdb, 0x75, 0x57, 0x57, - 0x02, 0xfa, 0x49, 0xef, 0xab, 0x9b, 0x54, 0x8b, 0x3e, 0xb8, 0x58, 0xcf, - 0x9d, 0x82, 0x8b, 0x71, 0x9c, 0x18, 0xed, 0xab, 0xb4, 0x6e, 0xb8, 0x84, - 0xf7, 0xe2, 0x84, 0x5f, 0x18, 0xef, 0x77, 0x12, 0x4e, 0x77, 0xc9, 0x7c, - 0x0e, 0x8b, 0x80, 0xea, 0x1c, 0x95, 0x4f, 0xbb, 0x3c, 0xc2, 0xe2, 0xa9, - 0xbc, 0xda, 0xc5, 0x25, 0x2c, 0x6a, 0xfe, 0xfa, 0x9f, 0x8c, 0x11, 0x1a, - 0x39, 0x22, 0x75, 0xc9, 0x16, 0x3d, 0x83, 0x46, 0x63, 0xd9, 0x36, 0xe4, - 0xfa, 0xdc, 0xf2, 0x7b, 0xd4, 0xfb, 0xd9, 0xa5, 0x1a, 0xe7, 0xe7, 0x2a, - 0x9e, 0x69, 0x0e, 0x32, 0x40, 0xeb, 0x49, 0xe4, 0x1d, 0x04, 0x5a, 0xb8, - 0x86, 0x8c, 0xbf, 0x5f, 0xa4, 0x43, 0x9d, 0xfb, 0x31, 0xcb, 0xfd, 0x38, - 0x11, 0xd2, 0x8f, 0xb0, 0xb9, 0x68, 0x9e, 0xc7, 0xdb, 0xe9, 0x20, 0x6f, - 0x61, 0xf3, 0xa3, 0xf8, 0xa6, 0xdd, 0x3f, 0xe5, 0xf1, 0x01, 0xf3, 0x58, - 0x24, 0x1e, 0x93, 0xdf, 0x5a, 0xf2, 0x94, 0xf6, 0xf0, 0x24, 0xeb, 0xec, - 0x0d, 0xe9, 0x73, 0x58, 0x7d, 0xd9, 0xbf, 0xee, 0x73, 0x20, 0x3f, 0xb8, - 0x8b, 0xdf, 0x9b, 0x04, 0x14, 0x0b, 0x2a, 0x5f, 0x3f, 0xcf, 0xc7, 0xa8, - 0xdf, 0x30, 0x97, 0x93, 0xfb, 0x62, 0xfe, 0x36, 0x35, 0x5c, 0x1b, 0xf9, - 0x88, 0x04, 0xab, 0x98, 0x23, 0x7f, 0x47, 0xd3, 0x78, 0x7d, 0x50, 0x5d, - 0xa8, 0xbe, 0x4b, 0x8c, 0x41, 0x7e, 0x9a, 0xeb, 0xcc, 0x50, 0x3c, 0xd2, - 0x81, 0xc1, 0x3a, 0xc8, 0xf3, 0xf7, 0x28, 0xc8, 0x87, 0x55, 0x5d, 0x59, - 0xf4, 0xce, 0x75, 0x12, 0x8a, 0x39, 0xd2, 0x55, 0x73, 0x5f, 0x59, 0x6f, - 0x6b, 0xea, 0xbb, 0x84, 0xdb, 0xd5, 0x92, 0xee, 0xab, 0xf7, 0x12, 0x64, - 0xbd, 0x3c, 0x47, 0x5a, 0xe8, 0xa3, 0x5d, 0x1c, 0xdf, 0x79, 0x0e, 0x64, - 0x5b, 0x7d, 0x6f, 0x4c, 0xae, 0xeb, 0x0c, 0xeb, 0xfb, 0x68, 0x93, 0xbe, - 0xd5, 0x7d, 0xf5, 0xef, 0x74, 0xce, 0xf5, 0x9b, 0x68, 0x97, 0xda, 0x59, - 0xf7, 0xde, 0x4f, 0x71, 0xcf, 0xfd, 0x44, 0x6e, 0xa6, 0xca, 0xbb, 0xcf, - 0x7b, 0xaf, 0x1c, 0x0a, 0xe9, 0x83, 0xf7, 0x3e, 0x0a, 0xd6, 0xeb, 0xd7, - 0x23, 0xf5, 0x35, 0xce, 0xf5, 0x9b, 0x0d, 0xee, 0xc3, 0x54, 0xff, 0x0c, - 0xe9, 0x3f, 0x53, 0x90, 0xfa, 0x71, 0xc1, 0x31, 0xe9, 0x7c, 0x42, 0x71, - 0x8e, 0x66, 0x62, 0xde, 0xf3, 0x1a, 0xad, 0xe7, 0x67, 0xd0, 0x2f, 0x3e, - 0xa7, 0xf6, 0xf3, 0x48, 0xd8, 0xe4, 0x8b, 0x2d, 0xe2, 0xbd, 0xa6, 0xab, - 0xb9, 0x70, 0x91, 0xef, 0x01, 0x97, 0xec, 0xcc, 0x2b, 0x8a, 0x2f, 0xb9, - 0xaf, 0xc3, 0x12, 0xcd, 0xc5, 0xad, 0x47, 0x84, 0x37, 0xe1, 0x32, 0x9d, - 0xfb, 0xfb, 0xfb, 0x66, 0x21, 0x42, 0x97, 0x57, 0xc7, 0x51, 0xa1, 0x63, - 0x9c, 0x63, 0x25, 0x57, 0x78, 0xae, 0x11, 0x9f, 0xf3, 0xa4, 0x73, 0x8d, - 0xf3, 0xc3, 0xab, 0x45, 0x3e, 0xab, 0xba, 0xac, 0xf7, 0x9a, 0xd2, 0x1d, - 0x0c, 0x9b, 0x38, 0x3f, 0xa9, 0xca, 0x02, 0x2e, 0x7b, 0x1d, 0x46, 0xbb, - 0x4c, 0x18, 0xc3, 0xfc, 0x75, 0x78, 0x58, 0x93, 0x7e, 0x05, 0xbe, 0xdf, - 0x7e, 0xb0, 0x5e, 0x74, 0xa8, 0xf0, 0xef, 0x8b, 0x05, 0x7c, 0x3f, 0x01, - 0xcd, 0xf7, 0x1b, 0xc5, 0x29, 0x0f, 0x11, 0xda, 0xa7, 0xb8, 0xaf, 0xc3, - 0xd2, 0xce, 0x11, 0x7e, 0xdc, 0x3f, 0xec, 0xc3, 0x05, 0x8f, 0x3f, 0x42, - 0xe5, 0xc3, 0x40, 0x98, 0xbf, 0xb4, 0xff, 0xde, 0xe2, 0x3e, 0xa5, 0xf7, - 0x2f, 0xc9, 0x7e, 0xaa, 0xff, 0x19, 0xd7, 0x3f, 0xec, 0xd5, 0xbd, 0x8a, - 0xf7, 0xae, 0xbe, 0xff, 0x7d, 0xdc, 0xc1, 0x76, 0x5b, 0xfb, 0xd8, 0xd1, - 0xf1, 0xf9, 0x41, 0xef, 0xfd, 0xfd, 0xa6, 0x4e, 0x3c, 0x6d, 0xd4, 0xd5, - 0x5c, 0x6d, 0x84, 0xcc, 0xd5, 0xc5, 0xff, 0x3a, 0x57, 0x10, 0x98, 0xab, - 0xd5, 0xfa, 0xc1, 0xe6, 0x0a, 0xb8, 0x7e, 0x08, 0x99, 0xab, 0x18, 0xf3, - 0xf0, 0x94, 0xcf, 0x33, 0x20, 0xaa, 0xc7, 0xb0, 0x7d, 0xc6, 0x2c, 0xeb, - 0x92, 0xf4, 0x68, 0x47, 0xcb, 0xa8, 0x3f, 0xc7, 0x2e, 0x93, 0x9d, 0x41, - 0xfb, 0x49, 0x85, 0x0b, 0xb3, 0xf4, 0x7b, 0x4a, 0x83, 0x9f, 0x94, 0x15, - 0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 }; + /* Date: 12/07/2007 14:57 */ + 0xd5, 0x56, 0x41, 0x6b, 0x13, 0x51, 0x10, 0x9e, 0xdd, 0x6c, 0xbb, 0xdb, + 0x64, 0xb3, 0x59, 0xaa, 0xd6, 0x50, 0x53, 0x93, 0x06, 0x2f, 0xad, 0x29, + 0x6d, 0xaa, 0x82, 0x42, 0xa1, 0x92, 0x4b, 0xc1, 0xf6, 0x20, 0xf5, 0x22, + 0x22, 0xd8, 0x46, 0xd1, 0x5f, 0x21, 0x06, 0xdb, 0xd4, 0x73, 0x05, 0x0b, + 0xf5, 0xa0, 0x3d, 0x59, 0x11, 0xc1, 0x04, 0x14, 0x44, 0x04, 0x41, 0x45, + 0x04, 0x3d, 0x78, 0xa8, 0x60, 0x2f, 0xad, 0x22, 0x56, 0x3c, 0x78, 0xd4, + 0x93, 0x26, 0xbe, 0x37, 0x33, 0xaf, 0xdd, 0xdd, 0x66, 0x9b, 0x2a, 0x82, + 0x18, 0x68, 0x3f, 0xde, 0xec, 0xbc, 0x37, 0x33, 0xdf, 0xcc, 0x9b, 0x79, + 0x2e, 0x00, 0xe8, 0x50, 0xaa, 0xa6, 0x05, 0x82, 0xa5, 0x69, 0x96, 0x00, + 0x0d, 0xe0, 0xae, 0x8d, 0x58, 0xea, 0x77, 0x05, 0xda, 0xda, 0x70, 0x46, + 0x62, 0x04, 0x86, 0xbb, 0x25, 0xee, 0x87, 0x27, 0x99, 0xa4, 0xc0, 0x9f, + 0x75, 0x28, 0xc9, 0xf5, 0xee, 0xca, 0xc3, 0x6a, 0x0c, 0xcf, 0x59, 0xed, + 0x07, 0xfc, 0xbd, 0x8b, 0x10, 0x1e, 0xce, 0x59, 0x88, 0x25, 0x46, 0xe8, + 0x73, 0x11, 0x96, 0x66, 0x2d, 0x34, 0x57, 0xea, 0xb3, 0x70, 0x1f, 0xe8, + 0x24, 0x5f, 0x99, 0x4d, 0x88, 0xff, 0x29, 0x78, 0x5f, 0x90, 0x6b, 0x2b, + 0x3a, 0x8d, 0x7a, 0x15, 0xde, 0x2f, 0xfe, 0x50, 0xff, 0xb8, 0xd8, 0x07, + 0xfc, 0x53, 0xfb, 0x5c, 0x3c, 0xa7, 0x98, 0x93, 0x7e, 0xb5, 0x0b, 0x83, + 0xca, 0x1f, 0x9b, 0xe2, 0x4b, 0x93, 0xb6, 0x89, 0xdf, 0xd7, 0x84, 0xdf, + 0xca, 0x6e, 0x33, 0x7b, 0x41, 0x7f, 0x83, 0x76, 0xe5, 0x79, 0x86, 0xb0, + 0xe7, 0xb7, 0x03, 0x20, 0xe5, 0xcb, 0xf5, 0x75, 0x79, 0x8f, 0xff, 0xfb, + 0x6a, 0xaf, 0x3c, 0xaf, 0x05, 0xa0, 0x57, 0xea, 0x2d, 0xb1, 0x3f, 0x83, + 0xb0, 0x4f, 0x4f, 0xe2, 0x77, 0x03, 0xf7, 0xef, 0x11, 0xe7, 0x4a, 0xec, + 0x62, 0xec, 0x66, 0x1c, 0x67, 0xbc, 0xca, 0xb8, 0x8b, 0x71, 0x27, 0xe3, + 0x0e, 0xc6, 0x76, 0xc6, 0x97, 0x8c, 0x2e, 0x63, 0x82, 0xd1, 0x61, 0x7c, + 0xce, 0x68, 0x33, 0xc6, 0x18, 0x5f, 0x30, 0xbe, 0x62, 0xb4, 0x18, 0x6f, + 0x30, 0x7e, 0x61, 0xfc, 0xaa, 0xfc, 0xd0, 0x08, 0x1f, 0xf1, 0xfa, 0x10, + 0xaf, 0x8f, 0x30, 0x02, 0xf3, 0xa4, 0x05, 0x78, 0xba, 0xcf, 0x75, 0x24, + 0x79, 0xe6, 0xef, 0x3d, 0x4a, 0x8f, 0xf3, 0x84, 0x3c, 0xdd, 0x63, 0xbd, + 0xf6, 0xca, 0x42, 0xa0, 0xde, 0x32, 0x5b, 0xd6, 0x59, 0xaa, 0x41, 0xde, + 0x12, 0x18, 0xcf, 0xc4, 0x48, 0x02, 0xed, 0x38, 0xad, 0x24, 0x57, 0x6e, + 0x9d, 0x4c, 0x10, 0x9e, 0x8b, 0x12, 0x7e, 0x62, 0x3c, 0x1f, 0x23, 0x9c, + 0x8c, 0x2b, 0x9e, 0xd5, 0x39, 0xca, 0x9f, 0x66, 0x7e, 0x84, 0xd9, 0x53, + 0x7e, 0x35, 0xb3, 0x4b, 0x58, 0xd4, 0xfd, 0xf1, 0x5f, 0x1f, 0x20, 0x34, + 0xf2, 0x44, 0xea, 0x9c, 0xdd, 0x26, 0xa0, 0x5e, 0x9f, 0xb7, 0x0d, 0xb9, + 0x3e, 0x38, 0xff, 0x1a, 0xef, 0xc7, 0xe0, 0x5c, 0x95, 0xfd, 0x4b, 0x28, + 0x9e, 0xe9, 0xde, 0x64, 0x81, 0xd6, 0xe3, 0xc8, 0xbb, 0xa8, 0xb0, 0x1e, + 0xee, 0x03, 0x59, 0x7f, 0xbe, 0xa8, 0x6e, 0x23, 0x9c, 0x8f, 0x8b, 0x9c, + 0x8f, 0xae, 0x90, 0x7c, 0x84, 0xdd, 0xa3, 0xcd, 0xf7, 0xf7, 0x4c, 0x26, + 0xc8, 0x5b, 0xd8, 0x7d, 0x53, 0x7c, 0x93, 0xf4, 0x77, 0x79, 0xbc, 0xc0, + 0x3c, 0x16, 0x89, 0xc7, 0xe4, 0xe7, 0x86, 0x3c, 0x65, 0x3c, 0x3c, 0xc9, + 0x38, 0xf7, 0x86, 0xe4, 0x39, 0x2c, 0xbe, 0xdc, 0x1f, 0xe7, 0x39, 0xe0, + 0x1f, 0x9c, 0xc5, 0xfe, 0xe4, 0x42, 0x71, 0x44, 0xf9, 0xeb, 0xe7, 0xb9, + 0x93, 0xf2, 0x0d, 0xd3, 0x79, 0x29, 0xaf, 0x03, 0x3c, 0xd5, 0x71, 0x6d, + 0x14, 0x34, 0x09, 0x56, 0x31, 0x4f, 0xfb, 0x1d, 0x5d, 0xe7, 0xf5, 0x76, + 0xeb, 0x42, 0xe5, 0x5d, 0x62, 0x2b, 0x14, 0x26, 0x39, 0xce, 0x2c, 0xd9, + 0xa3, 0x3a, 0x30, 0xb8, 0x0e, 0x86, 0xb8, 0x7f, 0x05, 0xf9, 0xb0, 0x2a, + 0x0b, 0xb3, 0xde, 0x7b, 0x9d, 0x84, 0x62, 0x9e, 0xea, 0x6a, 0x73, 0x5e, + 0xd5, 0xdc, 0x51, 0x7d, 0x09, 0xc5, 0x95, 0x52, 0xc4, 0x17, 0xef, 0x51, + 0xc8, 0x79, 0x79, 0xd6, 0x1a, 0xd4, 0x47, 0x33, 0x3b, 0xbe, 0xf3, 0x1c, + 0xc8, 0x35, 0xea, 0x37, 0x26, 0xc7, 0xd5, 0xcd, 0xf5, 0xdd, 0xb1, 0xa9, + 0xbe, 0xd5, 0x7c, 0xfb, 0x7b, 0x75, 0xce, 0xf1, 0x9b, 0xa8, 0x97, 0x5a, + 0x79, 0xe0, 0x9d, 0x67, 0x51, 0xcf, 0x3c, 0xa3, 0x6d, 0xa6, 0xf2, 0x3b, + 0xed, 0x9d, 0x43, 0xb1, 0x90, 0x3c, 0x78, 0xe7, 0x57, 0x30, 0x5e, 0x7f, + 0x3d, 0x52, 0x5e, 0xa3, 0x1c, 0xbf, 0xd6, 0xa4, 0x2f, 0xb7, 0xb1, 0xde, + 0x8f, 0x5a, 0xb8, 0x1e, 0x9d, 0x5b, 0xe8, 0xf1, 0xf6, 0xf1, 0xef, 0x35, + 0x9a, 0x07, 0xdf, 0x6a, 0x8a, 0xdf, 0xc7, 0x21, 0xfc, 0x0e, 0xfd, 0x53, + 0x7e, 0x21, 0xc0, 0xef, 0x6a, 0x6d, 0x7b, 0xfc, 0x02, 0xc7, 0x0f, 0x21, + 0xfc, 0xb6, 0x32, 0x0f, 0x6f, 0xb7, 0xe0, 0x4d, 0xea, 0xc5, 0x58, 0xef, + 0x8d, 0x47, 0x0f, 0xfd, 0x1e, 0xa2, 0x7b, 0x65, 0x16, 0xd7, 0x02, 0xbc, + 0xe5, 0x73, 0xf2, 0x7e, 0x5f, 0x82, 0x2a, 0xc7, 0xbf, 0xec, 0xe3, 0x21, + 0x2e, 0xfc, 0x73, 0xd1, 0xfe, 0xed, 0xaa, 0xe2, 0x8b, 0x3e, 0x67, 0x72, + 0x84, 0x8b, 0xa8, 0xef, 0x7a, 0x78, 0xf3, 0xbe, 0xaf, 0x5c, 0xb8, 0x55, + 0x55, 0xfd, 0x4c, 0xf6, 0x15, 0x13, 0x06, 0x78, 0x4e, 0x4e, 0x70, 0xff, + 0xfa, 0x10, 0xa5, 0x3e, 0x59, 0x1c, 0xc5, 0x3e, 0x03, 0x1d, 0xeb, 0xfd, + 0x8c, 0xd6, 0x9d, 0x71, 0x7a, 0x47, 0x0e, 0x98, 0x36, 0xea, 0x75, 0xc6, + 0x09, 0x3b, 0x62, 0x72, 0x5f, 0x12, 0x3e, 0x8e, 0xa1, 0x7a, 0x6e, 0xa3, + 0x3f, 0x05, 0xfb, 0x12, 0xc7, 0x79, 0x40, 0xca, 0x3b, 0x02, 0xfd, 0x48, + 0xe8, 0xf4, 0x92, 0x7f, 0x37, 0x81, 0xe3, 0x52, 0xfb, 0xd2, 0x92, 0xc7, + 0xc5, 0x9a, 0xea, 0xe3, 0xd9, 0x11, 0xe9, 0x4f, 0x02, 0x1c, 0x93, 0xf2, + 0x48, 0x28, 0xf4, 0x74, 0x53, 0x6e, 0x4b, 0x95, 0x75, 0x5a, 0x97, 0x2f, + 0xe3, 0x31, 0x63, 0x65, 0x25, 0x2f, 0x60, 0x61, 0x8e, 0xdf, 0x79, 0x86, + 0x72, 0xa7, 0x1a, 0x21, 0xb9, 0x39, 0xaa, 0xf8, 0x48, 0x60, 0x7c, 0x73, + 0xc4, 0xc7, 0xe9, 0x6b, 0x84, 0xa7, 0xe0, 0x18, 0x62, 0x74, 0x63, 0x2e, + 0x5b, 0x88, 0x10, 0xf7, 0xf6, 0xdf, 0x16, 0xe1, 0x1e, 0xf6, 0x4d, 0x4f, + 0x7e, 0x82, 0x73, 0xb5, 0x59, 0x9e, 0xbc, 0x73, 0x5d, 0xe6, 0xa9, 0xd1, + 0xfc, 0x8e, 0x73, 0x5d, 0x95, 0x9b, 0xd4, 0x9f, 0xea, 0x83, 0x25, 0xae, + 0xfb, 0x46, 0xef, 0x1a, 0x89, 0x4e, 0xc8, 0xfc, 0x4f, 0xad, 0xfb, 0x95, + 0x0e, 0x7d, 0x77, 0x91, 0xfe, 0xf6, 0xde, 0x5b, 0x6e, 0xc8, 0x1c, 0xfe, + 0x1f, 0xde, 0x55, 0x5b, 0xbd, 0xa7, 0x1c, 0xe6, 0xf9, 0x04, 0xf3, 0x6c, + 0x40, 0x4b, 0x04, 0x89, 0xb1, 0x8d, 0x29, 0x3c, 0x57, 0x2f, 0xd3, 0x58, + 0xb7, 0x5b, 0x66, 0x70, 0xae, 0x3b, 0xf6, 0x0c, 0xe9, 0x19, 0x24, 0x4f, + 0x2a, 0xbc, 0x32, 0x45, 0xef, 0x6c, 0x1d, 0x7e, 0x01, 0x50, 0xb6, 0x82, + 0xa7, 0xd8, 0x0d, 0x00, 0x00, 0x00 }; static u8 bnx2_rv2p_proc2[] = { -/* 0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ - 0xcd, 0x58, 0x5b, 0x6c, - 0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2, - 0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18, - 0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda, - 0x9a, 0x56, 0x9b, 0x16, 0xfb, 0x81, 0xaf, 0x09, 0x14, 0x6a, 0x4c, 0x25, - 0xd6, 0x08, 0xc5, 0x47, 0xa0, 0x11, 0x1f, 0x84, 0xf0, 0xd3, 0x1f, 0x3b, - 0x8d, 0x7f, 0x0a, 0x24, 0x6a, 0x88, 0xc4, 0xa8, 0x9f, 0x24, 0x68, 0xa0, - 0x21, 0x0a, 0x58, 0x8b, 0x63, 0x4c, 0xb4, 0xf5, 0xec, 0xbd, 0xf6, 0xb9, - 0x73, 0xef, 0x6d, 0x8b, 0x1a, 0xf9, 0x70, 0x3e, 0xba, 0x7b, 0xce, 0xd9, - 0x67, 0x3f, 0xd6, 0xde, 0x67, 0x9f, 0x7d, 0xae, 0x52, 0xfc, 0xbb, 0xb6, - 0x94, 0xc9, 0x37, 0x83, 0x96, 0xfe, 0x1b, 0x51, 0x0f, 0x85, 0xd3, 0x3c, - 0x8e, 0x2a, 0xa2, 0x49, 0xa5, 0xb2, 0x5e, 0xea, 0x08, 0x7d, 0x44, 0xe8, - 0x70, 0x08, 0xf4, 0xb4, 0xd0, 0x77, 0x84, 0xfe, 0x2e, 0xf4, 0x80, 0xd0, - 0x0f, 0x85, 0xea, 0x5f, 0xd6, 0xd6, 0x7f, 0xf4, 0xb0, 0x46, 0x89, 0x7e, - 0x1b, 0xd3, 0x35, 0xb0, 0xe3, 0xc1, 0x05, 0xc4, 0x77, 0x61, 0xa2, 0xc0, - 0x87, 0xf9, 0x53, 0x7d, 0xa0, 0xd7, 0x60, 0xd7, 0xe1, 0xec, 0x0a, 0xb3, - 0x1f, 0x64, 0x43, 0x09, 0xe8, 0xc6, 0x08, 0xe8, 0xea, 0x65, 0x4c, 0x7a, - 0x9f, 0x0a, 0x63, 0xdc, 0xb8, 0x94, 0xf6, 0x87, 0x55, 0x83, 0x22, 0x3f, - 0x67, 0xaa, 0x68, 0x98, 0xc6, 0xf5, 0x56, 0x6c, 0x18, 0xeb, 0x8f, 0xa5, - 0x40, 0x37, 0x25, 0x41, 0xcf, 0x08, 0xdd, 0x52, 0x2c, 0x7a, 0x6c, 0x31, - 0xbf, 0x98, 0xf6, 0x25, 0x5c, 0x39, 0xc7, 0x6d, 0xe0, 0x96, 0x95, 0xfd, - 0x4a, 0xc1, 0xce, 0x03, 0xb2, 0x3e, 0xa3, 0x0a, 0xb3, 0xaf, 0x6f, 0xc1, - 0xb8, 0xfc, 0x20, 0xf9, 0xa7, 0xff, 0xcf, 0x62, 0x7e, 0xfa, 0xfd, 0xf8, - 0x15, 0xf6, 0x83, 0x96, 0x2f, 0xa2, 0x75, 0x27, 0xd3, 0x3f, 0x88, 0xf1, - 0xde, 0x25, 0x32, 0x1f, 0x36, 0xf8, 0x18, 0x79, 0x41, 0x5c, 0x99, 0x58, - 0xc7, 0x2a, 0x7d, 0xf2, 0x2b, 0x15, 0xe4, 0x2f, 0xc8, 0x2e, 0x35, 0xf2, - 0x81, 0xfb, 0xfa, 0x16, 0xb2, 0x73, 0x4c, 0xc7, 0x01, 0xb8, 0xcd, 0x0a, - 0x95, 0xb2, 0xdc, 0x7d, 0x83, 0x5e, 0x3d, 0x51, 0xad, 0x07, 0xfa, 0x54, - 0xa5, 0xc5, 0x20, 0x65, 0x97, 0x81, 0xaa, 0x5a, 0xbf, 0x1f, 0x7b, 0x97, - 0x18, 0x7b, 0x30, 0x9e, 0x9d, 0x01, 0xdd, 0x23, 0xf4, 0xaa, 0x3a, 0x26, - 0xcb, 0x7f, 0xb8, 0xc1, 0x62, 0x0c, 0xb2, 0xb5, 0xde, 0x7c, 0x38, 0x32, - 0x61, 0xf0, 0x52, 0x8b, 0x40, 0xce, 0x2e, 0x21, 0x3e, 0x1d, 0x9c, 0x4a, - 0xc8, 0x5d, 0xdf, 0x32, 0x55, 0x1e, 0x7d, 0x30, 0x45, 0x1e, 0x61, 0xff, - 0xb7, 0x2b, 0x7c, 0xf9, 0xa4, 0xda, 0x25, 0x4f, 0x36, 0x22, 0x8f, 0xac, - 0xa7, 0x3e, 0x91, 0x85, 0x6b, 0x13, 0xfa, 0xcf, 0x84, 0x7a, 0x32, 0x4e, - 0x01, 0x8a, 0x2b, 0x87, 0xfd, 0x53, 0xe2, 0xe7, 0x26, 0xed, 0x27, 0xd1, - 0x8a, 0x50, 0xb6, 0x36, 0xc1, 0x38, 0x35, 0xc4, 0xa0, 0xaf, 0x61, 0x03, - 0xb6, 0xaf, 0x46, 0x5c, 0x7b, 0x4f, 0x86, 0x8d, 0xfd, 0x51, 0xfa, 0x3b, - 0xd0, 0xb6, 0x9d, 0x47, 0x03, 0xd1, 0x1d, 0x4c, 0xed, 0x63, 0x95, 0x58, - 0xee, 0x8a, 0xf0, 0x7a, 0x72, 0x97, 0xcc, 0xf7, 0xec, 0xf0, 0xdb, 0xfd, - 0x02, 0xf2, 0xdb, 0x7e, 0x7e, 0x47, 0x88, 0xa8, 0x13, 0x73, 0xf9, 0x98, - 0x3a, 0x3b, 0xb7, 0x13, 0xff, 0x55, 0x6a, 0xd7, 0x20, 0x29, 0x4e, 0xab, - 0x0d, 0x6b, 0xb1, 0x6f, 0x77, 0x2c, 0xc5, 0xb8, 0x36, 0xad, 0x05, 0xfd, - 0x1e, 0xf3, 0xf3, 0x9d, 0x1e, 0xe2, 0x2f, 0x9d, 0xe7, 0x0c, 0x71, 0x5e, - 0xa9, 0x11, 0xce, 0xc7, 0x04, 0x65, 0x06, 0xff, 0xda, 0xaa, 0xc1, 0xdf, - 0xbc, 0x99, 0x15, 0xbf, 0xd9, 0x9a, 0xe7, 0x3c, 0x18, 0xe8, 0x18, 0x26, - 0x3f, 0xe7, 0xaa, 0x91, 0x4e, 0xa2, 0x51, 0xd5, 0xb0, 0x90, 0xf0, 0x5e, - 0x15, 0x36, 0x71, 0x3a, 0x7f, 0x33, 0xcd, 0xcf, 0xd3, 0xeb, 0x26, 0x1e, - 0x24, 0xd7, 0x92, 0x78, 0x45, 0x5d, 0x7c, 0xf2, 0x61, 0xf8, 0xdb, 0xcd, - 0x76, 0x5f, 0x97, 0xec, 0xe6, 0xfc, 0x4a, 0xaa, 0x26, 0x8e, 0x7f, 0xd4, - 0x6a, 0x1b, 0xc6, 0xfa, 0xf9, 0x8f, 0x8d, 0x5c, 0xd2, 0x53, 0x23, 0x75, - 0x44, 0xb9, 0x72, 0xa2, 0x37, 0x83, 0xee, 0x34, 0x7a, 0xeb, 0x88, 0x6f, - 0xb1, 0x42, 0xfe, 0x26, 0x26, 0xc9, 0x69, 0x03, 0xce, 0xf6, 0x33, 0xec, - 0xf7, 0x35, 0xf6, 0x85, 0x3e, 0x63, 0x2f, 0xe6, 0x2f, 0xfa, 0xf4, 0x95, - 0x7b, 0xf4, 0x11, 0x7f, 0x51, 0xf2, 0x02, 0xef, 0x9b, 0x63, 0x3d, 0x3b, - 0xcc, 0xb8, 0x58, 0xcf, 0x0c, 0x41, 0xfe, 0xc5, 0x21, 0xe2, 0x9f, 0x23, - 0x7a, 0xed, 0xff, 0x88, 0xe7, 0x9c, 0x30, 0xe4, 0x4c, 0x8f, 0x5f, 0xc1, - 0x6f, 0xe3, 0x17, 0xcb, 0xb5, 0x47, 0x73, 0x69, 0xe6, 0x33, 0xf1, 0xe8, - 0x0e, 0x73, 0x02, 0xa6, 0x1b, 0x16, 0xfa, 0x71, 0x33, 0xf6, 0x9c, 0xdf, - 0xcc, 0x79, 0x3e, 0xd1, 0x26, 0x75, 0x40, 0x71, 0x9d, 0xb9, 0x5d, 0xe2, - 0xa1, 0xf3, 0x3a, 0x04, 0xff, 0x46, 0x73, 0x2c, 0x3f, 0xd9, 0xc5, 0x79, - 0xb9, 0xd2, 0x8e, 0xe6, 0x38, 0x5e, 0xd6, 0xd9, 0x21, 0x6c, 0x2b, 0xd4, - 0x4f, 0xc8, 0x6b, 0xb6, 0x41, 0x9b, 0xa4, 0x8e, 0x9e, 0x15, 0xda, 0x6d, - 0x33, 0x3e, 0xba, 0x8e, 0x59, 0x2c, 0x3f, 0x9b, 0x32, 0xf7, 0x0c, 0xd6, - 0x9f, 0x16, 0x39, 0x3f, 0x0a, 0x55, 0x22, 0xa7, 0x55, 0xf6, 0x9f, 0xf3, - 0xc9, 0x89, 0x04, 0xe4, 0x84, 0x94, 0xc1, 0xcd, 0x9c, 0xef, 0x5d, 0x52, - 0xbf, 0xf7, 0xc5, 0xa6, 0xab, 0xb7, 0x7c, 0x0e, 0xdc, 0xba, 0x5a, 0x8e, - 0x3a, 0x53, 0x1f, 0x0d, 0xb3, 0xbf, 0x03, 0xdd, 0x3b, 0x80, 0x53, 0x8f, - 0xe0, 0x14, 0x07, 0x4e, 0xf3, 0x0a, 0xf5, 0x59, 0x14, 0xd4, 0x90, 0xfe, - 0x53, 0x21, 0xe3, 0xc7, 0xbe, 0x98, 0xaf, 0xfe, 0xf6, 0x9a, 0xfa, 0x5b, - 0xa8, 0xd3, 0xc4, 0xff, 0xb3, 0xa9, 0x6f, 0x5a, 0x9f, 0xd1, 0xff, 0x6f, - 0xf5, 0x72, 0x9c, 0x92, 0xdd, 0x7d, 0x26, 0xce, 0x98, 0x2e, 0xd4, 0xd9, - 0x22, 0x22, 0xcb, 0x46, 0x3a, 0x99, 0x5e, 0xdf, 0xbc, 0x15, 0xf3, 0x65, - 0x7c, 0x4e, 0x6e, 0x09, 0x01, 0xaf, 0xa8, 0x3a, 0xde, 0x87, 0xba, 0xae, - 0xe2, 0x2c, 0xaf, 0xe2, 0x28, 0xc7, 0x3f, 0xaa, 0xe5, 0x12, 0xdf, 0x67, - 0xa1, 0x42, 0x3e, 0x7a, 0xfd, 0xd9, 0xad, 0xf3, 0x84, 0xec, 0x88, 0xe9, - 0xbc, 0xa5, 0xb1, 0x3e, 0x47, 0xb6, 0xe4, 0xf9, 0x1a, 0xe6, 0xb3, 0xc7, - 0x22, 0x34, 0xff, 0x80, 0xd5, 0xd3, 0x87, 0xf9, 0x9f, 0x1a, 0x69, 0xbc, - 0xce, 0x7e, 0x0d, 0xe7, 0xcc, 0x7e, 0x0d, 0xf5, 0xcb, 0x2a, 0x3a, 0x88, - 0xba, 0xd6, 0x78, 0x10, 0xf2, 0x71, 0x4f, 0x7b, 0xfd, 0xf2, 0xe2, 0x47, - 0xe7, 0xe1, 0xb2, 0x38, 0xd9, 0xcf, 0x09, 0x4e, 0x97, 0x7c, 0xf1, 0x39, - 0x6c, 0xe2, 0xd3, 0x1b, 0x93, 0xf3, 0xd2, 0x7c, 0x29, 0xe8, 0x17, 0xf1, - 0x9d, 0x71, 0xef, 0x9d, 0xae, 0x95, 0xa0, 0xdd, 0x2b, 0xe5, 0x9c, 0xd6, - 0xf9, 0xf3, 0x6b, 0x3e, 0xea, 0xf2, 0xb8, 0x7b, 0x4f, 0x20, 0xbf, 0xac, - 0x9d, 0xf0, 0x4b, 0xbd, 0x28, 0x79, 0x3c, 0x2e, 0xf4, 0x65, 0xc9, 0xdf, - 0x6d, 0xd2, 0xb7, 0x98, 0xfe, 0xe2, 0x0f, 0xcc, 0x3b, 0xfd, 0x6e, 0x5f, - 0x60, 0xea, 0x36, 0x8d, 0x43, 0xca, 0x89, 0x13, 0x83, 0x36, 0xeb, 0x33, - 0x24, 0x4a, 0xcf, 0x1a, 0xe0, 0x35, 0x52, 0x07, 0xbe, 0xdd, 0x91, 0xb0, - 0x8c, 0x21, 0x6f, 0xac, 0xda, 0x77, 0x0f, 0xd7, 0x4f, 0xc6, 0x93, 0xe4, - 0xc6, 0xdc, 0xfa, 0x24, 0x79, 0xaf, 0x26, 0x84, 0x96, 0x2f, 0xbe, 0x2c, - 0xbe, 0x85, 0xfe, 0x64, 0xa9, 0x17, 0xdf, 0x97, 0x34, 0xbe, 0xbc, 0xaf, - 0xbe, 0xf9, 0x12, 0xa6, 0x4b, 0x6f, 0x05, 0xed, 0xbb, 0x95, 0xe7, 0x17, - 0xa3, 0xee, 0x11, 0x7e, 0x9c, 0x5f, 0xf5, 0x6f, 0x0c, 0x9a, 0x7e, 0x42, - 0xf0, 0x08, 0xf4, 0x41, 0x65, 0x77, 0x80, 0xbe, 0x29, 0x74, 0xce, 0x2a, - 0xd0, 0xbd, 0xab, 0xfc, 0x71, 0x88, 0xa5, 0x7c, 0x71, 0xac, 0x47, 0x1c, - 0x8f, 0x4c, 0x04, 0xeb, 0x81, 0xc4, 0x4b, 0xc7, 0x27, 0x70, 0xbf, 0x1b, - 0xfd, 0xe2, 0xce, 0xdf, 0xc5, 0xed, 0x4a, 0xc7, 0xab, 0x7b, 0x25, 0xee, - 0x93, 0x0e, 0xe9, 0x4b, 0xc7, 0xdc, 0xfb, 0xe2, 0x9f, 0xc4, 0x31, 0x7e, - 0x85, 0xe3, 0x78, 0xf7, 0xff, 0x2c, 0x8e, 0x9d, 0x12, 0xc7, 0x22, 0xb9, - 0x57, 0x4d, 0xbf, 0xd9, 0x2e, 0x7d, 0x18, 0xf5, 0x8d, 0x7e, 0xbd, 0x4f, - 0x70, 0x1f, 0x78, 0xb5, 0x5b, 0x8f, 0xe7, 0x33, 0x7f, 0x4e, 0xf6, 0x95, - 0xca, 0xbe, 0x7b, 0x26, 0xed, 0x3b, 0xc5, 0xf5, 0xee, 0xf1, 0xf1, 0xc9, - 0xef, 0x15, 0x9f, 0x9d, 0x59, 0x95, 0x02, 0xee, 0xa8, 0xe3, 0xb1, 0x29, - 0xde, 0x37, 0x86, 0x1f, 0xf9, 0xb5, 0x36, 0x85, 0xba, 0x05, 0xfe, 0xb9, - 0x9e, 0x7a, 0x4a, 0xe3, 0xfb, 0xc7, 0xa7, 0xef, 0x57, 0x8d, 0x3c, 0xc4, - 0x6d, 0x43, 0xb8, 0x84, 0xf9, 0x4e, 0xb7, 0xf3, 0x7d, 0xe7, 0xfa, 0xb7, - 0x9a, 0xfd, 0x3a, 0x2a, 0xfe, 0x55, 0x88, 0x7f, 0x7a, 0xb9, 0x96, 0xeb, - 0xbe, 0x75, 0xba, 0xdd, 0xeb, 0xdf, 0x9d, 0x97, 0xd1, 0xf7, 0x4f, 0xfb, - 0x63, 0xd1, 0x9b, 0x32, 0xfa, 0x49, 0x5e, 0xb9, 0xf4, 0x7d, 0xd4, 0x4f, - 0x62, 0x7e, 0x72, 0x9f, 0x41, 0xfa, 0x5b, 0x34, 0x5e, 0x72, 0xdf, 0x70, - 0x3e, 0x47, 0xac, 0xa3, 0x6c, 0x57, 0x5e, 0xf9, 0x71, 0x39, 0x23, 0x7c, - 0x53, 0xc5, 0x8d, 0xd6, 0x8b, 0x64, 0x7d, 0x2a, 0xbf, 0xc5, 0x4e, 0x37, - 0x1f, 0x64, 0x1f, 0xf3, 0x35, 0x0b, 0x5f, 0x34, 0x34, 0x39, 0xfe, 0x18, - 0xe5, 0xab, 0x38, 0xaf, 0xf7, 0x6f, 0xcb, 0x11, 0x9f, 0x76, 0x9e, 0xf3, - 0xf0, 0xfb, 0x80, 0x7d, 0xe9, 0x2b, 0x80, 0x23, 0xf1, 0xcd, 0x50, 0x4d, - 0xce, 0x74, 0x78, 0xe1, 0xdd, 0x30, 0x9a, 0x33, 0x78, 0xdb, 0xec, 0xe7, - 0x48, 0x27, 0xe9, 0x5f, 0x1d, 0xc0, 0x31, 0x2c, 0x38, 0x9e, 0x50, 0x7f, - 0x9f, 0xf7, 0xc6, 0x0f, 0x6f, 0x5e, 0x8c, 0xff, 0x19, 0xcc, 0xe3, 0x87, - 0xe5, 0x5d, 0xdd, 0x18, 0x03, 0xfd, 0x2e, 0x62, 0xec, 0x46, 0x5e, 0xdf, - 0xc3, 0xe7, 0xb5, 0x4a, 0xf5, 0xf2, 0xbb, 0xc3, 0x52, 0x0d, 0x6b, 0xc9, - 0xee, 0x94, 0xae, 0x7f, 0xc8, 0x77, 0x27, 0xee, 0xbd, 0xb7, 0x75, 0x0d, - 0x4c, 0xc4, 0x69, 0x58, 0x31, 0x33, 0xc1, 0x82, 0xde, 0xf8, 0xe2, 0x4b, - 0x5e, 0x7e, 0xaf, 0xbf, 0x18, 0xf3, 0x65, 0xf7, 0x91, 0x9c, 0x88, 0xda, - 0x8b, 0xba, 0xfb, 0xee, 0x1e, 0xd0, 0xb7, 0xd5, 0xbd, 0xd8, 0x3f, 0x73, - 0x3b, 0xd7, 0x51, 0xab, 0x4c, 0xf2, 0x2b, 0x0d, 0x5c, 0xd3, 0xa8, 0xc3, - 0x13, 0x13, 0xaa, 0x04, 0xf7, 0x9a, 0x79, 0x07, 0xab, 0x1a, 0xd1, 0x8b, - 0xfa, 0x68, 0x17, 0xde, 0xc1, 0x44, 0x8b, 0x83, 0x7d, 0x9f, 0x55, 0xe8, - 0xaf, 0x08, 0x8f, 0xf7, 0x5d, 0x1c, 0xd3, 0xe1, 0x60, 0x5d, 0xf2, 0xfa, - 0x15, 0x93, 0x73, 0xfd, 0xab, 0xfb, 0x6e, 0xee, 0xe1, 0x7e, 0x2a, 0x19, - 0xac, 0xcb, 0x01, 0xf9, 0xfb, 0x24, 0x7e, 0x49, 0x89, 0x5f, 0x54, 0xc7, - 0x0f, 0xef, 0xed, 0x4f, 0x7d, 0xef, 0x7a, 0xaa, 0x1b, 0xde, 0xbc, 0xfb, - 0xfc, 0x4f, 0x63, 0xd7, 0xf6, 0x98, 0xb7, 0x0e, 0x57, 0xbb, 0xe7, 0xae, - 0x43, 0xde, 0x8b, 0x5d, 0x87, 0x30, 0xce, 0x73, 0xbf, 0xbc, 0x38, 0xd3, - 0x21, 0x79, 0x74, 0x57, 0x44, 0xf2, 0x41, 0xec, 0xfb, 0x22, 0x62, 0xee, - 0x1b, 0x8c, 0xbf, 0x92, 0xfb, 0xee, 0x97, 0x2a, 0xf4, 0xd9, 0x17, 0x87, - 0xcc, 0xfb, 0xc4, 0xbc, 0x57, 0xb0, 0xbe, 0x3e, 0xae, 0x04, 0x67, 0xbe, - 0xff, 0xb5, 0x3f, 0x9c, 0xaf, 0x99, 0x8e, 0x61, 0x1f, 0x5e, 0x2a, 0x16, - 0x78, 0xbf, 0xc4, 0xe5, 0xfb, 0x45, 0xbf, 0xe0, 0xe1, 0xf0, 0xf9, 0x29, - 0xd5, 0xf6, 0x13, 0x4d, 0x65, 0x3a, 0x73, 0xb0, 0xa7, 0xd5, 0xed, 0x23, - 0xc1, 0x27, 0xd4, 0x79, 0x4b, 0xde, 0xc1, 0xf2, 0x5e, 0xd6, 0xef, 0x61, - 0xf4, 0x73, 0xad, 0x79, 0x8c, 0xc7, 0xd0, 0xb7, 0x39, 0xbf, 0xca, 0xbd, - 0xb5, 0x75, 0x9b, 0xe9, 0x4b, 0xa7, 0xde, 0x67, 0xee, 0xb9, 0xb6, 0x6a, - 0xd0, 0x16, 0xee, 0x5b, 0x1f, 0xb2, 0xf3, 0x92, 0x1f, 0x85, 0x77, 0x89, - 0xff, 0x3d, 0x62, 0xfa, 0x85, 0x73, 0xc5, 0xb8, 0x67, 0xf3, 0xbd, 0x34, - 0xa1, 0xdf, 0x23, 0x09, 0x6f, 0x9e, 0x25, 0x32, 0x65, 0x82, 0xfb, 0xec, - 0x9b, 0x40, 0xf7, 0xdc, 0x84, 0xbe, 0xbc, 0xb5, 0x4b, 0x70, 0xb8, 0x91, - 0x71, 0x5b, 0x3e, 0x9a, 0x0b, 0x7e, 0x67, 0x21, 0x5c, 0x7f, 0x73, 0xfb, - 0xd1, 0x73, 0x6c, 0xd7, 0xbc, 0x81, 0x3c, 0xf3, 0xcd, 0x55, 0xb3, 0xf8, - 0xfc, 0xa6, 0x9d, 0x51, 0xd8, 0x99, 0xe9, 0x17, 0xbf, 0xda, 0x6f, 0x01, - 0xed, 0x92, 0x3a, 0x73, 0xd2, 0x7d, 0x97, 0xc3, 0x4e, 0x53, 0x4f, 0x26, - 0xbf, 0x13, 0x30, 0x9e, 0x5b, 0xc7, 0x63, 0xd5, 0xbc, 0x95, 0xe4, 0x97, - 0x4c, 0x7a, 0xcf, 0x16, 0xe2, 0x6e, 0xf2, 0xc1, 0xe4, 0x8f, 0xf7, 0x1d, - 0x7b, 0x9b, 0xa7, 0x5e, 0xfa, 0xe3, 0xef, 0x70, 0xbe, 0x84, 0x65, 0x3d, - 0x96, 0xe9, 0xef, 0xbb, 0x3c, 0x3e, 0x6f, 0x01, 0x9f, 0x8c, 0xd8, 0x6d, - 0xb7, 0xf0, 0x3b, 0x74, 0x96, 0xda, 0x25, 0xf1, 0x39, 0x57, 0x2d, 0x75, - 0x50, 0xec, 0xfb, 0x49, 0xfa, 0x1f, 0xc4, 0x31, 0x6e, 0x6f, 0xc9, 0x49, - 0xdc, 0x24, 0x8f, 0x9e, 0x16, 0xbf, 0x7f, 0x84, 0xdf, 0xb6, 0xf1, 0xbb, - 0xc5, 0xf5, 0xdb, 0xd4, 0x59, 0xaf, 0x9c, 0x99, 0x3a, 0x1f, 0xb8, 0x5e, - 0xdb, 0x27, 0xf9, 0xdd, 0x53, 0x24, 0xe7, 0xa1, 0x42, 0xbe, 0x3b, 0x38, - 0xe2, 0x4f, 0x89, 0x6a, 0x5a, 0xee, 0xdd, 0x57, 0x2c, 0xfb, 0x92, 0x7a, - 0x1f, 0xe6, 0x71, 0xfe, 0xec, 0x29, 0xf0, 0x34, 0xdf, 0x11, 0x8c, 0xdc, - 0xe0, 0x39, 0xf2, 0xe2, 0xc7, 0x37, 0x13, 0xff, 0x50, 0x07, 0x74, 0x9c, - 0x6a, 0xcd, 0xf7, 0x07, 0xcc, 0xe3, 0xfc, 0x26, 0xf7, 0xb7, 0xa1, 0xaf, - 0xdc, 0xdf, 0x76, 0x48, 0xfa, 0x08, 0xc1, 0xe5, 0x81, 0x21, 0xb2, 0x43, - 0xc7, 0xae, 0xd2, 0x7f, 0xfe, 0x61, 0x47, 0x54, 0xec, 0x28, 0xf7, 0xd8, - 0x11, 0xd0, 0x7b, 0x1d, 0xcd, 0xaf, 0x50, 0x5f, 0x73, 0x1e, 0x2e, 0x57, - 0xeb, 0x29, 0x47, 0xf4, 0xbd, 0xb0, 0xae, 0x88, 0xc6, 0xcb, 0xd4, 0xab, - 0xf0, 0xb7, 0x37, 0x59, 0x84, 0x3a, 0x96, 0xdc, 0x49, 0xf3, 0x35, 0xea, - 0xd5, 0x3e, 0x0e, 0xc4, 0x2b, 0xea, 0x18, 0xea, 0x73, 0xe3, 0x41, 0xb6, - 0x47, 0x1d, 0x1f, 0x34, 0xf5, 0x7a, 0xca, 0xef, 0x98, 0xbd, 0xeb, 0xa4, - 0x5e, 0x9c, 0xc0, 0x77, 0x51, 0xfd, 0x5e, 0x23, 0xfe, 0xd9, 0xe6, 0x3d, - 0xb8, 0xfb, 0x98, 0xa1, 0x8b, 0x7c, 0xe3, 0xfd, 0x27, 0x96, 0x0a, 0xad, - 0xf2, 0x8d, 0x07, 0xd6, 0x55, 0x09, 0xad, 0x36, 0xe3, 0xe9, 0xbe, 0x2b, - 0x5e, 0x29, 0xf9, 0x62, 0xf7, 0x7b, 0xe2, 0xcf, 0x47, 0xe2, 0xcf, 0x59, - 0xe0, 0x9f, 0xdc, 0x28, 0x78, 0x2c, 0x0a, 0xea, 0x17, 0xbb, 0xdc, 0x73, - 0x63, 0xd6, 0x11, 0x8f, 0x47, 0xd5, 0x5f, 0x3f, 0x97, 0x8f, 0x31, 0xd8, - 0x17, 0x00, 0x00, 0x00 }; + /* Date: 12/07/2007 14:57 */ + 0xed, 0x59, 0x5d, 0x6c, 0x54, 0xc7, 0x15, 0x9e, 0xbd, 0xbb, 0x7b, 0xf7, + 0x7a, 0x7d, 0xf7, 0xae, 0x71, 0xa8, 0xff, 0xf9, 0xb3, 0x09, 0xd8, 0xa9, + 0x21, 0xce, 0x9a, 0x98, 0x02, 0x55, 0x63, 0x39, 0x95, 0x81, 0xa6, 0x55, + 0x0c, 0x49, 0x9b, 0xbe, 0x35, 0x76, 0x02, 0xb6, 0xa9, 0x4d, 0x2d, 0x43, + 0x83, 0x4a, 0x1b, 0x65, 0x85, 0xd7, 0xf6, 0xcb, 0x26, 0xea, 0x22, 0xc0, + 0x24, 0xaa, 0xa8, 0x1b, 0xa4, 0x28, 0xea, 0xdb, 0x56, 0x6a, 0x6d, 0xda, + 0x97, 0xfe, 0x10, 0xb7, 0x4a, 0xa4, 0x42, 0xa5, 0xf6, 0xa1, 0x52, 0x85, + 0x44, 0xda, 0x62, 0x99, 0xc4, 0x20, 0x63, 0xba, 0x79, 0x21, 0x75, 0x67, + 0xce, 0x77, 0xe6, 0xee, 0xbd, 0xeb, 0xb5, 0x21, 0x2d, 0x8f, 0xdd, 0x07, + 0x1f, 0x66, 0xee, 0x99, 0x33, 0xe7, 0xe7, 0x9b, 0x33, 0x67, 0x0e, 0x65, + 0x42, 0x08, 0x43, 0x24, 0xb3, 0x1b, 0x24, 0x15, 0x56, 0x20, 0x20, 0xf0, + 0x7b, 0xac, 0x8c, 0xc8, 0x9f, 0xb3, 0x96, 0xfc, 0x1b, 0x16, 0xcf, 0x1b, + 0x55, 0x34, 0x0e, 0x09, 0x45, 0x1d, 0x21, 0x92, 0x5e, 0x5a, 0xce, 0xf4, + 0x67, 0x4c, 0x77, 0x1b, 0xa0, 0x3d, 0x4c, 0xeb, 0x98, 0x9e, 0x64, 0xba, + 0x91, 0xe9, 0x56, 0xa6, 0x27, 0x98, 0x7e, 0x8f, 0xe9, 0x07, 0x4c, 0x77, + 0xb2, 0x3c, 0xf9, 0x4b, 0xda, 0xf2, 0x4f, 0x40, 0x24, 0x9b, 0xb4, 0x7e, + 0x36, 0xa6, 0x9b, 0xa0, 0xe7, 0x73, 0x1b, 0x15, 0xdf, 0xcd, 0xa5, 0x3c, + 0x1f, 0xe6, 0xaf, 0x65, 0x40, 0x37, 0x60, 0xd5, 0x4f, 0x93, 0x8f, 0xeb, + 0xf5, 0x20, 0xdd, 0x31, 0xd0, 0x9e, 0x20, 0x68, 0x7b, 0x33, 0x91, 0xf4, + 0x4b, 0x06, 0xc6, 0x9d, 0x5b, 0x2c, 0xb2, 0x2f, 0x64, 0x28, 0x39, 0xeb, + 0x2d, 0xf3, 0x12, 0xe6, 0xbf, 0x19, 0x07, 0x7d, 0x39, 0x0a, 0xfa, 0x4f, + 0xa6, 0x87, 0x4b, 0x59, 0xbe, 0xcd, 0x6a, 0x97, 0x62, 0xfd, 0x8c, 0xad, + 0x68, 0x50, 0x24, 0x79, 0x9d, 0x10, 0xd0, 0xeb, 0xc7, 0x02, 0xdf, 0xd7, + 0x6c, 0xc5, 0xec, 0x0f, 0x0f, 0x63, 0x5c, 0x7b, 0xb1, 0x8c, 0xf8, 0xcf, + 0x67, 0xb5, 0xfe, 0x16, 0x79, 0x3f, 0x19, 0x87, 0x1c, 0x51, 0x6f, 0xd1, + 0x26, 0xc9, 0x66, 0x50, 0xb1, 0x4d, 0xcb, 0xc3, 0xef, 0xdc, 0xa3, 0xda, + 0x3f, 0x18, 0xaf, 0x4d, 0x80, 0x9e, 0x65, 0x5a, 0xd1, 0x4a, 0x64, 0xfb, + 0xdf, 0x9f, 0xb0, 0x48, 0x97, 0xe4, 0x36, 0xaf, 0x1f, 0x7f, 0x23, 0xfd, + 0xc8, 0x82, 0x1a, 0x40, 0x6e, 0x3c, 0xaa, 0xf8, 0xa4, 0x71, 0xf5, 0x90, + 0x7b, 0xb0, 0xbf, 0x98, 0xff, 0x7f, 0xf9, 0x19, 0xfc, 0xaf, 0xe4, 0xb5, + 0xb3, 0xfe, 0x1b, 0xa5, 0xfe, 0x8a, 0xd6, 0x05, 0x92, 0xdb, 0xfc, 0xfe, + 0xb9, 0x96, 0x89, 0xd3, 0xbf, 0x6f, 0x76, 0x94, 0x91, 0xfd, 0xcf, 0x62, + 0xfe, 0x74, 0xe7, 0x14, 0xfc, 0xb4, 0x9f, 0xe2, 0x22, 0xa2, 0xa9, 0x9f, + 0x63, 0x55, 0x77, 0x4c, 0x8d, 0x5f, 0xd8, 0x71, 0x23, 0x8b, 0xef, 0xe1, + 0x11, 0x35, 0x36, 0xe4, 0x3a, 0xfc, 0xf6, 0x07, 0x09, 0xe0, 0x69, 0x73, + 0x84, 0x86, 0xf6, 0x0c, 0x7d, 0xb7, 0xc5, 0x78, 0x16, 0xdf, 0x8f, 0x96, + 0xaa, 0xf1, 0xb3, 0xcd, 0x73, 0x18, 0x37, 0xf7, 0x8f, 0xf1, 0x42, 0xa3, + 0x44, 0xfe, 0x59, 0x5a, 0xba, 0x69, 0x40, 0x1e, 0x87, 0x37, 0x1a, 0x32, + 0xe2, 0x64, 0xaf, 0xdd, 0x09, 0x3a, 0x4a, 0xdf, 0xef, 0x05, 0xd2, 0x64, + 0x77, 0xa7, 0x13, 0x9a, 0x02, 0x23, 0xe3, 0xca, 0xc5, 0x8d, 0xc6, 0xdd, + 0x83, 0xe2, 0x67, 0xcc, 0xc5, 0x0f, 0xfb, 0xbf, 0x69, 0x25, 0xfc, 0x80, + 0x76, 0x6e, 0x01, 0x35, 0x1b, 0x14, 0x5f, 0xb8, 0x08, 0x8e, 0xfc, 0x7e, + 0xe6, 0xf8, 0x14, 0xe2, 0x44, 0xe2, 0x03, 0x63, 0xc6, 0x8b, 0xc4, 0x95, + 0xe2, 0xaf, 0x96, 0xfe, 0xd2, 0xf1, 0x57, 0x82, 0x22, 0xe2, 0xdb, 0x2c, + 0xaf, 0x9f, 0xed, 0x1a, 0x60, 0x7b, 0xe6, 0xa3, 0xda, 0xaf, 0xda, 0x1e, + 0xd0, 0x71, 0x9f, 0x3d, 0x01, 0x89, 0x27, 0x8d, 0x23, 0x9f, 0x3e, 0xe9, + 0xf7, 0xea, 0xf1, 0x8f, 0x5a, 0xc6, 0xa1, 0x6b, 0xe7, 0x16, 0xc5, 0x67, + 0x26, 0x26, 0xb2, 0x7e, 0x1c, 0x6e, 0x10, 0x5a, 0x8e, 0x96, 0xaf, 0x70, + 0x99, 0x93, 0xb8, 0x44, 0xdc, 0xce, 0x67, 0xbd, 0xe7, 0xa8, 0xa6, 0xc8, + 0x39, 0xf2, 0x9f, 0x07, 0xed, 0x97, 0xa3, 0x31, 0x4a, 0x10, 0x3b, 0xae, + 0xcc, 0xfa, 0xf7, 0x03, 0xbe, 0x23, 0x2e, 0x7e, 0xd6, 0xb6, 0xb1, 0xff, + 0x98, 0x56, 0xec, 0x54, 0xf2, 0xba, 0x58, 0x7e, 0x0b, 0xcb, 0xb7, 0x0b, + 0xce, 0xdb, 0x73, 0xee, 0x79, 0xd3, 0x71, 0xcb, 0x9f, 0x3b, 0xed, 0x3f, + 0xda, 0xbf, 0xf9, 0xca, 0xac, 0x5a, 0x5f, 0x7b, 0x9f, 0x73, 0xb8, 0xbf, + 0xc8, 0x39, 0x84, 0x9c, 0xbf, 0x3c, 0xee, 0xb7, 0x6b, 0x88, 0xf3, 0x5c, + 0x0f, 0xe2, 0x66, 0xbd, 0xf4, 0x2b, 0xfe, 0xf0, 0x18, 0xe1, 0x5d, 0xbc, + 0x18, 0x41, 0x7c, 0x1d, 0xd2, 0x5f, 0xb0, 0x1d, 0x2f, 0x7b, 0xce, 0x6b, + 0x09, 0xf9, 0xb5, 0xc3, 0xc4, 0x7e, 0x1d, 0xdd, 0x58, 0xde, 0xce, 0x78, + 0xc8, 0xf1, 0x79, 0x99, 0xb5, 0x49, 0xff, 0xe8, 0x9d, 0x53, 0x98, 0x1f, + 0xdd, 0x43, 0x24, 0x7d, 0xd5, 0xd0, 0xf6, 0x86, 0xd4, 0xdf, 0xc9, 0x41, + 0x7c, 0x9f, 0x0c, 0xf1, 0xf9, 0x7c, 0xaf, 0x9e, 0xd6, 0x5b, 0xf3, 0x19, + 0xac, 0xcf, 0xb1, 0x7e, 0x27, 0x82, 0xc4, 0x1f, 0x1d, 0x63, 0xbe, 0xf1, + 0x11, 0xbf, 0x9d, 0x3f, 0x40, 0x3e, 0xb7, 0xbf, 0x3f, 0x42, 0xe7, 0xdd, + 0x31, 0x5d, 0x3e, 0xa2, 0xce, 0xe8, 0x29, 0xc5, 0x5f, 0x29, 0xc6, 0xb2, + 0x4a, 0xd1, 0x2a, 0xd1, 0xbd, 0x17, 0xeb, 0xde, 0x30, 0x91, 0x6f, 0x7a, + 0xf7, 0x82, 0x7e, 0x88, 0xf9, 0xf5, 0xce, 0xb8, 0xe2, 0x5f, 0x53, 0xe3, + 0x4c, 0x29, 0x1a, 0x97, 0xf6, 0x28, 0xfb, 0xa5, 0xed, 0x8c, 0xcf, 0xc1, + 0x46, 0xf0, 0xf7, 0x1d, 0xa2, 0x8d, 0xcf, 0x0c, 0xe4, 0x28, 0x5f, 0x4d, + 0x0e, 0x5f, 0x52, 0x7e, 0xa9, 0x16, 0xb3, 0xc7, 0x14, 0x0d, 0x89, 0x8e, + 0x4d, 0xec, 0x97, 0x3d, 0xfe, 0xfc, 0x3c, 0xbf, 0x53, 0x8d, 0x6b, 0x24, + 0x9f, 0x17, 0xbf, 0x16, 0xc7, 0x39, 0xe4, 0xfa, 0xf5, 0x13, 0x03, 0x76, + 0xa7, 0x48, 0xff, 0x3d, 0xd1, 0x14, 0x9d, 0xeb, 0x98, 0xe8, 0x25, 0x3c, + 0x85, 0xac, 0xc1, 0x4b, 0xf8, 0x3e, 0xff, 0x0b, 0x2d, 0x57, 0xe1, 0x61, + 0x17, 0xdf, 0x9f, 0xc2, 0x95, 0x13, 0xda, 0xc9, 0x71, 0xd0, 0xfb, 0xb6, + 0xe2, 0xbe, 0xe9, 0x08, 0xa8, 0xf1, 0x3a, 0x39, 0xb6, 0x29, 0x6e, 0x1d, + 0xdd, 0x6a, 0xbd, 0x4c, 0x02, 0x74, 0x7e, 0x1c, 0x29, 0x5f, 0xcd, 0x47, + 0xa4, 0x1d, 0xfe, 0x7d, 0x06, 0x11, 0x0f, 0xfb, 0x28, 0xf9, 0xe7, 0xf3, + 0xf6, 0xad, 0x8c, 0xb6, 0x07, 0xf3, 0xb7, 0x5d, 0x7d, 0x6c, 0xb2, 0xab, + 0x63, 0x13, 0xf6, 0x9b, 0x75, 0x78, 0x9f, 0x4d, 0xbc, 0xef, 0x31, 0xb5, + 0x5f, 0x83, 0x47, 0x5f, 0xc5, 0x67, 0x45, 0x6f, 0x91, 0xdc, 0x75, 0xd6, + 0x77, 0x2e, 0x91, 0x7f, 0xad, 0xa3, 0x53, 0xd8, 0xff, 0xf6, 0xd4, 0x6a, + 0x7a, 0xd7, 0xb0, 0x9c, 0x75, 0xec, 0xd7, 0xd8, 0x43, 0x8c, 0xdb, 0xea, + 0x71, 0xca, 0xfb, 0x57, 0xfb, 0x87, 0xe4, 0xdb, 0x0b, 0xd3, 0xab, 0xe9, + 0x2b, 0x6d, 0x4a, 0x82, 0x3f, 0x65, 0xd0, 0xc1, 0xa8, 0x82, 0x5f, 0xf2, + 0x71, 0xd3, 0xfa, 0xce, 0x1f, 0xc2, 0x7d, 0x34, 0xe8, 0xe6, 0x0b, 0x25, + 0xb7, 0x9d, 0xf1, 0x20, 0xe5, 0x05, 0xe0, 0x9f, 0x85, 0x69, 0x9c, 0x9b, + 0x13, 0x74, 0x3e, 0xbe, 0x68, 0x87, 0x68, 0xff, 0xa8, 0x75, 0x83, 0xef, + 0xa5, 0xfc, 0xfd, 0x03, 0x79, 0x7d, 0x36, 0x68, 0x2f, 0xe7, 0xe9, 0x1b, + 0x4c, 0x53, 0xb6, 0x5a, 0x57, 0x2a, 0xf3, 0xad, 0x45, 0xf2, 0x91, 0x57, + 0x4b, 0x5c, 0x7d, 0x8f, 0xb0, 0x9c, 0x8f, 0x98, 0x0a, 0x96, 0x33, 0xc0, + 0xeb, 0xe7, 0x7c, 0x72, 0x0c, 0x8f, 0x1c, 0x7f, 0x3e, 0x1a, 0xe3, 0x7b, + 0xef, 0xbc, 0xb9, 0x52, 0xbd, 0xa4, 0x68, 0xb9, 0x5c, 0x8f, 0x59, 0x7d, + 0x2f, 0xa4, 0x1a, 0x89, 0xb4, 0x85, 0x0c, 0xb2, 0x77, 0x32, 0x35, 0x02, + 0x3f, 0x8d, 0xb3, 0x9f, 0x22, 0xf0, 0x53, 0x4d, 0xfe, 0x9e, 0xe4, 0x8d, + 0xf8, 0xfc, 0xcd, 0x6c, 0xf6, 0x9f, 0xc7, 0xf3, 0xa6, 0x8e, 0x2f, 0x91, + 0x34, 0xf2, 0x90, 0xbe, 0x3f, 0xf5, 0xbd, 0x72, 0x4b, 0xe7, 0x6d, 0xb9, + 0x6f, 0x81, 0x3e, 0x41, 0x8a, 0x73, 0x74, 0x9c, 0xf3, 0xd1, 0xd5, 0xa0, + 0x8e, 0x27, 0xf4, 0x1b, 0xff, 0x8c, 0xfa, 0xe5, 0xef, 0xe5, 0xb0, 0x22, + 0xcd, 0xb3, 0xc7, 0x88, 0xb6, 0xf4, 0x1d, 0xc7, 0x7c, 0x65, 0xab, 0xd2, + 0xe7, 0x27, 0x01, 0x9c, 0xd3, 0xb0, 0x98, 0xc9, 0xe0, 0x9e, 0x13, 0x11, + 0xd2, 0xa3, 0xee, 0x32, 0xe1, 0xc2, 0x8c, 0xa6, 0x32, 0x3e, 0x7f, 0x79, + 0xec, 0x2e, 0x66, 0xef, 0x84, 0xc4, 0x93, 0xfa, 0x6e, 0xf2, 0x79, 0x95, + 0x78, 0xb5, 0xf9, 0xbc, 0x3c, 0x4d, 0x7c, 0xf6, 0x22, 0xd9, 0xf9, 0x0d, + 0x6b, 0x9c, 0xeb, 0xb4, 0x8f, 0x3b, 0xd5, 0xf8, 0x79, 0xfb, 0x75, 0x9c, + 0x77, 0xfb, 0x75, 0xe4, 0x5b, 0x2b, 0x7c, 0x11, 0x79, 0xb8, 0xf3, 0xa2, + 0x6f, 0xff, 0x74, 0xc8, 0xd0, 0xe7, 0xe7, 0x7f, 0xf2, 0x9b, 0xfd, 0x5d, + 0xf6, 0xdb, 0xdd, 0xd5, 0xe3, 0x9a, 0x36, 0xf9, 0x1c, 0xf6, 0xdd, 0x2d, + 0xb4, 0x57, 0xf9, 0xef, 0x43, 0xf7, 0x1e, 0x0e, 0xed, 0x62, 0x7d, 0x76, + 0x71, 0x1e, 0xe0, 0xfa, 0x67, 0x7d, 0x50, 0xdf, 0x8b, 0x1a, 0x0f, 0x7c, + 0x3f, 0x02, 0xa7, 0xd6, 0x28, 0xec, 0x15, 0xaf, 0xf2, 0x39, 0xf8, 0x37, + 0xd3, 0xd7, 0x18, 0xff, 0x27, 0xb9, 0x3e, 0xd2, 0xf5, 0xdd, 0x3d, 0xcc, + 0x3b, 0x13, 0x6e, 0x3d, 0xa4, 0xef, 0x1f, 0x35, 0x0e, 0x08, 0x27, 0x52, + 0x4a, 0xfb, 0x25, 0x7f, 0x07, 0x80, 0x8d, 0x3f, 0x0d, 0x3f, 0xce, 0xb6, + 0x82, 0xef, 0x0d, 0xf8, 0xc7, 0xd1, 0xfa, 0x2d, 0x36, 0xfa, 0xde, 0x01, + 0x6d, 0xf0, 0xaf, 0xe9, 0xfa, 0x57, 0xe3, 0x73, 0x89, 0x69, 0xed, 0x66, + 0xb6, 0xf3, 0xbf, 0xf3, 0xbb, 0xa7, 0x1e, 0x5b, 0xc9, 0xef, 0xb4, 0xbe, + 0xad, 0xef, 0x2e, 0xe6, 0xcb, 0x76, 0x83, 0x66, 0x76, 0xd3, 0xfc, 0x66, + 0xe4, 0xdb, 0x70, 0xdb, 0xe9, 0xfb, 0xd4, 0xa7, 0xfa, 0x5d, 0x53, 0xf9, + 0x25, 0xd0, 0x33, 0x4c, 0x3f, 0xf7, 0x14, 0xe8, 0xb9, 0xa7, 0xfc, 0x79, + 0xc4, 0x8c, 0xfb, 0xe2, 0xdb, 0x86, 0xf8, 0xbe, 0xe3, 0xc6, 0x77, 0x3d, + 0xea, 0x03, 0x19, 0xaf, 0x55, 0xe3, 0xe9, 0xc6, 0xe9, 0x7e, 0xf1, 0x7c, + 0xd8, 0x71, 0x4c, 0xed, 0xc2, 0x3d, 0x37, 0xcc, 0xef, 0xcd, 0x45, 0xf7, + 0x9e, 0x2a, 0x16, 0xdf, 0xc8, 0xff, 0xe3, 0x4b, 0xf1, 0x3d, 0xb2, 0xa4, + 0xf3, 0x1f, 0xee, 0x79, 0x5d, 0xd7, 0x0f, 0x79, 0xea, 0x7a, 0xff, 0xbe, + 0xdf, 0xa2, 0x7a, 0x79, 0x34, 0xe0, 0xe2, 0x82, 0xf8, 0xa7, 0x79, 0x5d, + 0x19, 0xaf, 0xdb, 0xb7, 0x6c, 0xdd, 0xb5, 0x8c, 0x5a, 0xf7, 0xb7, 0x4f, + 0x97, 0xf7, 0x25, 0x7c, 0x7a, 0x26, 0x45, 0x1c, 0xf1, 0xc1, 0x7d, 0x61, + 0x16, 0xe9, 0x63, 0xf8, 0x71, 0xb7, 0x37, 0x8e, 0x7c, 0xa8, 0xdf, 0x79, + 0xfe, 0xba, 0xfe, 0x8f, 0x9f, 0xae, 0x5c, 0xd7, 0x6b, 0x79, 0x88, 0x5f, + 0xb7, 0x11, 0x23, 0xbe, 0xeb, 0x43, 0x6a, 0x5d, 0xbf, 0x6b, 0x5f, 0x3b, + 0xd9, 0x75, 0x99, 0xed, 0xab, 0x63, 0xfb, 0xe4, 0xe7, 0x6d, 0x74, 0x9f, + 0x58, 0xd7, 0x87, 0xbc, 0xf6, 0xfd, 0x7a, 0x95, 0xfd, 0x1e, 0xf4, 0x1d, + 0xc1, 0xfb, 0xc6, 0xf5, 0xfe, 0x4a, 0x5e, 0x2d, 0xd7, 0x63, 0x8e, 0xe0, + 0xe7, 0x54, 0x91, 0xba, 0x46, 0xed, 0xff, 0x7b, 0xe9, 0x00, 0xbe, 0xc7, + 0xe8, 0x1d, 0x11, 0xb4, 0x2e, 0x67, 0x8a, 0xf9, 0xe5, 0x6b, 0x01, 0xf0, + 0x15, 0x8b, 0x9b, 0xfa, 0x1e, 0x66, 0x39, 0xc5, 0xec, 0x66, 0x3d, 0x5d, + 0x3c, 0xf0, 0x3a, 0xe2, 0xeb, 0x63, 0xbe, 0x50, 0x91, 0xbe, 0x04, 0x46, + 0xb9, 0xad, 0x54, 0x2f, 0x5e, 0x38, 0x39, 0xad, 0xf8, 0x62, 0xee, 0xbb, + 0xcc, 0xaf, 0xdf, 0xc4, 0x43, 0xf0, 0x23, 0xbd, 0x3f, 0x44, 0xaf, 0xb3, + 0x92, 0xbf, 0xf0, 0x7e, 0x5a, 0x98, 0xd6, 0xfe, 0xb6, 0xc9, 0x4e, 0xd4, + 0xd3, 0x17, 0x0a, 0xfc, 0x68, 0x78, 0xfc, 0x08, 0xfe, 0x95, 0x71, 0xef, + 0x7f, 0x97, 0x03, 0x17, 0xaf, 0x16, 0xc1, 0x3d, 0xf5, 0xf7, 0x1e, 0xd8, + 0xce, 0x03, 0xad, 0x5e, 0xbb, 0x1a, 0xc4, 0x4c, 0x16, 0xf8, 0xef, 0x62, + 0x9c, 0xbc, 0xc8, 0x79, 0xf6, 0x7a, 0x54, 0x4d, 0x58, 0xa2, 0xe7, 0x19, + 0xe4, 0xe9, 0x8a, 0x52, 0xd8, 0xdd, 0xf3, 0x55, 0xed, 0x27, 0xcc, 0xd7, + 0xc4, 0x50, 0x57, 0x77, 0x45, 0xf0, 0xbe, 0xa8, 0x89, 0x81, 0x56, 0x70, + 0x9e, 0x9e, 0x71, 0xfb, 0x29, 0xa0, 0xf9, 0xfa, 0x12, 0x7d, 0xa5, 0xdf, + 0x9a, 0xa8, 0xc3, 0x45, 0x13, 0xd7, 0xcf, 0x94, 0xef, 0x82, 0xe2, 0x60, + 0x13, 0x70, 0x22, 0xea, 0xfd, 0x79, 0x8a, 0xf3, 0xec, 0xb2, 0x7a, 0x0d, + 0x7d, 0x99, 0x12, 0x4f, 0x5f, 0x42, 0xef, 0xa7, 0xfd, 0xa8, 0xe5, 0xd2, + 0x70, 0x85, 0xba, 0x72, 0x91, 0xf3, 0xd8, 0x23, 0xe2, 0x0f, 0x59, 0xd8, + 0x35, 0x93, 0x2d, 0xc4, 0x95, 0xde, 0x4f, 0xcb, 0x83, 0xde, 0xda, 0x8e, + 0xbc, 0x7c, 0xec, 0x7f, 0x88, 0xf5, 0xfc, 0x07, 0xf5, 0x33, 0x2b, 0xd8, + 0x1e, 0x25, 0x17, 0xf3, 0xfb, 0xb8, 0x4f, 0x94, 0x74, 0xc7, 0xfe, 0xfe, + 0x4e, 0x17, 0xe9, 0xb5, 0x86, 0x71, 0x54, 0xe1, 0xc1, 0x39, 0xf8, 0xd7, + 0xb6, 0x80, 0x9e, 0x6d, 0xd1, 0x71, 0xd0, 0xf1, 0xd2, 0xf1, 0x41, 0x1c, + 0x2b, 0xd0, 0x4f, 0xda, 0xd1, 0xf3, 0x04, 0xdd, 0x0f, 0x2d, 0x3d, 0x0b, + 0xfa, 0xdc, 0x61, 0xfd, 0x81, 0x66, 0xc5, 0xff, 0x9a, 0xf8, 0x13, 0xf7, + 0x1b, 0xfe, 0xca, 0xb4, 0xb0, 0x6f, 0x82, 0xbe, 0x8b, 0x8c, 0x5b, 0x98, + 0x03, 0xd2, 0xaa, 0xf3, 0xac, 0xf7, 0x9d, 0xa0, 0xcf, 0xdf, 0xd6, 0x65, + 0x78, 0xcd, 0xe7, 0x4b, 0x6d, 0x9f, 0xe2, 0x6f, 0x66, 0x1c, 0xca, 0xf7, + 0xe9, 0x5e, 0xa5, 0x47, 0x5c, 0xde, 0xdb, 0xc8, 0xc7, 0x4e, 0xc4, 0x1b, + 0x27, 0x89, 0x87, 0x92, 0x88, 0x1a, 0xd6, 0x95, 0x97, 0x90, 0x1d, 0xa7, + 0xdf, 0xff, 0x80, 0x3e, 0xbf, 0x3d, 0x51, 0x8a, 0xf9, 0xca, 0x67, 0xe2, + 0xe4, 0x87, 0x73, 0xc0, 0xf1, 0x8f, 0xce, 0x82, 0xbe, 0x25, 0xbe, 0x82, + 0xf5, 0xe5, 0xa7, 0xe8, 0xfe, 0xb7, 0x2a, 0x19, 0x97, 0x55, 0x38, 0xf7, + 0x69, 0xd4, 0x0f, 0x4b, 0x4b, 0x22, 0x86, 0xba, 0x4d, 0xdf, 0x03, 0xc0, + 0x65, 0xc8, 0x13, 0xdf, 0xfb, 0xe1, 0x54, 0x51, 0xbb, 0xf0, 0x9d, 0x64, + 0x15, 0xe2, 0x55, 0xfb, 0xa3, 0xca, 0x28, 0x8a, 0xcf, 0x36, 0x3f, 0x3e, + 0x4d, 0xc6, 0xe7, 0x5d, 0xb7, 0x8e, 0x5a, 0x2e, 0x97, 0xde, 0x89, 0x12, + 0xb7, 0x0f, 0x0b, 0xaf, 0xa0, 0xfb, 0x1a, 0xd4, 0xfe, 0x95, 0xcb, 0xf2, + 0xeb, 0x06, 0x5f, 0x9c, 0x6f, 0xde, 0xd3, 0x7a, 0x9d, 0x32, 0xbd, 0xdf, + 0x5b, 0xdc, 0x7b, 0x66, 0x98, 0xfb, 0xfc, 0x39, 0xf4, 0xa3, 0x12, 0xf3, + 0x69, 0x1a, 0xda, 0xd5, 0xef, 0x52, 0xdf, 0x22, 0x31, 0xcc, 0xf9, 0xf3, + 0xfd, 0xa0, 0xae, 0xb7, 0x30, 0xbe, 0xc2, 0x79, 0xe3, 0x0e, 0xeb, 0x75, + 0x80, 0x61, 0x39, 0xdf, 0x48, 0x79, 0x37, 0xa1, 0xeb, 0xb4, 0x61, 0x7e, + 0x5f, 0xe8, 0x3e, 0xd5, 0x97, 0x83, 0x9c, 0x4f, 0xc9, 0x8f, 0xa1, 0xc4, + 0xed, 0x29, 0xdd, 0x4f, 0xd0, 0xfd, 0x05, 0xd6, 0x07, 0xfd, 0x30, 0x71, + 0x30, 0x02, 0x2a, 0x9a, 0xfc, 0xf1, 0x11, 0xae, 0x9d, 0x18, 0x99, 0x05, + 0xfd, 0x86, 0x08, 0xf7, 0x09, 0x27, 0x58, 0xbf, 0x33, 0xfc, 0xbe, 0x73, + 0xc8, 0x4f, 0x65, 0xd2, 0x7e, 0xea, 0x5b, 0x25, 0x8e, 0x4d, 0xc3, 0xae, + 0x01, 0xf7, 0xfd, 0x06, 0x3e, 0xa6, 0xce, 0x9b, 0xdc, 0x2f, 0xe3, 0xbe, + 0x9a, 0x63, 0x8e, 0xc0, 0x9e, 0x81, 0x1c, 0xc6, 0x8b, 0x78, 0x17, 0x39, + 0xff, 0xe2, 0x3a, 0xef, 0xf8, 0x49, 0xfd, 0x1e, 0x2c, 0xbe, 0x4e, 0xd7, + 0x85, 0x83, 0xf4, 0x2e, 0x79, 0x61, 0x92, 0xfb, 0xea, 0xa2, 0x9f, 0xea, + 0xd1, 0xaf, 0xdb, 0x39, 0x1e, 0xe7, 0xfb, 0x07, 0xfe, 0xbe, 0x81, 0xae, + 0xbf, 0xe7, 0xd0, 0xff, 0x9c, 0xcc, 0xa5, 0x81, 0x97, 0x64, 0x89, 0x17, + 0xe7, 0x25, 0x89, 0x4a, 0x8e, 0xdb, 0xda, 0x27, 0x41, 0xcf, 0x3e, 0x89, + 0x77, 0xf2, 0xc0, 0x2b, 0xec, 0x97, 0x1d, 0x14, 0xa7, 0xed, 0xe8, 0xbf, + 0x78, 0xeb, 0x50, 0x85, 0x9b, 0x4f, 0x5c, 0x3c, 0xcf, 0x91, 0x5e, 0xb5, + 0x93, 0x39, 0xe2, 0xab, 0x11, 0x8f, 0xd0, 0xbd, 0x57, 0xed, 0x2c, 0x40, + 0xcf, 0xc4, 0x04, 0xdb, 0x37, 0xf4, 0x05, 0xd0, 0x57, 0x38, 0xce, 0x3a, + 0x7e, 0x57, 0xdd, 0x3e, 0x1e, 0xf4, 0xd5, 0xf7, 0xf1, 0xf2, 0xf7, 0x3b, + 0xc6, 0xd5, 0xad, 0x48, 0x60, 0x7d, 0xc7, 0x8b, 0xf7, 0xa7, 0xfc, 0x78, + 0x50, 0x78, 0xd1, 0xb8, 0xf4, 0xe2, 0xa8, 0xf0, 0x9c, 0xe5, 0x71, 0xe1, + 0x34, 0x55, 0x91, 0xbf, 0x70, 0x9f, 0x98, 0x89, 0x89, 0xcc, 0xea, 0x7e, + 0x7a, 0x13, 0x7e, 0x4a, 0xb0, 0xde, 0x76, 0xff, 0x08, 0xee, 0xa1, 0x31, + 0x8e, 0xd3, 0x5c, 0x23, 0xd7, 0x11, 0xac, 0xdf, 0xc7, 0xfc, 0xce, 0x40, + 0x3c, 0x23, 0xf6, 0xe1, 0x69, 0x8e, 0x1f, 0xe3, 0xea, 0x08, 0xdb, 0xfd, + 0x11, 0xec, 0xb6, 0xb5, 0xdd, 0xfd, 0xae, 0xdd, 0xba, 0x4e, 0xf1, 0xca, + 0x29, 0x97, 0xb8, 0xa0, 0x7a, 0xc7, 0xbe, 0x4a, 0x79, 0x24, 0xcc, 0x76, + 0x4a, 0xbe, 0x56, 0xfd, 0xff, 0x8e, 0xf0, 0x57, 0xef, 0x76, 0xef, 0xba, + 0x52, 0x5e, 0x17, 0x95, 0xeb, 0x30, 0x8f, 0xf3, 0x67, 0xaf, 0xe0, 0x4f, + 0xe5, 0x37, 0x2d, 0xb7, 0xf0, 0x7c, 0x79, 0xfd, 0x47, 0x95, 0x1d, 0xfd, + 0x90, 0x57, 0x64, 0x9c, 0xe8, 0x1e, 0xb2, 0xdd, 0xbc, 0x72, 0x87, 0xea, + 0xc0, 0xe8, 0x85, 0x41, 0xe4, 0x81, 0x0b, 0x83, 0xef, 0x72, 0x1d, 0xce, + 0x7e, 0xe9, 0xa2, 0xff, 0xaf, 0x92, 0xb1, 0xab, 0xf7, 0xe7, 0x15, 0xbf, + 0x1e, 0xb5, 0x1e, 0x3d, 0xf4, 0xbe, 0xff, 0x01, 0xfe, 0xf0, 0x11, 0xdc, + 0xa0, 0x1d, 0x00, 0x00, 0x00 }; static u8 bnx2_TPAT_b06FwText[] = { -/* 0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ - 0xc5, 0x57, 0x4d, 0x68, - 0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d, - 0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5, - 0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08, - 0xe4, 0xb2, 0x1d, 0x49, 0x36, 0x85, 0x1e, 0x5a, 0x9a, 0x43, 0xa0, 0x05, - 0x0f, 0x33, 0xeb, 0x34, 0x87, 0xc5, 0xdb, 0xaa, 0xc5, 0xbe, 0x94, 0xd6, - 0x95, 0xea, 0xe8, 0xb2, 0x68, 0xe2, 0x53, 0x0f, 0xc5, 0xd8, 0xb4, 0x54, - 0xd0, 0x53, 0x7b, 0x0a, 0x85, 0x5c, 0x4c, 0x69, 0x20, 0x85, 0x12, 0x44, - 0x0f, 0x21, 0xd4, 0xad, 0xa7, 0xcf, 0xfb, 0xcd, 0x8c, 0xbc, 0xbb, 0x95, - 0x5b, 0x1f, 0x02, 0x15, 0xac, 0x66, 0xe6, 0xfb, 0xde, 0xf7, 0xfb, 0x79, - 0x9f, 0xe7, 0x79, 0xbf, 0xf7, 0x6b, 0xca, 0x34, 0x49, 0xe5, 0xdf, 0x14, - 0x7e, 0x6f, 0x7f, 0xe3, 0xdb, 0x6f, 0x7f, 0xf5, 0xa5, 0x57, 0x2c, 0xa2, - 0x57, 0x5e, 0x92, 0x64, 0x5d, 0xa6, 0x2f, 0xe0, 0x4f, 0x21, 0x32, 0xab, - 0xf1, 0xf9, 0x47, 0x86, 0xec, 0x75, 0xce, 0x04, 0x0e, 0x19, 0x8a, 0x77, - 0x34, 0xbb, 0xe9, 0x10, 0xf9, 0x83, 0x15, 0x2b, 0xa4, 0x7f, 0xe5, 0x71, - 0x43, 0x25, 0x6e, 0x7f, 0xc1, 0xfb, 0xe7, 0xb9, 0x7b, 0xe7, 0xed, 0xa3, - 0xdb, 0x0a, 0x19, 0xa6, 0xd7, 0x31, 0xcc, 0x45, 0x32, 0x66, 0xe1, 0xf3, - 0xd3, 0xa5, 0x75, 0x8d, 0xa6, 0xab, 0xb1, 0x4c, 0x4a, 0xfa, 0x06, 0xad, - 0xf5, 0x30, 0x8e, 0xf3, 0x8e, 0x14, 0x66, 0xaa, 0x14, 0xde, 0x32, 0x48, - 0xf6, 0x7c, 0x29, 0xc8, 0x1c, 0xf4, 0x49, 0x14, 0xb8, 0x35, 0xf2, 0xcd, - 0x3c, 0xff, 0xa6, 0x2b, 0x93, 0xec, 0x3c, 0xce, 0xe7, 0x17, 0xd6, 0xa5, - 0x60, 0x7f, 0x43, 0x0a, 0xf7, 0x03, 0xde, 0x37, 0xd6, 0xb1, 0x2e, 0xf9, - 0xfb, 0xfc, 0xf4, 0x8c, 0xb0, 0x37, 0x4d, 0x9d, 0x06, 0xcd, 0xc8, 0x0e, - 0xfb, 0x5a, 0x14, 0xba, 0x2b, 0x4d, 0x85, 0xe6, 0xf1, 0x9b, 0xa0, 0x6d, - 0x97, 0xea, 0x81, 0x4b, 0xaa, 0xe2, 0xc8, 0x14, 0x36, 0x24, 0xfa, 0x65, - 0x4b, 0xc3, 0xef, 0x92, 0xd4, 0xde, 0xdf, 0x2a, 0xc7, 0x69, 0x50, 0x8a, - 0xb5, 0x44, 0x0d, 0x5e, 0x5b, 0xe1, 0x1f, 0xb8, 0x2b, 0xa6, 0x4c, 0xf3, - 0xf8, 0x4d, 0xe1, 0x3d, 0x82, 0x9d, 0x46, 0x41, 0x6b, 0xbc, 0x6f, 0x02, - 0xef, 0x58, 0x27, 0xc6, 0x0a, 0xc4, 0x3a, 0x2c, 0xac, 0xc3, 0xa1, 0x6e, - 0x7f, 0x03, 0xfb, 0x58, 0x68, 0x46, 0xa4, 0x53, 0x57, 0xac, 0x7d, 0x8a, - 0x12, 0x53, 0xa1, 0xe4, 0xac, 0x46, 0xfe, 0x65, 0x15, 0xdf, 0xcf, 0x51, - 0x6c, 0x4a, 0xb0, 0xe9, 0x96, 0xf8, 0xd5, 0xd0, 0xaf, 0xa3, 0x7d, 0x86, - 0x92, 0xc6, 0x29, 0x49, 0xf6, 0xbe, 0x8f, 0xf6, 0x05, 0x33, 0xa2, 0xef, - 0xe1, 0x29, 0xe1, 0xfb, 0x14, 0x8f, 0x87, 0x6f, 0x89, 0x14, 0x87, 0xcc, - 0x20, 0xb3, 0x28, 0xcd, 0x2a, 0x5f, 0x6e, 0x2f, 0xda, 0xe2, 0x6c, 0x1c, - 0x3b, 0xd8, 0xf5, 0x5f, 0xa5, 0x8e, 0x49, 0xb1, 0xea, 0xc1, 0xa6, 0xef, - 0x98, 0x6d, 0xe0, 0xe4, 0x0b, 0x3c, 0xbf, 0xc6, 0xed, 0xfc, 0x87, 0x76, - 0x8b, 0x14, 0xcf, 0x31, 0x43, 0x6a, 0x51, 0xd1, 0xd7, 0x30, 0x83, 0x5b, - 0x2f, 0x93, 0x2f, 0xe2, 0x61, 0xe0, 0xdd, 0xc4, 0x9e, 0x74, 0x60, 0x9b, - 0xf8, 0x32, 0xc5, 0x4d, 0x83, 0xec, 0xd5, 0x2d, 0xf4, 0x7c, 0xdc, 0x53, - 0x10, 0x67, 0xc6, 0x49, 0x2d, 0xfd, 0x18, 0xd7, 0xdf, 0x62, 0x5d, 0xb1, - 0x69, 0xd0, 0x0c, 0x75, 0x5e, 0xcf, 0xf3, 0x3b, 0x6e, 0x9e, 0xeb, 0x9e, - 0xb3, 0xfc, 0x3e, 0xad, 0x34, 0x35, 0x5a, 0x34, 0xf1, 0x44, 0xdc, 0x1c, - 0xc4, 0x46, 0x2d, 0xe7, 0x9f, 0x2a, 0xd7, 0xfa, 0x48, 0x42, 0xe8, 0xe9, - 0xcf, 0xbd, 0xdf, 0xf0, 0xde, 0x97, 0xd7, 0x85, 0x7d, 0x9e, 0xef, 0xae, - 0x3e, 0xcd, 0x5e, 0x93, 0x0b, 0xfb, 0x3c, 0x5f, 0x6b, 0xf1, 0x7c, 0x36, - 0xf6, 0xc6, 0x9c, 0x24, 0x5a, 0x1b, 0xb8, 0x46, 0xd4, 0xc3, 0xba, 0x1c, - 0x3c, 0x07, 0x4d, 0xac, 0xdd, 0x5e, 0xb6, 0x24, 0x83, 0x12, 0x27, 0x7f, - 0x11, 0x3c, 0xf0, 0x43, 0xc7, 0xfe, 0x53, 0xa8, 0xd4, 0x68, 0xcf, 0xad, - 0x53, 0x37, 0x6b, 0x52, 0x92, 0x75, 0x29, 0xc8, 0x64, 0x8c, 0x5f, 0xa3, - 0x5d, 0xe7, 0xf3, 0x7c, 0xcd, 0x75, 0x81, 0x33, 0xb1, 0x5f, 0x73, 0x8d, - 0x66, 0xd1, 0xbf, 0x62, 0x6e, 0x91, 0x8b, 0x98, 0xcb, 0x88, 0xc9, 0xbc, - 0x78, 0x4f, 0x32, 0x17, 0xfd, 0x14, 0xcb, 0x2d, 0xdb, 0x4c, 0xc8, 0x6e, - 0x06, 0x0a, 0x99, 0xb2, 0x67, 0xc2, 0x26, 0xa6, 0x76, 0x66, 0xd0, 0x43, - 0xe5, 0x1d, 0xc1, 0xe3, 0xb4, 0xff, 0x30, 0xbf, 0xb7, 0xd4, 0xa4, 0xfb, - 0x59, 0x83, 0xee, 0x66, 0x24, 0x47, 0x1c, 0xab, 0x86, 0x49, 0x1f, 0x64, - 0xd5, 0x3e, 0xc0, 0x65, 0x27, 0x39, 0xa3, 0x40, 0x67, 0x9b, 0xee, 0x03, - 0xb0, 0xc4, 0x06, 0x0e, 0x31, 0xf6, 0x5c, 0x3d, 0x79, 0x4f, 0xb7, 0xcf, - 0x6c, 0x3a, 0xf6, 0x7b, 0x21, 0xb3, 0xf3, 0x86, 0x8a, 0xd6, 0xe1, 0x38, - 0x7c, 0x1d, 0xfe, 0x26, 0x5d, 0x87, 0x5e, 0x64, 0xc4, 0x63, 0xee, 0xc0, - 0xa0, 0xfd, 0x5e, 0x8d, 0xac, 0x5d, 0x95, 0xa2, 0x7e, 0x83, 0xdc, 0x45, - 0xdb, 0x22, 0x59, 0x6e, 0xc8, 0x88, 0xdf, 0xdc, 0x6e, 0x4e, 0xeb, 0xae, - 0x46, 0x87, 0xce, 0x77, 0x75, 0x9a, 0x4e, 0x5c, 0x9d, 0xd8, 0xc6, 0xa0, - 0xb9, 0xf7, 0x0d, 0x29, 0xec, 0xf3, 0xfa, 0x39, 0xce, 0x46, 0x19, 0x67, - 0x55, 0x0a, 0x6e, 0xd5, 0x68, 0x7e, 0xe7, 0x6f, 0x79, 0xe0, 0x20, 0xc6, - 0xe0, 0xf1, 0x66, 0xcb, 0x56, 0x68, 0x12, 0x6d, 0xbb, 0xdc, 0x77, 0x54, - 0xb6, 0xf3, 0x18, 0x79, 0x1e, 0xb8, 0xcf, 0x53, 0xc0, 0xfc, 0x7e, 0x9d, - 0x7d, 0x6a, 0x34, 0xb7, 0xc3, 0xba, 0xc0, 0x73, 0x97, 0xbf, 0x79, 0x6d, - 0x13, 0x14, 0x61, 0x37, 0xd1, 0x72, 0x03, 0xfb, 0x97, 0x85, 0x06, 0x22, - 0xec, 0x56, 0x76, 0x26, 0xf1, 0x14, 0x71, 0x50, 0x0a, 0x3e, 0x73, 0x5e, - 0xa8, 0x53, 0x08, 0x5c, 0x55, 0xac, 0x67, 0x8b, 0x16, 0x9a, 0xdb, 0xa2, - 0x0f, 0x6d, 0x03, 0xee, 0x33, 0xc7, 0xfa, 0xf0, 0x3d, 0xa8, 0xd6, 0x20, - 0x03, 0xf3, 0x14, 0xb3, 0x68, 0x62, 0xaf, 0x6b, 0x2e, 0xdb, 0xb3, 0x6d, - 0xbc, 0xac, 0x91, 0xbd, 0xbc, 0x8b, 0xd1, 0xf7, 0x7b, 0xd8, 0xef, 0x4d, - 0xce, 0x35, 0x8e, 0xf5, 0x17, 0x62, 0xfb, 0x79, 0xec, 0x79, 0x61, 0x35, - 0xe5, 0xbe, 0x81, 0x46, 0xce, 0x4e, 0x6c, 0xaa, 0x88, 0xbd, 0x8c, 0xc0, - 0x87, 0x3f, 0xfc, 0x2c, 0xd7, 0x3c, 0x70, 0xb8, 0x35, 0x03, 0x6c, 0x6c, - 0x2b, 0x85, 0x9e, 0x1d, 0x8c, 0x9b, 0xb8, 0x0a, 0xfc, 0x0a, 0x8c, 0xd8, - 0x6e, 0xbd, 0x97, 0x53, 0x2a, 0xe6, 0xba, 0xc6, 0x73, 0x21, 0xe7, 0x38, - 0xab, 0xbf, 0x03, 0x27, 0x22, 0xaa, 0xd3, 0xe2, 0x41, 0x9d, 0xae, 0x0e, - 0xea, 0x34, 0x77, 0x43, 0x47, 0x1c, 0xf2, 0xbc, 0xdb, 0x62, 0x0d, 0x02, - 0x6b, 0x87, 0xed, 0xec, 0xa6, 0x22, 0xf3, 0x3a, 0xd0, 0x7f, 0x40, 0xb4, - 0x35, 0xd0, 0x11, 0x37, 0x75, 0x68, 0x6c, 0x99, 0x2e, 0xfe, 0x84, 0xe8, - 0xe2, 0x80, 0x7d, 0x79, 0xfc, 0xc2, 0x27, 0xc2, 0x9e, 0x65, 0x60, 0x7e, - 0x75, 0x20, 0x23, 0x1f, 0x20, 0x5f, 0xee, 0x07, 0xc8, 0x83, 0x6d, 0xfc, - 0xd6, 0x91, 0x1b, 0x19, 0x1b, 0xce, 0x13, 0x8f, 0x81, 0xcf, 0x06, 0xfa, - 0x2e, 0xa1, 0x8d, 0xf3, 0x16, 0xdb, 0xea, 0xd4, 0x76, 0xa7, 0x28, 0xad, - 0x72, 0x91, 0xc9, 0xb9, 0xe8, 0x14, 0xf8, 0x34, 0x81, 0xfc, 0x72, 0x47, - 0x19, 0xcd, 0x45, 0xc8, 0x59, 0x8d, 0xd3, 0xc8, 0x3d, 0x3f, 0x47, 0x3b, - 0x8f, 0xf7, 0x33, 0x3c, 0x27, 0xf0, 0x7d, 0x1a, 0xb6, 0xc3, 0x79, 0xa8, - 0xf2, 0x7b, 0x5a, 0x0e, 0x02, 0xef, 0x76, 0x0c, 0xd8, 0x5b, 0xd0, 0x0b, - 0xc7, 0xbb, 0x86, 0x7c, 0xc1, 0x31, 0xaf, 0x21, 0xa6, 0x3a, 0xe6, 0x36, - 0x69, 0xfe, 0x80, 0x62, 0xa5, 0xcc, 0x4f, 0xe1, 0x71, 0x7e, 0x6a, 0x0a, - 0x1e, 0x24, 0x99, 0x09, 0x1f, 0xd6, 0x6d, 0xa5, 0x53, 0xc6, 0x8e, 0xfc, - 0x00, 0x1a, 0x0e, 0x94, 0x3c, 0xdf, 0xc4, 0x19, 0x11, 0x01, 0x77, 0x1f, - 0xda, 0x8d, 0xa0, 0xdd, 0x70, 0x48, 0xbb, 0xe1, 0xff, 0xd4, 0x2e, 0x74, - 0x09, 0x8d, 0xdc, 0x05, 0xa7, 0x3e, 0xe8, 0x9f, 0xa4, 0x63, 0xd6, 0x30, - 0x6b, 0xd9, 0xa2, 0x7b, 0x4b, 0xcf, 0xa2, 0xe5, 0xbf, 0x3e, 0xab, 0x96, - 0x63, 0xd6, 0xb2, 0xca, 0x5a, 0x6e, 0x0c, 0x6b, 0xf9, 0x53, 0xf8, 0x17, - 0x9a, 0xbc, 0xa0, 0x36, 0x48, 0x5b, 0x04, 0x0e, 0x3b, 0x75, 0x52, 0x6e, - 0x3c, 0xe1, 0x1b, 0x73, 0x38, 0x1c, 0xe0, 0xdf, 0x81, 0x86, 0x3e, 0x69, - 0xb4, 0x1d, 0x39, 0x4f, 0xf5, 0xec, 0xe6, 0x96, 0xb0, 0x51, 0x49, 0x47, - 0xdc, 0xbf, 0xb3, 0x64, 0x5b, 0x96, 0x3c, 0xac, 0x79, 0xa8, 0x7e, 0x27, - 0xbf, 0xa6, 0x79, 0x3c, 0x4f, 0x6c, 0x81, 0xeb, 0xd6, 0x8f, 0x80, 0x51, - 0xda, 0x63, 0x9e, 0x3b, 0xe6, 0x9a, 0xe0, 0x17, 0xbe, 0xa1, 0x05, 0x0d, - 0x7c, 0xad, 0xc1, 0x4e, 0xdd, 0x29, 0xf4, 0x73, 0x17, 0xe3, 0xee, 0xf5, - 0x98, 0x5f, 0x06, 0xe9, 0x37, 0x9d, 0xe6, 0x55, 0x91, 0x73, 0xe7, 0xcd, - 0x75, 0x62, 0xed, 0xf1, 0x79, 0x87, 0xfe, 0x41, 0x8d, 0x14, 0xa1, 0xf7, - 0xc9, 0x52, 0xef, 0x2f, 0x20, 0x46, 0x93, 0xf8, 0x66, 0xcd, 0x9f, 0x2e, - 0x35, 0x3f, 0x8d, 0x27, 0xb7, 0x5d, 0x54, 0x0b, 0xee, 0x80, 0x87, 0x3b, - 0x8c, 0x6b, 0x1d, 0xf9, 0x8d, 0xe7, 0xff, 0x7b, 0xbe, 0xe9, 0x30, 0xb6, - 0x8e, 0xf5, 0x03, 0x5a, 0x80, 0xee, 0xd0, 0x7e, 0xc0, 0xb6, 0xec, 0x53, - 0xd9, 0x9a, 0xa5, 0xed, 0xa7, 0x63, 0xb6, 0x68, 0x3f, 0x60, 0x3b, 0xd6, - 0xc5, 0x73, 0xa4, 0xdc, 0xe4, 0xf3, 0x38, 0x60, 0x5d, 0xc0, 0xaf, 0x8d, - 0x36, 0xae, 0x19, 0xd8, 0x9f, 0xcf, 0x66, 0x5e, 0x27, 0xd7, 0x13, 0x7c, - 0x7e, 0x8f, 0x9d, 0xd3, 0xc7, 0xda, 0xb8, 0x00, 0xbe, 0x7f, 0x4b, 0xfd, - 0x4f, 0x6d, 0xbc, 0x06, 0x2d, 0x5c, 0x51, 0x0b, 0x6d, 0x6c, 0xe3, 0x79, - 0x01, 0xdf, 0xaf, 0x8d, 0x69, 0xa3, 0xf2, 0x7b, 0xfa, 0xf9, 0x9c, 0xf4, - 0x9b, 0xe2, 0x6c, 0xe5, 0xf9, 0x94, 0x1d, 0x8a, 0xb5, 0x52, 0x07, 0x6b, - 0xc7, 0x3a, 0x98, 0x44, 0xae, 0x18, 0xe1, 0xb8, 0x12, 0xba, 0xb6, 0x99, - 0x12, 0x6b, 0x62, 0xf8, 0xfc, 0xfa, 0x7f, 0xe9, 0x82, 0xc0, 0x23, 0x31, - 0x37, 0x6a, 0x0c, 0x3e, 0x0f, 0xf2, 0xfc, 0x8a, 0x8b, 0xfe, 0xaa, 0xd6, - 0x10, 0xd8, 0xf3, 0x59, 0xcb, 0x78, 0xa0, 0xbe, 0x73, 0xe6, 0xa1, 0x05, - 0xce, 0x01, 0x8f, 0xf3, 0x3d, 0x27, 0x40, 0x5b, 0x1b, 0xf1, 0x67, 0x4c, - 0x36, 0xa4, 0xf5, 0x7d, 0x83, 0xfd, 0xa0, 0xb3, 0x93, 0x6a, 0x2c, 0x1d, - 0x9a, 0x7a, 0x82, 0x13, 0xf3, 0x28, 0x1a, 0xc2, 0xa9, 0x23, 0x70, 0xfa, - 0xf0, 0x18, 0xa7, 0xa8, 0xc4, 0x29, 0x12, 0x38, 0xfd, 0xb1, 0xc4, 0xe9, - 0x0f, 0x4f, 0xc1, 0xe9, 0xc3, 0x67, 0xc0, 0xc9, 0xa0, 0x3d, 0xa7, 0x89, - 0x73, 0x56, 0x17, 0x35, 0xe9, 0xa1, 0x7b, 0x52, 0x4d, 0x75, 0x52, 0xdc, - 0x6d, 0x73, 0x8f, 0x86, 0xeb, 0x0e, 0xdb, 0x7a, 0x80, 0xf5, 0xa5, 0xc0, - 0xee, 0xfa, 0x58, 0xed, 0x91, 0xc0, 0xbe, 0x5d, 0xe2, 0x74, 0x1d, 0x38, - 0xb5, 0x4b, 0x9c, 0xb6, 0x87, 0x70, 0xda, 0x1e, 0xc1, 0x89, 0xf3, 0x49, - 0xcb, 0xd8, 0xee, 0x55, 0x18, 0x55, 0xf8, 0xe8, 0x74, 0xdb, 0x9c, 0xc6, - 0xfe, 0xcf, 0x51, 0xfa, 0x63, 0x95, 0xeb, 0x5a, 0x60, 0xf7, 0xaa, 0x2a, - 0x8b, 0xf3, 0x80, 0xdf, 0x9f, 0xd4, 0x27, 0x98, 0xcb, 0x0f, 0x5c, 0x8e, - 0x23, 0xea, 0x57, 0xa7, 0xca, 0x43, 0xcf, 0xab, 0xa8, 0xad, 0xf0, 0xcd, - 0x36, 0xaa, 0xd4, 0x86, 0xde, 0x15, 0xd4, 0xe5, 0xe1, 0x71, 0x5d, 0x5e, - 0xc4, 0xe0, 0x7a, 0x59, 0x97, 0xef, 0x39, 0x5c, 0x97, 0x2f, 0x6a, 0x34, - 0xb9, 0x51, 0x62, 0xc9, 0x9c, 0x9e, 0x42, 0xdf, 0x25, 0x81, 0x79, 0x8a, - 0xfc, 0xbd, 0x89, 0xfd, 0x47, 0x82, 0x9b, 0xa8, 0xb1, 0x4a, 0xde, 0xa2, - 0x86, 0xa5, 0x30, 0x2b, 0x62, 0xf5, 0xc5, 0xd6, 0x5d, 0x9f, 0x20, 0x4f, - 0x1b, 0x1d, 0x15, 0x75, 0xfd, 0xfd, 0x8c, 0xf3, 0x33, 0x5d, 0x4e, 0x7a, - 0x14, 0x9f, 0xf1, 0xae, 0xe5, 0xc0, 0xdc, 0x7f, 0xeb, 0x3c, 0x9f, 0x33, - 0xf5, 0xd5, 0xa0, 0x85, 0xf6, 0x81, 0x41, 0xa8, 0x7d, 0x70, 0x4f, 0xa1, - 0x38, 0x38, 0x2f, 0xa1, 0xc6, 0xc1, 0x37, 0x7c, 0x92, 0x6c, 0xb6, 0x23, - 0x7b, 0x4d, 0x70, 0x21, 0x26, 0x1f, 0xeb, 0xf4, 0x33, 0x71, 0x57, 0xe9, - 0x28, 0x9e, 0x81, 0xda, 0x92, 0x0c, 0x9c, 0xf3, 0x88, 0x89, 0x65, 0xa4, - 0x03, 0xd4, 0x41, 0x38, 0xfb, 0x83, 0x55, 0xc4, 0xe5, 0x2c, 0x70, 0xcb, - 0x54, 0xf8, 0xbe, 0xa9, 0x17, 0xf7, 0x1c, 0x54, 0x35, 0x22, 0x5e, 0x8f, - 0x4a, 0x7e, 0x88, 0x3a, 0x4b, 0x6a, 0xf7, 0xc9, 0x8a, 0x5c, 0xf0, 0x1c, - 0xe7, 0x48, 0x37, 0xe3, 0xda, 0xf9, 0xac, 0x21, 0xdf, 0xe0, 0x5c, 0x7e, - 0x88, 0x18, 0xe2, 0xfd, 0x80, 0xcf, 0x16, 0x85, 0xeb, 0x6f, 0xdc, 0x67, - 0x96, 0x90, 0x6b, 0x68, 0x0a, 0x79, 0x0f, 0x79, 0x77, 0x96, 0x71, 0xf2, - 0x23, 0xc6, 0x4b, 0x9c, 0x1b, 0xe7, 0xe4, 0x62, 0x9e, 0x5f, 0x6b, 0x05, - 0x7f, 0x71, 0x87, 0x41, 0xfc, 0x36, 0xfb, 0x2e, 0xe7, 0xdb, 0x2f, 0x2b, - 0x74, 0x44, 0x82, 0x8f, 0xe6, 0xcb, 0xc8, 0xc3, 0xe7, 0xe0, 0xe3, 0x0b, - 0x2d, 0x16, 0xf5, 0x56, 0xe5, 0xf3, 0xc9, 0xd8, 0x18, 0x1f, 0x29, 0xa3, - 0xdf, 0x3e, 0xf8, 0xbc, 0x52, 0xce, 0x57, 0xf1, 0xe3, 0x57, 0xe0, 0xc7, - 0x61, 0xd9, 0xcf, 0x77, 0x16, 0x1d, 0x36, 0xbc, 0x3e, 0xe6, 0x11, 0xdb, - 0x9b, 0xda, 0xe8, 0x18, 0x5f, 0x1a, 0xf3, 0xff, 0xfd, 0x90, 0xff, 0x34, - 0xef, 0xc9, 0x8c, 0x0a, 0x0e, 0xe2, 0xef, 0x3d, 0x7d, 0xd4, 0xf7, 0x17, - 0x6a, 0xf1, 0x7d, 0xb6, 0xe0, 0x9e, 0x83, 0x67, 0x76, 0x38, 0xb4, 0x36, - 0x75, 0x6c, 0xec, 0x87, 0x18, 0x7b, 0x15, 0x79, 0x84, 0x7c, 0x05, 0x77, - 0xa6, 0x90, 0xf0, 0x9e, 0x5d, 0xa9, 0xe2, 0x03, 0x4e, 0xd0, 0xe5, 0xb4, - 0xe4, 0x82, 0x5c, 0x70, 0x81, 0xeb, 0xb4, 0xd5, 0x4d, 0x70, 0x21, 0x05, - 0x17, 0xe0, 0xd7, 0xd1, 0xbc, 0x59, 0xe0, 0xcc, 0x39, 0x07, 0xdf, 0x19, - 0xf3, 0x82, 0x79, 0xc0, 0x9c, 0x78, 0xc2, 0x85, 0x2b, 0x3d, 0xc3, 0xd8, - 0xfd, 0x2f, 0x3c, 0x78, 0x57, 0xf0, 0x80, 0xf9, 0x58, 0xe4, 0x85, 0x2e, - 0x70, 0x48, 0xca, 0xbc, 0x50, 0xe8, 0x9c, 0xeb, 0x1b, 0xd6, 0x78, 0xa1, - 0x8d, 0x2d, 0x68, 0xa3, 0xad, 0x70, 0xbd, 0xc3, 0xba, 0x60, 0x3f, 0xd6, - 0xc6, 0x49, 0x7e, 0x85, 0x46, 0xd2, 0xbe, 0x6d, 0x55, 0xf9, 0x21, 0x85, - 0x2e, 0xba, 0xa5, 0x46, 0xd2, 0x52, 0x23, 0xb0, 0x89, 0x95, 0x16, 0xe7, - 0x7a, 0xdb, 0x0a, 0x91, 0x17, 0xba, 0x62, 0xcc, 0x98, 0x8a, 0x3b, 0x09, - 0xeb, 0x96, 0xf3, 0xe9, 0x50, 0x1e, 0x2d, 0xef, 0xa5, 0x1d, 0x71, 0x2f, - 0xfd, 0x8a, 0x3e, 0x9a, 0x47, 0x67, 0x90, 0x43, 0xf8, 0x5e, 0x3a, 0xa7, - 0xf3, 0xbd, 0x14, 0xba, 0xd3, 0x87, 0xef, 0xa5, 0xc9, 0xc8, 0xbd, 0xb4, - 0xf2, 0xe5, 0xf6, 0x93, 0xf2, 0x69, 0x15, 0x13, 0xce, 0xa9, 0x02, 0xf3, - 0x13, 0x6a, 0xbf, 0xca, 0x86, 0xf3, 0x0d, 0x6b, 0xb9, 0xcc, 0x51, 0xa8, - 0xb5, 0xee, 0x67, 0x15, 0xe7, 0xdf, 0xc0, 0x3c, 0xf8, 0xee, 0x9f, 0xc4, - 0x79, 0xa3, 0xe4, 0xfc, 0x54, 0xe1, 0xd3, 0x1f, 0xe6, 0xfd, 0x1b, 0xfa, - 0x28, 0xef, 0xab, 0x71, 0x2a, 0xde, 0x17, 0x63, 0x3e, 0x54, 0x9a, 0x38, - 0xdb, 0x96, 0x91, 0x6b, 0x66, 0xf8, 0xbe, 0x85, 0x5c, 0xe0, 0xd5, 0x71, - 0xef, 0x98, 0xe1, 0xb1, 0xd3, 0x0c, 0xe7, 0x4d, 0x03, 0xbc, 0x17, 0x9c, - 0x3d, 0x12, 0xf7, 0x01, 0xac, 0x7b, 0x86, 0xab, 0xab, 0x51, 0x2e, 0xbe, - 0x88, 0x0b, 0x45, 0xb5, 0x97, 0xaa, 0xcd, 0x19, 0x6a, 0x5b, 0x2e, 0xb1, - 0x2e, 0x62, 0xfd, 0xa0, 0xb8, 0x8f, 0xd3, 0x2e, 0x6a, 0xb1, 0x43, 0xd4, - 0x39, 0x77, 0x70, 0x9f, 0x4b, 0x06, 0x8f, 0xf2, 0x07, 0x0d, 0x95, 0xba, - 0xc7, 0x3e, 0x5d, 0xac, 0xd7, 0x36, 0x6f, 0xe3, 0xed, 0xdd, 0x41, 0x15, - 0x53, 0xee, 0xe7, 0xb6, 0x7f, 0xe0, 0xbc, 0x45, 0x1d, 0x37, 0x32, 0x67, - 0xf5, 0xce, 0x7f, 0xff, 0x06, 0x63, 0xe1, 0x4b, 0x7b, 0x30, 0x12, 0x00, - 0x00, 0x00 }; + 0xbd, 0x59, 0x6f, 0x70, 0x5c, 0xd5, 0x7d, 0x3d, 0x6f, 0xf7, 0xed, 0xee, + 0x93, 0xb4, 0x92, 0x9e, 0x90, 0x0c, 0xab, 0x56, 0x8d, 0xf6, 0x59, 0x6f, + 0xa5, 0xc5, 0xab, 0xd8, 0x6f, 0x2d, 0xb9, 0xac, 0x87, 0x37, 0xcd, 0xb3, + 0x2c, 0x29, 0x8b, 0xec, 0xd8, 0xeb, 0x42, 0x66, 0xe4, 0x09, 0x1d, 0x0b, + 0x59, 0xd8, 0xc2, 0x18, 0xa2, 0x12, 0x3e, 0xa8, 0x13, 0x4f, 0xbd, 0xe8, + 0x9f, 0x85, 0xbd, 0xd2, 0x23, 0x02, 0x2c, 0x3b, 0x93, 0x0e, 0x1e, 0xf9, + 0x8f, 0x18, 0x58, 0x6b, 0xa1, 0xfd, 0x92, 0x69, 0xc3, 0x44, 0x13, 0x1b, + 0xec, 0x90, 0x38, 0x4e, 0xa7, 0x5f, 0xcc, 0xb4, 0x9d, 0xaa, 0x80, 0x29, + 0x50, 0x70, 0xdc, 0xce, 0xa4, 0x63, 0x0a, 0xf5, 0xed, 0xb9, 0x6f, 0x57, + 0x46, 0x38, 0x4e, 0x3f, 0xd6, 0x33, 0x8b, 0x76, 0xef, 0x7b, 0xf7, 0xde, + 0xdf, 0xbd, 0xbf, 0x73, 0xce, 0xef, 0xdc, 0xcb, 0x6a, 0x1f, 0xca, 0x51, + 0xfa, 0x57, 0xc9, 0x4f, 0xfb, 0x23, 0x43, 0x4f, 0x6f, 0x58, 0x6b, 0xad, + 0x95, 0xbf, 0x95, 0x00, 0x54, 0xfc, 0x3f, 0xfe, 0xf3, 0x03, 0xfa, 0x72, + 0x1c, 0xf2, 0x03, 0xcd, 0x67, 0x2f, 0xae, 0xee, 0x30, 0xa1, 0xf9, 0xed, + 0x87, 0x5a, 0x76, 0x9b, 0x80, 0x93, 0x4f, 0x44, 0x37, 0xe3, 0x7f, 0x44, + 0xb6, 0x4e, 0x85, 0x6c, 0xff, 0x23, 0xfb, 0x8b, 0x75, 0x6f, 0xdc, 0x67, + 0x5c, 0x3f, 0xe1, 0x87, 0xa6, 0xdb, 0x93, 0x9a, 0xde, 0x0c, 0xad, 0x81, + 0x7d, 0x7e, 0xd4, 0xb2, 0x2b, 0x88, 0xaa, 0xe5, 0xb1, 0x80, 0x93, 0x39, + 0xc3, 0xda, 0x83, 0x84, 0x7e, 0x8e, 0x0b, 0x72, 0x38, 0xc7, 0x99, 0x3c, + 0x70, 0x28, 0xa7, 0xe0, 0x2a, 0xc7, 0x1c, 0xcf, 0x6b, 0x58, 0xf2, 0x7b, + 0xd3, 0xf5, 0x95, 0xd9, 0xc8, 0x98, 0x53, 0x07, 0x45, 0xc8, 0x44, 0xf6, + 0x0f, 0x6c, 0x33, 0x7e, 0x08, 0xe1, 0xd4, 0x5c, 0x3b, 0x32, 0xab, 0xcf, + 0x6a, 0xd8, 0xe9, 0x36, 0xf4, 0x69, 0x36, 0xf8, 0x8e, 0x82, 0xd4, 0x7d, + 0x1a, 0x7a, 0x0b, 0x71, 0x64, 0x0b, 0x59, 0x38, 0x85, 0x31, 0x7e, 0x34, + 0x84, 0xa6, 0x34, 0x6d, 0xdd, 0xd4, 0xdd, 0xf2, 0x1d, 0x84, 0xa7, 0xae, + 0x8b, 0x6b, 0x49, 0x1d, 0x6f, 0x6f, 0x14, 0xa2, 0xd2, 0x46, 0xb6, 0xa2, + 0x3d, 0x0b, 0xbf, 0x6d, 0x58, 0x5b, 0xfc, 0x0a, 0x3a, 0xbf, 0x6e, 0xc6, + 0xa7, 0x94, 0x07, 0x1f, 0xf4, 0xd9, 0xd0, 0x14, 0x3b, 0xaa, 0x35, 0xe5, + 0x1b, 0x30, 0x51, 0xd0, 0x71, 0xa8, 0x50, 0x87, 0xb1, 0x02, 0x0e, 0xf8, + 0x37, 0x04, 0x31, 0xa7, 0xc3, 0xf9, 0x4e, 0xcb, 0x01, 0xec, 0xcb, 0x0d, + 0x63, 0x77, 0x2e, 0x85, 0xc3, 0x05, 0x19, 0x63, 0x14, 0xa3, 0x05, 0x15, + 0xc1, 0x29, 0x23, 0xf2, 0x73, 0xdc, 0xe9, 0x99, 0x10, 0x63, 0x56, 0x08, + 0x23, 0x56, 0x1c, 0xe3, 0xae, 0x8f, 0xeb, 0x0c, 0x61, 0xd4, 0xbc, 0x21, + 0x06, 0x2c, 0xc3, 0x1a, 0x87, 0x68, 0x3c, 0x6f, 0x19, 0x91, 0x4e, 0x3f, + 0x9c, 0xef, 0x9b, 0x11, 0x8c, 0x33, 0xf6, 0x31, 0xaf, 0xdf, 0x18, 0x3a, + 0x6f, 0xf5, 0x73, 0xd8, 0x4f, 0xc7, 0xc4, 0x57, 0xfb, 0x46, 0xc7, 0x91, + 0x88, 0x4c, 0xc0, 0x87, 0xbe, 0xba, 0x56, 0xf6, 0x6b, 0x8a, 0x4e, 0xc0, + 0x88, 0x73, 0x9c, 0x6c, 0xb0, 0xdd, 0xe1, 0x18, 0x59, 0xf6, 0x37, 0xa2, + 0x67, 0x20, 0xc7, 0x6a, 0xe0, 0xef, 0x76, 0xf6, 0x57, 0xe0, 0xb3, 0x63, + 0xd1, 0x11, 0xf6, 0x39, 0x67, 0xa9, 0x78, 0x93, 0x9f, 0x3e, 0xdd, 0x90, + 0x99, 0x55, 0x42, 0x6c, 0x3f, 0x04, 0x3e, 0x37, 0x2b, 0x70, 0x22, 0x63, + 0x61, 0x84, 0xeb, 0xd6, 0xd8, 0x36, 0xc9, 0xb6, 0x80, 0x69, 0x71, 0x7c, + 0xe8, 0x9d, 0x85, 0x95, 0x98, 0x58, 0xce, 0xcd, 0xef, 0x6b, 0xe7, 0x18, + 0x6e, 0x31, 0xa7, 0xf2, 0x9d, 0xcd, 0xee, 0x4d, 0xf1, 0x88, 0xba, 0xf2, + 0xf9, 0xb0, 0xd2, 0xc1, 0x36, 0x47, 0x6d, 0xc0, 0x21, 0x17, 0x5a, 0xd0, + 0xd4, 0x38, 0x8f, 0x86, 0xf7, 0x72, 0xc3, 0x4a, 0x77, 0xc1, 0x51, 0xba, + 0xe6, 0x3b, 0x14, 0x67, 0x5e, 0x55, 0x3a, 0x67, 0x65, 0xdc, 0x42, 0x3c, + 0x6b, 0x29, 0x8c, 0xf9, 0x07, 0x32, 0x5e, 0x27, 0xaa, 0xdc, 0x14, 0x6b, + 0x62, 0x3e, 0x54, 0x98, 0xdd, 0xca, 0x96, 0x79, 0x21, 0xd2, 0xc9, 0xb4, + 0xd2, 0x33, 0x0f, 0x2d, 0x6c, 0xdb, 0x5a, 0x6e, 0xea, 0x30, 0xb2, 0xab, + 0x4c, 0x1c, 0x77, 0xa3, 0xb8, 0x64, 0xf9, 0x70, 0x62, 0x55, 0x19, 0x54, + 0x53, 0xe1, 0x07, 0xe1, 0xcb, 0x16, 0xd4, 0x2a, 0x7e, 0xbf, 0xb6, 0x43, + 0xc5, 0x58, 0x7b, 0x8f, 0xd2, 0xc9, 0x3e, 0x01, 0xe6, 0xf9, 0x74, 0x2e, + 0x8d, 0x30, 0xb1, 0x53, 0x61, 0xc7, 0x22, 0x79, 0xee, 0xcd, 0xdb, 0x56, + 0x2c, 0xfe, 0xb8, 0xc4, 0x63, 0x8d, 0x11, 0x91, 0x7b, 0x53, 0x69, 0xc7, + 0xe2, 0x67, 0xb9, 0x0f, 0x7e, 0x53, 0xc5, 0xaf, 0xac, 0x00, 0x16, 0x77, + 0x58, 0xcc, 0xa9, 0x8e, 0x20, 0xdb, 0xcf, 0x78, 0xed, 0xf2, 0x37, 0xf4, + 0xae, 0xaf, 0xec, 0x43, 0x71, 0x0f, 0x46, 0xdd, 0x26, 0xc6, 0x5c, 0xdc, + 0x83, 0xed, 0x5c, 0xef, 0xbf, 0x06, 0xe4, 0xd7, 0xaf, 0xdd, 0x6a, 0xdb, + 0xc9, 0x38, 0x7d, 0xb6, 0xb9, 0xb8, 0xda, 0x5f, 0x0f, 0xd4, 0xb6, 0xe3, + 0x30, 0x73, 0xdc, 0x99, 0xbc, 0x1b, 0x59, 0xef, 0x79, 0x9d, 0xbe, 0x65, + 0xb6, 0x16, 0x7d, 0xab, 0xbc, 0x7d, 0xd3, 0xb7, 0xcd, 0x0a, 0xf1, 0x66, + 0x32, 0x88, 0xb3, 0xe6, 0x48, 0xa4, 0x12, 0x59, 0xcb, 0xcf, 0x7c, 0x5f, + 0xe0, 0xfc, 0xf9, 0xa4, 0x1f, 0x27, 0x93, 0x27, 0x90, 0xad, 0x01, 0xe6, + 0x72, 0x92, 0x57, 0xc6, 0xe2, 0x05, 0xfe, 0xd7, 0x57, 0x90, 0xeb, 0xb3, + 0xb8, 0x3e, 0x05, 0x67, 0x4c, 0x89, 0x69, 0x4b, 0x6b, 0x26, 0xbf, 0xf6, + 0x71, 0x3f, 0xeb, 0xdb, 0xc3, 0xc4, 0x27, 0xf0, 0x6e, 0x6e, 0x00, 0x3b, + 0x8b, 0xb1, 0xe0, 0x46, 0x8e, 0xc2, 0xd2, 0x96, 0xc6, 0x89, 0xe2, 0x6f, + 0x72, 0x3c, 0xad, 0x75, 0xe4, 0x8c, 0x4c, 0x1a, 0x89, 0x8b, 0x1d, 0x8a, + 0xec, 0x9f, 0xd6, 0xd6, 0xe4, 0x83, 0x88, 0xd6, 0x16, 0x9f, 0x57, 0xd8, + 0x5b, 0xb5, 0xc7, 0xa7, 0x14, 0xec, 0x8d, 0xc9, 0x67, 0x5b, 0xb5, 0x96, + 0x3c, 0xb4, 0x4a, 0x7b, 0x48, 0x3b, 0x3b, 0x65, 0xf4, 0xbd, 0xac, 0x24, + 0xa2, 0x53, 0x5e, 0x9f, 0x21, 0xad, 0x35, 0x1f, 0xe2, 0x7a, 0xe2, 0xcc, + 0x09, 0xb4, 0x2a, 0xfb, 0x69, 0xed, 0x57, 0x7c, 0x70, 0xd1, 0xeb, 0xf3, + 0xb4, 0x16, 0xcf, 0xcb, 0x76, 0xc3, 0x8a, 0x2a, 0x21, 0xdc, 0x9b, 0xd4, + 0xb0, 0xa6, 0x45, 0x34, 0x76, 0x25, 0x8d, 0xc5, 0x2e, 0x7f, 0x04, 0xc7, + 0xc9, 0x05, 0xe2, 0xce, 0xf9, 0xc3, 0x96, 0x31, 0x74, 0x15, 0xfc, 0x88, + 0xd6, 0x38, 0x38, 0xe2, 0x86, 0xf0, 0x33, 0xe2, 0xbf, 0xdb, 0xd2, 0x31, + 0xe6, 0x1a, 0xf1, 0x5f, 0x20, 0x91, 0x3a, 0xc5, 0x9c, 0x2d, 0x91, 0x03, + 0x47, 0x0a, 0x4d, 0xf1, 0x53, 0x30, 0x06, 0xbb, 0xc8, 0x01, 0xad, 0x5d, + 0xc6, 0x00, 0x5d, 0xb5, 0xc9, 0x9d, 0x42, 0x03, 0x72, 0xe4, 0x43, 0x97, + 0xc7, 0xab, 0x61, 0xa5, 0xb3, 0xf0, 0x4b, 0x6a, 0x6b, 0x37, 0xf1, 0x85, + 0xea, 0x88, 0x19, 0x44, 0xaa, 0x36, 0x8a, 0xf3, 0xc4, 0x4a, 0xb6, 0xae, + 0x8c, 0xb9, 0x94, 0xf9, 0x7c, 0x87, 0xcf, 0x7b, 0x94, 0xcd, 0xf3, 0x51, + 0xfc, 0xcc, 0xfa, 0x42, 0x38, 0x75, 0x95, 0x6c, 0x0b, 0xac, 0x68, 0xd7, + 0x70, 0xf5, 0x85, 0x72, 0x7c, 0xfc, 0x42, 0x18, 0x9f, 0xbd, 0x40, 0x7e, + 0xbb, 0x68, 0x2f, 0x87, 0x10, 0xa9, 0x36, 0x21, 0x0a, 0x56, 0x2b, 0xde, + 0xab, 0x89, 0x45, 0xaf, 0x40, 0x6a, 0xa3, 0xa3, 0xed, 0xce, 0x19, 0x43, + 0x83, 0x48, 0x38, 0xe7, 0xbc, 0xbd, 0x70, 0xb4, 0xb5, 0xf9, 0xf3, 0x02, + 0x3b, 0x8a, 0x7b, 0x11, 0xb4, 0x3b, 0xb5, 0xb7, 0x98, 0x9b, 0xcb, 0x5e, + 0x6e, 0x3a, 0xb5, 0x75, 0xf9, 0xfb, 0xfd, 0x28, 0x2f, 0x3e, 0x53, 0xed, + 0x8c, 0x36, 0x96, 0x33, 0x7a, 0x27, 0xb9, 0xbe, 0x01, 0xaf, 0x6f, 0x46, + 0x4b, 0x70, 0xef, 0x97, 0x4a, 0xb9, 0xa9, 0xb4, 0x1f, 0xe2, 0x3e, 0x33, + 0xf7, 0xde, 0x3e, 0x3e, 0xc4, 0x3d, 0x96, 0xf3, 0x0d, 0xdf, 0x36, 0xdf, + 0x30, 0xe7, 0x7b, 0x79, 0xc5, 0x7c, 0x07, 0x56, 0xcc, 0x77, 0x60, 0xc5, + 0x7c, 0x29, 0x72, 0xf5, 0x1f, 0xc4, 0x48, 0x5d, 0x71, 0x6c, 0xd5, 0x1e, + 0xbc, 0x6d, 0xee, 0x41, 0xce, 0x7d, 0x54, 0x2c, 0x65, 0x8a, 0xe3, 0x54, + 0xda, 0xfb, 0x57, 0xcc, 0xbd, 0x9f, 0x73, 0x2f, 0x8f, 0xa3, 0x53, 0x8b, + 0x84, 0xd8, 0x66, 0x09, 0xa1, 0xda, 0xa6, 0xde, 0x89, 0xe6, 0x4c, 0x27, + 0xb1, 0x53, 0x8e, 0xc4, 0xa2, 0x0f, 0xe6, 0x70, 0xbd, 0x3f, 0x80, 0xa5, + 0x9a, 0x65, 0x6e, 0x54, 0x96, 0xfe, 0xbe, 0xa4, 0x80, 0x5a, 0xff, 0x6a, + 0xae, 0x9a, 0x63, 0xc4, 0xf4, 0x01, 0x45, 0x88, 0x73, 0x1b, 0x13, 0x83, + 0x7e, 0x24, 0xfa, 0xaa, 0x60, 0x12, 0x43, 0x81, 0x12, 0x17, 0x56, 0xf6, + 0x79, 0xd9, 0xeb, 0x53, 0xf0, 0xfa, 0x08, 0xf1, 0xee, 0x86, 0x0f, 0xc5, + 0x1b, 0x2d, 0x75, 0xf8, 0x29, 0x39, 0xf9, 0x5a, 0x61, 0x59, 0x57, 0xa4, + 0x6e, 0xc0, 0x77, 0xce, 0x0a, 0x32, 0xa6, 0x91, 0x7d, 0xc1, 0xaf, 0xf4, + 0x27, 0x60, 0x4c, 0xd9, 0xe6, 0xc7, 0x2b, 0x49, 0x3c, 0x52, 0x0e, 0xa3, + 0xf7, 0xb0, 0x92, 0x4d, 0x57, 0xc0, 0x70, 0xd6, 0x28, 0xd9, 0x94, 0x06, + 0xc9, 0x1b, 0xb5, 0xe9, 0xb4, 0x69, 0x64, 0xaf, 0xf2, 0x65, 0x75, 0xfa, + 0x4e, 0x31, 0xa8, 0x1c, 0x23, 0x8c, 0x27, 0xdd, 0x0b, 0x58, 0x0c, 0x34, + 0x50, 0x9f, 0xa5, 0x76, 0x72, 0xe0, 0x05, 0x8d, 0x35, 0x2d, 0x44, 0x22, + 0xaa, 0x38, 0xe8, 0xfa, 0xce, 0x37, 0x42, 0x20, 0xd8, 0x16, 0xc0, 0x3b, + 0xe6, 0xa8, 0x55, 0x8f, 0x4d, 0xb8, 0xdc, 0xca, 0x3d, 0x58, 0xa5, 0x22, + 0x32, 0xb7, 0x72, 0xac, 0x08, 0xc7, 0xfa, 0xb3, 0x10, 0xaa, 0xea, 0xa0, + 0x36, 0xab, 0xd8, 0xeb, 0x6a, 0x4a, 0x97, 0x2b, 0xb1, 0x6b, 0x46, 0x4e, + 0xe1, 0x14, 0xb5, 0x82, 0x35, 0xec, 0x8c, 0xaa, 0x6c, 0x99, 0x0d, 0xa1, + 0x7c, 0xe6, 0x13, 0xf1, 0x18, 0xb5, 0x2f, 0xbd, 0x41, 0x08, 0x33, 0x19, + 0x82, 0xc6, 0x79, 0x86, 0xc9, 0xe7, 0xea, 0xb6, 0x5a, 0x5c, 0xfb, 0x3a, + 0xb5, 0xe9, 0xdb, 0x21, 0xf8, 0x67, 0x42, 0x08, 0xce, 0x28, 0x78, 0xa7, + 0x3d, 0x84, 0xfa, 0x39, 0xf9, 0x5b, 0x41, 0xa3, 0x79, 0x14, 0x07, 0x75, + 0x3f, 0x63, 0xfc, 0x2b, 0xf4, 0xeb, 0x0d, 0x98, 0xa4, 0x36, 0x3f, 0xea, + 0x6a, 0xa8, 0x3a, 0x4a, 0x2d, 0xb0, 0x85, 0x38, 0x49, 0xfc, 0x1f, 0x64, + 0x8c, 0x32, 0xde, 0x0b, 0x56, 0x36, 0x1a, 0x42, 0x00, 0xc1, 0x39, 0x23, + 0x3d, 0xc9, 0xe8, 0x52, 0x53, 0xaa, 0xb2, 0x7d, 0x96, 0xb5, 0xd7, 0x36, + 0x7b, 0xeb, 0xfd, 0x42, 0x7c, 0x9a, 0x6c, 0xea, 0x5b, 0xa0, 0x06, 0x8f, + 0xc4, 0x62, 0x99, 0x7e, 0x05, 0x58, 0x73, 0x96, 0x76, 0x64, 0xe6, 0xbf, + 0x44, 0x98, 0xe3, 0x1c, 0xd9, 0x20, 0x30, 0x6e, 0x65, 0x23, 0x01, 0x18, + 0x37, 0x86, 0x50, 0x87, 0x0f, 0x9e, 0x17, 0x42, 0xb4, 0x57, 0xe3, 0x1d, + 0xcb, 0x18, 0x34, 0xfd, 0x02, 0x3f, 0x4e, 0x66, 0x87, 0x22, 0x30, 0x86, + 0x7f, 0xad, 0x44, 0xf1, 0xf1, 0x94, 0x91, 0xbe, 0xa8, 0x04, 0x51, 0x39, + 0x67, 0xea, 0x5b, 0x94, 0x30, 0xca, 0x17, 0xc2, 0x58, 0x7d, 0x36, 0x88, + 0xc0, 0x4c, 0x18, 0xc1, 0x69, 0xf3, 0xe2, 0x2e, 0x78, 0xe3, 0x2c, 0x0e, + 0xa1, 0x19, 0xd5, 0xb3, 0x66, 0xf4, 0x5f, 0x20, 0xb1, 0x1d, 0x86, 0xba, + 0x10, 0x45, 0x7d, 0xc1, 0x44, 0x35, 0xf3, 0x7d, 0xf9, 0xac, 0xcc, 0xb3, + 0x8e, 0xb0, 0xe9, 0xe3, 0xda, 0x1c, 0x65, 0xab, 0x57, 0x37, 0x3a, 0xf9, + 0xe9, 0x56, 0x3a, 0xe6, 0xe5, 0x9e, 0x29, 0x28, 0xe3, 0xb3, 0x8b, 0xd6, + 0x4d, 0xb1, 0x2f, 0x26, 0xeb, 0x44, 0x19, 0x02, 0x76, 0x8f, 0xf2, 0xc0, + 0x3c, 0x8b, 0x90, 0xa7, 0xef, 0x65, 0x4a, 0xc0, 0x2e, 0x6a, 0xfb, 0x25, + 0x6a, 0xfb, 0x89, 0x92, 0xb6, 0x57, 0x51, 0xdb, 0x17, 0xfe, 0x4f, 0x6d, + 0x67, 0xbd, 0x9f, 0xf1, 0xe1, 0xbc, 0x19, 0xc2, 0x71, 0xab, 0x69, 0xb1, + 0x1e, 0x21, 0x54, 0xb7, 0xe9, 0xa8, 0x5e, 0xb0, 0xf0, 0x1c, 0xf7, 0x16, + 0x77, 0x15, 0xf5, 0xfd, 0x9b, 0x52, 0xf3, 0x4b, 0x5e, 0xed, 0x71, 0x77, + 0x59, 0x13, 0xc2, 0xd4, 0x2a, 0x55, 0xe9, 0xa1, 0x9e, 0x3f, 0x90, 0xbc, + 0x29, 0xe2, 0x31, 0x23, 0x4e, 0xce, 0xde, 0x38, 0x89, 0xa2, 0x46, 0xc4, + 0xa8, 0x97, 0x4b, 0xb5, 0x71, 0x1c, 0x73, 0x65, 0x4d, 0xeb, 0x64, 0x4d, + 0x53, 0x30, 0x12, 0x2b, 0x6a, 0xc4, 0xea, 0xbc, 0x6c, 0xd7, 0x51, 0x4f, + 0x9d, 0x5c, 0xd7, 0x16, 0xc1, 0x31, 0x6a, 0xa4, 0x4b, 0x9f, 0xb3, 0x9d, + 0xe3, 0x6d, 0x9b, 0x35, 0xb2, 0xdb, 0x99, 0x9f, 0xf3, 0xc4, 0xc5, 0x14, + 0xab, 0xc3, 0x89, 0x1a, 0x6a, 0x67, 0x73, 0x08, 0x13, 0xd4, 0xcb, 0xf3, + 0xf4, 0x10, 0x2f, 0xb1, 0xdf, 0xb8, 0x6b, 0x44, 0x5f, 0x22, 0xaf, 0xc7, + 0x4b, 0x9a, 0xf9, 0x12, 0x7d, 0xc3, 0x38, 0xf3, 0xf4, 0x53, 0x3e, 0x7b, + 0xcd, 0x35, 0x1c, 0xe9, 0x1f, 0xfc, 0x9e, 0x7f, 0x30, 0xe2, 0x7e, 0x45, + 0x7a, 0x88, 0x08, 0xde, 0x68, 0x91, 0x58, 0x24, 0xc6, 0x6f, 0xe9, 0xa7, + 0xaa, 0x7c, 0x6b, 0xf6, 0xba, 0xc8, 0xc7, 0xca, 0x55, 0xc9, 0xbf, 0xb1, + 0xa4, 0xc4, 0x93, 0x10, 0x65, 0x76, 0x98, 0x5e, 0xcb, 0x8c, 0x7f, 0x84, + 0x18, 0x71, 0x1b, 0xe1, 0xb3, 0x30, 0xfc, 0x67, 0xb7, 0xa8, 0x9e, 0x8f, + 0x5d, 0x90, 0x7e, 0x8b, 0x79, 0x9a, 0x32, 0x7b, 0xa7, 0x94, 0x58, 0x66, + 0x40, 0x91, 0xcf, 0x75, 0x94, 0x9f, 0x5d, 0x22, 0x77, 0x23, 0xe4, 0x6e, + 0x1d, 0x5e, 0xbf, 0x8d, 0xbf, 0xd4, 0x55, 0xdf, 0x00, 0xf9, 0x9b, 0xad, + 0x1b, 0xe9, 0xf7, 0x7f, 0x85, 0x7b, 0x87, 0x24, 0x7f, 0xd9, 0xe6, 0xc7, + 0xb3, 0x49, 0xec, 0x2c, 0x83, 0x91, 0x79, 0x4c, 0xc9, 0x3a, 0xe4, 0x71, + 0xaa, 0x4c, 0xc9, 0xd2, 0x31, 0x7d, 0xc9, 0xdf, 0x37, 0xf9, 0xb6, 0x9f, + 0xfc, 0xed, 0xab, 0xbb, 0x9d, 0xbf, 0x47, 0x38, 0x86, 0x8a, 0x27, 0xdc, + 0xe3, 0x98, 0x0b, 0x04, 0x11, 0x99, 0x09, 0x20, 0x34, 0xa3, 0xa2, 0x92, + 0x5c, 0x09, 0xdb, 0xd9, 0x78, 0x08, 0x46, 0xfa, 0x35, 0x44, 0x90, 0x98, + 0xd2, 0xf0, 0xe7, 0x2d, 0x01, 0x9c, 0x89, 0x19, 0x99, 0xfd, 0x4a, 0x84, + 0x58, 0x1f, 0x61, 0x44, 0x46, 0x34, 0xea, 0x2b, 0xf2, 0x35, 0xd0, 0x1c, + 0x84, 0x36, 0x23, 0xb9, 0x2e, 0x0e, 0xfa, 0xec, 0x6c, 0x54, 0x23, 0x46, + 0x7f, 0x40, 0x6c, 0x5c, 0x99, 0x12, 0x62, 0x73, 0xbb, 0x79, 0xf1, 0x3d, + 0xbf, 0x41, 0xdd, 0x53, 0x89, 0xd3, 0xe2, 0xf8, 0x15, 0x33, 0x1a, 0x82, + 0x47, 0xbd, 0xf1, 0x6f, 0xbc, 0xce, 0x28, 0x3e, 0x75, 0x55, 0x65, 0x2b, + 0x71, 0x40, 0x6e, 0x45, 0xe6, 0xa9, 0x7d, 0x87, 0x93, 0x46, 0x7a, 0x8b, + 0xd2, 0xe4, 0x34, 0xf3, 0xbb, 0x2f, 0x19, 0x8b, 0xf6, 0xf3, 0x9d, 0xf7, + 0x0b, 0x45, 0x0e, 0xd7, 0x9b, 0xbb, 0xf1, 0x17, 0xe4, 0x70, 0x95, 0xf9, + 0x14, 0x9e, 0xf4, 0xf4, 0x88, 0x38, 0x98, 0x2e, 0x27, 0xb7, 0x1d, 0x65, + 0x17, 0x71, 0xbf, 0x73, 0x9e, 0xba, 0x32, 0xd3, 0xee, 0x69, 0x51, 0xc8, + 0xec, 0x54, 0x7a, 0xe7, 0xbb, 0x3d, 0x0f, 0xb5, 0x7d, 0xd6, 0x87, 0xd7, + 0xad, 0x4d, 0xf4, 0x2b, 0x69, 0x65, 0xfb, 0xbc, 0xc4, 0x7c, 0x8f, 0xf2, + 0x4d, 0xe2, 0x3f, 0x7a, 0x97, 0x8a, 0x39, 0x6b, 0x93, 0x12, 0xf4, 0xf0, + 0x1f, 0x80, 0x93, 0x29, 0x62, 0xdf, 0x6f, 0xc7, 0xac, 0x73, 0x2b, 0xb0, + 0xdf, 0x7d, 0x07, 0x5f, 0x23, 0xf5, 0x03, 0x45, 0x2d, 0xd7, 0x3b, 0x99, + 0xaf, 0x67, 0x4a, 0x18, 0x7f, 0x92, 0xed, 0x81, 0x19, 0x68, 0xe5, 0xc4, + 0x71, 0xcf, 0x54, 0x18, 0xd3, 0x1e, 0x56, 0x04, 0x5e, 0x65, 0x4d, 0xc8, + 0x27, 0x0d, 0x6b, 0xbf, 0x62, 0xa4, 0xbb, 0x95, 0x44, 0x76, 0x4d, 0xa9, + 0x1e, 0xde, 0xcb, 0x9a, 0x86, 0xbb, 0xa8, 0x0b, 0x16, 0xb4, 0x10, 0xf1, + 0xfd, 0x6f, 0xac, 0x4f, 0xff, 0x51, 0xaa, 0x87, 0xc9, 0x7c, 0x39, 0xaa, + 0x5b, 0xa8, 0xef, 0xc4, 0x73, 0x97, 0xc4, 0x33, 0x3d, 0xc4, 0x18, 0xeb, + 0xff, 0x4e, 0xe2, 0x79, 0x75, 0x9b, 0x91, 0xed, 0xa4, 0x77, 0xf6, 0xad, + 0x8f, 0x10, 0xab, 0x71, 0xfa, 0xd5, 0x31, 0x74, 0x70, 0xae, 0xf4, 0xac, + 0x11, 0xe9, 0x20, 0x07, 0x54, 0xf6, 0x79, 0x89, 0x7d, 0x96, 0x6a, 0xa5, + 0xaf, 0x0e, 0xe1, 0x59, 0xf6, 0x31, 0x93, 0x8e, 0xa7, 0x15, 0x92, 0x03, + 0x13, 0x48, 0x64, 0x24, 0x07, 0x9c, 0x55, 0xad, 0xf4, 0xf8, 0x92, 0x03, + 0xc4, 0xa0, 0x4b, 0x0c, 0x16, 0x79, 0x30, 0x28, 0x79, 0x50, 0x45, 0x0f, + 0xb1, 0x40, 0x0f, 0x51, 0x61, 0x47, 0xc9, 0x01, 0xc9, 0x89, 0xa2, 0x8f, + 0xe8, 0x2c, 0xf1, 0x60, 0x8b, 0x37, 0x9f, 0x4a, 0xed, 0x0b, 0xa3, 0x69, + 0xda, 0xd0, 0x55, 0xe5, 0x3f, 0xc5, 0x2e, 0xd3, 0x5c, 0xdc, 0x4b, 0x2f, + 0xf0, 0x59, 0x5b, 0x8c, 0x79, 0x0f, 0x63, 0xdd, 0x42, 0x79, 0x40, 0xe2, + 0xbc, 0x7e, 0x3a, 0x8c, 0xea, 0x69, 0xc9, 0x83, 0xec, 0x24, 0xf5, 0x6f, + 0xc8, 0xf2, 0xfd, 0x13, 0xf1, 0x1f, 0x25, 0x2e, 0x54, 0xa5, 0x8b, 0x63, + 0x54, 0xcd, 0xe8, 0x68, 0x9d, 0x36, 0x06, 0x17, 0x70, 0x4d, 0xbc, 0x1a, + 0x33, 0x33, 0x87, 0x98, 0xff, 0x3d, 0xc9, 0x18, 0xf7, 0x4a, 0xc7, 0xbd, + 0xb7, 0xc6, 0xf0, 0x38, 0xe1, 0xf4, 0x5b, 0xe1, 0x92, 0xaf, 0xd6, 0xd0, + 0xef, 0x02, 0x7b, 0x5c, 0x1a, 0x5b, 0xd3, 0xb7, 0x36, 0x88, 0xeb, 0x38, + 0x49, 0xf4, 0x0f, 0xe8, 0x0e, 0xf3, 0x1f, 0xc2, 0xde, 0xd2, 0x3b, 0x45, + 0xbf, 0xfd, 0xe3, 0xd2, 0x79, 0xf2, 0x17, 0xfe, 0xe2, 0xdf, 0xbf, 0x55, + 0x97, 0xcf, 0x97, 0xfd, 0xc4, 0xe0, 0x66, 0x62, 0xb0, 0x9b, 0x39, 0xda, + 0x6b, 0x91, 0xdf, 0xcc, 0x67, 0x56, 0x0d, 0x51, 0x0f, 0x9b, 0xfa, 0x2a, + 0xa9, 0x6b, 0x87, 0xa9, 0x51, 0x3f, 0x37, 0xcb, 0xe9, 0xb7, 0x1d, 0xfa, + 0xed, 0x0e, 0x6a, 0x68, 0x27, 0xf5, 0x53, 0x62, 0x2b, 0x4d, 0x1c, 0x69, + 0x4a, 0x9a, 0x1e, 0x36, 0x90, 0xa4, 0xd7, 0xae, 0x5b, 0xf6, 0xda, 0x32, + 0x4e, 0xe9, 0xaf, 0x8d, 0xb8, 0x2c, 0xb5, 0x4f, 0x32, 0x0f, 0x8b, 0x35, + 0x9b, 0xa0, 0xda, 0x9b, 0x14, 0xd5, 0x96, 0xe7, 0x09, 0x15, 0xdf, 0xa5, + 0xd6, 0x2e, 0xed, 0x90, 0xe7, 0x0a, 0xae, 0x8b, 0x6d, 0x11, 0x33, 0x16, + 0x3d, 0x4e, 0x5c, 0x1d, 0xfb, 0x9d, 0x73, 0x46, 0x11, 0x6f, 0xa3, 0xae, + 0x7a, 0xcb, 0x33, 0x4b, 0x7d, 0xd8, 0x74, 0x0b, 0x6f, 0x1a, 0x9e, 0x68, + 0x89, 0x12, 0x8f, 0x12, 0x6b, 0x1a, 0xf2, 0x2f, 0x96, 0xe3, 0xd5, 0x17, + 0xc3, 0x78, 0xe5, 0x45, 0x21, 0xc6, 0x93, 0xe0, 0x69, 0x46, 0x6a, 0xec, + 0x46, 0xbc, 0xac, 0xc7, 0xa2, 0xcf, 0x7a, 0x9e, 0xd5, 0xa1, 0x67, 0x35, + 0x06, 0x2f, 0xe0, 0x26, 0xf5, 0x4b, 0x72, 0x3a, 0x41, 0xbe, 0x15, 0xb1, + 0xe8, 0x79, 0xdb, 0x1a, 0x0d, 0x57, 0x88, 0xbf, 0x6a, 0xe2, 0xef, 0x37, + 0xd4, 0xdd, 0x6b, 0x25, 0xdd, 0x5d, 0x9b, 0x27, 0x1f, 0xdb, 0x42, 0xe8, + 0x96, 0x6b, 0x21, 0x0e, 0x47, 0x6f, 0xe1, 0x50, 0x88, 0x0f, 0xb8, 0xe7, + 0x17, 0x2c, 0x23, 0xbe, 0x99, 0x78, 0x9c, 0xb3, 0x0c, 0xa7, 0x83, 0xde, + 0x75, 0xd4, 0xc3, 0x24, 0xf5, 0x37, 0x26, 0x71, 0x49, 0x1c, 0x32, 0x27, + 0x87, 0xd9, 0xe7, 0x3c, 0xfb, 0x4c, 0x94, 0xbc, 0xeb, 0xdb, 0x48, 0xa4, + 0xa5, 0x77, 0x8d, 0x12, 0x83, 0x87, 0x3d, 0xef, 0x2a, 0xbd, 0xaa, 0xf4, + 0xa9, 0x32, 0xce, 0x76, 0x2f, 0xce, 0xae, 0x5b, 0x38, 0xa4, 0x86, 0xd5, + 0x48, 0xfc, 0x7d, 0x03, 0x13, 0xcf, 0x57, 0xa1, 0xda, 0xbc, 0x07, 0x97, + 0x33, 0xdf, 0x50, 0x23, 0x26, 0xf4, 0x7a, 0xbb, 0x88, 0xc7, 0x9d, 0x85, + 0x14, 0x5c, 0xf7, 0x2d, 0xe1, 0xd6, 0x19, 0xce, 0x05, 0xcf, 0x7f, 0x0e, + 0xb2, 0xd6, 0xdc, 0x14, 0xbe, 0x98, 0x71, 0xb1, 0x9f, 0x1e, 0xac, 0xc9, + 0x5f, 0xf4, 0x72, 0x1b, 0xf3, 0xbf, 0x14, 0xa8, 0x2d, 0xae, 0x53, 0xa5, + 0x7f, 0x1b, 0x23, 0xe7, 0xc6, 0xcd, 0xa2, 0x97, 0x8b, 0xe5, 0xaf, 0x06, + 0xa4, 0xa6, 0xfb, 0xda, 0xe4, 0xb8, 0x69, 0x6a, 0xc8, 0xf2, 0xd8, 0x5f, + 0xea, 0xf2, 0x18, 0x31, 0x38, 0x2a, 0x7d, 0x15, 0x7d, 0x09, 0xcf, 0xe5, + 0x2b, 0x34, 0x75, 0xd8, 0x0f, 0x53, 0xb6, 0x39, 0xca, 0x03, 0x5c, 0x83, + 0x66, 0x0e, 0x2b, 0x69, 0x9e, 0x3b, 0x0f, 0x11, 0x5f, 0xdd, 0xac, 0xc3, + 0x57, 0xad, 0x66, 0x72, 0x98, 0xf5, 0x89, 0xb5, 0xf8, 0xb0, 0xb9, 0x7c, + 0x7e, 0x93, 0x35, 0x99, 0x35, 0xcc, 0xad, 0x64, 0xfd, 0xee, 0x61, 0xcd, + 0xe6, 0x28, 0xcc, 0xe9, 0x67, 0x31, 0xd1, 0xb8, 0xb6, 0xcd, 0x18, 0xdc, + 0xe6, 0x0f, 0x21, 0x47, 0xbc, 0x1f, 0x63, 0x1d, 0x72, 0xb9, 0xa7, 0xd3, + 0x05, 0x23, 0x95, 0xc5, 0x18, 0xb6, 0x71, 0x4f, 0x79, 0xde, 0x71, 0xfe, + 0x2e, 0x56, 0x3c, 0x0f, 0xef, 0x65, 0x7d, 0x9b, 0x2c, 0x71, 0xfb, 0x43, + 0x24, 0x2c, 0xc9, 0xed, 0x45, 0xd6, 0xb7, 0x49, 0x8f, 0xdb, 0x46, 0x4a, + 0xf2, 0xb9, 0xac, 0x54, 0xd7, 0x3e, 0x82, 0xe4, 0xf0, 0xed, 0x35, 0x4d, + 0xe2, 0xd9, 0x0e, 0x4a, 0x1f, 0xeb, 0xba, 0xb2, 0x26, 0xc9, 0x5a, 0xb4, + 0x5c, 0x97, 0x34, 0x79, 0x77, 0x90, 0x69, 0x9c, 0x3a, 0x28, 0x7c, 0xc5, + 0xfb, 0x87, 0x8b, 0xef, 0xfa, 0xc3, 0xa9, 0xd4, 0x7d, 0xc8, 0x44, 0xce, + 0x6a, 0xd8, 0xe1, 0x36, 0xf4, 0x85, 0x6c, 0xf0, 0x1d, 0x05, 0xd6, 0x1f, + 0x6b, 0xc8, 0xdc, 0x76, 0xff, 0xf0, 0x41, 0x4e, 0xd3, 0xaa, 0xa7, 0xee, + 0x96, 0xef, 0xe0, 0x93, 0xdc, 0x1d, 0xef, 0x1f, 0xd2, 0xbf, 0xef, 0xfe, + 0xe1, 0x59, 0xf2, 0x63, 0xa2, 0x78, 0xff, 0xe0, 0x7c, 0xa7, 0xc5, 0x8f, + 0xb9, 0x3a, 0x1c, 0x78, 0xaf, 0x5d, 0xc5, 0xd5, 0x9c, 0x11, 0x79, 0x19, + 0x07, 0x30, 0xe0, 0xdd, 0x35, 0xf0, 0xcc, 0x6f, 0x0f, 0xe1, 0xd7, 0xed, + 0xf2, 0xae, 0x21, 0x25, 0xd7, 0x38, 0xc9, 0xe5, 0x43, 0xa3, 0xde, 0x6c, + 0x61, 0x2d, 0xd8, 0xb7, 0x51, 0xc1, 0x03, 0xc9, 0x7b, 0x3c, 0x6c, 0x4f, + 0x16, 0x8c, 0x74, 0x94, 0xcf, 0xd6, 0x4d, 0xc9, 0x1a, 0xf9, 0x30, 0xcf, + 0x86, 0xd0, 0x1a, 0xed, 0x5e, 0x4d, 0xb8, 0x4d, 0x91, 0x0f, 0x15, 0xc3, + 0x39, 0x09, 0x79, 0x1f, 0x90, 0xb8, 0xe8, 0x57, 0x8c, 0xc5, 0x77, 0xfd, + 0x46, 0xaa, 0xde, 0xc3, 0xcc, 0xc3, 0x3c, 0xa7, 0xc9, 0xbf, 0xbd, 0xf2, + 0x8c, 0x87, 0x6d, 0x1c, 0xf3, 0xd2, 0x46, 0x79, 0xee, 0xfc, 0x54, 0x64, + 0x57, 0x19, 0xce, 0x92, 0xa2, 0x31, 0x37, 0xa0, 0x3e, 0x49, 0x0d, 0x7f, + 0x98, 0x1a, 0x2e, 0xcf, 0x08, 0xbd, 0x3c, 0x23, 0x34, 0x2d, 0xc6, 0xfd, + 0x46, 0xe6, 0x06, 0xf5, 0x8e, 0x63, 0xf6, 0xf5, 0x2a, 0x46, 0xef, 0x02, + 0xf5, 0x7f, 0xbf, 0x52, 0x1c, 0x73, 0x4d, 0x69, 0xcc, 0x7b, 0xf3, 0x9a, + 0xb2, 0xd9, 0x05, 0x75, 0x07, 0xd1, 0x3d, 0x16, 0xb5, 0xa3, 0x50, 0x4e, + 0x8e, 0x99, 0x72, 0xcd, 0x8c, 0xad, 0x95, 0xb1, 0x29, 0xf8, 0xb0, 0x45, + 0xbe, 0xdb, 0x2a, 0xe3, 0x70, 0x2a, 0xec, 0x14, 0xb5, 0xf7, 0xb9, 0x60, + 0x49, 0xbf, 0x7c, 0xfd, 0xd6, 0x2a, 0x38, 0x75, 0xa8, 0x0e, 0x98, 0xb5, + 0x18, 0xd7, 0x51, 0x19, 0x36, 0x9b, 0x91, 0xd3, 0x83, 0xe8, 0xb7, 0x7e, + 0x2b, 0xa8, 0x93, 0x7c, 0x1f, 0x78, 0xec, 0x79, 0x9e, 0xd7, 0xcd, 0xeb, + 0x88, 0x25, 0x9f, 0xc6, 0x19, 0x7d, 0x08, 0xe5, 0xac, 0xa5, 0xaf, 0x78, + 0x7a, 0x62, 0x13, 0xcf, 0x0a, 0x31, 0x64, 0xcb, 0x5a, 0x77, 0xdb, 0xd8, + 0xf2, 0xfe, 0xe1, 0x7d, 0x91, 0x2d, 0x8e, 0xe1, 0xec, 0xb1, 0x32, 0x8c, + 0xeb, 0x4b, 0xdd, 0xdd, 0x47, 0xdd, 0xa5, 0xb7, 0xfc, 0x5a, 0x39, 0x75, + 0x77, 0xb7, 0xf5, 0x6d, 0x3c, 0x46, 0x8e, 0x57, 0x98, 0x9f, 0x88, 0xc7, + 0xeb, 0xe4, 0x98, 0xd4, 0xd7, 0xaa, 0x95, 0xe3, 0xff, 0x33, 0xc7, 0x94, + 0x73, 0xc8, 0x7a, 0x78, 0x59, 0x48, 0x6f, 0x56, 0x61, 0x0f, 0x2b, 0xdb, + 0xc8, 0xa9, 0x45, 0x96, 0xde, 0xef, 0x92, 0x4f, 0x4b, 0xcc, 0x4f, 0xe3, + 0x1d, 0xf8, 0xd4, 0x48, 0x3e, 0xed, 0x5a, 0xc1, 0xa7, 0xe3, 0xe4, 0x53, + 0x2f, 0xf9, 0xd4, 0xd2, 0xf6, 0x27, 0xd4, 0x15, 0x21, 0x82, 0x6d, 0x37, + 0xc5, 0x9b, 0x9e, 0xff, 0x95, 0x9e, 0x37, 0xad, 0x74, 0xcd, 0x4b, 0x7d, + 0xaa, 0xa4, 0x27, 0xee, 0xa1, 0x1f, 0x06, 0x06, 0xc8, 0xa7, 0xc7, 0x4d, + 0xd1, 0xb8, 0x2f, 0x69, 0xa4, 0x16, 0xe9, 0x6b, 0x7a, 0xc8, 0xa9, 0xb7, + 0xc8, 0xa9, 0xb1, 0x42, 0x51, 0xa7, 0x0e, 0x73, 0xdd, 0xf7, 0x53, 0xa7, + 0x7a, 0x0a, 0x52, 0xdb, 0x1c, 0xe2, 0x3f, 0x84, 0x4f, 0xc9, 0xa9, 0xf9, + 0xa4, 0xa7, 0x53, 0xd6, 0x6f, 0x90, 0x18, 0x3a, 0x2f, 0xf9, 0x44, 0x9d, + 0x72, 0x0b, 0x4d, 0xd6, 0x79, 0xae, 0x69, 0xd2, 0x35, 0x6e, 0x74, 0x93, + 0x53, 0x81, 0x76, 0xe3, 0xe2, 0x55, 0x62, 0x37, 0x14, 0x83, 0x1e, 0xb1, + 0xe5, 0x9a, 0x58, 0x63, 0x59, 0x27, 0x8f, 0x13, 0xff, 0xdd, 0xd4, 0x8c, + 0xde, 0x82, 0x8d, 0x43, 0x85, 0x95, 0x7b, 0xca, 0x3a, 0x74, 0xc7, 0x7d, + 0x19, 0x0d, 0xdd, 0xb9, 0x9d, 0xf5, 0xea, 0x8e, 0xed, 0x92, 0xaf, 0x7a, + 0x48, 0xf2, 0x75, 0xd4, 0xfd, 0x61, 0xe0, 0xce, 0xef, 0xc8, 0xfb, 0x33, + 0x21, 0x4e, 0x5b, 0xf2, 0xfe, 0x41, 0xfa, 0x1e, 0xfa, 0x68, 0x4b, 0xde, + 0xa1, 0x75, 0x44, 0x55, 0x18, 0x91, 0x47, 0xf1, 0xb9, 0xc8, 0xd6, 0x39, + 0xf1, 0x80, 0x57, 0x23, 0x0d, 0xbd, 0x8f, 0xb5, 0x6e, 0xb1, 0x74, 0xce, + 0x9b, 0xcb, 0x09, 0xf1, 0x16, 0xeb, 0xd4, 0x69, 0x9e, 0xe9, 0x46, 0xf2, + 0x9f, 0x8b, 0xc5, 0x3a, 0x15, 0x63, 0xe6, 0xad, 0xfb, 0x48, 0x4f, 0xc7, + 0x4e, 0xf2, 0xd9, 0x44, 0x7e, 0xb9, 0x46, 0x51, 0x33, 0x4d, 0x21, 0x76, + 0x9b, 0xff, 0x2d, 0xfa, 0xbf, 0xf2, 0xae, 0x10, 0xd3, 0x8c, 0xe1, 0x8a, + 0x85, 0x03, 0x01, 0xc4, 0xfa, 0x6e, 0xb0, 0xae, 0x5f, 0xda, 0x68, 0x64, + 0xf2, 0x4a, 0xa2, 0x77, 0xab, 0x22, 0xbd, 0x9e, 0xaf, 0xb3, 0x8c, 0xef, + 0xb4, 0xd0, 0x1b, 0x7d, 0xc8, 0x0c, 0x06, 0xf9, 0xfd, 0x4d, 0xcb, 0xa0, + 0x7f, 0x16, 0xa2, 0x3f, 0x25, 0xc7, 0x10, 0xa2, 0xc3, 0x92, 0xe7, 0x80, + 0x31, 0x9e, 0x03, 0xb2, 0xa2, 0xc2, 0xbc, 0x42, 0x6d, 0x32, 0x32, 0x63, + 0x8a, 0xc9, 0xbe, 0x51, 0x78, 0x3a, 0xcb, 0x67, 0xda, 0x54, 0x04, 0x7f, + 0xed, 0xf9, 0xe7, 0x28, 0x35, 0xab, 0x01, 0x7f, 0xe3, 0xe9, 0x96, 0x8a, + 0x3d, 0xcf, 0x1b, 0x29, 0x55, 0x39, 0x88, 0xf7, 0x2d, 0x43, 0xff, 0x21, + 0xe3, 0xa6, 0xd6, 0x3c, 0xb7, 0x19, 0x51, 0x70, 0x8e, 0x6c, 0x9f, 0xbf, + 0x46, 0xd1, 0x58, 0x3b, 0xbe, 0xdf, 0x22, 0x6b, 0xf7, 0x10, 0xba, 0x9b, + 0xf7, 0xf3, 0xa3, 0xa2, 0x76, 0x46, 0x55, 0x76, 0xd0, 0x93, 0x54, 0xcf, + 0x54, 0x63, 0xef, 0x7a, 0x21, 0xd6, 0xae, 0x77, 0xc0, 0x33, 0x5f, 0xfc, + 0x02, 0x6b, 0xd0, 0x89, 0x1a, 0x23, 0x0d, 0xfc, 0x04, 0x3b, 0xe9, 0x65, + 0x53, 0x6d, 0x39, 0xe0, 0x1e, 0xb9, 0xc6, 0x9f, 0x60, 0xb3, 0xf4, 0xc0, + 0x56, 0xb5, 0xf4, 0x5b, 0x1e, 0x7e, 0x8b, 0x77, 0x48, 0x4c, 0xf5, 0xd1, + 0xac, 0x28, 0x37, 0x8d, 0xbe, 0x79, 0xd6, 0xdb, 0x4b, 0xb1, 0xbb, 0xf5, + 0x6f, 0xcd, 0x4b, 0x0f, 0x6c, 0x46, 0xb7, 0x28, 0x82, 0xb9, 0x78, 0x86, + 0xb9, 0x88, 0x39, 0x61, 0x5a, 0x86, 0x6a, 0x3b, 0xe6, 0x54, 0x2b, 0xc3, + 0xca, 0x83, 0xe4, 0x43, 0x5f, 0xb0, 0x9c, 0x1e, 0xc2, 0xa1, 0x7f, 0xf0, + 0xa1, 0xf2, 0xa8, 0xf4, 0x14, 0x21, 0x6a, 0x4d, 0x53, 0x2f, 0x4f, 0x17, + 0xd8, 0x97, 0x94, 0xfe, 0x83, 0x58, 0x3f, 0x7a, 0x53, 0x6c, 0xa6, 0xc7, + 0xdd, 0x5c, 0xf2, 0xb8, 0xbb, 0x66, 0xd3, 0xf4, 0xc0, 0x9a, 0x22, 0xef, + 0xd3, 0x52, 0x6d, 0x3c, 0x94, 0x3e, 0x28, 0x7d, 0x88, 0x5c, 0x83, 0x8e, + 0x6b, 0x49, 0x89, 0x5d, 0x1d, 0xa3, 0xed, 0x46, 0x24, 0x0b, 0x79, 0x7f, + 0x73, 0xbb, 0xbf, 0x80, 0x9e, 0xfe, 0x1d, 0xcf, 0x01, 0x7d, 0x07, 0x63, + 0x31, 0x82, 0x42, 0xd4, 0x26, 0xfd, 0xe8, 0xf3, 0xce, 0x73, 0x11, 0x3d, + 0x4d, 0xde, 0x5f, 0xa4, 0x4f, 0xf0, 0xf3, 0xdc, 0x7c, 0x90, 0x58, 0xfa, + 0xac, 0x65, 0xe4, 0x58, 0x3d, 0xb2, 0x93, 0xb5, 0x30, 0xac, 0xfb, 0xa9, + 0xab, 0x57, 0x72, 0x0f, 0xb2, 0x9e, 0xfb, 0xda, 0x23, 0x3c, 0x03, 0x34, + 0xce, 0x64, 0x45, 0x3d, 0xfd, 0xe0, 0x37, 0x78, 0xee, 0xad, 0x69, 0x8b, + 0xd3, 0x6f, 0x2f, 0xef, 0x95, 0x0f, 0x4f, 0x59, 0x26, 0x1c, 0xef, 0x77, + 0x58, 0xef, 0x9a, 0xbd, 0x29, 0xe6, 0xcc, 0xbb, 0xf5, 0x8e, 0x62, 0x5c, + 0x6a, 0x99, 0x6d, 0xa1, 0x65, 0x03, 0xcf, 0x8e, 0x77, 0x88, 0xa9, 0x47, + 0x7a, 0x9f, 0x40, 0xb1, 0xdf, 0x9f, 0xce, 0x36, 0xe8, 0xdb, 0x59, 0xef, + 0x16, 0x89, 0x95, 0x5d, 0xeb, 0x2d, 0x19, 0xcb, 0xa2, 0x8c, 0x85, 0xfe, + 0xd2, 0xb9, 0xdf, 0x47, 0x5f, 0x92, 0x04, 0xaa, 0xcf, 0x3e, 0x45, 0x5e, + 0xf9, 0x5a, 0xab, 0x91, 0x1d, 0x62, 0x8c, 0xc7, 0xfe, 0x91, 0x5b, 0x33, + 0x30, 0x8d, 0x01, 0x1f, 0xfb, 0x4c, 0x59, 0xc0, 0x13, 0x0b, 0x3c, 0x97, + 0x4e, 0xc7, 0xe8, 0xcb, 0xe9, 0x23, 0x17, 0x34, 0x3c, 0x3a, 0x5b, 0x8e, + 0xef, 0xcd, 0x86, 0xb1, 0x6f, 0xd6, 0xbb, 0xd7, 0xda, 0x5a, 0xcb, 0xf7, + 0x3a, 0x92, 0x42, 0xcc, 0x5b, 0xeb, 0xf1, 0x1e, 0x3d, 0xd4, 0x6a, 0xc5, + 0x87, 0xc8, 0x51, 0xe8, 0x3a, 0x71, 0x53, 0xd3, 0xf2, 0x3d, 0x26, 0x58, + 0x08, 0x73, 0xbd, 0xd4, 0xc9, 0x67, 0xbc, 0xef, 0x63, 0xf4, 0x8f, 0x19, + 0x89, 0x41, 0x97, 0x18, 0x74, 0x89, 0xc9, 0x5b, 0x9e, 0x5a, 0x62, 0x39, + 0x4e, 0x1f, 0xfd, 0xb4, 0x28, 0x62, 0xe3, 0x0b, 0x71, 0xda, 0x7c, 0x95, + 0xfc, 0x55, 0xa9, 0xa1, 0xc0, 0xdf, 0xe7, 0x22, 0xfa, 0x8e, 0x82, 0xcc, + 0xff, 0x5f, 0x96, 0xf2, 0xbf, 0x18, 0x2a, 0xea, 0x85, 0xe1, 0xcc, 0xa3, + 0x01, 0xd3, 0x6e, 0x83, 0xbe, 0xd5, 0x1d, 0x19, 0xd6, 0x90, 0x8d, 0x56, + 0xc3, 0x18, 0x9c, 0x86, 0xaf, 0x35, 0x0c, 0xb9, 0x76, 0x20, 0xef, 0xad, + 0x51, 0x88, 0x09, 0xea, 0x9b, 0xcc, 0xc1, 0xbf, 0xe7, 0xd0, 0xea, 0x63, + 0x3e, 0x1c, 0xc6, 0xbe, 0x8f, 0x7b, 0xf0, 0x71, 0x5e, 0xde, 0x73, 0xc6, + 0xd2, 0x5d, 0xb8, 0xee, 0x8d, 0xf9, 0x51, 0x3e, 0x85, 0x23, 0xee, 0x25, + 0x71, 0xa4, 0xae, 0xa8, 0xf1, 0x69, 0x9e, 0x8f, 0xaa, 0x8f, 0x96, 0xbc, + 0x10, 0x39, 0x5c, 0xc9, 0xf5, 0x5e, 0x4b, 0x7a, 0xde, 0x9f, 0x35, 0x72, + 0x50, 0x3b, 0x6d, 0x6e, 0xe4, 0xda, 0x6e, 0x8a, 0x89, 0x58, 0xb3, 0x56, + 0x8c, 0x29, 0xa1, 0x9f, 0x42, 0x19, 0xb1, 0x2b, 0xcf, 0x48, 0x52, 0x3f, + 0xe4, 0x6f, 0x9e, 0x4f, 0x54, 0x27, 0xe2, 0xe7, 0xba, 0x9c, 0x87, 0x64, + 0x5b, 0xa8, 0xe4, 0x57, 0x97, 0xbd, 0x48, 0x07, 0x9f, 0x49, 0x2f, 0xf2, + 0xb9, 0xe8, 0xab, 0xeb, 0xb8, 0xa5, 0x39, 0x59, 0xbe, 0x31, 0xee, 0xca, + 0xfb, 0xab, 0x16, 0x3a, 0x62, 0x05, 0xe7, 0x18, 0xf9, 0xa9, 0xd6, 0x98, + 0x3e, 0xca, 0xf1, 0x1c, 0x5d, 0x27, 0x97, 0x0f, 0xd2, 0x2f, 0xf3, 0x9d, + 0x42, 0x0b, 0xfb, 0x48, 0x2d, 0xdb, 0xc1, 0xb5, 0xfe, 0xb6, 0x59, 0x62, + 0x7b, 0xd4, 0x7d, 0xc3, 0xa7, 0x9a, 0x72, 0x9d, 0x89, 0xd4, 0x28, 0xe3, + 0x59, 0xd2, 0xa5, 0xb7, 0x76, 0xa8, 0x6d, 0x09, 0xaf, 0x7f, 0x56, 0x95, + 0x71, 0x78, 0xf1, 0xb0, 0x4d, 0x6a, 0x96, 0x91, 0x39, 0x87, 0x84, 0x33, + 0x20, 0xcd, 0xc1, 0x2a, 0x19, 0x43, 0x53, 0x64, 0x80, 0xf1, 0x9c, 0xa8, + 0xf3, 0xf4, 0x90, 0xcf, 0x38, 0x9f, 0xeb, 0xdb, 0x5a, 0x0e, 0x81, 0xd5, + 0x49, 0xef, 0xdc, 0x5f, 0xfa, 0x7f, 0x18, 0x2a, 0x7d, 0x88, 0xc4, 0xe2, + 0xff, 0x02, 0xc7, 0x2a, 0x26, 0xcf, 0x94, 0x1a, 0x00, 0x00, 0x00 }; -static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; +static const u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 }; +static const u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; static struct fw_info bnx2_tpat_fw_06 = { - .ver_major = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, .ver_minor = 0x0, - .ver_fix = 0x0, + .ver_fix = 0x5, - .start_addr = 0x08000860, + .start_addr = 0x08000888, .text_addr = 0x08000800, - .text_len = 0x122c, + .text_len = 0x1a90, .text_index = 0x0, .gz_text = bnx2_TPAT_b06FwText, .gz_text_len = sizeof(bnx2_TPAT_b06FwText), - .data_addr = 0x08001a60, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_TPAT_b06FwData, - .sbss_addr = 0x08001a60, - .sbss_len = 0x34, + .sbss_addr = 0x080022c0, + .sbss_len = 0x44, .sbss_index = 0x0, - .bss_addr = 0x08001aa0, - .bss_len = 0x250, + .bss_addr = 0x08002304, + .bss_len = 0x450, .bss_index = 0x0, .rodata_addr = 0x00000000, @@ -2282,450 +3651,877 @@ static struct fw_info bnx2_tpat_fw_06 = { }; static u8 bnx2_TXP_b06FwText[] = { -/* 0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65, - 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */ - 0xed, 0x5c, 0x6d, 0x6c, - 0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2, - 0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05, - 0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71, - 0x94, 0x86, 0x6e, 0x0d, 0x8c, 0xa0, 0xec, 0xd8, 0xeb, 0x5a, 0x2c, 0x1f, - 0x8c, 0xd5, 0x68, 0xd1, 0x99, 0xa1, 0x68, 0xc7, 0xc9, 0x68, 0x51, 0xa9, - 0xe5, 0xa8, 0x43, 0x57, 0x80, 0x95, 0x64, 0xcb, 0x29, 0x4e, 0x3a, 0x65, - 0xcb, 0x16, 0x0c, 0x58, 0x16, 0xcd, 0x2f, 0x5d, 0x3f, 0x74, 0x80, 0x3f, - 0xec, 0x43, 0x3a, 0xec, 0x83, 0x91, 0x14, 0xad, 0x11, 0x6c, 0x59, 0xb0, - 0x2f, 0x33, 0xd6, 0x26, 0xb7, 0xdf, 0x73, 0x77, 0x94, 0x95, 0xc4, 0x4e, - 0xab, 0x7d, 0xbe, 0x07, 0x20, 0xee, 0x7f, 0xff, 0xd7, 0xe7, 0xfd, 0xe5, - 0x7f, 0x90, 0x06, 0xb7, 0x53, 0x17, 0x85, 0xb0, 0x1d, 0x3f, 0xed, 0x99, - 0x93, 0x27, 0x3e, 0xf7, 0xf9, 0xcf, 0x0d, 0xa1, 0x39, 0x4c, 0x4a, 0x4c, - 0xe4, 0xc1, 0x5b, 0x12, 0x51, 0xf9, 0x1d, 0x8a, 0x20, 0x82, 0x08, 0x22, - 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, - 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, - 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, - 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, - 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, 0x88, 0x20, 0x82, 0x08, 0x22, - 0xf8, 0x9d, 0x20, 0x11, 0xa9, 0xfc, 0xdc, 0x1e, 0xfe, 0x48, 0x11, 0xcd, - 0xf2, 0x53, 0xb6, 0x41, 0x8a, 0x64, 0x1e, 0x39, 0x34, 0x65, 0x10, 0x59, - 0xce, 0x80, 0x56, 0xa0, 0xf7, 0xbd, 0x6a, 0x52, 0x26, 0xee, 0xff, 0xb4, - 0xf9, 0xdb, 0x53, 0xaf, 0x7f, 0x41, 0x7f, 0xaf, 0x25, 0x91, 0xa2, 0x9a, - 0x6b, 0x79, 0xb5, 0x9f, 0x94, 0x34, 0xd6, 0xfc, 0xd5, 0xee, 0xaf, 0xef, - 0xa0, 0x44, 0x7b, 0xaf, 0x24, 0xd5, 0x9b, 0xb7, 0xbc, 0xd7, 0x77, 0x27, - 0xe9, 0x15, 0x57, 0xa5, 0x35, 0x57, 0x16, 0x46, 0x9b, 0x0a, 0x4d, 0x37, - 0x1d, 0x3a, 0xdd, 0xa8, 0x52, 0xc1, 0xbd, 0x4c, 0xb5, 0x39, 0x35, 0x61, - 0x2f, 0xff, 0x84, 0xa6, 0xe7, 0x7a, 0x13, 0x85, 0x65, 0x87, 0x6a, 0x8d, - 0x54, 0xc2, 0x76, 0xd5, 0x44, 0x61, 0x3e, 0x89, 0xf7, 0xde, 0x84, 0x3d, - 0xaf, 0x57, 0x89, 0x76, 0x62, 0x4e, 0x2a, 0x51, 0x68, 0xea, 0x65, 0xa2, - 0xbe, 0xdc, 0x75, 0x4a, 0x27, 0x0a, 0xee, 0x82, 0xb0, 0xae, 0x0a, 0x54, - 0xfb, 0x2c, 0xa9, 0x09, 0xf3, 0xb6, 0xf7, 0x29, 0x43, 0xa5, 0x1e, 0x83, - 0x76, 0xec, 0x30, 0xe8, 0xd9, 0x94, 0xa9, 0x50, 0xe5, 0x7c, 0x9c, 0x2c, - 0x9f, 0x26, 0x95, 0x2a, 0xf3, 0x03, 0xea, 0x15, 0x8a, 0x91, 0x95, 0x6c, - 0xbf, 0x7b, 0x9e, 0x9d, 0xfb, 0x16, 0xff, 0x9d, 0x16, 0xce, 0xa2, 0xc4, - 0xa8, 0x4b, 0x64, 0x03, 0x2f, 0x3b, 0xf7, 0xbe, 0x17, 0xac, 0x51, 0x70, - 0xae, 0x9c, 0x18, 0x69, 0x7a, 0x5e, 0x31, 0x87, 0x33, 0x72, 0xed, 0xb5, - 0x31, 0x6a, 0x25, 0xad, 0xd6, 0x74, 0x2e, 0xbf, 0x23, 0xf8, 0x1b, 0x2f, - 0xa6, 0x91, 0xdf, 0x2d, 0x12, 0x8d, 0xaf, 0x50, 0x25, 0x49, 0xad, 0x5a, - 0xee, 0x61, 0x7a, 0x21, 0xd7, 0x4d, 0x67, 0xb1, 0xdf, 0xf3, 0x39, 0xf0, - 0xd1, 0x38, 0x29, 0xd8, 0xae, 0x9e, 0x22, 0xe1, 0x05, 0xb2, 0xe7, 0xfb, - 0xd4, 0x02, 0xe1, 0x6c, 0xc3, 0xfb, 0x8c, 0x9d, 0xc3, 0x79, 0x83, 0xff, - 0xeb, 0x59, 0x49, 0xbd, 0xdc, 0xa2, 0x14, 0xd5, 0x9a, 0x7d, 0xb9, 0x9f, - 0x93, 0x40, 0x9d, 0x06, 0xf3, 0xc7, 0xa3, 0xc7, 0x70, 0xae, 0x6d, 0xa0, - 0xdf, 0x25, 0x4b, 0xcc, 0xc4, 0xe8, 0x4f, 0x55, 0x5d, 0xb3, 0xa5, 0x5e, - 0xaa, 0x9d, 0xef, 0x04, 0x9e, 0x56, 0xaf, 0x88, 0xb9, 0x63, 0x79, 0x4a, - 0x6e, 0x23, 0x12, 0x24, 0x33, 0x83, 0x7d, 0x89, 0x6a, 0x4e, 0x0a, 0x6b, - 0x33, 0xc3, 0xef, 0xd0, 0x0e, 0xd2, 0x7a, 0x64, 0x9a, 0x76, 0xba, 0xc0, - 0xc7, 0x6e, 0xc8, 0x20, 0x33, 0xfc, 0x2e, 0x84, 0x22, 0x1a, 0x99, 0xd4, - 0x49, 0x2a, 0x0b, 0x05, 0xb7, 0x83, 0xa6, 0x33, 0x0a, 0xd5, 0x81, 0x47, - 0x3d, 0xf7, 0x35, 0xc1, 0x5e, 0x2e, 0x09, 0x85, 0x65, 0xcc, 0x73, 0x5f, - 0x0b, 0xff, 0x76, 0xad, 0x1b, 0xfb, 0x88, 0x54, 0xcb, 0x94, 0x30, 0xa6, - 0xd0, 0x14, 0xe6, 0x4d, 0x81, 0xa6, 0x69, 0x77, 0x07, 0xad, 0x4f, 0x26, - 0x13, 0xcc, 0xab, 0x1a, 0xc6, 0xbf, 0x32, 0x21, 0x90, 0x6a, 0x58, 0xf4, - 0xeb, 0x3c, 0x64, 0x38, 0xdf, 0xcb, 0x32, 0xa3, 0xd3, 0x4d, 0x4a, 0x8a, - 0x94, 0x49, 0x55, 0xe8, 0x32, 0x2d, 0x3a, 0x2c, 0x7f, 0xc8, 0x13, 0xf2, - 0xae, 0x39, 0xbc, 0x0e, 0x72, 0x6b, 0x16, 0xc1, 0x8f, 0x71, 0xe0, 0x70, - 0x50, 0x78, 0x6c, 0x71, 0x52, 0x18, 0x73, 0x7f, 0x93, 0xa0, 0xae, 0x93, - 0xc2, 0x01, 0xf7, 0xa8, 0x10, 0xf2, 0x1e, 0xb2, 0x53, 0xc8, 0x9a, 0x50, - 0xe8, 0x92, 0x1b, 0xc8, 0x6e, 0x01, 0xfa, 0x69, 0xa9, 0x16, 0xe4, 0x70, - 0x78, 0x63, 0x0e, 0x8f, 0xd5, 0x97, 0x65, 0x3a, 0xed, 0xf2, 0xfc, 0x3f, - 0x82, 0x7c, 0x14, 0x72, 0x76, 0x77, 0x53, 0x19, 0xfd, 0xb5, 0x79, 0xb2, - 0xec, 0x9c, 0x88, 0x35, 0x09, 0x92, 0x8c, 0x9d, 0xf8, 0x75, 0xd1, 0xd4, - 0x62, 0xa7, 0x25, 0x19, 0x49, 0x9a, 0x72, 0x99, 0x87, 0x78, 0x36, 0xdb, - 0x7c, 0x64, 0x5c, 0xb9, 0x9f, 0xd7, 0x71, 0xbf, 0x8a, 0xfe, 0xcd, 0x7d, - 0xac, 0x17, 0x09, 0xe0, 0xa3, 0x67, 0x59, 0x9f, 0x2b, 0xcd, 0x8c, 0x7a, - 0x80, 0x9f, 0x2e, 0xf3, 0xb6, 0xcd, 0x53, 0x19, 0x73, 0x45, 0xaa, 0x2c, - 0xe2, 0x9c, 0xf3, 0xbf, 0xf5, 0x62, 0x79, 0xbc, 0x1b, 0x1d, 0xa0, 0x8b, - 0xcf, 0x95, 0x81, 0x93, 0x48, 0xe5, 0x45, 0xde, 0x8b, 0xc7, 0x09, 0xb2, - 0xaf, 0xf5, 0x88, 0x94, 0x85, 0x7c, 0x75, 0x9c, 0x13, 0xc7, 0x9c, 0x6e, - 0xf0, 0x0f, 0xb4, 0x2e, 0xa3, 0x0d, 0xda, 0x45, 0x43, 0xc4, 0xfa, 0x4e, - 0x9a, 0xca, 0xb1, 0xbe, 0x30, 0x9e, 0xdb, 0xb0, 0x77, 0x9c, 0x8e, 0x9c, - 0x67, 0x7e, 0xc8, 0xf4, 0x3c, 0x70, 0x9c, 0x9e, 0xd7, 0xd5, 0x22, 0xe9, - 0xe0, 0x8d, 0x85, 0x79, 0x9d, 0x54, 0x56, 0x3d, 0x6f, 0x24, 0x37, 0xa0, - 0xbe, 0xec, 0xeb, 0xf9, 0x80, 0x9a, 0x11, 0xa8, 0xda, 0x61, 0xfe, 0x21, - 0x70, 0xd0, 0x4b, 0x44, 0xfc, 0xfe, 0xcf, 0x64, 0x4d, 0xb2, 0xfd, 0x24, - 0xf9, 0x2c, 0xd8, 0xd3, 0x4e, 0xe0, 0xcf, 0x36, 0x97, 0x86, 0x5c, 0x52, - 0xbe, 0x1d, 0x8c, 0xdc, 0xd5, 0x0e, 0xf4, 0xf1, 0x16, 0x6c, 0xa6, 0xb6, - 0x2c, 0xb3, 0xfd, 0xe5, 0xa0, 0x6e, 0xb4, 0xcd, 0x80, 0x6e, 0xf9, 0xb2, - 0xd9, 0x8f, 0xfd, 0x3d, 0xef, 0xcb, 0xb9, 0x00, 0xa7, 0xda, 0xbc, 0x85, - 0xb5, 0x32, 0xf8, 0xae, 0x1f, 0xd7, 0xfc, 0xf3, 0xf7, 0x87, 0xe7, 0xab, - 0x34, 0x05, 0xbc, 0x6b, 0x4d, 0x89, 0x0a, 0x2a, 0xef, 0xf1, 0x2e, 0xf7, - 0x97, 0x83, 0xbd, 0xa0, 0xb7, 0xe7, 0xfa, 0xd4, 0x7d, 0xb0, 0x25, 0xb6, - 0xb1, 0xda, 0x0a, 0xf3, 0x18, 0xfb, 0xe4, 0x99, 0xc7, 0xaa, 0x8f, 0xa3, - 0x3d, 0xcf, 0x7a, 0x44, 0x69, 0x89, 0x58, 0xcf, 0x2f, 0xb3, 0x2e, 0x41, - 0x3f, 0x03, 0xbd, 0xaa, 0x38, 0x2c, 0xff, 0x2f, 0x85, 0xf6, 0x29, 0x52, - 0x7f, 0x86, 0xf5, 0xfd, 0x05, 0x2a, 0xc0, 0xc6, 0xa7, 0x70, 0xd2, 0x22, - 0x68, 0x5a, 0x68, 0xf6, 0x81, 0x57, 0x6d, 0xbb, 0x83, 0x7c, 0x07, 0xff, - 0xc7, 0x0b, 0xe6, 0x77, 0x03, 0x27, 0xb6, 0x99, 0x9a, 0x2a, 0x52, 0x15, - 0x3f, 0xe8, 0x8d, 0xa1, 0x67, 0x6d, 0x49, 0x9f, 0x28, 0x03, 0x37, 0xe8, - 0x3d, 0xd9, 0x7b, 0x58, 0x9f, 0x31, 0xc7, 0xa5, 0xa1, 0xb6, 0x9d, 0x2d, - 0x38, 0x2c, 0xa7, 0x2e, 0x9c, 0xdb, 0xc6, 0x49, 0x46, 0x1f, 0xef, 0xa3, - 0x40, 0xe7, 0xdb, 0x3a, 0xc3, 0xfa, 0xa7, 0x5b, 0xeb, 0xd4, 0x41, 0xd9, - 0x0c, 0x7c, 0xd9, 0xbc, 0x08, 0xf9, 0xa5, 0xe1, 0x53, 0x64, 0x7a, 0xba, - 0x99, 0xa4, 0x63, 0x4d, 0xc6, 0xaf, 0x08, 0xbb, 0x83, 0x6f, 0x9b, 0x1f, - 0x85, 0x9d, 0x8d, 0x0b, 0x23, 0xb0, 0x89, 0x47, 0x17, 0x19, 0x27, 0x8f, - 0xd8, 0x2e, 0x8b, 0xcb, 0x65, 0x61, 0xd4, 0x2d, 0x09, 0xe3, 0xcb, 0x6c, - 0x27, 0x6c, 0x23, 0xba, 0xfa, 0x38, 0x31, 0x0d, 0x98, 0xe3, 0xfe, 0x22, - 0xc1, 0xb6, 0x5a, 0x3b, 0x17, 0x07, 0x1e, 0xdb, 0x80, 0x4f, 0x37, 0x6c, - 0x0f, 0xfa, 0x65, 0xe8, 0x13, 0xac, 0x33, 0xc5, 0x8c, 0xa1, 0xfd, 0x25, - 0x7d, 0x9c, 0x0f, 0x23, 0x1b, 0x7c, 0x18, 0x00, 0x4f, 0x3e, 0xcc, 0x87, - 0xfa, 0xc7, 0xf9, 0x60, 0x55, 0xc1, 0x87, 0x3a, 0xfc, 0x50, 0xdd, 0x65, - 0x9a, 0x3d, 0x12, 0xf7, 0x10, 0xb4, 0x93, 0xf6, 0x8a, 0x26, 0xeb, 0x28, - 0xdb, 0x49, 0x46, 0x9b, 0xc6, 0x0e, 0x4b, 0x4e, 0xb7, 0x6f, 0x1b, 0xa3, - 0x3e, 0x2f, 0x7e, 0x17, 0xbd, 0x4c, 0xdf, 0x1d, 0x9a, 0xc7, 0x17, 0xd9, - 0xdf, 0x40, 0xcf, 0x33, 0x86, 0x7a, 0x88, 0xee, 0xd0, 0xbd, 0xef, 0x0e, - 0xdd, 0x38, 0xa7, 0xed, 0x83, 0x98, 0xe6, 0xb6, 0x3f, 0x66, 0x5d, 0x79, - 0xc3, 0x93, 0x0c, 0x03, 0x32, 0x60, 0x7d, 0x61, 0x1c, 0x74, 0xf5, 0xcb, - 0xa0, 0xa7, 0x02, 0xbf, 0xc0, 0xb6, 0x54, 0xf6, 0xe7, 0x75, 0x50, 0xb9, - 0x27, 0x98, 0x3f, 0xd5, 0xf4, 0xfe, 0x4b, 0x34, 0x3f, 0xf0, 0xec, 0xbc, - 0x11, 0xda, 0xb8, 0x42, 0x7f, 0xb2, 0xa8, 0x97, 0x35, 0xa1, 0x9b, 0xaa, - 0xf7, 0xc3, 0xaf, 0x34, 0xd9, 0x3e, 0x76, 0xde, 0xc3, 0x97, 0xa5, 0x43, - 0x5f, 0xf6, 0x3e, 0x78, 0xcf, 0xb1, 0xe7, 0xe8, 0x07, 0xeb, 0x49, 0x7e, - 0x66, 0xd4, 0x09, 0x2a, 0x71, 0xbc, 0xd9, 0x21, 0xfa, 0xfe, 0xbb, 0x8f, - 0x63, 0x41, 0x55, 0x36, 0xe3, 0x54, 0xed, 0xa1, 0xaa, 0x64, 0xb2, 0x1d, - 0xb1, 0x6d, 0xb4, 0xf1, 0xde, 0x1e, 0xc6, 0xdd, 0x41, 0x89, 0x0c, 0x1e, - 0x47, 0x8c, 0x68, 0x32, 0x0d, 0xef, 0x87, 0xf2, 0x60, 0x7f, 0x4a, 0xb1, - 0x40, 0xdf, 0xf6, 0xc3, 0x5f, 0x32, 0x3f, 0x37, 0xeb, 0x0a, 0xfb, 0x51, - 0xd2, 0x44, 0x83, 0xfd, 0x28, 0xa9, 0x92, 0x79, 0x50, 0xb0, 0x16, 0xbf, - 0x26, 0x58, 0xe0, 0x9b, 0x05, 0xbe, 0x59, 0xe0, 0x9b, 0x0d, 0xbe, 0x15, - 0x5c, 0xc6, 0x85, 0xf1, 0x08, 0xf6, 0x2f, 0x06, 0xfb, 0x03, 0xc7, 0x9d, - 0x54, 0xf1, 0xed, 0x9b, 0x69, 0x85, 0x3f, 0xf6, 0x7d, 0xc1, 0xa8, 0x10, - 0xf8, 0x02, 0xde, 0x6f, 0x1c, 0xeb, 0x1f, 0x47, 0x8c, 0xb3, 0x44, 0xd1, - 0xb8, 0xc3, 0x8f, 0xfa, 0x26, 0x7e, 0x4c, 0x3b, 0xcc, 0x1f, 0x9e, 0xcf, - 0x76, 0xec, 0x40, 0xe6, 0x6d, 0x9e, 0xec, 0x07, 0x0e, 0x9d, 0x4c, 0x77, - 0x48, 0x07, 0xef, 0xdf, 0x1b, 0xee, 0x7f, 0x00, 0x7b, 0xb2, 0xdd, 0xde, - 0xed, 0x5c, 0x3e, 0x93, 0xe3, 0xe8, 0x27, 0xd1, 0x83, 0x3c, 0x02, 0x7e, - 0x66, 0x0d, 0x76, 0x76, 0x53, 0x4a, 0xd1, 0xeb, 0xbb, 0x6f, 0x20, 0xb7, - 0xa0, 0xea, 0x03, 0xa6, 0xa7, 0xc9, 0xe6, 0xfb, 0x5e, 0x3d, 0x0f, 0xdf, - 0x69, 0xea, 0x29, 0x5b, 0x1a, 0xa4, 0x37, 0xdc, 0x2c, 0xfd, 0x9d, 0x6b, - 0xd0, 0xdf, 0xba, 0x1a, 0xbd, 0xea, 0xa6, 0xe9, 0x6f, 0xdc, 0x14, 0xfd, - 0xb5, 0xdb, 0xce, 0x43, 0x92, 0xac, 0x47, 0x89, 0xa2, 0x7b, 0xb7, 0x5c, - 0x08, 0x3a, 0x8e, 0xbd, 0xec, 0xbc, 0x5c, 0x96, 0x4d, 0x3f, 0x3f, 0x98, - 0x98, 0x6e, 0x90, 0xb2, 0xd3, 0xa0, 0xed, 0xf7, 0x23, 0xef, 0x49, 0x9a, - 0xb4, 0xe3, 0x3e, 0x3c, 0x7b, 0x4d, 0xb2, 0x7a, 0xcc, 0x53, 0x9e, 0x68, - 0xb0, 0x1e, 0x75, 0x0f, 0x4f, 0xe5, 0xe3, 0x8c, 0xfb, 0xc4, 0x34, 0xfc, - 0x91, 0x8d, 0xb3, 0xaa, 0xd0, 0xc5, 0xaa, 0x7b, 0xe8, 0xfe, 0x20, 0x17, - 0x7a, 0x2f, 0xcc, 0x89, 0x38, 0xaf, 0x5a, 0x7f, 0x6a, 0xc2, 0x60, 0x3f, - 0x2b, 0x6c, 0xf2, 0xb3, 0x24, 0x14, 0x41, 0x53, 0x1d, 0xb8, 0x16, 0x41, - 0xe7, 0x57, 0x5d, 0x45, 0x28, 0x9c, 0xef, 0xa5, 0xe9, 0x45, 0x8e, 0x55, - 0x3c, 0x4f, 0x09, 0x73, 0x19, 0x7e, 0xef, 0xc0, 0x3b, 0x21, 0x7e, 0x14, - 0xb6, 0x53, 0x42, 0x7f, 0x73, 0x82, 0x9c, 0x30, 0x17, 0x89, 0xd1, 0x05, - 0x5f, 0x77, 0xb8, 0xdf, 0x2a, 0xfd, 0xb0, 0xff, 0x4e, 0xff, 0xf9, 0x8d, - 0xfe, 0x72, 0xe9, 0xeb, 0x1b, 0xfd, 0xef, 0xa8, 0x01, 0x4e, 0xc3, 0xc2, - 0xe3, 0xee, 0xf3, 0x61, 0xdf, 0x6d, 0xf0, 0xd3, 0xf3, 0xea, 0x88, 0x27, - 0x35, 0xe3, 0x36, 0x72, 0x1f, 0xf6, 0x29, 0x5b, 0xf1, 0x21, 0x1f, 0xf2, - 0x1f, 0xaa, 0x2d, 0xb1, 0x9c, 0x14, 0x0a, 0xf6, 0xe4, 0xf1, 0x4e, 0xf8, - 0x92, 0xdb, 0x68, 0x73, 0xec, 0x6a, 0xfb, 0x31, 0x9e, 0xc3, 0xeb, 0x6f, - 0xdd, 0x43, 0x96, 0x2a, 0x64, 0xb9, 0x35, 0x79, 0xd5, 0x1a, 0xa7, 0x42, - 0x9f, 0xd0, 0x3d, 0x6c, 0x43, 0x2e, 0x12, 0xe4, 0x52, 0x83, 0x5c, 0x0a, - 0xf7, 0x94, 0x0b, 0xce, 0xd8, 0xd0, 0x29, 0xc6, 0xa3, 0x2b, 0x3c, 0x9b, - 0x14, 0xd9, 0xac, 0x96, 0xea, 0xc6, 0xa7, 0x28, 0x66, 0x30, 0x1e, 0x06, - 0xf0, 0x38, 0x8a, 0xb5, 0x1c, 0xc3, 0x48, 0x89, 0x99, 0x2c, 0xcf, 0xdc, - 0x13, 0xb6, 0x71, 0xab, 0xb4, 0xe0, 0xdc, 0x2a, 0x5d, 0x34, 0xf8, 0xfd, - 0xf6, 0x64, 0x90, 0x37, 0x77, 0x3f, 0x89, 0xbc, 0x19, 0xeb, 0xd9, 0x1f, - 0x72, 0xff, 0x30, 0xe6, 0x71, 0x7c, 0xa0, 0x43, 0x35, 0xfc, 0xea, 0xfe, - 0xdc, 0x6b, 0x4f, 0xf0, 0xdc, 0x4e, 0x53, 0x9e, 0xfc, 0x35, 0x9e, 0x1d, - 0xa6, 0xf6, 0xe4, 0x4f, 0x0d, 0xde, 0x77, 0x78, 0xf2, 0xa2, 0xbf, 0x07, - 0x62, 0xa6, 0xbf, 0x36, 0xfb, 0x24, 0xaf, 0x7d, 0x0e, 0x3e, 0xf6, 0x0c, - 0xe2, 0xcb, 0x69, 0x47, 0x3b, 0x54, 0xc1, 0x6f, 0x8a, 0x71, 0x6a, 0xf2, - 0xb8, 0x85, 0x71, 0x19, 0xb1, 0x90, 0xdb, 0x0a, 0x1d, 0xc3, 0xbc, 0xa7, - 0x31, 0xef, 0xa8, 0x33, 0x8e, 0xbc, 0xbd, 0x4d, 0xd7, 0xbf, 0xc5, 0x0b, - 0xf3, 0xec, 0xcf, 0x91, 0xed, 0xaf, 0xfc, 0x7b, 0xdc, 0x86, 0x5f, 0x16, - 0x57, 0x6e, 0xc6, 0x0b, 0xa0, 0x5b, 0x5a, 0xf9, 0x45, 0xbc, 0x08, 0x3d, - 0x13, 0x0d, 0x09, 0x7e, 0xf9, 0x33, 0x54, 0x53, 0x3d, 0x7a, 0x19, 0xf1, - 0xab, 0x96, 0x85, 0xbf, 0x82, 0x34, 0x45, 0x03, 0x7e, 0x4c, 0x25, 0xa5, - 0xcb, 0x3c, 0xa9, 0x52, 0x57, 0x3e, 0x6e, 0x23, 0xde, 0xd4, 0x54, 0x09, - 0xfd, 0xfd, 0x78, 0x6e, 0xee, 0xff, 0x65, 0x1c, 0x7e, 0x0b, 0x3e, 0x82, - 0x14, 0x3b, 0xdf, 0x8d, 0xfd, 0xbf, 0x8d, 0x7e, 0x4c, 0xc8, 0x6c, 0xf4, - 0x3f, 0x1b, 0xf4, 0xdf, 0x02, 0x2e, 0xbc, 0x8e, 0xe3, 0x27, 0x29, 0x53, - 0x79, 0x15, 0x38, 0xf0, 0xdc, 0xa4, 0x3f, 0xb7, 0x38, 0xcf, 0x3c, 0xa8, - 0x96, 0x16, 0x8c, 0x34, 0x15, 0xe6, 0x92, 0x34, 0x3a, 0xa7, 0xd2, 0xd8, - 0x9c, 0x3e, 0xd1, 0x62, 0xfb, 0x01, 0xcd, 0x84, 0x1c, 0x41, 0x5c, 0x21, - 0x50, 0xac, 0xa7, 0x9e, 0xa6, 0xbe, 0xd4, 0x31, 0xfa, 0x6f, 0x0f, 0xb1, - 0x08, 0x71, 0xa8, 0x9b, 0x64, 0x7f, 0x9f, 0x54, 0xfb, 0x4c, 0x96, 0xd1, - 0x87, 0xce, 0x2d, 0xce, 0xdf, 0x6b, 0x5f, 0x28, 0xf1, 0x4a, 0xea, 0x23, - 0xfb, 0xbe, 0x1b, 0xee, 0xab, 0x62, 0xdf, 0x34, 0xf6, 0x64, 0x1a, 0xf5, - 0xf8, 0xc8, 0x79, 0xb2, 0x3a, 0x81, 0x5f, 0x31, 0x83, 0x98, 0x8f, 0x7d, - 0xce, 0xcc, 0xb1, 0xde, 0xd3, 0x4e, 0xfc, 0x06, 0x63, 0x94, 0xc9, 0x2e, - 0x23, 0x27, 0x18, 0xf1, 0xf7, 0x08, 0xf2, 0x05, 0x71, 0x65, 0x10, 0xf9, - 0xda, 0x3b, 0xc0, 0x87, 0xe3, 0x18, 0xd3, 0x2c, 0x83, 0xde, 0x41, 0xe4, - 0x09, 0x9c, 0xe3, 0x7b, 0xa7, 0xec, 0x1c, 0xda, 0xcb, 0x5a, 0xbc, 0x00, - 0xdb, 0x16, 0x4d, 0x7a, 0x50, 0xf2, 0x7d, 0x2c, 0xcb, 0x65, 0x10, 0x72, - 0x62, 0xbc, 0x73, 0x90, 0x13, 0xf3, 0x68, 0x38, 0x5e, 0x6c, 0x32, 0x8f, - 0x08, 0xf8, 0x68, 0xb0, 0x27, 0xd9, 0xcf, 0xf3, 0xc5, 0x15, 0x0b, 0xf3, - 0x7e, 0xac, 0x72, 0x2e, 0x66, 0x1b, 0xdc, 0x86, 0xed, 0xac, 0x8c, 0x63, - 0x2e, 0xb7, 0x1f, 0xc6, 0xbe, 0x7d, 0xb9, 0x1a, 0x75, 0xe4, 0x9e, 0x86, - 0xdd, 0x8a, 0xf9, 0x01, 0xc4, 0x68, 0x01, 0xb9, 0xa0, 0xe7, 0x75, 0xe4, - 0xbf, 0x00, 0x7a, 0x98, 0x0e, 0xe8, 0xf5, 0x2c, 0xf3, 0x95, 0xfe, 0x40, - 0xe4, 0x5c, 0x2d, 0xdf, 0xce, 0x6b, 0x38, 0x9e, 0xf3, 0xf9, 0x88, 0x23, - 0x8d, 0x3d, 0x88, 0xa5, 0xfe, 0xd9, 0xd0, 0xb1, 0x71, 0x2a, 0x34, 0x3e, - 0x8b, 0x9c, 0x93, 0x6d, 0x67, 0x9b, 0x60, 0x9f, 0x67, 0x1a, 0x09, 0xb1, - 0x66, 0x8d, 0x2a, 0x0d, 0x39, 0x6c, 0xbf, 0x8a, 0xb6, 0x12, 0xb6, 0xd7, - 0xd1, 0xee, 0x0e, 0xdb, 0xd7, 0xd0, 0x56, 0xc3, 0xf6, 0xcf, 0xd0, 0x4e, - 0x86, 0xed, 0x9f, 0xa3, 0x9d, 0x0a, 0xdb, 0x37, 0xd1, 0x4e, 0x87, 0xed, - 0x5b, 0x68, 0x6b, 0x61, 0xfb, 0x3d, 0xb4, 0x13, 0xb0, 0x73, 0x03, 0xef, - 0x37, 0x50, 0x2b, 0x66, 0xf1, 0xfc, 0x57, 0xe0, 0x36, 0x08, 0xde, 0x64, - 0xc1, 0x8f, 0x5e, 0x8c, 0xe5, 0xd0, 0x87, 0x1c, 0xb1, 0x91, 0xc7, 0xd3, - 0xc1, 0x18, 0x95, 0x61, 0x7b, 0x18, 0x1f, 0x2f, 0x16, 0x1a, 0x26, 0x9e, - 0x6c, 0x0f, 0xba, 0x4a, 0xc2, 0x65, 0xd8, 0xb9, 0xef, 0x63, 0x72, 0xb6, - 0x34, 0x09, 0xdb, 0x9e, 0xa0, 0x7f, 0x74, 0xf7, 0xd3, 0x6b, 0xee, 0x38, - 0xe2, 0x46, 0x11, 0x71, 0xc3, 0x42, 0xdc, 0x30, 0x11, 0x37, 0x86, 0x11, - 0x37, 0xf2, 0x88, 0x1b, 0x39, 0xc4, 0x0d, 0xa2, 0x33, 0x7e, 0x8c, 0x4a, - 0x2a, 0xa8, 0x51, 0x15, 0xcb, 0x2d, 0x82, 0xbf, 0x13, 0x90, 0xcd, 0x24, - 0x78, 0x7d, 0x38, 0x3e, 0xd2, 0xcc, 0xc3, 0x9f, 0x69, 0xf0, 0x11, 0x69, - 0xf8, 0xf2, 0x1c, 0x6a, 0x13, 0xa2, 0x2b, 0xb3, 0x1a, 0xfc, 0x8f, 0x47, - 0x45, 0xc4, 0xfe, 0x69, 0x15, 0xb8, 0x19, 0xbb, 0x7c, 0x9b, 0x91, 0xcc, - 0x2f, 0xf6, 0x50, 0xd7, 0x20, 0xe8, 0x39, 0x8b, 0xbe, 0x14, 0xf6, 0x63, - 0xbe, 0xde, 0x2a, 0xd9, 0x86, 0x46, 0x0b, 0x6e, 0x1c, 0xfe, 0x9f, 0xdf, - 0xe3, 0xcc, 0xe3, 0x43, 0x4f, 0x19, 0x4c, 0x03, 0xea, 0x3c, 0x23, 0xad, - 0x14, 0x1c, 0x81, 0x24, 0x93, 0x9f, 0xed, 0x1c, 0xe2, 0xcf, 0x90, 0x43, - 0x74, 0x41, 0x06, 0x55, 0xc4, 0x05, 0x9d, 0xf3, 0x0b, 0xe8, 0xf2, 0x27, - 0xcd, 0xff, 0x1e, 0xe6, 0xef, 0xc5, 0xd9, 0x3c, 0x8f, 0xcf, 0x39, 0x85, - 0xfa, 0xc1, 0xea, 0x91, 0x68, 0x3d, 0x25, 0xa1, 0x9e, 0x28, 0xd0, 0x59, - 0x2a, 0x00, 0x9f, 0x82, 0xdb, 0xbe, 0x07, 0xb0, 0x0e, 0x05, 0xfe, 0x6c, - 0xe2, 0xd0, 0xb7, 0x0d, 0x0b, 0xeb, 0x18, 0x3f, 0xd6, 0x5b, 0xe0, 0xbe, - 0xb1, 0xe7, 0x05, 0xec, 0xf9, 0x4f, 0x49, 0xea, 0x9a, 0x0c, 0xfc, 0x91, - 0x5f, 0xf3, 0xca, 0xc2, 0x48, 0xf3, 0x2c, 0xf8, 0xd3, 0x87, 0x1a, 0x05, - 0x7e, 0xa4, 0xd4, 0x02, 0x9f, 0xda, 0xf3, 0x5f, 0xc1, 0x7c, 0x7e, 0xf7, - 0xef, 0x0e, 0x4a, 0xd2, 0xea, 0x12, 0xe6, 0x69, 0xac, 0x3f, 0x25, 0xb9, - 0xff, 0x86, 0xf7, 0xa2, 0x91, 0xa7, 0x5d, 0xab, 0xbc, 0x2e, 0x4b, 0x7d, - 0xab, 0x37, 0xbc, 0x9a, 0xa3, 0xd1, 0x62, 0x93, 0xc0, 0xab, 0xf8, 0x6d, - 0x8b, 0xf4, 0x35, 0x12, 0xf5, 0x59, 0x0b, 0x7a, 0x5a, 0x1c, 0x12, 0xc9, - 0x1e, 0xea, 0x84, 0x8f, 0x32, 0x68, 0x09, 0x7c, 0xdf, 0x35, 0x63, 0xd1, - 0x13, 0x43, 0xed, 0x7c, 0x10, 0x51, 0x0f, 0xb8, 0xee, 0x5a, 0xd5, 0x30, - 0x87, 0x73, 0x71, 0xa6, 0x45, 0x03, 0x2f, 0x85, 0x60, 0x8d, 0x1f, 0xb3, - 0xb8, 0x8e, 0x05, 0xdf, 0xdc, 0xb5, 0xd2, 0xd5, 0x19, 0xd4, 0x1a, 0x90, - 0xf3, 0xae, 0x19, 0xae, 0x85, 0xb6, 0x81, 0x2f, 0x31, 0xd8, 0x06, 0xe7, - 0xf1, 0x08, 0xf4, 0xf0, 0x87, 0x27, 0xe0, 0xf1, 0x6b, 0xcd, 0x13, 0xd0, - 0xfb, 0x2e, 0x2a, 0xcb, 0x3e, 0x11, 0x9f, 0xc0, 0xe3, 0xff, 0xe4, 0xbc, - 0x0e, 0xf3, 0xbf, 0x4b, 0xc5, 0xd9, 0x2e, 0xec, 0xb5, 0x9b, 0xa6, 0x93, - 0x8c, 0x9b, 0x3e, 0x8c, 0x41, 0x2d, 0x06, 0x7e, 0xc6, 0xcd, 0x8f, 0xe6, - 0x7d, 0x6b, 0xa5, 0x2b, 0x33, 0x6b, 0xa5, 0x6b, 0xa0, 0xbf, 0x6e, 0x70, - 0x8d, 0x0c, 0x5d, 0x6a, 0x70, 0x6d, 0xcf, 0x79, 0xd1, 0x18, 0x74, 0x64, - 0xbf, 0x5f, 0x33, 0xdb, 0x8b, 0x39, 0xea, 0x3b, 0x47, 0xaa, 0x68, 0x96, - 0x84, 0x31, 0xe4, 0x45, 0x23, 0xee, 0x49, 0x7f, 0xee, 0x99, 0x06, 0xd7, - 0x2b, 0x18, 0x5b, 0x61, 0x5d, 0x18, 0x03, 0x3e, 0x49, 0xba, 0xe8, 0xb2, - 0x4f, 0x0a, 0xec, 0x78, 0x0c, 0xfc, 0x5a, 0xf0, 0xe9, 0x4a, 0x71, 0x1c, - 0x47, 0xbe, 0xc1, 0xf2, 0xf9, 0x21, 0xc7, 0x41, 0xa1, 0xd3, 0x6c, 0xfb, - 0xdb, 0x89, 0x5e, 0xe6, 0x59, 0xa1, 0x01, 0xdf, 0x3f, 0x34, 0x11, 0xe6, - 0x1c, 0x7f, 0x8f, 0x39, 0x8c, 0x3b, 0xcd, 0x4a, 0x26, 0xce, 0xc8, 0x33, - 0xcf, 0x38, 0xa7, 0xe4, 0x7d, 0xc1, 0x5b, 0xf0, 0x7d, 0x53, 0x6e, 0xe9, - 0xc3, 0x74, 0x33, 0x46, 0x95, 0x59, 0xf0, 0x2e, 0x8f, 0x27, 0x9c, 0x6b, - 0x1d, 0x7c, 0x03, 0x2d, 0xd5, 0x20, 0x9f, 0x3d, 0xc1, 0x31, 0x0d, 0xfe, - 0x06, 0x36, 0xcd, 0x31, 0x6b, 0xe3, 0xde, 0xc9, 0xf7, 0x25, 0x32, 0x19, - 0x41, 0xce, 0x2a, 0xe2, 0x2c, 0x3b, 0xcf, 0x7e, 0x10, 0xf8, 0xb8, 0xdf, - 0xa5, 0xfa, 0x2c, 0xd3, 0x05, 0x1b, 0x4f, 0xb2, 0x2e, 0xfe, 0x7f, 0xf9, - 0x38, 0xba, 0x45, 0x3e, 0x8e, 0x6e, 0x99, 0x8f, 0x12, 0xf8, 0x58, 0xd9, - 0xe0, 0xa3, 0x82, 0x3d, 0xf8, 0x3e, 0xe1, 0xab, 0x64, 0x4d, 0x3c, 0x02, - 0x3f, 0x0c, 0xff, 0xd1, 0x3c, 0x05, 0x9f, 0x70, 0x52, 0xb8, 0xda, 0xf0, - 0x68, 0x1c, 0xb5, 0xb2, 0x74, 0xff, 0x66, 0xfa, 0x33, 0xa0, 0xff, 0xcf, - 0x31, 0x5e, 0xa5, 0x6b, 0xb3, 0x94, 0x56, 0xa8, 0x7d, 0x2e, 0xed, 0x92, - 0xe9, 0x3b, 0x74, 0x75, 0xb6, 0x8b, 0xae, 0xcf, 0x66, 0xc0, 0xeb, 0x2c, - 0xc5, 0x7a, 0x32, 0xc3, 0x15, 0x18, 0xf1, 0xcf, 0x5a, 0xba, 0xc5, 0xba, - 0xf8, 0xfb, 0xf3, 0x82, 0xf9, 0x70, 0xd0, 0xe7, 0xc3, 0xd8, 0x47, 0xf8, - 0x30, 0x7e, 0x4f, 0x3e, 0x1c, 0xfc, 0x18, 0x1f, 0xc6, 0x3f, 0xc6, 0x07, - 0xe6, 0x01, 0xf3, 0xe2, 0xd1, 0xde, 0xf0, 0xff, 0x1f, 0x7d, 0x82, 0x7d, - 0x7c, 0x09, 0x74, 0x22, 0xa7, 0xd8, 0x19, 0xe4, 0x50, 0x9c, 0x63, 0xd5, - 0x0c, 0xe6, 0x57, 0x60, 0xbf, 0x32, 0x72, 0xea, 0x23, 0xa1, 0xfd, 0x16, - 0x1c, 0xe8, 0x65, 0x23, 0xe6, 0xdb, 0xaf, 0x64, 0xe6, 0xe1, 0x03, 0xaa, - 0xa5, 0x96, 0xc3, 0xfe, 0x07, 0x6d, 0x87, 0x79, 0xda, 0x0b, 0x5a, 0x12, - 0x54, 0x99, 0x54, 0x10, 0x5f, 0x87, 0xa1, 0xb7, 0x71, 0xdf, 0x07, 0x4a, - 0x26, 0xeb, 0xe1, 0x7e, 0xcc, 0x3f, 0x1c, 0xe6, 0x45, 0x88, 0x73, 0x38, - 0xa3, 0xd6, 0x38, 0x0d, 0xfc, 0xf8, 0x9c, 0x6a, 0xa9, 0xec, 0xf0, 0x9a, - 0x34, 0x62, 0x21, 0x3f, 0x37, 0xeb, 0xb7, 0xaf, 0xef, 0xf7, 0xd2, 0x71, - 0xe8, 0x26, 0xeb, 0xb4, 0x82, 0xdc, 0x78, 0x02, 0xf1, 0xc5, 0xd7, 0xd3, - 0xec, 0x02, 0xb1, 0xdf, 0x7f, 0x06, 0x75, 0xd1, 0x61, 0xfc, 0x34, 0x1a, - 0x71, 0x03, 0x9b, 0x5a, 0xf2, 0xcf, 0xfc, 0xb0, 0x4f, 0xaa, 0x39, 0xeb, - 0xc8, 0xdf, 0x0d, 0xec, 0xcb, 0xe7, 0x56, 0xc1, 0x1b, 0x09, 0xe7, 0x72, - 0x5f, 0x37, 0xe2, 0x00, 0xf8, 0xe4, 0xfe, 0x07, 0xfa, 0x97, 0xe0, 0x1f, - 0x39, 0x2f, 0x68, 0xe3, 0x8e, 0x1c, 0xc2, 0xe1, 0x78, 0x9d, 0x07, 0xcd, - 0x9c, 0x63, 0x73, 0x2e, 0x81, 0xfc, 0x63, 0xe9, 0x4d, 0xf4, 0x0d, 0xd3, - 0xe9, 0xa1, 0x2c, 0xe4, 0xc3, 0x7d, 0x0f, 0x84, 0x7d, 0x3c, 0x8f, 0x94, - 0x07, 0x4d, 0xfd, 0x07, 0x55, 0xdf, 0xaf, 0x43, 0x0f, 0x51, 0xf7, 0xd5, - 0x96, 0x90, 0x63, 0x00, 0xa7, 0xca, 0x6a, 0x16, 0xb9, 0x3c, 0xdf, 0xab, - 0xe9, 0x97, 0x91, 0x07, 0x83, 0x27, 0x0a, 0xf5, 0x1a, 0xa5, 0xd0, 0x0f, - 0xe7, 0x40, 0x1f, 0xdf, 0x3d, 0xf5, 0x21, 0xf7, 0x91, 0xc0, 0x08, 0xd8, - 0xe9, 0xaa, 0x44, 0x7b, 0xe5, 0x01, 0xb5, 0x46, 0xff, 0x80, 0xb9, 0x32, - 0x95, 0x57, 0x39, 0x87, 0x90, 0xe9, 0xc8, 0x2a, 0xd1, 0x5b, 0x33, 0xec, - 0x97, 0x19, 0xd8, 0x2f, 0xb3, 0x7f, 0x7d, 0xd0, 0x1f, 0x7b, 0x6b, 0x06, - 0x35, 0xf8, 0xcc, 0x00, 0xc7, 0xb0, 0x75, 0x11, 0xbc, 0x44, 0xee, 0xc3, - 0xf9, 0xf9, 0x5d, 0xee, 0x98, 0xda, 0xf7, 0x4b, 0x0a, 0x55, 0x66, 0xf8, - 0x6e, 0x49, 0xc6, 0xf9, 0x5c, 0x5b, 0x6c, 0x03, 0x7e, 0x02, 0xa1, 0xee, - 0x12, 0x38, 0xa6, 0x09, 0xd0, 0xa1, 0x5d, 0x90, 0x3d, 0xf8, 0x1f, 0xb6, - 0xdb, 0xfa, 0xf4, 0x2f, 0xd0, 0x27, 0x9e, 0x27, 0x6f, 0xc2, 0x25, 0x33, - 0x6b, 0x8b, 0x1c, 0x1f, 0x3e, 0x0d, 0xdb, 0xb3, 0xe2, 0x63, 0xcd, 0x0e, - 0x6a, 0xf5, 0xb2, 0x3d, 0xb0, 0x5e, 0x5c, 0x66, 0x9d, 0xc0, 0x19, 0xd0, - 0xa1, 0x19, 0xae, 0xe7, 0x65, 0xcc, 0xbb, 0x2f, 0x9c, 0xc7, 0xfc, 0xfe, - 0x1e, 0x4d, 0x0f, 0xa9, 0x42, 0x59, 0x0d, 0xe2, 0x45, 0x6d, 0xa8, 0x03, - 0x63, 0x22, 0x1d, 0x7c, 0x38, 0x8f, 0xb5, 0x9c, 0x53, 0xc5, 0x85, 0xc0, - 0x6f, 0x71, 0x1f, 0xdf, 0xd7, 0xa9, 0x54, 0xbe, 0xd4, 0x4b, 0x95, 0x4b, - 0x0a, 0xf8, 0x02, 0x44, 0x17, 0x82, 0x7d, 0xd8, 0x17, 0x1c, 0x87, 0xdc, - 0xc4, 0x73, 0x0a, 0xc5, 0xce, 0x21, 0x87, 0xbc, 0xd0, 0x45, 0x1d, 0x17, - 0xfa, 0x49, 0xba, 0xa0, 0x73, 0x7e, 0xa8, 0x9d, 0x81, 0x0c, 0x8f, 0x50, - 0x9e, 0x9e, 0x73, 0x07, 0x39, 0xc7, 0xc3, 0x39, 0x5c, 0xe7, 0x25, 0x49, - 0x42, 0xf2, 0x2f, 0xbe, 0x68, 0xd1, 0x8b, 0x43, 0xc0, 0x2b, 0x8f, 0xf6, - 0x8f, 0x91, 0xc7, 0xbb, 0x23, 0xf7, 0x71, 0xcc, 0x96, 0xcd, 0x3e, 0xc8, - 0x16, 0x74, 0xe5, 0x1e, 0xf2, 0xef, 0x44, 0x5f, 0x1c, 0x62, 0x7a, 0x34, - 0xd0, 0x52, 0x87, 0xae, 0xf3, 0x3d, 0x57, 0x17, 0xd9, 0x32, 0xeb, 0x32, - 0xf2, 0xaa, 0x0b, 0x75, 0x9a, 0x6a, 0xe8, 0x90, 0x59, 0x1f, 0xf4, 0x02, - 0x32, 0x4b, 0x73, 0x3f, 0xef, 0x2d, 0x84, 0xfb, 0xde, 0xd1, 0xf7, 0x17, - 0xef, 0xad, 0xef, 0x3e, 0xd4, 0x9b, 0x8f, 0xc0, 0x67, 0xa3, 0x2e, 0x32, - 0xe0, 0xd3, 0x55, 0xe4, 0x72, 0x06, 0xbf, 0x07, 0x77, 0x95, 0x15, 0xe4, - 0x85, 0xfc, 0x5e, 0x6b, 0xdd, 0xcd, 0x77, 0x07, 0xf6, 0x7d, 0x06, 0x3c, - 0xba, 0x32, 0xf7, 0x00, 0x5d, 0x9d, 0x53, 0xe8, 0x5a, 0x43, 0xcf, 0x16, - 0xa8, 0x83, 0xaa, 0xc9, 0x34, 0x5d, 0x5f, 0x6a, 0xe7, 0x93, 0x22, 0xf4, - 0xc4, 0x22, 0xce, 0xcd, 0xaf, 0x2c, 0x55, 0x4b, 0x37, 0x76, 0xa7, 0x49, - 0x7e, 0x09, 0xb6, 0xfd, 0x92, 0xae, 0xd5, 0xc0, 0xe7, 0xba, 0xe1, 0xa2, - 0x56, 0xe3, 0x3a, 0x32, 0x05, 0xbb, 0xd3, 0x53, 0x2d, 0xca, 0x90, 0xb4, - 0xa0, 0xd0, 0xaf, 0x66, 0x74, 0x8d, 0x75, 0xee, 0xa2, 0x81, 0x7e, 0x37, - 0x7e, 0x7b, 0x3d, 0xd0, 0x43, 0xf4, 0xf5, 0xa3, 0xbe, 0xd5, 0xb3, 0x9a, - 0xd8, 0x4d, 0x6f, 0x43, 0x27, 0xca, 0x7e, 0xdf, 0x47, 0xf7, 0xbc, 0x1e, - 0xee, 0x59, 0x2d, 0x5d, 0xe1, 0x3a, 0x68, 0x86, 0x75, 0xbe, 0x17, 0xfe, - 0x03, 0xef, 0x6e, 0x07, 0x95, 0x27, 0x11, 0xa3, 0x66, 0x1e, 0xa5, 0xc2, - 0x90, 0x18, 0xd0, 0xed, 0xf3, 0x82, 0xfb, 0xf8, 0x7e, 0xb2, 0x76, 0x1f, - 0xdb, 0xb2, 0xb8, 0x0a, 0xbd, 0x3a, 0xc8, 0x7a, 0x80, 0xdc, 0x0e, 0x39, - 0x04, 0xfb, 0x4e, 0x09, 0x39, 0x44, 0xc1, 0x0d, 0x74, 0xa3, 0x75, 0x30, - 0x49, 0xc7, 0x5e, 0x62, 0x19, 0x61, 0x6c, 0x43, 0xef, 0x36, 0xee, 0xc4, - 0x31, 0x66, 0xd0, 0xf1, 0xef, 0xb7, 0x73, 0x4a, 0xb6, 0xbd, 0x34, 0xe4, - 0xa1, 0xa3, 0xf6, 0xe8, 0x53, 0x2b, 0xbe, 0x4f, 0x81, 0x4e, 0xa4, 0x02, - 0x19, 0xd4, 0x30, 0x36, 0xed, 0x4e, 0xc2, 0x27, 0xc6, 0xe8, 0xe6, 0xa4, - 0x05, 0x9d, 0x68, 0x01, 0x87, 0xc3, 0x71, 0xbe, 0x4b, 0xb8, 0x39, 0x59, - 0xc4, 0xfb, 0x61, 0x3f, 0xf7, 0x97, 0xf6, 0x40, 0x97, 0xdc, 0x07, 0xc2, - 0xfc, 0x9c, 0xcf, 0xd3, 0x84, 0xda, 0xac, 0x2e, 0x4c, 0xcf, 0x7a, 0x34, - 0x9a, 0xeb, 0x4b, 0x5d, 0xa5, 0x4e, 0xff, 0xce, 0xd8, 0xf7, 0x9b, 0xfe, - 0x9c, 0x5d, 0x18, 0xff, 0x00, 0x3a, 0x85, 0x27, 0xe2, 0xf5, 0xe9, 0x66, - 0x35, 0xd5, 0x41, 0xac, 0x53, 0x24, 0x2c, 0x18, 0xec, 0x3b, 0x04, 0xba, - 0xea, 0xdf, 0x47, 0x13, 0x15, 0x9d, 0xd7, 0x99, 0x6e, 0x61, 0xb1, 0xc5, - 0x6b, 0x58, 0xce, 0xbc, 0x46, 0xa2, 0x9b, 0x49, 0xd8, 0xe5, 0x9e, 0x3d, - 0x7e, 0xbd, 0xf8, 0xf8, 0x10, 0xe3, 0xda, 0x0d, 0x99, 0x42, 0xbf, 0x50, - 0xdb, 0x94, 0x83, 0xbe, 0x59, 0xae, 0x4d, 0xa7, 0xf9, 0xde, 0x23, 0xef, - 0xeb, 0x5a, 0xa8, 0x1f, 0x1f, 0xd7, 0xb5, 0xe7, 0xb0, 0xf6, 0x2d, 0xf6, - 0xab, 0x90, 0x75, 0xe0, 0x23, 0xbe, 0x41, 0x6f, 0xcd, 0x55, 0xb3, 0xfc, - 0xcd, 0xa3, 0x35, 0x21, 0xa0, 0x16, 0x3f, 0x4e, 0x6f, 0xcf, 0x3d, 0x4b, - 0xbf, 0x9c, 0x65, 0xdd, 0x31, 0x68, 0x14, 0xfa, 0x74, 0x94, 0xe4, 0xec, - 0x69, 0x1a, 0x50, 0xaf, 0xfb, 0xb5, 0x8d, 0x9e, 0xf3, 0x6b, 0x3a, 0x33, - 0x4b, 0xc5, 0xc6, 0x40, 0xea, 0x1a, 0xfa, 0xca, 0x93, 0xba, 0xb6, 0x8e, - 0xdc, 0xa3, 0xd0, 0xfc, 0x80, 0xef, 0x6c, 0xb2, 0x35, 0xd8, 0xde, 0x22, - 0x6a, 0x9b, 0xb7, 0x9d, 0xbb, 0xe9, 0x2c, 0xd7, 0x56, 0x81, 0xff, 0x5e, - 0x33, 0x50, 0x63, 0xac, 0xaa, 0xa1, 0x0e, 0x31, 0x70, 0x9d, 0xc1, 0xf1, - 0x07, 0x4f, 0x37, 0x06, 0x9f, 0xb2, 0x1f, 0x7c, 0x67, 0xd9, 0x42, 0xfe, - 0xab, 0xfc, 0x8d, 0x0a, 0xf2, 0x5f, 0x5d, 0xfe, 0x40, 0xeb, 0x65, 0x3f, - 0x6b, 0x80, 0x96, 0x41, 0x3a, 0x33, 0xcf, 0xf2, 0x47, 0xec, 0xf5, 0xed, - 0x34, 0x0d, 0xfe, 0x72, 0x7c, 0x19, 0xa4, 0x5f, 0x2d, 0x15, 0xfd, 0xfb, - 0x6b, 0x1b, 0xb9, 0xd6, 0x11, 0x67, 0x12, 0xf5, 0xfa, 0x77, 0x40, 0x2f, - 0xce, 0x1e, 0xda, 0x8d, 0xa7, 0x0a, 0x9b, 0xdc, 0x72, 0x9e, 0x23, 0x07, - 0x79, 0xce, 0xde, 0x2d, 0xe6, 0x39, 0x7b, 0xb7, 0x92, 0xe7, 0xc8, 0x9d, - 0xe0, 0xab, 0xd6, 0xbb, 0x65, 0xdc, 0xa4, 0x00, 0xb7, 0x03, 0x5b, 0xc4, - 0xed, 0xc0, 0x56, 0x70, 0x93, 0x3a, 0xcd, 0xbf, 0x40, 0x8c, 0x35, 0x10, - 0xdb, 0xe0, 0xd7, 0x86, 0xfa, 0x59, 0x7f, 0x80, 0xa3, 0x8f, 0xeb, 0xef, - 0x8b, 0xa7, 0x18, 0xe0, 0xf9, 0xd8, 0x16, 0xf1, 0x7c, 0x6c, 0x2b, 0x78, - 0x8a, 0x9d, 0x26, 0xe3, 0x28, 0xc3, 0xd7, 0x70, 0x6d, 0x83, 0xd8, 0x3c, - 0x24, 0x87, 0xba, 0x2e, 0x87, 0x75, 0x0e, 0x03, 0x7c, 0x50, 0xaf, 0x46, - 0x4b, 0x4c, 0xcb, 0x46, 0xdf, 0x9d, 0x3a, 0x4b, 0x32, 0x5b, 0xa5, 0x4a, - 0x83, 0xef, 0x95, 0xfb, 0xb0, 0x0f, 0xf7, 0xf1, 0x37, 0x2a, 0x8b, 0x64, - 0xc4, 0xf7, 0xe7, 0x9a, 0x77, 0xa7, 0xf5, 0x2a, 0x68, 0x9d, 0x0a, 0x69, - 0xad, 0xf8, 0xb9, 0xe0, 0xbe, 0x4d, 0xb9, 0x60, 0x40, 0xe3, 0x08, 0x68, - 0x2c, 0x86, 0x34, 0x3e, 0xdd, 0x60, 0xda, 0xf6, 0xf9, 0xb4, 0x2d, 0x6d, - 0xa2, 0x6d, 0xe4, 0x9e, 0xf9, 0x1f, 0xe3, 0x81, 0x5a, 0x1a, 0xb9, 0xd7, - 0x6b, 0x4d, 0xd4, 0xd2, 0x4d, 0xd4, 0xd2, 0xd0, 0xf7, 0x57, 0x9b, 0xa8, - 0xa5, 0x9b, 0xa8, 0xa5, 0x61, 0x07, 0xaf, 0xc0, 0x56, 0x82, 0x3b, 0xdc, - 0x12, 0x71, 0x0d, 0xee, 0xd7, 0xe3, 0x14, 0xe4, 0x39, 0x05, 0xc4, 0xf0, - 0xa3, 0xc8, 0xf1, 0xd8, 0x6e, 0x4f, 0x13, 0xc7, 0x04, 0x3d, 0x87, 0x9a, - 0x2f, 0x5b, 0x25, 0x33, 0x5e, 0x9c, 0x1f, 0x50, 0x97, 0x02, 0xfb, 0xd6, - 0x5a, 0xc4, 0x71, 0x70, 0x20, 0x85, 0x08, 0xa9, 0xb2, 0x5f, 0xb0, 0x73, - 0x4c, 0xe7, 0x76, 0xf0, 0x10, 0xbe, 0xdb, 0x60, 0x1f, 0xc6, 0xbe, 0xb4, - 0x4e, 0x0b, 0x8d, 0xf0, 0x1b, 0x9a, 0xcc, 0xfd, 0xfc, 0xce, 0x31, 0xb7, - 0xcf, 0xf7, 0x69, 0x76, 0xb6, 0x0f, 0x71, 0x80, 0xfb, 0x15, 0xf8, 0x35, - 0xe8, 0xca, 0x52, 0x1b, 0x17, 0x19, 0xeb, 0x55, 0xaa, 0xcf, 0x07, 0x31, - 0x7c, 0xca, 0xe0, 0x38, 0x87, 0xf8, 0xbe, 0xc4, 0xdf, 0xb0, 0x10, 0xeb, - 0x97, 0xae, 0x68, 0x32, 0x6a, 0xc7, 0x3a, 0x7f, 0xa3, 0x1d, 0xec, 0xc3, - 0xf9, 0x1d, 0xfe, 0x1d, 0xed, 0x51, 0xff, 0xae, 0xcd, 0xa0, 0x23, 0xad, - 0x80, 0x16, 0xdb, 0xc8, 0xd0, 0xc8, 0x2c, 0xdf, 0x35, 0x51, 0x8f, 0x68, - 0xca, 0x54, 0x75, 0xf8, 0x7e, 0x68, 0xe3, 0xbb, 0x49, 0x76, 0x91, 0xeb, - 0x4f, 0x23, 0xb8, 0xff, 0x3c, 0xed, 0xbc, 0xc9, 0xf7, 0x9f, 0xe1, 0x3a, - 0x8d, 0xde, 0x70, 0x33, 0x34, 0x8e, 0xf8, 0x5a, 0x6c, 0x68, 0xf0, 0x6f, - 0xbe, 0x3c, 0x39, 0xa7, 0xad, 0xc6, 0x42, 0x99, 0x8e, 0x84, 0x32, 0xad, - 0x34, 0xd6, 0x80, 0xdf, 0x0d, 0xef, 0x8f, 0x43, 0x99, 0xee, 0x3a, 0x47, - 0xda, 0xd5, 0x1c, 0xcb, 0x95, 0x65, 0x19, 0xc8, 0x75, 0x7c, 0xb1, 0x24, - 0x14, 0x21, 0xd3, 0x51, 0x5f, 0xa6, 0x32, 0xc7, 0x05, 0xec, 0x95, 0x83, - 0xfc, 0xd9, 0x8f, 0xe1, 0xe9, 0xb0, 0x8c, 0xb9, 0xde, 0xe0, 0x58, 0x98, - 0xa4, 0x4b, 0x9b, 0xe4, 0x5c, 0xbc, 0xa7, 0x0e, 0xe7, 0xa9, 0xff, 0x9c, - 0x16, 0xde, 0x9b, 0x66, 0x21, 0xc7, 0x76, 0x2e, 0xf6, 0x23, 0x81, 0x8c, - 0xf6, 0x9d, 0x6e, 0xbb, 0xef, 0xe5, 0x4d, 0x7d, 0xed, 0x67, 0x9b, 0x56, - 0xc4, 0xb7, 0x0d, 0xde, 0xf3, 0x1d, 0xe4, 0x9d, 0x7e, 0xc9, 0x1f, 0x53, - 0x31, 0xd6, 0x4b, 0x85, 0x25, 0x83, 0xac, 0x16, 0xcf, 0x91, 0x49, 0x34, - 0xda, 0x72, 0xea, 0xa4, 0xf5, 0x30, 0xc6, 0x2d, 0x34, 0x3c, 0xef, 0xa7, - 0xd0, 0x9d, 0x8b, 0x5c, 0x77, 0x3b, 0xbf, 0xf1, 0xd6, 0x93, 0xc8, 0x21, - 0x37, 0xce, 0xfc, 0xe6, 0xfd, 0xd4, 0xa5, 0xab, 0x88, 0x09, 0x74, 0xc6, - 0x09, 0x51, 0x22, 0x1e, 0xe7, 0x3e, 0xfe, 0x06, 0xef, 0x79, 0x17, 0x8d, - 0x3b, 0x78, 0x75, 0x99, 0xc7, 0x69, 0xdf, 0x39, 0xf6, 0xff, 0x3f, 0xd0, - 0x2e, 0x1a, 0xd6, 0x9e, 0x38, 0xf2, 0xe7, 0xeb, 0xc4, 0xb1, 0x4f, 0x4e, - 0x14, 0x9b, 0xba, 0x7a, 0x09, 0x6b, 0x8b, 0x8e, 0xc2, 0xdf, 0xd6, 0xf9, - 0xfb, 0xa8, 0x76, 0x89, 0xda, 0xf7, 0x65, 0x90, 0xa7, 0xa3, 0xf2, 0x77, - 0x52, 0xb5, 0x8a, 0xd8, 0x52, 0x70, 0x92, 0x98, 0xaf, 0x62, 0x2e, 0xc7, - 0x05, 0x8f, 0x14, 0xd8, 0x50, 0xc1, 0x49, 0x27, 0xc6, 0x9a, 0x9e, 0xa7, - 0x7c, 0x5e, 0xa0, 0x87, 0x32, 0x29, 0x1a, 0x73, 0xf8, 0xfe, 0xf7, 0x9b, - 0xf4, 0x36, 0xec, 0xac, 0x78, 0x9e, 0x6b, 0x26, 0xf6, 0x29, 0x78, 0x77, - 0xf8, 0xbe, 0xea, 0x14, 0x3d, 0xb4, 0x47, 0xcf, 0x5e, 0x22, 0xe0, 0xb3, - 0x42, 0xfd, 0x48, 0x72, 0x53, 0xc7, 0xfd, 0xef, 0x6d, 0x8c, 0x6b, 0x9a, - 0x96, 0xc0, 0x1b, 0xa7, 0x99, 0xa4, 0x95, 0x66, 0x8a, 0x56, 0xa1, 0x1f, - 0xdb, 0xcc, 0x32, 0x7d, 0x03, 0x78, 0x2b, 0x66, 0x95, 0x94, 0x8c, 0xb5, - 0xaf, 0x0b, 0x78, 0x67, 0x05, 0x3d, 0x15, 0x17, 0x18, 0x77, 0x5d, 0x2d, - 0x03, 0x6f, 0xd6, 0xd1, 0x51, 0xa7, 0x9b, 0x8e, 0x61, 0xed, 0x7e, 0xe4, - 0x1f, 0xdf, 0x72, 0xa8, 0x2c, 0x99, 0x29, 0x3a, 0x80, 0xf3, 0x8e, 0x36, - 0x38, 0x57, 0x3b, 0x02, 0x5f, 0x23, 0xd0, 0xa3, 0x19, 0x8f, 0x1e, 0xdd, - 0xa3, 0x5b, 0x71, 0x01, 0x7b, 0xae, 0xb0, 0x9e, 0xa0, 0xdf, 0x09, 0xce, - 0x8d, 0xad, 0xf8, 0xba, 0x08, 0x7f, 0xfa, 0x0c, 0x65, 0xce, 0xad, 0xe5, - 0xa6, 0x90, 0x9f, 0x8f, 0x36, 0xe9, 0x8b, 0x31, 0x9c, 0xf7, 0x36, 0xf8, - 0x34, 0xea, 0xc8, 0x02, 0xf3, 0xe9, 0x58, 0xc0, 0x27, 0x8c, 0xf1, 0xb7, - 0x23, 0xce, 0xd1, 0xf8, 0xec, 0x13, 0x74, 0xb6, 0xc1, 0x77, 0xdd, 0x27, - 0xe8, 0x4a, 0xe3, 0x11, 0xba, 0x98, 0xe3, 0x5c, 0x07, 0xfb, 0xf8, 0x67, - 0xa0, 0xcf, 0x3f, 0xa3, 0x9b, 0x8e, 0xfb, 0x72, 0xfa, 0x3f, 0xc3, 0x06, - 0xd0, 0x70, 0x4c, 0x57, 0x00, 0x00, 0x00 }; + 0xad, 0x7b, 0x7f, 0x70, 0x9b, 0x75, 0x7a, 0xe7, 0xe7, 0xd5, 0x0f, 0x5b, + 0xb2, 0x65, 0x59, 0x0e, 0x4a, 0x90, 0x77, 0xbd, 0x8d, 0x5e, 0xf4, 0xca, + 0x16, 0xd8, 0x49, 0x5e, 0x25, 0xce, 0xc6, 0x59, 0xab, 0x44, 0x75, 0x1c, + 0xdb, 0x71, 0x1c, 0x30, 0xc1, 0xdd, 0x3a, 0x3d, 0xae, 0xf1, 0x25, 0x26, + 0x31, 0x10, 0xc0, 0xe9, 0xa6, 0x7b, 0x62, 0x8f, 0xd6, 0xc2, 0x76, 0x82, + 0x43, 0x64, 0xbf, 0xce, 0x2a, 0x59, 0x87, 0x4e, 0x67, 0xd6, 0x60, 0x07, + 0x07, 0x56, 0x8e, 0x60, 0xdb, 0x6b, 0xbb, 0x73, 0xbb, 0x83, 0x8e, 0x40, + 0xf0, 0x72, 0x01, 0xb6, 0xfd, 0xa3, 0x47, 0x6f, 0xee, 0xda, 0xcc, 0x02, + 0x59, 0xa0, 0x4b, 0xa0, 0x3b, 0x7b, 0x53, 0x67, 0x0b, 0xbc, 0xf7, 0x79, + 0xde, 0x57, 0x4a, 0xb2, 0x94, 0x4e, 0x67, 0x3a, 0xe7, 0x19, 0x8f, 0xac, + 0xf7, 0xc7, 0xf3, 0x7d, 0x7e, 0x3f, 0x9f, 0xe7, 0xf9, 0x7e, 0x5d, 0x0f, + 0x54, 0xa0, 0xf8, 0x53, 0xc5, 0xdf, 0xe6, 0xe1, 0xd4, 0xe1, 0x8d, 0x6b, + 0xf5, 0xb5, 0xd6, 0x05, 0x37, 0x5c, 0x72, 0xf3, 0xab, 0x0a, 0x30, 0xf0, + 0x01, 0xfe, 0x5d, 0x3f, 0x5f, 0xf9, 0xf7, 0xbd, 0x66, 0xfd, 0x38, 0x81, + 0x40, 0x89, 0x2f, 0xf9, 0x85, 0xc7, 0x91, 0x40, 0x6b, 0x9b, 0x06, 0x8f, + 0x33, 0xf1, 0x67, 0x89, 0x7d, 0x1a, 0x90, 0xcc, 0x35, 0x86, 0xb7, 0xe2, + 0x53, 0x33, 0x1d, 0x74, 0x41, 0xae, 0x7f, 0x25, 0xf1, 0xc9, 0xc8, 0x8f, + 0x36, 0xa9, 0x1f, 0xcf, 0x3a, 0xe1, 0x09, 0x24, 0x4e, 0x23, 0x50, 0x0f, + 0x4f, 0x1d, 0xdf, 0xf9, 0x93, 0x86, 0x6a, 0x27, 0xfc, 0x25, 0x5a, 0x2d, + 0x18, 0x33, 0x90, 0xf6, 0x24, 0x86, 0x51, 0xbe, 0x11, 0x78, 0x37, 0x13, + 0xd5, 0xc7, 0x80, 0x69, 0x47, 0x22, 0x1a, 0x7e, 0x09, 0x3a, 0x8e, 0xe4, + 0xc3, 0x68, 0xe7, 0xef, 0x76, 0xe3, 0x33, 0x33, 0xec, 0x46, 0xda, 0xc9, + 0xe7, 0xf6, 0x36, 0x03, 0xdb, 0x32, 0x3a, 0x8e, 0x1a, 0xf0, 0xd4, 0x26, + 0x1e, 0xc5, 0x66, 0x7e, 0xfa, 0x13, 0x29, 0xbc, 0x31, 0x19, 0x09, 0x3f, + 0x03, 0xb5, 0x5f, 0x73, 0xaa, 0x29, 0xa0, 0x71, 0x68, 0x50, 0x51, 0x07, + 0xde, 0x54, 0xd4, 0xde, 0x49, 0x05, 0x1e, 0x85, 0xcf, 0x35, 0xe6, 0xe4, + 0x33, 0x85, 0xdb, 0x72, 0x1e, 0x5c, 0x72, 0xca, 0xfa, 0xbf, 0x49, 0x7d, + 0x2b, 0x70, 0x69, 0x2d, 0x18, 0x27, 0x0f, 0xee, 0x84, 0x82, 0xa7, 0x9b, + 0xa3, 0xa1, 0x51, 0xc8, 0xfd, 0x30, 0xb6, 0xe6, 0xe5, 0x53, 0xa5, 0xd4, + 0xa6, 0x39, 0xae, 0x9b, 0xe6, 0x19, 0xbd, 0x1c, 0xe9, 0x80, 0x1a, 0x02, + 0x14, 0x8c, 0xea, 0x0e, 0x24, 0x03, 0x6d, 0x61, 0x17, 0xd4, 0xd0, 0xbd, + 0xf8, 0x67, 0xca, 0x9c, 0x8c, 0xb9, 0x61, 0x3f, 0x3f, 0x80, 0x72, 0x14, + 0x02, 0xb6, 0xd6, 0x9e, 0xce, 0x98, 0xe6, 0x05, 0xcd, 0x85, 0x33, 0xd4, + 0xcf, 0x68, 0xee, 0x9f, 0xcd, 0x02, 0x75, 0x33, 0xae, 0x95, 0xd6, 0xf7, + 0x60, 0x36, 0x60, 0x9a, 0x73, 0xbc, 0x77, 0x34, 0x57, 0xd2, 0xb3, 0x69, + 0x3a, 0x34, 0xd3, 0xdc, 0xa7, 0xfd, 0xca, 0xdc, 0xfb, 0x6b, 0xcf, 0x9a, + 0xe6, 0x13, 0xfa, 0x4d, 0x38, 0x9b, 0x6d, 0x57, 0xba, 0x17, 0x56, 0xf9, + 0xb7, 0xcf, 0x98, 0xb8, 0xa0, 0x23, 0xe0, 0x48, 0x74, 0x28, 0xdb, 0x17, + 0xba, 0x94, 0x6d, 0xf9, 0x5d, 0x4a, 0xc7, 0xdc, 0xef, 0x2a, 0x5d, 0x0b, + 0x03, 0x4a, 0x67, 0x3e, 0x84, 0x79, 0x23, 0x88, 0x39, 0xa3, 0x5f, 0x69, + 0x5f, 0xe8, 0x53, 0x6c, 0x39, 0x52, 0x4a, 0x5b, 0xbe, 0x44, 0xeb, 0xba, + 0x1e, 0xb7, 0x67, 0x12, 0x98, 0x30, 0xca, 0xb9, 0xce, 0xb2, 0xf9, 0xa3, + 0x86, 0x65, 0xca, 0xa9, 0xe3, 0x58, 0xfe, 0x09, 0xec, 0x9c, 0x31, 0xcd, + 0x5c, 0x1c, 0xc8, 0xe5, 0x81, 0xef, 0x19, 0x91, 0xde, 0x21, 0xc5, 0x34, + 0x3b, 0xa3, 0xe6, 0xea, 0xcb, 0x7a, 0x63, 0xec, 0x65, 0xfc, 0x93, 0x39, + 0x1b, 0x44, 0xda, 0x47, 0x1a, 0xc7, 0x69, 0xb3, 0xfb, 0x27, 0xe1, 0x29, + 0x4f, 0x8c, 0xe3, 0x67, 0x19, 0x78, 0xca, 0x12, 0x69, 0x5c, 0xc8, 0x8c, + 0x06, 0x3c, 0x88, 0x84, 0xb6, 0x2b, 0xe9, 0x94, 0x03, 0xea, 0xf0, 0xdb, + 0x50, 0xc3, 0xb4, 0xc7, 0xd2, 0x79, 0x45, 0x2d, 0xbc, 0x0c, 0x35, 0xf9, + 0x2b, 0x45, 0xed, 0xaa, 0x75, 0x22, 0xe9, 0x88, 0x7a, 0xf0, 0xa3, 0x06, + 0xb1, 0xc9, 0x38, 0xd6, 0x5a, 0xb6, 0x49, 0xe3, 0xd6, 0x6b, 0xb6, 0x49, + 0x60, 0x94, 0x7c, 0x1d, 0x25, 0x5f, 0xaf, 0xe8, 0x6a, 0xe8, 0x69, 0x98, + 0xab, 0x07, 0x75, 0xb9, 0x97, 0xc0, 0x78, 0xde, 0x0c, 0xfb, 0x13, 0x97, + 0xc8, 0x2f, 0xd2, 0x5f, 0x4a, 0x78, 0xd2, 0xd5, 0x89, 0x4f, 0xcd, 0xd7, + 0x37, 0x86, 0xf0, 0x62, 0x3e, 0x88, 0x17, 0xf2, 0x01, 0x3c, 0x9f, 0x6f, + 0x87, 0x91, 0x87, 0x7f, 0x67, 0xfe, 0x8b, 0xfc, 0xd8, 0x84, 0x8f, 0xcf, + 0x93, 0x6f, 0xff, 0x8e, 0xbc, 0x6b, 0xa0, 0x2c, 0x81, 0xde, 0x1f, 0x67, + 0x46, 0xcc, 0x0a, 0x0d, 0x03, 0x35, 0x09, 0x2d, 0x79, 0x9b, 0xe2, 0x6b, + 0xa1, 0x1f, 0xf6, 0xbe, 0x9a, 0x6b, 0x71, 0x69, 0x53, 0x5e, 0xb8, 0xa9, + 0xff, 0x6d, 0x79, 0xd3, 0x1c, 0xd3, 0x0f, 0xad, 0xdb, 0xdb, 0xf2, 0xa7, + 0x85, 0x5e, 0xad, 0x07, 0xe9, 0xfc, 0x20, 0xe0, 0x4f, 0xf0, 0x93, 0xa1, + 0xb8, 0xab, 0xa9, 0x3d, 0x7c, 0xee, 0x41, 0x97, 0xed, 0xcf, 0xe4, 0x81, + 0x7a, 0x7f, 0xc1, 0x20, 0x0f, 0xc6, 0xb4, 0x1f, 0x15, 0x61, 0xca, 0xf7, + 0x13, 0xf2, 0x19, 0xc3, 0xf7, 0xf3, 0x1a, 0x79, 0x6b, 0x22, 0x8f, 0x61, + 0xf2, 0xe7, 0xc1, 0xde, 0xac, 0x3a, 0x9d, 0x86, 0x3a, 0x31, 0x8b, 0x35, + 0x48, 0x06, 0x03, 0xf4, 0xc1, 0x3f, 0x86, 0x4d, 0xa3, 0x07, 0x53, 0x06, + 0xd6, 0x07, 0x12, 0xb4, 0x6f, 0x1c, 0x8f, 0x96, 0x21, 0x3a, 0xf0, 0xb1, + 0xa2, 0xe0, 0xf5, 0x68, 0x0f, 0x26, 0x29, 0x4f, 0x4f, 0xce, 0x8b, 0x07, + 0xb2, 0x15, 0xb8, 0x2f, 0x6b, 0xe2, 0xfe, 0x38, 0x12, 0x15, 0x94, 0x27, + 0x16, 0x8f, 0x86, 0xdf, 0x83, 0x0b, 0xed, 0xb9, 0x1e, 0xc6, 0xd2, 0x56, + 0x24, 0xcb, 0x3c, 0xd8, 0x9a, 0xf3, 0x31, 0x1e, 0x93, 0x38, 0x3d, 0xe3, + 0x81, 0x7b, 0x83, 0x03, 0xb3, 0xc1, 0x32, 0xc4, 0xea, 0x1d, 0xfc, 0x0d, + 0xfa, 0xdb, 0x66, 0xea, 0xfc, 0xdb, 0x0c, 0x17, 0x0e, 0x18, 0x0e, 0x8c, + 0x64, 0x4d, 0xb3, 0x5d, 0x37, 0x71, 0x75, 0x43, 0x00, 0x3f, 0xa0, 0xfe, + 0x0e, 0x19, 0x21, 0x9c, 0xcd, 0x3f, 0x4e, 0x5e, 0x82, 0x36, 0xbf, 0x06, + 0x79, 0x37, 0xc8, 0xbb, 0x41, 0xbe, 0x0d, 0xe1, 0xf3, 0x3c, 0x63, 0x46, + 0xa7, 0x5c, 0x5e, 0xf2, 0x50, 0x89, 0x21, 0xf2, 0x11, 0x89, 0x9b, 0x70, + 0xc4, 0xd5, 0xf4, 0x5e, 0x26, 0xaf, 0xd5, 0xf5, 0xa6, 0xf9, 0xf1, 0x06, + 0x91, 0x85, 0x36, 0x77, 0xf4, 0x48, 0x8c, 0xfe, 0x56, 0x15, 0xe3, 0xea, + 0x6f, 0xa9, 0xb7, 0x27, 0xf3, 0x5e, 0xa4, 0xb2, 0x96, 0xdf, 0x1e, 0x2e, + 0x23, 0xdf, 0xc2, 0x57, 0x5e, 0x8b, 0x32, 0x46, 0xa3, 0xfd, 0x8c, 0x51, + 0xec, 0x20, 0xcf, 0xf7, 0x1b, 0xd1, 0x96, 0x5d, 0x8a, 0x0b, 0x9d, 0xb9, + 0xa0, 0xbf, 0xfd, 0x06, 0x3e, 0x29, 0xaf, 0xc4, 0x20, 0x65, 0x0d, 0x90, + 0xbf, 0x20, 0xf6, 0x91, 0xcf, 0x17, 0x8a, 0x7c, 0xce, 0xe5, 0x65, 0xad, + 0xcf, 0xf3, 0x5a, 0xe2, 0x13, 0xe9, 0x15, 0x89, 0xa0, 0x82, 0x0a, 0x1f, + 0x76, 0xe5, 0xde, 0xa2, 0x2d, 0xea, 0xf0, 0xa7, 0xb4, 0xc1, 0x8b, 0x8c, + 0x91, 0xef, 0x5f, 0xf3, 0x17, 0xb1, 0xc7, 0x63, 0xb4, 0x83, 0x7a, 0x3a, + 0x0d, 0x1f, 0x06, 0xf2, 0x49, 0x1c, 0x99, 0x41, 0x72, 0x5e, 0x3f, 0xce, + 0x78, 0x5f, 0x05, 0xa7, 0x56, 0x9e, 0x0c, 0x68, 0x15, 0xd8, 0x37, 0x17, + 0xc4, 0x70, 0xbe, 0x0d, 0x46, 0x36, 0x88, 0x83, 0xf4, 0xcd, 0x2b, 0xf1, + 0xe4, 0xfd, 0x7e, 0x08, 0xef, 0x41, 0x3c, 0xc0, 0x77, 0x9e, 0x98, 0x09, + 0x62, 0x88, 0x3a, 0xda, 0x1e, 0x8f, 0xb6, 0x78, 0x79, 0xed, 0x00, 0xaf, + 0x1d, 0xa5, 0xfe, 0xcf, 0xeb, 0x93, 0x18, 0xe8, 0x55, 0x63, 0x40, 0x10, + 0xfb, 0x0d, 0x04, 0xe8, 0xc2, 0x8f, 0x31, 0xbf, 0xc5, 0xce, 0xf3, 0xfb, + 0xbd, 0xf9, 0x0a, 0xca, 0xe9, 0x47, 0x48, 0xfb, 0xc4, 0x74, 0x37, 0x9b, + 0xe6, 0x77, 0xf5, 0xe8, 0xd2, 0x4f, 0x9d, 0x2e, 0x3c, 0x92, 0x77, 0x20, + 0x35, 0x57, 0x81, 0xdf, 0xcf, 0xba, 0x70, 0x57, 0x7d, 0x05, 0x0e, 0xcd, + 0x25, 0x31, 0x36, 0x53, 0x81, 0xc1, 0x2c, 0x56, 0xef, 0xd7, 0xc7, 0x6a, + 0xca, 0xa0, 0x2e, 0xb7, 0x23, 0x86, 0xab, 0xb4, 0xc3, 0x23, 0x73, 0x3e, + 0x7f, 0xff, 0x4c, 0x00, 0xa9, 0x05, 0x2f, 0x9f, 0x77, 0xf0, 0xf9, 0x72, + 0xe8, 0xeb, 0x23, 0xa9, 0x00, 0x84, 0xc7, 0x4a, 0x3c, 0x34, 0xe7, 0xc5, + 0x83, 0xd9, 0x00, 0x0e, 0xce, 0x34, 0x63, 0xda, 0x48, 0xe2, 0x18, 0x73, + 0xc7, 0xf7, 0xe2, 0x6a, 0xef, 0x41, 0x45, 0x4d, 0x6e, 0x53, 0x92, 0x68, + 0x88, 0xbb, 0x71, 0x89, 0x79, 0xc8, 0x1d, 0x6f, 0x6c, 0x79, 0x9e, 0xb9, + 0xa1, 0x2c, 0x11, 0xe4, 0x77, 0x75, 0x82, 0x31, 0x9b, 0x74, 0x3b, 0x36, + 0x00, 0x2b, 0x25, 0x7e, 0x83, 0xfe, 0x6e, 0x23, 0xe0, 0xef, 0xce, 0xd7, + 0xf9, 0xb7, 0x1b, 0x21, 0xff, 0x76, 0xc6, 0xd7, 0x36, 0xf1, 0x47, 0xc3, + 0x83, 0xe3, 0xf1, 0x4f, 0xcd, 0x81, 0x1a, 0x2b, 0x9f, 0xf9, 0x77, 0xce, + 0xa8, 0xe9, 0x59, 0xa8, 0x3a, 0xab, 0x01, 0x26, 0x17, 0x5c, 0xb4, 0x9f, + 0x82, 0x1a, 0xad, 0x99, 0x79, 0x3c, 0x80, 0x87, 0x98, 0x53, 0xfe, 0x9a, + 0x39, 0x65, 0x70, 0x2a, 0x12, 0x98, 0x86, 0x97, 0xfa, 0x06, 0xf6, 0x9e, + 0x0b, 0xd2, 0xe6, 0x5d, 0x78, 0x9c, 0x7c, 0x6d, 0xdf, 0x18, 0xc4, 0x7d, + 0xf9, 0x80, 0xbf, 0x8b, 0xf6, 0x7b, 0x2f, 0x17, 0xf2, 0x6f, 0xa5, 0x2d, + 0xdf, 0xce, 0xa9, 0xe1, 0x02, 0xfe, 0xaf, 0xf8, 0x53, 0x0c, 0x0e, 0x60, + 0xff, 0x94, 0x1b, 0x85, 0xa0, 0xac, 0x45, 0x9d, 0x1b, 0x2f, 0x9a, 0x3e, + 0x4d, 0x3b, 0x7d, 0x90, 0xba, 0xfe, 0x46, 0xde, 0x87, 0x07, 0x0d, 0x35, + 0xf6, 0x7d, 0xc5, 0x47, 0x9d, 0x7a, 0xa8, 0x07, 0x26, 0x98, 0x55, 0xf2, + 0x5c, 0x1c, 0xe1, 0x55, 0x76, 0xae, 0x3d, 0x34, 0x27, 0x7e, 0x42, 0xdb, + 0x1b, 0xf4, 0x01, 0xfa, 0xcf, 0xf7, 0xaf, 0xc5, 0xaa, 0x1a, 0x48, 0x5b, + 0xb9, 0x3b, 0x46, 0x7f, 0xb1, 0x75, 0x74, 0x62, 0x46, 0xf4, 0xa0, 0x4e, + 0xc3, 0x91, 0xc4, 0xba, 0xf5, 0x7f, 0x6d, 0x5e, 0x5a, 0x29, 0xfa, 0x08, + 0x60, 0x84, 0x3a, 0x3c, 0x6d, 0x98, 0xe6, 0xd5, 0x0d, 0x1f, 0x9a, 0x2d, + 0x37, 0x8b, 0x5e, 0x44, 0xd6, 0x1f, 0x28, 0x52, 0x47, 0x6a, 0x34, 0xff, + 0xff, 0x07, 0x5f, 0xf9, 0xa6, 0x39, 0x60, 0xc9, 0x27, 0xfe, 0xe2, 0xa2, + 0x2f, 0x3e, 0x4e, 0xda, 0x0e, 0x0c, 0x90, 0xde, 0xc3, 0x86, 0xf9, 0x51, + 0x6d, 0xe2, 0x33, 0xb3, 0x65, 0x93, 0x36, 0xbc, 0xac, 0xfc, 0x4f, 0x5e, + 0x0f, 0xe2, 0xa1, 0x7c, 0x0b, 0x75, 0xd7, 0x8e, 0x27, 0xa8, 0xc3, 0xa3, + 0x86, 0xe4, 0xc4, 0x10, 0xfd, 0xb9, 0x8e, 0xfe, 0xed, 0x52, 0xb6, 0x19, + 0x39, 0x6c, 0x9f, 0x4c, 0xa3, 0x93, 0xfe, 0xbe, 0x94, 0x89, 0xb4, 0x3c, + 0x0b, 0x35, 0x4d, 0x19, 0xfc, 0x5d, 0xd4, 0x71, 0xbb, 0xa1, 0x76, 0x89, + 0x4d, 0xdb, 0x99, 0x97, 0x5e, 0xca, 0x84, 0xfc, 0x6d, 0x79, 0xd1, 0x77, + 0x9d, 0x7f, 0x6b, 0xfe, 0xab, 0xb4, 0xbd, 0x82, 0xcd, 0x6b, 0x3c, 0xcc, + 0x33, 0x77, 0xc1, 0xb6, 0xab, 0x6d, 0xbb, 0xd7, 0xe3, 0x8d, 0x03, 0x1f, + 0x32, 0x3f, 0xa5, 0x57, 0xda, 0xd7, 0x52, 0xbc, 0x56, 0xbd, 0x01, 0xfe, + 0x3b, 0xe9, 0x07, 0x7b, 0xe8, 0x07, 0x57, 0x37, 0x7c, 0x6a, 0x86, 0x6f, + 0xb2, 0xfd, 0xa0, 0x6d, 0xc6, 0xe5, 0xef, 0xa0, 0x9e, 0xb6, 0xe9, 0x0a, + 0xe6, 0xf4, 0x0c, 0x06, 0xae, 0x61, 0x87, 0xe4, 0xec, 0x59, 0x3d, 0xc9, + 0x3c, 0xf2, 0x9b, 0x70, 0xd5, 0x60, 0xf6, 0x59, 0xfd, 0x71, 0x84, 0x6d, + 0xdf, 0xc1, 0xc1, 0xac, 0x17, 0xe9, 0xbb, 0x02, 0x98, 0x6f, 0x08, 0xe0, + 0x61, 0xd2, 0xbe, 0x12, 0x6f, 0x1c, 0x7a, 0x83, 0x3a, 0x98, 0xad, 0x91, + 0x6b, 0x49, 0xfc, 0xa5, 0xfe, 0x28, 0x70, 0x93, 0xbd, 0xf6, 0x82, 0xc4, + 0xe8, 0x42, 0x33, 0x8e, 0xe6, 0xfb, 0x15, 0x3b, 0x6f, 0xaa, 0x5d, 0x49, + 0xfc, 0xc4, 0x94, 0x5c, 0xba, 0x60, 0x30, 0xc7, 0x51, 0x1f, 0xe3, 0xf4, + 0xa3, 0xd1, 0x5c, 0x9d, 0xbf, 0x93, 0x7e, 0xf4, 0x78, 0x4e, 0x64, 0x8a, + 0xea, 0xba, 0xb3, 0x96, 0xb5, 0x99, 0xfa, 0x31, 0xac, 0x9a, 0x5f, 0x1d, + 0xd0, 0x8e, 0x61, 0xda, 0xe2, 0x2d, 0xa5, 0xf4, 0x13, 0x63, 0x30, 0x64, + 0xaa, 0xcb, 0xb5, 0x43, 0x78, 0xdc, 0xba, 0x16, 0xf4, 0xef, 0x9e, 0x49, + 0x3a, 0x1c, 0x1a, 0x02, 0x95, 0x89, 0x76, 0x65, 0x37, 0xeb, 0x6e, 0xc7, + 0x4c, 0x87, 0xd2, 0xb1, 0x20, 0x31, 0xd0, 0xa5, 0x6c, 0x67, 0xcd, 0x4d, + 0xb2, 0xe6, 0x26, 0x59, 0x73, 0x93, 0xe4, 0x23, 0xc9, 0x5a, 0xdb, 0x96, + 0x4f, 0x29, 0x3b, 0x44, 0xff, 0xf4, 0xaf, 0xe7, 0x0d, 0x1b, 0x47, 0x30, + 0x07, 0xf9, 0x3b, 0xf3, 0x6b, 0x1d, 0x36, 0xb6, 0x4b, 0x29, 0x45, 0x2c, + 0xe3, 0xa9, 0xd0, 0x58, 0xcb, 0x8c, 0x94, 0xd2, 0xcd, 0x7a, 0xdb, 0x6f, + 0xe9, 0x32, 0x32, 0xfc, 0x0e, 0xeb, 0xec, 0xeb, 0xac, 0xb3, 0xb9, 0x38, + 0xe3, 0x6a, 0xcd, 0x55, 0x73, 0x60, 0xa5, 0x5d, 0x13, 0xc6, 0xc8, 0xef, + 0x77, 0x69, 0xb3, 0x02, 0x6b, 0x69, 0xbb, 0x53, 0xc1, 0x7e, 0x0d, 0xd5, + 0xb5, 0xcc, 0xa9, 0x47, 0xf3, 0xac, 0x03, 0x7a, 0xa4, 0xe5, 0x7d, 0x2a, + 0xf6, 0xa8, 0xe6, 0xc6, 0xd5, 0x9b, 0x08, 0x76, 0xb4, 0x36, 0x1c, 0xcf, + 0x96, 0x63, 0x28, 0x9e, 0x5c, 0xe1, 0x21, 0x56, 0xe9, 0x6a, 0xc6, 0xa3, + 0x5c, 0x5a, 0x09, 0x25, 0xa2, 0xf4, 0x1b, 0x24, 0xa7, 0x58, 0x27, 0x26, + 0x8d, 0xaf, 0x22, 0xc7, 0x7a, 0x3a, 0xaf, 0xbb, 0xf0, 0x7a, 0x6e, 0x2d, + 0xf3, 0x5c, 0x54, 0xf7, 0x29, 0x15, 0x8c, 0xdf, 0x04, 0x32, 0x86, 0xe4, + 0x27, 0xd3, 0x9c, 0x17, 0x1e, 0xa2, 0xd1, 0xe4, 0x28, 0x24, 0x67, 0x99, + 0xab, 0xef, 0x8d, 0x97, 0x61, 0x73, 0xd4, 0x8f, 0xd5, 0xda, 0x80, 0xd2, + 0x95, 0x8f, 0xea, 0xe7, 0xf1, 0xbb, 0xca, 0x9e, 0x85, 0x04, 0x63, 0xbb, + 0x9f, 0xba, 0xa9, 0xc0, 0xa5, 0xa0, 0xf0, 0x88, 0x6a, 0xb7, 0xe6, 0xc0, + 0xbb, 0x77, 0x2b, 0x08, 0x68, 0x49, 0x5c, 0x68, 0x0e, 0xd0, 0xaf, 0xba, + 0x88, 0x31, 0xc2, 0x70, 0x2e, 0x86, 0xfc, 0x3b, 0x68, 0x8b, 0xca, 0xc5, + 0x3a, 0xda, 0x87, 0xbe, 0x47, 0x1d, 0xb6, 0x51, 0x87, 0xdd, 0x73, 0x08, + 0x54, 0x24, 0xfa, 0x94, 0x8e, 0x7c, 0xbb, 0xd2, 0x9e, 0x57, 0xa9, 0x27, + 0xd1, 0xc9, 0x37, 0x89, 0x95, 0xc4, 0x57, 0x4a, 0xb6, 0x14, 0x7f, 0xbd, + 0xd1, 0x9e, 0xfd, 0x0e, 0x89, 0xb9, 0xcd, 0x6b, 0x12, 0x8c, 0x47, 0x07, + 0xf9, 0x12, 0x1e, 0x3c, 0xa8, 0x6e, 0x30, 0x57, 0x5f, 0x89, 0x33, 0x79, + 0x56, 0x24, 0x30, 0x95, 0xef, 0xa1, 0x5d, 0x36, 0x14, 0xfd, 0x2b, 0xe0, + 0xdf, 0x36, 0xd3, 0xae, 0x6c, 0x5b, 0x58, 0xe1, 0xef, 0xa5, 0x0d, 0x7b, + 0x17, 0x42, 0x42, 0x97, 0xeb, 0x8b, 0x6d, 0x93, 0x70, 0x68, 0xff, 0x9a, + 0x2d, 0xbf, 0x41, 0x5a, 0x62, 0x4f, 0x6f, 0xc9, 0x4f, 0xfd, 0x7b, 0x66, + 0x92, 0x78, 0x77, 0x83, 0x9b, 0x35, 0xb5, 0x84, 0x29, 0xaa, 0x8a, 0x9f, + 0xa7, 0x1d, 0xd0, 0x52, 0x4a, 0x97, 0xf8, 0x91, 0xdb, 0x5e, 0xf3, 0xce, + 0x19, 0xb8, 0x09, 0x15, 0xc2, 0x4e, 0x62, 0xba, 0x0f, 0xe3, 0xd1, 0x81, + 0x73, 0x4a, 0x8f, 0xd2, 0x93, 0x97, 0x1a, 0x6c, 0xfb, 0x54, 0x1b, 0x7d, + 0xaa, 0x9d, 0xfc, 0xb4, 0xd3, 0xa7, 0xba, 0xc9, 0x4f, 0xb7, 0xe5, 0x53, + 0xe2, 0x9b, 0xbf, 0xce, 0xcb, 0xd6, 0xfc, 0x1e, 0x4b, 0x2f, 0x3b, 0xf8, + 0x6e, 0x17, 0xe5, 0xe8, 0xe2, 0x7b, 0x7b, 0xf8, 0xde, 0x9e, 0x85, 0xff, + 0x2d, 0xfc, 0x51, 0x16, 0x3b, 0xf6, 0xaf, 0xd7, 0x34, 0xc9, 0x01, 0xaf, + 0x15, 0x31, 0x05, 0xd2, 0x8e, 0x84, 0xe4, 0x88, 0x61, 0xf4, 0x36, 0xc3, + 0xb3, 0x22, 0xf1, 0x93, 0xd6, 0x5d, 0xf5, 0xcc, 0x67, 0xcc, 0xa7, 0x9e, + 0x29, 0x62, 0x69, 0xe6, 0xe8, 0xf9, 0x16, 0x05, 0x63, 0xfa, 0xcd, 0x8c, + 0x53, 0x1d, 0x13, 0x79, 0xb5, 0x2b, 0xcc, 0x7b, 0x4d, 0x93, 0x82, 0xf1, + 0x0f, 0xa2, 0x8d, 0xb8, 0x2e, 0x94, 0x18, 0x42, 0xc8, 0x88, 0x84, 0x26, + 0x14, 0x75, 0x68, 0x2b, 0xd4, 0x25, 0xd6, 0x86, 0xd4, 0x9c, 0xa2, 0x0e, + 0xd7, 0x3a, 0xd5, 0xe4, 0x9b, 0x16, 0xbe, 0x3e, 0x88, 0x35, 0x16, 0x86, + 0x1b, 0x42, 0x8c, 0x58, 0x76, 0x07, 0x69, 0x1e, 0xd8, 0xac, 0xe0, 0xb2, + 0xfe, 0x21, 0xed, 0xa8, 0x26, 0xd3, 0x8a, 0x8e, 0x0c, 0xf3, 0x44, 0x68, + 0x4a, 0xb0, 0xfa, 0x41, 0x62, 0x75, 0x78, 0x7c, 0x7c, 0x36, 0x33, 0x19, + 0x49, 0x79, 0x9c, 0x6a, 0x8c, 0x38, 0x3d, 0x49, 0x9a, 0x7a, 0x9e, 0xf8, + 0x9d, 0x6b, 0x84, 0xf7, 0x17, 0x69, 0x46, 0x8b, 0x34, 0xb5, 0x1c, 0x18, + 0x37, 0x13, 0xe8, 0x8c, 0xb2, 0x56, 0x30, 0xe7, 0x1d, 0x93, 0x9e, 0x80, + 0xf4, 0xca, 0xa7, 0x74, 0x7e, 0x4f, 0x29, 0xbb, 0x25, 0xa6, 0xca, 0x6d, + 0x2b, 0x54, 0x73, 0x8d, 0xaa, 0xc4, 0x61, 0x2c, 0x5a, 0x6b, 0x0c, 0xcb, + 0x1a, 0xc3, 0x3f, 0x53, 0xd4, 0xd8, 0x39, 0x45, 0x72, 0x75, 0x63, 0xff, + 0x39, 0xc6, 0xd0, 0x51, 0x45, 0x6d, 0x39, 0x4e, 0xf1, 0xbd, 0x9a, 0xd0, + 0x3f, 0x5c, 0x5c, 0x67, 0x18, 0x0d, 0x39, 0xc6, 0x67, 0xde, 0xa3, 0x6c, + 0xcd, 0xb6, 0x61, 0x6c, 0xae, 0x0d, 0xa3, 0x59, 0x05, 0x7b, 0xf4, 0x95, + 0xb8, 0x74, 0xb3, 0xd5, 0xa7, 0x54, 0xad, 0xd6, 0x6a, 0x31, 0x12, 0x40, + 0xb5, 0x43, 0xfb, 0x0a, 0xf6, 0x16, 0x31, 0x7e, 0xe7, 0x89, 0x5e, 0xe6, + 0x7d, 0x13, 0xef, 0x33, 0x96, 0x22, 0x35, 0x48, 0xba, 0x13, 0x2d, 0xc4, + 0xe3, 0x75, 0x4e, 0x3b, 0xde, 0xff, 0xc9, 0x63, 0xdb, 0x40, 0xf4, 0xff, + 0xf9, 0x7b, 0x6d, 0x78, 0x32, 0x5b, 0x86, 0x96, 0x0d, 0xb8, 0x2b, 0x84, + 0x2a, 0x07, 0x6b, 0xdc, 0x5b, 0xbb, 0x94, 0x14, 0xef, 0x59, 0xcf, 0x7a, + 0xbe, 0x9c, 0xe8, 0x4d, 0xfc, 0x97, 0x06, 0xb9, 0x6e, 0xe5, 0x8d, 0x1b, + 0xae, 0x0f, 0x7f, 0xc1, 0x75, 0x05, 0xcf, 0x31, 0x91, 0x7d, 0x8f, 0x35, + 0x25, 0x97, 0x31, 0xe1, 0x4c, 0xb8, 0x30, 0x34, 0x19, 0xc6, 0xc1, 0xc5, + 0x20, 0x16, 0x33, 0xea, 0xc0, 0x25, 0xf6, 0x0f, 0x7b, 0x9b, 0x35, 0x3c, + 0xb8, 0x18, 0xc2, 0x42, 0x06, 0xa6, 0x37, 0xa1, 0x15, 0xbc, 0x4a, 0x0c, + 0x07, 0x16, 0xeb, 0x70, 0x2e, 0xa3, 0x2d, 0x8d, 0x2a, 0xd1, 0x54, 0x2d, + 0x71, 0xc7, 0xc3, 0x8b, 0x4d, 0x78, 0x68, 0xd1, 0xc3, 0x77, 0x4c, 0x74, + 0xc7, 0xeb, 0xf8, 0xbc, 0x03, 0xcf, 0x9e, 0x34, 0x4d, 0xc1, 0x5d, 0x43, + 0x8b, 0xc0, 0xc2, 0x34, 0x6b, 0xd1, 0x19, 0xd6, 0xa5, 0xa7, 0x80, 0x03, + 0x4f, 0x39, 0x30, 0x37, 0x6d, 0x62, 0xaf, 0x3e, 0x5a, 0xeb, 0xa0, 0xc3, + 0x0f, 0xb0, 0x6e, 0xb8, 0x59, 0x03, 0xef, 0x0d, 0xd8, 0xf9, 0xfc, 0x12, + 0xf3, 0xd4, 0xfd, 0x4f, 0xc5, 0xf0, 0x56, 0x26, 0x8d, 0x6e, 0xe2, 0xf3, + 0x14, 0x79, 0x79, 0x33, 0xc3, 0x3a, 0xb6, 0xa8, 0xe3, 0x8d, 0x8c, 0x87, + 0xeb, 0x34, 0xe1, 0xe5, 0x8c, 0x3c, 0x23, 0xcf, 0xfa, 0x30, 0x48, 0x5e, + 0x5e, 0xcf, 0x84, 0xb8, 0x66, 0x10, 0x3f, 0xe6, 0x73, 0xf7, 0x2d, 0x6a, + 0xac, 0x5b, 0x1e, 0xae, 0x1b, 0xc6, 0xab, 0x19, 0x1f, 0x79, 0x0d, 0xb2, + 0x56, 0x0d, 0x62, 0x2c, 0xd3, 0xb8, 0xb4, 0x95, 0x89, 0xda, 0xae, 0x35, + 0x72, 0xed, 0x1d, 0xb3, 0xc7, 0x8a, 0x45, 0x59, 0xa7, 0xb4, 0xee, 0x20, + 0x46, 0x33, 0x6f, 0x38, 0x4b, 0xfd, 0xf4, 0x73, 0xd3, 0xcb, 0x16, 0xf6, + 0x7b, 0xd6, 0xe0, 0xdf, 0x73, 0xc0, 0x39, 0x23, 0x6d, 0x56, 0x27, 0x88, + 0x75, 0x59, 0xa3, 0x7e, 0xba, 0xb1, 0x89, 0xeb, 0x6a, 0x03, 0x2f, 0x29, + 0xd2, 0xef, 0xb8, 0x10, 0x7e, 0x4a, 0xf4, 0x45, 0xcc, 0xbc, 0x00, 0xfc, + 0x25, 0xf1, 0x67, 0xc3, 0xa4, 0x2a, 0x7e, 0xdf, 0x4f, 0x5c, 0xd3, 0x5b, + 0x40, 0x7d, 0xec, 0x41, 0x8c, 0x98, 0x65, 0xc4, 0xe7, 0xd5, 0xc4, 0xb5, + 0x8b, 0x4d, 0xac, 0x53, 0x1b, 0x4d, 0xf3, 0x6f, 0x9b, 0x61, 0x3a, 0x12, + 0x9a, 0x5e, 0xeb, 0x2c, 0x7c, 0xa5, 0x0a, 0xda, 0x92, 0x5f, 0xd1, 0x0a, + 0x3f, 0x45, 0x74, 0xf8, 0x3c, 0x44, 0xaf, 0xc0, 0xda, 0x45, 0x17, 0xd6, + 0x51, 0x9e, 0x6d, 0x93, 0x5c, 0x9b, 0xf8, 0x24, 0x4a, 0x99, 0x76, 0x4e, + 0x12, 0x73, 0x69, 0x3e, 0xac, 0xa1, 0x8e, 0x87, 0x4e, 0x99, 0x66, 0x39, + 0x75, 0xdc, 0x40, 0xfb, 0xec, 0x3f, 0x61, 0xe2, 0x25, 0xfd, 0x25, 0xea, + 0x54, 0x21, 0x6e, 0x6c, 0xe6, 0x3b, 0x41, 0x3e, 0xef, 0xc1, 0x81, 0x49, + 0xe9, 0x97, 0xea, 0xf8, 0xcc, 0x45, 0x1c, 0xcf, 0xc4, 0xd0, 0x44, 0xfd, + 0x85, 0x49, 0xb3, 0x91, 0xef, 0x84, 0x49, 0x2f, 0xbc, 0xf8, 0x35, 0x6c, + 0x3f, 0xa5, 0x40, 0x8b, 0x8a, 0x0e, 0xbe, 0x86, 0xf6, 0x33, 0x5f, 0x94, + 0x13, 0x98, 0xa5, 0xa6, 0xd5, 0x89, 0x02, 0xf1, 0x77, 0x55, 0x62, 0x04, + 0xac, 0xdf, 0x78, 0x73, 0x56, 0xc1, 0xd4, 0x34, 0xfb, 0xbd, 0x8d, 0x30, + 0x2b, 0x28, 0xd3, 0x1b, 0xb3, 0xbf, 0x81, 0x67, 0x4e, 0x52, 0x0f, 0x4f, + 0x07, 0xf1, 0xbd, 0x8c, 0x0b, 0xb7, 0x4e, 0x09, 0xa6, 0xd3, 0x62, 0x07, + 0x15, 0xe9, 0x8f, 0xa4, 0x6f, 0x89, 0x86, 0xdd, 0x8a, 0x03, 0xf5, 0xcf, + 0xb8, 0xa0, 0x9d, 0x0b, 0xc3, 0x5d, 0xef, 0x81, 0x56, 0xff, 0xfb, 0xcc, + 0x35, 0x0e, 0x94, 0xb1, 0x97, 0xed, 0xfc, 0x76, 0x8c, 0xd7, 0x82, 0xbc, + 0x86, 0xdf, 0x28, 0x87, 0x73, 0x95, 0x93, 0x35, 0xbc, 0x4c, 0x23, 0x1e, + 0x73, 0x99, 0xa6, 0x93, 0xb5, 0x61, 0xf7, 0x77, 0x4c, 0x33, 0xb2, 0x41, + 0x9e, 0x0f, 0x20, 0x72, 0x4e, 0xe3, 0x73, 0x76, 0xbd, 0xbc, 0x8e, 0xc7, + 0x9c, 0xf4, 0x23, 0x89, 0x55, 0xd6, 0x7b, 0xab, 0x87, 0xb2, 0x71, 0xfb, + 0x0b, 0x79, 0xc1, 0x36, 0x61, 0x4b, 0x86, 0xb3, 0xd3, 0x0a, 0x73, 0x76, + 0x82, 0xcf, 0x6e, 0x81, 0x33, 0xae, 0x4e, 0xa4, 0xe9, 0x07, 0x7b, 0x03, + 0x2d, 0x78, 0xce, 0x70, 0xa3, 0x52, 0x5b, 0x85, 0x07, 0x7a, 0x03, 0x78, + 0x8e, 0x7d, 0x01, 0x6d, 0x16, 0x2b, 0x80, 0x8d, 0xb4, 0x9f, 0xf4, 0x1c, + 0x3f, 0x84, 0xf6, 0x6d, 0x07, 0xf3, 0x9c, 0xd3, 0xca, 0x73, 0x65, 0xf5, + 0x40, 0x21, 0xe7, 0xc2, 0x05, 0xcd, 0xc6, 0x84, 0x2f, 0x58, 0x35, 0x5b, + 0x0d, 0x14, 0xae, 0x61, 0x41, 0xb5, 0x25, 0xa9, 0x90, 0x19, 0xbf, 0xe8, + 0xae, 0xdf, 0x65, 0xfb, 0xd2, 0xdf, 0x38, 0xa5, 0xe7, 0xb8, 0xfe, 0xbd, + 0x02, 0x8e, 0x84, 0x1a, 0x6a, 0x73, 0xc2, 0xe3, 0x4a, 0x0c, 0xb5, 0x8e, + 0x6b, 0x5f, 0xba, 0x81, 0xf7, 0x26, 0x8c, 0xe5, 0xaf, 0xf7, 0xda, 0x5d, + 0x19, 0xcb, 0x87, 0xba, 0x44, 0xf7, 0x4f, 0xe8, 0x92, 0x67, 0x53, 0x4a, + 0x3b, 0xf3, 0x56, 0xda, 0x85, 0x74, 0x15, 0x9f, 0xa1, 0xfe, 0x71, 0x74, + 0x52, 0xe8, 0x1c, 0xc6, 0x78, 0x46, 0x66, 0x1b, 0xc3, 0xd8, 0x6c, 0x44, + 0x62, 0x4b, 0xec, 0xa1, 0x8f, 0x40, 0xe6, 0x10, 0x8d, 0x85, 0x57, 0x14, + 0x35, 0x75, 0x8b, 0x53, 0x1d, 0x5a, 0x56, 0xec, 0xbc, 0xb5, 0xb6, 0x98, + 0xb7, 0xd6, 0xe4, 0x56, 0xf9, 0x7b, 0x58, 0x0f, 0x7a, 0x16, 0x4a, 0xf5, + 0xa1, 0x47, 0xe9, 0xb4, 0x6a, 0x6b, 0xbf, 0xb2, 0x63, 0xc1, 0xa3, 0x74, + 0x64, 0x3d, 0x78, 0x85, 0x58, 0x6c, 0xb6, 0x0f, 0x81, 0x5b, 0x37, 0xc2, + 0xbb, 0x23, 0xdb, 0x8b, 0x72, 0x4d, 0x7a, 0xc8, 0x72, 0x74, 0x5a, 0x75, + 0xad, 0xce, 0xdf, 0xc3, 0xfa, 0xd3, 0x93, 0xef, 0x63, 0xfe, 0x43, 0xc0, + 0x9b, 0xb0, 0x67, 0x06, 0x92, 0x0b, 0xef, 0xe0, 0xbb, 0x4b, 0xf1, 0x15, + 0x80, 0x5d, 0xff, 0x94, 0x7e, 0xf6, 0x12, 0xd5, 0x1b, 0x14, 0x5c, 0xba, + 0xcb, 0x03, 0xd2, 0x62, 0xcf, 0x7f, 0xb1, 0xf5, 0xc2, 0x74, 0xaf, 0xd2, + 0x31, 0x37, 0xef, 0xdd, 0x66, 0xc8, 0x2c, 0x62, 0xd6, 0xdb, 0x4e, 0x1e, + 0xda, 0x17, 0x9e, 0xf6, 0x6e, 0x25, 0x4f, 0x5b, 0x17, 0x3e, 0x4f, 0x53, + 0xea, 0xca, 0x44, 0x6b, 0x1b, 0x63, 0x7b, 0xb7, 0xfe, 0x91, 0x19, 0xfe, + 0x1d, 0xa1, 0xb3, 0x58, 0xd4, 0x67, 0x92, 0x7c, 0x05, 0x3d, 0x9d, 0xf9, + 0x80, 0x27, 0x99, 0x6f, 0xf7, 0xb6, 0x19, 0xbd, 0xde, 0xad, 0x46, 0x9f, + 0xb7, 0xdd, 0xb8, 0x87, 0xb4, 0x7b, 0xbc, 0x1d, 0x06, 0xe3, 0x3a, 0xdf, + 0x47, 0xbd, 0xf6, 0x62, 0x3c, 0x7f, 0x0f, 0xb1, 0x87, 0xd0, 0x1c, 0x20, + 0x0e, 0xf2, 0x52, 0xc6, 0x11, 0xca, 0x58, 0x08, 0xb9, 0x91, 0x54, 0xdd, + 0xd4, 0xd7, 0x98, 0x65, 0xc7, 0x09, 0x6b, 0x16, 0x55, 0x91, 0x98, 0x6c, + 0xed, 0x3e, 0xc1, 0x7c, 0x9f, 0x38, 0xda, 0x7a, 0xeb, 0x29, 0xd4, 0xb8, + 0x13, 0xd2, 0x3b, 0xb3, 0x1f, 0x8e, 0x46, 0xf5, 0xf7, 0x10, 0x0d, 0xbd, + 0xc2, 0x67, 0x47, 0xe9, 0xbb, 0x63, 0xd6, 0xfc, 0x81, 0x06, 0xc9, 0x35, + 0xa1, 0xdb, 0xf0, 0x78, 0x77, 0xb2, 0x37, 0xf3, 0x27, 0xd4, 0x96, 0x3b, + 0x9c, 0x32, 0x0f, 0x29, 0xfc, 0x96, 0x0f, 0x4d, 0xe8, 0xca, 0x7b, 0x28, + 0xd7, 0x97, 0xf0, 0x0f, 0x27, 0x59, 0xd7, 0x20, 0x7e, 0x68, 0x9a, 0xf7, + 0xb1, 0xaf, 0x39, 0x96, 0xab, 0xc3, 0x65, 0xcb, 0xc6, 0x2e, 0x1c, 0xcd, + 0x85, 0xf1, 0x0e, 0xe5, 0x73, 0x2d, 0xd6, 0xe2, 0xed, 0x69, 0x27, 0xf6, + 0xe9, 0xb7, 0x17, 0xeb, 0x85, 0x03, 0xf7, 0xc6, 0x0e, 0x11, 0x3b, 0x38, + 0x50, 0x4d, 0xfc, 0xf6, 0xb0, 0x75, 0xcd, 0xc9, 0xfe, 0xef, 0xb7, 0x91, + 0xb2, 0xeb, 0x09, 0x79, 0x7c, 0x94, 0x3c, 0x36, 0x7b, 0xb7, 0x66, 0x55, + 0xef, 0x9d, 0x59, 0x78, 0xdc, 0x89, 0xd1, 0xd6, 0x33, 0x27, 0x4d, 0x0c, + 0xea, 0xb7, 0xe1, 0xca, 0xc9, 0xd1, 0x21, 0x17, 0xfd, 0xe7, 0xe7, 0xf1, + 0x7e, 0x18, 0x33, 0xb8, 0x40, 0xe4, 0x71, 0xd1, 0xc7, 0xdc, 0xde, 0x10, + 0x8f, 0x06, 0x58, 0x8b, 0xf5, 0x05, 0xc6, 0x66, 0x07, 0xd4, 0x21, 0xd6, + 0xe4, 0xa4, 0x33, 0x11, 0x1d, 0x18, 0x23, 0x78, 0xac, 0x22, 0x3f, 0x5e, + 0xe6, 0x6e, 0xdf, 0x62, 0xd8, 0xbb, 0x9b, 0xf5, 0x26, 0xc4, 0xfe, 0xce, + 0x1b, 0xc5, 0xed, 0xb5, 0x88, 0xc6, 0x96, 0x29, 0xb7, 0x7b, 0xb1, 0xc9, + 0x7b, 0x07, 0xeb, 0xc7, 0xe5, 0xa8, 0x39, 0xf2, 0x92, 0xee, 0x83, 0x7f, + 0x51, 0xa7, 0xbe, 0xfb, 0x31, 0xba, 0xc0, 0x96, 0x2b, 0xca, 0x9e, 0x7f, + 0xb1, 0xc5, 0xbb, 0x93, 0xb1, 0x59, 0x45, 0x13, 0x35, 0x2e, 0x26, 0xbd, + 0xd2, 0xf3, 0x35, 0x2d, 0x6e, 0x22, 0x7f, 0xe2, 0xa3, 0x99, 0xd6, 0xcd, + 0xf4, 0x87, 0xf0, 0x22, 0x3a, 0x99, 0xe6, 0x5e, 0x26, 0xcd, 0xfe, 0x10, + 0x31, 0xec, 0x81, 0x8d, 0x3e, 0xe6, 0x29, 0xd1, 0x25, 0xf5, 0x98, 0x2f, + 0xc9, 0x24, 0x75, 0xf9, 0x68, 0xeb, 0xe2, 0x29, 0xa9, 0xcb, 0xa9, 0xd6, + 0xcc, 0x29, 0x0d, 0xef, 0xb0, 0xb6, 0xac, 0x8d, 0xab, 0xfa, 0x39, 0x25, + 0x12, 0xba, 0x48, 0x59, 0x5c, 0xf8, 0x85, 0xb9, 0x57, 0x8b, 0x16, 0x6e, + 0x61, 0x3c, 0x55, 0x33, 0x37, 0x86, 0x98, 0xf3, 0xab, 0x17, 0xa9, 0x98, + 0x45, 0xa7, 0x1b, 0x15, 0x21, 0x78, 0xa2, 0x1a, 0xde, 0x3d, 0x19, 0xa3, + 0x1e, 0xae, 0xd1, 0x3c, 0x48, 0xa8, 0x35, 0xc8, 0x52, 0xf8, 0xd8, 0x33, + 0xf4, 0xc5, 0x71, 0xae, 0x5b, 0xb6, 0x28, 0x3c, 0xcb, 0xf3, 0x41, 0x3e, + 0x7f, 0x7d, 0xed, 0x6a, 0xae, 0xfd, 0xd1, 0x29, 0xf1, 0xd7, 0x54, 0xeb, + 0x85, 0x93, 0xf6, 0xda, 0xd1, 0x78, 0x0c, 0x1f, 0x9e, 0x54, 0x87, 0xdf, + 0x55, 0x22, 0x03, 0x17, 0x14, 0x59, 0x1f, 0x75, 0x55, 0xb8, 0x62, 0x8e, + 0x46, 0xa3, 0xa9, 0xbd, 0xa4, 0xd9, 0xb2, 0x89, 0xfa, 0xb7, 0xf8, 0xa0, + 0xcf, 0x33, 0xcf, 0xba, 0xc9, 0x8f, 0xcd, 0x4b, 0x1d, 0x69, 0x9f, 0x2c, + 0xf6, 0x6a, 0xec, 0x53, 0xaf, 0xf3, 0x13, 0xa4, 0x1e, 0x3c, 0xbb, 0x9b, + 0x7d, 0xa8, 0xb5, 0x9e, 0x0b, 0xf0, 0x39, 0xd1, 0xc3, 0x2f, 0x15, 0x87, + 0xf6, 0x1e, 0xf3, 0x98, 0xe4, 0x92, 0x20, 0x73, 0xd8, 0x3d, 0xd2, 0xd3, + 0xa6, 0xd3, 0xf4, 0x77, 0x37, 0xfd, 0x7d, 0x9b, 0xf8, 0xb4, 0x41, 0x9f, + 0x36, 0xe8, 0xd3, 0x86, 0x1a, 0x1a, 0x46, 0x24, 0x30, 0x48, 0xbb, 0x25, + 0x43, 0xe2, 0xeb, 0x7d, 0xd8, 0xc7, 0xdf, 0xfd, 0xbc, 0x7f, 0x94, 0x7d, + 0x2e, 0x56, 0xc8, 0x9a, 0x87, 0xd1, 0x6e, 0x3c, 0x86, 0xa1, 0x2c, 0x7e, + 0xe5, 0x6d, 0x2e, 0x47, 0xf9, 0x1a, 0xe9, 0xe1, 0xd5, 0xc0, 0x31, 0x3c, + 0xc6, 0x3e, 0xea, 0x97, 0x4a, 0xa5, 0xe6, 0xea, 0x3d, 0xae, 0xa8, 0x81, + 0x76, 0xf6, 0xc3, 0x7b, 0xf3, 0xf7, 0xd0, 0xbe, 0x91, 0xa1, 0x57, 0x14, + 0xf6, 0x52, 0xb5, 0x5c, 0x9b, 0xb1, 0x74, 0x27, 0xd7, 0x31, 0x84, 0x0f, + 0x2b, 0xdf, 0xfe, 0x1e, 0x44, 0xb7, 0x3f, 0x6a, 0x18, 0xe4, 0xfa, 0x36, + 0x1f, 0xa3, 0xec, 0x29, 0x07, 0x19, 0x63, 0xfb, 0xac, 0xf8, 0xea, 0x23, + 0x8d, 0xeb, 0x79, 0x6c, 0x6b, 0x46, 0x6a, 0xa9, 0x89, 0xc7, 0x75, 0x13, + 0xcf, 0xf2, 0x77, 0x89, 0xb9, 0x6c, 0xec, 0x86, 0x5c, 0xe6, 0xe0, 0x73, + 0xbb, 0xf9, 0x5c, 0x0b, 0x53, 0xe7, 0xc2, 0x9c, 0xcc, 0x06, 0x0f, 0xcb, + 0x6c, 0x10, 0x39, 0x43, 0x74, 0x3f, 0x8c, 0x0b, 0x99, 0x48, 0xca, 0xe9, + 0x34, 0x47, 0x18, 0x57, 0x4b, 0x1f, 0xd1, 0x77, 0x5f, 0xdf, 0xa8, 0xf6, + 0x52, 0x87, 0xb1, 0x49, 0x45, 0x0d, 0xbd, 0x86, 0x42, 0xa7, 0x07, 0x8d, + 0xe1, 0x75, 0xce, 0x68, 0xe0, 0x2c, 0xd4, 0xc2, 0x20, 0x25, 0x7d, 0x3a, + 0x6f, 0xe7, 0xba, 0xcd, 0xc5, 0x5c, 0xd7, 0x92, 0xab, 0x50, 0xee, 0xcc, + 0xb2, 0x3e, 0xcf, 0x99, 0x69, 0x3f, 0xeb, 0x55, 0x7e, 0x4e, 0x68, 0x8f, + 0xa0, 0x31, 0x2e, 0xb4, 0xb4, 0xae, 0x49, 0x05, 0x5f, 0xaf, 0x44, 0x94, + 0xb5, 0x0a, 0x7a, 0xb9, 0x96, 0x36, 0x59, 0x93, 0x02, 0xee, 0x84, 0xd4, + 0xce, 0x1e, 0xf6, 0x2d, 0x7d, 0xcc, 0x8b, 0x82, 0xa9, 0x65, 0x5e, 0x6a, + 0xe7, 0xa3, 0x6d, 0x79, 0xb1, 0x8b, 0xd8, 0x44, 0x6c, 0x73, 0x18, 0x07, + 0xac, 0x79, 0xb4, 0x89, 0x69, 0x5d, 0x72, 0x83, 0xd8, 0xe9, 0x30, 0xf6, + 0xe7, 0xdd, 0xb8, 0x97, 0x79, 0x70, 0xbe, 0x99, 0xba, 0xf2, 0xbb, 0x31, + 0x38, 0x77, 0x3b, 0xf6, 0x65, 0x65, 0x9e, 0xe0, 0xa6, 0xfd, 0x92, 0xc4, + 0x40, 0xcc, 0x3a, 0xc4, 0x3f, 0x65, 0x5a, 0x49, 0xa7, 0x42, 0x5b, 0x74, + 0x5a, 0xfa, 0xbe, 0xe0, 0xb6, 0x75, 0x6c, 0xcf, 0x2d, 0x9d, 0x09, 0x59, + 0xab, 0x34, 0xb3, 0xb4, 0xf5, 0xda, 0x99, 0x91, 0x35, 0x4d, 0x9c, 0xd5, + 0x6d, 0x4c, 0x5b, 0xd2, 0x67, 0x88, 0x32, 0xd7, 0x6c, 0x02, 0xd6, 0xdd, + 0x80, 0x6b, 0x2b, 0x78, 0xad, 0xfb, 0x3a, 0xae, 0xed, 0x17, 0xec, 0x4c, + 0x5c, 0xdb, 0xb5, 0x83, 0xb8, 0xb6, 0x5e, 0x29, 0x61, 0x5a, 0x99, 0x59, + 0x94, 0x70, 0x6d, 0x75, 0x31, 0x7f, 0x1f, 0xc6, 0x5e, 0x62, 0x9e, 0xda, + 0xfa, 0x11, 0x78, 0xd6, 0x3b, 0x3e, 0x73, 0x60, 0x84, 0xbd, 0x4c, 0x19, + 0xb0, 0xd2, 0xc4, 0x2d, 0x1b, 0xd2, 0x66, 0xb9, 0x56, 0x1f, 0x2e, 0x77, + 0xc8, 0x4c, 0x3a, 0x9a, 0x1e, 0x63, 0x9e, 0x71, 0xac, 0x57, 0xd3, 0x49, + 0x78, 0x02, 0x35, 0xda, 0x3d, 0xc5, 0x5e, 0x22, 0xe4, 0xd9, 0x4e, 0x4c, + 0x14, 0x8d, 0x7f, 0x6a, 0xce, 0x06, 0x85, 0x46, 0xa1, 0xe0, 0x41, 0xf2, + 0x11, 0x0f, 0x6b, 0xd4, 0xb2, 0x32, 0x81, 0xd7, 0xa3, 0x21, 0xcf, 0xce, + 0x7c, 0xda, 0xdb, 0xdd, 0x70, 0x0b, 0x7a, 0x4e, 0x49, 0x3d, 0x0a, 0x63, + 0xc7, 0xa9, 0x76, 0xd6, 0x20, 0x0d, 0x1d, 0x93, 0x5d, 0xec, 0xf1, 0x7a, + 0x95, 0xde, 0x39, 0xd1, 0xa1, 0xd8, 0x40, 0x0d, 0x84, 0x1d, 0x37, 0xce, + 0x4c, 0x4b, 0xfd, 0xf2, 0x7b, 0x96, 0x7f, 0x8d, 0xeb, 0x01, 0xea, 0xe7, + 0xaa, 0x1b, 0x7e, 0x13, 0x67, 0x74, 0xf1, 0x4b, 0x7e, 0x37, 0x92, 0xd8, + 0xd6, 0x3c, 0x6d, 0xba, 0x34, 0x99, 0x7d, 0x87, 0x2c, 0x9b, 0x6e, 0x65, + 0x9d, 0x6b, 0x9f, 0xeb, 0xa3, 0x1d, 0x4b, 0x73, 0xee, 0x1b, 0xed, 0xb9, + 0xc5, 0xbb, 0x8d, 0x39, 0x8f, 0x3d, 0xbc, 0xc7, 0xc3, 0x3c, 0xea, 0x39, + 0x65, 0x62, 0x4e, 0x7f, 0xcb, 0x7c, 0x5c, 0x73, 0xd1, 0x6e, 0x5f, 0x65, + 0x4e, 0x16, 0xcc, 0x92, 0xf0, 0xde, 0x31, 0xe3, 0x72, 0x54, 0x25, 0xd0, + 0x5c, 0x46, 0x7f, 0xbc, 0x18, 0xb7, 0xe7, 0x91, 0xc7, 0x73, 0xb7, 0x7b, + 0xbb, 0xb3, 0xec, 0x33, 0xd8, 0x07, 0xdb, 0xbd, 0xdf, 0x57, 0xbd, 0x7b, + 0xb2, 0x4e, 0xa5, 0x36, 0x01, 0x67, 0xcb, 0x26, 0x13, 0x1f, 0x6f, 0x88, + 0xa6, 0x42, 0x0e, 0xe6, 0x4f, 0xd2, 0x32, 0x72, 0xcd, 0xde, 0x7e, 0xe6, + 0xeb, 0x9d, 0x59, 0xba, 0x01, 0x7d, 0xc7, 0xbf, 0x61, 0x74, 0xc0, 0x0f, + 0x99, 0xb3, 0xe1, 0xeb, 0x8c, 0xd8, 0x20, 0xfd, 0x31, 0xd4, 0xa6, 0x44, + 0x97, 0x87, 0x10, 0x5d, 0xfa, 0xd8, 0xf9, 0x96, 0xf9, 0x64, 0x6e, 0x13, + 0x9f, 0xef, 0x62, 0x2e, 0x4d, 0x32, 0xb7, 0x8e, 0xa6, 0xdc, 0x90, 0x77, + 0xd4, 0xfe, 0x37, 0x95, 0x08, 0xe3, 0x00, 0xbf, 0xc3, 0xe7, 0x03, 0x1d, + 0xcc, 0xa3, 0x73, 0x7a, 0x34, 0xb9, 0x15, 0xe9, 0xae, 0x6a, 0xa8, 0x7a, + 0x83, 0x22, 0x73, 0x31, 0xb1, 0x43, 0x0c, 0x3f, 0xe1, 0x9a, 0x2e, 0x4d, + 0xf4, 0xb8, 0x85, 0xbe, 0x48, 0x6c, 0xe0, 0xf8, 0xbc, 0xdf, 0xfd, 0x5e, + 0x19, 0x2a, 0x56, 0x50, 0xb6, 0x9f, 0x58, 0x39, 0xc7, 0xab, 0x69, 0xf8, + 0xaf, 0xc4, 0x4e, 0x7f, 0x96, 0x97, 0xf9, 0x67, 0x09, 0x0f, 0x8a, 0x6f, + 0x64, 0x5a, 0x6f, 0x9d, 0x8d, 0x15, 0xe7, 0xa1, 0x1e, 0x6f, 0xd7, 0x8c, + 0x89, 0xac, 0xee, 0x87, 0xf4, 0xff, 0xe5, 0xf1, 0x02, 0xd1, 0x41, 0x13, + 0x3a, 0x78, 0xbd, 0x7d, 0xa6, 0x52, 0x69, 0xcf, 0x9a, 0xf8, 0x33, 0x5d, + 0x4d, 0xb7, 0x39, 0x19, 0xef, 0xba, 0x7a, 0x16, 0xf8, 0x19, 0x71, 0x94, + 0xf8, 0x98, 0x0b, 0x3e, 0xcd, 0xa6, 0xd5, 0x34, 0x7b, 0x3b, 0xb1, 0x85, + 0xc4, 0x9f, 0x73, 0x6d, 0x05, 0x9a, 0x95, 0x59, 0x97, 0xe8, 0xad, 0x0b, + 0xc9, 0x7c, 0xa5, 0xb2, 0x8b, 0xba, 0xbc, 0x73, 0xbd, 0x17, 0x97, 0x2c, + 0x5d, 0xde, 0x4e, 0x5d, 0xe2, 0x8d, 0xd5, 0x70, 0x5e, 0xa8, 0x05, 0xc1, + 0x44, 0xb9, 0x1a, 0x1e, 0x70, 0x88, 0x4d, 0x18, 0x27, 0x82, 0xd5, 0x50, + 0xc9, 0x7a, 0x9e, 0x24, 0x0e, 0x26, 0x6e, 0x0c, 0xf4, 0xe1, 0xdb, 0xcc, + 0x4b, 0x8f, 0xd3, 0x6f, 0x7f, 0xa1, 0x35, 0xa1, 0xe2, 0x3b, 0xcd, 0xb4, + 0xe9, 0x26, 0xef, 0xf6, 0x6c, 0x3f, 0x9e, 0x58, 0x30, 0xf1, 0x0c, 0x63, + 0xa6, 0x21, 0x9e, 0x0e, 0x94, 0xb3, 0xaf, 0x63, 0xed, 0x5b, 0x3e, 0x61, + 0xf9, 0xfc, 0x68, 0xeb, 0x96, 0xf9, 0x10, 0x9c, 0xdf, 0xb6, 0xf6, 0x7e, + 0x5a, 0xc3, 0xf3, 0xd6, 0xde, 0x0f, 0x3f, 0x4d, 0x0c, 0xeb, 0x6a, 0xf2, + 0x63, 0x67, 0x05, 0x2a, 0xa3, 0xa6, 0x39, 0x1c, 0xb7, 0xf6, 0x1f, 0x5a, + 0x63, 0xd6, 0xfd, 0xa3, 0xfc, 0x2c, 0xcd, 0xae, 0xff, 0x46, 0x30, 0x63, + 0x38, 0x49, 0xf9, 0x77, 0x10, 0x07, 0xf4, 0x13, 0x07, 0xd4, 0x26, 0xd4, + 0xe4, 0x6e, 0xa7, 0xcc, 0x69, 0x0a, 0x87, 0xaa, 0x79, 0xfd, 0x8e, 0x22, + 0x0e, 0xa8, 0x3a, 0x25, 0xb3, 0x3f, 0x62, 0x45, 0xd8, 0x7b, 0x26, 0x3d, + 0xc4, 0x01, 0x15, 0x93, 0x2e, 0x74, 0x13, 0x03, 0xb8, 0x89, 0xd9, 0xb7, + 0xe5, 0x6a, 0xe1, 0x3d, 0xe1, 0x44, 0x24, 0xfe, 0x23, 0x1c, 0xa2, 0xbf, + 0x1d, 0x8a, 0x79, 0x94, 0xf0, 0x2a, 0x07, 0x75, 0xf6, 0x2b, 0x1c, 0x0c, + 0x38, 0x51, 0xa5, 0xbd, 0x86, 0x07, 0xbf, 0xa0, 0xf6, 0xf7, 0x67, 0x25, + 0xce, 0x47, 0x5b, 0xbb, 0x4f, 0xd9, 0xb5, 0xdf, 0x77, 0x6a, 0x74, 0x59, + 0x6a, 0x7f, 0xed, 0x86, 0x7e, 0x9c, 0x9e, 0xc1, 0x37, 0x57, 0x13, 0x64, + 0xd6, 0x72, 0xcd, 0xfa, 0x78, 0x94, 0x3d, 0xb8, 0x3a, 0xd4, 0xa1, 0x44, + 0x27, 0xaa, 0x98, 0x0f, 0x4e, 0xb3, 0xf6, 0x7b, 0x12, 0xd1, 0x40, 0xcc, + 0x81, 0x1e, 0x37, 0x6d, 0xf3, 0x3e, 0xfb, 0xf1, 0x9f, 0xe6, 0xc2, 0xa4, + 0x59, 0x06, 0x17, 0x6b, 0xff, 0xfb, 0x1a, 0x3e, 0x73, 0xd2, 0x0f, 0xdf, + 0x71, 0x7a, 0x70, 0x35, 0x67, 0xd7, 0xfe, 0xea, 0x06, 0x73, 0xe4, 0x72, + 0xdc, 0x87, 0x2b, 0x39, 0x9d, 0xfe, 0xd8, 0x8f, 0xa3, 0xac, 0xfd, 0x97, + 0xb5, 0x00, 0x3e, 0xcc, 0xb5, 0xd0, 0x47, 0x83, 0xf8, 0x39, 0x71, 0xf2, + 0x7a, 0xd6, 0xfe, 0xbb, 0xe8, 0x5f, 0x71, 0xd6, 0xfe, 0x36, 0x0b, 0x97, + 0x64, 0x5a, 0xcf, 0x4c, 0x5b, 0xb5, 0xbf, 0xc1, 0xc1, 0xba, 0xe9, 0x46, + 0x74, 0x99, 0x39, 0xc3, 0xfc, 0xc5, 0x26, 0x1f, 0x9f, 0xa5, 0xde, 0xf2, + 0x1b, 0x30, 0x6b, 0xd5, 0xaa, 0x2d, 0xde, 0x5d, 0x5c, 0x7b, 0xa5, 0x15, + 0x73, 0x26, 0x76, 0xac, 0xff, 0x6b, 0xfc, 0x41, 0x8d, 0x83, 0x3e, 0x99, + 0xf0, 0xde, 0xc9, 0xb8, 0xf3, 0x27, 0x4a, 0xb3, 0x91, 0x18, 0xd7, 0xb9, + 0xdd, 0x7b, 0x17, 0xfd, 0xe4, 0x96, 0xf5, 0xcc, 0x2a, 0x01, 0x3b, 0xe6, + 0xda, 0x19, 0x73, 0x21, 0xc6, 0xdc, 0x6a, 0xc6, 0xdc, 0x93, 0x7a, 0x34, + 0xb6, 0x85, 0xf8, 0xec, 0x95, 0x9c, 0xc4, 0x5d, 0x33, 0xe9, 0xaa, 0x94, + 0x6b, 0x74, 0x40, 0xe2, 0x67, 0xc7, 0xfa, 0xd1, 0xb3, 0x95, 0x10, 0x5d, + 0xe1, 0xb3, 0x95, 0xc4, 0x22, 0xcc, 0x52, 0x4b, 0xcb, 0xce, 0x68, 0xea, + 0x36, 0x67, 0x74, 0xf8, 0x3d, 0xe5, 0x2d, 0xf3, 0x0d, 0xc6, 0xdc, 0x4e, + 0xc6, 0xdc, 0x2e, 0xc6, 0x5c, 0x9b, 0x61, 0xe2, 0x85, 0xb8, 0xda, 0xdf, + 0xe4, 0x88, 0xe8, 0x6d, 0x0e, 0xac, 0xae, 0x64, 0x09, 0xf1, 0x22, 0xda, + 0xf5, 0x07, 0xe4, 0x7f, 0x49, 0x8f, 0xf6, 0xc6, 0x14, 0x89, 0xb3, 0x30, + 0x3e, 0xa0, 0xdc, 0xe5, 0xc5, 0x38, 0x3b, 0x30, 0x77, 0xbe, 0xe8, 0x1b, + 0x25, 0xd9, 0x9d, 0x78, 0x5e, 0x67, 0x5e, 0x5d, 0x21, 0xbe, 0xdb, 0x87, + 0x09, 0xea, 0xd1, 0x1b, 0xed, 0xc3, 0x31, 0xd6, 0xcd, 0xfb, 0x58, 0xaf, + 0xef, 0x37, 0x22, 0x2d, 0xdb, 0xd9, 0x27, 0x5d, 0x0a, 0xa9, 0xe1, 0xb0, + 0xd2, 0x87, 0x41, 0xfa, 0xf0, 0x20, 0xeb, 0x4b, 0x9b, 0xf1, 0x4b, 0xa5, + 0x83, 0x98, 0x62, 0x7f, 0x5e, 0xde, 0x53, 0x63, 0x69, 0xc7, 0x10, 0x06, + 0x16, 0x24, 0xcf, 0x21, 0x70, 0x53, 0xa2, 0x0f, 0x53, 0x46, 0x19, 0xfa, + 0x9a, 0x7b, 0x94, 0x3b, 0xf2, 0x32, 0xa7, 0x63, 0x6c, 0x1a, 0x8c, 0x5d, + 0x8b, 0x5f, 0x05, 0xb9, 0x68, 0x0f, 0x32, 0x12, 0xab, 0xc6, 0x2e, 0xe5, + 0xae, 0x39, 0x89, 0xf7, 0x3e, 0xa5, 0x4f, 0xe2, 0xd9, 0x48, 0x29, 0x77, + 0x4b, 0x7c, 0x5b, 0xb3, 0x6d, 0xc9, 0x01, 0xb2, 0xf7, 0x71, 0x3b, 0xf1, + 0x1e, 0x18, 0x5f, 0xce, 0xef, 0x84, 0x18, 0x83, 0x6d, 0x65, 0x0e, 0xfa, + 0x69, 0x84, 0xb6, 0x73, 0xa0, 0x5d, 0xff, 0xb2, 0x99, 0x0e, 0x0c, 0x30, + 0xa6, 0xfa, 0x70, 0xd4, 0x08, 0x99, 0x97, 0x2d, 0x1c, 0x53, 0xca, 0xf1, + 0x5b, 0x58, 0xeb, 0x56, 0xc1, 0xa3, 0x49, 0x7d, 0xf7, 0x21, 0x56, 0xe3, + 0x41, 0x85, 0x26, 0xb5, 0x27, 0xd3, 0xba, 0x78, 0x42, 0x91, 0x3e, 0xa5, + 0x18, 0xeb, 0x5b, 0xf0, 0x00, 0x73, 0xc2, 0xbe, 0xf8, 0xbd, 0xb8, 0x3f, + 0x50, 0x01, 0x3f, 0xf5, 0xf4, 0x50, 0xc0, 0xc7, 0x5c, 0xfb, 0x7b, 0x45, + 0x3a, 0x7f, 0x51, 0x56, 0xec, 0xbf, 0xaf, 0x61, 0xb0, 0x5a, 0xc6, 0xd8, + 0xe6, 0x19, 0x99, 0x27, 0xa5, 0x5a, 0x43, 0x33, 0x1a, 0xfc, 0xec, 0x7b, + 0xb7, 0xc4, 0xd5, 0xd4, 0x16, 0x67, 0x44, 0x7a, 0x9a, 0x8c, 0x9f, 0xf8, + 0x2f, 0x17, 0x8d, 0xf6, 0x36, 0x89, 0x8e, 0xb5, 0x10, 0x3a, 0xa9, 0xa7, + 0xee, 0x5c, 0x90, 0x31, 0xe4, 0x28, 0x17, 0x2c, 0x95, 0xcc, 0x5d, 0xa7, + 0x15, 0x22, 0xad, 0xd0, 0x8c, 0xe0, 0xba, 0x14, 0x71, 0x9d, 0xc6, 0x38, + 0x34, 0xcd, 0xcd, 0xc4, 0x73, 0xbe, 0x53, 0x32, 0x97, 0x8a, 0x4c, 0x10, + 0x03, 0x37, 0x11, 0x1f, 0xf7, 0xd1, 0xab, 0xcd, 0x5b, 0xea, 0xa3, 0x7a, + 0x9b, 0x82, 0xc7, 0xe6, 0x9b, 0xe1, 0x71, 0x92, 0xe6, 0x3b, 0xb9, 0x00, + 0x2e, 0xe7, 0x42, 0x78, 0x9b, 0xb4, 0x2f, 0x59, 0xb4, 0xeb, 0xf0, 0xb3, + 0x62, 0x0e, 0x8b, 0x33, 0x87, 0x6d, 0xcd, 0x2a, 0xf4, 0xd7, 0x30, 0x46, + 0xf4, 0xbf, 0xfa, 0xec, 0xd2, 0xcd, 0x1e, 0xea, 0x4d, 0x64, 0x71, 0xf1, + 0x73, 0x1c, 0x0f, 0x59, 0x39, 0xfb, 0xb5, 0xcf, 0x66, 0x6b, 0x68, 0x2b, + 0xea, 0xbe, 0xba, 0xf8, 0xde, 0xba, 0xd9, 0x3f, 0x2f, 0xca, 0xdb, 0x53, + 0xb4, 0x35, 0x71, 0x9b, 0x71, 0x9e, 0xd7, 0x04, 0x47, 0x69, 0x70, 0x9c, + 0x8a, 0xa1, 0xec, 0xd4, 0x35, 0xfe, 0x35, 0x89, 0x19, 0x56, 0xde, 0xc7, + 0xbe, 0x4b, 0x9e, 0x1e, 0x21, 0x5e, 0x34, 0xc9, 0xd3, 0x55, 0x8b, 0x97, + 0x20, 0x79, 0xf9, 0xe4, 0xb3, 0x12, 0xb6, 0x0c, 0x5d, 0x7b, 0x27, 0x40, + 0x7d, 0xe0, 0xd1, 0x10, 0xf5, 0x79, 0x65, 0xa3, 0x3c, 0xe7, 0xc3, 0x1d, + 0xb9, 0x44, 0xb9, 0xe4, 0x79, 0xaf, 0xb6, 0x05, 0x7b, 0xe7, 0x3e, 0xaf, + 0xf7, 0x20, 0x6d, 0x11, 0xa0, 0xf1, 0xe4, 0xde, 0x17, 0xd5, 0xd4, 0x3f, + 0x42, 0x8a, 0x3d, 0xd3, 0x23, 0xd9, 0x34, 0x1e, 0xca, 0x7e, 0xcb, 0xda, + 0xcb, 0x5b, 0xb7, 0x01, 0xfb, 0x49, 0xff, 0x60, 0x35, 0xe3, 0xe8, 0x7f, + 0xc4, 0xa3, 0x82, 0xa5, 0x76, 0x55, 0x42, 0xea, 0x6e, 0xb4, 0xe5, 0x36, + 0xc5, 0x44, 0x59, 0x1c, 0xc3, 0xed, 0xcd, 0xd1, 0xd8, 0x65, 0x3c, 0x66, + 0xca, 0x5c, 0xdc, 0x59, 0xac, 0xc1, 0xc4, 0xaf, 0x4a, 0x3b, 0xeb, 0x70, + 0x5b, 0x11, 0x53, 0x6d, 0xcd, 0xbf, 0xf5, 0xb9, 0xd9, 0x83, 0xf4, 0xed, + 0x52, 0x7b, 0xbc, 0x4a, 0x1b, 0xd7, 0x39, 0xca, 0x9c, 0xfd, 0xbc, 0xfe, + 0x52, 0x88, 0x95, 0x19, 0xae, 0xf5, 0x0a, 0x0e, 0x11, 0x3f, 0xa5, 0x83, + 0x26, 0x76, 0xf1, 0xf3, 0x00, 0x71, 0xd6, 0xbb, 0x7a, 0x15, 0x66, 0x03, + 0x01, 0x62, 0x4b, 0xe6, 0x60, 0xc7, 0xdf, 0x49, 0x4d, 0x88, 0x85, 0x1d, + 0xb2, 0x57, 0xff, 0x6f, 0xed, 0xdf, 0xac, 0x27, 0x96, 0x11, 0xd9, 0xbd, + 0x0a, 0x73, 0x68, 0x0c, 0xc4, 0x37, 0x7b, 0xf5, 0x42, 0xd8, 0x81, 0xe4, + 0x55, 0x07, 0xd4, 0xd3, 0xef, 0xb0, 0x1f, 0x7c, 0xa4, 0x5e, 0x3d, 0xdd, + 0xea, 0xd4, 0x90, 0x9a, 0xf2, 0xe0, 0xe1, 0xa9, 0x0e, 0x54, 0x5b, 0x73, + 0xa4, 0x71, 0xda, 0xcc, 0xc1, 0x3e, 0x6c, 0xf4, 0x53, 0x17, 0xfb, 0xb1, + 0xab, 0x1b, 0x1e, 0x45, 0x8b, 0x75, 0x7d, 0x0c, 0xfb, 0xb3, 0x5e, 0xa5, + 0x3b, 0xeb, 0x42, 0xc7, 0x5d, 0x8f, 0xc2, 0xbd, 0x7e, 0x80, 0x7c, 0xc9, + 0x75, 0xf9, 0xfb, 0x6e, 0xf6, 0x71, 0xc2, 0x5f, 0x19, 0xc2, 0xab, 0xc8, + 0xdb, 0x7a, 0x0d, 0x23, 0x53, 0x2e, 0x65, 0xb7, 0xf1, 0x37, 0xe6, 0x55, + 0x6b, 0x6f, 0x48, 0xae, 0x55, 0xc8, 0x99, 0x01, 0x3e, 0x23, 0x39, 0x67, + 0x10, 0x59, 0xc6, 0xf6, 0xdd, 0xd6, 0xfb, 0xa7, 0xca, 0x6c, 0x99, 0x92, + 0xec, 0x6f, 0xdb, 0xe9, 0x1f, 0xf2, 0x4c, 0x5b, 0xf1, 0xda, 0x76, 0x8f, + 0x7d, 0x2e, 0x41, 0xec, 0x3e, 0x88, 0x5b, 0x69, 0x84, 0xfa, 0xa8, 0xf8, + 0xd8, 0x20, 0xea, 0x73, 0x4c, 0xa8, 0xab, 0x6c, 0x7e, 0x1f, 0x34, 0x0a, + 0xec, 0x4d, 0x35, 0xe6, 0x4d, 0xea, 0x6e, 0xa5, 0xbc, 0x4f, 0x47, 0xfd, + 0xb5, 0xf7, 0x4b, 0xf5, 0x54, 0x70, 0xe9, 0x17, 0xdd, 0xff, 0x4d, 0xc8, + 0x3d, 0x97, 0xf6, 0x87, 0x8c, 0xe3, 0x68, 0x6f, 0xa5, 0x43, 0xfc, 0xe7, + 0x0f, 0x71, 0xff, 0x1c, 0x1b, 0xd7, 0x0a, 0xa1, 0x4f, 0xdc, 0x6b, 0xb8, + 0x94, 0x2e, 0xe6, 0x9f, 0x03, 0x53, 0x8e, 0x3b, 0xca, 0xf0, 0xe7, 0x66, + 0xf9, 0xca, 0x11, 0xd4, 0xc7, 0xc7, 0xf8, 0xbc, 0x82, 0x76, 0x62, 0xc8, + 0x27, 0xf4, 0xad, 0xe8, 0xa8, 0x91, 0x1c, 0xf0, 0xbc, 0x39, 0xd8, 0x27, + 0x3a, 0x54, 0xb0, 0x8d, 0xd7, 0x5f, 0xa0, 0x7d, 0x9f, 0xd6, 0x5d, 0xa8, + 0x5f, 0x21, 0x33, 0x41, 0x75, 0x3a, 0x89, 0x3d, 0x1e, 0x7b, 0x8f, 0x2c, + 0x6d, 0x56, 0x6b, 0xda, 0xf0, 0x9d, 0x8e, 0xfa, 0xe9, 0x37, 0xe9, 0x4f, + 0x6d, 0xeb, 0x6f, 0xbc, 0x57, 0xd2, 0x89, 0x8e, 0xd0, 0xfa, 0xe7, 0x4c, + 0xdc, 0x34, 0x8a, 0xc0, 0xfa, 0x1b, 0xed, 0x5f, 0xe2, 0xfb, 0x30, 0x63, + 0x10, 0xe9, 0xea, 0x84, 0xcc, 0x89, 0xa2, 0xa4, 0x73, 0x18, 0xbf, 0x9f, + 0x1f, 0xc3, 0xa1, 0xac, 0xc8, 0xb9, 0x60, 0xf9, 0xb6, 0xb6, 0xfe, 0xba, + 0x6c, 0x0f, 0x66, 0xa3, 0x03, 0x55, 0x45, 0xd9, 0x0e, 0xb2, 0x1f, 0xa9, + 0x64, 0x8e, 0x7d, 0x80, 0x3a, 0x1d, 0xb6, 0x74, 0xda, 0x07, 0x3d, 0x77, + 0x9d, 0xee, 0x10, 0xe9, 0x7a, 0x13, 0xa2, 0x37, 0xd9, 0x97, 0x63, 0x2f, + 0x40, 0xba, 0xfb, 0x6e, 0xa0, 0x3b, 0xa8, 0x5f, 0xa7, 0xbb, 0x37, 0x1b, + 0x3d, 0xed, 0x28, 0xd2, 0xfd, 0xc6, 0x5c, 0x89, 0x46, 0x1a, 0x3b, 0xd7, + 0xa7, 0x91, 0xdb, 0x7c, 0xd0, 0x3c, 0x68, 0xe9, 0xe3, 0xfb, 0xd6, 0xf5, + 0x6d, 0xf5, 0x12, 0x0f, 0xfc, 0x33, 0xa1, 0x59, 0x67, 0x00, 0x6c, 0x1c, + 0x76, 0x63, 0x7c, 0xa8, 0x6f, 0x75, 0x3b, 0x93, 0x8c, 0xe3, 0xa0, 0x67, + 0xfb, 0xe7, 0x66, 0x1f, 0x1d, 0xec, 0xd7, 0x3a, 0x8d, 0x1e, 0x6f, 0x97, + 0xe1, 0x21, 0x06, 0xab, 0x54, 0xb6, 0x65, 0x65, 0x06, 0x22, 0xb1, 0x5c, + 0xc4, 0xc5, 0x79, 0xe9, 0x0b, 0xef, 0x61, 0xcf, 0xb0, 0x81, 0xf6, 0x1d, + 0xc0, 0x44, 0x7e, 0x40, 0x49, 0x06, 0xb9, 0x8e, 0x21, 0x75, 0x05, 0xac, + 0x79, 0xbd, 0xa8, 0xa4, 0x2f, 0x05, 0x13, 0xd3, 0x89, 0x93, 0xf5, 0x26, + 0x88, 0x51, 0x3c, 0x2b, 0x12, 0xb3, 0x89, 0x5d, 0xf5, 0x4e, 0x1c, 0xb7, + 0xb0, 0x98, 0x3a, 0xcb, 0xdf, 0x69, 0x89, 0x99, 0x3b, 0xb3, 0x52, 0xc7, + 0x08, 0x27, 0xb5, 0x11, 0xfc, 0x63, 0xbc, 0x30, 0x5c, 0x83, 0xe4, 0x7d, + 0x35, 0x90, 0x1e, 0x63, 0x02, 0x7f, 0xa9, 0x85, 0x3c, 0xfd, 0x79, 0x97, + 0xd2, 0x6d, 0xcc, 0x7b, 0x77, 0x18, 0x7e, 0xf8, 0xd8, 0xbf, 0xf5, 0x38, + 0x23, 0xec, 0x39, 0xac, 0x19, 0x7d, 0xeb, 0xad, 0xb9, 0x7e, 0x6f, 0xbb, + 0x61, 0xe7, 0xc2, 0x5b, 0x66, 0x3d, 0xde, 0x8e, 0x99, 0x48, 0x68, 0xc2, + 0xc2, 0x62, 0x07, 0x5b, 0x23, 0x39, 0xd3, 0x7c, 0x55, 0x2f, 0x5c, 0x2d, + 0xb7, 0xbe, 0x4f, 0xb7, 0xc6, 0x72, 0x4d, 0xd8, 0x43, 0xfc, 0xd4, 0x36, + 0xd3, 0x04, 0x7d, 0x06, 0x38, 0x31, 0x15, 0xc2, 0xba, 0xac, 0x7a, 0x3a, + 0xe5, 0xec, 0xc7, 0xf4, 0x42, 0x17, 0xb2, 0x79, 0xef, 0x72, 0xd8, 0x41, + 0x8c, 0x1d, 0x77, 0xe0, 0x0e, 0x7d, 0x83, 0x52, 0xb0, 0x62, 0x5a, 0xc1, + 0xdd, 0xfa, 0x2e, 0x65, 0xc0, 0xc2, 0x14, 0xf3, 0xc4, 0x22, 0x0a, 0x6e, + 0xb2, 0x72, 0xef, 0xc9, 0xd6, 0x38, 0xf1, 0xf7, 0x1d, 0x59, 0xa9, 0xef, + 0x26, 0x2e, 0xc6, 0xa9, 0x97, 0x78, 0xba, 0xdf, 0xcd, 0x7e, 0xe8, 0xa0, + 0xa2, 0xf6, 0xea, 0x8a, 0x8d, 0xf1, 0x6e, 0x9b, 0xb7, 0x71, 0xe1, 0xad, + 0xf3, 0xcd, 0x5e, 0xc9, 0x41, 0xed, 0xba, 0x1a, 0x72, 0x39, 0x02, 0x18, + 0xb6, 0x68, 0xa4, 0x5b, 0xf5, 0xf9, 0x32, 0xac, 0xd6, 0xfa, 0x70, 0xda, + 0x92, 0x61, 0xa2, 0x75, 0x0b, 0xb1, 0xf6, 0x93, 0x46, 0x3f, 0x7b, 0x65, + 0xd9, 0x37, 0x8d, 0xc4, 0x5a, 0x9c, 0x6d, 0xc4, 0xb3, 0x91, 0xf0, 0xb2, + 0x92, 0x54, 0xd2, 0xae, 0xc6, 0xe4, 0x3c, 0x58, 0x51, 0x6a, 0xec, 0xfa, + 0x26, 0x32, 0x46, 0x89, 0xb3, 0xda, 0xa6, 0xbc, 0xcb, 0x49, 0xd8, 0x73, + 0x9e, 0x4e, 0xfd, 0xff, 0xe0, 0x52, 0x50, 0x9d, 0x48, 0x92, 0xef, 0x0e, + 0xe6, 0xdd, 0x42, 0x9f, 0x8b, 0xf7, 0x65, 0xbe, 0x37, 0xdc, 0x3a, 0x9e, + 0x41, 0xc1, 0x99, 0x90, 0x1e, 0x0b, 0xfe, 0xde, 0x3c, 0x64, 0xd6, 0xc4, + 0x3e, 0xe3, 0x53, 0xb3, 0xb4, 0xc7, 0xd4, 0x33, 0x63, 0xef, 0x9f, 0x65, + 0x16, 0x5c, 0xfe, 0x1d, 0x46, 0x33, 0x8e, 0xe7, 0x5d, 0x37, 0xd0, 0x8e, + 0x4e, 0xdc, 0xe2, 0x70, 0x20, 0xba, 0xfe, 0x6e, 0xa5, 0xb8, 0x07, 0xc5, + 0x3c, 0x91, 0xb2, 0x6a, 0x62, 0x19, 0xe5, 0xbc, 0x70, 0x52, 0xd6, 0xf8, + 0x56, 0xeb, 0xf8, 0x49, 0xa9, 0x91, 0xc3, 0xad, 0x21, 0x43, 0xed, 0x95, + 0x9e, 0xb0, 0x9a, 0x7a, 0xfa, 0x68, 0x52, 0x6a, 0xf0, 0x14, 0x6b, 0xb0, + 0xba, 0xdc, 0xae, 0x48, 0x1d, 0x53, 0x63, 0x5e, 0xa7, 0x03, 0x57, 0x1a, + 0xd4, 0xfe, 0x1f, 0x40, 0x1d, 0xb0, 0xe7, 0x8a, 0x8f, 0xb6, 0x36, 0x16, + 0xf1, 0xf0, 0x6d, 0xf3, 0x83, 0x72, 0xee, 0xc4, 0xd2, 0x71, 0x53, 0x4e, + 0xb0, 0xb1, 0x69, 0xbe, 0x1c, 0xef, 0x21, 0x6e, 0x10, 0x6c, 0x2c, 0xd7, + 0x27, 0x5b, 0x1b, 0x66, 0x3d, 0xe4, 0x4d, 0xc1, 0x7b, 0x5a, 0x0f, 0x7d, + 0xaf, 0xc4, 0xa3, 0x8d, 0x9b, 0xb7, 0x13, 0x37, 0x3b, 0x13, 0x6a, 0xcb, + 0x56, 0xe2, 0x66, 0x8d, 0xfd, 0x84, 0x0b, 0x7d, 0x78, 0xc2, 0xb0, 0x7b, + 0x0a, 0xc1, 0xce, 0xe6, 0x49, 0x35, 0x29, 0xb8, 0xf9, 0xea, 0x06, 0x60, + 0x37, 0x71, 0xf3, 0x72, 0xc6, 0x85, 0x7e, 0xe2, 0xe6, 0x8f, 0x98, 0x82, + 0xee, 0x24, 0x6e, 0xbe, 0x42, 0x8c, 0x75, 0x3e, 0xfe, 0x73, 0x7c, 0xa3, + 0x38, 0x3b, 0xdb, 0x4b, 0xec, 0x9c, 0x0c, 0xde, 0x88, 0x9d, 0xff, 0xe2, + 0x5f, 0x60, 0xe7, 0x3d, 0xc4, 0x84, 0x3d, 0x59, 0xd9, 0x67, 0x1a, 0x6d, + 0x7d, 0xe3, 0x94, 0x9c, 0x6d, 0xb9, 0x0d, 0xef, 0x9e, 0x1c, 0x1d, 0x22, + 0x56, 0xc6, 0x58, 0xbc, 0x1f, 0x99, 0x19, 0xac, 0x22, 0x2e, 0x78, 0xd9, + 0xc9, 0x75, 0xd7, 0xc5, 0x55, 0xfd, 0x4d, 0x25, 0xda, 0xd5, 0x8f, 0x28, + 0xfb, 0x66, 0x75, 0x99, 0x26, 0x4c, 0xba, 0x12, 0xc4, 0xc6, 0xac, 0x81, + 0xab, 0x89, 0x9d, 0xab, 0x16, 0x81, 0xda, 0x45, 0x1b, 0x3b, 0xcb, 0xdc, + 0xac, 0x2a, 0x8a, 0x3f, 0x22, 0x76, 0x66, 0xaf, 0xcb, 0x50, 0x5b, 0x6c, + 0x62, 0x8c, 0x2a, 0x38, 0x1a, 0xf5, 0xa1, 0x67, 0x8a, 0xb8, 0xc7, 0x9a, + 0x9b, 0x99, 0x23, 0x3f, 0xd6, 0xfb, 0x71, 0x6c, 0xc1, 0x9e, 0x9b, 0x75, + 0x12, 0xbf, 0xb9, 0xa2, 0x41, 0x94, 0x2f, 0xba, 0xf0, 0x1c, 0xf1, 0xf3, + 0x36, 0xda, 0xf9, 0x0c, 0xf1, 0xf3, 0x9e, 0x1b, 0x66, 0x67, 0xb3, 0x8b, + 0x78, 0x95, 0x58, 0xbe, 0xae, 0x16, 0x51, 0x99, 0x8b, 0x98, 0x57, 0x36, + 0xfa, 0x70, 0xce, 0xc2, 0xcf, 0xde, 0xe5, 0xb4, 0x62, 0xcb, 0x56, 0x46, + 0x5b, 0x88, 0x5d, 0x1d, 0xb4, 0x6b, 0xdb, 0x49, 0xb5, 0xeb, 0x25, 0xea, + 0xa2, 0x31, 0x7a, 0xde, 0xb2, 0xc7, 0x60, 0x5c, 0x66, 0x2c, 0x43, 0xad, + 0x72, 0xfe, 0xaa, 0x82, 0xf6, 0xee, 0x9e, 0x8c, 0x24, 0x3f, 0x80, 0x1d, + 0x93, 0xb1, 0x5c, 0x59, 0xb1, 0x1e, 0xca, 0xbd, 0x09, 0xde, 0x4b, 0xa2, + 0x6b, 0xa3, 0xed, 0xdf, 0xb1, 0xdc, 0x71, 0x62, 0x57, 0xd9, 0x5b, 0x0d, + 0xf8, 0x3b, 0x8d, 0x2e, 0x4c, 0x1b, 0x61, 0x94, 0x9f, 0x2b, 0xee, 0xd1, + 0x9e, 0x93, 0x33, 0x7b, 0x8f, 0xb6, 0x06, 0xbe, 0x53, 0xc2, 0x84, 0x49, + 0xe2, 0xbb, 0xa0, 0xe7, 0x8e, 0xbc, 0xe0, 0xc5, 0x5e, 0x1c, 0x33, 0xd4, + 0xd0, 0x4f, 0x18, 0x13, 0xf7, 0xc9, 0xfe, 0xfc, 0x0d, 0x33, 0xaa, 0x87, + 0x79, 0xcf, 0xf8, 0xdc, 0x8c, 0x2a, 0x95, 0xc5, 0xaf, 0x9c, 0xcd, 0xe5, + 0x70, 0xac, 0x93, 0x19, 0x89, 0x1a, 0x1a, 0xc3, 0x63, 0xc4, 0x1c, 0xbf, + 0x54, 0x7c, 0x9a, 0x6b, 0xa8, 0xc9, 0xa9, 0x86, 0xe6, 0x15, 0x1f, 0xdf, + 0xbd, 0x87, 0xf9, 0xed, 0x1e, 0xfa, 0x46, 0x64, 0xb9, 0x42, 0x71, 0xe2, + 0xd2, 0x97, 0x2d, 0x3c, 0xea, 0xed, 0xe5, 0xb5, 0xe9, 0x7c, 0x09, 0xd7, + 0xf4, 0x09, 0xaf, 0xe8, 0x9c, 0xb2, 0x73, 0x88, 0x96, 0xf3, 0x2e, 0x5f, + 0x82, 0x2d, 0x5b, 0x25, 0x65, 0x7d, 0x60, 0x32, 0x60, 0x0e, 0xac, 0x94, + 0x18, 0xd6, 0xb0, 0xd3, 0x10, 0xff, 0x1a, 0x24, 0x9f, 0x7d, 0x38, 0x62, + 0xac, 0x66, 0xef, 0x26, 0xf3, 0xd2, 0x26, 0x62, 0xeb, 0x5e, 0xd6, 0x60, + 0xd3, 0x4c, 0xe9, 0x69, 0xb3, 0x69, 0x93, 0xa6, 0xe7, 0x94, 0x42, 0x4d, + 0x88, 0xf8, 0x66, 0x3d, 0x6b, 0x77, 0x5b, 0xbe, 0x09, 0x6f, 0x9e, 0xd1, + 0xe8, 0x9b, 0xed, 0xc4, 0xef, 0xbd, 0xb8, 0x97, 0xf2, 0x7c, 0x23, 0xff, + 0x4d, 0x24, 0xbf, 0xee, 0xc2, 0xc4, 0x54, 0x12, 0x5b, 0xd6, 0x8f, 0xe0, + 0xd2, 0xef, 0x78, 0x98, 0xab, 0x7c, 0x78, 0x72, 0x4a, 0xf2, 0x6b, 0x09, + 0x6f, 0xdf, 0x88, 0x45, 0x3c, 0x08, 0x5b, 0x38, 0xe4, 0x8b, 0xef, 0xd9, + 0x18, 0xc5, 0xcb, 0x5e, 0xb8, 0xf4, 0x3e, 0xf3, 0xd0, 0xfa, 0x7f, 0x81, + 0x67, 0x88, 0x5b, 0x88, 0x05, 0x2a, 0x62, 0xd6, 0xf9, 0xb8, 0x12, 0xde, + 0x75, 0xd1, 0x07, 0x24, 0xa6, 0x57, 0x33, 0xd6, 0x4d, 0x62, 0xe7, 0xe5, + 0xe2, 0xfc, 0xf2, 0xed, 0x93, 0xea, 0xd2, 0x11, 0x44, 0x88, 0xa1, 0x31, + 0x28, 0xd8, 0xcd, 0x49, 0xbc, 0x7b, 0x25, 0x1a, 0xd5, 0xcf, 0x11, 0xef, + 0x8e, 0xd2, 0xd6, 0x2e, 0x4d, 0x7c, 0x33, 0x80, 0xb2, 0xc5, 0x10, 0x7d, + 0x52, 0xe6, 0x97, 0x7f, 0xe5, 0xb5, 0xe7, 0x97, 0x32, 0x33, 0x97, 0xf3, + 0x23, 0xe8, 0x28, 0x63, 0xef, 0x56, 0xae, 0xa4, 0x99, 0x93, 0x67, 0xbd, + 0xbb, 0x99, 0xdf, 0xfb, 0x8d, 0xa0, 0x7f, 0x77, 0x3e, 0xc0, 0xdf, 0x3a, + 0x7f, 0x7f, 0x7e, 0x07, 0x9f, 0x0f, 0xf1, 0x33, 0x8c, 0x6c, 0x2e, 0x52, + 0x21, 0xcd, 0x40, 0x36, 0x67, 0xe7, 0xbc, 0x70, 0xee, 0x90, 0x57, 0xb0, + 0x66, 0xdb, 0x94, 0xfd, 0x5d, 0xbb, 0xe1, 0xfb, 0xe7, 0x31, 0xbf, 0x9b, + 0x7c, 0x9f, 0x39, 0xa9, 0xe1, 0xa3, 0x93, 0x16, 0xe6, 0x2f, 0x10, 0xf3, + 0x0f, 0xbb, 0x9d, 0x82, 0x35, 0x7f, 0x61, 0x9e, 0x8f, 0x46, 0x07, 0xe6, + 0xe8, 0x07, 0x3d, 0xa4, 0xeb, 0xd0, 0x82, 0x16, 0xbf, 0x36, 0x9f, 0xf6, + 0xcc, 0xf7, 0xf2, 0xc9, 0x18, 0xde, 0xb9, 0x3e, 0x63, 0xfd, 0xa4, 0xcc, + 0x9a, 0x15, 0xe3, 0xb1, 0x77, 0x37, 0xc1, 0xd3, 0xc2, 0x7e, 0xd3, 0xcd, + 0xe7, 0x43, 0xd6, 0xf3, 0x32, 0xf3, 0xbd, 0x8e, 0x9d, 0x3f, 0xba, 0xfe, + 0xce, 0x61, 0x76, 0x6a, 0x9e, 0xf3, 0x8c, 0x2d, 0xa7, 0xf5, 0x9c, 0xcc, + 0x65, 0xbd, 0xcb, 0xb0, 0xe2, 0x6b, 0x88, 0x32, 0x89, 0x7d, 0x0f, 0x99, + 0xb6, 0xdf, 0x06, 0xfd, 0x3b, 0x19, 0x0f, 0xdf, 0xa6, 0x7d, 0x76, 0x9e, + 0xab, 0xf3, 0xdf, 0x6d, 0xec, 0xb2, 0x64, 0xbe, 0xfb, 0x9c, 0xd4, 0x24, + 0xb9, 0xff, 0x40, 0x85, 0x60, 0xef, 0x27, 0x59, 0xb3, 0x46, 0x0d, 0xd9, + 0x03, 0x80, 0xe2, 0x4a, 0x1c, 0x41, 0xe7, 0x74, 0x18, 0x6f, 0xeb, 0xde, + 0xe2, 0x59, 0x17, 0x89, 0xc9, 0x69, 0xc6, 0x64, 0x10, 0x63, 0x46, 0x24, + 0xfc, 0x36, 0xf1, 0x69, 0x9a, 0x0c, 0x1f, 0xcb, 0x3a, 0xf1, 0x36, 0x31, + 0x23, 0x14, 0xfb, 0xac, 0xa8, 0xfd, 0x6e, 0xe9, 0xef, 0x4a, 0x84, 0x6b, + 0x22, 0x2d, 0x07, 0x50, 0x87, 0x0c, 0x73, 0xbe, 0x57, 0xfb, 0x21, 0x8e, + 0x9f, 0x70, 0xe0, 0x7e, 0xf6, 0x7d, 0xc9, 0xbb, 0x74, 0x7e, 0x6f, 0x1c, + 0x7a, 0x1f, 0xff, 0x68, 0xce, 0xca, 0x79, 0x2c, 0x45, 0xce, 0x7c, 0x7c, + 0x62, 0xd6, 0x6a, 0x5a, 0xe1, 0x07, 0xd0, 0x52, 0x57, 0xd1, 0x38, 0xbc, + 0x8c, 0x0f, 0xcc, 0x02, 0xef, 0xbd, 0xc7, 0xf8, 0x79, 0x49, 0x8f, 0x84, + 0x1c, 0x14, 0xa6, 0x10, 0x74, 0xe2, 0x3e, 0x5d, 0xe6, 0x29, 0xea, 0xf0, + 0xb3, 0x50, 0x87, 0x2e, 0x28, 0x72, 0x86, 0xe7, 0x92, 0x99, 0xae, 0x91, + 0x75, 0x15, 0xac, 0x5b, 0xd3, 0xd8, 0x55, 0x06, 0xb5, 0xc5, 0xad, 0x68, + 0xfa, 0xfb, 0xca, 0xff, 0x32, 0x0b, 0xc1, 0x4f, 0xcc, 0x77, 0xb4, 0x12, + 0x5d, 0x35, 0xec, 0x71, 0x96, 0x78, 0xab, 0xc3, 0x71, 0x43, 0xf6, 0xf1, + 0x7e, 0x88, 0xfb, 0x4f, 0xb8, 0xd0, 0x1e, 0xff, 0xb9, 0x99, 0x0e, 0x0a, + 0xcd, 0x50, 0x25, 0x2a, 0x84, 0xbe, 0x3d, 0xdb, 0x7e, 0x31, 0x0f, 0xa5, + 0xc3, 0x10, 0xbc, 0x2c, 0x7e, 0x3a, 0x0d, 0xd3, 0x90, 0x99, 0xa2, 0x89, + 0x3b, 0xe3, 0x23, 0x78, 0x2f, 0x9e, 0xfc, 0x4f, 0x1e, 0xa8, 0x4b, 0x97, + 0x9d, 0x6a, 0xa1, 0xc9, 0x19, 0x56, 0xbc, 0x0d, 0xda, 0x70, 0x83, 0x55, + 0x6f, 0x2e, 0xb2, 0x77, 0xf2, 0x31, 0xb7, 0x48, 0x8f, 0x39, 0x8d, 0xc5, + 0xc9, 0x34, 0x5c, 0xc4, 0x76, 0xa3, 0xcd, 0x6a, 0xff, 0x33, 0x8a, 0x1a, + 0x3a, 0xa8, 0x84, 0x95, 0x7b, 0xb5, 0x14, 0x9e, 0xd3, 0xa3, 0xc9, 0x36, + 0xa5, 0xce, 0xd3, 0x95, 0x2f, 0xd1, 0x6e, 0x27, 0x56, 0x51, 0x0b, 0x97, + 0x9d, 0xe5, 0xa8, 0xdd, 0xa0, 0x75, 0x95, 0x3b, 0xd5, 0xd4, 0xd7, 0x18, + 0x5f, 0xdb, 0xf3, 0x05, 0xef, 0xfb, 0x51, 0x07, 0xd6, 0x5a, 0xfb, 0x0d, + 0x99, 0xe2, 0xbc, 0x74, 0x1a, 0xdd, 0x93, 0xe6, 0x96, 0x8b, 0x71, 0x35, + 0xf4, 0x8c, 0x92, 0xde, 0xed, 0x23, 0xa6, 0x79, 0x00, 0x5a, 0x78, 0x81, + 0x75, 0xaa, 0x3d, 0xef, 0xc0, 0x2d, 0xa7, 0x84, 0x66, 0x86, 0x34, 0x8f, + 0xa0, 0xfc, 0x84, 0xb9, 0x65, 0xb7, 0xae, 0xa6, 0x2e, 0x3b, 0xd3, 0xff, + 0xbd, 0x96, 0x7a, 0xeb, 0x50, 0x64, 0xbf, 0x6d, 0x84, 0xb8, 0x62, 0x44, + 0xce, 0xcd, 0xc5, 0xfe, 0x98, 0x98, 0xe2, 0x5b, 0xf4, 0x55, 0x67, 0xc2, + 0x4f, 0x3e, 0xd5, 0xd8, 0x1c, 0x64, 0xce, 0x1e, 0xc6, 0x65, 0x3d, 0xed, + 0xed, 0x6c, 0x88, 0x11, 0x9b, 0x85, 0x58, 0x07, 0xc3, 0x38, 0x46, 0x8c, + 0x77, 0x24, 0x5f, 0x86, 0x42, 0x40, 0x23, 0x36, 0xeb, 0x85, 0x63, 0xd2, + 0xa7, 0xcc, 0x67, 0x22, 0x7a, 0x3b, 0xfe, 0x33, 0x0a, 0x21, 0x71, 0x91, + 0x23, 0xf0, 0x9d, 0xf8, 0x7b, 0xb3, 0x4a, 0xd3, 0x5a, 0x26, 0x15, 0xae, + 0xfb, 0x54, 0x88, 0x3a, 0xe6, 0x7b, 0x72, 0xbe, 0xc5, 0xe8, 0xc1, 0xbd, + 0x93, 0x41, 0xbe, 0x5f, 0x85, 0x75, 0x27, 0xc2, 0xb8, 0x12, 0xbf, 0x19, + 0x85, 0x1a, 0x1b, 0x03, 0x79, 0x35, 0xfa, 0x11, 0xfb, 0xac, 0x34, 0x7b, + 0x4a, 0xd9, 0x63, 0x3a, 0x62, 0x48, 0x7f, 0xee, 0xe2, 0x77, 0x1f, 0x7f, + 0x45, 0x9f, 0xdf, 0x2a, 0x62, 0x9d, 0xa9, 0xd6, 0xf0, 0xfc, 0xcf, 0x2b, + 0xec, 0x79, 0x5a, 0x98, 0xcf, 0x05, 0xac, 0x19, 0xe1, 0x28, 0x69, 0x9e, + 0x9d, 0x96, 0xbe, 0xad, 0x6d, 0xb3, 0xa7, 0xb8, 0x4f, 0xff, 0x53, 0xdd, + 0x81, 0x2d, 0xec, 0xed, 0x43, 0x9a, 0xd4, 0xcb, 0x51, 0xb5, 0x16, 0x9b, + 0x71, 0x3a, 0xc0, 0x26, 0x5c, 0xfb, 0x0f, 0x98, 0x08, 0xc4, 0x98, 0xf3, + 0x35, 0xbc, 0x9b, 0xf9, 0x32, 0xfb, 0x9d, 0x3a, 0x39, 0xe3, 0x83, 0x5b, + 0x4e, 0xb8, 0xb9, 0xe6, 0x16, 0xe2, 0x9a, 0x4e, 0xbc, 0x16, 0xb0, 0x7b, + 0x8d, 0xa3, 0xbc, 0x3e, 0x3e, 0xe7, 0x23, 0x16, 0xf5, 0xf0, 0xf7, 0x46, + 0xde, 0xbe, 0x88, 0x27, 0x91, 0xe5, 0xdf, 0xe2, 0xc9, 0x43, 0x3c, 0xa0, + 0xe1, 0x6a, 0xe6, 0x65, 0x5c, 0x21, 0xed, 0xf4, 0x9c, 0x4d, 0x73, 0x2a, + 0x2f, 0x74, 0x65, 0xbd, 0x48, 0xaa, 0xd6, 0x29, 0xf4, 0x7d, 0x72, 0xde, + 0xf7, 0xdf, 0xb9, 0x06, 0x91, 0xdd, 0x09, 0xf6, 0xc7, 0x7a, 0x03, 0xda, + 0x03, 0xb4, 0x97, 0x21, 0x6b, 0xa8, 0xec, 0x45, 0xe5, 0xdd, 0x10, 0xd6, + 0x4e, 0x9a, 0x23, 0xa1, 0x84, 0x5c, 0x37, 0xcd, 0xea, 0x4d, 0x5a, 0xe8, + 0x4d, 0xc5, 0xc5, 0x5a, 0xe7, 0xa2, 0x0e, 0xc6, 0x71, 0x36, 0xd3, 0xb8, + 0xf4, 0x1e, 0xb1, 0x53, 0x98, 0xbd, 0xde, 0x25, 0xe7, 0x38, 0xe6, 0x33, + 0x0b, 0x95, 0x32, 0x23, 0x18, 0xcf, 0xfb, 0x94, 0xb9, 0xcc, 0x91, 0x4a, + 0xc9, 0x45, 0x63, 0xf4, 0x85, 0xa6, 0x49, 0xe1, 0xd5, 0x1c, 0xa9, 0x22, + 0x9d, 0x63, 0xa4, 0x33, 0xb7, 0x51, 0xeb, 0x1f, 0x53, 0x44, 0x67, 0x3e, + 0xe2, 0xba, 0x8b, 0x32, 0x3f, 0xa3, 0xde, 0xfe, 0x94, 0xcf, 0x8b, 0xde, + 0x82, 0x78, 0xad, 0x48, 0xe7, 0x89, 0xfc, 0x12, 0xe6, 0x32, 0x1f, 0x58, + 0x7f, 0x8f, 0xe5, 0x63, 0xac, 0x7d, 0x83, 0xc8, 0x31, 0x9f, 0x4c, 0x66, + 0x1a, 0xfb, 0x27, 0xc9, 0x87, 0x7d, 0x36, 0x6f, 0x10, 0x4f, 0x17, 0x9f, + 0x19, 0xe5, 0xbb, 0xa3, 0xd7, 0xfe, 0x16, 0x1d, 0xd9, 0xfb, 0xff, 0xf6, + 0x1e, 0x43, 0x39, 0x6d, 0x67, 0xf7, 0xe1, 0x47, 0x0d, 0xb7, 0xcc, 0xc3, + 0xf1, 0xf2, 0xf4, 0x16, 0x8c, 0xe9, 0x7f, 0x8e, 0xbd, 0x94, 0x7b, 0x9c, + 0xfa, 0x3c, 0x61, 0x58, 0xfb, 0xfc, 0x72, 0xfe, 0x8b, 0xb9, 0xfa, 0x60, + 0xeb, 0x19, 0x62, 0xb1, 0xe3, 0x8c, 0x99, 0xfd, 0xf1, 0xc6, 0xde, 0x57, + 0xe8, 0x77, 0xc9, 0xdf, 0x96, 0xbd, 0x74, 0x60, 0x32, 0xfb, 0x0d, 0xcc, + 0xd6, 0x34, 0x2e, 0x3f, 0xcf, 0x9c, 0x70, 0x9a, 0x79, 0xca, 0xc5, 0x9c, + 0x50, 0x9d, 0x25, 0x86, 0x64, 0x9e, 0x2a, 0x30, 0x4f, 0xb9, 0xb4, 0xc6, + 0xa5, 0x79, 0xfc, 0x15, 0xf5, 0x22, 0xfc, 0x45, 0x62, 0xf3, 0x90, 0x67, + 0xed, 0xf9, 0xab, 0x36, 0x3f, 0x84, 0x4b, 0x37, 0xdb, 0x33, 0x34, 0x27, + 0x6b, 0xf6, 0xbe, 0x4c, 0x63, 0x60, 0x4c, 0x68, 0xf7, 0xa9, 0xa1, 0x34, + 0x6d, 0x35, 0x61, 0x61, 0xef, 0x61, 0xf6, 0x0b, 0x72, 0xde, 0xab, 0x0a, + 0x2e, 0xfa, 0xfe, 0x98, 0x2e, 0xe7, 0x20, 0x42, 0xfe, 0xed, 0xb4, 0xe1, + 0x98, 0xd1, 0xd8, 0x12, 0x51, 0x76, 0xe3, 0x52, 0x31, 0xc7, 0xda, 0x58, + 0x5a, 0xed, 0x3f, 0x86, 0xc6, 0xde, 0x07, 0xf0, 0x75, 0x24, 0x6b, 0x1a, + 0x07, 0xa6, 0x11, 0xd1, 0xef, 0x83, 0x9c, 0x1b, 0xb5, 0x69, 0xd5, 0xe7, + 0x9c, 0xc4, 0x23, 0x9f, 0x98, 0xab, 0xb5, 0x27, 0x30, 0x4d, 0xcc, 0xd8, + 0xb0, 0x5e, 0x5b, 0xfa, 0x6e, 0xf1, 0x9e, 0xbd, 0xa7, 0x24, 0xfe, 0xe2, + 0xa1, 0x0e, 0xca, 0xe1, 0x5a, 0x51, 0xc7, 0x35, 0xa8, 0x0b, 0xeb, 0x4c, + 0xf1, 0x45, 0x1c, 0xa2, 0xbf, 0x4d, 0xe7, 0x15, 0xe8, 0xf5, 0x17, 0x31, + 0x2c, 0xb5, 0x89, 0xef, 0xb4, 0x65, 0x7c, 0xc4, 0x29, 0x21, 0x94, 0x6b, + 0x91, 0xf0, 0x28, 0xe5, 0x6b, 0x63, 0x2e, 0x1f, 0x67, 0x0e, 0x49, 0x07, + 0x7c, 0xd6, 0x39, 0xd7, 0x72, 0x2d, 0x64, 0xfd, 0x6f, 0x82, 0xf4, 0x41, + 0x0d, 0xb3, 0xb2, 0x9f, 0x7d, 0x04, 0x17, 0xa7, 0x0b, 0x38, 0x1e, 0x4f, + 0xe2, 0x40, 0x4d, 0x00, 0x93, 0xc6, 0x4a, 0x6b, 0x6e, 0x20, 0xfd, 0x56, + 0x77, 0xf6, 0xb0, 0x35, 0x8b, 0xdc, 0x16, 0x77, 0xd4, 0xcb, 0x79, 0x8f, + 0x39, 0xf6, 0x5d, 0xd3, 0xfa, 0x08, 0x0e, 0xe9, 0xdf, 0x82, 0xbe, 0x42, + 0x72, 0xe7, 0x18, 0xce, 0xcf, 0x4a, 0x0d, 0x9b, 0x68, 0xbd, 0x75, 0x52, + 0xf4, 0xe3, 0x20, 0xe6, 0xf5, 0xa0, 0xc9, 0xc2, 0x70, 0xaf, 0xb7, 0xae, + 0x99, 0xb5, 0xb1, 0x5c, 0x53, 0x4e, 0xce, 0x66, 0x57, 0xc1, 0x4f, 0x7d, + 0x5d, 0x88, 0xbb, 0x99, 0x73, 0x44, 0x9f, 0x72, 0x16, 0xd0, 0x96, 0x33, + 0x96, 0x53, 0x30, 0xd6, 0x7c, 0xe3, 0x5e, 0x8b, 0xfc, 0x9f, 0xc2, 0xb5, + 0xf3, 0x89, 0xc5, 0xd9, 0xf8, 0x1f, 0x9b, 0x97, 0x6e, 0x12, 0xb9, 0x5b, + 0x7d, 0xcc, 0xe9, 0xe1, 0xd9, 0x6b, 0xfa, 0x15, 0x9d, 0x9e, 0x93, 0x9a, + 0x61, 0xe9, 0xdc, 0x9e, 0xb7, 0xa9, 0xc3, 0xef, 0x28, 0x8d, 0xac, 0x27, + 0xf4, 0xab, 0x1a, 0xfa, 0x5b, 0x13, 0x06, 0x56, 0x27, 0x5c, 0x7d, 0x57, + 0x8d, 0x2d, 0x68, 0xd9, 0xf0, 0xae, 0x89, 0x9b, 0xdb, 0xe0, 0xd4, 0xe4, + 0xfa, 0xac, 0x99, 0x0c, 0xc8, 0xdf, 0x4f, 0xfa, 0xa4, 0x96, 0xbf, 0x68, + 0x14, 0xcc, 0x35, 0x2b, 0x6d, 0x6c, 0xf8, 0xf7, 0x19, 0xd9, 0x07, 0x4b, + 0x9b, 0xec, 0xb5, 0x97, 0xde, 0x76, 0x1e, 0xc6, 0xdf, 0xe6, 0x8e, 0xe0, + 0xad, 0x69, 0x17, 0x71, 0xa6, 0xc8, 0xb2, 0x05, 0xd5, 0x1b, 0xa2, 0xc9, + 0x77, 0x99, 0x17, 0x97, 0x66, 0x4b, 0x7e, 0xf1, 0x7a, 0xeb, 0xda, 0x59, + 0x85, 0xb4, 0xaa, 0x50, 0x46, 0x39, 0x7f, 0xac, 0x3b, 0x11, 0x2e, 0x62, + 0x5b, 0x27, 0xf9, 0xdc, 0x97, 0xb1, 0x31, 0x6f, 0x24, 0x37, 0xed, 0xb3, + 0xe7, 0x5f, 0x3e, 0xe6, 0xd1, 0x71, 0x4c, 0x64, 0x1a, 0x63, 0xef, 0xc9, + 0x79, 0x1e, 0xf6, 0x62, 0x97, 0x30, 0x8e, 0x13, 0x99, 0x52, 0x0e, 0x0d, + 0xc9, 0x39, 0xd8, 0x58, 0xd8, 0x61, 0xe7, 0xc8, 0xb0, 0x43, 0x4d, 0xf3, + 0xd7, 0x27, 0xd8, 0x60, 0x34, 0x1f, 0x09, 0x95, 0xc3, 0x89, 0xfd, 0xba, + 0xed, 0x1f, 0xf5, 0xf3, 0x6e, 0x84, 0x57, 0x48, 0x5d, 0x96, 0x9a, 0xec, + 0x62, 0x4d, 0x5e, 0x89, 0xe4, 0x4a, 0x17, 0x5e, 0xd7, 0x44, 0x1f, 0x53, + 0x25, 0x7d, 0xe8, 0xe7, 0xf0, 0x90, 0x59, 0xe8, 0x15, 0x5f, 0x72, 0xe3, + 0x48, 0xd3, 0x9c, 0x39, 0x1b, 0x14, 0xd9, 0x9d, 0x38, 0xcd, 0xfc, 0x8a, + 0x9b, 0x23, 0xa1, 0xd3, 0xac, 0xd9, 0x63, 0x5a, 0xc9, 0xc7, 0xff, 0x63, + 0x91, 0x4f, 0xad, 0x7f, 0x01, 0x47, 0xf8, 0x77, 0x7d, 0xe8, 0x80, 0x62, + 0xaf, 0xb7, 0x66, 0xfe, 0x43, 0x5f, 0x69, 0x76, 0x2a, 0xcf, 0x86, 0x73, + 0xa7, 0xf9, 0x5d, 0x68, 0xf9, 0xe8, 0x9f, 0xe5, 0x18, 0x08, 0xca, 0x79, + 0x10, 0xd1, 0x8b, 0xec, 0x3f, 0x82, 0xfa, 0x30, 0xf1, 0x32, 0xf5, 0x71, + 0xe4, 0xda, 0xd9, 0x2b, 0x3b, 0x7f, 0x55, 0xf0, 0xfa, 0xf6, 0xf8, 0x4b, + 0x9b, 0xbd, 0xf8, 0x95, 0x79, 0x29, 0x18, 0x62, 0x4e, 0x10, 0x9b, 0xa6, + 0x2c, 0x1c, 0xe9, 0x24, 0x3e, 0xd9, 0x67, 0x9f, 0x33, 0x69, 0x95, 0xff, + 0xa1, 0x29, 0xca, 0x51, 0x18, 0x24, 0xce, 0x5e, 0xcc, 0x58, 0x67, 0xfb, + 0x06, 0xde, 0x54, 0x22, 0xcc, 0x35, 0x5f, 0xc2, 0x40, 0xad, 0xd0, 0x0b, + 0xf8, 0x77, 0xce, 0xc4, 0xa8, 0x83, 0x3a, 0xa1, 0x6b, 0x3e, 0xc3, 0x6e, + 0xee, 0xc8, 0xa4, 0xd0, 0x07, 0xc6, 0x26, 0x23, 0x43, 0x3f, 0x06, 0x36, + 0x57, 0x41, 0x4d, 0x2d, 0x14, 0xff, 0xdf, 0xe3, 0x67, 0x8a, 0xd0, 0x12, + 0x3a, 0x2e, 0x18, 0xcc, 0x71, 0x53, 0x8b, 0x15, 0xd4, 0x9d, 0xda, 0xfb, + 0x3d, 0xa5, 0x02, 0x4f, 0x3c, 0x15, 0x23, 0xef, 0x2b, 0xfc, 0xdb, 0x67, + 0x3c, 0xf0, 0x9e, 0xa9, 0x62, 0xcd, 0xf5, 0xe0, 0x72, 0x33, 0xed, 0xfa, + 0x54, 0x89, 0x77, 0x6b, 0x9f, 0x14, 0x8f, 0x67, 0xc3, 0x30, 0xe8, 0xb3, + 0x8b, 0x86, 0xec, 0x17, 0x7b, 0xac, 0xfc, 0xb9, 0xb4, 0xb1, 0xce, 0xda, + 0xaf, 0x7a, 0x3e, 0xaf, 0x85, 0xce, 0x2a, 0x55, 0xf8, 0xe0, 0x44, 0xe1, + 0xe6, 0x72, 0x98, 0x2f, 0xae, 0x4e, 0x44, 0xfb, 0xf7, 0xd2, 0xe7, 0xd7, + 0xae, 0x09, 0xb2, 0x97, 0x61, 0x4f, 0xb9, 0x49, 0xfa, 0xdf, 0x69, 0xf6, + 0xbf, 0xa5, 0xbd, 0x7f, 0x6d, 0xe8, 0x11, 0x25, 0xdd, 0xe9, 0x87, 0xf9, + 0x51, 0x79, 0xc2, 0xfc, 0xd8, 0x9d, 0x88, 0xf2, 0x7d, 0xd9, 0xdf, 0x33, + 0xcd, 0x9f, 0x36, 0x9b, 0x66, 0xae, 0x39, 0xd2, 0x1f, 0x70, 0x06, 0x70, + 0xa6, 0x41, 0xf6, 0x04, 0x1d, 0xf8, 0x20, 0xaa, 0x85, 0xf6, 0x42, 0xf6, + 0xe8, 0x99, 0xe3, 0x57, 0xca, 0xf9, 0xc4, 0x3a, 0x7f, 0x97, 0xb1, 0x02, + 0xcf, 0x2d, 0x6c, 0xc2, 0x80, 0x1b, 0xd6, 0xf9, 0x19, 0x53, 0xc7, 0x9b, + 0xab, 0x21, 0x75, 0x3b, 0xda, 0xf2, 0x08, 0x82, 0x58, 0xc8, 0x1f, 0xc1, + 0xc3, 0x27, 0x64, 0xaf, 0x71, 0xb2, 0xd5, 0x73, 0xc2, 0xfc, 0xfb, 0x50, + 0xa2, 0xc0, 0xbc, 0x68, 0x9a, 0x15, 0x9b, 0x1a, 0x43, 0x2c, 0x47, 0xc4, + 0x18, 0x69, 0xc1, 0xee, 0x43, 0x1f, 0xa0, 0x06, 0x67, 0xe7, 0x92, 0x37, + 0xb3, 0x97, 0xec, 0x7a, 0x5a, 0x09, 0xe0, 0x07, 0x94, 0xf1, 0xd9, 0xbc, + 0xe0, 0x14, 0xa3, 0xb5, 0xfb, 0xc4, 0x2a, 0xbc, 0xb8, 0x10, 0xc4, 0x59, + 0x43, 0x23, 0x4e, 0x82, 0x52, 0x99, 0x30, 0xab, 0xab, 0xc9, 0x6b, 0xa5, + 0xd3, 0x89, 0xce, 0xb8, 0xf4, 0x87, 0xda, 0x90, 0x4f, 0xc1, 0xaa, 0x72, + 0x68, 0xcb, 0x0f, 0x01, 0xc3, 0x5e, 0xf6, 0xab, 0x4f, 0x2b, 0xd1, 0xfe, + 0xf7, 0x9d, 0x41, 0xfc, 0x80, 0xf9, 0xe7, 0x7b, 0x79, 0x39, 0x5b, 0xc5, + 0x1c, 0x33, 0x17, 0xa6, 0xad, 0x3c, 0x70, 0xd4, 0x57, 0xe1, 0x28, 0xe3, + 0xe5, 0x65, 0xbd, 0x8c, 0x39, 0x4a, 0xce, 0x5a, 0x49, 0x7e, 0x7f, 0x54, + 0xce, 0x94, 0x98, 0xcf, 0x6b, 0x76, 0xbf, 0xaf, 0xcf, 0xdf, 0x78, 0x5e, + 0x39, 0xc0, 0xbc, 0xde, 0xd8, 0x1b, 0x52, 0x5e, 0x35, 0x93, 0xbf, 0xad, + 0x50, 0xce, 0x07, 0xab, 0x50, 0x61, 0xc9, 0x8a, 0xd1, 0x6c, 0xa9, 0xa6, + 0x54, 0x4b, 0x2f, 0xd7, 0x9b, 0x2e, 0xfa, 0x60, 0x25, 0x63, 0xfd, 0x18, + 0x6b, 0x74, 0xf9, 0x09, 0xa9, 0x25, 0xec, 0x5f, 0x94, 0x2d, 0xc4, 0xc2, + 0x82, 0x1b, 0x3c, 0x78, 0x20, 0xa0, 0xb6, 0xc8, 0x99, 0xed, 0x67, 0xf3, + 0x1d, 0x2e, 0x39, 0x3b, 0xf5, 0x5c, 0x5e, 0x6a, 0xb9, 0xe4, 0x82, 0xd2, + 0x7a, 0x21, 0xd4, 0x4e, 0x8a, 0x8d, 0x86, 0x5b, 0x3f, 0x9a, 0xf4, 0xc9, + 0xf9, 0xfa, 0x11, 0x07, 0x7b, 0x6d, 0xcf, 0xa4, 0x69, 0xee, 0x69, 0xd6, + 0x86, 0xb6, 0x38, 0x65, 0x6f, 0x39, 0x32, 0x70, 0x4e, 0x51, 0x5b, 0x26, + 0x94, 0x1b, 0xe9, 0xfc, 0xb7, 0x2a, 0x89, 0x91, 0x34, 0xe5, 0x7c, 0xdc, + 0x92, 0x69, 0x8a, 0x32, 0x95, 0xce, 0x16, 0x55, 0xe1, 0xf2, 0x34, 0x34, + 0x46, 0x2d, 0xce, 0xeb, 0x4c, 0x4e, 0x81, 0x68, 0xb2, 0x1d, 0xe2, 0xff, + 0xea, 0x80, 0x60, 0xa8, 0x4a, 0xe6, 0xe4, 0xb9, 0x69, 0xa9, 0x31, 0x8a, + 0xe0, 0x93, 0x34, 0xd7, 0xc6, 0x95, 0x8d, 0xc0, 0xab, 0x93, 0xf6, 0xde, + 0x7b, 0xf1, 0x2c, 0xb8, 0x75, 0xe6, 0xe1, 0x11, 0xeb, 0x2c, 0x83, 0xd0, + 0x3f, 0x8c, 0x33, 0x19, 0xc1, 0x94, 0xc3, 0xc4, 0x94, 0x91, 0x14, 0xf1, + 0x66, 0x4b, 0xde, 0x3e, 0x97, 0xa5, 0x7f, 0x44, 0x9f, 0x7f, 0x9a, 0x58, + 0xf5, 0x28, 0xec, 0xbd, 0xf7, 0x86, 0xe2, 0x59, 0x85, 0x48, 0xae, 0x4b, + 0xd9, 0x91, 0x97, 0x18, 0x9b, 0x66, 0x8c, 0xb5, 0x2b, 0xdb, 0x17, 0x3a, + 0x94, 0xee, 0x85, 0x1e, 0x65, 0x77, 0x5e, 0x7a, 0xd6, 0xc9, 0xd6, 0x07, + 0x4e, 0xec, 0x52, 0x76, 0xcc, 0xf5, 0x29, 0xc4, 0xb4, 0x01, 0x4f, 0xa2, + 0x5f, 0xe9, 0x59, 0xb0, 0xe7, 0xe7, 0x5d, 0xec, 0xbb, 0x76, 0x18, 0xa5, + 0x7e, 0x5e, 0xfe, 0xdf, 0x2b, 0x28, 0xff, 0x5b, 0x31, 0xb0, 0x4d, 0x31, + 0xcd, 0xdb, 0xe2, 0x7f, 0x27, 0xf6, 0x30, 0x9f, 0x8d, 0xb3, 0x36, 0x1a, + 0x55, 0x18, 0x64, 0xdf, 0x31, 0xaa, 0xdf, 0x5a, 0xdc, 0x2f, 0x13, 0x99, + 0xe4, 0x3c, 0x85, 0xf8, 0x2b, 0xd2, 0xe5, 0xe4, 0xe1, 0x1f, 0xc8, 0xff, + 0x81, 0xa2, 0x5c, 0x3d, 0x72, 0xa6, 0xc0, 0x7d, 0xfd, 0xbc, 0xd9, 0xf1, + 0xc9, 0xeb, 0x72, 0x31, 0xd7, 0x63, 0x9c, 0xf8, 0xf4, 0x80, 0xa2, 0xa6, + 0x9e, 0xb1, 0xe5, 0x5a, 0xba, 0xcc, 0x18, 0x1e, 0xb5, 0x62, 0xd8, 0x96, + 0x6b, 0x5d, 0x51, 0xae, 0xb5, 0xb9, 0x2e, 0xeb, 0x1c, 0x17, 0xf1, 0x7a, + 0xeb, 0xe2, 0xa4, 0x9c, 0x37, 0x93, 0xd9, 0xa5, 0xc8, 0x26, 0x72, 0x9c, + 0x30, 0x2b, 0xb4, 0x1e, 0x65, 0xa7, 0x75, 0xfe, 0x4c, 0xce, 0x7e, 0xc9, + 0x5e, 0x7f, 0x49, 0x2e, 0xa9, 0xe3, 0x2b, 0xfc, 0x1d, 0x33, 0x72, 0x1e, + 0xdb, 0x34, 0x5f, 0xd3, 0x83, 0x7e, 0x91, 0xe5, 0xac, 0x2e, 0xb2, 0xc8, + 0xb9, 0x92, 0x92, 0x3c, 0x5f, 0x2b, 0xca, 0x23, 0xb6, 0xba, 0x6e, 0xa7, + 0xd2, 0xff, 0x09, 0xbe, 0x9d, 0xb1, 0xcf, 0x9c, 0x94, 0xe4, 0xf1, 0x27, + 0x84, 0xff, 0x8b, 0xad, 0xe3, 0xd3, 0xc3, 0x78, 0x95, 0xf7, 0x7f, 0x9e, + 0x29, 0xc9, 0xe5, 0xc4, 0xfc, 0x5c, 0xe9, 0x2c, 0x1d, 0x5b, 0x4a, 0x23, + 0xa2, 0x8f, 0xd1, 0x8f, 0x6c, 0xf9, 0xe4, 0x2c, 0x5d, 0x63, 0xe1, 0xb2, + 0x35, 0xf7, 0x8a, 0x26, 0xd9, 0x2f, 0xe3, 0x6c, 0xfe, 0xd7, 0xed, 0xd7, + 0x94, 0xab, 0x60, 0x8f, 0x2c, 0xb4, 0x5f, 0x27, 0x6d, 0x39, 0x73, 0xa2, + 0xe0, 0x99, 0x39, 0x60, 0xce, 0xe0, 0xb2, 0x89, 0x11, 0x3c, 0xa9, 0x9b, + 0xe6, 0xd3, 0xcd, 0x9a, 0x9c, 0x15, 0xba, 0x50, 0x6b, 0xcd, 0x85, 0xa0, + 0x57, 0x69, 0xb2, 0x77, 0x27, 0xe7, 0x4d, 0xfa, 0xa8, 0x03, 0x91, 0x5d, + 0x7c, 0xa0, 0x64, 0x7b, 0x39, 0x07, 0x97, 0xa6, 0x7e, 0x44, 0x37, 0xa5, + 0xf3, 0x70, 0x32, 0x73, 0xb9, 0x51, 0x27, 0x5d, 0x96, 0x4e, 0x9e, 0xd5, + 0xc5, 0x5f, 0x99, 0x7d, 0xe8, 0xab, 0xf3, 0xc4, 0x0f, 0x63, 0xba, 0xdb, + 0xc2, 0x6a, 0x47, 0x89, 0x4f, 0x26, 0x18, 0x3b, 0x8f, 0x1b, 0x4b, 0x58, + 0xca, 0xbd, 0x8c, 0x57, 0xaf, 0xfd, 0xcf, 0x9c, 0xf8, 0x8b, 0xde, 0xd2, + 0x6d, 0x9d, 0x79, 0xfa, 0xa4, 0xe5, 0xd6, 0xa8, 0xe4, 0xa1, 0x1f, 0x36, + 0xc9, 0x19, 0xa8, 0xf2, 0x44, 0xe0, 0x6b, 0xb2, 0xbf, 0x55, 0x96, 0x98, + 0xfd, 0xea, 0x05, 0x4d, 0x74, 0xa3, 0x35, 0x9f, 0xd1, 0x44, 0xae, 0x1e, + 0x7d, 0xdc, 0xfa, 0x1f, 0xce, 0x96, 0x4d, 0xfb, 0x34, 0x89, 0x1d, 0xdf, + 0xc6, 0x36, 0x2b, 0x27, 0x9c, 0x4e, 0xdc, 0x66, 0xe9, 0xe0, 0x64, 0xe2, + 0x56, 0xeb, 0x73, 0x3a, 0x11, 0xb3, 0x3e, 0xff, 0x24, 0x61, 0xeb, 0x26, + 0x97, 0xa8, 0xb7, 0x3e, 0xe7, 0x13, 0xf6, 0xd9, 0xe9, 0xd9, 0x84, 0x66, + 0x7d, 0x3e, 0x9f, 0x88, 0x58, 0x9f, 0x67, 0x13, 0xb7, 0x5c, 0xe7, 0x8b, + 0x3f, 0xff, 0x0f, 0x4c, 0xd3, 0x85, 0x76, 0xdc, 0x3a, 0x00, 0x00, 0x00 }; -static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 }; -static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; +static const u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 }; +static const u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 }; static struct fw_info bnx2_txp_fw_06 = { - .ver_major = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, .ver_minor = 0x0, - .ver_fix = 0x0, + .ver_fix = 0x5, - .start_addr = 0x080034b0, + .start_addr = 0x08000098, .text_addr = 0x08000000, - .text_len = 0x5748, + .text_len = 0x3ad8, .text_index = 0x0, .gz_text = bnx2_TXP_b06FwText, .gz_text_len = sizeof(bnx2_TXP_b06FwText), - .data_addr = 0x08005760, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_TXP_b06FwData, - .sbss_addr = 0x08005760, - .sbss_len = 0x38, + .sbss_addr = 0x08003b00, + .sbss_len = 0x68, .sbss_index = 0x0, - .bss_addr = 0x080057a0, - .bss_len = 0x1c4, + .bss_addr = 0x08003b68, + .bss_len = 0x14c, .bss_index = 0x0, .rodata_addr = 0x00000000, diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h index 4b129b7cbfad..13b222eb2f63 100644 --- a/drivers/net/bnx2_fw2.h +++ b/drivers/net/bnx2_fw2.h @@ -15,4088 +15,4566 @@ */ static u8 bnx2_COM_b09FwText[] = { - 0xdc, 0x5b, 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, - 0xc8, 0x15, 0x35, 0x22, 0x57, 0xd4, 0x9a, 0xa2, 0xed, 0x5d, 0x72, 0x28, - 0xb2, 0x96, 0xea, 0xae, 0x29, 0xa6, 0x62, 0xd3, 0x4d, 0xb4, 0xd9, 0xa5, - 0x5c, 0xb5, 0x75, 0x5a, 0x4a, 0x26, 0xfc, 0x48, 0x55, 0x83, 0xde, 0xa5, - 0x9c, 0xa0, 0xa8, 0x53, 0xc9, 0x76, 0x85, 0x20, 0x05, 0xaa, 0x05, 0x1f, - 0x89, 0x52, 0xb0, 0x1c, 0xc5, 0x92, 0x29, 0xb5, 0x71, 0x6b, 0x96, 0xb4, - 0x6c, 0x15, 0xd8, 0x6a, 0x65, 0xc7, 0x6d, 0x68, 0x54, 0x2e, 0x65, 0xca, - 0x69, 0x95, 0x26, 0x48, 0x8d, 0xa0, 0x42, 0x95, 0x3f, 0x8e, 0xe1, 0xf4, - 0x87, 0x5b, 0xf4, 0x87, 0xd1, 0x07, 0x22, 0xd7, 0x8f, 0xed, 0xf7, 0xdd, - 0xb9, 0x43, 0x0e, 0x97, 0x14, 0x45, 0xf9, 0xf5, 0xa3, 0x04, 0x56, 0x33, - 0xf7, 0x7d, 0xee, 0xb9, 0xe7, 0x7c, 0xe7, 0x31, 0x57, 0x3f, 0x2f, 0x52, - 0x27, 0xfa, 0x6f, 0x3d, 0x7e, 0x89, 0x87, 0x7f, 0xaf, 0x70, 0xfb, 0xce, - 0xdb, 0x77, 0xe0, 0xf5, 0x0e, 0xd3, 0xa8, 0x0d, 0xb1, 0x9e, 0xff, 0xc4, - 0xf0, 0xeb, 0xd6, 0xef, 0x2b, 0xfd, 0xd9, 0xf8, 0xbd, 0x89, 0xc6, 0xc1, - 0x7f, 0x17, 0x31, 0xae, 0xd1, 0x27, 0xf8, 0x57, 0xa9, 0xac, 0xde, 0x6e, - 0x92, 0x96, 0x55, 0xda, 0x43, 0xde, 0x92, 0x8a, 0x66, 0xfe, 0x24, 0x62, - 0xa6, 0x33, 0x47, 0xb2, 0x8e, 0x11, 0x09, 0xa5, 0xbb, 0x8a, 0x05, 0x47, - 0x24, 0x53, 0xda, 0x96, 0xc8, 0xc9, 0x7b, 0x95, 0x62, 0xcc, 0x92, 0xac, - 0x23, 0x91, 0x9b, 0xd3, 0xef, 0x3e, 0xf5, 0xd2, 0xce, 0xe4, 0x5b, 0x53, - 0x21, 0x89, 0xd8, 0xe9, 0x17, 0xc4, 0xde, 0x2a, 0x91, 0x56, 0x8c, 0x79, - 0xb2, 0x33, 0x63, 0x48, 0x83, 0x3f, 0xd7, 0x9b, 0x95, 0x97, 0x3a, 0xa5, - 0xd8, 0x92, 0x8e, 0x88, 0x99, 0xee, 0xb8, 0x92, 0x0d, 0xd9, 0x83, 0xa1, - 0xb4, 0x2d, 0x73, 0x65, 0xe9, 0x3f, 0x30, 0x2e, 0x91, 0x48, 0xfa, 0x4b, - 0x91, 0xda, 0x0e, 0x89, 0x58, 0xe9, 0xa9, 0x23, 0x5f, 0x73, 0x8e, 0x54, - 0x4c, 0xc7, 0xe9, 0x9a, 0x96, 0x68, 0xef, 0xe9, 0x1e, 0xb4, 0x97, 0x92, - 0x5d, 0x22, 0x3b, 0xc5, 0x74, 0x8a, 0xd1, 0x90, 0x13, 0x91, 0x6c, 0xd9, - 0x91, 0x5c, 0x59, 0xe4, 0x1f, 0x4a, 0x86, 0x9c, 0x76, 0x9a, 0x65, 0x7a, - 0xfb, 0xbb, 0x95, 0x0c, 0x68, 0xf9, 0x7b, 0x67, 0xea, 0xc8, 0xa8, 0x43, - 0x7a, 0x1f, 0x8b, 0x90, 0xae, 0x50, 0x7a, 0xa8, 0xb6, 0xe0, 0x58, 0x32, - 0x5c, 0x62, 0xdd, 0x80, 0xc9, 0xba, 0x70, 0x3a, 0x52, 0x77, 0xda, 0x89, - 0xea, 0xba, 0x52, 0x26, 0x8b, 0xf9, 0x46, 0x4a, 0xec, 0x1b, 0xe9, 0x2e, - 0x38, 0x31, 0x5d, 0x3f, 0xba, 0x33, 0xeb, 0xc4, 0x51, 0xdf, 0xaa, 0xdb, - 0x7a, 0xbe, 0x5c, 0x70, 0x1c, 0xdd, 0x76, 0x35, 0x94, 0x75, 0xba, 0x74, - 0xfd, 0xab, 0xbb, 0x0a, 0xce, 0x76, 0x5d, 0xff, 0xd6, 0xae, 0xac, 0x93, - 0xd2, 0xf5, 0xe3, 0xf7, 0x17, 0x9c, 0x1e, 0x5d, 0xdf, 0x8a, 0xfa, 0x5e, - 0x5d, 0xff, 0x83, 0xde, 0x82, 0x93, 0x46, 0xfd, 0x97, 0x22, 0x66, 0x87, - 0x2d, 0x63, 0xa5, 0x04, 0x7e, 0x19, 0xb4, 0xf5, 0xa1, 0x6e, 0x0f, 0x7e, - 0x77, 0xe1, 0x37, 0xbf, 0x41, 0x1a, 0xfa, 0xf1, 0x6c, 0x6b, 0xf5, 0x78, - 0x07, 0x1e, 0xb9, 0x11, 0x79, 0x3d, 0x14, 0x97, 0x97, 0x3a, 0x5f, 0x07, - 0x0f, 0x6d, 0x39, 0x57, 0x16, 0xa3, 0xbf, 0x33, 0x0e, 0xde, 0xc5, 0xe4, - 0xb9, 0x72, 0xbd, 0x84, 0x1e, 0x0f, 0x81, 0x37, 0x5f, 0x90, 0x7c, 0x2c, - 0x22, 0x1b, 0x27, 0x0d, 0x69, 0xeb, 0x8e, 0x48, 0xc6, 0xe6, 0xda, 0x38, - 0xed, 0x89, 0x98, 0x84, 0x26, 0x33, 0x4d, 0xa6, 0x74, 0xd8, 0x39, 0x29, - 0x82, 0x77, 0x57, 0x28, 0x97, 0x68, 0x4b, 0x48, 0x6e, 0xfc, 0x36, 0x19, - 0xb4, 0x49, 0xd7, 0xdc, 0xcd, 0xde, 0x5a, 0x11, 0x23, 0x7b, 0x72, 0x40, - 0xc6, 0xdc, 0xa8, 0x91, 0x3b, 0xf9, 0x59, 0xc9, 0xa6, 0x24, 0x86, 0x71, - 0xf1, 0x3c, 0x5a, 0x66, 0x4a, 0x03, 0x32, 0xea, 0x8a, 0x91, 0x75, 0xc9, - 0xcf, 0x66, 0xb4, 0x37, 0xa8, 0xbe, 0xa8, 0x6b, 0x0d, 0xa9, 0xb9, 0x23, - 0xa8, 0xb7, 0x51, 0xdf, 0x68, 0xf4, 0xa9, 0x39, 0x54, 0x7d, 0x62, 0x44, - 0xa2, 0xf2, 0x74, 0x29, 0xa6, 0xfb, 0x56, 0x2a, 0xd9, 0x94, 0x8d, 0x7e, - 0x03, 0x32, 0xe2, 0xc6, 0x64, 0x10, 0xcf, 0x61, 0x97, 0x72, 0x15, 0x87, - 0x4c, 0x35, 0x14, 0xf3, 0x27, 0xd4, 0x7c, 0x89, 0x50, 0x9a, 0xf3, 0xb5, - 0xa2, 0xdf, 0xdb, 0xa0, 0xcb, 0x10, 0x4b, 0x9d, 0x65, 0x46, 0xf2, 0xe3, - 0x06, 0xe4, 0x0d, 0x4f, 0xc5, 0xd7, 0x3e, 0xd0, 0x6f, 0x89, 0xd3, 0x6d, - 0x48, 0x01, 0x67, 0x55, 0xb4, 0x51, 0x2e, 0xcd, 0x9a, 0x59, 0xb7, 0x56, - 0x72, 0x56, 0x42, 0x42, 0x13, 0x94, 0xa5, 0x41, 0x19, 0xc1, 0x18, 0xd3, - 0x61, 0x9f, 0xb7, 0xb1, 0xef, 0x41, 0x75, 0x0e, 0x35, 0xe9, 0xa2, 0x99, - 0x2b, 0x37, 0x8b, 0x39, 0xb9, 0x5f, 0x5e, 0x19, 0x17, 0x3b, 0x94, 0x7e, - 0xb7, 0x92, 0x75, 0x46, 0xcd, 0xec, 0xb3, 0x96, 0x84, 0x27, 0x0c, 0x19, - 0x75, 0x92, 0xd0, 0x80, 0xa3, 0xe6, 0xee, 0xf2, 0x2c, 0xfa, 0x71, 0x1c, - 0xfa, 0x95, 0x4c, 0xf0, 0x95, 0xef, 0xdb, 0x6c, 0x53, 0xc9, 0x33, 0xfb, - 0xe0, 0x0c, 0xb0, 0x8f, 0xe7, 0x5c, 0x9c, 0x89, 0x3a, 0xa3, 0x04, 0xce, - 0x48, 0x8c, 0xbe, 0x4e, 0xc8, 0xd4, 0x09, 0x4b, 0xf2, 0x29, 0xec, 0x0b, - 0xbd, 0xf3, 0xa9, 0x45, 0xba, 0x46, 0xc6, 0xab, 0xe9, 0xe2, 0x38, 0xd2, - 0xe5, 0xd1, 0x34, 0x7c, 0x82, 0xf4, 0x2d, 0xd2, 0x33, 0x36, 0xee, 0xd3, - 0xc8, 0xf5, 0x48, 0x9b, 0x4f, 0x17, 0xc7, 0x91, 0xae, 0x26, 0x9e, 0x35, - 0xff, 0x8c, 0x3e, 0xd0, 0x31, 0xe2, 0x5a, 0x38, 0xa3, 0xa8, 0xe4, 0xed, - 0xa2, 0x31, 0xd2, 0xbb, 0x2d, 0x0e, 0x6d, 0x36, 0x86, 0x7b, 0x49, 0xb3, - 0x83, 0x73, 0xac, 0x51, 0xe7, 0x0d, 0xf9, 0x26, 0xef, 0xd0, 0x9f, 0xeb, - 0xe3, 0xbd, 0x64, 0xcb, 0xa8, 0x9a, 0x8f, 0x34, 0x7d, 0x14, 0xf3, 0x90, - 0xd6, 0x4b, 0x90, 0xd5, 0x1e, 0xc8, 0x68, 0x4a, 0xfe, 0xae, 0xbc, 0x5d, - 0xbe, 0x53, 0xee, 0x92, 0xbf, 0x81, 0xde, 0xfe, 0x75, 0x39, 0x21, 0x2f, - 0x94, 0x5b, 0xe5, 0xdb, 0xe5, 0xb8, 0x3c, 0xaf, 0xe4, 0xb7, 0x4f, 0xa4, - 0x81, 0x32, 0x9d, 0x90, 0x46, 0xe8, 0xcf, 0x46, 0xe8, 0xe6, 0x13, 0xe0, - 0xdf, 0x89, 0x4e, 0xc9, 0x34, 0xa5, 0x25, 0x72, 0x0b, 0x7e, 0x9b, 0xf1, - 0x6b, 0x4e, 0x43, 0xee, 0x5c, 0xf2, 0x8e, 0x3c, 0xb4, 0x24, 0xa7, 0xf6, - 0x6c, 0xc9, 0x48, 0x79, 0xfe, 0x16, 0x4f, 0x76, 0x45, 0xfa, 0xc1, 0x63, - 0xb3, 0xfb, 0x7f, 0x2a, 0x19, 0x1b, 0xfb, 0xe8, 0xde, 0xa6, 0x78, 0x6f, - 0x76, 0x53, 0x66, 0x13, 0x90, 0x7b, 0xcb, 0xc8, 0xb9, 0x67, 0x80, 0x1b, - 0xf5, 0x46, 0xf6, 0x78, 0x51, 0x0a, 0xc7, 0x2b, 0x52, 0x48, 0x85, 0xe5, - 0x11, 0xbb, 0x22, 0x7d, 0xa9, 0x1a, 0x39, 0x64, 0x83, 0xf7, 0xdb, 0x7f, - 0xdf, 0xf0, 0x31, 0xfb, 0x89, 0xf2, 0x61, 0xbc, 0xb3, 0x4e, 0xe4, 0x84, - 0x7a, 0xf7, 0xea, 0x8b, 0xe5, 0xb0, 0x64, 0x62, 0xc5, 0xb8, 0x25, 0x2d, - 0xa6, 0xb7, 0xee, 0xb0, 0xdf, 0x06, 0x7e, 0x4c, 0x01, 0x27, 0x93, 0x4a, - 0x5f, 0xf2, 0xe3, 0xeb, 0xae, 0x66, 0x54, 0x35, 0xfa, 0xdb, 0x3d, 0x32, - 0xaf, 0xf8, 0x99, 0x18, 0x34, 0xd2, 0x31, 0x69, 0x2b, 0xb1, 0xdc, 0x6b, - 0xdc, 0x5d, 0xa6, 0x3c, 0xe3, 0xbd, 0x4c, 0x3a, 0x6f, 0x42, 0x3f, 0x0b, - 0xcf, 0x8c, 0xa6, 0x37, 0x48, 0x23, 0xe7, 0x21, 0x8d, 0x7c, 0xfe, 0x79, - 0x80, 0xc6, 0xa7, 0x16, 0xde, 0x4f, 0x04, 0xde, 0x8b, 0xe5, 0x4b, 0x75, - 0x1e, 0x6d, 0xbd, 0xf2, 0xc6, 0xc4, 0x57, 0xf4, 0x3a, 0x78, 0x3f, 0xcb, - 0xf9, 0xff, 0xaa, 0xe2, 0xc9, 0x4b, 0xf1, 0x3a, 0xeb, 0xcc, 0x06, 0xd6, - 0x79, 0x31, 0xb0, 0xce, 0x8b, 0x81, 0x75, 0x8a, 0xe0, 0xa9, 0x6c, 0x30, - 0x21, 0xc3, 0x79, 0x9a, 0x31, 0x39, 0x8a, 0x39, 0x5f, 0x97, 0x50, 0x9a, - 0x7a, 0xee, 0xe3, 0xcd, 0x65, 0xf4, 0x4f, 0xcb, 0xfc, 0x44, 0x51, 0xf2, - 0xc7, 0xc3, 0xb2, 0x4f, 0xf5, 0xdb, 0xa5, 0xe9, 0x0b, 0xb6, 0x45, 0x64, - 0x6f, 0x8c, 0xef, 0x7e, 0x9b, 0x05, 0x3e, 0xb3, 0xfc, 0xc6, 0x4d, 0x5e, - 0x99, 0xef, 0xb3, 0x7a, 0x2f, 0x03, 0xde, 0xb8, 0xb3, 0x6f, 0x2a, 0x3c, - 0x9c, 0x2b, 0x13, 0xb7, 0x24, 0x15, 0x72, 0xe4, 0x60, 0x5f, 0xaa, 0x59, - 0x46, 0x6c, 0x23, 0x35, 0xdc, 0x55, 0x4b, 0xbd, 0xc8, 0x98, 0x4e, 0x3d, - 0xb0, 0x41, 0x12, 0x26, 0x31, 0x5f, 0xed, 0xcb, 0x30, 0x3d, 0xfa, 0x6d, - 0x96, 0xfb, 0x4d, 0xa7, 0xb1, 0xaa, 0x9e, 0xba, 0x1d, 0xc2, 0x3b, 0x65, - 0x78, 0xb7, 0x3e, 0x63, 0x0b, 0x65, 0xe2, 0xf0, 0xad, 0xba, 0xec, 0xb7, - 0xe3, 0xc0, 0x96, 0x94, 0x7f, 0xb6, 0x65, 0x69, 0xd9, 0xc7, 0x89, 0x20, - 0x86, 0x73, 0xaf, 0xc0, 0x27, 0x87, 0x72, 0x17, 0x06, 0xad, 0x29, 0xe8, - 0x5c, 0xad, 0xa6, 0x61, 0xb3, 0xa6, 0x01, 0xb4, 0x76, 0x42, 0xb2, 0x94, - 0x2e, 0x29, 0xd1, 0xaa, 0x2a, 0x93, 0xf7, 0xfe, 0xfb, 0x7a, 0xd5, 0xee, - 0xe9, 0x9c, 0xff, 0xf4, 0xf1, 0xfd, 0xcd, 0x80, 0xbd, 0x68, 0x85, 0xce, - 0xc6, 0xc0, 0x2b, 0x1f, 0xeb, 0x89, 0xc1, 0x71, 0xd8, 0x07, 0xc8, 0xaa, - 0xc2, 0xf6, 0x28, 0xf0, 0xd0, 0xd2, 0xd8, 0x1c, 0xd1, 0xd8, 0x1c, 0x05, - 0x2e, 0xb3, 0x6c, 0xeb, 0x72, 0x4c, 0x97, 0xe3, 0x28, 0xc3, 0x8e, 0x4f, - 0x12, 0xbb, 0x1b, 0x8a, 0x43, 0x27, 0x14, 0xde, 0xd3, 0x56, 0x00, 0x85, - 0x89, 0xd7, 0xc4, 0xed, 0x56, 0x99, 0x2e, 0x61, 0xbd, 0x05, 0x6c, 0xe4, - 0xde, 0x83, 0xf4, 0x90, 0x96, 0x75, 0x62, 0xc2, 0x76, 0x65, 0x62, 0xa4, - 0xf7, 0x61, 0xec, 0x9d, 0xf8, 0x43, 0xba, 0x6f, 0x06, 0xad, 0xdc, 0xc7, - 0x27, 0x49, 0x2b, 0xd7, 0xab, 0xa6, 0xf7, 0xc3, 0xe2, 0x20, 0x69, 0x3f, - 0x83, 0x3d, 0x67, 0x80, 0x79, 0x62, 0x0c, 0x74, 0x0e, 0x60, 0xcf, 0xfd, - 0xc0, 0xc3, 0xbb, 0x80, 0x87, 0x7b, 0x80, 0x87, 0x7d, 0xc0, 0xc3, 0x34, - 0xb0, 0xb0, 0x17, 0x58, 0xd8, 0x03, 0x2c, 0x4c, 0x81, 0x37, 0x31, 0x99, - 0x02, 0x36, 0x4e, 0x01, 0x23, 0xa7, 0x30, 0xc7, 0xf0, 0xa4, 0x18, 0x0f, - 0x60, 0x0f, 0xdf, 0x9c, 0x48, 0x9e, 0x82, 0x2c, 0xc5, 0x8b, 0x26, 0xe4, - 0x3f, 0xd5, 0x0b, 0xd9, 0xee, 0x92, 0x99, 0xb2, 0x25, 0x05, 0xd8, 0xd4, - 0xb6, 0xad, 0xed, 0xd0, 0x35, 0xc8, 0x7b, 0x5c, 0xf4, 0xdf, 0x7a, 0xfd, - 0xfc, 0xb1, 0x88, 0xf3, 0x4f, 0x94, 0xc5, 0x84, 0xc8, 0x79, 0xc9, 0xbb, - 0xed, 0x76, 0x9b, 0xd9, 0x85, 0x7e, 0x2c, 0xa7, 0xcc, 0x03, 0xc7, 0xef, - 0x30, 0x87, 0x8e, 0x2b, 0x7f, 0x05, 0x78, 0x55, 0x91, 0xd1, 0x14, 0x75, - 0xab, 0x22, 0xa7, 0x53, 0xc9, 0xde, 0xa2, 0xd4, 0xcb, 0x58, 0x6c, 0x5c, - 0xd9, 0x5a, 0x2b, 0x7d, 0x4c, 0xd9, 0xab, 0x82, 0x83, 0x67, 0xa9, 0xdb, - 0xcc, 0x1f, 0xe7, 0xfe, 0xdb, 0xf1, 0x0b, 0x83, 0x16, 0xce, 0x6f, 0x49, - 0x5f, 0x8f, 0x6d, 0x3e, 0xd4, 0x59, 0x84, 0x42, 0x24, 0xed, 0x79, 0xac, - 0x9c, 0x1b, 0x6f, 0x8f, 0xb7, 0x9b, 0x96, 0x0c, 0x5a, 0x86, 0x0c, 0x43, - 0xbe, 0xfb, 0x52, 0x6f, 0x57, 0xc6, 0x62, 0x6c, 0xaf, 0x95, 0xaf, 0x2b, - 0x9f, 0x03, 0x6b, 0xcf, 0x9c, 0xc0, 0xba, 0x61, 0x9c, 0x01, 0xd7, 0xe5, - 0x3c, 0x28, 0x97, 0x2c, 0x94, 0x93, 0xa7, 0x8a, 0x52, 0x86, 0x9e, 0x6c, - 0x90, 0xec, 0xf6, 0x1a, 0xc9, 0xf4, 0x27, 0x64, 0x78, 0xa2, 0x0c, 0x9c, - 0x8a, 0x28, 0x5d, 0xc9, 0x0f, 0x24, 0xe4, 0xf1, 0x09, 0xd6, 0x9d, 0xc3, - 0xfe, 0x93, 0xc7, 0x32, 0xc2, 0xfd, 0x1b, 0x92, 0xd9, 0x7f, 0x4e, 0x1e, - 0x71, 0xcf, 0xc9, 0x10, 0xce, 0xf0, 0xe9, 0xf2, 0xac, 0x1c, 0x70, 0x1d, - 0x39, 0x0d, 0xbc, 0xcf, 0x1d, 0x07, 0xee, 0x39, 0xeb, 0x81, 0x51, 0xc9, - 0x73, 0xb4, 0xa1, 0x26, 0xfc, 0xbc, 0x69, 0xf0, 0xf7, 0x89, 0x09, 0xf2, - 0xd7, 0x94, 0x47, 0x7f, 0xd1, 0x80, 0x3e, 0x26, 0xc0, 0xcf, 0x56, 0x39, - 0xec, 0x26, 0x67, 0x33, 0x26, 0x70, 0x31, 0x65, 0x87, 0xa4, 0x2e, 0x8e, - 0x7e, 0x5e, 0x9f, 0x5c, 0x2a, 0x84, 0xb3, 0x2e, 0xa2, 0xef, 0xdb, 0xa0, - 0x93, 0x63, 0x63, 0xf8, 0x65, 0xd0, 0x0f, 0xf2, 0x6b, 0x27, 0x67, 0xa7, - 0x4c, 0xf6, 0x4f, 0xe0, 0xcc, 0x80, 0x2b, 0x93, 0x00, 0x1e, 0x9b, 0xef, - 0x69, 0x33, 0x4f, 0x1a, 0x5c, 0xca, 0x59, 0x02, 0x34, 0x11, 0xd3, 0xda, - 0xcf, 0x7d, 0x47, 0xb8, 0xce, 0x46, 0xf4, 0x7f, 0x07, 0x7e, 0xae, 0x2d, - 0x33, 0x38, 0x97, 0x9f, 0x82, 0x57, 0x99, 0xb8, 0x57, 0x1e, 0x9e, 0x4c, - 0x9e, 0x9b, 0x37, 0xf9, 0xee, 0x14, 0xf3, 0xe6, 0x6d, 0x22, 0x8d, 0xe4, - 0x57, 0x0a, 0xbc, 0x72, 0x6c, 0xd3, 0xdc, 0xaa, 0x7d, 0x3b, 0xea, 0x89, - 0x03, 0x9a, 0xe0, 0x67, 0x74, 0x07, 0xf5, 0x84, 0xf6, 0xce, 0xd7, 0x93, - 0x64, 0x7c, 0xca, 0x84, 0xff, 0xd1, 0x6d, 0xc9, 0x31, 0x55, 0x06, 0x8f, - 0x06, 0x92, 0xf1, 0x8c, 0x49, 0x9f, 0xb7, 0x4b, 0x9e, 0x76, 0xd9, 0x1f, - 0x7c, 0x1c, 0x8f, 0xea, 0xfe, 0xe7, 0x20, 0x23, 0xf4, 0xcf, 0xba, 0x40, - 0xb3, 0xa7, 0x3b, 0xd3, 0xe3, 0x31, 0xd5, 0x36, 0xa6, 0xf6, 0x60, 0x60, - 0x5d, 0xc8, 0x26, 0x7c, 0xb5, 0x9c, 0xd2, 0x23, 0x3b, 0x03, 0x5f, 0x1e, - 0x7a, 0xe0, 0xe9, 0xd0, 0x4c, 0x89, 0xb4, 0xdc, 0x43, 0x7e, 0x14, 0x41, - 0xcc, 0x31, 0x33, 0x8d, 0x73, 0xed, 0x91, 0x22, 0xfd, 0xb9, 0xf9, 0xd0, - 0xd3, 0x32, 0x38, 0x43, 0x7b, 0x83, 0x9f, 0xeb, 0xd8, 0x8c, 0x1f, 0x32, - 0xca, 0x16, 0x6c, 0xc1, 0x39, 0xc3, 0x4e, 0xa4, 0x36, 0x6a, 0x3f, 0xe6, - 0x49, 0x9c, 0xdb, 0x79, 0x9c, 0x6b, 0x49, 0x86, 0x4e, 0x5e, 0xa2, 0xcc, - 0x76, 0xcd, 0x48, 0xb2, 0x6b, 0x4c, 0xb6, 0xd9, 0xd3, 0xd0, 0xb7, 0xcc, - 0x40, 0x65, 0x97, 0x99, 0xe6, 0x98, 0x23, 0x18, 0x83, 0xe7, 0xcc, 0x25, - 0x39, 0x54, 0x66, 0xdd, 0xef, 0x80, 0x9f, 0xb0, 0x3b, 0x3d, 0x4f, 0x6a, - 0x39, 0xc7, 0x7c, 0x96, 0x3f, 0xdf, 0x25, 0x3d, 0x1f, 0xfb, 0xb1, 0x0f, - 0xc7, 0x2c, 0xce, 0xbb, 0x9b, 0xb6, 0x06, 0x78, 0xd3, 0x61, 0x56, 0x76, - 0x85, 0xd1, 0x7e, 0xba, 0x87, 0xef, 0x98, 0x07, 0xb6, 0xc6, 0x76, 0xce, - 0xa3, 0x2f, 0xf6, 0xe5, 0xae, 0x93, 0xb6, 0x66, 0x9f, 0x5e, 0x9e, 0x3b, - 0xfd, 0x00, 0x96, 0x1f, 0x6e, 0xf2, 0x78, 0x3f, 0x12, 0xf2, 0xb0, 0xfb, - 0x2f, 0x51, 0xa6, 0x7e, 0x3d, 0x26, 0x39, 0x37, 0x89, 0x7d, 0x42, 0x87, - 0xca, 0x0d, 0x86, 0xb7, 0x47, 0xf0, 0xbf, 0xff, 0x32, 0xf8, 0x20, 0x45, - 0x8f, 0x37, 0xe4, 0x0b, 0x79, 0xd2, 0x00, 0xd9, 0xae, 0xc3, 0xbc, 0x58, - 0x47, 0xf1, 0xe0, 0x96, 0x26, 0xcf, 0xef, 0x4d, 0x16, 0x33, 0x8c, 0xd7, - 0x1a, 0x29, 0xb3, 0xc0, 0xa8, 0xf2, 0xfd, 0x36, 0xe7, 0x9e, 0x32, 0xd7, - 0x91, 0xde, 0xc4, 0x85, 0xd0, 0x7e, 0x96, 0xbb, 0xa6, 0x4c, 0xf0, 0x1e, - 0xe7, 0x93, 0xdd, 0xde, 0xae, 0x71, 0xe9, 0x99, 0x10, 0x65, 0x94, 0xf2, - 0x9c, 0x77, 0xb7, 0xd9, 0xf7, 0x08, 0x65, 0x34, 0x86, 0xf3, 0x26, 0x2e, - 0xf0, 0x69, 0xc1, 0x26, 0xc6, 0x71, 0xc6, 0x5b, 0x34, 0xed, 0x7c, 0xb7, - 0x64, 0xca, 0xc6, 0x1a, 0xee, 0x7f, 0x6f, 0xf0, 0xea, 0xf8, 0xde, 0xc2, - 0x33, 0x39, 0xb6, 0x94, 0x56, 0x9e, 0x67, 0xf5, 0x19, 0x9e, 0x06, 0xed, - 0xac, 0xc7, 0x73, 0xe6, 0x14, 0xf4, 0x0f, 0x58, 0xd1, 0xd3, 0x11, 0xbf, - 0x88, 0xfe, 0x39, 0x60, 0x7c, 0xd1, 0x62, 0xdb, 0x55, 0x63, 0x71, 0x8c, - 0x49, 0x3f, 0x13, 0x3e, 0xed, 0x05, 0xe3, 0x81, 0xf2, 0x2b, 0x46, 0x76, - 0xe6, 0xaa, 0x91, 0x83, 0x5c, 0xcc, 0xb8, 0x3b, 0x20, 0xcf, 0xd4, 0x17, - 0x1b, 0x6b, 0x27, 0xe3, 0xff, 0x62, 0xb6, 0x27, 0xa6, 0xa1, 0xdb, 0x07, - 0xc0, 0x58, 0xef, 0x2c, 0x5b, 0xd5, 0xd9, 0xce, 0x9b, 0x61, 0x8d, 0x75, - 0x2c, 0x27, 0xed, 0x7b, 0xe5, 0x35, 0xec, 0x77, 0x16, 0x7c, 0x9e, 0x95, - 0x42, 0xb9, 0x24, 0xf9, 0x93, 0xdb, 0xec, 0x61, 0xc4, 0xb8, 0x8b, 0xb4, - 0x13, 0xc3, 0x8a, 0xf4, 0xbd, 0x8d, 0xdd, 0xae, 0x14, 0x6b, 0xd2, 0xc4, - 0xb2, 0x0e, 0xc8, 0x13, 0xea, 0x4a, 0x8b, 0x32, 0x79, 0xe7, 0xb2, 0xfd, - 0x20, 0xbe, 0xed, 0x59, 0xba, 0xa7, 0x19, 0xb9, 0xfe, 0x9e, 0x76, 0x2f, - 0xec, 0x89, 0xd8, 0x01, 0xcc, 0x77, 0x81, 0xf9, 0x2e, 0x30, 0xdf, 0x05, - 0xe6, 0xbb, 0xc0, 0x7c, 0x17, 0xf6, 0xc0, 0x05, 0xee, 0xbb, 0xc0, 0x7d, - 0x17, 0xb8, 0xef, 0x02, 0xf7, 0xdd, 0x2c, 0xce, 0x8e, 0xd8, 0x4e, 0xbb, - 0x71, 0xdf, 0x82, 0xad, 0xf4, 0x7c, 0x9b, 0x9b, 0xb4, 0xbf, 0x00, 0x9d, - 0xb4, 0x5b, 0x64, 0xb8, 0x6b, 0x33, 0xf6, 0x56, 0x87, 0x67, 0x3d, 0x9e, - 0x58, 0xa3, 0xeb, 0x33, 0x5a, 0x77, 0xbe, 0x0a, 0xba, 0x4c, 0x94, 0x7f, - 0x09, 0xb2, 0x59, 0x03, 0x7a, 0x7e, 0x41, 0xfb, 0x15, 0xa7, 0x2c, 0x4f, - 0x36, 0xeb, 0x51, 0xf7, 0x69, 0xd4, 0xd5, 0xa3, 0xcf, 0x21, 0xf4, 0xa1, - 0x5f, 0xd2, 0xa0, 0xeb, 0x82, 0xfd, 0xe8, 0x9f, 0xfc, 0x26, 0xd6, 0x4a, - 0xa2, 0x5f, 0x03, 0xe6, 0x6e, 0x45, 0x9f, 0xcf, 0xa2, 0xcf, 0xcd, 0x28, - 0xd3, 0x9f, 0xdd, 0x82, 0xf2, 0xa7, 0xaa, 0xc6, 0xdc, 0x8a, 0xba, 0xcf, - 0x54, 0xd5, 0xcd, 0xa3, 0x0e, 0x71, 0xb0, 0x7d, 0x51, 0x8f, 0x2b, 0xa2, - 0xdc, 0x5c, 0xd5, 0xe7, 0x12, 0xea, 0x7a, 0x51, 0xf7, 0x3d, 0x3c, 0x11, - 0xff, 0xda, 0xa4, 0xc9, 0x6f, 0xa3, 0x6f, 0x9a, 0x40, 0x7d, 0x58, 0xfb, - 0x97, 0x4f, 0xd2, 0xdf, 0x82, 0x9d, 0xfd, 0x53, 0xcb, 0xf3, 0xc7, 0x9e, - 0xb1, 0x3d, 0x59, 0xf5, 0xcb, 0x3f, 0xaa, 0x2a, 0xb3, 0xef, 0xff, 0x56, - 0xd5, 0xed, 0xda, 0xb8, 0xb4, 0xfc, 0x7e, 0x78, 0xf9, 0x98, 0xe3, 0x55, - 0x7d, 0x5e, 0x6e, 0x5c, 0x5a, 0xfe, 0x7c, 0xcd, 0xf2, 0x31, 0xbf, 0xb5, - 0x61, 0x69, 0xdd, 0xe1, 0xa6, 0xa5, 0x65, 0xfa, 0x7d, 0x31, 0xc4, 0x2d, - 0x7e, 0xff, 0x07, 0x37, 0x79, 0xed, 0xe4, 0x6f, 0xb5, 0x2c, 0x29, 0xe3, - 0x8d, 0xb2, 0x89, 0x73, 0xb8, 0x60, 0x40, 0xe7, 0x6c, 0x33, 0xfd, 0x8a, - 0x91, 0x83, 0x4c, 0x65, 0xcb, 0xfe, 0x7c, 0xd4, 0xe5, 0xea, 0xdc, 0x80, - 0x9f, 0x13, 0xa0, 0x8f, 0x15, 0x85, 0xdc, 0x00, 0x8b, 0x63, 0xc9, 0xa3, - 0x45, 0x59, 0xd4, 0xe1, 0x36, 0xf3, 0x5a, 0x3a, 0x3c, 0xa9, 0x71, 0xeb, - 0x32, 0xe8, 0xac, 0x48, 0x7f, 0xaa, 0x96, 0x76, 0x47, 0xe3, 0x19, 0xb1, - 0xa8, 0x52, 0x09, 0x6d, 0xad, 0xc8, 0xc1, 0xd4, 0x3b, 0x15, 0x51, 0x38, - 0xf8, 0x4d, 0xcd, 0x57, 0xe2, 0xa1, 0x0d, 0xb9, 0x8d, 0x29, 0x3f, 0x2e, - 0x94, 0x3e, 0x45, 0x9f, 0xe4, 0x88, 0x87, 0xb3, 0xc4, 0x22, 0x94, 0xcb, - 0x63, 0xe8, 0xc3, 0xf5, 0xf1, 0x9c, 0x21, 0xb6, 0x5b, 0xca, 0xce, 0xe4, - 0x6d, 0xce, 0xbb, 0x12, 0x5e, 0xfe, 0xd8, 0xa2, 0x2f, 0x68, 0x39, 0x67, - 0x60, 0xf3, 0xd8, 0x46, 0xff, 0xe0, 0x0c, 0x7d, 0x91, 0x80, 0x6f, 0xd3, - 0x11, 0x12, 0x67, 0x11, 0x47, 0xbd, 0x7d, 0xb5, 0xd0, 0xd7, 0x5f, 0xc3, - 0x5e, 0x57, 0xc6, 0xab, 0x76, 0xf3, 0xfa, 0xba, 0xbd, 0x77, 0x41, 0xb7, - 0x7d, 0xd9, 0x5b, 0x29, 0x07, 0x70, 0x45, 0x9d, 0xc5, 0xf3, 0xe5, 0xe4, - 0xb1, 0x22, 0x74, 0x69, 0x4e, 0xc5, 0xbb, 0xfe, 0xb9, 0xd0, 0xaf, 0x49, - 0x9e, 0x9a, 0x82, 0x6c, 0x0f, 0xa9, 0x38, 0x80, 0x31, 0x40, 0x45, 0x76, - 0xa7, 0x86, 0x62, 0xe4, 0x43, 0xc6, 0xbc, 0x1a, 0xa6, 0x1f, 0x31, 0xe7, - 0x92, 0x67, 0x29, 0xb4, 0xa7, 0xc0, 0xdb, 0x7f, 0x95, 0x5c, 0x8c, 0x75, - 0xff, 0x55, 0x99, 0x86, 0xff, 0xa3, 0x7c, 0x22, 0xe5, 0x03, 0xd0, 0xa7, - 0x83, 0xad, 0x2f, 0x93, 0xa7, 0x17, 0xc0, 0x67, 0xdf, 0x2f, 0xb8, 0x4c, - 0xbf, 0x54, 0x96, 0xfa, 0xcf, 0x22, 0x8f, 0x94, 0xfe, 0x19, 0x76, 0xc8, - 0xc4, 0x7c, 0xb4, 0x77, 0xb4, 0x29, 0xac, 0xdf, 0x11, 0xa6, 0xff, 0xe6, - 0xd9, 0xff, 0x10, 0xd6, 0x43, 0x4c, 0x5d, 0xfa, 0x0f, 0x23, 0xef, 0xb6, - 0xd2, 0xb7, 0xc2, 0xfe, 0x89, 0xab, 0x6c, 0x63, 0x5d, 0x44, 0xfb, 0xdc, - 0x51, 0xed, 0x63, 0xdb, 0xda, 0xc7, 0x26, 0x1d, 0x46, 0xc4, 0x4e, 0xfb, - 0xbe, 0x02, 0xcf, 0x0c, 0x67, 0xb3, 0x55, 0xf9, 0x0a, 0xb2, 0xb2, 0xaf, - 0xe0, 0xd3, 0x74, 0x16, 0xfb, 0xa4, 0x6f, 0xa7, 0x72, 0x3f, 0x8d, 0x5e, - 0xbe, 0x89, 0x34, 0xf8, 0x36, 0x53, 0xd9, 0xe6, 0xa3, 0x30, 0x83, 0xd8, - 0xdb, 0x6f, 0x83, 0xd6, 0x3d, 0x92, 0x1d, 0x3f, 0xab, 0x6d, 0x30, 0x63, - 0x07, 0xfa, 0xed, 0x9e, 0xcc, 0x66, 0x53, 0x0d, 0x86, 0x9e, 0xa7, 0x19, - 0x56, 0x33, 0x90, 0x97, 0xe2, 0x5a, 0xf4, 0x6d, 0x7c, 0x3f, 0x67, 0x56, - 0xfb, 0x39, 0xe7, 0xe5, 0xa0, 0xeb, 0xc5, 0x0a, 0xfd, 0xa5, 0x0b, 0xa8, - 0x53, 0xb4, 0xc7, 0xe9, 0x4f, 0x9a, 0x26, 0xfd, 0xc9, 0x24, 0x82, 0x0e, - 0x6f, 0x2f, 0x6d, 0xd8, 0xcb, 0xcc, 0xc2, 0x5e, 0xea, 0x2f, 0x2c, 0xdd, - 0x0b, 0xe9, 0xb7, 0xc1, 0x4f, 0x4b, 0xe3, 0x14, 0xe7, 0xfc, 0x46, 0x98, - 0x18, 0xd6, 0x4f, 0x9f, 0xc8, 0xf5, 0x7c, 0xb1, 0xa5, 0xf3, 0xc2, 0x63, - 0x28, 0x4d, 0x5d, 0xa3, 0x8d, 0xfb, 0xf7, 0xf5, 0xca, 0xd2, 0xd8, 0xce, - 0x3d, 0xfc, 0x09, 0xe6, 0x8c, 0x19, 0x79, 0xe5, 0x9b, 0xd1, 0xcf, 0x41, - 0xdc, 0x5d, 0x7a, 0x05, 0x4f, 0xea, 0x8e, 0x9a, 0x07, 0xfb, 0x8d, 0xaa, - 0xfd, 0x8e, 0xb9, 0x97, 0xd4, 0x1e, 0xa7, 0x4b, 0x3f, 0x90, 0xc2, 0xc9, - 0x1f, 0xc2, 0x26, 0x06, 0x73, 0x75, 0xcc, 0x73, 0x92, 0x57, 0xc5, 0x00, - 0xb6, 0x92, 0x66, 0xe6, 0xe1, 0xbe, 0x17, 0xf6, 0xe2, 0x85, 0x71, 0x9c, - 0xbf, 0xe1, 0xb5, 0xab, 0xf5, 0x7d, 0x9e, 0xd7, 0x04, 0xe8, 0xa9, 0xc0, - 0x47, 0x8d, 0x83, 0x86, 0xe0, 0x98, 0xc7, 0xa4, 0xcf, 0xe5, 0x59, 0xb5, - 0xc7, 0x87, 0xc4, 0xb1, 0xf3, 0xe2, 0xfb, 0x25, 0x5c, 0x9f, 0x78, 0x90, - 0x43, 0x0c, 0xc5, 0xdc, 0xaa, 0xcf, 0x57, 0x9f, 0xa7, 0xd1, 0x0b, 0xd5, - 0xf2, 0x31, 0x8a, 0xd8, 0xab, 0xe0, 0x92, 0x4f, 0xbe, 0xdc, 0xfa, 0x6b, - 0x5f, 0x31, 0xb8, 0x9f, 0x11, 0x95, 0x4f, 0x7c, 0x6d, 0x41, 0x7e, 0x87, - 0x81, 0x2b, 0x9e, 0x3c, 0xbe, 0xaa, 0x79, 0xe3, 0xcb, 0x6d, 0x54, 0xcb, - 0x00, 0x63, 0x43, 0xea, 0x95, 0x2f, 0x23, 0x1d, 0xf6, 0xdd, 0x8a, 0x17, - 0x6c, 0x53, 0x79, 0x46, 0x75, 0xce, 0x83, 0x0b, 0xe7, 0xbc, 0xbe, 0x4a, - 0x66, 0x53, 0xb6, 0xa7, 0xa3, 0xd4, 0x45, 0xe8, 0x34, 0xf8, 0xf5, 0xfc, - 0x12, 0xdd, 0xef, 0xba, 0x46, 0x8e, 0x36, 0x2a, 0xa1, 0xc9, 0x97, 0xc1, - 0xcb, 0x5b, 0x11, 0xbb, 0x88, 0x58, 0x13, 0xc4, 0x28, 0xfa, 0x22, 0x8b, - 0xfe, 0xf1, 0xb4, 0xac, 0xe4, 0x1b, 0x5f, 0xcf, 0x0f, 0xb9, 0x7d, 0x8d, - 0x7e, 0xc8, 0xaf, 0xd6, 0x30, 0x96, 0x99, 0x83, 0x9e, 0x1e, 0xc0, 0xf8, - 0x1a, 0xe7, 0x47, 0xb0, 0x6f, 0xa7, 0xad, 0x5a, 0xc7, 0xc7, 0x8b, 0xa8, - 0x6c, 0x9c, 0xdc, 0xa2, 0x30, 0xc3, 0x9e, 0x58, 0xc4, 0x8c, 0x61, 0x97, - 0xf2, 0xab, 0xf4, 0x34, 0xb6, 0x51, 0x7c, 0x8c, 0x78, 0xd6, 0x62, 0xbe, - 0x67, 0x65, 0x1c, 0xf0, 0x72, 0xba, 0x2b, 0xc7, 0x0a, 0x37, 0x55, 0xf1, - 0x72, 0x25, 0xdc, 0x3c, 0x07, 0xde, 0xa5, 0x11, 0x13, 0x27, 0xcf, 0x88, - 0xec, 0x41, 0x9c, 0x9c, 0x7c, 0x4b, 0xa4, 0x0f, 0xb1, 0x72, 0x72, 0x56, - 0x24, 0x83, 0x78, 0x99, 0xf1, 0xdb, 0x5d, 0xe0, 0x69, 0x2f, 0xe2, 0xe9, - 0x1e, 0x60, 0x6a, 0x0a, 0x18, 0xbb, 0x1d, 0xfc, 0xed, 0x02, 0xbf, 0x6d, - 0xc4, 0x5b, 0x65, 0x39, 0x70, 0x5c, 0x8c, 0x7d, 0x2a, 0x7f, 0x4d, 0x7d, - 0x8f, 0xc1, 0xce, 0x56, 0x2a, 0x87, 0x52, 0xed, 0x88, 0xf5, 0x13, 0xf2, - 0x39, 0x8b, 0xb1, 0xad, 0x61, 0xb5, 0x75, 0x7f, 0x3f, 0x14, 0xf4, 0x6b, - 0xb3, 0xd7, 0xb5, 0x13, 0xcb, 0xf9, 0x9f, 0x53, 0xb6, 0xe2, 0xc5, 0xd0, - 0x6a, 0xfc, 0xdf, 0xb7, 0xc0, 0xff, 0x9e, 0x3a, 0xa9, 0xbb, 0x4b, 0xe5, - 0x16, 0xda, 0xba, 0x0f, 0x11, 0xcf, 0x52, 0xb0, 0xfb, 0xb0, 0xcf, 0x15, - 0xb9, 0x33, 0x75, 0xb5, 0x72, 0xd1, 0xd9, 0x20, 0xf9, 0xed, 0x0f, 0x6a, - 0x4c, 0x3f, 0xf5, 0x87, 0x59, 0xa7, 0x08, 0x1d, 0xf1, 0xf2, 0x88, 0x43, - 0xe3, 0x11, 0x58, 0x0a, 0xfe, 0x35, 0xca, 0x74, 0xef, 0x55, 0x9c, 0xe3, - 0xb6, 0x33, 0x4c, 0x42, 0x11, 0x6b, 0xa6, 0x63, 0x51, 0x95, 0x43, 0xde, - 0xe4, 0xb0, 0xde, 0xc6, 0xb9, 0x0e, 0xc8, 0x34, 0xfc, 0x8b, 0x99, 0x5e, - 0xd0, 0xb8, 0xbd, 0x19, 0xfd, 0xa9, 0x7b, 0xe4, 0xf9, 0x80, 0x0c, 0xc6, - 0xc8, 0xd3, 0x18, 0xfa, 0xef, 0x45, 0x9f, 0x46, 0x3c, 0xff, 0x28, 0x34, - 0x6d, 0x33, 0x9e, 0xfe, 0x3c, 0xca, 0x9c, 0x23, 0x68, 0x5b, 0x77, 0x85, - 0x45, 0xcd, 0xc9, 0x31, 0xcd, 0x0a, 0x03, 0x16, 0xd7, 0xe2, 0x3a, 0x6c, - 0x7b, 0xaf, 0x72, 0x47, 0x77, 0x6f, 0x60, 0xbd, 0x86, 0xc0, 0x7a, 0xbd, - 0x81, 0xf5, 0x48, 0x67, 0x63, 0x80, 0xce, 0x46, 0x8c, 0xff, 0x5d, 0xac, - 0x4d, 0x7e, 0x04, 0xd7, 0xcc, 0x07, 0xd6, 0xf4, 0xf7, 0xd7, 0x1c, 0x18, - 0xf7, 0x0e, 0xd6, 0x63, 0x5d, 0x2c, 0x50, 0x47, 0x1a, 0x9a, 0x50, 0xc7, - 0x72, 0x63, 0x80, 0xae, 0xa8, 0x8a, 0xf7, 0xa7, 0xd5, 0x19, 0x92, 0xcf, - 0x75, 0xb0, 0x6b, 0x26, 0x6c, 0x4b, 0x0d, 0xfc, 0xaf, 0xea, 0xbd, 0x7e, - 0x0d, 0xeb, 0xfa, 0xf3, 0xc5, 0x30, 0x07, 0xfb, 0xb3, 0x6f, 0x48, 0x8f, - 0x67, 0x3d, 0xdb, 0xff, 0xb6, 0xf2, 0x8c, 0xe2, 0x5b, 0x1a, 0xb4, 0x93, - 0xc6, 0x36, 0x99, 0x6a, 0xb4, 0x70, 0x9e, 0xa6, 0xb6, 0xa5, 0xc0, 0xda, - 0xb2, 0x69, 0xb4, 0x77, 0xf3, 0xfc, 0x37, 0x68, 0x4c, 0xad, 0x33, 0xb2, - 0xc7, 0x99, 0x4b, 0xa8, 0xd7, 0xb1, 0x22, 0xe2, 0x13, 0x65, 0x87, 0x7c, - 0x3b, 0x41, 0x3b, 0x44, 0xdf, 0x86, 0x36, 0xf6, 0x9c, 0x7e, 0xc7, 0x13, - 0x72, 0xfc, 0xd0, 0x4c, 0xa3, 0x5c, 0x54, 0x7c, 0xb5, 0x65, 0x7e, 0x81, - 0xaf, 0x61, 0xfd, 0xbd, 0xe6, 0x31, 0xfd, 0x2d, 0x64, 0x3f, 0x7c, 0x27, - 0xbc, 0x97, 0x32, 0xa0, 0x23, 0x21, 0xed, 0xdd, 0xcc, 0x61, 0x14, 0xf1, - 0x74, 0xf0, 0x34, 0xf0, 0x84, 0xcd, 0x42, 0x0c, 0xd2, 0xde, 0xcd, 0x58, - 0x50, 0x40, 0xdb, 0x15, 0x15, 0x07, 0xce, 0x94, 0x6d, 0xe3, 0x4e, 0xd7, - 0xcb, 0x1d, 0xcd, 0x3b, 0xab, 0xe5, 0x8e, 0x1e, 0xa8, 0xc5, 0x79, 0x9c, - 0xf2, 0x73, 0x47, 0xf3, 0xa2, 0x72, 0x47, 0xa7, 0xae, 0x93, 0x3b, 0xca, - 0xac, 0x3d, 0x77, 0xc4, 0xf9, 0x2d, 0xb9, 0xbb, 0xc7, 0x36, 0xbf, 0xa8, - 0x73, 0x47, 0x6f, 0x88, 0x97, 0x3b, 0xba, 0x28, 0x2b, 0xe7, 0x8e, 0x8e, - 0x56, 0xe5, 0x8e, 0x9a, 0x54, 0xee, 0x88, 0xf3, 0x78, 0xb9, 0x23, 0x96, - 0xf3, 0xdd, 0xbf, 0xac, 0x72, 0xe9, 0xf9, 0x6e, 0x60, 0xb0, 0xeb, 0x63, - 0x9c, 0x6d, 0x0c, 0xa8, 0xf8, 0xf2, 0x4a, 0xb8, 0xd9, 0xf1, 0x31, 0x8e, - 0xb6, 0x60, 0xf3, 0x82, 0x3d, 0xf3, 0xf1, 0x6e, 0x54, 0xd9, 0xbd, 0xe5, - 0xf9, 0xc5, 0x7b, 0xaa, 0xf2, 0x8b, 0x03, 0x9e, 0xdd, 0x50, 0x38, 0x37, - 0xa8, 0x71, 0x6e, 0x74, 0xc1, 0xcf, 0x39, 0x59, 0xcb, 0x18, 0x7c, 0xa4, - 0x14, 0xc4, 0x51, 0x4b, 0x8d, 0xf5, 0xf2, 0x2c, 0x8b, 0x18, 0x7a, 0xb8, - 0x0a, 0x43, 0x1f, 0x5b, 0xf1, 0xbb, 0x58, 0x3c, 0xb3, 0xfc, 0xbb, 0x98, - 0x21, 0xcd, 0xf4, 0x39, 0xba, 0xf3, 0xd8, 0x03, 0x63, 0xe6, 0xfd, 0x92, - 0x19, 0xb0, 0x81, 0x45, 0x7e, 0xfe, 0x85, 0xe7, 0xbc, 0x68, 0x63, 0xb2, - 0xe6, 0xc7, 0x97, 0x83, 0x79, 0x48, 0xe5, 0x60, 0xbe, 0x5f, 0x1b, 0xcc, - 0xc1, 0xcc, 0x03, 0xb3, 0x32, 0x16, 0xf3, 0x5b, 0x2b, 0xe7, 0x60, 0x1e, - 0x5a, 0x21, 0x07, 0xf3, 0x5d, 0x59, 0xcc, 0xc1, 0x7c, 0x57, 0xfc, 0x1c, - 0x0c, 0xe7, 0x08, 0x69, 0x9f, 0x56, 0x30, 0xee, 0x02, 0x7e, 0xe7, 0xf1, - 0xf3, 0xf2, 0x32, 0xf3, 0x0b, 0x7b, 0x58, 0x29, 0x2f, 0xf3, 0x6f, 0xb5, - 0x1f, 0x24, 0x2f, 0xe3, 0xd9, 0x04, 0x3f, 0x2f, 0x83, 0x9f, 0x0d, 0x1b, - 0x64, 0x06, 0xf3, 0x32, 0xef, 0x53, 0x37, 0x50, 0xc7, 0x32, 0xeb, 0xa1, - 0x23, 0xb0, 0x53, 0x19, 0xd8, 0x99, 0x69, 0xf7, 0xd7, 0xd5, 0x79, 0xcc, - 0xb8, 0x53, 0xd8, 0x77, 0x02, 0xe7, 0x41, 0x5e, 0xb6, 0x2b, 0x5f, 0x34, - 0x63, 0xc5, 0x8d, 0x6c, 0x27, 0xac, 0xda, 0x38, 0xbf, 0x9d, 0x5b, 0xc6, - 0x50, 0x99, 0xf2, 0x1e, 0x31, 0x0a, 0xd8, 0x4b, 0xdf, 0xf8, 0x94, 0x0c, - 0x95, 0x7d, 0x3f, 0xab, 0x5b, 0x9f, 0xc5, 0x94, 0xd2, 0xd3, 0x69, 0xf0, - 0x00, 0x98, 0xb1, 0x06, 0x9b, 0x75, 0x16, 0x34, 0x07, 0xf7, 0x81, 0x18, - 0xba, 0x07, 0x75, 0xea, 0xdc, 0xe9, 0x6f, 0xfa, 0xb4, 0x24, 0xa8, 0xf3, - 0x6b, 0x98, 0x8f, 0x75, 0x67, 0x55, 0xfc, 0x56, 0xe8, 0xe1, 0x5e, 0x69, - 0xfb, 0xe6, 0x40, 0x1f, 0xea, 0x66, 0x18, 0x33, 0xd2, 0x0e, 0xfa, 0x31, - 0x5d, 0x54, 0xc5, 0x74, 0x9b, 0x15, 0x3f, 0xc8, 0xeb, 0x5f, 0x8b, 0x10, - 0x3b, 0x37, 0x3b, 0xdc, 0xc3, 0x79, 0x8d, 0x7b, 0x2c, 0xfb, 0xb1, 0x23, - 0xdf, 0xc9, 0xa7, 0xa7, 0x54, 0xde, 0x67, 0xda, 0xf5, 0xcf, 0xf0, 0x5b, - 0xd8, 0x3b, 0xcb, 0xbd, 0x72, 0xa1, 0x59, 0x22, 0xb1, 0x34, 0x73, 0xbd, - 0xf4, 0xd5, 0x77, 0x30, 0xf7, 0x50, 0xd3, 0xb4, 0x8a, 0xfe, 0xee, 0x5b, - 0x45, 0x7f, 0xef, 0xae, 0xd2, 0xdf, 0xfe, 0x55, 0xf5, 0xf7, 0xeb, 0x91, - 0xa0, 0xfe, 0xee, 0x5b, 0x45, 0x7f, 0x1f, 0xad, 0xd2, 0xdf, 0x83, 0x37, - 0xa4, 0xbf, 0x3a, 0x36, 0x4e, 0xdd, 0xaa, 0x72, 0xc6, 0xc3, 0x13, 0xc4, - 0xac, 0x4f, 0xeb, 0xdc, 0xd5, 0x4a, 0xbe, 0x98, 0x4f, 0x43, 0x5b, 0xcd, - 0x47, 0xe3, 0x87, 0xfd, 0x23, 0xf6, 0xe9, 0xf9, 0xa3, 0xfd, 0xf0, 0x69, - 0xaf, 0xbd, 0xee, 0x1f, 0x8b, 0x99, 0xf6, 0x7d, 0xc0, 0xad, 0x1f, 0xd1, - 0xda, 0x6b, 0x91, 0x3f, 0xc6, 0x56, 0xf4, 0x07, 0xa2, 0xda, 0x66, 0x4e, - 0x6a, 0x1d, 0xf4, 0xf3, 0x12, 0x41, 0x7d, 0xa6, 0x9c, 0x52, 0x36, 0x7f, - 0x8a, 0x3d, 0x51, 0x3e, 0x7d, 0x0c, 0xd8, 0x52, 0xa5, 0x13, 0x73, 0x52, - 0x00, 0x6e, 0x79, 0x3a, 0x41, 0x39, 0xeb, 0xc4, 0xbe, 0x61, 0x2b, 0xdd, - 0xa7, 0xbd, 0xb3, 0x70, 0xf0, 0x9c, 0xf1, 0x75, 0x3f, 0x81, 0x75, 0xfd, - 0x36, 0xda, 0x1e, 0x07, 0x3e, 0xd9, 0x36, 0xf8, 0x93, 0x2d, 0xc0, 0x19, - 0xd6, 0x2f, 0xcd, 0x73, 0xaf, 0x8e, 0xb1, 0x52, 0x0c, 0xa3, 0xef, 0xe9, - 0x1e, 0x60, 0x4e, 0x0f, 0x71, 0xb3, 0x84, 0xd8, 0x8c, 0x7a, 0x41, 0x5d, - 0xe9, 0xe8, 0xda, 0x6d, 0xd2, 0xe7, 0x7b, 0x12, 0x71, 0xfc, 0x2d, 0x4a, - 0xaf, 0x76, 0x97, 0x3b, 0x66, 0xdf, 0x30, 0xb9, 0x46, 0xa5, 0x92, 0x57, - 0xdf, 0x19, 0xc4, 0x6c, 0xeb, 0xde, 0xb2, 0x8e, 0x36, 0xf3, 0x16, 0x27, - 0xa4, 0xe5, 0x3e, 0x83, 0x77, 0xea, 0xd1, 0xeb, 0xf0, 0x47, 0x78, 0x47, - 0xe1, 0x27, 0x2a, 0x5f, 0x37, 0xed, 0xd2, 0xf7, 0x60, 0xcc, 0xb4, 0x53, - 0xf7, 0xdb, 0xa2, 0xbe, 0xb1, 0x66, 0x53, 0x3b, 0xf4, 0xf7, 0x36, 0xda, - 0xc4, 0x24, 0x31, 0x75, 0xc9, 0x79, 0xf3, 0x8e, 0x47, 0x4e, 0xc5, 0x5c, - 0x1c, 0xaf, 0x7c, 0x7f, 0xc4, 0x49, 0x56, 0xe0, 0xfb, 0x40, 0x44, 0xc7, - 0x97, 0xd4, 0xf9, 0xa8, 0x8a, 0x7d, 0xbd, 0x78, 0x8a, 0xf1, 0xf7, 0xd2, - 0xbb, 0x1d, 0x2b, 0xcb, 0x40, 0xcb, 0x07, 0x90, 0x81, 0xea, 0xf3, 0x8b, - 0x00, 0x8b, 0xfc, 0xf3, 0xf3, 0x7d, 0xac, 0xbf, 0xd0, 0xfb, 0xde, 0xa2, - 0xf5, 0xe9, 0xff, 0xc3, 0x3e, 0x8d, 0xc0, 0x3e, 0x7d, 0x6c, 0xfc, 0xa2, - 0xde, 0xe7, 0xce, 0x2a, 0x6c, 0xec, 0x41, 0xfd, 0xe1, 0x9a, 0x8d, 0x1f, - 0x10, 0x1b, 0xf7, 0xde, 0x10, 0x36, 0xfe, 0x70, 0xdd, 0x5a, 0xb1, 0xf1, - 0xd0, 0x07, 0xc6, 0x46, 0xee, 0x6b, 0x65, 0x3c, 0xda, 0xb7, 0x0c, 0x8f, - 0xfe, 0xe0, 0x13, 0xc4, 0xa3, 0xd5, 0xb0, 0x84, 0xe7, 0xd2, 0xa0, 0x7c, - 0x6c, 0x4f, 0xff, 0xe0, 0x5f, 0xcc, 0x84, 0xe5, 0xc2, 0xbd, 0x11, 0x79, - 0x6d, 0x27, 0xfc, 0x6e, 0xf2, 0x48, 0x9d, 0x07, 0xcb, 0xd1, 0x3a, 0xcf, - 0x36, 0xc6, 0x1b, 0xbd, 0x9c, 0x02, 0xc7, 0xf8, 0x3a, 0x6d, 0xa3, 0x9d, - 0x6d, 0x5b, 0xe4, 0xf5, 0xc6, 0x1b, 0x89, 0x53, 0xf9, 0x8d, 0x66, 0xa5, - 0x38, 0x75, 0xf5, 0x9c, 0xe6, 0x62, 0x9c, 0x4a, 0xac, 0x6d, 0xd4, 0x79, - 0x2c, 0xc6, 0x67, 0xfb, 0x35, 0x7e, 0xf2, 0x1d, 0xf1, 0xb8, 0x8b, 0x58, - 0xdc, 0x45, 0x1c, 0xee, 0x22, 0x46, 0x87, 0x6d, 0x7e, 0x01, 0x32, 0xf7, - 0x6d, 0x17, 0x31, 0xb8, 0x8b, 0x18, 0xdc, 0xed, 0xd2, 0x71, 0x7c, 0xbf, - 0xfe, 0x76, 0xc1, 0xef, 0xfb, 0xcc, 0x83, 0x14, 0x61, 0x57, 0x46, 0x79, - 0x3f, 0xc3, 0xcc, 0xa6, 0xd6, 0xe9, 0xfd, 0xf9, 0x79, 0xfd, 0x56, 0x9d, - 0x5b, 0xda, 0xb4, 0x49, 0xf9, 0x0b, 0xe6, 0x2b, 0x75, 0xde, 0x1d, 0x00, - 0xde, 0x23, 0x79, 0x14, 0xbe, 0x92, 0xba, 0x87, 0x45, 0x3d, 0xad, 0x98, - 0x69, 0xe6, 0x8e, 0xc4, 0x34, 0xd3, 0x77, 0x60, 0xcc, 0x36, 0x2f, 0x66, - 0x89, 0x49, 0xc8, 0x4c, 0xd7, 0x93, 0xa7, 0x86, 0x99, 0x5e, 0xaf, 0xe7, - 0x9a, 0xaf, 0xf3, 0xfc, 0xbd, 0x4e, 0x96, 0x2d, 0x33, 0xfd, 0x59, 0x3e, - 0x71, 0xee, 0x7e, 0xfd, 0x3d, 0x8d, 0x4b, 0xd7, 0x1a, 0x53, 0x18, 0x9f, - 0x4d, 0xdd, 0x8b, 0xf9, 0xd4, 0xfd, 0xa7, 0x05, 0x7e, 0x9b, 0xd7, 0xe4, - 0xf7, 0x98, 0xe6, 0xb7, 0xc7, 0xe3, 0x10, 0xfb, 0xa9, 0xdc, 0x36, 0x79, - 0xed, 0xcf, 0xa7, 0x72, 0x93, 0x58, 0x47, 0xdd, 0x01, 0xc1, 0xb3, 0x62, - 0x49, 0xc3, 0xc0, 0x7d, 0x61, 0x27, 0xb8, 0xae, 0xff, 0x2d, 0x7f, 0x2d, - 0x6b, 0x6e, 0x51, 0xdf, 0x07, 0x3d, 0xbb, 0x31, 0xa6, 0x64, 0xd0, 0x4a, - 0x73, 0x5f, 0xef, 0x43, 0xfe, 0xc6, 0x94, 0xfc, 0xe5, 0x10, 0x67, 0x8d, - 0xf6, 0x74, 0x24, 0x2c, 0x73, 0xba, 0x8e, 0x39, 0xe4, 0xbe, 0xb2, 0x8f, - 0x7d, 0x5c, 0xaf, 0xda, 0xa6, 0x33, 0xff, 0xe7, 0x63, 0x9a, 0xb4, 0x78, - 0x79, 0xc1, 0xb5, 0xde, 0xa9, 0x58, 0xd4, 0xa5, 0xc1, 0x05, 0x5d, 0xaa, - 0xab, 0xd2, 0x25, 0x7f, 0x9f, 0xeb, 0xc5, 0xff, 0xe6, 0xbe, 0xd2, 0x5d, - 0x90, 0xb9, 0x72, 0xe0, 0x1b, 0xcf, 0x82, 0x6c, 0xf0, 0x4e, 0xcc, 0x3d, - 0x90, 0x41, 0x7e, 0xdf, 0xd8, 0x03, 0x3d, 0xaa, 0x54, 0xfa, 0x98, 0x27, - 0xdf, 0xde, 0xaf, 0xef, 0x5b, 0x5c, 0x51, 0x39, 0x12, 0x6b, 0x59, 0x8e, - 0xa4, 0x0f, 0xb2, 0x02, 0x3f, 0x00, 0x3a, 0x98, 0x57, 0x67, 0x49, 0x9f, - 0xa0, 0xfa, 0x1b, 0xd2, 0xc5, 0x7a, 0x8f, 0x0f, 0x9d, 0xf5, 0xde, 0x77, - 0x14, 0x73, 0xd3, 0xd2, 0x32, 0xc7, 0x27, 0xea, 0x3d, 0x59, 0x39, 0x06, - 0xfb, 0xdc, 0x07, 0x59, 0xac, 0x91, 0x9c, 0x9a, 0xef, 0x98, 0xe4, 0x9f, - 0xfd, 0xcf, 0xc6, 0xa5, 0xfd, 0x51, 0x77, 0xd2, 0xef, 0xff, 0x78, 0x55, - 0xff, 0xc7, 0xd1, 0xff, 0x67, 0x55, 0xfd, 0x1f, 0x0f, 0xf4, 0x3f, 0xa1, - 0xfb, 0xd7, 0xa2, 0xbf, 0xd2, 0x83, 0x26, 0xdf, 0x2f, 0x36, 0x1d, 0xc4, - 0xb3, 0xcf, 0xfa, 0x63, 0x4e, 0x04, 0xc6, 0x4c, 0x56, 0xad, 0x31, 0x89, - 0x7e, 0xf1, 0xa6, 0xa5, 0x6b, 0xa0, 0xee, 0x64, 0x8d, 0xfe, 0xbe, 0x47, - 0x9f, 0xe5, 0xa0, 0xce, 0x17, 0xe0, 0x59, 0x0a, 0x7e, 0x33, 0xe2, 0x77, - 0x0a, 0xca, 0x9e, 0xff, 0x8d, 0xc2, 0xbf, 0x93, 0x47, 0xbd, 0xcd, 0x40, - 0x6f, 0x17, 0xfd, 0x1a, 0x4f, 0x2e, 0x83, 0x32, 0x49, 0x9c, 0x28, 0x4a, - 0xc8, 0x29, 0xd3, 0x57, 0x32, 0x0a, 0x33, 0xbe, 0x7d, 0xe2, 0xbd, 0x2b, - 0xde, 0xd7, 0xf5, 0xec, 0x70, 0xd8, 0x99, 0xd3, 0x31, 0xe2, 0xaf, 0x90, - 0x7e, 0xe0, 0xa6, 0x8f, 0x9d, 0x72, 0xcc, 0xd3, 0x1f, 0xca, 0x31, 0xe7, - 0xd7, 0x7a, 0x44, 0x99, 0xd5, 0xeb, 0xf4, 0x2d, 0xc3, 0xb7, 0xc4, 0xb2, - 0x3c, 0x5c, 0x68, 0x0d, 0xf8, 0xd6, 0xbf, 0x80, 0x6f, 0xf7, 0xca, 0x94, - 0x9d, 0x50, 0x79, 0xd0, 0x43, 0x0b, 0x79, 0x81, 0xc3, 0x91, 0x46, 0x87, - 0x79, 0x81, 0xe4, 0xa9, 0x8c, 0x7c, 0xb0, 0xbc, 0xc0, 0xbe, 0x2a, 0x1d, - 0xd9, 0xbb, 0xaa, 0xed, 0xfc, 0xb3, 0xfa, 0xb5, 0xe6, 0x05, 0x1e, 0xa9, - 0xb2, 0x63, 0x87, 0x6e, 0xc0, 0x76, 0xe6, 0x95, 0xed, 0xe4, 0x5e, 0xaf, - 0xe7, 0xcb, 0x7f, 0x25, 0xf2, 0xd1, 0xd8, 0xce, 0xd5, 0x72, 0xe2, 0x41, - 0x7b, 0x40, 0xb9, 0xba, 0xac, 0xfd, 0x6c, 0x3c, 0x67, 0x2e, 0x43, 0x3f, - 0x4d, 0x19, 0x54, 0xb2, 0xcc, 0xb2, 0x1f, 0xff, 0xde, 0xb7, 0x10, 0xff, - 0x2e, 0xc6, 0xac, 0xf0, 0x67, 0xbb, 0xfc, 0xd8, 0x88, 0x7e, 0xb3, 0x6d, - 0x14, 0xdc, 0x3d, 0xe6, 0x90, 0x6a, 0x63, 0x8e, 0xf7, 0x36, 0xf9, 0x9c, - 0xba, 0x27, 0x70, 0x5e, 0xe7, 0xd2, 0xa6, 0x54, 0x4c, 0xc0, 0xef, 0x1c, - 0x85, 0xd4, 0x46, 0xed, 0x03, 0x5e, 0x0f, 0x67, 0x97, 0xc6, 0xcf, 0xa6, - 0x79, 0x04, 0x63, 0x19, 0x3f, 0x7f, 0x21, 0x4a, 0x4c, 0xcd, 0x96, 0x57, - 0x1d, 0x8f, 0x71, 0x1c, 0xcf, 0x3e, 0x2a, 0x56, 0x46, 0xbf, 0x39, 0x3d, - 0xde, 0x8b, 0x95, 0xb3, 0xe5, 0xad, 0x51, 0x0f, 0x17, 0x57, 0x8b, 0x63, - 0x8e, 0x44, 0x99, 0x8b, 0x9c, 0x73, 0xaf, 0x47, 0xeb, 0xf2, 0xd8, 0x3c, - 0xb4, 0x2c, 0x36, 0xb7, 0x74, 0xec, 0x7d, 0xbf, 0x8a, 0xcd, 0x3d, 0x1e, - 0x73, 0x2f, 0xc1, 0xd8, 0xca, 0x01, 0x36, 0xf2, 0x5b, 0x10, 0xb1, 0x82, - 0x3e, 0x0b, 0xe4, 0x67, 0xfc, 0x37, 0x94, 0x1f, 0xb3, 0x5c, 0x7e, 0x3e, - 0x6e, 0xbb, 0xe1, 0xef, 0xfd, 0xb2, 0x78, 0xf9, 0xc5, 0x3d, 0xa0, 0x85, - 0xf1, 0x56, 0x58, 0xcb, 0xc3, 0xcf, 0x69, 0xfc, 0xf6, 0xfb, 0xf9, 0xb9, - 0x86, 0x85, 0x6f, 0xc9, 0xc5, 0xcc, 0x92, 0x1c, 0xcf, 0x16, 0xa6, 0xce, - 0x71, 0xee, 0x99, 0x1b, 0xf8, 0xde, 0xf2, 0x61, 0xee, 0x7c, 0x54, 0xdb, - 0xb9, 0x57, 0x21, 0xfb, 0x09, 0x7d, 0xff, 0xaf, 0x0b, 0x3a, 0xc0, 0x3b, - 0xd0, 0xd5, 0x58, 0xab, 0xee, 0xf9, 0x45, 0x36, 0xa5, 0xf9, 0xed, 0x82, - 0x3e, 0xc1, 0x4f, 0xf4, 0x5e, 0xe3, 0x72, 0x6c, 0xc2, 0xcb, 0xd3, 0x9a, - 0xab, 0xde, 0xf1, 0xbb, 0x04, 0x5e, 0x24, 0x8f, 0xfa, 0x79, 0x5a, 0xd3, - 0xbb, 0xe3, 0x77, 0xf4, 0xa3, 0xbb, 0xe3, 0xc7, 0xf9, 0x2d, 0xd9, 0xbb, - 0xc2, 0x1d, 0xbf, 0xd0, 0x1a, 0xef, 0xf8, 0x6d, 0x54, 0x79, 0x5a, 0xce, - 0xe3, 0xe5, 0x69, 0x59, 0x6e, 0xeb, 0xfe, 0x94, 0xc2, 0xa8, 0xe9, 0x09, - 0xe6, 0x75, 0x1e, 0x5c, 0xf7, 0xc9, 0xe4, 0x75, 0xde, 0x8b, 0x7e, 0xfc, - 0x79, 0x1d, 0x7e, 0x17, 0xf8, 0xb2, 0xf7, 0xdd, 0x5a, 0x6e, 0x24, 0x3f, - 0xf0, 0xe1, 0x72, 0xb0, 0x07, 0x55, 0x0e, 0x76, 0xfb, 0xfa, 0x60, 0x0e, - 0xd6, 0xbc, 0xce, 0x3d, 0xb8, 0x83, 0x2b, 0xe4, 0x60, 0xc3, 0x81, 0x7b, - 0x70, 0x61, 0x7d, 0x0f, 0x6e, 0xa3, 0x83, 0x18, 0x53, 0xe7, 0x5b, 0xcd, - 0x55, 0xef, 0xc1, 0xed, 0x5e, 0xff, 0xe1, 0xf3, 0xad, 0xcb, 0xee, 0xc1, - 0x1d, 0xcd, 0x48, 0x8b, 0x24, 0x6e, 0x28, 0x16, 0xfa, 0x30, 0x71, 0x10, - 0xff, 0x8f, 0x40, 0x0d, 0xf6, 0x0c, 0x99, 0x8f, 0x51, 0x3e, 0x29, 0x77, - 0x69, 0x33, 0x5f, 0xe6, 0x7b, 0x17, 0xcf, 0xc7, 0xe8, 0xef, 0x5c, 0x7a, - 0xb7, 0x62, 0xf1, 0x6e, 0x72, 0x64, 0xe1, 0x6e, 0xf2, 0x18, 0x64, 0xc6, - 0x9c, 0x88, 0xc8, 0x74, 0xc0, 0xb6, 0x8e, 0xba, 0xf0, 0x9b, 0x26, 0x6d, - 0xdd, 0xce, 0xff, 0xa7, 0x82, 0xb8, 0xb0, 0xc4, 0xfb, 0xcc, 0x0d, 0x12, - 0x9a, 0x54, 0x98, 0x1a, 0xf3, 0xfe, 0xaf, 0x4e, 0x1c, 0x7d, 0x78, 0x77, - 0x35, 0x2c, 0x87, 0x62, 0x94, 0x65, 0x5f, 0x8e, 0xbf, 0x05, 0xfe, 0x36, - 0x65, 0x16, 0xcb, 0x31, 0x2d, 0xd7, 0x94, 0x69, 0x5f, 0xfe, 0x62, 0x32, - 0x32, 0x41, 0x59, 0xde, 0xa1, 0xff, 0x9f, 0xc4, 0x39, 0x29, 0x94, 0xcf, - 0xea, 0x78, 0x43, 0x7d, 0x8b, 0x02, 0x1f, 0x5b, 0xb4, 0x0d, 0xc6, 0x73, - 0xa6, 0x85, 0x36, 0x8f, 0xdf, 0x1e, 0xa5, 0x6f, 0x7c, 0x5b, 0x7c, 0x08, - 0x78, 0x37, 0xa8, 0x72, 0x27, 0x37, 0xc2, 0x6f, 0xe3, 0x1a, 0xdf, 0x48, - 0xd7, 0xca, 0x73, 0xdf, 0x5f, 0xbe, 0x8c, 0xfd, 0xb5, 0x40, 0x36, 0xbe, - 0x2a, 0xb9, 0x93, 0xb7, 0x49, 0xdf, 0x89, 0x24, 0xe8, 0x79, 0xbf, 0x52, - 0x48, 0xc1, 0xb7, 0x7e, 0x96, 0x77, 0xe1, 0x80, 0xa1, 0x2e, 0x30, 0x14, - 0xbc, 0x7b, 0x61, 0x99, 0xbf, 0x11, 0xbc, 0x43, 0x97, 0x5a, 0xb8, 0x13, - 0xf5, 0x7c, 0x59, 0x22, 0x8d, 0xa4, 0x7b, 0x62, 0xf1, 0x2e, 0xfc, 0x5c, - 0x39, 0xa7, 0xec, 0xdb, 0x73, 0xe5, 0x25, 0x39, 0x21, 0x75, 0x8e, 0xc3, - 0xa5, 0x97, 0x61, 0xe3, 0x2e, 0x1b, 0xb4, 0x71, 0x63, 0xae, 0xdc, 0x12, - 0x12, 0x9e, 0x89, 0x18, 0xe0, 0x83, 0xba, 0x9b, 0xe2, 0xdd, 0x4d, 0x68, - 0x55, 0x67, 0xfb, 0x7f, 0xd4, 0x5d, 0x7d, 0x6c, 0x5b, 0xd7, 0x75, 0x3f, - 0x7c, 0xa4, 0x3e, 0x4c, 0xcb, 0xd2, 0x93, 0x4c, 0xc9, 0xb4, 0x2d, 0xcb, - 0x8f, 0xd2, 0x93, 0xa5, 0xc4, 0x4a, 0xc1, 0x79, 0xda, 0xaa, 0x01, 0x5a, - 0xc7, 0x52, 0xf4, 0xc7, 0x82, 0x60, 0xa5, 0x65, 0x25, 0xf3, 0xd2, 0x2c, - 0x51, 0x29, 0xdb, 0xc9, 0xfe, 0x18, 0xe0, 0x25, 0xd9, 0x9a, 0xfd, 0x51, - 0xe4, 0x95, 0x94, 0x12, 0x63, 0x56, 0x4d, 0xc6, 0xe6, 0x84, 0x02, 0x0b, - 0x36, 0x56, 0x92, 0x9d, 0x14, 0x50, 0xc0, 0x24, 0x6d, 0x87, 0x2c, 0x6d, - 0x11, 0x55, 0x76, 0xda, 0x7f, 0x8d, 0x2d, 0xc0, 0xb2, 0x2e, 0x69, 0x14, - 0x3b, 0xc8, 0x02, 0x2c, 0x58, 0xbb, 0x6e, 0x28, 0xf6, 0x4f, 0xc7, 0x9d, - 0xdf, 0xfd, 0x20, 0x1f, 0xc9, 0x47, 0x7d, 0x24, 0x6e, 0x81, 0x09, 0x10, - 0xc8, 0xf7, 0xde, 0x7d, 0xef, 0xdd, 0x7b, 0xee, 0xf9, 0xf8, 0x9d, 0x73, - 0xcf, 0xb9, 0x94, 0xba, 0xe2, 0x35, 0x57, 0x6e, 0x49, 0x65, 0x7e, 0x65, - 0xce, 0x89, 0x9c, 0x0f, 0x95, 0x43, 0x0b, 0x9a, 0x3a, 0x27, 0x6d, 0x99, - 0x17, 0x33, 0xb0, 0x80, 0x73, 0x3d, 0x35, 0xf6, 0xaf, 0x95, 0xf9, 0xc0, - 0x14, 0x31, 0x85, 0x69, 0x13, 0x7d, 0xde, 0x2b, 0xf4, 0x81, 0xf7, 0xba, - 0x7c, 0x40, 0xe9, 0xbc, 0x56, 0xa5, 0xa3, 0x36, 0xc2, 0x6f, 0xf2, 0x9d, - 0xfd, 0xe2, 0x9d, 0xdd, 0x4a, 0x67, 0xe9, 0xdc, 0xf7, 0x71, 0x63, 0xba, - 0x08, 0x5f, 0x9b, 0xe9, 0x52, 0x87, 0xdf, 0xac, 0x4d, 0xe8, 0xf8, 0xb9, - 0x3a, 0x3a, 0x56, 0xcb, 0x03, 0xfb, 0xe6, 0x65, 0x9d, 0x2d, 0x69, 0x26, - 0xcf, 0x23, 0x9f, 0x5f, 0xe7, 0x65, 0x48, 0x9a, 0x95, 0xe5, 0xe7, 0x92, - 0x3b, 0x27, 0xa3, 0x42, 0xb3, 0xe9, 0x32, 0xcd, 0xf6, 0xfc, 0x3f, 0xa0, - 0xd9, 0x4d, 0x81, 0x79, 0x5f, 0x29, 0x22, 0xff, 0x6e, 0x58, 0xe4, 0x2e, - 0xac, 0xd2, 0x88, 0xb2, 0xff, 0xee, 0x1a, 0x28, 0xd0, 0x12, 0xba, 0x34, - 0x52, 0x58, 0xa7, 0x98, 0x8c, 0x43, 0x98, 0xa5, 0xd2, 0x77, 0xa2, 0x90, - 0x3f, 0xf8, 0x24, 0xf0, 0x51, 0x10, 0xdf, 0x3b, 0xc9, 0x63, 0xfb, 0x97, - 0x60, 0xd7, 0x06, 0x36, 0xf2, 0xe4, 0x36, 0x7c, 0x94, 0x8a, 0x8d, 0x04, - 0x5e, 0x22, 0x27, 0x6e, 0x57, 0xf2, 0x5e, 0x66, 0xb3, 0x3f, 0x6c, 0x67, - 0x3f, 0x92, 0x69, 0x5c, 0x79, 0xee, 0xd6, 0x7c, 0x14, 0x3c, 0x4f, 0xda, - 0xc9, 0xd9, 0x6c, 0xe5, 0xb9, 0x4e, 0xf9, 0xb9, 0x61, 0x0f, 0x5d, 0x65, - 0xd1, 0xcc, 0xa5, 0x7d, 0x75, 0xf9, 0x6a, 0x95, 0xf1, 0x48, 0x5f, 0x45, - 0x8f, 0xe7, 0xc9, 0x4d, 0xf1, 0xa5, 0xcc, 0x3b, 0xab, 0xe4, 0xf0, 0xd4, - 0xfa, 0x29, 0xfb, 0x5d, 0xf1, 0x19, 0xd0, 0xf8, 0x0f, 0x69, 0x75, 0x12, - 0x7a, 0xae, 0x96, 0xd6, 0xef, 0xff, 0x9a, 0x68, 0x1d, 0xe9, 0xf8, 0xf5, - 0xd2, 0x7a, 0x7f, 0x5d, 0x2c, 0xbc, 0x32, 0x1e, 0x0a, 0x75, 0x6f, 0x0b, - 0xcb, 0xd7, 0xd2, 0x7a, 0x7f, 0xc3, 0x78, 0x6a, 0xe3, 0x5c, 0xcc, 0xea, - 0x78, 0x6a, 0xbf, 0xc1, 0x32, 0x92, 0x65, 0x79, 0x69, 0xa8, 0xe3, 0xff, - 0xce, 0x15, 0x6f, 0x75, 0xeb, 0x79, 0xc8, 0x1a, 0xf9, 0x4e, 0x0e, 0xe9, - 0x77, 0x42, 0xae, 0x22, 0x8e, 0x43, 0xf0, 0x9f, 0xf0, 0x5e, 0xe4, 0x62, - 0xd5, 0xe1, 0x2e, 0x7e, 0x2f, 0xcb, 0xff, 0x0b, 0xcf, 0x0b, 0x9b, 0x25, - 0x63, 0x12, 0x68, 0x1f, 0xf2, 0x9d, 0x11, 0x6d, 0x65, 0x8e, 0x96, 0x8a, - 0x51, 0x28, 0x3f, 0xa0, 0x51, 0x6c, 0xa2, 0xde, 0xfe, 0x6d, 0xcf, 0x6f, - 0xd0, 0xf1, 0x88, 0x83, 0x3c, 0x3f, 0xe1, 0x2a, 0xbf, 0x0b, 0xfa, 0xf4, - 0x3c, 0x63, 0x84, 0xfe, 0x32, 0x3e, 0xa8, 0x9e, 0xa3, 0x59, 0xe1, 0xdf, - 0x69, 0x5d, 0xba, 0x2a, 0x73, 0x6b, 0xc5, 0x79, 0xe0, 0xb5, 0xb2, 0x2e, - 0xad, 0xc1, 0xc3, 0x07, 0x3d, 0xf8, 0xc3, 0xb3, 0x9e, 0x55, 0xcf, 0xa1, - 0x85, 0x9c, 0xfa, 0x84, 0xe7, 0x1c, 0x96, 0xeb, 0xd2, 0x9c, 0x4a, 0x5b, - 0x79, 0x7f, 0x42, 0x8c, 0x6b, 0xea, 0xde, 0x38, 0xea, 0xef, 0xca, 0x35, - 0x51, 0xb5, 0x75, 0x60, 0xb0, 0x0b, 0x5a, 0x1e, 0x75, 0xcd, 0x39, 0x68, - 0xd1, 0xe7, 0x51, 0x07, 0xe6, 0xb6, 0x2d, 0xb8, 0xaf, 0x96, 0x16, 0x15, - 0xbb, 0x32, 0xa7, 0xec, 0xca, 0xa2, 0x4b, 0xaf, 0xd7, 0xe3, 0xf7, 0x2e, - 0x0f, 0xfc, 0xee, 0x55, 0x0b, 0x86, 0x3e, 0x3d, 0xc5, 0x98, 0xe4, 0x33, - 0xc0, 0x24, 0x26, 0x6a, 0xb1, 0x24, 0x2e, 0xc1, 0xf5, 0x1c, 0x63, 0x93, - 0x30, 0xf3, 0xca, 0x6b, 0x74, 0x8e, 0x31, 0xf7, 0x35, 0xba, 0x4b, 0xf9, - 0x69, 0x90, 0x5f, 0x9d, 0x47, 0x8b, 0x5a, 0x06, 0x1f, 0x39, 0x0f, 0x45, - 0x86, 0x63, 0xf4, 0x1a, 0x9d, 0x15, 0xf9, 0x3e, 0x58, 0xff, 0x43, 0x9e, - 0xc4, 0xdd, 0xe2, 0xfd, 0x32, 0xae, 0x71, 0x27, 0xf2, 0x02, 0xb7, 0x5e, - 0x9f, 0xa0, 0xea, 0x05, 0xb9, 0x1d, 0xde, 0xb9, 0xac, 0x64, 0x4a, 0x9c, - 0xe3, 0xfb, 0x9f, 0x32, 0xea, 0xef, 0x8f, 0x19, 0x89, 0x62, 0xc2, 0x88, - 0x2f, 0xa1, 0xdd, 0x53, 0xc6, 0x44, 0x11, 0xbe, 0xa4, 0xe6, 0x91, 0x48, - 0x14, 0xf2, 0xb6, 0x46, 0x9b, 0xaf, 0x53, 0x2c, 0x52, 0x4d, 0xad, 0xc8, - 0x16, 0xfa, 0x7d, 0xac, 0xaa, 0xdf, 0x9a, 0xbe, 0xf8, 0x8e, 0xd8, 0xcf, - 0xcb, 0x4c, 0x53, 0x8d, 0x71, 0x83, 0x88, 0xbd, 0x0f, 0x3b, 0xb4, 0x11, - 0xc6, 0x8d, 0xd4, 0x61, 0xdc, 0xc5, 0x4d, 0xfb, 0xfd, 0x69, 0x65, 0x5c, - 0xd6, 0x7c, 0xfb, 0x6d, 0x81, 0x65, 0xb9, 0xdf, 0x55, 0x38, 0xb7, 0x86, - 0xa7, 0xd0, 0x46, 0xc7, 0xc8, 0x75, 0x4c, 0xac, 0x5d, 0xc5, 0x74, 0x75, - 0x3e, 0x45, 0x50, 0xc5, 0xb4, 0x71, 0x1d, 0xbe, 0xd6, 0x2a, 0xf7, 0x0f, - 0x7e, 0x17, 0xe2, 0x3f, 0x6e, 0xbf, 0xcb, 0x1d, 0xf3, 0xf5, 0xaa, 0x0d, - 0xed, 0xf7, 0xa8, 0x0d, 0x75, 0xcb, 0x59, 0xc0, 0x25, 0x67, 0x61, 0x17, - 0x86, 0xeb, 0x65, 0xff, 0xa5, 0x8d, 0xf5, 0x07, 0xfc, 0x97, 0x20, 0xf9, - 0x2f, 0xbb, 0xfd, 0x97, 0xda, 0x3a, 0x7f, 0xc8, 0x1c, 0x70, 0x9a, 0xf4, - 0x65, 0x12, 0xf9, 0xf2, 0x1e, 0x01, 0x3c, 0xe6, 0x4a, 0x1d, 0xe6, 0x52, - 0x5d, 0xcd, 0xa8, 0x57, 0x7f, 0xfb, 0xea, 0xfa, 0x0b, 0x1b, 0x16, 0x6b, - 0x88, 0xef, 0xbc, 0xfc, 0xab, 0x3b, 0xd5, 0xbf, 0x5a, 0x5d, 0x86, 0x77, - 0xf5, 0x8b, 0x18, 0xb8, 0x53, 0xd6, 0x63, 0x63, 0xb2, 0xbf, 0xd9, 0x6a, - 0x5f, 0xc3, 0x7f, 0x89, 0x14, 0xed, 0xbc, 0xf5, 0xfa, 0xf6, 0xe2, 0x68, - 0x3b, 0x6b, 0x6c, 0xef, 0x78, 0xa7, 0x8c, 0x8f, 0xcd, 0xa9, 0x3c, 0xf2, - 0x6e, 0xe5, 0xf7, 0x6d, 0xc6, 0xeb, 0x38, 0x37, 0xa7, 0x62, 0x8a, 0x11, - 0xab, 0x40, 0xe0, 0xf1, 0xc9, 0xd3, 0x4d, 0xb6, 0xa9, 0xd6, 0xb8, 0xb0, - 0x8e, 0x05, 0x9e, 0xd7, 0xcf, 0x97, 0x35, 0x65, 0x9b, 0xcf, 0x99, 0x55, - 0x37, 0x67, 0x92, 0xaf, 0xe0, 0x6f, 0x21, 0x3f, 0x7a, 0xa4, 0x26, 0x47, - 0xfd, 0xd3, 0xd0, 0xa2, 0xdd, 0x23, 0x6f, 0x1b, 0x79, 0xd7, 0x8d, 0xfa, - 0xb9, 0xee, 0xc2, 0xea, 0xb2, 0x6e, 0x63, 0x95, 0xd0, 0xef, 0x52, 0xe9, - 0xe5, 0x28, 0xb0, 0x69, 0x6f, 0x1d, 0xaf, 0x69, 0xbc, 0x64, 0xba, 0xfa, - 0xf9, 0xf8, 0xc6, 0xfd, 0xac, 0xb1, 0xbf, 0x7b, 0x3d, 0xec, 0x6f, 0x23, - 0x5f, 0x42, 0xec, 0x9d, 0xe2, 0x3b, 0x2a, 0x74, 0x41, 0x1b, 0x2d, 0xe5, - 0x91, 0x4b, 0xfe, 0x1b, 0xa8, 0x67, 0x65, 0x7d, 0xeb, 0xaa, 0xcf, 0xf3, - 0x9e, 0xd3, 0xf2, 0x7a, 0x4b, 0x60, 0x1c, 0xeb, 0x83, 0xc8, 0x41, 0xe9, - 0x62, 0x1d, 0x84, 0xf6, 0x83, 0xd6, 0x0d, 0xc4, 0x80, 0x55, 0x3c, 0x2a, - 0xa1, 0xec, 0xcc, 0xd1, 0x2d, 0xac, 0xbb, 0x6c, 0x4f, 0x5f, 0x47, 0xac, - 0x55, 0xc2, 0x9a, 0x10, 0xf2, 0x9e, 0x9d, 0x76, 0x6a, 0xbf, 0xbf, 0xa5, - 0xc5, 0xbe, 0xd9, 0x29, 0xd7, 0xaa, 0x70, 0xad, 0x8d, 0xae, 0xe6, 0x91, - 0x97, 0x8e, 0x6b, 0x0f, 0xf2, 0x35, 0x2f, 0x7d, 0xf5, 0xb6, 0xe2, 0x25, - 0x60, 0x3a, 0x39, 0x47, 0x05, 0x92, 0x73, 0xb6, 0x4e, 0xf0, 0xa5, 0x4a, - 0xf4, 0x4f, 0xd1, 0xdf, 0x14, 0xfe, 0x5f, 0x65, 0xae, 0xb6, 0xb7, 0x8e, - 0x53, 0x9b, 0x03, 0x31, 0xb9, 0x61, 0x1c, 0xb1, 0xa3, 0x6b, 0xab, 0xeb, - 0x38, 0xb5, 0x39, 0x10, 0x8f, 0x6f, 0x29, 0x8e, 0x18, 0xb1, 0xa6, 0x37, - 0xac, 0x33, 0x70, 0xaf, 0xa9, 0xe8, 0xb5, 0xe4, 0x51, 0x51, 0x7b, 0xeb, - 0xe6, 0x89, 0x3b, 0xb3, 0x9e, 0x0c, 0xde, 0xe8, 0xab, 0xd3, 0x61, 0x77, - 0x60, 0x3d, 0xa0, 0x86, 0xb6, 0x41, 0xcf, 0x58, 0x96, 0xf7, 0xba, 0x31, - 0x72, 0x04, 0x10, 0xc3, 0x2e, 0xd2, 0x99, 0x2b, 0xe0, 0x67, 0x83, 0x39, - 0x6f, 0x80, 0x32, 0x21, 0xd4, 0x52, 0x89, 0xba, 0x28, 0xbd, 0xbe, 0x28, - 0xea, 0xa3, 0xce, 0x88, 0xba, 0xcf, 0xc1, 0xf0, 0x6d, 0xb6, 0x91, 0x67, - 0x8a, 0x6f, 0xd1, 0xd9, 0xa5, 0x20, 0xff, 0x57, 0xf0, 0x7c, 0x7d, 0xed, - 0x67, 0x35, 0xbf, 0xdf, 0x16, 0xfc, 0xde, 0xbb, 0x21, 0xbf, 0x1f, 0x2f, - 0xf3, 0x3b, 0x77, 0x28, 0x28, 0x6b, 0x2b, 0x53, 0x57, 0xda, 0xe9, 0xa8, - 0x78, 0xee, 0x5b, 0xfc, 0x7d, 0x27, 0x1d, 0x35, 0xe5, 0xf7, 0xb3, 0x4b, - 0xac, 0xfb, 0xb3, 0x6f, 0xd1, 0xb9, 0x2b, 0x8e, 0x2f, 0x21, 0xea, 0x32, - 0xdc, 0x7b, 0x86, 0xe8, 0xfb, 0xd1, 0xce, 0x4b, 0x16, 0xea, 0xf5, 0x55, - 0x41, 0xea, 0x2b, 0xba, 0x29, 0x62, 0x20, 0xde, 0xfa, 0x0a, 0xfc, 0x79, - 0x5e, 0xd9, 0xc6, 0xc9, 0x0d, 0x62, 0x1f, 0xf5, 0xbc, 0xd9, 0xe9, 0x81, - 0x91, 0xbf, 0xdb, 0x25, 0xd7, 0xb1, 0x36, 0x8a, 0x81, 0x54, 0xe5, 0x81, - 0xb8, 0xd7, 0xf9, 0xd9, 0x1e, 0x4c, 0xaa, 0x75, 0xf7, 0x9f, 0x76, 0x49, - 0x3b, 0x82, 0x9a, 0xc8, 0x55, 0xa6, 0xc3, 0x3f, 0x30, 0x7e, 0xd9, 0x4f, - 0xcd, 0x97, 0xf5, 0x58, 0xf7, 0x0b, 0x7f, 0xc8, 0x1d, 0xcb, 0x99, 0x55, - 0x35, 0xee, 0x69, 0xd7, 0x98, 0x66, 0x85, 0xdf, 0xf3, 0x49, 0xd6, 0x31, - 0x7b, 0x6b, 0x6c, 0x45, 0x2d, 0xbf, 0x61, 0x3f, 0x16, 0xcc, 0x2f, 0x19, - 0x12, 0x1b, 0x8f, 0x31, 0xe6, 0xdd, 0xee, 0x7a, 0xd2, 0xa7, 0xc5, 0x8d, - 0xb5, 0x7b, 0x7d, 0xd4, 0x7e, 0xc7, 0x3c, 0x48, 0x3f, 0x24, 0xf5, 0x42, - 0x51, 0xe8, 0x82, 0xd9, 0x91, 0x12, 0x4d, 0x44, 0x77, 0x51, 0x6a, 0x84, - 0xdf, 0x3d, 0x66, 0xb3, 0x3f, 0xe6, 0x27, 0x87, 0xe5, 0x37, 0x35, 0xb2, - 0x43, 0xd5, 0xcc, 0xe9, 0x58, 0x7b, 0x8b, 0xc2, 0x90, 0xed, 0x62, 0xdd, - 0x52, 0xee, 0x49, 0xc4, 0xdf, 0x97, 0xf4, 0xb3, 0x71, 0x1e, 0xbc, 0xdb, - 0xac, 0xda, 0x5d, 0x74, 0xb5, 0x43, 0x9b, 0x8b, 0xaa, 0x2d, 0x9e, 0xa9, - 0xb1, 0x86, 0xae, 0xd3, 0x82, 0x1c, 0xae, 0xaa, 0xfa, 0x44, 0xf9, 0xbc, - 0x99, 0xe2, 0x45, 0x6e, 0xd3, 0xa5, 0xae, 0x5f, 0x64, 0xfc, 0x5b, 0x14, - 0x32, 0x22, 0xfb, 0xd2, 0x54, 0xee, 0x8b, 0xc4, 0xed, 0xb8, 0xa7, 0x5d, - 0xe5, 0x62, 0xbe, 0x25, 0xd7, 0x05, 0x54, 0x1f, 0xe4, 0x75, 0xfe, 0x5c, - 0xaa, 0xf6, 0x29, 0xdf, 0x28, 0xea, 0x75, 0x88, 0x8f, 0x7d, 0x33, 0xd9, - 0x77, 0x7c, 0x32, 0xe7, 0xd8, 0x14, 0x6b, 0xa9, 0x32, 0x7f, 0x43, 0x7f, - 0x47, 0xac, 0x19, 0x39, 0x16, 0xc8, 0x9f, 0x70, 0xeb, 0x16, 0x39, 0xb6, - 0x00, 0x6c, 0x50, 0x11, 0x6b, 0xa8, 0x1b, 0xe1, 0xe7, 0xbd, 0xcc, 0x9b, - 0xe6, 0x36, 0x70, 0xe8, 0x56, 0x64, 0xcd, 0xf2, 0x90, 0x35, 0xf7, 0xfb, - 0x51, 0xcb, 0x87, 0x9a, 0x3e, 0x67, 0xd8, 0xa0, 0x12, 0xfb, 0x0a, 0x06, - 0x15, 0x4c, 0x1f, 0x9d, 0xb3, 0x23, 0xd1, 0x25, 0x81, 0x37, 0xef, 0x43, - 0xce, 0xcf, 0xf0, 0x2a, 0x1d, 0x36, 0xcf, 0x92, 0xdc, 0xef, 0xa1, 0xc0, - 0xb6, 0x77, 0x9a, 0xf9, 0xed, 0x2c, 0xfb, 0x1f, 0xce, 0x14, 0xd6, 0x5d, - 0x34, 0xcd, 0xb0, 0x0f, 0x00, 0x3e, 0x2d, 0x9e, 0xa7, 0xe2, 0x6e, 0x0a, - 0xc6, 0xf8, 0x99, 0x16, 0x74, 0x11, 0x3f, 0x27, 0x49, 0x71, 0xf6, 0x93, - 0xe0, 0xb3, 0x4e, 0x4f, 0x45, 0xcc, 0x02, 0x19, 0xdc, 0x16, 0xbe, 0x2b, - 0x9e, 0x83, 0xfb, 0x63, 0x66, 0x13, 0xd5, 0xd6, 0x1c, 0xb7, 0x8b, 0x3a, - 0xcc, 0x9b, 0xd1, 0x7b, 0xc8, 0xe8, 0x81, 0x6e, 0xc2, 0x9c, 0xdd, 0xad, - 0xd6, 0x8b, 0x3a, 0xf8, 0xfb, 0x90, 0xfa, 0x2e, 0xe7, 0x5a, 0x7e, 0xd7, - 0xbc, 0x8c, 0xbf, 0x0f, 0x5b, 0xc8, 0xfe, 0x5d, 0x35, 0x7f, 0xd5, 0xeb, - 0x66, 0xfd, 0x46, 0x90, 0xce, 0x7b, 0xae, 0x9b, 0x6d, 0x54, 0xcb, 0xdb, - 0xb1, 0xc5, 0x5a, 0xde, 0x9f, 0xef, 0x96, 0xf5, 0x71, 0xee, 0xbe, 0xfc, - 0x9c, 0xfb, 0xe2, 0x15, 0x0f, 0x71, 0xeb, 0x5e, 0xad, 0x73, 0x4b, 0xf4, - 0x6f, 0xd1, 0xcf, 0xd2, 0x7a, 0x28, 0xac, 0xf2, 0x99, 0x90, 0xbf, 0x74, - 0x8f, 0xe2, 0x55, 0xad, 0xe7, 0xc9, 0x43, 0xcf, 0x3f, 0x20, 0xf2, 0x8e, - 0xa5, 0x9d, 0xd8, 0xaf, 0xe8, 0x01, 0x9a, 0x85, 0x5d, 0x34, 0xeb, 0x76, - 0xd1, 0xcc, 0x50, 0xdf, 0x77, 0x89, 0xe3, 0xf3, 0x4b, 0xaf, 0x76, 0xc8, - 0x7a, 0x78, 0xac, 0x29, 0x7e, 0x5f, 0x7d, 0xdf, 0x6c, 0xbc, 0x0f, 0x84, - 0x28, 0x28, 0xe2, 0x4d, 0xae, 0xb1, 0xbe, 0x44, 0x64, 0xb3, 0x37, 0x5c, - 0x47, 0x83, 0x6f, 0xb9, 0xce, 0xa3, 0x8f, 0x83, 0xae, 0x3e, 0xf6, 0xbb, - 0xfa, 0x78, 0xb0, 0x41, 0x1f, 0x59, 0x9f, 0xf3, 0x7b, 0xce, 0x16, 0x3f, - 0x69, 0x5f, 0xd1, 0x4f, 0xd4, 0x49, 0x83, 0x9e, 0x3b, 0x29, 0x1d, 0x0a, - 0x2b, 0x3b, 0x11, 0x55, 0xf5, 0x03, 0x5e, 0x7d, 0xfe, 0x31, 0x35, 0x9e, - 0x37, 0x37, 0xaf, 0xba, 0xeb, 0xab, 0x9f, 0xa3, 0x09, 0x59, 0x27, 0xaf, - 0x64, 0xfb, 0x62, 0x83, 0x78, 0x34, 0x72, 0x3b, 0x80, 0x37, 0x84, 0x6f, - 0xb8, 0x4f, 0xee, 0x6f, 0x17, 0xa0, 0xe5, 0x72, 0xad, 0xb2, 0x5f, 0xd5, - 0xf0, 0x3d, 0x1b, 0xba, 0xb3, 0x75, 0xca, 0x38, 0xff, 0x3d, 0x11, 0xcb, - 0x93, 0xeb, 0x48, 0xab, 0xaa, 0xde, 0x3a, 0x62, 0x21, 0x47, 0x60, 0x71, - 0x05, 0x71, 0xd8, 0x46, 0xb5, 0xc9, 0x52, 0x17, 0xa5, 0xca, 0x7b, 0xc2, - 0x14, 0x44, 0x1d, 0x86, 0x8c, 0x8f, 0xc9, 0x1a, 0xe2, 0xc5, 0x95, 0x1b, - 0xa2, 0x6e, 0x37, 0xae, 0x6a, 0x91, 0x53, 0xd4, 0x26, 0x70, 0xed, 0x27, - 0xaf, 0x21, 0xfe, 0x71, 0x68, 0xfb, 0x35, 0xc4, 0xee, 0x7b, 0xb6, 0x57, - 0x43, 0x6c, 0xf2, 0xd8, 0x8d, 0x05, 0x59, 0x43, 0x5c, 0xbd, 0x46, 0x23, - 0x6b, 0x88, 0x53, 0x2e, 0xac, 0x20, 0xf1, 0xf9, 0x4d, 0x57, 0x7e, 0xb7, - 0xac, 0x0f, 0x5e, 0x2c, 0xe3, 0x53, 0x59, 0x1f, 0x2c, 0xf3, 0xc1, 0xdd, - 0x7b, 0xdf, 0xc8, 0xb5, 0x20, 0xf9, 0x9e, 0x5d, 0x35, 0x6b, 0x41, 0xb2, - 0x2e, 0xd8, 0x32, 0xbc, 0xf8, 0x4e, 0xdb, 0x25, 0xec, 0xf7, 0x10, 0x63, - 0xde, 0xdd, 0xd9, 0x60, 0xbf, 0x87, 0x58, 0x83, 0xfd, 0x1e, 0xdc, 0xba, - 0xdf, 0x8d, 0xa7, 0x80, 0x7f, 0x61, 0x17, 0x81, 0x7b, 0xb1, 0x5f, 0x43, - 0x94, 0xce, 0x97, 0x71, 0xe6, 0x3d, 0x94, 0x54, 0x38, 0xf3, 0xfc, 0x92, - 0xd6, 0x47, 0xfd, 0x35, 0xfa, 0xc8, 0x0b, 0x77, 0x46, 0x54, 0xce, 0x8f, - 0x96, 0x57, 0xc7, 0x25, 0xaf, 0x8e, 0x87, 0xbc, 0xe2, 0x1e, 0xa7, 0x41, - 0xbf, 0x41, 0x13, 0xdc, 0x83, 0xff, 0x97, 0xc2, 0xd8, 0xa7, 0x86, 0xe8, - 0x0b, 0xdd, 0x0a, 0xeb, 0xb9, 0xe4, 0xf5, 0x2c, 0xcb, 0xab, 0x3e, 0x8f, - 0xfe, 0x36, 0xc2, 0xfb, 0x1a, 0x1f, 0xee, 0xf7, 0x1d, 0xbb, 0xf2, 0x0b, - 0x91, 0x17, 0x50, 0xed, 0x27, 0x6a, 0x0c, 0x71, 0x48, 0xc8, 0xd2, 0xba, - 0x1f, 0xf9, 0x2b, 0xfa, 0x1c, 0x6a, 0xa7, 0x20, 0x7f, 0x9a, 0x16, 0xcd, - 0x35, 0x38, 0xa3, 0x5d, 0xe1, 0x08, 0x91, 0xff, 0xeb, 0xea, 0xdb, 0x7f, - 0x72, 0xdf, 0xf4, 0x79, 0x6d, 0x33, 0xdf, 0xae, 0x8a, 0x69, 0x54, 0xe7, - 0x4d, 0x22, 0x7e, 0xb4, 0x2b, 0x69, 0xd8, 0x09, 0x91, 0x7f, 0xda, 0x69, - 0x23, 0x56, 0x16, 0x67, 0xd9, 0xef, 0x4c, 0x22, 0xd7, 0xb9, 0xf3, 0x92, - 0x45, 0xa7, 0xb2, 0x57, 0x0f, 0x48, 0x5e, 0x79, 0x5a, 0xec, 0xd3, 0x89, - 0x7d, 0x1d, 0x27, 0xd8, 0x3e, 0xc7, 0x19, 0x60, 0xce, 0x15, 0x5b, 0x68, - 0x91, 0x91, 0xbc, 0xdf, 0x2e, 0x88, 0x58, 0x1f, 0xeb, 0xa4, 0x1c, 0xf6, - 0x6b, 0x35, 0x16, 0x9a, 0xf9, 0xb9, 0x3d, 0xb4, 0x9c, 0x07, 0xcf, 0x35, - 0xa9, 0xfd, 0x53, 0xd0, 0xd6, 0x47, 0x5d, 0xf6, 0xdf, 0x32, 0xed, 0x1e, - 0x11, 0x79, 0x97, 0x8b, 0xb9, 0xa7, 0xe5, 0x67, 0xe1, 0x55, 0xf5, 0x0e, - 0x7e, 0x5f, 0xf1, 0x75, 0x8a, 0x75, 0xb9, 0xf3, 0x00, 0xdd, 0x7f, 0xde, - 0x78, 0xe5, 0xe4, 0xb6, 0xf0, 0x8a, 0x93, 0xac, 0xe0, 0x15, 0xf7, 0xb3, - 0x35, 0x76, 0xf9, 0xe3, 0x1e, 0xb9, 0x9f, 0x05, 0x68, 0xb0, 0x13, 0x58, - 0x2c, 0x09, 0x5a, 0x1a, 0xe3, 0x91, 0x70, 0xdc, 0x3f, 0x46, 0x99, 0xe2, - 0x35, 0x4a, 0xe5, 0x60, 0xe7, 0xf9, 0xb3, 0xf0, 0x37, 0x7b, 0x64, 0x9c, - 0x46, 0xdf, 0x03, 0xbd, 0xb2, 0x9b, 0xdb, 0x37, 0xef, 0x91, 0x39, 0xdb, - 0xee, 0xf3, 0xed, 0x7c, 0xfe, 0xc9, 0x70, 0xf5, 0xf9, 0x1d, 0x7c, 0xbe, - 0x2b, 0x89, 0x39, 0x34, 0x2e, 0x21, 0x36, 0x39, 0x4c, 0x69, 0x9e, 0x9f, - 0x4c, 0x91, 0x6d, 0xeb, 0x65, 0xd6, 0x57, 0x4b, 0xba, 0x5d, 0x37, 0xb7, - 0x0b, 0x89, 0x39, 0x31, 0xb8, 0xcd, 0x6c, 0x76, 0x84, 0xdb, 0xed, 0x27, - 0xff, 0x65, 0x8b, 0x32, 0x4b, 0x9a, 0x57, 0x75, 0x2e, 0xfe, 0x2f, 0xba, - 0x65, 0x6e, 0xd5, 0xae, 0xb0, 0xa4, 0xdf, 0xb0, 0x88, 0x7b, 0x22, 0xb7, - 0xe3, 0x19, 0xc1, 0x87, 0x91, 0x31, 0xab, 0xfc, 0x7e, 0xec, 0x31, 0x26, - 0xf6, 0x7c, 0xe5, 0x31, 0xb0, 0x5e, 0x1c, 0xb7, 0xcd, 0x74, 0x39, 0x6f, - 0x6d, 0x6d, 0x9f, 0xbc, 0x7f, 0x67, 0x8f, 0xdc, 0x7f, 0xb5, 0x53, 0xed, - 0x15, 0xa8, 0x6d, 0xce, 0x17, 0x90, 0xa7, 0x2d, 0x68, 0xe3, 0x5f, 0x80, - 0xbe, 0x34, 0xf8, 0x3b, 0x8f, 0x27, 0x89, 0x3e, 0xf6, 0xf6, 0xe8, 0x3d, - 0x17, 0xe5, 0xb8, 0x4e, 0x70, 0x7f, 0x13, 0x3c, 0x2e, 0x7d, 0x3e, 0xc6, - 0xc7, 0x5e, 0xf3, 0x8b, 0x67, 0x05, 0xf9, 0x39, 0x2c, 0x03, 0x53, 0xc1, - 0x64, 0x6a, 0x58, 0xce, 0x73, 0x25, 0xae, 0x1b, 0x2e, 0xc7, 0x75, 0xe7, - 0xb2, 0xc7, 0x7b, 0x10, 0xcf, 0x30, 0x2e, 0xf1, 0x7c, 0x87, 0x9e, 0xe1, - 0xb6, 0xa8, 0x63, 0x48, 0xf3, 0x67, 0x9b, 0xca, 0xef, 0xa9, 0xe7, 0x15, - 0x99, 0x2f, 0xa1, 0xed, 0x16, 0xee, 0xbd, 0x97, 0x9f, 0x21, 0x6d, 0x57, - 0xe3, 0xf7, 0x50, 0x5d, 0x4e, 0x4c, 0x3d, 0x8f, 0x6d, 0x14, 0x8b, 0x15, - 0xeb, 0x8a, 0x1e, 0x7c, 0xb6, 0x51, 0xac, 0x44, 0xe4, 0x39, 0xfb, 0x26, - 0xea, 0xe4, 0x15, 0x72, 0x1c, 0xa0, 0x27, 0xe6, 0x1d, 0xda, 0xc1, 0x73, - 0xf5, 0x27, 0x06, 0xea, 0x86, 0x4b, 0x24, 0x73, 0x9f, 0x98, 0xc6, 0x59, - 0x7b, 0xf8, 0xac, 0xc1, 0x74, 0xce, 0x3a, 0xa5, 0x80, 0xdd, 0x46, 0xcd, - 0x2c, 0xab, 0xbf, 0x4f, 0x03, 0xec, 0xeb, 0x41, 0x66, 0xed, 0x70, 0x82, - 0x20, 0x6f, 0x11, 0xf3, 0x18, 0xf3, 0xc4, 0x44, 0x11, 0xfc, 0x6c, 0xd0, - 0x63, 0x79, 0xa2, 0x47, 0xf3, 0x03, 0xe6, 0x37, 0xc9, 0xb6, 0x2a, 0xd7, - 0x23, 0x66, 0x9c, 0xfb, 0x91, 0x28, 0xfe, 0x25, 0x7d, 0x24, 0xf6, 0x71, - 0x01, 0x1d, 0xf5, 0xbc, 0xff, 0x39, 0x4d, 0x27, 0xd1, 0xef, 0xad, 0xcb, - 0xe7, 0xa9, 0x6d, 0xc9, 0x67, 0xd0, 0x43, 0x3e, 0x3f, 0x54, 0x7c, 0x53, - 0x62, 0x1e, 0x0d, 0xd2, 0x4c, 0x0e, 0xb9, 0x60, 0x9f, 0x47, 0x0d, 0x66, - 0x2e, 0xc5, 0x7a, 0x29, 0x55, 0xd1, 0x4b, 0x17, 0xe2, 0xfe, 0x18, 0x64, - 0x1c, 0x7b, 0xd1, 0xa9, 0x1c, 0x20, 0x8c, 0x63, 0x1f, 0x0d, 0x2c, 0xec, - 0xe4, 0x7b, 0x69, 0x35, 0x3e, 0x1a, 0x53, 0x7b, 0x15, 0x44, 0xac, 0x09, - 0xd6, 0x8f, 0x73, 0x2c, 0xcb, 0xe9, 0xdc, 0xdd, 0xb4, 0x18, 0xea, 0xa5, - 0xfe, 0x05, 0xbd, 0x7f, 0x0b, 0xc6, 0x3a, 0xd4, 0x2b, 0x75, 0x92, 0x1e, - 0xf7, 0x6f, 0x89, 0x38, 0x85, 0x75, 0xed, 0x57, 0x35, 0xee, 0x9d, 0x9b, - 0xe8, 0xa5, 0x92, 0x92, 0xd9, 0xd2, 0x1b, 0xf1, 0x28, 0x39, 0xf1, 0xd1, - 0xff, 0x15, 0xfc, 0xdf, 0x7f, 0x0d, 0xb5, 0x38, 0xd0, 0xd1, 0x16, 0x25, - 0xb3, 0xb5, 0xb4, 0xe8, 0xe5, 0x71, 0xe3, 0x7a, 0xe9, 0xa7, 0x33, 0xd1, - 0x57, 0x85, 0xed, 0x1f, 0xb8, 0xc6, 0xed, 0x84, 0x6d, 0xd2, 0x7a, 0xc3, - 0x8b, 0x0f, 0xf5, 0xde, 0x9c, 0x9a, 0x17, 0x65, 0xce, 0x27, 0xe3, 0x37, - 0x33, 0xe9, 0xaf, 0xe5, 0xc9, 0x8f, 0xe9, 0xe4, 0xbc, 0x45, 0x93, 0x59, - 0xec, 0x81, 0x38, 0xc6, 0x72, 0xed, 0xb6, 0x17, 0xdc, 0x9e, 0xc0, 0x67, - 0xe3, 0x2c, 0xfb, 0xec, 0xb7, 0xe7, 0x2c, 0x99, 0x7f, 0x27, 0xf6, 0xdb, - 0x6b, 0x11, 0x7a, 0xd4, 0xb4, 0xfb, 0xf7, 0x68, 0x7b, 0x90, 0xca, 0xa1, - 0xce, 0x90, 0x3f, 0x0b, 0xdc, 0x3e, 0xdb, 0x43, 0xa9, 0x3c, 0x9e, 0x03, - 0x7b, 0x87, 0xbe, 0xf3, 0xf1, 0xb2, 0x9c, 0xd7, 0x7e, 0x7e, 0x36, 0xf6, - 0x0e, 0x98, 0x2c, 0x8e, 0x88, 0x1c, 0x3c, 0xe8, 0x66, 0x39, 0x9f, 0xe3, - 0x34, 0xeb, 0xa9, 0x57, 0x14, 0xa6, 0x74, 0xc9, 0x77, 0x4a, 0xc8, 0xf7, - 0xb8, 0x98, 0x8f, 0x54, 0xde, 0x60, 0xbc, 0xa6, 0xe3, 0x0c, 0x5d, 0x7c, - 0x1c, 0x50, 0x3a, 0x04, 0xd7, 0xee, 0xdd, 0x23, 0xf2, 0x13, 0x6d, 0x9c, - 0xc7, 0xe7, 0x38, 0x3d, 0xc3, 0xb8, 0xf3, 0xd9, 0x6c, 0x0b, 0xdd, 0xc8, - 0xb5, 0xd0, 0x9b, 0xb9, 0x5e, 0xba, 0x3e, 0xdf, 0x41, 0xb3, 0x8c, 0x99, - 0x67, 0xed, 0x80, 0x95, 0x66, 0xff, 0xe2, 0x6a, 0x54, 0xe4, 0x10, 0xb1, - 0xdc, 0xa1, 0x3d, 0xf0, 0x5f, 0x7c, 0x2f, 0xf3, 0x1c, 0x63, 0xef, 0x56, - 0xfa, 0x80, 0xdf, 0x99, 0xce, 0xea, 0x9c, 0x07, 0xc4, 0xe3, 0x07, 0xcb, - 0xf8, 0x75, 0x73, 0x1e, 0x31, 0x37, 0xe1, 0x91, 0x71, 0xa1, 0xeb, 0x33, - 0xf3, 0x7c, 0x7d, 0x1e, 0x71, 0x73, 0x4b, 0xc4, 0x24, 0xbe, 0x14, 0x40, - 0x7b, 0x9c, 0xb3, 0x65, 0xce, 0xa4, 0x18, 0x5b, 0x98, 0x8f, 0x41, 0xdb, - 0xb0, 0xa2, 0x43, 0x2b, 0x8f, 0x4f, 0xc6, 0x30, 0x52, 0xcb, 0xad, 0x74, - 0x26, 0xcf, 0x18, 0x24, 0xef, 0x67, 0x1f, 0x06, 0x6d, 0x7f, 0xe7, 0xa0, - 0xde, 0xd3, 0x76, 0x96, 0xfb, 0x9e, 0xce, 0x4b, 0x0c, 0x92, 0x5e, 0x6e, - 0xa7, 0x4c, 0xbe, 0x4d, 0x1d, 0xdf, 0x2d, 0xf2, 0xdd, 0xe5, 0xde, 0x12, - 0xb8, 0xb6, 0x91, 0x7e, 0x43, 0xae, 0x11, 0x6c, 0xaa, 0xf4, 0x4b, 0xa1, - 0x6b, 0xbc, 0xf3, 0x8c, 0xc6, 0xe8, 0x39, 0xb6, 0xb7, 0xfd, 0x97, 0x11, - 0x2b, 0xfe, 0x22, 0xf8, 0xa6, 0x00, 0x1e, 0xeb, 0xbf, 0x8c, 0x7d, 0x9f, - 0xfc, 0x22, 0xf7, 0x68, 0x22, 0x34, 0x2c, 0x6a, 0x46, 0xa4, 0x8c, 0x4e, - 0x89, 0xba, 0xec, 0xef, 0x08, 0xdd, 0x14, 0x71, 0x2c, 0x03, 0x78, 0x24, - 0x12, 0x26, 0x92, 0x39, 0x59, 0xa7, 0xec, 0xce, 0x9b, 0xdd, 0xe3, 0x43, - 0x14, 0xeb, 0x01, 0xdf, 0x4b, 0x99, 0x95, 0x7b, 0x22, 0x90, 0xd0, 0xf7, - 0xe6, 0x21, 0x5d, 0x63, 0xa0, 0x8f, 0xb5, 0xad, 0xd0, 0xc7, 0x6d, 0x35, - 0xd7, 0xcd, 0x9a, 0xeb, 0x1a, 0x7f, 0x63, 0xad, 0x8c, 0xed, 0x3c, 0xc9, - 0x3d, 0x98, 0x52, 0x0b, 0x92, 0xff, 0xcc, 0x43, 0x83, 0xe6, 0xfd, 0x0a, - 0x83, 0xa7, 0x56, 0x06, 0xc2, 0x9d, 0x46, 0x9b, 0x3f, 0x35, 0xf2, 0xaf, - 0xa5, 0x58, 0x12, 0xb8, 0xe8, 0xf5, 0x3d, 0x52, 0xc7, 0xa1, 0x5f, 0x4e, - 0x14, 0xd0, 0x6d, 0x6a, 0xa5, 0x8d, 0x56, 0xc5, 0x9e, 0x63, 0xc0, 0x18, - 0xb8, 0x1f, 0xcf, 0x71, 0xcc, 0x26, 0xc2, 0x3e, 0xf2, 0x90, 0xf1, 0xc3, - 0xe1, 0x6b, 0x3c, 0x9f, 0x89, 0x95, 0xff, 0x29, 0x4d, 0x8b, 0x7d, 0x7a, - 0xd0, 0x96, 0x31, 0xa4, 0xc0, 0xfc, 0x8c, 0x5f, 0xaa, 0xfc, 0xaa, 0x31, - 0xf4, 0xd3, 0xc1, 0x9a, 0x8a, 0x61, 0xbf, 0xc0, 0x32, 0x26, 0xd7, 0xca, - 0x13, 0x35, 0x6b, 0xe5, 0x53, 0x62, 0xad, 0x1c, 0xeb, 0xe4, 0x1b, 0xe5, - 0x2d, 0xea, 0x3c, 0x16, 0x8b, 0x66, 0xaf, 0x08, 0x7d, 0x13, 0x9d, 0xf0, - 0xcb, 0x3c, 0xeb, 0x04, 0xbb, 0x37, 0x86, 0xa8, 0x6d, 0xc0, 0x67, 0xcc, - 0x88, 0xdb, 0x91, 0xe1, 0x35, 0xc6, 0x14, 0x4b, 0xb9, 0x1d, 0x74, 0xbd, - 0xd0, 0xc4, 0x98, 0xef, 0x9f, 0x69, 0xad, 0x40, 0x8c, 0x0d, 0x3b, 0x28, - 0x13, 0x65, 0x5e, 0x1b, 0x0e, 0xf2, 0xbc, 0x32, 0xbe, 0x1d, 0x66, 0xf9, - 0xe3, 0x31, 0x2c, 0xe5, 0x4b, 0xef, 0xa7, 0xa3, 0x31, 0x2b, 0x3e, 0xda, - 0xc6, 0xfe, 0x8b, 0xc9, 0xff, 0x36, 0xff, 0x9f, 0x0b, 0x83, 0x36, 0x8b, - 0xcb, 0xb8, 0xce, 0xd8, 0x27, 0x5b, 0x7a, 0x7f, 0x86, 0xdb, 0xcc, 0x8c, - 0xc2, 0x0f, 0x82, 0xbf, 0x67, 0xf3, 0xbf, 0x6c, 0xb3, 0xc4, 0x7c, 0x97, - 0xbe, 0xe2, 0x84, 0x0d, 0xa1, 0xe3, 0xb1, 0x2f, 0xcd, 0x80, 0xfa, 0x8c, - 0x19, 0x33, 0xdc, 0x97, 0xeb, 0x84, 0x67, 0x58, 0x94, 0x8a, 0x1e, 0x62, - 0x39, 0xe8, 0xe0, 0x4f, 0xd4, 0x6a, 0xed, 0xa4, 0xcc, 0xc8, 0xa0, 0xaa, - 0xd5, 0xfa, 0x59, 0x83, 0x5a, 0x2d, 0xdc, 0xc7, 0x38, 0x60, 0xbe, 0x74, - 0x7b, 0x26, 0xea, 0x7e, 0x2f, 0x19, 0xa9, 0xe8, 0x2e, 0x81, 0x99, 0x96, - 0x96, 0x1f, 0xe6, 0x3e, 0xc4, 0xac, 0xd4, 0x28, 0xf7, 0x35, 0xef, 0xee, - 0x7f, 0xe9, 0xf6, 0x44, 0x14, 0xed, 0xfc, 0x35, 0xed, 0x62, 0x24, 0xda, - 0x2e, 0xa3, 0x7d, 0xe9, 0x97, 0xf1, 0xa8, 0x1e, 0xa7, 0xfb, 0x5e, 0x8c, - 0x07, 0xf2, 0xc5, 0x9f, 0x4b, 0xef, 0xd0, 0xf5, 0x1c, 0xfc, 0x71, 0x43, - 0xd5, 0x5f, 0x59, 0xe4, 0x2c, 0x31, 0x06, 0xbc, 0x72, 0xd0, 0xb7, 0x96, - 0xfb, 0x41, 0x29, 0x55, 0x95, 0xdb, 0x52, 0x1d, 0x73, 0x97, 0x3e, 0x58, - 0x2f, 0xd9, 0x97, 0x60, 0x43, 0x61, 0x3f, 0x9d, 0x92, 0xdf, 0x06, 0xde, - 0x83, 0x6f, 0xf4, 0x34, 0xeb, 0x2f, 0x99, 0x9f, 0xc4, 0xba, 0x94, 0x75, - 0x98, 0x94, 0x9f, 0x44, 0xd5, 0x4f, 0x3c, 0x48, 0x1e, 0xee, 0xaf, 0xe4, - 0x49, 0xba, 0xd6, 0xd8, 0x03, 0xae, 0x35, 0x76, 0xd3, 0x95, 0x27, 0x19, - 0x12, 0xf8, 0xac, 0x82, 0xa9, 0x42, 0x0a, 0x53, 0x01, 0x7b, 0x49, 0xdd, - 0xb6, 0x58, 0xd6, 0x6d, 0xbb, 0x37, 0xd1, 0x6d, 0x5e, 0xbe, 0xea, 0xaa, - 0xd2, 0x23, 0x91, 0x28, 0x6c, 0x0c, 0xf6, 0x59, 0xfa, 0xfb, 0xe2, 0x28, - 0xeb, 0x91, 0x28, 0xeb, 0x91, 0x11, 0xd6, 0x23, 0xc3, 0xac, 0x47, 0x6c, - 0xa6, 0x81, 0xc5, 0x63, 0xff, 0x98, 0xf5, 0x34, 0xec, 0xc7, 0x18, 0x3d, - 0x53, 0x84, 0x4e, 0x1e, 0x61, 0x0c, 0xf4, 0x31, 0xad, 0xcd, 0xb7, 0x33, - 0xff, 0x4a, 0xdc, 0x53, 0xed, 0xd7, 0x60, 0xdf, 0x18, 0xc4, 0x86, 0x7f, - 0x08, 0xbd, 0xf3, 0xb2, 0x43, 0x7d, 0xbe, 0xeb, 0x39, 0xd0, 0x79, 0x0d, - 0x7b, 0x6b, 0xbc, 0x08, 0xd9, 0xc6, 0xbe, 0xc7, 0xdf, 0x1e, 0x1a, 0xe3, - 0xbe, 0xf7, 0xf9, 0x32, 0x3c, 0x2f, 0x8f, 0x47, 0x1d, 0xb3, 0x8b, 0x65, - 0x60, 0x52, 0xc9, 0xc0, 0x64, 0x45, 0x06, 0x9c, 0x34, 0x8f, 0xa4, 0x73, - 0xa1, 0x83, 0x06, 0x8f, 0xc4, 0xf7, 0x76, 0xb2, 0xfc, 0x22, 0x67, 0xa2, - 0xb2, 0xff, 0x90, 0x9f, 0xa6, 0x43, 0x41, 0xb5, 0x6f, 0x91, 0xc5, 0x76, - 0xf3, 0x27, 0x94, 0xc9, 0xbd, 0xcb, 0xb8, 0x84, 0xe5, 0xd4, 0xc4, 0xf1, - 0x45, 0xc4, 0x45, 0xd9, 0x6f, 0x68, 0x15, 0x71, 0xa5, 0x45, 0xd1, 0x16, - 0xc7, 0x91, 0x61, 0xd6, 0x71, 0xd1, 0x55, 0x23, 0x32, 0x16, 0x33, 0x2e, - 0xf7, 0x62, 0x5f, 0xfa, 0x6f, 0x17, 0x1f, 0xeb, 0x95, 0xf5, 0xb9, 0x4f, - 0xed, 0x95, 0xfa, 0x84, 0x79, 0x34, 0x14, 0x13, 0xbe, 0x5b, 0xd3, 0x25, - 0x69, 0x3f, 0x17, 0x79, 0xbe, 0x97, 0xa2, 0xc3, 0x3c, 0xdf, 0x6d, 0xca, - 0x76, 0x3a, 0x7c, 0x5d, 0xd8, 0x65, 0xb6, 0xa1, 0xbd, 0xd8, 0xd3, 0xdf, - 0x8c, 0x47, 0x9f, 0xe2, 0x77, 0x62, 0x1f, 0xa1, 0x2f, 0xe3, 0x79, 0xcc, - 0xbd, 0xd0, 0x1f, 0x3f, 0x61, 0x1b, 0x8d, 0xf7, 0x82, 0x1f, 0xf9, 0x7b, - 0x61, 0x8c, 0x2e, 0x64, 0x75, 0x1f, 0xde, 0x23, 0xe3, 0x39, 0xf4, 0xc3, - 0x47, 0xbb, 0xed, 0xf7, 0x44, 0x4d, 0x88, 0xf1, 0x8d, 0xda, 0x3e, 0x7d, - 0x45, 0xf5, 0x09, 0x7b, 0x79, 0xb6, 0xf0, 0x18, 0x76, 0x13, 0xf6, 0x74, - 0x5a, 0x14, 0x7b, 0x6d, 0x36, 0x0b, 0x9f, 0x75, 0x51, 0xf8, 0x1e, 0x0f, - 0xef, 0xad, 0xec, 0xff, 0x79, 0x57, 0xcd, 0xb9, 0x75, 0xb6, 0x5b, 0x47, - 0x05, 0x46, 0xeb, 0xc7, 0x1e, 0xf4, 0xa2, 0x66, 0xf5, 0x4f, 0xc5, 0x35, - 0x63, 0x01, 0xd7, 0x3e, 0xa7, 0xae, 0x7d, 0x56, 0x60, 0x63, 0x63, 0xbc, - 0x95, 0xf5, 0xa2, 0xe0, 0x77, 0x9e, 0x67, 0x7b, 0x98, 0xf9, 0x3d, 0xbc, - 0xc4, 0xcf, 0x9d, 0x16, 0xf4, 0xd4, 0xf4, 0x00, 0x2d, 0x20, 0x03, 0x6d, - 0x8a, 0xff, 0x23, 0x56, 0xc2, 0xaf, 0xc7, 0xdd, 0x88, 0xce, 0x63, 0xb0, - 0xcf, 0x3c, 0x56, 0x8c, 0xc9, 0xf2, 0xc5, 0x0a, 0x61, 0x5f, 0x7a, 0x1e, - 0xbe, 0x0e, 0xea, 0x5e, 0x0e, 0x20, 0x9f, 0x8a, 0xfb, 0xb0, 0x87, 0x62, - 0x49, 0xf4, 0x0b, 0xed, 0x34, 0x0d, 0xfe, 0xa8, 0x86, 0x16, 0xee, 0xfb, - 0x3a, 0xd4, 0x7d, 0xad, 0x62, 0x2e, 0xc8, 0xc0, 0x7b, 0xf4, 0xbb, 0xf1, - 0x5e, 0xbc, 0x1f, 0xf7, 0xe1, 0x79, 0xf2, 0xb9, 0xdd, 0xac, 0xb7, 0xe3, - 0xa3, 0xf2, 0x59, 0xc6, 0x35, 0x79, 0xad, 0xdb, 0xf6, 0xee, 0xaf, 0x9c, - 0x3f, 0x9f, 0xda, 0x83, 0x08, 0xf3, 0xd7, 0x41, 0x05, 0x11, 0xfb, 0xc4, - 0xb5, 0x3e, 0x9f, 0xf0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xe3, - 0x33, 0xb9, 0x77, 0x84, 0xcf, 0x9e, 0x4e, 0xf6, 0xf9, 0x0a, 0x05, 0x8c, - 0xb7, 0xcf, 0x97, 0x60, 0x19, 0x98, 0xc8, 0xc5, 0x4b, 0x19, 0xa1, 0x6b, - 0x18, 0xeb, 0x76, 0x45, 0xcc, 0x69, 0xa3, 0x47, 0x60, 0x3e, 0x7e, 0x1f, - 0x7f, 0x67, 0x39, 0xcc, 0xb2, 0x1c, 0x66, 0x59, 0x0e, 0xb3, 0x2c, 0x87, - 0xec, 0xab, 0x7e, 0x2b, 0xcb, 0x72, 0xc8, 0xb6, 0xe4, 0x15, 0xb6, 0x25, - 0x52, 0x76, 0x63, 0x2a, 0xbe, 0xa9, 0x65, 0x17, 0xeb, 0x7f, 0x6e, 0x1f, - 0x47, 0xcb, 0x2a, 0xec, 0x37, 0xf9, 0x8e, 0x0f, 0x55, 0xcb, 0xec, 0x0d, - 0x96, 0xd9, 0xa6, 0xf1, 0x1e, 0xba, 0x95, 0xc7, 0x9c, 0x45, 0xac, 0x39, - 0xd6, 0xd5, 0x09, 0x3f, 0xb0, 0x56, 0x80, 0xe5, 0x09, 0x58, 0x33, 0xc2, - 0x74, 0xef, 0xa1, 0xdb, 0xac, 0xaf, 0x6f, 0xe5, 0x21, 0xc3, 0x07, 0xd4, - 0x71, 0x84, 0x65, 0x18, 0xf6, 0xcf, 0xf6, 0xdd, 0xc8, 0x19, 0x8c, 0xc9, - 0x02, 0x66, 0x8a, 0xa0, 0x4f, 0x05, 0x4e, 0xe3, 0x79, 0x5f, 0x65, 0xbd, - 0x8f, 0x18, 0x1e, 0xec, 0xc5, 0x19, 0x1f, 0xdb, 0x8b, 0xf0, 0x75, 0xd6, - 0xa7, 0xe7, 0xf3, 0x36, 0xcb, 0x7d, 0x17, 0xfd, 0x59, 0x1e, 0x76, 0x1a, - 0x34, 0xe2, 0xe3, 0x02, 0x89, 0xd8, 0x98, 0x31, 0x8e, 0xb1, 0x0f, 0x3a, - 0x86, 0xe0, 0x93, 0xdb, 0x98, 0x23, 0xa6, 0xfd, 0x3b, 0x7b, 0xb1, 0x9f, - 0x7e, 0xcc, 0x68, 0x56, 0xb1, 0x46, 0x7c, 0x47, 0xfb, 0x1e, 0x85, 0x4d, - 0x71, 0xdc, 0x68, 0x0d, 0x12, 0xbf, 0x43, 0x11, 0x65, 0x7a, 0xd4, 0xea, - 0xaf, 0x0b, 0x7c, 0xbf, 0xa0, 0xd7, 0x58, 0xdc, 0x8f, 0xfa, 0x72, 0xfa, - 0xaa, 0x7f, 0x7c, 0x8c, 0x9e, 0x2d, 0xa2, 0xdf, 0x97, 0x29, 0x13, 0x82, - 0x3e, 0x8a, 0x44, 0xd7, 0x49, 0xd2, 0xae, 0x95, 0x71, 0xe7, 0x63, 0xde, - 0x3a, 0xce, 0x8a, 0x0b, 0x9c, 0xdc, 0xc2, 0xfa, 0x05, 0xb4, 0xf9, 0x3e, - 0xf3, 0x5a, 0x14, 0x75, 0x69, 0x4a, 0xbf, 0xbd, 0xce, 0x3a, 0x07, 0x73, - 0x86, 0xe3, 0x8d, 0x75, 0xda, 0x9a, 0xd2, 0x69, 0xb6, 0x4b, 0xa7, 0xa5, - 0xcb, 0x3a, 0x8d, 0x79, 0x43, 0xe8, 0xb2, 0xa0, 0xa8, 0x8d, 0x4e, 0xab, - 0xef, 0xc0, 0x87, 0xbb, 0x85, 0xee, 0x62, 0xdd, 0x3f, 0x84, 0x3d, 0xc8, - 0x1c, 0xdf, 0x31, 0xa1, 0x43, 0x34, 0x7f, 0x3f, 0xbc, 0x4f, 0xca, 0x45, - 0xab, 0xd0, 0x07, 0xe9, 0x29, 0xe8, 0x2d, 0xaf, 0xf6, 0x0f, 0x72, 0x3b, - 0xb4, 0xb7, 0xc3, 0x2f, 0xb2, 0x3e, 0x5b, 0x8c, 0xc2, 0xa7, 0x6d, 0x53, - 0xbe, 0x0f, 0xf6, 0x14, 0xc3, 0x5a, 0x17, 0xc6, 0xaa, 0xf5, 0x59, 0xb7, - 0x8a, 0x6b, 0x20, 0x0e, 0x89, 0x39, 0x6f, 0x88, 0x11, 0x2c, 0x60, 0x04, - 0xbe, 0x27, 0xc0, 0xf4, 0x82, 0x7e, 0x61, 0x3b, 0xf0, 0x2e, 0xad, 0x09, - 0xd9, 0x78, 0x57, 0x60, 0x97, 0x0c, 0x5f, 0x9b, 0x19, 0x7d, 0x54, 0xf4, - 0x33, 0xb3, 0x5c, 0xd1, 0x8f, 0x73, 0xd9, 0xf7, 0x60, 0x37, 0x44, 0x5f, - 0x97, 0x86, 0xa4, 0x0e, 0x5c, 0x2c, 0x98, 0xd8, 0xe3, 0x0c, 0x7d, 0xe6, - 0xbe, 0xea, 0x71, 0xa2, 0x1f, 0x5a, 0x1f, 0x6c, 0x45, 0xf6, 0x18, 0xd7, - 0x76, 0x61, 0x8e, 0x1c, 0x17, 0x0f, 0x7d, 0x8f, 0xdf, 0x8f, 0x73, 0x9b, - 0x8f, 0xe7, 0x76, 0x79, 0x3c, 0x88, 0xed, 0xe1, 0x9e, 0x77, 0xe9, 0x96, - 0x1a, 0xcf, 0xad, 0xf2, 0x78, 0xbe, 0xab, 0xc6, 0x43, 0x69, 0x63, 0xbc, - 0x5b, 0xe1, 0xfe, 0x2d, 0x3f, 0xbb, 0x35, 0xce, 0x38, 0x26, 0xbd, 0x0c, - 0x3a, 0xdf, 0xa5, 0xf8, 0xc9, 0x1d, 0x47, 0x75, 0xf7, 0x35, 0x32, 0xbc, - 0xce, 0xfa, 0xf7, 0xb6, 0xc0, 0x31, 0x7d, 0x8c, 0x63, 0x70, 0x9e, 0x32, - 0xd0, 0xd3, 0xe9, 0x10, 0xf6, 0xe1, 0x1d, 0xe3, 0x71, 0xb3, 0x3f, 0x36, - 0xca, 0x9f, 0x22, 0xbe, 0x26, 0xe2, 0xbe, 0xea, 0xfe, 0xaf, 0xd3, 0xed, - 0x79, 0xe8, 0x72, 0xe0, 0x58, 0xb9, 0x57, 0xef, 0xed, 0x15, 0x19, 0xdf, - 0x4d, 0x78, 0xc6, 0x77, 0x11, 0xdb, 0x1d, 0x05, 0xce, 0x37, 0x11, 0x07, - 0x9e, 0x50, 0xbf, 0x5f, 0x92, 0x2e, 0xe2, 0x59, 0x5e, 0x7a, 0x69, 0xcc, - 0x95, 0x1f, 0x87, 0xbc, 0x14, 0x87, 0xf5, 0x8c, 0x6d, 0x36, 0x19, 0x47, - 0x65, 0x9c, 0xb9, 0xa8, 0xb1, 0xd3, 0x09, 0x9e, 0x33, 0x3b, 0x6a, 0x18, - 0x09, 0x11, 0x6b, 0x68, 0xb5, 0xdb, 0xa8, 0x85, 0xed, 0xe8, 0x59, 0xc2, - 0x3e, 0x70, 0x11, 0x0b, 0x6b, 0x00, 0x17, 0x98, 0x27, 0x33, 0xd1, 0x48, - 0xf8, 0x51, 0xe1, 0x97, 0xc2, 0xbe, 0x18, 0xa0, 0x13, 0xd3, 0x1a, 0x7d, - 0xe0, 0xef, 0xcb, 0xd8, 0x0b, 0x34, 0xca, 0xe3, 0x47, 0xfc, 0x78, 0xc0, - 0x7a, 0x93, 0xed, 0xd2, 0x05, 0x11, 0x97, 0x79, 0x9a, 0xd2, 0x2c, 0xa7, - 0xc7, 0x85, 0x9c, 0x1a, 0x7d, 0x2c, 0x45, 0x2c, 0x57, 0xc8, 0x43, 0x18, - 0x44, 0x0c, 0x50, 0xf9, 0x3a, 0x3c, 0xca, 0x15, 0xb5, 0x57, 0x42, 0x12, - 0xba, 0x63, 0xeb, 0x31, 0x89, 0xe4, 0xa7, 0x8e, 0xc5, 0xb8, 0x31, 0x59, - 0xa3, 0xda, 0x51, 0xf8, 0x69, 0x2a, 0x9e, 0x88, 0xfc, 0xf8, 0xf2, 0x6f, - 0xe9, 0xb8, 0xe3, 0x06, 0xe7, 0x44, 0x6e, 0xe8, 0xcb, 0x45, 0x69, 0x83, - 0xd3, 0xec, 0xd3, 0x67, 0x8e, 0xb8, 0x31, 0x49, 0x24, 0x37, 0x21, 0x62, - 0x39, 0xfb, 0x28, 0xbe, 0x30, 0x42, 0x0f, 0x64, 0xa1, 0xc3, 0x68, 0x3d, - 0x6e, 0xe3, 0x57, 0x72, 0x20, 0xe3, 0x23, 0x94, 0x28, 0x82, 0x46, 0x3e, - 0xc6, 0x4a, 0xcc, 0x7b, 0x39, 0xac, 0xef, 0xf3, 0xf7, 0x02, 0x7e, 0x1b, - 0xe6, 0x0f, 0x54, 0xbc, 0xbc, 0x97, 0x26, 0x16, 0xc8, 0x49, 0x45, 0xef, - 0x15, 0x7b, 0x79, 0xa7, 0xa2, 0x43, 0x2a, 0xb6, 0x13, 0xe6, 0xf3, 0x88, - 0x97, 0x59, 0x74, 0x7f, 0x36, 0xe2, 0xa4, 0x48, 0xc6, 0x2c, 0x88, 0xfb, - 0x60, 0xb0, 0xed, 0xdd, 0xcd, 0x3a, 0xe4, 0x94, 0x88, 0x5b, 0x30, 0x52, - 0x99, 0x47, 0x7b, 0xc4, 0x1c, 0xba, 0x08, 0x7e, 0x5a, 0x2a, 0xf7, 0xaa, - 0x6a, 0x5b, 0x22, 0x93, 0x79, 0xc1, 0xfc, 0x6d, 0xdb, 0x89, 0x1a, 0x95, - 0xfb, 0x11, 0xf3, 0x38, 0x25, 0x70, 0x64, 0x1f, 0xfb, 0x3c, 0xa2, 0x5d, - 0x69, 0x46, 0xc4, 0x2f, 0xf8, 0xb8, 0xf0, 0xc8, 0x7e, 0xa9, 0xdb, 0xe4, - 0x79, 0x19, 0xd7, 0xe0, 0x67, 0x16, 0xb8, 0x1f, 0x55, 0xf9, 0xf4, 0xbd, - 0x14, 0xdb, 0x46, 0x9c, 0x69, 0xea, 0x8e, 0xc6, 0x99, 0x98, 0xd6, 0xc5, - 0xcd, 0x6a, 0x1a, 0xb4, 0xff, 0xf7, 0x91, 0xb6, 0xe1, 0x4c, 0x2b, 0x53, - 0xfc, 0x16, 0x08, 0x30, 0x78, 0xa6, 0xf8, 0x3c, 0x7e, 0x03, 0xc7, 0x97, - 0x14, 0xd8, 0x38, 0xcc, 0xd8, 0x06, 0x18, 0x67, 0x40, 0xac, 0x8b, 0xc5, - 0x1e, 0x0a, 0xfb, 0x32, 0x2b, 0x3d, 0xe4, 0x47, 0x3c, 0xce, 0xd6, 0xb9, - 0x1c, 0xad, 0x22, 0xef, 0x5d, 0xae, 0x47, 0xc2, 0x3e, 0x43, 0x27, 0xae, - 0xb3, 0xdf, 0xf0, 0x90, 0xca, 0xb9, 0x41, 0xcd, 0xa6, 0xce, 0xb9, 0xd1, - 0x3a, 0x45, 0xf3, 0x9e, 0x5e, 0xeb, 0x70, 0xff, 0xde, 0x18, 0x64, 0xd7, - 0x8d, 0x29, 0x10, 0x9f, 0x12, 0x73, 0x74, 0x81, 0x48, 0xce, 0x71, 0x65, - 0x1d, 0xa3, 0x85, 0xe7, 0x09, 0xfe, 0x20, 0xe2, 0x7e, 0x8f, 0xf0, 0x27, - 0xd6, 0x23, 0x7e, 0xb4, 0x1f, 0x38, 0xaa, 0xd3, 0x66, 0x9e, 0x19, 0xc5, - 0x71, 0x0f, 0xfb, 0x67, 0x1a, 0xf7, 0xca, 0x58, 0x14, 0xfb, 0x6c, 0x6a, - 0xbe, 0x10, 0x87, 0xea, 0x97, 0x39, 0x4c, 0xd9, 0x08, 0x59, 0x5d, 0xa0, - 0xd3, 0xaf, 0x4a, 0x1e, 0x37, 0x5b, 0xbb, 0xd8, 0x4a, 0x5e, 0x13, 0x7e, - 0x0b, 0x0d, 0xfb, 0x8d, 0x1e, 0x04, 0xed, 0x79, 0x8e, 0xdc, 0x6b, 0x1b, - 0xcf, 0xef, 0xd5, 0xbf, 0xc3, 0x74, 0x67, 0xe6, 0x6d, 0x87, 0xc7, 0xbc, - 0x1d, 0xec, 0x95, 0x6b, 0x67, 0x7f, 0xa1, 0xda, 0x78, 0xe5, 0xb8, 0x3a, - 0x4f, 0x22, 0x0e, 0x55, 0xa9, 0xbf, 0x78, 0x5b, 0xe8, 0x95, 0xfa, 0x58, - 0x78, 0x98, 0xf5, 0xa9, 0x94, 0xe3, 0x53, 0x1e, 0x72, 0xdc, 0x35, 0x0e, - 0xdc, 0xf2, 0xc9, 0xe5, 0x78, 0xb2, 0xa1, 0x1c, 0x4f, 0xf6, 0xca, 0x58, - 0x6c, 0xbd, 0x1c, 0xbf, 0x81, 0xbe, 0x14, 0x37, 0xca, 0x81, 0x44, 0x4d, - 0xbb, 0x3b, 0x56, 0x02, 0x9a, 0xe9, 0x78, 0x09, 0xd6, 0x0d, 0xc1, 0x97, - 0x58, 0x7b, 0x99, 0x32, 0x12, 0xf3, 0xb5, 0x6b, 0xa9, 0x5b, 0xb9, 0x17, - 0xeb, 0x34, 0xb5, 0xf7, 0x02, 0xbb, 0x43, 0x36, 0x22, 0x61, 0x19, 0x0b, - 0xd0, 0xf4, 0xeb, 0xf5, 0x1d, 0xcb, 0x47, 0x9c, 0x02, 0x21, 0xd6, 0x1d, - 0xa2, 0x73, 0x58, 0x9f, 0x56, 0xb1, 0xe4, 0x93, 0x59, 0x49, 0x07, 0xf3, - 0x88, 0xe0, 0x0f, 0xe0, 0xdb, 0x70, 0xd2, 0x9f, 0xe4, 0x39, 0x96, 0x71, - 0xe4, 0xd4, 0x72, 0x58, 0xcd, 0x1b, 0xb7, 0xc5, 0xf3, 0xaa, 0xf6, 0x92, - 0xd7, 0x71, 0x07, 0xcc, 0x57, 0xe4, 0xeb, 0x95, 0xdc, 0x64, 0xd8, 0x86, - 0x12, 0xfd, 0x37, 0xdb, 0x3d, 0xff, 0x11, 0x53, 0xec, 0xe3, 0xf0, 0x46, - 0xf1, 0x08, 0xe3, 0x4d, 0xcc, 0x29, 0x62, 0x90, 0x3a, 0x46, 0xfc, 0xc4, - 0x41, 0x6a, 0x3f, 0xcc, 0x28, 0xc0, 0x20, 0x9b, 0xf1, 0xa5, 0x71, 0x04, - 0xb9, 0xe6, 0x16, 0xdf, 0x83, 0xfd, 0xa8, 0x06, 0xad, 0x04, 0xb5, 0x21, - 0x0e, 0x81, 0xfd, 0xb0, 0xad, 0x74, 0x95, 0x8c, 0x9d, 0x16, 0x32, 0x96, - 0x58, 0x39, 0xad, 0x64, 0xec, 0xb4, 0x8a, 0xc3, 0x9f, 0x56, 0x32, 0x76, - 0x5a, 0xc9, 0xd8, 0x69, 0x25, 0x63, 0xa7, 0x99, 0xcf, 0x07, 0x18, 0xdf, - 0x02, 0x8b, 0xe8, 0x38, 0x68, 0x3b, 0xa5, 0xf2, 0x38, 0x0f, 0xfb, 0x5c, - 0x2b, 0x67, 0xef, 0xf6, 0x49, 0x39, 0x63, 0x6c, 0x22, 0xeb, 0xc9, 0xf8, - 0x5d, 0x98, 0x83, 0x57, 0x98, 0xe6, 0x1f, 0xd3, 0x99, 0x79, 0xf4, 0xd5, - 0x47, 0x13, 0x62, 0x1f, 0xdc, 0x26, 0x8a, 0xbb, 0xb1, 0xb0, 0xc9, 0x63, - 0xcd, 0x4a, 0xdf, 0xcf, 0x31, 0x6c, 0xc1, 0x27, 0xde, 0x7a, 0x15, 0x7c, - 0x32, 0xae, 0xe6, 0xab, 0xd6, 0x2f, 0x6a, 0xa1, 0x64, 0x0e, 0x74, 0x45, - 0xfe, 0xa4, 0xc5, 0x73, 0x23, 0xe8, 0xe4, 0x98, 0x1e, 0x34, 0x38, 0xa9, - 0x68, 0xf0, 0xb8, 0x18, 0x23, 0xf2, 0x0f, 0x11, 0xcb, 0x6c, 0x4c, 0x87, - 0x74, 0x76, 0x80, 0x9f, 0xc3, 0xb2, 0x70, 0x24, 0xcc, 0x3a, 0x69, 0xeb, - 0x74, 0xa8, 0x8c, 0xbd, 0x91, 0xee, 0xd9, 0x6a, 0x5d, 0xce, 0xba, 0xcb, - 0x96, 0x84, 0x95, 0x1d, 0x91, 0xb8, 0x78, 0x87, 0x5d, 0xa2, 0x13, 0xd1, - 0x83, 0xfc, 0x3d, 0x92, 0x74, 0xe8, 0x30, 0x19, 0x9d, 0x25, 0xfa, 0x11, - 0xcb, 0x41, 0x2b, 0xcb, 0xc1, 0x09, 0xe5, 0x97, 0x9c, 0x28, 0xfb, 0x25, - 0x93, 0x07, 0x90, 0x97, 0x91, 0x12, 0xeb, 0x5e, 0x3b, 0xcb, 0xbf, 0xc3, - 0x02, 0x3d, 0xb6, 0x88, 0xfd, 0x28, 0x7a, 0x71, 0x6c, 0xd2, 0x55, 0xf6, - 0xab, 0x63, 0xbe, 0x07, 0x0f, 0x08, 0xec, 0xee, 0x7b, 0x00, 0xf7, 0x9c, - 0x90, 0x7a, 0xcf, 0x47, 0xfe, 0xc1, 0x77, 0x18, 0x4f, 0x94, 0xe8, 0x31, - 0x7e, 0x67, 0x26, 0x77, 0x88, 0x9f, 0xad, 0xf7, 0x96, 0xb0, 0x63, 0x86, - 0x6f, 0x27, 0xf9, 0x3b, 0x1b, 0xbd, 0x3b, 0x22, 0xf8, 0x91, 0xf1, 0xb4, - 0x31, 0x13, 0x7d, 0xaf, 0x34, 0x3d, 0x85, 0x18, 0x3b, 0xe4, 0x24, 0x62, - 0x5a, 0x3e, 0x2f, 0xf9, 0x90, 0x58, 0xa9, 0x92, 0x0b, 0x2b, 0xf3, 0xc2, - 0xff, 0x8b, 0xc7, 0x66, 0x12, 0xd6, 0x4e, 0xe4, 0xf3, 0x93, 0x04, 0x9f, - 0x00, 0xfb, 0x53, 0x58, 0x4c, 0x67, 0xfd, 0x2e, 0x5b, 0xf1, 0xc6, 0x67, - 0x90, 0xe7, 0x96, 0x5b, 0xa4, 0x8d, 0x6d, 0x0e, 0xe2, 0x75, 0x03, 0x0b, - 0x6b, 0x9d, 0x21, 0x51, 0x1b, 0xde, 0xc1, 0x18, 0x49, 0xe7, 0x3e, 0x0f, - 0xf2, 0xf3, 0x11, 0xc7, 0x0b, 0xd0, 0xc4, 0x25, 0xb4, 0x6b, 0xa6, 0xfe, - 0x85, 0xd2, 0xef, 0xf1, 0x75, 0xb1, 0x7e, 0x99, 0xa2, 0x56, 0xb5, 0x36, - 0xa1, 0xf7, 0xad, 0x08, 0xb3, 0xec, 0x55, 0x6a, 0x9f, 0xfb, 0xcb, 0x31, - 0x3d, 0x21, 0x13, 0x35, 0x31, 0xbd, 0xaf, 0x6e, 0x62, 0xaf, 0x36, 0x93, - 0x03, 0xe4, 0xd4, 0xb5, 0x90, 0x8a, 0x55, 0x5a, 0x19, 0xda, 0x6a, 0x4d, - 0xdf, 0x76, 0xef, 0xf1, 0xb5, 0x36, 0x8f, 0x93, 0xf3, 0xa6, 0x1d, 0x54, - 0xfc, 0xd7, 0x4c, 0x67, 0xf2, 0x41, 0xb6, 0xf9, 0xd0, 0xad, 0xa0, 0x97, - 0xbf, 0x17, 0xb5, 0x2e, 0x5f, 0x0a, 0x34, 0xd3, 0xf2, 0x32, 0x72, 0x2d, - 0xfe, 0xf1, 0x80, 0xcc, 0x25, 0x4e, 0x32, 0x5d, 0x0e, 0xb3, 0x7d, 0x34, - 0xd4, 0xda, 0x11, 0xce, 0x41, 0x97, 0x88, 0xdf, 0x21, 0x0a, 0xdc, 0x3b, - 0x14, 0x64, 0xbf, 0x40, 0xae, 0x3d, 0x1c, 0xe5, 0x67, 0x7f, 0x33, 0x9f, - 0x44, 0xbc, 0xcc, 0x3c, 0xce, 0xcf, 0x9f, 0x60, 0x3c, 0x11, 0xa3, 0x66, - 0x5a, 0x5a, 0x6e, 0x66, 0xbf, 0xa0, 0x99, 0xf1, 0xc4, 0x80, 0xd9, 0xef, - 0x13, 0xef, 0x12, 0x75, 0x35, 0x9f, 0x0f, 0x1c, 0x66, 0xbe, 0xc2, 0xbb, - 0xfe, 0x5d, 0xbd, 0xab, 0xf6, 0x1d, 0xff, 0x51, 0xc2, 0xf1, 0x71, 0x3f, - 0x39, 0x37, 0xf0, 0x1b, 0x5c, 0xf3, 0x63, 0x8c, 0x9d, 0x43, 0x94, 0x99, - 0x6f, 0xe2, 0x31, 0x8c, 0xb3, 0x1f, 0x11, 0xe5, 0xe3, 0xfb, 0xc8, 0x29, - 0x4e, 0xd1, 0x5f, 0x15, 0xdd, 0x31, 0xe1, 0xfb, 0xb8, 0xcf, 0xb2, 0xb6, - 0xbf, 0x85, 0xfb, 0xf5, 0x91, 0x5d, 0xab, 0x63, 0x82, 0xe4, 0xff, 0xeb, - 0x10, 0x35, 0x7f, 0x0d, 0xb1, 0x97, 0x12, 0xe5, 0xa2, 0xa8, 0x57, 0x90, - 0xf1, 0xe7, 0xab, 0x22, 0x87, 0x96, 0xef, 0xe7, 0x67, 0xce, 0xa1, 0xdd, - 0x55, 0x8b, 0xae, 0xdb, 0x92, 0xde, 0x3f, 0x08, 0x84, 0xc8, 0xff, 0x12, - 0x72, 0x9f, 0xc4, 0xfe, 0x1a, 0x8e, 0x7d, 0x88, 0xf5, 0xfb, 0xd7, 0x70, - 0x1f, 0x7f, 0xbe, 0x84, 0xe3, 0x20, 0x8f, 0x13, 0xf6, 0x1a, 0xf9, 0x2e, - 0xd0, 0x8b, 0x87, 0xc3, 0xa6, 0xe0, 0xbf, 0xfb, 0x98, 0xa7, 0x9a, 0x44, - 0xac, 0xb1, 0x0b, 0x6d, 0xed, 0xfd, 0xc0, 0x16, 0xce, 0xd0, 0x21, 0x1c, - 0xc7, 0x3a, 0xfd, 0x4c, 0x23, 0xc9, 0x43, 0x18, 0x4f, 0x15, 0x73, 0x07, - 0x8e, 0x0e, 0x11, 0xcf, 0x27, 0xf0, 0xc7, 0x2f, 0xf1, 0x1b, 0x91, 0x4e, - 0x3f, 0xbf, 0x23, 0xc1, 0xef, 0x98, 0xc8, 0xcb, 0x71, 0xcf, 0x15, 0xfd, - 0x24, 0xe3, 0x54, 0x5f, 0xe9, 0xd3, 0xbf, 0xd1, 0x48, 0x3d, 0x78, 0x76, - 0x59, 0x56, 0xf8, 0x7b, 0x3b, 0xdd, 0xca, 0xb7, 0xd1, 0x6d, 0xb5, 0xa6, - 0x75, 0x4b, 0xf8, 0x65, 0xac, 0xc3, 0x93, 0xed, 0xb4, 0xbe, 0xdc, 0x44, - 0xd4, 0x15, 0x14, 0x6b, 0xce, 0xb7, 0xf2, 0x05, 0x7e, 0xff, 0x97, 0xfb, - 0x64, 0x5c, 0xa7, 0xc2, 0x23, 0xb7, 0x3c, 0x78, 0xe4, 0x03, 0xc1, 0x23, - 0x5f, 0xec, 0xdb, 0x98, 0x47, 0x50, 0xf3, 0x0f, 0xde, 0x08, 0x52, 0xb3, - 0xe2, 0x8f, 0x17, 0x99, 0x3f, 0x9e, 0x65, 0xfe, 0x38, 0xd6, 0x80, 0x3f, - 0x8c, 0x1a, 0xfe, 0x38, 0x2e, 0xf8, 0xe3, 0x89, 0xbe, 0x8d, 0xf8, 0xe3, - 0x98, 0x7f, 0xa3, 0x58, 0x93, 0xaf, 0x35, 0xc0, 0xef, 0x9e, 0xb3, 0xf7, - 0x31, 0xaf, 0xdb, 0xb4, 0x34, 0x8f, 0xfa, 0x84, 0xd5, 0xa8, 0x41, 0x3f, - 0x13, 0x3e, 0xd9, 0x9a, 0xf0, 0xf9, 0xc7, 0x45, 0xcd, 0xc1, 0xa2, 0xe0, - 0x2f, 0xb6, 0xff, 0xe3, 0xa8, 0xab, 0xaa, 0x9d, 0x8b, 0x56, 0xba, 0x1e, - 0xc5, 0x5c, 0x58, 0x7a, 0x2e, 0x08, 0xeb, 0xbb, 0x6a, 0xef, 0xc8, 0x40, - 0x3c, 0x4b, 0xce, 0x07, 0xe0, 0xd1, 0x95, 0xb6, 0xc0, 0x44, 0xf6, 0x1b, - 0x7d, 0xc0, 0x7f, 0x99, 0x15, 0x72, 0x9d, 0x0f, 0xf0, 0xf9, 0x90, 0xf8, - 0x6d, 0x2b, 0xc8, 0xca, 0x87, 0xc8, 0x71, 0x64, 0x9e, 0xbc, 0x9e, 0xef, - 0xa5, 0x1b, 0xf9, 0x7d, 0xb4, 0x96, 0xef, 0xa3, 0x37, 0xc5, 0xbe, 0x1a, - 0xb2, 0x36, 0x72, 0x4d, 0xcc, 0x91, 0x41, 0x47, 0x43, 0xdc, 0x66, 0x79, - 0x1f, 0xad, 0x2e, 0x6b, 0xfe, 0x06, 0x6f, 0x83, 0x5f, 0x62, 0x9d, 0xb2, - 0x66, 0xae, 0x9e, 0x67, 0x26, 0xaa, 0x79, 0x46, 0xdc, 0x03, 0x5e, 0xc9, - 0xd4, 0xd5, 0xfa, 0x22, 0x5f, 0x11, 0xb9, 0x7a, 0x41, 0x6a, 0x42, 0xde, - 0xa2, 0x11, 0x19, 0x3e, 0xea, 0x07, 0x86, 0xce, 0xb1, 0xcd, 0xe5, 0x39, - 0xb3, 0x91, 0xe7, 0xd4, 0xc7, 0x78, 0xb8, 0x43, 0xe0, 0xdf, 0xb8, 0x1d, - 0x08, 0x4f, 0x50, 0xe9, 0x69, 0xc3, 0xc6, 0x5e, 0x8f, 0x49, 0x7e, 0x9e, - 0xa1, 0xe2, 0x4d, 0xbb, 0x5c, 0xfc, 0x57, 0x8b, 0x75, 0xb1, 0x96, 0xfc, - 0x10, 0xf7, 0x19, 0x76, 0xb8, 0xb2, 0x5e, 0x43, 0xe5, 0xf5, 0x9a, 0x56, - 0x1e, 0xb7, 0x94, 0xbd, 0x19, 0x9b, 0xdb, 0x15, 0xff, 0x6f, 0x40, 0x75, - 0xeb, 0x41, 0x73, 0x7f, 0x40, 0xf1, 0x25, 0xa0, 0x79, 0x67, 0x19, 0x86, - 0x43, 0x3d, 0xa0, 0x3c, 0x0a, 0x1a, 0x0f, 0x41, 0xcc, 0xf5, 0x1e, 0x5a, - 0x03, 0x12, 0x07, 0x8d, 0x89, 0x20, 0xe6, 0x7a, 0x0f, 0x41, 0xe7, 0x7a, - 0x0f, 0xad, 0xb1, 0x01, 0x97, 0xdb, 0xcd, 0x53, 0x80, 0xe1, 0x3e, 0x85, - 0x19, 0xba, 0xce, 0x51, 0x0d, 0x7a, 0x77, 0x52, 0x0c, 0x78, 0x4c, 0x5b, - 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d, 0xb8, 0x9d, 0xe5, - 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23, 0x80, 0x79, 0x4f, - 0x18, 0x9a, 0xf7, 0x60, 0x73, 0xc7, 0xfc, 0x0c, 0x90, 0x7b, 0x98, 0x6c, - 0xc0, 0x7d, 0x0b, 0x48, 0x79, 0x25, 0x83, 0x56, 0x5e, 0x01, 0xd3, 0x84, - 0x3a, 0x44, 0x7f, 0xd3, 0x7a, 0x0d, 0x79, 0xd8, 0x38, 0x60, 0x13, 0xd0, - 0xdc, 0xe6, 0x29, 0xa4, 0xcc, 0x3d, 0x03, 0xeb, 0x5b, 0xac, 0x6b, 0x1b, - 0x6d, 0xc0, 0x7b, 0xac, 0x17, 0x4d, 0x61, 0x61, 0x58, 0xd2, 0xc3, 0x00, - 0xac, 0x1f, 0x40, 0x69, 0x1d, 0x54, 0x47, 0xc0, 0xd3, 0xbb, 0x40, 0x13, - 0xd0, 0x7d, 0x4e, 0xc0, 0xb6, 0xa8, 0x73, 0xbf, 0x32, 0x78, 0xad, 0x6c, - 0x03, 0xf4, 0xfc, 0xaa, 0x45, 0x3d, 0xde, 0xf2, 0xa0, 0x7c, 0xe6, 0xa4, - 0xc2, 0x40, 0x46, 0x5e, 0x60, 0x83, 0xe6, 0x05, 0x70, 0x38, 0x01, 0xd3, - 0x3a, 0xb0, 0x8c, 0x5a, 0x93, 0x04, 0x34, 0x8f, 0x87, 0xc5, 0xa5, 0x1f, - 0x24, 0xc6, 0x00, 0x15, 0x63, 0x01, 0xf2, 0x65, 0x80, 0x6d, 0x4a, 0x90, - 0x5f, 0x41, 0x79, 0x01, 0x64, 0x36, 0xc8, 0xef, 0xa0, 0xb2, 0x13, 0x94, - 0x17, 0x81, 0xec, 0x25, 0x42, 0x50, 0x3f, 0x03, 0x69, 0x20, 0xbb, 0x79, - 0x8a, 0x08, 0x98, 0x9f, 0x14, 0x20, 0xc4, 0xd0, 0x00, 0xcf, 0x07, 0xc4, - 0x86, 0x31, 0x4c, 0x7d, 0x0c, 0x19, 0xf9, 0x06, 0x62, 0x06, 0x22, 0xdf, - 0xb0, 0x33, 0x1c, 0x10, 0x80, 0x85, 0xd5, 0xff, 0xff, 0xc7, 0x54, 0x58, - 0x80, 0xe9, 0x14, 0xb4, 0x8e, 0xf5, 0xf7, 0xff, 0x03, 0x22, 0x2c, 0x0c, - 0x2d, 0xf0, 0xf5, 0x88, 0x0b, 0xe5, 0x41, 0x65, 0xe8, 0x02, 0x20, 0xab, - 0x0d, 0xde, 0x26, 0x60, 0x01, 0xdf, 0x61, 0xbd, 0x80, 0xe1, 0x17, 0xb0, - 0xcc, 0xfa, 0xff, 0x7f, 0x29, 0x5c, 0x2d, 0x08, 0x00, 0x00, 0xff, 0x88, - 0x78, 0xb5, 0x98, 0x7e, 0x00, 0x00, 0x00 }; + 0xcd, 0x7c, 0x7f, 0x6c, 0x5c, 0xd7, 0x95, 0xde, 0x79, 0x6f, 0x1e, 0xc9, + 0xe1, 0x88, 0xa2, 0x1e, 0xe9, 0x31, 0x3d, 0x8e, 0xb9, 0xc9, 0x0c, 0xe7, + 0x91, 0xa2, 0x4d, 0x26, 0xfb, 0xcc, 0x8e, 0x6d, 0x3a, 0x99, 0xb5, 0xc6, + 0x33, 0x94, 0xad, 0xc4, 0x8c, 0x41, 0x3b, 0xca, 0xd6, 0x28, 0xdc, 0x80, + 0x1d, 0x52, 0x8e, 0xb3, 0x75, 0xbb, 0x8e, 0x1b, 0xa4, 0x89, 0x11, 0x44, + 0x93, 0x21, 0xa5, 0x55, 0x82, 0x21, 0x67, 0x22, 0xd3, 0xdc, 0xfc, 0xb1, + 0x68, 0xc6, 0x43, 0x52, 0x71, 0xb6, 0x23, 0xd1, 0x4e, 0xb2, 0x41, 0x16, + 0xd8, 0xc0, 0x2c, 0x25, 0xcb, 0xc2, 0x22, 0x2d, 0xdc, 0x34, 0x28, 0x82, + 0xec, 0xfe, 0x21, 0xc8, 0xce, 0xc6, 0x29, 0xd2, 0xc2, 0xed, 0x06, 0x8d, + 0x37, 0x48, 0xf2, 0xfa, 0x7d, 0xf7, 0xde, 0x37, 0x1a, 0x8d, 0x68, 0x27, + 0xdd, 0xfe, 0x53, 0x02, 0x83, 0xfb, 0xde, 0xfd, 0x79, 0xee, 0xb9, 0xe7, + 0x9e, 0xf3, 0x9d, 0x73, 0xef, 0xe3, 0x3d, 0x22, 0x31, 0x31, 0x7f, 0xfb, + 0xf1, 0xcb, 0xfc, 0xab, 0x3f, 0x5e, 0xb8, 0xe3, 0x7d, 0xfe, 0xfb, 0xf8, + 0x6e, 0x77, 0x89, 0xc3, 0x34, 0x82, 0x5f, 0x1c, 0xbf, 0x29, 0xf3, 0xbc, + 0xd7, 0x9f, 0x8b, 0xdf, 0x9d, 0x96, 0xc8, 0xfc, 0x7f, 0x13, 0xb1, 0x3a, + 0xca, 0xa2, 0x7b, 0xd4, 0x0f, 0x82, 0xb7, 0xe9, 0xc8, 0xfc, 0xd9, 0xf8, + 0x25, 0xdf, 0xb9, 0xca, 0xff, 0xf3, 0x5f, 0x44, 0x93, 0xad, 0xe6, 0xcd, + 0x9f, 0x44, 0xed, 0x6c, 0xfd, 0x81, 0xbc, 0x27, 0xd1, 0x48, 0x76, 0x6d, + 0x76, 0xc1, 0x13, 0xc9, 0x35, 0x27, 0x92, 0x05, 0xf9, 0x75, 0x50, 0x8a, + 0x3b, 0xc2, 0xfc, 0xdf, 0xcb, 0xfe, 0xea, 0xab, 0xdf, 0xbd, 0x2b, 0xf5, + 0x66, 0x3d, 0x22, 0x51, 0x37, 0xfb, 0x96, 0xb8, 0x63, 0x12, 0x1d, 0x46, + 0x9b, 0x3f, 0x3b, 0x78, 0xc9, 0x96, 0xfe, 0xb0, 0x2f, 0x77, 0x3e, 0x92, + 0x95, 0xb9, 0x63, 0x95, 0xe3, 0x81, 0xed, 0x49, 0xc9, 0xc9, 0x7a, 0xe3, + 0x0d, 0xe9, 0x9b, 0xde, 0xca, 0xdc, 0x25, 0x78, 0x9f, 0x3b, 0xd6, 0x8c, + 0x4a, 0xb9, 0x59, 0xea, 0xb3, 0x3d, 0x0f, 0xa9, 0x44, 0xbb, 0xb3, 0x8b, + 0xd1, 0x8b, 0x1e, 0xc7, 0xfe, 0x21, 0xc6, 0xbe, 0x45, 0xba, 0xbc, 0x20, + 0xd8, 0xc2, 0xd8, 0xf7, 0x35, 0x7f, 0x1d, 0x3c, 0xe7, 0xe8, 0x71, 0xed, + 0xec, 0x93, 0x11, 0xa6, 0x56, 0xf6, 0xf2, 0x03, 0x23, 0x4d, 0xbe, 0x7b, + 0x3d, 0x9a, 0x4e, 0x37, 0x06, 0x3a, 0xa3, 0x4e, 0x76, 0x2e, 0xb6, 0x8c, + 0xb4, 0x2b, 0xfb, 0xe8, 0xed, 0x5b, 0xaa, 0xde, 0xeb, 0xa6, 0xde, 0x13, + 0x5d, 0xba, 0xdd, 0xf8, 0xec, 0x58, 0x93, 0x69, 0x66, 0x76, 0x54, 0xa5, + 0xd9, 0xd9, 0xb4, 0x4a, 0x73, 0xb3, 0x23, 0x2a, 0x9d, 0x99, 0xf5, 0x54, + 0xfa, 0xb7, 0x0f, 0xe8, 0xfc, 0x37, 0x1e, 0x48, 0xaa, 0xf4, 0x67, 0x26, + 0x7d, 0xd3, 0xa4, 0x3f, 0x37, 0xe9, 0x5b, 0x26, 0xfd, 0x95, 0x49, 0x65, + 0x56, 0xa7, 0x8e, 0xe9, 0x27, 0x6a, 0xde, 0xfb, 0x4c, 0xea, 0x9a, 0x34, + 0x6e, 0xd2, 0x84, 0x49, 0x87, 0x0d, 0x5d, 0x49, 0x93, 0x7a, 0x26, 0x9d, + 0x34, 0xe5, 0xbe, 0xa1, 0x77, 0x1a, 0xf4, 0x7e, 0xa1, 0xcb, 0xc8, 0x2a, + 0xe6, 0x9d, 0x94, 0x85, 0x8a, 0x23, 0xe5, 0x6a, 0x44, 0x0a, 0x6a, 0x0d, + 0x1f, 0xd9, 0x2f, 0x31, 0x47, 0x96, 0xb6, 0xa3, 0x72, 0x59, 0x89, 0xe8, + 0x1b, 0xc1, 0x77, 0x0f, 0x4a, 0xc9, 0xce, 0xba, 0xf2, 0xc2, 0x76, 0x5c, + 0x5e, 0xda, 0x16, 0x6b, 0x2e, 0xd3, 0x2b, 0xf6, 0xe9, 0x77, 0x49, 0xce, + 0xb5, 0x24, 0xa2, 0x78, 0x9a, 0x94, 0x7c, 0x65, 0x08, 0xef, 0xa9, 0x84, + 0xc8, 0xe9, 0xfd, 0x7a, 0xfd, 0xa2, 0x12, 0x59, 0xe7, 0x9a, 0x3c, 0x3d, + 0x7b, 0x71, 0x2d, 0x21, 0xce, 0xea, 0x24, 0xc6, 0xe8, 0x93, 0xae, 0x75, + 0x19, 0x8e, 0xc8, 0x68, 0xe2, 0x31, 0xd4, 0x98, 0x69, 0x3a, 0x72, 0xb8, + 0x69, 0x89, 0xe3, 0x45, 0x21, 0x1f, 0x7d, 0xf8, 0xb9, 0xf8, 0xc5, 0xf1, + 0x4b, 0xe0, 0xf7, 0x97, 0xe8, 0x67, 0x58, 0x0a, 0x4d, 0xf6, 0x89, 0x71, + 0xab, 0x18, 0xbf, 0x9a, 0x72, 0xe7, 0x85, 0x74, 0x25, 0xe4, 0xbb, 0x07, + 0x49, 0x97, 0x4b, 0x7a, 0x40, 0x5b, 0xd4, 0xca, 0xaf, 0xc9, 0x93, 0x05, + 0x5f, 0x92, 0xb6, 0x17, 0x93, 0xa2, 0x6b, 0x25, 0x17, 0xc7, 0x07, 0xa5, + 0x74, 0x14, 0xe5, 0x55, 0xc9, 0xd9, 0xe8, 0xbf, 0xe8, 0xca, 0xbc, 0x2e, + 0x63, 0xde, 0x5b, 0xd8, 0xab, 0x29, 0x97, 0x42, 0xfb, 0x52, 0xf5, 0xdb, + 0x78, 0x66, 0x7f, 0xff, 0xe0, 0x68, 0xba, 0x7f, 0x81, 0x77, 0xe6, 0xff, + 0x7d, 0x9f, 0x7e, 0xe7, 0x33, 0xeb, 0x86, 0xe3, 0x86, 0xf3, 0xe5, 0xf8, + 0xe3, 0x98, 0x33, 0x69, 0x08, 0xe7, 0x2c, 0xa5, 0x2e, 0xd0, 0xd2, 0x58, + 0xeb, 0xb3, 0x36, 0xd6, 0x26, 0xe5, 0x64, 0xf5, 0x1e, 0xc9, 0xfb, 0x41, + 0xb0, 0xe0, 0x4b, 0xdc, 0x96, 0x51, 0xb7, 0x80, 0x0a, 0xbb, 0x4d, 0xb1, + 0x1a, 0x15, 0x89, 0xf6, 0x80, 0x2f, 0x3f, 0x59, 0x63, 0xdf, 0x0e, 0xf2, + 0x86, 0x50, 0xbf, 0xdf, 0xda, 0x5c, 0x03, 0xfd, 0x59, 0xf2, 0x27, 0x08, + 0x96, 0xfd, 0xd1, 0xc4, 0x22, 0xc6, 0x3c, 0xdf, 0x1c, 0x9d, 0xbe, 0x22, + 0x2e, 0xfa, 0x1c, 0x44, 0x1d, 0xf2, 0x8a, 0x7d, 0xb1, 0x4f, 0xf6, 0xd7, + 0x87, 0xb6, 0x71, 0x94, 0x91, 0xae, 0x20, 0xc8, 0xfb, 0x2e, 0xdf, 0x65, + 0x07, 0xfc, 0xdb, 0x21, 0xff, 0x62, 0xc3, 0xf2, 0x4a, 0x93, 0x63, 0xec, + 0x45, 0xfb, 0xc4, 0xff, 0x87, 0xb4, 0x27, 0xd0, 0x7f, 0x1c, 0xe9, 0x3e, + 0xab, 0x51, 0x0b, 0x30, 0x7e, 0x02, 0xcf, 0x7b, 0xcd, 0xe3, 0xb2, 0x5a, + 0xfb, 0x17, 0xb0, 0xf6, 0x6e, 0x36, 0x2e, 0x2f, 0x6e, 0x0f, 0x63, 0x1e, + 0x09, 0xf9, 0x06, 0x64, 0x73, 0xe0, 0xce, 0x7d, 0x92, 0x86, 0x6c, 0x72, + 0xcd, 0xa7, 0xd6, 0x1f, 0x95, 0x62, 0x3c, 0x35, 0x4e, 0x3d, 0x9a, 0x9f, + 0xea, 0xc1, 0x7c, 0xb5, 0xb6, 0x1a, 0x59, 0x8d, 0x4b, 0x7a, 0x3d, 0x77, + 0x83, 0x9e, 0x57, 0xdd, 0x92, 0x58, 0x49, 0xec, 0x73, 0x21, 0x6f, 0xc6, + 0x4d, 0xbd, 0x96, 0x1c, 0x5b, 0xf6, 0x7a, 0x9f, 0x15, 0x59, 0x9f, 0x94, + 0x13, 0x7b, 0xf0, 0xa4, 0x01, 0x9e, 0xd8, 0xab, 0xa1, 0x9c, 0x3b, 0x78, + 0x1f, 0x42, 0xdd, 0x7e, 0xcb, 0x59, 0xbf, 0x9e, 0x1f, 0x1b, 0xcd, 0x51, + 0x7f, 0x17, 0xfc, 0xb0, 0xd7, 0x07, 0x51, 0xe7, 0x7a, 0x7e, 0x34, 0xc0, + 0x0f, 0x7b, 0x5d, 0xf3, 0xa2, 0x01, 0x5e, 0xd8, 0xa0, 0xb3, 0x01, 0x5e, + 0xd8, 0xa7, 0x35, 0x2f, 0x1a, 0x66, 0x4f, 0x9c, 0x51, 0xfa, 0x28, 0x07, + 0x5a, 0x2d, 0xd1, 0x3a, 0x29, 0x27, 0xd4, 0x3d, 0x91, 0xec, 0x0c, 0xf6, + 0xb2, 0x8d, 0xb9, 0x3a, 0x32, 0x33, 0x65, 0xc9, 0x82, 0x2a, 0x9b, 0x91, + 0x74, 0xf3, 0x5d, 0x60, 0xd4, 0xc4, 0x38, 0x2c, 0x41, 0xa9, 0x3b, 0xfb, + 0x1d, 0x7b, 0xb7, 0x12, 0x95, 0x82, 0x93, 0x14, 0x6f, 0x95, 0xfd, 0xcc, + 0xb7, 0xf5, 0x33, 0x8f, 0x7e, 0x76, 0xc1, 0x0f, 0x0b, 0xba, 0x93, 0x65, + 0x8f, 0xaa, 0x7d, 0x9d, 0x5e, 0x77, 0x64, 0x74, 0x95, 0x75, 0x4a, 0xf6, + 0x85, 0xe6, 0xaf, 0x02, 0xdd, 0xef, 0xa3, 0x1c, 0xd3, 0xb5, 0xb3, 0xcb, + 0xf6, 0xf9, 0xcd, 0x53, 0xf6, 0xcb, 0x4d, 0xf4, 0xdb, 0x24, 0xaf, 0xb1, + 0x16, 0x55, 0xac, 0x45, 0x15, 0xeb, 0x62, 0xf6, 0x6c, 0x5d, 0xed, 0x9d, + 0xa4, 0x59, 0x37, 0xd2, 0xc0, 0xb5, 0x4b, 0x60, 0xcd, 0xb8, 0x76, 0x62, + 0xbd, 0x9a, 0xd9, 0x27, 0x91, 0xd3, 0x11, 0xb5, 0x66, 0x03, 0xeb, 0x1f, + 0x68, 0xad, 0xd9, 0xc8, 0xd4, 0x81, 0xd6, 0x9a, 0xd9, 0xab, 0xb9, 0x5b, + 0x6c, 0x39, 0x24, 0x76, 0x16, 0xfc, 0xc9, 0x4c, 0x80, 0x5f, 0x11, 0x94, + 0xc5, 0xc5, 0x59, 0xcf, 0x21, 0x2f, 0x95, 0x28, 0x82, 0x8f, 0x65, 0xf0, + 0xb1, 0x28, 0x25, 0xc8, 0xcc, 0xcf, 0x2c, 0xad, 0xdf, 0x7e, 0x29, 0x46, + 0xb6, 0xdf, 0x91, 0x5f, 0x23, 0xe0, 0x97, 0xf7, 0x3b, 0xf0, 0xcb, 0xd9, + 0x93, 0x5f, 0xfd, 0x76, 0x27, 0xbf, 0x22, 0xe0, 0x57, 0xd7, 0xef, 0xcc, + 0x2f, 0xf0, 0x61, 0x4f, 0x5e, 0x45, 0xa1, 0xd7, 0x4a, 0x92, 0xcf, 0x88, + 0xe4, 0x6b, 0x5a, 0x17, 0x97, 0x94, 0x4e, 0xa6, 0x2e, 0x0a, 0x75, 0x32, + 0xf5, 0xb1, 0xda, 0x07, 0x56, 0xa1, 0x92, 0x84, 0xae, 0x74, 0x90, 0x3e, + 0x8f, 0x74, 0x9f, 0x35, 0x57, 0x83, 0x68, 0xf5, 0x07, 0xe2, 0x4e, 0x85, + 0xf6, 0xb0, 0x94, 0x70, 0xb1, 0x36, 0xee, 0xfb, 0xba, 0x44, 0x86, 0x52, + 0xe0, 0xd3, 0xcd, 0x28, 0x4f, 0x25, 0x72, 0x92, 0xb1, 0x43, 0xdc, 0x92, + 0xaf, 0xf4, 0xbe, 0x95, 0x53, 0x4f, 0xcc, 0x67, 0xbb, 0x0c, 0xf2, 0xba, + 0x64, 0x1e, 0x7a, 0x7e, 0xc6, 0xe3, 0x78, 0xec, 0x3f, 0x39, 0xcf, 0x71, + 0x0b, 0xcd, 0x50, 0x27, 0x4b, 0x0e, 0x36, 0x1a, 0x65, 0xdc, 0x97, 0xd3, + 0x56, 0x41, 0xdb, 0x46, 0xf1, 0x9a, 0xed, 0xf6, 0xa3, 0x45, 0x27, 0xf6, + 0x6b, 0x8e, 0x72, 0x8d, 0xb1, 0x93, 0xd8, 0x73, 0xe5, 0x48, 0xb8, 0x3e, + 0x4e, 0x76, 0x5a, 0x60, 0x77, 0xa5, 0x5c, 0x61, 0x7f, 0x9f, 0xb1, 0x22, + 0xe7, 0xc2, 0xfe, 0xc9, 0x47, 0xf6, 0xad, 0xfb, 0x2b, 0x37, 0xdf, 0x30, + 0x7b, 0x5f, 0xd9, 0x22, 0xf4, 0x57, 0x6a, 0xeb, 0xaf, 0x64, 0x45, 0x56, + 0xe5, 0x80, 0xd2, 0xf7, 0x47, 0xc9, 0xbf, 0x53, 0x28, 0xbb, 0x2c, 0x11, + 0xca, 0x8c, 0xda, 0x63, 0xdc, 0xe7, 0x9f, 0xe5, 0x7c, 0xdb, 0x78, 0x3b, + 0x07, 0x1b, 0xc6, 0xfd, 0x85, 0x35, 0x8e, 0x33, 0xff, 0x2e, 0x43, 0x93, + 0x23, 0x39, 0xf5, 0xfe, 0xb5, 0x7d, 0xa1, 0x7e, 0xc4, 0x7e, 0x06, 0x6d, + 0xdf, 0x51, 0x73, 0xb4, 0xb3, 0x59, 0xf0, 0xa6, 0x9d, 0x46, 0x85, 0x05, + 0xb0, 0xc6, 0xa1, 0x8e, 0x0a, 0xd7, 0x8a, 0xb8, 0xc5, 0xb1, 0x96, 0x2a, + 0x7d, 0xb0, 0x7f, 0x51, 0x63, 0x63, 0xd9, 0x7e, 0x19, 0xed, 0x99, 0xcf, + 0xb6, 0x7d, 0xb0, 0xb7, 0x6c, 0xbf, 0x6c, 0xda, 0x5f, 0xb5, 0xbb, 0xdc, + 0x2b, 0xb4, 0xb9, 0x17, 0x32, 0xc0, 0x3a, 0x6b, 0xb6, 0x14, 0x7c, 0xe0, + 0x18, 0x7f, 0xd8, 0xec, 0x0b, 0x2d, 0x9b, 0xf7, 0x3a, 0x96, 0xf4, 0x78, + 0x7b, 0xc9, 0xe6, 0xcb, 0xb6, 0xb6, 0x65, 0x57, 0x65, 0x73, 0x09, 0x3a, + 0xea, 0x04, 0x64, 0x65, 0xb9, 0x55, 0x8f, 0x72, 0xa9, 0x64, 0x14, 0xb2, + 0x99, 0x9a, 0xe6, 0x34, 0x2f, 0x34, 0xdb, 0x65, 0x34, 0xec, 0x23, 0xaa, + 0xe4, 0x40, 0x8f, 0xb3, 0xdc, 0x36, 0xce, 0x72, 0xdb, 0x38, 0x27, 0x0d, + 0x76, 0x63, 0x3f, 0xda, 0x6e, 0x5e, 0xbe, 0xc6, 0x5e, 0x73, 0xcd, 0x3e, + 0x8a, 0x3d, 0xa9, 0x65, 0x01, 0x58, 0x4c, 0xaf, 0x41, 0xc5, 0x95, 0xf2, + 0xf6, 0xd9, 0x70, 0xaf, 0x96, 0x7a, 0x90, 0xff, 0x53, 0xe4, 0x8f, 0xaf, + 0xb8, 0xb0, 0x43, 0xc4, 0x62, 0x7f, 0x25, 0x5b, 0x15, 0xca, 0xc8, 0x77, + 0x40, 0x77, 0xda, 0xef, 0xb6, 0xc8, 0xd7, 0xd4, 0xf8, 0x19, 0x49, 0x25, + 0xcb, 0x32, 0xe1, 0x33, 0x3d, 0x49, 0x45, 0x8d, 0x7a, 0x1a, 0xe3, 0x7c, + 0x07, 0xf2, 0x27, 0xf2, 0x66, 0xa5, 0x47, 0xec, 0xa9, 0x9f, 0x06, 0xb4, + 0x73, 0xa7, 0xb6, 0x3b, 0xfb, 0x11, 0x19, 0x5b, 0x51, 0xfd, 0xa0, 0x8f, + 0xb4, 0x7f, 0x49, 0xf5, 0x17, 0xf6, 0x85, 0x79, 0x4e, 0x75, 0xf6, 0xe7, + 0xc8, 0x65, 0xd7, 0x46, 0x7f, 0xb7, 0x98, 0x39, 0xf2, 0x19, 0x32, 0xe2, + 0x3a, 0x48, 0xef, 0xb3, 0x43, 0x99, 0xb1, 0xa7, 0xfe, 0x3a, 0xc8, 0xcd, + 0x71, 0x6e, 0xff, 0xcc, 0xe4, 0xfd, 0x47, 0x23, 0x6f, 0x52, 0xb3, 0xb3, + 0xe0, 0x59, 0x66, 0x14, 0xe3, 0xf1, 0x3d, 0x09, 0xfc, 0x23, 0x25, 0xe2, + 0xaf, 0x62, 0xe5, 0x37, 0x41, 0xce, 0xd1, 0x98, 0x49, 0xaf, 0x3d, 0xcb, + 0x2d, 0x29, 0xa0, 0xee, 0x92, 0xd1, 0x07, 0x33, 0xcd, 0xcb, 0x8a, 0x7f, + 0x2f, 0xaa, 0x7d, 0x94, 0x3a, 0x55, 0xa2, 0xde, 0xd8, 0x8e, 0x46, 0xb8, + 0xc7, 0x5f, 0xf0, 0x37, 0x83, 0xa5, 0x6a, 0x2a, 0x99, 0xb4, 0x47, 0xa5, + 0x58, 0x1b, 0x2d, 0xd9, 0x48, 0x9f, 0xac, 0x27, 0xe4, 0xc9, 0x0a, 0xfb, + 0xb9, 0x01, 0x75, 0xa0, 0x88, 0x6c, 0x6c, 0xf2, 0x21, 0xea, 0x1a, 0x8e, + 0xf9, 0x96, 0xa5, 0xc7, 0xc4, 0x1c, 0xbc, 0x1d, 0xeb, 0x93, 0xcd, 0x0b, + 0x56, 0xb1, 0xce, 0xf5, 0x47, 0x7e, 0xb3, 0x5d, 0x1f, 0xb5, 0xeb, 0xed, + 0x50, 0x5f, 0xeb, 0xb5, 0x73, 0xb0, 0xef, 0x6a, 0x95, 0x65, 0xab, 0xbc, + 0x26, 0x76, 0xde, 0xef, 0x32, 0xf2, 0x68, 0xb9, 0x7a, 0xce, 0x4f, 0x46, + 0xa8, 0x13, 0x23, 0xde, 0x29, 0xab, 0x5c, 0xb9, 0x55, 0x72, 0x0e, 0x31, + 0x1c, 0x9f, 0x25, 0x88, 0x64, 0x3d, 0xda, 0x4d, 0x27, 0x92, 0x4d, 0x63, + 0xbf, 0xb1, 0xce, 0x66, 0xf0, 0x65, 0x8c, 0x33, 0x72, 0x1a, 0xfa, 0xd9, + 0x7f, 0x0f, 0xfa, 0xe1, 0xf8, 0xbd, 0x78, 0x77, 0xcc, 0xbe, 0xec, 0x42, + 0xbd, 0x14, 0x36, 0xf7, 0xc5, 0x7e, 0xe9, 0x7f, 0x06, 0x7a, 0x36, 0xec, + 0x9b, 0x75, 0x12, 0xa6, 0x4e, 0x9f, 0xa9, 0x73, 0x37, 0xca, 0x3f, 0x86, + 0x7a, 0x29, 0x9f, 0xd0, 0x16, 0x29, 0xf2, 0x06, 0x31, 0x47, 0xd4, 0x6d, + 0xdc, 0x60, 0xde, 0xc3, 0xf6, 0x77, 0xb6, 0xd5, 0xe5, 0xfb, 0xb5, 0x7a, + 0x78, 0xbe, 0xa5, 0x87, 0xc9, 0xc3, 0x1c, 0xf4, 0x9e, 0xd8, 0xd8, 0xf7, + 0x6e, 0x24, 0xcb, 0xfc, 0x69, 0x3c, 0x3f, 0x1f, 0x94, 0xab, 0xd4, 0xfb, + 0xc0, 0xc1, 0x75, 0xa5, 0xff, 0xd0, 0x6f, 0xce, 0x9a, 0xa9, 0x84, 0xeb, + 0xc4, 0x79, 0x85, 0xb8, 0x44, 0xf1, 0x0c, 0xf4, 0x26, 0xaf, 0xd2, 0xeb, + 0x2a, 0x99, 0x40, 0x9e, 0x6f, 0xf2, 0x7a, 0xda, 0xf2, 0x42, 0x9d, 0xf4, + 0x05, 0xcc, 0x6b, 0x58, 0xad, 0x99, 0x9d, 0x3d, 0x62, 0xe5, 0x15, 0x26, + 0x0a, 0x82, 0x82, 0xd7, 0x25, 0xc5, 0xc9, 0xa7, 0xc1, 0x2b, 0x96, 0x95, + 0xdc, 0x88, 0xc2, 0xf1, 0x73, 0x0f, 0x2c, 0x78, 0x29, 0x85, 0x49, 0xf2, + 0xd0, 0x09, 0x5a, 0x8f, 0x4b, 0x69, 0x00, 0xb4, 0x7b, 0xab, 0xe4, 0xc5, + 0x66, 0x70, 0x1a, 0xf8, 0x7b, 0x6e, 0x75, 0xc6, 0x1a, 0x59, 0xc5, 0xba, + 0x0f, 0x59, 0xe0, 0x4b, 0x9f, 0xe4, 0xcf, 0x91, 0x2f, 0xac, 0xc3, 0xfc, + 0x6e, 0x99, 0x8b, 0x77, 0xda, 0xef, 0x3f, 0x3e, 0x20, 0x31, 0xf2, 0x01, + 0x75, 0x57, 0x21, 0xec, 0x31, 0x8d, 0x89, 0x47, 0xd6, 0x29, 0x47, 0x33, + 0xd6, 0x42, 0x85, 0xba, 0xb5, 0x17, 0x36, 0x5b, 0xad, 0x3f, 0xfa, 0x44, + 0xd9, 0x99, 0xce, 0x3e, 0x3e, 0x1d, 0xd1, 0x7d, 0xb0, 0x5d, 0xd8, 0x47, + 0x3b, 0x3f, 0xf6, 0x29, 0xdd, 0x3b, 0x98, 0x1d, 0xec, 0xe8, 0x37, 0xd1, + 0xd6, 0x2f, 0xca, 0xce, 0xfc, 0x34, 0x42, 0x2c, 0xf8, 0x52, 0x15, 0x7c, + 0x56, 0x73, 0x62, 0x19, 0xdb, 0xcc, 0x58, 0x85, 0xd5, 0x20, 0x98, 0xf3, + 0x6d, 0x89, 0x0c, 0x85, 0x75, 0xf5, 0xbc, 0x66, 0x30, 0xaf, 0x3c, 0xe6, + 0x65, 0x0f, 0x75, 0xd2, 0xf4, 0x39, 0x43, 0xd3, 0x60, 0x1b, 0x4d, 0xf1, + 0x77, 0x98, 0x57, 0x7c, 0x8f, 0x79, 0x9d, 0x1c, 0xd4, 0x7d, 0xc4, 0xdb, + 0xfa, 0x18, 0xea, 0xe8, 0x03, 0xb6, 0x28, 0xce, 0xf6, 0x43, 0x7b, 0xb4, + 0xff, 0x49, 0xaf, 0x6e, 0xcf, 0x36, 0xdd, 0xb0, 0x37, 0xc3, 0x46, 0x57, + 0x3f, 0xd9, 0xa6, 0x5f, 0x9f, 0x84, 0x7e, 0x6d, 0x6f, 0x13, 0xca, 0x65, + 0xbb, 0x5f, 0x46, 0x9f, 0x2c, 0xc4, 0xaf, 0xef, 0x52, 0xb8, 0xe8, 0x2a, + 0xae, 0x8f, 0x02, 0x23, 0xf5, 0x01, 0x93, 0xf4, 0xd3, 0xf7, 0x32, 0x38, + 0x95, 0xbe, 0x18, 0xb1, 0xa9, 0x78, 0x40, 0x76, 0xd0, 0x77, 0xa3, 0x89, + 0x63, 0x22, 0xca, 0xf7, 0x22, 0xa6, 0xa7, 0x1f, 0xc6, 0x71, 0xe8, 0x87, + 0x71, 0xdd, 0xf9, 0x5e, 0x68, 0xf9, 0x65, 0xc3, 0xd0, 0x45, 0xc4, 0xe4, + 0xc4, 0xaf, 0xa1, 0xfd, 0x6b, 0xd7, 0xf1, 0x7b, 0xd1, 0x34, 0xdc, 0x41, + 0x13, 0xf4, 0x24, 0xfc, 0xc1, 0x25, 0xc8, 0x23, 0x70, 0x32, 0xf4, 0xf2, + 0xd3, 0xb3, 0x5b, 0x6b, 0x22, 0xc5, 0x26, 0x6d, 0xf6, 0xa4, 0xc0, 0x97, + 0x03, 0x5d, 0xec, 0x5b, 0xd9, 0x6d, 0xe8, 0xcb, 0xfe, 0x9c, 0x9d, 0x1d, + 0x85, 0xef, 0xef, 0xc8, 0xa2, 0xa1, 0x6d, 0x5e, 0xf9, 0x8d, 0x7d, 0x48, + 0x13, 0x4a, 0xae, 0xe6, 0x41, 0x1f, 0x9f, 0xe7, 0x8d, 0xbf, 0x70, 0xac, + 0xd9, 0x49, 0xdb, 0x0f, 0x41, 0x9b, 0x07, 0x1a, 0x92, 0xf2, 0x2d, 0xf8, + 0x0b, 0xdf, 0x54, 0xfb, 0x32, 0xd4, 0x67, 0x4a, 0x57, 0xd4, 0x4a, 0xf2, + 0x7c, 0xb0, 0x56, 0xe5, 0xbe, 0x25, 0xae, 0xe8, 0x93, 0x12, 0xd6, 0x6b, + 0x64, 0x35, 0x95, 0xcc, 0xd9, 0x62, 0xdd, 0x70, 0x27, 0xe5, 0xe9, 0x09, + 0x19, 0x39, 0x27, 0x96, 0xb3, 0x8a, 0xbd, 0xde, 0x1f, 0x62, 0x3e, 0xce, + 0xef, 0xdd, 0x98, 0x1f, 0xfa, 0xae, 0x86, 0xf3, 0xeb, 0x93, 0xe2, 0x3a, + 0xe7, 0xd7, 0x9a, 0x5b, 0x9c, 0x51, 0x98, 0xa7, 0x60, 0x43, 0x30, 0x47, + 0xd0, 0x38, 0x0d, 0xec, 0xfd, 0x1e, 0x33, 0xa7, 0x3e, 0xcc, 0x09, 0xb8, + 0x61, 0x95, 0xed, 0x41, 0x17, 0x68, 0x2e, 0xa2, 0x5e, 0x79, 0x95, 0x6b, + 0x0e, 0x5a, 0xb1, 0xee, 0xc5, 0x26, 0xd7, 0x9e, 0x73, 0xd3, 0x58, 0xc3, + 0xf1, 0x38, 0x3f, 0xce, 0x73, 0x1c, 0xf3, 0x62, 0x1d, 0xb6, 0xeb, 0x94, + 0x91, 0xf1, 0x77, 0x58, 0x8f, 0x77, 0x77, 0xac, 0x87, 0x98, 0xf5, 0x88, + 0x4a, 0xf7, 0xba, 0xf2, 0xd1, 0x15, 0x0d, 0xf4, 0x6b, 0x1c, 0xd0, 0xbf, + 0xbc, 0x26, 0x93, 0x0c, 0x60, 0xd1, 0x36, 0x20, 0x2f, 0xd3, 0x2d, 0xa3, + 0xfe, 0x05, 0xc8, 0x55, 0x11, 0xb2, 0x40, 0x1f, 0xe5, 0xa5, 0xaa, 0x5e, + 0x8b, 0x62, 0x33, 0x26, 0xf6, 0x69, 0x8e, 0x4f, 0x7e, 0x73, 0x6e, 0xae, + 0x5a, 0x87, 0xf6, 0x75, 0x79, 0xec, 0xba, 0x75, 0xd9, 0x84, 0x1e, 0xa5, + 0x1e, 0x20, 0x16, 0xa3, 0x2e, 0x08, 0xe3, 0x10, 0x7f, 0xe4, 0xea, 0xfd, + 0x14, 0xda, 0xc4, 0xcb, 0x2d, 0xcc, 0xfb, 0xa2, 0xf2, 0x1d, 0xf4, 0x9c, + 0xf2, 0x19, 0xe8, 0xa5, 0xb5, 0x1b, 0xb0, 0x77, 0x68, 0x13, 0x37, 0x83, + 0x5a, 0xb5, 0x4b, 0xd1, 0x90, 0xf7, 0xfb, 0x89, 0xdf, 0x44, 0xdb, 0x01, + 0xa6, 0xcc, 0xa7, 0x8d, 0x44, 0x59, 0x86, 0x6b, 0x89, 0xf7, 0x06, 0xdf, + 0xdb, 0xf5, 0xfe, 0x7f, 0x72, 0xf4, 0x7e, 0x64, 0xec, 0x69, 0x2f, 0x3b, + 0x78, 0x35, 0xe6, 0xe0, 0xc0, 0x57, 0x2e, 0xaf, 0x05, 0xc0, 0x63, 0xef, + 0xc1, 0xde, 0xce, 0x49, 0xd1, 0x85, 0x1d, 0x1f, 0xbf, 0x19, 0x7c, 0x9d, + 0x16, 0x15, 0x67, 0x18, 0xdf, 0x8f, 0xe7, 0x7d, 0xca, 0xa7, 0x29, 0x8e, + 0xbf, 0x57, 0x72, 0x73, 0xc4, 0x43, 0x8f, 0xcb, 0x3c, 0x6c, 0x6e, 0x71, + 0x1c, 0x36, 0x31, 0xce, 0x77, 0xe8, 0x25, 0x6f, 0x8c, 0xb1, 0x09, 0xfc, + 0xfd, 0x1b, 0x13, 0x93, 0x39, 0x88, 0xf7, 0x7d, 0xa8, 0xf3, 0x31, 0x53, + 0xa7, 0x7f, 0x8f, 0x3a, 0x79, 0xbc, 0xdf, 0x8d, 0x3a, 0x31, 0x8c, 0x01, + 0x4c, 0x0b, 0x5b, 0x66, 0x7b, 0x1f, 0x46, 0xde, 0x5d, 0xc8, 0xbb, 0x0b, + 0x79, 0x77, 0xe0, 0xbd, 0x60, 0x62, 0x1d, 0x61, 0x9b, 0x7e, 0xbc, 0x7f, + 0x01, 0xe5, 0xd0, 0x33, 0xee, 0x25, 0x94, 0xdf, 0xad, 0xda, 0x5d, 0x5b, + 0x67, 0xb0, 0xe3, 0x7d, 0xcb, 0xd1, 0xb1, 0x11, 0xe6, 0x0d, 0x9b, 0x67, + 0xb1, 0x96, 0x2b, 0x7c, 0xff, 0xa1, 0x79, 0xbf, 0xb7, 0x23, 0xff, 0x71, + 0xf3, 0xde, 0xb9, 0xae, 0xb7, 0x61, 0x5d, 0x59, 0xfe, 0xd1, 0x03, 0x7a, + 0x3d, 0xc6, 0x74, 0xfc, 0xe1, 0x1a, 0x3c, 0xa2, 0x44, 0x11, 0xcf, 0x3b, + 0xc0, 0x21, 0xc4, 0x26, 0xed, 0xb8, 0x84, 0x34, 0xa9, 0xfa, 0x66, 0x9c, + 0xe7, 0xfa, 0xc3, 0x71, 0xcb, 0x90, 0x81, 0xc3, 0x6b, 0x61, 0xfe, 0xc5, + 0xfe, 0x6b, 0xe9, 0xf9, 0x9f, 0x6d, 0xf5, 0xf6, 0xcb, 0xe1, 0x5a, 0x98, + 0x7f, 0xe8, 0xc0, 0xb5, 0xf5, 0x6e, 0x3e, 0x70, 0x75, 0xae, 0xad, 0x78, + 0x09, 0x68, 0xfb, 0x8c, 0x7d, 0x15, 0x2b, 0xe5, 0xec, 0xc5, 0xe6, 0x8c, + 0xad, 0x69, 0x62, 0x1d, 0x94, 0x35, 0x77, 0x06, 0x1c, 0x25, 0xa3, 0x39, + 0x9b, 0x7e, 0x4a, 0x69, 0x83, 0xcf, 0x37, 0x23, 0x6d, 0x6f, 0x3b, 0x0c, + 0x7d, 0x9b, 0xb3, 0xf5, 0x9c, 0x3a, 0xdb, 0x87, 0xf2, 0xed, 0xcb, 0x52, + 0x0d, 0x32, 0xe9, 0xa5, 0xc6, 0x4b, 0xf0, 0x73, 0x17, 0xfc, 0xd4, 0x1c, + 0x65, 0x16, 0xbe, 0xf0, 0x23, 0x22, 0xb3, 0x52, 0xae, 0x3d, 0x08, 0xec, + 0x1e, 0xc8, 0x87, 0x60, 0xff, 0xff, 0x25, 0xf0, 0x43, 0x1d, 0xba, 0xa0, + 0xde, 0xf4, 0xf0, 0x1b, 0x96, 0xaf, 0x57, 0x12, 0xf2, 0x3c, 0x7c, 0x91, + 0xc6, 0x1a, 0xf5, 0x65, 0xda, 0xfd, 0x90, 0xc8, 0x80, 0x2d, 0xe7, 0xef, + 0xb2, 0x65, 0x22, 0x39, 0x62, 0xa5, 0x13, 0xf8, 0xb9, 0xdd, 0xf8, 0xcd, + 0xc0, 0xff, 0xdb, 0x68, 0x32, 0x8e, 0x10, 0x97, 0x3f, 0xdf, 0x4c, 0xe2, + 0x37, 0x24, 0xff, 0x7e, 0x93, 0xe3, 0x8f, 0x98, 0x34, 0xf4, 0x4d, 0xbe, + 0x05, 0x1d, 0x71, 0x29, 0x58, 0xae, 0x32, 0x26, 0x14, 0xda, 0xa1, 0x6f, + 0x29, 0x3b, 0xb4, 0x54, 0x09, 0x8e, 0x6b, 0x1f, 0xdc, 0x83, 0xcf, 0x8d, + 0xf7, 0xe6, 0x5b, 0x56, 0xa3, 0x35, 0xc7, 0x1d, 0xab, 0x61, 0xd6, 0xad, + 0xd1, 0x9a, 0x23, 0xca, 0x9b, 0x17, 0x20, 0x0b, 0xd4, 0xbf, 0xa1, 0xee, + 0xf5, 0x0c, 0x2e, 0x0a, 0xf5, 0x2f, 0xf6, 0x70, 0x4d, 0xa2, 0xf1, 0xec, + 0x2f, 0x64, 0xed, 0x34, 0xf7, 0x14, 0xed, 0xe5, 0x34, 0x64, 0x31, 0xf5, + 0x95, 0x12, 0x71, 0xb6, 0xc7, 0x98, 0xc0, 0x25, 0xf4, 0x31, 0x3f, 0xa8, + 0x65, 0xe7, 0x12, 0xf6, 0xf9, 0xac, 0x38, 0xa7, 0x3f, 0xdf, 0x25, 0xfd, + 0xc7, 0x65, 0xd9, 0x87, 0x3f, 0x6b, 0x97, 0x82, 0x88, 0xe7, 0x25, 0x0a, + 0xca, 0xdf, 0x5a, 0x03, 0x5d, 0xdf, 0x03, 0x26, 0x3e, 0xae, 0xfc, 0xba, + 0x63, 0x35, 0xd6, 0xed, 0xc6, 0x7a, 0xa4, 0x4a, 0x05, 0xac, 0xd5, 0x89, + 0xf8, 0x05, 0x94, 0x05, 0x81, 0xed, 0x0d, 0x48, 0xb1, 0x1e, 0x3e, 0x43, + 0xf6, 0x37, 0xff, 0x01, 0x32, 0xc6, 0x67, 0xc0, 0xc4, 0x75, 0x96, 0x8d, + 0x20, 0x65, 0x39, 0xcb, 0x3c, 0xa5, 0xeb, 0x8a, 0x4d, 0xd2, 0x31, 0x2b, + 0x85, 0x1a, 0xe7, 0x04, 0xbb, 0x58, 0xbf, 0x14, 0x9c, 0xa8, 0x5e, 0x00, + 0xaf, 0x38, 0x5e, 0x56, 0x1a, 0x58, 0x8b, 0x72, 0xf3, 0x71, 0x60, 0xfa, + 0xd7, 0x91, 0x2e, 0x22, 0xbd, 0x8c, 0xf4, 0x09, 0xa4, 0x6f, 0x20, 0xe5, + 0xbc, 0x1e, 0x97, 0x46, 0x3d, 0xd1, 0x2d, 0x31, 0xf6, 0xf3, 0xd9, 0xd6, + 0x7c, 0xca, 0xd0, 0x0d, 0xb9, 0x56, 0x3e, 0x9f, 0x99, 0x7e, 0x02, 0xe9, + 0x47, 0x91, 0xf7, 0x3d, 0x3c, 0x4f, 0x4b, 0xa1, 0xf2, 0x04, 0xec, 0x30, + 0xb1, 0xea, 0x27, 0x30, 0x2e, 0xc7, 0x7f, 0x19, 0x74, 0xb0, 0x2c, 0x90, + 0x4f, 0x62, 0x9e, 0xf9, 0xda, 0x71, 0x79, 0xd8, 0xbf, 0x45, 0xa6, 0x1e, + 0x26, 0x3d, 0xe4, 0x0d, 0xf5, 0xdb, 0x5e, 0xbc, 0x21, 0x5f, 0x42, 0x7e, + 0xf4, 0x61, 0x5e, 0xd4, 0x55, 0xc4, 0xc6, 0x10, 0xc0, 0x7e, 0x8d, 0x77, + 0x46, 0xc6, 0x02, 0x79, 0xc8, 0xcf, 0x4a, 0xe4, 0xf4, 0x98, 0x9b, 0xb1, + 0x27, 0xe0, 0xf9, 0xa4, 0xf1, 0x3b, 0x0e, 0xb9, 0xf4, 0x4e, 0x8d, 0xd8, + 0x23, 0xa0, 0x09, 0x65, 0x0d, 0x8e, 0x73, 0x29, 0xf8, 0x93, 0xea, 0xab, + 0xf0, 0xdb, 0xb3, 0x72, 0xa5, 0xf9, 0x2a, 0xe4, 0x83, 0xf4, 0x08, 0xe8, + 0x9c, 0x95, 0x1f, 0xd7, 0x5e, 0x96, 0x93, 0xe0, 0xfd, 0x6b, 0x48, 0x97, + 0x6b, 0x25, 0xf0, 0x95, 0xf1, 0x7b, 0xf6, 0x11, 0x60, 0xcd, 0x46, 0xe1, + 0x6f, 0xdd, 0x96, 0x58, 0xc4, 0xfa, 0xce, 0xbb, 0x81, 0x6c, 0xf9, 0x25, + 0xd9, 0x9a, 0x46, 0x9b, 0x3a, 0xdb, 0xf7, 0xca, 0x61, 0x95, 0x52, 0xfe, + 0xfa, 0x31, 0xc7, 0x98, 0xe2, 0xf3, 0x72, 0x35, 0x94, 0x3d, 0xca, 0x61, + 0xa7, 0xfc, 0x91, 0xee, 0x1d, 0xeb, 0x9b, 0x4d, 0xda, 0xd1, 0xbd, 0x6c, + 0x62, 0x28, 0x97, 0xb4, 0x8b, 0xed, 0xb2, 0x29, 0xd2, 0xa8, 0x69, 0xff, + 0xe6, 0x1b, 0xdb, 0x4a, 0xd6, 0xb1, 0x3e, 0xc4, 0xd3, 0x3f, 0x17, 0xe0, + 0x37, 0xf0, 0x29, 0x8c, 0x2f, 0x6a, 0xbf, 0xab, 0x0e, 0x7a, 0xe1, 0x6b, + 0x00, 0x2b, 0x88, 0xd4, 0xeb, 0x9f, 0x57, 0xfc, 0xf2, 0x4e, 0x0f, 0x4b, + 0xad, 0x4a, 0x1e, 0xa7, 0x5c, 0xdb, 0x56, 0xfe, 0x0d, 0x78, 0xeb, 0x41, + 0x56, 0xc2, 0xf2, 0x14, 0xfc, 0xaf, 0xe3, 0xe2, 0x4e, 0xc5, 0x60, 0xbf, + 0xf8, 0x2c, 0x32, 0x77, 0xae, 0x13, 0x0b, 0x86, 0x36, 0xa6, 0x1b, 0x7e, + 0x7e, 0x17, 0x74, 0x41, 0x1f, 0xfc, 0x74, 0xf8, 0xbf, 0x90, 0xa7, 0x3f, + 0x01, 0x7e, 0x3a, 0xa5, 0x7c, 0x76, 0xee, 0xc3, 0x07, 0x67, 0x47, 0x36, + 0x99, 0x7e, 0x78, 0x36, 0x5d, 0x67, 0x7a, 0xd4, 0xc4, 0xf5, 0x1f, 0x31, + 0xf1, 0xfe, 0xf9, 0xd9, 0x83, 0x2a, 0x5d, 0x9c, 0x1d, 0x57, 0xe9, 0xe3, + 0xb3, 0x57, 0x63, 0x31, 0x17, 0x20, 0xab, 0xa4, 0x4d, 0x9c, 0x62, 0x26, + 0x23, 0x9b, 0x15, 0x1f, 0x7e, 0xf7, 0x34, 0xf0, 0xc7, 0x34, 0xe4, 0x36, + 0x0b, 0x7a, 0xa1, 0x7f, 0xb2, 0x3e, 0x52, 0x31, 0x7f, 0x61, 0xbb, 0x6e, + 0xc6, 0xdd, 0xb8, 0x66, 0xc6, 0x77, 0xf5, 0xe9, 0xbb, 0xb6, 0xff, 0xb1, + 0x4f, 0xc8, 0x38, 0xed, 0xee, 0xaf, 0xe1, 0x6f, 0xb3, 0x7f, 0xb6, 0x65, + 0xff, 0x22, 0xbb, 0x6b, 0x12, 0x8d, 0x66, 0xff, 0x5a, 0xa2, 0xcf, 0x06, + 0xc1, 0x4f, 0xfc, 0xd4, 0x91, 0x92, 0x80, 0x4f, 0x16, 0xf2, 0x37, 0x59, + 0x46, 0x9d, 0x35, 0xe1, 0x5e, 0x81, 0xcc, 0xe5, 0x8e, 0x8a, 0xbc, 0x82, + 0xbc, 0xc6, 0x1a, 0xf9, 0xff, 0x3d, 0xf0, 0xdf, 0xac, 0x87, 0xca, 0x63, + 0x3d, 0xf8, 0x48, 0x71, 0xca, 0xdc, 0x84, 0xdb, 0x83, 0xf6, 0xf5, 0x4d, + 0xb6, 0x49, 0x4d, 0xf3, 0x98, 0xec, 0x95, 0xcd, 0x0b, 0x4a, 0x5f, 0x75, + 0x67, 0xc7, 0x19, 0x43, 0x92, 0x8d, 0xb5, 0xdf, 0x04, 0x0b, 0xfe, 0x0e, + 0x80, 0x5a, 0x0a, 0x72, 0x9f, 0x95, 0xf3, 0xc0, 0x58, 0xe7, 0x2b, 0x69, + 0xac, 0x0d, 0xf0, 0x6d, 0x82, 0x24, 0x7b, 0xa8, 0xf7, 0x66, 0x37, 0x71, + 0x6c, 0x9e, 0xe7, 0x47, 0x95, 0x69, 0xd9, 0x6d, 0xce, 0x09, 0xb1, 0x52, + 0x3e, 0xc3, 0xf9, 0xb4, 0xf3, 0x41, 0xff, 0x15, 0xb1, 0x06, 0x66, 0x7e, + 0xea, 0x0f, 0x74, 0x62, 0x3f, 0xa1, 0xbd, 0xbf, 0x83, 0xbd, 0x91, 0x82, + 0x7e, 0x15, 0x07, 0x7e, 0xa2, 0xa4, 0xcf, 0x3a, 0x4e, 0xbe, 0xe2, 0xc8, + 0xc8, 0x59, 0x6c, 0xa9, 0xac, 0xe1, 0x43, 0x33, 0x94, 0xb1, 0x50, 0xe7, + 0x51, 0xa6, 0x38, 0xff, 0x54, 0x69, 0x07, 0x8c, 0x1e, 0xcc, 0x5e, 0x94, + 0x87, 0xd7, 0xf5, 0x7c, 0xed, 0x33, 0xc2, 0xb3, 0x13, 0xb9, 0xb2, 0x96, + 0xf2, 0x2f, 0x0b, 0xfd, 0x5f, 0x1f, 0x32, 0x72, 0xb1, 0x1b, 0xfb, 0x79, + 0x3a, 0x67, 0x1f, 0xec, 0xd1, 0xb6, 0xd9, 0xc1, 0x1e, 0x00, 0x4e, 0xac, + 0xc0, 0x6f, 0xf6, 0x7a, 0xe4, 0x5f, 0x38, 0x78, 0x26, 0x6e, 0x44, 0x9e, + 0xb1, 0xa3, 0x78, 0xd6, 0xfd, 0x95, 0x31, 0x0f, 0x1d, 0x57, 0xb6, 0xe4, + 0x61, 0x58, 0x15, 0x41, 0xff, 0x23, 0x66, 0xac, 0x91, 0x33, 0x17, 0xd4, + 0x7e, 0x4d, 0xaf, 0x67, 0x81, 0xa3, 0x1c, 0xe3, 0x6f, 0x52, 0x4f, 0xc9, + 0x1e, 0xfe, 0x4a, 0x28, 0xa3, 0x17, 0x82, 0x2f, 0x56, 0xc3, 0x98, 0x40, + 0x46, 0x46, 0x56, 0xb4, 0x4c, 0x3d, 0x9e, 0x81, 0xce, 0x86, 0x2c, 0x8d, + 0xac, 0x04, 0xf2, 0x13, 0xdf, 0x97, 0x53, 0xdb, 0x7b, 0xc9, 0x54, 0xe7, + 0x5f, 0x1f, 0xe8, 0xe4, 0x6f, 0x48, 0x96, 0xfe, 0x14, 0x74, 0x9e, 0x75, + 0xf1, 0x9c, 0x9a, 0x9b, 0xa7, 0x8f, 0x70, 0x16, 0xba, 0x14, 0xbe, 0xac, + 0x7d, 0x76, 0x58, 0xd5, 0xb1, 0xcf, 0xc2, 0xc6, 0x41, 0xc6, 0x6c, 0xf0, + 0xb5, 0x0c, 0x7b, 0x67, 0x9f, 0xed, 0x82, 0x5d, 0xe4, 0x1e, 0x95, 0x41, + 0x1b, 0xba, 0x80, 0xf5, 0x1b, 0xd8, 0x2b, 0xf6, 0xd9, 0x3e, 0xa4, 0x49, + 0xd5, 0x57, 0xa3, 0xe2, 0xa9, 0xf6, 0x8d, 0xca, 0xb8, 0x6a, 0xd7, 0xa8, + 0x4c, 0x22, 0x85, 0x8e, 0xcf, 0xf8, 0xd2, 0x7d, 0x36, 0x23, 0x72, 0xd6, + 0x92, 0xe2, 0x5c, 0x10, 0xc4, 0x40, 0x7b, 0xec, 0xec, 0x01, 0xb9, 0xac, + 0xd6, 0x76, 0x4e, 0x46, 0x9e, 0x25, 0xbf, 0xb2, 0xa8, 0x3b, 0x23, 0xe9, + 0x67, 0x67, 0xc4, 0x7b, 0x96, 0x3c, 0x61, 0xac, 0x7e, 0x57, 0xc9, 0xd4, + 0x27, 0xe4, 0x28, 0xec, 0x4a, 0x0f, 0xf6, 0x84, 0xe3, 0x96, 0x65, 0x05, + 0x6b, 0x32, 0xea, 0x1e, 0x86, 0x9c, 0xc9, 0xdb, 0xd6, 0x67, 0x5d, 0xb6, + 0x61, 0xfd, 0x83, 0x90, 0x17, 0x0f, 0xf5, 0x8f, 0xc2, 0xc6, 0xb4, 0xf3, + 0x82, 0xfb, 0x2c, 0xf7, 0x0e, 0xf2, 0x17, 0xee, 0xaf, 0x0b, 0xc1, 0xc9, + 0x2a, 0xf7, 0x18, 0xf7, 0xd7, 0x87, 0xe4, 0x15, 0x6f, 0x4e, 0x76, 0xbd, + 0x8c, 0x5c, 0x00, 0x0e, 0x7d, 0xd9, 0x9b, 0x91, 0x8b, 0x5e, 0xb4, 0x87, + 0x31, 0xb6, 0x06, 0x71, 0x72, 0x6b, 0xcd, 0xe2, 0xc6, 0x1f, 0x79, 0x43, + 0xb6, 0x2a, 0xb4, 0xd5, 0xc1, 0xa1, 0x05, 0xbf, 0x74, 0x33, 0x68, 0x03, + 0x1d, 0x8c, 0x1b, 0x5c, 0xb5, 0x11, 0x5d, 0xd8, 0x43, 0x1b, 0xca, 0x46, + 0xf4, 0xd1, 0x46, 0xf8, 0x05, 0xd9, 0x2f, 0xbb, 0x35, 0x1d, 0xd3, 0xcb, + 0x03, 0x43, 0xed, 0xd6, 0xb9, 0xfe, 0x71, 0xf9, 0x52, 0x95, 0x73, 0x2d, + 0xdf, 0x10, 0x93, 0x88, 0x1c, 0x51, 0x36, 0xbb, 0x5f, 0xce, 0x6f, 0x02, + 0xf3, 0x02, 0x7d, 0xd8, 0xb7, 0x32, 0x26, 0x64, 0xab, 0x18, 0x83, 0x0c, + 0xd0, 0x66, 0xfd, 0x17, 0xf0, 0x88, 0x71, 0x20, 0xcc, 0x71, 0x80, 0xb3, + 0x09, 0xdf, 0x27, 0x65, 0xb7, 0xc2, 0x67, 0x4b, 0x0a, 0xf0, 0x27, 0x77, + 0x2b, 0x4c, 0x13, 0x48, 0x4d, 0x8c, 0x5f, 0x61, 0xf8, 0xbf, 0x55, 0xe5, + 0x3d, 0xde, 0x2c, 0xd6, 0x85, 0x72, 0x8b, 0x74, 0x4b, 0x8f, 0x5b, 0x80, + 0xcf, 0x5f, 0x9c, 0xec, 0xa5, 0xfd, 0x02, 0x6e, 0x72, 0x64, 0x5e, 0xd5, + 0xcf, 0xc8, 0xc5, 0xca, 0xcf, 0xcc, 0x3e, 0x99, 0x36, 0xcf, 0x2c, 0x67, + 0xac, 0x87, 0x3e, 0xcd, 0x91, 0xd9, 0x65, 0xef, 0x03, 0xa6, 0x5c, 0xc5, + 0x5c, 0xac, 0x0f, 0x02, 0x43, 0x8e, 0xac, 0x74, 0x63, 0x3e, 0xf6, 0x90, + 0x3e, 0x93, 0x39, 0x24, 0x33, 0xfe, 0x41, 0xd0, 0x7f, 0x40, 0xca, 0xf0, + 0x95, 0x96, 0xb6, 0xa1, 0x57, 0xc6, 0xe1, 0x13, 0xbb, 0xb7, 0x13, 0xa3, + 0xa9, 0x98, 0x52, 0xd9, 0x1d, 0x45, 0xda, 0x83, 0xf4, 0x66, 0x29, 0x3f, + 0x73, 0x43, 0x54, 0xf7, 0xd7, 0xd5, 0xf1, 0xfe, 0x3c, 0xc7, 0x4e, 0x26, + 0xad, 0xdf, 0x86, 0x07, 0xdb, 0xb1, 0x20, 0xe9, 0xe8, 0x12, 0xef, 0xcb, + 0x7d, 0x32, 0xba, 0xe2, 0xca, 0xd8, 0x4a, 0x42, 0x0e, 0xae, 0x0c, 0xcb, + 0xf8, 0x4a, 0x52, 0x6e, 0x5d, 0x09, 0xf1, 0xd8, 0x83, 0xb3, 0x69, 0x63, + 0x07, 0xbc, 0xdf, 0xd1, 0x0e, 0xdc, 0xda, 0xd4, 0xd8, 0xb4, 0xbc, 0x71, + 0x01, 0x36, 0x7b, 0x07, 0xfb, 0x37, 0x03, 0x2c, 0xe6, 0x43, 0x27, 0x4d, + 0x42, 0x27, 0x8d, 0x43, 0x27, 0x4d, 0x53, 0x27, 0x01, 0xff, 0xbd, 0x0a, + 0xfc, 0x77, 0x8f, 0xbc, 0x06, 0x9d, 0xfb, 0x82, 0xdf, 0xe3, 0xce, 0x81, + 0x1f, 0x87, 0xd5, 0xb9, 0x57, 0xea, 0x2b, 0x3b, 0x90, 0x81, 0xc6, 0xd7, + 0x24, 0x3a, 0x00, 0x7d, 0x75, 0xfb, 0x7a, 0x8f, 0x6c, 0xc4, 0x83, 0xe0, + 0x34, 0xf6, 0xfa, 0x95, 0x8a, 0x96, 0xd9, 0xbc, 0xc7, 0x3d, 0xff, 0x20, + 0xe6, 0x3e, 0x89, 0xbc, 0x1c, 0x74, 0x98, 0x8e, 0xa3, 0x34, 0x8e, 0x26, + 0x64, 0xf3, 0xe0, 0x74, 0x47, 0xbd, 0x0c, 0xde, 0xa9, 0x33, 0xfe, 0x39, + 0xea, 0x53, 0x7f, 0xbb, 0xb2, 0x05, 0x8c, 0x78, 0xe6, 0x60, 0x6a, 0x3a, + 0x69, 0x53, 0xdf, 0x25, 0xa5, 0xfe, 0xb5, 0x84, 0x6c, 0x54, 0xb5, 0xcd, + 0x59, 0x00, 0x26, 0x2c, 0x00, 0xef, 0x6e, 0x00, 0x67, 0x15, 0x9a, 0x5a, + 0xdf, 0xdb, 0xd9, 0x2e, 0x61, 0x7f, 0x85, 0x66, 0x1e, 0xf8, 0x58, 0x9c, + 0x7c, 0x86, 0x74, 0x4e, 0x24, 0x22, 0x76, 0x0f, 0x64, 0x81, 0xfb, 0xe3, + 0x41, 0xd8, 0x53, 0x96, 0xd1, 0x36, 0x53, 0xff, 0x3f, 0x15, 0x25, 0xc6, + 0x2b, 0xf8, 0xc4, 0xd3, 0x79, 0x94, 0xa5, 0x12, 0x69, 0xe4, 0xcf, 0x49, + 0x5a, 0x9d, 0x21, 0x2d, 0x60, 0xcf, 0x97, 0x15, 0xcd, 0x11, 0xc6, 0xa4, + 0x28, 0x1e, 0x51, 0x1d, 0x2f, 0x0c, 0xf3, 0x27, 0xdc, 0x22, 0xd6, 0x38, + 0xc7, 0xbe, 0xab, 0xcc, 0x4b, 0xbb, 0x6c, 0x57, 0xf0, 0xf9, 0x2e, 0xf2, + 0x91, 0x26, 0xe3, 0x27, 0x51, 0x79, 0xb8, 0xd9, 0x07, 0x9a, 0xba, 0x7f, + 0x8b, 0x3d, 0x71, 0xdb, 0xec, 0xc9, 0x6e, 0xc2, 0x85, 0x9e, 0x58, 0x34, + 0x7a, 0xc5, 0x99, 0xd2, 0x18, 0xf8, 0xa5, 0x2a, 0xd6, 0xa8, 0x8a, 0x35, + 0xaa, 0x62, 0x8d, 0xaa, 0x58, 0xa3, 0x2a, 0xf5, 0x07, 0x75, 0x4d, 0xce, + 0x9c, 0x31, 0x50, 0x87, 0x3c, 0x8f, 0xb5, 0x9c, 0x93, 0x6f, 0x6f, 0xcf, + 0xca, 0x5f, 0x6c, 0x1f, 0x01, 0xc6, 0x9e, 0xc1, 0xba, 0xe6, 0xb0, 0xae, + 0xd3, 0x58, 0xd3, 0xa3, 0x58, 0xd3, 0x2c, 0xcf, 0xd9, 0xe4, 0xcb, 0x95, + 0xd4, 0x0b, 0x25, 0x85, 0xef, 0xdf, 0xc0, 0xfa, 0x4e, 0x89, 0xb7, 0x3e, + 0x0c, 0x9d, 0x50, 0x0a, 0xe2, 0x5e, 0x70, 0x08, 0x18, 0x1a, 0xf3, 0x2f, + 0xa5, 0x1c, 0x45, 0x83, 0xe7, 0x7e, 0x0a, 0x13, 0xbf, 0x21, 0x9b, 0xaa, + 0x51, 0x3d, 0x6d, 0xd5, 0xc6, 0xa5, 0x78, 0x0e, 0xf5, 0x4f, 0xf7, 0x81, + 0xdf, 0xc4, 0x6f, 0xa9, 0x52, 0x51, 0x76, 0xa0, 0xcf, 0x72, 0xa0, 0xf1, + 0xbd, 0x52, 0x8e, 0xa7, 0x9e, 0xe7, 0x3e, 0xbb, 0x71, 0x95, 0xf1, 0x01, + 0x1b, 0xbc, 0x21, 0xed, 0x78, 0x3e, 0x97, 0x55, 0x31, 0xbe, 0xbc, 0x7f, + 0xc0, 0xec, 0x63, 0x8d, 0x49, 0xeb, 0xc2, 0x71, 0x39, 0xde, 0x67, 0x64, + 0x11, 0xb8, 0xcf, 0xce, 0x12, 0x57, 0x78, 0x09, 0x8c, 0x19, 0x5d, 0x38, + 0xe7, 0x46, 0x17, 0xcf, 0xb1, 0x9f, 0xa8, 0xa4, 0x57, 0xa9, 0x97, 0xd8, + 0x0f, 0x74, 0x36, 0xfa, 0x8e, 0xa8, 0x33, 0xb5, 0x09, 0xb4, 0xfb, 0x03, + 0x60, 0x46, 0xcd, 0xc3, 0xfc, 0x69, 0x6d, 0xc7, 0xf2, 0x8d, 0x76, 0xcc, + 0x06, 0x1d, 0x02, 0x3b, 0x97, 0x6b, 0x68, 0xfc, 0x35, 0xa3, 0xf0, 0x99, + 0xc6, 0x66, 0x47, 0xe5, 0x50, 0xaf, 0xc4, 0x3c, 0x35, 0x9f, 0xf4, 0xe9, + 0x1d, 0x62, 0x52, 0x8c, 0xa1, 0xe3, 0xcc, 0x57, 0xe9, 0xce, 0x60, 0x2e, + 0x37, 0xf7, 0x86, 0x31, 0x41, 0x7b, 0x55, 0x9f, 0x41, 0xd9, 0xe7, 0x7c, + 0xcc, 0x47, 0x86, 0x18, 0x65, 0xb4, 0x31, 0x87, 0x7b, 0x95, 0x9d, 0x9d, + 0x62, 0xec, 0x0f, 0xb2, 0x4d, 0xfd, 0x32, 0x84, 0xbd, 0xc1, 0x77, 0x1d, + 0x53, 0xee, 0xf1, 0x28, 0x2f, 0x71, 0xc8, 0x20, 0x74, 0x4d, 0xff, 0xb0, + 0xd4, 0xb7, 0x59, 0x36, 0xac, 0xf4, 0xb0, 0x83, 0x35, 0x58, 0xae, 0x04, + 0x87, 0xf2, 0x7e, 0x09, 0xda, 0x92, 0x3c, 0x27, 0x3f, 0xc8, 0xf7, 0x49, + 0xd0, 0x46, 0x1e, 0xf7, 0x97, 0xf4, 0xb9, 0xe6, 0x7e, 0x29, 0xd6, 0xa8, + 0x8b, 0x91, 0xd6, 0xf7, 0x9b, 0xd8, 0x46, 0x5c, 0x72, 0x73, 0x9c, 0x3b, + 0x7d, 0x13, 0xa0, 0xba, 0xd5, 0x94, 0x5f, 0xb7, 0x67, 0xa5, 0x48, 0xf9, + 0x84, 0x6e, 0x2c, 0x6e, 0x4e, 0xc9, 0xf2, 0x1a, 0xe3, 0x7d, 0x3c, 0x7b, + 0x9e, 0x88, 0x4a, 0x7f, 0x10, 0x6c, 0xf9, 0xb4, 0xf3, 0x79, 0x29, 0x20, + 0xdf, 0x5e, 0x87, 0x9d, 0x3f, 0xaa, 0x79, 0xc7, 0xf9, 0x96, 0x37, 0xfe, + 0x6f, 0xf8, 0xf8, 0xf6, 0x38, 0x77, 0x66, 0x0f, 0x9c, 0xfb, 0xea, 0x39, + 0xc8, 0x5f, 0x15, 0xb2, 0x09, 0x9f, 0xe9, 0x2f, 0xaa, 0x90, 0x4d, 0xd8, + 0x8c, 0x6f, 0x56, 0x21, 0x9b, 0xd8, 0x3b, 0x2f, 0xc2, 0xa7, 0xd1, 0x98, + 0xe2, 0x11, 0x85, 0x29, 0x4e, 0x54, 0x89, 0xf9, 0x2f, 0x41, 0x96, 0x27, + 0x21, 0xc7, 0x49, 0xc8, 0xaf, 0x0f, 0xd9, 0x1d, 0x87, 0x3c, 0x7b, 0x90, + 0xe7, 0x61, 0x15, 0xf7, 0x79, 0x61, 0x3b, 0x2a, 0xf7, 0xc3, 0x9f, 0x38, + 0x53, 0x23, 0x1f, 0x8f, 0xcb, 0xff, 0x82, 0x2f, 0xb1, 0xeb, 0xef, 0x80, + 0x87, 0x39, 0x59, 0xf4, 0xc8, 0xaf, 0x9c, 0xbd, 0xe0, 0xd1, 0xd7, 0x70, + 0xe5, 0xcc, 0x06, 0x7d, 0x04, 0xea, 0x88, 0x57, 0xe5, 0x9b, 0x95, 0x1f, + 0xc8, 0xb7, 0x80, 0x05, 0x0a, 0xf0, 0x9b, 0x37, 0x9e, 0xa1, 0xcf, 0xa8, + 0x68, 0x84, 0xdc, 0xc5, 0x65, 0x73, 0xfb, 0x76, 0x79, 0xca, 0xa5, 0x0c, + 0xc7, 0xa1, 0x5b, 0xf0, 0x7e, 0x90, 0x7a, 0x28, 0x83, 0xfd, 0x09, 0x39, + 0x87, 0x6e, 0xa8, 0xd9, 0x3c, 0xc3, 0x28, 0x05, 0x03, 0xd4, 0x59, 0x35, + 0xcf, 0x1d, 0xb1, 0xc9, 0x9b, 0x5b, 0x18, 0x73, 0xfa, 0x0a, 0x84, 0x17, + 0x79, 0xb4, 0xd9, 0x48, 0xeb, 0xd0, 0x8d, 0xcf, 0x90, 0x8f, 0xf4, 0x61, + 0xf1, 0xbc, 0xc1, 0xbd, 0xf6, 0x73, 0x15, 0xcb, 0x2d, 0xce, 0xc1, 0x5f, + 0xdf, 0x20, 0x9f, 0x20, 0x2b, 0xcf, 0x90, 0x8f, 0xe4, 0x9d, 0xe6, 0xe3, + 0x43, 0x12, 0xf2, 0x90, 0x65, 0x9d, 0x3c, 0xfc, 0x77, 0x90, 0xc3, 0x38, + 0xe6, 0xfd, 0xd5, 0x28, 0x63, 0x8e, 0x37, 0x7a, 0x5c, 0xf3, 0x57, 0xe5, + 0xc9, 0x26, 0xc7, 0x7a, 0xd9, 0x8c, 0xf9, 0xfd, 0xe0, 0xe1, 0x38, 0x69, + 0xe7, 0x7a, 0xee, 0x93, 0xc6, 0x90, 0x6f, 0xe2, 0x2a, 0xbf, 0xcd, 0xde, + 0xb0, 0x1e, 0x78, 0x0d, 0xbd, 0xf2, 0xad, 0x2a, 0x78, 0x0c, 0xbf, 0xe9, + 0x1b, 0xf0, 0x9b, 0x18, 0x6b, 0xd4, 0xeb, 0x32, 0x6d, 0xe2, 0xa6, 0x9d, + 0xf1, 0xd2, 0x24, 0xd6, 0x85, 0xbe, 0x79, 0xaa, 0x74, 0x19, 0xba, 0xef, + 0x45, 0x9f, 0x71, 0xc4, 0x40, 0xbe, 0xef, 0xb7, 0x6b, 0x37, 0x15, 0x63, + 0x96, 0x87, 0xa0, 0x0f, 0x1f, 0x86, 0x3e, 0xfc, 0xc8, 0x75, 0xf7, 0x7b, + 0x28, 0x67, 0x4f, 0xcf, 0x2e, 0xac, 0x8d, 0x96, 0x22, 0xf6, 0xb0, 0xcc, + 0x5d, 0xa3, 0x1b, 0x19, 0x4f, 0x4c, 0x9a, 0x78, 0x68, 0x3b, 0xfe, 0x0c, + 0x63, 0x9e, 0x94, 0xe7, 0x40, 0x2e, 0xfa, 0xa5, 0xbe, 0x88, 0x3a, 0x97, + 0xe6, 0xba, 0xee, 0x85, 0x2d, 0xbf, 0x6d, 0xf6, 0x30, 0x65, 0xab, 0xf3, + 0xdc, 0x98, 0xe7, 0xd0, 0xfd, 0xf0, 0x13, 0xb8, 0x57, 0x53, 0xc9, 0x1c, + 0xf6, 0x73, 0x79, 0x9b, 0xfa, 0x9f, 0xd8, 0xb0, 0x9b, 0xf1, 0xbc, 0xf9, + 0x9e, 0x2c, 0x63, 0x01, 0xfd, 0xf0, 0x3f, 0x7e, 0x24, 0x5b, 0x6b, 0x7f, + 0xd3, 0xab, 0xf7, 0x91, 0xbe, 0x6f, 0x66, 0x9f, 0xeb, 0x8c, 0x63, 0xd2, + 0xa6, 0x4a, 0xb4, 0x17, 0x76, 0xf1, 0xd6, 0x67, 0xfb, 0x95, 0xdd, 0xbb, + 0xcf, 0x77, 0x64, 0x27, 0xce, 0xfe, 0x7e, 0x24, 0x3f, 0x5e, 0x1b, 0x89, + 0x31, 0xfe, 0xb9, 0x0c, 0x3e, 0xef, 0x2a, 0xdd, 0xf5, 0x20, 0xea, 0x64, + 0xe5, 0xf5, 0x35, 0xda, 0xd6, 0xb4, 0x7b, 0x46, 0x26, 0x12, 0x67, 0xc0, + 0xcb, 0x53, 0x68, 0x03, 0x7f, 0x38, 0x98, 0x41, 0xde, 0xcb, 0xf4, 0xb9, + 0x2d, 0x3e, 0x4f, 0xb8, 0x5f, 0x04, 0x4e, 0xce, 0xb9, 0x69, 0xb7, 0xd7, + 0xba, 0xa4, 0xce, 0x9d, 0x22, 0x1e, 0xfb, 0x1a, 0x92, 0xc2, 0xa6, 0xa6, + 0xf1, 0xca, 0x26, 0xc7, 0xe0, 0x5c, 0x48, 0xe3, 0xdf, 0xf0, 0x5c, 0x01, + 0xf4, 0xdf, 0x06, 0x9f, 0x84, 0x98, 0xe5, 0x12, 0x64, 0x66, 0x08, 0xfa, + 0x81, 0xbe, 0x0a, 0xcf, 0x2c, 0xc9, 0xb3, 0xcf, 0x03, 0xef, 0xc7, 0x21, + 0xab, 0xc8, 0xdf, 0xbc, 0xea, 0x1f, 0x2e, 0xb7, 0x70, 0x3d, 0x6d, 0xe3, + 0x2c, 0x6c, 0xe4, 0xbb, 0x14, 0x3d, 0x47, 0x7c, 0xf8, 0xda, 0xcf, 0x50, + 0xbe, 0x0e, 0x4a, 0x31, 0x4e, 0x5c, 0x49, 0x7d, 0xb2, 0x9b, 0x88, 0x02, + 0xd7, 0x46, 0x6f, 0xe7, 0xbe, 0x3b, 0x22, 0xf7, 0x7b, 0x0f, 0xca, 0x07, + 0xbd, 0x49, 0x99, 0xf1, 0xee, 0x91, 0xc3, 0x5e, 0x5e, 0xee, 0xf3, 0x60, + 0x9b, 0x14, 0x3e, 0xef, 0xc1, 0x3c, 0x38, 0xf6, 0x90, 0x39, 0xdf, 0xd3, + 0xf8, 0xf4, 0xeb, 0xdb, 0x5a, 0x27, 0xe5, 0xd7, 0xb2, 0x31, 0xda, 0xe4, + 0x23, 0xfe, 0x8c, 0xb1, 0xc9, 0xf0, 0xf9, 0x55, 0xbd, 0x19, 0x65, 0xbb, + 0xcb, 0x9b, 0x73, 0x48, 0x61, 0xc7, 0x37, 0xa7, 0x81, 0xfb, 0xe9, 0x4b, + 0xe5, 0xf0, 0x7e, 0x0f, 0xde, 0x3f, 0x84, 0xf4, 0x08, 0x52, 0x75, 0xae, + 0x19, 0xd3, 0xb1, 0xdb, 0xd6, 0xb9, 0x1d, 0xe4, 0xeb, 0xe8, 0xec, 0x42, + 0x2d, 0x8c, 0x81, 0x1f, 0x92, 0xc7, 0x7d, 0x7d, 0x96, 0x7e, 0x18, 0x7e, + 0x74, 0x0c, 0xf8, 0xe9, 0x43, 0xcf, 0x4e, 0x49, 0xe4, 0xee, 0x43, 0x62, + 0xdf, 0x6d, 0xc9, 0xc2, 0x24, 0xe8, 0x9b, 0x1c, 0xc5, 0x3c, 0x86, 0xe5, + 0xc4, 0xb6, 0xf2, 0x51, 0x0d, 0x5e, 0xa4, 0x1e, 0x07, 0xd6, 0xdd, 0x0e, + 0x71, 0x63, 0x37, 0x70, 0x05, 0xe3, 0x7b, 0x49, 0x85, 0x77, 0xed, 0x1b, + 0xb9, 0xbe, 0x7d, 0x92, 0xbf, 0x91, 0xfc, 0x63, 0x1e, 0xfc, 0x9d, 0x1b, + 0xb5, 0xdd, 0x48, 0xaf, 0x70, 0x6d, 0x7a, 0x4c, 0xec, 0x96, 0x36, 0x80, + 0xe9, 0x6a, 0xac, 0x85, 0x0b, 0x19, 0x9f, 0xb1, 0x6e, 0x8f, 0x5d, 0xbd, + 0x67, 0x16, 0xca, 0x73, 0x78, 0x7f, 0xc0, 0x53, 0x38, 0xe7, 0x44, 0xf5, + 0x05, 0xcc, 0x81, 0x36, 0x3d, 0x22, 0xdd, 0xd0, 0x6b, 0x5b, 0x1e, 0xf7, + 0x1e, 0x6d, 0xce, 0x11, 0xcc, 0x87, 0x36, 0x9e, 0xb6, 0xfe, 0xde, 0x7e, + 0xe9, 0xa7, 0x9d, 0x67, 0xfd, 0x24, 0xca, 0x58, 0x97, 0x79, 0x97, 0x51, + 0x9f, 0xb1, 0x29, 0xf8, 0x3e, 0xd5, 0x45, 0xe8, 0x19, 0x0f, 0xe9, 0xe3, + 0x48, 0xc7, 0x91, 0x3e, 0x81, 0x54, 0xc7, 0xb1, 0x36, 0x9f, 0x61, 0x2c, + 0x49, 0xc5, 0x68, 0x14, 0xbe, 0xa0, 0x4d, 0x9c, 0xf3, 0xa9, 0x27, 0x8f, + 0x8b, 0x3d, 0x75, 0x1b, 0xf2, 0xe8, 0x6b, 0x63, 0xd4, 0xf7, 0x7f, 0xde, + 0xc4, 0x88, 0x5a, 0x71, 0x25, 0x63, 0x07, 0xd6, 0xd0, 0x17, 0xfb, 0xa1, + 0x2f, 0xfb, 0x0b, 0x79, 0xf8, 0x9a, 0xd8, 0x5c, 0x2b, 0xde, 0x34, 0x5d, + 0x50, 0x3a, 0x96, 0x7c, 0x81, 0x7e, 0x75, 0x33, 0xf2, 0xb5, 0xed, 0x01, + 0xe8, 0xaf, 0x38, 0xb1, 0x26, 0xf0, 0xb6, 0xc6, 0x6e, 0x8b, 0x98, 0x9b, + 0xb6, 0xef, 0x71, 0xf9, 0xbb, 0xb5, 0x61, 0xf9, 0x71, 0x25, 0x21, 0xaf, + 0x57, 0x82, 0xe0, 0xa2, 0x9f, 0xf6, 0xef, 0x13, 0xb9, 0xbd, 0x5b, 0x9f, + 0xfd, 0xa3, 0x86, 0x3e, 0xaf, 0x2f, 0xab, 0x33, 0x7b, 0xd4, 0x83, 0x5e, + 0x79, 0xbd, 0xf9, 0xf7, 0xe0, 0xaf, 0xee, 0xb3, 0xb3, 0xed, 0xae, 0x6e, + 0xcb, 0x33, 0xff, 0xc4, 0x8e, 0xa4, 0xcd, 0xdd, 0x81, 0x34, 0xda, 0xa6, + 0xc7, 0x37, 0x5a, 0xed, 0xd9, 0x36, 0xa3, 0xec, 0x40, 0x71, 0x73, 0x50, + 0x1a, 0x7f, 0xca, 0xfd, 0x01, 0xbf, 0x53, 0x9d, 0xcb, 0x30, 0xe5, 0x39, + 0x07, 0xeb, 0x24, 0x4d, 0xf9, 0x88, 0x29, 0xf7, 0x54, 0x6c, 0x70, 0xb9, + 0x4a, 0x19, 0x85, 0x1f, 0x4a, 0x6c, 0xd8, 0x24, 0x76, 0x0d, 0xe3, 0x61, + 0xd4, 0xd3, 0xb3, 0x52, 0x56, 0x71, 0x2d, 0xda, 0xa0, 0x5e, 0x15, 0xd3, + 0xd2, 0xb1, 0x3e, 0x96, 0x3d, 0x2c, 0x73, 0xee, 0x71, 0x19, 0x98, 0xba, + 0x36, 0x6e, 0xd7, 0xeb, 0x1d, 0x87, 0x6f, 0xa5, 0xec, 0xac, 0xfb, 0x41, + 0x21, 0x8f, 0xbb, 0x69, 0x17, 0x72, 0xb6, 0x05, 0xdf, 0xf4, 0xcb, 0x19, + 0x79, 0x7e, 0x3b, 0x95, 0x14, 0xac, 0xd7, 0x07, 0xe1, 0x7b, 0xda, 0xcf, + 0xe1, 0x9d, 0x71, 0xae, 0x67, 0xe3, 0x12, 0x79, 0x76, 0x58, 0x7a, 0x56, + 0x88, 0x3f, 0xc8, 0xd3, 0x84, 0x74, 0xaf, 0x10, 0xfb, 0x32, 0x2e, 0x9c, + 0x9a, 0xbe, 0x22, 0x8c, 0xb7, 0xa4, 0xfc, 0x0b, 0xf8, 0xed, 0x62, 0xde, + 0x3d, 0xf0, 0x9b, 0xbb, 0xcf, 0xea, 0x76, 0xf6, 0xd6, 0x10, 0x00, 0x1f, + 0x7c, 0xee, 0x15, 0xfa, 0xd9, 0x4c, 0xe9, 0x77, 0xb3, 0x0c, 0xb2, 0xbd, + 0x35, 0x62, 0xca, 0xe8, 0x53, 0x73, 0x7c, 0x9e, 0xd9, 0xeb, 0x7b, 0xa0, + 0xf6, 0x18, 0x7d, 0x52, 0x5f, 0x5e, 0xdc, 0x60, 0x0c, 0xfc, 0x55, 0xf8, + 0x6f, 0x19, 0x89, 0xac, 0x64, 0x20, 0x87, 0x3e, 0x6c, 0x29, 0x71, 0x1c, + 0xed, 0x17, 0xf2, 0x61, 0x73, 0x36, 0x9e, 0x51, 0x31, 0x87, 0x92, 0x93, + 0x85, 0xcc, 0xd5, 0x3f, 0x63, 0x97, 0xdb, 0x6c, 0x54, 0xd9, 0xd8, 0xa8, + 0xb2, 0xb1, 0x51, 0xe5, 0x66, 0xb8, 0x3f, 0x38, 0xc6, 0x71, 0xd8, 0xd5, + 0x2e, 0x79, 0x2a, 0x4e, 0x59, 0xd1, 0xb2, 0x17, 0xb1, 0xc7, 0x94, 0xac, + 0xce, 0xd0, 0xde, 0x3e, 0xe3, 0xee, 0x83, 0xaf, 0x55, 0x52, 0x7b, 0xe3, + 0x99, 0x50, 0xce, 0x78, 0xe7, 0x33, 0x90, 0x1a, 0xb0, 0x4c, 0xd9, 0xb3, + 0x64, 0xc9, 0x3b, 0xae, 0xb0, 0xde, 0xc3, 0xe8, 0xe3, 0x49, 0xd3, 0xc7, + 0x92, 0x8c, 0x19, 0x79, 0xe7, 0xda, 0x44, 0xd5, 0x79, 0xc5, 0x43, 0xfe, + 0xef, 0xc9, 0xc0, 0x20, 0xd7, 0x93, 0xf2, 0x4f, 0x7c, 0xc1, 0xf5, 0x60, + 0x8c, 0xff, 0x6d, 0x63, 0xa9, 0xea, 0x0e, 0x5f, 0xa1, 0x42, 0x5b, 0xb2, + 0x1f, 0xf2, 0x9b, 0x81, 0xff, 0x1d, 0xc6, 0x53, 0xd5, 0xbe, 0x4a, 0xd8, + 0x36, 0xec, 0xda, 0xd8, 0xd8, 0x78, 0x51, 0x8e, 0x4b, 0x19, 0x7e, 0x2b, + 0x69, 0x58, 0x82, 0x1d, 0xdb, 0xf0, 0xff, 0x2e, 0xf8, 0x64, 0x3c, 0x55, + 0x9a, 0x97, 0xce, 0x18, 0x27, 0x7d, 0xf1, 0xb7, 0x8b, 0x73, 0x1e, 0x51, + 0xfa, 0xf1, 0x5a, 0x2c, 0x15, 0xc6, 0x38, 0xe7, 0x3a, 0x62, 0x9c, 0xfa, + 0xec, 0xac, 0x27, 0x4b, 0xbd, 0x7e, 0xca, 0xfa, 0x71, 0x26, 0x22, 0x0d, + 0x60, 0xca, 0xfb, 0x7c, 0x62, 0xa4, 0x92, 0xf5, 0x7a, 0x45, 0xd4, 0x7b, + 0xc1, 0x8f, 0xe8, 0x58, 0xbb, 0x0b, 0xdb, 0xb2, 0xed, 0x98, 0xb3, 0x22, + 0x07, 0x79, 0xb6, 0xf2, 0x77, 0x8b, 0x4a, 0x27, 0x27, 0xfa, 0x24, 0x46, + 0x3d, 0x75, 0x2f, 0xde, 0x79, 0x5e, 0x71, 0xa4, 0x23, 0x7f, 0x67, 0x80, + 0x7b, 0xac, 0x0c, 0x3c, 0xb6, 0xe4, 0x69, 0x7e, 0x39, 0xe0, 0xf1, 0x0c, + 0x30, 0xce, 0x95, 0x26, 0x71, 0x6d, 0xcc, 0xe0, 0x5a, 0xe2, 0x26, 0xac, + 0xd1, 0xf6, 0x28, 0xca, 0x88, 0x9d, 0xe2, 0xca, 0xaf, 0x53, 0x58, 0xca, + 0x2f, 0x18, 0x3b, 0x41, 0x99, 0xa2, 0x3c, 0x11, 0x93, 0x69, 0x99, 0x5a, + 0xa8, 0xb8, 0x1d, 0xf2, 0xe4, 0xfe, 0x23, 0xe5, 0xe9, 0xa6, 0x3e, 0x9e, + 0xf7, 0xbc, 0x84, 0xfd, 0x79, 0x12, 0xf6, 0x74, 0xa3, 0xb6, 0x4f, 0x76, + 0x6b, 0xa3, 0xc0, 0xc5, 0xcc, 0xe3, 0xbe, 0x4c, 0xc8, 0xfd, 0x95, 0x59, + 0x39, 0x5c, 0x8b, 0xca, 0xc5, 0x9a, 0x7d, 0x4f, 0x8f, 0x30, 0x46, 0x4d, + 0xcc, 0xf1, 0x0d, 0xa5, 0xd7, 0x7e, 0xe2, 0x5f, 0x6d, 0xbf, 0x84, 0xf6, + 0x0d, 0xb4, 0x5f, 0xa8, 0xdd, 0x28, 0x45, 0xd5, 0x7e, 0xfd, 0xba, 0x31, + 0xae, 0xd6, 0xe9, 0x33, 0xf6, 0x33, 0x3c, 0x97, 0xa4, 0x6d, 0xee, 0xc2, + 0xbc, 0xe1, 0x27, 0x65, 0x90, 0xd6, 0x79, 0x36, 0x49, 0xdb, 0xfe, 0x47, + 0xae, 0x4e, 0x13, 0x6d, 0x76, 0x21, 0xd9, 0x66, 0x17, 0xde, 0x68, 0xbb, + 0x4b, 0xa9, 0xef, 0x65, 0xbf, 0x9c, 0x01, 0xf6, 0xab, 0x0d, 0xb5, 0xdd, + 0xa9, 0x48, 0x95, 0x68, 0x93, 0x18, 0x0b, 0xdb, 0xac, 0x84, 0xba, 0x3a, + 0x37, 0xc0, 0x38, 0xfe, 0xb2, 0x4f, 0xbe, 0x4b, 0x32, 0x92, 0xa5, 0xae, + 0xf7, 0xa3, 0xbb, 0xc0, 0x68, 0x0d, 0x75, 0x4e, 0x1d, 0xc1, 0x0f, 0xb6, + 0xd0, 0xb1, 0xc4, 0xf5, 0x98, 0x57, 0xd2, 0x58, 0xd7, 0x85, 0xde, 0xb4, + 0x55, 0x9d, 0x64, 0xde, 0xbf, 0xc9, 0xbc, 0x43, 0xbf, 0x55, 0xde, 0x3b, + 0x6c, 0x67, 0xff, 0xfb, 0xcd, 0xf9, 0x0c, 0xcf, 0x0e, 0x99, 0x47, 0xcc, + 0xfb, 0x03, 0x60, 0x5e, 0xde, 0xb7, 0xe5, 0xba, 0xbc, 0x89, 0xf5, 0xbf, + 0x08, 0xdb, 0xe2, 0x41, 0xaf, 0x3b, 0xb2, 0x90, 0xb9, 0x68, 0xce, 0x2e, + 0x38, 0xb7, 0x6e, 0xd8, 0xa8, 0x1f, 0xc9, 0xe1, 0xb5, 0x14, 0xb0, 0x4a, + 0x88, 0xaf, 0xd8, 0xc7, 0xf5, 0xd8, 0xea, 0x44, 0xb5, 0xfd, 0xfc, 0x37, + 0xbc, 0x3f, 0x4a, 0xd9, 0x50, 0xe7, 0xda, 0x56, 0x81, 0xf1, 0xc0, 0xd5, + 0x1f, 0x60, 0x9e, 0xa9, 0x53, 0x22, 0x3c, 0xeb, 0x62, 0x9c, 0x17, 0x3e, + 0xc2, 0x36, 0xf3, 0xe7, 0xd0, 0xf7, 0x0f, 0x78, 0x97, 0x16, 0xfe, 0x93, + 0x6d, 0xf8, 0xf3, 0xfb, 0xc6, 0xbf, 0x8f, 0x32, 0x36, 0x0a, 0xd9, 0x2f, + 0x2b, 0xdb, 0x5d, 0x8c, 0x2f, 0x23, 0xfd, 0x1f, 0xc6, 0x56, 0x7f, 0xbd, + 0x4f, 0xdb, 0x6a, 0xde, 0x03, 0xf9, 0x02, 0xf7, 0x96, 0xa1, 0x9b, 0xf4, + 0x92, 0xee, 0x2e, 0xe9, 0x3e, 0x4d, 0x9a, 0xbf, 0x82, 0x7a, 0x94, 0x8d, + 0x83, 0xe6, 0xbe, 0x08, 0xcf, 0xc1, 0xd9, 0x27, 0x6c, 0x84, 0xc2, 0x5b, + 0x39, 0xa4, 0x6c, 0xb7, 0x86, 0x7a, 0x39, 0xcc, 0x59, 0x61, 0xb0, 0xa1, + 0x88, 0x84, 0x79, 0xf7, 0x22, 0x8f, 0x3e, 0xe5, 0x4d, 0xf0, 0x29, 0x99, + 0x97, 0xc7, 0x3b, 0xc7, 0xba, 0xd9, 0x8c, 0x63, 0x30, 0xdd, 0x35, 0x34, + 0x71, 0x2e, 0xe1, 0x5a, 0x77, 0x9b, 0x33, 0x73, 0xe6, 0xdd, 0x64, 0xf2, + 0x1c, 0x33, 0xbf, 0x61, 0x73, 0x8f, 0x3d, 0x75, 0x2a, 0x27, 0xa1, 0xec, + 0x93, 0xbe, 0x68, 0x1b, 0x16, 0xfc, 0x83, 0xc1, 0xab, 0x77, 0x1c, 0x29, + 0x6b, 0x94, 0xaf, 0x84, 0xba, 0xbf, 0xc7, 0xf3, 0xf2, 0x17, 0x14, 0xfe, + 0x0e, 0x71, 0x95, 0xd2, 0x65, 0x3c, 0x07, 0xa8, 0xd9, 0xd9, 0x9e, 0xdf, + 0xf9, 0x3e, 0x5b, 0x24, 0x1b, 0xb6, 0x03, 0x1e, 0x52, 0x6d, 0x92, 0xb2, + 0xd8, 0x7c, 0xbb, 0xbb, 0x6f, 0xc0, 0x68, 0xd7, 0xdc, 0x67, 0x49, 0x28, + 0xfd, 0xb3, 0x51, 0x8b, 0x80, 0xbf, 0x43, 0x78, 0xbe, 0x0c, 0x1e, 0x44, + 0x31, 0x4f, 0xe0, 0xf4, 0xf8, 0x4d, 0xea, 0xbe, 0x4f, 0xc4, 0xbb, 0xa4, + 0xce, 0x8d, 0x0a, 0xf5, 0x9f, 0xa9, 0xb2, 0xaf, 0xad, 0xf5, 0xf0, 0x0e, + 0x28, 0x52, 0x9e, 0x43, 0xff, 0x06, 0x32, 0xd8, 0x65, 0x64, 0x10, 0x69, + 0x9d, 0xf9, 0xb7, 0xc0, 0x87, 0x14, 0xc8, 0x4b, 0x37, 0xb0, 0xbd, 0xf2, + 0x13, 0x30, 0x9b, 0xab, 0x34, 0x74, 0x67, 0xc3, 0x3b, 0x97, 0x81, 0x1c, + 0x86, 0x6c, 0x6c, 0x4c, 0x2f, 0x4b, 0x63, 0xba, 0x1d, 0x27, 0x02, 0x07, + 0xba, 0xa5, 0xa0, 0xe1, 0x31, 0xd6, 0xd7, 0x6f, 0xee, 0xbf, 0x2d, 0x1a, + 0x6c, 0x47, 0xfe, 0xdb, 0x52, 0x98, 0x5c, 0x52, 0x32, 0xd5, 0x50, 0xeb, + 0xe0, 0x58, 0xe7, 0xd5, 0xdd, 0x59, 0x8e, 0xc1, 0xfb, 0xb3, 0x11, 0x83, + 0x71, 0xfe, 0xa9, 0x59, 0xcf, 0xef, 0xf7, 0x85, 0xdf, 0x64, 0x74, 0x65, + 0x4f, 0xf2, 0xce, 0x08, 0xf0, 0x6b, 0x6d, 0x76, 0xa1, 0x42, 0xbd, 0x16, + 0x04, 0x0d, 0x7f, 0x07, 0x3d, 0xbe, 0xa9, 0xf0, 0xd9, 0xae, 0x68, 0xfd, + 0xb9, 0xa4, 0xee, 0xa1, 0x56, 0x66, 0xf3, 0x2a, 0xa6, 0x06, 0xdc, 0xd1, + 0x3a, 0xbf, 0x78, 0xa7, 0xb3, 0x8b, 0x28, 0xfc, 0xe5, 0x5e, 0xb3, 0xee, + 0x51, 0xa7, 0x58, 0xe9, 0x73, 0x16, 0xd4, 0xb9, 0xd2, 0xe7, 0xcc, 0xf7, + 0x2b, 0xa5, 0xd9, 0x74, 0x33, 0xbb, 0x9f, 0x58, 0x9a, 0x31, 0xfd, 0x42, + 0x85, 0x67, 0x19, 0xba, 0x3c, 0x6d, 0xca, 0x47, 0x9a, 0xaa, 0x4c, 0xc5, + 0xe4, 0xe0, 0x77, 0xc1, 0xae, 0x30, 0xfe, 0x47, 0xdd, 0x82, 0xfe, 0xe3, + 0x7a, 0x0e, 0x91, 0xec, 0x32, 0x7c, 0x3b, 0xd2, 0x77, 0x6a, 0x36, 0xbf, + 0xc6, 0x7b, 0x47, 0x5f, 0x9a, 0xbd, 0x08, 0xff, 0x63, 0xcb, 0xd3, 0x77, + 0xb5, 0x37, 0x19, 0x3b, 0x62, 0x3b, 0xd5, 0xe7, 0xb2, 0x89, 0x65, 0x9e, + 0x9c, 0x1d, 0xdd, 0x8c, 0xc8, 0x49, 0xd3, 0x07, 0xdf, 0x93, 0x2d, 0xdf, + 0x44, 0xe9, 0x3b, 0x60, 0xf0, 0x27, 0x80, 0xc1, 0x63, 0xb0, 0x8b, 0xc4, + 0xf2, 0xc4, 0xb7, 0x31, 0xec, 0x15, 0x8e, 0xf3, 0xaf, 0xd5, 0x38, 0x11, + 0x8c, 0xb3, 0xb0, 0x76, 0x40, 0xdd, 0x23, 0xc9, 0x7b, 0x0e, 0xec, 0x34, + 0xec, 0xa9, 0xc7, 0x58, 0xb2, 0x8d, 0x39, 0x8f, 0x43, 0x1f, 0xf0, 0x6e, + 0xc7, 0x60, 0x78, 0xef, 0x85, 0x77, 0xad, 0x4c, 0xbb, 0x4f, 0xa3, 0x1d, + 0x31, 0x38, 0xdb, 0xca, 0x8d, 0xb6, 0x8c, 0x2a, 0xbb, 0xab, 0x75, 0x0e, + 0x69, 0xa8, 0x63, 0xae, 0xb4, 0x5d, 0xd8, 0x6b, 0x6a, 0x5e, 0x9f, 0x56, + 0xed, 0xac, 0xec, 0x53, 0xa0, 0x9d, 0xd8, 0x0a, 0x7d, 0x57, 0x75, 0x7c, + 0xb0, 0xa0, 0xe4, 0x08, 0x72, 0x32, 0x1d, 0xde, 0x17, 0xd1, 0xed, 0xc2, + 0xfa, 0x23, 0x9b, 0x9f, 0x35, 0xe3, 0xff, 0x32, 0xc8, 0x1d, 0x8d, 0xa9, + 0xfb, 0x39, 0x2f, 0x5d, 0x73, 0x87, 0x8a, 0x6d, 0xc2, 0x3a, 0x11, 0x23, + 0x5b, 0x27, 0xda, 0x68, 0xfe, 0x9c, 0x59, 0x73, 0xb6, 0x63, 0xfc, 0x94, + 0x79, 0x25, 0xe6, 0x39, 0x8b, 0x19, 0xf6, 0xd1, 0x7e, 0xee, 0x32, 0x09, + 0x5b, 0xae, 0x6d, 0x46, 0x69, 0xdb, 0x83, 0x4d, 0xec, 0xc6, 0xda, 0xd1, + 0x06, 0x8c, 0x1a, 0xdc, 0xfe, 0x8e, 0x71, 0x49, 0xa7, 0x98, 0x81, 0x1f, + 0xdf, 0x6a, 0xcf, 0x75, 0x2c, 0xcd, 0x5e, 0xac, 0x78, 0x72, 0xa2, 0xaa, + 0xef, 0x37, 0x69, 0x3e, 0x50, 0x37, 0x73, 0x6d, 0x93, 0xb2, 0xe0, 0x31, + 0xfe, 0x91, 0x94, 0x57, 0xbc, 0x76, 0x3d, 0x8d, 0xfa, 0xdb, 0x93, 0xe6, + 0x8e, 0xf3, 0xa7, 0x31, 0x7f, 0xe2, 0x31, 0x2d, 0x4b, 0x07, 0x61, 0x77, + 0xfe, 0x83, 0x43, 0x9d, 0xdd, 0x2d, 0x97, 0x9d, 0xf6, 0xf9, 0x85, 0x71, + 0x6e, 0x2d, 0x97, 0x0e, 0x64, 0x64, 0xb9, 0xc5, 0x77, 0xf8, 0xbf, 0xef, + 0x1b, 0x83, 0x8e, 0xb7, 0x64, 0x66, 0xd2, 0x4b, 0x2c, 0x31, 0xee, 0xef, + 0x4e, 0xb8, 0xae, 0xba, 0xa7, 0x97, 0x04, 0xbd, 0x7c, 0x1e, 0x05, 0x06, + 0xe1, 0x9d, 0x3a, 0xbc, 0xf3, 0x4e, 0x5b, 0xdc, 0x03, 0xbd, 0xae, 0x8a, + 0xe7, 0x6b, 0x1d, 0xfd, 0xf5, 0xfd, 0x8c, 0xa7, 0x0c, 0x78, 0xe1, 0xda, + 0xab, 0x7b, 0xcd, 0xe8, 0x3b, 0x62, 0xca, 0x07, 0x5b, 0xfc, 0x97, 0x21, + 0xa6, 0xad, 0xbb, 0x52, 0x26, 0x6e, 0xc1, 0xfa, 0x9f, 0x51, 0xb4, 0x2c, + 0x78, 0x41, 0xb0, 0xa8, 0xe6, 0xf3, 0x34, 0x64, 0x21, 0x22, 0xe5, 0x96, + 0xfc, 0x3e, 0x0d, 0xf9, 0xdd, 0xc7, 0x6b, 0x35, 0x7b, 0xc8, 0x5a, 0x28, + 0x63, 0x94, 0x2f, 0xca, 0x56, 0xa2, 0x9f, 0x7b, 0xae, 0xd4, 0x5a, 0x77, + 0x47, 0xd9, 0xd8, 0xa4, 0x1d, 0xae, 0x3b, 0x9f, 0xf7, 0xba, 0x93, 0x14, + 0xee, 0x8f, 0xcc, 0x3f, 0x62, 0x6d, 0x7d, 0xb3, 0xb6, 0x99, 0xb6, 0x6f, + 0x0b, 0xc2, 0xfe, 0x18, 0x3b, 0x54, 0xf6, 0x38, 0x21, 0xd0, 0xd9, 0x25, + 0x7d, 0xbf, 0x57, 0xe1, 0xd6, 0x9c, 0x9b, 0x4f, 0x32, 0x4e, 0x7c, 0x4c, + 0xee, 0x02, 0xcd, 0xb9, 0xf1, 0x2e, 0xd1, 0x6d, 0xe7, 0xc1, 0xef, 0x1d, + 0x17, 0xbe, 0x16, 0xcf, 0x6c, 0x2b, 0x8e, 0x6c, 0xa9, 0xb3, 0x47, 0xec, + 0xd1, 0x98, 0x23, 0xcb, 0x5e, 0xd8, 0x6f, 0x54, 0xea, 0xa8, 0xb3, 0x81, + 0xb2, 0x93, 0x2d, 0xda, 0x88, 0xd3, 0xe1, 0xa7, 0x78, 0xbf, 0x0c, 0x8a, + 0xf1, 0x6b, 0xea, 0x9a, 0x7b, 0xfa, 0x8c, 0x77, 0xf4, 0x29, 0x1f, 0xaa, + 0x00, 0x9f, 0xab, 0x00, 0x7f, 0xab, 0xa0, 0xf4, 0x02, 0xe3, 0x1f, 0x8c, + 0x4f, 0x95, 0x80, 0xed, 0x4b, 0x41, 0x8f, 0x77, 0x5c, 0xc5, 0xdd, 0x5e, + 0xd8, 0xa6, 0x0f, 0xe0, 0x25, 0xef, 0x97, 0xd0, 0x86, 0xf4, 0x97, 0xa2, + 0xd9, 0xf6, 0x18, 0x56, 0x52, 0xc5, 0x80, 0x7a, 0x81, 0x43, 0x1f, 0x87, + 0xae, 0x7e, 0xd1, 0x67, 0xec, 0xea, 0x56, 0xf2, 0xfb, 0x2b, 0x9c, 0xa4, + 0x3d, 0x36, 0x29, 0xde, 0x59, 0x6f, 0xfc, 0x7e, 0x21, 0xb6, 0x4f, 0x25, + 0x8f, 0x90, 0x6f, 0xad, 0xef, 0x04, 0x42, 0xbb, 0x3a, 0x29, 0xa3, 0x67, + 0x7f, 0xa4, 0xce, 0x04, 0x3e, 0xe2, 0x77, 0xca, 0x86, 0x8a, 0x7d, 0x4d, + 0x0e, 0xc8, 0x28, 0xfc, 0x4a, 0x81, 0x75, 0xe2, 0x77, 0x03, 0x96, 0x2c, + 0x67, 0xd4, 0xbb, 0xcc, 0x35, 0x93, 0xe6, 0x9e, 0x25, 0x63, 0x5b, 0x8c, + 0x8d, 0x71, 0x4d, 0xfb, 0xd4, 0xdd, 0x4a, 0xde, 0xff, 0x9b, 0x69, 0x6a, + 0x9b, 0x9b, 0x53, 0x77, 0x1c, 0x19, 0x2b, 0x63, 0xcc, 0x4b, 0xdf, 0x9f, + 0x3b, 0xdc, 0xdc, 0x2b, 0x2e, 0x16, 0xde, 0xf7, 0xd3, 0x76, 0x6b, 0x37, + 0x73, 0x00, 0xb6, 0xce, 0x55, 0xf1, 0x89, 0xa2, 0x3b, 0x20, 0xc7, 0xc6, + 0x7b, 0xc0, 0xf3, 0x41, 0x75, 0x17, 0xcd, 0xf6, 0xde, 0x2f, 0x5d, 0xb4, + 0x9b, 0xae, 0xba, 0x23, 0x6d, 0xf8, 0x7c, 0x07, 0xf2, 0x7e, 0x05, 0xde, + 0x33, 0xef, 0x63, 0xfd, 0xda, 0x0e, 0x7d, 0x0a, 0x78, 0x9b, 0xf7, 0xca, + 0xeb, 0x07, 0xf2, 0x6a, 0x3d, 0xe8, 0xf7, 0x86, 0xba, 0x29, 0xbc, 0xff, + 0x18, 0x85, 0x6d, 0x72, 0xcd, 0x79, 0x71, 0x49, 0x96, 0x88, 0x01, 0x37, + 0xa9, 0x7f, 0x2c, 0x35, 0xd6, 0xe5, 0xc8, 0xbb, 0xa4, 0x54, 0xdf, 0xeb, + 0xdc, 0x3b, 0x08, 0xbe, 0xe1, 0xab, 0x3b, 0x97, 0xa7, 0x4a, 0x66, 0x8d, + 0xf5, 0x37, 0x85, 0x4e, 0xdb, 0x7d, 0xee, 0xa8, 0xd2, 0xbb, 0xb9, 0x41, + 0x60, 0x15, 0xef, 0xa3, 0xfd, 0x57, 0xef, 0xf0, 0xfd, 0xc6, 0xe0, 0x58, + 0xde, 0xdf, 0xd3, 0x77, 0xbb, 0xed, 0x46, 0x28, 0x27, 0xf4, 0x9b, 0x89, + 0x9f, 0x0f, 0xc2, 0xa7, 0x86, 0xde, 0x1c, 0xe2, 0xfb, 0x5f, 0x9a, 0xb6, + 0x7c, 0x0e, 0xe4, 0xbe, 0xa9, 0xce, 0x33, 0xed, 0x69, 0x7d, 0x0f, 0x3c, + 0x16, 0xde, 0x73, 0x1f, 0xee, 0xb8, 0x9b, 0xa4, 0xe8, 0x84, 0x3c, 0x85, + 0x34, 0xe8, 0xb1, 0x0e, 0x83, 0xde, 0x46, 0x2d, 0x21, 0x83, 0x1e, 0x7d, + 0xc5, 0x88, 0x4c, 0x0d, 0xa6, 0x5a, 0x77, 0xcd, 0x1b, 0x75, 0xd8, 0xfc, + 0x5a, 0x48, 0xa7, 0xbe, 0x6b, 0xd8, 0xa8, 0xb3, 0x3c, 0x89, 0xb1, 0x7a, + 0x64, 0x6a, 0x88, 0x7c, 0xee, 0xa4, 0x23, 0x61, 0xee, 0x23, 0x77, 0xe6, + 0xdf, 0xdd, 0x46, 0xdf, 0xf5, 0xdf, 0x62, 0xea, 0xfb, 0x8f, 0xbc, 0xcb, + 0x4e, 0x1a, 0x79, 0xce, 0x82, 0x39, 0xfa, 0xa1, 0x6f, 0x11, 0xf2, 0x65, + 0x50, 0xdd, 0x97, 0x2f, 0xd4, 0xbb, 0x94, 0x5c, 0x2c, 0x64, 0x38, 0x17, + 0xe2, 0xa0, 0xf0, 0x4e, 0xfc, 0x3f, 0x39, 0xa0, 0xd7, 0xfc, 0x63, 0xe1, + 0x1c, 0x4d, 0x3e, 0xdb, 0xdf, 0x82, 0x36, 0x5f, 0x0d, 0xd0, 0x3f, 0x83, + 0x5b, 0xd8, 0xf3, 0x21, 0x36, 0xbf, 0x45, 0xb7, 0x8f, 0x85, 0xdf, 0xe3, + 0xb5, 0x7f, 0x1f, 0xc0, 0x3d, 0x15, 0xf2, 0x8d, 0x7d, 0x70, 0x7c, 0xd2, + 0xc1, 0x71, 0x7b, 0xdb, 0xc6, 0x55, 0x3f, 0xff, 0x5a, 0xbd, 0x76, 0x47, + 0xdb, 0x7c, 0x29, 0x5f, 0xfd, 0xb2, 0x54, 0x8b, 0x49, 0xb9, 0xa6, 0xfc, + 0x99, 0x71, 0x20, 0x36, 0xe0, 0x39, 0xee, 0x45, 0x75, 0xff, 0xd6, 0xdc, + 0x2d, 0x0c, 0xf7, 0x64, 0x3f, 0xea, 0xd1, 0x6e, 0x20, 0xad, 0x6b, 0x9d, + 0x54, 0x97, 0xeb, 0xbf, 0x77, 0x58, 0x6c, 0x7d, 0xef, 0xa0, 0xfd, 0xe3, + 0x62, 0xeb, 0x6e, 0x46, 0xb4, 0x34, 0x98, 0x6d, 0xbf, 0xef, 0x53, 0x92, + 0x87, 0xee, 0xe4, 0x77, 0x06, 0x31, 0x23, 0x97, 0xef, 0x37, 0xe3, 0x60, + 0xbc, 0xd5, 0x69, 0x19, 0x59, 0xfd, 0xbc, 0x14, 0xe7, 0xd4, 0x9d, 0xed, + 0xb6, 0x3b, 0xfb, 0xa3, 0xe6, 0x3b, 0xa2, 0x9c, 0xc5, 0x3b, 0x20, 0x85, + 0x55, 0xac, 0xd1, 0x9d, 0xa9, 0xf1, 0xa4, 0xcd, 0x6f, 0x59, 0x1f, 0x95, + 0x91, 0xf5, 0x69, 0x49, 0xaf, 0x12, 0x27, 0xf0, 0x74, 0x3c, 0xa5, 0xe2, + 0x8d, 0xe9, 0x73, 0xba, 0x3f, 0x6f, 0x95, 0xe5, 0x69, 0x60, 0x54, 0x96, + 0x17, 0x12, 0x11, 0x75, 0x82, 0x7e, 0x1b, 0x64, 0xa8, 0xdb, 0x60, 0x00, + 0x47, 0xf2, 0xab, 0x6c, 0x4f, 0xbc, 0xf1, 0x1c, 0xd6, 0xac, 0x90, 0xb4, + 0x85, 0x6d, 0x54, 0x7f, 0x78, 0x8e, 0x2a, 0xec, 0x5c, 0xc8, 0x90, 0xd7, + 0x93, 0xb2, 0xd9, 0xf4, 0xb0, 0x0f, 0xf4, 0x3d, 0xff, 0x62, 0x3d, 0xbc, + 0x77, 0xf9, 0x90, 0xf9, 0x6e, 0x40, 0xd3, 0x38, 0x53, 0xe9, 0x94, 0xb7, + 0xc7, 0xcc, 0x7d, 0x7f, 0xce, 0xdb, 0x6d, 0xd7, 0x79, 0xa6, 0xfe, 0x6b, + 0x07, 0x78, 0x96, 0x4e, 0x9f, 0x68, 0xa4, 0xdd, 0xff, 0x88, 0xc7, 0xcd, + 0x77, 0x16, 0x61, 0xbd, 0xff, 0x7d, 0x40, 0xdf, 0xd5, 0x27, 0x9f, 0xb2, + 0x86, 0xe6, 0x29, 0xe5, 0xdf, 0xbc, 0x54, 0x3d, 0x88, 0xb6, 0x5c, 0x27, + 0xa4, 0x0d, 0x3e, 0x53, 0x6f, 0x1e, 0x31, 0x67, 0x4e, 0x43, 0x6a, 0x2c, + 0x37, 0xdb, 0xfe, 0x0d, 0x48, 0x6f, 0xdb, 0xf8, 0x9d, 0xf4, 0xf2, 0x9b, + 0x90, 0x8b, 0x46, 0x5e, 0x58, 0xce, 0xf7, 0xce, 0x3a, 0x87, 0x0e, 0x84, + 0xe5, 0x4e, 0xeb, 0xbb, 0x01, 0xf2, 0x92, 0xe7, 0x65, 0x48, 0x79, 0x4e, + 0xa9, 0x9e, 0x91, 0x9a, 0xef, 0x21, 0x9c, 0x55, 0xfe, 0x3a, 0xfb, 0x71, + 0xd0, 0x77, 0xb8, 0x4f, 0xf7, 0xba, 0x17, 0x43, 0xfd, 0x7b, 0xca, 0xda, + 0xad, 0x44, 0xe9, 0xef, 0xc8, 0xb1, 0x4c, 0x3f, 0xfc, 0x7d, 0x9b, 0xdf, + 0x78, 0x32, 0xb6, 0xc9, 0x33, 0x3d, 0x59, 0x54, 0x7a, 0x6d, 0x4c, 0xf4, + 0xf7, 0xad, 0xbd, 0x32, 0xe3, 0x52, 0x9e, 0xc7, 0x64, 0xb3, 0x3e, 0xd7, + 0x76, 0x57, 0xb6, 0xdb, 0xc8, 0xd9, 0x2b, 0x5d, 0x12, 0x2b, 0x59, 0x17, + 0x2a, 0xe1, 0x3e, 0x1e, 0x93, 0x99, 0x7a, 0xfb, 0x7d, 0x68, 0xde, 0xb3, + 0xa1, 0xdc, 0x0e, 0xb7, 0xed, 0x3d, 0xde, 0x4d, 0x03, 0x96, 0x8a, 0xd3, + 0x1f, 0x65, 0xbd, 0xfd, 0xc6, 0xc6, 0x7e, 0xd4, 0x95, 0x98, 0x6b, 0x89, + 0x47, 0xda, 0xfa, 0x4d, 0x5c, 0x3e, 0x2d, 0xf7, 0xc5, 0x4b, 0xf0, 0xc7, + 0xc6, 0xcc, 0xb8, 0xef, 0xc1, 0x3b, 0xeb, 0x1e, 0x30, 0xe5, 0xb7, 0x98, + 0xf7, 0x98, 0x79, 0x8f, 0xe0, 0x9d, 0x77, 0xac, 0xd9, 0x27, 0xd3, 0xe7, + 0x55, 0xdc, 0x65, 0x20, 0x9b, 0x95, 0xae, 0x73, 0x02, 0xdb, 0x14, 0x93, + 0xc7, 0xea, 0x8a, 0xbf, 0x96, 0xb7, 0x4a, 0x10, 0x70, 0x83, 0x79, 0xbe, + 0x7e, 0x0f, 0x3e, 0x75, 0xcd, 0x37, 0x47, 0x7f, 0xe8, 0x6a, 0x59, 0x69, + 0xa7, 0xf7, 0x6e, 0xd0, 0xfa, 0x76, 0xf7, 0x8f, 0x68, 0x97, 0xb4, 0x9f, + 0x38, 0x53, 0xa1, 0x0e, 0xcc, 0xca, 0xb1, 0x0a, 0x68, 0xad, 0x0d, 0xbb, + 0xfa, 0x9e, 0x08, 0xf9, 0xa5, 0xef, 0x0d, 0xe6, 0x6b, 0x63, 0xe6, 0x7c, + 0x97, 0x6d, 0x79, 0x8f, 0x91, 0x7c, 0x8b, 0x76, 0xc4, 0x11, 0x68, 0x7f, + 0x68, 0x5b, 0xf8, 0x2d, 0x8e, 0x8f, 0xba, 0xcb, 0xd4, 0x35, 0xb0, 0x4d, + 0x21, 0x7e, 0xf8, 0x82, 0x89, 0x47, 0x85, 0x76, 0x9e, 0xdf, 0x47, 0x8b, + 0xfc, 0x67, 0x60, 0x57, 0xfb, 0x74, 0xaf, 0x44, 0x4e, 0x87, 0x77, 0x90, + 0xb8, 0xc6, 0xa3, 0xea, 0x8e, 0xd9, 0x6e, 0xf3, 0xc3, 0x28, 0x0b, 0xcf, + 0x8a, 0xbb, 0xcc, 0x59, 0x71, 0x28, 0xe7, 0x70, 0x34, 0x62, 0x51, 0xc8, + 0x38, 0xdb, 0xe7, 0x14, 0x5f, 0x73, 0x71, 0xe2, 0xac, 0x83, 0x26, 0x6e, + 0xc0, 0xb2, 0x92, 0x0c, 0xdc, 0xf9, 0x61, 0xee, 0x8d, 0x77, 0x47, 0x24, + 0xfc, 0x8e, 0x40, 0x8d, 0x13, 0xd7, 0xb8, 0x91, 0xdf, 0x57, 0xfb, 0xd8, + 0x57, 0xfb, 0x76, 0xc2, 0xef, 0x08, 0xce, 0x37, 0x33, 0xea, 0x7b, 0x05, + 0x9e, 0x25, 0xec, 0xf2, 0x1e, 0xd6, 0x2a, 0xbf, 0xa5, 0xa6, 0x6c, 0x9b, + 0xef, 0xa8, 0xfb, 0x87, 0xe5, 0xe5, 0xa6, 0xfe, 0xf6, 0x42, 0xdf, 0xed, + 0x25, 0x3e, 0x4b, 0xa2, 0x9c, 0x77, 0xc7, 0xf8, 0xad, 0x03, 0xff, 0x9f, + 0xc2, 0x23, 0x48, 0x3f, 0x25, 0x1b, 0x15, 0x1d, 0xcf, 0x2c, 0xc3, 0x7f, + 0x18, 0x59, 0x75, 0xd5, 0x99, 0xcb, 0xc8, 0xea, 0x0c, 0xc6, 0x0b, 0xbf, + 0x7d, 0x8e, 0x23, 0x8f, 0xf4, 0x95, 0xcc, 0x1e, 0x0d, 0xef, 0x4b, 0xfc, + 0x57, 0x97, 0x36, 0xa1, 0xd4, 0xec, 0x43, 0x5d, 0xcb, 0x60, 0x10, 0xe2, + 0xbb, 0xf0, 0x1b, 0xaf, 0x18, 0x6d, 0x54, 0x40, 0x9d, 0x94, 0xc6, 0x38, + 0x8d, 0x0a, 0xef, 0x5d, 0xa8, 0xff, 0xc3, 0xe0, 0x16, 0xe9, 0xa3, 0x29, + 0x1d, 0x9f, 0x1a, 0x9f, 0x97, 0x82, 0xdb, 0x25, 0x09, 0xf5, 0x7f, 0x1d, + 0x6c, 0xcc, 0x3d, 0xbf, 0xd6, 0xb7, 0x13, 0xc9, 0x72, 0x6e, 0x1c, 0x9b, + 0xbe, 0x87, 0x9e, 0x0f, 0xbf, 0x19, 0x71, 0xb2, 0xbc, 0xdb, 0xcd, 0xef, + 0x9e, 0x98, 0x5f, 0x02, 0xce, 0x0a, 0xbf, 0x73, 0xd1, 0xdf, 0x31, 0xcc, + 0x37, 0x8f, 0xc8, 0x89, 0xca, 0x7e, 0x7e, 0x6f, 0xe1, 0xef, 0x82, 0x6f, + 0xc7, 0x9a, 0x7d, 0xea, 0x5b, 0x8a, 0xf9, 0x26, 0xef, 0x8f, 0x85, 0xb6, + 0x87, 0x6b, 0x15, 0x57, 0x67, 0x18, 0x2f, 0xa8, 0x6f, 0x2d, 0xf4, 0x77, + 0x16, 0x8f, 0xa9, 0xef, 0x16, 0xf4, 0x7e, 0xbf, 0x1e, 0x7b, 0x53, 0x06, + 0x3f, 0x07, 0x7f, 0x50, 0xeb, 0xdd, 0xfb, 0x32, 0xbc, 0x23, 0x19, 0x04, + 0xc7, 0x7c, 0xc6, 0x45, 0x73, 0xd3, 0x1b, 0x98, 0xe3, 0x85, 0x3a, 0x78, + 0x78, 0x94, 0x79, 0xbc, 0x43, 0xd5, 0x23, 0xf9, 0x49, 0xf5, 0x1d, 0xba, + 0xb5, 0xe1, 0xed, 0x97, 0xf3, 0x35, 0xee, 0x05, 0x07, 0xf3, 0x4e, 0xb9, + 0x0d, 0xb9, 0x61, 0x80, 0x67, 0x60, 0x87, 0x55, 0xfb, 0x70, 0xbf, 0xeb, + 0x58, 0xc1, 0xe1, 0x4d, 0xad, 0x4f, 0x78, 0xbf, 0xae, 0xeb, 0xac, 0x58, + 0x1f, 0xcf, 0x0c, 0xc3, 0xdf, 0xe6, 0x58, 0x69, 0xb4, 0x83, 0xec, 0x24, + 0xb8, 0xd7, 0x7f, 0x15, 0x34, 0x40, 0xef, 0x95, 0x26, 0x31, 0x3a, 0x70, + 0xd3, 0x1c, 0xdb, 0x64, 0xc5, 0x5e, 0x61, 0x9d, 0x41, 0xc8, 0x5f, 0x17, + 0xe6, 0xe3, 0x00, 0xff, 0x1f, 0x90, 0x86, 0xcb, 0x32, 0x3e, 0x27, 0x4c, + 0x6c, 0x42, 0x7d, 0x23, 0x0c, 0xfe, 0x25, 0x95, 0x4e, 0xca, 0xb9, 0x7a, + 0x7c, 0xde, 0xe1, 0x5c, 0xa8, 0xcd, 0x62, 0x0f, 0x39, 0x06, 0x8f, 0x39, + 0xe8, 0xe3, 0xd7, 0xe6, 0xbb, 0x8c, 0x92, 0x14, 0x32, 0x1a, 0x7f, 0x68, + 0x1b, 0xc3, 0xf3, 0x12, 0x07, 0xf8, 0x3f, 0xdc, 0x97, 0x8f, 0x1d, 0xb8, + 0xf6, 0xfb, 0x0d, 0x62, 0x97, 0x74, 0xe2, 0x0c, 0xcf, 0xb9, 0xb6, 0x1f, + 0x94, 0x79, 0xd0, 0x7c, 0xca, 0xcc, 0xf3, 0xfe, 0x8c, 0x27, 0x97, 0xeb, + 0x68, 0x93, 0x39, 0x88, 0x94, 0x77, 0xfd, 0x48, 0xf3, 0x84, 0xb9, 0xc7, + 0x98, 0xc5, 0x5c, 0x1f, 0x95, 0xd7, 0x80, 0xa9, 0x5f, 0xaf, 0xa4, 0xfd, + 0xc3, 0xea, 0x8e, 0x4e, 0x2a, 0x71, 0x5e, 0x26, 0x92, 0xf4, 0xfb, 0x4a, + 0x6e, 0x2a, 0x71, 0x59, 0x78, 0xd7, 0xe8, 0xb1, 0x01, 0xfe, 0x4f, 0x87, + 0x06, 0xec, 0xa1, 0xbe, 0x73, 0x94, 0x62, 0x9c, 0x04, 0xef, 0xc3, 0xe6, + 0xbb, 0x22, 0x8e, 0xc3, 0xb2, 0x61, 0x79, 0xad, 0xd2, 0xb2, 0xbf, 0x1c, + 0xc7, 0x7c, 0x4b, 0xce, 0xb1, 0xfe, 0xed, 0x00, 0xf5, 0x10, 0xc7, 0xd3, + 0x7d, 0x84, 0x75, 0xc8, 0x57, 0xbd, 0xc6, 0xf9, 0x8c, 0xfa, 0xae, 0x35, + 0x29, 0x96, 0x25, 0xdd, 0x1e, 0xe7, 0x7e, 0xd3, 0x80, 0xc6, 0x40, 0x6c, + 0x97, 0x76, 0xef, 0x53, 0xfd, 0xf1, 0xac, 0x8c, 0xe7, 0x49, 0x61, 0x3f, + 0xbc, 0x33, 0x84, 0x75, 0x8f, 0x73, 0xbd, 0xdb, 0x69, 0xd0, 0xf6, 0xff, + 0x35, 0x15, 0xa3, 0x9e, 0x46, 0x7d, 0xda, 0x68, 0xc8, 0x4b, 0x3d, 0xd1, + 0xfa, 0x36, 0x42, 0xf3, 0x92, 0xcf, 0x8f, 0xb5, 0xbe, 0x4f, 0xb0, 0x6f, + 0x77, 0x4d, 0x79, 0x88, 0x45, 0x87, 0xb1, 0x5f, 0x1f, 0x95, 0xc6, 0x5a, + 0x3a, 0xf1, 0x98, 0x84, 0xfd, 0x06, 0x87, 0x78, 0x8e, 0x30, 0x93, 0x99, + 0x70, 0x97, 0x14, 0x3d, 0xa9, 0x04, 0xef, 0xdd, 0x9e, 0xc7, 0x78, 0x8d, + 0x66, 0x67, 0xbc, 0x21, 0x95, 0xdb, 0x91, 0xb4, 0xaf, 0xd7, 0x66, 0x4c, + 0x76, 0xb0, 0x36, 0x5f, 0x32, 0x6b, 0xf3, 0x41, 0xf4, 0xed, 0xad, 0x4c, + 0x4a, 0x7a, 0x25, 0x9d, 0x3c, 0x25, 0x3c, 0x9b, 0x3b, 0xc0, 0xb8, 0x95, + 0x75, 0x7f, 0x26, 0x89, 0xf9, 0xa6, 0x30, 0x5f, 0xa4, 0x4d, 0x3e, 0x4f, + 0xc0, 0x1f, 0xdf, 0xc7, 0xbd, 0x7d, 0x88, 0x3a, 0x93, 0xbc, 0x98, 0x51, + 0x65, 0x8f, 0x9a, 0xbb, 0x94, 0xdf, 0xe3, 0xfa, 0xa8, 0xb8, 0xdf, 0xe5, + 0x26, 0xcf, 0xeb, 0x34, 0x7d, 0x05, 0xd0, 0xb7, 0xa8, 0xe9, 0x4b, 0xce, + 0xb7, 0xf0, 0x6a, 0x2a, 0x71, 0x42, 0x88, 0x97, 0x88, 0x5f, 0x88, 0xe5, + 0x6f, 0x19, 0xd4, 0xdf, 0x7e, 0xc0, 0x77, 0xbd, 0x3d, 0xd7, 0x9a, 0x7b, + 0x37, 0xea, 0x5e, 0x80, 0xee, 0xa7, 0xbc, 0x1c, 0x91, 0x0f, 0x48, 0xee, + 0x91, 0x54, 0x32, 0x67, 0x79, 0x06, 0x03, 0x22, 0xad, 0xf3, 0x99, 0x3a, + 0xd7, 0x33, 0xd8, 0x82, 0x6b, 0x93, 0xc1, 0x58, 0xfa, 0x3b, 0x92, 0x5d, + 0xcc, 0x2d, 0xaf, 0x64, 0xed, 0xf7, 0xb1, 0x87, 0xf4, 0xff, 0xb3, 0x38, + 0x0f, 0x3e, 0x96, 0xc1, 0xc7, 0xc7, 0xaf, 0xc3, 0x60, 0x5d, 0x2d, 0x0c, + 0xb6, 0xab, 0xc6, 0xb3, 0x40, 0x53, 0xc1, 0x25, 0xfe, 0x2a, 0xb7, 0x64, + 0x85, 0x34, 0x4d, 0xf2, 0x7f, 0xd2, 0xc8, 0xcb, 0x19, 0xae, 0x07, 0x30, + 0x18, 0xfa, 0xdb, 0xb8, 0x2a, 0x4b, 0x98, 0xbf, 0x92, 0x5f, 0xc8, 0x6e, + 0xca, 0x75, 0x2c, 0xae, 0x05, 0xfb, 0x13, 0xeb, 0x22, 0x68, 0xd9, 0x55, + 0x72, 0xa0, 0x65, 0x60, 0xb7, 0x1e, 0x7b, 0x07, 0x19, 0xe0, 0x3c, 0x29, + 0x7f, 0xa1, 0xec, 0xb5, 0xbe, 0x39, 0x87, 0x4f, 0x5b, 0x92, 0xdb, 0xee, + 0xc8, 0x4a, 0x7e, 0x85, 0x67, 0x4b, 0x62, 0x4d, 0xdc, 0x41, 0x99, 0x24, + 0x4e, 0x00, 0x86, 0x4c, 0x90, 0xc7, 0x1a, 0x0f, 0xce, 0x3f, 0xb7, 0x1f, + 0xbf, 0x73, 0x03, 0xbc, 0x5b, 0x92, 0xdf, 0xa2, 0xbe, 0x12, 0xeb, 0xd6, + 0x3b, 0xb4, 0x4f, 0x78, 0x25, 0x0e, 0x9e, 0xa3, 0x7c, 0xe4, 0xcb, 0xdd, + 0xd0, 0x57, 0x8e, 0x99, 0x37, 0xdf, 0xc9, 0x57, 0xa4, 0xcf, 0x71, 0x5c, + 0xed, 0x5f, 0xe8, 0x38, 0x20, 0xf7, 0x45, 0x49, 0x16, 0xa1, 0x0f, 0x16, + 0x32, 0x31, 0x39, 0x5c, 0x8b, 0xcb, 0x91, 0xca, 0xb4, 0x7c, 0xb1, 0xd2, + 0xa7, 0x70, 0xc3, 0x9f, 0xfb, 0xe9, 0xc4, 0xb8, 0x15, 0xc8, 0xfd, 0xc0, + 0x3f, 0xf3, 0xc3, 0xdd, 0xf2, 0xfa, 0xa4, 0xa5, 0xf4, 0xde, 0x15, 0x7e, + 0x18, 0xed, 0xf2, 0x0e, 0x27, 0xe7, 0x03, 0xbd, 0x6f, 0xc1, 0x17, 0xb0, + 0x78, 0x6f, 0xaf, 0x4f, 0x1e, 0xf0, 0x91, 0xde, 0xe8, 0xab, 0xef, 0x62, + 0xcd, 0x77, 0x5c, 0x46, 0x8f, 0x9c, 0x33, 0x63, 0x1f, 0x31, 0x69, 0x6a, + 0xb0, 0x8d, 0x16, 0x6b, 0x31, 0x13, 0x51, 0xf3, 0x2b, 0xd7, 0xa9, 0xdf, + 0xd8, 0x06, 0xfa, 0x04, 0x7b, 0xb7, 0x0b, 0x7c, 0xd9, 0x80, 0x7e, 0x29, + 0xd6, 0xc4, 0xda, 0xca, 0x00, 0x51, 0x7b, 0x1a, 0x7f, 0x16, 0x21, 0x5f, + 0x0b, 0x35, 0xea, 0xbf, 0x23, 0x90, 0x05, 0xda, 0x6f, 0x87, 0xdf, 0xdc, + 0x00, 0x43, 0x98, 0x3b, 0x1f, 0x31, 0xc6, 0x40, 0xda, 0x75, 0x58, 0xf8, + 0x3f, 0x67, 0x3e, 0x3e, 0x28, 0xfd, 0x25, 0xac, 0x4b, 0x88, 0xb9, 0xc1, + 0x53, 0x8c, 0x99, 0x57, 0xeb, 0x14, 0xae, 0x09, 0x75, 0x4f, 0x88, 0x37, + 0xda, 0xfd, 0x23, 0xee, 0x59, 0xda, 0x0b, 0x29, 0x45, 0x81, 0x69, 0x7b, + 0x57, 0x60, 0xbb, 0x6b, 0x59, 0xc8, 0x0a, 0xef, 0xe1, 0x4f, 0x4b, 0x19, + 0xd8, 0xed, 0xe3, 0xfe, 0xe7, 0xc4, 0x7e, 0xf6, 0xa0, 0x6c, 0xd4, 0x7a, + 0xc1, 0x0f, 0xda, 0x85, 0x2e, 0xe5, 0x53, 0x5f, 0x39, 0x4a, 0x7b, 0x47, + 0x5b, 0xa2, 0xd7, 0x62, 0xb7, 0x0e, 0x27, 0x38, 0xa6, 0xf3, 0x76, 0xea, + 0xa1, 0x2d, 0xe4, 0xf7, 0x34, 0x5d, 0xc6, 0x2e, 0xc7, 0xa0, 0xbb, 0xd7, + 0xa5, 0xa1, 0xfc, 0x73, 0xce, 0x9f, 0x36, 0xa8, 0x8b, 0xf7, 0xc7, 0xac, + 0x86, 0xc7, 0xb9, 0xb7, 0xdb, 0x20, 0x8d, 0x3b, 0xdc, 0x3b, 0x39, 0x1e, + 0xef, 0x26, 0x70, 0x8e, 0x71, 0xe9, 0x3a, 0xf3, 0xa8, 0xd8, 0xf0, 0x5b, + 0x22, 0xab, 0xc4, 0x7a, 0xd7, 0xfa, 0x2e, 0x91, 0x73, 0x51, 0xf3, 0xfd, + 0xf0, 0xa8, 0xc6, 0x32, 0x19, 0xa4, 0x8d, 0xf0, 0x9b, 0x62, 0xfe, 0xda, + 0xed, 0x66, 0xe8, 0x5b, 0xec, 0x69, 0x4b, 0xf1, 0xf7, 0x7f, 0x00, 0xb6, + 0x9d, 0x3c, 0x32, 0x44, 0x4b, 0x00, 0x00, 0x00 }; static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = { - 0x08001b7c, 0x08001bb8, 0x08001bb8, 0x08001bb8, 0x08001bb8, 0x08001bb8, - 0x08001ac8, 0x08001bb8, 0x08001b3c, 0x08001bb8, 0x08001a50, 0x08001bb8, - 0x08001bb8, 0x08001bb8, 0x08001a5c, 0x00000000, 0x08002b74, 0x08002bc4, - 0x08002bf4, 0x08002c24, 0x08002c58, 0x00000000, 0x08006120, 0x08006120, - 0x08006120, 0x08006120, 0x08006120, 0x0800614c, 0x0800614c, 0x0800618c, - 0x08006198, 0x08006198, 0x08006120, 0x00000000, 0x00000000 }; +static const u32 bnx2_COM_b09FwRodata[(0x30/4) + 1] = { + 0x80080100, 0x80080080, 0x80080000, 0x80080240, 0x08000e94, 0x08000eec, + 0x08000f30, 0x08000fc4, 0x08001008, 0x80080100, 0x80080080, 0x80080000, + 0x00000000 }; static struct fw_info bnx2_com_fw_09 = { - /* Firmware version: 3.7.1 */ - .ver_major = 0x3, - .ver_minor = 0x7, - .ver_fix = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x080000b4, + .start_addr = 0x080000f8, .text_addr = 0x08000000, - .text_len = 0x7e94, + .text_len = 0x4b40, .text_index = 0x0, .gz_text = bnx2_COM_b09FwText, .gz_text_len = sizeof(bnx2_COM_b09FwText), - .data_addr = 0x08007f40, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_COM_b09FwData, - .sbss_addr = 0x08007f40, - .sbss_len = 0x60, + .sbss_addr = 0x08004ba0, + .sbss_len = 0x38, .sbss_index = 0x0, - .bss_addr = 0x08007fa0, - .bss_len = 0x88, + .bss_addr = 0x08004bd8, + .bss_len = 0xbc, .bss_index = 0x0, - .rodata_addr = 0x08007e98, - .rodata_len = 0x88, + .rodata_addr = 0x08004b40, + .rodata_len = 0x30, .rodata_index = 0x0, .rodata = bnx2_COM_b09FwRodata, }; static u8 bnx2_CP_b09FwText[] = { - 0xbd, 0x7d, 0x0d, 0x74, 0x5c, 0xd7, 0x5d, 0xe7, 0xff, 0xdd, 0x79, 0x92, - 0xc6, 0xb2, 0x6c, 0x3f, 0xcb, 0x13, 0x79, 0x62, 0xab, 0xf6, 0x8c, 0xf4, - 0x64, 0xab, 0x91, 0x08, 0x2f, 0xae, 0x28, 0x82, 0x9d, 0x84, 0xe9, 0x48, - 0xb2, 0x9d, 0x34, 0xed, 0xca, 0x8d, 0x5b, 0xb2, 0x9c, 0x02, 0x62, 0x24, - 0x27, 0xe9, 0x77, 0xd2, 0x04, 0xb6, 0xec, 0xc9, 0x6e, 0x26, 0x23, 0xf9, - 0x83, 0x74, 0xec, 0x51, 0x12, 0x25, 0xce, 0xa1, 0x3d, 0xbb, 0xaa, 0xa4, - 0xd8, 0x06, 0x06, 0x8f, 0x93, 0xb8, 0xa5, 0xec, 0xa6, 0x54, 0x28, 0xae, - 0x09, 0xa1, 0x07, 0x52, 0x48, 0xd9, 0x40, 0x53, 0x2a, 0xdc, 0xb4, 0xcd, - 0x9e, 0x53, 0xb6, 0x01, 0xca, 0x12, 0x68, 0xe8, 0xdb, 0xdf, 0xef, 0xde, - 0xfb, 0x34, 0xa3, 0x0f, 0xe7, 0xa3, 0xec, 0xe2, 0x73, 0x9e, 0xdf, 0xbc, - 0xfb, 0xee, 0xc7, 0xff, 0xfe, 0xef, 0xff, 0xfb, 0xfe, 0xef, 0xd3, 0x76, - 0x91, 0x66, 0xb1, 0xff, 0x36, 0xe0, 0x7a, 0x5b, 0xea, 0xf6, 0xd1, 0x6b, - 0xae, 0xfe, 0xc9, 0xab, 0xf9, 0xec, 0x3a, 0x4d, 0x31, 0x79, 0x13, 0xff, - 0x52, 0x6f, 0xa0, 0x0e, 0x3a, 0xf4, 0xa2, 0xb1, 0x78, 0x49, 0x5c, 0x65, - 0xdc, 0x3b, 0x72, 0xbe, 0xc4, 0x63, 0x99, 0x91, 0x5f, 0x1e, 0xf5, 0x45, - 0xb2, 0x95, 0x9e, 0xd4, 0x80, 0xfc, 0x4b, 0x58, 0x48, 0xb8, 0xc2, 0xf2, - 0xb7, 0x64, 0x5e, 0xfd, 0x6f, 0x5f, 0xf8, 0xc9, 0xf4, 0xcb, 0xd3, 0x31, - 0x89, 0x7b, 0x99, 0x0f, 0x8b, 0xb7, 0x4b, 0xe2, 0xed, 0x19, 0xb9, 0xe3, - 0xd3, 0xbb, 0xff, 0x46, 0x64, 0x63, 0xd4, 0xd7, 0x4b, 0xe1, 0x17, 0x76, - 0x4b, 0x61, 0x5b, 0x26, 0x39, 0xd2, 0x90, 0x49, 0xc8, 0x17, 0xab, 0x9e, - 0x9c, 0xab, 0xca, 0xf0, 0xa9, 0xd2, 0xcb, 0xa1, 0x9b, 0x09, 0x63, 0x13, - 0x7d, 0x8e, 0xc4, 0x32, 0x72, 0x61, 0xb4, 0xef, 0x9e, 0x50, 0xf9, 0x32, - 0xe2, 0x65, 0xfc, 0x60, 0x41, 0x5a, 0xfa, 0x2f, 0xf6, 0xa1, 0x4e, 0xe5, - 0xe0, 0xb5, 0x8d, 0x27, 0xe2, 0xa2, 0x32, 0x5d, 0xcf, 0xe7, 0x62, 0xd7, - 0x88, 0xf2, 0xfd, 0xe0, 0x82, 0x74, 0x05, 0x4f, 0x09, 0xca, 0xcf, 0xc6, - 0x25, 0x57, 0x95, 0x16, 0x94, 0xe1, 0xde, 0x8c, 0x3a, 0x69, 0x2f, 0x17, - 0x4b, 0x48, 0xb1, 0xfa, 0x63, 0xcd, 0x66, 0xec, 0xaf, 0xaf, 0x33, 0xf7, - 0xdd, 0xf6, 0xbe, 0xee, 0x67, 0xdd, 0x4c, 0x3c, 0xae, 0x4e, 0xc8, 0xcb, - 0x13, 0x7d, 0x2f, 0x87, 0x31, 0xdf, 0xf7, 0x06, 0xa4, 0x41, 0x06, 0x13, - 0x80, 0xa9, 0xec, 0xa0, 0xef, 0x14, 0xda, 0xfe, 0x12, 0x70, 0x0e, 0xf8, - 0xca, 0x29, 0x29, 0x10, 0xce, 0x72, 0x5c, 0x16, 0x63, 0x49, 0x01, 0xfc, - 0xc0, 0x45, 0xbb, 0x8c, 0xa3, 0x3c, 0x57, 0xe2, 0x7c, 0x5c, 0xc9, 0x7b, - 0x1e, 0xe6, 0xd2, 0x8e, 0x36, 0x3b, 0x1d, 0xd3, 0x3f, 0x9e, 0x97, 0xd5, - 0x67, 0xdd, 0xe7, 0x51, 0x37, 0xa5, 0xeb, 0x3d, 0x51, 0x4d, 0xca, 0xe3, - 0xd5, 0x84, 0x3c, 0x56, 0xfd, 0x98, 0x64, 0x3d, 0xe2, 0x00, 0xb0, 0x96, - 0x1b, 0x65, 0x60, 0xaa, 0x59, 0x72, 0x53, 0x9d, 0xc9, 0xbc, 0x84, 0xe1, - 0x9d, 0xc1, 0x07, 0x64, 0xa4, 0x15, 0xf5, 0xcb, 0x7c, 0x97, 0x5c, 0xf6, - 0x2e, 0x1f, 0xf4, 0x78, 0x79, 0xe5, 0x48, 0xf6, 0x60, 0x3a, 0x39, 0xa2, - 0xf8, 0xdc, 0x20, 0xb9, 0x5e, 0x3c, 0x0f, 0xbb, 0x12, 0xf3, 0xc3, 0xf0, - 0x8e, 0x60, 0x17, 0xe0, 0x48, 0xa7, 0x52, 0x8a, 0x6d, 0xd9, 0x2e, 0x5d, - 0x48, 0xa9, 0x24, 0xe6, 0x71, 0xb5, 0xa4, 0x5a, 0xc3, 0xf0, 0x3d, 0x81, - 0x8f, 0x72, 0x91, 0x81, 0x92, 0xdc, 0xae, 0x32, 0x3e, 0xfa, 0x94, 0x40, - 0x65, 0xb6, 0x60, 0x1e, 0x3d, 0xc0, 0x43, 0xa3, 0x64, 0x13, 0x92, 0x55, - 0x19, 0x49, 0xa9, 0xcc, 0x3a, 0x94, 0x39, 0xd2, 0xe0, 0xff, 0x77, 0x4b, - 0x7f, 0x9b, 0xf0, 0x2c, 0xc3, 0x2a, 0xd3, 0xba, 0xa2, 0x3c, 0x9d, 0x12, - 0xf5, 0xe3, 0x71, 0x8c, 0xd9, 0x9d, 0x55, 0x2c, 0xc3, 0x5d, 0x97, 0x15, - 0x9a, 0x56, 0x97, 0x4d, 0x3a, 0xcb, 0xcb, 0x4e, 0xb5, 0x10, 0x56, 0x51, - 0xfc, 0x9d, 0xd4, 0x73, 0xcd, 0x26, 0x3a, 0xbd, 0x06, 0xcc, 0x6b, 0x38, - 0x48, 0x7b, 0x43, 0xea, 0xb9, 0x50, 0xda, 0x08, 0x33, 0xdf, 0x29, 0xbc, - 0x43, 0xd5, 0x4c, 0x80, 0x75, 0x4e, 0xc8, 0x51, 0xcc, 0xed, 0xd2, 0x54, - 0xda, 0xeb, 0x50, 0xb8, 0xcf, 0xf1, 0x77, 0x18, 0xe6, 0x82, 0x82, 0xa6, - 0x81, 0x6f, 0x4e, 0x25, 0xf1, 0x0c, 0xf8, 0x13, 0xd9, 0xf4, 0x66, 0xb9, - 0xc9, 0xae, 0xcb, 0x37, 0x31, 0x66, 0xa7, 0x77, 0x87, 0xea, 0xf4, 0x02, - 0x95, 0xf6, 0x66, 0xe4, 0xf7, 0xf1, 0x1c, 0x86, 0x07, 0x82, 0x74, 0xb2, - 0x80, 0x35, 0x7b, 0xb1, 0x94, 0x90, 0x6f, 0x95, 0xd2, 0xa0, 0xfc, 0x74, - 0xf7, 0xac, 0xf4, 0x04, 0xb3, 0x80, 0xb7, 0x88, 0xeb, 0x08, 0xdf, 0x55, - 0xf0, 0xae, 0xc2, 0xb6, 0x61, 0x78, 0x53, 0xf0, 0xeb, 0xe1, 0x48, 0x9b, - 0xe1, 0xa5, 0x2f, 0x96, 0xb1, 0x9e, 0x80, 0xf9, 0x71, 0xac, 0xd3, 0x63, - 0xe5, 0x88, 0x4e, 0xba, 0xb1, 0xee, 0xa4, 0x0d, 0xd2, 0xc5, 0x1e, 0x4b, - 0xff, 0xa3, 0xf6, 0x2e, 0x92, 0x03, 0x8d, 0xe5, 0x82, 0x1f, 0x84, 0x59, - 0xcd, 0x63, 0xe2, 0x0c, 0x94, 0x49, 0xbb, 0x0d, 0x80, 0x95, 0x8f, 0x1f, - 0xb3, 0xf5, 0xda, 0x1d, 0xe0, 0x96, 0xeb, 0xc0, 0xf7, 0x71, 0xe5, 0x37, - 0xd9, 0xf7, 0x11, 0x2f, 0xf1, 0x1f, 0xe8, 0xcd, 0xaf, 0xd5, 0xcb, 0x91, - 0x26, 0xab, 0x05, 0xc9, 0x3f, 0x18, 0xca, 0x40, 0x00, 0x3c, 0xb1, 0x4f, - 0x2f, 0x10, 0xdd, 0xd6, 0x63, 0x1d, 0x5d, 0x17, 0xff, 0xae, 0x69, 0xc4, - 0x18, 0xce, 0x60, 0xb9, 0xd6, 0x76, 0xb0, 0xfc, 0xe4, 0x16, 0x0b, 0x1f, - 0x9e, 0xfb, 0x9d, 0x5c, 0xf5, 0x6f, 0xed, 0xda, 0x46, 0xf3, 0xb8, 0x69, - 0x0d, 0xda, 0x0e, 0xc3, 0x89, 0x40, 0x46, 0x54, 0x66, 0x31, 0x9e, 0x2b, - 0x89, 0xd3, 0x90, 0xf1, 0xbd, 0x21, 0x59, 0x27, 0x76, 0x5e, 0xb6, 0xdc, - 0x03, 0xaf, 0x74, 0xa1, 0xdc, 0x11, 0xc8, 0x8d, 0x11, 0x07, 0x65, 0x1d, - 0x15, 0x94, 0x61, 0xfd, 0xc6, 0x81, 0xaf, 0x7c, 0xa9, 0x5f, 0xaf, 0x65, - 0xbe, 0x34, 0x0c, 0xde, 0xcf, 0xe0, 0x77, 0x76, 0xb3, 0x2b, 0x5d, 0xa0, - 0x43, 0xae, 0xb1, 0xb8, 0xb9, 0xdd, 0xa0, 0xd5, 0xea, 0xeb, 0x4b, 0x2c, - 0x3d, 0xf7, 0xe0, 0x5f, 0x88, 0xd3, 0x25, 0x78, 0x62, 0x19, 0xf2, 0xf5, - 0xf3, 0x21, 0xe8, 0x19, 0x65, 0x84, 0x99, 0x35, 0x13, 0x32, 0x51, 0xde, - 0x26, 0xc5, 0x29, 0x5f, 0xc6, 0x4b, 0xf3, 0xdd, 0x4a, 0x5e, 0x86, 0xac, - 0xf1, 0x41, 0x0b, 0x69, 0xf0, 0x41, 0x46, 0x06, 0xaa, 0x18, 0xaf, 0x84, - 0x7b, 0xb9, 0x13, 0x6d, 0x5d, 0xc9, 0x26, 0xcd, 0x3a, 0x17, 0x4b, 0x63, - 0xc0, 0x15, 0xd6, 0x8d, 0xb2, 0x41, 0xc3, 0x3c, 0x0c, 0x3a, 0xf4, 0x24, - 0xd7, 0xa7, 0xe1, 0x7c, 0x13, 0xf0, 0xc5, 0x65, 0x26, 0x68, 0xb4, 0x38, - 0x22, 0x7f, 0xc6, 0xdd, 0x01, 0xe0, 0x61, 0xa0, 0x72, 0x0f, 0xfa, 0x6f, - 0xc1, 0x6f, 0x96, 0x89, 0x2d, 0x73, 0xf5, 0xf3, 0x40, 0x85, 0x30, 0x47, - 0x74, 0x0f, 0x3e, 0x98, 0x82, 0xfc, 0x01, 0xdd, 0x0f, 0x90, 0x5f, 0xe6, - 0x38, 0x17, 0xc2, 0xb5, 0x4d, 0xff, 0x1e, 0x9f, 0xda, 0xa1, 0x9f, 0xf3, - 0xc3, 0xdb, 0xa4, 0x30, 0x17, 0xcd, 0x99, 0xb2, 0x87, 0xf2, 0x26, 0x7d, - 0x0c, 0x74, 0x05, 0xf9, 0x13, 0x86, 0x0f, 0x06, 0x94, 0x41, 0x61, 0xf8, - 0x78, 0x40, 0x99, 0x74, 0x1e, 0xb2, 0x86, 0x72, 0x88, 0x72, 0x61, 0x50, - 0x71, 0xdd, 0x73, 0xa5, 0x00, 0xeb, 0xd3, 0x28, 0xf9, 0xde, 0x47, 0x08, - 0x2b, 0x64, 0xd8, 0xb3, 0x1f, 0xcb, 0xf9, 0x85, 0x64, 0x4c, 0xe3, 0x49, - 0xb0, 0x5e, 0x71, 0xc9, 0xea, 0x99, 0x75, 0x48, 0xb1, 0x77, 0xd2, 0xd6, - 0x79, 0x49, 0xd7, 0x71, 0x57, 0xd5, 0xf9, 0x75, 0x65, 0x78, 0x3c, 0xc0, - 0x5a, 0xfe, 0xb4, 0x22, 0x1e, 0x3b, 0x76, 0xf1, 0x59, 0xe2, 0x0d, 0x99, - 0xaf, 0xe1, 0xdd, 0xb9, 0x3b, 0x1f, 0xf5, 0xd7, 0x7a, 0xb7, 0xb5, 0x61, - 0xf5, 0xbb, 0x09, 0x71, 0xfd, 0x74, 0xf7, 0x01, 0xf5, 0x4f, 0x78, 0x17, - 0x86, 0x8f, 0x06, 0x51, 0x79, 0x6f, 0xc3, 0xea, 0x31, 0x7e, 0x76, 0x8d, - 0xb2, 0xf3, 0x6b, 0x94, 0xfd, 0xc9, 0x1a, 0x65, 0xef, 0x6d, 0x5c, 0x5d, - 0xf6, 0xc0, 0x1a, 0x65, 0x4f, 0xaf, 0x51, 0xe6, 0x37, 0xad, 0x2e, 0xdb, - 0xb5, 0x46, 0xd9, 0x5b, 0xd7, 0x28, 0x3b, 0xb0, 0x46, 0x99, 0x0b, 0x1e, - 0xde, 0x25, 0xc5, 0xc4, 0xbd, 0x9c, 0xbb, 0xc5, 0xcd, 0xe7, 0x62, 0xab, - 0x71, 0xd3, 0x80, 0x7a, 0xed, 0x2b, 0xea, 0x7d, 0x6d, 0x8d, 0x7a, 0x8d, - 0xa8, 0xd7, 0xba, 0xa2, 0xde, 0xcd, 0xee, 0xea, 0x7a, 0x4d, 0xa8, 0x17, - 0x5f, 0x51, 0xef, 0x77, 0xd7, 0xa8, 0xc7, 0xf2, 0x4f, 0xd9, 0x71, 0x7a, - 0xa0, 0xd1, 0x5e, 0x6b, 0xbd, 0x1a, 0x45, 0xda, 0x58, 0x1e, 0x40, 0x1f, - 0xfd, 0xb4, 0x32, 0x32, 0x86, 0xf2, 0x4c, 0xe3, 0x0d, 0x74, 0x9e, 0x04, - 0xdd, 0x51, 0x26, 0x83, 0xcf, 0x7c, 0xf2, 0xfe, 0x06, 0x19, 0x49, 0xf4, - 0x78, 0x6f, 0x53, 0x2d, 0xa0, 0xb1, 0xb4, 0x97, 0x52, 0xe4, 0x3f, 0x29, - 0x80, 0xb7, 0x0b, 0x03, 0xa2, 0x12, 0x4a, 0x42, 0x19, 0x0c, 0x54, 0xab, - 0x92, 0x7b, 0xc0, 0x5f, 0x59, 0xe8, 0xbf, 0x03, 0xe1, 0x80, 0xe6, 0x2d, - 0x53, 0xf7, 0xf2, 0xf2, 0xb9, 0x5f, 0x8e, 0x50, 0xae, 0x66, 0x82, 0x3b, - 0x73, 0xfe, 0x7c, 0x7f, 0x23, 0x68, 0xf6, 0x12, 0xda, 0xec, 0x43, 0xcb, - 0x43, 0x15, 0x57, 0x06, 0x2b, 0x19, 0xf0, 0x82, 0x23, 0x17, 0xfd, 0x4d, - 0x72, 0x31, 0x40, 0xdd, 0x6a, 0x4c, 0x16, 0x12, 0x8e, 0x2c, 0xe0, 0x39, - 0x17, 0xe0, 0x5d, 0x35, 0xe2, 0xad, 0x8c, 0x1c, 0x2e, 0xf7, 0xcb, 0xb1, - 0xf2, 0x87, 0x55, 0xa4, 0x23, 0x87, 0x82, 0xf5, 0x72, 0xc6, 0x33, 0x7d, - 0xef, 0xf3, 0xe7, 0xa1, 0x9d, 0x5d, 0xb9, 0xe4, 0xa7, 0x93, 0x0b, 0x9a, - 0x27, 0xfe, 0x31, 0x1c, 0x44, 0x3f, 0x33, 0x7e, 0xda, 0xfb, 0x03, 0x0a, - 0xc9, 0x0a, 0x6d, 0xa9, 0x5a, 0x5f, 0xe3, 0xe8, 0xeb, 0x68, 0x79, 0x83, - 0xdc, 0x6a, 0xdb, 0xef, 0xf5, 0xe7, 0xbb, 0xc1, 0x73, 0xde, 0x29, 0xca, - 0x90, 0x12, 0xe0, 0x3a, 0x08, 0xde, 0x46, 0xdb, 0x2f, 0x09, 0xdb, 0xc0, - 0xf6, 0x2a, 0x6d, 0x82, 0xac, 0xff, 0x87, 0xf0, 0xd6, 0x04, 0xeb, 0xb3, - 0x8c, 0xfa, 0x4b, 0x26, 0x55, 0x06, 0x32, 0xa1, 0xaf, 0x0b, 0xfa, 0x2b, - 0x25, 0x83, 0x55, 0xc8, 0x9e, 0xf2, 0x0f, 0xc3, 0xac, 0xcb, 0x31, 0xa2, - 0xb1, 0xa4, 0x50, 0xab, 0xc3, 0x32, 0xd6, 0x23, 0xff, 0x2f, 0x2e, 0xc9, - 0x8a, 0x02, 0xe4, 0x8b, 0xb1, 0xd1, 0xfe, 0x13, 0x78, 0xb4, 0x5d, 0x06, - 0x4b, 0xe9, 0x42, 0x56, 0x76, 0x61, 0xfd, 0x7e, 0x0d, 0x6b, 0xea, 0xe2, - 0xfa, 0x93, 0xf5, 0xb2, 0x31, 0x80, 0x1d, 0xc0, 0x72, 0x74, 0xda, 0x46, - 0xfb, 0xec, 0x19, 0xe0, 0x61, 0x9c, 0x6b, 0x9e, 0xcc, 0xc5, 0x9c, 0x61, - 0xda, 0x3e, 0xc3, 0x90, 0x8f, 0xf9, 0x0a, 0xfb, 0x26, 0xbc, 0x49, 0xfb, - 0x1b, 0x36, 0x5b, 0xa9, 0xdd, 0xfe, 0x6e, 0xc1, 0xef, 0x94, 0xfd, 0x0d, - 0x99, 0x5a, 0xf2, 0xed, 0xef, 0x04, 0x7e, 0x77, 0xdb, 0xdf, 0x49, 0xfc, - 0xee, 0xd5, 0xbf, 0x27, 0xca, 0x7b, 0xf7, 0x2a, 0xff, 0x6a, 0xc9, 0xcf, - 0xb5, 0xcb, 0xe1, 0xd2, 0x7b, 0xad, 0x6c, 0xc1, 0x25, 0x9f, 0x77, 0xcc, - 0x3c, 0x01, 0x77, 0x99, 0x6d, 0x0a, 0xce, 0xb0, 0xb6, 0xdd, 0xda, 0x61, - 0xeb, 0xf4, 0x78, 0x9b, 0x85, 0x34, 0x30, 0xe1, 0x0c, 0x54, 0x9d, 0x6c, - 0x2c, 0xd3, 0x95, 0x1c, 0x97, 0x63, 0xf8, 0x2d, 0x5e, 0x2c, 0xf3, 0x79, - 0xdc, 0x0d, 0x0e, 0xbe, 0x00, 0x7d, 0x33, 0x5e, 0xa6, 0xbc, 0xf4, 0x31, - 0xf7, 0x94, 0x9c, 0x5f, 0x66, 0xaf, 0x11, 0x17, 0x4a, 0xf2, 0x53, 0xe9, - 0x47, 0x0a, 0x92, 0x2e, 0x4c, 0x83, 0x21, 0x0e, 0x04, 0xae, 0xbc, 0x27, - 0x00, 0xed, 0x5e, 0xed, 0xc8, 0xde, 0xab, 0x5d, 0xd8, 0x57, 0xfe, 0xf4, - 0x5e, 0xc8, 0xd8, 0x7c, 0xe9, 0xea, 0x18, 0xe9, 0x41, 0x9d, 0x95, 0x11, - 0x37, 0x03, 0x6c, 0x9f, 0xed, 0x1d, 0x1c, 0x2f, 0xe5, 0x3f, 0xac, 0x32, - 0xb7, 0xff, 0x6a, 0xae, 0x6f, 0x17, 0x74, 0x79, 0x18, 0xc6, 0x32, 0x6d, - 0xd0, 0x4b, 0x5c, 0x57, 0xea, 0xa9, 0x9b, 0x6e, 0x8a, 0x65, 0x1a, 0x64, - 0xe0, 0x60, 0x1b, 0xea, 0xb3, 0x9c, 0xb8, 0x72, 0xd0, 0x47, 0x3a, 0x35, - 0x28, 0x72, 0xf7, 0x44, 0xdf, 0xa2, 0x33, 0x3e, 0xf9, 0x73, 0xe0, 0xc7, - 0x7e, 0xc9, 0x1f, 0x7c, 0x00, 0xf8, 0x7d, 0xd9, 0x29, 0x4e, 0xbd, 0xe2, - 0x8c, 0x4f, 0xfd, 0x9d, 0x33, 0x31, 0xb5, 0x63, 0xc7, 0x50, 0xff, 0x8e, - 0x1d, 0xa3, 0xfd, 0xae, 0xd5, 0x2d, 0x3b, 0x76, 0x4c, 0xf4, 0x67, 0x31, - 0xff, 0x1e, 0x6f, 0x50, 0x7c, 0x6f, 0x2f, 0x95, 0x7c, 0xc2, 0xac, 0xfd, - 0x4c, 0xd0, 0x8d, 0xf7, 0x6c, 0xdf, 0xab, 0xdf, 0x0f, 0x48, 0x4f, 0xb2, - 0x55, 0x38, 0x7e, 0x87, 0xd5, 0x49, 0x6c, 0x07, 0x7a, 0xe9, 0xa5, 0x1d, - 0xa8, 0x50, 0x2f, 0x05, 0x7c, 0xd0, 0x26, 0xde, 0x06, 0x1b, 0x82, 0xed, - 0x94, 0x5d, 0xf7, 0x92, 0x6a, 0xf0, 0x63, 0xba, 0x5f, 0x75, 0x36, 0x13, - 0x33, 0x6b, 0xde, 0x63, 0xed, 0xeb, 0x4d, 0x28, 0xe7, 0x33, 0x71, 0x49, - 0x7c, 0xd1, 0xde, 0x69, 0xd0, 0xf6, 0x69, 0xbe, 0x44, 0x5a, 0x72, 0x65, - 0xac, 0xd4, 0x8f, 0x36, 0xa0, 0x97, 0xb3, 0xf6, 0x3a, 0x81, 0xf1, 0x0e, - 0xa2, 0xaf, 0x13, 0x47, 0xd1, 0x8e, 0xb2, 0x24, 0xdd, 0x2d, 0xea, 0x41, - 0xd4, 0xe9, 0xf1, 0xb6, 0x08, 0xed, 0x9a, 0x47, 0x24, 0x5f, 0x26, 0xdf, - 0xd3, 0x36, 0x88, 0x4b, 0xaa, 0x0d, 0xcf, 0xd5, 0xc3, 0xb0, 0x75, 0x1a, - 0x22, 0x7b, 0x43, 0x6a, 0x76, 0xd1, 0xaf, 0x2a, 0xf1, 0x0f, 0xcb, 0xc8, - 0xec, 0x76, 0xd4, 0x33, 0xf6, 0xbc, 0xf2, 0x61, 0x17, 0xcd, 0x66, 0x25, - 0xb7, 0xeb, 0x5e, 0xdc, 0x3d, 0x3c, 0x17, 0x71, 0x7f, 0x0b, 0xee, 0xe3, - 0xb8, 0x47, 0x70, 0x02, 0xe7, 0x41, 0xcc, 0xea, 0xb2, 0x51, 0x8c, 0xfd, - 0xef, 0x25, 0x37, 0x09, 0x7a, 0x2d, 0x85, 0x9b, 0x72, 0x7e, 0xd6, 0x53, - 0xa2, 0xb6, 0x28, 0x99, 0x40, 0x7d, 0xf8, 0x29, 0xfe, 0x11, 0x19, 0x3d, - 0x8d, 0xdf, 0x0f, 0xd2, 0xee, 0x9e, 0x90, 0xd1, 0x59, 0x8e, 0x53, 0x02, - 0x4c, 0x93, 0x92, 0x3f, 0xfd, 0x00, 0xae, 0x29, 0x5c, 0x0f, 0xe3, 0xe2, - 0xdc, 0xd8, 0xff, 0xc2, 0x66, 0x25, 0x2d, 0xfa, 0x39, 0x4f, 0xfa, 0xae, - 0xe2, 0x37, 0x69, 0xbb, 0x4a, 0x1b, 0x08, 0x74, 0x5d, 0x8d, 0xe8, 0x3d, - 0xb0, 0xbf, 0x93, 0x9a, 0xdf, 0x0b, 0xad, 0xa0, 0xa5, 0x6a, 0x56, 0xcb, - 0x22, 0xc0, 0x00, 0xb9, 0x03, 0x9b, 0xa4, 0x95, 0x73, 0xec, 0xb5, 0x65, - 0xbd, 0xba, 0x2c, 0xa5, 0xcb, 0xfa, 0x6c, 0x19, 0xee, 0xd5, 0x06, 0x19, - 0x69, 0x03, 0xc4, 0x94, 0xdb, 0x12, 0xe1, 0x93, 0xb2, 0x01, 0x74, 0x8d, - 0xf5, 0x3d, 0x7f, 0x59, 0xb9, 0xb8, 0xa8, 0xed, 0xbd, 0x73, 0x55, 0xd2, - 0x37, 0x69, 0x3e, 0x0c, 0xef, 0x0f, 0x9a, 0xd0, 0x3f, 0x65, 0x81, 0x48, - 0xc3, 0x09, 0x57, 0xa6, 0x3d, 0xd2, 0xc0, 0xc7, 0x5a, 0x48, 0x03, 0x8d, - 0x3e, 0x69, 0xbb, 0x9e, 0xef, 0xb8, 0x86, 0xec, 0xaf, 0x00, 0x1b, 0x92, - 0xb6, 0x64, 0x17, 0xec, 0x73, 0x8e, 0x71, 0x8c, 0xcf, 0x9e, 0x02, 0xaf, - 0xe5, 0x96, 0x78, 0x4d, 0x64, 0xa6, 0x44, 0xdc, 0x44, 0x36, 0x26, 0xd7, - 0x99, 0xf8, 0x39, 0x87, 0x39, 0xf3, 0x7e, 0xde, 0xe2, 0xe9, 0xf3, 0x16, - 0x4f, 0x4f, 0xda, 0xbb, 0xe7, 0xe4, 0xb5, 0xcd, 0x38, 0x8f, 0x67, 0xae, - 0x0f, 0xe8, 0xaa, 0x4a, 0x9e, 0x9b, 0xc6, 0x1d, 0x75, 0xcb, 0xe7, 0x64, - 0x54, 0xdb, 0x6f, 0x31, 0x79, 0x87, 0x96, 0x79, 0x5f, 0xc5, 0x5a, 0x96, - 0x00, 0x73, 0x83, 0x14, 0x12, 0x31, 0xbd, 0xf6, 0xae, 0xff, 0x5b, 0xae, - 0xa1, 0x55, 0xe2, 0x64, 0x99, 0xbf, 0x56, 0x07, 0x53, 0xe4, 0xa3, 0x12, - 0x2e, 0xd2, 0xee, 0xa7, 0x35, 0x5c, 0xb7, 0x40, 0x0e, 0x16, 0x44, 0xb5, - 0x35, 0xca, 0x95, 0xa0, 0x05, 0x95, 0x80, 0x46, 0x0b, 0x9f, 0x82, 0x3d, - 0x95, 0x9f, 0xa5, 0x9d, 0xde, 0x41, 0xdf, 0x28, 0x9e, 0xef, 0xdd, 0x48, - 0x3a, 0x52, 0x86, 0x6f, 0x1c, 0x95, 0xef, 0xd5, 0x74, 0xea, 0x28, 0x3f, - 0xa1, 0x6d, 0x71, 0xd7, 0xdf, 0xea, 0x5a, 0x9f, 0xde, 0x55, 0xfe, 0x96, - 0x95, 0x65, 0x29, 0xea, 0x67, 0xb4, 0x4b, 0xe5, 0x7b, 0xdb, 0xc8, 0x63, - 0x1e, 0xfc, 0xe1, 0xac, 0xf2, 0xb5, 0xff, 0x55, 0x50, 0x7d, 0x9b, 0x56, - 0xd4, 0xd7, 0x77, 0xc7, 0x3e, 0xbb, 0xf6, 0xee, 0xd9, 0x7b, 0xca, 0xde, - 0x0b, 0x6e, 0x1f, 0xef, 0x8e, 0xb8, 0x19, 0xde, 0xb1, 0x86, 0x19, 0xf6, - 0xa1, 0xf9, 0x2a, 0x34, 0xb6, 0x72, 0x97, 0x57, 0x14, 0xf2, 0xd5, 0x57, - 0xe5, 0x96, 0x59, 0x23, 0x97, 0xf7, 0x96, 0xc2, 0x10, 0x3e, 0xa2, 0xb7, - 0x00, 0xff, 0x38, 0x7b, 0xb0, 0x22, 0xb7, 0x54, 0x89, 0xb7, 0x4f, 0x02, - 0x7f, 0x43, 0x2e, 0x79, 0xd3, 0x13, 0xca, 0xe3, 0xbb, 0x84, 0xf6, 0x6a, - 0xb1, 0x44, 0x9c, 0x5f, 0x10, 0xae, 0x4d, 0xb1, 0xf4, 0xb4, 0x5e, 0x9b, - 0x23, 0xa5, 0x05, 0xe0, 0xe7, 0xcb, 0xa0, 0xfb, 0x30, 0x5c, 0x08, 0x8a, - 0xa0, 0x9c, 0x3f, 0xc6, 0x6f, 0xd8, 0x28, 0xa5, 0x67, 0xf1, 0x7e, 0xa3, - 0x14, 0x27, 0xc9, 0x73, 0xae, 0xe5, 0xe1, 0xb3, 0xe0, 0xa7, 0x9f, 0x41, - 0xbf, 0x28, 0xeb, 0xe3, 0xef, 0x1f, 0xe0, 0x1d, 0xee, 0xb3, 0x58, 0xc4, - 0x36, 0xda, 0x40, 0x1c, 0x9b, 0x6b, 0xc7, 0x35, 0xa3, 0xaf, 0x5e, 0xef, - 0x97, 0x73, 0xbd, 0xd2, 0xdd, 0x05, 0x59, 0x8a, 0x2b, 0xc8, 0xb9, 0x12, - 0xeb, 0x93, 0xfe, 0xfb, 0xd6, 0x19, 0x1d, 0xb1, 0xa1, 0xd9, 0xdc, 0x57, - 0xb6, 0xe5, 0x9a, 0xd7, 0xd3, 0x20, 0x7d, 0xa8, 0x74, 0x7f, 0x01, 0x72, - 0xc7, 0xf5, 0x37, 0xca, 0xa0, 0x96, 0x9d, 0xa4, 0x09, 0xd2, 0xc0, 0xcd, - 0xca, 0xd0, 0xe6, 0xfb, 0x95, 0xa1, 0xcd, 0xa7, 0x41, 0x8b, 0xb8, 0xca, - 0x8b, 0x8e, 0xa1, 0xcd, 0x2f, 0xe3, 0x8e, 0xab, 0xfc, 0xa2, 0x13, 0xf1, - 0xf1, 0x00, 0xfc, 0xca, 0xbd, 0x25, 0xd7, 0x19, 0xad, 0x82, 0x7e, 0xcb, - 0x71, 0x94, 0xcf, 0x13, 0xe7, 0x98, 0x3f, 0xc7, 0xd9, 0x69, 0xfb, 0x3f, - 0x27, 0x63, 0xe5, 0x50, 0xdb, 0x5b, 0xf9, 0xd9, 0x7b, 0x71, 0x5f, 0xaf, - 0xe5, 0x8c, 0xf2, 0xb3, 0xca, 0xc8, 0xab, 0x77, 0xe0, 0xde, 0x99, 0x3c, - 0x22, 0x9d, 0x5e, 0x4c, 0x9e, 0x45, 0x5f, 0xdf, 0x75, 0xc6, 0xaa, 0x2f, - 0xe3, 0xfa, 0x3e, 0xae, 0x57, 0x71, 0xbd, 0x82, 0x7e, 0x5f, 0x40, 0xf9, - 0x7a, 0x99, 0xf7, 0x9a, 0x51, 0x5f, 0xd4, 0x68, 0xf5, 0x79, 0x67, 0xe4, - 0xf4, 0x4b, 0xb8, 0x5c, 0x35, 0x56, 0x7d, 0xce, 0xc9, 0xcf, 0x86, 0x9b, - 0x16, 0x7c, 0xca, 0xb0, 0xaf, 0x3a, 0xa6, 0xef, 0x0c, 0xe6, 0x00, 0x9a, - 0x2e, 0xcf, 0x63, 0xec, 0xa7, 0x35, 0xcf, 0x0c, 0x42, 0x1f, 0xe4, 0x61, - 0xaf, 0x8c, 0x68, 0x98, 0xb6, 0x03, 0x3e, 0xf8, 0xd3, 0x7d, 0xb8, 0xcf, - 0x36, 0xca, 0x62, 0x82, 0xf6, 0xe5, 0x93, 0xba, 0x7e, 0xbe, 0x7c, 0xbd, - 0xc6, 0xed, 0xf4, 0x2a, 0xfe, 0xa1, 0x4f, 0x18, 0xc9, 0x03, 0x23, 0x8d, - 0x67, 0x4a, 0x94, 0x05, 0xd0, 0x4d, 0xa5, 0x09, 0xdc, 0x1b, 0xb5, 0x4c, - 0x28, 0x4a, 0x24, 0x0f, 0xd8, 0x8e, 0x32, 0xa1, 0x5e, 0xee, 0x50, 0xd6, - 0x50, 0xf6, 0x50, 0x96, 0x98, 0xf5, 0x18, 0x7d, 0x90, 0x32, 0xfc, 0x3a, - 0xe8, 0x4d, 0xda, 0x25, 0xbe, 0xf1, 0x4d, 0xa6, 0x72, 0xca, 0xc8, 0xd3, - 0xfd, 0x7a, 0x2d, 0xc6, 0x4a, 0x2a, 0x01, 0xc8, 0x51, 0x86, 0xeb, 0xe4, - 0x41, 0xdc, 0xf3, 0x6a, 0x0c, 0x57, 0xfe, 0xe4, 0xfb, 0xf0, 0x9b, 0x6b, - 0x33, 0x86, 0x7a, 0xb8, 0xca, 0xc3, 0xb8, 0xe3, 0x2a, 0xdf, 0xa8, 0x8c, - 0x1c, 0xe1, 0x9a, 0x26, 0xed, 0x9a, 0x3e, 0x09, 0x3c, 0x70, 0x7e, 0x4a, - 0xc7, 0x38, 0x94, 0xbf, 0x07, 0x78, 0xaf, 0x5a, 0x9f, 0x7a, 0xa3, 0x18, - 0x1e, 0xc4, 0xd5, 0x4d, 0x7e, 0x6e, 0x31, 0xeb, 0xa5, 0x69, 0x77, 0x5d, - 0x83, 0xe1, 0xc5, 0x04, 0xca, 0x62, 0x28, 0x6b, 0x33, 0x3a, 0x73, 0x09, - 0x8f, 0x59, 0x8b, 0x47, 0xfe, 0x56, 0xf6, 0x37, 0xe8, 0x09, 0xb6, 0x2e, - 0xe4, 0x35, 0xc6, 0xc5, 0x5c, 0x4e, 0xee, 0x57, 0xa3, 0x65, 0xfa, 0xc9, - 0x94, 0xe1, 0x8c, 0x65, 0x70, 0x7e, 0xec, 0x17, 0xe5, 0x1a, 0x07, 0x81, - 0xd4, 0xe2, 0x04, 0x4f, 0x62, 0xcd, 0xce, 0xc9, 0xa1, 0xf2, 0x47, 0xb4, - 0xdf, 0xde, 0x78, 0xc2, 0xac, 0x87, 0xa8, 0xa8, 0x1e, 0xfa, 0x4e, 0xd0, - 0xe6, 0xf9, 0x75, 0xfd, 0xde, 0x3d, 0xc1, 0xdf, 0x49, 0x1d, 0x4f, 0xaa, - 0xc9, 0x7b, 0x63, 0xef, 0x14, 0x97, 0xc9, 0x3a, 0xda, 0x1d, 0x58, 0xb3, - 0x4a, 0x3d, 0xde, 0x19, 0x47, 0xa0, 0xcc, 0x23, 0x3f, 0x1d, 0x01, 0x4f, - 0x60, 0xf2, 0x9a, 0xf7, 0xe9, 0x83, 0xac, 0xc5, 0x4f, 0x3e, 0x6c, 0x62, - 0x57, 0x4e, 0xc1, 0xa6, 0xdb, 0xbb, 0xd4, 0x07, 0x64, 0x65, 0x22, 0x2e, - 0xa7, 0x4b, 0x2d, 0x32, 0x5b, 0x52, 0x6d, 0x31, 0x2b, 0x3b, 0x63, 0x92, - 0xd4, 0xfa, 0x97, 0x76, 0xdf, 0xc0, 0x54, 0xcc, 0xd2, 0xdd, 0x8d, 0xe8, - 0xff, 0x93, 0xd0, 0xb1, 0x15, 0xe8, 0xd8, 0x8d, 0xd0, 0xc1, 0x2b, 0x65, - 0xc4, 0xfe, 0x86, 0xd5, 0x32, 0x82, 0x6d, 0xd2, 0xf0, 0xd6, 0x8f, 0xa0, - 0x5d, 0x44, 0x7f, 0x71, 0x4d, 0x6b, 0x79, 0x29, 0x38, 0x7b, 0xab, 0x13, - 0xce, 0xbe, 0xea, 0x4a, 0x1d, 0xd4, 0xe3, 0xb9, 0x62, 0x60, 0x3d, 0x5d, - 0xa2, 0xed, 0x9a, 0x0e, 0x72, 0xc0, 0xc9, 0x3e, 0xd0, 0xdd, 0x53, 0x93, - 0xf0, 0xef, 0x29, 0x97, 0x01, 0xf3, 0x19, 0xc0, 0x3c, 0x33, 0xe9, 0x44, - 0xb6, 0x81, 0x30, 0x40, 0x33, 0x33, 0xd5, 0x2b, 0x0b, 0x73, 0xa4, 0x43, - 0xc8, 0x80, 0x49, 0xac, 0x67, 0xb0, 0x0e, 0x76, 0x00, 0xc7, 0x87, 0xdc, - 0x9e, 0xda, 0xa6, 0xdf, 0x19, 0x7d, 0xde, 0x2e, 0x0b, 0x95, 0x3b, 0x2d, - 0x6c, 0xc7, 0xea, 0x60, 0x5b, 0xb7, 0x04, 0xdb, 0x3e, 0xc0, 0xb6, 0x7f, - 0x4d, 0xd8, 0xd6, 0xd2, 0xc5, 0x1d, 0xb0, 0x69, 0xc8, 0x1f, 0x11, 0x5e, - 0xdb, 0x2c, 0x3d, 0x94, 0xac, 0x1d, 0x4c, 0x9b, 0xe8, 0x87, 0x80, 0x87, - 0x34, 0x86, 0xdf, 0xb3, 0x8f, 0x52, 0x96, 0xa1, 0x9c, 0xcf, 0x0f, 0xa1, - 0x0e, 0x9e, 0x67, 0x13, 0x56, 0x0e, 0x7e, 0xc2, 0xc2, 0x42, 0x3b, 0x21, - 0x0b, 0x5b, 0x79, 0xd0, 0xc9, 0xcd, 0x12, 0x86, 0x53, 0x80, 0x17, 0xef, - 0xaa, 0xf5, 0x7d, 0xf2, 0xce, 0x7e, 0xaf, 0xb2, 0xfd, 0xb0, 0xef, 0x68, - 0x2e, 0xeb, 0xad, 0x9e, 0x8f, 0xe8, 0x2b, 0xb2, 0xbb, 0x27, 0x9c, 0xec, - 0xaa, 0x79, 0xd5, 0xd3, 0x1c, 0xe5, 0xad, 0x2b, 0x43, 0xa0, 0x93, 0xa1, - 0x65, 0xb4, 0xa6, 0xdd, 0x13, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x1b, - 0xbe, 0x09, 0xe2, 0xd0, 0x87, 0x94, 0x37, 0xff, 0xc5, 0xf8, 0xec, 0xf2, - 0xe5, 0x06, 0xc6, 0x69, 0xcd, 0x33, 0x69, 0x93, 0xbf, 0x29, 0x93, 0x6a, - 0xb4, 0x68, 0x7c, 0x9a, 0x76, 0x8c, 0x55, 0x6f, 0xc7, 0xbb, 0x32, 0x6c, - 0xd6, 0xfc, 0x18, 0xd7, 0x9c, 0x3e, 0x4a, 0xe7, 0x03, 0xc3, 0x96, 0xbf, - 0xd2, 0x93, 0x05, 0xb9, 0xd5, 0xce, 0xfd, 0xd2, 0x1a, 0x6b, 0xb7, 0x71, - 0x69, 0xed, 0x86, 0xab, 0x2b, 0xe7, 0x28, 0xd2, 0xf1, 0x80, 0xab, 0x7d, - 0x5e, 0xfa, 0xf0, 0x8d, 0x3e, 0xe5, 0x27, 0x6d, 0x25, 0x94, 0xcf, 0xf4, - 0x78, 0xad, 0xf0, 0x0d, 0xbe, 0xb8, 0xca, 0xee, 0x4a, 0x59, 0xb9, 0x49, - 0xff, 0x38, 0x1a, 0xa3, 0x60, 0xe5, 0x64, 0x01, 0xfd, 0x4f, 0x38, 0x43, - 0xd5, 0xb5, 0xe4, 0x65, 0x24, 0x27, 0x39, 0x9f, 0x7b, 0xe5, 0x8e, 0x07, - 0xc9, 0xa3, 0x25, 0x6d, 0x5f, 0x5f, 0xb3, 0xe7, 0x30, 0xf0, 0x47, 0xf8, - 0x17, 0x36, 0xc3, 0x64, 0x80, 0xce, 0xcd, 0xca, 0xa8, 0x5d, 0xb7, 0xd1, - 0xa5, 0xf5, 0xe7, 0x35, 0x0c, 0xdd, 0xc8, 0x58, 0xae, 0xb2, 0x30, 0x6b, - 0x3b, 0x16, 0x76, 0xdd, 0x4a, 0x5b, 0x96, 0x73, 0xa0, 0x3d, 0xdb, 0x68, - 0x6c, 0xc1, 0x32, 0xed, 0x4f, 0xca, 0x2e, 0xda, 0x9f, 0x57, 0x37, 0x4a, - 0x33, 0xe7, 0x93, 0xb5, 0x65, 0xb4, 0x53, 0x57, 0xce, 0x6f, 0xa5, 0x5f, - 0x49, 0x38, 0x09, 0xb7, 0xa1, 0xad, 0x94, 0x22, 0x6c, 0xa1, 0x0c, 0x07, - 0xd7, 0xe9, 0x35, 0x50, 0xb4, 0x5d, 0xf7, 0x34, 0x34, 0x9a, 0x38, 0xf6, - 0x5e, 0xf4, 0xcf, 0x31, 0xc9, 0x7f, 0xbc, 0xd3, 0xce, 0x5f, 0x4b, 0x96, - 0xd5, 0xeb, 0x9e, 0x2b, 0x97, 0xf0, 0x37, 0xb4, 0x6c, 0x8d, 0x22, 0xfc, - 0x45, 0x74, 0x51, 0x8f, 0x43, 0xd2, 0x04, 0x69, 0x21, 0xa2, 0xc5, 0x9d, - 0x56, 0xdf, 0x44, 0xb4, 0xb7, 0x15, 0xb4, 0x77, 0x1f, 0xf0, 0x44, 0x19, - 0xce, 0x78, 0xde, 0x16, 0x3c, 0x1f, 0xc7, 0x73, 0xc4, 0x27, 0x91, 0x0c, - 0xa7, 0x4d, 0xb4, 0x52, 0x8e, 0x53, 0x86, 0xc7, 0x61, 0xf7, 0x50, 0xd6, - 0x6f, 0xb7, 0xfc, 0x94, 0xb3, 0xbc, 0x44, 0x5d, 0xf0, 0xfb, 0xe8, 0xe7, - 0x86, 0x46, 0x63, 0xa7, 0x17, 0x1b, 0x29, 0x5f, 0x37, 0xcb, 0x91, 0xba, - 0xb2, 0xcb, 0xc9, 0xef, 0xfa, 0x39, 0x6f, 0xff, 0x7f, 0x30, 0xe7, 0xe4, - 0x8a, 0x39, 0x7b, 0x76, 0xce, 0x55, 0xbc, 0x6f, 0xc5, 0xfb, 0x16, 0xea, - 0x82, 0x54, 0x4d, 0xde, 0x58, 0x5c, 0x68, 0x7d, 0x56, 0x2f, 0x27, 0x22, - 0x19, 0xc1, 0x79, 0x1d, 0xb5, 0x73, 0xf8, 0x7c, 0xdd, 0xbc, 0x8e, 0xbe, - 0x89, 0x79, 0xb5, 0x2f, 0x9b, 0xd7, 0xde, 0xcb, 0xce, 0x6b, 0x2d, 0x1e, - 0x27, 0x2f, 0x47, 0xf3, 0x8b, 0xcb, 0x81, 0x12, 0xe7, 0x38, 0x84, 0x39, - 0x12, 0x86, 0x68, 0x8e, 0x19, 0x3b, 0x47, 0x51, 0x1d, 0x7b, 0x7e, 0x0a, - 0xbf, 0xeb, 0xe7, 0x47, 0xdd, 0xff, 0xf7, 0xa0, 0xe9, 0x26, 0xf8, 0xc4, - 0x4d, 0x56, 0xfe, 0x3f, 0x29, 0xb7, 0x96, 0xb9, 0xd6, 0xe9, 0xac, 0xc8, - 0x7e, 0x75, 0xa8, 0xfc, 0x72, 0x23, 0xf7, 0x11, 0xf6, 0x06, 0x56, 0x8f, - 0x41, 0x5f, 0xec, 0x83, 0xcd, 0x37, 0x54, 0x52, 0x7d, 0x31, 0x09, 0xc3, - 0xdb, 0x82, 0x66, 0x8c, 0xbd, 0x49, 0xfb, 0xaa, 0xab, 0x63, 0xf8, 0xcf, - 0x36, 0x8a, 0x4f, 0x7b, 0x83, 0xfa, 0x1c, 0xfa, 0xee, 0x24, 0x6d, 0xb0, - 0x1c, 0xec, 0xe4, 0x6c, 0x32, 0xa6, 0x6d, 0x31, 0xea, 0xc4, 0x74, 0x32, - 0x2b, 0x15, 0xc9, 0x9f, 0xcc, 0x26, 0xe1, 0xd8, 0x62, 0x0c, 0xd8, 0x6a, - 0xb0, 0x21, 0x6f, 0x85, 0xac, 0xb9, 0xb5, 0x7a, 0x50, 0xdd, 0x02, 0x7b, - 0xe7, 0x96, 0xd3, 0xef, 0x53, 0xb7, 0xc1, 0xd6, 0xb9, 0xed, 0xf4, 0x8d, - 0xea, 0x10, 0x6c, 0x9b, 0x43, 0xb0, 0x73, 0x0e, 0x55, 0x69, 0x7b, 0xde, - 0x0c, 0xba, 0x6b, 0x87, 0x1e, 0xe2, 0x5c, 0xb8, 0x26, 0xb4, 0x71, 0x38, - 0x3f, 0xe2, 0xfe, 0x0b, 0x5c, 0x83, 0x20, 0xa5, 0x76, 0x34, 0x71, 0x5d, - 0x5a, 0x97, 0x95, 0xbd, 0x96, 0xac, 0x8a, 0xf4, 0xd3, 0x06, 0x1b, 0x4f, - 0x32, 0x7e, 0xe5, 0xe5, 0x69, 0x8b, 0x34, 0xe2, 0x01, 0xcf, 0xc4, 0x1f, - 0x69, 0xab, 0x7e, 0xfe, 0x57, 0x36, 0x89, 0x9f, 0xc3, 0xf8, 0xf7, 0x42, - 0xbe, 0xd6, 0xd3, 0x14, 0xef, 0x5e, 0x1d, 0x7f, 0x50, 0x06, 0x47, 0xf4, - 0xb0, 0xf3, 0x35, 0xe4, 0xef, 0x65, 0xe9, 0xe9, 0x9e, 0x58, 0x26, 0x0c, - 0x47, 0xfb, 0x64, 0x13, 0xe3, 0x01, 0xb9, 0x6a, 0x2d, 0x26, 0xa0, 0xfc, - 0xfa, 0x98, 0x00, 0xfd, 0xac, 0x4f, 0x03, 0xbf, 0xd3, 0xb8, 0x44, 0x46, - 0x18, 0x77, 0xa8, 0x46, 0x76, 0xf9, 0x57, 0xac, 0x5d, 0x1e, 0xc1, 0x91, - 0x02, 0x1c, 0x46, 0x3e, 0xaf, 0xd6, 0x73, 0xcb, 0xf5, 0x77, 0x61, 0xc9, - 0xa6, 0x4d, 0xc9, 0x81, 0xb2, 0xb6, 0x13, 0x21, 0x83, 0x89, 0x9b, 0x7a, - 0x19, 0x9c, 0xb4, 0x76, 0x14, 0xea, 0x68, 0xf9, 0xb9, 0x5a, 0x76, 0x52, - 0xee, 0x31, 0x6e, 0xff, 0x40, 0x40, 0x5a, 0x7f, 0x97, 0x64, 0x97, 0xe2, - 0xf6, 0x02, 0x7a, 0x93, 0x20, 0x96, 0xd1, 0x7b, 0x7a, 0xde, 0x8c, 0xec, - 0x93, 0x81, 0x04, 0x63, 0xa0, 0x8c, 0xf3, 0xf9, 0x85, 0x19, 0xe9, 0x66, - 0x8c, 0x03, 0x16, 0x7c, 0xa3, 0x8c, 0x78, 0xa1, 0xec, 0x0d, 0x1c, 0x1d, - 0x53, 0x36, 0xba, 0xf6, 0x62, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0x17, 0x5e, - 0x00, 0xf5, 0x2d, 0x68, 0xfb, 0x56, 0x69, 0xfd, 0x3b, 0xaf, 0xeb, 0xfc, - 0x41, 0x53, 0x14, 0xdf, 0x5c, 0xf0, 0x62, 0xb6, 0x5e, 0x7d, 0xf9, 0xd7, - 0x6c, 0xdc, 0xba, 0x1b, 0xb2, 0x3f, 0x2a, 0xfb, 0xde, 0x1a, 0x65, 0xb1, - 0xf8, 0xea, 0xb2, 0xcd, 0x6b, 0x94, 0x99, 0x78, 0xe1, 0x50, 0x69, 0x27, - 0xde, 0x4d, 0x68, 0xdf, 0x5d, 0xf4, 0x9e, 0x5b, 0xb7, 0x14, 0x96, 0xea, - 0x6c, 0xb0, 0x7e, 0x19, 0x63, 0xc7, 0x26, 0x66, 0x9c, 0xd7, 0x31, 0xe3, - 0x1e, 0x6f, 0x8f, 0xd2, 0x7b, 0x2c, 0xb7, 0x33, 0xfe, 0x78, 0x48, 0xe3, - 0x85, 0x38, 0xf9, 0x02, 0x63, 0xc3, 0x05, 0xee, 0x0f, 0xa7, 0xd4, 0xe5, - 0x68, 0xbb, 0x66, 0x9b, 0x98, 0x75, 0xa3, 0x5d, 0xdc, 0x22, 0x83, 0xb0, - 0x15, 0x86, 0x4a, 0xad, 0xb2, 0x77, 0xea, 0xa3, 0xeb, 0xa8, 0xb7, 0xf6, - 0x4d, 0x19, 0x7f, 0xf0, 0x10, 0xf8, 0x2a, 0x2b, 0x84, 0x31, 0x1d, 0x88, - 0xd0, 0x26, 0x5e, 0x6d, 0x0b, 0xbf, 0x76, 0x7f, 0xf7, 0x5f, 0xa6, 0x3f, - 0x07, 0xb6, 0xc3, 0x1b, 0xed, 0xaf, 0x59, 0x06, 0xa7, 0x22, 0x5c, 0xa9, - 0x1f, 0xb1, 0x5d, 0xec, 0x32, 0xed, 0xb4, 0x5d, 0x22, 0x4f, 0x2d, 0xc9, - 0xe2, 0x9d, 0xb0, 0x99, 0x24, 0xcc, 0xf5, 0x49, 0x7b, 0x4c, 0x74, 0x8c, - 0x27, 0x30, 0xb2, 0xb9, 0x8b, 0x7b, 0x3e, 0xa0, 0x7f, 0x63, 0xab, 0x98, - 0x78, 0x6a, 0x64, 0xa7, 0xac, 0x45, 0xbb, 0xd7, 0x5b, 0xda, 0xe5, 0xbe, - 0xee, 0x3e, 0xca, 0x5c, 0xac, 0x89, 0xa1, 0xe3, 0xbd, 0x25, 0x49, 0x45, - 0x74, 0xbc, 0x20, 0xd9, 0x65, 0x74, 0xbc, 0x20, 0x83, 0x9a, 0x8e, 0x1b, - 0x97, 0xd1, 0x71, 0xbb, 0xa5, 0xe3, 0x8f, 0xc6, 0x0d, 0x5d, 0x28, 0xad, - 0xa7, 0x48, 0xa7, 0x86, 0x8e, 0x1d, 0x4d, 0xc7, 0x0b, 0xb8, 0xbb, 0xfe, - 0xc7, 0x6c, 0x9d, 0x98, 0x2d, 0xe3, 0xef, 0xa8, 0x8c, 0x72, 0x71, 0x2a, - 0x6e, 0xf4, 0xd2, 0x20, 0xe8, 0x28, 0x2a, 0xff, 0x4d, 0x4b, 0x9f, 0xf5, - 0x65, 0x26, 0x3e, 0x32, 0x54, 0x3a, 0xb2, 0x82, 0x3e, 0x07, 0x41, 0x9f, - 0x51, 0x9d, 0xd7, 0xa2, 0xcf, 0x66, 0xbb, 0x9f, 0x91, 0xd4, 0x7b, 0xff, - 0xd9, 0x84, 0xa1, 0xd5, 0x5b, 0xf4, 0xdc, 0x39, 0xef, 0x0b, 0x6f, 0x80, - 0x56, 0xcd, 0xda, 0x5c, 0xac, 0xf9, 0xdb, 0x8c, 0x45, 0xa5, 0x4c, 0x6c, - 0x9b, 0x71, 0xd2, 0xcb, 0xd9, 0x8e, 0x2f, 0xd5, 0xf9, 0x15, 0x1b, 0xa4, - 0xc0, 0xbc, 0x87, 0xea, 0x46, 0xc6, 0xa2, 0x47, 0xdc, 0x4c, 0x9f, 0x64, - 0x2b, 0xed, 0xa9, 0x62, 0x89, 0x7e, 0xd1, 0xab, 0x36, 0x37, 0x02, 0xcf, - 0x95, 0x16, 0x79, 0xb4, 0x44, 0xda, 0x3a, 0x62, 0x70, 0xb1, 0x26, 0xad, - 0x73, 0xad, 0xd9, 0x4f, 0xbd, 0x0e, 0xe8, 0x83, 0xee, 0xa1, 0xcd, 0xae, - 0xe5, 0x3e, 0xde, 0xb5, 0xa7, 0x72, 0xa5, 0xa8, 0x5f, 0xee, 0x3f, 0x70, - 0x4f, 0xb8, 0x3d, 0xd5, 0x51, 0xf1, 0x6d, 0x9c, 0x79, 0x23, 0x9e, 0xfb, - 0xa4, 0xa3, 0xa2, 0xe4, 0x03, 0x53, 0x2d, 0x72, 0x7b, 0xc9, 0x95, 0x0f, - 0xa1, 0xfd, 0x07, 0x4b, 0x1e, 0xfc, 0xfb, 0xff, 0x1d, 0xa7, 0x9d, 0x79, - 0xa8, 0xc4, 0x7d, 0x50, 0x47, 0xdb, 0x2a, 0xcb, 0xf7, 0x86, 0x63, 0xd2, - 0xd1, 0x55, 0x84, 0xe7, 0x23, 0xee, 0x7e, 0xc0, 0xd1, 0x94, 0xc9, 0xc8, - 0x77, 0xfa, 0x36, 0xa1, 0x2c, 0xca, 0xf1, 0x18, 0x76, 0x4c, 0xfc, 0xb8, - 0x5f, 0xde, 0x59, 0xcd, 0xc8, 0x0d, 0x55, 0xb3, 0x77, 0x5b, 0xdb, 0x9b, - 0x4d, 0x7b, 0xf3, 0xd0, 0x67, 0x59, 0x2f, 0x0c, 0x2f, 0xfa, 0xa0, 0xa2, - 0xe3, 0xae, 0xc4, 0xbb, 0xd2, 0xc9, 0x79, 0x31, 0xcf, 0x97, 0x2a, 0xff, - 0x1c, 0x8e, 0x24, 0x5c, 0xf9, 0x8e, 0xcf, 0x39, 0xf6, 0xcb, 0xf5, 0x95, - 0xfa, 0xb1, 0xb9, 0x3f, 0x1b, 0x5b, 0xc7, 0xfd, 0x90, 0x5c, 0xf5, 0x9f, - 0xe3, 0x8c, 0xdb, 0xd3, 0x87, 0xe9, 0xf8, 0x31, 0xee, 0x87, 0xbb, 0xb8, - 0x83, 0x0e, 0x13, 0xb0, 0x21, 0xae, 0x01, 0x8c, 0xd7, 0x30, 0x96, 0xc6, - 0x18, 0x1a, 0x9f, 0xbf, 0x8c, 0x71, 0xd9, 0xf6, 0x93, 0xd6, 0xfe, 0x3e, - 0xb2, 0xc4, 0x8b, 0x6b, 0xeb, 0xb1, 0x8d, 0x23, 0xf1, 0x8c, 0x38, 0xf1, - 0x9f, 0x48, 0xca, 0x3a, 0xbf, 0x7e, 0x7c, 0xee, 0x47, 0xc3, 0xa2, 0xec, - 0x13, 0x77, 0xdf, 0xee, 0x7e, 0x19, 0xc4, 0xfc, 0x86, 0x56, 0xcd, 0xef, - 0x1e, 0x61, 0xbc, 0xf6, 0x52, 0x89, 0x73, 0xa8, 0xcd, 0x4b, 0xfd, 0xb6, - 0x99, 0x57, 0xbc, 0x6b, 0xe5, 0x7c, 0x74, 0x7b, 0x75, 0x0a, 0xb0, 0x7c, - 0x49, 0xe7, 0x42, 0x84, 0xe1, 0x5b, 0xbb, 0x2e, 0x85, 0xa9, 0x2b, 0xd2, - 0xdd, 0xf3, 0xb5, 0x7d, 0xa4, 0x91, 0x58, 0x26, 0xab, 0xf5, 0x23, 0x9e, - 0x53, 0xf9, 0xca, 0x7e, 0xac, 0xa3, 0xb8, 0xf9, 0x5e, 0x57, 0xf3, 0x5d, - 0xde, 0xdf, 0x6f, 0xf7, 0xca, 0x22, 0x9f, 0x2c, 0x0c, 0x95, 0xbf, 0x52, - 0x0e, 0x51, 0xff, 0x61, 0xee, 0xf2, 0x98, 0xdd, 0x3f, 0xe8, 0x66, 0x7c, - 0x0c, 0xb4, 0x18, 0x07, 0xdd, 0xf9, 0xf8, 0xdd, 0x82, 0xfb, 0x1e, 0xd8, - 0x3f, 0x01, 0xec, 0x23, 0x49, 0x28, 0x23, 0x6b, 0xc0, 0x1b, 0x5d, 0x05, - 0xa5, 0xc8, 0xeb, 0x5e, 0x6a, 0xbc, 0x92, 0x48, 0x4d, 0x56, 0x9e, 0x60, - 0x7b, 0xd4, 0x5d, 0x2b, 0x36, 0x68, 0xf2, 0x6c, 0xbe, 0x58, 0xe5, 0x18, - 0xa4, 0xfb, 0x37, 0x32, 0x86, 0x6b, 0xfb, 0x66, 0x9f, 0x11, 0x5e, 0x5c, - 0xba, 0xf8, 0xf8, 0xb7, 0xdf, 0xfa, 0x3a, 0x9c, 0xdf, 0x13, 0x16, 0xee, - 0x95, 0xe3, 0x3e, 0xaf, 0xed, 0xa1, 0xc7, 0xab, 0xb4, 0x41, 0xb9, 0x8f, - 0x94, 0x7e, 0x64, 0x5a, 0x08, 0x47, 0x18, 0x3e, 0x1b, 0x18, 0x5b, 0xe0, - 0x8b, 0x55, 0xee, 0x99, 0x84, 0xe1, 0xdf, 0xd2, 0xce, 0x3e, 0x58, 0xc6, - 0x78, 0x11, 0x0e, 0x76, 0x16, 0x5c, 0xc8, 0xd9, 0x89, 0x3e, 0xe2, 0x57, - 0xe0, 0xf1, 0x76, 0x79, 0x07, 0x24, 0x9e, 0xfa, 0x78, 0xa5, 0x25, 0x75, - 0x67, 0xc5, 0x03, 0x9e, 0x39, 0xef, 0x44, 0x6a, 0xcc, 0xce, 0x39, 0x5f, - 0x21, 0x7e, 0x5f, 0x6b, 0xbf, 0xf3, 0xf9, 0x65, 0xfe, 0x17, 0x61, 0xaa, - 0xc1, 0x42, 0xd8, 0x52, 0x16, 0x37, 0x61, 0xf8, 0xf7, 0x01, 0xc7, 0xdc, - 0x0f, 0x1f, 0x46, 0x26, 0x30, 0x6e, 0x61, 0x8b, 0x22, 0x1e, 0xe2, 0xa9, - 0x3b, 0x30, 0xf6, 0xc7, 0x31, 0xf6, 0xed, 0x15, 0x8e, 0x07, 0xd9, 0x83, - 0xb9, 0x4f, 0x54, 0x23, 0x78, 0xd7, 0x1a, 0x3b, 0x5a, 0xf3, 0x6e, 0x6b, - 0x33, 0x46, 0xcf, 0x1a, 0x91, 0x6d, 0x0a, 0xbe, 0x63, 0xae, 0xba, 0xb0, - 0xd9, 0x95, 0x9f, 0x81, 0x1c, 0x0f, 0xe5, 0x51, 0xc8, 0xc7, 0x05, 0x4d, - 0x37, 0xb9, 0xed, 0xfc, 0x3f, 0x26, 0x4f, 0xad, 0x63, 0xbc, 0x7a, 0xc0, - 0xa7, 0x2d, 0xbc, 0x18, 0x2e, 0xf8, 0x94, 0xf7, 0x1b, 0x64, 0xda, 0x2b, - 0x74, 0x43, 0xf7, 0xa0, 0x6c, 0x23, 0xfd, 0xf7, 0x54, 0x2e, 0x96, 0x4e, - 0x8d, 0x0b, 0x73, 0xbe, 0x98, 0x13, 0xc1, 0xbc, 0x26, 0xca, 0x06, 0x17, - 0x32, 0x94, 0x6b, 0x68, 0xc6, 0x1b, 0xaf, 0xd4, 0xea, 0x1e, 0x16, 0xee, - 0x4d, 0xa6, 0x93, 0x87, 0xb4, 0xbd, 0x23, 0x32, 0x5a, 0x62, 0xdd, 0xdd, - 0xb0, 0x76, 0xfc, 0xba, 0xfa, 0x3a, 0x57, 0x0d, 0x7c, 0x1e, 0xc5, 0xc5, - 0xe2, 0xcc, 0x29, 0x79, 0x39, 0xd6, 0x27, 0x2f, 0xd3, 0x8e, 0x1d, 0x00, - 0x6d, 0x7b, 0xbe, 0xce, 0x2b, 0xd1, 0xe5, 0xb9, 0x40, 0x16, 0x73, 0xfd, - 0x3d, 0xb4, 0xdb, 0x0b, 0x4a, 0xf3, 0x84, 0x28, 0xb4, 0x8d, 0xe7, 0x2b, - 0x32, 0x98, 0x2f, 0xd9, 0xd8, 0xd1, 0x30, 0xe7, 0xbc, 0xa1, 0x6e, 0xee, - 0x1b, 0xc5, 0x05, 0x4c, 0x83, 0xb1, 0x94, 0xd3, 0xe0, 0x7f, 0xaa, 0xc5, - 0xd8, 0x10, 0xd0, 0x23, 0xad, 0xf7, 0xb7, 0x71, 0x6f, 0x56, 0xc1, 0x27, - 0x57, 0x6d, 0x1f, 0xbe, 0x56, 0x65, 0xfe, 0x32, 0x09, 0xbd, 0x6a, 0x65, - 0x65, 0x7c, 0xb0, 0x63, 0x89, 0xbe, 0x39, 0xbe, 0xb4, 0xc5, 0xfc, 0xd4, - 0xe0, 0x40, 0x45, 0x54, 0x2c, 0xe3, 0xc5, 0x07, 0x2a, 0xcb, 0x69, 0xfe, - 0x8b, 0xd5, 0xcf, 0x5a, 0xdb, 0xb2, 0x3e, 0x46, 0x5b, 0xff, 0x8e, 0x7c, - 0xb7, 0x6c, 0xff, 0x23, 0x05, 0xbe, 0xb2, 0xfb, 0xc6, 0x5c, 0x93, 0xec, - 0x5b, 0x19, 0xd8, 0x9c, 0xd6, 0x3e, 0x1f, 0x73, 0x3b, 0xe2, 0x36, 0xbf, - 0xce, 0xe0, 0x3a, 0x5b, 0x71, 0x64, 0x02, 0xf2, 0xe1, 0xb0, 0xfc, 0x53, - 0x98, 0x4d, 0x98, 0xf7, 0x66, 0x7d, 0x59, 0x9f, 0x7b, 0x1b, 0xcd, 0x52, - 0x3c, 0xed, 0x4a, 0xe1, 0x34, 0xf7, 0xd4, 0xce, 0xdd, 0x51, 0xcb, 0x0f, - 0xa1, 0x1c, 0xe0, 0xbe, 0xb0, 0x23, 0x45, 0xf8, 0xc8, 0x83, 0xdc, 0xef, - 0xef, 0xfd, 0x47, 0xe6, 0xea, 0xc4, 0xb9, 0x4e, 0xa6, 0x6d, 0x0b, 0xda, - 0x36, 0xda, 0xb6, 0xc1, 0xc7, 0xdf, 0x5c, 0xdb, 0x8d, 0x68, 0x1b, 0x8f, - 0xc6, 0x7d, 0x83, 0x6d, 0x35, 0x3e, 0xaf, 0x1d, 0x28, 0x95, 0x17, 0x5d, - 0xdf, 0x4f, 0x8e, 0x49, 0xd6, 0x19, 0xed, 0xd3, 0xf3, 0xb9, 0x76, 0xa0, - 0x02, 0x38, 0x12, 0x61, 0x58, 0x0c, 0x22, 0xbd, 0xce, 0x7f, 0x27, 0xa1, - 0xde, 0x59, 0xc6, 0x7d, 0x50, 0xfa, 0x27, 0x8c, 0xba, 0x7a, 0xcc, 0xc1, - 0x93, 0x22, 0xf7, 0x3b, 0x13, 0x9b, 0x70, 0x57, 0x1d, 0xc4, 0x49, 0xde, - 0x67, 0xfc, 0x78, 0x93, 0x2d, 0x8f, 0xb1, 0x3c, 0xed, 0x42, 0x96, 0x98, - 0xf2, 0x98, 0x2d, 0x07, 0x4c, 0x41, 0x31, 0x05, 0x6e, 0xb3, 0xe5, 0x7c, - 0x56, 0xba, 0xdc, 0x3c, 0x1b, 0x1e, 0x1a, 0x11, 0xc6, 0x89, 0x72, 0xd7, - 0x37, 0xc8, 0x4e, 0xac, 0x0f, 0x7d, 0x50, 0x47, 0x9a, 0x01, 0xc7, 0xc5, - 0xe0, 0xc7, 0x61, 0xab, 0x87, 0xf2, 0x9d, 0xc0, 0xd0, 0xff, 0x8c, 0x74, - 0x65, 0x95, 0xc3, 0x5c, 0x83, 0x50, 0x86, 0x82, 0x5d, 0xc9, 0xbd, 0xf8, - 0x3d, 0xda, 0x9b, 0x92, 0x99, 0x7e, 0xd0, 0x63, 0x2f, 0x79, 0x63, 0x27, - 0x6c, 0x28, 0xfc, 0xee, 0x6a, 0x91, 0x45, 0xaf, 0xe0, 0xad, 0x83, 0xff, - 0x37, 0x88, 0x59, 0xcd, 0x96, 0x7c, 0xef, 0x36, 0x08, 0xb9, 0xac, 0xd7, - 0x85, 0x7b, 0xfd, 0x7c, 0xbf, 0x8e, 0xf9, 0x9e, 0x6b, 0x96, 0x66, 0x96, - 0xd7, 0xd7, 0x6d, 0x94, 0xfd, 0xde, 0x6e, 0x2f, 0xbe, 0xac, 0xee, 0x25, - 0xd4, 0x65, 0x99, 0xef, 0x31, 0x17, 0x68, 0xa6, 0x42, 0x3a, 0x33, 0xb0, - 0x76, 0x74, 0x85, 0xe1, 0xf5, 0x01, 0xc7, 0x0d, 0xc3, 0x1b, 0x82, 0x1e, - 0xef, 0x19, 0x79, 0x2e, 0x34, 0x36, 0x5a, 0x44, 0x3b, 0xcf, 0x5a, 0x79, - 0x1d, 0x86, 0x2f, 0x07, 0xdd, 0xf2, 0xb9, 0x6a, 0xfa, 0x1c, 0x7d, 0xf8, - 0xf3, 0x78, 0x3e, 0x1f, 0x98, 0xfc, 0xa5, 0x3f, 0x43, 0xbb, 0x84, 0xea, - 0x05, 0x0d, 0xfb, 0xf2, 0x59, 0xed, 0xf3, 0x13, 0x7f, 0x66, 0xcf, 0xa0, - 0x06, 0x03, 0x26, 0xec, 0xe7, 0x36, 0x7b, 0xcc, 0x69, 0xd4, 0xf4, 0x5b, - 0xff, 0x4e, 0xe1, 0x1d, 0xcb, 0xc2, 0xf0, 0x8a, 0xbe, 0x96, 0xf5, 0xd0, - 0xd7, 0x93, 0xdc, 0x0b, 0x7c, 0x9f, 0xe6, 0x3f, 0x91, 0x03, 0xdc, 0xf7, - 0x02, 0x0e, 0x95, 0xf2, 0x8f, 0x75, 0xa8, 0x74, 0x41, 0xe4, 0x2d, 0x58, - 0x7f, 0xae, 0x31, 0x18, 0xa4, 0x15, 0xb0, 0xef, 0xfa, 0xa5, 0x66, 0x13, - 0x9b, 0xa2, 0x6f, 0x9e, 0xdd, 0x0c, 0xdf, 0x59, 0xdb, 0x33, 0xdc, 0x57, - 0x1f, 0x6b, 0x0d, 0xc3, 0xf7, 0x06, 0xd1, 0x9a, 0xd9, 0xd8, 0x37, 0x74, - 0x7c, 0xbe, 0x57, 0xd6, 0x1b, 0xbb, 0x90, 0xb9, 0x8d, 0x29, 0xbd, 0x4f, - 0xa0, 0xda, 0xa0, 0x43, 0x76, 0xfd, 0x00, 0x38, 0xe5, 0x18, 0xcc, 0x73, - 0x8c, 0x60, 0xaa, 0xb5, 0xcf, 0xf7, 0xae, 0xb3, 0x36, 0xac, 0x0b, 0x5c, - 0xfa, 0x5e, 0x87, 0xfa, 0x5e, 0x68, 0x74, 0x6b, 0x44, 0xc3, 0xff, 0x10, - 0x3e, 0x98, 0x30, 0xcf, 0xb9, 0x5d, 0xec, 0x63, 0xa7, 0x8c, 0xef, 0xc2, - 0xb3, 0x7b, 0x1d, 0xee, 0x03, 0x57, 0xc6, 0xe4, 0xaa, 0xe4, 0x80, 0xda, - 0xe5, 0x3d, 0x28, 0x3d, 0x56, 0xc6, 0x7d, 0x09, 0xfa, 0xbe, 0x00, 0xff, - 0xbe, 0x49, 0x1e, 0x04, 0x4d, 0xab, 0xbe, 0x74, 0x6a, 0x5e, 0xa5, 0xbb, - 0xa7, 0x55, 0x3a, 0x18, 0x51, 0x13, 0x9c, 0x57, 0x3f, 0x71, 0x31, 0x4d, - 0xfc, 0x96, 0x81, 0xff, 0x32, 0x70, 0x7c, 0xd9, 0x3d, 0xe3, 0xc0, 0xea, - 0x16, 0xa3, 0xdf, 0x0a, 0x9a, 0x36, 0x8d, 0x9d, 0xff, 0xa7, 0x41, 0xb4, - 0x86, 0x3d, 0x5e, 0x03, 0x73, 0x71, 0xd6, 0x5c, 0xa3, 0x3c, 0xd7, 0x08, - 0x8a, 0xa1, 0x00, 0xba, 0x4f, 0xa7, 0xc6, 0xd4, 0x62, 0xb8, 0x79, 0x4f, - 0x67, 0xf7, 0x63, 0xba, 0x9f, 0x74, 0x90, 0x55, 0x4f, 0x02, 0x9e, 0x9d, - 0xd2, 0xb4, 0x87, 0x78, 0x26, 0xac, 0x71, 0xc6, 0xa7, 0xbc, 0x3b, 0x50, - 0x77, 0x44, 0xe9, 0x3d, 0x6d, 0x5b, 0x87, 0x30, 0xbf, 0x1b, 0xf8, 0xa5, - 0x1e, 0x62, 0xcc, 0xed, 0xb5, 0x74, 0x21, 0x64, 0xd2, 0x49, 0xca, 0xc0, - 0x98, 0x89, 0x25, 0x57, 0xef, 0xe4, 0xfa, 0xd3, 0x13, 0x88, 0xbb, 0x90, - 0x51, 0x13, 0xe0, 0xe2, 0xa3, 0x27, 0xc5, 0x6d, 0xf0, 0xbb, 0xd7, 0x1b, - 0x3f, 0x8c, 0x3e, 0x19, 0xc7, 0x6e, 0x90, 0xe2, 0xaa, 0xf8, 0xcd, 0x24, - 0xe0, 0x6f, 0x96, 0xf1, 0x93, 0x5c, 0x0b, 0x17, 0x32, 0x87, 0x63, 0x8b, - 0x9b, 0xeb, 0x0d, 0xc3, 0x51, 0x96, 0x9f, 0x26, 0xff, 0x4a, 0x9a, 0xef, - 0x0a, 0xa7, 0xe7, 0x37, 0xab, 0x65, 0xb2, 0xb6, 0xc5, 0xc2, 0xa1, 0xf1, - 0x24, 0x93, 0x5a, 0x8e, 0x50, 0xdf, 0xcc, 0xd4, 0xc1, 0x13, 0x7c, 0x7c, - 0xc2, 0x6f, 0x7c, 0x13, 0xf0, 0xfc, 0x0f, 0xc0, 0xd3, 0x62, 0xe1, 0x69, - 0x5c, 0x01, 0x4f, 0x4b, 0x04, 0x0f, 0xe4, 0x1c, 0xe5, 0x6a, 0xfc, 0xda, - 0x6c, 0x45, 0x9c, 0xa2, 0x2f, 0xed, 0x4a, 0xfb, 0x43, 0xd4, 0x37, 0x8d, - 0xde, 0x68, 0x9f, 0x27, 0xa3, 0x5a, 0xd7, 0xb8, 0xd7, 0x76, 0x56, 0xe6, - 0x61, 0xbd, 0x8a, 0x93, 0xf3, 0x09, 0xfb, 0x5a, 0x76, 0xd5, 0x3d, 0x90, - 0xff, 0x0b, 0x69, 0xd7, 0xda, 0x12, 0x93, 0x01, 0xfd, 0xa0, 0x84, 0xce, - 0x15, 0xa8, 0xc1, 0xf4, 0x12, 0x60, 0x82, 0x3c, 0x3e, 0xd9, 0xe3, 0x0d, - 0xcb, 0x56, 0xed, 0xeb, 0x59, 0x5c, 0x63, 0x6e, 0xf1, 0xba, 0xb9, 0x41, - 0xff, 0xa9, 0x68, 0x6e, 0x90, 0x89, 0xa8, 0x37, 0x29, 0x7f, 0x64, 0x71, - 0xb1, 0x11, 0x73, 0x8a, 0xd7, 0xcd, 0xa7, 0x33, 0x79, 0x3b, 0xcb, 0xcc, - 0x7c, 0xba, 0x8a, 0x7e, 0xdc, 0xe2, 0x77, 0x2d, 0x9f, 0xc4, 0xd8, 0x3d, - 0xd3, 0x12, 0xca, 0x44, 0x80, 0x35, 0xea, 0xa6, 0x7f, 0x12, 0xb7, 0xb9, - 0xd7, 0x0a, 0xcf, 0x1b, 0x2c, 0x7f, 0x79, 0x52, 0xd4, 0xfe, 0xe0, 0xdf, - 0x59, 0x3e, 0x75, 0x6d, 0x9e, 0x1c, 0x7f, 0x1f, 0x5c, 0x6f, 0xf3, 0x05, - 0x0a, 0x59, 0x79, 0x65, 0x3d, 0xed, 0x92, 0x06, 0xff, 0x57, 0x56, 0x94, - 0xc5, 0x51, 0x76, 0x6a, 0xbd, 0x95, 0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1f, - 0xf3, 0x3e, 0xf8, 0x8e, 0x32, 0xb8, 0x1e, 0x27, 0x3d, 0x60, 0x45, 0xf2, - 0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc, 0x51, 0x6d, 0x8f, 0xe2, 0xf2, 0xf8, - 0xbd, 0x96, 0xed, 0x4f, 0x7c, 0x13, 0xd7, 0xf2, 0x8d, 0x09, 0xf0, 0xfd, - 0xe1, 0xc0, 0x71, 0x67, 0x98, 0x57, 0xa0, 0x69, 0xb8, 0xbe, 0xef, 0x1b, - 0x18, 0x26, 0xb4, 0xb4, 0x4c, 0x7a, 0x21, 0x4f, 0x3b, 0xd2, 0x44, 0x5d, - 0x7c, 0xd2, 0xd3, 0x39, 0xee, 0x39, 0xad, 0x97, 0xeb, 0xd7, 0xb1, 0x09, - 0xba, 0x26, 0x61, 0x78, 0xd4, 0x33, 0xfb, 0xe7, 0xb5, 0xfe, 0x46, 0xd0, - 0x1f, 0xed, 0x34, 0xf8, 0xfd, 0x3e, 0xa3, 0x43, 0x94, 0x5f, 0x8e, 0xab, - 0xae, 0xd6, 0x7e, 0x6b, 0x5c, 0xe7, 0x37, 0x2d, 0xd5, 0x1d, 0xb3, 0x63, - 0x93, 0x6e, 0xcd, 0x7e, 0x42, 0x6d, 0x7c, 0x71, 0xd4, 0x2e, 0x01, 0x95, - 0x35, 0xca, 0x44, 0x1f, 0x69, 0x94, 0x73, 0xd7, 0x36, 0xd4, 0xb5, 0xb4, - 0x23, 0x0c, 0x7d, 0xd2, 0x76, 0x72, 0xaf, 0xcd, 0x97, 0x1a, 0x8d, 0xcf, - 0x92, 0x90, 0x2d, 0x0d, 0x3a, 0x2f, 0x01, 0x65, 0x95, 0x48, 0x97, 0xb9, - 0x32, 0xd3, 0xfb, 0x7f, 0xc2, 0xec, 0x41, 0xd6, 0x5d, 0x33, 0x0f, 0x20, - 0x39, 0x2d, 0x1a, 0x4f, 0x5f, 0xab, 0xe1, 0xc9, 0xce, 0x2d, 0xb1, 0x72, - 0x6e, 0x70, 0x6a, 0xfd, 0x7b, 0x20, 0x3b, 0xb9, 0x4e, 0x26, 0xe7, 0xfc, - 0x9c, 0x38, 0x6e, 0xae, 0x7b, 0xad, 0xb9, 0x4d, 0x46, 0x78, 0xe5, 0xdc, - 0x40, 0xab, 0xd1, 0xbc, 0x48, 0xdb, 0x09, 0xbd, 0xef, 0xa4, 0x14, 0x61, - 0xd9, 0xb8, 0x02, 0xb7, 0x11, 0xdd, 0x19, 0x9a, 0xfb, 0xa2, 0xa6, 0xb9, - 0x16, 0x4b, 0x73, 0xa8, 0xeb, 0x71, 0x1f, 0xfd, 0xbe, 0x96, 0x1a, 0xcd, - 0x6d, 0xb0, 0x34, 0xa7, 0x5a, 0xcc, 0x1e, 0x7b, 0xb9, 0xc5, 0xec, 0x71, - 0x25, 0x57, 0x3c, 0xbf, 0x93, 0xcf, 0xf0, 0xc5, 0xa2, 0xe7, 0x7a, 0x58, - 0xcf, 0x03, 0xd6, 0x7a, 0x59, 0xd3, 0x64, 0xe3, 0x78, 0xdc, 0x8f, 0xa7, - 0xdf, 0xe7, 0xca, 0xa3, 0xb0, 0x83, 0x8a, 0x95, 0x1f, 0x84, 0xf3, 0xf0, - 0xfd, 0x26, 0x96, 0x74, 0xef, 0x4c, 0x0b, 0xf9, 0x6d, 0x1a, 0xbf, 0x8e, - 0xd4, 0xf9, 0x3c, 0x98, 0x2f, 0xca, 0xfe, 0x19, 0xeb, 0x01, 0xb9, 0xbc, - 0x54, 0x97, 0x31, 0x10, 0xe3, 0xe3, 0x9c, 0xab, 0xb6, 0xdb, 0xfd, 0x49, - 0xca, 0xf9, 0xbb, 0xe1, 0x13, 0xdd, 0x03, 0x3d, 0x49, 0xfa, 0xee, 0xd8, - 0x60, 0xf2, 0x89, 0x13, 0xd0, 0x63, 0x3f, 0x6f, 0x73, 0xab, 0x6e, 0xbf, - 0x7d, 0xed, 0x5c, 0x62, 0xd0, 0xbe, 0x43, 0x9a, 0x79, 0xdb, 0x06, 0x13, - 0x83, 0xde, 0xba, 0x81, 0x7c, 0xa6, 0x76, 0xed, 0xda, 0xa8, 0xf9, 0xc2, - 0x89, 0x9e, 0xab, 0x2b, 0x9e, 0xa3, 0x76, 0x7f, 0xb3, 0x71, 0x79, 0xbb, - 0xa8, 0xfc, 0xce, 0x4d, 0xcb, 0xcb, 0xff, 0xa3, 0xb7, 0xbc, 0x7d, 0xe3, - 0xe6, 0xe5, 0xcf, 0x7b, 0x57, 0x3c, 0x7f, 0x64, 0xc5, 0xf3, 0xef, 0xad, - 0x78, 0xde, 0xd1, 0xba, 0xfc, 0xf9, 0x43, 0x2b, 0x9e, 0x4f, 0xb5, 0xae, - 0x0d, 0xef, 0x42, 0xeb, 0x72, 0xb8, 0xee, 0xd6, 0xfb, 0x07, 0xd3, 0x55, - 0x57, 0xf6, 0x96, 0xf0, 0xde, 0x79, 0xdf, 0x16, 0xa3, 0xd7, 0xea, 0xdf, - 0x33, 0x5e, 0xb7, 0x7b, 0xcb, 0xf2, 0xfe, 0x6a, 0xed, 0xf6, 0xd5, 0xda, - 0x05, 0xb5, 0x76, 0x46, 0xb6, 0xcd, 0x54, 0xf9, 0x8e, 0xe5, 0x51, 0xbf, - 0xa6, 0xed, 0x44, 0xd9, 0xd7, 0x39, 0xb7, 0xc3, 0x3a, 0xe7, 0x36, 0x05, - 0x3e, 0xbc, 0x5b, 0xc7, 0xa8, 0x36, 0xc3, 0x50, 0x1e, 0xaf, 0x6e, 0xd4, - 0x71, 0x2a, 0xd1, 0x79, 0xb7, 0xc3, 0xb0, 0x6d, 0x99, 0x6b, 0x1b, 0xca, - 0xfe, 0xc0, 0xdc, 0x4d, 0xee, 0xed, 0xb1, 0x70, 0xc0, 0x0b, 0xc3, 0x71, - 0xff, 0x76, 0x9b, 0x7f, 0x86, 0x7b, 0xd5, 0xb4, 0xa1, 0x0e, 0x7e, 0x0c, - 0x3a, 0xb8, 0xa6, 0x7b, 0xef, 0xc6, 0x58, 0xf3, 0xa0, 0x99, 0x3e, 0xf9, - 0x9d, 0x6a, 0xfa, 0xf3, 0xa2, 0xcf, 0x16, 0xf5, 0xc2, 0x86, 0x9b, 0xbf, - 0xf3, 0xbd, 0x7e, 0x00, 0x5b, 0x2f, 0x94, 0x87, 0x83, 0x7e, 0xd0, 0x50, - 0x37, 0xec, 0x3d, 0x5f, 0xfb, 0xa5, 0x8f, 0x6b, 0xda, 0x22, 0x8d, 0x31, - 0xdf, 0x86, 0x76, 0x81, 0x13, 0xcf, 0xf5, 0xfe, 0xb1, 0x89, 0xd3, 0x04, - 0x9d, 0xde, 0x97, 0xc0, 0xb7, 0x43, 0xfe, 0x0e, 0xf8, 0x28, 0xa4, 0x21, - 0xc6, 0xd3, 0xb6, 0xdb, 0x7c, 0xc7, 0x36, 0x99, 0x76, 0x19, 0x77, 0x4c, - 0xf7, 0x8f, 0x08, 0xe7, 0x9d, 0x4e, 0xa6, 0x94, 0xb6, 0xab, 0xc2, 0x03, - 0x01, 0x73, 0x79, 0xb9, 0x67, 0x43, 0x7e, 0x1e, 0xbe, 0x6b, 0xc2, 0x2f, - 0x78, 0x31, 0x9b, 0xff, 0x9b, 0x2b, 0x19, 0xda, 0x1c, 0x23, 0x6d, 0xc2, - 0x9f, 0x5a, 0xe8, 0xfd, 0xbb, 0x90, 0xf6, 0x7d, 0x4a, 0x91, 0xf6, 0xbf, - 0x17, 0xce, 0xba, 0xec, 0x8b, 0x70, 0x0f, 0xdf, 0x95, 0xd3, 0xb8, 0xba, - 0x5b, 0x0e, 0x97, 0x69, 0x0b, 0xc7, 0x75, 0x7e, 0xc8, 0x68, 0x40, 0x3b, - 0x2d, 0x0e, 0x3c, 0x8e, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x6f, 0x44, 0x9d, - 0x98, 0x8c, 0x0c, 0xb7, 0x80, 0xf7, 0xc8, 0x9f, 0xbc, 0xbb, 0xa8, 0xef, - 0xc9, 0x5c, 0x69, 0x44, 0xe7, 0xef, 0x3d, 0x8e, 0xb6, 0x4f, 0xe0, 0x9a, - 0x29, 0x7d, 0x18, 0x6d, 0xde, 0xaf, 0xeb, 0xcf, 0x4c, 0x32, 0x17, 0x5a, - 0x20, 0x97, 0x3e, 0x21, 0xc5, 0xd9, 0x0e, 0x19, 0x49, 0xcc, 0x4f, 0xbb, - 0x4b, 0x71, 0x99, 0x47, 0x37, 0x70, 0xcf, 0xa4, 0x78, 0x35, 0xf7, 0x97, - 0xc5, 0x1d, 0xde, 0xad, 0xba, 0x5b, 0xb5, 0xcf, 0xd5, 0x2f, 0x43, 0xd5, - 0x8c, 0xdc, 0x54, 0x7d, 0x62, 0x8b, 0x89, 0x45, 0x2d, 0x8b, 0x6f, 0x1d, - 0xd3, 0x52, 0xe5, 0x84, 0xcb, 0xf3, 0x59, 0x32, 0x73, 0x56, 0x24, 0x76, - 0x22, 0x8a, 0x4d, 0xb2, 0xcc, 0x93, 0x8e, 0xab, 0x01, 0xd7, 0x59, 0xc8, - 0xd6, 0x44, 0x5c, 0x3e, 0xbb, 0x2b, 0x1a, 0xab, 0x10, 0x4e, 0xed, 0x2a, - 0xc8, 0x9d, 0xb8, 0xf2, 0x57, 0xa7, 0x27, 0x73, 0x8a, 0xe3, 0xfe, 0x75, - 0x48, 0x59, 0xa6, 0x32, 0xbe, 0x14, 0x5a, 0xa3, 0xb1, 0xe1, 0xdf, 0xec, - 0x89, 0xc6, 0xa7, 0xcd, 0x6d, 0xce, 0x56, 0x14, 0xb9, 0x8f, 0x03, 0xfa, - 0x8b, 0x65, 0x3e, 0xb7, 0x81, 0xbe, 0xc3, 0x80, 0xb0, 0x1d, 0x64, 0xba, - 0x62, 0xdf, 0x84, 0x93, 0xf0, 0xd7, 0xc3, 0xb9, 0x90, 0x4a, 0x00, 0x47, - 0x85, 0xd7, 0x85, 0xb7, 0xc7, 0xf3, 0xd5, 0x5a, 0xf0, 0xde, 0x6c, 0x63, - 0x89, 0x8c, 0x0f, 0xae, 0x03, 0xde, 0x5a, 0x50, 0x9e, 0x97, 0x89, 0x93, - 0xb7, 0x6e, 0xe1, 0xde, 0x78, 0x83, 0xef, 0xd8, 0x1c, 0x56, 0x9e, 0x39, - 0x9a, 0x40, 0x1d, 0xbe, 0x1f, 0x41, 0x9b, 0x74, 0x21, 0x17, 0xdb, 0x02, - 0x9f, 0x88, 0xe3, 0x86, 0xb1, 0x8e, 0x3d, 0xcd, 0x3a, 0x27, 0x55, 0xce, - 0x52, 0x9f, 0x47, 0x6d, 0x27, 0x74, 0xce, 0x07, 0xfc, 0xf6, 0xc2, 0x60, - 0x8c, 0xf2, 0xab, 0x5b, 0x06, 0xa8, 0x4f, 0xce, 0x8e, 0x68, 0xda, 0xef, - 0xdc, 0xc5, 0xf3, 0x57, 0x3d, 0xc6, 0x46, 0x4f, 0x10, 0xc6, 0x9b, 0x51, - 0x0e, 0xfb, 0xfd, 0x35, 0x61, 0x28, 0xbc, 0x49, 0x18, 0x0a, 0x6f, 0x12, - 0x06, 0xe2, 0x02, 0x70, 0x54, 0xaf, 0xd8, 0x18, 0xc5, 0xbe, 0xb7, 0x62, - 0x1e, 0x47, 0xca, 0x05, 0x39, 0x5a, 0x76, 0x74, 0xdc, 0x71, 0x5e, 0x51, - 0x26, 0x78, 0xe0, 0x49, 0xf0, 0x5e, 0x19, 0xbc, 0x59, 0x06, 0x2f, 0x96, - 0xc1, 0x97, 0xb0, 0xff, 0xcf, 0x43, 0x3e, 0x3c, 0x81, 0xb5, 0x79, 0x7c, - 0x19, 0x2f, 0x67, 0x35, 0x2f, 0x17, 0xcb, 0xf4, 0xd5, 0x7a, 0x2f, 0xc3, - 0xaf, 0xae, 0x0c, 0x94, 0xd2, 0x50, 0x25, 0x8e, 0x9b, 0xef, 0xfd, 0x28, - 0xf9, 0x55, 0x1e, 0x0c, 0x0e, 0xa2, 0xcd, 0x24, 0x68, 0x3c, 0x4d, 0x3b, - 0x90, 0xf6, 0x4f, 0x01, 0xbc, 0x79, 0x8c, 0xbe, 0x9a, 0xba, 0x7a, 0xb3, - 0x50, 0xbf, 0xb8, 0x7b, 0x98, 0xcb, 0xc8, 0xb9, 0xa6, 0x56, 0xe0, 0xc9, - 0xf0, 0xef, 0x98, 0x4f, 0x3d, 0x43, 0xbe, 0x7d, 0x96, 0x7c, 0x5b, 0xc7, - 0xab, 0x3f, 0xc5, 0xf9, 0x85, 0xde, 0xae, 0xb5, 0xda, 0xd6, 0xea, 0x6f, - 0x5e, 0xaa, 0xaf, 0xc7, 0x9f, 0x24, 0x3f, 0xaa, 0xcc, 0x24, 0x71, 0x9f, - 0xca, 0xc5, 0x76, 0x58, 0xdc, 0xc3, 0x76, 0xdb, 0x73, 0x05, 0x70, 0xdf, - 0x2e, 0x85, 0xb9, 0x50, 0xfc, 0x3d, 0x51, 0x9f, 0xb5, 0x7e, 0x3c, 0xdb, - 0xcf, 0x68, 0xc9, 0x91, 0xc1, 0x5d, 0xdc, 0xd7, 0x70, 0xa0, 0xe7, 0xa3, - 0xf5, 0x80, 0xbd, 0xaf, 0xd7, 0x9c, 0x32, 0x96, 0xb2, 0xb5, 0xc5, 0xc6, - 0x9f, 0xd8, 0xdf, 0xe4, 0x8a, 0x75, 0x7a, 0x31, 0xe4, 0xb9, 0xb6, 0x09, - 0xff, 0x60, 0x1d, 0xad, 0x3c, 0x60, 0x69, 0x45, 0xad, 0x98, 0xc7, 0x5d, - 0x96, 0x56, 0x22, 0x78, 0x13, 0x11, 0xad, 0x34, 0x45, 0xb4, 0x52, 0x98, - 0x8e, 0x68, 0x85, 0x6d, 0xef, 0x8a, 0x68, 0x25, 0x55, 0x4f, 0x2b, 0x85, - 0x69, 0x07, 0xd7, 0x4a, 0x38, 0x48, 0x2f, 0xec, 0x87, 0xf4, 0x02, 0x58, - 0xaa, 0x9f, 0x59, 0xa2, 0x97, 0x04, 0xfa, 0x39, 0x5a, 0x36, 0x39, 0x22, - 0xf0, 0xbb, 0xac, 0x0e, 0xf1, 0xb0, 0xe6, 0xc6, 0x47, 0x5c, 0x9b, 0x46, - 0x02, 0x4b, 0x23, 0xb5, 0x7c, 0xfa, 0x15, 0xb4, 0x01, 0xdc, 0x33, 0x37, - 0x76, 0xb7, 0xa6, 0x8d, 0xfb, 0x83, 0x12, 0xea, 0x0e, 0x83, 0x36, 0x22, - 0x1c, 0xbc, 0xc7, 0xe2, 0x60, 0xe5, 0x5a, 0xde, 0x66, 0x71, 0x30, 0x6c, - 0x71, 0xa0, 0xf9, 0xa5, 0xc0, 0x35, 0x53, 0x1a, 0x07, 0x4d, 0x1a, 0x07, - 0xa2, 0xa2, 0xb6, 0xb7, 0xad, 0x81, 0x03, 0xd6, 0x19, 0xd6, 0xf3, 0x8f, - 0x61, 0xfe, 0xb7, 0x63, 0xfe, 0x4a, 0xcf, 0x9f, 0xeb, 0x60, 0x72, 0xb9, - 0x8b, 0xd5, 0xbf, 0x5e, 0x9a, 0x7f, 0x2b, 0xfa, 0x38, 0x52, 0x8e, 0xe9, - 0xf9, 0xc3, 0xb6, 0xef, 0x8f, 0xe6, 0xff, 0x78, 0xd5, 0xe4, 0x53, 0x3f, - 0xbe, 0x4a, 0xcf, 0x95, 0x2c, 0x6f, 0xf8, 0xda, 0x2f, 0x66, 0x4c, 0xfb, - 0x3c, 0x74, 0xdb, 0x54, 0x90, 0xb2, 0xe7, 0xae, 0x8c, 0xbd, 0xf4, 0x95, - 0x80, 0xbc, 0xf3, 0x21, 0x9d, 0xd7, 0x72, 0x8e, 0x76, 0x53, 0xb9, 0x55, - 0x06, 0xa7, 0xea, 0xe1, 0x26, 0xbc, 0x05, 0x2d, 0x47, 0xf3, 0x98, 0xdf, - 0x68, 0xd0, 0x0d, 0xf9, 0xa6, 0x69, 0x09, 0xe5, 0xe9, 0xc2, 0x40, 0xac, - 0x49, 0xd4, 0x03, 0xef, 0xc7, 0x9c, 0x5d, 0xd9, 0xe2, 0x77, 0x7a, 0x7b, - 0x14, 0x75, 0xe1, 0x95, 0x75, 0xba, 0xb0, 0xcd, 0xea, 0xc2, 0xcd, 0xd4, - 0x85, 0x80, 0xfb, 0x6e, 0x39, 0x56, 0xe6, 0xfa, 0x15, 0x52, 0x4d, 0xd0, - 0xff, 0xdf, 0xf1, 0x79, 0xc6, 0x45, 0xc7, 0xcd, 0x92, 0xc7, 0x34, 0x2d, - 0x53, 0xa7, 0xa5, 0xf5, 0x99, 0x90, 0x05, 0xda, 0xd8, 0x09, 0xc6, 0x42, - 0xa9, 0xf7, 0xfe, 0x3e, 0xfc, 0xcc, 0x1a, 0x7a, 0x6f, 0xbc, 0x6c, 0xec, - 0xb7, 0x06, 0xd8, 0x84, 0x72, 0xaa, 0x0d, 0xd7, 0x26, 0x9e, 0x89, 0xe8, - 0xee, 0x52, 0xcd, 0xd2, 0x70, 0x6a, 0xa3, 0x8c, 0x4d, 0x19, 0x1b, 0x57, - 0x9d, 0x02, 0xfe, 0x4f, 0x31, 0x7f, 0x56, 0x74, 0xbe, 0x7f, 0x7e, 0x12, - 0x76, 0xee, 0xcc, 0xdd, 0xe6, 0x1c, 0xc8, 0x54, 0x83, 0xfe, 0x4d, 0x1b, - 0xa4, 0x18, 0x64, 0xa1, 0xef, 0xe2, 0x32, 0x86, 0x3e, 0x3b, 0x77, 0x35, - 0x62, 0xce, 0x09, 0xb4, 0xa5, 0xcf, 0xc7, 0x38, 0x5a, 0xa3, 0xb8, 0x33, - 0x49, 0x9d, 0xab, 0xcf, 0xf3, 0xae, 0xb9, 0xfe, 0x56, 0xbc, 0x63, 0x7e, - 0x84, 0x87, 0xb1, 0x22, 0xd9, 0x8f, 0x7e, 0x4f, 0x88, 0xdd, 0xef, 0xc9, - 0x68, 0xfd, 0x17, 0x3b, 0xe1, 0xd9, 0xb3, 0x7a, 0xfd, 0x58, 0xf7, 0xb5, - 0xf4, 0xa2, 0x31, 0x72, 0x73, 0x58, 0x3f, 0x75, 0xd6, 0xc5, 0xbd, 0x1d, - 0xf7, 0xa8, 0xbf, 0x48, 0x8f, 0x40, 0x37, 0xbe, 0xfd, 0xd0, 0x26, 0x69, - 0x06, 0xbe, 0x67, 0x14, 0x70, 0x6d, 0x72, 0xbc, 0x0a, 0x9a, 0x17, 0x6a, - 0xf4, 0xf0, 0xc4, 0xeb, 0xf2, 0x03, 0x69, 0x82, 0xb4, 0x40, 0xb9, 0x48, - 0xda, 0xa0, 0x4c, 0x24, 0x6d, 0x1b, 0x7a, 0x78, 0x2c, 0xf0, 0x63, 0xcc, - 0x03, 0x30, 0x71, 0x79, 0xd2, 0x06, 0x69, 0x3e, 0xa5, 0xe3, 0xf5, 0x59, - 0xf9, 0x96, 0x64, 0x5b, 0x3b, 0x61, 0x97, 0xfd, 0xdb, 0xae, 0xb1, 0x39, - 0x2b, 0xac, 0x69, 0x0e, 0xba, 0x89, 0x39, 0x79, 0xdd, 0xf2, 0x9e, 0x6a, - 0x01, 0x78, 0xb8, 0x17, 0x4a, 0xf9, 0x6e, 0x9d, 0xe7, 0xb8, 0xaf, 0xb4, - 0x49, 0x6e, 0x09, 0xe2, 0x36, 0xee, 0x7e, 0x04, 0x74, 0xb0, 0xe0, 0xc8, - 0xa9, 0x0b, 0xb8, 0x2e, 0x3a, 0x5c, 0xbf, 0x4b, 0x41, 0x36, 0xad, 0xc8, - 0xec, 0xbe, 0x9b, 0x5c, 0x90, 0x1e, 0x6f, 0x4c, 0x18, 0xeb, 0x98, 0x77, - 0x9a, 0x4e, 0xfd, 0xfe, 0x26, 0xe3, 0x4b, 0x03, 0x16, 0xbf, 0xd1, 0x1b, - 0xa4, 0x2d, 0x17, 0x84, 0x61, 0x9e, 0x76, 0x83, 0x28, 0xed, 0x23, 0xc1, - 0xe7, 0x43, 0x19, 0xe3, 0x13, 0x3b, 0x9d, 0xc6, 0xb3, 0x2f, 0x58, 0x5a, - 0x91, 0x98, 0xca, 0x3c, 0xed, 0x34, 0x9c, 0x7a, 0x84, 0x6b, 0xa6, 0xf3, - 0xae, 0x0d, 0x5d, 0x3d, 0xeb, 0xd4, 0xe8, 0xea, 0x2b, 0xf6, 0xb7, 0xca, - 0x34, 0x49, 0x36, 0xdd, 0x84, 0xf9, 0x0e, 0x94, 0x22, 0x18, 0xbf, 0x0d, - 0xb8, 0x08, 0x0f, 0xe8, 0x76, 0xe6, 0x7f, 0xe2, 0x5a, 0x04, 0x2c, 0xf7, - 0x01, 0xee, 0x4b, 0x80, 0xf9, 0x45, 0x5c, 0x6a, 0x5b, 0x4c, 0xfe, 0xd4, - 0x89, 0xcd, 0xd4, 0xc3, 0x4b, 0x18, 0xbf, 0x6b, 0xe1, 0x7d, 0x2d, 0x58, - 0x3d, 0x59, 0xe8, 0xeb, 0x00, 0x3c, 0x84, 0xf3, 0x25, 0xc0, 0x48, 0xbb, - 0xf5, 0x39, 0x3c, 0x7b, 0x80, 0xef, 0x79, 0x0b, 0x13, 0xe8, 0x71, 0xea, - 0x2f, 0x6a, 0xbf, 0x4b, 0xb4, 0xa3, 0xff, 0xd2, 0x3e, 0xb7, 0xaf, 0x90, - 0x01, 0x5d, 0x0e, 0xf1, 0x3c, 0x51, 0x5e, 0xa4, 0x1d, 0x00, 0xbe, 0xff, - 0xae, 0xc4, 0xce, 0x26, 0xe5, 0x68, 0x89, 0x7b, 0x40, 0xa7, 0x81, 0x0f, - 0x7d, 0xc6, 0x05, 0x75, 0xae, 0xc2, 0x05, 0x65, 0x3f, 0xb3, 0x1b, 0x57, - 0x37, 0xae, 0xb7, 0xe2, 0x02, 0x39, 0xcc, 0x9c, 0xc2, 0xd5, 0x83, 0xbe, - 0x55, 0xa2, 0x49, 0x98, 0x9b, 0xf5, 0x0d, 0xb4, 0xd1, 0xb6, 0x65, 0x41, - 0x65, 0xfa, 0x80, 0xbf, 0x3e, 0xc0, 0x96, 0xc4, 0xc5, 0x7c, 0xe6, 0xef, - 0x3a, 0x72, 0xf6, 0x65, 0x5c, 0x60, 0xb0, 0xb3, 0x20, 0xcc, 0xb3, 0xfd, - 0xb8, 0xa0, 0xc4, 0xce, 0x66, 0x71, 0x0d, 0xe2, 0xfa, 0x2b, 0xc7, 0xf0, - 0x5c, 0x3b, 0xf0, 0x15, 0xf1, 0x08, 0x70, 0xbe, 0x8c, 0xe7, 0xbe, 0xec, - 0xbc, 0x71, 0x9e, 0xfb, 0xbe, 0x63, 0x78, 0xee, 0x15, 0xa7, 0xc6, 0x73, - 0x17, 0x1c, 0xf5, 0xf0, 0xd3, 0x4e, 0xec, 0x61, 0xfa, 0x12, 0x17, 0x1c, - 0xc3, 0xff, 0x31, 0x19, 0x38, 0x08, 0x5a, 0x7a, 0x78, 0x1e, 0x17, 0xe9, - 0xea, 0x19, 0x94, 0x3f, 0xbf, 0x62, 0xdc, 0xe7, 0xde, 0xc4, 0xb8, 0xaf, - 0xda, 0x71, 0x45, 0xd5, 0xc6, 0x7d, 0x11, 0x7d, 0xbf, 0x64, 0xc7, 0x7d, - 0xb1, 0x6e, 0x5c, 0xd0, 0xca, 0xc3, 0x8b, 0xb8, 0x48, 0x17, 0x2f, 0xa0, - 0x3c, 0x92, 0x09, 0x1f, 0xf4, 0xa4, 0xb9, 0x01, 0xbc, 0x1b, 0x87, 0x7e, - 0x6c, 0x58, 0xd2, 0x8d, 0xd9, 0x3a, 0xfd, 0xf0, 0x46, 0xf4, 0xe3, 0x78, - 0x99, 0x36, 0xe2, 0x7c, 0x9d, 0x5c, 0xa0, 0x6f, 0x14, 0xca, 0x49, 0xed, - 0x07, 0xd1, 0x27, 0xa2, 0x7f, 0xb4, 0xd2, 0xb6, 0xfa, 0xa8, 0xce, 0x45, - 0xfb, 0x95, 0x52, 0xbb, 0xdc, 0x59, 0xa2, 0x4d, 0x48, 0x7a, 0x09, 0xc3, - 0xb1, 0x3d, 0xb4, 0x4f, 0x0b, 0xe1, 0x15, 0x3e, 0xe9, 0xc4, 0xf7, 0x7e, - 0x79, 0xb5, 0xce, 0x98, 0x1c, 0x80, 0xef, 0x9e, 0x3b, 0xf1, 0x8b, 0xd0, - 0x19, 0x0d, 0x80, 0x9b, 0xf4, 0xb6, 0x4d, 0x0e, 0x4c, 0xaa, 0x89, 0x2d, - 0x90, 0x25, 0x37, 0x95, 0x1a, 0x61, 0xf7, 0x30, 0x4f, 0xab, 0x59, 0x3a, - 0xf7, 0xc4, 0x4d, 0x1e, 0xb9, 0x97, 0xc0, 0x6f, 0xcf, 0xe4, 0xb5, 0x27, - 0x92, 0x78, 0xff, 0x0f, 0x1e, 0xe5, 0x60, 0xc2, 0xbf, 0x4e, 0xe7, 0x08, - 0x75, 0xec, 0xa1, 0xdd, 0x72, 0x83, 0xd6, 0xe1, 0xee, 0x2a, 0x3b, 0x49, - 0x6d, 0xf3, 0xa4, 0x66, 0xa3, 0x8d, 0x96, 0xd2, 0x29, 0xc2, 0xf5, 0x90, - 0x70, 0xff, 0xeb, 0x1e, 0x29, 0x06, 0x1b, 0xe1, 0x17, 0x30, 0x76, 0x9e, - 0xee, 0xa6, 0x6d, 0x34, 0x33, 0xe5, 0xd9, 0x3c, 0xeb, 0x4d, 0xf2, 0xac, - 0x1e, 0xa7, 0x51, 0xc3, 0x68, 0xce, 0x5e, 0x70, 0x1f, 0x21, 0xae, 0xcf, - 0xfb, 0xcc, 0x54, 0x5a, 0xb4, 0xde, 0x99, 0xa9, 0x30, 0xaf, 0x1f, 0xfe, - 0x54, 0x85, 0x79, 0xfc, 0x81, 0x78, 0x6f, 0x87, 0x9f, 0x5b, 0xd9, 0x21, - 0xa3, 0x53, 0xeb, 0xa4, 0xd1, 0x57, 0x89, 0x2d, 0xd0, 0x1f, 0x6c, 0xd3, - 0xb1, 0x07, 0xfe, 0xe1, 0xf4, 0x4e, 0x79, 0x62, 0x9a, 0x7d, 0x6f, 0x93, - 0xd9, 0x39, 0x71, 0xbc, 0xb7, 0xaf, 0x47, 0x1d, 0xc8, 0xf5, 0x3d, 0x2c, - 0x4b, 0xe1, 0x2e, 0xca, 0x7b, 0xbb, 0x2b, 0x17, 0xfb, 0xf8, 0xcc, 0xb3, - 0x04, 0xe2, 0xb2, 0xbf, 0x8b, 0x7d, 0xed, 0x72, 0x6e, 0x0e, 0x34, 0x01, - 0xb9, 0x3f, 0x78, 0x8a, 0x30, 0x89, 0xec, 0x9d, 0x61, 0x2c, 0xbd, 0xd3, - 0x63, 0xdc, 0x94, 0xfb, 0x34, 0xb7, 0xf4, 0x71, 0x2c, 0xe8, 0x25, 0xe8, - 0xb8, 0x8e, 0x3d, 0x46, 0x16, 0x64, 0x67, 0x1a, 0x50, 0xce, 0x7e, 0xe1, - 0x3f, 0x1e, 0x64, 0x3f, 0x51, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59, - 0x5c, 0xa1, 0x3f, 0xce, 0xff, 0x48, 0xf6, 0x37, 0xfb, 0xe8, 0xd6, 0x7b, - 0x21, 0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae, - 0xba, 0x4a, 0xdb, 0x17, 0xb3, 0x55, 0xae, 0x20, 0x63, 0x51, 0xd1, 0x1a, - 0x25, 0xe5, 0xd1, 0xf2, 0xd2, 0x3a, 0xed, 0x68, 0x58, 0xbe, 0x4e, 0xa4, - 0x95, 0x60, 0xc4, 0xda, 0x1e, 0x0b, 0x72, 0x0c, 0x76, 0x59, 0xb7, 0x5e, - 0xb3, 0x05, 0xd8, 0xb2, 0x76, 0xcd, 0xb4, 0x3d, 0x5b, 0x8c, 0xd6, 0x6c, - 0x18, 0x1a, 0xa7, 0x92, 0xd9, 0xcc, 0x35, 0xf3, 0x18, 0xef, 0x06, 0xde, - 0x0b, 0x58, 0xa7, 0x02, 0xd6, 0xa8, 0x50, 0xd9, 0x26, 0x33, 0x27, 0x55, - 0x7b, 0x83, 0x48, 0x6a, 0xd4, 0xdf, 0x26, 0xe3, 0x73, 0x8c, 0x25, 0xec, - 0x80, 0x0d, 0xb6, 0x13, 0x57, 0x3b, 0x9e, 0xd9, 0x2e, 0x21, 0xc5, 0x8a, - 0x42, 0xdb, 0xa6, 0x55, 0x76, 0xd6, 0x39, 0x8c, 0xcd, 0x33, 0x9d, 0x8f, - 0x01, 0x0f, 0x35, 0xde, 0x29, 0xd5, 0xc5, 0x9f, 0x38, 0x57, 0xad, 0x43, - 0x31, 0xdf, 0x84, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x37, 0xbe, 0x19, 0x7b, - 0x2a, 0x49, 0x7b, 0x2a, 0x3f, 0xe9, 0x99, 0xf3, 0x06, 0xc3, 0xf0, 0x9d, - 0xfc, 0xfc, 0x66, 0xd2, 0xfa, 0xc8, 0x34, 0xe1, 0x8a, 0x47, 0x70, 0x2d, - 0x5b, 0x33, 0x9e, 0x0f, 0x5b, 0x1d, 0xe7, 0x28, 0x2d, 0xe5, 0x43, 0x9a, - 0xd8, 0x3e, 0xe3, 0x28, 0xed, 0x6b, 0xc0, 0x74, 0xb7, 0xb6, 0x61, 0x45, - 0xdd, 0x26, 0x87, 0xcb, 0x3c, 0x5b, 0xc6, 0x78, 0xe2, 0x27, 0x19, 0x5f, - 0xea, 0x9e, 0x91, 0x63, 0x18, 0x9b, 0xb9, 0x3f, 0xca, 0xc6, 0x6f, 0x36, - 0xd8, 0x1c, 0x91, 0xfa, 0x18, 0x8e, 0xc9, 0x0d, 0x5a, 0x9e, 0x67, 0x9d, - 0x1e, 0x5e, 0xc4, 0x3a, 0xff, 0x9a, 0xde, 0x1b, 0x94, 0xc9, 0x18, 0xb4, - 0xdf, 0x68, 0x5f, 0xba, 0xdf, 0x9c, 0xab, 0x49, 0xc9, 0x50, 0xd9, 0xcc, - 0xff, 0x92, 0xce, 0x11, 0x32, 0xb9, 0x90, 0x26, 0x7f, 0xe8, 0x1e, 0xb9, - 0x04, 0x1d, 0x5e, 0x5b, 0xdb, 0x26, 0x19, 0x07, 0x2e, 0xf2, 0x7a, 0x5f, - 0x22, 0x25, 0xf9, 0xbe, 0x47, 0x37, 0xf3, 0xdc, 0x45, 0x1c, 0xeb, 0x53, - 0x9c, 0xe6, 0x59, 0x4c, 0xf6, 0x7b, 0xb9, 0xbe, 0x28, 0x66, 0x99, 0xd7, - 0x0f, 0x59, 0xf9, 0x63, 0x3d, 0xc9, 0x66, 0xfd, 0x7e, 0x9d, 0xcd, 0xdf, - 0x76, 0x44, 0x0e, 0x84, 0xf2, 0x87, 0xd0, 0x93, 0x67, 0xec, 0x9c, 0x52, - 0x3a, 0x66, 0x25, 0xe1, 0xc5, 0x20, 0x69, 0x63, 0x96, 0x9c, 0xcb, 0x41, - 0x4b, 0xdf, 0xc6, 0xfe, 0xa9, 0xd9, 0xd0, 0x66, 0xdf, 0xef, 0x09, 0x2d, - 0x0b, 0x7b, 0xad, 0xed, 0xac, 0xe3, 0x3c, 0x8f, 0x88, 0xce, 0x09, 0x88, - 0x7c, 0xa3, 0xae, 0x3a, 0xbf, 0xc0, 0xf8, 0x72, 0xc5, 0xa9, 0xb5, 0x64, - 0x54, 0xcd, 0x27, 0xa4, 0x2f, 0x37, 0xb6, 0x8b, 0xdf, 0x47, 0x88, 0x7c, - 0xb9, 0x5e, 0xeb, 0xcb, 0x6d, 0xd4, 0xbe, 0x9c, 0x89, 0x3d, 0x6c, 0x5c, - 0xf2, 0xe5, 0x8a, 0x53, 0x05, 0xd0, 0x4a, 0xf4, 0x3d, 0x07, 0x63, 0x0b, - 0x8d, 0x97, 0x78, 0x86, 0xa6, 0x51, 0xf2, 0xc3, 0x0a, 0x7e, 0x83, 0xf1, - 0xb1, 0x18, 0xab, 0x50, 0xea, 0xeb, 0xd6, 0xbf, 0x68, 0x97, 0x6c, 0xdb, - 0x3a, 0xcc, 0xfb, 0x6e, 0xbd, 0xe6, 0xb3, 0x25, 0xb3, 0xf7, 0x99, 0x3f, - 0xc8, 0x98, 0x10, 0xcf, 0x49, 0x69, 0xfe, 0x4a, 0x0d, 0xc4, 0xba, 0x8d, - 0x3d, 0xeb, 0x7b, 0xad, 0xd2, 0x7c, 0x1a, 0x38, 0x8f, 0xdb, 0x71, 0x53, - 0x80, 0xe9, 0x30, 0xd6, 0xe6, 0x3a, 0x2b, 0x93, 0x39, 0xf6, 0x47, 0x9b, - 0x18, 0x1b, 0x98, 0x2b, 0x45, 0x31, 0xc2, 0x98, 0x3d, 0xa3, 0xe9, 0xc7, - 0x1a, 0xfd, 0x75, 0x6b, 0xda, 0xaa, 0x8f, 0xbf, 0xae, 0x6e, 0x22, 0x2d, - 0xdd, 0xad, 0xf3, 0x5c, 0xd6, 0xf7, 0xa5, 0xf7, 0xeb, 0x9c, 0x7b, 0x1d, - 0x63, 0x2c, 0x08, 0x73, 0xd4, 0xbe, 0x29, 0x3f, 0xa1, 0x65, 0xfe, 0xe1, - 0x80, 0xfa, 0x6b, 0x8f, 0xfe, 0xdd, 0x98, 0x09, 0xc3, 0x8b, 0x7d, 0x13, - 0x8c, 0x29, 0x7a, 0xdf, 0x96, 0xce, 0xe4, 0x80, 0xb6, 0x9d, 0xb0, 0x46, - 0x07, 0x9b, 0x65, 0x9d, 0x3f, 0x62, 0x73, 0x66, 0x0a, 0x90, 0x9b, 0x69, - 0xd8, 0x4c, 0x3c, 0x7f, 0xdc, 0x65, 0xdf, 0x15, 0xc2, 0x66, 0xd0, 0xd1, - 0x07, 0xc5, 0xc8, 0x98, 0x7c, 0x4d, 0xc6, 0x30, 0xd7, 0x20, 0x4b, 0x42, - 0x76, 0x8f, 0x4b, 0x9a, 0xdf, 0x2a, 0xe1, 0xd8, 0x45, 0xd9, 0x0a, 0xbd, - 0xcc, 0x76, 0xb4, 0x55, 0xf9, 0xcc, 0x3d, 0x1c, 0xdf, 0x3b, 0x02, 0xdd, - 0x72, 0xc3, 0x6a, 0xdd, 0x92, 0xa4, 0x5f, 0x9f, 0x9f, 0xa4, 0x6f, 0xb8, - 0x1e, 0x6d, 0xb6, 0xc9, 0x87, 0xa6, 0x7e, 0xbe, 0x95, 0xbc, 0x35, 0x02, - 0xb9, 0xae, 0xee, 0x8f, 0xce, 0x16, 0xb1, 0x8c, 0xef, 0xd9, 0x6f, 0x93, - 0xa4, 0xde, 0xeb, 0xc9, 0x6f, 0x54, 0xd3, 0xa9, 0x45, 0xe8, 0xa6, 0x11, - 0xe7, 0x57, 0xb7, 0x9b, 0x98, 0xea, 0x07, 0x5a, 0xcd, 0x59, 0x84, 0x66, - 0xe0, 0x34, 0x8a, 0xb3, 0xd6, 0xd3, 0xec, 0xa2, 0x95, 0xc7, 0x61, 0xd8, - 0xdc, 0xa7, 0x65, 0xf0, 0x7e, 0xca, 0xe0, 0xc3, 0x41, 0x97, 0xa1, 0x7d, - 0xed, 0x33, 0x85, 0x58, 0x47, 0xe0, 0xa1, 0xcf, 0x65, 0xbe, 0x9f, 0xe5, - 0x4f, 0x3f, 0xbb, 0x60, 0xe5, 0x92, 0x72, 0x56, 0xf3, 0xa5, 0xba, 0x26, - 0xbe, 0x4c, 0xe6, 0x1e, 0x9d, 0xa2, 0x3e, 0x0e, 0xe6, 0xbf, 0x09, 0x39, - 0x95, 0xd7, 0x78, 0xd8, 0x26, 0xf7, 0x4d, 0x49, 0xf6, 0x12, 0x74, 0x55, - 0x71, 0x6e, 0x39, 0x6f, 0xae, 0xee, 0x8f, 0x73, 0x7d, 0xa4, 0xd5, 0xf8, - 0xb6, 0xcb, 0xe7, 0x3a, 0x8f, 0xb9, 0x66, 0xf5, 0x5c, 0xb9, 0x6f, 0x33, - 0x67, 0xe7, 0xba, 0x3e, 0x9a, 0x6b, 0xff, 0xf2, 0xb9, 0x46, 0xbe, 0x7d, - 0x24, 0x77, 0x53, 0x3a, 0xff, 0x5e, 0xe7, 0x7d, 0x4f, 0xad, 0x97, 0x81, - 0xc9, 0x8d, 0x56, 0x5e, 0x7a, 0xd0, 0x3d, 0xcc, 0x89, 0x9f, 0xbf, 0xd7, - 0x13, 0x8b, 0x33, 0x45, 0x3c, 0x50, 0xd6, 0xb6, 0xea, 0x33, 0x3b, 0x33, - 0xf0, 0xaf, 0x6e, 0x2d, 0xb1, 0x6e, 0xf4, 0xfe, 0x72, 0xb1, 0xe3, 0xc8, - 0xa7, 0xa6, 0xdf, 0xd4, 0xbd, 0x2a, 0xa6, 0x60, 0xe2, 0xc3, 0x8c, 0x0b, - 0x9b, 0xb3, 0xc4, 0xcc, 0x45, 0xbc, 0x03, 0x3c, 0xf5, 0xf1, 0x52, 0xba, - 0x3f, 0x17, 0xa3, 0x1c, 0x9d, 0x96, 0xa3, 0xd5, 0x41, 0xe9, 0xd0, 0xe7, - 0x49, 0x5f, 0x37, 0x76, 0x9c, 0xad, 0x8f, 0x1d, 0x33, 0x9d, 0x80, 0xb1, - 0xe3, 0xfd, 0x3f, 0x42, 0xec, 0x58, 0x1c, 0x13, 0x3b, 0x5e, 0xcb, 0xbf, - 0x9a, 0x28, 0x4f, 0x63, 0x5e, 0xcd, 0x90, 0x25, 0x0b, 0x4e, 0x7e, 0xae, - 0x05, 0xf7, 0x0b, 0xb8, 0xc7, 0x71, 0xbf, 0x84, 0xbb, 0x87, 0xfb, 0x8b, - 0xb8, 0x27, 0x64, 0x62, 0x49, 0x67, 0x4c, 0x43, 0x6e, 0x50, 0x97, 0xb1, - 0xad, 0xf1, 0x07, 0x66, 0x2b, 0x6d, 0xfc, 0x2e, 0x8c, 0x33, 0x33, 0xc7, - 0x39, 0x6c, 0x94, 0xf1, 0x29, 0xca, 0xec, 0x56, 0x99, 0x9c, 0x8a, 0x6c, - 0xdb, 0xbb, 0xb6, 0x71, 0xcf, 0x60, 0x44, 0x22, 0xdb, 0xf5, 0x77, 0xb7, - 0xd9, 0x5c, 0xfb, 0x2d, 0xd2, 0xbc, 0x09, 0x6b, 0x70, 0x5a, 0x2e, 0x4d, - 0x6f, 0x5a, 0x66, 0xc3, 0xa6, 0x6c, 0x4c, 0x70, 0xda, 0xea, 0xde, 0xb5, - 0x65, 0x44, 0xfd, 0xfa, 0x27, 0x6d, 0x4e, 0x69, 0x94, 0x23, 0x94, 0xd2, - 0xeb, 0x33, 0x5c, 0x9d, 0xc6, 0x78, 0xfd, 0x92, 0x9d, 0xe6, 0x3c, 0x97, - 0xbe, 0x4d, 0x01, 0x79, 0x78, 0x0a, 0x7a, 0x75, 0x19, 0x5d, 0x82, 0x6e, - 0x39, 0x37, 0x07, 0xb4, 0xfb, 0xa8, 0xcc, 0x4c, 0x12, 0xbe, 0xae, 0x64, - 0x4c, 0x9f, 0x5d, 0xc3, 0xf3, 0xb4, 0xc9, 0x99, 0x1f, 0xa8, 0x46, 0xe7, - 0xd6, 0x36, 0xeb, 0xef, 0x11, 0x2c, 0x3f, 0xbb, 0x66, 0xf5, 0xb3, 0xb6, - 0x1d, 0x78, 0x86, 0x2d, 0x9a, 0xc3, 0x5a, 0xf4, 0x14, 0xca, 0xb8, 0xce, - 0x3b, 0xdb, 0x22, 0x67, 0x1e, 0x5c, 0xca, 0xa1, 0x6d, 0x85, 0x8d, 0xd2, - 0x0e, 0x13, 0x79, 0xd8, 0xcd, 0x74, 0xc1, 0xc7, 0x63, 0x9e, 0x4c, 0x57, - 0xf2, 0x36, 0x9d, 0xdb, 0x5c, 0x3b, 0x47, 0x58, 0xcb, 0x6f, 0x8e, 0xce, - 0x6d, 0x25, 0x65, 0x10, 0x74, 0x38, 0xa4, 0xcb, 0x13, 0x98, 0x0f, 0xf7, - 0xfd, 0x34, 0x1e, 0x20, 0x7b, 0xb8, 0xe7, 0x87, 0xb9, 0x57, 0xbf, 0x01, - 0x7a, 0x77, 0xec, 0x19, 0x36, 0xd2, 0x58, 0x9f, 0x8c, 0x55, 0x92, 0xce, - 0x58, 0xa5, 0xcf, 0x39, 0x54, 0xb1, 0xef, 0xfa, 0x8a, 0x58, 0x0f, 0xfc, - 0x9e, 0xee, 0x70, 0x46, 0x80, 0xaf, 0x62, 0xb9, 0xd3, 0xc9, 0xea, 0xbb, - 0x6f, 0xef, 0x90, 0x03, 0x58, 0xab, 0x81, 0xe9, 0xa4, 0x96, 0xf3, 0xb5, - 0xef, 0x61, 0x45, 0xeb, 0xfa, 0xa4, 0xde, 0x1b, 0x9a, 0x97, 0x69, 0xfd, - 0x7d, 0x25, 0x63, 0x3b, 0x9c, 0x46, 0x7f, 0xd3, 0x36, 0x26, 0xde, 0xe3, - 0xe4, 0x75, 0x3f, 0x66, 0x3d, 0x8a, 0xe5, 0x53, 0xb8, 0xaf, 0x3c, 0x43, - 0x1d, 0xe9, 0x19, 0xc2, 0xfd, 0x08, 0xf4, 0x59, 0x78, 0x8f, 0x91, 0x57, - 0xd3, 0x32, 0x51, 0x65, 0xfe, 0x08, 0xfb, 0x41, 0x79, 0xe5, 0x30, 0x74, - 0xd2, 0xf2, 0x33, 0x84, 0x43, 0xb5, 0x75, 0x48, 0x4d, 0x0b, 0x61, 0xe1, - 0x1a, 0x2c, 0x3f, 0x5f, 0x7f, 0xf9, 0x7f, 0xd1, 0xbe, 0xa2, 0x91, 0xa1, - 0x16, 0x8e, 0x2c, 0xe5, 0x9d, 0x91, 0x2b, 0x9f, 0x96, 0x23, 0xc0, 0xe3, - 0x31, 0xc0, 0xa4, 0xee, 0xe7, 0xf7, 0x5e, 0x2a, 0x52, 0x9c, 0xbd, 0x4f, - 0xd4, 0x43, 0x97, 0x1c, 0xf7, 0xa1, 0x23, 0x12, 0x7b, 0x68, 0xc1, 0x69, - 0x78, 0xa8, 0x53, 0xfb, 0xe5, 0xfb, 0x82, 0xce, 0xe4, 0x21, 0x39, 0x2d, - 0xee, 0xfd, 0x4a, 0x9f, 0x27, 0x2b, 0x7a, 0x8c, 0xf1, 0x9d, 0x96, 0xd8, - 0xfd, 0x71, 0x7b, 0x16, 0xd5, 0xc4, 0xf5, 0x16, 0x35, 0xdf, 0x3f, 0x97, - 0x20, 0xce, 0x16, 0x65, 0x5a, 0xf3, 0xce, 0x00, 0xf4, 0x44, 0x6e, 0x32, - 0xb5, 0x54, 0xc7, 0xe4, 0x7b, 0x6e, 0x4c, 0x18, 0x7e, 0x61, 0x9d, 0x2e, - 0x87, 0xdf, 0x85, 0xb0, 0x3a, 0xff, 0xca, 0x28, 0xf7, 0xd3, 0xac, 0x29, - 0xdf, 0xff, 0x10, 0x6b, 0xd8, 0x85, 0xf5, 0xe2, 0x78, 0x8e, 0xde, 0xcf, - 0xe5, 0x59, 0x5c, 0x4f, 0x7a, 0x92, 0x4d, 0x4b, 0x76, 0x10, 0xeb, 0xde, - 0x27, 0x4d, 0x80, 0x5b, 0x3d, 0x54, 0x34, 0x76, 0x9d, 0x90, 0x4e, 0x05, - 0x92, 0x9b, 0x34, 0xdb, 0xd5, 0xbf, 0x4f, 0xaf, 0xe1, 0xbd, 0x96, 0x66, - 0xd6, 0x19, 0xfb, 0x11, 0xcf, 0x86, 0x2e, 0x8a, 0xb2, 0x77, 0xea, 0xbb, - 0xd0, 0xf3, 0xdc, 0x77, 0xd1, 0xf6, 0xe2, 0x1a, 0xb6, 0x20, 0x79, 0xe9, - 0x69, 0xeb, 0x57, 0x86, 0xe1, 0x54, 0x10, 0x00, 0x8f, 0x6b, 0xf9, 0x92, - 0x3b, 0x9c, 0xd9, 0xc9, 0x9d, 0xce, 0xcc, 0x64, 0x28, 0x63, 0x01, 0xbf, - 0x19, 0xc2, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x84, 0x6e, 0xdd, 0x9d, - 0xe0, 0xf9, 0xa6, 0x9b, 0xfc, 0x17, 0xc4, 0xd4, 0x23, 0x8e, 0xe9, 0x23, - 0x77, 0x3e, 0x92, 0x17, 0x7e, 0x9f, 0xa3, 0x27, 0x99, 0xd0, 0xdf, 0x10, - 0xf9, 0x0c, 0xda, 0x61, 0x8c, 0x32, 0xc7, 0x7d, 0xc6, 0x99, 0x81, 0x3c, - 0x9b, 0x9d, 0xe2, 0x37, 0x01, 0x98, 0x4f, 0x1b, 0x6b, 0x57, 0x72, 0x95, - 0x37, 0x6e, 0xbf, 0x5b, 0x57, 0x80, 0x0b, 0x14, 0xd3, 0x65, 0x3d, 0xde, - 0xe8, 0xd2, 0xb7, 0xec, 0xa2, 0xb2, 0xe8, 0x9b, 0x76, 0x4a, 0xe7, 0x4e, - 0xc3, 0x97, 0x3d, 0x33, 0x22, 0xdf, 0x77, 0xe6, 0x4a, 0xaf, 0x38, 0x8f, - 0x96, 0xb2, 0xd7, 0x5c, 0x01, 0xfa, 0xb8, 0x18, 0xe4, 0x29, 0xbf, 0x60, - 0xf3, 0x4d, 0x49, 0xa1, 0x3a, 0x26, 0xd3, 0xdb, 0x3a, 0xbd, 0xfb, 0xf5, - 0xda, 0x9c, 0x01, 0xce, 0xbe, 0x81, 0xf5, 0x3b, 0x93, 0xa0, 0x7e, 0x1b, - 0x2d, 0x29, 0xf0, 0xb2, 0xfa, 0x69, 0x5c, 0xb0, 0x6d, 0x1b, 0xb5, 0x8d, - 0x72, 0x28, 0x60, 0xbd, 0x9d, 0xce, 0xc0, 0xe4, 0x0e, 0xac, 0xe3, 0x41, - 0xe8, 0x4f, 0x07, 0x76, 0x1a, 0x68, 0x1b, 0x65, 0xe3, 0xc0, 0xc1, 0x68, - 0x60, 0xe4, 0xf9, 0x80, 0x14, 0xb4, 0x8f, 0x67, 0xee, 0x59, 0x65, 0x62, - 0x66, 0x61, 0x38, 0x0b, 0xfb, 0x80, 0xdf, 0xc5, 0x9a, 0xa8, 0xce, 0xe1, - 0xfa, 0x71, 0xbb, 0xa7, 0x3d, 0x7f, 0x99, 0x3d, 0x6d, 0x4f, 0x4e, 0x57, - 0xf5, 0x39, 0x79, 0x9d, 0x5f, 0x95, 0x52, 0xeb, 0xda, 0xf4, 0x5a, 0xa9, - 0x2e, 0x9d, 0x93, 0x96, 0x95, 0x47, 0x12, 0x46, 0x0f, 0x13, 0xa6, 0x14, - 0xe0, 0xd9, 0x09, 0x5c, 0x10, 0x1e, 0xd3, 0x46, 0xd4, 0x3b, 0xb7, 0x52, - 0x1f, 0x2e, 0xca, 0xa7, 0x12, 0xd1, 0x19, 0x05, 0xf4, 0x03, 0x19, 0x37, - 0xb7, 0xd5, 0xe8, 0xc9, 0x2d, 0x6b, 0xf4, 0x13, 0xcd, 0xcd, 0xb1, 0x73, - 0x23, 0xdd, 0x6e, 0xbe, 0x92, 0x3e, 0xc5, 0xa2, 0x34, 0xad, 0xa8, 0xcf, - 0x98, 0xfe, 0xbe, 0xed, 0xe6, 0xcc, 0x03, 0xeb, 0x7a, 0xb0, 0x4d, 0x69, - 0xe7, 0x12, 0x8f, 0x7a, 0xdd, 0x4a, 0x4a, 0x78, 0x6e, 0xe1, 0x0c, 0x64, - 0xcb, 0x55, 0xde, 0x4f, 0x28, 0xd2, 0x61, 0x84, 0xeb, 0x6f, 0x68, 0x3e, - 0x19, 0x2d, 0x31, 0xb6, 0xf2, 0x68, 0x98, 0x1d, 0x26, 0x8f, 0xb1, 0x0f, - 0xbe, 0x9f, 0xd2, 0xf1, 0xdc, 0x83, 0x01, 0x63, 0x45, 0x9d, 0x8f, 0xdc, - 0xa1, 0x22, 0x39, 0x05, 0xfd, 0x5b, 0x5e, 0x70, 0xf8, 0xdd, 0xbe, 0x03, - 0x82, 0xfb, 0xdc, 0x82, 0xf3, 0xcd, 0xa9, 0x67, 0xf0, 0xdc, 0x60, 0xbf, - 0xd5, 0x67, 0xf4, 0x94, 0xc8, 0x1f, 0x46, 0xf3, 0x4d, 0x16, 0xb0, 0xf6, - 0x2f, 0x62, 0xed, 0xd7, 0xfe, 0x36, 0x1f, 0xde, 0x55, 0xf0, 0xae, 0xf2, - 0x0b, 0x61, 0xb6, 0x95, 0xb4, 0x18, 0xe8, 0xb3, 0xa9, 0x97, 0xf7, 0x9b, - 0xfb, 0x35, 0x5f, 0x8c, 0x97, 0xcf, 0x81, 0x2f, 0xb2, 0xdc, 0x6f, 0x0e, - 0x1f, 0x0e, 0x6e, 0x04, 0x5f, 0xec, 0x97, 0xdf, 0x83, 0x5d, 0xf0, 0x3b, - 0xd5, 0x0c, 0xf8, 0xa3, 0x1f, 0xfc, 0xd2, 0x07, 0x1e, 0x09, 0xb4, 0x8d, - 0xfc, 0x18, 0xf4, 0x1f, 0xf4, 0x9a, 0x73, 0x68, 0xb2, 0xc3, 0xc9, 0x4f, - 0xfa, 0xce, 0xd8, 0x24, 0xbf, 0xff, 0xa2, 0xde, 0xda, 0x20, 0x6e, 0x72, - 0x56, 0xc8, 0x0b, 0x9d, 0xcc, 0x71, 0x6c, 0x03, 0xae, 0xce, 0x12, 0x57, - 0xb3, 0xd5, 0x1e, 0xef, 0x0a, 0xf0, 0x44, 0x9b, 0xe6, 0x89, 0x8d, 0x4e, - 0xd6, 0xbb, 0xd1, 0xf2, 0xc4, 0x0b, 0xe0, 0x89, 0x4b, 0xab, 0x78, 0xe2, - 0x29, 0x4b, 0xff, 0xf3, 0x75, 0x3c, 0x31, 0x6b, 0xcb, 0xa6, 0x2f, 0xc3, - 0x13, 0x5b, 0xfd, 0xf4, 0xe7, 0x47, 0xe4, 0x55, 0xf0, 0x84, 0x28, 0xf2, - 0xc4, 0x56, 0xcd, 0x13, 0x8c, 0x1d, 0x91, 0x2f, 0xda, 0x21, 0x47, 0xc8, - 0x17, 0x17, 0x64, 0x11, 0x7c, 0xf1, 0x9c, 0xe2, 0xd8, 0x67, 0x68, 0x2b, - 0x4c, 0xd2, 0x27, 0x3b, 0x55, 0xee, 0x00, 0xbf, 0x2b, 0xf9, 0xaf, 0x53, - 0x61, 0xb8, 0x00, 0x3f, 0xfd, 0x41, 0xd8, 0xf3, 0xae, 0xfe, 0x0e, 0xe4, - 0x3c, 0xe8, 0x3e, 0xa2, 0xf7, 0x31, 0x07, 0xf4, 0x7e, 0x6c, 0x06, 0x73, - 0x18, 0x53, 0x9f, 0x82, 0x2f, 0xec, 0x61, 0x5d, 0x69, 0xe7, 0x9f, 0xd4, - 0x3c, 0xd4, 0x00, 0x7d, 0xf0, 0x68, 0x1f, 0x63, 0x4d, 0xbe, 0x77, 0x48, - 0x75, 0x16, 0x06, 0x01, 0x73, 0x4c, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xae, - 0xb0, 0xf3, 0x29, 0x23, 0x86, 0x21, 0xeb, 0xcc, 0xbb, 0x42, 0xd8, 0x04, - 0x9b, 0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x49, 0x7b, 0x3f, 0x07, 0x01, - 0xda, 0x08, 0x7b, 0x61, 0x2f, 0x56, 0x7b, 0xb0, 0x54, 0x6f, 0xe3, 0xff, - 0x67, 0xd8, 0xf8, 0x6c, 0x23, 0xae, 0xb1, 0xf1, 0x7f, 0xc5, 0xf2, 0x1a, - 0x7f, 0x7b, 0xda, 0xde, 0x3f, 0x0c, 0xf8, 0xf6, 0x2d, 0xd9, 0xfb, 0xec, - 0x83, 0x76, 0x87, 0xc8, 0x0d, 0xb0, 0xf9, 0xde, 0x09, 0x1e, 0xbc, 0x11, - 0xbe, 0xd4, 0xbb, 0x4a, 0x9e, 0xec, 0x2f, 0xb5, 0xc1, 0xe7, 0x6e, 0x97, - 0x77, 0x4f, 0xed, 0x94, 0xa1, 0xc9, 0x0f, 0x5e, 0x21, 0xcd, 0xdb, 0x60, - 0xa3, 0x4e, 0x01, 0xce, 0x98, 0x95, 0xdb, 0x3f, 0x04, 0xde, 0x3a, 0x53, - 0xdf, 0x57, 0x6d, 0xdb, 0x8d, 0x9c, 0xe7, 0xd9, 0xc9, 0xb5, 0xfa, 0x49, - 0xa0, 0x3d, 0x63, 0x29, 0xdb, 0xe4, 0xec, 0x49, 0x7a, 0x5f, 0x29, 0xd8, - 0xe5, 0x01, 0x6c, 0x92, 0x1d, 0xe8, 0x8f, 0xf1, 0xe4, 0x4d, 0xf2, 0xd4, - 0x35, 0xee, 0x27, 0xf2, 0x9a, 0x0f, 0xdb, 0x9d, 0xdc, 0xd4, 0x8d, 0x52, - 0x3c, 0x18, 0xc7, 0x1c, 0x54, 0xdb, 0x16, 0xb9, 0x5e, 0x86, 0xf4, 0x7c, - 0xce, 0xc8, 0x11, 0xe8, 0xe6, 0x3f, 0x28, 0x0d, 0xc9, 0xe2, 0x70, 0x2b, - 0x9e, 0xe3, 0xf2, 0x54, 0xa9, 0x07, 0xbe, 0xcf, 0x3b, 0x80, 0xa3, 0x46, - 0x3c, 0x37, 0xca, 0xc0, 0x15, 0xe4, 0xd5, 0x16, 0x59, 0x40, 0xf9, 0x3b, - 0xe5, 0xdf, 0xd9, 0x72, 0x96, 0x91, 0x37, 0x5a, 0xd0, 0x36, 0x2e, 0x17, - 0x4b, 0xb4, 0x2b, 0x35, 0x4f, 0xf4, 0x7f, 0x4b, 0x7a, 0xb2, 0xdf, 0x82, - 0x9d, 0x7a, 0x01, 0xd7, 0xd3, 0x92, 0xde, 0x3f, 0xea, 0xf4, 0xa4, 0x3a, - 0x1d, 0xe8, 0x4e, 0x5c, 0xae, 0xd3, 0xe3, 0x35, 0x3a, 0x57, 0xd9, 0x3e, - 0x1a, 0xe4, 0xe9, 0x83, 0x2a, 0xd9, 0x82, 0x35, 0xd9, 0xed, 0x74, 0xd9, - 0x32, 0x3e, 0xeb, 0x9c, 0x3c, 0xe9, 0x3c, 0xab, 0x76, 0x6c, 0x10, 0xe9, - 0x68, 0x81, 0xcd, 0x33, 0x26, 0xaa, 0xad, 0x45, 0x5c, 0xe9, 0x9c, 0x51, - 0xed, 0x28, 0xf3, 0x6d, 0x59, 0xa2, 0x05, 0xfa, 0x01, 0x65, 0xdb, 0x50, - 0xb6, 0xcb, 0x96, 0xb5, 0xb6, 0x48, 0x23, 0xca, 0xce, 0x68, 0x9e, 0xbf, - 0xd4, 0xe5, 0x7b, 0x79, 0xa7, 0x59, 0x3a, 0x4e, 0xb5, 0x40, 0x36, 0x6c, - 0x92, 0x85, 0x6b, 0x9a, 0xa4, 0x03, 0xef, 0x18, 0xe7, 0x0e, 0x4e, 0xc5, - 0xe5, 0xba, 0x53, 0x9d, 0xc9, 0x0f, 0x61, 0x0e, 0x9d, 0x67, 0x19, 0xf7, - 0x7e, 0xf2, 0x0a, 0xc6, 0x7d, 0x3a, 0xce, 0xf2, 0xde, 0xa4, 0xe5, 0x0f, - 0xf1, 0x61, 0xbe, 0x71, 0x44, 0x99, 0x7c, 0x1a, 0x7e, 0x2e, 0x75, 0x78, - 0xa7, 0xfd, 0x1e, 0xc7, 0x9f, 0x5e, 0x41, 0xbf, 0x6d, 0x86, 0xf6, 0x54, - 0x99, 0xfc, 0x48, 0x3d, 0x84, 0xfb, 0xb4, 0x23, 0xc5, 0x9a, 0xcc, 0x9a, - 0x23, 0x5f, 0x9d, 0x54, 0xcc, 0x65, 0x41, 0x59, 0xf5, 0x67, 0x42, 0xb3, - 0xc6, 0xe4, 0x05, 0x23, 0x97, 0xde, 0x67, 0xe4, 0xd2, 0x99, 0xf3, 0xcb, - 0xe4, 0xd2, 0x25, 0x2d, 0x97, 0x0e, 0x0a, 0xee, 0x73, 0x97, 0x20, 0x97, - 0x5e, 0xc0, 0xb3, 0xa7, 0xe5, 0x52, 0x42, 0xac, 0xbd, 0x2c, 0x3f, 0xd0, - 0xe3, 0xcf, 0x96, 0x5d, 0x6d, 0x57, 0x15, 0xa7, 0x61, 0x93, 0x94, 0x27, - 0xac, 0xfe, 0x96, 0x4c, 0xab, 0x74, 0xf5, 0xff, 0x50, 0x22, 0x9b, 0xf3, - 0xcf, 0xae, 0xe0, 0xf7, 0x46, 0x9f, 0x53, 0x94, 0x61, 0xaf, 0x42, 0x86, - 0x89, 0x5a, 0x5b, 0x86, 0xe1, 0x5d, 0x05, 0xef, 0x2a, 0xec, 0xf7, 0x6f, - 0x7f, 0x38, 0xe2, 0x51, 0x7e, 0x50, 0x66, 0x40, 0x26, 0x95, 0x21, 0x93, - 0xca, 0x90, 0x53, 0x65, 0xc8, 0x25, 0xd8, 0x6c, 0xe7, 0xcb, 0x90, 0x4b, - 0x65, 0xc8, 0x25, 0xc8, 0xb8, 0xc7, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x86, - 0x4c, 0x3b, 0x23, 0xf7, 0x59, 0x5d, 0x6f, 0x62, 0x25, 0xbd, 0xd6, 0x47, - 0xea, 0xd3, 0x31, 0xe4, 0xf3, 0x75, 0xb1, 0xc1, 0x03, 0xc7, 0x35, 0xbf, - 0x7b, 0xbe, 0xba, 0xca, 0x61, 0x0e, 0xcd, 0xf7, 0xb5, 0xff, 0xbe, 0x9b, - 0xbf, 0xa5, 0x09, 0x7c, 0xfd, 0x1d, 0xcb, 0xd7, 0xbb, 0x97, 0xf8, 0x3a, - 0xed, 0x30, 0x56, 0xbc, 0x36, 0x5f, 0x6f, 0xb3, 0xef, 0x0a, 0xe1, 0x3a, - 0xf0, 0xf5, 0xba, 0x15, 0x7c, 0x1d, 0x07, 0x5f, 0xef, 0x5f, 0xc5, 0xd7, - 0x1b, 0x9c, 0x01, 0xdd, 0x86, 0x67, 0x24, 0xf8, 0xdc, 0xe8, 0xd4, 0xf8, - 0xfa, 0x1e, 0xcd, 0xd7, 0x47, 0xc1, 0xd7, 0xd7, 0xd7, 0xf1, 0xf5, 0x7e, - 0x49, 0xdf, 0x9c, 0x8b, 0xed, 0x94, 0xd1, 0xfb, 0x55, 0xdb, 0x66, 0xf9, - 0x17, 0x31, 0xed, 0x0d, 0x8f, 0x0d, 0x4c, 0xb5, 0x49, 0xfe, 0xa1, 0x57, - 0x50, 0x46, 0x3e, 0x4b, 0x8f, 0x64, 0x1d, 0x4f, 0x8e, 0x1c, 0xff, 0xbe, - 0xcc, 0x6b, 0xde, 0x12, 0x19, 0x3b, 0x1e, 0x97, 0xf1, 0xe3, 0x8c, 0x43, - 0x7c, 0xcf, 0xd2, 0x7b, 0x93, 0x8c, 0x1f, 0x64, 0xde, 0x9c, 0x2b, 0xa3, - 0xc7, 0xe1, 0x6f, 0x1d, 0x67, 0x1c, 0xe2, 0xa5, 0x25, 0x1e, 0x9b, 0x87, - 0x6c, 0x19, 0x3d, 0xce, 0xb5, 0x8e, 0xa3, 0x9f, 0x16, 0x39, 0x7a, 0x5c, - 0xe4, 0xb6, 0xe3, 0xae, 0x7c, 0xe0, 0xf8, 0x12, 0xaf, 0x0d, 0x47, 0xbc, - 0xf6, 0x0c, 0x78, 0xad, 0xd3, 0xf2, 0x9a, 0x5a, 0xe2, 0xb5, 0xaf, 0xd6, - 0xf1, 0x1a, 0xdb, 0x93, 0xd7, 0x9e, 0xb5, 0x65, 0x7c, 0x76, 0xe5, 0xd0, - 0xf1, 0x76, 0x19, 0x7d, 0xe8, 0x2d, 0x32, 0x76, 0x3f, 0x61, 0x35, 0xdf, - 0x85, 0xa2, 0x2d, 0x36, 0x5d, 0xed, 0x44, 0xff, 0x51, 0x0e, 0x11, 0x71, - 0xed, 0x77, 0xcf, 0x48, 0xba, 0xc0, 0xf1, 0x1a, 0xe1, 0x47, 0x9f, 0x82, - 0x7f, 0x71, 0x08, 0x30, 0xdd, 0x72, 0x5c, 0xd2, 0xae, 0xbc, 0x2c, 0x13, - 0xc1, 0xe9, 0xed, 0xc6, 0x9e, 0x80, 0x2d, 0xa2, 0x6d, 0x9f, 0xac, 0xe4, - 0xdf, 0x1e, 0x6a, 0x1f, 0x63, 0xb2, 0x22, 0x8c, 0x05, 0x30, 0x6e, 0x6e, - 0xbf, 0x85, 0xca, 0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0xfb, - 0xf8, 0x9e, 0xcf, 0xb0, 0x67, 0xf4, 0xd9, 0x45, 0xb6, 0x67, 0x3f, 0x09, - 0x1d, 0x53, 0x2f, 0x56, 0xf8, 0x4d, 0x1c, 0xf8, 0x9f, 0x15, 0x7e, 0x5b, - 0xeb, 0x37, 0xdb, 0x4c, 0x7c, 0x96, 0x7c, 0xf7, 0x5d, 0x27, 0x5f, 0x9a, - 0xd3, 0xdf, 0x38, 0xc8, 0xf9, 0xf8, 0x5d, 0xe1, 0x33, 0xeb, 0xcf, 0x31, - 0xde, 0x91, 0x4a, 0xa9, 0x63, 0xdb, 0x99, 0x7b, 0x70, 0x70, 0x8e, 0x75, - 0x77, 0x5a, 0x1e, 0xdd, 0xa9, 0xfd, 0x0e, 0xda, 0x58, 0xa3, 0x93, 0x2f, - 0x48, 0x91, 0xb6, 0xc9, 0xf0, 0x4e, 0xa7, 0x30, 0xfd, 0x73, 0xdb, 0x8d, - 0xfd, 0x3c, 0xb0, 0x95, 0x79, 0x87, 0x59, 0xb5, 0x5a, 0x26, 0x9f, 0x92, - 0x48, 0x26, 0xa7, 0x6f, 0xce, 0xc2, 0xce, 0xce, 0x1f, 0xd7, 0xdf, 0xab, - 0x4a, 0x75, 0x2a, 0xce, 0xe9, 0x4e, 0xc8, 0xd7, 0x88, 0x16, 0x92, 0xf2, - 0xd1, 0xe3, 0xa4, 0x07, 0x95, 0xd8, 0x28, 0x1f, 0xb1, 0xf4, 0x70, 0x46, - 0x4a, 0x90, 0x3b, 0xc7, 0x8f, 0x7f, 0x40, 0xa6, 0x0f, 0xac, 0xa4, 0x87, - 0xb1, 0x1a, 0x3d, 0x24, 0x60, 0x9f, 0x39, 0xf5, 0xf4, 0xf0, 0xf3, 0x4b, - 0xf4, 0x30, 0xed, 0xfc, 0x6b, 0xe9, 0xe1, 0x86, 0x65, 0xf4, 0x30, 0xa1, - 0xe9, 0x61, 0x68, 0x89, 0x1e, 0x26, 0x8e, 0x73, 0x5c, 0xbd, 0x37, 0xea, - 0x2d, 0x38, 0x5c, 0xf3, 0x25, 0x5a, 0x48, 0x8d, 0xeb, 0x7c, 0xfd, 0x74, - 0x81, 0xe7, 0x9b, 0x36, 0x28, 0xc6, 0x49, 0x6a, 0xeb, 0xbf, 0xf1, 0xdf, - 0x74, 0xfd, 0xaf, 0xda, 0xfa, 0xff, 0x77, 0xfd, 0x33, 0x5b, 0x99, 0xbb, - 0xcf, 0x33, 0xb0, 0x46, 0x1e, 0x47, 0xf4, 0x90, 0xdb, 0x6a, 0xf4, 0x02, - 0xd7, 0x98, 0xcf, 0x90, 0x67, 0x90, 0x7f, 0xe7, 0x21, 0xff, 0x9e, 0x80, - 0xfc, 0x7b, 0x7c, 0xd9, 0x9e, 0x40, 0xbf, 0x8d, 0x47, 0x84, 0x72, 0x24, - 0xa8, 0xe1, 0x63, 0xa1, 0x8f, 0xf8, 0x30, 0xf9, 0x27, 0xcc, 0xfd, 0x5d, - 0x8e, 0x13, 0x57, 0xe7, 0x1c, 0x3d, 0x1a, 0xd4, 0xe3, 0x84, 0x70, 0xbf, - 0x5c, 0x37, 0x47, 0xfc, 0xae, 0xf0, 0xf9, 0x8c, 0xce, 0x23, 0x29, 0xea, - 0x3d, 0x28, 0xe2, 0x85, 0x7b, 0x50, 0xc4, 0x89, 0xab, 0xed, 0xfd, 0x62, - 0xa5, 0x49, 0xe7, 0xd0, 0x1f, 0x9e, 0x4b, 0xc8, 0x42, 0x82, 0x31, 0x3e, - 0x7e, 0xe7, 0x90, 0x7e, 0xb3, 0x9f, 0x2c, 0x4a, 0x81, 0xb9, 0x72, 0xe0, - 0xe9, 0x0d, 0x96, 0xb6, 0x19, 0x1b, 0xe4, 0x19, 0xe0, 0x68, 0x2f, 0xa2, - 0xdb, 0xca, 0xba, 0x96, 0xba, 0x98, 0x25, 0xf0, 0x3e, 0x25, 0xa9, 0x5c, - 0x1f, 0xee, 0x73, 0x1c, 0xfb, 0x13, 0x32, 0xf1, 0xe0, 0x87, 0x61, 0xcb, - 0xbd, 0x1f, 0x3a, 0x87, 0xe7, 0xcf, 0xb8, 0xf7, 0xe0, 0x69, 0x18, 0x66, - 0xf4, 0x77, 0xac, 0xe8, 0x03, 0x92, 0x1e, 0x92, 0x78, 0x3e, 0x63, 0xe3, - 0x4a, 0x49, 0x29, 0x96, 0x5e, 0x94, 0x7c, 0x85, 0xdf, 0x5c, 0x7b, 0x09, - 0xf7, 0xd7, 0x5b, 0x0f, 0xe3, 0x87, 0x0c, 0xeb, 0x3b, 0xd7, 0x66, 0x51, - 0xb2, 0x15, 0x93, 0xe3, 0x52, 0x8b, 0x9b, 0x9c, 0x91, 0x63, 0xda, 0x7e, - 0xce, 0xd8, 0xdc, 0x96, 0xf4, 0x70, 0x41, 0x8c, 0x0d, 0xfd, 0x39, 0xd8, - 0xd0, 0x9f, 0xad, 0x66, 0xf5, 0x3e, 0xd6, 0xe3, 0xb0, 0xa1, 0x1f, 0x83, - 0xee, 0xa1, 0xce, 0x49, 0x58, 0x9d, 0x33, 0xa1, 0x0e, 0x68, 0x9d, 0xf3, - 0xe7, 0x5a, 0xe7, 0xbc, 0x7b, 0x95, 0xce, 0x39, 0xaa, 0x3a, 0x27, 0xa9, - 0x73, 0x06, 0xd4, 0x7e, 0x87, 0xf6, 0xe2, 0x96, 0x35, 0x74, 0xce, 0x7b, - 0xe4, 0x1d, 0xf6, 0xdd, 0x3d, 0xf2, 0xde, 0x3d, 0x7a, 0xef, 0xc6, 0x9b, - 0x51, 0xfc, 0x76, 0x93, 0xd1, 0x41, 0xd7, 0xab, 0x6e, 0xbd, 0xe7, 0xfb, - 0x95, 0x3a, 0x9d, 0xd3, 0xa1, 0xfa, 0x9c, 0x01, 0xdd, 0x86, 0xb1, 0x09, - 0x3e, 0x07, 0x4e, 0x76, 0xb8, 0x09, 0xcf, 0x49, 0x89, 0x1d, 0xc7, 0xdc, - 0xcd, 0xf7, 0xa5, 0x94, 0x79, 0xf7, 0x56, 0xfb, 0x4e, 0x45, 0xe5, 0xae, - 0x29, 0xef, 0xb4, 0xe5, 0x46, 0x57, 0x75, 0xa8, 0x76, 0xad, 0xab, 0x76, - 0x83, 0xa1, 0x66, 0xa0, 0x5f, 0x67, 0xca, 0x91, 0xce, 0xe2, 0x6f, 0xc6, - 0x9e, 0x19, 0xa3, 0x88, 0x62, 0xd8, 0x29, 0xd4, 0xc1, 0x55, 0x8e, 0x6c, - 0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x0e, 0x78, 0xbd, 0x19, 0xfc, 0xf3, - 0x1f, 0x4a, 0x8c, 0x81, 0xb6, 0xc9, 0x89, 0xa9, 0xfa, 0x77, 0xed, 0xf2, - 0xae, 0xa9, 0x1d, 0x72, 0xfb, 0xe4, 0xd6, 0xa4, 0x34, 0xef, 0x94, 0x89, - 0xc9, 0x29, 0x7d, 0xfe, 0x7d, 0xb3, 0xfe, 0x2e, 0x08, 0xbf, 0x97, 0x63, - 0x64, 0xe4, 0x90, 0x63, 0x64, 0x64, 0x56, 0xd5, 0x6c, 0xd6, 0xa8, 0x4f, - 0x7e, 0x8b, 0x64, 0x70, 0x32, 0xa9, 0xbf, 0xa5, 0x3a, 0x53, 0xbd, 0x4a, - 0x7e, 0xfb, 0xa4, 0xba, 0x4b, 0xd5, 0xce, 0xf7, 0x6a, 0x9b, 0x75, 0x76, - 0x99, 0xcd, 0xfa, 0xbf, 0x64, 0xe1, 0xbd, 0x71, 0xcc, 0x13, 0x34, 0x7c, - 0xf5, 0xb7, 0xb8, 0x17, 0xda, 0x96, 0x90, 0x17, 0x65, 0x50, 0xe3, 0x8f, - 0xf2, 0xb4, 0x05, 0x72, 0x70, 0x51, 0xeb, 0xd7, 0x2d, 0xa0, 0x41, 0xca, - 0xd2, 0x0f, 0xca, 0x0b, 0x5a, 0x9e, 0x6d, 0xb1, 0xb6, 0xeb, 0x3c, 0xbf, - 0x6d, 0x7d, 0x9c, 0xb6, 0xeb, 0x9f, 0xdb, 0x72, 0x96, 0xa5, 0x93, 0x8b, - 0x42, 0x7d, 0x97, 0x80, 0x0c, 0xa5, 0x3c, 0x7d, 0xa3, 0xb6, 0xeb, 0x97, - 0x6c, 0x1f, 0x94, 0x9f, 0x46, 0x76, 0xef, 0x76, 0xe6, 0x6d, 0x19, 0x9f, - 0xa3, 0x78, 0xba, 0x9f, 0xcd, 0x5b, 0x3e, 0x53, 0xce, 0xe7, 0xf1, 0x7e, - 0x33, 0xde, 0x93, 0xcf, 0x1e, 0xd7, 0x7c, 0xa6, 0xed, 0x13, 0xa7, 0xd7, - 0xee, 0x2f, 0x2c, 0xed, 0x0d, 0x14, 0xc8, 0x67, 0xea, 0x84, 0x37, 0x6f, - 0xe4, 0x01, 0xf3, 0x54, 0x7f, 0x03, 0xba, 0x83, 0x6d, 0x51, 0xfe, 0x70, - 0x96, 0xbe, 0x2d, 0xfc, 0x9f, 0x8d, 0x78, 0x6e, 0xc3, 0xf3, 0x8c, 0xbc, - 0xfb, 0x60, 0x5c, 0xcf, 0x7b, 0x02, 0xf3, 0x38, 0x7c, 0x1c, 0x73, 0x72, - 0x8c, 0xed, 0xec, 0x9e, 0x75, 0xa5, 0xe1, 0x2c, 0xf9, 0x8e, 0x67, 0x6d, - 0xc2, 0xf0, 0x50, 0x2f, 0xe9, 0x36, 0xed, 0x0d, 0xe9, 0xb3, 0xa5, 0xbb, - 0x93, 0x31, 0xe0, 0xe4, 0x30, 0xd6, 0x63, 0xa2, 0xe4, 0x7b, 0x39, 0xc7, - 0x4f, 0x62, 0x9e, 0xb0, 0x01, 0x3b, 0x61, 0x0b, 0x76, 0xc2, 0x0e, 0xec, - 0x84, 0x1d, 0xb8, 0x49, 0x4e, 0x5d, 0xc3, 0x1c, 0x93, 0xc2, 0x75, 0xf0, - 0xca, 0xe5, 0xaf, 0x75, 0x9c, 0xbe, 0xf1, 0xe6, 0x41, 0xf8, 0xec, 0xe2, - 0xa5, 0x87, 0x99, 0x87, 0xbf, 0xe8, 0x35, 0xde, 0x3c, 0x24, 0x9d, 0xfd, - 0x78, 0xdf, 0xff, 0xa2, 0x74, 0xdd, 0x7c, 0xab, 0xd3, 0x38, 0x3c, 0x08, - 0x3c, 0x66, 0x9d, 0x74, 0x72, 0xc4, 0x99, 0xc7, 0x38, 0xb9, 0xdd, 0x31, - 0x61, 0xdc, 0x72, 0x9e, 0xb1, 0x88, 0x9b, 0x3b, 0x63, 0x3d, 0xa9, 0x51, - 0x27, 0x3d, 0xac, 0x62, 0xe9, 0xe1, 0x41, 0x27, 0xaa, 0xc7, 0x6f, 0xae, - 0x42, 0xce, 0x00, 0xd6, 0xc3, 0xe5, 0x4f, 0x83, 0x9e, 0x8e, 0x48, 0xf1, - 0x64, 0x8b, 0xcc, 0x95, 0x3a, 0xbd, 0x9c, 0x4a, 0xe8, 0xdc, 0x12, 0x75, - 0x0a, 0x44, 0x7f, 0x36, 0x2e, 0x33, 0x93, 0x3b, 0x45, 0x69, 0xdb, 0x7d, - 0x9b, 0xe4, 0xa6, 0x26, 0xe5, 0x62, 0x9f, 0xb4, 0x2a, 0xf4, 0xcf, 0x6f, - 0xdc, 0xaa, 0x53, 0xdc, 0x4b, 0x8c, 0x78, 0x61, 0x3b, 0xf9, 0x64, 0x12, - 0x38, 0x04, 0xdd, 0x32, 0xc6, 0xdb, 0x24, 0x94, 0x7b, 0x1f, 0xd0, 0xf1, - 0x53, 0xc6, 0x6c, 0xeb, 0xf7, 0x1e, 0xc8, 0x1f, 0xf1, 0x35, 0xf9, 0x63, - 0xb6, 0xcc, 0x7d, 0x1a, 0x29, 0xb8, 0x8c, 0x11, 0xfb, 0xf8, 0x3d, 0xcd, - 0xba, 0x4d, 0x32, 0xd1, 0x57, 0xb0, 0x79, 0x1e, 0x7f, 0x9e, 0x64, 0x0e, - 0x31, 0x71, 0x32, 0xda, 0x47, 0x5e, 0x5f, 0xb9, 0xb7, 0x11, 0xaf, 0x93, - 0x07, 0x8e, 0x2c, 0x4c, 0x46, 0x7b, 0x21, 0xec, 0x0f, 0xcf, 0xd3, 0x46, - 0xde, 0xe6, 0x56, 0xb5, 0x23, 0x5c, 0xdc, 0xaf, 0x5c, 0x2e, 0x63, 0x95, - 0x4f, 0x99, 0xea, 0x69, 0xf9, 0x7a, 0xa6, 0x6a, 0x64, 0xeb, 0x74, 0x35, - 0xd2, 0x2d, 0x71, 0xa3, 0x4b, 0x57, 0xe9, 0x13, 0x13, 0xcd, 0xac, 0xe9, - 0x13, 0xea, 0x45, 0x25, 0xef, 0x9b, 0xdb, 0x26, 0xee, 0xc3, 0xb2, 0x38, - 0xe1, 0x7f, 0x7a, 0x3b, 0x73, 0x35, 0x26, 0x82, 0x37, 0xa3, 0x1f, 0x9b, - 0xae, 0xa4, 0x3e, 0x1c, 0x51, 0x8d, 0xb8, 0x6f, 0xd6, 0xf4, 0x07, 0x9e, - 0xc2, 0xb3, 0xf1, 0x13, 0x3e, 0x07, 0x3f, 0xe1, 0xb3, 0xd0, 0x75, 0xe7, - 0xe1, 0x27, 0x3c, 0x01, 0x3f, 0xe1, 0x71, 0xf8, 0x09, 0x8f, 0x41, 0x4f, - 0xd6, 0xfb, 0x07, 0xe3, 0xcb, 0xfc, 0x83, 0x50, 0xf3, 0x3f, 0xe3, 0x81, - 0x4f, 0xd4, 0xf9, 0x06, 0x87, 0x8c, 0xbe, 0x82, 0xdf, 0x6f, 0xf8, 0xa8, - 0x43, 0xdd, 0xa4, 0xf5, 0xa3, 0xc9, 0xdb, 0x1d, 0x5e, 0xd2, 0x57, 0x1d, - 0xca, 0xe8, 0xab, 0x99, 0x9a, 0xbe, 0x32, 0x7c, 0xf4, 0xf0, 0xa4, 0xc4, - 0xfc, 0xc9, 0xf9, 0x5c, 0xb0, 0x57, 0xf3, 0x50, 0xab, 0xbf, 0x53, 0x62, - 0x0f, 0xa8, 0xb6, 0x06, 0xc9, 0xd9, 0x67, 0xd0, 0xd7, 0x89, 0x4f, 0xa3, - 0xaf, 0xeb, 0x24, 0xaf, 0xed, 0xb3, 0xcb, 0xe3, 0xfb, 0xb1, 0x15, 0xf8, - 0x2e, 0x96, 0x27, 0x34, 0xce, 0xef, 0xaf, 0x70, 0x9f, 0xa5, 0x45, 0xc6, - 0x2b, 0x11, 0xce, 0x79, 0x9e, 0x95, 0xb9, 0x18, 0xed, 0x12, 0x7b, 0x78, - 0x1b, 0xcf, 0x59, 0xa9, 0x7c, 0xb0, 0x5e, 0xe7, 0xb0, 0x9c, 0xea, 0x93, - 0x64, 0xbe, 0x8f, 0xb4, 0x7a, 0x9f, 0xcc, 0xe8, 0xb5, 0xd8, 0x26, 0x0d, - 0x0f, 0xd3, 0x46, 0x89, 0xf6, 0xf3, 0xde, 0x7f, 0xa5, 0xfd, 0xe6, 0x6a, - 0xdc, 0xd4, 0x13, 0x39, 0xa2, 0xd7, 0x6b, 0x5a, 0xe7, 0x19, 0xde, 0x34, - 0xc7, 0xb8, 0x3c, 0xbf, 0x6f, 0xc5, 0x98, 0xfc, 0xbf, 0x66, 0xfd, 0x7e, - 0xf9, 0x4a, 0x63, 0xcf, 0x6c, 0xb6, 0x76, 0x8c, 0x89, 0x53, 0xad, 0x6d, - 0xc3, 0xb0, 0x9f, 0xfa, 0x6f, 0x32, 0xee, 0x70, 0xc6, 0x27, 0x77, 0x3a, - 0xc5, 0x49, 0xee, 0x65, 0xdb, 0xbf, 0xd1, 0xe1, 0xed, 0x77, 0x0e, 0xfb, - 0x3b, 0x50, 0xc6, 0x98, 0x25, 0x63, 0x36, 0xf7, 0x5f, 0xc9, 0x18, 0x6d, - 0xce, 0xe7, 0xd8, 0x2c, 0xdb, 0xe1, 0x4c, 0x4c, 0x76, 0xc2, 0x37, 0xe7, - 0xb9, 0x2a, 0xbe, 0x1f, 0xe2, 0xda, 0x41, 0x07, 0x7b, 0xfa, 0xcc, 0xee, - 0x98, 0x5c, 0x65, 0x63, 0xd0, 0xd4, 0xc3, 0x3f, 0xbd, 0x6c, 0xef, 0xf6, - 0x28, 0xf4, 0xd8, 0x2d, 0x90, 0x47, 0xd4, 0xc3, 0x47, 0xe5, 0x6d, 0x96, - 0x9e, 0x97, 0xeb, 0xe1, 0x4b, 0xc2, 0x38, 0x71, 0x2f, 0xde, 0x15, 0xc2, - 0x38, 0xe8, 0xe1, 0x58, 0x9d, 0xaf, 0x46, 0xbf, 0xaf, 0x29, 0x63, 0xf6, - 0xc3, 0x96, 0xfb, 0x7d, 0x90, 0x03, 0x89, 0xc8, 0xcf, 0x6b, 0x5c, 0xda, - 0xaf, 0xdd, 0x6f, 0xdb, 0x4e, 0x04, 0x7f, 0x44, 0x1c, 0xa5, 0x8e, 0xca, - 0x2f, 0x42, 0xa7, 0x31, 0x07, 0xe4, 0x2f, 0x34, 0xce, 0x44, 0x91, 0xf6, - 0x36, 0x6b, 0x18, 0xad, 0x9c, 0x4f, 0x45, 0x39, 0x1c, 0x45, 0xdb, 0x76, - 0xcc, 0xee, 0xc9, 0x17, 0xe5, 0xeb, 0x8c, 0x73, 0xa6, 0x06, 0x63, 0xeb, - 0xf9, 0x3d, 0x46, 0xb4, 0xfd, 0x45, 0xed, 0xb7, 0x67, 0x25, 0xea, 0x8b, - 0xcf, 0x0d, 0x75, 0x7d, 0xd3, 0x8e, 0xe2, 0x7d, 0xe5, 0x39, 0xb2, 0xa7, - 0xf5, 0x3e, 0xa3, 0xf9, 0x5e, 0x42, 0xc4, 0x27, 0xe4, 0x9d, 0x94, 0x3e, - 0xeb, 0xe4, 0x3f, 0x4c, 0xbb, 0x87, 0x7b, 0xb0, 0xde, 0xfc, 0x78, 0xf0, - 0x11, 0xfd, 0xcd, 0xc0, 0x69, 0x11, 0xa7, 0x18, 0xdc, 0xa6, 0x73, 0x4f, - 0x8a, 0x3a, 0xd6, 0x5c, 0xc0, 0xbd, 0xe6, 0xa3, 0x76, 0x3c, 0xcc, 0xbf, - 0xc3, 0xc1, 0xb2, 0x3c, 0x60, 0xa3, 0x0e, 0xa1, 0xec, 0x4d, 0x48, 0xc7, - 0x89, 0x5f, 0xd0, 0xbc, 0xb0, 0x05, 0xbe, 0xc0, 0xc0, 0x09, 0xe8, 0xea, - 0x13, 0x49, 0x19, 0x3a, 0xa1, 0x75, 0x63, 0x76, 0x75, 0xac, 0xa0, 0xc7, - 0x73, 0x9d, 0x77, 0xe9, 0x73, 0x6c, 0x6f, 0x3d, 0x11, 0x93, 0x63, 0x89, - 0x1e, 0xaf, 0xcb, 0x79, 0xb7, 0xd5, 0x85, 0x51, 0x0c, 0xbb, 0x05, 0xed, - 0x5f, 0x2f, 0x8e, 0x1d, 0xc5, 0xaf, 0x63, 0x32, 0x7d, 0xb0, 0x1d, 0xb0, - 0x75, 0x6e, 0x33, 0x67, 0x90, 0xb1, 0x56, 0xfa, 0x1b, 0xf7, 0x6e, 0x92, - 0xb2, 0xac, 0x03, 0xb0, 0x0c, 0x9e, 0xa0, 0x3e, 0xf3, 0x35, 0x8f, 0x03, - 0x06, 0xaf, 0x41, 0xfb, 0x21, 0xe4, 0xcb, 0xb7, 0x88, 0xff, 0x00, 0x64, - 0xdc, 0x89, 0xb8, 0x74, 0x9d, 0x68, 0x91, 0x5d, 0x27, 0xe8, 0x87, 0xd4, - 0xfb, 0xa5, 0xb4, 0x4b, 0xe7, 0x30, 0xc7, 0x77, 0x6a, 0x39, 0xc9, 0x3d, - 0xcd, 0xdb, 0xc9, 0xbb, 0xa8, 0x9b, 0x87, 0xcd, 0x9c, 0x3b, 0xe1, 0xe9, - 0x3d, 0xd2, 0x1c, 0xe6, 0x9c, 0xaf, 0x78, 0x18, 0xc7, 0xc8, 0x9c, 0x22, - 0xfd, 0x94, 0xe1, 0x6d, 0xc0, 0xf1, 0x31, 0xcb, 0x3b, 0x43, 0xdb, 0x2c, - 0x8f, 0xfe, 0x88, 0xbc, 0x77, 0xf3, 0x36, 0x23, 0x3b, 0x7f, 0x76, 0x1b, - 0x73, 0x93, 0xb6, 0xf8, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7, - 0xe2, 0x45, 0x01, 0x8e, 0xa2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0xbc, 0x18, - 0xe8, 0xf3, 0x2b, 0xc1, 0x02, 0xf3, 0x08, 0xf5, 0x77, 0x14, 0x6a, 0xdf, - 0x5b, 0xd9, 0x5b, 0x65, 0x9c, 0xfc, 0x89, 0xe8, 0x6f, 0xa9, 0xd4, 0xe5, - 0x1d, 0xd6, 0xef, 0x81, 0x31, 0xd6, 0xb4, 0x94, 0x1b, 0x14, 0x4e, 0xea, - 0xef, 0x21, 0x3d, 0xeb, 0x5c, 0x2a, 0x5d, 0x70, 0xbe, 0x39, 0x25, 0xa1, - 0xeb, 0x7f, 0xdf, 0xf9, 0xb6, 0xcf, 0x3d, 0xf3, 0x2f, 0x3b, 0xdf, 0x2a, - 0xf9, 0xe0, 0xc3, 0x0b, 0x98, 0xc7, 0x2b, 0xce, 0x77, 0xb0, 0xbe, 0x47, - 0xca, 0xd9, 0xb4, 0x67, 0x63, 0xe2, 0x17, 0x4a, 0xaf, 0x38, 0x5f, 0xaa, - 0xc5, 0x93, 0xfa, 0x23, 0x1a, 0x39, 0xca, 0x77, 0x15, 0xbc, 0xab, 0xe8, - 0xfd, 0x1f, 0x67, 0x76, 0xca, 0xe6, 0x97, 0x68, 0x3e, 0x9e, 0x5f, 0xda, - 0x97, 0x19, 0xd6, 0x7b, 0x15, 0xcf, 0x38, 0xb3, 0x73, 0x9f, 0xdb, 0x66, - 0xf2, 0x8c, 0x2e, 0xe0, 0x9d, 0xc9, 0xb9, 0x9c, 0x99, 0xbb, 0x80, 0x3a, - 0x4f, 0x3b, 0x33, 0x3a, 0xfe, 0xc5, 0x76, 0x17, 0x9c, 0xe9, 0xb9, 0xa7, - 0x9d, 0x39, 0xbd, 0x07, 0x7d, 0xd1, 0x79, 0x74, 0x8a, 0x7d, 0x5f, 0x44, - 0x9d, 0x79, 0xe7, 0x14, 0xfa, 0x9b, 0x9b, 0xe2, 0x79, 0xdc, 0x4e, 0xd8, - 0x05, 0xfc, 0x1b, 0x45, 0xfc, 0x1e, 0xc7, 0x33, 0xce, 0xdc, 0x52, 0xbf, - 0x0b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x19, 0xf4, 0xbf, 0x7a, - 0xaf, 0x6a, 0x35, 0x4e, 0x9e, 0x07, 0x4e, 0x5e, 0xb4, 0x38, 0x79, 0xd5, - 0xe2, 0xe4, 0xb9, 0x3a, 0x9c, 0x88, 0x5a, 0x8e, 0x93, 0x57, 0x81, 0x13, - 0x51, 0x6b, 0xe3, 0x04, 0xef, 0x2a, 0x78, 0xa7, 0x71, 0xf2, 0xd2, 0x0a, - 0x9c, 0x2c, 0x2e, 0xc5, 0xe5, 0x0d, 0x4e, 0x5e, 0x00, 0x4e, 0x7e, 0x60, - 0x61, 0x7f, 0xd1, 0xe2, 0x04, 0xf7, 0xb9, 0x17, 0x51, 0xe7, 0xa5, 0x3a, - 0x9c, 0xbc, 0x08, 0x9c, 0xbc, 0x64, 0x71, 0xf2, 0x6d, 0x8b, 0x93, 0x6f, - 0xa3, 0xce, 0x22, 0x70, 0x72, 0x69, 0x0d, 0x9c, 0xbc, 0x00, 0x9c, 0x44, - 0xfd, 0x5e, 0x42, 0x3f, 0xdf, 0xae, 0xc3, 0xc9, 0x0b, 0x6b, 0xe0, 0x84, - 0x7b, 0xb1, 0x51, 0x4e, 0xf7, 0x99, 0xd7, 0xc9, 0xe9, 0x5e, 0x7c, 0x03, - 0x39, 0xdd, 0xac, 0x73, 0x46, 0x6a, 0x7f, 0xbb, 0x62, 0xc2, 0xe6, 0xa8, - 0x99, 0x5c, 0xc0, 0xda, 0x37, 0x9b, 0x3a, 0xc1, 0xe7, 0xc5, 0x02, 0xbc, - 0x11, 0x9d, 0x53, 0xea, 0xee, 0x19, 0x03, 0xaf, 0xbd, 0x5b, 0x0e, 0x9f, - 0x6c, 0x3c, 0x96, 0xb7, 0x65, 0xfe, 0x9e, 0xce, 0x82, 0x52, 0x7c, 0x17, - 0xe5, 0x24, 0xd0, 0x2f, 0x69, 0xe0, 0xb7, 0x0a, 0xbb, 0xb3, 0x52, 0xbf, - 0x27, 0x3d, 0xc5, 0x6f, 0x34, 0x71, 0x7f, 0x8c, 0x7f, 0x67, 0x23, 0xc5, - 0x3c, 0xab, 0xa2, 0x86, 0x37, 0x0d, 0xfd, 0xd1, 0xaf, 0x73, 0xab, 0xf8, - 0x37, 0x82, 0x62, 0xf0, 0xfb, 0x47, 0xfb, 0x68, 0x2b, 0x67, 0xec, 0x99, - 0xb0, 0x40, 0x9f, 0x53, 0xa9, 0xf1, 0x4f, 0xfd, 0x79, 0x68, 0xf2, 0x5d, - 0x8d, 0x6e, 0x8e, 0x2c, 0x7d, 0x77, 0xf0, 0xb4, 0x3c, 0xa5, 0x63, 0xc5, - 0xcd, 0xfa, 0xef, 0x2b, 0x9c, 0x09, 0x4c, 0x8c, 0x76, 0x41, 0xc7, 0x68, - 0x05, 0xde, 0xf8, 0xb8, 0x8d, 0xd3, 0x76, 0xf5, 0xbf, 0xb4, 0x14, 0xa3, - 0xad, 0xcf, 0x67, 0x31, 0xfb, 0xeb, 0xb9, 0xc9, 0x39, 0x9d, 0xa3, 0x33, - 0xc8, 0xef, 0x6f, 0x40, 0x46, 0x8c, 0x4d, 0x57, 0x64, 0xfc, 0x41, 0x3e, - 0x53, 0xbf, 0xc5, 0xa0, 0xc3, 0x28, 0xc3, 0x0b, 0x92, 0xeb, 0x67, 0x99, - 0x69, 0x33, 0xa8, 0xfd, 0xe5, 0xd3, 0x32, 0xb0, 0x34, 0x3e, 0xf1, 0xfb, - 0x89, 0xba, 0xef, 0x60, 0xd3, 0xe6, 0xc9, 0x3a, 0xb9, 0x2a, 0xdf, 0x47, - 0x7b, 0xe4, 0x9f, 0xb0, 0xdf, 0x0a, 0xe4, 0xfb, 0xfa, 0x6f, 0xbf, 0x6a, - 0xd1, 0x81, 0xdf, 0xfc, 0xbe, 0xda, 0x84, 0x33, 0x88, 0x36, 0xf3, 0x5e, - 0xcb, 0xb0, 0xca, 0xdc, 0x38, 0xcc, 0x73, 0x73, 0x33, 0xab, 0xbe, 0x9d, - 0x5d, 0xd3, 0x8b, 0x45, 0xbd, 0xa6, 0xcc, 0xcf, 0x2a, 0x80, 0x16, 0x35, - 0x6d, 0x69, 0xfa, 0x3f, 0xbc, 0xa4, 0x2f, 0xa9, 0x67, 0xcd, 0xb7, 0x67, - 0x8c, 0xbe, 0x4c, 0x27, 0x07, 0x31, 0xbe, 0xfe, 0x1b, 0x0d, 0xf6, 0x5c, - 0x6f, 0x7e, 0xee, 0x2e, 0xad, 0xeb, 0x27, 0x82, 0x6c, 0xca, 0x95, 0x35, - 0xea, 0x4e, 0xd6, 0xd5, 0xd5, 0xf3, 0xf6, 0xe4, 0xb7, 0xb0, 0x36, 0xbf, - 0x51, 0xae, 0xc8, 0xc0, 0xd4, 0x5f, 0xc1, 0x7f, 0x4c, 0xca, 0x6f, 0x96, - 0x1f, 0x01, 0xbd, 0x16, 0xb6, 0xd8, 0x6f, 0x35, 0xe5, 0x00, 0x37, 0xbf, - 0xbd, 0xa2, 0xf3, 0x89, 0x63, 0xbf, 0x0d, 0xba, 0xf8, 0xcc, 0x23, 0x1c, - 0x03, 0xb0, 0xc4, 0x60, 0xdb, 0xc3, 0x4e, 0x98, 0x7e, 0x44, 0xe7, 0xce, - 0x5d, 0x5f, 0x79, 0x44, 0xc7, 0x2c, 0x86, 0x2a, 0xed, 0xb2, 0xb7, 0xd2, - 0x22, 0xfb, 0xa0, 0x17, 0xf6, 0x55, 0x7c, 0x5c, 0x71, 0x79, 0x67, 0xc5, - 0xac, 0xd3, 0x07, 0x2b, 0x5c, 0xef, 0x3d, 0x32, 0x73, 0x72, 0xe5, 0xf7, - 0x3e, 0xe7, 0x0b, 0xd1, 0xdf, 0x73, 0x52, 0x8a, 0xf9, 0x65, 0xa4, 0x25, - 0x5c, 0xe5, 0xf4, 0xb1, 0x79, 0x8d, 0x07, 0x66, 0xb8, 0xa6, 0x27, 0x17, - 0x85, 0x79, 0xfa, 0xfc, 0x1b, 0x4e, 0x7f, 0xb9, 0x9d, 0xe7, 0xa6, 0xf9, - 0x2d, 0xaf, 0xa1, 0x6a, 0x94, 0x37, 0xbe, 0x56, 0xce, 0x38, 0xec, 0xfc, - 0x3d, 0x51, 0x8e, 0x5f, 0x9c, 0x39, 0xe3, 0xd2, 0x71, 0xb6, 0x05, 0xf7, - 0xef, 0x6e, 0xd7, 0x67, 0x9b, 0xcf, 0x8a, 0x2d, 0xd3, 0xf9, 0xe4, 0x78, - 0x5e, 0xf9, 0xbd, 0xb6, 0x88, 0x1f, 0x6a, 0x7f, 0xf7, 0x40, 0xe4, 0xff, - 0x02, 0x06, 0x86, 0xe5, 0x0a, 0xd4, 0x6f, 0x00, 0x00, 0x00 }; + 0xad, 0xbc, 0x0f, 0x74, 0x53, 0xd7, 0x95, 0x2e, 0xfe, 0xdd, 0x2b, 0xc9, + 0x96, 0x6d, 0xd9, 0x96, 0x8d, 0x70, 0xe4, 0xc4, 0x0d, 0x52, 0x7c, 0x05, + 0x0a, 0x36, 0xe9, 0x95, 0x11, 0x89, 0xd3, 0x77, 0x13, 0x54, 0x70, 0x82, + 0x49, 0x68, 0xe2, 0x10, 0xa6, 0x75, 0x67, 0x98, 0xa9, 0x1e, 0x21, 0x09, + 0x49, 0x99, 0x3c, 0xb7, 0xaf, 0xed, 0x23, 0xf9, 0xd1, 0xf1, 0xad, 0xcd, + 0x1f, 0x03, 0x92, 0x25, 0x1b, 0xf3, 0x27, 0x6f, 0xba, 0x5e, 0x84, 0x31, + 0x18, 0x12, 0xd9, 0x4e, 0xda, 0x4c, 0x87, 0xbc, 0xd5, 0x79, 0x78, 0x0c, + 0x24, 0x90, 0x34, 0x7f, 0x9a, 0xb4, 0xab, 0x69, 0xa7, 0x6f, 0xe2, 0x12, + 0x92, 0x92, 0x7f, 0x94, 0x34, 0x9d, 0x0e, 0x74, 0x86, 0xde, 0xdf, 0xb7, + 0xaf, 0x24, 0x30, 0x94, 0xa4, 0xed, 0x5a, 0xcf, 0x6b, 0x69, 0x49, 0xf7, + 0xde, 0x73, 0xf6, 0x39, 0x67, 0x9f, 0xbd, 0xbf, 0xfd, 0xed, 0x73, 0xce, + 0xf5, 0xa7, 0x80, 0x52, 0xe4, 0xff, 0xca, 0xf9, 0xb9, 0x2e, 0xda, 0x71, + 0x0f, 0xe6, 0x5d, 0xa7, 0xcb, 0xb5, 0xd3, 0x05, 0x27, 0xfe, 0xc4, 0xbf, + 0xc0, 0x9f, 0x5a, 0x30, 0xff, 0xe7, 0x00, 0xbc, 0x85, 0x36, 0xe5, 0x03, + 0xb7, 0x6a, 0xac, 0xfb, 0xe2, 0x02, 0x0d, 0x6e, 0x87, 0x11, 0x5d, 0x7e, + 0x8f, 0x06, 0xc4, 0xb2, 0x0d, 0x81, 0x85, 0x38, 0x67, 0x99, 0x3e, 0x27, + 0xe4, 0xfe, 0xa7, 0x8c, 0xff, 0x7c, 0xec, 0x9f, 0x6e, 0x08, 0x9e, 0xce, + 0x38, 0xe0, 0xf6, 0x1a, 0x5f, 0x83, 0x77, 0x26, 0xdc, 0x75, 0xac, 0xf3, + 0xed, 0x59, 0xb3, 0x55, 0x54, 0x14, 0x64, 0x05, 0xfd, 0x19, 0x04, 0xbd, + 0x26, 0x82, 0x61, 0x13, 0x88, 0x3b, 0x0d, 0xc4, 0x8b, 0x0d, 0x37, 0x8a, + 0xb4, 0x22, 0xc4, 0xbd, 0x6b, 0x02, 0xeb, 0xa2, 0xc0, 0x82, 0x84, 0x3b, + 0x70, 0x3c, 0x0b, 0xdc, 0x93, 0x70, 0x63, 0xd2, 0xe1, 0x09, 0xbc, 0x99, + 0xbd, 0xb9, 0x32, 0xa7, 0x83, 0x18, 0x1c, 0x1a, 0xe2, 0xaa, 0x21, 0xf7, + 0x11, 0x58, 0x98, 0x8d, 0x62, 0x7d, 0xca, 0xb2, 0x9c, 0x1a, 0x9c, 0x83, + 0x8d, 0x0e, 0xc4, 0xbc, 0x0a, 0x76, 0x6b, 0x51, 0x74, 0x8f, 0x05, 0x39, + 0x58, 0x29, 0x23, 0xed, 0xfc, 0xe6, 0xdc, 0xc6, 0xd4, 0x49, 0xeb, 0x9f, + 0x66, 0x79, 0xf1, 0xe4, 0x98, 0x0f, 0x07, 0xc7, 0x82, 0xa6, 0x89, 0x2a, + 0x9c, 0x48, 0x37, 0xe2, 0xa4, 0x56, 0x87, 0x37, 0x35, 0x0b, 0xeb, 0xf5, + 0x30, 0x54, 0x2d, 0xa8, 0x43, 0xf1, 0x63, 0xd0, 0x1b, 0x0c, 0xc4, 0xc1, + 0x4e, 0x54, 0x04, 0xc3, 0xe3, 0xac, 0x9b, 0x4a, 0x21, 0x5e, 0x64, 0x38, + 0x51, 0xa2, 0xdd, 0x8c, 0x53, 0xdb, 0x0c, 0x7c, 0xb0, 0x0d, 0xcb, 0x2b, + 0x60, 0x59, 0xd9, 0x48, 0xa8, 0x6d, 0xb5, 0xe2, 0x0d, 0x3c, 0x9f, 0x45, + 0xe0, 0x58, 0x76, 0xaa, 0xde, 0x38, 0x21, 0xd5, 0x6c, 0x27, 0x15, 0xc5, + 0x4e, 0xf6, 0xcd, 0x3b, 0x2b, 0x8a, 0xf4, 0x18, 0xdb, 0x4e, 0x49, 0x7f, + 0xfc, 0xf8, 0xa7, 0x59, 0x7f, 0xcd, 0xf9, 0x64, 0x5b, 0x94, 0xbd, 0x21, + 0xf5, 0x3a, 0xfb, 0x55, 0x87, 0xef, 0x8e, 0xf9, 0xf1, 0x1d, 0xf6, 0xed, + 0x29, 0x29, 0x37, 0x16, 0x60, 0x1f, 0xab, 0x70, 0x84, 0xfd, 0xfb, 0x21, + 0xfb, 0xf7, 0x0a, 0xfb, 0xb7, 0x9b, 0xfd, 0x5b, 0xd1, 0x1c, 0xdc, 0x69, + 0x42, 0xc1, 0xd2, 0xc6, 0x36, 0xe9, 0x1b, 0xc7, 0xc7, 0x8f, 0xaa, 0x22, + 0x56, 0x1d, 0x0c, 0x07, 0xd4, 0x60, 0x18, 0x76, 0x9f, 0xa5, 0xfd, 0xdf, + 0x9c, 0x4b, 0xa6, 0x60, 0xba, 0xa9, 0x57, 0x97, 0x71, 0x33, 0xb2, 0xec, + 0xf3, 0x13, 0xdb, 0x42, 0xcd, 0xab, 0x54, 0x2c, 0xf1, 0xb0, 0xdf, 0x0f, + 0x46, 0x42, 0x81, 0xd9, 0xec, 0xf7, 0x50, 0x56, 0x55, 0x55, 0xcd, 0x17, + 0x18, 0xce, 0x2a, 0x88, 0x2d, 0x55, 0x39, 0x7e, 0xb6, 0x9b, 0x62, 0x5f, + 0x52, 0xec, 0x4b, 0x8a, 0x7d, 0x49, 0x49, 0x9f, 0xc3, 0xec, 0x6f, 0x4e, + 0xd7, 0x83, 0xd9, 0xcb, 0xf5, 0x35, 0xd8, 0xc3, 0xb9, 0xa4, 0x3e, 0xa5, + 0xcf, 0x96, 0xf5, 0xaa, 0xbe, 0x88, 0x7d, 0xb0, 0xac, 0x8f, 0x74, 0xe9, + 0x9b, 0xf4, 0xab, 0x1c, 0x31, 0x5f, 0x8a, 0x73, 0x56, 0xe8, 0x1b, 0x8c, + 0x6a, 0xcc, 0x30, 0x5d, 0x86, 0xcc, 0xbb, 0xca, 0xfb, 0x21, 0xfd, 0x23, + 0xc0, 0x1a, 0x8c, 0x7a, 0x03, 0x1b, 0xb2, 0xbe, 0x40, 0x17, 0x75, 0xd9, + 0x9d, 0x0d, 0xfa, 0xc5, 0x56, 0xff, 0xb0, 0x2f, 0x41, 0x6f, 0xdc, 0x9e, + 0x53, 0xe9, 0xd3, 0x64, 0x7e, 0x3e, 0x2d, 0xeb, 0x15, 0xdd, 0xcf, 0xb6, + 0xa5, 0x3f, 0x51, 0xbb, 0xed, 0x0f, 0x75, 0x44, 0xbd, 0x10, 0xbb, 0x08, + 0x99, 0x3f, 0xb4, 0xed, 0xcb, 0x1b, 0x48, 0x67, 0x59, 0xe6, 0xbc, 0x1c, + 0x27, 0xc7, 0x0a, 0xb6, 0x65, 0x59, 0xbb, 0xb5, 0xa0, 0x57, 0xda, 0xca, + 0x8d, 0x51, 0xec, 0x46, 0xec, 0xc4, 0x1f, 0xf7, 0x18, 0x5e, 0xca, 0x44, + 0xdb, 0xce, 0x64, 0xa7, 0x55, 0xab, 0x89, 0x2e, 0xb5, 0x35, 0xb5, 0x0e, + 0x4f, 0xf3, 0xa9, 0x79, 0x5f, 0x31, 0xcb, 0xa3, 0x11, 0x94, 0x6a, 0xf0, + 0x94, 0x68, 0x68, 0xeb, 0x1d, 0x29, 0x35, 0xcb, 0x8c, 0xef, 0xdf, 0x9d, + 0x1c, 0x71, 0xa3, 0x74, 0x44, 0x43, 0xc9, 0x48, 0xc8, 0x89, 0x0a, 0x03, + 0x5b, 0xc6, 0xde, 0x71, 0xe4, 0xc6, 0xbb, 0xb0, 0x30, 0x6e, 0xb1, 0x71, + 0xf7, 0x5b, 0x89, 0xd3, 0x56, 0x91, 0x56, 0xf2, 0x05, 0x87, 0xa1, 0x05, + 0xf6, 0x02, 0xa7, 0x57, 0x44, 0xfd, 0xe8, 0xa2, 0xcd, 0xce, 0xd0, 0x7e, + 0xe2, 0x41, 0x45, 0x2b, 0xcc, 0xb1, 0x1a, 0xf1, 0x07, 0xac, 0x4f, 0x58, + 0x56, 0x91, 0x71, 0xf7, 0xdd, 0x2c, 0xe7, 0xdd, 0x8b, 0x5a, 0x2c, 0xf4, + 0x62, 0xed, 0xfa, 0xe8, 0xaf, 0x95, 0x7d, 0x03, 0xcb, 0x61, 0x0e, 0xaf, + 0xe6, 0x47, 0x05, 0xaa, 0xae, 0xbe, 0xda, 0x71, 0xe3, 0x72, 0x74, 0x0f, + 0xb3, 0xaf, 0xa9, 0x18, 0xed, 0x53, 0x6c, 0x6b, 0x35, 0x36, 0x0d, 0x3f, + 0x04, 0x73, 0xf7, 0x4a, 0x96, 0x91, 0x31, 0x75, 0xf1, 0xbb, 0x15, 0x8f, + 0x8d, 0x89, 0x7c, 0xe9, 0xc6, 0xe5, 0xe4, 0xbf, 0x63, 0x2d, 0xf4, 0x89, + 0x7c, 0x27, 0x36, 0x26, 0xec, 0x79, 0x51, 0x68, 0x9f, 0xe1, 0x13, 0xb4, + 0x95, 0x6e, 0xdd, 0x40, 0x4f, 0xaa, 0x19, 0x1b, 0x53, 0xb1, 0x20, 0xd1, + 0x80, 0xf3, 0xd6, 0x06, 0xd5, 0x08, 0xb5, 0x76, 0x41, 0x7c, 0x02, 0x4a, + 0xa9, 0x01, 0x67, 0x36, 0x3a, 0xe9, 0x7e, 0x31, 0xa1, 0xb5, 0x3f, 0xae, + 0xb8, 0x10, 0xaf, 0x92, 0x36, 0x26, 0xdd, 0x2f, 0x27, 0x14, 0xfc, 0x52, + 0x0b, 0x75, 0xbc, 0xab, 0x4c, 0xba, 0x5f, 0xca, 0x7a, 0x51, 0x9b, 0x0c, + 0xb6, 0x9b, 0x4a, 0x33, 0x9e, 0xc9, 0xfa, 0xe0, 0x4f, 0x1a, 0x38, 0x90, + 0xd5, 0xb1, 0xff, 0x22, 0x9f, 0xb9, 0xec, 0x9f, 0xe9, 0x60, 0x5f, 0x57, + 0x26, 0x02, 0xe8, 0xd2, 0xcf, 0x59, 0x31, 0x2f, 0xe2, 0x95, 0xc6, 0xa4, + 0xfb, 0x83, 0x24, 0x94, 0x0a, 0x43, 0xf3, 0x8f, 0x2a, 0xbf, 0xb0, 0xe2, + 0x3e, 0x29, 0xc6, 0xfe, 0x8d, 0xc9, 0x58, 0x97, 0x50, 0xef, 0x06, 0xe7, + 0xfd, 0xb4, 0x55, 0xc6, 0x39, 0x2b, 0x32, 0xae, 0xc4, 0xf0, 0x80, 0x86, + 0xfd, 0x1c, 0xeb, 0xfb, 0xfa, 0x78, 0xb3, 0x07, 0x5a, 0xdb, 0x7b, 0x08, + 0xc6, 0x66, 0x2b, 0x06, 0x8e, 0x66, 0x35, 0x0c, 0x25, 0x0c, 0x1c, 0x4a, + 0xd4, 0x7b, 0xbb, 0x31, 0x17, 0x31, 0x7f, 0x0e, 0x1f, 0x47, 0xd8, 0xef, + 0xc1, 0x50, 0x1b, 0x2a, 0x8d, 0x66, 0x4c, 0xb0, 0xdf, 0xa7, 0xe6, 0x89, + 0x1c, 0x1d, 0x2f, 0xfd, 0x09, 0x7d, 0x15, 0xbd, 0x3e, 0xca, 0xbe, 0x36, + 0xcf, 0x3d, 0x67, 0x61, 0x9a, 0x1b, 0xc7, 0xf5, 0x2b, 0x88, 0x47, 0x30, + 0x4b, 0x0c, 0xb7, 0xb3, 0x27, 0xe1, 0xc5, 0xbe, 0xac, 0xc7, 0xd9, 0x9d, + 0xf0, 0x61, 0x77, 0x36, 0x80, 0x5a, 0x03, 0xa6, 0x9f, 0x72, 0x6b, 0xe9, + 0x4b, 0xa3, 0x03, 0x75, 0x18, 0x1b, 0x08, 0xea, 0x2f, 0x13, 0x7b, 0xf6, + 0x0e, 0x5d, 0x89, 0x91, 0x01, 0x05, 0xc3, 0x21, 0xf6, 0x9d, 0xbf, 0x9f, + 0x18, 0xb8, 0x1a, 0xd9, 0x01, 0x07, 0xb6, 0xd8, 0x7a, 0xb5, 0xfd, 0x30, + 0xff, 0x7d, 0x25, 0x32, 0x43, 0x70, 0xce, 0x4e, 0x7a, 0xf1, 0x78, 0xd6, + 0xe9, 0xd4, 0x92, 0x3e, 0x0c, 0x65, 0xbf, 0xce, 0x79, 0x13, 0xd9, 0x01, + 0x0c, 0x26, 0xfe, 0x9a, 0xbf, 0x65, 0x1c, 0xb7, 0x2b, 0xf9, 0xd8, 0x41, + 0xcc, 0x0e, 0x10, 0x4f, 0x5b, 0xd0, 0x95, 0x72, 0x60, 0x85, 0x8d, 0xeb, + 0x29, 0x3e, 0x6b, 0xa1, 0xcd, 0x17, 0xe4, 0x0a, 0xbe, 0x07, 0x88, 0xbd, + 0x47, 0xe9, 0x03, 0x51, 0xda, 0xbf, 0x8e, 0xff, 0x33, 0xd6, 0x88, 0x7f, + 0x1c, 0x0b, 0xe3, 0x7b, 0x63, 0x1a, 0xfe, 0x81, 0xb8, 0xf4, 0xf4, 0xd8, + 0x54, 0xff, 0xbf, 0x9b, 0xe3, 0x13, 0x1f, 0x34, 0xb0, 0x2e, 0x55, 0x84, + 0x0d, 0x03, 0xa5, 0xe8, 0x1e, 0xa8, 0x0f, 0x1f, 0xa2, 0xdd, 0x7c, 0x4f, + 0xff, 0x1c, 0xc6, 0xab, 0x29, 0x83, 0xfe, 0xbb, 0x89, 0xf7, 0x37, 0x0f, + 0xd4, 0x53, 0xef, 0x96, 0xa5, 0x46, 0x1a, 0x9a, 0x27, 0x88, 0x59, 0x93, + 0xbe, 0x60, 0x60, 0x5c, 0x0d, 0x06, 0x62, 0x70, 0x21, 0xd1, 0xa8, 0xc2, + 0x9c, 0x1e, 0xcc, 0x98, 0xc4, 0x4d, 0x9f, 0x76, 0xb5, 0x22, 0xd8, 0x66, + 0xaa, 0x06, 0x6d, 0x8e, 0x78, 0xa7, 0xc6, 0xe8, 0x13, 0xa5, 0xf8, 0x60, + 0x20, 0xd8, 0x63, 0xaa, 0x77, 0xc1, 0xac, 0xb6, 0xac, 0xef, 0x44, 0xd0, + 0x71, 0x85, 0x81, 0xd8, 0x74, 0x62, 0xc8, 0xd5, 0xc6, 0x12, 0x10, 0x9f, + 0x71, 0x2a, 0xa9, 0xf9, 0x7f, 0xa2, 0xdc, 0x8d, 0xaf, 0xb7, 0x05, 0x03, + 0x01, 0xb5, 0xc1, 0xdc, 0xad, 0x36, 0xd3, 0xd4, 0x11, 0xf0, 0x1b, 0xb7, + 0x61, 0x8d, 0x3d, 0x56, 0x05, 0x5e, 0x2d, 0x86, 0xee, 0x14, 0x2b, 0xf9, + 0xea, 0xdb, 0xfb, 0xd4, 0xfa, 0x33, 0xba, 0x1a, 0x3c, 0xda, 0xa6, 0x12, + 0x2f, 0xe6, 0x9e, 0xb2, 0x02, 0x35, 0x96, 0xd5, 0x34, 0x57, 0xda, 0x0c, + 0xa0, 0x9a, 0x73, 0x53, 0xc5, 0xb9, 0x69, 0x1a, 0x2d, 0xc5, 0xbb, 0x03, + 0x30, 0xaf, 0x30, 0x82, 0xad, 0x0f, 0xaa, 0xa5, 0x78, 0x67, 0xa8, 0x14, + 0x6f, 0x0e, 0x38, 0x71, 0x72, 0xc0, 0xb2, 0xee, 0xd5, 0x2b, 0x51, 0x14, + 0xc1, 0xf4, 0x22, 0x84, 0x4e, 0x0f, 0xc2, 0xc4, 0xef, 0x59, 0xf6, 0x37, + 0x03, 0x7e, 0xfc, 0xdb, 0xc0, 0x67, 0xf0, 0x74, 0x75, 0xec, 0xd8, 0x34, + 0xf8, 0x70, 0x86, 0x73, 0x7e, 0x2a, 0x11, 0x6c, 0xaf, 0x75, 0x04, 0xd7, + 0x00, 0x0d, 0xab, 0x1e, 0x56, 0x82, 0xf1, 0x97, 0x95, 0x60, 0x20, 0xa9, + 0xf8, 0xf0, 0x1e, 0x6d, 0xeb, 0x44, 0xb6, 0xbe, 0xf9, 0x35, 0xb6, 0xff, + 0x5b, 0xfd, 0x7b, 0xd6, 0x78, 0x8d, 0xe8, 0x50, 0xf4, 0x45, 0x9d, 0xa7, + 0xa8, 0x73, 0xe2, 0xee, 0xf7, 0x52, 0xd4, 0x39, 0xfb, 0xf3, 0xf4, 0x1f, + 0xe0, 0xa0, 0xcc, 0x57, 0x33, 0x7d, 0xfd, 0x2a, 0xfc, 0x9d, 0x3d, 0xb6, + 0x63, 0xd6, 0xff, 0xf0, 0xc9, 0xf8, 0x7e, 0x34, 0x3d, 0xe7, 0xe3, 0x32, + 0xce, 0xa3, 0x56, 0xdc, 0x2b, 0x63, 0x94, 0xb1, 0xda, 0xba, 0x0c, 0x74, + 0x28, 0xd3, 0x55, 0x94, 0x5a, 0xd6, 0x56, 0x3d, 0xff, 0xdc, 0x57, 0x18, + 0xeb, 0xbf, 0xd2, 0x0e, 0x64, 0xbc, 0x6b, 0x1d, 0xa2, 0xfb, 0x80, 0xfa, + 0xaa, 0xf8, 0xbf, 0x19, 0x43, 0xb9, 0x47, 0x62, 0x60, 0xec, 0xfc, 0xf5, + 0x53, 0x15, 0x17, 0x3f, 0xa7, 0x6d, 0xd9, 0xed, 0xfd, 0x3b, 0xaf, 0x65, + 0x2c, 0xaf, 0xd0, 0x6e, 0xc4, 0x4e, 0x38, 0x9d, 0x86, 0xd8, 0xcc, 0xa5, + 0xf6, 0x22, 0xb6, 0xd2, 0x48, 0xbb, 0xfa, 0x17, 0x62, 0x62, 0x07, 0x9e, + 0xbc, 0xde, 0x2d, 0xd3, 0x1c, 0x70, 0x18, 0x26, 0x3e, 0x1f, 0x75, 0xe0, + 0xab, 0x51, 0x05, 0xd3, 0xb4, 0x60, 0x06, 0xaa, 0x69, 0x55, 0x91, 0x5b, + 0x6c, 0xe8, 0x4d, 0x63, 0xc3, 0x18, 0x50, 0xd9, 0x0b, 0x77, 0x85, 0x61, + 0xe0, 0xa5, 0x24, 0xdc, 0x65, 0xf4, 0xcb, 0x2f, 0x27, 0xeb, 0xc7, 0xdf, + 0x56, 0x82, 0xb1, 0xd7, 0xa9, 0x4f, 0xea, 0xb5, 0xcd, 0xaf, 0x04, 0x5b, + 0x57, 0x2b, 0xc1, 0xe6, 0xd9, 0x0a, 0xdc, 0x0a, 0xcb, 0x85, 0xb3, 0x69, + 0xa4, 0xc6, 0xe4, 0x77, 0x33, 0x66, 0x65, 0xfb, 0xf2, 0x7d, 0x14, 0x3f, + 0x06, 0x8e, 0xd0, 0xbf, 0x87, 0x9a, 0x15, 0xe2, 0xc9, 0x3b, 0x56, 0xcc, + 0x47, 0xf9, 0x29, 0xb8, 0x4b, 0x59, 0xe7, 0xb6, 0x64, 0x1a, 0x8c, 0x99, + 0xee, 0x12, 0xd6, 0xb9, 0x36, 0x09, 0x78, 0x7a, 0x05, 0xf3, 0x83, 0x81, + 0x6b, 0x94, 0xfa, 0xf6, 0xa4, 0x12, 0x0c, 0xdf, 0xae, 0x34, 0xe8, 0x4f, + 0x90, 0xb7, 0x6c, 0x40, 0xae, 0x8d, 0x50, 0x36, 0x27, 0xbf, 0x3e, 0x0b, + 0x65, 0x46, 0x12, 0x9e, 0x5a, 0x6d, 0x26, 0xce, 0x4e, 0xb3, 0xdb, 0x51, + 0x2a, 0x93, 0x01, 0x3b, 0x96, 0x56, 0x8e, 0x00, 0x2f, 0xf5, 0x5b, 0x38, + 0x14, 0xa9, 0xa7, 0xbf, 0xb5, 0xc1, 0xcf, 0x32, 0x39, 0x5b, 0xb4, 0xb1, + 0x42, 0xe9, 0x49, 0xd0, 0xe9, 0xa6, 0xcb, 0xa5, 0x0f, 0xf1, 0xcf, 0x23, + 0x26, 0xf7, 0x76, 0x26, 0xa0, 0xf4, 0x26, 0x82, 0x3b, 0x01, 0x6d, 0x4d, + 0x95, 0x23, 0xf6, 0x40, 0x25, 0x3a, 0x31, 0x11, 0x09, 0xc5, 0x07, 0x95, + 0x50, 0x7b, 0xbf, 0xa2, 0xbb, 0xb7, 0xb0, 0xbd, 0xcd, 0x2c, 0xb3, 0x81, + 0x9f, 0x45, 0x21, 0xad, 0xf5, 0x43, 0xc4, 0xae, 0x2d, 0x61, 0x99, 0x43, + 0x7a, 0xe8, 0xcc, 0x6e, 0x84, 0x8e, 0xfe, 0xda, 0xa1, 0xbb, 0x1f, 0xcd, + 0x8a, 0xac, 0x66, 0x65, 0x68, 0xf4, 0x26, 0x35, 0xe7, 0xfb, 0xff, 0x33, + 0xaf, 0x83, 0xaf, 0xcb, 0xb5, 0xdd, 0xb6, 0x33, 0x79, 0xb4, 0xf4, 0x0f, + 0xef, 0x71, 0x92, 0x2e, 0xba, 0xd7, 0xe0, 0x1d, 0xa2, 0xdf, 0x38, 0xb4, + 0x12, 0xfa, 0xb9, 0xf0, 0x95, 0x58, 0xd8, 0x05, 0xb9, 0xe7, 0x40, 0xc6, + 0x19, 0xf3, 0x3b, 0xf0, 0x9f, 0x56, 0x6c, 0x99, 0xdc, 0x2b, 0x45, 0xbc, + 0xad, 0xc1, 0xef, 0x44, 0x43, 0xf3, 0x7a, 0xfa, 0xf0, 0xe4, 0xb2, 0x05, + 0x7c, 0x16, 0xd2, 0x0f, 0xa1, 0x3e, 0xb0, 0x1e, 0xf2, 0xfb, 0x2c, 0x6d, + 0x6d, 0x81, 0xd4, 0x65, 0x99, 0x1c, 0x27, 0x13, 0x8c, 0x58, 0xa7, 0x5b, + 0x78, 0x56, 0x87, 0x59, 0x6c, 0x1c, 0x50, 0x8e, 0x27, 0x7e, 0x6f, 0xc5, + 0x9c, 0x58, 0x42, 0x7f, 0xd2, 0x35, 0x05, 0x01, 0xb7, 0x11, 0x0a, 0x1c, + 0x25, 0xfb, 0xa4, 0x6d, 0x28, 0x93, 0xd9, 0x75, 0xca, 0x5b, 0xd9, 0x1e, + 0xe5, 0x44, 0x56, 0xea, 0x1e, 0x50, 0xde, 0xcc, 0x4a, 0xec, 0xa9, 0x0b, + 0x1c, 0x61, 0x2c, 0x65, 0x1c, 0x57, 0xbb, 0xc9, 0xda, 0x36, 0xe8, 0x15, + 0xe4, 0x8e, 0x5a, 0x78, 0x90, 0xfd, 0xdd, 0x13, 0x85, 0xbe, 0x51, 0x77, + 0x61, 0xd2, 0x0b, 0x4f, 0xb7, 0xee, 0x94, 0x6b, 0xc6, 0x34, 0xa9, 0x5b, + 0x17, 0x58, 0x9f, 0x3d, 0x47, 0xbf, 0xc8, 0x5d, 0xef, 0x89, 0x16, 0xee, + 0x7d, 0x64, 0x8d, 0x2f, 0x53, 0x79, 0xfd, 0xa2, 0x8c, 0x9b, 0x75, 0xa7, + 0x72, 0x45, 0x89, 0xdb, 0x2a, 0xb9, 0x69, 0x15, 0x4c, 0x6f, 0xd0, 0xcc, + 0x60, 0x09, 0x7d, 0xe7, 0x30, 0xb9, 0xac, 0x9f, 0x71, 0x69, 0x09, 0xb1, + 0x54, 0x78, 0x98, 0xc2, 0xe7, 0x1e, 0xdc, 0x92, 0xf8, 0x87, 0x3c, 0xc7, + 0x65, 0x6c, 0xae, 0x71, 0x08, 0x9f, 0xf4, 0xca, 0xdc, 0x1e, 0x4c, 0x4d, + 0xe5, 0x7e, 0x75, 0x81, 0x93, 0xec, 0x77, 0x89, 0xa6, 0x85, 0x4b, 0x94, + 0xba, 0xc0, 0x5b, 0xd9, 0x25, 0xf4, 0xcd, 0x77, 0xd9, 0xae, 0x07, 0x6f, + 0x25, 0x2a, 0xc8, 0x6b, 0x83, 0x31, 0x93, 0x02, 0x6f, 0x25, 0x2f, 0x20, + 0xbf, 0x98, 0xf2, 0xd7, 0x06, 0xc6, 0x5a, 0x89, 0x87, 0xea, 0xa2, 0x79, + 0xcd, 0x58, 0x95, 0x85, 0x73, 0x65, 0xd4, 0xc0, 0xbd, 0x8c, 0xa3, 0xf7, + 0x33, 0x36, 0xad, 0x66, 0xdc, 0xd9, 0x12, 0xe1, 0xd8, 0xaa, 0x2c, 0xab, + 0x58, 0xeb, 0x14, 0x8e, 0x8c, 0x24, 0xe3, 0xde, 0x3d, 0x9a, 0x13, 0xeb, + 0xf8, 0xfb, 0xc5, 0xec, 0x7f, 0x58, 0xf7, 0x93, 0xa3, 0x3f, 0x7b, 0x91, + 0x4c, 0xa8, 0x43, 0x5a, 0x43, 0x78, 0x3d, 0xe3, 0x1e, 0xe5, 0x9a, 0x15, + 0x86, 0x65, 0x5d, 0x1b, 0x0a, 0xc6, 0x5c, 0x8a, 0x8e, 0x43, 0x23, 0x93, + 0x56, 0x60, 0xba, 0xf0, 0xf3, 0x42, 0x6c, 0x90, 0xb1, 0x16, 0xf8, 0x9f, + 0x70, 0xbd, 0xa9, 0x3e, 0xad, 0xe2, 0xd6, 0x01, 0xe1, 0xa6, 0x7e, 0x2c, + 0x4d, 0x7c, 0x0b, 0x87, 0x1a, 0x9d, 0x68, 0x25, 0x6f, 0x5f, 0x94, 0xf0, + 0xe0, 0x2e, 0x62, 0xe0, 0xe2, 0x44, 0x31, 0xe7, 0xc6, 0x87, 0xdb, 0x12, + 0x4e, 0x1c, 0x6e, 0x9c, 0x06, 0xd3, 0x57, 0x8c, 0xf7, 0x74, 0x07, 0x8e, + 0xe8, 0x5e, 0x64, 0x6c, 0x7f, 0xd8, 0x42, 0xec, 0x0a, 0xe6, 0xf9, 0xa2, + 0xe8, 0xd0, 0x41, 0x7d, 0xaa, 0x88, 0x9f, 0xd7, 0xe1, 0xe5, 0xb8, 0x60, + 0x81, 0x07, 0x7e, 0x68, 0xc5, 0xa7, 0x4b, 0x7d, 0x98, 0x1e, 0x43, 0xc6, + 0x21, 0x5c, 0x4a, 0x47, 0xf7, 0x48, 0x8c, 0x9c, 0x67, 0xea, 0x50, 0x4f, + 0x93, 0xc7, 0x55, 0xe2, 0x75, 0x4d, 0x78, 0xdc, 0x2b, 0xf0, 0xd2, 0x77, + 0x7b, 0x46, 0x42, 0x1d, 0xa7, 0x15, 0x07, 0x5e, 0xd4, 0x2a, 0xe2, 0x6e, + 0xfa, 0xf4, 0xc6, 0x11, 0x38, 0xd7, 0xcf, 0xd3, 0xd1, 0x3b, 0xd2, 0xd5, + 0x5c, 0x0e, 0x12, 0x9b, 0x79, 0x39, 0xfe, 0xf1, 0x65, 0xea, 0x76, 0x45, + 0xc4, 0xe6, 0x1f, 0xb9, 0xd8, 0xeb, 0xb5, 0x2c, 0xe6, 0x0c, 0xd4, 0x33, + 0xb0, 0x2f, 0xaf, 0xe3, 0x3d, 0xfc, 0xdd, 0x93, 0xd7, 0xf1, 0x3a, 0xca, + 0xa3, 0xff, 0x61, 0xc3, 0x45, 0x9c, 0x21, 0x80, 0x62, 0x43, 0x30, 0x88, + 0xf8, 0x49, 0x3c, 0x89, 0x51, 0xc7, 0xcf, 0x65, 0x7f, 0xc7, 0xb1, 0x06, + 0x39, 0xdd, 0x62, 0x4f, 0x8c, 0x85, 0xea, 0x67, 0x1c, 0xc4, 0x55, 0xea, + 0x41, 0xf4, 0x2c, 0xfa, 0xb5, 0xac, 0x7e, 0x5d, 0x74, 0x2c, 0xfa, 0x16, + 0xbd, 0xe7, 0xf0, 0x93, 0x7c, 0xbf, 0x07, 0x48, 0xb3, 0xac, 0x83, 0x78, + 0x69, 0xe0, 0xbb, 0x6d, 0x62, 0x3b, 0xe5, 0x76, 0x8c, 0x9b, 0x33, 0xd3, + 0xb2, 0x9e, 0x8a, 0x04, 0xf0, 0xbe, 0xd6, 0xd0, 0xdc, 0xa4, 0x06, 0xd9, + 0xd7, 0x25, 0x48, 0x8c, 0xc5, 0x38, 0x77, 0x57, 0x93, 0x87, 0x8b, 0xad, + 0xa1, 0xa3, 0xc8, 0xc6, 0x5c, 0xe0, 0x44, 0x42, 0x0b, 0x6f, 0xe0, 0x9c, + 0xed, 0xf6, 0x2d, 0x23, 0x67, 0x52, 0x5b, 0x98, 0xb5, 0x90, 0xab, 0x68, + 0xe6, 0x26, 0xbc, 0x6b, 0x65, 0x7c, 0x16, 0xe3, 0x9b, 0x0a, 0xa7, 0x36, + 0x03, 0x87, 0xbd, 0x0e, 0x3c, 0x1f, 0xae, 0x41, 0xac, 0x4a, 0x41, 0x99, + 0xf6, 0x4b, 0xeb, 0x05, 0x9f, 0xb4, 0xc3, 0x7c, 0x43, 0xfd, 0x39, 0xfb, + 0xad, 0xb0, 0x8c, 0xc8, 0x5d, 0x86, 0xae, 0xb1, 0x4b, 0xdb, 0xff, 0x85, + 0x35, 0xe9, 0x93, 0xf6, 0x83, 0xde, 0x80, 0xfa, 0x49, 0x73, 0xf8, 0xaa, + 0xf5, 0x5a, 0x4e, 0xa6, 0x1d, 0x7f, 0xa0, 0x8a, 0xbc, 0xc7, 0x39, 0x3e, + 0x91, 0x59, 0x68, 0x47, 0xfc, 0x6c, 0x3f, 0xef, 0xc9, 0x33, 0xb1, 0x91, + 0x75, 0x6c, 0xf7, 0x90, 0x85, 0x1a, 0xb9, 0xde, 0x6c, 0x97, 0x35, 0xc7, + 0x26, 0x16, 0x3b, 0x31, 0x1f, 0xb3, 0x22, 0x0b, 0x16, 0xca, 0x58, 0x54, + 0x23, 0x16, 0x70, 0xc3, 0xac, 0x71, 0x10, 0x8b, 0xdf, 0x6e, 0x6c, 0xc4, + 0xc2, 0xec, 0xa4, 0xf5, 0x2e, 0xc1, 0xa5, 0x4b, 0x73, 0x60, 0x9c, 0xe3, + 0xdb, 0xaf, 0x4b, 0x6e, 0x68, 0x61, 0x51, 0xc4, 0x8c, 0xd3, 0x63, 0xcd, + 0x72, 0xda, 0x4e, 0xa9, 0x26, 0xf1, 0xb9, 0x02, 0x65, 0x86, 0x33, 0xfc, + 0x2e, 0x82, 0xfa, 0x16, 0xf2, 0x93, 0x40, 0xd5, 0xac, 0x66, 0x17, 0xb5, + 0xfb, 0x52, 0x22, 0xd4, 0x7c, 0x44, 0xc9, 0xf9, 0xc3, 0x73, 0x9c, 0xdb, + 0xd7, 0x13, 0xda, 0x9a, 0x62, 0x47, 0xee, 0xfa, 0xe5, 0xac, 0xe4, 0x23, + 0x05, 0x7f, 0xf0, 0xe7, 0x71, 0xc3, 0xed, 0x3e, 0x91, 0xc0, 0x69, 0x95, + 0xf8, 0x53, 0x65, 0xe0, 0x74, 0xb7, 0x9e, 0x51, 0x5c, 0x5a, 0x05, 0x71, + 0x55, 0xb0, 0xb4, 0x88, 0x31, 0x41, 0x62, 0xb6, 0xdb, 0xfd, 0x2e, 0xcb, + 0x2c, 0x8e, 0x60, 0x32, 0x7c, 0x63, 0x43, 0xb3, 0x1b, 0x31, 0xb3, 0x98, + 0x7e, 0x59, 0x6e, 0xf8, 0xdc, 0x73, 0x46, 0xcd, 0x1a, 0x0f, 0xed, 0xba, + 0xcc, 0x40, 0xcb, 0xac, 0xde, 0xd6, 0x4a, 0x54, 0x34, 0x62, 0xf5, 0x88, + 0xe4, 0x96, 0x7d, 0x35, 0x2a, 0xfb, 0xea, 0xd2, 0xca, 0xe1, 0xaa, 0x5e, + 0x3d, 0x5f, 0x35, 0x7e, 0x80, 0xb6, 0xa8, 0xbb, 0x45, 0x1f, 0x9d, 0x9a, + 0xe3, 0x08, 0x46, 0x9a, 0x35, 0x95, 0xc4, 0xc7, 0x0a, 0x43, 0xf2, 0x9b, + 0x40, 0xcb, 0xcb, 0x36, 0x7e, 0x7a, 0xc9, 0xc7, 0x7f, 0xe6, 0xff, 0xf3, + 0xeb, 0x3c, 0x4f, 0x1d, 0x4b, 0x9b, 0xf2, 0x2d, 0xb9, 0x26, 0x9c, 0xcc, + 0x1d, 0xd1, 0x35, 0xec, 0x61, 0x7e, 0x21, 0x73, 0x03, 0x77, 0x91, 0x11, + 0xfe, 0xcb, 0x67, 0xe9, 0x17, 0x2e, 0xea, 0x78, 0x93, 0x66, 0x12, 0xce, + 0x2d, 0x4b, 0x8b, 0x04, 0xfd, 0x45, 0x4a, 0x00, 0x1b, 0x1b, 0x7f, 0x47, + 0x5b, 0x00, 0xf1, 0x0a, 0x24, 0xab, 0x35, 0x58, 0x37, 0x5c, 0x31, 0xa5, + 0xde, 0xbe, 0xf3, 0xf5, 0x92, 0x9a, 0x19, 0x97, 0x7a, 0x43, 0x91, 0x60, + 0xfb, 0x06, 0xd6, 0xdb, 0xcc, 0x7a, 0x31, 0xc6, 0xc8, 0x7b, 0xe9, 0x9b, + 0x2e, 0xe6, 0x37, 0xeb, 0x99, 0xeb, 0x4c, 0x69, 0xef, 0xaf, 0x0a, 0xf5, + 0x1e, 0xd5, 0xcc, 0x71, 0xbb, 0xbd, 0xb9, 0xc1, 0x35, 0x45, 0x8e, 0x00, + 0x7a, 0x59, 0x6f, 0x9c, 0xf5, 0xde, 0x1a, 0xa9, 0xce, 0x97, 0x77, 0x62, + 0xc3, 0xac, 0x5c, 0xd9, 0x1e, 0xcd, 0xf4, 0x4b, 0x59, 0x67, 0x24, 0xd8, + 0x7c, 0x1f, 0xb1, 0xba, 0x4b, 0xda, 0x60, 0xdf, 0xde, 0xb2, 0xe3, 0x0a, + 0x6e, 0x7a, 0x21, 0x91, 0x9a, 0x74, 0x6a, 0x5a, 0xdb, 0x4a, 0x25, 0xa6, + 0x2c, 0x9e, 0x67, 0xcf, 0xef, 0x4d, 0xc7, 0xb2, 0x9d, 0xd8, 0xa8, 0x4d, + 0x44, 0x8a, 0x59, 0xef, 0x88, 0x36, 0xe1, 0x77, 0xd1, 0xd7, 0x56, 0xb2, + 0xed, 0x2e, 0xe6, 0x15, 0x2a, 0x7d, 0x7b, 0xdd, 0xb0, 0xf0, 0x01, 0x9d, + 0x7c, 0xa3, 0x8e, 0x76, 0x28, 0xfa, 0x91, 0x36, 0x65, 0x9e, 0x45, 0x17, + 0xc1, 0xf0, 0xb0, 0xad, 0x0b, 0xa5, 0x7a, 0x5f, 0x23, 0x8d, 0xa5, 0x8a, + 0xfc, 0xab, 0x51, 0x62, 0xa2, 0x42, 0x3c, 0xbe, 0x12, 0x1b, 0xec, 0x3c, + 0xad, 0x8e, 0x5c, 0xc7, 0xb2, 0xf6, 0xe8, 0x96, 0xf5, 0xac, 0x3e, 0x03, + 0xfb, 0xf4, 0x60, 0x5c, 0x6c, 0xf3, 0x97, 0xfa, 0x82, 0x6b, 0x5d, 0x08, + 0x32, 0xe1, 0xff, 0x14, 0xc6, 0x69, 0x2f, 0x25, 0x9a, 0xf8, 0xa0, 0x02, + 0x7f, 0xc8, 0x19, 0x28, 0x53, 0x2c, 0xb8, 0xe7, 0xce, 0x5c, 0x33, 0x93, + 0x7a, 0xaa, 0xb8, 0x51, 0xc1, 0x07, 0x73, 0x14, 0x4c, 0xcc, 0x09, 0xf9, + 0x07, 0x95, 0x72, 0xe2, 0x6d, 0xa8, 0xad, 0x45, 0x31, 0x8f, 0xb2, 0x6e, + 0xac, 0xd1, 0xc1, 0x7c, 0x5a, 0xa9, 0x24, 0x16, 0xcc, 0x0a, 0x08, 0x1d, + 0x70, 0x26, 0x43, 0xfe, 0xcd, 0xfc, 0x76, 0x8c, 0x28, 0x18, 0xd1, 0x82, + 0x31, 0xd8, 0xf2, 0xd9, 0x76, 0x44, 0xc1, 0x75, 0x21, 0xcb, 0x3a, 0x16, + 0x69, 0xf0, 0x1e, 0xc3, 0x2f, 0x2d, 0x59, 0x4b, 0xf1, 0x87, 0xce, 0xe7, + 0x06, 0x28, 0x4d, 0x6a, 0xb1, 0x16, 0x65, 0xbb, 0x53, 0x38, 0xc5, 0xaa, + 0xac, 0xc4, 0xc8, 0x42, 0x7f, 0x0b, 0xb1, 0xd2, 0xb2, 0x7e, 0xa9, 0xe7, + 0x64, 0x79, 0xa3, 0xc2, 0xcd, 0x66, 0x60, 0x4c, 0x0b, 0xb6, 0x8e, 0x53, + 0x07, 0x7e, 0xfa, 0x60, 0x2d, 0xe7, 0x7d, 0xd2, 0x15, 0xf4, 0x4e, 0x2a, + 0x0b, 0xcf, 0xaa, 0x98, 0xbd, 0xea, 0x31, 0xa5, 0xa1, 0xa3, 0x04, 0x5a, + 0x6c, 0x54, 0xb9, 0x82, 0x3a, 0x31, 0xfd, 0x1e, 0x04, 0xbd, 0x2b, 0x61, + 0xc7, 0x6d, 0xdc, 0x9e, 0x70, 0xc6, 0xce, 0xa0, 0x9e, 0xfe, 0xa0, 0xb5, + 0xdf, 0x4f, 0x6e, 0x07, 0x7c, 0x96, 0x84, 0x5f, 0xfa, 0x5a, 0x83, 0xf8, + 0x5f, 0x58, 0xd6, 0x03, 0xec, 0xeb, 0x16, 0xf6, 0x75, 0x75, 0xe4, 0x7d, + 0xeb, 0x17, 0xb6, 0xcc, 0x9b, 0x31, 0xa8, 0x5d, 0x2a, 0xf7, 0x3d, 0x0b, + 0xd3, 0x45, 0xae, 0x0b, 0xb7, 0x4e, 0x67, 0xee, 0x11, 0x15, 0x2c, 0x79, + 0x84, 0xf9, 0xb9, 0xc8, 0x63, 0x5c, 0x51, 0x2f, 0x8d, 0xcd, 0x0e, 0x30, + 0xe6, 0xf9, 0xe3, 0x8a, 0x5a, 0x57, 0x06, 0x2f, 0xdc, 0x9a, 0x85, 0x07, + 0xc9, 0x23, 0x62, 0xd3, 0x2b, 0xf1, 0x90, 0xee, 0x46, 0x79, 0x48, 0xbd, + 0xd2, 0xc1, 0x39, 0xd9, 0x17, 0x91, 0x6b, 0x17, 0xc6, 0xa7, 0x3b, 0xd0, + 0x49, 0x7e, 0xe1, 0x0d, 0xa9, 0xb5, 0x72, 0xdf, 0xdd, 0x24, 0xd7, 0xec, + 0xff, 0x15, 0x0a, 0x1e, 0xa0, 0x55, 0xa8, 0xa1, 0x2e, 0xbf, 0xdc, 0x6f, + 0xd5, 0xe5, 0x5a, 0x41, 0x7d, 0xc4, 0xc9, 0x79, 0xb1, 0xe0, 0x60, 0xdf, + 0x4b, 0x43, 0xbc, 0x1f, 0x91, 0xdf, 0xb1, 0x07, 0x38, 0xee, 0xd8, 0x6e, + 0x45, 0xb0, 0xe7, 0xc7, 0xd6, 0xf3, 0x8c, 0x2d, 0x5e, 0x3e, 0x7f, 0x88, + 0x6d, 0x1f, 0x8d, 0x3c, 0x6b, 0xd5, 0x12, 0x73, 0x8f, 0x35, 0x07, 0x30, + 0x63, 0x4e, 0x1d, 0x26, 0xef, 0x96, 0x31, 0x2b, 0x28, 0xd7, 0xca, 0x5d, + 0x92, 0xe7, 0x55, 0x68, 0x57, 0xe0, 0xd6, 0xbb, 0x72, 0xf7, 0x4a, 0x28, + 0x2f, 0x4c, 0xdc, 0x2d, 0x99, 0x53, 0x8d, 0x40, 0xfe, 0xde, 0xc2, 0x90, + 0xb3, 0xad, 0x5c, 0xd1, 0xbc, 0xb7, 0x2b, 0xf2, 0xfc, 0x37, 0xb4, 0x71, + 0xcb, 0x7a, 0x90, 0xf3, 0x35, 0x2b, 0xe2, 0xc1, 0x29, 0xb6, 0xd3, 0x45, + 0xfd, 0x2d, 0x39, 0x3f, 0x5f, 0x85, 0xfa, 0xbf, 0xb6, 0x02, 0x7f, 0x21, + 0x75, 0x45, 0xc6, 0xcc, 0xd6, 0x5b, 0x95, 0xe7, 0x9c, 0x92, 0x33, 0xac, + 0x8e, 0xd8, 0x3a, 0x63, 0xd9, 0x5a, 0x97, 0x5c, 0x7b, 0xa3, 0xaf, 0x9f, + 0x5f, 0x7f, 0x39, 0x6d, 0xc7, 0xa8, 0x05, 0x37, 0x7a, 0x31, 0x69, 0x55, + 0x35, 0x99, 0xde, 0x62, 0x48, 0xac, 0xaa, 0x0f, 0x3f, 0x45, 0xb9, 0xaf, + 0xe9, 0xb9, 0x38, 0xb6, 0x47, 0x0f, 0xa6, 0x4d, 0xfa, 0x43, 0x9c, 0x39, + 0x5f, 0x8b, 0xbd, 0x56, 0xb4, 0x87, 0xf3, 0x30, 0x03, 0xc5, 0x4d, 0xc1, + 0x9e, 0x6b, 0x98, 0x03, 0x39, 0xa2, 0x12, 0xff, 0x64, 0x7e, 0xec, 0x32, + 0x6c, 0xab, 0x04, 0x0b, 0xd9, 0xc7, 0x48, 0xd3, 0x1f, 0x8b, 0x1d, 0x22, + 0x47, 0xac, 0x33, 0xd8, 0x13, 0xc3, 0x1f, 0x2b, 0x0b, 0x46, 0x6a, 0xc4, + 0x1d, 0x86, 0xfb, 0xa6, 0x78, 0x56, 0x25, 0xf7, 0x28, 0xf2, 0x76, 0x45, + 0x6b, 0xf8, 0x91, 0xe7, 0xce, 0x9b, 0x56, 0x64, 0xcf, 0xaf, 0x29, 0x21, + 0xad, 0x17, 0x41, 0xbd, 0x4e, 0x70, 0x9c, 0x88, 0xec, 0x95, 0xf1, 0x99, + 0xcd, 0x5e, 0x3b, 0x87, 0x5e, 0xfb, 0x85, 0x7b, 0xb4, 0xa0, 0xfe, 0x26, + 0x5b, 0x3c, 0x4c, 0x8e, 0x63, 0xda, 0x9e, 0x21, 0xbe, 0x3e, 0x15, 0x47, + 0x25, 0xae, 0x88, 0x4c, 0xc1, 0xd0, 0x2b, 0xd1, 0xb7, 0xa3, 0x03, 0x81, + 0x9a, 0x1c, 0x66, 0xb9, 0x8c, 0xb9, 0xd8, 0x93, 0xde, 0xec, 0xca, 0xf1, + 0xf2, 0x4e, 0x3c, 0x45, 0x4c, 0xdb, 0xb8, 0x63, 0xa2, 0xb6, 0x8a, 0xba, + 0xea, 0xd0, 0x1b, 0xf4, 0xd3, 0xb8, 0x83, 0x7e, 0x2e, 0x65, 0x27, 0xbe, + 0x52, 0x05, 0x29, 0x67, 0xe1, 0x48, 0xa4, 0x06, 0xc9, 0x1d, 0x9f, 0x46, + 0x66, 0xba, 0xdc, 0x97, 0x7b, 0x6e, 0xe2, 0xb0, 0x0f, 0xeb, 0x77, 0xf8, + 0x91, 0xf1, 0xc9, 0x5a, 0x99, 0xac, 0x57, 0x0a, 0x36, 0xbf, 0x61, 0x99, + 0x5e, 0xe9, 0x87, 0xc4, 0xf7, 0x50, 0x73, 0x37, 0x63, 0x9a, 0xd7, 0x88, + 0x11, 0x3f, 0xc8, 0x3d, 0x46, 0x7f, 0x62, 0x65, 0x6c, 0x0e, 0xef, 0x36, + 0x85, 0x23, 0x3d, 0xab, 0x35, 0xc4, 0x8e, 0xb0, 0x07, 0xf1, 0xec, 0x7f, + 0xd2, 0x47, 0x9c, 0xb8, 0x47, 0xfb, 0xb8, 0xfe, 0x7b, 0xd8, 0x3f, 0xb8, + 0x9d, 0xc4, 0x76, 0xf2, 0x48, 0x62, 0x70, 0xc8, 0x25, 0x31, 0xbf, 0x88, + 0xed, 0x6f, 0xd9, 0xa1, 0xa0, 0x85, 0x18, 0xb8, 0x99, 0x36, 0xf5, 0x40, + 0x08, 0xce, 0xd6, 0x39, 0xe4, 0x35, 0xf8, 0x02, 0x73, 0x1a, 0x1f, 0x36, + 0x0d, 0x63, 0x6e, 0x56, 0x1b, 0xaf, 0xf5, 0xa0, 0xc7, 0x25, 0xdc, 0xd6, + 0x24, 0xde, 0xe7, 0xe4, 0xec, 0xbb, 0x44, 0x4e, 0x0d, 0x1e, 0xcd, 0xcb, + 0xd9, 0x49, 0x39, 0x9f, 0x9e, 0x05, 0x67, 0xc5, 0xa7, 0x65, 0x2e, 0x17, + 0xd2, 0xbf, 0x6a, 0x90, 0xb2, 0xe3, 0x04, 0x79, 0xe0, 0x67, 0xa0, 0x68, + 0x33, 0x25, 0x67, 0x58, 0x6a, 0xd7, 0xbb, 0xa5, 0x71, 0xfc, 0x4c, 0x15, + 0xc1, 0xf5, 0xf4, 0xac, 0x71, 0x3a, 0x72, 0x41, 0x27, 0xde, 0x42, 0x5f, + 0xff, 0xea, 0x42, 0x1b, 0x1c, 0x33, 0xed, 0xcb, 0x1d, 0x95, 0xbe, 0x3d, + 0x6e, 0xb5, 0x7a, 0x73, 0x73, 0x95, 0xd8, 0x11, 0x0c, 0xb4, 0x51, 0xe7, + 0x5b, 0xf4, 0xfa, 0xb6, 0x34, 0x29, 0xcc, 0x03, 0x73, 0x3e, 0x4d, 0xdf, + 0xf7, 0x63, 0xf3, 0x30, 0x6e, 0x18, 0xd1, 0x24, 0xc6, 0x8c, 0x07, 0xcb, + 0x2f, 0x9a, 0x83, 0xab, 0xa9, 0xef, 0x6a, 0xca, 0x27, 0xbf, 0x9b, 0x55, + 0xe8, 0x3b, 0xfb, 0x41, 0xfc, 0x7e, 0x74, 0x87, 0xe4, 0xc2, 0x75, 0xe4, + 0x58, 0x96, 0x75, 0x90, 0x63, 0x68, 0x9e, 0xd5, 0xb0, 0xe6, 0xb8, 0xa3, + 0x16, 0x93, 0xd3, 0xaf, 0xc4, 0xce, 0x61, 0x89, 0x3f, 0x01, 0xd6, 0x6d, + 0xaa, 0xcc, 0x71, 0x1b, 0xb8, 0x6e, 0xe5, 0x58, 0x0f, 0xe7, 0xc7, 0xe1, + 0xd2, 0xc4, 0x26, 0x9a, 0xb0, 0x67, 0xe0, 0xfc, 0xf3, 0xe0, 0x2d, 0xda, + 0x78, 0xd0, 0xf5, 0x07, 0xb6, 0x32, 0xce, 0xef, 0x0a, 0x89, 0x33, 0x17, + 0xe9, 0x75, 0xdd, 0xf0, 0x69, 0x7e, 0x57, 0x33, 0x2e, 0xe6, 0xfa, 0xbd, + 0x6e, 0xf8, 0x5f, 0x79, 0x2d, 0x7d, 0xb7, 0xb0, 0xce, 0xce, 0x63, 0x8a, + 0x18, 0xdf, 0x04, 0x9b, 0xc5, 0xae, 0x6b, 0x24, 0x8f, 0x6b, 0xce, 0x40, + 0x62, 0xb3, 0xd8, 0xf2, 0x80, 0xd8, 0x72, 0xd8, 0xa1, 0x00, 0x43, 0xe7, + 0x6d, 0xb9, 0x13, 0x3f, 0xd0, 0x26, 0xee, 0x2a, 0xc6, 0xc4, 0x17, 0x65, + 0xad, 0xb8, 0x23, 0x82, 0x63, 0x8b, 0x88, 0x13, 0x6f, 0xe9, 0x05, 0xbd, + 0x8a, 0x3e, 0x05, 0x43, 0x15, 0x14, 0xd3, 0x66, 0x36, 0x50, 0x8f, 0x45, + 0xaa, 0x9f, 0xed, 0x5e, 0x8a, 0xa5, 0xd2, 0x7f, 0x1d, 0x7b, 0x12, 0x13, + 0x0f, 0x17, 0xe3, 0x7f, 0x49, 0x5e, 0xf4, 0xc6, 0x09, 0xca, 0xb9, 0x45, + 0x17, 0xfd, 0x89, 0xee, 0x0a, 0x32, 0xae, 0x44, 0xef, 0x8e, 0x42, 0x5d, + 0x05, 0x2f, 0x86, 0xfc, 0xf9, 0xb5, 0xd8, 0x2b, 0x91, 0x1c, 0x9e, 0x38, + 0x46, 0x2e, 0x44, 0x7d, 0x4e, 0xac, 0xf1, 0xb3, 0x2f, 0xa7, 0x23, 0x05, + 0xfb, 0x11, 0x9c, 0x98, 0x2a, 0x43, 0xfc, 0x03, 0x4a, 0xc5, 0x4c, 0xac, + 0xab, 0xa0, 0x1f, 0x64, 0x43, 0x88, 0x97, 0x19, 0x35, 0x48, 0x0c, 0xd3, + 0xcf, 0x47, 0x8a, 0xe0, 0xbc, 0x5e, 0xec, 0x5e, 0xf8, 0x98, 0xf3, 0xa6, + 0xe3, 0x89, 0x22, 0x7c, 0x49, 0x3f, 0x67, 0x09, 0x46, 0x1f, 0xd3, 0x70, + 0x55, 0x11, 0xf5, 0x34, 0x33, 0x12, 0x8a, 0xad, 0x24, 0x3f, 0x38, 0xd2, + 0xe8, 0xbc, 0xe9, 0x64, 0xf6, 0xb7, 0xe4, 0xbe, 0x97, 0x8e, 0x45, 0xf4, + 0x81, 0x17, 0x17, 0x87, 0x72, 0x73, 0x4e, 0xde, 0x9f, 0xf7, 0x07, 0x69, + 0xdf, 0xb2, 0x42, 0x11, 0x1f, 0xed, 0xe2, 0xc2, 0x18, 0xde, 0xd6, 0x0a, + 0x63, 0xf0, 0x31, 0xb6, 0x2f, 0x21, 0xb7, 0x16, 0xde, 0xef, 0x66, 0x9e, + 0xeb, 0x64, 0xbe, 0xd0, 0x06, 0xe1, 0xa3, 0x47, 0xc9, 0xab, 0xf6, 0x27, + 0x80, 0x77, 0xd3, 0x16, 0x16, 0x44, 0xca, 0x89, 0x75, 0x3d, 0x94, 0x2d, + 0xeb, 0xab, 0x07, 0x94, 0x61, 0xe6, 0xc2, 0x93, 0xce, 0x92, 0x98, 0xca, + 0xdc, 0x77, 0x5f, 0x36, 0xe4, 0x9f, 0x60, 0x1e, 0xec, 0x66, 0x2e, 0x4e, + 0xcd, 0x29, 0xfb, 0x99, 0x07, 0xef, 0xce, 0xe7, 0xc1, 0xfb, 0xb2, 0x1e, + 0x64, 0x69, 0xbc, 0x5b, 0x22, 0xcc, 0xbf, 0xed, 0x75, 0x04, 0x0f, 0xc6, + 0xd2, 0x2a, 0x4e, 0x45, 0x3e, 0xb0, 0xc6, 0xab, 0x64, 0xcc, 0x3e, 0x3c, + 0x93, 0xa8, 0xc6, 0x81, 0x81, 0x3a, 0x9c, 0xcd, 0x3e, 0x52, 0x84, 0xd2, + 0x2b, 0x71, 0x66, 0xa8, 0x02, 0x23, 0x03, 0x9b, 0xf9, 0xbb, 0x11, 0x1f, + 0x0c, 0xd9, 0x39, 0x38, 0xb1, 0x59, 0xfa, 0x77, 0x40, 0x99, 0xb0, 0x73, + 0x70, 0x33, 0xc6, 0xdc, 0xbb, 0xb9, 0x27, 0x9f, 0x7b, 0x8f, 0x33, 0xf7, + 0x3e, 0xc2, 0x36, 0x9f, 0xcb, 0xb7, 0x79, 0xc8, 0xfe, 0x96, 0xbe, 0x48, + 0xdd, 0xa9, 0xf5, 0x9a, 0x59, 0x0f, 0x18, 0x4e, 0x84, 0xc2, 0x85, 0xba, + 0xcf, 0xb1, 0xde, 0x91, 0xf3, 0xf5, 0x72, 0x39, 0x35, 0x79, 0x31, 0x36, + 0x24, 0xec, 0x75, 0x1f, 0xea, 0x23, 0x4c, 0x5d, 0x48, 0x8e, 0x49, 0x7e, + 0x9e, 0xfd, 0x16, 0xf9, 0xfc, 0x9e, 0x22, 0x54, 0x54, 0x61, 0x61, 0x46, + 0xd6, 0xb3, 0x4b, 0x98, 0xfb, 0x15, 0xf4, 0x1f, 0x47, 0x32, 0xb5, 0x8a, + 0xfe, 0x05, 0xb7, 0xc7, 0xc8, 0xfe, 0x55, 0x82, 0xf3, 0xf0, 0x44, 0x68, + 0xbc, 0xad, 0x1c, 0x95, 0x58, 0x15, 0xb1, 0xf9, 0x23, 0x79, 0x60, 0xb0, + 0x79, 0x09, 0xe3, 0x9c, 0x23, 0x14, 0x64, 0xcc, 0x02, 0x42, 0x23, 0xcc, + 0x6f, 0xb2, 0x95, 0xb8, 0x87, 0x79, 0xa6, 0x5a, 0x15, 0x47, 0xcf, 0xf9, + 0x35, 0x4e, 0xf9, 0x5e, 0x85, 0xee, 0x31, 0x91, 0x17, 0x67, 0xee, 0x50, + 0x86, 0x45, 0xb9, 0x35, 0x19, 0xb7, 0x9b, 0xb2, 0xdd, 0xa1, 0xf1, 0x30, + 0x5d, 0x50, 0xdf, 0xc7, 0x1b, 0x87, 0x12, 0x0a, 0x16, 0x68, 0x2e, 0xac, + 0xf4, 0x56, 0x62, 0x81, 0xfe, 0x3b, 0x6b, 0xd1, 0x32, 0x79, 0x76, 0x61, + 0xad, 0xb4, 0x98, 0xed, 0xfe, 0x92, 0xf9, 0xc2, 0xb0, 0x78, 0x67, 0x36, + 0x77, 0xdf, 0xcc, 0x52, 0x36, 0xe5, 0x6e, 0xa0, 0xdc, 0xfb, 0xbc, 0x76, + 0x2e, 0x9f, 0x2f, 0x37, 0x1e, 0x76, 0x30, 0x3e, 0x49, 0xd9, 0x16, 0xca, + 0xbd, 0x87, 0x72, 0x7b, 0xbc, 0xd2, 0xbf, 0xdf, 0x59, 0xf7, 0x2d, 0x93, + 0x67, 0xb9, 0x75, 0x91, 0x9c, 0xdc, 0xac, 0xc8, 0xd5, 0x87, 0xf3, 0x6d, + 0x4d, 0x24, 0x98, 0xec, 0x11, 0xb3, 0x57, 0x44, 0x43, 0x81, 0x2e, 0x7b, + 0x4d, 0x3c, 0x80, 0x95, 0xd9, 0x00, 0xee, 0xa5, 0xde, 0x33, 0xce, 0xc2, + 0x98, 0xec, 0x3e, 0x99, 0x92, 0x17, 0x2c, 0x64, 0xb9, 0xee, 0x3c, 0x7e, + 0xb7, 0x64, 0xc5, 0xfe, 0x26, 0xf3, 0xf9, 0xa4, 0xc4, 0xb1, 0xba, 0x3c, + 0x16, 0x38, 0xf1, 0x64, 0xe2, 0x37, 0xe7, 0xfa, 0x52, 0x12, 0x97, 0x65, + 0xad, 0x27, 0x80, 0x74, 0xf6, 0x2a, 0xd4, 0xf7, 0x7b, 0xb1, 0x42, 0x9f, + 0x46, 0x9c, 0xf8, 0xd6, 0x79, 0x7b, 0xdc, 0xc7, 0x76, 0xe0, 0xb2, 0xc5, + 0x2b, 0x4f, 0x66, 0x1b, 0xbc, 0xd5, 0xc4, 0xba, 0x83, 0x17, 0xc5, 0xd7, + 0x19, 0xb1, 0x32, 0x23, 0xd4, 0xf6, 0x02, 0xe7, 0xbd, 0xc4, 0xce, 0x1b, + 0xd6, 0x29, 0x19, 0xce, 0xfd, 0xe3, 0xf9, 0xb9, 0xdf, 0x9f, 0x45, 0x71, + 0x0e, 0xdb, 0xae, 0xc2, 0xac, 0x7e, 0xf9, 0xf6, 0xe2, 0xed, 0x68, 0x29, + 0xef, 0x5d, 0x85, 0x99, 0x83, 0x57, 0x17, 0xe7, 0xf6, 0xc2, 0x64, 0x7d, + 0xe1, 0xd2, 0x1c, 0x2a, 0xd8, 0x63, 0xe2, 0x3d, 0xda, 0x44, 0x1d, 0x75, + 0x26, 0x18, 0x2b, 0xfd, 0xda, 0x74, 0xbe, 0x5f, 0x4f, 0xb0, 0x5f, 0x71, + 0x97, 0xac, 0xff, 0x4a, 0xbf, 0x94, 0x58, 0x85, 0x51, 0x87, 0x0f, 0x92, + 0xf0, 0x7a, 0x8d, 0x50, 0xfc, 0x25, 0xfa, 0xca, 0x08, 0xfb, 0x5a, 0x85, + 0x1e, 0x25, 0x6b, 0xef, 0xfd, 0x1c, 0x60, 0x99, 0xa9, 0x7c, 0x40, 0xfa, + 0xe9, 0xa4, 0xcd, 0xfd, 0x25, 0x71, 0x58, 0x27, 0x0e, 0x8b, 0xfc, 0x77, + 0xc8, 0x79, 0xbb, 0x29, 0x7f, 0x09, 0xe7, 0xcf, 0x2d, 0x7b, 0x54, 0x66, + 0xa9, 0xd1, 0x66, 0x73, 0x6e, 0x27, 0x7d, 0x76, 0x01, 0x6d, 0x6a, 0x7f, + 0x46, 0xc1, 0x10, 0x95, 0x7e, 0x34, 0x2d, 0x6b, 0xd7, 0x7e, 0xec, 0xcb, + 0xb8, 0xf0, 0x5c, 0xba, 0x16, 0xc3, 0x99, 0x22, 0x1c, 0x4a, 0x5f, 0x89, + 0xdd, 0x19, 0x22, 0x67, 0xfa, 0x2a, 0x0c, 0x66, 0xdc, 0x78, 0x23, 0x4d, + 0x3d, 0x65, 0x4a, 0xf0, 0xd3, 0xf4, 0xa7, 0xf0, 0x4c, 0xa6, 0x14, 0xaf, + 0xa7, 0xaf, 0xc6, 0x81, 0x4c, 0x19, 0x5e, 0x4e, 0x93, 0x17, 0x67, 0x3c, + 0x78, 0x29, 0x1d, 0xc0, 0x68, 0xa6, 0x1c, 0x2f, 0xa6, 0x83, 0x18, 0xc9, + 0x54, 0xe0, 0x07, 0xe9, 0x6b, 0x90, 0xcd, 0x54, 0xe2, 0x85, 0x74, 0x3d, + 0x9e, 0xa0, 0x0f, 0x3c, 0x9f, 0xd6, 0xf0, 0x78, 0xa6, 0x0a, 0xc7, 0xd2, + 0x21, 0xb6, 0xeb, 0xc3, 0xd1, 0x81, 0x30, 0xf6, 0x0d, 0xd5, 0xe0, 0xb9, + 0x81, 0xd9, 0x18, 0x1e, 0xf2, 0xe3, 0xd0, 0x40, 0x23, 0x76, 0x0f, 0x8d, + 0xdb, 0xfa, 0x39, 0x92, 0x68, 0x39, 0xaf, 0xc7, 0x0d, 0x1f, 0x33, 0xdf, + 0xaf, 0x24, 0x44, 0x6f, 0x6e, 0xb3, 0x8a, 0x73, 0xf4, 0x64, 0xd6, 0x9e, + 0x77, 0x68, 0xfd, 0x6d, 0xf4, 0x33, 0x0b, 0xdd, 0xfa, 0x95, 0xcc, 0x47, + 0x7b, 0x24, 0x1e, 0xd1, 0x16, 0x0e, 0x28, 0x1b, 0x6d, 0x0c, 0xaa, 0x88, + 0x95, 0x53, 0x97, 0x1c, 0xb6, 0xb7, 0x8c, 0xfe, 0x9c, 0x26, 0x16, 0x98, + 0x9c, 0xd7, 0x44, 0xf6, 0x80, 0xb2, 0x85, 0xf9, 0xef, 0xb5, 0xfd, 0xa6, + 0x55, 0x6a, 0x63, 0x71, 0x28, 0x36, 0x9b, 0x3e, 0x17, 0x1e, 0x14, 0x7d, + 0x96, 0x17, 0x89, 0x3e, 0x8b, 0xb4, 0xcb, 0xd9, 0x49, 0x41, 0xef, 0x3f, + 0x2e, 0xca, 0xd9, 0xc3, 0xdf, 0x17, 0xe7, 0x72, 0xc9, 0xc2, 0xbc, 0x5b, + 0x56, 0x9f, 0x5e, 0x98, 0x7b, 0xf2, 0xd8, 0x6a, 0x59, 0x6f, 0x03, 0x63, + 0x48, 0x15, 0x79, 0x8e, 0xac, 0x45, 0x4c, 0xc5, 0x1b, 0xc4, 0x8a, 0x8d, + 0x50, 0x60, 0x96, 0x7a, 0x51, 0xfe, 0xea, 0x75, 0xd8, 0xf6, 0x67, 0xda, + 0x98, 0x75, 0xf8, 0x3c, 0xf6, 0x4c, 0x14, 0x4b, 0x0c, 0xdd, 0x93, 0x90, + 0xbe, 0x41, 0x2d, 0x92, 0x3e, 0x23, 0x77, 0x0f, 0xa3, 0xb2, 0x9e, 0x77, + 0x39, 0xbb, 0x53, 0xb1, 0x72, 0xc0, 0x89, 0x2e, 0xfd, 0xbf, 0x48, 0xcc, + 0x64, 0x3f, 0xea, 0xe8, 0x6f, 0x2a, 0xfe, 0x76, 0x80, 0xf1, 0x25, 0x72, + 0x37, 0x4c, 0xe2, 0xad, 0x6b, 0xd4, 0x89, 0x15, 0x89, 0x65, 0x7c, 0xee, + 0x86, 0x3a, 0x4a, 0x56, 0xd1, 0xeb, 0x36, 0x2b, 0x68, 0x33, 0xb2, 0xff, + 0xd2, 0x3c, 0x66, 0xe2, 0xf0, 0x3c, 0x3f, 0x52, 0x09, 0x59, 0x3f, 0x5d, + 0x82, 0x9d, 0xa9, 0xd0, 0xaa, 0xb3, 0x8a, 0x1f, 0xc9, 0xac, 0x0b, 0x26, + 0xe7, 0xbe, 0x9b, 0x7d, 0xf3, 0xf4, 0x7a, 0xd1, 0x3d, 0x54, 0xcd, 0xcf, + 0xc4, 0x67, 0x3d, 0xc4, 0xea, 0x6e, 0xce, 0x6d, 0xf7, 0x90, 0x07, 0x47, + 0xf7, 0xb8, 0x51, 0x96, 0x82, 0xf2, 0xec, 0x3c, 0xa2, 0x8d, 0xd6, 0x88, + 0x17, 0x46, 0x3c, 0x28, 0x25, 0xa7, 0x7d, 0x7e, 0xc4, 0x8b, 0x92, 0xad, + 0xb4, 0x87, 0x5d, 0x55, 0x28, 0xde, 0xea, 0xc6, 0x73, 0x99, 0x6a, 0xb8, + 0xb6, 0xde, 0x81, 0xf5, 0x99, 0x69, 0x50, 0xb7, 0x56, 0x63, 0x62, 0x97, + 0x0f, 0x33, 0x76, 0x18, 0x78, 0x63, 0x4f, 0x0d, 0x6a, 0x77, 0xdc, 0x8c, + 0x9f, 0xee, 0xf1, 0xa3, 0x92, 0xba, 0x79, 0x79, 0xc4, 0x29, 0xfc, 0x93, + 0xf3, 0x74, 0xa0, 0x38, 0xbf, 0x6f, 0x1c, 0xbb, 0x94, 0xaf, 0x42, 0x29, + 0xcc, 0x0d, 0x90, 0xc9, 0xca, 0xfa, 0x68, 0x63, 0x4b, 0x77, 0x62, 0xe4, + 0x5f, 0x8b, 0x8d, 0x5f, 0xfd, 0x9f, 0xb7, 0xa3, 0x0d, 0xc4, 0x32, 0xf1, + 0xff, 0x15, 0xab, 0x4b, 0x8c, 0x8e, 0x87, 0xc3, 0xf3, 0x8a, 0xb1, 0xca, + 0x9e, 0x8f, 0x95, 0xe4, 0x80, 0xcb, 0xd1, 0xbd, 0xa3, 0xa1, 0xed, 0x1e, + 0xc5, 0x87, 0x58, 0x55, 0x3f, 0xef, 0xa9, 0x79, 0x9f, 0x82, 0x2a, 0xf9, + 0xba, 0xac, 0x99, 0xa9, 0xa3, 0x8b, 0xf2, 0x7b, 0xa0, 0x3e, 0x7b, 0x0d, + 0xaa, 0x3b, 0x55, 0xd0, 0xe3, 0x98, 0x65, 0xda, 0xfb, 0x5a, 0xe2, 0xe3, + 0x4e, 0xac, 0x4c, 0x8c, 0x32, 0x47, 0x11, 0x5d, 0x4a, 0x5f, 0x37, 0x52, + 0x8e, 0xf4, 0x57, 0x9e, 0x37, 0xc4, 0xaa, 0x3e, 0xb6, 0xbf, 0x85, 0x71, + 0x75, 0xb3, 0xfc, 0x67, 0xdd, 0x28, 0x95, 0xb2, 0xd2, 0xf7, 0x7a, 0xfe, + 0x96, 0xfe, 0x5a, 0xd6, 0xc6, 0x8b, 0xe2, 0x54, 0x51, 0xac, 0x94, 0x71, + 0x6a, 0x7f, 0x22, 0x14, 0x7b, 0x97, 0x78, 0x76, 0x2c, 0xeb, 0x24, 0xf7, + 0x11, 0xbb, 0x59, 0x47, 0x7b, 0xe9, 0x51, 0x8e, 0x9e, 0xb7, 0x99, 0x42, + 0x2e, 0xb0, 0x04, 0xe9, 0xd4, 0x54, 0x5f, 0x92, 0xfd, 0x6e, 0x27, 0x5c, + 0xbd, 0x05, 0xdc, 0x64, 0xac, 0x19, 0x25, 0xbf, 0xcb, 0x3a, 0xe0, 0xe8, + 0xa7, 0x3d, 0xe8, 0x2a, 0xc7, 0x58, 0xc4, 0x39, 0xaf, 0xe6, 0xc7, 0x6d, + 0x56, 0x1a, 0x26, 0x4e, 0xcd, 0x2b, 0xc1, 0xa1, 0x5d, 0x57, 0xa1, 0xbc, + 0x7f, 0xdc, 0xf2, 0xf0, 0x5e, 0xa9, 0x31, 0x1f, 0x4f, 0x44, 0x42, 0xad, + 0xab, 0x15, 0x13, 0xad, 0xf3, 0xdc, 0x28, 0xd9, 0xe5, 0x40, 0x71, 0x3f, + 0x79, 0x83, 0x7e, 0x03, 0xc6, 0x7d, 0x39, 0x3c, 0x57, 0x7b, 0x67, 0xdb, + 0x76, 0x75, 0xcd, 0xa8, 0xdb, 0xf4, 0x1b, 0x13, 0x37, 0xaa, 0x8c, 0xed, + 0xc5, 0xc3, 0x1e, 0x14, 0xf5, 0x9a, 0x98, 0x71, 0x83, 0xe0, 0x51, 0x23, + 0x8a, 0x68, 0xaf, 0xae, 0x5e, 0x1f, 0xf3, 0xea, 0x3a, 0xb8, 0xc8, 0xed, + 0x1c, 0xdb, 0x0d, 0x38, 0xc8, 0xc3, 0xd4, 0xed, 0x37, 0x43, 0x65, 0xd9, + 0x13, 0x7c, 0x7e, 0x82, 0xfc, 0xf3, 0x04, 0xef, 0x9d, 0x18, 0xae, 0xe1, + 0xa7, 0x0a, 0xb5, 0xbb, 0xcb, 0x10, 0x5b, 0x2a, 0xeb, 0xac, 0x0e, 0x54, + 0xf7, 0x8b, 0x7f, 0xaa, 0xb8, 0xab, 0x49, 0x81, 0x7e, 0x1d, 0xdb, 0x9c, + 0x79, 0x39, 0x5f, 0xbd, 0xd3, 0x8d, 0x8a, 0x2e, 0xb6, 0x77, 0xa9, 0x2f, + 0x4b, 0xac, 0xba, 0x30, 0x07, 0x01, 0x55, 0x62, 0xb7, 0xcc, 0xd9, 0x27, + 0xf9, 0xbd, 0x1b, 0xce, 0x5e, 0x99, 0x6b, 0x19, 0xe3, 0x37, 0xdd, 0x39, + 0x5e, 0x7b, 0xd1, 0x5a, 0x3b, 0xb2, 0x89, 0x25, 0xd8, 0x62, 0x9f, 0x5d, + 0x08, 0xc0, 0x33, 0x12, 0x6c, 0xcd, 0xe0, 0xf4, 0xb9, 0x9e, 0x94, 0x13, + 0xf7, 0x26, 0xe5, 0x0c, 0x87, 0x9c, 0x33, 0xe0, 0x58, 0x47, 0xdc, 0x78, + 0xb0, 0xcf, 0x2d, 0x6b, 0xdc, 0x01, 0x97, 0x56, 0x8b, 0x77, 0x33, 0x82, + 0x79, 0x25, 0x38, 0x9c, 0xf6, 0xe3, 0x84, 0xfd, 0xbb, 0x94, 0x18, 0x6c, + 0xa1, 0x45, 0x2f, 0x47, 0xb7, 0xb7, 0x04, 0xc9, 0xf0, 0xcd, 0xc8, 0xdc, + 0xc5, 0x1c, 0x9a, 0xb6, 0x59, 0x41, 0x4e, 0x41, 0xb7, 0x63, 0x6e, 0xe0, + 0x40, 0x2a, 0xfc, 0x39, 0x4c, 0x56, 0x39, 0xa9, 0x3f, 0x59, 0x9f, 0x50, + 0xb1, 0x93, 0x56, 0x45, 0xfc, 0x8b, 0x89, 0xdd, 0x96, 0x27, 0x61, 0x55, + 0x18, 0x5a, 0x7c, 0x54, 0x09, 0xb5, 0xaf, 0xa7, 0xdf, 0x96, 0x8d, 0x94, + 0x11, 0x8f, 0x67, 0xa1, 0x74, 0x97, 0xd8, 0xaf, 0x87, 0xd8, 0x70, 0xbd, + 0xec, 0x07, 0x84, 0x03, 0x8a, 0x07, 0xf7, 0x0d, 0x08, 0xae, 0x2e, 0x47, + 0xd1, 0x9e, 0x0a, 0x3c, 0x9c, 0x76, 0x12, 0xfb, 0xdc, 0xa8, 0xdd, 0x25, + 0x3e, 0x5f, 0x89, 0xca, 0xad, 0x07, 0x2d, 0xbf, 0x56, 0x82, 0x4a, 0x5e, + 0x3f, 0x46, 0x5d, 0x7c, 0x90, 0xfa, 0x1a, 0x46, 0x13, 0xf5, 0x94, 0xdb, + 0xce, 0xf1, 0xf9, 0xf0, 0x5e, 0xaa, 0x91, 0xb2, 0xfd, 0x78, 0x77, 0x87, + 0x65, 0xb5, 0x44, 0x62, 0x70, 0x8e, 0x5c, 0x89, 0x5f, 0xf2, 0xf7, 0x71, + 0xbd, 0x05, 0xea, 0x48, 0x1d, 0xde, 0x4c, 0xb5, 0xc2, 0x31, 0x52, 0x81, + 0xb3, 0x5b, 0x45, 0xa6, 0x1b, 0x95, 0x7d, 0x5a, 0xf8, 0x0c, 0x6d, 0xdf, + 0xb5, 0x8b, 0x81, 0xbf, 0x46, 0xda, 0x2f, 0xcc, 0x4f, 0x8e, 0xef, 0x1d, + 0xcc, 0xcf, 0xcd, 0x38, 0x0a, 0xdc, 0xe9, 0x07, 0xd6, 0x63, 0x4c, 0x67, + 0x5c, 0xd1, 0x20, 0xba, 0xc3, 0xc7, 0x64, 0xbf, 0x9c, 0xe3, 0x8b, 0x11, + 0xf3, 0x9f, 0xb5, 0xe4, 0xdc, 0x81, 0x8b, 0xf6, 0x59, 0xac, 0x1d, 0xb2, + 0x36, 0x2e, 0x93, 0xfb, 0x3f, 0xe7, 0x9c, 0x30, 0x41, 0x31, 0x44, 0xe6, + 0x16, 0x99, 0x4b, 0xa2, 0xf1, 0xe5, 0x64, 0xfe, 0xa3, 0xf5, 0xe8, 0xf9, + 0xf2, 0xf0, 0xba, 0xec, 0x75, 0x70, 0x59, 0x87, 0x95, 0xb9, 0x94, 0xf5, + 0xca, 0x00, 0x56, 0x8d, 0x78, 0xed, 0xdc, 0xf9, 0xdd, 0x84, 0xcc, 0x9f, + 0x9c, 0xa1, 0xf1, 0x90, 0x9b, 0xe8, 0x28, 0xe5, 0xdc, 0x7d, 0x90, 0x80, + 0x72, 0x5b, 0xb4, 0x0d, 0xe5, 0xc4, 0xb5, 0x77, 0x12, 0xc1, 0x55, 0x26, + 0x12, 0x6c, 0x2b, 0x8a, 0x12, 0xd6, 0x79, 0x33, 0xe1, 0x60, 0xbc, 0x6d, + 0xe6, 0x98, 0xbd, 0xb0, 0x6c, 0xae, 0xbc, 0x0c, 0x33, 0xa8, 0xa7, 0xb3, + 0x09, 0x03, 0xb5, 0xd4, 0xd3, 0x99, 0x84, 0x13, 0x67, 0xa8, 0x97, 0x53, + 0x89, 0x00, 0x2a, 0x18, 0x98, 0x8a, 0xfa, 0x2c, 0x4c, 0xe8, 0x95, 0x72, + 0x3e, 0x02, 0x72, 0xfe, 0xc5, 0x9f, 0xd4, 0x51, 0x9b, 0xac, 0x5f, 0x53, + 0xeb, 0x70, 0x60, 0xd2, 0xe6, 0x2c, 0x4e, 0xe6, 0xcd, 0xa2, 0x1f, 0x19, + 0x93, 0x9d, 0xab, 0xb7, 0xca, 0xa1, 0xa6, 0x83, 0x1c, 0x4f, 0x40, 0x29, + 0x8c, 0x67, 0x19, 0x40, 0x59, 0xa3, 0x89, 0x30, 0x1e, 0x62, 0x5b, 0x6f, + 0x27, 0x5e, 0xc1, 0xad, 0xfc, 0x7e, 0x3f, 0xf1, 0x23, 0x2c, 0x61, 0x3f, + 0xde, 0x23, 0x6e, 0xdc, 0x1f, 0xba, 0xad, 0x04, 0xa5, 0x75, 0x58, 0x34, + 0x72, 0xfa, 0x5c, 0xb7, 0x3d, 0xce, 0x42, 0x4e, 0xe5, 0xc6, 0xfd, 0xe9, + 0xc2, 0x59, 0xa6, 0x18, 0x7d, 0x58, 0xf0, 0xd5, 0xcd, 0x1c, 0x1e, 0x68, + 0x4b, 0x7c, 0x23, 0x77, 0x4e, 0x47, 0x95, 0xcf, 0x79, 0x3d, 0x3a, 0x51, + 0xea, 0xcf, 0xfb, 0x95, 0xf4, 0xe7, 0x93, 0xca, 0x5c, 0xe0, 0xcc, 0xa3, + 0xb6, 0x7e, 0x65, 0x7d, 0x3e, 0x80, 0xeb, 0x88, 0xe7, 0x27, 0xc9, 0xa1, + 0x19, 0x93, 0xb1, 0x7a, 0xde, 0x0a, 0xf4, 0xec, 0x11, 0x9d, 0x06, 0xdb, + 0xd9, 0x87, 0xb6, 0x0c, 0x56, 0x22, 0xb9, 0xc7, 0xc3, 0x31, 0x88, 0xde, + 0xc9, 0x43, 0xf7, 0xd0, 0xff, 0xd3, 0x7f, 0x83, 0x75, 0xbb, 0xa6, 0xe1, + 0xad, 0xf4, 0x97, 0xb0, 0x9e, 0x36, 0xe4, 0xa0, 0xef, 0xac, 0xd0, 0xaf, + 0x42, 0x6e, 0x3f, 0xc3, 0xc7, 0x39, 0x78, 0x9f, 0xbe, 0xb5, 0x0e, 0xef, + 0x64, 0x67, 0x61, 0x46, 0x9f, 0x8a, 0xc9, 0x69, 0x0a, 0xed, 0x43, 0xf6, + 0x5e, 0xdc, 0xc4, 0xb7, 0xaf, 0x40, 0xdd, 0x65, 0x62, 0x7d, 0xd4, 0x8d, + 0xdd, 0xcc, 0x2d, 0x56, 0xc8, 0x7a, 0x98, 0x5d, 0xaf, 0x19, 0x7b, 0x39, + 0x17, 0x89, 0x04, 0x79, 0x8b, 0x37, 0xa7, 0xe7, 0xf8, 0xf4, 0x62, 0xd6, + 0xb9, 0xa7, 0xc4, 0xde, 0xcb, 0x50, 0x04, 0x1f, 0x44, 0xcf, 0x05, 0x1d, + 0x7f, 0x0d, 0x37, 0x26, 0xdf, 0xa7, 0x1d, 0x84, 0xc6, 0xaf, 0x75, 0xfc, + 0x4f, 0xea, 0x72, 0x1d, 0xe7, 0xf1, 0x6f, 0x30, 0x94, 0xf6, 0xd0, 0x8f, + 0x64, 0xef, 0x69, 0x2d, 0x8e, 0x6e, 0x8b, 0x33, 0x37, 0x09, 0xea, 0x19, + 0xf2, 0xfa, 0x4c, 0x95, 0x65, 0x39, 0x22, 0x71, 0x0c, 0x0e, 0x58, 0xd6, + 0x62, 0x3d, 0xd6, 0x5c, 0x42, 0xfd, 0xde, 0x8f, 0xfd, 0xac, 0xe7, 0xc3, + 0x91, 0xa1, 0x15, 0xbc, 0x2f, 0x3c, 0x78, 0x2d, 0x1e, 0xe6, 0xf3, 0x2f, + 0xe9, 0xb1, 0xf1, 0x19, 0x08, 0x72, 0xce, 0x73, 0xcf, 0xc7, 0x86, 0x56, + 0x7e, 0x4c, 0xbd, 0x0b, 0xfa, 0x7c, 0x22, 0xaf, 0xcf, 0x52, 0xea, 0xf3, + 0xf6, 0x91, 0xf7, 0xcf, 0x6d, 0x48, 0x05, 0x63, 0x19, 0xc6, 0x98, 0xb7, + 0xa8, 0xb7, 0x8d, 0xb4, 0x57, 0xe6, 0x1a, 0x38, 0x92, 0x6d, 0xa6, 0x6e, + 0x5c, 0xe4, 0x44, 0x4e, 0x1c, 0xcb, 0x1a, 0xb4, 0x4d, 0x60, 0x21, 0xe3, + 0x85, 0xe9, 0xcd, 0xd9, 0x4f, 0xe6, 0xbc, 0x3f, 0x70, 0xee, 0x94, 0x66, + 0x1c, 0x4f, 0xc8, 0xd8, 0xa5, 0x9c, 0xfd, 0x5c, 0xd6, 0x80, 0xa7, 0x94, + 0xb9, 0xd0, 0xf6, 0xee, 0x84, 0xf0, 0xf4, 0x00, 0x65, 0x15, 0x53, 0xd6, + 0xe9, 0x73, 0x9b, 0x52, 0x6d, 0xf6, 0xd9, 0x37, 0xf2, 0x1b, 0x84, 0x69, + 0xcf, 0xc5, 0x91, 0x32, 0xbc, 0xed, 0x13, 0x19, 0x39, 0x5d, 0x0a, 0x06, + 0x6e, 0x61, 0x19, 0x79, 0xfe, 0x20, 0x9f, 0xdf, 0x12, 0x29, 0xc2, 0x90, + 0xb7, 0xb0, 0xee, 0x94, 0xeb, 0x8b, 0x79, 0xbe, 0x9d, 0x6b, 0x2b, 0x73, + 0x76, 0x55, 0x5c, 0x6a, 0xef, 0x25, 0xd9, 0xdc, 0xaa, 0xee, 0x92, 0xfd, + 0x3a, 0x89, 0x7f, 0x82, 0x93, 0x39, 0x9c, 0x2d, 0xa1, 0x3d, 0x3d, 0x97, + 0x90, 0x75, 0x21, 0x93, 0x39, 0x46, 0x18, 0x8b, 0xb2, 0xf6, 0x99, 0x2e, + 0xc6, 0x37, 0xea, 0x8c, 0xbc, 0x77, 0x65, 0x54, 0xf6, 0xe3, 0x6e, 0xae, + 0x14, 0x5e, 0xd7, 0x11, 0x95, 0x7c, 0x42, 0x6c, 0xb5, 0x70, 0xcf, 0x8d, + 0x3d, 0xf9, 0x39, 0x0f, 0xa8, 0x9f, 0x84, 0xfd, 0xaf, 0x5f, 0xc2, 0xf1, + 0x0a, 0x7b, 0x5a, 0xd2, 0xaf, 0xf3, 0x5c, 0xcf, 0xe6, 0xf5, 0x43, 0xf4, + 0x37, 0xd3, 0x59, 0x46, 0x7e, 0x27, 0xbc, 0x3e, 0xa4, 0xcf, 0x52, 0x85, + 0xd3, 0x4b, 0x4e, 0x21, 0x6b, 0x7b, 0x3d, 0xca, 0xde, 0xac, 0xac, 0xef, + 0x09, 0x9f, 0xbf, 0xdc, 0x1a, 0x9f, 0x9c, 0x8d, 0x93, 0xf8, 0x78, 0xfa, + 0x5c, 0x7f, 0xaa, 0xcd, 0xde, 0x07, 0x5d, 0xd0, 0x6f, 0xe1, 0x6e, 0xc6, + 0x82, 0x7b, 0xaa, 0xed, 0x1c, 0x29, 0x9f, 0x8b, 0x9c, 0x3e, 0xb7, 0x33, + 0xf5, 0x7b, 0x4b, 0xb5, 0xf7, 0x1d, 0x5d, 0x70, 0x6c, 0xd5, 0xce, 0xac, + 0x20, 0xe7, 0x3b, 0x7b, 0x83, 0xe4, 0x25, 0x2e, 0xc6, 0xc9, 0xff, 0x52, + 0x2a, 0x7b, 0xe0, 0xe4, 0xcb, 0xb8, 0xa5, 0x3f, 0x86, 0x21, 0xfd, 0x43, + 0xcb, 0xf4, 0x4d, 0xad, 0xef, 0xc2, 0x92, 0xfe, 0xdf, 0x5b, 0xe5, 0x76, + 0x7d, 0xad, 0x3d, 0xa9, 0xa8, 0x78, 0x70, 0x9e, 0x0b, 0xb7, 0x0d, 0x86, + 0xb0, 0xb8, 0x5f, 0x45, 0x78, 0x9e, 0xc8, 0x09, 0xa1, 0x75, 0xb0, 0xde, + 0x99, 0x5f, 0xd7, 0xc1, 0x22, 0xf6, 0xe3, 0x6d, 0xbd, 0x0c, 0xaf, 0x11, + 0x77, 0x2b, 0x6c, 0x9e, 0xbd, 0x46, 0x49, 0x09, 0xcf, 0x76, 0xa9, 0x98, + 0xa6, 0xc1, 0x5b, 0x6d, 0xc4, 0xc8, 0xb1, 0x5b, 0x94, 0xad, 0x99, 0x35, + 0x4a, 0x7f, 0xb6, 0xd0, 0xbe, 0x07, 0x77, 0x8c, 0x7a, 0x71, 0xc7, 0xde, + 0x6a, 0x7e, 0x7c, 0xfc, 0xd4, 0xf0, 0xf3, 0x8d, 0xd2, 0xdc, 0xfe, 0xfc, + 0x12, 0xac, 0x4b, 0x15, 0xec, 0xca, 0xc9, 0xbc, 0x5a, 0x6c, 0x57, 0xea, + 0x04, 0xb0, 0x97, 0xfc, 0xfc, 0x64, 0x5a, 0xb8, 0xfd, 0x06, 0xea, 0x42, + 0xd6, 0x99, 0x8b, 0xc9, 0xef, 0xe5, 0x3c, 0x63, 0x24, 0xbf, 0xef, 0x9f, + 0xb3, 0x1b, 0x9c, 0xb7, 0x1b, 0x17, 0xde, 0xa1, 0x7f, 0xcf, 0x8a, 0xfc, + 0xbb, 0x35, 0xe9, 0xbd, 0x60, 0x57, 0x17, 0x9e, 0x17, 0xf8, 0xd0, 0xe9, + 0x73, 0xe9, 0xd4, 0x54, 0x7b, 0x52, 0x50, 0xd4, 0x2f, 0x7c, 0x59, 0xf4, + 0xe2, 0xc4, 0xab, 0xc4, 0x07, 0x67, 0xff, 0xc4, 0xb5, 0x42, 0xeb, 0x5c, + 0x7b, 0x63, 0xe8, 0x8e, 0x52, 0xb7, 0x83, 0xa5, 0xc5, 0x39, 0xfb, 0xc8, + 0xe9, 0x22, 0xa0, 0x0a, 0xbe, 0x78, 0x6c, 0x9e, 0x17, 0x60, 0x2e, 0xa8, + 0xee, 0x15, 0xce, 0x58, 0xcd, 0x6f, 0xe1, 0xe6, 0xe4, 0x2f, 0x7b, 0x85, + 0xa7, 0xd7, 0xf0, 0x9b, 0x24, 0xbf, 0x46, 0xec, 0x69, 0x25, 0x7a, 0x18, + 0x13, 0x8b, 0x43, 0x2b, 0xb1, 0x71, 0xf8, 0x72, 0xb6, 0x95, 0xcb, 0x77, + 0x0e, 0x5e, 0xb0, 0x6f, 0x69, 0x8f, 0x7d, 0x3a, 0x7d, 0x4e, 0x6c, 0x35, + 0xc0, 0xb9, 0xda, 0x9d, 0x96, 0x3e, 0x58, 0xe8, 0xd0, 0xc9, 0x8d, 0xe8, + 0x6b, 0x6a, 0xb5, 0xdc, 0x9f, 0xca, 0x29, 0x0b, 0xb2, 0xa6, 0xde, 0xdb, + 0x55, 0x2a, 0xeb, 0xec, 0x17, 0xc6, 0x5e, 0x68, 0x43, 0xd6, 0x55, 0x03, + 0xa8, 0xea, 0x15, 0x3d, 0xca, 0x98, 0x02, 0x70, 0x92, 0x03, 0x56, 0x8d, + 0x5e, 0x4e, 0x1e, 0x6a, 0x4a, 0xec, 0xf3, 0x83, 0x61, 0xfa, 0x99, 0xc7, + 0x2c, 0x26, 0x5f, 0x7c, 0x3b, 0x21, 0xe7, 0x32, 0x5b, 0x5b, 0x76, 0x27, + 0x66, 0x7a, 0x0f, 0xe7, 0xf3, 0xfe, 0x15, 0x70, 0x93, 0xa3, 0x9a, 0x98, + 0x88, 0x2a, 0x36, 0xde, 0x38, 0xb4, 0x10, 0x16, 0x32, 0xb7, 0xbc, 0x25, + 0x23, 0xf3, 0xb9, 0x26, 0xbf, 0x26, 0x24, 0xed, 0xc5, 0x94, 0xa1, 0xac, + 0xe4, 0x05, 0xf0, 0x3a, 0x8d, 0x16, 0x65, 0x5f, 0x46, 0xea, 0xaf, 0xe1, + 0xbd, 0xc2, 0x9e, 0xf1, 0x12, 0xf4, 0xa7, 0x0a, 0xbe, 0x55, 0xd0, 0x47, + 0x05, 0x6d, 0x55, 0xf2, 0x3e, 0x13, 0xfa, 0xf5, 0xb5, 0x68, 0x1c, 0x2c, + 0xc7, 0xed, 0xfd, 0xb9, 0xfd, 0xfa, 0x86, 0xc1, 0x6a, 0xdc, 0xb6, 0x7d, + 0x39, 0x4a, 0xf7, 0x7a, 0xb1, 0x78, 0xbb, 0xec, 0x0d, 0x2c, 0x43, 0xf1, + 0xe8, 0xaf, 0x4a, 0xed, 0x9c, 0xbb, 0xb7, 0x99, 0x73, 0xd4, 0x4c, 0xce, + 0x19, 0x6c, 0x8e, 0x41, 0xd6, 0x3a, 0x0d, 0x14, 0x8d, 0x1a, 0xe4, 0xa6, + 0x56, 0xe7, 0x0c, 0x83, 0xf3, 0xcc, 0x7e, 0x5e, 0xc3, 0xbc, 0x67, 0x16, + 0xc7, 0xee, 0xe2, 0xc7, 0xd1, 0x6b, 0x59, 0x67, 0x6f, 0x40, 0x67, 0x19, + 0xf3, 0x70, 0xc7, 0xe8, 0x55, 0x08, 0x0c, 0x36, 0xa2, 0x76, 0xb4, 0x1a, + 0xda, 0xa0, 0x0f, 0xad, 0xbd, 0xe2, 0x8b, 0xc1, 0x40, 0x5c, 0x8d, 0xc2, + 0x3d, 0xca, 0x38, 0xdd, 0xfb, 0x7b, 0xeb, 0x24, 0xe7, 0xba, 0x99, 0x3a, + 0xbb, 0xb3, 0xb7, 0x15, 0x95, 0xa3, 0xb4, 0xf3, 0xfe, 0x3b, 0x50, 0x31, + 0xe8, 0x26, 0x4f, 0x0e, 0x20, 0x4b, 0x5e, 0xec, 0x19, 0xf4, 0xa3, 0xb4, + 0x57, 0x6b, 0xbd, 0x5d, 0x41, 0x6c, 0x26, 0x73, 0xa9, 0x22, 0xb6, 0xe5, + 0xa2, 0x0f, 0x0d, 0xd2, 0x97, 0x17, 0xd2, 0xcd, 0x3b, 0x7b, 0x05, 0x77, + 0x44, 0x27, 0x67, 0x6d, 0x9b, 0x5e, 0xd9, 0x7b, 0xf9, 0x33, 0xa3, 0x38, + 0x7f, 0x66, 0xd4, 0xb4, 0xcf, 0x72, 0x56, 0x1a, 0x50, 0xce, 0xcc, 0xd2, + 0x7a, 0x6a, 0x79, 0xef, 0x43, 0xc6, 0xfd, 0xaf, 0xf6, 0x7a, 0x18, 0x7f, + 0x3a, 0xf1, 0xb9, 0xa6, 0xa0, 0x39, 0xaa, 0xbc, 0xc2, 0xf1, 0xff, 0x88, + 0x01, 0xb7, 0x8e, 0xfd, 0xfc, 0x73, 0xe5, 0x5f, 0xba, 0x26, 0x36, 0xef, + 0xa2, 0xb5, 0xb4, 0x23, 0xcc, 0x9f, 0xc7, 0x2f, 0x5a, 0x4b, 0x13, 0x2c, + 0xbd, 0xf4, 0x4c, 0x6d, 0x60, 0xca, 0xfa, 0x8c, 0xcc, 0x99, 0xcc, 0x53, + 0x61, 0x7d, 0xc6, 0x44, 0xd3, 0xf5, 0x2e, 0x2c, 0xec, 0x97, 0x9c, 0x47, + 0x62, 0x71, 0x88, 0xb9, 0xc6, 0x66, 0xce, 0x83, 0xbd, 0xae, 0xc2, 0x7b, + 0x01, 0xe2, 0x4b, 0x80, 0x39, 0x44, 0x92, 0xf7, 0x4a, 0x70, 0x5b, 0x7f, + 0xb5, 0xbd, 0x87, 0xb5, 0x38, 0x72, 0x15, 0xc2, 0x55, 0xb2, 0xbe, 0x76, + 0x61, 0x1d, 0x66, 0x0e, 0x73, 0x95, 0x32, 0x1b, 0xbb, 0x16, 0x50, 0xd7, + 0x57, 0xd1, 0x26, 0x72, 0x78, 0x75, 0xfb, 0x60, 0x0e, 0x97, 0x7a, 0xd9, + 0xff, 0x71, 0x57, 0xce, 0xde, 0xd2, 0xb4, 0x37, 0xaf, 0xd6, 0xa2, 0xa4, + 0x33, 0x0d, 0xde, 0x69, 0x97, 0x3d, 0x8b, 0x01, 0x6f, 0xa5, 0x51, 0x38, + 0x27, 0x4c, 0x4c, 0xcb, 0x3e, 0x58, 0x96, 0xcf, 0xdb, 0x3e, 0xa6, 0xfc, + 0xc7, 0xe9, 0xeb, 0xfa, 0x3f, 0x51, 0x5f, 0x72, 0xae, 0xac, 0xa0, 0x2f, + 0x6d, 0xca, 0xd9, 0x88, 0x9c, 0xce, 0xaa, 0x0d, 0x39, 0x4b, 0x78, 0x41, + 0x67, 0x77, 0x51, 0x67, 0xf5, 0xe7, 0x75, 0x76, 0x5d, 0x5e, 0x67, 0x25, + 0xd4, 0x59, 0x35, 0x71, 0x57, 0x30, 0xf9, 0x5a, 0x62, 0xf2, 0xb7, 0xec, + 0x7b, 0xb3, 0xa9, 0x97, 0x9c, 0xce, 0x34, 0xea, 0x6c, 0x2a, 0xde, 0x5f, + 0x85, 0x76, 0xe2, 0x7d, 0x05, 0xe3, 0x61, 0x99, 0x9c, 0xed, 0xba, 0xe1, + 0x2a, 0xdc, 0x39, 0x58, 0x82, 0xb9, 0x83, 0x2e, 0xea, 0xd2, 0x8e, 0x01, + 0xe4, 0xf4, 0xae, 0xf3, 0x7a, 0x6c, 0x18, 0x94, 0x71, 0xad, 0x51, 0x7e, + 0xc8, 0x71, 0x05, 0x8a, 0x72, 0x7a, 0x7c, 0x25, 0x9b, 0xeb, 0x43, 0xb5, + 0x26, 0xf1, 0xac, 0x45, 0x79, 0x35, 0x23, 0x38, 0xfb, 0x3d, 0xea, 0x6a, + 0x0d, 0x9f, 0x35, 0x78, 0x7d, 0xe0, 0x58, 0x3e, 0xf6, 0xbc, 0x9f, 0xe8, + 0xeb, 0x7b, 0xe7, 0xf5, 0xfa, 0xc7, 0xcb, 0x16, 0xec, 0x4a, 0xce, 0xfb, + 0x15, 0xf4, 0xa5, 0x4d, 0xc1, 0x48, 0xcb, 0x7a, 0x5a, 0x9f, 0x85, 0x78, + 0x75, 0x30, 0x2d, 0x6b, 0x46, 0x69, 0xf2, 0x1d, 0x47, 0xaf, 0xf4, 0x59, + 0x72, 0x03, 0xf5, 0x66, 0xb2, 0xbf, 0x46, 0x07, 0x3a, 0x71, 0x42, 0xd7, + 0x7a, 0xee, 0xc3, 0xa7, 0xd0, 0xe5, 0xb3, 0xb0, 0x47, 0x6f, 0x67, 0xee, + 0x53, 0x8a, 0x55, 0x8d, 0x34, 0xf9, 0xbb, 0x62, 0xe8, 0x4b, 0x99, 0xed, + 0x0e, 0xc8, 0x9a, 0xec, 0xf7, 0xbf, 0x90, 0x08, 0x05, 0xdb, 0x56, 0x2b, + 0xc0, 0xe2, 0xa4, 0x1b, 0x01, 0xc5, 0xe6, 0x26, 0xe1, 0x7e, 0x55, 0xd6, + 0x96, 0xb7, 0x17, 0xe5, 0xce, 0x6a, 0xa8, 0x08, 0xd4, 0x48, 0x3b, 0xed, + 0x30, 0xc7, 0xa4, 0x2e, 0xf5, 0x38, 0x53, 0xc1, 0x6d, 0x33, 0x83, 0x66, + 0x5c, 0xb1, 0xac, 0xa5, 0x11, 0xa7, 0xfd, 0x7c, 0xcb, 0x58, 0x43, 0xfc, + 0x6e, 0xf5, 0xe7, 0x96, 0x69, 0xaf, 0x67, 0x07, 0xbd, 0x31, 0xf5, 0x8f, + 0x8d, 0x93, 0x79, 0x03, 0x73, 0x84, 0xfd, 0xf9, 0x35, 0x5c, 0x97, 0x11, + 0x5e, 0xbe, 0xc7, 0x5e, 0x47, 0xfe, 0x96, 0x7d, 0x2e, 0x25, 0x9d, 0x92, + 0x35, 0xc0, 0xa8, 0x07, 0xa5, 0xed, 0xe8, 0x1a, 0xbb, 0x01, 0x23, 0x8d, + 0xbf, 0xb0, 0x32, 0xb9, 0xbe, 0x8b, 0x79, 0xbb, 0x6b, 0x8d, 0x13, 0x5f, + 0xb8, 0x71, 0x96, 0x70, 0x47, 0x39, 0x43, 0x4a, 0xde, 0xae, 0xe4, 0xb8, + 0xec, 0x0c, 0xed, 0x16, 0x1c, 0xbc, 0x48, 0xa6, 0xac, 0x31, 0x14, 0x64, + 0xb6, 0x51, 0x9e, 0xc8, 0x75, 0x51, 0x57, 0xff, 0x6e, 0x0d, 0xfa, 0xa6, + 0x96, 0xfb, 0x47, 0x77, 0x2e, 0xc6, 0x49, 0xb9, 0x42, 0xbb, 0xc2, 0xed, + 0x3e, 0xb0, 0x86, 0x2e, 0x2a, 0xf7, 0x6a, 0x9e, 0x33, 0x3d, 0xe4, 0x91, + 0x33, 0x2d, 0xe9, 0x54, 0x31, 0xf9, 0xd4, 0x09, 0x6b, 0xef, 0x45, 0x65, + 0x3e, 0xbc, 0xa4, 0x4c, 0x3d, 0x73, 0xb5, 0x7f, 0xb1, 0x86, 0x2f, 0x2a, + 0x53, 0x59, 0x7a, 0x71, 0x99, 0x6b, 0x88, 0xb3, 0xaf, 0x5a, 0xbb, 0x2f, + 0x2a, 0xf3, 0x77, 0x97, 0xc8, 0x99, 0x4b, 0x1b, 0x7f, 0xda, 0xda, 0x97, + 0x2f, 0xe3, 0x64, 0x99, 0x75, 0xda, 0x53, 0xf9, 0xbc, 0xbc, 0x50, 0xa6, + 0x70, 0xbf, 0xa4, 0xec, 0xd2, 0xfb, 0x39, 0x99, 0xe1, 0x4b, 0x64, 0x06, + 0x4d, 0x99, 0x6f, 0x57, 0x53, 0x61, 0xbe, 0xa3, 0xf9, 0xfb, 0xdf, 0x28, + 0xbb, 0xb8, 0xdc, 0xc4, 0x25, 0xd7, 0x05, 0x79, 0x7f, 0xed, 0xbe, 0xf8, + 0x7e, 0x65, 0xf1, 0xc5, 0xd7, 0xbb, 0x8b, 0x72, 0xd7, 0x05, 0x9d, 0x6e, + 0xb9, 0xe4, 0xf9, 0x7f, 0x2b, 0xba, 0xf8, 0xfa, 0xc6, 0xe2, 0xcb, 0xb7, + 0xf3, 0x93, 0x4b, 0xee, 0x2b, 0x5d, 0xf2, 0xfe, 0x89, 0xc3, 0x50, 0x2b, + 0xba, 0xa2, 0xab, 0x6e, 0x8a, 0x67, 0x7b, 0x68, 0x9f, 0x62, 0x5b, 0xab, + 0x6f, 0x5a, 0x91, 0x3d, 0x79, 0x7e, 0x8f, 0x3b, 0xad, 0x2f, 0xf0, 0x7b, + 0xf1, 0x59, 0xac, 0xb0, 0xf7, 0xd2, 0x64, 0x8d, 0xc7, 0xe4, 0x18, 0xed, + 0x77, 0x51, 0xdc, 0x8a, 0x11, 0x87, 0x6e, 0x9f, 0x07, 0x5d, 0x89, 0xfa, + 0xac, 0xbd, 0x8f, 0x17, 0x8e, 0xe3, 0xa0, 0xda, 0xaa, 0x99, 0xf9, 0x73, + 0x7e, 0xe6, 0x8d, 0x5e, 0xc4, 0xa6, 0xe6, 0xd2, 0x81, 0x61, 0xfb, 0x2c, + 0x69, 0x07, 0xba, 0xed, 0x73, 0xaa, 0xed, 0xf9, 0xf3, 0xa4, 0xcb, 0xa1, + 0x65, 0x0b, 0x7c, 0x4b, 0xd6, 0x64, 0xe5, 0x6c, 0x85, 0x45, 0x1f, 0x14, + 0xfe, 0x70, 0x40, 0x51, 0x93, 0xf6, 0xba, 0xe7, 0x32, 0x07, 0x42, 0xcd, + 0x2d, 0x0a, 0xe2, 0x25, 0x46, 0x28, 0xf0, 0x4e, 0x1e, 0x2b, 0x5d, 0x23, + 0xeb, 0x94, 0xa2, 0x91, 0x1e, 0xc5, 0x39, 0x92, 0xc3, 0x4a, 0xc7, 0x88, + 0xf0, 0xfb, 0x6a, 0x96, 0xf1, 0x62, 0xd6, 0x3c, 0x27, 0x5e, 0x48, 0x54, + 0xd8, 0xef, 0x34, 0xac, 0x9f, 0x57, 0x84, 0x07, 0x23, 0x0a, 0x5a, 0xe7, + 0x1c, 0xc6, 0x49, 0xe6, 0x32, 0x87, 0x13, 0x66, 0x64, 0x88, 0x6d, 0x4e, + 0x24, 0x54, 0x1c, 0x1a, 0x58, 0x17, 0x19, 0xb4, 0xdb, 0x37, 0xd1, 0x6d, + 0xef, 0x5b, 0x2d, 0xb3, 0x36, 0xa6, 0x96, 0x5b, 0x1b, 0x52, 0x4e, 0xe6, + 0x9f, 0xd5, 0xf1, 0x4a, 0xd6, 0x3f, 0x39, 0x6f, 0x15, 0x4e, 0xb1, 0xcc, + 0x48, 0x62, 0x35, 0x3e, 0xc8, 0x7a, 0xed, 0xf5, 0x9a, 0x1f, 0x64, 0x3d, + 0xcc, 0xa7, 0x5a, 0xf1, 0x42, 0x76, 0x19, 0x9e, 0x1f, 0x90, 0x33, 0xe4, + 0x2d, 0x58, 0x90, 0x50, 0xb0, 0x38, 0xb4, 0x0c, 0xc7, 0x86, 0x96, 0xe1, + 0xf0, 0x80, 0xbc, 0x47, 0x70, 0x45, 0xfe, 0xcc, 0xb9, 0x3c, 0x8f, 0xf1, + 0xf9, 0x52, 0x4c, 0x0c, 0xf9, 0x99, 0x0b, 0xe9, 0x78, 0x33, 0xeb, 0xc3, + 0x60, 0xa2, 0x11, 0xc7, 0xc9, 0xe7, 0x9f, 0x49, 0x34, 0xe3, 0x2c, 0xaf, + 0x0f, 0x24, 0x84, 0x07, 0x45, 0x71, 0x26, 0xfb, 0x7d, 0x14, 0x25, 0x6b, + 0x71, 0xa4, 0xed, 0x69, 0xa8, 0xc9, 0x03, 0xfc, 0xb4, 0xe2, 0xf8, 0x50, + 0x2b, 0x4e, 0x0c, 0xdc, 0x86, 0x13, 0x43, 0x3f, 0xc3, 0xc9, 0x01, 0xe9, + 0xaf, 0x9c, 0x2b, 0x17, 0xb9, 0x1a, 0xe5, 0x2e, 0xc3, 0xf8, 0xd0, 0x9f, + 0x23, 0xfb, 0x3d, 0xeb, 0xc8, 0x32, 0x91, 0xfb, 0xf4, 0x27, 0xc8, 0xce, + 0xe5, 0x4a, 0x72, 0x66, 0xf4, 0x58, 0xc2, 0x8d, 0xa3, 0x89, 0xf1, 0x6b, + 0x4b, 0x30, 0x7e, 0x23, 0x91, 0x0e, 0x1b, 0x99, 0xc3, 0x1d, 0x4a, 0xcb, + 0xba, 0xdf, 0x67, 0x98, 0x17, 0xaf, 0xc3, 0xfa, 0xb1, 0x62, 0xbc, 0x90, + 0x76, 0x53, 0xc7, 0x37, 0x22, 0x56, 0xd5, 0x4e, 0xfd, 0x79, 0xf0, 0x62, + 0xc2, 0x87, 0x97, 0x12, 0x0d, 0x8c, 0x0f, 0x4d, 0xc8, 0xad, 0x77, 0x7a, + 0xa8, 0xef, 0x0e, 0xbb, 0x4f, 0x2f, 0x24, 0x96, 0x59, 0xeb, 0xa9, 0xe3, + 0x9e, 0xd4, 0xd7, 0xec, 0x33, 0xe1, 0xcf, 0x27, 0xce, 0x30, 0x27, 0x39, + 0x8a, 0xc7, 0xa9, 0xd3, 0x63, 0x89, 0x38, 0x39, 0x63, 0x1d, 0xe7, 0x68, + 0x1c, 0x43, 0xd9, 0xb5, 0x78, 0x33, 0xad, 0x1d, 0x5d, 0x81, 0xb5, 0x38, + 0x9b, 0x29, 0xc6, 0xeb, 0x6c, 0xa3, 0x72, 0xae, 0x13, 0x93, 0xb6, 0xbc, + 0xb5, 0xf8, 0x20, 0xad, 0x30, 0x8e, 0xaf, 0xc5, 0xfb, 0x7c, 0xf6, 0x32, + 0x7f, 0x9f, 0x8a, 0xb0, 0x87, 0xf9, 0x67, 0x27, 0xc8, 0xeb, 0x65, 0x7d, + 0xab, 0x2b, 0xba, 0x16, 0xc7, 0x33, 0xcf, 0x92, 0x0b, 0x57, 0xe2, 0x61, + 0x7d, 0x1a, 0x9a, 0xa7, 0x91, 0x8b, 0x69, 0xc5, 0x38, 0xc6, 0xe7, 0x33, + 0x89, 0xbf, 0xe3, 0xde, 0x5c, 0xf9, 0xf7, 0x38, 0x9e, 0x07, 0x29, 0xeb, + 0xdd, 0xcc, 0x37, 0x29, 0x77, 0x3e, 0xb2, 0x91, 0x6f, 0x52, 0xee, 0xcf, + 0x30, 0x9c, 0xd7, 0xc7, 0x71, 0x5d, 0xc6, 0xf5, 0xf5, 0x72, 0xc9, 0xa9, + 0x27, 0x12, 0xdf, 0xe0, 0x77, 0x07, 0x26, 0xb3, 0x3b, 0xf8, 0xfd, 0x03, + 0xec, 0x63, 0x8c, 0x4e, 0xa4, 0x2e, 0xe5, 0xe3, 0xd3, 0xb1, 0xa9, 0xaf, + 0x22, 0x5e, 0x45, 0xfb, 0x89, 0x5c, 0x5f, 0x89, 0xd9, 0x91, 0x04, 0x36, + 0xef, 0x76, 0x62, 0x13, 0xf1, 0x76, 0x73, 0xb2, 0x1a, 0x3b, 0xb7, 0x79, + 0x91, 0xda, 0x76, 0x25, 0x7a, 0xb7, 0x5d, 0x8d, 0xe4, 0xb6, 0x3a, 0x6c, + 0xdc, 0x46, 0x9d, 0xcf, 0xb5, 0xac, 0x93, 0x11, 0xcb, 0x3a, 0xcc, 0xcf, + 0x5e, 0x7e, 0xde, 0xd3, 0xc5, 0x3f, 0x62, 0x08, 0xdb, 0x7e, 0xd2, 0x42, + 0x3f, 0x91, 0x6f, 0x0d, 0xd7, 0x64, 0xd7, 0x44, 0x66, 0x8e, 0xae, 0x8d, + 0x34, 0x8c, 0x4e, 0x47, 0x77, 0x5f, 0x0d, 0xd6, 0x6f, 0xab, 0x8e, 0x7b, + 0xd9, 0x8e, 0xf7, 0x7a, 0x0b, 0x9d, 0xf4, 0x9f, 0x67, 0xf4, 0x9e, 0xc8, + 0xfc, 0xd1, 0xa7, 0xc9, 0x43, 0x7d, 0xd8, 0xd9, 0xe7, 0x67, 0x1b, 0x0a, + 0x2a, 0x35, 0xe7, 0xaa, 0x4a, 0x8e, 0xe3, 0x68, 0xe4, 0x00, 0xca, 0x47, + 0xbf, 0x4f, 0x9e, 0xe7, 0xc3, 0xc6, 0xbe, 0x22, 0x79, 0x4f, 0x08, 0xbd, + 0x51, 0x0b, 0xef, 0xe9, 0xe3, 0x28, 0xa3, 0xbc, 0xae, 0xbe, 0x0a, 0x74, + 0x6f, 0xf3, 0x50, 0x66, 0x05, 0x1e, 0xdb, 0x56, 0x1a, 0x2f, 0x32, 0x44, + 0xde, 0x12, 0xfc, 0x74, 0xe4, 0x6b, 0xd8, 0x34, 0xe6, 0x41, 0x0f, 0xef, + 0xaf, 0xdb, 0xe6, 0x75, 0xbf, 0xc0, 0x3a, 0xed, 0x6c, 0xeb, 0xbf, 0xf1, + 0xf3, 0x01, 0xfb, 0x5d, 0x1c, 0x59, 0x83, 0xcd, 0x63, 0xc2, 0x6d, 0x8e, + 0xc2, 0x3f, 0xda, 0x8a, 0x97, 0x47, 0xda, 0xf0, 0xb7, 0x23, 0xff, 0xea, + 0x41, 0xc5, 0x32, 0xdc, 0x3f, 0x22, 0xfb, 0xee, 0x71, 0xdc, 0x93, 0x10, + 0x3c, 0x5a, 0x89, 0x3d, 0x09, 0xd9, 0xbf, 0x6c, 0xc7, 0xb3, 0x09, 0xb1, + 0xdf, 0xe5, 0xb4, 0xdf, 0x0e, 0xe6, 0x74, 0x92, 0x47, 0x64, 0x22, 0xf5, + 0xa3, 0xdf, 0x8e, 0x5c, 0x33, 0xfa, 0x73, 0x72, 0xf0, 0xa1, 0x48, 0x68, + 0x74, 0x27, 0xc7, 0x39, 0x49, 0x5e, 0x7d, 0x82, 0x5c, 0xfb, 0x75, 0x72, + 0xe1, 0x42, 0x1c, 0xfc, 0xaf, 0xce, 0x5c, 0x8e, 0x52, 0xc8, 0x03, 0x0b, + 0x6b, 0xed, 0x96, 0xe5, 0x60, 0x9e, 0xb3, 0xd0, 0x2b, 0xb9, 0x42, 0x17, + 0xd6, 0xef, 0x58, 0x8d, 0x0d, 0x3b, 0x1a, 0xbc, 0x7b, 0x19, 0xb3, 0x62, + 0x3e, 0xe1, 0xee, 0xf9, 0xfc, 0xee, 0xfc, 0x1a, 0x98, 0xac, 0xd9, 0x77, + 0xd0, 0xe7, 0xd7, 0xd9, 0xe7, 0x38, 0x4b, 0x35, 0x04, 0x4a, 0xb4, 0xdf, + 0x5a, 0xb1, 0xf3, 0xf5, 0xdb, 0x2d, 0x59, 0x97, 0x2d, 0x36, 0x14, 0x8c, + 0x69, 0x6d, 0xf6, 0x7e, 0xd8, 0x71, 0x9b, 0x8f, 0x75, 0x21, 0x35, 0x4c, + 0x6e, 0xbc, 0x4b, 0xc6, 0xb1, 0x52, 0xc6, 0x61, 0xaa, 0xda, 0x32, 0x6b, + 0x5d, 0x0a, 0xb7, 0x16, 0x31, 0xbf, 0x58, 0x35, 0x52, 0x84, 0xf8, 0x9e, + 0x52, 0xdc, 0xb3, 0x6d, 0xb9, 0x95, 0x4a, 0x09, 0xff, 0x96, 0x3c, 0xbb, + 0x14, 0x9d, 0xbc, 0xb7, 0xa6, 0x4f, 0xf6, 0x21, 0x42, 0x1d, 0xb5, 0x8e, + 0x52, 0x3c, 0xb4, 0x8b, 0xfd, 0xd8, 0xb5, 0x04, 0xf1, 0x5d, 0x47, 0x60, + 0x66, 0x54, 0x8c, 0x0c, 0x38, 0xe1, 0x37, 0x4e, 0x93, 0x6f, 0xfd, 0x0c, + 0xc9, 0x21, 0x15, 0xd9, 0x01, 0x45, 0xdb, 0x18, 0x1a, 0xc5, 0xc6, 0x21, + 0x27, 0xf6, 0x26, 0x5a, 0xf0, 0x36, 0x71, 0x6e, 0x30, 0x11, 0xc3, 0x71, + 0xea, 0x76, 0x72, 0xcf, 0x32, 0x7e, 0x3c, 0xf4, 0xf7, 0x83, 0xf4, 0x9d, + 0x30, 0xba, 0xe9, 0x47, 0x07, 0x13, 0x1a, 0x1e, 0xcb, 0xde, 0x0c, 0x73, + 0xe8, 0x0e, 0x6c, 0x1e, 0x32, 0xf1, 0xe8, 0x8e, 0x36, 0x7e, 0x1b, 0x78, + 0x74, 0xe8, 0x6b, 0x58, 0x33, 0x72, 0x14, 0x9b, 0xb2, 0x71, 0xbc, 0x33, + 0xf2, 0x2c, 0x92, 0x69, 0x9d, 0xbe, 0x21, 0xdc, 0x4d, 0xc1, 0xe6, 0x79, + 0xcf, 0x62, 0x73, 0xe6, 0x30, 0x36, 0xa6, 0x3b, 0xc9, 0x09, 0x0f, 0x63, + 0x03, 0x7f, 0xaf, 0x4f, 0x6b, 0xfe, 0x41, 0x1c, 0x46, 0x77, 0x66, 0x2d, + 0x3a, 0xfb, 0x44, 0x5f, 0x0a, 0xce, 0xde, 0xb0, 0x16, 0x0f, 0xef, 0xea, + 0xc0, 0x03, 0x23, 0x3f, 0xc0, 0xce, 0xec, 0xb3, 0xe8, 0x4d, 0x27, 0x90, + 0xda, 0x2a, 0xfa, 0xac, 0xc4, 0x0f, 0x22, 0x78, 0xa0, 0x12, 0xa1, 0xb6, + 0xa4, 0x22, 0xb2, 0xd6, 0x60, 0x13, 0xfd, 0x7a, 0x63, 0x4a, 0xf4, 0xfb, + 0x34, 0xdb, 0x3c, 0x40, 0xbc, 0x58, 0x43, 0x7d, 0x3c, 0xc2, 0x4f, 0x61, + 0xcf, 0x76, 0xea, 0x3e, 0x83, 0xf8, 0x8b, 0xdf, 0xce, 0xe5, 0x4b, 0x7b, + 0x25, 0xaf, 0x1c, 0x0f, 0x96, 0x92, 0x8b, 0x94, 0xf4, 0x8a, 0x3e, 0xdb, + 0xad, 0xae, 0xd4, 0xf8, 0x67, 0x4b, 0x20, 0x73, 0x10, 0x20, 0x76, 0xff, + 0x0c, 0xeb, 0xe9, 0x8f, 0xb7, 0xca, 0xe1, 0x15, 0xc6, 0xa1, 0x43, 0xf4, + 0xe7, 0xb8, 0xcf, 0xb2, 0x9e, 0xd2, 0x59, 0xad, 0xb7, 0x83, 0x78, 0xe5, + 0xca, 0xef, 0xc5, 0x8d, 0x5f, 0x5b, 0x41, 0x19, 0xe5, 0xbd, 0x5d, 0x72, + 0xe6, 0x45, 0xcf, 0xe5, 0xbc, 0x96, 0xb5, 0x25, 0x54, 0xb0, 0x9f, 0xf1, + 0x6b, 0xcb, 0x31, 0x4d, 0xd6, 0x8f, 0x9b, 0x73, 0xef, 0xc1, 0x9d, 0x63, + 0x5c, 0xec, 0xc2, 0x96, 0xe1, 0xb6, 0xbc, 0x1d, 0xfd, 0xbf, 0x92, 0x77, + 0xb9, 0x3d, 0xbe, 0x6b, 0xec, 0x75, 0x1f, 0xd8, 0x67, 0xea, 0x81, 0x7b, + 0x13, 0xb2, 0x6f, 0xa2, 0xde, 0x40, 0x56, 0x45, 0x0b, 0x2d, 0xc6, 0x61, + 0xfd, 0x4a, 0x74, 0x93, 0x77, 0xde, 0xa2, 0x17, 0x61, 0xb8, 0xd1, 0xc0, + 0xa4, 0xd7, 0x6c, 0x13, 0xce, 0x56, 0x66, 0x8c, 0xb7, 0x7f, 0x39, 0x14, + 0x94, 0xbc, 0x10, 0x61, 0x62, 0x08, 0x6c, 0xce, 0xd6, 0x83, 0x64, 0x4a, + 0x81, 0x47, 0xbb, 0x03, 0xd9, 0x2a, 0x9f, 0xb4, 0x1f, 0x2e, 0x9c, 0xbf, + 0x2c, 0xd6, 0xce, 0xe5, 0xdf, 0x7d, 0x5b, 0xc2, 0xf9, 0xa0, 0x6d, 0xcf, + 0xb4, 0xac, 0xb6, 0x48, 0x00, 0xf5, 0xa1, 0x86, 0x40, 0x95, 0xfa, 0x0b, + 0xcb, 0x94, 0x3d, 0xa9, 0x31, 0x39, 0x0f, 0x78, 0xb9, 0xfc, 0xfd, 0x21, + 0x6c, 0xdc, 0x3a, 0x07, 0x93, 0x3e, 0x91, 0xf9, 0x44, 0x79, 0x4e, 0x8e, + 0xac, 0x5f, 0xbc, 0x5a, 0x81, 0xd2, 0x1e, 0xfa, 0x4a, 0x0f, 0x7a, 0x52, + 0x2a, 0xdb, 0x78, 0xd3, 0x2a, 0x9e, 0x2e, 0xe3, 0xfe, 0x1f, 0x15, 0xb9, + 0x32, 0xaf, 0x55, 0x08, 0xbf, 0xd8, 0x94, 0xea, 0xa1, 0xee, 0x54, 0xc6, + 0x9b, 0x7f, 0xb1, 0x8e, 0xf8, 0xaa, 0xf9, 0x3c, 0x9e, 0x97, 0xb1, 0x4e, + 0xd6, 0xd1, 0xf4, 0x18, 0xe4, 0xde, 0x2b, 0x2c, 0x2b, 0xfa, 0xea, 0xa1, + 0x1e, 0x1c, 0xe4, 0x9e, 0x3e, 0x74, 0x7a, 0x73, 0x6b, 0x34, 0x17, 0xc6, + 0x21, 0x65, 0x64, 0x2c, 0x3d, 0x48, 0xa5, 0x64, 0x1f, 0xe3, 0xac, 0x75, + 0x6a, 0xba, 0x3c, 0x2f, 0xc9, 0xb7, 0x57, 0x6b, 0xef, 0xad, 0x3d, 0x9a, + 0x72, 0x4c, 0xe9, 0x9b, 0xd4, 0xb5, 0x65, 0xb3, 0xfe, 0xa7, 0x2e, 0x69, + 0xd7, 0x6b, 0x73, 0x72, 0xd5, 0x9e, 0xa7, 0x57, 0xf2, 0xe5, 0xcb, 0xcb, + 0x0b, 0xef, 0x2f, 0xc8, 0xd9, 0xde, 0x0b, 0x6d, 0x4f, 0x2d, 0x23, 0x6b, + 0x01, 0xb9, 0xba, 0xcd, 0x3b, 0x0a, 0xf2, 0x2d, 0xab, 0x68, 0x6e, 0x3b, + 0x6d, 0xd4, 0xea, 0x2c, 0x26, 0x46, 0xbe, 0x1d, 0xf5, 0x63, 0x7d, 0x42, + 0x74, 0xa4, 0xf9, 0xf7, 0x12, 0x03, 0xba, 0x6d, 0x4e, 0xe1, 0x42, 0x57, + 0xa6, 0x70, 0xde, 0x44, 0xd6, 0x3d, 0xe5, 0xdc, 0x9a, 0xbc, 0x87, 0x43, + 0x2e, 0xe5, 0x5d, 0x10, 0x70, 0x92, 0x0f, 0xdd, 0x8b, 0xff, 0xe0, 0x5c, + 0xc8, 0xfb, 0x24, 0xb9, 0x35, 0x91, 0x38, 0x6d, 0x20, 0x17, 0x93, 0x40, + 0x5f, 0x27, 0x17, 0xca, 0x9f, 0xb3, 0xef, 0xca, 0xfe, 0x87, 0x35, 0x6e, + 0x9f, 0xb3, 0xbf, 0x70, 0xa6, 0x23, 0xe3, 0x95, 0x77, 0x39, 0x31, 0xe5, + 0xcc, 0x3d, 0x63, 0x88, 0x26, 0x67, 0xf3, 0x7f, 0x67, 0xad, 0xb8, 0xa8, + 0xec, 0x78, 0x55, 0xee, 0x1d, 0x94, 0x98, 0xba, 0x40, 0x2b, 0xf0, 0x3b, + 0xd9, 0x57, 0x12, 0x5e, 0x77, 0x77, 0x65, 0x6e, 0xbd, 0x35, 0xd8, 0xda, + 0x06, 0xd9, 0xdb, 0x2e, 0xf0, 0x35, 0x4d, 0x9f, 0xad, 0x74, 0x62, 0x56, + 0xa4, 0x54, 0xde, 0xa9, 0x0d, 0x3a, 0x8d, 0xa0, 0xf7, 0x24, 0x42, 0xe1, + 0xc3, 0xf6, 0x59, 0x0c, 0xf1, 0x6d, 0x0d, 0xf7, 0x66, 0x1b, 0xa9, 0x1b, + 0x79, 0x1f, 0x5a, 0x7e, 0xdb, 0xf2, 0xf9, 0x1b, 0xee, 0x72, 0x62, 0xfb, + 0x48, 0xd2, 0xfc, 0xaf, 0x2e, 0x5b, 0x5e, 0xb0, 0x7d, 0xc8, 0x7e, 0x57, + 0xa9, 0x20, 0xcf, 0x73, 0x19, 0x79, 0x61, 0xd6, 0x0f, 0x53, 0x96, 0xc8, + 0xd0, 0x28, 0xe3, 0xd2, 0xf3, 0x39, 0xd3, 0xe3, 0x92, 0x23, 0xef, 0xcb, + 0xf3, 0xbe, 0xc3, 0x7f, 0x90, 0x23, 0x5f, 0xb6, 0xcd, 0x18, 0xdb, 0x6c, + 0x2d, 0x55, 0x62, 0x11, 0x79, 0x57, 0xa8, 0x38, 0x12, 0x0a, 0x3f, 0x47, + 0xe7, 0x74, 0x1a, 0x21, 0xff, 0x90, 0x7d, 0x66, 0x44, 0x77, 0x2f, 0xcc, + 0xe6, 0xf2, 0x29, 0x73, 0xec, 0x93, 0x75, 0x52, 0xa6, 0x69, 0x6d, 0x0d, + 0x4a, 0xec, 0x46, 0x22, 0x38, 0xc2, 0x11, 0x04, 0x8a, 0x8c, 0x82, 0x8e, + 0x42, 0xe1, 0x93, 0x9c, 0xcf, 0x89, 0x68, 0x88, 0x78, 0x29, 0x5c, 0x49, + 0xf4, 0xa2, 0xbb, 0x73, 0x73, 0xdf, 0x28, 0x9c, 0xda, 0x74, 0x31, 0xee, + 0x0d, 0x27, 0x64, 0x9d, 0xab, 0xc1, 0xbb, 0x11, 0x55, 0xb4, 0x57, 0xc4, + 0xba, 0x1b, 0xe3, 0xd8, 0x97, 0x40, 0xcc, 0x31, 0xa7, 0x12, 0x71, 0x92, + 0x64, 0x87, 0x16, 0x27, 0xef, 0x69, 0x08, 0x6f, 0xa2, 0x0d, 0xca, 0xd9, + 0x46, 0x13, 0x71, 0x1c, 0x4a, 0x2c, 0xf8, 0x4b, 0x07, 0x4c, 0xbd, 0x0c, + 0xf2, 0xae, 0x16, 0xbe, 0x78, 0x5b, 0x28, 0x18, 0x78, 0x3e, 0x7f, 0xe6, + 0xa5, 0x2b, 0xf1, 0x91, 0xbd, 0xa7, 0xe5, 0xd0, 0x3e, 0xa9, 0x8c, 0xdb, + 0x5e, 0xc7, 0xdd, 0x9b, 0xfe, 0x36, 0xd6, 0x6d, 0x65, 0x1f, 0x99, 0xdf, + 0x2f, 0xd0, 0x3b, 0xb1, 0x50, 0xf7, 0x60, 0xa5, 0x77, 0x56, 0xb3, 0x9c, + 0xe9, 0x19, 0xcc, 0xe4, 0xd6, 0x3d, 0xd6, 0xdb, 0x67, 0x6a, 0x06, 0xb0, + 0x99, 0x3e, 0x56, 0xa2, 0xc9, 0xb9, 0xab, 0x98, 0xb2, 0x39, 0xdb, 0xa2, + 0x6c, 0xca, 0xaf, 0xb3, 0xf5, 0x64, 0x5f, 0xaf, 0x44, 0xa9, 0x89, 0xe3, + 0xba, 0xbc, 0x23, 0x29, 0x72, 0x4d, 0x0c, 0x45, 0xff, 0x94, 0x77, 0x25, + 0x45, 0xa7, 0x6b, 0xd0, 0x3d, 0xf0, 0x08, 0xba, 0x06, 0x5e, 0xb4, 0xcf, + 0xb6, 0xba, 0x34, 0xb7, 0x79, 0xb5, 0x11, 0x3c, 0x60, 0xe2, 0x69, 0xaf, + 0xac, 0xe7, 0xd6, 0x18, 0x47, 0xb1, 0xd9, 0x2b, 0xef, 0x00, 0x0e, 0x90, + 0x03, 0x08, 0xce, 0x2d, 0xc7, 0x97, 0x93, 0x32, 0x87, 0x15, 0xc4, 0xfc, + 0x60, 0x6c, 0xa5, 0x3d, 0x87, 0x8d, 0x38, 0x36, 0xfa, 0x08, 0xde, 0xde, + 0xde, 0x09, 0x35, 0x12, 0xf4, 0x2f, 0x82, 0xd5, 0x79, 0x44, 0x8f, 0x99, + 0x2e, 0x04, 0xf7, 0x39, 0x54, 0xe0, 0xe0, 0x76, 0xc9, 0x69, 0xdb, 0x71, + 0x23, 0x63, 0x6d, 0xa5, 0x66, 0xcd, 0xff, 0xb7, 0xb9, 0xc1, 0x1e, 0xcd, + 0x61, 0xfe, 0xf3, 0x74, 0x04, 0xd3, 0xcd, 0xaa, 0xd6, 0x7e, 0xa7, 0x0a, + 0xc5, 0x63, 0xc8, 0x7b, 0xeb, 0x9d, 0xb8, 0xa3, 0xc9, 0x63, 0x96, 0x1b, + 0xc1, 0xf4, 0x8b, 0x4a, 0x30, 0x6c, 0xaa, 0x9f, 0xe7, 0x3c, 0x87, 0xf1, + 0xfc, 0xa8, 0x17, 0xad, 0xbd, 0x3a, 0x16, 0xf7, 0x36, 0xda, 0xb8, 0xa5, + 0x6a, 0xf5, 0xcd, 0x25, 0x8a, 0x17, 0x8b, 0x46, 0x81, 0x89, 0xcc, 0x72, + 0xbc, 0xb9, 0x5d, 0x47, 0x0b, 0x9f, 0xf5, 0xa5, 0x9e, 0xaa, 0x94, 0xb3, + 0x6f, 0x1d, 0xba, 0xd9, 0xa0, 0x22, 0x74, 0xd4, 0xa5, 0x62, 0xc1, 0x0c, + 0x23, 0x34, 0x3e, 0xdf, 0xe1, 0x44, 0xf3, 0xa8, 0x13, 0x77, 0xb1, 0xcc, + 0x46, 0x62, 0xfa, 0x9d, 0xbd, 0x6e, 0xf2, 0x87, 0x3a, 0x7c, 0x48, 0xae, + 0xfb, 0x2b, 0x72, 0xda, 0x49, 0xc6, 0xe6, 0xc9, 0x6c, 0x29, 0xda, 0xfa, + 0x5d, 0x72, 0x8e, 0x67, 0xdc, 0xc5, 0xb9, 0xa8, 0x68, 0xf2, 0xe1, 0xd4, + 0x90, 0x1b, 0x9f, 0xdb, 0x1e, 0xdc, 0x39, 0xa9, 0xd6, 0xe0, 0x83, 0xa1, + 0x52, 0x7b, 0xbd, 0xb2, 0xdc, 0xb0, 0xb0, 0x85, 0x38, 0xfd, 0x1e, 0x9f, + 0xb5, 0x6c, 0x87, 0x92, 0x9d, 0x77, 0x0d, 0x79, 0xb9, 0xc6, 0xfa, 0x65, + 0xb8, 0xad, 0x5f, 0xd6, 0x68, 0x54, 0xbc, 0x33, 0xa4, 0xe0, 0x64, 0x46, + 0xc7, 0x02, 0xb6, 0xd7, 0x9d, 0x3a, 0x68, 0xb9, 0xe9, 0xe7, 0x2b, 0xb2, + 0x3a, 0xee, 0xcb, 0x34, 0xa2, 0x37, 0xf5, 0x06, 0x39, 0x50, 0x13, 0xde, + 0xd8, 0xa6, 0x1d, 0x7d, 0xcb, 0x11, 0x1a, 0x9f, 0xe7, 0x68, 0xc2, 0xeb, + 0x7b, 0x9a, 0xf0, 0xc3, 0xbe, 0xf9, 0xf8, 0x74, 0x53, 0x0c, 0xa7, 0xe7, + 0x35, 0xe1, 0x95, 0x5d, 0x8d, 0xc4, 0xe8, 0x28, 0x02, 0x23, 0xe3, 0xd8, + 0x92, 0x6c, 0x46, 0xc3, 0x88, 0x01, 0xad, 0xcf, 0xea, 0x2c, 0x33, 0x3a, + 0xb1, 0x59, 0x37, 0x30, 0x7b, 0x97, 0xe8, 0xc1, 0xb2, 0x56, 0xce, 0x33, + 0xf0, 0x5c, 0x5a, 0xa3, 0x9f, 0x1a, 0xd4, 0x43, 0x23, 0x71, 0xd6, 0x40, + 0x68, 0xab, 0x76, 0x66, 0x37, 0xaf, 0xe7, 0xef, 0x8e, 0xa2, 0x9d, 0xed, + 0x27, 0x52, 0x31, 0xec, 0x1c, 0x69, 0xe4, 0x98, 0x75, 0x8e, 0xbf, 0xde, + 0xfc, 0x50, 0x69, 0x41, 0x7a, 0xa4, 0x15, 0xbd, 0x7d, 0x9d, 0x78, 0x31, + 0xd2, 0x8a, 0x24, 0x65, 0xad, 0x4f, 0xe9, 0xb8, 0xad, 0xb7, 0x15, 0xfb, + 0x13, 0x72, 0x96, 0x5e, 0x6b, 0xbe, 0x5e, 0x09, 0xe9, 0x27, 0xd1, 0x8a, + 0xbd, 0xd4, 0xc9, 0x82, 0xfe, 0x25, 0xf6, 0xb9, 0xa1, 0x85, 0xdb, 0x1b, + 0xf1, 0x58, 0xea, 0x0e, 0xbc, 0x39, 0xac, 0xa3, 0xad, 0x57, 0xf4, 0x2d, + 0xe7, 0x27, 0xe3, 0x38, 0x92, 0x5a, 0x8b, 0x0f, 0xfb, 0x63, 0xff, 0xcc, + 0x69, 0x3e, 0xa6, 0xda, 0xfb, 0x5d, 0x2a, 0xae, 0x6b, 0x92, 0x73, 0xad, + 0x0e, 0xa2, 0x5a, 0xd0, 0xac, 0x54, 0xcd, 0x00, 0xef, 0x9b, 0x4e, 0x75, + 0x2d, 0xfe, 0xb6, 0xdf, 0x49, 0xde, 0xae, 0x32, 0xdf, 0x30, 0x3b, 0x68, + 0x1b, 0x66, 0x85, 0x9a, 0x9b, 0x37, 0x7b, 0x7f, 0x40, 0x73, 0x40, 0xce, + 0xbd, 0x96, 0xb1, 0xde, 0xe2, 0x48, 0x30, 0x56, 0xa2, 0x46, 0xc9, 0x27, + 0x1e, 0xc1, 0xca, 0xed, 0x8f, 0x60, 0x05, 0x3f, 0x1d, 0xdb, 0xad, 0xce, + 0x5b, 0x75, 0x05, 0x87, 0x34, 0xab, 0xb3, 0x53, 0xd7, 0x38, 0xb7, 0x32, + 0xaf, 0x8f, 0x60, 0xcd, 0xde, 0x47, 0xf0, 0x15, 0xda, 0x57, 0x35, 0xfd, + 0x78, 0x69, 0xaf, 0xd5, 0xf9, 0xe9, 0xa6, 0x30, 0x7e, 0x6d, 0xe7, 0x18, + 0x62, 0xaf, 0x5b, 0xec, 0xbc, 0x37, 0xa3, 0xca, 0xef, 0xbf, 0xb7, 0x7f, + 0x9b, 0xea, 0x2b, 0xf9, 0xbd, 0xa8, 0x35, 0xf8, 0x88, 0x72, 0x7f, 0xb3, + 0xbd, 0x12, 0x5b, 0xab, 0x25, 0x66, 0xb8, 0xcd, 0x12, 0x03, 0x8a, 0x36, + 0x8f, 0xb9, 0xd4, 0xd6, 0x23, 0x36, 0xdf, 0xf2, 0x45, 0x24, 0xcf, 0x6d, + 0xd0, 0xd7, 0xa9, 0x37, 0x13, 0xdb, 0xc9, 0xc5, 0x66, 0x7e, 0x1b, 0x49, + 0xfa, 0xea, 0x96, 0x99, 0xc1, 0x78, 0x12, 0x86, 0xb5, 0x65, 0xfa, 0xc0, + 0x9f, 0xf1, 0x7e, 0x6c, 0x61, 0xdf, 0x4d, 0xde, 0x91, 0x7d, 0x04, 0x9d, + 0xdb, 0x65, 0xfe, 0x1f, 0xc1, 0xc3, 0xec, 0xff, 0x9a, 0xfe, 0x47, 0xf0, + 0x10, 0x6d, 0xa7, 0x6a, 0xee, 0xc4, 0xc3, 0x55, 0x98, 0xc5, 0x4c, 0x68, + 0xfc, 0x81, 0x6a, 0x39, 0xf3, 0x4a, 0x4c, 0x4c, 0x2a, 0x8f, 0xe0, 0xde, + 0xc1, 0xfd, 0xf4, 0x45, 0xdb, 0xff, 0x88, 0xc5, 0x85, 0x78, 0xe5, 0xc7, + 0xca, 0x6c, 0x5d, 0x1e, 0xd7, 0x7d, 0x58, 0x91, 0x78, 0xd2, 0xf6, 0xfd, + 0x22, 0x63, 0x09, 0xfd, 0xbe, 0x95, 0x7e, 0xdf, 0x42, 0xbf, 0x8f, 0xd1, + 0xef, 0x0d, 0xfa, 0x7d, 0x33, 0xfd, 0x3e, 0x4a, 0xbf, 0xd7, 0xe9, 0xf7, + 0x8d, 0xf4, 0xfb, 0xb0, 0xec, 0x47, 0x28, 0x47, 0xa3, 0x47, 0xe0, 0xea, + 0x73, 0xd3, 0x86, 0x72, 0xef, 0x3d, 0xee, 0x21, 0xfe, 0x1c, 0xd7, 0x67, + 0xfb, 0x6f, 0x61, 0x2c, 0x1d, 0x22, 0x46, 0x64, 0x86, 0xbf, 0x6d, 0xbf, + 0x23, 0x97, 0x21, 0xee, 0x3f, 0x4f, 0x7d, 0x2c, 0x8e, 0xd4, 0xeb, 0xfb, + 0x19, 0xc3, 0x7e, 0xa4, 0x35, 0xf4, 0xf8, 0x58, 0xe6, 0xbb, 0xa9, 0x86, + 0xf4, 0x34, 0x68, 0x66, 0x93, 0xba, 0x1e, 0x58, 0xea, 0xe3, 0x98, 0x65, + 0xbf, 0x6e, 0x29, 0x1e, 0x1e, 0x68, 0xc3, 0xdf, 0x0d, 0x78, 0xa9, 0x8b, + 0xfa, 0xf1, 0x9b, 0x1d, 0xf8, 0xbe, 0x1f, 0x0e, 0xdf, 0x15, 0xc0, 0x7f, + 0xd6, 0x60, 0xf6, 0x3e, 0x79, 0xcf, 0x3a, 0x53, 0xe3, 0x68, 0x9c, 0x01, + 0xb1, 0x11, 0x10, 0xa9, 0x1d, 0xcc, 0xf6, 0x66, 0xdb, 0xef, 0x74, 0xc6, + 0x96, 0x09, 0xa6, 0x97, 0x60, 0x7d, 0xd8, 0xc6, 0xd9, 0x27, 0x65, 0xff, + 0xb0, 0x86, 0x78, 0xe4, 0x31, 0x5a, 0xb1, 0x21, 0x69, 0x7e, 0xb1, 0x86, + 0x5c, 0xa9, 0x27, 0x99, 0xd3, 0xc1, 0x03, 0x11, 0xaa, 0xc4, 0x90, 0xff, + 0x19, 0x01, 0x67, 0x47, 0xb4, 0x19, 0xf7, 0x65, 0x77, 0x22, 0xcd, 0xb1, + 0xae, 0xa2, 0x9f, 0xad, 0xfc, 0xe3, 0xef, 0xc5, 0xe3, 0xa1, 0x44, 0x80, + 0xf6, 0x7f, 0xce, 0xca, 0x54, 0xcd, 0x4e, 0xd7, 0x40, 0x5b, 0x73, 0x97, + 0x7a, 0x3d, 0xf3, 0xd6, 0xe0, 0x01, 0x3e, 0x32, 0xa7, 0xdb, 0xe7, 0xd1, + 0xdc, 0xb8, 0xa6, 0x1f, 0xca, 0x50, 0xaf, 0xbc, 0xd7, 0xd6, 0x89, 0xbf, + 0xd1, 0x3f, 0x6f, 0xdb, 0xcf, 0xb8, 0xc3, 0x8b, 0x19, 0xbd, 0x72, 0xdf, + 0x9a, 0x7f, 0x76, 0x6e, 0x30, 0x1c, 0x70, 0x3c, 0x54, 0x29, 0xfb, 0x12, + 0xcf, 0x30, 0xce, 0xfa, 0xfb, 0xe7, 0x43, 0x9d, 0xeb, 0xc6, 0xdd, 0x8d, + 0xe5, 0x88, 0x2f, 0x15, 0x0e, 0x69, 0xef, 0x9b, 0x50, 0x9f, 0x7f, 0x8d, + 0xfb, 0xf5, 0xa7, 0xc8, 0xd7, 0x76, 0xa2, 0x9f, 0xf8, 0xb5, 0x52, 0xff, + 0x9c, 0x62, 0xf2, 0xf7, 0x86, 0x94, 0x89, 0x55, 0xfa, 0x6d, 0xc0, 0x5f, + 0x54, 0xa3, 0x74, 0xbb, 0x94, 0x17, 0xb9, 0x5b, 0x6c, 0x79, 0x7b, 0x52, + 0xf2, 0xfb, 0xef, 0xf3, 0x6d, 0xde, 0x09, 0x54, 0xbb, 0xed, 0x3c, 0xe7, + 0x57, 0x33, 0x77, 0x62, 0x6b, 0x0a, 0xdf, 0xaf, 0x44, 0x7d, 0xa6, 0x4f, + 0x75, 0x7c, 0xff, 0x0a, 0xcc, 0x4e, 0xff, 0x56, 0x95, 0xf9, 0x88, 0xe1, + 0xbe, 0x99, 0x0a, 0x71, 0x4d, 0x3b, 0x7d, 0x97, 0x1a, 0x34, 0xc7, 0x41, + 0xf9, 0x63, 0x2f, 0x5a, 0xe3, 0x57, 0xf8, 0xb0, 0x6f, 0x4c, 0xea, 0xb6, + 0xc1, 0xe2, 0x9c, 0xec, 0xb7, 0xf7, 0xe2, 0x82, 0x47, 0x2d, 0x35, 0x00, + 0x27, 0xef, 0x9d, 0x1d, 0xd2, 0x99, 0xc7, 0xb7, 0xe1, 0xdf, 0x06, 0x96, + 0xe2, 0xb7, 0x03, 0xf5, 0x1d, 0x37, 0x28, 0x96, 0x75, 0x28, 0xf2, 0x59, + 0xfc, 0xb8, 0xda, 0x8b, 0xdd, 0xe4, 0xff, 0xbf, 0x4d, 0x98, 0xb5, 0x57, + 0x10, 0x0b, 0xfe, 0x3d, 0x11, 0x4c, 0x1f, 0x52, 0xed, 0x77, 0xc6, 0xf5, + 0x85, 0x6a, 0x70, 0xe7, 0xaf, 0xd8, 0xc6, 0x7d, 0xea, 0x12, 0xfc, 0x3a, + 0xdb, 0x8a, 0xd3, 0xd9, 0xa9, 0xb6, 0xd0, 0x69, 0xa1, 0x46, 0xec, 0x40, + 0xec, 0x81, 0xb6, 0x98, 0xa2, 0x2d, 0x92, 0xdf, 0x76, 0x7d, 0x86, 0xf6, + 0x48, 0x2c, 0xfa, 0x1e, 0x31, 0xea, 0x1f, 0x52, 0xb4, 0x47, 0xfa, 0xcd, + 0x77, 0xe9, 0x37, 0xdf, 0xa1, 0xdf, 0x3c, 0x45, 0xbf, 0xc9, 0x71, 0xdb, + 0x36, 0x7b, 0xbd, 0xfe, 0x65, 0xc6, 0xc4, 0xc4, 0xd6, 0x4e, 0x9c, 0x8a, + 0xd4, 0xaf, 0x1a, 0x45, 0xb0, 0x3d, 0xa9, 0x58, 0x5e, 0xe1, 0x73, 0x5f, + 0x0b, 0x89, 0x0f, 0xc8, 0xfb, 0x69, 0x7e, 0x3c, 0x3e, 0xdc, 0x59, 0x29, + 0xef, 0xbb, 0xee, 0xd9, 0xf1, 0x71, 0x3a, 0xfb, 0x07, 0xf6, 0x43, 0xf4, + 0xf5, 0xe7, 0x8e, 0x5d, 0x74, 0xf9, 0xcf, 0xd6, 0x8f, 0x6b, 0x64, 0xfc, + 0xcb, 0xf0, 0xfb, 0x81, 0x16, 0x9c, 0x66, 0xfc, 0x7d, 0x7e, 0xee, 0xb8, + 0xb7, 0x14, 0xc1, 0xb8, 0xaa, 0x1a, 0xc8, 0x66, 0x5b, 0x70, 0x26, 0x61, + 0xe0, 0x89, 0x44, 0xfd, 0xaa, 0x32, 0xc7, 0xcf, 0xd5, 0x4c, 0xad, 0x58, + 0x54, 0x0c, 0x27, 0x85, 0x5f, 0x86, 0xda, 0x50, 0x6c, 0x34, 0x63, 0x30, + 0x2b, 0x76, 0xea, 0xc5, 0x5b, 0x51, 0x5d, 0xde, 0x2f, 0xfb, 0xa3, 0x7f, + 0xf7, 0xd1, 0x1e, 0x5f, 0x95, 0xff, 0x27, 0xc1, 0x79, 0xf6, 0x1a, 0xcb, + 0xe0, 0xdc, 0x2e, 0xef, 0xf8, 0x8b, 0x3f, 0x2b, 0xd8, 0xa4, 0x8f, 0x77, + 0x94, 0x20, 0xf8, 0xe4, 0x4f, 0x68, 0xeb, 0x87, 0x7a, 0xe5, 0x2c, 0x6e, + 0x0b, 0x7e, 0xc9, 0xf2, 0x95, 0xf4, 0x8b, 0x43, 0x59, 0xa7, 0xf3, 0xc7, + 0xbd, 0xf2, 0x8e, 0xfa, 0x12, 0xfc, 0x38, 0x3b, 0xa1, 0x7e, 0xe4, 0xd5, + 0xf1, 0xab, 0xd1, 0xa5, 0xb4, 0x27, 0xc9, 0xe5, 0x63, 0xcc, 0xe5, 0x83, + 0xde, 0xc7, 0xb1, 0x14, 0xea, 0xde, 0x65, 0xf0, 0x6c, 0x97, 0xf7, 0x67, + 0x96, 0xa1, 0x8c, 0xbf, 0xfd, 0xdb, 0x2d, 0xcb, 0x39, 0xb7, 0xd2, 0xda, + 0xb8, 0x4c, 0xe6, 0x4e, 0xf0, 0xe4, 0xff, 0x7a, 0x65, 0x2d, 0x00, 0x7b, + 0x45, 0xbe, 0x46, 0xf9, 0x4b, 0xe1, 0xde, 0x5e, 0x1f, 0x5e, 0x84, 0xfa, + 0xd3, 0x2e, 0x65, 0x29, 0xae, 0xde, 0xab, 0x54, 0xa1, 0x54, 0xca, 0x86, + 0x69, 0x7f, 0x26, 0xe4, 0x9c, 0x74, 0x4b, 0xef, 0xaf, 0xac, 0x19, 0x86, + 0xbd, 0xbf, 0x86, 0x95, 0xa3, 0x1a, 0xe3, 0x5d, 0x29, 0xe2, 0x83, 0x8f, + 0x59, 0x95, 0x86, 0x13, 0x2b, 0x46, 0x1b, 0x71, 0x4b, 0xbf, 0x65, 0x9d, + 0x9a, 0x17, 0x83, 0xc7, 0xf0, 0x10, 0xc3, 0x3c, 0xf8, 0x4a, 0x6f, 0x19, + 0xbf, 0x2d, 0x14, 0x31, 0x26, 0xcf, 0x52, 0xb5, 0x55, 0xb5, 0x0e, 0xad, + 0x7d, 0x54, 0x91, 0xb8, 0xef, 0xc1, 0x83, 0x8c, 0xcf, 0x8b, 0x7b, 0xfd, + 0x88, 0x8f, 0x5a, 0xd6, 0x2b, 0x51, 0x1f, 0x1e, 0x60, 0xfd, 0xd6, 0xde, + 0x01, 0x74, 0xd1, 0x2e, 0xe2, 0x7b, 0xb5, 0x80, 0x97, 0xf1, 0x7e, 0xe5, + 0xa8, 0x9b, 0x31, 0xac, 0x1a, 0x8b, 0xb6, 0x07, 0xf0, 0x95, 0x51, 0x0f, + 0xe3, 0x9b, 0x35, 0xff, 0x4d, 0xdd, 0xbc, 0xd6, 0x01, 0x0d, 0x6b, 0x46, + 0x7d, 0x58, 0xd2, 0x1b, 0x3c, 0x23, 0xef, 0x5a, 0x9f, 0xd5, 0xc3, 0x58, + 0x3d, 0xea, 0xc7, 0xed, 0xbd, 0x13, 0x5f, 0x99, 0x01, 0xf3, 0xff, 0xab, + 0x45, 0x23, 0xbe, 0x3c, 0x5a, 0x47, 0xf9, 0xc1, 0x55, 0x2f, 0x2b, 0x75, + 0xf8, 0xdb, 0xbd, 0x3a, 0xe5, 0xab, 0xb8, 0x8d, 0x72, 0x6e, 0xed, 0xbd, + 0x1a, 0x0f, 0xee, 0x8d, 0xe2, 0xbe, 0xd1, 0xb9, 0x58, 0xc8, 0xf8, 0xd4, + 0xc1, 0xbc, 0x0e, 0x9f, 0x07, 0x6e, 0xef, 0x17, 0xdd, 0x43, 0x79, 0x25, + 0x3a, 0x0e, 0x37, 0xe3, 0x1d, 0x0d, 0x91, 0xf7, 0x1a, 0xc9, 0xc1, 0x74, + 0xdc, 0xbe, 0x6b, 0xae, 0xbd, 0x9f, 0x5e, 0x1f, 0x29, 0x46, 0xbc, 0x4d, + 0x41, 0x4b, 0xbf, 0xc4, 0x59, 0xe1, 0x36, 0x3a, 0xe3, 0x6a, 0x88, 0x6d, + 0xe8, 0x8c, 0xab, 0xb9, 0xfb, 0x5d, 0x29, 0x39, 0x6b, 0xf5, 0x06, 0xf9, + 0x52, 0x04, 0x2d, 0x76, 0x8c, 0x76, 0x93, 0x5f, 0x9b, 0x70, 0x32, 0x76, + 0x47, 0x68, 0xe3, 0xf3, 0x9b, 0x24, 0x56, 0x37, 0x32, 0x4f, 0x34, 0x30, + 0xd6, 0xa7, 0x75, 0x9c, 0x51, 0x0c, 0x8c, 0xee, 0x92, 0x98, 0xe8, 0xc3, + 0xea, 0x5e, 0x03, 0x6f, 0xca, 0x59, 0xfa, 0x39, 0xb1, 0xc5, 0x65, 0xd0, + 0xf4, 0x07, 0x11, 0x32, 0x8f, 0x31, 0xb6, 0x9f, 0xce, 0x54, 0xe3, 0x96, + 0xed, 0x52, 0xa6, 0x09, 0x6f, 0x0d, 0x39, 0x71, 0x4b, 0xef, 0x5a, 0x3c, + 0x96, 0x76, 0x60, 0x50, 0xaf, 0xef, 0x51, 0x19, 0x3f, 0x6f, 0x6c, 0x0a, + 0x7a, 0x9f, 0x21, 0x57, 0x3d, 0x33, 0x97, 0x51, 0xf9, 0x8a, 0x28, 0x5a, + 0xd8, 0xaf, 0x16, 0x2d, 0x77, 0x96, 0xe2, 0xbe, 0xe8, 0x5a, 0x1c, 0x4b, + 0x6b, 0xe6, 0x7e, 0xe6, 0xcb, 0xee, 0x26, 0x3e, 0x9f, 0xee, 0x44, 0xb7, + 0x26, 0x9c, 0xb6, 0x91, 0xbe, 0x25, 0xeb, 0x2a, 0x51, 0xbc, 0x49, 0x7b, + 0xed, 0xc9, 0xcc, 0x67, 0xec, 0x97, 0x98, 0x2f, 0x67, 0xfd, 0x4c, 0x54, + 0xde, 0xa0, 0xe0, 0xf8, 0x6e, 0xe1, 0x58, 0xf3, 0xf1, 0x45, 0xea, 0xa9, + 0xa5, 0x57, 0xc5, 0x8d, 0x7b, 0x97, 0xe3, 0xd4, 0xb6, 0x1c, 0xe7, 0x7a, + 0x25, 0x62, 0x7e, 0x99, 0x9c, 0xab, 0xbd, 0x9c, 0x9c, 0x8b, 0x5c, 0x2e, + 0xbc, 0x5a, 0x71, 0x22, 0x34, 0xda, 0x4c, 0x5e, 0x21, 0xfc, 0x82, 0xfe, + 0x9a, 0x8d, 0x62, 0x51, 0x6f, 0x1d, 0x86, 0xc9, 0xb7, 0x32, 0xc4, 0x8b, + 0x4c, 0x96, 0x71, 0x65, 0xa8, 0x86, 0x9f, 0x00, 0x3f, 0xd7, 0xf0, 0xa3, + 0xd9, 0xf7, 0x56, 0xd0, 0x96, 0x63, 0x6d, 0x8a, 0x7d, 0xce, 0x7e, 0x30, + 0x2b, 0xb1, 0x5a, 0x41, 0x95, 0xf6, 0x17, 0x55, 0x92, 0x67, 0x7a, 0x35, + 0x05, 0xaf, 0xa5, 0x03, 0xf8, 0x6a, 0xd3, 0x5a, 0x25, 0x56, 0x6d, 0xbf, + 0xa7, 0x6a, 0x96, 0xb2, 0x6f, 0x8b, 0xe6, 0xc9, 0x3a, 0x64, 0x98, 0x39, + 0xaf, 0xfc, 0x8f, 0x02, 0x05, 0x0f, 0x30, 0x97, 0x0f, 0x54, 0x05, 0xe4, + 0x1c, 0x14, 0xfd, 0xdd, 0x87, 0x17, 0x12, 0x71, 0x64, 0x13, 0x0d, 0x3d, + 0xab, 0x15, 0xd9, 0xef, 0x09, 0x36, 0xc7, 0x95, 0x1c, 0xe7, 0x2f, 0x67, + 0xdd, 0xdd, 0xf3, 0x3a, 0xd0, 0x41, 0x6e, 0x7f, 0x3a, 0xc7, 0xed, 0x03, + 0x93, 0xe8, 0xc0, 0xca, 0x84, 0xec, 0x6f, 0xc6, 0xad, 0x2e, 0xce, 0xc1, + 0xe1, 0x44, 0x07, 0xee, 0x4c, 0x34, 0x74, 0x10, 0x5a, 0x30, 0x7e, 0x57, + 0x07, 0x5a, 0x12, 0xf5, 0xe3, 0x5b, 0xe5, 0x7f, 0x50, 0x4d, 0xd3, 0x70, + 0x60, 0x4c, 0x45, 0xad, 0x16, 0x20, 0xf6, 0x07, 0x30, 0x98, 0x6a, 0x38, + 0xd3, 0xa5, 0xde, 0xa9, 0x4c, 0x5e, 0x21, 0x39, 0x64, 0x33, 0x9e, 0x4f, + 0x78, 0x50, 0x96, 0x34, 0x69, 0xfb, 0x40, 0xe9, 0x48, 0x94, 0xf9, 0xc3, + 0x63, 0x56, 0x95, 0x11, 0x4a, 0x8b, 0x5e, 0x4a, 0x46, 0xe6, 0xe3, 0x0d, + 0xc6, 0xdc, 0xfa, 0xeb, 0x35, 0xef, 0x42, 0x1b, 0x8b, 0x7e, 0x65, 0xd5, + 0x1a, 0x65, 0x98, 0xb1, 0x2b, 0xd4, 0xdc, 0xc2, 0xf8, 0xda, 0x7c, 0x03, + 0xed, 0x80, 0xb1, 0xaf, 0xd2, 0xd8, 0xc9, 0x39, 0x16, 0x7b, 0xf2, 0xa0, + 0x7c, 0xc4, 0x47, 0x1c, 0xa2, 0xe8, 0x11, 0x0d, 0x7b, 0xd9, 0x2f, 0xef, + 0x88, 0x9c, 0x0b, 0x0a, 0xb6, 0xdf, 0x27, 0xff, 0x53, 0x64, 0x4f, 0xee, + 0xfc, 0xe1, 0xfb, 0x89, 0xcf, 0x40, 0x92, 0x51, 0xcf, 0x88, 0x07, 0x1f, + 0x26, 0xe4, 0x0c, 0x1f, 0x69, 0xcd, 0x48, 0x00, 0x55, 0xac, 0xfb, 0x66, + 0xa2, 0x3e, 0xfd, 0xdf, 0x51, 0x1f, 0xb8, 0x55, 0xad, 0xb4, 0xcf, 0x0a, + 0x39, 0x47, 0x6e, 0xc2, 0x89, 0x74, 0x70, 0x9c, 0x79, 0xf4, 0xaa, 0x76, + 0xaa, 0x98, 0xb9, 0xae, 0x79, 0x8d, 0xd2, 0xd0, 0xa1, 0xaa, 0xc1, 0xf0, + 0xa8, 0x02, 0xca, 0x73, 0xb2, 0x8d, 0x9b, 0xf0, 0x76, 0xba, 0x14, 0x45, + 0xbb, 0x76, 0xd2, 0xee, 0x8b, 0xb0, 0x78, 0x9b, 0x1b, 0x25, 0x7b, 0xc4, + 0x56, 0x45, 0xaf, 0x92, 0xef, 0x83, 0xb6, 0x6a, 0x62, 0x6f, 0x74, 0x39, + 0x9e, 0x1f, 0x90, 0x7d, 0xf4, 0x0b, 0x1c, 0xbc, 0x2d, 0x62, 0xde, 0xae, + 0x32, 0x06, 0xad, 0x4f, 0x85, 0xe2, 0x25, 0xb4, 0x09, 0x87, 0x11, 0x6a, + 0xef, 0xe6, 0xd8, 0x1b, 0x46, 0xc5, 0xce, 0x9a, 0xf1, 0x1d, 0x8e, 0xa5, + 0x9f, 0x36, 0x31, 0x9c, 0xa8, 0xc3, 0x46, 0xda, 0x84, 0x49, 0x9b, 0x30, + 0x39, 0xff, 0x26, 0x6d, 0xc2, 0xa4, 0x4d, 0x98, 0xb4, 0x09, 0x93, 0x36, + 0x61, 0x66, 0xe7, 0x63, 0x5f, 0x5a, 0x45, 0xcf, 0x50, 0x19, 0xe2, 0xd5, + 0xf2, 0x1e, 0xbd, 0x86, 0xb1, 0x54, 0x97, 0x32, 0x79, 0xd7, 0x4d, 0x18, + 0x4c, 0xdf, 0xcc, 0x8f, 0x82, 0x76, 0xda, 0xc5, 0xce, 0x8c, 0xd8, 0x99, + 0x1b, 0xdf, 0xcd, 0xce, 0x99, 0x86, 0xd2, 0x5c, 0xac, 0x7c, 0xcc, 0xbe, + 0xa7, 0x70, 0x8e, 0xdc, 0x78, 0x26, 0x2b, 0xf7, 0x4c, 0x9c, 0xa0, 0xfd, + 0xf7, 0x50, 0x9e, 0x1a, 0x91, 0xfd, 0x92, 0x28, 0xf9, 0xbe, 0x9c, 0x0b, + 0xdf, 0xc9, 0x7e, 0x0b, 0xcf, 0x30, 0xb1, 0x65, 0x1e, 0xd0, 0xd4, 0xbf, + 0x16, 0x0f, 0xf5, 0x61, 0xbc, 0x9c, 0xcf, 0xbe, 0x93, 0xd9, 0x49, 0x1f, + 0x6e, 0xb4, 0xd7, 0x30, 0xee, 0x6f, 0x52, 0xf0, 0xa5, 0xb4, 0x9c, 0x27, + 0xaf, 0x8f, 0x6d, 0x44, 0xc4, 0xf6, 0xdb, 0xfe, 0xd4, 0x4e, 0xa4, 0xf8, + 0xcc, 0x1f, 0x69, 0xa2, 0x4f, 0x56, 0xe3, 0xdd, 0x6d, 0x41, 0xfd, 0x35, + 0x68, 0xad, 0x23, 0xb0, 0xe6, 0x2f, 0x8c, 0x84, 0xcc, 0x7a, 0xa5, 0x09, + 0x6d, 0x7b, 0x9b, 0x98, 0x3b, 0x04, 0xf5, 0xd7, 0xe9, 0x73, 0xcf, 0x45, + 0xe6, 0x33, 0x7f, 0x88, 0xe1, 0x2b, 0xe4, 0xf9, 0x77, 0x0d, 0xaa, 0x1c, + 0x53, 0xa3, 0xbd, 0xf6, 0xf1, 0x9c, 0xfd, 0x0e, 0x5c, 0x54, 0xce, 0xc8, + 0x28, 0x0f, 0x12, 0x73, 0x16, 0x27, 0x0f, 0x5a, 0xf2, 0x4e, 0xed, 0xca, + 0xeb, 0x9a, 0xb1, 0x3f, 0x6b, 0xe0, 0xc9, 0xf4, 0x1b, 0x96, 0xaa, 0xc5, + 0xce, 0x3a, 0xc9, 0x45, 0x3c, 0xc4, 0x8c, 0x6c, 0x46, 0xfc, 0x5f, 0xf6, + 0xc0, 0x0d, 0x7c, 0x98, 0xd6, 0xd2, 0x0d, 0x8c, 0x4b, 0xbf, 0xe6, 0xbd, + 0x9d, 0xc4, 0x11, 0xf7, 0x56, 0xed, 0xa8, 0x4a, 0x0e, 0x3f, 0xdf, 0x61, + 0xa0, 0x68, 0xb7, 0xcc, 0x81, 0xe0, 0x56, 0x00, 0x63, 0x89, 0x18, 0xee, + 0xa4, 0xfd, 0x8c, 0x26, 0x5a, 0x70, 0x07, 0x6d, 0x63, 0x24, 0xd1, 0x8a, + 0xcf, 0x31, 0x37, 0xd8, 0x9d, 0x10, 0x3f, 0x5b, 0x82, 0x85, 0xb4, 0x95, + 0xfd, 0xa9, 0xff, 0x05, 0x7d, 0x7a, 0x00, 0xbb, 0x6d, 0xae, 0x29, 0xfb, + 0xd6, 0x50, 0x56, 0x26, 0xdc, 0xcc, 0x6d, 0xe2, 0x56, 0x7f, 0x4a, 0x38, + 0x50, 0x27, 0x6e, 0x89, 0x34, 0x62, 0x0b, 0xe5, 0x65, 0xc9, 0x75, 0x87, + 0x98, 0x4f, 0xad, 0xde, 0xb5, 0x9c, 0x98, 0x7c, 0x61, 0xee, 0x4f, 0xeb, + 0xe6, 0x21, 0x62, 0x41, 0xd8, 0xcf, 0x79, 0x57, 0x69, 0xc3, 0x72, 0xce, + 0x7c, 0x90, 0x63, 0x9f, 0x43, 0x3c, 0x70, 0xa7, 0xc4, 0x7e, 0x82, 0x47, + 0x19, 0xf2, 0x1e, 0xae, 0x95, 0x77, 0x15, 0xe8, 0x1b, 0x33, 0x52, 0x56, + 0xa7, 0x93, 0x71, 0x64, 0x53, 0xb4, 0x0e, 0x07, 0x47, 0x6e, 0x86, 0x77, + 0x6b, 0x1d, 0x46, 0x93, 0x7e, 0x64, 0x93, 0xa8, 0xf5, 0x42, 0xbd, 0xc1, + 0x8b, 0x60, 0xf3, 0x21, 0xc6, 0x89, 0xb7, 0x95, 0x86, 0xf6, 0x37, 0x11, + 0xec, 0xd9, 0xac, 0x04, 0xbd, 0x0d, 0xaa, 0xb4, 0x4d, 0x3c, 0xa1, 0x1f, + 0x0c, 0xd2, 0xde, 0x33, 0x23, 0xc4, 0x14, 0xd6, 0x75, 0x6d, 0x75, 0xc9, + 0x3a, 0xf1, 0x78, 0x95, 0xe6, 0xc3, 0x9e, 0x3d, 0xc4, 0xb8, 0x1d, 0xf2, + 0xbf, 0x03, 0x6a, 0xb0, 0x6f, 0xcf, 0xcd, 0x98, 0xb1, 0x35, 0x80, 0x83, + 0xbc, 0x57, 0xbb, 0xe3, 0x1a, 0x3c, 0x43, 0x3f, 0xc9, 0xd0, 0x0f, 0x8b, + 0xb6, 0xaa, 0xd8, 0xbb, 0xe7, 0x26, 0x54, 0x92, 0xd7, 0x9f, 0x0a, 0x29, + 0x36, 0xf6, 0x26, 0x38, 0xae, 0xdd, 0x29, 0xfb, 0xdc, 0xbc, 0xf2, 0x22, + 0xf3, 0x81, 0xee, 0x11, 0x1d, 0x9b, 0x79, 0x3f, 0xc5, 0xb9, 0xde, 0x42, + 0xcc, 0x3d, 0xbe, 0xad, 0x1a, 0xf7, 0x6f, 0xd3, 0x62, 0xd7, 0xa8, 0xd6, + 0xfc, 0xb7, 0xf4, 0xd0, 0x19, 0x17, 0xe7, 0xd8, 0x62, 0x0e, 0x77, 0xb6, + 0xef, 0xa0, 0x55, 0x45, 0xac, 0x77, 0x69, 0xf3, 0x31, 0x73, 0x6e, 0x0c, + 0xaf, 0x47, 0x9b, 0x70, 0x66, 0x97, 0xe8, 0xca, 0x62, 0x0c, 0x90, 0xf8, + 0x10, 0x45, 0x9c, 0x39, 0xdd, 0x6e, 0xe6, 0x74, 0xf7, 0x30, 0xa7, 0x7b, + 0xb0, 0x4f, 0x74, 0xdc, 0x89, 0x25, 0x11, 0x83, 0x3a, 0x6c, 0x24, 0x7e, + 0x19, 0x50, 0xfb, 0xb4, 0xe6, 0xbb, 0x88, 0xf1, 0xc5, 0x76, 0x8e, 0x67, + 0x10, 0x27, 0x24, 0x4f, 0x30, 0xf0, 0xd3, 0x4c, 0xce, 0xef, 0x6a, 0x19, + 0xd3, 0x0f, 0x8c, 0xb4, 0xe0, 0xbb, 0xcc, 0xe1, 0x46, 0xfb, 0x42, 0x3b, + 0x5f, 0x56, 0x5a, 0xf1, 0x5d, 0x3b, 0x5e, 0x88, 0x0d, 0xb7, 0xe2, 0xdd, + 0x84, 0x16, 0x5f, 0xa8, 0x84, 0xda, 0xd3, 0xbc, 0xff, 0x5e, 0xf6, 0x66, + 0x72, 0xd8, 0x25, 0x38, 0x4e, 0x1b, 0xee, 0x49, 0x09, 0x96, 0x3b, 0xe1, + 0xda, 0x76, 0x07, 0xde, 0x1a, 0xce, 0xe5, 0x6e, 0x21, 0xe6, 0x6e, 0x77, + 0xf6, 0xd3, 0x1e, 0x52, 0x10, 0x6f, 0x60, 0x0e, 0x17, 0x5c, 0x55, 0xc4, + 0xfc, 0xed, 0xa3, 0x48, 0x2e, 0x7f, 0x8b, 0x57, 0x07, 0xf5, 0x17, 0x15, + 0x73, 0xa7, 0xbc, 0x7b, 0xf4, 0x1a, 0x72, 0xe7, 0xc6, 0x4f, 0x10, 0x6b, + 0x37, 0xd1, 0x07, 0xae, 0x8b, 0x48, 0x7e, 0xa7, 0x61, 0x38, 0x65, 0xbf, + 0xcf, 0xad, 0xff, 0x94, 0xf3, 0xeb, 0xd7, 0xc4, 0x06, 0x1c, 0x38, 0xad, + 0xd7, 0x7b, 0xbd, 0x0e, 0x07, 0x6e, 0xd1, 0x83, 0xab, 0x8e, 0x20, 0xca, + 0x79, 0x97, 0xbd, 0xc2, 0x5c, 0x3c, 0x75, 0x26, 0xe5, 0x1d, 0x94, 0x4e, + 0xbc, 0x35, 0xf7, 0xef, 0xf3, 0x79, 0x58, 0x21, 0x1f, 0x13, 0x9b, 0x6b, + 0x68, 0x76, 0xa0, 0xde, 0x2c, 0x86, 0x96, 0x49, 0x93, 0x5f, 0xc6, 0x39, + 0xd7, 0x71, 0x08, 0xf6, 0x37, 0x98, 0x5e, 0x84, 0xed, 0xff, 0xf9, 0xf5, + 0x7c, 0xc2, 0x3e, 0x03, 0x4a, 0x9c, 0xcb, 0xe1, 0xea, 0x73, 0x89, 0x52, + 0x80, 0xf8, 0x94, 0xe0, 0xd8, 0x8a, 0x47, 0x4c, 0xb8, 0x0c, 0xfa, 0x57, + 0x9f, 0x07, 0xea, 0x2e, 0x0f, 0xfc, 0xc9, 0xc7, 0xac, 0x72, 0xe2, 0x6a, + 0xd9, 0x2e, 0xce, 0x91, 0xc3, 0xb2, 0x9e, 0x9a, 0x27, 0x38, 0x2b, 0x65, + 0xb5, 0xd6, 0x0f, 0x79, 0xad, 0x11, 0x67, 0x35, 0x62, 0x6b, 0x05, 0xf1, + 0xb1, 0x3b, 0x59, 0x8d, 0xcd, 0xdb, 0x06, 0xa8, 0x73, 0x2f, 0x1c, 0xbc, + 0x4e, 0x25, 0xfd, 0x36, 0x76, 0x82, 0xbf, 0x2b, 0xe9, 0x33, 0xa0, 0x9d, + 0x6d, 0x4d, 0x5a, 0xf3, 0xef, 0x8c, 0x98, 0x7d, 0x95, 0xec, 0xcb, 0x34, + 0xe2, 0xed, 0xc6, 0x64, 0xd0, 0x7b, 0xab, 0xaa, 0xe0, 0xf6, 0x88, 0xce, + 0xb6, 0x3d, 0xe8, 0x4b, 0x0a, 0x4e, 0x4c, 0x50, 0x8f, 0x66, 0x43, 0x19, + 0x75, 0xe9, 0xa2, 0x2e, 0x67, 0xd8, 0xe7, 0x55, 0xeb, 0x50, 0xbe, 0x27, + 0xca, 0x3e, 0x37, 0x12, 0x8b, 0x4d, 0x6c, 0xe2, 0xcf, 0xf9, 0xbb, 0x97, + 0xe3, 0xba, 0x6d, 0x76, 0xee, 0xbb, 0x40, 0xf2, 0x99, 0xd7, 0x22, 0x21, + 0xfd, 0x1e, 0xd5, 0x89, 0xb7, 0xb3, 0x82, 0xb5, 0xf2, 0x3e, 0x3d, 0xc6, + 0x67, 0x68, 0xcd, 0x58, 0x9a, 0x14, 0x8c, 0xf2, 0x93, 0x67, 0x47, 0xb1, + 0x24, 0x29, 0xfe, 0x68, 0xe2, 0xb6, 0xeb, 0xeb, 0xf0, 0xfe, 0xf9, 0x75, + 0x0b, 0x1f, 0x26, 0x89, 0x99, 0x93, 0xc4, 0xcc, 0x49, 0x62, 0xe6, 0xa4, + 0xbd, 0x16, 0xa1, 0xe2, 0xf4, 0x90, 0x82, 0xf7, 0x6c, 0xfc, 0xdb, 0x69, + 0x73, 0xa8, 0x27, 0x19, 0xd3, 0xdb, 0xd3, 0x3a, 0x0e, 0xd0, 0x16, 0x92, + 0x29, 0xb1, 0x35, 0x05, 0x4f, 0xf5, 0x45, 0x50, 0x45, 0xdb, 0xd9, 0x4a, + 0x9b, 0x7e, 0x78, 0xbb, 0x16, 0x98, 0xef, 0x08, 0xb5, 0xa6, 0xd0, 0x84, + 0x07, 0x88, 0x57, 0x0f, 0x31, 0x97, 0x39, 0x44, 0x4c, 0xbb, 0x67, 0x70, + 0x2d, 0x96, 0xf4, 0xa9, 0xc4, 0x2c, 0x62, 0xd5, 0x74, 0xc1, 0x6e, 0xc1, + 0x4b, 0x79, 0x57, 0x2e, 0x2a, 0xeb, 0x9a, 0xca, 0x5d, 0xc4, 0xaa, 0xc6, + 0x5e, 0xe1, 0x38, 0xcc, 0x93, 0x18, 0x8b, 0x12, 0xc4, 0xaa, 0x2d, 0x69, + 0x99, 0xaf, 0x4e, 0xdc, 0x4b, 0xbb, 0x5e, 0x9f, 0x5f, 0x97, 0x98, 0xb3, + 0x55, 0x3b, 0x73, 0x40, 0xc9, 0x71, 0x9d, 0x5e, 0x5e, 0x1f, 0xee, 0x0b, + 0x50, 0x0f, 0x06, 0x8e, 0xed, 0x92, 0x3c, 0x48, 0xfa, 0x13, 0xc0, 0x21, + 0xe2, 0x93, 0x83, 0xba, 0x7e, 0x99, 0xf8, 0x54, 0x49, 0x7c, 0x7a, 0x8d, + 0xf8, 0x34, 0x8d, 0xf8, 0xf4, 0x6a, 0x1e, 0x9f, 0xaa, 0x47, 0xc4, 0x16, + 0x72, 0x5c, 0xfb, 0x78, 0xe2, 0xb9, 0x2a, 0xf9, 0x5f, 0x62, 0x82, 0xf3, + 0x97, 0xc7, 0xff, 0xa5, 0x78, 0x71, 0x00, 0xee, 0x19, 0xe4, 0xb2, 0x16, + 0xf1, 0xe6, 0x03, 0xc7, 0x52, 0xfc, 0x74, 0xa8, 0xc0, 0x61, 0x27, 0xed, + 0x5c, 0xb9, 0xdc, 0x90, 0x75, 0x30, 0x59, 0x03, 0xab, 0xcb, 0xef, 0x0b, + 0x9a, 0xf8, 0xce, 0x3c, 0xe1, 0x8d, 0xb2, 0xae, 0x53, 0x44, 0x7e, 0xd8, + 0x86, 0xe1, 0x6d, 0xcf, 0x62, 0x53, 0x9f, 0x7a, 0x6b, 0x19, 0xc8, 0x85, + 0x95, 0x4e, 0x38, 0x22, 0x95, 0x98, 0x19, 0x11, 0x1b, 0x64, 0x2e, 0x32, + 0xf6, 0x6d, 0x74, 0xef, 0x2e, 0xc3, 0x84, 0xd7, 0xb2, 0x9e, 0xd4, 0x6b, + 0xe5, 0xdf, 0x00, 0x08, 0x5e, 0x7a, 0x8a, 0x18, 0xa3, 0x6e, 0x1d, 0xfd, + 0xb8, 0x33, 0xa7, 0x6b, 0xf0, 0xc5, 0xed, 0x8f, 0xa0, 0x7d, 0xfb, 0x37, + 0xe9, 0x7b, 0x33, 0x7b, 0x6a, 0x69, 0x87, 0xd7, 0x35, 0x8d, 0xe3, 0x44, + 0x84, 0xb1, 0xcf, 0xa7, 0xe0, 0x87, 0x73, 0x66, 0x8a, 0x1c, 0xfe, 0x7d, + 0x60, 0x05, 0x6c, 0x79, 0x6f, 0xe5, 0xfd, 0xe3, 0x39, 0x1f, 0xc7, 0x4e, + 0xd9, 0x27, 0xbc, 0xf9, 0xb3, 0x9b, 0x7f, 0x42, 0x5b, 0x3f, 0x13, 0x19, + 0xfc, 0x2b, 0xc8, 0x78, 0xdd, 0x8a, 0x2d, 0x93, 0x7a, 0x45, 0xf9, 0x36, + 0xbe, 0x49, 0x8e, 0x47, 0x9e, 0xa7, 0xf3, 0x7b, 0xf0, 0x59, 0x91, 0xcf, + 0x67, 0x05, 0xf9, 0x2f, 0x5a, 0xb1, 0x36, 0xb9, 0x96, 0x32, 0x1f, 0xf1, + 0x99, 0x94, 0x2b, 0x3c, 0x7b, 0x36, 0x2f, 0xa7, 0x18, 0x81, 0xea, 0x9c, + 0x9c, 0x2f, 0x51, 0xce, 0x69, 0x62, 0x9e, 0x7a, 0xfd, 0x54, 0x59, 0x85, + 0x76, 0xff, 0xf7, 0x79, 0x59, 0xb9, 0x72, 0x45, 0xd3, 0x51, 0x2a, 0x65, + 0xa7, 0xae, 0x7b, 0x17, 0xd1, 0x77, 0x43, 0xde, 0xf5, 0xf6, 0x7a, 0xb3, + 0x8e, 0x15, 0x17, 0xe7, 0x4c, 0xf2, 0xde, 0x1b, 0xb9, 0x82, 0x17, 0x6f, + 0x33, 0x47, 0xca, 0xad, 0xbf, 0x4b, 0xfe, 0x65, 0xe0, 0xf1, 0x44, 0xb0, + 0x75, 0xa5, 0xd2, 0x10, 0x9b, 0x4d, 0x6e, 0x81, 0x2a, 0x59, 0x93, 0x6e, + 0xb6, 0xff, 0x5f, 0x5e, 0x36, 0xd4, 0xcc, 0x3c, 0xcd, 0xa0, 0x2d, 0x05, + 0x3b, 0x4e, 0xd8, 0xfb, 0x89, 0x06, 0x5e, 0xca, 0xbe, 0x92, 0x3f, 0x8f, + 0x28, 0x73, 0x1e, 0xe6, 0x9c, 0x4f, 0x5d, 0x13, 0x95, 0xf9, 0x0f, 0xa6, + 0x33, 0xa8, 0x16, 0x1e, 0x68, 0x9a, 0xd0, 0xe9, 0x37, 0x26, 0x43, 0xd8, + 0x0d, 0x88, 0xfb, 0x64, 0x6f, 0xc1, 0x97, 0xff, 0x3f, 0x66, 0xac, 0xf7, + 0x09, 0x6b, 0x3c, 0x60, 0xbd, 0xdc, 0x99, 0x33, 0x1d, 0xe6, 0xd8, 0xd5, + 0xc8, 0x78, 0x65, 0xfd, 0x00, 0xe6, 0x34, 0x23, 0x00, 0x9f, 0x76, 0x37, + 0xc7, 0xed, 0xc2, 0x74, 0xe6, 0x47, 0x91, 0x99, 0x0d, 0x6d, 0x4d, 0xea, + 0x15, 0x88, 0x55, 0xc9, 0x79, 0x22, 0x9d, 0xf6, 0x0f, 0x14, 0xf7, 0xca, + 0xf9, 0x0d, 0xb3, 0xd5, 0x8d, 0xa0, 0x7f, 0xae, 0xa2, 0xa0, 0x28, 0x04, + 0xe7, 0xfd, 0x59, 0xf2, 0xb0, 0x99, 0x1f, 0x59, 0x3f, 0xf2, 0xe9, 0xcc, + 0xe7, 0x0b, 0x7d, 0xd0, 0xf1, 0xf5, 0xd1, 0x4b, 0x33, 0xc8, 0x82, 0xcc, + 0xf7, 0xad, 0xd8, 0x74, 0x69, 0x5b, 0xe4, 0x7e, 0x52, 0x5f, 0x73, 0x7d, + 0xfc, 0xa7, 0x59, 0xf5, 0x01, 0x07, 0x2a, 0xb1, 0x5e, 0x37, 0xa6, 0xcb, + 0xd9, 0xec, 0x7b, 0x65, 0x8d, 0xc5, 0x3e, 0xcf, 0x36, 0xf5, 0x5c, 0xd6, + 0xd4, 0x75, 0x63, 0x2f, 0xaa, 0x89, 0xe1, 0x25, 0x49, 0xd1, 0xf5, 0x35, + 0x50, 0xa9, 0xef, 0x63, 0xc4, 0xa2, 0xe2, 0xa4, 0x87, 0x79, 0xab, 0x87, + 0x58, 0x67, 0xe0, 0xb9, 0x6c, 0x07, 0x5c, 0xe4, 0x4e, 0x13, 0xd9, 0x30, + 0x5e, 0xcd, 0xce, 0x99, 0x2e, 0xe7, 0x5e, 0xa9, 0x02, 0x38, 0x67, 0xca, + 0x6f, 0x53, 0xde, 0xe7, 0x53, 0x72, 0xbf, 0xdf, 0xb7, 0xdf, 0x35, 0x77, + 0x18, 0x2b, 0x71, 0x4f, 0xa2, 0x4a, 0xd6, 0xda, 0x4d, 0x9f, 0x61, 0x5a, + 0xd3, 0xb4, 0xaa, 0xe9, 0xb9, 0xf3, 0x30, 0xc1, 0xf6, 0xa5, 0xc4, 0x91, + 0xd5, 0x11, 0xad, 0xed, 0xbf, 0x2b, 0xc1, 0x40, 0x5a, 0x69, 0x63, 0xf9, + 0x30, 0x36, 0x8f, 0x4a, 0x5d, 0x85, 0xe3, 0x2d, 0xec, 0x57, 0x37, 0x04, + 0x42, 0xea, 0xaf, 0x0b, 0x67, 0xa1, 0xdd, 0x45, 0x46, 0x1c, 0xcf, 0x26, + 0xa6, 0xcb, 0xff, 0x2c, 0x90, 0x35, 0x95, 0xbc, 0x4c, 0x8f, 0x59, 0x65, + 0x48, 0x5b, 0xed, 0x6c, 0xcb, 0x3c, 0xeb, 0x25, 0x86, 0xb8, 0xb4, 0xe0, + 0xd1, 0xaf, 0x22, 0xb8, 0x66, 0xbe, 0xa3, 0x13, 0x67, 0x22, 0x5a, 0xc7, + 0x47, 0x6c, 0xa3, 0xca, 0x11, 0x46, 0x6f, 0x5e, 0xbe, 0xfc, 0x9f, 0xd8, + 0x9c, 0xac, 0x86, 0x55, 0x45, 0xea, 0x69, 0x2b, 0x33, 0x3d, 0x27, 0xbf, + 0xd8, 0x58, 0xce, 0xfc, 0xd8, 0x43, 0xb9, 0x72, 0xe6, 0x36, 0xb8, 0xf3, + 0xd7, 0x30, 0xad, 0x6a, 0x4d, 0xeb, 0xf9, 0xaa, 0xda, 0x89, 0x15, 0x4d, + 0xc1, 0xc0, 0x32, 0xda, 0x48, 0x95, 0x2d, 0x23, 0x16, 0x2e, 0xfa, 0xd8, + 0x33, 0x71, 0xf4, 0x23, 0xc8, 0xba, 0x23, 0xcb, 0x95, 0xca, 0x99, 0x31, + 0x79, 0xd7, 0xd4, 0x89, 0x85, 0x8c, 0x6f, 0xf1, 0xc2, 0xff, 0x74, 0xb2, + 0xf7, 0x86, 0xbe, 0x31, 0xfd, 0xc2, 0xff, 0xd9, 0xfd, 0xff, 0x01, 0x02, + 0x8b, 0x0c, 0x6e, 0x74, 0x57, 0x00, 0x00, 0x00 }; -static const u32 bnx2_CP_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = { - 0x0800069c, 0x080008bc, 0x08000800, 0x08000828, 0x08000850, 0x08000878, - 0x080006d4, 0x080006c0, 0x080008e4, 0x080008e4, 0x080006f0, 0x0800070c, - 0x0800070c, 0x080008e4, 0x08000724, 0x08000738, 0x080008e4, 0x0800074c, - 0x080008e4, 0x080008e4, 0x08000760, 0x080008e4, 0x080008e4, 0x080008e4, - 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, 0x080008e4, - 0x080008e4, 0x08000774, 0x080008e4, 0x08000788, 0x0800079c, 0x080007b0, - 0x080008e4, 0x080007c4, 0x080007d8, 0x080007ec, 0x080032e8, 0x08003300, - 0x08003310, 0x08003320, 0x08003338, 0x08003350, 0x08003360, 0x08003370, - 0x08003390, 0x080033a0, 0x080033b0, 0x08003440, 0x08003380, 0x080033c0, - 0x080033d0, 0x080033e8, 0x08003408, 0x08003440, 0x08003420, 0x08003420, - 0x080051bc, 0x080051bc, 0x080051bc, 0x080051bc, 0x080051bc, 0x080051e4, - 0x080051e4, 0x0800520c, 0x0800525c, 0x0800522c, 0x00000000 }; +static const u32 bnx2_CP_b09FwData[(0x84/4) + 1] = { + 0x00000000, 0x0000001b, 0x0000000f, 0x0000000a, 0x00000008, 0x00000006, + 0x00000005, 0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000003, + 0x00000003, 0x00000003, 0x00000003, 0x00000002, 0x00000002, 0x00000002, + 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, + 0x00000001, 0x00000001, 0x00000001, 0x00000000 }; +static const u32 bnx2_CP_b09FwRodata[(0x178/4) + 1] = { + 0x80080100, 0x80080080, 0x80080000, 0x080015a0, 0x080015d8, 0x08001600, + 0x08001600, 0x08001614, 0x080015bc, 0x080018a4, 0x0800186c, 0x080018f8, + 0x080018f8, 0x08001980, 0x080018b4, 0x80080240, 0x80080100, 0x80080080, + 0x80080000, 0x08003148, 0x080030b4, 0x08003170, 0x08003198, 0x080031c0, + 0x080031e4, 0x0800322c, 0x08003208, 0x08003250, 0x0800311c, 0x08003344, + 0x08003334, 0x080030d0, 0x080030d0, 0x080030d0, 0x080032a4, 0x080032a4, + 0x080030d0, 0x080030d0, 0x08003324, 0x080030d0, 0x080030d0, 0x080030d0, + 0x080030d0, 0x08003314, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, + 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, + 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x08003304, 0x080030d0, + 0x080030d0, 0x080032f4, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, + 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, + 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, 0x080030d0, + 0x080030d0, 0x080032dc, 0x080030d0, 0x080030d0, 0x080032cc, 0x080032bc, + 0x08003c0c, 0x08003be8, 0x08003bbc, 0x08003b9c, 0x08003b7c, 0x08003b24, + 0x80080100, 0x80080080, 0x80080000, 0x80080080, 0x00000000 }; static struct fw_info bnx2_cp_fw_09 = { - /* Firmware version: 3.7.1 */ - .ver_major = 0x3, - .ver_minor = 0x7, - .ver_fix = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x0800006c, + .start_addr = 0x08000074, .text_addr = 0x08000000, - .text_len = 0x6fd0, + .text_len = 0x5770, .text_index = 0x0, .gz_text = bnx2_CP_b09FwText, .gz_text_len = sizeof(bnx2_CP_b09FwText), - .data_addr = 0x08007100, - .data_len = 0x0, + .data_addr = 0x08005900, + .data_len = 0x84, .data_index = 0x0, .data = bnx2_CP_b09FwData, - .sbss_addr = 0x08007104, - .sbss_len = 0xa9, + .sbss_addr = 0x08005988, + .sbss_len = 0x99, .sbss_index = 0x0, - .bss_addr = 0x080071b0, - .bss_len = 0x3b0, + .bss_addr = 0x08005a28, + .bss_len = 0x20c, .bss_index = 0x0, - .rodata_addr = 0x08006fd0, - .rodata_len = 0x118, + .rodata_addr = 0x08005770, + .rodata_len = 0x178, .rodata_index = 0x0, .rodata = bnx2_CP_b09FwRodata, }; static u8 bnx2_RXP_b09FwText[] = { - 0xec, 0x5c, 0x7d, 0x6c, 0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x8e, - 0xd4, 0x91, 0x5c, 0x1e, 0x4f, 0xcc, 0x51, 0xa6, 0xed, 0x5b, 0x71, 0x25, - 0x9e, 0x4d, 0xc6, 0x59, 0xd1, 0x07, 0x9b, 0x28, 0x0e, 0xc9, 0x66, 0xef, - 0x24, 0xb1, 0x86, 0x5b, 0x53, 0x35, 0x1d, 0x1b, 0x6d, 0xea, 0xb2, 0x47, - 0xb5, 0x29, 0x8c, 0x06, 0x90, 0xbf, 0x00, 0x17, 0xa8, 0xe4, 0xcb, 0x91, - 0x8a, 0x55, 0xf7, 0xc0, 0xbd, 0xc8, 0x8c, 0x18, 0x20, 0x6e, 0x7d, 0x25, - 0x29, 0x4a, 0x08, 0x0e, 0x3a, 0xa6, 0x71, 0x1a, 0xfd, 0x61, 0xd7, 0x04, - 0x2b, 0x1b, 0x6e, 0x91, 0xd6, 0x72, 0xe3, 0xb6, 0x46, 0x50, 0x04, 0x84, - 0xec, 0x34, 0x6e, 0xd0, 0x0f, 0xa1, 0x2e, 0x6c, 0x03, 0x96, 0xbd, 0xfd, - 0xbd, 0xd9, 0x5d, 0xf2, 0x48, 0x5b, 0x76, 0xd0, 0x3f, 0xfa, 0x4f, 0x77, - 0x80, 0xc3, 0xce, 0xcc, 0xbe, 0xf7, 0xe6, 0xcd, 0x9b, 0xf7, 0x39, 0x4b, - 0xe9, 0xb7, 0xe3, 0xd4, 0x4e, 0x41, 0xeb, 0xc0, 0x2f, 0x7d, 0xf4, 0xb1, - 0x87, 0x6e, 0xb9, 0xfd, 0x96, 0x5b, 0xd1, 0xdd, 0xaf, 0x2a, 0x3b, 0xd4, - 0x70, 0x3e, 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, - 0x2d, 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, - 0x6a, 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, - 0x51, 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, 0x51, - 0x8b, 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0x2d, 0x6a, 0x51, 0x8b, - 0x5a, 0xd4, 0xa2, 0x16, 0xb5, 0xa8, 0x45, 0xed, 0xff, 0x7b, 0x53, 0x89, - 0x74, 0x7e, 0x76, 0x04, 0x3f, 0x8a, 0x89, 0x5c, 0xfa, 0x01, 0xc7, 0xa4, - 0x98, 0x9a, 0xeb, 0x3f, 0x3e, 0x65, 0x12, 0xd9, 0xf5, 0xa1, 0x74, 0x9e, - 0x3e, 0xf0, 0x4a, 0x49, 0x8d, 0x78, 0xfe, 0xfa, 0xdc, 0xd5, 0x67, 0x9e, - 0xbf, 0xdd, 0xb8, 0x52, 0x53, 0x29, 0xa6, 0xe7, 0x66, 0xf6, 0xeb, 0xfb, - 0x28, 0xd6, 0x0f, 0x9c, 0xa7, 0x07, 0xff, 0xb1, 0x93, 0x3a, 0x43, 0x5a, - 0x44, 0x0b, 0x15, 0xc3, 0x3a, 0x88, 0xe7, 0x72, 0x7d, 0xc8, 0x5a, 0x23, - 0x8d, 0x56, 0x75, 0x7f, 0xc5, 0x72, 0x45, 0x61, 0x3a, 0x54, 0xae, 0xc7, - 0x68, 0x5d, 0xfe, 0x3b, 0x0f, 0xac, 0x69, 0x72, 0xff, 0x82, 0xe2, 0x34, - 0x3c, 0xef, 0x8c, 0xe5, 0x79, 0x2f, 0xe1, 0xf7, 0x33, 0x0b, 0x63, 0xf7, - 0x43, 0xcf, 0xd6, 0x54, 0x12, 0xe6, 0x1f, 0x2b, 0xce, 0x62, 0x2b, 0x95, - 0xe7, 0x89, 0xa6, 0xdd, 0x18, 0x9d, 0x74, 0x4b, 0x4a, 0xa1, 0x51, 0x51, - 0x0e, 0x9c, 0x9d, 0x55, 0x0e, 0x9e, 0x3d, 0xa9, 0x1c, 0x3a, 0x5b, 0x55, - 0x9c, 0xb3, 0x54, 0x12, 0xfb, 0xe3, 0x64, 0xeb, 0xe7, 0x94, 0x7c, 0xa3, - 0x57, 0x71, 0xe6, 0xaf, 0x7a, 0x8e, 0x65, 0xe8, 0xbf, 0x4e, 0x9a, 0xcd, - 0xeb, 0x39, 0x15, 0x0f, 0x63, 0x8d, 0xec, 0xa4, 0xe7, 0x89, 0x9c, 0xf7, - 0xb8, 0x93, 0x35, 0x75, 0xa1, 0xc4, 0xa8, 0xdc, 0x68, 0x07, 0x5d, 0x4d, - 0xc9, 0xbb, 0xde, 0x0b, 0x8e, 0xb5, 0x0c, 0x3a, 0x75, 0xe0, 0x93, 0x2e, - 0x72, 0xcc, 0x4f, 0xc8, 0x63, 0x49, 0xc9, 0x0f, 0x86, 0xfc, 0x50, 0x9a, - 0xf9, 0x2d, 0x2e, 0x09, 0xf0, 0xb5, 0x93, 0x8a, 0x35, 0x9d, 0x26, 0x97, - 0xb6, 0xc3, 0xaf, 0x7b, 0xcf, 0x0f, 0xea, 0xb4, 0xd2, 0x30, 0x4a, 0x25, - 0xec, 0x7d, 0xc6, 0x4d, 0x93, 0xc8, 0x91, 0xed, 0x64, 0xfb, 0xe9, 0x85, - 0x46, 0x8a, 0xfe, 0xbc, 0x61, 0xa6, 0xca, 0xb4, 0x83, 0x8a, 0xc9, 0x24, - 0x7d, 0x17, 0x38, 0xd3, 0x58, 0x5b, 0x98, 0xa6, 0x5e, 0x06, 0x6c, 0xb9, - 0xf1, 0x23, 0xfe, 0xb7, 0x31, 0xfa, 0x54, 0x56, 0xe2, 0x94, 0xc0, 0x67, - 0x00, 0xcb, 0x7c, 0x4b, 0x58, 0xc9, 0xbb, 0x0f, 0x4b, 0xa5, 0xa9, 0x2c, - 0xe6, 0x1a, 0x4e, 0x20, 0xfb, 0x56, 0xec, 0x8f, 0x9f, 0x37, 0x28, 0xf9, - 0xf9, 0x1b, 0x20, 0x03, 0x4a, 0x0a, 0xda, 0x9b, 0x2a, 0x62, 0x66, 0xba, - 0x11, 0xc7, 0x98, 0x79, 0xf1, 0xbc, 0x43, 0x16, 0xe9, 0x65, 0xab, 0x0b, - 0xb2, 0x4a, 0x53, 0xd9, 0xea, 0x04, 0x4e, 0x0b, 0x75, 0x9b, 0xbc, 0x07, - 0xa6, 0xdb, 0x86, 0x79, 0xaf, 0x43, 0xcd, 0x79, 0xde, 0x54, 0x96, 0x3a, - 0xfd, 0xb9, 0x21, 0xd0, 0xd0, 0x68, 0x72, 0x5c, 0x01, 0xdc, 0xdb, 0xcc, - 0x5f, 0x2c, 0x91, 0xe3, 0x3e, 0x3f, 0xb3, 0xe4, 0xcc, 0xa6, 0x83, 0x75, - 0xe3, 0x54, 0x76, 0xaf, 0x0f, 0xfa, 0x90, 0xad, 0x8b, 0x3d, 0x5b, 0x7d, - 0x18, 0x2b, 0x37, 0x82, 0x8e, 0x55, 0x26, 0x5e, 0x63, 0x17, 0xad, 0x25, - 0x49, 0x5c, 0xb6, 0x7a, 0x02, 0xb8, 0x4e, 0xf0, 0x1a, 0x9e, 0x71, 0x3b, - 0xcd, 0xcc, 0xb7, 0xd2, 0x89, 0x79, 0x96, 0x6d, 0x05, 0x67, 0x21, 0x68, - 0xcf, 0x6d, 0x25, 0xc5, 0x6e, 0x9c, 0x44, 0x5f, 0xa3, 0x29, 0xd3, 0x7b, - 0x61, 0xc6, 0x9a, 0x55, 0xf2, 0x67, 0x97, 0x95, 0x02, 0xce, 0xfc, 0xc0, - 0xd9, 0x0b, 0xca, 0xc1, 0xc6, 0xcb, 0x1d, 0xd4, 0x6e, 0x40, 0xbb, 0x34, - 0x3a, 0xe1, 0x2a, 0xc4, 0xfc, 0x2e, 0x40, 0x5e, 0xb6, 0x0e, 0xc9, 0x9b, - 0x9d, 0xca, 0x41, 0xd0, 0x6a, 0x31, 0xbf, 0x1e, 0xa7, 0x4e, 0x95, 0x76, - 0x98, 0x21, 0x6c, 0x8c, 0xbe, 0x0e, 0xde, 0xd6, 0xac, 0x24, 0xe0, 0xa8, - 0xcb, 0xc7, 0xe9, 0x0e, 0xf8, 0x61, 0xdd, 0x61, 0xbd, 0x11, 0x76, 0x61, - 0xee, 0x8f, 0x7a, 0xca, 0xc3, 0x3b, 0x19, 0x06, 0xf6, 0x60, 0x3f, 0x30, - 0x65, 0x3a, 0xdd, 0x1a, 0x95, 0x74, 0x41, 0x86, 0x9e, 0xa7, 0x1b, 0x69, - 0xc6, 0x22, 0xca, 0x43, 0x9f, 0x85, 0xa9, 0x41, 0x46, 0x26, 0x64, 0xb4, - 0xb7, 0xa4, 0x8a, 0x7b, 0x41, 0xa2, 0xa4, 0x68, 0x81, 0x3c, 0x17, 0xe8, - 0x0e, 0x89, 0x2f, 0x72, 0x16, 0x74, 0xb0, 0x9d, 0xfb, 0x58, 0x37, 0x26, - 0xd7, 0x55, 0x73, 0x66, 0x6a, 0x91, 0x48, 0x11, 0xb9, 0x21, 0xd0, 0x63, - 0xdd, 0x64, 0x38, 0x17, 0x3c, 0x32, 0xef, 0xdc, 0x37, 0x81, 0x13, 0x23, - 0xc7, 0xea, 0x68, 0xe2, 0x13, 0xfc, 0x24, 0x59, 0xe6, 0x2c, 0x43, 0xb9, - 0x4f, 0x65, 0x73, 0x9f, 0xef, 0x7b, 0x83, 0x23, 0x1a, 0xbd, 0x24, 0xf7, - 0xcb, 0x76, 0xc4, 0x70, 0x72, 0x8f, 0xc4, 0xf2, 0x99, 0x76, 0x49, 0x29, - 0x5a, 0xfa, 0x06, 0x2d, 0xe8, 0x85, 0x50, 0x73, 0x71, 0xca, 0x4b, 0xfe, - 0x46, 0xb1, 0x16, 0xdb, 0x17, 0xec, 0xc4, 0xe4, 0xbd, 0xf0, 0x5c, 0x0e, - 0xb6, 0x6a, 0x48, 0xfd, 0x29, 0x56, 0xd9, 0xfe, 0x99, 0xb7, 0x55, 0x43, - 0x50, 0x48, 0x4f, 0xf4, 0xaa, 0xd4, 0x45, 0xe3, 0xd6, 0x55, 0x4f, 0xec, - 0xc3, 0xfb, 0xe1, 0x14, 0x78, 0x33, 0xd2, 0xb0, 0xb6, 0x84, 0x4a, 0xb0, - 0x73, 0x6b, 0x28, 0xa5, 0x93, 0x89, 0xbd, 0x25, 0xc8, 0x1e, 0x5f, 0x85, - 0xe0, 0xaf, 0xc5, 0xa7, 0x4f, 0x17, 0x6c, 0xda, 0x0e, 0x78, 0x74, 0xac, - 0x5b, 0xa5, 0xcc, 0x74, 0xec, 0x5f, 0x9d, 0x65, 0xf9, 0xb6, 0x43, 0xff, - 0x15, 0x2a, 0x5a, 0x4c, 0x3b, 0xa4, 0x21, 0x68, 0xf0, 0xb6, 0x66, 0x1a, - 0xe1, 0xd9, 0xb2, 0xfe, 0x6a, 0x34, 0x32, 0xc2, 0xb0, 0x0c, 0xc7, 0xf0, - 0xc6, 0x68, 0x5a, 0xbc, 0xef, 0xed, 0xdf, 0xb2, 0xa6, 0x49, 0x62, 0x16, - 0x3c, 0xfb, 0x67, 0x01, 0x19, 0x7e, 0x1a, 0x2c, 0x9f, 0xc3, 0x76, 0x79, - 0x33, 0x6c, 0x33, 0x1c, 0x74, 0xa8, 0x97, 0x79, 0xa8, 0xc7, 0x7d, 0x7b, - 0x0c, 0x79, 0x0a, 0xcf, 0x52, 0x09, 0x68, 0x7c, 0xd2, 0x3e, 0x18, 0x1e, - 0x7e, 0xc2, 0x85, 0x9f, 0x70, 0xe1, 0x1f, 0x5c, 0xf8, 0x11, 0x97, 0xfd, - 0x4a, 0x9a, 0x9e, 0x1f, 0x84, 0xdf, 0xdb, 0xf4, 0x43, 0x68, 0x63, 0xe8, - 0x0b, 0x52, 0xe1, 0x87, 0xa6, 0x6b, 0x02, 0xb6, 0x0e, 0x9b, 0x5b, 0xe2, - 0x39, 0x1d, 0xcf, 0x02, 0x9e, 0x26, 0xfc, 0x2c, 0xeb, 0x61, 0xe8, 0x5f, - 0xd9, 0x2f, 0xa5, 0xe0, 0x83, 0xd8, 0xef, 0xb0, 0x7f, 0x62, 0x58, 0xcf, - 0x2b, 0x58, 0x8c, 0xeb, 0xe1, 0x1c, 0xd9, 0xee, 0xe2, 0x24, 0x12, 0x25, - 0xe5, 0xf0, 0x20, 0x6c, 0xf2, 0xe6, 0x16, 0xf0, 0xca, 0xb6, 0x79, 0x1d, - 0xbb, 0x16, 0xb4, 0xf7, 0x3b, 0xfc, 0x7f, 0xb7, 0xb7, 0x03, 0x30, 0xd2, - 0xc6, 0x3b, 0xfd, 0x71, 0x77, 0xe0, 0x7f, 0xf8, 0xbd, 0x91, 0xb6, 0x69, - 0x5f, 0x30, 0xe6, 0xfe, 0x06, 0xbf, 0x96, 0xb8, 0x2d, 0x46, 0x7b, 0x96, - 0x7d, 0xbf, 0xb9, 0x67, 0x01, 0x9a, 0xb1, 0xec, 0xf3, 0xb8, 0xe7, 0x7c, - 0xe8, 0x3f, 0x3b, 0x40, 0x0f, 0xfc, 0xb9, 0x9b, 0x71, 0x84, 0xe8, 0xbf, - 0x14, 0x98, 0x16, 0xe6, 0xb6, 0xcb, 0xc2, 0xf3, 0x66, 0x2c, 0xb6, 0x4f, - 0xbd, 0xd9, 0x3e, 0xf7, 0xc3, 0x3e, 0xad, 0x56, 0x32, 0xac, 0xbf, 0x82, - 0x7d, 0x3e, 0x61, 0x29, 0x90, 0x0d, 0xd1, 0xc5, 0x4a, 0x1c, 0xbe, 0x41, - 0x4b, 0xbd, 0x41, 0x7b, 0xd3, 0xd3, 0xd0, 0xcb, 0x33, 0x3c, 0x87, 0x23, - 0x3a, 0x21, 0xfd, 0xb5, 0xef, 0x0f, 0xd6, 0xd5, 0x6f, 0x80, 0x2f, 0xcf, - 0x9b, 0x06, 0xcd, 0xe2, 0xb0, 0x1a, 0xd8, 0x62, 0x38, 0x6f, 0x23, 0x26, - 0x3a, 0x37, 0xa9, 0x54, 0xca, 0xb4, 0x90, 0x91, 0x59, 0x00, 0xed, 0x29, - 0xcb, 0xb7, 0x7b, 0xb6, 0x8d, 0x45, 0xd0, 0x9f, 0x71, 0x07, 0xe1, 0x17, - 0xd8, 0x6e, 0xc0, 0x17, 0xe8, 0x2f, 0x82, 0xfe, 0x4c, 0xa3, 0x85, 0xbe, - 0xa6, 0x85, 0xb1, 0x36, 0xdc, 0x0f, 0x44, 0x6d, 0x86, 0xeb, 0x1e, 0xa5, - 0x3b, 0xdc, 0x84, 0xe2, 0x3c, 0xc5, 0x7e, 0xb9, 0x9c, 0x81, 0x5d, 0x29, - 0x65, 0x8b, 0xd7, 0x56, 0x69, 0x71, 0x03, 0x86, 0xec, 0xb2, 0x6f, 0xb3, - 0xb6, 0x33, 0x58, 0x4a, 0xa9, 0xd2, 0xf7, 0x10, 0x1d, 0xac, 0x68, 0x80, - 0xe1, 0x31, 0xcf, 0xfb, 0x73, 0x63, 0x95, 0x5e, 0xf8, 0x52, 0x1e, 0x5f, - 0xf5, 0xa6, 0x2c, 0x7f, 0xee, 0x97, 0x2b, 0x0f, 0xf0, 0x19, 0x61, 0x2f, - 0x94, 0x2e, 0x5b, 0x3f, 0xf7, 0xa0, 0xbf, 0x5b, 0x70, 0x3e, 0x9e, 0x8e, - 0x31, 0xe6, 0xeb, 0x2c, 0x29, 0x87, 0x4c, 0xd1, 0xdb, 0x1a, 0xf8, 0xbc, - 0x43, 0x98, 0x3c, 0x50, 0x29, 0xf7, 0xb4, 0xd2, 0x55, 0x95, 0x63, 0xeb, - 0x65, 0x38, 0x01, 0xa7, 0xb2, 0x0f, 0xf2, 0x28, 0x77, 0x37, 0xcd, 0xc5, - 0x0a, 0x15, 0x8f, 0xd6, 0x2c, 0x1f, 0x07, 0xe3, 0x78, 0xbe, 0x22, 0x7a, - 0x63, 0xb4, 0x31, 0xd6, 0x19, 0x67, 0x89, 0xf6, 0x65, 0x16, 0x49, 0xe2, - 0xf6, 0xc4, 0x36, 0x71, 0x93, 0x85, 0x4a, 0xb9, 0xbb, 0x69, 0x9c, 0xca, - 0x83, 0x96, 0xd8, 0xbf, 0x81, 0xdb, 0xbf, 0x89, 0xbb, 0x8b, 0xd2, 0xdd, - 0x8c, 0x2f, 0x7a, 0xdb, 0x36, 0x69, 0xa7, 0x03, 0x7e, 0x7a, 0xda, 0x36, - 0x69, 0x98, 0x4c, 0xb3, 0x69, 0x9c, 0x61, 0x9a, 0x7b, 0x36, 0x69, 0x0e, - 0x6f, 0xe5, 0xe7, 0x28, 0xc1, 0x07, 0xc5, 0x5a, 0x73, 0xb4, 0xff, 0x62, - 0x65, 0x60, 0xfc, 0x0e, 0x42, 0x8c, 0x1c, 0xde, 0x11, 0xf8, 0x70, 0x6d, - 0xbf, 0x03, 0x59, 0x69, 0xc4, 0x3e, 0x51, 0xa1, 0x32, 0xce, 0xf9, 0x81, - 0x3a, 0xed, 0x5f, 0xab, 0x53, 0xa0, 0x4b, 0xac, 0x13, 0x6f, 0xc1, 0xc6, - 0xa8, 0xb4, 0x3b, 0x17, 0x9f, 0xd4, 0x72, 0x3a, 0x6c, 0x8d, 0xc6, 0xcb, - 0xf0, 0xe1, 0x6a, 0x6e, 0xef, 0xeb, 0x79, 0xf5, 0x71, 0x4f, 0x35, 0xd9, - 0x1f, 0xc6, 0x47, 0x9d, 0x2c, 0xe6, 0xeb, 0x6c, 0x5b, 0xf0, 0x2b, 0x0d, - 0xa6, 0xfd, 0x4c, 0x17, 0x75, 0x22, 0x8e, 0xd6, 0xcf, 0xec, 0xf2, 0x6d, - 0x87, 0x34, 0x0d, 0xbe, 0x79, 0x26, 0xcb, 0x71, 0xbf, 0x35, 0x06, 0xf8, - 0x49, 0x35, 0x37, 0xd6, 0x77, 0xa4, 0x7e, 0x67, 0x5f, 0xb1, 0x5e, 0xea, - 0x2b, 0x56, 0x74, 0xb6, 0x13, 0xe1, 0x64, 0xd1, 0x97, 0xb9, 0x54, 0x0a, - 0x36, 0xc1, 0x6b, 0x27, 0xb1, 0xe6, 0x0f, 0x60, 0x7f, 0x6c, 0xdf, 0x44, - 0xe3, 0x2e, 0xd6, 0x18, 0xf9, 0x00, 0xe7, 0x0e, 0xde, 0xe0, 0xd3, 0x6c, - 0xec, 0x5a, 0x8c, 0xfc, 0x6b, 0x60, 0x9f, 0xdc, 0x7f, 0xc7, 0xf3, 0xe3, - 0xc3, 0xdd, 0x5d, 0xfe, 0xdc, 0x8f, 0x03, 0x9b, 0x0e, 0x69, 0x31, 0x9d, - 0x8c, 0x32, 0x8e, 0x1c, 0x66, 0xbc, 0xa1, 0x29, 0xec, 0x9f, 0xf3, 0x2e, - 0xe7, 0x1e, 0x9c, 0x77, 0x4c, 0x07, 0x7e, 0x8e, 0x6c, 0xe4, 0x4f, 0x9e, - 0x40, 0x2e, 0x52, 0x84, 0xdd, 0x68, 0xb9, 0x2b, 0x34, 0x23, 0x7d, 0x24, - 0xc5, 0x5a, 0x72, 0x8f, 0x01, 0xe6, 0xdf, 0x60, 0x73, 0xdd, 0x5d, 0x81, - 0x1e, 0x06, 0x3e, 0x5e, 0xfa, 0x5d, 0xc0, 0xbe, 0xb5, 0x0d, 0xf6, 0xcd, - 0x66, 0x58, 0xbc, 0x5f, 0xdf, 0xf6, 0xfe, 0x9f, 0xd9, 0x7e, 0xf1, 0x6e, - 0x15, 0xfe, 0xb4, 0x35, 0xb0, 0xfd, 0x8b, 0x54, 0x84, 0x6f, 0xd5, 0x4c, - 0xce, 0x2d, 0x0f, 0x02, 0x17, 0xe3, 0x3a, 0x78, 0x84, 0xbf, 0x40, 0x8c, - 0x85, 0xbc, 0x11, 0x13, 0x92, 0x37, 0x72, 0x3e, 0x05, 0xd8, 0x34, 0x60, - 0xd9, 0xff, 0x32, 0xec, 0x85, 0x38, 0xcb, 0xbc, 0x58, 0x67, 0x1c, 0xf6, - 0x55, 0xe4, 0x39, 0xd9, 0x36, 0x68, 0x94, 0xf7, 0x82, 0x6a, 0x86, 0xb0, - 0x21, 0xdd, 0xed, 0xb0, 0x9c, 0xdf, 0x30, 0xed, 0xae, 0x20, 0x6f, 0x18, - 0x23, 0xbb, 0x61, 0xe3, 0x57, 0xa2, 0xa9, 0xa7, 0x90, 0xbb, 0x99, 0x2d, - 0x2c, 0x0b, 0x9e, 0xd7, 0x7d, 0x19, 0x85, 0x78, 0xa5, 0x9e, 0xad, 0xe3, - 0xdf, 0x4a, 0x6c, 0xfa, 0x4a, 0xb6, 0x34, 0xb2, 0x11, 0x2b, 0x20, 0xe3, - 0xf4, 0xa4, 0xc8, 0x25, 0x29, 0x5f, 0xf7, 0xe5, 0x8b, 0xf8, 0x0c, 0xff, - 0x28, 0xfd, 0x07, 0xce, 0x3d, 0xf4, 0x83, 0xe1, 0x99, 0xb3, 0x9e, 0xd9, - 0x38, 0x9b, 0x34, 0x74, 0x69, 0x0c, 0xb8, 0x74, 0x14, 0x34, 0x38, 0x6e, - 0x5b, 0x22, 0x97, 0xa0, 0xa2, 0xce, 0xf9, 0x85, 0xcc, 0x0d, 0x6d, 0xf6, - 0x03, 0x22, 0xd7, 0x86, 0x39, 0xee, 0xff, 0x41, 0x97, 0x7f, 0xd6, 0x1d, - 0x3c, 0x1e, 0x17, 0xb9, 0xae, 0x6d, 0xf3, 0x7f, 0xd7, 0xe1, 0xf3, 0x26, - 0xc7, 0x98, 0xff, 0xc9, 0xb6, 0xf1, 0xa3, 0x89, 0xad, 0xe3, 0xaf, 0xf6, - 0x85, 0xfa, 0x20, 0x72, 0x8f, 0x05, 0xfc, 0xb2, 0x9e, 0x6e, 0xe7, 0xf5, - 0x17, 0xd1, 0x97, 0x3f, 0x01, 0x4d, 0xa9, 0xe3, 0xbf, 0x80, 0xbe, 0x6c, - 0xc0, 0x5e, 0x43, 0x5f, 0x9a, 0x79, 0xd8, 0xa8, 0x3b, 0xaa, 0x02, 0x39, - 0xac, 0x93, 0xdd, 0x9b, 0x2e, 0xc3, 0xc6, 0x0b, 0x0d, 0xc8, 0x6e, 0x23, - 0xae, 0x6e, 0xc0, 0x94, 0x36, 0x61, 0xfc, 0xb8, 0x53, 0x68, 0x78, 0xc8, - 0xfb, 0x9a, 0x63, 0x70, 0x06, 0xfd, 0x12, 0xf6, 0xba, 0x42, 0x53, 0xee, - 0x9a, 0x2d, 0xcc, 0x93, 0x32, 0x6f, 0x15, 0xe6, 0x93, 0x4a, 0x61, 0x91, - 0x73, 0xda, 0x18, 0xfa, 0xb2, 0x3e, 0x41, 0x8c, 0x3b, 0xa5, 0xd8, 0x67, - 0xe7, 0x90, 0xcf, 0x2e, 0xe1, 0x77, 0x0e, 0xbf, 0x3a, 0x7e, 0x61, 0xdd, - 0xf0, 0x2d, 0xd4, 0x1d, 0xd2, 0xdf, 0x23, 0x36, 0xf9, 0xeb, 0xff, 0x74, - 0x09, 0xf9, 0xf4, 0x5c, 0x92, 0x9e, 0x30, 0x45, 0x8f, 0xf0, 0x7d, 0x9c, - 0x8d, 0x5c, 0x5c, 0x7f, 0x8b, 0x7e, 0x25, 0xc8, 0xe9, 0x88, 0xde, 0xa8, - 0xe2, 0x2c, 0x87, 0x0f, 0x05, 0xfe, 0xe9, 0xe4, 0x57, 0x1c, 0xe9, 0xcb, - 0x83, 0x9c, 0x0d, 0x7e, 0xc7, 0x96, 0x50, 0xaf, 0x40, 0x3e, 0x0a, 0xfd, - 0x0c, 0x7a, 0xfc, 0x46, 0xb5, 0x1d, 0xfc, 0x98, 0x54, 0x9c, 0x30, 0x46, - 0x49, 0x19, 0xd0, 0x77, 0x28, 0xed, 0xc8, 0xdb, 0xe0, 0x77, 0xe4, 0x98, - 0x65, 0x46, 0xc7, 0x17, 0x2a, 0x02, 0xb0, 0x90, 0x79, 0x16, 0x7d, 0xe8, - 0xdf, 0xe5, 0x2a, 0xe3, 0x09, 0x7a, 0xb3, 0xaa, 0xd2, 0xbf, 0x20, 0x0f, - 0xc4, 0xbb, 0xe3, 0xb0, 0xc1, 0x5e, 0xc4, 0xab, 0x7e, 0x95, 0xf6, 0x72, - 0xcc, 0xd8, 0xa3, 0xe1, 0x59, 0xc0, 0xef, 0x20, 0xf2, 0xc2, 0x6b, 0xe0, - 0x5c, 0x03, 0x9e, 0x79, 0x8b, 0x01, 0x87, 0xe1, 0x35, 0xf0, 0xd6, 0x09, - 0x1d, 0x34, 0xf4, 0x49, 0xfa, 0x8c, 0x2e, 0x73, 0x27, 0x85, 0xe7, 0x7d, - 0x3f, 0xf9, 0xd1, 0x79, 0x96, 0xb3, 0x0a, 0x1d, 0xe2, 0x31, 0xbf, 0x63, - 0x7f, 0xce, 0xf4, 0x8c, 0x51, 0x1b, 0x9b, 0xb9, 0x5c, 0xf5, 0xfb, 0xe1, - 0x1c, 0x29, 0x61, 0x4c, 0x65, 0x3f, 0x5d, 0x80, 0xad, 0xf2, 0x78, 0x9c, - 0xe4, 0x19, 0x6c, 0x39, 0x4f, 0xa9, 0x47, 0xc7, 0x66, 0x4c, 0x3e, 0x57, - 0x9d, 0xa6, 0x2b, 0xe1, 0xb9, 0xf2, 0x19, 0xa1, 0x0e, 0xad, 0x3e, 0x89, - 0x73, 0x15, 0x41, 0xcd, 0x02, 0x3f, 0x30, 0xc7, 0xe7, 0x8b, 0x3a, 0xb2, - 0x8a, 0x3c, 0xac, 0x4a, 0x09, 0xbf, 0xe6, 0x3a, 0x85, 0x3a, 0x05, 0xe7, - 0x57, 0x99, 0x03, 0x8d, 0x24, 0x9e, 0x4b, 0x78, 0xa6, 0xf0, 0x3c, 0x87, - 0x67, 0x3f, 0x9e, 0x75, 0xb6, 0x8f, 0x20, 0xef, 0xf9, 0x08, 0x3f, 0xb0, - 0x93, 0x02, 0xdb, 0x34, 0xfd, 0x65, 0x23, 0x47, 0x3f, 0x68, 0x8c, 0xd2, - 0x5f, 0x34, 0xb2, 0xf4, 0xfd, 0x86, 0x45, 0xcf, 0x36, 0x86, 0xe9, 0x7b, - 0x8d, 0x0c, 0xd7, 0x90, 0xc8, 0xe1, 0xd2, 0xf0, 0xcd, 0x17, 0xe8, 0x2b, - 0x6e, 0x03, 0x3e, 0x47, 0xfa, 0xcb, 0xe3, 0x76, 0xfd, 0x3a, 0x2a, 0x3e, - 0xa5, 0x23, 0xcf, 0x54, 0xb9, 0x8e, 0xa3, 0x47, 0xad, 0xbb, 0x13, 0x7c, - 0xf6, 0xc2, 0xe4, 0xba, 0xe6, 0x04, 0xc3, 0xa1, 0x1e, 0x56, 0x90, 0xbf, - 0xb4, 0xd0, 0x64, 0xd2, 0x58, 0x71, 0xd4, 0x74, 0xe0, 0x8f, 0x26, 0x00, - 0x87, 0x35, 0xdd, 0x38, 0xad, 0x9d, 0x86, 0x2d, 0x58, 0xa8, 0xa5, 0x93, - 0x31, 0xf8, 0x3e, 0x99, 0x9f, 0x48, 0xdf, 0xe2, 0xfb, 0xd2, 0xb0, 0xc6, - 0xe4, 0x39, 0x3b, 0x98, 0xe3, 0xf8, 0xa8, 0x03, 0xb6, 0x11, 0xc4, 0x90, - 0xed, 0x34, 0xd9, 0x37, 0x4e, 0x04, 0xfe, 0x71, 0x85, 0x1e, 0x76, 0x07, - 0xec, 0xb7, 0x11, 0x7b, 0x94, 0x96, 0x30, 0x2f, 0xda, 0x0d, 0xde, 0x3c, - 0xef, 0x30, 0xea, 0xf3, 0x74, 0x42, 0xa3, 0xbf, 0x9f, 0x35, 0xf4, 0xc3, - 0x02, 0x01, 0xae, 0xdd, 0xf3, 0xc6, 0x4d, 0xa3, 0x64, 0x8b, 0x0e, 0xfa, - 0xa7, 0x53, 0x1c, 0x93, 0xd7, 0x8f, 0xbd, 0x08, 0x3d, 0xa8, 0x2d, 0xb5, - 0x52, 0xad, 0xa6, 0xd1, 0xe5, 0x91, 0x01, 0xb9, 0x6e, 0xad, 0x9e, 0x40, - 0x9e, 0xd7, 0x46, 0x8b, 0xbd, 0x52, 0xd9, 0xe1, 0xb7, 0x33, 0xd2, 0x6f, - 0x3b, 0x26, 0x9e, 0xf5, 0xb4, 0xbe, 0x95, 0x97, 0x67, 0xa9, 0xe8, 0x76, - 0xa2, 0x42, 0xd9, 0x0d, 0x99, 0x70, 0x7f, 0x40, 0x77, 0x04, 0x62, 0xa0, - 0x36, 0xa0, 0x1f, 0x12, 0xff, 0xed, 0x7d, 0x51, 0x63, 0x39, 0xbe, 0x8e, - 0xd8, 0xc2, 0xb1, 0x52, 0x91, 0x7a, 0xb7, 0xb0, 0xf4, 0xa6, 0xce, 0xfe, - 0xe5, 0x7b, 0xf5, 0xdd, 0xc1, 0x98, 0xfd, 0x3b, 0x8f, 0xdb, 0xe9, 0xfb, - 0xb5, 0x9d, 0xb4, 0x58, 0xe3, 0xf7, 0xad, 0xb4, 0x50, 0x1b, 0xb8, 0xf2, - 0x90, 0xe8, 0xa5, 0xd5, 0xeb, 0x6e, 0xd6, 0x3f, 0x2f, 0x20, 0x93, 0x89, - 0x0f, 0xe9, 0xdd, 0x91, 0x2e, 0x7a, 0xf5, 0x5e, 0xa3, 0x7a, 0xbf, 0x80, - 0x3e, 0x8e, 0xc4, 0xd9, 0xce, 0xd0, 0xe7, 0x79, 0xe3, 0x4a, 0x5a, 0xb0, - 0x9e, 0xbd, 0x0c, 0xfd, 0x32, 0x4e, 0xfa, 0x3a, 0xc9, 0xb4, 0x99, 0x2e, - 0xce, 0xc7, 0x7c, 0x05, 0x34, 0xf1, 0xae, 0x3e, 0x00, 0x5a, 0xaf, 0x48, - 0x59, 0x1c, 0xb6, 0x8c, 0x2b, 0x08, 0x51, 0xde, 0x65, 0x73, 0x20, 0x23, - 0xc4, 0x6e, 0xaa, 0xa5, 0x6e, 0xd6, 0xbf, 0x8b, 0x78, 0x80, 0x9a, 0xab, - 0xb4, 0x4e, 0xeb, 0xc7, 0x2e, 0x9a, 0xac, 0x8b, 0x6c, 0xc3, 0x3f, 0x44, - 0x4e, 0xaa, 0xd3, 0x53, 0x75, 0xf6, 0x5d, 0x4c, 0x8b, 0xeb, 0x82, 0x7d, - 0xfa, 0xdd, 0xe0, 0xc1, 0x19, 0xc6, 0x3b, 0xcc, 0xab, 0x9f, 0xe5, 0x73, - 0x6b, 0x61, 0xdc, 0x4c, 0x9a, 0x37, 0xb3, 0x45, 0x46, 0x03, 0xfa, 0x5e, - 0xc1, 0xeb, 0xbd, 0x8b, 0x75, 0xdf, 0x01, 0xaf, 0x03, 0xc0, 0x45, 0x0c, - 0x4d, 0x35, 0xaf, 0xf1, 0x9a, 0x5c, 0xe3, 0x54, 0x1d, 0x39, 0xe0, 0xc6, - 0x1a, 0x98, 0xab, 0x0b, 0xec, 0xf3, 0x57, 0x65, 0xfe, 0xac, 0x22, 0xff, - 0xb9, 0x3c, 0xf2, 0x4c, 0x90, 0x5f, 0x3c, 0x07, 0x59, 0xc7, 0xe8, 0xb5, - 0x59, 0xae, 0x2f, 0x0f, 0x51, 0x39, 0xb1, 0x7e, 0x6c, 0xca, 0x44, 0x4d, - 0x8f, 0x38, 0x50, 0xde, 0x37, 0xe0, 0xeb, 0x55, 0x3f, 0xe3, 0x3c, 0x27, - 0xcf, 0xa4, 0x2c, 0x5a, 0xe9, 0x8b, 0x5a, 0x1a, 0xf8, 0x3c, 0x77, 0x29, - 0x38, 0xcf, 0x6f, 0x83, 0x1f, 0xf4, 0xeb, 0x3d, 0x81, 0xff, 0x4b, 0x40, - 0x57, 0x87, 0xf4, 0xc3, 0x14, 0x0b, 0xfc, 0x5f, 0x82, 0x5e, 0x3d, 0xad, - 0x42, 0x87, 0x58, 0x7f, 0xfa, 0xbb, 0x37, 0xf5, 0x87, 0xdf, 0xad, 0x1f, - 0x73, 0xc0, 0x63, 0x7e, 0xae, 0x95, 0x0a, 0xd5, 0x18, 0x4d, 0x65, 0x91, - 0x73, 0x23, 0xfe, 0xe4, 0xa1, 0x4b, 0x85, 0x1a, 0xeb, 0x72, 0x29, 0xd0, - 0xe5, 0x78, 0x40, 0xfb, 0x6f, 0xa0, 0xcb, 0x46, 0x7a, 0x55, 0x70, 0x7d, - 0xd5, 0x27, 0x6b, 0x64, 0x15, 0xf6, 0x55, 0xac, 0x70, 0x2c, 0x62, 0xdb, - 0xa2, 0xe3, 0xcc, 0x7f, 0xb1, 0x32, 0x2a, 0x8a, 0x8d, 0xac, 0x28, 0xba, - 0xcc, 0xdf, 0x3e, 0xf0, 0xad, 0xc8, 0x3a, 0x78, 0xa1, 0xf1, 0xae, 0xb7, - 0xb0, 0x6f, 0x07, 0xfa, 0xd0, 0xfd, 0x71, 0x3e, 0xdf, 0xeb, 0x99, 0xaf, - 0xb4, 0x2d, 0x58, 0xde, 0x49, 0x5a, 0x1e, 0x7c, 0xa9, 0x8b, 0x73, 0xb4, - 0xb3, 0x83, 0x4c, 0x1f, 0x7c, 0x24, 0x93, 0xb4, 0xe8, 0xf2, 0x1a, 0x2c, - 0x17, 0xf8, 0xba, 0x39, 0x9d, 0x1e, 0x96, 0xe7, 0xc7, 0xba, 0xc5, 0xf7, - 0x4d, 0x2a, 0xe5, 0x13, 0x03, 0xfa, 0x43, 0x64, 0x5c, 0x59, 0x53, 0x8d, - 0xea, 0x24, 0xe2, 0xea, 0xc2, 0xbc, 0x4a, 0x7b, 0x64, 0x1d, 0xc6, 0x67, - 0x64, 0x9c, 0x84, 0x35, 0x06, 0x7b, 0xff, 0x8d, 0xa6, 0xbd, 0x77, 0xd2, - 0xc5, 0xd3, 0x9f, 0x85, 0xdd, 0xb3, 0x5c, 0xb5, 0xf4, 0x11, 0xe4, 0x19, - 0x73, 0x04, 0xf9, 0x22, 0x7f, 0xb6, 0x53, 0xe1, 0xb9, 0xb0, 0xbc, 0x77, - 0x49, 0xf9, 0x0b, 0x29, 0xff, 0x1b, 0xa8, 0xdc, 0xeb, 0xdb, 0x38, 0xbf, - 0x13, 0xa0, 0xe1, 0xbf, 0xe3, 0xf1, 0x67, 0x90, 0x1f, 0xf1, 0xbb, 0x9a, - 0x8f, 0x47, 0x3d, 0x4c, 0x07, 0xef, 0xfe, 0x10, 0x6b, 0xb2, 0x8c, 0xc3, - 0xf9, 0x0e, 0xf2, 0x6d, 0x29, 0x94, 0x3b, 0x12, 0x8c, 0x7a, 0x92, 0x7e, - 0xad, 0x9e, 0xa2, 0x89, 0x7a, 0x3f, 0x15, 0xea, 0x69, 0x9c, 0xc1, 0x13, - 0xdd, 0xbc, 0xb7, 0xfc, 0x12, 0xf6, 0x23, 0x98, 0xd7, 0x1a, 0x1d, 0x71, - 0x43, 0x7e, 0xe2, 0x01, 0x7f, 0x5a, 0x30, 0x8e, 0x05, 0x3c, 0x34, 0xd3, - 0x8b, 0x83, 0x96, 0x0d, 0x3a, 0x67, 0x02, 0x3a, 0xec, 0x47, 0xc0, 0xeb, - 0x44, 0x8a, 0x96, 0x5c, 0xe6, 0x63, 0x27, 0x95, 0x93, 0xdc, 0x7f, 0x0e, - 0x7a, 0xc6, 0x74, 0x76, 0x70, 0x7e, 0xb3, 0x45, 0xc6, 0x47, 0xeb, 0x25, - 0xc8, 0x98, 0xe5, 0xcb, 0x70, 0x71, 0x5a, 0xf8, 0x25, 0x3e, 0xbf, 0x21, - 0xe4, 0xf8, 0xac, 0x0b, 0x3b, 0x03, 0xbd, 0xf2, 0xd7, 0x2c, 0xcc, 0x75, - 0xe2, 0xac, 0x78, 0xdd, 0x76, 0xba, 0x07, 0x76, 0x9f, 0xaf, 0xf1, 0xfa, - 0x13, 0xd0, 0xa3, 0x1f, 0xcb, 0xf5, 0x0b, 0x4b, 0xbd, 0x01, 0x3e, 0xe3, - 0x76, 0x6e, 0xc3, 0x6d, 0xa5, 0x03, 0x55, 0xfd, 0x63, 0xf0, 0x7f, 0x13, - 0xf8, 0x82, 0xce, 0x64, 0x19, 0x9f, 0xe9, 0x00, 0xae, 0x96, 0xfc, 0x04, - 0x3a, 0x09, 0x59, 0xef, 0xe7, 0x6b, 0xad, 0x94, 0xaf, 0x86, 0xb4, 0x98, - 0xce, 0x87, 0xa8, 0x87, 0xbf, 0x2c, 0x69, 0x4d, 0x49, 0x5a, 0x78, 0x5f, - 0x63, 0x9f, 0x73, 0x3b, 0xf0, 0xe3, 0xec, 0xff, 0x69, 0x21, 0xd1, 0x41, - 0x0b, 0xb2, 0xa6, 0x6f, 0xf7, 0x7d, 0x4d, 0xa2, 0x0d, 0xef, 0x77, 0xc1, - 0xe6, 0x87, 0x90, 0x5b, 0x74, 0x62, 0x2e, 0xbd, 0x6d, 0x6e, 0x3b, 0xff, - 0xb1, 0x6d, 0xfc, 0xeb, 0x80, 0xeb, 0xc1, 0x9a, 0x3e, 0x5c, 0x01, 0x70, - 0xd3, 0x73, 0x90, 0xb3, 0xc5, 0x7e, 0x85, 0xe3, 0xe4, 0x75, 0x92, 0x97, - 0xe9, 0x25, 0x05, 0x70, 0xbd, 0xc0, 0x0d, 0xc7, 0xbe, 0x1c, 0xaa, 0xa0, - 0xf3, 0xcd, 0x9a, 0xbc, 0xbb, 0xc0, 0x19, 0xf4, 0x24, 0x78, 0xef, 0xe5, - 0xda, 0xa7, 0xc9, 0xec, 0xba, 0x26, 0x79, 0xb1, 0xac, 0x98, 0x5f, 0xe6, - 0x15, 0x7a, 0x8a, 0x38, 0xe4, 0x58, 0xa8, 0x0b, 0x13, 0x2a, 0x15, 0xb2, - 0x3a, 0xf2, 0x73, 0xbe, 0xb7, 0x65, 0xbb, 0xd4, 0xf9, 0xae, 0x34, 0x26, - 0x4c, 0x8e, 0xb5, 0x9a, 0xdc, 0xfb, 0x91, 0x25, 0xbe, 0xbb, 0x4d, 0xf3, - 0x5d, 0x5f, 0x86, 0xb0, 0xf7, 0x07, 0x97, 0x4c, 0x7a, 0xa4, 0x9e, 0xa1, - 0x87, 0xea, 0x86, 0x7e, 0x3f, 0x7c, 0x40, 0x71, 0xe3, 0x4e, 0xf7, 0x73, - 0x09, 0xae, 0x45, 0x34, 0xe4, 0x81, 0x2d, 0xa6, 0x9f, 0x17, 0x94, 0xb9, - 0x66, 0x9b, 0x33, 0xf8, 0x1e, 0x47, 0xaf, 0xd1, 0xf6, 0xdc, 0xe1, 0xff, - 0x32, 0x6f, 0xe0, 0xf5, 0xd9, 0x5f, 0x23, 0x4f, 0x70, 0x91, 0x27, 0xb8, - 0xc8, 0x13, 0x5c, 0xe4, 0x09, 0x2e, 0xf2, 0x04, 0x17, 0x79, 0x82, 0x8b, - 0x3c, 0xc1, 0x45, 0x9e, 0x80, 0xd8, 0xed, 0xd7, 0x0b, 0x63, 0xc8, 0x7f, - 0xe1, 0xbf, 0xdc, 0xcf, 0x43, 0x4e, 0x7c, 0xdf, 0xc9, 0x31, 0x87, 0x63, - 0x33, 0xcf, 0xad, 0xee, 0x70, 0xf8, 0xdc, 0xa4, 0xef, 0xbb, 0x13, 0x73, - 0xe3, 0x41, 0x3e, 0xc2, 0x30, 0x61, 0xec, 0x66, 0x38, 0x1a, 0x75, 0x2c, - 0x05, 0x36, 0xc6, 0xf9, 0x8a, 0x1f, 0xb3, 0xfc, 0x5c, 0xf9, 0x75, 0xe4, - 0x2c, 0x69, 0xe4, 0x2c, 0xfd, 0xc8, 0x4f, 0xf8, 0x8e, 0x3b, 0xbc, 0x63, - 0xb2, 0x95, 0xc3, 0xee, 0x98, 0x72, 0xb7, 0xcb, 0xb9, 0xb4, 0x99, 0x2e, - 0x0a, 0x31, 0xd7, 0x43, 0x1e, 0xe5, 0x47, 0xbe, 0x86, 0xbc, 0xf5, 0x9b, - 0xf2, 0x3e, 0x6d, 0x7c, 0x90, 0xcf, 0x7c, 0xe5, 0x1a, 0xb9, 0x6b, 0x28, - 0x5f, 0xff, 0x1e, 0x50, 0x2c, 0xb0, 0xfc, 0x88, 0xba, 0xcf, 0x43, 0xe0, - 0xe7, 0x63, 0x94, 0x58, 0xde, 0x89, 0x39, 0x9d, 0x7a, 0xe4, 0x5d, 0x12, - 0x8e, 0xf2, 0xbc, 0xd6, 0x43, 0xed, 0x26, 0x89, 0xf3, 0x7c, 0xe3, 0xc0, - 0x74, 0xd9, 0xbf, 0x5e, 0x3a, 0x96, 0xaf, 0x5d, 0x92, 0x3a, 0x75, 0xb8, - 0x5e, 0x40, 0x7d, 0xd4, 0x07, 0x18, 0x0d, 0xb5, 0x55, 0x48, 0x9b, 0x69, - 0x5e, 0x4d, 0xc8, 0x9a, 0xe7, 0xfc, 0xc6, 0x79, 0xe2, 0xac, 0x79, 0x9d, - 0x4b, 0xc7, 0xca, 0x55, 0x23, 0xc5, 0xb5, 0xb2, 0xad, 0x5f, 0x3a, 0x76, - 0x02, 0x34, 0x16, 0x91, 0x1b, 0xa8, 0x72, 0xed, 0x4b, 0xc7, 0xa6, 0xab, - 0xfe, 0x7d, 0x96, 0xcf, 0x03, 0xe2, 0x60, 0xb6, 0x9d, 0xd4, 0x05, 0xff, - 0x5e, 0x4b, 0x48, 0x5c, 0xc6, 0x63, 0x7c, 0x0d, 0x78, 0x7c, 0x6e, 0x19, - 0xe0, 0xf2, 0xd9, 0x31, 0x0f, 0x97, 0x8e, 0x95, 0x6a, 0xcd, 0x3c, 0x30, - 0x1d, 0xa6, 0x1b, 0xee, 0x87, 0xf7, 0x92, 0x20, 0xb1, 0xec, 0x79, 0xc5, - 0x91, 0xfe, 0x20, 0xef, 0x3a, 0x81, 0xfc, 0x4e, 0x93, 0x7a, 0xee, 0x8f, - 0xff, 0x4c, 0xc6, 0xa9, 0xb4, 0xe0, 0x79, 0x7e, 0xe2, 0x5d, 0xf6, 0x3b, - 0x98, 0xc3, 0x78, 0x31, 0x84, 0x15, 0x01, 0x6c, 0x47, 0x93, 0x3c, 0x5b, - 0x82, 0xf5, 0x98, 0x27, 0xde, 0xe7, 0xcf, 0xb1, 0x7f, 0x79, 0x07, 0xc7, - 0xf9, 0x18, 0xd6, 0xc5, 0x59, 0xba, 0xff, 0x5b, 0xd9, 0x37, 0xef, 0x89, - 0x65, 0xaa, 0x01, 0x87, 0xe1, 0x99, 0x46, 0x88, 0x83, 0x17, 0xe7, 0x7d, - 0x3c, 0xb1, 0x71, 0xff, 0xf7, 0x49, 0xeb, 0x36, 0xf3, 0x1a, 0xae, 0x1f, - 0xd2, 0xc9, 0xf8, 0xe7, 0xb6, 0x81, 0x2f, 0xff, 0x4f, 0x31, 0x3c, 0xa1, - 0x8b, 0x1f, 0xb9, 0x47, 0xcd, 0x34, 0xd5, 0xa1, 0xe1, 0xfd, 0x05, 0xdf, - 0x07, 0x70, 0x7d, 0xcf, 0xdf, 0x1a, 0x9a, 0x6b, 0xc5, 0x67, 0x83, 0x58, - 0xd6, 0x47, 0xb6, 0xc6, 0x75, 0xc3, 0x85, 0x60, 0xbc, 0x0b, 0xb1, 0x8d, - 0xc7, 0x0d, 0xc8, 0x17, 0xba, 0x6c, 0xb5, 0x07, 0x75, 0x4b, 0xc2, 0xff, - 0x26, 0x94, 0x61, 0x3b, 0xe2, 0xba, 0xaf, 0x2d, 0x98, 0x0b, 0xed, 0x88, - 0xfd, 0xb0, 0x16, 0xcc, 0xb1, 0xbf, 0x15, 0xa8, 0x5d, 0xb8, 0x0f, 0x3a, - 0x8b, 0xcd, 0xb6, 0x14, 0x3e, 0x13, 0x74, 0x6e, 0x3e, 0xf4, 0x5b, 0xf0, - 0x29, 0x83, 0x5a, 0xe0, 0xfb, 0xe3, 0xf0, 0x7d, 0x9d, 0x74, 0x00, 0x3e, - 0xeb, 0x20, 0x7c, 0xd6, 0x21, 0xd4, 0x8b, 0x63, 0x4b, 0xcd, 0xf7, 0xbc, - 0x5c, 0xa3, 0x76, 0x2a, 0x47, 0xe4, 0xf9, 0x97, 0x3c, 0xd5, 0xfc, 0x10, - 0x3a, 0xc0, 0x75, 0x57, 0xa8, 0x13, 0xf0, 0xb7, 0x56, 0x02, 0x3a, 0xb1, - 0xfd, 0x3e, 0x39, 0x03, 0xdb, 0x68, 0xb7, 0x85, 0xcc, 0xe5, 0x7c, 0xd9, - 0x97, 0x6b, 0xbe, 0xec, 0xe1, 0x97, 0x41, 0x5f, 0xa3, 0x52, 0x5d, 0xa7, - 0x12, 0xd6, 0x2d, 0x61, 0xdd, 0x12, 0xea, 0xbc, 0xe9, 0x7a, 0xf3, 0x77, - 0xaf, 0x8e, 0x80, 0x77, 0xc6, 0x0d, 0xfb, 0x7a, 0xd3, 0xfe, 0xc3, 0xe7, - 0x49, 0xc8, 0xff, 0x11, 0xc8, 0xff, 0x28, 0xea, 0x9b, 0xdf, 0x47, 0x7d, - 0xf3, 0x7b, 0xa8, 0x6f, 0x8e, 0xa0, 0xbe, 0x99, 0x44, 0x7d, 0xf3, 0x65, - 0xf8, 0x8f, 0xfb, 0xe0, 0x3f, 0x26, 0xe0, 0x3f, 0xc6, 0xe5, 0xdd, 0xd3, - 0x61, 0x77, 0xfb, 0x9d, 0x4a, 0xb8, 0x16, 0xb7, 0x9f, 0x12, 0x99, 0x25, - 0xec, 0x69, 0x8c, 0x6a, 0x0d, 0xae, 0x6f, 0x2c, 0x72, 0x46, 0xb9, 0xbe, - 0x99, 0x50, 0x26, 0x91, 0xbf, 0xdf, 0x3f, 0xcc, 0x75, 0x4f, 0x42, 0xc9, - 0xcb, 0xba, 0xc7, 0xb8, 0xe0, 0x20, 0x75, 0x43, 0xee, 0x87, 0x3d, 0x1b, - 0xe7, 0xf2, 0xe0, 0xc5, 0xcf, 0xf9, 0xba, 0x03, 0xbf, 0x17, 0xa7, 0xc5, - 0x59, 0xd4, 0x0c, 0xee, 0x3f, 0x28, 0x45, 0xe9, 0x1b, 0x75, 0x8c, 0x51, - 0x2b, 0xbb, 0xaf, 0x06, 0xe3, 0x11, 0x9a, 0x9a, 0x47, 0x6d, 0x7b, 0xfa, - 0x6f, 0x95, 0xbc, 0x1c, 0x5b, 0x18, 0x23, 0xdf, 0x3d, 0xfd, 0xd7, 0xc1, - 0xb8, 0x14, 0xe8, 0x43, 0xc0, 0xab, 0x6e, 0xe1, 0xd9, 0x15, 0xe4, 0x1c, - 0x2f, 0xf6, 0x6c, 0xfd, 0x3f, 0xef, 0xb8, 0xb5, 0x28, 0x64, 0x1e, 0xdf, - 0xe5, 0xd7, 0x67, 0xcd, 0xf3, 0x9d, 0x4d, 0xf3, 0xba, 0xfc, 0x0e, 0x5b, - 0xac, 0xb4, 0xbd, 0x07, 0x0f, 0x4c, 0x4b, 0x83, 0x46, 0xd5, 0xa6, 0x0f, - 0x3d, 0xfe, 0x5e, 0xe8, 0x88, 0x76, 0xf9, 0x0d, 0xcf, 0x91, 0xf7, 0x7a, - 0xb0, 0xf3, 0x91, 0x27, 0x77, 0xf9, 0xbe, 0x80, 0xfb, 0x49, 0xc5, 0xf7, - 0xef, 0x8f, 0x83, 0x0e, 0x64, 0xed, 0x36, 0xd7, 0x70, 0x7a, 0x70, 0x97, - 0xa2, 0x1f, 0x9f, 0xe1, 0xb3, 0x96, 0xb4, 0xb9, 0xd6, 0xe3, 0xba, 0x2f, - 0x8c, 0x01, 0x21, 0xad, 0xff, 0x48, 0xfa, 0x7c, 0xdf, 0x87, 0x9a, 0x8e, - 0x61, 0xc2, 0x71, 0x73, 0xfd, 0x17, 0x0f, 0xee, 0xe1, 0x98, 0xd7, 0x58, - 0xc0, 0xab, 0x16, 0xd0, 0xfb, 0x77, 0xcf, 0xf7, 0x3d, 0x8c, 0xaf, 0x37, - 0xe1, 0x5f, 0x40, 0xae, 0xc7, 0x77, 0x26, 0xbb, 0xe5, 0x77, 0xc9, 0x77, - 0x66, 0x3b, 0xe8, 0xed, 0x53, 0xc8, 0x59, 0x2d, 0x23, 0x73, 0x09, 0xb5, - 0xc7, 0x32, 0xdb, 0xc9, 0x08, 0xf3, 0x39, 0x90, 0x9e, 0xa6, 0x9b, 0x7b, - 0xfc, 0x5c, 0xfc, 0xab, 0xca, 0x47, 0xf9, 0x16, 0xc1, 0x3a, 0x3f, 0x6a, - 0x5a, 0x27, 0xdd, 0xb4, 0xce, 0x0a, 0xdb, 0x6c, 0xed, 0x4b, 0xd8, 0x73, - 0x69, 0xf7, 0xcd, 0x7a, 0x32, 0xa8, 0xcb, 0x1e, 0x1e, 0x69, 0xa3, 0x6a, - 0xaf, 0xb1, 0xf2, 0x1a, 0xf2, 0xf5, 0xe2, 0x08, 0xe6, 0x92, 0x03, 0x78, - 0xc7, 0xf3, 0x46, 0x8d, 0x84, 0xb1, 0x52, 0xa3, 0xcf, 0x01, 0xdf, 0x28, - 0x11, 0xf1, 0x3c, 0xf7, 0x25, 0x6f, 0xb5, 0xc0, 0x07, 0xa4, 0xd6, 0xb0, - 0xe7, 0x49, 0xd4, 0x5f, 0x47, 0x37, 0xea, 0x61, 0x5e, 0xe7, 0x56, 0x65, - 0x4d, 0xe6, 0xc6, 0xfb, 0x95, 0x52, 0xd2, 0xdf, 0xe3, 0xef, 0xc2, 0x5f, - 0xa8, 0x82, 0x71, 0xdf, 0x01, 0x6d, 0x85, 0x16, 0x4e, 0xa9, 0xf2, 0x0e, - 0xb6, 0x38, 0xc2, 0x67, 0xcd, 0xcf, 0x8f, 0x93, 0x5d, 0xb8, 0xa7, 0x3f, - 0x0d, 0xf6, 0x34, 0x16, 0xd4, 0xd3, 0xe1, 0x9e, 0x62, 0xf4, 0xe6, 0xac, - 0x0e, 0xdc, 0x9b, 0x20, 0x8f, 0x02, 0x2d, 0x35, 0xd2, 0x9f, 0x42, 0xa7, - 0xd2, 0x24, 0x1b, 0x6d, 0xdb, 0x19, 0x96, 0x36, 0x6b, 0xf8, 0xf1, 0x14, - 0xec, 0xf0, 0x78, 0x4f, 0x78, 0x37, 0xac, 0x9a, 0x1e, 0xd7, 0x3d, 0x68, - 0x3c, 0xdf, 0x0f, 0x5b, 0x4c, 0xc3, 0x3e, 0x39, 0x67, 0x2a, 0x70, 0xad, - 0xc2, 0xf6, 0xa4, 0x3b, 0xaa, 0xa1, 0x4f, 0x50, 0x06, 0xf5, 0x0e, 0xef, - 0x3f, 0x47, 0x8b, 0x8d, 0x90, 0x87, 0x2c, 0xec, 0x71, 0x14, 0xbf, 0x61, - 0xbc, 0xb3, 0xf0, 0xe3, 0x5a, 0x69, 0x85, 0x1e, 0x95, 0xb9, 0x38, 0x72, - 0xed, 0x41, 0xe6, 0xef, 0x4e, 0xc0, 0xb3, 0x3e, 0xb3, 0x9e, 0xde, 0x49, - 0x4e, 0x2f, 0xfb, 0x8a, 0x14, 0x68, 0x03, 0xc7, 0x5d, 0x87, 0xad, 0xf7, - 0xe3, 0x69, 0xe8, 0x45, 0x96, 0xad, 0xa4, 0xef, 0x79, 0x6a, 0x96, 0xbf, - 0x51, 0x5c, 0x08, 0xc6, 0x03, 0xfa, 0x3d, 0xac, 0x7b, 0xa9, 0x1b, 0x68, - 0x65, 0x3e, 0x8c, 0x83, 0x67, 0x60, 0x83, 0x7c, 0x67, 0x3b, 0x06, 0xb9, - 0xf0, 0x58, 0x09, 0xe2, 0x21, 0xe6, 0x17, 0x91, 0x94, 0xb4, 0xe7, 0x68, - 0x19, 0xf5, 0x3f, 0xf5, 0xf2, 0x13, 0xf9, 0xae, 0xbb, 0x33, 0xd0, 0xf7, - 0xad, 0xf8, 0xaa, 0xc9, 0xfd, 0x31, 0xf0, 0xa7, 0x35, 0xe1, 0x33, 0x8e, - 0x5f, 0x9f, 0xac, 0x11, 0xe2, 0x71, 0xca, 0xfb, 0x82, 0xc8, 0x3d, 0x4d, - 0xbf, 0x23, 0xf7, 0x54, 0xa7, 0x23, 0xf3, 0xa8, 0x6d, 0xb3, 0x03, 0x99, - 0x45, 0x32, 0x32, 0x27, 0x68, 0x48, 0x3f, 0x40, 0xaa, 0xfc, 0xd6, 0x97, - 0x16, 0xde, 0x17, 0x5a, 0x72, 0x9e, 0x77, 0x06, 0xbc, 0xbf, 0x28, 0xd7, - 0x79, 0x1a, 0xfc, 0x43, 0x56, 0xb2, 0x26, 0x61, 0x5e, 0xf1, 0x4c, 0x32, - 0xbf, 0x15, 0x3a, 0xd2, 0xf8, 0x61, 0x70, 0x36, 0x8f, 0x90, 0xe3, 0xbe, - 0xa5, 0x3a, 0x66, 0x05, 0xb0, 0xdf, 0x09, 0x78, 0xcb, 0x81, 0x5f, 0xac, - 0xdf, 0x58, 0x4f, 0xb2, 0x6f, 0xe0, 0x33, 0x77, 0x90, 0x35, 0x3a, 0x23, - 0xc8, 0xa3, 0x92, 0xd7, 0xf2, 0x03, 0x09, 0xda, 0xea, 0x07, 0x18, 0x2f, - 0xf1, 0x31, 0xba, 0xc2, 0x7c, 0x94, 0xa4, 0xff, 0x94, 0x71, 0x4b, 0xd2, - 0x53, 0xb7, 0xf9, 0x82, 0x6f, 0xc9, 0xe7, 0xaa, 0xca, 0xbe, 0x89, 0xe3, - 0x1f, 0xeb, 0x70, 0x27, 0xfc, 0x1f, 0x74, 0x10, 0x76, 0x9c, 0x9f, 0xe7, - 0xfb, 0x89, 0x41, 0xbe, 0x57, 0x3a, 0x57, 0xc0, 0xd9, 0x2e, 0xf0, 0xf7, - 0xc7, 0xa4, 0x5f, 0x63, 0xfa, 0xf5, 0x57, 0x9a, 0x7d, 0x21, 0xda, 0x92, - 0xf4, 0x93, 0x05, 0xf9, 0xbd, 0x31, 0x01, 0x18, 0x8f, 0x7d, 0x67, 0xd3, - 0xdf, 0x58, 0xbc, 0x6c, 0xfb, 0x7f, 0x63, 0x11, 0x7c, 0xfb, 0xad, 0xf9, - 0x79, 0xc4, 0x83, 0x75, 0x8d, 0x26, 0xeb, 0xe1, 0xdf, 0x5c, 0xf0, 0x39, - 0xc0, 0x37, 0xd7, 0xc3, 0xdc, 0xc1, 0x93, 0xf1, 0xa5, 0xbc, 0xe5, 0x2c, - 0x97, 0x82, 0x9c, 0x88, 0x6b, 0x00, 0x96, 0x21, 0xc6, 0x8b, 0xfe, 0xf9, - 0x2d, 0x88, 0x3d, 0x38, 0x3f, 0xc8, 0x1c, 0x7c, 0xbd, 0x39, 0xeb, 0xd7, - 0xb9, 0x65, 0xf6, 0x8b, 0xfd, 0x61, 0xdd, 0xbb, 0x9b, 0xca, 0x13, 0xfc, - 0x3e, 0x46, 0x6f, 0xcc, 0xc6, 0xe4, 0xfb, 0x22, 0xc5, 0x82, 0xf7, 0x3c, - 0x4e, 0x50, 0x51, 0xbe, 0xaf, 0x05, 0xf4, 0x50, 0xa7, 0xdd, 0x17, 0x8e, - 0x35, 0xe5, 0x48, 0xc3, 0xc7, 0x9b, 0x6a, 0xd4, 0xe8, 0xd1, 0xc6, 0x2a, - 0xf6, 0xaf, 0x50, 0x7e, 0xbc, 0x44, 0x37, 0x98, 0xba, 0x8c, 0xfb, 0x4e, - 0x82, 0x75, 0x8c, 0xf5, 0x6b, 0x4c, 0xd6, 0x9d, 0x25, 0xe4, 0x0b, 0xc5, - 0x11, 0xfe, 0xc6, 0xf3, 0xde, 0x5d, 0xc5, 0x8a, 0xa1, 0xdb, 0xf4, 0x81, - 0xe7, 0x68, 0x3c, 0x26, 0x21, 0x72, 0xab, 0x77, 0x3d, 0x58, 0xbf, 0x78, - 0x97, 0xbf, 0x57, 0xbc, 0xaf, 0x33, 0xac, 0x2a, 0xbf, 0xcd, 0xfe, 0xe4, - 0x76, 0x8d, 0xd6, 0x6e, 0xf7, 0xbc, 0xfb, 0x2d, 0x9d, 0x9c, 0xa0, 0x76, - 0xf5, 0xbf, 0xb9, 0xb7, 0xcb, 0x1c, 0xc4, 0x19, 0x49, 0x2b, 0x05, 0xd8, - 0xeb, 0xb2, 0x8b, 0x3a, 0x47, 0x18, 0xa3, 0xab, 0x42, 0x47, 0xcc, 0xe5, - 0x3b, 0x80, 0x3b, 0x7a, 0xf8, 0x7b, 0xf3, 0x8c, 0xc5, 0x30, 0x7d, 0xfe, - 0x5d, 0xd7, 0x2d, 0xf7, 0x49, 0x3f, 0x4b, 0x14, 0xc4, 0x9e, 0x5b, 0x9a, - 0x6d, 0xa2, 0x39, 0xb7, 0x64, 0x5b, 0xa0, 0x49, 0x0d, 0xbc, 0x94, 0x2b, - 0x61, 0x9e, 0xc6, 0x7f, 0x4b, 0xb0, 0x7a, 0xd7, 0x37, 0xc0, 0xe7, 0x34, - 0xf8, 0xe4, 0x7d, 0x4c, 0xd7, 0x43, 0x9d, 0x0b, 0x6b, 0x05, 0xee, 0x23, - 0xe6, 0xbb, 0x88, 0xf9, 0x2e, 0x62, 0xbe, 0x8b, 0x98, 0xef, 0x22, 0xe6, - 0xbb, 0x88, 0xf9, 0x2e, 0x62, 0xbe, 0x8b, 0x98, 0xef, 0x8e, 0x07, 0x79, - 0xda, 0x63, 0x1b, 0x79, 0xda, 0x4a, 0x83, 0xbf, 0x43, 0x49, 0x5e, 0x4a, - 0x25, 0xf2, 0xf3, 0x5c, 0x12, 0x9c, 0xd3, 0x84, 0x79, 0xee, 0xc7, 0x7f, - 0x13, 0xf1, 0xf1, 0x38, 0xc7, 0x63, 0xbc, 0x92, 0x22, 0x4c, 0xc6, 0xf3, - 0xf3, 0x3c, 0xae, 0xad, 0xb6, 0xe2, 0x20, 0x5f, 0xcb, 0xb1, 0x3f, 0x63, - 0xbb, 0x48, 0xfa, 0xf5, 0x62, 0xee, 0xf5, 0x2f, 0xa1, 0x76, 0x3c, 0x5e, - 0xac, 0xcb, 0x18, 0x8c, 0xf1, 0x7b, 0x18, 0x6b, 0xac, 0x73, 0xfc, 0xee, - 0x5e, 0xae, 0x27, 0x8a, 0xf5, 0x14, 0x95, 0x16, 0xc3, 0xfc, 0x07, 0x78, - 0xee, 0x90, 0x52, 0xa8, 0xf2, 0xd9, 0x0a, 0x9a, 0x4e, 0x42, 0x28, 0x66, - 0x73, 0x5e, 0x77, 0x49, 0xd6, 0x48, 0xfe, 0xdf, 0x05, 0x0d, 0x83, 0xb7, - 0xf0, 0x1e, 0x97, 0x48, 0x9d, 0x4d, 0xca, 0xbf, 0x31, 0x48, 0x98, 0x83, - 0xf2, 0x6f, 0x1d, 0xba, 0xb1, 0x8e, 0x98, 0xdd, 0x13, 0xfe, 0xed, 0x06, - 0xd7, 0x5d, 0xf6, 0xe6, 0xfd, 0x2b, 0xef, 0x23, 0x09, 0x7b, 0xbd, 0xa7, - 0x0f, 0x7b, 0xc3, 0xb9, 0x5e, 0xd9, 0x25, 0xf3, 0x6e, 0xf8, 0xce, 0x33, - 0x83, 0x37, 0xf5, 0x52, 0xe7, 0x6e, 0x5a, 0x1e, 0xe4, 0x1a, 0xad, 0x0d, - 0xf4, 0x18, 0xd6, 0xc8, 0xd8, 0x62, 0x37, 0x9d, 0x9d, 0x87, 0x6f, 0x9d, - 0x37, 0x2c, 0xfe, 0xfb, 0x82, 0x85, 0xc1, 0x24, 0x7c, 0xf2, 0x78, 0x2f, - 0xc7, 0xe4, 0xc5, 0x06, 0xeb, 0x4a, 0x37, 0xf0, 0xfb, 0xa1, 0x8b, 0x3b, - 0x60, 0x43, 0x02, 0xeb, 0x87, 0xb4, 0xff, 0x53, 0xd2, 0xee, 0x36, 0xf3, - 0x7d, 0x52, 0x37, 0x84, 0xa1, 0xa7, 0x05, 0x78, 0xff, 0x48, 0x6d, 0x69, - 0x11, 0x7f, 0x2f, 0x9c, 0x76, 0x9b, 0xbf, 0x1b, 0x0e, 0x29, 0xc5, 0x2a, - 0xff, 0x8d, 0xc3, 0x20, 0xfd, 0x4f, 0xe1, 0x56, 0x17, 0xd3, 0xd6, 0x79, - 0x86, 0xdf, 0xcf, 0xe6, 0x2f, 0xc4, 0x81, 0x13, 0xe2, 0x80, 0x41, 0x54, - 0xf3, 0x31, 0x07, 0xe2, 0xca, 0x44, 0x3d, 0x20, 0x32, 0x59, 0x15, 0x52, - 0x2d, 0xdb, 0x50, 0xb7, 0x5d, 0x36, 0x77, 0xcb, 0xa6, 0x4c, 0xda, 0x22, - 0x06, 0x49, 0x9b, 0x6a, 0xd2, 0x2e, 0x76, 0x31, 0xed, 0x2e, 0x96, 0x81, - 0x34, 0xcd, 0xec, 0x1a, 0x56, 0x32, 0xa4, 0x5d, 0x4c, 0xae, 0x31, 0x04, - 0x88, 0x53, 0xab, 0x5b, 0x2f, 0x32, 0x4d, 0x53, 0x90, 0x57, 0x25, 0xdd, - 0x4d, 0x6f, 0x76, 0x3f, 0x55, 0x64, 0xad, 0x72, 0xd1, 0x25, 0x6a, 0xa7, - 0x6a, 0x7f, 0x17, 0x67, 0xcf, 0xf3, 0x9d, 0x63, 0x20, 0x6c, 0xd5, 0x90, - 0xac, 0xf3, 0x9d, 0xef, 0x7c, 0xff, 0xdf, 0xfb, 0x3e, 0xef, 0x2f, 0x53, - 0xa0, 0x2f, 0xc3, 0x8a, 0xa9, 0x4b, 0x65, 0xb6, 0xb1, 0x50, 0xa6, 0x1d, - 0x7e, 0x13, 0xbc, 0xdc, 0x23, 0x8b, 0xa0, 0xe3, 0xfc, 0x68, 0xab, 0xe7, - 0x6f, 0xed, 0xf4, 0x78, 0x38, 0xd2, 0xeb, 0xc9, 0x28, 0xad, 0x4b, 0xe6, - 0xb5, 0x3e, 0xdd, 0x7d, 0xe8, 0xdb, 0x0f, 0xb0, 0xa6, 0x10, 0xce, 0x61, - 0xb8, 0x57, 0xe3, 0x91, 0x8f, 0xef, 0x7d, 0x87, 0xde, 0x7b, 0x0f, 0xbd, - 0x9f, 0xfc, 0x1f, 0xed, 0x59, 0x3e, 0x4c, 0x0f, 0x5c, 0xa7, 0x19, 0xe7, - 0x2c, 0xf9, 0xc2, 0x84, 0x9a, 0x2b, 0x98, 0x09, 0xea, 0x02, 0x29, 0x71, - 0x54, 0xca, 0x6e, 0x03, 0xc6, 0xb5, 0xc9, 0xc2, 0x0a, 0x68, 0x1e, 0xfb, - 0x68, 0xb7, 0x18, 0x2f, 0x7f, 0xb6, 0x97, 0x3c, 0xd3, 0x81, 0x6b, 0xf0, - 0x59, 0x43, 0x21, 0xb4, 0x73, 0x5e, 0xb3, 0x63, 0xc6, 0x45, 0xed, 0xbf, - 0xa1, 0x0e, 0xe3, 0xa8, 0xbc, 0xce, 0xfd, 0x60, 0x9b, 0x16, 0x79, 0x60, - 0x25, 0x7b, 0xbc, 0x5c, 0x22, 0xd8, 0xbb, 0x2f, 0xf6, 0x52, 0xbf, 0x78, - 0xd5, 0xde, 0xab, 0x33, 0x76, 0x85, 0x79, 0x5a, 0x20, 0x9a, 0x97, 0x45, - 0xca, 0x55, 0x91, 0x9b, 0xf8, 0xfd, 0xb1, 0xea, 0xc5, 0x2f, 0x14, 0x6d, - 0xed, 0x49, 0xd9, 0x2e, 0x3d, 0x2b, 0x35, 0xc8, 0x9c, 0x2d, 0xdb, 0x71, - 0x1e, 0xda, 0x61, 0x7d, 0xe6, 0xaf, 0x17, 0x94, 0x44, 0xc6, 0x28, 0xd3, - 0xda, 0xe4, 0x67, 0x2b, 0xcc, 0xbb, 0x33, 0x8d, 0x87, 0xc2, 0xfc, 0xb7, - 0x90, 0x64, 0x82, 0x7e, 0xad, 0x97, 0xca, 0xb7, 0x45, 0x3e, 0xc1, 0xb7, - 0x4f, 0x56, 0x5e, 0xe9, 0xa5, 0xcf, 0xe5, 0xe3, 0x15, 0xbe, 0xfb, 0xf0, - 0xf4, 0x49, 0xc3, 0xf2, 0x43, 0x7f, 0x05, 0xf0, 0x18, 0x3c, 0x77, 0xee, - 0xf7, 0x47, 0x5c, 0x1b, 0xea, 0x68, 0xc3, 0xb6, 0x49, 0x7e, 0x18, 0x38, - 0xa8, 0x86, 0x74, 0xbe, 0x52, 0x23, 0xa8, 0x71, 0xd9, 0x5f, 0x61, 0x5e, - 0x9d, 0x71, 0x54, 0x63, 0x74, 0xf2, 0xf6, 0x82, 0xde, 0x0b, 0xca, 0xb9, - 0x8a, 0x4d, 0x5a, 0x35, 0x64, 0x0b, 0xbc, 0xb6, 0x59, 0xdf, 0xea, 0xe3, - 0x5d, 0x6d, 0xd7, 0x17, 0x7b, 0x5d, 0x1b, 0x8d, 0x75, 0xaf, 0xf7, 0xba, - 0x75, 0x61, 0xcf, 0xe6, 0xa2, 0x6d, 0x56, 0xc6, 0xde, 0x7e, 0x2c, 0xf5, - 0xd5, 0x9f, 0xca, 0x9d, 0xd2, 0x4f, 0xe4, 0xb7, 0xab, 0xe7, 0xa1, 0x73, - 0x98, 0xe5, 0x1c, 0xe4, 0xc9, 0xbb, 0x75, 0xc7, 0x79, 0xd7, 0x3e, 0x07, - 0xfb, 0xc0, 0x71, 0xfe, 0x64, 0xef, 0x48, 0x64, 0xfc, 0x7b, 0xd8, 0x73, - 0x16, 0x3c, 0x44, 0x2c, 0xcc, 0x80, 0xde, 0x52, 0x7d, 0xd2, 0x19, 0xd0, - 0x74, 0x32, 0x34, 0xde, 0x8a, 0x3d, 0xf8, 0x3c, 0x3d, 0x9c, 0x7b, 0x49, - 0xf7, 0x91, 0x66, 0x7c, 0xf5, 0x0a, 0xe6, 0x6f, 0x05, 0x5f, 0x1c, 0xc5, - 0x4f, 0xc9, 0xc3, 0x31, 0xac, 0x75, 0x8c, 0xb4, 0xd7, 0x2a, 0x91, 0x67, - 0xb0, 0x8f, 0x6c, 0x8b, 0x3c, 0x2a, 0xdc, 0xea, 0xa5, 0x3f, 0xef, 0x51, - 0x81, 0x65, 0xdf, 0x57, 0xbb, 0xc4, 0x91, 0x16, 0xc8, 0xef, 0x85, 0x09, - 0x57, 0x57, 0xfa, 0x83, 0x3a, 0x85, 0xf6, 0x56, 0xee, 0x7d, 0x45, 0xdd, - 0x2e, 0xe7, 0xb4, 0x42, 0x17, 0x9f, 0x82, 0x0e, 0x94, 0xac, 0x5f, 0x91, - 0xc6, 0x58, 0x00, 0x6d, 0xa8, 0xa3, 0x68, 0x2c, 0x91, 0x54, 0x81, 0xf9, - 0x5d, 0xcc, 0xb5, 0xc2, 0x1a, 0xcf, 0x11, 0x37, 0xb8, 0xc6, 0x36, 0xc6, - 0xe0, 0xbc, 0x3a, 0x0b, 0x34, 0xc2, 0x3a, 0xd2, 0x77, 0x02, 0x3c, 0x99, - 0xa0, 0xdc, 0xc4, 0x78, 0xa3, 0x18, 0x8f, 0xe5, 0x2e, 0x8c, 0x77, 0x45, - 0x92, 0x76, 0x73, 0xcc, 0x38, 0xda, 0x10, 0x67, 0xe2, 0xd0, 0x1f, 0x06, - 0x55, 0x7a, 0x25, 0x08, 0xf9, 0xdd, 0x2b, 0x69, 0xe3, 0xc8, 0x81, 0x3d, - 0xe6, 0xb4, 0x7d, 0xe0, 0xf3, 0x8d, 0x7a, 0x6b, 0xea, 0x3a, 0xb0, 0x26, - 0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x72, 0x65, 0x09, 0x38, 0xb5, 0xf4, 0x41, - 0xd2, 0xbe, 0x20, 0xa9, 0x20, 0xd7, 0xc4, 0xfa, 0x20, 0xd6, 0x4c, 0x3f, - 0xd6, 0x77, 0x81, 0x43, 0x47, 0xbc, 0x3a, 0xb6, 0x15, 0x5f, 0x12, 0x67, - 0xef, 0xda, 0xb5, 0xac, 0xfb, 0x8a, 0x24, 0x97, 0xb2, 0x32, 0xad, 0xfb, - 0xf1, 0x0c, 0x07, 0xb4, 0xee, 0x41, 0x5e, 0x8d, 0x9c, 0xc0, 0x59, 0xc6, - 0xf6, 0x6d, 0xe0, 0xf0, 0x09, 0x72, 0x91, 0xd1, 0xe7, 0xf2, 0x2c, 0xbe, - 0x9d, 0xe0, 0x1d, 0xb5, 0x49, 0xe4, 0x5b, 0x90, 0x91, 0x85, 0x66, 0x7d, - 0x40, 0x3e, 0x2d, 0xf4, 0xf4, 0x31, 0xce, 0xf2, 0xd7, 0x82, 0x21, 0x1f, - 0x17, 0x74, 0x2c, 0x74, 0xc6, 0x2f, 0xe6, 0x65, 0xd7, 0x3e, 0x1f, 0x9e, - 0x59, 0x50, 0xfc, 0x3e, 0x7c, 0x79, 0x5d, 0x75, 0xa0, 0x6d, 0x00, 0xed, - 0xb8, 0x0e, 0x43, 0xa6, 0x0a, 0x9f, 0x3b, 0xb3, 0x23, 0x8e, 0x33, 0xad, - 0xf3, 0xc3, 0x62, 0xc6, 0x82, 0x6a, 0xea, 0xe4, 0x51, 0x29, 0x04, 0xdb, - 0x31, 0x57, 0xcc, 0x58, 0x57, 0xc3, 0x58, 0x0f, 0xcb, 0x27, 0xc8, 0x13, - 0xa1, 0x1d, 0xe1, 0xf8, 0x66, 0x66, 0x4d, 0xc5, 0xc2, 0x43, 0xca, 0x4c, - 0xe4, 0xf1, 0x6b, 0x51, 0x3a, 0x8e, 0x18, 0x0a, 0x2b, 0xf0, 0x2e, 0xf6, - 0x64, 0x9d, 0x76, 0x9c, 0x8c, 0xc5, 0xfa, 0x98, 0x11, 0x50, 0xf4, 0xb7, - 0x74, 0xea, 0x78, 0xe3, 0xb5, 0x93, 0x31, 0xe3, 0xb4, 0x3a, 0xee, 0xbd, - 0xc7, 0x81, 0x99, 0x7b, 0xe3, 0x9d, 0x5f, 0x53, 0x86, 0xbc, 0x51, 0x88, - 0x85, 0xe7, 0x94, 0x99, 0xc5, 0x98, 0xd9, 0xb4, 0x22, 0x6e, 0xc4, 0x8c, - 0x4e, 0x45, 0x9f, 0x68, 0xbb, 0xde, 0x77, 0x06, 0xfd, 0x63, 0xaa, 0xc5, - 0x5b, 0x0f, 0xef, 0xeb, 0xed, 0x3e, 0x97, 0x67, 0x88, 0x39, 0x23, 0xc0, - 0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x44, 0x64, 0x7c, 0x44, 0x63, 0xe8, - 0xe3, 0x33, 0x7f, 0x47, 0x1d, 0xca, 0x65, 0xd6, 0x45, 0x3d, 0x7e, 0x1b, - 0xd1, 0x3a, 0xf3, 0xe3, 0x33, 0x39, 0x9d, 0xf7, 0xd8, 0x50, 0x11, 0x6f, - 0xdf, 0x7b, 0x77, 0x16, 0x4e, 0xda, 0x4f, 0x71, 0x9c, 0x25, 0xff, 0x64, - 0xbb, 0x30, 0xa7, 0x74, 0xaa, 0xd4, 0xa4, 0x0d, 0xfa, 0x03, 0x98, 0x2f, - 0xd0, 0x8c, 0x7b, 0x5f, 0x11, 0xdf, 0x78, 0xc7, 0x01, 0x3a, 0x81, 0xae, - 0x09, 0x1d, 0xb5, 0x8a, 0x71, 0xf2, 0x2b, 0x92, 0x73, 0xfb, 0x4b, 0x07, - 0x73, 0x58, 0xf3, 0xd5, 0x2f, 0x1b, 0x83, 0x73, 0x63, 0x0e, 0xbc, 0x3f, - 0x3e, 0x43, 0xfa, 0xe4, 0xd9, 0x84, 0xd5, 0xd4, 0x2a, 0xd7, 0x33, 0x20, - 0xd3, 0x2b, 0x83, 0x32, 0x87, 0xdf, 0xc2, 0x8a, 0x7b, 0x6f, 0x1b, 0xd0, - 0xad, 0xa7, 0x0b, 0x86, 0xe6, 0xd7, 0x39, 0x9b, 0x31, 0x13, 0xf0, 0x8a, - 0xce, 0xa9, 0x62, 0x5f, 0xc6, 0x89, 0x06, 0x29, 0x1f, 0xed, 0x06, 0xe4, - 0xea, 0x46, 0x9d, 0x7a, 0x2a, 0xeb, 0xcd, 0x78, 0xd8, 0xdf, 0x2d, 0x0b, - 0xc0, 0xbb, 0x0a, 0x64, 0x67, 0xfe, 0xcd, 0x80, 0xcc, 0x15, 0x74, 0x3c, - 0x39, 0xfc, 0x17, 0x65, 0x4b, 0xad, 0x3e, 0x21, 0xb7, 0xeb, 0x51, 0xfd, - 0x8d, 0x72, 0x2d, 0xff, 0x0b, 0x9f, 0xbc, 0x32, 0xa2, 0xf3, 0xea, 0xa2, - 0x15, 0x79, 0xaa, 0x9f, 0x3a, 0xcf, 0xba, 0xce, 0xb1, 0x03, 0x76, 0x40, - 0xe7, 0x78, 0x0f, 0x3a, 0xc7, 0x6f, 0xa0, 0x73, 0xfc, 0xba, 0x04, 0x7c, - 0x29, 0x65, 0x3c, 0xfc, 0x9f, 0x01, 0x0e, 0x51, 0x56, 0x9b, 0xe7, 0x71, - 0xa7, 0x33, 0x39, 0xd0, 0xe0, 0x47, 0x92, 0x01, 0xde, 0x26, 0x65, 0x73, - 0x75, 0x5a, 0xb6, 0x56, 0xdd, 0x3c, 0xe5, 0xfb, 0xcc, 0x01, 0x1b, 0xe3, - 0x3d, 0x45, 0x81, 0x43, 0x47, 0x24, 0x72, 0x9a, 0xf8, 0xd1, 0x21, 0x6b, - 0xc5, 0xdf, 0x69, 0x1c, 0x5a, 0x2b, 0xb2, 0xec, 0x17, 0x9d, 0x4f, 0x76, - 0x6e, 0x47, 0x2a, 0x76, 0x03, 0xf5, 0xc7, 0xb4, 0x0f, 0xc8, 0xf5, 0xc9, - 0x13, 0x2f, 0x3f, 0xf7, 0xee, 0x5e, 0xe9, 0x3c, 0xbb, 0x59, 0xa3, 0x1b, - 0xed, 0x9a, 0xd8, 0x35, 0xe4, 0xc6, 0xbc, 0xd5, 0xdf, 0xd0, 0x06, 0x73, - 0x94, 0xba, 0x65, 0x03, 0x32, 0xa4, 0x11, 0xed, 0xd6, 0xba, 0x5f, 0x23, - 0x3a, 0xa8, 0x73, 0x77, 0x39, 0x4e, 0xbe, 0x68, 0xc9, 0x7c, 0xd1, 0x0c, - 0xe7, 0x40, 0x7f, 0xb7, 0x61, 0xab, 0x6d, 0xe2, 0x0e, 0xb6, 0x70, 0x06, - 0xdb, 0x75, 0xca, 0xf9, 0x2f, 0x34, 0xf6, 0xae, 0xd5, 0x3f, 0xc3, 0x38, - 0xe6, 0xf9, 0x84, 0x3c, 0xee, 0x23, 0x06, 0xd2, 0x1f, 0x95, 0xd2, 0xfd, - 0xdd, 0x7e, 0x9b, 0x68, 0xbb, 0x55, 0x27, 0x1e, 0x8b, 0x5c, 0x2d, 0x58, - 0x90, 0x25, 0xbf, 0x0a, 0x51, 0x07, 0x28, 0xab, 0x66, 0x3f, 0xc7, 0x5b, - 0xb3, 0xe3, 0x1c, 0xb5, 0xb8, 0xae, 0xa8, 0x87, 0xdb, 0x94, 0xfd, 0x3b, - 0x5a, 0xee, 0x17, 0x4a, 0x17, 0xe4, 0x1d, 0xdc, 0xb7, 0xab, 0xe3, 0x64, - 0xe5, 0x16, 0x74, 0xbc, 0x7a, 0xa9, 0x99, 0xd7, 0x3d, 0x89, 0x73, 0x32, - 0xd5, 0xfc, 0xf2, 0x75, 0xb9, 0x76, 0x63, 0x57, 0xbd, 0x71, 0x23, 0xa2, - 0xae, 0x2f, 0x0f, 0xa9, 0xfc, 0xb2, 0xe3, 0xfc, 0xd3, 0x9e, 0x95, 0x3b, - 0xab, 0x8e, 0x9c, 0xb5, 0x7d, 0xfd, 0x7e, 0x69, 0xe6, 0xd6, 0x39, 0x4e, - 0x07, 0xb0, 0x79, 0xfb, 0xa4, 0xe3, 0x3c, 0x3d, 0x36, 0x26, 0xd1, 0x93, - 0xd4, 0x51, 0x9e, 0x0b, 0x31, 0x3f, 0x96, 0x98, 0x93, 0xb4, 0xac, 0xcb, - 0x15, 0xa5, 0x80, 0x6f, 0xdd, 0xae, 0xfe, 0xf2, 0xcc, 0x31, 0x2f, 0x56, - 0x72, 0xe7, 0x35, 0xfa, 0x92, 0x43, 0xff, 0xe5, 0x4b, 0x36, 0xe4, 0x62, - 0x71, 0x04, 0xfd, 0x83, 0xf2, 0xc3, 0x62, 0xe0, 0x50, 0xd9, 0xc0, 0x73, - 0x54, 0xe5, 0x8b, 0x8f, 0x9c, 0x21, 0x1d, 0x33, 0x80, 0x4e, 0x62, 0x38, - 0xce, 0x9c, 0xcd, 0xf9, 0xba, 0x31, 0xdf, 0x8e, 0x71, 0x0c, 0xf2, 0xff, - 0xac, 0x96, 0xcf, 0x17, 0x15, 0x6c, 0x5f, 0xf0, 0x77, 0x50, 0xd2, 0x45, - 0xc8, 0x78, 0xc5, 0x9c, 0x53, 0xea, 0x0a, 0x66, 0x68, 0x0e, 0xd8, 0x31, - 0x0b, 0xbc, 0x79, 0x49, 0xc7, 0x56, 0x4f, 0x68, 0xec, 0x99, 0x67, 0x39, - 0x2b, 0x89, 0x8a, 0xdd, 0xa3, 0xcf, 0x6f, 0xf7, 0xf6, 0x2f, 0x43, 0xee, - 0x9d, 0x83, 0x8f, 0xb3, 0x4a, 0xda, 0x60, 0x03, 0xa5, 0xd6, 0xcf, 0x81, - 0x27, 0x42, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x0d, 0xc8, 0xef, 0x86, 0xf6, - 0x23, 0xba, 0xf1, 0x8a, 0x86, 0xc1, 0x76, 0x17, 0xd0, 0xaf, 0x5d, 0x92, - 0xcb, 0x6d, 0x1a, 0x57, 0x9f, 0xac, 0x4b, 0x40, 0x0f, 0xf9, 0x3e, 0xca, - 0x7e, 0xd4, 0x85, 0xbd, 0xb2, 0x0f, 0xe5, 0x19, 0x94, 0x5b, 0xf0, 0x64, - 0x9b, 0x61, 0xe8, 0x15, 0x78, 0xbe, 0x8d, 0xf1, 0xc6, 0xb0, 0xe6, 0xac, - 0x21, 0x1f, 0x9e, 0xa1, 0x2c, 0x19, 0x55, 0xcc, 0x63, 0x9e, 0xb3, 0xf0, - 0xac, 0x0d, 0xa9, 0xd4, 0x12, 0xcb, 0x78, 0x96, 0xdd, 0xef, 0x4f, 0x60, - 0x12, 0xfa, 0x24, 0x6f, 0xb8, 0x98, 0xf4, 0xe1, 0x1e, 0x26, 0xb1, 0xae, - 0x5d, 0xd2, 0xcb, 0xe4, 0x75, 0x03, 0xf4, 0xd6, 0x29, 0xa9, 0x1b, 0x41, - 0xad, 0x8f, 0x56, 0x40, 0x8b, 0x1b, 0xa0, 0xab, 0x35, 0xd0, 0x54, 0xb2, - 0x68, 0xc6, 0x67, 0x54, 0x58, 0xfb, 0x02, 0x5e, 0x00, 0xbd, 0x76, 0xbc, - 0x49, 0x5d, 0x94, 0xbc, 0x1c, 0x05, 0xed, 0x89, 0xd3, 0x61, 0x59, 0x99, - 0xa8, 0xb2, 0x40, 0x83, 0xa0, 0xcb, 0xa2, 0xcb, 0xd3, 0xef, 0x2b, 0x8d, - 0xab, 0xf1, 0x07, 0x12, 0x4b, 0x3c, 0x10, 0x13, 0x58, 0x60, 0xda, 0x1f, - 0x88, 0x8d, 0x31, 0x27, 0xe4, 0x26, 0xe6, 0xf1, 0x81, 0xbf, 0x47, 0x4e, - 0x69, 0xfe, 0x8e, 0x8b, 0xff, 0x30, 0x8f, 0x83, 0xde, 0x80, 0x41, 0x2e, - 0x4f, 0x27, 0x3c, 0x1a, 0xfd, 0x26, 0xf8, 0xd7, 0x84, 0x25, 0x16, 0x94, - 0x05, 0xf0, 0xff, 0x06, 0xbe, 0xdf, 0xad, 0x0f, 0xab, 0xf9, 0x25, 0xe5, - 0xe5, 0x92, 0x7c, 0x07, 0x7a, 0xf2, 0x43, 0x9c, 0x5d, 0x97, 0xd6, 0xdd, - 0x23, 0x63, 0x8c, 0x9f, 0x65, 0xd4, 0x35, 0xeb, 0xb4, 0xec, 0x8e, 0x4e, - 0xa0, 0x7c, 0x0c, 0x4f, 0x1f, 0xce, 0x21, 0xa0, 0xe3, 0xdf, 0x6b, 0x05, - 0x5b, 0xb9, 0xff, 0xd3, 0x30, 0x8e, 0xbe, 0xc4, 0xb2, 0x93, 0xf8, 0x4e, - 0x5f, 0x0c, 0xf7, 0x06, 0x9d, 0x49, 0x85, 0x74, 0xbe, 0x69, 0x05, 0xba, - 0xc4, 0x3a, 0xc6, 0xbb, 0x47, 0x5f, 0x5e, 0x0d, 0x3c, 0x3c, 0xfa, 0x2f, - 0x27, 0x11, 0x64, 0x4e, 0xfb, 0x17, 0x21, 0x57, 0xfe, 0x7d, 0xea, 0xec, - 0x5a, 0xf3, 0x71, 0x1f, 0x5e, 0x3e, 0x32, 0x82, 0x68, 0x0b, 0x59, 0x06, - 0x59, 0x54, 0xd6, 0xf4, 0xcb, 0x76, 0x6e, 0xdf, 0x7c, 0x2d, 0x66, 0xdc, - 0x17, 0xb7, 0xef, 0x82, 0x45, 0xb9, 0xd3, 0x0e, 0x7c, 0x09, 0x6b, 0xbd, - 0xf2, 0x9e, 0x95, 0x03, 0x2a, 0x98, 0xe1, 0x0c, 0x68, 0xb4, 0x4d, 0xcc, - 0xe8, 0x94, 0xec, 0xcf, 0x3b, 0xa7, 0xfb, 0xb2, 0x6d, 0xb3, 0x6f, 0x73, - 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b, 0x36, 0x34, 0x8d, 0x36, - 0x6a, 0x03, 0xfd, 0x2e, 0x8d, 0x36, 0xf7, 0x11, 0xfc, 0x3f, 0xfb, 0x20, - 0x9d, 0xd8, 0xca, 0x8d, 0xd3, 0xe3, 0x59, 0xe3, 0x79, 0x0e, 0x83, 0x36, - 0x0e, 0xd2, 0x4f, 0xd3, 0xb7, 0xe8, 0xd2, 0xcf, 0xd3, 0x7b, 0xf4, 0x43, - 0xba, 0xe9, 0x94, 0xf4, 0x0d, 0x4b, 0xa6, 0x8b, 0xfa, 0xbe, 0xa1, 0x6b, - 0xd2, 0x67, 0x34, 0x01, 0xba, 0x21, 0xad, 0x93, 0xb7, 0x0c, 0x29, 0x83, - 0x8e, 0xca, 0xc0, 0xa7, 0x32, 0x68, 0xaa, 0x02, 0x7c, 0x2b, 0x03, 0xdf, - 0xca, 0x75, 0x33, 0x5a, 0xc5, 0x9e, 0x29, 0xb3, 0xd7, 0x41, 0x47, 0x1b, - 0x75, 0xde, 0xbf, 0x5e, 0xb3, 0x41, 0x39, 0x78, 0x77, 0xef, 0xee, 0xff, - 0x81, 0xbb, 0x1f, 0x94, 0xdb, 0xb0, 0x5b, 0xde, 0x29, 0x8d, 0x02, 0x93, - 0x04, 0x18, 0x65, 0x83, 0x36, 0xe2, 0xb2, 0x59, 0x9a, 0x94, 0x2d, 0xc8, - 0xa7, 0xed, 0xd5, 0x08, 0xf4, 0xe9, 0x90, 0xcc, 0xbf, 0x35, 0x22, 0xb7, - 0x56, 0x95, 0xcc, 0x82, 0x7e, 0xf3, 0x6b, 0xf4, 0xbb, 0x83, 0x9e, 0xcb, - 0x9d, 0x3a, 0x4e, 0x9f, 0xae, 0xba, 0xfe, 0xf7, 0xa9, 0x6a, 0x97, 0x4c, - 0x57, 0x0d, 0x79, 0xbe, 0xda, 0x23, 0x2f, 0x56, 0x83, 0x72, 0x16, 0x76, - 0xe0, 0xd7, 0xaa, 0x03, 0xf2, 0x52, 0x75, 0x50, 0xbe, 0x5e, 0x0b, 0xcb, - 0x37, 0x6a, 0x96, 0x64, 0x6b, 0x51, 0xc9, 0xd4, 0x46, 0xe5, 0x85, 0x1a, - 0xfd, 0xea, 0x98, 0x0f, 0xbf, 0xd4, 0x9e, 0xbf, 0x82, 0xeb, 0xea, 0xc0, - 0xba, 0xa2, 0x6a, 0x4a, 0xc7, 0x29, 0x25, 0xeb, 0xfa, 0x3c, 0x44, 0x2e, - 0x61, 0xac, 0xc5, 0xb7, 0x94, 0x54, 0xf4, 0xfc, 0xcd, 0xff, 0x33, 0x09, - 0x68, 0xdb, 0xe8, 0x52, 0x79, 0x00, 0x6d, 0x20, 0xf7, 0x0a, 0x4d, 0xdf, - 0x47, 0xd3, 0xe7, 0xdf, 0xb4, 0xbd, 0x7c, 0xda, 0x6f, 0x7d, 0x97, 0xb6, - 0x97, 0x3e, 0x7b, 0xe2, 0x07, 0xed, 0x9c, 0x9b, 0xda, 0x6f, 0xb2, 0x1f, - 0xdb, 0x68, 0xce, 0xbb, 0x98, 0x7d, 0xf2, 0xff, 0x59, 0xdc, 0x18, 0xd5, - 0xc5, 0xda, 0x00, 0xff, 0xaf, 0x05, 0x6b, 0xf9, 0xf2, 0xdc, 0xf1, 0xe9, - 0x52, 0x5a, 0x3d, 0x5f, 0xa2, 0x46, 0xe3, 0xc8, 0xe2, 0x5e, 0x4e, 0xdc, - 0x73, 0xb2, 0x66, 0x07, 0xf4, 0x1a, 0x5c, 0x5f, 0x7d, 0x42, 0xe7, 0xc7, - 0xa5, 0x4f, 0x91, 0xfe, 0x18, 0x7b, 0xeb, 0xf2, 0xe2, 0x09, 0xd0, 0x6d, - 0x6d, 0x43, 0xae, 0x56, 0x5d, 0x9f, 0xd5, 0xbc, 0xa6, 0x97, 0x7b, 0xa0, - 0x39, 0xc6, 0x1c, 0xdc, 0x67, 0xae, 0xec, 0xf6, 0x4d, 0xe1, 0xde, 0x60, - 0x8f, 0x63, 0xbf, 0xbe, 0x1e, 0xce, 0xc5, 0xff, 0xe3, 0x41, 0xd9, 0x5b, - 0x2f, 0x73, 0x8d, 0x2d, 0x4d, 0x8b, 0x6e, 0x5c, 0x37, 0x2a, 0xaf, 0xe2, - 0xfc, 0x2a, 0x06, 0xd7, 0xdf, 0x21, 0x95, 0x28, 0x6d, 0x5b, 0xe2, 0xf7, - 0x29, 0x29, 0x63, 0x9e, 0x4a, 0xb4, 0xe9, 0x0f, 0x73, 0x71, 0xb6, 0x62, - 0xec, 0xcf, 0x3b, 0x53, 0x3e, 0x8e, 0x77, 0xd4, 0x45, 0xa1, 0x33, 0x9d, - 0xe3, 0xfb, 0x22, 0xca, 0xf4, 0x8d, 0xcc, 0xe3, 0x19, 0xf2, 0xea, 0xde, - 0xeb, 0xd7, 0xba, 0xfa, 0xe4, 0x7e, 0xbf, 0xd9, 0xb2, 0x99, 0x4b, 0xfa, - 0x63, 0xca, 0xf7, 0xf3, 0xdf, 0xf7, 0x13, 0x73, 0x8f, 0x5b, 0xfc, 0x05, - 0xe4, 0x33, 0x43, 0xfb, 0x14, 0xbc, 0x6f, 0x47, 0xe4, 0x65, 0x83, 0x79, - 0xec, 0x09, 0x95, 0x2e, 0x5d, 0xf7, 0x72, 0x7c, 0x63, 0xea, 0x78, 0xe5, - 0x7e, 0xbf, 0x9b, 0xf3, 0xce, 0xb1, 0x0f, 0xe6, 0xb9, 0x1f, 0xa4, 0x13, - 0xe6, 0xbb, 0xb7, 0xef, 0xfd, 0x0f, 0x55, 0xa5, 0x00, 0xbc, 0xb3, 0x5a, - 0x34, 0x3f, 0xe6, 0x6b, 0xff, 0x76, 0x76, 0x34, 0x3f, 0x37, 0x7d, 0x0c, - 0x7f, 0xee, 0xa7, 0x6d, 0x4b, 0xdc, 0xb8, 0xea, 0xe6, 0x8e, 0x6a, 0x1b, - 0x1a, 0x58, 0x81, 0x3a, 0xf2, 0x2a, 0xf8, 0x64, 0xaf, 0x2d, 0xff, 0xfe, - 0x03, 0x9a, 0xb8, 0x8a, 0x6c, 0x8c, 0x67, 0x00, 0x00, 0x00 }; + 0xec, 0x5b, 0x7f, 0x70, 0x1c, 0xf5, 0x75, 0xff, 0x7c, 0xf7, 0xf6, 0xa4, + 0x95, 0x74, 0xba, 0x5b, 0x49, 0x27, 0xf9, 0x14, 0x8c, 0xb5, 0x8b, 0x56, + 0x27, 0x61, 0x19, 0x77, 0x4f, 0x3a, 0xd9, 0x4a, 0x66, 0x1b, 0x2e, 0xb6, + 0x63, 0xe4, 0x81, 0x82, 0xb0, 0x09, 0x31, 0x53, 0x26, 0xa8, 0xb6, 0x63, + 0xc4, 0x8f, 0x34, 0x26, 0x61, 0x06, 0x11, 0x68, 0xd8, 0x48, 0x36, 0xa6, + 0xf6, 0x9e, 0xd6, 0x36, 0x12, 0xe0, 0x99, 0x74, 0x22, 0x64, 0x59, 0x36, + 0xe4, 0xa4, 0x33, 0x90, 0x1f, 0x66, 0x5a, 0x6a, 0x81, 0xf9, 0x61, 0x88, + 0x0d, 0x84, 0x42, 0x02, 0x33, 0x99, 0x89, 0xf9, 0x11, 0xc7, 0x66, 0x68, + 0x50, 0x5a, 0x92, 0x8a, 0x89, 0xea, 0x6f, 0xdf, 0xbb, 0x93, 0xf8, 0x61, + 0x3a, 0x4d, 0x3b, 0xd3, 0x3f, 0xf7, 0xcd, 0xdc, 0x68, 0xf7, 0xfb, 0x7d, + 0xef, 0x7d, 0xdf, 0xef, 0xf7, 0xbe, 0x3b, 0xa3, 0x5b, 0x23, 0x28, 0xc7, + 0x1c, 0x54, 0xd2, 0x2f, 0xbd, 0xa5, 0xef, 0x5b, 0x1d, 0x4b, 0xed, 0xa5, + 0xfc, 0x1e, 0x0a, 0x43, 0xe5, 0xbf, 0x02, 0x01, 0x04, 0x10, 0x40, 0x00, + 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, + 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, + 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, + 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0x04, 0x10, + 0x40, 0x00, 0x01, 0x04, 0x10, 0x40, 0x00, 0x01, 0xfc, 0x7f, 0x42, 0x08, + 0xd0, 0xf9, 0x6f, 0xe5, 0xdc, 0x0f, 0x9a, 0xe2, 0x8c, 0x7c, 0x67, 0x85, + 0x05, 0x2d, 0xe4, 0xc4, 0xef, 0xd8, 0x68, 0x01, 0x99, 0x5c, 0xab, 0xb1, + 0x12, 0xff, 0x29, 0xdd, 0xb8, 0x0a, 0x5e, 0x3f, 0xdf, 0x99, 0xfd, 0xc1, + 0x13, 0xcb, 0xcd, 0xe9, 0x91, 0x10, 0x34, 0xdd, 0x79, 0x39, 0xa5, 0x27, + 0xa1, 0x2d, 0x24, 0x9a, 0xef, 0x37, 0x6f, 0xab, 0x46, 0x74, 0x9e, 0x17, + 0x5c, 0xc5, 0x91, 0x72, 0xbf, 0x2d, 0xf1, 0xac, 0xed, 0x8a, 0xae, 0x34, + 0xdc, 0x90, 0x73, 0x58, 0xdc, 0xe0, 0x9d, 0x95, 0x46, 0xb8, 0x78, 0xb2, + 0x3a, 0xa1, 0x21, 0xbc, 0x1f, 0xba, 0xea, 0x28, 0x08, 0x5b, 0xe5, 0x28, + 0x79, 0xb0, 0x02, 0xe1, 0x07, 0x13, 0x28, 0x9d, 0x38, 0x24, 0x7a, 0x46, + 0x34, 0x9c, 0x0c, 0x1d, 0x16, 0x9b, 0x72, 0xe8, 0x09, 0x3b, 0x33, 0x57, + 0x8c, 0x12, 0x5d, 0xa6, 0xf0, 0xff, 0x25, 0x53, 0x57, 0x8c, 0xe5, 0xa0, + 0x87, 0x1c, 0x28, 0xaa, 0xf3, 0x34, 0x3d, 0x33, 0xde, 0xcc, 0x15, 0xfb, + 0x72, 0xa7, 0xe5, 0x13, 0xcd, 0x71, 0x1c, 0xc9, 0xeb, 0x38, 0x94, 0xff, + 0x25, 0xc9, 0x61, 0xba, 0x2e, 0x34, 0x57, 0x75, 0x5c, 0x6c, 0x4b, 0x87, + 0x31, 0xbe, 0xeb, 0xac, 0x0c, 0x59, 0xa6, 0x01, 0xc5, 0xd2, 0x8f, 0x82, + 0xf0, 0x7c, 0xc2, 0xf3, 0xc3, 0x18, 0x1d, 0x79, 0xb3, 0x1a, 0xe5, 0x09, + 0x3c, 0xd1, 0xcc, 0xf4, 0x4c, 0xcb, 0x3c, 0x42, 0xb1, 0x79, 0xfa, 0x12, + 0xa2, 0x7f, 0x26, 0x0d, 0x8c, 0xed, 0xea, 0x26, 0x52, 0x89, 0x01, 0xbb, + 0x14, 0x1b, 0x74, 0xb8, 0x65, 0x0e, 0xf3, 0x9a, 0xe7, 0xe3, 0x0a, 0x63, + 0x22, 0xaa, 0x17, 0xf9, 0x40, 0x68, 0x16, 0xdc, 0xd2, 0x73, 0xf6, 0x4f, + 0xe7, 0xe6, 0xf7, 0xef, 0xa1, 0x73, 0x34, 0xda, 0xef, 0xc5, 0x4f, 0xf2, + 0x9b, 0xf0, 0xe3, 0xfc, 0xb5, 0x78, 0x2c, 0xdf, 0x4d, 0xe7, 0xde, 0x4a, + 0xe7, 0x6e, 0xc1, 0x3f, 0xe7, 0x6f, 0xc6, 0x4f, 0xf3, 0x3d, 0xf8, 0x51, + 0x7e, 0x3d, 0x1e, 0xcd, 0x5f, 0x85, 0x47, 0xf2, 0x28, 0xc8, 0x70, 0x3a, + 0xdd, 0x22, 0x7e, 0xee, 0x95, 0x41, 0xdd, 0xbd, 0x15, 0x53, 0xb9, 0x30, + 0xc2, 0xbb, 0x25, 0x76, 0xd9, 0xe6, 0x03, 0x40, 0xb3, 0x1e, 0x86, 0xc0, + 0x4a, 0xdb, 0x3c, 0x08, 0x7c, 0x01, 0x3d, 0x71, 0xf3, 0x10, 0x50, 0x27, + 0x5e, 0x19, 0xaa, 0x13, 0x27, 0x86, 0x54, 0xf1, 0xa2, 0x27, 0x10, 0x73, + 0x10, 0x79, 0x21, 0x2d, 0xe5, 0xa5, 0x6d, 0x52, 0xe6, 0x52, 0x56, 0xd7, + 0x4b, 0xc2, 0xb4, 0x77, 0x88, 0x45, 0x30, 0x6a, 0xcd, 0xcc, 0x8d, 0x42, + 0x73, 0xcb, 0x89, 0xff, 0x9a, 0x0e, 0xc0, 0xda, 0x6d, 0x90, 0x1f, 0x58, + 0xc7, 0x6d, 0xf8, 0x7a, 0x21, 0x26, 0xba, 0x51, 0x63, 0xad, 0xc4, 0xb7, + 0xbb, 0x6d, 0x8c, 0xe4, 0xa1, 0x55, 0x39, 0x1f, 0x20, 0x35, 0x28, 0x60, + 0x93, 0xbf, 0x05, 0x3d, 0xdb, 0xb9, 0x27, 0x6b, 0x8a, 0xfe, 0x26, 0xd9, + 0x7d, 0x92, 0xdd, 0x27, 0xd9, 0x7d, 0xd2, 0xcb, 0x27, 0xbd, 0x7c, 0xd2, + 0xc1, 0x27, 0xdd, 0x7c, 0xd2, 0xc3, 0x27, 0x3d, 0x7c, 0xd2, 0xd1, 0x67, + 0x5f, 0xf5, 0x91, 0x0d, 0x22, 0xf8, 0xa5, 0xb7, 0x10, 0x1f, 0x78, 0xe7, + 0xe3, 0x83, 0xb5, 0x3a, 0x5e, 0x27, 0x19, 0x15, 0xeb, 0xff, 0xca, 0xe3, + 0xa7, 0x11, 0xf2, 0x91, 0xf1, 0xbf, 0x3f, 0xdb, 0x24, 0x8d, 0xe6, 0x69, + 0x97, 0xe0, 0x94, 0xf7, 0xb6, 0x2c, 0x59, 0xc0, 0xe7, 0x7e, 0x11, 0x72, + 0x08, 0x58, 0x34, 0x2c, 0xe5, 0x87, 0xed, 0xbf, 0x96, 0x6f, 0x7c, 0x95, + 0xf9, 0x39, 0x78, 0x6b, 0x48, 0x41, 0x88, 0xd6, 0x2e, 0xb1, 0xdf, 0x90, + 0xd7, 0xc7, 0x19, 0xef, 0x8f, 0x11, 0x94, 0xb3, 0xad, 0xa0, 0xd5, 0x38, + 0xea, 0x1d, 0xdf, 0x4e, 0xc2, 0x8d, 0x3a, 0xaa, 0x78, 0x35, 0x6b, 0x60, + 0x81, 0x93, 0x41, 0xa5, 0x63, 0xed, 0xba, 0x5f, 0x69, 0xed, 0xab, 0x46, + 0xe6, 0xc2, 0x18, 0x6c, 0xec, 0xcf, 0xab, 0xe2, 0x78, 0xb6, 0x12, 0xd5, + 0xbb, 0xad, 0xf5, 0x59, 0xa1, 0xa0, 0xa7, 0x36, 0x83, 0xb1, 0xb4, 0x69, + 0x8c, 0xc0, 0xc0, 0xfa, 0x36, 0x05, 0x58, 0xe0, 0xe2, 0xee, 0xb4, 0x69, + 0xbb, 0xe8, 0xc7, 0x54, 0xdc, 0xc6, 0x78, 0x5e, 0xa3, 0xfc, 0x70, 0x71, + 0x7d, 0x5a, 0x83, 0xdc, 0x95, 0xc1, 0xa9, 0xf6, 0x52, 0x4c, 0x75, 0x73, + 0x9c, 0xa8, 0x74, 0xf6, 0x76, 0x28, 0xd5, 0xd5, 0xe4, 0x9b, 0xb4, 0x08, + 0x57, 0x17, 0x52, 0x94, 0xd6, 0x21, 0xfe, 0x35, 0xcd, 0x32, 0x7c, 0x4e, + 0x1c, 0x1f, 0x8e, 0xa2, 0x7c, 0x58, 0xc3, 0x0f, 0x77, 0xab, 0x58, 0x43, + 0x3e, 0xbe, 0x3f, 0xa5, 0x1a, 0x37, 0x0a, 0x07, 0x63, 0x79, 0x15, 0xf1, + 0x6c, 0x3d, 0x8c, 0x2a, 0x0d, 0x8b, 0xb2, 0x2e, 0xde, 0x26, 0xde, 0x7d, + 0xc4, 0x3b, 0xd6, 0xae, 0xe3, 0x64, 0x6d, 0xd1, 0xbf, 0xb7, 0x78, 0x8d, + 0xee, 0x6e, 0xa5, 0x04, 0x28, 0x81, 0xab, 0x39, 0x69, 0xdc, 0xe6, 0x35, + 0x92, 0x1e, 0xd7, 0x60, 0x45, 0x89, 0x86, 0x0d, 0x83, 0xbc, 0xb6, 0x0a, + 0x98, 0x58, 0x50, 0x89, 0x72, 0xb6, 0x01, 0xe7, 0xf5, 0x4a, 0x7a, 0xe6, + 0x78, 0xb8, 0x37, 0xce, 0xf6, 0x77, 0x95, 0xff, 0x90, 0x99, 0x38, 0xe3, + 0x15, 0x73, 0xe5, 0x68, 0x3a, 0x8d, 0xdb, 0xbd, 0xc6, 0xcc, 0x5e, 0xa5, + 0x06, 0x08, 0x9b, 0x86, 0xa1, 0x40, 0x8b, 0x3b, 0x48, 0x0d, 0x51, 0xdc, + 0xdc, 0x5b, 0x88, 0x1b, 0xa4, 0xda, 0x73, 0x9c, 0x9f, 0x9a, 0xab, 0x13, + 0x7e, 0xc3, 0xb2, 0x26, 0xfc, 0xf1, 0x5e, 0xc6, 0x53, 0xf1, 0x3c, 0x3d, + 0x9f, 0xd9, 0xf7, 0xe6, 0x5c, 0x0d, 0xf9, 0x87, 0x82, 0x7f, 0x0d, 0x65, + 0xfe, 0x6c, 0x1b, 0xd7, 0x7b, 0x8d, 0x33, 0xdb, 0x15, 0xf2, 0xe1, 0x79, + 0x11, 0x94, 0x51, 0x1d, 0x0a, 0x13, 0xaf, 0xfd, 0xde, 0x2c, 0xd6, 0xb6, + 0x99, 0x87, 0xf9, 0xff, 0xce, 0x46, 0xad, 0x22, 0xff, 0x0b, 0x72, 0x36, + 0x1e, 0xca, 0xdb, 0xd8, 0x48, 0x72, 0xdc, 0x8a, 0x37, 0x81, 0xfa, 0xc5, + 0xc6, 0x69, 0xe5, 0x2d, 0xe9, 0x5e, 0xc5, 0xfc, 0x16, 0xe2, 0x74, 0x75, + 0x63, 0xcf, 0x69, 0xc5, 0x1c, 0xb9, 0x47, 0x61, 0x5b, 0x29, 0xf8, 0xab, + 0xb6, 0x34, 0x46, 0xaa, 0x74, 0x5c, 0xd3, 0xa6, 0xb9, 0x8b, 0x48, 0xa6, + 0x97, 0x97, 0x6b, 0xa8, 0xdb, 0x93, 0xc1, 0x6b, 0x6d, 0xaf, 0x62, 0x64, + 0x2d, 0xdb, 0x81, 0xe9, 0x58, 0xe6, 0x04, 0xaa, 0xad, 0x32, 0x54, 0x8f, + 0x86, 0x11, 0xdb, 0x73, 0x56, 0x26, 0x2c, 0x5e, 0xb7, 0xb6, 0xcc, 0x08, + 0x96, 0x39, 0x8c, 0xe8, 0xe8, 0xe7, 0xa1, 0x5a, 0x66, 0x0b, 0xf0, 0x8d, + 0x38, 0xe3, 0x96, 0x58, 0xf3, 0xb2, 0x0b, 0x5c, 0xfa, 0x05, 0x81, 0x1b, + 0x53, 0x4f, 0xca, 0x4c, 0x2d, 0xd3, 0x3c, 0x46, 0xeb, 0x2c, 0x43, 0xd9, + 0x4c, 0x06, 0x75, 0x44, 0x33, 0x8f, 0x17, 0x41, 0xef, 0x9e, 0xa2, 0x0c, + 0x6f, 0x2c, 0xc7, 0x63, 0x1a, 0x3a, 0xd1, 0xec, 0x7f, 0x0f, 0xaf, 0x2d, + 0x63, 0x9a, 0xef, 0x4d, 0xef, 0x6f, 0xdb, 0x49, 0x36, 0xe1, 0x7a, 0x7a, + 0xae, 0x5f, 0x78, 0xbf, 0xbb, 0x96, 0xec, 0xd5, 0x02, 0x91, 0xa0, 0x35, + 0x8e, 0xe1, 0xdd, 0xd2, 0x58, 0x57, 0xf4, 0x4b, 0x29, 0xf1, 0x3b, 0x93, + 0xee, 0x44, 0x63, 0x56, 0x85, 0xf4, 0x1a, 0xed, 0x5f, 0x87, 0x76, 0xc8, + 0xa9, 0x6b, 0x79, 0xaf, 0x51, 0x3f, 0x1a, 0x12, 0x58, 0xa1, 0x9a, 0xd3, + 0x3d, 0x48, 0xe0, 0x20, 0xd5, 0x9a, 0x7a, 0x47, 0xa7, 0xda, 0x13, 0xa7, + 0x1a, 0x64, 0x88, 0xe6, 0xfb, 0x6d, 0x2c, 0xce, 0x5e, 0x8b, 0x8b, 0x87, + 0x1d, 0x1c, 0xf6, 0x6d, 0xfc, 0xd0, 0x97, 0xf2, 0x94, 0x2d, 0xe5, 0xfb, + 0xed, 0x66, 0xef, 0x31, 0x6a, 0x0b, 0x4b, 0x97, 0xb7, 0xf6, 0xc4, 0x42, + 0x2a, 0xd9, 0xa7, 0xc9, 0xb8, 0x59, 0x98, 0x89, 0x49, 0x61, 0x53, 0xcc, + 0x75, 0x91, 0xed, 0x0d, 0xec, 0xcb, 0xb7, 0xe0, 0xe1, 0xbc, 0x45, 0xbf, + 0x25, 0x14, 0x2b, 0x69, 0xaa, 0x6b, 0xac, 0xab, 0x8e, 0xb1, 0x66, 0xca, + 0x0d, 0x5f, 0xc1, 0x41, 0x9b, 0x72, 0xa0, 0x8a, 0x70, 0xfd, 0xb3, 0xe4, + 0x3f, 0x0d, 0x2d, 0xbb, 0x33, 0x28, 0x4b, 0xd5, 0xc0, 0xb8, 0xd2, 0xc2, + 0x98, 0xaf, 0xb9, 0x61, 0x8a, 0xfb, 0x51, 0xef, 0x61, 0x7c, 0x4d, 0x8f, + 0xa3, 0x9c, 0xec, 0xb7, 0xbe, 0x2d, 0x02, 0xac, 0xe3, 0xbd, 0x08, 0xea, + 0xad, 0xe7, 0x50, 0x5f, 0x5d, 0x89, 0x92, 0xc5, 0x4f, 0x62, 0x4a, 0x8f, + 0xa2, 0x94, 0x7a, 0x47, 0x03, 0xe1, 0x34, 0x90, 0xaf, 0x6a, 0x2d, 0x8b, + 0x78, 0x0a, 0x58, 0x4d, 0x84, 0x4b, 0x39, 0x95, 0x20, 0xdd, 0xc3, 0xcb, + 0xe3, 0xc8, 0x93, 0xfc, 0x93, 0x9e, 0x94, 0x91, 0xb4, 0xd9, 0xeb, 0x53, + 0x7e, 0x4e, 0xe4, 0x3a, 0x31, 0x99, 0xbf, 0x9c, 0xea, 0xba, 0x8d, 0x7d, + 0x9e, 0x83, 0x51, 0x5f, 0x5d, 0xef, 0xc1, 0xec, 0xbe, 0x09, 0x69, 0x3c, + 0x4c, 0xf1, 0x33, 0xee, 0x9b, 0xc6, 0x53, 0x21, 0x0d, 0xc7, 0xec, 0x0a, + 0x92, 0x93, 0x72, 0x97, 0x74, 0x7a, 0xdc, 0xbb, 0x0f, 0x56, 0x0d, 0xdb, + 0x9f, 0xfd, 0x94, 0xc6, 0x01, 0xbf, 0x10, 0xdf, 0x97, 0x6a, 0x70, 0x61, + 0x77, 0xb0, 0x6f, 0xdc, 0xe9, 0x70, 0x5b, 0xb1, 0x9e, 0x76, 0x77, 0xd8, + 0x28, 0x1d, 0xec, 0x24, 0xbe, 0x8d, 0xf6, 0x5b, 0xb8, 0x09, 0x53, 0x09, + 0x17, 0x4b, 0x29, 0xfe, 0x55, 0xe7, 0x81, 0xd4, 0x56, 0xcf, 0x95, 0x31, + 0xcb, 0xea, 0x7d, 0x49, 0xdc, 0x85, 0xe3, 0x29, 0xae, 0xef, 0x2a, 0xe5, + 0xbe, 0x8e, 0x9d, 0xf6, 0x2e, 0x9c, 0xc8, 0x7d, 0x09, 0x3d, 0x55, 0x66, + 0xcb, 0x80, 0xb8, 0x09, 0x87, 0x77, 0x5d, 0x0c, 0x7c, 0x95, 0xf3, 0x84, + 0x74, 0xb3, 0x6e, 0xc2, 0x91, 0x91, 0xef, 0xe0, 0x99, 0xa1, 0x72, 0x3c, + 0x6e, 0x55, 0xa3, 0x7e, 0xbc, 0x78, 0xce, 0x97, 0x3b, 0x34, 0x8c, 0x52, + 0x4e, 0x5f, 0x62, 0xab, 0x38, 0x19, 0xe7, 0x1a, 0x42, 0xb1, 0xd6, 0xf6, + 0x2d, 0xaa, 0x37, 0x85, 0x16, 0x8c, 0x4d, 0x69, 0x03, 0x9e, 0x97, 0xa1, + 0x3a, 0x58, 0x86, 0x3d, 0x55, 0x10, 0x1b, 0xa9, 0x97, 0xfd, 0xad, 0xd7, + 0xd8, 0x3b, 0xa8, 0x54, 0x63, 0xa4, 0x3e, 0x43, 0xbe, 0x10, 0xa8, 0xb3, + 0x0c, 0x6c, 0xcb, 0x51, 0x25, 0xcd, 0xa9, 0xf8, 0x6e, 0xae, 0x1d, 0x23, + 0x75, 0x4c, 0x7b, 0x11, 0xa6, 0x0a, 0x7f, 0xc3, 0x38, 0x59, 0x6d, 0x26, + 0x40, 0x36, 0x1b, 0xf3, 0x55, 0x0c, 0xdb, 0xc3, 0x67, 0x47, 0xd6, 0x9a, + 0x7a, 0x0f, 0xe5, 0x5b, 0xa8, 0x10, 0xb7, 0xfc, 0x0c, 0x7c, 0xd3, 0xfb, + 0xbd, 0xfc, 0xa0, 0x70, 0xa6, 0xca, 0xf9, 0x3f, 0xf5, 0x46, 0xe8, 0x8c, + 0x14, 0xa5, 0xcc, 0xff, 0xf6, 0x68, 0xf1, 0x7f, 0x46, 0x7f, 0xcc, 0xb8, + 0x19, 0x80, 0xe3, 0x60, 0xc1, 0x27, 0x62, 0x7e, 0xbe, 0x8e, 0x9f, 0x1b, + 0xd3, 0xc5, 0xfa, 0xa0, 0x2f, 0x63, 0xf9, 0xe6, 0xf3, 0xaf, 0x1a, 0x75, + 0xe3, 0x4d, 0x28, 0xdb, 0xc3, 0xef, 0xbc, 0x2e, 0x70, 0x41, 0x07, 0xe7, + 0x5e, 0x13, 0x94, 0xd1, 0x4d, 0xd1, 0x62, 0x7d, 0x9e, 0xaf, 0x1b, 0x7f, + 0x37, 0x77, 0x6e, 0x61, 0x16, 0xa0, 0xf7, 0x62, 0x7d, 0xfd, 0x6e, 0x9a, + 0x9f, 0x99, 0xa6, 0x0c, 0xaf, 0xed, 0x33, 0xed, 0x11, 0x65, 0x39, 0xc9, + 0xc2, 0xf9, 0xca, 0x79, 0x7b, 0xc7, 0x1c, 0x0d, 0xe5, 0x82, 0x7f, 0x50, + 0xe2, 0x1a, 0xe6, 0x37, 0x4f, 0xdf, 0x84, 0x92, 0x8f, 0xce, 0x55, 0xf1, + 0x54, 0xfa, 0xdc, 0x73, 0xaf, 0x96, 0xe5, 0x6b, 0xab, 0x29, 0xfe, 0x6a, + 0xa1, 0x2e, 0xa6, 0x01, 0x40, 0xaf, 0x43, 0x05, 0xe5, 0x73, 0xc8, 0xba, + 0x52, 0x86, 0xae, 0xe6, 0xf8, 0xd5, 0xdc, 0x88, 0x73, 0x1e, 0x06, 0x77, + 0x3f, 0x41, 0xbe, 0x8f, 0x72, 0x9c, 0x92, 0xff, 0xcf, 0x43, 0xf6, 0xc1, + 0x86, 0x28, 0xeb, 0xbb, 0xbe, 0x0d, 0x6e, 0x03, 0xd5, 0xf2, 0xdf, 0xdc, + 0xdf, 0x2b, 0x47, 0xba, 0x75, 0x3c, 0x9b, 0x5e, 0x49, 0xeb, 0x1c, 0x67, + 0x36, 0x7e, 0xe4, 0x69, 0xb8, 0x6d, 0x30, 0x41, 0x72, 0x72, 0x0d, 0x2d, + 0x9b, 0x39, 0xa9, 0xd8, 0x78, 0x8c, 0x62, 0xf4, 0x11, 0x9f, 0x6d, 0xa5, + 0xe2, 0x82, 0xb6, 0x95, 0xb2, 0xb4, 0x8e, 0xe3, 0x7e, 0x31, 0xd1, 0xe8, + 0xc4, 0x3b, 0x0a, 0xdd, 0xfa, 0x4b, 0x79, 0x68, 0x2d, 0x3f, 0x5f, 0x48, + 0x6b, 0x75, 0xf4, 0xf7, 0x2f, 0x64, 0xc5, 0x67, 0xe4, 0xd0, 0xff, 0x3b, + 0x39, 0x28, 0x1f, 0x4c, 0x7b, 0x33, 0x5a, 0x69, 0x4e, 0x52, 0x91, 0xa1, + 0xae, 0x39, 0x4e, 0xb1, 0xb1, 0x9d, 0x7a, 0xf4, 0x6f, 0x68, 0x16, 0xdc, + 0x56, 0x98, 0xb7, 0x0a, 0xe3, 0x5b, 0x61, 0x9e, 0xdb, 0x50, 0x9c, 0xcb, + 0x34, 0xd5, 0xe2, 0x59, 0x6d, 0x7e, 0x8f, 0x6d, 0xdd, 0x85, 0x0d, 0x43, + 0x52, 0x6e, 0xb5, 0xe3, 0xc4, 0xa3, 0x1a, 0x5b, 0xad, 0x2e, 0xf4, 0x0e, + 0x81, 0xf2, 0x5a, 0xca, 0xd2, 0xd4, 0xe2, 0xc4, 0x3b, 0x54, 0xe4, 0x7b, + 0x74, 0x57, 0x8c, 0xa7, 0x3f, 0x47, 0x76, 0xaa, 0xc0, 0xcf, 0x68, 0xde, + 0xdb, 0xe1, 0x23, 0xb3, 0x26, 0x55, 0x49, 0xfd, 0x4a, 0x87, 0xef, 0x1b, + 0x62, 0x72, 0x48, 0x47, 0xd6, 0x3f, 0x2b, 0x8f, 0x37, 0x09, 0xec, 0xef, + 0x88, 0xe3, 0xf8, 0x18, 0xf3, 0xd7, 0xb1, 0x2d, 0xcf, 0xb3, 0x65, 0x88, + 0xec, 0xe1, 0x8a, 0x6b, 0xd2, 0xbc, 0x56, 0x01, 0x6b, 0x1f, 0xd7, 0x63, + 0xcb, 0x9e, 0x11, 0x45, 0x9c, 0xbb, 0xf3, 0xaf, 0xd3, 0x9c, 0x65, 0x50, + 0x2d, 0x5b, 0x48, 0xf3, 0x55, 0x82, 0x66, 0xa9, 0x38, 0xcd, 0x52, 0xd6, + 0xdc, 0x7c, 0x68, 0x52, 0x36, 0x4a, 0xf9, 0x18, 0xd5, 0xb2, 0x57, 0xe8, + 0xf7, 0x01, 0xd5, 0xd3, 0x2a, 0xd2, 0xe5, 0x82, 0x41, 0xd6, 0xc5, 0x15, + 0x36, 0xd5, 0xdb, 0x8c, 0x52, 0x1e, 0xe3, 0x3e, 0x14, 0x9a, 0x24, 0x5e, + 0x34, 0x73, 0x6c, 0xf3, 0x81, 0x01, 0x1f, 0xee, 0xd3, 0x94, 0xfb, 0x35, + 0xe3, 0x51, 0x54, 0x8f, 0xeb, 0x08, 0x8f, 0xb7, 0xd0, 0xbe, 0x86, 0x38, + 0xbd, 0xbb, 0x34, 0x13, 0xc6, 0x9c, 0x3a, 0xb1, 0xe4, 0xbe, 0x59, 0xb9, + 0x33, 0xa5, 0xe2, 0xc6, 0x26, 0xb3, 0xeb, 0x4a, 0x81, 0x4c, 0x4b, 0x96, + 0xf5, 0x2d, 0xa5, 0xdc, 0x94, 0x47, 0xe2, 0x96, 0x94, 0x51, 0x47, 0xde, + 0x75, 0xa2, 0xc3, 0xb2, 0x4f, 0x80, 0x65, 0x64, 0x1a, 0x5e, 0x77, 0xc5, + 0xef, 0x3b, 0xac, 0x07, 0x5e, 0x45, 0x12, 0xed, 0xe3, 0xaa, 0xf8, 0xb7, + 0xec, 0x12, 0xb4, 0x4d, 0x42, 0x2f, 0x71, 0x0e, 0x89, 0x93, 0x0f, 0x1e, + 0x16, 0xa7, 0x26, 0x48, 0x6e, 0x9f, 0x74, 0xf1, 0x49, 0x17, 0x9f, 0x74, + 0xf1, 0x49, 0x97, 0xc2, 0x5c, 0xc9, 0xba, 0xb6, 0xd0, 0x3c, 0xf3, 0x7a, + 0x61, 0xf6, 0xe5, 0x59, 0xb1, 0xca, 0x31, 0x33, 0x2e, 0x58, 0x6f, 0xd6, + 0x53, 0xca, 0x57, 0xed, 0xa2, 0x3e, 0x2e, 0x95, 0x5b, 0x6d, 0x72, 0xde, + 0x16, 0x52, 0xfe, 0xbb, 0xcd, 0xb6, 0x60, 0x1d, 0xa5, 0x7c, 0xd4, 0x26, + 0x9b, 0x12, 0xaf, 0x01, 0x5f, 0x1e, 0x29, 0xb1, 0x2c, 0x63, 0x1c, 0x11, + 0xd2, 0x2f, 0x4a, 0x7a, 0x69, 0xa4, 0x6b, 0x12, 0x2a, 0xe9, 0x1a, 0x1a, + 0x87, 0xae, 0x90, 0x3c, 0xc6, 0x28, 0xd9, 0x69, 0xf2, 0xcf, 0xc9, 0xc3, + 0xfe, 0x71, 0xc5, 0x97, 0x69, 0x3e, 0x51, 0xc9, 0xae, 0x03, 0x14, 0x23, + 0x3d, 0x2a, 0x8c, 0x52, 0x4b, 0xa1, 0x9e, 0xa8, 0xe1, 0xc0, 0x58, 0x05, + 0xc6, 0x47, 0x74, 0x8c, 0x8c, 0x41, 0x0f, 0x13, 0x4f, 0x77, 0xe4, 0xb0, + 0xf8, 0x64, 0x5c, 0x95, 0x3a, 0x5b, 0xf0, 0x0e, 0xd5, 0xa9, 0x41, 0xaf, + 0x5a, 0x9c, 0xda, 0xa5, 0x61, 0xab, 0xcf, 0xb9, 0x29, 0x71, 0xd4, 0xee, + 0x4f, 0x10, 0x8a, 0xe8, 0xb7, 0xd7, 0x50, 0x4c, 0x85, 0xb0, 0xd9, 0x42, + 0x66, 0x9b, 0xdd, 0x05, 0x62, 0x65, 0xec, 0xa5, 0xfa, 0xd7, 0x67, 0xb9, + 0x7d, 0x34, 0xc6, 0xf4, 0x26, 0x60, 0xae, 0xff, 0xad, 0x30, 0x7b, 0x0e, + 0x90, 0xfd, 0x37, 0x67, 0x91, 0xd9, 0x99, 0xad, 0x13, 0xef, 0x0e, 0xcd, + 0xca, 0x35, 0x29, 0x33, 0xd3, 0x4c, 0x6b, 0x95, 0x59, 0x25, 0x59, 0x82, + 0xfe, 0x8d, 0x84, 0xdb, 0xa2, 0x62, 0x36, 0xb4, 0x3d, 0xd5, 0x5f, 0x45, + 0x13, 0x90, 0x16, 0xa1, 0x1a, 0xec, 0x35, 0x99, 0x89, 0x1c, 0xad, 0xad, + 0xa7, 0x7b, 0xcb, 0xf3, 0xb6, 0x79, 0xec, 0x3d, 0x4c, 0x63, 0x83, 0x37, + 0xad, 0x36, 0xfb, 0x66, 0x5f, 0x24, 0xe4, 0x76, 0x97, 0x41, 0x59, 0x5d, + 0x81, 0x69, 0xed, 0x4c, 0xd6, 0xb4, 0x2f, 0x13, 0x6e, 0x8b, 0x86, 0xfe, + 0x46, 0x7a, 0x8f, 0x1c, 0xf3, 0x8a, 0x74, 0x7b, 0xed, 0xfe, 0x27, 0x2b, + 0x90, 0xec, 0xbb, 0x84, 0x7a, 0xc9, 0x92, 0x90, 0xc4, 0xf5, 0xa9, 0x69, + 0x7d, 0xb3, 0x37, 0x1b, 0x0a, 0xb7, 0x27, 0xf5, 0x33, 0xc2, 0x4d, 0x94, + 0x62, 0x3a, 0x7e, 0x45, 0xd6, 0x34, 0x72, 0x48, 0x1e, 0xeb, 0xc2, 0x74, + 0x62, 0x87, 0x67, 0x4e, 0xdd, 0x8c, 0xe4, 0xfa, 0x64, 0x68, 0x7a, 0x61, + 0x99, 0x9f, 0xcc, 0x7c, 0x53, 0x24, 0x3b, 0xcb, 0x69, 0x36, 0x1f, 0xa9, + 0x4d, 0x66, 0xce, 0x14, 0x72, 0x8c, 0xe7, 0x1c, 0x95, 0xe6, 0x9c, 0x2d, + 0xb8, 0x9d, 0x6c, 0xd2, 0x49, 0x76, 0x9f, 0x58, 0x52, 0x4a, 0xf3, 0x4a, + 0xa3, 0x1d, 0x0d, 0xb9, 0x9d, 0x61, 0x98, 0xfa, 0x7b, 0x54, 0x8b, 0x27, + 0xad, 0x19, 0x7b, 0x75, 0x8e, 0xe7, 0x1f, 0x35, 0xb5, 0x94, 0xf2, 0xf5, + 0x9e, 0xbc, 0xa0, 0x79, 0x91, 0x6d, 0x6a, 0xea, 0x23, 0x74, 0x77, 0x33, + 0x6a, 0xd8, 0x86, 0x2a, 0xbe, 0x6e, 0xb9, 0x06, 0xe9, 0x6d, 0x33, 0xdd, + 0x73, 0x30, 0x13, 0xdb, 0xa9, 0x8f, 0x6f, 0xf6, 0x90, 0xb9, 0xd4, 0x7b, + 0x34, 0x46, 0xf5, 0xb9, 0x17, 0x50, 0x2e, 0xaf, 0x84, 0xdb, 0x57, 0x86, + 0xfe, 0x75, 0x95, 0x30, 0xed, 0xf7, 0xc4, 0x6c, 0xe8, 0xd2, 0x54, 0xff, + 0x85, 0x95, 0x98, 0x36, 0x5e, 0xf7, 0x4c, 0xea, 0xf3, 0x12, 0xa3, 0xa9, + 0xd9, 0xd0, 0x01, 0x7b, 0xda, 0xf2, 0x49, 0xe7, 0xf7, 0xe0, 0x1e, 0x53, + 0x30, 0xdd, 0xb2, 0xd9, 0x33, 0xbb, 0x96, 0x84, 0x92, 0xdd, 0x09, 0x31, + 0xbd, 0xe4, 0xa2, 0x6c, 0x32, 0x73, 0x85, 0x48, 0xae, 0x2f, 0x11, 0xbf, + 0x22, 0x9e, 0xc9, 0xcc, 0x37, 0x04, 0xe7, 0xcf, 0xc9, 0xb9, 0xfb, 0x15, + 0x32, 0xa3, 0x76, 0x82, 0x62, 0x8f, 0xe3, 0x55, 0x27, 0x3f, 0xf2, 0x3d, + 0xcb, 0x80, 0xea, 0x58, 0x89, 0x31, 0xba, 0x37, 0xf6, 0x50, 0x1e, 0x1d, + 0xb4, 0x39, 0xe7, 0xe4, 0x91, 0x52, 0xcb, 0x6a, 0x39, 0x40, 0xb7, 0xd3, + 0xa3, 0x94, 0xe3, 0x94, 0xf3, 0xc6, 0x24, 0xf5, 0xe2, 0xa9, 0x5a, 0x15, + 0x55, 0xce, 0x11, 0xca, 0x75, 0x42, 0x2a, 0xb7, 0xf4, 0x3e, 0x30, 0xfe, + 0x16, 0xa0, 0xd6, 0x00, 0xcd, 0xe6, 0x84, 0x33, 0x23, 0xa7, 0xa8, 0x7e, + 0x0c, 0xf8, 0x8c, 0x67, 0xf5, 0x3d, 0x82, 0x3f, 0xc8, 0x93, 0x55, 0x8c, + 0x9f, 0xc1, 0x86, 0x34, 0xc4, 0xe3, 0x76, 0x0c, 0x46, 0x8d, 0x8e, 0x7e, + 0xea, 0xe7, 0x8a, 0x63, 0xcd, 0x8c, 0x72, 0x7f, 0xab, 0x81, 0x5b, 0x41, + 0xf3, 0x46, 0x51, 0x86, 0xd3, 0x2c, 0x03, 0xc1, 0x22, 0x71, 0xe3, 0xf0, + 0x42, 0x71, 0x03, 0xdf, 0x01, 0x52, 0x58, 0x55, 0x86, 0x26, 0xfb, 0x34, + 0xad, 0x72, 0xce, 0x46, 0x9d, 0x88, 0x38, 0x31, 0x0c, 0x3d, 0x67, 0x53, + 0xe7, 0xaf, 0x92, 0xf2, 0x60, 0xca, 0x40, 0xde, 0x2e, 0xa1, 0x99, 0x3a, + 0x8c, 0x2a, 0x0b, 0x7a, 0xc2, 0xb1, 0xee, 0x39, 0x8c, 0xaf, 0xc0, 0xa8, + 0x43, 0x54, 0xa5, 0x7e, 0x4c, 0x6b, 0x62, 0xdc, 0x2e, 0xa3, 0x39, 0x5f, + 0x20, 0xe1, 0x24, 0xb0, 0xdd, 0xe7, 0x7a, 0x60, 0xf5, 0x1d, 0xa6, 0x1a, + 0x50, 0xac, 0x79, 0x3f, 0xa0, 0xb9, 0x47, 0x34, 0x54, 0x3a, 0xbc, 0xcf, + 0xeb, 0x97, 0xf3, 0x7c, 0x5e, 0x98, 0xc5, 0xb6, 0xd3, 0xbe, 0xe4, 0xde, + 0x5e, 0x83, 0x18, 0xc9, 0x9b, 0x18, 0xa5, 0xfb, 0x02, 0xdb, 0x28, 0xe2, + 0x90, 0xe6, 0x75, 0xd0, 0xcb, 0x1c, 0xcb, 0x7d, 0x08, 0x5d, 0x40, 0x35, + 0xcf, 0x11, 0xd0, 0x4a, 0x1c, 0x1b, 0xcf, 0x7a, 0xdf, 0xa7, 0xb3, 0x90, + 0x79, 0xd7, 0x86, 0x46, 0xfc, 0x90, 0xa0, 0xbc, 0x8c, 0xb5, 0x53, 0x2c, + 0x50, 0xff, 0x3f, 0x60, 0x23, 0xd6, 0xe0, 0x58, 0xc7, 0x8e, 0x50, 0x2c, + 0x18, 0x0b, 0xa0, 0x28, 0xa9, 0x57, 0xc0, 0xf3, 0xbb, 0xea, 0xf0, 0xde, + 0x04, 0x4e, 0xea, 0x88, 0x95, 0x38, 0x56, 0xd7, 0x38, 0x05, 0x82, 0xee, + 0x3c, 0x04, 0xbb, 0xaa, 0x90, 0x93, 0xc4, 0xa7, 0x93, 0xf8, 0x80, 0xeb, + 0xa0, 0x16, 0xa5, 0xe7, 0x17, 0x9b, 0xa4, 0x8c, 0x35, 0x5b, 0xbd, 0x79, + 0x98, 0x3d, 0x93, 0x42, 0xc5, 0xce, 0xdd, 0x5c, 0xf3, 0xa6, 0x4c, 0x6a, + 0x9f, 0xd4, 0xb7, 0xa3, 0xa2, 0xe4, 0x3e, 0x05, 0xcd, 0xcb, 0x54, 0xbc, + 0x48, 0x35, 0xef, 0xd9, 0x14, 0xdf, 0xef, 0x5b, 0x63, 0xc5, 0xb9, 0x9e, + 0x7c, 0xff, 0x51, 0xbd, 0x98, 0xbf, 0x93, 0x19, 0x54, 0x33, 0xac, 0xae, + 0x87, 0xb1, 0x4b, 0x1a, 0x55, 0xec, 0x43, 0x9a, 0x85, 0x68, 0xd6, 0xac, + 0xa4, 0x5a, 0x99, 0xeb, 0xb0, 0x5a, 0x28, 0x9c, 0xdd, 0x8d, 0x1d, 0x0d, + 0xe4, 0x6f, 0x8e, 0x03, 0x59, 0xa9, 0x14, 0xfc, 0x24, 0xe5, 0x75, 0xe9, + 0xd6, 0x63, 0x6f, 0x87, 0x0e, 0xd2, 0x9c, 0xcb, 0x36, 0xbe, 0x9c, 0xf6, + 0xd9, 0xfe, 0x51, 0x91, 0xba, 0xdf, 0xa5, 0xde, 0xc0, 0x67, 0x4a, 0x99, + 0x6c, 0xa3, 0x83, 0xca, 0x43, 0x34, 0x23, 0x22, 0xf3, 0xba, 0x07, 0x11, + 0x6b, 0xdf, 0x54, 0xb0, 0xc3, 0xe3, 0x76, 0x2d, 0xc5, 0x01, 0x62, 0x9a, + 0x63, 0xe9, 0x74, 0x71, 0x56, 0x1a, 0x9c, 0x2a, 0x5c, 0x47, 0xd2, 0x64, + 0x7d, 0xce, 0xb7, 0x4e, 0xec, 0xf7, 0xf8, 0xfb, 0x47, 0x27, 0x36, 0x12, + 0x8f, 0x49, 0xcb, 0x22, 0x1d, 0xcd, 0xf5, 0x03, 0x22, 0x2a, 0x9e, 0x1f, + 0x22, 0x3d, 0x77, 0x33, 0x6f, 0x15, 0xcd, 0x4d, 0x2a, 0x56, 0x35, 0xf1, + 0x4c, 0x3c, 0x65, 0xaa, 0x60, 0xfd, 0xfe, 0x24, 0x9b, 0xdb, 0x98, 0xce, + 0xa2, 0xbb, 0x87, 0xa0, 0x5a, 0x97, 0xc5, 0x66, 0x5d, 0xa0, 0xcf, 0xa6, + 0x28, 0x5e, 0xa0, 0xc2, 0x6e, 0x53, 0xd1, 0x6b, 0xef, 0x05, 0x85, 0x06, + 0xd5, 0x38, 0x0d, 0x9b, 0xec, 0x2c, 0xdc, 0x38, 0xfb, 0xf2, 0x1f, 0x25, + 0xae, 0x66, 0xbb, 0xec, 0x98, 0xb3, 0xd1, 0x9e, 0xc2, 0xb7, 0x82, 0x23, + 0x3e, 0xe3, 0x45, 0xc5, 0xa9, 0x21, 0x57, 0xb0, 0x3e, 0x1f, 0xdb, 0x93, + 0x75, 0x62, 0x19, 0xea, 0xc4, 0xce, 0x61, 0x64, 0x76, 0x74, 0x48, 0xb9, + 0x39, 0x65, 0x76, 0xbd, 0x00, 0x05, 0xc9, 0xe1, 0x30, 0x9e, 0x5e, 0xd2, + 0x27, 0x5d, 0x7d, 0x85, 0x49, 0x79, 0xae, 0x53, 0x54, 0x63, 0xa0, 0xd9, + 0x9c, 0x59, 0x49, 0x5c, 0x7f, 0xe7, 0x37, 0xe0, 0x0d, 0x9b, 0x62, 0xcc, + 0x52, 0xfb, 0x3a, 0x43, 0xdc, 0xf7, 0x37, 0x12, 0x9f, 0x26, 0xb7, 0x52, + 0xb1, 0x7a, 0x26, 0x28, 0xcf, 0x2a, 0x9c, 0x1e, 0xb9, 0xb3, 0x96, 0x63, + 0x10, 0x4a, 0x34, 0xf5, 0x35, 0x39, 0x55, 0xcb, 0xb1, 0xc8, 0x73, 0x59, + 0x54, 0xe8, 0xc3, 0x7c, 0x3e, 0xcf, 0x69, 0x2a, 0xc2, 0x49, 0x29, 0xc7, + 0xed, 0xcd, 0x24, 0x2b, 0xcb, 0x30, 0x2f, 0xeb, 0x26, 0x99, 0xa9, 0x42, + 0x2c, 0xea, 0x58, 0xbd, 0x93, 0x54, 0xa3, 0x23, 0x4e, 0x2b, 0xdd, 0x7b, + 0xaf, 0x93, 0xc5, 0x39, 0x94, 0xfb, 0x7e, 0x54, 0x8c, 0x0f, 0x31, 0x0f, + 0xf6, 0xcd, 0xb9, 0x7a, 0x40, 0xa3, 0xfb, 0x33, 0x26, 0xb2, 0x02, 0xfb, + 0x52, 0x7d, 0xb2, 0x47, 0x67, 0x7e, 0x51, 0xf1, 0xec, 0xd0, 0xc7, 0x67, + 0x7e, 0x1a, 0x7f, 0xef, 0x9c, 0x9d, 0xbe, 0x54, 0x8c, 0x09, 0xbf, 0x18, + 0xa3, 0x25, 0xce, 0xcb, 0x14, 0xfb, 0xca, 0x6a, 0xba, 0x9d, 0x41, 0x4f, + 0x09, 0x3c, 0xd5, 0x29, 0x70, 0xdd, 0x12, 0x9a, 0xc1, 0x96, 0x5a, 0x14, + 0x27, 0xd7, 0x48, 0x63, 0xc1, 0x14, 0x05, 0xdc, 0xac, 0x2c, 0x4d, 0xaa, + 0x78, 0x67, 0x09, 0x25, 0xd1, 0x55, 0x1c, 0xab, 0x0a, 0x5e, 0x20, 0xbc, + 0xd5, 0x17, 0x59, 0x5d, 0x47, 0x51, 0x01, 0xe3, 0x2b, 0xbc, 0xb6, 0x62, + 0x43, 0x18, 0xad, 0x09, 0x1d, 0x16, 0xf9, 0xbc, 0x86, 0x67, 0x69, 0x92, + 0x9f, 0x69, 0xe7, 0x63, 0xdb, 0x2b, 0xc8, 0xd1, 0xbc, 0x8c, 0x9f, 0x59, + 0xbe, 0x8f, 0xdf, 0x07, 0x86, 0x58, 0x3e, 0xf6, 0x17, 0xf9, 0x9a, 0x64, + 0x2e, 0x49, 0xcd, 0xc7, 0xc5, 0x6d, 0x73, 0xb2, 0x46, 0x69, 0xae, 0x61, + 0x9a, 0x62, 0x0c, 0x9d, 0xa0, 0xf8, 0x19, 0xff, 0x08, 0x87, 0x2c, 0x58, + 0xce, 0xe7, 0x70, 0xac, 0x08, 0x60, 0xad, 0x82, 0xd4, 0x32, 0x9e, 0x11, + 0x28, 0x06, 0x86, 0xcd, 0x4e, 0x43, 0x59, 0x44, 0xfb, 0x4c, 0x1b, 0x25, + 0xbf, 0xf3, 0x7b, 0xf1, 0x9c, 0x5b, 0x9a, 0x38, 0xce, 0x5b, 0xe7, 0xfc, + 0xf1, 0x0b, 0xbd, 0x38, 0xc3, 0x46, 0xa9, 0xe7, 0x81, 0xf6, 0x19, 0x4f, + 0xc5, 0x1a, 0xc6, 0x49, 0xcd, 0xe3, 0xcc, 0xc7, 0xe8, 0xbf, 0x10, 0xee, + 0x9f, 0x64, 0xaa, 0x8d, 0xfb, 0x75, 0x54, 0x5c, 0x37, 0xc4, 0xb8, 0x45, + 0x7b, 0x7f, 0xd8, 0x4c, 0xf8, 0xed, 0xe7, 0xe2, 0xbf, 0xfc, 0x09, 0xfc, + 0xcf, 0xf4, 0x77, 0x82, 0x2e, 0xb1, 0xc3, 0xa3, 0x0b, 0xbf, 0xa5, 0x5c, + 0x56, 0x4e, 0x79, 0xfd, 0x10, 0xf5, 0xf9, 0x83, 0x23, 0x5d, 0x62, 0x3b, + 0x99, 0xe7, 0xc0, 0xd8, 0x2a, 0x71, 0xb7, 0x67, 0xf1, 0x2c, 0x39, 0xd7, + 0xf3, 0x8b, 0xdf, 0xf7, 0xb6, 0x7d, 0xea, 0xbb, 0x5d, 0xa4, 0x47, 0x77, + 0xd0, 0x5d, 0x3f, 0x78, 0x97, 0x6c, 0xb0, 0xb8, 0x9e, 0x59, 0x53, 0x17, + 0x87, 0x22, 0x9d, 0xb1, 0xe5, 0x21, 0x44, 0x2d, 0x74, 0xc7, 0x68, 0xd6, + 0x7a, 0xb1, 0xd0, 0xe3, 0x0c, 0x18, 0xb9, 0x81, 0xda, 0x62, 0x0c, 0x48, + 0x49, 0x75, 0x5f, 0xad, 0x74, 0xd0, 0x53, 0xe2, 0x94, 0x68, 0x97, 0x74, + 0x44, 0x90, 0xeb, 0xe8, 0xaa, 0x3f, 0x9e, 0xbb, 0xac, 0xfe, 0xb9, 0x5c, + 0x5d, 0x0f, 0xdd, 0x7d, 0xeb, 0x7f, 0xe6, 0x01, 0x67, 0x48, 0x86, 0xb0, + 0x73, 0xa5, 0xbb, 0x2f, 0x0d, 0xa5, 0xb7, 0xc3, 0x32, 0x16, 0x8b, 0x75, + 0xeb, 0x48, 0x87, 0xfa, 0x63, 0xb9, 0x3b, 0xd7, 0x85, 0x26, 0xa9, 0xdb, + 0xe9, 0xb8, 0xf3, 0xed, 0xf4, 0x9d, 0xd8, 0xe2, 0xf5, 0x61, 0x93, 0x17, + 0x2f, 0xd4, 0xa8, 0x5d, 0x2c, 0x93, 0xcf, 0xdf, 0xec, 0x58, 0xd6, 0x08, + 0xb6, 0xe6, 0x55, 0xbc, 0x55, 0xd8, 0x33, 0x13, 0xab, 0xf1, 0x31, 0xee, + 0x67, 0xf1, 0x3e, 0xf9, 0x2d, 0x91, 0x63, 0x06, 0x99, 0xd0, 0xa0, 0x94, + 0x4a, 0x9a, 0xef, 0x7f, 0xd3, 0x34, 0x0b, 0x73, 0x8d, 0x79, 0x0f, 0xfb, + 0xad, 0x05, 0xfc, 0x2d, 0x91, 0x21, 0x53, 0x3a, 0xc8, 0x7b, 0xa7, 0xe7, + 0xf6, 0xde, 0xa1, 0x3d, 0x88, 0x53, 0xd4, 0xab, 0xa8, 0x8e, 0x17, 0xf6, + 0xcb, 0x07, 0x23, 0xf8, 0x7b, 0x9f, 0x71, 0x4e, 0xce, 0xe1, 0xfc, 0x8a, + 0x70, 0xe2, 0x58, 0x53, 0x05, 0xb7, 0x92, 0x73, 0x6b, 0x78, 0xfe, 0x5b, + 0x23, 0xe5, 0x89, 0xfd, 0x61, 0xb4, 0xf8, 0xad, 0x31, 0x2a, 0xb4, 0xfb, + 0xe8, 0x39, 0xca, 0x71, 0xc8, 0xb1, 0xca, 0xf4, 0xc7, 0x53, 0x45, 0xfa, + 0x63, 0x29, 0xa6, 0xff, 0x2c, 0x8d, 0x9a, 0x89, 0x0c, 0xc6, 0xa9, 0xfe, + 0xbe, 0x4b, 0xb5, 0xa0, 0xc8, 0xbb, 0x48, 0xf7, 0x4f, 0x73, 0x74, 0x87, + 0x89, 0xee, 0x0f, 0x14, 0x87, 0x4c, 0xcb, 0x7a, 0x72, 0x6e, 0xcc, 0xfb, + 0xaf, 0x45, 0x1c, 0xf2, 0x0c, 0x1c, 0xca, 0xa9, 0x62, 0x1f, 0xd5, 0xda, + 0x31, 0xba, 0xb7, 0x0c, 0x14, 0xbe, 0xa5, 0xea, 0x64, 0x93, 0x17, 0xaa, + 0x8a, 0xfe, 0xe2, 0xef, 0xcb, 0x53, 0x58, 0xe1, 0x25, 0xa9, 0xf7, 0x6b, + 0x05, 0x9d, 0x4a, 0x9d, 0xa7, 0xf1, 0x5b, 0xaa, 0x97, 0xa7, 0x0a, 0xdf, + 0x6f, 0x9e, 0x46, 0x32, 0xc7, 0x73, 0x8f, 0x25, 0x36, 0x79, 0x46, 0x8f, + 0x42, 0xbc, 0x57, 0xe5, 0x8a, 0x35, 0x84, 0xfa, 0x5b, 0x86, 0x6a, 0xb3, + 0x78, 0xa6, 0xf0, 0x5e, 0x43, 0x3d, 0x8f, 0x65, 0xc8, 0x88, 0x44, 0xd2, + 0x45, 0x43, 0xd2, 0x95, 0xaa, 0x65, 0x1d, 0x53, 0x43, 0x96, 0xfe, 0x4e, + 0x28, 0x73, 0x8b, 0x82, 0xbb, 0xf0, 0x7e, 0x7b, 0xe6, 0x6f, 0xea, 0xe9, + 0x6f, 0x65, 0x3b, 0x8c, 0x0a, 0xca, 0xf3, 0x1b, 0x3a, 0x9a, 0x32, 0x2f, + 0x89, 0xa6, 0xee, 0xac, 0x68, 0x72, 0xd7, 0x88, 0xa6, 0xce, 0x32, 0x61, + 0x6b, 0xcf, 0x51, 0x13, 0x7f, 0x39, 0x37, 0x6f, 0x07, 0xf6, 0x1f, 0xdb, + 0x80, 0xc2, 0xdc, 0xb1, 0x32, 0x8b, 0x45, 0x8c, 0xee, 0xfe, 0x9c, 0x0f, + 0x0d, 0xa0, 0x5e, 0x74, 0x36, 0xd7, 0xd1, 0xba, 0x7e, 0x97, 0x28, 0xa3, + 0x7a, 0xa0, 0x63, 0x2f, 0xcd, 0x27, 0x0d, 0x16, 0xc7, 0x27, 0x35, 0xc8, + 0x05, 0x2c, 0xcf, 0xcf, 0x23, 0x45, 0xfd, 0xd6, 0x55, 0x17, 0xf3, 0x4f, + 0x50, 0x9d, 0x83, 0x16, 0xa3, 0x58, 0x7d, 0x9f, 0xea, 0xda, 0xef, 0x9a, + 0x8a, 0x71, 0xbb, 0x94, 0xbf, 0x03, 0x17, 0xf0, 0x8e, 0x4b, 0xba, 0x5b, + 0x91, 0x4e, 0xe7, 0x31, 0x3e, 0xe9, 0x3b, 0x55, 0xfd, 0x69, 0xfa, 0xa2, + 0x6d, 0x15, 0x9a, 0x01, 0x8e, 0xe4, 0x33, 0x62, 0xb5, 0x87, 0x2d, 0xa1, + 0x82, 0xfe, 0x06, 0x56, 0xe7, 0xba, 0xc4, 0x2a, 0xcf, 0x32, 0x06, 0xc8, + 0x06, 0xdb, 0xf4, 0x56, 0x7d, 0x8c, 0xea, 0x16, 0xf1, 0x32, 0x4a, 0x29, + 0x07, 0x34, 0x67, 0x01, 0xee, 0x99, 0x8b, 0x29, 0xca, 0x0b, 0xb7, 0xcc, + 0xe9, 0x13, 0x8b, 0x27, 0xf8, 0x95, 0xf8, 0x7c, 0xa4, 0xdf, 0x87, 0x72, + 0xfb, 0x55, 0xbc, 0xdf, 0x3f, 0xe7, 0x93, 0x9b, 0xf9, 0x4c, 0x7a, 0x3f, + 0x35, 0x27, 0xc3, 0xff, 0x44, 0x3b, 0x71, 0xfe, 0xa7, 0x69, 0x78, 0xae, + 0xe3, 0x3b, 0x05, 0xdc, 0x6a, 0x87, 0x67, 0xba, 0x85, 0x73, 0xb1, 0x30, + 0x4c, 0xbc, 0xb7, 0xe0, 0xca, 0x65, 0x40, 0xf3, 0xe0, 0x42, 0x6c, 0xcf, + 0x03, 0x2d, 0x83, 0x3c, 0x63, 0xcf, 0xc2, 0xcb, 0x42, 0x2b, 0x73, 0x66, + 0x70, 0x61, 0xb6, 0xb1, 0xb7, 0x54, 0x98, 0x2d, 0x59, 0x61, 0x76, 0x03, + 0xad, 0x34, 0x7d, 0x98, 0x89, 0xc5, 0xc2, 0x34, 0x36, 0x83, 0x6d, 0x35, + 0x8b, 0xa6, 0x42, 0xae, 0xcf, 0xc0, 0x22, 0x7f, 0x77, 0x0f, 0x86, 0xa0, + 0xb4, 0xfd, 0x8e, 0x6c, 0x66, 0x76, 0x42, 0x2c, 0xa4, 0xf9, 0x96, 0x63, + 0x72, 0x16, 0x5b, 0xa9, 0x4f, 0xd7, 0x13, 0xce, 0xe7, 0xa9, 0x07, 0x34, + 0x0e, 0x9a, 0x33, 0x80, 0xd9, 0x77, 0x71, 0xa8, 0xb1, 0xa5, 0x17, 0xe6, + 0x96, 0x6d, 0x68, 0x9d, 0x7a, 0x46, 0x98, 0x99, 0x19, 0x21, 0x50, 0xda, + 0x56, 0xe4, 0xb9, 0x74, 0x8e, 0x67, 0x0b, 0xdf, 0x37, 0x0a, 0xb9, 0x45, + 0x77, 0x92, 0xb6, 0x5f, 0xc8, 0xa9, 0x82, 0xcd, 0xfe, 0x7a, 0x4e, 0xff, + 0xec, 0x9c, 0x0f, 0xd4, 0xb9, 0xf7, 0x9f, 0x54, 0x73, 0x7d, 0x2f, 0x69, + 0x2b, 0xcc, 0xe3, 0x14, 0x97, 0x5f, 0x44, 0x3f, 0xcd, 0x7e, 0x99, 0x02, + 0x7d, 0x17, 0x7a, 0x72, 0x10, 0x9b, 0xbd, 0xa9, 0xd2, 0x67, 0x68, 0xaa, + 0x1e, 0x29, 0xf0, 0xb9, 0x8c, 0xd6, 0xba, 0xe9, 0xc7, 0x36, 0xfb, 0xaf, + 0x4a, 0xbe, 0x3d, 0x38, 0xaa, 0xfb, 0x4a, 0xf3, 0xbb, 0xfd, 0x90, 0x5a, + 0xef, 0xab, 0x27, 0x2d, 0x03, 0x56, 0x37, 0x7d, 0x5b, 0x6a, 0x5b, 0xb2, + 0xb9, 0x0d, 0xcd, 0x22, 0x7b, 0xb5, 0x4b, 0x1b, 0x84, 0x2c, 0x82, 0xb1, + 0x65, 0x1b, 0xc7, 0xb8, 0xd6, 0xb5, 0x56, 0xb0, 0x31, 0x18, 0x3b, 0x89, + 0xec, 0xe1, 0x0f, 0x25, 0x9e, 0x1d, 0xf5, 0x48, 0x20, 0x04, 0xf4, 0x4b, + 0x12, 0x2c, 0xb0, 0x55, 0x53, 0x6e, 0xf4, 0x00, 0xe2, 0xb4, 0x24, 0xbc, + 0x99, 0xd4, 0x2a, 0xa9, 0x9a, 0xb1, 0x62, 0xc4, 0x2b, 0x36, 0xc6, 0x9e, + 0xc9, 0x6c, 0x91, 0x2d, 0xbb, 0xcc, 0x40, 0x00, 0x27, 0x7e, 0xe1, 0xcc, + 0x4c, 0x2c, 0xc6, 0x89, 0xef, 0x7e, 0xe7, 0xde, 0x6e, 0x10, 0x84, 0xc4, + 0x35, 0x54, 0xa9, 0xda, 0xdd, 0xf7, 0xf7, 0x3c, 0xbf, 0x73, 0xbe, 0xf3, + 0x9d, 0x73, 0x7e, 0xd7, 0x92, 0xcb, 0x58, 0xcb, 0xff, 0x0e, 0x9b, 0xed, + 0x36, 0x45, 0xd1, 0x98, 0x1b, 0xbc, 0x6a, 0x9c, 0x53, 0x2d, 0x1d, 0xb1, + 0x99, 0x1c, 0xbd, 0x59, 0x9e, 0x25, 0x25, 0x77, 0xb3, 0x3e, 0xe4, 0xf7, + 0x74, 0x9b, 0xbc, 0xdf, 0x83, 0x67, 0xd2, 0x1e, 0x6c, 0x20, 0xb6, 0xa6, + 0x4c, 0x6c, 0xbd, 0x1e, 0x1f, 0xd9, 0xd8, 0x6e, 0x05, 0xdb, 0xf5, 0x64, + 0xb8, 0x53, 0x73, 0xfa, 0xac, 0xa9, 0x2b, 0x8e, 0x26, 0x39, 0x07, 0x91, + 0xbd, 0xc4, 0x76, 0xd9, 0xd8, 0x57, 0xce, 0x24, 0xac, 0x0c, 0x46, 0x5b, + 0x95, 0xfe, 0x68, 0x31, 0xe7, 0x8b, 0x28, 0xc9, 0x90, 0x6d, 0x77, 0x29, + 0xe3, 0xa9, 0x15, 0x8b, 0x56, 0x12, 0x7f, 0xb4, 0x80, 0x66, 0x2b, 0xc1, + 0xb3, 0x81, 0x39, 0x98, 0x52, 0x97, 0x62, 0x73, 0x20, 0x87, 0x5c, 0x69, + 0x3f, 0x36, 0xaa, 0xb9, 0xd8, 0x14, 0xf8, 0x0b, 0xe0, 0xe1, 0x3c, 0xea, + 0xb1, 0xc5, 0x39, 0x73, 0x38, 0x6f, 0x1e, 0x31, 0xe3, 0x39, 0x73, 0xdf, + 0xe3, 0xb2, 0x57, 0xae, 0xb3, 0x59, 0x49, 0x12, 0xf3, 0x2b, 0x4c, 0xdb, + 0x9d, 0xf9, 0x7e, 0x28, 0x65, 0xe6, 0x60, 0x5f, 0x5e, 0x6c, 0xca, 0xf9, + 0xf7, 0xdf, 0xd7, 0xd3, 0xab, 0xcb, 0xc9, 0xd3, 0xa9, 0x3f, 0xcb, 0x11, + 0xae, 0x5c, 0x82, 0xe7, 0x03, 0x8d, 0x28, 0xd2, 0x9a, 0xf1, 0x6d, 0x35, + 0x42, 0x4c, 0x1f, 0xc2, 0x77, 0xcc, 0x31, 0x64, 0x3c, 0xb3, 0x66, 0xc4, + 0x7f, 0xbf, 0xb3, 0x43, 0xfb, 0xba, 0xf8, 0xd2, 0xca, 0xc9, 0xb4, 0xdb, + 0x9c, 0xe8, 0x19, 0x90, 0x4f, 0x07, 0xbe, 0x13, 0xb2, 0x72, 0xb0, 0xf1, + 0x21, 0x27, 0x62, 0x03, 0x0e, 0xa4, 0x83, 0x64, 0x3f, 0x95, 0x37, 0x8f, + 0x3d, 0xc4, 0xb1, 0xad, 0xbc, 0xc5, 0x77, 0x29, 0xd7, 0x73, 0x4e, 0x27, + 0xb9, 0x10, 0xd4, 0x0a, 0xb6, 0x29, 0x1f, 0x2f, 0x80, 0x7b, 0x48, 0xea, + 0x4e, 0x93, 0xca, 0x96, 0xb4, 0xd5, 0xe6, 0x7b, 0x52, 0xab, 0xca, 0xb5, + 0x81, 0xbe, 0x88, 0xdb, 0x75, 0xb0, 0x8d, 0x8b, 0x71, 0x71, 0x3e, 0x6a, + 0x86, 0x0a, 0xf8, 0xa7, 0xa2, 0xf4, 0x20, 0x1f, 0x8c, 0x37, 0x2b, 0x2f, + 0x46, 0x03, 0x28, 0x65, 0xbc, 0x5e, 0xd6, 0x64, 0xf5, 0x7f, 0x29, 0xfd, + 0x75, 0xeb, 0x77, 0xa2, 0xbd, 0x54, 0xce, 0xab, 0x06, 0x85, 0xda, 0x94, + 0xf1, 0x82, 0x85, 0xf1, 0xa6, 0x2f, 0xed, 0xbe, 0x56, 0xe7, 0x92, 0x35, + 0x29, 0xc2, 0x5b, 0xd5, 0xf2, 0x26, 0x89, 0x9b, 0xf9, 0xa3, 0x19, 0x77, + 0xcb, 0x1a, 0x64, 0xec, 0x7c, 0xe4, 0x0e, 0xc9, 0xd8, 0x05, 0xc8, 0xb9, + 0xb6, 0x16, 0x99, 0x87, 0x61, 0xde, 0xb8, 0xf8, 0x57, 0x99, 0x6f, 0x52, + 0x19, 0x4c, 0xcb, 0x1a, 0xb2, 0xf3, 0x9e, 0x32, 0x9e, 0x51, 0x0b, 0xe8, + 0xcf, 0x87, 0x8d, 0x0d, 0x15, 0x86, 0xe1, 0x5f, 0x74, 0xdc, 0x48, 0xad, + 0x35, 0xb1, 0xd6, 0xd8, 0x9d, 0x70, 0x62, 0x17, 0xe5, 0xb6, 0x39, 0x78, + 0x58, 0x78, 0x5c, 0xe6, 0x5f, 0x56, 0x6e, 0x47, 0x28, 0xb7, 0xb9, 0x99, + 0x73, 0x9c, 0x54, 0x8e, 0x5e, 0xf3, 0xf7, 0xb2, 0x46, 0x59, 0x97, 0x82, + 0x72, 0x4d, 0xd6, 0x65, 0x43, 0x99, 0x96, 0x8f, 0x72, 0xca, 0xa7, 0xcc, + 0x5c, 0x53, 0xb3, 0xf2, 0x6e, 0x14, 0x6a, 0x09, 0xb9, 0x43, 0xe9, 0xb8, + 0xb5, 0xae, 0x29, 0xca, 0xe7, 0xcc, 0x35, 0x9d, 0x98, 0x2d, 0x67, 0xa1, + 0x57, 0x62, 0xd3, 0x33, 0xdf, 0xdf, 0x9a, 0x94, 0x71, 0xed, 0x74, 0x9c, + 0x0a, 0xb6, 0x87, 0xc4, 0x5f, 0xe0, 0xe5, 0xe5, 0x51, 0x4b, 0x06, 0x36, + 0xf3, 0x0c, 0xc4, 0x06, 0x64, 0xff, 0xd9, 0xbd, 0x37, 0x2b, 0x4f, 0x45, + 0xa5, 0xbf, 0x86, 0x1a, 0xb3, 0x9f, 0x15, 0x37, 0xdb, 0xa8, 0x7f, 0xcb, + 0x79, 0x36, 0xb6, 0x71, 0x4b, 0x37, 0x3d, 0xa9, 0x56, 0xce, 0x2b, 0xe7, + 0x34, 0xa9, 0x74, 0x72, 0x4e, 0x98, 0x67, 0xfb, 0x5f, 0xcb, 0x2d, 0x5b, + 0x9f, 0xa4, 0x6d, 0xf2, 0x37, 0xa7, 0x8d, 0xfa, 0x5e, 0x00, 0xc7, 0x90, + 0xcb, 0xcc, 0xf1, 0xc8, 0xd8, 0xcf, 0x45, 0xcb, 0x90, 0x77, 0x30, 0xdb, + 0xd7, 0xf2, 0xed, 0x56, 0x8d, 0x30, 0x6b, 0x8f, 0x82, 0x8f, 0xe2, 0x27, + 0x22, 0x4a, 0xf8, 0x5a, 0x9d, 0x4f, 0x72, 0x5f, 0x52, 0xff, 0xcc, 0xe5, + 0x7a, 0x24, 0x7f, 0xaa, 0x10, 0x33, 0x6c, 0xc4, 0xe9, 0xe5, 0x1e, 0x07, + 0x71, 0x6e, 0x03, 0xbe, 0x34, 0x22, 0x15, 0xe1, 0x80, 0x13, 0x56, 0x8c, + 0xde, 0x8e, 0x5c, 0x58, 0x18, 0x44, 0x2d, 0x8d, 0xd2, 0x1f, 0x73, 0xaf, + 0xe4, 0x00, 0xe8, 0x4e, 0x7f, 0x69, 0x4c, 0x55, 0x38, 0xe8, 0xf3, 0xaf, + 0xe5, 0xd6, 0x68, 0x77, 0x86, 0x31, 0xcc, 0x67, 0xbd, 0xe9, 0xec, 0x39, + 0x91, 0x5b, 0x90, 0x6b, 0x3e, 0xad, 0xfd, 0xbb, 0xb1, 0xfe, 0x86, 0xb6, + 0x59, 0x6c, 0xb6, 0x62, 0xed, 0x23, 0x26, 0x36, 0x17, 0xa2, 0x77, 0xb7, + 0x37, 0x99, 0x02, 0x79, 0x8b, 0x66, 0x9b, 0x2b, 0x31, 0x82, 0x1d, 0xde, + 0xbe, 0x66, 0xc6, 0xfa, 0xc4, 0x4e, 0x4f, 0x0a, 0xff, 0x5c, 0x2e, 0x76, + 0xc4, 0x78, 0xcd, 0x53, 0x6a, 0x2b, 0x93, 0xb5, 0x9b, 0xab, 0xb2, 0x0f, + 0xe4, 0x61, 0x43, 0x43, 0x1e, 0x52, 0x6d, 0xc4, 0xac, 0x81, 0x48, 0x2b, + 0x87, 0x77, 0xe5, 0x37, 0xbd, 0xf5, 0xbd, 0x6f, 0xf8, 0xbd, 0xf4, 0x93, + 0x40, 0x6e, 0x8c, 0x73, 0x22, 0x83, 0x69, 0x03, 0xde, 0x88, 0xcd, 0x26, + 0xfd, 0x7f, 0x6b, 0x90, 0x63, 0xb3, 0xaf, 0x8c, 0xc1, 0xb9, 0xff, 0xc8, + 0x16, 0x24, 0xee, 0xfb, 0xb2, 0x5c, 0xf2, 0x8e, 0x6a, 0xad, 0x82, 0xc2, + 0x81, 0x42, 0x14, 0x30, 0x4e, 0xdf, 0x55, 0xe9, 0xeb, 0xd0, 0x6d, 0xf9, + 0x38, 0x7d, 0xd7, 0x7f, 0x41, 0xaa, 0x32, 0x07, 0xae, 0x5a, 0x60, 0x45, + 0xdc, 0x06, 0x5b, 0x2d, 0xb1, 0x37, 0x04, 0x34, 0x8f, 0xf3, 0xdc, 0x06, + 0x14, 0x3c, 0x91, 0xb4, 0xe1, 0xc1, 0xa4, 0x1d, 0xab, 0x93, 0xf8, 0xab, + 0x1a, 0x60, 0xba, 0x1a, 0xfe, 0xf6, 0x19, 0x05, 0x9b, 0x8b, 0x61, 0xfa, + 0xf8, 0xd6, 0xd5, 0x8c, 0x4b, 0x57, 0x8d, 0x13, 0xcf, 0xd8, 0xd6, 0xc9, + 0x98, 0xcd, 0xd1, 0x6f, 0x47, 0x75, 0x3f, 0x6e, 0xcf, 0x05, 0x42, 0x4e, + 0xf8, 0x67, 0xe8, 0x67, 0xca, 0x1c, 0xf0, 0x4f, 0x9d, 0xb7, 0xfb, 0x3b, + 0xab, 0xed, 0x3c, 0xdc, 0x5a, 0x59, 0x8b, 0x0b, 0x0f, 0x51, 0x9f, 0x6b, + 0x06, 0xd8, 0xbe, 0xd6, 0x06, 0x55, 0x53, 0x70, 0xe5, 0x71, 0xc9, 0xfb, + 0xca, 0x33, 0xc9, 0x55, 0x28, 0x28, 0x1e, 0xb0, 0x13, 0xc3, 0xde, 0x34, + 0x4e, 0x57, 0x0a, 0x7e, 0x03, 0x4f, 0x70, 0x6d, 0x6e, 0xfe, 0xa6, 0xd6, + 0xba, 0xb0, 0x70, 0xa9, 0x8a, 0x75, 0x43, 0x5f, 0x9a, 0x3a, 0x25, 0xe3, + 0x38, 0x69, 0x53, 0x39, 0xb4, 0xf1, 0x83, 0x66, 0x0d, 0xd1, 0xc6, 0x3d, + 0xda, 0x51, 0x30, 0x00, 0xac, 0x8a, 0xe3, 0x91, 0x42, 0xf8, 0xc3, 0xb2, + 0xc6, 0xba, 0x25, 0x0e, 0xf6, 0x2d, 0x44, 0xeb, 0xb8, 0xd5, 0xef, 0xfe, + 0xf1, 0x92, 0x0a, 0x2b, 0x07, 0xfe, 0xa7, 0x6b, 0xda, 0x3d, 0x21, 0x3f, + 0x36, 0x24, 0xa9, 0x73, 0x36, 0x0f, 0x86, 0x32, 0xb9, 0xe8, 0xf5, 0x29, + 0xef, 0xac, 0x9a, 0xf3, 0xdf, 0x14, 0x66, 0xea, 0xd1, 0xb4, 0x85, 0x19, + 0x8e, 0x13, 0x51, 0xd6, 0x53, 0x76, 0x43, 0x13, 0x06, 0xa2, 0xba, 0x81, + 0x31, 0xfe, 0xbd, 0xad, 0x4b, 0xde, 0x63, 0x52, 0x79, 0x26, 0xf6, 0x95, + 0x11, 0xc9, 0xd8, 0xf3, 0x0f, 0x12, 0x01, 0x65, 0x53, 0x0c, 0x78, 0x95, + 0xfe, 0xf4, 0x10, 0xff, 0x46, 0x12, 0x92, 0x47, 0xa2, 0xec, 0x69, 0xd7, + 0xdb, 0x52, 0xc0, 0x70, 0x02, 0xe1, 0xfd, 0x4b, 0x84, 0xc3, 0x17, 0x70, + 0x3e, 0x5a, 0x0d, 0xdb, 0xa4, 0xf9, 0x77, 0x90, 0x7f, 0x13, 0x3c, 0x53, + 0xce, 0x87, 0xc0, 0x98, 0x03, 0xe1, 0x31, 0x02, 0xed, 0x58, 0x00, 0x53, + 0xf4, 0x81, 0x57, 0x47, 0x54, 0x14, 0x1d, 0x2a, 0xc3, 0xa7, 0xa3, 0xc4, + 0xc7, 0x03, 0x16, 0xef, 0xdf, 0x30, 0x26, 0xf5, 0x42, 0xd9, 0x9f, 0xd4, + 0xd7, 0xc5, 0x9e, 0xf2, 0x70, 0x28, 0x59, 0x66, 0xd6, 0xd8, 0x2f, 0xe8, + 0x1c, 0x5b, 0x95, 0xda, 0x68, 0x1b, 0x0e, 0x47, 0x7d, 0x9e, 0x3e, 0xea, + 0x7c, 0xc4, 0x21, 0x36, 0x16, 0xc2, 0xab, 0xd1, 0x6c, 0x8d, 0xcd, 0xc7, + 0x78, 0xd7, 0x09, 0x8f, 0xb3, 0x8c, 0xf2, 0x95, 0x67, 0x59, 0x5f, 0x2a, + 0x7b, 0x96, 0x7c, 0x7e, 0x96, 0xb7, 0xcc, 0xfe, 0xfd, 0xa4, 0x21, 0xb5, + 0xdf, 0xd7, 0x26, 0xbc, 0x7d, 0x29, 0xe8, 0xa6, 0xaf, 0x1c, 0xad, 0xf3, + 0x26, 0x23, 0x90, 0xf3, 0x0d, 0x71, 0x0d, 0x1f, 0x53, 0xf7, 0x03, 0x94, + 0xf5, 0x5f, 0xd3, 0xb7, 0x4b, 0x9e, 0xbc, 0x14, 0xbb, 0xfa, 0xcb, 0xb0, + 0xb3, 0x3f, 0x82, 0xde, 0x25, 0x6b, 0x71, 0x32, 0x6a, 0x60, 0x43, 0xd0, + 0xc0, 0xaa, 0xa0, 0x37, 0xf0, 0x03, 0xd4, 0x37, 0x1e, 0xc6, 0x43, 0xe4, + 0x10, 0x2a, 0x65, 0xf2, 0x24, 0x3e, 0xd8, 0xed, 0xc0, 0xb3, 0xfa, 0x37, + 0x69, 0xc3, 0x86, 0xf1, 0xab, 0xc5, 0xf3, 0x30, 0x94, 0xa8, 0x57, 0xbb, + 0xb9, 0xbe, 0xf0, 0x5a, 0x9e, 0x55, 0x83, 0x03, 0x1b, 0xf5, 0xbf, 0x62, + 0x5b, 0xb7, 0xcd, 0xa1, 0xc9, 0x77, 0x1b, 0xfd, 0xa9, 0x9c, 0x65, 0x84, + 0xfa, 0x65, 0xf9, 0xb2, 0x70, 0xa6, 0x3e, 0xf1, 0x6c, 0x48, 0x30, 0xbf, + 0x10, 0x27, 0x28, 0xb7, 0x37, 0x92, 0x61, 0x49, 0x45, 0x29, 0x1b, 0x43, + 0x5d, 0x78, 0x8a, 0x7c, 0xe3, 0x03, 0x12, 0x81, 0x7b, 0xe2, 0x0a, 0x1a, + 0xeb, 0x74, 0x9c, 0x4d, 0x3f, 0x89, 0x77, 0x46, 0x9a, 0xf0, 0x36, 0x7d, + 0xfa, 0xc2, 0xff, 0xe9, 0x65, 0x2c, 0xef, 0xc1, 0xe9, 0x74, 0x13, 0xde, + 0x8c, 0x7a, 0xdb, 0x5e, 0x20, 0x3f, 0xfa, 0x79, 0xda, 0x81, 0x3b, 0xe2, + 0x8c, 0x7b, 0x38, 0x8e, 0x3f, 0xee, 0xc0, 0xc5, 0xb4, 0x8a, 0xc3, 0x3c, + 0x1f, 0x47, 0x70, 0x21, 0xe3, 0x5e, 0x0f, 0x0e, 0x0e, 0x3e, 0x88, 0xa9, + 0xd4, 0x83, 0x38, 0x96, 0xfc, 0xc0, 0x70, 0x69, 0x52, 0x27, 0x73, 0xe1, + 0x22, 0x63, 0xb2, 0x69, 0x4a, 0xa3, 0x70, 0x69, 0x1b, 0xfd, 0xbc, 0x16, + 0x11, 0xb9, 0xbf, 0xc3, 0xdf, 0xee, 0x89, 0x37, 0x62, 0xff, 0x18, 0x45, + 0x9a, 0xd0, 0x91, 0x88, 0xc9, 0x5c, 0x21, 0xc4, 0xc8, 0x0b, 0x77, 0xf5, + 0x1b, 0xf4, 0x17, 0x77, 0x48, 0x0c, 0xa2, 0xb4, 0xd6, 0xfe, 0x73, 0x66, + 0x1f, 0x8d, 0xb3, 0x6a, 0xa0, 0xf9, 0x3c, 0x1b, 0xca, 0x95, 0xfd, 0xfe, + 0x77, 0xa2, 0xc1, 0xf4, 0x4d, 0x47, 0xae, 0x9d, 0x47, 0x23, 0xcf, 0xe3, + 0x49, 0x9c, 0xdd, 0xbd, 0x16, 0xef, 0x10, 0xef, 0x8a, 0x17, 0xfb, 0x3a, + 0x9d, 0xb6, 0x7a, 0x8e, 0x9d, 0x36, 0x52, 0x95, 0x22, 0xd3, 0xb5, 0xf8, + 0x65, 0x54, 0x64, 0x9a, 0x26, 0xfe, 0xf9, 0x3c, 0x7e, 0xfb, 0x5b, 0xb4, + 0x09, 0xb7, 0xad, 0xbb, 0xc1, 0xaa, 0xe9, 0x15, 0x2e, 0x75, 0xe1, 0x92, + 0xb9, 0x36, 0x59, 0xeb, 0x9f, 0x5b, 0xdf, 0x2f, 0x8d, 0x55, 0x95, 0xb2, + 0xbe, 0x88, 0x91, 0xa3, 0x69, 0x81, 0x1c, 0x45, 0xfc, 0x6c, 0xc0, 0xac, + 0x63, 0xd4, 0xc5, 0xbb, 0x60, 0x0f, 0x16, 0x32, 0x3e, 0xf3, 0xce, 0x74, + 0xe0, 0x1d, 0x5c, 0x9e, 0x70, 0x61, 0x41, 0x3c, 0x80, 0x57, 0x26, 0x72, + 0x2b, 0x91, 0xff, 0x0b, 0x9c, 0xe7, 0x77, 0x5f, 0xdc, 0xb2, 0xb7, 0xee, + 0xd0, 0x5a, 0xac, 0x48, 0xcb, 0xfe, 0x9e, 0xe4, 0x44, 0x3a, 0xc2, 0x69, + 0xd9, 0x67, 0x8c, 0xb6, 0x21, 0xfb, 0x2c, 0xfb, 0x9a, 0x7d, 0xbe, 0xcb, + 0xb5, 0xcf, 0xa3, 0x2d, 0x65, 0x7d, 0x47, 0x11, 0x0e, 0x26, 0x55, 0x9c, + 0xd0, 0x8b, 0x70, 0x4e, 0x95, 0x7c, 0xbd, 0x8b, 0x3e, 0xc4, 0x81, 0x66, + 0xc6, 0x4b, 0xc3, 0xd1, 0x3c, 0x3c, 0xa3, 0x3a, 0x70, 0x4a, 0x77, 0xe0, + 0x98, 0x7e, 0x1b, 0xb1, 0x5e, 0xe2, 0x08, 0xd3, 0xbf, 0x90, 0x31, 0x65, + 0xf5, 0x58, 0x9e, 0x17, 0xc2, 0x53, 0x5a, 0x86, 0x37, 0x25, 0xef, 0x68, + 0xb6, 0x71, 0x49, 0xad, 0x17, 0x87, 0x28, 0xb3, 0x9c, 0x58, 0x39, 0x2e, + 0xb5, 0x35, 0xde, 0xa2, 0x1f, 0x69, 0xac, 0xf6, 0xb1, 0xb1, 0xb9, 0xf2, + 0xda, 0x98, 0x1e, 0x28, 0x47, 0x2a, 0x2c, 0x9c, 0xc8, 0xd6, 0xe1, 0xb2, + 0xbe, 0x6c, 0x76, 0xbf, 0xd9, 0xfb, 0x7c, 0xa1, 0x52, 0xb0, 0xc9, 0x61, + 0xc6, 0x82, 0x6d, 0xdf, 0xa4, 0x8f, 0xa2, 0xcf, 0x5e, 0xbb, 0x45, 0x62, + 0x43, 0x5b, 0xd3, 0xba, 0x6f, 0x2e, 0xd7, 0x72, 0x60, 0x37, 0xb9, 0xa0, + 0xe3, 0x65, 0x8b, 0xbf, 0xbb, 0x5e, 0xd6, 0xcc, 0xcf, 0xc2, 0x97, 0x17, + 0x98, 0x9f, 0xea, 0xcb, 0xbe, 0xd4, 0x75, 0x5f, 0x66, 0xf1, 0x63, 0xf3, + 0xae, 0x10, 0xfa, 0xf4, 0x88, 0x72, 0x7f, 0x48, 0x78, 0xe6, 0x6c, 0x8e, + 0x11, 0x50, 0x4e, 0x45, 0x23, 0x46, 0xb5, 0x96, 0x1f, 0x29, 0x26, 0xf7, + 0x6e, 0xf4, 0x6b, 0xc4, 0x6a, 0x89, 0xe9, 0x34, 0x9c, 0xe1, 0x79, 0x10, + 0x62, 0xa9, 0xe3, 0xff, 0x0f, 0xd1, 0xdd, 0x68, 0xcf, 0x37, 0x71, 0xc9, + 0x30, 0x76, 0x05, 0x25, 0x07, 0x21, 0xe3, 0x3a, 0xf0, 0x11, 0xcf, 0xf9, + 0x37, 0x23, 0x05, 0xf8, 0x30, 0xa5, 0xe1, 0x5c, 0x7a, 0x2d, 0x76, 0x4c, + 0x58, 0x1c, 0xe4, 0x58, 0xda, 0xe2, 0x44, 0x12, 0xd3, 0xef, 0x27, 0x47, + 0x88, 0x25, 0x5e, 0x37, 0xf2, 0x34, 0xdf, 0x94, 0xdf, 0xee, 0xc0, 0xbe, + 0xf4, 0x34, 0x26, 0xfa, 0x3f, 0x33, 0xec, 0x5a, 0x17, 0x3e, 0x0d, 0x4e, + 0x63, 0xfc, 0x80, 0xd4, 0x50, 0x43, 0xd8, 0x35, 0x18, 0x40, 0x6f, 0xc2, + 0x86, 0x9d, 0x4b, 0x5a, 0xb1, 0x6b, 0xa2, 0x05, 0x91, 0x43, 0x1e, 0xec, + 0x4c, 0xa7, 0x31, 0x35, 0x32, 0x8d, 0x93, 0x49, 0x8d, 0xf1, 0xe4, 0x34, + 0x4e, 0xa4, 0x38, 0x66, 0xe2, 0x3d, 0x44, 0x38, 0xc6, 0xb6, 0xa4, 0xa6, + 0x0e, 0x9b, 0x7b, 0x9c, 0x46, 0x77, 0xea, 0x56, 0x39, 0x13, 0xae, 0x27, + 0xd1, 0xd3, 0x6e, 0xd5, 0x45, 0x88, 0xbd, 0x69, 0x4d, 0xe9, 0xe3, 0xf9, + 0x1d, 0x4e, 0x67, 0x6b, 0x24, 0x37, 0xe7, 0x4a, 0x42, 0xe8, 0x1b, 0x6c, + 0x65, 0x9f, 0x00, 0xba, 0x13, 0x52, 0x87, 0xf6, 0x71, 0x4e, 0x03, 0xbf, + 0xd6, 0xbd, 0xee, 0x05, 0xfc, 0x1c, 0xd5, 0x3b, 0xb1, 0x89, 0x63, 0x4d, + 0x31, 0x46, 0xd2, 0x14, 0x6f, 0x63, 0x04, 0x76, 0xfc, 0x4a, 0x27, 0x1f, + 0xaa, 0xb0, 0xe3, 0x55, 0xea, 0x5a, 0xb8, 0xd4, 0x8e, 0xfa, 0x20, 0x7d, + 0x78, 0xc6, 0xa7, 0x7f, 0x92, 0x54, 0xf0, 0x20, 0xf1, 0xf6, 0x8d, 0x60, + 0x7d, 0xfb, 0x4a, 0x61, 0x7b, 0x07, 0x14, 0x5c, 0xd6, 0xae, 0x1a, 0x11, + 0xea, 0x87, 0xcb, 0x9f, 0x3d, 0xa3, 0x7f, 0xc9, 0xe4, 0xf0, 0xbe, 0x34, + 0xb2, 0xfd, 0x66, 0xb8, 0xc6, 0x27, 0xd8, 0x6f, 0xc1, 0xe2, 0xfa, 0x4e, + 0xe9, 0xe7, 0x26, 0xde, 0x4b, 0xbf, 0x73, 0x95, 0x8e, 0x59, 0xfd, 0x42, + 0xd8, 0x36, 0xd8, 0x6c, 0xae, 0x77, 0x7b, 0x02, 0x8b, 0x1c, 0x10, 0x5b, + 0xab, 0x57, 0x2f, 0x02, 0x5d, 0xd3, 0x7a, 0x09, 0x79, 0x90, 0x3f, 0xf0, + 0x0c, 0x44, 0x56, 0x12, 0x67, 0xbe, 0x87, 0x9d, 0xd1, 0x11, 0x30, 0xd6, + 0x24, 0x06, 0xfa, 0xd7, 0x0d, 0x23, 0x85, 0xe7, 0xd3, 0x29, 0xbc, 0x40, + 0x19, 0x45, 0xcc, 0xbb, 0x62, 0x69, 0x7c, 0x3b, 0xfa, 0x1e, 0x62, 0xe6, + 0x99, 0x1d, 0xc6, 0xfa, 0xa8, 0xbb, 0x0a, 0xf9, 0xd2, 0x77, 0x25, 0xc7, + 0x17, 0xb9, 0x7a, 0xdb, 0x22, 0xf8, 0x8a, 0xe3, 0xaf, 0x44, 0xcf, 0xb0, + 0x61, 0xfc, 0x90, 0xbe, 0xed, 0x2d, 0x72, 0xaf, 0xcb, 0x99, 0x7b, 0x67, + 0x79, 0x94, 0xb7, 0x66, 0xfa, 0xb8, 0xb5, 0x3c, 0xe7, 0x2a, 0xe1, 0xfc, + 0x28, 0x1a, 0xd3, 0x94, 0x05, 0x31, 0x39, 0x77, 0x72, 0xca, 0x31, 0x0f, + 0x9e, 0x20, 0x7f, 0xc9, 0x1d, 0xfd, 0x5b, 0x45, 0xfc, 0x5c, 0xf5, 0x01, + 0xc6, 0x02, 0x07, 0x3c, 0xca, 0xc2, 0x3d, 0x2e, 0x3c, 0x18, 0x73, 0xe0, + 0xfe, 0x58, 0x0b, 0x7a, 0xf6, 0x6a, 0x6c, 0xe3, 0xd5, 0xcf, 0x30, 0x5e, + 0x3d, 0x01, 0x9f, 0x67, 0x98, 0x9c, 0xcb, 0x4d, 0x9c, 0x76, 0x8c, 0x16, + 0xa3, 0x60, 0x54, 0x85, 0x6d, 0xb4, 0x0c, 0x85, 0xa3, 0x6e, 0x54, 0xd3, + 0xef, 0xb9, 0xc7, 0xce, 0x62, 0x62, 0x8f, 0xe4, 0x53, 0xbf, 0x30, 0x72, + 0xc9, 0xcb, 0x3e, 0x0d, 0x06, 0x50, 0x3c, 0xb6, 0x05, 0xe9, 0x58, 0x03, + 0x0a, 0xc7, 0x48, 0xb3, 0xc6, 0x26, 0x95, 0x7a, 0xce, 0xd9, 0x12, 0xd3, + 0x38, 0x96, 0xc5, 0x83, 0x56, 0xd2, 0x57, 0xf6, 0x25, 0xbc, 0xeb, 0xa4, + 0x2e, 0x79, 0x59, 0x3f, 0x8e, 0xbc, 0xfe, 0xec, 0xfd, 0x39, 0x78, 0xf3, + 0x80, 0x92, 0x1e, 0xdd, 0xdf, 0xb6, 0x11, 0xd6, 0x5d, 0xba, 0xfb, 0x33, + 0x7b, 0x6a, 0x90, 0x3d, 0x39, 0xd7, 0x52, 0x17, 0xe6, 0xa0, 0x84, 0x7b, + 0x3a, 0x4f, 0xfd, 0xb9, 0x87, 0xeb, 0xbd, 0xca, 0xb8, 0xb1, 0x33, 0x26, + 0x7a, 0xff, 0xb7, 0x0a, 0xed, 0x06, 0x33, 0xa9, 0x02, 0x7c, 0x96, 0xf2, + 0x28, 0x3e, 0xee, 0xe7, 0x3b, 0x7c, 0xfe, 0x6d, 0xee, 0x67, 0xeb, 0x5e, + 0x6f, 0xdb, 0x51, 0xc5, 0xdb, 0xbe, 0x46, 0xf1, 0xa9, 0x5b, 0x95, 0x42, + 0x9c, 0x1f, 0x29, 0xc6, 0x45, 0xfa, 0xe9, 0xab, 0x23, 0x65, 0xb8, 0x34, + 0x52, 0x41, 0x5b, 0xd1, 0x38, 0x86, 0x61, 0x14, 0x69, 0x6e, 0xcc, 0xa4, + 0x5f, 0x40, 0x49, 0x6c, 0x1e, 0x3e, 0x4b, 0x6f, 0x42, 0x71, 0x4c, 0xf8, + 0xbc, 0x07, 0x9f, 0xf2, 0xf9, 0x27, 0xe9, 0x71, 0xe4, 0xef, 0xf9, 0x82, + 0x6d, 0x0c, 0xa3, 0x85, 0x7b, 0xbc, 0x94, 0xee, 0x40, 0xe1, 0x9e, 0x97, + 0xe0, 0xd8, 0x63, 0x74, 0xf5, 0x04, 0xf1, 0x73, 0x3b, 0xf7, 0xd2, 0xad, + 0x7b, 0xa7, 0x16, 0xd8, 0x1b, 0x38, 0x86, 0xce, 0x31, 0x27, 0x95, 0x85, + 0x63, 0x2f, 0xa1, 0x78, 0x8f, 0x07, 0x9b, 0x29, 0xcb, 0x71, 0x68, 0x81, + 0x35, 0xca, 0x4b, 0xc8, 0x19, 0xb5, 0x64, 0xb0, 0x61, 0xcc, 0xb2, 0x91, + 0x96, 0x90, 0xe4, 0x94, 0x26, 0x95, 0x61, 0xd3, 0x46, 0xdc, 0x72, 0xd7, + 0x07, 0xd3, 0xe9, 0x02, 0x9c, 0x4a, 0x89, 0x8c, 0xe4, 0xbe, 0xe0, 0x38, + 0x72, 0xf7, 0x10, 0x3f, 0x47, 0x74, 0x93, 0x5f, 0x88, 0x6d, 0x8c, 0xa4, + 0x6f, 0x65, 0x5f, 0x3a, 0x76, 0x26, 0xaa, 0x69, 0x5b, 0xf3, 0xb0, 0x6a, + 0x8f, 0x61, 0x04, 0x82, 0x53, 0xf7, 0xb8, 0xa8, 0x4d, 0x87, 0xd2, 0xb7, + 0xb2, 0xad, 0x46, 0xea, 0xa9, 0xb7, 0x35, 0x62, 0xe6, 0xbb, 0x0d, 0x4c, + 0xeb, 0x93, 0x8a, 0x2d, 0x26, 0xb1, 0xd8, 0x5a, 0xda, 0x7c, 0x1b, 0x7a, + 0x06, 0xd1, 0xbe, 0x3f, 0x24, 0xb5, 0x70, 0x27, 0x86, 0x19, 0x5b, 0x9d, + 0x67, 0x3c, 0x42, 0x99, 0xab, 0x39, 0x4d, 0x39, 0x18, 0x1a, 0x71, 0xe1, + 0x27, 0x23, 0x1e, 0x34, 0xc6, 0xbe, 0x20, 0x66, 0xe4, 0x63, 0x92, 0xf2, + 0x9e, 0x20, 0x37, 0xfa, 0x34, 0xaa, 0x62, 0x9c, 0x7e, 0xf8, 0x93, 0x68, + 0x05, 0xc6, 0x18, 0x87, 0x7d, 0x1c, 0xd5, 0x90, 0xe6, 0xd9, 0x7c, 0x44, + 0xbc, 0xf9, 0x61, 0xba, 0x01, 0xbf, 0x89, 0x36, 0xe0, 0x55, 0xca, 0xb1, + 0x2e, 0xe6, 0xe6, 0x9a, 0x8e, 0x28, 0x38, 0x30, 0xa9, 0xe4, 0x50, 0x2f, + 0xfc, 0x31, 0xcd, 0x33, 0x9c, 0xd1, 0x0b, 0x6d, 0xac, 0x8d, 0x76, 0x24, + 0x77, 0x2d, 0xc4, 0x77, 0x38, 0xf4, 0x61, 0x90, 0xef, 0x35, 0x64, 0x73, + 0x8b, 0x5e, 0xf7, 0x14, 0xaa, 0x68, 0x4b, 0x5f, 0x19, 0xaa, 0x26, 0x79, + 0xb4, 0x64, 0xf0, 0x72, 0x54, 0x53, 0x2f, 0x99, 0x7b, 0x88, 0x28, 0xce, + 0x25, 0x92, 0xa3, 0xd8, 0xca, 0xfd, 0x07, 0x88, 0x19, 0x57, 0xcc, 0x73, + 0x52, 0xb5, 0xe3, 0x68, 0x30, 0xef, 0xa4, 0x31, 0xd6, 0x5b, 0x72, 0x1c, + 0x77, 0x1e, 0xf8, 0x3f, 0x55, 0x16, 0x57, 0xa2, 0x6d, 0xdb, 0x6e, 0xce, + 0x83, 0x49, 0x4e, 0x7d, 0x77, 0xf0, 0x78, 0xf4, 0x37, 0x55, 0x52, 0x6b, + 0x3b, 0x4a, 0xce, 0xb4, 0x3d, 0x71, 0xab, 0x98, 0xc2, 0xc0, 0x3b, 0xc4, + 0x97, 0x4b, 0x49, 0xe1, 0x55, 0xc2, 0xa7, 0xba, 0xe8, 0xbb, 0x8a, 0xc8, + 0x27, 0xe8, 0x67, 0xc9, 0xf9, 0x7d, 0xf1, 0x29, 0xc6, 0x34, 0x77, 0x93, + 0xd3, 0x15, 0x73, 0x98, 0xf7, 0x39, 0x5f, 0x1b, 0x76, 0xd2, 0x4e, 0xf3, + 0xb4, 0x05, 0x58, 0x45, 0xbe, 0xe4, 0xd0, 0xe8, 0x6e, 0x1e, 0x11, 0x9f, + 0x03, 0xd4, 0xc6, 0x55, 0x14, 0x36, 0x69, 0xeb, 0xde, 0xc2, 0x3d, 0x68, + 0xaf, 0x74, 0x41, 0xea, 0x09, 0x6f, 0x63, 0x19, 0x52, 0x8f, 0x89, 0xef, + 0xb5, 0x49, 0x7d, 0x2c, 0x72, 0x16, 0x35, 0x26, 0x73, 0xcf, 0x6f, 0x92, + 0xf5, 0x54, 0xf0, 0x2c, 0x54, 0x5c, 0xa0, 0x8c, 0x2f, 0x46, 0x7d, 0x33, + 0x2b, 0x50, 0x7f, 0xf2, 0xa2, 0x9d, 0xbc, 0xb0, 0x5c, 0xda, 0x37, 0x40, + 0xe3, 0x78, 0x9f, 0x47, 0x83, 0xe8, 0x57, 0xe5, 0xbb, 0xf0, 0xcb, 0x36, + 0x74, 0x0f, 0xcb, 0x1a, 0x0c, 0xa3, 0x8c, 0x58, 0xf9, 0x88, 0x39, 0xbf, + 0xcc, 0x7d, 0x73, 0x7c, 0x92, 0xf5, 0x7f, 0x12, 0xa3, 0x4c, 0xe3, 0x70, + 0xd2, 0x03, 0xc7, 0x92, 0xaa, 0x39, 0xc8, 0x9f, 0xc6, 0x48, 0x4a, 0x23, + 0xf7, 0x2c, 0x80, 0xa7, 0x52, 0xc7, 0x2e, 0xfa, 0xfc, 0x18, 0xdb, 0xa7, + 0x63, 0x05, 0x88, 0x54, 0x5a, 0x73, 0xde, 0x1d, 0xff, 0xd8, 0x98, 0x7a, + 0xd8, 0xf4, 0xa1, 0xfc, 0x1e, 0x64, 0x9f, 0x39, 0x72, 0xed, 0x14, 0xcf, + 0xc6, 0x2e, 0x19, 0x53, 0x6d, 0xb3, 0x7f, 0x2f, 0x35, 0xef, 0x6e, 0x85, + 0x6d, 0x95, 0xfc, 0xb4, 0xe4, 0xd2, 0x4d, 0xb9, 0x94, 0x68, 0xef, 0x19, + 0x0f, 0x59, 0x72, 0x99, 0x23, 0xf1, 0x40, 0x6d, 0xfc, 0xf1, 0x39, 0x92, + 0x6f, 0x15, 0x7f, 0xe6, 0x6a, 0xd2, 0x1a, 0x4f, 0xe2, 0x17, 0xc6, 0xb9, + 0x1b, 0xc6, 0x29, 0xe7, 0x33, 0xf1, 0x4d, 0xe7, 0x32, 0xf7, 0x00, 0xdc, + 0x99, 0x98, 0x61, 0x1a, 0x47, 0x93, 0xe2, 0x17, 0x3c, 0x58, 0x2f, 0xf9, + 0x2a, 0xd5, 0xdb, 0x17, 0xc1, 0x14, 0x39, 0xe2, 0x07, 0x94, 0xbd, 0x22, + 0xf5, 0x3a, 0xf2, 0xc4, 0xd9, 0xbe, 0x2b, 0x8c, 0x94, 0x59, 0x8f, 0x12, + 0x6c, 0x9d, 0xc6, 0xf6, 0xa4, 0xd4, 0x4d, 0x3f, 0x23, 0x6f, 0xea, 0x22, + 0x27, 0x9f, 0x46, 0x4f, 0xaa, 0x05, 0xaf, 0xec, 0x6d, 0x25, 0xde, 0x08, + 0x6e, 0xfa, 0x4e, 0x9e, 0xb7, 0xb7, 0x60, 0xff, 0xa1, 0x34, 0x52, 0xa3, + 0xe2, 0x2f, 0xe5, 0x1e, 0x9c, 0xf8, 0xca, 0x00, 0xa2, 0x89, 0x13, 0x88, + 0xf0, 0x73, 0x67, 0xe2, 0x25, 0x84, 0x47, 0xdf, 0x63, 0x2c, 0x30, 0x8d, + 0x95, 0xd4, 0xb9, 0x83, 0x98, 0xc6, 0xea, 0x03, 0x1a, 0x92, 0x89, 0x56, + 0x8e, 0xdf, 0x82, 0xde, 0xbd, 0xde, 0x80, 0xc3, 0x56, 0x42, 0x7f, 0xa5, + 0x61, 0xdb, 0x44, 0x33, 0x22, 0xc3, 0x56, 0x5d, 0xac, 0x21, 0xee, 0x51, + 0x3e, 0x21, 0x9f, 0xae, 0x8f, 0x7b, 0x19, 0xc7, 0x79, 0x23, 0xab, 0x15, + 0x9f, 0x27, 0xc7, 0x66, 0x18, 0xbd, 0xf4, 0x1b, 0x27, 0x75, 0x05, 0x79, + 0xf7, 0x28, 0x08, 0xd2, 0x8f, 0x79, 0xaa, 0xe8, 0x5f, 0x86, 0x43, 0xe8, + 0x1d, 0x9c, 0x5d, 0x53, 0x94, 0xf3, 0x7a, 0x80, 0xe3, 0xc9, 0xd9, 0xb5, + 0xa2, 0x77, 0xc2, 0xd7, 0x71, 0xd2, 0xac, 0x39, 0x4a, 0xbb, 0x6c, 0x1b, + 0x14, 0x7e, 0x16, 0xf2, 0x06, 0x4a, 0x14, 0x69, 0xbb, 0x95, 0x58, 0x36, + 0xbb, 0x7d, 0x44, 0x49, 0x2e, 0x21, 0x7f, 0xb5, 0x89, 0x5d, 0x74, 0x9b, + 0xb6, 0x23, 0xb2, 0xe8, 0x4d, 0x86, 0xa9, 0xd3, 0x3f, 0x35, 0x52, 0x6d, + 0x6d, 0x5c, 0x67, 0xa3, 0xd4, 0x9c, 0x4c, 0x9e, 0x72, 0x5a, 0xf2, 0x73, + 0x4e, 0xf1, 0xe3, 0xdd, 0xed, 0x2e, 0xea, 0x53, 0x2e, 0xb1, 0x2a, 0x6f, + 0xdc, 0x05, 0xd7, 0xc1, 0x02, 0xe4, 0x0e, 0x09, 0x9f, 0x83, 0x5a, 0xdc, + 0xa4, 0xc2, 0x3e, 0x5e, 0x48, 0x1b, 0xe0, 0x19, 0x8e, 0xd3, 0xc6, 0xa2, + 0x6e, 0xd4, 0x8c, 0xbb, 0xf1, 0x13, 0xe2, 0x41, 0xf5, 0xb8, 0x86, 0x49, + 0xe2, 0x81, 0x7b, 0x3c, 0x80, 0x09, 0xe2, 0x41, 0x49, 0x26, 0x47, 0xf2, + 0x76, 0xfa, 0x65, 0x9e, 0xab, 0xcc, 0x25, 0x72, 0xcc, 0x9e, 0xab, 0x9c, + 0x69, 0x2b, 0x31, 0x50, 0xce, 0xb7, 0x01, 0x3b, 0x06, 0xd3, 0x58, 0xbe, + 0xc7, 0xc0, 0xbb, 0x7a, 0xbd, 0x3b, 0x4f, 0x91, 0x78, 0xc2, 0x40, 0x5a, + 0x97, 0x3b, 0xab, 0xde, 0x75, 0x72, 0xaf, 0xbb, 0xbd, 0xc2, 0x40, 0x4e, + 0xd0, 0xab, 0x13, 0xf9, 0xd7, 0xe5, 0x29, 0xe2, 0xc3, 0xea, 0x3d, 0x9b, + 0x30, 0x57, 0x6a, 0x8e, 0xfc, 0xb7, 0x02, 0x9b, 0xc8, 0x1b, 0xf3, 0xb5, + 0x56, 0xec, 0x2c, 0x8d, 0xb8, 0x2e, 0x87, 0x0c, 0x63, 0x43, 0xf0, 0xf1, + 0x2a, 0x93, 0x03, 0xda, 0xf6, 0xf1, 0x73, 0x2d, 0xf7, 0x2d, 0x7b, 0xef, + 0x40, 0x6c, 0xb7, 0x82, 0xb4, 0xbf, 0x03, 0xd1, 0x91, 0x0e, 0xec, 0xda, + 0x2d, 0x98, 0xd0, 0x47, 0x4c, 0x30, 0xba, 0x36, 0x06, 0x1f, 0xc2, 0x25, + 0x93, 0x11, 0x48, 0x1f, 0x6f, 0xc0, 0x63, 0x9b, 0x7d, 0x0e, 0x1b, 0xb9, + 0x7e, 0xcb, 0x76, 0x9a, 0xfb, 0x85, 0x7b, 0xfb, 0xfb, 0x7a, 0x79, 0xfe, + 0x0f, 0x1f, 0x10, 0xdf, 0x63, 0x18, 0x7d, 0xfa, 0x3c, 0xa0, 0x54, 0xf6, + 0x10, 0x40, 0x3c, 0x61, 0x7c, 0x56, 0xad, 0xf9, 0x66, 0x76, 0xd1, 0xcf, + 0x9f, 0xdd, 0x53, 0xbf, 0x69, 0x93, 0x70, 0x9a, 0xc5, 0xc2, 0xf3, 0xd2, + 0x38, 0x33, 0x7a, 0x27, 0x52, 0x0f, 0x73, 0x3f, 0x3c, 0x2b, 0x67, 0xfc, + 0x4b, 0x43, 0x78, 0x9d, 0x5d, 0x93, 0x9a, 0x2d, 0xa7, 0x1c, 0xf7, 0xa3, + 0xa7, 0x14, 0x91, 0xcb, 0x21, 0x99, 0xff, 0xda, 0xfa, 0xb9, 0xdf, 0x16, + 0xec, 0xda, 0x2b, 0xbc, 0x43, 0x38, 0x9a, 0x2f, 0xf2, 0x11, 0x5a, 0x91, + 0x9c, 0xb0, 0xe6, 0x8a, 0x26, 0x6e, 0xd6, 0x15, 0x39, 0xf7, 0x13, 0xd8, + 0x41, 0x8e, 0xe7, 0xe2, 0xf8, 0xf4, 0x35, 0x1c, 0x4f, 0x0b, 0xe4, 0xc9, + 0x7c, 0xe3, 0x3f, 0x35, 0x76, 0x56, 0x8a, 0x6c, 0x64, 0x7c, 0xcd, 0xc4, + 0x8c, 0x0d, 0xc1, 0x3f, 0xb7, 0xd7, 0x1a, 0x37, 0xf2, 0xbd, 0xad, 0x96, + 0x3c, 0xa4, 0xad, 0xf6, 0x27, 0xd6, 0xb3, 0x90, 0xed, 0x64, 0x4d, 0x1d, + 0xd8, 0xb1, 0x1b, 0x91, 0x7c, 0x4d, 0x6a, 0x0d, 0x1d, 0xe8, 0xa3, 0x7c, + 0xb7, 0x25, 0x3b, 0xb0, 0x9f, 0x36, 0x3b, 0xa4, 0xbf, 0x51, 0x6d, 0x43, + 0xdd, 0x8c, 0x1d, 0x53, 0x3f, 0xab, 0x21, 0x9e, 0x2e, 0x5c, 0xec, 0xa7, + 0x7d, 0x75, 0x20, 0x9e, 0xca, 0x75, 0x9b, 0x35, 0x40, 0x9b, 0xf8, 0x42, + 0x91, 0x45, 0x27, 0xf2, 0xfb, 0x4f, 0xc0, 0xd9, 0xdf, 0x89, 0x3c, 0xff, + 0x32, 0xdc, 0x1f, 0x3c, 0x67, 0x5c, 0xd2, 0x1c, 0xee, 0xa3, 0x94, 0xcf, + 0x1b, 0x0d, 0xd5, 0x8c, 0x3b, 0x1b, 0xb0, 0x6d, 0xf8, 0x36, 0xda, 0x7e, + 0x23, 0xb9, 0x2f, 0xe7, 0x6a, 0xb2, 0x61, 0xf5, 0x12, 0x89, 0xe9, 0xa5, + 0x3e, 0x5d, 0x25, 0xf7, 0x10, 0xd4, 0xe7, 0x21, 0xf1, 0x1a, 0x39, 0x59, + 0x85, 0x07, 0x4f, 0xd3, 0xc6, 0xda, 0x55, 0x79, 0xbe, 0x85, 0x71, 0xc4, + 0x16, 0x54, 0xc7, 0x22, 0x86, 0xc8, 0xfb, 0x28, 0xc2, 0xdf, 0x93, 0x9a, + 0x4a, 0xe3, 0x62, 0xff, 0xa6, 0x19, 0x45, 0x74, 0xda, 0xdf, 0x3e, 0xae, + 0xe8, 0xae, 0x07, 0xc6, 0x14, 0x04, 0xfa, 0x39, 0x56, 0xf0, 0xfd, 0x39, + 0x56, 0x1e, 0x2d, 0xcb, 0xff, 0xb6, 0x90, 0x33, 0x6c, 0x41, 0x11, 0xfb, + 0xbb, 0x35, 0xc1, 0x86, 0xf0, 0x7d, 0xc5, 0xec, 0x9f, 0x0e, 0xfa, 0xdb, + 0x0a, 0x15, 0xe1, 0x46, 0xfe, 0xc6, 0xd5, 0x8a, 0xf0, 0x18, 0xe9, 0xa7, + 0xbb, 0xea, 0xc6, 0xce, 0x66, 0x6a, 0x66, 0x8d, 0xc4, 0x07, 0x8f, 0x79, + 0x07, 0xd5, 0xba, 0xaf, 0x95, 0xbd, 0xb3, 0xa4, 0xf2, 0xfc, 0x25, 0xc6, + 0x38, 0x12, 0x5c, 0x1e, 0x6d, 0x92, 0xfb, 0x21, 0xcb, 0x0e, 0x51, 0xef, + 0xcf, 0xa3, 0x02, 0xff, 0x10, 0x15, 0x5c, 0xf3, 0xe0, 0x1f, 0xa3, 0xb9, + 0x12, 0x57, 0xa7, 0x24, 0x6f, 0xf9, 0x66, 0x32, 0x62, 0x50, 0xae, 0xad, + 0xab, 0xa9, 0x4b, 0x81, 0x60, 0x21, 0x50, 0xd9, 0xfd, 0xb4, 0xd3, 0x8c, + 0xf3, 0x8b, 0x50, 0x4a, 0x1f, 0xd0, 0x3f, 0xfc, 0xa7, 0x72, 0xb4, 0xef, + 0x9b, 0xdc, 0xf2, 0xef, 0xea, 0xec, 0xd8, 0x16, 0xfc, 0x57, 0x23, 0x95, + 0xb9, 0x33, 0x7c, 0x66, 0xb7, 0xe8, 0x69, 0x00, 0xb9, 0xf1, 0xb3, 0xd4, + 0x49, 0x15, 0xa7, 0xa3, 0x3e, 0x7d, 0x8d, 0xed, 0x49, 0xea, 0x7f, 0xcd, + 0x0d, 0xd8, 0x5d, 0xa3, 0x3d, 0x88, 0xa7, 0x4c, 0xec, 0x0e, 0xa3, 0x87, + 0xbe, 0x81, 0x9c, 0x6e, 0xdf, 0xd3, 0x36, 0x15, 0x79, 0x31, 0x9f, 0xea, + 0xa3, 0x4e, 0xf5, 0x70, 0x0e, 0xe1, 0x9b, 0xe5, 0xe4, 0x83, 0x1b, 0xa3, + 0xf5, 0x9e, 0x7f, 0xc1, 0x7a, 0xda, 0xa3, 0xcc, 0x21, 0x7b, 0xd2, 0x50, + 0x18, 0xd7, 0x70, 0x8c, 0xfb, 0xd8, 0x56, 0x6a, 0xcd, 0x5b, 0x9c, 0x19, + 0x3b, 0x3e, 0x2c, 0x5c, 0x6c, 0x29, 0xd6, 0x98, 0x63, 0xeb, 0xb4, 0x4b, + 0x0d, 0xfb, 0xe4, 0x6e, 0x7f, 0x9d, 0x86, 0x44, 0xba, 0x19, 0x2f, 0x95, + 0x79, 0xb0, 0x3f, 0xb1, 0x05, 0x8b, 0x12, 0xf7, 0xe1, 0xd1, 0xb2, 0x88, + 0xdc, 0x85, 0x41, 0x5e, 0x5c, 0x53, 0xef, 0x54, 0xee, 0xcd, 0xd4, 0x29, + 0x2a, 0xe0, 0x88, 0x8b, 0xcf, 0xcb, 0xc1, 0x80, 0x3a, 0x17, 0x05, 0xe6, + 0x9d, 0x4a, 0x6b, 0xec, 0x5d, 0xc3, 0xde, 0x8c, 0x1f, 0x24, 0x6a, 0xc4, + 0x15, 0xf1, 0xbf, 0x81, 0x17, 0x50, 0xce, 0x38, 0x21, 0x82, 0x9c, 0x26, + 0x2d, 0xf5, 0x2c, 0xf2, 0x10, 0xa9, 0x12, 0x4c, 0x94, 0x3e, 0xb7, 0xdd, + 0xb4, 0xa6, 0xb2, 0xcc, 0x9a, 0xb2, 0xcf, 0x31, 0x07, 0xc5, 0xa2, 0x5b, + 0xc2, 0x35, 0xe4, 0xf7, 0x7c, 0xb4, 0x51, 0x9f, 0x2a, 0xb8, 0xe6, 0x84, + 0x79, 0x5f, 0xd6, 0xab, 0x47, 0x6c, 0x21, 0xfc, 0x76, 0x8f, 0xa5, 0x83, + 0xeb, 0x6a, 0x79, 0xfe, 0xc5, 0x21, 0xcc, 0x8c, 0x8a, 0x3f, 0xfb, 0x53, + 0x67, 0x92, 0xf5, 0xc5, 0x72, 0x2e, 0x22, 0x57, 0xef, 0xc9, 0x0b, 0xa8, + 0x9f, 0x7a, 0xc2, 0x76, 0xd8, 0x40, 0xb9, 0xc8, 0xf8, 0xb8, 0x5b, 0x62, + 0x58, 0x1b, 0x79, 0x44, 0x24, 0x7d, 0xc5, 0x2d, 0xbe, 0xd2, 0x11, 0x07, + 0x6a, 0xe2, 0x11, 0xe4, 0x36, 0x69, 0xfb, 0x2e, 0xdb, 0xaf, 0x1a, 0xed, + 0x55, 0xb7, 0x31, 0x26, 0xbc, 0xbe, 0xe7, 0x3e, 0xae, 0xdd, 0xae, 0xfd, + 0xd4, 0x58, 0x51, 0x21, 0x6b, 0xac, 0xae, 0xb6, 0xf2, 0xd1, 0xf3, 0x29, + 0x97, 0xac, 0x4c, 0x0c, 0xea, 0xcf, 0xff, 0x32, 0xbe, 0x71, 0xc3, 0x73, + 0xe1, 0x33, 0xa2, 0xa7, 0xb3, 0xef, 0x14, 0x8a, 0xce, 0x7a, 0xa8, 0xa7, + 0xd3, 0x38, 0x94, 0x6c, 0x44, 0x7f, 0x42, 0x64, 0x1c, 0xc6, 0x79, 0x72, + 0xc5, 0xda, 0x81, 0x69, 0x0c, 0x91, 0x2b, 0xfa, 0xe2, 0xde, 0x7d, 0x94, + 0x24, 0x5e, 0x52, 0x97, 0x99, 0x3c, 0xc9, 0xa5, 0x65, 0xd7, 0x70, 0xb7, + 0x29, 0x77, 0xf1, 0x31, 0x3b, 0xb9, 0xdf, 0x3b, 0xc8, 0x93, 0x9a, 0x63, + 0xb9, 0xd0, 0x4a, 0x8b, 0x51, 0xa8, 0x49, 0x5d, 0xc3, 0x6a, 0x17, 0xe5, + 0x5a, 0x0a, 0x34, 0x1f, 0x56, 0x9b, 0x6d, 0x3d, 0xe6, 0xfd, 0x09, 0x47, + 0x99, 0xf8, 0x60, 0xf1, 0xbb, 0xe4, 0xe2, 0x4b, 0xc4, 0xef, 0x86, 0xb9, + 0xb6, 0x05, 0x3c, 0xb3, 0x45, 0x70, 0xdf, 0xeb, 0x41, 0xf5, 0xbd, 0xf4, + 0x91, 0x0b, 0x15, 0x94, 0x2d, 0xf4, 0x47, 0x16, 0xd9, 0x9a, 0x81, 0xaa, + 0x00, 0xf1, 0x47, 0x33, 0x7a, 0x12, 0x7f, 0xe0, 0x18, 0x1d, 0x30, 0x76, + 0xe7, 0x63, 0xfd, 0xee, 0x12, 0xea, 0xaa, 0x47, 0xf2, 0xf0, 0x2e, 0x57, + 0x53, 0x34, 0xe8, 0x8a, 0xd5, 0xeb, 0x4e, 0x65, 0x01, 0xfd, 0xb1, 0x9c, + 0x9f, 0xcc, 0x7f, 0xd7, 0x0d, 0x7c, 0xa9, 0x9c, 0xfe, 0xed, 0x51, 0x73, + 0x0d, 0x92, 0x2b, 0x96, 0x7e, 0x7f, 0x7c, 0x4e, 0x53, 0xd7, 0xce, 0xe9, + 0x4e, 0x38, 0x1e, 0xa9, 0x20, 0xff, 0xba, 0xb5, 0x0f, 0xc9, 0xa3, 0x0f, + 0xb9, 0x23, 0x66, 0x74, 0x6d, 0x0e, 0x16, 0x48, 0xfe, 0xc8, 0xf4, 0x21, + 0xed, 0xb6, 0x8d, 0xa6, 0xee, 0x38, 0xb5, 0x1e, 0xca, 0xdb, 0xca, 0x47, + 0x53, 0x06, 0x73, 0xac, 0xbb, 0xb9, 0xd9, 0xdf, 0x3a, 0xb0, 0x9d, 0x98, + 0x29, 0x77, 0xea, 0x9d, 0x9a, 0x46, 0xfb, 0xef, 0x40, 0x0f, 0xc7, 0x7c, + 0x85, 0xb8, 0xd9, 0x4f, 0xdc, 0xbc, 0xba, 0xf8, 0x8d, 0x9f, 0x55, 0xa3, + 0x2e, 0xe9, 0xc6, 0xd4, 0x5f, 0x97, 0x09, 0x6e, 0x2e, 0xf2, 0x77, 0x5c, + 0x31, 0x71, 0x53, 0xc6, 0x96, 0xf1, 0x66, 0x8f, 0xfd, 0x3f, 0xf8, 0xdf, + 0xf9, 0x92, 0x73, 0x34, 0x9c, 0xda, 0xff, 0x35, 0xb6, 0x55, 0xc8, 0x5a, + 0x6f, 0xb5, 0x0e, 0xc1, 0xda, 0xd9, 0x35, 0xfd, 0x69, 0x62, 0xae, 0x19, + 0x2f, 0xd0, 0xe7, 0x86, 0xb1, 0x6a, 0x89, 0x8a, 0x4b, 0xd1, 0x69, 0xe4, + 0x1d, 0xc8, 0xe2, 0x93, 0xb1, 0xec, 0x18, 0xb1, 0x69, 0x08, 0x82, 0x47, + 0x4d, 0x3c, 0x97, 0x08, 0xed, 0xa4, 0x08, 0xe3, 0x49, 0xb9, 0x47, 0x64, + 0x60, 0x57, 0xd0, 0x45, 0x6e, 0xdb, 0x7d, 0x34, 0xc7, 0xf4, 0x13, 0x45, + 0x54, 0xad, 0x2c, 0xef, 0x16, 0xce, 0x2d, 0xf8, 0x23, 0xfc, 0xd8, 0x8e, + 0x92, 0xc5, 0x92, 0x17, 0xf8, 0xc2, 0xb8, 0xf4, 0x98, 0xb4, 0x9b, 0x87, + 0xa1, 0xdd, 0xa2, 0x7f, 0x3e, 0x54, 0x6b, 0x67, 0x19, 0x73, 0x80, 0x73, + 0xda, 0x6e, 0xcf, 0x21, 0x37, 0xee, 0xd2, 0x97, 0xe0, 0x6a, 0x79, 0x0f, + 0x0a, 0x9a, 0xdc, 0xf8, 0x30, 0x3a, 0x85, 0x43, 0xc4, 0x8f, 0x5c, 0xea, + 0x50, 0x5e, 0x46, 0xcf, 0x76, 0x0c, 0xcb, 0xfe, 0xaa, 0xb1, 0xd2, 0xb4, + 0x53, 0x19, 0x63, 0x1a, 0xaf, 0x92, 0xcf, 0x36, 0x2f, 0x11, 0x2e, 0xab, + 0x63, 0x5f, 0xa2, 0x08, 0x35, 0x83, 0x5d, 0x94, 0x5d, 0x11, 0xaa, 0x87, + 0xc5, 0xbe, 0xe6, 0x0b, 0x8e, 0xca, 0x05, 0x39, 0xca, 0x43, 0xc5, 0xf6, + 0x68, 0xbd, 0x7a, 0x81, 0x41, 0x42, 0xf8, 0x9a, 0xaf, 0x77, 0xd3, 0xef, + 0x30, 0x26, 0xca, 0xe8, 0x85, 0x4a, 0xbd, 0x68, 0xbb, 0xc6, 0xa3, 0xb3, + 0x7b, 0x99, 0x9d, 0x3f, 0x52, 0xb1, 0x23, 0x6a, 0x62, 0x21, 0xfb, 0xfa, + 0x02, 0x3e, 0x85, 0x58, 0x3e, 0x26, 0x3a, 0xf6, 0x7e, 0x46, 0xce, 0x79, + 0xb7, 0x59, 0xf7, 0x5a, 0x36, 0xde, 0xf4, 0x5d, 0x6b, 0x7f, 0x13, 0x67, + 0x8d, 0x5d, 0x8f, 0xc9, 0x1a, 0x8f, 0xe3, 0x60, 0xf2, 0x8a, 0xdc, 0x9b, + 0xef, 0x38, 0x03, 0x1b, 0x4e, 0x33, 0x76, 0x19, 0x4b, 0xfd, 0xae, 0x5a, + 0xde, 0x45, 0xd9, 0x97, 0x98, 0xed, 0x3b, 0xc4, 0x2e, 0x3d, 0x19, 0xbf, + 0x61, 0xd9, 0x67, 0x69, 0x5c, 0xee, 0xaf, 0x1c, 0x09, 0x3e, 0xcd, 0x73, + 0xf1, 0x2f, 0xaa, 0x37, 0x73, 0x32, 0xe4, 0xc2, 0x8c, 0x53, 0x04, 0x73, + 0x23, 0xf4, 0xf9, 0x45, 0xf8, 0x79, 0x52, 0x7c, 0xb0, 0x81, 0x5c, 0xea, + 0xe3, 0xb9, 0x8a, 0xee, 0xe7, 0x4b, 0x4d, 0x6e, 0x5d, 0x84, 0x32, 0xee, + 0x73, 0x60, 0xf8, 0x56, 0xba, 0x7e, 0xdd, 0x4f, 0xa4, 0x83, 0x0a, 0x71, + 0xe3, 0x5f, 0xb9, 0x4e, 0xab, 0xcf, 0x99, 0xa4, 0x0b, 0x9f, 0x06, 0xdb, + 0x31, 0x55, 0x1a, 0xc6, 0x60, 0x22, 0x0f, 0xed, 0x55, 0x75, 0xe6, 0xbb, + 0x1d, 0xd5, 0x71, 0x0f, 0xce, 0x46, 0x9d, 0x68, 0x9c, 0xe3, 0x31, 0x73, + 0x83, 0x36, 0x62, 0xfd, 0x07, 0xd1, 0xb0, 0x69, 0x83, 0xb3, 0x7d, 0x48, + 0x8e, 0xb6, 0x18, 0x2d, 0x19, 0x9c, 0xdf, 0x9f, 0xf8, 0x82, 0x38, 0x54, + 0x1c, 0x29, 0x6f, 0x2a, 0xc2, 0x1d, 0x83, 0x72, 0xc7, 0x41, 0xee, 0x64, + 0x68, 0x33, 0x77, 0x2a, 0x45, 0x58, 0x36, 0x2c, 0x98, 0x2f, 0xb6, 0x9b, + 0xa6, 0xed, 0xae, 0xe5, 0xb9, 0x75, 0x42, 0xde, 0xd9, 0x78, 0x85, 0xb2, + 0xb7, 0x2b, 0x46, 0xd7, 0x45, 0x3d, 0x2c, 0xf7, 0x3c, 0x3b, 0x5b, 0x68, + 0x07, 0x33, 0x41, 0x6f, 0x7b, 0xb9, 0x5d, 0xeb, 0xf8, 0x95, 0xd2, 0x80, + 0xf1, 0x31, 0xa0, 0x7f, 0x34, 0x80, 0x8f, 0x12, 0x12, 0x03, 0x04, 0xf0, + 0x1b, 0x72, 0xa3, 0x0b, 0x89, 0x06, 0xfa, 0x0b, 0x6f, 0xf8, 0x39, 0x34, + 0xe0, 0x43, 0x7e, 0xcf, 0x8d, 0xeb, 0xb8, 0x4c, 0xf9, 0x39, 0xe3, 0x21, + 0x5c, 0x9c, 0xb8, 0x17, 0x97, 0xf6, 0x2a, 0x78, 0x43, 0xbb, 0x17, 0xe7, + 0x0f, 0x75, 0x62, 0xf1, 0x5e, 0x79, 0xef, 0xef, 0x48, 0x50, 0xa5, 0xaf, + 0x78, 0xba, 0xd6, 0xe8, 0x7a, 0x51, 0xaf, 0x83, 0x5e, 0xe6, 0xd5, 0xdb, + 0x89, 0x09, 0x82, 0xf1, 0x61, 0x9b, 0x9c, 0xa1, 0x9c, 0x65, 0x27, 0x2e, + 0x99, 0xb8, 0x7e, 0x6b, 0xac, 0xb8, 0x8e, 0xe9, 0x32, 0x8f, 0xe0, 0xcb, + 0x7c, 0xfc, 0x48, 0x0d, 0x70, 0x1f, 0x6e, 0x72, 0xb1, 0x29, 0xfa, 0xc7, + 0x3c, 0xe4, 0x56, 0x4a, 0xcd, 0x5a, 0x43, 0x3e, 0x71, 0xe4, 0x14, 0x65, + 0xb7, 0xaa, 0xd2, 0x6b, 0xc6, 0x3a, 0xb9, 0xf1, 0x06, 0xc6, 0x31, 0xe5, + 0xf8, 0xe8, 0x06, 0xff, 0xfb, 0x23, 0xe3, 0x51, 0x13, 0xaf, 0x13, 0xb7, + 0x09, 0x1f, 0x7b, 0x3d, 0xf1, 0xf8, 0x6d, 0x82, 0xdb, 0x92, 0x5f, 0x2c, + 0xd6, 0xb4, 0x4d, 0xdf, 0x81, 0xbc, 0xff, 0xf6, 0xc6, 0x7f, 0x2b, 0x24, + 0x4f, 0x7e, 0x31, 0x58, 0x17, 0x29, 0x45, 0x1f, 0x9f, 0x4f, 0x2d, 0x56, + 0x71, 0x90, 0x9f, 0x7e, 0xb6, 0x6b, 0xe0, 0x3a, 0x3e, 0x36, 0x52, 0xaa, + 0xcf, 0xf4, 0x25, 0x71, 0xfa, 0xd3, 0xd3, 0xb1, 0xfa, 0xf6, 0x51, 0xe5, + 0xb2, 0x11, 0xa9, 0xac, 0xe5, 0x6f, 0x15, 0x38, 0x13, 0xf5, 0x4e, 0x1d, + 0x42, 0xbd, 0x67, 0x46, 0xd9, 0x6f, 0x44, 0x54, 0x39, 0x1f, 0xd9, 0xaf, + 0xf4, 0x5f, 0xc0, 0xe7, 0xe7, 0x66, 0xe9, 0xe1, 0xf5, 0x38, 0xcc, 0x79, + 0x4d, 0xff, 0x84, 0xa7, 0x18, 0xcb, 0x46, 0xf4, 0x7a, 0xb5, 0x87, 0xd8, + 0x10, 0x56, 0x6f, 0xa5, 0x7f, 0x79, 0xd4, 0xbf, 0x30, 0xe3, 0xca, 0x22, + 0xa8, 0xd6, 0x7b, 0x3d, 0x48, 0x0e, 0xcf, 0xe6, 0x9a, 0xa2, 0x77, 0x16, + 0x6f, 0x6d, 0x2f, 0xed, 0x3e, 0xea, 0x24, 0x36, 0x25, 0x88, 0xeb, 0x71, + 0xe2, 0x7a, 0x2e, 0x71, 0xfd, 0xe3, 0x3d, 0xf9, 0x38, 0xbd, 0xa7, 0x11, + 0xe9, 0x52, 0xe9, 0x63, 0x87, 0x93, 0xbb, 0x4b, 0x65, 0xee, 0x39, 0x54, + 0x0f, 0xdc, 0x27, 0x77, 0x1e, 0x21, 0x7e, 0x36, 0x27, 0xce, 0xb8, 0xab, + 0xcd, 0x0e, 0x87, 0xf9, 0x4e, 0x43, 0xc9, 0x0d, 0xfa, 0xe7, 0xd2, 0x72, + 0xd1, 0x4a, 0x39, 0xe6, 0x6a, 0xbe, 0xb9, 0xd6, 0xdd, 0xbe, 0x22, 0xc6, + 0x91, 0x72, 0x5f, 0x71, 0xa9, 0xd4, 0x03, 0xd9, 0x5e, 0xfa, 0x49, 0xac, + 0x63, 0x60, 0x07, 0x35, 0xac, 0xae, 0xd2, 0x40, 0x42, 0x0f, 0xd3, 0x87, + 0x05, 0x11, 0x26, 0xa7, 0x2f, 0xd4, 0xe4, 0xbb, 0x8a, 0x8b, 0x8c, 0xd3, + 0xc6, 0x1a, 0x14, 0x7c, 0x7a, 0x97, 0x70, 0x03, 0xbf, 0x7e, 0x5a, 0xc1, + 0x1c, 0xeb, 0x5d, 0x0a, 0xc1, 0x8c, 0x62, 0x13, 0x33, 0x72, 0x4d, 0x9e, + 0x34, 0xc7, 0xc4, 0x1b, 0x79, 0x57, 0xac, 0x9a, 0x7e, 0xe8, 0x9e, 0x44, + 0xfd, 0x94, 0xcf, 0x4e, 0xce, 0xf6, 0xf8, 0x5d, 0xe4, 0x6a, 0x26, 0x67, + 0x20, 0xfe, 0xbf, 0x9f, 0xe1, 0x15, 0xde, 0xc6, 0x9b, 0xef, 0x90, 0x9e, + 0xbb, 0x16, 0xa7, 0x5b, 0x7b, 0xe8, 0x1f, 0xfe, 0x9d, 0xd1, 0x76, 0xc3, + 0xfa, 0xb3, 0xb8, 0xb2, 0x80, 0xdf, 0xa5, 0xbf, 0xd8, 0x1d, 0xf5, 0x22, + 0xfe, 0x33, 0xe3, 0x29, 0x93, 0xdf, 0xd9, 0xe7, 0xca, 0x1d, 0x51, 0xc7, + 0xc0, 0x17, 0xb7, 0xc9, 0xfb, 0x13, 0xb6, 0x59, 0x3c, 0xc1, 0xf2, 0xbd, + 0x17, 0x8c, 0xd5, 0xe6, 0x5a, 0xf3, 0x33, 0xed, 0x24, 0xa6, 0x96, 0xb5, + 0x28, 0xf8, 0x81, 0x56, 0xaf, 0x9e, 0x42, 0xa1, 0xe0, 0x49, 0x58, 0x6a, + 0x9f, 0xf9, 0x9a, 0xcf, 0x7d, 0x90, 0x9f, 0xbb, 0xf8, 0xfc, 0xb8, 0xe6, + 0x68, 0xdc, 0x0c, 0xa9, 0xf7, 0xda, 0x78, 0x56, 0xf5, 0xee, 0x53, 0xf0, + 0x87, 0x73, 0x95, 0x19, 0xa3, 0xbd, 0x42, 0xda, 0x58, 0x75, 0x5f, 0x28, + 0x67, 0xcd, 0x7c, 0x8a, 0xa5, 0x33, 0xf3, 0xa8, 0x33, 0x82, 0x5d, 0xc2, + 0x4d, 0x16, 0x72, 0xef, 0x2a, 0x86, 0x27, 0x80, 0x9c, 0x01, 0x97, 0xc9, + 0x95, 0xd4, 0xda, 0x5a, 0xcf, 0xb3, 0x58, 0x3e, 0x57, 0xde, 0x01, 0xdb, + 0xaa, 0xe3, 0x76, 0x1b, 0xde, 0xbb, 0xdd, 0xd6, 0x74, 0xdf, 0x77, 0x5b, + 0x42, 0x9b, 0x65, 0x5f, 0x44, 0x67, 0x33, 0xb7, 0xeb, 0x96, 0x1a, 0xe5, + 0x4a, 0xfa, 0xb4, 0x21, 0xc6, 0xfc, 0x2b, 0x1b, 0xfe, 0xdd, 0xf8, 0x96, + 0x23, 0xec, 0xb1, 0xa3, 0xd6, 0xd3, 0x8b, 0xab, 0x46, 0xaa, 0x42, 0x9e, + 0xcb, 0x18, 0xf2, 0xae, 0xa7, 0xd4, 0x59, 0x0c, 0xe3, 0x8e, 0x5a, 0x83, + 0xf1, 0xb4, 0x6d, 0xb9, 0x9d, 0x76, 0x91, 0xab, 0x9d, 0x37, 0xea, 0xaa, + 0x6a, 0xdd, 0x36, 0xa5, 0x8e, 0xda, 0x51, 0x81, 0x57, 0xa9, 0xbf, 0xaf, + 0x4e, 0x88, 0x0f, 0x54, 0x71, 0x98, 0x76, 0x7a, 0xa8, 0xce, 0xd7, 0x79, + 0x89, 0xb1, 0xe5, 0x27, 0xe4, 0xfc, 0x6f, 0x6b, 0xde, 0xf6, 0x93, 0x92, + 0x93, 0x0c, 0x3a, 0xf0, 0x66, 0xc3, 0x55, 0x33, 0x4f, 0x1c, 0x3b, 0xa0, + 0x62, 0x28, 0x61, 0xd9, 0xfb, 0x6b, 0xb4, 0xe3, 0xeb, 0x77, 0x1e, 0x42, + 0xe8, 0x19, 0x14, 0xfb, 0x08, 0x99, 0x76, 0x74, 0x3d, 0x77, 0x24, 0x78, + 0x2d, 0x76, 0xb1, 0x5e, 0x6a, 0x7e, 0x91, 0x14, 0xc8, 0x6d, 0x06, 0x56, + 0x92, 0x13, 0x8b, 0xcf, 0x6d, 0x60, 0xfc, 0xeb, 0xa0, 0xfd, 0x9c, 0x64, + 0x2c, 0xc2, 0xb5, 0x35, 0x19, 0xc6, 0x05, 0xc6, 0x66, 0xc3, 0xa8, 0x57, + 0x8f, 0x61, 0x0d, 0x79, 0x2d, 0x39, 0xcf, 0x44, 0x0b, 0x76, 0x9a, 0xb1, + 0x95, 0x4f, 0xbd, 0x5f, 0x59, 0xc4, 0xfd, 0xb7, 0xa0, 0xfb, 0x90, 0x87, + 0x3e, 0xc1, 0x30, 0x1e, 0xd0, 0xff, 0x12, 0x65, 0x83, 0xdd, 0x9d, 0x65, + 0x94, 0xc7, 0xe7, 0xc1, 0x48, 0x07, 0x31, 0x7d, 0xd3, 0x31, 0x45, 0xee, + 0xa5, 0x7e, 0x8b, 0xe7, 0x11, 0x30, 0xf9, 0xf6, 0x8e, 0xc4, 0x03, 0xf4, + 0x71, 0xff, 0x1d, 0x3b, 0x54, 0x65, 0x19, 0xdd, 0x1d, 0x39, 0x23, 0xfc, + 0x6a, 0x93, 0x76, 0xf2, 0xbc, 0xfd, 0xfb, 0xd0, 0xe7, 0x34, 0xf2, 0x99, + 0xf8, 0x79, 0x69, 0x0b, 0x5c, 0x88, 0x76, 0xe2, 0x68, 0x9a, 0x7a, 0x1d, + 0xed, 0xc3, 0xb1, 0xb4, 0xcc, 0x29, 0x9c, 0xab, 0x01, 0xb1, 0x41, 0x3b, + 0xc6, 0x75, 0x5f, 0xb8, 0x98, 0x72, 0xc9, 0x0f, 0x7a, 0xc3, 0x6b, 0x88, + 0xb1, 0x7d, 0xc3, 0x69, 0xbc, 0xb9, 0xdb, 0xdb, 0x5e, 0xa7, 0x68, 0x88, + 0x4e, 0x40, 0x7d, 0x6e, 0x49, 0x1a, 0xa7, 0x46, 0x1e, 0x86, 0xa7, 0xca, + 0xeb, 0x59, 0xa9, 0xb4, 0x62, 0xeb, 0xc4, 0xd7, 0xe5, 0x9c, 0x34, 0xce, + 0xdd, 0x8a, 0x08, 0x65, 0xbf, 0x1d, 0xff, 0x38, 0x57, 0x70, 0xac, 0x77, + 0xa2, 0x10, 0x35, 0xf4, 0x47, 0xaf, 0x98, 0x7e, 0xd7, 0xb2, 0xa3, 0x6a, + 0xed, 0x53, 0xe3, 0x89, 0x8c, 0x5f, 0xff, 0xf3, 0xf2, 0xfa, 0xb1, 0x11, + 0x56, 0x45, 0x5e, 0xd2, 0xaf, 0x9a, 0xdc, 0x40, 0x78, 0x81, 0xe5, 0xbf, + 0x4b, 0xb5, 0xf7, 0x8d, 0x87, 0xcd, 0x31, 0x46, 0x39, 0x8f, 0xec, 0x29, + 0x90, 0xd9, 0xb7, 0x8e, 0xdf, 0x46, 0x25, 0xf7, 0xa1, 0xe2, 0x98, 0x2e, + 0x38, 0xd2, 0x4a, 0x5b, 0x75, 0x62, 0x53, 0x03, 0xcd, 0xd1, 0xac, 0x09, + 0x4c, 0x63, 0x67, 0xf2, 0xf7, 0xc6, 0xf3, 0xd4, 0xa3, 0x55, 0xe4, 0x34, + 0x1e, 0xe2, 0xc0, 0x33, 0xc1, 0x07, 0xc8, 0x4b, 0xb9, 0xe7, 0x84, 0x83, + 0x18, 0xa4, 0x20, 0xd1, 0x48, 0xfb, 0x0f, 0x2e, 0xc4, 0x94, 0xd9, 0xfe, + 0xb1, 0xb9, 0x56, 0xae, 0xb1, 0x61, 0x9e, 0x15, 0x2b, 0x8a, 0xfc, 0xff, + 0x23, 0xf2, 0x7b, 0xcd, 0xf0, 0x94, 0x89, 0xfc, 0x1c, 0x70, 0xfb, 0x1b, + 0xb0, 0x8f, 0x6d, 0xce, 0xec, 0x76, 0x60, 0x40, 0x6b, 0xc5, 0xc0, 0x04, + 0x3c, 0x9f, 0xb3, 0xcd, 0xbb, 0x23, 0xbf, 0x98, 0x6b, 0x71, 0x87, 0xf7, + 0xd0, 0x1d, 0x7d, 0xc1, 0x58, 0x5e, 0x26, 0xfb, 0x95, 0x7b, 0x3e, 0x6d, + 0x6c, 0x9f, 0xcd, 0xfb, 0x3d, 0x6b, 0x3c, 0x62, 0xfa, 0x89, 0x7f, 0x9a, + 0x2b, 0x75, 0xb9, 0xd7, 0x13, 0x06, 0x2e, 0xea, 0xe7, 0xe4, 0xfd, 0x49, + 0x93, 0xeb, 0xf5, 0x26, 0xe4, 0x6c, 0x65, 0x6d, 0xc7, 0x32, 0xf2, 0x28, + 0xa8, 0xba, 0x71, 0xdd, 0x67, 0x33, 0x39, 0x50, 0xe1, 0x10, 0x22, 0xab, + 0x2c, 0xd7, 0xf0, 0x64, 0xf2, 0x6e, 0xc7, 0xd1, 0x93, 0x94, 0x9a, 0xb9, + 0xbc, 0x9f, 0x5d, 0x82, 0x17, 0xf5, 0x87, 0xb0, 0xa0, 0xec, 0x0f, 0x9c, + 0x4f, 0x72, 0x30, 0xad, 0x1c, 0xcf, 0x30, 0x36, 0xea, 0xf5, 0xfa, 0x45, + 0x7c, 0x13, 0x53, 0x15, 0x21, 0xb3, 0x86, 0x91, 0xd7, 0xe4, 0x51, 0xb4, + 0x3d, 0x6b, 0xe0, 0x2c, 0xd5, 0x88, 0xfd, 0xa2, 0x93, 0x82, 0x31, 0xb2, + 0x26, 0xc1, 0x19, 0xc9, 0xf1, 0x4b, 0x4e, 0x3c, 0x12, 0xae, 0x69, 0xea, + 0x54, 0x1e, 0x64, 0xcc, 0xff, 0x4e, 0x50, 0xde, 0x21, 0xf4, 0xb7, 0xd7, + 0xd8, 0x90, 0x37, 0x19, 0xca, 0xc5, 0x2f, 0x83, 0x72, 0x9f, 0x1b, 0xae, + 0xb1, 0xb4, 0x37, 0xd2, 0x68, 0x57, 0x5d, 0x69, 0xb3, 0x56, 0x29, 0xb8, + 0x9b, 0xa0, 0xcc, 0x89, 0x2d, 0x26, 0xa6, 0xdc, 0x85, 0x15, 0xe6, 0x39, + 0xab, 0xf4, 0xa7, 0xc2, 0x1b, 0x8e, 0x90, 0x37, 0x00, 0xb9, 0x03, 0xc6, + 0xb2, 0xe6, 0x60, 0xbd, 0xde, 0x87, 0xdb, 0xc9, 0xfd, 0x97, 0xe1, 0x23, + 0x5d, 0xea, 0x24, 0x91, 0x6f, 0x39, 0xcc, 0xfb, 0x38, 0x87, 0x83, 0x5b, + 0xa3, 0x2b, 0xb1, 0x7f, 0x30, 0xa2, 0x38, 0x9b, 0xbc, 0xad, 0x31, 0xf2, + 0x22, 0x42, 0xba, 0x99, 0x23, 0xdc, 0x41, 0xfe, 0x70, 0x38, 0xd4, 0x89, + 0xed, 0x7a, 0x2e, 0x7a, 0xf5, 0x70, 0x5e, 0xcf, 0x92, 0x2e, 0xbc, 0xa2, + 0x17, 0x4a, 0x1e, 0x9e, 0xf8, 0xae, 0x6d, 0x4a, 0xc2, 0xdf, 0xf1, 0x21, + 0xbc, 0x53, 0x47, 0xc9, 0x41, 0xce, 0xdb, 0x15, 0xf8, 0x97, 0x3a, 0x5c, + 0xb1, 0xb1, 0x26, 0xec, 0x9b, 0xa8, 0x70, 0xc5, 0xc7, 0x18, 0x0f, 0x4e, + 0x30, 0x86, 0x61, 0x1c, 0xac, 0x8d, 0xad, 0xc4, 0xb6, 0x61, 0xb9, 0xe3, + 0x1b, 0xc0, 0xdd, 0x65, 0xe7, 0x8c, 0xa7, 0xfd, 0x82, 0xa3, 0xf3, 0x71, + 0x67, 0x99, 0xcf, 0xf4, 0x81, 0xed, 0xb6, 0xaf, 0xe3, 0x0f, 0x76, 0x6c, + 0x0e, 0xfe, 0xc8, 0x08, 0x3f, 0x26, 0x72, 0x7b, 0x9e, 0x67, 0xf4, 0x00, + 0xb1, 0xd4, 0x92, 0xe1, 0x86, 0x6b, 0x32, 0x0c, 0xa1, 0x7b, 0x30, 0x44, + 0xfb, 0x71, 0x93, 0x6f, 0x5d, 0x3f, 0x87, 0xf5, 0xba, 0x6f, 0x66, 0x08, + 0xad, 0x78, 0x65, 0xe2, 0x6f, 0xd8, 0x4f, 0xf2, 0x33, 0x4b, 0xd1, 0x91, + 0x89, 0x47, 0xc2, 0xb6, 0x02, 0xf2, 0x3f, 0xcb, 0x0f, 0x0c, 0x0c, 0xcb, + 0x73, 0xef, 0xbe, 0x30, 0xb9, 0xcc, 0x8b, 0x0d, 0x33, 0xd4, 0xc3, 0x48, + 0xa7, 0xdd, 0x7c, 0x2f, 0xe2, 0xca, 0xf7, 0xdc, 0x75, 0xde, 0x75, 0x33, + 0x0a, 0xf0, 0x17, 0x31, 0xfa, 0x64, 0x9b, 0xf4, 0x95, 0xb1, 0x9d, 0x38, + 0xd8, 0x30, 0x1f, 0x53, 0x6b, 0x65, 0x4c, 0x99, 0xcf, 0x30, 0x9e, 0xa3, + 0x8e, 0xff, 0x00, 0x4e, 0xe4, 0xde, 0x65, 0xc7, 0x39, 0x95, 0xb6, 0xa2, + 0xff, 0xde, 0x48, 0xd3, 0x57, 0x6e, 0xcd, 0xd8, 0xcc, 0x36, 0xda, 0xcc, + 0x28, 0x6d, 0xa6, 0x9f, 0x36, 0x73, 0xf7, 0xa2, 0x3b, 0x32, 0x36, 0x23, + 0xb1, 0xe1, 0x34, 0x1e, 0xe9, 0x57, 0xd1, 0xf6, 0x9f, 0xa6, 0xd1, 0x76, + 0x20, 0xbb, 0x76, 0xd1, 0xbb, 0xec, 0xfa, 0xa5, 0xde, 0x28, 0xf3, 0xc8, + 0x1a, 0x65, 0x2f, 0xd9, 0xdf, 0xaf, 0x7f, 0xaf, 0xd6, 0x9c, 0x78, 0xc2, + 0xdc, 0xd7, 0xdf, 0x57, 0x5b, 0x75, 0xfa, 0xec, 0x7e, 0xc2, 0x37, 0x7d, + 0xaf, 0xbd, 0xed, 0xc6, 0xef, 0x7b, 0xdd, 0x37, 0x7e, 0x3f, 0x79, 0xd3, + 0xf3, 0xac, 0x6d, 0x5c, 0x97, 0x69, 0xa7, 0xee, 0xeb, 0x9c, 0xe4, 0x3e, + 0x3f, 0xba, 0xeb, 0xb0, 0xd1, 0xfe, 0xb0, 0xac, 0x25, 0x40, 0x9e, 0x24, + 0xeb, 0x7b, 0x0f, 0x0b, 0xfe, 0x68, 0x6d, 0xef, 0x64, 0x6c, 0xc9, 0x7c, + 0x37, 0xc8, 0xd4, 0xab, 0xd7, 0x27, 0x34, 0xfc, 0xf8, 0x86, 0xfb, 0x8b, + 0x01, 0x65, 0x47, 0x4c, 0x74, 0xca, 0x11, 0x71, 0x35, 0x41, 0xb9, 0xd3, + 0x1f, 0xc1, 0x42, 0x7f, 0x17, 0x3e, 0xa2, 0xce, 0xb7, 0x29, 0x1a, 0xe3, + 0xbb, 0x24, 0xe2, 0x63, 0x5e, 0x7d, 0x13, 0xb1, 0x22, 0x36, 0xf6, 0x97, + 0x38, 0x91, 0xcc, 0xa7, 0x0e, 0x76, 0x61, 0x65, 0xd0, 0x1b, 0x18, 0xa2, + 0xef, 0xbd, 0xa0, 0x8b, 0x9d, 0x4a, 0xed, 0xd7, 0x43, 0x0c, 0x0d, 0x08, + 0x06, 0xaa, 0x29, 0xf1, 0xc9, 0xb4, 0x3d, 0xe1, 0xd8, 0x0e, 0xea, 0xc6, + 0xd6, 0xe1, 0xb7, 0xd0, 0x12, 0x95, 0x7c, 0xeb, 0x71, 0x3c, 0x9a, 0xa4, + 0x0f, 0xd2, 0x68, 0xb7, 0x8b, 0x1c, 0xd0, 0xca, 0x24, 0x27, 0xec, 0xc0, + 0xda, 0xf8, 0x7c, 0x44, 0xaa, 0xa4, 0xae, 0xb2, 0x12, 0xdb, 0x07, 0x15, + 0xfc, 0x56, 0x6a, 0x98, 0x8c, 0xc1, 0x5f, 0x27, 0x47, 0x9c, 0x8c, 0x6e, + 0xc1, 0x88, 0x59, 0xa3, 0xd6, 0xfa, 0xaa, 0xed, 0xe1, 0x17, 0x4b, 0xc9, + 0xb7, 0x13, 0xba, 0xbf, 0x9d, 0xf6, 0xe8, 0x29, 0x6a, 0xf2, 0x87, 0x63, + 0xca, 0x57, 0xf8, 0x37, 0xf3, 0xae, 0x8d, 0xee, 0xda, 0x44, 0x5d, 0xdf, + 0x33, 0x2c, 0xfd, 0xb8, 0xc7, 0x5b, 0xe6, 0x3a, 0xac, 0x77, 0xdd, 0xad, + 0xbc, 0xe4, 0x5b, 0x38, 0x98, 0x76, 0xe1, 0xa9, 0xb8, 0x47, 0xb1, 0xef, + 0x51, 0xd1, 0x12, 0xf7, 0x9e, 0xbc, 0x60, 0x37, 0x8c, 0xba, 0xc5, 0x25, + 0x98, 0x21, 0xbf, 0xa8, 0x5c, 0x2c, 0x3e, 0xe1, 0x3f, 0x23, 0x55, 0xd5, + 0x4c, 0x6c, 0x43, 0xa1, 0x6d, 0x89, 0x57, 0xb7, 0xd9, 0x7d, 0xad, 0x33, + 0xd8, 0x8a, 0xbc, 0xb1, 0x07, 0xcc, 0x75, 0x7f, 0x23, 0x2e, 0xef, 0x2f, + 0xd5, 0x53, 0xdf, 0xe8, 0x27, 0x0f, 0x89, 0x0c, 0x11, 0xa9, 0x6c, 0x82, + 0xa7, 0xa2, 0x69, 0xd7, 0x7c, 0xe4, 0x7f, 0x45, 0xce, 0x3d, 0x8d, 0x89, + 0xa4, 0xd6, 0x51, 0x62, 0x33, 0x70, 0x3a, 0x78, 0x27, 0x52, 0x66, 0x0d, + 0x63, 0x25, 0xfa, 0x07, 0x25, 0x3f, 0xaf, 0x40, 0x5b, 0x54, 0x40, 0xce, + 0xa7, 0x05, 0x5e, 0xb4, 0x49, 0xcd, 0x79, 0x0b, 0xbe, 0xc1, 0xbd, 0xde, + 0x1f, 0x15, 0x7b, 0xd5, 0xdc, 0x6d, 0x4a, 0xf8, 0xaa, 0x9d, 0x7b, 0xfd, + 0xb5, 0xee, 0x3f, 0xf9, 0x6b, 0xbb, 0x7f, 0x2a, 0x64, 0xd7, 0x5d, 0x93, + 0xe3, 0x2a, 0x31, 0xc4, 0x8a, 0x31, 0xd3, 0xe4, 0xb4, 0x85, 0x1c, 0xb7, + 0x20, 0x78, 0x89, 0xdc, 0x40, 0xc6, 0x5d, 0x3e, 0x0f, 0xc5, 0x2d, 0xe8, + 0xdf, 0xfb, 0xa1, 0x11, 0x6e, 0x93, 0x39, 0xfe, 0xc0, 0xb8, 0xd4, 0x89, + 0x95, 0x6b, 0x3d, 0x58, 0x11, 0x97, 0x9c, 0xea, 0x8f, 0x2b, 0x2d, 0xdd, + 0x92, 0xef, 0x0e, 0x74, 0xe8, 0x04, 0xdb, 0xaa, 0x2f, 0x8d, 0x0a, 0x33, + 0x66, 0xbd, 0x6f, 0xbe, 0xe8, 0x4b, 0x6f, 0xe2, 0x85, 0xf9, 0x62, 0xdf, + 0xbd, 0x13, 0x4f, 0xbb, 0x2d, 0xbd, 0x7b, 0x99, 0xdf, 0x65, 0x2c, 0x6d, + 0xdf, 0x16, 0x9c, 0xa9, 0x14, 0x5e, 0xf3, 0xe8, 0xf8, 0xec, 0xf6, 0x56, + 0xbd, 0xea, 0xf5, 0x6b, 0xb9, 0x1a, 0xa9, 0x13, 0x86, 0x95, 0xb6, 0x68, + 0xab, 0xb2, 0x3a, 0x2a, 0xb5, 0x42, 0x5b, 0xa8, 0x80, 0x1c, 0xe6, 0x98, + 0x2e, 0xef, 0xea, 0x65, 0xeb, 0x86, 0x11, 0xa5, 0x2f, 0x44, 0xc6, 0x33, + 0xd6, 0xac, 0xec, 0x88, 0x96, 0xc9, 0x5d, 0x07, 0xea, 0xa5, 0x83, 0x32, + 0x75, 0x21, 0x67, 0x54, 0x62, 0xf2, 0x02, 0xe4, 0x1c, 0xd0, 0x90, 0x3b, + 0xd6, 0x8e, 0x11, 0x32, 0xb8, 0x92, 0xda, 0x72, 0x1c, 0x0a, 0xc8, 0x5d, + 0x8e, 0x0a, 0x14, 0x09, 0xb6, 0x6a, 0x3d, 0x78, 0xb5, 0x0d, 0x4a, 0x41, + 0xed, 0x6c, 0x9e, 0x6a, 0xde, 0x5f, 0x57, 0xdd, 0x4d, 0xe2, 0xdb, 0x25, + 0xc7, 0x6f, 0xd5, 0x1d, 0xcf, 0xa6, 0x37, 0x60, 0x4c, 0xe5, 0xb2, 0xb5, + 0x7f, 0x33, 0xc6, 0x2b, 0xcc, 0x77, 0x7e, 0xc8, 0x81, 0x0f, 0x93, 0x03, + 0x1b, 0xcb, 0xba, 0x82, 0x91, 0x9f, 0xd5, 0xc0, 0xdb, 0xa7, 0xdb, 0xbd, + 0x9e, 0x46, 0x9b, 0xe4, 0x10, 0xa0, 0xe4, 0xd4, 0x46, 0x90, 0x5b, 0x5b, + 0x18, 0xb1, 0x53, 0xbf, 0xcf, 0xe8, 0x22, 0xfb, 0x2e, 0xec, 0xd4, 0xf3, + 0xe5, 0x7d, 0xf9, 0x48, 0x31, 0x79, 0x4b, 0x0c, 0x9a, 0x7a, 0x1a, 0xda, + 0xcc, 0x27, 0xec, 0xb7, 0x82, 0xf6, 0xd0, 0x3d, 0xe6, 0x0d, 0x5f, 0x54, + 0xbc, 0x53, 0x77, 0xd3, 0x46, 0x5e, 0x19, 0xa3, 0x1d, 0x12, 0x77, 0xfb, + 0x69, 0x03, 0x7d, 0xb4, 0x85, 0x7d, 0x13, 0x87, 0x84, 0x47, 0xf4, 0xb5, + 0x2b, 0xd6, 0x3d, 0x4c, 0xab, 0xde, 0x2e, 0x35, 0xb5, 0x88, 0xb2, 0x21, + 0x24, 0x7e, 0xb0, 0x08, 0xe7, 0x93, 0xc0, 0x91, 0x74, 0x0e, 0x5e, 0x1b, + 0x41, 0x8b, 0x0d, 0xf6, 0x5e, 0x17, 0xea, 0xd6, 0xa9, 0x78, 0xa3, 0xae, + 0x40, 0xfe, 0x87, 0x11, 0x15, 0x9d, 0x8c, 0x09, 0xcb, 0xb0, 0x62, 0xb7, + 0xb1, 0xec, 0xae, 0x45, 0xc6, 0xb2, 0xcd, 0xfa, 0x63, 0x58, 0x63, 0x62, + 0x4c, 0x77, 0x7b, 0x01, 0xe3, 0xdb, 0x1f, 0x8e, 0x38, 0x91, 0x4a, 0xb1, + 0x17, 0xe5, 0x35, 0x9c, 0xc2, 0x03, 0x0e, 0x62, 0x27, 0xfd, 0x58, 0x5d, + 0x71, 0x93, 0xbf, 0xed, 0x6e, 0x85, 0xbc, 0x32, 0x5d, 0x81, 0x54, 0x5a, + 0xe3, 0x5f, 0x80, 0x7f, 0x0d, 0xfc, 0x6b, 0xc4, 0x9a, 0xa8, 0xe8, 0xa8, + 0x1b, 0x63, 0xe9, 0x22, 0x7c, 0x98, 0xd4, 0x02, 0x2e, 0xea, 0xcf, 0x88, + 0x3e, 0x6e, 0x44, 0xda, 0xac, 0x38, 0xe4, 0xf3, 0xa4, 0xe4, 0x74, 0x8a, + 0xf0, 0x59, 0xea, 0xf4, 0x7c, 0x8b, 0xdb, 0x77, 0xe1, 0x62, 0x30, 0x3f, + 0x52, 0x6a, 0xfa, 0x1c, 0x6f, 0xe0, 0x35, 0x68, 0xeb, 0xae, 0x70, 0xdf, + 0xbb, 0xc6, 0x52, 0xc6, 0xb9, 0x0a, 0xb1, 0xf5, 0xe3, 0xf8, 0x49, 0xf2, + 0x8a, 0x51, 0x23, 0x9c, 0x33, 0x21, 0xf7, 0xf5, 0xad, 0x3c, 0x8b, 0xc4, + 0x46, 0x85, 0x4b, 0x67, 0x9f, 0xc9, 0x71, 0xa4, 0x53, 0xb3, 0xcf, 0x05, + 0xed, 0x8e, 0x26, 0x57, 0xc3, 0x8e, 0xa8, 0xfd, 0x4a, 0x3e, 0x79, 0xd4, + 0xfd, 0x4b, 0x34, 0xbd, 0x4e, 0x71, 0x35, 0xf4, 0xa6, 0x5d, 0x0d, 0x7d, + 0xd1, 0xd9, 0xe7, 0x7a, 0x44, 0xb1, 0x37, 0xc9, 0x38, 0x7e, 0xc6, 0xdc, + 0xd9, 0xb1, 0x5c, 0x0d, 0xdd, 0xe9, 0xd9, 0x63, 0x75, 0xa1, 0x23, 0x28, + 0x67, 0xe4, 0xdd, 0xe4, 0xbc, 0xa1, 0x6e, 0x20, 0x3e, 0xdc, 0x7c, 0xcf, + 0xa5, 0xe3, 0xbb, 0xd7, 0xfa, 0x6a, 0xc4, 0x32, 0xfa, 0xc5, 0x89, 0xd9, + 0xfd, 0xa7, 0xf1, 0x6e, 0xd2, 0xfc, 0x7f, 0x06, 0x74, 0x7c, 0xce, 0x18, + 0xf1, 0x54, 0xf0, 0xb0, 0xe1, 0x29, 0x15, 0x19, 0x1f, 0xc7, 0x07, 0xdc, + 0x5b, 0xa1, 0xb6, 0xb5, 0xdd, 0xad, 0x69, 0x27, 0x3f, 0xb6, 0x3b, 0x50, + 0xb7, 0xf4, 0x38, 0x4e, 0xa4, 0xe4, 0x0c, 0x8b, 0xcc, 0x77, 0x6d, 0x27, + 0x79, 0x06, 0x07, 0x53, 0xc5, 0xb7, 0xcb, 0xfd, 0x75, 0xbb, 0xdc, 0x63, + 0xc6, 0xff, 0x07, 0xb6, 0x0b, 0xca, 0xea, 0xc4, 0x79, 0x00, 0x00, 0x00 }; static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = { - 0x08004070, 0x08003f70, 0x08004014, 0x0800402c, 0x08004044, 0x08004064, - 0x08004070, 0x08004070, 0x08003f78, 0x00000000, 0x08004a2c, 0x08004a64, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004a9c, 0x08004c60, - 0x08004ba8, 0x08004be0, 0x08004c60, 0x08004b30, 0x08004c60, 0x08004c60, - 0x08004be0, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c20, - 0x08004c60, 0x08004c20, 0x08004ba8, 0x08004c60, 0x08004c60, 0x08004c20, - 0x08004c20, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, 0x08004c60, - 0x08004b0c, 0x00000000, 0x08006078, 0x08006090, 0x08006090, 0x08006090, - 0x08006078, 0x08006090, 0x08006090, 0x08006090, 0x08006078, 0x08006090, - 0x08006090, 0x08006090, 0x08006078, 0x08006090, 0x08006090, 0x08006090, - 0x08006084, 0x00000000, 0x00000000 }; +static const u32 bnx2_RXP_b09FwRodata[(0xb0/4) + 1] = { + 0x80080100, 0x80080080, 0x80080000, 0x08005054, 0x08005054, 0x08005130, + 0x08005104, 0x080050e8, 0x08005024, 0x08005024, 0x08005024, 0x0800505c, + 0x080073b8, 0x08007404, 0x080073c4, 0x080072ec, 0x080073c4, 0x080073f4, + 0x080073c4, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, + 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080073e4, + 0x080073d4, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, + 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, 0x080072ec, + 0x080072ec, 0x080073d4, 0x00000000 }; static struct fw_info bnx2_rxp_fw_09 = { - /* Firmware version: 3.7.1 */ - .ver_major = 0x3, - .ver_minor = 0x7, - .ver_fix = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x08003184, + .start_addr = 0x080031d0, .text_addr = 0x08000000, - .text_len = 0x6788, + .text_len = 0x79c0, .text_index = 0x0, .gz_text = bnx2_RXP_b09FwText, .gz_text_len = sizeof(bnx2_RXP_b09FwText), - .data_addr = 0x08006a20, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_RXP_b09FwData, - .sbss_addr = 0x08006a20, - .sbss_len = 0x20, + .sbss_addr = 0x08007aa0, + .sbss_len = 0x58, .sbss_index = 0x0, - .bss_addr = 0x08006a40, - .bss_len = 0x13dc, + .bss_addr = 0x08007af8, + .bss_len = 0x1c, .bss_index = 0x0, - .rodata_addr = 0x08006788, - .rodata_len = 0x278, + .rodata_addr = 0x080079c0, + .rodata_len = 0xb0, .rodata_index = 0x0, .rodata = bnx2_RXP_b09FwRodata, }; +static u8 bnx2_xi_rv2p_proc1[] = { + /* Date: 12/07/2007 16:21 */ + 0xc5, 0x56, 0xcd, 0x6b, 0x13, 0x51, 0x10, 0x9f, 0xdd, 0xa4, 0xd9, 0x34, + 0xd9, 0x64, 0x97, 0xaa, 0x25, 0xb4, 0x91, 0xa6, 0x55, 0x0f, 0x69, 0x23, + 0xb6, 0xea, 0xc1, 0x43, 0xc1, 0xda, 0x8b, 0xa0, 0x9e, 0x7a, 0x10, 0xf1, + 0xdb, 0x20, 0x05, 0xf1, 0x8f, 0x70, 0x51, 0xab, 0x20, 0x78, 0x28, 0x6a, + 0xb0, 0x0a, 0xea, 0x49, 0x45, 0x3c, 0x34, 0x07, 0x41, 0x50, 0x14, 0x14, + 0x3c, 0xe9, 0x4d, 0xf0, 0xe3, 0x50, 0x15, 0x3f, 0x0e, 0x7a, 0x13, 0x8f, + 0xda, 0xf8, 0xde, 0xcc, 0xef, 0xd9, 0xdd, 0x4d, 0xd3, 0x14, 0x0f, 0xba, + 0xd0, 0xfc, 0xfa, 0xde, 0x9b, 0x37, 0x6f, 0xe6, 0x37, 0xf3, 0x66, 0x9e, + 0x4f, 0x44, 0x36, 0x05, 0xf5, 0x3e, 0x85, 0x94, 0xb5, 0x12, 0x69, 0x05, + 0x16, 0xd1, 0x5d, 0x97, 0x31, 0xd8, 0x40, 0xf2, 0x0d, 0x09, 0x04, 0x43, + 0xbe, 0xfa, 0xfd, 0x4e, 0x5b, 0x4b, 0x1a, 0x13, 0xb4, 0xb5, 0x5f, 0xe3, + 0x36, 0x7a, 0x5c, 0x2a, 0x28, 0xfc, 0xd5, 0xa0, 0x40, 0x8f, 0xd7, 0xcc, + 0xde, 0xaf, 0x67, 0x59, 0xef, 0x3b, 0xec, 0x7f, 0x9d, 0x10, 0xdc, 0x52, + 0x49, 0x8b, 0x1e, 0x20, 0xad, 0xf7, 0x19, 0x5e, 0x4e, 0xeb, 0x71, 0xd1, + 0x0a, 0xd6, 0xe3, 0x7c, 0x5b, 0xe6, 0xe7, 0xa6, 0x3d, 0x3d, 0x4f, 0xef, + 0xc7, 0xf5, 0xd8, 0xcb, 0x9c, 0xae, 0xa7, 0x59, 0xaf, 0xac, 0x77, 0x65, + 0x4e, 0xf3, 0x3e, 0xd7, 0x12, 0x7d, 0xea, 0x8f, 0xf7, 0x6f, 0x56, 0x7a, + 0x60, 0x37, 0x89, 0x9e, 0x43, 0x25, 0x3d, 0x3f, 0x06, 0xb9, 0x51, 0xc8, + 0x15, 0x9b, 0xe4, 0xe6, 0xa6, 0x35, 0x3a, 0x54, 0xad, 0x68, 0x7f, 0xfa, + 0x95, 0xa1, 0xae, 0xf0, 0xd3, 0x27, 0xfe, 0x4e, 0xc2, 0xec, 0x77, 0x83, + 0xfa, 0x1f, 0x65, 0xdb, 0xa0, 0x96, 0x9b, 0x53, 0x7e, 0x1b, 0x7f, 0x8d, + 0xbc, 0xc8, 0x39, 0xac, 0xe7, 0xad, 0x5a, 0x37, 0x7e, 0x85, 0xfd, 0xc9, + 0x86, 0xfc, 0x89, 0xf9, 0xd9, 0xe4, 0x57, 0x98, 0xa7, 0xf4, 0x22, 0x76, + 0xeb, 0x73, 0x94, 0x0d, 0x7c, 0x4e, 0x0a, 0xfc, 0xa6, 0x62, 0xfb, 0x52, + 0x2d, 0xf6, 0x7d, 0x6a, 0x2c, 0xf8, 0x69, 0xd6, 0xf5, 0xfc, 0xd3, 0x85, + 0xf9, 0x72, 0x74, 0x5d, 0xfc, 0xef, 0x80, 0xff, 0x8f, 0xe0, 0xdf, 0x0e, + 0x5a, 0x6b, 0x17, 0x78, 0x3d, 0xc9, 0xfb, 0x7b, 0x95, 0x3d, 0x1a, 0x57, + 0x03, 0xfb, 0x81, 0x07, 0x81, 0x07, 0x80, 0xab, 0x80, 0x2b, 0x81, 0x2b, + 0x80, 0x5d, 0xc0, 0xcb, 0x40, 0x1f, 0xe8, 0x01, 0xf3, 0xc0, 0x8b, 0x40, + 0x17, 0x98, 0x05, 0xd6, 0x80, 0x57, 0x81, 0x69, 0xe0, 0x31, 0xe0, 0x23, + 0xe0, 0x13, 0xe0, 0x37, 0xe0, 0x39, 0xa3, 0xcf, 0xc2, 0xb9, 0x40, 0x42, + 0x3e, 0x58, 0x31, 0x9e, 0xae, 0x21, 0xef, 0x35, 0xcf, 0x58, 0x2f, 0x1b, + 0x39, 0xc4, 0x97, 0x79, 0x9a, 0x81, 0x5c, 0xd7, 0xec, 0x8d, 0xd8, 0xfd, + 0x28, 0xb5, 0xbd, 0x17, 0xf1, 0xb8, 0x79, 0xec, 0xcf, 0xe1, 0xed, 0x1e, + 0x9f, 0x93, 0x4f, 0xc9, 0xbc, 0x31, 0x6b, 0x8f, 0x27, 0x78, 0x34, 0x23, + 0xf8, 0x39, 0xd3, 0xa9, 0x7e, 0x1b, 0x8d, 0xc9, 0xac, 0x8c, 0x8f, 0xe4, + 0x0c, 0xcf, 0x46, 0x8f, 0xb1, 0xa7, 0x9d, 0x1d, 0xad, 0xce, 0x33, 0x76, + 0xb5, 0x3b, 0x57, 0xb0, 0x6a, 0x47, 0xfd, 0xbf, 0x32, 0x2c, 0x98, 0x1c, + 0x61, 0xa8, 0xb8, 0xa9, 0xa4, 0xc6, 0xcd, 0xee, 0x33, 0x73, 0x8e, 0x46, + 0xb7, 0x50, 0xe3, 0xfb, 0x92, 0xa4, 0x5a, 0x4a, 0xeb, 0xfd, 0xd9, 0x38, + 0x2f, 0x72, 0x3d, 0x47, 0x5e, 0x30, 0x16, 0xae, 0x3c, 0x17, 0xf9, 0x57, + 0x25, 0x97, 0x71, 0xf7, 0x10, 0xc5, 0x3e, 0xb3, 0x2e, 0xf7, 0x31, 0x60, + 0xbb, 0x7f, 0x58, 0x41, 0xdd, 0x9c, 0x83, 0x7d, 0xc7, 0x4d, 0x1c, 0x7d, + 0xb6, 0x73, 0x80, 0x64, 0x3c, 0x51, 0x96, 0xf5, 0x89, 0x32, 0xee, 0xf3, + 0x40, 0x34, 0x1f, 0xe4, 0x5e, 0x24, 0x10, 0xef, 0x7d, 0xb8, 0x17, 0xf1, + 0x7b, 0x9c, 0x9e, 0xbd, 0x31, 0x1d, 0xce, 0x97, 0x02, 0x55, 0x47, 0x60, + 0x4f, 0x53, 0x9c, 0x4d, 0x3d, 0x36, 0xf9, 0xce, 0xd3, 0xb3, 0x41, 0x22, + 0xc2, 0xdf, 0x18, 0x55, 0xc2, 0x71, 0xb2, 0x16, 0xc9, 0x97, 0x76, 0xe7, + 0x44, 0xf4, 0xe5, 0x55, 0x04, 0xa8, 0x39, 0x8f, 0x1d, 0xf8, 0x35, 0x86, + 0x3c, 0xee, 0x6d, 0xca, 0x63, 0x53, 0xe7, 0x25, 0x9f, 0x5b, 0xd5, 0xaf, + 0xbf, 0xaf, 0xcf, 0x22, 0x17, 0x84, 0xf2, 0xd3, 0xd4, 0x43, 0xf0, 0xe4, + 0xb0, 0x5c, 0x71, 0xee, 0x9e, 0xc4, 0x4d, 0xea, 0xb8, 0x4a, 0xc6, 0x20, + 0x6a, 0xa7, 0x63, 0xfc, 0xeb, 0x0b, 0xd7, 0xc1, 0x75, 0x2d, 0xe2, 0x15, + 0xae, 0xbb, 0x71, 0x5e, 0xa2, 0x79, 0x2f, 0xf1, 0xcf, 0x80, 0xa7, 0xde, + 0x36, 0x75, 0xa1, 0x13, 0x72, 0xdd, 0x4b, 0xc8, 0x89, 0xde, 0xf1, 0x72, + 0xb8, 0x8e, 0xf8, 0x0d, 0xd4, 0xc1, 0x3f, 0x71, 0x78, 0xd8, 0x22, 0x0e, + 0xa3, 0xff, 0x37, 0x0e, 0xe8, 0xa7, 0xed, 0xe2, 0x40, 0xb1, 0x38, 0xfc, + 0x98, 0x5f, 0x5e, 0x1c, 0x08, 0x3c, 0x51, 0x8b, 0x38, 0xa4, 0xc0, 0xd7, + 0xd7, 0xf9, 0xa5, 0xe3, 0x90, 0x85, 0xdc, 0xe7, 0x90, 0x1c, 0xdb, 0x3d, + 0x2a, 0xf7, 0xd4, 0xa9, 0x7e, 0x89, 0xf1, 0x3b, 0x52, 0xd1, 0xf5, 0xe7, + 0x04, 0xd5, 0xe1, 0xff, 0x9b, 0x08, 0x0f, 0x39, 0x65, 0x9f, 0xbc, 0x23, + 0x6e, 0xd7, 0x0d, 0x5f, 0xb2, 0x5c, 0xaa, 0x08, 0xde, 0x62, 0x79, 0x3f, + 0xc4, 0x5b, 0x94, 0x5f, 0xe1, 0xcd, 0xa7, 0x9b, 0x7f, 0xea, 0x92, 0xc7, + 0xfa, 0x86, 0x51, 0xd7, 0x0f, 0xa3, 0xbe, 0x7e, 0xc8, 0x48, 0xfd, 0xae, + 0xee, 0xe4, 0x3a, 0x4b, 0xdd, 0xa8, 0xb3, 0xd5, 0x9c, 0x8c, 0x7b, 0x72, + 0xf2, 0x6e, 0x19, 0x76, 0x5c, 0x96, 0xeb, 0xc9, 0x09, 0x76, 0x67, 0xf5, + 0xbe, 0x02, 0x7d, 0xdc, 0xc5, 0xe2, 0x95, 0x19, 0x57, 0xea, 0xed, 0xcc, + 0x73, 0xd4, 0x7f, 0xcf, 0xf0, 0x04, 0x7f, 0x37, 0xe9, 0xf9, 0x6e, 0x55, + 0xef, 0xc2, 0xfc, 0x2a, 0x99, 0x41, 0xb1, 0xef, 0x3a, 0xac, 0x2f, 0x99, + 0x7d, 0x7d, 0x9a, 0xcf, 0x07, 0xf3, 0xa6, 0xbf, 0x0c, 0x6c, 0xd7, 0xf6, + 0x78, 0x94, 0x77, 0x24, 0x9e, 0x82, 0x4a, 0xce, 0x76, 0xf4, 0xb6, 0xe2, + 0x94, 0x2d, 0xe3, 0xa9, 0x93, 0xac, 0x66, 0xd7, 0x94, 0x99, 0x1f, 0xe7, + 0x44, 0x9e, 0xb8, 0xf3, 0x94, 0xe7, 0xf3, 0xf5, 0x84, 0xcc, 0x3b, 0x3b, + 0x0d, 0x1f, 0x1e, 0xfb, 0x57, 0x13, 0x3e, 0xf6, 0x5f, 0x12, 0xdc, 0xab, + 0x9e, 0x22, 0xfa, 0xcb, 0xd4, 0x5c, 0xe9, 0x3f, 0x33, 0x6e, 0x9a, 0x91, + 0x98, 0x0f, 0x7b, 0xa3, 0xf4, 0x91, 0x0e, 0xd4, 0xff, 0xce, 0x50, 0x9c, + 0xe2, 0x7d, 0x79, 0xb9, 0xf1, 0x0a, 0xf7, 0x0b, 0xd3, 0x47, 0xe2, 0x7d, + 0x21, 0x87, 0x3c, 0xbb, 0xdc, 0x26, 0x1f, 0x4d, 0x9d, 0xbd, 0x80, 0x7b, + 0xb0, 0x58, 0x3f, 0xd6, 0x98, 0x6f, 0xf1, 0x8e, 0x28, 0x22, 0xff, 0x4c, + 0xdf, 0x5c, 0xec, 0xbd, 0x20, 0xf2, 0xcb, 0x7b, 0x27, 0xf8, 0x2d, 0xde, + 0x09, 0xff, 0xec, 0x3d, 0x50, 0x58, 0x88, 0xa3, 0xc9, 0xd3, 0x70, 0x1c, + 0xc3, 0xf9, 0x1a, 0xef, 0xd7, 0x4b, 0xf5, 0xe9, 0x3c, 0x78, 0x9e, 0x04, + 0xcf, 0x49, 0xea, 0x48, 0x30, 0x31, 0x6e, 0xf2, 0x14, 0xeb, 0xb5, 0xa7, + 0x6c, 0x16, 0x77, 0x3b, 0xce, 0x58, 0x1a, 0xf3, 0xee, 0x19, 0x91, 0x4b, + 0xca, 0x7c, 0xc1, 0xe0, 0xd9, 0x53, 0xf2, 0x3e, 0xb4, 0xe9, 0x37, 0xf9, + 0x0f, 0x65, 0x7b, 0x50, 0x0d, 0x00, 0x00, 0x00 }; + +static u8 bnx2_xi_rv2p_proc2[] = { + /* Date: 12/07/2007 16:21 */ + 0xad, 0x58, 0x5d, 0x6c, 0xd3, 0x55, 0x14, 0xbf, 0xfd, 0x58, 0xdb, 0xb5, + 0xff, 0xb6, 0x63, 0x9b, 0xdd, 0xa7, 0x6e, 0x6e, 0x61, 0x6c, 0xd8, 0xcd, + 0xd1, 0x8d, 0x4f, 0x4d, 0x5c, 0x86, 0x19, 0x20, 0x26, 0x8c, 0x61, 0xd4, + 0x37, 0xd8, 0x90, 0xb2, 0xb1, 0x8d, 0x2c, 0x8c, 0xf0, 0xc0, 0x8b, 0x0d, + 0xd3, 0xf1, 0xd2, 0x07, 0x47, 0xb2, 0x0d, 0x8d, 0xc1, 0x45, 0x7d, 0x40, + 0x9f, 0xec, 0x83, 0x32, 0x30, 0xc6, 0xc4, 0xe8, 0x42, 0xf0, 0x01, 0x48, + 0x30, 0xc6, 0x68, 0x48, 0x08, 0xea, 0x32, 0x10, 0x75, 0x0c, 0xfb, 0x64, + 0x98, 0xf7, 0x9e, 0xdf, 0xb9, 0xff, 0xfe, 0xff, 0x6d, 0x27, 0x18, 0xec, + 0x43, 0x4f, 0xef, 0xbd, 0xe7, 0x9e, 0x7b, 0x3e, 0x7e, 0xe7, 0x9c, 0x7b, + 0x5b, 0x24, 0x84, 0x70, 0x8a, 0x44, 0xaa, 0x46, 0x52, 0x11, 0x70, 0xb8, + 0x04, 0x3e, 0x6b, 0x8b, 0x88, 0x5c, 0x4b, 0xf9, 0xe4, 0x77, 0x81, 0x78, + 0xc9, 0x59, 0x4e, 0x63, 0xb7, 0x50, 0x34, 0x2c, 0x44, 0xc2, 0x4a, 0x4b, + 0x98, 0x5e, 0x65, 0xfa, 0x3b, 0xd3, 0xc7, 0x1d, 0xa0, 0x57, 0x78, 0xbc, + 0x85, 0xc7, 0xd7, 0x78, 0xfc, 0x23, 0xd3, 0x8d, 0x3c, 0xbf, 0x99, 0x69, + 0x92, 0xe9, 0x76, 0x5e, 0x9f, 0x65, 0x2a, 0x3f, 0x09, 0x43, 0x7e, 0xc9, + 0xe5, 0x26, 0xad, 0xa7, 0x81, 0xe9, 0x26, 0xe8, 0xbb, 0xa7, 0x56, 0xf1, + 0x2d, 0x2c, 0x67, 0xf8, 0x30, 0x7f, 0x7d, 0x02, 0xb4, 0x06, 0xbb, 0x3e, + 0x4e, 0x3c, 0xad, 0xf7, 0x83, 0xf4, 0x06, 0x41, 0xfb, 0xd8, 0xfe, 0x8e, + 0x28, 0x91, 0xe4, 0x7e, 0x27, 0xc6, 0x5d, 0x0d, 0xca, 0x0f, 0xc5, 0xc2, + 0xed, 0x54, 0x72, 0x5a, 0x7c, 0x9e, 0xf3, 0x98, 0x7f, 0x35, 0x0c, 0xfa, + 0x9a, 0x1f, 0xf4, 0x17, 0x7f, 0xa1, 0xfc, 0x5e, 0x5e, 0x8e, 0x07, 0x58, + 0xbe, 0xc1, 0x6a, 0x07, 0xb0, 0x7f, 0xce, 0x80, 0x1e, 0x2f, 0xd7, 0x42, + 0xbf, 0xef, 0x9f, 0x52, 0xf3, 0x2e, 0x91, 0x60, 0x39, 0x42, 0x68, 0x3d, + 0x79, 0x7d, 0x10, 0xfb, 0x56, 0xad, 0xc1, 0xea, 0x5b, 0x71, 0x8c, 0xab, + 0x3e, 0x28, 0xa2, 0xb8, 0x9c, 0x4e, 0x69, 0xfe, 0x7c, 0x72, 0xdd, 0x52, + 0x2e, 0xe4, 0x8b, 0x3a, 0x1f, 0x29, 0x93, 0x88, 0x82, 0x8a, 0xe6, 0xec, + 0x73, 0x20, 0x7f, 0x6a, 0xb5, 0x9a, 0x77, 0x8a, 0x1e, 0x97, 0x9a, 0xf7, + 0x88, 0x9e, 0x01, 0xed, 0x5f, 0xac, 0xc7, 0x3d, 0x44, 0xca, 0x7b, 0xc7, + 0x95, 0x9d, 0x61, 0xb1, 0xcf, 0x19, 0x26, 0x7e, 0xf8, 0xc5, 0xe5, 0x33, + 0x3e, 0x03, 0xff, 0x97, 0x35, 0x06, 0xd9, 0x12, 0x6f, 0xc3, 0xbe, 0xd2, + 0x18, 0xe8, 0x64, 0xac, 0x40, 0x91, 0x68, 0x7c, 0x94, 0x86, 0x2d, 0x37, + 0xd7, 0xf9, 0x88, 0x2f, 0xd1, 0xac, 0xe3, 0xa7, 0xe3, 0xa5, 0xe2, 0xf8, + 0x89, 0x8c, 0x23, 0xbb, 0xa5, 0x1e, 0x7e, 0xfd, 0x75, 0xb5, 0xe2, 0x97, + 0xce, 0xad, 0xc3, 0x39, 0x19, 0xfd, 0xac, 0xf1, 0xff, 0xe8, 0x3f, 0xc4, + 0x5f, 0xc9, 0xeb, 0x60, 0xbf, 0xd4, 0x4a, 0xbf, 0x28, 0x5a, 0xed, 0x48, + 0x34, 0xdb, 0xe3, 0x71, 0x7d, 0x22, 0x4c, 0xbf, 0x6f, 0x75, 0x16, 0x91, + 0x5f, 0x77, 0x61, 0xfe, 0x54, 0xd7, 0x39, 0xc4, 0x63, 0x07, 0xd9, 0x2f, + 0xfc, 0x6f, 0x7c, 0x8a, 0x5d, 0xbd, 0x41, 0x35, 0x7e, 0xa5, 0x3d, 0x7e, + 0x01, 0xeb, 0x05, 0x63, 0xf0, 0xeb, 0x2e, 0x96, 0xba, 0xc3, 0xe5, 0x50, + 0x24, 0xe9, 0x19, 0xa3, 0xa1, 0x31, 0x47, 0xeb, 0x86, 0x38, 0x99, 0xc2, + 0xfa, 0xe1, 0x80, 0x1a, 0xef, 0x8a, 0x2e, 0x60, 0x1c, 0x1d, 0x18, 0xe7, + 0x8d, 0x4e, 0xf8, 0xe1, 0x96, 0x13, 0xf2, 0x18, 0x5e, 0x7e, 0x37, 0xc5, + 0xc1, 0x21, 0x8c, 0x2e, 0xd0, 0x37, 0x69, 0xfd, 0x6f, 0x47, 0x92, 0xec, + 0xee, 0x0a, 0xb9, 0xcf, 0x81, 0x91, 0x71, 0x6d, 0xe2, 0x56, 0xe3, 0xfe, + 0x61, 0xf1, 0x3b, 0x6e, 0x68, 0xbc, 0xb2, 0xff, 0xd9, 0xbf, 0xef, 0x89, + 0x6c, 0x9c, 0x82, 0x76, 0x35, 0x80, 0x7a, 0xea, 0xb3, 0xf1, 0xaa, 0xf1, + 0x69, 0xf7, 0x33, 0xc7, 0xc7, 0x82, 0x17, 0x22, 0x12, 0x27, 0x36, 0xdc, + 0x30, 0x4e, 0x2b, 0xa4, 0xbf, 0x74, 0xfc, 0x95, 0x20, 0xaf, 0x18, 0x64, + 0x79, 0x03, 0x6c, 0xd7, 0x10, 0xdb, 0x75, 0xc7, 0xaf, 0xfd, 0xaa, 0xed, + 0x01, 0x3d, 0x69, 0xb3, 0xc7, 0x21, 0xf1, 0x64, 0xc7, 0x21, 0xeb, 0x93, + 0xfc, 0xa6, 0x0e, 0x3f, 0xaa, 0xea, 0x41, 0x4d, 0x3b, 0x1b, 0x14, 0x9f, + 0x27, 0x36, 0x9d, 0xb2, 0xe3, 0x50, 0xe7, 0xe3, 0x9e, 0x5a, 0x2d, 0x5f, + 0xe1, 0x32, 0x2d, 0x71, 0x89, 0xb8, 0x9d, 0x4e, 0x59, 0xf3, 0xb3, 0x32, + 0x4f, 0x7e, 0xda, 0xf3, 0x42, 0xfb, 0xe5, 0x70, 0x90, 0x0a, 0x54, 0xfb, + 0xe5, 0x79, 0xfb, 0x79, 0xc0, 0xb7, 0xd7, 0xc4, 0x4f, 0xe9, 0x06, 0xf6, + 0x1f, 0xd3, 0xc8, 0x46, 0x25, 0xaf, 0x9b, 0xe5, 0xb7, 0xb2, 0x7c, 0xc3, + 0x92, 0x77, 0x4a, 0xbf, 0x4e, 0x33, 0xdf, 0x74, 0xdc, 0x32, 0x79, 0xa7, + 0xfd, 0x47, 0xe7, 0x47, 0x2f, 0xcf, 0xab, 0xfd, 0x55, 0x0f, 0xc8, 0xc3, + 0x4d, 0xa6, 0xbc, 0xef, 0xcc, 0x7c, 0x53, 0xeb, 0x01, 0xf1, 0x1c, 0x0f, + 0xed, 0xf5, 0xe4, 0x4f, 0x59, 0x4f, 0xc8, 0x0e, 0x9f, 0x71, 0x8e, 0xeb, + 0xc7, 0xa8, 0x3a, 0xa7, 0x9c, 0xf5, 0x2e, 0x67, 0xbd, 0x65, 0xbf, 0x6a, + 0xe6, 0x3a, 0xb3, 0xd7, 0x5a, 0x2f, 0xd6, 0x5a, 0xf2, 0x5e, 0x8d, 0x1b, + 0x97, 0x73, 0xfb, 0x85, 0xcd, 0x9f, 0x09, 0x41, 0xfe, 0xf7, 0x72, 0x7c, + 0x3c, 0x79, 0xfa, 0x8b, 0xe6, 0x07, 0xbe, 0xb6, 0x11, 0xbf, 0xcf, 0xc4, + 0xbf, 0xdd, 0xde, 0xca, 0x3c, 0x75, 0x27, 0xdb, 0x7e, 0xf8, 0xb3, 0xd7, + 0x19, 0x24, 0xbe, 0x1b, 0x23, 0x6a, 0xdf, 0x49, 0x87, 0xf6, 0x53, 0x07, + 0xea, 0x90, 0x03, 0xf6, 0x56, 0xb3, 0xbd, 0x72, 0xb9, 0x99, 0xf0, 0xef, + 0xbb, 0x31, 0x62, 0xb5, 0xd7, 0xf8, 0x97, 0xf3, 0xec, 0xb8, 0x19, 0xe1, + 0x3e, 0xd6, 0x87, 0xbc, 0xf0, 0xed, 0xff, 0x5c, 0xeb, 0xc3, 0xe7, 0x86, + 0xf5, 0xf9, 0x4a, 0x5e, 0x95, 0x98, 0x1f, 0x55, 0xfb, 0x1f, 0x13, 0x0c, + 0x33, 0x31, 0xdc, 0x88, 0xfa, 0x77, 0xe7, 0x00, 0xf4, 0x1f, 0x6e, 0xd0, + 0x7d, 0x1c, 0x38, 0x16, 0x5c, 0xff, 0xbf, 0x9e, 0xc8, 0xe7, 0x97, 0x41, + 0x07, 0xf8, 0x4a, 0xd9, 0xae, 0x22, 0xb6, 0x2b, 0x2a, 0xb2, 0xeb, 0xec, + 0x5e, 0xca, 0x97, 0x0e, 0xe6, 0x7b, 0x56, 0xd7, 0xe3, 0x1c, 0x3e, 0xd8, + 0x5f, 0xc0, 0xe7, 0xe7, 0xf3, 0x57, 0x3e, 0xb9, 0xb3, 0x8c, 0xa3, 0x7e, + 0xe6, 0x73, 0xe7, 0xa9, 0xf3, 0x18, 0xa5, 0xd7, 0x50, 0x9d, 0x3f, 0x73, + 0x7c, 0x56, 0xf1, 0x05, 0x4d, 0x9c, 0xdb, 0xed, 0xfa, 0xe9, 0xfe, 0xa3, + 0xfb, 0x5f, 0xf1, 0x45, 0xc4, 0xc1, 0xd0, 0x4a, 0x7e, 0x76, 0xab, 0xe9, + 0x99, 0xc5, 0x59, 0x1d, 0x27, 0x83, 0xec, 0x9c, 0x1f, 0x55, 0xe7, 0x7f, + 0x98, 0xe5, 0x7f, 0xa7, 0xc5, 0xff, 0xe0, 0x7f, 0x22, 0xfa, 0xa8, 0x7e, + 0xcf, 0xd7, 0x97, 0xbf, 0xb8, 0x9f, 0x9b, 0x27, 0x6a, 0xfe, 0xc2, 0x43, + 0xfb, 0x63, 0x77, 0x9b, 0xd5, 0xfe, 0x7a, 0x31, 0x97, 0x42, 0x7e, 0x75, + 0x33, 0x0e, 0xf7, 0x71, 0xbd, 0xbe, 0xe1, 0x57, 0x13, 0x3e, 0xd1, 0xb7, + 0x93, 0xfc, 0x21, 0x22, 0x01, 0xf8, 0xa7, 0xef, 0x45, 0xed, 0x4f, 0xcc, + 0x57, 0x52, 0xbf, 0x75, 0x89, 0x6e, 0xaf, 0x41, 0xfc, 0x95, 0x41, 0xd0, + 0x08, 0xd7, 0xf9, 0x39, 0xb3, 0x8f, 0x81, 0x9e, 0xf6, 0xe8, 0xba, 0x8c, + 0x7e, 0xfe, 0x95, 0x47, 0x31, 0xc8, 0x20, 0x35, 0xa1, 0x3e, 0x77, 0x36, + 0x18, 0xb4, 0xde, 0xd3, 0x04, 0x3c, 0x89, 0x3a, 0xdd, 0xe7, 0xf0, 0xe1, + 0x3e, 0x50, 0x99, 0xe9, 0x77, 0xd6, 0x7e, 0x58, 0x68, 0xe9, 0x07, 0xfa, + 0x3c, 0xed, 0x47, 0x2d, 0x97, 0x86, 0xb2, 0xaf, 0x58, 0xfb, 0xa1, 0xee, + 0x13, 0x4b, 0xdc, 0x27, 0x4a, 0xc4, 0xc5, 0x14, 0xec, 0x9a, 0x4b, 0x65, + 0xe3, 0x4f, 0x9f, 0xa7, 0xe5, 0x41, 0x6f, 0x6d, 0x47, 0x46, 0x3e, 0xce, + 0x3f, 0xc0, 0x7a, 0xfe, 0x4c, 0xf7, 0xd8, 0x08, 0xdb, 0xa3, 0xe4, 0x62, + 0x7e, 0x3b, 0xf7, 0xe7, 0x84, 0x39, 0xb6, 0xf7, 0xd5, 0x6e, 0xd2, 0xab, + 0x98, 0xf1, 0x16, 0xb1, 0xe4, 0x03, 0xf8, 0x4b, 0x5b, 0x41, 0x27, 0x5b, + 0x75, 0x1c, 0x74, 0xbc, 0x74, 0x7c, 0x10, 0xc7, 0xc8, 0x3a, 0x62, 0x6b, + 0xef, 0x5b, 0x47, 0x7d, 0xa4, 0xb5, 0x6f, 0x51, 0xe3, 0x0f, 0xfb, 0x77, + 0x47, 0x15, 0xff, 0xeb, 0xe2, 0x2a, 0xe1, 0x50, 0x88, 0x1f, 0x98, 0x66, + 0xfa, 0x15, 0x07, 0xc0, 0xcc, 0x57, 0x8e, 0x5f, 0x01, 0x4f, 0xb7, 0xe9, + 0x7a, 0xae, 0xe3, 0x65, 0xcd, 0xd7, 0x78, 0x0e, 0x6e, 0x33, 0x75, 0x59, + 0xdb, 0xa9, 0xf8, 0xa3, 0x8c, 0x47, 0x9f, 0xe8, 0xdc, 0x86, 0x7b, 0x6e, + 0xc8, 0x8b, 0xba, 0x1f, 0xf2, 0x5a, 0xe3, 0x25, 0x71, 0x51, 0xe8, 0x55, + 0xc3, 0xea, 0xe2, 0x42, 0xb2, 0xe7, 0xd4, 0xa5, 0x6f, 0x69, 0xf9, 0xfd, + 0xe9, 0x00, 0xe6, 0xcb, 0x76, 0x86, 0xc9, 0x1f, 0x53, 0xc0, 0xf3, 0xbb, + 0x93, 0xa0, 0xef, 0x88, 0x17, 0xb0, 0xbf, 0xf8, 0x04, 0xdd, 0x03, 0x7d, + 0x65, 0x8c, 0xcf, 0x72, 0xd4, 0x89, 0xe4, 0x34, 0xdd, 0x4b, 0x96, 0x97, + 0x45, 0x50, 0x51, 0x8f, 0xd9, 0x6f, 0x80, 0x4f, 0xb7, 0x25, 0xce, 0x0f, + 0xc2, 0x2b, 0xdd, 0x2b, 0x25, 0x1e, 0xb1, 0x9d, 0x71, 0xeb, 0xcb, 0xc6, + 0xad, 0xf6, 0x47, 0xb9, 0x33, 0x2f, 0x4e, 0x37, 0xd8, 0x71, 0xea, 0x61, + 0x9c, 0xde, 0x33, 0xfb, 0x7b, 0xae, 0x5c, 0xf4, 0xf9, 0x8b, 0xff, 0x1b, + 0x6e, 0x41, 0xb7, 0xd7, 0xab, 0xf3, 0xcb, 0x72, 0xea, 0x71, 0x8d, 0x2d, + 0xce, 0x4d, 0xf7, 0xb5, 0x5e, 0x27, 0x3c, 0xd6, 0xf5, 0x66, 0xb3, 0x9f, + 0x1d, 0xe1, 0x77, 0x5e, 0xda, 0xa0, 0x1f, 0xb1, 0x3b, 0x49, 0x1a, 0x1a, + 0x15, 0x67, 0x15, 0x5f, 0x63, 0xec, 0x08, 0xd7, 0xdb, 0x4b, 0x2e, 0xd4, + 0x9b, 0xfe, 0x03, 0x18, 0x5f, 0xe6, 0xfa, 0x71, 0x77, 0x0d, 0xd5, 0xe5, + 0xd8, 0x91, 0xf3, 0x5a, 0x1e, 0xc9, 0x31, 0xd2, 0x5c, 0xd7, 0x9f, 0x77, + 0x71, 0xbd, 0x25, 0xbf, 0xb9, 0x63, 0x7f, 0xd0, 0x7d, 0xc6, 0x2d, 0x3a, + 0x9f, 0x54, 0xb4, 0x42, 0xd6, 0x6f, 0x3e, 0xff, 0x19, 0xd0, 0x1e, 0x2f, + 0xa8, 0x68, 0xb2, 0xc7, 0x43, 0x98, 0x76, 0x61, 0xe4, 0xa9, 0x63, 0x39, + 0xbd, 0x18, 0x7b, 0xf9, 0x5e, 0x36, 0xcd, 0x7e, 0x0a, 0x91, 0x3f, 0x8a, + 0xa4, 0x9d, 0x8a, 0x86, 0x63, 0xa3, 0xb3, 0xd0, 0x7f, 0x68, 0x2b, 0xec, + 0x5b, 0x62, 0xbb, 0x99, 0x86, 0xde, 0x1e, 0x23, 0xfc, 0x85, 0xc6, 0xf1, + 0x0e, 0x09, 0x79, 0xc6, 0x60, 0xc7, 0x50, 0x1a, 0xe3, 0xa5, 0xcd, 0xa0, + 0x7f, 0x6d, 0xc1, 0xbe, 0xa3, 0xc7, 0xd9, 0x1f, 0x5b, 0xf3, 0xef, 0xeb, + 0xbf, 0x07, 0xbe, 0xe1, 0x46, 0x75, 0xfe, 0xe0, 0x0c, 0xbf, 0x5f, 0xc4, + 0x80, 0x4b, 0x8d, 0x07, 0x8c, 0x34, 0x8f, 0x0f, 0x71, 0x7d, 0xbf, 0xcd, + 0xef, 0x8d, 0xa1, 0xac, 0xf7, 0xc6, 0x02, 0xee, 0x99, 0x33, 0xe9, 0x24, + 0x70, 0x91, 0x28, 0xcc, 0x7e, 0xaf, 0xaa, 0x71, 0x75, 0xac, 0x8c, 0xe3, + 0x54, 0xba, 0x1e, 0x74, 0x72, 0x3d, 0xde, 0x09, 0x43, 0xc7, 0xd8, 0x2f, + 0xed, 0x14, 0xa7, 0x96, 0xc5, 0xd9, 0x95, 0xde, 0xc9, 0xe0, 0x9b, 0xe2, + 0x73, 0x23, 0xdc, 0x4f, 0x22, 0xc8, 0x3f, 0x51, 0x9e, 0xe4, 0x77, 0xcb, + 0x04, 0xee, 0x9d, 0x53, 0x06, 0x68, 0x24, 0xa8, 0xf5, 0x45, 0x3e, 0x26, + 0x52, 0xc8, 0x3b, 0xac, 0x3b, 0x2c, 0xeb, 0x7c, 0x1f, 0xc9, 0x79, 0xe7, + 0x28, 0xba, 0xe4, 0x28, 0x71, 0x68, 0x3b, 0xb1, 0xda, 0x17, 0x54, 0xf8, + 0xbd, 0x69, 0xe6, 0xd5, 0x02, 0xf9, 0xad, 0x6a, 0x26, 0x4d, 0xfa, 0x57, + 0x8a, 0x12, 0xea, 0xc3, 0x15, 0xa1, 0x45, 0xf8, 0x31, 0x36, 0xcd, 0xfe, + 0x1f, 0xd9, 0x04, 0x7a, 0x8c, 0xf1, 0xa7, 0x71, 0x75, 0x65, 0xa3, 0x41, + 0xfb, 0xe6, 0x47, 0x71, 0x8e, 0xbe, 0x47, 0x64, 0xbf, 0xc7, 0x35, 0x1e, + 0x2b, 0xda, 0x50, 0x48, 0xfb, 0x8f, 0xaa, 0x73, 0x82, 0x12, 0x47, 0x4a, + 0x7f, 0xe9, 0x13, 0xce, 0x47, 0x3b, 0x4e, 0x15, 0x8e, 0x75, 0x7e, 0x58, + 0xf1, 0x9d, 0x9d, 0xef, 0x19, 0xbc, 0x86, 0xe8, 0x5e, 0x2e, 0x8b, 0x5c, + 0x82, 0xdf, 0x4d, 0x7c, 0x3f, 0x58, 0x29, 0x7e, 0x6f, 0x23, 0x7e, 0x31, + 0xd6, 0xdb, 0x18, 0x18, 0x43, 0x5f, 0x1c, 0x67, 0x1c, 0x2d, 0x34, 0xf2, + 0xfd, 0x87, 0xf5, 0xfb, 0x8d, 0xdf, 0x67, 0xc0, 0x9b, 0xd7, 0x88, 0xcf, + 0x32, 0xbe, 0x18, 0xf7, 0x87, 0xd8, 0xee, 0xdb, 0xb0, 0xdb, 0xd0, 0x76, + 0x0f, 0x98, 0x76, 0xeb, 0xfb, 0x95, 0x55, 0x4e, 0xb1, 0xc4, 0xad, 0xa2, + 0xab, 0x8c, 0x2b, 0x54, 0xcf, 0x0a, 0xd8, 0x4e, 0xc9, 0xd7, 0xa6, 0xec, + 0x09, 0xb1, 0x3d, 0x41, 0x71, 0xb0, 0xc5, 0xba, 0x2f, 0xc0, 0xfb, 0xfc, + 0x72, 0x1f, 0xe6, 0x51, 0x17, 0x8c, 0x15, 0xfc, 0xa9, 0xfc, 0xa6, 0xe5, + 0x66, 0xe7, 0xbd, 0xd5, 0x7f, 0x74, 0x23, 0xa5, 0x0f, 0xea, 0x9b, 0x8c, + 0x53, 0x33, 0xfe, 0x3f, 0xd0, 0xf5, 0xed, 0x2e, 0xdd, 0x5f, 0xfd, 0x67, + 0x86, 0x51, 0x9f, 0xce, 0x0c, 0x9f, 0xe5, 0x77, 0x07, 0xfb, 0xa5, 0x9b, + 0xfe, 0xb7, 0x90, 0xb1, 0xab, 0xb3, 0xd7, 0x37, 0xbb, 0x1e, 0x55, 0x16, + 0x3d, 0xf4, 0xb9, 0xff, 0x00, 0x0e, 0x4b, 0x7c, 0x26, 0x30, 0x14, 0x00, + 0x00, 0x00 }; + static u8 bnx2_TPAT_b09FwText[] = { - 0xcd, 0x58, 0x5d, 0x6c, 0x1c, 0x57, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0xde, - 0x38, 0xf1, 0x24, 0x19, 0xca, 0xa6, 0x72, 0xe9, 0x8c, 0x3d, 0x76, 0x8c, - 0x6c, 0x35, 0xd3, 0x76, 0xd5, 0x58, 0x68, 0xa4, 0x4e, 0x67, 0x76, 0x1d, - 0x2b, 0xf4, 0xc1, 0x85, 0x48, 0x3c, 0xf0, 0xe2, 0xae, 0x1d, 0x05, 0x78, - 0x2a, 0x28, 0x0f, 0x11, 0x2f, 0x59, 0x76, 0x37, 0xfd, 0x41, 0xdb, 0x2c, - 0x35, 0xc8, 0x41, 0x02, 0xa4, 0xb0, 0x69, 0xe2, 0x97, 0xad, 0x27, 0x2d, - 0x45, 0xea, 0x4b, 0x95, 0x28, 0x55, 0x2b, 0xc4, 0x13, 0x2f, 0x54, 0x79, - 0xac, 0x52, 0x5a, 0xf1, 0x00, 0x28, 0x42, 0x15, 0xaa, 0x68, 0xf0, 0xe5, - 0x3b, 0x77, 0x66, 0xdc, 0xdd, 0xc4, 0x49, 0xcb, 0x9f, 0x84, 0xa5, 0xf5, - 0x9d, 0xb9, 0xf7, 0x9e, 0x73, 0xcf, 0x3d, 0x3f, 0xdf, 0x39, 0x67, 0xca, - 0x2a, 0x95, 0x28, 0xfb, 0xdb, 0x8d, 0xdf, 0xc9, 0xa7, 0x9f, 0x39, 0x79, - 0xf8, 0xa1, 0x47, 0x1d, 0xa2, 0x87, 0x1f, 0x52, 0x94, 0xa2, 0x46, 0xff, - 0x85, 0x3f, 0x30, 0xb1, 0x72, 0xfe, 0xfc, 0x23, 0x53, 0x0d, 0x7e, 0xe3, - 0x44, 0x1e, 0x99, 0x5a, 0xb0, 0xf4, 0xe5, 0x15, 0x8f, 0x28, 0xec, 0xcf, - 0x3a, 0x31, 0xfd, 0x43, 0x34, 0x6c, 0x9d, 0x78, 0xfe, 0x81, 0xe0, 0xd6, - 0xa1, 0x37, 0x0f, 0xbb, 0x37, 0xcf, 0x6b, 0x64, 0x5a, 0xc1, 0xb2, 0x69, - 0x4d, 0x93, 0x39, 0x1e, 0x5c, 0x75, 0x7e, 0x7e, 0x30, 0x28, 0xd0, 0x9e, - 0x9c, 0x97, 0x4d, 0xcd, 0x2e, 0x35, 0xf4, 0xc0, 0xa4, 0x5a, 0xe7, 0x94, - 0x12, 0x75, 0x3d, 0xab, 0x0a, 0x1e, 0xa1, 0x0d, 0xfe, 0x1e, 0xde, 0x13, - 0x5d, 0xa9, 0x9e, 0x33, 0x49, 0x0d, 0x42, 0x3c, 0xcf, 0x51, 0xab, 0x2b, - 0xc4, 0x0f, 0x7d, 0x85, 0x56, 0x7c, 0x93, 0x96, 0x2d, 0x77, 0x31, 0x54, - 0xb6, 0x44, 0x3c, 0x25, 0xc4, 0xb7, 0x7d, 0x95, 0x54, 0x6f, 0x41, 0x89, - 0x36, 0x16, 0x95, 0x78, 0x63, 0x91, 0xf5, 0x01, 0xf9, 0x16, 0x94, 0x70, - 0x83, 0xc7, 0xc0, 0x8c, 0x3b, 0x7b, 0x68, 0xd9, 0xa6, 0x31, 0xd5, 0x9b, - 0xc3, 0x79, 0x65, 0xf0, 0x71, 0x28, 0xf2, 0x67, 0x2d, 0x95, 0x26, 0xf1, - 0x1b, 0xa1, 0x9a, 0x4f, 0x23, 0xaa, 0xa7, 0x52, 0xdd, 0x56, 0xe8, 0xe5, - 0x8a, 0x81, 0xdf, 0x51, 0xa5, 0xba, 0xf1, 0x9d, 0x8c, 0x0f, 0xef, 0x37, - 0xb1, 0xc6, 0x32, 0x33, 0xfd, 0x20, 0xed, 0x6e, 0x3c, 0x7f, 0x0b, 0xfb, - 0x0c, 0x8a, 0x2a, 0xb7, 0xaf, 0x8d, 0xe0, 0x59, 0xc1, 0xfc, 0x51, 0xc8, - 0xc5, 0x7c, 0x1c, 0xc8, 0x31, 0x4e, 0xed, 0xee, 0x22, 0xee, 0x53, 0xa0, - 0x86, 0x35, 0x35, 0x53, 0x27, 0x1d, 0x34, 0x1a, 0x85, 0xf6, 0x15, 0xa1, - 0x06, 0x42, 0x44, 0x15, 0x6f, 0xa6, 0x27, 0xcf, 0x50, 0x49, 0xf3, 0x0a, - 0x54, 0xf5, 0x77, 0x53, 0xcb, 0xd2, 0xa8, 0x39, 0x67, 0x50, 0xb8, 0xa4, - 0xe3, 0x8e, 0xfb, 0x40, 0xa7, 0x80, 0xfe, 0xa5, 0xcc, 0xe6, 0x45, 0x6a, - 0x5a, 0x05, 0xcc, 0x8f, 0x51, 0xd3, 0xde, 0xab, 0xa8, 0xc1, 0x0b, 0x98, - 0x9f, 0xb2, 0x7a, 0xf4, 0x3c, 0x46, 0x05, 0xef, 0x7b, 0xb1, 0x97, 0xdf, - 0x15, 0xf0, 0x23, 0x2b, 0x4a, 0x66, 0xa8, 0x95, 0xe4, 0xb4, 0x3c, 0x9f, - 0xce, 0x35, 0x92, 0xdb, 0xed, 0x8d, 0x7d, 0xdd, 0x1a, 0x74, 0xcc, 0xb6, - 0xc1, 0x9e, 0xdc, 0x2e, 0xd2, 0x07, 0x1e, 0xe7, 0x79, 0xfe, 0xc3, 0xbc, - 0x43, 0x5a, 0xe0, 0x59, 0x31, 0x7d, 0x85, 0xd2, 0xb5, 0x54, 0xf6, 0xc8, - 0x7f, 0x2c, 0x7b, 0xb7, 0xad, 0xe8, 0xdc, 0xa3, 0xb8, 0x9f, 0x74, 0x19, - 0x3c, 0xdb, 0xb8, 0x7f, 0x01, 0xfe, 0xd1, 0x0c, 0x55, 0x6a, 0x94, 0x4d, - 0x72, 0xe7, 0x57, 0xb1, 0xf2, 0x41, 0x47, 0xa3, 0x98, 0x75, 0xe5, 0xeb, - 0x19, 0x1d, 0xfb, 0xc6, 0xbb, 0x90, 0xb3, 0x61, 0x99, 0x70, 0xbc, 0xe5, - 0x63, 0x42, 0x5c, 0xf4, 0x85, 0x28, 0x04, 0xde, 0xcc, 0x25, 0x9a, 0x2d, - 0x1b, 0x34, 0x6d, 0x61, 0x84, 0x8e, 0xbd, 0x72, 0x9d, 0x8c, 0x5c, 0x9e, - 0xdc, 0x37, 0xf1, 0xd7, 0x57, 0x08, 0x3e, 0x79, 0xa3, 0xf3, 0x7b, 0xd6, - 0xc7, 0xcc, 0x82, 0xa4, 0x11, 0xa2, 0x37, 0x7f, 0x2f, 0x9a, 0x5f, 0x67, - 0x34, 0x42, 0xd4, 0x2a, 0x7c, 0xae, 0x8b, 0x3b, 0xb3, 0x7f, 0x13, 0xd5, - 0xfa, 0xbe, 0x59, 0xef, 0x40, 0x3e, 0x0f, 0x63, 0x9f, 0xa8, 0xde, 0xe5, - 0x7b, 0x98, 0xd4, 0x84, 0xde, 0x5a, 0xd8, 0xaf, 0x56, 0x76, 0xb1, 0x7f, - 0xc0, 0xc6, 0x4b, 0x66, 0xb5, 0xe3, 0x96, 0x5f, 0xa0, 0x25, 0x33, 0xee, - 0xcf, 0x96, 0x57, 0xe9, 0x01, 0x3e, 0xc7, 0x34, 0x82, 0x63, 0x66, 0x4f, - 0xd2, 0x1b, 0x1a, 0x95, 0xf0, 0x0c, 0x1e, 0xcd, 0x0e, 0x29, 0x91, 0xbf, - 0x8b, 0xef, 0x0b, 0xba, 0xc5, 0x8c, 0x6e, 0x31, 0xa3, 0x1b, 0xcb, 0xe8, - 0x9e, 0x1c, 0xa0, 0x7b, 0x92, 0xe9, 0xb0, 0x37, 0xcc, 0xf6, 0x86, 0xd9, - 0x5e, 0x3d, 0xdb, 0x5b, 0xcd, 0xf6, 0x62, 0xec, 0x3b, 0x90, 0xcf, 0x9d, - 0x09, 0x15, 0xc8, 0xe8, 0x89, 0x07, 0x23, 0x9f, 0xc2, 0xd8, 0x73, 0xaf, - 0xc7, 0xda, 0x18, 0x5d, 0xf0, 0x2d, 0x6a, 0x27, 0x0e, 0x64, 0x6f, 0x53, - 0x94, 0xa8, 0xa0, 0x1d, 0xa3, 0x9e, 0x77, 0x53, 0xd4, 0xfc, 0x0a, 0x6c, - 0x37, 0xca, 0x74, 0xe5, 0x1a, 0x14, 0xd1, 0x4c, 0x66, 0xad, 0x55, 0xaa, - 0xc0, 0x5f, 0x54, 0xd8, 0x6f, 0x52, 0x3e, 0x37, 0x93, 0x0a, 0xd6, 0xa9, - 0xa1, 0x56, 0x5c, 0xab, 0x49, 0x6e, 0x39, 0xd2, 0xc8, 0x52, 0x03, 0x1b, - 0x7b, 0x1a, 0x54, 0x4d, 0x4c, 0x7a, 0x4f, 0x3b, 0x25, 0xe3, 0xb4, 0xd9, - 0xbd, 0x2e, 0xde, 0x3c, 0xe8, 0xd0, 0x95, 0x64, 0x9c, 0x7e, 0x95, 0x94, - 0xe9, 0xb5, 0xc4, 0xa6, 0x57, 0x13, 0x52, 0x23, 0x1f, 0x7e, 0x6c, 0x5b, - 0x74, 0x39, 0x19, 0xd4, 0xfb, 0x07, 0xac, 0x77, 0x73, 0x7f, 0x40, 0xe6, - 0xbe, 0x80, 0x1a, 0x5a, 0x90, 0xe2, 0x40, 0x9c, 0xe2, 0x80, 0xf4, 0xa9, - 0x56, 0xb7, 0x79, 0xbf, 0x06, 0x0c, 0x5a, 0xf1, 0xc3, 0xbd, 0x1a, 0xec, - 0x12, 0x23, 0x0a, 0xd4, 0xed, 0x51, 0xda, 0xc8, 0x5d, 0xf1, 0xdc, 0xe7, - 0x63, 0xec, 0xf6, 0xce, 0x1a, 0x98, 0xbd, 0xdd, 0xb6, 0x7f, 0xc6, 0x19, - 0xa3, 0xb0, 0x9b, 0x46, 0x4f, 0xe8, 0x88, 0x1f, 0xef, 0x23, 0x8d, 0x63, - 0xc0, 0xd9, 0xb4, 0xe9, 0x4c, 0x97, 0x68, 0x62, 0xd3, 0xa4, 0x8d, 0x4e, - 0x91, 0x9c, 0xde, 0x28, 0xad, 0x74, 0x4b, 0x34, 0x79, 0x49, 0xc7, 0xde, - 0x5d, 0x34, 0xb9, 0xa6, 0xda, 0x1c, 0xcb, 0x31, 0x74, 0x3c, 0xd1, 0x13, - 0xf0, 0xd1, 0x12, 0x4d, 0xac, 0xbb, 0xd2, 0x7f, 0x56, 0xbc, 0x96, 0xaf, - 0xd1, 0x0f, 0xe8, 0xda, 0x5c, 0x01, 0x77, 0xb2, 0xc9, 0x9f, 0x1e, 0x3c, - 0xcf, 0x80, 0x9b, 0xf1, 0x1c, 0x98, 0xee, 0x71, 0x1d, 0x52, 0x99, 0x9f, - 0x49, 0x13, 0x97, 0x4c, 0x25, 0xee, 0xb2, 0xce, 0xd8, 0x07, 0xcd, 0xcc, - 0x07, 0x75, 0x25, 0x3a, 0x57, 0xc4, 0x59, 0x7f, 0x12, 0x91, 0x07, 0xdf, - 0x03, 0x96, 0xad, 0x54, 0xbe, 0x0f, 0xf9, 0x30, 0xd7, 0xe3, 0xb5, 0x9b, - 0xd9, 0x3c, 0xf3, 0x00, 0x46, 0xf8, 0xfb, 0x29, 0x62, 0x3c, 0x38, 0xc6, - 0x34, 0x45, 0x9a, 0x58, 0x63, 0x8c, 0xc1, 0xd8, 0xe3, 0x77, 0xbe, 0xdb, - 0x08, 0xd5, 0xa1, 0x95, 0xfa, 0x8c, 0x0d, 0xb9, 0x54, 0x89, 0x19, 0x75, - 0x60, 0x88, 0xea, 0x95, 0x30, 0xf2, 0x79, 0x3f, 0xd3, 0xd2, 0xf8, 0xb7, - 0xa5, 0xbd, 0x63, 0xf8, 0xaf, 0x0e, 0x79, 0x56, 0x69, 0xaa, 0x7c, 0x5c, - 0xae, 0x61, 0xae, 0xcf, 0x6b, 0xd6, 0x6d, 0x6b, 0x78, 0xef, 0xe7, 0x32, - 0x20, 0xc6, 0xbd, 0x16, 0x4e, 0x31, 0x32, 0xbd, 0xf0, 0xfe, 0x46, 0x19, - 0xb6, 0x01, 0xa6, 0x11, 0x74, 0x49, 0xd4, 0xeb, 0xe8, 0xc0, 0x1c, 0xf5, - 0x8b, 0x2a, 0xd3, 0xd9, 0xcc, 0x07, 0xf7, 0x5f, 0xd7, 0x95, 0xf8, 0x9c, - 0xe7, 0xfc, 0x81, 0x98, 0x7e, 0x12, 0x3a, 0x98, 0x9a, 0x6f, 0xf1, 0xfe, - 0xbe, 0x41, 0xde, 0x5a, 0xc3, 0xd2, 0x61, 0x53, 0x15, 0x06, 0x8d, 0x7f, - 0x34, 0x06, 0x5b, 0xbb, 0x4e, 0x8b, 0x7e, 0x07, 0x79, 0x0a, 0xe4, 0xf5, - 0x74, 0x7a, 0xb9, 0xc3, 0xba, 0x30, 0x69, 0x72, 0x5d, 0x88, 0xe7, 0x7c, - 0xb6, 0xc9, 0xbb, 0xd0, 0x0b, 0xe1, 0x86, 0x53, 0xf3, 0x37, 0x60, 0x9f, - 0x8d, 0x3e, 0xdb, 0xc6, 0x90, 0x3a, 0xf1, 0xd6, 0xe6, 0x60, 0xd7, 0x99, - 0x4c, 0x46, 0xb6, 0x97, 0x4e, 0xed, 0x8a, 0x4a, 0x17, 0x2b, 0x9f, 0x08, - 0xd5, 0x63, 0x8c, 0x2d, 0x40, 0xb7, 0xd8, 0xd7, 0xc3, 0xbe, 0xa4, 0x00, - 0x1d, 0xfe, 0x4d, 0x18, 0xc0, 0xdf, 0x8b, 0x15, 0xcc, 0xaf, 0x9d, 0x86, - 0xac, 0x1a, 0x68, 0x53, 0x1f, 0x63, 0x79, 0x16, 0x3a, 0xf9, 0xfd, 0xbc, - 0xf9, 0xb7, 0x25, 0xbf, 0x51, 0x9a, 0xde, 0x1c, 0xa5, 0x13, 0xfd, 0x51, - 0x9a, 0x38, 0xcb, 0x34, 0x42, 0xb4, 0x2b, 0x8c, 0x91, 0xf0, 0x51, 0x4f, - 0xea, 0xa1, 0xac, 0xa9, 0x7c, 0x4f, 0xac, 0x6f, 0x12, 0xad, 0xf6, 0xf9, - 0x0c, 0x7d, 0x80, 0xa7, 0x4a, 0x47, 0x7e, 0x42, 0x74, 0xa4, 0xcf, 0xb4, - 0xdb, 0xba, 0x03, 0x5f, 0x0b, 0x3c, 0x2d, 0xe2, 0x5c, 0xa4, 0x79, 0xc8, - 0x79, 0x1b, 0x11, 0x72, 0x58, 0x15, 0xbf, 0x05, 0xe4, 0x35, 0xbe, 0xff, - 0x1c, 0xe2, 0x8f, 0xb1, 0x7c, 0x0b, 0x77, 0x2f, 0x50, 0xdb, 0x5f, 0xc4, - 0x1e, 0xb6, 0xf1, 0x51, 0xac, 0xef, 0x46, 0x2e, 0xc8, 0x72, 0x85, 0xc5, - 0xb9, 0x62, 0x2f, 0xe2, 0x60, 0x04, 0xf8, 0x7f, 0xbf, 0x3e, 0x9c, 0x2b, - 0xb0, 0xcf, 0x3e, 0x80, 0xdc, 0x80, 0x44, 0x5d, 0x62, 0x5e, 0xfb, 0x31, - 0x8e, 0xe0, 0xfd, 0x00, 0xf6, 0x0e, 0xe6, 0x89, 0x9c, 0xee, 0x6e, 0x39, - 0x02, 0x31, 0xb1, 0x86, 0x58, 0x59, 0x9f, 0x61, 0xcc, 0x80, 0x3d, 0xd8, - 0xa6, 0x45, 0x60, 0xb8, 0x09, 0x1e, 0x6c, 0xdb, 0x22, 0x6c, 0xc8, 0x79, - 0xce, 0xa2, 0xc9, 0x4d, 0x8e, 0xeb, 0x34, 0x8f, 0xc4, 0xdb, 0x79, 0x84, - 0x64, 0x4c, 0x34, 0x13, 0xf6, 0x89, 0xd0, 0x8c, 0xce, 0x6e, 0x09, 0xc4, - 0x70, 0x39, 0x66, 0x5c, 0xdb, 0x9c, 0x05, 0xbd, 0x86, 0xf8, 0xa8, 0x9a, - 0xf5, 0xb3, 0x29, 0xa6, 0xd5, 0x37, 0x1d, 0xe9, 0x93, 0xcd, 0xc4, 0xc2, - 0x3b, 0x63, 0x5a, 0x8e, 0x61, 0x4c, 0x4f, 0x61, 0x04, 0x7c, 0x8b, 0x34, - 0x21, 0x56, 0xfc, 0x31, 0xaa, 0xc3, 0x3f, 0x43, 0xe0, 0x5a, 0x1d, 0xb8, - 0x16, 0x0f, 0xe0, 0x5a, 0xfc, 0x99, 0xb8, 0x06, 0xcc, 0xea, 0x02, 0xb3, - 0x50, 0x23, 0xbc, 0x06, 0x8c, 0x7f, 0x15, 0xe7, 0x5d, 0xee, 0xee, 0x84, - 0x75, 0x8c, 0x73, 0x8c, 0x77, 0x33, 0xf4, 0xe6, 0xc1, 0x7f, 0x15, 0xef, - 0xda, 0xc0, 0x06, 0x93, 0xbe, 0x7b, 0xf0, 0xde, 0x98, 0x77, 0x06, 0x98, - 0x67, 0x7c, 0x36, 0xe6, 0x35, 0x18, 0xf3, 0x74, 0xf8, 0x60, 0x03, 0x78, - 0xa0, 0xae, 0x0d, 0x9e, 0xd3, 0xc1, 0x39, 0x3c, 0xa7, 0x67, 0x79, 0x55, - 0xa5, 0x1e, 0xfc, 0x5f, 0xf3, 0xf8, 0x9c, 0x39, 0xd6, 0xbb, 0xd4, 0xff, - 0x13, 0xba, 0x4d, 0xc6, 0x34, 0xfc, 0x62, 0x6d, 0x94, 0xb4, 0xb3, 0x9f, - 0xfa, 0x3d, 0x6a, 0x03, 0xc4, 0x3b, 0xfe, 0x6d, 0xe6, 0x3c, 0x4a, 0xc0, - 0x1c, 0x9d, 0x0a, 0x6b, 0x06, 0xde, 0x95, 0xa1, 0x7d, 0x47, 0x90, 0x77, - 0xb4, 0xc0, 0x9d, 0x7f, 0x9f, 0x9f, 0xfb, 0xbc, 0xa7, 0x44, 0xea, 0xba, - 0xeb, 0x38, 0xaa, 0xeb, 0x5f, 0x03, 0x46, 0xbc, 0xe3, 0x31, 0x0e, 0x36, - 0xe1, 0x0d, 0x05, 0xd2, 0xd7, 0xc4, 0x69, 0x23, 0xe0, 0xb3, 0x1b, 0x0e, - 0xe2, 0xdd, 0x79, 0x09, 0x7e, 0xc4, 0x39, 0xf4, 0x22, 0xe2, 0xa7, 0x96, - 0xc5, 0x6a, 0xab, 0x9f, 0x9f, 0xb9, 0x0f, 0x72, 0x1b, 0xa0, 0x19, 0xdc, - 0xcb, 0x71, 0x20, 0xc4, 0x09, 0xdc, 0x49, 0xc3, 0x39, 0xc6, 0xba, 0x49, - 0x85, 0x75, 0xd6, 0x8b, 0x0b, 0xfa, 0x49, 0x6b, 0x81, 0xae, 0x0f, 0xe1, - 0xc2, 0x73, 0xfd, 0xeb, 0x3a, 0x63, 0xa9, 0x86, 0x18, 0x2d, 0xe2, 0x5c, - 0x63, 0x9b, 0x17, 0x65, 0xbc, 0x98, 0xde, 0x2b, 0x9f, 0xd8, 0xa6, 0x67, - 0x7c, 0x9b, 0x2a, 0x33, 0x8e, 0xb1, 0x1c, 0x9a, 0xc4, 0xd4, 0x52, 0x86, - 0xa9, 0x93, 0xb0, 0x67, 0x49, 0xc6, 0xa7, 0xea, 0x3d, 0x98, 0xe1, 0xea, - 0x5e, 0x8c, 0x3c, 0x27, 0xb2, 0x78, 0xd1, 0x21, 0x2f, 0xf3, 0x2d, 0x91, - 0xb6, 0xce, 0x35, 0x04, 0xdf, 0xe9, 0xaf, 0xf0, 0x6d, 0xc6, 0x0a, 0xf6, - 0x4f, 0x89, 0xa9, 0x98, 0x9f, 0x82, 0xcc, 0x8c, 0x0f, 0x4c, 0xc7, 0xf4, - 0x3b, 0xd1, 0xfd, 0x05, 0x74, 0xd6, 0x0e, 0x74, 0x98, 0xdb, 0x64, 0x1a, - 0xc6, 0x88, 0x7d, 0xd8, 0x1f, 0x31, 0x3e, 0x40, 0x67, 0x4c, 0x3b, 0x9e, - 0xc5, 0x63, 0x15, 0x6b, 0x5c, 0x03, 0xcb, 0xf8, 0x22, 0x23, 0xe0, 0x7b, - 0x70, 0x7d, 0xcc, 0xf9, 0x91, 0x6b, 0x52, 0xae, 0x3d, 0xf3, 0x5a, 0xd5, - 0x9b, 0xa9, 0xdd, 0xad, 0xee, 0xb4, 0x06, 0xeb, 0xce, 0x43, 0xc6, 0xce, - 0x75, 0xe7, 0x41, 0x23, 0xad, 0x3b, 0xa7, 0x8d, 0xbb, 0xd7, 0x9d, 0x39, - 0xed, 0xbd, 0xeb, 0xce, 0x66, 0x97, 0xcf, 0xdc, 0x19, 0x2f, 0x56, 0xe0, - 0xaf, 0xad, 0x24, 0xbf, 0x27, 0xf7, 0x06, 0xa1, 0x59, 0x3b, 0x9b, 0xda, - 0xbe, 0x29, 0x7d, 0x11, 0x38, 0xb2, 0x39, 0x0b, 0x3b, 0xa2, 0xa6, 0x1e, - 0xc2, 0x8e, 0x9c, 0x86, 0x75, 0x5a, 0x02, 0x46, 0xb3, 0x3e, 0x8b, 0x19, - 0x4e, 0x60, 0xf4, 0x3e, 0x06, 0x4e, 0xe4, 0xf8, 0xc2, 0xfc, 0xfe, 0x9f, - 0xf0, 0x85, 0xcc, 0x11, 0xe0, 0x84, 0x19, 0x30, 0x5e, 0x4a, 0x59, 0x50, - 0x93, 0x0b, 0xb1, 0xe0, 0x73, 0x0c, 0x0c, 0xf6, 0x4c, 0xec, 0x0f, 0x45, - 0x7a, 0xcb, 0x67, 0x9f, 0x40, 0xcf, 0xe4, 0x71, 0x8e, 0x64, 0x3c, 0xde, - 0x12, 0x6f, 0x79, 0x11, 0xe6, 0xaa, 0xb0, 0x3d, 0xfb, 0xc3, 0xa2, 0x72, - 0x64, 0xc3, 0x04, 0x1d, 0xfb, 0xc4, 0xf8, 0x1d, 0xbd, 0x50, 0xda, 0xb3, - 0x70, 0x7d, 0xfc, 0xef, 0xfa, 0xc8, 0x1b, 0x77, 0xf1, 0x91, 0xcb, 0x99, - 0x8f, 0x24, 0xf7, 0xf0, 0x91, 0x37, 0x3e, 0xa7, 0x8f, 0xb8, 0xe5, 0x0f, - 0x51, 0x3f, 0xbd, 0x0d, 0x39, 0x42, 0x4b, 0x88, 0x0f, 0xfd, 0x9d, 0xfa, - 0x94, 0xd0, 0xd4, 0x5f, 0x64, 0x9d, 0xa5, 0x79, 0xa5, 0x85, 0x77, 0xed, - 0x15, 0xae, 0x97, 0x39, 0xe7, 0xa4, 0xb9, 0x65, 0xe2, 0xc5, 0xd4, 0x3f, - 0x26, 0x5e, 0x11, 0xe2, 0xc2, 0x0e, 0xfe, 0xc0, 0x35, 0xf4, 0x55, 0xf8, - 0x55, 0x8b, 0xfe, 0x17, 0x35, 0x34, 0x63, 0x78, 0xc5, 0x3c, 0xde, 0xc9, - 0xed, 0x9f, 0xdb, 0xbe, 0x40, 0xe7, 0xad, 0x3d, 0xd0, 0xdb, 0xa3, 0xd4, - 0xfa, 0xb1, 0xce, 0x7d, 0x05, 0xfc, 0xe2, 0x71, 0x9d, 0x63, 0x17, 0x7d, - 0x24, 0x9e, 0x07, 0xeb, 0x6c, 0xf8, 0xa5, 0x5f, 0xc8, 0xe3, 0x65, 0x00, - 0xfb, 0x4f, 0xa1, 0x54, 0xb9, 0x23, 0xaf, 0x0c, 0xf5, 0xd4, 0x1a, 0x7a, - 0xea, 0x58, 0xf2, 0xe0, 0xbe, 0x2b, 0xd5, 0x63, 0x5b, 0xf6, 0xd1, 0x5b, - 0xa2, 0x25, 0x7b, 0xe9, 0x03, 0x05, 0x2a, 0x2d, 0x66, 0x3e, 0xe3, 0x20, - 0x1f, 0xb9, 0x7e, 0x03, 0xfc, 0xb9, 0xd6, 0x80, 0x1c, 0xb4, 0x8a, 0x58, - 0xbc, 0x80, 0x3c, 0xbc, 0x02, 0xbd, 0xd4, 0x65, 0x6c, 0x8c, 0xd1, 0x35, - 0xe4, 0xfe, 0x36, 0xf2, 0xf3, 0x19, 0xe8, 0xa6, 0x05, 0xdd, 0xc4, 0x49, - 0x1a, 0x27, 0xd7, 0xa0, 0x9b, 0x85, 0x01, 0xdd, 0x2c, 0xfc, 0x47, 0xfd, - 0xc5, 0x1f, 0x91, 0x6b, 0xcd, 0x65, 0x1d, 0xf3, 0x57, 0x12, 0x99, 0x5b, - 0x97, 0x5a, 0x1d, 0x6a, 0xdc, 0x1f, 0x9c, 0xe6, 0xda, 0x8e, 0x6b, 0xb3, - 0xf9, 0x95, 0x0a, 0xe6, 0xfa, 0x26, 0x45, 0xd0, 0xcf, 0x37, 0x0f, 0xd3, - 0xb2, 0x16, 0xb0, 0x4f, 0xe3, 0x3d, 0xa1, 0x46, 0x74, 0x18, 0xf5, 0x56, - 0x32, 0xbe, 0x8c, 0x7e, 0x1c, 0xbe, 0xd5, 0xa0, 0x10, 0x72, 0x86, 0xe0, - 0xbd, 0xd0, 0x31, 0xcd, 0xd5, 0x0e, 0xf7, 0x51, 0x0d, 0xe2, 0x5e, 0xbd, - 0xd7, 0xbf, 0x09, 0x7e, 0x23, 0xdf, 0x40, 0x7f, 0xeb, 0x34, 0x81, 0xd3, - 0xcf, 0xc2, 0x6d, 0x5b, 0x36, 0x7f, 0xcb, 0x60, 0x1c, 0x1d, 0x07, 0x8f, - 0xa7, 0x0b, 0xa9, 0xaf, 0x8e, 0x83, 0x0f, 0xc7, 0x11, 0xe1, 0x3c, 0xd6, - 0x65, 0xee, 0x7f, 0xe5, 0x81, 0xfa, 0xbe, 0x40, 0x39, 0x86, 0x35, 0xa1, - 0x37, 0xd6, 0x75, 0xe4, 0x9d, 0x2c, 0xe4, 0xdf, 0x6d, 0x5a, 0xc0, 0x81, - 0xfa, 0x1c, 0x63, 0x96, 0x02, 0xdf, 0xa3, 0xb4, 0xaf, 0x44, 0x1f, 0x52, - 0x9f, 0x43, 0xde, 0xb6, 0x8b, 0x72, 0x6c, 0x24, 0xa7, 0xb3, 0xfd, 0xaa, - 0xdc, 0xc7, 0xf9, 0xa2, 0x99, 0xc8, 0x7e, 0x42, 0xa9, 0x76, 0xc9, 0xa9, - 0xfb, 0xe8, 0x93, 0x50, 0x7b, 0xb4, 0x13, 0xce, 0xf5, 0x73, 0xa6, 0x2a, - 0xb1, 0xef, 0x06, 0x68, 0xf0, 0xbc, 0x49, 0x6a, 0xdd, 0xe7, 0xef, 0x0c, - 0xfc, 0x0d, 0x04, 0xf1, 0x63, 0xd3, 0x6e, 0xd0, 0x43, 0xae, 0x71, 0x96, - 0x2b, 0xac, 0xcb, 0x3a, 0x85, 0x79, 0x1f, 0x52, 0xd3, 0x6f, 0x33, 0xef, - 0x66, 0x67, 0x99, 0x88, 0x1f, 0xc6, 0x5d, 0x9f, 0x73, 0xde, 0x97, 0x34, - 0xba, 0x49, 0x12, 0x37, 0xad, 0x87, 0x91, 0x0b, 0x0f, 0x83, 0x26, 0x94, - 0x98, 0x93, 0xf6, 0x15, 0x39, 0x8d, 0xa7, 0x0d, 0xf3, 0x58, 0xd6, 0x87, - 0xdf, 0x43, 0xc4, 0x59, 0x25, 0x3b, 0x6f, 0xd0, 0x67, 0xdf, 0x87, 0xcf, - 0xde, 0xc8, 0xf6, 0x00, 0x87, 0xed, 0x02, 0xf6, 0xb1, 0x8c, 0x8c, 0x2f, - 0x4c, 0xb3, 0x65, 0x0c, 0xf3, 0x99, 0xdc, 0x81, 0xc7, 0x47, 0x03, 0x3c, - 0x6c, 0xbe, 0x9b, 0x55, 0x4f, 0x7b, 0x6c, 0xf9, 0x57, 0x87, 0x9e, 0xd1, - 0x93, 0xdc, 0xa7, 0xe2, 0x1e, 0x5c, 0x9b, 0xc5, 0x72, 0xfe, 0x97, 0xc5, - 0x61, 0xbe, 0xa7, 0xb2, 0x73, 0xfc, 0x34, 0x36, 0x3c, 0x8c, 0xc9, 0x8d, - 0x01, 0xd9, 0x8d, 0x1d, 0xce, 0xdd, 0xa5, 0xa3, 0x35, 0x50, 0xd8, 0xdf, - 0xb4, 0x80, 0xf3, 0x33, 0x9e, 0xb7, 0xfd, 0x83, 0x7d, 0xf5, 0xb3, 0x7d, - 0xd4, 0xf8, 0x9c, 0x3e, 0xfa, 0x72, 0x87, 0x71, 0x23, 0xf5, 0xd1, 0xfa, - 0x1d, 0x3e, 0x8a, 0xfa, 0xc8, 0xce, 0xfd, 0x93, 0xe3, 0x25, 0xf7, 0xcf, - 0xfc, 0x99, 0x63, 0x1c, 0xb8, 0x9c, 0xe1, 0x5c, 0x13, 0x38, 0x57, 0x95, - 0x79, 0xcf, 0x2d, 0x57, 0x29, 0x8d, 0xe5, 0x55, 0xc4, 0x72, 0x55, 0xe3, - 0x3c, 0xc8, 0x31, 0xcc, 0x74, 0x1c, 0xc7, 0x4c, 0x37, 0x96, 0xd1, 0x61, - 0x44, 0x3c, 0x57, 0xb3, 0x78, 0x6e, 0x75, 0x5d, 0xa7, 0x9a, 0xc5, 0x73, - 0x0b, 0x31, 0xdc, 0xce, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0x7f, 0xdf, 0xd3, - 0x2a, 0x9c, 0x1b, 0x5d, 0x27, 0x06, 0xc6, 0xb5, 0x25, 0xcf, 0x06, 0xee, - 0x09, 0x19, 0xbb, 0x79, 0x5c, 0xdc, 0xf1, 0x1d, 0x0c, 0xf7, 0xf9, 0x34, - 0xd7, 0xd4, 0x90, 0x6b, 0x2e, 0x20, 0xd7, 0xf4, 0x06, 0xbe, 0x83, 0x9d, - 0x97, 0xb9, 0xe6, 0xeb, 0xc5, 0x3c, 0xd7, 0xf4, 0xb2, 0x5c, 0xd3, 0x93, - 0xb9, 0xe6, 0xab, 0x45, 0xce, 0x35, 0x4d, 0x3a, 0x5a, 0x1c, 0xcc, 0x35, - 0xcd, 0xa1, 0x5c, 0x93, 0xd3, 0xf2, 0xfc, 0x4e, 0xb9, 0x26, 0xd7, 0xd9, - 0xbd, 0x6a, 0x92, 0x7c, 0x0f, 0xcb, 0xca, 0xb8, 0xc4, 0x78, 0x9c, 0xd6, - 0xfc, 0x57, 0x92, 0x3c, 0x96, 0x4e, 0xe3, 0x1c, 0xbc, 0x77, 0x77, 0x8a, - 0x25, 0x33, 0x8b, 0xa5, 0xdd, 0x29, 0x4d, 0x77, 0x30, 0x9e, 0x4e, 0x17, - 0x87, 0xe3, 0x29, 0xe7, 0x93, 0xc7, 0x53, 0xca, 0xf3, 0x3d, 0xad, 0xcc, - 0x35, 0x02, 0xfa, 0x6d, 0xd7, 0x5f, 0xc0, 0xec, 0xa5, 0xfe, 0x2c, 0x6a, - 0x6e, 0x9d, 0xae, 0xe6, 0x78, 0x23, 0xbf, 0x09, 0x61, 0xec, 0xe7, 0xb2, - 0x16, 0xb7, 0xd7, 0x7a, 0xa8, 0xbb, 0xdf, 0x01, 0x8e, 0x5c, 0x94, 0xeb, - 0x9f, 0x88, 0xab, 0x68, 0x09, 0xdb, 0x5e, 0xbe, 0xef, 0x17, 0x38, 0xcf, - 0xb5, 0xce, 0xe3, 0xe9, 0xd9, 0x7e, 0xae, 0x13, 0x5e, 0xe7, 0xb9, 0xbf, - 0x23, 0x9f, 0xa0, 0x66, 0xdf, 0xde, 0xcb, 0xfd, 0x8f, 0x87, 0x3b, 0x3b, - 0xf4, 0xfa, 0x50, 0x0f, 0x94, 0xf6, 0x3e, 0x75, 0xf9, 0x8d, 0x97, 0x6b, - 0x97, 0xe8, 0x0b, 0x2a, 0x9d, 0xa2, 0xaf, 0xf9, 0x3c, 0xa7, 0x52, 0xed, - 0x31, 0x21, 0x9e, 0x41, 0x1d, 0xf3, 0xd4, 0x50, 0x1d, 0x53, 0xa4, 0x89, - 0x47, 0x06, 0x7b, 0xc8, 0x2d, 0x31, 0x31, 0xed, 0x9e, 0x0f, 0x29, 0x54, - 0x6a, 0x1b, 0x5c, 0xe7, 0x6e, 0xd7, 0xb5, 0x44, 0xfb, 0x6e, 0x09, 0x75, - 0x9a, 0xf3, 0xe2, 0x6f, 0x33, 0x5d, 0x61, 0xed, 0xdc, 0x2d, 0x60, 0x6b, - 0x55, 0x7e, 0x0b, 0x0e, 0x37, 0xf8, 0x1c, 0x7e, 0xc7, 0x98, 0x70, 0xcd, - 0x73, 0xb7, 0xef, 0xb3, 0x3a, 0xec, 0xe2, 0x3a, 0xc7, 0x35, 0x92, 0xdf, - 0x37, 0x56, 0x7c, 0xf7, 0xa7, 0x2d, 0x4a, 0x71, 0xa2, 0xea, 0x2f, 0x41, - 0x16, 0xd4, 0x9d, 0xd6, 0x32, 0x6c, 0x33, 0x0d, 0x5c, 0x72, 0x9d, 0x47, - 0x54, 0x5b, 0xe2, 0xf8, 0x2a, 0x78, 0x6b, 0x8f, 0x70, 0x4d, 0xf9, 0xb1, - 0x58, 0xed, 0xcb, 0x7c, 0xec, 0xb3, 0x8f, 0xc4, 0xc9, 0x5e, 0x95, 0xc7, - 0x30, 0xe1, 0xe7, 0x02, 0x71, 0x2d, 0xb9, 0xb3, 0xff, 0xd8, 0x56, 0xf5, - 0x9c, 0x63, 0xd5, 0xba, 0x8e, 0xb5, 0xd0, 0x55, 0xe1, 0xdd, 0xfb, 0x4c, - 0xda, 0x03, 0x9b, 0x20, 0x1f, 0xd3, 0x7d, 0x90, 0xe5, 0x92, 0x63, 0xc5, - 0xa8, 0x0f, 0xbf, 0xa7, 0xb9, 0xd6, 0x53, 0xa4, 0x98, 0x54, 0xba, 0x25, - 0xd2, 0x6f, 0x33, 0x8e, 0x55, 0xdd, 0x3e, 0xfb, 0x16, 0xce, 0x66, 0x99, - 0x38, 0x46, 0x39, 0x5f, 0x2e, 0x2a, 0x4b, 0xd0, 0xd1, 0xb1, 0x8d, 0x5d, - 0xc0, 0x35, 0xce, 0x97, 0x07, 0xb2, 0x6f, 0x50, 0xb0, 0x0f, 0xee, 0xff, - 0xfa, 0x1d, 0xf5, 0x67, 0x5e, 0x67, 0x32, 0xbd, 0x10, 0xcd, 0x79, 0x3e, - 0x9f, 0x20, 0xcb, 0xd4, 0xcc, 0x25, 0xd9, 0x13, 0xcd, 0xa2, 0xee, 0xe3, - 0x51, 0xa0, 0x26, 0xe2, 0xef, 0x61, 0xae, 0x55, 0xc7, 0x73, 0x35, 0x7b, - 0x6e, 0x72, 0xbf, 0x34, 0xcf, 0x3c, 0xb8, 0x6f, 0xe2, 0xf8, 0xf9, 0x27, - 0x6e, 0xb7, 0x92, 0x82, 0x90, 0x18, 0x00, 0x00, 0x00 }; + 0xbd, 0x58, 0x5d, 0x6c, 0x1c, 0xd5, 0x15, 0x3e, 0x73, 0x67, 0xd6, 0x3b, + 0xb6, 0x9c, 0x78, 0x4c, 0xb6, 0xb0, 0x14, 0x47, 0xcc, 0xc4, 0xe3, 0x9f, + 0xca, 0x16, 0x0c, 0xe9, 0x96, 0x1a, 0x69, 0x55, 0x0d, 0xbb, 0x1b, 0x63, + 0xa5, 0x3c, 0x18, 0x29, 0x52, 0x91, 0xa0, 0xc8, 0x5d, 0x13, 0xe0, 0x81, + 0x87, 0xa0, 0xf6, 0xa1, 0x15, 0x0f, 0x59, 0xd6, 0x9b, 0x90, 0x87, 0x6d, + 0x06, 0x96, 0x2a, 0x79, 0x68, 0x55, 0x45, 0x0e, 0x8e, 0xa3, 0x76, 0xe5, + 0x25, 0x48, 0x7d, 0x8c, 0x40, 0xa1, 0x4a, 0x5f, 0x79, 0xa0, 0x15, 0x7d, + 0x22, 0x52, 0x5f, 0x78, 0xe8, 0x4f, 0x84, 0xd4, 0x16, 0xb5, 0x34, 0xb7, + 0xdf, 0x77, 0x67, 0xc6, 0x6c, 0x4d, 0x22, 0xc4, 0x4b, 0x57, 0x5a, 0xdd, + 0x99, 0x7b, 0xcf, 0x39, 0xf7, 0xdc, 0xf3, 0xf3, 0x9d, 0x73, 0xe7, 0x90, + 0x92, 0x31, 0xc9, 0x7e, 0xfb, 0xf0, 0xaf, 0xfc, 0xe0, 0xc4, 0x8f, 0xbe, + 0xf5, 0x40, 0xf4, 0x00, 0xdf, 0xad, 0x82, 0x38, 0xf2, 0x7f, 0xfc, 0xd9, + 0x22, 0x5e, 0xae, 0x07, 0xff, 0xe2, 0xaa, 0xea, 0xda, 0xc1, 0x5a, 0x28, + 0xae, 0x5d, 0x5d, 0x79, 0x60, 0x3d, 0x14, 0x89, 0xfb, 0x0b, 0x7e, 0x5d, + 0xfe, 0xa3, 0x5b, 0x25, 0x47, 0x38, 0x7f, 0xb0, 0xfa, 0xd9, 0x83, 0x57, + 0xbf, 0x1d, 0xdc, 0xbc, 0x60, 0x8b, 0xeb, 0x55, 0xcf, 0xb8, 0xde, 0xac, + 0xb8, 0x53, 0xe0, 0xf9, 0xc5, 0x5c, 0x6f, 0x44, 0xf6, 0xe7, 0xb2, 0x5a, + 0x5a, 0x85, 0x37, 0xf4, 0xd5, 0xb9, 0xd0, 0x6b, 0x4b, 0x49, 0xae, 0x0c, + 0x7c, 0xa9, 0x0d, 0xa6, 0xe4, 0x9d, 0x41, 0x59, 0xde, 0x1e, 0x78, 0xf2, + 0xd6, 0xc0, 0x91, 0xe3, 0x6f, 0x9c, 0x94, 0x4e, 0x14, 0x94, 0x1b, 0xb6, + 0x2b, 0xaa, 0x1a, 0x94, 0x9b, 0xe2, 0xcb, 0x56, 0x14, 0x9c, 0x59, 0xb3, + 0x27, 0x2d, 0xb7, 0xea, 0xca, 0xcb, 0x73, 0x4a, 0x2e, 0x94, 0x9e, 0x96, + 0xe7, 0xc2, 0x27, 0xf1, 0x77, 0xe4, 0x50, 0xcf, 0xb1, 0xea, 0xe7, 0x1d, + 0x09, 0x7b, 0x13, 0xf2, 0x58, 0xa4, 0xf5, 0x7a, 0x14, 0x83, 0x7f, 0x7a, + 0xfe, 0x79, 0x19, 0x95, 0x96, 0x17, 0xac, 0x88, 0x14, 0x48, 0x23, 0xb5, + 0xa8, 0x20, 0xb1, 0x97, 0x9e, 0xed, 0x82, 0x19, 0x3f, 0xd3, 0x5b, 0xe0, + 0x1f, 0x0d, 0xf3, 0xf5, 0xbb, 0xb2, 0x75, 0x2f, 0x5b, 0x57, 0x72, 0xe8, + 0x5c, 0xe0, 0x6f, 0xcb, 0x4c, 0xec, 0x58, 0xb7, 0x74, 0x2d, 0xbc, 0xdb, + 0xab, 0x6d, 0x3b, 0x32, 0xdd, 0xe3, 0x19, 0x42, 0xaf, 0x2e, 0x1a, 0x3c, + 0x36, 0x79, 0x1c, 0x55, 0xfd, 0x21, 0x7c, 0x37, 0x13, 0x2b, 0x4b, 0xe4, + 0x5a, 0xb7, 0xec, 0xd5, 0x06, 0x3f, 0xb6, 0x6a, 0xc9, 0x2d, 0x1d, 0x3b, + 0x63, 0xa2, 0xc2, 0xd8, 0xaa, 0x6d, 0x53, 0xd6, 0xa8, 0x38, 0x61, 0x11, + 0x3c, 0xd3, 0x9e, 0x12, 0x8e, 0xb5, 0x6c, 0x9e, 0xb2, 0x1b, 0x78, 0x5e, + 0xb6, 0xe2, 0x6d, 0xc7, 0xaa, 0x9d, 0x5f, 0xc1, 0xb3, 0x0b, 0x7e, 0xd8, + 0x26, 0xb2, 0x24, 0x5e, 0xb5, 0xc0, 0xc7, 0x73, 0x7a, 0x78, 0x57, 0x12, + 0x97, 0x3c, 0xd9, 0xa8, 0x04, 0xe5, 0x96, 0x1c, 0xb5, 0xea, 0xdb, 0x5f, + 0x70, 0x9c, 0xb7, 0x32, 0xf8, 0xe2, 0x1c, 0x75, 0x79, 0xd4, 0xd1, 0x5a, + 0x3d, 0x54, 0xcc, 0xce, 0x48, 0x79, 0x71, 0xaa, 0x7f, 0x89, 0xef, 0xd0, + 0x39, 0x81, 0xee, 0xfd, 0x11, 0xe8, 0xa3, 0x35, 0xf7, 0xa9, 0x85, 0xed, + 0xd7, 0x14, 0x2c, 0x78, 0x97, 0x04, 0xad, 0xa7, 0x68, 0x8d, 0xb3, 0x07, + 0xc4, 0x9f, 0x54, 0xa1, 0x92, 0xc0, 0xdb, 0x96, 0x29, 0xd9, 0x48, 0xa6, + 0xbc, 0x23, 0x49, 0xdb, 0x23, 0x0d, 0xe7, 0xea, 0xa0, 0x39, 0xd2, 0xd7, + 0xfa, 0x52, 0x74, 0x5f, 0x51, 0xf6, 0xab, 0xc5, 0x82, 0x04, 0x7e, 0x6c, + 0xf8, 0x64, 0xca, 0x11, 0xca, 0xc4, 0xf3, 0x0e, 0xdf, 0x67, 0x0c, 0xad, + 0xda, 0xd9, 0x6b, 0xcb, 0xb9, 0x4c, 0x37, 0xfa, 0x43, 0xd1, 0x4e, 0xd9, + 0xfb, 0xb8, 0x57, 0x3b, 0x9f, 0xdb, 0xdf, 0x9c, 0x07, 0xf6, 0x8e, 0xa4, + 0x56, 0xc1, 0xb9, 0xee, 0x78, 0xd6, 0x9c, 0x8f, 0x3a, 0x72, 0xef, 0x88, + 0xe7, 0xd9, 0xd5, 0xf5, 0xa9, 0x2f, 0xe8, 0xda, 0xf2, 0x71, 0x4e, 0xff, + 0xe7, 0x98, 0xdf, 0xe8, 0x4a, 0x49, 0x09, 0xe3, 0x08, 0xcf, 0x7d, 0xbe, + 0xcf, 0x20, 0x06, 0xf9, 0xac, 0x24, 0x3c, 0xe7, 0x4a, 0x27, 0x7c, 0xc6, + 0x96, 0xfd, 0x5a, 0x77, 0x22, 0xc7, 0x6a, 0x9c, 0x7f, 0x31, 0x7b, 0x46, + 0x0c, 0x27, 0x88, 0xe1, 0x04, 0x31, 0x9d, 0x20, 0x8e, 0x13, 0xf1, 0x54, + 0xd5, 0x97, 0xab, 0x73, 0xae, 0xdc, 0xb0, 0x11, 0x0b, 0x83, 0x05, 0xef, + 0x4d, 0xc4, 0x63, 0xec, 0x59, 0x62, 0x87, 0xf1, 0x7c, 0x41, 0xf8, 0x8e, + 0x38, 0x74, 0xe2, 0xb2, 0x8d, 0x38, 0x8c, 0x8f, 0x71, 0xae, 0x28, 0x6b, + 0xe6, 0xbc, 0x0b, 0xde, 0x29, 0xa1, 0x9f, 0x6b, 0x58, 0x9b, 0xf6, 0x4f, + 0x31, 0x60, 0xc7, 0x6a, 0x58, 0xa7, 0xac, 0xc0, 0x6b, 0x81, 0xa2, 0x9d, + 0x7c, 0x8c, 0x1c, 0x2a, 0x21, 0x6f, 0xe6, 0xca, 0x4a, 0x2c, 0x59, 0x5f, + 0x84, 0xbd, 0x16, 0x69, 0x57, 0xe6, 0x10, 0x63, 0xf2, 0xef, 0xb3, 0x4e, + 0x78, 0x12, 0xb1, 0x07, 0x5a, 0xd8, 0xe8, 0x54, 0x32, 0x07, 0xfe, 0xc5, + 0x22, 0x75, 0xdd, 0x8a, 0x1c, 0xe9, 0x24, 0x57, 0x55, 0x21, 0xfc, 0xa7, + 0x92, 0xfd, 0x41, 0x2b, 0x86, 0x7f, 0x95, 0x52, 0x25, 0x6e, 0xfd, 0xda, + 0x00, 0x32, 0x8d, 0xfe, 0x0e, 0xf8, 0xca, 0x99, 0xfe, 0xf4, 0x8d, 0xc8, + 0x66, 0x37, 0x88, 0x96, 0xa1, 0xdb, 0x35, 0xc4, 0x0e, 0xfd, 0x72, 0x09, + 0xb6, 0x69, 0x77, 0x2d, 0xe6, 0xbe, 0xb4, 0xfb, 0xa4, 0x33, 0x30, 0xb1, + 0xe6, 0x54, 0x65, 0xb5, 0xdd, 0x3d, 0xa9, 0xed, 0x50, 0xd6, 0x0a, 0x55, + 0xfa, 0x76, 0x7c, 0x09, 0xbe, 0x5a, 0x6d, 0xf7, 0xa7, 0x1e, 0xdf, 0xec, + 0x4a, 0xeb, 0xeb, 0x55, 0x69, 0xd9, 0x15, 0x75, 0xb7, 0x92, 0x09, 0xc8, + 0xad, 0x62, 0x1f, 0xc6, 0x64, 0xe0, 0xd7, 0xed, 0xa9, 0xc7, 0x2f, 0x76, + 0xef, 0x47, 0xce, 0xcb, 0x67, 0xb5, 0x4a, 0x08, 0x9b, 0x5f, 0xbb, 0xd7, + 0x96, 0x50, 0x36, 0x06, 0xae, 0xd4, 0x92, 0x29, 0xe9, 0x0c, 0x24, 0x7e, + 0x6a, 0x0e, 0xfb, 0x55, 0xf0, 0x3e, 0x58, 0x94, 0xd6, 0x60, 0x6a, 0x4d, + 0x55, 0x5b, 0x12, 0x0f, 0x3a, 0xf8, 0xbb, 0xd2, 0xe8, 0xba, 0xee, 0xc5, + 0x6e, 0x8b, 0xfc, 0xae, 0x55, 0xf5, 0xdd, 0x43, 0xfd, 0x9b, 0x8c, 0x2d, + 0xc8, 0x19, 0xfd, 0x9e, 0xaa, 0x3a, 0xd2, 0x2c, 0x95, 0x20, 0xc3, 0x82, + 0x4d, 0xa8, 0xeb, 0x3c, 0xf6, 0x4d, 0xc7, 0xd6, 0x80, 0xfe, 0x2b, 0x4a, + 0x3b, 0x5a, 0x84, 0x9d, 0x60, 0x77, 0xaf, 0x28, 0x1b, 0xe1, 0xa7, 0xfa, + 0xd9, 0x28, 0x80, 0x8f, 0xf4, 0xfd, 0x35, 0x60, 0x51, 0x0d, 0x26, 0x7d, + 0x39, 0x2c, 0xcb, 0x29, 0xec, 0x9b, 0xf2, 0x75, 0xa0, 0x03, 0xf9, 0x26, + 0xc0, 0xd7, 0x00, 0x5f, 0x49, 0x4e, 0x1b, 0xde, 0x09, 0xf0, 0xde, 0xcc, + 0x78, 0x17, 0xca, 0xcb, 0x12, 0x81, 0x67, 0xda, 0x5f, 0x86, 0x3f, 0xd7, + 0x4a, 0x0d, 0xf0, 0x36, 0xa0, 0x03, 0xc6, 0x44, 0x5a, 0x4e, 0x85, 0x72, + 0x83, 0xf2, 0xb3, 0xcc, 0x25, 0x23, 0xb3, 0x05, 0x99, 0xd0, 0x2b, 0x71, + 0x21, 0x67, 0x09, 0xe3, 0x07, 0xba, 0x9d, 0x00, 0xb3, 0x4a, 0x7c, 0x7e, + 0x47, 0xab, 0x2a, 0xe2, 0xb8, 0x12, 0xfa, 0x6d, 0xe1, 0xfb, 0x88, 0xd4, + 0x91, 0xa3, 0x2a, 0x9c, 0x90, 0xa6, 0x67, 0x59, 0xaa, 0x6a, 0x4b, 0x13, + 0x51, 0x1c, 0xaf, 0x3a, 0x66, 0x6e, 0x0d, 0x71, 0xa6, 0xaa, 0x5b, 0x76, + 0x5a, 0x4f, 0x0a, 0xa0, 0x19, 0xc1, 0xfc, 0x38, 0x6c, 0x30, 0x09, 0xda, + 0x5f, 0x62, 0x7e, 0x06, 0xf8, 0x3b, 0x09, 0x1a, 0x8e, 0xcc, 0x23, 0xda, + 0x85, 0xf4, 0x15, 0xe8, 0x98, 0xcf, 0x55, 0x60, 0x9b, 0xe1, 0xd4, 0xca, + 0x7d, 0x0c, 0x9a, 0xc4, 0xc9, 0x72, 0x73, 0x38, 0xdf, 0xf2, 0x75, 0x1f, + 0xeb, 0xd7, 0xbe, 0xa1, 0xe4, 0xa6, 0xbe, 0x18, 0x32, 0x86, 0xe5, 0xd3, + 0x46, 0x18, 0x4f, 0xda, 0x06, 0x23, 0x72, 0xac, 0xe0, 0xc8, 0x5a, 0x72, + 0xf9, 0xe0, 0x7a, 0x68, 0xd9, 0x9d, 0xc5, 0x03, 0xd2, 0x2a, 0x05, 0x51, + 0x1d, 0xfe, 0xee, 0x24, 0xcc, 0x8d, 0x09, 0x9c, 0x3b, 0x40, 0xd4, 0x4d, + 0xe3, 0x39, 0xbe, 0x17, 0x3c, 0xf0, 0x63, 0x0b, 0xb2, 0x38, 0x22, 0x66, + 0x92, 0x00, 0x3a, 0xc2, 0x1e, 0xe1, 0x82, 0x77, 0x84, 0xf1, 0x58, 0xe2, + 0x1a, 0x6b, 0xd4, 0x65, 0xd4, 0xa8, 0x20, 0x6a, 0x66, 0xb9, 0xf2, 0x2e, + 0x6c, 0xdb, 0x4e, 0x58, 0x6f, 0xca, 0xc8, 0x15, 0xd6, 0x1b, 0xe6, 0x07, + 0x63, 0x25, 0xc7, 0x67, 0xf0, 0x84, 0xcc, 0x4f, 0x37, 0xc3, 0xe9, 0x5a, + 0x86, 0xc1, 0x4b, 0xd0, 0x43, 0xeb, 0x27, 0x80, 0xbf, 0xed, 0xc8, 0xc4, + 0x67, 0xcb, 0x57, 0xb7, 0xf4, 0xf4, 0x2c, 0x6d, 0xae, 0xf5, 0x89, 0x68, + 0x19, 0xb4, 0x7f, 0x83, 0xbd, 0x56, 0x80, 0xc1, 0xc4, 0x6d, 0xee, 0x5d, + 0x75, 0x6b, 0xdd, 0x7d, 0xd0, 0xc5, 0x07, 0x36, 0xc2, 0x06, 0x06, 0xab, + 0x47, 0x91, 0xef, 0xcc, 0xf9, 0xc0, 0x5f, 0x13, 0xce, 0xcb, 0xa8, 0xc2, + 0x7b, 0x13, 0x7e, 0xea, 0x54, 0x8e, 0x5a, 0x8d, 0xed, 0x31, 0x27, 0xab, + 0xf9, 0x13, 0x0a, 0x75, 0xa8, 0x59, 0x22, 0xdf, 0x08, 0xf8, 0xf6, 0x81, + 0x67, 0x14, 0x6b, 0x05, 0x8c, 0xc3, 0x72, 0x0c, 0xe6, 0x63, 0x2f, 0x1f, + 0x7b, 0xad, 0x88, 0x53, 0x7d, 0x05, 0xf8, 0x33, 0xe3, 0x37, 0xe4, 0x57, + 0x76, 0x5a, 0x63, 0xe9, 0x9b, 0xef, 0x0c, 0xf9, 0xc6, 0x17, 0xdb, 0xe4, + 0xe0, 0x23, 0x59, 0x4c, 0x11, 0x57, 0x1f, 0xce, 0xd6, 0x4b, 0xc0, 0xc7, + 0x6f, 0x66, 0xf8, 0xef, 0x12, 0x2b, 0xe5, 0x8c, 0xc1, 0xca, 0x11, 0x62, + 0x25, 0x70, 0xa5, 0xb5, 0x04, 0x7b, 0x47, 0x1f, 0x03, 0x5f, 0xea, 0xf0, + 0xc4, 0x6f, 0xbb, 0x0e, 0xe2, 0xca, 0x06, 0x3f, 0xeb, 0xf8, 0x77, 0xa1, + 0x5b, 0xe0, 0x7d, 0x0c, 0xbc, 0x89, 0x8f, 0x31, 0x0f, 0xb4, 0x46, 0xae, + 0x03, 0xab, 0x66, 0xcb, 0xa7, 0x10, 0xf7, 0x36, 0x70, 0x02, 0x15, 0x19, + 0xfb, 0xe6, 0x35, 0x37, 0xaf, 0xff, 0xfc, 0xbd, 0x6f, 0xc1, 0xcd, 0xa8, + 0x93, 0x47, 0x21, 0x63, 0xc6, 0x3f, 0x02, 0x3f, 0x6e, 0x2c, 0x7d, 0x19, + 0xcf, 0x1f, 0x33, 0x1e, 0xad, 0x1b, 0x15, 0xee, 0x2b, 0xd2, 0xe8, 0xd3, + 0x0e, 0x11, 0xec, 0x60, 0x30, 0x08, 0x39, 0x1f, 0x21, 0xe7, 0x45, 0x9a, + 0xc4, 0x0a, 0x60, 0x18, 0x71, 0x6f, 0x03, 0xf4, 0xaa, 0x52, 0x84, 0x5d, + 0x11, 0x4b, 0x4a, 0x5c, 0xa7, 0x7a, 0xcc, 0xed, 0x80, 0xb6, 0x50, 0x5d, + 0x75, 0xb7, 0xc2, 0x17, 0x73, 0xdb, 0x03, 0xc7, 0xc4, 0xaa, 0xa5, 0x7e, + 0xce, 0xe8, 0x1e, 0xcf, 0xe8, 0x56, 0x86, 0xe9, 0x30, 0xdf, 0xc8, 0xe6, + 0x63, 0xcc, 0xcf, 0x65, 0x36, 0x67, 0x3d, 0x70, 0x51, 0xa3, 0x59, 0x0b, + 0x02, 0xdf, 0x57, 0x88, 0xb5, 0x3b, 0xd6, 0x81, 0xa5, 0x21, 0xec, 0x16, + 0x65, 0x7a, 0x92, 0x12, 0x63, 0x72, 0xf8, 0xac, 0xa3, 0x28, 0x34, 0xbb, + 0xf1, 0x89, 0xdf, 0xdb, 0xd9, 0x3e, 0xa4, 0x25, 0x5e, 0x0f, 0xd3, 0x22, + 0x8d, 0x42, 0xd6, 0xd4, 0xdb, 0xd9, 0xec, 0x00, 0xd6, 0x90, 0xf3, 0x89, + 0x2d, 0x8f, 0x3a, 0xcc, 0xef, 0xc3, 0x05, 0x73, 0x0e, 0xd6, 0xe0, 0x9d, + 0x29, 0x83, 0x33, 0x2b, 0xdd, 0x22, 0x80, 0x7d, 0x5c, 0x8e, 0x23, 0x9f, + 0x9f, 0x85, 0xef, 0x2f, 0x46, 0x0a, 0x9d, 0x06, 0x6b, 0x8e, 0x46, 0x1c, + 0x06, 0xc6, 0x17, 0xb5, 0x70, 0x03, 0x91, 0xfc, 0x8a, 0x5c, 0x5b, 0x1c, + 0x93, 0xc2, 0x25, 0xea, 0xe0, 0x88, 0xb3, 0x39, 0xbc, 0xcf, 0x02, 0xf6, + 0x99, 0x02, 0x06, 0x3e, 0x82, 0xfa, 0x52, 0x12, 0x67, 0x16, 0x58, 0x9b, + 0xb8, 0x56, 0x1d, 0xf2, 0xd5, 0x25, 0x9e, 0x9f, 0x18, 0xec, 0x66, 0xb5, + 0x8d, 0xb9, 0x55, 0x14, 0xbb, 0xf7, 0x67, 0xe4, 0xae, 0x92, 0xf5, 0x8a, + 0xd6, 0x47, 0xa2, 0xf7, 0x60, 0x5f, 0xcc, 0x6d, 0x72, 0xed, 0x26, 0xe6, + 0x39, 0x47, 0x19, 0x8c, 0xc5, 0x03, 0xa8, 0x6b, 0xd8, 0xf3, 0x18, 0x79, + 0x8a, 0xa2, 0x7a, 0xc4, 0x7f, 0x8c, 0x9b, 0x7c, 0xe7, 0x99, 0x88, 0x6d, + 0x36, 0xc6, 0x31, 0x8c, 0x3c, 0xd3, 0x47, 0x99, 0xaf, 0xf8, 0xac, 0xb5, + 0x53, 0x1d, 0x97, 0x7a, 0x37, 0x04, 0xc6, 0xce, 0x94, 0x8f, 0x0b, 0xd7, + 0xf0, 0xde, 0xe7, 0xbc, 0x37, 0x34, 0x8f, 0xe7, 0xbe, 0xd1, 0x59, 0x9c, + 0xdd, 0xde, 0x67, 0x03, 0x86, 0x2d, 0x60, 0x1f, 0xf6, 0x39, 0xac, 0x7f, + 0x06, 0xb7, 0xe6, 0xd9, 0xb7, 0x5c, 0xee, 0xb2, 0x16, 0x3a, 0xcc, 0xcb, + 0x7b, 0x94, 0x1c, 0x90, 0x7a, 0x29, 0x3f, 0x17, 0xe2, 0x38, 0x22, 0xff, + 0x34, 0xfb, 0x19, 0x8d, 0xbc, 0x2b, 0xdb, 0xa6, 0x6f, 0x9c, 0x89, 0xd9, + 0x3f, 0x5c, 0xee, 0x23, 0x97, 0x7b, 0x5a, 0x9a, 0xa9, 0x2c, 0x6f, 0x15, + 0xfd, 0x6f, 0xed, 0x35, 0xd6, 0x40, 0xda, 0xf9, 0x5e, 0xf8, 0x06, 0x18, + 0xbd, 0xe9, 0xc8, 0xc5, 0x6e, 0x2a, 0x8b, 0x39, 0xf5, 0x42, 0x26, 0xaf, + 0x21, 0x7f, 0x80, 0x1c, 0xf6, 0x25, 0xec, 0x31, 0xd1, 0x53, 0x9e, 0x73, + 0x20, 0x8f, 0x36, 0xc0, 0xb5, 0xa0, 0x37, 0x9f, 0xe9, 0x1b, 0x80, 0xce, + 0x81, 0x4d, 0x69, 0x4b, 0xca, 0x62, 0xac, 0xfd, 0x5b, 0x13, 0x3f, 0x50, + 0x37, 0xb0, 0x07, 0xde, 0x07, 0x23, 0xe0, 0x99, 0x92, 0x57, 0x13, 0x83, + 0xa5, 0xde, 0x09, 0x60, 0x52, 0xa3, 0xfb, 0x8f, 0xbc, 0xb6, 0xc4, 0x6d, + 0xe0, 0xeb, 0xf3, 0x32, 0x2e, 0xce, 0xce, 0xb8, 0xbc, 0x80, 0x5e, 0xb0, + 0xd0, 0x43, 0x1d, 0x87, 0x0d, 0xd5, 0xd9, 0xd6, 0x3c, 0xfb, 0xb9, 0xb7, + 0xd8, 0x17, 0x55, 0xc2, 0xc8, 0xb6, 0x66, 0xe5, 0xcc, 0xcf, 0x82, 0xf9, + 0x6d, 0x93, 0xaf, 0x58, 0xdf, 0xf1, 0xe5, 0x74, 0x3f, 0x94, 0x33, 0x7d, + 0x0f, 0x7a, 0x79, 0xbb, 0x3d, 0xaf, 0x0a, 0x89, 0xa7, 0x0d, 0xfc, 0x89, + 0x97, 0x3c, 0x17, 0x6c, 0x5c, 0xa5, 0x4d, 0xd8, 0xe3, 0xd2, 0x7f, 0xc4, + 0xaf, 0xa3, 0x78, 0x1e, 0x13, 0x1b, 0x67, 0x52, 0x3d, 0xda, 0x82, 0xf6, + 0x1f, 0xee, 0x93, 0x89, 0x6d, 0x9e, 0xe9, 0x1d, 0x9b, 0x49, 0x9e, 0x7b, + 0x79, 0x2e, 0x32, 0xcf, 0x1d, 0x6b, 0x19, 0xf6, 0xba, 0x1e, 0x31, 0x1f, + 0x6f, 0xe9, 0xeb, 0xa6, 0x3f, 0xf3, 0xd8, 0x33, 0x0f, 0xf5, 0x67, 0x79, + 0x5f, 0xc3, 0x78, 0x2c, 0x0f, 0xe5, 0xe3, 0x0d, 0x93, 0x8b, 0x57, 0x90, + 0x97, 0xaf, 0x27, 0x65, 0x93, 0x93, 0x87, 0x0e, 0xdf, 0x2e, 0x27, 0x7f, + 0xfd, 0x15, 0x72, 0xf2, 0xed, 0x2c, 0x27, 0x47, 0x4c, 0xdc, 0xaa, 0xde, + 0xf0, 0xda, 0x6f, 0xb0, 0xc6, 0x39, 0xde, 0x37, 0x58, 0x43, 0xd1, 0xff, + 0x3f, 0x4c, 0x1f, 0xe5, 0xfe, 0x49, 0xe3, 0xb0, 0xee, 0x90, 0x06, 0x3e, + 0xec, 0x8d, 0x8b, 0x7d, 0x96, 0x39, 0x9b, 0xc7, 0x8c, 0x8f, 0x58, 0xcd, + 0xf9, 0xd1, 0x4f, 0x1e, 0x63, 0x2c, 0x14, 0x4c, 0x5e, 0xd8, 0xd5, 0x9c, + 0xa6, 0x2c, 0xcb, 0xe8, 0xd5, 0xde, 0xe3, 0xd8, 0x4f, 0x63, 0x65, 0xa4, + 0xe7, 0xca, 0x4b, 0x73, 0xc4, 0xa6, 0x20, 0xba, 0x06, 0x9d, 0xaf, 0x87, + 0x25, 0x29, 0xcc, 0x32, 0x5f, 0x59, 0x6d, 0x46, 0x10, 0x43, 0xb8, 0x77, + 0x25, 0xfa, 0x24, 0xfa, 0x29, 0xdf, 0x81, 0x9f, 0x5f, 0x47, 0x1c, 0x11, + 0x3b, 0x11, 0x13, 0xf3, 0x9b, 0x88, 0x89, 0xe3, 0x7c, 0x37, 0xfb, 0x16, + 0x0c, 0xad, 0x6d, 0xf6, 0x2f, 0x41, 0x7f, 0x57, 0x8a, 0xe7, 0x34, 0xee, + 0x5b, 0x9f, 0xf3, 0x9d, 0x36, 0xf1, 0x0b, 0xac, 0xc0, 0xfc, 0xba, 0x89, + 0x5f, 0xfa, 0x34, 0xf0, 0x88, 0xf3, 0x7f, 0x32, 0xb9, 0xf1, 0xa1, 0xc9, + 0xf1, 0xeb, 0x91, 0x89, 0xe7, 0x88, 0xfd, 0xe4, 0xe9, 0xfe, 0xfb, 0x05, + 0x83, 0x01, 0xc8, 0x8f, 0x53, 0x91, 0x89, 0xb5, 0xf9, 0x2b, 0x38, 0xf6, + 0x9b, 0x69, 0x2e, 0x0c, 0xc9, 0x99, 0xf6, 0x1e, 0x4b, 0x73, 0xcb, 0xdf, + 0x30, 0x77, 0x8a, 0x19, 0xf4, 0x43, 0xa0, 0xeb, 0xef, 0xc5, 0x83, 0x49, + 0x8c, 0xb4, 0xf7, 0x27, 0x90, 0xeb, 0xc1, 0x86, 0x94, 0x43, 0xbd, 0xa9, + 0xd7, 0xb8, 0x84, 0x67, 0x73, 0x9d, 0x3e, 0x31, 0xba, 0xfc, 0xaf, 0x3c, + 0xac, 0xef, 0xdc, 0x8e, 0xcf, 0x1b, 0xe2, 0xfb, 0xeb, 0x6d, 0xf8, 0xb0, + 0xbe, 0x43, 0x9e, 0xb1, 0xdd, 0x5e, 0xa2, 0xbe, 0x1b, 0xd7, 0x31, 0xe2, + 0x9e, 0xbc, 0x7b, 0xef, 0x79, 0xc3, 0x39, 0x90, 0xd7, 0x70, 0xc6, 0x39, + 0xf7, 0xcc, 0x63, 0x3d, 0x8f, 0xf1, 0x3c, 0xe6, 0xf3, 0x58, 0x0f, 0xa2, + 0xe7, 0x24, 0xf5, 0xaf, 0xd3, 0x0b, 0xb0, 0xff, 0xd8, 0x1d, 0xee, 0x26, + 0x5f, 0x56, 0x8f, 0x24, 0xfe, 0xfc, 0x1e, 0xf8, 0xfb, 0xac, 0x67, 0x74, + 0x99, 0x6b, 0xf8, 0xb3, 0x4f, 0xbf, 0x89, 0xfa, 0x1f, 0x65, 0xb6, 0x8d, + 0xb3, 0x31, 0xa5, 0x49, 0xfb, 0xbd, 0x9f, 0x64, 0x98, 0xfb, 0xfd, 0xb4, + 0xbe, 0x48, 0x9e, 0x53, 0xcc, 0x21, 0x93, 0x53, 0x3c, 0x0f, 0xee, 0xe8, + 0x5a, 0xaf, 0xc2, 0x8f, 0x2f, 0x45, 0x79, 0x1e, 0x21, 0x9e, 0x0e, 0xe7, + 0x39, 0x0e, 0x3b, 0x85, 0xb7, 0xb4, 0x33, 0x1b, 0xc3, 0x66, 0xbc, 0x17, + 0x37, 0xd0, 0x1b, 0xd1, 0x4e, 0x2b, 0xd6, 0x13, 0xbb, 0x77, 0xe1, 0xbd, + 0x7d, 0x10, 0xed, 0x46, 0xbb, 0x0e, 0xdb, 0x2d, 0x88, 0x26, 0x15, 0x31, + 0xe0, 0x76, 0x38, 0x91, 0xd7, 0x6b, 0x60, 0xd0, 0x6c, 0x6e, 0xa7, 0xaf, + 0x5c, 0xb3, 0xe3, 0xf4, 0x3b, 0xc2, 0x5e, 0x7c, 0xd8, 0xb4, 0x87, 0xf0, + 0xe1, 0x36, 0x3d, 0x25, 0x65, 0xd0, 0x06, 0xa8, 0x5f, 0xa6, 0xcf, 0x60, + 0x0f, 0x79, 0x4b, 0xdb, 0xa6, 0x9f, 0x24, 0x36, 0xb2, 0x8f, 0xec, 0x8c, + 0xc8, 0xd8, 0x3e, 0xf3, 0x1e, 0x6f, 0x73, 0x64, 0x4c, 0x48, 0x5a, 0x97, + 0x8c, 0xfe, 0xcf, 0x64, 0xfa, 0xa7, 0x3a, 0x8b, 0xba, 0x13, 0xa6, 0x51, + 0x57, 0x0f, 0xba, 0x3e, 0x94, 0xdb, 0xa5, 0xa5, 0xaa, 0x27, 0xa4, 0x51, + 0x31, 0x77, 0x5b, 0xdc, 0xa5, 0xa0, 0xc3, 0x12, 0xf5, 0x28, 0x43, 0x8f, + 0x71, 0xdc, 0x3d, 0x82, 0x95, 0x96, 0x04, 0xf1, 0x1a, 0x08, 0xe7, 0x7e, + 0x4a, 0xbb, 0x3d, 0xed, 0x6e, 0x75, 0x69, 0xb7, 0x27, 0xdd, 0x4e, 0x77, + 0x1a, 0xfd, 0x5f, 0x00, 0x6f, 0x07, 0xf3, 0x97, 0x84, 0x31, 0xb6, 0x10, + 0x71, 0x3c, 0x2d, 0xec, 0xb7, 0x9e, 0x76, 0x67, 0xfa, 0x1c, 0x9f, 0x74, + 0xc3, 0xfe, 0xb0, 0xdc, 0xbf, 0x68, 0x60, 0x62, 0x7c, 0x03, 0x79, 0xf4, + 0xea, 0x20, 0xdd, 0x1b, 0xf7, 0xbf, 0x4c, 0x2e, 0xe6, 0x92, 0x5c, 0xb6, + 0x10, 0xa7, 0x28, 0x1b, 0x72, 0xa7, 0xa3, 0xdf, 0x99, 0x3d, 0x78, 0xff, + 0xb9, 0xd3, 0x1e, 0x77, 0xe7, 0xdf, 0x2e, 0x90, 0x3b, 0x05, 0x83, 0x3d, + 0x1b, 0x09, 0xee, 0xcc, 0x25, 0xad, 0x9b, 0xe1, 0x87, 0xb0, 0x1d, 0x7a, + 0x80, 0x45, 0x0f, 0x7f, 0xe0, 0xea, 0x2a, 0xd7, 0xd0, 0x67, 0xe3, 0xae, + 0xc7, 0xfb, 0xda, 0x46, 0xc2, 0x35, 0xc6, 0x38, 0x7a, 0xc1, 0xc5, 0x8f, + 0x40, 0xfb, 0x81, 0x6e, 0x0d, 0x94, 0xb9, 0x8f, 0xab, 0x10, 0xf7, 0xac, + 0x01, 0xfb, 0x15, 0xb1, 0x1a, 0x89, 0xf8, 0xcd, 0x68, 0xc9, 0xdc, 0xc7, + 0x62, 0xcf, 0xe7, 0x9d, 0x13, 0x3d, 0xe6, 0xe2, 0x50, 0x8f, 0xb9, 0x88, + 0x1e, 0xf3, 0x9e, 0x22, 0xe2, 0x3c, 0xc6, 0x3d, 0x53, 0x35, 0xd3, 0xbc, + 0x99, 0xe0, 0x9d, 0xb2, 0x5d, 0x92, 0x7d, 0xe8, 0x9e, 0xa0, 0x5b, 0x88, + 0xfd, 0xb9, 0x7e, 0x30, 0xfb, 0xee, 0x85, 0x4d, 0xc7, 0x62, 0xd3, 0x6f, + 0xb5, 0x4b, 0x23, 0xa8, 0xff, 0xa4, 0xb9, 0x2f, 0xa3, 0x79, 0x6e, 0x0f, + 0xcd, 0xd7, 0x78, 0x46, 0xca, 0x96, 0xe6, 0x1b, 0xcc, 0x3b, 0xd6, 0xd2, + 0x91, 0x2c, 0xdf, 0x4e, 0xe0, 0xb9, 0x98, 0x3d, 0xe7, 0xf4, 0x87, 0xf7, + 0xf0, 0x3f, 0xa2, 0xd2, 0x77, 0x3e, 0x53, 0xe7, 0x98, 0x7d, 0x30, 0xe4, + 0x2d, 0x59, 0xe9, 0xb7, 0x92, 0xf3, 0x38, 0x3b, 0x7d, 0x92, 0xf6, 0x17, + 0xc0, 0x60, 0x74, 0x57, 0x33, 0xb0, 0xbb, 0xd6, 0xed, 0x25, 0xe2, 0xda, + 0xc2, 0xfc, 0x11, 0x83, 0x6f, 0x6a, 0x4a, 0x49, 0x8e, 0xb9, 0xc3, 0xcf, + 0x18, 0x97, 0xcc, 0x37, 0x01, 0xbc, 0xa7, 0x32, 0xb6, 0x70, 0x3f, 0x16, + 0xe4, 0x70, 0xcb, 0xe8, 0x65, 0xa5, 0xf7, 0x1e, 0xaf, 0xc6, 0x7a, 0x80, + 0xba, 0xf1, 0x20, 0xf5, 0xda, 0xfd, 0x76, 0xb1, 0x86, 0x5a, 0xf3, 0x2e, + 0x62, 0x1f, 0xf9, 0x69, 0x7a, 0xa8, 0x2d, 0xf3, 0xed, 0x00, 0x75, 0x08, + 0xd7, 0xa0, 0x4e, 0xb8, 0xfb, 0x0d, 0x41, 0x2e, 0x80, 0xe6, 0x22, 0xd6, + 0x4e, 0xf7, 0xf3, 0x9e, 0x16, 0x7d, 0x3c, 0x70, 0x6f, 0x3d, 0xfc, 0x97, + 0x6e, 0x96, 0x86, 0x69, 0xf9, 0xfb, 0x2f, 0xb4, 0x78, 0xd5, 0x79, 0x38, + 0x15, 0x00, 0x00, 0x00 }; static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 }; -static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 }; +static const u32 bnx2_TPAT_b09FwRodata[(0x4/4) + 1] = { + 0x00000001, 0x00000000 }; static struct fw_info bnx2_tpat_fw_09 = { - /* Firmware version: 3.7.1 */ - .ver_major = 0x3, - .ver_minor = 0x7, - .ver_fix = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x08000860, + .start_addr = 0x08000888, .text_addr = 0x08000800, - .text_len = 0x188c, + .text_len = 0x1534, .text_index = 0x0, .gz_text = bnx2_TPAT_b09FwText, .gz_text_len = sizeof(bnx2_TPAT_b09FwText), - .data_addr = 0x080020c0, + .data_addr = 0x00000000, .data_len = 0x0, .data_index = 0x0, .data = bnx2_TPAT_b09FwData, - .sbss_addr = 0x080020c8, - .sbss_len = 0x30, + .sbss_addr = 0x08001d60, + .sbss_len = 0x48, .sbss_index = 0x0, - .bss_addr = 0x08002100, - .bss_len = 0x850, + .bss_addr = 0x08001da8, + .bss_len = 0x10a0, .bss_index = 0x0, - .rodata_addr = 0x00000000, - .rodata_len = 0x0, + .rodata_addr = 0x08001d34, + .rodata_len = 0x4, .rodata_index = 0x0, .rodata = bnx2_TPAT_b09FwRodata, }; static u8 bnx2_TXP_b09FwText[] = { - 0xbd, 0x7c, 0x7d, 0x70, 0x1c, 0xe7, 0x79, 0xdf, 0xb3, 0xbb, 0x07, 0xe0, - 0x00, 0x82, 0xe0, 0x12, 0x39, 0x52, 0x27, 0x0a, 0xa6, 0x6e, 0x89, 0x3d, - 0x08, 0x32, 0x20, 0x71, 0xc5, 0x20, 0x36, 0x26, 0xb9, 0xca, 0xab, 0xbb, - 0x03, 0x78, 0x94, 0x31, 0x31, 0xc4, 0xc2, 0x16, 0xed, 0x70, 0xd4, 0xeb, - 0x01, 0xa4, 0x95, 0x54, 0x9e, 0xb2, 0xb6, 0xda, 0x72, 0x5a, 0x35, 0x3a, - 0x1f, 0xc0, 0x0f, 0x29, 0x47, 0x1c, 0x24, 0xc0, 0x84, 0xfe, 0x70, 0x93, - 0x13, 0x0e, 0x24, 0x64, 0xf7, 0x88, 0x93, 0xfc, 0xd9, 0x3f, 0x62, 0x0b, - 0x03, 0xd2, 0xb4, 0x5a, 0xbb, 0xb5, 0xda, 0x28, 0x13, 0xcf, 0xf4, 0x63, - 0x30, 0x14, 0xa5, 0x28, 0x71, 0xa7, 0x56, 0x9b, 0x4c, 0xa2, 0x36, 0x94, - 0xaf, 0xbf, 0xdf, 0xbb, 0xbb, 0xe0, 0x01, 0x22, 0x65, 0x51, 0x93, 0x14, - 0x33, 0x37, 0x77, 0xfb, 0xee, 0xbb, 0xef, 0xfb, 0x7c, 0xbd, 0xcf, 0xf3, - 0xfc, 0x9e, 0xf7, 0x5d, 0x44, 0x45, 0xda, 0xc4, 0xff, 0xdb, 0x8a, 0x4f, - 0xec, 0xd8, 0xf1, 0xc7, 0xef, 0xfd, 0xf8, 0xbd, 0xbf, 0x8a, 0x9f, 0xf7, - 0x89, 0xd6, 0x62, 0xf0, 0xe6, 0x5b, 0x86, 0x48, 0xf6, 0xcf, 0xe5, 0x43, - 0xff, 0xe1, 0x71, 0x33, 0x18, 0x9f, 0x1f, 0x09, 0xeb, 0x89, 0x57, 0x87, - 0x93, 0xb6, 0x84, 0x8d, 0x44, 0xfe, 0xa1, 0x71, 0x5b, 0xc4, 0xad, 0xf6, - 0xc5, 0x52, 0xf2, 0x6e, 0x3d, 0x1f, 0x09, 0x09, 0xdb, 0x3f, 0x92, 0xb8, - 0xf6, 0xe4, 0xf7, 0x3e, 0x6e, 0xbd, 0x5d, 0x36, 0x24, 0x6c, 0x26, 0xb2, - 0x62, 0xf6, 0x48, 0xb8, 0x0b, 0xcf, 0x7c, 0xf5, 0xae, 0x47, 0x0d, 0xe9, - 0x08, 0xc6, 0x7a, 0xab, 0xfe, 0xbd, 0xbb, 0x24, 0xbf, 0x2b, 0x51, 0x8f, - 0x85, 0x12, 0xef, 0xd6, 0xa7, 0x06, 0xc2, 0xa2, 0x27, 0xac, 0x68, 0xd2, - 0x88, 0xc8, 0xcb, 0x35, 0x53, 0x5e, 0xac, 0xc5, 0x64, 0xb2, 0x26, 0x1d, - 0xe9, 0xda, 0x8d, 0x68, 0xaa, 0xa3, 0xef, 0xbb, 0xf5, 0xe4, 0x40, 0x28, - 0x6b, 0x24, 0xa4, 0x23, 0x59, 0x93, 0xd1, 0x63, 0xc5, 0xd6, 0x87, 0x9b, - 0x12, 0x4f, 0xd6, 0x75, 0x5b, 0xb2, 0xa1, 0x84, 0x9d, 0xd7, 0xf5, 0xf6, - 0x41, 0xf3, 0x63, 0x68, 0xaf, 0x0e, 0x86, 0x26, 0x8b, 0xa6, 0x9c, 0x1b, - 0x68, 0x15, 0xdd, 0x0e, 0x4b, 0xb2, 0xd6, 0xfa, 0xb0, 0x9e, 0x88, 0x88, - 0x5b, 0xab, 0xd7, 0x8f, 0x39, 0xff, 0x64, 0xaf, 0xf9, 0xeb, 0xe1, 0xf0, - 0x64, 0x51, 0xde, 0x0e, 0xd9, 0x76, 0x74, 0x42, 0x7a, 0xcc, 0x9c, 0x68, - 0x92, 0xec, 0xef, 0x89, 0x1e, 0xc1, 0xf7, 0x78, 0x7f, 0xdc, 0x4c, 0xc9, - 0x16, 0x71, 0xcd, 0x6f, 0xae, 0x98, 0x3d, 0x5d, 0x59, 0x3d, 0x11, 0x96, - 0x74, 0x51, 0x13, 0xc3, 0x8e, 0xc8, 0x64, 0xc5, 0x96, 0xfc, 0x52, 0x87, - 0xe4, 0x2b, 0xf2, 0xc4, 0x94, 0xd3, 0x2e, 0x53, 0x4b, 0x47, 0x7d, 0x5d, - 0x44, 0xd0, 0xd6, 0x2b, 0xf9, 0x5a, 0x14, 0x9f, 0x9f, 0xf8, 0xfc, 0xea, - 0x22, 0x3b, 0x05, 0xcf, 0xf7, 0xa7, 0xdd, 0xea, 0xd7, 0xc2, 0x5e, 0xdb, - 0x7f, 0xd9, 0xe2, 0x7d, 0x83, 0xdf, 0x12, 0xf8, 0x2d, 0x85, 0x65, 0xcd, - 0x88, 0xca, 0xf7, 0xee, 0x8a, 0xc9, 0x54, 0x69, 0x0d, 0xb2, 0x89, 0xca, - 0x37, 0x6a, 0x11, 0x79, 0x49, 0xc9, 0x22, 0xa4, 0x0d, 0xa3, 0xcf, 0x64, - 0x69, 0x42, 0x3f, 0x51, 0xcc, 0x4b, 0xaa, 0x96, 0xd5, 0x0b, 0x73, 0x66, - 0x47, 0x72, 0x29, 0xa7, 0x4f, 0xce, 0x75, 0x76, 0xa4, 0x96, 0x26, 0xf4, - 0x42, 0x31, 0x0a, 0x39, 0x98, 0x1d, 0xa9, 0xf9, 0x08, 0xae, 0x3b, 0x3b, - 0x92, 0xf3, 0xd6, 0x0c, 0x26, 0x45, 0x9f, 0x68, 0x47, 0xaa, 0x64, 0x65, - 0x45, 0xba, 0x9d, 0x1f, 0x48, 0x57, 0x47, 0xaa, 0xf6, 0x5b, 0xfa, 0x8a, - 0xa9, 0x49, 0xe1, 0x1e, 0x31, 0xa3, 0x89, 0xb7, 0xeb, 0xb7, 0xdb, 0x9a, - 0x98, 0xf6, 0x3b, 0xf5, 0xed, 0x90, 0x4d, 0x6e, 0xb6, 0x15, 0xbc, 0x92, - 0x26, 0x53, 0x72, 0xf3, 0x7d, 0xe6, 0xaa, 0x34, 0x89, 0x1b, 0x09, 0xae, - 0xeb, 0xf5, 0xa4, 0xf3, 0x07, 0xe4, 0x91, 0xf2, 0xee, 0x18, 0x86, 0x5e, - 0x92, 0xa0, 0x39, 0xe9, 0xbc, 0x5b, 0xf7, 0x9e, 0x09, 0x63, 0xce, 0x50, - 0xc7, 0x50, 0xa9, 0x5e, 0x4f, 0x3b, 0x18, 0xdf, 0x09, 0x9e, 0x6d, 0x92, - 0x72, 0xc4, 0x2d, 0x4f, 0x3a, 0x96, 0xe1, 0xc9, 0x87, 0xba, 0xe7, 0xb5, - 0x0b, 0x7d, 0xe4, 0x25, 0x17, 0x91, 0x72, 0xc1, 0xf9, 0x98, 0x3c, 0xe5, - 0x44, 0xc1, 0x5f, 0x58, 0x4e, 0x39, 0xb0, 0x2f, 0xfb, 0xb8, 0x96, 0xac, - 0x59, 0xb1, 0xac, 0x3c, 0x2d, 0xc9, 0xf9, 0x6e, 0x33, 0x2d, 0x98, 0xdb, - 0xae, 0xdf, 0x99, 0x74, 0x30, 0x5f, 0xff, 0xff, 0xad, 0xbb, 0x11, 0x2b, - 0x5b, 0x96, 0x5e, 0x29, 0x94, 0xba, 0x9d, 0x1f, 0x43, 0x4f, 0x61, 0x5b, - 0xdc, 0x71, 0xdb, 0x84, 0xdc, 0xac, 0xde, 0x94, 0x51, 0x97, 0x07, 0x31, - 0x7f, 0xd2, 0xc6, 0xfd, 0x9a, 0x6c, 0xd3, 0xed, 0x66, 0x29, 0x98, 0x12, - 0x69, 0x93, 0xdd, 0x52, 0x98, 0x45, 0xbb, 0xe3, 0x76, 0xea, 0x78, 0x26, - 0x33, 0xc0, 0x36, 0xd1, 0x8c, 0x04, 0x75, 0x2c, 0xb2, 0x50, 0xed, 0xc5, - 0xfc, 0x71, 0xb7, 0x55, 0x33, 0x65, 0xcd, 0x0c, 0x49, 0xa5, 0x1a, 0x77, - 0xa3, 0x5a, 0xb3, 0x9c, 0x8a, 0xb7, 0x41, 0xa6, 0x51, 0x8c, 0x2d, 0x5f, - 0xd6, 0x13, 0xf1, 0x68, 0x0e, 0x4a, 0xa3, 0x1d, 0x4d, 0x81, 0x9e, 0x29, - 0x27, 0xab, 0xa5, 0x6a, 0x9f, 0xd3, 0x92, 0x4b, 0x87, 0xb4, 0xfd, 0x4b, - 0xe8, 0x53, 0xfb, 0x1f, 0xbe, 0x0d, 0x44, 0x41, 0x9b, 0x8e, 0x67, 0xd9, - 0x0e, 0x9a, 0x15, 0xed, 0x68, 0x83, 0x2e, 0x57, 0xc6, 0x22, 0x1d, 0x49, - 0xa5, 0x4b, 0xd2, 0xa6, 0x4b, 0x6e, 0x54, 0x93, 0x4e, 0xdb, 0x95, 0xf0, - 0xaf, 0x41, 0x9f, 0xf3, 0xd0, 0xe5, 0x7c, 0x4c, 0x4e, 0x94, 0x24, 0xa2, - 0x0b, 0xe7, 0xca, 0xea, 0x95, 0x2a, 0xed, 0x01, 0xba, 0x85, 0xee, 0x0b, - 0x55, 0x3e, 0x0b, 0x1d, 0x96, 0xd2, 0x90, 0x4f, 0x06, 0x73, 0x1f, 0xd4, - 0x1e, 0xac, 0x8c, 0x69, 0x19, 0xd8, 0x49, 0x61, 0xb6, 0x0f, 0xba, 0xb3, - 0x62, 0x6b, 0xb2, 0x4d, 0x0a, 0xb6, 0x1d, 0xfb, 0xac, 0xb4, 0xcb, 0xa9, - 0x79, 0x5b, 0x4e, 0xcc, 0xc3, 0x1e, 0x4d, 0xcb, 0x5c, 0x94, 0xae, 0xec, - 0x96, 0x44, 0x87, 0x3c, 0x3d, 0x6b, 0x65, 0xca, 0xd2, 0xed, 0xbe, 0x81, - 0xfb, 0xb9, 0x33, 0xd4, 0xa9, 0xe4, 0x53, 0x8e, 0x21, 0x59, 0x93, 0x76, - 0x7d, 0x9b, 0x26, 0x6d, 0xf5, 0x27, 0x93, 0x8e, 0x15, 0xa5, 0xcd, 0xa6, - 0x3e, 0xdd, 0x6d, 0x1e, 0x10, 0xcb, 0xcc, 0x50, 0xfe, 0x4e, 0x1f, 0xf4, - 0xf0, 0xbf, 0x29, 0x7b, 0x8c, 0x45, 0x1d, 0xf7, 0x45, 0x4f, 0x41, 0x97, - 0x59, 0xa5, 0xe3, 0x0e, 0xcc, 0x1f, 0xf2, 0x6d, 0x87, 0x6b, 0xe2, 0x6e, - 0xcd, 0x93, 0x43, 0x87, 0xcc, 0x54, 0xda, 0xa5, 0x00, 0x1d, 0x16, 0xc4, - 0x96, 0xc2, 0xd2, 0x5e, 0xbf, 0xdd, 0xc6, 0x7a, 0xf9, 0x53, 0x5d, 0xda, - 0x8e, 0x6b, 0x87, 0x6a, 0x3f, 0xd7, 0x7c, 0xfb, 0x81, 0xfd, 0x85, 0xc5, - 0x1d, 0x0d, 0xcb, 0xf9, 0x9a, 0x67, 0x7f, 0x0b, 0xf0, 0x3d, 0xae, 0xe9, - 0xc2, 0x96, 0xde, 0x5c, 0xef, 0x73, 0xbe, 0xd6, 0x85, 0x67, 0xc3, 0x72, - 0xa2, 0xc6, 0xfe, 0x79, 0xd8, 0x58, 0x58, 0x96, 0xef, 0x6a, 0x97, 0x2c, - 0xda, 0x0b, 0xf3, 0xe2, 0x26, 0x1d, 0x1d, 0xcf, 0x74, 0x80, 0x97, 0x9d, - 0xf8, 0xb4, 0xc9, 0x78, 0xa5, 0xc5, 0xe5, 0x7a, 0x1d, 0xaf, 0x51, 0xff, - 0xf8, 0x2e, 0x05, 0x36, 0x40, 0xf9, 0xb2, 0x9d, 0xcf, 0xb1, 0xdd, 0x44, - 0x7b, 0x63, 0x1b, 0x6d, 0x7b, 0x1b, 0x65, 0xda, 0xcb, 0x35, 0x9a, 0x2b, - 0xc5, 0xcd, 0x43, 0xfc, 0xae, 0xd1, 0x1e, 0x1a, 0x6d, 0x21, 0x84, 0xfe, - 0xd0, 0x63, 0x05, 0x73, 0xcd, 0x5e, 0xab, 0x37, 0x0d, 0xe0, 0xda, 0xfe, - 0x1d, 0xf0, 0xc9, 0xb9, 0x43, 0xa0, 0x4b, 0x97, 0x6c, 0x45, 0xd1, 0x16, - 0xa3, 0x0d, 0x78, 0x7c, 0x74, 0xc9, 0xe4, 0x7c, 0x7b, 0x47, 0x7a, 0x9e, - 0xed, 0xc9, 0xa8, 0x01, 0x3e, 0xc7, 0x1d, 0x59, 0x99, 0x72, 0xf4, 0xee, - 0x10, 0xe8, 0x9a, 0xc0, 0x82, 0x03, 0x1f, 0x3e, 0x8d, 0x2b, 0xb8, 0xdf, - 0x29, 0xe3, 0x4b, 0xec, 0xcb, 0x39, 0x0a, 0xdb, 0x75, 0x49, 0x80, 0x36, - 0x7c, 0x6c, 0x0b, 0xf7, 0x5b, 0x31, 0x4f, 0x3b, 0x6c, 0x67, 0x9a, 0xba, - 0xfb, 0x44, 0xd2, 0xe9, 0x94, 0xec, 0x7a, 0x5f, 0x81, 0xdd, 0xb1, 0x7f, - 0xef, 0xa6, 0xbe, 0x90, 0xef, 0x12, 0xc6, 0x9c, 0x6f, 0x85, 0x0c, 0xd9, - 0xae, 0x83, 0xe6, 0x16, 0xd0, 0x00, 0x1f, 0x6c, 0x77, 0x63, 0x3d, 0xb4, - 0x60, 0xfc, 0x2d, 0xe0, 0xa9, 0x55, 0x26, 0x66, 0x3b, 0xa1, 0x0b, 0x13, - 0x7d, 0xc3, 0xf2, 0x74, 0xc9, 0x82, 0x0d, 0xb0, 0x3f, 0x74, 0x30, 0x6f, - 0x45, 0x2b, 0xe2, 0xca, 0x94, 0xd3, 0x02, 0xfb, 0xaa, 0xd7, 0x8f, 0xc0, - 0x3e, 0xbe, 0xae, 0xfc, 0x45, 0x9f, 0x39, 0xa4, 0x49, 0xbe, 0x25, 0xf1, - 0x7d, 0xd0, 0x63, 0x3d, 0x2a, 0xc2, 0xeb, 0xbd, 0x1a, 0xd7, 0x2c, 0xe4, - 0xc8, 0xb9, 0xe1, 0x93, 0x76, 0x42, 0x86, 0xf4, 0x5b, 0x5d, 0xb0, 0xe7, - 0xa8, 0xf2, 0x27, 0x43, 0x37, 0xf4, 0x27, 0xd6, 0x68, 0x19, 0x73, 0x15, - 0x96, 0x42, 0xf4, 0x61, 0x83, 0x58, 0xae, 0xb2, 0x15, 0x6b, 0x6f, 0x52, - 0xd9, 0xc7, 0x4f, 0xc8, 0x6f, 0xfd, 0x53, 0x0e, 0xe9, 0x22, 0xbf, 0x2e, - 0x9e, 0xa5, 0x0d, 0x5a, 0xc7, 0x5d, 0x35, 0xff, 0x4f, 0xfc, 0xf9, 0x3d, - 0xda, 0x0b, 0xa5, 0x0e, 0x2d, 0xa5, 0x68, 0x08, 0xc6, 0x11, 0x59, 0x3d, - 0xd3, 0x6d, 0x3e, 0x08, 0x1b, 0xa6, 0x9f, 0x5a, 0xbd, 0x40, 0x1d, 0x63, - 0x8c, 0x01, 0xea, 0xd8, 0x54, 0xf4, 0x25, 0xe7, 0xb9, 0xf6, 0xa4, 0xcb, - 0x10, 0xfa, 0x08, 0xf8, 0x5c, 0xac, 0xc5, 0x49, 0x7f, 0x2d, 0xe6, 0xaa, - 0xb4, 0xbf, 0xc7, 0xf1, 0xac, 0x2e, 0x43, 0x71, 0xfa, 0x87, 0xa7, 0x25, - 0x05, 0x1f, 0x09, 0x3d, 0x4a, 0x05, 0xbc, 0x2c, 0x94, 0x1a, 0xfd, 0x16, - 0x6c, 0xab, 0xff, 0xaf, 0xeb, 0x9e, 0x3f, 0xa4, 0x6f, 0xa0, 0xaf, 0x29, - 0x98, 0x3a, 0x24, 0x87, 0xc8, 0xe0, 0x42, 0x37, 0x4e, 0xd2, 0xb0, 0x32, - 0x59, 0xc6, 0x1c, 0xbb, 0x2e, 0xf6, 0x7d, 0x82, 0x48, 0xda, 0xcb, 0xf8, - 0xb7, 0x2f, 0xf0, 0x4f, 0xab, 0xd5, 0x40, 0x17, 0xd4, 0x2b, 0xf5, 0x10, - 0xf8, 0x88, 0x90, 0x5c, 0x84, 0xef, 0x9a, 0x2a, 0xb5, 0xcb, 0x0a, 0x68, - 0xba, 0x54, 0x0d, 0x6c, 0xcd, 0xf0, 0x6d, 0x8d, 0xcf, 0xb4, 0xe3, 0xf9, - 0x10, 0xfc, 0x9a, 0xe4, 0x8d, 0x04, 0x7e, 0x17, 0x39, 0x26, 0xdb, 0x02, - 0x3b, 0xe7, 0x9a, 0xb1, 0xdc, 0xb2, 0x34, 0x4b, 0x26, 0x8e, 0xf8, 0x31, - 0xaf, 0x63, 0xae, 0x2e, 0xf8, 0xf2, 0x90, 0x1c, 0x2d, 0x45, 0xe4, 0xf3, - 0x25, 0xf2, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xbe, 0x0e, 0x9d, 0x0f, - 0xc3, 0xe7, 0x65, 0xb4, 0x21, 0xf8, 0x9f, 0x03, 0x95, 0xcf, 0x69, 0xe9, - 0xa5, 0xac, 0x36, 0x5c, 0x3b, 0xa4, 0x65, 0x96, 0xc6, 0xb4, 0xfd, 0x0d, - 0xbe, 0x48, 0xb4, 0xf7, 0xf7, 0x45, 0x4f, 0xcd, 0x72, 0xce, 0x6e, 0xe7, - 0xc6, 0xbe, 0xe8, 0xd7, 0xf5, 0x46, 0x5f, 0xd4, 0x0d, 0x5f, 0x94, 0x81, - 0x2f, 0x1a, 0xbe, 0x65, 0x5f, 0x34, 0xa2, 0xdf, 0xd8, 0x17, 0x1d, 0xd4, - 0xaf, 0xfb, 0x22, 0xc6, 0x9e, 0x15, 0x5c, 0x9b, 0xb2, 0x67, 0x5f, 0x20, - 0xe7, 0x28, 0xfc, 0xf0, 0x16, 0xc8, 0xba, 0x8d, 0x6b, 0x27, 0x56, 0x80, - 0xdd, 0x4f, 0x60, 0xae, 0xdf, 0x86, 0xbd, 0xef, 0x89, 0xdb, 0xe6, 0x43, - 0x6a, 0xde, 0xf7, 0xea, 0x7c, 0x68, 0x5d, 0xe7, 0xa4, 0xf1, 0x97, 0xea, - 0xdc, 0xf5, 0x74, 0x4e, 0x5d, 0xb7, 0xca, 0x11, 0x35, 0x6f, 0x5d, 0x42, - 0xf7, 0x09, 0xbc, 0x8a, 0x3c, 0x60, 0x24, 0x2c, 0x8c, 0xa7, 0x63, 0x7e, - 0xea, 0x2b, 0x0e, 0x1a, 0x04, 0xfa, 0x6d, 0x57, 0xbe, 0x68, 0x3f, 0xf4, - 0xbe, 0x5a, 0xbd, 0x35, 0x5d, 0x65, 0x1a, 0x74, 0xf5, 0xe0, 0x06, 0x5d, - 0xb5, 0x48, 0x7f, 0x3c, 0xd0, 0xd1, 0x36, 0x49, 0xc6, 0xa9, 0xb3, 0x5b, - 0xd1, 0xd5, 0xb9, 0xbf, 0x25, 0x5d, 0x7d, 0xf7, 0x26, 0xba, 0xfa, 0xde, - 0x26, 0x5d, 0xd9, 0xe6, 0x33, 0x1a, 0xc7, 0x66, 0xfc, 0xa0, 0x3f, 0xaa, - 0xdf, 0x39, 0xce, 0xfc, 0xa1, 0xc6, 0x35, 0x1d, 0xe4, 0x1d, 0x5c, 0xcf, - 0x2f, 0xd7, 0x0d, 0xdb, 0x86, 0xec, 0xb8, 0xa6, 0x29, 0x37, 0xcb, 0xfc, - 0x14, 0xe9, 0x47, 0xec, 0x18, 0x47, 0xac, 0xf1, 0x68, 0x68, 0x96, 0xf2, - 0x76, 0xaf, 0xff, 0x78, 0xa9, 0xfe, 0x73, 0x3d, 0xf1, 0x0b, 0xe4, 0x95, - 0xb6, 0x1f, 0x07, 0xc2, 0xf2, 0x85, 0x8a, 0x95, 0x75, 0xb5, 0x76, 0xc9, - 0xef, 0x40, 0xec, 0x29, 0xd1, 0x7f, 0xed, 0xbc, 0x49, 0x8c, 0xee, 0xf2, - 0x63, 0xf4, 0x9f, 0x81, 0x56, 0xe6, 0x57, 0xff, 0xe6, 0xdd, 0x95, 0x08, - 0xbf, 0xe3, 0xe6, 0x41, 0xf9, 0x2c, 0x79, 0x44, 0xbc, 0x67, 0xdc, 0xb7, - 0x99, 0xf3, 0xe4, 0x43, 0x89, 0x36, 0xc9, 0x6f, 0xe7, 0x7a, 0xa4, 0x9f, - 0xa3, 0xef, 0x6a, 0xf6, 0xe9, 0x0e, 0x72, 0x24, 0xfe, 0xb5, 0x18, 0x60, - 0x19, 0x7d, 0x90, 0x0f, 0x95, 0xc8, 0xc7, 0xbb, 0xbe, 0x3d, 0x31, 0x57, - 0x90, 0x26, 0xcf, 0x37, 0x8c, 0x20, 0x17, 0xa0, 0x1d, 0x04, 0x3a, 0xa7, - 0xbe, 0x99, 0x23, 0x48, 0x4c, 0xb7, 0x99, 0x23, 0x88, 0x69, 0x24, 0x0e, - 0x6a, 0x2e, 0x74, 0xef, 0x42, 0xf7, 0x2e, 0x74, 0xef, 0x42, 0xf7, 0xc9, - 0xda, 0x71, 0xdc, 0x53, 0x79, 0x08, 0x68, 0xf1, 0xc6, 0x4f, 0x7b, 0xe3, - 0x83, 0xce, 0x9d, 0x92, 0x53, 0x3a, 0x21, 0xbf, 0xc8, 0x35, 0x94, 0xbf, - 0x1e, 0xd6, 0x3c, 0x7f, 0xcd, 0xf1, 0x32, 0x78, 0xfe, 0x7e, 0xe4, 0x73, - 0xae, 0xae, 0xdb, 0xd7, 0x65, 0x32, 0xd5, 0x20, 0x93, 0xc9, 0x2a, 0x65, - 0xc4, 0xfe, 0xf4, 0xb9, 0x13, 0xfa, 0xc2, 0xba, 0x5c, 0x46, 0x40, 0x43, - 0x0b, 0x79, 0xf7, 0xf9, 0xe0, 0xf8, 0x9d, 0xfe, 0xf8, 0xbf, 0x81, 0x31, - 0xe9, 0x5f, 0x6f, 0x34, 0x2f, 0xe7, 0x64, 0xce, 0xf8, 0x7e, 0xfc, 0x20, - 0x67, 0xc6, 0x1a, 0x78, 0x69, 0x3d, 0x9f, 0x8e, 0x21, 0x9f, 0x7e, 0x07, - 0xb9, 0x74, 0xbd, 0xce, 0x38, 0x55, 0x40, 0x9e, 0x9b, 0x76, 0xb8, 0xae, - 0x6f, 0x65, 0xdd, 0x6e, 0x58, 0xb3, 0x66, 0xd2, 0xe0, 0xb8, 0x61, 0xf1, - 0xc6, 0xe4, 0xfd, 0x16, 0xe4, 0x82, 0xef, 0xe0, 0x37, 0x7d, 0x72, 0x90, - 0xe7, 0xb1, 0x0f, 0x9f, 0x7f, 0x15, 0x73, 0xf7, 0x03, 0xcf, 0xf4, 0xca, - 0x77, 0x6a, 0xb6, 0x7c, 0x1b, 0x98, 0xe6, 0x5b, 0xc8, 0x2d, 0xbe, 0x59, - 0x0b, 0x72, 0xfb, 0xbd, 0x30, 0x75, 0xe6, 0xf7, 0x12, 0xde, 0x69, 0x13, - 0x57, 0xe5, 0xf7, 0x7f, 0xda, 0x96, 0xad, 0x11, 0xfc, 0xfe, 0x95, 0x84, - 0x6c, 0xeb, 0xc4, 0xf7, 0xf6, 0x04, 0x4c, 0x27, 0xc1, 0xd8, 0xa8, 0x35, - 0xc4, 0x46, 0xd1, 0xd2, 0xe0, 0x71, 0x0a, 0xe3, 0xa5, 0xc1, 0xf7, 0x67, - 0x6a, 0x61, 0x2d, 0x35, 0xbb, 0x1b, 0x98, 0x24, 0xc8, 0x71, 0x91, 0x47, - 0x99, 0xab, 0xdb, 0x43, 0xf2, 0x36, 0x78, 0x4a, 0x82, 0x76, 0x17, 0x39, - 0xc0, 0x3f, 0xc5, 0x5c, 0xd6, 0x4f, 0x3f, 0x2d, 0xff, 0xda, 0xcf, 0xc3, - 0x9b, 0x64, 0x4e, 0xf1, 0xc8, 0x76, 0xc9, 0xfc, 0xcb, 0x9e, 0xeb, 0xed, - 0xcf, 0xae, 0xb7, 0xc7, 0x32, 0xbf, 0xb1, 0xde, 0x7e, 0x35, 0xe4, 0xe1, - 0x95, 0x41, 0x6d, 0xb4, 0xf6, 0x2f, 0x8c, 0x00, 0xeb, 0x14, 0x66, 0x7b, - 0x31, 0xd7, 0x36, 0x99, 0xb4, 0xdf, 0x06, 0xf6, 0xb2, 0x63, 0x39, 0xac, - 0xaf, 0xa7, 0x36, 0xf9, 0xfa, 0x36, 0xf8, 0x8f, 0xd3, 0xb3, 0xd6, 0x20, - 0xfd, 0x47, 0x1c, 0x6b, 0x29, 0xf9, 0x1e, 0xff, 0xf1, 0x6d, 0xa3, 0xd1, - 0x7f, 0x18, 0xf0, 0x1f, 0xfb, 0xdf, 0xc7, 0x7f, 0x3c, 0xf5, 0x1e, 0xff, - 0xa1, 0xc1, 0x2e, 0xe8, 0x3f, 0x7e, 0x68, 0x04, 0xfe, 0xa3, 0xb0, 0xc1, - 0x7f, 0x04, 0xfa, 0xb0, 0x55, 0xee, 0xe8, 0xfd, 0x26, 0xfe, 0x6c, 0xf3, - 0x31, 0xa7, 0x84, 0x43, 0x09, 0x37, 0x33, 0x65, 0xef, 0x92, 0x26, 0xac, - 0xd1, 0x97, 0x6b, 0x03, 0xf0, 0x25, 0xbf, 0x0f, 0x9c, 0x66, 0x39, 0x4c, - 0x44, 0x9a, 0x12, 0xd4, 0xcd, 0x48, 0x2c, 0x69, 0xbf, 0x90, 0x59, 0xa8, - 0xbe, 0x90, 0x39, 0xa7, 0x74, 0x35, 0x61, 0x79, 0x18, 0xf8, 0x09, 0x0b, - 0x18, 0x18, 0xcf, 0x87, 0x80, 0x21, 0xd8, 0xde, 0x6e, 0x26, 0x91, 0xa3, - 0x54, 0xaa, 0x2b, 0x99, 0x02, 0x3e, 0x53, 0xaa, 0xef, 0x58, 0x8c, 0x7d, - 0x5b, 0x12, 0xe5, 0xd8, 0x9f, 0xe2, 0xbb, 0x39, 0x31, 0x67, 0x5d, 0xb6, - 0x39, 0xee, 0x6b, 0xb1, 0x73, 0x6a, 0x8c, 0x90, 0x14, 0xd4, 0xb3, 0x5f, - 0xb5, 0xf8, 0xec, 0x29, 0xf8, 0xf8, 0x93, 0x55, 0x53, 0x4e, 0x54, 0xd7, - 0x32, 0x39, 0x7c, 0x88, 0x6d, 0x5e, 0x2e, 0xf1, 0xfe, 0xb7, 0x70, 0x3f, - 0x24, 0xcc, 0x3d, 0x3e, 0x8f, 0x3e, 0x47, 0xd1, 0xe7, 0x48, 0x35, 0xc0, - 0x8d, 0xbc, 0xef, 0x66, 0x52, 0xb8, 0x7f, 0xa4, 0xe8, 0x66, 0xd2, 0x45, - 0xe6, 0x39, 0x7d, 0xd1, 0x13, 0x90, 0x67, 0x16, 0xb1, 0xdd, 0x15, 0xab, - 0x37, 0x2f, 0x8f, 0xb5, 0x0e, 0x23, 0xaf, 0x3e, 0x8f, 0x98, 0xe3, 0x8e, - 0x59, 0x4e, 0x19, 0xcc, 0x4d, 0x95, 0xee, 0x90, 0xc2, 0x0c, 0x62, 0x8c, - 0x73, 0x0f, 0x73, 0xed, 0x8c, 0x1e, 0x77, 0xe0, 0x13, 0x06, 0x80, 0x27, - 0xbb, 0x81, 0x85, 0xef, 0x92, 0x15, 0xd3, 0x8a, 0x0e, 0x03, 0x03, 0xa7, - 0x42, 0xe8, 0xd3, 0x7b, 0x9b, 0x64, 0xa3, 0x94, 0xf5, 0x0e, 0xf8, 0x07, - 0x4d, 0x5a, 0xec, 0x46, 0x5f, 0xf5, 0x17, 0x10, 0x2f, 0x92, 0xdf, 0x36, - 0xb6, 0xb7, 0xfa, 0x3a, 0xd9, 0x22, 0xab, 0xef, 0xe9, 0xf7, 0x37, 0x0d, - 0xfd, 0x1a, 0xdb, 0x35, 0x4d, 0xd0, 0x7f, 0x0d, 0x34, 0x84, 0xe2, 0x90, - 0x3f, 0x78, 0x68, 0x82, 0x9d, 0x5c, 0x06, 0x3f, 0xf4, 0x9b, 0x85, 0x32, - 0xe3, 0xa4, 0x21, 0x65, 0x13, 0xf7, 0xaa, 0xf5, 0xfa, 0x82, 0x0d, 0x5a, - 0x2f, 0x90, 0xde, 0xb0, 0x0c, 0x57, 0x7b, 0xc4, 0x5d, 0xa4, 0x1c, 0x2c, - 0xac, 0x8e, 0x5d, 0x6d, 0xa9, 0x79, 0xcb, 0xcd, 0x63, 0x44, 0xe3, 0x42, - 0x57, 0x5b, 0x12, 0x71, 0x51, 0xbf, 0x10, 0x6b, 0x4b, 0xc1, 0x1f, 0x18, - 0x17, 0x6e, 0x6f, 0x4b, 0xcf, 0x92, 0x2e, 0x03, 0x71, 0xf1, 0x4e, 0xe0, - 0xc2, 0xba, 0x7c, 0x0d, 0xb9, 0x4f, 0xa1, 0x17, 0x31, 0x03, 0xab, 0x44, - 0x07, 0xdd, 0x79, 0x53, 0xc2, 0x6d, 0x89, 0x79, 0xd0, 0xd7, 0xdf, 0x9a, - 0x9c, 0xdd, 0x82, 0x3e, 0x06, 0xda, 0x7b, 0x88, 0x21, 0x1b, 0xda, 0xed, - 0x36, 0xf8, 0x5f, 0xf8, 0x3a, 0x09, 0x27, 0x07, 0xda, 0x31, 0xfe, 0xd9, - 0x10, 0x73, 0x87, 0x70, 0x7c, 0xbd, 0xfd, 0xcb, 0x5e, 0x7b, 0x2f, 0x68, - 0xe1, 0x73, 0xcc, 0x21, 0x25, 0x3c, 0x3e, 0x60, 0x82, 0x06, 0xf6, 0x8d, - 0xa8, 0xbe, 0xe9, 0x79, 0xda, 0x80, 0x9b, 0x59, 0xb0, 0x77, 0x4b, 0x6a, - 0x6e, 0xa7, 0x0c, 0xcf, 0x75, 0xca, 0xfe, 0x39, 0xe6, 0xbc, 0xc4, 0xc0, - 0x60, 0x05, 0x39, 0xa9, 0x7e, 0x81, 0xb9, 0x80, 0x15, 0x3d, 0x2a, 0xdd, - 0xd1, 0xcf, 0x63, 0x1d, 0x8c, 0xdb, 0xf1, 0xd8, 0x24, 0xd6, 0x58, 0x48, - 0x8d, 0x13, 0x0d, 0xe6, 0xa4, 0x8d, 0x6e, 0x98, 0x37, 0x3d, 0x7f, 0xb3, - 0x71, 0xb1, 0x70, 0x2e, 0x44, 0x37, 0x8d, 0xfb, 0x3f, 0xfd, 0x71, 0x4d, - 0x8c, 0xdb, 0x85, 0x31, 0xc9, 0xe3, 0xed, 0xad, 0x43, 0xb3, 0xe2, 0xb6, - 0x80, 0xbe, 0x74, 0x7c, 0x97, 0x4c, 0x62, 0x9c, 0x93, 0x73, 0xf4, 0x85, - 0xb2, 0x13, 0x9f, 0xfe, 0x26, 0x89, 0xf7, 0x2e, 0x21, 0x2f, 0x1e, 0x52, - 0x63, 0x78, 0x39, 0xaa, 0x7e, 0x21, 0x01, 0x5c, 0xf3, 0x51, 0xd0, 0xc3, - 0x98, 0x4c, 0x9e, 0x43, 0xe0, 0x37, 0x81, 0x75, 0x48, 0x3c, 0xce, 0xf5, - 0x8d, 0xdf, 0x4b, 0xd1, 0xd6, 0xd4, 0x6c, 0x33, 0xd6, 0x9d, 0xec, 0x36, - 0x54, 0xac, 0xa0, 0x5e, 0xec, 0xd6, 0x64, 0x49, 0xd1, 0xdd, 0x9a, 0x2a, - 0x51, 0x46, 0x4e, 0x6b, 0xba, 0x44, 0x19, 0x09, 0xe8, 0x71, 0xe0, 0x63, - 0x43, 0x12, 0xdb, 0x4e, 0x3d, 0x1e, 0x43, 0xbf, 0x95, 0x10, 0xf3, 0xfe, - 0xa4, 0xcd, 0xdf, 0xc0, 0x2b, 0x17, 0x8e, 0xa3, 0x2f, 0x7f, 0xdf, 0x8b, - 0x71, 0xbb, 0x7b, 0x0b, 0xd2, 0xdc, 0x7b, 0x04, 0x7e, 0x42, 0x1f, 0x00, - 0xee, 0x50, 0x76, 0x5e, 0x07, 0x26, 0xdb, 0x0b, 0x7e, 0xb0, 0x36, 0xe2, - 0xb6, 0x4c, 0xcc, 0x50, 0xae, 0x72, 0x1b, 0x78, 0x00, 0xff, 0x71, 0xf8, - 0x16, 0xf2, 0xc0, 0xb9, 0x05, 0x76, 0xbf, 0x2c, 0xb9, 0x99, 0xb0, 0xc2, - 0x3e, 0xae, 0xc9, 0xf9, 0x35, 0x4d, 0x4f, 0xb4, 0x41, 0xc7, 0xe4, 0x6d, - 0x0a, 0xb4, 0x3d, 0x0e, 0x3f, 0x6c, 0xa9, 0x9c, 0xdb, 0x40, 0xff, 0x42, - 0x69, 0x50, 0x4f, 0x15, 0x49, 0xbf, 0x6f, 0x7b, 0xda, 0x0a, 0x7c, 0x8a, - 0xaa, 0x63, 0x21, 0xb7, 0x4b, 0xc0, 0x8f, 0x0c, 0xca, 0xf7, 0xe1, 0x4b, - 0xbe, 0x5b, 0x73, 0xe0, 0xff, 0xfb, 0xe1, 0xff, 0x7b, 0xe1, 0xff, 0x6d, - 0xf8, 0xff, 0x18, 0xfc, 0x7f, 0x17, 0xfc, 0x7f, 0x94, 0xbe, 0x5f, 0x4e, - 0xd6, 0xf2, 0xb0, 0xb1, 0x15, 0xf8, 0x41, 0x33, 0xec, 0xd6, 0x22, 0xe1, - 0x64, 0x2d, 0x1a, 0x4e, 0xd5, 0x42, 0xe0, 0xe9, 0x30, 0xe7, 0x04, 0x7f, - 0xf9, 0xd6, 0xa1, 0x52, 0x3f, 0xe2, 0x8a, 0x0b, 0xbf, 0x94, 0x86, 0xdf, - 0x77, 0x80, 0x7f, 0xf3, 0xb2, 0x3a, 0x13, 0xc3, 0x33, 0x75, 0x49, 0x3b, - 0x4d, 0x32, 0x69, 0x3a, 0x18, 0x63, 0xbb, 0xb2, 0x53, 0x23, 0xb1, 0xab, - 0x09, 0x76, 0x2a, 0xb9, 0x22, 0xe3, 0x73, 0x17, 0xc6, 0x6b, 0x45, 0x7c, - 0xa0, 0x7f, 0xa0, 0x2f, 0x58, 0xc9, 0x3c, 0x6c, 0x73, 0xcd, 0xb5, 0x69, - 0x49, 0xe0, 0x67, 0x62, 0x13, 0xc4, 0x3a, 0xd8, 0x05, 0xdb, 0xf6, 0xe0, - 0x39, 0xfe, 0xfe, 0x6f, 0x7e, 0x8d, 0xea, 0xaf, 0x5a, 0x04, 0xc6, 0xfb, - 0x32, 0x63, 0x8f, 0x8d, 0xf1, 0xaa, 0x8d, 0xeb, 0x75, 0x49, 0x17, 0x3b, - 0xb8, 0xcf, 0x7a, 0x0d, 0x6b, 0x54, 0xaf, 0x80, 0xde, 0x7a, 0x7d, 0x55, - 0x61, 0x48, 0xe4, 0x33, 0x87, 0xd6, 0xc0, 0x43, 0xe3, 0x33, 0xdf, 0xc0, - 0x33, 0xaa, 0x2d, 0x6c, 0x26, 0x1c, 0xe6, 0x50, 0xf0, 0x9b, 0x2f, 0xc0, - 0x47, 0x1e, 0xcb, 0xe8, 0xcb, 0x57, 0xf1, 0x2c, 0x64, 0x5a, 0x3c, 0x96, - 0x09, 0xf5, 0xbc, 0x5a, 0x7f, 0x16, 0x39, 0xf1, 0xd0, 0xf2, 0x80, 0xa4, - 0x96, 0xbb, 0xa3, 0x17, 0xa5, 0xf5, 0x1d, 0x17, 0xb1, 0x74, 0xb2, 0x6a, - 0x9d, 0x76, 0x85, 0x39, 0xba, 0x29, 0x0b, 0xc0, 0xd5, 0x7b, 0xf6, 0x3d, - 0x0f, 0xda, 0xad, 0x17, 0x45, 0x8f, 0xe1, 0x37, 0x31, 0x0c, 0x79, 0x5c, - 0x03, 0x7f, 0x1a, 0xae, 0x5b, 0xd6, 0x6b, 0x57, 0x85, 0x12, 0xf8, 0xac, - 0x1d, 0xcb, 0x5c, 0x9c, 0x06, 0xae, 0x83, 0x3e, 0x92, 0xd3, 0xc4, 0x9c, - 0x5b, 0x20, 0x93, 0x21, 0xd8, 0x05, 0xf5, 0x1d, 0xc7, 0xb3, 0x75, 0xf9, - 0x92, 0x43, 0x1b, 0x78, 0x0e, 0x72, 0xc3, 0x58, 0xa1, 0x80, 0x6e, 0x60, - 0x80, 0x19, 0xca, 0x6a, 0x17, 0xf2, 0x36, 0x57, 0x06, 0xf6, 0x49, 0x78, - 0x47, 0x62, 0x73, 0x4e, 0x76, 0x2c, 0xb3, 0x3a, 0x8d, 0xf1, 0x7b, 0x80, - 0x79, 0x84, 0xb5, 0x19, 0xfa, 0x60, 0x81, 0xed, 0xec, 0x87, 0x7e, 0x98, - 0x7b, 0x33, 0x47, 0xa3, 0x6f, 0x3a, 0xa8, 0xa5, 0x2a, 0x65, 0x43, 0x3a, - 0x0e, 0x21, 0xb7, 0x71, 0x64, 0x71, 0x9a, 0x39, 0x1a, 0xf3, 0x99, 0x20, - 0x7f, 0xd1, 0x90, 0x4b, 0xa0, 0x7d, 0xf9, 0x25, 0xa5, 0x07, 0x03, 0xfa, - 0xca, 0xed, 0xbb, 0x9f, 0x7c, 0xcd, 0x18, 0x09, 0xf8, 0xbf, 0x01, 0xf2, - 0xa2, 0x68, 0x40, 0xce, 0xc6, 0x35, 0x17, 0x03, 0x5f, 0xf8, 0x5c, 0xcf, - 0xdd, 0xd4, 0xdf, 0x64, 0xe9, 0x04, 0xec, 0x58, 0xf2, 0x4d, 0x09, 0xf0, - 0x36, 0x80, 0xdf, 0x58, 0xf8, 0x27, 0xa1, 0xc3, 0x73, 0x03, 0xac, 0x91, - 0x3d, 0x07, 0xfc, 0x47, 0xfa, 0xe3, 0xb1, 0x13, 0x6a, 0xdd, 0xe2, 0xba, - 0xca, 0x3c, 0x62, 0x8b, 0x5c, 0x54, 0x7c, 0xde, 0xc1, 0xfc, 0x14, 0x7a, - 0xb9, 0x15, 0x3e, 0x87, 0x3f, 0x24, 0x9f, 0xde, 0x3c, 0x8c, 0x5b, 0x49, - 0x3b, 0x26, 0xa9, 0xe2, 0xcb, 0x75, 0xaf, 0x0e, 0xfb, 0x47, 0xb0, 0x2b, - 0x5c, 0x57, 0xc3, 0xa0, 0x87, 0x75, 0x99, 0x01, 0xa5, 0x5b, 0xd0, 0x43, - 0x9b, 0xc9, 0x87, 0x13, 0xdb, 0xe4, 0xfc, 0x4c, 0x87, 0x2c, 0xcc, 0xbc, - 0x26, 0x95, 0x99, 0x36, 0x59, 0x9a, 0xa9, 0xcb, 0x65, 0x47, 0xf9, 0x25, - 0xbb, 0x59, 0xad, 0x69, 0xd9, 0xe5, 0x61, 0xf6, 0xf8, 0xe0, 0x15, 0x79, - 0x5a, 0xce, 0x97, 0x3d, 0x1e, 0x32, 0x0d, 0x3c, 0xbc, 0x0a, 0x1b, 0xeb, - 0xec, 0x21, 0x0f, 0xb4, 0x07, 0xf2, 0xc3, 0xdc, 0x83, 0x39, 0xe6, 0x41, - 0xac, 0xa3, 0x11, 0x60, 0xa3, 0x83, 0x5a, 0xd2, 0xe7, 0x21, 0xe5, 0xf1, - 0x90, 0x7d, 0x2f, 0x0f, 0x2d, 0x92, 0xdd, 0x49, 0x3e, 0xa0, 0x83, 0x69, - 0xea, 0x25, 0xc0, 0x1b, 0x1e, 0xfd, 0xc9, 0xe5, 0x57, 0xeb, 0xfa, 0x74, - 0x93, 0xa2, 0xdd, 0x48, 0x0c, 0xc0, 0xae, 0x5e, 0xad, 0xcb, 0x32, 0xd7, - 0x12, 0x7e, 0x57, 0xff, 0x31, 0xfc, 0x55, 0xa7, 0xca, 0x5b, 0x72, 0x63, - 0xed, 0xad, 0xc9, 0xf9, 0x41, 0xe8, 0xba, 0x55, 0xad, 0x45, 0xb8, 0x0e, - 0xe8, 0xf0, 0x0f, 0xd1, 0xff, 0xab, 0x5c, 0x73, 0x4a, 0x3e, 0x69, 0xc8, - 0xa7, 0x50, 0xbc, 0xbd, 0x19, 0x39, 0x37, 0xe6, 0x71, 0x33, 0xd9, 0x2a, - 0x9f, 0xe9, 0x82, 0x7f, 0xe3, 0xf7, 0x07, 0xb6, 0x8f, 0x3c, 0xfc, 0x2e, - 0x6c, 0x00, 0xb9, 0x05, 0xd7, 0xf4, 0xc0, 0x0a, 0xe2, 0x6c, 0xbc, 0x77, - 0x41, 0xd5, 0xf4, 0x1d, 0x85, 0x9f, 0x26, 0xab, 0x5f, 0xc5, 0xc7, 0x9b, - 0x6f, 0xa8, 0xc6, 0x39, 0x37, 0xf2, 0x84, 0x9c, 0x06, 0xb9, 0xa4, 0x8d, - 0x71, 0x39, 0x6f, 0x5e, 0x8c, 0x84, 0x81, 0x79, 0xd9, 0xd6, 0x0e, 0x3f, - 0x13, 0x83, 0xdf, 0xea, 0x87, 0xff, 0xe7, 0x5a, 0xa6, 0xaf, 0x0f, 0x68, - 0xef, 0xc7, 0x98, 0xf4, 0xc1, 0xfd, 0xe0, 0x99, 0xb9, 0x34, 0x7d, 0x28, - 0x62, 0xca, 0x62, 0xb4, 0x2d, 0x39, 0xeb, 0xd5, 0x93, 0xbc, 0xdf, 0xbc, - 0x2f, 0xe1, 0xdd, 0x09, 0xab, 0x9c, 0x47, 0xfe, 0x97, 0xc2, 0xda, 0x4d, - 0xda, 0xc8, 0xa7, 0x17, 0xad, 0x17, 0x88, 0xd3, 0x74, 0xca, 0x60, 0x99, - 0x72, 0x62, 0x6d, 0xc3, 0x94, 0xfc, 0xc2, 0xef, 0x42, 0x1e, 0x61, 0xd9, - 0x6e, 0x67, 0xe1, 0x53, 0x98, 0xb7, 0xb8, 0xe0, 0x8d, 0xbe, 0xa7, 0x1b, - 0xb1, 0xcc, 0x80, 0x10, 0x90, 0x57, 0x2d, 0x1b, 0xf2, 0x40, 0xa8, 0x0f, - 0x79, 0xe0, 0xa7, 0xd0, 0x37, 0x24, 0xf9, 0x65, 0xc6, 0x84, 0x90, 0x4c, - 0x2d, 0x8b, 0x5c, 0x99, 0xa6, 0x5f, 0x51, 0x7f, 0x90, 0xb9, 0x9b, 0x99, - 0x20, 0x3e, 0x9b, 0xa1, 0x8f, 0xa1, 0xff, 0xd8, 0x01, 0x5d, 0xc4, 0x9f, - 0xfb, 0x12, 0xe2, 0xd3, 0x64, 0xb1, 0x1b, 0x7e, 0x53, 0x56, 0x74, 0xc8, - 0x14, 0x71, 0x8d, 0xf5, 0xaa, 0x1b, 0xd4, 0xaa, 0x82, 0x3a, 0x55, 0x58, - 0x0a, 0xd3, 0xac, 0x51, 0x85, 0x41, 0x0b, 0x73, 0x57, 0x43, 0xe5, 0x42, - 0x3b, 0x94, 0x7f, 0xe5, 0x77, 0xa8, 0x61, 0xde, 0xf8, 0xe9, 0x3d, 0x3a, - 0xfd, 0xd8, 0x6e, 0x71, 0x47, 0x8f, 0xb5, 0xee, 0x2f, 0x01, 0x8b, 0x76, - 0xd2, 0x3e, 0xa9, 0xff, 0xac, 0x4e, 0x7f, 0x3b, 0x55, 0x1a, 0xc0, 0x78, - 0xc4, 0x95, 0x21, 0xf4, 0x8b, 0xf8, 0xfd, 0x28, 0xd7, 0x7f, 0x25, 0xe3, - 0xfb, 0xfe, 0x1a, 0x74, 0x79, 0xfe, 0x8e, 0x75, 0xee, 0xdc, 0x67, 0x74, - 0xb9, 0xef, 0x63, 0x69, 0x3c, 0xcb, 0x78, 0xf8, 0xb6, 0x8f, 0xe1, 0xd8, - 0xc6, 0xba, 0x1e, 0x72, 0xf5, 0xf3, 0x26, 0xbe, 0x3b, 0x25, 0x7f, 0x3e, - 0x0c, 0x39, 0x20, 0x2f, 0x5e, 0xf0, 0xc6, 0x62, 0xee, 0x7b, 0x1a, 0x3a, - 0xd2, 0xcf, 0x84, 0xa5, 0xe9, 0x4c, 0xa7, 0x84, 0xbe, 0xd2, 0x26, 0xcd, - 0x5f, 0xe9, 0x11, 0xe3, 0x2b, 0xac, 0x3f, 0x58, 0xb1, 0x93, 0xaa, 0xf6, - 0x91, 0x96, 0x53, 0x88, 0x61, 0x3a, 0xe2, 0xb1, 0xb2, 0x53, 0x73, 0xa7, - 0x18, 0x48, 0x5e, 0xf5, 0x67, 0x5c, 0xf9, 0xe2, 0xbe, 0x9f, 0xab, 0xda, - 0x1b, 0x70, 0xb3, 0xe8, 0xcf, 0x67, 0xc4, 0xad, 0xbd, 0x46, 0x3b, 0xcd, - 0xbc, 0x7a, 0xd7, 0x1d, 0xd0, 0x39, 0x73, 0xcb, 0x5e, 0x55, 0xc7, 0xfd, - 0xe2, 0x3e, 0xc6, 0x4c, 0x2f, 0xbf, 0x4c, 0x23, 0xbf, 0x9c, 0x94, 0x6e, - 0xf8, 0x59, 0xf6, 0xdb, 0x29, 0x3a, 0xe6, 0xca, 0x09, 0xf3, 0xf5, 0x3b, - 0xc5, 0x3d, 0x8c, 0x75, 0x71, 0x56, 0x66, 0xf4, 0x84, 0xa6, 0xc6, 0x34, - 0x9e, 0xa1, 0xdf, 0xa2, 0x3f, 0xa3, 0x8d, 0xb3, 0x0e, 0x82, 0xb6, 0xe7, - 0xe9, 0xb3, 0x3c, 0xdb, 0x1e, 0x6a, 0xf0, 0x7d, 0x53, 0xa5, 0x1a, 0x74, - 0x88, 0xbc, 0xde, 0x6e, 0x02, 0xff, 0x88, 0xeb, 0x36, 0xaf, 0xc9, 0x3f, - 0x7c, 0x69, 0x24, 0xa2, 0xae, 0x0b, 0x65, 0x0f, 0xf7, 0x7a, 0xe3, 0x33, - 0x07, 0x81, 0xaf, 0xa9, 0x91, 0x0e, 0xce, 0xdb, 0x25, 0xc6, 0xd9, 0x88, - 0x84, 0xce, 0xd2, 0xfe, 0xac, 0x58, 0x1a, 0xf2, 0x9b, 0xb2, 0x89, 0xf5, - 0x0e, 0xc0, 0x17, 0xec, 0x16, 0xfd, 0x7c, 0x2f, 0xd6, 0x8e, 0x15, 0x2d, - 0x4b, 0x5c, 0x8c, 0x85, 0xb0, 0xbc, 0x09, 0xdf, 0x41, 0x7b, 0x39, 0x87, - 0x78, 0x75, 0xa2, 0xd6, 0xfa, 0xce, 0x8a, 0xa2, 0x82, 0x6d, 0x43, 0xc0, - 0x4b, 0x56, 0xaf, 0xab, 0xb7, 0xcb, 0xeb, 0xd0, 0x77, 0x56, 0xb5, 0xed, - 0xc6, 0xb8, 0xa0, 0xe1, 0x2c, 0xeb, 0x49, 0x1c, 0xf7, 0x1f, 0x60, 0x4c, - 0x8e, 0xed, 0x66, 0x56, 0x99, 0x9f, 0x4e, 0xd3, 0x76, 0x3b, 0x61, 0x77, - 0xb8, 0xae, 0x35, 0x4b, 0x76, 0x2c, 0x26, 0xfa, 0xf4, 0x83, 0xd2, 0xbd, - 0x4f, 0xf7, 0xf8, 0x51, 0x3c, 0xb2, 0x8d, 0x75, 0xca, 0x16, 0xb5, 0x1e, - 0xf5, 0x65, 0xd8, 0xcc, 0x41, 0xea, 0x18, 0xf1, 0x1f, 0xf1, 0x8d, 0xfe, - 0xcc, 0x40, 0x7c, 0x4b, 0xd5, 0x3c, 0xbd, 0x97, 0x0f, 0xee, 0x94, 0x53, - 0x67, 0x69, 0x4f, 0xb8, 0xb7, 0x6e, 0x53, 0xc1, 0x7e, 0x02, 0xef, 0xd9, - 0x72, 0xfa, 0x59, 0xe6, 0x1f, 0xcc, 0x3b, 0x98, 0x6b, 0x59, 0xd1, 0xfd, - 0xe0, 0x47, 0xbf, 0x8f, 0xfe, 0x40, 0x57, 0xb6, 0x9b, 0x83, 0xaf, 0x2e, - 0xd4, 0xa8, 0xb7, 0x7e, 0xee, 0xb9, 0x98, 0xcc, 0xd9, 0xdc, 0xa8, 0x27, - 0xef, 0x02, 0xda, 0x26, 0x11, 0x07, 0x52, 0xd5, 0x26, 0x59, 0x1b, 0x73, - 0xa1, 0xfb, 0x8f, 0x82, 0xae, 0xc3, 0xad, 0xc4, 0xab, 0x6b, 0x63, 0x69, - 0x5c, 0x1f, 0x56, 0x79, 0x9a, 0x71, 0x9f, 0x8b, 0x31, 0x76, 0x72, 0x1d, - 0xf9, 0x7a, 0x72, 0xf4, 0xc2, 0xcc, 0x7d, 0xfa, 0x24, 0x7c, 0xf7, 0xb0, - 0xc3, 0x18, 0xcf, 0xfa, 0x73, 0x0b, 0xe8, 0x68, 0x57, 0xd8, 0x42, 0xb7, - 0xf7, 0xe9, 0x85, 0x32, 0xfd, 0x7d, 0x3e, 0xda, 0x2c, 0x0e, 0x7d, 0x96, - 0xbe, 0x60, 0x53, 0x27, 0x9a, 0x5c, 0x54, 0xb5, 0x6a, 0x44, 0xa0, 0x6a, - 0x0a, 0x73, 0x39, 0x7a, 0xa5, 0xbc, 0x4f, 0xcf, 0xc3, 0x55, 0xaf, 0x45, - 0x48, 0x77, 0x4c, 0xe5, 0xf2, 0xfb, 0x94, 0xad, 0x15, 0x11, 0x53, 0x60, - 0x33, 0xce, 0x1d, 0x98, 0x57, 0xb5, 0xc1, 0xa6, 0xa8, 0x7b, 0xea, 0x5d, - 0xf9, 0x48, 0x5f, 0xf7, 0x37, 0x8a, 0xa1, 0x45, 0xf8, 0x5f, 0x62, 0xe9, - 0x16, 0xbf, 0x3e, 0xf5, 0xcf, 0xfd, 0x9c, 0xe8, 0x71, 0x61, 0x9e, 0x32, - 0x55, 0x22, 0x2d, 0x45, 0xf8, 0xc3, 0x1b, 0xd9, 0x12, 0xe5, 0xe8, 0xf9, - 0x94, 0x63, 0xb0, 0x0b, 0x7d, 0xd9, 0xf4, 0x6d, 0x40, 0xe1, 0x67, 0xdc, - 0x63, 0x0c, 0xc0, 0x77, 0xad, 0x09, 0xeb, 0x7d, 0x04, 0x32, 0xa2, 0x6e, - 0xa0, 0xbf, 0x65, 0xee, 0xd5, 0x41, 0x7f, 0xcb, 0x97, 0x7e, 0xe1, 0x76, - 0xd2, 0xe7, 0x0d, 0xc8, 0x29, 0xf8, 0xd1, 0x93, 0xf3, 0xa4, 0x27, 0xad, - 0xd6, 0xce, 0x14, 0xe4, 0x7d, 0x42, 0xf9, 0xf8, 0x7e, 0x79, 0x73, 0xf1, - 0x5b, 0x0a, 0x0b, 0xee, 0xd9, 0xb7, 0x22, 0x13, 0xf0, 0x0f, 0x47, 0xaa, - 0x90, 0xb7, 0x19, 0xc3, 0xfa, 0xdc, 0xa5, 0xfc, 0xe3, 0x17, 0x3f, 0x78, - 0xae, 0x12, 0xd2, 0x13, 0x0f, 0x7c, 0xc8, 0x18, 0xbe, 0x55, 0xdc, 0xce, - 0x0f, 0x3c, 0x8f, 0xa1, 0x27, 0xfe, 0x10, 0x3a, 0xfb, 0x4d, 0xcc, 0x15, - 0x06, 0x9d, 0x6a, 0x3f, 0xe4, 0x83, 0x3c, 0xa7, 0xeb, 0x89, 0x4f, 0x7e, - 0x48, 0xfa, 0x4c, 0x59, 0x04, 0x7e, 0xc8, 0xab, 0xb8, 0xca, 0xdc, 0xb1, - 0xc9, 0xd7, 0xe7, 0x0b, 0xc0, 0xd5, 0xc0, 0xd2, 0xc5, 0xc0, 0x17, 0xb7, - 0x48, 0xbe, 0x33, 0xc8, 0x47, 0xe1, 0xc3, 0xd7, 0xdb, 0x83, 0x1c, 0x97, - 0xcf, 0x67, 0x33, 0xc8, 0xa9, 0x61, 0x13, 0xb7, 0x61, 0x8d, 0xb2, 0x4d, - 0xe5, 0xb0, 0x37, 0xa1, 0xdf, 0xa3, 0x3d, 0x57, 0x6c, 0xcc, 0x2d, 0x0e, - 0xa8, 0xdc, 0x62, 0x68, 0x43, 0x6e, 0x11, 0xd4, 0xb4, 0x02, 0xba, 0x39, - 0x2e, 0x70, 0x03, 0xec, 0xe0, 0xbb, 0x18, 0xff, 0x3b, 0xd0, 0xf7, 0xb7, - 0x4b, 0xc0, 0x0d, 0x25, 0xe0, 0x86, 0x12, 0x70, 0x43, 0x09, 0xb8, 0xa1, - 0x14, 0xf5, 0xeb, 0x5b, 0x2e, 0x71, 0xff, 0x07, 0xb4, 0xe9, 0xa0, 0xee, - 0xb1, 0xd9, 0x5e, 0xbd, 0x3a, 0x59, 0xaa, 0x16, 0xe0, 0xe7, 0x30, 0xeb, - 0x76, 0xc0, 0x71, 0x41, 0x4d, 0xc4, 0x8f, 0x1d, 0x8b, 0xdc, 0x43, 0x41, - 0xec, 0x58, 0x74, 0xb1, 0x9e, 0xfa, 0xa2, 0x06, 0x70, 0xa3, 0x21, 0x51, - 0xfc, 0x36, 0xe1, 0x93, 0xb9, 0x67, 0xde, 0x8d, 0x15, 0xd6, 0xac, 0x6a, - 0x4f, 0x27, 0x54, 0x4d, 0xc2, 0x96, 0xc9, 0x72, 0x90, 0xdb, 0xc5, 0x65, - 0x68, 0x86, 0x58, 0x54, 0xb6, 0xeb, 0x09, 0xe8, 0xa2, 0x4a, 0xfc, 0xc8, - 0x3d, 0x27, 0xce, 0x1f, 0xef, 0xad, 0x60, 0xce, 0x82, 0xed, 0xd1, 0x77, - 0xa2, 0xaa, 0xce, 0x05, 0xf8, 0xcf, 0x05, 0x67, 0x01, 0xe2, 0xb2, 0x7f, - 0x86, 0x7b, 0xef, 0x31, 0x19, 0x2d, 0x3a, 0xc8, 0x65, 0x55, 0x8e, 0x84, - 0x78, 0xe0, 0xc9, 0x7d, 0xc8, 0x97, 0x7b, 0x0e, 0xd8, 0x61, 0xdc, 0x0e, - 0xe4, 0x4e, 0x79, 0x8f, 0x68, 0xc3, 0x90, 0xf5, 0x7e, 0x5f, 0xd6, 0xe9, - 0x25, 0x31, 0x91, 0xff, 0xc4, 0x8c, 0x7d, 0x63, 0xda, 0x68, 0x4d, 0x61, - 0x16, 0xfa, 0x23, 0x8c, 0xe5, 0x78, 0x6b, 0x1d, 0xf6, 0x92, 0xab, 0x6e, - 0xde, 0x8f, 0x6f, 0xc4, 0x2f, 0x9f, 0xd5, 0xc4, 0x0e, 0xe4, 0xd8, 0xd8, - 0x3e, 0xd1, 0xd0, 0xbe, 0x7e, 0xdf, 0xe7, 0x01, 0xbe, 0x72, 0xbd, 0x3e, - 0x41, 0xbf, 0x76, 0xbd, 0x1d, 0x78, 0x4f, 0x42, 0xea, 0x3e, 0x7c, 0xfe, - 0x62, 0x44, 0x52, 0x8b, 0xb6, 0xa4, 0xcb, 0xec, 0xc7, 0x9a, 0x07, 0xfd, - 0xd7, 0x1f, 0x4b, 0x0a, 0x79, 0x6e, 0x36, 0x62, 0x39, 0xae, 0xfc, 0x47, - 0x59, 0x9d, 0xcb, 0xc7, 0xb8, 0x77, 0x9d, 0x1f, 0xd5, 0xf0, 0xdc, 0x8f, - 0x71, 0x4d, 0xda, 0x6d, 0xac, 0x0f, 0xc6, 0xa9, 0xbe, 0xe8, 0x22, 0xee, - 0x65, 0xc7, 0x58, 0xe7, 0x79, 0x2a, 0x2c, 0x6d, 0x56, 0xac, 0x0c, 0x3b, - 0xb8, 0x54, 0xe4, 0x7c, 0xc0, 0x52, 0x45, 0xd6, 0x82, 0x82, 0xfb, 0x7f, - 0x0c, 0xec, 0xa8, 0x13, 0x3b, 0x79, 0x7d, 0x94, 0xbe, 0x5c, 0x33, 0x84, - 0x35, 0xb0, 0xe2, 0xfb, 0xe7, 0x85, 0xa2, 0x57, 0x7b, 0x39, 0x47, 0x3a, - 0xaa, 0x7f, 0x53, 0x5f, 0x89, 0x20, 0x67, 0x5a, 0xe7, 0xf1, 0x1c, 0xc7, - 0x37, 0xe1, 0x9e, 0xe5, 0x64, 0x35, 0x90, 0x05, 0xef, 0xb3, 0x8d, 0xfb, - 0xf3, 0xf5, 0xfa, 0x39, 0xfb, 0xc3, 0xd6, 0xd9, 0x9e, 0xbb, 0x27, 0x69, - 0xcb, 0x81, 0x85, 0xaa, 0x1c, 0xf0, 0xea, 0x6c, 0xd1, 0xbd, 0x5e, 0x9d, - 0x2d, 0xb6, 0x77, 0x63, 0x9d, 0xad, 0x7c, 0x8f, 0x57, 0x67, 0x33, 0x0f, - 0xc0, 0x07, 0x1f, 0xf0, 0xea, 0x6c, 0xff, 0xf5, 0x1e, 0xaf, 0xce, 0xd6, - 0x75, 0xaf, 0x57, 0x67, 0xeb, 0xdd, 0xeb, 0xd5, 0xd9, 0x46, 0xef, 0xdd, - 0x58, 0x67, 0x73, 0xf6, 0x6e, 0xac, 0xb3, 0x39, 0x07, 0x72, 0xf8, 0x5c, - 0xaf, 0xb3, 0x65, 0xf6, 0xde, 0xbc, 0xce, 0xf6, 0x4a, 0x80, 0xf1, 0xc1, - 0xcf, 0x00, 0x78, 0x70, 0x80, 0xf1, 0xfb, 0x81, 0xf1, 0x6f, 0x56, 0xe3, - 0x55, 0xe7, 0x37, 0xc0, 0xa7, 0xe6, 0xc7, 0x8f, 0x0f, 0x83, 0xf5, 0xb7, - 0xfa, 0xcf, 0xba, 0xc8, 0x8f, 0x63, 0x7e, 0x6e, 0x43, 0xbc, 0xbf, 0xcd, - 0xcf, 0xf1, 0xba, 0x5a, 0xaf, 0x9f, 0xad, 0x68, 0xfc, 0xbe, 0x0d, 0xa9, - 0x7a, 0x50, 0x03, 0x20, 0x5f, 0x72, 0xe0, 0x61, 0x25, 0x87, 0x3b, 0xd1, - 0xdf, 0x3c, 0xf0, 0x25, 0x9b, 0x75, 0x81, 0x27, 0xb1, 0x86, 0xdd, 0xed, - 0x86, 0xda, 0x67, 0x66, 0x4c, 0x3b, 0x2d, 0x29, 0xf4, 0x4f, 0xa9, 0xfe, - 0xa3, 0x0d, 0xfd, 0xb3, 0xe8, 0xcf, 0x71, 0xad, 0x7f, 0x8b, 0xcf, 0x73, - 0xca, 0xbe, 0x6d, 0x0f, 0xf7, 0xa7, 0x4b, 0x01, 0x4e, 0x0b, 0xf9, 0x18, - 0xdc, 0xcd, 0xb8, 0xd5, 0x7b, 0xf1, 0x8c, 0xf5, 0xa2, 0x2b, 0x57, 0x15, - 0xde, 0x37, 0x12, 0xd6, 0x8b, 0x59, 0x95, 0xdf, 0xb9, 0x99, 0x5c, 0x75, - 0x3d, 0x5f, 0x07, 0x0e, 0x63, 0xce, 0x03, 0x7b, 0x5f, 0xee, 0x45, 0xdc, - 0x6b, 0xcc, 0xc9, 0x99, 0x87, 0xeb, 0x7e, 0x1e, 0x6e, 0xca, 0xfd, 0xfb, - 0x1a, 0x31, 0xbe, 0x73, 0xe0, 0xef, 0x2b, 0x8c, 0xbf, 0x05, 0xb9, 0x3c, - 0x31, 0x3c, 0x71, 0x0f, 0x31, 0x07, 0x71, 0x3e, 0xeb, 0x0b, 0xcc, 0x7f, - 0x18, 0x4b, 0x99, 0x0f, 0x45, 0xf0, 0xe1, 0xb9, 0x97, 0x00, 0xeb, 0x37, - 0xfb, 0xfe, 0x9f, 0x79, 0x54, 0x80, 0x6d, 0xac, 0x2d, 0x5e, 0x2e, 0xb5, - 0x45, 0xf3, 0xf2, 0xd5, 0x98, 0xdf, 0x27, 0xb4, 0x8e, 0xa5, 0x43, 0xeb, - 0x58, 0x7a, 0xc3, 0x5e, 0x89, 0xa8, 0x33, 0x36, 0x6a, 0xcf, 0x85, 0x7b, - 0x30, 0x6e, 0xe6, 0x52, 0x0f, 0xf1, 0x30, 0xf7, 0x62, 0x80, 0x8d, 0xec, - 0xc6, 0x58, 0xc5, 0x38, 0x45, 0x3c, 0x15, 0xec, 0xb7, 0x06, 0x7a, 0xa2, - 0xec, 0xd8, 0xf6, 0x47, 0x1a, 0x72, 0x64, 0xa7, 0xd9, 0xde, 0x0f, 0x5a, - 0x32, 0xf8, 0x0e, 0x64, 0xfa, 0x80, 0x8a, 0x91, 0x2d, 0xb0, 0xdd, 0x13, - 0x25, 0x62, 0xde, 0x6d, 0xb2, 0xe8, 0xe3, 0xde, 0xf3, 0x33, 0x1e, 0xe6, - 0x0d, 0x6d, 0xc4, 0xbc, 0xce, 0xaa, 0x78, 0x34, 0xee, 0xbf, 0x21, 0x8d, - 0xc4, 0xb7, 0xa4, 0x8f, 0x31, 0x89, 0xfe, 0xd1, 0xcd, 0x5c, 0xee, 0x61, - 0x3c, 0x62, 0x2c, 0x8a, 0xc9, 0xea, 0x4d, 0xe9, 0x53, 0x6d, 0xc7, 0x5a, - 0xec, 0x30, 0x3e, 0x13, 0xf0, 0x1f, 0xa3, 0x78, 0x26, 0x23, 0x93, 0xb3, - 0x5f, 0x00, 0x6f, 0x13, 0x72, 0x69, 0x66, 0x0c, 0xf4, 0x3d, 0x29, 0x53, - 0x4e, 0x1e, 0x7e, 0x84, 0x7b, 0x21, 0xc4, 0x79, 0xdd, 0xfe, 0xf7, 0x84, - 0x7e, 0xce, 0xb6, 0x88, 0x33, 0xa5, 0x52, 0xa4, 0x0f, 0xe6, 0xbe, 0x14, - 0xf7, 0x1f, 0x69, 0x3f, 0xac, 0xc3, 0x20, 0xd7, 0x65, 0xce, 0x3b, 0xcd, - 0xf9, 0x37, 0xea, 0x64, 0xb5, 0x4a, 0xbc, 0xe6, 0x66, 0x56, 0x96, 0x89, - 0x37, 0x3f, 0x28, 0xf6, 0xa4, 0x1e, 0x88, 0x3f, 0x6f, 0x05, 0x77, 0x5a, - 0x33, 0xc0, 0x9c, 0x2f, 0xac, 0xe8, 0x8d, 0xb8, 0xd3, 0xc3, 0x9c, 0xc9, - 0xe5, 0x2c, 0xc6, 0x74, 0x14, 0xb6, 0x46, 0xde, 0x07, 0xb7, 0xd7, 0x8d, - 0x67, 0xbb, 0x91, 0xc3, 0x7b, 0x18, 0x33, 0x05, 0x8c, 0xf9, 0x0f, 0x81, - 0x31, 0x27, 0xe5, 0xad, 0x56, 0x62, 0x4c, 0xd7, 0xc7, 0x98, 0x69, 0xd8, - 0x73, 0x6e, 0x83, 0x3d, 0x6b, 0xaa, 0x76, 0xc5, 0x7b, 0x39, 0x60, 0xc4, - 0xd4, 0xb4, 0x75, 0x0b, 0xb8, 0x52, 0x93, 0x88, 0x3a, 0xfb, 0x10, 0x6a, - 0x18, 0x33, 0xc0, 0x8f, 0x7b, 0x14, 0x2e, 0x3c, 0x50, 0xda, 0x82, 0x1c, - 0x46, 0xe1, 0x44, 0x7f, 0x4f, 0x2e, 0xb4, 0x69, 0x9f, 0x32, 0xd4, 0xb0, - 0x4f, 0x79, 0x1d, 0x4f, 0xe2, 0x39, 0xbf, 0x3e, 0xd8, 0x04, 0x5f, 0xf0, - 0x7f, 0x40, 0x13, 0xd7, 0x17, 0xd7, 0x82, 0xe6, 0xad, 0x97, 0xd1, 0x46, - 0x5c, 0xf9, 0xbf, 0x36, 0xe1, 0x4a, 0xc4, 0xae, 0xf3, 0x11, 0x49, 0x02, - 0x53, 0xba, 0xcb, 0x1c, 0x8b, 0x6b, 0xba, 0x5f, 0x9a, 0xc1, 0x5f, 0xcb, - 0x74, 0x27, 0xb0, 0x54, 0x9b, 0x84, 0x81, 0xa9, 0x9a, 0x14, 0xa6, 0xea, - 0x21, 0xf6, 0xe9, 0x3d, 0x02, 0x2c, 0xb4, 0xb8, 0x8e, 0xab, 0x2c, 0xe7, - 0x87, 0xd0, 0xcb, 0xa3, 0xca, 0xf7, 0xa4, 0xe5, 0x29, 0xf8, 0xd2, 0xe6, - 0x65, 0xe0, 0xc1, 0xf3, 0x1e, 0xde, 0x6a, 0xda, 0x84, 0xb7, 0x8e, 0xde, - 0x10, 0x6f, 0xa9, 0x9a, 0xff, 0x20, 0x65, 0xf2, 0x7a, 0xd5, 0xab, 0xf9, - 0x5f, 0xa9, 0x7a, 0x35, 0xff, 0xd7, 0xab, 0x8d, 0x35, 0xff, 0x8f, 0x48, - 0xc1, 0xb4, 0xdc, 0x35, 0xd9, 0x54, 0xf3, 0x1f, 0x65, 0x0d, 0xfd, 0xf7, - 0xda, 0xbc, 0xda, 0x7e, 0x9b, 0x5f, 0xf3, 0xb7, 0xa4, 0xb0, 0xa1, 0xdd, - 0x94, 0xb7, 0xec, 0xa0, 0xe6, 0xff, 0x34, 0xda, 0xda, 0x31, 0xc7, 0xc6, - 0x7a, 0xff, 0x95, 0x2a, 0xeb, 0xfd, 0x11, 0xf6, 0xf3, 0xeb, 0xfd, 0xec, - 0x87, 0xdc, 0xbf, 0xca, 0x5a, 0xff, 0x6e, 0xc8, 0x62, 0x27, 0xe4, 0xd0, - 0x29, 0xcd, 0x67, 0xa3, 0xec, 0xa3, 0x6a, 0xfc, 0x6b, 0xc8, 0x37, 0xae, - 0x54, 0xbd, 0x5a, 0xfc, 0x11, 0xd8, 0xd5, 0xd1, 0xf5, 0x1a, 0xbf, 0x37, - 0xc7, 0xd5, 0xea, 0xc6, 0xf1, 0x37, 0x8e, 0xd3, 0xe5, 0x8f, 0x13, 0xc1, - 0x38, 0xd1, 0x4d, 0xe3, 0x5c, 0xaf, 0xe9, 0x5f, 0xad, 0x7a, 0xf5, 0xfc, - 0xf4, 0xac, 0xb8, 0xcd, 0xf0, 0xcd, 0x2f, 0xf6, 0xec, 0xf2, 0xc7, 0x58, - 0xaf, 0xe7, 0xd3, 0x87, 0x00, 0xe7, 0xc7, 0xd5, 0xf9, 0x9e, 0x23, 0xff, - 0x1f, 0xea, 0xf9, 0xac, 0xe5, 0x7b, 0x7b, 0x32, 0x5c, 0x9f, 0xc0, 0xf3, - 0xcf, 0x7a, 0x75, 0xfc, 0xa1, 0x52, 0x50, 0x9f, 0x67, 0x5e, 0x19, 0x9c, - 0xbd, 0xe9, 0x8e, 0x9d, 0x10, 0xda, 0x0a, 0xe9, 0xe3, 0xb8, 0xed, 0x32, - 0xae, 0xf0, 0x14, 0x6c, 0x2a, 0x7e, 0x73, 0x4c, 0xbd, 0x30, 0x1d, 0x60, - 0xea, 0x88, 0xc2, 0xd4, 0x0b, 0xcb, 0x01, 0xa6, 0x4e, 0xde, 0x04, 0x53, - 0xff, 0xf7, 0x36, 0x2f, 0x0e, 0x84, 0x25, 0xaf, 0x30, 0xf5, 0xcd, 0xce, - 0x2b, 0xf1, 0x5e, 0x1b, 0xf1, 0x82, 0x78, 0x7b, 0xd8, 0x9d, 0x37, 0x59, - 0x6b, 0x01, 0xce, 0x66, 0xec, 0xdf, 0x29, 0xa3, 0x67, 0xaf, 0xe3, 0x6c, - 0x0f, 0x4b, 0x5b, 0xb1, 0x63, 0x2a, 0x26, 0x02, 0xd7, 0xd5, 0x58, 0x2f, - 0x27, 0x56, 0x66, 0xcc, 0x09, 0x29, 0x3c, 0x97, 0x2b, 0x32, 0x0f, 0x60, - 0x1b, 0xb1, 0x73, 0x2b, 0x8f, 0xf2, 0xf8, 0x31, 0x29, 0xc0, 0xa6, 0xc1, - 0xd9, 0x09, 0xee, 0x4b, 0xbc, 0x65, 0x24, 0x6d, 0xb4, 0x57, 0x83, 0x5c, - 0xc1, 0x51, 0x67, 0x4e, 0x92, 0xc0, 0x3f, 0xe3, 0xeb, 0xd8, 0x93, 0xbe, - 0xe2, 0x47, 0xbf, 0x70, 0x4d, 0xfa, 0xb5, 0x00, 0x5b, 0x22, 0x27, 0x2a, - 0x71, 0x6d, 0x07, 0xd8, 0xd2, 0xc3, 0x95, 0xa9, 0xea, 0x0a, 0xf0, 0x75, - 0x48, 0x86, 0x80, 0xeb, 0x57, 0x1e, 0x66, 0xcd, 0x2a, 0xc0, 0x4e, 0x2e, - 0xbe, 0x1b, 0x6b, 0x58, 0xbc, 0x6e, 0x56, 0x7b, 0x87, 0x17, 0x7b, 0xc2, - 0x0d, 0xed, 0xbf, 0x05, 0xff, 0x8d, 0xfc, 0x08, 0x98, 0xc5, 0xc3, 0x4c, - 0x7b, 0xa1, 0x83, 0x01, 0x85, 0x99, 0xa6, 0xde, 0x83, 0x99, 0x36, 0xc7, - 0x28, 0xc6, 0xcc, 0xeb, 0x31, 0x2a, 0x5d, 0xa3, 0x3f, 0xbf, 0x1e, 0xa3, - 0x6e, 0x1e, 0x43, 0xd9, 0x06, 0xee, 0xec, 0x0c, 0x3e, 0x13, 0x52, 0xd8, - 0x14, 0xa3, 0xa6, 0x3e, 0x44, 0x8c, 0x1a, 0x56, 0x31, 0xca, 0xa3, 0xfb, - 0xfb, 0x90, 0xcd, 0x77, 0x21, 0xd3, 0xef, 0x00, 0x8b, 0x7d, 0x1b, 0x7c, - 0x7d, 0x0b, 0x38, 0xe9, 0x9b, 0xa5, 0xcd, 0x67, 0x0e, 0x06, 0x85, 0xf9, - 0xa1, 0x87, 0xa5, 0xbc, 0x1a, 0xc0, 0x11, 0xac, 0xae, 0xc5, 0xa2, 0x9b, - 0x19, 0x2f, 0xf6, 0x99, 0x13, 0xde, 0xde, 0x6b, 0x2c, 0x2b, 0x8f, 0xb5, - 0xa6, 0xe6, 0x19, 0x33, 0xd4, 0x75, 0x94, 0xf5, 0x4e, 0x62, 0x87, 0x8a, - 0xca, 0x33, 0x7b, 0xa4, 0xbc, 0xe8, 0xe1, 0xb0, 0xa9, 0x79, 0x6f, 0x8c, - 0x71, 0x1f, 0x87, 0xe5, 0x7c, 0x1c, 0x96, 0x5d, 0x5c, 0x8d, 0x85, 0xd0, - 0x7f, 0xca, 0xd9, 0x88, 0xbd, 0x8e, 0xf8, 0xd8, 0x6b, 0xe2, 0x43, 0x61, - 0x2f, 0x6f, 0xae, 0x1c, 0x9e, 0x19, 0x9e, 0x89, 0xc9, 0x7e, 0xc8, 0x79, - 0xa8, 0x48, 0x7d, 0xf1, 0x9c, 0xd2, 0x2f, 0xd3, 0x19, 0xf5, 0xe5, 0xe9, - 0x2a, 0x14, 0x3f, 0xa8, 0x0d, 0x43, 0x57, 0x43, 0xbf, 0x54, 0x57, 0x62, - 0xbe, 0x39, 0x10, 0xc6, 0xe7, 0x6f, 0x4b, 0x57, 0xe4, 0x83, 0xfa, 0xda, - 0x8c, 0xc5, 0x6e, 0x05, 0x93, 0x6d, 0xc4, 0x63, 0xae, 0xc2, 0x63, 0xcd, - 0x7e, 0x9f, 0xfc, 0x81, 0x61, 0xe8, 0xf2, 0x3f, 0xa0, 0xcf, 0x8f, 0xed, - 0x76, 0xf9, 0x11, 0xfc, 0xf7, 0xbf, 0x87, 0x4e, 0xfe, 0x1d, 0x72, 0x85, - 0x57, 0xec, 0x2e, 0xf9, 0x21, 0xda, 0xae, 0xe3, 0x1c, 0xf6, 0x9f, 0x72, - 0x92, 0xf6, 0x28, 0xf0, 0xc9, 0xa8, 0x8f, 0x4f, 0xde, 0x7a, 0x20, 0x69, - 0x8f, 0xb1, 0xce, 0x0e, 0x39, 0xff, 0x34, 0x39, 0xae, 0xb0, 0x49, 0x80, - 0x49, 0x1e, 0x4f, 0x73, 0xfe, 0xc9, 0x6a, 0x16, 0xd8, 0x27, 0xeb, 0x63, - 0x9f, 0x9f, 0xa6, 0x3d, 0xec, 0x33, 0xf5, 0xf7, 0xa8, 0x7f, 0x0f, 0xf7, - 0x1c, 0x76, 0x93, 0x98, 0x07, 0xb8, 0x07, 0xd7, 0x87, 0x25, 0x5f, 0x1b, - 0x51, 0x9f, 0x13, 0x25, 0xd7, 0x6a, 0x82, 0x9c, 0x58, 0xab, 0x3d, 0xc3, - 0x55, 0x59, 0xb5, 0xcc, 0x22, 0xbe, 0xb3, 0x55, 0x2b, 0xfa, 0x7b, 0xfe, - 0xf5, 0xd3, 0xfe, 0xf5, 0x53, 0xfe, 0xf5, 0x69, 0xc4, 0xe1, 0x53, 0x2a, - 0x96, 0xb2, 0x9d, 0x6d, 0x50, 0x72, 0x15, 0x63, 0x01, 0x7b, 0x9c, 0xeb, - 0xff, 0xf3, 0x7a, 0x59, 0xe9, 0x98, 0xe3, 0x8f, 0xe2, 0x73, 0x1a, 0x9f, - 0x09, 0x7c, 0x0e, 0xe1, 0x93, 0xc7, 0x67, 0x5d, 0xa6, 0x5a, 0xaa, 0x34, - 0x06, 0x1b, 0xe9, 0x95, 0x54, 0xed, 0x39, 0xe8, 0xf1, 0x49, 0xe8, 0xf6, - 0xb8, 0x14, 0x2a, 0x7f, 0x22, 0x93, 0x33, 0x9a, 0xb4, 0xd9, 0xd0, 0x69, - 0x05, 0xb6, 0x3c, 0xe3, 0xed, 0x41, 0xb6, 0x26, 0x46, 0xd0, 0xb7, 0x2e, - 0x8f, 0x3a, 0x4f, 0x8a, 0x7e, 0xdf, 0x14, 0xfa, 0x89, 0x5e, 0xe8, 0xbf, - 0x5b, 0xed, 0xbf, 0x55, 0x1c, 0x4f, 0xc6, 0xfb, 0x6d, 0xd7, 0x82, 0xce, - 0x7b, 0x4f, 0x61, 0xec, 0xa4, 0x3a, 0x7f, 0x99, 0x91, 0x93, 0xb3, 0xab, - 0xdb, 0x3d, 0xdf, 0x6a, 0x99, 0x57, 0xa9, 0x77, 0xf0, 0xe1, 0xc2, 0x17, - 0x66, 0x60, 0xef, 0x47, 0xab, 0x21, 0x6d, 0x08, 0xf1, 0x66, 0xa8, 0x7a, - 0x55, 0xc5, 0x9b, 0x54, 0xd5, 0xcd, 0xc4, 0xcf, 0x44, 0x70, 0xcd, 0x73, - 0x31, 0x88, 0x8b, 0xea, 0xfc, 0xde, 0x2a, 0xf0, 0x8d, 0xa6, 0xea, 0x86, - 0x93, 0xeb, 0xfb, 0x4a, 0xea, 0x7c, 0x71, 0x26, 0x1e, 0xd7, 0x25, 0x37, - 0x40, 0x9c, 0x3b, 0xa2, 0x62, 0x13, 0xd6, 0xea, 0xed, 0xcc, 0x15, 0x5f, - 0xe7, 0xbb, 0x00, 0xf6, 0x27, 0xd0, 0xaf, 0x0b, 0xfe, 0x18, 0xf7, 0x6a, - 0xb4, 0x4f, 0xf2, 0xca, 0x67, 0x26, 0xa4, 0x52, 0x1e, 0x04, 0xbf, 0x7e, - 0x8e, 0xa4, 0x72, 0x89, 0x18, 0xec, 0x31, 0xd8, 0xc3, 0xf2, 0xea, 0x2a, - 0x95, 0x6a, 0x80, 0x29, 0xda, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xed, - 0xbf, 0xa9, 0xbd, 0xb7, 0x42, 0x75, 0x10, 0x72, 0x4a, 0xa2, 0x9d, 0xb5, - 0x6d, 0xfc, 0x2e, 0xeb, 0xaa, 0x26, 0xb0, 0x66, 0x1c, 0x91, 0xc5, 0x72, - 0x1d, 0xf4, 0x22, 0xe6, 0x6e, 0x3f, 0x22, 0x0b, 0xe5, 0x09, 0x79, 0xa1, - 0xfc, 0xcd, 0x76, 0x60, 0x2a, 0xc8, 0x94, 0xf4, 0xb7, 0xcb, 0xf5, 0x33, - 0x9e, 0x41, 0x3b, 0xe4, 0x39, 0x9b, 0x8f, 0x7a, 0x79, 0x6e, 0x5e, 0xd5, - 0x68, 0xbc, 0x6f, 0x57, 0x1f, 0xb7, 0xad, 0xe8, 0x24, 0x7a, 0x1e, 0x9d, - 0x53, 0xb6, 0x39, 0x3c, 0x65, 0xef, 0x95, 0xcb, 0xce, 0x36, 0x59, 0x75, - 0x54, 0x5e, 0x4c, 0xfc, 0x80, 0xb5, 0x6e, 0x99, 0x2b, 0xf2, 0xa0, 0x9c, - 0xc4, 0xba, 0xbd, 0xec, 0x3c, 0x06, 0x3b, 0x7d, 0x02, 0xb6, 0xc0, 0x1a, - 0xc0, 0x31, 0xe6, 0x5a, 0xb2, 0xa2, 0x6a, 0x68, 0xf5, 0xfa, 0xb0, 0x3a, - 0x27, 0xdc, 0x2c, 0xab, 0x0a, 0x8b, 0x79, 0xb5, 0xf6, 0xd5, 0x31, 0x6f, - 0x8d, 0x18, 0xca, 0xee, 0xbf, 0x01, 0x7a, 0x8a, 0xb0, 0xdd, 0x26, 0xd5, - 0xc7, 0x48, 0xb4, 0xf8, 0x7d, 0x14, 0x06, 0x6d, 0xe8, 0x63, 0x27, 0x92, - 0xf6, 0x6b, 0xfb, 0x92, 0xf6, 0xc4, 0x81, 0x5c, 0xd5, 0xf3, 0x99, 0xae, - 0xb6, 0xb6, 0x5e, 0xff, 0xc9, 0x60, 0x5d, 0xbd, 0xbc, 0x8e, 0xa1, 0x61, - 0xa4, 0xcf, 0x5f, 0x82, 0x7e, 0x43, 0xd2, 0x7c, 0xa6, 0xfe, 0x89, 0x71, - 0xa7, 0x2f, 0x76, 0x54, 0x78, 0x32, 0x8b, 0x79, 0xb5, 0xe5, 0x64, 0xe5, - 0x12, 0xe2, 0xe4, 0x35, 0x62, 0x87, 0xde, 0x8b, 0x72, 0xed, 0x13, 0x49, - 0x67, 0x50, 0x5b, 0x18, 0x43, 0xd6, 0xf2, 0xfc, 0x18, 0xe3, 0xec, 0x31, - 0x11, 0xe0, 0xcb, 0x33, 0x03, 0x92, 0x2e, 0xaa, 0x77, 0x21, 0x78, 0x96, - 0x53, 0x9b, 0x80, 0xfc, 0xf0, 0xfc, 0x28, 0x03, 0xa3, 0x6e, 0x77, 0xc7, - 0xd2, 0xf2, 0x18, 0x6b, 0x63, 0x92, 0x9b, 0x93, 0x3d, 0x49, 0xf8, 0x55, - 0x77, 0xb4, 0x59, 0x26, 0x16, 0xdd, 0x4c, 0xf7, 0xf4, 0x13, 0x18, 0x63, - 0x1c, 0x63, 0x8d, 0x20, 0x37, 0xc9, 0x22, 0x56, 0x53, 0xbe, 0xf4, 0xdd, - 0x8f, 0x43, 0x46, 0x1f, 0xe1, 0x59, 0xd7, 0xc1, 0xac, 0x58, 0xa3, 0x79, - 0x35, 0xee, 0xbb, 0x5a, 0xae, 0xff, 0x57, 0x10, 0xeb, 0x42, 0xb2, 0x3f, - 0x2e, 0xfa, 0x48, 0x3c, 0xf4, 0x8b, 0x71, 0x9b, 0x6d, 0x61, 0xb6, 0xe9, - 0x68, 0x0b, 0xfd, 0x66, 0x3c, 0xac, 0x27, 0xe3, 0xd6, 0x20, 0xcf, 0xe0, - 0x1a, 0xf6, 0xb8, 0x18, 0xcf, 0xd7, 0x21, 0x8b, 0x11, 0xe9, 0xb8, 0x60, - 0x0d, 0xbe, 0x0e, 0x5a, 0x42, 0xca, 0xd7, 0x8f, 0x8b, 0xee, 0xb7, 0xb7, - 0xaf, 0xb7, 0x87, 0xfc, 0xf6, 0x11, 0x69, 0xbb, 0xd0, 0x67, 0xbe, 0x21, - 0x47, 0x30, 0xa6, 0x21, 0x57, 0x90, 0xeb, 0xd8, 0x3d, 0xe3, 0xb0, 0xc5, - 0x47, 0x48, 0xcb, 0x21, 0xd6, 0x1b, 0x5d, 0xd8, 0x5f, 0x8b, 0x7d, 0x87, - 0x7c, 0xde, 0x6c, 0x95, 0x9c, 0xca, 0x75, 0x43, 0xea, 0xbd, 0x85, 0x1c, - 0xec, 0xfd, 0xae, 0x9e, 0xa1, 0x0e, 0xaf, 0x5e, 0xc0, 0xfd, 0x91, 0x7e, - 0xb4, 0x5d, 0xab, 0x9f, 0xb7, 0xd9, 0xc6, 0x7b, 0xd7, 0xea, 0x15, 0xbb, - 0xcf, 0x4c, 0x69, 0x61, 0x7f, 0xff, 0xfc, 0x98, 0xe2, 0x3d, 0x5f, 0xee, - 0x36, 0x17, 0xe4, 0x2e, 0x2d, 0xb5, 0x03, 0xf1, 0xa2, 0x9a, 0x42, 0xdf, - 0x6b, 0x3c, 0x83, 0xa1, 0xf6, 0x03, 0x16, 0x24, 0xb8, 0xe6, 0x38, 0x7d, - 0xe6, 0xb0, 0x7a, 0xb6, 0xcf, 0x3c, 0xa9, 0x35, 0x3e, 0x1b, 0xd5, 0x86, - 0x37, 0x3c, 0xdb, 0xa6, 0x64, 0x64, 0xd8, 0x5e, 0x9f, 0xc9, 0xf2, 0x88, - 0x3c, 0x5d, 0x65, 0xbf, 0x6b, 0xf5, 0x94, 0xbd, 0x55, 0x3b, 0xb9, 0x83, - 0xbe, 0x90, 0x7d, 0xdf, 0xd9, 0x34, 0x0f, 0xaf, 0x6f, 0x36, 0x47, 0x5d, - 0x36, 0xce, 0xb1, 0x45, 0xf5, 0xb9, 0xac, 0xfa, 0x84, 0x94, 0xac, 0x37, - 0xce, 0xf3, 0x17, 0xb2, 0x71, 0x9e, 0xb6, 0x75, 0x9e, 0x27, 0x31, 0xe6, - 0x29, 0xf4, 0x2d, 0x56, 0xbb, 0xa3, 0x15, 0x79, 0xa7, 0x9e, 0xb3, 0xdf, - 0x92, 0xcb, 0xeb, 0x63, 0xff, 0x25, 0xae, 0x1b, 0x69, 0xfa, 0x4b, 0x9f, - 0x46, 0xfe, 0x66, 0xdb, 0x3f, 0x53, 0xf2, 0xde, 0x6a, 0x77, 0x1f, 0x5a, - 0xd0, 0xac, 0xc1, 0x9f, 0x09, 0x75, 0xf5, 0x3b, 0xca, 0xd7, 0xdc, 0x0d, - 0x3d, 0xed, 0x79, 0x06, 0x6b, 0xb7, 0x3f, 0xa9, 0xfa, 0x5c, 0xb1, 0x47, - 0x64, 0xcf, 0x99, 0x6e, 0xf3, 0x8a, 0xdc, 0x2f, 0xe9, 0x08, 0xaf, 0x91, - 0x43, 0xd9, 0x7c, 0xf7, 0xe1, 0x57, 0x99, 0x17, 0x40, 0x97, 0xdd, 0xbd, - 0x3f, 0x93, 0x27, 0xe4, 0x64, 0x69, 0x0a, 0xbe, 0x67, 0x5c, 0x7a, 0x9f, - 0xa1, 0xff, 0xc9, 0x9b, 0x5e, 0xad, 0xc6, 0x8b, 0x89, 0x29, 0x3f, 0x26, - 0x4e, 0x29, 0x3f, 0xf7, 0x8a, 0x7f, 0x8e, 0xa2, 0xbb, 0xf7, 0x3c, 0x9e, - 0x7d, 0x41, 0xf9, 0x80, 0x6f, 0x48, 0x05, 0x6b, 0x21, 0xf6, 0xfc, 0x36, - 0xd9, 0xfa, 0x10, 0x6d, 0x12, 0x19, 0xc0, 0xdd, 0x4d, 0xea, 0x5d, 0x0b, - 0xdd, 0x6e, 0x11, 0xd9, 0x4e, 0xfb, 0x59, 0xd8, 0x2a, 0x6d, 0xe3, 0xde, - 0x5e, 0xd9, 0x86, 0x6b, 0x6b, 0x74, 0x4d, 0xca, 0x5b, 0x69, 0x87, 0x1f, - 0xbd, 0xe0, 0x7d, 0xf7, 0x5f, 0x40, 0xba, 0x1c, 0x1f, 0x91, 0x7b, 0x2f, - 0x78, 0x76, 0x37, 0x39, 0xf3, 0x84, 0x92, 0xef, 0xb8, 0x92, 0x6f, 0x5d, - 0x8e, 0x38, 0x94, 0x3d, 0x79, 0xe2, 0xb9, 0x4a, 0x4f, 0x26, 0x9f, 0xf4, - 0xed, 0xa8, 0xfb, 0x19, 0xbe, 0x23, 0x46, 0x19, 0x91, 0xee, 0x74, 0x07, - 0xf7, 0x6f, 0xf7, 0x5c, 0x20, 0xbf, 0x5d, 0x1b, 0xf8, 0x7d, 0x0a, 0x3e, - 0xb6, 0xa7, 0xc7, 0xe3, 0xf9, 0x95, 0x99, 0x0f, 0xce, 0xf3, 0xd7, 0xd6, - 0x79, 0x36, 0xa4, 0xa2, 0xf2, 0xdc, 0xd0, 0x36, 0x69, 0xcb, 0xc9, 0x0a, - 0xec, 0xe3, 0xcf, 0x84, 0xe7, 0x92, 0x49, 0x8b, 0x37, 0xef, 0x6a, 0x95, - 0x34, 0x05, 0x3c, 0x90, 0xae, 0xa4, 0xaf, 0x3f, 0xd2, 0xf1, 0xc4, 0x0d, - 0xef, 0x5d, 0x11, 0x37, 0xd3, 0x8b, 0x36, 0x5d, 0xe9, 0x70, 0xc8, 0x5f, - 0x6f, 0x23, 0xa2, 0x2b, 0x1d, 0x26, 0xd7, 0x75, 0xf8, 0x3a, 0x74, 0x58, - 0x91, 0x8f, 0x83, 0x27, 0xac, 0xef, 0x67, 0xfa, 0xcc, 0x23, 0xb2, 0x53, - 0xe9, 0xdf, 0xee, 0x81, 0x4f, 0xf5, 0x75, 0xd9, 0x7c, 0x0b, 0xba, 0x7c, - 0x43, 0x94, 0x3e, 0xd5, 0xd9, 0xa3, 0x8a, 0x1a, 0x87, 0xbe, 0x8d, 0xbc, - 0x35, 0x2b, 0x9f, 0x40, 0x1a, 0xd5, 0x59, 0x82, 0x51, 0x4f, 0xbf, 0x6a, - 0xcd, 0xfb, 0xfa, 0xcd, 0x8e, 0x52, 0x87, 0xd1, 0x0e, 0x4f, 0x9f, 0x2d, - 0xaa, 0xcf, 0x74, 0xfc, 0x36, 0xb5, 0xde, 0xed, 0x9e, 0x9d, 0x1d, 0xd4, - 0xe9, 0xd3, 0x55, 0xef, 0xbb, 0x88, 0x38, 0x37, 0x5d, 0xfd, 0x65, 0x7a, - 0xf5, 0x74, 0x3a, 0x24, 0xde, 0xba, 0xda, 0xac, 0x4f, 0xfd, 0x42, 0x48, - 0xd9, 0xf0, 0x10, 0x64, 0x78, 0xba, 0xb4, 0xc3, 0xb7, 0x7b, 0x8f, 0xe7, - 0x9e, 0x0f, 0xc8, 0xf3, 0x89, 0x62, 0xb7, 0xf9, 0x16, 0xee, 0x0d, 0x83, - 0xe7, 0x23, 0xd2, 0x24, 0x29, 0x9f, 0xe7, 0xd8, 0x3a, 0xcf, 0x01, 0x8d, - 0x5e, 0xbf, 0x14, 0xf3, 0xd8, 0x2a, 0xfd, 0xd7, 0xef, 0xaa, 0x77, 0x1a, - 0xae, 0x16, 0xe9, 0xb7, 0x81, 0x95, 0x22, 0x9d, 0x72, 0x65, 0x31, 0x26, - 0x57, 0x88, 0x41, 0x06, 0xf0, 0x5d, 0x9d, 0xf2, 0x63, 0x78, 0x58, 0xde, - 0x28, 0xde, 0x88, 0x8e, 0x7e, 0x79, 0xbd, 0x18, 0xd0, 0x42, 0x2c, 0xcc, - 0x7c, 0x61, 0x5c, 0xde, 0x9c, 0xe9, 0x96, 0x95, 0x51, 0xc4, 0xfd, 0x1e, - 0xca, 0xa4, 0xcf, 0x7c, 0x50, 0xbd, 0xeb, 0x72, 0xad, 0x7e, 0xd1, 0xc6, - 0xf8, 0x73, 0x75, 0x39, 0xca, 0xfd, 0x6f, 0xfe, 0x5e, 0xbc, 0x5d, 0x56, - 0x98, 0x53, 0xf4, 0x74, 0xca, 0xc2, 0x1c, 0xf2, 0xf9, 0x22, 0xc7, 0xa7, - 0xdc, 0x46, 0xd4, 0xef, 0x61, 0xcc, 0xf7, 0x49, 0x9e, 0x41, 0x8f, 0x50, - 0x37, 0xd7, 0xea, 0xab, 0x36, 0xf7, 0x3f, 0xc7, 0x65, 0x11, 0xfa, 0xfb, - 0x47, 0x71, 0xee, 0xcf, 0xe7, 0xd4, 0xfb, 0x85, 0x0b, 0x8b, 0xa3, 0xc8, - 0x1d, 0xae, 0xd5, 0xa7, 0xec, 0x29, 0xa5, 0xb7, 0xc5, 0xf2, 0x43, 0x7e, - 0x3b, 0xaf, 0x79, 0xcf, 0xcd, 0xec, 0xe9, 0x61, 0xbe, 0xfa, 0x10, 0xf2, - 0x05, 0xe6, 0xaa, 0xa3, 0xc0, 0x6b, 0x94, 0x49, 0x4c, 0x26, 0x8b, 0x1c, - 0x4b, 0x22, 0x5b, 0x90, 0xdf, 0xe7, 0x64, 0x18, 0xf4, 0xc4, 0x90, 0xdb, - 0x33, 0x3e, 0xdc, 0x25, 0xab, 0x11, 0x2f, 0x0e, 0xf0, 0xac, 0xd8, 0x2a, - 0x62, 0xc3, 0xea, 0x7a, 0x6c, 0xd8, 0x89, 0x6b, 0x37, 0xe3, 0xf4, 0xfc, - 0x67, 0x8c, 0xcf, 0xba, 0x0d, 0x63, 0xc3, 0x20, 0xfa, 0xb3, 0xad, 0x53, - 0x26, 0xe7, 0x90, 0x44, 0x20, 0x67, 0x59, 0x10, 0x9e, 0x01, 0xc9, 0xca, - 0xf4, 0x62, 0x77, 0xf4, 0xa2, 0x96, 0x56, 0x67, 0x45, 0xe2, 0x98, 0x73, - 0xa1, 0xd8, 0x29, 0x8b, 0x73, 0x12, 0x33, 0x12, 0x8f, 0x48, 0x75, 0xd1, - 0xc3, 0xec, 0x53, 0x1a, 0xda, 0xab, 0xae, 0x2c, 0x6e, 0xec, 0x63, 0x1a, - 0x89, 0xc3, 0xf2, 0x75, 0xbf, 0x4f, 0x5a, 0xf5, 0x79, 0xb5, 0x83, 0x7b, - 0x6c, 0x8b, 0xd5, 0x0e, 0xd0, 0x40, 0xda, 0x76, 0x35, 0xce, 0x1b, 0xbb, - 0x3e, 0x2f, 0xe7, 0x44, 0x36, 0xb3, 0xdd, 0xc5, 0xbc, 0x17, 0xf1, 0xcc, - 0x23, 0xa0, 0xe3, 0x9a, 0xa1, 0xdb, 0x8f, 0x48, 0x61, 0x71, 0xf3, 0x1c, - 0x8d, 0x34, 0xf0, 0x19, 0x8e, 0xcf, 0x79, 0x0e, 0x83, 0xbe, 0x6b, 0x9a, - 0x6e, 0x1f, 0x86, 0x2c, 0xbd, 0x39, 0x8c, 0xb3, 0x96, 0xf9, 0x23, 0xe9, - 0x11, 0xfd, 0xbc, 0xa6, 0xe4, 0xaf, 0x2f, 0xf4, 0x63, 0x81, 0x64, 0xa4, - 0x6d, 0x79, 0x4c, 0x8c, 0x65, 0xd6, 0x10, 0x5e, 0x69, 0x4d, 0xab, 0xfd, - 0xde, 0x2d, 0x58, 0xdf, 0xe2, 0x86, 0x6c, 0xd6, 0x0b, 0x58, 0x0f, 0xfe, - 0xfa, 0x36, 0xe9, 0x60, 0xbd, 0x80, 0x79, 0xc3, 0x21, 0x7c, 0x33, 0x77, - 0x78, 0xb9, 0x9e, 0x74, 0x7e, 0xa6, 0xe2, 0x6b, 0x6e, 0x91, 0xf7, 0xad, - 0x98, 0x08, 0xef, 0xd1, 0x6f, 0x74, 0x4a, 0xd3, 0x57, 0x7a, 0xe1, 0x2b, - 0x1e, 0x03, 0xf6, 0xc6, 0xb8, 0x67, 0x7a, 0x24, 0xe4, 0x9d, 0xb1, 0x50, - 0xf5, 0x96, 0x37, 0xe7, 0x2c, 0xff, 0x9d, 0x21, 0xd9, 0x73, 0xd1, 0x61, - 0x4d, 0xb4, 0x8b, 0x35, 0x1f, 0xf4, 0x13, 0x7d, 0x15, 0xf9, 0xe9, 0x95, - 0x45, 0x63, 0x1b, 0xcf, 0x7c, 0xbe, 0x5e, 0xc5, 0x35, 0xb1, 0x7f, 0x44, - 0x61, 0x4c, 0xff, 0x1e, 0x7f, 0x23, 0x5f, 0x7a, 0xcf, 0xf9, 0x77, 0xe6, - 0x53, 0x63, 0xfe, 0x59, 0x3b, 0x37, 0x73, 0x72, 0x43, 0x4e, 0xd5, 0xab, - 0xea, 0xbd, 0x2b, 0x55, 0x1b, 0xfe, 0x71, 0x00, 0xf6, 0xc9, 0x35, 0x50, - 0xd7, 0x1e, 0x02, 0x36, 0x8b, 0x75, 0xaa, 0x9c, 0xe8, 0xf4, 0x43, 0xe2, - 0xd9, 0x3b, 0xac, 0x4c, 0xf9, 0xb2, 0x95, 0xb2, 0x97, 0x83, 0xac, 0x96, - 0x33, 0xf2, 0x9f, 0xaa, 0x97, 0x54, 0xad, 0x75, 0x06, 0x79, 0x49, 0x68, - 0x5a, 0xe5, 0x64, 0x0d, 0xf8, 0x16, 0x7e, 0xef, 0xd9, 0x2f, 0x62, 0x2d, - 0x5a, 0xea, 0x4c, 0x83, 0x7e, 0xbe, 0x5e, 0x4f, 0xc1, 0x7f, 0xe8, 0xb6, - 0x6d, 0x16, 0x10, 0x0f, 0x53, 0xea, 0x5c, 0x0c, 0xd7, 0xf1, 0x61, 0xe5, - 0x9f, 0x65, 0x01, 0xb2, 0x39, 0x1b, 0xc3, 0x38, 0x9a, 0xb2, 0x4f, 0x43, - 0xe9, 0xe1, 0x21, 0x85, 0x79, 0x8d, 0xf3, 0x70, 0x58, 0xcb, 0x3d, 0x22, - 0xe7, 0x33, 0x32, 0x85, 0x35, 0x1c, 0x5a, 0xa6, 0x0e, 0x28, 0xdb, 0x31, - 0x69, 0x82, 0xec, 0x4f, 0x00, 0x7b, 0x18, 0xd3, 0x94, 0x71, 0x14, 0xeb, - 0xa2, 0x53, 0x42, 0x67, 0x21, 0xe3, 0x69, 0x60, 0x84, 0xb9, 0x66, 0x79, - 0x69, 0x31, 0x90, 0xe9, 0xcb, 0x3c, 0xef, 0xaf, 0x8f, 0x0f, 0x74, 0x11, - 0x47, 0x49, 0x65, 0x71, 0x4a, 0xa6, 0x66, 0x99, 0xb3, 0x8f, 0xa9, 0x33, - 0x06, 0x21, 0x75, 0xc6, 0xc5, 0xcb, 0x99, 0xbd, 0x6f, 0x0f, 0x63, 0x56, - 0x84, 0x7b, 0x6d, 0x02, 0xdb, 0xe9, 0xc7, 0xbc, 0x37, 0x92, 0xaf, 0x97, - 0xab, 0x0e, 0x83, 0xde, 0x8b, 0x33, 0x56, 0x26, 0x2f, 0x0e, 0xcf, 0x5b, - 0x8f, 0xba, 0xe0, 0x7f, 0x15, 0xfe, 0x73, 0xaa, 0x74, 0x2f, 0xf8, 0x2c, - 0x60, 0x85, 0x65, 0xe4, 0x62, 0x91, 0x39, 0xe3, 0x47, 0xa1, 0x37, 0x5e, - 0x17, 0x06, 0x0d, 0xf8, 0x81, 0x35, 0xf5, 0x7e, 0xa1, 0xe5, 0xae, 0x20, - 0x87, 0x8d, 0x69, 0x87, 0xa0, 0xeb, 0xbc, 0xd9, 0xe4, 0xdb, 0x03, 0xdf, - 0x35, 0x3e, 0x07, 0x3f, 0xba, 0x24, 0x7c, 0xef, 0xe7, 0x9d, 0x3a, 0xf3, - 0xa5, 0xcb, 0xf0, 0x7b, 0x99, 0x78, 0x06, 0x36, 0x94, 0x8f, 0xb6, 0x80, - 0xe6, 0xdf, 0xc6, 0xbd, 0x5c, 0x95, 0xf3, 0x58, 0xce, 0x9a, 0x14, 0x62, - 0x21, 0xe9, 0x8b, 0x5d, 0x92, 0x6d, 0xf0, 0x64, 0x9a, 0xbc, 0x61, 0x5b, - 0x83, 0xa2, 0xa9, 0xf1, 0x7a, 0x0f, 0xc0, 0x06, 0xaf, 0xc2, 0xdf, 0x35, - 0xfb, 0xb9, 0x7e, 0xaa, 0x48, 0x0c, 0xf5, 0x84, 0x3a, 0x8b, 0x70, 0xd9, - 0x66, 0x1d, 0x90, 0xef, 0xfb, 0xfe, 0x95, 0x9a, 0xe3, 0xfa, 0xde, 0x1d, - 0xeb, 0xd0, 0xa4, 0xcf, 0xe3, 0x71, 0xbf, 0xed, 0xd1, 0xc8, 0x71, 0x9a, - 0x1a, 0xc6, 0xb9, 0xe8, 0x8f, 0x73, 0xce, 0x1f, 0x67, 0xc1, 0x1f, 0xe7, - 0xf2, 0xfa, 0x38, 0x0f, 0xc2, 0x0e, 0xea, 0xf5, 0xa7, 0x80, 0x37, 0x92, - 0x4e, 0xbd, 0x9e, 0x46, 0x5e, 0x36, 0xd9, 0x3f, 0xa1, 0xf6, 0x5e, 0xf5, - 0xc4, 0x8b, 0x43, 0x49, 0xdb, 0x93, 0x3f, 0xac, 0x40, 0x26, 0x60, 0x8f, - 0x79, 0xf1, 0xb0, 0x3a, 0xf7, 0x03, 0xbd, 0xfd, 0xc2, 0x36, 0xf8, 0x81, - 0xc7, 0x10, 0x4b, 0x9c, 0xe1, 0x25, 0x5b, 0xf2, 0x7b, 0x7e, 0x4d, 0x87, - 0xbd, 0x77, 0x20, 0x2e, 0xbd, 0x09, 0xdb, 0x71, 0x86, 0x2b, 0x8b, 0x8f, - 0xa9, 0x3d, 0xe1, 0xa6, 0xc4, 0xbd, 0xd0, 0x67, 0x79, 0x78, 0x61, 0xb1, - 0x3c, 0x7c, 0x8e, 0xfb, 0x43, 0xe8, 0xb7, 0xb0, 0xd8, 0x0e, 0xb9, 0xb7, - 0xab, 0xba, 0xca, 0xa5, 0x62, 0x04, 0x7a, 0x34, 0x61, 0xf3, 0x11, 0xb4, - 0x45, 0x61, 0x07, 0x5d, 0x68, 0x7f, 0x0d, 0x6b, 0x3b, 0x86, 0xf6, 0xb5, - 0xd6, 0x61, 0x85, 0x63, 0x6d, 0x39, 0x5f, 0xbd, 0x8a, 0x98, 0xfb, 0x16, - 0xfc, 0x68, 0x2f, 0xfa, 0xf4, 0xa3, 0xcf, 0x0e, 0x13, 0xf8, 0x2a, 0x53, - 0xbe, 0x21, 0x4d, 0x2e, 0x68, 0xd2, 0x1b, 0x68, 0x72, 0x41, 0x0f, 0x7c, - 0xe7, 0x19, 0xd6, 0xa0, 0xfb, 0xe5, 0x64, 0x91, 0x67, 0xaa, 0xf8, 0xee, - 0xb5, 0x29, 0x21, 0x60, 0xd2, 0xa6, 0x33, 0x56, 0x74, 0x45, 0xd5, 0x7a, - 0x68, 0x5b, 0x7d, 0x4e, 0x45, 0x54, 0x9c, 0x89, 0x9d, 0x44, 0xfc, 0xba, - 0x5a, 0x6d, 0x97, 0x37, 0xfc, 0xb9, 0xd6, 0x84, 0xfb, 0x97, 0x1b, 0xe7, - 0x3a, 0x55, 0x1a, 0x1d, 0xfe, 0x81, 0x6d, 0xf8, 0x7c, 0x75, 0x62, 0xae, - 0x76, 0xf4, 0x1d, 0x1d, 0xbe, 0xb8, 0x78, 0xa3, 0xbe, 0x13, 0xe8, 0xdb, - 0xd4, 0xd0, 0x77, 0x02, 0xfd, 0xda, 0x11, 0x07, 0xdb, 0x15, 0x4f, 0x93, - 0xa0, 0xeb, 0x4a, 0x51, 0xbd, 0x0b, 0x0c, 0xb9, 0x73, 0x4e, 0x93, 0x98, - 0x3a, 0xe3, 0xd5, 0x4a, 0x2c, 0x33, 0xa6, 0xbd, 0xa7, 0xde, 0xa3, 0x6c, - 0x60, 0xc8, 0x06, 0xee, 0x9d, 0x19, 0xd5, 0x52, 0x95, 0x1c, 0x62, 0xd6, - 0x2e, 0xe2, 0x27, 0xc7, 0x45, 0xcc, 0x5c, 0xc0, 0x78, 0x8b, 0xc5, 0x15, - 0x9e, 0xc1, 0x86, 0x5d, 0xbc, 0x4d, 0x9c, 0xbd, 0xcb, 0x50, 0x67, 0x1e, - 0xd2, 0xaa, 0x66, 0xb7, 0x50, 0x14, 0x33, 0x39, 0xc0, 0x33, 0x0e, 0xf7, - 0x63, 0x5d, 0x7e, 0x0e, 0x6d, 0x49, 0xc4, 0xc7, 0xc3, 0x5a, 0x72, 0x69, - 0x18, 0xd7, 0x8f, 0xe0, 0x1a, 0xfe, 0x78, 0x2e, 0x8b, 0xfb, 0x8f, 0xe0, - 0x7a, 0x42, 0x4b, 0xd5, 0xb2, 0xb8, 0x7e, 0x14, 0xd7, 0x49, 0x93, 0x79, - 0xca, 0x0f, 0xec, 0x8c, 0xe6, 0x62, 0x2c, 0x77, 0x69, 0x18, 0x9f, 0xc6, - 0xf1, 0x78, 0x0f, 0x7a, 0x2a, 0x72, 0xaf, 0x2d, 0x0e, 0x9a, 0x0e, 0x6a, - 0xe9, 0x4a, 0x1b, 0xc6, 0xe8, 0xc1, 0xf3, 0xb4, 0xa9, 0x43, 0xfe, 0xfc, - 0xac, 0x39, 0xdd, 0xad, 0x6a, 0x4e, 0x46, 0x22, 0x03, 0x9c, 0x7c, 0x1c, - 0x79, 0x80, 0x26, 0x69, 0xfb, 0x49, 0x29, 0x38, 0xf0, 0x2b, 0x15, 0x43, - 0x52, 0x91, 0x3c, 0x7e, 0xe7, 0x25, 0x39, 0x88, 0xfb, 0x15, 0xda, 0x02, - 0xfb, 0xfd, 0x89, 0x14, 0xca, 0xc4, 0xfd, 0xac, 0x33, 0xb1, 0x36, 0xc5, - 0xfa, 0x52, 0x0e, 0x32, 0x88, 0xd0, 0x7e, 0x6f, 0x50, 0x13, 0xf3, 0xce, - 0x55, 0x23, 0x2e, 0x6b, 0xc9, 0x0a, 0xf7, 0xfd, 0xdc, 0xcc, 0x45, 0x9b, - 0xef, 0x28, 0x4d, 0x70, 0x1f, 0xb1, 0x60, 0x24, 0x58, 0x1f, 0x51, 0xf5, - 0x75, 0xc7, 0xdb, 0x1f, 0xe4, 0xb8, 0x63, 0xe0, 0xb7, 0xb1, 0x6e, 0xc5, - 0x79, 0xbf, 0x80, 0xe7, 0xbd, 0x7a, 0x56, 0xaa, 0xf6, 0x5e, 0x5d, 0xf0, - 0xbd, 0x81, 0xf3, 0xd0, 0xc5, 0x45, 0x95, 0x1b, 0x73, 0x0f, 0xf7, 0xfd, - 0x72, 0x2a, 0xe4, 0x30, 0x45, 0xd6, 0xc8, 0x82, 0x7d, 0xbb, 0x40, 0x8e, - 0x9b, 0x69, 0x25, 0x9d, 0x47, 0x30, 0xa6, 0x38, 0xf4, 0xbb, 0xd9, 0x08, - 0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf9, 0x3a, 0xdd, 0xa4, 0x99, 0xf2, 0x38, - 0x0e, 0xff, 0xc9, 0x77, 0x32, 0x9e, 0x94, 0x9c, 0xc3, 0x1a, 0x8f, 0x81, - 0xd8, 0x98, 0xc7, 0xef, 0xeb, 0xf2, 0x9b, 0xf4, 0xe5, 0x97, 0x2b, 0xbf, - 0xa4, 0x74, 0xb8, 0x60, 0x73, 0xbe, 0xa0, 0xf6, 0x31, 0xa2, 0x74, 0xb7, - 0xa0, 0xce, 0xfd, 0x06, 0x32, 0x08, 0xea, 0x77, 0x37, 0xb6, 0xbd, 0x61, - 0x9b, 0xb4, 0xdd, 0xce, 0xf3, 0x10, 0xbd, 0xae, 0x90, 0x7e, 0xf2, 0xc1, - 0x18, 0x16, 0xec, 0xb5, 0x06, 0x3c, 0x04, 0x7c, 0xde, 0xaa, 0x7c, 0x48, - 0x6f, 0x64, 0xbb, 0xb4, 0x65, 0x4c, 0xc3, 0x66, 0x6c, 0xf8, 0x84, 0xbf, - 0x3f, 0xf0, 0x77, 0x21, 0x67, 0x4f, 0x16, 0xa1, 0x84, 0x4c, 0xfa, 0xef, - 0xf8, 0xde, 0xc0, 0x1e, 0x36, 0xef, 0x35, 0xbb, 0x99, 0x73, 0xf6, 0x75, - 0xbe, 0x17, 0x6e, 0xc0, 0xf7, 0x82, 0xcf, 0x77, 0xe5, 0x16, 0xe9, 0x5d, - 0x98, 0x71, 0xc1, 0x33, 0x6d, 0xee, 0x46, 0xf6, 0x28, 0xea, 0x7f, 0x5f, - 0xac, 0x19, 0xe1, 0xb0, 0x5b, 0xbd, 0x59, 0x0d, 0x95, 0x79, 0xb5, 0x67, - 0x97, 0xe7, 0x10, 0x0b, 0xcb, 0x65, 0x2f, 0xc7, 0x2e, 0x57, 0x59, 0xcb, - 0x7e, 0x3f, 0x1a, 0xf8, 0xfe, 0xd7, 0x67, 0xd4, 0x79, 0x97, 0xc9, 0xaa, - 0x57, 0xf7, 0x2a, 0x97, 0x1b, 0x63, 0xea, 0x0e, 0xc6, 0xd3, 0xde, 0xbc, - 0x8c, 0xf2, 0xbd, 0x65, 0x5c, 0xef, 0x96, 0x4b, 0x73, 0x6a, 0xcf, 0xca, - 0xdf, 0x1b, 0xe2, 0x9e, 0x8f, 0xda, 0xff, 0x86, 0x5f, 0x1b, 0x53, 0x7e, - 0x7d, 0x75, 0x4e, 0xdd, 0xf3, 0xb0, 0x52, 0x75, 0x14, 0x7e, 0x1f, 0xb9, - 0x84, 0xbd, 0x55, 0x0a, 0xc8, 0xb9, 0xcf, 0xd9, 0x0f, 0x6f, 0x27, 0xce, - 0xe1, 0x58, 0xab, 0x18, 0xeb, 0xe2, 0x9c, 0x6c, 0xe7, 0x99, 0x92, 0xb2, - 0xda, 0x67, 0xf3, 0xea, 0xe2, 0x13, 0x12, 0xfc, 0x4f, 0x88, 0xb0, 0x1f, - 0x0b, 0x79, 0xae, 0x85, 0xef, 0xd2, 0xd2, 0x57, 0x20, 0x0f, 0x1a, 0xe5, - 0x3e, 0x4e, 0xbd, 0xee, 0xd5, 0xcd, 0xeb, 0x58, 0x17, 0x4d, 0x7c, 0xef, - 0x02, 0x7f, 0xc7, 0x61, 0x3f, 0x58, 0x27, 0xeb, 0xed, 0xbc, 0x66, 0xee, - 0x11, 0x5c, 0x33, 0xb0, 0xfd, 0x3f, 0xd4, 0x46, 0x90, 0x7c, 0xb4, 0x45, - 0x00, 0x00, 0x00 }; + 0xa5, 0x7b, 0x0b, 0x74, 0x1c, 0x55, 0x7a, 0xe6, 0x77, 0xab, 0xba, 0xa5, + 0xea, 0x56, 0xab, 0x55, 0x92, 0xdb, 0xa6, 0x95, 0xd1, 0xe0, 0x2e, 0x77, + 0xb5, 0xdc, 0x58, 0xc2, 0x54, 0xcb, 0x2d, 0xd3, 0x44, 0xe5, 0xb8, 0xc7, + 0x08, 0x5b, 0x06, 0x4d, 0x46, 0x38, 0xca, 0xac, 0x98, 0xc3, 0x2e, 0x1d, + 0x63, 0x83, 0x30, 0x06, 0x04, 0xc3, 0x66, 0x95, 0x2c, 0x89, 0x6a, 0xe4, + 0x07, 0x7e, 0xb4, 0xba, 0xf5, 0x32, 0x32, 0xd9, 0x9c, 0xb8, 0x2d, 0xc9, + 0x96, 0x81, 0x7e, 0xc0, 0x00, 0x33, 0x43, 0x76, 0x67, 0xe9, 0x35, 0x60, + 0x0c, 0x8c, 0x61, 0x92, 0x3d, 0x67, 0x97, 0xc9, 0x99, 0x49, 0x7c, 0x30, + 0x78, 0x6c, 0xde, 0x9b, 0x99, 0xdd, 0x15, 0x09, 0x93, 0xda, 0xff, 0xaf, + 0x96, 0x8c, 0x61, 0xd8, 0x24, 0x9b, 0xd5, 0x39, 0x7d, 0x4a, 0x5d, 0x75, + 0xeb, 0xde, 0xff, 0xfd, 0x7f, 0xff, 0x7f, 0x6f, 0x47, 0x00, 0x2f, 0x16, + 0xfe, 0x6a, 0xe9, 0x13, 0x1f, 0x18, 0x7c, 0xb0, 0x7d, 0xb5, 0xb1, 0xda, + 0xb9, 0xe1, 0x86, 0x8b, 0x1f, 0xae, 0x15, 0x40, 0xea, 0x5d, 0xfc, 0x8b, + 0xfe, 0xbe, 0xfa, 0x2f, 0x7b, 0x0d, 0x32, 0xa0, 0x2e, 0xd2, 0xc4, 0x1f, + 0x28, 0x92, 0x99, 0xfb, 0xcd, 0x0d, 0x3a, 0x14, 0xd9, 0xec, 0x5b, 0x77, + 0xbb, 0x0e, 0x24, 0xf3, 0x2d, 0xa1, 0xeb, 0xf1, 0x2b, 0xdb, 0x0a, 0xb8, + 0xc0, 0xf7, 0xbf, 0x6a, 0x7e, 0x3a, 0xf4, 0xc3, 0x6b, 0xb5, 0x8f, 0x73, + 0x32, 0x14, 0xd5, 0x9c, 0x84, 0xda, 0x0c, 0xa5, 0x89, 0xde, 0xf9, 0xd3, + 0x95, 0xdf, 0x77, 0xc1, 0xbf, 0x38, 0x17, 0x2c, 0xb7, 0x69, 0x60, 0x57, + 0x76, 0x00, 0x73, 0x71, 0xe0, 0x42, 0x3a, 0x62, 0xec, 0x02, 0x46, 0x25, + 0x33, 0x12, 0x3a, 0x89, 0x10, 0x66, 0xf3, 0xb0, 0xaa, 0x4d, 0x1d, 0xfb, + 0x4a, 0x21, 0x5c, 0x4c, 0xff, 0x83, 0x1d, 0x72, 0x0f, 0xe0, 0xed, 0x38, + 0x94, 0xa0, 0xf9, 0x10, 0x82, 0x59, 0x28, 0xb5, 0xe6, 0x20, 0x0a, 0x23, + 0xc0, 0x9e, 0xb4, 0x36, 0x00, 0x68, 0x7d, 0x45, 0x11, 0x3e, 0x7d, 0x02, + 0x5a, 0x4f, 0xa3, 0xdc, 0x92, 0xba, 0x45, 0x68, 0xc9, 0x9d, 0x02, 0x8a, + 0xa0, 0xb1, 0xab, 0xf2, 0x7c, 0x1d, 0x44, 0x34, 0xaf, 0xe0, 0xac, 0xcc, + 0xcb, 0x9a, 0x24, 0x67, 0x01, 0x97, 0x6e, 0x60, 0x4f, 0x16, 0x96, 0xcb, + 0x14, 0xd8, 0x15, 0x8f, 0xa8, 0x33, 0xe0, 0xe7, 0x21, 0x0c, 0x3b, 0xe3, + 0x34, 0xe2, 0xd8, 0xb6, 0x77, 0x1b, 0xb6, 0x7d, 0xcc, 0xa8, 0x86, 0xa5, + 0x6a, 0x41, 0x40, 0x60, 0xd8, 0x90, 0x90, 0x54, 0x37, 0x84, 0x5c, 0xd0, + 0x82, 0xdb, 0xf1, 0xf7, 0xc4, 0x6f, 0x32, 0xea, 0x46, 0x65, 0x7c, 0x0a, + 0xd5, 0x28, 0xab, 0x15, 0x89, 0x4d, 0xa7, 0x6d, 0xfb, 0x94, 0xee, 0xc2, + 0x31, 0x92, 0xcd, 0x70, 0xfe, 0xef, 0xed, 0x32, 0xc9, 0x65, 0xb7, 0xbe, + 0xb8, 0xbe, 0x82, 0x9c, 0x6a, 0xdb, 0x33, 0xf4, 0x6c, 0x6f, 0x7e, 0x51, + 0xc6, 0xb6, 0x2d, 0xe9, 0xb6, 0x7d, 0xbb, 0xfe, 0x77, 0xf6, 0xd6, 0xcf, + 0x8d, 0x8d, 0xe1, 0xf1, 0x51, 0x15, 0x4f, 0x64, 0x93, 0xc8, 0xa7, 0x6d, + 0xc8, 0xa6, 0x0b, 0xfd, 0x23, 0x21, 0xec, 0x2c, 0x74, 0xa2, 0x90, 0xd6, + 0x52, 0x67, 0xe9, 0xbd, 0xad, 0x71, 0x1d, 0xf7, 0x14, 0xba, 0x30, 0x97, + 0x86, 0xed, 0x31, 0xf5, 0xb2, 0x47, 0x44, 0x71, 0x67, 0xa1, 0x1b, 0xc5, + 0xb4, 0x7e, 0x7a, 0x58, 0x44, 0x06, 0x1b, 0x65, 0x17, 0xee, 0x2b, 0xb4, + 0xe2, 0xde, 0x42, 0x82, 0xde, 0xb1, 0x71, 0x63, 0xac, 0x89, 0xc6, 0xb7, + 0xe1, 0xb1, 0x49, 0xdb, 0x8e, 0xc6, 0x54, 0xf4, 0x17, 0x0c, 0xcc, 0x8d, + 0x4a, 0x48, 0x1d, 0x73, 0x21, 0x75, 0x14, 0xb8, 0xf3, 0x68, 0x1b, 0x66, + 0x46, 0x6d, 0x6c, 0x35, 0x86, 0x1b, 0x25, 0x32, 0xbb, 0x94, 0x2a, 0xe0, + 0xd6, 0xfd, 0xd8, 0xae, 0x56, 0x68, 0x3f, 0x2b, 0x0b, 0xec, 0x38, 0x1a, + 0xc5, 0x9b, 0x69, 0x0b, 0x37, 0xb6, 0x07, 0x31, 0x58, 0x08, 0xe0, 0x8d, + 0x74, 0x80, 0xd6, 0x30, 0xf0, 0x7a, 0x5a, 0xa1, 0x75, 0x5a, 0xf1, 0x62, + 0x9a, 0xc7, 0xf0, 0x58, 0x1f, 0xb6, 0x15, 0x9a, 0x70, 0x26, 0x1d, 0xa4, + 0x35, 0x03, 0x78, 0x85, 0xc6, 0xdd, 0x55, 0xd0, 0x71, 0x9a, 0xc6, 0xf5, + 0x17, 0x42, 0x78, 0x39, 0xed, 0x23, 0x5a, 0x03, 0x38, 0x99, 0x1e, 0xc0, + 0xae, 0x74, 0xcb, 0xe9, 0xeb, 0x49, 0x86, 0xa1, 0x25, 0xbc, 0x0e, 0xdf, + 0x7b, 0xdb, 0xee, 0x0e, 0x38, 0x66, 0x42, 0xeb, 0x2c, 0xae, 0x3b, 0x80, + 0xe1, 0xf4, 0x8b, 0x0b, 0x7e, 0x62, 0x60, 0xff, 0xe8, 0xbc, 0xfd, 0xc3, + 0x95, 0x4d, 0x38, 0x91, 0x05, 0x1e, 0x9b, 0x01, 0x66, 0xb2, 0x96, 0x5d, + 0x6b, 0xda, 0xf6, 0x74, 0x7b, 0x2b, 0xc9, 0x4b, 0xef, 0xdb, 0x4a, 0xa3, + 0x9e, 0x28, 0xb9, 0x80, 0xa3, 0x5a, 0x5f, 0x19, 0x12, 0x72, 0x73, 0x2e, + 0x54, 0x8d, 0x68, 0x5d, 0x39, 0x68, 0xa7, 0xef, 0x24, 0x4f, 0x3a, 0x96, + 0xd5, 0x7a, 0x2c, 0x0c, 0xd9, 0x41, 0xb3, 0x39, 0xd4, 0x2a, 0xdb, 0xf0, + 0x93, 0x2d, 0xa4, 0x5b, 0x6d, 0xbb, 0xee, 0x5a, 0xdb, 0x3e, 0xd3, 0x0e, + 0x5b, 0x32, 0xf5, 0xd3, 0x25, 0xe8, 0xe5, 0x0f, 0xa0, 0x0f, 0x9e, 0x44, + 0xf9, 0xab, 0x3e, 0x44, 0xfa, 0xc3, 0x72, 0x64, 0x60, 0x9e, 0xde, 0xad, + 0x2d, 0x90, 0x29, 0x13, 0x2f, 0x3a, 0xd9, 0x60, 0xa1, 0xa4, 0xc0, 0x45, + 0xfc, 0xb4, 0x8e, 0xd8, 0xb6, 0x4b, 0xf7, 0xc1, 0x47, 0xf2, 0xdd, 0x74, + 0xc8, 0xb6, 0xcf, 0x1b, 0x2a, 0xaa, 0x48, 0x37, 0x37, 0x8c, 0xd9, 0x98, + 0x36, 0x4e, 0x92, 0x3c, 0x05, 0x52, 0x3d, 0x71, 0x7a, 0x27, 0x40, 0xe3, + 0x13, 0xd8, 0x34, 0x12, 0xc4, 0xe3, 0x59, 0x05, 0x3f, 0x5c, 0x19, 0x45, + 0x0d, 0xcd, 0xe5, 0x25, 0x59, 0x55, 0x93, 0xfc, 0x50, 0x20, 0x73, 0x2b, + 0x54, 0xec, 0x11, 0x85, 0xb3, 0xc4, 0x63, 0x10, 0xdf, 0x2d, 0x05, 0xf0, + 0x54, 0x49, 0xc5, 0x93, 0xa5, 0x26, 0x3c, 0x5f, 0x32, 0x90, 0x1d, 0xd5, + 0xf6, 0x95, 0x61, 0xa3, 0x96, 0xcc, 0xf9, 0x8d, 0x5c, 0x0c, 0x99, 0x51, + 0xdb, 0xce, 0x13, 0xcd, 0x5e, 0xe2, 0xe1, 0xf5, 0xdc, 0x95, 0x38, 0x3e, + 0xe9, 0x42, 0x68, 0x3a, 0x80, 0x27, 0xd2, 0x2e, 0x5c, 0x95, 0xd1, 0xac, + 0x1c, 0xf4, 0xe8, 0x4e, 0xa1, 0x27, 0x57, 0x09, 0x6d, 0xd4, 0x42, 0x24, + 0xe4, 0x16, 0x12, 0x9a, 0x8f, 0xbb, 0xa0, 0x17, 0x43, 0x70, 0x37, 0x2b, + 0xd0, 0x9b, 0xc9, 0x8d, 0xfc, 0x12, 0xaa, 0xc8, 0x2f, 0x36, 0x8d, 0x47, + 0xe9, 0x5e, 0x80, 0xee, 0xe1, 0xca, 0x6a, 0xc8, 0xcb, 0x64, 0x90, 0xdc, + 0x74, 0x19, 0x49, 0x97, 0x6d, 0xcb, 0x7a, 0x1b, 0xfa, 0x1e, 0xa1, 0xeb, + 0x1a, 0x1e, 0xaf, 0x22, 0x5c, 0x24, 0x19, 0x34, 0x13, 0x4d, 0x59, 0xa2, + 0x31, 0x4b, 0x34, 0x66, 0x89, 0xc6, 0xac, 0x4c, 0x36, 0xa3, 0x19, 0xc0, + 0x1f, 0x92, 0xae, 0x42, 0xc4, 0xdf, 0x9b, 0x8e, 0x9e, 0x9e, 0x2a, 0x05, + 0x89, 0xfe, 0x90, 0x43, 0xff, 0x63, 0xa3, 0x02, 0x92, 0xae, 0xf5, 0x9c, + 0xc5, 0x7a, 0x84, 0x63, 0x5a, 0x32, 0x87, 0x24, 0xbd, 0xa7, 0xed, 0xb3, + 0xa0, 0x75, 0x95, 0x49, 0xff, 0x5b, 0xd5, 0x04, 0xe6, 0xb2, 0x6e, 0xd4, + 0xe8, 0x5a, 0x88, 0xf4, 0x15, 0x2d, 0x63, 0x09, 0xee, 0x56, 0x69, 0x4e, + 0xa9, 0x4a, 0x54, 0x62, 0xc8, 0x43, 0x88, 0x8c, 0x4b, 0x98, 0x35, 0x64, + 0xf2, 0x4f, 0x03, 0x72, 0x33, 0x2d, 0x57, 0x8c, 0xd3, 0x95, 0xe6, 0xcf, + 0xd2, 0x5a, 0x44, 0x0f, 0xcd, 0x47, 0x7e, 0xc9, 0x72, 0x8c, 0x12, 0x0d, + 0x7b, 0x1c, 0x7a, 0x9f, 0x2c, 0x75, 0x8b, 0x8a, 0xfd, 0x98, 0x64, 0x2f, + 0x5a, 0x08, 0x42, 0x8b, 0x86, 0x84, 0x66, 0x24, 0x85, 0x8a, 0x99, 0xd2, + 0x8f, 0x68, 0x4c, 0xe0, 0xb2, 0x31, 0x3d, 0x18, 0xce, 0x0a, 0x5c, 0xaf, + 0xdb, 0xd8, 0x60, 0xf4, 0x60, 0x57, 0x69, 0xd1, 0x2f, 0x39, 0x76, 0xa9, + 0xfe, 0x99, 0x74, 0x27, 0x76, 0x67, 0x43, 0xd8, 0x95, 0x0f, 0xfa, 0xa7, + 0xd3, 0xfc, 0x4c, 0x27, 0x7f, 0xe7, 0x67, 0x81, 0xcb, 0x9e, 0x35, 0x5d, + 0xf6, 0x2c, 0x81, 0xe1, 0x89, 0xaf, 0x50, 0x0c, 0xa9, 0xc3, 0x2e, 0xfd, + 0x63, 0xb2, 0x15, 0x3d, 0xb1, 0x0d, 0x8d, 0x38, 0xab, 0xb6, 0xe2, 0xe0, + 0x54, 0x37, 0x76, 0x4f, 0xad, 0xc6, 0xfe, 0x89, 0xa6, 0x94, 0xd7, 0x1c, + 0xa1, 0xf5, 0xc3, 0xc9, 0x6d, 0x42, 0x1b, 0x90, 0x45, 0x38, 0xba, 0x8d, + 0x6c, 0xb7, 0xb9, 0xde, 0xb6, 0x4f, 0xc6, 0xc8, 0xb6, 0x8d, 0x16, 0x63, + 0x13, 0x09, 0xa0, 0xdc, 0xa3, 0x75, 0xbd, 0x0d, 0x1f, 0xbe, 0x4e, 0x36, + 0x37, 0x13, 0xc3, 0x36, 0x19, 0x72, 0xab, 0x0f, 0xbf, 0xb0, 0x8f, 0xba, + 0x58, 0xee, 0xf6, 0xd0, 0xed, 0xc6, 0x1e, 0xc1, 0x71, 0xae, 0xea, 0x52, + 0x2c, 0xe1, 0xf9, 0xf9, 0x1d, 0xdb, 0x0e, 0xd3, 0x3c, 0xfd, 0xb1, 0x96, + 0x44, 0x3f, 0xe6, 0xed, 0xb3, 0xbd, 0xdd, 0xd8, 0x35, 0xb7, 0x1a, 0x07, + 0x26, 0xdc, 0x48, 0xd6, 0x0b, 0xd4, 0xe9, 0xe1, 0xf2, 0xdd, 0x58, 0x0d, + 0x6b, 0x86, 0xdf, 0xeb, 0xc6, 0xe1, 0xb9, 0xca, 0xf7, 0xec, 0xa5, 0xef, + 0x8b, 0xf3, 0x5d, 0x20, 0x9d, 0xb2, 0x3c, 0x39, 0x4e, 0x92, 0x0a, 0xcc, + 0x16, 0x9c, 0x98, 0x08, 0x90, 0x6e, 0x3b, 0x85, 0xeb, 0xf8, 0x32, 0xbf, + 0xf7, 0x11, 0x1b, 0xa7, 0x0c, 0xd2, 0x73, 0x76, 0xa3, 0xf0, 0x1e, 0xef, + 0x12, 0xee, 0xe2, 0x16, 0x51, 0x35, 0xfd, 0x2d, 0xa1, 0x1c, 0x4f, 0x89, + 0xea, 0x62, 0x2b, 0xc9, 0xbe, 0x4f, 0x78, 0x8e, 0x6b, 0xa1, 0x90, 0xf8, + 0x03, 0xd2, 0x67, 0xaf, 0x90, 0x8b, 0x50, 0x25, 0x73, 0x50, 0x48, 0x45, + 0x9a, 0xc3, 0xb1, 0x21, 0x5e, 0x27, 0x48, 0x7a, 0x83, 0x25, 0x9b, 0x03, + 0xd8, 0x4a, 0x39, 0xe2, 0xa6, 0xb4, 0x89, 0x03, 0xd9, 0x6a, 0x8a, 0x8f, + 0xec, 0xf7, 0xf3, 0xb4, 0xae, 0x8e, 0x83, 0x25, 0x58, 0x1e, 0xf3, 0x00, + 0x56, 0x93, 0xbf, 0x9d, 0x89, 0xb1, 0x2f, 0x02, 0xf9, 0x6c, 0x38, 0x79, + 0x40, 0xd8, 0x76, 0x75, 0xc4, 0x5e, 0x7e, 0xde, 0x68, 0x89, 0xbe, 0x88, + 0xff, 0x6d, 0xe7, 0x02, 0x03, 0x88, 0xb6, 0x43, 0xa9, 0x36, 0x77, 0xe3, + 0xe7, 0x69, 0x28, 0x55, 0xa6, 0x85, 0x53, 0x69, 0xc0, 0x37, 0x32, 0xac, + 0x7a, 0x41, 0x76, 0x80, 0x70, 0xf0, 0xa0, 0xd0, 0x7a, 0xce, 0x51, 0x3a, + 0x4b, 0xb4, 0x5b, 0x83, 0x12, 0x28, 0x1e, 0x09, 0xad, 0xef, 0x45, 0xb2, + 0xc7, 0x3f, 0x10, 0x9a, 0x3a, 0x2f, 0xd8, 0x4f, 0x39, 0x97, 0xec, 0x5e, + 0xc8, 0x29, 0x16, 0xae, 0xba, 0x2c, 0xa7, 0x0c, 0x13, 0x5d, 0x7b, 0x89, + 0xae, 0x97, 0x0c, 0x2d, 0x38, 0x0d, 0x7b, 0xf9, 0x36, 0x83, 0x9f, 0x99, + 0xd8, 0x5d, 0xb2, 0x43, 0x2e, 0x93, 0x65, 0x05, 0x4b, 0x31, 0x7f, 0x65, + 0x0f, 0xc7, 0x55, 0x92, 0x11, 0x79, 0x5a, 0xe1, 0xcb, 0x72, 0xad, 0x8d, + 0xe5, 0x34, 0xe6, 0x93, 0x6b, 0xe1, 0x6f, 0x2c, 0xb8, 0x52, 0x35, 0x26, + 0x7a, 0xee, 0x1b, 0xa1, 0xf8, 0xa4, 0x4b, 0x14, 0x9b, 0xf4, 0xc4, 0xbc, + 0xf0, 0x25, 0xde, 0x8f, 0x7b, 0x04, 0xc5, 0xa6, 0x54, 0xb5, 0x19, 0xec, + 0xfe, 0x20, 0xef, 0x21, 0xfd, 0xa2, 0x67, 0x67, 0x21, 0xe1, 0x7a, 0x97, + 0x6c, 0xac, 0x8a, 0x62, 0x29, 0x0a, 0x4d, 0xdd, 0x17, 0x29, 0xff, 0xdc, + 0x10, 0xf3, 0xfc, 0xab, 0x2a, 0x53, 0xba, 0xd2, 0x83, 0xfb, 0xaf, 0x99, + 0x4d, 0xd4, 0x51, 0x3c, 0x57, 0x71, 0x3a, 0xde, 0x85, 0xe1, 0x52, 0x35, + 0xd9, 0xdf, 0xd3, 0xe5, 0x3d, 0x7a, 0x53, 0xf7, 0xbb, 0xe9, 0xe5, 0xf0, + 0x99, 0xf8, 0xf4, 0x60, 0xbb, 0xde, 0x75, 0x93, 0x38, 0xd9, 0xe8, 0x41, + 0x9c, 0x6d, 0x5c, 0x99, 0x4f, 0xe3, 0xe3, 0x46, 0x5d, 0xa7, 0xdc, 0xd1, + 0x3c, 0x70, 0x41, 0x34, 0x27, 0xce, 0x0b, 0x81, 0xf3, 0xad, 0x02, 0x67, + 0xae, 0x8e, 0x24, 0xcf, 0xc0, 0x03, 0xdc, 0x9c, 0x20, 0xfb, 0x68, 0x4a, + 0xc9, 0xa6, 0x82, 0x6d, 0x69, 0xf6, 0x63, 0xb2, 0xeb, 0x19, 0x3c, 0x74, + 0xc4, 0xe8, 0x86, 0x35, 0xc7, 0xb6, 0xd3, 0x8a, 0x23, 0x73, 0x3d, 0xb0, + 0x4a, 0x32, 0x72, 0x01, 0x93, 0xae, 0x48, 0xb9, 0xcd, 0xd6, 0xce, 0x5c, + 0x7e, 0xab, 0xbb, 0xe2, 0xbb, 0x24, 0x83, 0xec, 0xbd, 0x7e, 0x78, 0x59, + 0xbf, 0xa7, 0x49, 0x36, 0xad, 0x78, 0xba, 0x14, 0xa5, 0x18, 0x67, 0x90, + 0x6c, 0x74, 0x8a, 0x13, 0x21, 0xb2, 0x2b, 0x05, 0x5b, 0x27, 0xb4, 0xc3, + 0x14, 0x0f, 0x46, 0x73, 0x68, 0x47, 0x32, 0xa0, 0x52, 0xce, 0x3e, 0xb5, + 0xe0, 0xfb, 0xdb, 0xe9, 0xaa, 0x59, 0x49, 0xe0, 0x45, 0x09, 0x68, 0x6b, + 0x34, 0x23, 0xfb, 0x1a, 0x49, 0x0f, 0xf5, 0x45, 0x0f, 0xee, 0x9b, 0x68, + 0xc0, 0xbd, 0x53, 0x5e, 0xec, 0x98, 0xb0, 0xf1, 0x7e, 0x8c, 0x6d, 0x42, + 0xeb, 0x23, 0x6f, 0xea, 0xac, 0x21, 0xd9, 0x6e, 0x8e, 0x45, 0x12, 0x1e, + 0xe1, 0x42, 0x75, 0xb1, 0x87, 0x72, 0x7f, 0x92, 0xfd, 0xc1, 0xa0, 0x39, + 0x42, 0xbb, 0x8c, 0xaf, 0x23, 0x15, 0x50, 0xe0, 0x2e, 0xfa, 0x28, 0x86, + 0xb0, 0xff, 0xf2, 0xb3, 0x6f, 0x60, 0x6b, 0x95, 0x0f, 0x72, 0x46, 0xc1, + 0x28, 0xe5, 0x7d, 0x2c, 0xab, 0x42, 0x57, 0xb3, 0x44, 0x9f, 0x80, 0x7f, + 0x76, 0xb2, 0xc9, 0x7f, 0x8c, 0xe2, 0xea, 0x9d, 0x59, 0x89, 0xd7, 0x61, + 0x9c, 0x40, 0x73, 0xab, 0x78, 0x8c, 0x62, 0xf4, 0x03, 0x14, 0x77, 0x4e, + 0x94, 0xf2, 0x82, 0xe3, 0x88, 0xc3, 0x4f, 0x96, 0x78, 0xcb, 0x12, 0x6f, + 0x59, 0xe2, 0x8b, 0xe2, 0xc1, 0x93, 0x59, 0xe6, 0xe3, 0x23, 0xf2, 0xcd, + 0x04, 0xf1, 0xee, 0xc1, 0x76, 0xa2, 0xf7, 0xfe, 0xa9, 0x1a, 0xdc, 0x43, + 0xf4, 0x16, 0x0d, 0xad, 0xef, 0x2f, 0x84, 0x8d, 0x7c, 0x4c, 0xb3, 0x76, + 0x0a, 0x2f, 0xa4, 0x66, 0xdb, 0xee, 0x31, 0x98, 0x67, 0xb2, 0x4f, 0xc9, + 0xe1, 0x79, 0x5f, 0x92, 0xe4, 0xdf, 0x4f, 0xef, 0x6c, 0x9b, 0xc2, 0xa7, + 0x12, 0xf1, 0xe4, 0x21, 0x1e, 0x0f, 0x18, 0x5a, 0x62, 0x15, 0xc5, 0xf3, + 0x73, 0x7a, 0xa4, 0x7c, 0x4e, 0xc6, 0xd7, 0x48, 0x1e, 0x06, 0xcb, 0xa3, + 0x99, 0xf8, 0xb9, 0x8f, 0x30, 0x8e, 0xdf, 0x64, 0x3e, 0x23, 0xd1, 0x5f, + 0x10, 0xef, 0x91, 0x62, 0xc0, 0x7f, 0xe6, 0x50, 0x93, 0xff, 0xa5, 0x91, + 0x0a, 0xfd, 0x3b, 0x89, 0xfe, 0xd9, 0x98, 0x8d, 0x83, 0x44, 0xff, 0x13, + 0x44, 0x7f, 0x3f, 0xc7, 0xf1, 0x05, 0xfa, 0x4f, 0x94, 0x78, 0xdd, 0x2f, + 0xe3, 0x61, 0x91, 0xfe, 0x06, 0x6c, 0x9d, 0x5a, 0x94, 0x97, 0x6d, 0xdf, + 0x66, 0x3c, 0x63, 0xff, 0x1e, 0xc9, 0x6c, 0x79, 0x91, 0xe5, 0xc6, 0xf8, + 0x2d, 0x72, 0xf8, 0x4e, 0xdc, 0x21, 0xc1, 0xeb, 0xc3, 0x92, 0x22, 0xe7, + 0x80, 0x10, 0x9e, 0x21, 0xfd, 0x3e, 0x4f, 0x39, 0xec, 0xe9, 0xd2, 0xe5, + 0x39, 0x8d, 0x75, 0x3d, 0x49, 0x3a, 0xd6, 0x72, 0x16, 0xc5, 0xb4, 0x54, + 0x29, 0x89, 0x3d, 0x53, 0x48, 0xce, 0x1a, 0x7f, 0x46, 0x81, 0x65, 0x19, + 0x64, 0xbd, 0x3a, 0xa9, 0xea, 0x5e, 0xdc, 0x3e, 0x13, 0xc0, 0x40, 0x69, + 0x03, 0xb2, 0x14, 0x67, 0x76, 0x52, 0x5c, 0xfe, 0x30, 0x96, 0xdc, 0xe1, + 0x47, 0x84, 0xf4, 0x1b, 0xc0, 0xdd, 0xf4, 0xce, 0x81, 0x29, 0xa6, 0x5f, + 0x5d, 0xd0, 0x73, 0x00, 0x77, 0xd2, 0xbd, 0xbd, 0x53, 0x0a, 0x5e, 0x30, + 0x8e, 0x10, 0x8e, 0xa9, 0xe0, 0x8a, 0x3b, 0xb2, 0x50, 0xc9, 0x2d, 0x09, + 0xf7, 0x45, 0xa2, 0x2f, 0xd0, 0xf7, 0xed, 0x25, 0xaf, 0x7f, 0x78, 0x12, + 0xdf, 0x59, 0x6e, 0xfa, 0xb1, 0x84, 0x30, 0xd8, 0x2d, 0x46, 0xa4, 0xbc, + 0x9e, 0x30, 0xd3, 0x60, 0x49, 0xc2, 0xb7, 0x67, 0xbc, 0x78, 0x60, 0xe2, + 0x53, 0xbb, 0x2a, 0xee, 0xc2, 0xcd, 0xcd, 0x5e, 0xdc, 0x3f, 0x93, 0xc4, + 0xbe, 0x29, 0x84, 0xaa, 0x63, 0x63, 0x14, 0xb3, 0x2b, 0x79, 0xa0, 0x86, + 0x78, 0xdf, 0x3f, 0xe5, 0xf3, 0xf7, 0x1f, 0x62, 0x19, 0x6c, 0x08, 0x92, + 0x77, 0x94, 0xab, 0x63, 0x32, 0xb6, 0x1b, 0xf2, 0x92, 0x6a, 0x32, 0xf4, + 0x23, 0x34, 0xdf, 0x34, 0xe4, 0x57, 0x97, 0x23, 0x72, 0xb8, 0x51, 0x2e, + 0x8f, 0x2e, 0x41, 0x03, 0x1e, 0x98, 0x4b, 0x62, 0x8c, 0x6c, 0xf4, 0xbe, + 0x89, 0xe1, 0xef, 0xd4, 0x53, 0xec, 0xf0, 0xb7, 0x69, 0xfd, 0x6f, 0x08, + 0x13, 0xf9, 0x88, 0x07, 0x3b, 0x67, 0x7c, 0xfe, 0x1d, 0x87, 0xec, 0xf5, + 0x6c, 0x4f, 0x77, 0xcd, 0x35, 0xe0, 0x9e, 0x29, 0xba, 0x37, 0xc1, 0x36, + 0x4c, 0xb6, 0x16, 0xa9, 0x26, 0xde, 0xc2, 0x49, 0x0f, 0xe1, 0x24, 0x39, + 0x56, 0x43, 0xf2, 0xf0, 0xe0, 0x4e, 0xc7, 0x16, 0x54, 0x6c, 0x9f, 0xb2, + 0xf1, 0x96, 0x11, 0xc5, 0x28, 0xd9, 0xf5, 0xe1, 0x29, 0x6d, 0xbe, 0x93, + 0x30, 0xce, 0x3b, 0xb2, 0x76, 0xb8, 0x59, 0x4e, 0xa2, 0x61, 0x0d, 0xc5, + 0xf6, 0x06, 0xdb, 0xbe, 0xa3, 0xad, 0x65, 0xe0, 0xc7, 0x44, 0x73, 0xbd, + 0xb9, 0x0c, 0xe5, 0x7a, 0x6d, 0x14, 0x68, 0x19, 0xac, 0x92, 0xae, 0xc6, + 0xd9, 0xa5, 0x1c, 0xff, 0x38, 0x86, 0x07, 0xfc, 0x0d, 0x99, 0x4a, 0x6e, + 0x6b, 0x28, 0x36, 0xf9, 0xeb, 0x33, 0x41, 0x7f, 0x7d, 0x11, 0xfe, 0xaa, + 0x22, 0xf0, 0x03, 0x8a, 0x2f, 0x4b, 0xd6, 0xfc, 0xca, 0x4e, 0x35, 0x38, + 0x38, 0xd0, 0xff, 0xdc, 0xa4, 0x66, 0x95, 0xa1, 0xed, 0xa3, 0x70, 0x89, + 0x47, 0xe7, 0x5c, 0xfe, 0xe3, 0x14, 0x07, 0x1a, 0xf4, 0x28, 0xf6, 0x92, + 0x3e, 0x87, 0xc8, 0x16, 0x7e, 0xb1, 0x06, 0xd8, 0x9f, 0x09, 0x87, 0x0c, + 0xd1, 0x47, 0x13, 0x03, 0xbb, 0x8b, 0x14, 0xeb, 0xa5, 0xdf, 0xa2, 0x40, + 0xa6, 0x45, 0x29, 0x9d, 0x21, 0x9d, 0x71, 0xc3, 0x5a, 0x5a, 0xd1, 0xc9, + 0x3d, 0xd9, 0xe7, 0x6d, 0xbf, 0xae, 0xe7, 0x8a, 0xa4, 0xb3, 0x07, 0x4b, + 0x3e, 0x0c, 0x12, 0x0e, 0x58, 0x42, 0xd8, 0xf1, 0x7e, 0xb2, 0x8b, 0xfb, + 0x26, 0x64, 0xa2, 0x8f, 0xc7, 0x25, 0x91, 0x5c, 0x56, 0xc1, 0xa0, 0x0f, + 0xcc, 0xb0, 0x5d, 0x92, 0x1d, 0x91, 0x2d, 0x3e, 0x43, 0xb9, 0xfe, 0xe9, + 0xcf, 0x61, 0x0f, 0x4d, 0xb5, 0x2e, 0xe5, 0xfc, 0x8a, 0x3c, 0x86, 0xa7, + 0x98, 0x67, 0xed, 0x30, 0xa4, 0x24, 0x6e, 0x30, 0x7e, 0x42, 0xb9, 0x80, + 0x79, 0x27, 0xec, 0x3b, 0x15, 0xc5, 0xc3, 0x59, 0xc2, 0x32, 0xb1, 0xf7, + 0xed, 0x3b, 0x03, 0x2c, 0x03, 0xe6, 0x27, 0x2e, 0x73, 0xde, 0x6c, 0x20, + 0xcc, 0xfb, 0xff, 0x6f, 0x77, 0xb7, 0xdb, 0x29, 0x07, 0xc3, 0x12, 0xb6, + 0x26, 0x7b, 0x4a, 0x5d, 0xb2, 0x9f, 0xfb, 0xed, 0xb3, 0x01, 0xce, 0xd3, + 0x0d, 0x48, 0x5d, 0xb2, 0x05, 0xb6, 0x25, 0x2c, 0x37, 0xda, 0x76, 0xdd, + 0xaf, 0x82, 0xed, 0x21, 0x7a, 0x99, 0x3d, 0xb8, 0x89, 0x26, 0x15, 0x3b, + 0xe6, 0xd8, 0x7e, 0xed, 0x8f, 0x96, 0x9b, 0xff, 0x40, 0x39, 0x42, 0x3f, + 0xfc, 0x13, 0xdc, 0x48, 0xf7, 0x03, 0xf8, 0x36, 0xf9, 0xd1, 0xdd, 0xc4, + 0xe7, 0x8e, 0xf6, 0xbb, 0x1d, 0xbf, 0xdd, 0x51, 0xba, 0x8e, 0xee, 0xb3, + 0xbc, 0x3b, 0xb1, 0x2f, 0x6b, 0x20, 0x9d, 0x2d, 0x3b, 0xf9, 0xc7, 0x65, + 0xc6, 0xf1, 0x7d, 0x8a, 0xb3, 0xcf, 0x94, 0x18, 0x8b, 0x25, 0x1c, 0x1c, + 0xf6, 0xbd, 0x52, 0x2b, 0x9e, 0x25, 0x9f, 0x7c, 0x9a, 0x62, 0xee, 0x77, + 0x1d, 0x7c, 0xe6, 0x12, 0x07, 0xd3, 0x84, 0x45, 0x47, 0x2c, 0xa4, 0xf3, + 0x21, 0x78, 0x0e, 0x85, 0xf7, 0xed, 0x10, 0xda, 0x0f, 0x48, 0x5e, 0xfe, + 0xfd, 0xb3, 0x2b, 0x50, 0x7d, 0x48, 0xcb, 0x11, 0xdd, 0xfe, 0x87, 0x67, + 0x75, 0xc2, 0xd2, 0x41, 0xff, 0xde, 0xbc, 0xea, 0xdf, 0x33, 0x19, 0xf0, + 0xef, 0x99, 0x6d, 0x20, 0x3f, 0x5a, 0xe6, 0x1f, 0x9e, 0x0d, 0xfa, 0x77, + 0xa5, 0x9b, 0xfc, 0xbb, 0xf2, 0x6b, 0x10, 0x6a, 0x80, 0xb5, 0x8c, 0x72, + 0xc4, 0x3d, 0x13, 0xdf, 0x44, 0xae, 0xbe, 0x12, 0xf7, 0x07, 0xc8, 0x36, + 0xea, 0xc8, 0x0e, 0xaf, 0x91, 0x6e, 0x46, 0x79, 0x69, 0xe5, 0xde, 0xb7, + 0xe9, 0xde, 0x03, 0x6d, 0xf0, 0xff, 0xa5, 0x13, 0x7b, 0x81, 0x67, 0xc9, + 0xd6, 0x9e, 0x69, 0xa3, 0x7a, 0xf2, 0x92, 0xad, 0xb9, 0x28, 0xde, 0xda, + 0xb6, 0xb1, 0x46, 0x20, 0xd8, 0xb6, 0x11, 0x58, 0xb2, 0x58, 0x43, 0x26, + 0x73, 0xae, 0xb6, 0x24, 0x96, 0xeb, 0x9b, 0x70, 0x44, 0xa5, 0x54, 0xd3, + 0xf6, 0x35, 0x2c, 0xbc, 0x83, 0x6f, 0x4f, 0x78, 0x90, 0xda, 0xa2, 0x62, + 0x96, 0x30, 0xca, 0x5d, 0x34, 0xff, 0xca, 0x58, 0x8b, 0x3a, 0x47, 0x7a, + 0x48, 0xaa, 0x7c, 0x8f, 0x7c, 0xa2, 0x6d, 0x2d, 0xf9, 0x44, 0x65, 0xfd, + 0xa7, 0x48, 0x5f, 0xa3, 0x73, 0x51, 0xec, 0x29, 0xfd, 0x40, 0xaa, 0xe4, + 0x17, 0x2d, 0x97, 0xc4, 0x69, 0x67, 0xec, 0x53, 0xd9, 0x37, 0xec, 0x90, + 0x63, 0x77, 0x02, 0x8f, 0xac, 0x8e, 0xec, 0xfb, 0xef, 0x52, 0x23, 0xf1, + 0x45, 0xb2, 0xcb, 0x3a, 0xf5, 0x63, 0xdd, 0x15, 0xfa, 0xbf, 0xc5, 0xf7, + 0x55, 0x96, 0xed, 0xa0, 0xd8, 0x47, 0x75, 0x2a, 0x95, 0x4c, 0x75, 0x4b, + 0xf4, 0x43, 0x78, 0xba, 0x87, 0xef, 0x05, 0xfc, 0xfb, 0x27, 0x93, 0x52, + 0x40, 0x87, 0xea, 0x36, 0x3b, 0xc5, 0xfe, 0xd9, 0x65, 0xfe, 0x87, 0x27, + 0x37, 0x8a, 0x87, 0x67, 0x9b, 0xfc, 0xc3, 0xe9, 0x2e, 0x31, 0x9c, 0xdf, + 0x22, 0xac, 0xdc, 0xb7, 0x84, 0x35, 0x9b, 0x12, 0x56, 0xbe, 0x8f, 0xae, + 0xbd, 0x62, 0x32, 0x3f, 0x28, 0xf6, 0xe4, 0x79, 0x7e, 0xd2, 0x15, 0xad, + 0xf1, 0x3d, 0x8a, 0xbd, 0xcf, 0x52, 0xec, 0x7d, 0x86, 0x62, 0xef, 0xd3, + 0x64, 0xef, 0xdf, 0xbd, 0x84, 0x6d, 0xd9, 0xc6, 0x93, 0x8c, 0x49, 0xfc, + 0x7f, 0x51, 0x3c, 0x49, 0xfa, 0x66, 0xd9, 0xfd, 0x27, 0xb2, 0x6d, 0x96, + 0xc9, 0x03, 0x9c, 0x2b, 0x48, 0x4f, 0x17, 0x1d, 0x5b, 0x7e, 0x64, 0x35, + 0x63, 0xa8, 0x41, 0xb1, 0x95, 0xe8, 0x4b, 0xba, 0x08, 0xfb, 0xe8, 0x84, + 0x4b, 0xb2, 0x83, 0xe2, 0x8e, 0x3c, 0xdf, 0x3f, 0x80, 0x9d, 0x54, 0x0b, + 0x1e, 0x8c, 0x85, 0x7b, 0xb6, 0x11, 0x66, 0xda, 0x4c, 0x98, 0x69, 0x65, + 0x4c, 0xc1, 0x85, 0xd6, 0x4f, 0x6c, 0x2c, 0x45, 0xf2, 0xde, 0xb8, 0x96, + 0xcb, 0x55, 0xf2, 0xed, 0x68, 0x06, 0x5c, 0xaf, 0xa3, 0xae, 0x56, 0xd7, + 0x4e, 0x24, 0x11, 0xde, 0x17, 0x97, 0x60, 0x55, 0x99, 0x6e, 0xdc, 0xe3, + 0xd4, 0x88, 0x1b, 0x30, 0x31, 0x21, 0xb0, 0xbd, 0x2d, 0xf9, 0x87, 0x6e, + 0x92, 0xd5, 0x3b, 0xed, 0x08, 0x90, 0x7a, 0x85, 0x42, 0xf5, 0x7c, 0x17, + 0x49, 0xaf, 0x93, 0x72, 0xee, 0x91, 0xec, 0x5a, 0x34, 0xb6, 0x29, 0xa4, + 0x43, 0x17, 0x6e, 0x2b, 0xde, 0x40, 0x7a, 0x8c, 0x1c, 0x7e, 0x0e, 0x5e, + 0xff, 0x0b, 0x93, 0x26, 0x46, 0xb2, 0xf8, 0x8e, 0x8f, 0x6a, 0xb7, 0xbb, + 0x09, 0x37, 0x7d, 0x97, 0x68, 0xd8, 0xd4, 0x16, 0xe9, 0xa2, 0x1a, 0x5e, + 0xf5, 0x9a, 0x55, 0x18, 0x6f, 0xf6, 0x43, 0xd5, 0x53, 0xe2, 0x95, 0x7c, + 0xe4, 0xf0, 0x0e, 0xe9, 0x5b, 0xe2, 0xc7, 0xb3, 0x26, 0x1e, 0x2e, 0xf5, + 0x89, 0xbf, 0x9c, 0x55, 0x40, 0xba, 0xa1, 0xb8, 0x65, 0xe0, 0x30, 0xd1, + 0xe5, 0x26, 0x9c, 0xe4, 0xfe, 0x1d, 0x81, 0x2b, 0xf4, 0x24, 0xbe, 0xbd, + 0x96, 0x7d, 0xa1, 0x12, 0xd3, 0x5c, 0x6b, 0x81, 0x7d, 0x64, 0x93, 0x8d, + 0x99, 0x4e, 0xb1, 0x9c, 0xfe, 0xbf, 0x40, 0x79, 0x2d, 0x29, 0x75, 0x89, + 0x46, 0xc2, 0xa4, 0x4b, 0xa7, 0x7b, 0xc5, 0x92, 0x22, 0x63, 0x50, 0xa8, + 0x4b, 0x49, 0x46, 0x4b, 0x8b, 0xe7, 0xe5, 0x0a, 0xf6, 0x77, 0xb3, 0x2d, + 0x59, 0x3e, 0x53, 0xf1, 0x1f, 0xa4, 0xd8, 0xbe, 0x23, 0xd6, 0x45, 0xf8, + 0x98, 0xef, 0x0f, 0x8a, 0x11, 0x92, 0x63, 0xce, 0xed, 0xd8, 0x8e, 0xff, + 0xc8, 0x24, 0xdc, 0x8d, 0x26, 0x42, 0x55, 0x94, 0x3b, 0xfe, 0xe7, 0x9a, + 0x88, 0xf5, 0x9c, 0xd4, 0x2d, 0x46, 0xf3, 0x01, 0xff, 0xe1, 0x49, 0xce, + 0x33, 0x9d, 0xe2, 0x30, 0xe9, 0x3c, 0x4b, 0x3a, 0xcf, 0x92, 0xce, 0x33, + 0xa4, 0xf3, 0xcc, 0x97, 0xe8, 0x7c, 0x2f, 0xe9, 0x7c, 0x57, 0xfe, 0x63, + 0x47, 0x87, 0x2e, 0xd3, 0x44, 0x96, 0xf2, 0xf2, 0x78, 0x73, 0x85, 0xbf, + 0x0f, 0x49, 0x16, 0xa7, 0x62, 0x5f, 0x77, 0xc1, 0x6b, 0x52, 0x6c, 0xed, + 0xa6, 0x77, 0xbe, 0xb2, 0x60, 0xe3, 0xaa, 0x7f, 0x6c, 0xb2, 0x53, 0x8c, + 0x91, 0xdf, 0x8d, 0xd3, 0xfc, 0xe3, 0xe4, 0x77, 0xc3, 0xe9, 0x7f, 0x8e, + 0xdd, 0xb0, 0xdd, 0xc1, 0xf2, 0x52, 0xde, 0xaa, 0x21, 0xbb, 0x74, 0x99, + 0x6c, 0x43, 0x5b, 0x44, 0xf2, 0xe8, 0xb7, 0x44, 0xf2, 0x58, 0x4a, 0x24, + 0x0b, 0x7d, 0x74, 0xed, 0x15, 0x37, 0x39, 0xf5, 0xe7, 0xa0, 0xe8, 0x2c, + 0x04, 0xfc, 0x53, 0xb4, 0xce, 0x14, 0xf1, 0xf1, 0x08, 0xad, 0xf3, 0x88, + 0x63, 0xbb, 0xe3, 0x2e, 0xce, 0xff, 0xcf, 0x67, 0xd9, 0xce, 0xd8, 0xbe, + 0xde, 0x25, 0xda, 0xd9, 0x37, 0x2e, 0xf5, 0x76, 0xe8, 0xaf, 0x5d, 0x86, + 0xbe, 0xc3, 0x55, 0xe1, 0x89, 0x73, 0x3f, 0xe7, 0x7a, 0x8e, 0xc3, 0xaa, + 0x53, 0x03, 0x3e, 0x73, 0x09, 0x03, 0x30, 0x1e, 0x80, 0xb2, 0xc4, 0x7c, + 0xb0, 0xe3, 0xdb, 0xcd, 0xff, 0x8b, 0xe6, 0x1b, 0x80, 0xb1, 0x16, 0x4a, + 0xc0, 0xfc, 0x65, 0xc7, 0x64, 0x33, 0xc5, 0x69, 0x9a, 0x53, 0xc9, 0x00, + 0x7a, 0x46, 0x60, 0x57, 0x42, 0x10, 0x8e, 0x5d, 0x46, 0x7e, 0xc9, 0xf4, + 0x6b, 0x5d, 0x49, 0x7a, 0xb6, 0x62, 0x04, 0xca, 0x72, 0x73, 0x27, 0xec, + 0x2c, 0x94, 0x3a, 0xb3, 0x1f, 0x1f, 0x8d, 0x84, 0x83, 0x5d, 0xd0, 0x52, + 0xe7, 0x64, 0xad, 0x4c, 0xf9, 0x6d, 0x60, 0x97, 0xd0, 0xfa, 0xe7, 0x05, + 0xf7, 0x87, 0x18, 0xb3, 0xef, 0x44, 0xab, 0x83, 0xdd, 0xfb, 0xd1, 0x92, + 0x07, 0xd5, 0xdf, 0x84, 0x6b, 0x69, 0xce, 0x97, 0x8c, 0x0f, 0x38, 0x27, + 0x24, 0x09, 0x0b, 0x7e, 0x61, 0x2e, 0x10, 0x8e, 0xe1, 0x79, 0x78, 0x8e, + 0xb0, 0xda, 0x4f, 0xf3, 0xbe, 0x25, 0xb7, 0x0c, 0x0c, 0x0b, 0x2d, 0xf1, + 0xc5, 0xf9, 0x56, 0xe6, 0x21, 0x56, 0x66, 0x2c, 0xbb, 0x46, 0xf7, 0x32, + 0x1e, 0x92, 0xce, 0xeb, 0x7a, 0xf2, 0x35, 0x84, 0xb0, 0x92, 0xea, 0xe3, + 0x68, 0x91, 0x79, 0x18, 0xc2, 0x8b, 0x86, 0xd6, 0x43, 0x55, 0x28, 0xd5, + 0x2b, 0x9d, 0x38, 0x40, 0xb1, 0xf7, 0xe1, 0x12, 0xf7, 0xb7, 0x06, 0xc5, + 0xaa, 0x11, 0xf2, 0x4b, 0xc7, 0x9e, 0xa0, 0x34, 0x9a, 0x0f, 0xe2, 0x3a, + 0x5a, 0xdf, 0x4f, 0x35, 0xcf, 0xeb, 0xb4, 0xbe, 0x94, 0xd1, 0x06, 0x69, + 0xfd, 0xd4, 0x1b, 0x22, 0x3c, 0x4f, 0x7c, 0xf5, 0xad, 0x97, 0x5b, 0xfa, + 0x87, 0x84, 0x96, 0x24, 0xd2, 0xc9, 0x8f, 0x79, 0xed, 0x07, 0x99, 0x17, + 0xba, 0x52, 0x7d, 0x43, 0x76, 0xd4, 0x5c, 0x50, 0x44, 0x64, 0x6c, 0x03, + 0xf6, 0xcc, 0x6c, 0xc0, 0x6e, 0xf2, 0xc7, 0xfd, 0x46, 0x1d, 0x42, 0xf5, + 0xa8, 0xad, 0xd3, 0x31, 0x7f, 0x4e, 0x17, 0xf2, 0x8e, 0xd6, 0x26, 0xb2, + 0xe3, 0x93, 0x8d, 0xd5, 0xf8, 0xd8, 0xde, 0xa6, 0x6f, 0xe8, 0xa2, 0x88, + 0x78, 0x9d, 0x07, 0x87, 0x64, 0xf2, 0xef, 0x37, 0x7f, 0x41, 0x01, 0xd5, + 0x63, 0x32, 0x6e, 0x4b, 0x88, 0x8b, 0xf9, 0x53, 0xae, 0x8a, 0x1f, 0x34, + 0xe3, 0x23, 0x15, 0x75, 0x41, 0x7d, 0x15, 0xe6, 0x55, 0x85, 0xe2, 0x85, + 0xe5, 0xd4, 0x62, 0x37, 0x8e, 0xf6, 0xa0, 0x91, 0xea, 0xe2, 0xdb, 0x62, + 0xbf, 0xb0, 0x3f, 0xb9, 0x82, 0xdf, 0xfb, 0x23, 0x4f, 0x25, 0x76, 0x7e, + 0xd9, 0x1c, 0x71, 0x8a, 0x37, 0x2d, 0x54, 0xc7, 0xd6, 0x50, 0x90, 0xee, + 0xa2, 0x7c, 0xa4, 0xf5, 0xa5, 0xa9, 0x0e, 0xed, 0x8f, 0xb4, 0x18, 0xb2, + 0xa8, 0x42, 0x39, 0x10, 0x1e, 0xd8, 0x86, 0xe4, 0x5d, 0xfe, 0x05, 0x3a, + 0x9e, 0x11, 0x2b, 0xdc, 0xf4, 0x1e, 0xcf, 0x73, 0x99, 0x3d, 0xe5, 0xc9, + 0x9e, 0xf8, 0x39, 0xff, 0x7f, 0xe9, 0xb9, 0xf2, 0x15, 0xf3, 0x97, 0xe6, + 0xbf, 0x5f, 0xf9, 0x65, 0xf7, 0x03, 0xeb, 0x7e, 0xfd, 0xfe, 0xff, 0xad, + 0x9e, 0x2f, 0xd7, 0xbb, 0x1c, 0xcc, 0x90, 0x94, 0xb8, 0x7f, 0xe9, 0x32, + 0x7d, 0x1d, 0xbb, 0xf5, 0xdf, 0xa0, 0x98, 0xc6, 0xfd, 0x0b, 0xce, 0xd3, + 0x67, 0x9d, 0xfe, 0xc5, 0xf3, 0x9f, 0xc3, 0xac, 0x1c, 0x5b, 0x3c, 0xa2, + 0x66, 0xdc, 0xb2, 0x1b, 0xf4, 0xdb, 0xa8, 0xae, 0x19, 0xc2, 0xb6, 0x98, + 0x81, 0xb1, 0xac, 0xd6, 0x73, 0x33, 0xf4, 0xe4, 0x16, 0x41, 0x13, 0x15, + 0x3d, 0x42, 0x1e, 0x5f, 0x78, 0x66, 0x58, 0x54, 0xab, 0x95, 0x51, 0x4d, + 0xb1, 0xc9, 0xa5, 0xab, 0x0a, 0x8a, 0x01, 0xc5, 0x55, 0x0c, 0x2a, 0x55, + 0xc5, 0x26, 0xa5, 0x9a, 0xc6, 0xf9, 0xc6, 0xb5, 0xf9, 0x9b, 0x31, 0x84, + 0xf9, 0x35, 0x5e, 0xab, 0xd1, 0xd4, 0xd4, 0x46, 0x79, 0x08, 0xbb, 0x63, + 0xfc, 0x6e, 0x27, 0xd5, 0x6c, 0x10, 0xf5, 0x19, 0x42, 0xc6, 0xa6, 0xc0, + 0x9e, 0x76, 0x6d, 0x70, 0x85, 0xa4, 0x77, 0xfd, 0xad, 0x70, 0x29, 0x9e, + 0x22, 0x84, 0x3f, 0x23, 0xe1, 0x70, 0x3b, 0x3c, 0x9e, 0xb5, 0x5a, 0xff, + 0x49, 0x31, 0x88, 0x27, 0x62, 0x91, 0x9e, 0xed, 0x22, 0xa4, 0x78, 0xe9, + 0x99, 0x3b, 0x43, 0xf1, 0x37, 0x63, 0x79, 0xdc, 0x6b, 0xb5, 0xa0, 0x24, + 0x92, 0xd8, 0xa6, 0xeb, 0xc6, 0x38, 0x14, 0x5a, 0x13, 0xa2, 0x3a, 0xa3, + 0xcd, 0xbf, 0x45, 0x98, 0xea, 0x93, 0x95, 0x83, 0x68, 0x5b, 0x13, 0xd9, + 0xd7, 0x27, 0xe9, 0x0a, 0x61, 0x3d, 0xe1, 0xca, 0xf8, 0x70, 0xcd, 0xa1, + 0xc5, 0x7e, 0x8e, 0x6d, 0x7f, 0x18, 0x2b, 0x93, 0x5e, 0xa0, 0xd4, 0x16, + 0xa3, 0x8a, 0x8f, 0x70, 0x7d, 0xcb, 0x21, 0xc6, 0x59, 0xb6, 0xbd, 0x23, + 0x56, 0xfe, 0x9a, 0x17, 0xad, 0xc4, 0x63, 0x0f, 0x66, 0xd2, 0x8c, 0xbb, + 0x4c, 0x4c, 0x53, 0x4d, 0xa4, 0x8f, 0x34, 0xe1, 0x38, 0xc5, 0xa1, 0xb9, + 0x34, 0xf7, 0x7d, 0xfa, 0x49, 0xc6, 0x7d, 0x44, 0x7f, 0x2f, 0xd5, 0xc1, + 0x29, 0x8a, 0x5f, 0x2c, 0xe3, 0x6d, 0x64, 0xf7, 0x50, 0xbc, 0x66, 0xac, + 0xe3, 0xc6, 0x31, 0x28, 0x1e, 0x73, 0x55, 0xc7, 0x55, 0x87, 0x50, 0x4f, + 0x79, 0xdf, 0xa4, 0x8a, 0x07, 0xd1, 0x48, 0xc4, 0xb8, 0x80, 0x48, 0xf0, + 0x25, 0xd2, 0xc7, 0xb0, 0x0e, 0xec, 0x72, 0x6a, 0x6c, 0x17, 0xac, 0x3c, + 0xd7, 0xcf, 0xf0, 0x54, 0xb7, 0xd7, 0xe3, 0xfc, 0xa8, 0xcb, 0xe9, 0x1d, + 0x59, 0x54, 0xff, 0xbc, 0x60, 0x68, 0xa9, 0x1c, 0xbd, 0xb7, 0x55, 0xfd, + 0xd9, 0xde, 0x9a, 0x38, 0x14, 0x8a, 0x69, 0x64, 0x7b, 0x7f, 0xe2, 0x7d, + 0x8b, 0x6c, 0xf4, 0x96, 0xc9, 0x3f, 0xf5, 0x7e, 0x14, 0xcf, 0x79, 0x3f, + 0x88, 0xdb, 0x76, 0x82, 0xf0, 0x68, 0x1f, 0xd5, 0xdc, 0x1f, 0x8e, 0x58, + 0xde, 0x0b, 0x71, 0xee, 0xff, 0xba, 0xf0, 0xdb, 0xf4, 0xfd, 0xb1, 0x11, + 0x05, 0x9b, 0x0b, 0x8d, 0x70, 0x8f, 0xc9, 0x98, 0x31, 0xae, 0xc7, 0x36, + 0x55, 0xc2, 0x1d, 0xd1, 0x27, 0xc9, 0x26, 0x25, 0x1a, 0x73, 0x90, 0xbe, + 0x73, 0x2f, 0xeb, 0x11, 0x6c, 0x57, 0x67, 0xbd, 0xe7, 0xe3, 0x4c, 0x6f, + 0x88, 0xe9, 0x55, 0x24, 0xfd, 0xeb, 0xd8, 0x7a, 0x33, 0xd7, 0x56, 0xce, + 0xc7, 0xf3, 0x52, 0x7b, 0x03, 0x8e, 0x8f, 0x36, 0xe2, 0xb9, 0x51, 0xcb, + 0xf3, 0x5a, 0x7b, 0x14, 0xfd, 0x23, 0x36, 0x5e, 0x36, 0xac, 0xc1, 0x6a, + 0xb2, 0xf3, 0x04, 0xd5, 0x57, 0xe1, 0x35, 0xdc, 0x43, 0x40, 0x44, 0x46, + 0x64, 0x80, 0x40, 0xe6, 0xad, 0x14, 0xba, 0x52, 0xb5, 0x54, 0xa7, 0x9d, + 0x11, 0x76, 0xd5, 0x5d, 0xed, 0x2e, 0xa2, 0x01, 0xd8, 0x58, 0x68, 0x25, + 0xb9, 0x45, 0xb1, 0x39, 0xa2, 0x60, 0x53, 0xc1, 0xc0, 0x73, 0x69, 0x1f, + 0x6e, 0x29, 0xc4, 0x09, 0x7b, 0xab, 0x44, 0x7b, 0x02, 0xa5, 0x74, 0x00, + 0xdf, 0x28, 0x34, 0x91, 0xbc, 0x83, 0xb8, 0xbe, 0x10, 0xc2, 0x89, 0x34, + 0xe7, 0x6f, 0xd3, 0xb3, 0x35, 0xde, 0x84, 0xae, 0x82, 0x8e, 0xd9, 0x34, + 0x3c, 0xf7, 0xc5, 0x43, 0xe8, 0x2c, 0x44, 0x51, 0x20, 0x0c, 0xf7, 0x75, + 0x9a, 0xf3, 0x16, 0xd2, 0x49, 0x6b, 0x21, 0x80, 0x15, 0x11, 0xe0, 0xba, + 0x82, 0x4f, 0x0c, 0x12, 0xb6, 0x4a, 0x14, 0x1a, 0x70, 0x61, 0x8c, 0xed, + 0xdc, 0xe8, 0xd8, 0x3d, 0xaa, 0x22, 0x54, 0xc0, 0x35, 0x0a, 0xb0, 0x93, + 0xaa, 0xc3, 0x54, 0x81, 0xe8, 0x3d, 0xd0, 0x5e, 0xe9, 0xdd, 0xae, 0x2a, + 0x7c, 0xc6, 0x6f, 0x1d, 0xe9, 0xe9, 0xa3, 0x43, 0xb3, 0xde, 0x4f, 0xe2, + 0x1c, 0x9b, 0x9a, 0x3a, 0x5e, 0x3f, 0x04, 0x44, 0xa7, 0x98, 0x37, 0x27, + 0x36, 0x72, 0x3c, 0x6c, 0x55, 0xf0, 0xb7, 0x36, 0xd5, 0xa0, 0xa1, 0x19, + 0xde, 0x23, 0xd0, 0x7d, 0x44, 0x87, 0x8a, 0x24, 0xad, 0x7d, 0x53, 0xe1, + 0x7b, 0xf6, 0xd6, 0xa5, 0x41, 0xdc, 0x18, 0xa9, 0xc8, 0xea, 0x0c, 0xe9, + 0x70, 0x7a, 0xac, 0x11, 0x73, 0x44, 0x83, 0xdb, 0x6c, 0xee, 0x38, 0x36, + 0x69, 0x63, 0xa3, 0x61, 0x79, 0x5f, 0x6b, 0x5f, 0x85, 0x7b, 0x0f, 0x0d, + 0x9f, 0xae, 0x22, 0xbd, 0xce, 0x1b, 0xb7, 0xe2, 0xe1, 0x29, 0x5c, 0xd9, + 0x08, 0x3c, 0x14, 0x04, 0xf7, 0xaa, 0xb5, 0xd0, 0x09, 0x44, 0xba, 0xee, + 0x43, 0x44, 0xd5, 0x85, 0x66, 0xbc, 0x2c, 0x90, 0xac, 0x31, 0x23, 0xa7, + 0x6f, 0x02, 0x5e, 0xac, 0x22, 0x0f, 0xbe, 0xa5, 0xe0, 0x22, 0x19, 0x05, + 0x51, 0x1a, 0xab, 0x82, 0x4c, 0x7e, 0x72, 0x51, 0xc7, 0xc6, 0x3a, 0x92, + 0xb5, 0x2c, 0x14, 0xd2, 0x73, 0x2b, 0x8e, 0x8d, 0x2c, 0xca, 0xca, 0x87, + 0x1b, 0x48, 0x86, 0x4f, 0x8c, 0xd8, 0x43, 0x7a, 0x2c, 0x40, 0xb2, 0x56, + 0x89, 0xbe, 0x45, 0x39, 0xb1, 0xfc, 0x16, 0xe5, 0x74, 0x2b, 0x76, 0xcf, + 0xb1, 0xdc, 0xfe, 0x5f, 0xe4, 0x35, 0xeb, 0xd8, 0xdd, 0xc6, 0xc9, 0x28, + 0x1a, 0x0f, 0x5d, 0x92, 0x1d, 0xd3, 0xf7, 0x10, 0xf1, 0xf1, 0x1d, 0xff, + 0xb5, 0x91, 0xfe, 0xf7, 0x84, 0x8f, 0xe8, 0x51, 0x49, 0x37, 0xef, 0xb9, + 0x19, 0xbb, 0x93, 0x4c, 0x2e, 0xc9, 0x38, 0x48, 0x32, 0x0e, 0x4e, 0xb1, + 0xac, 0x9b, 0x48, 0xd6, 0xc0, 0xeb, 0x84, 0xcb, 0xae, 0x8b, 0x45, 0x51, + 0x7b, 0x48, 0x4b, 0x36, 0xca, 0xe1, 0x44, 0x9d, 0x00, 0x55, 0x25, 0x68, + 0xad, 0xc5, 0x87, 0x2c, 0x67, 0x83, 0xe4, 0xfc, 0x9d, 0x61, 0xe2, 0x67, + 0x03, 0xcd, 0xb7, 0x91, 0xe4, 0x9c, 0x24, 0xfe, 0x6f, 0x72, 0xe6, 0x6d, + 0xa2, 0x79, 0x7b, 0xa9, 0xf6, 0x98, 0xf5, 0x5e, 0x24, 0x7a, 0xa2, 0x9f, + 0xd1, 0x42, 0x68, 0x3c, 0x12, 0x7c, 0x8f, 0x6a, 0xec, 0xeb, 0x9d, 0x71, + 0x2a, 0x8d, 0x63, 0xda, 0x7f, 0x5c, 0x2d, 0xe9, 0x5f, 0xd6, 0x67, 0xfe, + 0x16, 0xb8, 0xe7, 0x60, 0xa1, 0x8f, 0xea, 0x88, 0x5e, 0xaa, 0x95, 0x14, + 0xca, 0x6d, 0x16, 0xbe, 0x1b, 0xd7, 0xa2, 0xf5, 0x82, 0xe3, 0x9f, 0x45, + 0x7e, 0x58, 0xa6, 0x3a, 0x29, 0x1c, 0x9a, 0x43, 0x50, 0x91, 0x8a, 0x0a, + 0xe1, 0xc1, 0x26, 0x45, 0x2e, 0x92, 0xbf, 0x06, 0xfb, 0x08, 0x4f, 0xbb, + 0xf0, 0x52, 0xde, 0x85, 0x57, 0xd2, 0xbd, 0xd8, 0x5f, 0xf2, 0x10, 0x6e, + 0xb6, 0x3c, 0xae, 0xb5, 0x7f, 0x56, 0x55, 0x89, 0xc9, 0x2b, 0xd1, 0x3d, + 0xfe, 0x20, 0x6a, 0x32, 0xae, 0x1e, 0xca, 0xa7, 0xc6, 0x4d, 0x24, 0x97, + 0x8d, 0x45, 0x7e, 0xde, 0x84, 0x4c, 0x3a, 0x45, 0x18, 0x28, 0x4c, 0x35, + 0x90, 0x0b, 0xb9, 0xc6, 0x26, 0xa7, 0x9f, 0x3b, 0x4a, 0xf7, 0x46, 0x4b, + 0x5f, 0xec, 0x33, 0xdf, 0xba, 0xd0, 0x5f, 0xee, 0xc7, 0xde, 0x6c, 0x1f, + 0x61, 0xd3, 0x5e, 0x8a, 0xef, 0x15, 0x1a, 0x67, 0xe3, 0x3d, 0xd8, 0x9b, + 0x37, 0x2f, 0xc5, 0x8f, 0x69, 0x27, 0x7e, 0x0c, 0xa0, 0xba, 0x9d, 0xf7, + 0xad, 0x7a, 0x71, 0x7b, 0x1a, 0x78, 0x37, 0xcd, 0x7d, 0x44, 0xc2, 0x14, + 0x94, 0x0f, 0x0e, 0x1a, 0x9c, 0x43, 0x7b, 0xb1, 0x22, 0x6f, 0x23, 0x6f, + 0xd8, 0x38, 0x6d, 0xe8, 0x94, 0xa3, 0x39, 0x57, 0x0f, 0x0a, 0x9d, 0xf2, + 0xb3, 0xe5, 0x1a, 0x40, 0xa4, 0x9d, 0x75, 0xf4, 0xe0, 0xc2, 0xfe, 0xd3, + 0x80, 0xb3, 0xff, 0x34, 0x97, 0x96, 0xf1, 0x04, 0x29, 0xe2, 0xb9, 0x6c, + 0x38, 0xf4, 0x2e, 0xec, 0x21, 0xd9, 0xd4, 0x12, 0x2e, 0x99, 0xf7, 0x65, + 0x78, 0x5f, 0x4a, 0xef, 0x59, 0x21, 0x6b, 0x46, 0x51, 0xb4, 0xf4, 0xbd, + 0x8d, 0xf2, 0x26, 0x05, 0x5a, 0xe8, 0x35, 0x44, 0xa2, 0x5d, 0xbc, 0xf7, + 0x50, 0xaa, 0xe4, 0xee, 0x95, 0x0b, 0xb9, 0x5b, 0xcf, 0x7b, 0x45, 0x78, + 0x4c, 0x42, 0x6e, 0xc6, 0xb6, 0x24, 0xb2, 0xdf, 0x19, 0x9a, 0xf3, 0x07, + 0xd9, 0x21, 0x64, 0x63, 0xb6, 0x7d, 0x4b, 0x5c, 0xef, 0x6f, 0x94, 0xf1, + 0xfb, 0x94, 0xc9, 0x41, 0x36, 0x9f, 0x22, 0x5f, 0x0b, 0xed, 0x68, 0xb7, + 0xec, 0x2a, 0xa7, 0xae, 0xe0, 0xbe, 0x64, 0xb7, 0x68, 0x2d, 0xf4, 0x8a, + 0x55, 0x84, 0xdd, 0x42, 0xc7, 0xb6, 0x88, 0xe6, 0xa3, 0x15, 0xec, 0x16, + 0x29, 0x7c, 0xd6, 0x3b, 0xbd, 0x31, 0x6d, 0x23, 0x4d, 0x7c, 0x3d, 0xf1, + 0x6b, 0x7c, 0xb1, 0x2e, 0x06, 0x70, 0x55, 0x3b, 0xfb, 0xe2, 0x83, 0x38, + 0x96, 0x66, 0x3b, 0x1f, 0xc0, 0x6e, 0x92, 0xcf, 0xea, 0x11, 0xde, 0x07, + 0xd3, 0x4e, 0x0f, 0x23, 0xdc, 0xff, 0xaa, 0xd0, 0xca, 0x05, 0xb4, 0x18, + 0xb5, 0x32, 0xc7, 0x57, 0x6d, 0xb0, 0x59, 0xae, 0xd0, 0x9f, 0xc8, 0x83, + 0xe2, 0x69, 0x85, 0x87, 0x6b, 0xf2, 0x2b, 0xc8, 0x56, 0x2d, 0xcf, 0xc5, + 0x78, 0xcb, 0x40, 0x0d, 0x36, 0x8a, 0x0f, 0x66, 0x43, 0xf0, 0x1e, 0x4a, + 0x2e, 0xf5, 0xa3, 0x53, 0xbc, 0xeb, 0xd4, 0x8b, 0x5d, 0xe2, 0x7c, 0xbe, + 0x47, 0xbc, 0x9f, 0xeb, 0x46, 0x64, 0xec, 0x1e, 0xf1, 0x4e, 0x8e, 0xe9, + 0xec, 0x13, 0x67, 0x67, 0xb9, 0x3f, 0x6a, 0x63, 0xb7, 0xc1, 0xbd, 0xd1, + 0xa5, 0xd5, 0xf0, 0xdb, 0x38, 0x66, 0xb0, 0x3e, 0xb9, 0x4f, 0x58, 0xe9, + 0x2f, 0x6d, 0x8c, 0x8f, 0xda, 0x2e, 0x9d, 0x7b, 0xc4, 0x41, 0x87, 0xdf, + 0x19, 0xc2, 0xd1, 0xb3, 0xb9, 0x5e, 0x71, 0x3c, 0x5f, 0xe1, 0x75, 0x3a, + 0xcf, 0xf6, 0xab, 0x90, 0x8e, 0xbf, 0x98, 0xa7, 0x2d, 0xa8, 0xed, 0x41, + 0x54, 0x39, 0xfd, 0x28, 0x1b, 0xe3, 0x46, 0x24, 0xf4, 0x32, 0x82, 0x70, + 0x15, 0xd9, 0xb6, 0x6d, 0x3c, 0x65, 0xb8, 0x21, 0x8f, 0x2b, 0x24, 0x23, + 0xb2, 0x25, 0xbf, 0x1b, 0xd2, 0x34, 0xd7, 0x06, 0xeb, 0xab, 0xb9, 0x4f, + 0x11, 0x92, 0xf8, 0xff, 0x2f, 0xda, 0x9c, 0x9b, 0xf2, 0x01, 0xf7, 0xd5, + 0xdf, 0xac, 0xaa, 0xd8, 0x5e, 0xa5, 0xb7, 0xeb, 0x31, 0xb9, 0xf7, 0xed, + 0xac, 0xe7, 0x59, 0xd9, 0xee, 0xc1, 0x3b, 0xa3, 0x55, 0xdc, 0xa2, 0x50, + 0x6a, 0x28, 0xbe, 0xdd, 0x7d, 0xc8, 0xa6, 0xdc, 0x02, 0x4f, 0xb4, 0xfd, + 0x4d, 0xfb, 0x00, 0xe5, 0x1d, 0xb7, 0x9e, 0xa0, 0x7c, 0xc5, 0x7b, 0x2d, + 0xb7, 0x62, 0x7e, 0xd2, 0x25, 0xa9, 0x26, 0xe2, 0x14, 0xf3, 0xec, 0xba, + 0x35, 0x91, 0x81, 0x8f, 0xc9, 0x36, 0x32, 0xc4, 0xd3, 0x07, 0xa3, 0x21, + 0xe4, 0xa9, 0x0e, 0xb3, 0x9c, 0x9a, 0xe3, 0xb7, 0x71, 0x6e, 0x54, 0x16, + 0x3e, 0x13, 0xf2, 0x70, 0xbb, 0x8d, 0x21, 0x23, 0x72, 0xfa, 0x2d, 0x59, + 0xa1, 0x79, 0x5c, 0x78, 0x34, 0x5f, 0x0f, 0x3f, 0xc5, 0x52, 0x69, 0x6c, + 0x38, 0xe5, 0xa6, 0xb8, 0xf9, 0xe3, 0xd8, 0x70, 0x50, 0xa5, 0xeb, 0x6d, + 0x06, 0x4e, 0x11, 0xb4, 0xf9, 0xd1, 0x72, 0xf0, 0x1e, 0x60, 0x64, 0xe0, + 0xbd, 0x4a, 0xbc, 0xb4, 0x5e, 0x13, 0x6f, 0xda, 0xa3, 0xf9, 0x06, 0xc8, + 0x63, 0x71, 0x7c, 0x92, 0xf6, 0x89, 0xf5, 0x23, 0xbc, 0xd7, 0xa7, 0x95, + 0xbb, 0x11, 0x1e, 0x58, 0x2f, 0x63, 0x28, 0x88, 0x48, 0xdf, 0x79, 0xaa, + 0x03, 0x5f, 0x8a, 0x59, 0xfd, 0x3e, 0x8a, 0xb7, 0xdb, 0x09, 0x6b, 0x3e, + 0x2e, 0x42, 0x94, 0x9f, 0x58, 0x5e, 0x51, 0xa8, 0x11, 0x85, 0xe4, 0xc8, + 0xfb, 0x41, 0x16, 0xde, 0x76, 0x64, 0xe6, 0xc1, 0xde, 0x1c, 0xd9, 0x89, + 0xf4, 0xc5, 0xbe, 0xfd, 0x1f, 0x55, 0xc3, 0xdb, 0xc0, 0x72, 0x5a, 0xe8, + 0xfb, 0x2d, 0xe2, 0x7d, 0x96, 0x11, 0x63, 0xfe, 0x4a, 0x3d, 0x50, 0x65, + 0xd6, 0x88, 0x17, 0x46, 0x59, 0x2f, 0x36, 0x9e, 0x36, 0x0c, 0xa6, 0x85, + 0xea, 0xd6, 0xdf, 0x27, 0x8c, 0xaf, 0x59, 0x0c, 0x95, 0x5f, 0x8a, 0x2b, + 0x38, 0x31, 0x8a, 0xdf, 0x52, 0x20, 0x37, 0x57, 0xe3, 0x08, 0x15, 0x13, + 0x2c, 0x3f, 0xb6, 0x37, 0xa3, 0x23, 0x92, 0x83, 0x55, 0x6b, 0x76, 0x21, + 0xe7, 0xd8, 0x79, 0x8d, 0xb8, 0x9f, 0x64, 0x16, 0x69, 0x23, 0x8c, 0xa9, + 0x72, 0x2f, 0xc5, 0xa2, 0x58, 0xaf, 0xe0, 0xb6, 0x51, 0xbc, 0xbe, 0x1c, + 0xf2, 0xa9, 0x46, 0x1c, 0x03, 0xaa, 0x59, 0x9f, 0xfc, 0x3e, 0xe9, 0xce, + 0xcf, 0xb8, 0x8e, 0xc7, 0xd5, 0x88, 0x1d, 0x63, 0x49, 0x6c, 0x8e, 0xc9, + 0x84, 0x93, 0xfb, 0x08, 0xbf, 0xf5, 0x11, 0x3e, 0xb5, 0xed, 0xb1, 0x08, + 0xeb, 0x94, 0x75, 0x66, 0x79, 0xc3, 0xed, 0xad, 0xb8, 0x77, 0xb2, 0x1e, + 0xae, 0xb1, 0x06, 0x54, 0x8f, 0x05, 0xb1, 0x9d, 0xe8, 0x3d, 0x62, 0x70, + 0xbf, 0xcd, 0x3a, 0x2d, 0x41, 0x2b, 0xaf, 0x97, 0xb5, 0x7e, 0x55, 0xb6, + 0xf1, 0xa4, 0xa1, 0x19, 0x4f, 0x0a, 0x2f, 0xde, 0xa0, 0x5a, 0xf0, 0xe3, + 0xd8, 0xad, 0xc8, 0xcc, 0x31, 0x9d, 0xcd, 0x1d, 0x57, 0xcf, 0xf2, 0x35, + 0xda, 0xd1, 0xec, 0x5c, 0x57, 0x2d, 0x5c, 0x43, 0x1d, 0x21, 0xe7, 0xda, + 0x44, 0xd7, 0xc5, 0x1e, 0xef, 0x7f, 0x74, 0xf3, 0x35, 0x09, 0xfe, 0x9c, + 0x76, 0x57, 0x6c, 0xf0, 0xdf, 0xc0, 0x72, 0xfa, 0x0f, 0x1f, 0x2d, 0x8c, + 0x81, 0x52, 0x4f, 0xbc, 0xc7, 0xc6, 0x65, 0xc4, 0xdb, 0xa8, 0xf8, 0x6d, + 0x60, 0x7d, 0xf4, 0x21, 0x43, 0x71, 0xaf, 0x96, 0xe2, 0xde, 0xf1, 0x76, + 0x81, 0x1f, 0x45, 0x4c, 0xfc, 0x28, 0xcf, 0x71, 0xd0, 0x85, 0x27, 0xd2, + 0x5a, 0xc8, 0x12, 0xe1, 0x9e, 0x9d, 0x42, 0x42, 0xb2, 0x91, 0x78, 0xa3, + 0x98, 0x3c, 0x9b, 0xe6, 0x18, 0xec, 0x72, 0xf6, 0xd8, 0xb9, 0xde, 0x48, + 0x2c, 0xc4, 0xcc, 0x52, 0x5c, 0xb3, 0xfa, 0x28, 0x37, 0x7c, 0x5c, 0xe0, + 0x39, 0x2d, 0xbc, 0x15, 0x67, 0x79, 0x69, 0xd1, 0x94, 0x74, 0x37, 0x92, + 0x39, 0xf6, 0x4b, 0x5a, 0x8e, 0xd6, 0x3a, 0x92, 0xad, 0x42, 0x6f, 0xbc, + 0x5b, 0xdc, 0x56, 0xbc, 0x85, 0xfb, 0xf9, 0xea, 0x12, 0x73, 0x8b, 0xd8, + 0x30, 0xcd, 0xfd, 0xb8, 0x5e, 0xd1, 0x5b, 0x64, 0x3f, 0x19, 0x14, 0xbf, + 0x53, 0xbc, 0xbc, 0x37, 0xb7, 0x68, 0x17, 0xdc, 0x93, 0xb3, 0x3c, 0x2f, + 0x90, 0x5e, 0xee, 0x1f, 0xc5, 0x1f, 0xd7, 0x43, 0xa6, 0x98, 0xd6, 0x8e, + 0x72, 0xa5, 0xf6, 0xa1, 0xfb, 0x5f, 0xc1, 0x10, 0xe5, 0x57, 0x69, 0x41, + 0xbf, 0x2b, 0x72, 0x12, 0x3e, 0x59, 0xb3, 0xdf, 0x0e, 0x2d, 0x61, 0xfd, + 0x12, 0x6e, 0x24, 0xdd, 0xec, 0xce, 0xee, 0xb1, 0xdf, 0x76, 0x7a, 0x6a, + 0x6c, 0x8f, 0x4e, 0xc9, 0xc4, 0xba, 0xc6, 0x76, 0xf2, 0xb9, 0xc7, 0x47, + 0x97, 0x41, 0xd1, 0xb9, 0x17, 0x5f, 0x8b, 0xa8, 0xe3, 0x37, 0x1e, 0x14, + 0x46, 0x19, 0xaf, 0x18, 0x1d, 0xaf, 0x8f, 0x29, 0xf0, 0xd1, 0xb3, 0xd9, + 0x98, 0xc0, 0xa9, 0xf6, 0xca, 0xfc, 0xcd, 0xb9, 0xab, 0x91, 0x56, 0xbd, + 0xa8, 0xd3, 0x9b, 0x91, 0x55, 0x7d, 0xb4, 0xee, 0xad, 0x0b, 0x73, 0xfe, + 0xb8, 0x9a, 0xeb, 0x56, 0xd9, 0xbc, 0xb7, 0xba, 0xa2, 0x0f, 0x45, 0xa9, + 0xd4, 0x31, 0x8a, 0xe5, 0xa3, 0xb5, 0x0e, 0xb6, 0xf7, 0x62, 0xc7, 0x88, + 0x4f, 0xbc, 0x92, 0xfe, 0xd7, 0x36, 0xdb, 0xcc, 0x01, 0xb2, 0xe5, 0x2a, + 0x7d, 0x71, 0xce, 0xd7, 0x9d, 0x77, 0x6b, 0x29, 0x2e, 0x0f, 0x8c, 0x4a, + 0x08, 0x2c, 0xdc, 0x8f, 0xe7, 0x42, 0x08, 0xb6, 0x09, 0xfa, 0xde, 0x6b, + 0xe3, 0x0a, 0x05, 0xaa, 0xfe, 0x06, 0x8d, 0x73, 0xd1, 0x55, 0xa1, 0xfa, + 0xd8, 0xc2, 0xc3, 0xf1, 0x04, 0x2e, 0x10, 0x06, 0xd9, 0x47, 0xf9, 0x72, + 0x57, 0xda, 0xc4, 0xb9, 0xfc, 0x5f, 0x3b, 0xf3, 0xd4, 0x98, 0x1e, 0x4c, + 0xe7, 0xbe, 0x48, 0x57, 0x80, 0x68, 0x7d, 0x98, 0x68, 0xe2, 0x67, 0x17, + 0x9c, 0xda, 0xfa, 0xf9, 0xcb, 0x6a, 0x12, 0x69, 0x9c, 0xfb, 0x31, 0x95, + 0x38, 0xda, 0x69, 0x28, 0x16, 0xf7, 0xb6, 0xe7, 0x27, 0x2c, 0x9c, 0xbb, + 0xb6, 0x0e, 0x9f, 0x4c, 0x34, 0xe3, 0xde, 0x51, 0x2f, 0x2e, 0x4e, 0xd8, + 0xb8, 0x66, 0x0d, 0xee, 0x08, 0x12, 0x8e, 0xa9, 0xa3, 0x78, 0xf1, 0x1a, + 0xd5, 0x0d, 0x54, 0x53, 0x92, 0xf7, 0x44, 0x12, 0x1b, 0x85, 0x8d, 0x68, + 0x0c, 0xa9, 0x1b, 0xe2, 0x91, 0xd0, 0x05, 0x7c, 0xc7, 0x26, 0x7d, 0xa8, + 0xb2, 0xd9, 0x2d, 0x5c, 0xce, 0xde, 0x5c, 0xaf, 0xb3, 0x97, 0x27, 0x4d, + 0x0f, 0x0a, 0xb9, 0x78, 0xb9, 0xbf, 0x7f, 0x59, 0x0c, 0xe7, 0xb8, 0xcd, + 0xf5, 0xff, 0xb8, 0xed, 0xd6, 0xb9, 0xcf, 0xb1, 0x45, 0xec, 0xc9, 0x5d, + 0x8a, 0xeb, 0x97, 0x62, 0xf9, 0xae, 0x85, 0x18, 0x3e, 0x9c, 0x7f, 0xf3, + 0x0b, 0x18, 0x24, 0xb4, 0xb0, 0x57, 0xc0, 0xb1, 0xdb, 0x23, 0xde, 0x22, + 0xbf, 0xdb, 0x6b, 0xb0, 0x9f, 0x9d, 0x0c, 0x52, 0x74, 0x85, 0x8b, 0xe4, + 0x79, 0x3f, 0x9f, 0xcf, 0x08, 0xd8, 0xd8, 0x42, 0x7c, 0x7a, 0x48, 0x8e, + 0x6b, 0xda, 0xdd, 0xe8, 0xa7, 0x78, 0xee, 0x8e, 0xf9, 0x28, 0x0e, 0xa8, + 0x78, 0xd5, 0x60, 0x1b, 0xee, 0x59, 0x88, 0xe7, 0xbc, 0x57, 0x55, 0xd9, + 0x1f, 0xfe, 0x7c, 0xcf, 0x78, 0xd1, 0x36, 0x0d, 0x24, 0x97, 0xc2, 0xfb, + 0x4e, 0x5c, 0x27, 0xec, 0xad, 0x10, 0xee, 0xde, 0x84, 0xc4, 0x12, 0x8d, + 0xdb, 0x02, 0x84, 0x5b, 0x2d, 0xfc, 0xd7, 0xf6, 0x7e, 0xdc, 0x33, 0x2e, + 0xa1, 0x46, 0xe7, 0x3d, 0x1a, 0xb2, 0x83, 0x7a, 0x8e, 0x5f, 0xdd, 0x18, + 0x1a, 0xf7, 0x88, 0x17, 0xa9, 0x26, 0x39, 0xd2, 0xf3, 0x10, 0x96, 0xb4, + 0xdd, 0x09, 0x38, 0xb6, 0xc7, 0xff, 0x7f, 0x0b, 0xa9, 0x65, 0xbc, 0x3e, + 0xf7, 0xa9, 0x04, 0x7c, 0x6d, 0xcc, 0x07, 0xbc, 0xef, 0xd1, 0xfc, 0xdb, + 0x47, 0x5c, 0xe2, 0x42, 0xfa, 0xa7, 0xf6, 0x89, 0x00, 0xe7, 0x58, 0x7e, + 0x56, 0x4b, 0xb1, 0x9e, 0xc7, 0xb2, 0x0e, 0x7d, 0x54, 0xd7, 0xf5, 0x63, + 0x84, 0xe8, 0x3a, 0xe3, 0xcc, 0xf5, 0xbd, 0x05, 0xfa, 0x7d, 0xa2, 0x2e, + 0xa3, 0x58, 0x41, 0xa2, 0x45, 0xbd, 0xb6, 0x07, 0x75, 0xc5, 0xcb, 0x73, + 0xd5, 0x5f, 0x29, 0xdc, 0xeb, 0x63, 0xdf, 0xa9, 0x26, 0x5f, 0xf9, 0x79, + 0x5a, 0xe0, 0xbc, 0x63, 0x7b, 0xdb, 0xd0, 0x9c, 0xa7, 0x1a, 0xda, 0x89, + 0x21, 0x3c, 0x6e, 0x7d, 0xc5, 0xa6, 0xa5, 0x7e, 0xdc, 0x47, 0xbc, 0xd4, + 0x12, 0x2f, 0x1f, 0xc6, 0x56, 0xd0, 0x3a, 0x7c, 0x2f, 0xa3, 0x54, 0xec, + 0x6c, 0x71, 0x2e, 0x2a, 0xc0, 0xfd, 0x5c, 0x2b, 0x45, 0xb0, 0x73, 0x3c, + 0xd2, 0xe7, 0x93, 0xd8, 0x0e, 0x23, 0xb8, 0x7b, 0xfa, 0x37, 0x3c, 0x54, + 0x17, 0xd3, 0x5c, 0x41, 0xdc, 0x9e, 0x71, 0x89, 0xb7, 0xa9, 0xd6, 0x78, + 0x3e, 0x2d, 0x2d, 0x93, 0xf1, 0xac, 0x7d, 0x24, 0x30, 0x84, 0x1b, 0x8c, + 0x6e, 0xdc, 0x45, 0x36, 0xd8, 0xd9, 0x3c, 0x84, 0x09, 0xb2, 0x81, 0xed, + 0x0d, 0x54, 0xff, 0xc4, 0x4a, 0xf6, 0xb6, 0x00, 0xcb, 0x51, 0xa0, 0x8b, + 0xee, 0xd7, 0x53, 0x4d, 0x24, 0xc5, 0xc8, 0xda, 0x1a, 0x04, 0xf9, 0xac, + 0x36, 0x9a, 0xc4, 0xcf, 0x9d, 0x35, 0xeb, 0xf5, 0xc5, 0xf8, 0xcc, 0x39, + 0xf6, 0x8b, 0xf4, 0x58, 0x76, 0xb5, 0xae, 0x47, 0x37, 0x49, 0xcd, 0xa3, + 0x73, 0x64, 0xb3, 0x1b, 0xda, 0x2e, 0x7f, 0x6f, 0x51, 0x46, 0x06, 0xaa, + 0xda, 0x66, 0xec, 0xb2, 0x3a, 0x0c, 0xb5, 0xed, 0x72, 0xdd, 0x2f, 0xce, + 0xc1, 0x34, 0x57, 0xe2, 0x5a, 0x48, 0x8a, 0xa8, 0x77, 0xe0, 0x49, 0x5a, + 0x23, 0x88, 0xad, 0xc5, 0x6e, 0x6c, 0x1b, 0x97, 0x3f, 0xcb, 0xed, 0x7e, + 0xb6, 0xe5, 0xcf, 0xf8, 0xdf, 0x31, 0x1e, 0xe9, 0xf2, 0x2e, 0xf0, 0x7f, + 0xd7, 0xf4, 0x67, 0x73, 0x0d, 0x66, 0x38, 0x86, 0xf2, 0x7c, 0x9c, 0x67, + 0x17, 0xe5, 0x1b, 0xc4, 0x7d, 0xce, 0x7c, 0x5b, 0x3d, 0xec, 0xe3, 0x6e, + 0xca, 0x95, 0x1b, 0xdb, 0x2c, 0xbc, 0x9a, 0xb8, 0xd7, 0xde, 0xe1, 0xc8, + 0xa0, 0xc3, 0xc3, 0xef, 0x77, 0x35, 0x9f, 0x5e, 0xd8, 0x43, 0xaf, 0xf4, + 0x30, 0x9f, 0x2f, 0xb5, 0x3a, 0xfd, 0xf9, 0xef, 0x51, 0x7e, 0x7c, 0xf6, + 0x73, 0x3d, 0xb2, 0x3b, 0xdd, 0xdc, 0xd7, 0x7f, 0xaa, 0xa4, 0x08, 0xd7, + 0x78, 0x8d, 0x70, 0x8f, 0x33, 0x6d, 0xff, 0x45, 0xa9, 0xf8, 0xd8, 0x5f, + 0x23, 0x19, 0xe0, 0x3d, 0xba, 0x8a, 0xfd, 0x47, 0xdb, 0xef, 0x06, 0x8e, + 0x5a, 0x9e, 0xea, 0xb5, 0xa0, 0x3a, 0xb9, 0xc7, 0xb1, 0x87, 0xa5, 0x66, + 0x7c, 0xdd, 0xb3, 0xcd, 0x5c, 0x2b, 0x73, 0x5f, 0xad, 0x73, 0xdd, 0x24, + 0x81, 0xb7, 0xad, 0x2a, 0xaf, 0xa9, 0x9d, 0xe0, 0x5e, 0x37, 0xf7, 0xc0, + 0x97, 0xeb, 0xf0, 0xd6, 0xaf, 0xb5, 0x3c, 0x4b, 0xd6, 0xba, 0xc4, 0x15, + 0x99, 0x3e, 0xb2, 0x3d, 0x1d, 0x89, 0x8c, 0xe5, 0x6d, 0x5c, 0x1b, 0xc2, + 0x03, 0x99, 0x4a, 0x0c, 0x5b, 0x9f, 0x6b, 0x45, 0xeb, 0x14, 0x59, 0x63, + 0x26, 0x88, 0x96, 0x89, 0xf0, 0xc0, 0xd7, 0xa5, 0xf0, 0xe0, 0xbc, 0xc4, + 0xcf, 0x7c, 0x1d, 0xd7, 0x38, 0x38, 0x56, 0xed, 0x58, 0xed, 0x5c, 0xe3, + 0x1d, 0x57, 0xe7, 0x6f, 0x45, 0x7a, 0xce, 0x33, 0x5f, 0x96, 0x6c, 0x3c, + 0x10, 0x93, 0x70, 0xa3, 0xf1, 0x9f, 0xc9, 0xb7, 0x04, 0xd9, 0xc6, 0xab, + 0x9c, 0x9f, 0x9d, 0xe0, 0xbc, 0x7c, 0xad, 0x8e, 0xb5, 0x99, 0x7a, 0x8a, + 0x49, 0x0d, 0x14, 0x9f, 0xea, 0xf1, 0x11, 0xc5, 0xa4, 0xd5, 0x6b, 0x28, + 0x3c, 0xae, 0xb1, 0xfa, 0xaf, 0x00, 0xef, 0xdf, 0x6a, 0x56, 0x51, 0x68, + 0x7d, 0xdd, 0x92, 0xd6, 0xd3, 0x20, 0xa9, 0xb8, 0x2b, 0xc2, 0x73, 0x27, + 0x3a, 0xd6, 0xe6, 0x2b, 0xf9, 0x74, 0x95, 0x93, 0x3f, 0xf5, 0x8e, 0xab, + 0x66, 0x2b, 0x79, 0xd6, 0x98, 0xd5, 0x7e, 0x90, 0x92, 0x78, 0xcf, 0xa1, + 0x0f, 0xe3, 0xd9, 0x14, 0xf6, 0x64, 0x43, 0xf8, 0x45, 0xa6, 0x8a, 0x6c, + 0x23, 0x6c, 0x7c, 0x17, 0x3c, 0xa6, 0xb5, 0x23, 0x96, 0x0f, 0x47, 0x1f, + 0x90, 0xfe, 0x1c, 0x65, 0x97, 0x76, 0x98, 0x10, 0x36, 0x72, 0xae, 0x96, + 0xd0, 0x4b, 0xf8, 0x73, 0x67, 0x8f, 0x0a, 0xa8, 0xf0, 0xd0, 0x9c, 0x07, + 0x46, 0x33, 0x9e, 0x79, 0x38, 0xfd, 0x4c, 0xde, 0x73, 0x95, 0xb0, 0xc1, + 0xb8, 0x97, 0xe4, 0x2c, 0xd0, 0xdc, 0x56, 0x8f, 0x72, 0xaf, 0x0b, 0xe3, + 0x24, 0x13, 0xc5, 0x0c, 0x74, 0x28, 0x23, 0x28, 0x2f, 0xec, 0x27, 0x26, + 0x64, 0xca, 0xd0, 0x2f, 0x17, 0x81, 0x03, 0x14, 0x3b, 0x36, 0xc7, 0x7e, + 0x45, 0xb9, 0xa1, 0xb2, 0x7f, 0x91, 0x9e, 0x14, 0x58, 0xa2, 0x27, 0x49, + 0x1e, 0x2e, 0xff, 0x41, 0xaa, 0xef, 0x0f, 0x96, 0xf8, 0x7d, 0xcf, 0x7c, + 0xd2, 0x99, 0x3f, 0xb2, 0x6f, 0x85, 0x24, 0xe1, 0xea, 0xb6, 0xa3, 0xc8, + 0x2d, 0xad, 0xd0, 0x10, 0x24, 0x4c, 0xc0, 0x75, 0x60, 0x03, 0xf1, 0xb8, + 0xe5, 0x11, 0xee, 0x09, 0x5e, 0xd9, 0x71, 0xdd, 0x14, 0xfb, 0x75, 0xa0, + 0xe3, 0xe7, 0x69, 0x2d, 0xd9, 0x20, 0x33, 0xae, 0x4c, 0x74, 0xdc, 0x3d, + 0xc2, 0xb9, 0xad, 0x8d, 0x6b, 0x71, 0xca, 0xcb, 0xda, 0x60, 0xa3, 0xf0, + 0x89, 0x1b, 0x33, 0x54, 0x8f, 0x13, 0xbd, 0xef, 0x47, 0xb4, 0x20, 0xc9, + 0xae, 0xeb, 0x4e, 0xd1, 0xcf, 0x78, 0xdf, 0x91, 0xdb, 0x55, 0xf9, 0x0a, + 0xee, 0x08, 0x2f, 0xe0, 0x90, 0xa8, 0x83, 0x3b, 0x6c, 0x7b, 0x77, 0x8c, + 0xf3, 0xb8, 0xb3, 0x9f, 0x4e, 0xf7, 0x63, 0x94, 0x77, 0x15, 0x0c, 0x33, + 0x7d, 0x7c, 0x2e, 0x42, 0xa2, 0x3a, 0x2e, 0x7b, 0x7a, 0x01, 0x97, 0xf8, + 0xb0, 0x97, 0xee, 0x97, 0x1d, 0x7c, 0xc2, 0x67, 0xfb, 0x56, 0x75, 0xa8, + 0x8f, 0xf0, 0x79, 0xc0, 0x2b, 0x3b, 0x36, 0x4c, 0x6a, 0x21, 0x89, 0xf8, + 0xd8, 0xc3, 0x7b, 0xdb, 0x34, 0xe7, 0xac, 0xc1, 0x74, 0xfb, 0x3a, 0xb8, + 0x97, 0xb9, 0x9c, 0xe8, 0xb6, 0xb3, 0x61, 0xc2, 0x49, 0x15, 0x5b, 0x49, + 0xe4, 0xa9, 0x22, 0xbe, 0xa2, 0xc2, 0xab, 0x9b, 0x74, 0x72, 0x2c, 0x9d, + 0xc4, 0xf3, 0xf1, 0x8a, 0x7e, 0xd6, 0xe7, 0xbf, 0x81, 0x54, 0x43, 0x27, + 0x46, 0xb3, 0xaa, 0x7f, 0x63, 0xa6, 0x13, 0x13, 0xa4, 0xc3, 0x3b, 0x8a, + 0x41, 0x7f, 0x67, 0x46, 0xc7, 0xb6, 0x22, 0xd7, 0x26, 0xa1, 0x8e, 0xdd, + 0x93, 0xb9, 0x85, 0x1a, 0xb2, 0x92, 0x4b, 0xf6, 0x67, 0x2a, 0x36, 0x17, + 0xce, 0x7b, 0xe6, 0x43, 0xa2, 0x32, 0xaf, 0x42, 0xeb, 0x28, 0x23, 0x7f, + 0x6c, 0x63, 0x29, 0xdb, 0xc2, 0xad, 0x98, 0x9c, 0xf2, 0x5b, 0x57, 0x98, + 0x2a, 0xd6, 0xb6, 0xbd, 0x41, 0xef, 0xb6, 0xe2, 0x97, 0xc7, 0xbf, 0x86, + 0xf2, 0x37, 0x5d, 0x78, 0x3c, 0x93, 0x44, 0x4b, 0xdb, 0x4d, 0x48, 0xfd, + 0xae, 0x82, 0xa7, 0x32, 0x3e, 0x3c, 0x97, 0xa9, 0xec, 0x77, 0x7f, 0x3f, + 0x4b, 0x7e, 0x48, 0x3e, 0xf0, 0xec, 0x97, 0xee, 0x31, 0x52, 0x3c, 0x97, + 0x79, 0xff, 0xfb, 0x9f, 0x1e, 0x77, 0xd6, 0x19, 0xe7, 0x11, 0xf5, 0xe3, + 0x8b, 0xf3, 0xda, 0xd0, 0xdb, 0xfe, 0xb1, 0x77, 0xb4, 0x28, 0x40, 0x31, + 0xa4, 0x72, 0x3e, 0x40, 0x28, 0xe3, 0xce, 0x9e, 0x0b, 0xe1, 0xdf, 0x88, + 0x71, 0x0e, 0x16, 0xaa, 0x08, 0x57, 0xad, 0x20, 0x59, 0xe8, 0x99, 0x80, + 0x5f, 0x2a, 0xaa, 0xf4, 0x69, 0xf2, 0xbb, 0x48, 0x3e, 0xae, 0xe2, 0x0f, + 0x29, 0xa6, 0xb0, 0x4f, 0x55, 0x72, 0x9c, 0x54, 0xdc, 0xec, 0x85, 0x57, + 0xa7, 0x6b, 0xc5, 0xa6, 0x43, 0xf9, 0xb7, 0xf9, 0x39, 0xd9, 0x75, 0xe5, + 0x7b, 0xe4, 0xd2, 0x77, 0xd2, 0xb3, 0x23, 0xb3, 0xdb, 0x68, 0x3c, 0xcb, + 0xe2, 0x59, 0x3b, 0xb5, 0x85, 0xe5, 0x15, 0xf0, 0xbf, 0x41, 0xf2, 0x9f, + 0x24, 0x1a, 0xb3, 0xb4, 0xc6, 0xeb, 0xb4, 0x66, 0xa6, 0xd8, 0x47, 0x63, + 0xf8, 0x19, 0xc9, 0xd9, 0xb1, 0xdd, 0xad, 0x5e, 0xde, 0xdb, 0x7f, 0x2e, + 0x03, 0xaa, 0xbb, 0x2d, 0xcd, 0xb5, 0x70, 0x16, 0x72, 0x18, 0x8b, 0xf8, + 0xf1, 0x2e, 0x5c, 0x3f, 0xaa, 0x25, 0x2d, 0xc2, 0x61, 0x29, 0x15, 0xc2, + 0x65, 0xb2, 0x0d, 0xc7, 0xc9, 0x86, 0x9b, 0x88, 0xa7, 0x70, 0xe8, 0x1c, + 0x8d, 0xb7, 0x5c, 0x0a, 0xf6, 0x4f, 0xc8, 0x38, 0xc7, 0xfb, 0xaf, 0xa2, + 0xf2, 0x3e, 0x01, 0x7f, 0x1a, 0xbb, 0xf8, 0x7f, 0x0d, 0xe1, 0xf2, 0x70, + 0x82, 0xb2, 0x2a, 0xe3, 0x5b, 0x4f, 0xbe, 0xfd, 0x21, 0x1c, 0xa4, 0x3a, + 0x79, 0x47, 0x2c, 0x84, 0x64, 0x7d, 0x1c, 0x1e, 0xbd, 0x65, 0xe0, 0x22, + 0xfe, 0x87, 0x5d, 0xe6, 0x3d, 0x6c, 0x11, 0x4e, 0x5c, 0xc4, 0xa7, 0xb6, + 0xac, 0xeb, 0xa7, 0x67, 0xa0, 0x97, 0xcf, 0xa1, 0x65, 0xf0, 0x13, 0xbc, + 0x6b, 0xf3, 0xfe, 0xb6, 0x22, 0xcb, 0x78, 0xd1, 0x08, 0xab, 0x2e, 0x04, + 0x50, 0x0e, 0xc8, 0xd8, 0x6c, 0x30, 0xfe, 0xd7, 0x06, 0x1f, 0x83, 0x36, + 0x70, 0x5e, 0xb4, 0xf4, 0x7f, 0x88, 0xb3, 0x76, 0xae, 0x9e, 0xd7, 0x15, + 0x48, 0x5c, 0xdd, 0x72, 0xba, 0x0a, 0x5a, 0x97, 0x5b, 0xe8, 0x89, 0x46, + 0xf9, 0xaf, 0xec, 0xb3, 0x81, 0x4f, 0x6d, 0x3d, 0xf2, 0x29, 0xe1, 0x20, + 0x3d, 0x38, 0x4d, 0xb6, 0xdf, 0x8f, 0x45, 0xda, 0x5e, 0x27, 0xfe, 0xa9, + 0xb0, 0xd3, 0x79, 0x9f, 0xc8, 0xf2, 0xec, 0x25, 0xda, 0x5e, 0x23, 0x1c, + 0xb0, 0x23, 0x76, 0xd1, 0x4e, 0x2e, 0xe5, 0x1a, 0xe9, 0x67, 0xde, 0x4a, + 0xff, 0x98, 0x7b, 0x0e, 0xb7, 0xe2, 0x76, 0xc2, 0x77, 0xc3, 0xd9, 0x45, + 0xbc, 0xe6, 0xa6, 0x18, 0xcc, 0xb1, 0xbf, 0x7c, 0x15, 0x95, 0xd4, 0x12, + 0x95, 0xc7, 0xd8, 0x4d, 0x71, 0x61, 0x97, 0x93, 0x0b, 0xe0, 0x5d, 0xbe, + 0xb6, 0x0d, 0x9f, 0x4c, 0x95, 0xbc, 0xe4, 0x4b, 0xeb, 0xf5, 0x35, 0x10, + 0xc1, 0x8c, 0x25, 0xea, 0x4c, 0x19, 0x1f, 0xb6, 0x6b, 0x5d, 0x92, 0x3c, + 0x88, 0xab, 0x63, 0x96, 0xed, 0xd3, 0xf5, 0xbe, 0x56, 0x11, 0xe9, 0x29, + 0x8a, 0x28, 0x6a, 0x8a, 0x3e, 0xa5, 0xa6, 0xd8, 0xaa, 0x78, 0x8b, 0x96, + 0x47, 0x5d, 0x7b, 0x17, 0xd5, 0xb4, 0x43, 0x58, 0x19, 0xf3, 0x51, 0x3d, + 0xac, 0x19, 0x17, 0x50, 0x45, 0xf2, 0x0f, 0x61, 0x6f, 0xc9, 0x84, 0x2b, + 0xb3, 0x13, 0xee, 0x4c, 0x58, 0xdd, 0x83, 0x21, 0x24, 0x83, 0x15, 0x4c, + 0xab, 0x90, 0xae, 0xaa, 0xdb, 0x19, 0xcb, 0xdc, 0x85, 0xb3, 0x39, 0xc6, + 0xe7, 0x54, 0x9f, 0xa6, 0xf9, 0x3b, 0xbc, 0x2f, 0xc5, 0x4d, 0x3c, 0x49, + 0x75, 0x95, 0xa7, 0xad, 0x91, 0xf4, 0xd0, 0x84, 0xe1, 0x92, 0x60, 0xb3, + 0x22, 0x5d, 0xc0, 0xfb, 0x64, 0xbb, 0x82, 0x03, 0x33, 0x94, 0x48, 0x28, + 0x5f, 0xb9, 0x32, 0x2a, 0xc5, 0x09, 0xc6, 0xd8, 0x3e, 0xfa, 0x1e, 0xe0, + 0x33, 0x3f, 0x64, 0x67, 0x57, 0x76, 0xb4, 0x3a, 0xb1, 0xa6, 0x8d, 0x6a, + 0x9c, 0xa7, 0xbd, 0x95, 0x9a, 0xcb, 0x44, 0xcd, 0xf8, 0x62, 0xad, 0xb8, + 0xe1, 0xe6, 0x1a, 0xaa, 0xc5, 0x87, 0x4b, 0x8c, 0x03, 0x2b, 0x67, 0x3c, + 0x37, 0xc4, 0xda, 0x08, 0xb3, 0x8b, 0x05, 0x8c, 0x35, 0xac, 0xf9, 0xb0, + 0x1e, 0x07, 0xa9, 0x56, 0xf6, 0xeb, 0x5b, 0x91, 0x51, 0xcb, 0xde, 0x37, + 0xe3, 0x8c, 0x7f, 0xe1, 0xdd, 0x46, 0x18, 0x6a, 0x24, 0xfd, 0x55, 0x8e, + 0x99, 0x9e, 0x3b, 0xe2, 0x06, 0x0e, 0x8f, 0x52, 0x88, 0xd2, 0xd7, 0xa3, + 0x6e, 0x4d, 0x37, 0x3e, 0xac, 0x67, 0xfc, 0x4b, 0xb1, 0x8a, 0xe8, 0xd9, + 0x33, 0x13, 0x70, 0xce, 0x24, 0xec, 0x2d, 0x2d, 0xd2, 0x7c, 0x39, 0xad, + 0x5f, 0x46, 0x23, 0xcb, 0xe4, 0x9f, 0xa2, 0x91, 0x6c, 0x96, 0x30, 0xcf, + 0x68, 0x7a, 0x1b, 0x5e, 0x4e, 0xf3, 0xbc, 0xe1, 0xa4, 0x21, 0x54, 0xee, + 0x6b, 0x3b, 0x32, 0xb1, 0x66, 0x78, 0x0d, 0x5e, 0x7f, 0x71, 0x9d, 0x00, + 0xf6, 0x7d, 0xa9, 0x3c, 0xfe, 0x39, 0x6b, 0x51, 0xdc, 0x18, 0x5d, 0x4f, + 0x75, 0x50, 0x14, 0xfa, 0xef, 0x94, 0x49, 0x1f, 0xdc, 0xe7, 0x5d, 0x41, + 0x98, 0x17, 0x9e, 0x57, 0xe2, 0x7c, 0xee, 0xd7, 0x1e, 0x52, 0x4c, 0xdb, + 0x76, 0xb7, 0xeb, 0xea, 0x3b, 0x60, 0x3b, 0xf4, 0xf1, 0x7e, 0x81, 0x67, + 0x4f, 0xbb, 0x0f, 0x07, 0x28, 0x07, 0x3e, 0x91, 0x6e, 0xb1, 0x6e, 0x12, + 0x7c, 0x7e, 0x89, 0x62, 0xb6, 0x48, 0xd1, 0xbb, 0x37, 0xd6, 0xb0, 0xcf, + 0xee, 0x2e, 0xed, 0x84, 0x94, 0x89, 0xd4, 0x70, 0x3d, 0x51, 0x45, 0x35, + 0xf4, 0x70, 0x9a, 0xe9, 0xb5, 0x87, 0x5c, 0x34, 0xd7, 0xae, 0xb8, 0x3e, + 0x7f, 0x3d, 0xd9, 0x45, 0xa3, 0xc9, 0x72, 0x0c, 0xe0, 0x08, 0x8d, 0x0d, + 0x95, 0x58, 0x96, 0x7d, 0x35, 0xdc, 0x33, 0xdc, 0x4b, 0xfa, 0xad, 0xcb, + 0x56, 0xe6, 0xc9, 0x96, 0xfa, 0xb1, 0x62, 0x64, 0xdc, 0x99, 0x87, 0x7d, + 0xe0, 0xc5, 0xf8, 0x00, 0xf6, 0xa6, 0x03, 0x98, 0x49, 0xb7, 0xa8, 0x2f, + 0x38, 0xfb, 0xed, 0x95, 0xfe, 0xd2, 0x70, 0x7a, 0x71, 0x4c, 0x00, 0xd3, + 0x97, 0xfe, 0x67, 0xf9, 0x54, 0xfa, 0x8e, 0x95, 0x7e, 0x80, 0x82, 0x5c, + 0xa0, 0x82, 0x87, 0x28, 0x56, 0x78, 0x1f, 0x26, 0xbd, 0x9e, 0x27, 0xbd, + 0x4a, 0xa4, 0xd7, 0x17, 0x8c, 0xef, 0x33, 0x66, 0xf1, 0xec, 0x8e, 0xfb, + 0x78, 0x8f, 0xc5, 0x22, 0xd0, 0xe2, 0x8c, 0xc9, 0xc4, 0x5d, 0x38, 0x33, + 0xc2, 0xe7, 0xf9, 0xd4, 0x8e, 0x53, 0x69, 0x7b, 0xfd, 0x5c, 0xac, 0x25, + 0x75, 0x9e, 0xf0, 0xb4, 0xf5, 0xbb, 0x9a, 0x71, 0x96, 0xfc, 0x34, 0x3b, + 0xf1, 0xfb, 0x38, 0x5b, 0xdf, 0xa2, 0xfe, 0x98, 0xca, 0xf9, 0x47, 0xe3, + 0x0f, 0x21, 0x31, 0x41, 0x75, 0xc3, 0x9a, 0x7f, 0x47, 0x4e, 0x16, 0x87, + 0xac, 0xb7, 0xcc, 0xbf, 0x80, 0xff, 0x86, 0xb3, 0x57, 0x84, 0x8d, 0x17, + 0xc0, 0x63, 0x2a, 0xf5, 0x78, 0x78, 0xf6, 0x1e, 0x3e, 0x8b, 0x14, 0xe4, + 0x5a, 0xdb, 0xd9, 0x0b, 0x4a, 0xf3, 0xde, 0x95, 0x40, 0xae, 0x57, 0x0b, + 0xa5, 0x9c, 0xb3, 0x9f, 0xf0, 0x3e, 0x46, 0x7e, 0x11, 0x1d, 0xe3, 0xf1, + 0x81, 0x0e, 0x3d, 0x1f, 0x82, 0x4c, 0x18, 0x27, 0x15, 0xd0, 0xba, 0x80, + 0xa0, 0xff, 0xb1, 0x74, 0x10, 0xfb, 0xb2, 0x2d, 0x3d, 0x51, 0x71, 0xdb, + 0xc2, 0x9e, 0x31, 0xe7, 0xb9, 0x00, 0xe5, 0x39, 0x2d, 0xf5, 0x18, 0x5a, + 0xfa, 0x7c, 0xe2, 0x56, 0xa4, 0xea, 0x5b, 0xfa, 0x9f, 0x44, 0x38, 0xe1, + 0x11, 0x5a, 0xf4, 0x2c, 0x2a, 0xf3, 0xac, 0xcc, 0xcb, 0x40, 0x03, 0xc7, + 0x99, 0x34, 0x9e, 0x54, 0x65, 0xac, 0x6a, 0xd3, 0xe7, 0xa7, 0xb1, 0x68, + 0x2f, 0x95, 0x31, 0xeb, 0xf3, 0x34, 0x5e, 0x56, 0xa9, 0x0e, 0xae, 0x82, + 0xab, 0x81, 0xf7, 0xe3, 0x76, 0x62, 0x47, 0x9a, 0xf3, 0x34, 0xc9, 0x85, + 0x7c, 0xb3, 0x27, 0xb2, 0x13, 0x03, 0xf9, 0x00, 0x0e, 0x66, 0xc3, 0xfb, + 0xf6, 0x10, 0xae, 0x1b, 0x2b, 0x85, 0x43, 0xdb, 0x45, 0x80, 0xf4, 0x2d, + 0x21, 0xd4, 0x10, 0x44, 0xb5, 0xae, 0xd2, 0xa7, 0x52, 0xcf, 0x9c, 0xa2, + 0x7a, 0xe6, 0x0c, 0xf9, 0x9a, 0x6f, 0xa1, 0x46, 0x5d, 0x99, 0xb3, 0x31, + 0x17, 0xdb, 0x84, 0xf7, 0x1d, 0x9d, 0x05, 0xc9, 0xc6, 0x38, 0x17, 0x39, + 0x35, 0xa8, 0xd8, 0x3e, 0x66, 0x79, 0xee, 0x6f, 0x0f, 0x22, 0x9c, 0x61, + 0xcc, 0x29, 0x7d, 0x53, 0x26, 0x79, 0xcc, 0xe8, 0x43, 0xd8, 0x18, 0x1b, + 0xc2, 0x80, 0xf1, 0xc7, 0xa8, 0x6a, 0xe0, 0x78, 0xa4, 0x58, 0x75, 0x34, + 0xef, 0xc5, 0xf6, 0x6e, 0x84, 0x8f, 0x72, 0x0e, 0x6e, 0xa5, 0x1c, 0xcc, + 0xbe, 0xcb, 0xf3, 0xdf, 0xdf, 0xb1, 0x9a, 0x70, 0x45, 0x6d, 0x7b, 0x25, + 0xcf, 0x5f, 0x9d, 0x57, 0xb9, 0x8f, 0x43, 0xb5, 0x29, 0xbc, 0x6f, 0x5f, + 0x6b, 0xe2, 0x51, 0x8a, 0x31, 0x89, 0x35, 0x6e, 0x60, 0x09, 0x9f, 0xf7, + 0x15, 0x0b, 0x3d, 0x80, 0x40, 0xc7, 0x8a, 0xbc, 0xc0, 0x6c, 0x9c, 0xec, + 0xe3, 0xd7, 0xce, 0xf7, 0x84, 0x16, 0xce, 0x63, 0x72, 0xff, 0xe4, 0x90, + 0x9d, 0xe4, 0x33, 0xfa, 0xd2, 0x3b, 0x64, 0x57, 0x5a, 0xb0, 0x8c, 0x9f, + 0xd5, 0x70, 0x5c, 0x96, 0xf5, 0x45, 0xb9, 0xb3, 0xac, 0x4f, 0xd8, 0xb9, + 0x05, 0x5d, 0xb8, 0xe8, 0x9d, 0xdd, 0x93, 0xda, 0xe0, 0x1e, 0xb4, 0x0c, + 0xfc, 0x5c, 0x54, 0x3b, 0xbb, 0x7f, 0xd3, 0xad, 0x48, 0x2d, 0x37, 0x5d, + 0xbd, 0x9f, 0x64, 0xd7, 0x13, 0x1d, 0xe7, 0x08, 0x84, 0x6e, 0x70, 0xf6, + 0x88, 0xa6, 0x5b, 0xff, 0x84, 0xe6, 0xe6, 0xff, 0xbb, 0x7c, 0x7c, 0x5e, + 0xf1, 0xf9, 0xec, 0x73, 0x76, 0x74, 0x69, 0x45, 0x3e, 0x27, 0xc9, 0xf7, + 0x83, 0xa6, 0x84, 0x46, 0x3d, 0x32, 0xdf, 0x47, 0xdf, 0xff, 0x26, 0x4f, + 0x68, 0xff, 0xda, 0x7e, 0xfc, 0x24, 0x67, 0x62, 0x3f, 0xe5, 0x81, 0x3a, + 0x5d, 0x53, 0x73, 0x08, 0x71, 0x2d, 0xed, 0xf0, 0x7f, 0x4d, 0x8e, 0xfc, + 0xb0, 0x5e, 0x75, 0x6a, 0x8c, 0x0a, 0x7f, 0x3e, 0xe2, 0xef, 0xb7, 0x7c, + 0xec, 0x0b, 0x84, 0x91, 0xc8, 0x66, 0x52, 0x14, 0x57, 0x5a, 0xa2, 0x54, + 0xc1, 0x93, 0x1f, 0x68, 0xfb, 0x40, 0xfe, 0x3a, 0x96, 0x66, 0xf9, 0x07, + 0xfd, 0xdb, 0xf8, 0x48, 0xb0, 0xee, 0xf4, 0x24, 0x8d, 0x90, 0xc4, 0x71, + 0xd7, 0x89, 0xa7, 0x56, 0x48, 0xfa, 0x51, 0x0d, 0xd3, 0x35, 0x5c, 0x0a, + 0x07, 0xbd, 0x7c, 0x7e, 0x9e, 0xc0, 0xe1, 0x36, 0xa3, 0x92, 0x2b, 0xe7, + 0x28, 0x1f, 0xbd, 0x4f, 0x74, 0x1c, 0x8c, 0x35, 0x22, 0x45, 0xf9, 0x28, + 0xa3, 0x57, 0x6c, 0x49, 0x9f, 0x65, 0x8c, 0xd9, 0x46, 0x18, 0x53, 0x0b, + 0xb9, 0xe5, 0x96, 0xc1, 0x17, 0xb1, 0xd3, 0x3e, 0x5b, 0xcf, 0x36, 0xe5, + 0xc6, 0xf1, 0xd6, 0x59, 0xbb, 0x1c, 0x60, 0x7e, 0x65, 0x3c, 0x67, 0x90, + 0xcd, 0x5c, 0x11, 0x0e, 0x3e, 0x47, 0x39, 0x75, 0x66, 0x41, 0x1f, 0xe1, + 0xfc, 0xa2, 0x3d, 0xd6, 0xf8, 0xb8, 0x06, 0x4c, 0x41, 0x4f, 0xe4, 0x41, + 0xc5, 0xb6, 0xb7, 0x39, 0xf8, 0xfe, 0x82, 0xad, 0xae, 0x9e, 0xfd, 0x0f, + 0xbe, 0x85, 0xdf, 0xb2, 0x38, 0xef, 0x84, 0xf2, 0x9b, 0xe8, 0x3b, 0xcf, + 0x19, 0x60, 0x2c, 0xc3, 0xe7, 0x9c, 0xbc, 0x3b, 0xda, 0xab, 0xd8, 0x5f, + 0x54, 0x3e, 0xc7, 0xbf, 0x71, 0x8c, 0x7b, 0xaa, 0x36, 0xe5, 0x67, 0x19, + 0x7b, 0x2e, 0xfd, 0xce, 0x80, 0xaf, 0x5d, 0xd8, 0x3c, 0xc6, 0xbd, 0x88, + 0x93, 0xd7, 0x29, 0xf8, 0x3b, 0xca, 0xc3, 0xdc, 0x2b, 0x61, 0x5f, 0x6f, + 0xea, 0x38, 0x35, 0xc9, 0x39, 0x35, 0xde, 0x71, 0x7b, 0x7a, 0x51, 0xc7, + 0x97, 0x78, 0x3a, 0x7d, 0x07, 0xc5, 0x9d, 0x4c, 0x5a, 0x1b, 0x8c, 0xc8, + 0xce, 0xde, 0x54, 0xaa, 0x28, 0xbe, 0x4a, 0x45, 0x1a, 0xcf, 0xa7, 0xfa, + 0x07, 0x0f, 0x85, 0x90, 0xc9, 0x76, 0xe3, 0x1b, 0x63, 0xb6, 0x5d, 0xb5, + 0xc6, 0x85, 0x57, 0x46, 0x6c, 0x7c, 0x10, 0x03, 0x5e, 0x1e, 0x09, 0x0f, + 0x9e, 0x01, 0x7e, 0xaf, 0x8e, 0x6a, 0xe4, 0x56, 0xa1, 0xf5, 0x10, 0x36, + 0x08, 0xbd, 0x8b, 0x96, 0x60, 0x1e, 0xda, 0xe9, 0x5d, 0x34, 0xdf, 0x4b, + 0x05, 0xe0, 0x27, 0x05, 0x2f, 0xde, 0x1c, 0xe3, 0x39, 0xbd, 0x38, 0x73, + 0xb4, 0xc1, 0xbf, 0x93, 0xe6, 0x3a, 0x40, 0xf1, 0xbd, 0xfb, 0x58, 0x02, + 0x9b, 0x0f, 0x09, 0x44, 0x23, 0x09, 0x74, 0x1d, 0xab, 0xc5, 0xa6, 0x31, + 0x05, 0xef, 0xc5, 0x6b, 0x71, 0xd3, 0xd1, 0x45, 0x3e, 0x2a, 0x7d, 0x0d, + 0x3e, 0xe7, 0xc8, 0x67, 0xc8, 0x9e, 0xcc, 0x72, 0xcc, 0xa6, 0x7c, 0x91, + 0xe5, 0x18, 0x68, 0xdb, 0xc1, 0xf6, 0x4a, 0x9f, 0xe3, 0x29, 0xca, 0x1f, + 0x8f, 0xb6, 0xeb, 0xc1, 0xa0, 0x64, 0x62, 0xd5, 0x44, 0xf9, 0xb6, 0x3a, + 0xd8, 0xcf, 0xf3, 0x5e, 0xc0, 0xc7, 0xad, 0xb6, 0xbd, 0x39, 0x1e, 0x99, + 0xbf, 0xdb, 0xc1, 0xb5, 0x71, 0xf2, 0xa9, 0x26, 0x3c, 0x9a, 0x5d, 0xdc, + 0x2f, 0xd2, 0xfb, 0x2e, 0xca, 0xd6, 0x90, 0x0a, 0xfb, 0xa3, 0x6a, 0xd3, + 0xfe, 0xd8, 0x6d, 0x46, 0x82, 0xf7, 0x09, 0x3e, 0x67, 0x11, 0xa2, 0x1a, + 0xc4, 0xb6, 0xdf, 0x8a, 0xdb, 0x76, 0x21, 0x6e, 0x79, 0x56, 0xaf, 0x55, + 0x71, 0x6c, 0x25, 0xf7, 0x9c, 0xc3, 0xc9, 0x46, 0xb2, 0x2f, 0xef, 0x4a, + 0x3d, 0xb8, 0x15, 0x9a, 0x65, 0x51, 0x90, 0x0b, 0x2d, 0xd5, 0xfa, 0x80, + 0x26, 0xff, 0xc1, 0x91, 0x06, 0x3c, 0x3e, 0xf7, 0x9b, 0x7c, 0xf4, 0x85, + 0x62, 0x84, 0x8d, 0x8f, 0x0c, 0xac, 0xaf, 0x43, 0x24, 0x79, 0x27, 0xe5, + 0x02, 0xc9, 0xe4, 0xf3, 0xa0, 0x16, 0x6e, 0x8a, 0xf7, 0x63, 0xc7, 0x18, + 0xef, 0x51, 0xc5, 0x3a, 0x3e, 0x1a, 0xb3, 0xff, 0xc6, 0x43, 0xf4, 0xaf, + 0x6f, 0x6f, 0x49, 0x79, 0x9d, 0xdf, 0x05, 0xe9, 0x54, 0x07, 0xd4, 0xa3, + 0x34, 0xa3, 0x97, 0x97, 0x8b, 0xe4, 0x1b, 0x3e, 0x44, 0x82, 0x8d, 0x14, + 0xab, 0xe6, 0xc8, 0x77, 0x67, 0x4a, 0x5c, 0x07, 0xac, 0xe9, 0xb0, 0x27, + 0x96, 0x61, 0x7a, 0x8e, 0xe6, 0xca, 0xea, 0x5d, 0x1f, 0x10, 0xce, 0xab, + 0x31, 0xed, 0x3a, 0xaf, 0x19, 0x39, 0xdd, 0x22, 0x64, 0xcc, 0xaf, 0xb1, + 0xed, 0xee, 0x76, 0x7d, 0xb0, 0x56, 0x60, 0x80, 0xe6, 0x4a, 0xb4, 0xca, + 0xb8, 0x32, 0x88, 0x48, 0xd7, 0x5b, 0x88, 0xf4, 0x9d, 0xa3, 0x18, 0xf6, + 0x44, 0x89, 0xcf, 0xd8, 0x3e, 0x84, 0xbf, 0x19, 0x5b, 0x8a, 0xe7, 0x67, + 0x06, 0x16, 0x7a, 0x62, 0xf0, 0x5e, 0xbd, 0xd6, 0xc4, 0xf1, 0xb1, 0x10, + 0xd9, 0x4f, 0x15, 0xc5, 0x75, 0x05, 0x52, 0x33, 0xf7, 0x48, 0x43, 0x1d, + 0xb1, 0x47, 0x6c, 0x7b, 0x75, 0x73, 0xa5, 0xe6, 0x59, 0x3d, 0x7b, 0xf9, + 0xef, 0x02, 0x16, 0xfb, 0x3d, 0x41, 0xd2, 0x5f, 0x4b, 0x6a, 0x87, 0x78, + 0xd1, 0xb6, 0x7e, 0x57, 0x10, 0xcf, 0x91, 0x5a, 0x78, 0x99, 0x6f, 0x05, + 0xbb, 0x26, 0x08, 0x94, 0x39, 0xe7, 0x56, 0xe0, 0xed, 0x8a, 0xf3, 0x5e, + 0x33, 0xeb, 0xa8, 0xec, 0xdd, 0x18, 0xa7, 0x98, 0x28, 0xfc, 0x84, 0xa7, + 0x2c, 0x4f, 0x27, 0xe5, 0xa7, 0xea, 0x31, 0xfe, 0x8d, 0x82, 0x0f, 0xfb, + 0x29, 0x6e, 0xbc, 0x6f, 0xd4, 0xe0, 0x60, 0xbd, 0x96, 0xe0, 0x7a, 0xfa, + 0xb1, 0x12, 0xf7, 0x25, 0x77, 0xe2, 0x2e, 0xfe, 0x8d, 0x47, 0xe9, 0x5a, + 0xe7, 0x5c, 0x1e, 0xdd, 0x23, 0x6c, 0xc0, 0x74, 0x2c, 0xae, 0xdf, 0x85, + 0xe5, 0x23, 0xac, 0xc7, 0x40, 0x47, 0x90, 0x64, 0xf4, 0x28, 0xd9, 0x85, + 0x64, 0x76, 0x42, 0x19, 0xb1, 0xed, 0xeb, 0xe3, 0x97, 0xcf, 0xa1, 0x0f, + 0x9c, 0x93, 0xa9, 0xbe, 0x93, 0x79, 0x4f, 0x4c, 0x4b, 0x9c, 0x10, 0x97, + 0xcf, 0xf9, 0x87, 0x44, 0x33, 0xcf, 0x5b, 0xc9, 0x4b, 0xc7, 0x29, 0x2f, + 0xbd, 0x3c, 0xca, 0x3e, 0xd2, 0xe6, 0xf8, 0x88, 0x44, 0xb1, 0x76, 0x43, + 0x3a, 0x84, 0x73, 0x06, 0xf4, 0x2a, 0xc4, 0x88, 0xee, 0x48, 0x4f, 0xe7, + 0x02, 0xe6, 0x73, 0x53, 0xfc, 0x9f, 0x19, 0xe5, 0x7d, 0x2a, 0x81, 0x5a, + 0x9d, 0x6d, 0xc0, 0xc9, 0x05, 0x14, 0xd3, 0x06, 0x50, 0x77, 0x2d, 0x70, + 0x71, 0x84, 0xf7, 0xcc, 0x74, 0xec, 0x2f, 0x0d, 0x8a, 0xc6, 0x91, 0x7f, + 0xb0, 0x43, 0xd5, 0x8b, 0xfb, 0x67, 0x0f, 0xf2, 0xfe, 0x19, 0xd9, 0xc0, + 0x80, 0x73, 0x46, 0xe6, 0xad, 0x34, 0x9f, 0x91, 0x09, 0x87, 0x36, 0x93, + 0xef, 0x6c, 0x43, 0x8b, 0x31, 0x4b, 0xd8, 0x79, 0x9e, 0xe8, 0x6c, 0x16, + 0x95, 0x3d, 0xa2, 0xc8, 0xc2, 0x1e, 0xd7, 0xca, 0x7c, 0x97, 0xa8, 0x2d, + 0x30, 0x4d, 0x71, 0xa2, 0xa9, 0x53, 0xd4, 0x1c, 0xdb, 0x28, 0x7c, 0xc7, + 0xba, 0x85, 0x54, 0xe0, 0x98, 0x1c, 0xeb, 0xd8, 0x3d, 0xca, 0xf9, 0x6c, + 0x8b, 0x70, 0x1d, 0xed, 0x15, 0xde, 0x42, 0x9f, 0xf0, 0x1f, 0xb3, 0x70, + 0x6f, 0xbc, 0x1b, 0x67, 0xc6, 0xf8, 0x1c, 0xd8, 0x3d, 0xa2, 0x76, 0x61, + 0x5f, 0xcb, 0x5b, 0x68, 0xf2, 0x17, 0x68, 0x7d, 0xc2, 0x12, 0x1d, 0xe9, + 0x91, 0x65, 0xfe, 0x27, 0x26, 0x03, 0xfe, 0xc7, 0x26, 0xb5, 0x81, 0xbd, + 0xc2, 0xb6, 0x77, 0xc6, 0xa6, 0x59, 0x87, 0x76, 0x4b, 0xac, 0x82, 0x0f, + 0x76, 0x91, 0x3c, 0xb6, 0x53, 0x6e, 0x99, 0x36, 0x5a, 0x16, 0xb0, 0x88, + 0x96, 0xe2, 0xdf, 0x8b, 0xd1, 0xa7, 0x87, 0x73, 0x1b, 0xef, 0x09, 0xba, + 0xda, 0x41, 0x71, 0xf7, 0x33, 0x5e, 0x6b, 0x47, 0xf8, 0x7c, 0xd7, 0x00, + 0xfc, 0x5f, 0xb2, 0x27, 0x76, 0xe6, 0xb3, 0x3d, 0xb1, 0xc4, 0x63, 0x42, + 0x2b, 0xcf, 0x11, 0xbf, 0xd5, 0xf2, 0xe7, 0xf6, 0xc3, 0x16, 0xf6, 0xc2, + 0xba, 0x84, 0xaf, 0xc0, 0xf5, 0x79, 0xbc, 0xe3, 0xf5, 0x91, 0x4e, 0xe1, + 0x3d, 0x36, 0x46, 0xf9, 0x71, 0x23, 0xf1, 0xcc, 0xe7, 0xae, 0xba, 0x85, + 0xbf, 0xb0, 0x45, 0xf8, 0x88, 0xcf, 0x1a, 0xe2, 0x13, 0xc7, 0x3c, 0xc2, + 0x4b, 0x3c, 0x7a, 0x88, 0x47, 0xef, 0x02, 0x8f, 0x9e, 0x42, 0xd0, 0x9f, + 0x4e, 0x37, 0xf8, 0x1f, 0x9e, 0x54, 0xfd, 0x7b, 0x27, 0x6d, 0xfb, 0x3d, + 0xe3, 0x67, 0x0e, 0x5f, 0xaf, 0x1a, 0x5f, 0xe4, 0xeb, 0x3a, 0xe2, 0xab, + 0xb2, 0x8f, 0x49, 0x3a, 0x4c, 0xb1, 0x0e, 0xf9, 0x0c, 0xc4, 0x22, 0x5f, + 0x07, 0xd2, 0xbc, 0x8f, 0xc1, 0x7b, 0x7e, 0x83, 0x62, 0x35, 0xf1, 0x55, + 0x26, 0xbe, 0xae, 0xf9, 0x12, 0xbe, 0x3e, 0xbc, 0x8c, 0xaf, 0x57, 0xff, + 0x51, 0xbe, 0x3c, 0x62, 0xd5, 0x18, 0xc7, 0xa1, 0xfb, 0x3b, 0x94, 0x31, + 0x9b, 0xb0, 0xa3, 0x8c, 0xc7, 0x67, 0x80, 0x62, 0x76, 0x08, 0x0a, 0xc5, + 0x9b, 0x93, 0xf1, 0x48, 0xe8, 0x15, 0xaa, 0x27, 0x67, 0x4b, 0x5e, 0xb1, + 0xd2, 0xd9, 0xcf, 0xc4, 0x6a, 0x85, 0x68, 0x9a, 0x73, 0x7e, 0x9f, 0x05, + 0xa3, 0x4e, 0x67, 0x5d, 0xea, 0xa7, 0xb7, 0x22, 0x52, 0x8e, 0xc8, 0xdd, + 0x22, 0x51, 0xe0, 0xfd, 0xcb, 0x5e, 0x71, 0x8d, 0xb3, 0x77, 0xd9, 0x25, + 0xae, 0x2e, 0x74, 0x8a, 0x56, 0xb2, 0x8b, 0x96, 0x63, 0x7c, 0x96, 0x6a, + 0x8b, 0x68, 0x59, 0x90, 0xc7, 0x2a, 0x92, 0xc7, 0xc8, 0xe7, 0xe4, 0xb1, + 0xc4, 0xcf, 0xf2, 0xf8, 0x91, 0x71, 0xe1, 0xb2, 0x1e, 0x1a, 0xd7, 0x55, + 0x94, 0x0d, 0xa9, 0x76, 0xaa, 0x5b, 0xa8, 0x9d, 0xde, 0x8e, 0xf1, 0x19, + 0x19, 0xcb, 0xae, 0xd5, 0x11, 0x72, 0x99, 0x5a, 0xdf, 0x49, 0xa1, 0xa7, + 0xee, 0x11, 0xc9, 0xcd, 0x3e, 0xaa, 0x7f, 0x76, 0xc4, 0x22, 0xc9, 0x55, + 0x22, 0x92, 0x70, 0x09, 0xce, 0x2b, 0x86, 0x52, 0x5d, 0xb4, 0xb0, 0x97, + 0xe2, 0xdb, 0x4b, 0xa3, 0x12, 0x61, 0x07, 0xfe, 0xcd, 0x96, 0x0b, 0xd7, + 0xab, 0x3e, 0x1c, 0x21, 0xdc, 0xf1, 0x68, 0xb6, 0x1f, 0x47, 0xf2, 0xdb, + 0xf0, 0x68, 0xfe, 0xd7, 0x7e, 0x9f, 0xa2, 0x78, 0xcd, 0x9e, 0x6b, 0x2b, + 0xfb, 0xf8, 0xd1, 0xc4, 0x55, 0x11, 0x96, 0xcd, 0x4f, 0x5b, 0x94, 0x08, + 0xd7, 0xba, 0x89, 0xeb, 0x7e, 0xae, 0xb3, 0x2f, 0xa6, 0xdb, 0x4f, 0x39, + 0x58, 0xe4, 0xed, 0xb6, 0x63, 0xce, 0xf9, 0xa2, 0x5f, 0xae, 0xde, 0xed, + 0xfc, 0x7e, 0x32, 0xb9, 0xf6, 0x76, 0x9d, 0xfd, 0xe1, 0xa7, 0x6b, 0x36, + 0x38, 0xf9, 0xd5, 0x5c, 0x57, 0xf9, 0x6d, 0x49, 0x62, 0x5d, 0xa5, 0x57, + 0x13, 0x5f, 0x17, 0x75, 0xae, 0xc9, 0x75, 0x95, 0x7d, 0xe2, 0x9e, 0x75, + 0xcd, 0xce, 0xb5, 0x6b, 0x5d, 0xc5, 0xa7, 0x3a, 0xd7, 0xe9, 0xce, 0xb5, + 0x77, 0x5d, 0x25, 0x2f, 0x77, 0xaf, 0x5b, 0x71, 0xe9, 0x37, 0x29, 0xfc, + 0xf7, 0x7f, 0x00, 0x2f, 0xc1, 0x67, 0x8a, 0x54, 0x3a, 0x00, 0x00, 0x00 }; -static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = { - 0x00000000, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000010, - 0x00000030, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x00000010, - 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00008002, 0x00000000, - 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000005, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000004, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000006, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; +static const u32 bnx2_TXP_b09FwData[(0x0/4) + 1] = { 0x0 }; static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = { - 0x08003fdc, 0x08004008, 0x08004050, 0x08004050, 0x08003edc, 0x08003f08, - 0x08003f08, 0x08004050, 0x08004050, 0x08004050, 0x08003f70, 0x00000000, + 0x80000940, 0x80000900, 0x80080100, 0x80080080, 0x80080000, 0x800e0000, + 0x80080080, 0x80080000, 0x80000a80, 0x80000a00, 0x80000980, 0x80000900, 0x00000000 }; static struct fw_info bnx2_txp_fw_09 = { - /* Firmware version: 3.7.1 */ - .ver_major = 0x3, - .ver_minor = 0x7, - .ver_fix = 0x1, + /* Firmware version: 4.0.5 */ + .ver_major = 0x4, + .ver_minor = 0x0, + .ver_fix = 0x5, - .start_addr = 0x08000060, + .start_addr = 0x08000094, .text_addr = 0x08000000, - .text_len = 0x45b0, + .text_len = 0x3a50, .text_index = 0x0, .gz_text = bnx2_TXP_b09FwText, .gz_text_len = sizeof(bnx2_TXP_b09FwText), - .data_addr = 0x08004600, - .data_len = 0xd0, + .data_addr = 0x00000000, + .data_len = 0x0, .data_index = 0x0, .data = bnx2_TXP_b09FwData, - .sbss_addr = 0x080046d0, - .sbss_len = 0x8c, + .sbss_addr = 0x08003aa0, + .sbss_len = 0x6c, .sbss_index = 0x0, - .bss_addr = 0x08004760, - .bss_len = 0xa20, + .bss_addr = 0x08003b0c, + .bss_len = 0x24c, .bss_index = 0x0, - .rodata_addr = 0x080045b0, + .rodata_addr = 0x08003a50, .rodata_len = 0x30, .rodata_index = 0x0, .rodata = bnx2_TXP_b09FwRodata, diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c new file mode 100644 index 000000000000..4a73c884d0c4 --- /dev/null +++ b/drivers/net/bnx2x.c @@ -0,0 +1,9064 @@ +/* bnx2x.c: Broadcom Everest network driver. + * + * Copyright (c) 2007 Broadcom Corporation + * + * 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. + * + * Written by: Eliezer Tamir <eliezert@broadcom.com> + * Based on code from Michael Chan's bnx2 driver + * UDP CSUM errata workaround by Arik Gendelman + * Slowpath rework by Vladislav Zolotarov + * Statistics and Link managment by Yitchak Gertner + * + */ + +/* define this to make the driver freeze on error + * to allow getting debug info + * (you will need to reboot afterwords) + */ +/*#define BNX2X_STOP_ON_ERROR*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/device.h> /* for dev_info() */ +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/dma-mapping.h> +#include <linux/bitops.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <asm/byteorder.h> +#include <linux/time.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#ifdef NETIF_F_HW_VLAN_TX + #include <linux/if_vlan.h> + #define BCM_VLAN 1 +#endif +#include <net/ip.h> +#include <net/tcp.h> +#include <net/checksum.h> +#include <linux/workqueue.h> +#include <linux/crc32.h> +#include <linux/prefetch.h> +#include <linux/zlib.h> +#include <linux/version.h> +#include <linux/io.h> + +#include "bnx2x_reg.h" +#include "bnx2x_fw_defs.h" +#include "bnx2x_hsi.h" +#include "bnx2x.h" +#include "bnx2x_init.h" + +#define DRV_MODULE_VERSION "0.40.15" +#define DRV_MODULE_RELDATE "$DateTime: 2007/11/15 07:28:37 $" +#define BNX2X_BC_VER 0x040009 + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (5*HZ) + +static const char version[] __devinitdata = + "Broadcom NetXtreme II 577xx 10Gigabit Ethernet Driver " + DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("Eliezer Tamir <eliezert@broadcom.com>"); +MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_INFO(cvs_version, "$Revision: #356 $"); + +static int use_inta; +static int poll; +static int onefunc; +static int nomcp; +static int debug; +static int use_multi; + +module_param(use_inta, int, 0); +module_param(poll, int, 0); +module_param(onefunc, int, 0); +module_param(debug, int, 0); +MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X"); +MODULE_PARM_DESC(poll, "use polling (for debug)"); +MODULE_PARM_DESC(onefunc, "enable only first function"); +MODULE_PARM_DESC(nomcp, "ignore managment CPU (Implies onefunc)"); +MODULE_PARM_DESC(debug, "defualt debug msglevel"); + +#ifdef BNX2X_MULTI +module_param(use_multi, int, 0); +MODULE_PARM_DESC(use_multi, "use per-CPU queues"); +#endif + +enum bnx2x_board_type { + BCM57710 = 0, +}; + +/* indexed by board_t, above */ +static const struct { + char *name; +} board_info[] __devinitdata = { + { "Broadcom NetXtreme II BCM57710 XGb" } +}; + +static const struct pci_device_id bnx2x_pci_tbl[] = { + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); + +/**************************************************************************** +* General service functions +****************************************************************************/ + +/* used only at init + * locking is done by mcp + */ +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val) +{ + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); + pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val); + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); +} + +#ifdef BNX2X_IND_RD +static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr) +{ + u32 val; + + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr); + pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val); + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); + + return val; +} +#endif + +static const u32 dmae_reg_go_c[] = { + DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3, + DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7, + DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11, + DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15 +}; + +/* copy command into DMAE command memory and set DMAE command go */ +static void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, + int idx) +{ + u32 cmd_offset; + int i; + + cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx); + for (i = 0; i < (sizeof(struct dmae_command)/4); i++) { + REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i)); + +/* DP(NETIF_MSG_DMAE, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n", + idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i)); */ + } + REG_WR(bp, dmae_reg_go_c[idx], 1); +} + +static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, + u32 dst_addr, u32 len32) +{ + struct dmae_command *dmae = &bp->dmae; + int port = bp->port; + u32 *wb_comp = bnx2x_sp(bp, wb_comp); + int timeout = 200; + + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + dmae->src_addr_lo = U64_LO(dma_addr); + dmae->src_addr_hi = U64_HI(dma_addr); + dmae->dst_addr_lo = dst_addr >> 2; + dmae->dst_addr_hi = 0; + dmae->len = len32; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_val = BNX2X_WB_COMP_VAL; + +/* + DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n" + DP_LEVEL "src_addr [%x:%08x] len [%d *4] " + "dst_addr [%x:%08x (%08x)]\n" + DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", + dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, + dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr, + dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); +*/ +/* + DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", + bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], + bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); +*/ + + *wb_comp = 0; + + bnx2x_post_dmae(bp, dmae, port * 8); + + udelay(5); + /* adjust timeout for emulation/FPGA */ + if (CHIP_REV_IS_SLOW(bp)) + timeout *= 100; + while (*wb_comp != BNX2X_WB_COMP_VAL) { +/* DP(NETIF_MSG_DMAE, "wb_comp 0x%08x\n", *wb_comp); */ + udelay(5); + if (!timeout) { + BNX2X_ERR("dmae timeout!\n"); + break; + } + timeout--; + } +} + +#ifdef BNX2X_DMAE_RD +static void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) +{ + struct dmae_command *dmae = &bp->dmae; + int port = bp->port; + u32 *wb_comp = bnx2x_sp(bp, wb_comp); + int timeout = 200; + + memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4); + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + dmae->src_addr_lo = src_addr >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data)); + dmae->len = len32; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp)); + dmae->comp_val = BNX2X_WB_COMP_VAL; + +/* + DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n" + DP_LEVEL "src_addr [%x:%08x] len [%d *4] " + "dst_addr [%x:%08x (%08x)]\n" + DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n", + dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo, + dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr, + dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val); +*/ + + *wb_comp = 0; + + bnx2x_post_dmae(bp, dmae, port * 8); + + udelay(5); + while (*wb_comp != BNX2X_WB_COMP_VAL) { + udelay(5); + if (!timeout) { + BNX2X_ERR("dmae timeout!\n"); + break; + } + timeout--; + } +/* + DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n", + bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], + bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); +*/ +} +#endif + +static int bnx2x_mc_assert(struct bnx2x *bp) +{ + int i, j; + int rc = 0; + char last_idx; + const char storm[] = {"XTCU"}; + const u32 intmem_base[] = { + BAR_XSTRORM_INTMEM, + BAR_TSTRORM_INTMEM, + BAR_CSTRORM_INTMEM, + BAR_USTRORM_INTMEM + }; + + /* Go through all instances of all SEMIs */ + for (i = 0; i < 4; i++) { + last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET + + intmem_base[i]); + BNX2X_ERR("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n", + storm[i], last_idx); + + /* print the asserts */ + for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) { + u32 row0, row1, row2, row3; + + row0 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + + intmem_base[i]); + row1 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 4 + + intmem_base[i]); + row2 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 8 + + intmem_base[i]); + row3 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 12 + + intmem_base[i]); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("DATA %cSTORM_ASSERT_INDEX 0x%x =" + " 0x%08x 0x%08x 0x%08x 0x%08x\n", + storm[i], j, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + } + return rc; +} +static void bnx2x_fw_dump(struct bnx2x *bp) +{ + u32 mark, offset; + u32 data[9]; + int word; + + mark = REG_RD(bp, MCP_REG_MCPR_SCRATCH + 0xf104); + printk(KERN_ERR PFX "begin fw dump (mark 0x%x)\n", mark); + + for (offset = mark - 0x08000000; offset <= 0xF900; offset += 0x8*4) { + for (word = 0; word < 8; word++) + data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH + + offset + 4*word)); + data[8] = 0x0; + printk(KERN_ERR PFX "%s", (char *)data); + } + for (offset = 0xF108; offset <= mark - 0x08000000; offset += 0x8*4) { + for (word = 0; word < 8; word++) + data[word] = htonl(REG_RD(bp, MCP_REG_MCPR_SCRATCH + + offset + 4*word)); + data[8] = 0x0; + printk(KERN_ERR PFX "%s", (char *)data); + } + printk("\n" KERN_ERR PFX "end of fw dump\n"); +} + +static void bnx2x_panic_dump(struct bnx2x *bp) +{ + int i; + u16 j, start, end; + + BNX2X_ERR("begin crash dump -----------------\n"); + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct eth_tx_db_data *hw_prods = fp->hw_tx_prods; + + BNX2X_ERR("queue[%d]: tx_pkt_prod(%x) tx_pkt_cons(%x)" + " tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)" + " *rx_cons_sb(%x) rx_comp_prod(%x)" + " rx_comp_cons(%x) fp_c_idx(%x) fp_u_idx(%x)" + " bd data(%x,%x)\n", + i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod, + fp->tx_bd_cons, *fp->tx_cons_sb, *fp->rx_cons_sb, + fp->rx_comp_prod, fp->rx_comp_cons, fp->fp_c_idx, + fp->fp_u_idx, hw_prods->packets_prod, + hw_prods->bds_prod); + + start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10); + end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245); + for (j = start; j < end; j++) { + struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j]; + + BNX2X_ERR("packet[%x]=[%p,%x]\n", j, + sw_bd->skb, sw_bd->first_bd); + } + + start = TX_BD(fp->tx_bd_cons - 10); + end = TX_BD(fp->tx_bd_cons + 254); + for (j = start; j < end; j++) { + u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j]; + + BNX2X_ERR("tx_bd[%x]=[%x:%x:%x:%x]\n", + j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]); + } + + start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10); + end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503); + for (j = start; j < end; j++) { + u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j]; + struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j]; + + BNX2X_ERR("rx_bd[%x]=[%x:%x] sw_bd=[%p]\n", + j, rx_bd[0], rx_bd[1], sw_bd->skb); + } + + start = RCQ_BD(fp->rx_comp_cons - 10); + end = RCQ_BD(fp->rx_comp_cons + 503); + for (j = start; j < end; j++) { + u32 *cqe = (u32 *)&fp->rx_comp_ring[j]; + + BNX2X_ERR("cqe[%x]=[%x:%x:%x:%x]\n", + j, cqe[0], cqe[1], cqe[2], cqe[3]); + } + } + + BNX2X_ERR("def_c_idx(%u) def_u_idx(%u) def_t_idx(%u)" + " def_x_idx(%u) def_att_idx(%u) attn_state(%u)" + " spq_prod_idx(%u)\n", + bp->def_c_idx, bp->def_u_idx, bp->def_t_idx, bp->def_x_idx, + bp->def_att_idx, bp->attn_state, bp->spq_prod_idx); + + + bnx2x_mc_assert(bp); + BNX2X_ERR("end crash dump -----------------\n"); + + bp->stats_state = STATS_STATE_DISABLE; + DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n"); +} + +static void bnx2x_enable_int(struct bnx2x *bp) +{ + int port = bp->port; + u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; + u32 val = REG_RD(bp, addr); + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + + if (msix) { + val &= ~HC_CONFIG_0_REG_SINGLE_ISR_EN_0; + val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + } else { + val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | + HC_CONFIG_0_REG_INT_LINE_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0; + } + + DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) msi %d\n", + val, port, addr, msix); + + REG_WR(bp, addr, val); +} + +static void bnx2x_disable_int(struct bnx2x *bp) +{ + int port = bp->port; + u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0; + u32 val = REG_RD(bp, addr); + + val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 | + HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 | + HC_CONFIG_0_REG_INT_LINE_EN_0 | + HC_CONFIG_0_REG_ATTN_BIT_EN_0); + + DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n", + val, port, addr); + + REG_WR(bp, addr, val); + if (REG_RD(bp, addr) != val) + BNX2X_ERR("BUG! proper val not read from IGU!\n"); +} + +static void bnx2x_disable_int_sync(struct bnx2x *bp) +{ + + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + int i; + + atomic_inc(&bp->intr_sem); + /* prevent the HW from sending interrupts*/ + bnx2x_disable_int(bp); + + /* make sure all ISRs are done */ + if (msix) { + for_each_queue(bp, i) + synchronize_irq(bp->msix_table[i].vector); + + /* one more for the Slow Path IRQ */ + synchronize_irq(bp->msix_table[i].vector); + } else + synchronize_irq(bp->pdev->irq); + + /* make sure sp_task is not running */ + cancel_work_sync(&bp->sp_task); + +} + +/* fast path code */ + +/* + * general service functions + */ + +static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 id, + u8 storm, u16 index, u8 op, u8 update) +{ + u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_PORT_BASE * bp->port) * 8; + struct igu_ack_register igu_ack; + + igu_ack.status_block_index = index; + igu_ack.sb_id_and_flags = + ((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) | + (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) | + (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) | + (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT)); + +/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", + (*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); */ + REG_WR(bp, BAR_IGU_INTMEM + igu_addr, (*(u32 *)&igu_ack)); +} + +static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) +{ + struct host_status_block *fpsb = fp->status_blk; + u16 rc = 0; + + barrier(); /* status block is written to by the chip */ + if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) { + fp->fp_c_idx = fpsb->c_status_block.status_block_index; + rc |= 1; + } + if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) { + fp->fp_u_idx = fpsb->u_status_block.status_block_index; + rc |= 2; + } + return rc; +} + +static inline int bnx2x_has_work(struct bnx2x_fastpath *fp) +{ + u16 rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); + + if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) + rx_cons_sb++; + + if ((rx_cons_sb != fp->rx_comp_cons) || + (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons)) + return 1; + + return 0; +} + +static u16 bnx2x_ack_int(struct bnx2x *bp) +{ + u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_PORT_BASE * bp->port) * 8; + u32 result = REG_RD(bp, BAR_IGU_INTMEM + igu_addr); + +/* DP(NETIF_MSG_INTR, "read 0x%08x from IGU addr 0x%x\n", + result, BAR_IGU_INTMEM + igu_addr); */ + +#ifdef IGU_DEBUG +#warning IGU_DEBUG active + if (result == 0) { + BNX2X_ERR("read %x from IGU\n", result); + REG_WR(bp, TM_REG_TIMER_SOFT_RST, 0); + } +#endif + return result; +} + + +/* + * fast path service functions + */ + +/* free skb in the packet ring at pos idx + * return idx of last bd freed + */ +static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 idx) +{ + struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx]; + struct eth_tx_bd *tx_bd; + struct sk_buff *skb = tx_buf->skb; + u16 bd_idx = tx_buf->first_bd; + int nbd; + + DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n", + idx, tx_buf, skb); + + /* unmap first bd */ + DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx); + tx_bd = &fp->tx_desc_ring[bd_idx]; + pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd), + BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + + nbd = le16_to_cpu(tx_bd->nbd) - 1; +#ifdef BNX2X_STOP_ON_ERROR + if (nbd > (MAX_SKB_FRAGS + 2)) { + BNX2X_ERR("bad nbd!\n"); + bnx2x_panic(); + } +#endif + + /* Skip a parse bd and the TSO split header bd + since they have no mapping */ + if (nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + + if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM | + ETH_TX_BD_FLAGS_TCP_CSUM | + ETH_TX_BD_FLAGS_SW_LSO)) { + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + tx_bd = &fp->tx_desc_ring[bd_idx]; + /* is this a TSO split header bd? */ + if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) { + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + } + + /* now free frags */ + while (nbd > 0) { + + DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx); + tx_bd = &fp->tx_desc_ring[bd_idx]; + pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd), + BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE); + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + + /* release skb */ + BUG_TRAP(skb); + dev_kfree_skb(skb); + tx_buf->first_bd = 0; + tx_buf->skb = NULL; + + return bd_idx; +} + +static inline u32 bnx2x_tx_avail(struct bnx2x_fastpath *fp) +{ + u16 used; + u32 prod; + u32 cons; + + /* Tell compiler that prod and cons can change */ + barrier(); + prod = fp->tx_bd_prod; + cons = fp->tx_bd_cons; + + used = (NUM_TX_BD - NUM_TX_RINGS + prod - cons + + (cons / TX_DESC_CNT) - (prod / TX_DESC_CNT)); + + if (prod >= cons) { + /* used = prod - cons - prod/size + cons/size */ + used -= NUM_TX_BD - NUM_TX_RINGS; + } + + BUG_TRAP(used <= fp->bp->tx_ring_size); + BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL); + + return (fp->bp->tx_ring_size - used); +} + +static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work) +{ + struct bnx2x *bp = fp->bp; + u16 hw_cons, sw_cons, bd_cons = fp->tx_bd_cons; + int done = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return; +#endif + + hw_cons = le16_to_cpu(*fp->tx_cons_sb); + sw_cons = fp->tx_pkt_cons; + + while (sw_cons != hw_cons) { + u16 pkt_cons; + + pkt_cons = TX_BD(sw_cons); + + /* prefetch(bp->tx_buf_ring[pkt_cons].skb); */ + + DP(NETIF_MSG_TX_DONE, "hw_cons %u sw_cons %u pkt_cons %d\n", + hw_cons, sw_cons, pkt_cons); + +/* if (NEXT_TX_IDX(sw_cons) != hw_cons) { + rmb(); + prefetch(fp->tx_buf_ring[NEXT_TX_IDX(sw_cons)].skb); + } +*/ + bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons); + sw_cons++; + done++; + + if (done == work) + break; + } + + fp->tx_pkt_cons = sw_cons; + fp->tx_bd_cons = bd_cons; + + /* Need to make the tx_cons update visible to start_xmit() + * before checking for netif_queue_stopped(). Without the + * memory barrier, there is a small possibility that start_xmit() + * will miss it and cause the queue to be stopped forever. + */ + smp_mb(); + + /* TBD need a thresh? */ + if (unlikely(netif_queue_stopped(bp->dev))) { + + netif_tx_lock(bp->dev); + + if (netif_queue_stopped(bp->dev) && + (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3)) + netif_wake_queue(bp->dev); + + netif_tx_unlock(bp->dev); + + } +} + +static void bnx2x_sp_event(struct bnx2x_fastpath *fp, + union eth_rx_cqe *rr_cqe) +{ + struct bnx2x *bp = fp->bp; + int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data); + int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data); + + DP(NETIF_MSG_RX_STATUS, + "fp %d cid %d got ramrod #%d state is %x type is %d\n", + fp->index, cid, command, bp->state, rr_cqe->ramrod_cqe.type); + + bp->spq_left++; + + if (fp->index) { + switch (command | fp->state) { + case (RAMROD_CMD_ID_ETH_CLIENT_SETUP | + BNX2X_FP_STATE_OPENING): + DP(NETIF_MSG_IFUP, "got MULTI[%d] setup ramrod\n", + cid); + fp->state = BNX2X_FP_STATE_OPEN; + break; + + case (RAMROD_CMD_ID_ETH_HALT | BNX2X_FP_STATE_HALTING): + DP(NETIF_MSG_IFDOWN, "got MULTI[%d] halt ramrod\n", + cid); + fp->state = BNX2X_FP_STATE_HALTED; + break; + + default: + BNX2X_ERR("unexpected MC reply(%d) state is %x\n", + command, fp->state); + } + mb(); /* force bnx2x_wait_ramrod to see the change */ + return; + } + switch (command | bp->state) { + case (RAMROD_CMD_ID_ETH_PORT_SETUP | BNX2X_STATE_OPENING_WAIT4_PORT): + DP(NETIF_MSG_IFUP, "got setup ramrod\n"); + bp->state = BNX2X_STATE_OPEN; + break; + + case (RAMROD_CMD_ID_ETH_HALT | BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(NETIF_MSG_IFDOWN, "got halt ramrod\n"); + bp->state = BNX2X_STATE_CLOSING_WAIT4_DELETE; + fp->state = BNX2X_FP_STATE_HALTED; + break; + + case (RAMROD_CMD_ID_ETH_PORT_DEL | BNX2X_STATE_CLOSING_WAIT4_DELETE): + DP(NETIF_MSG_IFDOWN, "got delete ramrod\n"); + bp->state = BNX2X_STATE_CLOSING_WAIT4_UNLOAD; + break; + + case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(NETIF_MSG_IFDOWN, "got delete ramrod for MULTI[%d]\n", cid); + bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_DELETED; + break; + + case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN): + DP(NETIF_MSG_IFUP, "got set mac ramrod\n"); + break; + + default: + BNX2X_ERR("unexpected ramrod (%d) state is %x\n", + command, bp->state); + } + + mb(); /* force bnx2x_wait_ramrod to see the change */ +} + +static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct sk_buff *skb; + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index]; + struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index]; + dma_addr_t mapping; + + skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size); + if (unlikely(skb == NULL)) + return -ENOMEM; + + mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + if (unlikely(dma_mapping_error(mapping))) { + + dev_kfree_skb(skb); + return -ENOMEM; + } + + rx_buf->skb = skb; + pci_unmap_addr_set(rx_buf, mapping, mapping); + + rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + + return 0; +} + +/* note that we are not allocating a new skb, + * we are just moving one from cons to prod + * we are not creating a new mapping, + * so there is no need to check for dma_mapping_error(). + */ +static void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp, + struct sk_buff *skb, u16 cons, u16 prod) +{ + struct bnx2x *bp = fp->bp; + struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; + struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; + struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons]; + struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; + + pci_dma_sync_single_for_device(bp->pdev, + pci_unmap_addr(cons_rx_buf, mapping), + bp->rx_offset + RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); + + prod_rx_buf->skb = cons_rx_buf->skb; + pci_unmap_addr_set(prod_rx_buf, mapping, + pci_unmap_addr(cons_rx_buf, mapping)); + *prod_bd = *cons_bd; +} + +static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) +{ + struct bnx2x *bp = fp->bp; + u16 bd_cons, bd_prod, comp_ring_cons; + u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; + int rx_pkt = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return 0; +#endif + + hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb); + if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) + hw_comp_cons++; + + bd_cons = fp->rx_bd_cons; + bd_prod = fp->rx_bd_prod; + sw_comp_cons = fp->rx_comp_cons; + sw_comp_prod = fp->rx_comp_prod; + + /* Memory barrier necessary as speculative reads of the rx + * buffer can be ahead of the index in the status block + */ + rmb(); + + DP(NETIF_MSG_RX_STATUS, + "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n", + fp->index, hw_comp_cons, sw_comp_cons); + + while (sw_comp_cons != hw_comp_cons) { + unsigned int len, pad; + struct sw_rx_bd *rx_buf; + struct sk_buff *skb; + union eth_rx_cqe *cqe; + + comp_ring_cons = RCQ_BD(sw_comp_cons); + bd_prod = RX_BD(bd_prod); + bd_cons = RX_BD(bd_cons); + + cqe = &fp->rx_comp_ring[comp_ring_cons]; + + DP(NETIF_MSG_RX_STATUS, "hw_comp_cons %u sw_comp_cons %u" + " comp_ring (%u) bd_ring (%u,%u)\n", + hw_comp_cons, sw_comp_cons, + comp_ring_cons, bd_prod, bd_cons); + DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x" + " queue %x vlan %x len %x\n", + cqe->fast_path_cqe.type, + cqe->fast_path_cqe.error_type_flags, + cqe->fast_path_cqe.status_flags, + cqe->fast_path_cqe.rss_hash_result, + cqe->fast_path_cqe.vlan_tag, cqe->fast_path_cqe.pkt_len); + + /* is this a slowpath msg? */ + if (unlikely(cqe->fast_path_cqe.type)) { + bnx2x_sp_event(fp, cqe); + goto next_cqe; + + /* this is an rx packet */ + } else { + rx_buf = &fp->rx_buf_ring[bd_cons]; + skb = rx_buf->skb; + + len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); + pad = cqe->fast_path_cqe.placement_offset; + + pci_dma_sync_single_for_device(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + pad + RX_COPY_THRESH, + PCI_DMA_FROMDEVICE); + prefetch(skb); + prefetch(((char *)(skb)) + 128); + + /* is this an error packet? */ + if (unlikely(cqe->fast_path_cqe.error_type_flags & + ETH_RX_ERROR_FALGS)) { + /* do we sometimes forward error packets anyway? */ + DP(NETIF_MSG_RX_ERR, + "ERROR flags(%u) Rx packet(%u)\n", + cqe->fast_path_cqe.error_type_flags, + sw_comp_cons); + /* TBD make sure MC counts this as a drop */ + goto reuse_rx; + } + + /* Since we don't have a jumbo ring + * copy small packets if mtu > 1500 + */ + if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) && + (len <= RX_COPY_THRESH)) { + struct sk_buff *new_skb; + + new_skb = netdev_alloc_skb(bp->dev, + len + pad); + if (new_skb == NULL) { + DP(NETIF_MSG_RX_ERR, + "ERROR packet dropped " + "because of alloc failure\n"); + /* TBD count this as a drop? */ + goto reuse_rx; + } + + /* aligned copy */ + skb_copy_from_linear_data_offset(skb, pad, + new_skb->data + pad, len); + skb_reserve(new_skb, pad); + skb_put(new_skb, len); + + bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); + + skb = new_skb; + + } else if (bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0) { + pci_unmap_single(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + skb_reserve(skb, pad); + skb_put(skb, len); + + } else { + DP(NETIF_MSG_RX_ERR, + "ERROR packet dropped because " + "of alloc failure\n"); +reuse_rx: + bnx2x_reuse_rx_skb(fp, skb, bd_cons, bd_prod); + goto next_rx; + } + + skb->protocol = eth_type_trans(skb, bp->dev); + + skb->ip_summed = CHECKSUM_NONE; + if (bp->rx_csum && BNX2X_RX_SUM_OK(cqe)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* TBD do we pass bad csum packets in promisc */ + } + +#ifdef BCM_VLAN + if ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) + & PARSING_FLAGS_NUMBER_OF_NESTED_VLANS) + && (bp->vlgrp != NULL)) + vlan_hwaccel_receive_skb(skb, bp->vlgrp, + le16_to_cpu(cqe->fast_path_cqe.vlan_tag)); + else +#endif + netif_receive_skb(skb); + + bp->dev->last_rx = jiffies; + +next_rx: + rx_buf->skb = NULL; + + bd_cons = NEXT_RX_IDX(bd_cons); + bd_prod = NEXT_RX_IDX(bd_prod); +next_cqe: + sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod); + sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons); + rx_pkt++; + + if ((rx_pkt == budget)) + break; + } /* while */ + + fp->rx_bd_cons = bd_cons; + fp->rx_bd_prod = bd_prod; + fp->rx_comp_cons = sw_comp_cons; + fp->rx_comp_prod = sw_comp_prod; + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_RCQ_PROD_OFFSET(bp->port, fp->index), sw_comp_prod); + + mmiowb(); /* keep prod updates ordered */ + + fp->rx_pkt += rx_pkt; + fp->rx_calls++; + + return rx_pkt; +} + +static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) +{ + struct bnx2x_fastpath *fp = fp_cookie; + struct bnx2x *bp = fp->bp; + struct net_device *dev = bp->dev; + int index = fp->index; + + DP(NETIF_MSG_INTR, "got an msix interrupt on [%d]\n", index); + bnx2x_ack_sb(bp, index, USTORM_ID, 0, IGU_INT_DISABLE, 0); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + prefetch(fp->rx_cons_sb); + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block.status_block_index); + prefetch(&fp->status_blk->u_status_block.status_block_index); + + netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi)); + return IRQ_HANDLED; +} + +static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct bnx2x *bp = netdev_priv(dev); + u16 status = bnx2x_ack_int(bp); + + if (unlikely(status == 0)) { + DP(NETIF_MSG_INTR, "not our interrupt!\n"); + return IRQ_NONE; + } + + DP(NETIF_MSG_INTR, "got an interrupt status is %u\n", status); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + /* Return here if interrupt is shared and is disabled */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) { + DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); + return IRQ_HANDLED; + } + + if (status & 0x2) { + struct bnx2x_fastpath *fp = &bp->fp[0]; + + prefetch(fp->rx_cons_sb); + prefetch(fp->tx_cons_sb); + prefetch(&fp->status_blk->c_status_block.status_block_index); + prefetch(&fp->status_blk->u_status_block.status_block_index); + + netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi)); + + status &= ~0x2; + if (!status) + return IRQ_HANDLED; + } + + if (unlikely(status & 0x1)) { + + schedule_work(&bp->sp_task); + + status &= ~0x1; + if (!status) + return IRQ_HANDLED; + } + + DP(NETIF_MSG_INTR, "got an unknown interrupt! (status is %u)\n", + status); + + return IRQ_HANDLED; +} + +/* end of fast path */ + +/* PHY/MAC */ + +/* + * General service functions + */ + +static void bnx2x_leds_set(struct bnx2x *bp, unsigned int speed) +{ + int port = bp->port; + + NIG_WR(NIG_REG_LED_MODE_P0 + port*4, + ((bp->hw_config & SHARED_HW_CFG_LED_MODE_MASK) >> + SHARED_HW_CFG_LED_MODE_SHIFT)); + NIG_WR(NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); + + /* Set blinking rate to ~15.9Hz */ + NIG_WR(NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4, + LED_BLINK_RATE_VAL); + NIG_WR(NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + port*4, 1); + + /* On Ax chip versions for speeds less than 10G + LED scheme is different */ + if ((CHIP_REV(bp) == CHIP_REV_Ax) && (speed < SPEED_10000)) { + NIG_WR(NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 1); + NIG_WR(NIG_REG_LED_CONTROL_TRAFFIC_P0 + port*4, 0); + NIG_WR(NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 + port*4, 1); + } +} + +static void bnx2x_leds_unset(struct bnx2x *bp) +{ + int port = bp->port; + + NIG_WR(NIG_REG_LED_10G_P0 + port*4, 0); + NIG_WR(NIG_REG_LED_MODE_P0 + port*4, SHARED_HW_CFG_LED_MAC1); +} + +static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits) +{ + u32 val = REG_RD(bp, reg); + + val |= bits; + REG_WR(bp, reg, val); + return val; +} + +static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits) +{ + u32 val = REG_RD(bp, reg); + + val &= ~bits; + REG_WR(bp, reg, val); + return val; +} + +static int bnx2x_mdio22_write(struct bnx2x *bp, u32 reg, u32 val) +{ + int rc; + u32 tmp, i; + int port = bp->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + +/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x val 0x%08x\n", + bp->phy_addr, reg, val); */ + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + tmp &= ~EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); + REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + udelay(40); + } + + tmp = ((bp->phy_addr << 21) | (reg << 16) | + (val & EMAC_MDIO_COMM_DATA) | + EMAC_MDIO_COMM_COMMAND_WRITE_22 | + EMAC_MDIO_COMM_START_BUSY); + EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + BNX2X_ERR("write phy register failed\n"); + + rc = -EBUSY; + } else { + rc = 0; + } + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + tmp |= EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); + } + + return rc; +} + +static int bnx2x_mdio22_read(struct bnx2x *bp, u32 reg, u32 *ret_val) +{ + int port = bp->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val, i; + int rc; + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + val &= ~EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); + REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + udelay(40); + } + + val = ((bp->phy_addr << 21) | (reg << 16) | + EMAC_MDIO_COMM_COMMAND_READ_22 | + EMAC_MDIO_COMM_START_BUSY); + EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + val &= EMAC_MDIO_COMM_DATA; + break; + } + } + + if (val & EMAC_MDIO_COMM_START_BUSY) { + BNX2X_ERR("read phy register failed\n"); + + *ret_val = 0x0; + rc = -EBUSY; + } else { + *ret_val = val; + rc = 0; + } + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + val |= EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); + } + +/* DP(NETIF_MSG_HW, "phy_addr 0x%x reg 0x%x ret_val 0x%08x\n", + bp->phy_addr, reg, *ret_val); */ + + return rc; +} + +static int bnx2x_mdio45_write(struct bnx2x *bp, u32 reg, u32 addr, u32 val) +{ + int rc = 0; + u32 tmp, i; + int port = bp->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + tmp &= ~EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); + REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + udelay(40); + } + + /* set clause 45 mode */ + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + tmp |= EMAC_MDIO_MODE_CLAUSE_45; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); + + /* address */ + tmp = ((bp->phy_addr << 21) | (reg << 16) | addr | + EMAC_MDIO_COMM_COMMAND_ADDRESS | + EMAC_MDIO_COMM_START_BUSY); + EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + BNX2X_ERR("write phy register failed\n"); + + rc = -EBUSY; + } else { + /* data */ + tmp = ((bp->phy_addr << 21) | (reg << 16) | val | + EMAC_MDIO_COMM_COMMAND_WRITE_45 | + EMAC_MDIO_COMM_START_BUSY); + EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + BNX2X_ERR("write phy register failed\n"); + + rc = -EBUSY; + } + } + + /* unset clause 45 mode */ + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + tmp &= ~EMAC_MDIO_MODE_CLAUSE_45; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + tmp = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + tmp |= EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, tmp); + } + + return rc; +} + +static int bnx2x_mdio45_read(struct bnx2x *bp, u32 reg, u32 addr, + u32 *ret_val) +{ + int port = bp->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val, i; + int rc = 0; + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + val &= ~EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); + REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + udelay(40); + } + + /* set clause 45 mode */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + val |= EMAC_MDIO_MODE_CLAUSE_45; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); + + /* address */ + val = ((bp->phy_addr << 21) | (reg << 16) | addr | + EMAC_MDIO_COMM_COMMAND_ADDRESS | + EMAC_MDIO_COMM_START_BUSY); + EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + + if (val & EMAC_MDIO_COMM_START_BUSY) { + BNX2X_ERR("read phy register failed\n"); + + *ret_val = 0; + rc = -EBUSY; + } else { + /* data */ + val = ((bp->phy_addr << 21) | (reg << 16) | + EMAC_MDIO_COMM_COMMAND_READ_45 | + EMAC_MDIO_COMM_START_BUSY); + EMAC_WR(EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + val &= EMAC_MDIO_COMM_DATA; + break; + } + } + + if (val & EMAC_MDIO_COMM_START_BUSY) { + BNX2X_ERR("read phy register failed\n"); + + val = 0; + rc = -EBUSY; + } + + *ret_val = val; + } + + /* unset clause 45 mode */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + val &= ~EMAC_MDIO_MODE_CLAUSE_45; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); + + if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) { + + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + val |= EMAC_MDIO_MODE_AUTO_POLL; + EMAC_WR(EMAC_REG_EMAC_MDIO_MODE, val); + } + + return rc; +} + +static int bnx2x_mdio45_vwrite(struct bnx2x *bp, u32 reg, u32 addr, u32 val) +{ + int i; + u32 rd_val; + + might_sleep(); + for (i = 0; i < 10; i++) { + bnx2x_mdio45_write(bp, reg, addr, val); + msleep(5); + bnx2x_mdio45_read(bp, reg, addr, &rd_val); + /* if the read value is not the same as the value we wrote, + we should write it again */ + if (rd_val == val) + return 0; + } + BNX2X_ERR("MDIO write in CL45 failed\n"); + return -EBUSY; +} + +/* + * link managment + */ + +static void bnx2x_flow_ctrl_resolve(struct bnx2x *bp, u32 gp_status) +{ + u32 ld_pause; /* local driver */ + u32 lp_pause; /* link partner */ + u32 pause_result; + + bp->flow_ctrl = 0; + + /* reolve from gp_status in case of AN complete and not sgmii */ + if ((bp->req_autoneg & AUTONEG_FLOW_CTRL) && + (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) && + (!(bp->phy_flags & PHY_SGMII_FLAG)) && + (XGXS_EXT_PHY_TYPE(bp) == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)) { + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, + &ld_pause); + bnx2x_mdio22_read(bp, + MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, + &lp_pause); + pause_result = (ld_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5; + pause_result |= (lp_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; + DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); + + switch (pause_result) { /* ASYM P ASYM P */ + case 0xb: /* 1 0 1 1 */ + bp->flow_ctrl = FLOW_CTRL_TX; + break; + + case 0xe: /* 1 1 1 0 */ + bp->flow_ctrl = FLOW_CTRL_RX; + break; + + case 0x5: /* 0 1 0 1 */ + case 0x7: /* 0 1 1 1 */ + case 0xd: /* 1 1 0 1 */ + case 0xf: /* 1 1 1 1 */ + bp->flow_ctrl = FLOW_CTRL_BOTH; + break; + + default: + break; + } + + } else { /* forced mode */ + switch (bp->req_flow_ctrl) { + case FLOW_CTRL_AUTO: + if (bp->dev->mtu <= 4500) + bp->flow_ctrl = FLOW_CTRL_BOTH; + else + bp->flow_ctrl = FLOW_CTRL_TX; + break; + + case FLOW_CTRL_TX: + case FLOW_CTRL_RX: + case FLOW_CTRL_BOTH: + bp->flow_ctrl = bp->req_flow_ctrl; + break; + + case FLOW_CTRL_NONE: + default: + break; + } + } + DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", bp->flow_ctrl); +} + +static void bnx2x_link_settings_status(struct bnx2x *bp, u32 gp_status) +{ + bp->link_status = 0; + + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { + DP(NETIF_MSG_LINK, "link up\n"); + + bp->link_up = 1; + bp->link_status |= LINK_STATUS_LINK_UP; + + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS) + bp->duplex = DUPLEX_FULL; + else + bp->duplex = DUPLEX_HALF; + + bnx2x_flow_ctrl_resolve(bp, gp_status); + + switch (gp_status & GP_STATUS_SPEED_MASK) { + case GP_STATUS_10M: + bp->line_speed = SPEED_10; + if (bp->duplex == DUPLEX_FULL) + bp->link_status |= LINK_10TFD; + else + bp->link_status |= LINK_10THD; + break; + + case GP_STATUS_100M: + bp->line_speed = SPEED_100; + if (bp->duplex == DUPLEX_FULL) + bp->link_status |= LINK_100TXFD; + else + bp->link_status |= LINK_100TXHD; + break; + + case GP_STATUS_1G: + case GP_STATUS_1G_KX: + bp->line_speed = SPEED_1000; + if (bp->duplex == DUPLEX_FULL) + bp->link_status |= LINK_1000TFD; + else + bp->link_status |= LINK_1000THD; + break; + + case GP_STATUS_2_5G: + bp->line_speed = SPEED_2500; + if (bp->duplex == DUPLEX_FULL) + bp->link_status |= LINK_2500TFD; + else + bp->link_status |= LINK_2500THD; + break; + + case GP_STATUS_5G: + case GP_STATUS_6G: + BNX2X_ERR("link speed unsupported gp_status 0x%x\n", + gp_status); + break; + + case GP_STATUS_10G_KX4: + case GP_STATUS_10G_HIG: + case GP_STATUS_10G_CX4: + bp->line_speed = SPEED_10000; + bp->link_status |= LINK_10GTFD; + break; + + case GP_STATUS_12G_HIG: + bp->line_speed = SPEED_12000; + bp->link_status |= LINK_12GTFD; + break; + + case GP_STATUS_12_5G: + bp->line_speed = SPEED_12500; + bp->link_status |= LINK_12_5GTFD; + break; + + case GP_STATUS_13G: + bp->line_speed = SPEED_13000; + bp->link_status |= LINK_13GTFD; + break; + + case GP_STATUS_15G: + bp->line_speed = SPEED_15000; + bp->link_status |= LINK_15GTFD; + break; + + case GP_STATUS_16G: + bp->line_speed = SPEED_16000; + bp->link_status |= LINK_16GTFD; + break; + + default: + BNX2X_ERR("link speed unsupported gp_status 0x%x\n", + gp_status); + break; + } + + bp->link_status |= LINK_STATUS_SERDES_LINK; + + if (bp->req_autoneg & AUTONEG_SPEED) { + bp->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED; + + if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) + bp->link_status |= + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + + if (bp->autoneg & AUTONEG_PARALLEL) + bp->link_status |= + LINK_STATUS_PARALLEL_DETECTION_USED; + } + + if (bp->flow_ctrl & FLOW_CTRL_TX) + bp->link_status |= LINK_STATUS_TX_FLOW_CONTROL_ENABLED; + + if (bp->flow_ctrl & FLOW_CTRL_RX) + bp->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED; + + } else { /* link_down */ + DP(NETIF_MSG_LINK, "link down\n"); + + bp->link_up = 0; + + bp->line_speed = 0; + bp->duplex = DUPLEX_FULL; + bp->flow_ctrl = 0; + } + + DP(NETIF_MSG_LINK, "gp_status 0x%x link_up %d\n" + DP_LEVEL " line_speed %d duplex %d flow_ctrl 0x%x" + " link_status 0x%x\n", + gp_status, bp->link_up, bp->line_speed, bp->duplex, bp->flow_ctrl, + bp->link_status); +} + +static void bnx2x_link_int_ack(struct bnx2x *bp, int is_10g) +{ + int port = bp->port; + + /* first reset all status + * we asume only one line will be change at a time */ + bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + (NIG_XGXS0_LINK_STATUS | + NIG_SERDES0_LINK_STATUS | + NIG_STATUS_INTERRUPT_XGXS0_LINK10G)); + if (bp->link_up) { + if (is_10g) { + /* Disable the 10G link interrupt + * by writing 1 to the status register + */ + DP(NETIF_MSG_LINK, "10G XGXS link up\n"); + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + NIG_STATUS_INTERRUPT_XGXS0_LINK10G); + + } else if (bp->phy_flags & PHY_XGXS_FLAG) { + /* Disable the link interrupt + * by writing 1 to the relevant lane + * in the status register + */ + DP(NETIF_MSG_LINK, "1G XGXS link up\n"); + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + ((1 << bp->ser_lane) << + NIG_XGXS0_LINK_STATUS_SIZE)); + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "SerDes link up\n"); + /* Disable the link interrupt + * by writing 1 to the status register + */ + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + NIG_SERDES0_LINK_STATUS); + } + + } else { /* link_down */ + } +} + +static int bnx2x_ext_phy_is_link_up(struct bnx2x *bp) +{ + u32 ext_phy_type; + u32 ext_phy_addr; + u32 local_phy; + u32 val = 0; + u32 rx_sd, pcs_status; + + if (bp->phy_flags & PHY_XGXS_FLAG) { + local_phy = bp->phy_addr; + ext_phy_addr = ((bp->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + bp->phy_addr = (u8)ext_phy_addr; + + ext_phy_type = XGXS_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "XGXS Direct\n"); + val = 1; + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + DP(NETIF_MSG_LINK, "XGXS 8705\n"); + bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD, + EXT_PHY_OPT_LASI_STATUS, &val); + DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val); + + bnx2x_mdio45_read(bp, EXT_PHY_OPT_WIS_DEVAD, + EXT_PHY_OPT_LASI_STATUS, &val); + DP(NETIF_MSG_LINK, "8705 LASI status is %d\n", val); + + bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_PMD_RX_SD, &rx_sd); + val = (rx_sd & 0x1); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "XGXS 8706\n"); + bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_LASI_STATUS, &val); + DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val); + + bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_LASI_STATUS, &val); + DP(NETIF_MSG_LINK, "8706 LASI status is %d\n", val); + + bnx2x_mdio45_read(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_PMD_RX_SD, &rx_sd); + bnx2x_mdio45_read(bp, EXT_PHY_OPT_PCS_DEVAD, + EXT_PHY_OPT_PCS_STATUS, &pcs_status); + DP(NETIF_MSG_LINK, "8706 rx_sd 0x%x" + " pcs_status 0x%x\n", rx_sd, pcs_status); + /* link is up if both bit 0 of pmd_rx and + * bit 0 of pcs_status are set + */ + val = (rx_sd & pcs_status); + break; + + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + bp->ext_phy_config); + val = 0; + break; + } + bp->phy_addr = local_phy; + + } else { /* SerDes */ + ext_phy_type = SERDES_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "SerDes Direct\n"); + val = 1; + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + DP(NETIF_MSG_LINK, "SerDes 5482\n"); + val = 1; + break; + + default: + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", + bp->ext_phy_config); + val = 0; + break; + } + } + + return val; +} + +static void bnx2x_bmac_enable(struct bnx2x *bp, int is_lb) +{ + int port = bp->port; + u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 wb_write[2]; + u32 val; + + DP(NETIF_MSG_LINK, "enableing BigMAC\n"); + /* reset and unreset the BigMac */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + msleep(5); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* enable access for bmac registers */ + NIG_WR(NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); + + /* XGXS control */ + wb_write[0] = 0x3c; + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL, + wb_write, 2); + + /* tx MAC SA */ + wb_write[0] = ((bp->dev->dev_addr[2] << 24) | + (bp->dev->dev_addr[3] << 16) | + (bp->dev->dev_addr[4] << 8) | + bp->dev->dev_addr[5]); + wb_write[1] = ((bp->dev->dev_addr[0] << 8) | + bp->dev->dev_addr[1]); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, + wb_write, 2); + + /* tx control */ + val = 0xc0; + if (bp->flow_ctrl & FLOW_CTRL_TX) + val |= 0x800000; + wb_write[0] = val; + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_write, 2); + + /* set tx mtu */ + wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; /* -CRC */ + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_write, 2); + + /* mac control */ + val = 0x3; + if (is_lb) { + val |= 0x4; + DP(NETIF_MSG_LINK, "enable bmac loopback\n"); + } + wb_write[0] = val; + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, + wb_write, 2); + + /* rx control set to don't strip crc */ + val = 0x14; + if (bp->flow_ctrl & FLOW_CTRL_RX) + val |= 0x20; + wb_write[0] = val; + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_write, 2); + + /* set rx mtu */ + wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_write, 2); + + /* set cnt max size */ + wb_write[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; /* -VLAN */ + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, + wb_write, 2); + + /* configure safc */ + wb_write[0] = 0x1000200; + wb_write[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, + wb_write, 2); + + /* fix for emulation */ + if (CHIP_REV(bp) == CHIP_REV_EMUL) { + wb_write[0] = 0xf000; + wb_write[1] = 0; + REG_WR_DMAE(bp, + bmac_addr + BIGMAC_REGISTER_TX_PAUSE_THRESHOLD, + wb_write, 2); + } + + /* reset old bmac stats */ + memset(&bp->old_bmac, 0, sizeof(struct bmac_stats)); + + NIG_WR(NIG_REG_XCM0_OUT_EN + port*4, 0x0); + + /* select XGXS */ + NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1); + NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); + + /* disable the NIG in/out to the emac */ + NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0x0); + NIG_WR(NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0); + NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); + + /* enable the NIG in/out to the bmac */ + NIG_WR(NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); + + NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0x1); + val = 0; + if (bp->flow_ctrl & FLOW_CTRL_TX) + val = 1; + NIG_WR(NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); + NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0x1); + + bp->phy_flags |= PHY_BMAC_FLAG; + + bp->stats_state = STATS_STATE_ENABLE; +} + +static void bnx2x_emac_enable(struct bnx2x *bp) +{ + int port = bp->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val; + int timeout; + + DP(NETIF_MSG_LINK, "enableing EMAC\n"); + /* reset and unreset the emac core */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + msleep(5); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + + /* enable emac and not bmac */ + NIG_WR(NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); + + /* for paladium */ + if (CHIP_REV(bp) == CHIP_REV_EMUL) { + /* Use lane 1 (of lanes 0-3) */ + NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); + NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); + } + /* for fpga */ + else if (CHIP_REV(bp) == CHIP_REV_FPGA) { + /* Use lane 1 (of lanes 0-3) */ + NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, 1); + NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); + } + /* ASIC */ + else { + if (bp->phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "XGXS\n"); + /* select the master lanes (out of 0-3) */ + NIG_WR(NIG_REG_XGXS_LANE_SEL_P0 + port*4, + bp->ser_lane); + /* select XGXS */ + NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "SerDes\n"); + /* select SerDes */ + NIG_WR(NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); + } + } + + /* enable emac */ + NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 1); + + /* init emac - use read-modify-write */ + /* self clear reset */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET)); + + timeout = 200; + while (val & EMAC_MODE_RESET) { + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val); + if (!timeout) { + BNX2X_ERR("EMAC timeout!\n"); + break; + } + timeout--; + } + + /* reset tx part */ + EMAC_WR(EMAC_REG_EMAC_TX_MODE, EMAC_TX_MODE_RESET); + + timeout = 200; + while (val & EMAC_TX_MODE_RESET) { + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_TX_MODE); + DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val); + if (!timeout) { + BNX2X_ERR("EMAC timeout!\n"); + break; + } + timeout--; + } + + if (CHIP_REV_IS_SLOW(bp)) { + /* config GMII mode */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII)); + + } else { /* ASIC */ + /* pause enable/disable */ + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + if (bp->flow_ctrl & FLOW_CTRL_RX) + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_EXT_PAUSE_EN); + if (bp->flow_ctrl & FLOW_CTRL_TX) + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_EXT_PAUSE_EN); + } + + /* KEEP_VLAN_TAG, promiscous */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); + val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS; + EMAC_WR(EMAC_REG_EMAC_RX_MODE, val); + + /* identify magic packets */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(EMAC_REG_EMAC_MODE, (val | EMAC_MODE_MPKT)); + + /* enable emac for jumbo packets */ + EMAC_WR(EMAC_REG_EMAC_RX_MTU_SIZE, + (EMAC_RX_MTU_SIZE_JUMBO_ENA | + (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD))); /* -VLAN */ + + /* strip CRC */ + NIG_WR(NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1); + + val = ((bp->dev->dev_addr[0] << 8) | + bp->dev->dev_addr[1]); + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val); + + val = ((bp->dev->dev_addr[2] << 24) | + (bp->dev->dev_addr[3] << 16) | + (bp->dev->dev_addr[4] << 8) | + bp->dev->dev_addr[5]); + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val); + + /* disable the NIG in/out to the bmac */ + NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0x0); + NIG_WR(NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0); + NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0x0); + + /* enable the NIG in/out to the emac */ + NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0x1); + val = 0; + if (bp->flow_ctrl & FLOW_CTRL_TX) + val = 1; + NIG_WR(NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); + NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1); + + if (CHIP_REV(bp) == CHIP_REV_FPGA) { + /* take the BigMac out of reset */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* enable access for bmac registers */ + NIG_WR(NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); + } + + bp->phy_flags |= PHY_EMAC_FLAG; + + bp->stats_state = STATS_STATE_ENABLE; +} + +static void bnx2x_emac_program(struct bnx2x *bp) +{ + u16 mode = 0; + int port = bp->port; + + DP(NETIF_MSG_LINK, "setting link speed & duplex\n"); + bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, + (EMAC_MODE_25G_MODE | + EMAC_MODE_PORT_MII_10M | + EMAC_MODE_HALF_DUPLEX)); + switch (bp->line_speed) { + case SPEED_10: + mode |= EMAC_MODE_PORT_MII_10M; + break; + + case SPEED_100: + mode |= EMAC_MODE_PORT_MII; + break; + + case SPEED_1000: + mode |= EMAC_MODE_PORT_GMII; + break; + + case SPEED_2500: + mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII); + break; + + default: + /* 10G not valid for EMAC */ + BNX2X_ERR("Invalid line_speed 0x%x\n", bp->line_speed); + break; + } + + if (bp->duplex == DUPLEX_HALF) + mode |= EMAC_MODE_HALF_DUPLEX; + bnx2x_bits_en(bp, GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, + mode); + + bnx2x_leds_set(bp, bp->line_speed); +} + +static void bnx2x_set_sgmii_tx_driver(struct bnx2x *bp) +{ + u32 lp_up2; + u32 tx_driver; + + /* read precomp */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G); + bnx2x_mdio22_read(bp, MDIO_OVER_1G_LP_UP2, &lp_up2); + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_TX0); + bnx2x_mdio22_read(bp, MDIO_TX0_TX_DRIVER, &tx_driver); + + /* bits [10:7] at lp_up2, positioned at [15:12] */ + lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >> + MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) << + MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT); + + if ((lp_up2 != 0) && + (lp_up2 != (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK))) { + /* replace tx_driver bits [15:12] */ + tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK; + tx_driver |= lp_up2; + bnx2x_mdio22_write(bp, MDIO_TX0_TX_DRIVER, tx_driver); + } +} + +static void bnx2x_pbf_update(struct bnx2x *bp) +{ + int port = bp->port; + u32 init_crd, crd; + u32 count = 1000; + u32 pause = 0; + + + /* disable port */ + REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1); + + /* wait for init credit */ + init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4); + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd); + + while ((init_crd != crd) && count) { + msleep(5); + + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + count--; + } + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + if (init_crd != crd) + BNX2X_ERR("BUG! init_crd 0x%x != crd 0x%x\n", init_crd, crd); + + if (bp->flow_ctrl & FLOW_CTRL_RX) + pause = 1; + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, pause); + if (pause) { + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0); + /* update init credit */ + init_crd = 778; /* (800-18-4) */ + + } else { + u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD)/16; + + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh); + /* update init credit */ + switch (bp->line_speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + init_crd = thresh + 55 - 22; + break; + + case SPEED_2500: + init_crd = thresh + 138 - 22; + break; + + case SPEED_10000: + init_crd = thresh + 553 - 22; + break; + + default: + BNX2X_ERR("Invalid line_speed 0x%x\n", + bp->line_speed); + break; + } + } + REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); + DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n", + bp->line_speed, init_crd); + + /* probe the credit changes */ + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1); + msleep(5); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0); + + /* enable port */ + REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0); +} + +static void bnx2x_update_mng(struct bnx2x *bp) +{ + if (!nomcp) + SHMEM_WR(bp, drv_fw_mb[bp->port].link_status, + bp->link_status); +} + +static void bnx2x_link_report(struct bnx2x *bp) +{ + if (bp->link_up) { + netif_carrier_on(bp->dev); + printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name); + + printk("%d Mbps ", bp->line_speed); + + if (bp->duplex == DUPLEX_FULL) + printk("full duplex"); + else + printk("half duplex"); + + if (bp->flow_ctrl) { + if (bp->flow_ctrl & FLOW_CTRL_RX) { + printk(", receive "); + if (bp->flow_ctrl & FLOW_CTRL_TX) + printk("& transmit "); + } else { + printk(", transmit "); + } + printk("flow control ON"); + } + printk("\n"); + + } else { /* link_down */ + netif_carrier_off(bp->dev); + printk(KERN_INFO PFX "%s NIC Link is Down\n", bp->dev->name); + } +} + +static void bnx2x_link_up(struct bnx2x *bp) +{ + int port = bp->port; + + /* PBF - link up */ + bnx2x_pbf_update(bp); + + /* disable drain */ + NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0); + + /* update shared memory */ + bnx2x_update_mng(bp); + + /* indicate link up */ + bnx2x_link_report(bp); +} + +static void bnx2x_link_down(struct bnx2x *bp) +{ + int port = bp->port; + + /* notify stats */ + if (bp->stats_state != STATS_STATE_DISABLE) { + bp->stats_state = STATS_STATE_STOP; + DP(BNX2X_MSG_STATS, "stats_state - STOP\n"); + } + + /* indicate link down */ + bp->phy_flags &= ~(PHY_BMAC_FLAG | PHY_EMAC_FLAG); + + /* reset BigMac */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* ignore drain flag interrupt */ + /* activate nig drain */ + NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); + + /* update shared memory */ + bnx2x_update_mng(bp); + + /* indicate link down */ + bnx2x_link_report(bp); +} + +static void bnx2x_init_mac_stats(struct bnx2x *bp); + +/* This function is called upon link interrupt */ +static void bnx2x_link_update(struct bnx2x *bp) +{ + u32 gp_status; + int port = bp->port; + int i; + int link_10g; + + DP(NETIF_MSG_LINK, "port %x, is xgxs %x, stat_mask 0x%x," + " int_mask 0x%x, saved_mask 0x%x, MI_INT %x, SERDES_LINK %x," + " 10G %x, XGXS_LINK %x\n", port, (bp->phy_flags & PHY_XGXS_FLAG), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4), + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), bp->nig_mask, + REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), + REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68) + ); + + might_sleep(); + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_GP_STATUS); + /* avoid fast toggling */ + for (i = 0 ; i < 10 ; i++) { + msleep(10); + bnx2x_mdio22_read(bp, MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); + } + + bnx2x_link_settings_status(bp, gp_status); + + /* anything 10 and over uses the bmac */ + link_10g = ((bp->line_speed >= SPEED_10000) && + (bp->line_speed <= SPEED_16000)); + + bnx2x_link_int_ack(bp, link_10g); + + /* link is up only if both local phy and external phy are up */ + if (bp->link_up && bnx2x_ext_phy_is_link_up(bp)) { + if (link_10g) { + bnx2x_bmac_enable(bp, 0); + bnx2x_leds_set(bp, SPEED_10000); + + } else { + bnx2x_emac_enable(bp); + bnx2x_emac_program(bp); + + /* AN complete? */ + if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) { + if (!(bp->phy_flags & PHY_SGMII_FLAG)) + bnx2x_set_sgmii_tx_driver(bp); + } + } + bnx2x_link_up(bp); + + } else { /* link down */ + bnx2x_leds_unset(bp); + bnx2x_link_down(bp); + } + + bnx2x_init_mac_stats(bp); +} + +/* + * Init service functions + */ + +static void bnx2x_set_aer_mmd(struct bnx2x *bp) +{ + u16 offset = (bp->phy_flags & PHY_XGXS_FLAG) ? + (bp->phy_addr + bp->ser_lane) : 0; + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_AER_BLOCK); + bnx2x_mdio22_write(bp, MDIO_AER_BLOCK_AER_REG, 0x3800 + offset); +} + +static void bnx2x_set_master_ln(struct bnx2x *bp) +{ + u32 new_master_ln; + + /* set the master_ln for AN */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2); + bnx2x_mdio22_read(bp, MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + &new_master_ln); + bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + (new_master_ln | bp->ser_lane)); +} + +static void bnx2x_reset_unicore(struct bnx2x *bp) +{ + u32 mii_control; + int i; + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control); + /* reset the unicore */ + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | MDIO_COMBO_IEEO_MII_CONTROL_RESET)); + + /* wait for the reset to self clear */ + for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { + udelay(5); + + /* the reset erased the previous bank value */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + + if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) { + udelay(5); + return; + } + } + + BNX2X_ERR("BUG! unicore is still in reset!\n"); +} + +static void bnx2x_set_swap_lanes(struct bnx2x *bp) +{ + /* Each two bits represents a lane number: + No swap is 0123 => 0x1b no need to enable the swap */ + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_XGXS_BLOCK2); + if (bp->rx_lane_swap != 0x1b) { + bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_RX_LN_SWAP, + (bp->rx_lane_swap | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE)); + } else { + bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0); + } + + if (bp->tx_lane_swap != 0x1b) { + bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TX_LN_SWAP, + (bp->tx_lane_swap | + MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE)); + } else { + bnx2x_mdio22_write(bp, MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0); + } +} + +static void bnx2x_set_parallel_detection(struct bnx2x *bp) +{ + u32 control2; + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); + bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + &control2); + + if (bp->autoneg & AUTONEG_PARALLEL) { + control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; + } else { + control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; + } + bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + control2); + + if (bp->phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "XGXS\n"); + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_10G_PARALLEL_DETECT); + + bnx2x_mdio22_write(bp, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT); + + bnx2x_mdio22_read(bp, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + &control2); + + if (bp->autoneg & AUTONEG_PARALLEL) { + control2 |= + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; + } else { + control2 &= + ~MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; + } + bnx2x_mdio22_write(bp, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + control2); + } +} + +static void bnx2x_set_autoneg(struct bnx2x *bp) +{ + u32 reg_val; + + /* CL37 Autoneg */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + if ((bp->req_autoneg & AUTONEG_SPEED) && + (bp->autoneg & AUTONEG_CL37)) { + /* CL37 Autoneg Enabled */ + reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN; + } else { + /* CL37 Autoneg Disabled */ + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN); + } + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* Enable/Disable Autodetection */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); + bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN; + + if ((bp->req_autoneg & AUTONEG_SPEED) && + (bp->autoneg & AUTONEG_SGMII_FIBER_AUTODET)) { + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; + } else { + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; + } + bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val); + + /* Enable TetonII and BAM autoneg */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_BAM_NEXT_PAGE); + bnx2x_mdio22_read(bp, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + ®_val); + if ((bp->req_autoneg & AUTONEG_SPEED) && + (bp->autoneg & AUTONEG_CL37) && (bp->autoneg & AUTONEG_BAM)) { + /* Enable BAM aneg Mode and TetonII aneg Mode */ + reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); + } else { + /* TetonII and BAM Autoneg Disabled */ + reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); + } + bnx2x_mdio22_write(bp, MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + reg_val); + + /* Enable Clause 73 Aneg */ + if ((bp->req_autoneg & AUTONEG_SPEED) && + (bp->autoneg & AUTONEG_CL73)) { + /* Enable BAM Station Manager */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_USERB0); + bnx2x_mdio22_write(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL1, + (MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN)); + + /* Merge CL73 and CL37 aneg resolution */ + bnx2x_mdio22_read(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL3, + ®_val); + bnx2x_mdio22_write(bp, MDIO_CL73_USERB0_CL73_BAM_CTRL3, + (reg_val | + MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR)); + + /* Set the CL73 AN speed */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB1); + bnx2x_mdio22_read(bp, MDIO_CL73_IEEEB1_AN_ADV2, ®_val); + /* In the SerDes we support only the 1G. + In the XGXS we support the 10G KX4 + but we currently do not support the KR */ + if (bp->phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "XGXS\n"); + /* 10G KX4 */ + reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4; + } else { + DP(NETIF_MSG_LINK, "SerDes\n"); + /* 1000M KX */ + reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX; + } + bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB1_AN_ADV2, reg_val); + + /* CL73 Autoneg Enabled */ + reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; + } else { + /* CL73 Autoneg Disabled */ + reg_val = 0; + } + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0); + bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val); +} + +/* program SerDes, forced speed */ +static void bnx2x_program_serdes(struct bnx2x *bp) +{ + u32 reg_val; + + /* program duplex, disable autoneg */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN); + if (bp->req_duplex == DUPLEX_FULL) + reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* program speed + - needed only if the speed is greater than 1G (2.5G or 10G) */ + if (bp->req_line_speed > SPEED_1000) { + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); + bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_MISC1, ®_val); + /* clearing the speed value before setting the right speed */ + reg_val &= ~MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK; + reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M | + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL); + if (bp->req_line_speed == SPEED_10000) + reg_val |= + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4; + bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_MISC1, reg_val); + } +} + +static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x *bp) +{ + u32 val = 0; + + /* configure the 48 bits for BAM AN */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_OVER_1G); + + /* set extended capabilities */ + if (bp->advertising & ADVERTISED_2500baseT_Full) + val |= MDIO_OVER_1G_UP1_2_5G; + if (bp->advertising & ADVERTISED_10000baseT_Full) + val |= MDIO_OVER_1G_UP1_10G; + bnx2x_mdio22_write(bp, MDIO_OVER_1G_UP1, val); + + bnx2x_mdio22_write(bp, MDIO_OVER_1G_UP3, 0); +} + +static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x *bp) +{ + u32 an_adv; + + /* for AN, we are always publishing full duplex */ + an_adv = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; + + /* set pause */ + switch (bp->pause_mode) { + case PAUSE_SYMMETRIC: + an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC; + break; + case PAUSE_ASYMMETRIC: + an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + case PAUSE_BOTH: + an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + break; + case PAUSE_NONE: + an_adv |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; + break; + } + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_AUTO_NEG_ADV, an_adv); +} + +static void bnx2x_restart_autoneg(struct bnx2x *bp) +{ + if (bp->autoneg & AUTONEG_CL73) { + /* enable and restart clause 73 aneg */ + u32 an_ctrl; + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0); + bnx2x_mdio22_read(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &an_ctrl); + bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (an_ctrl | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + + } else { + /* Enable and restart BAM/CL37 aneg */ + u32 mii_control; + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + } +} + +static void bnx2x_initialize_sgmii_process(struct bnx2x *bp) +{ + u32 control1; + + /* in SGMII mode, the unicore is always slave */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_SERDES_DIGITAL); + bnx2x_mdio22_read(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + &control1); + control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT; + /* set sgmii mode (and not fiber) */ + control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE); + bnx2x_mdio22_write(bp, MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + control1); + + /* if forced speed */ + if (!(bp->req_autoneg & AUTONEG_SPEED)) { + /* set speed, disable autoneg */ + u32 mii_control; + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK | + MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX); + + switch (bp->req_line_speed) { + case SPEED_100: + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100; + break; + case SPEED_1000: + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000; + break; + case SPEED_10: + /* there is nothing to set for 10M */ + break; + default: + /* invalid speed for SGMII */ + DP(NETIF_MSG_LINK, "Invalid req_line_speed 0x%x\n", + bp->req_line_speed); + break; + } + + /* setting the full duplex */ + if (bp->req_duplex == DUPLEX_FULL) + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + mii_control); + + } else { /* AN mode */ + /* enable and restart AN */ + bnx2x_restart_autoneg(bp); + } +} + +static void bnx2x_link_int_enable(struct bnx2x *bp) +{ + int port = bp->port; + + /* setting the status to report on link up + for either XGXS or SerDes */ + bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + (NIG_XGXS0_LINK_STATUS | + NIG_STATUS_INTERRUPT_XGXS0_LINK10G | + NIG_SERDES0_LINK_STATUS)); + + if (bp->phy_flags & PHY_XGXS_FLAG) { + /* TBD - + * in force mode (not AN) we can enable just the relevant + * interrupt + * Even in AN we might enable only one according to the AN + * speed mask + */ + bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G)); + DP(NETIF_MSG_LINK, "enable XGXS interrupt\n"); + + } else { /* SerDes */ + bnx2x_bits_en(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + NIG_MASK_SERDES0_LINK_STATUS); + DP(NETIF_MSG_LINK, "enable SerDes interrupt\n"); + } +} + +static void bnx2x_ext_phy_init(struct bnx2x *bp) +{ + int port = bp->port; + u32 ext_phy_type; + u32 ext_phy_addr; + u32 local_phy; + + if (bp->phy_flags & PHY_XGXS_FLAG) { + local_phy = bp->phy_addr; + ext_phy_addr = ((bp->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + + ext_phy_type = XGXS_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "XGXS Direct\n"); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + DP(NETIF_MSG_LINK, "XGXS 8705\n"); + bnx2x_bits_en(bp, + NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + NIG_MASK_MI_INT); + DP(NETIF_MSG_LINK, "enabled extenal phy int\n"); + + bp->phy_addr = ext_phy_type; + bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_PMD_MISC_CNTL, + 0x8288); + bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_PHY_IDENTIFIER, + 0x7fbf); + bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_CMU_PLL_BYPASS, + 0x0100); + bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_WIS_DEVAD, + EXT_PHY_OPT_LASI_CNTL, 0x1); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "XGXS 8706\n"); + bnx2x_bits_en(bp, + NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + NIG_MASK_MI_INT); + DP(NETIF_MSG_LINK, "enabled extenal phy int\n"); + + bp->phy_addr = ext_phy_type; + bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_PMD_DIGITAL_CNT, + 0x400); + bnx2x_mdio45_vwrite(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_LASI_CNTL, 0x1); + break; + + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + bp->ext_phy_config); + break; + } + bp->phy_addr = local_phy; + + } else { /* SerDes */ +/* ext_phy_addr = ((bp->ext_phy_config & + PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT); +*/ + ext_phy_type = SERDES_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "SerDes Direct\n"); + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + DP(NETIF_MSG_LINK, "SerDes 5482\n"); + bnx2x_bits_en(bp, + NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + NIG_MASK_MI_INT); + DP(NETIF_MSG_LINK, "enabled extenal phy int\n"); + break; + + default: + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", + bp->ext_phy_config); + break; + } + } +} + +static void bnx2x_ext_phy_reset(struct bnx2x *bp) +{ + u32 ext_phy_type; + u32 ext_phy_addr; + u32 local_phy; + + if (bp->phy_flags & PHY_XGXS_FLAG) { + ext_phy_type = XGXS_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "XGXS Direct\n"); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + DP(NETIF_MSG_LINK, "XGXS 8705/6\n"); + local_phy = bp->phy_addr; + ext_phy_addr = ((bp->ext_phy_config & + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT); + bp->phy_addr = (u8)ext_phy_addr; + bnx2x_mdio45_write(bp, EXT_PHY_OPT_PMA_PMD_DEVAD, + EXT_PHY_OPT_CNTL, 0xa040); + bp->phy_addr = local_phy; + break; + + default: + DP(NETIF_MSG_LINK, "BAD XGXS ext_phy_config 0x%x\n", + bp->ext_phy_config); + break; + } + + } else { /* SerDes */ + ext_phy_type = SERDES_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + DP(NETIF_MSG_LINK, "SerDes Direct\n"); + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + DP(NETIF_MSG_LINK, "SerDes 5482\n"); + break; + + default: + DP(NETIF_MSG_LINK, "BAD SerDes ext_phy_config 0x%x\n", + bp->ext_phy_config); + break; + } + } +} + +static void bnx2x_link_initialize(struct bnx2x *bp) +{ + int port = bp->port; + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + bnx2x_ext_phy_reset(bp); + + bnx2x_set_aer_mmd(bp); + + if (bp->phy_flags & PHY_XGXS_FLAG) + bnx2x_set_master_ln(bp); + + /* reset the SerDes and wait for reset bit return low */ + bnx2x_reset_unicore(bp); + + bnx2x_set_aer_mmd(bp); + + /* setting the masterLn_def again after the reset */ + if (bp->phy_flags & PHY_XGXS_FLAG) { + bnx2x_set_master_ln(bp); + bnx2x_set_swap_lanes(bp); + } + + /* Set Parallel Detect */ + if (bp->req_autoneg & AUTONEG_SPEED) + bnx2x_set_parallel_detection(bp); + + if (bp->phy_flags & PHY_XGXS_FLAG) { + if (bp->req_line_speed && + bp->req_line_speed < SPEED_1000) { + bp->phy_flags |= PHY_SGMII_FLAG; + } else { + bp->phy_flags &= ~PHY_SGMII_FLAG; + } + } + + if (!(bp->phy_flags & PHY_SGMII_FLAG)) { + u16 bank, rx_eq; + + rx_eq = ((bp->serdes_config & + PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK) >> + PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT); + + DP(NETIF_MSG_LINK, "setting rx eq to %d\n", rx_eq); + for (bank = MDIO_REG_BANK_RX0; bank <= MDIO_REG_BANK_RX_ALL; + bank += (MDIO_REG_BANK_RX1 - MDIO_REG_BANK_RX0)) { + MDIO_SET_REG_BANK(bp, bank); + bnx2x_mdio22_write(bp, MDIO_RX0_RX_EQ_BOOST, + ((rx_eq & + MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK) | + MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL)); + } + + /* forced speed requested? */ + if (!(bp->req_autoneg & AUTONEG_SPEED)) { + DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); + + /* disable autoneg */ + bnx2x_set_autoneg(bp); + + /* program speed and duplex */ + bnx2x_program_serdes(bp); + + } else { /* AN_mode */ + DP(NETIF_MSG_LINK, "not SGMII, AN\n"); + + /* AN enabled */ + bnx2x_set_brcm_cl37_advertisment(bp); + + /* program duplex & pause advertisment (for aneg) */ + bnx2x_set_ieee_aneg_advertisment(bp); + + /* enable autoneg */ + bnx2x_set_autoneg(bp); + + /* enalbe and restart AN */ + bnx2x_restart_autoneg(bp); + } + + } else { /* SGMII mode */ + DP(NETIF_MSG_LINK, "SGMII\n"); + + bnx2x_initialize_sgmii_process(bp); + } + + /* enable the interrupt */ + bnx2x_link_int_enable(bp); + + /* init ext phy and enable link state int */ + bnx2x_ext_phy_init(bp); +} + +static void bnx2x_phy_deassert(struct bnx2x *bp) +{ + int port = bp->port; + u32 val; + + if (bp->phy_flags & PHY_XGXS_FLAG) { + DP(NETIF_MSG_LINK, "XGXS\n"); + val = XGXS_RESET_BITS; + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "SerDes\n"); + val = SERDES_RESET_BITS; + } + + val = val << (port*16); + + /* reset and unreset the SerDes/XGXS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val); + msleep(5); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val); +} + +static int bnx2x_phy_init(struct bnx2x *bp) +{ + DP(NETIF_MSG_LINK, "started\n"); + if (CHIP_REV(bp) == CHIP_REV_FPGA) { + bp->phy_flags |= PHY_EMAC_FLAG; + bp->link_up = 1; + bp->line_speed = SPEED_10000; + bp->duplex = DUPLEX_FULL; + NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + bp->port*4, 0); + bnx2x_emac_enable(bp); + bnx2x_link_report(bp); + return 0; + + } else if (CHIP_REV(bp) == CHIP_REV_EMUL) { + bp->phy_flags |= PHY_BMAC_FLAG; + bp->link_up = 1; + bp->line_speed = SPEED_10000; + bp->duplex = DUPLEX_FULL; + NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + bp->port*4, 0); + bnx2x_bmac_enable(bp, 0); + bnx2x_link_report(bp); + return 0; + + } else { + bnx2x_phy_deassert(bp); + bnx2x_link_initialize(bp); + } + + return 0; +} + +static void bnx2x_link_reset(struct bnx2x *bp) +{ + int port = bp->port; + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + bnx2x_ext_phy_reset(bp); + + /* reset the SerDes/XGXS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, + (0x1ff << (port*16))); + + /* reset EMAC / BMAC and disable NIG interfaces */ + NIG_WR(NIG_REG_BMAC0_IN_EN + port*4, 0); + NIG_WR(NIG_REG_BMAC0_OUT_EN + port*4, 0); + + NIG_WR(NIG_REG_NIG_EMAC0_EN + port*4, 0); + NIG_WR(NIG_REG_EMAC0_IN_EN + port*4, 0); + NIG_WR(NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0); + + NIG_WR(NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); +} + +#ifdef BNX2X_XGXS_LB +static void bnx2x_set_xgxs_loopback(struct bnx2x *bp, int is_10g) +{ + int port = bp->port; + + if (is_10g) { + u32 md_devad; + + DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n"); + + /* change the uni_phy_addr in the nig */ + REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18), + &md_devad); + NIG_WR(NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, 0x5); + + /* change the aer mmd */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_AER_BLOCK); + bnx2x_mdio22_write(bp, MDIO_AER_BLOCK_AER_REG, 0x2800); + + /* config combo IEEE0 control reg for loopback */ + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_CL73_IEEEB0); + bnx2x_mdio22_write(bp, MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + 0x6041); + + /* set aer mmd back */ + bnx2x_set_aer_mmd(bp); + + /* and md_devad */ + NIG_WR(NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad); + + } else { + u32 mii_control; + + DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n"); + + MDIO_SET_REG_BANK(bp, MDIO_REG_BANK_COMBO_IEEE0); + bnx2x_mdio22_read(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + bnx2x_mdio22_write(bp, MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK)); + } +} +#endif + +/* end of PHY/MAC */ + +/* slow path */ + +/* + * General service functions + */ + +/* the slow path queue is odd since completions arrive on the fastpath ring */ +static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, + u32 data_hi, u32 data_lo, int common) +{ + int port = bp->port; + + DP(NETIF_MSG_TIMER, + "spe (%x:%x) command %x hw_cid %x data (%x:%x) left %x\n", + (u32)U64_HI(bp->spq_mapping), (u32)(U64_LO(bp->spq_mapping) + + (void *)bp->spq_prod_bd - (void *)bp->spq), command, + HW_CID(bp, cid), data_hi, data_lo, bp->spq_left); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EIO; +#endif + + spin_lock(&bp->spq_lock); + + if (!bp->spq_left) { + BNX2X_ERR("BUG! SPQ ring full!\n"); + spin_unlock(&bp->spq_lock); + bnx2x_panic(); + return -EBUSY; + } + /* CID needs port number to be encoded int it */ + bp->spq_prod_bd->hdr.conn_and_cmd_data = + cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) | + HW_CID(bp, cid))); + bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE); + if (common) + bp->spq_prod_bd->hdr.type |= + cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT)); + + bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi); + bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo); + + bp->spq_left--; + + if (bp->spq_prod_bd == bp->spq_last_bd) { + bp->spq_prod_bd = bp->spq; + bp->spq_prod_idx = 0; + DP(NETIF_MSG_TIMER, "end of spq\n"); + + } else { + bp->spq_prod_bd++; + bp->spq_prod_idx++; + } + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(port), + bp->spq_prod_idx); + + spin_unlock(&bp->spq_lock); + return 0; +} + +/* acquire split MCP access lock register */ +static int bnx2x_lock_alr(struct bnx2x *bp) +{ + int rc = 0; + u32 i, j, val; + + might_sleep(); + i = 100; + for (j = 0; j < i*10; j++) { + val = (1UL << 31); + REG_WR(bp, GRCBASE_MCP + 0x9c, val); + val = REG_RD(bp, GRCBASE_MCP + 0x9c); + if (val & (1L << 31)) + break; + + msleep(5); + } + + if (!(val & (1L << 31))) { + BNX2X_ERR("Cannot acquire nvram interface\n"); + + rc = -EBUSY; + } + + return rc; +} + +/* Release split MCP access lock register */ +static void bnx2x_unlock_alr(struct bnx2x *bp) +{ + u32 val = 0; + + REG_WR(bp, GRCBASE_MCP + 0x9c, val); +} + +static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp) +{ + struct host_def_status_block *def_sb = bp->def_status_blk; + u16 rc = 0; + + barrier(); /* status block is written to by the chip */ + + if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) { + bp->def_att_idx = def_sb->atten_status_block.attn_bits_index; + rc |= 1; + } + if (bp->def_c_idx != def_sb->c_def_status_block.status_block_index) { + bp->def_c_idx = def_sb->c_def_status_block.status_block_index; + rc |= 2; + } + if (bp->def_u_idx != def_sb->u_def_status_block.status_block_index) { + bp->def_u_idx = def_sb->u_def_status_block.status_block_index; + rc |= 4; + } + if (bp->def_x_idx != def_sb->x_def_status_block.status_block_index) { + bp->def_x_idx = def_sb->x_def_status_block.status_block_index; + rc |= 8; + } + if (bp->def_t_idx != def_sb->t_def_status_block.status_block_index) { + bp->def_t_idx = def_sb->t_def_status_block.status_block_index; + rc |= 16; + } + return rc; +} + +/* + * slow path service functions + */ + +static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) +{ + int port = bp->port; + u32 igu_addr = (IGU_ADDR_ATTN_BITS_SET + IGU_PORT_BASE * port) * 8; + u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + u32 nig_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 : + NIG_REG_MASK_INTERRUPT_PORT0; + + if (~bp->aeu_mask & (asserted & 0xff)) + BNX2X_ERR("IGU ERROR\n"); + if (bp->attn_state & asserted) + BNX2X_ERR("IGU ERROR\n"); + + DP(NETIF_MSG_HW, "aeu_mask %x newly asserted %x\n", + bp->aeu_mask, asserted); + bp->aeu_mask &= ~(asserted & 0xff); + DP(NETIF_MSG_HW, "after masking: aeu_mask %x\n", bp->aeu_mask); + + REG_WR(bp, aeu_addr, bp->aeu_mask); + + bp->attn_state |= asserted; + + if (asserted & ATTN_HARD_WIRED_MASK) { + if (asserted & ATTN_NIG_FOR_FUNC) { + u32 nig_status_port; + u32 nig_int_addr = port ? + NIG_REG_STATUS_INTERRUPT_PORT1 : + NIG_REG_STATUS_INTERRUPT_PORT0; + + bp->nig_mask = REG_RD(bp, nig_mask_addr); + REG_WR(bp, nig_mask_addr, 0); + + nig_status_port = REG_RD(bp, nig_int_addr); + bnx2x_link_update(bp); + + /* handle unicore attn? */ + } + if (asserted & ATTN_SW_TIMER_4_FUNC) + DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n"); + + if (asserted & GPIO_2_FUNC) + DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n"); + + if (asserted & GPIO_3_FUNC) + DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n"); + + if (asserted & GPIO_4_FUNC) + DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n"); + + if (port == 0) { + if (asserted & ATTN_GENERAL_ATTN_1) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_2) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_3) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0); + } + } else { + if (asserted & ATTN_GENERAL_ATTN_4) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_5) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_6) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0); + } + } + + } /* if hardwired */ + + DP(NETIF_MSG_HW, "about to mask 0x%08x at IGU addr 0x%x\n", + asserted, BAR_IGU_INTMEM + igu_addr); + REG_WR(bp, BAR_IGU_INTMEM + igu_addr, asserted); + + /* now set back the mask */ + if (asserted & ATTN_NIG_FOR_FUNC) + REG_WR(bp, nig_mask_addr, bp->nig_mask); +} + +static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) +{ + int port = bp->port; + int index; + struct attn_route attn; + struct attn_route group_mask; + u32 reg_addr; + u32 val; + + /* need to take HW lock because MCP or other port might also + try to handle this event */ + bnx2x_lock_alr(bp); + + attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4); + attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4); + attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4); + attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4); + DP(NETIF_MSG_HW, "attn %llx\n", (unsigned long long)attn.sig[0]); + + for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { + if (deasserted & (1 << index)) { + group_mask = bp->attn_group[index]; + + DP(NETIF_MSG_HW, "group[%d]: %llx\n", index, + (unsigned long long)group_mask.sig[0]); + + if (attn.sig[3] & group_mask.sig[3] & + EVEREST_GEN_ATTN_IN_USE_MASK) { + + if (attn.sig[3] & BNX2X_MC_ASSERT_BITS) { + + BNX2X_ERR("MC assert!\n"); + bnx2x_panic(); + + } else if (attn.sig[3] & BNX2X_MCP_ASSERT) { + + BNX2X_ERR("MCP assert!\n"); + REG_WR(bp, + MISC_REG_AEU_GENERAL_ATTN_11, 0); + bnx2x_mc_assert(bp); + + } else { + BNX2X_ERR("UNKOWEN HW ASSERT!\n"); + } + } + + if (attn.sig[1] & group_mask.sig[1] & + BNX2X_DOORQ_ASSERT) { + + val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR); + BNX2X_ERR("DB hw attention 0x%x\n", val); + /* DORQ discard attention */ + if (val & 0x2) + BNX2X_ERR("FATAL error from DORQ\n"); + } + + if (attn.sig[2] & group_mask.sig[2] & + AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) { + + val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR); + BNX2X_ERR("CFC hw attention 0x%x\n", val); + /* CFC error attention */ + if (val & 0x2) + BNX2X_ERR("FATAL error from CFC\n"); + } + + if (attn.sig[2] & group_mask.sig[2] & + AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) { + + val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0); + BNX2X_ERR("PXP hw attention 0x%x\n", val); + /* RQ_USDMDP_FIFO_OVERFLOW */ + if (val & 0x18000) + BNX2X_ERR("FATAL error from PXP\n"); + } + + if (attn.sig[3] & group_mask.sig[3] & + EVEREST_LATCHED_ATTN_IN_USE_MASK) { + + REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, + 0x7ff); + DP(NETIF_MSG_HW, "got latched bits 0x%x\n", + attn.sig[3]); + } + + if ((attn.sig[0] & group_mask.sig[0] & + HW_INTERRUT_ASSERT_SET_0) || + (attn.sig[1] & group_mask.sig[1] & + HW_INTERRUT_ASSERT_SET_1) || + (attn.sig[2] & group_mask.sig[2] & + HW_INTERRUT_ASSERT_SET_2)) + BNX2X_ERR("FATAL HW block attention\n"); + + if ((attn.sig[0] & group_mask.sig[0] & + HW_PRTY_ASSERT_SET_0) || + (attn.sig[1] & group_mask.sig[1] & + HW_PRTY_ASSERT_SET_1) || + (attn.sig[2] & group_mask.sig[2] & + HW_PRTY_ASSERT_SET_2)) + BNX2X_ERR("FATAL HW block parity atention\n"); + } + } + + bnx2x_unlock_alr(bp); + + reg_addr = (IGU_ADDR_ATTN_BITS_CLR + IGU_PORT_BASE * port) * 8; + + val = ~deasserted; +/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n", + val, BAR_IGU_INTMEM + reg_addr); */ + REG_WR(bp, BAR_IGU_INTMEM + reg_addr, val); + + if (bp->aeu_mask & (deasserted & 0xff)) + BNX2X_ERR("IGU BUG\n"); + if (~bp->attn_state & deasserted) + BNX2X_ERR("IGU BUG\n"); + + reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + + DP(NETIF_MSG_HW, "aeu_mask %x\n", bp->aeu_mask); + bp->aeu_mask |= (deasserted & 0xff); + + DP(NETIF_MSG_HW, "new mask %x\n", bp->aeu_mask); + REG_WR(bp, reg_addr, bp->aeu_mask); + + DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state); + bp->attn_state &= ~deasserted; + DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state); +} + +static void bnx2x_attn_int(struct bnx2x *bp) +{ + /* read local copy of bits */ + u32 attn_bits = bp->def_status_blk->atten_status_block.attn_bits; + u32 attn_ack = bp->def_status_blk->atten_status_block.attn_bits_ack; + u32 attn_state = bp->attn_state; + + /* look for changed bits */ + u32 asserted = attn_bits & ~attn_ack & ~attn_state; + u32 deasserted = ~attn_bits & attn_ack & attn_state; + + DP(NETIF_MSG_HW, + "attn_bits %x attn_ack %x asserted %x deasserted %x\n", + attn_bits, attn_ack, asserted, deasserted); + + if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state)) + BNX2X_ERR("bad attention state\n"); + + /* handle bits that were raised */ + if (asserted) + bnx2x_attn_int_asserted(bp, asserted); + + if (deasserted) + bnx2x_attn_int_deasserted(bp, deasserted); +} + +static void bnx2x_sp_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, sp_task); + u16 status; + + /* Return here if interrupt is disabled */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) { + DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); + return; + } + + status = bnx2x_update_dsb_idx(bp); + if (status == 0) + BNX2X_ERR("spurious slowpath interrupt!\n"); + + DP(NETIF_MSG_INTR, "got a slowpath interrupt (updated %x)\n", status); + + if (status & 0x1) { + /* HW attentions */ + bnx2x_attn_int(bp); + } + + /* CStorm events: query_stats, cfc delete ramrods */ + if (status & 0x2) + bp->stat_pending = 0; + + bnx2x_ack_sb(bp, DEF_SB_ID, ATTENTION_ID, bp->def_att_idx, + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, USTORM_ID, le16_to_cpu(bp->def_u_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, le16_to_cpu(bp->def_c_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, XSTORM_ID, le16_to_cpu(bp->def_x_idx), + IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, DEF_SB_ID, TSTORM_ID, le16_to_cpu(bp->def_t_idx), + IGU_INT_ENABLE, 1); +} + +static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct bnx2x *bp = netdev_priv(dev); + + /* Return here if interrupt is disabled */ + if (unlikely(atomic_read(&bp->intr_sem) != 0)) { + DP(NETIF_MSG_INTR, "called but intr_sem not 0, returning\n"); + return IRQ_HANDLED; + } + + bnx2x_ack_sb(bp, 16, XSTORM_ID, 0, IGU_INT_DISABLE, 0); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + schedule_work(&bp->sp_task); + + return IRQ_HANDLED; +} + +/* end of slow path */ + +/* Statistics */ + +/**************************************************************************** +* Macros +****************************************************************************/ + +#define UPDATE_STAT(s, t) \ + do { \ + estats->t += new->s - old->s; \ + old->s = new->s; \ + } while (0) + +/* sum[hi:lo] += add[hi:lo] */ +#define ADD_64(s_hi, a_hi, s_lo, a_lo) \ + do { \ + s_lo += a_lo; \ + s_hi += a_hi + (s_lo < a_lo) ? 1 : 0; \ + } while (0) + +/* difference = minuend - subtrahend */ +#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \ + do { \ + if (m_lo < s_lo) { /* underflow */ \ + d_hi = m_hi - s_hi; \ + if (d_hi > 0) { /* we can 'loan' 1 */ \ + d_hi--; \ + d_lo = m_lo + (UINT_MAX - s_lo) + 1; \ + } else { /* m_hi <= s_hi */ \ + d_hi = 0; \ + d_lo = 0; \ + } \ + } else { /* m_lo >= s_lo */ \ + if (m_hi < s_hi) { \ + d_hi = 0; \ + d_lo = 0; \ + } else { /* m_hi >= s_hi */ \ + d_hi = m_hi - s_hi; \ + d_lo = m_lo - s_lo; \ + } \ + } \ + } while (0) + +/* minuend -= subtrahend */ +#define SUB_64(m_hi, s_hi, m_lo, s_lo) \ + do { \ + DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \ + } while (0) + +#define UPDATE_STAT64(s_hi, t_hi, s_lo, t_lo) \ + do { \ + DIFF_64(diff.hi, new->s_hi, old->s_hi, \ + diff.lo, new->s_lo, old->s_lo); \ + old->s_hi = new->s_hi; \ + old->s_lo = new->s_lo; \ + ADD_64(estats->t_hi, diff.hi, \ + estats->t_lo, diff.lo); \ + } while (0) + +/* sum[hi:lo] += add */ +#define ADD_EXTEND_64(s_hi, s_lo, a) \ + do { \ + s_lo += a; \ + s_hi += (s_lo < a) ? 1 : 0; \ + } while (0) + +#define UPDATE_EXTEND_STAT(s, t_hi, t_lo) \ + do { \ + ADD_EXTEND_64(estats->t_hi, estats->t_lo, new->s); \ + } while (0) + +#define UPDATE_EXTEND_TSTAT(s, t_hi, t_lo) \ + do { \ + diff = le32_to_cpu(tclient->s) - old_tclient->s; \ + old_tclient->s = le32_to_cpu(tclient->s); \ + ADD_EXTEND_64(estats->t_hi, estats->t_lo, diff); \ + } while (0) + +/* + * General service functions + */ + +static inline long bnx2x_hilo(u32 *hiref) +{ + u32 lo = *(hiref + 1); +#if (BITS_PER_LONG == 64) + u32 hi = *hiref; + + return HILO_U64(hi, lo); +#else + return lo; +#endif +} + +/* + * Init service functions + */ + +static void bnx2x_init_mac_stats(struct bnx2x *bp) +{ + struct dmae_command *dmae; + int port = bp->port; + int loader_idx = port * 8; + u32 opcode; + u32 mac_addr; + + bp->executer_idx = 0; + if (bp->fw_mb) { + /* MCP */ + opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + + if (bp->link_up) + opcode |= (DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE); + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, eth_stats) + + sizeof(u32)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, eth_stats) + + sizeof(u32)); + dmae->dst_addr_lo = bp->fw_mb >> 2; + dmae->dst_addr_hi = 0; + dmae->len = (offsetof(struct bnx2x_eth_stats, mac_stx_end) - + sizeof(u32)) >> 2; + if (bp->link_up) { + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } else { + dmae->comp_addr_lo = 0; + dmae->comp_addr_hi = 0; + dmae->comp_val = 0; + } + } + + if (!bp->link_up) { + /* no need to collect statistics in link down */ + return; + } + + opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + + if (bp->phy_flags & PHY_BMAC_FLAG) { + + mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM); + + /* BIGMAC_REGISTER_TX_STAT_GTPKT .. + BIGMAC_REGISTER_TX_STAT_GTBYT */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); + dmae->len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT - + BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* BIGMAC_REGISTER_RX_STAT_GR64 .. + BIGMAC_REGISTER_RX_STAT_GRIPJ */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + BIGMAC_REGISTER_RX_STAT_GR64) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct bmac_stats, rx_gr64)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct bmac_stats, rx_gr64)); + dmae->len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ - + BIGMAC_REGISTER_RX_STAT_GR64) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + } else if (bp->phy_flags & PHY_EMAC_FLAG) { + + mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0); + + /* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_RX_STAT_AC) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); + dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* EMAC_REG_EMAC_RX_STAT_AC_28 */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_RX_STAT_AC_28) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, + rx_falsecarriererrors)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, + rx_falsecarriererrors)); + dmae->len = 1; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_TX_STAT_AC) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, + tx_ifhcoutoctets)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, + tx_ifhcoutoctets)); + dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + /* NIG */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI | + DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE | + DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD : + NIG_REG_STAT0_BRB_DISCARD) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig)); + dmae->len = (sizeof(struct nig_stats) - 2*sizeof(u32)) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig) + + offsetof(struct nig_stats, done)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig) + + offsetof(struct nig_stats, done)); + dmae->comp_val = 0xffffffff; +} + +static void bnx2x_init_stats(struct bnx2x *bp) +{ + int port = bp->port; + + bp->stats_state = STATS_STATE_DISABLE; + bp->executer_idx = 0; + + bp->old_brb_discard = REG_RD(bp, + NIG_REG_STAT0_BRB_DISCARD + port*0x38); + + memset(&bp->old_bmac, 0, sizeof(struct bmac_stats)); + memset(&bp->old_tclient, 0, sizeof(struct tstorm_per_client_stats)); + memset(&bp->dev->stats, 0, sizeof(struct net_device_stats)); + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), 1); + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_STATS_FLAGS_OFFSET(port) + 4, 0); + + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port), 1); + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_STATS_FLAGS_OFFSET(port) + 4, 0); + + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port), 0); + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_STATS_FLAGS_OFFSET(port) + 4, 0); + + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port), + U64_LO(bnx2x_sp_mapping(bp, fw_stats))); + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port) + 4, + U64_HI(bnx2x_sp_mapping(bp, fw_stats))); + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port), + U64_LO(bnx2x_sp_mapping(bp, fw_stats))); + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port) + 4, + U64_HI(bnx2x_sp_mapping(bp, fw_stats))); +} + +static void bnx2x_stop_stats(struct bnx2x *bp) +{ + might_sleep(); + if (bp->stats_state != STATS_STATE_DISABLE) { + int timeout = 10; + + bp->stats_state = STATS_STATE_STOP; + DP(BNX2X_MSG_STATS, "stats_state - STOP\n"); + + while (bp->stats_state != STATS_STATE_DISABLE) { + if (!timeout) { + BNX2X_ERR("timeout wating for stats stop\n"); + break; + } + timeout--; + msleep(100); + } + } + DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n"); +} + +/* + * Statistics service functions + */ + +static void bnx2x_update_bmac_stats(struct bnx2x *bp) +{ + struct regp diff; + struct regp sum; + struct bmac_stats *new = bnx2x_sp(bp, mac_stats.bmac); + struct bmac_stats *old = &bp->old_bmac; + struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); + + sum.hi = 0; + sum.lo = 0; + + UPDATE_STAT64(tx_gtbyt.hi, total_bytes_transmitted_hi, + tx_gtbyt.lo, total_bytes_transmitted_lo); + + UPDATE_STAT64(tx_gtmca.hi, total_multicast_packets_transmitted_hi, + tx_gtmca.lo, total_multicast_packets_transmitted_lo); + ADD_64(sum.hi, diff.hi, sum.lo, diff.lo); + + UPDATE_STAT64(tx_gtgca.hi, total_broadcast_packets_transmitted_hi, + tx_gtgca.lo, total_broadcast_packets_transmitted_lo); + ADD_64(sum.hi, diff.hi, sum.lo, diff.lo); + + UPDATE_STAT64(tx_gtpkt.hi, total_unicast_packets_transmitted_hi, + tx_gtpkt.lo, total_unicast_packets_transmitted_lo); + SUB_64(estats->total_unicast_packets_transmitted_hi, sum.hi, + estats->total_unicast_packets_transmitted_lo, sum.lo); + + UPDATE_STAT(tx_gtxpf.lo, pause_xoff_frames_transmitted); + UPDATE_STAT(tx_gt64.lo, frames_transmitted_64_bytes); + UPDATE_STAT(tx_gt127.lo, frames_transmitted_65_127_bytes); + UPDATE_STAT(tx_gt255.lo, frames_transmitted_128_255_bytes); + UPDATE_STAT(tx_gt511.lo, frames_transmitted_256_511_bytes); + UPDATE_STAT(tx_gt1023.lo, frames_transmitted_512_1023_bytes); + UPDATE_STAT(tx_gt1518.lo, frames_transmitted_1024_1522_bytes); + UPDATE_STAT(tx_gt2047.lo, frames_transmitted_1523_9022_bytes); + UPDATE_STAT(tx_gt4095.lo, frames_transmitted_1523_9022_bytes); + UPDATE_STAT(tx_gt9216.lo, frames_transmitted_1523_9022_bytes); + UPDATE_STAT(tx_gt16383.lo, frames_transmitted_1523_9022_bytes); + + UPDATE_STAT(rx_grfcs.lo, crc_receive_errors); + UPDATE_STAT(rx_grund.lo, runt_packets_received); + UPDATE_STAT(rx_grovr.lo, stat_Dot3statsFramesTooLong); + UPDATE_STAT(rx_grxpf.lo, pause_xoff_frames_received); + UPDATE_STAT(rx_grxcf.lo, control_frames_received); + /* UPDATE_STAT(rx_grxpf.lo, control_frames_received); */ + UPDATE_STAT(rx_grfrg.lo, error_runt_packets_received); + UPDATE_STAT(rx_grjbr.lo, error_jabber_packets_received); + + UPDATE_STAT64(rx_grerb.hi, stat_IfHCInBadOctets_hi, + rx_grerb.lo, stat_IfHCInBadOctets_lo); + UPDATE_STAT64(tx_gtufl.hi, stat_IfHCOutBadOctets_hi, + tx_gtufl.lo, stat_IfHCOutBadOctets_lo); + UPDATE_STAT(tx_gterr.lo, stat_Dot3statsInternalMacTransmitErrors); + /* UPDATE_STAT(rx_grxpf.lo, stat_XoffStateEntered); */ + estats->stat_XoffStateEntered = estats->pause_xoff_frames_received; +} + +static void bnx2x_update_emac_stats(struct bnx2x *bp) +{ + struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac); + struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); + + UPDATE_EXTEND_STAT(tx_ifhcoutoctets, total_bytes_transmitted_hi, + total_bytes_transmitted_lo); + UPDATE_EXTEND_STAT(tx_ifhcoutucastpkts, + total_unicast_packets_transmitted_hi, + total_unicast_packets_transmitted_lo); + UPDATE_EXTEND_STAT(tx_ifhcoutmulticastpkts, + total_multicast_packets_transmitted_hi, + total_multicast_packets_transmitted_lo); + UPDATE_EXTEND_STAT(tx_ifhcoutbroadcastpkts, + total_broadcast_packets_transmitted_hi, + total_broadcast_packets_transmitted_lo); + + estats->pause_xon_frames_transmitted += new->tx_outxonsent; + estats->pause_xoff_frames_transmitted += new->tx_outxoffsent; + estats->single_collision_transmit_frames += + new->tx_dot3statssinglecollisionframes; + estats->multiple_collision_transmit_frames += + new->tx_dot3statsmultiplecollisionframes; + estats->late_collision_frames += new->tx_dot3statslatecollisions; + estats->excessive_collision_frames += + new->tx_dot3statsexcessivecollisions; + estats->frames_transmitted_64_bytes += new->tx_etherstatspkts64octets; + estats->frames_transmitted_65_127_bytes += + new->tx_etherstatspkts65octetsto127octets; + estats->frames_transmitted_128_255_bytes += + new->tx_etherstatspkts128octetsto255octets; + estats->frames_transmitted_256_511_bytes += + new->tx_etherstatspkts256octetsto511octets; + estats->frames_transmitted_512_1023_bytes += + new->tx_etherstatspkts512octetsto1023octets; + estats->frames_transmitted_1024_1522_bytes += + new->tx_etherstatspkts1024octetsto1522octet; + estats->frames_transmitted_1523_9022_bytes += + new->tx_etherstatspktsover1522octets; + + estats->crc_receive_errors += new->rx_dot3statsfcserrors; + estats->alignment_errors += new->rx_dot3statsalignmenterrors; + estats->false_carrier_detections += new->rx_falsecarriererrors; + estats->runt_packets_received += new->rx_etherstatsundersizepkts; + estats->stat_Dot3statsFramesTooLong += new->rx_dot3statsframestoolong; + estats->pause_xon_frames_received += new->rx_xonpauseframesreceived; + estats->pause_xoff_frames_received += new->rx_xoffpauseframesreceived; + estats->control_frames_received += new->rx_maccontrolframesreceived; + estats->error_runt_packets_received += new->rx_etherstatsfragments; + estats->error_jabber_packets_received += new->rx_etherstatsjabbers; + + UPDATE_EXTEND_STAT(rx_ifhcinbadoctets, stat_IfHCInBadOctets_hi, + stat_IfHCInBadOctets_lo); + UPDATE_EXTEND_STAT(tx_ifhcoutbadoctets, stat_IfHCOutBadOctets_hi, + stat_IfHCOutBadOctets_lo); + estats->stat_Dot3statsInternalMacTransmitErrors += + new->tx_dot3statsinternalmactransmiterrors; + estats->stat_Dot3StatsCarrierSenseErrors += + new->rx_dot3statscarriersenseerrors; + estats->stat_Dot3StatsDeferredTransmissions += + new->tx_dot3statsdeferredtransmissions; + estats->stat_FlowControlDone += new->tx_flowcontroldone; + estats->stat_XoffStateEntered += new->rx_xoffstateentered; +} + +static int bnx2x_update_storm_stats(struct bnx2x *bp) +{ + struct eth_stats_query *stats = bnx2x_sp(bp, fw_stats); + struct tstorm_common_stats *tstats = &stats->tstorm_common; + struct tstorm_per_client_stats *tclient = + &tstats->client_statistics[0]; + struct tstorm_per_client_stats *old_tclient = &bp->old_tclient; + struct xstorm_common_stats *xstats = &stats->xstorm_common; + struct nig_stats *nstats = bnx2x_sp(bp, nig); + struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); + u32 diff; + + /* are DMAE stats valid? */ + if (nstats->done != 0xffffffff) { + DP(BNX2X_MSG_STATS, "stats not updated by dmae\n"); + return -1; + } + + /* are storm stats valid? */ + if (tstats->done.hi != 0xffffffff) { + DP(BNX2X_MSG_STATS, "stats not updated by tstorm\n"); + return -2; + } + if (xstats->done.hi != 0xffffffff) { + DP(BNX2X_MSG_STATS, "stats not updated by xstorm\n"); + return -3; + } + + estats->total_bytes_received_hi = + estats->valid_bytes_received_hi = + le32_to_cpu(tclient->total_rcv_bytes.hi); + estats->total_bytes_received_lo = + estats->valid_bytes_received_lo = + le32_to_cpu(tclient->total_rcv_bytes.lo); + ADD_64(estats->total_bytes_received_hi, + le32_to_cpu(tclient->rcv_error_bytes.hi), + estats->total_bytes_received_lo, + le32_to_cpu(tclient->rcv_error_bytes.lo)); + + UPDATE_EXTEND_TSTAT(rcv_unicast_pkts, + total_unicast_packets_received_hi, + total_unicast_packets_received_lo); + UPDATE_EXTEND_TSTAT(rcv_multicast_pkts, + total_multicast_packets_received_hi, + total_multicast_packets_received_lo); + UPDATE_EXTEND_TSTAT(rcv_broadcast_pkts, + total_broadcast_packets_received_hi, + total_broadcast_packets_received_lo); + + estats->frames_received_64_bytes = MAC_STX_NA; + estats->frames_received_65_127_bytes = MAC_STX_NA; + estats->frames_received_128_255_bytes = MAC_STX_NA; + estats->frames_received_256_511_bytes = MAC_STX_NA; + estats->frames_received_512_1023_bytes = MAC_STX_NA; + estats->frames_received_1024_1522_bytes = MAC_STX_NA; + estats->frames_received_1523_9022_bytes = MAC_STX_NA; + + estats->x_total_sent_bytes_hi = + le32_to_cpu(xstats->total_sent_bytes.hi); + estats->x_total_sent_bytes_lo = + le32_to_cpu(xstats->total_sent_bytes.lo); + estats->x_total_sent_pkts = le32_to_cpu(xstats->total_sent_pkts); + + estats->t_rcv_unicast_bytes_hi = + le32_to_cpu(tclient->rcv_unicast_bytes.hi); + estats->t_rcv_unicast_bytes_lo = + le32_to_cpu(tclient->rcv_unicast_bytes.lo); + estats->t_rcv_broadcast_bytes_hi = + le32_to_cpu(tclient->rcv_broadcast_bytes.hi); + estats->t_rcv_broadcast_bytes_lo = + le32_to_cpu(tclient->rcv_broadcast_bytes.lo); + estats->t_rcv_multicast_bytes_hi = + le32_to_cpu(tclient->rcv_multicast_bytes.hi); + estats->t_rcv_multicast_bytes_lo = + le32_to_cpu(tclient->rcv_multicast_bytes.lo); + estats->t_total_rcv_pkt = le32_to_cpu(tclient->total_rcv_pkts); + + estats->checksum_discard = le32_to_cpu(tclient->checksum_discard); + estats->packets_too_big_discard = + le32_to_cpu(tclient->packets_too_big_discard); + estats->jabber_packets_received = estats->packets_too_big_discard + + estats->stat_Dot3statsFramesTooLong; + estats->no_buff_discard = le32_to_cpu(tclient->no_buff_discard); + estats->ttl0_discard = le32_to_cpu(tclient->ttl0_discard); + estats->mac_discard = le32_to_cpu(tclient->mac_discard); + estats->mac_filter_discard = le32_to_cpu(tstats->mac_filter_discard); + estats->xxoverflow_discard = le32_to_cpu(tstats->xxoverflow_discard); + estats->brb_truncate_discard = + le32_to_cpu(tstats->brb_truncate_discard); + + estats->brb_discard += nstats->brb_discard - bp->old_brb_discard; + bp->old_brb_discard = nstats->brb_discard; + + estats->brb_packet = nstats->brb_packet; + estats->brb_truncate = nstats->brb_truncate; + estats->flow_ctrl_discard = nstats->flow_ctrl_discard; + estats->flow_ctrl_octets = nstats->flow_ctrl_octets; + estats->flow_ctrl_packet = nstats->flow_ctrl_packet; + estats->mng_discard = nstats->mng_discard; + estats->mng_octet_inp = nstats->mng_octet_inp; + estats->mng_octet_out = nstats->mng_octet_out; + estats->mng_packet_inp = nstats->mng_packet_inp; + estats->mng_packet_out = nstats->mng_packet_out; + estats->pbf_octets = nstats->pbf_octets; + estats->pbf_packet = nstats->pbf_packet; + estats->safc_inp = nstats->safc_inp; + + xstats->done.hi = 0; + tstats->done.hi = 0; + nstats->done = 0; + + return 0; +} + +static void bnx2x_update_net_stats(struct bnx2x *bp) +{ + struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); + struct net_device_stats *nstats = &bp->dev->stats; + + nstats->rx_packets = + bnx2x_hilo(&estats->total_unicast_packets_received_hi) + + bnx2x_hilo(&estats->total_multicast_packets_received_hi) + + bnx2x_hilo(&estats->total_broadcast_packets_received_hi); + + nstats->tx_packets = + bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) + + bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) + + bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi); + + nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi); + + nstats->tx_bytes = + bnx2x_hilo(&estats->total_bytes_transmitted_hi); + + nstats->rx_dropped = estats->checksum_discard + + estats->mac_discard; + nstats->tx_dropped = 0; + + nstats->multicast = + bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi); + + nstats->collisions = + estats->single_collision_transmit_frames + + estats->multiple_collision_transmit_frames + + estats->late_collision_frames + + estats->excessive_collision_frames; + + nstats->rx_length_errors = estats->runt_packets_received + + estats->jabber_packets_received; + nstats->rx_over_errors = estats->no_buff_discard; + nstats->rx_crc_errors = estats->crc_receive_errors; + nstats->rx_frame_errors = estats->alignment_errors; + nstats->rx_fifo_errors = estats->brb_discard + + estats->brb_truncate_discard; + nstats->rx_missed_errors = estats->xxoverflow_discard; + + nstats->rx_errors = nstats->rx_length_errors + + nstats->rx_over_errors + + nstats->rx_crc_errors + + nstats->rx_frame_errors + + nstats->rx_fifo_errors; + + nstats->tx_aborted_errors = estats->late_collision_frames + + estats->excessive_collision_frames; + nstats->tx_carrier_errors = estats->false_carrier_detections; + nstats->tx_fifo_errors = 0; + nstats->tx_heartbeat_errors = 0; + nstats->tx_window_errors = 0; + + nstats->tx_errors = nstats->tx_aborted_errors + + nstats->tx_carrier_errors; + + estats->mac_stx_start = ++estats->mac_stx_end; +} + +static void bnx2x_update_stats(struct bnx2x *bp) +{ + int i; + + if (!bnx2x_update_storm_stats(bp)) { + + if (bp->phy_flags & PHY_BMAC_FLAG) { + bnx2x_update_bmac_stats(bp); + + } else if (bp->phy_flags & PHY_EMAC_FLAG) { + bnx2x_update_emac_stats(bp); + + } else { /* unreached */ + BNX2X_ERR("no MAC active\n"); + return; + } + + bnx2x_update_net_stats(bp); + } + + if (bp->msglevel & NETIF_MSG_TIMER) { + struct bnx2x_eth_stats *estats = bnx2x_sp(bp, eth_stats); + struct net_device_stats *nstats = &bp->dev->stats; + + printk(KERN_DEBUG "%s:\n", bp->dev->name); + printk(KERN_DEBUG " tx avail (%4x) tx hc idx (%x)" + " tx pkt (%lx)\n", + bnx2x_tx_avail(bp->fp), + *bp->fp->tx_cons_sb, nstats->tx_packets); + printk(KERN_DEBUG " rx usage (%4x) rx hc idx (%x)" + " rx pkt (%lx)\n", + (u16)(*bp->fp->rx_cons_sb - bp->fp->rx_comp_cons), + *bp->fp->rx_cons_sb, nstats->rx_packets); + printk(KERN_DEBUG " %s (Xoff events %u) brb drops %u\n", + netif_queue_stopped(bp->dev)? "Xoff" : "Xon", + estats->driver_xoff, estats->brb_discard); + printk(KERN_DEBUG "tstats: checksum_discard %u " + "packets_too_big_discard %u no_buff_discard %u " + "mac_discard %u mac_filter_discard %u " + "xxovrflow_discard %u brb_truncate_discard %u " + "ttl0_discard %u\n", + estats->checksum_discard, + estats->packets_too_big_discard, + estats->no_buff_discard, estats->mac_discard, + estats->mac_filter_discard, estats->xxoverflow_discard, + estats->brb_truncate_discard, estats->ttl0_discard); + + for_each_queue(bp, i) { + printk(KERN_DEBUG "[%d]: %lu\t%lu\t%lu\n", i, + bnx2x_fp(bp, i, tx_pkt), + bnx2x_fp(bp, i, rx_pkt), + bnx2x_fp(bp, i, rx_calls)); + } + } + + if (bp->state != BNX2X_STATE_OPEN) { + DP(BNX2X_MSG_STATS, "state is %x, returning\n", bp->state); + return; + } + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return; +#endif + + /* loader */ + if (bp->executer_idx) { + struct dmae_command *dmae = &bp->dmae; + int port = bp->port; + int loader_idx = port * 8; + + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC | + DMAE_CMD_C_DST_GRC | DMAE_CMD_C_ENABLE | + DMAE_CMD_DST_RESET | +#ifdef __BIG_ENDIAN + DMAE_CMD_ENDIANITY_B_DW_SWAP | +#else + DMAE_CMD_ENDIANITY_DW_SWAP | +#endif + (port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0)); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0])); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0])); + dmae->dst_addr_lo = (DMAE_REG_CMD_MEM + + sizeof(struct dmae_command) * + (loader_idx + 1)) >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct dmae_command) >> 2; + dmae->len--; /* !!! for A0/1 only */ + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + bnx2x_post_dmae(bp, dmae, loader_idx); + } + + if (bp->stats_state != STATS_STATE_ENABLE) { + bp->stats_state = STATS_STATE_DISABLE; + return; + } + + if (bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_STAT_QUERY, 0, 0, 0, 0) == 0) { + /* stats ramrod has it's own slot on the spe */ + bp->spq_left++; + bp->stat_pending = 1; + } +} + +static void bnx2x_timer(unsigned long data) +{ + struct bnx2x *bp = (struct bnx2x *) data; + + if (!netif_running(bp->dev)) + return; + + if (atomic_read(&bp->intr_sem) != 0) + goto bnx2x_restart_timer; + + if (poll) { + struct bnx2x_fastpath *fp = &bp->fp[0]; + int rc; + + bnx2x_tx_int(fp, 1000); + rc = bnx2x_rx_int(fp, 1000); + } + + if (!nomcp && (bp->bc_ver >= 0x040003)) { + int port = bp->port; + u32 drv_pulse; + u32 mcp_pulse; + + ++bp->fw_drv_pulse_wr_seq; + bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK; + /* TBD - add SYSTEM_TIME */ + drv_pulse = bp->fw_drv_pulse_wr_seq; + SHMEM_WR(bp, drv_fw_mb[port].drv_pulse_mb, drv_pulse); + + mcp_pulse = (SHMEM_RD(bp, drv_fw_mb[port].mcp_pulse_mb) & + MCP_PULSE_SEQ_MASK); + /* The delta between driver pulse and mcp response + * should be 1 (before mcp response) or 0 (after mcp response) + */ + if ((drv_pulse != mcp_pulse) && + (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) { + /* someone lost a heartbeat... */ + BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n", + drv_pulse, mcp_pulse); + } + } + + if (bp->stats_state == STATS_STATE_DISABLE) + goto bnx2x_restart_timer; + + bnx2x_update_stats(bp); + +bnx2x_restart_timer: + mod_timer(&bp->timer, jiffies + bp->current_interval); +} + +/* end of Statistics */ + +/* nic init */ + +/* + * nic init service functions + */ + +static void bnx2x_init_sb(struct bnx2x *bp, struct host_status_block *sb, + dma_addr_t mapping, int id) +{ + int port = bp->port; + u64 section; + int index; + + /* USTORM */ + section = ((u64)mapping) + offsetof(struct host_status_block, + u_status_block); + sb->u_status_block.status_block_id = id; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section)); + REG_WR(bp, BAR_USTRORM_INTMEM + + ((USTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4), + U64_HI(section)); + + for (index = 0; index < HC_USTORM_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1); + + /* CSTORM */ + section = ((u64)mapping) + offsetof(struct host_status_block, + c_status_block); + sb->c_status_block.status_block_id = id; + + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_SB_HOST_SB_ADDR_OFFSET(port, id)) + 4), + U64_HI(section)); + + for (index = 0; index < HC_CSTORM_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_OFFSET(port, id, index), 0x1); + + bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); +} + +static void bnx2x_init_def_sb(struct bnx2x *bp, + struct host_def_status_block *def_sb, + dma_addr_t mapping, int id) +{ + int port = bp->port; + int index, val, reg_offset; + u64 section; + + /* ATTN */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + atten_status_block); + def_sb->atten_status_block.status_block_id = id; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + + for (index = 0; index < 3; index++) { + bp->attn_group[index].sig[0] = REG_RD(bp, + reg_offset + 0x10*index); + bp->attn_group[index].sig[1] = REG_RD(bp, + reg_offset + 0x4 + 0x10*index); + bp->attn_group[index].sig[2] = REG_RD(bp, + reg_offset + 0x8 + 0x10*index); + bp->attn_group[index].sig[3] = REG_RD(bp, + reg_offset + 0xc + 0x10*index); + } + + bp->aeu_mask = REG_RD(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0)); + + reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L : + HC_REG_ATTN_MSG0_ADDR_L); + + REG_WR(bp, reg_offset, U64_LO(section)); + REG_WR(bp, reg_offset + 4, U64_HI(section)); + + reg_offset = (port ? HC_REG_ATTN_NUM_P1 : HC_REG_ATTN_NUM_P0); + + val = REG_RD(bp, reg_offset); + val |= id; + REG_WR(bp, reg_offset, val); + + /* USTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + u_def_status_block); + def_sb->u_def_status_block.status_block_id = id; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + REG_WR(bp, BAR_USTRORM_INTMEM + + ((USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + U64_HI(section)); + REG_WR(bp, BAR_USTRORM_INTMEM + USTORM_HC_BTR_OFFSET(port), + BNX2X_BTR); + + for (index = 0; index < HC_USTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + + /* CSTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + c_def_status_block); + def_sb->c_def_status_block.status_block_id = id; + + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + + ((CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + U64_HI(section)); + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_HC_BTR_OFFSET(port), + BNX2X_BTR); + + for (index = 0; index < HC_CSTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + + /* TSTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + t_def_status_block); + def_sb->t_def_status_block.status_block_id = id; + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + REG_WR(bp, BAR_TSTRORM_INTMEM + + ((TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + U64_HI(section)); + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_HC_BTR_OFFSET(port), + BNX2X_BTR); + + for (index = 0; index < HC_TSTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_TSTRORM_INTMEM + + TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + + /* XSTORM */ + section = ((u64)mapping) + offsetof(struct host_def_status_block, + x_def_status_block); + def_sb->x_def_status_block.status_block_id = id; + + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port), U64_LO(section)); + REG_WR(bp, BAR_XSTRORM_INTMEM + + ((XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)) + 4), + U64_HI(section)); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_HC_BTR_OFFSET(port), + BNX2X_BTR); + + for (index = 0; index < HC_XSTORM_DEF_SB_NUM_INDICES; index++) + REG_WR16(bp, BAR_XSTRORM_INTMEM + + XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index), 0x1); + + bnx2x_ack_sb(bp, id, CSTORM_ID, 0, IGU_INT_ENABLE, 0); +} + +static void bnx2x_update_coalesce(struct bnx2x *bp) +{ + int port = bp->port; + int i; + + for_each_queue(bp, i) { + + /* HC_INDEX_U_ETH_RX_CQ_CONS */ + REG_WR8(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HC_TIMEOUT_OFFSET(port, i, + HC_INDEX_U_ETH_RX_CQ_CONS), + bp->rx_ticks_int/12); + REG_WR16(bp, BAR_USTRORM_INTMEM + + USTORM_SB_HC_DISABLE_OFFSET(port, i, + HC_INDEX_U_ETH_RX_CQ_CONS), + bp->rx_ticks_int ? 0 : 1); + + /* HC_INDEX_C_ETH_TX_CQ_CONS */ + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_TIMEOUT_OFFSET(port, i, + HC_INDEX_C_ETH_TX_CQ_CONS), + bp->tx_ticks_int/12); + REG_WR16(bp, BAR_CSTRORM_INTMEM + + CSTORM_SB_HC_DISABLE_OFFSET(port, i, + HC_INDEX_C_ETH_TX_CQ_CONS), + bp->tx_ticks_int ? 0 : 1); + } +} + +static void bnx2x_init_rx_rings(struct bnx2x *bp) +{ + u16 ring_prod; + int i, j; + int port = bp->port; + + bp->rx_buf_use_size = bp->dev->mtu; + + bp->rx_buf_use_size += bp->rx_offset + ETH_OVREHEAD; + bp->rx_buf_size = bp->rx_buf_use_size + 64; + + for_each_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + fp->rx_bd_cons = 0; + fp->rx_cons_sb = BNX2X_RX_SB_INDEX; + + for (i = 1; i <= NUM_RX_RINGS; i++) { + struct eth_rx_bd *rx_bd; + + rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2]; + rx_bd->addr_hi = + cpu_to_le32(U64_HI(fp->rx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + rx_bd->addr_lo = + cpu_to_le32(U64_LO(fp->rx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + + } + + for (i = 1; i <= NUM_RCQ_RINGS; i++) { + struct eth_rx_cqe_next_page *nextpg; + + nextpg = (struct eth_rx_cqe_next_page *) + &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1]; + nextpg->addr_hi = + cpu_to_le32(U64_HI(fp->rx_comp_mapping + + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + nextpg->addr_lo = + cpu_to_le32(U64_LO(fp->rx_comp_mapping + + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + } + + /* rx completion queue */ + fp->rx_comp_cons = ring_prod = 0; + + for (i = 0; i < bp->rx_ring_size; i++) { + if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { + BNX2X_ERR("was only able to allocate " + "%d rx skbs\n", i); + break; + } + ring_prod = NEXT_RX_IDX(ring_prod); + BUG_TRAP(ring_prod > i); + } + + fp->rx_bd_prod = fp->rx_comp_prod = ring_prod; + fp->rx_pkt = fp->rx_calls = 0; + + /* Warning! this will genrate an interrupt (to the TSTORM) */ + /* must only be done when chip is initialized */ + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_RCQ_PROD_OFFSET(port, j), ring_prod); + if (j != 0) + continue; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port), + U64_LO(fp->rx_comp_mapping)); + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port) + 4, + U64_HI(fp->rx_comp_mapping)); + } +} + +static void bnx2x_init_tx_ring(struct bnx2x *bp) +{ + int i, j; + + for_each_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + for (i = 1; i <= NUM_TX_RINGS; i++) { + struct eth_tx_bd *tx_bd = + &fp->tx_desc_ring[TX_DESC_CNT * i - 1]; + + tx_bd->addr_hi = + cpu_to_le32(U64_HI(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + tx_bd->addr_lo = + cpu_to_le32(U64_LO(fp->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + } + + fp->tx_pkt_prod = 0; + fp->tx_pkt_cons = 0; + fp->tx_bd_prod = 0; + fp->tx_bd_cons = 0; + fp->tx_cons_sb = BNX2X_TX_SB_INDEX; + fp->tx_pkt = 0; + } +} + +static void bnx2x_init_sp_ring(struct bnx2x *bp) +{ + int port = bp->port; + + spin_lock_init(&bp->spq_lock); + + bp->spq_left = MAX_SPQ_PENDING; + bp->spq_prod_idx = 0; + bp->dsb_sp_prod_idx = 0; + bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX; + bp->spq_prod_bd = bp->spq; + bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT; + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port), + U64_LO(bp->spq_mapping)); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PAGE_BASE_OFFSET(port) + 4, + U64_HI(bp->spq_mapping)); + + REG_WR(bp, XSEM_REG_FAST_MEMORY + XSTORM_SPQ_PROD_OFFSET(port), + bp->spq_prod_idx); +} + +static void bnx2x_init_context(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct eth_context *context = bnx2x_sp(bp, context[i].eth); + struct bnx2x_fastpath *fp = &bp->fp[i]; + + context->xstorm_st_context.tx_bd_page_base_hi = + U64_HI(fp->tx_desc_mapping); + context->xstorm_st_context.tx_bd_page_base_lo = + U64_LO(fp->tx_desc_mapping); + context->xstorm_st_context.db_data_addr_hi = + U64_HI(fp->tx_prods_mapping); + context->xstorm_st_context.db_data_addr_lo = + U64_LO(fp->tx_prods_mapping); + + context->ustorm_st_context.rx_bd_page_base_hi = + U64_HI(fp->rx_desc_mapping); + context->ustorm_st_context.rx_bd_page_base_lo = + U64_LO(fp->rx_desc_mapping); + context->ustorm_st_context.status_block_id = i; + context->ustorm_st_context.sb_index_number = + HC_INDEX_U_ETH_RX_CQ_CONS; + context->ustorm_st_context.rcq_base_address_hi = + U64_HI(fp->rx_comp_mapping); + context->ustorm_st_context.rcq_base_address_lo = + U64_LO(fp->rx_comp_mapping); + context->ustorm_st_context.flags = + USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT; + context->ustorm_st_context.mc_alignment_size = 64; + context->ustorm_st_context.num_rss = bp->num_queues; + + context->cstorm_st_context.sb_index_number = + HC_INDEX_C_ETH_TX_CQ_CONS; + context->cstorm_st_context.status_block_id = i; + + context->xstorm_ag_context.cdu_reserved = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), + CDU_REGION_NUMBER_XCM_AG, + ETH_CONNECTION_TYPE); + context->ustorm_ag_context.cdu_usage = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, i), + CDU_REGION_NUMBER_UCM_AG, + ETH_CONNECTION_TYPE); + } +} + +static void bnx2x_init_ind_table(struct bnx2x *bp) +{ + int port = bp->port; + int i; + + if (!is_multi(bp)) + return; + + for (i = 0; i < TSTORM_INDIRECTION_TABLE_SIZE; i++) + REG_WR8(bp, TSTORM_INDIRECTION_TABLE_OFFSET(port) + i, + i % bp->num_queues); + + REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); +} + +static void bnx2x_set_storm_rx_mode(struct bnx2x *bp) +{ + int mode = bp->rx_mode; + int port = bp->port; + struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0}; + int i; + + DP(NETIF_MSG_RX_STATUS, "rx mode is %d\n", mode); + + switch (mode) { + case BNX2X_RX_MODE_NONE: /* no Rx */ + tstorm_mac_filter.ucast_drop_all = 1; + tstorm_mac_filter.mcast_drop_all = 1; + tstorm_mac_filter.bcast_drop_all = 1; + break; + case BNX2X_RX_MODE_NORMAL: + tstorm_mac_filter.bcast_accept_all = 1; + break; + case BNX2X_RX_MODE_ALLMULTI: + tstorm_mac_filter.mcast_accept_all = 1; + tstorm_mac_filter.bcast_accept_all = 1; + break; + case BNX2X_RX_MODE_PROMISC: + tstorm_mac_filter.ucast_accept_all = 1; + tstorm_mac_filter.mcast_accept_all = 1; + tstorm_mac_filter.bcast_accept_all = 1; + break; + default: + BNX2X_ERR("bad rx mode (%d)\n", mode); + } + + for (i = 0; i < sizeof(struct tstorm_eth_mac_filter_config)/4; i++) { + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_MAC_FILTER_CONFIG_OFFSET(port) + i * 4, + ((u32 *)&tstorm_mac_filter)[i]); + +/* DP(NETIF_MSG_IFUP, "tstorm_mac_filter[%d]: 0x%08x\n", i, + ((u32 *)&tstorm_mac_filter)[i]); */ + } +} + +static void bnx2x_set_client_config(struct bnx2x *bp, int client_id) +{ +#ifdef BCM_VLAN + int mode = bp->rx_mode; +#endif + int port = bp->port; + struct tstorm_eth_client_config tstorm_client = {0}; + + tstorm_client.mtu = bp->dev->mtu; + tstorm_client.statistics_counter_id = 0; + tstorm_client.config_flags = + TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE; +#ifdef BCM_VLAN + if (mode && bp->vlgrp) { + tstorm_client.config_flags |= + TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE; + DP(NETIF_MSG_IFUP, "vlan removal enabled\n"); + } +#endif + tstorm_client.drop_flags = (TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR | + TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR | + TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR | + TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR); + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_CLIENT_CONFIG_OFFSET(port, client_id), + ((u32 *)&tstorm_client)[0]); + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_CLIENT_CONFIG_OFFSET(port, client_id) + 4, + ((u32 *)&tstorm_client)[1]); + +/* DP(NETIF_MSG_IFUP, "tstorm_client: 0x%08x 0x%08x\n", + ((u32 *)&tstorm_client)[0], ((u32 *)&tstorm_client)[1]); */ +} + +static void bnx2x_init_internal(struct bnx2x *bp) +{ + int port = bp->port; + struct tstorm_eth_function_common_config tstorm_config = {0}; + struct stats_indication_flags stats_flags = {0}; + int i; + + if (is_multi(bp)) { + tstorm_config.config_flags = MULTI_FLAGS; + tstorm_config.rss_result_mask = MULTI_MASK; + } + + REG_WR(bp, BAR_TSTRORM_INTMEM + + TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(port), + (*(u32 *)&tstorm_config)); + +/* DP(NETIF_MSG_IFUP, "tstorm_config: 0x%08x\n", + (*(u32 *)&tstorm_config)); */ + + bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx untill link is up */ + bnx2x_set_storm_rx_mode(bp); + + for_each_queue(bp, i) + bnx2x_set_client_config(bp, i); + + + stats_flags.collect_eth = cpu_to_le32(1); + + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port), + ((u32 *)&stats_flags)[0]); + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_STATS_FLAGS_OFFSET(port) + 4, + ((u32 *)&stats_flags)[1]); + + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port), + ((u32 *)&stats_flags)[0]); + REG_WR(bp, BAR_TSTRORM_INTMEM + TSTORM_STATS_FLAGS_OFFSET(port) + 4, + ((u32 *)&stats_flags)[1]); + + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port), + ((u32 *)&stats_flags)[0]); + REG_WR(bp, BAR_CSTRORM_INTMEM + CSTORM_STATS_FLAGS_OFFSET(port) + 4, + ((u32 *)&stats_flags)[1]); + +/* DP(NETIF_MSG_IFUP, "stats_flags: 0x%08x 0x%08x\n", + ((u32 *)&stats_flags)[0], ((u32 *)&stats_flags)[1]); */ +} + +static void bnx2x_nic_init(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + fp->state = BNX2X_FP_STATE_CLOSED; + DP(NETIF_MSG_IFUP, "bnx2x_init_sb(%p,%p,%d);\n", + bp, fp->status_blk, i); + fp->index = i; + bnx2x_init_sb(bp, fp->status_blk, fp->status_blk_mapping, i); + } + + bnx2x_init_def_sb(bp, bp->def_status_blk, + bp->def_status_blk_mapping, 0x10); + bnx2x_update_coalesce(bp); + bnx2x_init_rx_rings(bp); + bnx2x_init_tx_ring(bp); + bnx2x_init_sp_ring(bp); + bnx2x_init_context(bp); + bnx2x_init_internal(bp); + bnx2x_init_stats(bp); + bnx2x_init_ind_table(bp); + bnx2x_enable_int(bp); + +} + +/* end of nic init */ + +/* + * gzip service functions + */ + +static int bnx2x_gunzip_init(struct bnx2x *bp) +{ + bp->gunzip_buf = pci_alloc_consistent(bp->pdev, FW_BUF_SIZE, + &bp->gunzip_mapping); + if (bp->gunzip_buf == NULL) + goto gunzip_nomem1; + + bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL); + if (bp->strm == NULL) + goto gunzip_nomem2; + + bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), + GFP_KERNEL); + if (bp->strm->workspace == NULL) + goto gunzip_nomem3; + + return 0; + +gunzip_nomem3: + kfree(bp->strm); + bp->strm = NULL; + +gunzip_nomem2: + pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf, + bp->gunzip_mapping); + bp->gunzip_buf = NULL; + +gunzip_nomem1: + printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for" + " uncompression\n", bp->dev->name); + return -ENOMEM; +} + +static void bnx2x_gunzip_end(struct bnx2x *bp) +{ + kfree(bp->strm->workspace); + + kfree(bp->strm); + bp->strm = NULL; + + if (bp->gunzip_buf) { + pci_free_consistent(bp->pdev, FW_BUF_SIZE, bp->gunzip_buf, + bp->gunzip_mapping); + bp->gunzip_buf = NULL; + } +} + +static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len) +{ + int n, rc; + + /* check gzip header */ + if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) + return -EINVAL; + + n = 10; + +#define FNAME 0x8 + + if (zbuf[3] & FNAME) + while ((zbuf[n++] != 0) && (n < len)); + + bp->strm->next_in = zbuf + n; + bp->strm->avail_in = len - n; + bp->strm->next_out = bp->gunzip_buf; + bp->strm->avail_out = FW_BUF_SIZE; + + rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); + if (rc != Z_OK) + return rc; + + rc = zlib_inflate(bp->strm, Z_FINISH); + if ((rc != Z_OK) && (rc != Z_STREAM_END)) + printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n", + bp->dev->name, bp->strm->msg); + + bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out); + if (bp->gunzip_outlen & 0x3) + printk(KERN_ERR PFX "%s: Firmware decompression error:" + " gunzip_outlen (%d) not aligned\n", + bp->dev->name, bp->gunzip_outlen); + bp->gunzip_outlen >>= 2; + + zlib_inflateEnd(bp->strm); + + if (rc == Z_STREAM_END) + return 0; + + return rc; +} + +/* nic load/unload */ + +/* + * general service functions + */ + +/* send a NIG loopback debug packet */ +static void bnx2x_lb_pckt(struct bnx2x *bp) +{ +#ifdef USE_DMAE + u32 wb_write[3]; +#endif + + /* Ethernet source and destination addresses */ +#ifdef USE_DMAE + wb_write[0] = 0x55555555; + wb_write[1] = 0x55555555; + wb_write[2] = 0x20; /* SOP */ + REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); +#else + REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x55555555); + REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555); + /* SOP */ + REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x20); +#endif + + /* NON-IP protocol */ +#ifdef USE_DMAE + wb_write[0] = 0x09000000; + wb_write[1] = 0x55555555; + wb_write[2] = 0x10; /* EOP, eop_bvalid = 0 */ + REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); +#else + REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB, 0x09000000); + REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 4, 0x55555555); + /* EOP, eop_bvalid = 0 */ + REG_WR_IND(bp, NIG_REG_DEBUG_PACKET_LB + 8, 0x10); +#endif +} + +/* some of the internal memories + * are not directly readable from the driver + * to test them we send debug packets + */ +static int bnx2x_int_mem_test(struct bnx2x *bp) +{ + int factor; + int count, i; + u32 val = 0; + + switch (CHIP_REV(bp)) { + case CHIP_REV_EMUL: + factor = 200; + break; + case CHIP_REV_FPGA: + factor = 120; + break; + default: + factor = 1; + break; + } + + DP(NETIF_MSG_HW, "start part1\n"); + + /* Disable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); + REG_WR(bp, CFC_REG_DEBUG0, 0x1); + NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0); + + /* Write 0 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); + + /* send Ethernet packet */ + bnx2x_lb_pckt(bp); + + /* TODO do i reset NIG statistic? */ + /* Wait until NIG register shows 1 packet of size 0x10 */ + count = 1000 * factor; + while (count) { +#ifdef BNX2X_DMAE_RD + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); +#else + val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); + REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); +#endif + if (val == 0x10) + break; + + msleep(10); + count--; + } + if (val != 0x10) { + BNX2X_ERR("NIG timeout val = 0x%x\n", val); + return -1; + } + + /* Wait until PRS register shows 1 packet */ + count = 1000 * factor; + while (count) { + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + + if (val == 1) + break; + + msleep(10); + count--; + } + if (val != 0x1) { + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + return -2; + } + + /* Reset and init BRB, PRS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x3); + msleep(50); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x3); + msleep(50); + bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); + bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + + DP(NETIF_MSG_HW, "part2\n"); + + /* Disable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); + REG_WR(bp, CFC_REG_DEBUG0, 0x1); + NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x0); + + /* Write 0 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); + + /* send 10 Ethernet packets */ + for (i = 0; i < 10; i++) + bnx2x_lb_pckt(bp); + + /* Wait until NIG register shows 10 + 1 + packets of size 11*0x10 = 0xb0 */ + count = 1000 * factor; + while (count) { +#ifdef BNX2X_DMAE_RD + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); +#else + val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); + REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); +#endif + if (val == 0xb0) + break; + + msleep(10); + count--; + } + if (val != 0xb0) { + BNX2X_ERR("NIG timeout val = 0x%x\n", val); + return -3; + } + + /* Wait until PRS register shows 2 packets */ + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val != 2) + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + + /* Write 1 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1); + + /* Wait until PRS register shows 3 packets */ + msleep(10 * factor); + /* Wait until NIG register shows 1 packet of size 0x10 */ + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val != 3) + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + + /* clear NIG EOP FIFO */ + for (i = 0; i < 11; i++) + REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO); + val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY); + if (val != 1) { + BNX2X_ERR("clear of NIG failed\n"); + return -4; + } + + /* Reset and init BRB, PRS, NIG */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); + msleep(50); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); + msleep(50); + bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); + bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); +#ifndef BCM_ISCSI + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); +#endif + + /* Enable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x1); + REG_WR(bp, CFC_REG_DEBUG0, 0x0); + NIG_WR(NIG_REG_PRS_REQ_IN_EN, 0x1); + + DP(NETIF_MSG_HW, "done\n"); + + return 0; /* OK */ +} + +static void enable_blocks_attention(struct bnx2x *bp) +{ + REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); + REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0); + REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); + REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); + REG_WR(bp, QM_REG_QM_INT_MASK, 0); + REG_WR(bp, TM_REG_TM_INT_MASK, 0); + REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0); + REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0); + REG_WR(bp, XCM_REG_XCM_INT_MASK, 0); +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */ + REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0); + REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0); + REG_WR(bp, UCM_REG_UCM_INT_MASK, 0); +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */ +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */ + REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0); + REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0); + REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0); + REG_WR(bp, CCM_REG_CCM_INT_MASK, 0); +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */ + REG_WR(bp, PXP2_REG_PXP2_INT_MASK, 0x480000); + REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0); + REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0); + REG_WR(bp, TCM_REG_TCM_INT_MASK, 0); +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0); */ + REG_WR(bp, CDU_REG_CDU_INT_MASK, 0); + REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0); +/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */ + REG_WR(bp, PBF_REG_PBF_INT_MASK, 0X18); /* bit 3,4 masked */ +} + +static int bnx2x_function_init(struct bnx2x *bp, int mode) +{ + int func = bp->port; + int port = func ? PORT1 : PORT0; + u32 val, i; +#ifdef USE_DMAE + u32 wb_write[2]; +#endif + + DP(BNX2X_MSG_MCP, "function is %d mode is %x\n", func, mode); + if ((func != 0) && (func != 1)) { + BNX2X_ERR("BAD function number (%d)\n", func); + return -ENODEV; + } + + bnx2x_gunzip_init(bp); + + if (mode & 0x1) { /* init common */ + DP(BNX2X_MSG_MCP, "starting common init func %d mode %x\n", + func, mode); + REG_WR(bp, MISC_REG_RESET_REG_1, 0xffffffff); + REG_WR(bp, MISC_REG_RESET_REG_2, 0xfffc); + bnx2x_init_block(bp, MISC_COMMON_START, MISC_COMMON_END); + + REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x100); + msleep(30); + REG_WR(bp, MISC_REG_LCPLL_CTRL_REG_2, 0x0); + + bnx2x_init_block(bp, PXP_COMMON_START, PXP_COMMON_END); + bnx2x_init_block(bp, PXP2_COMMON_START, PXP2_COMMON_END); + + bnx2x_init_pxp(bp); + + if (CHIP_REV(bp) == CHIP_REV_Ax) { + /* enable HW interrupt from PXP on USDM + overflow bit 16 on INT_MASK_0 */ + REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); + } + +#ifdef __BIG_ENDIAN + REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 1); + +/* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ + REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1); +#endif + +#ifndef BCM_ISCSI + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); +#endif + + REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 5); +#ifdef BCM_ISCSI + REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5); + REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5); +#endif + + bnx2x_init_block(bp, DMAE_COMMON_START, DMAE_COMMON_END); + + /* let the HW do it's magic ... */ + msleep(100); + /* finish PXP init + (can be moved up if we want to use the DMAE) */ + val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 CFG failed\n"); + return -EBUSY; + } + + val = REG_RD(bp, PXP2_REG_RD_INIT_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 RD_INIT failed\n"); + return -EBUSY; + } + + REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); + REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); + + bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8); + + bnx2x_init_block(bp, TCM_COMMON_START, TCM_COMMON_END); + bnx2x_init_block(bp, UCM_COMMON_START, UCM_COMMON_END); + bnx2x_init_block(bp, CCM_COMMON_START, CCM_COMMON_END); + bnx2x_init_block(bp, XCM_COMMON_START, XCM_COMMON_END); + +#ifdef BNX2X_DMAE_RD + bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3); +#else + REG_RD(bp, XSEM_REG_PASSIVE_BUFFER); + REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 4); + REG_RD(bp, XSEM_REG_PASSIVE_BUFFER + 8); + REG_RD(bp, CSEM_REG_PASSIVE_BUFFER); + REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 4); + REG_RD(bp, CSEM_REG_PASSIVE_BUFFER + 8); + REG_RD(bp, TSEM_REG_PASSIVE_BUFFER); + REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 4); + REG_RD(bp, TSEM_REG_PASSIVE_BUFFER + 8); + REG_RD(bp, USEM_REG_PASSIVE_BUFFER); + REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 4); + REG_RD(bp, USEM_REG_PASSIVE_BUFFER + 8); +#endif + bnx2x_init_block(bp, QM_COMMON_START, QM_COMMON_END); + /* softrest pulse */ + REG_WR(bp, QM_REG_SOFT_RESET, 1); + REG_WR(bp, QM_REG_SOFT_RESET, 0); + +#ifdef BCM_ISCSI + bnx2x_init_block(bp, TIMERS_COMMON_START, TIMERS_COMMON_END); +#endif + bnx2x_init_block(bp, DQ_COMMON_START, DQ_COMMON_END); + REG_WR(bp, DORQ_REG_DPM_CID_OFST, BCM_PAGE_BITS); + if (CHIP_REV(bp) == CHIP_REV_Ax) { + /* enable hw interrupt from doorbell Q */ + REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); + } + + bnx2x_init_block(bp, BRB1_COMMON_START, BRB1_COMMON_END); + + if (CHIP_REV_IS_SLOW(bp)) { + /* fix for emulation and FPGA for no pause */ + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0, 513); + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_1, 513); + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0, 0); + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_1, 0); + } + + bnx2x_init_block(bp, PRS_COMMON_START, PRS_COMMON_END); + + bnx2x_init_block(bp, TSDM_COMMON_START, TSDM_COMMON_END); + bnx2x_init_block(bp, CSDM_COMMON_START, CSDM_COMMON_END); + bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END); + bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END); + + bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); + bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); + bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); + bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE); + + bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END); + bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END); + bnx2x_init_block(bp, CSEM_COMMON_START, CSEM_COMMON_END); + bnx2x_init_block(bp, XSEM_COMMON_START, XSEM_COMMON_END); + + /* sync semi rtc */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0x80000000); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, + 0x80000000); + + bnx2x_init_block(bp, UPB_COMMON_START, UPB_COMMON_END); + bnx2x_init_block(bp, XPB_COMMON_START, XPB_COMMON_END); + bnx2x_init_block(bp, PBF_COMMON_START, PBF_COMMON_END); + + REG_WR(bp, SRC_REG_SOFT_RST, 1); + for (i = SRC_REG_KEYRSS0_0; i <= SRC_REG_KEYRSS1_9; i += 4) { + REG_WR(bp, i, 0xc0cac01a); + /* TODO: repleace with something meaningfull */ + } + /* SRCH COMMON comes here */ + REG_WR(bp, SRC_REG_SOFT_RST, 0); + + if (sizeof(union cdu_context) != 1024) { + /* we currently assume that a context is 1024 bytes */ + printk(KERN_ALERT PFX "please adjust the size of" + " cdu_context(%ld)\n", + (long)sizeof(union cdu_context)); + } + val = (4 << 24) + (0 << 12) + 1024; + REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); + bnx2x_init_block(bp, CDU_COMMON_START, CDU_COMMON_END); + + bnx2x_init_block(bp, CFC_COMMON_START, CFC_COMMON_END); + REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); + + bnx2x_init_block(bp, HC_COMMON_START, HC_COMMON_END); + bnx2x_init_block(bp, MISC_AEU_COMMON_START, + MISC_AEU_COMMON_END); + /* RXPCS COMMON comes here */ + /* EMAC0 COMMON comes here */ + /* EMAC1 COMMON comes here */ + /* DBU COMMON comes here */ + /* DBG COMMON comes here */ + bnx2x_init_block(bp, NIG_COMMON_START, NIG_COMMON_END); + + if (CHIP_REV_IS_SLOW(bp)) + msleep(200); + + /* finish CFC init */ + val = REG_RD(bp, CFC_REG_LL_INIT_DONE); + if (val != 1) { + BNX2X_ERR("CFC LL_INIT failed\n"); + return -EBUSY; + } + + val = REG_RD(bp, CFC_REG_AC_INIT_DONE); + if (val != 1) { + BNX2X_ERR("CFC AC_INIT failed\n"); + return -EBUSY; + } + + val = REG_RD(bp, CFC_REG_CAM_INIT_DONE); + if (val != 1) { + BNX2X_ERR("CFC CAM_INIT failed\n"); + return -EBUSY; + } + + REG_WR(bp, CFC_REG_DEBUG0, 0); + + /* read NIG statistic + to see if this is our first up since powerup */ +#ifdef BNX2X_DMAE_RD + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); +#else + val = REG_RD(bp, NIG_REG_STAT2_BRB_OCTET); + REG_RD(bp, NIG_REG_STAT2_BRB_OCTET + 4); +#endif + /* do internal memory self test */ + if ((val == 0) && bnx2x_int_mem_test(bp)) { + BNX2X_ERR("internal mem selftest failed\n"); + return -EBUSY; + } + + /* clear PXP2 attentions */ + REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR); + + enable_blocks_attention(bp); + /* enable_blocks_parity(bp); */ + + } /* end of common init */ + + /* per port init */ + + /* the phys address is shifted right 12 bits and has an added + 1=valid bit added to the 53rd bit + then since this is a wide register(TM) + we split it into two 32 bit writes + */ +#define RQ_ONCHIP_AT_PORT_SIZE 384 +#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) +#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) +#define PXP_ONE_ILT(x) ((x << 10) | x) + + DP(BNX2X_MSG_MCP, "starting per-function init port is %x\n", func); + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + func*4, 0); + + /* Port PXP comes here */ + /* Port PXP2 comes here */ + + /* Offset is + * Port0 0 + * Port1 384 */ + i = func * RQ_ONCHIP_AT_PORT_SIZE; +#ifdef USE_DMAE + wb_write[0] = ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context)); + wb_write[1] = ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context)); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); +#else + REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, + ONCHIP_ADDR1(bnx2x_sp_mapping(bp, context))); + REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + i*8 + 4, + ONCHIP_ADDR2(bnx2x_sp_mapping(bp, context))); +#endif + REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4, PXP_ONE_ILT(i)); + +#ifdef BCM_ISCSI + /* Port0 1 + * Port1 385 */ + i++; + wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping); + wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); + REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i)); + + /* Port0 2 + * Port1 386 */ + i++; + wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping); + wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); + REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i)); + + /* Port0 3 + * Port1 387 */ + i++; + wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping); + wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping); + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); + REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i)); +#endif + + /* Port TCM comes here */ + /* Port UCM comes here */ + /* Port CCM comes here */ + bnx2x_init_block(bp, func ? XCM_PORT1_START : XCM_PORT0_START, + func ? XCM_PORT1_END : XCM_PORT0_END); + +#ifdef USE_DMAE + wb_write[0] = 0; + wb_write[1] = 0; +#endif + for (i = 0; i < 32; i++) { + REG_WR(bp, QM_REG_BASEADDR + (func*32 + i)*4, 1024 * 4 * i); +#ifdef USE_DMAE + REG_WR_DMAE(bp, QM_REG_PTRTBL + (func*32 + i)*8, wb_write, 2); +#else + REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8, 0); + REG_WR_IND(bp, QM_REG_PTRTBL + (func*32 + i)*8 + 4, 0); +#endif + } + REG_WR(bp, QM_REG_CONNNUM_0 + func*4, 1024/16 - 1); + + /* Port QM comes here */ + +#ifdef BCM_ISCSI + REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20); + REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31); + + bnx2x_init_block(bp, func ? TIMERS_PORT1_START : TIMERS_PORT0_START, + func ? TIMERS_PORT1_END : TIMERS_PORT0_END); +#endif + /* Port DQ comes here */ + /* Port BRB1 comes here */ + bnx2x_init_block(bp, func ? PRS_PORT1_START : PRS_PORT0_START, + func ? PRS_PORT1_END : PRS_PORT0_END); + /* Port TSDM comes here */ + /* Port CSDM comes here */ + /* Port USDM comes here */ + /* Port XSDM comes here */ + bnx2x_init_block(bp, func ? TSEM_PORT1_START : TSEM_PORT0_START, + func ? TSEM_PORT1_END : TSEM_PORT0_END); + bnx2x_init_block(bp, func ? USEM_PORT1_START : USEM_PORT0_START, + func ? USEM_PORT1_END : USEM_PORT0_END); + bnx2x_init_block(bp, func ? CSEM_PORT1_START : CSEM_PORT0_START, + func ? CSEM_PORT1_END : CSEM_PORT0_END); + bnx2x_init_block(bp, func ? XSEM_PORT1_START : XSEM_PORT0_START, + func ? XSEM_PORT1_END : XSEM_PORT0_END); + /* Port UPB comes here */ + /* Port XSDM comes here */ + bnx2x_init_block(bp, func ? PBF_PORT1_START : PBF_PORT0_START, + func ? PBF_PORT1_END : PBF_PORT0_END); + + /* configure PBF to work without PAUSE mtu 9000 */ + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + func*4, 0); + + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + func*4, (9040/16)); + /* update init credit */ + REG_WR(bp, PBF_REG_P0_INIT_CRD + func*4, (9040/16) + 553 - 22); + + /* probe changes */ + REG_WR(bp, PBF_REG_INIT_P0 + func*4, 1); + msleep(5); + REG_WR(bp, PBF_REG_INIT_P0 + func*4, 0); + +#ifdef BCM_ISCSI + /* tell the searcher where the T2 table is */ + REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64); + + wb_write[0] = U64_LO(bp->t2_mapping); + wb_write[1] = U64_HI(bp->t2_mapping); + REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2); + wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64); + wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64); + REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2); + + REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10); + /* Port SRCH comes here */ +#endif + /* Port CDU comes here */ + /* Port CFC comes here */ + bnx2x_init_block(bp, func ? HC_PORT1_START : HC_PORT0_START, + func ? HC_PORT1_END : HC_PORT0_END); + bnx2x_init_block(bp, func ? MISC_AEU_PORT1_START : + MISC_AEU_PORT0_START, + func ? MISC_AEU_PORT1_END : MISC_AEU_PORT0_END); + /* Port PXPCS comes here */ + /* Port EMAC0 comes here */ + /* Port EMAC1 comes here */ + /* Port DBU comes here */ + /* Port DBG comes here */ + bnx2x_init_block(bp, func ? NIG_PORT1_START : NIG_PORT0_START, + func ? NIG_PORT1_END : NIG_PORT0_END); + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + func*4, 1); + /* Port MCP comes here */ + /* Port DMAE comes here */ + + bnx2x_link_reset(bp); + + /* Reset pciex errors for debug */ + REG_WR(bp, 0x2114, 0xffffffff); + REG_WR(bp, 0x2120, 0xffffffff); + REG_WR(bp, 0x2814, 0xffffffff); + + /* !!! move to init_values.h */ + REG_WR(bp, XSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); + REG_WR(bp, USDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); + REG_WR(bp, CSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); + REG_WR(bp, TSDM_REG_INIT_CREDIT_PXP_CTRL, 0x1); + + REG_WR(bp, DBG_REG_PCI_REQ_CREDIT, 0x1); + REG_WR(bp, TM_REG_PCIARB_CRDCNT_VAL, 0x1); + REG_WR(bp, CDU_REG_CDU_DEBUG, 0x264); + REG_WR(bp, CDU_REG_CDU_DEBUG, 0x0); + + bnx2x_gunzip_end(bp); + + if (!nomcp) { + port = bp->port; + + bp->fw_drv_pulse_wr_seq = + (SHMEM_RD(bp, drv_fw_mb[port].drv_pulse_mb) & + DRV_PULSE_SEQ_MASK); + bp->fw_mb = SHMEM_RD(bp, drv_fw_mb[port].fw_mb_param); + DP(BNX2X_MSG_MCP, "drv_pulse 0x%x fw_mb 0x%x\n", + bp->fw_drv_pulse_wr_seq, bp->fw_mb); + } else { + bp->fw_mb = 0; + } + + return 0; +} + + +/* send the MCP a request, block untill there is a reply */ +static u32 bnx2x_fw_command(struct bnx2x *bp, u32 command) +{ + u32 rc = 0; + u32 seq = ++bp->fw_seq; + int port = bp->port; + + SHMEM_WR(bp, drv_fw_mb[port].drv_mb_header, command|seq); + DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB\n", command|seq); + + /* let the FW do it's magic ... */ + msleep(100); /* TBD */ + + if (CHIP_REV_IS_SLOW(bp)) + msleep(900); + + rc = SHMEM_RD(bp, drv_fw_mb[port].fw_mb_header); + + DP(BNX2X_MSG_MCP, "read (%x) seq is (%x) from FW MB\n", rc, seq); + + /* is this a reply to our command? */ + if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) { + rc &= FW_MSG_CODE_MASK; + } else { + /* FW BUG! */ + BNX2X_ERR("FW failed to respond!\n"); + bnx2x_fw_dump(bp); + rc = 0; + } + return rc; +} + +static void bnx2x_free_mem(struct bnx2x *bp) +{ + +#define BNX2X_PCI_FREE(x, y, size) \ + do { \ + if (x) { \ + pci_free_consistent(bp->pdev, size, x, y); \ + x = NULL; \ + y = 0; \ + } \ + } while (0) + +#define BNX2X_FREE(x) \ + do { \ + if (x) { \ + vfree(x); \ + x = NULL; \ + } \ + } while (0) + + int i; + + /* fastpath */ + for_each_queue(bp, i) { + + /* Status blocks */ + BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk), + bnx2x_fp(bp, i, status_blk_mapping), + sizeof(struct host_status_block) + + sizeof(struct eth_tx_db_data)); + + /* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */ + BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring), + bnx2x_fp(bp, i, tx_desc_mapping), + sizeof(struct eth_tx_bd) * NUM_TX_BD); + + BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring), + bnx2x_fp(bp, i, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring), + bnx2x_fp(bp, i, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + } + + BNX2X_FREE(bp->fp); + + /* end of fastpath */ + + BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, + (sizeof(struct host_def_status_block))); + + BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping, + (sizeof(struct bnx2x_slowpath))); + +#ifdef BCM_ISCSI + BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024); + BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024); + BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024); + BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024); +#endif + BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, PAGE_SIZE); + +#undef BNX2X_PCI_FREE +#undef BNX2X_KFREE +} + +static int bnx2x_alloc_mem(struct bnx2x *bp) +{ + +#define BNX2X_PCI_ALLOC(x, y, size) \ + do { \ + x = pci_alloc_consistent(bp->pdev, size, y); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset(x, 0, size); \ + } while (0) + +#define BNX2X_ALLOC(x, size) \ + do { \ + x = vmalloc(size); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset(x, 0, size); \ + } while (0) + + int i; + + /* fastpath */ + BNX2X_ALLOC(bp->fp, sizeof(struct bnx2x_fastpath) * bp->num_queues); + + for_each_queue(bp, i) { + bnx2x_fp(bp, i, bp) = bp; + + /* Status blocks */ + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, status_blk), + &bnx2x_fp(bp, i, status_blk_mapping), + sizeof(struct host_status_block) + + sizeof(struct eth_tx_db_data)); + + bnx2x_fp(bp, i, hw_tx_prods) = + (void *)(bnx2x_fp(bp, i, status_blk) + 1); + + bnx2x_fp(bp, i, tx_prods_mapping) = + bnx2x_fp(bp, i, status_blk_mapping) + + sizeof(struct host_status_block); + + /* fast path rings: tx_buf tx_desc rx_buf rx_desc rx_comp */ + BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring), + sizeof(struct sw_tx_bd) * NUM_TX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring), + &bnx2x_fp(bp, i, tx_desc_mapping), + sizeof(struct eth_tx_bd) * NUM_TX_BD); + + BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring), + sizeof(struct sw_rx_bd) * NUM_RX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring), + &bnx2x_fp(bp, i, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring), + &bnx2x_fp(bp, i, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + } + /* end of fastpath */ + + BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping, + sizeof(struct host_def_status_block)); + + BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping, + sizeof(struct bnx2x_slowpath)); + +#ifdef BCM_ISCSI + BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024); + + /* Initialize T1 */ + for (i = 0; i < 64*1024; i += 64) { + *(u64 *)((char *)bp->t1 + i + 56) = 0x0UL; + *(u64 *)((char *)bp->t1 + i + 3) = 0x0UL; + } + + /* allocate searcher T2 table + we allocate 1/4 of alloc num for T2 + (which is not entered into the ILT) */ + BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024); + + /* Initialize T2 */ + for (i = 0; i < 16*1024; i += 64) + * (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64; + + /* now sixup the last line in the block to point to the next block */ + *(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping; + + /* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */ + BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024); + + /* QM queues (128*MAX_CONN) */ + BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024); +#endif + + /* Slow path ring */ + BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE); + + return 0; + +alloc_mem_err: + bnx2x_free_mem(bp); + return -ENOMEM; + +#undef BNX2X_PCI_ALLOC +#undef BNX2X_ALLOC +} + +static void bnx2x_free_tx_skbs(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + u16 bd_cons = fp->tx_bd_cons; + u16 sw_prod = fp->tx_pkt_prod; + u16 sw_cons = fp->tx_pkt_cons; + + BUG_TRAP(fp->tx_buf_ring != NULL); + + while (sw_cons != sw_prod) { + bd_cons = bnx2x_free_tx_pkt(bp, fp, TX_BD(sw_cons)); + sw_cons++; + } + } +} + +static void bnx2x_free_rx_skbs(struct bnx2x *bp) +{ + int i, j; + + for_each_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + BUG_TRAP(fp->rx_buf_ring != NULL); + + for (i = 0; i < NUM_RX_BD; i++) { + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; + struct sk_buff *skb = rx_buf->skb; + + if (skb == NULL) + continue; + + pci_unmap_single(bp->pdev, + pci_unmap_addr(rx_buf, mapping), + bp->rx_buf_use_size, + PCI_DMA_FROMDEVICE); + + rx_buf->skb = NULL; + dev_kfree_skb(skb); + } + } +} + +static void bnx2x_free_skbs(struct bnx2x *bp) +{ + bnx2x_free_tx_skbs(bp); + bnx2x_free_rx_skbs(bp); +} + +static void bnx2x_free_msix_irqs(struct bnx2x *bp) +{ + int i; + + free_irq(bp->msix_table[0].vector, bp->dev); + DP(NETIF_MSG_IFDOWN, "rleased sp irq (%d)\n", + bp->msix_table[0].vector); + + for_each_queue(bp, i) { + DP(NETIF_MSG_IFDOWN, "about to rlease fp #%d->%d irq " + "state(%x)\n", i, bp->msix_table[i + 1].vector, + bnx2x_fp(bp, i, state)); + + if (bnx2x_fp(bp, i, state) != BNX2X_FP_STATE_CLOSED) { + + free_irq(bp->msix_table[i + 1].vector, &bp->fp[i]); + bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_CLOSED; + + } else + DP(NETIF_MSG_IFDOWN, "irq not freed\n"); + + } + +} + +static void bnx2x_free_irq(struct bnx2x *bp) +{ + + if (bp->flags & USING_MSIX_FLAG) { + + bnx2x_free_msix_irqs(bp); + pci_disable_msix(bp->pdev); + + bp->flags &= ~USING_MSIX_FLAG; + + } else + free_irq(bp->pdev->irq, bp->dev); +} + +static int bnx2x_enable_msix(struct bnx2x *bp) +{ + + int i; + + bp->msix_table[0].entry = 0; + for_each_queue(bp, i) + bp->msix_table[i + 1].entry = i + 1; + + if (pci_enable_msix(bp->pdev, &bp->msix_table[0], + bp->num_queues + 1)){ + BNX2X_ERR("failed to enable msix\n"); + return -1; + + } + + bp->flags |= USING_MSIX_FLAG; + + return 0; + +} + + +static int bnx2x_req_msix_irqs(struct bnx2x *bp) +{ + + + int i, rc; + + DP(NETIF_MSG_IFUP, "about to request sp irq\n"); + + rc = request_irq(bp->msix_table[0].vector, bnx2x_msix_sp_int, 0, + bp->dev->name, bp->dev); + + if (rc) { + BNX2X_ERR("request sp irq failed\n"); + return -EBUSY; + } + + for_each_queue(bp, i) { + rc = request_irq(bp->msix_table[i + 1].vector, + bnx2x_msix_fp_int, 0, + bp->dev->name, &bp->fp[i]); + + if (rc) { + BNX2X_ERR("request fp #%d irq failed\n", i); + bnx2x_free_msix_irqs(bp); + return -EBUSY; + } + + bnx2x_fp(bp, i, state) = BNX2X_FP_STATE_IRQ; + + } + + return 0; + +} + +static int bnx2x_req_irq(struct bnx2x *bp) +{ + + int rc = request_irq(bp->pdev->irq, bnx2x_interrupt, + IRQF_SHARED, bp->dev->name, bp->dev); + if (!rc) + bnx2x_fp(bp, 0, state) = BNX2X_FP_STATE_IRQ; + + return rc; + +} + +/* + * Init service functions + */ + +static void bnx2x_set_mac_addr(struct bnx2x *bp) +{ + struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config); + + /* CAM allocation + * unicasts 0-31:port0 32-63:port1 + * multicast 64-127:port0 128-191:port1 + */ + config->hdr.length_6b = 2; + config->hdr.offset = bp->port ? 31 : 0; + config->hdr.reserved0 = 0; + config->hdr.reserved1 = 0; + + /* primary MAC */ + config->config_table[0].cam_entry.msb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[0]); + config->config_table[0].cam_entry.middle_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[2]); + config->config_table[0].cam_entry.lsb_mac_addr = + swab16(*(u16 *)&bp->dev->dev_addr[4]); + config->config_table[0].cam_entry.flags = cpu_to_le16(bp->port); + config->config_table[0].target_table_entry.flags = 0; + config->config_table[0].target_table_entry.client_id = 0; + config->config_table[0].target_table_entry.vlan_id = 0; + + DP(NETIF_MSG_IFUP, "setting MAC (%04x:%04x:%04x)\n", + config->config_table[0].cam_entry.msb_mac_addr, + config->config_table[0].cam_entry.middle_mac_addr, + config->config_table[0].cam_entry.lsb_mac_addr); + + /* broadcast */ + config->config_table[1].cam_entry.msb_mac_addr = 0xffff; + config->config_table[1].cam_entry.middle_mac_addr = 0xffff; + config->config_table[1].cam_entry.lsb_mac_addr = 0xffff; + config->config_table[1].cam_entry.flags = cpu_to_le16(bp->port); + config->config_table[1].target_table_entry.flags = + TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST; + config->config_table[1].target_table_entry.client_id = 0; + config->config_table[1].target_table_entry.vlan_id = 0; + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mac_config)), + U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0); +} + +static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx, + int *state_p, int poll) +{ + /* can take a while if any port is running */ + int timeout = 500; + + /* DP("waiting for state to become %d on IDX [%d]\n", + state, sb_idx); */ + + might_sleep(); + + while (timeout) { + + if (poll) { + bnx2x_rx_int(bp->fp, 10); + /* If index is different from 0 + * The reply for some commands will + * be on the none default queue + */ + if (idx) + bnx2x_rx_int(&bp->fp[idx], 10); + } + + mb(); /* state is changed by bnx2x_sp_event()*/ + + if (*state_p != state) + return 0; + + timeout--; + msleep(1); + + } + + + /* timeout! */ + BNX2X_ERR("timeout waiting for ramrod %d on %d\n", state, idx); + return -EBUSY; + +} + +static int bnx2x_setup_leading(struct bnx2x *bp) +{ + + /* reset IGU staae */ + bnx2x_ack_sb(bp, DEF_SB_ID, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + + /* SETUP ramrod */ + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_SETUP, 0, 0, 0, 0); + + return bnx2x_wait_ramrod(bp, BNX2X_STATE_OPEN, 0, &(bp->state), 0); + +} + +static int bnx2x_setup_multi(struct bnx2x *bp, int index) +{ + + /* reset IGU state */ + bnx2x_ack_sb(bp, index, CSTORM_ID, 0, IGU_INT_ENABLE, 0); + + bp->fp[index].state = BNX2X_FP_STATE_OPENING; + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_SETUP, index, 0, index, 0); + + /* Wait for completion */ + return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_OPEN, index, + &(bp->fp[index].state), 1); + +} + + +static int bnx2x_poll(struct napi_struct *napi, int budget); +static void bnx2x_set_rx_mode(struct net_device *dev); + +static int bnx2x_nic_load(struct bnx2x *bp, int req_irq) +{ + int rc; + int i = 0; + + bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; + + /* Send LOAD_REQUEST command to MCP. + Returns the type of LOAD command: if it is the + first port to be initialized common blocks should be + initialized, otherwise - not. + */ + if (!nomcp) { + rc = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ); + if (rc == FW_MSG_CODE_DRV_LOAD_REFUSED) { + return -EBUSY; /* other port in diagnostic mode */ + } + } else { + rc = FW_MSG_CODE_DRV_LOAD_COMMON; + } + + DP(NETIF_MSG_IFUP, "set number of queues to %d\n", bp->num_queues); + + /* if we can't use msix we only need one fp, + * so try to enable msix with the requested number of fp's + * and fallback to inta with one fp + */ + if (req_irq) { + + if (use_inta) { + bp->num_queues = 1; + } else { + if (use_multi > 1 && use_multi <= 16) + /* user requested number */ + bp->num_queues = use_multi; + else if (use_multi == 1) + bp->num_queues = num_online_cpus(); + else + bp->num_queues = 1; + + if (bnx2x_enable_msix(bp)) { + /* faild to enable msix */ + bp->num_queues = 1; + if (use_multi) + BNX2X_ERR("Muti requested but failed" + " to enable MSI-X\n"); + } + } + } + + if (bnx2x_alloc_mem(bp)) + return -ENOMEM; + + if (req_irq) { + if (bp->flags & USING_MSIX_FLAG) { + if (bnx2x_req_msix_irqs(bp)) { + pci_disable_msix(bp->pdev); + goto out_error; + } + + } else { + if (bnx2x_req_irq(bp)) { + BNX2X_ERR("IRQ request failed, aborting\n"); + goto out_error; + } + } + } + + for_each_queue(bp, i) + netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), + bnx2x_poll, 128); + + + /* Initialize HW */ + if (bnx2x_function_init(bp, (rc == FW_MSG_CODE_DRV_LOAD_COMMON))) { + BNX2X_ERR("HW init failed, aborting\n"); + goto out_error; + } + + + atomic_set(&bp->intr_sem, 0); + + /* Reenable SP tasklet */ + /*if (bp->sp_task_en) { */ + /* tasklet_enable(&bp->sp_task);*/ + /*} else { */ + /* bp->sp_task_en = 1; */ + /*} */ + + /* Setup NIC internals and enable interrupts */ + bnx2x_nic_init(bp); + + /* Send LOAD_DONE command to MCP */ + if (!nomcp) { + rc = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE); + DP(NETIF_MSG_IFUP, "rc = 0x%x\n", rc); + if (!rc) { + BNX2X_ERR("MCP response failure, unloading\n"); + goto int_disable; + } + } + + bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; + + /* Enable Rx interrupt handling before sending the ramrod + as it's completed on Rx FP queue */ + for_each_queue(bp, i) + napi_enable(&bnx2x_fp(bp, i, napi)); + + if (bnx2x_setup_leading(bp)) + goto stop_netif; + + for_each_nondefault_queue(bp, i) + if (bnx2x_setup_multi(bp, i)) + goto stop_netif; + + bnx2x_set_mac_addr(bp); + + bnx2x_phy_init(bp); + + /* Start fast path */ + if (req_irq) { /* IRQ is only requested from bnx2x_open */ + netif_start_queue(bp->dev); + if (bp->flags & USING_MSIX_FLAG) + printk(KERN_INFO PFX "%s: using MSI-X\n", + bp->dev->name); + + /* Otherwise Tx queue should be only reenabled */ + } else if (netif_running(bp->dev)) { + netif_wake_queue(bp->dev); + bnx2x_set_rx_mode(bp->dev); + } + + /* start the timer */ + mod_timer(&bp->timer, jiffies + bp->current_interval); + + return 0; + +stop_netif: + for_each_queue(bp, i) + napi_disable(&bnx2x_fp(bp, i, napi)); + +int_disable: + bnx2x_disable_int_sync(bp); + + bnx2x_free_skbs(bp); + bnx2x_free_irq(bp); + +out_error: + bnx2x_free_mem(bp); + + /* TBD we really need to reset the chip + if we want to recover from this */ + return rc; +} + +static void bnx2x_netif_stop(struct bnx2x *bp) +{ + int i; + + bp->rx_mode = BNX2X_RX_MODE_NONE; + bnx2x_set_storm_rx_mode(bp); + + bnx2x_disable_int_sync(bp); + bnx2x_link_reset(bp); + + for_each_queue(bp, i) + napi_disable(&bnx2x_fp(bp, i, napi)); + + if (netif_running(bp->dev)) { + netif_tx_disable(bp->dev); + bp->dev->trans_start = jiffies; /* prevent tx timeout */ + } +} + +static void bnx2x_reset_chip(struct bnx2x *bp, u32 reset_code) +{ + int port = bp->port; +#ifdef USE_DMAE + u32 wb_write[2]; +#endif + int base, i; + + DP(NETIF_MSG_IFDOWN, "reset called with code %x\n", reset_code); + + /* Do not rcv packets to BRB */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0); + /* Do not direct rcv packets that are not for MCP to the BRB */ + REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : + NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); + + /* Configure IGU and AEU */ + REG_WR(bp, HC_REG_CONFIG_0 + port*4, 0x1000); + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0); + + /* TODO: Close Doorbell port? */ + + /* Clear ILT */ +#ifdef USE_DMAE + wb_write[0] = 0; + wb_write[1] = 0; +#endif + base = port * RQ_ONCHIP_AT_PORT_SIZE; + for (i = base; i < base + RQ_ONCHIP_AT_PORT_SIZE; i++) { +#ifdef USE_DMAE + REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2); +#else + REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT, 0); + REG_WR_IND(bp, PXP2_REG_RQ_ONCHIP_AT + 4, 0); +#endif + } + + if (reset_code == FW_MSG_CODE_DRV_UNLOAD_COMMON) { + /* reset_common */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffff7f); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + 0x1403); + } +} + +static int bnx2x_stop_multi(struct bnx2x *bp, int index) +{ + + int rc; + + /* halt the connnection */ + bp->fp[index].state = BNX2X_FP_STATE_HALTING; + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, index, 0, 0, 0); + + + rc = bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, index, + &(bp->fp[index].state), 1); + if (rc) /* timout */ + return rc; + + /* delete cfc entry */ + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CFC_DEL, index, 0, 0, 1); + + return bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_DELETED, index, + &(bp->fp[index].state), 1); + +} + + +static void bnx2x_stop_leading(struct bnx2x *bp) +{ + + /* if the other port is hadling traffic, + this can take a lot of time */ + int timeout = 500; + + might_sleep(); + + /* Send HALT ramrod */ + bp->fp[0].state = BNX2X_FP_STATE_HALTING; + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, 0, 0, 0, 0); + + if (bnx2x_wait_ramrod(bp, BNX2X_FP_STATE_HALTED, 0, + &(bp->fp[0].state), 1)) + return; + + bp->dsb_sp_prod_idx = *bp->dsb_sp_prod; + + /* Send CFC_DELETE ramrod */ + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_PORT_DEL, 0, 0, 0, 1); + + /* + Wait for completion. + we are going to reset the chip anyway + so there is not much to do if this times out + */ + while (bp->dsb_sp_prod_idx == *bp->dsb_sp_prod && timeout) { + timeout--; + msleep(1); + } + +} + +static int bnx2x_nic_unload(struct bnx2x *bp, int fre_irq) +{ + u32 reset_code = 0; + int rc; + int i; + + bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + + /* Calling flush_scheduled_work() may deadlock because + * linkwatch_event() may be on the workqueue and it will try to get + * the rtnl_lock which we are holding. + */ + + while (bp->in_reset_task) + msleep(1); + + /* Delete the timer: do it before disabling interrupts, as it + may be stil STAT_QUERY ramrod pending after stopping the timer */ + del_timer_sync(&bp->timer); + + /* Wait until stat ramrod returns and all SP tasks complete */ + while (bp->stat_pending && (bp->spq_left != MAX_SPQ_PENDING)) + msleep(1); + + /* Stop fast path, disable MAC, disable interrupts, disable napi */ + bnx2x_netif_stop(bp); + + if (bp->flags & NO_WOL_FLAG) + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; + else if (bp->wol) { + u32 emac_base = bp->port ? GRCBASE_EMAC0 : GRCBASE_EMAC1; + u8 *mac_addr = bp->dev->dev_addr; + u32 val = (EMAC_MODE_MPKT | EMAC_MODE_MPKT_RCVD | + EMAC_MODE_ACPI_RCVD); + + EMAC_WR(EMAC_REG_EMAC_MODE, val); + + val = (mac_addr[0] << 8) | mac_addr[1]; + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH, val); + + val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]; + EMAC_WR(EMAC_REG_EMAC_MAC_MATCH + 4, val); + + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN; + } else + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + + for_each_nondefault_queue(bp, i) + if (bnx2x_stop_multi(bp, i)) + goto error; + + + bnx2x_stop_leading(bp); + +error: + if (!nomcp) + rc = bnx2x_fw_command(bp, reset_code); + else + rc = FW_MSG_CODE_DRV_UNLOAD_COMMON; + + /* Release IRQs */ + if (fre_irq) + bnx2x_free_irq(bp); + + /* Reset the chip */ + bnx2x_reset_chip(bp, rc); + + /* Report UNLOAD_DONE to MCP */ + if (!nomcp) + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE); + + /* Free SKBs and driver internals */ + bnx2x_free_skbs(bp); + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; + /* Set link down */ + bp->link_up = 0; + netif_carrier_off(bp->dev); + + return 0; +} + +/* end of nic load/unload */ + +/* ethtool_ops */ + +/* + * Init service functions + */ + +static void bnx2x_link_settings_supported(struct bnx2x *bp, u32 switch_cfg) +{ + int port = bp->port; + u32 ext_phy_type; + + bp->phy_flags = 0; + + switch (switch_cfg) { + case SWITCH_CFG_1G: + BNX2X_DEV_INFO("switch_cfg 0x%x (1G)\n", switch_cfg); + + ext_phy_type = SERDES_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT: + BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", + ext_phy_type); + + bp->supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseT_Full | + SUPPORTED_TP | SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482: + BNX2X_DEV_INFO("ext_phy_type 0x%x (5482)\n", + ext_phy_type); + + bp->phy_flags |= PHY_SGMII_FLAG; + + bp->supported |= (/* SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full |*/ + SUPPORTED_1000baseT_Full | + SUPPORTED_TP | SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + default: + BNX2X_ERR("NVRAM config error. " + "BAD SerDes ext_phy_config 0x%x\n", + bp->ext_phy_config); + return; + } + + bp->phy_addr = REG_RD(bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + + port*0x10); + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr); + break; + + case SWITCH_CFG_10G: + BNX2X_DEV_INFO("switch_cfg 0x%x (10G)\n", switch_cfg); + + bp->phy_flags |= PHY_XGXS_FLAG; + + ext_phy_type = XGXS_EXT_PHY_TYPE(bp); + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + BNX2X_DEV_INFO("ext_phy_type 0x%x (Direct)\n", + ext_phy_type); + + bp->supported |= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + BNX2X_DEV_INFO("ext_phy_type 0x%x (8705/6)\n", + ext_phy_type); + + bp->supported |= (SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + + default: + BNX2X_ERR("NVRAM config error. " + "BAD XGXS ext_phy_config 0x%x\n", + bp->ext_phy_config); + return; + } + + bp->phy_addr = REG_RD(bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + + port*0x18); + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->phy_addr); + + bp->ser_lane = ((bp->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + bp->rx_lane_swap = ((bp->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT); + bp->tx_lane_swap = ((bp->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT); + BNX2X_DEV_INFO("rx_lane_swap 0x%x tx_lane_swap 0x%x\n", + bp->rx_lane_swap, bp->tx_lane_swap); + break; + + default: + BNX2X_ERR("BAD switch_cfg link_config 0x%x\n", + bp->link_config); + return; + } + + /* mask what we support according to speed_cap_mask */ + if (!(bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) + bp->supported &= ~SUPPORTED_10baseT_Half; + + if (!(bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL)) + bp->supported &= ~SUPPORTED_10baseT_Full; + + if (!(bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) + bp->supported &= ~SUPPORTED_100baseT_Half; + + if (!(bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL)) + bp->supported &= ~SUPPORTED_100baseT_Full; + + if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) + bp->supported &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) + bp->supported &= ~SUPPORTED_2500baseT_Full; + + if (!(bp->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) + bp->supported &= ~SUPPORTED_10000baseT_Full; + + BNX2X_DEV_INFO("supported 0x%x\n", bp->supported); +} + +static void bnx2x_link_settings_requested(struct bnx2x *bp) +{ + bp->req_autoneg = 0; + bp->req_duplex = DUPLEX_FULL; + + switch (bp->link_config & PORT_FEATURE_LINK_SPEED_MASK) { + case PORT_FEATURE_LINK_SPEED_AUTO: + if (bp->supported & SUPPORTED_Autoneg) { + bp->req_autoneg |= AUTONEG_SPEED; + bp->req_line_speed = 0; + bp->advertising = bp->supported; + } else { + u32 ext_phy_type; + + ext_phy_type = XGXS_EXT_PHY_TYPE(bp); + if ((ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) || + (ext_phy_type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706)) { + /* force 10G, no AN */ + bp->req_line_speed = SPEED_10000; + bp->advertising = + (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + break; + } + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " Autoneg not supported\n", + bp->link_config); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10M_FULL: + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) { + bp->req_line_speed = SPEED_10; + bp->advertising = (ADVERTISED_10baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10M_HALF: + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF) { + bp->req_line_speed = SPEED_10; + bp->req_duplex = DUPLEX_HALF; + bp->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_100M_FULL: + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL) { + bp->req_line_speed = SPEED_100; + bp->advertising = (ADVERTISED_100baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_100M_HALF: + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF) { + bp->req_line_speed = SPEED_100; + bp->req_duplex = DUPLEX_HALF; + bp->advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_1G: + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) { + bp->req_line_speed = SPEED_1000; + bp->advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_2_5G: + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) { + bp->req_line_speed = SPEED_2500; + bp->advertising = (ADVERTISED_2500baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10G_CX4: + case PORT_FEATURE_LINK_SPEED_10G_KX4: + case PORT_FEATURE_LINK_SPEED_10G_KR: + if (!(bp->phy_flags & PHY_XGXS_FLAG)) { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " phy_flags 0x%x\n", + bp->link_config, bp->phy_flags); + return; + } + if (bp->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) { + bp->req_line_speed = SPEED_10000; + bp->advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + bp->link_config, bp->speed_cap_mask); + return; + } + break; + + default: + BNX2X_ERR("NVRAM config error. " + "BAD link speed link_config 0x%x\n", + bp->link_config); + bp->req_autoneg |= AUTONEG_SPEED; + bp->req_line_speed = 0; + bp->advertising = bp->supported; + break; + } + BNX2X_DEV_INFO("req_line_speed %d req_duplex %d\n", + bp->req_line_speed, bp->req_duplex); + + bp->req_flow_ctrl = (bp->link_config & + PORT_FEATURE_FLOW_CONTROL_MASK); + /* Please refer to Table 28B-3 of the 802.3ab-1999 spec */ + switch (bp->req_flow_ctrl) { + case FLOW_CTRL_AUTO: + bp->req_autoneg |= AUTONEG_FLOW_CTRL; + if (bp->dev->mtu <= 4500) { + bp->pause_mode = PAUSE_BOTH; + bp->advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + } else { + bp->pause_mode = PAUSE_ASYMMETRIC; + bp->advertising |= ADVERTISED_Asym_Pause; + } + break; + + case FLOW_CTRL_TX: + bp->pause_mode = PAUSE_ASYMMETRIC; + bp->advertising |= ADVERTISED_Asym_Pause; + break; + + case FLOW_CTRL_RX: + case FLOW_CTRL_BOTH: + bp->pause_mode = PAUSE_BOTH; + bp->advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + + case FLOW_CTRL_NONE: + default: + bp->pause_mode = PAUSE_NONE; + bp->advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + } + BNX2X_DEV_INFO("req_autoneg 0x%x req_flow_ctrl 0x%x\n" + KERN_INFO " pause_mode %d advertising 0x%x\n", + bp->req_autoneg, bp->req_flow_ctrl, + bp->pause_mode, bp->advertising); +} + +static void bnx2x_get_hwinfo(struct bnx2x *bp) +{ + u32 val, val2, val3, val4, id; + int port = bp->port; + u32 switch_cfg; + + bp->shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + BNX2X_DEV_INFO("shmem offset is %x\n", bp->shmem_base); + + /* Get the chip revision id and number. */ + /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ + val = REG_RD(bp, MISC_REG_CHIP_NUM); + id = ((val & 0xffff) << 16); + val = REG_RD(bp, MISC_REG_CHIP_REV); + id |= ((val & 0xf) << 12); + val = REG_RD(bp, MISC_REG_CHIP_METAL); + id |= ((val & 0xff) << 4); + REG_RD(bp, MISC_REG_BOND_ID); + id |= (val & 0xf); + bp->chip_id = id; + BNX2X_DEV_INFO("chip ID is %x\n", id); + + if (!bp->shmem_base || (bp->shmem_base != 0xAF900)) { + BNX2X_DEV_INFO("MCP not active\n"); + nomcp = 1; + goto set_mac; + } + + val = SHMEM_RD(bp, validity_map[port]); + if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + BNX2X_ERR("MCP validity signature bad\n"); + + bp->fw_seq = (SHMEM_RD(bp, drv_fw_mb[port].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + + bp->hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config); + + bp->serdes_config = + SHMEM_RD(bp, dev_info.port_hw_config[bp->port].serdes_config); + bp->lane_config = + SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config); + bp->ext_phy_config = + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config); + bp->speed_cap_mask = + SHMEM_RD(bp, + dev_info.port_hw_config[port].speed_capability_mask); + + bp->link_config = + SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); + + BNX2X_DEV_INFO("hw_config (%08x) serdes_config (%08x)\n" + KERN_INFO " lane_config (%08x) ext_phy_config (%08x)\n" + KERN_INFO " speed_cap_mask (%08x) link_config (%08x)" + " fw_seq (%08x)\n", + bp->hw_config, bp->serdes_config, bp->lane_config, + bp->ext_phy_config, bp->speed_cap_mask, + bp->link_config, bp->fw_seq); + + switch_cfg = (bp->link_config & PORT_FEATURE_CONNECTED_SWITCH_MASK); + bnx2x_link_settings_supported(bp, switch_cfg); + + bp->autoneg = (bp->hw_config & SHARED_HW_CFG_AN_ENABLE_MASK); + /* for now disable cl73 */ + bp->autoneg &= ~SHARED_HW_CFG_AN_ENABLE_CL73; + BNX2X_DEV_INFO("autoneg 0x%x\n", bp->autoneg); + + bnx2x_link_settings_requested(bp); + + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); + bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff); + bp->dev->dev_addr[1] = (u8)(val2 & 0xff); + bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff); + bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff); + bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff); + bp->dev->dev_addr[5] = (u8)(val & 0xff); + + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6); + + + val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num); + val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]); + val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]); + val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]); + + printk(KERN_INFO PFX "part number %X-%X-%X-%X\n", + val, val2, val3, val4); + + /* bc ver */ + if (!nomcp) { + bp->bc_ver = val = ((SHMEM_RD(bp, dev_info.bc_rev)) >> 8); + BNX2X_DEV_INFO("bc_ver %X\n", val); + if (val < BNX2X_BC_VER) { + /* for now only warn + * later we might need to enforce this */ + BNX2X_ERR("This driver needs bc_ver %X but found %X," + " please upgrade BC\n", BNX2X_BC_VER, val); + } + } else { + bp->bc_ver = 0; + } + + val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4); + bp->flash_size = (NVRAM_1MB_SIZE << (val & MCPR_NVM_CFG4_FLASH_SIZE)); + BNX2X_DEV_INFO("flash_size 0x%x (%d)\n", + bp->flash_size, bp->flash_size); + + return; + +set_mac: /* only supposed to happen on emulation/FPGA */ + BNX2X_ERR("warning constant MAC workaround active\n"); + bp->dev->dev_addr[0] = 0; + bp->dev->dev_addr[1] = 0x50; + bp->dev->dev_addr[2] = 0xc2; + bp->dev->dev_addr[3] = 0x2c; + bp->dev->dev_addr[4] = 0x71; + bp->dev->dev_addr[5] = port ? 0x0d : 0x0e; + + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, 6); + +} + +/* + * ethtool service functions + */ + +/* All ethtool functions called with rtnl_lock */ + +static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + + cmd->supported = bp->supported; + cmd->advertising = bp->advertising; + + if (netif_carrier_ok(dev)) { + cmd->speed = bp->line_speed; + cmd->duplex = bp->duplex; + } else { + cmd->speed = bp->req_line_speed; + cmd->duplex = bp->req_duplex; + } + + if (bp->phy_flags & PHY_XGXS_FLAG) { + cmd->port = PORT_FIBRE; + } else { + cmd->port = PORT_TP; + } + + cmd->phy_address = bp->phy_addr; + cmd->transceiver = XCVR_INTERNAL; + + if (bp->req_autoneg & AUTONEG_SPEED) { + cmd->autoneg = AUTONEG_ENABLE; + } else { + cmd->autoneg = AUTONEG_DISABLE; + } + + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + + DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" + DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + return 0; +} + +static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 advertising; + + DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %d\n" + DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" + DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, cmd->speed, + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + switch (cmd->port) { + case PORT_TP: + if (!(bp->supported & SUPPORTED_TP)) + return -EINVAL; + + if (bp->phy_flags & PHY_XGXS_FLAG) { + bnx2x_link_reset(bp); + bnx2x_link_settings_supported(bp, SWITCH_CFG_1G); + bnx2x_phy_deassert(bp); + } + break; + + case PORT_FIBRE: + if (!(bp->supported & SUPPORTED_FIBRE)) + return -EINVAL; + + if (!(bp->phy_flags & PHY_XGXS_FLAG)) { + bnx2x_link_reset(bp); + bnx2x_link_settings_supported(bp, SWITCH_CFG_10G); + bnx2x_phy_deassert(bp); + } + break; + + default: + return -EINVAL; + } + + if (cmd->autoneg == AUTONEG_ENABLE) { + if (!(bp->supported & SUPPORTED_Autoneg)) + return -EINVAL; + + /* advertise the requested speed and duplex if supported */ + cmd->advertising &= bp->supported; + + bp->req_autoneg |= AUTONEG_SPEED; + bp->req_line_speed = 0; + bp->req_duplex = DUPLEX_FULL; + bp->advertising |= (ADVERTISED_Autoneg | cmd->advertising); + + } else { /* forced speed */ + /* advertise the requested speed and duplex if supported */ + switch (cmd->speed) { + case SPEED_10: + if (cmd->duplex == DUPLEX_FULL) { + if (!(bp->supported & SUPPORTED_10baseT_Full)) + return -EINVAL; + + advertising = (ADVERTISED_10baseT_Full | + ADVERTISED_TP); + } else { + if (!(bp->supported & SUPPORTED_10baseT_Half)) + return -EINVAL; + + advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_TP); + } + break; + + case SPEED_100: + if (cmd->duplex == DUPLEX_FULL) { + if (!(bp->supported & + SUPPORTED_100baseT_Full)) + return -EINVAL; + + advertising = (ADVERTISED_100baseT_Full | + ADVERTISED_TP); + } else { + if (!(bp->supported & + SUPPORTED_100baseT_Half)) + return -EINVAL; + + advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_TP); + } + break; + + case SPEED_1000: + if (cmd->duplex != DUPLEX_FULL) + return -EINVAL; + + if (!(bp->supported & SUPPORTED_1000baseT_Full)) + return -EINVAL; + + advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); + break; + + case SPEED_2500: + if (cmd->duplex != DUPLEX_FULL) + return -EINVAL; + + if (!(bp->supported & SUPPORTED_2500baseT_Full)) + return -EINVAL; + + advertising = (ADVERTISED_2500baseT_Full | + ADVERTISED_TP); + break; + + case SPEED_10000: + if (cmd->duplex != DUPLEX_FULL) + return -EINVAL; + + if (!(bp->supported & SUPPORTED_10000baseT_Full)) + return -EINVAL; + + advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + break; + + default: + return -EINVAL; + } + + bp->req_autoneg &= ~AUTONEG_SPEED; + bp->req_line_speed = cmd->speed; + bp->req_duplex = cmd->duplex; + bp->advertising = advertising; + } + + DP(NETIF_MSG_LINK, "req_autoneg 0x%x req_line_speed %d\n" + DP_LEVEL " req_duplex %d advertising 0x%x\n", + bp->req_autoneg, bp->req_line_speed, bp->req_duplex, + bp->advertising); + + bnx2x_stop_stats(bp); + bnx2x_link_initialize(bp); + + return 0; +} + +static void bnx2x_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bnx2x *bp = netdev_priv(dev); + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + snprintf(info->fw_version, 32, "%d.%d.%d:%d (BC VER %x)", + BCM_5710_FW_MAJOR_VERSION, BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, BCM_5710_FW_COMPILE_FLAGS, + bp->bc_ver); + strcpy(info->bus_info, pci_name(bp->pdev)); + info->n_stats = BNX2X_NUM_STATS; + info->testinfo_len = BNX2X_NUM_TESTS; + info->eedump_len = bp->flash_size; + info->regdump_len = 0; +} + +static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->flags & NO_WOL_FLAG) { + wol->supported = 0; + wol->wolopts = 0; + } else { + wol->supported = WAKE_MAGIC; + if (bp->wol) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; + } + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) { + if (bp->flags & NO_WOL_FLAG) + return -EINVAL; + + bp->wol = 1; + } else { + bp->wol = 0; + } + return 0; +} + +static u32 bnx2x_get_msglevel(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->msglevel; +} + +static void bnx2x_set_msglevel(struct net_device *dev, u32 level) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (capable(CAP_NET_ADMIN)) + bp->msglevel = level; +} + +static int bnx2x_nway_reset(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state); + return -EAGAIN; + } + + bnx2x_stop_stats(bp); + bnx2x_link_initialize(bp); + + return 0; +} + +static int bnx2x_get_eeprom_len(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->flash_size; +} + +static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) +{ + int port = bp->port; + int count, i; + u32 val = 0; + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* request access to nvram interface */ + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port)); + + for (i = 0; i < count*10; i++) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); + if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) + break; + + udelay(5); + } + + if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) { + DP(NETIF_MSG_NVM, "cannot get access to nvram interface\n"); + return -EBUSY; + } + + return 0; +} + +static int bnx2x_release_nvram_lock(struct bnx2x *bp) +{ + int port = bp->port; + int count, i; + u32 val = 0; + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* relinquish nvram interface */ + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port)); + + for (i = 0; i < count*10; i++) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); + if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) + break; + + udelay(5); + } + + if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) { + DP(NETIF_MSG_NVM, "cannot free access to nvram interface\n"); + return -EBUSY; + } + + return 0; +} + +static void bnx2x_enable_nvram_access(struct bnx2x *bp) +{ + u32 val; + + val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); + + /* enable both bits, even on read */ + REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, + (val | MCPR_NVM_ACCESS_ENABLE_EN | + MCPR_NVM_ACCESS_ENABLE_WR_EN)); +} + +static void bnx2x_disable_nvram_access(struct bnx2x *bp) +{ + u32 val; + + val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); + + /* disable both bits, even after read */ + REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, + (val & ~(MCPR_NVM_ACCESS_ENABLE_EN | + MCPR_NVM_ACCESS_ENABLE_WR_EN))); +} + +static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, u32 *ret_val, + u32 cmd_flags) +{ + int rc; + int count, i; + u32 val; + + /* build the command word */ + cmd_flags |= MCPR_NVM_COMMAND_DOIT; + + /* need to clear DONE bit separately */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); + + /* address of the NVRAM to read from */ + REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, + (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); + + /* issue a read command */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* wait for completion */ + *ret_val = 0; + rc = -EBUSY; + for (i = 0; i < count; i++) { + udelay(5); + val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); + + if (val & MCPR_NVM_COMMAND_DONE) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_READ); + DP(NETIF_MSG_NVM, "val 0x%08x\n", val); + /* we read nvram data in cpu order + * but ethtool sees it as an array of bytes + * converting to big-endian will do the work */ + val = cpu_to_be32(val); + *ret_val = val; + rc = 0; + break; + } + } + + return rc; +} + +static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 val; + + if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { + DP(NETIF_MSG_NVM, + "Invalid paramter: offset 0x%x buf_size 0x%x\n", + offset, buf_size); + return -EINVAL; + } + + if (offset + buf_size > bp->flash_size) { + DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + /* read the first word(s) */ + cmd_flags = MCPR_NVM_COMMAND_FIRST; + while ((buf_size > sizeof(u32)) && (rc == 0)) { + rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); + memcpy(ret_buf, &val, 4); + + /* advance to the next dword */ + offset += sizeof(u32); + ret_buf += sizeof(u32); + buf_size -= sizeof(u32); + cmd_flags = 0; + } + + if (rc == 0) { + cmd_flags |= MCPR_NVM_COMMAND_LAST; + rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); + memcpy(ret_buf, &val, 4); + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *eebuf) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc; + + DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, + eeprom->len, eeprom->len); + + /* parameters already validated in ethtool_get_eeprom */ + + rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); + + return rc; +} + +static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val, + u32 cmd_flags) +{ + int rc; + int count, i; + + /* build the command word */ + cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR; + + /* need to clear DONE bit separately */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); + + /* write the data */ + REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val); + + /* address of the NVRAM to write to */ + REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, + (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); + + /* issue the write command */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); + + /* adjust timeout for emulation/FPGA */ + count = NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* wait for completion */ + rc = -EBUSY; + for (i = 0; i < count; i++) { + udelay(5); + val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); + if (val & MCPR_NVM_COMMAND_DONE) { + rc = 0; + break; + } + } + + return rc; +} + +#define BYTE_OFFSET(offset) (8 * (offset & 0x03)) + +static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 align_offset; + u32 val; + + if (offset + buf_size > bp->flash_size) { + DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST); + align_offset = (offset & ~0x03); + rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags); + + if (rc == 0) { + val &= ~(0xff << BYTE_OFFSET(offset)); + val |= (*data_buf << BYTE_OFFSET(offset)); + + /* nvram data is returned as an array of bytes + * convert it back to cpu order */ + val = be32_to_cpu(val); + + DP(NETIF_MSG_NVM, "val 0x%08x\n", val); + + rc = bnx2x_nvram_write_dword(bp, align_offset, val, + cmd_flags); + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 val; + u32 written_so_far; + + if (buf_size == 1) { /* ethtool */ + return bnx2x_nvram_write1(bp, offset, data_buf, buf_size); + } + + if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { + DP(NETIF_MSG_NVM, + "Invalid paramter: offset 0x%x buf_size 0x%x\n", + offset, buf_size); + return -EINVAL; + } + + if (offset + buf_size > bp->flash_size) { + DP(NETIF_MSG_NVM, "Invalid paramter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + written_so_far = 0; + cmd_flags = MCPR_NVM_COMMAND_FIRST; + while ((written_so_far < buf_size) && (rc == 0)) { + if (written_so_far == (buf_size - sizeof(u32))) + cmd_flags |= MCPR_NVM_COMMAND_LAST; + else if (((offset + 4) % NVRAM_PAGE_SIZE) == 0) + cmd_flags |= MCPR_NVM_COMMAND_LAST; + else if ((offset % NVRAM_PAGE_SIZE) == 0) + cmd_flags |= MCPR_NVM_COMMAND_FIRST; + + memcpy(&val, data_buf, 4); + DP(NETIF_MSG_NVM, "val 0x%08x\n", val); + + rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags); + + /* advance to the next dword */ + offset += sizeof(u32); + data_buf += sizeof(u32); + written_so_far += sizeof(u32); + cmd_flags = 0; + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *eebuf) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc; + + DP(NETIF_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, + eeprom->len, eeprom->len); + + /* parameters already validated in ethtool_set_eeprom */ + + rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); + + return rc; +} + +static int bnx2x_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct bnx2x *bp = netdev_priv(dev); + + memset(coal, 0, sizeof(struct ethtool_coalesce)); + + coal->rx_coalesce_usecs = bp->rx_ticks; + coal->tx_coalesce_usecs = bp->tx_ticks; + coal->stats_block_coalesce_usecs = bp->stats_ticks; + + return 0; +} + +static int bnx2x_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->rx_ticks = (u16) coal->rx_coalesce_usecs; + if (bp->rx_ticks > 3000) + bp->rx_ticks = 3000; + + bp->tx_ticks = (u16) coal->tx_coalesce_usecs; + if (bp->tx_ticks > 0x3000) + bp->tx_ticks = 0x3000; + + bp->stats_ticks = coal->stats_block_coalesce_usecs; + if (bp->stats_ticks > 0xffff00) + bp->stats_ticks = 0xffff00; + bp->stats_ticks &= 0xffff00; + + if (netif_running(bp->dev)) + bnx2x_update_coalesce(bp); + + return 0; +} + +static void bnx2x_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct bnx2x *bp = netdev_priv(dev); + + ering->rx_max_pending = MAX_RX_AVAIL; + ering->rx_mini_max_pending = 0; + ering->rx_jumbo_max_pending = 0; + + ering->rx_pending = bp->rx_ring_size; + ering->rx_mini_pending = 0; + ering->rx_jumbo_pending = 0; + + ering->tx_max_pending = MAX_TX_AVAIL; + ering->tx_pending = bp->tx_ring_size; +} + +static int bnx2x_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct bnx2x *bp = netdev_priv(dev); + + if ((ering->rx_pending > MAX_RX_AVAIL) || + (ering->tx_pending > MAX_TX_AVAIL) || + (ering->tx_pending <= MAX_SKB_FRAGS + 4)) + return -EINVAL; + + bp->rx_ring_size = ering->rx_pending; + bp->tx_ring_size = ering->tx_pending; + + if (netif_running(bp->dev)) { + bnx2x_nic_unload(bp, 0); + bnx2x_nic_load(bp, 0); + } + + return 0; +} + +static void bnx2x_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct bnx2x *bp = netdev_priv(dev); + + epause->autoneg = + ((bp->req_autoneg & AUTONEG_FLOW_CTRL) == AUTONEG_FLOW_CTRL); + epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) == FLOW_CTRL_RX); + epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) == FLOW_CTRL_TX); + + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" + DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", + epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); +} + +static int bnx2x_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct bnx2x *bp = netdev_priv(dev); + + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" + DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", + epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); + + bp->req_flow_ctrl = FLOW_CTRL_AUTO; + if (epause->autoneg) { + bp->req_autoneg |= AUTONEG_FLOW_CTRL; + if (bp->dev->mtu <= 4500) { + bp->pause_mode = PAUSE_BOTH; + bp->advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + } else { + bp->pause_mode = PAUSE_ASYMMETRIC; + bp->advertising |= ADVERTISED_Asym_Pause; + } + + } else { + bp->req_autoneg &= ~AUTONEG_FLOW_CTRL; + + if (epause->rx_pause) + bp->req_flow_ctrl |= FLOW_CTRL_RX; + if (epause->tx_pause) + bp->req_flow_ctrl |= FLOW_CTRL_TX; + + switch (bp->req_flow_ctrl) { + case FLOW_CTRL_AUTO: + bp->req_flow_ctrl = FLOW_CTRL_NONE; + bp->pause_mode = PAUSE_NONE; + bp->advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + + case FLOW_CTRL_TX: + bp->pause_mode = PAUSE_ASYMMETRIC; + bp->advertising |= ADVERTISED_Asym_Pause; + break; + + case FLOW_CTRL_RX: + case FLOW_CTRL_BOTH: + bp->pause_mode = PAUSE_BOTH; + bp->advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + break; + } + } + + DP(NETIF_MSG_LINK, "req_autoneg 0x%x req_flow_ctrl 0x%x\n" + DP_LEVEL " pause_mode %d advertising 0x%x\n", + bp->req_autoneg, bp->req_flow_ctrl, bp->pause_mode, + bp->advertising); + + bnx2x_stop_stats(bp); + bnx2x_link_initialize(bp); + + return 0; +} + +static u32 bnx2x_get_rx_csum(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->rx_csum; +} + +static int bnx2x_set_rx_csum(struct net_device *dev, u32 data) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->rx_csum = data; + return 0; +} + +static int bnx2x_set_tso(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN); + else + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN); + return 0; +} + +static struct { + char string[ETH_GSTRING_LEN]; +} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { + { "MC Errors (online)" } +}; + +static int bnx2x_self_test_count(struct net_device *dev) +{ + return BNX2X_NUM_TESTS; +} + +static void bnx2x_self_test(struct net_device *dev, + struct ethtool_test *etest, u64 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + int stats_state; + + memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS); + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_PROBE, "state is %x, returning\n", bp->state); + return; + } + + stats_state = bp->stats_state; + bnx2x_stop_stats(bp); + + if (bnx2x_mc_assert(bp) != 0) { + buf[0] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + +#ifdef BNX2X_EXTRA_DEBUG + bnx2x_panic_dump(bp); +#endif + bp->stats_state = stats_state; +} + +static struct { + char string[ETH_GSTRING_LEN]; +} bnx2x_stats_str_arr[BNX2X_NUM_STATS] = { + { "rx_bytes"}, /* 0 */ + { "rx_error_bytes"}, /* 1 */ + { "tx_bytes"}, /* 2 */ + { "tx_error_bytes"}, /* 3 */ + { "rx_ucast_packets"}, /* 4 */ + { "rx_mcast_packets"}, /* 5 */ + { "rx_bcast_packets"}, /* 6 */ + { "tx_ucast_packets"}, /* 7 */ + { "tx_mcast_packets"}, /* 8 */ + { "tx_bcast_packets"}, /* 9 */ + { "tx_mac_errors"}, /* 10 */ + { "tx_carrier_errors"}, /* 11 */ + { "rx_crc_errors"}, /* 12 */ + { "rx_align_errors"}, /* 13 */ + { "tx_single_collisions"}, /* 14 */ + { "tx_multi_collisions"}, /* 15 */ + { "tx_deferred"}, /* 16 */ + { "tx_excess_collisions"}, /* 17 */ + { "tx_late_collisions"}, /* 18 */ + { "tx_total_collisions"}, /* 19 */ + { "rx_fragments"}, /* 20 */ + { "rx_jabbers"}, /* 21 */ + { "rx_undersize_packets"}, /* 22 */ + { "rx_oversize_packets"}, /* 23 */ + { "rx_xon_frames"}, /* 24 */ + { "rx_xoff_frames"}, /* 25 */ + { "tx_xon_frames"}, /* 26 */ + { "tx_xoff_frames"}, /* 27 */ + { "rx_mac_ctrl_frames"}, /* 28 */ + { "rx_filtered_packets"}, /* 29 */ + { "rx_discards"}, /* 30 */ +}; + +#define STATS_OFFSET32(offset_name) \ + (offsetof(struct bnx2x_eth_stats, offset_name) / 4) + +static unsigned long bnx2x_stats_offset_arr[BNX2X_NUM_STATS] = { + STATS_OFFSET32(total_bytes_received_hi), /* 0 */ + STATS_OFFSET32(stat_IfHCInBadOctets_hi), /* 1 */ + STATS_OFFSET32(total_bytes_transmitted_hi), /* 2 */ + STATS_OFFSET32(stat_IfHCOutBadOctets_hi), /* 3 */ + STATS_OFFSET32(total_unicast_packets_received_hi), /* 4 */ + STATS_OFFSET32(total_multicast_packets_received_hi), /* 5 */ + STATS_OFFSET32(total_broadcast_packets_received_hi), /* 6 */ + STATS_OFFSET32(total_unicast_packets_transmitted_hi), /* 7 */ + STATS_OFFSET32(total_multicast_packets_transmitted_hi), /* 8 */ + STATS_OFFSET32(total_broadcast_packets_transmitted_hi), /* 9 */ + STATS_OFFSET32(stat_Dot3statsInternalMacTransmitErrors), /* 10 */ + STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors), /* 11 */ + STATS_OFFSET32(crc_receive_errors), /* 12 */ + STATS_OFFSET32(alignment_errors), /* 13 */ + STATS_OFFSET32(single_collision_transmit_frames), /* 14 */ + STATS_OFFSET32(multiple_collision_transmit_frames), /* 15 */ + STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions), /* 16 */ + STATS_OFFSET32(excessive_collision_frames), /* 17 */ + STATS_OFFSET32(late_collision_frames), /* 18 */ + STATS_OFFSET32(number_of_bugs_found_in_stats_spec), /* 19 */ + STATS_OFFSET32(runt_packets_received), /* 20 */ + STATS_OFFSET32(jabber_packets_received), /* 21 */ + STATS_OFFSET32(error_runt_packets_received), /* 22 */ + STATS_OFFSET32(error_jabber_packets_received), /* 23 */ + STATS_OFFSET32(pause_xon_frames_received), /* 24 */ + STATS_OFFSET32(pause_xoff_frames_received), /* 25 */ + STATS_OFFSET32(pause_xon_frames_transmitted), /* 26 */ + STATS_OFFSET32(pause_xoff_frames_transmitted), /* 27 */ + STATS_OFFSET32(control_frames_received), /* 28 */ + STATS_OFFSET32(mac_filter_discard), /* 29 */ + STATS_OFFSET32(no_buff_discard), /* 30 */ +}; + +static u8 bnx2x_stats_len_arr[BNX2X_NUM_STATS] = { + 8, 0, 8, 0, 8, 8, 8, 8, 8, 8, + 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, +}; + +static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(buf, bnx2x_stats_str_arr, sizeof(bnx2x_stats_str_arr)); + break; + + case ETH_SS_TEST: + memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr)); + break; + } +} + +static int bnx2x_get_stats_count(struct net_device *dev) +{ + return BNX2X_NUM_STATS; +} + +static void bnx2x_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 *hw_stats = (u32 *)bnx2x_sp_check(bp, eth_stats); + int i; + + for (i = 0; i < BNX2X_NUM_STATS; i++) { + if (bnx2x_stats_len_arr[i] == 0) { + /* skip this counter */ + buf[i] = 0; + continue; + } + if (!hw_stats) { + buf[i] = 0; + continue; + } + if (bnx2x_stats_len_arr[i] == 4) { + /* 4-byte counter */ + buf[i] = (u64) *(hw_stats + bnx2x_stats_offset_arr[i]); + continue; + } + /* 8-byte counter */ + buf[i] = HILO_U64(*(hw_stats + bnx2x_stats_offset_arr[i]), + *(hw_stats + bnx2x_stats_offset_arr[i] + 1)); + } +} + +static int bnx2x_phys_id(struct net_device *dev, u32 data) +{ + struct bnx2x *bp = netdev_priv(dev); + int i; + + if (data == 0) + data = 2; + + for (i = 0; i < (data * 2); i++) { + if ((i % 2) == 0) { + bnx2x_leds_set(bp, SPEED_1000); + } else { + bnx2x_leds_unset(bp); + } + msleep_interruptible(500); + if (signal_pending(current)) + break; + } + + if (bp->link_up) + bnx2x_leds_set(bp, bp->line_speed); + + return 0; +} + +static struct ethtool_ops bnx2x_ethtool_ops = { + .get_settings = bnx2x_get_settings, + .set_settings = bnx2x_set_settings, + .get_drvinfo = bnx2x_get_drvinfo, + .get_wol = bnx2x_get_wol, + .set_wol = bnx2x_set_wol, + .get_msglevel = bnx2x_get_msglevel, + .set_msglevel = bnx2x_set_msglevel, + .nway_reset = bnx2x_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = bnx2x_get_eeprom_len, + .get_eeprom = bnx2x_get_eeprom, + .set_eeprom = bnx2x_set_eeprom, + .get_coalesce = bnx2x_get_coalesce, + .set_coalesce = bnx2x_set_coalesce, + .get_ringparam = bnx2x_get_ringparam, + .set_ringparam = bnx2x_set_ringparam, + .get_pauseparam = bnx2x_get_pauseparam, + .set_pauseparam = bnx2x_set_pauseparam, + .get_rx_csum = bnx2x_get_rx_csum, + .set_rx_csum = bnx2x_set_rx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = bnx2x_set_tso, + .self_test_count = bnx2x_self_test_count, + .self_test = bnx2x_self_test, + .get_strings = bnx2x_get_strings, + .phys_id = bnx2x_phys_id, + .get_stats_count = bnx2x_get_stats_count, + .get_ethtool_stats = bnx2x_get_ethtool_stats +}; + +/* end of ethtool_ops */ + +/**************************************************************************** +* General service functions +****************************************************************************/ + +static int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) +{ + u16 pmcsr; + + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr); + + switch (state) { + case PCI_D0: + pci_write_config_word(bp->pdev, + bp->pm_cap + PCI_PM_CTRL, + ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) | + PCI_PM_CTRL_PME_STATUS)); + + if (pmcsr & PCI_PM_CTRL_STATE_MASK) + /* delay required during transition out of D3hot */ + msleep(20); + break; + + case PCI_D3hot: + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= 3; + + if (bp->wol) + pmcsr |= PCI_PM_CTRL_PME_ENABLE; + + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, + pmcsr); + + /* No more memory access after this point until + * device is brought back to D0. + */ + break; + + default: + return -EINVAL; + } + return 0; +} + +/* + * net_device service functions + */ + +/* Called with rtnl_lock from vlan functions and also netif_tx_lock + * from set_multicast. + */ +static void bnx2x_set_rx_mode(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 rx_mode = BNX2X_RX_MODE_NORMAL; + + DP(NETIF_MSG_IFUP, "called dev->flags = %x\n", dev->flags); + + if (dev->flags & IFF_PROMISC) + rx_mode = BNX2X_RX_MODE_PROMISC; + + else if ((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > BNX2X_MAX_MULTICAST)) + rx_mode = BNX2X_RX_MODE_ALLMULTI; + + else { /* some multicasts */ + int i, old, offset; + struct dev_mc_list *mclist; + struct mac_configuration_cmd *config = + bnx2x_sp(bp, mcast_config); + + for (i = 0, mclist = dev->mc_list; + mclist && (i < dev->mc_count); + i++, mclist = mclist->next) { + + config->config_table[i].cam_entry.msb_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[0]); + config->config_table[i].cam_entry.middle_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[2]); + config->config_table[i].cam_entry.lsb_mac_addr = + swab16(*(u16 *)&mclist->dmi_addr[4]); + config->config_table[i].cam_entry.flags = + cpu_to_le16(bp->port); + config->config_table[i].target_table_entry.flags = 0; + config->config_table[i].target_table_entry. + client_id = 0; + config->config_table[i].target_table_entry. + vlan_id = 0; + + DP(NETIF_MSG_IFUP, + "setting MCAST[%d] (%04x:%04x:%04x)\n", + i, config->config_table[i].cam_entry.msb_mac_addr, + config->config_table[i].cam_entry.middle_mac_addr, + config->config_table[i].cam_entry.lsb_mac_addr); + } + old = config->hdr.length_6b; + if (old > i) { + for (; i < old; i++) { + if (CAM_IS_INVALID(config->config_table[i])) { + i--; /* already invalidated */ + break; + } + /* invalidate */ + CAM_INVALIDATE(config->config_table[i]); + } + } + + if (CHIP_REV_IS_SLOW(bp)) + offset = BNX2X_MAX_EMUL_MULTI*(1 + bp->port); + else + offset = BNX2X_MAX_MULTICAST*(1 + bp->port); + + config->hdr.length_6b = i; + config->hdr.offset = offset; + config->hdr.reserved0 = 0; + config->hdr.reserved1 = 0; + + bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0, + U64_HI(bnx2x_sp_mapping(bp, mcast_config)), + U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0); + } + + bp->rx_mode = rx_mode; + bnx2x_set_storm_rx_mode(bp); +} + +static int bnx2x_poll(struct napi_struct *napi, int budget) +{ + struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath, + napi); + struct bnx2x *bp = fp->bp; + int work_done = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + goto out_panic; +#endif + + prefetch(fp->tx_buf_ring[TX_BD(fp->tx_pkt_cons)].skb); + prefetch(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb); + prefetch((char *)(fp->rx_buf_ring[RX_BD(fp->rx_bd_cons)].skb) + 256); + + bnx2x_update_fpsb_idx(fp); + + if (le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons) + bnx2x_tx_int(fp, budget); + + + if (le16_to_cpu(*fp->rx_cons_sb) != fp->rx_comp_cons) + work_done = bnx2x_rx_int(fp, budget); + + + rmb(); /* bnx2x_has_work() reads the status block */ + + /* must not complete if we consumed full budget */ + if ((work_done < budget) && !bnx2x_has_work(fp)) { + +#ifdef BNX2X_STOP_ON_ERROR +out_panic: +#endif + netif_rx_complete(bp->dev, napi); + + bnx2x_ack_sb(bp, fp->index, USTORM_ID, + le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, fp->index, CSTORM_ID, + le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1); + } + + return work_done; +} + +/* Called with netif_tx_lock. + * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call + * netif_wake_queue(). + */ +static int bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + struct bnx2x_fastpath *fp; + struct sw_tx_bd *tx_buf; + struct eth_tx_bd *tx_bd; + struct eth_tx_parse_bd *pbd = NULL; + u16 pkt_prod, bd_prod; + int nbd, fp_index = 0; + dma_addr_t mapping; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return NETDEV_TX_BUSY; +#endif + + fp_index = smp_processor_id() % (bp->num_queues); + + fp = &bp->fp[fp_index]; + if (unlikely(bnx2x_tx_avail(bp->fp) < + (skb_shinfo(skb)->nr_frags + 3))) { + bp->slowpath->eth_stats.driver_xoff++, + netif_stop_queue(dev); + BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + /* + This is a bit ugly. First we use one BD which we mark as start, + then for TSO or xsum we have a parsing info BD, + and only then we have the rest of the TSO bds. + (don't forget to mark the last one as last, + and to unmap only AFTER you write to the BD ...) + I would like to thank DovH for this mess. + */ + + pkt_prod = fp->tx_pkt_prod++; + bd_prod = fp->tx_bd_prod; + bd_prod = TX_BD(bd_prod); + + /* get a tx_buff and first bd */ + tx_buf = &fp->tx_buf_ring[TX_BD(pkt_prod)]; + tx_bd = &fp->tx_desc_ring[bd_prod]; + + tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + tx_bd->general_data = (UNICAST_ADDRESS << + ETH_TX_BD_ETH_ADDR_TYPE_SHIFT); + tx_bd->general_data |= 1; /* header nbd */ + + /* remeber the first bd of the packet */ + tx_buf->first_bd = bd_prod; + + DP(NETIF_MSG_TX_QUEUED, + "sending pkt %u @%p next_idx %u bd %u @%p\n", + pkt_prod, tx_buf, fp->tx_pkt_prod, bd_prod, tx_bd); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + struct iphdr *iph = ip_hdr(skb); + u8 len; + + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IP_CSUM; + + /* turn on parsing and get a bd */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + pbd = (void *)&fp->tx_desc_ring[bd_prod]; + len = ((u8 *)iph - (u8 *)skb->data) / 2; + + /* for now NS flag is not used in Linux */ + pbd->global_data = (len | + ((skb->protocol == ETH_P_8021Q) << + ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT)); + pbd->ip_hlen = ip_hdrlen(skb) / 2; + pbd->total_hlen = cpu_to_le16(len + pbd->ip_hlen); + if (iph->protocol == IPPROTO_TCP) { + struct tcphdr *th = tcp_hdr(skb); + + tx_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_TCP_CSUM; + pbd->tcp_flags = htonl(tcp_flag_word(skb)) & 0xFFFF; + pbd->total_hlen += cpu_to_le16(tcp_hdrlen(skb) / 2); + pbd->tcp_pseudo_csum = swab16(th->check); + + } else if (iph->protocol == IPPROTO_UDP) { + struct udphdr *uh = udp_hdr(skb); + + tx_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_TCP_CSUM; + pbd->total_hlen += cpu_to_le16(4); + pbd->global_data |= ETH_TX_PARSE_BD_CS_ANY_FLG; + pbd->cs_offset = 5; /* 10 >> 1 */ + pbd->tcp_pseudo_csum = 0; + /* HW bug: we need to subtract 10 bytes before the + * UDP header from the csum + */ + uh->check = (u16) ~csum_fold(csum_sub(uh->check, + csum_partial(((u8 *)(uh)-10), 10, 0))); + } + } + + if ((bp->vlgrp != NULL) && vlan_tx_tag_present(skb)) { + tx_bd->vlan = cpu_to_le16(vlan_tx_tag_get(skb)); + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_VLAN_TAG; + } else { + tx_bd->vlan = cpu_to_le16(pkt_prod); + } + + mapping = pci_map_single(bp->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + + tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + nbd = skb_shinfo(skb)->nr_frags + ((pbd == NULL)? 1 : 2); + tx_bd->nbd = cpu_to_le16(nbd); + tx_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + + DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d" + " nbytes %d flags %x vlan %u\n", + tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, tx_bd->nbd, + tx_bd->nbytes, tx_bd->bd_flags.as_bitfield, tx_bd->vlan); + + if (skb_shinfo(skb)->gso_size && + (skb->len > (bp->dev->mtu + ETH_HLEN))) { + int hlen = 2 * le32_to_cpu(pbd->total_hlen); + + DP(NETIF_MSG_TX_QUEUED, + "TSO packet len %d hlen %d total len %d tso size %d\n", + skb->len, hlen, skb_headlen(skb), + skb_shinfo(skb)->gso_size); + + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; + + if (tx_bd->nbytes > cpu_to_le16(hlen)) { + /* we split the first bd into headers and data bds + * to ease the pain of our fellow micocode engineers + * we use one mapping for both bds + * So far this has only been observed to happen + * in Other Operating Systems(TM) + */ + + /* first fix first bd */ + nbd++; + tx_bd->nbd = cpu_to_le16(nbd); + tx_bd->nbytes = cpu_to_le16(hlen); + + /* we only print this as an error + * because we don't think this will ever happen. + */ + BNX2X_ERR("TSO split header size is %d (%x:%x)" + " nbd %d\n", tx_bd->nbytes, tx_bd->addr_hi, + tx_bd->addr_lo, tx_bd->nbd); + + /* now get a new data bd + * (after the pbd) and fill it */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + tx_bd = &fp->tx_desc_ring[bd_prod]; + + tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping) + hlen); + tx_bd->nbytes = cpu_to_le16(skb_headlen(skb) - hlen); + tx_bd->vlan = cpu_to_le16(pkt_prod); + /* this marks the bd + * as one that has no individual mapping + * the FW ignors this flag in a bd not maked start + */ + tx_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_SW_LSO; + DP(NETIF_MSG_TX_QUEUED, + "TSO split data size is %d (%x:%x)\n", + tx_bd->nbytes, tx_bd->addr_hi, tx_bd->addr_lo); + } + + if (!pbd) { + /* supposed to be unreached + * (and therefore not handled properly...) + */ + BNX2X_ERR("LSO with no PBD\n"); + BUG(); + } + + pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq); + pbd->ip_id = swab16(ip_hdr(skb)->id); + pbd->tcp_pseudo_csum = + swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0)); + pbd->global_data |= ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN; + } + + { + int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + tx_bd = &fp->tx_desc_ring[bd_prod]; + + mapping = pci_map_page(bp->pdev, frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + + tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_bd->nbytes = cpu_to_le16(frag->size); + tx_bd->vlan = cpu_to_le16(pkt_prod); + tx_bd->bd_flags.as_bitfield = 0; + DP(NETIF_MSG_TX_QUEUED, "frag %d bd @%p" + " addr (%x:%x) nbytes %d flags %x\n", + i, tx_bd, tx_bd->addr_hi, tx_bd->addr_lo, + tx_bd->nbytes, tx_bd->bd_flags.as_bitfield); + } /* for */ + } + + /* now at last mark the bd as the last bd */ + tx_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_END_BD; + + DP(NETIF_MSG_TX_QUEUED, "last bd @%p flags %x\n", + tx_bd, tx_bd->bd_flags.as_bitfield); + + tx_buf->skb = skb; + + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + + /* now send a tx doorbell, counting the next bd + * if the packet contains or ends with it + */ + if (TX_BD_POFF(bd_prod) < nbd) + nbd++; + + if (pbd) + DP(NETIF_MSG_TX_QUEUED, + "PBD @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u" + " tcp_flags %x xsum %x seq %u hlen %u\n", + pbd, pbd->global_data, pbd->ip_hlen, pbd->ip_id, + pbd->lso_mss, pbd->tcp_flags, pbd->tcp_pseudo_csum, + pbd->tcp_send_seq, pbd->total_hlen); + + DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %u bd %d\n", nbd, bd_prod); + + fp->hw_tx_prods->bds_prod += cpu_to_le16(nbd); + mb(); /* FW restriction: must not reorder writing nbd and packets */ + fp->hw_tx_prods->packets_prod += cpu_to_le32(1); + DOORBELL(bp, fp_index, 0); + + mmiowb(); + + fp->tx_bd_prod = bd_prod; + dev->trans_start = jiffies; + + if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { + netif_stop_queue(dev); + bp->slowpath->eth_stats.driver_xoff++; + if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) + netif_wake_queue(dev); + } + fp->tx_pkt++; + + return NETDEV_TX_OK; +} + +static struct net_device_stats *bnx2x_get_stats(struct net_device *dev) +{ + return &dev->stats; +} + +/* Called with rtnl_lock */ +static int bnx2x_open(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + bnx2x_set_power_state(bp, PCI_D0); + + return bnx2x_nic_load(bp, 1); +} + +/* Called with rtnl_lock */ +static int bnx2x_close(struct net_device *dev) +{ + int rc; + struct bnx2x *bp = netdev_priv(dev); + + /* Unload the driver, release IRQs */ + rc = bnx2x_nic_unload(bp, 1); + if (rc) { + BNX2X_ERR("bnx2x_nic_unload failed: %d\n", rc); + return rc; + } + bnx2x_set_power_state(bp, PCI_D3hot); + + return 0; +} + +/* Called with rtnl_lock */ +static int bnx2x_change_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + struct bnx2x *bp = netdev_priv(dev); + + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + if (netif_running(dev)) + bnx2x_set_mac_addr(bp); + + return 0; +} + +/* Called with rtnl_lock */ +static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mii_ioctl_data *data = if_mii(ifr); + struct bnx2x *bp = netdev_priv(dev); + int err; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = bp->phy_addr; + + /* fallthru */ + case SIOCGMIIREG: { + u32 mii_regval; + + spin_lock_bh(&bp->phy_lock); + if (bp->state == BNX2X_STATE_OPEN) { + err = bnx2x_mdio22_read(bp, data->reg_num & 0x1f, + &mii_regval); + + data->val_out = mii_regval; + } else { + err = -EAGAIN; + } + spin_unlock_bh(&bp->phy_lock); + return err; + } + + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_bh(&bp->phy_lock); + if (bp->state == BNX2X_STATE_OPEN) { + err = bnx2x_mdio22_write(bp, data->reg_num & 0x1f, + data->val_in); + } else { + err = -EAGAIN; + } + spin_unlock_bh(&bp->phy_lock); + return err; + + default: + /* do nothing */ + break; + } + + return -EOPNOTSUPP; +} + +/* Called with rtnl_lock */ +static int bnx2x_change_mtu(struct net_device *dev, int new_mtu) +{ + struct bnx2x *bp = netdev_priv(dev); + + if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) || + ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE)) + return -EINVAL; + + /* This does not race with packet allocation + * because the actuall alloc size is + * only updated as part of load + */ + dev->mtu = new_mtu; + + if (netif_running(dev)) { + bnx2x_nic_unload(bp, 0); + bnx2x_nic_load(bp, 0); + } + return 0; +} + +static void bnx2x_tx_timeout(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + +#ifdef BNX2X_STOP_ON_ERROR + if (!bp->panic) + bnx2x_panic(); +#endif + /* This allows the netif to be shutdown gracefully before resetting */ + schedule_work(&bp->reset_task); +} + +#ifdef BCM_VLAN +/* Called with rtnl_lock */ +static void bnx2x_vlan_rx_register(struct net_device *dev, + struct vlan_group *vlgrp) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->vlgrp = vlgrp; + if (netif_running(dev)) + bnx2x_set_rx_mode(dev); +} +#endif + +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) +static void poll_bnx2x(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + disable_irq(bp->pdev->irq); + bnx2x_interrupt(bp->pdev->irq, dev); + enable_irq(bp->pdev->irq); +} +#endif + +static void bnx2x_reset_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, reset_task); + +#ifdef BNX2X_STOP_ON_ERROR + BNX2X_ERR("reset task called but STOP_ON_ERROR defined" + " so reset not done to allow debug dump,\n" + KERN_ERR " you will need to reboot when done\n"); + return; +#endif + + if (!netif_running(bp->dev)) + return; + + bp->in_reset_task = 1; + + bnx2x_netif_stop(bp); + + bnx2x_nic_unload(bp, 0); + bnx2x_nic_load(bp, 0); + + bp->in_reset_task = 0; +} + +static int __devinit bnx2x_init_board(struct pci_dev *pdev, + struct net_device *dev) +{ + struct bnx2x *bp; + int rc; + + SET_NETDEV_DEV(dev, &pdev->dev); + bp = netdev_priv(dev); + + bp->flags = 0; + bp->port = PCI_FUNC(pdev->devfn); + + rc = pci_enable_device(pdev); + if (rc) { + printk(KERN_ERR PFX "Cannot enable PCI device, aborting\n"); + goto err_out; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find PCI device base address," + " aborting\n"); + rc = -ENODEV; + goto err_out_disable; + } + + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "Cannot find second PCI device" + " base address, aborting\n"); + rc = -ENODEV; + goto err_out_disable; + } + + rc = pci_request_regions(pdev, DRV_MODULE_NAME); + if (rc) { + printk(KERN_ERR PFX "Cannot obtain PCI resources," + " aborting\n"); + goto err_out_disable; + } + + pci_set_master(pdev); + + bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (bp->pm_cap == 0) { + printk(KERN_ERR PFX "Cannot find power management" + " capability, aborting\n"); + rc = -EIO; + goto err_out_release; + } + + bp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (bp->pcie_cap == 0) { + printk(KERN_ERR PFX "Cannot find PCI Express capability," + " aborting\n"); + rc = -EIO; + goto err_out_release; + } + + if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { + bp->flags |= USING_DAC_FLAG; + if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) { + printk(KERN_ERR PFX "pci_set_consistent_dma_mask" + " failed, aborting\n"); + rc = -EIO; + goto err_out_release; + } + + } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) { + printk(KERN_ERR PFX "System does not support DMA," + " aborting\n"); + rc = -EIO; + goto err_out_release; + } + + bp->dev = dev; + bp->pdev = pdev; + + spin_lock_init(&bp->phy_lock); + + bp->in_reset_task = 0; + + INIT_WORK(&bp->reset_task, bnx2x_reset_task); + INIT_WORK(&bp->sp_task, bnx2x_sp_task); + + dev->base_addr = pci_resource_start(pdev, 0); + + dev->irq = pdev->irq; + + bp->regview = ioremap_nocache(dev->base_addr, + pci_resource_len(pdev, 0)); + if (!bp->regview) { + printk(KERN_ERR PFX "Cannot map register space, aborting\n"); + rc = -ENOMEM; + goto err_out_release; + } + + bp->doorbells = ioremap_nocache(pci_resource_start(pdev , 2), + pci_resource_len(pdev, 2)); + if (!bp->doorbells) { + printk(KERN_ERR PFX "Cannot map doorbell space, aborting\n"); + rc = -ENOMEM; + goto err_out_unmap; + } + + bnx2x_set_power_state(bp, PCI_D0); + + bnx2x_get_hwinfo(bp); + + if (CHIP_REV(bp) == CHIP_REV_FPGA) { + printk(KERN_ERR PFX "FPGA detacted. MCP disabled," + " will only init first device\n"); + onefunc = 1; + nomcp = 1; + } + + if (nomcp) { + printk(KERN_ERR PFX "MCP disabled, will only" + " init first device\n"); + onefunc = 1; + } + + if (onefunc && bp->port) { + printk(KERN_ERR PFX "Second device disabled, exiting\n"); + rc = -ENODEV; + goto err_out_unmap; + } + + bp->tx_ring_size = MAX_TX_AVAIL; + bp->rx_ring_size = MAX_RX_AVAIL; + + bp->rx_csum = 1; + + bp->rx_offset = 0; + + bp->tx_quick_cons_trip_int = 0xff; + bp->tx_quick_cons_trip = 0xff; + bp->tx_ticks_int = 50; + bp->tx_ticks = 50; + + bp->rx_quick_cons_trip_int = 0xff; + bp->rx_quick_cons_trip = 0xff; + bp->rx_ticks_int = 25; + bp->rx_ticks = 25; + + bp->stats_ticks = 1000000 & 0xffff00; + + bp->timer_interval = HZ; + bp->current_interval = (poll ? poll : HZ); + + init_timer(&bp->timer); + bp->timer.expires = jiffies + bp->current_interval; + bp->timer.data = (unsigned long) bp; + bp->timer.function = bnx2x_timer; + + return 0; + +err_out_unmap: + if (bp->regview) { + iounmap(bp->regview); + bp->regview = NULL; + } + + if (bp->doorbells) { + iounmap(bp->doorbells); + bp->doorbells = NULL; + } + +err_out_release: + pci_release_regions(pdev); + +err_out_disable: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + +err_out: + return rc; +} + +static int __devinit bnx2x_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int version_printed; + struct net_device *dev = NULL; + struct bnx2x *bp; + int rc, i; + int port = PCI_FUNC(pdev->devfn); + + if (version_printed++ == 0) + printk(KERN_INFO "%s", version); + + /* dev zeroed in init_etherdev */ + dev = alloc_etherdev(sizeof(*bp)); + if (!dev) + return -ENOMEM; + + netif_carrier_off(dev); + + bp = netdev_priv(dev); + bp->msglevel = debug; + + if (port && onefunc) { + printk(KERN_ERR PFX "second function disabled. exiting\n"); + return 0; + } + + rc = bnx2x_init_board(pdev, dev); + if (rc < 0) { + free_netdev(dev); + return rc; + } + + dev->hard_start_xmit = bnx2x_start_xmit; + dev->watchdog_timeo = TX_TIMEOUT; + + dev->get_stats = bnx2x_get_stats; + dev->ethtool_ops = &bnx2x_ethtool_ops; + dev->open = bnx2x_open; + dev->stop = bnx2x_close; + dev->set_multicast_list = bnx2x_set_rx_mode; + dev->set_mac_address = bnx2x_change_mac_addr; + dev->do_ioctl = bnx2x_ioctl; + dev->change_mtu = bnx2x_change_mtu; + dev->tx_timeout = bnx2x_tx_timeout; +#ifdef BCM_VLAN + dev->vlan_rx_register = bnx2x_vlan_rx_register; +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + dev->poll_controller = poll_bnx2x; +#endif + dev->features |= NETIF_F_SG; + if (bp->flags & USING_DAC_FLAG) + dev->features |= NETIF_F_HIGHDMA; + dev->features |= NETIF_F_IP_CSUM; +#ifdef BCM_VLAN + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +#endif + dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN; + + rc = register_netdev(dev); + if (rc) { + printk(KERN_ERR PFX "Cannot register net device\n"); + if (bp->regview) + iounmap(bp->regview); + if (bp->doorbells) + iounmap(bp->doorbells); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + free_netdev(dev); + return rc; + } + + pci_set_drvdata(pdev, dev); + + bp->name = board_info[ent->driver_data].name; + printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz " + "found at mem %lx, IRQ %d, ", + dev->name, bp->name, + ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', + ((CHIP_ID(bp) & 0x0ff0) >> 4), + ((bp->flags & PCIX_FLAG) ? "-X" : ""), + ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"), + bp->bus_speed_mhz, + dev->base_addr, + bp->pdev->irq); + + printk("node addr "); + for (i = 0; i < 6; i++) + printk("%2.2x", dev->dev_addr[i]); + printk("\n"); + + return 0; +} + +static void __devexit bnx2x_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + flush_scheduled_work(); + /*tasklet_kill(&bp->sp_task);*/ + unregister_netdev(dev); + + if (bp->regview) + iounmap(bp->regview); + + if (bp->doorbells) + iounmap(bp->doorbells); + + free_netdev(dev); + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + int rc; + + if (!netif_running(dev)) + return 0; + + rc = bnx2x_nic_unload(bp, 0); + if (!rc) + return rc; + + netif_device_detach(dev); + pci_save_state(pdev); + + bnx2x_set_power_state(bp, pci_choose_state(pdev, state)); + return 0; +} + +static int bnx2x_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + int rc; + + if (!netif_running(dev)) + return 0; + + pci_restore_state(pdev); + + bnx2x_set_power_state(bp, PCI_D0); + netif_device_attach(dev); + + rc = bnx2x_nic_load(bp, 0); + if (rc) + return rc; + + return 0; +} + +static struct pci_driver bnx2x_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = bnx2x_pci_tbl, + .probe = bnx2x_init_one, + .remove = __devexit_p(bnx2x_remove_one), + .suspend = bnx2x_suspend, + .resume = bnx2x_resume, +}; + +static int __init bnx2x_init(void) +{ + return pci_register_driver(&bnx2x_pci_driver); +} + +static void __exit bnx2x_cleanup(void) +{ + pci_unregister_driver(&bnx2x_pci_driver); +} + +module_init(bnx2x_init); +module_exit(bnx2x_cleanup); + diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h new file mode 100644 index 000000000000..4f7ae6f77452 --- /dev/null +++ b/drivers/net/bnx2x.h @@ -0,0 +1,1071 @@ +/* bnx2x.h: Broadcom Everest network driver. + * + * Copyright (c) 2007 Broadcom Corporation + * + * 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. + * + * Written by: Eliezer Tamir <eliezert@broadcom.com> + * Based on code from Michael Chan's bnx2 driver + */ + +#ifndef BNX2X_H +#define BNX2X_H + +/* error/debug prints */ + +#define DRV_MODULE_NAME "bnx2x" +#define PFX DRV_MODULE_NAME ": " + +/* for messages that are currently off */ +#define BNX2X_MSG_OFF 0 +#define BNX2X_MSG_MCP 0x10000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_STATS 0x20000 /* was: NETIF_MSG_TIMER */ +#define NETIF_MSG_NVM 0x40000 /* was: NETIF_MSG_HW */ +#define NETIF_MSG_DMAE 0x80000 /* was: NETIF_MSG_HW */ + +#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */ + +/* regular debug print */ +#define DP(__mask, __fmt, __args...) do { \ + if (bp->msglevel & (__mask)) \ + printk(DP_LEVEL "[%s:%d(%s)]" __fmt, __FUNCTION__, \ + __LINE__, bp->dev?(bp->dev->name):"?", ##__args); \ + } while (0) + +/* for errors (never masked) */ +#define BNX2X_ERR(__fmt, __args...) do { \ + printk(KERN_ERR "[%s:%d(%s)]" __fmt, __FUNCTION__, \ + __LINE__, bp->dev?(bp->dev->name):"?", ##__args); \ + } while (0) + +/* before we have a dev->name use dev_info() */ +#define BNX2X_DEV_INFO(__fmt, __args...) do { \ + if (bp->msglevel & NETIF_MSG_PROBE) \ + dev_info(&bp->pdev->dev, __fmt, ##__args); \ + } while (0) + + +#ifdef BNX2X_STOP_ON_ERROR +#define bnx2x_panic() do { \ + bp->panic = 1; \ + BNX2X_ERR("driver assert\n"); \ + bnx2x_disable_int(bp); \ + bnx2x_panic_dump(bp); \ + } while (0) +#else +#define bnx2x_panic() do { \ + BNX2X_ERR("driver assert\n"); \ + bnx2x_panic_dump(bp); \ + } while (0) +#endif + + +#define U64_LO(x) (((u64)x) & 0xffffffff) +#define U64_HI(x) (((u64)x) >> 32) +#define HILO_U64(hi, lo) (((u64)hi << 32) + lo) + + +#define REG_ADDR(bp, offset) (bp->regview + offset) + +#define REG_RD(bp, offset) readl(REG_ADDR(bp, offset)) +#define REG_RD8(bp, offset) readb(REG_ADDR(bp, offset)) +#define REG_RD64(bp, offset) readq(REG_ADDR(bp, offset)) + +#define REG_WR(bp, offset, val) writel((u32)val, REG_ADDR(bp, offset)) +#define REG_WR8(bp, offset, val) writeb((u8)val, REG_ADDR(bp, offset)) +#define REG_WR16(bp, offset, val) writew((u16)val, REG_ADDR(bp, offset)) +#define REG_WR32(bp, offset, val) REG_WR(bp, offset, val) + +#define REG_RD_IND(bp, offset) bnx2x_reg_rd_ind(bp, offset) +#define REG_WR_IND(bp, offset, val) bnx2x_reg_wr_ind(bp, offset, val) + +#define REG_WR_DMAE(bp, offset, val, len32) \ + do { \ + memcpy(bnx2x_sp(bp, wb_data[0]), val, len32 * 4); \ + bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), \ + offset, len32); \ + } while (0) + +#define SHMEM_RD(bp, type) \ + REG_RD(bp, bp->shmem_base + offsetof(struct shmem_region, type)) +#define SHMEM_WR(bp, type, val) \ + REG_WR(bp, bp->shmem_base + offsetof(struct shmem_region, type), val) + +#define NIG_WR(reg, val) REG_WR(bp, reg, val) +#define EMAC_WR(reg, val) REG_WR(bp, emac_base + reg, val) +#define BMAC_WR(reg, val) REG_WR(bp, GRCBASE_NIG + bmac_addr + reg, val) + + +#define for_each_queue(bp, var) for (var = 0; var < bp->num_queues; var++) + +#define for_each_nondefault_queue(bp, var) \ + for (var = 1; var < bp->num_queues; var++) +#define is_multi(bp) (bp->num_queues > 1) + + +struct regp { + u32 lo; + u32 hi; +}; + +struct bmac_stats { + struct regp tx_gtpkt; + struct regp tx_gtxpf; + struct regp tx_gtfcs; + struct regp tx_gtmca; + struct regp tx_gtgca; + struct regp tx_gtfrg; + struct regp tx_gtovr; + struct regp tx_gt64; + struct regp tx_gt127; + struct regp tx_gt255; /* 10 */ + struct regp tx_gt511; + struct regp tx_gt1023; + struct regp tx_gt1518; + struct regp tx_gt2047; + struct regp tx_gt4095; + struct regp tx_gt9216; + struct regp tx_gt16383; + struct regp tx_gtmax; + struct regp tx_gtufl; + struct regp tx_gterr; /* 20 */ + struct regp tx_gtbyt; + + struct regp rx_gr64; + struct regp rx_gr127; + struct regp rx_gr255; + struct regp rx_gr511; + struct regp rx_gr1023; + struct regp rx_gr1518; + struct regp rx_gr2047; + struct regp rx_gr4095; + struct regp rx_gr9216; /* 30 */ + struct regp rx_gr16383; + struct regp rx_grmax; + struct regp rx_grpkt; + struct regp rx_grfcs; + struct regp rx_grmca; + struct regp rx_grbca; + struct regp rx_grxcf; + struct regp rx_grxpf; + struct regp rx_grxuo; + struct regp rx_grjbr; /* 40 */ + struct regp rx_grovr; + struct regp rx_grflr; + struct regp rx_grmeg; + struct regp rx_grmeb; + struct regp rx_grbyt; + struct regp rx_grund; + struct regp rx_grfrg; + struct regp rx_grerb; + struct regp rx_grfre; + struct regp rx_gripj; /* 50 */ +}; + +struct emac_stats { + u32 rx_ifhcinoctets ; + u32 rx_ifhcinbadoctets ; + u32 rx_etherstatsfragments ; + u32 rx_ifhcinucastpkts ; + u32 rx_ifhcinmulticastpkts ; + u32 rx_ifhcinbroadcastpkts ; + u32 rx_dot3statsfcserrors ; + u32 rx_dot3statsalignmenterrors ; + u32 rx_dot3statscarriersenseerrors ; + u32 rx_xonpauseframesreceived ; /* 10 */ + u32 rx_xoffpauseframesreceived ; + u32 rx_maccontrolframesreceived ; + u32 rx_xoffstateentered ; + u32 rx_dot3statsframestoolong ; + u32 rx_etherstatsjabbers ; + u32 rx_etherstatsundersizepkts ; + u32 rx_etherstatspkts64octets ; + u32 rx_etherstatspkts65octetsto127octets ; + u32 rx_etherstatspkts128octetsto255octets ; + u32 rx_etherstatspkts256octetsto511octets ; /* 20 */ + u32 rx_etherstatspkts512octetsto1023octets ; + u32 rx_etherstatspkts1024octetsto1522octets; + u32 rx_etherstatspktsover1522octets ; + + u32 rx_falsecarriererrors ; + + u32 tx_ifhcoutoctets ; + u32 tx_ifhcoutbadoctets ; + u32 tx_etherstatscollisions ; + u32 tx_outxonsent ; + u32 tx_outxoffsent ; + u32 tx_flowcontroldone ; /* 30 */ + u32 tx_dot3statssinglecollisionframes ; + u32 tx_dot3statsmultiplecollisionframes ; + u32 tx_dot3statsdeferredtransmissions ; + u32 tx_dot3statsexcessivecollisions ; + u32 tx_dot3statslatecollisions ; + u32 tx_ifhcoutucastpkts ; + u32 tx_ifhcoutmulticastpkts ; + u32 tx_ifhcoutbroadcastpkts ; + u32 tx_etherstatspkts64octets ; + u32 tx_etherstatspkts65octetsto127octets ; /* 40 */ + u32 tx_etherstatspkts128octetsto255octets ; + u32 tx_etherstatspkts256octetsto511octets ; + u32 tx_etherstatspkts512octetsto1023octets ; + u32 tx_etherstatspkts1024octetsto1522octet ; + u32 tx_etherstatspktsover1522octets ; + u32 tx_dot3statsinternalmactransmiterrors ; /* 46 */ +}; + +union mac_stats { + struct emac_stats emac; + struct bmac_stats bmac; +}; + +struct nig_stats { + u32 brb_discard; + u32 brb_packet; + u32 brb_truncate; + u32 flow_ctrl_discard; + u32 flow_ctrl_octets; + u32 flow_ctrl_packet; + u32 mng_discard; + u32 mng_octet_inp; + u32 mng_octet_out; + u32 mng_packet_inp; + u32 mng_packet_out; + u32 pbf_octets; + u32 pbf_packet; + u32 safc_inp; + u32 done; + u32 pad; +}; + +struct bnx2x_eth_stats { + u32 pad; /* to make long counters u64 aligned */ + u32 mac_stx_start; + u32 total_bytes_received_hi; + u32 total_bytes_received_lo; + u32 total_bytes_transmitted_hi; + u32 total_bytes_transmitted_lo; + u32 total_unicast_packets_received_hi; + u32 total_unicast_packets_received_lo; + u32 total_multicast_packets_received_hi; + u32 total_multicast_packets_received_lo; + u32 total_broadcast_packets_received_hi; + u32 total_broadcast_packets_received_lo; + u32 total_unicast_packets_transmitted_hi; + u32 total_unicast_packets_transmitted_lo; + u32 total_multicast_packets_transmitted_hi; + u32 total_multicast_packets_transmitted_lo; + u32 total_broadcast_packets_transmitted_hi; + u32 total_broadcast_packets_transmitted_lo; + u32 crc_receive_errors; + u32 alignment_errors; + u32 false_carrier_detections; + u32 runt_packets_received; + u32 jabber_packets_received; + u32 pause_xon_frames_received; + u32 pause_xoff_frames_received; + u32 pause_xon_frames_transmitted; + u32 pause_xoff_frames_transmitted; + u32 single_collision_transmit_frames; + u32 multiple_collision_transmit_frames; + u32 late_collision_frames; + u32 excessive_collision_frames; + u32 control_frames_received; + u32 frames_received_64_bytes; + u32 frames_received_65_127_bytes; + u32 frames_received_128_255_bytes; + u32 frames_received_256_511_bytes; + u32 frames_received_512_1023_bytes; + u32 frames_received_1024_1522_bytes; + u32 frames_received_1523_9022_bytes; + u32 frames_transmitted_64_bytes; + u32 frames_transmitted_65_127_bytes; + u32 frames_transmitted_128_255_bytes; + u32 frames_transmitted_256_511_bytes; + u32 frames_transmitted_512_1023_bytes; + u32 frames_transmitted_1024_1522_bytes; + u32 frames_transmitted_1523_9022_bytes; + u32 valid_bytes_received_hi; + u32 valid_bytes_received_lo; + u32 error_runt_packets_received; + u32 error_jabber_packets_received; + u32 mac_stx_end; + + u32 pad2; + u32 stat_IfHCInBadOctets_hi; + u32 stat_IfHCInBadOctets_lo; + u32 stat_IfHCOutBadOctets_hi; + u32 stat_IfHCOutBadOctets_lo; + u32 stat_Dot3statsFramesTooLong; + u32 stat_Dot3statsInternalMacTransmitErrors; + u32 stat_Dot3StatsCarrierSenseErrors; + u32 stat_Dot3StatsDeferredTransmissions; + u32 stat_FlowControlDone; + u32 stat_XoffStateEntered; + + u32 x_total_sent_bytes_hi; + u32 x_total_sent_bytes_lo; + u32 x_total_sent_pkts; + + u32 t_rcv_unicast_bytes_hi; + u32 t_rcv_unicast_bytes_lo; + u32 t_rcv_broadcast_bytes_hi; + u32 t_rcv_broadcast_bytes_lo; + u32 t_rcv_multicast_bytes_hi; + u32 t_rcv_multicast_bytes_lo; + u32 t_total_rcv_pkt; + + u32 checksum_discard; + u32 packets_too_big_discard; + u32 no_buff_discard; + u32 ttl0_discard; + u32 mac_discard; + u32 mac_filter_discard; + u32 xxoverflow_discard; + u32 brb_truncate_discard; + + u32 brb_discard; + u32 brb_packet; + u32 brb_truncate; + u32 flow_ctrl_discard; + u32 flow_ctrl_octets; + u32 flow_ctrl_packet; + u32 mng_discard; + u32 mng_octet_inp; + u32 mng_octet_out; + u32 mng_packet_inp; + u32 mng_packet_out; + u32 pbf_octets; + u32 pbf_packet; + u32 safc_inp; + u32 driver_xoff; + u32 number_of_bugs_found_in_stats_spec; /* just kidding */ +}; + +#define MAC_STX_NA 0xffffffff + +#ifdef BNX2X_MULTI +#define MAX_CONTEXT 16 +#else +#define MAX_CONTEXT 1 +#endif + +union cdu_context { + struct eth_context eth; + char pad[1024]; +}; + +#define MAX_DMAE_C 5 + +/* DMA memory not used in fastpath */ +struct bnx2x_slowpath { + union cdu_context context[MAX_CONTEXT]; + struct eth_stats_query fw_stats; + struct mac_configuration_cmd mac_config; + struct mac_configuration_cmd mcast_config; + + /* used by dmae command executer */ + struct dmae_command dmae[MAX_DMAE_C]; + + union mac_stats mac_stats; + struct nig_stats nig; + struct bnx2x_eth_stats eth_stats; + + u32 wb_comp; +#define BNX2X_WB_COMP_VAL 0xe0d0d0ae + u32 wb_data[4]; +}; + +#define bnx2x_sp(bp, var) (&bp->slowpath->var) +#define bnx2x_sp_check(bp, var) ((bp->slowpath) ? (&bp->slowpath->var) : NULL) +#define bnx2x_sp_mapping(bp, var) \ + (bp->slowpath_mapping + offsetof(struct bnx2x_slowpath, var)) + + +struct sw_rx_bd { + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(mapping) +}; + +struct sw_tx_bd { + struct sk_buff *skb; + u16 first_bd; +}; + +struct bnx2x_fastpath { + + struct napi_struct napi; + + struct host_status_block *status_blk; + dma_addr_t status_blk_mapping; + + struct eth_tx_db_data *hw_tx_prods; + dma_addr_t tx_prods_mapping; + + struct sw_tx_bd *tx_buf_ring; + + struct eth_tx_bd *tx_desc_ring; + dma_addr_t tx_desc_mapping; + + struct sw_rx_bd *rx_buf_ring; + + struct eth_rx_bd *rx_desc_ring; + dma_addr_t rx_desc_mapping; + + union eth_rx_cqe *rx_comp_ring; + dma_addr_t rx_comp_mapping; + + int state; +#define BNX2X_FP_STATE_CLOSED 0 +#define BNX2X_FP_STATE_IRQ 0x80000 +#define BNX2X_FP_STATE_OPENING 0x90000 +#define BNX2X_FP_STATE_OPEN 0xa0000 +#define BNX2X_FP_STATE_HALTING 0xb0000 +#define BNX2X_FP_STATE_HALTED 0xc0000 +#define BNX2X_FP_STATE_DELETED 0xd0000 +#define BNX2X_FP_STATE_CLOSE_IRQ 0xe0000 + + int index; + + u16 tx_pkt_prod; + u16 tx_pkt_cons; + u16 tx_bd_prod; + u16 tx_bd_cons; + u16 *tx_cons_sb; + + u16 fp_c_idx; + u16 fp_u_idx; + + u16 rx_bd_prod; + u16 rx_bd_cons; + u16 rx_comp_prod; + u16 rx_comp_cons; + u16 *rx_cons_sb; + + unsigned long tx_pkt, + rx_pkt, + rx_calls; + + struct bnx2x *bp; /* parent */ +}; + +#define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) + + +/* attn group wiring */ +#define MAX_DYNAMIC_ATTN_GRPS 8 + +struct attn_route { + u32 sig[4]; +}; + +struct bnx2x { + /* Fields used in the tx and intr/napi performance paths + * are grouped together in the beginning of the structure + */ + struct bnx2x_fastpath *fp; + void __iomem *regview; + void __iomem *doorbells; + + struct net_device *dev; + struct pci_dev *pdev; + + atomic_t intr_sem; + struct msix_entry msix_table[MAX_CONTEXT+1]; + + int tx_ring_size; + +#ifdef BCM_VLAN + struct vlan_group *vlgrp; +#endif + + u32 rx_csum; + u32 rx_offset; + u32 rx_buf_use_size; /* useable size */ + u32 rx_buf_size; /* with alignment */ +#define ETH_OVREHEAD (ETH_HLEN + 8) /* 8 for CRC + VLAN */ +#define ETH_MIN_PACKET_SIZE 60 +#define ETH_MAX_PACKET_SIZE 1500 +#define ETH_MAX_JUMBO_PACKET_SIZE 9600 + + struct host_def_status_block *def_status_blk; +#define DEF_SB_ID 16 + u16 def_c_idx; + u16 def_u_idx; + u16 def_t_idx; + u16 def_x_idx; + u16 def_att_idx; + u32 attn_state; + struct attn_route attn_group[MAX_DYNAMIC_ATTN_GRPS]; + u32 aeu_mask; + u32 nig_mask; + + /* slow path ring */ + struct eth_spe *spq; + dma_addr_t spq_mapping; + u16 spq_prod_idx; + u16 dsb_sp_prod_idx; + struct eth_spe *spq_prod_bd; + struct eth_spe *spq_last_bd; + u16 *dsb_sp_prod; + u16 spq_left; /* serialize spq */ + spinlock_t spq_lock; + + /* Flag for marking that there is either + * STAT_QUERY or CFC DELETE ramrod pending + */ + u8 stat_pending; + + /* End of fileds used in the performance code paths */ + + int panic; + int msglevel; + + u32 flags; +#define PCIX_FLAG 1 +#define PCI_32BIT_FLAG 2 +#define ONE_TDMA_FLAG 4 /* no longer used */ +#define NO_WOL_FLAG 8 +#define USING_DAC_FLAG 0x10 +#define USING_MSIX_FLAG 0x20 +#define ASF_ENABLE_FLAG 0x40 + + int port; + + int pm_cap; + int pcie_cap; + + /* Used to synchronize phy accesses */ + spinlock_t phy_lock; + + struct work_struct reset_task; + u16 in_reset_task; + + struct work_struct sp_task; + + struct timer_list timer; + int timer_interval; + int current_interval; + + u32 shmem_base; + + u32 chip_id; +/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ +#define CHIP_ID(bp) (((bp)->chip_id) & 0xfffffff0) + +#define CHIP_NUM(bp) (((bp)->chip_id) & 0xffff0000) +#define CHIP_NUM_5710 0x57100000 + +#define CHIP_REV(bp) (((bp)->chip_id) & 0x0000f000) +#define CHIP_REV_Ax 0x00000000 +#define CHIP_REV_Bx 0x00001000 +#define CHIP_REV_Cx 0x00002000 +#define CHIP_REV_EMUL 0x0000e000 +#define CHIP_REV_FPGA 0x0000f000 +#define CHIP_REV_IS_SLOW(bp) ((CHIP_REV(bp) == CHIP_REV_EMUL) || \ + (CHIP_REV(bp) == CHIP_REV_FPGA)) + +#define CHIP_METAL(bp) (((bp)->chip_id) & 0x00000ff0) +#define CHIP_BOND_ID(bp) (((bp)->chip_id) & 0x0000000f) + + u16 fw_seq; + u16 fw_drv_pulse_wr_seq; + u32 fw_mb; + + u32 hw_config; + u32 serdes_config; + u32 lane_config; + u32 ext_phy_config; +#define XGXS_EXT_PHY_TYPE(bp) (bp->ext_phy_config & \ + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) +#define SERDES_EXT_PHY_TYPE(bp) (bp->ext_phy_config & \ + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) + + u32 speed_cap_mask; + u32 link_config; +#define SWITCH_CFG_1G PORT_FEATURE_CON_SWITCH_1G_SWITCH +#define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH +#define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT +#define SWITCH_CFG_ONE_TIME_DETECT \ + PORT_FEATURE_CON_SWITCH_ONE_TIME_DETECT + + u8 ser_lane; + u8 rx_lane_swap; + u8 tx_lane_swap; + + u8 link_up; + + u32 supported; +/* link settings - missing defines */ +#define SUPPORTED_2500baseT_Full (1 << 15) +#define SUPPORTED_CX4 (1 << 16) + + u32 phy_flags; +/*#define PHY_SERDES_FLAG 0x1*/ +#define PHY_BMAC_FLAG 0x2 +#define PHY_EMAC_FLAG 0x4 +#define PHY_XGXS_FLAG 0x8 +#define PHY_SGMII_FLAG 0x10 +#define PHY_INT_MODE_MASK_FLAG 0x300 +#define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100 +#define PHY_INT_MODE_LINK_READY_FLAG 0x200 + + u32 phy_addr; + u32 phy_id; + + u32 autoneg; +#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37 +#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73 +#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM +#define AUTONEG_PARALLEL \ + SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION +#define AUTONEG_SGMII_FIBER_AUTODET \ + SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT +#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY + + u32 req_autoneg; +#define AUTONEG_SPEED 0x1 +#define AUTONEG_FLOW_CTRL 0x2 + + u32 req_line_speed; +/* link settings - missing defines */ +#define SPEED_12000 12000 +#define SPEED_12500 12500 +#define SPEED_13000 13000 +#define SPEED_15000 15000 +#define SPEED_16000 16000 + + u32 req_duplex; + u32 req_flow_ctrl; +#define FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO +#define FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX +#define FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX +#define FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH +#define FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE + + u32 pause_mode; +#define PAUSE_NONE 0 +#define PAUSE_SYMMETRIC 1 +#define PAUSE_ASYMMETRIC 2 +#define PAUSE_BOTH 3 + + u32 advertising; +/* link settings - missing defines */ +#define ADVERTISED_2500baseT_Full (1 << 15) +#define ADVERTISED_CX4 (1 << 16) + + u32 link_status; + u32 line_speed; + u32 duplex; + u32 flow_ctrl; + + u32 bc_ver; + + int flash_size; +#define NVRAM_1MB_SIZE 0x20000 /* 1M bit in bytes */ +#define NVRAM_TIMEOUT_COUNT 30000 +#define NVRAM_PAGE_SIZE 256 + + int rx_ring_size; + + u16 tx_quick_cons_trip_int; + u16 tx_quick_cons_trip; + u16 tx_ticks_int; + u16 tx_ticks; + + u16 rx_quick_cons_trip_int; + u16 rx_quick_cons_trip; + u16 rx_ticks_int; + u16 rx_ticks; + + u32 stats_ticks; + + int state; +#define BNX2X_STATE_CLOSED 0x0 +#define BNX2X_STATE_OPENING_WAIT4_LOAD 0x1000 +#define BNX2X_STATE_OPENING_WAIT4_PORT 0x2000 +#define BNX2X_STATE_OPEN 0x3000 +#define BNX2X_STATE_CLOSING_WAIT4_HALT 0x4000 +#define BNX2X_STATE_CLOSING_WAIT4_DELETE 0x5000 +#define BNX2X_STATE_CLOSING_WAIT4_UNLOAD 0x6000 +#define BNX2X_STATE_ERROR 0xF000 + + int num_queues; + + u32 rx_mode; +#define BNX2X_RX_MODE_NONE 0 +#define BNX2X_RX_MODE_NORMAL 1 +#define BNX2X_RX_MODE_ALLMULTI 2 +#define BNX2X_RX_MODE_PROMISC 3 +#define BNX2X_MAX_MULTICAST 64 +#define BNX2X_MAX_EMUL_MULTI 16 + + dma_addr_t def_status_blk_mapping; + + struct bnx2x_slowpath *slowpath; + dma_addr_t slowpath_mapping; + +#ifdef BCM_ISCSI + void *t1; + dma_addr_t t1_mapping; + void *t2; + dma_addr_t t2_mapping; + void *timers; + dma_addr_t timers_mapping; + void *qm; + dma_addr_t qm_mapping; +#endif + + char *name; + u16 bus_speed_mhz; + u8 wol; + u8 pad; + + /* used to synchronize stats collecting */ + int stats_state; +#define STATS_STATE_DISABLE 0 +#define STATS_STATE_ENABLE 1 +#define STATS_STATE_STOP 2 /* stop stats on next iteration */ + + /* used by dmae command loader */ + struct dmae_command dmae; + int executer_idx; + + u32 old_brb_discard; + struct bmac_stats old_bmac; + struct tstorm_per_client_stats old_tclient; + struct z_stream_s *strm; + void *gunzip_buf; + dma_addr_t gunzip_mapping; + int gunzip_outlen; +#define FW_BUF_SIZE 0x8000 + +}; + + +/* DMAE command defines */ +#define DMAE_CMD_SRC_PCI 0 +#define DMAE_CMD_SRC_GRC DMAE_COMMAND_SRC + +#define DMAE_CMD_DST_PCI (1 << DMAE_COMMAND_DST_SHIFT) +#define DMAE_CMD_DST_GRC (2 << DMAE_COMMAND_DST_SHIFT) + +#define DMAE_CMD_C_DST_PCI 0 +#define DMAE_CMD_C_DST_GRC (1 << DMAE_COMMAND_C_DST_SHIFT) + +#define DMAE_CMD_C_ENABLE DMAE_COMMAND_C_TYPE_ENABLE + +#define DMAE_CMD_ENDIANITY_NO_SWAP (0 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_B_SWAP (1 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_DW_SWAP (2 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_B_DW_SWAP (3 << DMAE_COMMAND_ENDIANITY_SHIFT) + +#define DMAE_CMD_PORT_0 0 +#define DMAE_CMD_PORT_1 DMAE_COMMAND_PORT + +#define DMAE_CMD_SRC_RESET DMAE_COMMAND_SRC_RESET +#define DMAE_CMD_DST_RESET DMAE_COMMAND_DST_RESET + +#define DMAE_LEN32_MAX 0x400 + + +/* MC hsi */ +#define RX_COPY_THRESH 92 +#define BCM_PAGE_BITS 12 +#define BCM_PAGE_SIZE (1 << BCM_PAGE_BITS) + +#define NUM_TX_RINGS 16 +#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_tx_bd)) +#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) +#define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) +#define MAX_TX_BD (NUM_TX_BD - 1) +#define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2) +#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \ + (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) +#define TX_BD(x) ((x) & MAX_TX_BD) +#define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT) + +/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */ +#define NUM_RX_RINGS 8 +#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd)) +#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2) +#define RX_DESC_MASK (RX_DESC_CNT - 1) +#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) +#define MAX_RX_BD (NUM_RX_BD - 1) +#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) +#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ + (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1) +#define RX_BD(x) ((x) & MAX_RX_BD) + +#define NUM_RCQ_RINGS (NUM_RX_RINGS * 2) +#define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe)) +#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1) +#define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS) +#define MAX_RCQ_BD (NUM_RCQ_BD - 1) +#define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2) +#define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \ + (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) +#define RCQ_BD(x) ((x) & MAX_RCQ_BD) + + +/* used on a CID received from the HW */ +#define SW_CID(x) (le32_to_cpu(x) & \ + (COMMON_RAMROD_ETH_RX_CQE_CID >> 1)) +#define CQE_CMD(x) (le32_to_cpu(x) >> \ + COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT) + +#define BD_UNMAP_ADDR(bd) HILO_U64(le32_to_cpu((bd)->addr_hi), \ + le32_to_cpu((bd)->addr_lo)) +#define BD_UNMAP_LEN(bd) (le16_to_cpu((bd)->nbytes)) + + +#define STROM_ASSERT_ARRAY_SIZE 50 + + +#define MDIO_INDIRECT_REG_ADDR 0x1f +#define MDIO_SET_REG_BANK(bp, reg_bank) \ + bnx2x_mdio22_write(bp, MDIO_INDIRECT_REG_ADDR, reg_bank) + +#define MDIO_ACCESS_TIMEOUT 1000 + + +/* must be used on a CID before placing it on a HW ring */ +#define HW_CID(bp, x) (x | (bp->port << 23)) + +#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) +#define MAX_SP_DESC_CNT (SP_DESC_CNT - 1) + +#define ATTN_NIG_FOR_FUNC (1L << 8) +#define ATTN_SW_TIMER_4_FUNC (1L << 9) +#define GPIO_2_FUNC (1L << 10) +#define GPIO_3_FUNC (1L << 11) +#define GPIO_4_FUNC (1L << 12) +#define ATTN_GENERAL_ATTN_1 (1L << 13) +#define ATTN_GENERAL_ATTN_2 (1L << 14) +#define ATTN_GENERAL_ATTN_3 (1L << 15) +#define ATTN_GENERAL_ATTN_4 (1L << 13) +#define ATTN_GENERAL_ATTN_5 (1L << 14) +#define ATTN_GENERAL_ATTN_6 (1L << 15) + +#define ATTN_HARD_WIRED_MASK 0xff00 +#define ATTENTION_ID 4 + + +#define BNX2X_BTR 3 +#define MAX_SPQ_PENDING 8 + + +#define BNX2X_NUM_STATS 31 +#define BNX2X_NUM_TESTS 2 + + +#define DPM_TRIGER_TYPE 0x40 +#define DOORBELL(bp, cid, val) \ + do { \ + writel((u32)val, (bp)->doorbells + (BCM_PAGE_SIZE * cid) + \ + DPM_TRIGER_TYPE); \ + } while (0) + + +/* stuff added to make the code fit 80Col */ + +#define TPA_TYPE_START ETH_FAST_PATH_RX_CQE_START_FLG +#define TPA_TYPE_END ETH_FAST_PATH_RX_CQE_END_FLG +#define TPA_TYPE(cqe) (cqe->fast_path_cqe.error_type_flags & \ + (TPA_TYPE_START | TPA_TYPE_END)) +#define BNX2X_RX_SUM_OK(cqe) \ + (!(cqe->fast_path_cqe.status_flags & \ + (ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG | \ + ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG))) + +#define BNX2X_RX_SUM_FIX(cqe) \ + ((le16_to_cpu(cqe->fast_path_cqe.pars_flags.flags) & \ + PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == \ + (1 << PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT)) + + +#define MDIO_AN_CL73_OR_37_COMPLETE \ + (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \ + MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE) + +#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \ + MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE +#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \ + MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE +#define GP_STATUS_SPEED_MASK \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK +#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M +#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M +#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G +#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G +#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G +#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G +#define GP_STATUS_10G_HIG \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG +#define GP_STATUS_10G_CX4 \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 +#define GP_STATUS_12G_HIG \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG +#define GP_STATUS_12_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G +#define GP_STATUS_13G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G +#define GP_STATUS_15G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G +#define GP_STATUS_16G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G +#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX +#define GP_STATUS_10G_KX4 \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 + +#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD +#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD +#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD +#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 +#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD +#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD +#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD +#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD +#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD +#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD +#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD +#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD +#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD +#define LINK_12GTFD LINK_STATUS_SPEED_AND_DUPLEX_12GTFD +#define LINK_12GXFD LINK_STATUS_SPEED_AND_DUPLEX_12GXFD +#define LINK_12_5GTFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD +#define LINK_12_5GXFD LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD +#define LINK_13GTFD LINK_STATUS_SPEED_AND_DUPLEX_13GTFD +#define LINK_13GXFD LINK_STATUS_SPEED_AND_DUPLEX_13GXFD +#define LINK_15GTFD LINK_STATUS_SPEED_AND_DUPLEX_15GTFD +#define LINK_15GXFD LINK_STATUS_SPEED_AND_DUPLEX_15GXFD +#define LINK_16GTFD LINK_STATUS_SPEED_AND_DUPLEX_16GTFD +#define LINK_16GXFD LINK_STATUS_SPEED_AND_DUPLEX_16GXFD + +#define NIG_STATUS_INTERRUPT_XGXS0_LINK10G \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G +#define NIG_XGXS0_LINK_STATUS \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS +#define NIG_XGXS0_LINK_STATUS_SIZE \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE +#define NIG_SERDES0_LINK_STATUS \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS +#define NIG_MASK_MI_INT \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT +#define NIG_MASK_XGXS0_LINK10G \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G +#define NIG_MASK_XGXS0_LINK_STATUS \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS +#define NIG_MASK_SERDES0_LINK_STATUS \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS + +#define XGXS_RESET_BITS \ + (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB) + +#define SERDES_RESET_BITS \ + (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD) + + +#define BNX2X_MC_ASSERT_BITS \ + (GENERAL_ATTEN_OFFSET(TSTORM_FATAL_ASSERT_ATTENTION_BIT) | \ + GENERAL_ATTEN_OFFSET(USTORM_FATAL_ASSERT_ATTENTION_BIT) | \ + GENERAL_ATTEN_OFFSET(CSTORM_FATAL_ASSERT_ATTENTION_BIT) | \ + GENERAL_ATTEN_OFFSET(XSTORM_FATAL_ASSERT_ATTENTION_BIT)) + +#define BNX2X_MCP_ASSERT \ + GENERAL_ATTEN_OFFSET(MCP_FATAL_ASSERT_ATTENTION_BIT) + +#define BNX2X_DOORQ_ASSERT \ + AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT + +#define HW_INTERRUT_ASSERT_SET_0 \ + (AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_PBF_HW_INTERRUPT) +#define HW_PRTY_ASSERT_SET_0 (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR) +#define HW_INTERRUT_ASSERT_SET_1 \ + (AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_XCM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_XSEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_USDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_UCM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_USEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT) +#define HW_PRTY_ASSERT_SET_1 (AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR) +#define HW_INTERRUT_ASSERT_SET_2 \ + (AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT |\ + AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT) +#define HW_PRTY_ASSERT_SET_2 (AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR) + + +#define ETH_RX_ERROR_FALGS (ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG | \ + ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | \ + ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG) + + +#define MULTI_FLAGS \ + (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE) + +#define MULTI_MASK 0x7f + + +#define U_SB_ETH_RX_CQ_INDEX HC_INDEX_U_ETH_RX_CQ_CONS +#define C_SB_ETH_TX_CQ_INDEX HC_INDEX_C_ETH_TX_CQ_CONS +#define C_DEF_SB_SP_INDEX HC_INDEX_DEF_C_ETH_SLOW_PATH + +#define BNX2X_RX_SB_INDEX \ + &fp->status_blk->u_status_block.index_values[U_SB_ETH_RX_CQ_INDEX] + +#define BNX2X_TX_SB_INDEX \ + &fp->status_blk->c_status_block.index_values[C_SB_ETH_TX_CQ_INDEX] + +#define BNX2X_SP_DSB_INDEX \ +&bp->def_status_blk->c_def_status_block.index_values[C_DEF_SB_SP_INDEX] + + +#define CAM_IS_INVALID(x) \ +(x.target_table_entry.flags == TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE) + +#define CAM_INVALIDATE(x) \ +x.target_table_entry.flags = TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE + + +/* MISC_REG_RESET_REG - this is here for the hsi to work don't touch */ + +#endif /* bnx2x.h */ diff --git a/drivers/net/bnx2x_fw_defs.h b/drivers/net/bnx2x_fw_defs.h new file mode 100644 index 000000000000..62a6eb81025a --- /dev/null +++ b/drivers/net/bnx2x_fw_defs.h @@ -0,0 +1,198 @@ +/* bnx2x_fw_defs.h: Broadcom Everest network driver. + * + * Copyright (c) 2007 Broadcom Corporation + * + * 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. + */ + + +#define CSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ + (0x1922 + (port * 0x40) + (index * 0x4)) +#define CSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ + (0x1900 + (port * 0x40)) +#define CSTORM_HC_BTR_OFFSET(port)\ + (0x1984 + (port * 0xc0)) +#define CSTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index)\ + (0x141a + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) +#define CSTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index)\ + (0x1418 + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) +#define CSTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id)\ + (0x1400 + (port * 0x280) + (cpu_id * 0x28)) +#define CSTORM_STATS_FLAGS_OFFSET(port) (0x5108 + (port * 0x8)) +#define TSTORM_CLIENT_CONFIG_OFFSET(port, client_id)\ + (0x1510 + (port * 0x240) + (client_id * 0x20)) +#define TSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ + (0x138a + (port * 0x28) + (index * 0x4)) +#define TSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ + (0x1370 + (port * 0x28)) +#define TSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port)\ + (0x4b70 + (port * 0x8)) +#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(function)\ + (0x1418 + (function * 0x30)) +#define TSTORM_HC_BTR_OFFSET(port)\ + (0x13c4 + (port * 0x18)) +#define TSTORM_INDIRECTION_TABLE_OFFSET(port)\ + (0x22c8 + (port * 0x80)) +#define TSTORM_INDIRECTION_TABLE_SIZE 0x80 +#define TSTORM_MAC_FILTER_CONFIG_OFFSET(port)\ + (0x1420 + (port * 0x30)) +#define TSTORM_RCQ_PROD_OFFSET(port, client_id)\ + (0x1508 + (port * 0x240) + (client_id * 0x20)) +#define TSTORM_STATS_FLAGS_OFFSET(port) (0x4b90 + (port * 0x8)) +#define USTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ + (0x191a + (port * 0x28) + (index * 0x4)) +#define USTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ + (0x1900 + (port * 0x28)) +#define USTORM_HC_BTR_OFFSET(port)\ + (0x1954 + (port * 0xb8)) +#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(port)\ + (0x5408 + (port * 0x8)) +#define USTORM_SB_HC_DISABLE_OFFSET(port, cpu_id, index)\ + (0x141a + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) +#define USTORM_SB_HC_TIMEOUT_OFFSET(port, cpu_id, index)\ + (0x1418 + (port * 0x280) + (cpu_id * 0x28) + (index * 0x4)) +#define USTORM_SB_HOST_SB_ADDR_OFFSET(port, cpu_id)\ + (0x1400 + (port * 0x280) + (cpu_id * 0x28)) +#define XSTORM_ASSERT_LIST_INDEX_OFFSET 0x1000 +#define XSTORM_ASSERT_LIST_OFFSET(idx) (0x1020 + (idx * 0x10)) +#define XSTORM_DEF_SB_HC_DISABLE_OFFSET(port, index)\ + (0x141a + (port * 0x28) + (index * 0x4)) +#define XSTORM_DEF_SB_HOST_SB_ADDR_OFFSET(port)\ + (0x1400 + (port * 0x28)) +#define XSTORM_ETH_STATS_QUERY_ADDR_OFFSET(port)\ + (0x5408 + (port * 0x8)) +#define XSTORM_HC_BTR_OFFSET(port)\ + (0x1454 + (port * 0x18)) +#define XSTORM_SPQ_PAGE_BASE_OFFSET(port)\ + (0x5328 + (port * 0x18)) +#define XSTORM_SPQ_PROD_OFFSET(port)\ + (0x5330 + (port * 0x18)) +#define XSTORM_STATS_FLAGS_OFFSET(port) (0x53f8 + (port * 0x8)) +#define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0 + +/** +* This file defines HSI constatnts for the ETH flow +*/ + +/* hash types */ +#define DEFAULT_HASH_TYPE 0 +#define IPV4_HASH_TYPE 1 +#define TCP_IPV4_HASH_TYPE 2 +#define IPV6_HASH_TYPE 3 +#define TCP_IPV6_HASH_TYPE 4 + +/* values of command IDs in the ramrod message */ +#define RAMROD_CMD_ID_ETH_PORT_SETUP (80) +#define RAMROD_CMD_ID_ETH_CLIENT_SETUP (85) +#define RAMROD_CMD_ID_ETH_STAT_QUERY (90) +#define RAMROD_CMD_ID_ETH_UPDATE (100) +#define RAMROD_CMD_ID_ETH_HALT (105) +#define RAMROD_CMD_ID_ETH_SET_MAC (110) +#define RAMROD_CMD_ID_ETH_CFC_DEL (115) +#define RAMROD_CMD_ID_ETH_PORT_DEL (120) +#define RAMROD_CMD_ID_ETH_FORWARD_SETUP (125) + + +/* command values for set mac command */ +#define T_ETH_MAC_COMMAND_SET 0 +#define T_ETH_MAC_COMMAND_INVALIDATE 1 + +#define T_ETH_INDIRECTION_TABLE_SIZE 128 + +/* Maximal L2 clients supported */ +#define ETH_MAX_RX_CLIENTS (18) + +/** +* This file defines HSI constatnts common to all microcode flows +*/ + +/* Connection types */ +#define ETH_CONNECTION_TYPE 0 + +#define PROTOCOL_STATE_BIT_OFFSET 6 + +#define ETH_STATE (ETH_CONNECTION_TYPE << PROTOCOL_STATE_BIT_OFFSET) + +/* microcode fixed page page size 4K (chains and ring segments) */ +#define MC_PAGE_SIZE (4096) + +/* Host coalescing constants */ + +/* IGU constants */ +#define IGU_PORT_BASE 0x0400 + +#define IGU_ADDR_MSIX 0x0000 +#define IGU_ADDR_INT_ACK 0x0200 +#define IGU_ADDR_PROD_UPD 0x0201 +#define IGU_ADDR_ATTN_BITS_UPD 0x0202 +#define IGU_ADDR_ATTN_BITS_SET 0x0203 +#define IGU_ADDR_ATTN_BITS_CLR 0x0204 +#define IGU_ADDR_COALESCE_NOW 0x0205 +#define IGU_ADDR_SIMD_MASK 0x0206 +#define IGU_ADDR_SIMD_NOMASK 0x0207 +#define IGU_ADDR_MSI_CTL 0x0210 +#define IGU_ADDR_MSI_ADDR_LO 0x0211 +#define IGU_ADDR_MSI_ADDR_HI 0x0212 +#define IGU_ADDR_MSI_DATA 0x0213 + +#define IGU_INT_ENABLE 0 +#define IGU_INT_DISABLE 1 +#define IGU_INT_NOP 2 +#define IGU_INT_NOP2 3 + +/* index numbers */ +#define HC_USTORM_DEF_SB_NUM_INDICES 4 +#define HC_CSTORM_DEF_SB_NUM_INDICES 8 +#define HC_XSTORM_DEF_SB_NUM_INDICES 4 +#define HC_TSTORM_DEF_SB_NUM_INDICES 4 +#define HC_USTORM_SB_NUM_INDICES 4 +#define HC_CSTORM_SB_NUM_INDICES 4 + +/* index values - which counterto update */ + +#define HC_INDEX_U_ETH_RX_CQ_CONS 1 + +#define HC_INDEX_C_ETH_TX_CQ_CONS 1 + +#define HC_INDEX_DEF_X_SPQ_CONS 0 + +#define HC_INDEX_DEF_C_ETH_FW_TX_CQ_CONS 2 +#define HC_INDEX_DEF_C_ETH_SLOW_PATH 3 + +/* used by the driver to get the SB offset */ +#define USTORM_ID 0 +#define CSTORM_ID 1 +#define XSTORM_ID 2 +#define TSTORM_ID 3 +#define ATTENTION_ID 4 + +/* max number of slow path commands per port */ +#define MAX_RAMRODS_PER_PORT (8) + +/* values for RX ETH CQE type field */ +#define RX_ETH_CQE_TYPE_ETH_FASTPATH (0) +#define RX_ETH_CQE_TYPE_ETH_RAMROD (1) + +/* MAC address list size */ +#define T_MAC_ADDRESS_LIST_SIZE (96) + +#define XSTORM_IP_ID_ROLL_HALF 0x8000 +#define XSTORM_IP_ID_ROLL_ALL 0 + +#define FW_LOG_LIST_SIZE (50) + +#define NUM_OF_PROTOCOLS 4 +#define MAX_COS_NUMBER 16 +#define MAX_T_STAT_COUNTER_ID 18 + +#define T_FAIR 1 +#define FAIR_MEM 2 +#define RS_PERIODIC_TIMEOUT_IN_SDM_TICS 25 + +#define UNKNOWN_ADDRESS 0 +#define UNICAST_ADDRESS 1 +#define MULTICAST_ADDRESS 2 +#define BROADCAST_ADDRESS 3 + diff --git a/drivers/net/bnx2x_hsi.h b/drivers/net/bnx2x_hsi.h new file mode 100644 index 000000000000..6fd959c34d1f --- /dev/null +++ b/drivers/net/bnx2x_hsi.h @@ -0,0 +1,2176 @@ +/* bnx2x_hsi.h: Broadcom Everest network driver. + * + * Copyright (c) 2007 Broadcom Corporation + * + * 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. + */ + + +#define FUNC_0 0 +#define FUNC_1 1 +#define FUNC_MAX 2 + + +/* This value (in milliseconds) determines the frequency of the driver + * issuing the PULSE message code. The firmware monitors this periodic + * pulse to determine when to switch to an OS-absent mode. */ +#define DRV_PULSE_PERIOD_MS 250 + +/* This value (in milliseconds) determines how long the driver should + * wait for an acknowledgement from the firmware before timing out. Once + * the firmware has timed out, the driver will assume there is no firmware + * running and there won't be any firmware-driver synchronization during a + * driver reset. */ +#define FW_ACK_TIME_OUT_MS 5000 + +#define FW_ACK_POLL_TIME_MS 1 + +#define FW_ACK_NUM_OF_POLL (FW_ACK_TIME_OUT_MS/FW_ACK_POLL_TIME_MS) + +/* LED Blink rate that will achieve ~15.9Hz */ +#define LED_BLINK_RATE_VAL 480 + +/**************************************************************************** + * Driver <-> FW Mailbox * + ****************************************************************************/ +struct drv_fw_mb { + u32 drv_mb_header; +#define DRV_MSG_CODE_MASK 0xffff0000 +#define DRV_MSG_CODE_LOAD_REQ 0x10000000 +#define DRV_MSG_CODE_LOAD_DONE 0x11000000 +#define DRV_MSG_CODE_UNLOAD_REQ_WOL_EN 0x20000000 +#define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 0x20010000 +#define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 0x20020000 +#define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 +#define DRV_MSG_CODE_DIAG_ENTER_REQ 0x50000000 +#define DRV_MSG_CODE_DIAG_EXIT_REQ 0x60000000 +#define DRV_MSG_CODE_VALIDATE_KEY 0x70000000 +#define DRV_MSG_CODE_GET_CURR_KEY 0x80000000 +#define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000 +#define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000 +#define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000 + +#define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 drv_mb_param; + + u32 fw_mb_header; +#define FW_MSG_CODE_MASK 0xffff0000 +#define FW_MSG_CODE_DRV_LOAD_COMMON 0x11000000 +#define FW_MSG_CODE_DRV_LOAD_PORT 0x12000000 +#define FW_MSG_CODE_DRV_LOAD_REFUSED 0x13000000 +#define FW_MSG_CODE_DRV_LOAD_DONE 0x14000000 +#define FW_MSG_CODE_DRV_UNLOAD_COMMON 0x21000000 +#define FW_MSG_CODE_DRV_UNLOAD_PORT 0x22000000 +#define FW_MSG_CODE_DRV_UNLOAD_DONE 0x23000000 +#define FW_MSG_CODE_DIAG_ENTER_DONE 0x50000000 +#define FW_MSG_CODE_DIAG_REFUSE 0x51000000 +#define FW_MSG_CODE_VALIDATE_KEY_SUCCESS 0x70000000 +#define FW_MSG_CODE_VALIDATE_KEY_FAILURE 0x71000000 +#define FW_MSG_CODE_GET_KEY_DONE 0x80000000 +#define FW_MSG_CODE_NO_KEY 0x8f000000 +#define FW_MSG_CODE_LIC_INFO_NOT_READY 0x8f800000 +#define FW_MSG_CODE_L2B_PRAM_LOADED 0x90000000 +#define FW_MSG_CODE_L2B_PRAM_T_LOAD_FAILURE 0x91000000 +#define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x92000000 +#define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x93000000 +#define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x94000000 + +#define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 fw_mb_param; + + u32 link_status; + /* Driver should update this field on any link change event */ + +#define LINK_STATUS_LINK_FLAG_MASK 0x00000001 +#define LINK_STATUS_LINK_UP 0x00000001 +#define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001E +#define LINK_STATUS_SPEED_AND_DUPLEX_AN_NOT_COMPLETE (0<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_10THD (1<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_10TFD (2<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_100TXHD (3<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_100T4 (4<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_100TXFD (5<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_1000THD (6<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (7<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_1000XFD (7<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_2500THD (8<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_2500TFD (9<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_2500XFD (9<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_10GTFD (10<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_10GXFD (10<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_12GTFD (11<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_12GXFD (11<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GTFD (12<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_12_5GXFD (12<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_13GTFD (13<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_13GXFD (13<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_15GTFD (14<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_15GXFD (14<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_16GTFD (15<<1) +#define LINK_STATUS_SPEED_AND_DUPLEX_16GXFD (15<<1) + +#define LINK_STATUS_AUTO_NEGOTIATE_FLAG_MASK 0x00000020 +#define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020 + +#define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040 +#define LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK 0x00000080 +#define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080 + +#define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200 +#define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400 +#define LINK_STATUS_LINK_PARTNER_100T4_CAPABLE 0x00000800 +#define LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE 0x00001000 +#define LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE 0x00002000 +#define LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE 0x00004000 +#define LINK_STATUS_LINK_PARTNER_10THD_CAPABLE 0x00008000 + +#define LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK 0x00010000 +#define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00010000 + +#define LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK 0x00020000 +#define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00020000 + +#define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000 +#define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0<<18) +#define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE (1<<18) +#define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2<<18) +#define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3<<18) + +#define LINK_STATUS_SERDES_LINK 0x00100000 + +#define LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE 0x00200000 +#define LINK_STATUS_LINK_PARTNER_2500XHD_CAPABLE 0x00400000 +#define LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE 0x00800000 +#define LINK_STATUS_LINK_PARTNER_12GXFD_CAPABLE 0x01000000 +#define LINK_STATUS_LINK_PARTNER_12_5GXFD_CAPABLE 0x02000000 +#define LINK_STATUS_LINK_PARTNER_13GXFD_CAPABLE 0x04000000 +#define LINK_STATUS_LINK_PARTNER_15GXFD_CAPABLE 0x08000000 +#define LINK_STATUS_LINK_PARTNER_16GXFD_CAPABLE 0x10000000 + + u32 drv_pulse_mb; +#define DRV_PULSE_SEQ_MASK 0x00007fff +#define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 + /* The system time is in the format of + * (year-2001)*12*32 + month*32 + day. */ +#define DRV_PULSE_ALWAYS_ALIVE 0x00008000 + /* Indicate to the firmware not to go into the + * OS-absent when it is not getting driver pulse. + * This is used for debugging as well for PXE(MBA). */ + + u32 mcp_pulse_mb; +#define MCP_PULSE_SEQ_MASK 0x00007fff +#define MCP_PULSE_ALWAYS_ALIVE 0x00008000 + /* Indicates to the driver not to assert due to lack + * of MCP response */ +#define MCP_EVENT_MASK 0xffff0000 +#define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000 + +}; + + +/**************************************************************************** + * Shared HW configuration * + ****************************************************************************/ +struct shared_hw_cfg { /* NVRAM Offset */ + /* Up to 16 bytes of NULL-terminated string */ + u8 part_num[16]; /* 0x104 */ + + u32 config; /* 0x114 */ +#define SHARED_HW_CFG_MDIO_VOLTAGE_MASK 0x00000001 +#define SHARED_HW_CFG_MDIO_VOLTAGE_SHIFT 0 +#define SHARED_HW_CFG_MDIO_VOLTAGE_1_2V 0x00000000 +#define SHARED_HW_CFG_MDIO_VOLTAGE_2_5V 0x00000001 +#define SHARED_HW_CFG_MCP_RST_ON_CORE_RST_EN 0x00000002 + +#define SHARED_HW_CFG_PORT_SWAP 0x00000004 + +#define SHARED_HW_CFG_BEACON_WOL_EN 0x00000008 + +#define SHARED_HW_CFG_MFW_SELECT_MASK 0x00000700 +#define SHARED_HW_CFG_MFW_SELECT_SHIFT 8 + /* Whatever MFW found in NVM + (if multiple found, priority order is: NC-SI, UMP, IPMI) */ +#define SHARED_HW_CFG_MFW_SELECT_DEFAULT 0x00000000 +#define SHARED_HW_CFG_MFW_SELECT_NC_SI 0x00000100 +#define SHARED_HW_CFG_MFW_SELECT_UMP 0x00000200 +#define SHARED_HW_CFG_MFW_SELECT_IPMI 0x00000300 + /* Use SPIO4 as an arbiter between: 0-NC_SI, 1-IPMI + (can only be used when an add-in board, not BMC, pulls-down SPIO4) */ +#define SHARED_HW_CFG_MFW_SELECT_SPIO4_NC_SI_IPMI 0x00000400 + /* Use SPIO4 as an arbiter between: 0-UMP, 1-IPMI + (can only be used when an add-in board, not BMC, pulls-down SPIO4) */ +#define SHARED_HW_CFG_MFW_SELECT_SPIO4_UMP_IPMI 0x00000500 + /* Use SPIO4 as an arbiter between: 0-NC-SI, 1-UMP + (can only be used when an add-in board, not BMC, pulls-down SPIO4) */ +#define SHARED_HW_CFG_MFW_SELECT_SPIO4_NC_SI_UMP 0x00000600 + +#define SHARED_HW_CFG_LED_MODE_MASK 0x000f0000 +#define SHARED_HW_CFG_LED_MODE_SHIFT 16 +#define SHARED_HW_CFG_LED_MAC1 0x00000000 +#define SHARED_HW_CFG_LED_PHY1 0x00010000 +#define SHARED_HW_CFG_LED_PHY2 0x00020000 +#define SHARED_HW_CFG_LED_PHY3 0x00030000 +#define SHARED_HW_CFG_LED_MAC2 0x00040000 +#define SHARED_HW_CFG_LED_PHY4 0x00050000 +#define SHARED_HW_CFG_LED_PHY5 0x00060000 +#define SHARED_HW_CFG_LED_PHY6 0x00070000 +#define SHARED_HW_CFG_LED_MAC3 0x00080000 +#define SHARED_HW_CFG_LED_PHY7 0x00090000 +#define SHARED_HW_CFG_LED_PHY9 0x000a0000 +#define SHARED_HW_CFG_LED_PHY11 0x000b0000 +#define SHARED_HW_CFG_LED_MAC4 0x000c0000 +#define SHARED_HW_CFG_LED_PHY8 0x000d0000 + +#define SHARED_HW_CFG_AN_ENABLE_MASK 0x3f000000 +#define SHARED_HW_CFG_AN_ENABLE_SHIFT 24 +#define SHARED_HW_CFG_AN_ENABLE_CL37 0x01000000 +#define SHARED_HW_CFG_AN_ENABLE_CL73 0x02000000 +#define SHARED_HW_CFG_AN_ENABLE_BAM 0x04000000 +#define SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION 0x08000000 +#define SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT 0x10000000 +#define SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY 0x20000000 + + u32 config2; /* 0x118 */ + /* one time auto detect grace period (in sec) */ +#define SHARED_HW_CFG_GRACE_PERIOD_MASK 0x000000ff +#define SHARED_HW_CFG_GRACE_PERIOD_SHIFT 0 + +#define SHARED_HW_CFG_PCIE_GEN2_ENABLED 0x00000100 + + /* The default value for the core clock is 250MHz and it is + achieved by setting the clock change to 4 */ +#define SHARED_HW_CFG_CLOCK_CHANGE_MASK 0x00000e00 +#define SHARED_HW_CFG_CLOCK_CHANGE_SHIFT 9 + +#define SHARED_HW_CFG_SMBUS_TIMING_100KHZ 0x00000000 +#define SHARED_HW_CFG_SMBUS_TIMING_400KHZ 0x00001000 + +#define SHARED_HW_CFG_HIDE_FUNC1 0x00002000 + + u32 power_dissipated; /* 0x11c */ +#define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000 +#define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24 + +#define SHARED_HW_CFG_POWER_MGNT_SCALE_MASK 0x00ff0000 +#define SHARED_HW_CFG_POWER_MGNT_SCALE_SHIFT 16 +#define SHARED_HW_CFG_POWER_MGNT_UNKNOWN_SCALE 0x00000000 +#define SHARED_HW_CFG_POWER_MGNT_DOT_1_WATT 0x00010000 +#define SHARED_HW_CFG_POWER_MGNT_DOT_01_WATT 0x00020000 +#define SHARED_HW_CFG_POWER_MGNT_DOT_001_WATT 0x00030000 + + u32 ump_nc_si_config; /* 0x120 */ +#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MASK 0x00000003 +#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_SHIFT 0 +#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MAC 0x00000000 +#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_PHY 0x00000001 +#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MII 0x00000000 +#define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_RMII 0x00000002 + +#define SHARED_HW_CFG_UMP_NC_SI_NUM_DEVS_MASK 0x00000f00 +#define SHARED_HW_CFG_UMP_NC_SI_NUM_DEVS_SHIFT 8 + +#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_MASK 0x00ff0000 +#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_SHIFT 16 +#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_NONE 0x00000000 +#define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_BCM5221 0x00010000 + + u32 board; /* 0x124 */ +#define SHARED_HW_CFG_BOARD_TYPE_MASK 0x0000ffff +#define SHARED_HW_CFG_BOARD_TYPE_SHIFT 0 +#define SHARED_HW_CFG_BOARD_TYPE_NONE 0x00000000 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1000 0x00000001 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1001 0x00000002 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1002G 0x00000003 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1004G 0x00000004 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1007G 0x00000005 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1015G 0x00000006 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710A1020G 0x00000007 +#define SHARED_HW_CFG_BOARD_TYPE_BCM957710T1003G 0x00000008 + +#define SHARED_HW_CFG_BOARD_VER_MASK 0xffff0000 +#define SHARED_HW_CFG_BOARD_VER_SHIFT 16 +#define SHARED_HW_CFG_BOARD_MAJOR_VER_MASK 0xf0000000 +#define SHARED_HW_CFG_BOARD_MAJOR_VER_SHIFT 28 +#define SHARED_HW_CFG_BOARD_MINOR_VER_MASK 0x0f000000 +#define SHARED_HW_CFG_BOARD_MINOR_VER_SHIFT 24 +#define SHARED_HW_CFG_BOARD_REV_MASK 0x00ff0000 +#define SHARED_HW_CFG_BOARD_REV_SHIFT 16 + + u32 reserved; /* 0x128 */ + +}; + +/**************************************************************************** + * Port HW configuration * + ****************************************************************************/ +struct port_hw_cfg { /* function 0: 0x12c-0x2bb, function 1: 0x2bc-0x44b */ + + /* Fields below are port specific (in anticipation of dual port + devices */ + u32 pci_id; +#define PORT_HW_CFG_PCI_VENDOR_ID_MASK 0xffff0000 +#define PORT_HW_CFG_PCI_DEVICE_ID_MASK 0x0000ffff + + u32 pci_sub_id; +#define PORT_HW_CFG_PCI_SUBSYS_DEVICE_ID_MASK 0xffff0000 +#define PORT_HW_CFG_PCI_SUBSYS_VENDOR_ID_MASK 0x0000ffff + + u32 power_dissipated; +#define PORT_HW_CFG_POWER_DIS_D3_MASK 0xff000000 +#define PORT_HW_CFG_POWER_DIS_D3_SHIFT 24 +#define PORT_HW_CFG_POWER_DIS_D2_MASK 0x00ff0000 +#define PORT_HW_CFG_POWER_DIS_D2_SHIFT 16 +#define PORT_HW_CFG_POWER_DIS_D1_MASK 0x0000ff00 +#define PORT_HW_CFG_POWER_DIS_D1_SHIFT 8 +#define PORT_HW_CFG_POWER_DIS_D0_MASK 0x000000ff +#define PORT_HW_CFG_POWER_DIS_D0_SHIFT 0 + + u32 power_consumed; +#define PORT_HW_CFG_POWER_CONS_D3_MASK 0xff000000 +#define PORT_HW_CFG_POWER_CONS_D3_SHIFT 24 +#define PORT_HW_CFG_POWER_CONS_D2_MASK 0x00ff0000 +#define PORT_HW_CFG_POWER_CONS_D2_SHIFT 16 +#define PORT_HW_CFG_POWER_CONS_D1_MASK 0x0000ff00 +#define PORT_HW_CFG_POWER_CONS_D1_SHIFT 8 +#define PORT_HW_CFG_POWER_CONS_D0_MASK 0x000000ff +#define PORT_HW_CFG_POWER_CONS_D0_SHIFT 0 + + u32 mac_upper; +#define PORT_HW_CFG_UPPERMAC_MASK 0x0000ffff +#define PORT_HW_CFG_UPPERMAC_SHIFT 0 + u32 mac_lower; + + u32 iscsi_mac_upper; /* Upper 16 bits are always zeroes */ + u32 iscsi_mac_lower; + + u32 rdma_mac_upper; /* Upper 16 bits are always zeroes */ + u32 rdma_mac_lower; + + u32 serdes_config; + /* for external PHY, or forced mode or during AN */ +#define PORT_HW_CFG_SERDES_TX_DRV_PRE_EMPHASIS_MASK 0xffff0000 +#define PORT_HW_CFG_SERDES_TX_DRV_PRE_EMPHASIS_SHIFT 16 + +#define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK 0x0000ffff +#define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT 0 + + u16 serdes_tx_driver_pre_emphasis[16]; + u16 serdes_rx_driver_equalizer[16]; + + u32 xgxs_config_lane0; + u32 xgxs_config_lane1; + u32 xgxs_config_lane2; + u32 xgxs_config_lane3; + /* for external PHY, or forced mode or during AN */ +#define PORT_HW_CFG_XGXS_TX_DRV_PRE_EMPHASIS_MASK 0xffff0000 +#define PORT_HW_CFG_XGXS_TX_DRV_PRE_EMPHASIS_SHIFT 16 + +#define PORT_HW_CFG_XGXS_RX_DRV_EQUALIZER_MASK 0x0000ffff +#define PORT_HW_CFG_XGXS_RX_DRV_EQUALIZER_SHIFT 0 + + u16 xgxs_tx_driver_pre_emphasis_lane0[16]; + u16 xgxs_tx_driver_pre_emphasis_lane1[16]; + u16 xgxs_tx_driver_pre_emphasis_lane2[16]; + u16 xgxs_tx_driver_pre_emphasis_lane3[16]; + + u16 xgxs_rx_driver_equalizer_lane0[16]; + u16 xgxs_rx_driver_equalizer_lane1[16]; + u16 xgxs_rx_driver_equalizer_lane2[16]; + u16 xgxs_rx_driver_equalizer_lane3[16]; + + u32 lane_config; +#define PORT_HW_CFG_LANE_SWAP_CFG_MASK 0x0000ffff +#define PORT_HW_CFG_LANE_SWAP_CFG_SHIFT 0 +#define PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK 0x000000ff +#define PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT 0 +#define PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK 0x0000ff00 +#define PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT 8 +#define PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK 0x0000c000 +#define PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT 14 + /* AN and forced */ +#define PORT_HW_CFG_LANE_SWAP_CFG_01230123 0x00001b1b + /* forced only */ +#define PORT_HW_CFG_LANE_SWAP_CFG_01233210 0x00001be4 + /* forced only */ +#define PORT_HW_CFG_LANE_SWAP_CFG_31203120 0x0000d8d8 + /* forced only */ +#define PORT_HW_CFG_LANE_SWAP_CFG_32103210 0x0000e4e4 + + u32 external_phy_config; +#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK 0xff000000 +#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_SHIFT 24 +#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT 0x00000000 +#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482 0x01000000 +#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN 0xff000000 + +#define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK 0x00ff0000 +#define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT 16 + +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK 0x0000ff00 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SHIFT 8 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT 0x00000000 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8071 0x00000100 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072 0x00000200 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073 0x00000300 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 0x00000400 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 0x00000500 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8276 0x00000600 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 + +#define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK 0x000000ff +#define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT 0 + + u32 speed_capability_mask; +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_MASK 0xffff0000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_SHIFT 16 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL 0x00010000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF 0x00020000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF 0x00040000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL 0x00080000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_1G 0x00100000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G 0x00200000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_10G 0x00400000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_12G 0x00800000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_12_5G 0x01000000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_13G 0x02000000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_15G 0x04000000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_16G 0x08000000 +#define PORT_HW_CFG_SPEED_CAPABILITY_D0_RESERVED 0xf0000000 + +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_MASK 0x0000ffff +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_SHIFT 0 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_10M_FULL 0x00000001 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_10M_HALF 0x00000002 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_100M_HALF 0x00000004 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_100M_FULL 0x00000008 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_1G 0x00000010 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_2_5G 0x00000020 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_10G 0x00000040 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_12G 0x00000080 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_12_5G 0x00000100 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_13G 0x00000200 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_15G 0x00000400 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_16G 0x00000800 +#define PORT_HW_CFG_SPEED_CAPABILITY_D3_RESERVED 0x0000f000 + + u32 reserved[2]; + +}; + +/**************************************************************************** + * Shared Feature configuration * + ****************************************************************************/ +struct shared_feat_cfg { /* NVRAM Offset */ + u32 bmc_common; /* 0x450 */ +#define SHARED_FEATURE_BMC_ECHO_MODE_EN 0x00000001 + +}; + + +/**************************************************************************** + * Port Feature configuration * + ****************************************************************************/ +struct port_feat_cfg { /* function 0: 0x454-0x4c7, function 1: 0x4c8-0x53b */ + u32 config; +#define PORT_FEATURE_BAR1_SIZE_MASK 0x0000000f +#define PORT_FEATURE_BAR1_SIZE_SHIFT 0 +#define PORT_FEATURE_BAR1_SIZE_DISABLED 0x00000000 +#define PORT_FEATURE_BAR1_SIZE_64K 0x00000001 +#define PORT_FEATURE_BAR1_SIZE_128K 0x00000002 +#define PORT_FEATURE_BAR1_SIZE_256K 0x00000003 +#define PORT_FEATURE_BAR1_SIZE_512K 0x00000004 +#define PORT_FEATURE_BAR1_SIZE_1M 0x00000005 +#define PORT_FEATURE_BAR1_SIZE_2M 0x00000006 +#define PORT_FEATURE_BAR1_SIZE_4M 0x00000007 +#define PORT_FEATURE_BAR1_SIZE_8M 0x00000008 +#define PORT_FEATURE_BAR1_SIZE_16M 0x00000009 +#define PORT_FEATURE_BAR1_SIZE_32M 0x0000000a +#define PORT_FEATURE_BAR1_SIZE_64M 0x0000000b +#define PORT_FEATURE_BAR1_SIZE_128M 0x0000000c +#define PORT_FEATURE_BAR1_SIZE_256M 0x0000000d +#define PORT_FEATURE_BAR1_SIZE_512M 0x0000000e +#define PORT_FEATURE_BAR1_SIZE_1G 0x0000000f +#define PORT_FEATURE_BAR2_SIZE_MASK 0x000000f0 +#define PORT_FEATURE_BAR2_SIZE_SHIFT 4 +#define PORT_FEATURE_BAR2_SIZE_DISABLED 0x00000000 +#define PORT_FEATURE_BAR2_SIZE_64K 0x00000010 +#define PORT_FEATURE_BAR2_SIZE_128K 0x00000020 +#define PORT_FEATURE_BAR2_SIZE_256K 0x00000030 +#define PORT_FEATURE_BAR2_SIZE_512K 0x00000040 +#define PORT_FEATURE_BAR2_SIZE_1M 0x00000050 +#define PORT_FEATURE_BAR2_SIZE_2M 0x00000060 +#define PORT_FEATURE_BAR2_SIZE_4M 0x00000070 +#define PORT_FEATURE_BAR2_SIZE_8M 0x00000080 +#define PORT_FEATURE_BAR2_SIZE_16M 0x00000090 +#define PORT_FEATURE_BAR2_SIZE_32M 0x000000a0 +#define PORT_FEATURE_BAR2_SIZE_64M 0x000000b0 +#define PORT_FEATURE_BAR2_SIZE_128M 0x000000c0 +#define PORT_FEATURE_BAR2_SIZE_256M 0x000000d0 +#define PORT_FEATURE_BAR2_SIZE_512M 0x000000e0 +#define PORT_FEATURE_BAR2_SIZE_1G 0x000000f0 +#define PORT_FEATURE_EN_SIZE_MASK 0x07000000 +#define PORT_FEATURE_EN_SIZE_SHIFT 24 +#define PORT_FEATURE_WOL_ENABLED 0x01000000 +#define PORT_FEATURE_MBA_ENABLED 0x02000000 +#define PORT_FEATURE_MFW_ENABLED 0x04000000 + + u32 wol_config; + /* Default is used when driver sets to "auto" mode */ +#define PORT_FEATURE_WOL_DEFAULT_MASK 0x00000003 +#define PORT_FEATURE_WOL_DEFAULT_SHIFT 0 +#define PORT_FEATURE_WOL_DEFAULT_DISABLE 0x00000000 +#define PORT_FEATURE_WOL_DEFAULT_MAGIC 0x00000001 +#define PORT_FEATURE_WOL_DEFAULT_ACPI 0x00000002 +#define PORT_FEATURE_WOL_DEFAULT_MAGIC_AND_ACPI 0x00000003 +#define PORT_FEATURE_WOL_RES_PAUSE_CAP 0x00000004 +#define PORT_FEATURE_WOL_RES_ASYM_PAUSE_CAP 0x00000008 +#define PORT_FEATURE_WOL_ACPI_UPON_MGMT 0x00000010 + + u32 mba_config; +#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK 0x00000003 +#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_SHIFT 0 +#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_PXE 0x00000000 +#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_RPL 0x00000001 +#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_BOOTP 0x00000002 +#define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_ISCSIB 0x00000003 +#define PORT_FEATURE_MBA_RES_PAUSE_CAP 0x00000100 +#define PORT_FEATURE_MBA_RES_ASYM_PAUSE_CAP 0x00000200 +#define PORT_FEATURE_MBA_SETUP_PROMPT_ENABLE 0x00000400 +#define PORT_FEATURE_MBA_HOTKEY_CTRL_S 0x00000000 +#define PORT_FEATURE_MBA_HOTKEY_CTRL_B 0x00000800 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_MASK 0x000ff000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_SHIFT 12 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_DISABLED 0x00000000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_2K 0x00001000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_4K 0x00002000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_8K 0x00003000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_16K 0x00004000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_32K 0x00005000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_64K 0x00006000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_128K 0x00007000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_256K 0x00008000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_512K 0x00009000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_1M 0x0000a000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_2M 0x0000b000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_4M 0x0000c000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_8M 0x0000d000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_16M 0x0000e000 +#define PORT_FEATURE_MBA_EXP_ROM_SIZE_32M 0x0000f000 +#define PORT_FEATURE_MBA_MSG_TIMEOUT_MASK 0x00f00000 +#define PORT_FEATURE_MBA_MSG_TIMEOUT_SHIFT 20 +#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_MASK 0x03000000 +#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_SHIFT 24 +#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_AUTO 0x00000000 +#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_BBS 0x01000000 +#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT18H 0x02000000 +#define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT19H 0x03000000 +#define PORT_FEATURE_MBA_LINK_SPEED_MASK 0x3c000000 +#define PORT_FEATURE_MBA_LINK_SPEED_SHIFT 26 +#define PORT_FEATURE_MBA_LINK_SPEED_AUTO 0x00000000 +#define PORT_FEATURE_MBA_LINK_SPEED_10HD 0x04000000 +#define PORT_FEATURE_MBA_LINK_SPEED_10FD 0x08000000 +#define PORT_FEATURE_MBA_LINK_SPEED_100HD 0x0c000000 +#define PORT_FEATURE_MBA_LINK_SPEED_100FD 0x10000000 +#define PORT_FEATURE_MBA_LINK_SPEED_1GBPS 0x14000000 +#define PORT_FEATURE_MBA_LINK_SPEED_2_5GBPS 0x18000000 +#define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_CX4 0x1c000000 +#define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_KX4 0x20000000 +#define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_KR 0x24000000 +#define PORT_FEATURE_MBA_LINK_SPEED_12GBPS 0x28000000 +#define PORT_FEATURE_MBA_LINK_SPEED_12_5GBPS 0x2c000000 +#define PORT_FEATURE_MBA_LINK_SPEED_13GBPS 0x30000000 +#define PORT_FEATURE_MBA_LINK_SPEED_15GBPS 0x34000000 +#define PORT_FEATURE_MBA_LINK_SPEED_16GBPS 0x38000000 + + u32 bmc_config; +#define PORT_FEATURE_BMC_LINK_OVERRIDE_DEFAULT 0x00000000 +#define PORT_FEATURE_BMC_LINK_OVERRIDE_EN 0x00000001 + + u32 mba_vlan_cfg; +#define PORT_FEATURE_MBA_VLAN_TAG_MASK 0x0000ffff +#define PORT_FEATURE_MBA_VLAN_TAG_SHIFT 0 +#define PORT_FEATURE_MBA_VLAN_EN 0x00010000 + + u32 resource_cfg; +#define PORT_FEATURE_RESOURCE_CFG_VALID 0x00000001 +#define PORT_FEATURE_RESOURCE_CFG_DIAG 0x00000002 +#define PORT_FEATURE_RESOURCE_CFG_L2 0x00000004 +#define PORT_FEATURE_RESOURCE_CFG_ISCSI 0x00000008 +#define PORT_FEATURE_RESOURCE_CFG_RDMA 0x00000010 + + u32 smbus_config; + /* Obsolete */ +#define PORT_FEATURE_SMBUS_EN 0x00000001 +#define PORT_FEATURE_SMBUS_ADDR_MASK 0x000000fe +#define PORT_FEATURE_SMBUS_ADDR_SHIFT 1 + + u32 iscsib_boot_cfg; +#define PORT_FEATURE_ISCSIB_SKIP_TARGET_BOOT 0x00000001 + + u32 link_config; /* Used as HW defaults for the driver */ +#define PORT_FEATURE_CONNECTED_SWITCH_MASK 0x03000000 +#define PORT_FEATURE_CONNECTED_SWITCH_SHIFT 24 + /* (forced) low speed switch (< 10G) */ +#define PORT_FEATURE_CON_SWITCH_1G_SWITCH 0x00000000 + /* (forced) high speed switch (>= 10G) */ +#define PORT_FEATURE_CON_SWITCH_10G_SWITCH 0x01000000 +#define PORT_FEATURE_CON_SWITCH_AUTO_DETECT 0x02000000 +#define PORT_FEATURE_CON_SWITCH_ONE_TIME_DETECT 0x03000000 + +#define PORT_FEATURE_LINK_SPEED_MASK 0x000f0000 +#define PORT_FEATURE_LINK_SPEED_SHIFT 16 +#define PORT_FEATURE_LINK_SPEED_AUTO 0x00000000 +#define PORT_FEATURE_LINK_SPEED_10M_FULL 0x00010000 +#define PORT_FEATURE_LINK_SPEED_10M_HALF 0x00020000 +#define PORT_FEATURE_LINK_SPEED_100M_HALF 0x00030000 +#define PORT_FEATURE_LINK_SPEED_100M_FULL 0x00040000 +#define PORT_FEATURE_LINK_SPEED_1G 0x00050000 +#define PORT_FEATURE_LINK_SPEED_2_5G 0x00060000 +#define PORT_FEATURE_LINK_SPEED_10G_CX4 0x00070000 +#define PORT_FEATURE_LINK_SPEED_10G_KX4 0x00080000 +#define PORT_FEATURE_LINK_SPEED_10G_KR 0x00090000 +#define PORT_FEATURE_LINK_SPEED_12G 0x000a0000 +#define PORT_FEATURE_LINK_SPEED_12_5G 0x000b0000 +#define PORT_FEATURE_LINK_SPEED_13G 0x000c0000 +#define PORT_FEATURE_LINK_SPEED_15G 0x000d0000 +#define PORT_FEATURE_LINK_SPEED_16G 0x000e0000 + +#define PORT_FEATURE_FLOW_CONTROL_MASK 0x00000700 +#define PORT_FEATURE_FLOW_CONTROL_SHIFT 8 +#define PORT_FEATURE_FLOW_CONTROL_AUTO 0x00000000 +#define PORT_FEATURE_FLOW_CONTROL_TX 0x00000100 +#define PORT_FEATURE_FLOW_CONTROL_RX 0x00000200 +#define PORT_FEATURE_FLOW_CONTROL_BOTH 0x00000300 +#define PORT_FEATURE_FLOW_CONTROL_NONE 0x00000400 + + /* The default for MCP link configuration, + uses the same defines as link_config */ + u32 mfw_wol_link_cfg; + + u32 reserved[19]; + +}; + + +/**************************************************************************** + * Device Information * + ****************************************************************************/ +struct dev_info { /* size */ + + u32 bc_rev; /* 8 bits each: major, minor, build */ /* 4 */ + + struct shared_hw_cfg shared_hw_config; /* 40 */ + + struct port_hw_cfg port_hw_config[FUNC_MAX]; /* 400*2=800 */ + + struct shared_feat_cfg shared_feature_config; /* 4 */ + + struct port_feat_cfg port_feature_config[FUNC_MAX];/* 116*2=232 */ + +}; + + +/**************************************************************************** + * Management firmware state * + ****************************************************************************/ +/* Allocate 320 bytes for management firmware: still not known exactly + * how much IMD needs. */ +#define MGMTFW_STATE_WORD_SIZE 80 + +struct mgmtfw_state { + u32 opaque[MGMTFW_STATE_WORD_SIZE]; +}; + + +/**************************************************************************** + * Shared Memory Region * + ****************************************************************************/ +struct shmem_region { /* SharedMem Offset (size) */ + u32 validity_map[FUNC_MAX]; /* 0x0 (4 * 2 = 0x8) */ +#define SHR_MEM_VALIDITY_PCI_CFG 0x00000001 +#define SHR_MEM_VALIDITY_MB 0x00000002 +#define SHR_MEM_VALIDITY_DEV_INFO 0x00000004 + /* One licensing bit should be set */ +#define SHR_MEM_VALIDITY_LIC_KEY_IN_EFFECT_MASK 0x00000038 +#define SHR_MEM_VALIDITY_LIC_MANUF_KEY_IN_EFFECT 0x00000008 +#define SHR_MEM_VALIDITY_LIC_UPGRADE_KEY_IN_EFFECT 0x00000010 +#define SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT 0x00000020 + + struct drv_fw_mb drv_fw_mb[FUNC_MAX]; /* 0x8 (28 * 2 = 0x38) */ + + struct dev_info dev_info; /* 0x40 (0x438) */ + +#ifdef _LICENSE_H + license_key_t drv_lic_key[FUNC_MAX]; /* 0x478 (52 * 2 = 0x68) */ +#else /* Linux! */ + u8 reserved[52*FUNC_MAX]; +#endif + + /* FW information (for internal FW use) */ + u32 fw_info_fio_offset; /* 0x4e0 (0x4) */ + struct mgmtfw_state mgmtfw_state; /* 0x4e4 (0x140) */ + +}; /* 0x624 */ + + +#define BCM_5710_FW_MAJOR_VERSION 4 +#define BCM_5710_FW_MINOR_VERSION 0 +#define BCM_5710_FW_REVISION_VERSION 14 +#define BCM_5710_FW_COMPILE_FLAGS 1 + + +/* + * attention bits + */ +struct atten_def_status_block { + u32 attn_bits; + u32 attn_bits_ack; +#if defined(__BIG_ENDIAN) + u16 attn_bits_index; + u8 reserved0; + u8 status_block_id; +#elif defined(__LITTLE_ENDIAN) + u8 status_block_id; + u8 reserved0; + u16 attn_bits_index; +#endif + u32 reserved1; +}; + + +/* + * common data for all protocols + */ +struct doorbell_hdr { + u8 header; +#define DOORBELL_HDR_RX (0x1<<0) +#define DOORBELL_HDR_RX_SHIFT 0 +#define DOORBELL_HDR_DB_TYPE (0x1<<1) +#define DOORBELL_HDR_DB_TYPE_SHIFT 1 +#define DOORBELL_HDR_DPM_SIZE (0x3<<2) +#define DOORBELL_HDR_DPM_SIZE_SHIFT 2 +#define DOORBELL_HDR_CONN_TYPE (0xF<<4) +#define DOORBELL_HDR_CONN_TYPE_SHIFT 4 +}; + +/* + * doorbell message send to the chip + */ +struct doorbell { +#if defined(__BIG_ENDIAN) + u16 zero_fill2; + u8 zero_fill1; + struct doorbell_hdr header; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr header; + u8 zero_fill1; + u16 zero_fill2; +#endif +}; + + +/* + * IGU driver acknowlegement register + */ +struct igu_ack_register { +#if defined(__BIG_ENDIAN) + u16 sb_id_and_flags; +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID (0x1F<<0) +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT 0 +#define IGU_ACK_REGISTER_STORM_ID (0x7<<5) +#define IGU_ACK_REGISTER_STORM_ID_SHIFT 5 +#define IGU_ACK_REGISTER_UPDATE_INDEX (0x1<<8) +#define IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT 8 +#define IGU_ACK_REGISTER_INTERRUPT_MODE (0x3<<9) +#define IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT 9 +#define IGU_ACK_REGISTER_RESERVED (0x1F<<11) +#define IGU_ACK_REGISTER_RESERVED_SHIFT 11 + u16 status_block_index; +#elif defined(__LITTLE_ENDIAN) + u16 status_block_index; + u16 sb_id_and_flags; +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID (0x1F<<0) +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT 0 +#define IGU_ACK_REGISTER_STORM_ID (0x7<<5) +#define IGU_ACK_REGISTER_STORM_ID_SHIFT 5 +#define IGU_ACK_REGISTER_UPDATE_INDEX (0x1<<8) +#define IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT 8 +#define IGU_ACK_REGISTER_INTERRUPT_MODE (0x3<<9) +#define IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT 9 +#define IGU_ACK_REGISTER_RESERVED (0x1F<<11) +#define IGU_ACK_REGISTER_RESERVED_SHIFT 11 +#endif +}; + + +/* + * Parser parsing flags field + */ +struct parsing_flags { + u16 flags; +#define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE (0x1<<0) +#define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE_SHIFT 0 +#define PARSING_FLAGS_NUMBER_OF_NESTED_VLANS (0x3<<1) +#define PARSING_FLAGS_NUMBER_OF_NESTED_VLANS_SHIFT 1 +#define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL (0x3<<3) +#define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT 3 +#define PARSING_FLAGS_IP_OPTIONS (0x1<<5) +#define PARSING_FLAGS_IP_OPTIONS_SHIFT 5 +#define PARSING_FLAGS_FRAGMENTATION_STATUS (0x1<<6) +#define PARSING_FLAGS_FRAGMENTATION_STATUS_SHIFT 6 +#define PARSING_FLAGS_OVER_IP_PROTOCOL (0x3<<7) +#define PARSING_FLAGS_OVER_IP_PROTOCOL_SHIFT 7 +#define PARSING_FLAGS_PURE_ACK_INDICATION (0x1<<9) +#define PARSING_FLAGS_PURE_ACK_INDICATION_SHIFT 9 +#define PARSING_FLAGS_TCP_OPTIONS_EXIST (0x1<<10) +#define PARSING_FLAGS_TCP_OPTIONS_EXIST_SHIFT 10 +#define PARSING_FLAGS_TIME_STAMP_EXIST_FLAG (0x1<<11) +#define PARSING_FLAGS_TIME_STAMP_EXIST_FLAG_SHIFT 11 +#define PARSING_FLAGS_CONNECTION_MATCH (0x1<<12) +#define PARSING_FLAGS_CONNECTION_MATCH_SHIFT 12 +#define PARSING_FLAGS_LLC_SNAP (0x1<<13) +#define PARSING_FLAGS_LLC_SNAP_SHIFT 13 +#define PARSING_FLAGS_RESERVED0 (0x3<<14) +#define PARSING_FLAGS_RESERVED0_SHIFT 14 +}; + + +/* + * dmae command structure + */ +struct dmae_command { + u32 opcode; +#define DMAE_COMMAND_SRC (0x1<<0) +#define DMAE_COMMAND_SRC_SHIFT 0 +#define DMAE_COMMAND_DST (0x3<<1) +#define DMAE_COMMAND_DST_SHIFT 1 +#define DMAE_COMMAND_C_DST (0x1<<3) +#define DMAE_COMMAND_C_DST_SHIFT 3 +#define DMAE_COMMAND_C_TYPE_ENABLE (0x1<<4) +#define DMAE_COMMAND_C_TYPE_ENABLE_SHIFT 4 +#define DMAE_COMMAND_C_TYPE_CRC_ENABLE (0x1<<5) +#define DMAE_COMMAND_C_TYPE_CRC_ENABLE_SHIFT 5 +#define DMAE_COMMAND_C_TYPE_CRC_OFFSET (0x7<<6) +#define DMAE_COMMAND_C_TYPE_CRC_OFFSET_SHIFT 6 +#define DMAE_COMMAND_ENDIANITY (0x3<<9) +#define DMAE_COMMAND_ENDIANITY_SHIFT 9 +#define DMAE_COMMAND_PORT (0x1<<11) +#define DMAE_COMMAND_PORT_SHIFT 11 +#define DMAE_COMMAND_CRC_RESET (0x1<<12) +#define DMAE_COMMAND_CRC_RESET_SHIFT 12 +#define DMAE_COMMAND_SRC_RESET (0x1<<13) +#define DMAE_COMMAND_SRC_RESET_SHIFT 13 +#define DMAE_COMMAND_DST_RESET (0x1<<14) +#define DMAE_COMMAND_DST_RESET_SHIFT 14 +#define DMAE_COMMAND_RESERVED0 (0x1FFFF<<15) +#define DMAE_COMMAND_RESERVED0_SHIFT 15 + u32 src_addr_lo; + u32 src_addr_hi; + u32 dst_addr_lo; + u32 dst_addr_hi; +#if defined(__BIG_ENDIAN) + u16 reserved1; + u16 len; +#elif defined(__LITTLE_ENDIAN) + u16 len; + u16 reserved1; +#endif + u32 comp_addr_lo; + u32 comp_addr_hi; + u32 comp_val; + u32 crc32; + u32 crc32_c; +#if defined(__BIG_ENDIAN) + u16 crc16_c; + u16 crc16; +#elif defined(__LITTLE_ENDIAN) + u16 crc16; + u16 crc16_c; +#endif +#if defined(__BIG_ENDIAN) + u16 reserved2; + u16 crc_t10; +#elif defined(__LITTLE_ENDIAN) + u16 crc_t10; + u16 reserved2; +#endif +#if defined(__BIG_ENDIAN) + u16 xsum8; + u16 xsum16; +#elif defined(__LITTLE_ENDIAN) + u16 xsum16; + u16 xsum8; +#endif +}; + + +struct double_regpair { + u32 regpair0_lo; + u32 regpair0_hi; + u32 regpair1_lo; + u32 regpair1_hi; +}; + + +/* + * The eth Rx Buffer Descriptor + */ +struct eth_rx_bd { + u32 addr_lo; + u32 addr_hi; +}; + +/* + * The eth storm context of Ustorm + */ +struct ustorm_eth_st_context { +#if defined(__BIG_ENDIAN) + u8 sb_index_number; + u8 status_block_id; + u8 __local_rx_bd_cons; + u8 __local_rx_bd_prod; +#elif defined(__LITTLE_ENDIAN) + u8 __local_rx_bd_prod; + u8 __local_rx_bd_cons; + u8 status_block_id; + u8 sb_index_number; +#endif +#if defined(__BIG_ENDIAN) + u16 rcq_cons; + u16 rx_bd_cons; +#elif defined(__LITTLE_ENDIAN) + u16 rx_bd_cons; + u16 rcq_cons; +#endif + u32 rx_bd_page_base_lo; + u32 rx_bd_page_base_hi; + u32 rcq_base_address_lo; + u32 rcq_base_address_hi; +#if defined(__BIG_ENDIAN) + u16 __num_of_returned_cqes; + u8 num_rss; + u8 flags; +#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT (0x1<<0) +#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT_SHIFT 0 +#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC (0x1<<1) +#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC_SHIFT 1 +#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA (0x1<<2) +#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA_SHIFT 2 +#define __USTORM_ETH_ST_CONTEXT_RESERVED0 (0x1F<<3) +#define __USTORM_ETH_ST_CONTEXT_RESERVED0_SHIFT 3 +#elif defined(__LITTLE_ENDIAN) + u8 flags; +#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT (0x1<<0) +#define USTORM_ETH_ST_CONTEXT_ENABLE_MC_ALIGNMENT_SHIFT 0 +#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC (0x1<<1) +#define USTORM_ETH_ST_CONTEXT_ENABLE_DYNAMIC_HC_SHIFT 1 +#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA (0x1<<2) +#define USTORM_ETH_ST_CONTEXT_ENABLE_TPA_SHIFT 2 +#define __USTORM_ETH_ST_CONTEXT_RESERVED0 (0x1F<<3) +#define __USTORM_ETH_ST_CONTEXT_RESERVED0_SHIFT 3 + u8 num_rss; + u16 __num_of_returned_cqes; +#endif +#if defined(__BIG_ENDIAN) + u16 mc_alignment_size; + u16 agg_threshold; +#elif defined(__LITTLE_ENDIAN) + u16 agg_threshold; + u16 mc_alignment_size; +#endif + struct eth_rx_bd __local_bd_ring[16]; +}; + +/* + * The eth storm context of Tstorm + */ +struct tstorm_eth_st_context { + u32 __reserved0[28]; +}; + +/* + * The eth aggregative context section of Xstorm + */ +struct xstorm_eth_extra_ag_context_section { +#if defined(__BIG_ENDIAN) + u8 __tcp_agg_vars1; + u8 __reserved50; + u16 __mss; +#elif defined(__LITTLE_ENDIAN) + u16 __mss; + u8 __reserved50; + u8 __tcp_agg_vars1; +#endif + u32 __snd_nxt; + u32 __tx_wnd; + u32 __snd_una; + u32 __reserved53; +#if defined(__BIG_ENDIAN) + u8 __agg_val8_th; + u8 __agg_val8; + u16 __tcp_agg_vars2; +#elif defined(__LITTLE_ENDIAN) + u16 __tcp_agg_vars2; + u8 __agg_val8; + u8 __agg_val8_th; +#endif + u32 __reserved58; + u32 __reserved59; + u32 __reserved60; + u32 __reserved61; +#if defined(__BIG_ENDIAN) + u16 __agg_val7_th; + u16 __agg_val7; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val7; + u16 __agg_val7_th; +#endif +#if defined(__BIG_ENDIAN) + u8 __tcp_agg_vars5; + u8 __tcp_agg_vars4; + u8 __tcp_agg_vars3; + u8 __reserved62; +#elif defined(__LITTLE_ENDIAN) + u8 __reserved62; + u8 __tcp_agg_vars3; + u8 __tcp_agg_vars4; + u8 __tcp_agg_vars5; +#endif + u32 __tcp_agg_vars6; +#if defined(__BIG_ENDIAN) + u16 __agg_misc6; + u16 __tcp_agg_vars7; +#elif defined(__LITTLE_ENDIAN) + u16 __tcp_agg_vars7; + u16 __agg_misc6; +#endif + u32 __agg_val10; + u32 __agg_val10_th; +#if defined(__BIG_ENDIAN) + u16 __reserved3; + u8 __reserved2; + u8 __agg_misc7; +#elif defined(__LITTLE_ENDIAN) + u8 __agg_misc7; + u8 __reserved2; + u16 __reserved3; +#endif +}; + +/* + * The eth aggregative context of Xstorm + */ +struct xstorm_eth_ag_context { +#if defined(__BIG_ENDIAN) + u16 __bd_prod; + u8 __agg_vars1; + u8 __state; +#elif defined(__LITTLE_ENDIAN) + u8 __state; + u8 __agg_vars1; + u16 __bd_prod; +#endif +#if defined(__BIG_ENDIAN) + u8 cdu_reserved; + u8 __agg_vars4; + u8 __agg_vars3; + u8 __agg_vars2; +#elif defined(__LITTLE_ENDIAN) + u8 __agg_vars2; + u8 __agg_vars3; + u8 __agg_vars4; + u8 cdu_reserved; +#endif + u32 __more_packets_to_send; +#if defined(__BIG_ENDIAN) + u16 __agg_vars5; + u16 __agg_val4_th; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val4_th; + u16 __agg_vars5; +#endif + struct xstorm_eth_extra_ag_context_section __extra_section; +#if defined(__BIG_ENDIAN) + u16 __agg_vars7; + u8 __agg_val3_th; + u8 __agg_vars6; +#elif defined(__LITTLE_ENDIAN) + u8 __agg_vars6; + u8 __agg_val3_th; + u16 __agg_vars7; +#endif +#if defined(__BIG_ENDIAN) + u16 __agg_val11_th; + u16 __agg_val11; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val11; + u16 __agg_val11_th; +#endif +#if defined(__BIG_ENDIAN) + u8 __reserved1; + u8 __agg_val6_th; + u16 __agg_val9; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val9; + u8 __agg_val6_th; + u8 __reserved1; +#endif +#if defined(__BIG_ENDIAN) + u16 __agg_val2_th; + u16 __agg_val2; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val2; + u16 __agg_val2_th; +#endif + u32 __agg_vars8; +#if defined(__BIG_ENDIAN) + u16 __agg_misc0; + u16 __agg_val4; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val4; + u16 __agg_misc0; +#endif +#if defined(__BIG_ENDIAN) + u8 __agg_val3; + u8 __agg_val6; + u8 __agg_val5_th; + u8 __agg_val5; +#elif defined(__LITTLE_ENDIAN) + u8 __agg_val5; + u8 __agg_val5_th; + u8 __agg_val6; + u8 __agg_val3; +#endif +#if defined(__BIG_ENDIAN) + u16 __agg_misc1; + u16 __bd_ind_max_val; +#elif defined(__LITTLE_ENDIAN) + u16 __bd_ind_max_val; + u16 __agg_misc1; +#endif + u32 __reserved57; + u32 __agg_misc4; + u32 __agg_misc5; +}; + +/* + * The eth aggregative context section of Tstorm + */ +struct tstorm_eth_extra_ag_context_section { + u32 __agg_val1; +#if defined(__BIG_ENDIAN) + u8 __tcp_agg_vars2; + u8 __agg_val3; + u16 __agg_val2; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val2; + u8 __agg_val3; + u8 __tcp_agg_vars2; +#endif +#if defined(__BIG_ENDIAN) + u16 __agg_val5; + u8 __agg_val6; + u8 __tcp_agg_vars3; +#elif defined(__LITTLE_ENDIAN) + u8 __tcp_agg_vars3; + u8 __agg_val6; + u16 __agg_val5; +#endif + u32 __reserved63; + u32 __reserved64; + u32 __reserved65; + u32 __reserved66; + u32 __reserved67; + u32 __tcp_agg_vars1; + u32 __reserved61; + u32 __reserved62; + u32 __reserved2; +}; + +/* + * The eth aggregative context of Tstorm + */ +struct tstorm_eth_ag_context { +#if defined(__BIG_ENDIAN) + u16 __reserved54; + u8 __agg_vars1; + u8 __state; +#elif defined(__LITTLE_ENDIAN) + u8 __state; + u8 __agg_vars1; + u16 __reserved54; +#endif +#if defined(__BIG_ENDIAN) + u16 __agg_val4; + u16 __agg_vars2; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_vars2; + u16 __agg_val4; +#endif + struct tstorm_eth_extra_ag_context_section __extra_section; +}; + +/* + * The eth aggregative context of Cstorm + */ +struct cstorm_eth_ag_context { + u32 __agg_vars1; +#if defined(__BIG_ENDIAN) + u8 __aux1_th; + u8 __aux1_val; + u16 __agg_vars2; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_vars2; + u8 __aux1_val; + u8 __aux1_th; +#endif + u32 __num_of_treated_packet; + u32 __last_packet_treated; +#if defined(__BIG_ENDIAN) + u16 __reserved58; + u16 __reserved57; +#elif defined(__LITTLE_ENDIAN) + u16 __reserved57; + u16 __reserved58; +#endif +#if defined(__BIG_ENDIAN) + u8 __reserved62; + u8 __reserved61; + u8 __reserved60; + u8 __reserved59; +#elif defined(__LITTLE_ENDIAN) + u8 __reserved59; + u8 __reserved60; + u8 __reserved61; + u8 __reserved62; +#endif +#if defined(__BIG_ENDIAN) + u16 __reserved64; + u16 __reserved63; +#elif defined(__LITTLE_ENDIAN) + u16 __reserved63; + u16 __reserved64; +#endif + u32 __reserved65; +#if defined(__BIG_ENDIAN) + u16 __agg_vars3; + u16 __rq_inv_cnt; +#elif defined(__LITTLE_ENDIAN) + u16 __rq_inv_cnt; + u16 __agg_vars3; +#endif +#if defined(__BIG_ENDIAN) + u16 __packet_index_th; + u16 __packet_index; +#elif defined(__LITTLE_ENDIAN) + u16 __packet_index; + u16 __packet_index_th; +#endif +}; + +/* + * The eth aggregative context of Ustorm + */ +struct ustorm_eth_ag_context { +#if defined(__BIG_ENDIAN) + u8 __aux_counter_flags; + u8 __agg_vars2; + u8 __agg_vars1; + u8 __state; +#elif defined(__LITTLE_ENDIAN) + u8 __state; + u8 __agg_vars1; + u8 __agg_vars2; + u8 __aux_counter_flags; +#endif +#if defined(__BIG_ENDIAN) + u8 cdu_usage; + u8 __agg_misc2; + u16 __agg_misc1; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_misc1; + u8 __agg_misc2; + u8 cdu_usage; +#endif + u32 __agg_misc4; +#if defined(__BIG_ENDIAN) + u8 __agg_val3_th; + u8 __agg_val3; + u16 __agg_misc3; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_misc3; + u8 __agg_val3; + u8 __agg_val3_th; +#endif + u32 __agg_val1; + u32 __agg_misc4_th; +#if defined(__BIG_ENDIAN) + u16 __agg_val2_th; + u16 __agg_val2; +#elif defined(__LITTLE_ENDIAN) + u16 __agg_val2; + u16 __agg_val2_th; +#endif +#if defined(__BIG_ENDIAN) + u16 __reserved2; + u8 __decision_rules; + u8 __decision_rule_enable_bits; +#elif defined(__LITTLE_ENDIAN) + u8 __decision_rule_enable_bits; + u8 __decision_rules; + u16 __reserved2; +#endif +}; + +/* + * Timers connection context + */ +struct timers_block_context { + u32 __reserved_0; + u32 __reserved_1; + u32 __reserved_2; + u32 __reserved_flags; +}; + +/* + * structure for easy accessability to assembler + */ +struct eth_tx_bd_flags { + u8 as_bitfield; +#define ETH_TX_BD_FLAGS_VLAN_TAG (0x1<<0) +#define ETH_TX_BD_FLAGS_VLAN_TAG_SHIFT 0 +#define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<1) +#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 1 +#define ETH_TX_BD_FLAGS_TCP_CSUM (0x1<<2) +#define ETH_TX_BD_FLAGS_TCP_CSUM_SHIFT 2 +#define ETH_TX_BD_FLAGS_END_BD (0x1<<3) +#define ETH_TX_BD_FLAGS_END_BD_SHIFT 3 +#define ETH_TX_BD_FLAGS_START_BD (0x1<<4) +#define ETH_TX_BD_FLAGS_START_BD_SHIFT 4 +#define ETH_TX_BD_FLAGS_HDR_POOL (0x1<<5) +#define ETH_TX_BD_FLAGS_HDR_POOL_SHIFT 5 +#define ETH_TX_BD_FLAGS_SW_LSO (0x1<<6) +#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT 6 +#define ETH_TX_BD_FLAGS_IPV6 (0x1<<7) +#define ETH_TX_BD_FLAGS_IPV6_SHIFT 7 +}; + +/* + * The eth Tx Buffer Descriptor + */ +struct eth_tx_bd { + u32 addr_lo; + u32 addr_hi; + u16 nbd; + u16 nbytes; + u16 vlan; + struct eth_tx_bd_flags bd_flags; + u8 general_data; +#define ETH_TX_BD_HDR_NBDS (0x3F<<0) +#define ETH_TX_BD_HDR_NBDS_SHIFT 0 +#define ETH_TX_BD_ETH_ADDR_TYPE (0x3<<6) +#define ETH_TX_BD_ETH_ADDR_TYPE_SHIFT 6 +}; + +/* + * Tx parsing BD structure for ETH,Relevant in START + */ +struct eth_tx_parse_bd { + u8 global_data; +#define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET (0xF<<0) +#define ETH_TX_PARSE_BD_IP_HDR_START_OFFSET_SHIFT 0 +#define ETH_TX_PARSE_BD_CS_ANY_FLG (0x1<<4) +#define ETH_TX_PARSE_BD_CS_ANY_FLG_SHIFT 4 +#define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN (0x1<<5) +#define ETH_TX_PARSE_BD_PSEUDO_CS_WITHOUT_LEN_SHIFT 5 +#define ETH_TX_PARSE_BD_LLC_SNAP_EN (0x1<<6) +#define ETH_TX_PARSE_BD_LLC_SNAP_EN_SHIFT 6 +#define ETH_TX_PARSE_BD_NS_FLG (0x1<<7) +#define ETH_TX_PARSE_BD_NS_FLG_SHIFT 7 + u8 tcp_flags; +#define ETH_TX_PARSE_BD_FIN_FLG (0x1<<0) +#define ETH_TX_PARSE_BD_FIN_FLG_SHIFT 0 +#define ETH_TX_PARSE_BD_SYN_FLG (0x1<<1) +#define ETH_TX_PARSE_BD_SYN_FLG_SHIFT 1 +#define ETH_TX_PARSE_BD_RST_FLG (0x1<<2) +#define ETH_TX_PARSE_BD_RST_FLG_SHIFT 2 +#define ETH_TX_PARSE_BD_PSH_FLG (0x1<<3) +#define ETH_TX_PARSE_BD_PSH_FLG_SHIFT 3 +#define ETH_TX_PARSE_BD_ACK_FLG (0x1<<4) +#define ETH_TX_PARSE_BD_ACK_FLG_SHIFT 4 +#define ETH_TX_PARSE_BD_URG_FLG (0x1<<5) +#define ETH_TX_PARSE_BD_URG_FLG_SHIFT 5 +#define ETH_TX_PARSE_BD_ECE_FLG (0x1<<6) +#define ETH_TX_PARSE_BD_ECE_FLG_SHIFT 6 +#define ETH_TX_PARSE_BD_CWR_FLG (0x1<<7) +#define ETH_TX_PARSE_BD_CWR_FLG_SHIFT 7 + u8 ip_hlen; + s8 cs_offset; + u16 total_hlen; + u16 lso_mss; + u16 tcp_pseudo_csum; + u16 ip_id; + u32 tcp_send_seq; +}; + +/* + * The last BD in the BD memory will hold a pointer to the next BD memory + */ +struct eth_tx_next_bd { + u32 addr_lo; + u32 addr_hi; + u8 reserved[8]; +}; + +/* + * union for 3 Bd types + */ +union eth_tx_bd_types { + struct eth_tx_bd reg_bd; + struct eth_tx_parse_bd parse_bd; + struct eth_tx_next_bd next_bd; +}; + +/* + * The eth storm context of Xstorm + */ +struct xstorm_eth_st_context { + u32 tx_bd_page_base_lo; + u32 tx_bd_page_base_hi; +#if defined(__BIG_ENDIAN) + u16 tx_bd_cons; + u8 __reserved0; + u8 __local_tx_bd_prod; +#elif defined(__LITTLE_ENDIAN) + u8 __local_tx_bd_prod; + u8 __reserved0; + u16 tx_bd_cons; +#endif + u32 db_data_addr_lo; + u32 db_data_addr_hi; + u32 __pkt_cons; + u32 __gso_next; + u32 is_eth_conn_1b; + union eth_tx_bd_types __bds[13]; +}; + +/* + * The eth storm context of Cstorm + */ +struct cstorm_eth_st_context { +#if defined(__BIG_ENDIAN) + u16 __reserved0; + u8 sb_index_number; + u8 status_block_id; +#elif defined(__LITTLE_ENDIAN) + u8 status_block_id; + u8 sb_index_number; + u16 __reserved0; +#endif + u32 __reserved1[3]; +}; + +/* + * Ethernet connection context + */ +struct eth_context { + struct ustorm_eth_st_context ustorm_st_context; + struct tstorm_eth_st_context tstorm_st_context; + struct xstorm_eth_ag_context xstorm_ag_context; + struct tstorm_eth_ag_context tstorm_ag_context; + struct cstorm_eth_ag_context cstorm_ag_context; + struct ustorm_eth_ag_context ustorm_ag_context; + struct timers_block_context timers_context; + struct xstorm_eth_st_context xstorm_st_context; + struct cstorm_eth_st_context cstorm_st_context; +}; + + +/* + * ethernet doorbell + */ +struct eth_tx_doorbell { +#if defined(__BIG_ENDIAN) + u16 npackets; + u8 params; +#define ETH_TX_DOORBELL_NUM_BDS (0x3F<<0) +#define ETH_TX_DOORBELL_NUM_BDS_SHIFT 0 +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG (0x1<<6) +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG_SHIFT 6 +#define ETH_TX_DOORBELL_SPARE (0x1<<7) +#define ETH_TX_DOORBELL_SPARE_SHIFT 7 + struct doorbell_hdr hdr; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr hdr; + u8 params; +#define ETH_TX_DOORBELL_NUM_BDS (0x3F<<0) +#define ETH_TX_DOORBELL_NUM_BDS_SHIFT 0 +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG (0x1<<6) +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG_SHIFT 6 +#define ETH_TX_DOORBELL_SPARE (0x1<<7) +#define ETH_TX_DOORBELL_SPARE_SHIFT 7 + u16 npackets; +#endif +}; + + +/* + * ustorm status block + */ +struct ustorm_def_status_block { + u16 index_values[HC_USTORM_DEF_SB_NUM_INDICES]; + u16 status_block_index; + u8 reserved0; + u8 status_block_id; + u32 __flags; +}; + +/* + * cstorm status block + */ +struct cstorm_def_status_block { + u16 index_values[HC_CSTORM_DEF_SB_NUM_INDICES]; + u16 status_block_index; + u8 reserved0; + u8 status_block_id; + u32 __flags; +}; + +/* + * xstorm status block + */ +struct xstorm_def_status_block { + u16 index_values[HC_XSTORM_DEF_SB_NUM_INDICES]; + u16 status_block_index; + u8 reserved0; + u8 status_block_id; + u32 __flags; +}; + +/* + * tstorm status block + */ +struct tstorm_def_status_block { + u16 index_values[HC_TSTORM_DEF_SB_NUM_INDICES]; + u16 status_block_index; + u8 reserved0; + u8 status_block_id; + u32 __flags; +}; + +/* + * host status block + */ +struct host_def_status_block { + struct atten_def_status_block atten_status_block; + struct ustorm_def_status_block u_def_status_block; + struct cstorm_def_status_block c_def_status_block; + struct xstorm_def_status_block x_def_status_block; + struct tstorm_def_status_block t_def_status_block; +}; + + +/* + * ustorm status block + */ +struct ustorm_status_block { + u16 index_values[HC_USTORM_SB_NUM_INDICES]; + u16 status_block_index; + u8 reserved0; + u8 status_block_id; + u32 __flags; +}; + +/* + * cstorm status block + */ +struct cstorm_status_block { + u16 index_values[HC_CSTORM_SB_NUM_INDICES]; + u16 status_block_index; + u8 reserved0; + u8 status_block_id; + u32 __flags; +}; + +/* + * host status block + */ +struct host_status_block { + struct ustorm_status_block u_status_block; + struct cstorm_status_block c_status_block; +}; + + +/* + * The data for RSS setup ramrod + */ +struct eth_client_setup_ramrod_data { + u32 client_id_5b; + u8 is_rdma_1b; + u8 reserved0; + u16 reserved1; +}; + + +/* + * L2 dynamic host coalescing init parameters + */ +struct eth_dynamic_hc_config { + u32 threshold[3]; + u8 hc_timeout[4]; +}; + + +/* + * regular eth FP CQE parameters struct + */ +struct eth_fast_path_rx_cqe { + u8 type; + u8 error_type_flags; +#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<0) +#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 0 +#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<1) +#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 1 +#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<2) +#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 2 +#define ETH_FAST_PATH_RX_CQE_START_FLG (0x1<<3) +#define ETH_FAST_PATH_RX_CQE_START_FLG_SHIFT 3 +#define ETH_FAST_PATH_RX_CQE_END_FLG (0x1<<4) +#define ETH_FAST_PATH_RX_CQE_END_FLG_SHIFT 4 +#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x7<<5) +#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 5 + u8 status_flags; +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0) +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0 +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3) +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3 +#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4) +#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4 +#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5) +#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5 +#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6) +#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6 +#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7) +#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7 + u8 placement_offset; + u32 rss_hash_result; + u16 vlan_tag; + u16 pkt_len; + u16 queue_index; + struct parsing_flags pars_flags; +}; + + +/* + * The data for RSS setup ramrod + */ +struct eth_halt_ramrod_data { + u32 client_id_5b; + u32 reserved0; +}; + + +/* + * Place holder for ramrods protocol specific data + */ +struct ramrod_data { + u32 data_lo; + u32 data_hi; +}; + +/* + * union for ramrod data for ethernet protocol (CQE) (force size of 16 bits) + */ +union eth_ramrod_data { + struct ramrod_data general; +}; + + +/* + * Rx Last BD in page (in ETH) + */ +struct eth_rx_bd_next_page { + u32 addr_lo; + u32 addr_hi; + u8 reserved[8]; +}; + + +/* + * Eth Rx Cqe structure- general structure for ramrods + */ +struct common_ramrod_eth_rx_cqe { + u8 type; + u8 conn_type_3b; + u16 reserved; + u32 conn_and_cmd_data; +#define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0) +#define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0 +#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24) +#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24 + struct ramrod_data protocol_data; +}; + +/* + * Rx Last CQE in page (in ETH) + */ +struct eth_rx_cqe_next_page { + u32 addr_lo; + u32 addr_hi; + u32 reserved0; + u32 reserved1; +}; + +/* + * union for all eth rx cqe types (fix their sizes) + */ +union eth_rx_cqe { + struct eth_fast_path_rx_cqe fast_path_cqe; + struct common_ramrod_eth_rx_cqe ramrod_cqe; + struct eth_rx_cqe_next_page next_page_cqe; +}; + + +/* + * common data for all protocols + */ +struct spe_hdr { + u32 conn_and_cmd_data; +#define SPE_HDR_CID (0xFFFFFF<<0) +#define SPE_HDR_CID_SHIFT 0 +#define SPE_HDR_CMD_ID (0xFF<<24) +#define SPE_HDR_CMD_ID_SHIFT 24 + u16 type; +#define SPE_HDR_CONN_TYPE (0xFF<<0) +#define SPE_HDR_CONN_TYPE_SHIFT 0 +#define SPE_HDR_COMMON_RAMROD (0xFF<<8) +#define SPE_HDR_COMMON_RAMROD_SHIFT 8 + u16 reserved; +}; + +struct regpair { + u32 lo; + u32 hi; +}; + +/* + * ethernet slow path element + */ +union eth_specific_data { + u8 protocol_data[8]; + struct regpair mac_config_addr; + struct eth_client_setup_ramrod_data client_setup_ramrod_data; + struct eth_halt_ramrod_data halt_ramrod_data; + struct regpair leading_cqe_addr; + struct regpair update_data_addr; +}; + +/* + * ethernet slow path element + */ +struct eth_spe { + struct spe_hdr hdr; + union eth_specific_data data; +}; + + +/* + * doorbell data in host memory + */ +struct eth_tx_db_data { + u32 packets_prod; + u16 bds_prod; + u16 reserved; +}; + + +/* + * Common configuration parameters per port in Tstorm + */ +struct tstorm_eth_function_common_config { + u32 config_flags; +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY_SHIFT 0 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY (0x1<<1) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY_SHIFT 1 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY (0x1<<2) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY_SHIFT 2 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY (0x1<<3) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY_SHIFT 3 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE (0x1<<4) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_ENABLE_SHIFT 4 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE (0x1<<5) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_DEFAULT_ENABLE_SHIFT 5 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0x3FFFFFF<<6) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 6 +#if defined(__BIG_ENDIAN) + u16 __secondary_vlan_id; + u8 leading_client_id; + u8 rss_result_mask; +#elif defined(__LITTLE_ENDIAN) + u8 rss_result_mask; + u8 leading_client_id; + u16 __secondary_vlan_id; +#endif +}; + +/* + * parameters for eth update ramrod + */ +struct eth_update_ramrod_data { + struct tstorm_eth_function_common_config func_config; + u8 indirectionTable[128]; +}; + + +/* + * MAC filtering configuration command header + */ +struct mac_configuration_hdr { + u8 length_6b; + u8 offset; + u16 reserved0; + u32 reserved1; +}; + +/* + * MAC address in list for ramrod + */ +struct tstorm_cam_entry { + u16 lsb_mac_addr; + u16 middle_mac_addr; + u16 msb_mac_addr; + u16 flags; +#define TSTORM_CAM_ENTRY_PORT_ID (0x1<<0) +#define TSTORM_CAM_ENTRY_PORT_ID_SHIFT 0 +#define TSTORM_CAM_ENTRY_RSRVVAL0 (0x7<<1) +#define TSTORM_CAM_ENTRY_RSRVVAL0_SHIFT 1 +#define TSTORM_CAM_ENTRY_RESERVED0 (0xFFF<<4) +#define TSTORM_CAM_ENTRY_RESERVED0_SHIFT 4 +}; + +/* + * MAC filtering: CAM target table entry + */ +struct tstorm_cam_target_table_entry { + u8 flags; +#define TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST (0x1<<0) +#define TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST_SHIFT 0 +#define TSTORM_CAM_TARGET_TABLE_ENTRY_OVERRIDE_VLAN_REMOVAL (0x1<<1) +#define TSTORM_CAM_TARGET_TABLE_ENTRY_OVERRIDE_VLAN_REMOVAL_SHIFT 1 +#define TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE (0x1<<2) +#define TSTORM_CAM_TARGET_TABLE_ENTRY_ACTION_TYPE_SHIFT 2 +#define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC (0x1<<3) +#define TSTORM_CAM_TARGET_TABLE_ENTRY_RDMA_MAC_SHIFT 3 +#define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0 (0xF<<4) +#define TSTORM_CAM_TARGET_TABLE_ENTRY_RESERVED0_SHIFT 4 + u8 client_id; + u16 vlan_id; +}; + +/* + * MAC address in list for ramrod + */ +struct mac_configuration_entry { + struct tstorm_cam_entry cam_entry; + struct tstorm_cam_target_table_entry target_table_entry; +}; + +/* + * MAC filtering configuration command + */ +struct mac_configuration_cmd { + struct mac_configuration_hdr hdr; + struct mac_configuration_entry config_table[64]; +}; + + +/* + * Configuration parameters per client in Tstorm + */ +struct tstorm_eth_client_config { +#if defined(__BIG_ENDIAN) + u16 statistics_counter_id; + u16 mtu; +#elif defined(__LITTLE_ENDIAN) + u16 mtu; + u16 statistics_counter_id; +#endif +#if defined(__BIG_ENDIAN) + u16 drop_flags; +#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR (0x1<<2) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR_SHIFT 2 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<3) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 3 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<4) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x7FF<<5) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 5 + u16 config_flags; +#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE (0x1<<0) +#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE_SHIFT 0 +#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<1) +#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 1 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x3FFF<<2) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 2 +#elif defined(__LITTLE_ENDIAN) + u16 config_flags; +#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE (0x1<<0) +#define TSTORM_ETH_CLIENT_CONFIG_VLAN_REMOVAL_ENABLE_SHIFT 0 +#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE (0x1<<1) +#define TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE_SHIFT 1 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0 (0x3FFF<<2) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED0_SHIFT 2 + u16 drop_flags; +#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR (0x1<<0) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_IP_CS_ERR_SHIFT 0 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR (0x1<<1) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TCP_CS_ERR_SHIFT 1 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR (0x1<<2) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_MAC_ERR_SHIFT 2 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0 (0x1<<3) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_TTL0_SHIFT 3 +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR (0x1<<4) +#define TSTORM_ETH_CLIENT_CONFIG_DROP_UDP_CS_ERR_SHIFT 4 +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1 (0x7FF<<5) +#define __TSTORM_ETH_CLIENT_CONFIG_RESERVED1_SHIFT 5 +#endif +}; + + +/* + * MAC filtering configuration parameters per port in Tstorm + */ +struct tstorm_eth_mac_filter_config { + u32 ucast_drop_all; + u32 ucast_accept_all; + u32 mcast_drop_all; + u32 mcast_accept_all; + u32 bcast_drop_all; + u32 bcast_accept_all; + u32 strict_vlan; + u32 __secondary_vlan_clients; +}; + + +struct rate_shaping_per_protocol { +#if defined(__BIG_ENDIAN) + u16 reserved0; + u16 protocol_rate; +#elif defined(__LITTLE_ENDIAN) + u16 protocol_rate; + u16 reserved0; +#endif + u32 protocol_quota; + s32 current_credit; + u32 reserved; +}; + +struct rate_shaping_vars { + struct rate_shaping_per_protocol protocol_vars[NUM_OF_PROTOCOLS]; + u32 pause_mask; + u32 periodic_stop; + u32 rs_periodic_timeout; + u32 rs_threshold; + u32 last_periodic_time; + u32 reserved; +}; + +struct fairness_per_protocol { + u32 credit_delta; + s32 fair_credit; +#if defined(__BIG_ENDIAN) + u16 reserved0; + u8 state; + u8 weight; +#elif defined(__LITTLE_ENDIAN) + u8 weight; + u8 state; + u16 reserved0; +#endif + u32 reserved1; +}; + +struct fairness_vars { + struct fairness_per_protocol protocol_vars[NUM_OF_PROTOCOLS]; + u32 upper_bound; + u32 port_rate; + u32 pause_mask; + u32 fair_threshold; +}; + +struct safc_struct { + u32 cur_pause_mask; + u32 expire_time; +#if defined(__BIG_ENDIAN) + u16 reserved0; + u8 cur_cos_types; + u8 safc_timeout_usec; +#elif defined(__LITTLE_ENDIAN) + u8 safc_timeout_usec; + u8 cur_cos_types; + u16 reserved0; +#endif + u32 reserved1; +}; + +struct demo_struct { + u8 con_number[NUM_OF_PROTOCOLS]; +#if defined(__BIG_ENDIAN) + u8 reserved1; + u8 fairness_enable; + u8 rate_shaping_enable; + u8 cmng_enable; +#elif defined(__LITTLE_ENDIAN) + u8 cmng_enable; + u8 rate_shaping_enable; + u8 fairness_enable; + u8 reserved1; +#endif +}; + +struct cmng_struct { + struct rate_shaping_vars rs_vars; + struct fairness_vars fair_vars; + struct safc_struct safc_vars; + struct demo_struct demo_vars; +}; + + +struct cos_to_protocol { + u8 mask[MAX_COS_NUMBER]; +}; + + +/* + * Common statistics collected by the Xstorm (per port) + */ +struct xstorm_common_stats { + struct regpair total_sent_bytes; + u32 total_sent_pkts; + u32 unicast_pkts_sent; + struct regpair unicast_bytes_sent; + struct regpair multicast_bytes_sent; + u32 multicast_pkts_sent; + u32 broadcast_pkts_sent; + struct regpair broadcast_bytes_sent; + struct regpair done; +}; + +/* + * Protocol-common statistics collected by the Tstorm (per client) + */ +struct tstorm_per_client_stats { + struct regpair total_rcv_bytes; + struct regpair rcv_unicast_bytes; + struct regpair rcv_broadcast_bytes; + struct regpair rcv_multicast_bytes; + struct regpair rcv_error_bytes; + u32 checksum_discard; + u32 packets_too_big_discard; + u32 total_rcv_pkts; + u32 rcv_unicast_pkts; + u32 rcv_broadcast_pkts; + u32 rcv_multicast_pkts; + u32 no_buff_discard; + u32 ttl0_discard; + u32 mac_discard; + u32 reserved; +}; + +/* + * Protocol-common statistics collected by the Tstorm (per port) + */ +struct tstorm_common_stats { + struct tstorm_per_client_stats client_statistics[MAX_T_STAT_COUNTER_ID]; + u32 mac_filter_discard; + u32 xxoverflow_discard; + u32 brb_truncate_discard; + u32 reserved; + struct regpair done; +}; + +/* + * Eth statistics query sturcture for the eth_stats_quesry ramrod + */ +struct eth_stats_query { + struct xstorm_common_stats xstorm_common; + struct tstorm_common_stats tstorm_common; +}; + + +/* + * FW version stored in the Xstorm RAM + */ +struct fw_version { +#if defined(__BIG_ENDIAN) + u16 patch; + u8 primary; + u8 client; +#elif defined(__LITTLE_ENDIAN) + u8 client; + u8 primary; + u16 patch; +#endif + u32 flags; +#define FW_VERSION_OPTIMIZED (0x1<<0) +#define FW_VERSION_OPTIMIZED_SHIFT 0 +#define FW_VERSION_BIG_ENDIEN (0x1<<1) +#define FW_VERSION_BIG_ENDIEN_SHIFT 1 +#define __FW_VERSION_RESERVED (0x3FFFFFFF<<2) +#define __FW_VERSION_RESERVED_SHIFT 2 +}; + + +/* + * FW version stored in first line of pram + */ +struct pram_fw_version { +#if defined(__BIG_ENDIAN) + u16 patch; + u8 primary; + u8 client; +#elif defined(__LITTLE_ENDIAN) + u8 client; + u8 primary; + u16 patch; +#endif + u8 flags; +#define PRAM_FW_VERSION_OPTIMIZED (0x1<<0) +#define PRAM_FW_VERSION_OPTIMIZED_SHIFT 0 +#define PRAM_FW_VERSION_STORM_ID (0x3<<1) +#define PRAM_FW_VERSION_STORM_ID_SHIFT 1 +#define PRAM_FW_VERSION_BIG_ENDIEN (0x1<<3) +#define PRAM_FW_VERSION_BIG_ENDIEN_SHIFT 3 +#define __PRAM_FW_VERSION_RESERVED0 (0xF<<4) +#define __PRAM_FW_VERSION_RESERVED0_SHIFT 4 +}; + + +/* + * The send queue element + */ +struct slow_path_element { + struct spe_hdr hdr; + u8 protocol_data[8]; +}; + + +/* + * eth/toe flags that indicate if to query + */ +struct stats_indication_flags { + u32 collect_eth; + u32 collect_toe; +}; + + diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h new file mode 100644 index 000000000000..04f93bff2ef4 --- /dev/null +++ b/drivers/net/bnx2x_init.h @@ -0,0 +1,564 @@ +/* bnx2x_init.h: Broadcom Everest network driver. + * + * Copyright (c) 2007 Broadcom Corporation + * + * 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. + * + * Written by: Eliezer Tamir <eliezert@broadcom.com> + */ + +#ifndef BNX2X_INIT_H +#define BNX2X_INIT_H + +#define COMMON 0x1 +#define PORT0 0x2 +#define PORT1 0x4 + +#define INIT_EMULATION 0x1 +#define INIT_FPGA 0x2 +#define INIT_ASIC 0x4 +#define INIT_HARDWARE 0x7 + +#define STORM_INTMEM_SIZE (0x5800 / 4) +#define TSTORM_INTMEM_ADDR 0x1a0000 +#define CSTORM_INTMEM_ADDR 0x220000 +#define XSTORM_INTMEM_ADDR 0x2a0000 +#define USTORM_INTMEM_ADDR 0x320000 + + +/* Init operation types and structures */ + +#define OP_RD 0x1 /* read single register */ +#define OP_WR 0x2 /* write single register */ +#define OP_IW 0x3 /* write single register using mailbox */ +#define OP_SW 0x4 /* copy a string to the device */ +#define OP_SI 0x5 /* copy a string using mailbox */ +#define OP_ZR 0x6 /* clear memory */ +#define OP_ZP 0x7 /* unzip then copy with DMAE */ +#define OP_WB 0x8 /* copy a string using DMAE */ + +struct raw_op { + u32 op :8; + u32 offset :24; + u32 raw_data; +}; + +struct op_read { + u32 op :8; + u32 offset :24; + u32 pad; +}; + +struct op_write { + u32 op :8; + u32 offset :24; + u32 val; +}; + +struct op_string_write { + u32 op :8; + u32 offset :24; +#ifdef __LITTLE_ENDIAN + u16 data_off; + u16 data_len; +#else /* __BIG_ENDIAN */ + u16 data_len; + u16 data_off; +#endif +}; + +struct op_zero { + u32 op :8; + u32 offset :24; + u32 len; +}; + +union init_op { + struct op_read read; + struct op_write write; + struct op_string_write str_wr; + struct op_zero zero; + struct raw_op raw; +}; + +#include "bnx2x_init_values.h" + +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); + +static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, + u32 dst_addr, u32 len32); + +static int bnx2x_gunzip(struct bnx2x *bp, u8 *zbuf, int len); + +static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len) +{ + int i; + + for (i = 0; i < len; i++) { + REG_WR(bp, addr + i*4, data[i]); + if (!(i % 10000)) { + touch_softlockup_watchdog(); + cpu_relax(); + } + } +} + +#define INIT_MEM_WR(reg, data, reg_off, len) \ + bnx2x_init_str_wr(bp, reg + reg_off*4, data, len) + +static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data, + u16 len) +{ + int i; + + for (i = 0; i < len; i++) { + REG_WR_IND(bp, addr + i*4, data[i]); + if (!(i % 10000)) { + touch_softlockup_watchdog(); + cpu_relax(); + } + } +} + +static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, const u32 *data, + u32 len, int gunzip) +{ + int offset = 0; + + if (gunzip) { + int rc; +#ifdef __BIG_ENDIAN + int i, size; + u32 *temp; + + temp = kmalloc(len, GFP_KERNEL); + size = (len / 4) + ((len % 4) ? 1 : 0); + for (i = 0; i < size; i++) + temp[i] = swab32(data[i]); + data = temp; +#endif + rc = bnx2x_gunzip(bp, (u8 *)data, len); + if (rc) { + DP(NETIF_MSG_HW, "gunzip failed ! rc %d\n", rc); + return; + } + len = bp->gunzip_outlen; +#ifdef __BIG_ENDIAN + kfree(temp); + for (i = 0; i < len; i++) + ((u32 *)bp->gunzip_buf)[i] = + swab32(((u32 *)bp->gunzip_buf)[i]); +#endif + } else { + if ((len * 4) > FW_BUF_SIZE) { + BNX2X_ERR("LARGE DMAE OPERATION ! len 0x%x\n", len*4); + return; + } + memcpy(bp->gunzip_buf, data, len * 4); + } + + while (len > DMAE_LEN32_MAX) { + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, DMAE_LEN32_MAX); + offset += DMAE_LEN32_MAX * 4; + len -= DMAE_LEN32_MAX; + } + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, addr + offset, len); +} + +#define INIT_MEM_WB(reg, data, reg_off, len) \ + bnx2x_init_wr_wb(bp, reg + reg_off*4, data, len, 0) + +#define INIT_GUNZIP_DMAE(reg, data, reg_off, len) \ + bnx2x_init_wr_wb(bp, reg + reg_off*4, data, len, 1) + +static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) +{ + int offset = 0; + + if ((len * 4) > FW_BUF_SIZE) { + BNX2X_ERR("LARGE DMAE OPERATION ! len 0x%x\n", len * 4); + return; + } + memset(bp->gunzip_buf, fill, len * 4); + + while (len > DMAE_LEN32_MAX) { + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, + addr + offset, DMAE_LEN32_MAX); + offset += DMAE_LEN32_MAX * 4; + len -= DMAE_LEN32_MAX; + } + bnx2x_write_dmae(bp, bp->gunzip_mapping + offset, addr + offset, len); +} + +static void bnx2x_init_block(struct bnx2x *bp, u32 op_start, u32 op_end) +{ + int i; + union init_op *op; + u32 op_type, addr, len; + const u32 *data; + + for (i = op_start; i < op_end; i++) { + + op = (union init_op *)&(init_ops[i]); + + op_type = op->str_wr.op; + addr = op->str_wr.offset; + len = op->str_wr.data_len; + data = init_data + op->str_wr.data_off; + + switch (op_type) { + case OP_RD: + REG_RD(bp, addr); + break; + case OP_WR: + REG_WR(bp, addr, op->write.val); + break; + case OP_SW: + bnx2x_init_str_wr(bp, addr, data, len); + break; + case OP_WB: + bnx2x_init_wr_wb(bp, addr, data, len, 0); + break; + case OP_SI: + bnx2x_init_ind_wr(bp, addr, data, len); + break; + case OP_ZR: + bnx2x_init_fill(bp, addr, 0, op->zero.len); + break; + case OP_ZP: + bnx2x_init_wr_wb(bp, addr, data, len, 1); + break; + default: + BNX2X_ERR("BAD init operation!\n"); + } + } +} + + +/**************************************************************************** +* PXP +****************************************************************************/ +/* + * This code configures the PCI read/write arbiter + * which implements a wighted round robin + * between the virtual queues in the chip. + * + * The values were derived for each PCI max payload and max request size. + * since max payload and max request size are only known at run time, + * this is done as a separate init stage. + */ + +#define NUM_WR_Q 13 +#define NUM_RD_Q 29 +#define MAX_RD_ORD 3 +#define MAX_WR_ORD 2 + +/* configuration for one arbiter queue */ +struct arb_line { + int l; + int add; + int ubound; +}; + +/* derived configuration for each read queue for each max request size */ +static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = { + {{8 , 64 , 25}, {16 , 64 , 25}, {32 , 64 , 25}, {64 , 64 , 41} }, + {{4 , 8 , 4}, {4 , 8 , 4}, {4 , 8 , 4}, {4 , 8 , 4} }, + {{4 , 3 , 3}, {4 , 3 , 3}, {4 , 3 , 3}, {4 , 3 , 3} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {16 , 3 , 11}, {16 , 3 , 11} }, + {{8 , 64 , 25}, {16 , 64 , 25}, {32 , 64 , 25}, {64 , 64 , 41} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {64 , 3 , 41} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {64 , 3 , 41} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {64 , 3 , 41} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {64 , 3 , 41} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 3 , 6}, {16 , 3 , 11}, {32 , 3 , 21}, {32 , 3 , 21} }, + {{8 , 64 , 25}, {16 , 64 , 41}, {32 , 64 , 81}, {64 , 64 , 120} } +}; + +/* derived configuration for each write queue for each max request size */ +static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { + {{4 , 6 , 3}, {4 , 6 , 3}, {4 , 6 , 3} }, + {{4 , 2 , 3}, {4 , 2 , 3}, {4 , 2 , 3} }, + {{8 , 2 , 6}, {16 , 2 , 11}, {16 , 2 , 11} }, + {{8 , 2 , 6}, {16 , 2 , 11}, {32 , 2 , 21} }, + {{8 , 2 , 6}, {16 , 2 , 11}, {32 , 2 , 21} }, + {{8 , 2 , 6}, {16 , 2 , 11}, {32 , 2 , 21} }, + {{8 , 64 , 25}, {16 , 64 , 25}, {32 , 64 , 25} }, + {{8 , 2 , 6}, {16 , 2 , 11}, {16 , 2 , 11} }, + {{8 , 2 , 6}, {16 , 2 , 11}, {16 , 2 , 11} }, + {{8 , 9 , 6}, {16 , 9 , 11}, {32 , 9 , 21} }, + {{8 , 47 , 19}, {16 , 47 , 19}, {32 , 47 , 21} }, + {{8 , 9 , 6}, {16 , 9 , 11}, {16 , 9 , 11} }, + {{8 , 64 , 25}, {16 , 64 , 41}, {32 , 64 , 81} } +}; + +/* register adresses for read queues */ +static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { + {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, + PXP2_REG_RQ_BW_RD_UBOUND0}, + {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4, + PXP2_REG_RQ_BW_RD_UBOUND4}, + {PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5, + PXP2_REG_RQ_BW_RD_UBOUND5}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, + {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, + {PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12, + PXP2_REG_RQ_BW_RD_UBOUND12}, + {PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13, + PXP2_REG_RQ_BW_RD_UBOUND13}, + {PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14, + PXP2_REG_RQ_BW_RD_UBOUND14}, + {PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15, + PXP2_REG_RQ_BW_RD_UBOUND15}, + {PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16, + PXP2_REG_RQ_BW_RD_UBOUND16}, + {PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17, + PXP2_REG_RQ_BW_RD_UBOUND17}, + {PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18, + PXP2_REG_RQ_BW_RD_UBOUND18}, + {PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19, + PXP2_REG_RQ_BW_RD_UBOUND19}, + {PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20, + PXP2_REG_RQ_BW_RD_UBOUND20}, + {PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22, + PXP2_REG_RQ_BW_RD_UBOUND22}, + {PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23, + PXP2_REG_RQ_BW_RD_UBOUND23}, + {PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24, + PXP2_REG_RQ_BW_RD_UBOUND24}, + {PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25, + PXP2_REG_RQ_BW_RD_UBOUND25}, + {PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26, + PXP2_REG_RQ_BW_RD_UBOUND26}, + {PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27, + PXP2_REG_RQ_BW_RD_UBOUND27}, + {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28} +}; + +/* register adresses for wrtie queues */ +static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { + {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, + {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, + {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28}, + {PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29, + PXP2_REG_RQ_BW_WR_UBOUND29}, + {PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30, + PXP2_REG_RQ_BW_WR_UBOUND30} +}; + +static void bnx2x_init_pxp(struct bnx2x *bp) +{ + int r_order, w_order; + u32 val, i; + + pci_read_config_word(bp->pdev, + bp->pcie_cap + PCI_EXP_DEVCTL, (u16 *)&val); + DP(NETIF_MSG_HW, "read 0x%x from devctl\n", val); + w_order = ((val & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + r_order = ((val & PCI_EXP_DEVCTL_READRQ) >> 12); + + if (r_order > MAX_RD_ORD) { + DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", + r_order, MAX_RD_ORD); + r_order = MAX_RD_ORD; + } + if (w_order > MAX_WR_ORD) { + DP(NETIF_MSG_HW, "write order of %d order adjusted to %d\n", + w_order, MAX_WR_ORD); + w_order = MAX_WR_ORD; + } + DP(NETIF_MSG_HW, "read order %d write order %d\n", r_order, w_order); + + for (i = 0; i < NUM_RD_Q-1; i++) { + REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l); + REG_WR(bp, read_arb_addr[i].add, + read_arb_data[i][r_order].add); + REG_WR(bp, read_arb_addr[i].ubound, + read_arb_data[i][r_order].ubound); + } + + for (i = 0; i < NUM_WR_Q-1; i++) { + if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) || + (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) { + + REG_WR(bp, write_arb_addr[i].l, + write_arb_data[i][w_order].l); + + REG_WR(bp, write_arb_addr[i].add, + write_arb_data[i][w_order].add); + + REG_WR(bp, write_arb_addr[i].ubound, + write_arb_data[i][w_order].ubound); + } else { + + val = REG_RD(bp, write_arb_addr[i].l); + REG_WR(bp, write_arb_addr[i].l, + val | (write_arb_data[i][w_order].l << 10)); + + val = REG_RD(bp, write_arb_addr[i].add); + REG_WR(bp, write_arb_addr[i].add, + val | (write_arb_data[i][w_order].add << 10)); + + val = REG_RD(bp, write_arb_addr[i].ubound); + REG_WR(bp, write_arb_addr[i].ubound, + val | (write_arb_data[i][w_order].ubound << 7)); + } + } + + val = write_arb_data[NUM_WR_Q-1][w_order].add; + val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10; + val += write_arb_data[NUM_WR_Q-1][w_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val); + + val = read_arb_data[NUM_RD_Q-1][r_order].add; + val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10; + val += read_arb_data[NUM_RD_Q-1][r_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val); + + REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order); + REG_WR(bp, PXP2_REG_RQ_WR_MBS0 + 8, w_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS0 + 8, r_order); + + REG_WR(bp, PXP2_REG_WR_DMAE_TH, (128 << w_order)/16); +} + + +/**************************************************************************** +* CDU +****************************************************************************/ + +#define CDU_REGION_NUMBER_XCM_AG 2 +#define CDU_REGION_NUMBER_UCM_AG 4 + +/** + * String-to-compress [31:8] = CID (all 24 bits) + * String-to-compress [7:4] = Region + * String-to-compress [3:0] = Type + */ +#define CDU_VALID_DATA(_cid, _region, _type) \ + (((_cid) << 8) | (((_region) & 0xf) << 4) | (((_type) & 0xf))) +#define CDU_CRC8(_cid, _region, _type) \ + calc_crc8(CDU_VALID_DATA(_cid, _region, _type), 0xff) +#define CDU_RSRVD_VALUE_TYPE_A(_cid, _region, _type) \ + (0x80 | (CDU_CRC8(_cid, _region, _type) & 0x7f)) +#define CDU_RSRVD_VALUE_TYPE_B(_crc, _type) \ + (0x80 | ((_type) & 0xf << 3) | (CDU_CRC8(_cid, _region, _type) & 0x7)) +#define CDU_RSRVD_INVALIDATE_CONTEXT_VALUE(_val) ((_val) & ~0x80) + +/***************************************************************************** + * Description: + * Calculates crc 8 on a word value: polynomial 0-1-2-8 + * Code was translated from Verilog. + ****************************************************************************/ +static u8 calc_crc8(u32 data, u8 crc) +{ + u8 D[32]; + u8 NewCRC[8]; + u8 C[8]; + u8 crc_res; + u8 i; + + /* split the data into 31 bits */ + for (i = 0; i < 32; i++) { + D[i] = data & 1; + data = data >> 1; + } + + /* split the crc into 8 bits */ + for (i = 0; i < 8; i++) { + C[i] = crc & 1; + crc = crc >> 1; + } + + NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ + D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ + C[6] ^ C[7]; + NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ + D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ + D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[6]; + NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ + D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ + C[0] ^ C[1] ^ C[4] ^ C[5]; + NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ + D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ + C[1] ^ C[2] ^ C[5] ^ C[6]; + NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ + D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ + C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; + NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ + D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ + C[3] ^ C[4] ^ C[7]; + NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ + D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ + C[5]; + NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ + D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ + C[6]; + + crc_res = 0; + for (i = 0; i < 8; i++) + crc_res |= (NewCRC[i] << i); + + return crc_res; +} + + +#endif /* BNX2X_INIT_H */ + diff --git a/drivers/net/bnx2x_init_values.h b/drivers/net/bnx2x_init_values.h new file mode 100644 index 000000000000..bef0a9b19d68 --- /dev/null +++ b/drivers/net/bnx2x_init_values.h @@ -0,0 +1,6368 @@ +#ifndef __BNX2X_INIT_VALUES_H__ +#define __BNX2X_INIT_VALUES_H__ + +/* This array contains the list of operations needed to initialize the chip. + * + * For each block in the chip there are three init stages: + * common - HW used by both ports, + * port1 and port2 - initialization for a specific Ethernet port. + * When a port is opened or closed, the management CPU tells the driver + * whether to init/disable common HW in addition to the port HW. + * This way the first port going up will first initializes the common HW, + * and the last port going down also resets the common HW + * + * For each init stage/block there is a list of actions needed in a format: + * {operation, register, data} + * where: + * OP_WR - write a value to the chip. + * OP_RD - read a register (usually a clear on read register). + * OP_SW - string write, write a section of consecutive addresses to the chip. + * OP_SI - copy a string using indirect writes. + * OP_ZR - clear a range of memory. + * OP_ZP - unzip and copy using DMAE. + * OP_WB - string copy using DMAE. + * + * The #defines mark the stages. + * + */ + +static const struct raw_op init_ops[] = { +#define PRS_COMMON_START 0 + {OP_WR, PRS_REG_INC_VALUE, 0xf}, + {OP_WR, PRS_REG_EVENT_ID_1, 0x45}, + {OP_WR, PRS_REG_EVENT_ID_2, 0x84}, + {OP_WR, PRS_REG_EVENT_ID_3, 0x6}, + {OP_WR, PRS_REG_NO_MATCH_EVENT_ID, 0x4}, + {OP_WR, PRS_REG_CM_HDR_TYPE_0, 0x0}, + {OP_WR, PRS_REG_CM_HDR_TYPE_1, 0x12170000}, + {OP_WR, PRS_REG_CM_HDR_TYPE_2, 0x22170000}, + {OP_WR, PRS_REG_CM_HDR_TYPE_3, 0x32170000}, + {OP_ZR, PRS_REG_CM_HDR_TYPE_4, 0x5}, + {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_1, 0x12150000}, + {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_2, 0x22150000}, + {OP_WR, PRS_REG_CM_HDR_LOOPBACK_TYPE_3, 0x32150000}, + {OP_ZR, PRS_REG_CM_HDR_LOOPBACK_TYPE_4, 0x4}, + {OP_WR, PRS_REG_CM_NO_MATCH_HDR, 0x2100000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0, 0x100000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1, 0x10100000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2, 0x20100000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3, 0x30100000}, + {OP_ZR, PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4, 0x4}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0, 0x100000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1, 0x12140000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2, 0x22140000}, + {OP_WR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3, 0x32140000}, + {OP_ZR, PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4, 0x4}, + {OP_RD, PRS_REG_NUM_OF_PACKETS, 0x0}, + {OP_RD, PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES, 0x0}, + {OP_RD, PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES, 0x0}, + {OP_RD, PRS_REG_NUM_OF_DEAD_CYCLES, 0x0}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_0, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_1, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_2, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_3, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_4, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_5, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_6, 0xff}, + {OP_WR, PRS_REG_FLUSH_REGIONS_TYPE_7, 0xff}, + {OP_WR, PRS_REG_PURE_REGIONS, 0x3e}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_0, 0x0}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_1, 0x3f}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_2, 0x3f}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_3, 0x3f}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_4, 0x0}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_5, 0x3f}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_6, 0x3f}, + {OP_WR, PRS_REG_PACKET_REGIONS_TYPE_7, 0x3f}, +#define PRS_COMMON_END 46 +#define PRS_PORT0_START 46 + {OP_WR, PRS_REG_CID_PORT_0, 0x0}, +#define PRS_PORT0_END 47 +#define PRS_PORT1_START 47 + {OP_WR, PRS_REG_CID_PORT_1, 0x800000}, +#define PRS_PORT1_END 48 +#define TSDM_COMMON_START 48 + {OP_WR, TSDM_REG_CFC_RSP_START_ADDR, 0x411}, + {OP_WR, TSDM_REG_CMP_COUNTER_START_ADDR, 0x400}, + {OP_WR, TSDM_REG_Q_COUNTER_START_ADDR, 0x404}, + {OP_WR, TSDM_REG_PCK_END_MSG_START_ADDR, 0x419}, + {OP_WR, TSDM_REG_CMP_COUNTER_MAX0, 0xffff}, + {OP_WR, TSDM_REG_CMP_COUNTER_MAX1, 0xffff}, + {OP_WR, TSDM_REG_CMP_COUNTER_MAX2, 0xffff}, + {OP_WR, TSDM_REG_CMP_COUNTER_MAX3, 0xffff}, + {OP_ZR, TSDM_REG_AGG_INT_EVENT_0, 0x80}, + {OP_WR, TSDM_REG_ENABLE_IN1, 0x7ffffff}, + {OP_WR, TSDM_REG_ENABLE_IN2, 0x3f}, + {OP_WR, TSDM_REG_ENABLE_OUT1, 0x7ffffff}, + {OP_WR, TSDM_REG_ENABLE_OUT2, 0xf}, + {OP_RD, TSDM_REG_NUM_OF_Q0_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q1_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q3_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q4_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q5_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q6_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q7_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q8_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q9_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q10_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_Q11_CMD, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, + {OP_RD, TSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, + {OP_WR, TSDM_REG_TIMER_TICK, 0x3e8}, +#define TSDM_COMMON_END 76 +#define TCM_COMMON_START 76 + {OP_WR, TCM_REG_XX_MAX_LL_SZ, 0x20}, + {OP_WR, TCM_REG_XX_OVFL_EVNT_ID, 0x32}, + {OP_WR, TCM_REG_TQM_TCM_HDR_P, 0x2150020}, + {OP_WR, TCM_REG_TQM_TCM_HDR_S, 0x2150020}, + {OP_WR, TCM_REG_TM_TCM_HDR, 0x30}, + {OP_WR, TCM_REG_ERR_TCM_HDR, 0x8100000}, + {OP_WR, TCM_REG_ERR_EVNT_ID, 0x33}, + {OP_WR, TCM_REG_EXPR_EVNT_ID, 0x30}, + {OP_WR, TCM_REG_STOP_EVNT_ID, 0x31}, + {OP_WR, TCM_REG_PRS_WEIGHT, 0x4}, + {OP_WR, TCM_REG_PBF_WEIGHT, 0x5}, + {OP_WR, TCM_REG_CP_WEIGHT, 0x0}, + {OP_WR, TCM_REG_TSDM_WEIGHT, 0x4}, + {OP_WR, TCM_REG_TCM_TQM_USE_Q, 0x1}, + {OP_WR, TCM_REG_GR_ARB_TYPE, 0x1}, + {OP_WR, TCM_REG_GR_LD0_PR, 0x1}, + {OP_WR, TCM_REG_GR_LD1_PR, 0x2}, + {OP_WR, TCM_REG_CFC_INIT_CRD, 0x1}, + {OP_WR, TCM_REG_FIC0_INIT_CRD, 0x40}, + {OP_WR, TCM_REG_FIC1_INIT_CRD, 0x40}, + {OP_WR, TCM_REG_TQM_INIT_CRD, 0x20}, + {OP_WR, TCM_REG_XX_INIT_CRD, 0x13}, + {OP_WR, TCM_REG_XX_MSG_NUM, 0x20}, + {OP_ZR, TCM_REG_XX_TABLE, 0xa}, + {OP_SW, TCM_REG_XX_DESCR_TABLE, 0x200000}, + {OP_WR, TCM_REG_N_SM_CTX_LD_0, 0x7}, + {OP_WR, TCM_REG_N_SM_CTX_LD_1, 0x7}, + {OP_WR, TCM_REG_N_SM_CTX_LD_2, 0x8}, + {OP_WR, TCM_REG_N_SM_CTX_LD_3, 0x8}, + {OP_ZR, TCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_WR, TCM_REG_TCM_REG0_SZ, 0x6}, + {OP_WR, TCM_REG_PHYS_QNUM0_0, 0xd}, + {OP_WR, TCM_REG_PHYS_QNUM0_1, 0x2d}, + {OP_ZR, TCM_REG_PHYS_QNUM1_0, 0x6}, + {OP_WR, TCM_REG_TCM_STORM0_IFEN, 0x1}, + {OP_WR, TCM_REG_TCM_STORM1_IFEN, 0x1}, + {OP_WR, TCM_REG_TCM_TQM_IFEN, 0x1}, + {OP_WR, TCM_REG_STORM_TCM_IFEN, 0x1}, + {OP_WR, TCM_REG_TQM_TCM_IFEN, 0x1}, + {OP_WR, TCM_REG_TSDM_IFEN, 0x1}, + {OP_WR, TCM_REG_TM_TCM_IFEN, 0x1}, + {OP_WR, TCM_REG_PRS_IFEN, 0x1}, + {OP_WR, TCM_REG_PBF_IFEN, 0x1}, + {OP_WR, TCM_REG_USEM_IFEN, 0x1}, + {OP_WR, TCM_REG_CSEM_IFEN, 0x1}, + {OP_WR, TCM_REG_CDU_AG_WR_IFEN, 0x1}, + {OP_WR, TCM_REG_CDU_AG_RD_IFEN, 0x1}, + {OP_WR, TCM_REG_CDU_SM_WR_IFEN, 0x1}, + {OP_WR, TCM_REG_CDU_SM_RD_IFEN, 0x1}, + {OP_WR, TCM_REG_TCM_CFC_IFEN, 0x1}, +#define TCM_COMMON_END 126 +#define BRB1_COMMON_START 126 + {OP_SW, BRB1_REG_LL_RAM, 0x2000020}, + {OP_WR, BRB1_REG_SOFT_RESET, 0x1}, + {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_0, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_1, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_2, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_PAUSE_CYCLES_3, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_0, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_1, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_2, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_3, 0x0}, + {OP_RD, BRB1_REG_NUM_OF_FULL_CYCLES_4, 0x0}, + {OP_SW, BRB1_REG_FREE_LIST_PRS_CRDT, 0x30220}, + {OP_WR, BRB1_REG_SOFT_RESET, 0x0}, +#define BRB1_COMMON_END 139 +#define TSEM_COMMON_START 139 + {OP_RD, TSEM_REG_MSG_NUM_FIC0, 0x0}, + {OP_RD, TSEM_REG_MSG_NUM_FIC1, 0x0}, + {OP_RD, TSEM_REG_MSG_NUM_FOC0, 0x0}, + {OP_RD, TSEM_REG_MSG_NUM_FOC1, 0x0}, + {OP_RD, TSEM_REG_MSG_NUM_FOC2, 0x0}, + {OP_RD, TSEM_REG_MSG_NUM_FOC3, 0x0}, + {OP_WR, TSEM_REG_ARB_ELEMENT0, 0x1}, + {OP_WR, TSEM_REG_ARB_ELEMENT1, 0x2}, + {OP_WR, TSEM_REG_ARB_ELEMENT2, 0x3}, + {OP_WR, TSEM_REG_ARB_ELEMENT3, 0x0}, + {OP_WR, TSEM_REG_ARB_ELEMENT4, 0x4}, + {OP_WR, TSEM_REG_ARB_CYCLE_SIZE, 0x1}, + {OP_WR, TSEM_REG_TS_0_AS, 0x0}, + {OP_WR, TSEM_REG_TS_1_AS, 0x1}, + {OP_WR, TSEM_REG_TS_2_AS, 0x4}, + {OP_WR, TSEM_REG_TS_3_AS, 0x0}, + {OP_WR, TSEM_REG_TS_4_AS, 0x1}, + {OP_WR, TSEM_REG_TS_5_AS, 0x3}, + {OP_WR, TSEM_REG_TS_6_AS, 0x0}, + {OP_WR, TSEM_REG_TS_7_AS, 0x1}, + {OP_WR, TSEM_REG_TS_8_AS, 0x4}, + {OP_WR, TSEM_REG_TS_9_AS, 0x0}, + {OP_WR, TSEM_REG_TS_10_AS, 0x1}, + {OP_WR, TSEM_REG_TS_11_AS, 0x3}, + {OP_WR, TSEM_REG_TS_12_AS, 0x0}, + {OP_WR, TSEM_REG_TS_13_AS, 0x1}, + {OP_WR, TSEM_REG_TS_14_AS, 0x4}, + {OP_WR, TSEM_REG_TS_15_AS, 0x0}, + {OP_WR, TSEM_REG_TS_16_AS, 0x4}, + {OP_WR, TSEM_REG_TS_17_AS, 0x3}, + {OP_ZR, TSEM_REG_TS_18_AS, 0x2}, + {OP_WR, TSEM_REG_ENABLE_IN, 0x3fff}, + {OP_WR, TSEM_REG_ENABLE_OUT, 0x3ff}, + {OP_WR, TSEM_REG_FIC0_DISABLE, 0x0}, + {OP_WR, TSEM_REG_FIC1_DISABLE, 0x0}, + {OP_WR, TSEM_REG_PAS_DISABLE, 0x0}, + {OP_WR, TSEM_REG_THREADS_LIST, 0xff}, + {OP_ZR, TSEM_REG_PASSIVE_BUFFER, 0x400}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x18000, 0x34}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x18040, 0x18}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x18080, 0xc}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x180c0, 0x20}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, + {OP_WR, TSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x2000, 0x1b3}, + {OP_SW, TSEM_REG_FAST_MEMORY + 0x2000 + 0x6cc, 0x10223}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1000, 0x2}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x810, 0x4}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1fa0, 0x4}, + {OP_SW, TSEM_REG_FAST_MEMORY + 0x4cf0, 0x80224}, + {OP_ZP, TSEM_REG_INT_TABLE, 0x8c022c}, + {OP_ZP, TSEM_REG_PRAM, 0x3395024f}, + {OP_ZP, TSEM_REG_PRAM + 0x8000, 0x2c760f35}, + {OP_ZP, TSEM_REG_PRAM + 0x10000, 0x5e1a53}, + {OP_ZP, TSEM_REG_PRAM + 0x18000, 0x5e1a6b}, + {OP_ZP, TSEM_REG_PRAM + 0x20000, 0x5e1a83}, + {OP_ZP, TSEM_REG_PRAM + 0x28000, 0x5e1a9b}, + {OP_ZP, TSEM_REG_PRAM + 0x30000, 0x5e1ab3}, + {OP_ZP, TSEM_REG_PRAM + 0x38000, 0x5e1acb}, +#define TSEM_COMMON_END 202 +#define TSEM_PORT0_START 202 + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x4000, 0x16c}, + {OP_SW, TSEM_REG_FAST_MEMORY + 0x4000 + 0x5b0, 0x21ae3}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1370, 0xa}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x13c0, 0x6}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1418, 0xc}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1478, 0x12}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1508, 0x90}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x800, 0x2}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x820, 0x10}, + {OP_SW, TSEM_REG_FAST_MEMORY + 0x820 + 0x40, 0x21ae5}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x2908, 0xa}, +#define TSEM_PORT0_END 213 +#define TSEM_PORT1_START 213 + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x45b8, 0x16c}, + {OP_SW, TSEM_REG_FAST_MEMORY + 0x45b8 + 0x5b0, 0x21ae7}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1398, 0xa}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x13d8, 0x6}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1448, 0xc}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x14c0, 0x12}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x1748, 0x90}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x808, 0x2}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x868, 0x10}, + {OP_SW, TSEM_REG_FAST_MEMORY + 0x868 + 0x40, 0x21ae9}, + {OP_ZR, TSEM_REG_FAST_MEMORY + 0x2930, 0xa}, +#define TSEM_PORT1_END 224 +#define MISC_COMMON_START 224 + {OP_WR, MISC_REG_GRC_TIMEOUT_EN, 0x1}, + {OP_WR, MISC_REG_PLL_STORM_CTRL_1, 0x71d2911}, + {OP_WR, MISC_REG_PLL_STORM_CTRL_2, 0x0}, + {OP_WR, MISC_REG_PLL_STORM_CTRL_3, 0x9c0424}, + {OP_WR, MISC_REG_PLL_STORM_CTRL_4, 0x0}, + {OP_WR, MISC_REG_LCPLL_CTRL_1, 0x209}, +#define MISC_COMMON_END 230 +#define NIG_COMMON_START 230 + {OP_WR, NIG_REG_PBF_LB_IN_EN, 0x1}, + {OP_WR, NIG_REG_PRS_REQ_IN_EN, 0x1}, + {OP_WR, NIG_REG_EGRESS_DEBUG_IN_EN, 0x1}, + {OP_WR, NIG_REG_BRB_LB_OUT_EN, 0x1}, + {OP_WR, NIG_REG_PRS_EOP_OUT_EN, 0x1}, +#define NIG_COMMON_END 235 +#define NIG_PORT0_START 235 + {OP_WR, NIG_REG_LLH0_CM_HEADER, 0x300000}, + {OP_WR, NIG_REG_LLH0_EVENT_ID, 0x26}, + {OP_WR, NIG_REG_LLH0_ERROR_MASK, 0x0}, + {OP_WR, NIG_REG_LLH0_XCM_MASK, 0x4}, + {OP_WR, NIG_REG_LLH0_BRB1_NOT_MCP, 0x1}, + {OP_WR, NIG_REG_STATUS_INTERRUPT_PORT0, 0x0}, + {OP_WR, NIG_REG_LLH0_XCM_INIT_CREDIT, 0x30}, + {OP_WR, NIG_REG_BRB0_PAUSE_IN_EN, 0x1}, + {OP_WR, NIG_REG_EGRESS_PBF0_IN_EN, 0x1}, + {OP_WR, NIG_REG_BRB0_OUT_EN, 0x1}, + {OP_WR, NIG_REG_XCM0_OUT_EN, 0x1}, +#define NIG_PORT0_END 246 +#define NIG_PORT1_START 246 + {OP_WR, NIG_REG_LLH1_CM_HEADER, 0x300000}, + {OP_WR, NIG_REG_LLH1_EVENT_ID, 0x26}, + {OP_WR, NIG_REG_LLH1_ERROR_MASK, 0x0}, + {OP_WR, NIG_REG_LLH1_XCM_MASK, 0x4}, + {OP_WR, NIG_REG_LLH1_BRB1_NOT_MCP, 0x1}, + {OP_WR, NIG_REG_STATUS_INTERRUPT_PORT1, 0x0}, + {OP_WR, NIG_REG_LLH1_XCM_INIT_CREDIT, 0x30}, + {OP_WR, NIG_REG_BRB1_PAUSE_IN_EN, 0x1}, + {OP_WR, NIG_REG_EGRESS_PBF1_IN_EN, 0x1}, + {OP_WR, NIG_REG_BRB1_OUT_EN, 0x1}, + {OP_WR, NIG_REG_XCM1_OUT_EN, 0x1}, +#define NIG_PORT1_END 257 +#define UPB_COMMON_START 257 + {OP_WR, GRCBASE_UPB + PB_REG_CONTROL, 0x20}, +#define UPB_COMMON_END 258 +#define CSDM_COMMON_START 258 + {OP_WR, CSDM_REG_CFC_RSP_START_ADDR, 0xa11}, + {OP_WR, CSDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, + {OP_WR, CSDM_REG_Q_COUNTER_START_ADDR, 0xa04}, + {OP_WR, CSDM_REG_CMP_COUNTER_MAX0, 0xffff}, + {OP_WR, CSDM_REG_CMP_COUNTER_MAX1, 0xffff}, + {OP_WR, CSDM_REG_CMP_COUNTER_MAX2, 0xffff}, + {OP_WR, CSDM_REG_CMP_COUNTER_MAX3, 0xffff}, + {OP_ZR, CSDM_REG_AGG_INT_EVENT_0, 0x80}, + {OP_WR, CSDM_REG_ENABLE_IN1, 0x7ffffff}, + {OP_WR, CSDM_REG_ENABLE_IN2, 0x3f}, + {OP_WR, CSDM_REG_ENABLE_OUT1, 0x7ffffff}, + {OP_WR, CSDM_REG_ENABLE_OUT2, 0xf}, + {OP_RD, CSDM_REG_NUM_OF_Q0_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q1_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q3_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q4_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q5_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q6_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q7_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q8_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q9_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q10_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_Q11_CMD, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, + {OP_RD, CSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, + {OP_WR, CSDM_REG_TIMER_TICK, 0x3e8}, +#define CSDM_COMMON_END 285 +#define USDM_COMMON_START 285 + {OP_WR, USDM_REG_CFC_RSP_START_ADDR, 0xa11}, + {OP_WR, USDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, + {OP_WR, USDM_REG_Q_COUNTER_START_ADDR, 0xa04}, + {OP_WR, USDM_REG_PCK_END_MSG_START_ADDR, 0xa21}, + {OP_WR, USDM_REG_CMP_COUNTER_MAX0, 0xffff}, + {OP_WR, USDM_REG_CMP_COUNTER_MAX1, 0xffff}, + {OP_WR, USDM_REG_CMP_COUNTER_MAX2, 0xffff}, + {OP_WR, USDM_REG_CMP_COUNTER_MAX3, 0xffff}, + {OP_WR, USDM_REG_AGG_INT_EVENT_0, 0x46}, + {OP_ZR, USDM_REG_AGG_INT_EVENT_1, 0x5f}, + {OP_WR, USDM_REG_AGG_INT_MODE_0, 0x1}, + {OP_ZR, USDM_REG_AGG_INT_MODE_1, 0x1f}, + {OP_WR, USDM_REG_ENABLE_IN1, 0x7ffffff}, + {OP_WR, USDM_REG_ENABLE_IN2, 0x3f}, + {OP_WR, USDM_REG_ENABLE_OUT1, 0x7ffffff}, + {OP_WR, USDM_REG_ENABLE_OUT2, 0xf}, + {OP_RD, USDM_REG_NUM_OF_Q0_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q1_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q2_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q3_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q4_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q5_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q6_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q7_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q8_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q9_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q10_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_Q11_CMD, 0x0}, + {OP_RD, USDM_REG_NUM_OF_PKT_END_MSG, 0x0}, + {OP_RD, USDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, + {OP_RD, USDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, + {OP_WR, USDM_REG_TIMER_TICK, 0x3e8}, +#define USDM_COMMON_END 317 +#define CCM_COMMON_START 317 + {OP_WR, CCM_REG_XX_OVFL_EVNT_ID, 0x32}, + {OP_WR, CCM_REG_CQM_CCM_HDR_P, 0x2150020}, + {OP_WR, CCM_REG_CQM_CCM_HDR_S, 0x2150020}, + {OP_WR, CCM_REG_ERR_CCM_HDR, 0x8100000}, + {OP_WR, CCM_REG_ERR_EVNT_ID, 0x33}, + {OP_WR, CCM_REG_TSEM_WEIGHT, 0x0}, + {OP_WR, CCM_REG_XSEM_WEIGHT, 0x4}, + {OP_WR, CCM_REG_USEM_WEIGHT, 0x4}, + {OP_ZR, CCM_REG_PBF_WEIGHT, 0x2}, + {OP_WR, CCM_REG_CQM_P_WEIGHT, 0x2}, + {OP_WR, CCM_REG_CCM_CQM_USE_Q, 0x1}, + {OP_WR, CCM_REG_CNT_AUX1_Q, 0x2}, + {OP_WR, CCM_REG_CNT_AUX2_Q, 0x2}, + {OP_WR, CCM_REG_INV_DONE_Q, 0x1}, + {OP_WR, CCM_REG_GR_ARB_TYPE, 0x1}, + {OP_WR, CCM_REG_GR_LD0_PR, 0x1}, + {OP_WR, CCM_REG_GR_LD1_PR, 0x2}, + {OP_WR, CCM_REG_CFC_INIT_CRD, 0x1}, + {OP_WR, CCM_REG_CQM_INIT_CRD, 0x20}, + {OP_WR, CCM_REG_FIC0_INIT_CRD, 0x40}, + {OP_WR, CCM_REG_FIC1_INIT_CRD, 0x40}, + {OP_WR, CCM_REG_XX_INIT_CRD, 0x3}, + {OP_WR, CCM_REG_XX_MSG_NUM, 0x18}, + {OP_ZR, CCM_REG_XX_TABLE, 0x12}, + {OP_SW, CCM_REG_XX_DESCR_TABLE, 0x241aeb}, + {OP_WR, CCM_REG_N_SM_CTX_LD_0, 0x1}, + {OP_WR, CCM_REG_N_SM_CTX_LD_1, 0x2}, + {OP_WR, CCM_REG_N_SM_CTX_LD_2, 0x8}, + {OP_WR, CCM_REG_N_SM_CTX_LD_3, 0x8}, + {OP_ZR, CCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_WR, CCM_REG_CCM_REG0_SZ, 0x4}, + {OP_WR, CCM_REG_QOS_PHYS_QNUM0_0, 0x9}, + {OP_WR, CCM_REG_QOS_PHYS_QNUM0_1, 0x29}, + {OP_WR, CCM_REG_QOS_PHYS_QNUM1_0, 0xa}, + {OP_WR, CCM_REG_QOS_PHYS_QNUM1_1, 0x2a}, + {OP_ZR, CCM_REG_QOS_PHYS_QNUM2_0, 0x4}, + {OP_WR, CCM_REG_PHYS_QNUM1_0, 0xc}, + {OP_WR, CCM_REG_PHYS_QNUM1_1, 0x2c}, + {OP_WR, CCM_REG_PHYS_QNUM2_0, 0xb}, + {OP_WR, CCM_REG_PHYS_QNUM2_1, 0x2b}, + {OP_ZR, CCM_REG_PHYS_QNUM3_0, 0x2}, + {OP_WR, CCM_REG_CCM_STORM0_IFEN, 0x1}, + {OP_WR, CCM_REG_CCM_STORM1_IFEN, 0x1}, + {OP_WR, CCM_REG_CCM_CQM_IFEN, 0x1}, + {OP_WR, CCM_REG_STORM_CCM_IFEN, 0x1}, + {OP_WR, CCM_REG_CQM_CCM_IFEN, 0x1}, + {OP_WR, CCM_REG_CSDM_IFEN, 0x1}, + {OP_WR, CCM_REG_TSEM_IFEN, 0x1}, + {OP_WR, CCM_REG_XSEM_IFEN, 0x1}, + {OP_WR, CCM_REG_USEM_IFEN, 0x1}, + {OP_WR, CCM_REG_PBF_IFEN, 0x1}, + {OP_WR, CCM_REG_CDU_AG_WR_IFEN, 0x1}, + {OP_WR, CCM_REG_CDU_AG_RD_IFEN, 0x1}, + {OP_WR, CCM_REG_CDU_SM_WR_IFEN, 0x1}, + {OP_WR, CCM_REG_CDU_SM_RD_IFEN, 0x1}, + {OP_WR, CCM_REG_CCM_CFC_IFEN, 0x1}, +#define CCM_COMMON_END 373 +#define UCM_COMMON_START 373 + {OP_WR, UCM_REG_XX_OVFL_EVNT_ID, 0x32}, + {OP_WR, UCM_REG_UQM_UCM_HDR_P, 0x2150020}, + {OP_WR, UCM_REG_UQM_UCM_HDR_S, 0x2150020}, + {OP_WR, UCM_REG_TM_UCM_HDR, 0x30}, + {OP_WR, UCM_REG_ERR_UCM_HDR, 0x8100000}, + {OP_WR, UCM_REG_ERR_EVNT_ID, 0x33}, + {OP_WR, UCM_REG_EXPR_EVNT_ID, 0x30}, + {OP_WR, UCM_REG_STOP_EVNT_ID, 0x31}, + {OP_WR, UCM_REG_TSEM_WEIGHT, 0x3}, + {OP_WR, UCM_REG_CSEM_WEIGHT, 0x0}, + {OP_WR, UCM_REG_CP_WEIGHT, 0x0}, + {OP_WR, UCM_REG_UQM_P_WEIGHT, 0x6}, + {OP_WR, UCM_REG_UCM_UQM_USE_Q, 0x1}, + {OP_WR, UCM_REG_INV_CFLG_Q, 0x1}, + {OP_WR, UCM_REG_GR_ARB_TYPE, 0x1}, + {OP_WR, UCM_REG_GR_LD0_PR, 0x1}, + {OP_WR, UCM_REG_GR_LD1_PR, 0x2}, + {OP_WR, UCM_REG_CFC_INIT_CRD, 0x1}, + {OP_WR, UCM_REG_FIC0_INIT_CRD, 0x40}, + {OP_WR, UCM_REG_FIC1_INIT_CRD, 0x40}, + {OP_WR, UCM_REG_TM_INIT_CRD, 0x4}, + {OP_WR, UCM_REG_UQM_INIT_CRD, 0x20}, + {OP_WR, UCM_REG_XX_INIT_CRD, 0xc}, + {OP_WR, UCM_REG_XX_MSG_NUM, 0x20}, + {OP_ZR, UCM_REG_XX_TABLE, 0x12}, + {OP_SW, UCM_REG_XX_DESCR_TABLE, 0x201b0f}, + {OP_WR, UCM_REG_N_SM_CTX_LD_0, 0xa}, + {OP_WR, UCM_REG_N_SM_CTX_LD_1, 0x7}, + {OP_WR, UCM_REG_N_SM_CTX_LD_2, 0xf}, + {OP_WR, UCM_REG_N_SM_CTX_LD_3, 0x10}, + {OP_ZR, UCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_WR, UCM_REG_UCM_REG0_SZ, 0x3}, + {OP_WR, UCM_REG_PHYS_QNUM0_0, 0xf}, + {OP_WR, UCM_REG_PHYS_QNUM0_1, 0x2f}, + {OP_WR, UCM_REG_PHYS_QNUM1_0, 0xe}, + {OP_WR, UCM_REG_PHYS_QNUM1_1, 0x2e}, + {OP_WR, UCM_REG_UCM_STORM0_IFEN, 0x1}, + {OP_WR, UCM_REG_UCM_STORM1_IFEN, 0x1}, + {OP_WR, UCM_REG_UCM_UQM_IFEN, 0x1}, + {OP_WR, UCM_REG_STORM_UCM_IFEN, 0x1}, + {OP_WR, UCM_REG_UQM_UCM_IFEN, 0x1}, + {OP_WR, UCM_REG_USDM_IFEN, 0x1}, + {OP_WR, UCM_REG_TM_UCM_IFEN, 0x1}, + {OP_WR, UCM_REG_UCM_TM_IFEN, 0x1}, + {OP_WR, UCM_REG_TSEM_IFEN, 0x1}, + {OP_WR, UCM_REG_CSEM_IFEN, 0x1}, + {OP_WR, UCM_REG_XSEM_IFEN, 0x1}, + {OP_WR, UCM_REG_DORQ_IFEN, 0x1}, + {OP_WR, UCM_REG_CDU_AG_WR_IFEN, 0x1}, + {OP_WR, UCM_REG_CDU_AG_RD_IFEN, 0x1}, + {OP_WR, UCM_REG_CDU_SM_WR_IFEN, 0x1}, + {OP_WR, UCM_REG_CDU_SM_RD_IFEN, 0x1}, + {OP_WR, UCM_REG_UCM_CFC_IFEN, 0x1}, +#define UCM_COMMON_END 426 +#define USEM_COMMON_START 426 + {OP_RD, USEM_REG_MSG_NUM_FIC0, 0x0}, + {OP_RD, USEM_REG_MSG_NUM_FIC1, 0x0}, + {OP_RD, USEM_REG_MSG_NUM_FOC0, 0x0}, + {OP_RD, USEM_REG_MSG_NUM_FOC1, 0x0}, + {OP_RD, USEM_REG_MSG_NUM_FOC2, 0x0}, + {OP_RD, USEM_REG_MSG_NUM_FOC3, 0x0}, + {OP_WR, USEM_REG_ARB_ELEMENT0, 0x1}, + {OP_WR, USEM_REG_ARB_ELEMENT1, 0x2}, + {OP_WR, USEM_REG_ARB_ELEMENT2, 0x3}, + {OP_WR, USEM_REG_ARB_ELEMENT3, 0x0}, + {OP_WR, USEM_REG_ARB_ELEMENT4, 0x4}, + {OP_WR, USEM_REG_ARB_CYCLE_SIZE, 0x1}, + {OP_WR, USEM_REG_TS_0_AS, 0x0}, + {OP_WR, USEM_REG_TS_1_AS, 0x1}, + {OP_WR, USEM_REG_TS_2_AS, 0x4}, + {OP_WR, USEM_REG_TS_3_AS, 0x0}, + {OP_WR, USEM_REG_TS_4_AS, 0x1}, + {OP_WR, USEM_REG_TS_5_AS, 0x3}, + {OP_WR, USEM_REG_TS_6_AS, 0x0}, + {OP_WR, USEM_REG_TS_7_AS, 0x1}, + {OP_WR, USEM_REG_TS_8_AS, 0x4}, + {OP_WR, USEM_REG_TS_9_AS, 0x0}, + {OP_WR, USEM_REG_TS_10_AS, 0x1}, + {OP_WR, USEM_REG_TS_11_AS, 0x3}, + {OP_WR, USEM_REG_TS_12_AS, 0x0}, + {OP_WR, USEM_REG_TS_13_AS, 0x1}, + {OP_WR, USEM_REG_TS_14_AS, 0x4}, + {OP_WR, USEM_REG_TS_15_AS, 0x0}, + {OP_WR, USEM_REG_TS_16_AS, 0x4}, + {OP_WR, USEM_REG_TS_17_AS, 0x3}, + {OP_ZR, USEM_REG_TS_18_AS, 0x2}, + {OP_WR, USEM_REG_ENABLE_IN, 0x3fff}, + {OP_WR, USEM_REG_ENABLE_OUT, 0x3ff}, + {OP_WR, USEM_REG_FIC0_DISABLE, 0x0}, + {OP_WR, USEM_REG_FIC1_DISABLE, 0x0}, + {OP_WR, USEM_REG_PAS_DISABLE, 0x0}, + {OP_WR, USEM_REG_THREADS_LIST, 0xffff}, + {OP_ZR, USEM_REG_PASSIVE_BUFFER, 0x800}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x18000, 0x1a}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x18040, 0x4e}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x18080, 0x10}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x180c0, 0x20}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x5000, 0x102}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1020, 0xc8}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1000, 0x2}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1e20, 0x40}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3000, 0x400}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x2400, 0x2}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x2408, 0x2}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x2410, 0x6}, + {OP_SW, USEM_REG_FAST_MEMORY + 0x2410 + 0x18, 0x21b2f}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x4b68, 0x2}, + {OP_SW, USEM_REG_FAST_MEMORY + 0x4b68 + 0x8, 0x21b31}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x4b10, 0x2}, + {OP_SW, USEM_REG_FAST_MEMORY + 0x2c30, 0x21b33}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, + {OP_SW, USEM_REG_FAST_MEMORY + 0x10c00, 0x101b35}, + {OP_WR, USEM_REG_FAST_MEMORY + 0x10800, 0x0}, + {OP_SW, USEM_REG_FAST_MEMORY + 0x10c40, 0x101b45}, + {OP_ZP, USEM_REG_INT_TABLE, 0xb41b55}, + {OP_ZP, USEM_REG_PRAM, 0x32d01b82}, + {OP_ZP, USEM_REG_PRAM + 0x8000, 0x32172836}, + {OP_ZP, USEM_REG_PRAM + 0x10000, 0x1a7a34bc}, + {OP_ZP, USEM_REG_PRAM + 0x18000, 0x5f3b5b}, + {OP_ZP, USEM_REG_PRAM + 0x20000, 0x5f3b73}, + {OP_ZP, USEM_REG_PRAM + 0x28000, 0x5f3b8b}, + {OP_ZP, USEM_REG_PRAM + 0x30000, 0x5f3ba3}, + {OP_ZP, USEM_REG_PRAM + 0x38000, 0x5f3bbb}, +#define USEM_COMMON_END 498 +#define USEM_PORT0_START 498 + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1400, 0xa0}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1900, 0xa}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1950, 0x2e}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1d00, 0x24}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3000, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3100, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3200, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3300, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3400, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3500, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3600, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3700, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3800, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3900, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3a00, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3b00, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3c00, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3d00, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3e00, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3f00, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x2400, 0x2}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x4b78, 0x52}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x4e08, 0xc}, +#define USEM_PORT0_END 521 +#define USEM_PORT1_START 521 + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1680, 0xa0}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1928, 0xa}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1a08, 0x2e}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x1d90, 0x24}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3080, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3180, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3280, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3380, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3480, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3580, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3680, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3780, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3880, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3980, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3a80, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3b80, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3c80, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3d80, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3e80, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x3f80, 0x20}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x2408, 0x2}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x4cc0, 0x52}, + {OP_ZR, USEM_REG_FAST_MEMORY + 0x4e38, 0xc}, +#define USEM_PORT1_END 544 +#define CSEM_COMMON_START 544 + {OP_RD, CSEM_REG_MSG_NUM_FIC0, 0x0}, + {OP_RD, CSEM_REG_MSG_NUM_FIC1, 0x0}, + {OP_RD, CSEM_REG_MSG_NUM_FOC0, 0x0}, + {OP_RD, CSEM_REG_MSG_NUM_FOC1, 0x0}, + {OP_RD, CSEM_REG_MSG_NUM_FOC2, 0x0}, + {OP_RD, CSEM_REG_MSG_NUM_FOC3, 0x0}, + {OP_WR, CSEM_REG_ARB_ELEMENT0, 0x1}, + {OP_WR, CSEM_REG_ARB_ELEMENT1, 0x2}, + {OP_WR, CSEM_REG_ARB_ELEMENT2, 0x3}, + {OP_WR, CSEM_REG_ARB_ELEMENT3, 0x0}, + {OP_WR, CSEM_REG_ARB_ELEMENT4, 0x4}, + {OP_WR, CSEM_REG_ARB_CYCLE_SIZE, 0x1}, + {OP_WR, CSEM_REG_TS_0_AS, 0x0}, + {OP_WR, CSEM_REG_TS_1_AS, 0x1}, + {OP_WR, CSEM_REG_TS_2_AS, 0x4}, + {OP_WR, CSEM_REG_TS_3_AS, 0x0}, + {OP_WR, CSEM_REG_TS_4_AS, 0x1}, + {OP_WR, CSEM_REG_TS_5_AS, 0x3}, + {OP_WR, CSEM_REG_TS_6_AS, 0x0}, + {OP_WR, CSEM_REG_TS_7_AS, 0x1}, + {OP_WR, CSEM_REG_TS_8_AS, 0x4}, + {OP_WR, CSEM_REG_TS_9_AS, 0x0}, + {OP_WR, CSEM_REG_TS_10_AS, 0x1}, + {OP_WR, CSEM_REG_TS_11_AS, 0x3}, + {OP_WR, CSEM_REG_TS_12_AS, 0x0}, + {OP_WR, CSEM_REG_TS_13_AS, 0x1}, + {OP_WR, CSEM_REG_TS_14_AS, 0x4}, + {OP_WR, CSEM_REG_TS_15_AS, 0x0}, + {OP_WR, CSEM_REG_TS_16_AS, 0x4}, + {OP_WR, CSEM_REG_TS_17_AS, 0x3}, + {OP_ZR, CSEM_REG_TS_18_AS, 0x2}, + {OP_WR, CSEM_REG_ENABLE_IN, 0x3fff}, + {OP_WR, CSEM_REG_ENABLE_OUT, 0x3ff}, + {OP_WR, CSEM_REG_FIC0_DISABLE, 0x0}, + {OP_WR, CSEM_REG_FIC1_DISABLE, 0x0}, + {OP_WR, CSEM_REG_PAS_DISABLE, 0x0}, + {OP_WR, CSEM_REG_THREADS_LIST, 0xffff}, + {OP_ZR, CSEM_REG_PASSIVE_BUFFER, 0x800}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x18000, 0x10}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x18040, 0x12}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x18080, 0x30}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x180c0, 0xe}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x5000, 0x42}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1000, 0x2}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2000, 0xc0}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x3070, 0x80}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x4280, 0x4}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x25c0, 0x240}, + {OP_SW, CSEM_REG_FAST_MEMORY + 0x25c0 + 0x900, 0x83bd3}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x13fffff}, + {OP_SW, CSEM_REG_FAST_MEMORY + 0x10c00, 0x103bdb}, + {OP_WR, CSEM_REG_FAST_MEMORY + 0x10800, 0x0}, + {OP_SW, CSEM_REG_FAST_MEMORY + 0x10c40, 0x103beb}, + {OP_ZP, CSEM_REG_INT_TABLE, 0x5f3bfb}, + {OP_ZP, CSEM_REG_PRAM, 0x32423c13}, + {OP_ZP, CSEM_REG_PRAM + 0x8000, 0xf2148a4}, + {OP_ZP, CSEM_REG_PRAM + 0x10000, 0x5f4c6d}, + {OP_ZP, CSEM_REG_PRAM + 0x18000, 0x5f4c85}, + {OP_ZP, CSEM_REG_PRAM + 0x20000, 0x5f4c9d}, + {OP_ZP, CSEM_REG_PRAM + 0x28000, 0x5f4cb5}, + {OP_ZP, CSEM_REG_PRAM + 0x30000, 0x5f4ccd}, + {OP_ZP, CSEM_REG_PRAM + 0x38000, 0x5f4ce5}, +#define CSEM_COMMON_END 609 +#define CSEM_PORT0_START 609 + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1400, 0xa0}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1900, 0x10}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1980, 0x30}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2300, 0x2}, + {OP_SW, CSEM_REG_FAST_MEMORY + 0x2300 + 0x8, 0x24cfd}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x3040, 0x6}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2410, 0x30}, +#define CSEM_PORT0_END 616 +#define CSEM_PORT1_START 616 + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1680, 0xa0}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1940, 0x10}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x1a40, 0x30}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x2310, 0x2}, + {OP_SW, CSEM_REG_FAST_MEMORY + 0x2310 + 0x8, 0x24cff}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x3058, 0x6}, + {OP_ZR, CSEM_REG_FAST_MEMORY + 0x24d0, 0x30}, +#define CSEM_PORT1_END 623 +#define XPB_COMMON_START 623 + {OP_WR, GRCBASE_XPB + PB_REG_CONTROL, 0x20}, +#define XPB_COMMON_END 624 +#define DQ_COMMON_START 624 + {OP_WR, DORQ_REG_MODE_ACT, 0x2}, + {OP_WR, DORQ_REG_NORM_CID_OFST, 0x3}, + {OP_WR, DORQ_REG_OUTST_REQ, 0x4}, + {OP_WR, DORQ_REG_DPM_CID_ADDR, 0x8}, + {OP_WR, DORQ_REG_RSP_INIT_CRD, 0x2}, + {OP_WR, DORQ_REG_NORM_CMHEAD_TX, 0x90}, + {OP_WR, DORQ_REG_CMHEAD_RX, 0x90}, + {OP_WR, DORQ_REG_SHRT_CMHEAD, 0x800090}, + {OP_WR, DORQ_REG_ERR_CMHEAD, 0x8140000}, + {OP_WR, DORQ_REG_AGG_CMD0, 0x8a}, + {OP_WR, DORQ_REG_AGG_CMD1, 0x80}, + {OP_WR, DORQ_REG_AGG_CMD2, 0x90}, + {OP_WR, DORQ_REG_AGG_CMD3, 0x80}, + {OP_WR, DORQ_REG_SHRT_ACT_CNT, 0x6}, + {OP_WR, DORQ_REG_DQ_FIFO_FULL_TH, 0x7d0}, + {OP_WR, DORQ_REG_DQ_FIFO_AFULL_TH, 0x76c}, + {OP_WR, DORQ_REG_REGN, 0x7c1004}, + {OP_WR, DORQ_REG_IF_EN, 0xf}, +#define DQ_COMMON_END 642 +#define TIMERS_COMMON_START 642 + {OP_ZR, TM_REG_CLIN_PRIOR0_CLIENT, 0x2}, + {OP_WR, TM_REG_LIN_SETCLR_FIFO_ALFULL_THR, 0x1c}, + {OP_WR, TM_REG_CFC_AC_CRDCNT_VAL, 0x1}, + {OP_WR, TM_REG_CFC_CLD_CRDCNT_VAL, 0x1}, + {OP_WR, TM_REG_CLOUT_CRDCNT0_VAL, 0x1}, + {OP_WR, TM_REG_CLOUT_CRDCNT1_VAL, 0x1}, + {OP_WR, TM_REG_CLOUT_CRDCNT2_VAL, 0x1}, + {OP_WR, TM_REG_EXP_CRDCNT_VAL, 0x1}, + {OP_WR, TM_REG_PCIARB_CRDCNT_VAL, 0x2}, + {OP_WR, TM_REG_TIMER_TICK_SIZE, 0x3d090}, + {OP_WR, TM_REG_CL0_CONT_REGION, 0x8}, + {OP_WR, TM_REG_CL1_CONT_REGION, 0xc}, + {OP_WR, TM_REG_CL2_CONT_REGION, 0x10}, + {OP_WR, TM_REG_TM_CONTEXT_REGION, 0x20}, + {OP_WR, TM_REG_EN_TIMERS, 0x1}, + {OP_WR, TM_REG_EN_REAL_TIME_CNT, 0x1}, + {OP_WR, TM_REG_EN_CL0_INPUT, 0x1}, + {OP_WR, TM_REG_EN_CL1_INPUT, 0x1}, + {OP_WR, TM_REG_EN_CL2_INPUT, 0x1}, +#define TIMERS_COMMON_END 661 +#define TIMERS_PORT0_START 661 + {OP_ZR, TM_REG_LIN0_PHY_ADDR, 0x2}, +#define TIMERS_PORT0_END 662 +#define TIMERS_PORT1_START 662 + {OP_ZR, TM_REG_LIN1_PHY_ADDR, 0x2}, +#define TIMERS_PORT1_END 663 +#define XSDM_COMMON_START 663 + {OP_WR, XSDM_REG_CFC_RSP_START_ADDR, 0xa14}, + {OP_WR, XSDM_REG_CMP_COUNTER_START_ADDR, 0xa00}, + {OP_WR, XSDM_REG_Q_COUNTER_START_ADDR, 0xa04}, + {OP_WR, XSDM_REG_CMP_COUNTER_MAX0, 0xffff}, + {OP_WR, XSDM_REG_CMP_COUNTER_MAX1, 0xffff}, + {OP_WR, XSDM_REG_CMP_COUNTER_MAX2, 0xffff}, + {OP_WR, XSDM_REG_CMP_COUNTER_MAX3, 0xffff}, + {OP_WR, XSDM_REG_AGG_INT_EVENT_0, 0x20}, + {OP_WR, XSDM_REG_AGG_INT_EVENT_1, 0x20}, + {OP_ZR, XSDM_REG_AGG_INT_EVENT_2, 0x5e}, + {OP_WR, XSDM_REG_AGG_INT_MODE_0, 0x1}, + {OP_ZR, XSDM_REG_AGG_INT_MODE_1, 0x1f}, + {OP_WR, XSDM_REG_ENABLE_IN1, 0x7ffffff}, + {OP_WR, XSDM_REG_ENABLE_IN2, 0x3f}, + {OP_WR, XSDM_REG_ENABLE_OUT1, 0x7ffffff}, + {OP_WR, XSDM_REG_ENABLE_OUT2, 0xf}, + {OP_RD, XSDM_REG_NUM_OF_Q0_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q1_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q3_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q4_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q5_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q6_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q7_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q8_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q9_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q10_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_Q11_CMD, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_PKT_END_MSG, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_PXP_ASYNC_REQ, 0x0}, + {OP_RD, XSDM_REG_NUM_OF_ACK_AFTER_PLACE, 0x0}, + {OP_WR, XSDM_REG_TIMER_TICK, 0x3e8}, +#define XSDM_COMMON_END 694 +#define QM_COMMON_START 694 + {OP_WR, QM_REG_ACTCTRINITVAL_0, 0x6}, + {OP_WR, QM_REG_ACTCTRINITVAL_1, 0x5}, + {OP_WR, QM_REG_ACTCTRINITVAL_2, 0xa}, + {OP_WR, QM_REG_ACTCTRINITVAL_3, 0x5}, + {OP_WR, QM_REG_PCIREQAT, 0x2}, + {OP_WR, QM_REG_CMINITCRD_0, 0x4}, + {OP_WR, QM_REG_CMINITCRD_1, 0x4}, + {OP_WR, QM_REG_CMINITCRD_2, 0x4}, + {OP_WR, QM_REG_CMINITCRD_3, 0x4}, + {OP_WR, QM_REG_CMINITCRD_4, 0x4}, + {OP_WR, QM_REG_CMINITCRD_5, 0x4}, + {OP_WR, QM_REG_CMINITCRD_6, 0x4}, + {OP_WR, QM_REG_CMINITCRD_7, 0x4}, + {OP_WR, QM_REG_OUTLDREQ, 0x4}, + {OP_WR, QM_REG_CTXREG_0, 0x7c}, + {OP_WR, QM_REG_CTXREG_1, 0x3d}, + {OP_WR, QM_REG_CTXREG_2, 0x3f}, + {OP_WR, QM_REG_CTXREG_3, 0x9c}, + {OP_WR, QM_REG_ENSEC, 0x7}, + {OP_ZR, QM_REG_QVOQIDX_0, 0x5}, + {OP_WR, QM_REG_WRRWEIGHTS_0, 0x1010101}, + {OP_WR, QM_REG_QVOQIDX_5, 0x0}, + {OP_WR, QM_REG_QVOQIDX_6, 0x4}, + {OP_WR, QM_REG_QVOQIDX_7, 0x4}, + {OP_WR, QM_REG_QVOQIDX_8, 0x2}, + {OP_WR, QM_REG_WRRWEIGHTS_1, 0x8012004}, + {OP_WR, QM_REG_QVOQIDX_9, 0x5}, + {OP_WR, QM_REG_QVOQIDX_10, 0x5}, + {OP_WR, QM_REG_QVOQIDX_11, 0x5}, + {OP_WR, QM_REG_QVOQIDX_12, 0x5}, + {OP_WR, QM_REG_WRRWEIGHTS_2, 0x20081001}, + {OP_WR, QM_REG_QVOQIDX_13, 0x8}, + {OP_WR, QM_REG_QVOQIDX_14, 0x6}, + {OP_WR, QM_REG_QVOQIDX_15, 0x7}, + {OP_WR, QM_REG_QVOQIDX_16, 0x0}, + {OP_WR, QM_REG_WRRWEIGHTS_3, 0x1010120}, + {OP_ZR, QM_REG_QVOQIDX_17, 0x4}, + {OP_WR, QM_REG_WRRWEIGHTS_4, 0x1010101}, + {OP_ZR, QM_REG_QVOQIDX_21, 0x4}, + {OP_WR, QM_REG_WRRWEIGHTS_5, 0x1010101}, + {OP_ZR, QM_REG_QVOQIDX_25, 0x4}, + {OP_WR, QM_REG_WRRWEIGHTS_6, 0x1010101}, + {OP_ZR, QM_REG_QVOQIDX_29, 0x3}, + {OP_WR, QM_REG_QVOQIDX_32, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_7, 0x1010101}, + {OP_WR, QM_REG_QVOQIDX_33, 0x1}, + {OP_WR, QM_REG_QVOQIDX_34, 0x1}, + {OP_WR, QM_REG_QVOQIDX_35, 0x1}, + {OP_WR, QM_REG_QVOQIDX_36, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_8, 0x1010101}, + {OP_WR, QM_REG_QVOQIDX_37, 0x1}, + {OP_WR, QM_REG_QVOQIDX_38, 0x4}, + {OP_WR, QM_REG_QVOQIDX_39, 0x4}, + {OP_WR, QM_REG_QVOQIDX_40, 0x2}, + {OP_WR, QM_REG_WRRWEIGHTS_9, 0x8012004}, + {OP_WR, QM_REG_QVOQIDX_41, 0x5}, + {OP_WR, QM_REG_QVOQIDX_42, 0x5}, + {OP_WR, QM_REG_QVOQIDX_43, 0x5}, + {OP_WR, QM_REG_QVOQIDX_44, 0x5}, + {OP_WR, QM_REG_WRRWEIGHTS_10, 0x20081001}, + {OP_WR, QM_REG_QVOQIDX_45, 0x8}, + {OP_WR, QM_REG_QVOQIDX_46, 0x6}, + {OP_WR, QM_REG_QVOQIDX_47, 0x7}, + {OP_WR, QM_REG_QVOQIDX_48, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_11, 0x1010120}, + {OP_WR, QM_REG_QVOQIDX_49, 0x1}, + {OP_WR, QM_REG_QVOQIDX_50, 0x1}, + {OP_WR, QM_REG_QVOQIDX_51, 0x1}, + {OP_WR, QM_REG_QVOQIDX_52, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_12, 0x1010101}, + {OP_WR, QM_REG_QVOQIDX_53, 0x1}, + {OP_WR, QM_REG_QVOQIDX_54, 0x1}, + {OP_WR, QM_REG_QVOQIDX_55, 0x1}, + {OP_WR, QM_REG_QVOQIDX_56, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_13, 0x1010101}, + {OP_WR, QM_REG_QVOQIDX_57, 0x1}, + {OP_WR, QM_REG_QVOQIDX_58, 0x1}, + {OP_WR, QM_REG_QVOQIDX_59, 0x1}, + {OP_WR, QM_REG_QVOQIDX_60, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_14, 0x1010101}, + {OP_WR, QM_REG_QVOQIDX_61, 0x1}, + {OP_WR, QM_REG_QVOQIDX_62, 0x1}, + {OP_WR, QM_REG_QVOQIDX_63, 0x1}, + {OP_WR, QM_REG_WRRWEIGHTS_15, 0x1010101}, + {OP_WR, QM_REG_VOQQMASK_0_LSB, 0xffff003f}, + {OP_ZR, QM_REG_VOQQMASK_0_MSB, 0x2}, + {OP_WR, QM_REG_VOQQMASK_1_MSB, 0xffff003f}, + {OP_WR, QM_REG_VOQQMASK_2_LSB, 0x100}, + {OP_WR, QM_REG_VOQQMASK_2_MSB, 0x100}, + {OP_ZR, QM_REG_VOQQMASK_3_LSB, 0x2}, + {OP_WR, QM_REG_VOQQMASK_4_LSB, 0xc0}, + {OP_WR, QM_REG_VOQQMASK_4_MSB, 0xc0}, + {OP_WR, QM_REG_VOQQMASK_5_LSB, 0x1e00}, + {OP_WR, QM_REG_VOQQMASK_5_MSB, 0x1e00}, + {OP_WR, QM_REG_VOQQMASK_6_LSB, 0x4000}, + {OP_WR, QM_REG_VOQQMASK_6_MSB, 0x4000}, + {OP_WR, QM_REG_VOQQMASK_7_LSB, 0x8000}, + {OP_WR, QM_REG_VOQQMASK_7_MSB, 0x8000}, + {OP_WR, QM_REG_VOQQMASK_8_LSB, 0x2000}, + {OP_WR, QM_REG_VOQQMASK_8_MSB, 0x2000}, + {OP_ZR, QM_REG_VOQQMASK_9_LSB, 0x7}, + {OP_WR, QM_REG_VOQPORT_1, 0x1}, + {OP_ZR, QM_REG_VOQPORT_2, 0xa}, + {OP_WR, QM_REG_CMINTVOQMASK_0, 0xc08}, + {OP_WR, QM_REG_CMINTVOQMASK_1, 0x40}, + {OP_WR, QM_REG_CMINTVOQMASK_2, 0x100}, + {OP_WR, QM_REG_CMINTVOQMASK_3, 0x20}, + {OP_WR, QM_REG_CMINTVOQMASK_4, 0x17}, + {OP_WR, QM_REG_CMINTVOQMASK_5, 0x80}, + {OP_WR, QM_REG_CMINTVOQMASK_6, 0x200}, + {OP_WR, QM_REG_CMINTVOQMASK_7, 0x0}, + {OP_WR, QM_REG_HWAEMPTYMASK_LSB, 0xffff01ff}, + {OP_WR, QM_REG_HWAEMPTYMASK_MSB, 0xffff01ff}, + {OP_WR, QM_REG_ENBYPVOQMASK, 0x13}, + {OP_WR, QM_REG_VOQCREDITAFULLTHR, 0x13f}, + {OP_WR, QM_REG_VOQINITCREDIT_0, 0x140}, + {OP_WR, QM_REG_VOQINITCREDIT_1, 0x140}, + {OP_ZR, QM_REG_VOQINITCREDIT_2, 0x2}, + {OP_WR, QM_REG_VOQINITCREDIT_4, 0xc0}, + {OP_ZR, QM_REG_VOQINITCREDIT_5, 0x7}, + {OP_WR, QM_REG_TASKCRDCOST_0, 0x48}, + {OP_WR, QM_REG_TASKCRDCOST_1, 0x48}, + {OP_ZR, QM_REG_TASKCRDCOST_2, 0x2}, + {OP_WR, QM_REG_TASKCRDCOST_4, 0x48}, + {OP_ZR, QM_REG_TASKCRDCOST_5, 0x7}, + {OP_WR, QM_REG_BYTECRDINITVAL, 0x8000}, + {OP_WR, QM_REG_BYTECRDCOST, 0x25e4}, + {OP_WR, QM_REG_BYTECREDITAFULLTHR, 0x7fff}, + {OP_WR, QM_REG_ENBYTECRD_LSB, 0x7}, + {OP_WR, QM_REG_ENBYTECRD_MSB, 0x7}, + {OP_WR, QM_REG_BYTECRDPORT_LSB, 0x0}, + {OP_WR, QM_REG_BYTECRDPORT_MSB, 0xffffffff}, + {OP_WR, QM_REG_FUNCNUMSEL_LSB, 0x0}, + {OP_WR, QM_REG_FUNCNUMSEL_MSB, 0xffffffff}, + {OP_WR, QM_REG_CMINTEN, 0xff}, +#define QM_COMMON_END 829 +#define PBF_COMMON_START 829 + {OP_WR, PBF_REG_INIT, 0x1}, + {OP_WR, PBF_REG_INIT_P4, 0x1}, + {OP_WR, PBF_REG_MAC_LB_ENABLE, 0x1}, + {OP_WR, PBF_REG_IF_ENABLE_REG, 0x7fff}, + {OP_WR, PBF_REG_INIT_P4, 0x0}, + {OP_WR, PBF_REG_INIT, 0x0}, + {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P4, 0x0}, +#define PBF_COMMON_END 836 +#define PBF_PORT0_START 836 + {OP_WR, PBF_REG_INIT_P0, 0x1}, + {OP_WR, PBF_REG_MAC_IF0_ENABLE, 0x1}, + {OP_WR, PBF_REG_INIT_P0, 0x0}, + {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P0, 0x0}, +#define PBF_PORT0_END 840 +#define PBF_PORT1_START 840 + {OP_WR, PBF_REG_INIT_P1, 0x1}, + {OP_WR, PBF_REG_MAC_IF1_ENABLE, 0x1}, + {OP_WR, PBF_REG_INIT_P1, 0x0}, + {OP_WR, PBF_REG_DISABLE_NEW_TASK_PROC_P1, 0x0}, +#define PBF_PORT1_END 844 +#define XCM_COMMON_START 844 + {OP_WR, XCM_REG_XX_OVFL_EVNT_ID, 0x32}, + {OP_WR, XCM_REG_XQM_XCM_HDR_P, 0x3150020}, + {OP_WR, XCM_REG_XQM_XCM_HDR_S, 0x3150020}, + {OP_WR, XCM_REG_TM_XCM_HDR, 0x1000030}, + {OP_WR, XCM_REG_ERR_XCM_HDR, 0x8100000}, + {OP_WR, XCM_REG_ERR_EVNT_ID, 0x33}, + {OP_WR, XCM_REG_EXPR_EVNT_ID, 0x30}, + {OP_WR, XCM_REG_STOP_EVNT_ID, 0x31}, + {OP_WR, XCM_REG_STORM_WEIGHT, 0x2}, + {OP_WR, XCM_REG_TSEM_WEIGHT, 0x5}, + {OP_WR, XCM_REG_CSEM_WEIGHT, 0x2}, + {OP_WR, XCM_REG_USEM_WEIGHT, 0x2}, + {OP_WR, XCM_REG_PBF_WEIGHT, 0x7}, + {OP_WR, XCM_REG_NIG1_WEIGHT, 0x1}, + {OP_WR, XCM_REG_CP_WEIGHT, 0x0}, + {OP_WR, XCM_REG_XSDM_WEIGHT, 0x5}, + {OP_WR, XCM_REG_XQM_P_WEIGHT, 0x3}, + {OP_WR, XCM_REG_XCM_XQM_USE_Q, 0x1}, + {OP_WR, XCM_REG_XQM_BYP_ACT_UPD, 0x6}, + {OP_WR, XCM_REG_UNA_GT_NXT_Q, 0x0}, + {OP_WR, XCM_REG_AUX1_Q, 0x2}, + {OP_WR, XCM_REG_AUX_CNT_FLG_Q_19, 0x1}, + {OP_WR, XCM_REG_GR_ARB_TYPE, 0x1}, + {OP_WR, XCM_REG_GR_LD0_PR, 0x1}, + {OP_WR, XCM_REG_GR_LD1_PR, 0x2}, + {OP_WR, XCM_REG_CFC_INIT_CRD, 0x1}, + {OP_WR, XCM_REG_FIC0_INIT_CRD, 0x40}, + {OP_WR, XCM_REG_FIC1_INIT_CRD, 0x40}, + {OP_WR, XCM_REG_TM_INIT_CRD, 0x4}, + {OP_WR, XCM_REG_XQM_INIT_CRD, 0x20}, + {OP_WR, XCM_REG_XX_INIT_CRD, 0x2}, + {OP_WR, XCM_REG_XX_MSG_NUM, 0x1f}, + {OP_ZR, XCM_REG_XX_TABLE, 0x12}, + {OP_SW, XCM_REG_XX_DESCR_TABLE, 0x1f4d01}, + {OP_WR, XCM_REG_N_SM_CTX_LD_0, 0xf}, + {OP_WR, XCM_REG_N_SM_CTX_LD_1, 0x7}, + {OP_WR, XCM_REG_N_SM_CTX_LD_2, 0xb}, + {OP_WR, XCM_REG_N_SM_CTX_LD_3, 0xe}, + {OP_ZR, XCM_REG_N_SM_CTX_LD_4, 0x4}, + {OP_WR, XCM_REG_XCM_REG0_SZ, 0x4}, + {OP_WR, XCM_REG_XCM_STORM0_IFEN, 0x1}, + {OP_WR, XCM_REG_XCM_STORM1_IFEN, 0x1}, + {OP_WR, XCM_REG_XCM_XQM_IFEN, 0x1}, + {OP_WR, XCM_REG_STORM_XCM_IFEN, 0x1}, + {OP_WR, XCM_REG_XQM_XCM_IFEN, 0x1}, + {OP_WR, XCM_REG_XSDM_IFEN, 0x1}, + {OP_WR, XCM_REG_TM_XCM_IFEN, 0x1}, + {OP_WR, XCM_REG_XCM_TM_IFEN, 0x1}, + {OP_WR, XCM_REG_TSEM_IFEN, 0x1}, + {OP_WR, XCM_REG_CSEM_IFEN, 0x1}, + {OP_WR, XCM_REG_USEM_IFEN, 0x1}, + {OP_WR, XCM_REG_DORQ_IFEN, 0x1}, + {OP_WR, XCM_REG_PBF_IFEN, 0x1}, + {OP_WR, XCM_REG_NIG0_IFEN, 0x1}, + {OP_WR, XCM_REG_NIG1_IFEN, 0x1}, + {OP_WR, XCM_REG_CDU_AG_WR_IFEN, 0x1}, + {OP_WR, XCM_REG_CDU_AG_RD_IFEN, 0x1}, + {OP_WR, XCM_REG_CDU_SM_WR_IFEN, 0x1}, + {OP_WR, XCM_REG_CDU_SM_RD_IFEN, 0x1}, + {OP_WR, XCM_REG_XCM_CFC_IFEN, 0x1}, +#define XCM_COMMON_END 904 +#define XCM_PORT0_START 904 + {OP_WR, XCM_REG_GLB_DEL_ACK_TMR_VAL_0, 0xc8}, + {OP_WR, XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 0x2}, + {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 0x0}, + {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10, 0x0}, + {OP_WR, XCM_REG_WU_DA_CNT_CMD00, 0x2}, + {OP_WR, XCM_REG_WU_DA_CNT_CMD10, 0x2}, + {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL00, 0xff}, + {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL10, 0xff}, +#define XCM_PORT0_END 912 +#define XCM_PORT1_START 912 + {OP_WR, XCM_REG_GLB_DEL_ACK_TMR_VAL_1, 0xc8}, + {OP_WR, XCM_REG_GLB_DEL_ACK_MAX_CNT_1, 0x2}, + {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01, 0x0}, + {OP_WR, XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11, 0x0}, + {OP_WR, XCM_REG_WU_DA_CNT_CMD01, 0x2}, + {OP_WR, XCM_REG_WU_DA_CNT_CMD11, 0x2}, + {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL01, 0xff}, + {OP_WR, XCM_REG_WU_DA_CNT_UPD_VAL11, 0xff}, +#define XCM_PORT1_END 920 +#define XSEM_COMMON_START 920 + {OP_RD, XSEM_REG_MSG_NUM_FIC0, 0x0}, + {OP_RD, XSEM_REG_MSG_NUM_FIC1, 0x0}, + {OP_RD, XSEM_REG_MSG_NUM_FOC0, 0x0}, + {OP_RD, XSEM_REG_MSG_NUM_FOC1, 0x0}, + {OP_RD, XSEM_REG_MSG_NUM_FOC2, 0x0}, + {OP_RD, XSEM_REG_MSG_NUM_FOC3, 0x0}, + {OP_WR, XSEM_REG_ARB_ELEMENT0, 0x1}, + {OP_WR, XSEM_REG_ARB_ELEMENT1, 0x2}, + {OP_WR, XSEM_REG_ARB_ELEMENT2, 0x3}, + {OP_WR, XSEM_REG_ARB_ELEMENT3, 0x0}, + {OP_WR, XSEM_REG_ARB_ELEMENT4, 0x4}, + {OP_WR, XSEM_REG_ARB_CYCLE_SIZE, 0x1}, + {OP_WR, XSEM_REG_TS_0_AS, 0x0}, + {OP_WR, XSEM_REG_TS_1_AS, 0x1}, + {OP_WR, XSEM_REG_TS_2_AS, 0x4}, + {OP_WR, XSEM_REG_TS_3_AS, 0x0}, + {OP_WR, XSEM_REG_TS_4_AS, 0x1}, + {OP_WR, XSEM_REG_TS_5_AS, 0x3}, + {OP_WR, XSEM_REG_TS_6_AS, 0x0}, + {OP_WR, XSEM_REG_TS_7_AS, 0x1}, + {OP_WR, XSEM_REG_TS_8_AS, 0x4}, + {OP_WR, XSEM_REG_TS_9_AS, 0x0}, + {OP_WR, XSEM_REG_TS_10_AS, 0x1}, + {OP_WR, XSEM_REG_TS_11_AS, 0x3}, + {OP_WR, XSEM_REG_TS_12_AS, 0x0}, + {OP_WR, XSEM_REG_TS_13_AS, 0x1}, + {OP_WR, XSEM_REG_TS_14_AS, 0x4}, + {OP_WR, XSEM_REG_TS_15_AS, 0x0}, + {OP_WR, XSEM_REG_TS_16_AS, 0x4}, + {OP_WR, XSEM_REG_TS_17_AS, 0x3}, + {OP_ZR, XSEM_REG_TS_18_AS, 0x2}, + {OP_WR, XSEM_REG_ENABLE_IN, 0x3fff}, + {OP_WR, XSEM_REG_ENABLE_OUT, 0x3ff}, + {OP_WR, XSEM_REG_FIC0_DISABLE, 0x0}, + {OP_WR, XSEM_REG_FIC1_DISABLE, 0x0}, + {OP_WR, XSEM_REG_PAS_DISABLE, 0x0}, + {OP_WR, XSEM_REG_THREADS_LIST, 0xffff}, + {OP_ZR, XSEM_REG_PASSIVE_BUFFER, 0x800}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18bc0, 0x1}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18000, 0x0}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18040, 0x18}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18080, 0xc}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x180c0, 0x66}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18300, 0x7a120}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x183c0, 0x1f4}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18340, 0x1f4}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x18380, 0x1dcd6500}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x55d8, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5000, 0x48}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1020, 0xc8}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1000, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5128, 0x92}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x5378, 0x0}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x5380, 0x24d20}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x5428, 0x44d22}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x1518, 0x1}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x1830, 0x0}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x1838, 0x0}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x1820, 0x24d26}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4ac0, 0x2}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x4ad8, 0x24d28}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4b08, 0x4}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x1f50, 0x24d2a}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x0}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c00, 0x104d2c}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x1000000}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c40, 0x84d3c}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x2000000}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c60, 0x84d44}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x10800, 0x3000000}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x10c80, 0x84d4c}, + {OP_ZP, XSEM_REG_INT_TABLE, 0x814d54}, + {OP_ZP, XSEM_REG_PRAM, 0x35774d75}, + {OP_ZP, XSEM_REG_PRAM + 0x8000, 0x36525ad3}, + {OP_ZP, XSEM_REG_PRAM + 0x10000, 0x27266868}, + {OP_ZP, XSEM_REG_PRAM + 0x18000, 0x5e7232}, + {OP_ZP, XSEM_REG_PRAM + 0x20000, 0x5e724a}, + {OP_ZP, XSEM_REG_PRAM + 0x28000, 0x5e7262}, + {OP_ZP, XSEM_REG_PRAM + 0x30000, 0x5e727a}, + {OP_ZP, XSEM_REG_PRAM + 0x38000, 0x5e7292}, +#define XSEM_COMMON_END 1000 +#define XSEM_PORT0_START 1000 + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1400, 0xa}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1450, 0x6}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5388, 0xc}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x5388 + 0x30, 0x272aa}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x55e0, 0x772ac}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5600, 0x7}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x1500, 0x0}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x1508, 0x1}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3020, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3030, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3000, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3010, 0x2}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x3040, 0x0}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3048, 0xc}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x3048 + 0x30, 0x272b3}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x30b8, 0x1}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x4ac8, 0x272b5}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4b18, 0x42}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4d28, 0x4}, +#define XSEM_PORT0_END 1019 +#define XSEM_PORT1_START 1019 + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1428, 0xa}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x1468, 0x6}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x53c0, 0xc}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x53c0 + 0x30, 0x272b7}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x5620, 0x772b9}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x5640, 0x7}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x1504, 0x0}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x150c, 0x1}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3028, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3038, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3008, 0x2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3018, 0x2}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x3044, 0x0}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x3080, 0xc}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x3080 + 0x30, 0x272c0}, + {OP_WR, XSEM_REG_FAST_MEMORY + 0x30bc, 0x1}, + {OP_SW, XSEM_REG_FAST_MEMORY + 0x4ad0, 0x272c2}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4c20, 0x42}, + {OP_ZR, XSEM_REG_FAST_MEMORY + 0x4d38, 0x4}, +#define XSEM_PORT1_END 1038 +#define CDU_COMMON_START 1038 + {OP_WR, CDU_REG_CDU_CONTROL0, 0x1}, + {OP_WR, CDU_REG_CDU_CHK_MASK0, 0x3d000}, + {OP_WR, CDU_REG_CDU_CHK_MASK1, 0x3d}, + {OP_WB, CDU_REG_L1TT, 0x20072c4}, + {OP_WB, CDU_REG_MATT, 0x2074c4}, + {OP_ZR, CDU_REG_MATT + 0x80, 0x20}, +#define CDU_COMMON_END 1044 +#define DMAE_COMMON_START 1044 + {OP_WR, DMAE_REG_CRC16C_INIT, 0x0}, + {OP_WR, DMAE_REG_CRC16T10_INIT, 0x1}, + {OP_WR, DMAE_REG_PXP_REQ_INIT_CRD, 0x2}, + {OP_WR, DMAE_REG_PCI_IFEN, 0x1}, + {OP_WR, DMAE_REG_GRC_IFEN, 0x1}, +#define DMAE_COMMON_END 1049 +#define PXP_COMMON_START 1049 + {OP_SI, PXP_REG_HST_INBOUND_INT + 0x400, 0x574e4}, + {OP_SI, PXP_REG_HST_INBOUND_INT + 0x420, 0x574e9}, + {OP_SI, PXP_REG_HST_INBOUND_INT, 0x574ee}, +#define PXP_COMMON_END 1052 +#define CFC_COMMON_START 1052 + {OP_WR, CFC_REG_CONTROL0, 0x10}, + {OP_WR, CFC_REG_DISABLE_ON_ERROR, 0x3fff}, + {OP_WR, CFC_REG_LCREQ_WEIGHTS, 0x84924a}, +#define CFC_COMMON_END 1055 +#define HC_COMMON_START 1055 + {OP_ZR, HC_REG_USTORM_ADDR_FOR_COALESCE, 0x4}, +#define HC_COMMON_END 1056 +#define HC_PORT0_START 1056 + {OP_WR, HC_REG_CONFIG_0, 0x1080}, + {OP_ZR, HC_REG_UC_RAM_ADDR_0, 0x2}, + {OP_WR, HC_REG_ATTN_NUM_P0, 0x10}, + {OP_WR, HC_REG_LEADING_EDGE_0, 0xffff}, + {OP_WR, HC_REG_TRAILING_EDGE_0, 0xffff}, + {OP_WR, HC_REG_AGG_INT_0, 0x0}, + {OP_WR, HC_REG_ATTN_IDX, 0x0}, + {OP_ZR, HC_REG_ATTN_BIT, 0x2}, + {OP_WR, HC_REG_VQID_0, 0x2b5}, + {OP_WR, HC_REG_PCI_CONFIG_0, 0x0}, + {OP_ZR, HC_REG_P0_PROD_CONS, 0x4a}, + {OP_ZR, HC_REG_PBA_COMMAND, 0x2}, + {OP_WR, HC_REG_INT_MASK, 0x1ffff}, + {OP_WR, HC_REG_CONFIG_0, 0x1a82}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS, 0x24}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x120, 0x4a}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x370, 0x4a}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x5c0, 0x4a}, +#define HC_PORT0_END 1074 +#define HC_PORT1_START 1074 + {OP_WR, HC_REG_CONFIG_1, 0x1080}, + {OP_ZR, HC_REG_UC_RAM_ADDR_1, 0x2}, + {OP_WR, HC_REG_ATTN_NUM_P1, 0x10}, + {OP_WR, HC_REG_LEADING_EDGE_1, 0xffff}, + {OP_WR, HC_REG_TRAILING_EDGE_1, 0xffff}, + {OP_WR, HC_REG_AGG_INT_1, 0x0}, + {OP_WR, HC_REG_ATTN_IDX + 0x4, 0x0}, + {OP_ZR, HC_REG_ATTN_BIT + 0x8, 0x2}, + {OP_WR, HC_REG_VQID_1, 0x2b5}, + {OP_WR, HC_REG_PCI_CONFIG_1, 0x0}, + {OP_ZR, HC_REG_P1_PROD_CONS, 0x4a}, + {OP_ZR, HC_REG_PBA_COMMAND + 0x8, 0x2}, + {OP_WR, HC_REG_INT_MASK + 0x4, 0x1ffff}, + {OP_WR, HC_REG_CONFIG_1, 0x1a82}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x90, 0x24}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x248, 0x4a}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x498, 0x4a}, + {OP_ZR, HC_REG_STATISTIC_COUNTERS + 0x6e8, 0x4a}, +#define HC_PORT1_END 1092 +#define PXP2_COMMON_START 1092 + {OP_WR, PXP2_REG_PGL_CONTROL0, 0xe38324}, + {OP_WR, PXP2_REG_PGL_CONTROL1, 0x3c10}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_0, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_1, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_2, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_3, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_4, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_5, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_6, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_TSDM_7, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_1, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_2, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_3, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_4, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_5, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_6, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_USDM_7, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_2, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_3, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_4, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_5, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_6, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_7, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_0, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_1, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_2, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_3, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_4, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_5, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_6, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_CSDM_7, 0xffffffff}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_0, 0xffff5330}, + {OP_WR, PXP2_REG_PGL_INT_XSDM_1, 0xffff5348}, + {OP_WR, PXP2_REG_PGL_INT_USDM_0, 0xf0003000}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ6, 0x8}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ9, 0x8}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ10, 0x8}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ11, 0x2}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ17, 0x4}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ18, 0x5}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ19, 0x4}, + {OP_WR, PXP2_REG_RD_MAX_BLKS_VQ22, 0x0}, + {OP_WR, PXP2_REG_RD_START_INIT, 0x1}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD0, 0x40}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD1, 0x1808}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD2, 0x803}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD3, 0x803}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD4, 0x40}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD5, 0x3}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD6, 0x803}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD7, 0x803}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD8, 0x803}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD9, 0x10003}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD10, 0x803}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD11, 0x803}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD12, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD13, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD14, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD15, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD16, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD17, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD18, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD19, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD20, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD22, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD23, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD24, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD25, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD26, 0x3}, + {OP_WR, PXP2_REG_RQ_BW_RD_ADD27, 0x3}, + {OP_WR, PXP2_REG_PSWRQ_BW_ADD28, 0x2403}, + {OP_WR, PXP2_REG_RQ_BW_WR_ADD29, 0x2f}, + {OP_WR, PXP2_REG_RQ_BW_WR_ADD30, 0x9}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND0, 0x19}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB1, 0x184}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB2, 0x183}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB3, 0x306}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND4, 0x19}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND5, 0x6}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB6, 0x306}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB7, 0x306}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB8, 0x306}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB9, 0xc86}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB10, 0x306}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB11, 0x306}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND12, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND13, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND14, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND15, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND16, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND17, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND18, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND19, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND20, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND22, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND23, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND24, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND25, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND26, 0x6}, + {OP_WR, PXP2_REG_RQ_BW_RD_UBOUND27, 0x6}, + {OP_WR, PXP2_REG_PSWRQ_BW_UB28, 0x306}, + {OP_WR, PXP2_REG_RQ_BW_WR_UBOUND29, 0x13}, + {OP_WR, PXP2_REG_RQ_BW_WR_UBOUND30, 0x6}, + {OP_WR, PXP2_REG_PSWRQ_BW_L1, 0x1004}, + {OP_WR, PXP2_REG_PSWRQ_BW_L2, 0x1004}, + {OP_WR, PXP2_REG_PSWRQ_BW_RD, 0x106440}, + {OP_WR, PXP2_REG_PSWRQ_BW_WR, 0x106440}, + {OP_WR, PXP2_REG_RQ_RBC_DONE, 0x1}, +#define PXP2_COMMON_END 1200 +#define MISC_AEU_COMMON_START 1200 + {OP_ZR, MISC_REG_AEU_GENERAL_ATTN_0, 0x16}, +#define MISC_AEU_COMMON_END 1201 +#define MISC_AEU_PORT0_START 1201 + {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0, 0xbf5c0000}, + {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0, 0xfff51fef}, + {OP_WR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0, 0xffff}, + {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, 0x500003e0}, + {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1, 0x0}, + {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1, 0xa000}, + {OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1, 0x5}, + {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2, 0xfe00000}, + {OP_ZR, MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3, 0x14}, + {OP_WR, MISC_REG_AEU_ENABLE1_NIG_0, 0x55540000}, + {OP_WR, MISC_REG_AEU_ENABLE2_NIG_0, 0x55555555}, + {OP_WR, MISC_REG_AEU_ENABLE3_NIG_0, 0x5555}, + {OP_WR, MISC_REG_AEU_ENABLE4_NIG_0, 0x0}, + {OP_WR, MISC_REG_AEU_ENABLE1_PXP_0, 0x55540000}, + {OP_WR, MISC_REG_AEU_ENABLE2_PXP_0, 0x55555555}, + {OP_WR, MISC_REG_AEU_ENABLE3_PXP_0, 0x5555}, + {OP_WR, MISC_REG_AEU_ENABLE4_PXP_0, 0x0}, + {OP_WR, MISC_REG_AEU_INVERTER_1_FUNC_0, 0x0}, + {OP_ZR, MISC_REG_AEU_INVERTER_2_FUNC_0, 0x3}, + {OP_WR, MISC_REG_AEU_MASK_ATTN_FUNC_0, 0x7}, +#define MISC_AEU_PORT0_END 1221 +#define MISC_AEU_PORT1_START 1221 + {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0, 0xbf5c0000}, + {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0, 0xfff51fef}, + {OP_WR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0, 0xffff}, + {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, 0x500003e0}, + {OP_WR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1, 0x0}, + {OP_WR, MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1, 0xa000}, + {OP_ZR, MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1, 0x5}, + {OP_WR, MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2, 0xfe00000}, + {OP_ZR, MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3, 0x14}, + {OP_WR, MISC_REG_AEU_ENABLE1_NIG_1, 0x55540000}, + {OP_WR, MISC_REG_AEU_ENABLE2_NIG_1, 0x55555555}, + {OP_WR, MISC_REG_AEU_ENABLE3_NIG_1, 0x5555}, + {OP_WR, MISC_REG_AEU_ENABLE4_NIG_1, 0x0}, + {OP_WR, MISC_REG_AEU_ENABLE1_PXP_1, 0x55540000}, + {OP_WR, MISC_REG_AEU_ENABLE2_PXP_1, 0x55555555}, + {OP_WR, MISC_REG_AEU_ENABLE3_PXP_1, 0x5555}, + {OP_WR, MISC_REG_AEU_ENABLE4_PXP_1, 0x0}, + {OP_WR, MISC_REG_AEU_INVERTER_1_FUNC_1, 0x0}, + {OP_ZR, MISC_REG_AEU_INVERTER_2_FUNC_1, 0x3}, + {OP_WR, MISC_REG_AEU_MASK_ATTN_FUNC_1, 0x7} +#define MISC_AEU_PORT1_END 1241 +}; + +static const u32 init_data[] = { + 0x00010000, 0x000204c0, 0x00030980, 0x00040e40, 0x00051300, 0x000617c0, + 0x00071c80, 0x00082140, 0x00092600, 0x000a2ac0, 0x000b2f80, 0x000c3440, + 0x000d3900, 0x000e3dc0, 0x000f4280, 0x00104740, 0x00114c00, 0x001250c0, + 0x00135580, 0x00145a40, 0x00155f00, 0x001663c0, 0x00176880, 0x00186d40, + 0x00197200, 0x001a76c0, 0x001b7b80, 0x001c8040, 0x001d8500, 0x001e89c0, + 0x001f8e80, 0x00209340, 0x00002000, 0x00004000, 0x00006000, 0x00008000, + 0x0000a000, 0x0000c000, 0x0000e000, 0x00010000, 0x00012000, 0x00014000, + 0x00016000, 0x00018000, 0x0001a000, 0x0001c000, 0x0001e000, 0x00020000, + 0x00022000, 0x00024000, 0x00026000, 0x00028000, 0x0002a000, 0x0002c000, + 0x0002e000, 0x00030000, 0x00032000, 0x00034000, 0x00036000, 0x00038000, + 0x0003a000, 0x0003c000, 0x0003e000, 0x00040000, 0x00042000, 0x00044000, + 0x00046000, 0x00048000, 0x0004a000, 0x0004c000, 0x0004e000, 0x00050000, + 0x00052000, 0x00054000, 0x00056000, 0x00058000, 0x0005a000, 0x0005c000, + 0x0005e000, 0x00060000, 0x00062000, 0x00064000, 0x00066000, 0x00068000, + 0x0006a000, 0x0006c000, 0x0006e000, 0x00070000, 0x00072000, 0x00074000, + 0x00076000, 0x00078000, 0x0007a000, 0x0007c000, 0x0007e000, 0x00080000, + 0x00082000, 0x00084000, 0x00086000, 0x00088000, 0x0008a000, 0x0008c000, + 0x0008e000, 0x00090000, 0x00092000, 0x00094000, 0x00096000, 0x00098000, + 0x0009a000, 0x0009c000, 0x0009e000, 0x000a0000, 0x000a2000, 0x000a4000, + 0x000a6000, 0x000a8000, 0x000aa000, 0x000ac000, 0x000ae000, 0x000b0000, + 0x000b2000, 0x000b4000, 0x000b6000, 0x000b8000, 0x000ba000, 0x000bc000, + 0x000be000, 0x000c0000, 0x000c2000, 0x000c4000, 0x000c6000, 0x000c8000, + 0x000ca000, 0x000cc000, 0x000ce000, 0x000d0000, 0x000d2000, 0x000d4000, + 0x000d6000, 0x000d8000, 0x000da000, 0x000dc000, 0x000de000, 0x000e0000, + 0x000e2000, 0x000e4000, 0x000e6000, 0x000e8000, 0x000ea000, 0x000ec000, + 0x000ee000, 0x000f0000, 0x000f2000, 0x000f4000, 0x000f6000, 0x000f8000, + 0x000fa000, 0x000fc000, 0x000fe000, 0x00100000, 0x00102000, 0x00104000, + 0x00106000, 0x00108000, 0x0010a000, 0x0010c000, 0x0010e000, 0x00110000, + 0x00112000, 0x00114000, 0x00116000, 0x00118000, 0x0011a000, 0x0011c000, + 0x0011e000, 0x00120000, 0x00122000, 0x00124000, 0x00126000, 0x00128000, + 0x0012a000, 0x0012c000, 0x0012e000, 0x00130000, 0x00132000, 0x00134000, + 0x00136000, 0x00138000, 0x0013a000, 0x0013c000, 0x0013e000, 0x00140000, + 0x00142000, 0x00144000, 0x00146000, 0x00148000, 0x0014a000, 0x0014c000, + 0x0014e000, 0x00150000, 0x00152000, 0x00154000, 0x00156000, 0x00158000, + 0x0015a000, 0x0015c000, 0x0015e000, 0x00160000, 0x00162000, 0x00164000, + 0x00166000, 0x00168000, 0x0016a000, 0x0016c000, 0x0016e000, 0x00170000, + 0x00172000, 0x00174000, 0x00176000, 0x00178000, 0x0017a000, 0x0017c000, + 0x0017e000, 0x00180000, 0x00182000, 0x00184000, 0x00186000, 0x00188000, + 0x0018a000, 0x0018c000, 0x0018e000, 0x00190000, 0x00192000, 0x00194000, + 0x00196000, 0x00198000, 0x0019a000, 0x0019c000, 0x0019e000, 0x001a0000, + 0x001a2000, 0x001a4000, 0x001a6000, 0x001a8000, 0x001aa000, 0x001ac000, + 0x001ae000, 0x001b0000, 0x001b2000, 0x001b4000, 0x001b6000, 0x001b8000, + 0x001ba000, 0x001bc000, 0x001be000, 0x001c0000, 0x001c2000, 0x001c4000, + 0x001c6000, 0x001c8000, 0x001ca000, 0x001cc000, 0x001ce000, 0x001d0000, + 0x001d2000, 0x001d4000, 0x001d6000, 0x001d8000, 0x001da000, 0x001dc000, + 0x001de000, 0x001e0000, 0x001e2000, 0x001e4000, 0x001e6000, 0x001e8000, + 0x001ea000, 0x001ec000, 0x001ee000, 0x001f0000, 0x001f2000, 0x001f4000, + 0x001f6000, 0x001f8000, 0x001fa000, 0x001fc000, 0x001fe000, 0x00200000, + 0x00202000, 0x00204000, 0x00206000, 0x00208000, 0x0020a000, 0x0020c000, + 0x0020e000, 0x00210000, 0x00212000, 0x00214000, 0x00216000, 0x00218000, + 0x0021a000, 0x0021c000, 0x0021e000, 0x00220000, 0x00222000, 0x00224000, + 0x00226000, 0x00228000, 0x0022a000, 0x0022c000, 0x0022e000, 0x00230000, + 0x00232000, 0x00234000, 0x00236000, 0x00238000, 0x0023a000, 0x0023c000, + 0x0023e000, 0x00240000, 0x00242000, 0x00244000, 0x00246000, 0x00248000, + 0x0024a000, 0x0024c000, 0x0024e000, 0x00250000, 0x00252000, 0x00254000, + 0x00256000, 0x00258000, 0x0025a000, 0x0025c000, 0x0025e000, 0x00260000, + 0x00262000, 0x00264000, 0x00266000, 0x00268000, 0x0026a000, 0x0026c000, + 0x0026e000, 0x00270000, 0x00272000, 0x00274000, 0x00276000, 0x00278000, + 0x0027a000, 0x0027c000, 0x0027e000, 0x00280000, 0x00282000, 0x00284000, + 0x00286000, 0x00288000, 0x0028a000, 0x0028c000, 0x0028e000, 0x00290000, + 0x00292000, 0x00294000, 0x00296000, 0x00298000, 0x0029a000, 0x0029c000, + 0x0029e000, 0x002a0000, 0x002a2000, 0x002a4000, 0x002a6000, 0x002a8000, + 0x002aa000, 0x002ac000, 0x002ae000, 0x002b0000, 0x002b2000, 0x002b4000, + 0x002b6000, 0x002b8000, 0x002ba000, 0x002bc000, 0x002be000, 0x002c0000, + 0x002c2000, 0x002c4000, 0x002c6000, 0x002c8000, 0x002ca000, 0x002cc000, + 0x002ce000, 0x002d0000, 0x002d2000, 0x002d4000, 0x002d6000, 0x002d8000, + 0x002da000, 0x002dc000, 0x002de000, 0x002e0000, 0x002e2000, 0x002e4000, + 0x002e6000, 0x002e8000, 0x002ea000, 0x002ec000, 0x002ee000, 0x002f0000, + 0x002f2000, 0x002f4000, 0x002f6000, 0x002f8000, 0x002fa000, 0x002fc000, + 0x002fe000, 0x00300000, 0x00302000, 0x00304000, 0x00306000, 0x00308000, + 0x0030a000, 0x0030c000, 0x0030e000, 0x00310000, 0x00312000, 0x00314000, + 0x00316000, 0x00318000, 0x0031a000, 0x0031c000, 0x0031e000, 0x00320000, + 0x00322000, 0x00324000, 0x00326000, 0x00328000, 0x0032a000, 0x0032c000, + 0x0032e000, 0x00330000, 0x00332000, 0x00334000, 0x00336000, 0x00338000, + 0x0033a000, 0x0033c000, 0x0033e000, 0x00340000, 0x00342000, 0x00344000, + 0x00346000, 0x00348000, 0x0034a000, 0x0034c000, 0x0034e000, 0x00350000, + 0x00352000, 0x00354000, 0x00356000, 0x00358000, 0x0035a000, 0x0035c000, + 0x0035e000, 0x00360000, 0x00362000, 0x00364000, 0x00366000, 0x00368000, + 0x0036a000, 0x0036c000, 0x0036e000, 0x00370000, 0x00372000, 0x00374000, + 0x00376000, 0x00378000, 0x0037a000, 0x0037c000, 0x0037e000, 0x00380000, + 0x00382000, 0x00384000, 0x00386000, 0x00388000, 0x0038a000, 0x0038c000, + 0x0038e000, 0x00390000, 0x00392000, 0x00394000, 0x00396000, 0x00398000, + 0x0039a000, 0x0039c000, 0x0039e000, 0x003a0000, 0x003a2000, 0x003a4000, + 0x003a6000, 0x003a8000, 0x003aa000, 0x003ac000, 0x003ae000, 0x003b0000, + 0x003b2000, 0x003b4000, 0x003b6000, 0x003b8000, 0x003ba000, 0x003bc000, + 0x003be000, 0x003c0000, 0x003c2000, 0x003c4000, 0x003c6000, 0x003c8000, + 0x003ca000, 0x003cc000, 0x003ce000, 0x003d0000, 0x003d2000, 0x003d4000, + 0x003d6000, 0x003d8000, 0x003da000, 0x003dc000, 0x003de000, 0x003e0000, + 0x003e2000, 0x003e4000, 0x003e6000, 0x003e8000, 0x003ea000, 0x003ec000, + 0x003ee000, 0x003f0000, 0x003f2000, 0x003f4000, 0x003f6000, 0x003f8000, + 0x003fa000, 0x003fc000, 0x003fe000, 0x003fe001, 0x00000000, 0x000001ff, + 0x00000200, 0x00000001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00088b1f, 0x00000000, + 0x51fbff00, 0x03f0c0cf, 0x3130ef8a, 0x22b1c430, 0x3b0143f8, 0x02ecdd01, + 0xdc406ec4, 0x19b7c404, 0x23dfd348, 0xf1476080, 0x03343031, 0x032f3731, + 0x423f2483, 0x4d5011fc, 0x02ef9025, 0xa40cdb15, 0x77280475, 0xf2c060fb, + 0x77629812, 0x056c1144, 0x58c8f22c, 0x4dde4d11, 0x44af950c, 0xe340ff40, + 0xfca8b235, 0x6d081948, 0x8b5f150b, 0x95051f26, 0xd0849577, 0xe76964eb, + 0x00607a36, 0x2726b9d6, 0x00000400, 0x00088b1f, 0x00000000, 0x7dedff00, + 0xd554780b, 0x333ef0b5, 0x64ccce67, 0x093c991e, 0x20f264af, 0xf09c0682, + 0x93a8a808, 0x07be3040, 0x0e22a5e4, 0x27902018, 0xf5e8bd48, 0x620c19bf, + 0x2f06d6b4, 0x93a45a2a, 0xb6968a80, 0x6c1a06c1, 0x822203b4, 0x6b06f5bf, + 0x368b6d7b, 0x2062a28a, 0xa5ebd8b9, 0xaffadaf7, 0x99def6b5, 0x91332673, + 0xfebffdaa, 0x5fa7f7df, 0xf7b3ecdd, 0xf5ed7bd9, 0xb3ef6b5e, 0xa66e6547, + 0x97d8ce5d, 0x9be507f8, 0x232c630a, 0xa1bbd65a, 0xed58cc9c, 0x9ef8731e, + 0xec66c65c, 0x4f2e44b1, 0x12ab7a87, 0xf4dd42b6, 0x4fda9d92, 0x7af5e56f, + 0x9743f773, 0xb9fb3b40, 0x05053d99, 0x589bb1eb, 0x6c276309, 0xf2f5ff8c, + 0xaf3b72fa, 0x5feeb6d6, 0x557fa0cc, 0xe1d995a7, 0x661d13fd, 0x3cd7d63f, + 0xc01984a5, 0x3eefbb50, 0xbf8c046d, 0xdbb4ac22, 0x0a7f50bd, 0xcafb421e, + 0xfb18730e, 0x33bbb9f7, 0x4ec64e03, 0x5798da36, 0x937ef843, 0xd8c453d9, + 0x59eef0aa, 0xaadfa023, 0x04cf8a5d, 0xaadaacf3, 0x8c9f2e44, 0x19b095cf, + 0xe9dea886, 0x1cb1de60, 0xcd192f86, 0xf358eb4b, 0xe30bcc24, 0x0b45b532, + 0x4dbe70b8, 0xc515d79a, 0x0f46c9cf, 0xb5eb23cd, 0xf03cc2cf, 0x144fdd5e, + 0xceb12e1f, 0x30ed82c4, 0xf67de9ff, 0xb89ddb85, 0xa15af5be, 0x258ebf4b, + 0xab1d717b, 0x2cdaadc2, 0xaad5c227, 0x8e8a2f2d, 0xcd33bd57, 0xfc96d708, + 0x7b5d4161, 0x91b2796c, 0xb4616f31, 0x7f318abe, 0x0fe113bb, 0x47c7b36b, + 0x29641f9f, 0x9deacf44, 0x45b5e666, 0x442c67c7, 0x17cccdcf, 0x2eb2bc41, + 0xb74f4f97, 0xdd231e33, 0x7788a4d6, 0x7df3c013, 0x024d8741, 0xf843df4f, + 0x7bf64ca0, 0xfeb0abd6, 0xa3cc99e4, 0x26fef10c, 0x1ed85b0b, 0x900bbd67, + 0x1630a619, 0xb7822664, 0xc26f058e, 0x50d4cfb2, 0x5fc3c005, 0xeb002b24, + 0xefe14fbd, 0xd4bccf5f, 0x9ad1beff, 0xe9bae91f, 0xe6ed92ca, 0x7496b15c, + 0xfa7f2fac, 0xb5321801, 0xbf10cfc2, 0x88ade22a, 0x43321e16, 0xca576bbb, + 0x7abc07c4, 0xc72d95fc, 0x4d93dcf9, 0xa678fa06, 0xa9ea1927, 0xf0635333, + 0xb89cf4eb, 0x4e01d440, 0x827fa9ab, 0x6958cf9a, 0xedf88db6, 0xe48d6c8e, + 0x38cb8ee6, 0x3b64775c, 0x7fa821c3, 0x08b85f17, 0x42f05aea, 0xc07c1c4f, + 0x859626cc, 0xa6c4d065, 0x466f6e0d, 0x941f023c, 0xf8517ce5, 0xa6f5941e, + 0x2814c2fe, 0x21a52b57, 0xc446cbc4, 0x330e9423, 0x3b75c06b, 0xd4f08cac, + 0x7b64a63c, 0xfba78748, 0xb94f0173, 0xb7ef71d1, 0x1f316434, 0xca840f63, + 0xc070ea43, 0xf7102e6f, 0x3cb78462, 0xf7802a12, 0x42c8ef73, 0x9034da7c, + 0x1afcfd03, 0xf3445fcc, 0x1f1e20b7, 0x9d8c7415, 0xcd3856df, 0xaf3dbf30, + 0x5dbf30ca, 0x2781f983, 0x2b5d089f, 0x8e3c07e6, 0xec07ec60, 0x96df9a5a, + 0x6fe68eb7, 0x619558d6, 0xf981a4fe, 0xd3ef38c3, 0x2e6fe609, 0xfeb8d8bc, + 0xf5c655bc, 0xcffd7c6b, 0xf989e685, 0x3ffd6893, 0xfaf8f362, 0xebe2eef3, + 0xfab8c2b7, 0xf803ddf9, 0xefbc476f, 0xdb7f804d, 0xeb8dd379, 0xae31afcf, + 0x7fe7cadf, 0x988b7421, 0xfff349df, 0xd7c2dd82, 0xcd377f9f, 0xf836b56f, + 0xcd64d03c, 0x23086a49, 0x7fe17b5f, 0x802ca0c3, 0x5942a679, 0xbc18ca94, + 0x47961dff, 0x2923b878, 0xfff61e78, 0xcdf8093c, 0x2c0bd519, 0xb94151bc, + 0x5d3c13af, 0xf6896bb9, 0xb2a5783d, 0x064beb93, 0xc00c74fa, 0xb3f3ba77, + 0xf000ffcf, 0xf628ee56, 0x8f24bd99, 0x265bdf0c, 0xe66f5296, 0x902c60f8, + 0xfa85db3d, 0x673d9029, 0x59f9353c, 0x4645e826, 0xe3e20e30, 0x13962d65, + 0x5af93a3d, 0x5f58c5b1, 0x25d63619, 0x24c8a5dc, 0xd8ca8650, 0xf79806d8, + 0x0623e804, 0xd07df27a, 0x647e5847, 0xdda2b761, 0x15f400f8, 0xb572f4d3, + 0x4272e89e, 0xb13ff8e5, 0xf8f241c5, 0x1ad5a6f9, 0x1c7847cb, 0x7cdd6480, + 0x1156f621, 0x58be73ac, 0x04b9e127, 0xcf5f15f5, 0x6bdaaefc, 0xdc02c4c0, + 0x4ef78669, 0xd416225b, 0xf0b0b75b, 0xfe3059bd, 0xb6ee0f6d, 0xf8ff4904, + 0xae489a47, 0xc81348d9, 0x968582f5, 0xef747bf7, 0x64d8ec2d, 0x8de50919, + 0x9bf3e341, 0xd3f58cab, 0x84c5b096, 0xc2a57976, 0x5bfc615a, 0x72ed8c1a, + 0x54b13f9e, 0xdf31674e, 0xf0c5a07c, 0x06575c54, 0xe1e82fd1, 0x3ebb00eb, + 0x87da246b, 0x53df14db, 0xfb05bf50, 0x1e3a444d, 0xe2f9f0d6, 0x07be2965, + 0x997860d8, 0xdf40930a, 0x78dd8577, 0x743cb557, 0xfe183291, 0x7e1c979e, + 0xebc184d3, 0x56fb8588, 0xdc3a21e6, 0x7cf8ceba, 0x7d762849, 0x3bea0f9c, + 0xd03ed34b, 0xbf6daf3d, 0x1d03ed32, 0x9cef54bf, 0x0cafa86d, 0xbfe868df, + 0x4312cb62, 0x9596b2fb, 0x9adbf686, 0x4bea1b57, 0xfa1a7742, 0xbd6ebadf, + 0x8696fda1, 0x37ed0dfb, 0xd4326d57, 0x6e3e0c6f, 0x6160bfe8, 0x795da1ab, + 0xfa0e6569, 0x305af537, 0xfde03867, 0xacacefd4, 0xb1f2894d, 0x1b8ff3e4, + 0xd93ca8b3, 0x3d72a5e8, 0xbfc82bca, 0xeb2f1f69, 0xa0e496db, 0xffbe4b9c, + 0x8d90d2c8, 0xdfcb1272, 0xcb18f2b1, 0x6837c8c7, 0xf3d91287, 0x5005851a, + 0x6e14fbee, 0x77f3e48f, 0xec65fe84, 0x1ab7921e, 0xcd63cb8d, 0x50cbc3f3, + 0x48b46a5e, 0xf1338361, 0xa15dacb8, 0x46d63075, 0x830cace3, 0x9ae81854, + 0x77b3806f, 0xafe699bf, 0x22e3e743, 0x2581f7b4, 0x791fce0a, 0xf186fb39, + 0x297f8f08, 0x48333bd5, 0x5636f62f, 0x22a07da4, 0x7e5402fe, 0xca90b8dc, + 0x2a418d13, 0xa2ac683f, 0x06c6fdf2, 0xd71a7b2a, 0x636ef951, 0x8d63ca88, + 0xbefe54cd, 0xb7ca85b1, 0xf950b71b, 0x9530c6db, 0x54fd1ba7, 0xb5a9f00e, + 0x43fd10bf, 0x432b07f6, 0x0ebd9717, 0xcdc816fe, 0x7737e919, 0xe11afaf2, + 0x4bc22737, 0xe213dd2c, 0x434c858f, 0x89292dd1, 0xc4c923d3, 0xf9c8182a, + 0xfaf6e303, 0x8abaf296, 0xe008032a, 0x0397fbd3, 0x860d22e3, 0xde3d357d, + 0xf683bb41, 0xd93365ef, 0x99f9163f, 0x1e9706ef, 0xd423401f, 0x8474bf37, + 0x35fd029f, 0x7e72f14a, 0x9cbc0af9, 0x8dddbc39, 0x964d747a, 0xa4c1f3c9, + 0x6dabebc4, 0x7538f5cf, 0x1a77d4f0, 0x945a67eb, 0x7a0fee0a, 0x478ee793, + 0x3e78f07e, 0x65ba4028, 0x59c72951, 0x3e79a593, 0x617ec348, 0x95db0f5a, + 0xf105fc42, 0xb6fbf508, 0x4e3448e1, 0x760e8e14, 0x1f27de1c, 0xff713f3b, + 0xfea17c84, 0x9a3f4349, 0x473e5975, 0xff856abb, 0x1401897f, 0xc72ea953, + 0x87376fad, 0xf3e217ac, 0xe0f9865d, 0xf58caf3d, 0x8a1bccbe, 0x427654ff, + 0xa4a807f2, 0xacde22a3, 0x18f769de, 0xa18a75f5, 0xdc39df5e, 0xf8dfd063, + 0x3657900f, 0x5ed15153, 0xe8b608d5, 0x0acd9d53, 0xf90bb7c0, 0xaf52e806, + 0xb6b57ef0, 0x8f082d1e, 0xcd3474ce, 0x3d8bc4bf, 0xb1bd685b, 0x3c6c9df0, + 0xc4d555ec, 0xcf9b57f0, 0xe38811dc, 0xf0ae7f97, 0xc4c6a538, 0x0b665ffd, + 0x584e51b9, 0x873dc856, 0x07399bf8, 0x0b7143f0, 0xcbaba3cc, 0xe9afc071, + 0x7acf678f, 0x8dafdc4d, 0x526ad79d, 0x757f09ce, 0xc2ce8ebb, 0xb1e2c775, + 0xb43ff3ae, 0xcc8dc520, 0xdf894780, 0x6ac04a5d, 0xed57f182, 0xf9434f7c, + 0x2a12d8fa, 0xc4dce7fc, 0xbf0c19f8, 0x2384eb33, 0x7b35ceba, 0xad5fe45c, + 0xede224d9, 0x79c6eb10, 0x13134e97, 0x74bd017f, 0x62e58070, 0x26dfa826, + 0x5dee326a, 0xfe4d51da, 0xa42c87d5, 0x89f53fa1, 0xfd04a5b9, 0xaded5583, + 0x3ce01f9a, 0x88154cc5, 0x4dec53af, 0xbd1d24f7, 0xd11a4c8a, 0xa366b6e9, + 0xa6fe00df, 0xa6fe0ea1, 0xcd9cbea1, 0x7638c4c9, 0xb80b66f9, 0x434eb4be, + 0x879328fb, 0x3582b0e8, 0x7afb446c, 0xfcd263bc, 0x3f0e904b, 0xf104b27f, + 0x479a14bb, 0x8f1e22a6, 0xd6ff1e12, 0xfbe257f9, 0x1bcf0713, 0x7c98dbe5, + 0xed43c080, 0x8e1fc54e, 0x991737c3, 0xfe4abf38, 0x4ff080da, 0x2dcdfa89, + 0x4d6bf531, 0x6b724a8a, 0xe3a46666, 0x642d8f29, 0x5f76a64a, 0x7a12f004, + 0x026beade, 0x12a3fafe, 0xbb226d98, 0x74c0991e, 0x04a8fefd, 0xf2af79e9, + 0x013472fa, 0xc04c8d4c, 0x06d80b3c, 0xd04d3be2, 0x60f08ad7, 0x1aa59cbc, + 0x728f59d6, 0x9dd8e30d, 0xb7df0c1d, 0xf1da637b, 0xc637681f, 0x8e1bb232, + 0x2776c6b1, 0x87f219b0, 0xbe7c67cb, 0x180fc842, 0x4c3be222, 0xebdfa17b, + 0x662339b6, 0x34d94bf0, 0xce2077b5, 0xc878c3c8, 0xfe91813d, 0x645e52f3, + 0xaff787ad, 0xb5847913, 0x4b0d94ef, 0xa97fc21d, 0x84b61b3f, 0xb57574d3, + 0xa97e435f, 0x12c3bb3f, 0xf40df49e, 0x989617a0, 0x279b9519, 0xca236094, + 0xd49bc4ad, 0x3c3d517f, 0xcb97a3ca, 0xfef431ad, 0x03a470da, 0xec70753d, + 0x482d8252, 0xbe3858f7, 0x8359f8f6, 0xadfadfc6, 0x68305f8e, 0xf0f19dfc, + 0x631c7a78, 0x0337a4dd, 0xfee80cc9, 0xa8f3dd9f, 0x8ff7444c, 0x85233e41, + 0x58f84fe8, 0x4b79e344, 0xb8f8cbac, 0x59e5ebaa, 0x81575718, 0xfe05eb7f, + 0x485ac95d, 0x294c448f, 0xb335cfc2, 0x55de0e88, 0xfea6bf5d, 0xff783aab, + 0xfd4ed66a, 0x3119bf31, 0xe1927bac, 0x7def293d, 0x9cd49ec2, 0x1d11612d, + 0x790b763f, 0xe087bf00, 0x106bcf93, 0xb26bcc3e, 0xb6a79a6e, 0xcf30cd3d, + 0xf6735f80, 0xf9d11662, 0x376ab53d, 0xd9ed77f1, 0x019e68cb, 0x6afe067b, + 0xfc6a1b44, 0xa3b80691, 0xc0334fe3, 0x3a7f1d1b, 0xcfc72bcd, 0xca72039a, + 0x2be513f5, 0xc293cb42, 0xb7a7804d, 0x91f7c1ac, 0x9b5cb25f, 0x76415f73, + 0x04f1fa5a, 0x744fc7d4, 0x1d34df6c, 0xea09fae8, 0x9b975c39, 0x739eb9b9, + 0x92174c86, 0x7c853afe, 0x18bfa030, 0x43f1afe8, 0xb7e8c7b4, 0x8c0af851, + 0x28f59a3f, 0x3746dfa8, 0x8e50f518, 0xef84dd33, 0x3e33ace5, 0x019ea2f7, + 0x521b95bd, 0x9f5ce263, 0x6fcfc709, 0x9f4f3e36, 0xc73aba51, 0xd3516e07, + 0x2798a533, 0xba505f4a, 0xb187a47b, 0x7957d40b, 0xe2d299fd, 0x79ff50e1, + 0x1532bad3, 0x7ff4d5fc, 0x86ce2d2b, 0x91b2d3ba, 0xca15abd7, 0xb7cc592b, + 0x89be8594, 0xcac0081e, 0x6294728d, 0x0a9cfc06, 0xccbf9b1c, 0x5fb47a8b, + 0x9e8478e3, 0xd3d19f80, 0x39467e38, 0xfc46ed8f, 0xd67a98e4, 0xc3f973a3, + 0x052bff17, 0xe62f4643, 0x1e0f013d, 0xf483c1b6, 0xbed34781, 0x8ebfc21c, + 0x5f2533f5, 0xf305b14c, 0x4b938e10, 0x167f7ec7, 0xeaa27d3c, 0x5b0dc500, + 0x71f9fe44, 0xf46eb710, 0x326f55bb, 0x3364e3f2, 0x0965d7cf, 0x378ceebf, + 0xfd487937, 0xa195959e, 0x53eae0ea, 0x9fc8ddfb, 0x5f1c5f7d, 0xd6237e8c, + 0x13d08653, 0x32a359f5, 0xa3139254, 0x749e667e, 0xc14aa3e2, 0x5b378847, + 0xb6cf3466, 0x7e510942, 0xc0b5fa44, 0xbf5c1e01, 0x7f31aa12, 0x8edfc179, + 0xe0d6e3a7, 0x775866d5, 0x83c85985, 0xbdb0b98b, 0xf08f2ab7, 0xf6836e96, + 0x6b3d688c, 0xe809cee9, 0x0398a4e7, 0xc37be2d7, 0xc6cd9f97, 0x43d98e7a, + 0xb4a2dbf8, 0x00f8470c, 0xc3cfb48f, 0x569d82f6, 0xdcc93168, 0xcf26f64f, + 0x69ce2219, 0x1f4acc6b, 0x55cf2fca, 0xde718b83, 0xf7bebdfc, 0xf1fc619b, + 0xf70f9a95, 0x9bafc65b, 0xccf88e99, 0xc03d7132, 0x72f390ee, 0xf82f5f3d, + 0xf8aacfae, 0x77ded0fd, 0x8435a7bb, 0xda0b33ed, 0xb519afd1, 0xfdc3ebce, + 0x42873e80, 0x7a35f7ef, 0xe7282f29, 0x1c95dd1d, 0x9e49bbb1, 0xf3c8373f, + 0xd07d633a, 0x3b7a5f7c, 0x7fbc707b, 0x9c42f8f6, 0x1d0f949e, 0x67d9e82d, + 0x725dfbe6, 0xb42cd1be, 0x7391fd1f, 0xcc5fef9d, 0x7fda74ae, 0xba037410, + 0x925e9084, 0xfbdf402e, 0x121b5f10, 0x78bef7d3, 0x6b6e5df4, 0x5db946c8, + 0x659f6815, 0xe625e781, 0xafd883e0, 0x21f76166, 0x50decd0b, 0xe927fc88, + 0x70d0d4ce, 0x740353d4, 0xfc21497f, 0x7c717667, 0xb7361fd6, 0xcb1e7ee2, + 0x40b7ae0a, 0x42ca99fb, 0xa22627ca, 0xfe75f8f3, 0x017cbd74, 0xfce2b7dd, + 0x9a8ebbe3, 0xef493e10, 0x49de44c7, 0xffecadca, 0xbdfa598c, 0x0f76be62, + 0xfc55f7cd, 0x166eb457, 0x7c780b8d, 0x80dfcf56, 0xff9c76c7, 0x1fe166c7, + 0x3b63c60f, 0x3c073ff6, 0x3c1739ee, 0x939de87e, 0xcfe30799, 0x7f093b32, + 0x87329f2b, 0xbea4b0ad, 0xf52fd2d9, 0x333c335f, 0x5e5627aa, 0xd71fb0d4, + 0x8549f2b9, 0x6bb2acf8, 0xc26c35c5, 0xf96378e0, 0xe3e910c2, 0xd903b8d8, + 0x5ab2f912, 0x7f13178e, 0xff07b354, 0x734e4cc3, 0xf54ef498, 0xbffb634e, + 0x9b30f945, 0x24ce04f2, 0xf1b1b79e, 0xf1d0b2f1, 0xe248be47, 0x8b26717c, + 0x619e1c91, 0xd0f7c429, 0xbb608bee, 0x33fca2e6, 0xdc6291db, 0x314cac9f, + 0x6e8e4fec, 0x4ff21930, 0xc9b1f3b1, 0x5fec4cca, 0x6730e42a, 0x6fb0c99d, + 0xee321b97, 0xa737e5eb, 0x5a63ea1a, 0x9ffa1846, 0xd0cf25b7, 0xbe7c2e3e, + 0x9d82fda1, 0xf1f50d13, 0xfa1b17ed, 0x6659d85f, 0xae4717a8, 0x749ff432, + 0x3ea18e78, 0x4326fba5, 0x2f6fa9ff, 0xd45fb435, 0x7ed0cab3, 0x0c6bc7c9, + 0xeffb4bf5, 0x2c8ff432, 0x00ac38a9, 0xff025efd, 0xe086f314, 0x67c8a857, + 0x99acfe07, 0xfc0e4f90, 0xa8c4d0b9, 0x2bc867dd, 0xa673f81e, 0xf81f9f1f, + 0xfb1f8973, 0xe7cb3295, 0x5952e2f1, 0xdb19b0ce, 0x0be05553, 0xc0d96fb4, + 0x569a9817, 0x7203f28d, 0x39454235, 0x0fc3a7fb, 0x469d0215, 0x46482cac, + 0x34f20d3b, 0xbd373d42, 0x27ef8394, 0x962da792, 0x290f1b96, 0xac7ded83, + 0x38e590be, 0x5bade655, 0xbad37de8, 0x65a7616c, 0xb230f17d, 0x5f9f9233, + 0x7a1c5333, 0xe3d70366, 0x86a43667, 0xdf9efef9, 0x0fe75c39, 0x24e8399e, + 0x9efdcefe, 0xaf01db93, 0x892cebd3, 0x7f2901da, 0x323f22f9, 0x7945582a, + 0xe3fe418f, 0xb8f59ea2, 0x1ff573ce, 0x99c6fd63, 0xff021e92, 0x05d1d709, + 0xf1f68972, 0x27da1483, 0x7161e35a, 0x36b6eff7, 0x16770f36, 0x4b2e7e0c, + 0xdce1cd65, 0xb40f30fb, 0xe159f14f, 0x1fd86dfd, 0xbc587bec, 0xb5ea26d7, + 0xbd454d21, 0xebe22b56, 0x521e71d8, 0x7e466f4b, 0xdd96a1d8, 0xc5d14eac, + 0xdc5a0dd3, 0xd077c7bc, 0x0473c089, 0x0d80efaa, 0xcf5fefe6, 0xff306d7c, + 0x0ca78b1a, 0xf4ee6beb, 0x9af21d12, 0x7ae1667b, 0x5dc13a73, 0x73fbd9d7, + 0xc056a780, 0xd4f08b53, 0xa714fda9, 0xb0a8bff5, 0x879c5cb6, 0x5f66bb8f, + 0x487e432e, 0xd51ce704, 0x72057c42, 0x738e3770, 0x4ed09aa7, 0xf28e7ddf, + 0x638d5eb0, 0xf2ec065f, 0xf15bed52, 0x137072c7, 0x9eb44a78, 0xe196d0ff, + 0x9d39b728, 0xc0a89fa5, 0x60e039b7, 0x9f22a726, 0xd1bef632, 0xebef623f, + 0xf344d0fc, 0x7689557e, 0xf1157def, 0x0631f7ce, 0xc7231dc1, 0xe46f75de, + 0xebe9a417, 0x4c17e7af, 0x10950012, 0x306c14bc, 0xe5e2db88, 0x95f6738b, + 0x2427561e, 0xbdefe786, 0x377881ce, 0x4bfd5e46, 0x7c8f5ec7, 0xb311fb77, + 0xb2845562, 0xc84178c1, 0xe677b2eb, 0xf0e8a664, 0xe5b1b5b3, 0xaf27556a, + 0xf7f012a3, 0x9ff72a9b, 0x5c3635b6, 0xe380595d, 0x3d7a4c7a, 0xca13dd90, + 0xd27988dd, 0x8c2f870e, 0x9327acfa, 0x702b58f0, 0xbe0a6c90, 0xf4bcfc89, + 0xd7ca6ec2, 0xe97c88e6, 0x297e7168, 0x2ae3be76, 0x97f847cf, 0x8c2958da, + 0x16cda7fb, 0x34b277f2, 0x08e28798, 0x5a5b9d07, 0x0a6c0636, 0x93db2fb4, + 0x0c53f5c6, 0xd0c6e15c, 0xa20a1bd5, 0xc71c02f3, 0x3dbc1e51, 0x7f3859c1, + 0x4451c22e, 0xe11276f2, 0xe84d48fb, 0x473c9dcf, 0xd21beb79, 0x43c6c4fe, + 0xf0e2fd09, 0xa7e485fd, 0x7e4dffe6, 0xa1c3fa31, 0x0c3fa8a2, 0xd058b2eb, + 0xeb8c594e, 0x8b55d9d2, 0x95d6dce5, 0xaeda1964, 0x92416e3e, 0x32407389, + 0x9ae1230f, 0x57f2e169, 0xe618d1ef, 0x4e51ead3, 0x54d9f0e3, 0xbb88628b, + 0x3138adbf, 0xede6553f, 0x7887bda4, 0xe5c2e311, 0x33a3e24e, 0x0bfbd6de, + 0x877c7327, 0xc8f7c086, 0x04322375, 0x0f887d5e, 0x16f1c789, 0xbc069ea3, + 0xb5e2e2fa, 0x326af006, 0x57ca75e0, 0x95fc95e0, 0xa98f9daf, 0x9cefee34, + 0xa5dff816, 0xde703304, 0x5bbc3753, 0xbab0f982, 0x086b9f79, 0x679ed7d7, + 0xe7e9b32e, 0x981ef991, 0x9cf383c7, 0x9aafe1be, 0xe825a7d0, 0x39ed3667, + 0x35cf192f, 0x93f38ad4, 0xfd5af6a7, 0x3e5f8e8a, 0x1e70f2fd, 0x1b4fa5ea, + 0xf2c7ccaf, 0x5bcf2a54, 0xf53bda9e, 0xa9d5f210, 0xb12d1c9f, 0x9ea738c0, + 0xd2a25a3f, 0x60d85b3e, 0xef2f6a7f, 0x203b412e, 0x7c03daf3, 0xdfaf8b67, + 0xfcfe0b56, 0x4aafebda, 0xc8d5e788, 0xef1ca707, 0xebfae096, 0x0f09675c, + 0x7cb9db0f, 0x6da1923c, 0xd32332c4, 0x17fa10f4, 0x4fc1a45a, 0x5b8788db, + 0x75265822, 0x7971fbb7, 0x23bbb7ce, 0xfa7bba58, 0xbd7618fd, 0xe201fe05, + 0x67b1f3d5, 0xbe1fd63f, 0x33e504f2, 0x1ab017d9, 0x80916380, 0x3b59f7e3, + 0x3a04a91e, 0xf37d2efc, 0x7e86e423, 0xf685eb01, 0xa0dff19b, 0x1e818e87, + 0xdc6c80f2, 0x7cfb72a4, 0xb512a553, 0x191ff853, 0xe9187947, 0x8a3545d3, + 0xeea5aec1, 0xd3f94199, 0x6429af3e, 0x61a47581, 0xbff81a56, 0x66ceeb4f, + 0xc5cec0df, 0x3883bf96, 0x9d9d7de5, 0x0952acfa, 0x67df30a9, 0x7fac8f42, + 0xd3f1127d, 0x178a65e6, 0xfefb18f1, 0xcb5eeb63, 0x727a099f, 0xf3879dd8, + 0x6efc8267, 0x90027916, 0xa7cf0537, 0x80f22c3d, 0x877b866b, 0x9ae3ede9, + 0x8252f323, 0x46defaba, 0x89d6dfbe, 0x7ca15ee7, 0xed7b9c41, 0xfaa2cc6a, + 0x2a5e8d4b, 0xe9638d23, 0x434b66f9, 0x7bdf9e0a, 0x3342c2cd, 0x77bf97c1, + 0xe51bff78, 0x1ddb42e0, 0x699b2fbf, 0x33d6f187, 0xd6f8cf3a, 0x13ddefbd, + 0x1df00e9a, 0x1929a4f8, 0xd2a740ed, 0xa61c478e, 0x23fdbe2a, 0xcb5d4f51, + 0x75a54f48, 0x306e742a, 0x3611cbad, 0xb7d3fce9, 0x765edc2c, 0x72de785b, + 0xb442da2a, 0x7fa5b32f, 0xef413fd7, 0x0fea0cc7, 0x7b9e1f81, 0xa98f9d8e, + 0x4ecf94fd, 0x7c30def4, 0xbfb9fc6f, 0xad4c77d7, 0x2a89f3a0, 0x66a77fb7, + 0x903eb667, 0xcfebfbcb, 0x79e1f497, 0xfa7238ce, 0xbdef3117, 0xc7f74e16, + 0x64768d72, 0x8fdb9597, 0x1df316ff, 0xa392dc68, 0x9651bf3f, 0xffe8dfc0, + 0x335ff2a6, 0xe488ff68, 0x68f596be, 0x3f72bcfc, 0x11fc49e5, 0x3619af8e, + 0x577d470e, 0xca04b2b1, 0x97ae4e19, 0xe50eb0d2, 0xeb9c550c, 0x689cfc66, + 0x2b56455a, 0xe28e5f9e, 0x5a73af81, 0x1c16bf4f, 0x7dc3dfcf, 0x7c0fb4df, + 0x29ebf20a, 0x7fee39a4, 0xfd11b6cc, 0xaa825b67, 0xbc52f486, 0x9d22578f, + 0x3a238cf6, 0xec958fd9, 0x5c3a464f, 0xde4cf2cb, 0x2dec1f28, 0x9c627a05, + 0xb6f14fb4, 0xa73ee8b1, 0xe340bf9c, 0x23e595f8, 0xc877e04a, 0xea5a05e7, + 0x784fdc0c, 0x82581ec4, 0x7e113247, 0x678c165b, 0x478cde0f, 0x5debedd2, + 0xf4e0154d, 0x3b40b5ed, 0xba360bd4, 0xfe00369b, 0x4704a6f6, 0x6b9796e2, + 0x30e9a3bd, 0xb970a7b6, 0x68e8d828, 0xd1c8b942, 0xe61f3c3c, 0x5f22e7f4, + 0x503dd40d, 0xdbabaf1f, 0xaf2aea62, 0xbed575cb, 0xc843e7fc, 0x5c5d75a7, + 0xd6f006be, 0xfea0ac59, 0x7e135f3c, 0xf4398392, 0x547fddfb, 0xbe341382, + 0xedc85d8f, 0x4a07dc98, 0x81f62ed0, 0x828b58b2, 0x1e04767a, 0xff47cb60, + 0x6cca9bba, 0xdca54fd6, 0x59dbc8df, 0xea04607c, 0x76605353, 0x35e7d239, + 0x18f7970b, 0x72b1efbc, 0x2d6bdd3e, 0xf985659d, 0x63d01e1e, 0x46ba5f7c, + 0x81b669e8, 0xc15eedeb, 0x9b369fbb, 0xc9c01a42, 0x79e83876, 0x553f388d, + 0x4c81cef3, 0xd4f8d7dc, 0xc9e22acf, 0x7b085cc5, 0x5b5f8f11, 0xb946822e, + 0xef907fa8, 0xcc7c819b, 0x21d57c45, 0xd937505c, 0x847ce9ba, 0x87f69ee5, + 0xff3718cc, 0x73c1e2d8, 0xbeb9d58e, 0xa2fe78fd, 0x0fae5f7a, 0xc3bde555, + 0x9d577c79, 0xd1399ed2, 0xbacbe519, 0x21d94dce, 0xfb27f7c0, 0x95f2477f, + 0x61ec878f, 0xa38edafc, 0xd79e105a, 0xa1a7bc75, 0x4524fd61, 0xda3e81fa, + 0xb877bdb7, 0x9c12f92f, 0x3c6657ef, 0xa7803859, 0x14ee96d1, 0xc3c979fd, + 0xa0fde7a0, 0x3d035fcf, 0xd021e58f, 0xf3d07eff, 0xd7f8be47, 0xaf3fd44c, + 0xccd7c25a, 0xcd9e71c1, 0xe15e60f7, 0xc1f84f53, 0xb4ff5089, 0x3d6f8c60, + 0x6b3e57d4, 0x7fbc600e, 0x96716d44, 0x6083ff40, 0x9dfde847, 0xc2f4eaff, + 0xdb0583f3, 0xf471bd33, 0xd36795dd, 0x60981f99, 0x7cef997b, 0x36078f94, + 0x976c9bfa, 0xbeb9f802, 0xea18ac55, 0x0d93795a, 0xa99365e4, 0x1f62d1fd, + 0xc73867d5, 0xce597f81, 0xf2b187e5, 0x278e52a6, 0x71b4dfaa, 0xdfdc0cd3, + 0x8a7bbb5b, 0xc89a7c82, 0x7d9d56de, 0xc825ce8e, 0x6b263e7a, 0xd4aaef80, + 0xaa59e510, 0xce84fece, 0x271acc33, 0x61fe68f3, 0x1f2dc68c, 0x8edd7886, + 0x13177c7b, 0xbdf843c9, 0x68b2f6c2, 0xabc1f51d, 0xd0be02a9, 0x41334d8d, + 0x0cb11fbe, 0xdcf1fbb4, 0xe12b9aa0, 0x523c2167, 0xfb26aafc, 0x099a6e2f, + 0xcd76ea41, 0x36867e38, 0x02afdfd0, 0x249abe1f, 0xfc682beb, 0x6293fd41, + 0xf1c997fa, 0xf3c2e3eb, 0xb75a3d88, 0x2ff57f41, 0x59fbe8d6, 0x3b68ff88, + 0xc727978d, 0x56f0475f, 0xf6f3370f, 0xbf65e850, 0x4dcfa51a, 0xeb4dfdda, + 0xdaaf6f01, 0x97a8a57d, 0xa465affa, 0x7cff916f, 0x49b87e3a, 0xb3aad9e8, + 0x39fd3157, 0x58b49b92, 0x90c75cba, 0xde3ee76e, 0xa2f186f9, 0x7a604ce3, + 0x7e047ffa, 0x6fb7584d, 0xedd762bf, 0x03ce90b3, 0xc510b3f3, 0xf35b55f3, + 0x07a75859, 0x5f1c3ffe, 0x027f0e17, 0x5ffe6638, 0x61ac6386, 0x451c28be, + 0xfefef806, 0x80259470, 0x02b7d663, 0x959dac47, 0x67617ee5, 0x0d5452fb, + 0xbdb63bf7, 0x8ffda564, 0x96c85374, 0xceba7687, 0x5b7a7644, 0xbf1f8b6a, + 0xc6b6d8bf, 0x1ee1e74b, 0x722a04b1, 0xdd0a7fc1, 0xabfda269, 0x6ebe796d, + 0xf6dadfdc, 0x26be792f, 0x8b3d349c, 0x071662ec, 0x3c5b6d81, 0x087e2aff, + 0xa3efef8d, 0x3e3b44e9, 0xf646c532, 0xe59cdb72, 0x9f4fff94, 0xda1c7673, + 0x0a7e9d49, 0x66531d91, 0xf3353f93, 0x3c26d6be, 0x149191ef, 0x2ffd1c78, + 0x74dad425, 0x76bc7878, 0x58667fae, 0xbe6066db, 0xcf595b68, 0x73938c38, + 0x803e702e, 0xfcf5abaa, 0xff311311, 0xbc1adc73, 0xbb780ad6, 0x1bf22aca, + 0xf2852c29, 0xc9051562, 0x6dd2c2a8, 0x5a253ed0, 0xa7caf87f, 0x3191cf29, + 0xefc860af, 0xaf814b18, 0xa67a3abc, 0xf641ffa9, 0x461afeb9, 0x8bf47179, + 0x172feff5, 0x027d7d7e, 0xb4e81dff, 0xad1ce11c, 0xd4c21cf4, 0xd1e75d61, + 0xd45f18d9, 0x139955ae, 0xe46d496c, 0x8bffdc77, 0xfd6207f1, 0x22de595a, + 0x7c44acfc, 0xf3958cf1, 0x25ff80e5, 0xe40fadfc, 0xb3f0a37e, 0x1ea2ed2a, + 0x9e506e73, 0xfe13ec17, 0xfc62df4f, 0x37d61268, 0xd769978c, 0xee7ce904, + 0xe5deb172, 0xd1334a5b, 0x7fdca9bf, 0xd963ad23, 0xf7e4d9e6, 0x84bcdf2f, + 0x784a7bce, 0x9bfc632a, 0x51265acf, 0x1d112bbe, 0xfd221fa4, 0x273f5899, + 0xde157bd1, 0x41cfa256, 0x58edafcf, 0xe67cc36e, 0xf67fa8c4, 0x7367c42a, + 0xf1a6dca0, 0xb31e09ef, 0x1b6d38f3, 0xb6005f7e, 0x399650ff, 0xb957d715, + 0xdf092329, 0x716b623f, 0xf91e5ca2, 0x61d7d7e2, 0xf093f43f, 0x9529ccbc, + 0x9eb2a5fb, 0xb72b9e08, 0x55e93f70, 0xe1accf31, 0xeff3661f, 0x1879c4ab, + 0xe97ca696, 0xec7efc48, 0xa69d9879, 0xaf903bb2, 0x9d7810ef, 0x873e0b62, + 0x155793f5, 0x5ea79f12, 0xc7cdd079, 0x79d79e37, 0xd3a5c44c, 0xee4dc3fb, + 0xbfdf3a74, 0x71e5e1db, 0x23ac1946, 0x653e4fed, 0x7f1e8ea9, 0xaf8978b1, + 0xc528fe31, 0x47d7a438, 0x702ce0f1, 0x0579f82f, 0x7e48df23, 0xa6f3eafb, + 0x2dff066d, 0x69f4de7a, 0x8b4edbf2, 0xacf5e5b8, 0x724be6c8, 0x51ef6c31, + 0xdebd4e31, 0xbf416e99, 0x16bcc030, 0xf5ae4b8c, 0x16eb9cc5, 0x11aedae7, + 0x7dc209fa, 0xfa0daefa, 0xaf15f619, 0xcfac669f, 0x37eb1bf6, 0x7effc454, + 0xee374d8b, 0xdf169fdb, 0xf0299e75, 0xb10ca726, 0x002d82de, 0x3bbd6eb4, + 0xae127f54, 0x9bcb4777, 0x26fe7d6e, 0xb0584f36, 0x4f212345, 0x900eee34, + 0xbca43c0f, 0x9d688580, 0x99dda94f, 0xc0a0b8fa, 0xb579ce22, 0x12f33aff, + 0x36c391a0, 0x9fea266c, 0xe7eb955e, 0x4afefbbe, 0x4b18ebf1, 0xcefc0de4, + 0x168bcc78, 0x2853ee2f, 0xff285a2f, 0x4edb3f51, 0xa5bf03df, 0xf7a1935c, + 0x3900c7c7, 0x5d33ae10, 0x5f3c8663, 0x9bacf73a, 0xb79ec5fa, 0xe7cdfbff, + 0xcec73c24, 0xe23e5ec7, 0x16007bc6, 0xf9d1366c, 0x5c8b85ab, 0xa4889df4, + 0x6338ec6f, 0xe171a8b6, 0x84ff844e, 0xb8f4b774, 0x74e6ff71, 0x4af299bb, + 0x6de3edb1, 0x5f8b37ca, 0xbaf31a17, 0x43fd9ea7, 0x57d60461, 0x375cf4ab, + 0xd8e2972e, 0x638c36f1, 0x5f719d37, 0x3fbe7a49, 0xaefba033, 0x86fdb7a9, + 0xe3cf20a4, 0x4903be18, 0x2f128fc4, 0xea70f089, 0x7e16edf0, 0xd164327e, + 0x28c6d7e7, 0xef9439fe, 0xa7b2a4db, 0xd1a77ce2, 0x7be71364, 0xc44c9ed5, + 0xfda5dd57, 0x2f2ab714, 0x41eee87e, 0x7ef160bd, 0x23e0e29f, 0xe97b0710, + 0x3c775efb, 0xfc1bfdfb, 0xc4ec10ee, 0x8fb71b02, 0x12f3edb1, 0x17f8a39c, + 0xecdf8741, 0x9bd1e4ff, 0xd013e087, 0x6f30733c, 0xd551ef35, 0x3aaef983, + 0xdbc90f4b, 0x3718affc, 0x76fc7f11, 0xa0f29dbf, 0xe9da160b, 0xf9d888fe, + 0x8f3dab4e, 0x9df30cde, 0xff707806, 0x00a8f4ff, 0x66f4f1e1, 0xf6fb83d5, + 0x983ae7f3, 0x54ffd74d, 0x08f9f1c7, 0x0cce99df, 0xba701f3a, 0x49df3e2b, + 0xfb655d3c, 0x45c57986, 0xf209fcc6, 0x8eadca1f, 0x3c57feff, 0xc70abbfe, + 0xd7e1c29e, 0xd53a8b9f, 0x8f1c9f91, 0x7c1f72ae, 0x1cf18b4c, 0x2ee80955, + 0x775eb71e, 0xb180acb0, 0x0c8eb261, 0xa075f30e, 0x7071e39e, 0xfb24f104, + 0xdd7cd43f, 0x8577dc4c, 0x03f11fba, 0x9d5bf9ef, 0x7762bfd4, 0xe8cfc211, + 0x059ab9bb, 0x3b01e64e, 0x74a399f4, 0x54f00db3, 0x43407dd2, 0x6475857f, + 0xc46bfad0, 0x6ef0b1fb, 0x68fd8bb3, 0xe4ca87bb, 0xc23ffdb7, 0xba3a4a7b, + 0x49f8bc93, 0xfc6a4756, 0x5d9a0073, 0x60039c31, 0xf1e50f6a, 0x3cf06632, + 0x473eff6b, 0x87894db8, 0x3bfcf59f, 0x2abb18af, 0x8d46b7e5, 0x11ad7d90, + 0xe6abf5f6, 0x5bdf10ef, 0x9ac492be, 0x355df46d, 0xbfe013e0, 0xb41717fe, + 0x7af9403d, 0x1cac9dfe, 0xf31164a7, 0x47fae9b7, 0xe33cf26c, 0x833d7cc3, + 0xbd70e7de, 0xfb033a02, 0x4cf6a667, 0x01bff250, 0x7e316e1f, 0xeb6b5267, + 0xf43d4429, 0x15fc1284, 0xedfeadd2, 0x77ac4c9e, 0xfc9279bc, 0x67c573ae, + 0x7f3205ee, 0xeed0d114, 0x3a5dddac, 0xb57f286c, 0x9d40e306, 0x7de28c7e, + 0xf187c516, 0x5abcc3c6, 0x2c11d9cd, 0xdd143694, 0x126859b2, 0x9fdf33c7, + 0xdf8099e8, 0x6e3ac1ef, 0x2ff5039d, 0x3fccf462, 0x69e9fc2a, 0x574cffdc, + 0x730d41d9, 0xdd376a6c, 0x214bf0bf, 0xf214bf2f, 0x33dff1d2, 0x74fa46ae, + 0xdcf269bc, 0x97e3ab93, 0xc1b21624, 0x7b5bd77b, 0x8efe827e, 0xebf6cbac, + 0x869d2fc1, 0x72e36afc, 0x66b5e523, 0x7d397c51, 0xfe26e6d2, 0xc476f61c, + 0xc7ce798d, 0xff23e951, 0x7f271fb7, 0xccd3a3a1, 0x61cd93f0, 0xa0e6828b, + 0xc1ff8a33, 0x2a3d70e3, 0x96a21de5, 0xde425c0b, 0xe57bdf91, 0x951e59f7, + 0xc2b5c7fc, 0x3c65ec7f, 0xfb11a87e, 0xf02a7fac, 0x1afe39d3, 0x5c600b3b, + 0x3f8f27f7, 0x78fc8539, 0xdf2d9fa3, 0xbdf67e93, 0xa55e39eb, 0x38a362de, + 0xf266647f, 0xaf296bfd, 0xf687ab2c, 0x207f24b1, 0x03d3c4ff, 0xd47a0a97, + 0xe819359c, 0x46a7a51a, 0xdfcf94f4, 0xd2127b07, 0xfa5cc39d, 0x377d0171, + 0x51f31b73, 0x66b6e33e, 0xe4e90b07, 0x3e51e3b6, 0xc63dc76f, 0x798967f9, + 0x3e38925b, 0xf877c43b, 0x91dfaa1d, 0x37d5145a, 0xae075f80, 0xabcbfd4f, + 0x79498f14, 0x95dce390, 0x7ee1f7c4, 0xadf357f1, 0x2bb67db2, 0x76a5deba, + 0x2f24b7d3, 0x27de437e, 0x24999f8a, 0xc5e58947, 0x92f215f3, 0x4d05f84e, + 0xf97b46ea, 0x9f1ff09c, 0x68aa6c3b, 0xdb7fc38b, 0xe73d7c6d, 0xec01a867, + 0xdb844177, 0x32fd44b3, 0x15f9c553, 0x3c589781, 0x3fc7e7a4, 0xd056b2ff, + 0x7f8ca6a5, 0x22f78ccf, 0xca0c3e60, 0xd78c1f6c, 0xd10ce65b, 0xef22cbf3, + 0xcd493ee2, 0xca2f56f3, 0xf6f3ef6f, 0xf49bcc2a, 0x6aad6f3e, 0xc7a60e73, + 0x1e8d6fe6, 0xebfd6f7f, 0xf42bf49f, 0xbecd3b63, 0xf3c1de31, 0x845dd927, + 0x93bd019f, 0x68d83fc0, 0x3b3c7273, 0x792d9e38, 0x5ba78f5c, 0xb1ff788d, + 0x33748790, 0xd7a0b644, 0xfe7905a6, 0x90bb39e9, 0x5b87900f, 0x4eec2f90, + 0x2c7efe03, 0xafa969fc, 0xc6575f1e, 0x7ee1a78e, 0x6ff6886c, 0xc91f7e3b, + 0x4b7a79c6, 0xb56fdfe3, 0x6309f05b, 0xea6eff46, 0xfb42af4c, 0x678aede8, + 0x9ff68b0c, 0xe7bfceda, 0x061ddb35, 0xf02cdbbf, 0x7638e521, 0x3cc40f9e, + 0x90cfa81d, 0xc31ece2e, 0x03e4bb3e, 0x7ae4d7a9, 0xfd911da4, 0x67f82f7e, + 0x8ccfe0ba, 0xfc1f3e26, 0xca9ac2b3, 0xdeff01ed, 0x7841eb9d, 0x9da2b21e, + 0x78f34160, 0xaddd67a0, 0x16f7d18c, 0x33fc1f62, 0xbb2df047, 0x07e81d6e, + 0x7e16fe92, 0xd738875f, 0xd407fd28, 0x7a9d134f, 0x0e1c43b8, 0x55f5c2b3, + 0x70927e8c, 0x7cfc3ac0, 0x138d171c, 0x8edc6fb5, 0xb58f42a9, 0x6322ef8a, + 0xfe7fe6e5, 0x569b911f, 0xe9025e71, 0xbcdf4f10, 0xc96eec25, 0x0562fedb, + 0xc04c6bf8, 0x624fc3e9, 0x1ce7ba4a, 0xb0bd40b0, 0x37cb414b, 0x82855720, + 0x45bc70df, 0x18f8a3e3, 0xf032e49d, 0x3e2a3fdf, 0x0366df0a, 0xa3a2dff0, + 0x2e2494e7, 0xf32a19c7, 0xc3fedf13, 0x80381fc2, 0x00d4efdf, 0xdf34505d, + 0x969bf01a, 0xbf4763dc, 0x43e66de7, 0xfb74e9bf, 0x8c78d312, 0xbf70b75f, + 0x6e2f4065, 0xbd07ebe6, 0x6d7a8ed6, 0x477edbcc, 0x2167d411, 0x5bce30fd, + 0xd379f8c4, 0xe3185776, 0x198f2925, 0xe0667b73, 0xa39d473e, 0xf75dbd61, + 0x277fa07c, 0xca8dcff4, 0x35ca0d75, 0x82b53bcc, 0x2b4eb3b7, 0x8b160fdd, + 0x47bec62f, 0xeff226f3, 0x7ae24c6e, 0xd234f50d, 0x6ec21ca9, 0x4afdc03b, + 0x798cc86e, 0xe4c657d4, 0x957dc44e, 0xa2c14943, 0xa67ef035, 0x29983738, + 0x26669bce, 0x126b72f1, 0x0e99cbd7, 0x5c1d065e, 0x79ba67bf, 0xef79d8ff, + 0x54defd12, 0xed7f064c, 0x7c3c8204, 0x38af9f30, 0x327e88cb, 0xed42bf4f, + 0x8002cdff, 0x9997456f, 0x4d3b07f2, 0xea24fac1, 0xfb1d12a7, 0x0f8b3d4c, + 0x1ef10123, 0xf3128ba5, 0xb167d493, 0xa3ea34fe, 0xfcf20d9b, 0x3be3825d, + 0x9190afb8, 0xfafcbfd8, 0x027e7d7c, 0xb7c26b7f, 0xfa496fe2, 0x8c80bccb, + 0x307f25bf, 0x6bad20f6, 0xbfce4cea, 0x6177afa0, 0xbafa0afc, 0xebc91a68, + 0x6bbc780f, 0x719178e3, 0x4f66667c, 0xc0b7c61d, 0xbc9ef487, 0xe4f729f7, + 0xe41e749b, 0xf537248d, 0xb7f0e5db, 0x5bc9c526, 0x6869a88d, 0x8487fba2, + 0x42f795dd, 0xafdf6a8d, 0x19be3aa8, 0xfee1c555, 0x60c59269, 0x7d443a17, + 0xd3971277, 0xa5115551, 0xd88dfa00, 0x015143ba, 0xfced119e, 0x0688f77c, + 0x0c9ff746, 0xf0e61bcc, 0x95870d8e, 0x70a28adb, 0x17669b37, 0xe69e0079, + 0x09af874c, 0xe0ce699e, 0xcd77080b, 0x039d08b1, 0x5bac7a9d, 0xd32978c5, + 0xf205ffe9, 0x6bd7849b, 0xbcc08cf6, 0x8718e3bd, 0x9fc065b3, 0x79e6c9ef, + 0x3c0aefc9, 0xc9fb09b7, 0x4efdd30e, 0x336f6e4e, 0xa6db19ef, 0xfd26673f, + 0xccd7e858, 0x72e3ee28, 0x614f799e, 0xb8ba03db, 0xb03f3cb1, 0x0f979f03, + 0xbf11371b, 0x307fcfb7, 0xc73ee2a2, 0x154d5b0b, 0xf6fc38e1, 0xa75394b6, + 0x2eb8d7ff, 0xc957ff09, 0x4967ec87, 0x1def9a1a, 0xb7060f82, 0xa5ed443f, + 0x84dfa64f, 0xd06cd6f0, 0x48f16e18, 0x033a67bc, 0x239f1027, 0xc4155bda, + 0x9f8e63c9, 0xae0e7828, 0xce798aba, 0xaef6d203, 0x7bc1cb6b, 0x7cee6a97, + 0x79ef072e, 0x38c0f092, 0x98d6ef84, 0x0fd28b73, 0x67e11ff9, 0x67033b94, + 0xcebafc70, 0xb7bfb44d, 0x5fbf0772, 0xcfbae127, 0x9eb02f11, 0xd5bfc8f5, + 0x5478bfc0, 0x8dfb0147, 0x6859acf4, 0x6a26efa3, 0x63fe7176, 0x18f0b41b, + 0x8eefb7ac, 0xe47da098, 0xa61f7edd, 0xed77abef, 0xf0e99656, 0x4c26b235, + 0xb9e77bfb, 0x97227ee4, 0x4bed11f7, 0xb38f886a, 0x63e43e1c, 0x71d92fcc, + 0xfdcecf3f, 0x1e52deaa, 0x425af49f, 0xafd0bd63, 0x87c93737, 0xbabd3bdf, + 0xdefa0afb, 0x35bcf5d0, 0x7ca3b8a2, 0x6f7ac0f3, 0x40f9c229, 0xdf20f339, + 0x835fde80, 0x2726f2f5, 0x1a9fbe43, 0x77a9c743, 0x3bf6be73, 0xc31ef2dc, + 0x63d7c889, 0x81aedc1d, 0xeebf205d, 0xf3c38590, 0xdd74e33c, 0x75c8149a, + 0x87f7e064, 0x54f18611, 0x86bb454a, 0x387608f9, 0xbd5bf095, 0x37d683b5, + 0x7bf71772, 0x92b577aa, 0x82fd4a3c, 0x7b7bc0f8, 0x457be2a7, 0x47040fc4, + 0x943b93e9, 0x927fd0e3, 0xbcf3ccc3, 0xc7ec775b, 0xf019887b, 0xd02fc60b, + 0xce4affbe, 0xe96e2a3f, 0xce3dc80d, 0x59e7c453, 0x097b93a6, 0xbff91c77, + 0x1e77e118, 0xe5c83eeb, 0x6fefc23f, 0xe921fc12, 0xf5c1c330, 0x21c7a48f, + 0xe300e80d, 0xa24bca1c, 0xa23ca471, 0xfa11ccfc, 0xc68ce4c9, 0x090e1249, + 0xd9472ee7, 0xb8298e15, 0x775a6eee, 0xe09556ed, 0x0502d72e, 0x3b7c75ab, + 0xfbf9c1cf, 0xb57782c0, 0xf9be781e, 0x9f0947e7, 0x3f0a2db5, 0x5472dac7, + 0x3e7a879b, 0xe319acf4, 0xff19ab9d, 0x51cf747b, 0x7757cfd2, 0x76d7bc70, + 0x736f56ec, 0xf728f946, 0x74c581e4, 0x95bb751f, 0xe9923fa1, 0x788cde0c, + 0x024fc418, 0x25cf520f, 0xf4871392, 0xf91a4253, 0xe421e029, 0xf520dc62, + 0xdf1156e4, 0xfe7f2730, 0x515d624f, 0x41ac10fd, 0xf927947c, 0xdf50d80e, + 0x3ce8544d, 0xe933b487, 0xf51e3833, 0x37bdc4f0, 0xd287e64f, 0xb25f8c98, + 0x63bee8e7, 0xe2b7d018, 0x5d04bbfd, 0x3f8479e1, 0x37687967, 0x74b1dc25, + 0x6bf081fb, 0x1351f0e2, 0x476b1fc2, 0xfac05f24, 0xf73db19a, 0x41ec89a4, + 0x86d6c86d, 0x98af26fb, 0x75df90e6, 0xf09b8160, 0xdf90b357, 0x67f9bc63, + 0x84d4af5c, 0x777f749c, 0x256e704d, 0xdba543ed, 0xc50fb87d, 0x79b50782, + 0xf774c1ae, 0xce9fbf3e, 0xcedd5c31, 0x8f4060e5, 0x4bfa73b6, 0x1fd72efd, + 0xcfc7375d, 0xec858d2c, 0x6dbc51a9, 0x7d08f24d, 0xdfe5cc10, 0x3ccd7fa3, + 0x7b1666f7, 0x88b3d29f, 0xcf5b5a8f, 0x2faadc21, 0xd35fbb79, 0xf2c727ef, + 0xd7baf557, 0xac2ed10a, 0xa54c3aca, 0xb7a0ff3e, 0x7d057b57, 0x8be5149e, + 0xa7985f48, 0xc93b727a, 0x0d07f54d, 0x0ace6f24, 0xc79c67ae, 0xd6307a8c, + 0xb4772a5f, 0xdefdc2cf, 0x9e2a1ff2, 0x5ed89626, 0xde7850ac, 0x2fada3f3, + 0xc19cf1bb, 0xe26bbdc0, 0x0e1bf03c, 0x3bbdffce, 0x97c4e101, 0xfe50da0d, + 0xc78d57e2, 0x74296f22, 0x7dc0808f, 0x1719aeef, 0xd2e7887d, 0x7e532677, + 0x375dd3e7, 0xc021f9dc, 0x72e3bbdd, 0x4de943b2, 0xfe9fe201, 0xf70fbb0c, + 0xa97e20df, 0xebee8050, 0xe3765fdb, 0x3f27e4fe, 0xda2270ba, 0x9c050fb7, + 0x5e667f27, 0xe7b97887, 0x865e9f99, 0x2561d5ed, 0xef6cf50d, 0x15fe1fce, + 0x8ed570f5, 0x9a9f8a7a, 0x0d4bf47e, 0xe14d39f7, 0x677cfe56, 0x7dfb07b2, + 0x65d37db2, 0xf6a6ef88, 0xb93f6a26, 0x07ea95bd, 0x4be9f99e, 0x33f68dff, + 0xbf61f6e0, 0x4fdb3f93, 0xaa09a974, 0x04f0defc, 0xeee8fd7c, 0xa19f5cfd, + 0xb07287bf, 0xc919eb90, 0x3f7f92d7, 0x8bd6e679, 0xc6bbfaf4, 0x60a5181c, + 0x1f5661ff, 0x7d07d79e, 0x15fbfa4e, 0xc4ed533b, 0xce9cadf7, 0xaf74d5e6, + 0xd73e7943, 0xdc61883b, 0x72febaf7, 0x91477d07, 0x4afb10e1, 0x293f1176, + 0xbcc3ed0a, 0x6d05e972, 0x217dba4d, 0x9457bf49, 0x1756a3d9, 0x8b379f45, + 0xb8939b79, 0xf514f93d, 0xd539c430, 0xac1efc65, 0x5f6c7f4f, 0xd6b5fe48, + 0xd76bf743, 0x34be7114, 0x9a3d393b, 0xb7e57e45, 0x39630ee0, 0xcf02e41e, + 0x8eeb40d5, 0xfadf292f, 0x1a6fd913, 0xbed357c2, 0x784752da, 0x0e7f11f9, + 0x8ee7c658, 0x354b06a2, 0x1b592f3c, 0xe91c5e3f, 0x3dfd3274, 0x663a2376, + 0xde92f28f, 0xe8c6fab1, 0x5511d2fc, 0x27dc26c1, 0x906d6ab8, 0xe17ea9ee, + 0x5ee937e3, 0x2ac667e3, 0x30df8893, 0x2f76847f, 0x6a79a4e4, 0x70078f31, + 0x7114ef9e, 0x17a987a3, 0x32aff1eb, 0x75fb49d5, 0x6a97a4fd, 0xdc5d859b, + 0x5b19e221, 0x6bde367f, 0x2f39ef0a, 0xc09bedd6, 0xd5274e7b, 0x8fe7b3fb, + 0x5a143b47, 0xabc87648, 0xa527bc11, 0x09a161fe, 0xa1e2e8b7, 0xf51738d8, + 0xca77e61b, 0xe77ea59d, 0xe3296894, 0xdd3c58df, 0x3877da25, 0xea277efd, + 0x16e79dc7, 0x7a09d687, 0x2cf4aa3f, 0xed0e3e47, 0x2f907bb3, 0x29eb2eeb, + 0x3bb1ebd4, 0x0b4e9e04, 0x41dfc13e, 0x64cdb8a0, 0xb5df110a, 0xa4dad05d, + 0xe77bb60c, 0x44757f09, 0xba41e2a7, 0xc73ad88c, 0x9bf03f40, 0x7f686bd6, + 0xe4252ac6, 0x7eae76cf, 0x11e61c6d, 0xaf586e81, 0x495d98eb, 0x833b03f8, + 0xe75d6cfe, 0x73840eec, 0x3eb5fa64, 0x3f0797dc, 0xe77d1664, 0xa0a6c351, + 0xda3a3efc, 0xad246fbf, 0x1e786143, 0x384b51f3, 0xa3f7ed0b, 0x787d0ae3, + 0x582ea63e, 0x0af24359, 0x2f7d2d7e, 0xfe40dc15, 0x26f79d6b, 0xc6a7ed1f, + 0x853ef9ca, 0x1be054fc, 0xab8b1dfa, 0x7c2cbbf1, 0x7920ec3f, 0x2dccebaf, + 0x9eaef845, 0x9e60f3e9, 0x8fc494ed, 0xf4dd2d2c, 0xf7a7183b, 0x27485958, + 0x03eeaf97, 0xf80266bf, 0xafc17b35, 0x3fdf8099, 0x1571d9fa, 0x0d7a71c6, + 0x5deab779, 0xcdef74b9, 0x7f8ed129, 0x2d7ddd5e, 0xe21195b5, 0xcfe11acb, + 0xc5fd5ba6, 0x26e8ebb7, 0xfa5894fd, 0xf6e4ee3f, 0xe727bce8, 0x00463d12, + 0x239f103d, 0xa26e9ab6, 0x863485f5, 0x8aaabbeb, 0xbe01ea45, 0x229ab6ab, + 0xfa884f97, 0x3de3b131, 0x4f7114e9, 0xf518a05a, 0xa702f95b, 0xca87af4f, + 0xbb26fc93, 0x2c628fce, 0x92e31930, 0x845d338f, 0xaf4e1df7, 0x7e0c87f4, + 0xd3b8e0cf, 0xe1f8c3ee, 0x04d0969a, 0xaf0e87dc, 0xf2885a4f, 0x49d47a08, + 0x781eebfb, 0xb6d6e31f, 0xb8f3b64b, 0xf9d689b5, 0xc247a77d, 0xe301b937, + 0x5ac0fcdc, 0xbe5c7f6e, 0xe5d6fb78, 0x2ee7e94e, 0xbef3c62e, 0x3e9d7375, + 0xff36af8c, 0xe38a5942, 0x746c85d7, 0x705d6e39, 0xf2579bed, 0x5fdf8038, + 0xbaa2fc23, 0x347d1bf4, 0x7a7e20ff, 0x4e8ddb8f, 0x4ebaaf4e, 0x1c642f6e, + 0x5e217a8b, 0x29ca5ede, 0x6b8c63ea, 0x39497f24, 0x3c79573d, 0xfc90096d, + 0x2375869c, 0xe1f00e3f, 0x630f9c0b, 0xff8934e3, 0x8bc2f8d8, 0xef7506c2, + 0x8f7d0776, 0xe69af52f, 0x3d451c0c, 0x6476d754, 0xd0abb123, 0xdc2f7543, + 0x3f94385f, 0x78f95365, 0x3d2b9036, 0x1359e0df, 0x432a44d7, 0xc0df3a4e, + 0xc6df5fb8, 0x1d8e8fef, 0x4f42b7ef, 0xbf4a7c49, 0xcf82f319, 0xc29ff943, + 0xfa227d7e, 0xcf29d5fd, 0xfc0d8457, 0xdf0535e7, 0x44f17dc3, 0xf7be56fa, + 0x7226f34d, 0x63efa97c, 0x99f325e9, 0x45d98eb8, 0xecb5fb89, 0x0c48f117, + 0x3e0b14ff, 0x80e7037e, 0x07724f75, 0xbea0b917, 0xd3f99928, 0x7e8bdf00, + 0x29f7e569, 0xc42fed8c, 0x655aaa78, 0x5797cc21, 0xf584b4ef, 0xa1f736e7, + 0xf5ef040f, 0x33216cb9, 0x3bb95df0, 0x0671c1e8, 0xcbbd87ee, 0xc1e1e74e, + 0x7282994d, 0x481ed23b, 0xf7e06575, 0x4f743d89, 0x1e0e63ec, 0x311ff44f, + 0xc5cbcf87, 0xe87bbe7b, 0xacce84f7, 0xea7ca7cd, 0x61fc2f3b, 0xede01fcf, + 0x1a3e7b53, 0xd493cfad, 0x55364cd9, 0xad3c6f97, 0x2b67dfc4, 0x167d7176, + 0xf3f65bcd, 0x438be5bc, 0x63eb41e7, 0xf3d1fbf2, 0xfdf9b1b3, 0x6fa878e8, + 0xfbf263eb, 0x6f5c5d07, 0xf9e7df47, 0xf14c77fd, 0xc7bd6fbf, 0x8bafdc65, + 0xc5cfbf6d, 0x8f23abf9, 0xe3ff45cb, 0xe4fd184a, 0x115d6be5, 0x396b8fbc, + 0x63bf463c, 0x311427b9, 0xf9ae51b9, 0xcdfc323e, 0xbe5f81b5, 0xe807d844, + 0xbe474ea7, 0xff68790c, 0xd0f42831, 0xff57ce92, 0x72f4f18c, 0xc3a6d995, + 0xbe6d4b38, 0x13fbf843, 0xba673a1f, 0x7e56ed51, 0x744c86e7, 0x6a2d86e6, + 0xf455bca0, 0xf374f57c, 0xfabe72df, 0x57302bb0, 0x7fd21bf2, 0x5f5cedd1, + 0x9756fec8, 0xe467373c, 0xd01377b7, 0x665dc739, 0x3ababe46, 0xc698b029, + 0x4194fdbd, 0x7a569caf, 0xf201fe9e, 0x7bfe6ae3, 0xd7efb147, 0x8afaf98a, + 0xc53ee9bb, 0xc97fd5be, 0xebaebf26, 0xff51b7d5, 0x817bcad5, 0x7b862c3b, + 0xfc932b81, 0xf7efc4d5, 0xfba14f4d, 0x73c186ce, 0x1ab82782, 0xf6fe41e1, + 0xdbf9eba7, 0x2ce78c9b, 0xba01b5ea, 0x921ef7d0, 0xcb946c2e, 0x23ae8f48, + 0x36a58f44, 0x701bdd3f, 0xf0403f9b, 0x4c8e4a2d, 0x5ff018f1, 0xf7dd37f4, + 0xf6e42958, 0xfdfe2d1d, 0x3e09f7e2, 0x8dfb283c, 0x4efafce0, 0x1e7aab36, + 0xff234ccb, 0x2ce42c3e, 0x71cbde2c, 0xbc421ffb, 0x18795e80, 0x8e7400f1, + 0xcaf5e8a4, 0xe7ba7ee4, 0x374a6fa2, 0xae7d1f7d, 0x80ac66f8, 0x8e784bd6, + 0xd1385e73, 0xf0b56f7a, 0xb5df0075, 0x47af48b9, 0x87bfebc6, 0x5b80b9ff, + 0x493be5ca, 0x142cbc46, 0xe091fbeb, 0x87974a93, 0xfd7c1be7, 0x3bce38d9, + 0xb8f1f1a9, 0x768f8a28, 0x7fb583c2, 0x6fd01a71, 0x6d35d83e, 0x12a7e122, + 0x938a0f9f, 0x49ff228a, 0x5c6b6dfb, 0x0bc5ed0c, 0xfdc9be72, 0x963f8f3c, + 0x885a0bcf, 0x57d96eff, 0xc2bd6de0, 0x3145e77f, 0x2b6844c3, 0xdf2f32c7, + 0x7fce980f, 0x203ecaaf, 0x195c8797, 0xcec4fc51, 0xc09b0c7b, 0xc4bb779e, + 0xe63e40f7, 0x1f16f7c3, 0x8b75ccfd, 0xf43df0d7, 0xef4e385b, 0x1fc8479d, + 0x0a45a63b, 0xda719c5b, 0xc7b6c8b5, 0x6b3b6894, 0xadc17ee0, 0xbbe99acf, + 0x9ea66398, 0x2d7f7047, 0xfc99a6f4, 0x3dde3fa8, 0xfa2bbe83, 0xffa30ef4, + 0x45d0527a, 0x20309f7e, 0x830b783f, 0xc5eff079, 0xcb9ce6dc, 0x3ee629e5, + 0x14164af6, 0xfb13fbbf, 0xe103427d, 0x893df079, 0xe73c87eb, 0x7ce6e995, + 0xf38269f3, 0xebfb8a19, 0x3ee327da, 0xc4bed45d, 0xf1f1d3ee, 0x474e6edc, + 0xf6fea769, 0x304aaef9, 0xe77175df, 0xba7cf393, 0xb3bafe3c, 0xd58edcdc, + 0x461becc7, 0xb3e795c7, 0xa49fa85a, 0x2cd9fd77, 0xd2eb2e7a, 0x37be8a8f, + 0xfd8bc68a, 0x13e6472e, 0xa7beff25, 0x9efd1b30, 0xf224db11, 0x78099e86, + 0x687bd0bf, 0x06df412f, 0xf52f60af, 0xfe4b8800, 0x9aa17879, 0xd8efe517, + 0x9d5f0075, 0xd51effd4, 0x4fb8b704, 0x217642ef, 0xf821177d, 0xe59df179, + 0xf25aee74, 0x854f546f, 0x71adbc78, 0xa7319e3f, 0x18b3ff41, 0x13a4b0fb, + 0xb204c1ec, 0xfc0e74cb, 0x12378bf8, 0x5f32571f, 0x17d1e926, 0xe93f74ad, + 0x120bb5d7, 0x4b421b9e, 0x8adefc2c, 0x6bc7ba74, 0x86ff988e, 0x981fee2e, + 0xfbfe7e6c, 0xf5e67e55, 0x03dff264, 0xca05fb21, 0xa5fa855d, 0x00cc8eb2, + 0x3162e9f5, 0xf00fbe0a, 0xb64a2a5f, 0xf2859834, 0xb7ffef26, 0x961670b3, + 0xbcf9174d, 0x04ae5e58, 0xa7070e54, 0x30d62cf3, 0x6c9bfb0a, 0xff9c663d, + 0x58da7991, 0x4fa01fbc, 0xdf89f249, 0x74fba3fb, 0xf3f303ad, 0x9dd64bba, + 0x0eefc32e, 0x7dc5bbd4, 0xa366360f, 0x4673ebdf, 0x057da13e, 0x616cda51, + 0x0701ddfa, 0xcdba448b, 0x8c00fbf8, 0x614f9bbe, 0x3dfc112d, 0xff17be8c, + 0x1e1c518b, 0x76fc0fbd, 0xef2194f7, 0xc7b6370b, 0x2a9e17dc, 0x7e634ae0, + 0xad221fba, 0x635f78c2, 0x42ad7386, 0x3016e13f, 0xc444cf3e, 0x0b61ff43, + 0x6f0bef63, 0xe1fc7051, 0x1b73e341, 0x5f7a463b, 0xbeb20489, 0x93de8b4c, + 0xdf8920b4, 0x22eff44b, 0x115b9c8e, 0x6f015728, 0xafd88bf3, 0xe8de50fc, + 0xe1177e09, 0x4370f1bf, 0x17d40d6d, 0xe3c6cebe, 0xc9c530f7, 0x185dea9e, + 0xefcadd7f, 0x3efe2d6b, 0xec361d67, 0xf0c78a3c, 0xc9b51707, 0x2b2ace78, + 0xb17d718c, 0xd48fb443, 0x7f18bda8, 0x3fdf1100, 0x95f74bcf, 0x74f38bd4, + 0x9a7987f8, 0xc333f3d6, 0x67d30768, 0x7ac46ff4, 0xee8cfdff, 0x19f79059, + 0x408ec76d, 0xbf4afa9f, 0x87da0325, 0xe23e64cf, 0x03bed149, 0xebcf9dff, + 0xdf889797, 0x5d47c08d, 0x2733ca9b, 0xc6fa9b13, 0x5cfcc1b0, 0x18bb35df, + 0x73f954f3, 0x297f13a7, 0xba0a2f82, 0x7c51ff14, 0x3f68c22f, 0x972bbeb5, + 0x1c17dfce, 0x719e51f6, 0xd4e1a981, 0x1bdf5c1e, 0x13effe3c, 0xc84cc6fb, + 0x7918d4f3, 0xafca24b9, 0xe72c5ed4, 0x7accfb97, 0x3ce046be, 0xfc44a0f0, + 0xc7bd12c4, 0x1662ece5, 0x6671c3fd, 0xbd25c744, 0xbdb45332, 0x3fdf0b72, + 0xf646aa9b, 0x225e1ca3, 0x4e5162ca, 0xe2330166, 0x7f73c4ab, 0x5177ce13, + 0xf21a68e0, 0xaf9b74fd, 0x9f46af19, 0xb86150bb, 0x4e9cc4af, 0xffb17ebe, + 0x3d8af52d, 0xfb67e799, 0xddbab3dc, 0xdf997dba, 0x30df85ba, 0xb98d8d96, + 0x24f7ff67, 0x3bffa517, 0xdb18dc91, 0x4066e463, 0x7d3f313f, 0x7dfb18b7, + 0xff3f3ce1, 0xc05e6a6e, 0x7e3e7cf8, 0xe71f97d7, 0x15d0ec77, 0x0b8e8ccb, + 0x78416472, 0x6ec77f62, 0x2ab7f48e, 0xa2d6fe8c, 0x8522fa7f, 0xa7b0c0ec, + 0xc1ccbf6b, 0xe25ce67c, 0xb12ebacb, 0x43fc0f3f, 0xfd89e3df, 0xe34efaf9, + 0xd77d7cfe, 0x74337b92, 0x9d75f3fb, 0xcf3fb55f, 0x5bbfeeed, 0xd30f74c2, + 0xd604afbf, 0x165e7982, 0x7107c2fb, 0x9462783f, 0x3cc5aeee, 0xe35073af, + 0x3107f4fb, 0x4bcba37f, 0xfcf070cc, 0x340b8ce8, 0xe5573e7a, 0x2129f2fb, + 0x0b92f927, 0x665defc4, 0x7e41d998, 0x1fe7847e, 0xeb3e22c2, 0xb40d7e16, + 0x47fca06f, 0xa465dc8c, 0x6547ca31, 0xf2963cdc, 0x8abb0b3a, 0x0d3e6327, + 0x7fe533f4, 0x7a5eddbb, 0x98b0617f, 0x395723f2, 0x8af3a46f, 0x6aad5df5, + 0x7adf4ea5, 0xf5f78d93, 0x9a5df9c4, 0xfa29e482, 0xe019a5df, 0x489e7a27, + 0xa7dfcb0f, 0x9bbe62ac, 0x7de2e597, 0x9d774001, 0x3194b79d, 0x53fb4f7e, + 0x5d2b9d0a, 0x76483ce5, 0x630ed578, 0xd45b943f, 0x6bafd57b, 0xcd537f74, + 0x467c41ae, 0x5de52d72, 0xa1b517de, 0x3ee0afd4, 0xe611df4f, 0x77fa436b, + 0xc05b8cc4, 0xe04f98ed, 0xa5e858b3, 0x3666f349, 0x24e53ee1, 0x565f9713, + 0x7fc91be9, 0xe7917377, 0xc7551d84, 0xfe50cad3, 0x63eb9f40, 0x067dfcb3, + 0xc4531fd4, 0x717ab1f8, 0x2e03f08a, 0x137d6153, 0x0a7d76a3, 0xa683f5e3, + 0xbddd332e, 0x3c9ce02f, 0x9fdc4720, 0xd24a7a90, 0xc6e5ef03, 0x92cb5df3, + 0x63c87e85, 0x184f4879, 0xc157f89f, 0x8d2a73cc, 0xbca1521f, 0xf407cc44, + 0x84df210e, 0x9dfa364c, 0x034a8d8f, 0xfa1b79e9, 0xa03e508d, 0xfd7f4904, + 0x46642abc, 0x1ac45ebc, 0x1726b86e, 0x03b758f5, 0xb07c05e9, 0x4d1fcf52, + 0x5bbd922c, 0xb509f031, 0xe8c4a6f7, 0x3d12a61d, 0xc238304c, 0xa5ad7669, + 0xc42bf47d, 0x6e53a273, 0xc9d51fb4, 0x3fb4618f, 0x87c01fea, 0xf52fddb1, + 0x93ea3309, 0x8f05f65c, 0xf43feed3, 0xfb0f8c1d, 0x8c5fc22c, 0xa1dd4ba1, + 0x641f8b93, 0xbe49fa51, 0x983598ba, 0xca1f00b3, 0xf75e792f, 0x2a5ba462, + 0xfc8c51fa, 0x892c69a7, 0xe64d8be4, 0x57c907f9, 0xa2255e92, 0x4fa484f6, + 0x7841cb0e, 0x53b4ed2f, 0xa462e9de, 0x58bdd013, 0x4aed2f8c, 0x6af4e4c4, + 0xb0174879, 0x7ec1e61b, 0x97aa665e, 0xe4c933e8, 0x614cfa27, 0xdba434be, + 0xd7ddf6cf, 0xe8eb7084, 0xe3192db0, 0x80e80545, 0x3ed8357c, 0xe463db18, + 0x94bbe259, 0x2c9fc979, 0x9c394665, 0x670d04e1, 0x8dcafba2, 0xa0b363f7, + 0x7b94f08a, 0x6f8fdd06, 0x41b1d232, 0xc8ae7845, 0x444bf632, 0xa7a41ccf, + 0x89690fb4, 0x6ae529e9, 0xa9d39db7, 0xfa84e81e, 0xd2afd266, 0x34813867, + 0x25ccade7, 0xc53bb0fb, 0xfaf584db, 0xc5f4851a, 0xcbdf6ee4, 0x106fcf58, + 0x337eb9ed, 0xafd683ee, 0xde53ede5, 0x7ac0cc0a, 0x5ede3ac1, 0xc9b04f7c, + 0xaddfe385, 0x2fd8bdd0, 0xcbc7727c, 0x47be1ed8, 0xcfca5fbc, 0xe06fd6e1, + 0xf9847fef, 0x3cf10bde, 0x7c0ccb44, 0x9739ae3e, 0xf0b00eff, 0xfc172e67, + 0xe3695bb2, 0xc83c20f7, 0xc8715dc7, 0xce28c496, 0x65cafee1, 0x6f979d62, + 0x3f4cebe5, 0x1785557e, 0x37b2a9f8, 0x2d95d740, 0x1109c164, 0x3372ef58, + 0xf1f9f204, 0x10bc1be4, 0x0d288f28, 0x500aa744, 0x72fbf49d, 0xc0b67cd3, + 0xc7ef9e78, 0x92fa79ef, 0xf329bc79, 0x35ffb8e5, 0xfb4f675b, 0x469e7992, + 0x654ccbf6, 0x09ef3f7c, 0x91a3f917, 0x7c8298c7, 0xfec0b88f, 0x57faf289, + 0xbd9037e4, 0xe64722ba, 0xa5d47bf3, 0x97f15f30, 0x178acd9f, 0xcc9e7f07, + 0x62c7e4ed, 0xaf3e4f1f, 0xbdfdf30a, 0xf4cbc8dd, 0x30e9ad7d, 0xe19853d5, + 0xb9ddab1e, 0xfe7aaebc, 0x28f35f7a, 0x06b35dfc, 0x36ca8435, 0xcc7da15b, + 0x679fe0eb, 0xffe14627, 0x2830d93f, 0x00800092, 0x00000000, 0x00088b1f, + 0x00000000, 0x7dedff00, 0x45947c09, 0xf37f78b2, 0x093215cd, 0x87213b93, + 0x98884013, 0x861c2184, 0x4109264b, 0xe8098414, 0x720d7282, 0xeb22dc85, + 0x97f75763, 0xd9110441, 0x73d6f8dd, 0x0160763d, 0x18896151, 0xc3824830, + 0x12a20882, 0x75040411, 0x0844ae22, 0xf1e20c49, 0xabaf2e1e, 0xbe667bba, + 0xfc38666f, 0xddbf7ffb, 0xdb2e23f7, 0xaaefafa9, 0xeaeaeaea, 0x084c8eaa, + 0x908238b9, 0xadc4b45b, 0x9680a1cf, 0xc8401bfe, 0xd5fa25dc, 0x3f02242b, + 0x213c6376, 0x33fe1277, 0x192d7aec, 0xf01dc844, 0x289085bb, 0x2afda4b3, + 0x9fdefe83, 0xd328bff4, 0xf3bfcf72, 0xc84d94a3, 0x3a558caf, 0xd50a1dd2, + 0x8459ece8, 0x9c9b359c, 0x7c84be9a, 0xcce2392e, 0x7d690903, 0x965cff76, + 0x64beceef, 0x47e696be, 0xb048d4d0, 0xefde62df, 0x13d2e27c, 0x977cdfda, + 0x918f0bee, 0xfd22ed0d, 0xa43a6a57, 0xae9a1a27, 0x232f7e57, 0x41e93d1e, + 0xf2ad7948, 0xe271257b, 0xe57acaf7, 0x91d99277, 0x845efd06, 0xf69f8a1f, + 0x5907cb67, 0xcfff6932, 0xe6147fbc, 0xb9346c57, 0x97129a65, 0xc193d5ae, + 0x1e7ce1eb, 0x4e157f34, 0xc8fba793, 0x64246f17, 0x6cc89752, 0xbb9095d2, + 0xe67e8ecc, 0xf99c4238, 0x146529e6, 0xe1e9cebf, 0x5c5025d6, 0x4c396536, + 0x6308fdb4, 0x8bce9b96, 0x4cc588d8, 0x79f12df1, 0x9f0c0d4a, 0x3c52471f, + 0x4832f8c3, 0xe699e006, 0x14d1f53b, 0x8448e3ee, 0x93881bf1, 0x88c23e00, + 0x4252112b, 0xbf1846ac, 0x42475e1f, 0x2179adff, 0x57ccaef1, 0x1f027de1, + 0xd36244cf, 0x47137f41, 0xa775f12b, 0xfbd22169, 0xfbf2bb4e, 0xcb1388af, + 0xc2ac9a4f, 0x24c9b12f, 0xe0aed7de, 0xca1cbb93, 0x9e041372, 0x3cf1ab47, + 0xc515fccc, 0x01309d2f, 0x54d24c7c, 0x58c9e3fd, 0xb30d6f0a, 0x1cf6c5ae, + 0xb852178f, 0xbac12eb3, 0x4b44c002, 0xfdb409d7, 0x926c404a, 0x3d22ae8f, + 0xab189d58, 0xe707e9ed, 0x93761991, 0xee389e0f, 0x1499a0d8, 0xcfe5d22e, + 0x06913c03, 0x29837ffa, 0xd210c53f, 0xb2f80994, 0x18262574, 0x52d47107, + 0xde92d3b8, 0xd814da35, 0x132b488f, 0xfdb4e313, 0xdb4bf8fd, 0x3e066911, + 0xb0cf20b8, 0x2a383267, 0x53f552f3, 0xc131b4e2, 0x5acf37fa, 0x91787809, + 0xa38e81e1, 0xadf943de, 0x2b5f7d73, 0x2a7210e5, 0x942468ce, 0xa67467de, + 0x1f5f52e5, 0xea2ee63e, 0x4a95ed86, 0xd0b6efae, 0xc764836f, 0x52cf3023, + 0xf8cf5b8d, 0xa13a6aa9, 0x6f3f96ed, 0xf748adb0, 0xf8d43fcd, 0x2d23f008, + 0xc93bffa2, 0x1d7ad2d0, 0xeaeb1752, 0x0bdefc74, 0xddca2ce8, 0x2b17451f, + 0x9185ef5d, 0xdd60278e, 0xe8b8c3b7, 0xa309697a, 0xaf8e86eb, 0x01932245, + 0x74e2549f, 0x7e02ca2d, 0x04eba3bc, 0x951297ca, 0x81d1c953, 0x351856fd, + 0x5e1fb764, 0x757d78db, 0x096655b9, 0x9989f7c7, 0x4dc7ff60, 0xdf30d5b6, + 0xae293d16, 0xe96c78a5, 0x9a48d3c2, 0xa01bfad2, 0xcf2840fc, 0x70e0edea, + 0xabe5868b, 0xbee517db, 0xdd9236ac, 0x545fac74, 0xf29bb213, 0x4369e597, + 0x4bb68b95, 0x147fd2a6, 0xa2dbed2f, 0x453e0156, 0xbce67dbd, 0xdd1c604f, + 0x802df64d, 0xcd35d98f, 0xfb5f877a, 0xe01f30ed, 0x579b1d13, 0x454b187b, + 0x45ccfb7f, 0xef1e209f, 0xbcdd20f2, 0xdb0160f0, 0xe1f6fdb1, 0x1fd21e4c, + 0x72c3ac0d, 0xc5cb0ebe, 0xae53ab7a, 0x04a64937, 0x63f9468d, 0x5aa0b941, + 0xc67a957f, 0x17ef844f, 0x4ebac4d3, 0xfb42d089, 0x64535953, 0x1fbec35a, + 0xa64248a5, 0x64b2c91b, 0x21a33f9a, 0x7175e501, 0x1997b3a4, 0x0cd23ce9, + 0x0ce489fb, 0x5f862f97, 0xe4b4bf8a, 0xd93e312b, 0xa9ed6fc7, 0xf6cf384d, + 0x81a63f55, 0x786f2ebc, 0xa875e507, 0x191f3979, 0x48f38516, 0xd6e0fb60, + 0xd9391b6a, 0x059787d3, 0x428f3666, 0x0f40acb9, 0x313664f2, 0x7ea7e81b, + 0xc3d3fba4, 0x57b95c28, 0x6f285c47, 0x93901a6c, 0x9c63c397, 0x7e2c435d, + 0x72612df2, 0xf0c96217, 0x688e49c1, 0xdc5c9c05, 0xb53e514d, 0xff22bbaa, + 0x147d45ba, 0x1ccee9f9, 0xf963dc05, 0xebf94510, 0x7015f26b, 0x536e67ef, + 0x35c1bf94, 0xc2770141, 0x9e3f202f, 0xca4e5d97, 0xbfae37a7, 0xde7f515b, + 0xbf4859be, 0x895ebe3a, 0x4994d6d3, 0xd05b30f1, 0x80686e9f, 0x670e52c7, + 0x68a3ded5, 0xb725b89f, 0xe1cfcb44, 0x69bb31fc, 0xf94258ee, 0x897d6fa3, + 0x67221fa2, 0xd28e30ca, 0xa18912ed, 0x46a73eac, 0x7bcc4fb9, 0x37170946, + 0x992cbe3c, 0xf407ea04, 0xdb4b4327, 0xac5d2129, 0xf5a8dfa0, 0x11519e84, + 0xdd0fc8b1, 0x57c63748, 0x79303e6a, 0x074861f1, 0xf4f5e83e, 0x3e3e01b0, + 0x19ebe2f0, 0xb9d5f109, 0x7b8e07b7, 0xee3a36de, 0x18fc40f4, 0x10fc9512, + 0x43f25166, 0x1f928678, 0x7e4aac22, 0xe4ab9ae8, 0xa3be3507, 0x20fe4a6c, + 0x105ffa1e, 0x568cc77c, 0xbca94df2, 0xefe00f72, 0x5f9e7872, 0x1fe90abf, + 0xf0a987a0, 0x1af01e3a, 0xff6bc3ee, 0x2625b6dd, 0x61df660b, 0xe478041c, + 0x197620f8, 0x046c52e5, 0x3e561dea, 0xcca7a14e, 0x107ae288, 0xd69fa76f, + 0xf7d613bd, 0xa049c932, 0x967fd09e, 0xdcd3bae4, 0xc639df14, 0xd520a02a, + 0xa2b3ec6f, 0xd32c1ca8, 0xdf21b3bb, 0xefc1ef4f, 0x417bd2ad, 0xa7411ef5, + 0x7281c439, 0xa61f0025, 0x2f50f427, 0x3f40ff80, 0xff8411ed, 0xed077ea8, + 0x5179f256, 0x7234b93a, 0x06a4be20, 0x0d911dc9, 0x72106cd3, 0x3fb171d6, + 0x157ca366, 0x4a0da2f8, 0xe84772fe, 0x817da28f, 0x448f211f, 0x255206bb, + 0xab7f0227, 0x50c913e4, 0xa9371de2, 0x223ff841, 0x35e80bd8, 0x416f9bc4, + 0x0899037e, 0xbc4de94a, 0xd30f723f, 0x06a48d4b, 0xb242b2e9, 0x7f69972e, + 0x4be975f2, 0x7f4ba508, 0x64ffd533, 0xa69b42d8, 0xd18d77c0, 0x773ec329, + 0xfe60b91d, 0x3f5a06ea, 0xc5f95d61, 0xbff2d098, 0x5b8d8dfc, 0x281f549d, + 0x2464f4d9, 0x5afaf4a1, 0xa56f135b, 0x2ed6cbf5, 0xb4d1b48d, 0x7d44eb45, + 0x3c976bea, 0x7f6415da, 0xed8a3f7e, 0x264274df, 0x7c153f90, 0x795fa72a, + 0xd7ac1c6c, 0xccead6ef, 0xb9522d32, 0xd036e0de, 0x375151f5, 0x46c92c7f, + 0x8fc199b8, 0x54f8037c, 0x5e4a1b9f, 0x82de327a, 0x5933a3fb, 0x3ba90893, + 0x62b4d099, 0x81463fcd, 0x3a49567e, 0xd4b8c196, 0x1fffa0f5, 0x595afee8, + 0x77d4cf2b, 0xe11e720d, 0xb5d05aeb, 0x6fb1eeb2, 0xcdf848e4, 0x557e07a3, + 0xbd062f97, 0x3b67ea8e, 0x89bb3c84, 0x45eb04dc, 0xe2b883e0, 0xdf93ef50, + 0x99bb2178, 0xf66badc2, 0x787e4a47, 0xc421e422, 0xaced674f, 0x0969bcbf, + 0xaa36874d, 0xfe5e90d7, 0xcf585cf5, 0x9ee12f52, 0x5a581a4a, 0x0e4773a6, + 0xb654aca5, 0x687a874a, 0xaebfc6d9, 0x33c533fb, 0x5eb06639, 0xdd2fdb4f, + 0x43c7f6f8, 0xa6bfbe40, 0xa6cb1d8b, 0x7de29261, 0xffa4a974, 0xe8f8e516, + 0xdbfaf250, 0xfb164b7a, 0x8fb460fe, 0xedafa51e, 0x40ac93d4, 0xeed4147c, + 0x414c7bd4, 0x3cdb52e8, 0x1e02648a, 0xdd03d27e, 0x9121debf, 0xf820f484, + 0xa476f55c, 0xe909e383, 0xa5e4e9c8, 0x5cfabd5b, 0x412bf4c9, 0x2bbe7527, + 0x0afa8cca, 0xca7a87b4, 0xf6ff1b1b, 0xf14fc526, 0xcc2b0627, 0xf76ff8bf, + 0x4e3cc245, 0x5f18ab69, 0xde34b0bf, 0xd62dfb46, 0x98cde339, 0x2fc5efb2, + 0x6df91afe, 0x8ebf87de, 0xd93fa827, 0x38b93492, 0xdf9824cf, 0xc4efe79c, + 0x0e25cdf9, 0x17e2bbe4, 0x9fe83b64, 0xf464b5e7, 0x45d6416b, 0x175b3441, + 0x15d356a7, 0x4a77e74d, 0xf38044cf, 0x8b5aeca0, 0x517bd287, 0x28dafc18, + 0x8402ffd6, 0x9d191bcf, 0xf86b45ba, 0xdf4ba2ba, 0x3cd75f9f, 0x39f404d2, + 0x004b6a9d, 0x6892af3d, 0xd21f1c9d, 0xfcaeda45, 0xa3026161, 0x8568b10f, + 0xa8f2a47c, 0xf943be00, 0x2c2d9d26, 0x5c8f515b, 0xbff5f74c, 0xc74ff790, + 0xd0f405dd, 0xf5c1f153, 0xa668caf2, 0x269fd327, 0x7e5fc7e2, 0xf7ad9beb, + 0xf5b28f35, 0xabbbd62d, 0x7fe43468, 0x1fad887b, 0x839c97a8, 0x602772e3, + 0x243bcefe, 0xe2060794, 0xd7aeb60e, 0x56baf8e8, 0xa13e0be6, 0xb9c2d6e3, + 0x842fcbc7, 0xf14e6f9d, 0x27dcc8f3, 0x7dbf3d68, 0x8bfa12be, 0xac4f6c0c, + 0xfd7c79db, 0xf7cd1cdf, 0xc9febe5d, 0xcf4171f3, 0x5b73eabf, 0xeeb5ce99, + 0xe95eb0cf, 0x605a74fa, 0x30eceabd, 0x761b33ef, 0x5d377c7d, 0xc56a6727, + 0x4fca553a, 0xde2d3af5, 0xa7f236fc, 0xa99e9d7a, 0xe83e3b7d, 0xeded7d3a, + 0xb0664f78, 0x2bbffa75, 0xe6fe053f, 0xa7e52b46, 0xf0a18790, 0x728796a8, + 0xa9f105b4, 0xe7f48796, 0xc8141910, 0x04ef827f, 0x5abc95bf, 0x1dc81d7e, + 0xbe0a5f2f, 0xe0a5f2f3, 0x957cf53b, 0x5be753f8, 0xf9472ce1, 0xf0edbec4, + 0xcf4a64a8, 0x6ac906b2, 0x3dbd60b0, 0xd93c5300, 0x35231b70, 0xfd63927b, + 0xae0a9761, 0xa9b79555, 0xbcaabb60, 0xa9570543, 0x5c70bbca, 0xf4bbf565, + 0x5b81e504, 0x10f75e51, 0x3d804671, 0xad7651a1, 0xa76ca8a6, 0xeb465e63, + 0x47486fb7, 0x12697b7d, 0xc474dbb3, 0xfc8197e9, 0x4477376a, 0x75fc5346, + 0xb373f184, 0xca3223bd, 0xdcd32ecf, 0xf5fca320, 0xdae8c8b8, 0xaa1af620, + 0x3cfd2249, 0x62fe5424, 0x4d90bf66, 0xef408b69, 0xa0ad91af, 0x3c5ecd0b, + 0xcef41229, 0xe31e86f6, 0x73efd327, 0x43baa1f6, 0x903db9da, 0x49b4039e, + 0x38b3fe94, 0xe710b63f, 0x7ce8c353, 0xa2943566, 0xa57b3e3e, 0x4d735e92, + 0x9ccf510b, 0x1efd04fb, 0xe12fdf44, 0xaf3f14ed, 0x2b212fcc, 0x1d289f91, + 0x297760f5, 0x77cca359, 0x2ecffb70, 0x48fde7c1, 0x87b9c53f, 0x3942d5cb, + 0xb064fc73, 0x0995ec57, 0x836749f0, 0xdcef788c, 0x9e08b920, 0xa83d986b, + 0x3ca07482, 0x8569f813, 0x2d0fa0f5, 0x7cb75a6f, 0x5a01e83a, 0xf1eb6ca4, + 0xda68e7ec, 0xaf58f5ba, 0x71bf00ed, 0x0938ed24, 0x08ed3fb2, 0x64dda1b3, + 0x00cb8447, 0x3f7c6ff4, 0xa3b401ed, 0xce30ac18, 0x67df1df6, 0x3fb4df03, + 0x79062864, 0xecca9ed5, 0xbf1a4b23, 0xe57266cf, 0x5b57a461, 0x37e99eb4, + 0x99fdff0d, 0x06fae704, 0xf7d82b3a, 0xf9e38477, 0x30cdf2ad, 0xbff6c117, + 0xfd30e41f, 0xd0a9f372, 0x61f20713, 0x19bc9904, 0x704517c6, 0x07db953e, + 0xed3175ff, 0xa76ebcbf, 0x2fcd167e, 0x6ca7eb78, 0x37db0fd8, 0x4da67d33, + 0x5dd2b847, 0xad1e68f2, 0x61c616d7, 0x056eefe7, 0x160db77d, 0x9e423747, + 0xab70d98e, 0x4f0c14d3, 0x5e21a53f, 0xd13f10ae, 0xfbe47a31, 0x48fc7d7f, + 0x2bf28236, 0x609465c2, 0x767e3fde, 0x0ec1e41c, 0x98a9f203, 0xc5da99ef, + 0x6e5c7fa8, 0xfe62fdde, 0x4ae2f85d, 0xafb92de7, 0x7ff6de64, 0xe21f7a71, + 0x5d7aa8fb, 0xe379f204, 0x8c6f08fd, 0xaf78e2b0, 0xfeabdf90, 0x337dd1af, + 0xe5e47ba5, 0x7fc7fde7, 0xa68779f1, 0x9ce9befb, 0xc3b066ee, 0x13f5be55, + 0xe56aef8e, 0x537fa6dc, 0xba7a17be, 0x3890befa, 0xf0a5a225, 0x744f0e70, + 0xd2e79e4a, 0xc388f77d, 0xd2113a79, 0xdd475048, 0xcad38f27, 0x2a4b24c3, + 0xde132828, 0x7a071dec, 0x8aa932cb, 0x4737eca8, 0x6476d3b7, 0x940c474d, + 0x2d0e242b, 0x217217bb, 0x3c91df1e, 0x15f9d768, 0xb4852db1, 0x9a8ed482, + 0x3bdd6902, 0x97b42547, 0x923f2184, 0x9e3df57a, 0x0d11f516, 0x1de8019d, + 0xce2b00a5, 0xbe9f5a77, 0x8bc20722, 0xa293d8e9, 0x313f7f2f, 0xcfccd63a, + 0x58bd1d7d, 0xc46fd33e, 0xfbe8727d, 0x66f8e55c, 0x4ba76699, 0xf36f41dd, + 0x8c15c71b, 0x291e0093, 0x3ca6de9e, 0x7bfaa463, 0xd1d1dc12, 0x618fecf1, + 0x72ef2df4, 0x141b63e2, 0xe694d01b, 0xa9563f7f, 0xec193627, 0xae0d5b24, + 0xad4fd0b5, 0x1b4ddef2, 0xa1dbcecb, 0xef13d0f1, 0x421e0453, 0x3efaabf1, + 0x1be80665, 0x667c6103, 0x74c6f8c5, 0x29631bb1, 0xf3d47a9c, 0xd5f1a495, + 0xd75b942f, 0x60fa073d, 0x2b7fd33d, 0xf57bb386, 0xda326d8a, 0x0c1ada0f, + 0xb18e892e, 0xde177eb8, 0x1b56b4c7, 0x9eb7dc09, 0xab48eba6, 0x55fe04bd, + 0x371c0df3, 0xcd67075b, 0xea86a746, 0xee5896d5, 0xb24d908f, 0x3fd31e61, + 0xcd31173c, 0x9ede7682, 0x5e76feb1, 0xab37fdef, 0xedcf9017, 0xedef54c0, + 0xcce2f20a, 0x65ef04fd, 0x6d23b689, 0x1cbf9642, 0x23a3ce50, 0xa9e3d186, + 0xb4167b68, 0xf294dcd7, 0x2857b414, 0x06e9ec37, 0xcec859f8, 0xc40c2359, + 0x64e94619, 0x56b5ef90, 0xde95c9f9, 0x9cf196bf, 0xfbc2e9fd, 0xfa6567a2, + 0x692dedda, 0x741eecec, 0xa5bf67f3, 0x988ef4ed, 0xd3daf78a, 0x93bcec0c, + 0xbbb87f7e, 0x6f5f5d07, 0xf81189e9, 0xeabdd74b, 0x4e70ade0, 0xabad928a, + 0x32b17f69, 0x217c0919, 0xce1b1bc6, 0xe7be23e6, 0x0246b0bd, 0x8fbe22f9, + 0x7fd1d258, 0xb1f54d01, 0xf8c53f8c, 0xf4741446, 0xf0f932af, 0xe7e466de, + 0xd716b319, 0xb4c3b093, 0xec0979c1, 0xeb0e7024, 0x3db7c84b, 0x5e1f786d, + 0x20ec4611, 0xdb35bef7, 0x7ce146ba, 0xb66f782c, 0xb7acacd0, 0x04fcd3f0, + 0xa0571f28, 0xe91787bc, 0xc76658ac, 0x4341fb29, 0xe2767e9c, 0x0f5bad32, + 0x1fb281f6, 0x77e9c4f4, 0x9d05fc0f, 0x5cefd3b7, 0x4f4b4f7e, 0x22cc27b4, + 0xcc27b456, 0x9c4e1e5a, 0x3aa2e77e, 0xbd350e3e, 0x56fa71cf, 0x96896944, + 0x2242abce, 0xdb954bf6, 0x9f764ffe, 0x23ff1eaf, 0x70e36eb0, 0x779fb87e, + 0xab5c1a34, 0x9dcb03d3, 0xb8f6618b, 0x3dc51bf4, 0xc5cf07bf, 0x25e5b70b, + 0x8aed2090, 0x1b07e2b4, 0xa5e1f971, 0x7983d682, 0x9230fc56, 0x6f07fab8, + 0x66f982cf, 0x81cede05, 0x5fe81a7c, 0x4df1163f, 0xb091c44f, 0x97a95e7e, + 0xf13d8347, 0xd19abd95, 0x678c83ab, 0x9f679f03, 0xf5f22d38, 0x5b626e8d, + 0xa29e8415, 0xdb347c5c, 0x459f0117, 0xa8788159, 0x074cf7cb, 0x2469b87e, + 0xefeb05b1, 0xc42f9c2f, 0x19a2ebb8, 0x18762b7e, 0xdb405ed0, 0x011455ed, + 0x71733ddf, 0x74959b3d, 0x8d863cfb, 0x4f36eea3, 0x76d3f41a, 0x083ff72b, + 0xe173df41, 0xe018f68e, 0x30b449c3, 0xda4187e5, 0xb7ecc92a, 0xbe94ae3e, + 0xd6ac3f15, 0x102bd3f9, 0xae74ebef, 0xc576befe, 0x22f3643d, 0xe6def519, + 0x95fefc83, 0x62eee3db, 0x499a4cac, 0x97b02ed5, 0x68495734, 0x41dbbbc7, + 0xdeba22c8, 0x14b87aef, 0x97d34ded, 0x8234bebe, 0xca907f7f, 0x0912bb8d, + 0x77a699b9, 0x09da56cf, 0xb70596a6, 0x3f7839a7, 0xfa0748d3, 0xa85f4cf9, + 0xfb702fb2, 0xe541e383, 0x17e02ff7, 0xc60fd72a, 0x0e43bb72, 0xbd7901c9, + 0x3d39e960, 0xf8a109a8, 0xc3ca85ba, 0x8b905a9e, 0xab5b4c46, 0x157e98cd, + 0xf604fb6b, 0x8eb1f3a5, 0xb6ee414f, 0x52e4c87f, 0x4c73cae7, 0x418f2f9e, + 0x2ef2c73b, 0xd78dff6c, 0xd3ea3b58, 0x3e3efe41, 0x8fc51c71, 0xeb5a2fe1, + 0x9b878a12, 0xc0d3353c, 0x35e84525, 0x905aac8f, 0x127e8b11, 0xefc041d6, + 0x32deafb1, 0x7133ec1a, 0x00db86af, 0x5cf22b7f, 0x62b18f78, 0xe7f41771, + 0x0fcdd232, 0x0d8f7ae4, 0x3fb81a79, 0xb16ea1bd, 0xd76d1ba6, 0x0dd3b0dc, + 0x35cb0efe, 0x6b3da0df, 0xf984cdf9, 0x287ef17f, 0x6919fb3e, 0x4c13f13b, + 0x171d2f78, 0x50d44aee, 0xbd46ee38, 0x17ea0975, 0xe0a95f4c, 0x2c976834, + 0x7e0a1c7f, 0x8264fb64, 0x16b13e7e, 0x087daf94, 0x0b92bfb3, 0x0f945f14, + 0x8fc40c60, 0x2dab5aef, 0x92fc9f68, 0xd0fb29db, 0xce8ea1f3, 0x4f8a2be7, + 0x6a1ecb80, 0xebe3051a, 0xabac48d8, 0xb7d89169, 0x912df292, 0xea337780, + 0x13aba7bb, 0x16e31531, 0x6bd947fb, 0x3f41a36b, 0x9999229e, 0x43d7095f, + 0x10121f05, 0x4c9e1456, 0x8bbf9c98, 0xa8539feb, 0xe3a30dd8, 0xd35887bd, + 0x46dddea0, 0xf8a1a912, 0x3b50529f, 0x5299f710, 0xe7ec145d, 0xe30542a0, + 0x8bfa5087, 0x72ea2758, 0x81af41a7, 0xc98db8f5, 0x11758a83, 0x6bbbb44e, + 0xecffb03a, 0x7b1ebe38, 0xd22e3f31, 0xfd60d893, 0xbde8ec54, 0xa062e80a, + 0xa5e303fc, 0x9b98ca72, 0xd19cfa83, 0x7f3fe748, 0x8a5b987b, 0xd9a7a3f4, + 0xfa034fd6, 0x1c9484fc, 0x4a3a97f4, 0xd80447e5, 0xb8693c71, 0xeb47419e, + 0x7d5cc306, 0x54ebdc1b, 0xfb30dc50, 0xee0ccbce, 0x2d6761c6, 0x7978d383, + 0x777066e2, 0xdbddff51, 0xc743fec0, 0x621fcbcb, 0x1f011f70, 0x45b3e566, + 0xce0c63f9, 0x1927f911, 0x7fb4483c, 0x1843c18a, 0xd3c9fc7c, 0x0f4139b7, + 0x8ffae289, 0xaee783d5, 0x6b7b378a, 0xde96fdfc, 0xf3726389, 0x772b1874, + 0x98cc9d3a, 0x08cbf400, 0x5e55fe5e, 0x02c5e85e, 0x493ea27f, 0x266f5e0c, + 0x80bf37af, 0x64e129eb, 0x5bf31879, 0xba524675, 0xbde86eee, 0xc617ca1a, + 0xd03a7345, 0xdaf80676, 0xed11f411, 0x244b7e89, 0xe9b497a6, 0xbbd89d98, + 0xfdb1c66f, 0x30f3f684, 0xd293d3f6, 0x909bda15, 0x81f80fd2, 0xf39681f2, + 0x80f81681, 0x7c6c5590, 0xc028ddb4, 0x3fa3b9b9, 0xbeedbff8, 0xfba7cb40, + 0xcbe6adc6, 0xcddf3807, 0x81cec25f, 0x703d511d, 0xce1118bf, 0x403244f4, + 0x380f8f39, 0x8b89de1e, 0xd2f4f362, 0x7ec24125, 0xa63c7096, 0xc84d7a78, + 0xff79faba, 0x97e78f9e, 0xbd1fb79e, 0xd7e4326c, 0xcd9ab0df, 0xd60bd187, + 0x85ea3447, 0x3bda2b8f, 0x3f5558bd, 0x98702e97, 0xac0f746f, 0x311848ff, + 0xdab277e2, 0x9b3d2f5b, 0xc7a0abe9, 0x27ca2f96, 0x74ff6127, 0x85f78cde, + 0x952a5c65, 0xe3d26f2f, 0x64ad6bfd, 0xef3cbf43, 0xe00ec73c, 0x79f334f3, + 0x5d3cd99a, 0x87257e0a, 0x88eed23a, 0x2f63e408, 0x65edbdfe, 0x14f6f0e6, + 0x7b582372, 0xd1422720, 0xd34bfdc5, 0x85538c45, 0x559e2f4f, 0x84f813e3, + 0x32f58df5, 0xc6297c95, 0xf5a87af9, 0xfb33fe9d, 0xcaf563cb, 0x08e9437f, + 0xc945a7fa, 0xe975e5d7, 0x7d327b9a, 0xae8036f5, 0xf3f3e717, 0xfdc71939, + 0x0a485286, 0x7cce0fec, 0xfec37562, 0xfb80d9b9, 0xfd92e7fe, 0x505c5c54, + 0xaefc20ff, 0x47b6173e, 0x1bec09e9, 0x7b40fb6a, 0x06c9b59c, 0x0967e5f7, + 0x550edffa, 0x6fc033d9, 0x57c9b373, 0x295fb7cf, 0x4cf111e1, 0xc3b40cbf, + 0xe68a7dd0, 0xb868300f, 0x018dd73c, 0x5c203d79, 0xf0d57705, 0xe0c8c4fd, + 0x293b0e04, 0x2034f14c, 0x3187e459, 0x3f513af8, 0x51bf958c, 0x5f70e794, + 0xa208fe55, 0xfdb28784, 0xb0a9e624, 0x20ff7031, 0x78d8a0f4, 0x2e43ce0b, + 0x4be010d0, 0x80d53803, 0xc196f5be, 0xa08d7a05, 0xce94a853, 0x3dd82ab3, + 0xf0bc6a7e, 0x977e6033, 0xbb40f2e8, 0x047615ca, 0x4761568f, 0x3a348f68, + 0xc768aee5, 0xadf605eb, 0xf747788c, 0x32bf5a78, 0x3a7a75bc, 0xff0a1f85, + 0x256cfd0c, 0x258fd31b, 0xa54c998b, 0x575a95e3, 0x23df41d8, 0x16a35625, + 0x4aedc4e9, 0xe94bf770, 0xcbc77db1, 0x6eb3240f, 0xc18e30ec, 0xee54ae5c, + 0xe3bbf1f8, 0x369fffb0, 0x7dfae159, 0xf7b3c370, 0xb838be81, 0x4c8fff61, + 0x5fa1304f, 0x60f718ac, 0xdfa29bf0, 0x380deb73, 0x370dc1fe, 0x43f281cc, + 0x01e86a3f, 0x84fc377c, 0x9988097b, 0x9237c6f6, 0xb91f281d, 0x25392c9f, + 0xd5c19c41, 0x7c5e45ea, 0x7e8f43fc, 0x231f141e, 0xcc2e3e19, 0xc5b4fc05, + 0x41e65c1d, 0x8b0a62a3, 0xe9f5e067, 0xb9fd03b9, 0x2b17493b, 0x23db5dd8, + 0x3b6a3b58, 0x3a22d1e4, 0x787dfa3f, 0x9f811d07, 0x07e23fde, 0x3e4c1523, + 0x29448f38, 0x926302e0, 0x39a17ca2, 0x4b7f915d, 0xfc8a0de2, 0x14fd2d5b, + 0xc18c98f0, 0x5bb7f28a, 0xf8f014f3, 0xe5155bdc, 0x0a456c8b, 0x56bb9fb8, + 0xdeffbe51, 0x21fe657a, 0x721d0322, 0x41775a8e, 0x1b4bf03a, 0xb507359a, + 0x7482ed54, 0x1d0cb7f0, 0x90ec3b6a, 0xc1776a1f, 0x15876177, 0xce30f0fa, + 0x3b2ec22f, 0xf4b93649, 0x89afedc1, 0x959e9a5a, 0x649f283c, 0xafed1d8d, + 0x078e61c9, 0x473d29e2, 0x2814aa91, 0xb0ec0237, 0x33850894, 0xfc01fece, + 0x32a73aad, 0x2051dc7b, 0xbbbbc80c, 0x788ed022, 0xf1b55754, 0xce43ea38, + 0xc3a39054, 0xe62b263b, 0x8707e23d, 0x6479de62, 0xf74e8abe, 0xf342e02a, + 0x6fe5146f, 0xc8ac5c49, 0xa8f2d5bf, 0x2b8f4e8a, 0xcfaddbe0, 0x4ab4e8aa, + 0x1597a745, 0x1bbf82f9, 0x076c7db8, 0x3a68b5d8, 0x0054d3cc, 0xa5b9b874, + 0xdb91e903, 0x74005354, 0x16b4721a, 0x6dc035e9, 0x3bf1002f, 0x2ed56f68, + 0x5cf4dd48, 0x4efef503, 0xee9035cf, 0xb023e7a6, 0xcea9ed8f, 0xb56f74c0, + 0x5bbfbf15, 0x7be98b9d, 0x3f4c36d5, 0x698d1ea8, 0xd31db553, 0x2c5aeada, + 0x9ebab9bf, 0xf862d7d9, 0x0bf1473e, 0x38368c76, 0x9cbca253, 0x0db2f28a, + 0x5f2850ce, 0x177066ef, 0x0c29930e, 0xebe5648e, 0xf2829a9f, 0x8cf83f74, + 0x30bf81c4, 0xd824cf4b, 0xdd3409ec, 0x8186e70b, 0x5a89b8be, 0xe4a7688d, + 0xb1eb9031, 0x525fbc31, 0x4296c632, 0x5ec5d2c8, 0xc18431f8, 0x2307eb28, + 0x1bc1f8b3, 0xe21b6b61, 0xc61edfab, 0x97c6f7f2, 0x4173818c, 0xf330fae9, + 0x29747e97, 0xc0528daf, 0xe649f595, 0x88e8fd2f, 0x7654c97e, 0xe5091492, + 0x36c3d09f, 0x20438e48, 0x1e8dca7f, 0x1aa627f4, 0x6c2bfa30, 0x8044b16c, + 0x85e0ea5d, 0xcf8011de, 0x672edc83, 0x3374fd23, 0xeda79a69, 0xff7d83a7, + 0x124f4aa8, 0xef2941e9, 0x56b76853, 0xf413bd63, 0x3a6de724, 0x413ffc02, + 0x51007662, 0xa604ddee, 0x6edfb4af, 0x21e0f3c0, 0xc60e6d8d, 0x9f024811, + 0x149f718b, 0x11c2f7f3, 0x7489df22, 0xf9128f6b, 0xe5538e1c, 0x1d60a927, + 0x5f19df2b, 0x05fe748d, 0x904ff9f1, 0xca7c6a0b, 0x97a66609, 0xa0a96db9, + 0x50f808c7, 0xe41cad91, 0xdb3ca1c7, 0x83ef30f5, 0x17930376, 0xf5d708f6, + 0x0db33768, 0xfecfd3bc, 0xc3a09d55, 0x1f00777a, 0xddc4fdc3, 0x3515ca32, + 0x604a5ffe, 0x15f22afa, 0x0aefbb9c, 0x21cd73c7, 0x1cde290d, 0x387b5e84, + 0x0974ce1d, 0x277df76e, 0xf9fbed81, 0x6e37cb13, 0x85cf7b81, 0xbb74d861, + 0x93ea37bd, 0xf31255ed, 0x3aa96903, 0x560df2cb, 0x33f4128e, 0xd1bf029f, + 0xf70d8dfc, 0xcb4c3f9d, 0xdc30b67f, 0xb9967b8a, 0x6eefe20f, 0x8c5a785e, + 0x69bff511, 0x61f35213, 0xfdc29e1f, 0x6847a79a, 0x59bdd1e3, 0xd337a51b, + 0xfa9b6676, 0x2418a32d, 0xf48b6373, 0x4e2e1451, 0xa41977b9, 0xd71f3d25, + 0x595dd5c3, 0x40cb6be6, 0x22a72f0d, 0x5bca2063, 0x74d5fbcf, 0xc916335c, + 0xe51e7616, 0xf4adb8fb, 0x045de2aa, 0xf1e21fbf, 0x78091447, 0xf1cbdede, + 0xe5edea2d, 0xe0482af8, 0x245922f7, 0xb8aca2eb, 0x0125b8f7, 0xbda63dee, + 0xbdc42bdf, 0xeb9f3288, 0x59eb1fbf, 0x75eba5bf, 0xb9104f2e, 0x9d812fbc, + 0x89e90f9b, 0x9d55ee0d, 0x277db377, 0x87b9f27b, 0x67f9d206, 0xe8359837, + 0x7ca33457, 0xb3a1d00b, 0x4751d39e, 0x4dfd61ea, 0xecfcce74, 0x96261230, + 0x5e1fc7f8, 0x36b67f6e, 0xf7fc0b99, 0x7b1e01e7, 0x9cfeff81, 0x005351db, + 0x8fd8b0fb, 0xbba83dc5, 0x03ef98ba, 0x77bf2855, 0x78422f57, 0xd313b54f, + 0xf9cbd5bd, 0xf983503e, 0xc33f55ef, 0xdf1701f7, 0xf7e3d607, 0x98c9ea86, + 0x6076a8ee, 0xbd8ba63a, 0x1df4e402, 0x47c60746, 0x81acfdbe, 0x675e7dc0, + 0x47e30183, 0xf1788ae8, 0x538858b9, 0x58579832, 0xd495e302, 0x1f978afb, + 0xb3fb7e54, 0x0b7ed8bb, 0x99e378fd, 0x2ebd3f40, 0x241d3f34, 0xdf390e5c, + 0xd0743945, 0x07d6e42c, 0x7808b60c, 0xa2ad833f, 0xf72807fc, 0xbe78da0e, + 0xed833f73, 0x601c9f3c, 0xefc043b0, 0x944ab831, 0x73dac03f, 0x063df80a, + 0x4df288d7, 0x7831760c, 0xa21fd3ed, 0xd223cc5c, 0x056f586e, 0x2091f4c6, + 0x79cd0b62, 0xdd9d61bb, 0x24733892, 0x826333ac, 0x56fcf905, 0x00dde2cb, + 0xa558c98f, 0xcdba1305, 0xa861efd4, 0xa45b1f97, 0x53237a85, 0xea187dee, + 0xb8f9ea8d, 0xe8debfd6, 0x061ed7cc, 0x9575ac78, 0x236bf416, 0xbe81c5c8, + 0xf22c0476, 0xe2213ec5, 0xd836faf0, 0xaeca3f71, 0x247ee3b7, 0x477f9cf0, + 0x9c3352d1, 0xb325ea03, 0x43b8e304, 0x404f06f2, 0x05c5630c, 0x1e291aba, + 0xe13c12ea, 0x2b3ce98b, 0xf0821e01, 0xd97f8b63, 0x109dd5fd, 0xc2383f64, + 0x2be807e5, 0x23ffb445, 0x3f835d74, 0x4bc70442, 0x88ccc365, 0x755e7899, + 0x189e8044, 0x0490f5c3, 0x2dfe6948, 0xbfcb1d3c, 0xef6c941f, 0x30f8bc82, + 0x03b79f81, 0x1861cde5, 0x73279507, 0xe40238d9, 0xcb9f328d, 0xdf62239b, + 0xb2e2c01a, 0x8b0d49cb, 0x7c4cbee7, 0xb8dc405f, 0x84a71e2a, 0xa5b1eed4, + 0x6f178b07, 0x2e2f1a0a, 0xfd031bfc, 0xb0b9f96d, 0x93cf930b, 0xc3d17641, + 0xb9686760, 0xab971dfb, 0xcca0f0a1, 0xe0e285ff, 0xf90e2389, 0xbc3c5423, + 0xf9c08be0, 0xb6f3b0d5, 0xea9fe196, 0x81c4c69f, 0x8823bf20, 0x6794ab1c, + 0xcf212f87, 0x97f1f2d4, 0x6693bb92, 0xfdc1a794, 0x98b91043, 0xcb54e30a, + 0xc93e6745, 0x7505fb80, 0x0a68f42a, 0xd3de213b, 0xed0c23b9, 0x8e31f514, + 0x0fd0448c, 0x83be3bf3, 0xeb122d78, 0x371c3c41, 0xf6846e39, 0xbff33d25, + 0x2dcdf110, 0x753f7d5e, 0x7923c62c, 0xfb0a7bf5, 0x9efdf7e9, 0xf20b1d49, + 0xdec9bbad, 0x1921da1f, 0xc85d1fcc, 0xbef1508f, 0x3ed91343, 0xff92981f, + 0x8e5838b7, 0xae7a369f, 0xf4e74dda, 0x62bf86ce, 0x57d9ccdc, 0x56c1c79a, + 0x265dba5c, 0xb68f8a46, 0x0dc4110d, 0xe52d1be7, 0xd4969a3f, 0x2b8c36c9, + 0x4d07bad2, 0x5bd7f08c, 0xe974ff98, 0xcadc08a6, 0x5c1b364b, 0x92fd6963, + 0xd1b327ad, 0x0ea1f5af, 0xbe730fbc, 0x22d75922, 0x13d93cfa, 0x1b594fc1, + 0x353e4edc, 0xad87e991, 0x8327c2db, 0xbf5a56bd, 0x25deed13, 0x707493b5, + 0x4dca2a0f, 0x3e21d44c, 0xa7b43968, 0xb8965f3b, 0xe41eeb1e, 0xfc2caf7f, + 0x665f5bb7, 0x7a92a976, 0xc60c2b9d, 0x36b5feb7, 0x3929c788, 0x4dfb406a, + 0xf46ffae5, 0x4d82c740, 0x1f01231b, 0xd932f595, 0x550fbcad, 0x97ac41c6, + 0xe3f006dd, 0x7f472baf, 0x23370a6e, 0x1e3c1b5c, 0xfafe72e8, 0xb71a9ba5, + 0x4b0a293a, 0x12297f5f, 0x374e29e2, 0xbc048dad, 0x192f76d3, 0xf7101487, + 0x25e8fb50, 0x134e1ee3, 0x134b03c6, 0xeb237155, 0xcb71b863, 0x3fdfc83d, + 0x274787c9, 0xf3c6f3a3, 0x5e5c422f, 0x2f33e6eb, 0xfecb78c2, 0xf045ee79, + 0xc23b26cf, 0xad0f60cc, 0xc630e57c, 0x7f7a8935, 0x627a6449, 0xe12fcbdb, + 0x31db6a3d, 0x35b7afa6, 0x6dbe429e, 0x78c7ed7b, 0xd85af388, 0x0efe8858, + 0x2414b70b, 0x02e72090, 0xbadf0291, 0x4d1e20ae, 0x755daf4d, 0xfc8fd0bb, + 0xe837a52c, 0x9638dea1, 0x171672da, 0x2bf1e164, 0xfdc7821b, 0xd4abc405, + 0x1c3f1c4d, 0x3a75e2ec, 0x415c85ab, 0x4a21cadc, 0x4057bec7, 0x728f0dbf, + 0xf4e0fe7f, 0x50bf0b3b, 0x2a26353a, 0xd7ce56e3, 0x9fcbf9cd, 0x262eaf21, + 0xfb8adc64, 0xe226f00a, 0xda24570a, 0x6c3c82f6, 0xc62afcdd, 0xc6dd0109, + 0x6db689d2, 0xf1069f3c, 0x8eba2d98, 0xc1efdce9, 0x25acf70c, 0xfd70478d, + 0x10f96db4, 0x8f08f6e3, 0xde236bef, 0x258f161f, 0x89ae79f1, 0x1c2ef160, + 0x030f10ff, 0x3bf4d0f7, 0x7c617b8f, 0x4261e22c, 0x4c5cc1c5, 0x2df6ceec, + 0xbe58ef1e, 0x2b8f38e6, 0xca4bd1f1, 0x5f353a05, 0xe048be32, 0xb8780cc1, + 0x2bae3fc9, 0x3791bc78, 0x0bd38ffe, 0x5cf107e8, 0x0a2db8de, 0x3a58430f, + 0x83c88242, 0x1e2c55b6, 0xe3ff7d4c, 0x3843cfa3, 0xd152ffaf, 0xf433cc59, + 0xd3ad9239, 0x6aff8dcb, 0xd12673f1, 0x127388a2, 0x10bd6a78, 0x26a78e5c, + 0x67eafdb1, 0x00b6b7eb, 0x092536fd, 0x66badbf4, 0xe62b7e85, 0x05754adb, + 0xafadef90, 0x960c77b0, 0x3942eed5, 0x141796ae, 0xf760b62f, 0x98937d0d, + 0x67a8aa9c, 0xe6eb44fb, 0xb6899708, 0x6df7fad3, 0x1b15cfc8, 0x8fb0f59a, + 0xbaff59ef, 0xb317f99e, 0x84fb03f5, 0xadfc6fcb, 0x8d99db7f, 0x09fa1b72, + 0xbce1d742, 0xe086ca9f, 0xf86e54fd, 0xa94fd146, 0xfccf56b3, 0xdfdd2e8d, + 0x126dad69, 0x49ba77b4, 0x7269a607, 0x6df996ba, 0x24b7fba9, 0x4abdf8e9, + 0xa8f7d70d, 0xc83f47bc, 0x9c271e61, 0x51c3735b, 0xc5e6b63e, 0x35a45da3, + 0x6965af55, 0x7fff842f, 0x935bfbdb, 0xbfac8d72, 0x371f1851, 0xd6e8c62e, + 0x8073f5d0, 0xaf513fbf, 0x00fff677, 0x8707cfee, 0x78e3dfa1, 0x4dbefcc9, + 0x6827bc0a, 0xdf3537dd, 0x5f781d92, 0x91912ad0, 0x65279512, 0xf0a59acd, + 0x0fef6aed, 0x477d16ca, 0xa19d1de0, 0x78102e8b, 0xefeae7df, 0xb3a29a13, + 0x70b7602d, 0xfa6d812c, 0x829ad6a6, 0x597216ae, 0x0edcef3f, 0x67b012d7, + 0xdec0b88c, 0xba4a18b7, 0x4daae158, 0xfccfddca, 0xbeaa79be, 0x31ae9877, + 0x83ddf4b9, 0xe7909fbc, 0xdc82481e, 0x867b8837, 0x8ac730e4, 0xf71081a4, + 0xc01beecf, 0xe4f915f3, 0x3fa6c7b7, 0x3081e780, 0xe71573f4, 0x27f58d99, + 0x9fac60e3, 0xb93dc537, 0x34af7e9d, 0x79f8877f, 0x8f9f8932, 0xf28ac4ac, + 0xf50f7e4b, 0xfb25cff8, 0xfb8a49b3, 0x08b9ef58, 0x63efabbf, 0x8cee7f85, + 0xec276597, 0x0dbf85a3, 0xc608781b, 0x03961751, 0xc31fd8e3, 0x980641fd, + 0xf1401f6f, 0xf5cb7673, 0x5b3fe039, 0x9eefb5e4, 0x88bcbd47, 0x338963db, + 0xafd876f3, 0xd7bd848a, 0xdcf961e9, 0xd9febbde, 0x3ac3b7de, 0xa1c1fe14, + 0xa2c56de4, 0x421f9137, 0xda12cbe6, 0xa6e4c939, 0xbd3f22b4, 0x072e4df9, + 0x397efdc4, 0xa78b0bf7, 0xf68dc8d3, 0xbc5791f9, 0xba46e611, 0xcec4d97e, + 0xe976dbc5, 0x09af1d99, 0xa78f21cf, 0x7c02de3a, 0x81da2c55, 0x762626f8, + 0x6c96396e, 0x1d31fee6, 0x0eae5099, 0x6eb027ce, 0x7da184b6, 0xd1eb4136, + 0x2ab8e95b, 0x8bf4128e, 0x33c7c638, 0xd40be9a8, 0x70e6bff7, 0x37e67ad7, + 0xd7c3c6a1, 0xf1aa1149, 0xc60c37bf, 0x2231f02f, 0xfdc2d49c, 0x958f9d30, + 0x98aac7cf, 0x814fd78f, 0x6ff74bd6, 0xebf0a2d7, 0x5b2af312, 0xdffc49d4, + 0x1c5d6ad3, 0xe311df7c, 0x97dbdf56, 0x840f7698, 0x2ae4a37d, 0x02a7fafd, + 0x3e01c46f, 0x871eaa59, 0x7ee32d3a, 0x17efea1d, 0xf67dc492, 0x7fae3b2f, + 0x69bd7bb7, 0xf9153b55, 0xbbed1633, 0x713f7ba2, 0x75bff71f, 0xdeea17ff, + 0xf66ec1ef, 0x8e946ecc, 0x29fcdfe3, 0x9df108f3, 0x1105eddb, 0xbe51c718, + 0xc8156135, 0x7e470fe5, 0xc2f60f14, 0xf71231fd, 0x1cb4bde7, 0xf7bb52b9, + 0x717bd567, 0x393f625c, 0x5846ed51, 0x3a9f076d, 0xa7bc31e2, 0xdb2dfc1e, + 0xb05e8637, 0xf2c9b91d, 0xc231edf3, 0x32ec230e, 0xd4cf3b6a, 0xefe4666e, + 0xec29bfe9, 0x9417fcca, 0xac472e7c, 0xffdc83d1, 0x17ee7cb9, 0xd65d3347, + 0xe2877b40, 0xce89bda1, 0xb0475ee6, 0xc23de51d, 0x7b8e2e98, 0x73134e80, + 0x88863f99, 0x5b942a5b, 0x7a049c9f, 0xfb8c934e, 0x7ddfc2d7, 0x2ce7b7f4, + 0x34a8f481, 0x131ca277, 0x5eeb1774, 0x86a543f0, 0x14e7b1f9, 0x097fd058, + 0x57d811e4, 0x0d34746b, 0x299ee742, 0x3c600bf9, 0x0e3afded, 0x8abf024f, + 0x669dff2d, 0x09aebd41, 0xb39779cf, 0xbffd80df, 0xd73b105b, 0xe8393cb2, + 0x298977fb, 0x6aceff4c, 0xbbfbb0d6, 0x7aeb92f9, 0x347973b0, 0x39acaa88, + 0xe0192ee9, 0x559f963a, 0x2892e51e, 0x8c38359c, 0x851bdfe5, 0x88d3df71, + 0xf3fb0747, 0xa60af00c, 0xc1624ce9, 0xf1b11674, 0xba3ae5f7, 0x9cfeb44b, + 0x83f32306, 0x309e9e25, 0xfa10ec9f, 0xcc6eceef, 0x3bb7d3be, 0xf37ddf93, + 0x19fc7295, 0x726eff9e, 0xef9849fe, 0x67b66ee9, 0xdd1bed21, 0x704fe2b4, + 0x21a2dcde, 0x1a9df7a0, 0x9bb41bfc, 0x24df7a8a, 0x8dd8bfe7, 0x3124dbd6, + 0x23674aff, 0x1d22a78f, 0xb6f6fef1, 0xd60b93d7, 0x02af7b40, 0xae3c815f, + 0x29be462d, 0x935c3332, 0x457cec91, 0xca5da5eb, 0xf857d20e, 0x5c87c2f7, + 0x86e117ec, 0xfdba4f3f, 0xbeef3a61, 0x073dfa1a, 0x02d8e5c6, 0xf74beae3, + 0xff8c1373, 0x40a71e05, 0xdee0d2aa, 0x068bde6c, 0xc79bec0d, 0xbf03bca8, + 0xa7e0e3eb, 0xb94fd34d, 0xdce7f63f, 0xfc19bb1f, 0x927a69ba, 0xe7482dca, + 0x842560fc, 0x64c8e7f2, 0x95f2235b, 0x883bf82e, 0x21e726ef, 0xb4ebb31e, + 0xd7678fb8, 0xfae7227b, 0x377f65d1, 0xb59a1f16, 0x5848cbe5, 0xef666d4f, + 0xed126cbc, 0x73b71c6a, 0x0736efee, 0xb26ef5e7, 0xe7cc24ed, 0x01c764f5, + 0xa3feb76c, 0x753f04ff, 0x7fde3eda, 0x4f1d4bb4, 0xf102950d, 0xa37f9dea, + 0xe39fcd9e, 0xd3545379, 0x69bfa80a, 0x2cc0774b, 0x2c7ee2c9, 0x0527e804, + 0xe7b33fc3, 0x0c74378d, 0xf8d17380, 0xff50728b, 0x3fef3131, 0xf38b3a0a, + 0x286ba70e, 0xcf9287ba, 0x80cc78de, 0x442e1377, 0xe22f5c82, 0xbafa9376, + 0x6fd0079e, 0xe04caf7f, 0x27ca23dd, 0x498efe0a, 0x48807a66, 0xf8f51ab3, + 0xc6a6cf5e, 0x36ce7aaf, 0xce7a1d21, 0xe4e5e5a1, 0x507a15eb, 0xff1fe0d6, + 0x2c58a7fc, 0x92412f0f, 0x42aac8bb, 0x629af7b8, 0x4c36f9dc, 0xb9b99a61, + 0x66bdee10, 0x207b4a24, 0x1f49699d, 0xe25df705, 0x232b38dc, 0xecb00f6f, + 0xca116b58, 0xc4583ce1, 0x814bfb7e, 0x1eee1c31, 0x39a170bc, 0x92df0146, + 0x7f28ac98, 0x2287a5ab, 0x8dc64c7f, 0x9faf7c8a, 0xefbfb5bc, 0x47c0777b, + 0xc3b07747, 0x9ca079d3, 0xb4656b21, 0x396d66db, 0x148ddb74, 0x4eeeb71e, + 0x9b036c2b, 0xcdb8fe78, 0x4fd82e05, 0xb00a5de1, 0x3ee4b463, 0xa09fd4fa, + 0x5f7b2d31, 0x74611e63, 0xebfc6b28, 0x799b6028, 0x3da1e6c3, 0x8c9de036, + 0xd5dfc135, 0x52c1f610, 0x65e9ecc2, 0xbbf6d41b, 0x550ecc95, 0xe54faca7, + 0x3c827fd1, 0x0ef5bbea, 0x6e97f833, 0x3763fc1a, 0x64d6e790, 0x284bbc65, + 0xbff2f17e, 0x1fe03964, 0x17e6a1e7, 0xe9120761, 0x6e2c83b8, 0xc5e56ae1, + 0xf85e403f, 0xe57917c5, 0x31fb9e98, 0xc41278f1, 0x3f1f0f47, 0x628e4b4f, + 0x5aaf67e5, 0xd0b8ef0a, 0x13c4277c, 0x4b9db291, 0x85efaec1, 0xf32b3617, + 0x2996941f, 0x95d387e0, 0x65bccaf0, 0xad43f5fe, 0x66fa8abb, 0xefca83bd, + 0x39d8278a, 0x639f7024, 0x992ee8eb, 0x6fdb0554, 0x4a31fe44, 0x7853f40b, + 0xc70bed83, 0xfef47aba, 0xc96527fe, 0xbb3b4f4c, 0x7ddff1ed, 0x6de27607, + 0xce46fd04, 0x5cfb3146, 0x8d29dd76, 0x177ae406, 0xb36caf86, 0xec7e0347, + 0x4ee1c5ed, 0x9cac83f0, 0x24fe811f, 0x866ce17d, 0xbfedc9e7, 0x7843d1b7, + 0xbf09efe5, 0x03ff0f57, 0xd13f379c, 0x46fb1468, 0xff9589bb, 0x6cede48f, + 0xeb67c8df, 0x83d03a63, 0x974261cb, 0xe252e566, 0xeeb0cb95, 0xbf003e60, + 0xf78edcf6, 0xd37b009f, 0x5a3eb63e, 0x29e3fb89, 0x4cd8bfb8, 0x95a3ebfe, + 0x7e77b2d4, 0x427dec2d, 0x7218bf71, 0xd1aeecbd, 0xbf8dfbc3, 0x2279baf4, + 0x843bdf99, 0xc7071f5e, 0xdca93e50, 0x3b1afcc6, 0x4aefae1b, 0x804bd6fc, + 0x068cf69e, 0x6dc05af9, 0x3bfdfc0d, 0xd8a17c55, 0x17b58837, 0xf78b13fa, + 0x3ae80f3e, 0x541fa026, 0xc6fd16a3, 0x092ce816, 0x6fea9751, 0xfc5886b9, + 0x68dbebfa, 0xe62df940, 0x73666ed1, 0x3e78dbed, 0x8171de1a, 0xc3ea3174, + 0x87fd8a35, 0x58ba73ee, 0xec455810, 0x6370ec5e, 0xe1d03e42, 0x199c44b0, + 0x309a9839, 0x35fb9bce, 0x27fc244d, 0xffeb4331, 0x6fd0b6ae, 0xf3bc6cef, + 0x3e87d07a, 0xcee7bbae, 0x24fbf401, 0xe29b9778, 0xfb7740f7, 0x81df9834, + 0x73f4255f, 0xfa91fc2a, 0x77f7acfc, 0xf307e50b, 0x65dd80c6, 0xfe83312a, + 0xfa665e3c, 0xad8b7916, 0x2a37212b, 0xe868a6a5, 0x09e4f5ff, 0xbce99287, + 0x01fd1613, 0x3df569f5, 0x5bea95f3, 0x26b0f285, 0xebede81b, 0x6e7f1625, + 0x31577c65, 0x9393ccec, 0x7d508e40, 0xf28ff41e, 0x1ef89dfa, 0xe6dcfa81, + 0xe7d5abd5, 0xf38dabef, 0xedcbd00f, 0x7071c96d, 0x7877388e, 0xcfd40912, + 0xcd56f27d, 0x021f5477, 0xdc36b479, 0xa6aef8c5, 0x6fce94ad, 0xb364dac1, + 0xf6e78a13, 0xa2d6f162, 0xdba7f0fc, 0xcbf3437e, 0x83370a5e, 0x9d30bdda, + 0x818de138, 0xa37aab85, 0xdeafbbbd, 0xd006eaf2, 0xa1d65eaf, 0xe06bf45d, + 0xbd7f0a1d, 0xd81706f9, 0x2c69e783, 0x8cf7847f, 0xf9193ac9, 0x060bd4ed, + 0x1fe75fdc, 0x2bfb81e9, 0xa50b23ac, 0x4254a9cf, 0xfcdeb4cc, 0x5db193d7, + 0xaf7625f9, 0x02537f3b, 0xfa0aa1c6, 0x8610bcb6, 0xd9c591f1, 0xf4dcbdb5, + 0x47449edb, 0xbc1c4a54, 0x975ae7ff, 0xf054f144, 0xc01f4fd2, 0x537f36be, + 0x47cbd21c, 0x61fbe0e7, 0xb60f4367, 0x84be39ce, 0xef05fedc, 0x0653120f, + 0x87895f82, 0xeece77bf, 0x7db8720f, 0xd977cd4e, 0x7e32ffbc, 0xd840c3ce, + 0x67cff058, 0xdca24cf1, 0x628d14a8, 0x4f942d3f, 0x3e076c54, 0xf9e037ad, + 0xb82c35b2, 0x0a486a9d, 0x8c2b57db, 0x49ec2adf, 0x507e8b15, 0x322b13d8, + 0xe7bbde09, 0xbff4b12c, 0x71f7a697, 0xd9c4a7fc, 0x4a7cc387, 0xfadf1f6a, + 0xf9f1e21e, 0x7e813ffb, 0x3bd89af7, 0x7c31ef6f, 0x6f02ff0b, 0xbe0ec67b, + 0xf429570e, 0x476db6cb, 0x7f781db2, 0x382bfc77, 0x3c6d9f0f, 0x25a654f2, + 0xc7cc7ec8, 0x658cec2b, 0x60fede30, 0x4b8db487, 0xb473b3f1, 0x5efc1d7f, + 0xeeaff44b, 0x53646cf7, 0xb6dbbc36, 0x07698200, 0x46cff2fa, 0x3ec36537, + 0x4437fc2b, 0x14cccedc, 0x4a947fee, 0xfbc44352, 0x0b8949cc, 0xdf83ef1a, + 0xe7de3aaf, 0x19f78b3c, 0x7de333fe, 0x0c9f393a, 0xef1e0988, 0x5fcf04f2, + 0x43d96a42, 0x43ee5c72, 0x077f0dd8, 0x67bc5658, 0x8899e5c9, 0xc0da18f3, + 0xb943ffec, 0x6364ab1f, 0x88432e71, 0x7aa7b59b, 0xe5640597, 0x89119054, + 0x113ae237, 0xc606fdef, 0x7be13425, 0x0e9337cd, 0xacc46d4c, 0x1ba29485, + 0x8ec491d3, 0x855228e9, 0x835268e9, 0x16a46de9, 0x09a4b1d3, 0x8dc7d253, + 0xff78c7ef, 0xf3adc67e, 0x0cffb034, 0x6f5c1498, 0xbfaf837b, 0x5243e04b, + 0x9578afbc, 0xd84518f8, 0xf121c5fb, 0x7e819292, 0xea2f0258, 0x9c31bfbf, + 0x119db078, 0x80f651b0, 0xef0594f3, 0x0d880a4f, 0xc42bc2e1, 0xa1c7ae47, + 0x2532f665, 0xe0e9025e, 0x1bd4854c, 0x19ee4607, 0x2b038ca7, 0x5e718719, + 0x5cec39fd, 0xe26ff2c0, 0xb1f79de5, 0x2824507c, 0x82ca45fc, 0x5c71fe71, + 0xef190f72, 0xb187261d, 0x6ef17ab8, 0x4230e4c9, 0xb5bf809a, 0xcf9438ce, + 0xde297a8b, 0x392530f3, 0x355ca00e, 0x142d23ba, 0x16670b7f, 0xb1c6ffa2, + 0xdb8dcb38, 0x7e3c5f25, 0xd75b0a4b, 0xc4aaa547, 0x8f1e743e, 0x77dfa7e4, + 0xbfafba7f, 0x04e7e82b, 0x3f755bac, 0x3c3ac46f, 0xf6313fd0, 0x2cfcf3c2, + 0xde6cafbe, 0xaadb343c, 0xaccd7e81, 0xdd67dfdf, 0x32cd3f77, 0x424edaa7, + 0x821496f9, 0x5da44deb, 0xf02dece2, 0x893bc45d, 0xbf33edef, 0xbe26eadf, + 0x531faa38, 0x5ca1671c, 0xd693c6a5, 0x571d0e5f, 0x5c46c4b6, 0x655be47a, + 0x2e3a993c, 0x3df7b68b, 0xee52abcc, 0xd3fc0b98, 0xfe91f516, 0xcaefea2c, + 0x1dc6acb8, 0x687114fb, 0xe3781d62, 0x1c593ad0, 0x438850da, 0xbff1f48b, + 0x7c134388, 0x10c3d62c, 0x72c34388, 0xf281cc37, 0x813a3fc3, 0x4e236871, + 0xda1c7878, 0x9a1c6511, 0x159ffbed, 0xb1de2687, 0xbd85b058, 0xdb80bfa7, + 0xfd060077, 0x5f7894e2, 0xc4579f86, 0xdf7ca4b9, 0xdf9eecdb, 0x041bff49, + 0xa7ec907e, 0xe859f9f8, 0x0fe0122f, 0x0cb5c279, 0x0fe01dc6, 0x09aff2a9, + 0x568277fd, 0xe9fbf506, 0x2bcfca93, 0x5c219f7c, 0xcbc7997f, 0xaec0fcc0, + 0x8f51a0b5, 0x1782d1fa, 0xfe82b3ee, 0x64d520b4, 0xf2b77945, 0x514be43e, + 0xfccf3c9e, 0x9b7ac473, 0xdea09cbf, 0xac4f3de5, 0xeff0d833, 0x404bac23, + 0x3e7bcafd, 0x0814f6e7, 0xebfb84d3, 0xdd1d514d, 0x536ddee1, 0xf4158663, + 0x5b220fbb, 0x71b14256, 0x5e9f0ce1, 0x0e98797d, 0x9603aff5, 0x74888298, + 0xf3b13adf, 0xf99e4275, 0x3af98335, 0x7bb136b3, 0xf6a39c85, 0xdc0b4882, + 0x84fbb02b, 0xefc12d41, 0x4ae7c7a9, 0xc08a7b8a, 0xcb16c9f7, 0x7fb8255d, + 0x6a10f760, 0xbfb8bd3b, 0x2985b22e, 0xdd423fee, 0x0ef38b67, 0x1e89efdd, + 0x118d7bf6, 0xc48337fd, 0xf7233dd3, 0xf663bdf0, 0xf3c0e48e, 0xa6c61dd0, + 0x4fabe034, 0x53731c63, 0xcb6e20e3, 0xce39416a, 0xf17ceae3, 0xbca06f40, + 0x073ef114, 0x20e32da5, 0x54deea1e, 0xa3d40547, 0x067b30d3, 0x9947def9, + 0xc5f27b99, 0xa7682dd7, 0xb7f54caf, 0x3bbff3d3, 0x1e2f5ea2, 0x59e3058d, + 0x5095bf9c, 0x8d0338af, 0x15f3c60c, 0x8a674ff2, 0xdbf98729, 0x4adefeaa, + 0xdfe5576c, 0xf167a95b, 0xad89a50d, 0x59b3af4c, 0xfa6e2cad, 0x959dfde7, + 0x9553ddcb, 0xf428b626, 0xe621b255, 0xbea6ec8a, 0xfdae5df9, 0x5a7f6c36, + 0x7e0a87d5, 0x98e8b198, 0x3a66cf82, 0xb5f9959b, 0xaf7838d2, 0x1567d28c, + 0x35b3c7d0, 0x0b14d469, 0xf01801f8, 0xf7cbbf5d, 0x77f11a7b, 0xcf09baa2, + 0x9f5e628b, 0xd8451f55, 0xc651ed53, 0xa979f067, 0x704f8bfd, 0xdc1399bf, + 0xf704e66f, 0xfdc1399b, 0xbf704e5a, 0x7c87e116, 0x4c8aa242, 0xe47f5074, + 0x828f8137, 0xc23723f8, 0xc8fe90f7, 0x0a71c7e4, 0xb7e7647f, 0xe47f0b08, + 0x91e7a95d, 0xec9bbb8f, 0xc43b436f, 0x9ffbd1e6, 0x23f943bb, 0xeeca9fbf, + 0xa5503e93, 0x22f3d29f, 0xb4f1a9fa, 0x0bd95e50, 0x37ac59df, 0xcb879010, + 0xf1a6d924, 0xb0f18fbf, 0x16ce5377, 0x1dfc28a5, 0x8b7f962a, 0x0f7e17f8, + 0xd0196f39, 0xdf7ca04f, 0xd7405ec1, 0xe71d53c7, 0x1dfd9952, 0xab2e87df, + 0x5fbfb033, 0xbf21cfc7, 0xebf139e0, 0x718181d4, 0x77e6a114, 0x53d34e76, + 0xe55e7499, 0xef153b91, 0x8af18b22, 0xfa718979, 0x5f8cb9da, 0xc50ef2c9, + 0xf6db6b3a, 0x63e02f48, 0x9c167ef1, 0xa904275b, 0xe8c69f1f, 0x5287cf42, + 0xa4bfed1a, 0x7d0f9d8a, 0xffb9adf4, 0x3ec7a013, 0x509dca13, 0x2cf3d5f5, + 0xf10fb1df, 0xd2173ea1, 0x0b4d7679, 0x3b9fcf32, 0x6bf5abbf, 0x4e217437, + 0x715097e0, 0x9b250751, 0x2d77c605, 0x4b5e96bd, 0xd2d7a5af, 0xf4b5e96b, + 0xbd2d7a5a, 0xaf4b5e96, 0x6bd2d7a5, 0xf4e5ffe9, 0xfffd007f, 0x8000c102, + 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, + 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, + 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, + 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, + 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, + 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, + 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, + 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, + 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, + 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, + 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x30001131, 0xafb00408, + 0x521cae88, 0x11447fea, 0x992c9a42, 0x326ebaf3, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0x7f6db6db, 0x98a102fc, 0x80005382, + 0x00008000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x00002000, 0x000040c0, 0x00006180, + 0x00008240, 0x0000a300, 0x0000c3c0, 0x0000e480, 0x00010540, 0x00012600, + 0x000146c0, 0x00016780, 0x00018840, 0x0001a900, 0x0001c9c0, 0x0001ea80, + 0x00020b40, 0x00022c00, 0x00024cc0, 0x00026d80, 0x00028e40, 0x0002af00, + 0x0002cfc0, 0x0002f080, 0x00031140, 0x00033200, 0x000352c0, 0x00037380, + 0x00039440, 0x0003b500, 0x0003d5c0, 0x0003f680, 0x00041740, 0x00043800, + 0x000458c0, 0x00047980, 0x00049a40, 0x00008000, 0x00010300, 0x00018600, + 0x00020900, 0x00028c00, 0x00030f00, 0x00039200, 0x00041500, 0x00049800, + 0x00051b00, 0x00059e00, 0x00062100, 0x0006a400, 0x00072700, 0x0007aa00, + 0x00082d00, 0x0008b000, 0x00093300, 0x0009b600, 0x000a3900, 0x000abc00, + 0x000b3f00, 0x000bc200, 0x000c4500, 0x000cc800, 0x000d4b00, 0x000dce00, + 0x000e5100, 0x000ed400, 0x000f5700, 0x000fda00, 0x00105d00, 0x00000028, + 0x00000000, 0x00100000, 0x00000000, 0x00000000, 0xffffffff, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x00088b1f, 0x00000000, 0x51fbff00, 0x03f0c0cf, 0x65e21f09, + 0x63e62860, 0x88237860, 0xcc2b4e2a, 0xfe9942ce, 0x0c0cccf3, 0x32f88117, + 0xe2055f10, 0xe9a48cd3, 0xb045e2b7, 0x30327377, 0x7df90358, 0x9b8b5a40, + 0xc8014181, 0xb3e201b6, 0x204bfe40, 0xadc40afe, 0xdc0c0c3c, 0x6a0c0c5c, + 0xc4042c40, 0xcdf8bcb6, 0xff2023b7, 0xaf951b9f, 0x17ca83cd, 0x3fafc6e6, + 0x7cbf0789, 0x6c790106, 0xf928b3f8, 0x4620e1f1, 0x2d43749f, 0xca86aeac, + 0x6065522f, 0xe7c40df8, 0x681ae2a1, 0x10aac5f2, 0x03329cfa, 0x7e1ab243, + 0xc80853b3, 0x000c060f, 0x4022bae9, 0x00000400, 0x00088b1f, 0x00000000, + 0x7dedff00, 0xd554780b, 0x733ef0b5, 0x27bcce66, 0x20212793, 0xf0841e4c, + 0x04242074, 0x11093a8c, 0x5076c403, 0xc2ab16fe, 0x25786784, 0x5ae5a911, + 0xc0133bff, 0x51b91688, 0x7e2da5a8, 0x68bc104e, 0x01226f69, 0x903a4483, + 0xbd08a5c0, 0x168b6ad1, 0xe088786d, 0x7e929205, 0xcfe956de, 0xe7dad6bf, + 0x9939cccc, 0x77e8f881, 0xbf41ffbf, 0xdecfb3ba, 0xd7b5ef67, 0xcfb5ef5e, + 0x30733d1e, 0xd7632776, 0x73941ff1, 0x4158c645, 0xf81d0ca4, 0x614b3ce2, + 0xc18b72ec, 0x6c64cc65, 0xe8431eca, 0x68afa84e, 0xd7588214, 0x3633301d, + 0x5b2bb181, 0xec46bd79, 0xb41b78dc, 0xb645d7b3, 0xd3b60a03, 0x8c8563a6, + 0xfe31379d, 0xb1d76f4f, 0x9916c634, 0xe3457579, 0x7e3839c1, 0x9991ab55, + 0x2df3fde1, 0x2beb07a2, 0x26410877, 0x27befb40, 0x7f180ca5, 0x32685071, + 0xe3bea0bb, 0x6765c959, 0x2f81cd6c, 0x0abce0ae, 0x4dfa9f5c, 0x7c2125cc, + 0x8d75a5ef, 0xb0696c66, 0x8c066a79, 0xe09774b3, 0x4b3cc1d6, 0x3ba10ab7, + 0x2173e027, 0xcbb8c228, 0x2b995a76, 0x9d70c38f, 0x8eb4bcd1, 0xbcc02f95, + 0x83670899, 0xe647b5e4, 0xa9f3f053, 0x72b981bf, 0xaf15f523, 0x5ef03cc0, + 0x3704aff5, 0xc75ab12e, 0xff304d7c, 0xd9e67d95, 0x7d70d92f, 0x3dae5275, + 0x7b951d7a, 0x834b1d71, 0x1b54d28d, 0x2d28d5c2, 0x6f191d1a, 0xcc4dced9, + 0x6b828a65, 0x5f00f64b, 0xfcb6bb54, 0xf054cfd4, 0xd3cc652c, 0x83f84364, + 0x9131ccd2, 0x22422de7, 0xbe38a963, 0xb19f1aa8, 0x99173d00, 0x6778843b, + 0xf477766d, 0xaa755dbe, 0xa2656df7, 0x781c6efc, 0x87de45fe, 0x2a4efd67, + 0xa9d3f937, 0x45dfb1fc, 0x9fc4fe70, 0xfd4fe547, 0x73fe7a6e, 0x2f95117f, + 0xbe543df8, 0xb2a72fe8, 0x7ea5efd1, 0x5367f92f, 0xa3efc3b9, 0xafeaffe7, + 0x7f15f2a2, 0x85ff3d2d, 0xbf95357f, 0xf9e807f4, 0x53d7f9bf, 0x04fb8cd9, + 0x16ff6ee5, 0x83f8f72a, 0xff75efd4, 0xf9f72a4e, 0x33f9e89b, 0x13283f88, + 0x3d3ace3c, 0x19424fec, 0xb0790273, 0xceb7af64, 0x59e4f500, 0xd7c03ebc, + 0x7e012750, 0x3a802c06, 0xdaa0dfec, 0xb4233ace, 0xdbc55a0f, 0x6b9c0687, + 0x743ed04c, 0x6ecf6f1d, 0x4331aef0, 0xde66f67b, 0xb0d83c3e, 0xc3ed02c6, + 0x51f6f3b7, 0xac6b9d4d, 0x85aa3ed0, 0x721adfb7, 0xfd41b5ae, 0xcf5e0ed6, + 0xb5aef4ef, 0x5dff3d43, 0xd5d89f5e, 0xef01d6b0, 0xdfc73c4f, 0xd9bde2d7, + 0x60cf9ce0, 0xee0736af, 0x4207e8f2, 0xc23e725d, 0x1cbd8cdc, 0x77d516f8, + 0xded4dc1b, 0x47aef81a, 0x92ea093f, 0x058fda9b, 0xc7bed47c, 0x53f6a5e0, + 0xbed42581, 0xfb52f247, 0x6a4ac095, 0x4b50dd7f, 0x87eeaced, 0x54bafed4, + 0x7549ed4b, 0xcfbea8eb, 0x8c196d00, 0xe33dd4e5, 0xcdfd0009, 0x511b7c11, + 0x6aeb747e, 0x12ca18ab, 0xf91d287d, 0xcd8149e9, 0x5d80fe46, 0xf27bba23, + 0x7c83c916, 0xc29bfcd7, 0x994cc497, 0xbeb052d6, 0x05a7e5e8, 0xd827e71a, + 0x71825baf, 0xce3e6fb2, 0xaa4563b8, 0xab1dc671, 0x1209c652, 0x8dfe963c, + 0xb26c7cd3, 0x4b639e1a, 0xa15e7195, 0x5bfd1c71, 0x8ab7b8d7, 0xb5bcf0d5, + 0x35e7195c, 0x7fa9271a, 0x1b7eecf0, 0xc64423f0, 0xe036fdd9, 0xd9c69327, + 0xf5a4e34f, 0x77fc9e0f, 0xe4e3548a, 0x8ca553bf, 0xce7841d3, 0xbb38dfe8, + 0x86ac99df, 0xcaa59de7, 0x9c682738, 0x575bfd21, 0xd58aeffe, 0xb96efcf0, + 0x69efce32, 0x8dfeac9c, 0x357de7b3, 0x3f79ecfd, 0xa27f3f4c, 0xb7fb7271, + 0xd40f82ae, 0x41f053f4, 0x102e7e98, 0x6ff6479e, 0xa81f3d9c, 0x07cf67e9, + 0x33f9fa61, 0x7fb633c1, 0xa3f82aeb, 0xfe0a7e9a, 0xcf9fa618, 0xfdf19e09, + 0xd3f5e783, 0x7ebcfc6a, 0x511f8c3a, 0xfb0a7840, 0x33c4cf07, 0x3c4cfc6a, + 0x8d8fc613, 0xbfdc99c6, 0xa33f5e71, 0x67ebcfc6, 0x1549f8c2, 0xf4775d70, + 0xcf135d6f, 0xf133f1aa, 0x433f186c, 0x19529e08, 0x8ce3061e, 0xbece3f89, + 0xecfc6a8b, 0x33f1c8bb, 0x3a27d3be, 0xce90dda0, 0xe4ce08dc, 0x0080de0b, + 0xa814faed, 0x30f4b0bb, 0x3d3bc81f, 0xf8d1ddea, 0x84405772, 0xc4aefb76, + 0xa2bb4ff1, 0x58e96ff5, 0x8263975c, 0x3877654e, 0x7aaa2d8b, 0x4a925952, + 0x6454a73f, 0xb369eaa8, 0xf4f554b2, 0xdeaa4707, 0x5e3058cf, 0x7cbc1f55, + 0x643eaab2, 0x7deaa955, 0x55d3e3d7, 0xeeeb59ed, 0x3673d555, 0xcf554f7c, + 0x554f3cdd, 0x54badbcf, 0xedc8de35, 0xd1f5552b, 0xd5531ebb, 0x51acb6c7, + 0x4f6dddd5, 0x3be3eaab, 0x3f8d539e, 0x54cff8e1, 0xb777c2f5, 0xa745eaa9, + 0x3fbd555e, 0x1a6bdcf9, 0x3ce6c6fb, 0x8bae4a3f, 0xc95acf68, 0x910e33ce, + 0x192d5ec8, 0xa3faa262, 0x7f546c43, 0x70df0ef4, 0x8fe3ec27, 0x6bd005f0, + 0x5bbe4a8f, 0x2fec319d, 0x4b1d39d8, 0x63a7d2c7, 0xd7db7d45, 0x80ce801b, + 0x5e874a2e, 0x650d3dcb, 0x3727ae8d, 0xe8dfca11, 0x2e916a4a, 0x4474151f, + 0xd591567f, 0x8d58dd22, 0xfd70e88c, 0x0297c2b0, 0x54f87451, 0xcaf39726, + 0x6a194fb8, 0x3eef51d3, 0x0066f756, 0x9993f2f5, 0x664cbc60, 0x9bc287ec, + 0xbc0e40a1, 0x3a68f99f, 0x09268bda, 0xf9e8d0ec, 0x347f9825, 0xf9c01fcd, + 0x6fcce3eb, 0xcd522dca, 0x52aace6f, 0x60966fcd, 0x4f63277e, 0xe7961dd7, + 0xffde9137, 0xe6987091, 0xa6ad6537, 0xac4bd7f9, 0x25bf354a, 0xf2037f3c, + 0x7f38f3c1, 0xe7f58c41, 0x3faf564e, 0xfd7aa96b, 0xcfff5f12, 0xf3c84eea, + 0x3ffd685b, 0xf5f04e17, 0xd7c63d67, 0xa371846f, 0xf18477e7, 0x5ff9c41f, + 0x69bf338e, 0xfd7ab178, 0xebd5cbd9, 0x5ff9f237, 0x9e4f7bad, 0xfff346df, + 0xaf8f7842, 0x9a71fb3f, 0x75ac68df, 0x38c9a13b, 0x441b52d4, 0x2fe600b9, + 0x050c801b, 0xc6444cf3, 0xde0c6248, 0xd164285f, 0x016a3c3e, 0x9ffe83ba, + 0xd0de8059, 0x72ed977e, 0xd017ac16, 0x6996af0e, 0x4aaec17a, 0x657819e9, + 0x57f72b41, 0xc333f818, 0xad2bbe00, 0x11fd9fbd, 0x7db05de0, 0xa025c91c, + 0x2def8674, 0x23529794, 0xe6307c72, 0xe413321d, 0x877bd329, 0x9a863bdc, + 0x2fd7683c, 0x1f630466, 0x60d85e3a, 0xc515df38, 0xa8b78b6f, 0xea824beb, + 0x097702ba, 0x81940912, 0x0b579652, 0x7f079ef3, 0x7ddd8180, 0x2c6dec06, + 0xb9b0313f, 0x0e7e785e, 0x452605fc, 0xed1d55f3, 0xabbd79cb, 0x73d61d3e, + 0xc3704abe, 0x0d81ec88, 0x3a196395, 0x7bcf0172, 0x77ef0039, 0x852ff298, + 0x7273e9d6, 0x003617f8, 0x7ff1477f, 0xb0bbc88d, 0x0ee08517, 0x7fbfe790, + 0xba054573, 0x83d7d0bc, 0x5e577def, 0xc92de2f7, 0xde98f7aa, 0xa9cdef44, + 0x1ea20c4c, 0xc36ceef8, 0x3b552eb9, 0xf1c03f30, 0xdd0fec91, 0xf1eebacf, + 0xdfb99e82, 0x75d7eea7, 0x8dd1eac0, 0xbb4b7285, 0x3dbec181, 0x8719a550, + 0x1f7f6879, 0xa878e192, 0x973edd56, 0x5fd42539, 0x9fab5773, 0xe3b40657, + 0xcf00f800, 0xf81c793c, 0xe6f844e7, 0xd7f36dcb, 0x7daa021b, 0x0a947a02, + 0xa22cf6e5, 0xbd0f5a02, 0x3fb7dd9f, 0x434041d0, 0xfb588107, 0xf9f7fffe, + 0xae7d8dff, 0x3e492d69, 0x8ad70517, 0xe7c969a6, 0xdb2dfaa2, 0x5f555339, + 0xd55fbc12, 0x4a96f17f, 0x86c2fb55, 0xf9f6aa25, 0xd5561feb, 0xa4ff032b, + 0x75773fea, 0xa1fdaa9d, 0xed54a7da, 0xab3d540f, 0xfbefdfaa, 0x77ffaaa9, + 0xdaaa3767, 0x864b0385, 0x46a8dc62, 0x881d0df2, 0x8df7aef1, 0xa1109b6c, + 0x2fae855b, 0xfca9d3f8, 0xb2a2efd4, 0xc830e50e, 0x5e3edd75, 0x1cab6cd6, + 0xa15bf28a, 0xb50c4ff3, 0x69fe5043, 0x672b55e9, 0x6325d0fb, 0x88bed083, + 0x2e596717, 0xf3ca2f30, 0x19db816e, 0xb213f3ca, 0x0d6c675e, 0x8972d7f1, + 0xd7f2dff3, 0x3f229606, 0xb942972c, 0xe3f8b6b5, 0xd68126b2, 0x1a36d8c1, + 0x10704967, 0xfbd17918, 0xf382ad9a, 0xe69141d2, 0x6e1f46af, 0xdec1da12, + 0x3f9c3a0d, 0xbee43ed4, 0xe78f0831, 0xc1c01d19, 0xdf49535a, 0x2797f25d, + 0xfe23d39f, 0xf05e54bc, 0xbcf2a6cf, 0x39e547df, 0x6795157f, 0x7654b5fc, + 0xf95357f9, 0xe5403f91, 0x2a7aff29, 0x5037f03f, 0x85bfd279, 0x83fbdfca, + 0x7bf15e54, 0xf4e854a8, 0xb57d96ff, 0xf2bdb8e8, 0xffafb8df, 0x16afbd1e, + 0x23c3939d, 0x0d06ebef, 0x55794abc, 0x61797027, 0xf31676e4, 0x788e2958, + 0xc3078955, 0x94571448, 0xf0ddc1e3, 0xd3f62777, 0x1831e537, 0xcfe8eaef, + 0x7b8e3173, 0xb191a4f5, 0xd3ebf8cc, 0x3c5c5fee, 0x46ee80b0, 0x3858b7f8, + 0x72aa015e, 0xdcec1e36, 0xf3dd7b11, 0x92cf5d78, 0x7726fdf0, 0x3c355c74, + 0xc072e22e, 0xd16af1cd, 0xdacf7b71, 0x847c722e, 0xb3efbb76, 0xc6b5e847, + 0x718b93d8, 0x2347f662, 0x36c63d43, 0x055871cb, 0x575e015f, 0x3a7ff5f0, + 0xfda04e3e, 0x1f1f105b, 0x47e0a5dd, 0x32bff0c4, 0x574aafc5, 0xae90439d, + 0x7bf4cab6, 0x027865b5, 0xe7191d1b, 0xd38b9d6e, 0x7ef04df5, 0x0e4be8f5, + 0xa657f3b4, 0xf2e79ceb, 0x456fe3e3, 0x16d3a653, 0xaab4a76d, 0x841b57eb, + 0x70371e72, 0x831acc25, 0x3ce9d1f2, 0x2c728397, 0x9c654a9d, 0xf392e995, + 0x0bf6325c, 0x2576f872, 0xea7e5f12, 0x6fbf5137, 0xe3788e1a, 0x6168e044, + 0x247de167, 0xf1d9ebd1, 0x3ba5c7fb, 0x8c245ffd, 0xc336b0c7, 0x985f6867, + 0xd1d7ffe0, 0xaa7a63ee, 0x34d6e32b, 0xade30189, 0x6a977cf8, 0xa5cf783e, + 0x67ae94e4, 0xf5be88dd, 0x7f42bcec, 0xa0e7ca20, 0x1079489d, 0xbf6d53b3, + 0x35eaaa24, 0x2a9d03ad, 0x00ff067b, 0x04cac739, 0x72c1d23d, 0xf5ba2c99, + 0xc002f5b6, 0x2e9d0937, 0xf78147a4, 0x92ea615b, 0xafa42e7c, 0xcdb9dfb5, + 0x681b3d85, 0x60f85abd, 0xf5ea66ff, 0x265fe1f1, 0x1bd47d5e, 0x22d7fe83, + 0xd01ea3fd, 0x999f3f71, 0x43e40e02, 0xdc701e96, 0x6cc3fc4b, 0x9ae0fc61, + 0x5513cc19, 0xff01c657, 0x5f6d47ad, 0xa4bbbe72, 0x76bbfee3, 0xbcf2cdde, + 0xf55fc337, 0xe2a7b7ae, 0xac78b5ba, 0xe4b3fd6e, 0x5314fca3, 0xefc151e1, + 0x59bbd124, 0xee97f984, 0x7f212d3c, 0x7204305d, 0xb903787f, 0x5b7e17df, + 0x646b79fa, 0xd8f72b9d, 0xf95fbec9, 0x0bd79cac, 0x779c4eb0, 0xf13c915e, + 0x0515e835, 0xa67c6807, 0xd3d88c2b, 0x5e6d7e4a, 0x27f232cb, 0x0901663e, + 0xc51792e3, 0x9fb44286, 0x4a353697, 0x32f3801e, 0xbe2395d3, 0x1c77b32e, + 0xb5fb51f9, 0x9f08944f, 0x899f6760, 0x6cec1386, 0x6cec1d55, 0xbb117d55, + 0x51f30d37, 0xc01b368b, 0xaa75a7c5, 0x9d115fda, 0x5662ee34, 0xc9768f5b, + 0xeffc96d9, 0xf0fb86dc, 0x88850bfa, 0x3cd079df, 0xf8f10928, 0xcbf1e136, + 0xdf04bfce, 0xde77df1f, 0xf26add08, 0x561e328e, 0xc13c14ec, 0x44737418, + 0x7d0ad796, 0x5f8641fd, 0xc59c0f89, 0xdea4417a, 0xa17fa9ad, 0xfe657fa9, + 0x4bba014d, 0x24f7ec8b, 0xe91677d1, 0x38f906ad, 0x5fb7c221, 0x3ef4fc79, + 0xa37f77e3, 0xf3560fe3, 0xc5ff8c0d, 0x4e7e3a37, 0xfa8df81f, 0x77e3be82, + 0x59631d9b, 0xc4a9d902, 0x3a71815f, 0x1fe9bbf2, 0xd2136bda, 0xc0a69fc9, + 0x39ddd638, 0xd9a38c41, 0x14e99dcd, 0x54bf07d7, 0x6024f30f, 0x0edf907f, + 0xf9f016e6, 0x2cd37ed3, 0xf8ca8794, 0xe55eb776, 0xe914267f, 0x7b28fe35, + 0x61f00737, 0x38a6a793, 0xfcedd41b, 0x5b6b666f, 0xe30b7c4c, 0x04e8fca8, + 0x2ffe45d6, 0x9e7aa78c, 0xa1d59a38, 0xa8f44a1a, 0x6d154f9f, 0x9c4b6f14, + 0x9c4e28c6, 0xfad7ae5c, 0xd2c315f7, 0x4740e0a2, 0x32c9ea1b, 0xcfa6e01c, + 0x67fde014, 0xf08cf4cb, 0xc5ff8012, 0xbc593380, 0x01f9c216, 0x39df155e, + 0x65f540f2, 0xe7aabc11, 0x4d19e700, 0xe50f207c, 0xb8b31246, 0x53801e71, + 0xdbd1eed5, 0x0e1e2853, 0xa3e517f2, 0xc989d4cd, 0xaaef9c7f, 0xf4ebaf0a, + 0x190b23e9, 0xfc385085, 0x942fa601, 0x83ef8bf7, 0xd313bfaa, 0x8f04d9d4, + 0xd8361c7a, 0x6f8f2d19, 0x8309fd95, 0xe9133bc1, 0xad6870aa, 0xa717f388, + 0xaec872bb, 0x3a214b68, 0xca5d5acc, 0x685d42ce, 0x9cf78460, 0x39ef1c0d, + 0xf71e3a3d, 0x0e09675c, 0x268cb183, 0x9c833016, 0x301cad02, 0x8259c78c, + 0x5ae49fb2, 0xcd3cc3a3, 0x7829a07a, 0x54a7adaf, 0xa73610b7, 0xfc609b09, + 0x3e3de96f, 0x67c1c63d, 0xe375d2fa, 0x9ae161f0, 0xa5a0c18e, 0xb8211b19, + 0x05080b41, 0xc2de8e87, 0xdf184a43, 0x790f4185, 0xd72ed46c, 0xdaed0859, + 0x2faf0b06, 0xae9417d7, 0x988ff787, 0x5d71cbbc, 0x891ce4cc, 0x4a162b79, + 0xb7c6f5a2, 0x0724024f, 0xb6f2b815, 0x4cb54d77, 0x2814fe40, 0x1ecc3fcf, + 0x24255bb6, 0xa5361dae, 0x6ed0921e, 0x2dbcb6f5, 0xa2bb7fa1, 0xd76a6de9, + 0xa1ca1d61, 0x07535dc9, 0xd4f88981, 0xf4d2b2ba, 0x4b5e3011, 0xd60eba65, + 0xb2badcf5, 0x4f75ea43, 0x1c51d35b, 0x775eb759, 0x77dd66b7, 0xcfdd70df, + 0x5d2eefe9, 0x75ffdc5f, 0x8b3fbec2, 0xa25199f8, 0xeefe510b, 0xf0282da4, + 0xec99bb78, 0xc69c7941, 0x1287f638, 0x7e718437, 0xe850eb8a, 0xa14f7947, + 0x9174789b, 0x79239ccd, 0x1f4d503e, 0x6d9ef4c7, 0x7a4bd708, 0x4054894f, + 0x787b25eb, 0x2ee7cf86, 0x2dd08fcb, 0xd1f2f9b3, 0xe61832be, 0x57e702fd, + 0xb2519ae0, 0x7802cc52, 0x21ec6177, 0xd49eb235, 0x2e7301d5, 0x03d533ac, + 0x7be177d8, 0xcf7c66be, 0x8427bb31, 0x32262647, 0x4620be5f, 0xaf995ee8, + 0xdf1e4dfe, 0x05d4afaf, 0xed5c90d7, 0x08bc7012, 0xe869743d, 0x43d387a1, + 0x87a269eb, 0x9cd3b6ea, 0x4aeb5a1e, 0xdbaa9e91, 0x85d1a704, 0x8719eaeb, + 0xebeffcfb, 0x61ea97e6, 0x7b5a879f, 0x1d0107ea, 0x69655818, 0x7af09985, + 0xb3ebe118, 0xca7c323f, 0x6fede2ba, 0x1facd1c3, 0x707d468d, 0xe61ee75c, + 0xe94de08a, 0xd12f4977, 0x7c906c3e, 0x295e90ef, 0xcb823aea, 0x3be8ed7f, + 0x1c5bb40e, 0x883defc7, 0xc1663bef, 0xf322b90e, 0x535f1c36, 0x1a67e78a, + 0x64381d60, 0xa009eb02, 0x1f1f13dd, 0xf8c25f9c, 0xf84d3968, 0x9e1d61d1, + 0xa7e72abf, 0x5ec8cf80, 0x7ee56a19, 0x1e7ac7ee, 0x5e9bfb3f, 0xef6e4b94, + 0x2abf1ea6, 0x5c4fd0b9, 0xa9fea3a7, 0x5e8e8e58, 0xf7ea3aff, 0x055e5437, + 0xfb287c11, 0x4813d0a9, 0x5fe62b4a, 0x577c5996, 0x6493f4d5, 0x4f1a8acd, + 0x9fa36f79, 0x7f8017b9, 0xde63b137, 0x81ff2823, 0xf543fe7e, 0x198318de, + 0x47f4a6f1, 0x3fb58cfa, 0x14331ef0, 0xd05c79f0, 0xa563b9bf, 0x7f617688, + 0xf650b5f7, 0xacad0b8f, 0xbf7835f6, 0xac4a0130, 0x01f5cb27, 0x2f107d72, + 0x75b94fb3, 0x946f3c02, 0x6e9effb8, 0x7a92e390, 0x3bcc48e7, 0x3db81ba5, + 0x923e9c58, 0xb7c2bee4, 0x2484be88, 0x58021b32, 0xe964f566, 0x3e14df70, + 0x42e8f7d6, 0x594a5076, 0x0dce977a, 0x61f98fcf, 0x9ff037dd, 0xbd108fa6, + 0xd1d1ecb1, 0xfcbf5d06, 0x5276b898, 0x6c3b1f57, 0xec9521b4, 0x42f78da3, + 0xaf447abd, 0xc6b5fb84, 0x8ddb7d5a, 0xe169efce, 0x13ed763f, 0x577bfa07, + 0x8f2c6afe, 0x5078f715, 0xff51dbc6, 0xb14f7a6c, 0x30ab68a3, 0x3ec0cfbe, + 0xd70bf0e2, 0x7d92548d, 0x3c890774, 0x3e80c7dc, 0x55a7f509, 0x777e73a0, + 0xebb3fa46, 0x8477e7c0, 0xb1b05696, 0xb72bf950, 0x3ff04c6f, 0xe98faff4, + 0xed1e747d, 0x9a79e318, 0x3b6d6b42, 0xd33199d6, 0xf985c3bd, 0xa29e753e, + 0x2ca1a130, 0x42489509, 0xc533cd26, 0x0e4f69a4, 0xb2fe51e8, 0xe71e4cec, + 0x945f3062, 0x44f40e9f, 0x7c3658f9, 0x3395d924, 0x65dd2af2, 0x48bdfbf2, + 0x731b7eac, 0xfae44426, 0xeefdd734, 0xd1dd9532, 0xfd3946e0, 0xe245dfd6, + 0x7f1e2d6b, 0x7d7ce065, 0x9775efd4, 0x63c5f4e5, 0x67584ba9, 0xa7c5f577, + 0xfc5a5f16, 0xc95fc3c6, 0x52597729, 0xf1693c0c, 0x46ff0c72, 0x06368f3c, + 0x9de20203, 0x4b98e9e3, 0x78188160, 0x29d2ec52, 0xa4683176, 0x9dd90f76, + 0x68f0c977, 0x4f17d6f1, 0xd2bb8a9e, 0x411ff022, 0x4e91e87c, 0x884aefdc, + 0xdb0304ff, 0xdd0ceb81, 0x6ab7f949, 0x434c1fb9, 0xf93bb579, 0x8375e150, + 0xf087707c, 0x386301bd, 0x6d55fd7d, 0xb83dde7f, 0x14a0dd72, 0xfb9803c4, + 0xd4671f1c, 0xf1b8c374, 0x7da4cd61, 0xdba8fc07, 0x587e3993, 0xcbbf6f32, + 0xd0d769a9, 0x0abd768d, 0x3e1bfcdd, 0x3f17d498, 0x30ecdd0a, 0x067276c8, + 0x1e788c1b, 0x02426fbb, 0x78da2dc5, 0x4f4b5ede, 0xc37a4f13, 0x47f4c8e3, + 0x5f3025f4, 0xfb33b9f8, 0x569bc86b, 0xf25166d0, 0x7be8b866, 0x51bc9623, + 0x7976fff6, 0x81676e9f, 0x4b03a283, 0x74c25ffd, 0xff591993, 0xda275c21, + 0x20d883e7, 0x8318e75c, 0x7969cb8b, 0xcb75e19d, 0xe58a09e7, 0xb64d8bf9, + 0x7acb8e10, 0xf8c297f4, 0x5cf8a2cf, 0xc08a4a40, 0xb3fb9061, 0xdb8cb521, + 0x79d20f5d, 0xbb0bc01c, 0xf1c08d6e, 0xa7a08307, 0xc70c9578, 0x80a69de5, + 0x57ac2b78, 0xf511fdf4, 0xf8e125d6, 0x3e9f5a58, 0x4a7a8b94, 0xdadbdedb, + 0xd0ed8d51, 0x93f5116f, 0x71865fe1, 0x9ea7a007, 0x6dc18d37, 0x8a48e231, + 0x4a6c093d, 0x83e15cf2, 0x6505513b, 0x92dfa5f7, 0x1c7af1d6, 0xa5b74b5f, + 0x1da159e0, 0xbbd7a5aa, 0x7c1ccf58, 0x4553a5ae, 0x7a597eaf, 0x30a9ec50, + 0x74d4845d, 0xd003d0a1, 0xfa42ffc7, 0xf1f09ee8, 0x9efe68f3, 0x169bd098, + 0xbd810f4b, 0xeca293a7, 0xb3f678e8, 0x48273762, 0xc7da333e, 0x595d797a, + 0x9e1d2e79, 0xf25dba8f, 0x62b9f058, 0x0fccdc4f, 0x80e01d60, 0x91cc7d02, + 0x83a4ddf1, 0xc0dbe006, 0xf288214a, 0x63d621e6, 0xaa1ef9c0, 0xc9fca835, + 0x8f9ee639, 0xe6fd087e, 0x3d270dd4, 0xbf28c3e4, 0x38f3ef48, 0xffcf3d44, + 0x5c9ebcb3, 0xaee6bff4, 0xd1fc6836, 0x39e3a224, 0x23ecfe4e, 0x09303be8, + 0x4d4aedc7, 0x76f94d1a, 0xfced7f55, 0xe3b43aca, 0x91abdf6a, 0xee78b2e3, + 0xf7851dca, 0x83b71251, 0x131ef0c2, 0x6f80bc39, 0x6aebac1d, 0xd3e088db, + 0x2954e831, 0x8e5d267d, 0xef52393e, 0x3b38d37a, 0x955f6318, 0x3f7c1479, + 0x7c153ac8, 0x0e8b1e7e, 0xffdc7d8b, 0x910e6dd6, 0x2f1dacbd, 0xec8ca7a7, + 0x81269cb0, 0x4de5deec, 0x2af9ba25, 0xa3fb9bfb, 0xa6efec7d, 0xf2de3483, + 0xfedc8396, 0x3b23aa6e, 0xf70b797e, 0xa43ec047, 0xc80463f3, 0x15cbb268, + 0x7983d33f, 0xb79815a2, 0xbd21ede4, 0xf3d5cf0b, 0x78d235fe, 0xf21ca9f1, + 0xc0ff7913, 0xa7e8b5c4, 0xa85afd86, 0xbab5fb47, 0x9576c2ba, 0x6c281b5f, + 0x5b5f91bf, 0x05385f53, 0x8fe05afd, 0xcdc15245, 0xe4b663f9, 0x797fa1ba, + 0x41ade4c4, 0x02e2533e, 0x6abffdda, 0xfd202572, 0xbdfb253d, 0x23cf57d3, + 0xfc3cde7b, 0xa37990da, 0x7df2de51, 0x76e24c7f, 0x7be88a4b, 0x3eebc70c, + 0xcf172d74, 0x7fb4d4cb, 0xbcf911ba, 0x1ec3ce4d, 0x5d9157f7, 0x13dfeca3, + 0xa777b712, 0xa077688f, 0xc14f7ffd, 0xcfe81cef, 0xbcf3d65c, 0x4922a5cf, + 0x18f66f65, 0xd7027aee, 0x1e8094ad, 0xf16ee511, 0x82938e84, 0x8ffcbe23, + 0x808f77c8, 0x7b5d9df2, 0x5bd70d3b, 0x81d872d3, 0x7e84bef8, 0x5bc9c610, + 0x8f30d3da, 0x77f9a2b8, 0x9e7bf40e, 0x7b5db897, 0x40e9df59, 0x1ef96ebf, + 0x5fc9dbb0, 0x003da50a, 0x32d4ba78, 0x3e69f0bf, 0xbf5a298d, 0x85f57fe1, + 0x76edbb11, 0xeb282053, 0x284e253b, 0xefa1875c, 0x663d116c, 0xedfb5f47, + 0x4dacd1f2, 0xcc0fb815, 0x0f861ee0, 0xec83acf5, 0x09962539, 0x21cf0a92, + 0xbf2b901d, 0xefbde96e, 0xe7162236, 0xda0251ba, 0x0c14be3d, 0x8db69592, + 0x9188375b, 0x73d950be, 0x12ef7b5a, 0x1b77dd73, 0x7aa3b9ca, 0xd6b37686, + 0xfdd163fe, 0x9f7fe387, 0xd6bcbc25, 0xfdc56d92, 0x59d320da, 0x54ef4b4d, + 0x166a97e4, 0x6f7e0efa, 0x3a22dd55, 0x7246ec43, 0xf85bdd77, 0x9b7753fd, + 0xd8f485c1, 0x34d876dd, 0x22adeb16, 0x4e6a99c5, 0x3a428f14, 0x2866d2ba, + 0xbcd7bc47, 0xf903b1f9, 0x57cfd15b, 0xde7a44da, 0x9e9676dd, 0x695ee32b, + 0x7a851e4d, 0xfdc759a5, 0x9f238ebc, 0x7fdf915b, 0x326aed7d, 0x7eb297f9, + 0xaaa7618d, 0xddad4eec, 0x6e19e53a, 0xb5494e47, 0xec579c93, 0xf8fa3ecb, + 0x67675b14, 0x6b1f425f, 0x4919f0f4, 0x616ef3b6, 0xd8af31e3, 0x19792d7a, + 0x9b7765f2, 0xe286b9d5, 0xe88edc1e, 0xb9f4f8ee, 0xb8fcf819, 0xee9c7148, + 0xf1d1226b, 0x86cb03a1, 0xf1a2d976, 0xf5fb4f5c, 0x5f3fc0d9, 0x3ffd0fd9, + 0x07716c3b, 0xf77a7d70, 0xd63daf28, 0x78e504be, 0x97432841, 0x4320658e, + 0xec35f457, 0xe27d93c4, 0x7f91d7f7, 0xa67a9857, 0xddcd18a2, 0xfe425a7a, + 0x057920df, 0x2687e923, 0x8075f22b, 0x73c20e95, 0x561655cc, 0x53d4f48a, + 0xa0db9cc7, 0x9d51cf75, 0x30fb04ce, 0x1ba64761, 0xf955edb7, 0xa692f35c, + 0x4a332906, 0xbf912c5e, 0x0860bb3b, 0x7a8a490c, 0xcb91a4fe, 0x97870bab, + 0xeef248be, 0x161b237d, 0x362dbf43, 0x5bb57d72, 0x85d8cc0a, 0xe8e8cefd, + 0x238ec1fb, 0xf3c11c6f, 0xba4e4b10, 0x28bea1c6, 0x6ffa7231, 0x3d6afe3d, + 0x3d690b9e, 0x76f478c5, 0x83a8a57b, 0x1733f779, 0xabbd3f8f, 0x1c23ff23, + 0x649e63b7, 0x461de75c, 0x1ff6672e, 0xc74795d5, 0xe7cbf605, 0x1a356e1c, + 0x4661fc68, 0x8ed7ca91, 0x23cf2696, 0x19e5f3be, 0x75ceef91, 0x915c3bd5, + 0xef629578, 0xb5f77a4c, 0xcfe06319, 0x4e749749, 0xbbd76edc, 0xaf5c44db, + 0x896302eb, 0x07fb5f42, 0xf88f1bc6, 0x7fdbc657, 0x70078f89, 0x54be421c, + 0xf41a0ff0, 0xbea1a347, 0x849f53bf, 0xf82813df, 0xcca1d657, 0x9e626aef, + 0x8eb11b46, 0xc41bb5e7, 0x8f52314d, 0x54ef91f4, 0x7449cef8, 0x29e486f9, + 0x1810f4e5, 0x870bf582, 0xec57642d, 0x4b11f596, 0xf88a1caf, 0xbe69f653, + 0x0513eb91, 0xcff3789e, 0xca54e191, 0xafd74b2f, 0xa2015c1a, 0xc5023d9b, + 0x90815c19, 0xfb053b29, 0xe739d365, 0x37d8de48, 0xbd87f707, 0xd6ffa6ab, + 0x8ace9d2e, 0x214df1f2, 0xfde0d291, 0x74c34fb4, 0xfa226fa6, 0x88c93d6b, + 0x7cee978f, 0x58cdc798, 0x728e9068, 0xc84181c8, 0x9c3fc8b7, 0x0503437f, + 0x35b52728, 0xf8441dae, 0xaf90390d, 0xbe027822, 0x41b6b2c1, 0xb25d7a42, + 0xe58b978a, 0x6c9647ef, 0x2e7f11f1, 0x15395ada, 0x98d5a7ed, 0x28bd40f4, + 0x59d32bd3, 0x4ebcf032, 0x85df6caf, 0xdd3897e1, 0xd4d96c5e, 0x7d02f38e, + 0x63e233fd, 0xcfb3eb72, 0xbd0ab823, 0xa06edc5e, 0xde90aa71, 0xad74f8a3, + 0xde7bafbc, 0x693ef4e5, 0x7bf4a1bb, 0x0149eeb0, 0xec38c4e6, 0x443bedfe, + 0x91fbdf94, 0x9f39339e, 0x70be9ea3, 0x63eb69f8, 0xeb4ecfa8, 0x777bc618, + 0x39aaac4b, 0x1a3a2f8a, 0xeff1575f, 0x33759dd2, 0x95dcae28, 0xa66ba024, + 0xf782adf0, 0x1a7b92dd, 0x34b7fff1, 0xdfc65ffc, 0x81ff87df, 0xfe649b7e, + 0xfc0e54df, 0xb7128f0f, 0xce380a27, 0x79f6296e, 0xfd8d57a1, 0x5710b73b, + 0x23ef1eae, 0x72355f57, 0x0d91dbff, 0x73df57f3, 0x30effc95, 0x6cdd327c, + 0x26e8532a, 0x7b71f053, 0xf8839753, 0x3d22bc02, 0xf289bd93, 0xb82b24b6, + 0x8f45884d, 0x967c946b, 0x72236f8a, 0x5f5fe14d, 0x5853c21b, 0xed16bb56, + 0x008ae4e4, 0xc145e9d1, 0xf4093437, 0xe7e445da, 0x67e17218, 0x333e5e32, + 0x1be754f8, 0x32c1c2fb, 0xc0abae90, 0x69f3a2e3, 0xee27055b, 0xdaeed28f, + 0xf782fdca, 0x9e573e65, 0xf915ffbf, 0x53f78c3e, 0xeface27d, 0x933eb91b, + 0xdcceb04c, 0x4c67d720, 0x60be2528, 0xc819e9ba, 0x8f404b6f, 0x8f4a2f7d, + 0x1034345d, 0x38782abd, 0x67fbd32b, 0xcfdd7c89, 0xc41e70c9, 0x5be12998, + 0x7a0947ce, 0x5af9c0bd, 0x8bbf3814, 0xc3c5fe38, 0xdd11a793, 0xee9b13df, + 0x246aed97, 0x772c4cfa, 0xb3b9438e, 0x2736ef49, 0x8f258e8e, 0xec765483, + 0x49f909f8, 0xf7c8c748, 0x0aa0f8f1, 0xa0c580f9, 0x7fd020ff, 0x7429fed4, + 0x1d717400, 0xd73ca5f1, 0x379285d2, 0x5bb2f053, 0x669b7793, 0x601a78e2, + 0x25def2e2, 0xfa78a9cb, 0xf3ef2be5, 0x2bf87dbb, 0xe6a054cd, 0x456fdc2f, + 0x13717c4e, 0xe2679b3e, 0xfa644fed, 0x780ede4e, 0xe4a0627a, 0xeb720b5a, + 0xe766d809, 0xa63e48f8, 0x595f9e49, 0xa09348c7, 0xf368dbca, 0x6f830629, + 0x9f0a2984, 0x8d73f798, 0x334bd08e, 0xd81cfce3, 0x43cf946e, 0x5f765538, + 0xc6912981, 0x40c1ea77, 0x967fd405, 0x0361d959, 0x0ceeeeb8, 0xe1718c54, + 0x5981db77, 0xbae264f7, 0x853e829c, 0x53ace5d6, 0xdf20ce8e, 0x7c50b71d, + 0x3ddb3f24, 0x974cfc8a, 0xf7c71f3b, 0xeca4fbc8, 0x6b75bc67, 0xfdbc5cf5, + 0x21e3279c, 0xcad76e55, 0x2e26418f, 0xf9657a37, 0xf83fe5a1, 0x526f9317, + 0x3b242fb7, 0x6d8c9d90, 0x326fde07, 0xff5179f0, 0x00d4bf40, 0x23ddfeff, + 0xdcec27ef, 0xc343c41c, 0xa39d2376, 0x31d7f850, 0xf18e9bcb, 0xe48a4713, + 0xaeb8c176, 0x7e1a6c59, 0xe8f2efbf, 0xd651bfc8, 0x26e1ff5f, 0x7ea26fba, + 0x7da19187, 0x57ef209f, 0x0c162cc2, 0xbaf9f109, 0xb1e80763, 0xd3fe2894, + 0xee89eb07, 0x5103bf80, 0xd93437fc, 0x2d806e97, 0xdbfac1fe, 0xc0b74cca, + 0x8ccc993c, 0xa82aea16, 0x347c006f, 0x96047924, 0xb675f548, 0x0fe3f181, + 0x2e4d303f, 0xbf04f3c3, 0x6fbe7a32, 0xc438a54a, 0x1c2cb00f, 0x28b22b50, + 0x1d99bdbe, 0xb1f955f3, 0xb0738e46, 0x69469036, 0x9ce2f8aa, 0x2f8a2e9d, + 0x507c8d3e, 0x79fe719d, 0x8da6ae1c, 0x078beb9f, 0x678c8a47, 0x17c4e790, + 0x115ade29, 0xcf857ffd, 0xc925379e, 0x3011ebfb, 0x1dd0aefe, 0x93da29f2, + 0xe31d7e4a, 0x2f8a762e, 0xb0ee8907, 0xc23e309e, 0x742a1b7f, 0x61e2b1e5, + 0xafb64cbb, 0xf23487a7, 0xb17db589, 0x4bd031f7, 0x48b7f835, 0x29976af2, + 0x54d81eca, 0xc78d2671, 0x439d19cd, 0xe39e447e, 0xffee35c5, 0xe1f28e18, + 0x947efcb7, 0x80294671, 0xfdc0aae7, 0xe4d33975, 0xda9d90f1, 0xfc1d9084, + 0xd1cf9add, 0xf37f0173, 0x2f951d73, 0x3cb7b3fe, 0x56d9ed13, 0x032c1b9d, + 0x5c93ebcc, 0x41650f70, 0x9373d013, 0x2a9b9f85, 0x9079b769, 0x1305bbfe, + 0x13e99b9d, 0x19ea2f8f, 0xd7da0bb2, 0x411f01b6, 0xb184bbb5, 0xef57844e, + 0x0ad0f3a6, 0xd89ec77e, 0x63df4794, 0x37dc1be9, 0xcbc55b8a, 0xb6af16df, + 0x894adc50, 0xf4f71593, 0xb5649d10, 0x61f8ea65, 0x5e8f3e29, 0xd792af5e, + 0xbef1926d, 0x226be8fb, 0xb2c2b1ea, 0xef68b586, 0xef7d1867, 0x2e4ddd23, + 0x1339db56, 0x3b76da84, 0x4634d7d2, 0x1fc2827e, 0x20ec5dc9, 0x4f12a986, + 0xcfd07976, 0x73c17c9a, 0x04a9fd10, 0x77f8132f, 0x24f3e192, 0x58ff70e7, + 0x07b8478a, 0x13fc29c6, 0xe328bc23, 0x2a5a3eec, 0xd2919da0, 0x46b82659, + 0x2defa5f7, 0xe04e77e8, 0x5f701ee7, 0xe8687f15, 0x6196462f, 0x2fe9487c, + 0xbd5cb99a, 0x429be7cd, 0xafa34fa1, 0x349de717, 0xa98ed83b, 0x81558997, + 0x84f10c76, 0xd184b3d7, 0x02ba8378, 0x27818eb4, 0x9658257d, 0xf7048948, + 0x3a210be4, 0x96a0312f, 0x5b9231d1, 0xfb25df3a, 0x4eda96e1, 0xf771f701, + 0xef0443d1, 0x5e0ecee0, 0x9af57cca, 0xb814ffac, 0xa27f644a, 0xd5c38e44, + 0x8e9f9e5f, 0xecd181fe, 0xa338c12b, 0x12fa8eb2, 0xbf9e3a5f, 0x3ce782dc, + 0xe73fc426, 0x14966691, 0x8cc1373f, 0xaeecee7e, 0x5a7b4823, 0xf8ed39bf, + 0xb48fda19, 0xdd1ddcd5, 0x80a57c72, 0xc1e5b5f4, 0x22b37ed8, 0x71c8b62f, + 0x14f3a8c4, 0x7ad1cd83, 0x9ac932b9, 0xc28f2515, 0x9e722672, 0x9e7cb762, + 0x6f7aa6c2, 0xa46613cc, 0x27834ea7, 0xdf2b9f07, 0xdf2abce1, 0x71f8a01b, + 0x961ebe0a, 0x9e68d3f7, 0x1086e749, 0xe3a04e4f, 0xbfb1cd57, 0xd6685987, + 0xd3977ac9, 0xf4e4eb0b, 0xb688eb82, 0xb999a633, 0xe3cdbd5e, 0x74e7a29b, + 0x9c788452, 0x476c1454, 0x1e589dba, 0xbffa4768, 0x5274c985, 0x4b44e9ce, + 0x939bf7ef, 0xa1e93a64, 0xe0260a7b, 0xe43145f7, 0xdb998563, 0xa59d2977, + 0x0fc03f44, 0x857ce177, 0x03456a83, 0x339cd0a5, 0xf0f8ef50, 0x9e7822f2, + 0x4769e45f, 0xbc7a737a, 0xa8db8e22, 0xc9ba7277, 0xb8c49ef4, 0xe4aa7d77, + 0x38d02b5e, 0xe0c736df, 0xa7e416ab, 0x4a7e11d1, 0x5a47e391, 0xc3229cba, + 0x1cf193e5, 0x43df1e7f, 0xa74a4f38, 0x33f783ce, 0x4c25b9e0, 0x055c4e46, + 0x96f912fa, 0xd2f9d275, 0x09672aa4, 0xe5a0ddf2, 0xf9f7016e, 0x016fbd25, + 0x3c76b3ee, 0x350c9f45, 0xbffe8879, 0x6268deb2, 0xf2ff8d26, 0xb5db99b0, + 0x7e512b1b, 0x8499f2bf, 0xf0a5d5f2, 0xd6f1d1e5, 0xf3745179, 0xf83a5f74, + 0xa07458a7, 0x3a5a7f95, 0xb50bc888, 0xadbc03fc, 0xedc3fbe5, 0x55ce94dc, + 0x6a1b9722, 0x7f6f1779, 0x0d0dc8fa, 0x3de98f1e, 0x097ae0cf, 0xf39105e9, + 0x74f4f1db, 0xae1ff9a3, 0x31cd1ba7, 0xd4ceb4f4, 0x9f3c1bf3, 0x744da2bb, + 0x5f225c61, 0xf6ba8f3e, 0x4f3a24f1, 0xe09362f0, 0xd1439746, 0x502244d3, + 0x6127b2bf, 0x4a15bb2c, 0x6ae78078, 0xb2250302, 0x08c759cf, 0x24d633ca, + 0x1bac70ca, 0xdbb7fa41, 0x51e600a9, 0x256063eb, 0x91d3fa01, 0x684b181d, + 0xf310783a, 0x988b6b2c, 0xb77000cf, 0x80f3f1b7, 0x485bd62f, 0x7e3eef9f, + 0x400f37f5, 0x1d71e73d, 0x0e047f1d, 0x4ab673a6, 0x03b145de, 0xe8590e3a, + 0xb32f703c, 0x7754d1b8, 0xf8790d8b, 0x21fbec02, 0xe8d983c4, 0xe2281fcb, + 0x77aec439, 0xf1eca38a, 0xccbfd6de, 0xe48ae439, 0x7d0e9a97, 0xdf6d185e, + 0x14a9f929, 0x3996f7d1, 0x963fdfca, 0x77cb9677, 0x055fb9cd, 0x9c5e309e, + 0x5da27f1c, 0x2375f04f, 0x48bf687c, 0x10fb861e, 0xe3d648f8, 0xfb94de32, + 0x0adbba0f, 0xbe80fa4e, 0x98393c5e, 0x7b5be1c7, 0xef7768cd, 0x214ef932, + 0xf4b7899d, 0xf6a9f9d0, 0xe811deb6, 0xf9fc834f, 0x1ef79f08, 0x9d149b3f, + 0xeb12feff, 0x3f5a24fb, 0x729f5bc4, 0x1f4b5e3e, 0xda167dda, 0x184dfe0e, + 0x50c07c4b, 0xb086054e, 0xf567fa20, 0x17adc663, 0x31672371, 0x341dc517, + 0x999fb479, 0x8e65ffbc, 0x4c679fe2, 0xde21bfde, 0x4efc1e71, 0x05f9d603, + 0x989ec7d6, 0xdb478f9f, 0xf53ac2be, 0x18fb9896, 0x215afda2, 0xe60567af, + 0x537cf0fd, 0x3852e18b, 0xef231ddf, 0x8091fb07, 0xdd4a05e3, 0x9fb87d27, + 0x6bdcd81f, 0x4efa1f11, 0x0091da27, 0xb3b6227f, 0x97ba4aa2, 0x50f060c7, + 0x3ad5f47e, 0x5bbd7e7e, 0x1e31b8b0, 0x6491dcd6, 0x33f87941, 0xfb1d2f93, + 0x9d5dd48f, 0x09fa7183, 0x3cdd5e9d, 0x41be53d2, 0xe753b216, 0x8e09eaf7, + 0xdfda315a, 0xcfeb12fe, 0xe7dcc4b1, 0xc790fb3e, 0xa1f7c5d7, 0xf462e7df, + 0x3e9c7bfc, 0x45d651f9, 0xfb83f6f1, 0x3cc5c93e, 0x4f81f552, 0x7ead3fc8, + 0x5b9b48c3, 0x0488c6f6, 0x252be3a4, 0x4b89edb1, 0x1eb75afe, 0x967199ec, + 0xcb9b922c, 0x23dd2759, 0x61e9a2b0, 0x5e4a3eb7, 0x71d3f62a, 0x8e056743, + 0x6440bc7f, 0xbd774075, 0x580389ee, 0x94ac390c, 0x097b45bf, 0xfd1f7f60, + 0x9f9bd4d2, 0x9de6d283, 0x338fb4fb, 0x42a11c53, 0xb3cc8763, 0x88f73d70, + 0x8fbc325c, 0xbcbce005, 0xe0e74ed7, 0xcf7f8f2e, 0x5c4b1f81, 0x7e5df96e, + 0xb0ffcf00, 0xbf3047ce, 0x8d8bf816, 0x718aa8fc, 0xd9d7e5ef, 0x3b76fc23, + 0xdbb0418f, 0x70e13f5f, 0xe68aff41, 0x144094f6, 0xa1e7b4fe, 0xc7d7911e, + 0x6e745df4, 0x98bfed84, 0x563ef786, 0x829c3bec, 0xec37fdeb, 0xaedfc318, + 0xf44d5d58, 0x9f22d533, 0x1960caa3, 0x8bfa0f28, 0x0573ed07, 0x5dc7c70f, + 0xf77a821c, 0xd23b1c4a, 0x75ebf72f, 0xf6801a4f, 0xca14854d, 0x55bf1589, + 0xbc2d2bfc, 0x3b373b37, 0x58f7e243, 0xb6af9f6a, 0xebdf3d70, 0xf000b336, + 0x068d23e9, 0xc4eeaefa, 0xcacc3fb5, 0x64f8fd87, 0x06b9c1ab, 0x85eaadf8, + 0x309bc1f6, 0x48ce395e, 0x5c4f97f1, 0xcba41ca1, 0xf3f02fc5, 0x7d6c9fb8, + 0xc8f30d24, 0xb5f409ff, 0xdc58e01c, 0x55e7a068, 0xe7a7df8d, 0x5bba6517, + 0xe52a42fc, 0x3c744f97, 0xaceb869d, 0xdf93fbfa, 0x966ffe41, 0x41c6a39c, + 0xa0977cb9, 0x74b7773a, 0x575559bb, 0xbacad2f2, 0x8f391099, 0x7e7802e7, + 0xe79af969, 0x89f57780, 0xc2d2fe5b, 0xdd6f8bed, 0x2eaeeb07, 0xaefb25e8, + 0x8c8588fd, 0x44db5fa8, 0x71a1dfd2, 0xadd6f5ff, 0x77f29f50, 0xd31f9bbd, + 0xb239274d, 0xece5c4c8, 0x70fa7d94, 0xff719cbe, 0x615776dd, 0x08797cfc, + 0xdbd200e4, 0xe18a9f94, 0x79f479bc, 0x5cde6d54, 0xf36b8fc9, 0x029c78e6, + 0xf2cdf1e5, 0x1c3f0ae6, 0x49cf84b3, 0x1fb7dd12, 0x45f279e1, 0x2f6e45c7, + 0xfc4e44dd, 0xe3d6e116, 0x107b1efe, 0x6427dde3, 0xf6b89c6c, 0xafbc3ac9, + 0x012293e1, 0x93ec2033, 0x58f2c66b, 0x2287707c, 0x659cf02f, 0xef5f645e, + 0xd7092f71, 0x5dbe0d91, 0x1ceab0f4, 0xd5e5ff68, 0x49f0f98d, 0x419eff0b, + 0xfcb4cf2b, 0x67928ff2, 0x0f0ee315, 0x7ca9d809, 0xcd4bcb19, 0xe568ae5c, + 0x14a7581b, 0xe4e55a87, 0xa5c0a2f4, 0x5fc57785, 0x3f3058b3, 0xf5177e1a, + 0x94efa15b, 0xf8acbe50, 0x260b2e6b, 0x50fea37f, 0x3f8635b2, 0xf095fa04, + 0x07d42815, 0xfd408fd1, 0xdb46fd8f, 0x0025c95c, 0x96673ad2, 0x2772e515, + 0x416b7fe8, 0x6a313e24, 0xe50e8357, 0x376fd845, 0xc577fda8, 0x72b2c95f, + 0x795a31ba, 0xddfc98fd, 0x5df3bc4f, 0x3c4af8ca, 0xf184bea4, 0xb91273ef, + 0x839ca6fd, 0x3967eb5c, 0x933e3df8, 0xd26bc3bf, 0xc8f0eff1, 0xfcf5c4a7, + 0x83fdc8d8, 0x5c5574bc, 0x29bf09f0, 0x792def07, 0xf7a4efd2, 0x53a7f29f, + 0x8bbf23f9, 0x79fc67ca, 0x135efc39, 0xc7c8fe46, 0xd18d2c87, 0xe49b04e7, + 0xb093cdbc, 0xd062d7de, 0xe55623e1, 0xf497a03c, 0xd8d2c2db, 0x567bfdf2, + 0xe4a5e13d, 0xa087fbf9, 0xc1f1f1dd, 0x097dd1ef, 0x83e26b1f, 0x6e6f250b, + 0x13f37d2c, 0xc9379f99, 0x32c7e5fa, 0xfd900d7f, 0x9e729047, 0x4f78d1e6, + 0xff773f30, 0xc31dfcac, 0xa9abfd4f, 0xf3cad3bc, 0x8ff76923, 0xf0073b7f, + 0x3f036e75, 0xa4ce749f, 0x6cf3bf23, 0x85bcadad, 0xfd8ef0e0, 0xde76511f, + 0xf1dc329d, 0xfd6355d6, 0x057e726a, 0xdea072eb, 0x876fd30a, 0x5c3e1e3a, + 0xfa432df4, 0x695d66eb, 0xe846afd8, 0x2315ddcc, 0x79209b8f, 0xff84ac6b, + 0x5f28219e, 0xed02fd95, 0xfefa2a31, 0xe72b228c, 0x7ce38fcb, 0xa65ab6ff, + 0xcf25dbdb, 0xfa9e3e6a, 0x195fc37e, 0xf2b43f3d, 0xb4ffe678, 0x8c02f9ca, + 0xce4894df, 0xdb9d7c70, 0xd635dedb, 0x78997118, 0x8e16bf7e, 0x9e9c6c5b, + 0xa500f1b4, 0xcf01e254, 0x65044da0, 0x7049d5a6, 0x1803e36b, 0x07158d27, + 0x8f2b4ff8, 0x3c7ba61f, 0x9f15d5a2, 0xcef8272f, 0x6c9b7dd0, 0x7bf3a336, + 0x0e9b8a03, 0x60643c62, 0xd90eb059, 0xcb513ea5, 0xc63301a7, 0xba7cb249, + 0xa4dbcc34, 0xa33f0275, 0x6a9781bd, 0xd69d22a5, 0x4f5d21d6, 0xf168e9f0, + 0x412c3a13, 0x54e67141, 0x660266e7, 0x0bfeef39, 0xda82f3c2, 0x1db718b5, + 0x797fbcb4, 0x9f7936f7, 0x84d9bc95, 0xc3c206ed, 0xa63fed84, 0xed84d6fc, + 0x2885eb77, 0x35693efe, 0x878bff50, 0xff250e97, 0xaa39ce38, 0x26dc794e, + 0xfc417bc4, 0xadc710f3, 0x8879f8df, 0xb8a8d6e3, 0xab8af54a, 0x5a77c724, + 0x39f8feb9, 0x9f0169e6, 0xe4a05f3f, 0xfe291b69, 0x9a6a5bb6, 0x40887986, + 0x43ce8eb5, 0x0bdcf386, 0xf08f79f8, 0x86ef98fb, 0xe2af3fe7, 0xc181eef9, + 0xf6df2967, 0x03e79999, 0x6461db3f, 0xf25d2798, 0xefe51376, 0xb1d72cb6, + 0xc364f758, 0x9cf9064c, 0xefcf018e, 0x7ca3fee0, 0x081df653, 0x08fdc24b, + 0xf9b5c3e7, 0x8bae193f, 0xe9723e72, 0x4869e6ce, 0x93cb1927, 0x563fbc04, + 0xeaebeb81, 0xbf506f91, 0xe5f7975e, 0x6f55fa66, 0xb55fa18b, 0xe0d3b57a, + 0x6f52da31, 0x641b5fae, 0x2ab5eafa, 0x78e406e7, 0x6247e637, 0xd633cbec, + 0x34ce713e, 0x738857db, 0x3149adfa, 0xf7ca9ce3, 0x6c490d9e, 0xfc18ccee, + 0x37cc98f0, 0x743dcdba, 0x4da5230e, 0x4a972988, 0x17c94924, 0xc545b08d, + 0x35f2b5c7, 0xd8dd7e06, 0xd0aec47f, 0x3e35ec21, 0x668ac731, 0x9c73e000, + 0xf2719f0a, 0x9533bf0c, 0xe4a27d90, 0xd49a2e15, 0x6c77dbf6, 0x6dcf3f4a, + 0xc4b78fb8, 0x6c53db91, 0x297f0282, 0xc5594bf6, 0x2572f154, 0x1b529e4e, + 0xaffbf010, 0x3f230f14, 0xafb26862, 0x7afd00ce, 0x36f73126, 0xe83c27a8, + 0x9779412c, 0x883ee554, 0xcbfadda1, 0x0fcaf7f2, 0x395efa33, 0x65f5ef9c, + 0x7883bd91, 0x4f0efe8f, 0xfaca0fd1, 0x6bdd6f40, 0xb2cd70e3, 0x7d6f40dd, + 0xcf317c83, 0x58be3fd6, 0xf769708c, 0x81ef1b2d, 0x7fd98d4a, 0xb0feac45, + 0xd9fdd5cf, 0xbc720de7, 0xa4f9bfbf, 0xf5f0bd46, 0xf17de5e2, 0xbc2c44f2, + 0xe5d0a86c, 0x009479e1, 0xe963b8b3, 0x7fb62d9d, 0x8b7edc78, 0x9edc462d, + 0xfebf24dd, 0x49773fe2, 0xe2560f18, 0x507b61cf, 0x9e575793, 0xf909b757, + 0xb49597e8, 0xb7fb235f, 0x64e7e0fb, 0x8fcdf6ff, 0x025779f3, 0xdc7f2279, + 0xbf6f9f25, 0xf7fb95ba, 0xa4fd7322, 0x39a8e018, 0x6841606a, 0x606f8abf, + 0x882116fb, 0x3d5f0bf7, 0x8bea853a, 0x192c09f7, 0xe9e02409, 0x160cefc4, + 0x425e3e30, 0x8f754e91, 0x7d47a275, 0x7972784f, 0xea9eaa92, 0x3e13df55, + 0xaa967660, 0xa46fa07d, 0xd5507daa, 0x96fd5578, 0xe13df55a, 0x457f4143, + 0xd30333d7, 0xd7b3fd55, 0x0faaabdf, 0x13df506b, 0xcbadf8ae, 0xdf0cf5e4, + 0x2f7d4f32, 0x61084877, 0xbca163be, 0x38e40bdd, 0x52e088c5, 0xc4cb38d5, + 0xbbf0470d, 0x57de9b8a, 0x7448dad4, 0x68afbdaa, 0x7d754ed9, 0x46fb89ec, + 0x5e0cf3f1, 0xc675373a, 0xdc5f8ea6, 0xc3035f74, 0x1abed6bf, 0x6afbd5d3, + 0x886e5976, 0x7a9e6b37, 0x6f7c999f, 0x766f168c, 0xbfff7ab7, 0xed19bc69, + 0x0c193c6a, 0xe31d8b3e, 0x44abad80, 0x5cb2defa, 0x4bee4e7d, 0xed93ddc4, + 0xcaeee231, 0xcf376abd, 0x0dffb4a7, 0xd04664f3, 0x173c0634, 0x8536e455, + 0x48e627f3, 0xaf2b5d9c, 0x75e41294, 0x2af29d8e, 0x5ad3bc91, 0xff21df86, + 0x2b708bde, 0xf7588979, 0x05ce6880, 0xbe71c68e, 0x4d0afdea, 0xd240e7f8, + 0xae76f983, 0x51ec0b07, 0x8739507a, 0x78c1e8a2, 0x897928e3, 0x4870a578, + 0x0f44b8a4, 0xc86257e6, 0xbfdb6ff1, 0x7be93ea6, 0xf6dbf38e, 0xe0bf2882, + 0x5047bdfb, 0xefde039e, 0xedd9f5c5, 0x888527a0, 0xd589fc9e, 0xf3d3fc41, + 0x3c38311b, 0x48be7233, 0xe1689fc9, 0x0f7cd62d, 0x87b9a6d9, 0xb73c7eb4, + 0xb9dae63b, 0xdf2c3d5e, 0xd7235143, 0x7a76346b, 0x8fee7acd, 0x6d15bde2, + 0x8d5ff651, 0xe7fd4edd, 0x106a4be8, 0xf70b46ee, 0x8105eaab, 0xa67d78f4, + 0x6e3ef340, 0x71f6a52a, 0x5c6a92f6, 0xacb930f7, 0x2a5e58c1, 0xed443bdd, + 0x5efb1892, 0x6e765582, 0x7896cf2f, 0xddfd2fff, 0x0ee60ad4, 0x9bbe44a5, + 0xd3be7162, 0x3d83c6d7, 0x140ece79, 0x3bf55f8b, 0x9a1fc42a, 0x3f1d0ade, + 0x43e70f63, 0xfaf9fbe8, 0x66e7aecc, 0x109ebee0, 0xdb1e78dd, 0x1d602a75, + 0x57c7829b, 0xa02256f1, 0x8d6cad93, 0x038bea19, 0x18f78a2e, 0x8fb25fc0, + 0xcbddf08f, 0xc7c24cf6, 0xd3219398, 0x789f6858, 0xe3107bca, 0x58b3b9c3, + 0x06ed8a12, 0x7f0530d6, 0x55b0291f, 0x5ab31bce, 0x19abfdfa, 0xe8a52b25, + 0x5ba94073, 0xe2f3a61f, 0xf87579ca, 0x28fc4167, 0x9e47dff7, 0x4338f3f3, + 0xe32f654d, 0x98e5297e, 0xc578ec60, 0xccbbf96c, 0x5ddef587, 0x5a63dfb8, + 0xbddee8ba, 0x5b1c8ac5, 0x9defa3a0, 0xe1f793ef, 0x0f3cadbe, 0xbf5daecc, + 0xce46162e, 0x0cf8c1fd, 0x2cf173f9, 0xb3bbdd3b, 0xbe932db8, 0x815e668b, + 0x6d351be2, 0xbf497b6f, 0x44e0984c, 0x01f3d37f, 0x4b7ef013, 0x039701c4, + 0x952efbea, 0x95efd37b, 0xa77ca7d7, 0x8372f20a, 0x78bbf015, 0x81a1dd6b, + 0x2f7bde30, 0xa18fba31, 0xf240acf0, 0x37168981, 0xcb85edda, 0x05cfba04, + 0xbdd1f40f, 0x6d862314, 0x7e3b8e8b, 0xb78bcb2a, 0xe5a078fe, 0x9c297404, + 0x2a48f952, 0xfda768ec, 0x5dfc54c2, 0x95fdc2a8, 0xa338648f, 0x7b2a9bea, + 0xde11bb07, 0x80cb530b, 0xe760fe4e, 0x85d74cf0, 0xd9bbfcf4, 0x543fca4e, + 0xd20f24d8, 0x9d2d8569, 0x80ae37ee, 0xf400bdad, 0xdfa3fd35, 0x9f2e51eb, + 0x05f7cbb2, 0x5c5cb2e4, 0x77c3b267, 0x2accf89e, 0xaf10339f, 0x0fb68d8d, + 0xe539f4a3, 0xacdbba47, 0xf9586994, 0x3fe53666, 0xfbb4f795, 0xdf9f9cfa, + 0xf0ec9873, 0x57fdc79c, 0xfade81fa, 0x93ddeb1c, 0x1db97f3f, 0xfc52bdc6, + 0x17082197, 0x677e8fe0, 0x4ebfb941, 0x296dc719, 0x3f2762b9, 0x3f717986, + 0xf9e3936e, 0xbb6d9d93, 0xebb7dd71, 0x0e516b42, 0xa9fef9be, 0x28671c64, + 0x3eb8e078, 0xf5d573f8, 0x4570bee4, 0xbf7abee4, 0xf9f0a70b, 0xef2bbf0b, + 0x8bc79b9b, 0x500df7bb, 0x0eed8bc5, 0xbfb86fbe, 0xc0937fd4, 0xcfd9f1ef, + 0x937c564b, 0x9055fef7, 0x05824f7f, 0xe577e844, 0xc00fde4d, 0x66a87f21, + 0x13a270ff, 0xb3cb839f, 0x51e7acc9, 0xb6e4e75c, 0x87efa77f, 0xf2792b27, + 0xb93cea0b, 0xe2a59f0f, 0xf43d23b5, 0xb5f7701d, 0x63796fde, 0x43a95bf0, + 0xfbf0fbc9, 0x837ec3f0, 0xf87e1f7c, 0xec5342bc, 0x7197f0fb, 0x89f120ca, + 0xc52f0fdf, 0xe12fe03a, 0xe907f9ef, 0xc166c1fc, 0xb04c798d, 0xcfef5483, + 0x87ded3c8, 0xf17fefcf, 0xe3df93c9, 0xc91f33ee, 0x1e194adf, 0x5dff1b5f, + 0xcf3c0e82, 0xdeea7803, 0x51377fc0, 0x777fcf7b, 0x05b7e739, 0x4ba085eb, + 0x553bfba0, 0xd6650bed, 0x6776085e, 0x3cec9328, 0x3dc477cd, 0x5c5f6c5e, + 0x041befcc, 0xded34fbb, 0x754fe0a0, 0xf961ec4f, 0xfe1671f7, 0xf237d658, + 0x64f32fbd, 0x590f31f8, 0xaf591692, 0xf9147fa2, 0xe16050b9, 0x1abee9f7, + 0xed463ef9, 0xbb95e7fa, 0x36f3cf09, 0x761c6e08, 0xd067aff1, 0x078053f7, + 0x2f995e95, 0x837e73af, 0x6ff3e740, 0xb2a98f76, 0xeeb845ee, 0xaef6becc, + 0x50587ef6, 0x5f842e6f, 0xc6b1f990, 0x49afe1c8, 0x885f7466, 0xba25ec90, + 0x125dc780, 0xf83b0f94, 0x0de10b39, 0xe627c923, 0xf2937b05, 0xe44e6574, + 0x85058143, 0xcffaa3eb, 0x30fbe1af, 0xf842e7c2, 0x12c98efb, 0xc74cdbf9, + 0xca3b6dfd, 0xd223d01d, 0x4e10dac9, 0xf2b126b7, 0x67bc0731, 0x20f06aea, + 0x342e58cb, 0x2cdcb085, 0x3e7bbbc7, 0xaffc1134, 0x846cbe0b, 0x2a18a27f, + 0xe79af927, 0xee93341b, 0xcaf9e3af, 0x167f328d, 0xaefa06b1, 0xa26b3260, + 0x527598b2, 0xa1eb0779, 0xac5f83d2, 0xe03da364, 0x798cb2a6, 0x6aca9ca9, + 0x0d672ca9, 0x712b7e54, 0xc002625e, 0x51359d35, 0x39e402bd, 0x32890bdd, + 0xf74de319, 0xeecec89a, 0xac1cd37e, 0x0e6af800, 0x38bcb918, 0x577d2560, + 0x08466073, 0x1fddf9e3, 0x7bf85cd9, 0xa7b176a0, 0xbf48e29a, 0xf7f93ab6, + 0xbdd52e34, 0x2bb935dc, 0x78e3f77b, 0x7c7f421f, 0xbaad9e90, 0xafe27ba7, + 0x7a8f907f, 0xe1ade260, 0xe81cf27b, 0xcb6d5fcf, 0xcafe3f26, 0x9446dd40, + 0x5219d5d3, 0x7ab7e23d, 0x95ee8598, 0x05d3cee9, 0x415b2824, 0xe9fde3fe, + 0x05efe06f, 0xff26d940, 0xf901c05e, 0xde10f57e, 0xdab60eaf, 0x951e7f21, + 0x95377e1d, 0x5445fc47, 0xa87bf51e, 0x397f31df, 0x5efdc795, 0x9d1eaf2a, + 0x77c7df4f, 0x839e9fa7, 0xc87427bf, 0x19a4f951, 0xb28fe1f4, 0x44fc2e7c, + 0xfdf4eb08, 0x45aec0c8, 0xd508fdf8, 0xd7d67f41, 0xd19dd2f9, 0x555352ed, + 0x92ea1db8, 0x7008fdfc, 0x629e93d2, 0xea4527a8, 0x118dfdf8, 0xbc199ce3, + 0x57f3065e, 0xfb5220bf, 0x303f7811, 0xc72bd618, 0x2e094ca3, 0x03461f2e, + 0x74e18cbd, 0x7c65df83, 0xea99d5d8, 0x69762310, 0x4e5c13e5, 0xedc0be54, + 0xec67cace, 0x9eeef7f2, 0xef0d2132, 0x89cb511d, 0xf94c45f9, 0xbded13fd, + 0xea2c45a5, 0x83b9983e, 0xe60f2475, 0xd3f756ae, 0x4ce807ca, 0x95aad3bf, + 0x643a1f0b, 0x8d9733fb, 0x97faefc1, 0x1d93b1cf, 0xa76ec976, 0x763f7a73, + 0x0164a475, 0x44fbd5bc, 0x0ab413ca, 0xb5b07640, 0xeab8de7f, 0xced0136e, + 0xd7a7159d, 0xbeb1b8a6, 0xaefc49fa, 0x4ff352e2, 0x233aa4a7, 0xf4ec59f5, + 0xdda007c6, 0xddf56eb9, 0x2ffac0f7, 0xb8c0bd23, 0xfc0d5b97, 0x12939b1e, + 0xded32efd, 0x0b21af4c, 0x763f7bea, 0xa6ff3c33, 0x99bbf5e0, 0xbddbfbfc, + 0x2b41be99, 0xa7deab47, 0x1afd61df, 0x6bf133ef, 0x00dc2fbe, 0x8a7bed7e, + 0x7efbdb5c, 0xa77f0dee, 0x6dead976, 0xcea27243, 0x37d32c15, 0x658279d1, + 0x921e5fab, 0xa5cdf603, 0xe88d96e2, 0x7835ef77, 0xf942ef12, 0x71e06cd5, + 0xec904366, 0x89af4f80, 0x02466f34, 0x0609fbd7, 0x7c249f6e, 0x3d446a68, + 0x1382f603, 0x6bdcafbf, 0xa439f0e6, 0xc112572e, 0xc2c3ebc9, 0x86f1f1ef, + 0xf7b97025, 0xb25eb5e9, 0xd76e7ba7, 0x8082efd3, 0xc4faa07c, 0x6884523b, + 0x226f67bb, 0x8af3de7f, 0xcc52fd48, 0xf1e8c49e, 0x2f1debb5, 0xdcd7b7cf, + 0xc53f1aa3, 0xd653dfc0, 0xe36f9da3, 0x9de51324, 0x496e289e, 0xb2ebfcc3, + 0x207bfe12, 0x8abc3245, 0xa3f1357d, 0xe1a3dba9, 0xeeff289b, 0x26e4ceb0, + 0x557079fa, 0x7dfa38e2, 0xe297a742, 0xe71e73fb, 0x38f269f5, 0xe08e4520, + 0xdcb9e772, 0xf20cd153, 0x28657c39, 0x79e417b7, 0x8afd608f, 0xf510a7a1, + 0x24aab886, 0x33de0030, 0x9f495e3c, 0xd5d719f7, 0x6f34b005, 0xe1036468, + 0xcdcdc2f9, 0xa13df70c, 0x8a176cf9, 0xefe69499, 0xaf6d7c53, 0xd813a641, + 0xfe51998f, 0xa96736d7, 0xd7e60137, 0x391db939, 0x4245ac7d, 0x467a607b, + 0xf5f9d906, 0xcc1cc1a5, 0x308cf70f, 0x3a627c53, 0x9f80258c, 0xc5886c72, + 0xd412fe83, 0xcf58893d, 0xa7fd4c98, 0x86591d8f, 0xc658f87a, 0xb78c74f7, + 0x9e2bc7af, 0x5fc0658e, 0xc21fda0e, 0x8969cf57, 0x963eafbe, 0xf92a74b1, + 0xbd382315, 0x6c78cb1f, 0xd22bf62a, 0xc2cbee05, 0xf289a176, 0x70278fae, + 0x0c5d3f3d, 0x09efc71d, 0xcef819ef, 0x566ff471, 0xc77ec826, 0x622b9018, + 0x5c981fc4, 0x9f8edcd4, 0xde7b15cb, 0xeaea829e, 0xb73ff28e, 0x26f1e963, + 0x2f7aa196, 0x03ae3d9d, 0xccdf32cb, 0xe8731032, 0xf88e3caf, 0x70f55a9e, + 0x01ffd607, 0x88e3cafe, 0x55c992e7, 0x9f37fbf4, 0xa3e5dfdd, 0x7024e93c, + 0x7dc463d4, 0x4b09f622, 0x781af7e2, 0x485f5092, 0xdf7db86b, 0x7b244fb3, + 0x39751582, 0xea6e5c74, 0x33aafe90, 0x9e90d2bb, 0x38f207eb, 0x976715cb, + 0xfdf2ea83, 0xf322ff02, 0x57624541, 0xc561d21a, 0x9e0261be, 0xe1e2bd3b, + 0x56a04a76, 0x3061e7e4, 0xff2694cb, 0xd51678ee, 0x93fceec9, 0xfcf5ebc0, + 0xf3d676ee, 0x23ed237d, 0x2f10cf8c, 0xe30f0f3d, 0xeabe0170, 0xb92f5ef1, + 0xb983c33f, 0x52abf748, 0x87f21ee9, 0xfc24a72c, 0xe3302469, 0xae3e50d2, + 0xe276ca68, 0xef06cdf3, 0x15f71a4c, 0x96e389c1, 0x3c966cef, 0x2a4fd236, + 0x90f41e3b, 0x7ba7eed6, 0x3e32e687, 0xd126dcdf, 0x9aba0663, 0x03fcd2db, + 0xeecd2e81, 0x8ff7c832, 0x4d6bdea9, 0xfa9f74e0, 0x4fba66cb, 0x87ce1976, + 0xee81ab65, 0xab365d95, 0xf1443245, 0x3dd6b2cb, 0x577cafd4, 0xcbc5e533, + 0x2f64ecf3, 0xeb0d634f, 0xdf2d5f28, 0x53e3e457, 0xc9add3b0, 0x65003fcf, + 0xbe399fc5, 0x3efc53d8, 0x0f83f9b5, 0xbb2f91d9, 0xfc53960a, 0x942143e7, + 0xf8bd001a, 0x0ee76650, 0xc92e1ff4, 0x0fd68ef6, 0x0b1dfad1, 0xa2a7335c, + 0xdfd7d149, 0x38e8b660, 0xb03f168a, 0xdef11b1d, 0xa24d45a3, 0xd131ef13, + 0xfe0a23fa, 0x953f78b4, 0xc7db2290, 0x3f706320, 0x20eca69b, 0xfa71933f, + 0xd6017b20, 0x987dc971, 0xd39ab3ee, 0x6279efc4, 0x8a14a13d, 0xb3f06b03, + 0x8cda1f41, 0xd60549f7, 0x02fee819, 0x5c02fe1f, 0x8dfdac52, 0xec4a27ba, + 0xeb2d3f5b, 0x5bcf3ecb, 0x7a775fb9, 0x1b9f28bd, 0xdbcfb751, 0xb3247f97, + 0x26fbe31f, 0xeed27df0, 0xcfd002c7, 0xdf8217e4, 0xafa97287, 0xdfa5e85f, + 0xfed9b883, 0xdffff828, 0xc7a90a29, 0x00008000, 0x00088b1f, 0x00000000, + 0x7dedff00, 0xc554780b, 0x3d9cf0d9, 0xcd8dcd7b, 0x09c246fd, 0xb8094404, + 0x9fb1dc24, 0x4a34021b, 0x414045d0, 0x2dc8d812, 0x088d9242, 0x59b6b696, + 0x5a4062e4, 0x7da5aac1, 0x2c142ea8, 0x11a0d05a, 0x86ec5d43, 0xba8b4508, + 0x8ad45cb1, 0x14178026, 0xb16d0042, 0xfbdfad1f, 0xbb2733be, 0x6a2364e7, + 0xffefefd5, 0x27a3cbff, 0x9cccce73, 0x997ef799, 0x6318c399, 0xb17fc39f, + 0x50dff876, 0x261d8ac6, 0xd8c21b27, 0x4fab569c, 0x8a6c61c9, 0xef74676b, + 0xa79cc624, 0x18564c0d, 0xedfd2e6b, 0xd543262f, 0x8ad79b24, 0xcb7693f7, + 0xcd942f0e, 0x3b58eef1, 0xdaf4b7b4, 0xd5f6c468, 0x512c490f, 0x6724ac62, + 0x618b126f, 0x9b0e576c, 0x7783cae5, 0xd0daefe1, 0x950ed135, 0x6cdb1992, + 0xfb622577, 0x1b32dee7, 0x1ec60f58, 0x87f5e78c, 0xe3db99bd, 0xfd5098b6, + 0x687f5841, 0xd5b23ca8, 0x467f58c0, 0xe8c79c3f, 0xb318a30f, 0xebdfca86, + 0xaf94d048, 0xa9a198bd, 0x68fac85f, 0x0759179e, 0xb38f9e68, 0xdfca6817, + 0xa9ad1b4f, 0xa4529d7f, 0x3fe84f29, 0xa27f5341, 0xbca6b263, 0xeb8ac8d6, + 0x63675e61, 0x8f4b5e8c, 0xd8463cd0, 0xb787040d, 0x478702d3, 0x683b584b, + 0x8576c572, 0xa98d5957, 0x7dec35a3, 0x9c38da0f, 0x819c5d58, 0x4eec630d, + 0xffa899f5, 0x58df0143, 0x7be0d599, 0xdd46a303, 0xb5bc046f, 0x160d941f, + 0x42f32fc0, 0xcec614bb, 0x1a17768b, 0xbe207a0b, 0x7f7e01d8, 0xdfdf8d91, + 0xded1f025, 0xc335e0df, 0x816b5bb8, 0xde85fa26, 0x660c56e3, 0xdd7e1843, + 0x8259b28d, 0x730370f2, 0x17dd7be3, 0x1059cccd, 0x5163071a, 0xde76bdfc, + 0xe64e3abf, 0x8defe68c, 0xaedff7e7, 0xec62e245, 0x5d2b5a9d, 0x82cf0e7f, + 0xc0633e38, 0x691fa0cc, 0x34f8cc74, 0x06f6b7a0, 0xfa016ec9, 0x366c6cac, + 0xed17f8e3, 0x316549cc, 0x5ea7e15d, 0x31a6d78f, 0x5aabfa05, 0xd52ab2dc, + 0x1f6ef401, 0x682bf752, 0xe303555f, 0xb1a91200, 0x965bab0f, 0xbb62d8cb, + 0x6716f442, 0x7f43f981, 0xbff4feef, 0xf0073ccf, 0xd4b3fe3b, 0xfd07e47c, + 0xffb559f3, 0x17e8f4fc, 0x27f77f3c, 0x83f63f7f, 0xd3ff6a2f, 0x65fbdecf, + 0xc6eef3d8, 0x932ebb3f, 0x30746129, 0xace1cccc, 0xe90cb7af, 0x3b3ffa0a, + 0x358f1fea, 0xb2497f43, 0xe01d997b, 0x27cd7edc, 0xc51e0cd9, 0xcc34bf0e, + 0x37e2131d, 0x095ffb7d, 0xb1bc037e, 0xfb338018, 0x15b7cd81, 0x0ddf06e9, + 0x924b63e5, 0x5e906b7d, 0x669ac15d, 0x95b1f718, 0xe06b1c7d, 0x0ec7e53d, + 0x86f7338e, 0x2f3cb1f2, 0x24cbfbc3, 0x2cfb8307, 0x3a446acd, 0x5703899d, + 0x2b2ef868, 0xd31674e0, 0xf9d02dd2, 0x7c61adfb, 0xb6a96b33, 0x96d5ee5c, + 0x61fce387, 0xd899cf1e, 0xbc30fab4, 0xeffcc4fb, 0x047c2f89, 0xce3b8be5, + 0x5376e54e, 0xfac85dc7, 0xbfb4f58c, 0x81fa2d1f, 0x32008e39, 0xb7b2f1c5, + 0x9fcf34ac, 0xf89183e1, 0xf2266f3f, 0x4f82dbe3, 0xd6c4c4cf, 0x6707c049, + 0x6f070e14, 0xd2e1cc8d, 0xed056013, 0x6e2777ab, 0xdfc0b822, 0xb3ee5451, + 0xa4c7cb19, 0xde17b240, 0xfb07265b, 0x28cffbe2, 0x1d630fad, 0x4668e2ef, + 0x53b491ed, 0x10fa7c04, 0x30f3148c, 0xe7801f01, 0x69d946cc, 0xf1f0441b, + 0x29a3e0ea, 0xa8d0fe8f, 0x43af7f29, 0xa2f6be5b, 0xb4c85cb6, 0xdaac8bed, + 0x8e02cbf2, 0xfbdaece3, 0x96d34fdf, 0x1e3a55df, 0x1d8bf2e2, 0xf3c30dca, + 0x259521cc, 0xcfe00e2c, 0x179c66ec, 0xb864f78c, 0xc11e2b1c, 0x3adb78e1, + 0x21cbe7c9, 0x5f9e6afc, 0xecab1cc7, 0xdaf74879, 0x418bf0fb, 0xe82b9a7a, + 0xed3aee67, 0x19dfebf3, 0xbc019e35, 0xe325d84e, 0x207f78fb, 0x4e78881b, + 0x419f738c, 0xc744f03e, 0xc37d420d, 0x46b9ede4, 0xabd9ff78, 0xe3990e6c, + 0x3b21cb81, 0x3938ff1f, 0xe7c011c6, 0x058768fe, 0xd3da2d6e, 0x8fe51527, + 0x37cf5eda, 0x52dc800f, 0x9c7be1fa, 0x99af4867, 0x25d20559, 0x28fa021b, + 0xe4c2c81d, 0xf6878f8c, 0xceb71dcf, 0x3be04772, 0xef955ce0, 0x77c8259c, + 0x35f4e63f, 0x1ec8cda6, 0x352c71c7, 0x9c20b26d, 0x8fc427eb, 0xb999fa03, + 0x5b9df38c, 0x3064ac0a, 0x647b99bf, 0x25cce782, 0x44498f92, 0xf435e72f, + 0xbea0f022, 0x5e71f00f, 0x329a5fc7, 0xfdd12850, 0xecc62683, 0x678ebef0, + 0x1466df25, 0x648d53d9, 0xbb6d542f, 0x337047c2, 0xef1117b2, 0x2a8f816e, + 0xa81e2323, 0x0658fe04, 0x4bd4e7f5, 0x178fae34, 0xa8067c5b, 0x261db55f, + 0xae3fcf08, 0x2824f931, 0x3328dc7f, 0xbeb10fce, 0x7db550be, 0x7c2f2f3b, + 0xf82d96fc, 0xff3c5dbc, 0x2db8fb78, 0xa2b5bef8, 0x9062ef7f, 0x6ddf504b, + 0x3e6b5664, 0x0259b75c, 0x63b7a076, 0x4757f651, 0xe8ed3d21, 0x3e0cf0f3, + 0xc618c524, 0xab59c74f, 0x85d0e109, 0x9f03b69f, 0x2be575c5, 0xa0f1d237, + 0x50b9f4ae, 0x839039aa, 0x9267e372, 0x95d2ab63, 0xa974f54e, 0xc17cedd2, + 0xd9b3d01f, 0x1bca1035, 0x1d38f5f4, 0x1fd635ac, 0xb9e715b9, 0x3bfea642, + 0xb71009e7, 0xdc2d4902, 0x28c8f7d1, 0xdabe5e78, 0x32efe884, 0x33f3aecf, + 0x6ce6fcd1, 0x673274e7, 0xa453e4a9, 0xcfd5f3ae, 0x98bccbb3, 0xa63d956b, + 0xcebafceb, 0x218fd383, 0xf1104876, 0xa2d1be75, 0x9dd1fda0, 0xab5d3b7e, + 0xff411b64, 0x675adbb6, 0x238c0732, 0x2575bb7e, 0x907688c8, 0x179fa8c1, + 0xec5ddfac, 0x2d39be05, 0x4a6f7971, 0xf95874e6, 0x5926ea74, 0x6953f50a, + 0x4073f40e, 0x15e3bbbd, 0x81a56382, 0xc1fa09eb, 0x4e0f4e38, 0xc606bcd8, + 0x856de601, 0x32679fa6, 0xe361c937, 0x8604b4ab, 0x3b41fa69, 0x7c9fbc26, + 0x1c19cfde, 0x9fa85e4f, 0xf1da5daa, 0x9a839954, 0xfb0954f1, 0x0ce7ed48, + 0x9fea078e, 0xf784f1c1, 0x3c769cf3, 0x66a09655, 0x769d553c, 0x9f27e895, + 0xae55d3f7, 0x73f634f8, 0xb64e7d55, 0x2b4f0c31, 0xfb1631af, 0x0f4dd822, + 0xbff973c4, 0x7ecd9b70, 0x557eac32, 0xeca6bc7d, 0x9fb74c69, 0x859fa30c, + 0x3bc807f8, 0x032418b6, 0x314ad3c8, 0xfbb291c4, 0xa3d47881, 0x011faf49, + 0x5b559a0b, 0xa748cc3b, 0xfcfa5d8c, 0x865861f3, 0xcf1c653f, 0x38450394, + 0x1d93469f, 0xf00cfd59, 0x71e017bf, 0xf5f061c6, 0x7fddf986, 0x119b83e9, + 0x4dbb313e, 0x7940f709, 0xab45e3ad, 0xdb5fe302, 0xe5f62a68, 0x67dddea1, + 0x5f261d9d, 0xfdb93ad7, 0xeb019ccd, 0xfba181e4, 0x8f5f8331, 0x0cf17b43, + 0x5e2316b3, 0xd6031ad7, 0x587061c1, 0x3eaa2a0b, 0xc5765c02, 0x5fd744cb, + 0xb54b2e1b, 0x01e15170, 0xf085d9f0, 0x535b58f1, 0xffbb4ed0, 0x6871e39a, + 0x360d15a7, 0x9ca7a44a, 0x9721e912, 0xabaff39f, 0x0d7f2644, 0x08525626, + 0xf441bbf0, 0xfa0ad677, 0xdbf06ae9, 0xd885091c, 0xbc71c6ee, 0xd2f978dd, + 0x9e50c9a1, 0xca993dfc, 0x4d99eeaf, 0xe2600d72, 0x27bc0008, 0xbf258d4f, + 0x3863fa0e, 0x9fa8a9be, 0xe126d481, 0xa937682d, 0xe005f258, 0x308e377d, + 0xf3e70f1d, 0x796d4e49, 0x0cb6b172, 0x335f91fd, 0xafbda5d5, 0xe28759da, + 0x07de9363, 0xb1458c17, 0xfed1cf8c, 0x6632fa11, 0x1f6b5ef0, 0x11d9d718, + 0xebcd0766, 0xeca9dfd2, 0xb6c0c6bd, 0xa7337b62, 0xb28d9ffb, 0x84e796fa, + 0x443dfbd3, 0x030e4db7, 0x37fb6133, 0x9bd43e2c, 0xbb33db7f, 0x77a08b17, + 0xd198ed43, 0x35e34690, 0xdcfeb832, 0xfd8c51d4, 0x067bfcff, 0x8ffa0cb6, + 0xfb76651b, 0x27bfb422, 0x4231f85e, 0xef072dde, 0x2f2dfd0f, 0x256c728b, + 0x3f2148bb, 0x58b7f54d, 0xab2a1f5a, 0x340c967e, 0x34fa4419, 0x9e3d1076, + 0x81e9f7f7, 0xe68d8ce3, 0xa07f3c78, 0x2f6e1ed9, 0x047fa234, 0xd01fc676, + 0xa36b823f, 0xb5fd7fb0, 0x00bf2a76, 0x035e0e7e, 0x4ff90ab5, 0xd3fb6b7b, + 0x075ac5f5, 0x8ed7f75d, 0x5a81eba0, 0xb97bd527, 0x07ae98b6, 0x75745d6b, + 0xf9f025c7, 0xec5db918, 0x920afe79, 0xdbafe073, 0x88e28612, 0x3e20066b, + 0x793e3bcf, 0x0af0b7f2, 0xafd3a8cf, 0xacf5c116, 0x735771d4, 0x3ff9fc98, + 0x3f074fcd, 0x7fc71728, 0xef5d7f39, 0xb73d542f, 0x70179763, 0x87a9e0b4, + 0xfbcc18e2, 0x0a5d7194, 0xadcae1ca, 0x709ce32b, 0x0e3bb305, 0x9f29e1f5, + 0x3e891c5c, 0xfa54134a, 0x2848c670, 0xabe718e7, 0xefb89e8f, 0xbfabe406, + 0x51d9356d, 0x7ec0785f, 0xae7e80b1, 0xf89db86e, 0xbc6dca12, 0x1939ef7c, + 0xfe5a8dcb, 0x87bbf059, 0xa2589452, 0xb74e4cbb, 0xdba44c81, 0x8def2dea, + 0xb0f23a47, 0xfad3d20e, 0x8bfef876, 0xbd4f7a00, 0xbd7e8e5c, 0xffcab9fe, + 0x9eae411e, 0xc9cefb86, 0xab57f871, 0xafaef119, 0x0e34815f, 0x41313c7c, + 0x3670f1f0, 0x156ded1c, 0x4c97cc1e, 0xf73f2cfc, 0xa86d419b, 0x39fcb7bf, + 0xcaebca4e, 0x67ebe7af, 0xa507fa3f, 0x176cfe7b, 0x6bd7af74, 0x200c234a, + 0x7e7e8a15, 0xe20534ad, 0xb9fda346, 0xacf244c9, 0x1f6fc772, 0xd3da35fb, + 0x7d1c5a6f, 0xf69bb415, 0xe505191d, 0x494d3b85, 0x311a7c25, 0x2f084a52, + 0x696ff81e, 0x0b0f087e, 0x5667d99e, 0x77fbf206, 0xb1f08427, 0x99936770, + 0x8f0aec0d, 0x7326faa2, 0xbc044c6b, 0x478db7d4, 0xfb9f96be, 0x7ef119a7, + 0xa58905ea, 0xe78044e6, 0x6e717da6, 0xa3c22701, 0xde2753c0, 0x803df574, + 0x1553a417, 0x57e7fa4f, 0xc67a7027, 0xa23c94fe, 0x00ff27e7, 0xcb78a9f0, + 0x57f9c0e2, 0x1c67793c, 0x6303e3ce, 0xdfeba70d, 0xc2714cac, 0xde4c2b7b, + 0xf95d3b14, 0x96478afd, 0x6fcdbd10, 0xc8c29259, 0x1ba670ee, 0xd33cd046, + 0x37737e71, 0xcdf9a54e, 0xbba26e63, 0x2ec8df8a, 0x353e2bb4, 0x119de2b2, + 0xc175e2f8, 0x066c1f17, 0xfbf3046d, 0xef73c840, 0xcb8fb2eb, 0xca183bcd, + 0xdcaa25c9, 0xfca88b64, 0xe9e395a9, 0xe08304f1, 0x70f2e02b, 0x6f72dd7a, + 0x51f3f110, 0xfd153396, 0xbf030f47, 0x7d21f797, 0x2dcafd0e, 0x7e3952e3, + 0xed4cbdb8, 0xc2290ec0, 0x683f58fb, 0xac3b7f22, 0x273cfb1d, 0xe2c5fef4, + 0x28ee30fd, 0x07f3e409, 0xd36edc29, 0x095fefcf, 0xbf028e3c, 0xafa30b20, + 0xfce6fe30, 0xe73565be, 0x7ddf956f, 0xf9f18a93, 0xff388727, 0x7cccbb60, + 0x9520571a, 0x914d379e, 0x58581e48, 0x6f5f1220, 0xd6be0931, 0x04e9573e, + 0x38c46dc6, 0x60bd2746, 0x7f0409ff, 0x3de787b2, 0xe4c2ed08, 0x17df07a1, + 0x953fb5d7, 0xfe0be76f, 0x3ff9057f, 0x6cffc43a, 0xeefbe723, 0xf097adf5, + 0x3df26957, 0x57e46bf6, 0x82af4fe0, 0xe1726afc, 0xdede3fbc, 0xf456e47c, + 0x3e55eb1b, 0x3d4fcad5, 0xbd3c569f, 0xcf53e88f, 0xefd71fa7, 0xa7c8894b, + 0xb4a5f73b, 0xd3e245e6, 0xaa7e56ef, 0x2754fbf0, 0xd879553f, 0xf2f51c1d, + 0x250481f0, 0xdf843ca2, 0x2bac3621, 0xa774a9fd, 0xdf82dbd2, 0xb942f557, + 0x2a9749d3, 0xa5d275dd, 0xf9fa774a, 0x7fa7e16a, 0x158047fe, 0xb90df9e2, + 0xf7da1863, 0x45b8c153, 0x03054dbc, 0x6b1f34a3, 0x4d5f11a5, 0xfef3e311, + 0xb7184983, 0x79c21241, 0xf4bff54d, 0x0df7be19, 0xdfa2f313, 0x2dcf767b, + 0xab57da0a, 0x990ead92, 0xe68f84e4, 0x5eec8efd, 0xb00f7189, 0x8e51aaa3, + 0xdb47f74c, 0xddb96ed1, 0x32709eea, 0x7f448411, 0x8dcbe489, 0x07b2656b, + 0x2e3c79ad, 0xf2611ae1, 0x9efa5fa1, 0x2be345c1, 0xfd5e1829, 0xf73d1a23, + 0xb93dd1cf, 0x2157c606, 0x8c3f87c6, 0xc2ceddd7, 0x0f5faa7e, 0x46bbce5d, + 0xa1c5440a, 0xe3b12c3f, 0xddb87061, 0xefe32da7, 0xfd4252bf, 0x777eae5e, + 0x5f4df47c, 0x3aba05df, 0x1b787e0e, 0xba7c8d5e, 0xcb3cf4e1, 0xa9e8e1cf, + 0x031fc894, 0x615c9bbc, 0x44bad57e, 0xbddef72e, 0xcce280bb, 0xec0ff785, + 0x2e6de5c1, 0x423cd7c5, 0x2af79e7e, 0xa8af503d, 0x03f9eef6, 0xe8efe445, + 0xe822d3c7, 0xdec22ffc, 0x5a563b3d, 0x9ddf0327, 0x3f641d65, 0xd8dac779, + 0x6f7e08d6, 0x7ea7624d, 0xd430f260, 0x86afea4b, 0x4f13b0f8, 0x329e276b, + 0x7f0aea0e, 0xe5571dfc, 0xc3effca0, 0xe109f915, 0x1d6b62d9, 0xcf308aef, + 0x4adc047b, 0x46667ef6, 0x3f937639, 0xb8f084c7, 0xb1acac69, 0x28947f63, + 0x2b0144e4, 0xec9571c0, 0x246e2ebd, 0xec80e3e2, 0x3d5c01b0, 0xf76673fe, + 0x11c3cbc0, 0xf5fb47fb, 0x0f31c984, 0x67e278e1, 0x3e05e636, 0x45c44578, + 0xf51391e0, 0x44e5741a, 0x225f7dfd, 0x9bbc078f, 0x4eb82768, 0x2534292e, + 0x1af37bc3, 0x6f3183ec, 0xbfea2191, 0xf3d0a89b, 0xad4ed14c, 0xebc95197, + 0xd5ed99b5, 0x23dfe691, 0x6a5f53b9, 0xdefb35f0, 0x0fe8cd3b, 0xabe16fff, + 0xc0d8fef0, 0x8d5f8c18, 0x746e4895, 0xfc4663a5, 0x63fc1e70, 0xfbcf13f4, + 0x7cf2bc79, 0x02c38f09, 0x735db93c, 0x8d764493, 0xf87ae74a, 0xabe0273e, + 0x28a8ffbe, 0x9db913fb, 0x8557c2a4, 0x6abc7eab, 0xd757907d, 0x1bfbcb86, + 0x293f071b, 0x2fc23e61, 0x55d00dd9, 0x8cd5b1b5, 0x5c69e77c, 0x667f426f, + 0x65fbc2ba, 0x29a0d746, 0x6ef37461, 0xdbde91a2, 0x267a3f9c, 0xb585c7d2, + 0x77f38616, 0x871739ce, 0x8315f37a, 0xc8d1b5e3, 0xe4caaf7f, 0xc707778f, + 0xafdad6bf, 0xef0c6b1f, 0x39c68737, 0x84d0b2b9, 0x654669ea, 0x8c352993, + 0x4c4dde8e, 0xfdeae7a0, 0xf2854a8c, 0x1a3ef062, 0x16e7f787, 0xd5e49bca, + 0xc344c707, 0xf13519f3, 0xc02afe9c, 0x8e72a6f0, 0xbea68f26, 0x5347cf47, + 0xe535a24a, 0x3dad45d9, 0x96252e11, 0x044762c0, 0xa926f4fa, 0xf535f9f4, + 0x37e81382, 0x5ffedd02, 0xab1617a7, 0x9355a17a, 0xa92ebecf, 0x8d485e8b, + 0x2d1617a4, 0x0f115253, 0xd165be6a, 0x2252e34b, 0xb5c385e9, 0x1472df3c, + 0xcf5e19e4, 0x70bd014e, 0x985e9875, 0xd13a2362, 0xba482bb7, 0xf1505e8c, + 0x99cb1df4, 0x2217a8c3, 0x24f8f5f0, 0xd9b85ead, 0xe17a4e5f, 0x533229e6, + 0x497df3c2, 0x56eefec2, 0x4ca6142f, 0x11c9b2a7, 0x106e811d, 0x3a17189e, + 0xf8eef22a, 0x3f0fd41e, 0xbc13b24e, 0x3ba27af4, 0x39799e39, 0x04bffe39, + 0x2f8e555f, 0xbd912a9a, 0x18ee95d7, 0xe9a2efd1, 0x16ade512, 0x7c72e1ed, + 0xf1c81951, 0xae45d61c, 0x0eae50ba, 0xbcab9709, 0xeb9bb57d, 0xce634f01, + 0xf9e14b2f, 0x0e4cebad, 0x35bfd42b, 0x85876724, 0x271fd9cb, 0x2b672375, + 0xe0bd9cb8, 0x45f1e82f, 0x4263cb71, 0xcafc82be, 0x8ba04475, 0x9ad1a569, + 0x06270375, 0x19ef29ff, 0x64578fe4, 0x27bc878a, 0xc1c1fdf4, 0xf6821a7f, + 0x0f1c61ff, 0x49b7efe0, 0x9f80ef5c, 0xe058fd71, 0xdc39a2fb, 0x2edaae5e, + 0x1baafc13, 0x6f57bf38, 0x3d0e2893, 0x3333ff3e, 0xf0f6ede5, 0x971a86b8, + 0xf0bff156, 0x9955d695, 0xc4937cf8, 0xfc0acce3, 0xcd87cb0b, 0xbf242c73, + 0xad06fe64, 0xe96250ff, 0x4aed8fd8, 0x3639277e, 0xec8bfc91, 0x7e89556f, + 0x3ed36e16, 0x16ac72af, 0xe48057fe, 0xf6bd5576, 0x5fc15ef9, 0xde40e573, + 0x7bcf9833, 0xd244764d, 0x4ebd6a67, 0x9bfc5478, 0x780168f0, 0xf0eaf90c, + 0x44dfddb8, 0x0baf9379, 0x5ffcfd07, 0x3e46e554, 0xf6fc821b, 0x7249c19e, + 0xcf32fbc3, 0xdf59ce3b, 0xfe3c3537, 0x8ba0bafc, 0x55ee0c57, 0x9aaf58e9, + 0x6fe73fe7, 0xca1a8704, 0x306cf5a5, 0x37f36efa, 0xa76bf568, 0x48506f3e, + 0xecd6975f, 0x43cb6e94, 0x5abcf3b8, 0xf8fd6f85, 0xb65e780c, 0xd437f414, + 0x716f9d9f, 0xc5a8fc63, 0x517241d6, 0x05cfcfa5, 0xe053fcbf, 0xc74644e3, + 0x8d3bd258, 0x2ef89d92, 0x087ae360, 0x728362f0, 0x8fbfc8f3, 0x5bb07817, + 0xde392f88, 0xe427803c, 0x517ef1db, 0xddf6e7ae, 0xee39ff0c, 0x4c9bfbff, + 0x91a2aed8, 0xa0236baf, 0x8c3be986, 0x84a61447, 0x1b4f73e1, 0x92adefa7, + 0xe0f86e83, 0xe7c197df, 0xdaa8f065, 0x9f165f23, 0x4f3e5c2a, 0xc0827e12, + 0x582d8b6b, 0xfc798052, 0x3363923d, 0x53c7f656, 0xbae4e15c, 0xd8df843e, + 0x3d578e64, 0x80dfa3dd, 0xf2d4a6eb, 0xfa201c24, 0x7636c5f4, 0x6f6f7d42, + 0xcb855f6e, 0xa3be351d, 0xbe6abf5e, 0x1482c3cc, 0x66f352af, 0x83f76523, + 0x7257a889, 0xa44f5a25, 0x4660cfe6, 0x40dfd7c4, 0xbe9313ff, 0x66967fa0, + 0xecedebe7, 0xe13b7dea, 0x6e5136e9, 0xb4761ace, 0xa17be014, 0xbae0764e, + 0xca0c5bb4, 0x9e506b91, 0xe43131ac, 0x4d070b8f, 0xa3df2e4e, 0xbf949f49, + 0xfa84c272, 0x82731cb0, 0x09ffc798, 0xc4271bd7, 0x3d02de78, 0x2898c4ec, + 0x093a1fab, 0xd1c53fde, 0x9cf30e34, 0xacb48753, 0xe4ee38c4, 0x2391fb22, + 0x32d5cf88, 0xaf1e7c43, 0xeb3f222b, 0xe2243bce, 0x6f0037af, 0x94ea7ed8, + 0xe047239c, 0xc97565bd, 0x75295314, 0x0d3cdf26, 0x6507a5ca, 0x66f50287, + 0x831b18df, 0xfd09d7f1, 0x830ee665, 0xae0b194f, 0x6957f8c4, 0x71531dcd, + 0xe7a015dc, 0xe15d1f30, 0x8a97196f, 0xb5128de5, 0xe6dd78f7, 0xe09d2054, + 0x21e67386, 0x5079fef0, 0xd9eec10f, 0xb679ebc8, 0x754c0e48, 0x27aff3cd, + 0x8b6f3879, 0x598970c4, 0x2b58ec10, 0x8567d7ef, 0xa11b837e, 0x63e7943d, + 0x4b77ec7b, 0x90d3cdfc, 0xd49c618f, 0xfdb2c47e, 0x41e72f28, 0x82cc783b, + 0xfea0ee5b, 0xb128df6e, 0x62afe834, 0x47cfce44, 0x4d077f60, 0xb47e7c0e, + 0x671457e9, 0x4bef099f, 0xcb67fe87, 0x9d68e3ad, 0x3b258fd7, 0xb92abbad, + 0x5677f099, 0x9b4b19f0, 0x47baf64a, 0x6f3daa62, 0x3edb8f0c, 0xe89bdc96, + 0x65d2de78, 0xad5e70ab, 0x031ce4de, 0x5a39d5d1, 0xe0127897, 0xf43b06ed, + 0x83c79984, 0xcc27bd9b, 0xb37261ad, 0xf10fb939, 0x42c69ce5, 0x3aea2f92, + 0x6e32f70a, 0xb4adb467, 0x36987ad1, 0xef1b3d93, 0xd0b4af37, 0x5c1df6fd, + 0xb567b4bf, 0xdc7e83be, 0xcc4d1b07, 0xbe5c630b, 0x88c3cfb1, 0x9bb60fc7, + 0xdfe4de88, 0xcd8e4898, 0x5be3c1df, 0xbf791bcd, 0x72e36c1f, 0x5337e8ad, + 0x9ebca3c7, 0x42c9f20f, 0xafcad3f3, 0x1e02ca79, 0x89b75d47, 0x9557cbf4, + 0x53e45d53, 0x5f1455cf, 0x7aef4eec, 0x77aa8c58, 0x5ebe31f2, 0x7335955e, + 0x196fd203, 0x03068c4f, 0x087d3fbb, 0x2c6569f5, 0x46d53bc3, 0xa712c3fb, + 0x96c7ca07, 0x8a7e77fa, 0x6a515ff4, 0xde1e2073, 0xbf23f847, 0x78a44dac, + 0x395f3cea, 0xab3e79c1, 0xdfcf3821, 0x356fa5a0, 0x2ddd386e, 0x9eb86733, + 0xce6688aa, 0x7f477ab0, 0xef0a7402, 0xf928d599, 0xdb96126c, 0x42192ff6, + 0x6b8d3b65, 0x6bfbd0a9, 0x8f8e8963, 0x4adcf0fe, 0x7799d3a4, 0x6eed0c4b, + 0x42af75e6, 0x41bd57bd, 0xd6bd7052, 0xfb79bbfc, 0xc71ed0f9, 0x9c57f47d, + 0x15ae809e, 0x8deafba4, 0xfd53f7eb, 0xfd82922d, 0x4e54dd1f, 0x57854276, + 0x4b7cf466, 0xa001f91b, 0xd30f2897, 0x905395ec, 0x5857abee, 0x57d798ec, + 0xc7a547e9, 0x661f9136, 0xc9a0c756, 0xb2516ed0, 0xe50e9112, 0xdea75269, + 0x78f17a44, 0xedb57d39, 0x25903930, 0x7c8f4f2e, 0x6f4a825d, 0x90dbd232, + 0x6f35bd10, 0xfd23322c, 0xebe3e07d, 0x5e908a11, 0x571f1e91, 0x262c2ae3, + 0xe9523edc, 0x07e80ab1, 0xe8e5f4e5, 0xd3fa3bb1, 0x02f81dd3, 0xcee47eb4, + 0x771a3695, 0x37ddaad1, 0xc47ce52f, 0xab459c70, 0x8179487e, 0xff1e4679, + 0xeb88e156, 0xd24f30da, 0x2e0f1c65, 0x997fa733, 0xf1c6e8f1, 0x10d8e48b, + 0x96e803fd, 0x01bac59b, 0xe5039443, 0x5698c4d3, 0x31e304a3, 0x51187525, + 0xe14f0f3f, 0xc23979fa, 0x3325eb0a, 0x67281f5a, 0xacee081a, 0xa3d7c297, + 0x876476e6, 0xa67b63c7, 0xb06efea8, 0x189fde27, 0x5851e50d, 0xff404db6, + 0x5745a26e, 0x60a061ee, 0xbc516313, 0x5eca2a9c, 0x4c9d0328, 0x479f54cc, + 0xd12f72f3, 0xebcd1bde, 0xc79f500f, 0xead5f2f0, 0x7f5e18f3, 0x99e7a334, + 0x7013b129, 0x14cf573d, 0x237c66bb, 0xfd0d4951, 0x62d957fa, 0x6eb489a8, + 0x9a8a6fa7, 0xaf146787, 0xf4fff976, 0x5cb5e606, 0xf90098d6, 0xe9d34e07, + 0x867b30d6, 0x13ca7589, 0xa4b23d04, 0xae0bb238, 0x2f01bfc7, 0x26818c13, + 0x06b06f6c, 0xb0573f08, 0xfbf7f615, 0xf65222e3, 0xdd05e7e0, 0x56a86bfb, + 0x6ff30fde, 0x4b632725, 0xc524ae81, 0xe590f94e, 0x46db994b, 0xed4b94eb, + 0xcc49bf68, 0xaf9cf869, 0xfbe17657, 0xefa8f1d5, 0x802e32ef, 0x7c2131b4, + 0x1fa91b5c, 0x07675c75, 0xb798bc5b, 0xfd618ef4, 0x74e0c26b, 0xf08ae916, + 0xe22264b4, 0x098daced, 0xac728bbc, 0x8447fcfa, 0xeaf1b3d7, 0xd64e5173, + 0x95d74f3d, 0xa4febc4d, 0x78272b94, 0x64b3bde1, 0x6814a4e7, 0xd0c73163, + 0x28baeaba, 0xbee5debe, 0xed17b764, 0x5a73a023, 0x32cde497, 0x76317f93, + 0x5f0ce488, 0xd043315f, 0xb114b1f5, 0xaeb2d94e, 0x0ded05a6, 0x4196c3f0, + 0x0ba5cf7d, 0x4c4f8c66, 0x9199b7f4, 0x401baaee, 0xcb15e26e, 0x68dd5798, + 0xf75a4676, 0x56452a76, 0xf59a17e3, 0xfab2fbc0, 0xb9424cad, 0xafcb873c, + 0xc7e3bb45, 0x39517961, 0xbd6ff7b7, 0x0438e766, 0x69ab9941, 0xb1675e25, + 0x8a687dd6, 0x74517ea3, 0x4edc25fa, 0xd449ab2e, 0x03ad6794, 0x75c20e6c, + 0xfef5da99, 0xa7b9e44c, 0xe30fd0b3, 0xde04d38d, 0xa5ada7a7, 0xb774f7bc, + 0x44e73d76, 0x026332ff, 0x2246bb8e, 0xb8e6093d, 0xf066ed82, 0x6c35c219, + 0x7dc0385d, 0x67d0a35c, 0x97ce5c95, 0xb4a97f0a, 0xdd17af82, 0xc2666597, + 0x7f71f2df, 0x84d8fd6a, 0xa3f71421, 0x7f1efef5, 0xcfeb098b, 0x137e0258, + 0x4ec97bf7, 0xda0ea598, 0x86e60ceb, 0xe3c61b8d, 0xe755fa45, 0x3ee50d35, + 0xf5edc3ae, 0x10ed09be, 0x5d668f98, 0x6d0a8ce9, 0x5b46acb9, 0xf733afd6, + 0x3b3908a5, 0x7e400d80, 0x19229adb, 0xf944ff89, 0x5791d674, 0xefae0a03, + 0x194b6d74, 0x0747eb4a, 0x295ca1a1, 0xf9dca9bb, 0xe6a81cdc, 0xc78c07fb, + 0x25cf895b, 0x26e5dfe2, 0xe310bda7, 0x0fdc5529, 0x35cf819e, 0x7d7806eb, + 0xcb5dcb2a, 0xfee14d7f, 0x6b9b72da, 0xc12dc531, 0xc13cc54f, 0x98d3a358, + 0x307c4790, 0x7b3c922d, 0xabffd05b, 0x8c15b40c, 0x25121fab, 0xe4dfa5e0, + 0xcf8c3e1e, 0xb963fbf5, 0xfd53e317, 0x0aef000a, 0x779e05ca, 0xaef2209d, + 0xb33e8037, 0x5c9fb5c1, 0xc7f48d3f, 0x176e66d5, 0x2aac7c8b, 0x6b8f9c4f, + 0x7a13b1f3, 0xe50cf81e, 0xd61b0dce, 0xdb99ff92, 0x1ebf99c7, 0x8d9f77c6, + 0xddbeffbf, 0xcea98fdc, 0x35f24fdb, 0xf4f229d5, 0x36ce4269, 0xe7559c82, + 0x454df80f, 0x64fe87b9, 0x37bd1e49, 0x87bd73bd, 0x14a4e493, 0x1cf86318, + 0x78aa57e4, 0x0a599def, 0x41652bc1, 0xcef384bd, 0x6865de62, 0x6819ff37, + 0xd7abef0a, 0x533ebdaf, 0x56ebf491, 0x541d2067, 0xf58ab5a5, 0xdfcf5faa, + 0xe7fe82fc, 0xf7d41ca2, 0xebe7d30f, 0xec4ced04, 0xf144b847, 0xde2e3540, + 0xad917e9d, 0x30dc8d06, 0xf234a3d9, 0xad7f4265, 0xd0e899bc, 0x471b99ca, + 0x9f3cd1f4, 0x79a01ce4, 0x40b8b93e, 0x1aea9e53, 0xcb7fa9ad, 0xd94d22b4, + 0xa6bd7692, 0x49b94dbe, 0x7fee8e53, 0xac7ea6ab, 0x73cd36e3, 0x4ecf4bcb, + 0x662e0093, 0x0dd5b7ab, 0xde03a870, 0xd2109118, 0xace2031b, 0xaa287eb4, + 0x6c7e46c0, 0x004b60dd, 0x832ea4e9, 0xbcb0d3ef, 0x002d24b4, 0x6c7b58fd, + 0xf5c216b7, 0x0c6f92f7, 0x62ac73c6, 0x7755f61d, 0xf95e8d33, 0x2be70665, + 0xaa657af5, 0x5c1a687b, 0x9929b6f3, 0xf068048c, 0x358fc42a, 0x6bbb718a, + 0x7437df17, 0x91cfea35, 0x64967ea1, 0xc54a0e15, 0xaf3b7776, 0x91b3bf23, + 0xbd42fbd9, 0x91bf62cd, 0xda999777, 0x1ab635e5, 0xfdfc619c, 0x0f2e5487, + 0xb98d721e, 0x32f8898e, 0x0deac3ea, 0xf7e8cdc7, 0x689bfb57, 0xd720e1dd, + 0x16f7da71, 0x9af42fba, 0xd70a23b1, 0x1f553d3d, 0xc2e23d79, 0x6bcd3354, + 0x65e390bf, 0x7f61644b, 0x2aa4f8f3, 0x7676cb97, 0x1b8c6404, 0x93e36954, + 0xf20d397a, 0xded76359, 0x7140223a, 0x11d3900d, 0x0f5545fd, 0x3cd6dc80, + 0x3af6859f, 0x7943275f, 0x9ae39023, 0x4553d3e7, 0xcb006b3c, 0x6fc275c3, + 0xe7110cb8, 0x1e0cdbf7, 0x5dc37ebf, 0x087f7044, 0xc21216e3, 0x0e2f0f53, + 0x69c1cbc7, 0x15bf9a87, 0x7bd7d2f8, 0x6be3832a, 0x3a723747, 0xceedca90, + 0x1f3052cd, 0x15c7a885, 0x033af445, 0x2014a5d7, 0x0ab6fe1e, 0x67b2a8fd, + 0xf4fa8625, 0xd12f4daf, 0xae33263a, 0xa438c24f, 0x6954bf58, 0x7fa19652, + 0x40e0f400, 0x31baa6fb, 0xaaafe340, 0xfbc2682f, 0xce3c8d55, 0xf1e069e2, + 0x4ad66acb, 0x6ee6dd7e, 0x2a6f75c6, 0x5207efa7, 0xc7bf1a15, 0xbd44ef0d, + 0xf9f160de, 0x2b7fc424, 0x76ca57c5, 0x941d6c4b, 0x4eb6af37, 0x3d2f648b, + 0xe2fde02f, 0xf5c3336a, 0x1ed095e6, 0x6b3fb1e7, 0x3be319bf, 0xca253b65, + 0x5bea7867, 0xd6be62a6, 0xd0c4d8b3, 0x77c7508e, 0x7e482b26, 0x84739be4, + 0xc787391f, 0xcc5cde2d, 0xee790fed, 0x9d57147b, 0xc8fc255e, 0x0e281739, + 0xf08566f4, 0xb8f2e723, 0xd43bf4c7, 0x8e968ebc, 0xd3d53a55, 0xf56e9e9f, + 0xe955faf4, 0xa76a4773, 0xf508319d, 0x1c7be03a, 0x1fdef1fa, 0x4c27ca32, + 0x426cd4bb, 0x2af7bf3f, 0x281ee3bb, 0x2b7d940f, 0x9ace5e31, 0x95c1f3f9, + 0x5f2e249b, 0x3e715b94, 0x86667599, 0x020239fb, 0x53c4014f, 0x43a94e32, + 0x357e468a, 0x1ca37b06, 0x0175c1ca, 0xc1a7c700, 0xf949dfcf, 0x065f2e25, + 0x69b6973e, 0xd6bd184d, 0xcaa2b908, 0xe66601bd, 0x017189de, 0xc6067d63, + 0xf8987717, 0xd16c963e, 0x1d3edf5f, 0xb5c127e3, 0x65ffbc4d, 0x7fcb5571, + 0x94fe10c9, 0x75c11673, 0x5da3c8a2, 0x8a5034bf, 0x744ec8f3, 0x6f315307, + 0x12a47d99, 0xef5d5af5, 0x1fd0f397, 0xabc3d751, 0x91e6f471, 0x13bc6c1f, + 0x32bb6be6, 0xdb69f08a, 0xf48edeb3, 0x243beb6b, 0x57de5235, 0x2a2e7abd, + 0x53fc0dcc, 0x5d37b17d, 0xbda4f2d5, 0x6dfd68a7, 0x78dcffb5, 0x698b8fe2, + 0xf76d5f74, 0x81ee3127, 0xf32cff62, 0x065e9127, 0x911c6cb9, 0xc2a7aa1f, + 0x68e75d41, 0xf085bbeb, 0x3c1de775, 0x7ad8c1bf, 0x654667ea, 0xfd0e548b, + 0x9a7262dc, 0x47de0062, 0x709b4c7a, 0xd5d71732, 0xc1c1b8f3, 0xa5c52b5a, + 0x53b5ad5e, 0x469b5839, 0x156bd7e5, 0xec915eba, 0x34e104fa, 0xbe9ac5f5, + 0xace6b708, 0xa7985d87, 0x44d07b3c, 0xaecc60f0, 0xc17de7d9, 0xea3c532f, + 0x5f5f0342, 0xe67f8ea2, 0x4ee60cc5, 0x8a6371e4, 0x0bfd2c57, 0xc54739c9, + 0xf7e8f1b9, 0x5b6cae0c, 0xd2cf6585, 0xee9d694f, 0x282fa03b, 0xe3c8d1ef, + 0x2d8d55a7, 0xf4b9ceb4, 0xb3f50262, 0x1e31d0c3, 0x82fbccf9, 0xde3beb44, + 0x4e673c69, 0xd288fae5, 0x7c451b3a, 0x3c5a4879, 0x1fe3c1c1, 0xe5f8e06c, + 0x8245d579, 0xfaae9a1e, 0xc3e21c47, 0xf5a154ba, 0x6407d522, 0x19acb38a, + 0x8f6711d3, 0x6e317720, 0xde93eb8d, 0xf494eb12, 0xbd99a7cf, 0xc07d717d, + 0xfde44334, 0x50b48ecf, 0x75d71f7e, 0xc7f53297, 0x3f83d7f7, 0xca88eb43, + 0x8ca745fc, 0x6ef9ad78, 0x196acff2, 0xfdf0c1fd, 0x320fe806, 0x34bdfbcd, + 0xae564b7e, 0x85d6ef26, 0x98335bfe, 0xaeaa7802, 0x20173003, 0xd7455f9d, + 0x2af7ddf6, 0xa8d637c8, 0x2f51878e, 0xf2067eb0, 0x5abcaa27, 0xe84b273b, + 0xee0cacad, 0x89a7173f, 0x2fc2b2fd, 0x4267ff02, 0xe27ff71a, 0x5f8d32f6, + 0x7e4fbfa4, 0xc7ec5591, 0x7978001e, 0xafb8c23a, 0xc2e318cc, 0x1d6cd976, + 0xfa0337d1, 0xcfd2ba46, 0x1f1a4673, 0xd3cfca97, 0x28f39f91, 0xacfc4ece, + 0x464877ef, 0xcfb40ce1, 0x5fb37756, 0xefc12aeb, 0xc1181b55, 0x8121b3cb, + 0x6d8674e0, 0x7a018d70, 0xd8e3033c, 0xd678f40c, 0x878e8ae5, 0xaedd67f6, + 0x109884e8, 0x886f57ff, 0x73ab76a2, 0x872c4a6f, 0xf7a08d72, 0x2b22c6f6, + 0x06e679c2, 0xfbea77ce, 0x4f4c09de, 0x6a1a3e44, 0xde6330ea, 0x2dbfa7ae, + 0xa1bbed0e, 0x222727bb, 0x4e3775ff, 0x779f3a77, 0xb445d2d5, 0xb87f155e, + 0xd0a1627e, 0x3a7b9e63, 0xd57ca11e, 0xdbf44652, 0xd5afebb4, 0xfeedbfc8, + 0x9e6bca68, 0x7a4d13d9, 0x3cd3ecf0, 0xd4c679af, 0xaa60eb4a, 0xf476cb77, + 0x7c2f3d07, 0x9ff230fc, 0xa1459767, 0xdeffbd78, 0xb6aeb873, 0xad1d7fd2, + 0xfedca8c3, 0xd541f2dd, 0xfec8bbd2, 0xd71fcb51, 0x37285d5a, 0x2e5c8ddb, + 0x867c6c2c, 0x9785d9ec, 0xfcc20c2e, 0xff3d99ef, 0x98e50c3d, 0x86178fe7, + 0xe7ec3ed1, 0xe7c30c2f, 0x6ba2e79e, 0xef25d922, 0x8e38f066, 0x0e731faa, + 0x9ef13519, 0x73fe8209, 0xc62bac56, 0xb6864d73, 0xaf84714c, 0xd7da1b1b, + 0x8617fb40, 0x389b1e1e, 0x8addac37, 0x392fdf20, 0xf46c65a4, 0x747a309c, + 0xb8d49866, 0xd38ad7d1, 0xa11fb130, 0x34132e33, 0xd5843ed0, 0x6f3f2341, + 0xa1f242a0, 0x8a7600ff, 0x4bd91dbe, 0xe44f6f67, 0x5d1832e7, 0x1d220613, + 0xf697dedc, 0x75af3387, 0x3d986e5f, 0xa0683d34, 0xfcd3ddf5, 0xefd90096, + 0xefad2341, 0x99a4ed56, 0xcd883ee7, 0x5dc42291, 0x0e3ebffa, 0xfe3eb6e5, + 0x6ec6b3d2, 0x2fef0898, 0x08ecc15d, 0x063c7d3f, 0xfb9db17e, 0xf8d75992, + 0xd07c128c, 0x5c95ed8a, 0xa7c71d83, 0xb78899da, 0x3efc0886, 0xb3f39d2d, + 0x822b47ca, 0x8ac7c206, 0x2e6b18e0, 0xe789275c, 0x7136a00d, 0xff0ae8df, + 0x1f18ade4, 0x96e97158, 0x9ef081e8, 0x626e8715, 0xdbbf20f7, 0x62fb58c7, + 0xb7df4bbb, 0xd10bcd4e, 0x4a7dfe89, 0x2127d73a, 0x7eb2207b, 0xfbfc178b, + 0xd8b9e95d, 0x3d6cfff4, 0x52757e07, 0xabf250fa, 0x07b8f067, 0xfaf5abf7, + 0x6abb9541, 0x7e04e3bf, 0x53ddcabb, 0xff80bf64, 0x5c77724b, 0x7af542ba, + 0x922527fa, 0x4a687c5f, 0xb5d312a2, 0x87463eff, 0x6baf2121, 0xe69daaff, + 0x59f73af1, 0xf2717fd1, 0x8a6796fc, 0x90a493e4, 0x4971e75d, 0xa9649f7c, + 0xd4f587c9, 0xf0a70571, 0xa754e9b8, 0xaa86f289, 0x87daa7fd, 0x3c1dcf9d, + 0x8bdaa8af, 0x74185daa, 0x94ec38f1, 0x15f9fc21, 0x106beec9, 0xf588ef5e, + 0xf247432d, 0xf6b98cfb, 0xcb747fa1, 0x7e2312cd, 0x4aa2f617, 0x527b7a9f, + 0x1ddf6f5d, 0xba0a371e, 0x5b2bf954, 0x9eaa17c7, 0xba7a11aa, 0x2274f51a, + 0x34cfe9ea, 0x5fbeb776, 0xf4aed3d0, 0x08c76c64, 0x1b0e43be, 0xeefc915d, + 0x375fa213, 0x3dae0fe2, 0xe2162f83, 0x7058b378, 0xdd8bfa19, 0xb0974fe9, + 0x5e7bba63, 0x5f9fc693, 0x08d78f8e, 0x7c577ffc, 0x9c3feabc, 0xbeed3b8f, + 0xba23ce6e, 0x7ef0a332, 0xb928dba4, 0x7c885826, 0xc51367f7, 0x4af5f5c9, + 0xff063e85, 0xfbbf4355, 0xf406ccb2, 0xdc153c77, 0x578bafff, 0xe4bf235e, + 0xd5d69925, 0x0eff042c, 0x1705b3ed, 0x44ad74ed, 0x33ae183b, 0xfe50b5b6, + 0x76854660, 0x831875fc, 0xe477f6c5, 0x32fc7ad0, 0x44e29636, 0x3b78fe65, + 0x4baf23ee, 0x86f5a7ae, 0xb2b2adde, 0xedfebc35, 0x8f2b7d6a, 0xf74d2d9b, + 0x6b79e72d, 0xab2fbe8d, 0x5af3dbd1, 0xc45a3ffd, 0x03b3ba7d, 0x71b26f9e, + 0x26407279, 0x78c6aefe, 0x998cd5d1, 0x4bd5f5d5, 0xdaa39c79, 0x23f68cbf, + 0x1fe78957, 0x4714831a, 0x5417fca2, 0x9f5fe53d, 0x9cc87c82, 0xd54f7cda, + 0x2724c396, 0x849f79f5, 0x3c8f2e06, 0xf3c8b295, 0x7d68930c, 0xa7d8a363, + 0x223728aa, 0xcc5c61dc, 0x863ee0a7, 0xce3fe413, 0xf325fdd8, 0x17f84e3c, + 0x7fb3cf31, 0xf972a65f, 0x63754f3c, 0x84fd098b, 0xde7be5cb, 0xc38cef49, + 0x97b09c50, 0x7b5fc791, 0xc63b25f9, 0xf5897a97, 0x4757c37e, 0xc77ff5f1, + 0xdf2224e6, 0x9f6978ab, 0xfed9e1c4, 0xd88527e6, 0xa331d86e, 0x3e11d71d, + 0xbfe2e6ff, 0xad32f264, 0x6c7f18d3, 0x25fa3471, 0x4516c7ed, 0x879f3c23, + 0xb9e3e22b, 0xe3118c37, 0x78a1e589, 0x7bd205f2, 0xb2788b77, 0x6c5ef411, + 0x6fa32e28, 0xd72153f7, 0x8adf30ea, 0xe79bb974, 0xddd2ebfd, 0x57f953d7, + 0x13ff69bd, 0xbcc279c3, 0xc63a019e, 0x9800cfb8, 0x9f95e62c, 0x302b628c, + 0xec9753cf, 0xe6f8997e, 0xf9050657, 0x7e53da06, 0x2153bbc8, 0x55a1883d, + 0x020cc3cc, 0x7da563dd, 0x8f944979, 0x2fe04ab9, 0xf452fc1d, 0x5334610f, + 0x403c8f30, 0x450663e4, 0x7ff62331, 0xe6bdc99f, 0x34ffcc4a, 0x88cb1d19, + 0x93891de8, 0x85e6bb62, 0x77cf2724, 0x3521f9ab, 0x7e5dddef, 0x0cf7c248, + 0xf945f4e2, 0x3094e620, 0x81e6ae1f, 0x4a2ecdd8, 0x511f2d4e, 0x7967e743, + 0x9d37d8b2, 0x8b4a29ff, 0xa5719f90, 0x6bef6131, 0xfa6b81f3, 0xfa744d3f, + 0x6b80f355, 0x71e9bfd2, 0xd5efdc2b, 0xfc487b8d, 0xa3f214f9, 0x3a77f9fe, + 0xffb560b7, 0xb3bde902, 0x0e71161d, 0x938f2b45, 0x2f144dfb, 0x58fe0b38, + 0xdd3e9872, 0xddfbc69e, 0xfa222feb, 0x8d8e086f, 0xc487fac6, 0xa687d5fd, + 0xde7b464c, 0xfa3a341b, 0x7fb848d2, 0x0e3410d5, 0x1be4fb45, 0x7a694bc4, + 0xa359f984, 0xf3d23eb8, 0xbfe09c51, 0xe70e0cb8, 0x5fb937a2, 0xf3cc59e5, + 0x1d75761f, 0x73cf0d70, 0x914acfef, 0x6a77f8d4, 0x6ec8fca4, 0xecbd2ebe, + 0x2df68976, 0xc8fcd97f, 0x7fb6c68c, 0x8fa23f2b, 0x219ddf3b, 0x790322f2, + 0xdd23b9dc, 0xa84bf34e, 0xfb885c19, 0x7ef9d49e, 0x901f7083, 0x43e6edf9, + 0xedf9efaf, 0x352fdff6, 0x837cdd02, 0xcb7d97fd, 0x96fc2ffd, 0xf52fbffb, + 0xdb7f85db, 0xcbffdcb7, 0x8fff72df, 0xff07d244, 0xf5ebe6af, 0xfe7d78f9, + 0xb7979f5e, 0x8bd734bc, 0xd695eecf, 0x6ae00476, 0x4d35db8d, 0x8c687902, + 0xbd4562df, 0xe7923259, 0xb58f56af, 0xa14936fa, 0xaf0abe3c, 0x3fdc5991, + 0xf39de7b3, 0x6ce356e2, 0x226c7067, 0x3246bbc6, 0xdacf6ff2, 0x198b1e78, + 0xd798e9ed, 0x37e99a82, 0x67521d81, 0x7d079c8b, 0xf7f0a7af, 0x4b1bd1ba, + 0xc8af0ab2, 0xfed5a64c, 0x59f648ce, 0xdb2f88ad, 0x17c5191b, 0xbf495199, + 0xa4abde89, 0xe3d3fda3, 0x2e3f7e45, 0x689b9cc0, 0x4dce4a5c, 0x928f6e74, + 0x407be383, 0xae1367e4, 0xf18397ef, 0x03b004e4, 0x1eb78f31, 0xa7e479f3, + 0xfa9ea9da, 0xdc99ddbe, 0xc4c07a4f, 0xef305ce8, 0x11dd7c95, 0xbd9156b3, + 0x0ee1e6a6, 0xcb27029a, 0x8dc3ca25, 0x62bff1c1, 0xce6de408, 0x449c4411, + 0x3f296dfb, 0xdfc8eaf8, 0x7bd377f5, 0x86fecd14, 0x6187f466, 0x29ee771c, + 0xb19dfa20, 0x6fed2477, 0x091ae4f0, 0x46fc5dce, 0x43780711, 0x38d431c4, + 0x7a8f9a80, 0xde3fc45b, 0x3f4ab8c1, 0xa1584f3c, 0xc34caceb, 0x5a9e77bf, + 0x159cfe57, 0x203d3f49, 0xf78fb8f1, 0x29f71e15, 0x84fa3b30, 0xccac7faf, + 0x0f2c78e4, 0x1a83bcf0, 0xcc4279c7, 0x7287e0a7, 0x687602c0, 0x6681aac1, + 0xab05ebd4, 0x3af0a2b2, 0xa433e9c8, 0xcfa7bc00, 0xf15069d9, 0xee8e8917, + 0x89f114ca, 0x8f941d03, 0x9797467b, 0xd7c99ddf, 0x7165e41b, 0x64ceeefc, + 0xafb3be54, 0x8b9a3971, 0xcbb1ae3d, 0x6541f291, 0x38e2f7e0, 0xb8f8ebcb, + 0x05977855, 0x4f7c2294, 0x558ebedb, 0xc8afcd78, 0x79b8a229, 0xb455b9e5, + 0x85d2e9bf, 0x1c52d7fd, 0xffa0accc, 0x1b55b330, 0xc5909b4f, 0xa0cfe7e3, + 0xbb708dc1, 0x6ffe48ce, 0xa24675c1, 0x1b32849f, 0x2609a7f9, 0x7960c726, + 0xf283b712, 0xb08a938b, 0x93c4a6cc, 0x407f97fd, 0x179b9f89, 0x5c256f8a, + 0xe11938b7, 0xa8bcb974, 0x22bb271a, 0xa44bf9d9, 0x179aafdf, 0x88783aad, + 0xf3aa7bd6, 0xe6a2e152, 0x8bcbbb37, 0x3c12ebaa, 0xd6689fc5, 0x1d8c7851, + 0x58ae31e3, 0xaccda7b0, 0xcb4b37ee, 0x0b4de509, 0x7ca39f76, 0xf51f9aa9, + 0x3b239cd4, 0xb199da1a, 0x3fa0017d, 0x4364e41d, 0xee9bcf2d, 0x1a7bfb12, + 0xae78fe61, 0xfe601ff6, 0xfcc3f578, 0xb50bfef1, 0xa81ae9fd, 0x6f75d075, + 0x7aba08ed, 0xcf28e7fc, 0x36a642fa, 0x8f99d75f, 0x084d5d93, 0x1d7cb0af, + 0x3af9f595, 0x63c78a39, 0xee303f70, 0xb41cf21f, 0xf42efc92, 0x7f42f797, + 0xee2d6fe0, 0x6aee385e, 0xd18597cc, 0x61d3bb45, 0xdb6c73c3, 0xe61b0e5d, + 0x4e9a0ac9, 0x6a847ed1, 0x15ce9063, 0xa6073ce8, 0x775f1ce1, 0x21b42feb, + 0xd79b2f7c, 0x79fffc6a, 0xd7932fad, 0x32f905ba, 0xf23f2439, 0x26e7065d, + 0xda701ebc, 0x87c986e6, 0x179e2ed5, 0x9bdb9d59, 0x5741eff8, 0x6139f8ef, + 0xe628adfd, 0xeb848a71, 0xf7e16d72, 0x79e2c89f, 0xb98904ac, 0xe4b1c922, + 0xbcb8df9e, 0xef648e4e, 0xf402bfb7, 0xc3d03578, 0x5abdf9ee, 0x71b4ae89, + 0x73c5d5b6, 0xdbb9e17a, 0xac2c37de, 0x69c38f2f, 0x974c6ce2, 0xde2eeb4f, + 0x40d8a336, 0x7bc2e2e7, 0xeb5f51b3, 0xd8cc62e3, 0xb9f5cd91, 0xe4739c53, + 0x582364cd, 0x5bdabc97, 0x173877cc, 0x362f4fea, 0xf3509e90, 0x46c5f96b, + 0x99f40b56, 0xa3e4d4bf, 0xb1b15abc, 0xff0b9e8d, 0x3f3d8570, 0x3bc9e513, + 0x8c76cd07, 0x60e3e9a3, 0x752de28e, 0xa3bda1bd, 0x6d7da252, 0x373fd65d, + 0xf8c38d36, 0xaeb660d9, 0x1bd42c6e, 0xe3b06b9c, 0xe5cbe57a, 0x3d85f2e1, + 0x219f8fa3, 0xa1fda15d, 0x2f5fa38f, 0xb0bd7ef0, 0xbf43ee97, 0x8fd43932, + 0x2f4f4eda, 0xbe94f68f, 0xbf7f2e30, 0x71456fe8, 0xc45ceafe, 0xa1818967, + 0x3c5158de, 0xd61b9ac6, 0x234f595f, 0x7986af5f, 0xbcf0a4bd, 0xe9dfcf1e, + 0x3caa79f3, 0x8cfa682b, 0x083efff6, 0x95f51972, 0xffc78d27, 0x3c285e0b, + 0x34227280, 0x1f9fae4e, 0x37bf534c, 0x7c6788e0, 0xd14fb45e, 0xb8a247bb, + 0x27c97e5b, 0xcca1a37b, 0x7fb4f15c, 0x773073de, 0xef939e39, 0xc50e3129, + 0x971e3afd, 0xc22799d4, 0xd7e4d07c, 0xf5c7ae2a, 0x075305fc, 0xa67e20b7, + 0x9d689a96, 0xa6d7e4de, 0xaae539d1, 0xba982b9e, 0x7c289ee9, 0xf3a25fde, + 0x56bf261a, 0x4f9f063c, 0x88c01ed8, 0xb3889b38, 0x3c193907, 0x7c88d278, + 0xfbb24572, 0x0537c827, 0xa89e4493, 0xa9e3eb94, 0xc62649fe, 0x7e8d46ed, + 0x1bface6c, 0xf3d479c5, 0x7d711204, 0x2f485e42, 0x7d01ec15, 0x57d21b15, + 0x7a9eaeff, 0xe09da7b4, 0x2be83579, 0x24c24f1c, 0x62ef4f9e, 0x77fc08bf, + 0x93ba7fa7, 0xc467a8bb, 0x529983f9, 0xad7d575a, 0x38673c60, 0x9d12e5da, + 0xfd1dd683, 0xcfec26bd, 0xb6ec6ef8, 0x76fd04d7, 0xf1a9aebb, 0xfd13c9bb, + 0x787fe7b9, 0x57f8489e, 0xf548be6a, 0x7b09fac7, 0x215ebd57, 0x7b7fbbfc, + 0xd12a013f, 0x1209fb88, 0x9827ef22, 0xbda12f59, 0xd827eea4, 0x3b856667, + 0xab3d7093, 0x73e44fd8, 0xefb41d91, 0x7aad6fd7, 0x7bce893c, 0xa0cc6dc0, + 0x9f485af7, 0x43fd8157, 0x63ff92f6, 0xe7ad3f1e, 0x1aabb1eb, 0xd496fbb5, + 0x5f616ceb, 0x50f9858f, 0x77ac459e, 0x91ce2f1d, 0xef21c508, 0x21c78632, + 0x59304a3d, 0xe3eb475d, 0x5c4d1779, 0x6438bbb2, 0x75a0eb35, 0x9215d5b3, + 0xb7c3f503, 0x91ec971d, 0xddaf5da5, 0x83cb9327, 0x42496e69, 0x706ad5fb, + 0xf8bad255, 0x6c7ef817, 0x66fa7c3d, 0x413c7971, 0x331e31e4, 0x6c787a73, + 0x5bfb4494, 0xe21c1f70, 0xf817b1f9, 0xf2c7973e, 0x35173ef9, 0x5feea16f, + 0xb79432b9, 0xea6ffda0, 0x1f7517be, 0x780fba8b, 0x00a886d2, 0x99f707da, + 0x1db8d3ea, 0x3c3a25eb, 0xf3d193dc, 0x6f3f0b28, 0xf8ce3f5d, 0x28c3c2ac, + 0xf37f0f87, 0xac88d176, 0x25a67108, 0xaffc2fc2, 0x98fb2eac, 0x30bffb54, + 0xfec6a86b, 0xfedeb2a7, 0x16f2a6ff, 0x6f9f0141, 0x32abde70, 0xe6f8ddbf, + 0xfc72df67, 0x7b247cfa, 0x4b88b976, 0xd9e7e9e9, 0x68bf552c, 0xbac34bbf, + 0xfae43fec, 0x8e524ebb, 0x2f6bb9d2, 0x542573f1, 0xcb175a39, 0xe4215ffb, + 0x547d7aa7, 0x914ceb5c, 0x884f5fe3, 0xe764b3e7, 0x0193a472, 0xc8f1b4db, + 0x78daf581, 0x098dd5e4, 0x40e0f29a, 0xc17ea686, 0xe79ade81, 0x69578343, + 0x237f0f9e, 0xd91e535f, 0x7f534a3a, 0xb46387f4, 0x68755ae7, 0x5ed791e3, + 0x2fb749bc, 0x2bf047d2, 0x6f0dca04, 0xad9d6457, 0xa15997a9, 0x8d56579d, + 0x96bd5e76, 0x2fcee826, 0x78e6fde1, 0x53ebf3b5, 0x025f9da7, 0xbef2d3e6, + 0xd4cd3e7e, 0xecf7a153, 0x61b1f7f5, 0x738a07bb, 0xa99f686d, 0xc1db99fb, + 0x6411786e, 0xffb69fdf, 0x9cd7d696, 0x06eda279, 0x79e6cf3a, 0x0379e199, + 0x5963dbed, 0xa3e3de80, 0x34162873, 0x661ef4c8, 0x1c9b0c0c, 0x9d1afe76, + 0xe9f28f4c, 0x911258a9, 0xf8b69e0b, 0x82fda04a, 0xe106275d, 0x7bf692fe, + 0xfbcb3e78, 0x31f14484, 0x841d6de6, 0x60584bdf, 0xa89dfc8c, 0xbcb8b2d7, + 0x9a3bbd3b, 0xdb49ebd6, 0xbf52669a, 0x3098b7f5, 0xdbd6a69f, 0xa849fc2f, + 0x3d3df7c7, 0x5e77d12e, 0x71e17c70, 0x27bbf54d, 0xfae71fa7, 0x89a3416f, + 0xb059efce, 0x9e3b676d, 0x0de0bd57, 0xe65b9d0b, 0xf48e76d9, 0x3b53d16a, + 0x469ece08, 0xd5a8bd99, 0x8273da57, 0x5db8f1b7, 0xe9154375, 0xff932841, + 0xf91f5d55, 0x9dcbecbc, 0xa9f0bb67, 0x00bcbb3d, 0xfccf85c2, 0x1ee30e2e, + 0xc6b7051f, 0xedbedf91, 0xeee9cf8b, 0xfd702e72, 0x173c2fea, 0x03fc23f8, + 0x2cc5cbe4, 0xdbcab9dd, 0xa9f7c512, 0xf7c2c302, 0xe8e087f9, 0xf1de78e5, + 0x6e7823e9, 0x3fa7e9fd, 0x5bc7047e, 0x8f0baff9, 0xadf498fc, 0xc3728ecd, + 0x3a61c4f3, 0x976d5bf7, 0x40e5cd90, 0xa3bfe3fb, 0xdfdbd2f3, 0xb7b038b4, + 0x641f3df6, 0xefb77d23, 0xe3052cfc, 0x8cf78b5c, 0xe2f078a3, 0xf0be8b67, + 0xb7486b7b, 0xe3e17ebe, 0x3e7375f2, 0xcd5f16b1, 0x38d9cd0d, 0x6f8033ce, + 0x9e75f38c, 0xc55f5cf3, 0xc456cdcf, 0x23dbcef9, 0xe5df8b9f, 0xc986e73c, + 0xed0f7e37, 0x2e7e069e, 0x75cf65cc, 0xbc78043e, 0x6fe04bfa, 0xbe716afb, + 0x9dfc6449, 0x4f003fc1, 0xb9ed6c8e, 0xcc369fce, 0xf8d7f47d, 0xdbb121ac, + 0x5f039d73, 0xb9ea6e02, 0x72ccfffb, 0x3e46ce8e, 0x74f7fa7c, 0xade2368e, + 0x3a73c144, 0x7f46cd3e, 0x075343ee, 0xb1d72b9d, 0xefc762c7, 0x73d82d37, + 0xfda7f894, 0x64b71e59, 0x76fbfce2, 0xe7e3f9d6, 0x8a988b95, 0x3f2c4b67, + 0x1fc05a0f, 0xe2568bcf, 0x1738bee8, 0x7ab1d39a, 0xe777745e, 0xeeca2f44, + 0xf89cf5cd, 0x96d5401e, 0x9fb99abf, 0x3497c21a, 0x7fe9f682, 0x2adbf9e1, + 0xbfc2ec1c, 0x96dbc4eb, 0x7771e7c8, 0xf02f8f9e, 0x73c3f885, 0x35cf3a3c, + 0x5435f287, 0x08b28e96, 0x137da0f2, 0xbdbd2f3f, 0xeea9fd1b, 0xd6caaa0f, + 0x6798a9f1, 0xf2a1fc77, 0xffc6e5e9, 0x3333e155, 0x8bd0d15b, 0x97d3a70a, + 0x75f1cb22, 0xb6bfef82, 0x62ece3fd, 0xf48fdcff, 0x66d0d558, 0x44d9fbe6, + 0xf7cc547e, 0xf4dfd834, 0x6427a4fd, 0xd557e3b2, 0xd71c9337, 0x6eea8bcb, + 0xb39b6df2, 0x7153bac5, 0xa7e9c14e, 0xefb87d63, 0xdddef4ea, 0xf6effd7c, + 0xfa17b336, 0x19edbfdb, 0x721b8f33, 0xe13d41fe, 0xe9ff1b0b, 0x91069b27, + 0xdd66eedc, 0x8f78bd77, 0x3df91fc7, 0x34e7ed9e, 0xade859ef, 0x72efff27, + 0xe8c8fbef, 0xfbfb05bc, 0x3bf7c828, 0x4ffb847e, 0x17ffbc23, 0x176126d9, + 0x22eb13ae, 0x3f03de41, 0x9ee02bbf, 0x3cf5cbd6, 0x9d1999c2, 0xe3be1083, + 0x2725917e, 0xaf979f01, 0x7fa8ec95, 0x4c18af67, 0x9ccf9274, 0x89652744, + 0xfa937bfc, 0xe6cf1cf7, 0x1ab6fc7a, 0xc3fa4313, 0x280cded3, 0xb624eb7f, + 0x3197fb86, 0xe7425313, 0x6ead56d1, 0x0abc2389, 0xef3d533f, 0x3e66a2b6, + 0x39fd07c9, 0xdeac9538, 0x2d6fe78c, 0x2dcfcb58, 0xa38b9fd4, 0xcf5dab97, + 0x85fb5a89, 0x956df672, 0x81cc1cef, 0x07e7377c, 0xd7e456b1, 0x4a68f0ae, + 0xb3ca05be, 0x07a4c80f, 0x2eb0b854, 0xebcbfddf, 0x7f3cf881, 0x973f2fa0, + 0xb152515c, 0x3c1e9cde, 0xdd19282e, 0x597ef1c3, 0x19b87ba2, 0xb19beae5, + 0xb596c7b8, 0x7c50345d, 0x36595980, 0x59d9938e, 0x537db876, 0x60a7b26e, + 0x16cbc4de, 0x58fc51a5, 0xeb0addff, 0x1eff20da, 0x157bf683, 0x5f9c8965, + 0xeff3763a, 0x1e46b1ef, 0xeb32b6bf, 0x9c778c32, 0xe0a5d652, 0x95ae5411, + 0xc53dfe26, 0x4714f1ed, 0x91456db8, 0xba5fcf19, 0xf69e21ad, 0x93af30b5, + 0xe2a8cfbe, 0xc1456db1, 0xf7e834fe, 0x871cfab6, 0x269fc5ac, 0xaea0bc1e, + 0xc9dbc54d, 0x64ede0cb, 0xbe01bc24, 0x7a13f734, 0xeec5f169, 0xe94cf6e6, + 0x62fafb1d, 0x0d7ceefe, 0x77631eff, 0x340e92f2, 0x35c5094a, 0xe33a338b, + 0xef4829b5, 0x250ed617, 0x55f1e9bc, 0xc3d9affc, 0x7b337f71, 0x05ce962b, + 0x66c3eb2e, 0x6ff184dd, 0xd953f389, 0xa316262f, 0x8bd01ade, 0xb56bfdf3, + 0x82d9fe3c, 0x787ecff1, 0xca9dba6e, 0xf3fc4587, 0xe13fc628, 0x3fc626fa, + 0x7c527ae1, 0x33e5433f, 0xd7a20020, 0x7f38bdc1, 0x8925ee0d, 0x34e2ddf8, + 0xff8a4bb4, 0x73f38b25, 0x61637d7e, 0xce878d0c, 0xa3fef9cb, 0x7bd1bebf, + 0x3a37630d, 0x69b4f1b5, 0xb4f1b453, 0x663915f2, 0x736fd7f4, 0xa3d4d68d, + 0x0f5abc88, 0x925e98ba, 0x337e79a8, 0xbfcc34be, 0xf0a5ee2f, 0x1f7147f8, + 0x4b5bbd4d, 0x2a5bdfb5, 0xb3c668bf, 0x62dbd985, 0x26b3309f, 0x87bfc219, + 0xf1ca4402, 0x3e6de762, 0x416e3a31, 0x60e4fc7a, 0x5e7284b2, 0xaf150f8f, + 0x080037b3, 0x1b39dfa0, 0xbd97940c, 0x55e3b66b, 0xaeeccf3c, 0x7bf7f8a7, + 0x467bae4e, 0x39805df3, 0xbf84994f, 0xa1fb2763, 0xf232c568, 0x607dca3b, + 0xcb88022f, 0xa23ef45f, 0x467e3196, 0x0f91594b, 0x80bec90e, 0xe2727844, + 0x4fbd83f7, 0x7e47eff0, 0x0ed86208, 0x2b7677fa, 0x1287c71f, 0x53e5815b, + 0xfdfbb7b6, 0x6675e600, 0x0679bae2, 0x307c8dc4, 0xd3e2e499, 0x2cfa4332, + 0xe744c3bd, 0x587ede39, 0x31f4efa6, 0xc5533f29, 0xd9cbe62b, 0x1dfe1613, + 0x04a00e9b, 0x71f8b7a8, 0x8f9f7d0b, 0xcfcb0328, 0x11adf40e, 0xf2f48874, + 0xc6733c61, 0xfe7960d3, 0x6496a3e0, 0x82119f5a, 0xce106f9b, 0xfae09bd7, + 0xa3a02f51, 0x06f9e68f, 0x3bbafc91, 0x0f47f899, 0x2e6693df, 0xef48bc9f, + 0xea2e4852, 0x26d996ed, 0xc7df7d07, 0xa3a486cb, 0x96b93a5c, 0xf40f477f, + 0x3f5f1c4a, 0xabd134f3, 0x46939efa, 0xef8e3c65, 0xe90e5d64, 0x0ad6dbaf, + 0x06f4137f, 0xfae3efaf, 0x46ecbd6a, 0x275bc3bb, 0xaf9db9b9, 0x4db78fa5, + 0x688b9ede, 0xd68db1fd, 0x6809dcaf, 0x9dca3cc5, 0x2ec9533b, 0x5bec2998, + 0x2ddbc696, 0x3b3a73b6, 0x0f4fa07f, 0xea7ad7dc, 0xea01e010, 0x75f3a7b4, + 0xacc6a705, 0x3747861b, 0x1dec369d, 0xffb803f6, 0xfbef44f1, 0xc8dbc046, + 0x5ee6f76c, 0xac329f18, 0x4473c6cd, 0xfc4fface, 0xf50fbf1c, 0x83930ed1, + 0x97e974d8, 0x0c4ed3b3, 0xeb835d8d, 0xf2eb67c2, 0x3f042704, 0x5bf8293c, + 0x8b6fcfd5, 0xa7036cf2, 0x2482f63f, 0x34c46bbe, 0x9e217872, 0xe4872a43, + 0x2b872aa5, 0xc7fadd85, 0x3e6edc5e, 0x60a5d6c5, 0x4fa005bd, 0x3b3cfef1, + 0xb72a4bb7, 0x7ee7eff1, 0x4c9c7c84, 0xf5c31a7d, 0xe4167cf2, 0xea014e7a, + 0x77dd0949, 0xc0388b45, 0x409fbe3a, 0xb9e7f72f, 0xe06ffb7d, 0xa3003bfd, + 0x7cffe45d, 0x8f1b1ae6, 0x3c6deb71, 0xff97ac9e, 0xb9b7e84c, 0x3d7a7de2, + 0xbbe85730, 0x377d3ab9, 0xce8e71cf, 0x0edca91d, 0xb2b945ef, 0xc2efab4e, + 0x9a44a9e6, 0x872f3ce7, 0x873f3cf7, 0x769d7bcb, 0x08fda30d, 0x3d59dc2a, + 0x77b4d3fc, 0x791c61c5, 0xc33283fe, 0x78aa1cef, 0x823e66a8, 0xb02cc7f7, + 0x8f18ed0a, 0x062e31bc, 0xa1f0ba70, 0x2dc7ecbf, 0xa06b944a, 0x7efef3f3, + 0x9427b3bf, 0xa4b2f37b, 0x6f7efdfc, 0xd570aecf, 0x829bf1c3, 0x6ef9131b, + 0x9863076a, 0x377f85bb, 0xc91eac3a, 0x0901fffb, 0x00d0a8f5, 0x0000d0a8, + 0x00088b1f, 0x00000000, 0x3bedff00, 0xe5557469, 0x73dcfbb5, 0xe1dc8487, + 0xc2040464, 0xc06e49b9, 0x612f4865, 0x1213d41e, 0xde0d4b22, 0x00c10580, + 0x86120137, 0x7c07504c, 0x0040e3e2, 0xaa1a4583, 0xf50af8a5, 0x22d28342, + 0xb04a0834, 0xc141170c, 0xd6de8ba7, 0xa44f7d6a, 0x40932861, 0xd2bb6a52, + 0xf7b79457, 0x3b939df7, 0xed83a404, 0x58b593af, 0x9ef37efb, 0x77f7bdbf, + 0x52015000, 0xaaa8e601, 0xd08eceb5, 0x092bd00c, 0x72c06e60, 0xd80e35b6, + 0x37fc0ddf, 0xbb746b7f, 0x01e5e696, 0xf7473754, 0xa41c5fe3, 0xbfe6cc01, + 0xff5616a1, 0xd845cc41, 0x766f3d12, 0xe890eadc, 0x556679a4, 0x086e17eb, + 0xa1e6ca0c, 0x840cfada, 0x9f12a24d, 0x6e0f351b, 0xca7a01b8, 0x7773948e, + 0xde0bc361, 0xc5c2221b, 0x002300c9, 0x5c78174a, 0x439c1cfe, 0x2186f77f, + 0xb09e7468, 0x39cd23c0, 0x098a6584, 0x68c79cf0, 0xb1c6994f, 0x477f788d, + 0x617c67e2, 0xc1864ef6, 0x15483f08, 0x3a6f3c54, 0xeba236e1, 0x71eb15be, + 0xdf8841e7, 0x11f8137a, 0xcbbf5b9e, 0xfe3e47e9, 0x695dc5fe, 0x88772b04, + 0x66084410, 0xdcf015bf, 0x2f65f582, 0x56fb833f, 0xdaf78d6c, 0x88e2bbb0, + 0x3c7008bf, 0x252b7c0f, 0xe3d7971c, 0xe070c341, 0x71dd8445, 0x8428f23d, + 0xdfd982fd, 0x513de68f, 0xd927efe1, 0xd187faa3, 0xf4cc4fbe, 0xee3f7cff, + 0x04b6c4fb, 0x9248caaf, 0x44e1a682, 0x84041489, 0x7b7f0bd5, 0x04fc8cd2, + 0x9e8f83f1, 0xf2b8014a, 0xb6c408ba, 0x817f24ec, 0xcfdc4a9c, 0x703d05eb, + 0x5d29b89e, 0x22f6c4ca, 0xeff9ecec, 0x8d4ce7e7, 0x4fc4e59f, 0xd599e914, + 0xf3a50e1f, 0xbe70374f, 0x4d99face, 0xf397a7e3, 0xe7e73573, 0x339f8d4c, + 0x7e35788f, 0x4f892bca, 0x9f8d6af2, 0xeace1c0d, 0x3a7537c2, 0x4fc4f5e1, + 0xa7155e6c, 0xa60f885c, 0x173f909a, 0x4f508a76, 0x12a80b6d, 0x4485c3da, + 0xdf511250, 0x3f8d04ff, 0x7e610a0e, 0xe50ecdce, 0xd29e9106, 0xc49d47b5, + 0x453bb9d7, 0x3f2c704e, 0x73eee941, 0xc81f9e44, 0x24d53c25, 0x087942df, + 0x408aa5c0, 0xb7fbe12e, 0x825a7df2, 0x79e3e522, 0xde2dfbed, 0x36efc8cd, + 0x85c01587, 0x8384f676, 0x227265c1, 0x3a81679b, 0x505f3c00, 0xf8845814, + 0xdd3e50db, 0xb2159e90, 0x5905c6cc, 0x87ec5282, 0x7e13200d, 0x24288282, + 0x1d2fed75, 0x3e462283, 0x814c3bb5, 0x67ff48cd, 0x3c80d0d6, 0xffaf187b, + 0xe913b192, 0x03c835f8, 0xd252bce8, 0xccafc235, 0xfc8cd815, 0x6c4c0879, + 0x0cc087df, 0x982708a5, 0xd8713541, 0xba224f60, 0x3fa85990, 0xf1bf35e3, + 0x7410e1ed, 0xef82af21, 0x3fae7081, 0x73a55d30, 0xc14d0726, 0x1e0fe87e, + 0x090f0732, 0xb2714d08, 0x7c73c245, 0x913c84e3, 0x660cb0e4, 0xf15decf8, + 0x21f846db, 0x1326a5bd, 0x8129ebc7, 0x0a28f1d1, 0xdd32f89d, 0x8444470c, + 0x4439e28f, 0x5904b4f7, 0x0816f365, 0xa30ccdde, 0x54df8614, 0x2881bf0d, + 0x4bc87387, 0x0df76ddc, 0x3547d3d4, 0x069f707c, 0xf1cf5b27, 0x1edf9588, + 0xad004f8d, 0xcd6be256, 0x227fef63, 0x71359d20, 0x49f920f6, 0x6e5cb168, + 0x39f9afed, 0x48afe1e4, 0xc05f384e, 0xf4f90083, 0x04db06a8, 0xb87b3bb4, + 0x1e0d21ff, 0xa5ace8d7, 0xde0bca36, 0xdc5b0212, 0x03e73fb7, 0xd3ad8939, + 0x3b0347f7, 0x1026e34d, 0xed6bfc80, 0xb2562dfe, 0xbf5a79bf, 0xb22187ee, + 0x5dacde2d, 0x169f912a, 0x41ba6fc0, 0x8b3edad0, 0x13dc2958, 0x7afb25ef, + 0xa1ecdad4, 0x5e76277b, 0x5874df2c, 0xef53805c, 0x3e75f9a0, 0x03c03465, + 0x0bdbd3df, 0xcbda0a7c, 0xe39de1a4, 0x8e164a8d, 0x8e7f177f, 0x7828e864, + 0x452fc133, 0xd7253ede, 0xfce39685, 0x8a728f0a, 0xdcd39ffc, 0xa0fecc0a, + 0x58bbf191, 0x28061324, 0x28a37d1c, 0xb858f911, 0x6c9e605b, 0xe636e8ea, + 0x50f13a77, 0xd478619f, 0x76f413ec, 0x71bbc148, 0x36ceeeea, 0xb070a3c3, + 0xf27c6a2b, 0x9f1a8868, 0x1be91d78, 0x6a71b5a9, 0xd194f488, 0x4a8d9ff1, + 0x235b6c6f, 0x42dae3e6, 0x4ba74f3a, 0x65ffef0e, 0x835f19e0, 0x9d75d199, + 0xcc5075f9, 0xba6101be, 0x91df665c, 0x5dff223f, 0xe2a48229, 0xfc5f1aba, + 0x6117f26a, 0x3d181a7a, 0x8f9d78a1, 0xf1a37cd1, 0x06bfa442, 0x8d55f1f4, + 0x67cdf20a, 0xd2af9cea, 0x3f3ab1fc, 0x337f7d70, 0x7d6c4973, 0x4686a6d2, + 0x9fa61ed5, 0xbe18b3b5, 0x7c21ee49, 0x295fd339, 0xc42f48ff, 0x4ef906b3, + 0x5ca74557, 0x5f8c75d5, 0x6d1131a1, 0xa62337c2, 0xff022ddd, 0x52fc11de, + 0x59f949d7, 0x7cd2f811, 0x8b4a67c4, 0x127fbd10, 0xb4ddcf1f, 0x1d1d51ae, + 0x90fc036e, 0x5e8227f1, 0x9d299fc6, 0x9be75ef2, 0x6ac7eb85, 0xfee019fc, + 0x45e88fa1, 0x7d3972fa, 0xd2fd2881, 0x65bcaef5, 0x14b48aed, 0x2004b38a, + 0x68f2c37a, 0xe7fc91f2, 0x9bff3a4b, 0x586f8442, 0xa13dbc1e, 0xa9bf3f59, + 0x64abf491, 0x6f2f4eb7, 0xf70bf587, 0xbff216fb, 0xea7c7a21, 0x53f5e8f2, + 0x667f73a0, 0xf53a5357, 0xfa43cf17, 0xbcfc69e6, 0x4853537f, 0xbf76fae5, + 0x67ac353b, 0xad12b365, 0xed85bf74, 0x6be31b71, 0x93b8de27, 0xbc0fe380, + 0x07c7cd1f, 0xb27b79ea, 0xc1af9b7b, 0x4d7ed91e, 0x7764e3e7, 0x7d72bd94, + 0xc4fd1df9, 0x4024f37b, 0x161fbd94, 0x4487dba3, 0x437baf9d, 0xa750e58f, + 0x1f5efe7e, 0xfc0fb7dd, 0x719f1a30, 0xc7bdbd36, 0x6fe91857, 0x5f1937d4, + 0xf9f4fc74, 0xd7a25f45, 0xddaaf3c3, 0x729afa6f, 0x320cdee8, 0xc49a56ff, + 0x71c75c21, 0xb56a47bc, 0xbf68a938, 0xbcd00be8, 0xc2cf416e, 0x873d309c, + 0xff99169e, 0x8085eb56, 0x196cfd07, 0x04ba56c8, 0xa5628267, 0xcb90f5fb, + 0x9c15e8b5, 0x7169f87f, 0x3df70051, 0xc59928b9, 0xadb81f9b, 0x5d87ff8c, + 0x6366d37d, 0x0cc250fb, 0x0ef38cab, 0xc1963b3d, 0x7fe93bb7, 0x337a47d7, + 0xc9a5ce2b, 0x97e65df9, 0xf6f0250e, 0xbedbf72a, 0xd5af28a5, 0xe7ed996e, + 0x5ad2924f, 0x39e13f50, 0x09916c0b, 0x098fef4f, 0x6de7b2bf, 0xfc239f03, + 0x4695de96, 0x41ff2ef2, 0x9c4f5149, 0xe2c2be57, 0xab5e7015, 0x7c274a49, + 0x658dcffd, 0xb96b30fa, 0x18fbd506, 0x4fd5f83c, 0xcf749dea, 0x1c58146e, + 0xcd17f773, 0xbb62e7ef, 0x4bd321b2, 0x30e81ea8, 0x9ce78481, 0x202fdf5e, + 0x899dcaa2, 0x3c777baf, 0xbf340f9f, 0x7c7cbaf2, 0x2f9a60fc, 0xfe70cb4a, + 0x7017ec39, 0x712adcfc, 0x397840b3, 0x2404dd1d, 0xc097dce9, 0x2b73f0ae, + 0xb865816c, 0x7fbb69cf, 0x673a7afa, 0xd29605bd, 0x93d7413a, 0x4e5f198f, + 0x3f5cba4b, 0xa1cfcc6e, 0x2dbd3679, 0xca9f2195, 0x157a9d4c, 0x2aefbc04, + 0xb5fb7912, 0xb6f91f4d, 0x2f73fae0, 0xaaf163f5, 0x276ca19c, 0xa19d3d7d, + 0x3ffb20ec, 0x462ed5f8, 0x3c4bfb5f, 0x51d03b6e, 0x111e569e, 0x315c5427, + 0x68387d33, 0x7c231f95, 0x23eb760f, 0x6a2f2ca8, 0xf8a12e4e, 0xe28cf511, + 0x45ebd46d, 0x1f126ebb, 0x2645ba36, 0x4ddf43af, 0xea472d1d, 0xf9867ab7, + 0xde64e289, 0x6d6eea3e, 0x9cafd154, 0x33822db5, 0xfaf5e159, 0xe8aef9fe, + 0x39983938, 0x81d128e1, 0xca30c679, 0xeb7cf453, 0x0733f533, 0xf533f1c9, + 0xe3630653, 0x43a74ad4, 0xde7fe725, 0x1c9330e1, 0x9c979a4e, 0x62b938a3, + 0xb9f985a3, 0x8ba98d8a, 0x414e29db, 0x5740f17d, 0x2c32927a, 0xda5b9e8c, + 0x2beedaa5, 0x07191dec, 0x5dad7fb4, 0xf36a6eb6, 0x6d6fd935, 0x5b129597, + 0x2d1b4503, 0xcaabb23e, 0xa0330e21, 0xf1b31cbf, 0xefa42d9d, 0xf3e20b95, + 0xe578886c, 0x53931b46, 0x4aa1c3ab, 0x3a77ee38, 0xaf0889cc, 0x6e8c4dba, + 0x60cc8657, 0xb8e60881, 0x5397063c, 0xf10d711e, 0xc5f6c649, 0xa3ac2f45, + 0x0412e4b4, 0x3d430d26, 0xfd70a6bd, 0x0c5bb6bc, 0x66047e50, 0xf98c5cc5, + 0x7ee01cd3, 0x5dbdfaa2, 0x39fc7cd6, 0x41f2aea7, 0xf9f965c8, 0xfcfc98e9, + 0x8e1e7474, 0xfe51a61b, 0x30aaffcd, 0xc43b24de, 0x5e6a3d7c, 0xd51e7e44, + 0xf2d0c96f, 0xa3c83ceb, 0x9d5aee38, 0xdd829b25, 0x13da3b4a, 0x41b059d2, + 0x2e56f860, 0xc4360312, 0xe79920b7, 0xa0976747, 0x5e8caddc, 0x2576c255, + 0x37c4b1e5, 0xf8710210, 0x0b0dbef3, 0x1767e4cc, 0x4ca57e6b, 0xdbe91f00, + 0xfa6f7899, 0x36c78a02, 0x56be33c6, 0xc7ee78fe, 0xd6bae12f, 0xa229c5a5, + 0x5e87d61c, 0xfee03e9a, 0xde149710, 0x67d2fce7, 0x0bdf49d2, 0x4857ee5e, + 0x22657871, 0x26e298ec, 0x974cf539, 0x9579e1ed, 0xe6ce9ecb, 0x8083e2f3, + 0x2ad970f1, 0x6f01d191, 0x521e02d8, 0x4520fec8, 0xf2d66df2, 0x1cd6acf7, + 0xd34a5bfe, 0xfc991ee2, 0x9c5faf37, 0xced171c6, 0xc676a7f8, 0x066ff8bd, + 0xf993d5ed, 0x57d13f09, 0x4c66126a, 0x5bb4fb60, 0x328b8ec9, 0xb7701e78, + 0xbdd2cb06, 0xea8f09d3, 0x32ef3635, 0x1c47df37, 0xb181e1aa, 0x5429b54d, + 0xf3c223f1, 0x0b779b4d, 0xbc796dc9, 0xb924ef12, 0x0e7af282, 0xad98c7ab, + 0xa72fb449, 0x76e64ab3, 0x989ffd8c, 0xc1dabfb1, 0x227560fd, 0x15cedbf2, + 0xb7fb84c4, 0xbe4cafd1, 0xf0dccf5f, 0x85f3cefa, 0xb99df8f0, 0x49e4afc4, + 0xdb1e108f, 0xc8af6645, 0x29c3358c, 0x0e2ed96e, 0xf1a64e7a, 0x57e445c3, + 0xc81cefe7, 0x1db2b6e2, 0x617bb21f, 0x56e726be, 0xc7296f2d, 0x33844ef6, + 0xf8bdb832, 0x666ba845, 0xe8bf9e6d, 0xabc7d6f2, 0x9c985957, 0x937fd1aa, + 0xfa5ea8e3, 0xb56fb65b, 0x79469423, 0x961bf556, 0xcb6fe4a1, 0x97cbfc35, + 0x09fd19f6, 0xc5b94fea, 0x543dd125, 0xa95b16a5, 0xb028d55d, 0x6a5d7876, + 0xe7e3e93a, 0x4938f7cb, 0x07c4ce4f, 0xb4df743d, 0x52f7882f, 0xc0da887e, + 0x97cf93ee, 0x873f367b, 0xc85259ed, 0xacf8e021, 0xc89332c7, 0x82949f2f, + 0xd93f1a56, 0x5b5136ec, 0xd4d1a491, 0x62dfcc56, 0x55d1cfed, 0x43fa6b35, + 0xe046a5fe, 0xed7aacf2, 0xcf0335b0, 0xffc9a95b, 0xb30ff6ca, 0xa756cfc9, + 0x397db287, 0x14d9de4c, 0x04cfc2ff, 0xbcd6df76, 0xba60ebc6, 0xde486bbc, + 0x34f35f68, 0xdeecd739, 0x7de924f3, 0xaf3bc90d, 0xdea0beab, 0xaffd611e, + 0xbe022a6f, 0xc5e908fe, 0x53cc7899, 0x05b97b79, 0xbcacc7db, 0xbfe6acfd, + 0xf790bfb0, 0x4f3c39ab, 0xac6b79e3, 0xbe4adfbe, 0x263f244d, 0xa7f31b0f, + 0xadbd1a4d, 0x9270deab, 0x3f6caefc, 0xc1c8eefc, 0x57e61784, 0x5ef44df2, + 0xd12d47e3, 0xb3f864ef, 0xe896a1b8, 0xefe98675, 0xdecd73d4, 0xa7d3816a, + 0xd66b5bd3, 0xb5c7d7e8, 0x3a345bf5, 0xd7e340ab, 0xbedc7eee, 0x7b227b34, + 0xa749fca5, 0xd7c49fcf, 0xbef9faeb, 0x4d6edf46, 0x766a414f, 0xbe487f12, + 0x7f5067e4, 0xcd50eb14, 0x2b94e06f, 0xfcb1373b, 0x8e979751, 0xfbe1a7ff, + 0x0a4c4942, 0x04d5b1cb, 0x5ded9a73, 0x1a23c5ef, 0xe8ad4f1f, 0xfc82de9e, + 0x06f31cfb, 0xbea36e96, 0xd3ce239a, 0xaf3f46f5, 0xfdc95b60, 0x86600eac, + 0x9fafed20, 0x304d527b, 0x81273ed3, 0xbf8e87db, 0xf505976e, 0xe81feed3, + 0x1c5779a4, 0x37443999, 0x0cd3ff3f, 0x5457ad89, 0x4af3f307, 0x7010108b, + 0xebc094e8, 0xec56a782, 0x84e79671, 0x327ffdf5, 0x62ff4e84, 0xa78aeb4e, + 0xfa117fae, 0x782cf0cc, 0xd4fdf276, 0x7a16f4fe, 0xd74df3a9, 0xca9c584f, + 0x3d5893e2, 0xca7dedad, 0xf6c5e74a, 0x19caf1eb, 0xfec97bca, 0x10faf2f7, + 0x5923872c, 0xeeb0f711, 0x0ecff1d7, 0x84f7c343, 0x65e72f7e, 0x2efa3066, + 0x1f35b341, 0x85d578fd, 0xa6539150, 0xf5644fb8, 0x08bfbba0, 0xb3d42e8a, + 0xbceeddaa, 0xeaad7bc8, 0xa7a611f2, 0x756210d5, 0x1f55b2cb, 0x7d230f16, + 0x45c629fc, 0x8c5757e4, 0x3d5c52b5, 0xa1cccb77, 0x0dd3e724, 0xb8badefc, + 0x142bc87c, 0x786e9f17, 0x0e666d21, 0x1a282bad, 0x6b65fd89, 0x9e393207, + 0x53150f89, 0x1171fdbb, 0x6a358ea8, 0x53c590cb, 0xd1ca3db1, 0x39e89137, + 0x8e1624d9, 0x2cfb908c, 0xa54f1690, 0x92eccc78, 0x6a4e0ec8, 0xc2deabfe, + 0x933bd2e5, 0x277279eb, 0xa0bafee4, 0x44db3ebe, 0x7e84db7c, 0xc5aee913, + 0xd507a018, 0xff1e054d, 0x5c42b1cc, 0x1fd63ccf, 0x4dfb13d7, 0x09aa2709, + 0x13c7b6ff, 0x4ddbaa24, 0x883781b3, 0xfb0769ed, 0xa6e851e4, 0xc6287168, + 0x9d5cecab, 0xbdf9fa4f, 0xc51eb932, 0xf5e20bee, 0xc76fa4a1, 0x19d63ab4, + 0xcb8bef0d, 0xee893a7f, 0x3d5b8ba5, 0xf9f74449, 0x140df1fd, 0x70b79cc7, + 0x7fefa57f, 0xd88f77bb, 0x77d88ef7, 0x0c65800d, 0x189901af, 0x6740253f, + 0xe3eba4fc, 0x70baeaed, 0xcdd78d22, 0xfaf53db5, 0x5ecd1ffa, 0xd64de257, + 0x12f2f0e9, 0xce365864, 0x9e083aa3, 0xe5f0985f, 0xd9c510ae, 0x86c9368d, + 0xbd259ef4, 0x86fab6c6, 0x1481eac8, 0x9f9e9313, 0x8050637d, 0x138ab7f2, + 0x2cd15dbc, 0x7884a804, 0x22b3ed64, 0x718d9fcd, 0x2221775e, 0xed717d6e, + 0x6bff5224, 0x9ecaff5e, 0x56daff38, 0xe037bd81, 0x5e263db0, 0xfca7b77d, + 0xf5578bef, 0xe754bffc, 0xa42ef6bb, 0x57cf5bf3, 0x0c5ea20e, 0xedf30bcf, + 0x2c3992ea, 0xc4bcbd5e, 0x709b60cf, 0x5628cd6a, 0xbab176e7, 0x5e5a2fef, + 0xdc917b10, 0x4ebc0f77, 0xbb48e779, 0xbdbb224b, 0x401164ba, 0x63abad36, + 0x5ebb9750, 0xf77bb9df, 0x6aeeb621, 0xa37da0cb, 0xbb01dd70, 0xcee7f98b, + 0xf79892f7, 0xbc58ef91, 0x7dd913dd, 0x7451dfc1, 0xd772ebf9, 0xded4abe9, + 0x2ffc7445, 0xdee5c53d, 0xd33aded9, 0xfa1ef449, 0x11bef251, 0x9704ef24, + 0xb9da7144, 0x5c5fdcf5, 0xf2bd7388, 0xc2fbca20, 0x80698986, 0xa1f6727e, + 0x7f512787, 0xa2417ec5, 0xbfbbdcf8, 0xd3f949c4, 0x4eadcdef, 0xbf7ef3ca, + 0x0abf7f5e, 0x469fe488, 0x3489838e, 0x0cd0647f, 0xe233ee32, 0x2337ae41, + 0x0a039b2e, 0xcfd83bc5, 0xbbd716ea, 0xfe05bab1, 0xfde09725, 0xaf2f7b39, + 0xd072e873, 0x1a51adf3, 0x9333079d, 0xfeb4ff38, 0xffbce182, 0xe35d86fc, + 0x4d8bbf69, 0xbef08916, 0xfb6164da, 0xc93cc3cf, 0x5b33ef44, 0xed421e79, + 0x37d93778, 0x35e637cf, 0x7aa37cf3, 0xbab14581, 0x4167eaba, 0xe7ca3cc4, + 0x73a64fb0, 0xa7fa6ae7, 0x853cedeb, 0xef0f37d3, 0x5637a235, 0x99a1138f, + 0x4edddbbd, 0x3d56ff9f, 0x37e31dde, 0xa982584e, 0xef9f8993, 0x77565e89, + 0xe87e85b9, 0x403f257c, 0xc3ebac7a, 0x0517d43c, 0x079a9287, 0xea3e93e6, + 0x9bfba1fa, 0xa5e35bf9, 0x2dfe51b3, 0xdb5daa31, 0x1b3a53d2, 0x7a69e719, + 0x99823908, 0xe9d2abe8, 0x535d6b8b, 0xf8a6b082, 0xc421150f, 0xafe88473, + 0x9152a4f0, 0xc05e8bef, 0xc69ed964, 0x642091de, 0x061ef601, 0x6a17ff4c, + 0xa2b1b075, 0xe519bfbd, 0xf3742a58, 0x96d93e52, 0x2e4d50ef, 0xf9327796, + 0x04253e96, 0xc44ffb00, 0x9ea9733b, 0x0e420330, 0xbb3fb637, 0x464d7643, + 0xf5ebd5f9, 0x2d63b56a, 0xe65767d5, 0xfffb5a8b, 0x3aa8944a, 0x8afdffc8, + 0x530f20ea, 0xffb5943d, 0xf6f5425a, 0x71b477b6, 0xe3425eb8, 0xab402b6d, + 0xdbc57d8b, 0x85c7d03f, 0xdb5fb409, 0xe45c7d2a, 0xfdf5e7ed, 0x98daf6b5, + 0xe331a5f1, 0x1ff6f12f, 0x504e227e, 0x88f5c273, 0x9ef7b527, 0x7d5a65d2, + 0x8336f4c2, 0x93df2cf6, 0x1d17cf54, 0xe7941d67, 0x27947914, 0x7bf0dde9, + 0xcd7ffd7d, 0x44af3844, 0x9f78ad50, 0xd9026fc1, 0xda75e7c4, 0xe1ffdd7c, + 0xc9bac83c, 0x6f3439bc, 0xcb3cd448, 0xda7de6cd, 0x376ebf75, 0x89e2979b, + 0xe77f4fde, 0x9c56e29d, 0x278f5f34, 0x94afef62, 0x8c471e2c, 0x699254ca, + 0xb40b239e, 0xe9bc42b8, 0x16615a3b, 0xbb4a038f, 0x99b677f1, 0x32711d43, + 0x37e431e2, 0xf9077afe, 0xbe3c0db3, 0x98efb57a, 0xf41fb43e, 0xc757be8e, + 0xcc43ef21, 0x3cb3b5af, 0x86fb8ff2, 0xd1bfc8b8, 0xebaf24db, 0xea9f7da5, + 0x759dc5ee, 0x67dfbea6, 0xacb74def, 0x409df543, 0x5f71a875, 0x66f3bd71, + 0xc93efcf5, 0x01b0da75, 0xb48fc8dd, 0x25effba4, 0xbb0da63c, 0xf9da88bb, + 0xaef662b6, 0xefafa3dd, 0x6b3fea1e, 0xa1089e52, 0x6346fb3e, 0x7f611b20, + 0xa2130a13, 0x983f0fda, 0x3d844a0c, 0x57b87a4e, 0xd291fb54, 0x53f9a8cc, + 0x3515dd67, 0x0d0b6c5e, 0xf69c7966, 0x78ab7cce, 0xc61df3a2, 0x9f3debc1, + 0xc7d3fbed, 0x6a1fa28f, 0x5d59126b, 0x2dfeee77, 0x70828f1f, 0xec46805c, + 0x74bdfb22, 0x93ca044c, 0x5757eb63, 0xb46eb420, 0x80f135f0, 0xe5c58474, + 0x8d1fa8ff, 0xc6a34bc8, 0xfb4567a7, 0x1f756bd3, 0x23180ba5, 0xac7568d5, + 0x594f7b2b, 0xbbff5e65, 0xeafd0371, 0xde90b47d, 0xfe903b3b, 0x2d7fa841, + 0x38adaca7, 0xe64b23de, 0x05ef4779, 0xe5007966, 0x4acc0b11, 0xa1171e84, + 0xbea8b81d, 0xde3f71d2, 0x83474878, 0x74d7d6c2, 0xb8bb5898, 0x5465b4d7, + 0xc336aa6f, 0xc754dd80, 0x6e2c1d90, 0x7df9fe2a, 0x67e580e3, 0x63f74282, + 0xe7c2a355, 0x4c1ebf8b, 0x1db1b0f5, 0xc53ed8e3, 0x50131c22, 0xe0281f37, + 0x31d5d17e, 0x76d7f581, 0x6e0f9b00, 0x54ace2ff, 0x7144aefe, 0x29aefe6f, + 0x72888985, 0x86795bb2, 0x2297ebf4, 0xfbbb222c, 0x86f7bde5, 0x5f7a1494, + 0x32283418, 0xc59358ff, 0x6a400ddf, 0x5df74ebf, 0x990481ed, 0xc5eac8e4, + 0xb7ed0f14, 0xec7c77b1, 0xda90f567, 0x94cdb603, 0xdb3ad5e7, 0x0afec9b3, + 0x8907c60e, 0xe307438e, 0xcdbf2ccd, 0x73a1aff4, 0x2bf60e0b, 0xd9537ca4, + 0xf3033367, 0x98f7ca63, 0xca589e3d, 0xd25d3ae4, 0xea37fb04, 0xbfbf6c63, + 0x4cabf381, 0x872ebbe3, 0x7eef8d72, 0x1a659f8d, 0xdf1067df, 0xc5f2ee91, + 0x587b6fc8, 0x29a2c52e, 0xb260fd7b, 0xca5e3e8f, 0x15bf743f, 0x8eaaf7cb, + 0xeaf7c638, 0x7c9a1e8e, 0xa1c945bb, 0xb58323bc, 0xdb7dba07, 0x7ae2ce89, + 0x5fee2f94, 0x287a0f6e, 0x17519a3f, 0x87f7a5ef, 0x45dd8b6b, 0xab85d7c4, + 0xfee6e1b0, 0x8ab5ee8b, 0x74add4df, 0x4a65c844, 0xb8c82e47, 0x2c8ec4df, + 0xebed5f06, 0x2e724bdf, 0xcecf18eb, 0x66c8ef29, 0xa95c62e7, 0x23fef8b0, + 0xfbffbe3d, 0x20b9c7be, 0x21811b30, 0x75dfca8a, 0x26ef3602, 0xcbfdfc21, + 0x54238c4c, 0x1696673c, 0x5b650e7f, 0x6c9b7f22, 0xf8424381, 0x72ff18fb, + 0x9da86a91, 0x3be5d7f6, 0x678c7c99, 0x26e5dd70, 0xd543930b, 0x950f5fa1, + 0x9092fc70, 0x4eec9ddf, 0xc47ff24d, 0x810995ee, 0xcf6c161d, 0x73977e7f, + 0x8fd61c84, 0x43d07366, 0xf919a67e, 0xe6b5f548, 0x00b8e2d5, 0x942667af, + 0x9eb5b80c, 0x83b8ebcc, 0xb79febf1, 0x286b4dd3, 0x66cb869f, 0xed879796, + 0xb78ef375, 0xb8127f48, 0x6ecadcfe, 0x58912cf7, 0xbf6b167c, 0x959eddba, + 0xf9227ffd, 0xcfadbbde, 0xfee11fe0, 0x584a5363, 0x99ef1cbd, 0x87583ca8, + 0x7f31eec9, 0xb3b7f9a1, 0xcac7bb6f, 0xcf6b12f8, 0x6db37d7a, 0xb2019dff, + 0xf68093f7, 0x2fb47a4f, 0xd9a2de41, 0xdd07f33b, 0xb3af815c, 0x339951f7, + 0xddef14ed, 0x9e1ddec4, 0xdece6fd4, 0xf23939bf, 0xf85201bc, 0x1c846afb, + 0xa43d50d7, 0xc9852db8, 0x2e9b9751, 0xba7e5d47, 0xfd963ebc, 0x637d1177, + 0xd775fdb6, 0xd55762ff, 0x53073deb, 0x793b767c, 0xfee1e3dc, 0x8f285ff6, + 0xf7373c7b, 0xfe7af7bf, 0x7e8bff09, 0xe26ec072, 0x5bc3a64f, 0xa3f9872f, + 0xb741e3cb, 0x2433d8bf, 0x68241fcc, 0x6f4fd530, 0x9ee98fc7, 0x99fefc6f, + 0x67fa0b7e, 0xfff433fc, 0x1292f9c3, 0x78b12f9d, 0x49e50466, 0x5527963e, + 0xfc83bd53, 0x4fe818df, 0x15bd59f1, 0x9aa43e58, 0xee4979ba, 0x42d97625, + 0xc5259771, 0x3afd216b, 0xbea211ea, 0x48f56bef, 0x2496087d, 0xbd0ddfe8, + 0x128cf2cd, 0x43cb4997, 0x30f6f30e, 0x09bdfc7d, 0x0c94d794, 0x18e1c6d2, + 0x6c089f1f, 0x472df9fc, 0xcdb25e59, 0xfc20aca3, 0x4c48f05e, 0x74b7173e, + 0xfde7e3ef, 0x5747c40d, 0x04bbffb2, 0x5676ad6b, 0xda136b4f, 0xc3b91773, + 0xdfb57ff3, 0x8817f271, 0xaca3c877, 0x502f79a1, 0x12352231, 0x16ad79f2, + 0x84e6f748, 0x5601cbfb, 0xae58bdd0, 0x6044fd1e, 0x1c3c1df1, 0x1fbe9437, + 0x959f7604, 0x35b1dfeb, 0x06c77f44, 0xb3e3175e, 0xfea11dfe, 0xb09de09d, + 0xd7bed25c, 0xf92370db, 0x866ce4eb, 0xafdf1173, 0x2e9059b5, 0x22efd757, + 0xff477d85, 0xabd6fb42, 0xf2cf1ad0, 0xd7efe8d9, 0x4f3013aa, 0x7b287e45, + 0xca3b411c, 0x04f6e171, 0xab986756, 0xa47b8fd7, 0x31f44bb0, 0x3d03d389, + 0xfd7dd8d2, 0xe74ba6b8, 0x2cff4097, 0x6fcdc533, 0x1e23355f, 0xeff1f66f, + 0x99543925, 0x285f483e, 0xdea45d53, 0x95d0f749, 0x4a97a21d, 0x9d5a5530, + 0xb5529a1e, 0xbc188afa, 0xb98fc717, 0xf54cdcef, 0xfe1ec3bd, 0x0dd9714e, + 0x5d519dec, 0x10b6936a, 0xa70fd72e, 0x71ed8d3f, 0xe979f719, 0xcef2eefd, + 0xa366b367, 0xc05ad01c, 0x00fae2c9, 0x36c1675b, 0xd2b91f7d, 0x96ba42fd, + 0x4220fbbf, 0xbb9f3a1e, 0xa28f1ff0, 0x0e29bdfa, 0x09dede98, 0xc78a241b, + 0xa58c3975, 0x838a53c7, 0xc8efe0de, 0x6ce8050b, 0x3e725c53, 0x5dfbe78e, + 0xb0ef8beb, 0x52cd017c, 0x6cdbaa8d, 0xfcf37998, 0xa5602522, 0xbae9bfad, + 0xf68f25e3, 0x06103e4e, 0x791deff2, 0x9b52a35d, 0x952c5633, 0x6a4f44cd, + 0xbfe4979c, 0x77666370, 0x7c3043f2, 0x83ce441d, 0x2f4cc90d, 0x1845ba56, + 0xb7367a8e, 0xfba4c905, 0x160ee5a8, 0x92d83df7, 0xe313a0c4, 0xf8bfea4e, + 0x7983fbca, 0xa7cb871d, 0x63eed5f8, 0x6afb1c58, 0xf563063f, 0x4fb9fcd6, + 0xd84b77a1, 0x123ab023, 0x75ca12f9, 0xc7563d75, 0x6eac8378, 0xeec096f7, + 0xbf9b293d, 0x75495463, 0xd20e1dec, 0xc22f2c7d, 0x2ec94b25, 0x6cddf45d, + 0x8faeff12, 0xf7dacce5, 0x3e4d4eb1, 0x7df9d009, 0x881bef6c, 0xccb67277, + 0x3d208bbf, 0x264949c1, 0x5cfc9bb7, 0x393fb66a, 0xe6bde29b, 0x9f54459d, + 0x4aea0b9a, 0x13d94770, 0x6ae848dc, 0x77b497a7, 0x2b0f5d31, 0x852173b5, + 0xc6855feb, 0x3e8d4ad6, 0x2b5418cb, 0x4772cfa4, 0x377ae6f6, 0x80fe8691, + 0x1f0adf7d, 0x40fe3dfc, 0x3f7407bf, 0x2cf535fd, 0xc7d2cfc6, 0x7ce3ddb9, + 0x0ffd175e, 0x511f5021, 0x6faceac7, 0x77b0233d, 0x326ebd6d, 0xbd0a0ccd, + 0x095422ef, 0xd2f7d296, 0x8598e104, 0x62e38b9d, 0x8cc3ab12, 0x63ebfc62, + 0xd39d5952, 0x9830ebce, 0xfd43dc27, 0xbf66ead7, 0x7920f8cb, 0xc51bf7d9, + 0x6c4f5e36, 0xdf644f7f, 0xee8add1f, 0x555e5af1, 0x6f62e07b, 0x5f71dbb2, + 0xf7e27e89, 0x11e38b71, 0x67c753ca, 0xf197f7f3, 0x9828a6d9, 0xe98bfb2e, + 0xea3b3fdc, 0x5f909ba6, 0xc167be7f, 0x8771df2b, 0xae887ae9, 0x40a7ba2c, + 0x4d3e90b6, 0x371de504, 0xf06df56e, 0x5064f6b3, 0xf7496c19, 0xa54eca4f, + 0xac0310ef, 0x7dc47c7d, 0x8b125eac, 0x655e2c7f, 0x2c5efcd9, 0xc14536cb, + 0xcfdfb271, 0x5e1852f1, 0xd1365fb8, 0x24f5e3a5, 0xdfea4ee9, 0x88555f25, + 0x7ccaef90, 0x02d7df91, 0xf2c3afbf, 0x25496b1d, 0xbd108ef9, 0x0c17ab4c, + 0xe0f48479, 0xa5eadd9a, 0xbe5d3b77, 0x9bde8108, 0x638e72c3, 0x88ba52fa, + 0x6c91cbeb, 0x6a0baf37, 0x580e4772, 0xf942ae28, 0x9a7c4d3f, 0x75e44237, + 0x3fe50938, 0x4addc980, 0x82995e36, 0x2ae8cf72, 0xde2d5adf, 0x66e2d1ad, + 0x66f51fbd, 0xeae9f105, 0x89fd61de, 0x4607b53f, 0x7a9fc4c8, 0xd4dbcf13, + 0xd0ead6ff, 0xa38bc99a, 0x47ef62ee, 0x297af660, 0x45be2aff, 0x9355b29e, + 0x961ef1cb, 0x5fb60171, 0x4076bbf4, 0xa6809fd3, 0x9c70ff57, 0xe2a21fd5, + 0xffa211ac, 0x754fe265, 0xf32b55dc, 0xfe7bda63, 0x19b37a56, 0xd11fd612, + 0xb26ff0ea, 0xf5cbe247, 0x55f9f506, 0x44e7ff5a, 0xa64ce7d4, 0xef28e7cf, + 0x75e56e3c, 0x156456e7, 0xff107ffd, 0xccbbfccb, 0x3e9a77f0, 0xbc512b06, + 0x8042e704, 0xbad0f9c1, 0x9fce1072, 0x469658d8, 0xfc9854f8, 0xa2ad3eec, + 0x3be9bc2f, 0xec2f681b, 0x76fcfc81, 0x7a77d2c3, 0x5e538a20, 0x5c285b74, + 0xb041b49b, 0x97be40f4, 0x41582d34, 0xb78fb46d, 0xb70f4e48, 0x0ee77a6c, + 0xe39d17ec, 0x8f1c7d98, 0x1cac5391, 0x45fc6b0e, 0xd39b787b, 0x70ba30a5, + 0xa1ed4dfd, 0xe12bdd06, 0x01ffffa5, 0xd5b93efd, 0xefd023ff, 0xe3781b15, + 0x7a6ec8e2, 0x3fbfcc83, 0xf3e7f68f, 0xfa27df80, 0x923afa7e, 0xf397dd20, + 0xf4979ba1, 0xfb8592ea, 0x807d4bcd, 0x0125c1d9, 0xf0bcec2f, 0xfee906fd, + 0xe199791e, 0xf4d6a37b, 0x39f92e5a, 0xc77e57bc, 0xe699e2fc, 0xe4dd0395, + 0x64e903ff, 0xd99f96af, 0x735ff5bc, 0x9510ccbf, 0x80ceb4d3, 0x01a03406, + 0x0340680d, 0x0680d01a, 0x0d01a034, 0x1a034068, 0x340680d0, 0x680d01a0, + 0xd01a0340, 0xa0340680, 0x40680d01, 0x80d01a03, 0x01a03406, 0x0340680d, + 0x0680d01a, 0x0d01a034, 0x1a034068, 0x340680d0, 0x680d01a0, 0xd01a0340, + 0xa0340680, 0x40680d01, 0x80d01a03, 0x01a03406, 0x0340680d, 0x055ff01a, + 0x328d1fff, 0x800060f6, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, + 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, + 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, + 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, + 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, + 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, + 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, + 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, + 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0xee017e3f, 0x0014ab55, 0x000014ab, 0x00088b1f, 0x00000000, 0xc5edff00, + 0x30001131, 0xee300408, 0xd80ea5ea, 0xabdef271, 0x964d2104, 0x5dbbcce4, + 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, + 0xee017e3f, 0x0014ab55, 0x000014ab, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x00088b1f, 0x00000000, 0x62f3ff00, 0x51f86063, 0x408cc10f, + 0x7f120cb6, 0x66476028, 0x48107d08, 0xf3e2061f, 0x2fe9a48c, 0xb9b04160, + 0x40afec80, 0xa8597833, 0x88a1bee7, 0xcfd2738f, 0x81ae792e, 0x66322ff7, + 0xe86067e6, 0x6ff047e4, 0xb3caa3f2, 0x3dd7d3f0, 0xb000c6b4, 0x00eeff4a, + 0x0000eeff, 0x00088b1f, 0x00000000, 0x7dd5ff00, 0xc554780b, 0x3d9cf0d9, + 0x3764dd97, 0x2485cd9b, 0x200d8410, 0x125c40a2, 0x126e20ee, 0xc3116088, + 0x65e28145, 0xb201ae41, 0xdb3f6911, 0x5cbb7ffa, 0xc6d6a444, 0xa0b45b4b, + 0x06a2828b, 0x82482459, 0xa5c8ba1b, 0x5835b5b4, 0x0da978aa, 0x24c4dc88, + 0x97f4b004, 0x3bef3fca, 0xce7bbb33, 0xf4bc4c6e, 0x7d6f9ffb, 0x7339867c, + 0xef3bccce, 0x6779de7d, 0x313b10a2, 0x0ae42775, 0x64246efc, 0x19084c99, + 0xbbc32d14, 0x32413cbf, 0x46bcf909, 0x08f39a75, 0x86a1d929, 0xc5f5a46f, + 0xd400a41b, 0x0893bb4d, 0xd3484819, 0xcaf7563a, 0xa08e8f0d, 0x4ca764ed, + 0x8482d136, 0x4592266d, 0x610b09c8, 0xd60a673f, 0xeab126e7, 0xee7b0de2, + 0xd7e7fe82, 0xfd12499a, 0xec8d44fe, 0x4d92fa86, 0xb4488052, 0xad21eebd, + 0x5e7fed0b, 0x39260a40, 0x63d37d69, 0x9085339a, 0x6cbfbbe5, 0x5c057182, + 0xe2167c67, 0xbfbe00d4, 0x23f63565, 0xadb03ca4, 0xa7ed0bb4, 0x99725abc, + 0xebe538e8, 0x038df0a4, 0x9014b9e1, 0x370bbf69, 0x0fb3895b, 0xc10ae183, + 0x4b1e7171, 0x6971d3d6, 0xd2a9447f, 0xe3a252ca, 0xf19cfc09, 0x4471c5ad, + 0x744bf17d, 0xc55dfa1c, 0xa60b92ab, 0x9e226158, 0xa9bf1d20, 0xf3da692e, + 0x32df9836, 0xec4a77ad, 0x0ebe663c, 0x6c0f28f3, 0x006d4ad0, 0x6e6d06d7, + 0x0b7f68bf, 0x0f56ff37, 0xd99edad7, 0x6376989e, 0x5147c679, 0x2f5a3bda, + 0xb41dc427, 0x6d01fc01, 0xf3e8ff62, 0x908d295a, 0x4cbfd04e, 0xff68969c, + 0xb9f1f884, 0xc0615c4c, 0xb8a5093b, 0xead6e962, 0x496dd3d0, 0x0db6ff1a, + 0xe9c97e78, 0x81cf98f0, 0x1cbe13e5, 0x73e57f2c, 0xf1bf9c22, 0x29f2c1f5, + 0xff9f0b9f, 0xcb1437d6, 0x96373ef5, 0x62c6facf, 0x8657c1b9, 0x9bef3def, + 0x9f26e586, 0xe8bf9f07, 0x4be58f9b, 0xfe7c4abe, 0x2c7eef8a, 0xf8fcf8b7, + 0x356fab7c, 0x557cdb96, 0xf4e76e58, 0xe00be1da, 0x9b7d3b7b, 0x05f3acb1, + 0xbe1bf9f1, 0x017f2c5a, 0xaa65a478, 0xa14cb1db, 0x4d1d4a74, 0x484d941c, + 0x32d95946, 0xa633d695, 0xa7b67ab0, 0xf146996a, 0xd69b3d94, 0x2b731d29, + 0x6999961b, 0xd652ee7b, 0x58efddde, 0xddeda16e, 0x9ef6b257, 0x93cb6555, + 0x27cf7b68, 0x8135fb59, 0xb4c9e5aa, 0xac8d9afd, 0x61b06fbd, 0xf7b695b9, + 0xd7ed61ad, 0x6c2b1d87, 0x3efd7eb4, 0x286c2f56, 0xeb42915b, 0x7d598785, + 0x0ad56348, 0xc87efd3b, 0x88fdf671, 0x4ceca096, 0x55db1fc0, 0xd2843dd7, + 0x52fed7ee, 0xd68c32b7, 0xc47dd735, 0xff66c845, 0x33a56ead, 0x865a87c5, + 0xd3fcbbed, 0xc32b5d58, 0x33fcb7f6, 0x6a9dfdf1, 0xec7fb625, 0x9df6c72f, + 0xb7b6255a, 0xf6c3eff8, 0xdb0ab53a, 0x601ecb4d, 0xdb0aad75, 0x883d9733, + 0x52a1bfef, 0xd2138760, 0x6ea3d97b, 0x966f853f, 0x7d02a9e4, 0x9caa6cd2, + 0x28b7404f, 0xaf901ce1, 0x0d322487, 0xc4a7e5e4, 0xa1e6fa89, 0xc83734ab, + 0x8343f6e1, 0xc539079f, 0xe7d4265f, 0x0f26b0be, 0xfb0a79fb, 0x3d3f68d1, + 0xf0a7efdb, 0x7ebaa19d, 0x2f99df0a, 0xf80e79fa, 0x63b939be, 0x677f6cfd, + 0x779e1eb8, 0xaf3f45ca, 0x8ef63f60, 0xaff0abcd, 0xfcf0f523, 0xa7e89175, + 0xde95e706, 0xbc767831, 0x1793f14f, 0xfbc767ed, 0xf6123f14, 0x64fd8f53, + 0x419e0c75, 0xf5d50c1f, 0xf983e833, 0xd8039fa2, 0xf58e974f, 0xe183e3b3, + 0x283e787a, 0x8dbcfd17, 0xd8eb74fd, 0x387d06bc, 0x87cf0f52, 0x473f448b, + 0x1d1e9fb0, 0x51e767eb, 0x1e767e3d, 0x28e7e08d, 0x63bbd3f6, 0x4c721af3, + 0xc7219f8f, 0x8339f822, 0x63aebf74, 0xa63cecfd, 0x63cecfc7, 0x479cfc11, + 0x363bf278, 0xe89f21af, 0x93e433f1, 0x632e7e08, 0x831d053f, 0x1eb4eea7, + 0x23a7753f, 0x982551f8, 0xc18ee0d7, 0x1e8cec33, 0x44cec33f, 0x009763f0, + 0xeb1de19e, 0x1e8ceea7, 0x2267753f, 0x7846c9f8, 0x5e6c7546, 0xe3d33ec3, + 0x1167d867, 0x9e1138fc, 0x08cdcae2, 0xf4fda10f, 0x379fbb6f, 0xcff5e9ce, + 0xfe98e71b, 0x8fc47819, 0x21cd57fa, 0x6467002e, 0xa25f994b, 0xd6932575, + 0x89ba509d, 0x055fda87, 0xf83f70ec, 0xd32fd1b8, 0xb4ea94f6, 0x58ce3582, + 0x02ec5c7b, 0x4d03ec78, 0x18ef7b3a, 0xa7abac99, 0xd9d74e8f, 0x5df1cceb, + 0x29acf574, 0x9cf5743d, 0x7dd3ae3b, 0x817665df, 0xd175deae, 0xdbbd5d70, + 0xf7dd62d2, 0xd66e07ce, 0x3958f7b5, 0xf5ef5749, 0xf5750fc8, 0xd2ce4fde, + 0x2bacfbd5, 0xdd77f5d7, 0x7aba25c6, 0xea9feabf, 0xcb35f9ea, 0x68577575, + 0xb05eae8d, 0xff5d71ef, 0x5a7adf03, 0xf87c1f57, 0xe87d5d39, 0xbeeb2f47, + 0x35fc7e1f, 0xd9e47d5d, 0xc7ff065d, 0x97d138e6, 0x77f065d7, 0x9a07e8ad, + 0xcfe869bb, 0x60b37516, 0x6cddc7fd, 0x28f1ff58, 0x4a0e35cf, 0x07c39fd7, + 0x58fdeed4, 0x48ef5cf3, 0x25297f60, 0x4a07244d, 0x8d0c898f, 0x52ad5f6f, + 0x527ca3be, 0xef72fddc, 0x9af4b4a3, 0xd1a77a5a, 0xa2a6eff2, 0x3f17c0a5, + 0x97e84c95, 0x09526559, 0x1335647c, 0x57d5cbe4, 0x1fde7e0f, 0xe70fdfc3, + 0xfd14be31, 0xe656ac3e, 0xeffe1d80, 0x83f3bf65, 0x4f287e1d, 0x93ec3b43, + 0xf7f6177e, 0xfde7dfa2, 0x49fc0738, 0xd4fd468b, 0x3a35f1d8, 0x7f1c3f7e, + 0xa6bf8c25, 0xbd2df18d, 0x4fc6ea87, 0x375f31ea, 0xc746927e, 0xe8f21077, + 0xf1f3dfb2, 0x50bafe29, 0x3dfa50bf, 0x71e96f8e, 0x5abf8e3f, 0xe375f323, + 0x7fc64727, 0x69fde412, 0x82507f18, 0xae1ef7f9, 0x728f7f9f, 0x3635fcfd, + 0xbd9667ff, 0xc64fc7cd, 0xbd2b3ff9, 0xe3dfe6cd, 0x66fe6ca7, 0xf8ec6fda, + 0x37fe08f6, 0xb72ff8c2, 0x9ae5be31, 0xf7f9fa91, 0xbf9fa45c, 0xeaff8d99, + 0xf8f8f7b2, 0xab7f1c36, 0x7f9b1ef4, 0x7c7007cf, 0xe5d2b9b3, 0xeee64da0, + 0xd00195c9, 0x263dd413, 0x746020d9, 0x2820219c, 0xefd084e9, 0x903d4817, + 0xa64e3f0e, 0xffdf477c, 0x1bf29922, 0x6fdcf7f8, 0x12558127, 0x1dd74c19, + 0x5767a79c, 0x417ed4cf, 0xcb5d993f, 0xae8433d6, 0xf0a6ae77, 0xff9ed535, + 0xef0a43e2, 0x50038dec, 0x274e514f, 0x3e1cddf0, 0xf0ccaf15, 0xb7594841, + 0x12bf5489, 0xa4dbaca5, 0x06e4d8fe, 0x411e7fbf, 0x78f8e318, 0xa27a954e, + 0xe6fe4631, 0x17d7d5ad, 0x0175f404, 0x09301177, 0xa4c5fd2d, 0xf71d254f, + 0x10275d18, 0x447f97ea, 0x594270fd, 0xdc9513f6, 0xf2f1465d, 0x404f5d31, + 0x27ae91bd, 0x4cae9da0, 0x14c72e91, 0xb63bf382, 0x7a001ada, 0x0193f17c, + 0xbb87d81a, 0x1bf2a7ef, 0x727edf2b, 0x5fc28738, 0xd339e7c6, 0x076fa19f, + 0x4c3c53bc, 0x0b2bf3e4, 0x974f1e2d, 0xd59ee4c4, 0x459954b9, 0xf24a6bdf, + 0x54ffd0a8, 0xe9b356e2, 0x9d2e7778, 0x5f107aa8, 0xca135cee, 0x5135c939, + 0x56e89f39, 0xf4c6358f, 0x8066a93f, 0x93227b4a, 0xdf9feac7, 0x37afa656, + 0x44d56ea9, 0x5134d3e9, 0xdda81b22, 0xdf4d3a99, 0x2339c62e, 0xc5fce3a5, + 0x6e746578, 0x9e61d39d, 0xeffa63f4, 0x3cd83a1f, 0x34bc3ae8, 0x3f73d617, + 0x689b5c90, 0x57bc2a7d, 0xa83d7400, 0xb769f3c1, 0x90d6b9a4, 0x92897878, + 0xe11cfd83, 0xca23bceb, 0xcd0c5fa6, 0x83ff878b, 0x29b756dd, 0x461e7e3f, + 0xa093a7b8, 0xba76f60a, 0xc67cff47, 0x18fce37c, 0x74e09c5f, 0x407c063e, + 0x07c093cb, 0x39c7cf14, 0x2bf5441f, 0xc01383e3, 0x4eb09907, 0xa7307c66, + 0x6ffd312a, 0x479ff4e7, 0x29676afc, 0x9ca9f74a, 0xba73b7ee, 0xe7ab5bcf, + 0x3cf9b88f, 0x1cc1e1b9, 0x3cf98267, 0xa62547b2, 0x657979f8, 0x2ff91f06, + 0x8e89b029, 0xbea5677b, 0xfd0376fd, 0x777e9c3c, 0x7165e846, 0xbf3e5197, + 0x011927eb, 0x7c7133d0, 0x31f5e9c1, 0xb5b4d7a7, 0x4cefed8f, 0xe46be1e2, + 0xf6b13af4, 0xfb44d579, 0x112f9c6b, 0xf08c6ff0, 0x9bbbe11a, 0xdfa03438, + 0x9febf7dd, 0xa627f4cf, 0x28b6b79f, 0xf3cc78e3, 0x1971c1c5, 0x68e463c7, + 0xba89e6e1, 0x74c082fa, 0xd6f3fbdd, 0xcfb5d4ce, 0x6ba05aa9, 0xbdf567bf, + 0xff4cfaba, 0xdfef744f, 0x5d32ff7d, 0x0f959dfb, 0xcc67daeb, 0x9f574c7f, + 0xf74a79ee, 0x1b69d4fe, 0x95b7ed74, 0x9f6ba4bd, 0xae9b763c, 0xa75dd13e, + 0xbdda5f7b, 0x9fc43ba0, 0xd9e79abc, 0xbd9b886c, 0x49cf266f, 0xe84c7af1, + 0x273ee3bb, 0xebe13f3e, 0x9f29e583, 0xf19f9f0b, 0x1972c50d, 0x176a71e8, + 0xf4ac754c, 0x3bb33e3e, 0x07217fe8, 0x6eaea89f, 0x7a8d3fa0, 0xc4e7a8cf, + 0x46bd46fb, 0xa7e0b97f, 0x59cf15b4, 0xb0329124, 0xf312cd0b, 0x43f3c457, + 0xb2123edc, 0x1a45cb1c, 0xaf45d393, 0x39062e75, 0x7b85a45a, 0xeedada57, + 0x9c250497, 0x9eaa9ccf, 0xade7383a, 0xef806bed, 0x05abe439, 0xf3dd4281, + 0xe8479b85, 0x47bb3bbe, 0x402af846, 0xff8187b6, 0x04deb65d, 0xb7bc31f6, + 0x00fee4db, 0x1319fbaf, 0x09db5bc0, 0xdf59eaed, 0x0ae38cd8, 0xcb0cb9e0, + 0x5869be53, 0xb079f09e, 0x8f9bee3c, 0x255f31e5, 0xfbbe8d96, 0xe7d8fcb1, + 0xdf23f2c7, 0xf03f2c6a, 0xc4796155, 0x77cb16b7, 0x0f2c017d, 0xf96336fb, + 0x65882f8e, 0xcb16af83, 0x4b1b9f26, 0xfc312f21, 0x0c73bdd2, 0x277d08bf, + 0xce29e1f4, 0x5f80672f, 0x73c5f112, 0xa938be7a, 0x185f2256, 0x0e91a1f5, + 0x6df77d46, 0xf4dd21f9, 0x9443f0fd, 0x7a06b9de, 0xde8f6cf7, 0x397d221f, + 0x0e4dd3bd, 0xf7a70f06, 0x45780623, 0x041281a9, 0x7e6665bd, 0x595b711e, + 0xabc453dc, 0x7b8b3249, 0x337578f2, 0xbc0377fd, 0x10fb04a7, 0xbf6b5fda, + 0xe21bdbff, 0xcc47adcc, 0x3db5e484, 0xdafd233f, 0x9bf103c4, 0xc9ff0ebe, + 0x14af0cc9, 0xda84b1aa, 0xbed73587, 0xeac59aee, 0x423b010a, 0xb8d8ae82, + 0xc05fa46f, 0x78fb7665, 0x7f31374d, 0x6657bad3, 0x776f08f8, 0xf2894e4d, + 0xd2dcd7ab, 0x95f833bb, 0xd8099a1f, 0xe9b01233, 0xf5a7e5f1, 0xb57c51c1, + 0xf4f68f35, 0xfc2fffde, 0xda8fa7b4, 0xa48743d3, 0x735fc7af, 0x24f75d31, + 0x008e2f58, 0x6df41c3e, 0x1ba1b0f8, 0xf81061f0, 0x5adff69d, 0xe92a4d73, + 0x66e7ed17, 0x13af9393, 0xde4e9ebe, 0xd37e0854, 0x1334537e, 0xcbae9eb9, + 0xf24dcf65, 0x5dcff020, 0x6f4a7e8d, 0x6bab6eff, 0x49d61385, 0x7612fe67, + 0x75fa17c2, 0xe7c1eb73, 0x59aeb0ed, 0x1c726392, 0x3e9b6c2f, 0x0e79838b, + 0x547fac5b, 0x56b7afab, 0xdc596349, 0xa53a99c4, 0x8769e83f, 0xd02f78e3, + 0x8a58399b, 0x68e4967e, 0xf019e38e, 0x79c9805e, 0x81ea1a75, 0xbe0b3e33, + 0xd1c37df7, 0x38513f56, 0xf427c86a, 0x2b89107b, 0xbf7edb3d, 0x2e56be4d, + 0x228f1068, 0x580bf521, 0xffd1252f, 0x7e80f4af, 0x7e8bac15, 0x6fd941bd, + 0x579e1ebe, 0xdfa3c6eb, 0x1b1ec539, 0xfcb6d77c, 0xe084e428, 0x3f374a5f, + 0x2fb8a7f8, 0xfbd0e494, 0xbaba696d, 0x43b3b6b7, 0x3fc1c7e7, 0x2d1cd1c0, + 0x8b47c029, 0x2b355b38, 0x8512d5b6, 0x322c066f, 0xf6259f81, 0xa34b62de, + 0x968fa1e6, 0x7f4148ec, 0x7c63c978, 0x1a4fcd9f, 0x4359fbe0, 0x29970779, + 0x51fd3154, 0xb44c470b, 0x89af0f7e, 0x3559aefd, 0xff5fd10b, 0xdd71f894, + 0x1aae5a77, 0x796a7e0c, 0xa6e68370, 0x989cfb74, 0xffbe82c6, 0x2f63bc9c, + 0x57b7918c, 0x7be70d64, 0xffbd6acf, 0xbab1d74a, 0xeac75d3a, 0xa4c973ea, + 0x9a17d82c, 0x974aa4fb, 0xd5aeb8d4, 0x7656ffb5, 0x91e77ce0, 0x876055ca, + 0xbc29a93f, 0x71e0047d, 0xb0c1fae7, 0x9b459c4e, 0x29fea973, 0x03487cdf, + 0xe3a6f939, 0x0bef802f, 0xf315c7e2, 0xe407db8a, 0x59bc5878, 0xd8120772, + 0xf76e5abd, 0x3bfa5e84, 0x1eb31fc0, 0x23e7cd3f, 0x3f9adfea, 0x65c32932, + 0x4339e945, 0xc1921cf6, 0xa49f008e, 0x5be2f946, 0xd7139ff7, 0xd7bfdfff, + 0x1d12bbfe, 0x4ffed37f, 0xdefc5e83, 0x0715effa, 0xf044c5ff, 0xb22c3a0b, + 0x17c01c34, 0xbe096e1d, 0x14dcb853, 0x7c60714d, 0x725ab9aa, 0xc4fbe999, + 0x2c8e9c4d, 0x3d601fa6, 0x6a5afcd9, 0xe1bd413e, 0x1f3a6e20, 0x552e7f2b, + 0xd123d9ef, 0x3b4ae175, 0xfe51a771, 0x9953e954, 0x692ad1ca, 0xe5a24580, + 0x7f739ae2, 0x9bf68379, 0x88099214, 0xa1853374, 0xdd97f701, 0xac776069, + 0x03b411e4, 0x257ec7b0, 0xd1a70a23, 0x0578103e, 0x8d8397ec, 0x61b6463b, + 0x9d75a6fc, 0x9955718c, 0x919bf75c, 0x0f782f54, 0xeda2f952, 0xb405f0ad, + 0x5d7095af, 0x04b07adf, 0x24eaf3eb, 0x6beb4192, 0x60f9ec93, 0x26dcd2af, + 0x63373c5d, 0x4e7e3eac, 0x5806eefc, 0xf3e6cfff, 0x1c00c405, 0x53bd790b, + 0x7de1ba59, 0x5c4c5ffa, 0xee67b66c, 0x93f14278, 0x771f4d3d, 0x723f285f, + 0xed3ae200, 0x06ed6dca, 0x9463900d, 0xf59b85db, 0x21b78175, 0x09e64a4a, + 0x6236c9b0, 0xadb5bc03, 0x67c1dbc7, 0x8cdfef63, 0x7c71d81c, 0xce64f11a, + 0xc935e3d1, 0xb5abc7a9, 0x066f018f, 0xf4b8a6bc, 0x3a66a2f8, 0xa9af0890, + 0xfae87b43, 0x7af1bef9, 0x6fb3e017, 0x57f49f14, 0xa262c966, 0x56767007, + 0x46ffc8c2, 0x85b5c979, 0x55f7f825, 0xf8658199, 0xf5052b95, 0x5f870e40, + 0xb3becd9a, 0x60c8bc82, 0x2f285d55, 0x3b046910, 0x391f256e, 0xf2268e80, + 0xb7d2b909, 0x37de3a6d, 0x59d1df71, 0xc075abf4, 0x1f23d7cf, 0xe9fc5d20, + 0x0f22b024, 0x00e5d1e4, 0x59f416bb, 0xbae9b39c, 0x711f55f1, 0xcdfea6ce, + 0x96073e6b, 0xf7b0168f, 0x0091fb9b, 0xe1831bac, 0x884e590b, 0xeba1cf67, + 0x1fffaa34, 0x80265ad5, 0x9517fc3f, 0x55eecfad, 0xab772c35, 0x47ffae26, + 0x79f201ff, 0x00ffa99a, 0xd0e6a5f1, 0x50d5cb26, 0xbf3195af, 0x75569bc0, + 0x14df8c2d, 0xb35c1952, 0xf64f182d, 0xc768abd6, 0xc48f669b, 0x9f311a7c, + 0x163c90a6, 0xa1cdd9e2, 0xc4f7ec4f, 0xdaa69dd8, 0xbb05ae27, 0xb12994f7, + 0x628cfbff, 0xc87e6efa, 0xfa3d38ba, 0xf509d28c, 0xe83da3e7, 0xb6262a3c, + 0x9becbf22, 0x77ce337b, 0x9a724847, 0xf2a5dc29, 0x0fe83f1d, 0x537f86fb, + 0xee24de98, 0x58b333f1, 0x5f563ce8, 0xabd4888c, 0x7ec32afe, 0xc3c45d25, + 0xcac0e2be, 0x8c87e8b9, 0x0292490e, 0xc108ebfa, 0x0fc8467e, 0x7f32c094, + 0xe3a28350, 0x0921c1c7, 0x91b836f1, 0x90d37e60, 0x61f6fa23, 0xae218a8d, + 0x9f819016, 0x3fd29c46, 0x6d7c13af, 0xd7c05927, 0x25965e4f, 0x5b9a4ff0, + 0x1d396b88, 0x977679bf, 0xf9a78022, 0xd046ec02, 0x363cb2f2, 0x8ff7fad1, + 0x9e87f30a, 0xc6fed8d2, 0x816d7353, 0x6fbe9465, 0xb8c72dce, 0xf13f17c4, + 0xbfb44f74, 0x5287a315, 0xdc83684d, 0x75cfb0a9, 0x1295c4df, 0xd552031a, + 0xfe252cb9, 0x82bfc17d, 0x771f059f, 0x09ec9b9e, 0xb2671824, 0xe294fcca, + 0x8d247db9, 0x5bb4d7c2, 0x4da57422, 0x747b969a, 0xe9630ef1, 0x0173cb27, + 0x79ed6f1e, 0x2594ec0d, 0xfa0fd894, 0x3ca3b14c, 0x2ff72d34, 0x1fb5bc83, + 0x3bf46153, 0x27dfaebf, 0x48723e31, 0x2cefb271, 0x9e813355, 0xe42c732d, + 0xd6379639, 0xf00a5279, 0x55b8c97b, 0xcba7de14, 0x9f37684c, 0xbf085d52, + 0x7961317f, 0xa2ff7c71, 0x61b204eb, 0x5cfc8c4d, 0x95248a54, 0x0ea92bf6, + 0xe3c33fec, 0xd77e0092, 0x8769ffbf, 0x4be690fd, 0x1763a466, 0xdf10f71e, + 0xfad95575, 0xfeea8371, 0xd0f58152, 0x0b944cfc, 0x9ceec797, 0xf5f2ed4d, + 0x09ef14b5, 0xffe146fc, 0x98e87ba5, 0x9b749e14, 0xb892f909, 0xd5074edd, + 0x7e225e77, 0x8883947e, 0xa225845c, 0x51ea8e0c, 0x53852429, 0x681c3ea8, + 0x5a6585b1, 0xf3a7cfa6, 0x6231fd86, 0x2835fd61, 0x40fb2367, 0x7ca1aeb8, + 0x4d821839, 0xaef587f4, 0xafd0bfd8, 0x84af2f42, 0x67ed36b8, 0x604a63e5, + 0x9d67ed05, 0x357498d2, 0xcedcf32d, 0xba412062, 0x5003f4e2, 0x2e27cd57, + 0xf6b1210a, 0xf1169f5c, 0x0ed0a847, 0x78c64af8, 0xd38e9180, 0xf4f2f822, + 0xf3fce952, 0x09bcb60f, 0x892b8b6e, 0x6fdae78d, 0xca593b41, 0x4fb0eaed, + 0x17d0014d, 0xee237c24, 0x112d799b, 0x17d3a0fd, 0xc4686ec3, 0xef61ae7c, + 0x54a87833, 0x41fde1b9, 0x7d723c11, 0xa136fdc2, 0x8284863f, 0x2eaeb085, + 0xb5ee1508, 0x3e0bf1d1, 0xa71b7262, 0x15d20e3f, 0xaf6f8f5b, 0x307c8c37, + 0x90e54c20, 0x1d1fa5d3, 0x23a0f0bf, 0x52f68752, 0x7019ea95, 0xc99eb916, + 0x1b30389c, 0x7f38bdf7, 0xe42af119, 0x05e728d9, 0x9af6bbf7, 0x0c885c19, + 0x8a4438e3, 0x09ece1c2, 0x392de87a, 0x1157f415, 0xeb8503c5, 0x696f2e73, + 0x60e30217, 0x6e864ffe, 0x65df224a, 0x7e99b25d, 0xc62f631d, 0x20d99ec9, + 0xd85ed477, 0x7b150f01, 0x8f4c682e, 0x11de9185, 0x0172a7be, 0x10b909df, + 0x6fe46efc, 0xe82b0f21, 0x189ea657, 0x4760249f, 0xce082965, 0xeb61d52e, + 0xe157801c, 0x1a7f1337, 0x3a9663c6, 0x78eb38d8, 0x24d2ca5e, 0xd7fa7677, + 0x25ef5fe8, 0xc4c40913, 0x8b4abc39, 0x7bd17a06, 0x8c812349, 0x8d9f80ef, + 0xad59f871, 0xcfc78a76, 0xebf3c86c, 0xfe02bff4, 0x87fe1180, 0x5ff8519c, + 0x421456b7, 0xe70efe9d, 0xef9bd2c4, 0x15f90a13, 0xb6b43af2, 0x9cb52f72, + 0x2719f271, 0x0c80a197, 0x4f978a78, 0xccf41932, 0x23f33088, 0x817a728c, + 0xf6f9a3cf, 0xefc0de96, 0x0ea7b2f9, 0xf7def7e0, 0x2fe83745, 0xc63249df, + 0x6bf32053, 0x2bd81765, 0xb3a190d2, 0xda76f107, 0xf5c4e8cf, 0x9f9f057a, + 0xd4f94b54, 0x9e05fb0e, 0x0affd07d, 0x41ff5b07, 0xc7f41e40, 0x7bf3c545, + 0x852b0b90, 0xa7e2192d, 0x1879c27d, 0x45c832a7, 0x3560725b, 0xce9079f0, + 0x9f8cec17, 0xa5ab99da, 0x5879e1b6, 0x52f0634d, 0xa23f07e9, 0x06c260eb, + 0x8fb820ab, 0xe59f35da, 0x602d74af, 0x729fd6f9, 0x50c27e7d, 0x3eca545e, + 0x0aa97986, 0xbe0b9bf1, 0x2a00dc3d, 0xaa4e5fc4, 0x1f008fee, 0x9c6eb196, + 0xb883ae47, 0x72276a24, 0xa2e4a095, 0x722fa470, 0x9fc6bda2, 0xbfb49fb0, + 0x22cef1dc, 0xd52e77a0, 0xcaf71089, 0x91247f05, 0xc22aa85c, 0x3ef9adfd, + 0x5f07e710, 0x407f7ce1, 0x18cdf3a3, 0xbcb1a2df, 0xd4ce2a85, 0xdbf0092e, + 0x4e3b7294, 0xc4a2e9b6, 0x8634fcfc, 0x08bae367, 0x52f30608, 0x8d41fd78, + 0xb8e94928, 0xbec3f16e, 0xc164dfb2, 0xb8958b75, 0xbae7a082, 0xbe1e2c68, + 0x86ad724a, 0x16952ffa, 0x78f9e40b, 0xfefd6cad, 0x2e49c8e8, 0xbf62be85, + 0xd61f35a1, 0x3bcf949e, 0xa6fdf469, 0x57bdad91, 0xba5a0ce2, 0xcb737e31, + 0x27c12f30, 0xb56e8215, 0x496e8eaa, 0xa1888f10, 0xad148adb, 0x4dc5f80f, + 0xd60bb252, 0x240b4d29, 0xe164a706, 0xff9053f3, 0x1e127122, 0xf2d42857, + 0x6f423f10, 0x86acf9d3, 0xfb0dc052, 0xf92fd0fa, 0x89b0359d, 0x8f1bfabe, + 0x81c433a5, 0xed8e67b3, 0xaf67710c, 0x491ba5bd, 0xf3a60710, 0xcbf3001b, + 0x40d32b56, 0x79df65cf, 0x30f40edc, 0xd7f62dc2, 0x4bfb07f0, 0x586c656f, + 0x7125fe83, 0xe7cf7ab3, 0x05094eb0, 0x60e39978, 0x2a49cff0, 0xb7d58acb, + 0x132cfa4f, 0xef5a2515, 0xec4bc914, 0xffe7cba3, 0x89daefb5, 0xbd7be9a3, + 0x59372635, 0x9fe3f5a4, 0xd6e671d1, 0x3f105d58, 0x8cf65478, 0x773fb803, + 0x70975f3b, 0x01295d1d, 0x959f8b1c, 0xf079d3c8, 0x43fb611d, 0x1f943f1c, + 0xd98ecf3a, 0x2ef3a037, 0xd3c506d3, 0xb52559b5, 0x7212e710, 0x2ca7c999, + 0x4ba082f4, 0xea9bd026, 0xe5465205, 0x8dce2634, 0xdc6166af, 0xe8527f0a, + 0xbf02fff7, 0x31437ed1, 0x1ba09dca, 0x48f4c3e9, 0x4c75c812, 0xfeb9aabc, + 0x14fcabbd, 0x9fffbf8e, 0xb68429f3, 0x496943ff, 0xf53e3901, 0xdc535fc0, + 0x00f60f90, 0x977acf5b, 0xeebce2a4, 0x8ff77ee2, 0xb46a9e38, 0xd79872b2, + 0x637fbedd, 0x6fa2379c, 0x8efb67ef, 0x8ffaa80b, 0x4b6a2fdd, 0x1479c32f, + 0xfd7793a2, 0x8562ecbe, 0x7e30eb9d, 0xeb6349bf, 0x1bd505e6, 0xc0275cb4, + 0x806ff9e3, 0x5f5f14e7, 0xf161aa9c, 0xacdf011e, 0xf81a01ea, 0x9908ffdc, + 0x1fed9849, 0xb95f4ca9, 0xb7c5126d, 0x08d1e387, 0x179e01f7, 0x3257e739, + 0xe933c1fa, 0xb953f758, 0x601684f7, 0xff08c71c, 0x52bcba9c, 0xf3987fc8, + 0x29eb84b0, 0xaa01ff78, 0x3ff73d3f, 0x68e80e74, 0x9f319f9c, 0x171f18c4, + 0x43c8b37e, 0x983c4d9b, 0x27171297, 0xfb1cfd0a, 0x9e8bc637, 0x797af8d5, + 0xfb021930, 0xbef96725, 0x621b9c3a, 0xcb04ebfb, 0x14925072, 0x1e968b9f, + 0xb926052a, 0xc61b72a3, 0x33f8c5eb, 0xf833f8f8, 0xaae15438, 0xe633c7c0, + 0xf36217ab, 0xdc68b6dc, 0xc7421e6f, 0x89e3a393, 0x39731671, 0x7a0be314, + 0xe72abe0a, 0x7f515d74, 0xd3235bb2, 0x0c498703, 0x9ff88c7d, 0xca2b3bf7, + 0xa1cf0447, 0xfd039c5f, 0x51736738, 0xec271769, 0xc28e545f, 0xcfe269fc, + 0xe16af961, 0x1bb7581c, 0x36a4def1, 0xd8257376, 0xfee2689f, 0xb9717b5c, + 0x03c89a1d, 0x94f2c2a8, 0x67e07552, 0x191b87c0, 0xb9de2c1f, 0xb79075e5, + 0xb2bfadf2, 0x569dbc83, 0xbc60b2aa, 0xb41e9b45, 0x29c57ec3, 0xbd076fc5, + 0xe4c03a78, 0x8aefc8ce, 0x305bec59, 0xe0f6157e, 0x9f3fcbcc, 0xc5f9fc00, + 0x7a01d526, 0x1cd9bbde, 0x547c5336, 0xd0fc30d4, 0x7f5651fa, 0xade2f108, + 0xfe5dc3d5, 0x9cb2afe2, 0xe7969f6c, 0x9d7185f3, 0xd3f1b15f, 0x2f0f9052, + 0x1d7dc169, 0xfe3077e3, 0x97dc74a5, 0xc6a5a99b, 0x11be0bb7, 0x8d6f05eb, + 0x3c469be0, 0x7f7c665f, 0x172fd73e, 0xfe72bf05, 0x0120f811, 0x9de457a6, + 0xd28ff3eb, 0x7f8dd9fa, 0x62fd4bb2, 0xbfcb09f5, 0xf3de0d68, 0xdb672eec, + 0xe71360fe, 0x0177e8c3, 0xcb59cefc, 0xac4230f3, 0xed86a45c, 0xb4591710, + 0xecf5c541, 0xbfcf2da2, 0xbdd834f0, 0xabaecdf7, 0xb70bff69, 0x38777fec, + 0xa6dc2fad, 0xd3678e66, 0x763149b0, 0x5a7c0bda, 0xf943a510, 0xb39afdf6, + 0x40fe7b3f, 0x0b1e947a, 0x48d1edb7, 0x947c78ff, 0x8c68f704, 0x09740dff, + 0x7d852d1e, 0xbfe7796e, 0xe9fba035, 0xbc8112dd, 0x6e7c38cc, 0xd2fb8fd8, + 0x23a42780, 0x6e8453a7, 0x94bdf786, 0x39e7682e, 0xefed8c9d, 0x3fe40e69, + 0x5dce0fe8, 0x757e7e51, 0xfccfc517, 0x982ecc0f, 0xef57fcff, 0x4e3cc3b3, + 0xaf8c952a, 0x05983fd7, 0xeabe6476, 0xc96072cf, 0xe67fcf9e, 0xf36fc847, + 0x8b28fd0e, 0x99d2fd30, 0x9dfcd1c5, 0xd6737e61, 0x9bf386dd, 0x77c83c4b, + 0x65cbd7f3, 0xa8babf10, 0x12dbb190, 0xb94fc5c8, 0xce7c9c5c, 0x27f8fb8c, + 0xb8531ec1, 0xccc8effc, 0xa2f721cf, 0x9f11fd7d, 0x58fcb50b, 0x18e3c8bf, + 0x1e22cd13, 0x2c72b54c, 0xa87c6ebf, 0xe673e801, 0xc436772a, 0xf144bd01, + 0x57487c73, 0xa1f2bf68, 0x3f5cd931, 0x7f189539, 0xc39e04b7, 0x3baa0dfb, + 0x1df75f29, 0x1d1792b9, 0x9f1f297f, 0xfb0c9dc2, 0x12b327c6, 0x305f87c7, + 0xd611624b, 0xa303f3a0, 0x7de4cdf2, 0xbe4cc3e3, 0x2607bc85, 0x0bf6858e, + 0xc0fc9987, 0x53c7e077, 0xd8d9c2b8, 0x848a67be, 0xc3da80fa, 0x51bd7244, + 0x6fad72e5, 0xe1427c17, 0x897fc056, 0xfb610bf0, 0x7e7927bc, 0xe927dcfb, + 0xc1763177, 0xe3d9e30b, 0x3b7213fb, 0x6617f84f, 0x7593fcbd, 0x5bc6129d, + 0x22c47e8c, 0xd3c2f035, 0x3e54af20, 0xda2edf41, 0xbcc196a2, 0xfbdeab3f, + 0x9ca90fee, 0x7214167c, 0x469fd7aa, 0xdaff9d39, 0xa34fe47e, 0xdc167e9c, + 0x4e50959f, 0x73c7edb7, 0xfa72f1b7, 0x053fab3f, 0xf01bd6fe, 0x5b61f427, + 0xc3ea3478, 0x4fc410e1, 0xb7090fa0, 0x13fe46c3, 0xadf8277c, 0xddc595fc, + 0xf844ef41, 0x845df052, 0xc5df052f, 0xf0ead1e5, 0x083f3717, 0x589f01a2, + 0x75828ed6, 0xf6c5c586, 0xcb39ae13, 0x819693e2, 0x67d6fd6c, 0x43f582ad, + 0xb020c726, 0xec4613fb, 0xa427ecfc, 0xbef9fe6d, 0x963e9dcb, 0x65075fa3, + 0x895f042f, 0x1090e3a5, 0x16fbd383, 0x7d40f409, 0xf76396e0, 0x930b640b, + 0xbd1f9df7, 0x2c780856, 0xca97ee6a, 0xae1babf8, 0xb5fc445b, 0x054cefd5, + 0xea1ada7d, 0xad4f7989, 0x4494e507, 0xe25fa5e7, 0xfb857df4, 0x491bcd5b, + 0xadf94c95, 0xdfa0b499, 0xc168dfe0, 0xbe38b67c, 0xe67f3330, 0xe803e2bb, + 0x2978f80f, 0x5134b1a9, 0xf9f09a3c, 0x5ff3784e, 0x0baf1f68, 0xbf81306d, + 0x9346dd7e, 0x24be4fce, 0x1480baf8, 0x784f5f00, 0x20652933, 0x2ecaf3ee, + 0x0dee5738, 0x093cd39d, 0xf38c95f2, 0xdfc1fe87, 0xe0716fea, 0xc1a86fb8, + 0xdbdcf07b, 0xeb0216e7, 0x6aad3a85, 0x3b382261, 0xeb383125, 0x7cba338e, + 0x6a29785f, 0x618b85b6, 0x61237a7f, 0x3a38f671, 0xde0eb613, 0xaa7f704c, + 0x7ab32435, 0xa347db35, 0x2462fca0, 0xf699777c, 0xd79f231a, 0x057b6ed4, + 0x8455e7ce, 0xb6898724, 0x1a8d2857, 0x36b78bf0, 0x363d064d, 0xcbce29c0, + 0x894ffa3b, 0x16febfe1, 0x77b9e705, 0x00331bf8, 0x6acfe72f, 0xddd5f604, + 0x60ec5afb, 0x0a87ceef, 0x9adadf91, 0x191f76d7, 0xfee9eb05, 0x78a77f00, + 0x4eabf63a, 0x9447d5d6, 0x5c00ba78, 0x4b8dcc13, 0xfef0095d, 0xf7d9858a, + 0xdb3e4bef, 0xbf2c3b2b, 0x7afc8587, 0x7c41bf70, 0x378700ff, 0x13b37e46, + 0x6592efc9, 0xf7986cce, 0xd99efa92, 0x7f25cf80, 0xe2253b50, 0x963e2dab, + 0xee15b4df, 0xadf90017, 0x7d7bf2a1, 0x50d6fc8c, 0xff8bcdf9, 0xfbe5ae6e, + 0x202ddf95, 0xfbe009bf, 0x90af9f09, 0x51d0fcdf, 0x1afcdf94, 0x4acef9fd, + 0x2bf27b4b, 0xf2c29a75, 0x04d65c60, 0x00f01afa, 0x795bb2f9, 0x038c387e, + 0x37c2fc72, 0x24bce394, 0x4a7fef06, 0x20ec978e, 0x4f128798, 0x4bc7266f, + 0x4b1ca8ea, 0xc7267740, 0xcb09ea4b, 0x6fc83407, 0x65f9389f, 0xd98457df, + 0xbcdadef7, 0xc741dcdf, 0x2eab702b, 0x20bf7d0b, 0x6283cf2a, 0xb685f9e5, + 0xc760f9e4, 0x970779e4, 0x3da72a67, 0xeae8095c, 0x63f3e90a, 0xb27618de, + 0xe5f03b7a, 0x275c659f, 0x0f79e21d, 0x7276197f, 0x3fc5f020, 0xff8a1e00, + 0x9a6f9c3d, 0xbfec7e7c, 0xe853f874, 0xabec9547, 0x03ec35fa, 0x12a8de2e, + 0x351587d0, 0x328fd147, 0x5f85bfae, 0x0b875c65, 0x7e5ed23d, 0x776e61cc, + 0x088dca26, 0xc65b792f, 0xf38c3ffb, 0xc1c5ef17, 0x5deab079, 0xc042afb8, + 0x407c5ed9, 0xb83da3cc, 0x15debcc4, 0x148032f2, 0xe286dc42, 0xffc5e511, + 0xb5cf1947, 0xad5d1595, 0x23e51fbb, 0xaac2cf8e, 0x870812a2, 0x37e7e44f, + 0xf7bdaee7, 0x18af9c00, 0x0059c474, 0xe188f4ee, 0xa7ac0f66, 0x416a4a5e, + 0x49741679, 0xb974624d, 0xa379fbc4, 0xf031654b, 0x7256b79b, 0x86f1dd80, + 0xc1f785ff, 0x8bea7dec, 0x05a3e052, 0x8cc392f5, 0x834e787c, 0xb5295e75, + 0x854fc0bf, 0x7eb873a1, 0x245f505b, 0xea0bf7c3, 0xa3c0bc24, 0x9474fc3d, + 0x0edc296e, 0x6df8016f, 0xb30b6700, 0xd13e1c6b, 0x3afc55ee, 0xbe9e4bf8, + 0xc1972ab4, 0x571704ed, 0x02283bc0, 0xe7194cef, 0x057841d5, 0x3783dbde, + 0xc74f4935, 0x679e47b7, 0xb4a110fb, 0xbe6bad0e, 0x97887ee9, 0x4cfae034, + 0x90cc8bec, 0xac0b663d, 0xf3e97b6f, 0xc1690995, 0xa1efebbc, 0xf5d7ff7f, + 0x0037d91f, 0xece41dff, 0xcbae2a4f, 0xb338a497, 0x1df1dce1, 0xb75d2af0, + 0xfb336d34, 0xff313de1, 0xabb73e13, 0xc3710297, 0xf19e58b1, 0xf57ab995, + 0x4f6fb18a, 0xbe43b79d, 0x821f7357, 0x294d2179, 0xda274e2c, 0x0b3249dd, + 0x587e73fa, 0xf57c34a4, 0x1b49f821, 0x5c03061b, 0xbcf32e27, 0xb1e6cb92, + 0xd3ddd689, 0xe7109db9, 0x3802ef28, 0x2fb2249d, 0xe59f377a, 0x927e705d, + 0xad6667ae, 0xf8852b4b, 0xa0bcf1b2, 0x83403827, 0xde31a438, 0x11b88738, + 0xd0f9718f, 0xbf1611e4, 0xeedff034, 0x273b0724, 0x706a54aa, 0x3ac4f65e, + 0x8829f889, 0x8f88db0b, 0xf1e24c6f, 0x1fc20ec8, 0x46b1ce77, 0x11b978c2, + 0x971b79ee, 0x6042eaad, 0xf15e6cbe, 0xb579b3f0, 0x78d20f35, 0x8bb58923, + 0xbcec420b, 0x3223c576, 0xaf3c83b3, 0xe02bc044, 0x2a5dc233, 0xa7ff422f, + 0xfa8cad79, 0x607f2ef7, 0xba479c15, 0xfb84a56b, 0x54f9c62e, 0x009cced4, + 0xdf43c0fa, 0xf3693887, 0x69ed0447, 0x00296af3, 0xd73f8c78, 0x4bfb66e9, + 0x427bbc7c, 0x7e7351f2, 0x1ea2f4db, 0x3665d20e, 0x849acba5, 0xd5c8a3fa, + 0x168e462b, 0x7ab9c604, 0xe20bc6e9, 0xe6e17eba, 0xbfe7ba89, 0x74f1e249, + 0x4f6fbf1e, 0x6265489e, 0x47e422bd, 0xaf9093c8, 0x817ce0dd, 0x0702519e, + 0x4f00f372, 0x1a7ea18f, 0x4c5e7b27, 0x8f217962, 0x54afa74e, 0xe79e753c, + 0x0cbc7085, 0x2399f465, 0x6de7c78f, 0x078a31e9, 0xb6c0fedd, 0xe27c7d24, + 0xcc47cebb, 0x9881c843, 0x8c0e519f, 0x21e91bdf, 0xba46c0e2, 0x6721e918, + 0x7e40fa9b, 0x5d939121, 0xb9cb77e0, 0xe8d7caa6, 0x5a7772b8, 0xcbf703f6, + 0x65a4cf25, 0x7928c955, 0xa8572d16, 0x30ad2f4c, 0x1898b8b1, 0x970e5dff, + 0xcb923328, 0x3ec1270e, 0x830ddbe3, 0x0c2f2cad, 0x5c7145f7, 0x9215a78a, + 0xe83f809b, 0xfed04fdf, 0xbd926417, 0x712b7f80, 0xd6fdc50f, 0x9e3e7124, + 0x5fd2e1e5, 0x582e942e, 0x35a70fc7, 0x83473fff, 0x8ab2ecbf, 0x4f5625fa, + 0x153de135, 0xab25ffc4, 0xb93af367, 0xa2b9eacc, 0xfc29d69d, 0x7bfceeae, + 0xef566ff2, 0xcdffda2b, 0xb45ebfde, 0x21dac57f, 0x7fb69481, 0xa357f0f5, + 0xae7f30fd, 0xbbb548c7, 0x62bbf02f, 0xe529eb62, 0xdcf30d4d, 0x15fe3e44, + 0x96ab97ce, 0x8562bf15, 0xb762a23c, 0x67c4f213, 0xdf3b73f0, 0x90f414b6, + 0xf7bc26ad, 0x9ba04a01, 0xc0e2cc96, 0xc6a49e82, 0xcbce17dd, 0x2fbba091, + 0x246635e4, 0xc192927b, 0x61ab7abf, 0xcd47c814, 0x060c1f3b, 0x0ee80bff, + 0x05be14fd, 0xfa50da77, 0x436abced, 0x46705e6c, 0x193d9172, 0x6cdd1af2, + 0x3a724adf, 0x14051dc8, 0xadf6b80e, 0xf4d68427, 0x8035b2fb, 0xfb0f6a3a, + 0xc1659527, 0x986ba478, 0x9cb8fbc5, 0x2e9ecbe4, 0xb8b9bcf0, 0xe061d1f1, + 0x7ed89997, 0xef48693b, 0xe5a13f90, 0x74798fdf, 0x47b5b9e9, 0x3e3ee166, + 0xdc90cfdb, 0x6e838c6e, 0x24179c8d, 0x25603f98, 0x6fdc2ec9, 0x7f1c9177, + 0x307fcf16, 0x1cccbe31, 0xccffb31c, 0x1fbf45e7, 0x870fe70d, 0x375e5958, + 0x710ca79d, 0x89c401b8, 0x33e42165, 0xf55604f4, 0x09177d60, 0xed19f91e, + 0x7624f1ff, 0x336585ef, 0x4c87e5d1, 0xd876664f, 0x21f9656f, 0x12706ac9, + 0x73e4ede8, 0xbb7a01c4, 0xe0a6bd79, 0xf1c50ef9, 0x3c5fcc03, 0xef002260, + 0x01c06a8b, 0xd72d7479, 0x48e7ce2a, 0x4e66bfb4, 0xe3efd17f, 0xc85af39a, + 0xcad078cb, 0xb1162fea, 0xd396833c, 0x5af2005a, 0x952d73d3, 0x93b3f9b1, + 0xf13f9992, 0x78f14a62, 0x3eb043a0, 0x43f8c099, 0xa2065376, 0xbaa579f4, + 0x63f80920, 0xe288e02b, 0xb8ecdd21, 0x3f4bfa17, 0xc3cde14f, 0xafc46ee7, + 0x4a901ce2, 0x66fc3bf1, 0x47ee139b, 0x7829317a, 0xcb41c833, 0x839e1316, + 0x26b9aade, 0xab6b7d42, 0x257901d3, 0x9305e62f, 0x4c5b3e71, 0xc9ad9f38, + 0xa12dd72d, 0xa3e9af70, 0x14f8058c, 0xe92c512b, 0xcec54f20, 0x99f3e97b, + 0xacaf4cc9, 0x7a793134, 0xf589d93c, 0x7e3a25c7, 0x8457bc01, 0x4fce24f2, + 0x75b0b734, 0x0d29a76b, 0xf275f032, 0x25de7144, 0x3c7f832c, 0xbda08cb2, + 0x0353691c, 0xb9538c4e, 0xfd29336d, 0x07661147, 0x08b47d46, 0x0528c3f3, + 0xfda08f0e, 0x04a9b5ed, 0x1e7845e6, 0x4f9c8de8, 0xb28d206e, 0x70dfb685, + 0x74c2b889, 0xe92f1bbc, 0x2ddcbff3, 0x8d14d18e, 0xb62488a4, 0x78f863c7, + 0x00adc4c5, 0xf45894ff, 0x7b018def, 0xe318e14c, 0x49339c30, 0x1bb476e6, + 0x2e7b16e9, 0x8dede447, 0x853dfb91, 0xcd58c0fe, 0x66d87805, 0xfb07bf73, + 0x9506fe7f, 0x46175a24, 0x6a3ed7d6, 0x61537a39, 0x798c94b9, 0x6d1f947b, + 0xadd707c0, 0xfdc3f2ad, 0x62f5d787, 0x81df03fd, 0x7d66b95e, 0x87d80666, + 0x511f4e02, 0x7e033e0a, 0x7e32a472, 0x951f5c72, 0x79c9f5c7, 0xbe429fc8, + 0x9fa0cf80, 0x46606a5d, 0xe50738a2, 0x9fc0f5cf, 0xfd046cdb, 0xb6779fdb, + 0x12b9034c, 0xfce31ce3, 0x2d572c6f, 0x8547b25b, 0x76645f79, 0x4b977466, + 0x3c8c635a, 0xc1852bfe, 0x4d5675eb, 0x1bf1009e, 0x2dfb8a9b, 0x162e3c59, + 0x639d1fcb, 0x59f043f8, 0x51e58d93, 0xa9297e08, 0xbbae2bfb, 0xe2122e4a, + 0x3f1123c8, 0x28cbf04f, 0x61f3187f, 0xd7e61147, 0xe8a5f919, 0x7d015382, + 0xb4bf1ed4, 0x089027c5, 0xc8d27605, 0xb992072f, 0xbf26d29f, 0x5e03b65c, + 0x6497d696, 0xa4fc5d7f, 0x5b47f396, 0x4cacc3ed, 0x5f9f19ef, 0xa8f66148, + 0x41faab4e, 0x5b85e83e, 0x7b902e4c, 0x70b90dca, 0x325d513f, 0x95288efb, + 0x4dbea13d, 0x5b667a61, 0x667a8cc8, 0xc1e3cd9b, 0x161cd07d, 0xa78a241f, + 0x5c9af211, 0x35ce2c5d, 0x0cfcfc31, 0x1aa0bfe7, 0xe212761e, 0x74607f0b, + 0x014b7a1f, 0x9d25189c, 0x1fb93367, 0x00db4a78, 0x6c3dcbf7, 0x7c0d3a2d, + 0x04b20c95, 0x35c74f79, 0x38ad77dc, 0xdbfea1ae, 0x2950fbb9, 0x9e0afdd8, + 0xd76431e7, 0xd062d2a1, 0x37a65627, 0x29fd71cf, 0x4e60c3ea, 0xf70d0fa0, + 0x4c230d15, 0x53ddc54f, 0x1f937c04, 0x77bb8f6d, 0x0635d1a8, 0xef771ac8, + 0x98f711d0, 0x7bdc2714, 0x797bc1e3, 0xe1efeee2, 0x67bc60fc, 0xc7927fa6, + 0xf83f0562, 0x36dd8695, 0xb3276be0, 0xb2ad41c7, 0xa92bcb2f, 0x23fc09ec, + 0x147f0ce4, 0xf7bfc15f, 0x7cf62e79, 0xbe7c2dc3, 0xb614b88f, 0x61a8dd3f, + 0x082fe81e, 0xedc82efb, 0x1e6b6f52, 0x5f4b0bd3, 0x5d7c019d, 0xf98ddf38, + 0xc8a58fb6, 0x2497fcf8, 0x7409e96c, 0xaf182972, 0x92ceaa0a, 0x3df45293, + 0x81f594a2, 0x4eaed4b8, 0xfe3085c9, 0xb5cf56c3, 0x5a513f00, 0x4377c20e, + 0x82141786, 0x580db65e, 0x4a760199, 0x1ae14dc0, 0x8516c9bb, 0x6595c043, + 0xb0f87c65, 0xd6b5e675, 0xd03bec4e, 0x4f47b53b, 0x417be058, 0x39fd60ff, + 0x3e18f746, 0xf947ba00, 0xea1bba40, 0xdc050f02, 0xbff2dede, 0x25c60f87, + 0x87e103e2, 0x76ecbf51, 0x1ff78fc0, 0x73b37b97, 0x6fcf2c1d, 0x24778c88, + 0x9b25f246, 0xb05d8a72, 0xf9d1597f, 0x3e525887, 0xa067ff3a, 0xff766ee7, + 0x04e7f0b0, 0x45cbe4df, 0x234bafd8, 0x2e83de78, 0xe21fb0d8, 0x823cc349, + 0x63060eed, 0x744fdff3, 0x59282ea3, 0x72674d60, 0x1bb5efc9, 0xefd09610, + 0xc715401c, 0x75d7e81d, 0xe2e8bd45, 0x242725f8, 0x03c5ce09, 0x05c95f2b, + 0x019c33ff, 0x8f300fe3, 0xed3ec30f, 0xb951d66b, 0xeb029f30, 0x8fc09ec8, + 0xfa59f7af, 0xaf693027, 0x7dbf9977, 0x4fea33a3, 0x97b8fd09, 0xbfc62b77, + 0xcbf4cadf, 0xcfb66e8d, 0x163d7a0e, 0x801f610e, 0x1487008c, 0x62ba6a9e, + 0x6a1dbd45, 0x11be78a4, 0xd8f4a0e0, 0xf01a9123, 0xee4c8a17, 0xfbf012cc, + 0x8015853a, 0x5ffeb9b3, 0x340e20dd, 0x23fbf43e, 0x9178ef00, 0xe7d2eb1f, + 0x6cfd1ac7, 0xf588ffe1, 0x148ff086, 0x47e1088a, 0x7874fb41, 0xe0e9f14e, + 0x0c8de0f7, 0xfefe305b, 0x5af3ab78, 0x85779737, 0x98bc63ce, 0x572be5c7, + 0x4cba5246, 0x5a3f3120, 0x0a4a05bf, 0x2483f8ff, 0x82f18c9c, 0xe7f80516, + 0x8e449716, 0xadd9f0c5, 0xf875f543, 0xf68aca8d, 0x46fbded7, 0x2242323b, + 0xff1f9b5f, 0x3e83cb4d, 0x47f62fb6, 0x18f7db1f, 0x2bf643de, 0xed0db0e0, + 0x1c3bf6cc, 0xb5070f0c, 0x73ed76c4, 0x4dc3ef2e, 0xef10f98d, 0x4bebb3dd, + 0xee6fa3b4, 0xf05df2fa, 0x569d871b, 0x8767c408, 0x8a981e9f, 0x39a1d271, + 0xf442be78, 0xc6b4fdeb, 0xe473d84a, 0xdfff711f, 0x5b8f0a01, 0x582cf803, + 0xf1f671be, 0x0bbfa027, 0xdbc615c7, 0xcd52fc7c, 0xebe20bd3, 0xc81efca5, + 0xa7f31203, 0x7e01fb44, 0xd6bbdaef, 0x31105e48, 0x3497d2c7, 0xe820bfa0, + 0xb1a9cb78, 0x78fc95a7, 0x98efc0ba, 0x39afbfe0, 0x295edccf, 0x714e97f6, + 0xefbd91bc, 0x4ddb3ee3, 0xe02af735, 0x2394dfa7, 0xb8cc7713, 0xe2569ce3, + 0xfc6b898e, 0x63f06ac3, 0xc4f4bef6, 0xbf8b8804, 0x2f91e325, 0x9fdb686f, + 0x20dea1f2, 0x3377dc27, 0xd0a6f5e2, 0xfdf00abd, 0x97931b38, 0x7e1fc6f6, + 0xeb8fe51d, 0xf984de81, 0x9425837f, 0xdf5d231f, 0x8cdbf5dc, 0xf8f17ec6, + 0x02de8b6e, 0x6f0e82ef, 0x054e2d9c, 0x0747b47c, 0xa6ee9f23, 0x79d3f3f3, + 0xfcfce985, 0xd37b4fd4, 0x3efac0e7, 0x05d60e5f, 0x9feb7a7f, 0x4f3f00cf, + 0x0c98e5f0, 0xeac327c6, 0xb620c89e, 0xf88c9d28, 0x74636eea, 0xc0e9fc9b, + 0x7e3e5414, 0x6ce700d2, 0x536c38ca, 0x57ef1389, 0xbdfcfc24, 0x954dbed1, + 0xea0318ef, 0x8cdf68d2, 0x738a6d76, 0xd7c3de26, 0x6384bdde, 0x2052aadf, + 0x5954b3dd, 0x80fbb0aa, 0xe02e9f99, 0x6ff3d231, 0x09b6eca4, 0x19f0db52, + 0x67071de9, 0x3d353caf, 0x3fc2bc01, 0x4e10f717, 0x78f686f9, 0xd7cf4db8, + 0x7e8d4fe7, 0x5b6ad41b, 0x8ba46472, 0x83e85db1, 0x00a01852, 0x23f83f4b, + 0x48596ce3, 0x1a4bd2bf, 0xb579c371, 0x93e449ae, 0xc642bb18, 0xba7e4777, + 0xb59ec1cf, 0x97154fc5, 0x1193c44c, 0xf6b52be5, 0x55f02b31, 0x8565529d, + 0x6c1babfd, 0x52a45713, 0xb4fe8c3c, 0x5bee0a78, 0x84089a35, 0xce84c6c6, + 0x813885ed, 0x1c5d5f38, 0x7c0253da, 0xc0694fb8, 0x05f35375, 0xf8c61bea, + 0x15a1b599, 0x6ac3f056, 0x0b8c6533, 0xba23481c, 0x6dc7a073, 0x3daaefcc, + 0x9dc13ade, 0x0a73bda0, 0xdc4c9f6b, 0x6768f999, 0x51be3053, 0xf384daba, + 0xf6b92d1f, 0x321f8267, 0xd9afdd9d, 0x7f643f5c, 0xe9b78526, 0x1fd434ce, + 0xba1f6a63, 0x110941d7, 0x3e2177fc, 0xb929996f, 0x95efa39e, 0x2f585d3a, + 0xeb879d9d, 0x655f21b8, 0xed0f1e4c, 0xd75c54e3, 0x2917918c, 0x3cfa6f10, + 0xf5802a47, 0x71a92ee1, 0xe4fc1999, 0xe21c6c89, 0x7ac067f0, 0x19f19df3, + 0xcf20d603, 0x05d5fa88, 0x75ea186b, 0x3ba5b3eb, 0xbf81efce, 0x36f4b04f, + 0x8e51cf09, 0x7f12e471, 0xae94ff0c, 0xfea4f4a6, 0x7650a4d7, 0xe4f1f031, + 0xc40932b1, 0x656df1f0, 0x5d881256, 0xb1f3f20f, 0xde2af52d, 0xf8e42037, + 0x53bfce66, 0xdee865a7, 0x0ede6fa7, 0x886267f6, 0xfcb841c7, 0xd9cb80fc, + 0x3bfd7ccd, 0x1bab93dd, 0xbf308cb7, 0x65a4cfe6, 0x671d2a74, 0x960f4a76, + 0x70d2d51f, 0xe5f07318, 0xcf4083ae, 0x618fa0fd, 0x5a2f2b3d, 0x2390fc89, + 0xb77f00b9, 0xb7edf4b8, 0xe3d7d50e, 0xe8353fee, 0x74e0db81, 0x0faf1c94, + 0x56dfdc84, 0xc710ab2f, 0xe288adb9, 0xbd61fd17, 0x5eaede7f, 0x107cecb8, + 0x5bef86dc, 0xb2a4ec2f, 0xefca9436, 0xae1fa16e, 0x7e815722, 0x3f572318, + 0x4cd2fc01, 0x01399eed, 0x21fb08bf, 0x54a5f3d6, 0xc83f815e, 0xab8c4cd9, + 0xe544b98e, 0x9eba2336, 0xea0be88f, 0xf812b84f, 0x7ad81f39, 0x221df6ea, + 0xd4fe83fa, 0x9fdddfc1, 0xb550a318, 0x75700052, 0xd442fe25, 0x2c571857, + 0x10450385, 0x8739cbdf, 0x42af1b71, 0x5768a7d7, 0x8c7a679f, 0xd2ae0bfe, + 0xf46ffc15, 0x789c4433, 0x7ff08a52, 0x89117cf4, 0x31514e17, 0xa1f8238e, + 0xf208f014, 0x38c6453d, 0x21fc7b7e, 0xe29fffc6, 0xe3c2920b, 0xaf48bd7f, + 0xe083f08e, 0x4617c103, 0x4347f1fb, 0xfb2da75c, 0xf5f29691, 0x1f7f63f6, + 0x7b74f515, 0x6764887e, 0x7363d97a, 0xb5f37960, 0x0fc0d9b7, 0x83f5c499, + 0xf89143b0, 0x17c65ad4, 0x29671bfb, 0x05e46fb0, 0xc51790bd, 0x0adf88bb, + 0x4d58ac3e, 0x9e397e30, 0x7aa6a5eb, 0x8ef3cf16, 0x12900396, 0xec7a1252, + 0xf9675609, 0xb79e822e, 0x5228be70, 0xf7f028f6, 0x49756e5f, 0xb913882e, + 0x82703c79, 0x6078c25b, 0x7f823e9c, 0xc75bf6d0, 0xd758014a, 0xa093f519, + 0x7fde64f7, 0x7df09f1c, 0xdc9f2357, 0xbee5c290, 0x9ffee93b, 0x03c60bf4, + 0x4db53b5d, 0x7b7df157, 0xbe0d9d74, 0x5ed9c82d, 0xfe02bf96, 0xa6f5d035, + 0x3bf60a4b, 0xe7ef4535, 0xf05b385c, 0xf20b5c4b, 0xaf798df7, 0x37b4f9c6, + 0xc7e124fe, 0x8c5ebf73, 0xf2c2b37b, 0xa6768df9, 0xbfc2bb5d, 0x32abd233, + 0x26bfb125, 0xde1c6bf4, 0x8b6dfeb9, 0x5fe9ed6e, 0x53feefa1, 0x2bf457fa, + 0xcf1882ec, 0x5adb97a8, 0xbb3d09cf, 0xe309836a, 0xf5f03727, 0xae3c0df2, + 0xc3f70cfb, 0xdede3c02, 0xf782d17c, 0xb6550653, 0x63dfe53f, 0xd6d038c3, + 0xe97fccdd, 0xfbe2756d, 0xc6324a0f, 0x641c1e29, 0xd74c3d42, 0x3f308526, + 0x3e9098a5, 0x85dacfb0, 0x2b56b3ed, 0xe3d432e1, 0x7e40852e, 0xf1959e54, + 0xfa6f83c1, 0x0fff4067, 0x5a6deb1e, 0x70e37181, 0x4331f803, 0xa7dc140a, + 0x313b334a, 0x6f54dcce, 0xe6aabcc6, 0x03daffba, 0xf9aa277f, 0xf2c17122, + 0x39bd5f66, 0x7a044fb2, 0x96fc8c62, 0xcd11790c, 0x0ef3042d, 0x970b4e47, + 0x06e97ac0, 0xd602b0d2, 0x7635c3e1, 0xa788dd8e, 0xc6de7ca3, 0xbec8847d, + 0x1bcb3d41, 0x79e14929, 0x06fb7123, 0x6fb8250d, 0x15ae48a0, 0xd33ed124, + 0x60df667f, 0xf29ce038, 0x7a0c5ff3, 0x7fb1b488, 0xfb6355b0, 0x54872d4c, + 0x39327e02, 0x5e309995, 0x423eded3, 0xb764eedd, 0x82fb0ed3, 0xdbaf9fcc, + 0xccedc5dd, 0xfcfdfb6f, 0x986296c6, 0xd36ad6c6, 0x47632b4a, 0xe246bb8c, + 0x727c4671, 0xbfedc7bc, 0x61a35c84, 0x63c462dd, 0xe2194b71, 0x4fe29bf7, + 0x13d6c5c8, 0xebe06ec9, 0xb8ba27ad, 0x3c63dc61, 0x3b32e70e, 0xbf7604fe, + 0x326b78ee, 0x6e6ab3ee, 0x5a1bac27, 0x762e2cd2, 0xf3e3110f, 0x78dee760, + 0x3c07fc6f, 0xb935b7ae, 0x337d8fe5, 0xd851f763, 0xc51349be, 0x0faa3eeb, + 0x3cfd5f7f, 0xfe7e03e6, 0x13cc51f2, 0x4c86f85a, 0xadaf102c, 0x85e7e14e, + 0x03f81a03, 0xee3235e5, 0x18b9534f, 0x5625393c, 0x7960acdf, 0x3dd95b34, + 0x99afe59f, 0xf7e9e303, 0x927fafe5, 0x4df6f90f, 0xc00e5bcb, 0xbff01fdf, + 0x33bfb12c, 0x87cc6fe7, 0x95cb9afb, 0x2eb271c4, 0x9d7fe676, 0x034eb3ad, + 0xccda40ff, 0x79605efe, 0x8e6aaa70, 0xd9a5ef59, 0xd31ef155, 0xec492f0b, + 0x5f0a097e, 0xe2bf7dec, 0x7d9c06ef, 0xd5f06249, 0xbbf801aa, 0xb79be583, + 0xbe39c135, 0x5c6623f2, 0x9f3779bf, 0x4b33fbc3, 0xfcc16eb6, 0x4cad6f60, + 0x09d619f6, 0x9b53f3ba, 0x45e430e5, 0xbfb0d455, 0x98eb4023, 0x4c115527, + 0xbdb08e7c, 0xb70b3e73, 0x87eebfd6, 0x2feda83c, 0x9dbec1da, 0x0764d869, + 0xbf7ed3bc, 0xdc62fcf6, 0xc3e0a979, 0xea5e7b5f, 0x5a72610c, 0x379c3762, + 0x37c19cdb, 0x6383c223, 0x78a3faf3, 0x70b9fc64, 0xe067c5cb, 0xd7d9ef3c, + 0xe0067b3e, 0xf9d5f45d, 0x0d7f6067, 0xbd60f512, 0x6ff97dea, 0x7c521e78, + 0xdff72777, 0x117a5e9a, 0xbd3691cf, 0x6f41766f, 0xbb27f54d, 0xa6ca79c1, + 0x82caff6d, 0xfad2deb8, 0x2e77e831, 0xcffd41dd, 0xa2bafb04, 0x83e8326c, + 0x1ab1ceb6, 0x66b7b5e9, 0xf380376f, 0xf06f4a73, 0xdfe7237b, 0x2ecf2c82, + 0x3aadee72, 0xb8e179f1, 0x93356e73, 0x2061bd6f, 0xd40baa94, 0xdde7bb46, + 0x5e3a530e, 0x55fa01df, 0xeaf3cc3f, 0x73efd312, 0xd3a507f8, 0xf3faeccf, + 0xe66b17e6, 0xb434fb3c, 0x79b464d5, 0x01dc2dde, 0xc8f389bc, 0x55eeed63, + 0xd79b9076, 0x85f3c15e, 0x74f1b740, 0x2e5b4da2, 0xdc738376, 0xbb96d4a7, + 0xda836f30, 0x940b8843, 0xf287bfd7, 0x10e3b4d3, 0x3f0969c6, 0x2244dc17, + 0x538e763f, 0x98dcf3e2, 0x71c9cec2, 0x3a39c3fc, 0x39f4e3d0, 0xf8c72f3f, + 0x6ba39c58, 0xbd5cfceb, 0xefbf07bd, 0x77bb13ba, 0x1a87e378, 0x4a20dfbb, + 0x3468692f, 0x3a2dbd0f, 0x00383c09, 0xcf62430f, 0xa73e2683, 0xcc373918, + 0x03f405e9, 0xde722fff, 0x6247d693, 0x248f7a5d, 0x1b4d07d0, 0x26d239d8, + 0xf53df135, 0xad687ce2, 0x9e62ce81, 0x9087c96d, 0xffe0f6d3, 0xc979f8a6, + 0x8bf1d4ee, 0xcbd9d3c0, 0x87f8f589, 0xddbbe976, 0x8c96e36b, 0x607cdaf7, + 0xd3f704ef, 0x98f9e51e, 0xcc5acf2c, 0x96f82cf7, 0xbecf4f94, 0x17fde32c, + 0x517b82ab, 0x85f51b8f, 0xc23597d8, 0xb78739fb, 0x89d996a2, 0x04a5afb3, + 0xb39fb46c, 0x3f21d66f, 0xd51f5457, 0xc0ef8f20, 0x8b1aede6, 0x01f933d7, + 0xc71b113b, 0x9eeafb3a, 0x24dbd47c, 0x97f27e71, 0x437a1f5c, 0x56f1c789, + 0xb38dd39f, 0xfbc41fd0, 0xef1bdab1, 0x0a9ee28c, 0x50699dfd, 0x4cfa3f31, + 0x8d41c590, 0xedcc7fe3, 0x203ee466, 0xcf412f6a, 0x5768fb88, 0x3cf30468, + 0xe79626fd, 0x6a7efc69, 0x00d3c32a, 0xee04b387, 0x82d9750b, 0x52b8b9b8, + 0xd4cdc32e, 0x6c7b9115, 0xf6f7f85c, 0xe4977922, 0x2f309b91, 0x925de452, + 0x50bd5927, 0x613703d4, 0xfe10e51e, 0xdac03fbe, 0xeb4c2161, 0xecf97eb3, + 0x2c7efe4d, 0x3320b26f, 0x9cffcfea, 0x829630fa, 0xd5a67ee8, 0xa049fc4c, + 0x3ebdf82f, 0x22b27f22, 0x3575e449, 0x9ef7f3b2, 0xfa5f9d6c, 0x77a7bb47, + 0x5b73ec2a, 0x552776c2, 0xc6eb4b29, 0x4e2a1da0, 0xfabe2075, 0x03911f6e, + 0xc1ffc1fb, 0x76a707f1, 0xa57f1f8a, 0x6ab7faca, 0xe074dfb4, 0x4025be97, + 0x09ddbee7, 0x831773e6, 0xa3bf4a13, 0x9e7c14cb, 0xfec1c944, 0x073b995e, + 0xd22b1fe2, 0x2c63cc34, 0xdd00b0a6, 0x5e5c658c, 0x72a9aa68, 0xa5c72d1b, + 0xcdc875b2, 0x1ebe4ea9, 0x277f6169, 0xffc2d1cc, 0xe7db184e, 0x9682e597, + 0xe981d830, 0xecbfcc29, 0xdc31f2da, 0xb4eef1ff, 0x37582ebe, 0x7a4c0d4d, + 0x21b7e610, 0xf00933d5, 0xeeb4befb, 0x9b5f946a, 0x34fc0527, 0xfcb1ddc9, + 0x8871f8d0, 0xdbf4fc05, 0x61057187, 0xbc18f763, 0xe955943b, 0xa7c01e78, + 0xae323f18, 0x03d8bf21, 0x13883d71, 0xf11efbf1, 0xce3a7afe, 0xcc26e3f6, + 0xb64a6f8f, 0x59b47bf3, 0x00b608dc, 0x3fc7def0, 0xbef9972f, 0x5f775f96, + 0xa7bb2d5c, 0xb89eee3e, 0x08129e83, 0x8bef1839, 0x3b37de33, 0x4f300494, + 0xdc7f78d4, 0x307ebe08, 0x40f71bde, 0x5d0fb72a, 0xbddd1748, 0x5fd616db, + 0xf03d5beb, 0x09dc1b9c, 0x6b3c5325, 0x4d0c994e, 0x0d73ca8f, 0x3e708fd5, + 0x4e7e75f8, 0xc761ffb8, 0x2d7f003d, 0x79435fdc, 0x1dfc177b, 0x072a2d13, + 0xbb930ffd, 0xb9a75ec1, 0xacd4ff99, 0xd3cb7bb2, 0xbf4058e8, 0xc98fb834, + 0x89c4fa0e, 0x9bfe1b79, 0x3c7bee09, 0xa0499729, 0x92e9721f, 0x5c47ee1b, + 0x3dc7cfc9, 0xf6e9326a, 0xca9d7e61, 0xf96fe3f4, 0xefb1633d, 0xb7a04a4d, + 0xeb654d9f, 0x552cdb85, 0x9f198557, 0x9f740b3d, 0x70a8f26e, 0x599a9b4f, + 0x331c42a9, 0xce4fca35, 0x13e2092b, 0xeecedfef, 0xab5f7f4b, 0x81ebf39a, + 0xef66f3d1, 0xc7814600, 0x6fb8e92c, 0xbee38d3b, 0x4d4ce9d5, 0xd5a7818b, + 0x99dbe426, 0xeadb720a, 0x91e589e9, 0x1f719a1f, 0xcfa688e9, 0x02f71783, + 0xc480fb89, 0x7da2417d, 0x291586fe, 0xe91f1fe0, 0x74e77443, 0xd2ff5c42, + 0xf9039ef5, 0xf3a3047f, 0xa67f73fb, 0xff15dfc2, 0x82f48fab, 0xc5f187bf, + 0x4cdd73f4, 0x73cddf14, 0xd7f8b9ff, 0x79a3ddb4, 0xdcbc04de, 0x1578db9d, + 0x531dd7c8, 0x4dfa41ce, 0xf9bf7cdc, 0x9e3f653c, 0x61250ecb, 0xef3bc23c, + 0x4f180acb, 0xe6f687e8, 0x1d972f9b, 0x2a70bd06, 0x8bde09f0, 0xf626c646, + 0x8dfe8d5f, 0xe71773e0, 0x0db231f3, 0x493356ed, 0x5cac7966, 0x73ee636e, + 0xb37ee273, 0xe209fc9b, 0x98f62b3a, 0xd99fec08, 0xe1778941, 0x87754882, + 0x8af6165d, 0xf5942db8, 0xda1fcd21, 0xb95ea54f, 0x17c42569, 0xc8682fe0, + 0xfa80faf1, 0x56296e2b, 0x4f2bec0f, 0x79d607ac, 0x5a96c056, 0x58607a7b, + 0xdb7e84d8, 0x5f07d537, 0xe281f419, 0x82be2270, 0x605033e0, 0xc43e1fff, + 0x8000938b, 0x00008000, 0x00088b1f, 0x00000000, 0x59edff00, 0xe554707b, + 0xef773f15, 0xc3cdddde, 0x210366e4, 0x804d8404, 0x85701020, 0x5c7c0188, + 0x94422101, 0xd6da0300, 0x02101ba9, 0x16a52d79, 0x9b8cea9d, 0x8e233480, + 0xd29dad13, 0x542cce96, 0x2ec4952a, 0x4dd0689a, 0xd15c04ba, 0x63e02711, + 0xb46d63a0, 0xec083a2d, 0x98f8a71a, 0xe739ec76, 0x647dd7bb, 0xeffa7471, + 0xe5f98617, 0x7cebdfbb, 0xe3cefce7, 0x648a12fb, 0x40a50307, 0x676a733f, + 0xf1d31c02, 0xee016bb7, 0x0d1c442a, 0x00f250e0, 0x007f73e6, 0xd63c03c6, + 0xe9b6dc06, 0xdb007b5a, 0x2ed8c9ae, 0x95d6c801, 0xfc76edf6, 0x06dbb8fd, + 0xbab60173, 0xc00f77f0, 0xf9e9b1f0, 0xffbf8150, 0xbe956be7, 0x16bcea57, + 0x373f4d7c, 0xb772b025, 0xecf7000d, 0xb5ddc372, 0x9d701e34, 0x913ac4a2, + 0x46383668, 0x9dbac401, 0xef289d7b, 0xb1b0b870, 0xddc3db13, 0x5a64d759, + 0x1e17c2cf, 0x40074ec2, 0xf3e36e8d, 0x91bdb05c, 0x35eb8157, 0x87973cf5, + 0x33c685c7, 0xd752e6a7, 0x64df0e9b, 0x4e7dcf1d, 0x9aee5bd9, 0xc1ed1d84, + 0x508fa459, 0x87df2ca4, 0x43b4ccf2, 0xe47b3ec0, 0xf8ddfefa, 0xcb400e71, + 0xcce3376e, 0x987a9cf0, 0xe223df85, 0x8687b43c, 0x817ad35d, 0xb77b17db, + 0xff3d69bb, 0x7c4afa5f, 0x470700b9, 0xc4219dc3, 0x2e98be67, 0x4ec1dbe6, + 0x05e9e7e3, 0xd0402f2c, 0x39170ab6, 0x9c38e1a8, 0x1b0bf177, 0x9ff6b38f, + 0xaab37bd9, 0x222a89a3, 0xfa80031d, 0x3d3b0ac8, 0xa7accf64, 0x676e1400, + 0xfdc14105, 0x528297fa, 0x002bfa89, 0x5dfd82af, 0x01f7f1d9, 0xa73ef1db, + 0x67f61f67, 0xc6e01de9, 0x421cbbf5, 0x8c00d3ff, 0xdf1372e7, 0xc2b2fdad, + 0x65c806bf, 0xea411bbb, 0x0dc077b7, 0x9b7e89b9, 0xfdcb057e, 0xa7f05d43, + 0xcb623b2b, 0x53e23945, 0x5cb1f600, 0xf7813909, 0x169ce4b5, 0x7fb4280c, + 0xa303ecfc, 0x9f7d2e58, 0x7210e487, 0x67aa7842, 0x0dd7cd3f, 0xee96473e, + 0x74f8d2f1, 0x20b3fcb9, 0x9e09f908, 0x55018fe2, 0xd13b3df8, 0xfb855d76, + 0x42de0994, 0xe2fb7660, 0xc4da93eb, 0x7cc4aaf3, 0xfb6d7ebf, 0x1db9e40e, + 0xa9a2afed, 0x70af1073, 0x7c3d39d3, 0x31bca43e, 0x83d0b67a, 0xe394f517, + 0x8cdffd12, 0x52e6fe47, 0xf38c573b, 0x659cf53a, 0x400feca5, 0x8202d0fe, + 0x912af7df, 0x00a937b3, 0xcdaf1fe7, 0x9d73c0af, 0xeb6c0db7, 0xd49f71c4, + 0xd823ca85, 0xfdf3ceae, 0x5efdc75c, 0xaedd6f7c, 0x739fa899, 0x06b79a5d, + 0xe050c1e7, 0x8fa87189, 0xcf346786, 0x007e4923, 0xc445e3e3, 0xfc7df4df, + 0x189eda67, 0x58747e47, 0x1db0b8f1, 0x4813e2d3, 0x47f096ee, 0x7978830e, + 0x078703f8, 0xf81715e7, 0x543f9276, 0x222eb6f5, 0x8e83cebd, 0x0ce23aed, + 0xaf88f81b, 0x0f5c62a1, 0xbb7e1df7, 0x926b5f7c, 0x85753a1d, 0x7dc407e3, + 0x0a916b13, 0xfaffd361, 0xf631721f, 0x24c1f91c, 0x1347bf5a, 0xb5e6b33c, + 0xd238c0c2, 0x631c1b7b, 0x82c7beb4, 0xd9e26af6, 0x775d778c, 0x9fe3491b, + 0x69f9fd36, 0x41710fda, 0xc90f6f81, 0x43e478db, 0xf39d1e47, 0x8009a19f, + 0x4f764243, 0xf97b9ebe, 0xf34fe0f8, 0xee3dbf27, 0x8ffef1a0, 0x7415df91, + 0x079f0f1e, 0x1f23beed, 0xddf078ed, 0xd875e9de, 0xfc2a53df, 0x1dab47b1, + 0xdf5be347, 0x086b34b9, 0x123231f1, 0xd7d4bf8e, 0x86f49138, 0x4d985ffc, + 0xf908767e, 0x69f849ef, 0x8a29f905, 0xaffc415e, 0x8e34f6a4, 0xc18e5dc3, + 0x3d97ec65, 0x44bf2036, 0x203fb3fe, 0x40fdf5ff, 0x781fd1e3, 0xf3f654fe, + 0x419b41ae, 0xf1c600ed, 0xb85edc29, 0x835dda9a, 0x73f6758b, 0x3679f21b, + 0x80646bf9, 0x4c0109d7, 0x5029d321, 0xf648aa1b, 0xa3d63cdb, 0xdba7d4cd, + 0x55d0dff4, 0x9e2f7c9e, 0x53554723, 0xb54f23fc, 0xb502f225, 0x3fdc2bb7, + 0xed0df1e6, 0xc13fa24f, 0x740799a0, 0x2d383bc1, 0x5d4ff9e2, 0x7d6ffe22, + 0x4e8afe65, 0x13d6e73c, 0x13f7f72a, 0xce31ca4f, 0x78193c9b, 0xe536e748, + 0xe7da0f05, 0xfcc543d8, 0x1b6c5afd, 0x1ae74718, 0xba51165b, 0x38eeaaa9, + 0x36bf384a, 0xbc4348b4, 0xa3c1cefe, 0x19f3709a, 0x81eebfc4, 0x29d8675b, + 0x42719dee, 0xfdd88a16, 0x67fdfc55, 0xfadb0f50, 0xf219ff51, 0xf9871e06, + 0x0e3b5007, 0xc7f6478a, 0xdc8e2b14, 0xbc7c4d5f, 0xda26add8, 0x120b4828, + 0xf417da9b, 0x6c01ed6d, 0xc46057df, 0x71bf9789, 0x8d44e2fb, 0x8aafc9d8, + 0xde7b2dc8, 0xe28f30fe, 0x98c3b77f, 0x2ee9fc41, 0x0ca14d83, 0xd74f7d3c, + 0x4e954f98, 0xdfa992d8, 0xa0fc205d, 0x88bb003c, 0xaadd2d47, 0x5fbb441e, + 0xc70d56e8, 0x431f00d5, 0x8a02ed60, 0xb0630137, 0x01bff518, 0xc8031fac, + 0xa6894d1e, 0x68daf641, 0x6b1c3736, 0xd63ca1a8, 0x20e83ea4, 0xa4f8da3f, + 0x55d0e1f6, 0xffc6ee66, 0x27686153, 0x53ff11c5, 0xed82378a, 0xfb527b4d, + 0x7887c21b, 0xa953c35e, 0xb13a9bdf, 0xddb44aed, 0x3a8c5705, 0x997f033b, + 0x42b09304, 0x5c711e20, 0xdc70ecd0, 0xd97dbc89, 0x6f4953ed, 0x3f426d07, + 0x0fd94f18, 0x2cbf2b55, 0x7e287114, 0x2fec8201, 0xf3474207, 0x9df9ae50, + 0x63da5ea5, 0xcff45dbe, 0xfce52def, 0xbaa0f602, 0x65500d12, 0xde9096f8, + 0x176f2f51, 0x9937b9e3, 0xfc7411f1, 0xa6cded87, 0x1e91361e, 0x073635d0, + 0x079ee553, 0x4fb4edc1, 0x3f3c01fd, 0x903c6bce, 0xd7e96fda, 0xb4d3ae6f, + 0x2c7464fb, 0x75287362, 0xfd1e1f9c, 0xa17aa554, 0x73fbf537, 0x5cc09bc0, + 0x60133f4b, 0xeb07e902, 0x97b1802b, 0x8ee4678f, 0x344f97a4, 0x329c5751, + 0xd7fab1d7, 0x41697c9a, 0x344e28f1, 0xf120d505, 0xc8129365, 0xcfb79503, + 0xd7b943ad, 0xe0f0bc5b, 0x3dc7d43f, 0x9bd67ea6, 0xe173e0bc, 0x4a3de6fc, + 0xeff38230, 0xfe553479, 0x25baa10d, 0x79233ce3, 0xab53a9b3, 0x6e7e6073, + 0xb40e2d80, 0x98de48f9, 0x70e800fa, 0xe74afe50, 0xb94f8b4f, 0x6e46dc8c, + 0x5fffdcdd, 0xe22d46ee, 0xf8da7ca0, 0x201bc52b, 0xe27fbbf9, 0xe791b280, + 0x60dbecb0, 0xd73cc4f1, 0x56cf3df7, 0x61d3becb, 0xbab7db3a, 0x37d93bf0, + 0x6f463ebd, 0xc618ff63, 0x9150577c, 0xfcfa4fe0, 0xbd9d6625, 0x5e303774, + 0xcf2cfde8, 0x8362f383, 0x68c079c3, 0x47bca6ab, 0xf149c9ed, 0xcec0ada6, + 0xfe2ceefb, 0x500b63c7, 0x690f4b3f, 0xa0e0ac5e, 0x96ad4ae9, 0x95d373f2, + 0x4e4d14af, 0xe6ed27ca, 0x3687a5f8, 0x9c5165b4, 0x25e293f8, 0x7f858bf7, + 0x40ed4036, 0x829de2a7, 0xc383a3f3, 0x7b202e6f, 0xa5cce714, 0xb77dfcf5, + 0x76c2e8cc, 0xaf1cdf74, 0x17ac49ea, 0x2df38b75, 0x7ce352bd, 0xe724be79, + 0xbf68350f, 0xfb2f6306, 0x9e97f9f1, 0xc79f9077, 0xc62814ba, 0x47c5a28d, + 0xbea00d9f, 0xd270bfcf, 0xa2f84541, 0xa18e93ee, 0x2e03a96f, 0x50885504, + 0x3877b03c, 0xdb52bee8, 0x10c72ff3, 0x7d4f45d5, 0x34bd20e0, 0x471c2af4, + 0x41a8f61a, 0xb47afe0f, 0xf10745ef, 0x8153a5a8, 0xfdc9a531, 0xe663f71a, + 0xc23e7964, 0x092adffe, 0xf933ae7e, 0xe2d3f168, 0xce333aeb, 0xe54f6fac, + 0x763046e3, 0x0dfce096, 0x4f1c759d, 0x8e647437, 0xaabc5633, 0x28ead88f, + 0x4eefd7ee, 0x1bf9b71d, 0x941c061e, 0xd9e3d317, 0xd3878b51, 0x70f11a60, + 0xa26eb238, 0xe97f791d, 0xa844c364, 0x37afa918, 0xe56d7ccc, 0xf5e9cbcb, + 0x0e67ef62, 0xf1fe73ca, 0xfc17df1a, 0x48edffe3, 0xe209c9e6, 0x25b7e609, + 0x3ed94fe1, 0x8b23e135, 0xc0dbbf69, 0xbdfa44d7, 0x53a39c2d, 0x24335bfd, + 0xd85976fc, 0x242a0c19, 0xdbf38d9f, 0x41da106d, 0x3bf58ff6, 0x92f03fb9, + 0x981075c2, 0xd4deac71, 0xdfa9bd77, 0x8d5fbc7a, 0x30f54d9b, 0xfae283ea, + 0x6ea37b55, 0xbf316fec, 0x3476bd37, 0x0cbcf48f, 0x16599c44, 0xb2c67112, + 0xd2279597, 0xd0331cfd, 0x8ddec98f, 0x823c2761, 0x719b97e3, 0xc6277966, + 0xdfa46519, 0x30e6c6c7, 0x423d025f, 0xd8bcf4de, 0xfe3a9dd2, 0x2ba8814c, + 0xf67acd87, 0xd57b34cb, 0x02a721c4, 0x51e65bd7, 0x359e41bd, 0x8ffda768, + 0xe1fe42cf, 0x933dc7fa, 0x397b1ef8, 0xd669bd3b, 0x057b56e9, 0xc3ea8b12, + 0x5b91de90, 0xf737e490, 0x3921d860, 0x01a9e61a, 0xbdd27fd2, 0xd2ecc565, + 0xdd16f78c, 0x1d5fe38d, 0x6bd1febf, 0xc62def92, 0xe1e272de, 0x597f8a2f, + 0x43e29b33, 0x172788a7, 0x7cdd70ab, 0xeb81c3aa, 0x33a77f5a, 0x3f0bf748, + 0xadea88f2, 0xf213c4a5, 0x0b72b0cf, 0xfeeb04f1, 0x4afeb4f1, 0xe146192c, + 0x8af657f9, 0xe2e5647a, 0xaf77994f, 0x46e7164d, 0x74c98dbd, 0xffeab00f, + 0x9d442f96, 0xb16f7d69, 0xa03df10f, 0x6f30ac25, 0x9cbe07bb, 0xc6f28a50, + 0x509f3efa, 0x16eb5887, 0x54f5b479, 0x797d5036, 0xa0ceaff1, 0x74bce513, + 0x1f0fe5f8, 0x2ea5f6c0, 0xf2e63117, 0xc1d95c71, 0x0da2d37e, 0x721d7115, + 0xebbceb18, 0x7c73bd68, 0xc81ee88f, 0xbc40dbba, 0x5137ceb8, 0xb5bb16ff, + 0xa9d71b42, 0x9183b06d, 0x3ae499ea, 0xcac75eae, 0x8d864b14, 0x566bfe66, + 0x7bc42373, 0x57346e2b, 0x883dc625, 0x6b88dffc, 0x533b38dc, 0x5cec08fc, + 0x1b8c8ca0, 0x777b158d, 0xfd5321ba, 0x977ce113, 0xe3dcef5e, 0x24e6de46, + 0x1e2a1b78, 0xde84b67a, 0xa13b4e71, 0xffce94b5, 0xafb204d5, 0x9ceb7e75, + 0x9e7e4ce7, 0xc601fba7, 0x952ad69d, 0x279b65f5, 0x708baad0, 0x7626f31e, + 0xf5483732, 0x17fe8cfe, 0x8d0788cb, 0xb25c7007, 0x7d1da1ff, 0x90438854, + 0x421cdcf9, 0x3ce492a1, 0x74e2ffd8, 0x97d91be2, 0xa6fc9dde, 0xb2e5d37d, + 0xfdc45150, 0xfb88a6d5, 0x287d8f6b, 0xfe4dee8f, 0x306d6ac3, 0xfcd67ec9, + 0x80fe4d7b, 0xefd3dc5d, 0x7c4420a7, 0xd81e0b0a, 0xef2204fa, 0x1a778ad6, + 0x334aca0d, 0x7e442ff4, 0x035e4b7c, 0xea6d0b92, 0x33cce2d7, 0xcb1b49ff, + 0x5c393fe3, 0x03df9c94, 0x8a18eeb4, 0xc04dad7b, 0x28072471, 0x0b1c62ce, + 0xf97b63e4, 0x97ae2ce9, 0x6abb65a2, 0xa9956e38, 0x5b6b7140, 0xc9a9e6ff, + 0x05bfe1f9, 0xe91738aa, 0x95aa98a1, 0xa6fec527, 0x9560da1e, 0xbc17cf79, + 0x7888140d, 0x27a3f782, 0x47ee19dd, 0x6ddeb5df, 0x3d8273ed, 0xfa974ec9, + 0x0dfef9ea, 0x52a6f85f, 0xef9f019c, 0xfd6dc26a, 0xfbe953f5, 0x57cdfea5, + 0xd2a4bbf3, 0x02bf9296, 0xd5315f24, 0x7914ef45, 0xefb9bfb0, 0xd460229d, + 0x276a7e58, 0x6efdafe7, 0x8ec4e751, 0x84fbf164, 0x07826502, 0xdd653930, + 0xb857eea6, 0x55ea688e, 0x583e648d, 0x22dc7af3, 0x1e261e0f, 0x1486b620, + 0x487ced83, 0xf3ef5360, 0x16a34f2c, 0x76b63b62, 0x4bbfa26a, 0x3c97d620, + 0x00ee002f, 0x39feafc9, 0x52754c3c, 0x87964f73, 0x3eb14bde, 0xc4b1f914, + 0xfa8fdc19, 0x99c2f459, 0xcd5b8a22, 0xf50a682f, 0xbbea50c3, 0x679b736d, + 0xbde88fc5, 0xe81575e0, 0xda55e1dd, 0xc4b0ed02, 0x4d54d181, 0x1d66efca, + 0x5f9bb560, 0xc8d4abaa, 0xcb06dbef, 0xe6ce512b, 0x3b4abafe, 0x78b4f419, + 0xb634ba0f, 0x3009eb91, 0x95b65d84, 0x27f0a634, 0xf7290300, 0xb14e506e, + 0x8d61631e, 0x03a281df, 0xfde9ca67, 0x6fe4b9a8, 0x7347e4e5, 0x537bc50a, + 0x554bbd33, 0x7de27c90, 0x4d7f9aca, 0xafb3f0a1, 0x0b7b7f4d, 0x7bcda3bc, + 0x9e1b2ece, 0x4d1aadff, 0x05eb847f, 0x6edd9f51, 0xb7d5cdc6, 0xbc5f5c69, + 0xc78d1e05, 0xcca18a1b, 0xfac8bce5, 0xa78cddb9, 0xe352aa2b, 0xf03dcadb, + 0x91a11670, 0x635b4eb9, 0x0c0abfae, 0x7575775e, 0x6635b8ea, 0x36a6b69d, + 0x56e7fbf5, 0x930c9cdc, 0xc2ea6e39, 0x66c75b9e, 0xb90c7e71, 0x0cdef93c, + 0xb475e279, 0xf541c78f, 0x683c0b9a, 0x1c66e3a7, 0x01c92b6d, 0x177e28f7, + 0xa3fd9209, 0x53bfbed9, 0x719f8ade, 0x34553bf2, 0x1565ce2d, 0x29cd3f0a, + 0x514a7114, 0x9b276ca2, 0xa3ed9c72, 0xed9baf28, 0xe7ec5237, 0x533bc4d7, + 0xfc937914, 0xacc27c8e, 0x788aa223, 0x7b974b47, 0x8778a17c, 0x34dfa11a, + 0x5fd08ebd, 0x36a2de9a, 0x6ec5c751, 0x5ffef856, 0xc519f58e, 0x958bb5af, + 0x14f141a0, 0x2bfdc0f5, 0x54c3d615, 0x62704f88, 0x8f981dff, 0x4d8beea8, + 0xb6fd7513, 0xefe2f9b5, 0x9b780124, 0x64f168ec, 0x57e45d85, 0x286b0f8b, + 0xdf12cebf, 0x6ede9f29, 0x7755d3e6, 0x850af35e, 0xadaf4b45, 0x2f9ca7e4, + 0xb1463146, 0x475e20be, 0x53c7eafb, 0x917d23dc, 0xf32f479f, 0xadc2742e, + 0xa72e7eb1, 0x2fd36abf, 0xa839476e, 0x7adefdae, 0xeba5e734, 0x9530bab3, + 0x2b581887, 0xf2138fc8, 0xc7e6333b, 0x943ca6d5, 0x47e80363, 0xedfd4d6b, + 0x2eadf7cd, 0x0477efc4, 0x7e4c3d57, 0xb3d94675, 0xce2410ff, 0x9d187a4d, + 0x85addeb4, 0x090c3de2, 0x9b7ef192, 0x16f0179e, 0xd7b8e016, 0x54af718f, + 0x241777bc, 0x933eebe9, 0xb161d7d7, 0x079c764a, 0x25de9501, 0xdc3b03ae, + 0x443b6d45, 0x200b88ec, 0xfe81dfc2, 0x4fc45608, 0x9d73fcea, 0x9944723d, + 0xeff8e3c5, 0x9061f343, 0x7108ddc7, 0x3b740346, 0x32f042e1, 0xcb22b956, + 0x08af6ca9, 0x4baa5485, 0x82f64523, 0x5213a8b3, 0x2473a665, 0xb38763ce, + 0xd2a2fd56, 0x0b6011df, 0x3cfd3dd9, 0x0c79d61d, 0x0d4a4bc1, 0x555ca177, + 0x93695210, 0x1548601b, 0x39f32ff1, 0x4ddd6016, 0x01b8b77f, 0xfacd9fed, + 0xebf8f208, 0xa66a3ce9, 0xaf2d0cf3, 0xeb1615e0, 0x29129f24, 0xf39d7db2, + 0x2b11cfdd, 0x6f375e02, 0x03e2fc7d, 0xfbbf8995, 0x9eafc378, 0x2a3d3fa6, + 0xd3f70186, 0x665c4ddf, 0x9fb11add, 0x788f86ff, 0xe17dfd3f, 0x5215dfba, + 0x7ce8f23c, 0x8781f04e, 0xf60638f8, 0xb23f74e8, 0x7142b8d1, 0x128b8fdc, + 0x5c103bbc, 0x2f21b1e5, 0xf2e518ee, 0x43cca5aa, 0xab8d675e, 0xcf7a4ae3, + 0xe14e4d43, 0x91e4c1ba, 0x6aab7f25, 0x2af891fc, 0x8944a251, 0x944a2512, + 0x44a25128, 0x4a251289, 0xa2512894, 0x25128944, 0x5128944a, 0x128944a2, + 0x28944a25, 0x8944a251, 0x944a2512, 0x44a25128, 0x4a251289, 0xa2512894, + 0x25128944, 0x5128944a, 0x128944a2, 0x28944a25, 0x8944a251, 0x944a2512, + 0x44a25128, 0x4a251289, 0xa2512894, 0x25128944, 0x5128944a, 0x128944a2, + 0x28944a25, 0xffe12251, 0x72255300, 0x008000ab, 0x00000000, 0x00088b1f, + 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, + 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, + 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, + 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, + 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, + 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, + 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, + 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, + 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, + 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0x00088b1f, + 0x00000000, 0xc5edff00, 0x30001131, 0xee300408, 0xd85aa12a, 0xaa66f6b1, + 0x964d2113, 0x5dbbcce4, 0x6db6db15, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x3d017e3f, 0x009b1baa, 0x00009b1b, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0x00001000, 0x00002080, 0x00003100, + 0x00004180, 0x00005200, 0x00006280, 0x00007300, 0x00008380, 0x00009400, + 0x0000a480, 0x0000b500, 0x0000c580, 0x0000d600, 0x0000e680, 0x0000f700, + 0x00010780, 0x00011800, 0x00012880, 0x00013900, 0x00014980, 0x00015a00, + 0x00016a80, 0x00017b00, 0x00018b80, 0x00019c00, 0x0001ac80, 0x0001bd00, + 0x0001cd80, 0x0001de00, 0x0001ee80, 0x0001ff00, 0x00000000, 0x00010001, + 0x000e0004, 0xcccccccd, 0xffffffff, 0xffffffff, 0xcccc0201, 0xcccccccc, + 0x00100000, 0x00000000, 0x00000000, 0xffffffff, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000, + 0x40000000, 0x40000000, 0x00088b1f, 0x00000000, 0x1113ff00, 0x51f86066, + 0x423ec08f, 0xac9d0c0c, 0xc4b462a8, 0x1818990b, 0x12b102fe, 0x3c430333, + 0x203aded0, 0x2388107d, 0x16181858, 0x2fd610b0, 0x022bd404, 0x2c4062c4, + 0x19b7c401, 0x9cdfb348, 0x1f0f680b, 0xc8037f82, 0x3f4024be, 0x1c360fff, + 0xfb5f40ad, 0x1819d502, 0x8aa06bfe, 0xf2a26831, 0x9bf13519, 0xcf2684c1, + 0x2167c68c, 0x63247fa0, 0x0d75b600, 0x000400f1, 0x00000000, 0x00088b1f, + 0x00000000, 0x7dd5ff00, 0xd554780b, 0x673ef0b5, 0xf3399cce, 0x00fde4cc, + 0x108f0992, 0x2104e034, 0x0432b445, 0x3b69488c, 0xc514543c, 0xf791e109, + 0xb14a3e44, 0x44033bd2, 0x350af808, 0x0380a050, 0xed168d02, 0x06823ca0, + 0xfda2901c, 0x5a1bdedb, 0xcb6ab7bd, 0x880b851f, 0x52d11921, 0xf77ac5ea, + 0xcc9f7b5a, 0xd0049339, 0x9fdffed6, 0xcfb3767e, 0xd6bdaf7e, 0xf7b5ebda, + 0xa441c448, 0x84be421c, 0xfc8471bf, 0xa484205e, 0x83bf52c6, 0xa908a3a6, + 0x2d0867d9, 0xc26425cf, 0x5c64633e, 0x136fcd0a, 0x179a2642, 0xbcb19b0f, + 0xfbcb3373, 0xdd4f6d0d, 0x01c9cb4a, 0x1349d903, 0x49116f92, 0x1467211a, + 0xd146fec2, 0xf321117c, 0xb35b2ccd, 0x426cc8ed, 0x98b797eb, 0x3fb69988, + 0x81e0d7b3, 0x429dc2fc, 0xd439d088, 0x67255c1c, 0x8417fed1, 0x45d9b084, + 0x47e93bf3, 0xd7b15e5a, 0x5dfa8210, 0xaf34b68e, 0x01f3908d, 0x9864b885, + 0xed693bdf, 0x86548405, 0xd16494f6, 0x05bb957a, 0xa9c748b7, 0xc6442cdc, + 0x42ef828d, 0xa8bb40c8, 0x5712b66a, 0x97c39b3e, 0x75c5c704, 0xc742dc2c, + 0xa912fda5, 0x61daf651, 0xcbb2b5bc, 0xf9cf831e, 0x51c71380, 0xd3cf35f3, + 0xdabb6871, 0x2c370497, 0xbe2456b1, 0xf3bf1d30, 0x73e679a0, 0x32df5836, + 0x5daecf39, 0x587ee947, 0x9b686547, 0x7983625c, 0x17e7936d, 0x6aabfac4, + 0x6bcfd64e, 0x9f74a0c3, 0x3d3e3ca6, 0x95c4201f, 0x1257cb17, 0x60db09e2, + 0xea7921fe, 0x63f7d8f0, 0xb3f71124, 0x5c40d9aa, 0x427fac4a, 0x40ddf882, + 0x2b8011dc, 0xb5bbb569, 0xa9d176fb, 0x8985b7df, 0xf31f6dbc, 0xc3ef9a79, + 0x27a70e5a, 0x4d347e61, 0x499738f0, 0x1309fd74, 0x4ab85389, 0x3246b5fb, + 0x7acbdc33, 0x186405ef, 0x888f884d, 0xe25adf38, 0x2ed21fbb, 0x4e9caeb1, + 0x3245fe9e, 0xabbd74bc, 0xfbfed604, 0x57f585c4, 0xb03d900d, 0x2aef6baf, + 0xcb90ce7a, 0xf90292d7, 0xd0d6bbf9, 0x7926932e, 0x0257c008, 0x614015b8, + 0xcb40d07b, 0x4713bbed, 0xe16971ae, 0xc61f3c57, 0x75128c73, 0xcdbce3fb, + 0x4d27cba2, 0xaf838a4c, 0x46e679cd, 0x34f3a79e, 0xd211d189, 0x67c64220, + 0x8b6f882b, 0x9ba465b3, 0x79b3b7c5, 0x85b6ce2d, 0x38ff3482, 0xe685b834, + 0xce4ddf65, 0x4741e05e, 0xa4064916, 0xe98c913e, 0x7000de59, 0x9c5078a4, + 0x03ef2573, 0x68c5fa9a, 0x1f4d225e, 0x0107c616, 0x8e012b2e, 0x481ab534, + 0x6adbac1d, 0x86a70822, 0x05cf4521, 0x9d5a7035, 0x1b94e14b, 0xb1b577eb, + 0x09b8832e, 0x23bc1359, 0xf8526528, 0x1dcdd2e6, 0x23bdf30b, 0xdb4c1c12, + 0x00ce2ee7, 0xa5322a78, 0x32f8ed03, 0xc700bf1d, 0xae38046f, 0x3f18fbe7, + 0x463792be, 0x6079be37, 0xb37c6eb9, 0x38a7c74c, 0x5df829b9, 0x63853e3e, + 0x233f2116, 0x95f1c5df, 0xfc704b81, 0xeb949906, 0x8f74b7c6, 0x7771821f, + 0x437e31f5, 0xfafd58de, 0xd7ea5607, 0xbff5b32f, 0x8f9bbc10, 0xfff5c16f, + 0xd6cddc82, 0x6c47f03f, 0xafda26fd, 0x37477c76, 0xf700c3fc, 0x5fc07dfd, + 0x7e9b7a19, 0xf5aa83fd, 0xf1b137eb, 0xc83e0d5f, 0xf8e1b7c7, 0xd90791af, + 0xc52d07fa, 0x3aa64df1, 0x991693b7, 0x21752c72, 0xfd176bc0, 0x074d3a5f, + 0x45be71d3, 0x422482d3, 0x901ffb68, 0xc5870881, 0xa850df16, 0xf142c97f, + 0x0be316cd, 0x0052b424, 0x38e5afba, 0xa977773d, 0x326d24fc, 0x4bf185b7, + 0x10e9f942, 0x96cebf3a, 0x4fbd2f4f, 0x47773be7, 0x42e0dba1, 0x6ed0247a, + 0xdf8a5f1e, 0x8841e0c0, 0x1daa7b37, 0x7b3793f8, 0xf22c70da, 0x40599f00, + 0xf03d8e70, 0xf1a35e78, 0xbe86bb4c, 0xe7d06c16, 0xbcfa422b, 0x80f1ef3a, + 0x160d3424, 0x3a3afc93, 0x8fca19ee, 0x1f93e508, 0xe9047e52, 0x08792359, + 0x94d38dce, 0x4b59115f, 0x5f70cb57, 0xfe0c48ce, 0x91583667, 0x7dad2f1e, + 0x60832658, 0x640a563e, 0xf24178cd, 0xff9d3e76, 0x089d7c3d, 0x57e022e7, + 0xb4f73d6c, 0x47a14cd6, 0xb2779d2c, 0x31a75dae, 0xf5be0462, 0x963d0920, + 0x7b2ffb41, 0x87d18f62, 0x4fd3c7fc, 0xfd26ba44, 0xf7d74a44, 0xd87e34ce, + 0x733769ae, 0x3f635aef, 0xd3e7de9a, 0xae559f7f, 0x431a77cf, 0xe5ce1146, + 0xa36c810a, 0xa7583ffd, 0xf9c7572f, 0x7db1248c, 0x43dde3e6, 0x049992d7, + 0xfe91fa59, 0xeb64e7db, 0x497ae7a0, 0xca1f383f, 0x9a4ef704, 0x8dea107f, + 0x4b7c7d84, 0xe7b3ef86, 0x90d7ba25, 0x5225f39e, 0x9273f606, 0x25271b9f, + 0x08b753e3, 0x7edfe73d, 0x4711ead8, 0xfc475cf4, 0x4e221fbc, 0x968787dc, + 0x0697bfe8, 0xf0c7d7e3, 0x3e32dfc0, 0x7be6b4f9, 0xe4aef84d, 0xa97c1ad3, + 0xcbaa9e6a, 0xd3ee8457, 0xa1b05fd5, 0xaf3e5754, 0x5e5742b1, 0x2eb0f0d6, + 0x447c1a5f, 0x25a1ff57, 0x0fe574cb, 0x95d6add6, 0xab5f2acf, 0xdbe7dfcb, + 0xef7faba8, 0x72ba6dcc, 0x0e4570e1, 0xd97e37c8, 0xe1499397, 0x135de17e, + 0xf0c42ed9, 0x73f3c558, 0xcf4c0c81, 0x2e985c07, 0xf4a57a03, 0xa9641e2f, + 0x0e697b7f, 0xf78ab9d0, 0xd9758d67, 0xf8f12740, 0xf18f4f1d, 0x03780c78, + 0xe75f50e7, 0xbc40b579, 0x025df740, 0xefd48f3b, 0x97fce67f, 0x6f48e590, + 0xc7a332d5, 0x8b3397ea, 0xe5aa5e81, 0xad9d5e48, 0x58497eef, 0xb21075c0, + 0x08a9fb1d, 0xedd0aa51, 0x3cdd20eb, 0x70188e3b, 0x3e105afc, 0xdef3816e, + 0xf8c02a5b, 0xa7b23791, 0x78f9870f, 0x25be60e6, 0x4762f915, 0x69f25260, + 0xc5e7e009, 0x26605cf4, 0x3e0267a6, 0xca074f4c, 0x5030fd31, 0x607b6987, + 0x0327a609, 0x14ff4c41, 0xbdf4c068, 0x7fa62340, 0xf4c06c0c, 0x4c21033f, + 0x4c1e033b, 0x14d4f1bb, 0x90f903cd, 0x20226fbc, 0x2e1492e2, 0x3372a97f, + 0x5c85f961, 0x2e0bee6e, 0x27defbf1, 0xbc5048fc, 0x2c59beda, 0xa8e83f6c, + 0xf3a50893, 0xbbf6c335, 0x44bcb0e7, 0xdd843f90, 0xbbb2f95a, 0xf483d85f, + 0x9fc7ef6b, 0xf381dce1, 0x9e030def, 0x8af2247f, 0x0b5dba7b, 0xc047ba0f, + 0x86b75e6f, 0xd5fe5276, 0x7c31705f, 0x2e5c06b9, 0x039cf5be, 0x0cc2e8f8, + 0xe6fa79d1, 0x1357d7be, 0x34da75ce, 0xe8b7f1f3, 0x851b17f3, 0x741e4c49, + 0x0e18cc25, 0x9e74e0f8, 0x96fb0c1e, 0xcfdaa981, 0x79d90cc2, 0x85ea193a, + 0x77643d70, 0xd517e222, 0x3fdeb047, 0xf57d1e7b, 0x5ec79b13, 0x47b68a72, + 0xdf507b19, 0x0bc4fbf5, 0xe41933e9, 0xbc6ad268, 0x85aae704, 0x40e5f7fe, + 0xbcc257e8, 0x6c3fafda, 0x826e9a08, 0xe375bbef, 0x552e76d1, 0x7d7683d7, + 0xce449fe3, 0x5941f8a8, 0x6fae09d2, 0x9d9b3556, 0xa89d7e7a, 0x325bfbcb, + 0x0dfe3a9d, 0x4af4a0ff, 0x9c120a26, 0x2b1cd5bb, 0x835b24ba, 0x1bb7e740, + 0x8bee86f0, 0x6af5605f, 0x47d97694, 0x67dc2d3f, 0xe17df3c7, 0x05efae5a, + 0x9fb41b49, 0x70778633, 0xd34ace85, 0x449ce51f, 0x9e32f9a4, 0x39aef553, + 0x7cf0ab7b, 0x94126fff, 0xc8ff3ce1, 0xe70458d0, 0x9b786553, 0x76fba1ec, + 0x80938881, 0xbf205cef, 0x91acdc77, 0x3208afe3, 0x41acb7ae, 0x79516e7f, + 0xf2a79747, 0x9f3f2e8e, 0x3d034b4c, 0x91937e6a, 0xff285e8a, 0x043bcae8, + 0x80bbf627, 0xfe04add4, 0xcdef6a7e, 0x700adcf7, 0xc8a5b03c, 0x6873f347, + 0xbf4a3f71, 0x6427cd95, 0x3aaf93a0, 0x1fb4057e, 0x755c73d9, 0x51f43d5d, + 0x669a870e, 0x85ea13c1, 0xa6459b9f, 0x9f74a9d7, 0x72753a25, 0x7e5c5e5b, + 0xf6fe5c64, 0xc6d7fcb8, 0x908a149f, 0xdefdb169, 0x44f2f82d, 0x478043e0, + 0xf9bc3109, 0xf467fdda, 0x3fe47fe8, 0x44feffb5, 0xffb4ff87, 0xfda9ffdb, + 0xff31ee0f, 0x5ff5bdc9, 0x149e8a6b, 0xdd7b1ce0, 0xe198e78c, 0x7a0839b0, + 0x19ab7f82, 0xf637dcf5, 0xd01775fd, 0x26b3e75d, 0x8e7a6262, 0x93bff280, + 0xdf767bf5, 0x0ffeb75f, 0x8d0b3f2d, 0xb60b7f69, 0xef80fad2, 0x64c8adbb, + 0x184e5eba, 0x2f5d2841, 0xefd1fd78, 0x2e2f2a11, 0x91dee2b0, 0x0f4cbf05, + 0x51fb00ad, 0x799fcb2a, 0x08284071, 0xed979e76, 0x1808c311, 0xa3ed40f7, + 0xad2fee30, 0xa42d1e84, 0xd61375f3, 0xa305fceb, 0x2ee78a7f, 0x24415e9d, + 0xe77e3757, 0xb5241c02, 0xe052f85c, 0xf0e22840, 0xd55ef4a1, 0x8f31e092, + 0xfbeaf800, 0x2e8c60b9, 0x0eff2376, 0x5bc88966, 0x77205922, 0xcb53d7c7, + 0x5540e2fd, 0xb6ec581e, 0xfd53eac5, 0x37cb3e79, 0xa0fd3166, 0x052feb0d, + 0x958d49fa, 0xd597ecf7, 0xcec891ff, 0xac3f58db, 0x53d72d7d, 0x1572e9e3, + 0xe6aacba7, 0xa6f6862f, 0x7f32f55f, 0xa65fbefc, 0xafdd0582, 0x10e6cbe0, + 0x23b5616c, 0x6bef7a82, 0x6d511edc, 0x9e1ea089, 0x3905c7c5, 0x6944f20f, + 0x8ced097f, 0xf404cc07, 0xedd79add, 0x9adfd81e, 0xf33d7ffd, 0x63bdfa33, + 0xf80dd59f, 0x0ffaf350, 0x4c6bdf71, 0xdd02d991, 0x2a1ee8bf, 0x1dfad2ff, + 0x4d9d7e7b, 0xc61d3f68, 0x55d27648, 0x613565ec, 0xcafc9c53, 0xe03e7de6, + 0x98f2019e, 0x3b5447ca, 0x53fb7c5a, 0x45cff162, 0x4417970a, 0x7c88b34f, + 0xa9df6f4b, 0x5d39525c, 0xfdabde7b, 0xbecc4a54, 0xc43f7ea4, 0x1ba87be1, + 0x2e935fce, 0xf2e83d6d, 0x02ebcc10, 0xf3834b69, 0x13f9b6a8, 0x4aed4419, + 0x2e813590, 0xbee032df, 0xa12b9b10, 0x4d4df937, 0x4cc605cf, 0x75de5097, + 0xfedfea63, 0xc28b2381, 0x4f86fe7f, 0xe91ce1b2, 0x199e643a, 0x7f39fd42, + 0xbf1834ba, 0xa0f5dca3, 0x51eb8ac1, 0xe3a4abc7, 0xf5b10bd5, 0x755c6b5f, + 0xaefc753c, 0xcfac9f8d, 0x69f8e174, 0xb8fc7e30, 0x5c753b6a, 0xde7c572a, + 0xd886978d, 0x414b96fe, 0x72c3ce19, 0x947ee122, 0x14797a93, 0xcd8841d2, + 0x74ed4977, 0x97ca9f90, 0x4a5d3edc, 0xf900f366, 0x6901e60d, 0x5ef1c6d7, + 0xfb7fa380, 0x3a520554, 0x305f5c0f, 0x221a16d3, 0x3ca0f9b0, 0x7d414c1f, + 0x777be257, 0xe9fdf026, 0x17b87f4c, 0xb81d39fb, 0xf1c6f313, 0x1437c875, + 0x85a988d2, 0x1ffd3184, 0x8f9c46f1, 0x90238a8d, 0x98f81aa7, 0x0e11c359, + 0xb6245979, 0xe913f87e, 0xcdbf2b38, 0x572ddad7, 0x30e1c53d, 0x580679c5, + 0xbe47d066, 0x08ae5da4, 0xa3f364cc, 0xbe5128f8, 0x517f84e5, 0xc79d3a78, + 0x103826ff, 0x4a7ad9ef, 0x5d056848, 0x7c73248f, 0xbe184c99, 0x5e265c34, + 0xdd3c1d8d, 0x090ef8c0, 0xe83e411e, 0x5fc1fde0, 0x9451e694, 0x245655a7, + 0x7802df64, 0x089270e1, 0x91b7638c, 0xd8047588, 0x5af3a551, 0x1b79c1f9, + 0xa8ecebcd, 0x3a78f2fa, 0xb14bed53, 0x7e70db71, 0xe2cfdfb4, 0xae2cfdfa, + 0xd6aecfdf, 0xbf270aaf, 0x740bddb2, 0x87c058fc, 0xa78ea6fb, 0x7c28f1f0, + 0x113f51f2, 0x429dee2d, 0xd616ae0c, 0x22633d15, 0xc0337fb8, 0xf4e14ce8, + 0xe8e1c278, 0xb29050a3, 0xd7fe0081, 0xfd353b73, 0xed34daf3, 0x7a415388, + 0x99c7cd5e, 0xa1fc6061, 0x9ecff39e, 0xee78cdf5, 0xee6fa8f7, 0xf7a5beab, + 0xe6bef6fa, 0x3e75ed63, 0xd55f955f, 0xff5ffebe, 0xf869711e, 0x52829396, + 0x30ccaf2f, 0x126b7ed0, 0x1dbdfccf, 0x0f5144bf, 0xf7ebfa51, 0x4af802cb, + 0x5832c7f1, 0xa056ddff, 0xf05ee7df, 0xd74996c5, 0x63af9331, 0x14e97366, + 0x86264738, 0x526496a6, 0x5abfbf3c, 0x17709b70, 0xbce8ffe9, 0xbaf3e3ee, + 0x3a4051bf, 0x21917fb8, 0x6ec5eae4, 0x41fe0b35, 0x09d567cb, 0xd3d088a1, + 0x1b4b057e, 0x3e760696, 0x3b4f6e36, 0xeaf1045c, 0x6cde3e21, 0x0c1a4a42, + 0x845bed3d, 0xef2957e3, 0x35dede27, 0x2ed1b887, 0xffcf2f16, 0xe463e419, + 0x91b921c7, 0x46c1afee, 0x31e416f1, 0xfe8dc583, 0x3037fe90, 0xdc2159fd, + 0x2e5047ce, 0xa4040722, 0x573e8bfb, 0xec55d242, 0x33025b30, 0x62f0ced1, + 0xd9a60360, 0xce043c8b, 0x412f6961, 0xa05b7f79, 0xdf0fbf1c, 0xd1942edb, + 0x176ce4bc, 0x6774d3e6, 0x1f7e0960, 0x3fafaf58, 0x644baf7c, 0xd4225cf5, + 0xc3e0367b, 0xea05cf7a, 0x7cf5bed0, 0x3ff301a0, 0xcd31040f, 0x95f3626b, + 0x2fe82a96, 0x11a045fc, 0x18fed1eb, 0x41427aff, 0x2f7c3cfe, 0x79b797ab, + 0x2dd6084c, 0x777e7939, 0x197fe639, 0x377f6108, 0xb5fde0ec, 0xb30b9412, + 0xb3afdd17, 0xce96b863, 0x030fc9d1, 0xe5752beb, 0x3f063aea, 0x6f5750b1, + 0x5890def8, 0xfdf30056, 0xe4bbee91, 0xffe0890c, 0x5cbcdfcb, 0x3b0dcfd7, + 0x15eae8d6, 0xae89feec, 0x4ddec47c, 0x75bbbcba, 0xeeaf2ebb, 0xca65f54f, + 0x5679e9d8, 0x4205f975, 0x2fdb3f28, 0xf4375e79, 0x075cb722, 0x76bca05e, + 0x69f87c2d, 0x5c7083c0, 0x4840f545, 0xb3fcb833, 0x3493ec1a, 0x27d838ff, + 0xecc82fd1, 0x3b734f54, 0x3e40dad5, 0xe0267f7e, 0xc0bafcc6, 0x0c6fcc18, + 0xcffcc24c, 0xdfcc5e02, 0x09bf3123, 0xf00da9e0, 0xda3359f4, 0xe9671087, + 0x525b5d7f, 0x923f2043, 0x32f1c68c, 0xa2e637e4, 0x3f709a5d, 0xb3a70543, + 0x955687b3, 0x7122a6ac, 0x288beb55, 0x9939511f, 0x4e9adc80, 0xefd6bd79, + 0x037f2d77, 0xfef58395, 0x0721b987, 0x258aadf0, 0x0a29c993, 0xcfcda3ef, + 0xfae9da39, 0x432c762b, 0x3abcbb7d, 0x6d20bb28, 0xd3fd067e, 0x0dc4d5e5, + 0xb6e547c7, 0x4b9eff6d, 0x99f55dc7, 0x0f80da40, 0x0107214b, 0x91b376bf, + 0xde58ae72, 0x009cfcdc, 0xd93b34f3, 0xee9d98be, 0x0a79e208, 0xc5710f71, + 0x519cdaf0, 0x7f6e7e87, 0xe825f47a, 0x3c87dcdf, 0x2ee92bfb, 0xe50d1a41, + 0x8a30c46d, 0xf7d80cd1, 0x78582f1f, 0xe791ec04, 0x80b7201f, 0x6bf1e73f, + 0xe74ecbcc, 0x4eeded05, 0x93bb0b06, 0xf36393fb, 0x1d96ff42, 0x9b1b95e6, + 0xe5e89d97, 0x52bccd62, 0x772854a4, 0x4ece780a, 0xf04f1824, 0x79fa6df4, + 0xb2f30d3d, 0x44af3df5, 0xebc02f3a, 0xc4af0e44, 0xfd42f09e, 0x5e0e3134, + 0x6bc37d89, 0x912bcc28, 0xf4230578, 0xebc18333, 0x79fa2999, 0x780d733d, + 0x4179d2a5, 0xaf0e54fb, 0xc2f09ed4, 0xbc1c6a7c, 0xd786fb52, 0xd2979858, + 0x0df1d45f, 0x8e8b60cb, 0xefc0d82f, 0xfb5729a7, 0xd2ca8c73, 0xfddf4f7d, + 0x005150b0, 0xdd40d3f2, 0x3789a4f7, 0x5329f2e8, 0x4ffaea46, 0x9756319b, + 0x58a078cf, 0x3b9acf97, 0x7fbed759, 0x795d34f5, 0x191103fa, 0xcb9a8bf4, + 0xd6f9e3db, 0x7c2f523d, 0x0728cbab, 0x35d7cec1, 0x4163c99c, 0xbd63ca81, + 0x3e8baff0, 0x5b17db86, 0xff436f87, 0x39789fea, 0x1fb40bc7, 0xe0f03d83, + 0x55f7f450, 0x13ddfa73, 0xf3be4668, 0x7c8c204a, 0x6fb71f68, 0x8738801d, + 0x0381823c, 0xd378df68, 0x82788215, 0x19e6dfea, 0xfceb3ce0, 0xfc13329d, + 0x8be69dae, 0xefc8230e, 0x3771d452, 0xa94107cd, 0x8905b881, 0x1f6dea4c, + 0xb7f38dff, 0x9ecf07e5, 0x1d2f7e84, 0xb44cbb34, 0x56af09df, 0xf9a7643c, + 0xdd98f7da, 0xfbfe2fa4, 0x63f7c92b, 0x97e62706, 0x93f97da9, 0x5f8e8411, + 0x00d13bb8, 0x180aa7fc, 0x07f82a44, 0x1f41b3db, 0x05ec791a, 0xfd47fc1d, + 0xfedd65f6, 0x230b1e14, 0x43f752df, 0x7ee84f3d, 0x8538c034, 0x56e3e07d, + 0xe225db89, 0x067f74f9, 0xa7c0b3af, 0xbfe59569, 0x9697eca3, 0xda6cdfcf, + 0xbf9ceb0e, 0xe071d961, 0x1cb767cb, 0x0bbefe38, 0xdbe3a1a7, 0xb9435f54, + 0xe7f36bf0, 0x53dcf07f, 0xbd7e22f1, 0x119b9755, 0x70f9dd2e, 0xbdcef6ef, + 0x7b53d312, 0x57b7d3c2, 0x18587f42, 0x2eaa8ee3, 0x7bdf84bf, 0xd42eb1ca, + 0xd539172f, 0xfdc9b5f9, 0x601d0f80, 0x8545d97e, 0x2fc812e1, 0xbdd1317a, + 0xf95faa02, 0x46834bf2, 0xda345ece, 0x2af0be93, 0xddea91f6, 0xc5ea1226, + 0x4625d23e, 0x48d2996b, 0x578a50e5, 0x2768965d, 0xf5477fe4, 0x986349fa, + 0x12e20abd, 0x62daa59a, 0xbf36ac69, 0xfaca58b0, 0x4d42faea, 0xdfc7c7eb, + 0x817d3127, 0x427f07ea, 0xf5e814f8, 0xe84f5506, 0xae703d6b, 0x0cec3ea3, + 0xbbaf5af7, 0x728d75dc, 0xd2e51ae5, 0x45ffca35, 0xcf29f7e3, 0x55ea66bf, + 0xe058bf9e, 0xd03e074a, 0x76098f45, 0xe064468e, 0x2d0d555f, 0x1adf3f0c, + 0x8ff9009d, 0x7d5abeb9, 0x72f8c439, 0x5cd79588, 0x788108a6, 0xd426e2ca, + 0x49163f7e, 0xe17c6f79, 0x1fd32356, 0x20ff5a6b, 0x73cf80bb, 0x7ce1a93a, + 0x4532e6a4, 0x695f4a28, 0x1bd61346, 0xfe233466, 0xef491915, 0xad8d9f72, + 0x8027e54f, 0xce4fc093, 0x3cc5cc6e, 0xf5f227e5, 0x8e1a93f0, 0x9f955f67, + 0x02f30adc, 0xf3da54bc, 0xf7905e30, 0xdaeebf13, 0xa9c20746, 0xfe80ce9b, + 0xed7e066f, 0x02a63429, 0xf71809dd, 0x4262dd58, 0xa356e439, 0x5eebed8b, + 0xbeac4fe6, 0x03f18bbc, 0x17d38d89, 0x538fc7be, 0xe3a2d8d5, 0x16f83d4b, + 0xff8c578f, 0xf1919f7e, 0xe2848bef, 0xfc4f4147, 0xafa2f150, 0x5b2e6b7e, + 0xdee8f374, 0x767deeef, 0xc6c73ee0, 0x953c7053, 0xa470aa1f, 0x38dbb9f0, + 0x627c27ba, 0x38412970, 0x48fb7276, 0xc98d5f3c, 0xc55edc0f, 0x81e3d9f9, + 0xb5adde3f, 0x38fb5af7, 0x387156c7, 0xd1040eac, 0xf51d242e, 0x5aaec138, + 0x6f07766f, 0x49f0c437, 0xa164d8e6, 0x9d035e62, 0x849525a7, 0x16a6d196, + 0xe7f02b98, 0x2af8825c, 0xfe1d24d9, 0xaf3429c8, 0x288db7e3, 0x13069b27, + 0xe957f001, 0x615f2faf, 0x6b3af164, 0x4b3bb7f2, 0x927fbce9, 0xb820fbff, + 0x6d601dd2, 0xebfda033, 0x63bfaea2, 0xca64dcd2, 0xfcf8132f, 0x72d1b79c, + 0xc1e6f8cd, 0xade4014e, 0x76fa89a4, 0x0cb070f1, 0x8abfeba6, 0x1c524cdd, + 0x20a197e8, 0xc2317662, 0x612230e5, 0x272ae8dc, 0xadcb47e3, 0x95d7a40e, + 0x63ee2239, 0xadb7b713, 0xc81b3b07, 0xfc848a52, 0xeac894cb, 0xb44109cb, + 0x4ec199a3, 0x8a7d806b, 0xda4ede60, 0xeb009f31, 0xb8f2041e, 0x4c9fd70b, + 0x6f412b22, 0xbedf1aef, 0x164fbe18, 0xfe02cf7d, 0x3b6cca5c, 0xd53d8029, + 0xf40a1beb, 0x2c10c1be, 0xcffad174, 0x5085a21a, 0xfd169b2f, 0x39a58931, + 0xd3e4d710, 0xff987ff8, 0xf437963b, 0x912ce7cc, 0x5721fce2, 0x5fcb6a86, + 0x012f3d10, 0x129ca79d, 0xba909e50, 0x09bd4de3, 0x2bf70f10, 0xb1878f23, + 0x2fe93d31, 0x8f4cb9ad, 0xeac721ed, 0xf70537f9, 0x79ba63f4, 0x63f2e3b9, + 0xd8d31fa6, 0x2797fdc3, 0x0ec1f8ea, 0x1d8d03a0, 0x11e4b07d, 0xa4355fc1, + 0xcabf7e91, 0x6dd6bf7e, 0x601a0cbf, 0xf8f1f77e, 0xb3d5220b, 0x22f78f3c, + 0xff744bb0, 0x6cd455df, 0x593bcb3d, 0xf9873fce, 0xc0f9baf3, 0xec045361, + 0xce1eef7b, 0xdcfb062c, 0x51e8c66b, 0x3ff5c82b, 0xfdcdf260, 0x5a331cef, + 0xedefba69, 0x4b9076ed, 0x9cfa724f, 0xd846a24d, 0x0f8f1f47, 0xaafaed53, + 0x55ca8c5d, 0x0f9be046, 0x7f774244, 0x3c1ee697, 0x1c2efa16, 0x8adfb397, + 0x9ad80afe, 0xb12cec2f, 0x16bb4d12, 0x679671f7, 0x45eb34ed, 0x57ad8e7c, + 0xd668f5c1, 0x5b15fb8b, 0x50f082af, 0xfc19fbd7, 0x787ce69f, 0x14fbe8db, + 0xdd7e33f0, 0x5b344ad5, 0xfbf8881a, 0x5a9bc057, 0x8d272f83, 0x00c2e3ae, + 0x5854d0df, 0xf2325b4f, 0x6ff8bebf, 0xf466fc77, 0xcdb71606, 0xf386a7f1, + 0x86fb15fb, 0xe11d8026, 0x220daffc, 0x21e7ddc8, 0xbf7e921e, 0x81343cd8, + 0x73bec55c, 0x2e75db8e, 0xe8095d3a, 0x911d094f, 0xbec00b4b, 0x539e4471, + 0x9a9eb3d0, 0x91ed0f2f, 0xb20ed14b, 0xa2388647, 0x1af71e1a, 0x993f7fdf, + 0x6379c1d1, 0x20e804b8, 0x04e0a2fa, 0xeed55eff, 0x5ed1c73d, 0x247123b2, + 0x710d2f8b, 0x08db473f, 0x908a9fd8, 0x146f1f41, 0x91057266, 0xb0cc46da, + 0x8f52e16b, 0x63fd34ed, 0xed57dcfc, 0x31496cbf, 0xbb720539, 0xfa0f1cec, + 0xc32b7043, 0x1e89b2cf, 0x33f69d83, 0x7f4041b6, 0xdba72de5, 0xaca98e31, + 0xbf409129, 0x472c8f65, 0x9b6d533f, 0xf81da5ab, 0x0f704864, 0x794fe021, + 0x14c7f0b8, 0xb28eeb1e, 0xc3fc807d, 0xb8f32fe8, 0x6fbb1a6c, 0xd0aeb187, + 0xa0f0f409, 0x5cf203cd, 0xbbcf0ce9, 0x205957e0, 0xfe008e45, 0x7d2ceba8, + 0x0e0635c0, 0xd9b0d285, 0x2442a983, 0xa56be50b, 0x4d205112, 0x86648997, + 0xffcfeb7c, 0x6c289cc2, 0xa216e9bd, 0xfebfefb0, 0x8de1e01b, 0x8edeb2cd, + 0x6fe7d619, 0x0be7d16a, 0xcdfcfa23, 0x4ff3e96f, 0xf74941c0, 0x0c2fb5f7, + 0x37f088c4, 0x47fe0085, 0x8588990f, 0x97eaabae, 0x2703d466, 0x9cf0d954, + 0x7305f8f8, 0xde47f208, 0xec08b57b, 0xb4bf954b, 0x6f01b8b3, 0xaf2825f8, + 0x811fa97a, 0x0dff7273, 0x8cb7b544, 0xff64b900, 0x3ed80ddf, 0x9fed3cfa, + 0xe0f8ffd6, 0x947a5fcf, 0xf9f8ffb6, 0x1210497e, 0xdf87d594, 0xef59aabb, + 0x41ba1e1f, 0x2161ff3f, 0x664abe7d, 0x2f0bfafa, 0x187e2ac8, 0xdba5df18, + 0x17f5c695, 0x907f9697, 0x6e20fd45, 0x8182e400, 0x4455efb1, 0xbf46afd3, + 0xe1e9c89f, 0x019dc05c, 0xc88a63e7, 0x85cfeae2, 0x7a0348de, 0x1bc768fa, + 0xe74f4069, 0x4fd04b03, 0x6767bd55, 0xd5e79c12, 0xf0e1bfcf, 0xaedf7a40, + 0xdc82c6a7, 0x0c21bcf4, 0xd3dfa0f3, 0xf8477be0, 0xf4598e57, 0xc91db9fb, + 0xd17def88, 0x30a8457b, 0x7c0e7b43, 0x8ee87c55, 0x383272a3, 0x9de3181c, + 0x0fba5dfe, 0x780d9b55, 0x7c2aa65f, 0x038677f7, 0xa2366c1d, 0x8f7aabdd, + 0xbe3ea091, 0x7bb456ed, 0x813eed55, 0x8dfec771, 0x5e5718a5, 0x61af1124, + 0x664cba24, 0x75ae7a40, 0xb7ec039f, 0x926e7f55, 0xefc81725, 0x78a3fdfa, + 0x548c7180, 0x069a28f2, 0xb2cf494e, 0xa9bff022, 0x57ae7bdf, 0x5f7e3edf, + 0x78d5915e, 0xddaf9225, 0xc97af8df, 0x37688253, 0x5cb25ea9, 0x7d500f17, + 0xfe0651ba, 0x4a0e3f1a, 0xfa739a90, 0x017f0835, 0xeb917f3a, 0x51ce5439, + 0xc3cfa2e8, 0x3cb106bf, 0x80952b9c, 0x1bfeb047, 0x851744c8, 0x3234d547, + 0x032cd209, 0xe42c7bc1, 0xefefe615, 0x7a0473a0, 0x237dd8e8, 0x84bab7da, + 0xc33f5df6, 0xb7c8edfe, 0x07119c3a, 0xb6544dc4, 0xe2ee319a, 0xf2320be3, + 0x37e1658d, 0xdc6f101c, 0x145992f1, 0xf1f5b0a9, 0x8362e49e, 0x37e7f003, + 0x4e19aecc, 0x571d962e, 0x7b9a2fd1, 0x00f8b78f, 0xafcf49fe, 0x273d94ff, + 0x7d678064, 0xe98b9e32, 0xbd8575c9, 0xedaafdc5, 0x42bae452, 0xb3d3c817, + 0x5aefdc6d, 0x72f80b9f, 0x06e197d1, 0x6054a979, 0xf4480efd, 0xed7e849e, + 0x924bd6cc, 0x076c32de, 0x70653a7c, 0xf852762f, 0x945e25cd, 0xf28ee60b, + 0xa48740c9, 0x96fdc59e, 0x51222449, 0xf80cb039, 0xa3cc08ea, 0x59b65efc, + 0xb9a2f8c0, 0xe775184f, 0x69e1c400, 0x1a4e57d7, 0x124adfb1, 0xb37cb4c6, + 0xf802bcbe, 0xa5578534, 0x95e0fcc2, 0xf0718c3b, 0x5a3ea089, 0x930bfbbd, + 0xfd751c76, 0xfaea217f, 0xd1e5973c, 0xfd45fd4c, 0xf70129be, 0xd8c8ffd9, + 0xe65f380c, 0xf8e0f699, 0x985cfc55, 0x7e58ea4f, 0xa00c8922, 0xeba3cfe3, + 0x9e607382, 0x918e8242, 0x92309f2c, 0xdf93c7ad, 0x0eb03d73, 0x36f277ed, + 0x56aaafdb, 0xd61c3221, 0xf20de743, 0x5b47ac37, 0xb3af9aaf, 0xaefd377a, + 0x7690ffb5, 0xf7bb5fac, 0x5fae930b, 0xe7a0cf6e, 0x7dd33110, 0x37cdd758, + 0x71b4c343, 0xe1bdaa23, 0xbac78724, 0x0267e7bb, 0x720d3dbd, 0xd8071658, + 0x8127aa18, 0x032c676f, 0xb7c742ac, 0xc79ddcdc, 0x2ce5a2f2, 0x76b4c83f, + 0x54fe86c2, 0x32fa310f, 0x3329ae41, 0x68438f78, 0x37c54ece, 0x29c744d4, + 0x12d93d93, 0x1e4f75f2, 0xb09659da, 0x6474fff5, 0x5ebab0dd, 0xbf7518e4, + 0x08e10bd6, 0x641d43c6, 0xbd7c41f2, 0x4fc62671, 0x1fb68e12, 0xdd173e07, + 0x5a11e547, 0xc1f0a36f, 0x6de3b071, 0x5645cbbc, 0xdd067cd0, 0x1b77e01f, + 0x502f5205, 0x4bda8cb8, 0xa3d01be5, 0xd4378ef7, 0x4cdd70d8, 0x6dd6b06e, + 0xfa47fb03, 0x0123f943, 0xb930ef5f, 0xdd741e70, 0xe5a34d0f, 0xb983cb19, + 0x384bff60, 0x0ede6a1a, 0x8b70efe7, 0xa74bc61b, 0x6127b1b0, 0x7fe700da, + 0x023c2906, 0xc5319574, 0x88ec1235, 0xffac1ceb, 0xd0f0d154, 0x46539054, + 0x28d27cb2, 0xfb8ed9e2, 0x49c716b3, 0x30499137, 0xf20ef83f, 0xb3d6ed17, + 0xc4349107, 0x5d4275f6, 0x3e9f8c21, 0x7064a588, 0x8bcbca06, 0x9eaa7cb8, + 0xf7f59f6f, 0xea3f0024, 0x3f01f7e2, 0x201279b3, 0x1b1c8c8e, 0x9fed6a26, + 0x0345fd6a, 0xdf50e93c, 0xc124597f, 0x287fe464, 0x5e67fa5f, 0xff857b42, + 0x1a824cb2, 0x9cbfec3e, 0xd777cfa4, 0xb1f6c34b, 0x4a12167a, 0x839eadee, + 0x11fd7484, 0x7f2d7f7d, 0xec24f5e5, 0x77698c8f, 0xe9d91c80, 0xdb3e476a, + 0x46831215, 0x1174f7aa, 0x9dc1f182, 0x6d5df64e, 0x265339df, 0xa2679411, + 0x40474fd8, 0xb2630881, 0xf413f5a9, 0x1eb7561f, 0x35ef8129, 0x7ce30da4, + 0x1256c26b, 0xdbffc5ec, 0x970b0011, 0x3f29fce6, 0xfdd4ed8a, 0x9037b588, + 0xb38fd690, 0x52222da2, 0xeab75a5a, 0xc00a2bd7, 0xd3947704, 0x2b37f04d, + 0x72d1b73c, 0x23a3a883, 0xba6ea8eb, 0x275f3242, 0x061d181a, 0xe262bb7f, + 0xaf3c9a6d, 0xf83edddf, 0x291309bb, 0x602a8ddd, 0xf55d9fed, 0x972c6fef, + 0xae807c62, 0xd76bdb3f, 0xbcb895e4, 0x6b87e68d, 0xf2b8cef2, 0x8cf2b894, + 0x567f7cb8, 0xc91ec3bf, 0x1ca9b836, 0x13f7eab7, 0x3a4fca24, 0xa9b32332, + 0x309e4f04, 0x226133bc, 0x6a8f8dc4, 0x5a79c0f3, 0x59b82adb, 0x5f830fb8, + 0xb9e19bad, 0x832eddcd, 0xaa3adf7f, 0x7688b8ed, 0x7209c12a, 0x27bc2da6, + 0xe7687982, 0x330bb4d2, 0xfc3aa4fd, 0xb3ebb601, 0xe9117cff, 0x87fe4d7c, + 0x765aef58, 0x8faf9274, 0x6e2bef83, 0x3be0b770, 0x92bd026a, 0x77bf9144, + 0x992ff9ec, 0x7c633fdd, 0xf3d333ab, 0x43adf206, 0xb7cb5382, 0xa41f30fc, + 0x0e5c65e7, 0x935c7062, 0xb886517f, 0xb787f78d, 0xa9c703be, 0xcb27d175, + 0x73fb1e40, 0x20d1d9cd, 0x1f2d809f, 0x217af4f8, 0xd6f18664, 0x7861a18b, + 0xc866adff, 0x7a05d111, 0xf016fb7c, 0x75574417, 0xda4ffc22, 0x284007db, + 0x9755c5fb, 0x7db53e59, 0x5dc7ec0b, 0x009b7f0d, 0x0e4f1ef7, 0xd2201f68, + 0x8355a5fc, 0x487e6227, 0xf7c816fb, 0x3f2c1c53, 0x81807dbc, 0x0921cfb6, + 0x76ff6113, 0x8abf193a, 0x3967bfe7, 0xf7e755ff, 0x29cf7f4e, 0x66a90b80, + 0x1c0b7dfc, 0xed9f94cf, 0x73b538ec, 0x9d9fdd17, 0x9fc8cc4b, 0x10bc6429, + 0xe1ce938f, 0xf20ee78c, 0x8df50953, 0x926b384c, 0xcf68fb62, 0x7f21736e, + 0x0f6ea1be, 0xb3e9d79c, 0xff3f900b, 0xac99ec87, 0xfdd2c6a4, 0xfad29a36, + 0xe3271593, 0xed1106a7, 0xda8fe99e, 0xda78fe51, 0x0561d6cc, 0x1b534afe, + 0x7c2b8fdf, 0x4c4c571d, 0xdf24b91f, 0xdacdfd81, 0x950cf946, 0x240966db, + 0x309c80a8, 0x81394655, 0x3341a3aa, 0xdc5537cd, 0xddd27180, 0x335ad2fa, + 0xd0a9bfce, 0x26760993, 0x9a693f55, 0xd44cc9ea, 0xdb4d65c8, 0x67cab958, + 0x5e69729b, 0x12102e73, 0xad9779c6, 0xbb424dcf, 0xf3eec4bc, 0x743b5fac, + 0x573c1afb, 0x9b3ae1a7, 0x68664312, 0x2fffc2a7, 0xf0c93dfd, 0xbef57efd, + 0x7507df28, 0xd30ac9dc, 0xec0cca87, 0xf1527e3c, 0x44cb3ae1, 0x39a208cf, + 0x4d03279f, 0xa448e068, 0xfdf0d1f6, 0x8c7843ff, 0xa3fdf586, 0xf1daf8f0, + 0x84fc71c5, 0xa0bb8df2, 0x67259aff, 0xf30cdc79, 0x5df0a9bf, 0xe98c442f, + 0x77b06f8c, 0xd077e804, 0x3e4c0abb, 0xe753b42f, 0x1ad1fb3d, 0xf5d4d794, + 0x60787f58, 0x9d99dc12, 0xc5fe795d, 0xecfdb49d, 0xf775591f, 0xa4be5581, + 0xae46bde2, 0x11eec618, 0x4fbb29ab, 0xe80a7208, 0x3aeaed77, 0xc4264f24, + 0x18afaf8b, 0x609e8228, 0x828ff805, 0xb7432efb, 0x9c18132f, 0x9caa9e60, + 0x08bb8843, 0x2953b3d6, 0xf97d86ae, 0xa05e2952, 0xf071b2a4, 0xa75e097c, + 0x03d78dfd, 0x7aeae779, 0xfc72610d, 0xefa604a6, 0xd0f10249, 0x8dffcdf9, + 0x811adb71, 0x13e21f03, 0xb0bb30b6, 0xc357972a, 0x79f74ee9, 0xe7e3973e, + 0xc17e3973, 0x1deea306, 0x3e908a82, 0xbcd89a4f, 0x523eb9aa, 0x9fb0da45, + 0xbd7d66aa, 0xd82faa6a, 0x83bf701d, 0x8690f1ca, 0xf9eae5f5, 0xc2f96fe1, + 0xa0f77fa4, 0xa361f711, 0x09f1c999, 0x8fb93d23, 0xb5fc7f01, 0xffcde511, + 0xc2a2fbe6, 0xf1624061, 0x8b5f00c3, 0x9ff84441, 0xec394916, 0x95c0676f, + 0x93307831, 0x02f5a76f, 0x9aaf35bf, 0x361f01cb, 0xffcea22b, 0x64628f78, + 0xcce5c37e, 0x4fbd1e9e, 0xc8133b46, 0xffbd5ac1, 0xe7d54539, 0x10ff72d7, + 0x129a33d3, 0xa9bedc99, 0xe9077049, 0x2b4d277c, 0x5ff800af, 0xc021699c, + 0x3d72e76a, 0x746a42f3, 0xfaadc031, 0x76bb4bbe, 0x7c37d011, 0x74be022f, + 0xc7ecd18a, 0x967fd172, 0x0fb3fe00, 0x7cef8c43, 0xfdc0eb48, 0x9dab6098, + 0x4f1355c5, 0xefda3ce6, 0x6ee9d5a9, 0xe3533b88, 0x641d4e49, 0x46f5cbfe, + 0xf3dc096f, 0xfa63ee0d, 0x574687c3, 0xeb23dc36, 0xd011caf2, 0xd744cbbb, + 0x7b2025d6, 0xaaf6b61d, 0x5a9ff85f, 0xfeae7180, 0x23dfa5ca, 0xfdd3d157, + 0xbd3d7a2d, 0x61b34493, 0x07ca9b5d, 0xfc742386, 0x6e61d6ce, 0x40cad666, + 0x93ad4be3, 0xd54d3dd5, 0x7187bc3a, 0xbdf088c8, 0xff91fede, 0xf0fc7ed1, + 0x684bf06f, 0xef681fed, 0x7a43dbd0, 0xfabed9e6, 0x7e674d5f, 0xeff2b892, + 0xb093becb, 0xf93fb50f, 0x0825c9eb, 0x37d228d7, 0x3e7a6469, 0xa144779d, + 0xb46f4fed, 0xdda77f23, 0xf9fdbde1, 0xbe053654, 0xd194b393, 0xf486f55b, + 0x4837606d, 0x57eac89c, 0x768a186f, 0xfedcb184, 0xea40df3b, 0x133ba015, + 0xa1390069, 0x696ae4cc, 0x9c63c4d7, 0x5bd267b9, 0xbcb45f40, 0x0dabca1e, + 0x82fcdeec, 0x8da2b6b6, 0xecc22f30, 0x02cde5c3, 0x78c53881, 0xdad115fb, + 0x3560a889, 0x80cdbc36, 0x55d83f4a, 0x55df63f2, 0xbf79ee3a, 0x3d26efe5, + 0xbf2a82dc, 0x7abd31f1, 0x9ff83a70, 0x901c7a54, 0x48cc95e8, 0xe074ae07, + 0x3e0c67a7, 0xe02c97b4, 0xb82b1bf7, 0x478eaf9e, 0x3be30df9, 0x281fb70a, + 0x2d70aecc, 0x47daa3fe, 0x0f403b54, 0xf294b3be, 0xf37d119d, 0x0aea421d, + 0x80f84ed1, 0xd2740dcd, 0xfe70ff83, 0xba53eea6, 0xd8d0f8cc, 0xd10321a5, + 0x6497b9c8, 0xcd3697cf, 0xa3ffe2b9, 0x826eb8a2, 0xb40c97bc, 0xbe365c81, + 0xf70a91d2, 0xcebf98dc, 0xdb3c46da, 0x662df7e8, 0xfed02f2a, 0x90b871ee, + 0x0cc8647f, 0x97928c0f, 0xa2f2d214, 0xfb9436e2, 0x09c4a9a3, 0xc6decefc, + 0xa762dffa, 0x3b4246ed, 0xdbba77c6, 0xa2dea42b, 0x2afc5f69, 0xe9725fbb, + 0xdfed1da0, 0x734b1297, 0xbe748f80, 0xa77e476a, 0xba53bbfa, 0x8958d5df, + 0x1e1db9eb, 0xd5854a45, 0x3d03f715, 0xfb93088b, 0xd86277b1, 0xf46358b9, + 0xe9ff00e5, 0x9644d778, 0xe08b7ed3, 0xbc54a231, 0xef0257b7, 0x2ebed536, + 0xca486400, 0x8216772b, 0x5864d91d, 0xf7428f74, 0x34b0c4a7, 0x576d08fa, + 0x04e6c033, 0x9cc4c293, 0x7de7fd3f, 0x5ed1ff34, 0xaba7de23, 0x266139d8, + 0xa2fad1d8, 0xa2fbf8ff, 0x7975bf74, 0xbcbabfba, 0xbf9f45bf, 0x814f6cd7, + 0x36942cfb, 0xd8cf70dd, 0xb73baa64, 0xf4d7ce8d, 0x354dc99a, 0xd9b37211, + 0xe81980f7, 0x071e8c5d, 0x3a729978, 0xe17c8046, 0xc044fd6f, 0x559250f7, + 0x072f80ff, 0x9992e7e8, 0xf3efb3c1, 0x9eec289b, 0x6967551d, 0xc36d94da, + 0x597a68fd, 0x6f8c0908, 0x045d194f, 0xf7e130e7, 0x97183c4f, 0x265367e5, + 0x4cfefc4d, 0x68437ed3, 0xded79c19, 0x5c27bc72, 0x856bcf4b, 0xb87177e6, + 0x8b47d557, 0x53445ee0, 0x3061a4d2, 0xc90be92f, 0x0abbfb0b, 0x17c8d13a, + 0x3fe2cdcb, 0x115a3f76, 0x2d89efe2, 0x7b873a07, 0xf8e9e39b, 0x0cf8bee3, + 0xe8532ee3, 0xc9cfc030, 0xee376656, 0xfda21652, 0x43ae6fda, 0x44b8d5bf, + 0x60b5d709, 0xa0242d80, 0x9f20991d, 0x3932260c, 0xcb41611a, 0xffb986cf, + 0x0b4e0e3a, 0x9ab930b6, 0xbbe033ec, 0xc1400b31, 0xd5fbb902, 0x700f18a9, + 0xc9a7f376, 0x5b6e01e3, 0xbb0270ef, 0xccbdf5a2, 0x8369e78f, 0xada4bbf7, + 0xbd0172df, 0x6262db1f, 0x765448f3, 0xfb8f7ec1, 0x837280c2, 0xc81f1224, + 0x67b24d0d, 0x6b91d018, 0x8012cef3, 0x59a9d9eb, 0x517fd622, 0x37184e20, + 0x7c1a4971, 0x5e48205f, 0xfdfa3f46, 0xa26bf753, 0x05c99939, 0x7f782b86, + 0x4db4d8fa, 0x3e3dcf18, 0xc6f7f367, 0x8d3b7f42, 0xd2846f78, 0x3e703dc7, + 0xc0f5d0d4, 0xbcb66a7c, 0xb38cc693, 0x628a4484, 0xa3fcdbef, 0xaab26074, + 0x07975c78, 0xf2c16c7c, 0x3bed3cba, 0x78f03d1e, 0x1b9ba533, 0x166078a9, + 0xaf2097c8, 0x35ea4ff7, 0x1e5e293e, 0xc54af555, 0x6d3b3c4d, 0x08f3d768, + 0x329d3f94, 0x4e47c84b, 0x27ac6599, 0xf3616dfd, 0x3f105cef, 0xd02dfbeb, + 0x60f10e5f, 0xea2b853c, 0x0ee2a62c, 0x69cf0080, 0x9fc599b2, 0xf51f73d1, + 0x44a9f5a0, 0xffd1aef7, 0x3a51fde5, 0xb2f0077e, 0xc72bddf3, 0xd9b5ae01, + 0x8f40231d, 0x0cfe5ff0, 0x56b65eed, 0xb9b4f766, 0x0d9e64bd, 0x992a7be8, + 0x83e3105b, 0xcfe3377e, 0xd1baebf1, 0x63f16462, 0xc7ec5129, 0xd7f4656a, + 0x4df6f5c4, 0xf7a82c4b, 0x99094a6d, 0x955fd261, 0x573f54ce, 0x2a63b705, + 0x7b415e3b, 0x4e09090e, 0x2e296bf0, 0xe55d2746, 0x3fcf11b3, 0x882831da, + 0xd1e3bdf9, 0xf1db65af, 0x8040c35c, 0x83f30b53, 0x0eeddcd9, 0x3b47df58, + 0x7d60394e, 0xb80c3be5, 0x27d0f2ee, 0x620af369, 0xf049bd74, 0xfaf3c15d, + 0x46b59d0a, 0xc768fb4f, 0x6d7369a7, 0x730a4f4c, 0x706f417b, 0x2f1952f9, + 0xc65c2858, 0x751d9839, 0xf7c453dc, 0x386de232, 0x4f6f6b5b, 0x6af3b0b5, + 0x0dc9859c, 0x7ad0d6e3, 0x7c618788, 0x1ebe29cf, 0x57a32079, 0xf8fc6d3b, + 0xb4441be7, 0x26ac56a3, 0xff3d6768, 0xf46c81fc, 0x903cee6b, 0x5f53473d, + 0x6f8c3f8d, 0xf1616d9f, 0xa7f1a41f, 0xe20d251e, 0x7378d83d, 0x2007cabc, + 0x3b86909f, 0x1e38fa3c, 0xbd4d130a, 0xa7c40dae, 0xefd58a0c, 0x01dcff2a, + 0x5a736a71, 0xb413110d, 0xa70678f7, 0xebcbbc80, 0x2f77f7c7, 0x45a123c7, + 0x5ac93d40, 0xfa3e4510, 0x1134f9b5, 0x4d3e5a6c, 0xe324f7f7, 0xf0e3d1d3, + 0x19d813ee, 0x6b933ce1, 0xf5c8126d, 0x5e182b69, 0xa2207f45, 0xc435ddfc, + 0xf9522f52, 0xb0cace45, 0xb14aff01, 0x01acb8b0, 0xbf58f959, 0x1a679efb, + 0x4999e7bb, 0x8a7e30ea, 0x1f51db38, 0x38863fee, 0x580d0e41, 0x41911c98, + 0x830c1bdc, 0x7a3c9820, 0xf10151ea, 0x8e7c03c4, 0xa9ea0a88, 0x3f185f14, + 0xfa33e477, 0xf952f0e6, 0xa02ad0a8, 0x92db371c, 0x862bf5c8, 0xa3c2d757, + 0x3c62ffd9, 0x778ea05a, 0x12e478bd, 0x5be1f5c8, 0x1fc2761f, 0x845fb828, + 0xf0a771fb, 0x3628a67e, 0xb880af7c, 0xf1dd1d8d, 0xcd9fb464, 0xfd04de54, + 0xf62bb541, 0x62ea515b, 0x76b6e07e, 0xdface790, 0x7c5cf052, 0x05cb6c5c, + 0xcede3a79, 0x11367748, 0x533801ce, 0x1f94bd61, 0x5797fb30, 0x9d71fbc6, + 0xe21b8f01, 0x44880607, 0xcfdf3e02, 0x35ef8b90, 0xdd380bf6, 0x59dc182b, + 0xbb1e631c, 0xb12b5c0f, 0x075942fb, 0x1772c912, 0x5f4cc7c8, 0xcb8eface, + 0x78b52e0d, 0x225346ff, 0x7ea987b3, 0x69ecbef7, 0x9f4f41a4, 0xcbad5daa, + 0x537e174e, 0x0659ce0c, 0x85049f3e, 0x41ee4fdf, 0x35c00ae7, 0xff510c6d, + 0x4b3e4036, 0x14fe37cd, 0xae957bcf, 0xbd9d7b55, 0x736b9bc0, 0x7abb9213, + 0x8be031dd, 0xb8e7efd7, 0xfdd5e57f, 0x025dff1c, 0x9e7a0e7e, 0xb4c39776, + 0xe6ab39e9, 0xae12203d, 0x21cac7b2, 0x11695ece, 0x2575fb78, 0xde5c4877, + 0x3ee7f1c2, 0x3caaef06, 0xf1ba266d, 0xe293f3b4, 0x629087fa, 0xdfad4b9b, + 0x5bfa1138, 0x83e79237, 0x5f83d41f, 0xbea369e7, 0x6f29043f, 0x029a990f, + 0xc9f07fd6, 0x1a9fc741, 0xe1ef3b1c, 0xa97807fc, 0xf7aafee7, 0x44de34a6, + 0x3f3ab2c7, 0xf50778c5, 0xf4a7f6fc, 0x24e22f7e, 0xff5fe3e7, 0x761e841d, + 0x261693ca, 0xc90096df, 0xf9003d51, 0x17a97fb2, 0x9ca825e3, 0xb7cc21f1, + 0x338eddf3, 0xe7796847, 0xf78fcfb4, 0x7d6e3c03, 0x31e83678, 0xfa03b7e0, + 0x501b37f1, 0x055a55ce, 0x462d6f86, 0x7f1517a4, 0x7f1c9d2a, 0x7f788312, + 0x3090e9b0, 0x5445ec1a, 0x9bbecd3f, 0xd5b165ee, 0x31c70173, 0x533fdfea, + 0xeccad953, 0xe2fcfe56, 0xffd0798d, 0xf9c0810e, 0xc3ff26bf, 0xbfa8b9b4, + 0x4f36907c, 0x65a2aed3, 0x691f8b1d, 0x470af636, 0xfa606ad9, 0x1e7dc1dc, + 0x43e70be0, 0xca4b1618, 0x906ad0a5, 0x45cbcb57, 0x8546efd4, 0xbe43ef4a, + 0x2026533d, 0x5c587787, 0xd3cd1e6c, 0xe42f1083, 0xbf81ffa7, 0x7e77936a, + 0x3347ca29, 0xd5c41b15, 0xce2fcf9e, 0x5795fb44, 0x061c0276, 0x926537bc, + 0x149ef80b, 0xadb4b8c6, 0x2091b6b5, 0x83efadd7, 0x63693ecf, 0x782f5cfb, + 0x7e67df83, 0x5bb5a271, 0xf930b4e5, 0xe4cac32e, 0x867bf541, 0xb79dc995, + 0x0026db05, 0xda961c3a, 0xfaf720ad, 0xd013e789, 0xe6d7894b, 0x0f7089da, + 0x129ddea3, 0x4d3da170, 0xfc7f6949, 0x4dbf2826, 0x223b38c2, 0xe3033fb5, + 0x894eae76, 0xfc850bdd, 0x6f680523, 0x1beacc7b, 0x14e3a562, 0xf3b27971, + 0x10859de0, 0xe1ce38d7, 0xe824c9fa, 0xed0973e7, 0x8a9ee33a, 0xf8004db6, + 0xd9903e7d, 0x08e895b9, 0x9376b9ed, 0x9e93ad95, 0x92ef286f, 0xfbf237c3, + 0x1d9eb40a, 0x5a16f1ba, 0xb8de4153, 0xfd18f458, 0x24694c6c, 0x7d549f80, + 0x9282bb40, 0x872025e2, 0x4a96084c, 0x271cb718, 0x71e04c87, 0xf4a4881d, + 0xfbc7317b, 0xe1777421, 0x558a2dfd, 0xc7265ff5, 0xaeb792e4, 0xa3e090cc, + 0x8a88af2a, 0x1399ed0f, 0xc6085a67, 0x1e8cafd3, 0x9e2ec117, 0x0a7af942, + 0xf160cbde, 0xb32ff9a2, 0x466120fb, 0x3ffeddb7, 0xa8fd1da9, 0x7e56ad93, + 0xfc33d7ae, 0xb7186d21, 0xb0900940, 0xd6cf68fd, 0xfd5057de, 0xf27f6a86, + 0xad8f6672, 0x7c17f6e1, 0xdf9696f9, 0xb2ed556d, 0x467e75cb, 0xf0bedc75, + 0xc6aac2ab, 0x804b4453, 0xd507a31e, 0x4a4f8a78, 0x8cfa2f00, 0x5778e0a7, + 0x78f572db, 0xd195bf0a, 0x4f1d37c9, 0x913588f1, 0x11f44bc5, 0x471f114f, + 0x911999d1, 0xda4b5ed0, 0x7d04eeb7, 0x7e84c5bc, 0x6f2d29db, 0xcbce11fe, + 0x43090a29, 0x5cbc56dc, 0x5f4d35e1, 0x75def80e, 0xc056cce1, 0xef7775c3, + 0xb03f3377, 0xd7885e5e, 0x7cabb60f, 0x1b73cb97, 0x1fa7d7ad, 0x29bef5a8, + 0xcbe54eb9, 0x5187ae7e, 0xb9c072fa, 0x23d383b3, 0xd1c41250, 0xdd6dcbc5, + 0x1c9c7ef2, 0xd19eff11, 0x9d6f69a4, 0x61a47bc1, 0xa87100b3, 0xde0919af, + 0x63ee0dd3, 0x85b56dfa, 0xc3ea93f1, 0x2ca9fdec, 0xe3ed1793, 0xf22315e4, + 0xf9e57f0d, 0xfd114497, 0xdc00af04, 0x27e5a653, 0x5faefd40, 0xd50e901b, + 0x85b690f7, 0x2a74fc98, 0x94c88c5f, 0x79c1b7ce, 0xa13ce30c, 0x3d741bf7, + 0x31f18fd9, 0x5ae837ee, 0x9706fccd, 0x6033e3cc, 0x330ecaf3, 0xb7197ffb, + 0xf14aafff, 0xae8332fd, 0xc64ff16b, 0x1e75dda3, 0xd65a61f1, 0xc71bb7a0, + 0xbfccbdec, 0x78af0554, 0xcc05fbb3, 0x8fb1a7df, 0xae523bc1, 0xce18a906, + 0x5ce25ca5, 0x15d97c0e, 0x16fdd0a4, 0xbbf9eb4d, 0x802882c3, 0x4ead213c, + 0xac7ec0b1, 0x012717aa, 0x45eb05bd, 0x5bb88f7c, 0xd7e7e00e, 0x29ffce25, + 0x8e3042c8, 0x77f3d69a, 0x96fed57b, 0xa9023111, 0x9574b028, 0xdbd49a53, + 0x57f6a8b9, 0xc653ac6f, 0x4034be83, 0x25ecbb44, 0xe01333d9, 0x8f29297a, + 0xbd645c40, 0x1261aebd, 0xbf1c472b, 0xb17a8e64, 0x1312dbfc, 0x092b88d8, + 0xfcdbd9f8, 0xdb878edc, 0x3838c6bc, 0xe3f3d9c6, 0x88cb3ee3, 0xa0e6686f, + 0x6f92719e, 0x69733e73, 0xbfbf2e4d, 0xaeaee0c0, 0x067f597f, 0x4b007137, + 0x9e280e07, 0x303ffb09, 0xa04d8651, 0xd223b329, 0x07fce095, 0xef053b7e, + 0xb7cfc513, 0xc023841e, 0xbdecd5ab, 0xff3aaf8f, 0xddff79f8, 0xcce9c69a, + 0x5f780193, 0x3df194e6, 0x17d96baf, 0x705cb972, 0xd6a1fe2d, 0x07f806fb, + 0x1b578bd3, 0x13adbc78, 0x97bc08f9, 0x04a77f08, 0x9e08aef7, 0x79d5a1df, + 0x06d5aeb0, 0xc27e1f7c, 0xef9e1b74, 0xfbd987b5, 0xdb4b3576, 0xad9ce1b3, + 0xf7c76e2d, 0x0de1e36b, 0xfe5495b3, 0x49cdeb43, 0x1c6ef821, 0x79fbd069, + 0x3cb3fa7a, 0xd3e03645, 0x37aec8c6, 0x654338e9, 0xd7c858df, 0x02ee8d2e, + 0x91e3b579, 0x5e404af7, 0xd26f539b, 0x2792a7c5, 0xd2227ef4, 0x65768490, + 0x5effa4d2, 0x5dae39be, 0x2351bf0f, 0xd97ae3e2, 0x7be80c37, 0xd3f9839c, + 0xef88a549, 0x01db75fc, 0xe1ce1a9e, 0xeed3cee7, 0xee7d03ef, 0xef67ad2f, + 0xf77aef59, 0x2fec02f7, 0xbe6ad7dd, 0x7df617bf, 0xb7f60f2b, 0xf2b7cf63, + 0x1bd77f60, 0x3f403d1b, 0x0f9f153b, 0xefa73cfc, 0xa39ca2f0, 0x0b5c45c6, + 0x275d172f, 0xe6fa2e5e, 0xe7aaf2f0, 0xcaa6c05a, 0x5ced5f49, 0x9ead3f83, + 0x218af87d, 0x34bf4668, 0x3d98ffc3, 0xf077fcec, 0x0a2cb95c, 0xabe8f7e0, + 0xae5c51bf, 0x104850cc, 0xc54513ec, 0xe8aed8ed, 0xdc809173, 0xf179caa4, + 0x9f09f870, 0x4f36f3ff, 0x5f879c02, 0xce5aeed7, 0x4fa128eb, 0x43b9fc99, + 0x6bbb3370, 0x1dd5c598, 0x9d82752a, 0xd9885cf5, 0xb1f76b5d, 0x422bea77, + 0x5df0446f, 0x09c156f3, 0x8ec541fa, 0xeef01c0f, 0xae4e2690, 0x448ce819, + 0x9deceff5, 0x40729d0b, 0xb79d1bbc, 0x6b78e415, 0x7a06544a, 0xf1172da8, + 0x295ab3dd, 0xb5bcf18a, 0x241dc429, 0xf5ea5f20, 0x6c2e352d, 0xba465793, + 0xdecad4d9, 0x7d934ca1, 0x0f11fdb9, 0x6dfbe3fb, 0xb7edfd2a, 0xf800fe79, + 0x7ad3f31b, 0x8b576c5a, 0xc32ff91b, 0x617fe636, 0xccd97fe5, 0x6e3502e4, + 0xce8ff544, 0xf3eef1e7, 0xf83bbc79, 0xf81a236d, 0x9b56df82, 0xd5b6fd57, + 0x88322f10, 0xe5b56df9, 0x8d687edd, 0xae5b56df, 0xe889178d, 0x93234df8, + 0x310b0d77, 0x25d2864e, 0x579163c6, 0x88ced505, 0x74a7e9f4, 0x0c6464b0, + 0xf0fdd57f, 0x12b87f97, 0x3cfcf3e2, 0xf01ab2ee, 0x61c60477, 0x5fc04c46, + 0x355f14c3, 0x4b6a2efc, 0x7d7374e4, 0x37e8c8f6, 0xedf1df4c, 0xe3c7573f, + 0xb3aead74, 0x02ad5d7b, 0x75b8c3a3, 0xf189ebc5, 0xcf5569f6, 0x4bdf16bb, + 0xdf1f5fb6, 0xabfdeb53, 0xfdb65ef9, 0xbef7c39f, 0x47fffb29, 0x3034c6ae, + 0xe87b3e05, 0xd083df87, 0xad8312a4, 0x4c9477fb, 0xae3fe1d7, 0x437062d9, + 0x21cd4ddc, 0xaaf21bbb, 0x7fde323f, 0x94f64958, 0xfde3c800, 0x5710d588, + 0xfedae831, 0xb77b62c4, 0xfb573d5f, 0xb151785e, 0x61bf5f9e, 0xa7d934fb, + 0x02e2d3c1, 0x82f7e02a, 0x24148ab7, 0xa9f638da, 0x7eb7e676, 0x9fefbf83, + 0x88069321, 0x6eda7893, 0x14467bc5, 0xa62e306b, 0x6e9dead8, 0x9afc0d1f, + 0x83d9efc1, 0x0b8812f7, 0xc618d67e, 0x1ac13efb, 0x5727de1b, 0xff6a23ed, + 0xa97ea96f, 0xcd73e06b, 0xcd73e275, 0xf1cf8c37, 0xe3ab17ed, 0x61dfaf5d, + 0x06918503, 0xb3f1e3df, 0xf17d76af, 0xef765581, 0x91d23b72, 0x5eb9ef07, + 0x11e8ff2f, 0xf1b92987, 0x4dc41d5e, 0xfc559c42, 0x74f7a87e, 0x6b70b954, + 0x97a1fb9f, 0xc57eb707, 0x3c96b8fd, 0x0de2a4f8, 0x8f4f7ac1, 0x3e81e4f7, + 0xeccecabb, 0x0ccd9b2e, 0x0c0b372f, 0x13e07b1f, 0xe2a3efbf, 0xf5fb01d5, + 0x7ad43bd9, 0x78fe6aff, 0x2d7c2ed4, 0x69fc077b, 0x886c90f1, 0x7d767be2, + 0xfe9ec7f2, 0x5977162e, 0x517a86dc, 0xef8090f4, 0xf6f3ab33, 0xd63b31b7, + 0xd45c39ef, 0x1cb8fbef, 0xfcf0e398, 0xf10a9ec1, 0x8f028a49, 0x59028c3b, + 0x2f28e40e, 0x0da9378b, 0xda8fb8b3, 0x70e304a5, 0xb511fbd4, 0xc809532d, + 0xbecd0b6d, 0x55fb433f, 0x8682d9ef, 0x4fa3b004, 0x75a72023, 0x37f2cbbe, + 0x401f7d9b, 0x3b697fb9, 0xa69bfdda, 0xa138c79d, 0x5d3f2fa2, 0x3a5df609, + 0xa40bb45f, 0xd3f7f498, 0xc7c60e1d, 0x50ead4d4, 0x7b41ebe1, 0xfb950778, + 0xa7f2de40, 0x5f609c78, 0x56cded50, 0xe1da1b57, 0x6732f76b, 0xad81915f, + 0x9fda3c87, 0x8ef6d1f9, 0xe415fc2f, 0x9042e6c3, 0xb7de8b57, 0xe3a8fda1, + 0x138c2c91, 0xbbeacc78, 0x1f6af80c, 0xe40bba15, 0x0e3a1ccb, 0x7b1dadc8, + 0x79842aee, 0xe0a17d77, 0xccecbaba, 0x24f5d0bf, 0xcaf88999, 0x665dd1ed, + 0x9f022786, 0x666ad76f, 0xba1e0a9f, 0xdd03bf91, 0x38368f6d, 0xd1ecc746, + 0xa5407cf1, 0x08fbeeff, 0x1ff414b3, 0xbd61fcab, 0xeaa39d91, 0xeece77f9, + 0x3c16f1e2, 0x2a75aeae, 0x79e0d78b, 0xf8554f1b, 0xe3bb6f3e, 0x9cf3ac1c, + 0xdec7fa5d, 0xe24cbec3, 0x2fd8e7fd, 0xe36939c4, 0xdfe0add5, 0x53897b01, + 0x37b2bc46, 0xa1dfe610, 0xf9f20578, 0x09b6d16d, 0x839d7409, 0x01b7229b, + 0x165f0fbc, 0x53a0bbd9, 0x92f78b7f, 0xde360413, 0x57da27a0, 0x8afb050f, + 0xc36fedf3, 0x9d1abad6, 0x5b92e0c5, 0x870ef668, 0xd52241b8, 0xc578c3e5, + 0x3c5918ef, 0xda2b21df, 0xabb29a09, 0xbb691273, 0x684cf7ce, 0x03e789af, + 0xcb241a6a, 0x606f8e31, 0x0ed01fcb, 0xe82bdf6f, 0x93a6a6e0, 0xf7e6361c, + 0x6095b609, 0x296dc9ac, 0x0e6e77ec, 0x7f041fbd, 0x5f1ab4bd, 0x46f52486, + 0x7572088f, 0x7b411970, 0xa72690e4, 0xc395fb08, 0x0eba44e3, 0x1f08cfff, + 0xddaa9f9e, 0x64a9843d, 0x7a095f6c, 0xfdacb495, 0xc7ec20f6, 0xb6b144de, + 0xd68bfa00, 0x12b27c32, 0x5a739f38, 0x95bf2d06, 0x9c1a73e6, 0x7aea3fe8, + 0x0de30ab5, 0x439d7483, 0xa167597a, 0xdce5c583, 0xa520e3c8, 0xfc115643, + 0xb85ad2d2, 0x5341440d, 0xd29671ef, 0x129c43f6, 0xc38e7de2, 0xd4f00b37, + 0x5902f9ca, 0x9c7f4162, 0x6d78625d, 0x8bdef25f, 0x55bfcf10, 0x1d4fef66, + 0x34e37c3d, 0x96addfb4, 0xc6ab5ed0, 0x74e02e51, 0x47de13dc, 0xe0725e31, + 0xbf303fa1, 0xfa0b1d0d, 0x3f0c8c97, 0xf829d5a4, 0xc87fe07e, 0xfd0b8c3e, + 0x80c47d76, 0xe9e728fe, 0xaeb92667, 0xebc4b7ad, 0x891ccb29, 0x622e295f, + 0x3d9be399, 0x3fdbe24f, 0x55f78eae, 0xd7a210f5, 0x63e87acf, 0x5c7572f1, + 0x0ee4befb, 0xf542ee35, 0x504f1177, 0xcc526f17, 0xbe8a21c7, 0xef0b6abf, + 0x50a3c78f, 0xf205c439, 0xd70ada4e, 0x8ebf8832, 0xdfa098fe, 0x09978d46, + 0x9738b316, 0xbde0a8a0, 0x88d20cab, 0x48fd3271, 0x1ed01044, 0xd3b6e2c6, + 0xb6865e21, 0x8818ef5b, 0xee216ffd, 0x41f20306, 0xa4abbe17, 0xfdd055c6, + 0xd3243a41, 0xc13f1e64, 0x566b37f0, 0x70e2085a, 0x9f7edcfd, 0x7f1f2b35, + 0x3f135567, 0x33feecc1, 0x7d4f882d, 0x10aa53de, 0xd6253df9, 0x1710d36f, + 0x4d7ff3de, 0x693e6bb5, 0xe2e3ed67, 0xaa38542c, 0xfc2a1671, 0xf14c7bd4, + 0x79314c70, 0x57bc02df, 0x7dd425e3, 0x0d8fdeee, 0x55d82ecc, 0x1cbbe221, + 0x155d7f6a, 0xdc83679f, 0x626adc50, 0xefd712f8, 0xaefbeea6, 0x67c63321, + 0x96bd7df3, 0xdfbeaa1c, 0x23bf9475, 0xd7bf8c75, 0xc21665de, 0x399f8006, + 0xc9381b3a, 0xee4784f6, 0x5d817b84, 0xdc3668f6, 0x78dcdc2b, 0xa7cc24ff, + 0xfe424f46, 0xc3ff84b5, 0x5ba243f2, 0x89e19ee1, 0x1e58b3a7, 0x908b2e70, + 0x49848e33, 0xe07f82c1, 0xe3d73a5c, 0x022e1a77, 0xfb486b1c, 0xd3b436ca, + 0x146973f0, 0xa26463e3, 0x44ecc429, 0x13ffdc2e, 0x631dec99, 0xbdc0fe5b, + 0xdfde506d, 0x5a2df684, 0x627bf88e, 0xee5678c8, 0xfa4dfb62, 0x029c59db, + 0x13d33dff, 0x1fd1e3b9, 0x4df8035e, 0x462b85e5, 0xc740989f, 0xe1b420bf, + 0xee27593b, 0xe00161f8, 0x8ffd85eb, 0xe2b9060e, 0x77f7b94e, 0x72731ee1, + 0x7ec8c239, 0xa34de5f7, 0xf9409acf, 0xb3ad1fc3, 0xff69124b, 0xcbc79333, + 0xe0ef3089, 0x51eef8f3, 0xc4bfdf2a, 0x4bee4c19, 0x2015e89c, 0x3363f17e, + 0x1f54b3a3, 0xe2063dfb, 0x3ddc219b, 0x12d7235c, 0xc4113bf6, 0x7b804ae7, + 0x68eff108, 0x6b5e12dc, 0xf7f73900, 0x780ce881, 0xfefd5552, 0x38f7a107, + 0xc604828b, 0x5c19a6c7, 0x141f01c3, 0x29cdf1b1, 0x2bc6c4b7, 0xfbf17048, + 0x70a375c5, 0x51ba86dc, 0x28f4c7a0, 0xd072d1b7, 0xe5a09e93, 0x97297bc3, + 0xd67afb78, 0x938ef35e, 0xa974e01b, 0x2fbc03f4, 0x04eb38b4, 0xc27647be, + 0x0ef03c48, 0xfb93304e, 0x0739e8f5, 0x273c7dfb, 0x3b4fc591, 0x40704c37, + 0xffdb107e, 0xfd0848bb, 0xb06653bc, 0x21df597b, 0xb4edf56d, 0xfa199dde, + 0xcbb963df, 0x277fcfa5, 0xc29f9f5f, 0xebbe07e3, 0x1eff7fd6, 0x0f804a89, + 0xffa31fdf, 0x441797dd, 0x0be0094f, 0x2f8c27e5, 0x2aee3c0a, 0xf9c20845, + 0x2c81e37e, 0xc61a9ef5, 0xf5c0bdb3, 0x7fbf3f11, 0x91aa6701, 0x8586e3ae, + 0x1bdc9dec, 0x93928833, 0xf92bfc04, 0xf07bbe08, 0xa729f711, 0xf4789bc0, + 0xd713a97b, 0xf419e2af, 0x1f7c3b75, 0xe2e0cf9d, 0xd2538321, 0x418eefd8, + 0x6b2309d9, 0x84b1fc1b, 0x7d684e7c, 0x3e2c6ff3, 0xf184bc62, 0xd7ab0277, + 0x4ff86665, 0xfefc524f, 0xe21ede53, 0x27c89caa, 0x4abfdc2d, 0x8be85df0, + 0x78d8d2a3, 0xfa8b0f1c, 0x5bc01629, 0x7cbb5df5, 0x1bf6e127, 0x7069a64a, + 0xe794103e, 0xfd54bc54, 0x3c380348, 0x7f327e28, 0x1f872671, 0x06f7f091, + 0xcfda8932, 0xadc61374, 0x04bafcf1, 0xde2a6f46, 0xb5ec7fae, 0x5f00a737, + 0xc03f5c12, 0x3bb2ee7e, 0x74f9bd61, 0x804999ac, 0x78d829bf, 0xf449e707, + 0x247927bb, 0x8c5d8798, 0xb09a1b18, 0xbf7f307c, 0x4fa4fa6c, 0xfe1a4866, + 0x61adfb45, 0xfdf55afd, 0x459ba3c2, 0x68337e9a, 0x7e9a49bf, 0xf2c2689f, + 0xbfe5fbbe, 0xe7e92147, 0xaf8fb6a7, 0xf3f5ea4f, 0x7c7dabec, 0x14f7f53d, + 0x4df87326, 0xf329e356, 0x640f71f5, 0x7e615b8c, 0xc39c7d6c, 0x8edf1c9b, + 0x306dff5b, 0x09250be8, 0x2844a70f, 0x1a524c3d, 0xf408dbeb, 0xd0fa461b, + 0x802ff5d0, 0x7e652e2e, 0xb6fbbf80, 0xd989e078, 0x97a519d0, 0x7ba309dd, + 0xe7c547ce, 0x3c5179ee, 0xf1543c06, 0xdd9e7e38, 0x30bdfc78, 0xa16d7206, + 0xaaa407f2, 0x9d48423c, 0x0d70eb80, 0x2283ad88, 0x87528961, 0x22b37ff3, + 0x33bdf388, 0xff8c19f1, 0x3be49319, 0x799af302, 0x3dec27d3, 0xa1d28c93, + 0xf9d10720, 0xfd484d1e, 0x355f377f, 0xe1dc796e, 0xbd82373b, 0xe3ee9bb4, + 0x5fed5ce8, 0xf234d395, 0x2af73b15, 0xf2be5545, 0x19642900, 0xe57cb832, + 0xacd678c2, 0xf10dcb80, 0x8af91aaa, 0x44d547c9, 0xeece07bd, 0xa060fced, + 0x987abe5e, 0xb76ebc60, 0x271a557c, 0xede3cd5f, 0xc42092a7, 0x93d936c5, + 0x805e2c42, 0x162d39ce, 0x8db4dbff, 0xb74d8dc9, 0x82419cb8, 0x33d31672, + 0xe87bf166, 0x6bde4cb9, 0x77c98fba, 0xbaea1ce3, 0x6b78fa2c, 0x133567ee, + 0xb8b12f2a, 0x99abb40c, 0xa5d97d9d, 0xb53576f4, 0xf202ffde, 0x007f0832, + 0x00007f08, 0x00088b1f, 0x00000000, 0x7de5ff00, 0xd5547c09, 0x73b9f8b9, + 0x64cacb67, 0x109848df, 0x424e3b08, 0x875b3612, 0xe22948b0, 0x3cb888b0, + 0x4240b21c, 0x3eb44196, 0xc33fedad, 0x0d220222, 0xc168d46d, 0x2a14180e, + 0x0431a0d8, 0xa4587049, 0x141a87d0, 0x2f1f682d, 0x48145840, 0xad88a0c6, + 0xbefbffcb, 0xef726e73, 0xf6b42264, 0xfa7fb6ff, 0xef7397b3, 0x6df3be59, + 0x39ce5be7, 0xd78deec3, 0x1ec658b1, 0xacc630b4, 0x98eb458c, 0xb19436b3, + 0x96eff0ef, 0x95e5e7ae, 0x6289e63a, 0xa31574ac, 0x47d7e5e7, 0x7a83cfa6, + 0x4c8c7697, 0x66e783cf, 0x92d433b3, 0x50e158cd, 0x2fa18a7b, 0x7b46f963, + 0x9b19933a, 0xbeb45e64, 0xcc9eba19, 0xd393f516, 0x5b09fb18, 0xcf074c74, + 0x48ce9151, 0xc8673fac, 0x287a2967, 0x0379f8b3, 0xfd8c611c, 0xc28f675e, + 0x19b98cf7, 0x718535c2, 0x4398a6b8, 0xf870f2bd, 0xa5c340f7, 0xfe8c8196, + 0x1c7183be, 0x4b6f6726, 0x1155630c, 0x67971fb5, 0xa35cf631, 0xe2b6e6c9, + 0xec1496d7, 0x11deb18f, 0x043086e7, 0x543ce185, 0x39e814f0, 0x4cb2d13c, + 0x040bf4f0, 0xc65e630f, 0x68e0ba72, 0x94ae8437, 0xb1e0a97a, 0x00d17eb3, + 0xc7be24a7, 0x06895ab1, 0x6a5383f3, 0x1257e3fc, 0x33d38fd4, 0x63265877, + 0xea97981b, 0x1ce75efd, 0xb3c6e381, 0xb8e1894a, 0x112b6c2b, 0x96e0dd4f, + 0xbf30c901, 0x1ec977d9, 0x0ae60c13, 0x7ace1f09, 0xd4fb3d61, 0xba7f1804, + 0x2af67f18, 0xac0884c7, 0x78e25d37, 0x00ffc2f0, 0xfbe219fe, 0xa9b2c6f4, + 0x3198e00c, 0x13ba70c1, 0xa66ff83e, 0x0181ba65, 0xc2a6b39c, 0x7bd7737b, + 0x61d2209c, 0x2cffd28e, 0x6c39bb6d, 0x387267cd, 0x10191696, 0xd5ee735f, + 0x09669f7e, 0x42173e8b, 0x077c076d, 0x60603af3, 0x79f68f34, 0xe609b3cc, + 0x82cc56f1, 0x3347f7f5, 0x43b7e036, 0x7fe86533, 0xcd716c62, 0xf4bf283a, + 0xbf2a60dc, 0x83cf7b15, 0xf3fbf147, 0xa09e54e9, 0x6e504683, 0xb3ce99ff, + 0x9cd01529, 0x5494d773, 0x9040ff18, 0x467ef7e8, 0x9d83e3ef, 0x5ea1d355, + 0x99bef0fc, 0x04d3e0cb, 0x0aede323, 0xde9ff7f9, 0x9ce54614, 0x191eacfb, + 0x6c109cba, 0x30f7d375, 0xaa09b6c9, 0xd130c91e, 0x53e361f7, 0xccbef7f9, + 0xe7df851e, 0x23fb5185, 0x0b5e2199, 0x47f2f78c, 0x01fbe883, 0x0eb9b3e9, + 0x595b5120, 0x52e91ea8, 0xe336689e, 0xc940c873, 0x3df0083b, 0x5f8c5221, + 0x353de7c6, 0xca226b73, 0xdf5c84cd, 0x6850c75c, 0x670e6897, 0xfe1f1137, + 0x8879f90c, 0x34aadc6d, 0x5f16afe4, 0x150f9a8a, 0xf8574f3a, 0xcf96826f, + 0xc51e7e40, 0xfa9f0af6, 0x87c2a7f3, 0xea0b3e1a, 0xb97f33e2, 0xd7009e57, + 0xb18f924a, 0x97721f20, 0xe38e747c, 0xe3fe2727, 0xf8bf24f6, 0xdca2c527, + 0xc2777f88, 0xd0f24b57, 0xb9e9b99b, 0xcb83e501, 0x8708b3cb, 0xc56cd751, + 0xdb247df7, 0x33c20b60, 0x0c7666ca, 0x0a372eeb, 0x783ac97c, 0x2e1dd991, + 0x3943d3fc, 0x45fe7589, 0xb8e0e747, 0xb3b43bfc, 0xb82ec8b3, 0xa4adfc60, + 0x7870569f, 0xb88b4836, 0xd09763bc, 0x5768b94f, 0x41b7ccae, 0x0678df3b, + 0x2ffa8778, 0xc4967ec4, 0xfe18dddb, 0x82b87995, 0x4f81ee41, 0x611d9966, + 0x1dd39846, 0xb724f911, 0xebf73277, 0xb38f8011, 0xc2136706, 0xae643c77, + 0xed7e1191, 0xf757a146, 0x74285f20, 0xc7f4e052, 0x7a0f794f, 0xfe1e7fcd, + 0x57a2e978, 0x133e0273, 0x2b2a22d8, 0x79e1bdf3, 0xae5e0ff6, 0x69bdf983, + 0x147c9df0, 0x6fcdebe4, 0xeb3736cc, 0x20cdf382, 0xbc3d12eb, 0xd992ff77, + 0xb3e00736, 0x051f8168, 0xb32e772e, 0xcebeb19b, 0x8a9659ec, 0xe06af674, + 0xcfe88fca, 0x7f174c58, 0x5eeb31c5, 0x2afb3154, 0x3d56b6ec, 0x57a487ad, + 0xcf50c2d8, 0xab9f6866, 0x99c4e5e7, 0x50a59eb1, 0xdce8f76e, 0x3c6f1806, + 0x347375e8, 0xefe74fbe, 0x38230b59, 0xc20b3147, 0x90011559, 0xbbaaf7c2, + 0xd1c03dd2, 0xd95bfeac, 0x7ddf041d, 0x0fa4c1c5, 0xc16032aa, 0x83efc2cb, + 0x896efbe9, 0xd62ee38f, 0xd355b8d1, 0xeaa8feb9, 0x53b8f16f, 0x54ceb271, + 0x8daaf7e4, 0xd04884f6, 0x5b328923, 0xa47a0b54, 0xf0ca152a, 0xeec65d8c, + 0xf4c47d43, 0xc3d3e1f6, 0x78fbf0ba, 0x11deb8d8, 0x84b71fc0, 0x96fe75f3, + 0x2af9ccb5, 0x29b563d6, 0xd57587d3, 0x00008a8b, 0xd4305eb0, 0x596efe83, + 0x6286f50d, 0xac2f507f, 0x83763d7b, 0x68a7c476, 0xac608c47, 0x9f11d858, + 0x8299dd6e, 0x9b27c476, 0xa9e4a677, 0xd8945fea, 0xbfd71c1c, 0xbc656f7d, + 0x66ec67ca, 0xa0926f18, 0xf98724fb, 0x50eb8494, 0xe77b44fc, 0x1a7c85fa, + 0x0235bf61, 0xef9061f5, 0xb47ba445, 0xf90e77d1, 0x6261bd8a, 0xa3ae199b, + 0x1a5d72be, 0xf7876faf, 0x1bc8efe5, 0xdb7e0357, 0xdbfe3862, 0xbe041976, + 0x2dff9e5b, 0x0c34af94, 0x3c61ab60, 0x0231bc17, 0xd71cbbff, 0x853d702a, + 0xbfce333f, 0x57112854, 0x55d98983, 0xfc1b60eb, 0xc5d99457, 0xd04ced2f, + 0xe88421b7, 0x1b372e5b, 0x75caff91, 0x70875d92, 0x59ec1c2c, 0xa7e97526, + 0xe8af4512, 0x132972d8, 0x262cede9, 0x9827bcbe, 0xfdf0966d, 0x80c5f4e9, + 0x9af352af, 0xa18f5c66, 0xd70901de, 0xb407a41c, 0x53ed885f, 0xbcb3e3bb, + 0xad54e00e, 0xb4dba5f7, 0xc6642f70, 0x0784efae, 0xd7cbc937, 0xc414e706, + 0xb730596b, 0xcd4b2e43, 0xf03f0839, 0xf017b79d, 0x2649afa9, 0xc0c426be, + 0xbe8a79f8, 0xdc7ce6a9, 0xb3c7d55e, 0x09e7be04, 0xca35e5ba, 0x0b3c135e, + 0x5a7bbce3, 0x2d4addb0, 0xfbc74b1d, 0x3952ea0e, 0x1ea38e1e, 0x4dc152af, + 0xa7054e7a, 0xa25cbddc, 0x7d45eef7, 0xc63f3fe0, 0xeba935be, 0x4ab689dd, + 0xe709f236, 0xf495667b, 0x0797d066, 0x4ca15d05, 0xe62499f3, 0xf5f23466, + 0x14ef9fdb, 0xd08eaefc, 0x8eba3971, 0xbe412dbc, 0xbcbeb98e, 0xb3fef529, + 0xdff56de4, 0x06ec6f29, 0x8267c1d7, 0xf8083b98, 0xd8ca5ab3, 0xfab27a8b, + 0x465b6636, 0x37ebb55f, 0x088673ac, 0xc035fd7c, 0x85987403, 0x9d7906ff, + 0xad3f7d1d, 0xfc97607b, 0x9cd9f516, 0x776ec201, 0x2424bb70, 0x9b19f38b, + 0x61fd3cc0, 0x1ca2610a, 0x23d9b932, 0x1eb91f03, 0x006765ce, 0xf8fb311f, + 0x32f5f2fb, 0xe51375d9, 0xa865d8bf, 0x659431db, 0x5cc80582, 0xd53f4417, + 0xa633f512, 0x24fee371, 0x6e4c4728, 0x7016464e, 0x6674bc3d, 0x9c0208eb, + 0xd058b1e8, 0xdfe1f163, 0x67c5bd50, 0x7d827979, 0x57942f60, 0x799921d7, + 0xa1c761a0, 0x2f2c7a99, 0x28b125d8, 0x104cf718, 0xd501a397, 0xc955663a, + 0x304f20e3, 0x75f8aab3, 0x4d4896c8, 0xa26d5879, 0x0d4dfea6, 0x33df357d, + 0xdf3583bc, 0xd4ca1c47, 0xc79bb394, 0x3c8fea68, 0x8f29ab9e, 0xa9a2996e, + 0x0cc2f63f, 0xbe47f94d, 0x99f535bb, 0x103cdedb, 0xe82050f0, 0x8a0ff8af, + 0x5ae5bafe, 0x2c3da69e, 0xe8095ec7, 0xb15fc85a, 0xc80b3582, 0x2d07193f, + 0xc896fdd4, 0x8da20e6b, 0xf5a95856, 0x6b54164f, 0x1b0dc5cb, 0x5609408d, + 0x2fbed1ec, 0x0f2da2d9, 0x43a79e88, 0x011b3abe, 0xf820c9fe, 0x428b1447, + 0x2ec9eff9, 0x44efa7f1, 0x00758fe1, 0x7e8098df, 0x33dface9, 0x7d234737, + 0xdf03cc0d, 0x7e05b03b, 0xf5c1be07, 0x03d0e3a3, 0x8523e43a, 0x3278fede, + 0x1ee96bc5, 0x3dd2d564, 0xee96a064, 0xdd2d3661, 0xd2d28d7b, 0xa5aec23d, + 0x2d64d47b, 0x5a1c63dd, 0xd1cdc7ba, 0xa9c13dd2, 0x91527ba5, 0x8bc9ee96, + 0xf3ef74b4, 0xa9ae96b0, 0xbe5a85ee, 0xc503e3f0, 0xb95b4b4e, 0x8e9eafd8, + 0xe0fcd4e9, 0x40ca9a28, 0xfcaff4cf, 0x7fffa6b9, 0x45a43f36, 0x92353f0a, + 0x7e477e45, 0x645fbd86, 0x46ff7776, 0x7f6a6bd1, 0x65d39f42, 0xefa4f67f, + 0xd3cbd9ba, 0x47a09c78, 0xdc9ad97b, 0xf5272f65, 0x982797cc, 0x4bd689bb, + 0xf08746b6, 0x70e165dd, 0xa357c15c, 0xd59bbb19, 0x13dfb01a, 0xc0146750, + 0x03e7027b, 0x9acbdfe3, 0xe65cfde9, 0x5993a7a3, 0x63ccf88c, 0x30167a36, + 0xe8a73d07, 0x1e22b79c, 0x392dcd4a, 0xceaf6fa8, 0x42527a3b, 0x21448ea0, + 0x2f23dfd0, 0x4ea75a6e, 0xd999cc57, 0xd6b18fda, 0xb44ce70a, 0x16e33ba7, + 0x568d6676, 0xbc6f2de1, 0x7a8f5034, 0xa1b60e56, 0xa777943d, 0xde6cf644, + 0x3739fc97, 0xfe43af92, 0x2b0f65cf, 0xfe14ab78, 0x1e43f707, 0xbb0ab48e, + 0xc943399e, 0x7059b3be, 0xb8fe805d, 0x9182ff3d, 0x82582eec, 0x2e80d7f5, + 0x4f4e24db, 0x4dda2ba4, 0x7cccf4c3, 0x9843ca0d, 0x27ccfc93, 0x7892a0f4, + 0x1fb1833f, 0xa0dbda17, 0x75234a02, 0x8e394e34, 0x3cd4f007, 0xaa20cccb, + 0xe98126ac, 0x9afb4207, 0xf12ca225, 0xbce1fe32, 0x454cdfc9, 0x4d2b6d78, + 0x4858af64, 0x4ccd923e, 0xe3dc91c4, 0x493ef0dc, 0xed090d06, 0xbfc01bd6, + 0x6b942488, 0x2198c3e6, 0xfaf99ce2, 0x934c157e, 0x51f8539d, 0x0a2f7c26, + 0x1dbfdeb4, 0x9595edc9, 0x40efc715, 0xcdef297a, 0x84b3377a, 0xf7825ea2, + 0xeb31b92a, 0xb0f11d99, 0x533dc2a2, 0xc8d9ff5d, 0xf1e7ea48, 0x4e2d8bde, + 0xdf723ef8, 0x720428a2, 0xd9739067, 0x10a1658f, 0xe9458962, 0x069ad46f, + 0x1ec3fb99, 0x919afd19, 0xd4e7f5c7, 0x2dd1a471, 0x0bd8f2da, 0x0f42b2da, + 0xc177f376, 0x82650728, 0x00f14caf, 0x195eaa97, 0x67c0f63a, 0x0fdcf165, + 0x84c1be63, 0x1b90a377, 0x0de49d53, 0xc130f902, 0x0a61925c, 0x9ccc0c2b, + 0xedeb7480, 0x6e5da0b4, 0xd0ebd44c, 0x2ff2603f, 0xf800ce6c, 0x78a69e53, + 0x7eb555fd, 0x17ea03f9, 0x48d86bb0, 0xdff11236, 0x41e02f09, 0x1a3a7802, + 0x46ae36e2, 0xcdcc9c78, 0x613603cb, 0xb3fea7b9, 0x7a59becd, 0x0b6cc110, + 0xbc3fc67f, 0x447e9674, 0xa3af7af7, 0x64e3075d, 0xd93db8eb, 0x8e5cde9d, + 0x6bb3e93a, 0x01646c81, 0xb0d553e8, 0x7fd4e3ff, 0x25793e9c, 0x51e22ba9, + 0x6fc092ee, 0xcd698787, 0xf8009612, 0xc75aac2e, 0x092e3f90, 0x8f325c38, + 0x24d7b1c3, 0xb5e8a7aa, 0x10022c97, 0x875a1af3, 0x62f04407, 0x0eb72f7a, + 0x6bd2f2e5, 0x2fae88bd, 0xf1474efe, 0xa3cc41b8, 0x610cf9c3, 0x8c3efa5e, + 0x26f950b5, 0x67281514, 0xdbf12b30, 0xbb23e608, 0x2b5cf411, 0xd972b9ea, + 0x2820bbf9, 0xbe764e5f, 0xe84e7a44, 0x4fc174fd, 0xaf7e8ae9, 0xddc7fbd6, + 0xf8a48d3e, 0xad0b6f4a, 0x54ce4223, 0x3af82674, 0x7f91448e, 0xe768e209, + 0x544db4e5, 0xc688303e, 0x587c1429, 0x8d88ec98, 0xc5ebd154, 0xf5336b8a, + 0x7802f92a, 0x5bbf28ec, 0x4d66822a, 0xa397bd50, 0x32071e38, 0xa18fd5df, + 0x2175f9ff, 0xe047b436, 0xf97ec68d, 0x4729c90f, 0x5b97bc01, 0x9a3af5ac, + 0xf50ea567, 0x24efd962, 0x33c01cf6, 0x66b97180, 0x7035e2fd, 0x9848a96d, + 0xf9f40135, 0x0fdc917b, 0x1c7cc971, 0xe28433b6, 0x8cc98531, 0x853f4385, + 0x7c91a7af, 0x0bd0c40d, 0xcc32b1c2, 0x8c2f7683, 0xdd95151b, 0xf1ff1e1d, + 0x35df43df, 0xb733f49b, 0x1ef543bf, 0xdd9973f4, 0x7bc7556e, 0x19bb0b56, + 0xe39213fc, 0x3b9fd160, 0x7aff7197, 0x84fb8f30, 0x296ae6b2, 0x62f5e7ad, + 0x9a651a20, 0x014c02f5, 0x36ce5718, 0x16ae5c93, 0x47acc472, 0xe18fe8ad, + 0x3a184673, 0x8f0e9cfd, 0x1cfbb187, 0x24fd7a2a, 0x3f0baf8a, 0x6a78e289, + 0x077b7337, 0x2a19f5e3, 0x31af387f, 0x251bec9f, 0xec2edfbe, 0x9503f6c9, + 0x27e8c1b9, 0xbe388a57, 0x058a9fb0, 0xfa682d2b, 0x4ad78e4d, 0x3e91587d, + 0xfe7de2f9, 0x535dad4a, 0xf649c5b8, 0x24ecf5cf, 0x09c514c0, 0x49a4edfd, + 0xd96f4251, 0xefc60658, 0x3b49accf, 0x307a8c18, 0x1e305995, 0x9abf249f, + 0xf11428b1, 0x871cace0, 0x4f543df2, 0x67afeb72, 0x1a87041e, 0xe245b9e9, + 0xe7f774f4, 0xd92db4f1, 0xb2dcefdc, 0x7f5a63b7, 0x58cbe7e8, 0xdda52f8e, + 0x6a06b197, 0x38e828f7, 0xd8cb5f7c, 0x6e7e40e4, 0xc977c091, 0x7a8b2096, + 0x8dab2a7d, 0x0d5d94d0, 0x7af51609, 0x2c28f640, 0x4c146caa, 0x7e2ba721, + 0x72d0d653, 0x768ac430, 0xca017381, 0xbfc1fb49, 0x3a250f86, 0xff5072f8, + 0xf9c7183d, 0x02b6e113, 0x9f743b3c, 0xffd355cd, 0x80bd28d1, 0xffa7af9b, + 0x2d765c30, 0x1e87975c, 0xe1c29d8b, 0xd5c239fa, 0x8b1d3de6, 0x8cb805f4, + 0xe476b86a, 0x3f9ff8f2, 0xa1fc9e9e, 0x88f564f0, 0x87df35a7, 0xc0c61da7, + 0x74126cf0, 0x6e80f97b, 0xfac027b2, 0xcfc849b4, 0x1aef0c3f, 0x6b6dfc3f, + 0x15618d9e, 0xe1137780, 0x9635be2f, 0x7f021672, 0xe04e22b5, 0xc6fa12ce, + 0xfd03ba06, 0x7a468fba, 0xead40f50, 0x2c54d459, 0x96d814e7, 0x46af3cc0, + 0x5da0fb38, 0xfe21eae4, 0x7f8091f2, 0x7014a247, 0xef881ffe, 0xf5e48f7b, + 0x89ff75c1, 0xf28626e3, 0x09ebe0af, 0x1339ad4b, 0xe6fa37fb, 0xf59cb0db, + 0x1a1ad9b9, 0xef1d7fa0, 0xf27e57ff, 0x3caff4a1, 0xc81a8ddf, 0x01d247e3, + 0xfb209419, 0x9ac7cdd5, 0x7f9cc3c7, 0x9d27a595, 0x79e30ffa, 0x79fe36b9, + 0x762c7bd9, 0x778be71a, 0x4b97df51, 0x876fc367, 0xbdf24bb2, 0x97f31433, + 0xd7cd2746, 0x6d8991f5, 0xbce7600c, 0x9942f821, 0x057f329f, 0x151fb0ee, + 0xee0091f4, 0x5a2613b0, 0xf5103e0c, 0x97a07595, 0x5e71a3b0, 0xacdc0eb4, + 0x6ca071e7, 0x57f7d13d, 0x1c50c6a3, 0x27c88768, 0x291b46fa, 0x870fe95e, + 0xff8f9a21, 0x9bf7b5c4, 0x8d3f62fb, 0x33e78a06, 0x4cfc4b7d, 0xdbd717e0, + 0x9427877a, 0x8ef266f8, 0x4763a450, 0x753c0b78, 0xa76a06d1, 0x7287bd43, + 0x8c9e4d71, 0xc8fdae7a, 0xc55916e7, 0xccb472e7, 0xb9ac6be3, 0xbff42c79, + 0x30599336, 0xd62a1cbe, 0xad23d0df, 0xe87f0845, 0x249b9fa8, 0x4af6fc55, + 0xadda8994, 0x6d62fa35, 0x09ab9fd0, 0xf78a051c, 0xb1b118b7, 0x85970782, + 0xeb3ca1e3, 0xe866e800, 0x4760d1a7, 0x2b68e578, 0x7700a7d7, 0x1e0fbc3d, + 0x1f25b9f4, 0x78c167bf, 0x87dabb7d, 0x833d3859, 0x439e61b3, 0xb3de5f91, + 0x97b3c014, 0xdf081cc4, 0x3f5cd183, 0xc455702b, 0xfc02fd71, 0xf114321e, + 0x7ca3ac9a, 0x66fae3ea, 0x96e3dfc2, 0x8c25967e, 0x79c76ef0, 0x299b46f9, + 0xed1d56ee, 0xf9c6898c, 0x1e1cd818, 0x8c766cf7, 0x32587c27, 0x07002356, + 0xf0bd9106, 0xc38bc133, 0xb21cf358, 0x168cb20b, 0xf594475c, 0x8ede8bf9, + 0xcd37685e, 0xd076e68d, 0xd742b7f9, 0xc0abbae0, 0x2c02b677, 0xb957633a, + 0x8498e6d0, 0x9ccf9978, 0xe78e502b, 0x551e0157, 0xc0de7efc, 0x16bc2dfb, + 0xaa51bccc, 0x36eea376, 0x6bc2bb62, 0x760bcce1, 0x5e20f9f7, 0x5f187cef, + 0xf18ac6cf, 0x33fc156f, 0xea07fa33, 0x7c9f9b31, 0x8bf3f86d, 0x8d8f5c79, + 0x4995bc45, 0x7bb4462d, 0xabf98ed7, 0xb3e9ed11, 0x4de61615, 0x4679beff, + 0x9c6aaf31, 0xccd77ace, 0x3ca51f34, 0x5b24f917, 0xc250df3d, 0xf88ad9c3, + 0x4931e0eb, 0xfeaec783, 0xd8f06afb, 0x1a74ffbd, 0xc0c56cff, 0xa43ff4eb, + 0x1aadfe87, 0xedfabbf8, 0xedb6e347, 0x04297bcb, 0x779f7bf8, 0x31bb73e9, + 0x64c7bb1e, 0x373ca131, 0x3f22e6d4, 0xbc0edd5e, 0xd0f4fc04, 0xff28af9e, + 0xa326d0f8, 0x3768c70d, 0x02dae6f8, 0xcc7eefe8, 0xea8dd6e2, 0xa746167a, + 0xdffd9d11, 0x0b1ef59b, 0x03cd95c6, 0x375c16f5, 0xb3d9accc, 0x4cd7f894, + 0x3f8944fa, 0x8b4efd28, 0xccfa3592, 0x5fd9f425, 0x9047cef5, 0x5f3aedde, + 0x89da1e7d, 0xb70f3f03, 0x41117f92, 0x3f12ba76, 0x892383d0, 0x3989ad76, + 0xde4de618, 0xa3ba758e, 0x82dfbfa1, 0x411c62b8, 0xc4e3561e, 0x2293fb78, + 0x5064ffee, 0xa54dbc73, 0xeb45d697, 0xb09d987f, 0xb35f8fd2, 0xcbd17c3f, + 0xc47583d7, 0x2bf372af, 0xb58bbf08, 0xc55c7918, 0x5e67f64a, 0x94e3c1d6, + 0xacfc520f, 0x05fbfe95, 0xbfd02392, 0xe11de252, 0x9ae2ace8, 0xd68c36bd, + 0x5e10fceb, 0x28b7ffce, 0x8a819fca, 0x6ac43d26, 0x162f9e65, 0x310e9671, + 0xdaf37687, 0xda1ff414, 0xa3ab1e45, 0x46e83f71, 0x4fecae78, 0xf37fcf74, + 0x9f6869d1, 0x79e33e83, 0x5a30a6ab, 0x624df227, 0x9106279c, 0x9123b17f, + 0x7ab57fdb, 0xcaa6786f, 0x77bc7c1e, 0x685f736e, 0x7f656977, 0x5dcbda1d, + 0x0efbcdfa, 0x39dae7f6, 0x574df888, 0x39e9e83f, 0xd7489718, 0xdcebb0d9, + 0x31eaaffa, 0x16b650de, 0xef1801ec, 0xa469e812, 0xc4feae93, 0x705f5c70, + 0xcb3f5c6c, 0x9fc893ea, 0xd1f10fcc, 0x60b293fe, 0xea05ba5b, 0x4d8fd7e5, + 0xf33fbe47, 0x5c14a0e4, 0x58c74e0f, 0xdc4f3053, 0x192024fe, 0x69ba79e6, + 0x6abf7f00, 0x17d470e4, 0x9c436b61, 0xadfc009e, 0x95fcf7e8, 0x14767226, + 0xcc48ef3a, 0x7c406b68, 0x7e93320c, 0xf6450507, 0xdf21fe53, 0x17786b0c, + 0x473f159e, 0xa15ac7c1, 0x3ffe954f, 0x79517a16, 0xd299fac2, 0x31ef7082, + 0x1ccffd11, 0xc38d7bd1, 0xf1b21ed1, 0xd08556f1, 0x0730f978, 0x29cbc80b, + 0x8e9d8eb1, 0xbc470eb4, 0x2832ebe7, 0xe443ba0f, 0x7c5956e5, 0xe41eb8e1, + 0x194ad9eb, 0xbe62afea, 0xf8d508f0, 0xd7b28df9, 0xfbddf448, 0x4d5ff90e, + 0xabe90c61, 0xfc8c337b, 0xa69bd773, 0x018f684d, 0x6821ddfe, 0x91371e17, + 0xc9afb2df, 0xfb617644, 0xd7f21089, 0x42c3f1fc, 0x3f48297d, 0x44499bd7, + 0xdf64f6df, 0x0c8edcf3, 0x680f9862, 0x891cea3f, 0xd1694274, 0x9ec3e3c5, + 0xd5cd7680, 0xda2f20a6, 0x60f4f035, 0x6acdd07c, 0x9efde9e2, 0x347e8610, + 0xa8643d3c, 0xe0f17549, 0x1082a0b3, 0xfda99bed, 0x01ce2943, 0x4a1f1fa8, + 0xb143fe83, 0xbbd52b7d, 0x9379d7da, 0x1221c785, 0xd48978c5, 0x5fb7326f, + 0x8d39f499, 0xef89fd03, 0x65ddf4cd, 0x79a48e72, 0x36c61c7c, 0x61679806, + 0xa0bcb6a5, 0xf62e5b5a, 0x5b25cb68, 0x745f65b4, 0x814fd114, 0x7f73e15b, + 0x70c4a4bc, 0x87c142bb, 0xd2769f3f, 0x61f03af3, 0xcbf1013c, 0x571d391a, + 0x929aba0f, 0x0f2de387, 0x9753e4d6, 0x3e279d34, 0x9fd8376c, 0x77c075c1, + 0x9136c0d4, 0xd50360fe, 0xf8ffb6fe, 0xe7adf3dd, 0xbcf5be45, 0x26dadf26, + 0x160c2ef4, 0x5084f18e, 0xe11c359b, 0xad4ba1d8, 0x3d5f22f5, 0xbe7c4419, + 0x21cbf716, 0x401baddf, 0x054452f0, 0xf0b3cfc6, 0xfd08cff1, 0x54c5e677, + 0x642d33ca, 0x4b4fa4b5, 0x44bef399, 0x5887e78c, 0x57ff9073, 0xcdfb02d9, + 0x27baf8fe, 0x34e3d386, 0x7d8ac6b3, 0x6fcc564d, 0x80bfe114, 0x74fd4504, + 0xdfbe20f6, 0xd175f48f, 0xd481137a, 0xd8ccf7c9, 0xf3ff9655, 0x0d0077cb, + 0x3655fe11, 0x67ae3877, 0xde7c2c17, 0x91593f60, 0x9f3245be, 0x8875fa07, + 0x2f120bc7, 0xd942fa2b, 0xdf00b12f, 0x989e7ccb, 0x518f2fa7, 0xc7ae38fc, + 0xf75e925c, 0xd693e830, 0xf2386b08, 0xb4aaeb53, 0xb79825c8, 0x66c6b088, + 0x3aecf0aa, 0xd026bcc0, 0x0946d65f, 0xf0ddbf63, 0xf39223b5, 0x085d6fa3, + 0x8eaf2bad, 0xf6ab996b, 0x8635ff13, 0xc58f91db, 0x16a6ff70, 0x40ec826d, + 0x5a74e078, 0xcab4e820, 0xf931fce6, 0x16f57e4b, 0xf412f754, 0xb95f7bf3, + 0x2f295ffb, 0x0fc55eb5, 0x8a4edeb0, 0x385de3e5, 0x374b7464, 0xfb4a5f91, + 0x82eb7c9a, 0x70bf6ec8, 0xae3a4a68, 0x82eb4543, 0x155f5122, 0x8b135e1d, + 0x8db8c8f6, 0x3ae2c58f, 0x6269b055, 0x9fe2533a, 0x482a3e2a, 0x3da3a7b1, + 0xb6567be4, 0xd5453f60, 0x4ab5c132, 0x167e695f, 0x36ab9fde, 0x24549d90, + 0xdbd73ae0, 0x2f788e19, 0x11bd33d2, 0xef4e7ef0, 0xf03b270c, 0x2ffc9959, + 0xbd40f9ff, 0x00ccfa63, 0xfa0b3278, 0x00b48be2, 0x47547bfc, 0x66082a74, + 0x36e75724, 0xb9edfcf2, 0x587de764, 0x157f056e, 0xaaad77f7, 0x0eb70e2c, + 0x73f78eed, 0xddf12766, 0x051f3102, 0x28e3feaf, 0xbc476d78, 0xe871fda2, + 0x2768c9b9, 0x91929eb8, 0xc6ded933, 0x8e47e42b, 0x72789a6b, 0x075fbe2c, + 0xd7158076, 0xdcefbec7, 0x4ad4eb83, 0x909da199, 0xcb1694d7, 0x57d76a86, + 0xdef22fb4, 0xa3ae159e, 0x90d31df7, 0x6d5b4e9f, 0xfb2a99b1, 0xcfc11dee, + 0x5fc974fe, 0xec70b7f7, 0x818d68af, 0xdff057e0, 0xfd93630e, 0x41e21953, + 0xedef6f3e, 0x7a157ea3, 0x2116fd28, 0x81fe15be, 0x2c63577a, 0x7c795f82, + 0x99d535b1, 0x0fc00b63, 0xe3037ff3, 0x61d57f62, 0xdcbfcc76, 0xbccab8e8, + 0xc8aae93b, 0xafd399ad, 0x8a54f9f5, 0xea8eeadf, 0xe9e99369, 0x50535bca, + 0xfd61f2de, 0x5f3a7f46, 0xfe449df2, 0xe315b285, 0x4aebf9d5, 0xf2f1c3ee, + 0xf874984f, 0xadcf75bd, 0x3f2e09c3, 0x529e01fa, 0x7b75f102, 0xa6c52faa, + 0xfbac1fc2, 0x7ccacf24, 0x1c137054, 0xe4307fe0, 0xa054f6ff, 0xbfee4a9b, + 0xf50f7210, 0x63e2462d, 0x5fc470fb, 0x7e2d7ce7, 0xcdf8b5f3, 0x3e2318f7, + 0xcd273666, 0x9323e0a7, 0xfc17df0e, 0x28e9a7fa, 0xc7abad9f, 0x235abcd3, + 0x8e51c3ed, 0xffa0535a, 0x59e7dda1, 0xe7986bf0, 0x6799efd0, 0xabd11065, + 0xfa4679c7, 0x33df679e, 0xed58c8cf, 0xadeacf3c, 0x5c5fa8e1, 0xfb8664bb, + 0x8ec95cc3, 0xd97963b5, 0x768614b2, 0x05d0f589, 0xd5e912fa, 0xb8a068d6, + 0x30ef22a1, 0x83f20dde, 0x35a1f88e, 0x28f4fad7, 0x0b656f5a, 0x575bd9c6, + 0x51e7788f, 0x95aeb728, 0xb407682d, 0x81fc72e6, 0x0f50ebdc, 0xa638a6b4, + 0xc18f7951, 0x39fa14b2, 0x0fb7f953, 0x0c0bf225, 0x73f34656, 0xbe3b45ac, + 0xfd45e01d, 0xcd997805, 0xcd034aed, 0xa7cad57f, 0x7777e256, 0xfe964df5, + 0xa7eb40d6, 0x6b45cf16, 0x321c8d64, 0x73c695bd, 0x8ac93afd, 0x0cf050f3, + 0xc67d349a, 0x607c2eb0, 0x2eb0d679, 0xfd94b8bc, 0xeb3d626c, 0x9f885bd4, + 0xc05d7cbe, 0xafa8ea7d, 0xa77d3f70, 0x57affb3c, 0xdfc67a7e, 0xd04db89e, + 0x16ef5fd3, 0x7ca9cbab, 0x5cbaa15f, 0x4a37a7e2, 0xbac3befd, 0xfc502d3b, + 0x78e77774, 0x02796f1c, 0xaf5c4a6f, 0xd68949fd, 0xd5bd3cd5, 0xabc17e88, + 0x155c78e3, 0x8ff301fc, 0x683b0e49, 0xb67a793e, 0xef8994dc, 0x994f546d, + 0xdcb7f427, 0x8ef46b04, 0xa077ae60, 0xaaa364de, 0x0557e8ac, 0xfe44479e, + 0xc3fe7942, 0xad64f3fe, 0xb38aacff, 0x201b123f, 0xf7299ece, 0xc608ed7d, + 0x64c976db, 0xf30eba37, 0x7d7d8575, 0xf06de9e5, 0x1a4f7cbe, 0xe6555bed, + 0xf6c78fef, 0x7de12b86, 0x21db7de1, 0xcbc63063, 0x72a31af2, 0xf48a2fc9, + 0xaffbc405, 0xfe94fcc4, 0xe12df4da, 0x2df6d5d3, 0xa19f096b, 0x86bc8fe2, + 0x164fb42b, 0x5596e7f0, 0x534cfb7a, 0x79fa2e4c, 0xcc4a7ff9, 0x55f3c1d5, + 0x06b5cf41, 0x506b0beb, 0xc899764e, 0x3c3b6f6f, 0xdbed8747, 0xe789170e, + 0x9e7a7643, 0xe382933d, 0x7f38eb87, 0x14bde32b, 0x7ca5edcb, 0x7fe7a9dd, + 0x8dfefa84, 0xaa65d4b8, 0x2ebe69f8, 0x6dc4fc93, 0x845cdf06, 0x95f1ec1b, + 0xe943efb8, 0x2b58d5e7, 0xebb6d1c1, 0x0fa8f3fc, 0xce4dacce, 0xb6d23544, + 0xcc70c06b, 0x189db7fb, 0x3fe78e91, 0xb04c9eda, 0x66d81ea1, 0xfc443eb0, + 0x86cc2ab6, 0x87f4ae72, 0xac7e60e3, 0x1cc8d76d, 0x4edbb3f4, 0x4ca17870, + 0x73d4377e, 0xa50efee3, 0xf59d70df, 0x8c8fb857, 0x7940c9fd, 0xa4dfc5b4, + 0x1abfa1c5, 0x5f9c0c6e, 0xbb5dfb40, 0xc1296a7f, 0xf1e3ecad, 0x7d95efb7, + 0xd17efe3d, 0xf80bd07c, 0x2b7fdfde, 0x702b9562, 0x1fbf917f, 0xdc7e40c7, + 0xfa62beca, 0xbdf5a5ab, 0x2677cb64, 0x0fb13d4d, 0xbe031a88, 0x571e40f2, + 0xc3c65c53, 0xe52b5fe3, 0x5f42f980, 0x3ec7cf2c, 0xdcedf213, 0x4f5d1516, + 0x1e3e98eb, 0xc8da7af0, 0x7f99f1cc, 0xaf973fbf, 0xbacc57de, 0x73a777fb, + 0x00b9953d, 0x32d5e9d7, 0xa1fd47ed, 0x7b7f9dfe, 0xf3e88480, 0x4effb099, + 0x3e705cc3, 0x5ab3fb3d, 0x067c1578, 0xfe057d89, 0xfe22cdf5, 0x991bf03e, + 0x9bee51d9, 0xcfe41e0c, 0x3f9f8d90, 0x67f20f7d, 0x6a92c1a3, 0xed017ca5, + 0x64bb6573, 0xb75c7f4f, 0x2f84cf1a, 0xd76575c4, 0xd34e3a08, 0x92ecbfe9, + 0xd6dfee29, 0xf3162570, 0xe50fd003, 0x4f4d5d3b, 0x7b7f90d9, 0x4e312382, + 0xeffa61fe, 0xa1f8bf66, 0x6db67bc8, 0xfa8e973c, 0x6260f41d, 0xfa67ca1c, + 0xff9e46d7, 0x7da1c96c, 0x273f1bbf, 0x73ddbcbb, 0x7349ec95, 0x940f6ca3, + 0x671a1c57, 0x4df061fc, 0xf007c2d0, 0x1478450c, 0x3eadcb38, 0xbd737f3a, + 0x5d84ffbc, 0x1cf14b85, 0xd1f9e608, 0x94682fbe, 0x582add69, 0x40ac7b2f, + 0x7e030997, 0xed082fb1, 0x8a24a7d1, 0x6f924e0b, 0xd40e70fe, 0x4ca4f05f, + 0x1f1bbde5, 0x7480d0fa, 0xbca06f5d, 0x99a682e1, 0xfc57da46, 0x122cc494, + 0x37d9ab8d, 0x12972c50, 0x09f6dd5c, 0x680fedf8, 0x7d0b76cb, 0xe37ef7e0, + 0xa2fb198a, 0x9267a9f1, 0x017efbb5, 0xcb103bfc, 0xdfe047cf, 0x126bfe96, + 0x416d0e91, 0x5ca3358c, 0x5fc85bea, 0x3e7e5e61, 0xd9d76db3, 0xeb97a414, + 0x5e292f8d, 0xb01c93d9, 0xf33fbe46, 0xfc8938ce, 0x5cdf81d2, 0x5008e699, + 0x6fc8b67f, 0x13b8316f, 0xb7dd3ed1, 0xe38f2af1, 0xae71e2ec, 0xee67fb1e, + 0xf26f1e20, 0x2c1c5106, 0x0532d6ab, 0x3cec01e5, 0x36b93fcc, 0x09b198ad, + 0x0dbb41ca, 0xabab4456, 0x05c9287f, 0xaaa141ca, 0xb61e455f, 0xb2947c88, + 0xd8b661bf, 0x6feca397, 0xf83bf650, 0x77eca1c3, 0x3bf62d98, 0x78eb1dbc, + 0xc19e0e28, 0xd9385f3a, 0x5ffb7eb1, 0xe2cfda7a, 0x3fd1efbf, 0x4f9fee6e, + 0xcbecad5b, 0x47146088, 0x8dfac237, 0xcd86c395, 0xabf51778, 0xfe4c98e1, + 0xef23ded0, 0xf1f5aac5, 0x38737d0a, 0xd72f31c6, 0xd1fe4419, 0xc316f947, + 0xa98dcf91, 0x862597a4, 0xca0bae76, 0xb375def8, 0x338eaede, 0xe7c71d3f, + 0x9d2e22bb, 0xfb7ab7af, 0xb7afcc21, 0x688cf259, 0x148e1b8f, 0x367e464c, + 0xf919e7c4, 0x54e6b9f8, 0x9e844ba4, 0xa3457ff8, 0x05b36e32, 0x7bf257fb, + 0x2cc71161, 0x598577c8, 0xbf3fbeb3, 0x4a83f227, 0xdf33af7e, 0x7be33f17, + 0xe33b7bf3, 0x8bf71d38, 0xff71bbe7, 0x3b7bf2cf, 0x5265fe91, 0x30f1a4cb, + 0x8ef88ac4, 0x6ebdf9c0, 0xfcb1bcf3, 0x567147de, 0x9ceb7f9e, 0xbdf90f6f, + 0x58dffd6e, 0xff7baf7e, 0xbaf7e43d, 0xf9837ff5, 0x797ecebd, 0x50f96f7e, + 0x5b3fed1d, 0xe3c4dc7e, 0xffbe66e4, 0x65e424c3, 0x668277b9, 0x74f284ff, + 0x184909b3, 0x275e5f27, 0xbcfe464f, 0xa0b3c96c, 0x78221a7c, 0xb064c83c, + 0xd43f464f, 0x85191114, 0x711ff97c, 0xabaf3469, 0x3f888b11, 0xc87982af, + 0x722d89cf, 0xef797960, 0xca649902, 0xd6177f2f, 0xd57cf324, 0x7758b368, + 0x87e4b7df, 0xf3fbfe52, 0x3d1e5538, 0xed00fb2c, 0xce0d648b, 0x8fbf283e, + 0x127f405b, 0x7c50b79f, 0x7f3928c6, 0x76217187, 0xbb639f82, 0x601ce41a, + 0x3ea5c951, 0x2eec28de, 0x33ea126f, 0xa7a2ab37, 0xe10ae1ab, 0x2a478959, + 0x47cc5ddf, 0xa5794778, 0x7a09b8c3, 0x706f7d2b, 0xb573a00e, 0xbb4e8e02, + 0x6ea18fe0, 0x6a69a73c, 0x8ff286fa, 0x34df7aed, 0x36d4eb8c, 0xfc6a21ca, + 0xb973c526, 0x9cfe4dc8, 0xd8e556f2, 0x57e617ae, 0x7ca0064b, 0xc37c9b96, + 0x7b7dee11, 0xf51c36fe, 0x92a6d5ca, 0x0b7ef83e, 0xdc75a7d4, 0xe7572be8, + 0xaaf3fd5d, 0xf381f1d1, 0x969a5bad, 0xdb1c2225, 0xf6005e30, 0x3fc3f955, + 0x663a73a7, 0xea0dff66, 0x837a060f, 0x99868afc, 0x93b438f2, 0x01db003e, + 0xf8bb59ca, 0xcc959bfa, 0x2d37983c, 0x0e60fa6f, 0xdb3cabd2, 0x32974168, + 0x6de78338, 0x16cdb383, 0x45a6ff5c, 0xe2303e71, 0xed869b3a, 0xdd214627, + 0x3031c41e, 0x7b73b9cf, 0xb7f01bbd, 0x854f0ff0, 0x27dfc033, 0xafda4afa, + 0xb1f9ba51, 0x2f3c3b70, 0xc714dde8, 0x0723c4fc, 0x1794ffdc, 0xf6b7f8af, + 0xfe754950, 0x3fdfd3e0, 0x6ef88d31, 0x7982c1b3, 0x1316d77f, 0xaf2b9f9d, + 0x33f3a62b, 0xcbc53e50, 0xfe867f8f, 0xbb41ab95, 0xe97c2f4e, 0xad2b58a9, + 0xb124ee0b, 0x941f11ee, 0x849d9cd7, 0xc1f857f8, 0x8f8e1dbf, 0xb55de5fb, + 0xaf633cf2, 0x7b15dfee, 0x5dff5943, 0xfb884f75, 0x3fc85a01, 0x845faff0, + 0xb19a3232, 0xfddaf199, 0x983e0ad1, 0xa3f48627, 0xf0c373bc, 0x54be5053, + 0x92e16ff3, 0xbf8a4f0a, 0xff9b51d3, 0x3dac37bb, 0xb06defaf, 0x7574b02e, + 0xb3b50f3b, 0x177e0836, 0xf06a5f7c, 0x955ca386, 0xdcd8346e, 0xfb74baf0, + 0x973e2f0b, 0xc3667245, 0xfb64ac75, 0x818e1f5b, 0x430ec972, 0x8d3e54f4, + 0xde754950, 0x61ff05cd, 0xc3a1405e, 0x32ded7c2, 0xf7f1875a, 0xa2ec88bf, + 0xbd8ec947, 0xfc5e7446, 0x76be31f1, 0xbbf291af, 0x3da974fe, 0xef2b7245, + 0xbbec86fc, 0x2c48f64f, 0x3e00352e, 0xee15be37, 0x3a227814, 0xd2753a0a, + 0x92beafcd, 0xe4e8577f, 0xde3b3dff, 0xfd85f242, 0x3f023ca1, 0xc606f2bf, + 0xd9323ffb, 0xaf45fe70, 0xf38e103c, 0xc45faf38, 0x63c37af9, 0xb71876b1, + 0xb58ee0c8, 0x2fbf93d0, 0xc467fe7a, 0xfe8e0b6f, 0xcc7fdb8c, 0xfca3a09e, + 0x7bf29ba5, 0xd0efeb85, 0x0da2ffe8, 0x85ffae3c, 0x11de4d9e, 0x0b8e2e40, + 0x937e72bd, 0xe7d9f289, 0xf6860f31, 0xdf327bcb, 0xa7eec7b7, 0xdf629078, + 0xe54d2780, 0xfe1e842f, 0x894ebc43, 0xfc359b7f, 0x3378f35a, 0x64d3e7d2, + 0x25ea1c7b, 0x05bbd317, 0xa0efa43e, 0xc4e8f95f, 0x1e1f4e38, 0x6076a33f, + 0xf7c78e8f, 0x40d9bf58, 0x3b5550f1, 0x8f966e71, 0x1f18a0ff, 0x7cc60ee0, + 0x5658f9ca, 0xd44fc814, 0xe7c67427, 0x29e7359b, 0xcb9be4bb, 0x2e2acd7b, + 0x7bbc8adf, 0xefc64fa6, 0xf2e31f9f, 0x3292ed83, 0x1c6f2e09, 0x4b3bdf7d, + 0x27cfce1a, 0x75c9037b, 0xb5c8418d, 0x27c2bbf6, 0xee9eb700, 0x05f85021, + 0xfc248ffb, 0xbad2d517, 0x1dd8d26d, 0xbc2f1c2e, 0xdc8a7f7b, 0xfff2102e, + 0x7f38bc7e, 0xad9fe425, 0xf3a1b98f, 0xcf06a545, 0xbca1cf8b, 0xbef7e09e, + 0x90376e94, 0xdb717e5d, 0x06ef0ffe, 0xab58b939, 0x7f56a9c8, 0xd169cbfa, + 0x7f116fab, 0xc5e9cbfa, 0x0362b7da, 0xb78ee9ca, 0x2eee0ec8, 0xfab9ffa7, + 0xdfdfc153, 0xe8a7f0fc, 0xe8f09ec3, 0xe3ab0faf, 0x21f501ad, 0x9f531dfc, + 0xa5f0537b, 0x6fc29df0, 0xeb2e5f0b, 0x93a77a83, 0xebbe152f, 0xef854be4, + 0xd73bedba, 0xfbffcfe0, 0xe00df85b, 0x60faec72, 0xb3d01252, 0xc9fb91b4, + 0x9620eed0, 0x5a764f01, 0x41e558c6, 0x55db6f3c, 0x6b95f8f6, 0xfddbeafd, + 0xfabf0eca, 0x22f2bf4e, 0x821efabf, 0x3f61b4ab, 0xbcc96fdf, 0xa586fa9a, + 0xdd161dcc, 0xf31e0e75, 0xcfd02b58, 0xf4f3c6df, 0xb8f0258f, 0xb8c62fa9, + 0x891ff682, 0xe13e2a7d, 0xb43bb467, 0x354e54fb, 0x5b7fa4ca, 0xf8f3813c, + 0x3c9209e0, 0x3fb0f4b4, 0x4d3b895e, 0x1e534394, 0x2a3a3806, 0x60a0fc79, + 0x94e19dc9, 0xbb4c69cf, 0x850ae31d, 0x2c31f987, 0x73143f65, 0xaa09f5db, + 0x98170efd, 0x319be9fb, 0x4258d64f, 0x35828bf1, 0x0fcd7a5a, 0x0be2907d, + 0xf7b4abf3, 0xad7c2900, 0xd68b0bc4, 0xc42fbf6b, 0x1ee8847b, 0x47da4a85, + 0xfb46b0b4, 0x0e7c89dd, 0x41273c7c, 0x2c1909d8, 0xf9bde443, 0x57a11239, + 0x6f43ca27, 0x21cbfca7, 0x1da5f299, 0xbde1328d, 0xfb449b63, 0x863b9869, + 0xf99ca5e4, 0xf8299f48, 0x60f284b9, 0x5cdf59ec, 0x73dffd7a, 0xa52a851e, + 0xff0f1ff5, 0xd52f3c2d, 0x8ddf489f, 0x4e7f9de5, 0xaf7598f9, 0x104f7e3f, + 0xdf6a1fed, 0x35f74613, 0x9dbd37b5, 0x85e528f2, 0x07ba364c, 0x9497cf61, + 0x6a5f6b7f, 0xd57d422a, 0xcafdcc9e, 0x0e5f4d65, 0x39657ae7, 0xc098df3f, + 0x34744dcf, 0x94f28dfe, 0xca268d1d, 0x84f6b933, 0x7ae11f90, 0x9cfc8823, + 0x292fa6f6, 0x9acffcbe, 0x3788b94f, 0x3cf187b7, 0xbfb8bb4f, 0xf47bb5c4, + 0x2d87980b, 0x446bdbab, 0x9bfc65bf, 0xdf5d90df, 0x67b72afe, 0x1eded0da, + 0x5bae7883, 0x7dc44e33, 0x4d0ecca8, 0x0db77b45, 0xb1912385, 0x9d5dcfa1, + 0x081a1eea, 0x5e50df4f, 0xf3f146f5, 0xfc18ffd2, 0xb9dfb448, 0x63cc31b4, + 0x5fde7096, 0xf518fc9d, 0xd79e1ec1, 0xb17be657, 0x1fd90976, 0xc1f79bd7, + 0xfddfee04, 0xe4b799ef, 0x9f7991bd, 0xef4e6ffd, 0x98d43c62, 0xba2e5ddd, + 0xcf1379f3, 0xb30f6d17, 0xc837bc11, 0xffc486ef, 0x157f7465, 0xfd7e1ee8, + 0x6ffbf779, 0xe99eef3e, 0xa0ae787e, 0xf3e305bb, 0x21bf37ae, 0x3d5efef8, + 0xe87fe137, 0xfd3b15fc, 0x6fd7c67d, 0x91c3a257, 0xee9efb88, 0x5f02bc38, + 0x274e74b9, 0xcd12c3c5, 0x4d9fee74, 0x8e87e28d, 0x33618ef5, 0x57877586, + 0x25fe1bf1, 0x31273ed1, 0x07feaba6, 0xa619efb3, 0x7d57779e, 0x58d1be3e, + 0x379d3f7b, 0xfca50b29, 0xc18f6e2c, 0x36cc2f76, 0xf713fe71, 0x990f1c3c, + 0xa606307b, 0x738347f2, 0xe739c23e, 0xc0ac9fce, 0xca2fb4b2, 0x35e718ba, + 0xdc4725af, 0xc710b08b, 0xfb3b352f, 0x72f9aa60, 0x2f4073b2, 0x511c47b4, + 0x1ccb9e3c, 0xe1011cc3, 0x37ce6b77, 0x994bf62a, 0xea3aa1b0, 0xbe517ad2, + 0x645ed5e4, 0xb8e9b57f, 0xe026d87f, 0xb767e0bd, 0x1a8e7917, 0x5c58ff31, + 0xcea8d473, 0x7389963f, 0x3fe3fea9, 0x23f3c891, 0x87f6be9f, 0x8bf748ab, + 0xa3a7d45f, 0x5d2256bd, 0xdd5d79a2, 0x98ae747a, 0xff9c0adf, 0x14be1d43, + 0xb4abcc23, 0xc791af76, 0xf4fcc523, 0x9beff4be, 0x79ae9b5f, 0xaabb9d12, + 0x8e7ce897, 0xeeacaed2, 0x93b424e8, 0xe8226a8b, 0xa7dc473e, 0xca9dcfc2, + 0x7860fb7e, 0x8eb2493f, 0x4bf7dbf8, 0xd21bf689, 0xe9dfb41f, 0xbee0f08e, + 0xcaee936a, 0x676899b1, 0x8ce7e30f, 0x438307d6, 0xbbc77e0f, 0xc41b5f02, + 0xbf780779, 0x07c7df12, 0x4ff1f6f3, 0xfedf68eb, 0x9409b90b, 0x7bdd543f, + 0x72075291, 0x36b26494, 0x49b8c0b4, 0x0f28bd15, 0xb9d13dbc, 0x5f71f105, + 0x18e52e94, 0x421ce1c1, 0x8e6f80e7, 0x753f21ba, 0xf818b306, 0x9e7e527e, + 0x4f85867d, 0xb5d850a5, 0xee9d9933, 0x3983b8e1, 0x6d7bdea9, 0xd7da3b46, + 0x336e61ef, 0xa3f7ee93, 0x0f3177f7, 0x5e61ef3d, 0xac2fffaa, 0x5f0aca85, + 0x17de3f02, 0x3cf1f9cd, 0x8e8160a6, 0x47dc226f, 0x3f278643, 0xfe9ef80c, + 0x94fe80cc, 0x76e2ad2f, 0x9ee0f5f0, 0x574bfc2e, 0xf210f3a2, 0x2fe4c77b, + 0x7e82af9e, 0xf12f6674, 0x91ee7283, 0x7c11884d, 0xdb72fdf1, 0x0f99d1dc, + 0xe2bf450d, 0x5bd24156, 0x509fdced, 0x2edc0dce, 0xd9ef01e4, 0x343a0489, + 0xa7bdf95b, 0x3dbd2acc, 0xc793ca02, 0xe59fb4c9, 0x20d6e08f, 0x4331fc7f, + 0xd9a5f716, 0xd134fda9, 0x3371d4ef, 0x7a82f797, 0xc96ebe93, 0x9327f3c2, + 0x8afd6b7b, 0x5c6f449f, 0x29cf011e, 0x7fefb4fd, 0x88f59aca, 0xb543a9d7, + 0x2cb4cdfe, 0x38bdbd6d, 0x2a962466, 0x4b845ee9, 0x193fc289, 0xfdab06cc, + 0x1d3e6513, 0xd118af53, 0xe493ec17, 0x597482bc, 0xb9d9db7c, 0xcf4ede74, + 0x4d111ede, 0xbcd1cff7, 0xe6f02b5a, 0x55cec646, 0xa179e998, 0x20ecc2c2, + 0xc4569ff7, 0x8552f3d3, 0x55b7de95, 0xf8e7a40c, 0x90dfc724, 0x9f95053e, + 0x670fd1e9, 0xee34e955, 0x9acf8203, 0x9d1d5e75, 0xd124d85f, 0x82079a7e, + 0x8ef1739a, 0xa73607ac, 0x61739c52, 0x0c41ed43, 0x1d78141f, 0xf39c9093, + 0x883a2d0f, 0xc06bb2cf, 0x158023e9, 0x24a61c12, 0xa763eb94, 0x7ac6df67, + 0xe37b1be6, 0xd05183a9, 0x1b0af9ff, 0xc549f5c1, 0xac5e7a28, 0xb3dc13b0, + 0xa4961c92, 0x67d2a46c, 0x6db73fc4, 0x824fa53b, 0x12ad13fa, 0xb63f2bad, + 0xe4078f33, 0xd7c0daab, 0xb304ea85, 0xdc74e50d, 0x1e1b19b0, 0x9df7a864, + 0x1dc70889, 0xe2278a53, 0xcd46d338, 0xeeb47ba3, 0x7bf19afc, 0x58dc2695, + 0xe9f988dc, 0x247bcbdd, 0x3acbcbe2, 0xff18edeb, 0xa649ff75, 0xde0740fc, + 0xe3fe80d3, 0xe32f7e71, 0xe2d3d7e2, 0x362f3f50, 0x5fd0e358, 0x79f62ddf, + 0xe97a045c, 0xc5eceb55, 0x9cce7fed, 0x25bfd2a7, 0xfabaecaf, 0xf2fbf411, + 0xea1b48c9, 0xe2918bbd, 0x28b6467e, 0x9b48f504, 0x19623bc8, 0xd65015ef, + 0x5833d45d, 0xebcc18be, 0x9492bce7, 0xe382728b, 0x7a5d8d59, 0x6795fd28, + 0xed6a3efa, 0x6d4b6f1a, 0x41cf47e1, 0xe747b2f9, 0x723ac036, 0x61b6d599, + 0x135dd6dc, 0x066dfb4a, 0x87e0fa4a, 0x7c3d6f89, 0xd56488bf, 0xeb6c3c63, + 0xd1121b2b, 0x392dd80e, 0xfa823ee6, 0xffaf037b, 0xe48fd3d2, 0x53e7c2ed, + 0x823eaf65, 0xa08a4f78, 0x2b9ff376, 0x36fc8c1e, 0x5d5efd6c, 0xa9bfbc22, + 0x7c52d4e6, 0xc2a240ce, 0x926d8cf7, 0x8cdd778c, 0x865d4ba8, 0x1fb898af, + 0xfbc0b06e, 0xed9ff5d0, 0xf4107703, 0x08e2ed6b, 0x525757ca, 0x671bd7bb, + 0xc10f7fbe, 0x7bc04ee1, 0x8cf3dd35, 0xb8f03edc, 0x5c9f2237, 0x51b40e76, + 0x7ee1cd7e, 0xd973e916, 0xf5c36b19, 0x0ee75ea0, 0x4ff5831f, 0x76087bf2, + 0xc70d1cd6, 0xeabd11fd, 0xed082c0c, 0xad1f0c95, 0x56c9654b, 0x259659bc, + 0x64eb7f3f, 0xd7927946, 0xa53f5237, 0x99e61b66, 0x42bf5e8b, 0x13f61cf1, + 0xfc8feb66, 0x4fcbc751, 0xfd13b04c, 0xc17e368a, 0x2a0ecdcb, 0x2a77643b, + 0x0f945fdd, 0xfbf40c76, 0x5877588c, 0x47d270cb, 0x2ed672c4, 0x9f013f7c, + 0x3abdf02d, 0xfb809dd5, 0x0af594c3, 0x219f99d6, 0x839ba37f, 0xef739bed, + 0xf775a149, 0xa519d706, 0xfc8c679f, 0x46f5bd7e, 0xb66e1ebe, 0xf42778f0, + 0x4fe514bf, 0x64931759, 0xae1d5869, 0x6c98cf73, 0x3e37accb, 0xfee2ddce, + 0x2af813ae, 0x430d6c41, 0xf8ffba42, 0xe9ffc636, 0xfbf23dfe, 0x15675799, + 0xf941ecf7, 0x4fc3a4e9, 0xe619bf2e, 0xe003f82d, 0x83013820, 0xf2a7f50c, + 0xe38b2c3e, 0xb669d233, 0x2e2b7e61, 0x33dd116a, 0xd307f0a1, 0xdda0477b, + 0x995bfab0, 0xffb94bce, 0x7f714a1a, 0x4ddf787f, 0x7af471e2, 0x639e07c0, + 0x7bf07772, 0x5ac31a9f, 0xf403fe5e, 0x9bdc58df, 0x0dbbc6e2, 0xf756fefc, + 0xdc5df174, 0x5778dd27, 0xa27dc92c, 0x7601eb89, 0xd38d304f, 0x7e6cf068, + 0x8f4fbf1a, 0x85c7f6a7, 0xde671d9c, 0x955f707b, 0x7ba467db, 0x1822ab39, + 0xb55367dd, 0xfdc50064, 0xe07dbfea, 0xbda186df, 0x639f84b2, 0xacf0caab, + 0x55ff7dc4, 0x70e34cbf, 0x1724de48, 0x260e2fb6, 0xdd355d3d, 0x4071809e, + 0xba10b4e7, 0xfba7ba57, 0x28323f5e, 0x09ec89e7, 0x0ae78f88, 0xfdf533fa, + 0xca4e7f41, 0x57748c3d, 0x3a73d1f2, 0x8ecc22f3, 0x21de5bf7, 0x6e15770a, + 0xbb7e420e, 0x14e828a3, 0x178f6bc6, 0xb8c30d2d, 0x7e4e1de3, 0x359b273f, + 0x8f3eaed1, 0xfb24e7f9, 0x5657e461, 0xdeedd8a0, 0x1ed3c47c, 0xbdce999f, + 0xa847f901, 0x7f8544ed, 0xbe77aafe, 0x8ddaed87, 0x92e35ee2, 0xb6cda6af, + 0x6bf1faaa, 0xf27edfe7, 0x37bf330c, 0x7644cea9, 0x8ec27dc1, 0xb3bc9972, + 0xad5a0ed1, 0xf607fe73, 0xe9f85aef, 0xa277b470, 0x17fbf067, 0x09be31db, + 0x7a0a4f75, 0xff7c649d, 0x98517ba0, 0xb2f11bc8, 0x0f28d1f3, 0x9ec7a7bf, + 0x07e58850, 0x1f70d886, 0x99e45390, 0x7c44b958, 0xf9c2d272, 0x146364e4, + 0xe33e8fdf, 0x30e9d3da, 0xab8e938f, 0x7a848f6f, 0x79f81b27, 0xcc3cbf8e, + 0x2f9619cf, 0x60d2913b, 0x7baf3eed, 0xd97bf297, 0x0bf85def, 0x93da6f3a, + 0xaa5bddfc, 0xd21987dd, 0xce15fedb, 0xb5c67a33, 0x1287a849, 0x2d9f4a4b, + 0xdbdabd44, 0x2fbe2df9, 0x2394b637, 0xff77ca3e, 0x7fda0a7b, 0xda5ebbed, + 0xaf9e1071, 0xdeba9d19, 0xade97df8, 0x67618fa9, 0xd72f9ec2, 0xae403d03, + 0x34edea9f, 0x717e06f6, 0x63a6f04d, 0xe6864bbb, 0xf6378849, 0x1bb31b8b, + 0x5cdc6d3f, 0x115fa12f, 0x4f4e58dc, 0xe11c33d9, 0xc37928b8, 0xa71e1ef1, + 0xc97e8fd8, 0x188f0de2, 0x72c7f78a, 0x1f3ff5fe, 0x8ac5a048, 0xaed0327d, + 0xe71656a4, 0x27143c97, 0x025faff6, 0x0ddea9ef, 0xcbce57be, 0xac344495, + 0x66f44b1d, 0xee166f5e, 0xf74feceb, 0xfd7e5d32, 0x5fb574a5, 0x0eecffe5, + 0x9d3f9f2f, 0xa9bcc6e7, 0x7bf7df87, 0xe4068a09, 0x71266db3, 0x51f38f8e, + 0xc104d6db, 0xda8f9c67, 0xa8f00eb6, 0x9cf3b6e5, 0x8736ada0, 0x6bdbedf6, + 0x501ed073, 0x6b999fe4, 0x36677ee9, 0xda3876b0, 0xc23d8add, 0xf4e9b51c, + 0x8e9b53de, 0x3c75ebf5, 0xbb8ca73f, 0x7e24e5f0, 0xeb9998df, 0x0f2f85c5, + 0x94c6fba1, 0xcf37af7e, 0x4d46d501, 0x5b479079, 0xef9bd69e, 0xeffdf85b, + 0xcbf1f73b, 0x93c61ec2, 0x40f79d85, 0xbd73de76, 0xf2f05255, 0xfa0e5260, + 0xaaf28ca3, 0x0be07bbb, 0xbd21ae05, 0xf30b3fb9, 0xbbceb863, 0xbbfae23f, + 0xf331c33e, 0x6fd72836, 0xb6fb2348, 0xe9f8e74d, 0x79e71c30, 0x3ebaafbe, + 0x9cf947c2, 0xfdb967fa, 0x5de62e5b, 0x424ce11f, 0xc2a17a7d, 0xffee2f16, + 0xe96c3b26, 0x98e11589, 0x61dfaff7, 0xd5f8c0c8, 0x63fb3527, 0xad3e2f91, + 0x37ee9878, 0x75e3bc1c, 0x6e94a3ca, 0x1c7de07d, 0x8336d2f7, 0xd2acdd0d, + 0x8b5c5ebb, 0x56e948f6, 0x5be716b9, 0xe53f75ba, 0xbed52fc7, 0x71fb8e15, + 0x9144d42f, 0x53f08c1f, 0x1cf7fafe, 0x2ff8fe0f, 0xabc464f6, 0xc91591f7, + 0x7f78b5ee, 0x5a2d90c9, 0x3c7d17bc, 0xedea10e9, 0x18cff50b, 0x1fbc56f5, + 0xa6fdfb56, 0xeff96d06, 0xe4abaf3d, 0xd4e39091, 0xdcc85c74, 0xdda9f507, + 0xb5645feb, 0x3f18edb3, 0x9727bce8, 0xdae8edcb, 0xbb379475, 0x6e6e78fe, + 0xe9da853c, 0xa379ab9e, 0xe231b7f8, 0xe6b65efe, 0xdbc424e8, 0x5a2427bc, + 0x36bde6ef, 0xcfea00e0, 0x9aee3b53, 0x93d9cf42, 0xe8f91f09, 0xd67ee085, + 0x061bc946, 0x8e28cb65, 0x9e6ac2ef, 0xee5bca17, 0x8d69ee77, 0x2af8fedf, + 0x0d05f7ed, 0xbcc2bf7b, 0x79f99176, 0x3f741f8a, 0xfba1e3c7, 0x605e177f, + 0xac2dcfe4, 0x2814cef9, 0xcca851be, 0xda63fdc3, 0x264dc01f, 0xfff0fff0, + 0x4daee346, 0xe1ea3d47, 0x651b5531, 0x731957c4, 0x2349643e, 0x021bc5bf, + 0x8137cfe3, 0xeb4992dd, 0x4ae7cd21, 0x8f3a2f75, 0x5059ef0e, 0xda03de26, + 0xe4eb839c, 0x1b30ba95, 0x9cd69fdf, 0x02d57683, 0x21f9d328, 0x0bce2956, + 0xf1fee87b, 0xcd06d505, 0x1ec5e07d, 0x7255996d, 0xef14b0fb, 0xfa470ed3, + 0x92bb50b7, 0xa57ada2d, 0x91e39f30, 0xfb51ffb8, 0x5b7cc5de, 0x2b7da45f, + 0xefd498df, 0xb1547b15, 0x0e38958f, 0xe460b228, 0x7237bb97, 0x04b77a3d, + 0x0c3b45f3, 0xafb234ed, 0x420e3b3c, 0x2878aab9, 0xdff54fd9, 0xca5bfdf2, + 0x0caad4f9, 0x279e3a7b, 0x88375aab, 0xb25bbfe6, 0x7a863ea7, 0xd859ba60, + 0xe1ee8c57, 0xa44e2aaf, 0x1c23fbf5, 0x2ced0132, 0xf729ef6e, 0xeea227f5, + 0x18e371c2, 0xb53f8fbf, 0xb37a8bd6, 0x3fae29ea, 0x81563b14, 0x4f675f3b, + 0xb36e75c1, 0xcdebe9d9, 0x23a56ff7, 0x09bff9dc, 0x4557bc22, 0xfce8c2f8, + 0x0dd4517f, 0xc59ba7ad, 0xabcca0fa, 0x7dd07255, 0x293d4ae8, 0x9cdbeb99, + 0xa28bfb5c, 0x0b39c51e, 0x6fab1d72, 0x3c147c01, 0x1fa2b3ad, 0xbb6789dd, + 0x13ef1d3d, 0x94175d68, 0xcc9cf089, 0x47367ae0, 0xf6061bdc, 0x3c137dbb, + 0x9a759383, 0x32706578, 0xc163a7b7, 0x5af1c27f, 0x5438f227, 0xfc839658, + 0xe6a9c079, 0x19e53c1e, 0x302be02b, 0xa3f4fe3a, 0xd274f000, 0x7bc7027b, + 0xad12fdeb, 0xa21f3047, 0x83afce5f, 0x2ad00e28, 0x4e8503d6, 0xb4d92fc0, + 0x54bd09ce, 0x21f80ab5, 0x2da1ed15, 0x6afa835b, 0x0be286f8, 0x3ebe2eec, + 0x7c704554, 0x4c393d56, 0x6f82e5d8, 0xbf120c9e, 0x6cedc0c7, 0xec51fd65, + 0x3d3e6570, 0xef40e1d9, 0x7c2ac961, 0xe999d3f9, 0x7dead93d, 0x5e74fe94, + 0xd2986e60, 0x0bc1550a, 0x5c067825, 0x6b7d91d2, 0xde0892ce, 0x2a7ad581, + 0xb259d51f, 0x8da6ee51, 0x11f179dd, 0x7e7857d4, 0xebf47907, 0x39bbbeef, + 0xa951f707, 0x7dc472fe, 0xeb0fc8ca, 0xef183799, 0xd894afd9, 0xa03acd69, + 0x8fdfe32d, 0xb9fabb63, 0xf89efd5e, 0xdcfd9ff7, 0x69d8c159, 0xf85d8590, + 0xebc347ec, 0x4665fbd5, 0xb93c7236, 0x5f4f308e, 0x597677d2, 0x0467ef8d, + 0xcbfcee1f, 0x6e3023ab, 0x687dae31, 0xe9679e2f, 0xd3ef53a7, 0x5ed660ed, + 0xa3b4efb8, 0xee17ad31, 0x2438eb4b, 0xf0033987, 0x038056f5, 0x572ff1e3, + 0x5ed9e998, 0xf0652ac3, 0x8f99da2b, 0x6bba67f6, 0x5f902ccc, 0x73b934ba, + 0x739319ff, 0x3ba5f7d4, 0xa4ec7d68, 0x9fa9a5d3, 0xc77787e8, 0x569dfe3f, + 0x87f913d6, 0xebf715e3, 0x06b75e20, 0x740a4cb5, 0xe04aafde, 0xafbeda6d, + 0xe0e33f68, 0x943a8dc6, 0x3a35c1f7, 0x26b93acd, 0xca43ec59, 0xd7089964, + 0x61417db4, 0x438f4859, 0xe6082db2, 0xccfc6ae7, 0xd7e00ce8, 0xfb11e3f9, + 0x8702fdc7, 0xa7842d93, 0xf25a86dd, 0x365f772b, 0xbb29fdd3, 0x8125958c, + 0x23eccce0, 0xd8ebc405, 0x5f6833f3, 0x5e157fca, 0x7a87b5c7, 0x588e3173, + 0xbb1c78c3, 0x7d71bf1b, 0xd185b1d4, 0x710ef739, 0x1b63a80e, 0xa01ebca3, + 0x77dc49e2, 0x8b7df203, 0x80d63f7a, 0xe32f1d86, 0x28de5efa, 0x72e4fed1, + 0xf7118b7d, 0x221aba5b, 0x65bfcc64, 0xae3dc558, 0x59b0cb7a, 0x9c38392a, + 0x17e7e7ac, 0x07beecc6, 0xc972bdc7, 0xec87e748, 0xef747c07, 0x11c695c0, + 0x3cefbebd, 0x6c156bce, 0x7b3bde0a, 0x5f119938, 0xd0c1f3f8, 0xf29ac16d, + 0x8899d958, 0xd4cd34f2, 0x002da0f2, 0xc4528add, 0x7aa370fa, 0x89fff3cc, + 0xe8a63b1e, 0x8eaca731, 0x74a46487, 0x817163d3, 0xc962d8f4, 0x5ef8871a, + 0x871694dc, 0xd87c5cf4, 0x8f481310, 0xac38076d, 0x007f7720, 0x7b67c3f9, + 0x9bb1e81d, 0x0eac7a54, 0xbf0058f4, 0x3ae52924, 0x5ff3cc7a, 0x51db6f23, + 0xe798058f, 0x1fae14f0, 0xbc363d14, 0xb1e914f1, 0xcd3a75e1, 0x29feda39, + 0x5263d3d7, 0x2c68accc, 0x01216c1b, 0x89f106f8, 0x27c47779, 0xd41c713e, + 0x9629f967, 0xfd9f4bbf, 0xecfa7af8, 0x8abf08bf, 0x3afc5b3e, 0x3ba37f23, + 0xdfe231df, 0xfd18bbc5, 0x26e2cfce, 0x3716cfae, 0xcf0fbe31, 0xec0d8f4f, + 0xff18c7a6, 0x6f2f165d, 0x7d486aef, 0x2fe85ee6, 0x99b06ed3, 0x97667ea1, + 0xeb56cb5e, 0x1e94fcb5, 0x1ba1daf4, 0x0baf6bd3, 0xaafa06bd, 0x7f51ea2f, + 0x6a35b0be, 0xf763977f, 0x5edbf3e8, 0x5b78f943, 0x4701f3a6, 0x9dfebe45, + 0x90b3e7d1, 0x1e11eaaf, 0x4235d390, 0xdc2adb5e, 0x03f8ffd4, 0xdb657e7c, + 0xca0f5a24, 0x57bdb8eb, 0xf07b235e, 0x31a4e180, 0xff3ed15f, 0xe18926e2, + 0xa6e9b2d1, 0xfef1a7ca, 0x8192f630, 0xd4e53889, 0x143f150c, 0xf8a12a8c, + 0x999e8161, 0xc96ddf71, 0xb73fbe28, 0x7b959444, 0xf53b0ba2, 0xcdbedfa0, + 0xf7e9fb86, 0x7bcffc34, 0xdcf7134e, 0xf2417b4d, 0xdd5ffde0, 0x712a7bcf, + 0x97fbed38, 0xcba77cc5, 0xf61f842d, 0xde73e06e, 0xe5e3fb2f, 0x8d4bc090, + 0x478bc5ac, 0xe517880a, 0x8782ad5c, 0x565bb7e2, 0xf8a75c60, 0x32fc8959, + 0x782b79ff, 0x761f76ea, 0x909dff23, 0xdb62f7ee, 0xd25bbf35, 0x144477ed, + 0x7fcdfb3c, 0x323fa2bb, 0x37bc08d8, 0xf482f81b, 0xfc4ffb87, 0xb8c7421e, + 0x3d6a71fe, 0xc3c09afc, 0xe371ca88, 0x2e99add1, 0xd5f98afc, 0x804c1ff7, + 0xb71f67f9, 0x6303fdd2, 0x9ee898c7, 0x3e41adbe, 0x9f0a6fd2, 0x3e70fa19, + 0xecfd116b, 0x4b945c4e, 0x241a74fb, 0x2e13da0b, 0x37bf106f, 0x082df805, + 0xf67fecaa, 0x478124ea, 0x689efd0b, 0x006f5883, 0x4e57e8ef, 0xc01fd652, + 0x88cfca3b, 0xd7074e46, 0x2c874e16, 0xe567e3c6, 0xf30d92d5, 0xf70de5ea, + 0x8a3e711b, 0x50bf85de, 0xfc545d35, 0x27f357a9, 0x7bad547d, 0x34fbe225, + 0x1887e553, 0xfc06993f, 0x0cd891be, 0xfc3df7fe, 0x5f77eddb, 0x2f7bf3ae, + 0xa78e1f72, 0xf44788ed, 0xdc7d12f3, 0xbac2f26e, 0xddf5d610, 0xf06b77a5, + 0x6bb9fe38, 0x249abf9c, 0x3b01c62b, 0xefc354f1, 0xf056cf6d, 0x788afc84, + 0x63279c6f, 0xf8837e79, 0xf9bf1fdd, 0xb5083ee2, 0x9d37171c, 0x906ffde2, + 0xbcc02c6c, 0x7fdfe47b, 0x927b6f90, 0x2d1f435f, 0xe413beff, 0x2efb823b, + 0x77e24ddc, 0x34231a19, 0x7dfec279, 0x35b01db8, 0xfd1cf808, 0x1b06c3e8, + 0x2fe0a7de, 0x3d62b1ef, 0xaadf7b43, 0x420f97ca, 0xb12e3180, 0x28ceccc5, + 0x76e5f470, 0x6edf5aa5, 0xb331620f, 0xbfee7ab2, 0x4f5ba09f, 0x1e528df6, + 0x5ea1e386, 0x54f1806c, 0x7d7f2cf9, 0xd7e5f8af, 0x0fc6579b, 0xce32979c, + 0xd87e7bdf, 0xfe799ac5, 0xd0245f02, 0x26dfe179, 0x9fa9bc63, 0x7bdf57a4, + 0xfe6fdcae, 0x3b3fe84f, 0xfee7a625, 0xf685bc59, 0x4efb2937, 0x0e3cfd94, + 0xf3fb130b, 0xae33fe6f, 0xfcec57e3, 0x8e9641fc, 0xae33707d, 0x3a06b90f, + 0x88e57ac7, 0x573fe281, 0x2e7bf026, 0xbf7b7f6f, 0xedf2f51e, 0xff0114a8, + 0xe44b67b7, 0xaec51d1f, 0x6d1da347, 0x80257da6, 0x1f9811bf, 0x1ca9a8c9, + 0x333ee78f, 0xe19678b7, 0x17de36d3, 0x6dd20efd, 0x7bf74c9c, 0xc6a3db34, + 0xc0fa3ae3, 0x71819659, 0xa9ef5877, 0x1621e67d, 0xd8c6f583, 0x18fdc863, + 0xb1f9f75d, 0xe8c70099, 0x0acdb223, 0x0fefa6f5, 0xf77cc50d, 0xe63af5c0, + 0x0c6be154, 0x73c32cf3, 0xed5ba33e, 0x22ee1133, 0x2e305fb0, 0x71b8d45f, + 0x2e439e19, 0x7b512f5a, 0x2939db97, 0xbdb3e61c, 0x4349b3fa, 0x3d401f50, + 0x9eb5c6ec, 0x48d573d7, 0xcf394c36, 0x24675c6f, 0xefc3517d, 0x91eed86f, + 0xebf79998, 0xdbbf4331, 0x2cfb43d7, 0xd05b638a, 0x7cd5720e, 0x5cdffb46, + 0xdfb52700, 0xccc5cfc6, 0x94567687, 0xa9fb9a97, 0x12f5e2bf, 0x457323c3, + 0x543af8db, 0xc360c474, 0x9f7b75ef, 0x2a74f5a5, 0x8a90978c, 0x02778eeb, + 0x884739c5, 0xffc77b7d, 0xed5df90f, 0xd58fd38c, 0x2feb92fc, 0x9fbf2989, + 0x4f9f57ab, 0x97d3e8eb, 0x2db10bef, 0x3f414631, 0x498a8cef, 0x7d5f11d5, + 0x71b4e746, 0xf013935f, 0x179c547d, 0x8cea3fdb, 0x409f7d51, 0x4f3f2b2f, + 0x8e30d05b, 0x321551ce, 0x9aa39d07, 0x8fdb9a36, 0xc828feef, 0xde33fb83, + 0xe37af835, 0xe23ffdfb, 0xb6dcd3bf, 0xb6dfeb9d, 0x1fda16e4, 0x307f1e7b, + 0xb65c6009, 0x717d265e, 0xce819b7e, 0x7018c90d, 0xe76dfc44, 0xf5fec5f6, + 0x5bf3dfbc, 0x7e361db8, 0x70931dc3, 0x59b05dbd, 0xf5c46739, 0xce3fe2b3, + 0x62f388b7, 0xfc8d1b95, 0x5fefacde, 0xac3d1477, 0xbf911efc, 0xfceb2d9e, + 0xc92f6cfd, 0xffad594f, 0x2ed0ccf9, 0xefe9043f, 0xb9f88afd, 0xa18188fc, + 0xb99d221f, 0x4f8ff944, 0xef871d70, 0x3b251ba3, 0x3a2a3b9e, 0x1d90f26e, + 0xdf7799ed, 0x393d71cf, 0x3afba261, 0x1cf055ce, 0xef9328f6, 0xf781bf2f, + 0xe3351c9f, 0x97e03cce, 0x05ef8479, 0x3be1116c, 0x473f336b, 0x2ab47597, + 0xe7ae3e76, 0x7fdc7813, 0x9cccb541, 0x89f0fd2a, 0x37799f64, 0x1ee8175f, + 0x598e856b, 0xb8f9cac6, 0xe562de9e, 0xd9bad8fa, 0x2fcde740, 0x760cfd08, + 0x5103dd3e, 0xac5d6bbc, 0xe2ff4551, 0xf8b175a6, 0xc42b2853, 0xe265b439, + 0x91b17a9c, 0x47bc538f, 0x8d546cb2, 0xf4a3f4a3, 0xdbc5dc6b, 0x67f135a5, + 0x2317fd4f, 0x2fcf347c, 0xfc27a88c, 0x7e36e9fb, 0x7a8cfd0f, 0xee155aff, + 0xaef51817, 0x8c72974c, 0x2d35333a, 0x0f643ef0, 0xd31fcf8f, 0x747f7e69, + 0x35825fd4, 0x6cba91f9, 0xdfa07790, 0x4edc0d6d, 0x653ecbab, 0xb2a2cb2c, + 0x5cbbe505, 0x27cb85c4, 0x75f57df0, 0xa3974719, 0x92cd4fbc, 0xdb981f88, + 0x29dfc469, 0x8accbb07, 0x5905a779, 0x6802fdbc, 0xf758728f, 0xd04b972c, + 0x1fd4560f, 0x830017ff, 0x8000007b, 0x00008000, 0x00088b1f, 0x00000000, + 0x7cedff00, 0x55537c7b, 0x393ef0b6, 0x526d3479, 0xa0fa5b42, 0xb4db4e50, + 0x9494b14d, 0x27457897, 0x880b5a3c, 0x46107006, 0xf4228206, 0xbd185499, + 0x35fde338, 0x9c414415, 0x0e7c570b, 0x42d2d37a, 0x1429a2c1, 0x20d5b16c, + 0xb47441d2, 0x3bd15ef6, 0x0f8afea3, 0x52d25a04, 0x8ef4f987, 0x6b5adfa3, + 0xa126d39f, 0xdf7ef515, 0x37f5375f, 0xef6758b3, 0xbdeb1fb3, 0xce275ef6, + 0x620a3b5d, 0xd67318e3, 0x319e920a, 0x6abd54d6, 0xc614f273, 0x2c8ba68a, + 0x67e7c242, 0xf01192b4, 0x2c7133e6, 0xd3e3b187, 0x1939db3f, 0x74339dda, + 0x7ff41d26, 0xc637d357, 0xf3ec6064, 0x991cc64a, 0x5ea5b388, 0x698459c0, + 0x8c09e2c2, 0x060e313d, 0xead8ca99, 0x0c0599e6, 0xeccddf9e, 0xf8bfb19b, + 0x7981f436, 0x47a20d5d, 0x2e9c0027, 0xc60dba8e, 0xc680f77d, 0x7e3b280a, + 0xfdda8e83, 0x153da007, 0x4faed8e0, 0xdcbfc004, 0xe86e61a5, 0xc89771b0, + 0xb2fff418, 0xc5f7a05e, 0x90597ee7, 0x3adaf804, 0x2983aac1, 0xad9aef8f, + 0x1efec24d, 0xd9bc61c0, 0xbc6869cf, 0x7f78fbb5, 0xc5e433f8, 0xf186b633, + 0xe2a635bf, 0x632e599b, 0x65a7cce5, 0x69efd0e9, 0x115da7cd, 0xf87bedbc, + 0x1827b15f, 0xc60fad2f, 0x4bb6d9cb, 0x6f403462, 0x750ef3f0, 0xef386dd7, + 0xb4f41bfa, 0xb637d9ee, 0xeb8f5e9c, 0x5c30d06e, 0xef1bece7, 0xba02ef8f, + 0x963351ae, 0x8e90693c, 0x0cc788e5, 0x559d8eb1, 0xb31fa4da, 0x1c75909e, + 0x3b8c6719, 0x63fc0d7b, 0x3df49b12, 0xb8dcee90, 0x628d8c91, 0x740b5dcc, + 0xb67e0049, 0xf00f360a, 0x4765b8a5, 0xf3d616bc, 0x02fdfe3d, 0xf11db6f0, + 0xb6d73c22, 0xbd2fd408, 0xad62c38d, 0x60aff16d, 0x0aafc51f, 0xb0696aa6, + 0xb9ce32bf, 0x7df10271, 0xbfef3373, 0xb5e015b1, 0xac5f8fc3, 0x0ac6bedd, + 0x65dd4a70, 0x72b864ad, 0xb17e651c, 0x739c782d, 0x8e857cb2, 0x2c1a2f97, + 0x10bba46a, 0xaf7e4569, 0xadbcb817, 0xdc799bbf, 0xacc94f20, 0x87406042, + 0x9013e644, 0xbd29c0df, 0x86fce41d, 0xcb55903e, 0xf17edd20, 0x1d5b0475, + 0x6c99c740, 0x3b3e1064, 0x7fa82922, 0xa83529be, 0xecc4a6fd, 0x52b9f6a0, + 0xdf3e105e, 0xff505d72, 0x4199d605, 0xe7d3adf8, 0x685ff506, 0xdb84185b, + 0xeb8d4998, 0xba5cad6f, 0x999073f8, 0x041d2b57, 0x70287a15, 0xd8c54e86, + 0xee0bc13f, 0xa036ec9b, 0x19288ccf, 0x3e397367, 0xd8d1f002, 0x06ddb37e, + 0x20919d74, 0xc7016ce3, 0x05f69593, 0xe538ffbc, 0xfb785bfd, 0x2dfb4a35, + 0xd2a27dbc, 0xafc72b7e, 0xf1eed467, 0x03776adc, 0x8ed1ebfe, 0xb6f8096a, + 0x138aebe4, 0xfde9a023, 0xa77745aa, 0x45583f02, 0x18d36306, 0x0034875b, + 0xed182ed6, 0x351a4a78, 0x7ff4aed8, 0xe357b255, 0xd14bdef3, 0x63226cb9, + 0x51dfc80d, 0xe6321f3f, 0x716779a3, 0x1159b2d2, 0x33ea1f06, 0x0cf4d08b, + 0x631a51e8, 0x0db18d82, 0x906f4831, 0x0477a213, 0x89a55f41, 0x8995ebe0, + 0x94a8df04, 0x63336ad8, 0x821695ed, 0xf4ad2b27, 0x74e554fc, 0xda576f82, + 0x5953be08, 0xd2a3b048, 0xe290504e, 0x9f1872d8, 0xa23eb1ed, 0xd5b87a41, + 0xfcc2cf23, 0x7e40cff8, 0xd4c64286, 0x1722acec, 0xcabf79d0, 0x65f48ad6, + 0x6ce98c6c, 0x5ef3e0d4, 0x815243a1, 0x46a7bade, 0x0f40eb58, 0xf37a0f8c, + 0x4617a04c, 0x11bac1a7, 0xe59c6168, 0xbb43524b, 0xbad69d71, 0x029fda11, + 0xf587ab73, 0xda991ad4, 0x1cc9f602, 0x34f1100f, 0xf7aa8d0e, 0x7fec0552, + 0x1ff5045f, 0x0236c603, 0x196825fa, 0x7de0f7c3, 0x1ffd8116, 0xdfd81163, + 0x684024fc, 0x10e1adaf, 0x37f48224, 0x43cde741, 0xe2e09efb, 0xd555d8eb, + 0xee304921, 0x5c7ca9ae, 0x29f13158, 0x8119cc5f, 0x499fb2f6, 0xb8394c23, + 0x005abd1f, 0x83d5e881, 0x2bb009df, 0x45034f59, 0xdb24f402, 0x01d4c113, + 0xbd4d757a, 0xe09f0829, 0x3fea0c4d, 0x6a0a59b1, 0x8259f3cf, 0xb49f27da, + 0x3b53e106, 0xbff507a6, 0x105b43f6, 0x61575d7e, 0xcfebff50, 0xfef083d9, + 0x618fd81c, 0x94defe78, 0x9ff50428, 0x703ade0b, 0x89aac67c, 0x232df33e, + 0x1bf79e83, 0x1b869d38, 0x78358177, 0xb71f855c, 0x7f1e0f4e, 0xdc782da1, + 0x3d87cb1f, 0x906a27a0, 0x13d07aff, 0x4f41fb84, 0x0de720d4, 0xbf8827a0, + 0xd0827a08, 0xcf827a0b, 0x209e820f, 0x827a04de, 0x13d011f8, 0x4f419bc4, + 0x3d051e10, 0xa357e7c1, 0xef3cbb57, 0x53de7949, 0xed8cbcf2, 0x8d5d3a20, + 0xefcb6f2e, 0xdfbf23bf, 0x079bef81, 0x30bcb0e5, 0xc835f543, 0xf398ccf3, + 0x87582eda, 0x01575d6d, 0x6f7d4dc6, 0x8246ac8a, 0xc9cf0e6e, 0x5aab8c4a, + 0x9456d962, 0x5bdf7b5f, 0xa70fc42a, 0xfb42b69b, 0x78ffe696, 0x4dfddb07, + 0xcdf184a2, 0x459fcdeb, 0x5f3d38e3, 0x2c753247, 0x3459f7be, 0xdf654bc6, + 0x42b7c230, 0xb9c5fa3b, 0xe5f3228d, 0xb57bbaa0, 0x5663ded8, 0xe3168f70, + 0xa3437b33, 0x5a52f916, 0x6fed48df, 0xedc1357a, 0xed41d5f5, 0xb00fec26, + 0x4689ed54, 0x56685e7a, 0xff51f3c6, 0xc3f73332, 0x6f8fea17, 0x5bd61ebe, + 0x562ab8de, 0x3697f584, 0xd77f17bc, 0xe2ffd00f, 0x1c721791, 0x0b797ef0, + 0x1c18678c, 0x2345bcaf, 0x65fd7ce3, 0x1882c6e6, 0x621a1ba0, 0x87acfcb0, + 0xc01b676d, 0xd736942e, 0x577c6195, 0xc343b96a, 0x5ebd3e80, 0x01d710b1, + 0x71062a7f, 0x9189995b, 0x7ef1e87f, 0x8c177d15, 0xc4f79afb, 0x7a87e82d, + 0xe3478f5b, 0xd04dbdbc, 0xabbf803f, 0xb11c7953, 0xfc4b553a, 0x1e3a69eb, + 0x16fb412d, 0x774e71ef, 0xfff68fb5, 0x02f78cba, 0x8b377a24, 0x5afa2e3c, + 0xc6507c45, 0x9a33a173, 0x4619ed8a, 0x97a757dc, 0xaa7f77cf, 0x579b9fc4, + 0x9ff5c6ad, 0x55365c4a, 0xae05fb24, 0xf1def01a, 0xc2b6ebf3, 0x30bd4a52, + 0xf7f210ee, 0xbb6e3ca8, 0x69bf471c, 0x1a3ed43e, 0x30aa7ee8, 0x807c8f36, + 0xaa636fdc, 0x6815fa8a, 0xe80ae61d, 0x8c9069d7, 0x160fcf28, 0xbf911ba6, + 0xe7c423af, 0x0eb5bb85, 0x7c4d2580, 0x47534ebe, 0x675dca34, 0xe31164d3, + 0x7fbc6551, 0x901de791, 0xb9be01ef, 0x9e454f89, 0x338e036a, 0xfcfe3fc8, + 0xbd1354fe, 0xdef3ca77, 0x7f603b92, 0x2b28969d, 0xcb5da5f2, 0xa5fd708a, + 0xbe7160e8, 0xa46ae4d6, 0xfddf3283, 0x2d7a3f32, 0xbfabe22a, 0xbbf72359, + 0xf5058ea3, 0xd57e70d3, 0xe4c7af06, 0x3bfbf339, 0x73d97fa0, 0xbef8c322, + 0x8f11534c, 0x20fcc7fb, 0x9d32dd68, 0xf8be34cb, 0x2d7900f8, 0x1bd0196b, + 0x8b79c903, 0xf11227a2, 0xa763e153, 0x4aebe445, 0x2c1879d4, 0x8eb1acb9, + 0xced41ae4, 0x4d3907ad, 0xff20ea8e, 0xdccffc97, 0xfc0ad54f, 0xfb2559b9, + 0xb5c7154d, 0x3e2fd100, 0x7853fb27, 0x1f00999f, 0x00146c0b, 0x4fa614d7, + 0x917c4155, 0x21e6362c, 0xb6a9753f, 0xff9854a6, 0xc87ec97d, 0x6489f142, + 0x553e43b4, 0x66e0d97e, 0x7efed023, 0xdbce24f4, 0x047904df, 0xd11e5bcc, + 0x9073ef3c, 0x282b7ecf, 0x7fb7ac08, 0x5ce28697, 0x00833b10, 0xe99acd71, + 0x94be5f5c, 0x8844d31c, 0x54abcb17, 0xc832afb4, 0x5f98f4bf, 0x62eef6c9, + 0x28adea63, 0x452765a7, 0x2be60453, 0x9d7fd4de, 0x86837881, 0x57a72af2, + 0xff30fab0, 0x255a326b, 0x9deacfc0, 0x9d379869, 0xe2d3eaad, 0x3e21677b, + 0xcbcf9c7f, 0xa7cb4f50, 0xd4519f73, 0x193da3bc, 0x57e60960, 0xafc8cfe2, + 0x3a99f242, 0x8c75c7fc, 0xf21539fd, 0xb26f8c1a, 0x37c63659, 0x048ce2f9, + 0x7f995fd2, 0x1710276c, 0x13f5a612, 0xdfa809ac, 0x3cd2d45b, 0xab6f77dc, + 0x71f484c6, 0xc62a1db5, 0x22ca7b75, 0xafd82aad, 0xa251c373, 0x815fef63, + 0xf65710ce, 0x33ca3226, 0x67a7197b, 0x6797336f, 0x44f04697, 0x9e20fbe0, + 0xe0845e34, 0x5ea682a9, 0xd9347f77, 0x510ac621, 0xcb2dd7fe, 0x68bc6150, + 0x80337203, 0x57b91447, 0xf5c0a5fc, 0x977546fc, 0x7bde1238, 0xe7fdc343, + 0x48d353df, 0x9968e7ee, 0x46f5f103, 0xc62bf92b, 0x887de8aa, 0x52fe28a7, + 0x67c435fc, 0xc7254f14, 0x147e497a, 0x6d50bc3f, 0xab8e04d2, 0x821bdfbc, + 0x0580f32b, 0xe0ede3e1, 0xf8c0def1, 0xa6fc7923, 0x1e740f8c, 0x6afe7481, + 0x70fc958a, 0x91f042ca, 0xa41577a4, 0xf59e8a77, 0x01cd5c80, 0x3810cab9, + 0x1d76cabf, 0x728073a3, 0x00e741d6, 0xde7cd105, 0xf11f9c02, 0xd2130e48, + 0xedffda04, 0xdb5e9c69, 0xa7d8a864, 0xc4b66913, 0x698d8034, 0xa469318e, + 0xb792261f, 0x408cb2f5, 0x35d0927c, 0xf75d7d84, 0xf06e7e27, 0xda3dc815, + 0x08575f99, 0xfe203992, 0x6ed3fd29, 0x69c34b2d, 0x18161d6c, 0xbd7188af, + 0xc5d9e451, 0x1b95b2bb, 0x303992f4, 0x7fc3b2fe, 0x72c567a0, 0x279e117b, + 0xd8e0fe40, 0x27992f10, 0x8f627bc3, 0x4fd73c16, 0x73577396, 0x73d3ee30, + 0x0519f379, 0xffc9c60f, 0xf5e72694, 0xc8a7fcb2, 0x10ed58f2, 0xabdf683c, + 0xee1355bf, 0x90782e5e, 0x8784bf07, 0x45e4621b, 0x99a2bf62, 0xbf47f41e, + 0x8ef29404, 0x2fa4719d, 0xb9fb08d4, 0x2fffde4d, 0x0263bed5, 0xc684e7ec, + 0xc2f98a9b, 0x2b08f289, 0x418cbf8e, 0x64f60180, 0x7820eb39, 0xd879ca3a, + 0xc7bb8347, 0x81ff3c62, 0xf8c56743, 0x8d537aa7, 0x2e66ed11, 0x3cc264db, + 0xff514805, 0x9f1fe4fd, 0x0b8830cf, 0x5f0aff90, 0xcbecd31b, 0x073f00d2, + 0x749c493c, 0xefa5fbe5, 0x3e468e1f, 0xd0e6ff76, 0xda19db92, 0x3bb23e9d, + 0x1a551525, 0xa8c41c9c, 0x906d32c3, 0xe0bf0abf, 0x1f1052df, 0x90630f61, + 0x42cf622e, 0x177ffbd2, 0xabb1fa19, 0xf3a151f1, 0xac7e642f, 0x21f6e16d, + 0xdd0abf94, 0xa21e676f, 0x5daff81f, 0x23a617c4, 0xffca147b, 0x0407f1ab, + 0xcd363971, 0xe431d38e, 0xdb8ab26b, 0x2035e4ab, 0x3beeb02f, 0x0bada398, + 0x8fa892e0, 0x32e72434, 0x7ccb969f, 0x167980fa, 0xdfff5258, 0x9a44e9f1, + 0xe91a7b63, 0xfd4869ad, 0x32c7d50c, 0xe2aefac9, 0x67a43c6f, 0x3579fac1, + 0xf85664bd, 0x8e7f802f, 0x7fa4d10d, 0x625d7f0a, 0xd5f7e903, 0xad18f3cf, + 0xf059bcab, 0x847f52f8, 0x10b00a5e, 0x884363e0, 0x1afc2a3e, 0xf6291ece, + 0xfb96b4ec, 0xa27df763, 0x8ff2f307, 0x1309df05, 0xceeca7da, 0xd282640c, + 0x8eaae3ff, 0x38c0f7b1, 0xf0e4cf1f, 0x0159c634, 0xad922db8, 0xa49e23b4, + 0x3f7ee373, 0xa167b216, 0xf858fe7f, 0x9e385be7, 0x5f1095a0, 0x04cb3096, + 0xef0d69f8, 0xc57dd8af, 0xecbc7fde, 0x4fd439da, 0xbee06f60, 0x47a25c60, + 0xa782fddf, 0x256a4406, 0x5f5c6a98, 0x0aa7acea, 0x27f9e0d3, 0x43cf4dbf, + 0x05d6d87e, 0x2e7e878f, 0x3ce22275, 0xebf1baef, 0x9caacd3e, 0xfc0679c1, + 0xf44b9cd4, 0xfd53f15c, 0xb25a1965, 0x2833ab53, 0x69922fde, 0x1ec98b6d, + 0x87f829f1, 0x08fa4f7e, 0x5fa0ce55, 0xc8793fe9, 0xefa008e0, 0x4c3bf079, + 0x3f67801b, 0x97e81296, 0x3479ed8e, 0xa451f913, 0xb9e2e775, 0x3feab9e3, + 0x2edfa0a4, 0x2670f3da, 0xb67b8dc5, 0x5ffc6264, 0xa668f354, 0x0728f08d, + 0x4e6a1fe5, 0xd703ee87, 0x101adeed, 0xf26526a7, 0xc47979f8, 0x1f8c7cb1, + 0xf1735de7, 0xcbf41321, 0x4260adf8, 0xeb35f831, 0xddfd0878, 0x77970b0a, + 0xec8233b6, 0x43678c31, 0x2f65d7be, 0x3d7d45a8, 0xb34cf965, 0x74bfe31a, + 0x056bd135, 0x804b6cf3, 0x6088f676, 0xfd8163aa, 0xff6356c7, 0x6d049b55, + 0xb1fa1c62, 0x97987991, 0xd247d2e9, 0x247cee3a, 0xaf9f1daf, 0x9f3f8078, + 0x7534f3a7, 0x694f38e2, 0x37a475ad, 0x278c34f6, 0xd2ebf595, 0xcadef4b5, + 0xcbc5026d, 0x4f193cca, 0xee0757c6, 0xfdce9753, 0x8db29b32, 0x32adcfec, + 0xe07e6e5f, 0x611237bd, 0x1d6349dc, 0x7f6874c6, 0x66b389e7, 0x139f3c1f, + 0xf3073e73, 0xe3ad0c86, 0x77dc62d9, 0xfb8ace8d, 0x2c9b9298, 0xdfff6026, + 0xe11c7ccc, 0x3d5607ca, 0xf2768c5b, 0x73ca08e9, 0x13adf594, 0x83e61524, + 0xbf6fabc7, 0xee76e913, 0x778a0889, 0x256755d7, 0xdfc81fb0, 0xa5ff02f7, + 0x41f6c64c, 0x05f08efe, 0xd825dfc8, 0x44ca81e2, 0x94aa5fc2, 0x5ca5b208, + 0xb899d6be, 0xbc6e193d, 0x4b9790c9, 0x3ca64760, 0x7c41e302, 0xcd9c6f38, + 0xcaf40e92, 0xb35e5f18, 0x0657de45, 0x4ee79fbc, 0x98748d9d, 0x769ee5b2, + 0xd2e31d0c, 0x56f2fe79, 0xa82923e7, 0x381f6bc7, 0xb4317cf3, 0xe7b74aaf, + 0xbb11fbe1, 0x7e3e512e, 0x15e1e5bc, 0x1aa2ef48, 0xbc9fdf1d, 0x644f73ef, + 0xe78b3c26, 0x286a6f75, 0x3aed763f, 0x8016fcf3, 0x47bb6d77, 0x3fef281b, + 0x7113bf76, 0xba7f533d, 0x97470d9e, 0x8f67ae9f, 0xd53e90a6, 0xfce59e80, + 0x3d733d7c, 0xdcf44550, 0x15ff6e9c, 0x8d39dbca, 0xebf5053b, 0x240df65c, + 0x8136eef7, 0x5fd8a1f8, 0xf2a5fde5, 0xde554bfe, 0xce02336d, 0xc6432f15, + 0xd63ef486, 0xc62665f2, 0x979b97b5, 0x47dc088d, 0xfb023c28, 0x35864c86, + 0xda7dbd03, 0x69a7db2b, 0xd856e91d, 0x8f1534df, 0xabdb4367, 0xbdb255d2, + 0xcf0ffc85, 0xc5ff1433, 0x0f78b43a, 0xf82ad651, 0xaa3ef122, 0x6af3a6f9, + 0xd81257ba, 0x7de741a7, 0xe01a7d8c, 0xe75b8777, 0xc713a0d5, 0xe3da0f51, + 0x31543f6b, 0xbdbf805f, 0xf9922bae, 0xc81de602, 0x114f6023, 0x4b7f1fc0, + 0xd87d9052, 0xe7042e9e, 0x36aef013, 0x15f21fa0, 0x2dfc65ef, 0x9f8835d9, + 0xfb3e72d7, 0xc47c408f, 0x389849cf, 0xe71e906d, 0xd173ba5b, 0x70f42b2e, + 0xb926ed1e, 0xf87e6b29, 0x99f44092, 0x7b9d5e7b, 0xdb1cfa75, 0x7c8b9dd3, + 0x9ae9af3d, 0x5f947986, 0xfc8b95db, 0xedc2be71, 0x93a54ffe, 0x11f8bcf2, + 0x05d800d8, 0x3ca260a7, 0xa1ec5f2f, 0x927fdcbc, 0x96cee5e7, 0xfb7764dd, + 0x88b9f95b, 0x9051d54b, 0x1508e780, 0xeed1da67, 0xfcf227f5, 0x21b7c609, + 0xcba466bd, 0x97dd53fe, 0xdfec10b2, 0xe1390189, 0xd439da79, 0xe38e2d73, + 0xc17b432d, 0x1d58a372, 0xf501778c, 0xd8af9e1e, 0xe519ba90, 0xd4679cff, + 0x6fa3b424, 0x49ddfee5, 0x45af68e7, 0x638a4499, 0x7f0069e0, 0x11e1f607, + 0x1e282d99, 0x80b6628a, 0x74ad2e7e, 0xa7bfc52b, 0x74c7ba44, 0xc67ae78d, + 0x2b3d728e, 0x9b4c74df, 0xa35e3018, 0x7894f76c, 0x7f6bde70, 0x345d7d27, + 0xf023b991, 0x14f597bd, 0x2031b0e7, 0x7a2f80ff, 0xf283c139, 0xdca8f7e0, + 0x178bc81a, 0x87fee64d, 0x7ef1d21d, 0xa454d289, 0x6af31f87, 0x4c794fa0, + 0xc00c6647, 0x2b89df23, 0x4e4f98ed, 0x2be01c02, 0xf2cf9702, 0x23991d45, + 0xd0495cf1, 0xa4bcf0ab, 0x77b786bc, 0x54bc78aa, 0xf7dfc69e, 0x7b57dc0f, + 0xde821653, 0x9cbdb6f5, 0x5be02772, 0x9c35be0d, 0x7c4cbe0f, 0xb99eda0e, + 0x46efe608, 0x5cf74d9f, 0x5ed08be5, 0xdc151b75, 0xf78c71c9, 0xb5cd9ee9, + 0x5baae508, 0xbc15e0af, 0x5c64105d, 0xe5c15f79, 0x8c8547f7, 0xb4859237, + 0x0a4ff487, 0x3dca35c1, 0x58ff3c9c, 0xb517fefe, 0x7bc22cf7, 0xcf3af9b7, + 0x57f44ac9, 0xd218692f, 0xf0e07f55, 0x697fa459, 0xb33bf70b, 0x39ee1c0e, + 0xd872f288, 0xb1e6f748, 0xe3e254e6, 0xdbbd96c6, 0x375ca126, 0xada073f2, + 0xff3fef0d, 0xc3a7ea3b, 0x57183163, 0xe69eb759, 0xebca2f9d, 0x1e39eb66, + 0xdfb3b725, 0xb2847c72, 0x3c71dfaf, 0x6b7fb796, 0xa75a17fe, 0xfb81f0ff, + 0x9fa05e50, 0x17a5e29b, 0xa2605e40, 0x73d94392, 0x1bf59e30, 0xfce0563b, + 0xab3afdce, 0x09e7c25b, 0x95be30b3, 0xa4dcfccc, 0x14f6fc78, 0x4754a7cc, + 0x1df9edf7, 0xd7efbb9e, 0x2ba139d3, 0x12a5db86, 0x3dda7ab1, 0xf7bb3f24, + 0xb5f701fc, 0xf6e74f4f, 0x1edcd1c5, 0xa0c9ef15, 0xfe579ef3, 0x940ad9f1, + 0xd7717c83, 0xd7fe7c1e, 0xe90abd5a, 0x8db5a9d4, 0x4cfd01b8, 0xa9e286a7, + 0x3e2f1962, 0x13d7cb1d, 0xf24055d5, 0x653db713, 0x4948c811, 0xe0b7fdec, + 0xdb8be7ba, 0xce7f479f, 0x0ce8eaf6, 0xa03efceb, 0xbe77bc2b, 0x2da7434e, + 0x35467dfe, 0xb0b76bca, 0x38b3c57d, 0xd7ef1d7e, 0xf44edfad, 0x3165d776, + 0x31fa0f9c, 0x16ea9f3c, 0x3f3d0476, 0x1737b75f, 0xfb0bade3, 0xa5dc53e7, + 0x97a293e8, 0x20bab525, 0x293fc7fd, 0xf963f31e, 0x8666e4cf, 0xc2e9fc80, + 0xcffc6791, 0x85f5e806, 0x0b4f8d06, 0xb1d62a34, 0xa7af784d, 0xf24963e8, + 0xbfb8854d, 0xe6755512, 0x278bc03a, 0xbd40ad77, 0x1167af3c, 0x2defd089, + 0x2e0f3f15, 0x885aaa69, 0xf5b87b76, 0x7c799b14, 0x9f913979, 0xd66e5f97, + 0xa9cf027b, 0x9547e143, 0x3d5b7a4c, 0x42baff88, 0x19473e47, 0xb7ad2def, + 0x670ee30c, 0x9fc3f70c, 0x3306ff40, 0xee6661c4, 0x086e56a7, 0x1cdcbfee, + 0xda9dcf43, 0xcbb44cae, 0xcccbf8ca, 0xd4cf6e26, 0x9fe8995d, 0x7923df43, + 0x82f57b47, 0xa4aaf640, 0xf7433849, 0xf8d248c7, 0x44967a41, 0xee623db8, + 0x9c487cd0, 0xc601f326, 0x77ac87fa, 0x9b7a0d25, 0x8d29c61e, 0x7f468aec, + 0x8aec6655, 0xff6f73c6, 0xc8d59151, 0xc6538bec, 0x4f9c1b4f, 0xbd8b8fc9, + 0xa87e9b1a, 0x183b60f9, 0x7fc5adef, 0x32622903, 0x3514deb8, 0xcc7cd147, + 0xe50d35d4, 0xf05768b6, 0x534fb87b, 0x9bfa3e80, 0xc607c777, 0x75c7bfa1, + 0x8677de53, 0x1ff7a6f4, 0x1ca0a69f, 0x26d8a894, 0x20bee73c, 0xc0617bf0, + 0x82f85ee9, 0xf25e5e7c, 0xca244337, 0x65cb85cf, 0x01fec7a4, 0xd928fb3b, + 0x6762bf07, 0x15c70d59, 0x7076cb3b, 0xeecec07c, 0x3762b8e2, 0x42a3fe95, + 0x1d0a4fde, 0x9077a94f, 0xe6ed93c7, 0x6e7abaa2, 0x7f7e4537, 0x4c6b76c7, + 0xfce27f3c, 0x19d32b5a, 0x95d3b412, 0x123577e4, 0x19c5b1fa, 0x76a579ca, + 0xa0e27e90, 0x7499fa3e, 0xbbf509a0, 0x10f940c8, 0x070d15c4, 0x59791cf1, + 0x07ef15bc, 0x9caee943, 0x7cc5c777, 0x7cf906b3, 0x8af1d6ab, 0x7269ef19, + 0x82afc8ba, 0x74bf90b6, 0xb8a3aabe, 0xb7d357aa, 0x965fed07, 0xf61af1d6, + 0x6c76d32b, 0xea4b029e, 0xe3b574d1, 0x943cd091, 0x5c43b257, 0xbb39fd5e, + 0x39527ce9, 0xe6577f2f, 0x5ea70323, 0x7025f28d, 0x7cde3939, 0x57b46de8, + 0xf2748efe, 0x03e45703, 0xa3478fcd, 0xe210f9dd, 0x5c407714, 0xbdaae1fc, + 0x14b50f74, 0xde011fef, 0x7f7829b9, 0xa62edffd, 0x0b6d8838, 0xbcf28e78, + 0xa50f1833, 0x2fb5ca0b, 0x24dc8f48, 0x9ba5dfc7, 0xeace9608, 0x061d2270, + 0x8b8045f0, 0x21ebf801, 0x667f4878, 0x1e6266f7, 0x08d61dfa, 0xc6ca3d01, + 0xbc534efa, 0xd0c3407a, 0xbf046c3f, 0x28e1f849, 0x1d532baa, 0xc718bf00, + 0x9bfa22fd, 0xca0ee8d2, 0x7587fceb, 0x60f0df74, 0xb82997cb, 0x8ba6bf7f, + 0x96d295f2, 0x9e31e397, 0x344b358d, 0x78dff83e, 0xdc3d8fba, 0xb6318f12, + 0xe54cbcf2, 0x94eb94cd, 0x28fed172, 0x5f45cbcf, 0x54bfae26, 0xf6c5c8e8, + 0xd453b458, 0x7111701f, 0x1328fb46, 0x2d60ddb8, 0x5089f922, 0x706745be, + 0x25f60bbb, 0x8f11ee97, 0xb15978f2, 0x605f6427, 0x79f1d7bc, 0x261fb70e, + 0x5e14fce5, 0x31bb462d, 0xa4d99d84, 0x41564dd8, 0x06644d79, 0x3ef2b75f, + 0x30f3cb8d, 0xd2be776a, 0x83969b9d, 0x7bf249ef, 0x7d2cf601, 0x1da13ed0, + 0xf23b2449, 0xf61e26a0, 0x60bcf255, 0x14af08dd, 0x802aaf2f, 0xfaad6cee, + 0x2fca029e, 0x19ee9b99, 0x8575d742, 0x7f39997e, 0xd2f3e44b, 0xbcfc3d92, + 0x9f8682f4, 0xf2bd832f, 0x3b5afda1, 0xf500aaa7, 0x72b8eeef, 0xdcb9e06d, + 0xb35fc6d5, 0x5b5f1833, 0x30905551, 0x6c979e84, 0x8a3ed1d8, 0x1d17e10d, + 0xd2f105d5, 0x7595cf95, 0xeb2bd05f, 0x1519a59c, 0x55a58f48, 0xae00a305, + 0xf4b9f88d, 0xd0befbe0, 0xdfa1f3a2, 0xf9d2fa06, 0x575f8de9, 0x5c3f9d04, + 0xe662bc6d, 0xe1c2f3a1, 0xcb0a1fd6, 0xcc69df04, 0x57e818a3, 0xe819e91d, + 0x2f7cc04d, 0xb4fbfeca, 0x9e78a04a, 0x871aad15, 0xac7301f9, 0x6b7e871a, + 0x0c0178b8, 0xdd1568e5, 0x8209ba49, 0x0eb0ae1e, 0xffa50f41, 0xbcfc191d, + 0xaf5945e1, 0x7d2fcf46, 0x9fb420e6, 0x19456c96, 0x5c28a8c0, 0x8945e623, + 0xda183c23, 0x7203be53, 0x036394ed, 0x5f7cab43, 0xbb522858, 0x586459ab, + 0x8d12caa7, 0x57d80c9e, 0xf54edb21, 0x7798f37b, 0xa9791506, 0x3d7f7ebb, + 0x4d7fcfb4, 0xd195bc9c, 0x37e50f7d, 0x330e9105, 0x5fb055c6, 0x4ef43f39, + 0x7e701859, 0x37f647b7, 0xfc814433, 0x14525f40, 0x5dced39d, 0x503cbe5a, + 0x10853b4e, 0x72fa79ba, 0xf5f1bf29, 0x6dd206e5, 0x15516bc9, 0xbcc80e74, + 0xcc049653, 0xaf0672f3, 0x696af89f, 0xb8979d06, 0xd27bf32e, 0x27dbf17c, + 0xd7588f31, 0x80af7906, 0x407ea7e3, 0x2f906675, 0x0dd09c62, 0xcc1ce9f9, + 0x66cc1df5, 0x61387b43, 0xae7be514, 0x7ac30203, 0xae8b6733, 0x9d9bef06, + 0x8c78ae9a, 0xbf34b673, 0xec3f45af, 0x569efc3a, 0x92abbcc2, 0x2637f5c9, + 0x05d7d215, 0x5bbf40ec, 0x01f59cde, 0x93f2b5da, 0x5cb0d4fc, 0x3fdd1efd, + 0xce14b9e2, 0x48d4da57, 0xcc658df7, 0xd65f7247, 0xf6ff9c10, 0x075d0e27, + 0xa76cb2f4, 0xd3ee7c14, 0x225fcf3c, 0xb72f0ab2, 0xce9f148b, 0x73a04c4d, + 0x38f7c1d8, 0xf7626d7d, 0xdb6e7843, 0x0558269b, 0xd237aa18, 0x26e309bd, + 0xc73f2677, 0x85f57ded, 0x7ce86b29, 0xeb0533c4, 0x73e57ba4, 0xec8fb9fc, + 0xeb018b50, 0xebcadb99, 0x59237a17, 0xbbe211d1, 0x23f20c63, 0x92ded52b, + 0xb6967181, 0xf1eb9def, 0xaf8e59de, 0x57b1f743, 0x253e6fbe, 0xbacae9c7, + 0xf32727e7, 0x21e618f3, 0xf3976a39, 0xda0a9b62, 0x4cd3ee03, 0x77528299, + 0x046befc7, 0x9c3e8f7e, 0x17bd617e, 0xbd623bd6, 0x72fdc217, 0x7bd6245d, + 0x5ca2fe21, 0x5ef58917, 0xbdeb1cf8, 0xeb926f10, 0x0bdeb122, 0x42f7ac71, + 0x8bae5478, 0xa54b853c, 0xbfd2eef8, 0x3edb9e61, 0xfc721f10, 0x3e084c74, + 0xe9ffb83a, 0x1f182118, 0x33ff502d, 0xcdfe9775, 0x1675839d, 0xf0dfd926, + 0x9ce50b3a, 0xb670b3ab, 0xb1f20779, 0x3c24c275, 0x69266747, 0xb74bea04, + 0x56ffe7cc, 0x1da02fdb, 0xe47d1160, 0x64c4e797, 0x78bb408f, 0xba62e4f2, + 0xd38feb87, 0x93bc3e91, 0x7ec3e8ee, 0x9e6f98ae, 0xeb06cc3f, 0x265a66e6, + 0xfc029a6f, 0xe4106998, 0x44fb7238, 0x059f72bb, 0xbadd99fc, 0xdb9a8a6a, + 0x994e130b, 0xc6ad962f, 0xe925d771, 0xaa1e6327, 0x1dfc734b, 0x5fe855c7, + 0x19ad7a30, 0x48d76fe7, 0xeabc601f, 0xf3cf13fe, 0xa501fa95, 0x33a927df, + 0xdef099f5, 0x26fa4b5c, 0x2819ebcc, 0x4dbc8a1f, 0x3e501acb, 0x6128aa6c, + 0x4933d923, 0x67d5fb8d, 0x92cefdf2, 0x4f80fdf8, 0x6063a92b, 0xcce45f7c, + 0xdb77cc38, 0x949fbe65, 0xe64a7ef9, 0xcdd1d63b, 0x3a3af351, 0x87475884, + 0x20ea10f0, 0xdd2fbfcc, 0x7149931e, 0xd20a5f72, 0x984ba95d, 0xedc67a87, + 0xf5d20a4f, 0x27c72c90, 0x99d3fb64, 0xefe24f66, 0x54acf8f1, 0x96e81fae, + 0x7d9473cf, 0xbe0def2a, 0xfb05e7cf, 0x6ffee12d, 0x5f645510, 0x5b38e543, + 0x788efb96, 0xbd4abde3, 0x3739c608, 0x261fdc88, 0x41dffaab, 0x6f1c93bb, + 0x90c23694, 0x78a3b3f9, 0x09bd36bf, 0xdb6f6c4d, 0xddce7437, 0x296190fb, + 0x30314fbf, 0x3da11efc, 0xe04d4271, 0xe51fe979, 0x908fc079, 0x9a2cba5e, + 0x3923f61f, 0x423f01c6, 0x144e66f9, 0x9bf923dd, 0xa4fca2bf, 0x09aa75b7, + 0xe1dfd4e5, 0x715fa031, 0xc4ffe3fd, 0xb7f0bfa3, 0x6cf5417e, 0xa4bf6ffe, + 0x722db73a, 0xcdebe1bd, 0x87589d72, 0xbde7c464, 0x60159f85, 0x1c32adbf, + 0x3cfc23b4, 0x686f814f, 0x681de66c, 0x51509ecf, 0x8dd8a2fe, 0x98597d50, + 0xf78e5239, 0x676831ec, 0xc4ec5f40, 0x597d01b7, 0xc1798316, 0x12917da0, + 0x132ea87e, 0xcd598bed, 0xb4420bed, 0xb733662f, 0x7da3882f, 0x05f68841, + 0x417da39f, 0xe20bed1c, 0x47105f68, 0xed1082fb, 0xebff3e0b, 0xd3a75e52, + 0x3f29810b, 0x5c5035c7, 0x7f8ebebf, 0x8dbeb27f, 0xafaddbdf, 0xac0ea816, + 0x94dfe607, 0x509d4439, 0xe4275c93, 0xa2f741dd, 0x15a2c3ae, 0xd6017859, + 0x6dcf09bd, 0xd0277d35, 0x051ab82f, 0xcf84956b, 0xb63ad297, 0x60fd4eb4, + 0xd3af3e39, 0x2fe85558, 0xa3c72f5a, 0xad692bdf, 0x2735ff23, 0xbfcb4da1, + 0x9e181197, 0x71d12f1f, 0xe11728fd, 0x3fba24e9, 0xae5ffb26, 0xad73a0eb, + 0x0a417ad2, 0x35c08efc, 0x7fc512fd, 0xf2b9fdca, 0x57b94bdd, 0xca0ead2f, + 0x6ebc6c9f, 0x4aff718b, 0x9e406579, 0xc3277cab, 0x74d56fc4, 0xc08afe3f, + 0xd7ab8562, 0x36b49573, 0xaffac66e, 0xb4767bd0, 0x16d75424, 0x44febf72, + 0x95d75ca6, 0x6f30f2c7, 0xf5627c2e, 0x5f30c381, 0xe51d76ff, 0x774f609d, + 0x409efea1, 0x9cba0439, 0xb9d3d368, 0xb23be7db, 0xde1f1046, 0xf6489914, + 0xb7d90c72, 0xf2811a75, 0x3597b031, 0xc2ecdef8, 0xceaec8bb, 0xfc8abb06, + 0x93eee454, 0xca2d7b54, 0x1209bae7, 0x1d7cb9f9, 0x93c697bb, 0x9200c5eb, + 0x146fe5de, 0x57c02a3c, 0x2f7d2b31, 0x86c812b4, 0xc6af50f1, 0x75d608f0, + 0xaebc64ad, 0x75a39143, 0x8eef943b, 0x577d10c6, 0xd95cf4c8, 0xb06fc7fa, + 0x1d2ee36e, 0x56490f3f, 0xe4803af1, 0xe7bebcad, 0xf5e0e66e, 0x8b4d9872, + 0xdabd2f94, 0x511dcf05, 0x79f85263, 0xe380948f, 0xa1a53aaf, 0x84fce33a, + 0x8a0e9905, 0xfd50e64f, 0x43bbe086, 0x1f9afefc, 0xeb83878a, 0xec684e37, + 0x3b573df4, 0x73d925ca, 0x9553c107, 0xbb150445, 0xf63fd4ad, 0x88dcbdb6, + 0x0cbbe7f3, 0x62b7a456, 0x83a8ae07, 0xa950e48c, 0x100b1c83, 0xc0cc0aeb, + 0xda0c5363, 0x44ec8967, 0xb273aab2, 0x1bfffb84, 0x3f200eff, 0xe30f2da1, + 0xfc7974a6, 0x43fd92d3, 0x9a2d9fe4, 0xbc3df1b9, 0xf40eda4f, 0x080dc02c, + 0x6d7b2f18, 0x6dbfc622, 0x1a46a982, 0x78ee8eca, 0x5c97eb08, 0x7184c166, + 0xf6e44159, 0xbf1878fc, 0x8ad52d20, 0xccd5dc76, 0x403f2de3, 0x3debf7ce, + 0x55dfc0a2, 0xce9c63c7, 0xea9596f9, 0x351ccee8, 0xacbe7cf8, 0x5fadbd4f, + 0xabe3faf1, 0x38b563c7, 0xade99bbe, 0xc8f8f275, 0x8cd7f9f7, 0x914cb8a5, + 0x8486fe9b, 0xef9b941a, 0x7cbbff65, 0xcc1a7bf9, 0x1cd33b03, 0xaff38dff, + 0xa1e97d58, 0xd0e7da78, 0xd3a9507e, 0x4a83f50f, 0xabfff37c, 0xcaedff3e, + 0x54ef820a, 0x51d8206e, 0x51f6a6e9, 0x735cfc59, 0xfc0ab8b8, 0x10d65c43, + 0xbf4294f1, 0xe4aae221, 0xae3ca9ac, 0x89473cc2, 0xa388aeab, 0x0155df40, + 0x75bb3efa, 0x608f9de4, 0x6b53b3dc, 0xeb0090c5, 0xc81bd7a8, 0x4d64643e, + 0x529e2a1d, 0xf8a069e8, 0x27e99fab, 0x2cb3fce1, 0x1fbc6ae9, 0x0425989f, + 0x3fa80be5, 0x1fd46fb8, 0xea3fa884, 0x39e7b880, 0x14f6a82d, 0x29b82f1e, + 0xbf13d05e, 0x5d815737, 0x662efc01, 0x3d2bb20a, 0x31857621, 0x1d70affb, + 0x9d795a6b, 0x3a5f5297, 0x93d7c00b, 0x5e33b086, 0x46c6676e, 0x3ce1f77a, + 0x54919d63, 0xc3427caf, 0x16c4eee5, 0x9ab82f5e, 0x8ff7f9d9, 0x689bda57, + 0xb15defa4, 0x01fc9f7d, 0xa8f5dffa, 0xcd9ee281, 0xfda66b49, 0xf8cdec4f, + 0x7f0f4e2c, 0xe7de6fa5, 0x22731f20, 0x905cf7f9, 0xee2859bb, 0x7e924555, + 0x8ed97e40, 0x6bac57df, 0x8ed0f211, 0x77d9d1cf, 0x6a9d3ae1, 0x27167ebe, + 0x3baa27df, 0xbf42f78a, 0x2b64f8ce, 0x1263cfe6, 0xffac308f, 0xe61577ca, + 0x64ecbda0, 0xbf7be9db, 0x5dc73a8d, 0x39c5e7c8, 0x7b9d0215, 0x5897faca, + 0x95b35518, 0x153591f8, 0x2708bef9, 0xe6e473a3, 0x2e8f98c5, 0xf1c10a8a, + 0x8dce8b1e, 0x6c78e55f, 0xd2827b48, 0x1cc9e32e, 0x2f356777, 0xd2e573c6, + 0xf3e9bd7a, 0x91cffaa0, 0x39abb841, 0x6079f4c9, 0x03fe2a7d, 0x822daecf, + 0x93dc059a, 0x078e0837, 0x85e53f70, 0x2e39f917, 0x5abf23eb, 0x7d112595, + 0x7ccebd47, 0x737dff28, 0x902e748d, 0x87915b10, 0x472c09e7, 0x52fd8a9a, + 0x17147d34, 0x96ab7ef6, 0x8be8b3bf, 0xef202dbe, 0x7f95be7f, 0xcfca117f, + 0x7b970b3c, 0x0db0d997, 0x8c4ce6f9, 0x7ad82088, 0xa616e289, 0xdef19bb6, + 0x3a0af214, 0x3f7d08b7, 0xb7efc2dd, 0x656b3753, 0x90ff813a, 0x8e337ae4, + 0xc674d9bb, 0x948befaa, 0x266ccae9, 0x866d3ff8, 0xfcffc64a, 0x0113e638, + 0x7fd86dfd, 0x6b5f9db0, 0xf77bef2b, 0x26f8fbbe, 0xca1f3cb3, 0xf1461ad7, + 0xa0f7e873, 0x06625a9f, 0x2e5033ea, 0x53d38b9e, 0xf7583f9e, 0x6ba0ebcf, + 0x7f3d72f5, 0xf83fbd68, 0x8ae7f43b, 0x725f7b9f, 0x52bf1d50, 0xf9d4aff7, + 0xcd2f3127, 0xe027b4a7, 0xda88baed, 0x3847a1db, 0x2193f303, 0x659376e8, + 0x91647fe6, 0x17d9b8de, 0xfee7c1ea, 0x810de8a8, 0xe486727c, 0x66593737, + 0xfbca7bd1, 0xb1661be5, 0x26e3262f, 0xaccc38e5, 0x14e7ff22, 0xd9021bd9, + 0xa28f5e11, 0xec1a77bc, 0x9ff7ce3c, 0x7e11f760, 0x0bfef608, 0xc19fe7a0, + 0x08fc21de, 0xff3e1dec, 0xc21dec04, 0xf803f02e, 0x03f053fc, 0x61dc9708, + 0xe57a829c, 0x5f62ae6a, 0x3b3dd704, 0xd3bfe302, 0x97968733, 0x9e2a598b, + 0xdd0ea5bf, 0xe9e596ae, 0x6f9c8df4, 0x4f3377bd, 0xdfc92a4d, 0x86178c26, + 0xd7b7eefb, 0x5afbedc8, 0x37bc1cf9, 0xb2e7e389, 0x473cfc34, 0xf7c69ec5, + 0x3af066d7, 0x2b8ec539, 0x1fc82af9, 0x63acaf8d, 0x29d79c9c, 0x55663cfd, + 0x0a48f7d0, 0xfde1639c, 0x5f313e48, 0x0d4c7947, 0x44a74f90, 0x172a19f2, + 0x1d385a9f, 0x772e3acc, 0xa09768c9, 0x9e82727f, 0xe361c6e2, 0x51ef90b0, + 0x394f90ae, 0x32c64b1e, 0xf3e1988f, 0xf7aca363, 0x7e3f3a3f, 0x943150d8, + 0x3ff998fd, 0x3e80ffdd, 0x8affef06, 0x8e876b7d, 0xf7db873f, 0xca2bbd40, + 0xc1f610cf, 0xb81f603a, 0xb164dcfc, 0x1d4cb78d, 0x05483bfe, 0xebe0cdae, + 0x6a83e456, 0xc5ee3094, 0xee0fa57d, 0x91fd6067, 0xcb5bfb21, 0x94225ee8, + 0x13df018f, 0x05fafb29, 0x1ba147ae, 0xa38a3e58, 0xa81994c7, 0xc590fbce, + 0x4769efc4, 0x0762b97d, 0xf645feb4, 0xf1507f13, 0x6ec51a7a, 0xc4173c0f, + 0x82730b95, 0x513339ec, 0xfd23ad9c, 0x7bbc41f2, 0x4f7830d0, 0xb7f7eca9, + 0xcbf63eb2, 0x6fffb5f9, 0x8ff65f3c, 0x73dfa3ee, 0xefcd3ff0, 0x9bc460d1, + 0x6eee0eb1, 0xcc253bf9, 0x9e5ad5af, 0xcf21ab37, 0x7d2f7bf6, 0xae01f782, + 0xaa3c4467, 0x9733e262, 0xd3fc5097, 0x7e6131a6, 0xc7e9f1be, 0x9dbca24f, + 0x7424126d, 0xd826fed9, 0x3ba7e636, 0xf43d1e8d, 0xe7e2682f, 0x45eb6b27, + 0xfcff048f, 0x696efe42, 0xfa1a33f6, 0x234d699e, 0xfe3977af, 0x6bca7af4, + 0xcf207acf, 0xc40b7186, 0xbcf1da07, 0xfe39e4be, 0xfb2512bb, 0x1efc5adc, + 0xa05aa4af, 0x97c9537c, 0xaf75e4cb, 0x6c7909d9, 0x30483dd0, 0x14bccc5e, + 0x06d4955f, 0x086b2f3f, 0xb5ef7fce, 0x94d77c0c, 0xf9c8ebc7, 0x3f62acbd, + 0xdcab8caf, 0xfac1a7c4, 0xe3c6bfeb, 0x76d8be79, 0x0353e539, 0xf8ca17c7, + 0xca2fc019, 0xfacaf6e7, 0x62e8fc95, 0x85e29b12, 0x2e313afd, 0x50efe495, + 0xc8aedf81, 0x1f485bae, 0x8c268a8f, 0x8b34b6b3, 0x7967a46e, 0x7d377eab, + 0xf4e78537, 0x3df3a446, 0xc26ff7e4, 0x273c267b, 0x83b67c84, 0xce83a6e4, + 0x6fad99e5, 0xb697dd0d, 0x4fe84de8, 0x683f479d, 0xfd06efc7, 0x57860587, + 0x7cefcaf8, 0xd78679ac, 0xcddfc199, 0x229afdf8, 0x5f006217, 0x436bef91, + 0xc33e2af8, 0x8d35f3f3, 0xdedf2823, 0xf568b4f8, 0x39785ca1, 0x17be157f, + 0x3ce8db88, 0x7c48f805, 0xdd4cfd9e, 0x07289193, 0x05fdf8fb, 0xfdf101c8, + 0x77ce2eec, 0xc443db6d, 0x2cb57f77, 0xf7fc2d07, 0xf8ea4a49, 0x17e81079, + 0xf1abc9f9, 0x5f7c6aff, 0x7c83db20, 0x3889c671, 0xe5ef778c, 0xe988adf3, + 0x9a07bf2e, 0x20bb993e, 0x7975f515, 0x26c6eee1, 0x07891980, 0xce621999, + 0x51db3a53, 0x5cb9e04b, 0x79d79e9b, 0xca045103, 0x4bfae433, 0x53dd4ce9, + 0x5e47af68, 0xfe31f143, 0xf79c0445, 0x60cf3f00, 0xb23bd09e, 0xd8cbc0fb, + 0x7e8e946f, 0x55bca58f, 0xa2e5d3e7, 0x9bf2e45f, 0x715bedaf, 0xafddc60f, + 0x433ee8ea, 0x45dff1b0, 0xe3fd6d28, 0xc84f7887, 0x416df29a, 0xff209bbf, + 0xfe2941ae, 0x37b602ae, 0xe8067a68, 0x3fa6ed80, 0x165d7bd1, 0x9e92875e, + 0x71848370, 0xcc65c6ec, 0x943e9911, 0xe764679d, 0x8729ef95, 0x3986c38d, + 0x2fe2506f, 0x12331ee6, 0x7df94cf5, 0xad0ec505, 0x3c5bbf95, 0x7529df71, + 0x96afd22c, 0x714c8eff, 0x389fd82b, 0x7922df3a, 0x38aee73b, 0xbf9782a2, + 0x468ab944, 0x0e68fab9, 0xc7db2ff6, 0x3c0683fb, 0xdf871919, 0x4f286b29, + 0x7937d01b, 0xa3df867c, 0x05f3bb40, 0x0ea6c581, 0xab6a2f61, 0x421e8f37, + 0x2e214a6e, 0xca8745c3, 0xb829b38f, 0x768377df, 0xf8f7c264, 0x9726567d, + 0x662cf72f, 0x0d5ffdc1, 0x40d8f92a, 0x947e067e, 0x19e660ea, 0xc972df29, + 0xd5ced2e7, 0x51273a26, 0xed538dfc, 0xf299b33d, 0x43972332, 0x63dfa335, + 0xb68d54e9, 0xef380d6e, 0x4e979ce8, 0x6fc59fdf, 0xdc70faf4, 0xb58205be, + 0x44e69a06, 0x5f2efcf1, 0x0bdb2f65, 0xb8a86fed, 0xf30e7ddf, 0x17fd1137, + 0xff419397, 0x93cfcfc6, 0x7f3c8d0b, 0x9adca8f3, 0xa61df489, 0xdd94eb1b, + 0x2bd52d76, 0x1d291ced, 0x677c0268, 0xefd90e71, 0x73f1df23, 0x5a65bef4, + 0xf33bf3f2, 0xae51cbec, 0x4f1b2e77, 0xd208afed, 0xe33f7863, 0x7da48e2e, + 0xcfc85cec, 0x4c2e771b, 0x5967f6a4, 0xdf1a955f, 0xd9fbe6ab, 0x3a04d8f9, + 0x39d38dff, 0xbef1b372, 0xd8c7be58, 0xc24b6a99, 0x0527d37a, 0x71bbb2fb, + 0x1a0609bc, 0xe24590ef, 0xc6cb12f7, 0xe907b63f, 0x8a9a4634, 0x7e0fdb76, + 0x7ff00def, 0x4dd86c7f, 0xf71732f5, 0xc705b99f, 0xe4057d2f, 0x37f7c60f, + 0xebbe8318, 0x66efbe57, 0xc5b4df6a, 0xb0bf40c6, 0xbcb5d791, 0xeaf6e464, + 0x3373cea0, 0xe4725fbc, 0xebb45cb3, 0xdafb07fe, 0xdaee3193, 0x243af02f, + 0xde2e5777, 0x87a89647, 0xce6faf8e, 0x4f4bf1e6, 0x8c52d44b, 0x63fa84e7, + 0xe252df54, 0xe7435dbd, 0xd9bf7254, 0x866e3cd9, 0xed1f747e, 0xdfc827de, + 0x05a6f8bb, 0x752b5bde, 0xb8fb3dcd, 0x6b34951c, 0x92e47be8, 0x51ff46fa, + 0x59d43fc4, 0xf55d7c51, 0x783ee897, 0xe8074bf6, 0x3fef02de, 0x473a08de, + 0x3b39dfe6, 0xaae63b65, 0x395ec917, 0x77f9ca9b, 0x19e2f55f, 0xd28fbdc2, + 0xf15d34ef, 0x27731d5d, 0x5f4912ab, 0x29e6b193, 0xa5f4bdb4, 0x206e23b6, + 0xbda1e961, 0x2ee7e8d1, 0x2345d474, 0x55dc61dd, 0x5e7c11da, 0x2b883dfc, + 0x7d05b5c7, 0x6ef2e69f, 0x02ebc4b9, 0x845fc8bb, 0xff80bff6, 0x6f7f3f00, + 0xd91dfcb6, 0xf25aecb5, 0x14b1f5ff, 0xa6fac157, 0x13b77e05, 0x0f4bffea, + 0x0dde7e5c, 0xbb073ded, 0x96f5c79f, 0xd515f77d, 0xf557b123, 0xdae6b754, + 0x73f93eff, 0xcd7fbde5, 0x7fa871e6, 0x583ddedf, 0x2fffea97, 0xf347159d, + 0x22997db7, 0xe36839e1, 0xf10f7437, 0xfa7cb69b, 0x8737e6de, 0xd0fc2767, + 0xb7281177, 0x75c0cc9e, 0x92bf8879, 0xac503bfc, 0xfc218655, 0x3c74de3a, + 0x1179d705, 0xba754df8, 0x72f73f12, 0xbee9cb7a, 0x8007f101, 0x8786cebe, + 0xb8ffa12f, 0x4d9cff1a, 0x61bd6f8b, 0x2b43d90a, 0xf58b95aa, 0xe87ffdd1, + 0xfb7c037b, 0xc4e3e04f, 0x86bfc11f, 0x70ff342d, 0xff88bbfc, 0x081d3e00, + 0xa6e5dfe1, 0xeb1dffbb, 0x6c535968, 0x8128f7d0, 0x08fdf374, 0x7c0915ba, + 0xdb66dffc, 0xf4bed19a, 0x0f617c1c, 0xdf2309d6, 0x2eb0966e, 0x330a72ed, + 0x7d30f7e2, 0x697f282b, 0xaed099d3, 0x407db495, 0xeb97e3fa, 0x80cfe029, + 0x06cfce7e, 0x2fc83afe, 0x55d9b6c9, 0xa2e9f46b, 0xf4efe907, 0xa2942c2c, + 0x7a19f9e9, 0x8c72e1ee, 0x2ddfc3f4, 0xdd8e7a73, 0x97c10c26, 0x9e34ecde, + 0xd1467927, 0xff6bcbbe, 0x00c0e3c2, 0x91d3097e, 0x6e28674f, 0x0a4f8e1c, + 0xeff24c1d, 0xadf00d88, 0x685feb96, 0x87f0177f, 0x7e653fee, 0xf7f0ff21, + 0xceb85cd4, 0x20cf8e68, 0x0d80f85c, 0xd5fc0f61, 0xfce3ca3a, 0x83c9f721, + 0xd79079fc, 0xa9ea855d, 0xf4e1cfbc, 0xabd3d143, 0xd2a7ffad, 0x52d92fe7, + 0x7428bc90, 0x6876f9ea, 0xcf1c6e3b, 0x9f67fef5, 0x3504da3f, 0x7f3a0f8b, + 0xf3c78c34, 0x4133a6c7, 0x7eca8fe7, 0xda73e47b, 0xf922fd9e, 0xeff2cdc7, + 0x0bda84ac, 0xd0983be5, 0xd7938ef5, 0x7f7f94eb, 0xd1a0e7a1, 0x7a718063, + 0x79216f5e, 0xd19c3676, 0x7b6a79e2, 0x9efa21fd, 0xf41fd14e, 0xf5809e13, + 0x2c78bcf7, 0xce36ec97, 0x275f0433, 0x33cf978c, 0xc79e875b, 0x682970d5, + 0x57b7529e, 0x57ab754b, 0xda82ef99, 0x778e3b76, 0x7eff83a1, 0xd0ef05e1, + 0xf1a6a9e7, 0x615cf91a, 0x2fe0873b, 0xbcfe01ed, 0x1b4db053, 0xc30c2a3f, + 0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0x0c30c30c, 0xc30c30c3, + 0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0x0c30c30c, 0xc30c30c3, + 0x30c30c30, 0x0c30c30c, 0xc30c30c3, 0x30c30c30, 0xc1b7ff0c, 0x8dca0bff, + 0x8000e737, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, + 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, + 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, + 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, + 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, + 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, + 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, + 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, + 0x8000dcb1, 0x00008000, 0x00088b1f, 0x00000000, 0xc5edff00, 0x20000131, + 0x22b0030c, 0xb0131302, 0x14e7ff1b, 0x93c9084d, 0x26ebaf39, 0x6db6db63, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, + 0xdb6db6db, 0xb6db6db6, 0x6db6db6d, 0xdb6db6db, 0xf6db6db6, 0x10192fc7, + 0x8000dcb1, 0x00008000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0x00100000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0x00100000, 0x00000000, 0xfffffff3, 0x314fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, + 0xfffffff1, 0x30efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, + 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, + 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x31efffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, + 0xfffffff5, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x310fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, + 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, + 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, + 0xfffffffa, 0x302fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0010cf3c, 0xcdcdcdcd, 0xfffffff7, 0x30efffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x304fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, + 0xfffffff3, 0x31efffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0000cf3c, 0xcdcdcdcd, 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, + 0xfffff406, 0x1cbfffff, 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, + 0x0004cf3c, 0xcdcdcdcd, 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xfffffffa, 0x302fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, + 0xffffff97, 0x056fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, + 0x0020cf3c, 0xcdcdcdcd, 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xfffffff3, 0x320fffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, + 0xfffffff1, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0001cf3c, 0xcdcdcdcd, 0xfffffff6, 0x305fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf300, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xfffff406, 0x1cbfffff, + 0x0c30c305, 0xc30c30c3, 0xcf300014, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, + 0xfffffff2, 0x304fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0008cf3c, 0xcdcdcdcd, 0xffffff8a, 0x042fffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cc000, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffff97, 0x05cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cc000, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, + 0xfffffff5, 0x310fffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf300, 0xf3cf3cf3, + 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0001cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0008cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0040cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0000cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0001cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0002cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0004cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0008cf3c, 0xcdcdcdcd, + 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, + 0x0010cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, 0x0c30c30c, 0xc30c30c3, + 0xcf3cf3cc, 0xf3cf3cf3, 0x0020cf3c, 0xcdcdcdcd, 0xffffffff, 0x30cfffff, + 0x0c30c30c, 0xc30c30c3, 0xcf3cf3cc, 0xf3cf3cf3, 0x0040cf3c, 0xcdcdcdcd, + 0x000a0000, 0x000700a0, 0x00028110, 0x000b8138, 0x000201f0, 0x00010210, + 0x000f0220, 0x00010310, 0x00080000, 0x00080080, 0x00028100, 0x000b8128, + 0x000201e0, 0x00010200, 0x00070210, 0x00020280, 0x000f0000, 0x000800f0, + 0x00028170, 0x000b8198, 0x00020250, 0x00010270, 0x000b8280, 0x00080338, + 0x00100000, 0x00080100, 0x00028180, 0x000b81a8, 0x00020260, 0x00018280, + 0x000e8298, 0x00080380, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, + 0x00002000, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000, + 0xcccccccc, 0xcccccccc, 0xcccccccc, 0xcccccccc, 0x00002000 +}; + +#endif /*__BNX2X_INIT_VALUES_H__*/ diff --git a/drivers/net/bnx2x_reg.h b/drivers/net/bnx2x_reg.h new file mode 100644 index 000000000000..86055297ab02 --- /dev/null +++ b/drivers/net/bnx2x_reg.h @@ -0,0 +1,4394 @@ +/* bnx2x_reg.h: Broadcom Everest network driver. + * + * Copyright (c) 2007 Broadcom Corporation + * + * 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. + * + * The registers description starts with the regsister Access type followed + * by size in bits. For example [RW 32]. The access types are: + * R - Read only + * RC - Clear on read + * RW - Read/Write + * ST - Statistics register (clear on read) + * W - Write only + * WB - Wide bus register - the size is over 32 bits and it should be + * read/write in consecutive 32 bits accesses + * WR - Write Clear (write 1 to clear the bit) + * + */ + + +/* [R 19] Interrupt register #0 read */ +#define BRB1_REG_BRB1_INT_STS 0x6011c +/* [RW 4] Parity mask register #0 read/write */ +#define BRB1_REG_BRB1_PRTY_MASK 0x60138 +/* [RW 10] At address BRB1_IND_FREE_LIST_PRS_CRDT initialize free head. At + address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address + BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. */ +#define BRB1_REG_FREE_LIST_PRS_CRDT 0x60200 +/* [RW 23] LL RAM data. */ +#define BRB1_REG_LL_RAM 0x61000 +/* [R 24] The number of full blocks. */ +#define BRB1_REG_NUM_OF_FULL_BLOCKS 0x60090 +/* [ST 32] The number of cycles that the write_full signal towards MAC #0 + was asserted. */ +#define BRB1_REG_NUM_OF_FULL_CYCLES_0 0x600c8 +#define BRB1_REG_NUM_OF_FULL_CYCLES_1 0x600cc +#define BRB1_REG_NUM_OF_FULL_CYCLES_2 0x600d0 +#define BRB1_REG_NUM_OF_FULL_CYCLES_3 0x600d4 +#define BRB1_REG_NUM_OF_FULL_CYCLES_4 0x600d8 +/* [ST 32] The number of cycles that the pause signal towards MAC #0 was + asserted. */ +#define BRB1_REG_NUM_OF_PAUSE_CYCLES_0 0x600b8 +#define BRB1_REG_NUM_OF_PAUSE_CYCLES_1 0x600bc +#define BRB1_REG_NUM_OF_PAUSE_CYCLES_2 0x600c0 +#define BRB1_REG_NUM_OF_PAUSE_CYCLES_3 0x600c4 +/* [RW 10] Write client 0: De-assert pause threshold. */ +#define BRB1_REG_PAUSE_HIGH_THRESHOLD_0 0x60078 +#define BRB1_REG_PAUSE_HIGH_THRESHOLD_1 0x6007c +/* [RW 10] Write client 0: Assert pause threshold. */ +#define BRB1_REG_PAUSE_LOW_THRESHOLD_0 0x60068 +#define BRB1_REG_PAUSE_LOW_THRESHOLD_1 0x6006c +/* [RW 1] Reset the design by software. */ +#define BRB1_REG_SOFT_RESET 0x600dc +/* [R 5] Used to read the value of the XX protection CAM occupancy counter. */ +#define CCM_REG_CAM_OCCUP 0xd0188 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_CFC_IFEN 0xd003c +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_CQM_IFEN 0xd000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. + Otherwise 0 is inserted. */ +#define CCM_REG_CCM_CQM_USE_Q 0xd00c0 +/* [RW 11] Interrupt mask register #0 read/write */ +#define CCM_REG_CCM_INT_MASK 0xd01e4 +/* [R 11] Interrupt register #0 read */ +#define CCM_REG_CCM_INT_STS 0xd01d8 +/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the input message Reg1WbFlg isn't set. */ +#define CCM_REG_CCM_REG0_SZ 0xd00c4 +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_STORM0_IFEN 0xd0004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_STORM1_IFEN 0xd0008 +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define CCM_REG_CDU_AG_RD_IFEN 0xd0030 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define CCM_REG_CDU_AG_WR_IFEN 0xd002c +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define CCM_REG_CDU_SM_RD_IFEN 0xd0038 +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define CCM_REG_CDU_SM_WR_IFEN 0xd0034 +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define CCM_REG_CFC_INIT_CRD 0xd0204 +/* [RW 2] Auxillary counter flag Q number 1. */ +#define CCM_REG_CNT_AUX1_Q 0xd00c8 +/* [RW 2] Auxillary counter flag Q number 2. */ +#define CCM_REG_CNT_AUX2_Q 0xd00cc +/* [RW 28] The CM header value for QM request (primary). */ +#define CCM_REG_CQM_CCM_HDR_P 0xd008c +/* [RW 28] The CM header value for QM request (secondary). */ +#define CCM_REG_CQM_CCM_HDR_S 0xd0090 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CQM_CCM_IFEN 0xd0014 +/* [RW 6] QM output initial credit. Max credit available - 32. Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define CCM_REG_CQM_INIT_CRD 0xd020c +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_CQM_P_WEIGHT 0xd00b8 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CSDM_IFEN 0xd0018 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the SDM interface is detected. */ +#define CCM_REG_CSDM_LENGTH_MIS 0xd0170 +/* [RW 28] The CM header for QM formatting in case of an error in the QM + inputs. */ +#define CCM_REG_ERR_CCM_HDR 0xd0094 +/* [RW 8] The Event ID in case the input message ErrorFlg is set. */ +#define CCM_REG_ERR_EVNT_ID 0xd0098 +/* [RW 8] FIC0 output initial credit. Max credit available - 255. Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define CCM_REG_FIC0_INIT_CRD 0xd0210 +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define CCM_REG_FIC1_INIT_CRD 0xd0214 +/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~ccm_registers_gr_ag_pr.gr_ag_pr; + ~ccm_registers_gr_ld0_pr.gr_ld0_pr and + ~ccm_registers_gr_ld1_pr.gr_ld1_pr. Groups are according to channels and + outputs to STORM: aggregation; load FIC0; load FIC1 and store. */ +#define CCM_REG_GR_ARB_TYPE 0xd015c +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed; that the Store channel priority is + the compliment to 4 of the rest priorities - Aggregation channel; Load + (FIC0) channel and Load (FIC1). */ +#define CCM_REG_GR_LD0_PR 0xd0164 +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed; that the Store channel priority is + the compliment to 4 of the rest priorities - Aggregation channel; Load + (FIC0) channel and Load (FIC1). */ +#define CCM_REG_GR_LD1_PR 0xd0168 +/* [RW 2] General flags index. */ +#define CCM_REG_INV_DONE_Q 0xd0108 +/* [RW 4] The number of double REG-pairs(128 bits); loaded from the STORM + context and sent to STORM; for a specific connection type. The double + REG-pairs are used in order to align to STORM context row size of 128 + bits. The offset of these data in the STORM context is always 0. Index + _(0..15) stands for the connection type (one of 16). */ +#define CCM_REG_N_SM_CTX_LD_0 0xd004c +#define CCM_REG_N_SM_CTX_LD_1 0xd0050 +#define CCM_REG_N_SM_CTX_LD_10 0xd0074 +#define CCM_REG_N_SM_CTX_LD_11 0xd0078 +#define CCM_REG_N_SM_CTX_LD_12 0xd007c +#define CCM_REG_N_SM_CTX_LD_13 0xd0080 +#define CCM_REG_N_SM_CTX_LD_14 0xd0084 +#define CCM_REG_N_SM_CTX_LD_15 0xd0088 +#define CCM_REG_N_SM_CTX_LD_2 0xd0054 +#define CCM_REG_N_SM_CTX_LD_3 0xd0058 +#define CCM_REG_N_SM_CTX_LD_4 0xd005c +/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_PBF_IFEN 0xd0028 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the pbf interface is detected. */ +#define CCM_REG_PBF_LENGTH_MIS 0xd0180 +/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_PBF_WEIGHT 0xd00ac +/* [RW 6] The physical queue number of queue number 1 per port index. */ +#define CCM_REG_PHYS_QNUM1_0 0xd0134 +#define CCM_REG_PHYS_QNUM1_1 0xd0138 +/* [RW 6] The physical queue number of queue number 2 per port index. */ +#define CCM_REG_PHYS_QNUM2_0 0xd013c +#define CCM_REG_PHYS_QNUM2_1 0xd0140 +/* [RW 6] The physical queue number of queue number 3 per port index. */ +#define CCM_REG_PHYS_QNUM3_0 0xd0144 +/* [RW 6] The physical queue number of queue number 0 with QOS equal 0 port + index 0. */ +#define CCM_REG_QOS_PHYS_QNUM0_0 0xd0114 +#define CCM_REG_QOS_PHYS_QNUM0_1 0xd0118 +/* [RW 6] The physical queue number of queue number 0 with QOS equal 1 port + index 0. */ +#define CCM_REG_QOS_PHYS_QNUM1_0 0xd011c +#define CCM_REG_QOS_PHYS_QNUM1_1 0xd0120 +/* [RW 6] The physical queue number of queue number 0 with QOS equal 2 port + index 0. */ +#define CCM_REG_QOS_PHYS_QNUM2_0 0xd0124 +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_STORM_CCM_IFEN 0xd0010 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the STORM interface is detected. */ +#define CCM_REG_STORM_LENGTH_MIS 0xd016c +/* [RW 1] Input tsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_TSEM_IFEN 0xd001c +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the tsem interface is detected. */ +#define CCM_REG_TSEM_LENGTH_MIS 0xd0174 +/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_TSEM_WEIGHT 0xd00a0 +/* [RW 1] Input usem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_USEM_IFEN 0xd0024 +/* [RC 1] Set when message length mismatch (relative to last indication) at + the usem interface is detected. */ +#define CCM_REG_USEM_LENGTH_MIS 0xd017c +/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_USEM_WEIGHT 0xd00a8 +/* [RW 1] Input xsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_XSEM_IFEN 0xd0020 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the xsem interface is detected. */ +#define CCM_REG_XSEM_LENGTH_MIS 0xd0178 +/* [RW 3] The weight of the input xsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_XSEM_WEIGHT 0xd00a4 +/* [RW 19] Indirect access to the descriptor table of the XX protection + mechanism. The fields are: [5:0] - message length; [12:6] - message + pointer; 18:13] - next pointer. */ +#define CCM_REG_XX_DESCR_TABLE 0xd0300 +/* [R 7] Used to read the value of XX protection Free counter. */ +#define CCM_REG_XX_FREE 0xd0184 +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Max credit available - 127. Write writes the initial credit + value; read returns the current value of the credit counter. Must be + initialized to maximum XX protected message size - 2 at start-up. */ +#define CCM_REG_XX_INIT_CRD 0xd0220 +/* [RW 7] The maximum number of pending messages; which may be stored in XX + protection. At read the ~ccm_registers_xx_free.xx_free counter is read. + At write comprises the start value of the ~ccm_registers_xx_free.xx_free + counter. */ +#define CCM_REG_XX_MSG_NUM 0xd0224 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define CCM_REG_XX_OVFL_EVNT_ID 0xd0044 +/* [RW 18] Indirect access to the XX table of the XX protection mechanism. + The fields are: [5:0] - tail pointer; 11:6] - Link List size; 17:12] - + header pointer. */ +#define CCM_REG_XX_TABLE 0xd0280 +#define CDU_REG_CDU_CHK_MASK0 0x101000 +#define CDU_REG_CDU_CHK_MASK1 0x101004 +#define CDU_REG_CDU_CONTROL0 0x101008 +#define CDU_REG_CDU_DEBUG 0x101010 +#define CDU_REG_CDU_GLOBAL_PARAMS 0x101020 +/* [RW 7] Interrupt mask register #0 read/write */ +#define CDU_REG_CDU_INT_MASK 0x10103c +/* [R 7] Interrupt register #0 read */ +#define CDU_REG_CDU_INT_STS 0x101030 +/* [RW 5] Parity mask register #0 read/write */ +#define CDU_REG_CDU_PRTY_MASK 0x10104c +/* [RC 32] logging of error data in case of a CDU load error: + {expected_cid[15:0]; xpected_type[2:0]; xpected_region[2:0]; ctive_error; + ype_error; ctual_active; ctual_compressed_context}; */ +#define CDU_REG_ERROR_DATA 0x101014 +/* [WB 216] L1TT ram access. each entry has the following format : + {mrege_regions[7:0]; ffset12[5:0]...offset0[5:0]; + ength12[5:0]...length0[5:0]; d12[3:0]...id0[3:0]} */ +#define CDU_REG_L1TT 0x101800 +/* [WB 24] MATT ram access. each entry has the following + format:{RegionLength[11:0]; egionOffset[11:0]} */ +#define CDU_REG_MATT 0x101100 +/* [R 1] indication the initializing the activity counter by the hardware + was done. */ +#define CFC_REG_AC_INIT_DONE 0x104078 +/* [RW 13] activity counter ram access */ +#define CFC_REG_ACTIVITY_COUNTER 0x104400 +#define CFC_REG_ACTIVITY_COUNTER_SIZE 256 +/* [R 1] indication the initializing the cams by the hardware was done. */ +#define CFC_REG_CAM_INIT_DONE 0x10407c +/* [RW 2] Interrupt mask register #0 read/write */ +#define CFC_REG_CFC_INT_MASK 0x104108 +/* [R 2] Interrupt register #0 read */ +#define CFC_REG_CFC_INT_STS 0x1040fc +/* [RC 2] Interrupt register #0 read clear */ +#define CFC_REG_CFC_INT_STS_CLR 0x104100 +/* [RW 4] Parity mask register #0 read/write */ +#define CFC_REG_CFC_PRTY_MASK 0x104118 +/* [RW 21] CID cam access (21:1 - Data; alid - 0) */ +#define CFC_REG_CID_CAM 0x104800 +#define CFC_REG_CONTROL0 0x104028 +#define CFC_REG_DEBUG0 0x104050 +/* [RW 14] indicates per error (in #cfc_registers_cfc_error_vector.cfc_error + vector) whether the cfc should be disabled upon it */ +#define CFC_REG_DISABLE_ON_ERROR 0x104044 +/* [RC 14] CFC error vector. when the CFC detects an internal error it will + set one of these bits. the bit description can be found in CFC + specifications */ +#define CFC_REG_ERROR_VECTOR 0x10403c +#define CFC_REG_INIT_REG 0x10404c +/* [RW 24] {weight_load_client7[2:0] to weight_load_client0[2:0]}. this + field allows changing the priorities of the weighted-round-robin arbiter + which selects which CFC load client should be served next */ +#define CFC_REG_LCREQ_WEIGHTS 0x104084 +/* [R 1] indication the initializing the link list by the hardware was done. */ +#define CFC_REG_LL_INIT_DONE 0x104074 +/* [R 9] Number of allocated LCIDs which are at empty state */ +#define CFC_REG_NUM_LCIDS_ALLOC 0x104020 +/* [R 9] Number of Arriving LCIDs in Link List Block */ +#define CFC_REG_NUM_LCIDS_ARRIVING 0x104004 +/* [R 9] Number of Inside LCIDs in Link List Block */ +#define CFC_REG_NUM_LCIDS_INSIDE 0x104008 +/* [R 9] Number of Leaving LCIDs in Link List Block */ +#define CFC_REG_NUM_LCIDS_LEAVING 0x104018 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define CSDM_REG_AGG_INT_EVENT_0 0xc2038 +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define CSDM_REG_CFC_RSP_START_ADDR 0xc2008 +/* [RW 16] The maximum value of the competion counter #0 */ +#define CSDM_REG_CMP_COUNTER_MAX0 0xc201c +/* [RW 16] The maximum value of the competion counter #1 */ +#define CSDM_REG_CMP_COUNTER_MAX1 0xc2020 +/* [RW 16] The maximum value of the competion counter #2 */ +#define CSDM_REG_CMP_COUNTER_MAX2 0xc2024 +/* [RW 16] The maximum value of the competion counter #3 */ +#define CSDM_REG_CMP_COUNTER_MAX3 0xc2028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define CSDM_REG_CMP_COUNTER_START_ADDR 0xc200c +/* [RW 32] Interrupt mask register #0 read/write */ +#define CSDM_REG_CSDM_INT_MASK_0 0xc229c +#define CSDM_REG_CSDM_INT_MASK_1 0xc22ac +/* [RW 11] Parity mask register #0 read/write */ +#define CSDM_REG_CSDM_PRTY_MASK 0xc22bc +#define CSDM_REG_ENABLE_IN1 0xc2238 +#define CSDM_REG_ENABLE_IN2 0xc223c +#define CSDM_REG_ENABLE_OUT1 0xc2240 +#define CSDM_REG_ENABLE_OUT2 0xc2244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define CSDM_REG_INIT_CREDIT_PXP_CTRL 0xc24bc +/* [ST 32] The number of ACK after placement messages received */ +#define CSDM_REG_NUM_OF_ACK_AFTER_PLACE 0xc227c +/* [ST 32] The number of packet end messages received from the parser */ +#define CSDM_REG_NUM_OF_PKT_END_MSG 0xc2274 +/* [ST 32] The number of requests received from the pxp async if */ +#define CSDM_REG_NUM_OF_PXP_ASYNC_REQ 0xc2278 +/* [ST 32] The number of commands received in queue 0 */ +#define CSDM_REG_NUM_OF_Q0_CMD 0xc2248 +/* [ST 32] The number of commands received in queue 10 */ +#define CSDM_REG_NUM_OF_Q10_CMD 0xc226c +/* [ST 32] The number of commands received in queue 11 */ +#define CSDM_REG_NUM_OF_Q11_CMD 0xc2270 +/* [ST 32] The number of commands received in queue 1 */ +#define CSDM_REG_NUM_OF_Q1_CMD 0xc224c +/* [ST 32] The number of commands received in queue 3 */ +#define CSDM_REG_NUM_OF_Q3_CMD 0xc2250 +/* [ST 32] The number of commands received in queue 4 */ +#define CSDM_REG_NUM_OF_Q4_CMD 0xc2254 +/* [ST 32] The number of commands received in queue 5 */ +#define CSDM_REG_NUM_OF_Q5_CMD 0xc2258 +/* [ST 32] The number of commands received in queue 6 */ +#define CSDM_REG_NUM_OF_Q6_CMD 0xc225c +/* [ST 32] The number of commands received in queue 7 */ +#define CSDM_REG_NUM_OF_Q7_CMD 0xc2260 +/* [ST 32] The number of commands received in queue 8 */ +#define CSDM_REG_NUM_OF_Q8_CMD 0xc2264 +/* [ST 32] The number of commands received in queue 9 */ +#define CSDM_REG_NUM_OF_Q9_CMD 0xc2268 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define CSDM_REG_Q_COUNTER_START_ADDR 0xc2010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define CSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0xc2548 +/* [R 1] parser fifo empty in sdm_sync block */ +#define CSDM_REG_SYNC_PARSER_EMPTY 0xc2550 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define CSDM_REG_SYNC_SYNC_EMPTY 0xc2558 +/* [RW 32] Tick for timer counter. Applicable only when + ~csdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define CSDM_REG_TIMER_TICK 0xc2000 +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define CSEM_REG_ARB_CYCLE_SIZE 0x200034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define CSEM_REG_ARB_ELEMENT0 0x200020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~csem_registers_arb_element0.arb_element0 */ +#define CSEM_REG_ARB_ELEMENT1 0x200024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~csem_registers_arb_element0.arb_element0 + and ~csem_registers_arb_element1.arb_element1 */ +#define CSEM_REG_ARB_ELEMENT2 0x200028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~csem_registers_arb_element0.arb_element0 and + ~csem_registers_arb_element1.arb_element1 and + ~csem_registers_arb_element2.arb_element2 */ +#define CSEM_REG_ARB_ELEMENT3 0x20002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~csem_registers_arb_element0.arb_element0 + and ~csem_registers_arb_element1.arb_element1 and + ~csem_registers_arb_element2.arb_element2 and + ~csem_registers_arb_element3.arb_element3 */ +#define CSEM_REG_ARB_ELEMENT4 0x200030 +/* [RW 32] Interrupt mask register #0 read/write */ +#define CSEM_REG_CSEM_INT_MASK_0 0x200110 +#define CSEM_REG_CSEM_INT_MASK_1 0x200120 +/* [RW 32] Parity mask register #0 read/write */ +#define CSEM_REG_CSEM_PRTY_MASK_0 0x200130 +#define CSEM_REG_CSEM_PRTY_MASK_1 0x200140 +#define CSEM_REG_ENABLE_IN 0x2000a4 +#define CSEM_REG_ENABLE_OUT 0x2000a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the SEM_FAST registers the base address + CSEM_REGISTERS_FAST_MEMORY (Offset: 0x220000) should be added to each + SEM_FAST register offset. */ +#define CSEM_REG_FAST_MEMORY 0x220000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define CSEM_REG_FIC0_DISABLE 0x200224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define CSEM_REG_FIC1_DISABLE 0x200234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define CSEM_REG_INT_TABLE 0x200400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define CSEM_REG_MSG_NUM_FIC0 0x200000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define CSEM_REG_MSG_NUM_FIC1 0x200004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define CSEM_REG_MSG_NUM_FOC0 0x200008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define CSEM_REG_MSG_NUM_FOC1 0x20000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define CSEM_REG_MSG_NUM_FOC2 0x200010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define CSEM_REG_MSG_NUM_FOC3 0x200014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define CSEM_REG_PAS_DISABLE 0x20024c +/* [WB 128] Debug only. Passive buffer memory */ +#define CSEM_REG_PASSIVE_BUFFER 0x202000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define CSEM_REG_PRAM 0x240000 +/* [R 16] Valid sleeping threads indication have bit per thread */ +#define CSEM_REG_SLEEP_THREADS_VALID 0x20026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define CSEM_REG_SLOW_EXT_STORE_EMPTY 0x2002a0 +/* [RW 16] List of free threads . There is a bit per thread. */ +#define CSEM_REG_THREADS_LIST 0x2002e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define CSEM_REG_TS_0_AS 0x200038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define CSEM_REG_TS_10_AS 0x200060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define CSEM_REG_TS_11_AS 0x200064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define CSEM_REG_TS_12_AS 0x200068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define CSEM_REG_TS_13_AS 0x20006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define CSEM_REG_TS_14_AS 0x200070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define CSEM_REG_TS_15_AS 0x200074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define CSEM_REG_TS_16_AS 0x200078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define CSEM_REG_TS_17_AS 0x20007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define CSEM_REG_TS_18_AS 0x200080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define CSEM_REG_TS_1_AS 0x20003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define CSEM_REG_TS_2_AS 0x200040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define CSEM_REG_TS_3_AS 0x200044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define CSEM_REG_TS_4_AS 0x200048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define CSEM_REG_TS_5_AS 0x20004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define CSEM_REG_TS_6_AS 0x200050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define CSEM_REG_TS_7_AS 0x200054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define CSEM_REG_TS_8_AS 0x200058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define CSEM_REG_TS_9_AS 0x20005c +/* [RW 1] Parity mask register #0 read/write */ +#define DBG_REG_DBG_PRTY_MASK 0xc0a8 +/* [RW 2] debug only: These bits indicate the credit for PCI request type 4 + interface; MUST be configured AFTER pci_ext_buffer_strt_addr_lsb/msb are + configured */ +#define DBG_REG_PCI_REQ_CREDIT 0xc120 +/* [RW 32] Commands memory. The address to command X; row Y is to calculated + as 14*X+Y. */ +#define DMAE_REG_CMD_MEM 0x102400 +/* [RW 1] If 0 - the CRC-16c initial value is all zeroes; if 1 - the CRC-16c + initial value is all ones. */ +#define DMAE_REG_CRC16C_INIT 0x10201c +/* [RW 1] If 0 - the CRC-16 T10 initial value is all zeroes; if 1 - the + CRC-16 T10 initial value is all ones. */ +#define DMAE_REG_CRC16T10_INIT 0x102020 +/* [RW 2] Interrupt mask register #0 read/write */ +#define DMAE_REG_DMAE_INT_MASK 0x102054 +/* [RW 4] Parity mask register #0 read/write */ +#define DMAE_REG_DMAE_PRTY_MASK 0x102064 +/* [RW 1] Command 0 go. */ +#define DMAE_REG_GO_C0 0x102080 +/* [RW 1] Command 1 go. */ +#define DMAE_REG_GO_C1 0x102084 +/* [RW 1] Command 10 go. */ +#define DMAE_REG_GO_C10 0x102088 +#define DMAE_REG_GO_C10_SIZE 1 +/* [RW 1] Command 11 go. */ +#define DMAE_REG_GO_C11 0x10208c +#define DMAE_REG_GO_C11_SIZE 1 +/* [RW 1] Command 12 go. */ +#define DMAE_REG_GO_C12 0x102090 +#define DMAE_REG_GO_C12_SIZE 1 +/* [RW 1] Command 13 go. */ +#define DMAE_REG_GO_C13 0x102094 +#define DMAE_REG_GO_C13_SIZE 1 +/* [RW 1] Command 14 go. */ +#define DMAE_REG_GO_C14 0x102098 +#define DMAE_REG_GO_C14_SIZE 1 +/* [RW 1] Command 15 go. */ +#define DMAE_REG_GO_C15 0x10209c +#define DMAE_REG_GO_C15_SIZE 1 +/* [RW 1] Command 10 go. */ +#define DMAE_REG_GO_C10 0x102088 +/* [RW 1] Command 11 go. */ +#define DMAE_REG_GO_C11 0x10208c +/* [RW 1] Command 12 go. */ +#define DMAE_REG_GO_C12 0x102090 +/* [RW 1] Command 13 go. */ +#define DMAE_REG_GO_C13 0x102094 +/* [RW 1] Command 14 go. */ +#define DMAE_REG_GO_C14 0x102098 +/* [RW 1] Command 15 go. */ +#define DMAE_REG_GO_C15 0x10209c +/* [RW 1] Command 2 go. */ +#define DMAE_REG_GO_C2 0x1020a0 +/* [RW 1] Command 3 go. */ +#define DMAE_REG_GO_C3 0x1020a4 +/* [RW 1] Command 4 go. */ +#define DMAE_REG_GO_C4 0x1020a8 +/* [RW 1] Command 5 go. */ +#define DMAE_REG_GO_C5 0x1020ac +/* [RW 1] Command 6 go. */ +#define DMAE_REG_GO_C6 0x1020b0 +/* [RW 1] Command 7 go. */ +#define DMAE_REG_GO_C7 0x1020b4 +/* [RW 1] Command 8 go. */ +#define DMAE_REG_GO_C8 0x1020b8 +/* [RW 1] Command 9 go. */ +#define DMAE_REG_GO_C9 0x1020bc +/* [RW 1] DMAE GRC Interface (Target; aster) enable. If 0 - the acknowledge + input is disregarded; valid is deasserted; all other signals are treated + as usual; if 1 - normal activity. */ +#define DMAE_REG_GRC_IFEN 0x102008 +/* [RW 1] DMAE PCI Interface (Request; ead; rite) enable. If 0 - the + acknowledge input is disregarded; valid is deasserted; full is asserted; + all other signals are treated as usual; if 1 - normal activity. */ +#define DMAE_REG_PCI_IFEN 0x102004 +/* [RW 4] DMAE- PCI Request Interface initial credit. Write writes the + initial value to the credit counter; related to the address. Read returns + the current value of the counter. */ +#define DMAE_REG_PXP_REQ_INIT_CRD 0x1020c0 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD0 0x170060 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD1 0x170064 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD2 0x170068 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD3 0x17006c +/* [RW 28] UCM Header. */ +#define DORQ_REG_CMHEAD_RX 0x170050 +/* [RW 5] Interrupt mask register #0 read/write */ +#define DORQ_REG_DORQ_INT_MASK 0x170180 +/* [R 5] Interrupt register #0 read */ +#define DORQ_REG_DORQ_INT_STS 0x170174 +/* [RC 5] Interrupt register #0 read clear */ +#define DORQ_REG_DORQ_INT_STS_CLR 0x170178 +/* [RW 2] Parity mask register #0 read/write */ +#define DORQ_REG_DORQ_PRTY_MASK 0x170190 +/* [RW 8] The address to write the DPM CID to STORM. */ +#define DORQ_REG_DPM_CID_ADDR 0x170044 +/* [RW 5] The DPM mode CID extraction offset. */ +#define DORQ_REG_DPM_CID_OFST 0x170030 +/* [RW 12] The threshold of the DQ FIFO to send the almost full interrupt. */ +#define DORQ_REG_DQ_FIFO_AFULL_TH 0x17007c +/* [RW 12] The threshold of the DQ FIFO to send the full interrupt. */ +#define DORQ_REG_DQ_FIFO_FULL_TH 0x170078 +/* [R 13] Current value of the DQ FIFO fill level according to following + pointer. The range is 0 - 256 FIFO rows; where each row stands for the + doorbell. */ +#define DORQ_REG_DQ_FILL_LVLF 0x1700a4 +/* [R 1] DQ FIFO full status. Is set; when FIFO filling level is more or + equal to full threshold; reset on full clear. */ +#define DORQ_REG_DQ_FULL_ST 0x1700c0 +/* [RW 28] The value sent to CM header in the case of CFC load error. */ +#define DORQ_REG_ERR_CMHEAD 0x170058 +#define DORQ_REG_IF_EN 0x170004 +#define DORQ_REG_MODE_ACT 0x170008 +/* [RW 5] The normal mode CID extraction offset. */ +#define DORQ_REG_NORM_CID_OFST 0x17002c +/* [RW 28] TCM Header when only TCP context is loaded. */ +#define DORQ_REG_NORM_CMHEAD_TX 0x17004c +/* [RW 3] The number of simultaneous outstanding requests to Context Fetch + Interface. */ +#define DORQ_REG_OUTST_REQ 0x17003c +#define DORQ_REG_REGN 0x170038 +/* [R 4] Current value of response A counter credit. Initial credit is + configured through write to ~dorq_registers_rsp_init_crd.rsp_init_crd + register. */ +#define DORQ_REG_RSPA_CRD_CNT 0x1700ac +/* [R 4] Current value of response B counter credit. Initial credit is + configured through write to ~dorq_registers_rsp_init_crd.rsp_init_crd + register. */ +#define DORQ_REG_RSPB_CRD_CNT 0x1700b0 +/* [RW 4] The initial credit at the Doorbell Response Interface. The write + writes the same initial credit to the rspa_crd_cnt and rspb_crd_cnt. The + read reads this written value. */ +#define DORQ_REG_RSP_INIT_CRD 0x170048 +/* [RW 4] Initial activity counter value on the load request; when the + shortcut is done. */ +#define DORQ_REG_SHRT_ACT_CNT 0x170070 +/* [RW 28] TCM Header when both ULP and TCP context is loaded. */ +#define DORQ_REG_SHRT_CMHEAD 0x170054 +#define HC_CONFIG_0_REG_ATTN_BIT_EN_0 (0x1<<4) +#define HC_CONFIG_0_REG_INT_LINE_EN_0 (0x1<<3) +#define HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 (0x1<<2) +#define HC_CONFIG_0_REG_SINGLE_ISR_EN_0 (0x1<<1) +#define HC_REG_AGG_INT_0 0x108050 +#define HC_REG_AGG_INT_1 0x108054 +/* [RW 16] attention bit and attention acknowledge bits status for port 0 + and 1 according to the following address map: addr 0 - attn_bit_0; addr 1 + - attn_ack_bit_0; addr 2 - attn_bit_1; addr 3 - attn_ack_bit_1; */ +#define HC_REG_ATTN_BIT 0x108120 +/* [RW 16] attn bits status index for attn bit msg; addr 0 - function 0; + addr 1 - functin 1 */ +#define HC_REG_ATTN_IDX 0x108100 +/* [RW 32] port 0 lower 32 bits address field for attn messag. */ +#define HC_REG_ATTN_MSG0_ADDR_L 0x108018 +/* [RW 32] port 1 lower 32 bits address field for attn messag. */ +#define HC_REG_ATTN_MSG1_ADDR_L 0x108020 +/* [RW 8] status block number for attn bit msg - function 0; */ +#define HC_REG_ATTN_NUM_P0 0x108038 +/* [RW 8] status block number for attn bit msg - function 1 */ +#define HC_REG_ATTN_NUM_P1 0x10803c +#define HC_REG_CONFIG_0 0x108000 +#define HC_REG_CONFIG_1 0x108004 +/* [RW 3] Parity mask register #0 read/write */ +#define HC_REG_HC_PRTY_MASK 0x1080a0 +/* [RW 17] status block interrupt mask; one in each bit means unmask; zerow + in each bit means mask; bit 0 - default SB; bit 1 - SB_0; bit 2 - SB_1... + bit 16- SB_15; addr 0 - port 0; addr 1 - port 1 */ +#define HC_REG_INT_MASK 0x108108 +/* [RW 16] port 0 attn bit condition monitoring; each bit that is set will + lock a change fron 0 to 1 in the corresponding attention signals that + comes from the AEU */ +#define HC_REG_LEADING_EDGE_0 0x108040 +#define HC_REG_LEADING_EDGE_1 0x108048 +/* [RW 16] all producer and consumer of port 0 according to the following + addresses; U_prod: 0-15; C_prod: 16-31; U_cons: 32-47; C_cons:48-63; + Defoult_prod: U/C/X/T/Attn-64/65/66/67/68; Defoult_cons: + U/C/X/T/Attn-69/70/71/72/73 */ +#define HC_REG_P0_PROD_CONS 0x108200 +/* [RW 16] all producer and consumer of port 1according to the following + addresses; U_prod: 0-15; C_prod: 16-31; U_cons: 32-47; C_cons:48-63; + Defoult_prod: U/C/X/T/Attn-64/65/66/67/68; Defoult_cons: + U/C/X/T/Attn-69/70/71/72/73 */ +#define HC_REG_P1_PROD_CONS 0x108400 +/* [W 1] This register is write only and has 4 addresses as follow: 0 = + clear all PBA bits port 0; 1 = clear all pending interrupts request + port0; 2 = clear all PBA bits port 1; 3 = clear all pending interrupts + request port1; here is no meaning for the data in this register */ +#define HC_REG_PBA_COMMAND 0x108140 +#define HC_REG_PCI_CONFIG_0 0x108010 +#define HC_REG_PCI_CONFIG_1 0x108014 +/* [RW 24] all counters acording to the following address: LSB: 0=read; 1= + read_clear; 0-71 = HW counters (the inside order is the same as the + interrupt table in the spec); 72-219 = SW counters 1 (stops after first + consumer upd) the inside order is: 72-103 - U_non_default_p0; 104-135 + C_non_defaul_p0; 36-145 U/C/X/T/Attn_default_p0; 146-177 + U_non_default_p1; 178-209 C_non_defaul_p1; 10-219 U/C/X/T/Attn_default_p1 + ; 220-367 = SW counters 2 (stops when prod=cons) the inside order is: + 220-251 - U_non_default_p0; 252-283 C_non_defaul_p0; 84-293 + U/C/X/T/Attn_default_p0; 294-325 U_non_default_p1; 326-357 + C_non_defaul_p1; 58-367 U/C/X/T/Attn_default_p1 ; 368-515 = mailbox + counters; (the inside order of the mailbox counter is 368-431 U and C + non_default_p0; 432-441 U/C/X/T/Attn_default_p0; 442-505 U and C + non_default_p1; 506-515 U/C/X/T/Attn_default_p1) */ +#define HC_REG_STATISTIC_COUNTERS 0x109000 +/* [RW 16] port 0 attn bit condition monitoring; each bit that is set will + lock a change fron 1 to 0 in the corresponding attention signals that + comes from the AEU */ +#define HC_REG_TRAILING_EDGE_0 0x108044 +#define HC_REG_TRAILING_EDGE_1 0x10804c +#define HC_REG_UC_RAM_ADDR_0 0x108028 +#define HC_REG_UC_RAM_ADDR_1 0x108030 +/* [RW 16] ustorm address for coalesc now message */ +#define HC_REG_USTORM_ADDR_FOR_COALESCE 0x108068 +#define HC_REG_VQID_0 0x108008 +#define HC_REG_VQID_1 0x10800c +#define MCP_REG_MCPR_NVM_ACCESS_ENABLE 0x86424 +#define MCP_REG_MCPR_NVM_ADDR 0x8640c +#define MCP_REG_MCPR_NVM_CFG4 0x8642c +#define MCP_REG_MCPR_NVM_COMMAND 0x86400 +#define MCP_REG_MCPR_NVM_READ 0x86410 +#define MCP_REG_MCPR_NVM_SW_ARB 0x86420 +#define MCP_REG_MCPR_NVM_WRITE 0x86408 +#define MCP_REG_MCPR_NVM_WRITE1 0x86428 +#define MCP_REG_MCPR_SCRATCH 0xa0000 +/* [R 32] read first 32 bit after inversion of function 0. mapped as + follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; + [6] GPIO1 function 1; [7] GPIO2 function 1; [8] GPIO3 function 1; [9] + GPIO4 function 1; [10] PCIE glue/PXP VPD event function0; [11] PCIE + glue/PXP VPD event function1; [12] PCIE glue/PXP Expansion ROM event0; + [13] PCIE glue/PXP Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] + MSI/X indication for mcp; [17] MSI/X indication for function 1; [18] BRB + Parity error; [19] BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw + interrupt; [22] SRC Parity error; [23] SRC Hw interrupt; [24] TSDM Parity + error; [25] TSDM Hw interrupt; [26] TCM Parity error; [27] TCM Hw + interrupt; [28] TSEMI Parity error; [29] TSEMI Hw interrupt; [30] PBF + Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 0xa42c +#define MISC_REG_AEU_AFTER_INVERT_1_FUNC_1 0xa430 +/* [R 32] read first 32 bit after inversion of mcp. mapped as follows: [0] + NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 + mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; + [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10] + PCIE glue/PXP VPD event function0; [11] PCIE glue/PXP VPD event + function1; [12] PCIE glue/PXP Expansion ROM event0; [13] PCIE glue/PXP + Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] MSI/X indication for + mcp; [17] MSI/X indication for function 1; [18] BRB Parity error; [19] + BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC + Parity error; [23] SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw + interrupt; [26] TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI + Parity error; [29] TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw + interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_1_MCP 0xa434 +/* [R 32] read second 32 bit after inversion of function 0. mapped as + follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 0xa438 +#define MISC_REG_AEU_AFTER_INVERT_2_FUNC_1 0xa43c +/* [R 32] read second 32 bit after inversion of mcp. mapped as follows: [0] + PBClient Parity error; [1] PBClient Hw interrupt; [2] QM Parity error; + [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw interrupt; + [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity error; [9] + XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw interrupt; [12] + DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] NIG Parity + error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; [17] Vaux + PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw interrupt; + [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM Parity error; + [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI Hw interrupt; + [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM Parity error; + [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_2_MCP 0xa440 +/* [R 32] read third 32 bit after inversion of function 0. mapped as + follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP Parity + error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; [5] + PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 0xa444 +#define MISC_REG_AEU_AFTER_INVERT_3_FUNC_1 0xa448 +/* [R 32] read third 32 bit after inversion of mcp. mapped as follows: [0] + CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP Parity error; [3] PXP + Hw interrupt; [4] PXPpciClockClient Parity error; [5] PXPpciClockClient + Hw interrupt; [6] CFC Parity error; [7] CFC Hw interrupt; [8] CDU Parity + error; [9] CDU Hw interrupt; [10] DMAE Parity error; [11] DMAE Hw + interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) Hw interrupt; [14] + MISC Parity error; [15] MISC Hw interrupt; [16] pxp_misc_mps_attn; [17] + Flash event; [18] SMB event; [19] MCP attn0; [20] MCP attn1; [21] SW + timers attn_1 func0; [22] SW timers attn_2 func0; [23] SW timers attn_3 + func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW timers attn_1 + func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 func1; [29] SW + timers attn_4 func1; [30] General attn0; [31] General attn1; */ +#define MISC_REG_AEU_AFTER_INVERT_3_MCP 0xa44c +/* [R 32] read fourth 32 bit after inversion of function 0. mapped as + follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 0xa450 +#define MISC_REG_AEU_AFTER_INVERT_4_FUNC_1 0xa454 +/* [R 32] read fourth 32 bit after inversion of mcp. mapped as follows: [0] + General attn2; [1] General attn3; [2] General attn4; [3] General attn5; + [4] General attn6; [5] General attn7; [6] General attn8; [7] General + attn9; [8] General attn10; [9] General attn11; [10] General attn12; [11] + General attn13; [12] General attn14; [13] General attn15; [14] General + attn16; [15] General attn17; [16] General attn18; [17] General attn19; + [18] General attn20; [19] General attn21; [20] Main power interrupt; [21] + RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN Latched attn; [24] + RBCU Latched attn; [25] RBCP Latched attn; [26] GRC Latched timeout + attention; [27] GRC Latched reserved access attention; [28] MCP Latched + rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP Latched + ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_AFTER_INVERT_4_MCP 0xa458 +/* [W 11] write to this register results with the clear of the latched + signals; one in d0 clears RBCR latch; one in d1 clears RBCT latch; one in + d2 clears RBCN latch; one in d3 clears RBCU latch; one in d4 clears RBCP + latch; one in d5 clears GRC Latched timeout attention; one in d6 clears + GRC Latched reserved access attention; one in d7 clears Latched + rom_parity; one in d8 clears Latched ump_rx_parity; one in d9 clears + Latched ump_tx_parity; one in d10 clears Latched scpad_parity; read from + this register return zero */ +#define MISC_REG_AEU_CLR_LATCH_SIGNAL 0xa45c +/* [RW 32] first 32b for enabling the output for function 0 output0. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function + 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0 0xa06c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1 0xa07c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3 0xa09c +/* [RW 32] first 32b for enabling the output for function 1 output0. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 1; [3] GPIO2 function 1; [4] GPIO3 function + 1; [5] GPIO4 function 1; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 1; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 0xa10c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 0xa11c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3 0xa13c +/* [RW 32] first 32b for enabling the output for close the gate nig 0. + mapped as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function + 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_NIG_0 0xa0ec +#define MISC_REG_AEU_ENABLE1_NIG_1 0xa18c +/* [RW 32] first 32b for enabling the output for close the gate pxp 0. + mapped as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function + 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_PXP_0 0xa0fc +#define MISC_REG_AEU_ENABLE1_PXP_1 0xa19c +/* [RW 32] second 32b for enabling the output for function 0 output0. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0 0xa070 +#define MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1 0xa080 +/* [RW 32] second 32b for enabling the output for function 1 output0. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0 0xa110 +#define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1 0xa120 +/* [RW 32] second 32b for enabling the output for close the gate nig 0. + mapped as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; + [2] QM Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] + Timers Hw interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] + XCM Parity error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] + XSEMI Hw interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw + interrupt; [14] NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI + core Parity error; [17] Vaux PCI core Hw interrupt; [18] Debug Parity + error; [19] Debug Hw interrupt; [20] USDM Parity error; [21] USDM Hw + interrupt; [22] UCM Parity error; [23] UCM Hw interrupt; [24] USEMI + Parity error; [25] USEMI Hw interrupt; [26] UPB Parity error; [27] UPB Hw + interrupt; [28] CSDM Parity error; [29] CSDM Hw interrupt; [30] CCM + Parity error; [31] CCM Hw interrupt; */ +#define MISC_REG_AEU_ENABLE2_NIG_0 0xa0f0 +#define MISC_REG_AEU_ENABLE2_NIG_1 0xa190 +/* [RW 32] second 32b for enabling the output for close the gate pxp 0. + mapped as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; + [2] QM Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] + Timers Hw interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] + XCM Parity error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] + XSEMI Hw interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw + interrupt; [14] NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI + core Parity error; [17] Vaux PCI core Hw interrupt; [18] Debug Parity + error; [19] Debug Hw interrupt; [20] USDM Parity error; [21] USDM Hw + interrupt; [22] UCM Parity error; [23] UCM Hw interrupt; [24] USEMI + Parity error; [25] USEMI Hw interrupt; [26] UPB Parity error; [27] UPB Hw + interrupt; [28] CSDM Parity error; [29] CSDM Hw interrupt; [30] CCM + Parity error; [31] CCM Hw interrupt; */ +#define MISC_REG_AEU_ENABLE2_PXP_0 0xa100 +#define MISC_REG_AEU_ENABLE2_PXP_1 0xa1a0 +/* [RW 32] third 32b for enabling the output for function 0 output0. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0 0xa074 +#define MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1 0xa084 +/* [RW 32] third 32b for enabling the output for function 1 output0. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0 0xa114 +#define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1 0xa124 +/* [RW 32] third 32b for enabling the output for close the gate nig 0. + mapped as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] + PXP Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity + error; [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC + Hw interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE + Parity error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] + IGU (HC) Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; + [16] pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; + [20] MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; + [23] SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; + [26] SW timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers + attn_3 func1; [29] SW timers attn_4 func1; [30] General attn0; [31] + General attn1; */ +#define MISC_REG_AEU_ENABLE3_NIG_0 0xa0f4 +#define MISC_REG_AEU_ENABLE3_NIG_1 0xa194 +/* [RW 32] third 32b for enabling the output for close the gate pxp 0. + mapped as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] + PXP Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity + error; [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC + Hw interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE + Parity error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] + IGU (HC) Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; + [16] pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; + [20] MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; + [23] SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; + [26] SW timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers + attn_3 func1; [29] SW timers attn_4 func1; [30] General attn0; [31] + General attn1; */ +#define MISC_REG_AEU_ENABLE3_PXP_0 0xa104 +#define MISC_REG_AEU_ENABLE3_PXP_1 0xa1a4 +/* [RW 32] fourth 32b for enabling the output for function 0 output0.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0 0xa078 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2 0xa098 +/* [RW 32] fourth 32b for enabling the output for function 1 output0.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0 0xa118 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2 0xa138 +/* [RW 32] fourth 32b for enabling the output for close the gate nig + 0.mapped as follows: [0] General attn2; [1] General attn3; [2] General + attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6] + General attn8; [7] General attn9; [8] General attn10; [9] General attn11; + [10] General attn12; [11] General attn13; [12] General attn14; [13] + General attn15; [14] General attn16; [15] General attn17; [16] General + attn18; [17] General attn19; [18] General attn20; [19] General attn21; + [20] Main power interrupt; [21] RBCR Latched attn; [22] RBCT Latched + attn; [23] RBCN Latched attn; [24] RBCU Latched attn; [25] RBCP Latched + attn; [26] GRC Latched timeout attention; [27] GRC Latched reserved + access attention; [28] MCP Latched rom_parity; [29] MCP Latched + ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched + scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_NIG_0 0xa0f8 +#define MISC_REG_AEU_ENABLE4_NIG_1 0xa198 +/* [RW 32] fourth 32b for enabling the output for close the gate pxp + 0.mapped as follows: [0] General attn2; [1] General attn3; [2] General + attn4; [3] General attn5; [4] General attn6; [5] General attn7; [6] + General attn8; [7] General attn9; [8] General attn10; [9] General attn11; + [10] General attn12; [11] General attn13; [12] General attn14; [13] + General attn15; [14] General attn16; [15] General attn17; [16] General + attn18; [17] General attn19; [18] General attn20; [19] General attn21; + [20] Main power interrupt; [21] RBCR Latched attn; [22] RBCT Latched + attn; [23] RBCN Latched attn; [24] RBCU Latched attn; [25] RBCP Latched + attn; [26] GRC Latched timeout attention; [27] GRC Latched reserved + access attention; [28] MCP Latched rom_parity; [29] MCP Latched + ump_rx_parity; [30] MCP Latched ump_tx_parity; [31] MCP Latched + scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_PXP_0 0xa108 +#define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8 +/* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu + 128 bit vector */ +#define MISC_REG_AEU_GENERAL_ATTN_0 0xa000 +#define MISC_REG_AEU_GENERAL_ATTN_1 0xa004 +#define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 +#define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c +#define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 +#define MISC_REG_AEU_GENERAL_ATTN_13 0xa034 +#define MISC_REG_AEU_GENERAL_ATTN_14 0xa038 +#define MISC_REG_AEU_GENERAL_ATTN_15 0xa03c +#define MISC_REG_AEU_GENERAL_ATTN_16 0xa040 +#define MISC_REG_AEU_GENERAL_ATTN_17 0xa044 +#define MISC_REG_AEU_GENERAL_ATTN_18 0xa048 +#define MISC_REG_AEU_GENERAL_ATTN_19 0xa04c +#define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c +#define MISC_REG_AEU_GENERAL_ATTN_2 0xa008 +#define MISC_REG_AEU_GENERAL_ATTN_20 0xa050 +#define MISC_REG_AEU_GENERAL_ATTN_21 0xa054 +#define MISC_REG_AEU_GENERAL_ATTN_3 0xa00c +#define MISC_REG_AEU_GENERAL_ATTN_4 0xa010 +#define MISC_REG_AEU_GENERAL_ATTN_5 0xa014 +#define MISC_REG_AEU_GENERAL_ATTN_6 0xa018 +/* [RW 32] first 32b for inverting the input for function 0; for each bit: + 0= do not invert; 1= invert; mapped as follows: [0] NIG attention for + function0; [1] NIG attention for function1; [2] GPIO1 mcp; [3] GPIO2 mcp; + [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; [7] GPIO2 function 1; + [8] GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for mcp; [17] MSI/X indication + for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; [20] PRS + Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] SRC Hw + interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] TCM + Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] TSEMI + Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_INVERTER_1_FUNC_0 0xa22c +#define MISC_REG_AEU_INVERTER_1_FUNC_1 0xa23c +/* [RW 32] second 32b for inverting the input for function 0; for each bit: + 0= do not invert; 1= invert. mapped as follows: [0] PBClient Parity + error; [1] PBClient Hw interrupt; [2] QM Parity error; [3] QM Hw + interrupt; [4] Timers Parity error; [5] Timers Hw interrupt; [6] XSDM + Parity error; [7] XSDM Hw interrupt; [8] XCM Parity error; [9] XCM Hw + interrupt; [10] XSEMI Parity error; [11] XSEMI Hw interrupt; [12] + DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] NIG Parity + error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; [17] Vaux + PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw interrupt; + [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM Parity error; + [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI Hw interrupt; + [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM Parity error; + [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw interrupt; */ +#define MISC_REG_AEU_INVERTER_2_FUNC_0 0xa230 +#define MISC_REG_AEU_INVERTER_2_FUNC_1 0xa240 +/* [RW 10] [7:0] = mask 8 attention output signals toward IGU function0; + [9:8] = mask close the gates signals of function 0 toward PXP [8] and NIG + [9]. Zero = mask; one = unmask */ +#define MISC_REG_AEU_MASK_ATTN_FUNC_0 0xa060 +#define MISC_REG_AEU_MASK_ATTN_FUNC_1 0xa064 +/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1 + Port. */ +#define MISC_REG_BOND_ID 0xa400 +/* [R 8] These bits indicate the metal revision of the chip. This value + starts at 0x00 for each all-layer tape-out and increments by one for each + tape-out. */ +#define MISC_REG_CHIP_METAL 0xa404 +/* [R 16] These bits indicate the part number for the chip. */ +#define MISC_REG_CHIP_NUM 0xa408 +/* [R 4] These bits indicate the base revision of the chip. This value + starts at 0x0 for the A0 tape-out and increments by one for each + all-layer tape-out. */ +#define MISC_REG_CHIP_REV 0xa40c +/* [RW 1] Setting this bit enables a timer in the GRC block to timeout any + access that does not finish within + ~misc_registers_grc_timout_val.grc_timeout_val cycles. When this bit is + cleared; this timeout is disabled. If this timeout occurs; the GRC shall + assert it attention output. */ +#define MISC_REG_GRC_TIMEOUT_EN 0xa280 +/* [RW 28] 28 LSB of LCPLL first register; reset val = 521. inside order of + the bits is: [2:0] OAC reset value 001) CML output buffer bias control; + 111 for +40%; 011 for +20%; 001 for 0%; 000 for -20%. [5:3] Icp_ctrl + (reset value 001) Charge pump current control; 111 for 720u; 011 for + 600u; 001 for 480u and 000 for 360u. [7:6] Bias_ctrl (reset value 00) + Global bias control; When bit 7 is high bias current will be 10 0gh; When + bit 6 is high bias will be 100w; Valid values are 00; 10; 01. [10:8] + Pll_observe (reset value 010) Bits to control observability. bit 10 is + for test bias; bit 9 is for test CK; bit 8 is test Vc. [12:11] Vth_ctrl + (reset value 00) Comparator threshold control. 00 for 0.6V; 01 for 0.54V + and 10 for 0.66V. [13] pllSeqStart (reset value 0) Enables VCO tuning + sequencer: 1= sequencer disabled; 0= sequencer enabled (inverted + internally). [14] reserved (reset value 0) Reset for VCO sequencer is + connected to RESET input directly. [15] capRetry_en (reset value 0) + enable retry on cap search failure (inverted). [16] freqMonitor_e (reset + value 0) bit to continuously monitor vco freq (inverted). [17] + freqDetRestart_en (reset value 0) bit to enable restart when not freq + locked (inverted). [18] freqDetRetry_en (reset value 0) bit to enable + retry on freq det failure(inverted). [19] pllForceFdone_en (reset value + 0) bit to enable pllForceFdone & pllForceFpass into pllSeq. [20] + pllForceFdone (reset value 0) bit to force freqDone. [21] pllForceFpass + (reset value 0) bit to force freqPass. [22] pllForceDone_en (reset value + 0) bit to enable pllForceCapDone. [23] pllForceCapDone (reset value 0) + bit to force capDone. [24] pllForceCapPass_en (reset value 0) bit to + enable pllForceCapPass. [25] pllForceCapPass (reset value 0) bit to force + capPass. [26] capRestart (reset value 0) bit to force cap sequencer to + restart. [27] capSelectM_en (reset value 0) bit to enable cap select + register bits. */ +#define MISC_REG_LCPLL_CTRL_1 0xa2a4 +#define MISC_REG_LCPLL_CTRL_REG_2 0xa2a8 +/* [RW 4] Interrupt mask register #0 read/write */ +#define MISC_REG_MISC_INT_MASK 0xa388 +/* [RW 1] Parity mask register #0 read/write */ +#define MISC_REG_MISC_PRTY_MASK 0xa398 +/* [RW 32] 32 LSB of storm PLL first register; reset val = 0x 071d2911. + inside order of the bits is: [0] P1 divider[0] (reset value 1); [1] P1 + divider[1] (reset value 0); [2] P1 divider[2] (reset value 0); [3] P1 + divider[3] (reset value 0); [4] P2 divider[0] (reset value 1); [5] P2 + divider[1] (reset value 0); [6] P2 divider[2] (reset value 0); [7] P2 + divider[3] (reset value 0); [8] ph_det_dis (reset value 1); [9] + freq_det_dis (reset value 0); [10] Icpx[0] (reset value 0); [11] Icpx[1] + (reset value 1); [12] Icpx[2] (reset value 0); [13] Icpx[3] (reset value + 1); [14] Icpx[4] (reset value 0); [15] Icpx[5] (reset value 0); [16] + Rx[0] (reset value 1); [17] Rx[1] (reset value 0); [18] vc_en (reset + value 1); [19] vco_rng[0] (reset value 1); [20] vco_rng[1] (reset value + 1); [21] Kvco_xf[0] (reset value 0); [22] Kvco_xf[1] (reset value 0); + [23] Kvco_xf[2] (reset value 0); [24] Kvco_xs[0] (reset value 1); [25] + Kvco_xs[1] (reset value 1); [26] Kvco_xs[2] (reset value 1); [27] + testd_en (reset value 0); [28] testd_sel[0] (reset value 0); [29] + testd_sel[1] (reset value 0); [30] testd_sel[2] (reset value 0); [31] + testa_en (reset value 0); */ +#define MISC_REG_PLL_STORM_CTRL_1 0xa294 +#define MISC_REG_PLL_STORM_CTRL_2 0xa298 +#define MISC_REG_PLL_STORM_CTRL_3 0xa29c +#define MISC_REG_PLL_STORM_CTRL_4 0xa2a0 +/* [RW 32] reset reg#1; rite/read one = the specific block is out of reset; + write/read zero = the specific block is in reset; addr 0-wr- the write + value will be written to the register; addr 1-set - one will be written + to all the bits that have the value of one in the data written (bits that + have the value of zero will not be change) ; addr 2-clear - zero will be + written to all the bits that have the value of one in the data written + (bits that have the value of zero will not be change); addr 3-ignore; + read ignore from all addr except addr 00; inside order of the bits is: + [0] rst_brb1; [1] rst_prs; [2] rst_src; [3] rst_tsdm; [4] rst_tsem; [5] + rst_tcm; [6] rst_rbcr; [7] rst_nig; [8] rst_usdm; [9] rst_ucm; [10] + rst_usem; [11] rst_upb; [12] rst_ccm; [13] rst_csem; [14] rst_csdm; [15] + rst_rbcu; [16] rst_pbf; [17] rst_qm; [18] rst_tm; [19] rst_dorq; [20] + rst_xcm; [21] rst_xsdm; [22] rst_xsem; [23] rst_rbct; [24] rst_cdu; [25] + rst_cfc; [26] rst_pxp; [27] rst_pxpv; [28] rst_rbcp; [29] rst_hc; [30] + rst_dmae; [31] rst_semi_rtc; */ +#define MISC_REG_RESET_REG_1 0xa580 +#define MISC_REG_RESET_REG_2 0xa590 +/* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is + shared with the driver resides */ +#define MISC_REG_SHARED_MEM_ADDR 0xa2b4 +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS (0xf<<18) +/* [RW 1] Input enable for RX_BMAC0 IF */ +#define NIG_REG_BMAC0_IN_EN 0x100ac +/* [RW 1] output enable for TX_BMAC0 IF */ +#define NIG_REG_BMAC0_OUT_EN 0x100e0 +/* [RW 1] output enable for TX BMAC pause port 0 IF */ +#define NIG_REG_BMAC0_PAUSE_OUT_EN 0x10110 +/* [RW 1] output enable for RX_BMAC0_REGS IF */ +#define NIG_REG_BMAC0_REGS_OUT_EN 0x100e8 +/* [RW 1] output enable for RX BRB1 port0 IF */ +#define NIG_REG_BRB0_OUT_EN 0x100f8 +/* [RW 1] Input enable for TX BRB1 pause port 0 IF */ +#define NIG_REG_BRB0_PAUSE_IN_EN 0x100c4 +/* [RW 1] output enable for RX BRB1 port1 IF */ +#define NIG_REG_BRB1_OUT_EN 0x100fc +/* [RW 1] Input enable for TX BRB1 pause port 1 IF */ +#define NIG_REG_BRB1_PAUSE_IN_EN 0x100c8 +/* [RW 1] output enable for RX BRB1 LP IF */ +#define NIG_REG_BRB_LB_OUT_EN 0x10100 +/* [WB_W 72] Debug packet to LP from RBC; Data spelling:[63:0] data; 64] + error; [67:65]eop_bvalid; [68]eop; [69]sop; [70]port_id; 71]flush */ +#define NIG_REG_DEBUG_PACKET_LB 0x10800 +/* [RW 1] Input enable for TX Debug packet */ +#define NIG_REG_EGRESS_DEBUG_IN_EN 0x100dc +/* [RW 1] If 1 - egress drain mode for port0 is active. In this mode all + packets from PBFare not forwarded to the MAC and just deleted from FIFO. + First packet may be deleted from the middle. And last packet will be + always deleted till the end. */ +#define NIG_REG_EGRESS_DRAIN0_MODE 0x10060 +/* [RW 1] Output enable to EMAC0 */ +#define NIG_REG_EGRESS_EMAC0_OUT_EN 0x10120 +/* [RW 1] MAC configuration for packets of port0. If 1 - all packet outputs + to emac for port0; other way to bmac for port0 */ +#define NIG_REG_EGRESS_EMAC0_PORT 0x10058 +/* [RW 1] Input enable for TX PBF user packet port0 IF */ +#define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc +/* [RW 1] Input enable for TX PBF user packet port1 IF */ +#define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0 +/* [RW 1] Input enable for RX_EMAC0 IF */ +#define NIG_REG_EMAC0_IN_EN 0x100a4 +/* [RW 1] output enable for TX EMAC pause port 0 IF */ +#define NIG_REG_EMAC0_PAUSE_OUT_EN 0x10118 +/* [R 1] status from emac0. This bit is set when MDINT from either the + EXT_MDINT pin or from the Copper PHY is driven low. This condition must + be cleared in the attached PHY device that is driving the MINT pin. */ +#define NIG_REG_EMAC0_STATUS_MISC_MI_INT 0x10494 +/* [WB 48] This address space contains BMAC0 registers. The BMAC registers + are described in appendix A. In order to access the BMAC0 registers; the + base address; NIG_REGISTERS_INGRESS_BMAC0_MEM; Offset: 0x10c00; should be + added to each BMAC register offset */ +#define NIG_REG_INGRESS_BMAC0_MEM 0x10c00 +/* [WB 48] This address space contains BMAC1 registers. The BMAC registers + are described in appendix A. In order to access the BMAC0 registers; the + base address; NIG_REGISTERS_INGRESS_BMAC1_MEM; Offset: 0x11000; should be + added to each BMAC register offset */ +#define NIG_REG_INGRESS_BMAC1_MEM 0x11000 +/* [R 1] FIFO empty in EOP descriptor FIFO of LP in NIG_RX_EOP */ +#define NIG_REG_INGRESS_EOP_LB_EMPTY 0x104e0 +/* [RW 17] Debug only. RX_EOP_DSCR_lb_FIFO in NIG_RX_EOP. Data + packet_length[13:0]; mac_error[14]; trunc_error[15]; parity[16] */ +#define NIG_REG_INGRESS_EOP_LB_FIFO 0x104e4 +/* [RW 1] led 10g for port 0 */ +#define NIG_REG_LED_10G_P0 0x10320 +/* [RW 1] Port0: This bit is set to enable the use of the + ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 field + defined below. If this bit is cleared; then the blink rate will be about + 8Hz. */ +#define NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 0x10318 +/* [RW 12] Port0: Specifies the period of each blink cycle (on + off) for + Traffic LED in milliseconds. Must be a non-zero value. This 12-bit field + is reset to 0x080; giving a default blink period of approximately 8Hz. */ +#define NIG_REG_LED_CONTROL_BLINK_RATE_P0 0x10310 +/* [RW 1] Port0: If set along with the + nig_registers_led_control_override_traffic_p0.led_control_override_traffic_p0 + bit and ~nig_registers_led_control_traffic_p0.led_control_traffic_p0 LED + bit; the Traffic LED will blink with the blink rate specified in + ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and + ~nig_registers_led_control_blink_rate_ena_p0.led_control_blink_rate_ena_p0 + fields. */ +#define NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 0x10308 +/* [RW 1] Port0: If set overrides hardware control of the Traffic LED. The + Traffic LED will then be controlled via bit ~nig_registers_ + led_control_traffic_p0.led_control_traffic_p0 and bit + ~nig_registers_led_control_blink_traffic_p0.led_control_blink_traffic_p0 */ +#define NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 0x102f8 +/* [RW 1] Port0: If set along with the led_control_override_trafic_p0 bit; + turns on the Traffic LED. If the led_control_blink_traffic_p0 bit is also + set; the LED will blink with blink rate specified in + ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and + ~nig_regsters_led_control_blink_rate_ena_p0.led_control_blink_rate_ena_p0 + fields. */ +#define NIG_REG_LED_CONTROL_TRAFFIC_P0 0x10300 +/* [RW 4] led mode for port0: 0 MAC; 1-3 PHY1; 4 MAC2; 5-7 PHY4; 8-MAC3; + 9-11PHY7; 12 MAC4; 13-15 PHY10; */ +#define NIG_REG_LED_MODE_P0 0x102f0 +#define NIG_REG_LLH0_BRB1_DRV_MASK 0x10244 +/* [RW 1] send to BRB1 if no match on any of RMP rules. */ +#define NIG_REG_LLH0_BRB1_NOT_MCP 0x1025c +/* [RW 32] cm header for llh0 */ +#define NIG_REG_LLH0_CM_HEADER 0x1007c +#define NIG_REG_LLH0_ERROR_MASK 0x1008c +/* [RW 8] event id for llh0 */ +#define NIG_REG_LLH0_EVENT_ID 0x10084 +/* [RW 8] init credit counter for port0 in LLH */ +#define NIG_REG_LLH0_XCM_INIT_CREDIT 0x10554 +#define NIG_REG_LLH0_XCM_MASK 0x10130 +/* [RW 1] send to BRB1 if no match on any of RMP rules. */ +#define NIG_REG_LLH1_BRB1_NOT_MCP 0x102dc +/* [RW 32] cm header for llh1 */ +#define NIG_REG_LLH1_CM_HEADER 0x10080 +#define NIG_REG_LLH1_ERROR_MASK 0x10090 +/* [RW 8] event id for llh1 */ +#define NIG_REG_LLH1_EVENT_ID 0x10088 +/* [RW 8] init credit counter for port1 in LLH */ +#define NIG_REG_LLH1_XCM_INIT_CREDIT 0x10564 +#define NIG_REG_LLH1_XCM_MASK 0x10134 +#define NIG_REG_MASK_INTERRUPT_PORT0 0x10330 +#define NIG_REG_MASK_INTERRUPT_PORT1 0x10334 +/* [RW 1] Output signal from NIG to EMAC0. When set enables the EMAC0 block. */ +#define NIG_REG_NIG_EMAC0_EN 0x1003c +/* [RW 1] Output signal from NIG to TX_EMAC0. When set indicates to the + EMAC0 to strip the CRC from the ingress packets. */ +#define NIG_REG_NIG_INGRESS_EMAC0_NO_CRC 0x10044 +/* [RW 1] Input enable for RX PBF LP IF */ +#define NIG_REG_PBF_LB_IN_EN 0x100b4 +/* [RW 1] output enable for RX parser descriptor IF */ +#define NIG_REG_PRS_EOP_OUT_EN 0x10104 +/* [RW 1] Input enable for RX parser request IF */ +#define NIG_REG_PRS_REQ_IN_EN 0x100b8 +/* [RW 5] control to serdes - CL22 PHY_ADD and CL45 PRTAD */ +#define NIG_REG_SERDES0_CTRL_PHY_ADDR 0x10374 +/* [R 1] status from serdes0 that inputs to interrupt logic of link status */ +#define NIG_REG_SERDES0_STATUS_LINK_STATUS 0x10578 +/* [R 32] Rx statistics : In user packets discarded due to BRB backpressure + for port0 */ +#define NIG_REG_STAT0_BRB_DISCARD 0x105f0 +/* [R 32] Rx statistics : In user packets discarded due to BRB backpressure + for port1 */ +#define NIG_REG_STAT1_BRB_DISCARD 0x10628 +/* [WB_R 64] Rx statistics : User octets received for LP */ +#define NIG_REG_STAT2_BRB_OCTET 0x107e0 +#define NIG_REG_STATUS_INTERRUPT_PORT0 0x10328 +#define NIG_REG_STATUS_INTERRUPT_PORT1 0x1032c +/* [RW 1] output enable for RX_XCM0 IF */ +#define NIG_REG_XCM0_OUT_EN 0x100f0 +/* [RW 1] output enable for RX_XCM1 IF */ +#define NIG_REG_XCM1_OUT_EN 0x100f4 +/* [RW 5] control to xgxs - CL45 DEVAD */ +#define NIG_REG_XGXS0_CTRL_MD_DEVAD 0x1033c +/* [RW 5] control to xgxs - CL22 PHY_ADD and CL45 PRTAD */ +#define NIG_REG_XGXS0_CTRL_PHY_ADDR 0x10340 +/* [R 1] status from xgxs0 that inputs to interrupt logic of link10g. */ +#define NIG_REG_XGXS0_STATUS_LINK10G 0x10680 +/* [R 4] status from xgxs0 that inputs to interrupt logic of link status */ +#define NIG_REG_XGXS0_STATUS_LINK_STATUS 0x10684 +/* [RW 2] selection for XGXS lane of port 0 in NIG_MUX block */ +#define NIG_REG_XGXS_LANE_SEL_P0 0x102e8 +/* [RW 1] selection for port0 for NIG_MUX block : 0 = SerDes; 1 = XGXS */ +#define NIG_REG_XGXS_SERDES0_MODE_SEL 0x102e0 +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS (0x1<<9) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G (0x1<<15) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS (0xf<<18) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE 18 +/* [RW 1] Disable processing further tasks from port 0 (after ending the + current task in process). */ +#define PBF_REG_DISABLE_NEW_TASK_PROC_P0 0x14005c +/* [RW 1] Disable processing further tasks from port 1 (after ending the + current task in process). */ +#define PBF_REG_DISABLE_NEW_TASK_PROC_P1 0x140060 +/* [RW 1] Disable processing further tasks from port 4 (after ending the + current task in process). */ +#define PBF_REG_DISABLE_NEW_TASK_PROC_P4 0x14006c +#define PBF_REG_IF_ENABLE_REG 0x140044 +/* [RW 1] Init bit. When set the initial credits are copied to the credit + registers (except the port credits). Should be set and then reset after + the configuration of the block has ended. */ +#define PBF_REG_INIT 0x140000 +/* [RW 1] Init bit for port 0. When set the initial credit of port 0 is + copied to the credit register. Should be set and then reset after the + configuration of the port has ended. */ +#define PBF_REG_INIT_P0 0x140004 +/* [RW 1] Init bit for port 1. When set the initial credit of port 1 is + copied to the credit register. Should be set and then reset after the + configuration of the port has ended. */ +#define PBF_REG_INIT_P1 0x140008 +/* [RW 1] Init bit for port 4. When set the initial credit of port 4 is + copied to the credit register. Should be set and then reset after the + configuration of the port has ended. */ +#define PBF_REG_INIT_P4 0x14000c +/* [RW 1] Enable for mac interface 0. */ +#define PBF_REG_MAC_IF0_ENABLE 0x140030 +/* [RW 1] Enable for mac interface 1. */ +#define PBF_REG_MAC_IF1_ENABLE 0x140034 +/* [RW 1] Enable for the loopback interface. */ +#define PBF_REG_MAC_LB_ENABLE 0x140040 +/* [RW 10] Port 0 threshold used by arbiter in 16 byte lines used when pause + not suppoterd. */ +#define PBF_REG_P0_ARB_THRSH 0x1400e4 +/* [R 11] Current credit for port 0 in the tx port buffers in 16 byte lines. */ +#define PBF_REG_P0_CREDIT 0x140200 +/* [RW 11] Initial credit for port 0 in the tx port buffers in 16 byte + lines. */ +#define PBF_REG_P0_INIT_CRD 0x1400d0 +/* [RW 1] Indication that pause is enabled for port 0. */ +#define PBF_REG_P0_PAUSE_ENABLE 0x140014 +/* [R 8] Number of tasks in port 0 task queue. */ +#define PBF_REG_P0_TASK_CNT 0x140204 +/* [R 11] Current credit for port 1 in the tx port buffers in 16 byte lines. */ +#define PBF_REG_P1_CREDIT 0x140208 +/* [RW 11] Initial credit for port 1 in the tx port buffers in 16 byte + lines. */ +#define PBF_REG_P1_INIT_CRD 0x1400d4 +/* [R 8] Number of tasks in port 1 task queue. */ +#define PBF_REG_P1_TASK_CNT 0x14020c +/* [R 11] Current credit for port 4 in the tx port buffers in 16 byte lines. */ +#define PBF_REG_P4_CREDIT 0x140210 +/* [RW 11] Initial credit for port 4 in the tx port buffers in 16 byte + lines. */ +#define PBF_REG_P4_INIT_CRD 0x1400e0 +/* [R 8] Number of tasks in port 4 task queue. */ +#define PBF_REG_P4_TASK_CNT 0x140214 +/* [RW 5] Interrupt mask register #0 read/write */ +#define PBF_REG_PBF_INT_MASK 0x1401d4 +/* [R 5] Interrupt register #0 read */ +#define PBF_REG_PBF_INT_STS 0x1401c8 +#define PB_REG_CONTROL 0 +/* [RW 2] Interrupt mask register #0 read/write */ +#define PB_REG_PB_INT_MASK 0x28 +/* [R 2] Interrupt register #0 read */ +#define PB_REG_PB_INT_STS 0x1c +/* [RW 4] Parity mask register #0 read/write */ +#define PB_REG_PB_PRTY_MASK 0x38 +#define PRS_REG_A_PRSU_20 0x40134 +/* [R 8] debug only: CFC load request current credit. Transaction based. */ +#define PRS_REG_CFC_LD_CURRENT_CREDIT 0x40164 +/* [R 8] debug only: CFC search request current credit. Transaction based. */ +#define PRS_REG_CFC_SEARCH_CURRENT_CREDIT 0x40168 +/* [RW 6] The initial credit for the search message to the CFC interface. + Credit is transaction based. */ +#define PRS_REG_CFC_SEARCH_INITIAL_CREDIT 0x4011c +/* [RW 24] CID for port 0 if no match */ +#define PRS_REG_CID_PORT_0 0x400fc +#define PRS_REG_CID_PORT_1 0x40100 +/* [RW 32] The CM header for flush message where 'load existed' bit in CFC + load response is reset and packet type is 0. Used in packet start message + to TCM. */ +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0 0x400dc +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1 0x400e0 +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2 0x400e4 +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3 0x400e8 +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4 0x400ec +/* [RW 32] The CM header for flush message where 'load existed' bit in CFC + load response is set and packet type is 0. Used in packet start message + to TCM. */ +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0 0x400bc +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1 0x400c0 +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2 0x400c4 +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3 0x400c8 +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4 0x400cc +/* [RW 32] The CM header for a match and packet type 1 for loopback port. + Used in packet start message to TCM. */ +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_1 0x4009c +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_2 0x400a0 +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_3 0x400a4 +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_4 0x400a8 +/* [RW 32] The CM header for a match and packet type 0. Used in packet start + message to TCM. */ +#define PRS_REG_CM_HDR_TYPE_0 0x40078 +#define PRS_REG_CM_HDR_TYPE_1 0x4007c +#define PRS_REG_CM_HDR_TYPE_2 0x40080 +#define PRS_REG_CM_HDR_TYPE_3 0x40084 +#define PRS_REG_CM_HDR_TYPE_4 0x40088 +/* [RW 32] The CM header in case there was not a match on the connection */ +#define PRS_REG_CM_NO_MATCH_HDR 0x400b8 +/* [RW 8] The 8-bit event ID for a match and packet type 1. Used in packet + start message to TCM. */ +#define PRS_REG_EVENT_ID_1 0x40054 +#define PRS_REG_EVENT_ID_2 0x40058 +#define PRS_REG_EVENT_ID_3 0x4005c +/* [RW 8] Context region for flush packet with packet type 0. Used in CFC + load request message. */ +#define PRS_REG_FLUSH_REGIONS_TYPE_0 0x40004 +#define PRS_REG_FLUSH_REGIONS_TYPE_1 0x40008 +#define PRS_REG_FLUSH_REGIONS_TYPE_2 0x4000c +#define PRS_REG_FLUSH_REGIONS_TYPE_3 0x40010 +#define PRS_REG_FLUSH_REGIONS_TYPE_4 0x40014 +#define PRS_REG_FLUSH_REGIONS_TYPE_5 0x40018 +#define PRS_REG_FLUSH_REGIONS_TYPE_6 0x4001c +#define PRS_REG_FLUSH_REGIONS_TYPE_7 0x40020 +/* [RW 4] The increment value to send in the CFC load request message */ +#define PRS_REG_INC_VALUE 0x40048 +/* [RW 1] If set indicates not to send messages to CFC on received packets */ +#define PRS_REG_NIC_MODE 0x40138 +/* [RW 8] The 8-bit event ID for cases where there is no match on the + connection. Used in packet start message to TCM. */ +#define PRS_REG_NO_MATCH_EVENT_ID 0x40070 +/* [ST 24] The number of input CFC flush packets */ +#define PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES 0x40128 +/* [ST 32] The number of cycles the Parser halted its operation since it + could not allocate the next serial number */ +#define PRS_REG_NUM_OF_DEAD_CYCLES 0x40130 +/* [ST 24] The number of input packets */ +#define PRS_REG_NUM_OF_PACKETS 0x40124 +/* [ST 24] The number of input transparent flush packets */ +#define PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES 0x4012c +/* [RW 8] Context region for received Ethernet packet with a match and + packet type 0. Used in CFC load request message */ +#define PRS_REG_PACKET_REGIONS_TYPE_0 0x40028 +#define PRS_REG_PACKET_REGIONS_TYPE_1 0x4002c +#define PRS_REG_PACKET_REGIONS_TYPE_2 0x40030 +#define PRS_REG_PACKET_REGIONS_TYPE_3 0x40034 +#define PRS_REG_PACKET_REGIONS_TYPE_4 0x40038 +#define PRS_REG_PACKET_REGIONS_TYPE_5 0x4003c +#define PRS_REG_PACKET_REGIONS_TYPE_6 0x40040 +#define PRS_REG_PACKET_REGIONS_TYPE_7 0x40044 +/* [R 2] debug only: Number of pending requests for CAC on port 0. */ +#define PRS_REG_PENDING_BRB_CAC0_RQ 0x40174 +/* [R 2] debug only: Number of pending requests for header parsing. */ +#define PRS_REG_PENDING_BRB_PRS_RQ 0x40170 +/* [R 1] Interrupt register #0 read */ +#define PRS_REG_PRS_INT_STS 0x40188 +/* [RW 8] Parity mask register #0 read/write */ +#define PRS_REG_PRS_PRTY_MASK 0x401a4 +/* [RW 8] Context region for pure acknowledge packets. Used in CFC load + request message */ +#define PRS_REG_PURE_REGIONS 0x40024 +/* [R 32] debug only: Serial number status lsb 32 bits. '1' indicates this + serail number was released by SDM but cannot be used because a previous + serial number was not released. */ +#define PRS_REG_SERIAL_NUM_STATUS_LSB 0x40154 +/* [R 32] debug only: Serial number status msb 32 bits. '1' indicates this + serail number was released by SDM but cannot be used because a previous + serial number was not released. */ +#define PRS_REG_SERIAL_NUM_STATUS_MSB 0x40158 +/* [R 4] debug only: SRC current credit. Transaction based. */ +#define PRS_REG_SRC_CURRENT_CREDIT 0x4016c +/* [R 8] debug only: TCM current credit. Cycle based. */ +#define PRS_REG_TCM_CURRENT_CREDIT 0x40160 +/* [R 8] debug only: TSDM current credit. Transaction based. */ +#define PRS_REG_TSDM_CURRENT_CREDIT 0x4015c +/* [R 6] Debug only: Number of used entries in the data FIFO */ +#define PXP2_REG_HST_DATA_FIFO_STATUS 0x12047c +/* [R 7] Debug only: Number of used entries in the header FIFO */ +#define PXP2_REG_HST_HEADER_FIFO_STATUS 0x120478 +#define PXP2_REG_PGL_CONTROL0 0x120490 +#define PXP2_REG_PGL_CONTROL1 0x120514 +/* [RW 32] Inbound interrupt table for CSDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_CSDM_0 0x1204f4 +#define PXP2_REG_PGL_INT_CSDM_1 0x1204f8 +#define PXP2_REG_PGL_INT_CSDM_2 0x1204fc +#define PXP2_REG_PGL_INT_CSDM_3 0x120500 +#define PXP2_REG_PGL_INT_CSDM_4 0x120504 +#define PXP2_REG_PGL_INT_CSDM_5 0x120508 +#define PXP2_REG_PGL_INT_CSDM_6 0x12050c +#define PXP2_REG_PGL_INT_CSDM_7 0x120510 +/* [RW 32] Inbound interrupt table for TSDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_TSDM_0 0x120494 +#define PXP2_REG_PGL_INT_TSDM_1 0x120498 +#define PXP2_REG_PGL_INT_TSDM_2 0x12049c +#define PXP2_REG_PGL_INT_TSDM_3 0x1204a0 +#define PXP2_REG_PGL_INT_TSDM_4 0x1204a4 +#define PXP2_REG_PGL_INT_TSDM_5 0x1204a8 +#define PXP2_REG_PGL_INT_TSDM_6 0x1204ac +#define PXP2_REG_PGL_INT_TSDM_7 0x1204b0 +/* [RW 32] Inbound interrupt table for USDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_USDM_0 0x1204b4 +#define PXP2_REG_PGL_INT_USDM_1 0x1204b8 +#define PXP2_REG_PGL_INT_USDM_2 0x1204bc +#define PXP2_REG_PGL_INT_USDM_3 0x1204c0 +#define PXP2_REG_PGL_INT_USDM_4 0x1204c4 +#define PXP2_REG_PGL_INT_USDM_5 0x1204c8 +#define PXP2_REG_PGL_INT_USDM_6 0x1204cc +#define PXP2_REG_PGL_INT_USDM_7 0x1204d0 +/* [RW 32] Inbound interrupt table for XSDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_XSDM_0 0x1204d4 +#define PXP2_REG_PGL_INT_XSDM_1 0x1204d8 +#define PXP2_REG_PGL_INT_XSDM_2 0x1204dc +#define PXP2_REG_PGL_INT_XSDM_3 0x1204e0 +#define PXP2_REG_PGL_INT_XSDM_4 0x1204e4 +#define PXP2_REG_PGL_INT_XSDM_5 0x1204e8 +#define PXP2_REG_PGL_INT_XSDM_6 0x1204ec +#define PXP2_REG_PGL_INT_XSDM_7 0x1204f0 +/* [R 1] this bit indicates that a read request was blocked because of + bus_master_en was deasserted */ +#define PXP2_REG_PGL_READ_BLOCKED 0x120568 +/* [R 6] debug only */ +#define PXP2_REG_PGL_TXR_CDTS 0x120528 +/* [R 18] debug only */ +#define PXP2_REG_PGL_TXW_CDTS 0x12052c +/* [R 1] this bit indicates that a write request was blocked because of + bus_master_en was deasserted */ +#define PXP2_REG_PGL_WRITE_BLOCKED 0x120564 +#define PXP2_REG_PSWRQ_BW_ADD1 0x1201c0 +#define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 +#define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 +#define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 +#define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 +#define PXP2_REG_PSWRQ_BW_ADD2 0x1201c4 +#define PXP2_REG_PSWRQ_BW_ADD28 0x120228 +#define PXP2_REG_PSWRQ_BW_ADD28 0x120228 +#define PXP2_REG_PSWRQ_BW_ADD3 0x1201c8 +#define PXP2_REG_PSWRQ_BW_ADD6 0x1201d4 +#define PXP2_REG_PSWRQ_BW_ADD7 0x1201d8 +#define PXP2_REG_PSWRQ_BW_ADD8 0x1201dc +#define PXP2_REG_PSWRQ_BW_ADD9 0x1201e0 +#define PXP2_REG_PSWRQ_BW_CREDIT 0x12032c +#define PXP2_REG_PSWRQ_BW_L1 0x1202b0 +#define PXP2_REG_PSWRQ_BW_L10 0x1202d4 +#define PXP2_REG_PSWRQ_BW_L11 0x1202d8 +#define PXP2_REG_PSWRQ_BW_L10 0x1202d4 +#define PXP2_REG_PSWRQ_BW_L11 0x1202d8 +#define PXP2_REG_PSWRQ_BW_L2 0x1202b4 +#define PXP2_REG_PSWRQ_BW_L28 0x120318 +#define PXP2_REG_PSWRQ_BW_L28 0x120318 +#define PXP2_REG_PSWRQ_BW_L3 0x1202b8 +#define PXP2_REG_PSWRQ_BW_L6 0x1202c4 +#define PXP2_REG_PSWRQ_BW_L7 0x1202c8 +#define PXP2_REG_PSWRQ_BW_L8 0x1202cc +#define PXP2_REG_PSWRQ_BW_L9 0x1202d0 +#define PXP2_REG_PSWRQ_BW_RD 0x120324 +#define PXP2_REG_PSWRQ_BW_UB1 0x120238 +#define PXP2_REG_PSWRQ_BW_UB10 0x12025c +#define PXP2_REG_PSWRQ_BW_UB11 0x120260 +#define PXP2_REG_PSWRQ_BW_UB10 0x12025c +#define PXP2_REG_PSWRQ_BW_UB11 0x120260 +#define PXP2_REG_PSWRQ_BW_UB2 0x12023c +#define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 +#define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 +#define PXP2_REG_PSWRQ_BW_UB3 0x120240 +#define PXP2_REG_PSWRQ_BW_UB6 0x12024c +#define PXP2_REG_PSWRQ_BW_UB7 0x120250 +#define PXP2_REG_PSWRQ_BW_UB8 0x120254 +#define PXP2_REG_PSWRQ_BW_UB9 0x120258 +#define PXP2_REG_PSWRQ_BW_WR 0x120328 +#define PXP2_REG_PSWRQ_CDU0_L2P 0x120000 +#define PXP2_REG_PSWRQ_QM0_L2P 0x120038 +#define PXP2_REG_PSWRQ_SRC0_L2P 0x120054 +#define PXP2_REG_PSWRQ_TM0_L2P 0x12001c +/* [RW 25] Interrupt mask register #0 read/write */ +#define PXP2_REG_PXP2_INT_MASK 0x120578 +/* [R 25] Interrupt register #0 read */ +#define PXP2_REG_PXP2_INT_STS 0x12056c +/* [RC 25] Interrupt register #0 read clear */ +#define PXP2_REG_PXP2_INT_STS_CLR 0x120570 +/* [RW 32] Parity mask register #0 read/write */ +#define PXP2_REG_PXP2_PRTY_MASK_0 0x120588 +#define PXP2_REG_PXP2_PRTY_MASK_1 0x120598 +/* [R 1] Debug only: The 'almost full' indication from each fifo (gives + indication about backpressure) */ +#define PXP2_REG_RD_ALMOST_FULL_0 0x120424 +/* [R 8] Debug only: The blocks counter - number of unused block ids */ +#define PXP2_REG_RD_BLK_CNT 0x120418 +/* [RW 8] Debug only: Total number of available blocks in Tetris Buffer. + Must be bigger than 6. Normally should not be changed. */ +#define PXP2_REG_RD_BLK_NUM_CFG 0x12040c +/* [RW 2] CDU byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_CDURD_SWAP_MODE 0x120404 +/* [RW 1] When '1'; inputs to the PSWRD block are ignored */ +#define PXP2_REG_RD_DISABLE_INPUTS 0x120374 +/* [R 1] PSWRD internal memories initialization is done */ +#define PXP2_REG_RD_INIT_DONE 0x120370 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq10 */ +#define PXP2_REG_RD_MAX_BLKS_VQ10 0x1203a0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq11 */ +#define PXP2_REG_RD_MAX_BLKS_VQ11 0x1203a4 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq17 */ +#define PXP2_REG_RD_MAX_BLKS_VQ17 0x1203bc +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq18 */ +#define PXP2_REG_RD_MAX_BLKS_VQ18 0x1203c0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq19 */ +#define PXP2_REG_RD_MAX_BLKS_VQ19 0x1203c4 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq22 */ +#define PXP2_REG_RD_MAX_BLKS_VQ22 0x1203d0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq6 */ +#define PXP2_REG_RD_MAX_BLKS_VQ6 0x120390 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq9 */ +#define PXP2_REG_RD_MAX_BLKS_VQ9 0x12039c +/* [RW 2] PBF byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_PBF_SWAP_MODE 0x1203f4 +/* [R 1] Debug only: Indication if delivery ports are idle */ +#define PXP2_REG_RD_PORT_IS_IDLE_0 0x12041c +#define PXP2_REG_RD_PORT_IS_IDLE_1 0x120420 +/* [RW 2] QM byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_QM_SWAP_MODE 0x1203f8 +/* [R 7] Debug only: The SR counter - number of unused sub request ids */ +#define PXP2_REG_RD_SR_CNT 0x120414 +/* [RW 2] SRC byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_SRC_SWAP_MODE 0x120400 +/* [RW 7] Debug only: Total number of available PCI read sub-requests. Must + be bigger than 1. Normally should not be changed. */ +#define PXP2_REG_RD_SR_NUM_CFG 0x120408 +/* [RW 1] Signals the PSWRD block to start initializing internal memories */ +#define PXP2_REG_RD_START_INIT 0x12036c +/* [RW 2] TM byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_TM_SWAP_MODE 0x1203fc +/* [RW 10] Bandwidth addition to VQ0 write requests */ +#define PXP2_REG_RQ_BW_RD_ADD0 0x1201bc +/* [RW 10] Bandwidth addition to VQ12 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD12 0x1201ec +/* [RW 10] Bandwidth addition to VQ13 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD13 0x1201f0 +/* [RW 10] Bandwidth addition to VQ14 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD14 0x1201f4 +/* [RW 10] Bandwidth addition to VQ15 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD15 0x1201f8 +/* [RW 10] Bandwidth addition to VQ16 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD16 0x1201fc +/* [RW 10] Bandwidth addition to VQ17 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD17 0x120200 +/* [RW 10] Bandwidth addition to VQ18 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD18 0x120204 +/* [RW 10] Bandwidth addition to VQ19 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD19 0x120208 +/* [RW 10] Bandwidth addition to VQ20 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD20 0x12020c +/* [RW 10] Bandwidth addition to VQ22 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD22 0x120210 +/* [RW 10] Bandwidth addition to VQ23 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD23 0x120214 +/* [RW 10] Bandwidth addition to VQ24 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD24 0x120218 +/* [RW 10] Bandwidth addition to VQ25 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD25 0x12021c +/* [RW 10] Bandwidth addition to VQ26 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD26 0x120220 +/* [RW 10] Bandwidth addition to VQ27 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD27 0x120224 +/* [RW 10] Bandwidth addition to VQ4 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD4 0x1201cc +/* [RW 10] Bandwidth addition to VQ5 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD5 0x1201d0 +/* [RW 10] Bandwidth Typical L for VQ0 Read requests */ +#define PXP2_REG_RQ_BW_RD_L0 0x1202ac +/* [RW 10] Bandwidth Typical L for VQ12 Read requests */ +#define PXP2_REG_RQ_BW_RD_L12 0x1202dc +/* [RW 10] Bandwidth Typical L for VQ13 Read requests */ +#define PXP2_REG_RQ_BW_RD_L13 0x1202e0 +/* [RW 10] Bandwidth Typical L for VQ14 Read requests */ +#define PXP2_REG_RQ_BW_RD_L14 0x1202e4 +/* [RW 10] Bandwidth Typical L for VQ15 Read requests */ +#define PXP2_REG_RQ_BW_RD_L15 0x1202e8 +/* [RW 10] Bandwidth Typical L for VQ16 Read requests */ +#define PXP2_REG_RQ_BW_RD_L16 0x1202ec +/* [RW 10] Bandwidth Typical L for VQ17 Read requests */ +#define PXP2_REG_RQ_BW_RD_L17 0x1202f0 +/* [RW 10] Bandwidth Typical L for VQ18 Read requests */ +#define PXP2_REG_RQ_BW_RD_L18 0x1202f4 +/* [RW 10] Bandwidth Typical L for VQ19 Read requests */ +#define PXP2_REG_RQ_BW_RD_L19 0x1202f8 +/* [RW 10] Bandwidth Typical L for VQ20 Read requests */ +#define PXP2_REG_RQ_BW_RD_L20 0x1202fc +/* [RW 10] Bandwidth Typical L for VQ22 Read requests */ +#define PXP2_REG_RQ_BW_RD_L22 0x120300 +/* [RW 10] Bandwidth Typical L for VQ23 Read requests */ +#define PXP2_REG_RQ_BW_RD_L23 0x120304 +/* [RW 10] Bandwidth Typical L for VQ24 Read requests */ +#define PXP2_REG_RQ_BW_RD_L24 0x120308 +/* [RW 10] Bandwidth Typical L for VQ25 Read requests */ +#define PXP2_REG_RQ_BW_RD_L25 0x12030c +/* [RW 10] Bandwidth Typical L for VQ26 Read requests */ +#define PXP2_REG_RQ_BW_RD_L26 0x120310 +/* [RW 10] Bandwidth Typical L for VQ27 Read requests */ +#define PXP2_REG_RQ_BW_RD_L27 0x120314 +/* [RW 10] Bandwidth Typical L for VQ4 Read requests */ +#define PXP2_REG_RQ_BW_RD_L4 0x1202bc +/* [RW 10] Bandwidth Typical L for VQ5 Read- currently not used */ +#define PXP2_REG_RQ_BW_RD_L5 0x1202c0 +/* [RW 7] Bandwidth upper bound for VQ0 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND0 0x120234 +/* [RW 7] Bandwidth upper bound for VQ12 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND12 0x120264 +/* [RW 7] Bandwidth upper bound for VQ13 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND13 0x120268 +/* [RW 7] Bandwidth upper bound for VQ14 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND14 0x12026c +/* [RW 7] Bandwidth upper bound for VQ15 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND15 0x120270 +/* [RW 7] Bandwidth upper bound for VQ16 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND16 0x120274 +/* [RW 7] Bandwidth upper bound for VQ17 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND17 0x120278 +/* [RW 7] Bandwidth upper bound for VQ18 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND18 0x12027c +/* [RW 7] Bandwidth upper bound for VQ19 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND19 0x120280 +/* [RW 7] Bandwidth upper bound for VQ20 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND20 0x120284 +/* [RW 7] Bandwidth upper bound for VQ22 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND22 0x120288 +/* [RW 7] Bandwidth upper bound for VQ23 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND23 0x12028c +/* [RW 7] Bandwidth upper bound for VQ24 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND24 0x120290 +/* [RW 7] Bandwidth upper bound for VQ25 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND25 0x120294 +/* [RW 7] Bandwidth upper bound for VQ26 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND26 0x120298 +/* [RW 7] Bandwidth upper bound for VQ27 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND27 0x12029c +/* [RW 7] Bandwidth upper bound for VQ4 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND4 0x120244 +/* [RW 7] Bandwidth upper bound for VQ5 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND5 0x120248 +/* [RW 10] Bandwidth addition to VQ29 write requests */ +#define PXP2_REG_RQ_BW_WR_ADD29 0x12022c +/* [RW 10] Bandwidth addition to VQ30 write requests */ +#define PXP2_REG_RQ_BW_WR_ADD30 0x120230 +/* [RW 10] Bandwidth Typical L for VQ29 Write requests */ +#define PXP2_REG_RQ_BW_WR_L29 0x12031c +/* [RW 10] Bandwidth Typical L for VQ30 Write requests */ +#define PXP2_REG_RQ_BW_WR_L30 0x120320 +/* [RW 7] Bandwidth upper bound for VQ29 */ +#define PXP2_REG_RQ_BW_WR_UBOUND29 0x1202a4 +/* [RW 7] Bandwidth upper bound for VQ30 */ +#define PXP2_REG_RQ_BW_WR_UBOUND30 0x1202a8 +/* [RW 2] Endian mode for cdu */ +#define PXP2_REG_RQ_CDU_ENDIAN_M 0x1201a0 +/* [RW 3] page size in L2P table for CDU module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_CDU_P_SIZE 0x120018 +/* [R 1] 1' indicates that the requester has finished its internal + configuration */ +#define PXP2_REG_RQ_CFG_DONE 0x1201b4 +/* [RW 2] Endian mode for debug */ +#define PXP2_REG_RQ_DBG_ENDIAN_M 0x1201a4 +/* [RW 1] When '1'; requests will enter input buffers but wont get out + towards the glue */ +#define PXP2_REG_RQ_DISABLE_INPUTS 0x120330 +/* [RW 2] Endian mode for hc */ +#define PXP2_REG_RQ_HC_ENDIAN_M 0x1201a8 +/* [WB 53] Onchip address table */ +#define PXP2_REG_RQ_ONCHIP_AT 0x122000 +/* [RW 2] Endian mode for qm */ +#define PXP2_REG_RQ_QM_ENDIAN_M 0x120194 +/* [RW 3] page size in L2P table for QM module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_QM_P_SIZE 0x120050 +/* [RW 1] 1' indicates that the RBC has finished configurating the PSWRQ */ +#define PXP2_REG_RQ_RBC_DONE 0x1201b0 +/* [RW 3] Max burst size filed for read requests port 0; 000 - 128B; + 001:256B; 010: 512B; 11:1K:100:2K; 01:4K */ +#define PXP2_REG_RQ_RD_MBS0 0x120160 +/* [RW 2] Endian mode for src */ +#define PXP2_REG_RQ_SRC_ENDIAN_M 0x12019c +/* [RW 3] page size in L2P table for SRC module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_SRC_P_SIZE 0x12006c +/* [RW 2] Endian mode for tm */ +#define PXP2_REG_RQ_TM_ENDIAN_M 0x120198 +/* [RW 3] page size in L2P table for TM module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_TM_P_SIZE 0x120034 +/* [R 5] Number of entries in the ufifo; his fifo has l2p completions */ +#define PXP2_REG_RQ_UFIFO_NUM_OF_ENTRY 0x12080c +/* [R 8] Number of entries occupied by vq 0 in pswrq memory */ +#define PXP2_REG_RQ_VQ0_ENTRY_CNT 0x120810 +/* [R 8] Number of entries occupied by vq 10 in pswrq memory */ +#define PXP2_REG_RQ_VQ10_ENTRY_CNT 0x120818 +/* [R 8] Number of entries occupied by vq 11 in pswrq memory */ +#define PXP2_REG_RQ_VQ11_ENTRY_CNT 0x120820 +/* [R 8] Number of entries occupied by vq 12 in pswrq memory */ +#define PXP2_REG_RQ_VQ12_ENTRY_CNT 0x120828 +/* [R 8] Number of entries occupied by vq 13 in pswrq memory */ +#define PXP2_REG_RQ_VQ13_ENTRY_CNT 0x120830 +/* [R 8] Number of entries occupied by vq 14 in pswrq memory */ +#define PXP2_REG_RQ_VQ14_ENTRY_CNT 0x120838 +/* [R 8] Number of entries occupied by vq 15 in pswrq memory */ +#define PXP2_REG_RQ_VQ15_ENTRY_CNT 0x120840 +/* [R 8] Number of entries occupied by vq 16 in pswrq memory */ +#define PXP2_REG_RQ_VQ16_ENTRY_CNT 0x120848 +/* [R 8] Number of entries occupied by vq 17 in pswrq memory */ +#define PXP2_REG_RQ_VQ17_ENTRY_CNT 0x120850 +/* [R 8] Number of entries occupied by vq 18 in pswrq memory */ +#define PXP2_REG_RQ_VQ18_ENTRY_CNT 0x120858 +/* [R 8] Number of entries occupied by vq 19 in pswrq memory */ +#define PXP2_REG_RQ_VQ19_ENTRY_CNT 0x120860 +/* [R 8] Number of entries occupied by vq 1 in pswrq memory */ +#define PXP2_REG_RQ_VQ1_ENTRY_CNT 0x120868 +/* [R 8] Number of entries occupied by vq 20 in pswrq memory */ +#define PXP2_REG_RQ_VQ20_ENTRY_CNT 0x120870 +/* [R 8] Number of entries occupied by vq 21 in pswrq memory */ +#define PXP2_REG_RQ_VQ21_ENTRY_CNT 0x120878 +/* [R 8] Number of entries occupied by vq 22 in pswrq memory */ +#define PXP2_REG_RQ_VQ22_ENTRY_CNT 0x120880 +/* [R 8] Number of entries occupied by vq 23 in pswrq memory */ +#define PXP2_REG_RQ_VQ23_ENTRY_CNT 0x120888 +/* [R 8] Number of entries occupied by vq 24 in pswrq memory */ +#define PXP2_REG_RQ_VQ24_ENTRY_CNT 0x120890 +/* [R 8] Number of entries occupied by vq 25 in pswrq memory */ +#define PXP2_REG_RQ_VQ25_ENTRY_CNT 0x120898 +/* [R 8] Number of entries occupied by vq 26 in pswrq memory */ +#define PXP2_REG_RQ_VQ26_ENTRY_CNT 0x1208a0 +/* [R 8] Number of entries occupied by vq 27 in pswrq memory */ +#define PXP2_REG_RQ_VQ27_ENTRY_CNT 0x1208a8 +/* [R 8] Number of entries occupied by vq 28 in pswrq memory */ +#define PXP2_REG_RQ_VQ28_ENTRY_CNT 0x1208b0 +/* [R 8] Number of entries occupied by vq 29 in pswrq memory */ +#define PXP2_REG_RQ_VQ29_ENTRY_CNT 0x1208b8 +/* [R 8] Number of entries occupied by vq 2 in pswrq memory */ +#define PXP2_REG_RQ_VQ2_ENTRY_CNT 0x1208c0 +/* [R 8] Number of entries occupied by vq 30 in pswrq memory */ +#define PXP2_REG_RQ_VQ30_ENTRY_CNT 0x1208c8 +/* [R 8] Number of entries occupied by vq 31 in pswrq memory */ +#define PXP2_REG_RQ_VQ31_ENTRY_CNT 0x1208d0 +/* [R 8] Number of entries occupied by vq 3 in pswrq memory */ +#define PXP2_REG_RQ_VQ3_ENTRY_CNT 0x1208d8 +/* [R 8] Number of entries occupied by vq 4 in pswrq memory */ +#define PXP2_REG_RQ_VQ4_ENTRY_CNT 0x1208e0 +/* [R 8] Number of entries occupied by vq 5 in pswrq memory */ +#define PXP2_REG_RQ_VQ5_ENTRY_CNT 0x1208e8 +/* [R 8] Number of entries occupied by vq 6 in pswrq memory */ +#define PXP2_REG_RQ_VQ6_ENTRY_CNT 0x1208f0 +/* [R 8] Number of entries occupied by vq 7 in pswrq memory */ +#define PXP2_REG_RQ_VQ7_ENTRY_CNT 0x1208f8 +/* [R 8] Number of entries occupied by vq 8 in pswrq memory */ +#define PXP2_REG_RQ_VQ8_ENTRY_CNT 0x120900 +/* [R 8] Number of entries occupied by vq 9 in pswrq memory */ +#define PXP2_REG_RQ_VQ9_ENTRY_CNT 0x120908 +/* [RW 3] Max burst size filed for write requests port 0; 000 - 128B; + 001:256B; 010: 512B; */ +#define PXP2_REG_RQ_WR_MBS0 0x12015c +/* [RW 10] if Number of entries in dmae fifo will be higer than this + threshold then has_payload indication will be asserted; the default value + should be equal to > write MBS size! */ +#define PXP2_REG_WR_DMAE_TH 0x120368 +/* [R 1] debug only: Indication if PSWHST arbiter is idle */ +#define PXP_REG_HST_ARB_IS_IDLE 0x103004 +/* [R 8] debug only: A bit mask for all PSWHST arbiter clients. '1' means + this client is waiting for the arbiter. */ +#define PXP_REG_HST_CLIENTS_WAITING_TO_ARB 0x103008 +/* [WB 160] Used for initialization of the inbound interrupts memory */ +#define PXP_REG_HST_INBOUND_INT 0x103800 +/* [RW 32] Interrupt mask register #0 read/write */ +#define PXP_REG_PXP_INT_MASK_0 0x103074 +#define PXP_REG_PXP_INT_MASK_1 0x103084 +/* [R 32] Interrupt register #0 read */ +#define PXP_REG_PXP_INT_STS_0 0x103068 +#define PXP_REG_PXP_INT_STS_1 0x103078 +/* [RC 32] Interrupt register #0 read clear */ +#define PXP_REG_PXP_INT_STS_CLR_0 0x10306c +/* [RW 26] Parity mask register #0 read/write */ +#define PXP_REG_PXP_PRTY_MASK 0x103094 +/* [RW 4] The activity counter initial increment value sent in the load + request */ +#define QM_REG_ACTCTRINITVAL_0 0x168040 +#define QM_REG_ACTCTRINITVAL_1 0x168044 +#define QM_REG_ACTCTRINITVAL_2 0x168048 +#define QM_REG_ACTCTRINITVAL_3 0x16804c +/* [RW 32] The base logical address (in bytes) of each physical queue. The + index I represents the physical queue number. The 12 lsbs are ignore and + considered zero so practically there are only 20 bits in this register. */ +#define QM_REG_BASEADDR 0x168900 +/* [RW 16] The byte credit cost for each task. This value is for both ports */ +#define QM_REG_BYTECRDCOST 0x168234 +/* [RW 16] The initial byte credit value for both ports. */ +#define QM_REG_BYTECRDINITVAL 0x168238 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1. */ +#define QM_REG_BYTECRDPORT_LSB 0x168228 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1. */ +#define QM_REG_BYTECRDPORT_MSB 0x168224 +/* [RW 16] The byte credit value that if above the QM is considered almost + full */ +#define QM_REG_BYTECREDITAFULLTHR 0x168094 +/* [RW 4] The initial credit for interface */ +#define QM_REG_CMINITCRD_0 0x1680cc +#define QM_REG_CMINITCRD_1 0x1680d0 +#define QM_REG_CMINITCRD_2 0x1680d4 +#define QM_REG_CMINITCRD_3 0x1680d8 +#define QM_REG_CMINITCRD_4 0x1680dc +#define QM_REG_CMINITCRD_5 0x1680e0 +#define QM_REG_CMINITCRD_6 0x1680e4 +#define QM_REG_CMINITCRD_7 0x1680e8 +/* [RW 8] A mask bit per CM interface. If this bit is 0 then this interface + is masked */ +#define QM_REG_CMINTEN 0x1680ec +/* [RW 12] A bit vector which indicates which one of the queues are tied to + interface 0 */ +#define QM_REG_CMINTVOQMASK_0 0x1681f4 +#define QM_REG_CMINTVOQMASK_1 0x1681f8 +#define QM_REG_CMINTVOQMASK_2 0x1681fc +#define QM_REG_CMINTVOQMASK_3 0x168200 +#define QM_REG_CMINTVOQMASK_4 0x168204 +#define QM_REG_CMINTVOQMASK_5 0x168208 +#define QM_REG_CMINTVOQMASK_6 0x16820c +#define QM_REG_CMINTVOQMASK_7 0x168210 +/* [RW 20] The number of connections divided by 16 which dictates the size + of each queue per port 0 */ +#define QM_REG_CONNNUM_0 0x168020 +/* [R 6] Keep the fill level of the fifo from write client 4 */ +#define QM_REG_CQM_WRC_FIFOLVL 0x168018 +/* [RW 8] The context regions sent in the CFC load request */ +#define QM_REG_CTXREG_0 0x168030 +#define QM_REG_CTXREG_1 0x168034 +#define QM_REG_CTXREG_2 0x168038 +#define QM_REG_CTXREG_3 0x16803c +/* [RW 12] The VOQ mask used to select the VOQs which needs to be full for + bypass enable */ +#define QM_REG_ENBYPVOQMASK 0x16823c +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit */ +#define QM_REG_ENBYTECRD_LSB 0x168220 +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit */ +#define QM_REG_ENBYTECRD_MSB 0x16821c +/* [RW 4] If cleared then the secondary interface will not be served by the + RR arbiter */ +#define QM_REG_ENSEC 0x1680f0 +/* [RW 32] A bit vector per each physical queue which selects which function + number to use on PCI access for that queue. */ +#define QM_REG_FUNCNUMSEL_LSB 0x168230 +/* [RW 32] A bit vector per each physical queue which selects which function + number to use on PCI access for that queue. */ +#define QM_REG_FUNCNUMSEL_MSB 0x16822c +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block */ +#define QM_REG_HWAEMPTYMASK_LSB 0x168218 +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block */ +#define QM_REG_HWAEMPTYMASK_MSB 0x168214 +/* [RW 4] The number of outstanding request to CFC */ +#define QM_REG_OUTLDREQ 0x168804 +/* [RC 1] A flag to indicate that overflow error occurred in one of the + queues. */ +#define QM_REG_OVFERROR 0x16805c +/* [RC 6] the Q were the qverflow occurs */ +#define QM_REG_OVFQNUM 0x168058 +/* [R 32] Pause state for physical queues 31-0 */ +#define QM_REG_PAUSESTATE0 0x168410 +/* [R 32] Pause state for physical queues 64-32 */ +#define QM_REG_PAUSESTATE1 0x168414 +/* [RW 2] The PCI attributes field used in the PCI request. */ +#define QM_REG_PCIREQAT 0x168054 +/* [R 16] The byte credit of port 0 */ +#define QM_REG_PORT0BYTECRD 0x168300 +/* [R 16] The byte credit of port 1 */ +#define QM_REG_PORT1BYTECRD 0x168304 +/* [WB 54] Pointer Table Memory; The mapping is as follow: ptrtbl[53:30] + read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read bank0; + ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */ +#define QM_REG_PTRTBL 0x168a00 +/* [RW 2] Interrupt mask register #0 read/write */ +#define QM_REG_QM_INT_MASK 0x168444 +/* [R 2] Interrupt register #0 read */ +#define QM_REG_QM_INT_STS 0x168438 +/* [RW 9] Parity mask register #0 read/write */ +#define QM_REG_QM_PRTY_MASK 0x168454 +/* [R 32] Current queues in pipeline: Queues from 32 to 63 */ +#define QM_REG_QSTATUS_HIGH 0x16802c +/* [R 32] Current queues in pipeline: Queues from 0 to 31 */ +#define QM_REG_QSTATUS_LOW 0x168028 +/* [R 24] The number of tasks queued for each queue */ +#define QM_REG_QTASKCTR_0 0x168308 +/* [RW 4] Queue tied to VOQ */ +#define QM_REG_QVOQIDX_0 0x1680f4 +#define QM_REG_QVOQIDX_10 0x16811c +#define QM_REG_QVOQIDX_11 0x168120 +#define QM_REG_QVOQIDX_12 0x168124 +#define QM_REG_QVOQIDX_13 0x168128 +#define QM_REG_QVOQIDX_14 0x16812c +#define QM_REG_QVOQIDX_15 0x168130 +#define QM_REG_QVOQIDX_16 0x168134 +#define QM_REG_QVOQIDX_17 0x168138 +#define QM_REG_QVOQIDX_21 0x168148 +#define QM_REG_QVOQIDX_25 0x168158 +#define QM_REG_QVOQIDX_29 0x168168 +#define QM_REG_QVOQIDX_32 0x168174 +#define QM_REG_QVOQIDX_33 0x168178 +#define QM_REG_QVOQIDX_34 0x16817c +#define QM_REG_QVOQIDX_35 0x168180 +#define QM_REG_QVOQIDX_36 0x168184 +#define QM_REG_QVOQIDX_37 0x168188 +#define QM_REG_QVOQIDX_38 0x16818c +#define QM_REG_QVOQIDX_39 0x168190 +#define QM_REG_QVOQIDX_40 0x168194 +#define QM_REG_QVOQIDX_41 0x168198 +#define QM_REG_QVOQIDX_42 0x16819c +#define QM_REG_QVOQIDX_43 0x1681a0 +#define QM_REG_QVOQIDX_44 0x1681a4 +#define QM_REG_QVOQIDX_45 0x1681a8 +#define QM_REG_QVOQIDX_46 0x1681ac +#define QM_REG_QVOQIDX_47 0x1681b0 +#define QM_REG_QVOQIDX_48 0x1681b4 +#define QM_REG_QVOQIDX_49 0x1681b8 +#define QM_REG_QVOQIDX_5 0x168108 +#define QM_REG_QVOQIDX_50 0x1681bc +#define QM_REG_QVOQIDX_51 0x1681c0 +#define QM_REG_QVOQIDX_52 0x1681c4 +#define QM_REG_QVOQIDX_53 0x1681c8 +#define QM_REG_QVOQIDX_54 0x1681cc +#define QM_REG_QVOQIDX_55 0x1681d0 +#define QM_REG_QVOQIDX_56 0x1681d4 +#define QM_REG_QVOQIDX_57 0x1681d8 +#define QM_REG_QVOQIDX_58 0x1681dc +#define QM_REG_QVOQIDX_59 0x1681e0 +#define QM_REG_QVOQIDX_50 0x1681bc +#define QM_REG_QVOQIDX_51 0x1681c0 +#define QM_REG_QVOQIDX_52 0x1681c4 +#define QM_REG_QVOQIDX_53 0x1681c8 +#define QM_REG_QVOQIDX_54 0x1681cc +#define QM_REG_QVOQIDX_55 0x1681d0 +#define QM_REG_QVOQIDX_56 0x1681d4 +#define QM_REG_QVOQIDX_57 0x1681d8 +#define QM_REG_QVOQIDX_58 0x1681dc +#define QM_REG_QVOQIDX_59 0x1681e0 +#define QM_REG_QVOQIDX_6 0x16810c +#define QM_REG_QVOQIDX_60 0x1681e4 +#define QM_REG_QVOQIDX_61 0x1681e8 +#define QM_REG_QVOQIDX_62 0x1681ec +#define QM_REG_QVOQIDX_63 0x1681f0 +#define QM_REG_QVOQIDX_60 0x1681e4 +#define QM_REG_QVOQIDX_61 0x1681e8 +#define QM_REG_QVOQIDX_62 0x1681ec +#define QM_REG_QVOQIDX_63 0x1681f0 +#define QM_REG_QVOQIDX_7 0x168110 +#define QM_REG_QVOQIDX_8 0x168114 +#define QM_REG_QVOQIDX_9 0x168118 +/* [R 24] Remaining pause timeout for port 0 */ +#define QM_REG_REMAINPAUSETM0 0x168418 +/* [R 24] Remaining pause timeout for port 1 */ +#define QM_REG_REMAINPAUSETM1 0x16841c +/* [RW 1] Initialization bit command */ +#define QM_REG_SOFT_RESET 0x168428 +/* [RW 8] The credit cost per every task in the QM. A value per each VOQ */ +#define QM_REG_TASKCRDCOST_0 0x16809c +#define QM_REG_TASKCRDCOST_1 0x1680a0 +#define QM_REG_TASKCRDCOST_10 0x1680c4 +#define QM_REG_TASKCRDCOST_11 0x1680c8 +#define QM_REG_TASKCRDCOST_2 0x1680a4 +#define QM_REG_TASKCRDCOST_4 0x1680ac +#define QM_REG_TASKCRDCOST_5 0x1680b0 +/* [R 6] Keep the fill level of the fifo from write client 3 */ +#define QM_REG_TQM_WRC_FIFOLVL 0x168010 +/* [R 6] Keep the fill level of the fifo from write client 2 */ +#define QM_REG_UQM_WRC_FIFOLVL 0x168008 +/* [RC 32] Credit update error register */ +#define QM_REG_VOQCRDERRREG 0x168408 +/* [R 16] The credit value for each VOQ */ +#define QM_REG_VOQCREDIT_0 0x1682d0 +#define QM_REG_VOQCREDIT_1 0x1682d4 +#define QM_REG_VOQCREDIT_10 0x1682f8 +#define QM_REG_VOQCREDIT_11 0x1682fc +#define QM_REG_VOQCREDIT_4 0x1682e0 +/* [RW 16] The credit value that if above the QM is considered almost full */ +#define QM_REG_VOQCREDITAFULLTHR 0x168090 +/* [RW 16] The init and maximum credit for each VoQ */ +#define QM_REG_VOQINITCREDIT_0 0x168060 +#define QM_REG_VOQINITCREDIT_1 0x168064 +#define QM_REG_VOQINITCREDIT_10 0x168088 +#define QM_REG_VOQINITCREDIT_11 0x16808c +#define QM_REG_VOQINITCREDIT_2 0x168068 +#define QM_REG_VOQINITCREDIT_4 0x168070 +#define QM_REG_VOQINITCREDIT_5 0x168074 +/* [RW 1] The port of which VOQ belongs */ +#define QM_REG_VOQPORT_1 0x1682a4 +#define QM_REG_VOQPORT_10 0x1682c8 +#define QM_REG_VOQPORT_11 0x1682cc +#define QM_REG_VOQPORT_2 0x1682a8 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_0_LSB 0x168240 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_0_MSB 0x168244 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_1_MSB 0x16824c +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_2_LSB 0x168250 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_2_MSB 0x168254 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_3_LSB 0x168258 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_4_LSB 0x168260 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_4_MSB 0x168264 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_5_LSB 0x168268 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_5_MSB 0x16826c +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_6_LSB 0x168270 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_6_MSB 0x168274 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_7_LSB 0x168278 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_7_MSB 0x16827c +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_8_LSB 0x168280 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_8_MSB 0x168284 +/* [RW 32] The physical queue number associated with each VOQ */ +#define QM_REG_VOQQMASK_9_LSB 0x168288 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_0 0x16880c +#define QM_REG_WRRWEIGHTS_1 0x168810 +#define QM_REG_WRRWEIGHTS_10 0x168814 +#define QM_REG_WRRWEIGHTS_10_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_11 0x168818 +#define QM_REG_WRRWEIGHTS_11_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_12 0x16881c +#define QM_REG_WRRWEIGHTS_12_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_13 0x168820 +#define QM_REG_WRRWEIGHTS_13_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_14 0x168824 +#define QM_REG_WRRWEIGHTS_14_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_15 0x168828 +#define QM_REG_WRRWEIGHTS_15_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_10 0x168814 +#define QM_REG_WRRWEIGHTS_11 0x168818 +#define QM_REG_WRRWEIGHTS_12 0x16881c +#define QM_REG_WRRWEIGHTS_13 0x168820 +#define QM_REG_WRRWEIGHTS_14 0x168824 +#define QM_REG_WRRWEIGHTS_15 0x168828 +#define QM_REG_WRRWEIGHTS_2 0x16882c +#define QM_REG_WRRWEIGHTS_3 0x168830 +#define QM_REG_WRRWEIGHTS_4 0x168834 +#define QM_REG_WRRWEIGHTS_5 0x168838 +#define QM_REG_WRRWEIGHTS_6 0x16883c +#define QM_REG_WRRWEIGHTS_7 0x168840 +#define QM_REG_WRRWEIGHTS_8 0x168844 +#define QM_REG_WRRWEIGHTS_9 0x168848 +/* [R 6] Keep the fill level of the fifo from write client 1 */ +#define QM_REG_XQM_WRC_FIFOLVL 0x168000 +#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define DORQ_DORQ_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define DORQ_DORQ_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define DORQ_DORQ_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define DORQ_DORQ_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR (0x1<<0) +#define NIG_NIG_INT_STS_0_REG_ADDRESS_ERROR_SIZE 0 +#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR (0x1<<0) +#define NIG_NIG_INT_STS_CLR_0_REG_ADDRESS_ERROR_SIZE 0 +#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR (0x1<<0) +#define NIG_NIG_INT_STS_WR_0_REG_ADDRESS_ERROR_SIZE 0 +#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR (0x1<<0) +#define NIG_NIG_INT_MASK_0_REG_ADDRESS_ERROR_SIZE 0 +#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define TCM_TCM_INT_STS_REG_ADDRESS_ERROR_SIZE 0 +#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR (0x1<<0) +#define TCM_TCM_INT_STS_CLR_REG_ADDRESS_ERROR_SIZE 0 +#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR (0x1<<0) +#define TCM_TCM_INT_STS_WR_REG_ADDRESS_ERROR_SIZE 0 +#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR (0x1<<0) +#define TCM_TCM_INT_MASK_REG_ADDRESS_ERROR_SIZE 0 +#define CFC_DEBUG1_REG_WRITE_AC (0x1<<4) +#define CFC_DEBUG1_REG_WRITE_AC_SIZE 4 +/* [R 1] debug only: This bit indicates wheter indicates that external + buffer was wrapped (oldest data was thrown); Relevant only when + ~dbg_registers_debug_target=2 (PCI) & ~dbg_registers_full_mode=1 (wrap); */ +#define DBG_REG_WRAP_ON_EXT_BUFFER 0xc124 +#define DBG_REG_WRAP_ON_EXT_BUFFER_SIZE 1 +/* [R 1] debug only: This bit indicates wheter the internal buffer was + wrapped (oldest data was thrown) Relevant only when + ~dbg_registers_debug_target=0 (internal buffer) */ +#define DBG_REG_WRAP_ON_INT_BUFFER 0xc128 +#define DBG_REG_WRAP_ON_INT_BUFFER_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_0 0x16880c +#define QM_REG_WRRWEIGHTS_0_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_1 0x168810 +#define QM_REG_WRRWEIGHTS_1_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_10 0x168814 +#define QM_REG_WRRWEIGHTS_10_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_11 0x168818 +#define QM_REG_WRRWEIGHTS_11_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_12 0x16881c +#define QM_REG_WRRWEIGHTS_12_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_13 0x168820 +#define QM_REG_WRRWEIGHTS_13_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_14 0x168824 +#define QM_REG_WRRWEIGHTS_14_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_15 0x168828 +#define QM_REG_WRRWEIGHTS_15_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_2 0x16882c +#define QM_REG_WRRWEIGHTS_2_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_3 0x168830 +#define QM_REG_WRRWEIGHTS_3_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_4 0x168834 +#define QM_REG_WRRWEIGHTS_4_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_5 0x168838 +#define QM_REG_WRRWEIGHTS_5_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_6 0x16883c +#define QM_REG_WRRWEIGHTS_6_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_7 0x168840 +#define QM_REG_WRRWEIGHTS_7_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_8 0x168844 +#define QM_REG_WRRWEIGHTS_8_SIZE 1 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_9 0x168848 +#define QM_REG_WRRWEIGHTS_9_SIZE 1 +/* [RW 22] Number of free element in the free list of T2 entries - port 0. */ +#define SRC_REG_COUNTFREE0 0x40500 +/* [WB 64] First free element in the free list of T2 entries - port 0. */ +#define SRC_REG_FIRSTFREE0 0x40510 +#define SRC_REG_KEYRSS0_0 0x40408 +#define SRC_REG_KEYRSS1_9 0x40454 +/* [WB 64] Last free element in the free list of T2 entries - port 0. */ +#define SRC_REG_LASTFREE0 0x40530 +/* [RW 5] The number of hash bits used for the search (h); Values can be 8 + to 24. */ +#define SRC_REG_NUMBER_HASH_BITS0 0x40400 +/* [RW 1] Reset internal state machines. */ +#define SRC_REG_SOFT_RST 0x4049c +/* [R 1] Interrupt register #0 read */ +#define SRC_REG_SRC_INT_STS 0x404ac +/* [RW 3] Parity mask register #0 read/write */ +#define SRC_REG_SRC_PRTY_MASK 0x404c8 +/* [R 4] Used to read the value of the XX protection CAM occupancy counter. */ +#define TCM_REG_CAM_OCCUP 0x5017c +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define TCM_REG_CDU_AG_RD_IFEN 0x50034 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define TCM_REG_CDU_AG_WR_IFEN 0x50030 +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define TCM_REG_CDU_SM_RD_IFEN 0x5003c +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define TCM_REG_CDU_SM_WR_IFEN 0x50038 +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define TCM_REG_CFC_INIT_CRD 0x50204 +/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_CP_WEIGHT 0x500c0 +/* [RW 1] Input csem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_CSEM_IFEN 0x5002c +/* [RC 1] Message length mismatch (relative to last indication) at the In#9 + interface. */ +#define TCM_REG_CSEM_LENGTH_MIS 0x50174 +/* [RW 8] The Event ID in case of ErrorFlg is set in the input message. */ +#define TCM_REG_ERR_EVNT_ID 0x500a0 +/* [RW 28] The CM erroneous header for QM and Timers formatting. */ +#define TCM_REG_ERR_TCM_HDR 0x5009c +/* [RW 8] The Event ID for Timers expiration. */ +#define TCM_REG_EXPR_EVNT_ID 0x500a4 +/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define TCM_REG_FIC0_INIT_CRD 0x5020c +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define TCM_REG_FIC1_INIT_CRD 0x50210 +/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~tcm_registers_gr_ag_pr.gr_ag_pr; + ~tcm_registers_gr_ld0_pr.gr_ld0_pr and + ~tcm_registers_gr_ld1_pr.gr_ld1_pr. */ +#define TCM_REG_GR_ARB_TYPE 0x50114 +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel is the + compliment of the other 3 groups. */ +#define TCM_REG_GR_LD0_PR 0x5011c +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel is the + compliment of the other 3 groups. */ +#define TCM_REG_GR_LD1_PR 0x50120 +/* [RW 4] The number of double REG-pairs; loaded from the STORM context and + sent to STORM; for a specific connection type. The double REG-pairs are + used to align to STORM context row size of 128 bits. The offset of these + data in the STORM context is always 0. Index _i stands for the connection + type (one of 16). */ +#define TCM_REG_N_SM_CTX_LD_0 0x50050 +#define TCM_REG_N_SM_CTX_LD_1 0x50054 +#define TCM_REG_N_SM_CTX_LD_10 0x50078 +#define TCM_REG_N_SM_CTX_LD_11 0x5007c +#define TCM_REG_N_SM_CTX_LD_12 0x50080 +#define TCM_REG_N_SM_CTX_LD_13 0x50084 +#define TCM_REG_N_SM_CTX_LD_14 0x50088 +#define TCM_REG_N_SM_CTX_LD_15 0x5008c +#define TCM_REG_N_SM_CTX_LD_2 0x50058 +#define TCM_REG_N_SM_CTX_LD_3 0x5005c +#define TCM_REG_N_SM_CTX_LD_4 0x50060 +/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_PBF_IFEN 0x50024 +/* [RC 1] Message length mismatch (relative to last indication) at the In#7 + interface. */ +#define TCM_REG_PBF_LENGTH_MIS 0x5016c +/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_PBF_WEIGHT 0x500b4 +/* [RW 6] The physical queue number 0 per port index. */ +#define TCM_REG_PHYS_QNUM0_0 0x500e0 +#define TCM_REG_PHYS_QNUM0_1 0x500e4 +/* [RW 6] The physical queue number 1 per port index. */ +#define TCM_REG_PHYS_QNUM1_0 0x500e8 +/* [RW 1] Input prs Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_PRS_IFEN 0x50020 +/* [RC 1] Message length mismatch (relative to last indication) at the In#6 + interface. */ +#define TCM_REG_PRS_LENGTH_MIS 0x50168 +/* [RW 3] The weight of the input prs in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_PRS_WEIGHT 0x500b0 +/* [RW 8] The Event ID for Timers formatting in case of stop done. */ +#define TCM_REG_STOP_EVNT_ID 0x500a8 +/* [RC 1] Message length mismatch (relative to last indication) at the STORM + interface. */ +#define TCM_REG_STORM_LENGTH_MIS 0x50160 +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_STORM_TCM_IFEN 0x50010 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_CFC_IFEN 0x50040 +/* [RW 11] Interrupt mask register #0 read/write */ +#define TCM_REG_TCM_INT_MASK 0x501dc +/* [R 11] Interrupt register #0 read */ +#define TCM_REG_TCM_INT_STS 0x501d0 +/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the input message Reg1WbFlg isn't set. */ +#define TCM_REG_TCM_REG0_SZ 0x500d8 +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_STORM0_IFEN 0x50004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_STORM1_IFEN 0x50008 +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_TQM_IFEN 0x5000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */ +#define TCM_REG_TCM_TQM_USE_Q 0x500d4 +/* [RW 28] The CM header for Timers expiration command. */ +#define TCM_REG_TM_TCM_HDR 0x50098 +/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_TM_TCM_IFEN 0x5001c +/* [RW 6] QM output initial credit. Max credit available - 32.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define TCM_REG_TQM_INIT_CRD 0x5021c +/* [RW 28] The CM header value for QM request (primary). */ +#define TCM_REG_TQM_TCM_HDR_P 0x50090 +/* [RW 28] The CM header value for QM request (secondary). */ +#define TCM_REG_TQM_TCM_HDR_S 0x50094 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TQM_TCM_IFEN 0x50014 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TSDM_IFEN 0x50018 +/* [RC 1] Message length mismatch (relative to last indication) at the SDM + interface. */ +#define TCM_REG_TSDM_LENGTH_MIS 0x50164 +/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_TSDM_WEIGHT 0x500c4 +/* [RW 1] Input usem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_USEM_IFEN 0x50028 +/* [RC 1] Message length mismatch (relative to last indication) at the In#8 + interface. */ +#define TCM_REG_USEM_LENGTH_MIS 0x50170 +/* [RW 21] Indirect access to the descriptor table of the XX protection + mechanism. The fields are: [5:0] - length of the message; 15:6] - message + pointer; 20:16] - next pointer. */ +#define TCM_REG_XX_DESCR_TABLE 0x50280 +/* [R 6] Use to read the value of XX protection Free counter. */ +#define TCM_REG_XX_FREE 0x50178 +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Max credit available - 127.Write writes the initial credit + value; read returns the current value of the credit counter. Must be + initialized to 19 at start-up. */ +#define TCM_REG_XX_INIT_CRD 0x50220 +/* [RW 6] Maximum link list size (messages locked) per connection in the XX + protection. */ +#define TCM_REG_XX_MAX_LL_SZ 0x50044 +/* [RW 6] The maximum number of pending messages; which may be stored in XX + protection. ~tcm_registers_xx_free.xx_free is read on read. */ +#define TCM_REG_XX_MSG_NUM 0x50224 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define TCM_REG_XX_OVFL_EVNT_ID 0x50048 +/* [RW 16] Indirect access to the XX table of the XX protection mechanism. + The fields are:[4:0] - tail pointer; [10:5] - Link List size; 15:11] - + header pointer. */ +#define TCM_REG_XX_TABLE 0x50240 +/* [RW 4] Load value for for cfc ac credit cnt. */ +#define TM_REG_CFC_AC_CRDCNT_VAL 0x164208 +/* [RW 4] Load value for cfc cld credit cnt. */ +#define TM_REG_CFC_CLD_CRDCNT_VAL 0x164210 +/* [RW 8] Client0 context region. */ +#define TM_REG_CL0_CONT_REGION 0x164030 +/* [RW 8] Client1 context region. */ +#define TM_REG_CL1_CONT_REGION 0x164034 +/* [RW 8] Client2 context region. */ +#define TM_REG_CL2_CONT_REGION 0x164038 +/* [RW 2] Client in High priority client number. */ +#define TM_REG_CLIN_PRIOR0_CLIENT 0x164024 +/* [RW 4] Load value for clout0 cred cnt. */ +#define TM_REG_CLOUT_CRDCNT0_VAL 0x164220 +/* [RW 4] Load value for clout1 cred cnt. */ +#define TM_REG_CLOUT_CRDCNT1_VAL 0x164228 +/* [RW 4] Load value for clout2 cred cnt. */ +#define TM_REG_CLOUT_CRDCNT2_VAL 0x164230 +/* [RW 1] Enable client0 input. */ +#define TM_REG_EN_CL0_INPUT 0x164008 +/* [RW 1] Enable client1 input. */ +#define TM_REG_EN_CL1_INPUT 0x16400c +/* [RW 1] Enable client2 input. */ +#define TM_REG_EN_CL2_INPUT 0x164010 +/* [RW 1] Enable real time counter. */ +#define TM_REG_EN_REAL_TIME_CNT 0x1640d8 +/* [RW 1] Enable for Timers state machines. */ +#define TM_REG_EN_TIMERS 0x164000 +/* [RW 4] Load value for expiration credit cnt. CFC max number of + outstanding load requests for timers (expiration) context loading. */ +#define TM_REG_EXP_CRDCNT_VAL 0x164238 +/* [RW 18] Linear0 Max active cid. */ +#define TM_REG_LIN0_MAX_ACTIVE_CID 0x164048 +/* [WB 64] Linear0 phy address. */ +#define TM_REG_LIN0_PHY_ADDR 0x164270 +/* [RW 24] Linear0 array scan timeout. */ +#define TM_REG_LIN0_SCAN_TIME 0x16403c +/* [WB 64] Linear1 phy address. */ +#define TM_REG_LIN1_PHY_ADDR 0x164280 +/* [RW 6] Linear timer set_clear fifo threshold. */ +#define TM_REG_LIN_SETCLR_FIFO_ALFULL_THR 0x164070 +/* [RW 2] Load value for pci arbiter credit cnt. */ +#define TM_REG_PCIARB_CRDCNT_VAL 0x164260 +/* [RW 1] Timer software reset - active high. */ +#define TM_REG_TIMER_SOFT_RST 0x164004 +/* [RW 20] The amount of hardware cycles for each timer tick. */ +#define TM_REG_TIMER_TICK_SIZE 0x16401c +/* [RW 8] Timers Context region. */ +#define TM_REG_TM_CONTEXT_REGION 0x164044 +/* [RW 1] Interrupt mask register #0 read/write */ +#define TM_REG_TM_INT_MASK 0x1640fc +/* [R 1] Interrupt register #0 read */ +#define TM_REG_TM_INT_STS 0x1640f0 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define TSDM_REG_AGG_INT_EVENT_0 0x42038 +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define TSDM_REG_CFC_RSP_START_ADDR 0x42008 +/* [RW 16] The maximum value of the competion counter #0 */ +#define TSDM_REG_CMP_COUNTER_MAX0 0x4201c +/* [RW 16] The maximum value of the competion counter #1 */ +#define TSDM_REG_CMP_COUNTER_MAX1 0x42020 +/* [RW 16] The maximum value of the competion counter #2 */ +#define TSDM_REG_CMP_COUNTER_MAX2 0x42024 +/* [RW 16] The maximum value of the competion counter #3 */ +#define TSDM_REG_CMP_COUNTER_MAX3 0x42028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define TSDM_REG_CMP_COUNTER_START_ADDR 0x4200c +#define TSDM_REG_ENABLE_IN1 0x42238 +#define TSDM_REG_ENABLE_IN2 0x4223c +#define TSDM_REG_ENABLE_OUT1 0x42240 +#define TSDM_REG_ENABLE_OUT2 0x42244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define TSDM_REG_INIT_CREDIT_PXP_CTRL 0x424bc +/* [ST 32] The number of ACK after placement messages received */ +#define TSDM_REG_NUM_OF_ACK_AFTER_PLACE 0x4227c +/* [ST 32] The number of packet end messages received from the parser */ +#define TSDM_REG_NUM_OF_PKT_END_MSG 0x42274 +/* [ST 32] The number of requests received from the pxp async if */ +#define TSDM_REG_NUM_OF_PXP_ASYNC_REQ 0x42278 +/* [ST 32] The number of commands received in queue 0 */ +#define TSDM_REG_NUM_OF_Q0_CMD 0x42248 +/* [ST 32] The number of commands received in queue 10 */ +#define TSDM_REG_NUM_OF_Q10_CMD 0x4226c +/* [ST 32] The number of commands received in queue 11 */ +#define TSDM_REG_NUM_OF_Q11_CMD 0x42270 +/* [ST 32] The number of commands received in queue 1 */ +#define TSDM_REG_NUM_OF_Q1_CMD 0x4224c +/* [ST 32] The number of commands received in queue 3 */ +#define TSDM_REG_NUM_OF_Q3_CMD 0x42250 +/* [ST 32] The number of commands received in queue 4 */ +#define TSDM_REG_NUM_OF_Q4_CMD 0x42254 +/* [ST 32] The number of commands received in queue 5 */ +#define TSDM_REG_NUM_OF_Q5_CMD 0x42258 +/* [ST 32] The number of commands received in queue 6 */ +#define TSDM_REG_NUM_OF_Q6_CMD 0x4225c +/* [ST 32] The number of commands received in queue 7 */ +#define TSDM_REG_NUM_OF_Q7_CMD 0x42260 +/* [ST 32] The number of commands received in queue 8 */ +#define TSDM_REG_NUM_OF_Q8_CMD 0x42264 +/* [ST 32] The number of commands received in queue 9 */ +#define TSDM_REG_NUM_OF_Q9_CMD 0x42268 +/* [RW 13] The start address in the internal RAM for the packet end message */ +#define TSDM_REG_PCK_END_MSG_START_ADDR 0x42014 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define TSDM_REG_Q_COUNTER_START_ADDR 0x42010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define TSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0x42548 +/* [R 1] parser fifo empty in sdm_sync block */ +#define TSDM_REG_SYNC_PARSER_EMPTY 0x42550 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define TSDM_REG_SYNC_SYNC_EMPTY 0x42558 +/* [RW 32] Tick for timer counter. Applicable only when + ~tsdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define TSDM_REG_TIMER_TICK 0x42000 +/* [RW 32] Interrupt mask register #0 read/write */ +#define TSDM_REG_TSDM_INT_MASK_0 0x4229c +#define TSDM_REG_TSDM_INT_MASK_1 0x422ac +/* [RW 11] Parity mask register #0 read/write */ +#define TSDM_REG_TSDM_PRTY_MASK 0x422bc +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define TSEM_REG_ARB_CYCLE_SIZE 0x180034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define TSEM_REG_ARB_ELEMENT0 0x180020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~tsem_registers_arb_element0.arb_element0 */ +#define TSEM_REG_ARB_ELEMENT1 0x180024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~tsem_registers_arb_element0.arb_element0 + and ~tsem_registers_arb_element1.arb_element1 */ +#define TSEM_REG_ARB_ELEMENT2 0x180028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~tsem_registers_arb_element0.arb_element0 and + ~tsem_registers_arb_element1.arb_element1 and + ~tsem_registers_arb_element2.arb_element2 */ +#define TSEM_REG_ARB_ELEMENT3 0x18002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~tsem_registers_arb_element0.arb_element0 + and ~tsem_registers_arb_element1.arb_element1 and + ~tsem_registers_arb_element2.arb_element2 and + ~tsem_registers_arb_element3.arb_element3 */ +#define TSEM_REG_ARB_ELEMENT4 0x180030 +#define TSEM_REG_ENABLE_IN 0x1800a4 +#define TSEM_REG_ENABLE_OUT 0x1800a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the SEM_FAST registers the base address + TSEM_REGISTERS_FAST_MEMORY (Offset: 0x1a0000) should be added to each + SEM_FAST register offset. */ +#define TSEM_REG_FAST_MEMORY 0x1a0000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define TSEM_REG_FIC0_DISABLE 0x180224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define TSEM_REG_FIC1_DISABLE 0x180234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define TSEM_REG_INT_TABLE 0x180400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define TSEM_REG_MSG_NUM_FIC0 0x180000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define TSEM_REG_MSG_NUM_FIC1 0x180004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define TSEM_REG_MSG_NUM_FOC0 0x180008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define TSEM_REG_MSG_NUM_FOC1 0x18000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define TSEM_REG_MSG_NUM_FOC2 0x180010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define TSEM_REG_MSG_NUM_FOC3 0x180014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define TSEM_REG_PAS_DISABLE 0x18024c +/* [WB 128] Debug only. Passive buffer memory */ +#define TSEM_REG_PASSIVE_BUFFER 0x181000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define TSEM_REG_PRAM 0x1c0000 +/* [R 8] Valid sleeping threads indication have bit per thread */ +#define TSEM_REG_SLEEP_THREADS_VALID 0x18026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define TSEM_REG_SLOW_EXT_STORE_EMPTY 0x1802a0 +/* [RW 8] List of free threads . There is a bit per thread. */ +#define TSEM_REG_THREADS_LIST 0x1802e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define TSEM_REG_TS_0_AS 0x180038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define TSEM_REG_TS_10_AS 0x180060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define TSEM_REG_TS_11_AS 0x180064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define TSEM_REG_TS_12_AS 0x180068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define TSEM_REG_TS_13_AS 0x18006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define TSEM_REG_TS_14_AS 0x180070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define TSEM_REG_TS_15_AS 0x180074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define TSEM_REG_TS_16_AS 0x180078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define TSEM_REG_TS_17_AS 0x18007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define TSEM_REG_TS_18_AS 0x180080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define TSEM_REG_TS_1_AS 0x18003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define TSEM_REG_TS_2_AS 0x180040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define TSEM_REG_TS_3_AS 0x180044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define TSEM_REG_TS_4_AS 0x180048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define TSEM_REG_TS_5_AS 0x18004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define TSEM_REG_TS_6_AS 0x180050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define TSEM_REG_TS_7_AS 0x180054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define TSEM_REG_TS_8_AS 0x180058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define TSEM_REG_TS_9_AS 0x18005c +/* [RW 32] Interrupt mask register #0 read/write */ +#define TSEM_REG_TSEM_INT_MASK_0 0x180100 +#define TSEM_REG_TSEM_INT_MASK_1 0x180110 +/* [RW 32] Parity mask register #0 read/write */ +#define TSEM_REG_TSEM_PRTY_MASK_0 0x180120 +#define TSEM_REG_TSEM_PRTY_MASK_1 0x180130 +/* [R 5] Used to read the XX protection CAM occupancy counter. */ +#define UCM_REG_CAM_OCCUP 0xe0170 +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define UCM_REG_CDU_AG_RD_IFEN 0xe0038 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define UCM_REG_CDU_AG_WR_IFEN 0xe0034 +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define UCM_REG_CDU_SM_RD_IFEN 0xe0040 +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define UCM_REG_CDU_SM_WR_IFEN 0xe003c +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define UCM_REG_CFC_INIT_CRD 0xe0204 +/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_CP_WEIGHT 0xe00c4 +/* [RW 1] Input csem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_CSEM_IFEN 0xe0028 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the csem interface is detected. */ +#define UCM_REG_CSEM_LENGTH_MIS 0xe0160 +/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_CSEM_WEIGHT 0xe00b8 +/* [RW 1] Input dorq Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_DORQ_IFEN 0xe0030 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the dorq interface is detected. */ +#define UCM_REG_DORQ_LENGTH_MIS 0xe0168 +/* [RW 8] The Event ID in case ErrorFlg input message bit is set. */ +#define UCM_REG_ERR_EVNT_ID 0xe00a4 +/* [RW 28] The CM erroneous header for QM and Timers formatting. */ +#define UCM_REG_ERR_UCM_HDR 0xe00a0 +/* [RW 8] The Event ID for Timers expiration. */ +#define UCM_REG_EXPR_EVNT_ID 0xe00a8 +/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define UCM_REG_FIC0_INIT_CRD 0xe020c +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define UCM_REG_FIC1_INIT_CRD 0xe0210 +/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~ucm_registers_gr_ag_pr.gr_ag_pr; + ~ucm_registers_gr_ld0_pr.gr_ld0_pr and + ~ucm_registers_gr_ld1_pr.gr_ld1_pr. */ +#define UCM_REG_GR_ARB_TYPE 0xe0144 +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel group is + compliment to the others. */ +#define UCM_REG_GR_LD0_PR 0xe014c +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel group is + compliment to the others. */ +#define UCM_REG_GR_LD1_PR 0xe0150 +/* [RW 2] The queue index for invalidate counter flag decision. */ +#define UCM_REG_INV_CFLG_Q 0xe00e4 +/* [RW 5] The number of double REG-pairs; loaded from the STORM context and + sent to STORM; for a specific connection type. the double REG-pairs are + used in order to align to STORM context row size of 128 bits. The offset + of these data in the STORM context is always 0. Index _i stands for the + connection type (one of 16). */ +#define UCM_REG_N_SM_CTX_LD_0 0xe0054 +#define UCM_REG_N_SM_CTX_LD_1 0xe0058 +#define UCM_REG_N_SM_CTX_LD_10 0xe007c +#define UCM_REG_N_SM_CTX_LD_11 0xe0080 +#define UCM_REG_N_SM_CTX_LD_12 0xe0084 +#define UCM_REG_N_SM_CTX_LD_13 0xe0088 +#define UCM_REG_N_SM_CTX_LD_14 0xe008c +#define UCM_REG_N_SM_CTX_LD_15 0xe0090 +#define UCM_REG_N_SM_CTX_LD_2 0xe005c +#define UCM_REG_N_SM_CTX_LD_3 0xe0060 +#define UCM_REG_N_SM_CTX_LD_4 0xe0064 +/* [RW 6] The physical queue number 0 per port index (CID[23]) */ +#define UCM_REG_PHYS_QNUM0_0 0xe0110 +#define UCM_REG_PHYS_QNUM0_1 0xe0114 +/* [RW 6] The physical queue number 1 per port index (CID[23]) */ +#define UCM_REG_PHYS_QNUM1_0 0xe0118 +#define UCM_REG_PHYS_QNUM1_1 0xe011c +/* [RW 8] The Event ID for Timers formatting in case of stop done. */ +#define UCM_REG_STOP_EVNT_ID 0xe00ac +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the STORM interface is detected. */ +#define UCM_REG_STORM_LENGTH_MIS 0xe0154 +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_STORM_UCM_IFEN 0xe0010 +/* [RW 4] Timers output initial credit. Max credit available - 15.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 4 at start-up. */ +#define UCM_REG_TM_INIT_CRD 0xe021c +/* [RW 28] The CM header for Timers expiration command. */ +#define UCM_REG_TM_UCM_HDR 0xe009c +/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_TM_UCM_IFEN 0xe001c +/* [RW 1] Input tsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_TSEM_IFEN 0xe0024 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the tsem interface is detected. */ +#define UCM_REG_TSEM_LENGTH_MIS 0xe015c +/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_TSEM_WEIGHT 0xe00b4 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_CFC_IFEN 0xe0044 +/* [RW 11] Interrupt mask register #0 read/write */ +#define UCM_REG_UCM_INT_MASK 0xe01d4 +/* [R 11] Interrupt register #0 read */ +#define UCM_REG_UCM_INT_STS 0xe01c8 +/* [RW 2] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the Reg1WbFlg isn't set. */ +#define UCM_REG_UCM_REG0_SZ 0xe00dc +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_STORM0_IFEN 0xe0004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_STORM1_IFEN 0xe0008 +/* [RW 1] CM - Timers Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_UCM_TM_IFEN 0xe0020 +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_UQM_IFEN 0xe000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */ +#define UCM_REG_UCM_UQM_USE_Q 0xe00d8 +/* [RW 6] QM output initial credit. Max credit available - 32.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define UCM_REG_UQM_INIT_CRD 0xe0220 +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_UQM_P_WEIGHT 0xe00cc +/* [RW 28] The CM header value for QM request (primary). */ +#define UCM_REG_UQM_UCM_HDR_P 0xe0094 +/* [RW 28] The CM header value for QM request (secondary). */ +#define UCM_REG_UQM_UCM_HDR_S 0xe0098 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UQM_UCM_IFEN 0xe0014 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_USDM_IFEN 0xe0018 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the SDM interface is detected. */ +#define UCM_REG_USDM_LENGTH_MIS 0xe0158 +/* [RW 1] Input xsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_XSEM_IFEN 0xe002c +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the xsem interface isdetected. */ +#define UCM_REG_XSEM_LENGTH_MIS 0xe0164 +/* [RW 20] Indirect access to the descriptor table of the XX protection + mechanism. The fields are:[5:0] - message length; 14:6] - message + pointer; 19:15] - next pointer. */ +#define UCM_REG_XX_DESCR_TABLE 0xe0280 +/* [R 6] Use to read the XX protection Free counter. */ +#define UCM_REG_XX_FREE 0xe016c +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Write writes the initial credit value; read returns the current + value of the credit counter. Must be initialized to 12 at start-up. */ +#define UCM_REG_XX_INIT_CRD 0xe0224 +/* [RW 6] The maximum number of pending messages; which may be stored in XX + protection. ~ucm_registers_xx_free.xx_free read on read. */ +#define UCM_REG_XX_MSG_NUM 0xe0228 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define UCM_REG_XX_OVFL_EVNT_ID 0xe004c +/* [RW 16] Indirect access to the XX table of the XX protection mechanism. + The fields are: [4:0] - tail pointer; 10:5] - Link List size; 15:11] - + header pointer. */ +#define UCM_REG_XX_TABLE 0xe0300 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define USDM_REG_AGG_INT_EVENT_0 0xc4038 +#define USDM_REG_AGG_INT_EVENT_1 0xc403c +#define USDM_REG_AGG_INT_EVENT_10 0xc4060 +#define USDM_REG_AGG_INT_EVENT_11 0xc4064 +#define USDM_REG_AGG_INT_EVENT_12 0xc4068 +#define USDM_REG_AGG_INT_EVENT_13 0xc406c +#define USDM_REG_AGG_INT_EVENT_14 0xc4070 +#define USDM_REG_AGG_INT_EVENT_15 0xc4074 +#define USDM_REG_AGG_INT_EVENT_16 0xc4078 +#define USDM_REG_AGG_INT_EVENT_17 0xc407c +#define USDM_REG_AGG_INT_EVENT_18 0xc4080 +#define USDM_REG_AGG_INT_EVENT_19 0xc4084 +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define USDM_REG_AGG_INT_MODE_0 0xc41b8 +#define USDM_REG_AGG_INT_MODE_1 0xc41bc +#define USDM_REG_AGG_INT_MODE_10 0xc41e0 +#define USDM_REG_AGG_INT_MODE_11 0xc41e4 +#define USDM_REG_AGG_INT_MODE_12 0xc41e8 +#define USDM_REG_AGG_INT_MODE_13 0xc41ec +#define USDM_REG_AGG_INT_MODE_14 0xc41f0 +#define USDM_REG_AGG_INT_MODE_15 0xc41f4 +#define USDM_REG_AGG_INT_MODE_16 0xc41f8 +#define USDM_REG_AGG_INT_MODE_17 0xc41fc +#define USDM_REG_AGG_INT_MODE_18 0xc4200 +#define USDM_REG_AGG_INT_MODE_19 0xc4204 +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define USDM_REG_CFC_RSP_START_ADDR 0xc4008 +/* [RW 16] The maximum value of the competion counter #0 */ +#define USDM_REG_CMP_COUNTER_MAX0 0xc401c +/* [RW 16] The maximum value of the competion counter #1 */ +#define USDM_REG_CMP_COUNTER_MAX1 0xc4020 +/* [RW 16] The maximum value of the competion counter #2 */ +#define USDM_REG_CMP_COUNTER_MAX2 0xc4024 +/* [RW 16] The maximum value of the competion counter #3 */ +#define USDM_REG_CMP_COUNTER_MAX3 0xc4028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define USDM_REG_CMP_COUNTER_START_ADDR 0xc400c +#define USDM_REG_ENABLE_IN1 0xc4238 +#define USDM_REG_ENABLE_IN2 0xc423c +#define USDM_REG_ENABLE_OUT1 0xc4240 +#define USDM_REG_ENABLE_OUT2 0xc4244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define USDM_REG_INIT_CREDIT_PXP_CTRL 0xc44c0 +/* [ST 32] The number of ACK after placement messages received */ +#define USDM_REG_NUM_OF_ACK_AFTER_PLACE 0xc4280 +/* [ST 32] The number of packet end messages received from the parser */ +#define USDM_REG_NUM_OF_PKT_END_MSG 0xc4278 +/* [ST 32] The number of requests received from the pxp async if */ +#define USDM_REG_NUM_OF_PXP_ASYNC_REQ 0xc427c +/* [ST 32] The number of commands received in queue 0 */ +#define USDM_REG_NUM_OF_Q0_CMD 0xc4248 +/* [ST 32] The number of commands received in queue 10 */ +#define USDM_REG_NUM_OF_Q10_CMD 0xc4270 +/* [ST 32] The number of commands received in queue 11 */ +#define USDM_REG_NUM_OF_Q11_CMD 0xc4274 +/* [ST 32] The number of commands received in queue 1 */ +#define USDM_REG_NUM_OF_Q1_CMD 0xc424c +/* [ST 32] The number of commands received in queue 2 */ +#define USDM_REG_NUM_OF_Q2_CMD 0xc4250 +/* [ST 32] The number of commands received in queue 3 */ +#define USDM_REG_NUM_OF_Q3_CMD 0xc4254 +/* [ST 32] The number of commands received in queue 4 */ +#define USDM_REG_NUM_OF_Q4_CMD 0xc4258 +/* [ST 32] The number of commands received in queue 5 */ +#define USDM_REG_NUM_OF_Q5_CMD 0xc425c +/* [ST 32] The number of commands received in queue 6 */ +#define USDM_REG_NUM_OF_Q6_CMD 0xc4260 +/* [ST 32] The number of commands received in queue 7 */ +#define USDM_REG_NUM_OF_Q7_CMD 0xc4264 +/* [ST 32] The number of commands received in queue 8 */ +#define USDM_REG_NUM_OF_Q8_CMD 0xc4268 +/* [ST 32] The number of commands received in queue 9 */ +#define USDM_REG_NUM_OF_Q9_CMD 0xc426c +/* [RW 13] The start address in the internal RAM for the packet end message */ +#define USDM_REG_PCK_END_MSG_START_ADDR 0xc4014 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define USDM_REG_Q_COUNTER_START_ADDR 0xc4010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define USDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0xc4550 +/* [R 1] parser fifo empty in sdm_sync block */ +#define USDM_REG_SYNC_PARSER_EMPTY 0xc4558 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define USDM_REG_SYNC_SYNC_EMPTY 0xc4560 +/* [RW 32] Tick for timer counter. Applicable only when + ~usdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define USDM_REG_TIMER_TICK 0xc4000 +/* [RW 32] Interrupt mask register #0 read/write */ +#define USDM_REG_USDM_INT_MASK_0 0xc42a0 +#define USDM_REG_USDM_INT_MASK_1 0xc42b0 +/* [RW 11] Parity mask register #0 read/write */ +#define USDM_REG_USDM_PRTY_MASK 0xc42c0 +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define USEM_REG_ARB_CYCLE_SIZE 0x300034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define USEM_REG_ARB_ELEMENT0 0x300020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~usem_registers_arb_element0.arb_element0 */ +#define USEM_REG_ARB_ELEMENT1 0x300024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~usem_registers_arb_element0.arb_element0 + and ~usem_registers_arb_element1.arb_element1 */ +#define USEM_REG_ARB_ELEMENT2 0x300028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~usem_registers_arb_element0.arb_element0 and + ~usem_registers_arb_element1.arb_element1 and + ~usem_registers_arb_element2.arb_element2 */ +#define USEM_REG_ARB_ELEMENT3 0x30002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~usem_registers_arb_element0.arb_element0 + and ~usem_registers_arb_element1.arb_element1 and + ~usem_registers_arb_element2.arb_element2 and + ~usem_registers_arb_element3.arb_element3 */ +#define USEM_REG_ARB_ELEMENT4 0x300030 +#define USEM_REG_ENABLE_IN 0x3000a4 +#define USEM_REG_ENABLE_OUT 0x3000a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the SEM_FAST registers... the base address + USEM_REGISTERS_FAST_MEMORY (Offset: 0x320000) should be added to each + SEM_FAST register offset. */ +#define USEM_REG_FAST_MEMORY 0x320000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define USEM_REG_FIC0_DISABLE 0x300224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define USEM_REG_FIC1_DISABLE 0x300234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define USEM_REG_INT_TABLE 0x300400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define USEM_REG_MSG_NUM_FIC0 0x300000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define USEM_REG_MSG_NUM_FIC1 0x300004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define USEM_REG_MSG_NUM_FOC0 0x300008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define USEM_REG_MSG_NUM_FOC1 0x30000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define USEM_REG_MSG_NUM_FOC2 0x300010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define USEM_REG_MSG_NUM_FOC3 0x300014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define USEM_REG_PAS_DISABLE 0x30024c +/* [WB 128] Debug only. Passive buffer memory */ +#define USEM_REG_PASSIVE_BUFFER 0x302000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define USEM_REG_PRAM 0x340000 +/* [R 16] Valid sleeping threads indication have bit per thread */ +#define USEM_REG_SLEEP_THREADS_VALID 0x30026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define USEM_REG_SLOW_EXT_STORE_EMPTY 0x3002a0 +/* [RW 16] List of free threads . There is a bit per thread. */ +#define USEM_REG_THREADS_LIST 0x3002e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define USEM_REG_TS_0_AS 0x300038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define USEM_REG_TS_10_AS 0x300060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define USEM_REG_TS_11_AS 0x300064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define USEM_REG_TS_12_AS 0x300068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define USEM_REG_TS_13_AS 0x30006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define USEM_REG_TS_14_AS 0x300070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define USEM_REG_TS_15_AS 0x300074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define USEM_REG_TS_16_AS 0x300078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define USEM_REG_TS_17_AS 0x30007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define USEM_REG_TS_18_AS 0x300080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define USEM_REG_TS_1_AS 0x30003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define USEM_REG_TS_2_AS 0x300040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define USEM_REG_TS_3_AS 0x300044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define USEM_REG_TS_4_AS 0x300048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define USEM_REG_TS_5_AS 0x30004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define USEM_REG_TS_6_AS 0x300050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define USEM_REG_TS_7_AS 0x300054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define USEM_REG_TS_8_AS 0x300058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define USEM_REG_TS_9_AS 0x30005c +/* [RW 32] Interrupt mask register #0 read/write */ +#define USEM_REG_USEM_INT_MASK_0 0x300110 +#define USEM_REG_USEM_INT_MASK_1 0x300120 +/* [RW 32] Parity mask register #0 read/write */ +#define USEM_REG_USEM_PRTY_MASK_0 0x300130 +#define USEM_REG_USEM_PRTY_MASK_1 0x300140 +/* [RW 2] The queue index for registration on Aux1 counter flag. */ +#define XCM_REG_AUX1_Q 0x20134 +/* [RW 2] Per each decision rule the queue index to register to. */ +#define XCM_REG_AUX_CNT_FLG_Q_19 0x201b0 +/* [R 5] Used to read the XX protection CAM occupancy counter. */ +#define XCM_REG_CAM_OCCUP 0x20244 +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define XCM_REG_CDU_AG_RD_IFEN 0x20044 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define XCM_REG_CDU_AG_WR_IFEN 0x20040 +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define XCM_REG_CDU_SM_RD_IFEN 0x2004c +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define XCM_REG_CDU_SM_WR_IFEN 0x20048 +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define XCM_REG_CFC_INIT_CRD 0x20404 +/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_CP_WEIGHT 0x200dc +/* [RW 1] Input csem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_CSEM_IFEN 0x20028 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the csem interface. */ +#define XCM_REG_CSEM_LENGTH_MIS 0x20228 +/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_CSEM_WEIGHT 0x200c4 +/* [RW 1] Input dorq Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_DORQ_IFEN 0x20030 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the dorq interface. */ +#define XCM_REG_DORQ_LENGTH_MIS 0x20230 +/* [RW 8] The Event ID in case the ErrorFlg input message bit is set. */ +#define XCM_REG_ERR_EVNT_ID 0x200b0 +/* [RW 28] The CM erroneous header for QM and Timers formatting. */ +#define XCM_REG_ERR_XCM_HDR 0x200ac +/* [RW 8] The Event ID for Timers expiration. */ +#define XCM_REG_EXPR_EVNT_ID 0x200b4 +/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define XCM_REG_FIC0_INIT_CRD 0x2040c +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define XCM_REG_FIC1_INIT_CRD 0x20410 +/* [RW 8] The maximum delayed ACK counter value.Must be at least 2. Per port + value. */ +#define XCM_REG_GLB_DEL_ACK_MAX_CNT_0 0x20118 +#define XCM_REG_GLB_DEL_ACK_MAX_CNT_1 0x2011c +/* [RW 28] The delayed ACK timeout in ticks. Per port value. */ +#define XCM_REG_GLB_DEL_ACK_TMR_VAL_0 0x20108 +#define XCM_REG_GLB_DEL_ACK_TMR_VAL_1 0x2010c +/* [RW 1] Arbitratiojn between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~xcm_registers_gr_ag_pr.gr_ag_pr; + ~xcm_registers_gr_ld0_pr.gr_ld0_pr and + ~xcm_registers_gr_ld1_pr.gr_ld1_pr. */ +#define XCM_REG_GR_ARB_TYPE 0x2020c +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Channel group is the + compliment of the other 3 groups. */ +#define XCM_REG_GR_LD0_PR 0x20214 +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Channel group is the + compliment of the other 3 groups. */ +#define XCM_REG_GR_LD1_PR 0x20218 +/* [RW 1] Input nig0 Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_NIG0_IFEN 0x20038 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the nig0 interface. */ +#define XCM_REG_NIG0_LENGTH_MIS 0x20238 +/* [RW 1] Input nig1 Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_NIG1_IFEN 0x2003c +/* [RC 1] Set at message length mismatch (relative to last indication) at + the nig1 interface. */ +#define XCM_REG_NIG1_LENGTH_MIS 0x2023c +/* [RW 3] The weight of the input nig1 in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_NIG1_WEIGHT 0x200d8 +/* [RW 5] The number of double REG-pairs; loaded from the STORM context and + sent to STORM; for a specific connection type. The double REG-pairs are + used in order to align to STORM context row size of 128 bits. The offset + of these data in the STORM context is always 0. Index _i stands for the + connection type (one of 16). */ +#define XCM_REG_N_SM_CTX_LD_0 0x20060 +#define XCM_REG_N_SM_CTX_LD_1 0x20064 +#define XCM_REG_N_SM_CTX_LD_10 0x20088 +#define XCM_REG_N_SM_CTX_LD_11 0x2008c +#define XCM_REG_N_SM_CTX_LD_12 0x20090 +#define XCM_REG_N_SM_CTX_LD_13 0x20094 +#define XCM_REG_N_SM_CTX_LD_14 0x20098 +#define XCM_REG_N_SM_CTX_LD_15 0x2009c +#define XCM_REG_N_SM_CTX_LD_2 0x20068 +#define XCM_REG_N_SM_CTX_LD_3 0x2006c +#define XCM_REG_N_SM_CTX_LD_4 0x20070 +/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_PBF_IFEN 0x20034 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the pbf interface. */ +#define XCM_REG_PBF_LENGTH_MIS 0x20234 +/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_PBF_WEIGHT 0x200d0 +/* [RW 8] The Event ID for Timers formatting in case of stop done. */ +#define XCM_REG_STOP_EVNT_ID 0x200b8 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the STORM interface. */ +#define XCM_REG_STORM_LENGTH_MIS 0x2021c +/* [RW 3] The weight of the STORM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_STORM_WEIGHT 0x200bc +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_STORM_XCM_IFEN 0x20010 +/* [RW 4] Timers output initial credit. Max credit available - 15.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 4 at start-up. */ +#define XCM_REG_TM_INIT_CRD 0x2041c +/* [RW 28] The CM header for Timers expiration command. */ +#define XCM_REG_TM_XCM_HDR 0x200a8 +/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_TM_XCM_IFEN 0x2001c +/* [RW 1] Input tsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_TSEM_IFEN 0x20024 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the tsem interface. */ +#define XCM_REG_TSEM_LENGTH_MIS 0x20224 +/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_TSEM_WEIGHT 0x200c0 +/* [RW 2] The queue index for registration on UNA greater NXT decision rule. */ +#define XCM_REG_UNA_GT_NXT_Q 0x20120 +/* [RW 1] Input usem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_USEM_IFEN 0x2002c +/* [RC 1] Message length mismatch (relative to last indication) at the usem + interface. */ +#define XCM_REG_USEM_LENGTH_MIS 0x2022c +/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_USEM_WEIGHT 0x200c8 +/* [RW 2] DA counter command; used in case of window update doorbell.The + first index stands for the value DaEnable of that connection. The second + index stands for port number. */ +#define XCM_REG_WU_DA_CNT_CMD00 0x201d4 +/* [RW 2] DA counter command; used in case of window update doorbell.The + first index stands for the value DaEnable of that connection. The second + index stands for port number. */ +#define XCM_REG_WU_DA_CNT_CMD01 0x201d8 +/* [RW 2] DA counter command; used in case of window update doorbell.The + first index stands for the value DaEnable of that connection. The second + index stands for port number. */ +#define XCM_REG_WU_DA_CNT_CMD10 0x201dc +/* [RW 2] DA counter command; used in case of window update doorbell.The + first index stands for the value DaEnable of that connection. The second + index stands for port number. */ +#define XCM_REG_WU_DA_CNT_CMD11 0x201e0 +/* [RW 8] DA counter update value used in case of window update doorbell.The + first index stands for the value DaEnable of that connection. The second + index stands for port number. */ +#define XCM_REG_WU_DA_CNT_UPD_VAL00 0x201e4 +/* [RW 8] DA counter update value; used in case of window update + doorbell.The first index stands for the value DaEnable of that + connection. The second index stands for port number. */ +#define XCM_REG_WU_DA_CNT_UPD_VAL01 0x201e8 +/* [RW 8] DA counter update value; used in case of window update + doorbell.The first index stands for the value DaEnable of that + connection. The second index stands for port number. */ +#define XCM_REG_WU_DA_CNT_UPD_VAL10 0x201ec +/* [RW 8] DA counter update value; used in case of window update + doorbell.The first index stands for the value DaEnable of that + connection. The second index stands for port number. */ +#define XCM_REG_WU_DA_CNT_UPD_VAL11 0x201f0 +/* [RW 1] DA timer command; used in case of window update doorbell.The first + index stands for the value DaEnable of that connection. The second index + stands for port number. */ +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00 0x201c4 +/* [RW 1] DA timer command; used in case of window update doorbell.The first + index stands for the value DaEnable of that connection. The second index + stands for port number. */ +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01 0x201c8 +/* [RW 1] DA timer command; used in case of window update doorbell.The first + index stands for the value DaEnable of that connection. The second index + stands for port number. */ +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10 0x201cc +/* [RW 1] DA timer command; used in case of window update doorbell.The first + index stands for the value DaEnable of that connection. The second index + stands for port number. */ +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11 0x201d0 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_CFC_IFEN 0x20050 +/* [RW 14] Interrupt mask register #0 read/write */ +#define XCM_REG_XCM_INT_MASK 0x202b4 +/* [R 14] Interrupt register #0 read */ +#define XCM_REG_XCM_INT_STS 0x202a8 +/* [RW 4] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the Reg1WbFlg isn't set. */ +#define XCM_REG_XCM_REG0_SZ 0x200f4 +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_STORM0_IFEN 0x20004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_STORM1_IFEN 0x20008 +/* [RW 1] CM - Timers Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_XCM_TM_IFEN 0x20020 +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_XQM_IFEN 0x2000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */ +#define XCM_REG_XCM_XQM_USE_Q 0x200f0 +/* [RW 4] The value by which CFC updates the activity counter at QM bypass. */ +#define XCM_REG_XQM_BYP_ACT_UPD 0x200fc +/* [RW 6] QM output initial credit. Max credit available - 32.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define XCM_REG_XQM_INIT_CRD 0x20420 +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_XQM_P_WEIGHT 0x200e4 +/* [RW 28] The CM header value for QM request (primary). */ +#define XCM_REG_XQM_XCM_HDR_P 0x200a0 +/* [RW 28] The CM header value for QM request (secondary). */ +#define XCM_REG_XQM_XCM_HDR_S 0x200a4 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XQM_XCM_IFEN 0x20014 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XSDM_IFEN 0x20018 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the SDM interface. */ +#define XCM_REG_XSDM_LENGTH_MIS 0x20220 +/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_XSDM_WEIGHT 0x200e0 +/* [RW 17] Indirect access to the descriptor table of the XX protection + mechanism. The fields are: [5:0] - message length; 11:6] - message + pointer; 16:12] - next pointer. */ +#define XCM_REG_XX_DESCR_TABLE 0x20480 +/* [R 6] Used to read the XX protection Free counter. */ +#define XCM_REG_XX_FREE 0x20240 +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Max credit available - 3.Write writes the initial credit value; + read returns the current value of the credit counter. Must be initialized + to 2 at start-up. */ +#define XCM_REG_XX_INIT_CRD 0x20424 +/* [RW 6] The maximum number of pending messages; which may be stored in XX + protection. ~xcm_registers_xx_free.xx_free read on read. */ +#define XCM_REG_XX_MSG_NUM 0x20428 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define XCM_REG_XX_OVFL_EVNT_ID 0x20058 +/* [RW 15] Indirect access to the XX table of the XX protection mechanism. + The fields are:[4:0] - tail pointer; 9:5] - Link List size; 14:10] - + header pointer. */ +#define XCM_REG_XX_TABLE 0x20500 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define XSDM_REG_AGG_INT_EVENT_0 0x166038 +#define XSDM_REG_AGG_INT_EVENT_1 0x16603c +#define XSDM_REG_AGG_INT_EVENT_10 0x166060 +#define XSDM_REG_AGG_INT_EVENT_11 0x166064 +#define XSDM_REG_AGG_INT_EVENT_12 0x166068 +#define XSDM_REG_AGG_INT_EVENT_13 0x16606c +#define XSDM_REG_AGG_INT_EVENT_14 0x166070 +#define XSDM_REG_AGG_INT_EVENT_15 0x166074 +#define XSDM_REG_AGG_INT_EVENT_16 0x166078 +#define XSDM_REG_AGG_INT_EVENT_17 0x16607c +#define XSDM_REG_AGG_INT_EVENT_18 0x166080 +#define XSDM_REG_AGG_INT_EVENT_19 0x166084 +#define XSDM_REG_AGG_INT_EVENT_2 0x166040 +#define XSDM_REG_AGG_INT_EVENT_20 0x166088 +#define XSDM_REG_AGG_INT_EVENT_21 0x16608c +#define XSDM_REG_AGG_INT_EVENT_22 0x166090 +#define XSDM_REG_AGG_INT_EVENT_23 0x166094 +#define XSDM_REG_AGG_INT_EVENT_24 0x166098 +#define XSDM_REG_AGG_INT_EVENT_25 0x16609c +#define XSDM_REG_AGG_INT_EVENT_26 0x1660a0 +#define XSDM_REG_AGG_INT_EVENT_27 0x1660a4 +#define XSDM_REG_AGG_INT_EVENT_28 0x1660a8 +#define XSDM_REG_AGG_INT_EVENT_29 0x1660ac +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define XSDM_REG_AGG_INT_MODE_0 0x1661b8 +#define XSDM_REG_AGG_INT_MODE_1 0x1661bc +#define XSDM_REG_AGG_INT_MODE_10 0x1661e0 +#define XSDM_REG_AGG_INT_MODE_11 0x1661e4 +#define XSDM_REG_AGG_INT_MODE_12 0x1661e8 +#define XSDM_REG_AGG_INT_MODE_13 0x1661ec +#define XSDM_REG_AGG_INT_MODE_14 0x1661f0 +#define XSDM_REG_AGG_INT_MODE_15 0x1661f4 +#define XSDM_REG_AGG_INT_MODE_16 0x1661f8 +#define XSDM_REG_AGG_INT_MODE_17 0x1661fc +#define XSDM_REG_AGG_INT_MODE_18 0x166200 +#define XSDM_REG_AGG_INT_MODE_19 0x166204 +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define XSDM_REG_CFC_RSP_START_ADDR 0x166008 +/* [RW 16] The maximum value of the competion counter #0 */ +#define XSDM_REG_CMP_COUNTER_MAX0 0x16601c +/* [RW 16] The maximum value of the competion counter #1 */ +#define XSDM_REG_CMP_COUNTER_MAX1 0x166020 +/* [RW 16] The maximum value of the competion counter #2 */ +#define XSDM_REG_CMP_COUNTER_MAX2 0x166024 +/* [RW 16] The maximum value of the competion counter #3 */ +#define XSDM_REG_CMP_COUNTER_MAX3 0x166028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define XSDM_REG_CMP_COUNTER_START_ADDR 0x16600c +#define XSDM_REG_ENABLE_IN1 0x166238 +#define XSDM_REG_ENABLE_IN2 0x16623c +#define XSDM_REG_ENABLE_OUT1 0x166240 +#define XSDM_REG_ENABLE_OUT2 0x166244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define XSDM_REG_INIT_CREDIT_PXP_CTRL 0x1664bc +/* [ST 32] The number of ACK after placement messages received */ +#define XSDM_REG_NUM_OF_ACK_AFTER_PLACE 0x16627c +/* [ST 32] The number of packet end messages received from the parser */ +#define XSDM_REG_NUM_OF_PKT_END_MSG 0x166274 +/* [ST 32] The number of requests received from the pxp async if */ +#define XSDM_REG_NUM_OF_PXP_ASYNC_REQ 0x166278 +/* [ST 32] The number of commands received in queue 0 */ +#define XSDM_REG_NUM_OF_Q0_CMD 0x166248 +/* [ST 32] The number of commands received in queue 10 */ +#define XSDM_REG_NUM_OF_Q10_CMD 0x16626c +/* [ST 32] The number of commands received in queue 11 */ +#define XSDM_REG_NUM_OF_Q11_CMD 0x166270 +/* [ST 32] The number of commands received in queue 1 */ +#define XSDM_REG_NUM_OF_Q1_CMD 0x16624c +/* [ST 32] The number of commands received in queue 3 */ +#define XSDM_REG_NUM_OF_Q3_CMD 0x166250 +/* [ST 32] The number of commands received in queue 4 */ +#define XSDM_REG_NUM_OF_Q4_CMD 0x166254 +/* [ST 32] The number of commands received in queue 5 */ +#define XSDM_REG_NUM_OF_Q5_CMD 0x166258 +/* [ST 32] The number of commands received in queue 6 */ +#define XSDM_REG_NUM_OF_Q6_CMD 0x16625c +/* [ST 32] The number of commands received in queue 7 */ +#define XSDM_REG_NUM_OF_Q7_CMD 0x166260 +/* [ST 32] The number of commands received in queue 8 */ +#define XSDM_REG_NUM_OF_Q8_CMD 0x166264 +/* [ST 32] The number of commands received in queue 9 */ +#define XSDM_REG_NUM_OF_Q9_CMD 0x166268 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define XSDM_REG_Q_COUNTER_START_ADDR 0x166010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define XSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0x166548 +/* [R 1] parser fifo empty in sdm_sync block */ +#define XSDM_REG_SYNC_PARSER_EMPTY 0x166550 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define XSDM_REG_SYNC_SYNC_EMPTY 0x166558 +/* [RW 32] Tick for timer counter. Applicable only when + ~xsdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define XSDM_REG_TIMER_TICK 0x166000 +/* [RW 32] Interrupt mask register #0 read/write */ +#define XSDM_REG_XSDM_INT_MASK_0 0x16629c +#define XSDM_REG_XSDM_INT_MASK_1 0x1662ac +/* [RW 11] Parity mask register #0 read/write */ +#define XSDM_REG_XSDM_PRTY_MASK 0x1662bc +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define XSEM_REG_ARB_CYCLE_SIZE 0x280034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define XSEM_REG_ARB_ELEMENT0 0x280020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~xsem_registers_arb_element0.arb_element0 */ +#define XSEM_REG_ARB_ELEMENT1 0x280024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~xsem_registers_arb_element0.arb_element0 + and ~xsem_registers_arb_element1.arb_element1 */ +#define XSEM_REG_ARB_ELEMENT2 0x280028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~xsem_registers_arb_element0.arb_element0 and + ~xsem_registers_arb_element1.arb_element1 and + ~xsem_registers_arb_element2.arb_element2 */ +#define XSEM_REG_ARB_ELEMENT3 0x28002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~xsem_registers_arb_element0.arb_element0 + and ~xsem_registers_arb_element1.arb_element1 and + ~xsem_registers_arb_element2.arb_element2 and + ~xsem_registers_arb_element3.arb_element3 */ +#define XSEM_REG_ARB_ELEMENT4 0x280030 +#define XSEM_REG_ENABLE_IN 0x2800a4 +#define XSEM_REG_ENABLE_OUT 0x2800a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the SEM_FAST registers the base address + XSEM_REGISTERS_FAST_MEMORY (Offset: 0x2a0000) should be added to each + SEM_FAST register offset. */ +#define XSEM_REG_FAST_MEMORY 0x2a0000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define XSEM_REG_FIC0_DISABLE 0x280224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define XSEM_REG_FIC1_DISABLE 0x280234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define XSEM_REG_INT_TABLE 0x280400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define XSEM_REG_MSG_NUM_FIC0 0x280000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define XSEM_REG_MSG_NUM_FIC1 0x280004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define XSEM_REG_MSG_NUM_FOC0 0x280008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define XSEM_REG_MSG_NUM_FOC1 0x28000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define XSEM_REG_MSG_NUM_FOC2 0x280010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define XSEM_REG_MSG_NUM_FOC3 0x280014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define XSEM_REG_PAS_DISABLE 0x28024c +/* [WB 128] Debug only. Passive buffer memory */ +#define XSEM_REG_PASSIVE_BUFFER 0x282000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define XSEM_REG_PRAM 0x2c0000 +/* [R 16] Valid sleeping threads indication have bit per thread */ +#define XSEM_REG_SLEEP_THREADS_VALID 0x28026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define XSEM_REG_SLOW_EXT_STORE_EMPTY 0x2802a0 +/* [RW 16] List of free threads . There is a bit per thread. */ +#define XSEM_REG_THREADS_LIST 0x2802e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define XSEM_REG_TS_0_AS 0x280038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define XSEM_REG_TS_10_AS 0x280060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define XSEM_REG_TS_11_AS 0x280064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define XSEM_REG_TS_12_AS 0x280068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define XSEM_REG_TS_13_AS 0x28006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define XSEM_REG_TS_14_AS 0x280070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define XSEM_REG_TS_15_AS 0x280074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define XSEM_REG_TS_16_AS 0x280078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define XSEM_REG_TS_17_AS 0x28007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define XSEM_REG_TS_18_AS 0x280080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define XSEM_REG_TS_1_AS 0x28003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define XSEM_REG_TS_2_AS 0x280040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define XSEM_REG_TS_3_AS 0x280044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define XSEM_REG_TS_4_AS 0x280048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define XSEM_REG_TS_5_AS 0x28004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define XSEM_REG_TS_6_AS 0x280050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define XSEM_REG_TS_7_AS 0x280054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define XSEM_REG_TS_8_AS 0x280058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define XSEM_REG_TS_9_AS 0x28005c +/* [RW 32] Interrupt mask register #0 read/write */ +#define XSEM_REG_XSEM_INT_MASK_0 0x280110 +#define XSEM_REG_XSEM_INT_MASK_1 0x280120 +/* [RW 32] Parity mask register #0 read/write */ +#define XSEM_REG_XSEM_PRTY_MASK_0 0x280130 +#define XSEM_REG_XSEM_PRTY_MASK_1 0x280140 +#define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0) +#define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1) +#define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0) +#define MCPR_NVM_CFG4_FLASH_SIZE (0x7L<<0) +#define MCPR_NVM_COMMAND_DOIT (1L<<4) +#define MCPR_NVM_COMMAND_DONE (1L<<3) +#define MCPR_NVM_COMMAND_FIRST (1L<<7) +#define MCPR_NVM_COMMAND_LAST (1L<<8) +#define MCPR_NVM_COMMAND_WR (1L<<5) +#define MCPR_NVM_COMMAND_WREN (1L<<16) +#define MCPR_NVM_COMMAND_WREN_BITSHIFT 16 +#define MCPR_NVM_COMMAND_WRDI (1L<<17) +#define MCPR_NVM_COMMAND_WRDI_BITSHIFT 17 +#define MCPR_NVM_SW_ARB_ARB_ARB1 (1L<<9) +#define MCPR_NVM_SW_ARB_ARB_REQ_CLR1 (1L<<5) +#define MCPR_NVM_SW_ARB_ARB_REQ_SET1 (1L<<1) +#define BIGMAC_REGISTER_BMAC_CONTROL (0x00<<3) +#define BIGMAC_REGISTER_BMAC_XGXS_CONTROL (0x01<<3) +#define BIGMAC_REGISTER_CNT_MAX_SIZE (0x05<<3) +#define BIGMAC_REGISTER_RX_CONTROL (0x21<<3) +#define BIGMAC_REGISTER_RX_LLFC_MSG_FLDS (0x46<<3) +#define BIGMAC_REGISTER_RX_MAX_SIZE (0x23<<3) +#define BIGMAC_REGISTER_RX_STAT_GR64 (0x26<<3) +#define BIGMAC_REGISTER_RX_STAT_GRIPJ (0x42<<3) +#define BIGMAC_REGISTER_TX_CONTROL (0x07<<3) +#define BIGMAC_REGISTER_TX_MAX_SIZE (0x09<<3) +#define BIGMAC_REGISTER_TX_PAUSE_THRESHOLD (0x0A<<3) +#define BIGMAC_REGISTER_TX_SOURCE_ADDR (0x08<<3) +#define BIGMAC_REGISTER_TX_STAT_GTBYT (0x20<<3) +#define BIGMAC_REGISTER_TX_STAT_GTPKT (0x0C<<3) +#define EMAC_MDIO_COMM_COMMAND_ADDRESS (0L<<26) +#define EMAC_MDIO_COMM_COMMAND_READ_22 (2L<<26) +#define EMAC_MDIO_COMM_COMMAND_READ_45 (3L<<26) +#define EMAC_MDIO_COMM_COMMAND_WRITE_22 (1L<<26) +#define EMAC_MDIO_COMM_COMMAND_WRITE_45 (1L<<26) +#define EMAC_MDIO_COMM_DATA (0xffffL<<0) +#define EMAC_MDIO_COMM_START_BUSY (1L<<29) +#define EMAC_MDIO_MODE_AUTO_POLL (1L<<4) +#define EMAC_MDIO_MODE_CLAUSE_45 (1L<<31) +#define EMAC_MODE_25G_MODE (1L<<5) +#define EMAC_MODE_ACPI_RCVD (1L<<20) +#define EMAC_MODE_HALF_DUPLEX (1L<<1) +#define EMAC_MODE_MPKT (1L<<18) +#define EMAC_MODE_MPKT_RCVD (1L<<19) +#define EMAC_MODE_PORT_GMII (2L<<2) +#define EMAC_MODE_PORT_MII (1L<<2) +#define EMAC_MODE_PORT_MII_10M (3L<<2) +#define EMAC_MODE_RESET (1L<<0) +#define EMAC_REG_EMAC_MAC_MATCH 0x10 +#define EMAC_REG_EMAC_MDIO_COMM 0xac +#define EMAC_REG_EMAC_MDIO_MODE 0xb4 +#define EMAC_REG_EMAC_MODE 0x0 +#define EMAC_REG_EMAC_RX_MODE 0xc8 +#define EMAC_REG_EMAC_RX_MTU_SIZE 0x9c +#define EMAC_REG_EMAC_RX_STAT_AC 0x180 +#define EMAC_REG_EMAC_RX_STAT_AC_28 0x1f4 +#define EMAC_REG_EMAC_RX_STAT_AC_COUNT 23 +#define EMAC_REG_EMAC_TX_MODE 0xbc +#define EMAC_REG_EMAC_TX_STAT_AC 0x280 +#define EMAC_REG_EMAC_TX_STAT_AC_COUNT 22 +#define EMAC_RX_MODE_FLOW_EN (1L<<2) +#define EMAC_RX_MODE_KEEP_VLAN_TAG (1L<<10) +#define EMAC_RX_MODE_PROMISCUOUS (1L<<8) +#define EMAC_RX_MTU_SIZE_JUMBO_ENA (1L<<31) +#define EMAC_TX_MODE_EXT_PAUSE_EN (1L<<3) +#define EMAC_TX_MODE_RESET (1L<<0) +#define MISC_REGISTERS_RESET_REG_1_CLEAR 0x588 +#define MISC_REGISTERS_RESET_REG_1_SET 0x584 +#define MISC_REGISTERS_RESET_REG_2_CLEAR 0x598 +#define MISC_REGISTERS_RESET_REG_2_RST_BMAC0 (0x1<<0) +#define MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE (0x1<<14) +#define MISC_REGISTERS_RESET_REG_2_SET 0x594 +#define MISC_REGISTERS_RESET_REG_3_CLEAR 0x5a8 +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ (0x1<<1) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN (0x1<<2) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD (0x1<<3) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW (0x1<<0) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ (0x1<<5) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN (0x1<<6) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD (0x1<<7) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW (0x1<<4) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB (0x1<<8) +#define MISC_REGISTERS_RESET_REG_3_SET 0x5a4 +#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (1<<18) +#define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT (1<<31) +#define AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT (1<<9) +#define AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR (1<<8) +#define AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT (1<<7) +#define AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR (1<<6) +#define AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT (1<<29) +#define AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR (1<<28) +#define AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT (1<<1) +#define AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR (1<<0) +#define AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR (1<<18) +#define AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT (1<<11) +#define AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT (1<<13) +#define AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR (1<<12) +#define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR (1<<12) +#define AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT (1<<15) +#define AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR (1<<14) +#define AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR (1<<20) +#define AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR (1<<0) +#define AEU_INPUTS_ATTN_BITS_PBF_HW_INTERRUPT (1<<31) +#define AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT (1<<3) +#define AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR (1<<2) +#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT (1<<5) +#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR (1<<4) +#define AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT (1<<3) +#define AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR (1<<2) +#define AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR (1<<22) +#define AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT (1<<27) +#define AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT (1<<5) +#define AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT (1<<25) +#define AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR (1<<24) +#define AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT (1<<29) +#define AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR (1<<28) +#define AEU_INPUTS_ATTN_BITS_UCM_HW_INTERRUPT (1<<23) +#define AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT (1<<27) +#define AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR (1<<26) +#define AEU_INPUTS_ATTN_BITS_USDM_HW_INTERRUPT (1<<21) +#define AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR (1<<20) +#define AEU_INPUTS_ATTN_BITS_USEMI_HW_INTERRUPT (1<<25) +#define AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR (1<<24) +#define AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR (1<<16) +#define AEU_INPUTS_ATTN_BITS_XCM_HW_INTERRUPT (1<<9) +#define AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT (1<<7) +#define AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR (1<<6) +#define AEU_INPUTS_ATTN_BITS_XSEMI_HW_INTERRUPT (1<<11) +#define AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR (1<<10) +#define RESERVED_GENERAL_ATTENTION_BIT_0 0 + +#define EVEREST_GEN_ATTN_IN_USE_MASK 0x3e0 +#define EVEREST_LATCHED_ATTN_IN_USE_MASK 0xffe00000 + +#define RESERVED_GENERAL_ATTENTION_BIT_6 6 +#define RESERVED_GENERAL_ATTENTION_BIT_7 7 +#define RESERVED_GENERAL_ATTENTION_BIT_8 8 +#define RESERVED_GENERAL_ATTENTION_BIT_9 9 +#define RESERVED_GENERAL_ATTENTION_BIT_10 10 +#define RESERVED_GENERAL_ATTENTION_BIT_11 11 +#define RESERVED_GENERAL_ATTENTION_BIT_12 12 +#define RESERVED_GENERAL_ATTENTION_BIT_13 13 +#define RESERVED_GENERAL_ATTENTION_BIT_14 14 +#define RESERVED_GENERAL_ATTENTION_BIT_15 15 +#define RESERVED_GENERAL_ATTENTION_BIT_16 16 +#define RESERVED_GENERAL_ATTENTION_BIT_17 17 +#define RESERVED_GENERAL_ATTENTION_BIT_18 18 +#define RESERVED_GENERAL_ATTENTION_BIT_19 19 +#define RESERVED_GENERAL_ATTENTION_BIT_20 20 +#define RESERVED_GENERAL_ATTENTION_BIT_21 21 + +/* storm asserts attention bits */ +#define TSTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_7 +#define USTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_8 +#define CSTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_9 +#define XSTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_10 + +/* mcp error attention bit */ +#define MCP_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_11 + +#define LATCHED_ATTN_RBCR 23 +#define LATCHED_ATTN_RBCT 24 +#define LATCHED_ATTN_RBCN 25 +#define LATCHED_ATTN_RBCU 26 +#define LATCHED_ATTN_RBCP 27 +#define LATCHED_ATTN_TIMEOUT_GRC 28 +#define LATCHED_ATTN_RSVD_GRC 29 +#define LATCHED_ATTN_ROM_PARITY_MCP 30 +#define LATCHED_ATTN_UM_RX_PARITY_MCP 31 +#define LATCHED_ATTN_UM_TX_PARITY_MCP 32 +#define LATCHED_ATTN_SCPAD_PARITY_MCP 33 + +#define GENERAL_ATTEN_WORD(atten_name) ((94 + atten_name) / 32) +#define GENERAL_ATTEN_OFFSET(atten_name) (1 << ((94 + atten_name) % 32)) +/* + * This file defines GRC base address for every block. + * This file is included by chipsim, asm microcode and cpp microcode. + * These values are used in Design.xml on regBase attribute + * Use the base with the generated offsets of specific registers. + */ + +#define GRCBASE_PXPCS 0x000000 +#define GRCBASE_PCICONFIG 0x002000 +#define GRCBASE_PCIREG 0x002400 +#define GRCBASE_EMAC0 0x008000 +#define GRCBASE_EMAC1 0x008400 +#define GRCBASE_DBU 0x008800 +#define GRCBASE_MISC 0x00A000 +#define GRCBASE_DBG 0x00C000 +#define GRCBASE_NIG 0x010000 +#define GRCBASE_XCM 0x020000 +#define GRCBASE_PRS 0x040000 +#define GRCBASE_SRCH 0x040400 +#define GRCBASE_TSDM 0x042000 +#define GRCBASE_TCM 0x050000 +#define GRCBASE_BRB1 0x060000 +#define GRCBASE_MCP 0x080000 +#define GRCBASE_UPB 0x0C1000 +#define GRCBASE_CSDM 0x0C2000 +#define GRCBASE_USDM 0x0C4000 +#define GRCBASE_CCM 0x0D0000 +#define GRCBASE_UCM 0x0E0000 +#define GRCBASE_CDU 0x101000 +#define GRCBASE_DMAE 0x102000 +#define GRCBASE_PXP 0x103000 +#define GRCBASE_CFC 0x104000 +#define GRCBASE_HC 0x108000 +#define GRCBASE_PXP2 0x120000 +#define GRCBASE_PBF 0x140000 +#define GRCBASE_XPB 0x161000 +#define GRCBASE_TIMERS 0x164000 +#define GRCBASE_XSDM 0x166000 +#define GRCBASE_QM 0x168000 +#define GRCBASE_DQ 0x170000 +#define GRCBASE_TSEM 0x180000 +#define GRCBASE_CSEM 0x200000 +#define GRCBASE_XSEM 0x280000 +#define GRCBASE_USEM 0x300000 +#define GRCBASE_MISC_AEU GRCBASE_MISC + + +/*the offset of the configuration space in the pci core register*/ +#define PCICFG_OFFSET 0x2000 +#define PCICFG_VENDOR_ID_OFFSET 0x00 +#define PCICFG_DEVICE_ID_OFFSET 0x02 +#define PCICFG_SUBSYSTEM_VENDOR_ID_OFFSET 0x2c +#define PCICFG_SUBSYSTEM_ID_OFFSET 0x2e +#define PCICFG_INT_LINE 0x3c +#define PCICFG_INT_PIN 0x3d +#define PCICFG_CACHE_LINE_SIZE 0x0c +#define PCICFG_LATENCY_TIMER 0x0d +#define PCICFG_REVESION_ID 0x08 +#define PCICFG_BAR_1_LOW 0x10 +#define PCICFG_BAR_1_HIGH 0x14 +#define PCICFG_BAR_2_LOW 0x18 +#define PCICFG_BAR_2_HIGH 0x1c +#define PCICFG_GRC_ADDRESS 0x78 +#define PCICFG_GRC_DATA 0x80 +#define PCICFG_DEVICE_CONTROL 0xb4 +#define PCICFG_LINK_CONTROL 0xbc + +#define BAR_USTRORM_INTMEM 0x400000 +#define BAR_CSTRORM_INTMEM 0x410000 +#define BAR_XSTRORM_INTMEM 0x420000 +#define BAR_TSTRORM_INTMEM 0x430000 + +#define BAR_IGU_INTMEM 0x440000 + +#define BAR_DOORBELL_OFFSET 0x800000 + +#define BAR_ME_REGISTER 0x450000 + + +#define GRC_CONFIG_2_SIZE_REG 0x408 /* config_2 offset */ +#define PCI_CONFIG_2_BAR1_SIZE (0xfL<<0) +#define PCI_CONFIG_2_BAR1_SIZE_DISABLED (0L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_64K (1L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_128K (2L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_256K (3L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_512K (4L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_1M (5L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_2M (6L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_4M (7L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_8M (8L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_16M (9L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_32M (10L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_64M (11L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_128M (12L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_256M (13L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_512M (14L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_1G (15L<<0) +#define PCI_CONFIG_2_BAR1_64ENA (1L<<4) +#define PCI_CONFIG_2_EXP_ROM_RETRY (1L<<5) +#define PCI_CONFIG_2_CFG_CYCLE_RETRY (1L<<6) +#define PCI_CONFIG_2_FIRST_CFG_DONE (1L<<7) +#define PCI_CONFIG_2_EXP_ROM_SIZE (0xffL<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_DISABLED (0L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_2K (1L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_4K (2L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_8K (3L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_16K (4L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_32K (5L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_64K (6L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_128K (7L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_256K (8L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_512K (9L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_1M (10L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_2M (11L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_4M (12L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_8M (13L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_16M (14L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_32M (15L<<8) +#define PCI_CONFIG_2_BAR_PREFETCH (1L<<16) +#define PCI_CONFIG_2_RESERVED0 (0x7fffL<<17) + +/* config_3 offset */ +#define GRC_CONFIG_3_SIZE_REG (0x40c) +#define PCI_CONFIG_3_STICKY_BYTE (0xffL<<0) +#define PCI_CONFIG_3_FORCE_PME (1L<<24) +#define PCI_CONFIG_3_PME_STATUS (1L<<25) +#define PCI_CONFIG_3_PME_ENABLE (1L<<26) +#define PCI_CONFIG_3_PM_STATE (0x3L<<27) +#define PCI_CONFIG_3_VAUX_PRESET (1L<<30) +#define PCI_CONFIG_3_PCI_POWER (1L<<31) + +/* config_2 offset */ +#define GRC_CONFIG_2_SIZE_REG 0x408 + +#define GRC_BAR2_CONFIG 0x4e0 +#define PCI_CONFIG_2_BAR2_SIZE (0xfL<<0) +#define PCI_CONFIG_2_BAR2_SIZE_DISABLED (0L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_64K (1L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_128K (2L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_256K (3L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_512K (4L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_1M (5L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_2M (6L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_4M (7L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_8M (8L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_16M (9L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_32M (10L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_64M (11L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_128M (12L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_256M (13L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_512M (14L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_1G (15L<<0) +#define PCI_CONFIG_2_BAR2_64ENA (1L<<4) + +#define PCI_PM_DATA_A (0x410) +#define PCI_PM_DATA_B (0x414) +#define PCI_ID_VAL1 (0x434) +#define PCI_ID_VAL2 (0x438) + +#define MDIO_REG_BANK_CL73_IEEEB0 0x0 +#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL 0x0 +#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN 0x0200 +#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN 0x1000 +#define MDIO_CL73_IEEEB0_CL73_AN_CONTROL_MAIN_RST 0x8000 + +#define MDIO_REG_BANK_CL73_IEEEB1 0x10 +#define MDIO_CL73_IEEEB1_AN_ADV2 0x01 +#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M 0x0000 +#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX 0x0020 +#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4 0x0040 +#define MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KR 0x0080 + +#define MDIO_REG_BANK_RX0 0x80b0 +#define MDIO_RX0_RX_EQ_BOOST 0x1c +#define MDIO_RX0_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 +#define MDIO_RX0_RX_EQ_BOOST_OFFSET_CTRL 0x10 + +#define MDIO_REG_BANK_RX1 0x80c0 +#define MDIO_RX1_RX_EQ_BOOST 0x1c +#define MDIO_RX1_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 +#define MDIO_RX1_RX_EQ_BOOST_OFFSET_CTRL 0x10 + +#define MDIO_REG_BANK_RX2 0x80d0 +#define MDIO_RX2_RX_EQ_BOOST 0x1c +#define MDIO_RX2_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 +#define MDIO_RX2_RX_EQ_BOOST_OFFSET_CTRL 0x10 + +#define MDIO_REG_BANK_RX3 0x80e0 +#define MDIO_RX3_RX_EQ_BOOST 0x1c +#define MDIO_RX3_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 +#define MDIO_RX3_RX_EQ_BOOST_OFFSET_CTRL 0x10 + +#define MDIO_REG_BANK_RX_ALL 0x80f0 +#define MDIO_RX_ALL_RX_EQ_BOOST 0x1c +#define MDIO_RX_ALL_RX_EQ_BOOST_EQUALIZER_CTRL_MASK 0x7 +#define MDIO_RX_ALL_RX_EQ_BOOST_OFFSET_CTRL 0x10 + +#define MDIO_REG_BANK_TX0 0x8060 +#define MDIO_TX0_TX_DRIVER 0x17 +#define MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK 0xf000 +#define MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT 12 +#define MDIO_TX0_TX_DRIVER_IDRIVER_MASK 0x0f00 +#define MDIO_TX0_TX_DRIVER_IDRIVER_SHIFT 8 +#define MDIO_TX0_TX_DRIVER_IPREDRIVER_MASK 0x00f0 +#define MDIO_TX0_TX_DRIVER_IPREDRIVER_SHIFT 4 +#define MDIO_TX0_TX_DRIVER_IFULLSPD_MASK 0x000e +#define MDIO_TX0_TX_DRIVER_IFULLSPD_SHIFT 1 +#define MDIO_TX0_TX_DRIVER_ICBUF1T 1 + +#define MDIO_REG_BANK_XGXS_BLOCK0 0x8000 +#define MDIO_BLOCK0_XGXS_CONTROL 0x10 + +#define MDIO_REG_BANK_XGXS_BLOCK1 0x8010 +#define MDIO_BLOCK1_LANE_CTRL0 0x15 +#define MDIO_BLOCK1_LANE_CTRL1 0x16 +#define MDIO_BLOCK1_LANE_CTRL2 0x17 +#define MDIO_BLOCK1_LANE_PRBS 0x19 + +#define MDIO_REG_BANK_XGXS_BLOCK2 0x8100 +#define MDIO_XGXS_BLOCK2_RX_LN_SWAP 0x10 +#define MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE 0x8000 +#define MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE 0x4000 +#define MDIO_XGXS_BLOCK2_TX_LN_SWAP 0x11 +#define MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE 0x8000 +#define MDIO_XGXS_BLOCK2_TEST_MODE_LANE 0x15 + +#define MDIO_REG_BANK_GP_STATUS 0x8120 +#define MDIO_GP_STATUS_TOP_AN_STATUS1 0x1B +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE 0x0001 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE 0x0002 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS 0x0004 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS 0x0008 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE 0x0010 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_LP_NP_BAM_ABLE 0x0020 + +#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE 0x0040 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE 0x0080 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK 0x3f00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M 0x0000 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M 0x0100 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G 0x0200 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G 0x0300 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G 0x0400 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G 0x0500 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG 0x0600 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 0x0700 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12G_HIG 0x0800 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_12_5G 0x0900 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_13G 0x0A00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_15G 0x0B00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_16G 0x0C00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX 0x0D00 +#define MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 0x0E00 + + +#define MDIO_REG_BANK_10G_PARALLEL_DETECT 0x8130 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL 0x11 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN 0x1 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK 0x13 +#define MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT (0xb71<<1) + +#define MDIO_REG_BANK_SERDES_DIGITAL 0x8300 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1 0x10 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE 0x0001 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_TBI_IF 0x0002 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN 0x0004 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT 0x0008 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET 0x0010 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE 0x0020 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2 0x11 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN 0x0001 +#define MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_AN_FST_TMR 0x0040 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1 0x14 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_DUPLEX 0x0004 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_MASK 0x0018 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_SHIFT 3 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_2_5G 0x0018 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_1G 0x0010 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_100M 0x0008 +#define MDIO_SERDES_DIGITAL_A_1000X_STATUS1_SPEED_10M 0x0000 +#define MDIO_SERDES_DIGITAL_MISC1 0x18 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_MASK 0xE000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_25M 0x0000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_100M 0x2000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_125M 0x4000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M 0x6000 +#define MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_187_5M 0x8000 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL 0x0010 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK 0x000f +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_2_5G 0x0000 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_5G 0x0001 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_6G 0x0002 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_HIG 0x0003 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4 0x0004 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12G 0x0005 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_12_5G 0x0006 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_13G 0x0007 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_15G 0x0008 +#define MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_16G 0x0009 + +#define MDIO_REG_BANK_OVER_1G 0x8320 +#define MDIO_OVER_1G_DIGCTL_3_4 0x14 +#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_MASK 0xffe0 +#define MDIO_OVER_1G_DIGCTL_3_4_MP_ID_SHIFT 5 +#define MDIO_OVER_1G_UP1 0x19 +#define MDIO_OVER_1G_UP1_2_5G 0x0001 +#define MDIO_OVER_1G_UP1_5G 0x0002 +#define MDIO_OVER_1G_UP1_6G 0x0004 +#define MDIO_OVER_1G_UP1_10G 0x0010 +#define MDIO_OVER_1G_UP1_10GH 0x0008 +#define MDIO_OVER_1G_UP1_12G 0x0020 +#define MDIO_OVER_1G_UP1_12_5G 0x0040 +#define MDIO_OVER_1G_UP1_13G 0x0080 +#define MDIO_OVER_1G_UP1_15G 0x0100 +#define MDIO_OVER_1G_UP1_16G 0x0200 +#define MDIO_OVER_1G_UP2 0x1A +#define MDIO_OVER_1G_UP2_IPREDRIVER_MASK 0x0007 +#define MDIO_OVER_1G_UP2_IDRIVER_MASK 0x0038 +#define MDIO_OVER_1G_UP2_PREEMPHASIS_MASK 0x03C0 +#define MDIO_OVER_1G_UP3 0x1B +#define MDIO_OVER_1G_UP3_HIGIG2 0x0001 +#define MDIO_OVER_1G_LP_UP1 0x1C +#define MDIO_OVER_1G_LP_UP2 0x1D +#define MDIO_OVER_1G_LP_UP2_MR_ADV_OVER_1G_MASK 0x03ff +#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK 0x0780 +#define MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT 7 +#define MDIO_OVER_1G_LP_UP3 0x1E + +#define MDIO_REG_BANK_BAM_NEXT_PAGE 0x8350 +#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL 0x10 +#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE 0x0001 +#define MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN 0x0002 + +#define MDIO_REG_BANK_CL73_USERB0 0x8370 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1 0x12 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN 0x8000 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN 0x4000 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN 0x2000 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL3 0x14 +#define MDIO_CL73_USERB0_CL73_BAM_CTRL3_USE_CL73_HCD_MR 0x0001 + +#define MDIO_REG_BANK_AER_BLOCK 0xFFD0 +#define MDIO_AER_BLOCK_AER_REG 0x1E + +#define MDIO_REG_BANK_COMBO_IEEE0 0xFFE0 +#define MDIO_COMBO_IEEE0_MII_CONTROL 0x10 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK 0x2040 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_10 0x0000 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100 0x2000 +#define MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000 0x0040 +#define MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX 0x0100 +#define MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN 0x0200 +#define MDIO_COMBO_IEEO_MII_CONTROL_AN_EN 0x1000 +#define MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK 0x4000 +#define MDIO_COMBO_IEEO_MII_CONTROL_RESET 0x8000 +#define MDIO_COMBO_IEEE0_MII_STATUS 0x11 +#define MDIO_COMBO_IEEE0_MII_STATUS_LINK_PASS 0x0004 +#define MDIO_COMBO_IEEE0_MII_STATUS_AUTONEG_COMPLETE 0x0020 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV 0x14 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX 0x0020 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_HALF_DUPLEX 0x0040 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE 0x0000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC 0x0080 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC 0x0100 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_ADV_NEXT_PAGE 0x8000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1 0x15 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_NEXT_PAGE 0x8000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_ACK 0x4000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_MASK 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_NONE\ + 0x0000 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_PAUSE_BOTH\ + 0x0180 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_HALF_DUP_CAP 0x0040 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_FULL_DUP_CAP 0x0020 +#define MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1_SGMII_MODE 0x0001 + + +#define EXT_PHY_OPT_PMA_PMD_DEVAD 0x1 +#define EXT_PHY_OPT_WIS_DEVAD 0x2 +#define EXT_PHY_OPT_PCS_DEVAD 0x3 +#define EXT_PHY_OPT_PHY_XS_DEVAD 0x4 +#define EXT_PHY_OPT_CNTL 0x0 +#define EXT_PHY_OPT_PMD_RX_SD 0xa +#define EXT_PHY_OPT_PMD_MISC_CNTL 0xca0a +#define EXT_PHY_OPT_PHY_IDENTIFIER 0xc800 +#define EXT_PHY_OPT_PMD_DIGITAL_CNT 0xc808 +#define EXT_PHY_OPT_PMD_DIGITAL_SATUS 0xc809 +#define EXT_PHY_OPT_CMU_PLL_BYPASS 0xca09 +#define EXT_PHY_OPT_LASI_CNTL 0x9002 +#define EXT_PHY_OPT_RX_ALARM 0x9003 +#define EXT_PHY_OPT_LASI_STATUS 0x9005 +#define EXT_PHY_OPT_PCS_STATUS 0x0020 +#define EXT_PHY_OPT_XGXS_LANE_STATUS 0x0018 + +#define EXT_PHY_KR_PMA_PMD_DEVAD 0x1 +#define EXT_PHY_KR_PCS_DEVAD 0x3 +#define EXT_PHY_KR_AUTO_NEG_DEVAD 0x7 +#define EXT_PHY_KR_CTRL 0x0000 +#define EXT_PHY_KR_CTRL2 0x0007 +#define EXT_PHY_KR_PCS_STATUS 0x0020 +#define EXT_PHY_KR_PMD_CTRL 0x0096 +#define EXT_PHY_KR_LASI_CNTL 0x9002 +#define EXT_PHY_KR_LASI_STATUS 0x9005 +#define EXT_PHY_KR_MISC_CTRL1 0xca85 +#define EXT_PHY_KR_GEN_CTRL 0xca10 +#define EXT_PHY_KR_ROM_CODE 0xca19 + diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 49a198206e3d..2039f7838f2d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2517,7 +2517,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) fl.fl4_dst = targets[i]; fl.fl4_tos = RTO_ONLINK; - rv = ip_route_output_key(&rt, &fl); + rv = ip_route_output_key(&init_net, &rt, &fl); if (rv) { if (net_ratelimit()) { printk(KERN_WARNING DRV_NAME diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig new file mode 100644 index 000000000000..57def0d57371 --- /dev/null +++ b/drivers/net/can/Kconfig @@ -0,0 +1,25 @@ +menu "CAN Device Drivers" + depends on CAN + +config CAN_VCAN + tristate "Virtual Local CAN Interface (vcan)" + depends on CAN + default N + ---help--- + Similar to the network loopback devices, vcan offers a + virtual local CAN interface. + + This driver can also be built as a module. If so, the module + will be called vcan. + +config CAN_DEBUG_DEVICES + bool "CAN devices debugging messages" + depends on CAN + default N + ---help--- + Say Y here if you want the CAN device drivers to produce a bunch of + debug messages to the system log. Select this if you are having + a problem with CAN support and want to see more of what is going + on. + +endmenu diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile new file mode 100644 index 000000000000..c4bead705cd9 --- /dev/null +++ b/drivers/net/can/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Linux Controller Area Network drivers. +# + +obj-$(CONFIG_CAN_VCAN) += vcan.o diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c new file mode 100644 index 000000000000..103f0f1df280 --- /dev/null +++ b/drivers/net/can/vcan.c @@ -0,0 +1,169 @@ +/* + * vcan.c - Virtual CAN interface + * + * Copyright (c) 2002-2007 Volkswagen Group Electronic Research + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Volkswagen nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Alternatively, provided that this notice is retained in full, this + * software may be distributed under the terms of the GNU General + * Public License ("GPL") version 2, in which case the provisions of the + * GPL apply INSTEAD OF those given above. + * + * The provided data structures and external interfaces from this code + * are not restricted to be used by modules with a GPL compatible license. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Send feedback to <socketcan-users@lists.berlios.de> + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/if_ether.h> +#include <linux/can.h> +#include <net/rtnetlink.h> + +static __initdata const char banner[] = + KERN_INFO "vcan: Virtual CAN interface driver\n"; + +MODULE_DESCRIPTION("virtual CAN interface"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Urs Thuermann <urs.thuermann@volkswagen.de>"); + + +/* + * CAN test feature: + * Enable the echo on driver level for testing the CAN core echo modes. + * See Documentation/networking/can.txt for details. + */ + +static int echo; /* echo testing. Default: 0 (Off) */ +module_param(echo, bool, S_IRUGO); +MODULE_PARM_DESC(echo, "Echo sent frames (for testing). Default: 0 (Off)"); + + +static void vcan_rx(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device_stats *stats = &dev->stats; + + stats->rx_packets++; + stats->rx_bytes += skb->len; + + skb->protocol = htons(ETH_P_CAN); + skb->pkt_type = PACKET_BROADCAST; + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_rx(skb); +} + +static int vcan_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct net_device_stats *stats = &dev->stats; + int loop; + + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* set flag whether this packet has to be looped back */ + loop = skb->pkt_type == PACKET_LOOPBACK; + + if (!echo) { + /* no echo handling available inside this driver */ + + if (loop) { + /* + * only count the packets here, because the + * CAN core already did the echo for us + */ + stats->rx_packets++; + stats->rx_bytes += skb->len; + } + kfree_skb(skb); + return NETDEV_TX_OK; + } + + /* perform standard echo handling for CAN network interfaces */ + + if (loop) { + struct sock *srcsk = skb->sk; + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NETDEV_TX_OK; + + /* receive with packet counting */ + skb->sk = srcsk; + vcan_rx(skb, dev); + } else { + /* no looped packets => no counting */ + kfree_skb(skb); + } + return NETDEV_TX_OK; +} + +static void vcan_setup(struct net_device *dev) +{ + dev->type = ARPHRD_CAN; + dev->mtu = sizeof(struct can_frame); + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 0; + dev->flags = IFF_NOARP; + + /* set flags according to driver capabilities */ + if (echo) + dev->flags |= IFF_ECHO; + + dev->hard_start_xmit = vcan_tx; + dev->destructor = free_netdev; +} + +static struct rtnl_link_ops vcan_link_ops __read_mostly = { + .kind = "vcan", + .setup = vcan_setup, +}; + +static __init int vcan_init_module(void) +{ + printk(banner); + + if (echo) + printk(KERN_INFO "vcan: enabled echo on driver level.\n"); + + return rtnl_link_register(&vcan_link_ops); +} + +static __exit void vcan_cleanup_module(void) +{ + rtnl_link_unregister(&vcan_link_ops); +} + +module_init(vcan_init_module); +module_exit(vcan_cleanup_module); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index d66915d82b24..14299f8063af 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4394,7 +4394,7 @@ static struct { {"tx_fifo_errors"}, {"tx_packets"} }; -#define CAS_NUM_STAT_KEYS (sizeof(ethtool_cassini_statnames)/ETH_GSTRING_LEN) +#define CAS_NUM_STAT_KEYS ARRAY_SIZE(ethtool_cassini_statnames) static struct { const int offsets; /* neg. values for 2nd arg to cas_read_phy */ @@ -5085,7 +5085,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, /* give us access to cassini registers */ cp->regs = pci_iomap(pdev, 0, casreg_len); - if (cp->regs == 0UL) { + if (!cp->regs) { dev_err(&pdev->dev, "Cannot map device registers, aborting.\n"); goto err_out_free_res; } diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 846ca5383d3c..4bd2455b0fe3 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h @@ -379,7 +379,7 @@ extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config extern const struct board_info *t1_get_board_info(unsigned int board_id); extern const struct board_info *t1_get_board_info_from_ids(unsigned int devid, unsigned short ssid); -extern int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data); +extern int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data); extern int t1_get_board_rev(adapter_t *adapter, const struct board_info *bi, struct adapter_params *p); extern int t1_init_hw_modules(adapter_t *adapter); diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index c5975047c89b..a509337eab2d 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -814,7 +814,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, e->magic = EEPROM_MAGIC(adapter); for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32)) - t1_seeprom_read(adapter, i, (u32 *)&buf[i]); + t1_seeprom_read(adapter, i, (__le32 *)&buf[i]); memcpy(data, buf + e->offset, e->len); return 0; } @@ -1042,7 +1042,7 @@ static int __devinit init_one(struct pci_dev *pdev, pci_using_dac = 1; if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) { - CH_ERR("%s: unable to obtain 64-bit DMA for" + CH_ERR("%s: unable to obtain 64-bit DMA for " "consistent allocations\n", pci_name(pdev)); err = -ENODEV; goto out_disable_pdev; diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c index d7c5406a6c3f..1e0749e000b0 100644 --- a/drivers/net/chelsio/espi.c +++ b/drivers/net/chelsio/espi.c @@ -297,6 +297,7 @@ struct peespi *t1_espi_create(adapter_t *adapter) return espi; } +#if 0 void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) { struct peespi *espi = adapter->espi; @@ -309,6 +310,7 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val) writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL); spin_unlock(&espi->lock); } +#endif /* 0 */ u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait) { diff --git a/drivers/net/chelsio/espi.h b/drivers/net/chelsio/espi.h index 84f2c98bc4cc..5694aad4fbc0 100644 --- a/drivers/net/chelsio/espi.h +++ b/drivers/net/chelsio/espi.h @@ -62,7 +62,6 @@ void t1_espi_intr_disable(struct peespi *); int t1_espi_intr_handler(struct peespi *); const struct espi_intr_counts *t1_espi_get_intr_counts(struct peespi *espi); -void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val); u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait); int t1_espi_get_mon_t204(adapter_t *, u32 *, u8); diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index b301c0428ae0..8a7efd38e95b 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -330,6 +330,8 @@ unsigned int t1_sched_update_parms(struct sge *sge, unsigned int port, return max_avail_segs * (p->mtu - 40); } +#if 0 + /* * t1_sched_max_avail_bytes() tells the scheduler the maximum amount of * data that can be pushed per port. @@ -357,6 +359,8 @@ void t1_sched_set_drain_bits_per_us(struct sge *sge, unsigned int port, t1_sched_update_parms(sge, port, 0, 0); } +#endif /* 0 */ + /* * get_clock() implements a ns clock (see ktime_get) diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h index cced9dff91c5..8c9405123992 100644 --- a/drivers/net/chelsio/sge.h +++ b/drivers/net/chelsio/sge.h @@ -88,8 +88,6 @@ void t1_sge_intr_disable(struct sge *); void t1_sge_intr_clear(struct sge *); const struct sge_intr_counts *t1_sge_get_intr_counts(const struct sge *sge); void t1_sge_get_port_stats(const struct sge *sge, int port, struct sge_port_stats *); -void t1_sched_set_max_avail_bytes(struct sge *, unsigned int); -void t1_sched_set_drain_bits_per_us(struct sge *, unsigned int, unsigned int); unsigned int t1_sched_update_parms(struct sge *, unsigned int, unsigned int, unsigned int); diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index dc50151bed81..7adf30230c4f 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -563,10 +563,11 @@ struct chelsio_vpd_t { * written to the Control register. The hardware device will set the flag to a * one when 4B have been transferred to the Data register. */ -int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data) +int t1_seeprom_read(adapter_t *adapter, u32 addr, __le32 *data) { int i = EEPROM_MAX_POLL; u16 val; + u32 v; if (addr >= EEPROMSIZE || (addr & 3)) return -EINVAL; @@ -582,8 +583,8 @@ int t1_seeprom_read(adapter_t *adapter, u32 addr, u32 *data) adapter->name, addr); return -EIO; } - pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, data); - *data = le32_to_cpu(*data); + pci_read_config_dword(adapter->pdev, A_PCICFG_VPD_DATA, &v); + *data = cpu_to_le32(v); return 0; } @@ -593,7 +594,7 @@ static int t1_eeprom_vpd_get(adapter_t *adapter, struct chelsio_vpd_t *vpd) for (addr = 0; !ret && addr < sizeof(*vpd); addr += sizeof(u32)) ret = t1_seeprom_read(adapter, addr, - (u32 *)((u8 *)vpd + addr)); + (__le32 *)((u8 *)vpd + addr)); return ret; } diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 6e12d48351b8..6ccebb830ff9 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -661,9 +661,6 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) int queue; u32 status; - if (!dev) - return IRQ_NONE; - priv = netdev_priv(dev); status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 60a62f510db7..eb305a0895fc 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -71,6 +71,7 @@ enum { /* adapter flags */ USING_MSI = (1 << 1), USING_MSIX = (1 << 2), QUEUES_BOUND = (1 << 3), + TP_PARITY_INIT = (1 << 4), }; struct fl_pg_chunk { diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index 99c75d30f67a..91ee7277b813 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -681,8 +681,8 @@ int t3_phy_intr_handler(struct adapter *adapter); void t3_link_changed(struct adapter *adapter, int port_id); int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc); const struct adapter_info *t3_get_adapter_info(unsigned int board_id); -int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data); -int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data); +int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); +int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data); int t3_seeprom_wp(struct adapter *adapter, int enable); int t3_get_tp_version(struct adapter *adapter, u32 *vers); int t3_check_tpsram_version(struct adapter *adapter, int *must_load); diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 61ffc925eae7..fd2e05bbb903 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -76,20 +76,20 @@ enum { #define EEPROM_MAGIC 0x38E2F10C -#define CH_DEVICE(devid, ssid, idx) \ - { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx } +#define CH_DEVICE(devid, idx) \ + { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx } static const struct pci_device_id cxgb3_pci_tbl[] = { - CH_DEVICE(0x20, 1, 0), /* PE9000 */ - CH_DEVICE(0x21, 1, 1), /* T302E */ - CH_DEVICE(0x22, 1, 2), /* T310E */ - CH_DEVICE(0x23, 1, 3), /* T320X */ - CH_DEVICE(0x24, 1, 1), /* T302X */ - CH_DEVICE(0x25, 1, 3), /* T320E */ - CH_DEVICE(0x26, 1, 2), /* T310X */ - CH_DEVICE(0x30, 1, 2), /* T3B10 */ - CH_DEVICE(0x31, 1, 3), /* T3B20 */ - CH_DEVICE(0x32, 1, 1), /* T3B02 */ + CH_DEVICE(0x20, 0), /* PE9000 */ + CH_DEVICE(0x21, 1), /* T302E */ + CH_DEVICE(0x22, 2), /* T310E */ + CH_DEVICE(0x23, 3), /* T320X */ + CH_DEVICE(0x24, 1), /* T302X */ + CH_DEVICE(0x25, 3), /* T320E */ + CH_DEVICE(0x26, 2), /* T310X */ + CH_DEVICE(0x30, 2), /* T3B10 */ + CH_DEVICE(0x31, 3), /* T3B20 */ + CH_DEVICE(0x32, 1), /* T3B02 */ {0,} }; @@ -306,6 +306,77 @@ static int request_msix_data_irqs(struct adapter *adap) return 0; } +static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, + unsigned long n) +{ + int attempts = 5; + + while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { + if (!--attempts) + return -ETIMEDOUT; + msleep(10); + } + return 0; +} + +static int init_tp_parity(struct adapter *adap) +{ + int i; + struct sk_buff *skb; + struct cpl_set_tcb_field *greq; + unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; + + t3_tp_set_offload_mode(adap, 1); + + for (i = 0; i < 16; i++) { + struct cpl_smt_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); + req->iff = i; + t3_mgmt_tx(adap, skb); + } + + for (i = 0; i < 2048; i++) { + struct cpl_l2t_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); + req->params = htonl(V_L2T_W_IDX(i)); + t3_mgmt_tx(adap, skb); + } + + for (i = 0; i < 2048; i++) { + struct cpl_rte_write_req *req; + + skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL); + req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req)); + memset(req, 0, sizeof(*req)); + req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); + req->l2t_idx = htonl(V_L2T_W_IDX(i)); + t3_mgmt_tx(adap, skb); + } + + skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL); + greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq)); + memset(greq, 0, sizeof(*greq)); + greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); + OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); + greq->mask = cpu_to_be64(1); + t3_mgmt_tx(adap, skb); + + i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); + t3_tp_set_offload_mode(adap, 0); + return i; +} + /** * setup_rss - configure RSS * @adap: the adapter @@ -336,7 +407,7 @@ static void setup_rss(struct adapter *adap) t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | - V_RRCPLCPUSIZE(6), cpus, rspq_map); + V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map); } static void init_napi(struct adapter *adap) @@ -410,8 +481,7 @@ static int setup_sge_qsets(struct adapter *adap) return 0; } -static ssize_t attr_show(struct device *d, struct device_attribute *attr, - char *buf, +static ssize_t attr_show(struct device *d, char *buf, ssize_t(*format) (struct net_device *, char *)) { ssize_t len; @@ -423,7 +493,7 @@ static ssize_t attr_show(struct device *d, struct device_attribute *attr, return len; } -static ssize_t attr_store(struct device *d, struct device_attribute *attr, +static ssize_t attr_store(struct device *d, const char *buf, size_t len, ssize_t(*set) (struct net_device *, unsigned int), unsigned int min_val, unsigned int max_val) @@ -457,7 +527,7 @@ static ssize_t format_##name(struct net_device *dev, char *buf) \ static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ char *buf) \ { \ - return attr_show(d, attr, buf, format_##name); \ + return attr_show(d, buf, format_##name); \ } static ssize_t set_nfilters(struct net_device *dev, unsigned int val) @@ -480,7 +550,7 @@ static ssize_t set_nfilters(struct net_device *dev, unsigned int val) static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return attr_store(d, attr, buf, len, set_nfilters, 0, ~0); + return attr_store(d, buf, len, set_nfilters, 0, ~0); } static ssize_t set_nservers(struct net_device *dev, unsigned int val) @@ -500,7 +570,7 @@ static ssize_t set_nservers(struct net_device *dev, unsigned int val) static ssize_t store_nservers(struct device *d, struct device_attribute *attr, const char *buf, size_t len) { - return attr_store(d, attr, buf, len, set_nservers, 0, ~0); + return attr_store(d, buf, len, set_nservers, 0, ~0); } #define CXGB3_ATTR_R(name, val_expr) \ @@ -524,7 +594,7 @@ static struct attribute *cxgb3_attrs[] = { static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs }; -static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr, +static ssize_t tm_attr_show(struct device *d, char *buf, int sched) { struct port_info *pi = netdev_priv(to_net_dev(d)); @@ -550,7 +620,7 @@ static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr, return len; } -static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr, +static ssize_t tm_attr_store(struct device *d, const char *buf, size_t len, int sched) { struct port_info *pi = netdev_priv(to_net_dev(d)); @@ -578,12 +648,12 @@ static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr, static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ char *buf) \ { \ - return tm_attr_show(d, attr, buf, sched); \ + return tm_attr_show(d, buf, sched); \ } \ static ssize_t store_##name(struct device *d, struct device_attribute *attr, \ const char *buf, size_t len) \ { \ - return tm_attr_store(d, attr, buf, len, sched); \ + return tm_attr_store(d, buf, len, sched); \ } \ static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name) @@ -720,7 +790,7 @@ static int upgrade_fw(struct adapter *adap) else dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n", FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); - + return ret; } @@ -747,7 +817,7 @@ static int update_tpsram(struct adapter *adap) struct device *dev = &adap->pdev->dev; int ret; char rev; - + rev = t3rev2char(adap); if (!rev) return 0; @@ -761,10 +831,10 @@ static int update_tpsram(struct adapter *adap) buf); return ret; } - + ret = t3_check_tpsram(adap, tpsram->data, tpsram->size); if (ret) - goto release_tpsram; + goto release_tpsram; ret = t3_set_proto_sram(adap, tpsram->data); if (ret == 0) @@ -780,7 +850,7 @@ static int update_tpsram(struct adapter *adap) release_tpsram: release_firmware(tpsram); - + return ret; } @@ -818,6 +888,7 @@ static int cxgb_up(struct adapter *adap) if (err) goto out; + t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); err = setup_sge_qsets(adap); @@ -839,7 +910,8 @@ static int cxgb_up(struct adapter *adap) if (err) goto irq_err; - if (request_msix_data_irqs(adap)) { + err = request_msix_data_irqs(adap); + if (err) { free_irq(adap->msix_info[0].vec, adap); goto irq_err; } @@ -856,6 +928,16 @@ static int cxgb_up(struct adapter *adap) t3_sge_start(adap); t3_intr_enable(adap); + if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) && + is_offload(adap) && init_tp_parity(adap) == 0) + adap->flags |= TP_PARITY_INIT; + + if (adap->flags & TP_PARITY_INIT) { + t3_write_reg(adap, A_TP_INT_CAUSE, + F_CMCACHEPERR | F_ARPLUTPERR); + t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff); + } + if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX) bind_qsets(adap); adap->flags |= QUEUES_BOUND; @@ -1560,7 +1642,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, e->magic = EEPROM_MAGIC; for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4) - err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]); + err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]); if (!err) memcpy(data, buf + e->offset, e->len); @@ -1573,7 +1655,8 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, { struct port_info *pi = netdev_priv(dev); struct adapter *adapter = pi->adapter; - u32 aligned_offset, aligned_len, *p; + u32 aligned_offset, aligned_len; + __le32 *p; u8 *buf; int err; @@ -1587,11 +1670,11 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, buf = kmalloc(aligned_len, GFP_KERNEL); if (!buf) return -ENOMEM; - err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf); + err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf); if (!err && aligned_len > 4) err = t3_seeprom_read(adapter, aligned_offset + aligned_len - 4, - (u32 *) & buf[aligned_len - 4]); + (__le32 *) & buf[aligned_len - 4]); if (err) goto out; memcpy(buf + (eeprom->offset & 3), data, eeprom->len); @@ -1602,7 +1685,7 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (err) goto out; - for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) { + for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) { err = t3_seeprom_write(adapter, aligned_offset, *p); aligned_offset += 4; } @@ -2144,7 +2227,7 @@ static void cxgb_netpoll(struct net_device *dev) for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) { struct sge_qset *qs = &adapter->sge.qs[qidx]; void *source; - + if (adapter->flags & USING_MSIX) source = qs; else @@ -2315,6 +2398,106 @@ void t3_fatal_err(struct adapter *adapter) } +/** + * t3_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + int i; + + /* Stop all ports */ + for_each_port(adapter, i) { + struct net_device *netdev = adapter->port[i]; + + if (netif_running(netdev)) + cxgb_close(netdev); + } + + if (is_offload(adapter) && + test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) + offload_close(&adapter->tdev); + + /* Free sge resources */ + t3_free_sge_resources(adapter); + + adapter->flags &= ~FULL_INIT_DONE; + + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * t3_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + t3_prep_adapter(adapter, adapter->params.info, 1); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * t3_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void t3_io_resume(struct pci_dev *pdev) +{ + struct adapter *adapter = pci_get_drvdata(pdev); + int i; + + /* Restart the ports */ + for_each_port(adapter, i) { + struct net_device *netdev = adapter->port[i]; + + if (netif_running(netdev)) { + if (cxgb_open(netdev)) { + dev_err(&pdev->dev, + "can't bring device back up" + " after reset\n"); + continue; + } + netif_device_attach(netdev); + } + } + + if (is_offload(adapter)) { + __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map); + if (offload_open(adapter->port[0])) + printk(KERN_WARNING + "Could not bring back offload capabilities\n"); + } +} + +static struct pci_error_handlers t3_err_handler = { + .error_detected = t3_io_error_detected, + .slot_reset = t3_io_slot_reset, + .resume = t3_io_resume, +}; + static int __devinit cxgb_enable_msix(struct adapter *adap) { struct msix_entry entries[SGE_QSETS + 1]; @@ -2507,7 +2690,7 @@ static int __devinit init_one(struct pci_dev *pdev, err = -ENODEV; goto out_free_dev; } - + /* * The card is now ready to go. If any errors occur during device * registration we do not fail the whole card but rather proceed only @@ -2584,10 +2767,6 @@ static void __devexit remove_one(struct pci_dev *pdev) sysfs_remove_group(&adapter->port[0]->dev.kobj, &cxgb3_attr_group); - for_each_port(adapter, i) - if (test_bit(i, &adapter->registered_device_map)) - unregister_netdev(adapter->port[i]); - if (is_offload(adapter)) { cxgb3_adapter_unofld(adapter); if (test_bit(OFFLOAD_DEVMAP_BIT, @@ -2595,6 +2774,10 @@ static void __devexit remove_one(struct pci_dev *pdev) offload_close(&adapter->tdev); } + for_each_port(adapter, i) + if (test_bit(i, &adapter->registered_device_map)) + unregister_netdev(adapter->port[i]); + t3_free_sge_resources(adapter); cxgb_disable_msi(adapter); @@ -2615,6 +2798,7 @@ static struct pci_driver driver = { .id_table = cxgb3_pci_tbl, .probe = init_one, .remove = __devexit_p(remove_one), + .err_handler = &t3_err_handler, }; static int __init cxgb3_init_module(void) diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index bd25421bc12a..d48c396bdabb 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -403,8 +403,6 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs, int n) { - CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n", - n, ntohl(*(__be32 *)skbs[0]->data)); while (n--) dev_kfree_skb_any(skbs[n]); return 0; @@ -488,7 +486,7 @@ static void t3_process_tid_release_list(struct work_struct *work) tid_release_task); struct sk_buff *skb; struct t3cdev *tdev = td->dev; - + spin_lock_bh(&td->tid_release_lock); while (td->tid_release_list) { @@ -634,6 +632,18 @@ static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb) return CPL_RET_BUF_DONE; } +static int do_rte_write_rpl(struct t3cdev *dev, struct sk_buff *skb) +{ + struct cpl_rte_write_rpl *rpl = cplhdr(skb); + + if (rpl->status != CPL_ERR_NONE) + printk(KERN_ERR + "Unexpected RTE_WRITE_RPL status %u for entry %u\n", + rpl->status, GET_TID(rpl)); + + return CPL_RET_BUF_DONE; +} + static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb) { struct cpl_act_open_rpl *rpl = cplhdr(skb); @@ -1004,7 +1014,7 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) if (!is_offloading(olddev)) return; if (!is_offloading(newdev)) { - printk(KERN_WARNING "%s: Redirect to non-offload" + printk(KERN_WARNING "%s: Redirect to non-offload " "device ignored.\n", __FUNCTION__); return; } @@ -1257,6 +1267,7 @@ void __init cxgb3_offload_init(void) t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl); t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl); + t3_register_cpl_handler(CPL_RTE_WRITE_RPL, do_rte_write_rpl); t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl); t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl); t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr); diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h index 6a835f6a262a..b75ddd8777fe 100644 --- a/drivers/net/cxgb3/firmware_exports.h +++ b/drivers/net/cxgb3/firmware_exports.h @@ -76,14 +76,14 @@ #define FW_WROPCODE_MNGT 0x1D #define FW_MNGTOPCODE_PKTSCHED_SET 0x00 -/* Maximum size of a WR sent from the host, limited by the SGE. +/* Maximum size of a WR sent from the host, limited by the SGE. * - * Note: WR coming from ULP or TP are only limited by CIM. + * Note: WR coming from ULP or TP are only limited by CIM. */ #define FW_WR_SIZE 128 /* Maximum number of outstanding WRs sent from the host. Value must be - * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by + * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by * offload modules to limit the number of WRs per connection. */ #define FW_T3_WR_NUM 16 @@ -99,7 +99,7 @@ * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START. * - * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent + * Ingress Traffic (e.g. DMA completion credit) for TUNNEL Queue[i] is sent * to RESP Queue[i]. */ #define FW_TUNNEL_NUM 8 @@ -116,10 +116,10 @@ #define FW_CTRL_SGEEC_START 65528 #define FW_CTRL_TID_START 65536 -/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These - * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. - * - * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for +/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These + * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. + * + * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for * OFFLOAD Queues, as the host is responsible for providing the correct TID in * every WR. * @@ -129,14 +129,14 @@ #define FW_OFLD_SGEEC_START 0 /* - * + * */ #define FW_RI_NUM 1 #define FW_RI_SGEEC_START 65527 #define FW_RI_TID_START 65552 /* - * The RX_PKT_TID + * The RX_PKT_TID */ #define FW_RX_PKT_NUM 1 #define FW_RX_PKT_TID_START 65553 diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index d660af74606e..17ed4c3527b7 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -337,7 +337,7 @@ struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh, atomic_set(&e->refcnt, 1); neigh_replace(e, neigh); if (neigh->dev->priv_flags & IFF_802_1Q_VLAN) - e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id; + e->vlan = vlan_dev_info(neigh->dev)->vlan_id; else e->vlan = VLAN_NONE; spin_unlock(&e->lock); diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h index 6e12bf4bc6cf..02dbbb300929 100644 --- a/drivers/net/cxgb3/regs.h +++ b/drivers/net/cxgb3/regs.h @@ -1,5 +1,17 @@ #define A_SG_CONTROL 0x0 +#define S_CONGMODE 29 +#define V_CONGMODE(x) ((x) << S_CONGMODE) +#define F_CONGMODE V_CONGMODE(1U) + +#define S_TNLFLMODE 28 +#define V_TNLFLMODE(x) ((x) << S_TNLFLMODE) +#define F_TNLFLMODE V_TNLFLMODE(1U) + +#define S_FATLPERREN 27 +#define V_FATLPERREN(x) ((x) << S_FATLPERREN) +#define F_FATLPERREN V_FATLPERREN(1U) + #define S_DROPPKT 20 #define V_DROPPKT(x) ((x) << S_DROPPKT) #define F_DROPPKT V_DROPPKT(1U) @@ -172,6 +184,64 @@ #define A_SG_INT_CAUSE 0x5c +#define S_HIRCQPARITYERROR 31 +#define V_HIRCQPARITYERROR(x) ((x) << S_HIRCQPARITYERROR) +#define F_HIRCQPARITYERROR V_HIRCQPARITYERROR(1U) + +#define S_LORCQPARITYERROR 30 +#define V_LORCQPARITYERROR(x) ((x) << S_LORCQPARITYERROR) +#define F_LORCQPARITYERROR V_LORCQPARITYERROR(1U) + +#define S_HIDRBPARITYERROR 29 +#define V_HIDRBPARITYERROR(x) ((x) << S_HIDRBPARITYERROR) +#define F_HIDRBPARITYERROR V_HIDRBPARITYERROR(1U) + +#define S_LODRBPARITYERROR 28 +#define V_LODRBPARITYERROR(x) ((x) << S_LODRBPARITYERROR) +#define F_LODRBPARITYERROR V_LODRBPARITYERROR(1U) + +#define S_FLPARITYERROR 22 +#define M_FLPARITYERROR 0x3f +#define V_FLPARITYERROR(x) ((x) << S_FLPARITYERROR) +#define G_FLPARITYERROR(x) (((x) >> S_FLPARITYERROR) & M_FLPARITYERROR) + +#define S_ITPARITYERROR 20 +#define M_ITPARITYERROR 0x3 +#define V_ITPARITYERROR(x) ((x) << S_ITPARITYERROR) +#define G_ITPARITYERROR(x) (((x) >> S_ITPARITYERROR) & M_ITPARITYERROR) + +#define S_IRPARITYERROR 19 +#define V_IRPARITYERROR(x) ((x) << S_IRPARITYERROR) +#define F_IRPARITYERROR V_IRPARITYERROR(1U) + +#define S_RCPARITYERROR 18 +#define V_RCPARITYERROR(x) ((x) << S_RCPARITYERROR) +#define F_RCPARITYERROR V_RCPARITYERROR(1U) + +#define S_OCPARITYERROR 17 +#define V_OCPARITYERROR(x) ((x) << S_OCPARITYERROR) +#define F_OCPARITYERROR V_OCPARITYERROR(1U) + +#define S_CPPARITYERROR 16 +#define V_CPPARITYERROR(x) ((x) << S_CPPARITYERROR) +#define F_CPPARITYERROR V_CPPARITYERROR(1U) + +#define S_R_REQ_FRAMINGERROR 15 +#define V_R_REQ_FRAMINGERROR(x) ((x) << S_R_REQ_FRAMINGERROR) +#define F_R_REQ_FRAMINGERROR V_R_REQ_FRAMINGERROR(1U) + +#define S_UC_REQ_FRAMINGERROR 14 +#define V_UC_REQ_FRAMINGERROR(x) ((x) << S_UC_REQ_FRAMINGERROR) +#define F_UC_REQ_FRAMINGERROR V_UC_REQ_FRAMINGERROR(1U) + +#define S_HICTLDRBDROPERR 13 +#define V_HICTLDRBDROPERR(x) ((x) << S_HICTLDRBDROPERR) +#define F_HICTLDRBDROPERR V_HICTLDRBDROPERR(1U) + +#define S_LOCTLDRBDROPERR 12 +#define V_LOCTLDRBDROPERR(x) ((x) << S_LOCTLDRBDROPERR) +#define F_LOCTLDRBDROPERR V_LOCTLDRBDROPERR(1U) + #define S_HIPIODRBDROPERR 11 #define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR) #define F_HIPIODRBDROPERR V_HIPIODRBDROPERR(1U) @@ -286,6 +356,10 @@ #define A_PCIX_CFG 0x88 +#define S_DMASTOPEN 19 +#define V_DMASTOPEN(x) ((x) << S_DMASTOPEN) +#define F_DMASTOPEN V_DMASTOPEN(1U) + #define S_CLIDECEN 18 #define V_CLIDECEN(x) ((x) << S_CLIDECEN) #define F_CLIDECEN V_CLIDECEN(1U) @@ -313,6 +387,22 @@ #define V_BISTERR(x) ((x) << S_BISTERR) +#define S_TXPARERR 18 +#define V_TXPARERR(x) ((x) << S_TXPARERR) +#define F_TXPARERR V_TXPARERR(1U) + +#define S_RXPARERR 17 +#define V_RXPARERR(x) ((x) << S_RXPARERR) +#define F_RXPARERR V_RXPARERR(1U) + +#define S_RETRYLUTPARERR 16 +#define V_RETRYLUTPARERR(x) ((x) << S_RETRYLUTPARERR) +#define F_RETRYLUTPARERR V_RETRYLUTPARERR(1U) + +#define S_RETRYBUFPARERR 15 +#define V_RETRYBUFPARERR(x) ((x) << S_RETRYBUFPARERR) +#define F_RETRYBUFPARERR V_RETRYBUFPARERR(1U) + #define S_PCIE_MSIXPARERR 12 #define M_PCIE_MSIXPARERR 0x7 @@ -348,6 +438,10 @@ #define A_PCIE_INT_CAUSE 0x84 +#define S_PCIE_DMASTOPEN 24 +#define V_PCIE_DMASTOPEN(x) ((x) << S_PCIE_DMASTOPEN) +#define F_PCIE_DMASTOPEN V_PCIE_DMASTOPEN(1U) + #define A_PCIE_CFG 0x88 #define S_PCIE_CLIDECEN 16 @@ -741,6 +835,54 @@ #define A_CIM_HOST_INT_ENABLE 0x298 +#define S_DTAGPARERR 28 +#define V_DTAGPARERR(x) ((x) << S_DTAGPARERR) +#define F_DTAGPARERR V_DTAGPARERR(1U) + +#define S_ITAGPARERR 27 +#define V_ITAGPARERR(x) ((x) << S_ITAGPARERR) +#define F_ITAGPARERR V_ITAGPARERR(1U) + +#define S_IBQTPPARERR 26 +#define V_IBQTPPARERR(x) ((x) << S_IBQTPPARERR) +#define F_IBQTPPARERR V_IBQTPPARERR(1U) + +#define S_IBQULPPARERR 25 +#define V_IBQULPPARERR(x) ((x) << S_IBQULPPARERR) +#define F_IBQULPPARERR V_IBQULPPARERR(1U) + +#define S_IBQSGEHIPARERR 24 +#define V_IBQSGEHIPARERR(x) ((x) << S_IBQSGEHIPARERR) +#define F_IBQSGEHIPARERR V_IBQSGEHIPARERR(1U) + +#define S_IBQSGELOPARERR 23 +#define V_IBQSGELOPARERR(x) ((x) << S_IBQSGELOPARERR) +#define F_IBQSGELOPARERR V_IBQSGELOPARERR(1U) + +#define S_OBQULPLOPARERR 22 +#define V_OBQULPLOPARERR(x) ((x) << S_OBQULPLOPARERR) +#define F_OBQULPLOPARERR V_OBQULPLOPARERR(1U) + +#define S_OBQULPHIPARERR 21 +#define V_OBQULPHIPARERR(x) ((x) << S_OBQULPHIPARERR) +#define F_OBQULPHIPARERR V_OBQULPHIPARERR(1U) + +#define S_OBQSGEPARERR 20 +#define V_OBQSGEPARERR(x) ((x) << S_OBQSGEPARERR) +#define F_OBQSGEPARERR V_OBQSGEPARERR(1U) + +#define S_DCACHEPARERR 19 +#define V_DCACHEPARERR(x) ((x) << S_DCACHEPARERR) +#define F_DCACHEPARERR V_DCACHEPARERR(1U) + +#define S_ICACHEPARERR 18 +#define V_ICACHEPARERR(x) ((x) << S_ICACHEPARERR) +#define F_ICACHEPARERR V_ICACHEPARERR(1U) + +#define S_DRAMPARERR 17 +#define V_DRAMPARERR(x) ((x) << S_DRAMPARERR) +#define F_DRAMPARERR V_DRAMPARERR(1U) + #define A_CIM_HOST_INT_CAUSE 0x29c #define S_BLKWRPLINT 12 @@ -799,8 +941,42 @@ #define A_CIM_HOST_ACC_DATA 0x2b4 +#define A_CIM_IBQ_DBG_CFG 0x2c0 + +#define S_IBQDBGADDR 16 +#define M_IBQDBGADDR 0x1ff +#define V_IBQDBGADDR(x) ((x) << S_IBQDBGADDR) +#define G_IBQDBGADDR(x) (((x) >> S_IBQDBGADDR) & M_IBQDBGADDR) + +#define S_IBQDBGQID 3 +#define M_IBQDBGQID 0x3 +#define V_IBQDBGQID(x) ((x) << S_IBQDBGQID) +#define G_IBQDBGQID(x) (((x) >> S_IBQDBGQID) & M_IBQDBGQID) + +#define S_IBQDBGWR 2 +#define V_IBQDBGWR(x) ((x) << S_IBQDBGWR) +#define F_IBQDBGWR V_IBQDBGWR(1U) + +#define S_IBQDBGBUSY 1 +#define V_IBQDBGBUSY(x) ((x) << S_IBQDBGBUSY) +#define F_IBQDBGBUSY V_IBQDBGBUSY(1U) + +#define S_IBQDBGEN 0 +#define V_IBQDBGEN(x) ((x) << S_IBQDBGEN) +#define F_IBQDBGEN V_IBQDBGEN(1U) + +#define A_CIM_IBQ_DBG_DATA 0x2c8 + #define A_TP_IN_CONFIG 0x300 +#define S_RXFBARBPRIO 25 +#define V_RXFBARBPRIO(x) ((x) << S_RXFBARBPRIO) +#define F_RXFBARBPRIO V_RXFBARBPRIO(1U) + +#define S_TXFBARBPRIO 24 +#define V_TXFBARBPRIO(x) ((x) << S_TXFBARBPRIO) +#define F_TXFBARBPRIO V_TXFBARBPRIO(1U) + #define S_NICMODE 14 #define V_NICMODE(x) ((x) << S_NICMODE) #define F_NICMODE V_NICMODE(1U) @@ -965,8 +1141,30 @@ #define V_LOCKTID(x) ((x) << S_LOCKTID) #define F_LOCKTID V_LOCKTID(1U) +#define S_TABLELATENCYDELTA 0 +#define M_TABLELATENCYDELTA 0xf +#define V_TABLELATENCYDELTA(x) ((x) << S_TABLELATENCYDELTA) +#define G_TABLELATENCYDELTA(x) \ + (((x) >> S_TABLELATENCYDELTA) & M_TABLELATENCYDELTA) + #define A_TP_PC_CONFIG2 0x34c +#define S_DISBLEDAPARBIT0 15 +#define V_DISBLEDAPARBIT0(x) ((x) << S_DISBLEDAPARBIT0) +#define F_DISBLEDAPARBIT0 V_DISBLEDAPARBIT0(1U) + +#define S_ENABLEARPMISS 13 +#define V_ENABLEARPMISS(x) ((x) << S_ENABLEARPMISS) +#define F_ENABLEARPMISS V_ENABLEARPMISS(1U) + +#define S_ENABLENONOFDTNLSYN 12 +#define V_ENABLENONOFDTNLSYN(x) ((x) << S_ENABLENONOFDTNLSYN) +#define F_ENABLENONOFDTNLSYN V_ENABLENONOFDTNLSYN(1U) + +#define S_ENABLEIPV6RSS 11 +#define V_ENABLEIPV6RSS(x) ((x) << S_ENABLEIPV6RSS) +#define F_ENABLEIPV6RSS V_ENABLEIPV6RSS(1U) + #define S_CHDRAFULL 4 #define V_CHDRAFULL(x) ((x) << S_CHDRAFULL) #define F_CHDRAFULL V_CHDRAFULL(1U) @@ -1018,6 +1216,12 @@ #define A_TP_PARA_REG4 0x370 +#define A_TP_PARA_REG5 0x374 + +#define S_RXDDPOFFINIT 3 +#define V_RXDDPOFFINIT(x) ((x) << S_RXDDPOFFINIT) +#define F_RXDDPOFFINIT V_RXDDPOFFINIT(1U) + #define A_TP_PARA_REG6 0x378 #define S_T3A_ENABLEESND 13 @@ -1138,6 +1342,10 @@ #define V_TNLLKPEN(x) ((x) << S_TNLLKPEN) #define F_TNLLKPEN V_TNLLKPEN(1U) +#define S_RRCPLMAPEN 7 +#define V_RRCPLMAPEN(x) ((x) << S_RRCPLMAPEN) +#define F_RRCPLMAPEN V_RRCPLMAPEN(1U) + #define S_RRCPLCPUSIZE 4 #define M_RRCPLCPUSIZE 0x7 #define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE) @@ -1146,6 +1354,10 @@ #define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE) #define F_RQFEEDBACKENABLE V_RQFEEDBACKENABLE(1U) +#define S_HASHTOEPLITZ 2 +#define V_HASHTOEPLITZ(x) ((x) << S_HASHTOEPLITZ) +#define F_HASHTOEPLITZ V_HASHTOEPLITZ(1U) + #define S_DISABLE 0 #define A_TP_TM_PIO_ADDR 0x418 @@ -1198,6 +1410,22 @@ #define A_TP_INT_ENABLE 0x470 +#define S_FLMTXFLSTEMPTY 30 +#define V_FLMTXFLSTEMPTY(x) ((x) << S_FLMTXFLSTEMPTY) +#define F_FLMTXFLSTEMPTY V_FLMTXFLSTEMPTY(1U) + +#define S_FLMRXFLSTEMPTY 29 +#define V_FLMRXFLSTEMPTY(x) ((x) << S_FLMRXFLSTEMPTY) +#define F_FLMRXFLSTEMPTY V_FLMRXFLSTEMPTY(1U) + +#define S_ARPLUTPERR 26 +#define V_ARPLUTPERR(x) ((x) << S_ARPLUTPERR) +#define F_ARPLUTPERR V_ARPLUTPERR(1U) + +#define S_CMCACHEPERR 24 +#define V_CMCACHEPERR(x) ((x) << S_CMCACHEPERR) +#define F_CMCACHEPERR V_CMCACHEPERR(1U) + #define A_TP_INT_CAUSE 0x474 #define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8 @@ -1241,9 +1469,37 @@ #define A_ULPRX_INT_ENABLE 0x504 -#define S_PARERR 0 -#define V_PARERR(x) ((x) << S_PARERR) -#define F_PARERR V_PARERR(1U) +#define S_DATASELFRAMEERR0 7 +#define V_DATASELFRAMEERR0(x) ((x) << S_DATASELFRAMEERR0) +#define F_DATASELFRAMEERR0 V_DATASELFRAMEERR0(1U) + +#define S_DATASELFRAMEERR1 6 +#define V_DATASELFRAMEERR1(x) ((x) << S_DATASELFRAMEERR1) +#define F_DATASELFRAMEERR1 V_DATASELFRAMEERR1(1U) + +#define S_PCMDMUXPERR 5 +#define V_PCMDMUXPERR(x) ((x) << S_PCMDMUXPERR) +#define F_PCMDMUXPERR V_PCMDMUXPERR(1U) + +#define S_ARBFPERR 4 +#define V_ARBFPERR(x) ((x) << S_ARBFPERR) +#define F_ARBFPERR V_ARBFPERR(1U) + +#define S_ARBPF0PERR 3 +#define V_ARBPF0PERR(x) ((x) << S_ARBPF0PERR) +#define F_ARBPF0PERR V_ARBPF0PERR(1U) + +#define S_ARBPF1PERR 2 +#define V_ARBPF1PERR(x) ((x) << S_ARBPF1PERR) +#define F_ARBPF1PERR V_ARBPF1PERR(1U) + +#define S_PARERRPCMD 1 +#define V_PARERRPCMD(x) ((x) << S_PARERRPCMD) +#define F_PARERRPCMD V_PARERRPCMD(1U) + +#define S_PARERRDATA 0 +#define V_PARERRDATA(x) ((x) << S_PARERRDATA) +#define F_PARERRDATA V_PARERRDATA(1U) #define A_ULPRX_INT_CAUSE 0x508 @@ -1291,6 +1547,10 @@ #define A_ULPTX_CONFIG 0x580 +#define S_CFG_CQE_SOP_MASK 1 +#define V_CFG_CQE_SOP_MASK(x) ((x) << S_CFG_CQE_SOP_MASK) +#define F_CFG_CQE_SOP_MASK V_CFG_CQE_SOP_MASK(1U) + #define S_CFG_RR_ARB 0 #define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB) #define F_CFG_RR_ARB V_CFG_RR_ARB(1U) @@ -1537,6 +1797,10 @@ #define A_CPL_INTR_ENABLE 0x650 +#define S_CIM_OP_MAP_PERR 5 +#define V_CIM_OP_MAP_PERR(x) ((x) << S_CIM_OP_MAP_PERR) +#define F_CIM_OP_MAP_PERR V_CIM_OP_MAP_PERR(1U) + #define S_CIM_OVFL_ERROR 4 #define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR) #define F_CIM_OVFL_ERROR V_CIM_OVFL_ERROR(1U) diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index c15e43a8543b..cb684d30831f 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -91,6 +91,10 @@ struct rx_desc { struct tx_sw_desc { /* SW state per Tx descriptor */ struct sk_buff *skb; + u8 eop; /* set if last descriptor for packet */ + u8 addr_idx; /* buffer index of first SGL entry in descriptor */ + u8 fragidx; /* first page fragment associated with descriptor */ + s8 sflit; /* start flit of first SGL entry in descriptor */ }; struct rx_sw_desc { /* SW state per Rx descriptor */ @@ -109,13 +113,6 @@ struct rsp_desc { /* response queue descriptor */ u8 intr_gen; }; -struct unmap_info { /* packet unmapping info, overlays skb->cb */ - int sflit; /* start flit of first SGL entry in Tx descriptor */ - u16 fragidx; /* first page fragment in current Tx descriptor */ - u16 addr_idx; /* buffer index of first SGL entry in descriptor */ - u32 len; /* mapped length of skb main body */ -}; - /* * Holds unmapping information for Tx packets that need deferred unmapping. * This structure lives at skb->head and must be allocated by callers. @@ -177,6 +174,7 @@ static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx) static inline void refill_rspq(struct adapter *adapter, const struct sge_rspq *q, unsigned int credits) { + rmb(); t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN, V_RSPQ(q->cntxt_id) | V_CREDITS(credits)); } @@ -209,32 +207,36 @@ static inline int need_skb_unmap(void) * * Unmap the main body of an sk_buff and its page fragments, if any. * Because of the fairly complicated structure of our SGLs and the desire - * to conserve space for metadata, we keep the information necessary to - * unmap an sk_buff partly in the sk_buff itself (in its cb), and partly - * in the Tx descriptors (the physical addresses of the various data - * buffers). The send functions initialize the state in skb->cb so we - * can unmap the buffers held in the first Tx descriptor here, and we - * have enough information at this point to update the state for the next - * Tx descriptor. + * to conserve space for metadata, the information necessary to unmap an + * sk_buff is spread across the sk_buff itself (buffer lengths), the HW Tx + * descriptors (the physical addresses of the various data buffers), and + * the SW descriptor state (assorted indices). The send functions + * initialize the indices for the first packet descriptor so we can unmap + * the buffers held in the first Tx descriptor here, and we have enough + * information at this point to set the state for the next Tx descriptor. + * + * Note that it is possible to clean up the first descriptor of a packet + * before the send routines have written the next descriptors, but this + * race does not cause any problem. We just end up writing the unmapping + * info for the descriptor first. */ static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, unsigned int cidx, struct pci_dev *pdev) { const struct sg_ent *sgp; - struct unmap_info *ui = (struct unmap_info *)skb->cb; - int nfrags, frag_idx, curflit, j = ui->addr_idx; + struct tx_sw_desc *d = &q->sdesc[cidx]; + int nfrags, frag_idx, curflit, j = d->addr_idx; - sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit]; + sgp = (struct sg_ent *)&q->desc[cidx].flit[d->sflit]; + frag_idx = d->fragidx; - if (ui->len) { - pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len, - PCI_DMA_TODEVICE); - ui->len = 0; /* so we know for next descriptor for this skb */ + if (frag_idx == 0 && skb_headlen(skb)) { + pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), + skb_headlen(skb), PCI_DMA_TODEVICE); j = 1; } - frag_idx = ui->fragidx; - curflit = ui->sflit + 1 + j; + curflit = d->sflit + 1 + j; nfrags = skb_shinfo(skb)->nr_frags; while (frag_idx < nfrags && curflit < WR_FLITS) { @@ -250,10 +252,11 @@ static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q, frag_idx++; } - if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ - ui->fragidx = frag_idx; - ui->addr_idx = j; - ui->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ + if (frag_idx < nfrags) { /* SGL continues into next Tx descriptor */ + d = cidx + 1 == q->size ? q->sdesc : d + 1; + d->fragidx = frag_idx; + d->addr_idx = j; + d->sflit = curflit - WR_FLITS - j; /* sflit can be -1 */ } } @@ -281,7 +284,7 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, if (d->skb) { /* an SGL is present */ if (need_unmap) unmap_skb(d->skb, q, cidx, pdev); - if (d->skb->priority == cidx) + if (d->eop) kfree_skb(d->skb); } ++d; @@ -456,7 +459,7 @@ nomem: q->alloc_failed++; } q->credits++; } - + wmb(); t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id)); } @@ -912,15 +915,13 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, sd->skb = skb; if (need_skb_unmap()) { - struct unmap_info *ui = (struct unmap_info *)skb->cb; - - ui->fragidx = 0; - ui->addr_idx = 0; - ui->sflit = flits; + sd->fragidx = 0; + sd->addr_idx = 0; + sd->sflit = flits; } if (likely(ndesc == 1)) { - skb->priority = pidx; + sd->eop = 1; wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) | V_WR_SGLSFLT(flits)) | wr_hi; wmb(); @@ -948,6 +949,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, fp += avail; d++; + sd->eop = 0; sd++; if (++pidx == q->size) { pidx = 0; @@ -966,7 +968,7 @@ static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb, wr_gen2(d, gen); flits = 1; } - skb->priority = pidx; + sd->eop = 1; wrp->wr_hi |= htonl(F_WR_EOP); wmb(); wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo; @@ -1051,8 +1053,6 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); - if (need_skb_unmap()) - ((struct unmap_info *)skb->cb)->len = skb_headlen(skb); write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), @@ -1354,6 +1354,7 @@ static void restart_ctrlq(unsigned long data) } spin_unlock(&q->lock); + wmb(); t3_write_reg(qs->adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); } @@ -1363,7 +1364,12 @@ static void restart_ctrlq(unsigned long data) */ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) { - return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); + int ret; + local_bh_disable(); + ret = ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb); + local_bh_enable(); + + return ret; } /** @@ -1380,13 +1386,14 @@ static void deferred_unmap_destructor(struct sk_buff *skb) const dma_addr_t *p; const struct skb_shared_info *si; const struct deferred_unmap_info *dui; - const struct unmap_info *ui = (struct unmap_info *)skb->cb; dui = (struct deferred_unmap_info *)skb->head; p = dui->addr; - if (ui->len) - pci_unmap_single(dui->pdev, *p++, ui->len, PCI_DMA_TODEVICE); + if (skb->tail - skb->transport_header) + pci_unmap_single(dui->pdev, *p++, + skb->tail - skb->transport_header, + PCI_DMA_TODEVICE); si = skb_shinfo(skb); for (i = 0; i < si->nr_frags; i++) @@ -1451,8 +1458,6 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, if (need_skb_unmap()) { setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); skb->destructor = deferred_unmap_destructor; - ((struct unmap_info *)skb->cb)->len = (skb->tail - - skb->transport_header); } write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, @@ -1574,6 +1579,7 @@ static void restart_offloadq(unsigned long data) set_bit(TXQ_RUNNING, &q->flags); set_bit(TXQ_LAST_PKT_DB, &q->flags); #endif + wmb(); t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); } @@ -1739,7 +1745,6 @@ static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq, struct sk_buff *skb, struct sk_buff *rx_gather[], unsigned int gather_idx) { - rq->offload_pkts++; skb_reset_mac_header(skb); skb_reset_network_header(skb); skb_reset_transport_header(skb); @@ -1809,7 +1814,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb->protocol = eth_type_trans(skb, adap->port[p->iff]); skb->dev->last_rx = jiffies; pi = netdev_priv(skb->dev); - if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff && + if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -1956,7 +1961,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, int eth, ethpad = 2; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); - u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val; + __be32 rss_hi = *(const __be32 *)r, rss_lo = r->rss_hdr.rss_hash_val; eth = r->rss_hdr.opcode == CPL_RX_PKT; @@ -2033,6 +2038,7 @@ no_mem: if (eth) rx_eth(adap, q, skb, ethpad); else { + q->offload_pkts++; /* Preserve the RSS info in csum & priority */ skb->csum = rss_hi; skb->priority = rss_lo; @@ -2442,6 +2448,15 @@ irq_handler_t t3_intr_handler(struct adapter *adap, int polling) return t3_intr; } +#define SGE_PARERR (F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ + F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ + V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ + F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ + F_HIRCQPARITYERROR) +#define SGE_FRAMINGERR (F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR) +#define SGE_FATALERR (SGE_PARERR | SGE_FRAMINGERR | F_RSPQCREDITOVERFOW | \ + F_RSPQDISABLED) + /** * t3_sge_err_intr_handler - SGE async event interrupt handler * @adapter: the adapter @@ -2452,6 +2467,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter) { unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE); + if (status & SGE_PARERR) + CH_ALERT(adapter, "SGE parity error (0x%x)\n", + status & SGE_PARERR); + if (status & SGE_FRAMINGERR) + CH_ALERT(adapter, "SGE framing error (0x%x)\n", + status & SGE_FRAMINGERR); + if (status & F_RSPQCREDITOVERFOW) CH_ALERT(adapter, "SGE response queue credit overflow\n"); @@ -2468,7 +2490,7 @@ void t3_sge_err_intr_handler(struct adapter *adapter) status & F_HIPIODRBDROPERR ? "high" : "lo"); t3_write_reg(adapter, A_SG_INT_CAUSE, status); - if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED)) + if (status & SGE_FATALERR) t3_fatal_err(adapter); } @@ -2780,7 +2802,7 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p) unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12); ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL | - F_CQCRDTCTRL | + F_CQCRDTCTRL | F_CONGMODE | F_TNLFLMODE | F_FATLPERREN | V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS | V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING; #if SGE_NUM_GENBITS == 1 @@ -2789,7 +2811,6 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p) if (adap->params.rev > 0) { if (!(adap->flags & (USING_MSIX | USING_MSI))) ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ; - ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL; } t3_write_reg(adap, A_SG_CONTROL, ctrl); t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) | @@ -2797,7 +2818,8 @@ void t3_sge_init(struct adapter *adap, struct sge_params *p) t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10); t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) | V_TIMEOUT(200 * core_ticks_per_usec(adap))); - t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000); + t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, + adap->params.rev < T3_REV_C ? 1000 : 500); t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256); t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000); t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256); diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 522834c42ae7..7469935877bd 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -62,7 +62,7 @@ int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask, return 0; } if (--attempts == 0) - return -EAGAIN; + return -EAGAIN; if (delay) udelay(delay); } @@ -537,10 +537,11 @@ struct t3_vpd { * addres is written to the control register. The hardware device will * set the flag to 1 when 4 bytes have been read into the data register. */ -int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) +int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data) { u16 val; int attempts = EEPROM_MAX_POLL; + u32 v; unsigned int base = adapter->params.pci.vpd_cap_addr; if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3)) @@ -556,8 +557,8 @@ int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr); return -EIO; } - pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data); - *data = le32_to_cpu(*data); + pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v); + *data = cpu_to_le32(v); return 0; } @@ -570,7 +571,7 @@ int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data) * Write a 32-bit word to a location in VPD EEPROM using the card's PCI * VPD ROM capability. */ -int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data) +int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data) { u16 val; int attempts = EEPROM_MAX_POLL; @@ -580,7 +581,7 @@ int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data) return -EINVAL; pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA, - cpu_to_le32(data)); + le32_to_cpu(data)); pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR, addr | PCI_VPD_ADDR_F); do { @@ -631,14 +632,14 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p) * Card information is normally at VPD_BASE but some early cards had * it at 0. */ - ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd); + ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd); if (ret) return ret; addr = vpd.id_tag == 0x82 ? VPD_BASE : 0; for (i = 0; i < sizeof(vpd); i += 4) { ret = t3_seeprom_read(adapter, addr + i, - (u32 *)((u8 *)&vpd + i)); + (__le32 *)((u8 *)&vpd + i)); if (ret) return ret; } @@ -865,7 +866,7 @@ int t3_get_tp_version(struct adapter *adapter, u32 *vers) 1, 1, 5, 1); if (ret) return ret; - + *vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1); return 0; @@ -896,7 +897,7 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load) major = G_TP_VERSION_MAJOR(vers); minor = G_TP_VERSION_MINOR(vers); - if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) + if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) return 0; if (major != TP_VERSION_MAJOR) @@ -913,7 +914,7 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load) } /** - * t3_check_tpsram - check if provided protocol SRAM + * t3_check_tpsram - check if provided protocol SRAM * is compatible with this driver * @adapter: the adapter * @tp_sram: the firmware image to write @@ -926,7 +927,7 @@ int t3_check_tpsram(struct adapter *adapter, u8 *tp_sram, unsigned int size) { u32 csum; unsigned int i; - const u32 *p = (const u32 *)tp_sram; + const __be32 *p = (const __be32 *)tp_sram; /* Verify checksum */ for (csum = 0, i = 0; i < size / sizeof(csum); i++) @@ -988,13 +989,17 @@ int t3_check_fw_version(struct adapter *adapter, int *must_load) CH_ERR(adapter, "found wrong FW version(%u.%u), " "driver needs version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); - else { + else if (minor < FW_VERSION_MINOR) { *must_load = 0; - CH_WARN(adapter, "found wrong FW minor version(%u.%u), " + CH_WARN(adapter, "found old FW minor version(%u.%u), " "driver compiled for version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); + } else { + CH_WARN(adapter, "found newer FW version(%u.%u), " + "driver compiled for version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); + return 0; } - return -EINVAL; } @@ -1036,7 +1041,7 @@ int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size) { u32 csum; unsigned int i; - const u32 *p = (const u32 *)fw_data; + const __be32 *p = (const __be32 *)fw_data; int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16; if ((size & 3) || size < FW_MIN_SIZE) @@ -1259,7 +1264,13 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, return fatal; } -#define SGE_INTR_MASK (F_RSPQDISABLED) +#define SGE_INTR_MASK (F_RSPQDISABLED | \ + F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \ + F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \ + F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \ + V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \ + F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \ + F_HIRCQPARITYERROR) #define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \ F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \ F_NFASRCHFAIL) @@ -1276,16 +1287,23 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg, #define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\ F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \ /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \ - V_BISTERR(M_BISTERR) | F_PEXERR) -#define ULPRX_INTR_MASK F_PARERR -#define ULPTX_INTR_MASK 0 -#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \ + F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \ + F_TXPARERR | V_BISTERR(M_BISTERR)) +#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \ + F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \ + F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0) +#define ULPTX_INTR_MASK 0xfc +#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \ F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \ F_ZERO_SWITCH_ERROR) #define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \ F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \ F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \ - F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT) + F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \ + F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \ + F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \ + F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \ + F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR) #define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR)) @@ -1354,6 +1372,10 @@ static void pcie_intr_handler(struct adapter *adapter) {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1}, {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR), "PCI MSI-X table/PBA parity error", -1, 1}, + {F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1}, + {F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1}, + {F_RXPARERR, "PCI Rx parity error", -1, 1}, + {F_TXPARERR, "PCI Tx parity error", -1, 1}, {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1}, {0} }; @@ -1379,8 +1401,16 @@ static void tp_intr_handler(struct adapter *adapter) {0} }; + static struct intr_info tp_intr_info_t3c[] = { + {0x1fffffff, "TP parity error", -1, 1}, + {F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1}, + {F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1}, + {0} + }; + if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff, - tp_intr_info, NULL)) + adapter->params.rev < T3_REV_C ? + tp_intr_info : tp_intr_info_t3c, NULL)) t3_fatal_err(adapter); } @@ -1402,6 +1432,18 @@ static void cim_intr_handler(struct adapter *adapter) {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1}, {F_BLKRDPLINT, "CIM block read from PL space", -1, 1}, {F_BLKWRPLINT, "CIM block write to PL space", -1, 1}, + {F_DRAMPARERR, "CIM DRAM parity error", -1, 1}, + {F_ICACHEPARERR, "CIM icache parity error", -1, 1}, + {F_DCACHEPARERR, "CIM dcache parity error", -1, 1}, + {F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1}, + {F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1}, + {F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1}, + {F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1}, + {F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1}, + {F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1}, + {F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1}, + {F_ITAGPARERR, "CIM itag parity error", -1, 1}, + {F_DTAGPARERR, "CIM dtag parity error", -1, 1}, {0} }; @@ -1416,7 +1458,14 @@ static void cim_intr_handler(struct adapter *adapter) static void ulprx_intr_handler(struct adapter *adapter) { static const struct intr_info ulprx_intr_info[] = { - {F_PARERR, "ULP RX parity error", -1, 1}, + {F_PARERRDATA, "ULP RX data parity error", -1, 1}, + {F_PARERRPCMD, "ULP RX command parity error", -1, 1}, + {F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1}, + {F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1}, + {F_ARBFPERR, "ULP RX ArbF parity error", -1, 1}, + {F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1}, + {F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1}, + {F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1}, {0} }; @@ -1435,6 +1484,7 @@ static void ulptx_intr_handler(struct adapter *adapter) STAT_ULP_CH0_PBL_OOB, 0}, {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds", STAT_ULP_CH1_PBL_OOB, 0}, + {0xfc, "ULP TX parity error", -1, 1}, {0} }; @@ -1509,7 +1559,8 @@ static void pmrx_intr_handler(struct adapter *adapter) static void cplsw_intr_handler(struct adapter *adapter) { static const struct intr_info cplsw_intr_info[] = { -/* { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */ + {F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1}, + {F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1}, {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1}, {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1}, {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1}, @@ -1730,7 +1781,6 @@ void t3_intr_enable(struct adapter *adapter) MC7_INTR_MASK}, {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK}, {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK}, - {A_TP_INT_ENABLE, 0x3bfffff}, {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK}, {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK}, {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK}, @@ -1740,6 +1790,8 @@ void t3_intr_enable(struct adapter *adapter) adapter->slow_intr_mask = PL_INTR_MASK; t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0); + t3_write_reg(adapter, A_TP_INT_ENABLE, + adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff); if (adapter->params.rev > 0) { t3_write_reg(adapter, A_CPL_INTR_ENABLE, @@ -1894,6 +1946,16 @@ static int t3_sge_write_context(struct adapter *adapter, unsigned int id, 0, SG_CONTEXT_CMD_ATTEMPTS, 1); } +static int clear_sge_ctxt(struct adapter *adap, unsigned int id, + unsigned int type) +{ + t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0); + t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0); + t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0); + t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0); + return t3_sge_write_context(adap, id, type); +} + /** * t3_sge_init_ecntxt - initialize an SGE egress context * @adapter: the adapter to configure @@ -2395,7 +2457,7 @@ static inline unsigned int pm_num_pages(unsigned int mem_size, t3_write_reg((adap), A_ ## reg, (start)); \ start += size -/* +/** * partition_mem - partition memory and configure TP memory settings * @adap: the adapter * @p: the TP parameters @@ -2480,7 +2542,7 @@ static void tp_config(struct adapter *adap, const struct tp_params *p) V_AUTOSTATE2(1) | V_AUTOSTATE1(0) | V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) | F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1)); - t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE, + t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO, F_IPV6ENABLE | F_NICMODE); t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814); t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105); @@ -2492,10 +2554,12 @@ static void tp_config(struct adapter *adap, const struct tp_params *p) F_ENABLEEPCMDAFULL, F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE | F_RXCONGESTIONMODE); - t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0); + t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, + F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN | + F_ENABLEARPMISS | F_DISBLEDAPARBIT0); t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080); t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000); - + if (adap->params.rev > 0) { tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE); t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO, @@ -2505,6 +2569,11 @@ static void tp_config(struct adapter *adap, const struct tp_params *p) } else t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED); + if (adap->params.rev == T3_REV_C) + t3_set_reg_field(adap, A_TP_PC_CONFIG, + V_TABLELATENCYDELTA(M_TABLELATENCYDELTA), + V_TABLELATENCYDELTA(4)); + t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0); t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0); t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0); @@ -2809,15 +2878,15 @@ static void ulp_config(struct adapter *adap, const struct tp_params *p) int t3_set_proto_sram(struct adapter *adap, u8 *data) { int i; - u32 *buf = (u32 *)data; + __be32 *buf = (__be32 *)data; for (i = 0; i < PROTO_SRAM_LINES; i++) { - t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++)); - t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++)); - + t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*buf++)); + t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31); if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1)) return -EIO; @@ -3194,7 +3263,8 @@ static void config_pcie(struct adapter *adap) V_REPLAYLMT(rpllmt)); t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff); - t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN); + t3_set_reg_field(adap, A_PCIE_CFG, 0, + F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN); } /* @@ -3207,7 +3277,7 @@ static void config_pcie(struct adapter *adap) */ int t3_init_hw(struct adapter *adapter, u32 fw_params) { - int err = -EIO, attempts = 100; + int err = -EIO, attempts, i; const struct vpd_params *vpd = &adapter->params.vpd; if (adapter->params.rev > 0) @@ -3225,6 +3295,10 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) adapter->params.mc5.nfilters, adapter->params.mc5.nroutes)) goto out_err; + + for (i = 0; i < 32; i++) + if (clear_sge_ctxt(adapter, i, F_CQ)) + goto out_err; } if (tp_init(adapter, &adapter->params.tp)) @@ -3240,7 +3314,12 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) if (is_pcie(adapter)) config_pcie(adapter); else - t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN); + t3_set_reg_field(adapter, A_PCIX_CFG, 0, + F_DMASTOPEN | F_CLIDECEN); + + if (adapter->params.rev == T3_REV_C) + t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0, + F_CFG_CQE_SOP_MASK); t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff); t3_write_reg(adapter, A_PM1_RX_MODE, 0); @@ -3253,6 +3332,7 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params) V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2)); t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */ + attempts = 100; do { /* wait for uP to initialize */ msleep(20); } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts); @@ -3387,6 +3467,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) t3_write_reg(adapter, A_T3DBG_GPIO_EN, ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL); t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0); + t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff)); if (adapter->params.rev == 0 || !uses_xaui(adapter)) val |= F_ENRGMII; @@ -3403,13 +3484,13 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai) } /* - * Reset the adapter. + * Reset the adapter. * Older PCIe cards lose their config space during reset, PCI-X * ones don't. */ static int t3_reset_adapter(struct adapter *adapter) { - int i, save_and_restore_pcie = + int i, save_and_restore_pcie = adapter->params.rev < T3_REV_B2 && is_pcie(adapter); uint16_t devid = 0; @@ -3436,6 +3517,36 @@ static int t3_reset_adapter(struct adapter *adapter) return 0; } +static int __devinit init_parity(struct adapter *adap) +{ + int i, err, addr; + + if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY) + return -EBUSY; + + for (err = i = 0; !err && i < 16; i++) + err = clear_sge_ctxt(adap, i, F_EGRESS); + for (i = 0xfff0; !err && i <= 0xffff; i++) + err = clear_sge_ctxt(adap, i, F_EGRESS); + for (i = 0; !err && i < SGE_QSETS; i++) + err = clear_sge_ctxt(adap, i, F_RESPONSEQ); + if (err) + return err; + + t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0); + for (i = 0; i < 4; i++) + for (addr = 0; addr <= M_IBQDBGADDR; addr++) { + t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN | + F_IBQDBGWR | V_IBQDBGQID(i) | + V_IBQDBGADDR(addr)); + err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG, + F_IBQDBGBUSY, 0, 2, 1); + if (err) + return err; + } + return 0; +} + /* * Initialize adapter SW state for the various HW modules, set initial values * for some adapter tunables, take PHYs out of reset, and initialize the MDIO @@ -3503,6 +3614,9 @@ int __devinit t3_prep_adapter(struct adapter *adapter, } early_hw_init(adapter, ai); + ret = init_parity(adapter); + if (ret) + return ret; for_each_port(adapter, i) { u8 hw_addr[6]; diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index ef1c6339c806..229303ff6a39 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -38,7 +38,7 @@ #define DRV_VERSION "1.0-ko" /* Firmware version */ -#define FW_VERSION_MAJOR 4 -#define FW_VERSION_MINOR 6 +#define FW_VERSION_MAJOR 5 +#define FW_VERSION_MINOR 0 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c index efcf09a709cf..ffdc0a1892bd 100644 --- a/drivers/net/cxgb3/xgmac.c +++ b/drivers/net/cxgb3/xgmac.c @@ -153,7 +153,7 @@ static int t3b2_mac_reset(struct cmac *mac) unsigned int oft = mac->offset; u32 val; - if (!macidx(mac)) + if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); @@ -187,11 +187,11 @@ static int t3b2_mac_reset(struct cmac *mac) msleep(1); t3b_pcs_reset(mac); } - t3_write_reg(adap, A_XGM_RX_CFG + oft, + t3_write_reg(adap, A_XGM_RX_CFG + oft, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); - if (!macidx(mac)) + if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); else t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); @@ -336,7 +336,7 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu) * Adjust the PAUSE frame watermarks. We always set the LWM, and the * HWM only if flow-control is enabled. */ - hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu, + hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE * 38 / 100); hwm = min(hwm, MAC_RXFIFO_SIZE - 8192); lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4); @@ -449,7 +449,7 @@ int t3_mac_enable(struct cmac *mac, int which) struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; struct mac_stats *s = &mac->stats; - + if (which & MAC_DIRECTION_TX) { t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx); t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401); diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 00e0194bfef0..6b1e77cc069e 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -719,15 +719,15 @@ out: spin_unlock(&lp->lock); } -static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id) +static irqreturn_t lance_dma_merr_int(int irq, void *dev_id) { struct net_device *dev = dev_id; - printk("%s: DMA error\n", dev->name); + printk(KERN_ERR "%s: DMA error\n", dev->name); return IRQ_HANDLED; } -static irqreturn_t lance_interrupt(const int irq, void *dev_id) +static irqreturn_t lance_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct lance_private *lp = netdev_priv(dev); diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 3286d2a0a870..6a20a5491a96 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -66,6 +66,7 @@ #include <linux/dm9000.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/irq.h> #include <asm/delay.h> #include <asm/irq.h> @@ -113,7 +114,7 @@ #define writesl outsl #define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQF_TRIGGER_HIGH) #else -#define DM9000_IRQ_FLAGS IRQF_SHARED +#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQT_RISING) #endif /* diff --git a/drivers/net/e100.c b/drivers/net/e100.c index b87402bc8308..51cf577035be 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -106,6 +106,13 @@ * the RFD, the RFD must be dma_sync'ed to maintain a consistent * view from software and hardware. * + * In order to keep updates to the RFD link field from colliding with + * hardware writes to mark packets complete, we use the feature that + * hardware will not write to a size 0 descriptor and mark the previous + * packet as end-of-list (EL). After updating the link, we remove EL + * and only then restore the size such that hardware may use the + * previous-to-end RFD. + * * Under typical operation, the receive unit (RU) is start once, * and the controller happily fills RFDs as frames arrive. If * replacement RFDs cannot be allocated, or the RU goes non-active, @@ -281,6 +288,7 @@ struct csr { }; enum scb_status { + rus_no_res = 0x08, rus_ready = 0x10, rus_mask = 0x3C, }; @@ -393,12 +401,12 @@ enum cb_command { }; struct rfd { - u16 status; - u16 command; - u32 link; - u32 rbd; - u16 actual_size; - u16 size; + __le16 status; + __le16 command; + __le32 link; + __le32 rbd; + __le16 actual_size; + __le16 size; }; struct rx { @@ -453,19 +461,19 @@ struct config { #define E100_MAX_MULTICAST_ADDRS 64 struct multi { - u16 count; + __le16 count; u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/]; }; /* Important: keep total struct u32-aligned */ #define UCODE_SIZE 134 struct cb { - u16 status; - u16 command; - u32 link; + __le16 status; + __le16 command; + __le32 link; union { u8 iaaddr[ETH_ALEN]; - u32 ucode[UCODE_SIZE]; + __le32 ucode[UCODE_SIZE]; struct config config; struct multi multi; struct { @@ -474,12 +482,12 @@ struct cb { u8 threshold; u8 tbd_count; struct { - u32 buf_addr; - u16 size; + __le32 buf_addr; + __le16 size; u16 eol; } tbd; } tcb; - u32 dump_buffer_addr; + __le32 dump_buffer_addr; } u; struct cb *next, *prev; dma_addr_t dma_addr; @@ -491,15 +499,15 @@ enum loopback { }; struct stats { - u32 tx_good_frames, tx_max_collisions, tx_late_collisions, + __le32 tx_good_frames, tx_max_collisions, tx_late_collisions, tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions, tx_multiple_collisions, tx_total_collisions; - u32 rx_good_frames, rx_crc_errors, rx_alignment_errors, + __le32 rx_good_frames, rx_crc_errors, rx_alignment_errors, rx_resource_errors, rx_overrun_errors, rx_cdt_errors, rx_short_frame_errors; - u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; - u16 xmt_tco_frames, rcv_tco_frames; - u32 complete; + __le32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported; + __le16 xmt_tco_frames, rcv_tco_frames; + __le32 complete; }; struct mem { @@ -544,7 +552,7 @@ struct nic { struct cb *cb_to_use; struct cb *cb_to_send; struct cb *cb_to_clean; - u16 tx_command; + __le16 tx_command; /* End: frequently used values: keep adjacent for cache effect */ enum { @@ -585,7 +593,7 @@ struct nic { u16 leds; u16 eeprom_wc; - u16 eeprom[256]; + __le16 eeprom[256]; spinlock_t mdio_lock; }; @@ -663,7 +671,7 @@ static int e100_self_test(struct nic *nic) return 0; } -static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) +static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, __le16 data) { u32 cmd_addr_data[3]; u8 ctrl; @@ -672,7 +680,7 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) /* Three cmds: write/erase enable, write data, write/erase disable */ cmd_addr_data[0] = op_ewen << (addr_len - 2); cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) | - cpu_to_le16(data); + le16_to_cpu(data); cmd_addr_data[2] = op_ewds << (addr_len - 2); /* Bit-bang cmds to write word to eeprom */ @@ -701,7 +709,7 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) }; /* General technique stolen from the eepro100 driver - very clever */ -static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) +static __le16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) { u32 cmd_addr_data; u16 data = 0; @@ -738,7 +746,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) iowrite8(0, &nic->csr->eeprom_ctrl_lo); e100_write_flush(nic); udelay(4); - return le16_to_cpu(data); + return cpu_to_le16(data); }; /* Load entire EEPROM image into driver cache and validate checksum */ @@ -753,13 +761,12 @@ static int e100_eeprom_load(struct nic *nic) for(addr = 0; addr < nic->eeprom_wc; addr++) { nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr); if(addr < nic->eeprom_wc - 1) - checksum += cpu_to_le16(nic->eeprom[addr]); + checksum += le16_to_cpu(nic->eeprom[addr]); } /* The checksum, stored in the last word, is calculated such that * the sum of words should be 0xBABA */ - checksum = le16_to_cpu(0xBABA - checksum); - if(checksum != nic->eeprom[nic->eeprom_wc - 1]) { + if (cpu_to_le16(0xBABA - checksum) != nic->eeprom[nic->eeprom_wc - 1]) { DPRINTK(PROBE, ERR, "EEPROM corrupted\n"); if (!eeprom_bad_csum_allow) return -EAGAIN; @@ -786,8 +793,8 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) /* The checksum, stored in the last word, is calculated such that * the sum of words should be 0xBABA */ for(addr = 0; addr < nic->eeprom_wc - 1; addr++) - checksum += cpu_to_le16(nic->eeprom[addr]); - nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum); + checksum += le16_to_cpu(nic->eeprom[addr]); + nic->eeprom[nic->eeprom_wc - 1] = cpu_to_le16(0xBABA - checksum); e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1, nic->eeprom[nic->eeprom_wc - 1]); @@ -952,7 +959,7 @@ static void e100_get_defaults(struct nic *nic) ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); /* Template for a freshly allocated RFD */ - nic->blank_rfd.command = cpu_to_le16(cb_el); + nic->blank_rfd.command = 0; nic->blank_rfd.rbd = 0xFFFFFFFF; nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); @@ -1485,15 +1492,15 @@ static void e100_update_stats(struct nic *nic) struct net_device *dev = nic->netdev; struct net_device_stats *ns = &dev->stats; struct stats *s = &nic->mem->stats; - u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : - (nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames : + __le32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause : + (nic->mac < mac_82559_D101M) ? (__le32 *)&s->xmt_tco_frames : &s->complete; /* Device's stats reporting may take several microseconds to * complete, so where always waiting for results of the * previous command. */ - if(*complete == le32_to_cpu(cuc_dump_reset_complete)) { + if(*complete == cpu_to_le32(cuc_dump_reset_complete)) { *complete = 0; nic->tx_frames = le32_to_cpu(s->tx_good_frames); nic->tx_collisions = le32_to_cpu(s->tx_total_collisions); @@ -1783,7 +1790,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data, RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL); - if(pci_dma_mapping_error(rx->dma_addr)) { + if (pci_dma_mapping_error(rx->dma_addr)) { dev_kfree_skb_any(rx->skb); rx->skb = NULL; rx->dma_addr = 0; @@ -1791,15 +1798,11 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) } /* Link the RFD to end of RFA by linking previous RFD to - * this one, and clearing EL bit of previous. */ - if(rx->prev->skb) { + * this one. We are safe to touch the previous RFD because + * it is protected by the before last buffer's el bit being set */ + if (rx->prev->skb) { struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; - put_unaligned(cpu_to_le32(rx->dma_addr), - (u32 *)&prev_rfd->link); - wmb(); - prev_rfd->command &= ~cpu_to_le16(cb_el); - pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, - sizeof(struct rfd), PCI_DMA_TODEVICE); + put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link); } return 0; @@ -1824,8 +1827,19 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); /* If data isn't ready, nothing to indicate */ - if(unlikely(!(rfd_status & cb_complete))) + if (unlikely(!(rfd_status & cb_complete))) { + /* If the next buffer has the el bit, but we think the receiver + * is still running, check to see if it really stopped while + * we had interrupts off. + * This allows for a fast restart without re-enabling + * interrupts */ + if ((le16_to_cpu(rfd->command) & cb_el) && + (RU_RUNNING == nic->ru_running)) + + if (readb(&nic->csr->scb.status) & rus_no_res) + nic->ru_running = RU_SUSPENDED; return -ENODATA; + } /* Get actual data size */ actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; @@ -1836,9 +1850,18 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, pci_unmap_single(nic->pdev, rx->dma_addr, RFD_BUF_LEN, PCI_DMA_FROMDEVICE); - /* this allows for a fast restart without re-enabling interrupts */ - if(le16_to_cpu(rfd->command) & cb_el) + /* If this buffer has the el bit, but we think the receiver + * is still running, check to see if it really stopped while + * we had interrupts off. + * This allows for a fast restart without re-enabling interrupts. + * This can happen when the RU sees the size change but also sees + * the el bit set. */ + if ((le16_to_cpu(rfd->command) & cb_el) && + (RU_RUNNING == nic->ru_running)) { + + if (readb(&nic->csr->scb.status) & rus_no_res) nic->ru_running = RU_SUSPENDED; + } /* Pull off the RFD and put the actual data (minus eth hdr) */ skb_reserve(skb, sizeof(struct rfd)); @@ -1870,31 +1893,30 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done, unsigned int work_to_do) { struct rx *rx; - int restart_required = 0; - struct rx *rx_to_start = NULL; - - /* are we already rnr? then pay attention!!! this ensures that - * the state machine progression never allows a start with a - * partially cleaned list, avoiding a race between hardware - * and rx_to_clean when in NAPI mode */ - if(RU_SUSPENDED == nic->ru_running) - restart_required = 1; + int restart_required = 0, err = 0; + struct rx *old_before_last_rx, *new_before_last_rx; + struct rfd *old_before_last_rfd, *new_before_last_rfd; /* Indicate newly arrived packets */ for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { - int err = e100_rx_indicate(nic, rx, work_done, work_to_do); - if(-EAGAIN == err) { - /* hit quota so have more work to do, restart once - * cleanup is complete */ - restart_required = 0; + err = e100_rx_indicate(nic, rx, work_done, work_to_do); + /* Hit quota or no more to clean */ + if (-EAGAIN == err || -ENODATA == err) break; - } else if(-ENODATA == err) - break; /* No more to clean */ } - /* save our starting point as the place we'll restart the receiver */ - if(restart_required) - rx_to_start = nic->rx_to_clean; + + /* On EAGAIN, hit quota so have more work to do, restart once + * cleanup is complete. + * Else, are we already rnr? then pay attention!!! this ensures that + * the state machine progression never allows a start with a + * partially cleaned list, avoiding a race between hardware + * and rx_to_clean when in NAPI mode */ + if (-EAGAIN != err && RU_SUSPENDED == nic->ru_running) + restart_required = 1; + + old_before_last_rx = nic->rx_to_use->prev->prev; + old_before_last_rfd = (struct rfd *)old_before_last_rx->skb->data; /* Alloc new skbs to refill list */ for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { @@ -1902,10 +1924,42 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done, break; /* Better luck next time (see watchdog) */ } + new_before_last_rx = nic->rx_to_use->prev->prev; + if (new_before_last_rx != old_before_last_rx) { + /* Set the el-bit on the buffer that is before the last buffer. + * This lets us update the next pointer on the last buffer + * without worrying about hardware touching it. + * We set the size to 0 to prevent hardware from touching this + * buffer. + * When the hardware hits the before last buffer with el-bit + * and size of 0, it will RNR interrupt, the RUS will go into + * the No Resources state. It will not complete nor write to + * this buffer. */ + new_before_last_rfd = + (struct rfd *)new_before_last_rx->skb->data; + new_before_last_rfd->size = 0; + new_before_last_rfd->command |= cpu_to_le16(cb_el); + pci_dma_sync_single_for_device(nic->pdev, + new_before_last_rx->dma_addr, sizeof(struct rfd), + PCI_DMA_TODEVICE); + + /* Now that we have a new stopping point, we can clear the old + * stopping point. We must sync twice to get the proper + * ordering on the hardware side of things. */ + old_before_last_rfd->command &= ~cpu_to_le16(cb_el); + pci_dma_sync_single_for_device(nic->pdev, + old_before_last_rx->dma_addr, sizeof(struct rfd), + PCI_DMA_TODEVICE); + old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN); + pci_dma_sync_single_for_device(nic->pdev, + old_before_last_rx->dma_addr, sizeof(struct rfd), + PCI_DMA_TODEVICE); + } + if(restart_required) { // ack the rnr? writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); - e100_start_receiver(nic, rx_to_start); + e100_start_receiver(nic, nic->rx_to_clean); if(work_done) (*work_done)++; } @@ -1937,6 +1991,7 @@ static int e100_rx_alloc_list(struct nic *nic) { struct rx *rx; unsigned int i, count = nic->params.rfds.count; + struct rfd *before_last; nic->rx_to_use = nic->rx_to_clean = NULL; nic->ru_running = RU_UNINITIALIZED; @@ -1952,6 +2007,19 @@ static int e100_rx_alloc_list(struct nic *nic) return -ENOMEM; } } + /* Set the el-bit on the buffer that is before the last buffer. + * This lets us update the next pointer on the last buffer without + * worrying about hardware touching it. + * We set the size to 0 to prevent hardware from touching this buffer. + * When the hardware hits the before last buffer with el-bit and size + * of 0, it will RNR interrupt, the RU will go into the No Resources + * state. It will not complete nor write to this buffer. */ + rx = nic->rxs->prev->prev; + before_last = (struct rfd *)rx->skb->data; + before_last->command |= cpu_to_le16(cb_el); + before_last->size = 0; + pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); nic->rx_to_use = nic->rx_to_clean = nic->rxs; nic->ru_running = RU_SUSPENDED; @@ -2369,7 +2437,7 @@ static const char e100_gstrings_test[][ETH_GSTRING_LEN] = { "Mac loopback (offline)", "Phy loopback (offline)", }; -#define E100_TEST_LEN sizeof(e100_gstrings_test) / ETH_GSTRING_LEN +#define E100_TEST_LEN ARRAY_SIZE(e100_gstrings_test) static void e100_diag_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) @@ -2431,7 +2499,7 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets", }; #define E100_NET_STATS_LEN 21 -#define E100_STATS_LEN sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN +#define E100_STATS_LEN ARRAY_SIZE(e100_gstrings_stats) static int e100_get_sset_count(struct net_device *netdev, int sset) { diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index b83ccce8a9b7..d876787ce336 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -110,7 +110,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)" }; -#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN +#define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test) static int e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) @@ -728,39 +728,65 @@ err_setup: return err; } -#define REG_PATTERN_TEST(R, M, W) \ -{ \ - uint32_t pat, val; \ - const uint32_t test[] = \ - {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ - for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \ - E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ - val = E1000_READ_REG(&adapter->hw, R); \ - if (val != (test[pat] & W & M)) { \ - DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \ - "0x%08X expected 0x%08X\n", \ - E1000_##R, val, (test[pat] & W & M)); \ - *data = (adapter->hw.mac_type < e1000_82543) ? \ - E1000_82542_##R : E1000_##R; \ - return 1; \ - } \ - } \ +static bool reg_pattern_test(struct e1000_adapter *adapter, uint64_t *data, + int reg, uint32_t mask, uint32_t write) +{ + static const uint32_t test[] = + {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + uint8_t __iomem *address = adapter->hw.hw_addr + reg; + uint32_t read; + int i; + + for (i = 0; i < ARRAY_SIZE(test); i++) { + writel(write & test[i], address); + read = readl(address); + if (read != (write & test[i] & mask)) { + DPRINTK(DRV, ERR, "pattern test reg %04X failed: " + "got 0x%08X expected 0x%08X\n", + reg, read, (write & test[i] & mask)); + *data = reg; + return true; + } + } + return false; } -#define REG_SET_AND_CHECK(R, M, W) \ -{ \ - uint32_t val; \ - E1000_WRITE_REG(&adapter->hw, R, W & M); \ - val = E1000_READ_REG(&adapter->hw, R); \ - if ((W & M) != (val & M)) { \ - DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\ - "expected 0x%08X\n", E1000_##R, (val & M), (W & M)); \ - *data = (adapter->hw.mac_type < e1000_82543) ? \ - E1000_82542_##R : E1000_##R; \ - return 1; \ - } \ +static bool reg_set_and_check(struct e1000_adapter *adapter, uint64_t *data, + int reg, uint32_t mask, uint32_t write) +{ + uint8_t __iomem *address = adapter->hw.hw_addr + reg; + uint32_t read; + + writel(write & mask, address); + read = readl(address); + if ((read & mask) != (write & mask)) { + DPRINTK(DRV, ERR, "set/check reg %04X test failed: " + "got 0x%08X expected 0x%08X\n", + reg, (read & mask), (write & mask)); + *data = reg; + return true; + } + return false; } +#define REG_PATTERN_TEST(reg, mask, write) \ + do { \ + if (reg_pattern_test(adapter, data, \ + (adapter->hw.mac_type >= e1000_82543) \ + ? E1000_##reg : E1000_82542_##reg, \ + mask, write)) \ + return 1; \ + } while (0) + +#define REG_SET_AND_CHECK(reg, mask, write) \ + do { \ + if (reg_set_and_check(adapter, data, \ + (adapter->hw.mac_type >= e1000_82543) \ + ? E1000_##reg : E1000_82542_##reg, \ + mask, write)) \ + return 1; \ + } while (0) + static int e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) { diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index a2a86c54a75c..a6c3c34feb98 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -421,8 +421,6 @@ void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, u void e1000_get_bus_info(struct e1000_hw *hw); void e1000_pci_set_mwi(struct e1000_hw *hw); void e1000_pci_clear_mwi(struct e1000_hw *hw); -void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); -void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value); int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value); void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc); int e1000_pcix_get_mmrbc(struct e1000_hw *hw); @@ -595,35 +593,35 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); /* Receive Descriptor */ struct e1000_rx_desc { - uint64_t buffer_addr; /* Address of the descriptor's data buffer */ - uint16_t length; /* Length of data DMAed into data buffer */ - uint16_t csum; /* Packet checksum */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 length; /* Length of data DMAed into data buffer */ + __le16 csum; /* Packet checksum */ uint8_t status; /* Descriptor status */ uint8_t errors; /* Descriptor Errors */ - uint16_t special; + __le16 special; }; /* Receive Descriptor - Extended */ union e1000_rx_desc_extended { struct { - uint64_t buffer_addr; - uint64_t reserved; + __le64 buffer_addr; + __le64 reserved; } read; struct { struct { - uint32_t mrq; /* Multiple Rx Queues */ + __le32 mrq; /* Multiple Rx Queues */ union { - uint32_t rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - uint16_t ip_id; /* IP id */ - uint16_t csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - uint32_t status_error; /* ext status/error */ - uint16_t length; - uint16_t vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length; + __le16 vlan; /* VLAN tag */ } upper; } wb; /* writeback */ }; @@ -633,29 +631,29 @@ union e1000_rx_desc_extended { union e1000_rx_desc_packet_split { struct { /* one buffer for protocol header(s), three data buffers */ - uint64_t buffer_addr[MAX_PS_BUFFERS]; + __le64 buffer_addr[MAX_PS_BUFFERS]; } read; struct { struct { - uint32_t mrq; /* Multiple Rx Queues */ + __le32 mrq; /* Multiple Rx Queues */ union { - uint32_t rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - uint16_t ip_id; /* IP id */ - uint16_t csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - uint32_t status_error; /* ext status/error */ - uint16_t length0; /* length of buffer 0 */ - uint16_t vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length0; /* length of buffer 0 */ + __le16 vlan; /* VLAN tag */ } middle; struct { - uint16_t header_status; - uint16_t length[3]; /* length of buffers 1-3 */ + __le16 header_status; + __le16 length[3]; /* length of buffers 1-3 */ } upper; - uint64_t reserved; + __le64 reserved; } wb; /* writeback */ }; @@ -715,21 +713,21 @@ union e1000_rx_desc_packet_split { /* Transmit Descriptor */ struct e1000_tx_desc { - uint64_t buffer_addr; /* Address of the descriptor's data buffer */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ union { - uint32_t data; + __le32 data; struct { - uint16_t length; /* Data buffer length */ + __le16 length; /* Data buffer length */ uint8_t cso; /* Checksum offset */ uint8_t cmd; /* Descriptor control */ } flags; } lower; union { - uint32_t data; + __le32 data; struct { uint8_t status; /* Descriptor status */ uint8_t css; /* Checksum start */ - uint16_t special; + __le16 special; } fields; } upper; }; @@ -759,49 +757,49 @@ struct e1000_tx_desc { /* Offload Context Descriptor */ struct e1000_context_desc { union { - uint32_t ip_config; + __le32 ip_config; struct { uint8_t ipcss; /* IP checksum start */ uint8_t ipcso; /* IP checksum offset */ - uint16_t ipcse; /* IP checksum end */ + __le16 ipcse; /* IP checksum end */ } ip_fields; } lower_setup; union { - uint32_t tcp_config; + __le32 tcp_config; struct { uint8_t tucss; /* TCP checksum start */ uint8_t tucso; /* TCP checksum offset */ - uint16_t tucse; /* TCP checksum end */ + __le16 tucse; /* TCP checksum end */ } tcp_fields; } upper_setup; - uint32_t cmd_and_length; /* */ + __le32 cmd_and_length; /* */ union { - uint32_t data; + __le32 data; struct { uint8_t status; /* Descriptor status */ uint8_t hdr_len; /* Header length */ - uint16_t mss; /* Maximum segment size */ + __le16 mss; /* Maximum segment size */ } fields; } tcp_seg_setup; }; /* Offload data descriptor */ struct e1000_data_desc { - uint64_t buffer_addr; /* Address of the descriptor's buffer address */ + __le64 buffer_addr; /* Address of the descriptor's buffer address */ union { - uint32_t data; + __le32 data; struct { - uint16_t length; /* Data buffer length */ + __le16 length; /* Data buffer length */ uint8_t typ_len_ext; /* */ uint8_t cmd; /* */ } flags; } lower; union { - uint32_t data; + __le32 data; struct { uint8_t status; /* Descriptor status */ uint8_t popts; /* Packet Options */ - uint16_t special; /* */ + __le16 special; /* */ } fields; } upper; }; @@ -817,8 +815,8 @@ struct e1000_data_desc { /* Receive Address Register */ struct e1000_rar { - volatile uint32_t low; /* receive address low */ - volatile uint32_t high; /* receive address high */ + volatile __le32 low; /* receive address low */ + volatile __le32 high; /* receive address high */ }; /* Number of entries in the Multicast Table Array (MTA). */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 76c0fa690cc6..8c87940a9ce8 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -47,6 +47,12 @@ static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation * Macro expands to... * {PCI_DEVICE(PCI_VENDOR_ID_INTEL, device_id)} */ +#ifdef CONFIG_E1000E_ENABLED + #define PCIE(x) +#else + #define PCIE(x) x, +#endif + static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1000), INTEL_E1000_ETHERNET_DEVICE(0x1001), @@ -73,14 +79,14 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x1026), INTEL_E1000_ETHERNET_DEVICE(0x1027), INTEL_E1000_ETHERNET_DEVICE(0x1028), - INTEL_E1000_ETHERNET_DEVICE(0x1049), - INTEL_E1000_ETHERNET_DEVICE(0x104A), - INTEL_E1000_ETHERNET_DEVICE(0x104B), - INTEL_E1000_ETHERNET_DEVICE(0x104C), - INTEL_E1000_ETHERNET_DEVICE(0x104D), - INTEL_E1000_ETHERNET_DEVICE(0x105E), - INTEL_E1000_ETHERNET_DEVICE(0x105F), - INTEL_E1000_ETHERNET_DEVICE(0x1060), +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1049)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104A)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104B)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104C)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x104D)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x105E)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x105F)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1060)) INTEL_E1000_ETHERNET_DEVICE(0x1075), INTEL_E1000_ETHERNET_DEVICE(0x1076), INTEL_E1000_ETHERNET_DEVICE(0x1077), @@ -89,28 +95,28 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x107A), INTEL_E1000_ETHERNET_DEVICE(0x107B), INTEL_E1000_ETHERNET_DEVICE(0x107C), - INTEL_E1000_ETHERNET_DEVICE(0x107D), - INTEL_E1000_ETHERNET_DEVICE(0x107E), - INTEL_E1000_ETHERNET_DEVICE(0x107F), +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x107D)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x107E)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x107F)) INTEL_E1000_ETHERNET_DEVICE(0x108A), - INTEL_E1000_ETHERNET_DEVICE(0x108B), - INTEL_E1000_ETHERNET_DEVICE(0x108C), - INTEL_E1000_ETHERNET_DEVICE(0x1096), - INTEL_E1000_ETHERNET_DEVICE(0x1098), +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x108B)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x108C)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1096)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x1098)) INTEL_E1000_ETHERNET_DEVICE(0x1099), - INTEL_E1000_ETHERNET_DEVICE(0x109A), - INTEL_E1000_ETHERNET_DEVICE(0x10A4), - INTEL_E1000_ETHERNET_DEVICE(0x10A5), +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x109A)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10A4)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10A5)) INTEL_E1000_ETHERNET_DEVICE(0x10B5), - INTEL_E1000_ETHERNET_DEVICE(0x10B9), - INTEL_E1000_ETHERNET_DEVICE(0x10BA), - INTEL_E1000_ETHERNET_DEVICE(0x10BB), - INTEL_E1000_ETHERNET_DEVICE(0x10BC), - INTEL_E1000_ETHERNET_DEVICE(0x10C4), - INTEL_E1000_ETHERNET_DEVICE(0x10C5), - INTEL_E1000_ETHERNET_DEVICE(0x10D5), - INTEL_E1000_ETHERNET_DEVICE(0x10D9), - INTEL_E1000_ETHERNET_DEVICE(0x10DA), +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10B9)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10BA)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10BB)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10BC)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10C4)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10C5)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10D5)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10D9)) +PCIE( INTEL_E1000_ETHERNET_DEVICE(0x10DA)) /* required last entry */ {0,} }; @@ -153,7 +159,7 @@ static void e1000_clean_tx_ring(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring); static void e1000_clean_rx_ring(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring); -static void e1000_set_multi(struct net_device *netdev); +static void e1000_set_rx_mode(struct net_device *netdev); static void e1000_update_phy_info(unsigned long data); static void e1000_watchdog(unsigned long data); static void e1000_82547_tx_fifo_stall(unsigned long data); @@ -299,14 +305,14 @@ module_exit(e1000_exit_module); static int e1000_request_irq(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - void (*handler) = &e1000_intr; + irq_handler_t handler = e1000_intr; int irq_flags = IRQF_SHARED; int err; if (adapter->hw.mac_type >= e1000_82571) { adapter->have_msi = !pci_enable_msi(adapter->pdev); if (adapter->have_msi) { - handler = &e1000_intr_msi; + handler = e1000_intr_msi; irq_flags = 0; } } @@ -514,7 +520,7 @@ static void e1000_configure(struct e1000_adapter *adapter) struct net_device *netdev = adapter->netdev; int i; - e1000_set_multi(netdev); + e1000_set_rx_mode(netdev); e1000_restore_vlan(adapter); e1000_init_manageability(adapter); @@ -845,6 +851,64 @@ e1000_reset(struct e1000_adapter *adapter) } /** + * Dump the eeprom for users having checksum issues + **/ +void e1000_dump_eeprom(struct e1000_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct ethtool_eeprom eeprom; + const struct ethtool_ops *ops = netdev->ethtool_ops; + u8 *data; + int i; + u16 csum_old, csum_new = 0; + + eeprom.len = ops->get_eeprom_len(netdev); + eeprom.offset = 0; + + data = kmalloc(eeprom.len, GFP_KERNEL); + if (!data) { + printk(KERN_ERR "Unable to allocate memory to dump EEPROM" + " data\n"); + return; + } + + ops->get_eeprom(netdev, &eeprom, data); + + csum_old = (data[EEPROM_CHECKSUM_REG * 2]) + + (data[EEPROM_CHECKSUM_REG * 2 + 1] << 8); + for (i = 0; i < EEPROM_CHECKSUM_REG * 2; i += 2) + csum_new += data[i] + (data[i + 1] << 8); + csum_new = EEPROM_SUM - csum_new; + + printk(KERN_ERR "/*********************/\n"); + printk(KERN_ERR "Current EEPROM Checksum : 0x%04x\n", csum_old); + printk(KERN_ERR "Calculated : 0x%04x\n", csum_new); + + printk(KERN_ERR "Offset Values\n"); + printk(KERN_ERR "======== ======\n"); + print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, data, 128, 0); + + printk(KERN_ERR "Include this output when contacting your support " + "provider.\n"); + printk(KERN_ERR "This is not a software error! Something bad " + "happened to your hardware or\n"); + printk(KERN_ERR "EEPROM image. Ignoring this " + "problem could result in further problems,\n"); + printk(KERN_ERR "possibly loss of data, corruption or system hangs!\n"); + printk(KERN_ERR "The MAC Address will be reset to 00:00:00:00:00:00, " + "which is invalid\n"); + printk(KERN_ERR "and requires you to set the proper MAC " + "address manually before continuing\n"); + printk(KERN_ERR "to enable this network device.\n"); + printk(KERN_ERR "Please inspect the EEPROM dump and report the issue " + "to your hardware vendor\n"); + printk(KERN_ERR "or Intel Customer Support: linux-nics@intel.com\n"); + printk(KERN_ERR "/*********************/\n"); + + kfree(data); +} + +/** * e1000_probe - Device Initialization Routine * @pdev: PCI device information struct * @ent: entry in e1000_pci_tbl @@ -927,7 +991,7 @@ e1000_probe(struct pci_dev *pdev, netdev->stop = &e1000_close; netdev->hard_start_xmit = &e1000_xmit_frame; netdev->get_stats = &e1000_get_stats; - netdev->set_multicast_list = &e1000_set_multi; + netdev->set_rx_mode = &e1000_set_rx_mode; netdev->set_mac_address = &e1000_set_mac; netdev->change_mtu = &e1000_change_mtu; netdev->do_ioctl = &e1000_ioctl; @@ -995,7 +1059,6 @@ e1000_probe(struct pci_dev *pdev, adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw); /* initialize eeprom parameters */ - if (e1000_init_eeprom_params(&adapter->hw)) { E1000_ERR("EEPROM initialization failed\n"); goto err_eeprom; @@ -1007,23 +1070,29 @@ e1000_probe(struct pci_dev *pdev, e1000_reset_hw(&adapter->hw); /* make sure the EEPROM is good */ - if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) { DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n"); - goto err_eeprom; + e1000_dump_eeprom(adapter); + /* + * set MAC address to all zeroes to invalidate and temporary + * disable this device for the user. This blocks regular + * traffic while still permitting ethtool ioctls from reaching + * the hardware as well as allowing the user to run the + * interface after manually setting a hw addr using + * `ip set address` + */ + memset(adapter->hw.mac_addr, 0, netdev->addr_len); + } else { + /* copy the MAC address out of the EEPROM */ + if (e1000_read_mac_addr(&adapter->hw)) + DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); } - - /* copy the MAC address out of the EEPROM */ - - if (e1000_read_mac_addr(&adapter->hw)) - DPRINTK(PROBE, ERR, "EEPROM Read Error\n"); + /* don't block initalization here due to bad MAC address */ memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); - if (!is_valid_ether_addr(netdev->perm_addr)) { + if (!is_valid_ether_addr(netdev->perm_addr)) DPRINTK(PROBE, ERR, "Invalid MAC Address\n"); - goto err_eeprom; - } e1000_get_bus_info(&adapter->hw); @@ -2410,21 +2479,22 @@ e1000_set_mac(struct net_device *netdev, void *p) } /** - * e1000_set_multi - Multicast and Promiscuous mode set + * e1000_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set * @netdev: network interface device structure * - * The set_multi entry point is called whenever the multicast address - * list or the network interface flags are updated. This routine is - * responsible for configuring the hardware for proper multicast, + * The set_rx_mode entry point is called whenever the unicast or multicast + * address lists or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper unicast, multicast, * promiscuous mode, and all-multi behavior. **/ static void -e1000_set_multi(struct net_device *netdev) +e1000_set_rx_mode(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct dev_mc_list *mc_ptr; + struct dev_addr_list *uc_ptr; + struct dev_addr_list *mc_ptr; uint32_t rctl; uint32_t hash_value; int i, rar_entries = E1000_RAR_ENTRIES; @@ -2447,9 +2517,16 @@ e1000_set_multi(struct net_device *netdev) rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); } else if (netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; - rctl &= ~E1000_RCTL_UPE; } else { - rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + rctl &= ~E1000_RCTL_MPE; + } + + uc_ptr = NULL; + if (netdev->uc_count > rar_entries - 1) { + rctl |= E1000_RCTL_UPE; + } else if (!(netdev->flags & IFF_PROMISC)) { + rctl &= ~E1000_RCTL_UPE; + uc_ptr = netdev->uc_list; } E1000_WRITE_REG(hw, RCTL, rctl); @@ -2459,7 +2536,10 @@ e1000_set_multi(struct net_device *netdev) if (hw->mac_type == e1000_82542_rev2_0) e1000_enter_82542_rst(adapter); - /* load the first 14 multicast address into the exact filters 1-14 + /* load the first 14 addresses into the exact filters 1-14. Unicast + * addresses take precedence to avoid disabling unicast filtering + * when possible. + * * RAR 0 is used for the station MAC adddress * if there are not 14 addresses, go ahead and clear the filters * -- with 82571 controllers only 0-13 entries are filled here @@ -2467,8 +2547,11 @@ e1000_set_multi(struct net_device *netdev) mc_ptr = netdev->mc_list; for (i = 1; i < rar_entries; i++) { - if (mc_ptr) { - e1000_rar_set(hw, mc_ptr->dmi_addr, i); + if (uc_ptr) { + e1000_rar_set(hw, uc_ptr->da_addr, i); + uc_ptr = uc_ptr->next; + } else if (mc_ptr) { + e1000_rar_set(hw, mc_ptr->da_addr, i); mc_ptr = mc_ptr->next; } else { E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0); @@ -2477,6 +2560,7 @@ e1000_set_multi(struct net_device *netdev) E1000_WRITE_FLUSH(hw); } } + WARN_ON(uc_ptr != NULL); /* clear the old settings from the multicast hash table */ @@ -2488,7 +2572,7 @@ e1000_set_multi(struct net_device *netdev) /* load any remaining addresses into the hash table */ for (; mc_ptr; mc_ptr = mc_ptr->next) { - hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr); + hash_value = e1000_hash_mc_addr(hw, mc_ptr->da_addr); e1000_mta_set(hw, hash_value); } @@ -3680,10 +3764,6 @@ e1000_update_stats(struct e1000_adapter *adapter) } /* Fill out the OS statistics structure */ - adapter->net_stats.rx_packets = adapter->stats.gprc; - adapter->net_stats.tx_packets = adapter->stats.gptc; - adapter->net_stats.rx_bytes = adapter->stats.gorcl; - adapter->net_stats.tx_bytes = adapter->stats.gotcl; adapter->net_stats.multicast = adapter->stats.mprc; adapter->net_stats.collisions = adapter->stats.colc; @@ -4059,6 +4139,8 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, } adapter->total_tx_bytes += total_tx_bytes; adapter->total_tx_packets += total_tx_packets; + adapter->net_stats.tx_bytes += total_tx_bytes; + adapter->net_stats.tx_packets += total_tx_packets; return cleaned; } @@ -4106,8 +4188,8 @@ e1000_rx_checksum(struct e1000_adapter *adapter, /* Hardware complements the payload checksum, so we undo it * and then put the value in host order for further stack use. */ - csum = ntohl(csum ^ 0xFFFF); - skb->csum = csum; + __sum16 sum = (__force __sum16)htons(csum); + skb->csum = csum_unfold(~sum); skb->ip_summed = CHECKSUM_COMPLETE; } adapter->hw_csum_good++; @@ -4281,6 +4363,8 @@ next_desc: adapter->total_rx_packets += total_rx_packets; adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; return cleaned; } @@ -4468,6 +4552,8 @@ next_desc: adapter->total_rx_packets += total_rx_packets; adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; return cleaned; } @@ -4631,7 +4717,7 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, rx_desc->read.buffer_addr[j+1] = cpu_to_le64(ps_page_dma->ps_page_dma[j]); } else - rx_desc->read.buffer_addr[j+1] = ~0; + rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0); } skb = netdev_alloc_skb(netdev, @@ -4874,22 +4960,6 @@ e1000_pci_clear_mwi(struct e1000_hw *hw) pci_clear_mwi(adapter->pdev); } -void -e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - struct e1000_adapter *adapter = hw->back; - - pci_read_config_word(adapter->pdev, reg, value); -} - -void -e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - struct e1000_adapter *adapter = hw->back; - - pci_write_config_word(adapter->pdev, reg, *value); -} - int e1000_pcix_get_mmrbc(struct e1000_hw *hw) { @@ -5095,7 +5165,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) if (wufc) { e1000_setup_rctl(adapter); - e1000_set_multi(netdev); + e1000_set_rx_mode(netdev); /* turn on all-multi mode if wake on multicast is enabled */ if (wufc & E1000_WUFC_MC) { diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 14141a55eaa6..3beace55b58d 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -194,6 +194,8 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter) break; case E1000_DEV_ID_82571EB_SERDES: case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_82571EB_SERDES_DUAL: + case E1000_DEV_ID_82571EB_SERDES_QUAD: hw->media_type = e1000_media_type_internal_serdes; break; default: @@ -260,6 +262,7 @@ static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter) case E1000_DEV_ID_82571EB_QUAD_COPPER: case E1000_DEV_ID_82571EB_QUAD_FIBER: case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: + case E1000_DEV_ID_82571PT_QUAD_COPPER: adapter->flags |= FLAG_IS_QUAD_PORT; /* mark the first port */ if (global_quad_port_a == 0) @@ -285,6 +288,9 @@ static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter) if (adapter->flags & FLAG_IS_QUAD_PORT && (!(adapter->flags & FLAG_IS_QUAD_PORT_A))) adapter->flags &= ~FLAG_HAS_WOL; + /* Does not support WoL on any port */ + if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) + adapter->flags &= ~FLAG_HAS_WOL; break; case e1000_82573: @@ -752,6 +758,10 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw) ew32(IMC, 0xffffffff); icr = er32(ICR); + if (hw->mac.type == e1000_82571 && + hw->dev_spec.e82571.alt_mac_addr_is_present) + e1000e_set_laa_state_82571(hw, true); + return 0; } @@ -1339,7 +1349,6 @@ struct e1000_info e1000_82573_info = { | FLAG_HAS_STATS_ICR_ICT | FLAG_HAS_SMART_POWER_DOWN | FLAG_HAS_AMT - | FLAG_HAS_ASPM | FLAG_HAS_ERT | FLAG_HAS_SWSM_ON_LOAD, .pba = 20, diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index b32ed45b4b34..f2175ea46b83 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -557,6 +557,7 @@ #define NVM_INIT_3GIO_3 0x001A #define NVM_INIT_CONTROL3_PORT_A 0x0024 #define NVM_CFG 0x0012 +#define NVM_ALT_MAC_ADDR_PTR 0x0037 #define NVM_CHECKSUM_REG 0x003F #define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 473f78de4be0..8b88c226e858 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -288,7 +288,6 @@ struct e1000_info { #define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) #define FLAG_HAS_SWSM_ON_LOAD (1 << 6) #define FLAG_HAS_JUMBO_FRAMES (1 << 7) -#define FLAG_HAS_ASPM (1 << 8) #define FLAG_HAS_STATS_ICR_ICT (1 << 9) #define FLAG_HAS_STATS_PTC_PRC (1 << 10) #define FLAG_HAS_SMART_POWER_DOWN (1 << 11) diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 87f9da1b6b4e..6d9c27fd0b53 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -95,15 +95,14 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "tx_dma_failed", E1000_STAT(tx_dma_failed) }, }; -#define E1000_GLOBAL_STATS_LEN \ - sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) +#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats) #define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN) static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)" }; -#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN +#define E1000_TEST_LEN ARRAY_SIZE(e1000_gstrings_test) static int e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) @@ -691,41 +690,63 @@ err_setup: return err; } -#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W) -#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable) \ -{ \ - u32 _pat; \ - u32 _value; \ - u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ - for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) { \ - E1000_WRITE_REG_ARRAY(hw, reg, offset, \ - (_test[_pat] & writeable)); \ - _value = E1000_READ_REG_ARRAY(hw, reg, offset); \ - if (_value != (_test[_pat] & writeable & mask)) { \ - ndev_err(netdev, "pattern test reg %04X " \ - "failed: got 0x%08X expected 0x%08X\n", \ - reg + offset, \ - value, (_test[_pat] & writeable & mask)); \ - *data = reg; \ - return 1; \ - } \ - } \ +bool reg_pattern_test_array(struct e1000_adapter *adapter, u64 *data, + int reg, int offset, u32 mask, u32 write) +{ + int i; + u32 read; + static const u32 test[] = + {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + for (i = 0; i < ARRAY_SIZE(test); i++) { + E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset, + (test[i] & write)); + read = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset); + if (read != (test[i] & write & mask)) { + ndev_err(adapter->netdev, "pattern test reg %04X " + "failed: got 0x%08X expected 0x%08X\n", + reg + offset, + read, (test[i] & write & mask)); + *data = reg; + return true; + } + } + return false; } -#define REG_SET_AND_CHECK(R, M, W) \ -{ \ - u32 _value; \ - __ew32(hw, R, W & M); \ - _value = __er32(hw, R); \ - if ((W & M) != (_value & M)) { \ - ndev_err(netdev, "set/check reg %04X test failed: " \ - "got 0x%08X expected 0x%08X\n", R, (_value & M), \ - (W & M)); \ - *data = R; \ - return 1; \ - } \ +static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, + int reg, u32 mask, u32 write) +{ + u32 read; + __ew32(&adapter->hw, reg, write & mask); + read = __er32(&adapter->hw, reg); + if ((write & mask) != (read & mask)) { + ndev_err(adapter->netdev, "set/check reg %04X test failed: " + "got 0x%08X expected 0x%08X\n", reg, (read & mask), + (write & mask)); + *data = reg; + return true; + } + return false; } +#define REG_PATTERN_TEST(R, M, W) \ + do { \ + if (reg_pattern_test_array(adapter, data, R, 0, M, W)) \ + return 1; \ + } while (0) + +#define REG_PATTERN_TEST_ARRAY(R, offset, M, W) \ + do { \ + if (reg_pattern_test_array(adapter, data, R, offset, M, W)) \ + return 1; \ + } while (0) + +#define REG_SET_AND_CHECK(R, M, W) \ + do { \ + if (reg_set_and_check(adapter, data, R, M, W)) \ + return 1; \ + } while (0) + static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) { struct e1000_hw *hw = &adapter->hw; diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 64515789fd4d..3c5862f97dbf 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -303,8 +303,11 @@ enum e1e_registers { #define E1000_DEV_ID_82571EB_FIBER 0x105F #define E1000_DEV_ID_82571EB_SERDES 0x1060 #define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 +#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 #define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC +#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 +#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA #define E1000_DEV_ID_82572EI_COPPER 0x107D #define E1000_DEV_ID_82572EI_FIBER 0x107E #define E1000_DEV_ID_82572EI_SERDES 0x107F @@ -420,35 +423,35 @@ enum e1000_smart_speed { /* Receive Descriptor */ struct e1000_rx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ - u16 length; /* Length of data DMAed into data buffer */ - u16 csum; /* Packet checksum */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 length; /* Length of data DMAed into data buffer */ + __le16 csum; /* Packet checksum */ u8 status; /* Descriptor status */ u8 errors; /* Descriptor Errors */ - u16 special; + __le16 special; }; /* Receive Descriptor - Extended */ union e1000_rx_desc_extended { struct { - u64 buffer_addr; - u64 reserved; + __le64 buffer_addr; + __le64 reserved; } read; struct { struct { - u32 mrq; /* Multiple Rx Queues */ + __le32 mrq; /* Multiple Rx Queues */ union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length; - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length; + __le16 vlan; /* VLAN tag */ } upper; } wb; /* writeback */ }; @@ -458,49 +461,49 @@ union e1000_rx_desc_extended { union e1000_rx_desc_packet_split { struct { /* one buffer for protocol header(s), three data buffers */ - u64 buffer_addr[MAX_PS_BUFFERS]; + __le64 buffer_addr[MAX_PS_BUFFERS]; } read; struct { struct { - u32 mrq; /* Multiple Rx Queues */ + __le32 mrq; /* Multiple Rx Queues */ union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ - u16 csum; /* Packet Checksum */ + __le16 ip_id; /* IP id */ + __le16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length0; /* length of buffer 0 */ - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length0; /* length of buffer 0 */ + __le16 vlan; /* VLAN tag */ } middle; struct { - u16 header_status; - u16 length[3]; /* length of buffers 1-3 */ + __le16 header_status; + __le16 length[3]; /* length of buffers 1-3 */ } upper; - u64 reserved; + __le64 reserved; } wb; /* writeback */ }; /* Transmit Descriptor */ struct e1000_tx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ union { - u32 data; + __le32 data; struct { - u16 length; /* Data buffer length */ + __le16 length; /* Data buffer length */ u8 cso; /* Checksum offset */ u8 cmd; /* Descriptor control */ } flags; } lower; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 css; /* Checksum start */ - u16 special; + __le16 special; } fields; } upper; }; @@ -508,49 +511,49 @@ struct e1000_tx_desc { /* Offload Context Descriptor */ struct e1000_context_desc { union { - u32 ip_config; + __le32 ip_config; struct { u8 ipcss; /* IP checksum start */ u8 ipcso; /* IP checksum offset */ - u16 ipcse; /* IP checksum end */ + __le16 ipcse; /* IP checksum end */ } ip_fields; } lower_setup; union { - u32 tcp_config; + __le32 tcp_config; struct { u8 tucss; /* TCP checksum start */ u8 tucso; /* TCP checksum offset */ - u16 tucse; /* TCP checksum end */ + __le16 tucse; /* TCP checksum end */ } tcp_fields; } upper_setup; - u32 cmd_and_length; + __le32 cmd_and_length; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 hdr_len; /* Header length */ - u16 mss; /* Maximum segment size */ + __le16 mss; /* Maximum segment size */ } fields; } tcp_seg_setup; }; /* Offload data descriptor */ struct e1000_data_desc { - u64 buffer_addr; /* Address of the descriptor's buffer address */ + __le64 buffer_addr; /* Address of the descriptor's buffer address */ union { - u32 data; + __le32 data; struct { - u16 length; /* Data buffer length */ + __le16 length; /* Data buffer length */ u8 typ_len_ext; u8 cmd; } flags; } lower; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 popts; /* Packet Options */ - u16 special; /* */ + __le16 special; /* */ } fields; } upper; }; @@ -816,6 +819,7 @@ struct e1000_bus_info { struct e1000_dev_spec_82571 { bool laa_is_present; + bool alt_mac_addr_is_present; }; struct e1000_shadow_ram { diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 0bdeca30c75f..16f35fadb74b 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -2059,9 +2059,44 @@ s32 e1000e_read_mac_addr(struct e1000_hw *hw) { s32 ret_val; u16 offset, nvm_data, i; + u16 mac_addr_offset = 0; + + if (hw->mac.type == e1000_82571) { + /* Check for an alternate MAC address. An alternate MAC + * address can be setup by pre-boot software and must be + * treated like a permanent address and must override the + * actual permanent MAC address. */ + ret_val = e1000_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, + &mac_addr_offset); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + if (mac_addr_offset == 0xFFFF) + mac_addr_offset = 0; + + if (mac_addr_offset) { + if (hw->bus.func == E1000_FUNC_1) + mac_addr_offset += ETH_ALEN/sizeof(u16); + + /* make sure we have a valid mac address here + * before using it */ + ret_val = e1000_read_nvm(hw, mac_addr_offset, 1, + &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + return ret_val; + } + if (nvm_data & 0x0001) + mac_addr_offset = 0; + } + + if (mac_addr_offset) + hw->dev_spec.e82571.alt_mac_addr_is_present = 1; + } for (i = 0; i < ETH_ALEN; i += 2) { - offset = i >> 1; + offset = mac_addr_offset + (i >> 1); ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data); if (ret_val) { hw_dbg(hw, "NVM Read Error\n"); @@ -2072,7 +2107,7 @@ s32 e1000e_read_mac_addr(struct e1000_hw *hw) } /* Flip last bit of mac address if we're on second port */ - if (hw->bus.func == E1000_FUNC_1) + if (!mac_addr_offset && hw->bus.func == E1000_FUNC_1) hw->mac.perm_addr[5] ^= 1; for (i = 0; i < ETH_ALEN; i++) diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 9cc5a6b01bc1..0a2cb7960c9e 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -91,7 +91,7 @@ static int e1000_desc_unused(struct e1000_ring *ring) static void e1000_receive_skb(struct e1000_adapter *adapter, struct net_device *netdev, struct sk_buff *skb, - u8 status, u16 vlan) + u8 status, __le16 vlan) { skb->protocol = eth_type_trans(skb, netdev); @@ -142,8 +142,8 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err, /* Hardware complements the payload checksum, so we undo it * and then put the value in host order for further stack use. */ - csum = ntohl(csum ^ 0xFFFF); - skb->csum = csum; + __sum16 sum = (__force __sum16)htons(csum); + skb->csum = csum_unfold(~sum); skb->ip_summed = CHECKSUM_COMPLETE; } adapter->hw_csum_good++; @@ -248,7 +248,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, ps_page = &buffer_info->ps_pages[j]; if (j >= adapter->rx_ps_pages) { /* all unused desc entries get hw null ptr */ - rx_desc->read.buffer_addr[j+1] = ~0; + rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0); continue; } if (!ps_page->page) { @@ -458,6 +458,8 @@ next_desc: adapter->total_rx_packets += total_rx_packets; adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + adapter->net_stats.rx_bytes += total_rx_bytes; return cleaned; } @@ -593,6 +595,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) } adapter->total_tx_bytes += total_tx_bytes; adapter->total_tx_packets += total_tx_packets; + adapter->net_stats.tx_packets += total_tx_packets; + adapter->net_stats.tx_bytes += total_tx_bytes; return cleaned; } @@ -755,6 +759,8 @@ next_desc: adapter->total_rx_packets += total_rx_packets; adapter->total_rx_bytes += total_rx_bytes; + adapter->net_stats.rx_packets += total_rx_packets; + adapter->net_stats.rx_bytes += total_rx_bytes; return cleaned; } @@ -935,7 +941,7 @@ static irqreturn_t e1000_intr(int irq, void *data) static int e1000_request_irq(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; - void (*handler) = &e1000_intr; + irq_handler_t handler = e1000_intr; int irq_flags = IRQF_SHARED; int err; @@ -945,7 +951,7 @@ static int e1000_request_irq(struct e1000_adapter *adapter) "Unable to allocate MSI interrupt Error: %d\n", err); } else { adapter->flags |= FLAG_MSI_ENABLED; - handler = &e1000_intr_msi; + handler = e1000_intr_msi; irq_flags = 0; } @@ -2535,10 +2541,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter) } /* Fill out the OS statistics structure */ - adapter->net_stats.rx_packets = adapter->stats.gprc; - adapter->net_stats.tx_packets = adapter->stats.gptc; - adapter->net_stats.rx_bytes = adapter->stats.gorcl; - adapter->net_stats.tx_bytes = adapter->stats.gotcl; adapter->net_stats.multicast = adapter->stats.mprc; adapter->net_stats.collisions = adapter->stats.colc; @@ -3509,6 +3511,33 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } +static void e1000e_disable_l1aspm(struct pci_dev *pdev) +{ + int pos; + u32 cap; + u16 val; + + /* + * 82573 workaround - disable L1 ASPM on mobile chipsets + * + * L1 ASPM on various mobile (ich7) chipsets do not behave properly + * resulting in lost data or garbage information on the pci-e link + * level. This could result in (false) bad EEPROM checksum errors, + * long ping times (up to 2s) or even a system freeze/hang. + * + * Unfortunately this feature saves about 1W power consumption when + * active. + */ + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &cap); + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &val); + if (val & 0x2) { + dev_warn(&pdev->dev, "Disabling L1 ASPM\n"); + val &= ~0x2; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, val); + } +} + #ifdef CONFIG_PM static int e1000_resume(struct pci_dev *pdev) { @@ -3519,6 +3548,7 @@ static int e1000_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + e1000e_disable_l1aspm(pdev); err = pci_enable_device(pdev); if (err) { dev_err(&pdev->dev, @@ -3619,6 +3649,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + e1000e_disable_l1aspm(pdev); if (pci_enable_device(pdev)) { dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n"); @@ -3720,6 +3751,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; + e1000e_disable_l1aspm(pdev); err = pci_enable_device(pdev); if (err) return err; @@ -4056,16 +4088,15 @@ static struct pci_error_handlers e1000_err_handler = { }; static struct pci_device_id e1000_pci_tbl[] = { - /* - * Support for 82571/2/3, es2lan and ich8 will be phased in - * stepwise. - { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_DUAL), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES_QUAD), board_82571 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82571PT_QUAD_COPPER), board_82571 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 }, @@ -4088,8 +4119,6 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan }, - */ - { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan }, diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c index 332789238b9c..df266c32ac4b 100644 --- a/drivers/net/e1000e/param.c +++ b/drivers/net/e1000e/param.c @@ -262,13 +262,6 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter) .max = MAX_RXDELAY } } }; - /* modify min and default if 82573 for slow ping w/a, - * a value greater than 8 needs to be set for RDTR */ - if (adapter->flags & FLAG_HAS_ASPM) { - opt.def = 32; - opt.arg.r.min = 8; - } - if (num_RxIntDelay > bd) { adapter->rx_int_delay = RxIntDelay[bd]; e1000_validate_option(&adapter->rx_int_delay, &opt, diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 793231810ae0..fc6fee112f1c 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -49,8 +49,7 @@ static const u16 e1000_igp_2_cable_length_table[] = 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, 124}; #define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_2_cable_length_table) / \ - sizeof(e1000_igp_2_cable_length_table[0])) + ARRAY_SIZE(e1000_igp_2_cable_length_table) /** * e1000e_check_reset_block_generic - Check if PHY reset is blocked diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 1548a80f917d..e3e26c595fa3 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -304,13 +304,7 @@ enum commands { #if defined(__alpha__) # define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status); #else -# if defined(__LITTLE_ENDIAN) -# define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000 -# elif defined(__BIG_ENDIAN) -# define clear_suspend(cmd) ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040 -# else -# error Unsupported byteorder -# endif +# define clear_suspend(cmd) ((__le16 *)&(cmd)->cmd_status)[1] &= ~cpu_to_le16(1<<14) #endif enum SCBCmdBits { @@ -331,17 +325,17 @@ enum SCBPort_cmds { /* The Speedo3 Rx and Tx frame/buffer descriptors. */ struct descriptor { /* A generic descriptor. */ - volatile s32 cmd_status; /* All command and status fields. */ - u32 link; /* struct descriptor * */ + volatile __le32 cmd_status; /* All command and status fields. */ + __le32 link; /* struct descriptor * */ unsigned char params[0]; }; /* The Speedo3 Rx and Tx buffer descriptors. */ struct RxFD { /* Receive frame descriptor. */ - volatile s32 status; - u32 link; /* struct RxFD * */ - u32 rx_buf_addr; /* void * */ - u32 count; + volatile __le32 status; + __le32 link; /* struct RxFD * */ + __le32 rx_buf_addr; /* void * */ + __le32 count; } RxFD_ALIGNMENT; /* Selected elements of the Tx/RxFD.status word. */ @@ -354,16 +348,16 @@ enum RxFD_bits { #define CONFIG_DATA_SIZE 22 struct TxFD { /* Transmit frame descriptor set. */ - s32 status; - u32 link; /* void * */ - u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ - s32 count; /* # of TBD (=1), Tx start thresh., etc. */ + __le32 status; + __le32 link; /* void * */ + __le32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ + __le32 count; /* # of TBD (=1), Tx start thresh., etc. */ /* This constitutes two "TBD" entries -- we only use one. */ #define TX_DESCR_BUF_OFFSET 16 - u32 tx_buf_addr0; /* void *, frame to be transmitted. */ - s32 tx_buf_size0; /* Length of Tx frame. */ - u32 tx_buf_addr1; /* void *, frame to be transmitted. */ - s32 tx_buf_size1; /* Length of Tx frame. */ + __le32 tx_buf_addr0; /* void *, frame to be transmitted. */ + __le32 tx_buf_size0; /* Length of Tx frame. */ + __le32 tx_buf_addr1; /* void *, frame to be transmitted. */ + __le32 tx_buf_size1; /* Length of Tx frame. */ /* the structure must have space for at least CONFIG_DATA_SIZE starting * from tx_desc_addr field */ }; @@ -379,23 +373,23 @@ struct speedo_mc_block { /* Elements of the dump_statistics block. This block must be lword aligned. */ struct speedo_stats { - u32 tx_good_frames; - u32 tx_coll16_errs; - u32 tx_late_colls; - u32 tx_underruns; - u32 tx_lost_carrier; - u32 tx_deferred; - u32 tx_one_colls; - u32 tx_multi_colls; - u32 tx_total_colls; - u32 rx_good_frames; - u32 rx_crc_errs; - u32 rx_align_errs; - u32 rx_resource_errs; - u32 rx_overrun_errs; - u32 rx_colls_errs; - u32 rx_runt_errs; - u32 done_marker; + __le32 tx_good_frames; + __le32 tx_coll16_errs; + __le32 tx_late_colls; + __le32 tx_underruns; + __le32 tx_lost_carrier; + __le32 tx_deferred; + __le32 tx_one_colls; + __le32 tx_multi_colls; + __le32 tx_total_colls; + __le32 rx_good_frames; + __le32 rx_crc_errs; + __le32 rx_align_errs; + __le32 rx_resource_errs; + __le32 rx_overrun_errs; + __le32 rx_colls_errs; + __le32 rx_runt_errs; + __le32 done_marker; }; enum Rx_ring_state_bits { @@ -1139,7 +1133,7 @@ speedo_rx_soft_reset(struct net_device *dev) rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; - rfd->rx_buf_addr = 0xffffffff; + rfd->rx_buf_addr = cpu_to_le32(0xffffffff); if (wait_for_cmd_done(dev, sp) != 0) { printk("%s: RxAbort command stalled\n", dev->name); @@ -1275,7 +1269,7 @@ speedo_init_rx_ring(struct net_device *dev) rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ /* This field unused by i82557. */ - rxf->rx_buf_addr = 0xffffffff; + rxf->rx_buf_addr = cpu_to_le32(0xffffffff); rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i], sizeof(struct RxFD), PCI_DMA_TODEVICE); @@ -1657,7 +1651,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); - rxf->rx_buf_addr = 0xffffffff; + rxf->rx_buf_addr = cpu_to_le32(0xffffffff); pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; @@ -1788,7 +1782,7 @@ speedo_rx(struct net_device *dev) /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], @@ -1933,7 +1927,7 @@ speedo_get_stats(struct net_device *dev) void __iomem *ioaddr = sp->regs; /* Update only if the previous dump finished. */ - if (sp->lstats->done_marker == le32_to_cpu(0xA007)) { + if (sp->lstats->done_marker == cpu_to_le32(0xA007)) { sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats->tx_coll16_errs); sp->stats.tx_window_errors += le32_to_cpu(sp->lstats->tx_late_colls); sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_underruns); @@ -2142,7 +2136,7 @@ static void set_rx_mode(struct net_device *dev) /* The simple case of 0-3 multicast list entries occurs often, and fits within one tx_ring[] entry. */ struct dev_mc_list *mclist; - u16 *setup_params, *eaddrs; + __le16 *setup_params, *eaddrs; spin_lock_irqsave(&sp->lock, flags); entry = sp->cur_tx++ % TX_RING_SIZE; @@ -2154,12 +2148,12 @@ static void set_rx_mode(struct net_device *dev) sp->tx_ring[entry].link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ - setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr; + setup_params = (__le16 *)&sp->tx_ring[entry].tx_desc_addr; *setup_params++ = cpu_to_le16(dev->mc_count*6); /* Fill in the multicast addresses. */ for (i = 0, mclist = dev->mc_list; i < dev->mc_count; i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; + eaddrs = (__le16 *)mclist->dmi_addr; *setup_params++ = *eaddrs++; *setup_params++ = *eaddrs++; *setup_params++ = *eaddrs++; @@ -2177,7 +2171,7 @@ static void set_rx_mode(struct net_device *dev) spin_unlock_irqrestore(&sp->lock, flags); } else if (new_rx_mode == 0) { struct dev_mc_list *mclist; - u16 *setup_params, *eaddrs; + __le16 *setup_params, *eaddrs; struct speedo_mc_block *mc_blk; struct descriptor *mc_setup_frm; int i; @@ -2204,12 +2198,12 @@ static void set_rx_mode(struct net_device *dev) mc_setup_frm->cmd_status = cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList); /* Link set below. */ - setup_params = (u16 *)&mc_setup_frm->params; + setup_params = (__le16 *)&mc_setup_frm->params; *setup_params++ = cpu_to_le16(dev->mc_count*6); /* Fill in the multicast addresses. */ for (i = 0, mclist = dev->mc_list; i < dev->mc_count; i++, mclist = mclist->next) { - eaddrs = (u16 *)mclist->dmi_addr; + eaddrs = (__le16 *)mclist->dmi_addr; *setup_params++ = *eaddrs++; *setup_params++ = *eaddrs++; *setup_params++ = *eaddrs++; diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 70509ed6c11d..d5459a8056b1 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -456,8 +456,9 @@ static int eexp_open(struct net_device *dev) if (!dev->irq || !irqrmap[dev->irq]) return -ENXIO; - ret = request_irq(dev->irq,&eexp_irq,0,dev->name,dev); - if (ret) return ret; + ret = request_irq(dev->irq, &eexp_irq, 0, dev->name, dev); + if (ret) + return ret; if (!request_region(ioaddr, EEXP_IO_EXTENT, "EtherExpress")) { printk(KERN_WARNING "EtherExpress io port %x, is busy.\n" @@ -768,7 +769,7 @@ static void eexp_cmd_clear(struct net_device *dev) } } -static irqreturn_t eexp_irq(int irq, void *dev_info) +static irqreturn_t eexp_irq(int dummy, void *dev_info) { struct net_device *dev = dev_info; struct net_local *lp; @@ -783,8 +784,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info) old_read_ptr = inw(ioaddr+READ_PTR); old_write_ptr = inw(ioaddr+WRITE_PTR); - outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ); - + outb(SIRQ_dis|irqrmap[dev->irq], ioaddr+SET_IRQ); status = scb_status(dev); @@ -851,7 +851,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info) eexp_cmd_clear(dev); - outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ); + outb(SIRQ_en|irqrmap[dev->irq], ioaddr+SET_IRQ); #if NET_DEBUG > 6 printk("%s: leaving eexp_irq()\n", dev->name); diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c new file mode 100644 index 000000000000..0809a6a5a286 --- /dev/null +++ b/drivers/net/enc28j60.c @@ -0,0 +1,1600 @@ +/* + * Microchip ENC28J60 ethernet driver (MAC + PHY) + * + * Copyright (C) 2007 Eurek srl + * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com> + * based on enc28j60.c written by David Anders for 2.4 kernel version + * + * 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. + * + * $Id: enc28j60.c,v 1.22 2007/12/20 10:47:01 claudio Exp $ + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/tcp.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/spi/spi.h> + +#include "enc28j60_hw.h" + +#define DRV_NAME "enc28j60" +#define DRV_VERSION "1.01" + +#define SPI_OPLEN 1 + +#define ENC28J60_MSG_DEFAULT \ + (NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK) + +/* Buffer size required for the largest SPI transfer (i.e., reading a + * frame). */ +#define SPI_TRANSFER_BUF_LEN (4 + MAX_FRAMELEN) + +#define TX_TIMEOUT (4 * HZ) + +/* Max TX retries in case of collision as suggested by errata datasheet */ +#define MAX_TX_RETRYCOUNT 16 + +enum { + RXFILTER_NORMAL, + RXFILTER_MULTI, + RXFILTER_PROMISC +}; + +/* Driver local data */ +struct enc28j60_net { + struct net_device *netdev; + struct spi_device *spi; + struct mutex lock; + struct sk_buff *tx_skb; + struct work_struct tx_work; + struct work_struct irq_work; + struct work_struct setrx_work; + struct work_struct restart_work; + u8 bank; /* current register bank selected */ + u16 next_pk_ptr; /* next packet pointer within FIFO */ + u16 max_pk_counter; /* statistics: max packet counter */ + u16 tx_retry_count; + bool hw_enable; + bool full_duplex; + int rxfilter; + u32 msg_enable; + u8 spi_transfer_buf[SPI_TRANSFER_BUF_LEN]; +}; + +/* use ethtool to change the level for any given device */ +static struct { + u32 msg_enable; +} debug = { -1 }; + +/* + * SPI read buffer + * wait for the SPI transfer and copy received data to destination + */ +static int +spi_read_buf(struct enc28j60_net *priv, int len, u8 *data) +{ + u8 *rx_buf = priv->spi_transfer_buf + 4; + u8 *tx_buf = priv->spi_transfer_buf; + struct spi_transfer t = { + .tx_buf = tx_buf, + .rx_buf = rx_buf, + .len = SPI_OPLEN + len, + }; + struct spi_message msg; + int ret; + + tx_buf[0] = ENC28J60_READ_BUF_MEM; + tx_buf[1] = tx_buf[2] = tx_buf[3] = 0; /* don't care */ + + spi_message_init(&msg); + spi_message_add_tail(&t, &msg); + ret = spi_sync(priv->spi, &msg); + if (ret == 0) { + memcpy(data, &rx_buf[SPI_OPLEN], len); + ret = msg.status; + } + if (ret && netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", + __FUNCTION__, ret); + + return ret; +} + +/* + * SPI write buffer + */ +static int spi_write_buf(struct enc28j60_net *priv, int len, + const u8 *data) +{ + int ret; + + if (len > SPI_TRANSFER_BUF_LEN - 1 || len <= 0) + ret = -EINVAL; + else { + priv->spi_transfer_buf[0] = ENC28J60_WRITE_BUF_MEM; + memcpy(&priv->spi_transfer_buf[1], data, len); + ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1); + if (ret && netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", + __FUNCTION__, ret); + } + return ret; +} + +/* + * basic SPI read operation + */ +static u8 spi_read_op(struct enc28j60_net *priv, u8 op, + u8 addr) +{ + u8 tx_buf[2]; + u8 rx_buf[4]; + u8 val = 0; + int ret; + int slen = SPI_OPLEN; + + /* do dummy read if needed */ + if (addr & SPRD_MASK) + slen++; + + tx_buf[0] = op | (addr & ADDR_MASK); + ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen); + if (ret) + printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", + __FUNCTION__, ret); + else + val = rx_buf[slen - 1]; + + return val; +} + +/* + * basic SPI write operation + */ +static int spi_write_op(struct enc28j60_net *priv, u8 op, + u8 addr, u8 val) +{ + int ret; + + priv->spi_transfer_buf[0] = op | (addr & ADDR_MASK); + priv->spi_transfer_buf[1] = val; + ret = spi_write(priv->spi, priv->spi_transfer_buf, 2); + if (ret && netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n", + __FUNCTION__, ret); + return ret; +} + +static void enc28j60_soft_reset(struct enc28j60_net *priv) +{ + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + + spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); + /* Errata workaround #1, CLKRDY check is unreliable, + * delay at least 1 mS instead */ + udelay(2000); +} + +/* + * select the current register bank if necessary + */ +static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr) +{ + if ((addr & BANK_MASK) != priv->bank) { + u8 b = (addr & BANK_MASK) >> 5; + + if (b != (ECON1_BSEL1 | ECON1_BSEL0)) + spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, + ECON1_BSEL1 | ECON1_BSEL0); + if (b != 0) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b); + priv->bank = (addr & BANK_MASK); + } +} + +/* + * Register access routines through the SPI bus. + * Every register access comes in two flavours: + * - nolock_xxx: caller needs to invoke mutex_lock, usually to access + * atomically more than one register + * - locked_xxx: caller doesn't need to invoke mutex_lock, single access + * + * Some registers can be accessed through the bit field clear and + * bit field set to avoid a read modify write cycle. + */ + +/* + * Register bit field Set + */ +static void nolock_reg_bfset(struct enc28j60_net *priv, + u8 addr, u8 mask) +{ + enc28j60_set_bank(priv, addr); + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, addr, mask); +} + +static void locked_reg_bfset(struct enc28j60_net *priv, + u8 addr, u8 mask) +{ + mutex_lock(&priv->lock); + nolock_reg_bfset(priv, addr, mask); + mutex_unlock(&priv->lock); +} + +/* + * Register bit field Clear + */ +static void nolock_reg_bfclr(struct enc28j60_net *priv, + u8 addr, u8 mask) +{ + enc28j60_set_bank(priv, addr); + spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, addr, mask); +} + +static void locked_reg_bfclr(struct enc28j60_net *priv, + u8 addr, u8 mask) +{ + mutex_lock(&priv->lock); + nolock_reg_bfclr(priv, addr, mask); + mutex_unlock(&priv->lock); +} + +/* + * Register byte read + */ +static int nolock_regb_read(struct enc28j60_net *priv, + u8 address) +{ + enc28j60_set_bank(priv, address); + return spi_read_op(priv, ENC28J60_READ_CTRL_REG, address); +} + +static int locked_regb_read(struct enc28j60_net *priv, + u8 address) +{ + int ret; + + mutex_lock(&priv->lock); + ret = nolock_regb_read(priv, address); + mutex_unlock(&priv->lock); + + return ret; +} + +/* + * Register word read + */ +static int nolock_regw_read(struct enc28j60_net *priv, + u8 address) +{ + int rl, rh; + + enc28j60_set_bank(priv, address); + rl = spi_read_op(priv, ENC28J60_READ_CTRL_REG, address); + rh = spi_read_op(priv, ENC28J60_READ_CTRL_REG, address + 1); + + return (rh << 8) | rl; +} + +static int locked_regw_read(struct enc28j60_net *priv, + u8 address) +{ + int ret; + + mutex_lock(&priv->lock); + ret = nolock_regw_read(priv, address); + mutex_unlock(&priv->lock); + + return ret; +} + +/* + * Register byte write + */ +static void nolock_regb_write(struct enc28j60_net *priv, + u8 address, u8 data) +{ + enc28j60_set_bank(priv, address); + spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address, data); +} + +static void locked_regb_write(struct enc28j60_net *priv, + u8 address, u8 data) +{ + mutex_lock(&priv->lock); + nolock_regb_write(priv, address, data); + mutex_unlock(&priv->lock); +} + +/* + * Register word write + */ +static void nolock_regw_write(struct enc28j60_net *priv, + u8 address, u16 data) +{ + enc28j60_set_bank(priv, address); + spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address, (u8) data); + spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, address + 1, + (u8) (data >> 8)); +} + +static void locked_regw_write(struct enc28j60_net *priv, + u8 address, u16 data) +{ + mutex_lock(&priv->lock); + nolock_regw_write(priv, address, data); + mutex_unlock(&priv->lock); +} + +/* + * Buffer memory read + * Select the starting address and execute a SPI buffer read + */ +static void enc28j60_mem_read(struct enc28j60_net *priv, + u16 addr, int len, u8 *data) +{ + mutex_lock(&priv->lock); + nolock_regw_write(priv, ERDPTL, addr); +#ifdef CONFIG_ENC28J60_WRITEVERIFY + if (netif_msg_drv(priv)) { + u16 reg; + reg = nolock_regw_read(priv, ERDPTL); + if (reg != addr) + printk(KERN_DEBUG DRV_NAME ": %s() error writing ERDPT " + "(0x%04x - 0x%04x)\n", __FUNCTION__, reg, addr); + } +#endif + spi_read_buf(priv, len, data); + mutex_unlock(&priv->lock); +} + +/* + * Write packet to enc28j60 TX buffer memory + */ +static void +enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data) +{ + mutex_lock(&priv->lock); + /* Set the write pointer to start of transmit buffer area */ + nolock_regw_write(priv, EWRPTL, TXSTART_INIT); +#ifdef CONFIG_ENC28J60_WRITEVERIFY + if (netif_msg_drv(priv)) { + u16 reg; + reg = nolock_regw_read(priv, EWRPTL); + if (reg != TXSTART_INIT) + printk(KERN_DEBUG DRV_NAME + ": %s() ERWPT:0x%04x != 0x%04x\n", + __FUNCTION__, reg, TXSTART_INIT); + } +#endif + /* Set the TXND pointer to correspond to the packet size given */ + nolock_regw_write(priv, ETXNDL, TXSTART_INIT + len); + /* write per-packet control byte */ + spi_write_op(priv, ENC28J60_WRITE_BUF_MEM, 0, 0x00); + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME + ": %s() after control byte ERWPT:0x%04x\n", + __FUNCTION__, nolock_regw_read(priv, EWRPTL)); + /* copy the packet into the transmit buffer */ + spi_write_buf(priv, len, data); + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME + ": %s() after write packet ERWPT:0x%04x, len=%d\n", + __FUNCTION__, nolock_regw_read(priv, EWRPTL), len); + mutex_unlock(&priv->lock); +} + +/* + * Wait until the PHY operation is complete. + */ +static int wait_phy_ready(struct enc28j60_net *priv) +{ + unsigned long timeout = jiffies + 20 * HZ / 1000; + int ret = 1; + + /* 20 msec timeout read */ + while (nolock_regb_read(priv, MISTAT) & MISTAT_BUSY) { + if (time_after(jiffies, timeout)) { + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME + ": PHY ready timeout!\n"); + ret = 0; + break; + } + cpu_relax(); + } + return ret; +} + +/* + * PHY register read + * PHY registers are not accessed directly, but through the MII + */ +static u16 enc28j60_phy_read(struct enc28j60_net *priv, u8 address) +{ + u16 ret; + + mutex_lock(&priv->lock); + /* set the PHY register address */ + nolock_regb_write(priv, MIREGADR, address); + /* start the register read operation */ + nolock_regb_write(priv, MICMD, MICMD_MIIRD); + /* wait until the PHY read completes */ + wait_phy_ready(priv); + /* quit reading */ + nolock_regb_write(priv, MICMD, 0x00); + /* return the data */ + ret = nolock_regw_read(priv, MIRDL); + mutex_unlock(&priv->lock); + + return ret; +} + +static int enc28j60_phy_write(struct enc28j60_net *priv, u8 address, u16 data) +{ + int ret; + + mutex_lock(&priv->lock); + /* set the PHY register address */ + nolock_regb_write(priv, MIREGADR, address); + /* write the PHY data */ + nolock_regw_write(priv, MIWRL, data); + /* wait until the PHY write completes and return */ + ret = wait_phy_ready(priv); + mutex_unlock(&priv->lock); + + return ret; +} + +/* + * Program the hardware MAC address from dev->dev_addr. + */ +static int enc28j60_set_hw_macaddr(struct net_device *ndev) +{ + int ret; + struct enc28j60_net *priv = netdev_priv(ndev); + + mutex_lock(&priv->lock); + if (!priv->hw_enable) { + if (netif_msg_drv(priv)) { + DECLARE_MAC_BUF(mac); + printk(KERN_INFO DRV_NAME + ": %s: Setting MAC address to %s\n", + ndev->name, print_mac(mac, ndev->dev_addr)); + } + /* NOTE: MAC address in ENC28J60 is byte-backward */ + nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]); + nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]); + nolock_regb_write(priv, MAADR3, ndev->dev_addr[2]); + nolock_regb_write(priv, MAADR2, ndev->dev_addr[3]); + nolock_regb_write(priv, MAADR1, ndev->dev_addr[4]); + nolock_regb_write(priv, MAADR0, ndev->dev_addr[5]); + ret = 0; + } else { + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME + ": %s() Hardware must be disabled to set " + "Mac address\n", __FUNCTION__); + ret = -EBUSY; + } + mutex_unlock(&priv->lock); + return ret; +} + +/* + * Store the new hardware address in dev->dev_addr, and update the MAC. + */ +static int enc28j60_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *address = addr; + + if (netif_running(dev)) + return -EBUSY; + if (!is_valid_ether_addr(address->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, address->sa_data, dev->addr_len); + return enc28j60_set_hw_macaddr(dev); +} + +/* + * Debug routine to dump useful register contents + */ +static void enc28j60_dump_regs(struct enc28j60_net *priv, const char *msg) +{ + mutex_lock(&priv->lock); + printk(KERN_DEBUG DRV_NAME " %s\n" + "HwRevID: 0x%02x\n" + "Cntrl: ECON1 ECON2 ESTAT EIR EIE\n" + " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n" + "MAC : MACON1 MACON3 MACON4\n" + " 0x%02x 0x%02x 0x%02x\n" + "Rx : ERXST ERXND ERXWRPT ERXRDPT ERXFCON EPKTCNT MAMXFL\n" + " 0x%04x 0x%04x 0x%04x 0x%04x " + "0x%02x 0x%02x 0x%04x\n" + "Tx : ETXST ETXND MACLCON1 MACLCON2 MAPHSUP\n" + " 0x%04x 0x%04x 0x%02x 0x%02x 0x%02x\n", + msg, nolock_regb_read(priv, EREVID), + nolock_regb_read(priv, ECON1), nolock_regb_read(priv, ECON2), + nolock_regb_read(priv, ESTAT), nolock_regb_read(priv, EIR), + nolock_regb_read(priv, EIE), nolock_regb_read(priv, MACON1), + nolock_regb_read(priv, MACON3), nolock_regb_read(priv, MACON4), + nolock_regw_read(priv, ERXSTL), nolock_regw_read(priv, ERXNDL), + nolock_regw_read(priv, ERXWRPTL), + nolock_regw_read(priv, ERXRDPTL), + nolock_regb_read(priv, ERXFCON), + nolock_regb_read(priv, EPKTCNT), + nolock_regw_read(priv, MAMXFLL), nolock_regw_read(priv, ETXSTL), + nolock_regw_read(priv, ETXNDL), + nolock_regb_read(priv, MACLCON1), + nolock_regb_read(priv, MACLCON2), + nolock_regb_read(priv, MAPHSUP)); + mutex_unlock(&priv->lock); +} + +/* + * ERXRDPT need to be set always at odd addresses, refer to errata datasheet + */ +static u16 erxrdpt_workaround(u16 next_packet_ptr, u16 start, u16 end) +{ + u16 erxrdpt; + + if ((next_packet_ptr - 1 < start) || (next_packet_ptr - 1 > end)) + erxrdpt = end; + else + erxrdpt = next_packet_ptr - 1; + + return erxrdpt; +} + +static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end) +{ + u16 erxrdpt; + + if (start > 0x1FFF || end > 0x1FFF || start > end) { + if (netif_msg_drv(priv)) + printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO " + "bad parameters!\n", __FUNCTION__, start, end); + return; + } + /* set receive buffer start + end */ + priv->next_pk_ptr = start; + nolock_regw_write(priv, ERXSTL, start); + erxrdpt = erxrdpt_workaround(priv->next_pk_ptr, start, end); + nolock_regw_write(priv, ERXRDPTL, erxrdpt); + nolock_regw_write(priv, ERXNDL, end); +} + +static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end) +{ + if (start > 0x1FFF || end > 0x1FFF || start > end) { + if (netif_msg_drv(priv)) + printk(KERN_ERR DRV_NAME ": %s(%d, %d) TXFIFO " + "bad parameters!\n", __FUNCTION__, start, end); + return; + } + /* set transmit buffer start + end */ + nolock_regw_write(priv, ETXSTL, start); + nolock_regw_write(priv, ETXNDL, end); +} + +static int enc28j60_hw_init(struct enc28j60_net *priv) +{ + u8 reg; + + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __FUNCTION__, + priv->full_duplex ? "FullDuplex" : "HalfDuplex"); + + mutex_lock(&priv->lock); + /* first reset the chip */ + enc28j60_soft_reset(priv); + /* Clear ECON1 */ + spi_write_op(priv, ENC28J60_WRITE_CTRL_REG, ECON1, 0x00); + priv->bank = 0; + priv->hw_enable = false; + priv->tx_retry_count = 0; + priv->max_pk_counter = 0; + priv->rxfilter = RXFILTER_NORMAL; + /* enable address auto increment */ + nolock_regb_write(priv, ECON2, ECON2_AUTOINC); + + nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT); + nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT); + mutex_unlock(&priv->lock); + + /* + * Check the RevID. + * If it's 0x00 or 0xFF probably the enc28j60 is not mounted or + * damaged + */ + reg = locked_regb_read(priv, EREVID); + if (netif_msg_drv(priv)) + printk(KERN_INFO DRV_NAME ": chip RevID: 0x%02x\n", reg); + if (reg == 0x00 || reg == 0xff) { + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() Invalid RevId %d\n", + __FUNCTION__, reg); + return 0; + } + + /* default filter mode: (unicast OR broadcast) AND crc valid */ + locked_regb_write(priv, ERXFCON, + ERXFCON_UCEN | ERXFCON_CRCEN | ERXFCON_BCEN); + + /* enable MAC receive */ + locked_regb_write(priv, MACON1, + MACON1_MARXEN | MACON1_TXPAUS | MACON1_RXPAUS); + /* enable automatic padding and CRC operations */ + if (priv->full_duplex) { + locked_regb_write(priv, MACON3, + MACON3_PADCFG0 | MACON3_TXCRCEN | + MACON3_FRMLNEN | MACON3_FULDPX); + /* set inter-frame gap (non-back-to-back) */ + locked_regb_write(priv, MAIPGL, 0x12); + /* set inter-frame gap (back-to-back) */ + locked_regb_write(priv, MABBIPG, 0x15); + } else { + locked_regb_write(priv, MACON3, + MACON3_PADCFG0 | MACON3_TXCRCEN | + MACON3_FRMLNEN); + locked_regb_write(priv, MACON4, 1 << 6); /* DEFER bit */ + /* set inter-frame gap (non-back-to-back) */ + locked_regw_write(priv, MAIPGL, 0x0C12); + /* set inter-frame gap (back-to-back) */ + locked_regb_write(priv, MABBIPG, 0x12); + } + /* + * MACLCON1 (default) + * MACLCON2 (default) + * Set the maximum packet size which the controller will accept + */ + locked_regw_write(priv, MAMXFLL, MAX_FRAMELEN); + + /* Configure LEDs */ + if (!enc28j60_phy_write(priv, PHLCON, ENC28J60_LAMPS_MODE)) + return 0; + + if (priv->full_duplex) { + if (!enc28j60_phy_write(priv, PHCON1, PHCON1_PDPXMD)) + return 0; + if (!enc28j60_phy_write(priv, PHCON2, 0x00)) + return 0; + } else { + if (!enc28j60_phy_write(priv, PHCON1, 0x00)) + return 0; + if (!enc28j60_phy_write(priv, PHCON2, PHCON2_HDLDIS)) + return 0; + } + if (netif_msg_hw(priv)) + enc28j60_dump_regs(priv, "Hw initialized."); + + return 1; +} + +static void enc28j60_hw_enable(struct enc28j60_net *priv) +{ + /* enable interrutps */ + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n", + __FUNCTION__); + + enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE); + + mutex_lock(&priv->lock); + nolock_reg_bfclr(priv, EIR, EIR_DMAIF | EIR_LINKIF | + EIR_TXIF | EIR_TXERIF | EIR_RXERIF | EIR_PKTIF); + nolock_regb_write(priv, EIE, EIE_INTIE | EIE_PKTIE | EIE_LINKIE | + EIE_TXIE | EIE_TXERIE | EIE_RXERIE); + + /* enable receive logic */ + nolock_reg_bfset(priv, ECON1, ECON1_RXEN); + priv->hw_enable = true; + mutex_unlock(&priv->lock); +} + +static void enc28j60_hw_disable(struct enc28j60_net *priv) +{ + mutex_lock(&priv->lock); + /* disable interrutps and packet reception */ + nolock_regb_write(priv, EIE, 0x00); + nolock_reg_bfclr(priv, ECON1, ECON1_RXEN); + priv->hw_enable = false; + mutex_unlock(&priv->lock); +} + +static int +enc28j60_setlink(struct net_device *ndev, u8 autoneg, u16 speed, u8 duplex) +{ + struct enc28j60_net *priv = netdev_priv(ndev); + int ret = 0; + + if (!priv->hw_enable) { + if (autoneg == AUTONEG_DISABLE && speed == SPEED_10) { + priv->full_duplex = (duplex == DUPLEX_FULL); + if (!enc28j60_hw_init(priv)) { + if (netif_msg_drv(priv)) + dev_err(&ndev->dev, + "hw_reset() failed\n"); + ret = -EINVAL; + } + } else { + if (netif_msg_link(priv)) + dev_warn(&ndev->dev, + "unsupported link setting\n"); + ret = -EOPNOTSUPP; + } + } else { + if (netif_msg_link(priv)) + dev_warn(&ndev->dev, "Warning: hw must be disabled " + "to set link mode\n"); + ret = -EBUSY; + } + return ret; +} + +/* + * Read the Transmit Status Vector + */ +static void enc28j60_read_tsv(struct enc28j60_net *priv, u8 tsv[TSV_SIZE]) +{ + int endptr; + + endptr = locked_regw_read(priv, ETXNDL); + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME ": reading TSV at addr:0x%04x\n", + endptr + 1); + enc28j60_mem_read(priv, endptr + 1, sizeof(tsv), tsv); +} + +static void enc28j60_dump_tsv(struct enc28j60_net *priv, const char *msg, + u8 tsv[TSV_SIZE]) +{ + u16 tmp1, tmp2; + + printk(KERN_DEBUG DRV_NAME ": %s - TSV:\n", msg); + tmp1 = tsv[1]; + tmp1 <<= 8; + tmp1 |= tsv[0]; + + tmp2 = tsv[5]; + tmp2 <<= 8; + tmp2 |= tsv[4]; + + printk(KERN_DEBUG DRV_NAME ": ByteCount: %d, CollisionCount: %d," + " TotByteOnWire: %d\n", tmp1, tsv[2] & 0x0f, tmp2); + printk(KERN_DEBUG DRV_NAME ": TxDone: %d, CRCErr:%d, LenChkErr: %d," + " LenOutOfRange: %d\n", TSV_GETBIT(tsv, TSV_TXDONE), + TSV_GETBIT(tsv, TSV_TXCRCERROR), + TSV_GETBIT(tsv, TSV_TXLENCHKERROR), + TSV_GETBIT(tsv, TSV_TXLENOUTOFRANGE)); + printk(KERN_DEBUG DRV_NAME ": Multicast: %d, Broadcast: %d, " + "PacketDefer: %d, ExDefer: %d\n", + TSV_GETBIT(tsv, TSV_TXMULTICAST), + TSV_GETBIT(tsv, TSV_TXBROADCAST), + TSV_GETBIT(tsv, TSV_TXPACKETDEFER), + TSV_GETBIT(tsv, TSV_TXEXDEFER)); + printk(KERN_DEBUG DRV_NAME ": ExCollision: %d, LateCollision: %d, " + "Giant: %d, Underrun: %d\n", + TSV_GETBIT(tsv, TSV_TXEXCOLLISION), + TSV_GETBIT(tsv, TSV_TXLATECOLLISION), + TSV_GETBIT(tsv, TSV_TXGIANT), TSV_GETBIT(tsv, TSV_TXUNDERRUN)); + printk(KERN_DEBUG DRV_NAME ": ControlFrame: %d, PauseFrame: %d, " + "BackPressApp: %d, VLanTagFrame: %d\n", + TSV_GETBIT(tsv, TSV_TXCONTROLFRAME), + TSV_GETBIT(tsv, TSV_TXPAUSEFRAME), + TSV_GETBIT(tsv, TSV_BACKPRESSUREAPP), + TSV_GETBIT(tsv, TSV_TXVLANTAGFRAME)); +} + +/* + * Receive Status vector + */ +static void enc28j60_dump_rsv(struct enc28j60_net *priv, const char *msg, + u16 pk_ptr, int len, u16 sts) +{ + printk(KERN_DEBUG DRV_NAME ": %s - NextPk: 0x%04x - RSV:\n", + msg, pk_ptr); + printk(KERN_DEBUG DRV_NAME ": ByteCount: %d, DribbleNibble: %d\n", len, + RSV_GETBIT(sts, RSV_DRIBBLENIBBLE)); + printk(KERN_DEBUG DRV_NAME ": RxOK: %d, CRCErr:%d, LenChkErr: %d," + " LenOutOfRange: %d\n", RSV_GETBIT(sts, RSV_RXOK), + RSV_GETBIT(sts, RSV_CRCERROR), + RSV_GETBIT(sts, RSV_LENCHECKERR), + RSV_GETBIT(sts, RSV_LENOUTOFRANGE)); + printk(KERN_DEBUG DRV_NAME ": Multicast: %d, Broadcast: %d, " + "LongDropEvent: %d, CarrierEvent: %d\n", + RSV_GETBIT(sts, RSV_RXMULTICAST), + RSV_GETBIT(sts, RSV_RXBROADCAST), + RSV_GETBIT(sts, RSV_RXLONGEVDROPEV), + RSV_GETBIT(sts, RSV_CARRIEREV)); + printk(KERN_DEBUG DRV_NAME ": ControlFrame: %d, PauseFrame: %d," + " UnknownOp: %d, VLanTagFrame: %d\n", + RSV_GETBIT(sts, RSV_RXCONTROLFRAME), + RSV_GETBIT(sts, RSV_RXPAUSEFRAME), + RSV_GETBIT(sts, RSV_RXUNKNOWNOPCODE), + RSV_GETBIT(sts, RSV_RXTYPEVLAN)); +} + +static void dump_packet(const char *msg, int len, const char *data) +{ + printk(KERN_DEBUG DRV_NAME ": %s - packet len:%d\n", msg, len); + print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1, + data, len, true); +} + +/* + * Hardware receive function. + * Read the buffer memory, update the FIFO pointer to free the buffer, + * check the status vector and decrement the packet counter. + */ +static void enc28j60_hw_rx(struct net_device *ndev) +{ + struct enc28j60_net *priv = netdev_priv(ndev); + struct sk_buff *skb = NULL; + u16 erxrdpt, next_packet, rxstat; + u8 rsv[RSV_SIZE]; + int len; + + if (netif_msg_rx_status(priv)) + printk(KERN_DEBUG DRV_NAME ": RX pk_addr:0x%04x\n", + priv->next_pk_ptr); + + if (unlikely(priv->next_pk_ptr > RXEND_INIT)) { + if (netif_msg_rx_err(priv)) + dev_err(&ndev->dev, + "%s() Invalid packet address!! 0x%04x\n", + __FUNCTION__, priv->next_pk_ptr); + /* packet address corrupted: reset RX logic */ + mutex_lock(&priv->lock); + nolock_reg_bfclr(priv, ECON1, ECON1_RXEN); + nolock_reg_bfset(priv, ECON1, ECON1_RXRST); + nolock_reg_bfclr(priv, ECON1, ECON1_RXRST); + nolock_rxfifo_init(priv, RXSTART_INIT, RXEND_INIT); + nolock_reg_bfclr(priv, EIR, EIR_RXERIF); + nolock_reg_bfset(priv, ECON1, ECON1_RXEN); + mutex_unlock(&priv->lock); + ndev->stats.rx_errors++; + return; + } + /* Read next packet pointer and rx status vector */ + enc28j60_mem_read(priv, priv->next_pk_ptr, sizeof(rsv), rsv); + + next_packet = rsv[1]; + next_packet <<= 8; + next_packet |= rsv[0]; + + len = rsv[3]; + len <<= 8; + len |= rsv[2]; + + rxstat = rsv[5]; + rxstat <<= 8; + rxstat |= rsv[4]; + + if (netif_msg_rx_status(priv)) + enc28j60_dump_rsv(priv, __FUNCTION__, next_packet, len, rxstat); + + if (!RSV_GETBIT(rxstat, RSV_RXOK)) { + if (netif_msg_rx_err(priv)) + dev_err(&ndev->dev, "Rx Error (%04x)\n", rxstat); + ndev->stats.rx_errors++; + if (RSV_GETBIT(rxstat, RSV_CRCERROR)) + ndev->stats.rx_crc_errors++; + if (RSV_GETBIT(rxstat, RSV_LENCHECKERR)) + ndev->stats.rx_frame_errors++; + } else { + skb = dev_alloc_skb(len); + if (!skb) { + if (netif_msg_rx_err(priv)) + dev_err(&ndev->dev, + "out of memory for Rx'd frame\n"); + ndev->stats.rx_dropped++; + } else { + skb->dev = ndev; + /* copy the packet from the receive buffer */ + enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv), + len, skb_put(skb, len)); + if (netif_msg_pktdata(priv)) + dump_packet(__FUNCTION__, skb->len, skb->data); + skb->protocol = eth_type_trans(skb, ndev); + /* update statistics */ + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + ndev->last_rx = jiffies; + netif_rx(skb); + } + } + /* + * Move the RX read pointer to the start of the next + * received packet. + * This frees the memory we just read out + */ + erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT); + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n", + __FUNCTION__, erxrdpt); + + mutex_lock(&priv->lock); + nolock_regw_write(priv, ERXRDPTL, erxrdpt); +#ifdef CONFIG_ENC28J60_WRITEVERIFY + if (netif_msg_drv(priv)) { + u16 reg; + reg = nolock_regw_read(priv, ERXRDPTL); + if (reg != erxrdpt) + printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT verify " + "error (0x%04x - 0x%04x)\n", __FUNCTION__, + reg, erxrdpt); + } +#endif + priv->next_pk_ptr = next_packet; + /* we are done with this packet, decrement the packet counter */ + nolock_reg_bfset(priv, ECON2, ECON2_PKTDEC); + mutex_unlock(&priv->lock); +} + +/* + * Calculate free space in RxFIFO + */ +static int enc28j60_get_free_rxfifo(struct enc28j60_net *priv) +{ + int epkcnt, erxst, erxnd, erxwr, erxrd; + int free_space; + + mutex_lock(&priv->lock); + epkcnt = nolock_regb_read(priv, EPKTCNT); + if (epkcnt >= 255) + free_space = -1; + else { + erxst = nolock_regw_read(priv, ERXSTL); + erxnd = nolock_regw_read(priv, ERXNDL); + erxwr = nolock_regw_read(priv, ERXWRPTL); + erxrd = nolock_regw_read(priv, ERXRDPTL); + + if (erxwr > erxrd) + free_space = (erxnd - erxst) - (erxwr - erxrd); + else if (erxwr == erxrd) + free_space = (erxnd - erxst); + else + free_space = erxrd - erxwr - 1; + } + mutex_unlock(&priv->lock); + if (netif_msg_rx_status(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() free_space = %d\n", + __FUNCTION__, free_space); + return free_space; +} + +/* + * Access the PHY to determine link status + */ +static void enc28j60_check_link_status(struct net_device *ndev) +{ + struct enc28j60_net *priv = netdev_priv(ndev); + u16 reg; + int duplex; + + reg = enc28j60_phy_read(priv, PHSTAT2); + if (netif_msg_hw(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() PHSTAT1: %04x, " + "PHSTAT2: %04x\n", __FUNCTION__, + enc28j60_phy_read(priv, PHSTAT1), reg); + duplex = reg & PHSTAT2_DPXSTAT; + + if (reg & PHSTAT2_LSTAT) { + netif_carrier_on(ndev); + if (netif_msg_ifup(priv)) + dev_info(&ndev->dev, "link up - %s\n", + duplex ? "Full duplex" : "Half duplex"); + } else { + if (netif_msg_ifdown(priv)) + dev_info(&ndev->dev, "link down\n"); + netif_carrier_off(ndev); + } +} + +static void enc28j60_tx_clear(struct net_device *ndev, bool err) +{ + struct enc28j60_net *priv = netdev_priv(ndev); + + if (err) + ndev->stats.tx_errors++; + else + ndev->stats.tx_packets++; + + if (priv->tx_skb) { + if (!err) + ndev->stats.tx_bytes += priv->tx_skb->len; + dev_kfree_skb(priv->tx_skb); + priv->tx_skb = NULL; + } + locked_reg_bfclr(priv, ECON1, ECON1_TXRTS); + netif_wake_queue(ndev); +} + +/* + * RX handler + * ignore PKTIF because is unreliable! (look at the errata datasheet) + * check EPKTCNT is the suggested workaround. + * We don't need to clear interrupt flag, automatically done when + * enc28j60_hw_rx() decrements the packet counter. + * Returns how many packet processed. + */ +static int enc28j60_rx_interrupt(struct net_device *ndev) +{ + struct enc28j60_net *priv = netdev_priv(ndev); + int pk_counter, ret; + + pk_counter = locked_regb_read(priv, EPKTCNT); + if (pk_counter && netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME ": intRX, pk_cnt: %d\n", pk_counter); + if (pk_counter > priv->max_pk_counter) { + /* update statistics */ + priv->max_pk_counter = pk_counter; + if (netif_msg_rx_status(priv) && priv->max_pk_counter > 1) + printk(KERN_DEBUG DRV_NAME ": RX max_pk_cnt: %d\n", + priv->max_pk_counter); + } + ret = pk_counter; + while (pk_counter-- > 0) + enc28j60_hw_rx(ndev); + + return ret; +} + +static void enc28j60_irq_work_handler(struct work_struct *work) +{ + struct enc28j60_net *priv = + container_of(work, struct enc28j60_net, irq_work); + struct net_device *ndev = priv->netdev; + int intflags, loop; + + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + /* disable further interrupts */ + locked_reg_bfclr(priv, EIE, EIE_INTIE); + + do { + loop = 0; + intflags = locked_regb_read(priv, EIR); + /* DMA interrupt handler (not currently used) */ + if ((intflags & EIR_DMAIF) != 0) { + loop++; + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME + ": intDMA(%d)\n", loop); + locked_reg_bfclr(priv, EIR, EIR_DMAIF); + } + /* LINK changed handler */ + if ((intflags & EIR_LINKIF) != 0) { + loop++; + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME + ": intLINK(%d)\n", loop); + enc28j60_check_link_status(ndev); + /* read PHIR to clear the flag */ + enc28j60_phy_read(priv, PHIR); + } + /* TX complete handler */ + if ((intflags & EIR_TXIF) != 0) { + bool err = false; + loop++; + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME + ": intTX(%d)\n", loop); + priv->tx_retry_count = 0; + if (locked_regb_read(priv, ESTAT) & ESTAT_TXABRT) { + if (netif_msg_tx_err(priv)) + dev_err(&ndev->dev, + "Tx Error (aborted)\n"); + err = true; + } + if (netif_msg_tx_done(priv)) { + u8 tsv[TSV_SIZE]; + enc28j60_read_tsv(priv, tsv); + enc28j60_dump_tsv(priv, "Tx Done", tsv); + } + enc28j60_tx_clear(ndev, err); + locked_reg_bfclr(priv, EIR, EIR_TXIF); + } + /* TX Error handler */ + if ((intflags & EIR_TXERIF) != 0) { + u8 tsv[TSV_SIZE]; + + loop++; + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME + ": intTXErr(%d)\n", loop); + locked_reg_bfclr(priv, ECON1, ECON1_TXRTS); + enc28j60_read_tsv(priv, tsv); + if (netif_msg_tx_err(priv)) + enc28j60_dump_tsv(priv, "Tx Error", tsv); + /* Reset TX logic */ + mutex_lock(&priv->lock); + nolock_reg_bfset(priv, ECON1, ECON1_TXRST); + nolock_reg_bfclr(priv, ECON1, ECON1_TXRST); + nolock_txfifo_init(priv, TXSTART_INIT, TXEND_INIT); + mutex_unlock(&priv->lock); + /* Transmit Late collision check for retransmit */ + if (TSV_GETBIT(tsv, TSV_TXLATECOLLISION)) { + if (netif_msg_tx_err(priv)) + printk(KERN_DEBUG DRV_NAME + ": LateCollision TXErr (%d)\n", + priv->tx_retry_count); + if (priv->tx_retry_count++ < MAX_TX_RETRYCOUNT) + locked_reg_bfset(priv, ECON1, + ECON1_TXRTS); + else + enc28j60_tx_clear(ndev, true); + } else + enc28j60_tx_clear(ndev, true); + locked_reg_bfclr(priv, EIR, EIR_TXERIF); + } + /* RX Error handler */ + if ((intflags & EIR_RXERIF) != 0) { + loop++; + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME + ": intRXErr(%d)\n", loop); + /* Check free FIFO space to flag RX overrun */ + if (enc28j60_get_free_rxfifo(priv) <= 0) { + if (netif_msg_rx_err(priv)) + printk(KERN_DEBUG DRV_NAME + ": RX Overrun\n"); + ndev->stats.rx_dropped++; + } + locked_reg_bfclr(priv, EIR, EIR_RXERIF); + } + /* RX handler */ + if (enc28j60_rx_interrupt(ndev)) + loop++; + } while (loop); + + /* re-enable interrupts */ + locked_reg_bfset(priv, EIE, EIE_INTIE); + if (netif_msg_intr(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __FUNCTION__); +} + +/* + * Hardware transmit function. + * Fill the buffer memory and send the contents of the transmit buffer + * onto the network + */ +static void enc28j60_hw_tx(struct enc28j60_net *priv) +{ + if (netif_msg_tx_queued(priv)) + printk(KERN_DEBUG DRV_NAME + ": Tx Packet Len:%d\n", priv->tx_skb->len); + + if (netif_msg_pktdata(priv)) + dump_packet(__FUNCTION__, + priv->tx_skb->len, priv->tx_skb->data); + enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data); + +#ifdef CONFIG_ENC28J60_WRITEVERIFY + /* readback and verify written data */ + if (netif_msg_drv(priv)) { + int test_len, k; + u8 test_buf[64]; /* limit the test to the first 64 bytes */ + int okflag; + + test_len = priv->tx_skb->len; + if (test_len > sizeof(test_buf)) + test_len = sizeof(test_buf); + + /* + 1 to skip control byte */ + enc28j60_mem_read(priv, TXSTART_INIT + 1, test_len, test_buf); + okflag = 1; + for (k = 0; k < test_len; k++) { + if (priv->tx_skb->data[k] != test_buf[k]) { + printk(KERN_DEBUG DRV_NAME + ": Error, %d location differ: " + "0x%02x-0x%02x\n", k, + priv->tx_skb->data[k], test_buf[k]); + okflag = 0; + } + } + if (!okflag) + printk(KERN_DEBUG DRV_NAME ": Tx write buffer, " + "verify ERROR!\n"); + } +#endif + /* set TX request flag */ + locked_reg_bfset(priv, ECON1, ECON1_TXRTS); +} + +static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct enc28j60_net *priv = netdev_priv(dev); + + if (netif_msg_tx_queued(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + + /* If some error occurs while trying to transmit this + * packet, you should return '1' from this function. + * In such a case you _may not_ do anything to the + * SKB, it is still owned by the network queueing + * layer when an error is returned. This means you + * may not modify any SKB fields, you may not free + * the SKB, etc. + */ + netif_stop_queue(dev); + + /* save the timestamp */ + priv->netdev->trans_start = jiffies; + /* Remember the skb for deferred processing */ + priv->tx_skb = skb; + schedule_work(&priv->tx_work); + + return 0; +} + +static void enc28j60_tx_work_handler(struct work_struct *work) +{ + struct enc28j60_net *priv = + container_of(work, struct enc28j60_net, tx_work); + + /* actual delivery of data */ + enc28j60_hw_tx(priv); +} + +static irqreturn_t enc28j60_irq(int irq, void *dev_id) +{ + struct enc28j60_net *priv = dev_id; + + /* + * Can't do anything in interrupt context because we need to + * block (spi_sync() is blocking) so fire of the interrupt + * handling workqueue. + * Remember that we access enc28j60 registers through SPI bus + * via spi_sync() call. + */ + schedule_work(&priv->irq_work); + + return IRQ_HANDLED; +} + +static void enc28j60_tx_timeout(struct net_device *ndev) +{ + struct enc28j60_net *priv = netdev_priv(ndev); + + if (netif_msg_timer(priv)) + dev_err(&ndev->dev, DRV_NAME " tx timeout\n"); + + ndev->stats.tx_errors++; + /* can't restart safely under softirq */ + schedule_work(&priv->restart_work); +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int enc28j60_net_open(struct net_device *dev) +{ + struct enc28j60_net *priv = netdev_priv(dev); + + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + + if (!is_valid_ether_addr(dev->dev_addr)) { + if (netif_msg_ifup(priv)) { + DECLARE_MAC_BUF(mac); + dev_err(&dev->dev, "invalid MAC address %s\n", + print_mac(mac, dev->dev_addr)); + } + return -EADDRNOTAVAIL; + } + /* Reset the hardware here */ + enc28j60_hw_disable(priv); + if (!enc28j60_hw_init(priv)) { + if (netif_msg_ifup(priv)) + dev_err(&dev->dev, "hw_reset() failed\n"); + return -EINVAL; + } + /* Update the MAC address (in case user has changed it) */ + enc28j60_set_hw_macaddr(dev); + /* Enable interrupts */ + enc28j60_hw_enable(priv); + /* check link status */ + enc28j60_check_link_status(dev); + /* We are now ready to accept transmit requests from + * the queueing layer of the networking. + */ + netif_start_queue(dev); + + return 0; +} + +/* The inverse routine to net_open(). */ +static int enc28j60_net_close(struct net_device *dev) +{ + struct enc28j60_net *priv = netdev_priv(dev); + + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__); + + enc28j60_hw_disable(priv); + netif_stop_queue(dev); + + return 0; +} + +/* + * Set or clear the multicast filter for this adapter + * num_addrs == -1 Promiscuous mode, receive all packets + * num_addrs == 0 Normal mode, filter out multicast packets + * num_addrs > 0 Multicast mode, receive normal and MC packets + */ +static void enc28j60_set_multicast_list(struct net_device *dev) +{ + struct enc28j60_net *priv = netdev_priv(dev); + int oldfilter = priv->rxfilter; + + if (dev->flags & IFF_PROMISC) { + if (netif_msg_link(priv)) + dev_info(&dev->dev, "promiscuous mode\n"); + priv->rxfilter = RXFILTER_PROMISC; + } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count) { + if (netif_msg_link(priv)) + dev_info(&dev->dev, "%smulticast mode\n", + (dev->flags & IFF_ALLMULTI) ? "all-" : ""); + priv->rxfilter = RXFILTER_MULTI; + } else { + if (netif_msg_link(priv)) + dev_info(&dev->dev, "normal mode\n"); + priv->rxfilter = RXFILTER_NORMAL; + } + + if (oldfilter != priv->rxfilter) + schedule_work(&priv->setrx_work); +} + +static void enc28j60_setrx_work_handler(struct work_struct *work) +{ + struct enc28j60_net *priv = + container_of(work, struct enc28j60_net, setrx_work); + + if (priv->rxfilter == RXFILTER_PROMISC) { + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": promiscuous mode\n"); + locked_regb_write(priv, ERXFCON, 0x00); + } else if (priv->rxfilter == RXFILTER_MULTI) { + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": multicast mode\n"); + locked_regb_write(priv, ERXFCON, + ERXFCON_UCEN | ERXFCON_CRCEN | + ERXFCON_BCEN | ERXFCON_MCEN); + } else { + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": normal mode\n"); + locked_regb_write(priv, ERXFCON, + ERXFCON_UCEN | ERXFCON_CRCEN | + ERXFCON_BCEN); + } +} + +static void enc28j60_restart_work_handler(struct work_struct *work) +{ + struct enc28j60_net *priv = + container_of(work, struct enc28j60_net, restart_work); + struct net_device *ndev = priv->netdev; + int ret; + + rtnl_lock(); + if (netif_running(ndev)) { + enc28j60_net_close(ndev); + ret = enc28j60_net_open(ndev); + if (unlikely(ret)) { + dev_info(&ndev->dev, " could not restart %d\n", ret); + dev_close(ndev); + } + } + rtnl_unlock(); +} + +/* ......................... ETHTOOL SUPPORT ........................... */ + +static void +enc28j60_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, + dev->dev.parent->bus_id, sizeof(info->bus_info)); +} + +static int +enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct enc28j60_net *priv = netdev_priv(dev); + + cmd->transceiver = XCVR_INTERNAL; + cmd->supported = SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_TP; + cmd->speed = SPEED_10; + cmd->duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + cmd->port = PORT_TP; + cmd->autoneg = AUTONEG_DISABLE; + + return 0; +} + +static int +enc28j60_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + return enc28j60_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex); +} + +static u32 enc28j60_get_msglevel(struct net_device *dev) +{ + struct enc28j60_net *priv = netdev_priv(dev); + return priv->msg_enable; +} + +static void enc28j60_set_msglevel(struct net_device *dev, u32 val) +{ + struct enc28j60_net *priv = netdev_priv(dev); + priv->msg_enable = val; +} + +static const struct ethtool_ops enc28j60_ethtool_ops = { + .get_settings = enc28j60_get_settings, + .set_settings = enc28j60_set_settings, + .get_drvinfo = enc28j60_get_drvinfo, + .get_msglevel = enc28j60_get_msglevel, + .set_msglevel = enc28j60_set_msglevel, +}; + +static int enc28j60_chipset_init(struct net_device *dev) +{ + struct enc28j60_net *priv = netdev_priv(dev); + + return enc28j60_hw_init(priv); +} + +static int __devinit enc28j60_probe(struct spi_device *spi) +{ + struct net_device *dev; + struct enc28j60_net *priv; + int ret = 0; + + if (netif_msg_drv(&debug)) + dev_info(&spi->dev, DRV_NAME " Ethernet driver %s loaded\n", + DRV_VERSION); + + dev = alloc_etherdev(sizeof(struct enc28j60_net)); + if (!dev) { + if (netif_msg_drv(&debug)) + dev_err(&spi->dev, DRV_NAME + ": unable to alloc new ethernet\n"); + ret = -ENOMEM; + goto error_alloc; + } + priv = netdev_priv(dev); + + priv->netdev = dev; /* priv to netdev reference */ + priv->spi = spi; /* priv to spi reference */ + priv->msg_enable = netif_msg_init(debug.msg_enable, + ENC28J60_MSG_DEFAULT); + mutex_init(&priv->lock); + INIT_WORK(&priv->tx_work, enc28j60_tx_work_handler); + INIT_WORK(&priv->setrx_work, enc28j60_setrx_work_handler); + INIT_WORK(&priv->irq_work, enc28j60_irq_work_handler); + INIT_WORK(&priv->restart_work, enc28j60_restart_work_handler); + dev_set_drvdata(&spi->dev, priv); /* spi to priv reference */ + SET_NETDEV_DEV(dev, &spi->dev); + + if (!enc28j60_chipset_init(dev)) { + if (netif_msg_probe(priv)) + dev_info(&spi->dev, DRV_NAME " chip not found\n"); + ret = -EIO; + goto error_irq; + } + random_ether_addr(dev->dev_addr); + enc28j60_set_hw_macaddr(dev); + + ret = request_irq(spi->irq, enc28j60_irq, IRQF_TRIGGER_FALLING, + DRV_NAME, priv); + if (ret < 0) { + if (netif_msg_probe(priv)) + dev_err(&spi->dev, DRV_NAME ": request irq %d failed " + "(ret = %d)\n", spi->irq, ret); + goto error_irq; + } + + dev->if_port = IF_PORT_10BASET; + dev->irq = spi->irq; + dev->open = enc28j60_net_open; + dev->stop = enc28j60_net_close; + dev->hard_start_xmit = enc28j60_send_packet; + dev->set_multicast_list = &enc28j60_set_multicast_list; + dev->set_mac_address = enc28j60_set_mac_address; + dev->tx_timeout = &enc28j60_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops); + + ret = register_netdev(dev); + if (ret) { + if (netif_msg_probe(priv)) + dev_err(&spi->dev, "register netdev " DRV_NAME + " failed (ret = %d)\n", ret); + goto error_register; + } + dev_info(&dev->dev, DRV_NAME " driver registered\n"); + + return 0; + +error_register: + free_irq(spi->irq, priv); +error_irq: + free_netdev(dev); +error_alloc: + return ret; +} + +static int enc28j60_remove(struct spi_device *spi) +{ + struct enc28j60_net *priv = dev_get_drvdata(&spi->dev); + + if (netif_msg_drv(priv)) + printk(KERN_DEBUG DRV_NAME ": remove\n"); + + unregister_netdev(priv->netdev); + free_irq(spi->irq, priv); + free_netdev(priv->netdev); + + return 0; +} + +static struct spi_driver enc28j60_driver = { + .driver = { + .name = DRV_NAME, + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = enc28j60_probe, + .remove = __devexit_p(enc28j60_remove), +}; + +static int __init enc28j60_init(void) +{ + return spi_register_driver(&enc28j60_driver); +} + +module_init(enc28j60_init); + +static void __exit enc28j60_exit(void) +{ + spi_unregister_driver(&enc28j60_driver); +} + +module_exit(enc28j60_exit); + +MODULE_DESCRIPTION(DRV_NAME " ethernet driver"); +MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>"); +MODULE_LICENSE("GPL"); +module_param_named(debug, debug.msg_enable, int, 0); +MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., ffff=all)"); diff --git a/drivers/net/enc28j60_hw.h b/drivers/net/enc28j60_hw.h new file mode 100644 index 000000000000..1a0b20969f80 --- /dev/null +++ b/drivers/net/enc28j60_hw.h @@ -0,0 +1,309 @@ +/* + * enc28j60_hw.h: EDTP FrameThrower style enc28j60 registers + * + * $Id: enc28j60_hw.h,v 1.9 2007/12/14 11:59:16 claudio Exp $ + */ + +#ifndef _ENC28J60_HW_H +#define _ENC28J60_HW_H + +/* + * ENC28J60 Control Registers + * Control register definitions are a combination of address, + * bank number, and Ethernet/MAC/PHY indicator bits. + * - Register address (bits 0-4) + * - Bank number (bits 5-6) + * - MAC/MII indicator (bit 7) + */ +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 +/* All-bank registers */ +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F +/* Bank 0 registers */ +#define ERDPTL (0x00|0x00) +#define ERDPTH (0x01|0x00) +#define EWRPTL (0x02|0x00) +#define EWRPTH (0x03|0x00) +#define ETXSTL (0x04|0x00) +#define ETXSTH (0x05|0x00) +#define ETXNDL (0x06|0x00) +#define ETXNDH (0x07|0x00) +#define ERXSTL (0x08|0x00) +#define ERXSTH (0x09|0x00) +#define ERXNDL (0x0A|0x00) +#define ERXNDH (0x0B|0x00) +#define ERXRDPTL (0x0C|0x00) +#define ERXRDPTH (0x0D|0x00) +#define ERXWRPTL (0x0E|0x00) +#define ERXWRPTH (0x0F|0x00) +#define EDMASTL (0x10|0x00) +#define EDMASTH (0x11|0x00) +#define EDMANDL (0x12|0x00) +#define EDMANDH (0x13|0x00) +#define EDMADSTL (0x14|0x00) +#define EDMADSTH (0x15|0x00) +#define EDMACSL (0x16|0x00) +#define EDMACSH (0x17|0x00) +/* Bank 1 registers */ +#define EHT0 (0x00|0x20) +#define EHT1 (0x01|0x20) +#define EHT2 (0x02|0x20) +#define EHT3 (0x03|0x20) +#define EHT4 (0x04|0x20) +#define EHT5 (0x05|0x20) +#define EHT6 (0x06|0x20) +#define EHT7 (0x07|0x20) +#define EPMM0 (0x08|0x20) +#define EPMM1 (0x09|0x20) +#define EPMM2 (0x0A|0x20) +#define EPMM3 (0x0B|0x20) +#define EPMM4 (0x0C|0x20) +#define EPMM5 (0x0D|0x20) +#define EPMM6 (0x0E|0x20) +#define EPMM7 (0x0F|0x20) +#define EPMCSL (0x10|0x20) +#define EPMCSH (0x11|0x20) +#define EPMOL (0x14|0x20) +#define EPMOH (0x15|0x20) +#define EWOLIE (0x16|0x20) +#define EWOLIR (0x17|0x20) +#define ERXFCON (0x18|0x20) +#define EPKTCNT (0x19|0x20) +/* Bank 2 registers */ +#define MACON1 (0x00|0x40|SPRD_MASK) +/* #define MACON2 (0x01|0x40|SPRD_MASK) */ +#define MACON3 (0x02|0x40|SPRD_MASK) +#define MACON4 (0x03|0x40|SPRD_MASK) +#define MABBIPG (0x04|0x40|SPRD_MASK) +#define MAIPGL (0x06|0x40|SPRD_MASK) +#define MAIPGH (0x07|0x40|SPRD_MASK) +#define MACLCON1 (0x08|0x40|SPRD_MASK) +#define MACLCON2 (0x09|0x40|SPRD_MASK) +#define MAMXFLL (0x0A|0x40|SPRD_MASK) +#define MAMXFLH (0x0B|0x40|SPRD_MASK) +#define MAPHSUP (0x0D|0x40|SPRD_MASK) +#define MICON (0x11|0x40|SPRD_MASK) +#define MICMD (0x12|0x40|SPRD_MASK) +#define MIREGADR (0x14|0x40|SPRD_MASK) +#define MIWRL (0x16|0x40|SPRD_MASK) +#define MIWRH (0x17|0x40|SPRD_MASK) +#define MIRDL (0x18|0x40|SPRD_MASK) +#define MIRDH (0x19|0x40|SPRD_MASK) +/* Bank 3 registers */ +#define MAADR1 (0x00|0x60|SPRD_MASK) +#define MAADR0 (0x01|0x60|SPRD_MASK) +#define MAADR3 (0x02|0x60|SPRD_MASK) +#define MAADR2 (0x03|0x60|SPRD_MASK) +#define MAADR5 (0x04|0x60|SPRD_MASK) +#define MAADR4 (0x05|0x60|SPRD_MASK) +#define EBSTSD (0x06|0x60) +#define EBSTCON (0x07|0x60) +#define EBSTCSL (0x08|0x60) +#define EBSTCSH (0x09|0x60) +#define MISTAT (0x0A|0x60|SPRD_MASK) +#define EREVID (0x12|0x60) +#define ECOCON (0x15|0x60) +#define EFLOCON (0x17|0x60) +#define EPAUSL (0x18|0x60) +#define EPAUSH (0x19|0x60) +/* PHY registers */ +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 + +/* ENC28J60 EIE Register Bit Definitions */ +#define EIE_INTIE 0x80 +#define EIE_PKTIE 0x40 +#define EIE_DMAIE 0x20 +#define EIE_LINKIE 0x10 +#define EIE_TXIE 0x08 +/* #define EIE_WOLIE 0x04 (reserved) */ +#define EIE_TXERIE 0x02 +#define EIE_RXERIE 0x01 +/* ENC28J60 EIR Register Bit Definitions */ +#define EIR_PKTIF 0x40 +#define EIR_DMAIF 0x20 +#define EIR_LINKIF 0x10 +#define EIR_TXIF 0x08 +/* #define EIR_WOLIF 0x04 (reserved) */ +#define EIR_TXERIF 0x02 +#define EIR_RXERIF 0x01 +/* ENC28J60 ESTAT Register Bit Definitions */ +#define ESTAT_INT 0x80 +#define ESTAT_LATECOL 0x10 +#define ESTAT_RXBUSY 0x04 +#define ESTAT_TXABRT 0x02 +#define ESTAT_CLKRDY 0x01 +/* ENC28J60 ECON2 Register Bit Definitions */ +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 +#define ECON2_PWRSV 0x20 +#define ECON2_VRPS 0x08 +/* ENC28J60 ECON1 Register Bit Definitions */ +#define ECON1_TXRST 0x80 +#define ECON1_RXRST 0x40 +#define ECON1_DMAST 0x20 +#define ECON1_CSUMEN 0x10 +#define ECON1_TXRTS 0x08 +#define ECON1_RXEN 0x04 +#define ECON1_BSEL1 0x02 +#define ECON1_BSEL0 0x01 +/* ENC28J60 MACON1 Register Bit Definitions */ +#define MACON1_LOOPBK 0x10 +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_PASSALL 0x02 +#define MACON1_MARXEN 0x01 +/* ENC28J60 MACON2 Register Bit Definitions */ +#define MACON2_MARST 0x80 +#define MACON2_RNDRST 0x40 +#define MACON2_MARXRST 0x08 +#define MACON2_RFUNRST 0x04 +#define MACON2_MATXRST 0x02 +#define MACON2_TFUNRST 0x01 +/* ENC28J60 MACON3 Register Bit Definitions */ +#define MACON3_PADCFG2 0x80 +#define MACON3_PADCFG1 0x40 +#define MACON3_PADCFG0 0x20 +#define MACON3_TXCRCEN 0x10 +#define MACON3_PHDRLEN 0x08 +#define MACON3_HFRMLEN 0x04 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 +/* ENC28J60 MICMD Register Bit Definitions */ +#define MICMD_MIISCAN 0x02 +#define MICMD_MIIRD 0x01 +/* ENC28J60 MISTAT Register Bit Definitions */ +#define MISTAT_NVALID 0x04 +#define MISTAT_SCAN 0x02 +#define MISTAT_BUSY 0x01 +/* ENC28J60 ERXFCON Register Bit Definitions */ +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_PMEN 0x10 +#define ERXFCON_MPEN 0x08 +#define ERXFCON_HTEN 0x04 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 + +/* ENC28J60 PHY PHCON1 Register Bit Definitions */ +#define PHCON1_PRST 0x8000 +#define PHCON1_PLOOPBK 0x4000 +#define PHCON1_PPWRSV 0x0800 +#define PHCON1_PDPXMD 0x0100 +/* ENC28J60 PHY PHSTAT1 Register Bit Definitions */ +#define PHSTAT1_PFDPX 0x1000 +#define PHSTAT1_PHDPX 0x0800 +#define PHSTAT1_LLSTAT 0x0004 +#define PHSTAT1_JBSTAT 0x0002 +/* ENC28J60 PHY PHSTAT2 Register Bit Definitions */ +#define PHSTAT2_TXSTAT (1 << 13) +#define PHSTAT2_RXSTAT (1 << 12) +#define PHSTAT2_COLSTAT (1 << 11) +#define PHSTAT2_LSTAT (1 << 10) +#define PHSTAT2_DPXSTAT (1 << 9) +#define PHSTAT2_PLRITY (1 << 5) +/* ENC28J60 PHY PHCON2 Register Bit Definitions */ +#define PHCON2_FRCLINK 0x4000 +#define PHCON2_TXDIS 0x2000 +#define PHCON2_JABBER 0x0400 +#define PHCON2_HDLDIS 0x0100 +/* ENC28J60 PHY PHIE Register Bit Definitions */ +#define PHIE_PLNKIE (1 << 4) +#define PHIE_PGEIE (1 << 1) +/* ENC28J60 PHY PHIR Register Bit Definitions */ +#define PHIR_PLNKIF (1 << 4) +#define PHIR_PGEIF (1 << 1) + +/* ENC28J60 Packet Control Byte Bit Definitions */ +#define PKTCTRL_PHUGEEN 0x08 +#define PKTCTRL_PPADEN 0x04 +#define PKTCTRL_PCRCEN 0x02 +#define PKTCTRL_POVERRIDE 0x01 + +/* ENC28J60 Transmit Status Vector */ +#define TSV_TXBYTECNT 0 +#define TSV_TXCOLLISIONCNT 16 +#define TSV_TXCRCERROR 20 +#define TSV_TXLENCHKERROR 21 +#define TSV_TXLENOUTOFRANGE 22 +#define TSV_TXDONE 23 +#define TSV_TXMULTICAST 24 +#define TSV_TXBROADCAST 25 +#define TSV_TXPACKETDEFER 26 +#define TSV_TXEXDEFER 27 +#define TSV_TXEXCOLLISION 28 +#define TSV_TXLATECOLLISION 29 +#define TSV_TXGIANT 30 +#define TSV_TXUNDERRUN 31 +#define TSV_TOTBYTETXONWIRE 32 +#define TSV_TXCONTROLFRAME 48 +#define TSV_TXPAUSEFRAME 49 +#define TSV_BACKPRESSUREAPP 50 +#define TSV_TXVLANTAGFRAME 51 + +#define TSV_SIZE 7 +#define TSV_BYTEOF(x) ((x) / 8) +#define TSV_BITMASK(x) (1 << ((x) % 8)) +#define TSV_GETBIT(x, y) (((x)[TSV_BYTEOF(y)] & TSV_BITMASK(y)) ? 1 : 0) + +/* ENC28J60 Receive Status Vector */ +#define RSV_RXLONGEVDROPEV 16 +#define RSV_CARRIEREV 18 +#define RSV_CRCERROR 20 +#define RSV_LENCHECKERR 21 +#define RSV_LENOUTOFRANGE 22 +#define RSV_RXOK 23 +#define RSV_RXMULTICAST 24 +#define RSV_RXBROADCAST 25 +#define RSV_DRIBBLENIBBLE 26 +#define RSV_RXCONTROLFRAME 27 +#define RSV_RXPAUSEFRAME 28 +#define RSV_RXUNKNOWNOPCODE 29 +#define RSV_RXTYPEVLAN 30 + +#define RSV_SIZE 6 +#define RSV_BITMASK(x) (1 << ((x) - 16)) +#define RSV_GETBIT(x, y) (((x) & RSV_BITMASK(y)) ? 1 : 0) + + +/* SPI operation codes */ +#define ENC28J60_READ_CTRL_REG 0x00 +#define ENC28J60_READ_BUF_MEM 0x3A +#define ENC28J60_WRITE_CTRL_REG 0x40 +#define ENC28J60_WRITE_BUF_MEM 0x7A +#define ENC28J60_BIT_FIELD_SET 0x80 +#define ENC28J60_BIT_FIELD_CLR 0xA0 +#define ENC28J60_SOFT_RESET 0xFF + + +/* buffer boundaries applied to internal 8K ram + * entire available packet buffer space is allocated. + * Give TX buffer space for one full ethernet frame (~1500 bytes) + * receive buffer gets the rest */ +#define TXSTART_INIT 0x1A00 +#define TXEND_INIT 0x1FFF + +/* Put RX buffer at 0 as suggested by the Errata datasheet */ +#define RXSTART_INIT 0x0000 +#define RXEND_INIT 0x19FF + +/* maximum ethernet frame length */ +#define MAX_FRAMELEN 1518 + +/* Prefered half duplex: LEDA: Link status LEDB: Rx/Tx activity */ +#define ENC28J60_LAMPS_MODE 0x3476 + +#endif diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index f84c752997a4..7667a62ac31f 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -712,8 +712,8 @@ static const struct nv_ethtool_str nv_etests_str[] = { }; struct register_test { - __le32 reg; - __le32 mask; + __u32 reg; + __u32 mask; }; static const struct register_test nv_registers_test[] = { @@ -929,6 +929,16 @@ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, #define NV_SETUP_RX_RING 0x01 #define NV_SETUP_TX_RING 0x02 +static inline u32 dma_low(dma_addr_t addr) +{ + return addr; +} + +static inline u32 dma_high(dma_addr_t addr) +{ + return addr>>31>>1; /* 0 if 32bit, shift down by 32 if 64bit */ +} + static void setup_hw_rings(struct net_device *dev, int rxtx_flags) { struct fe_priv *np = get_nvpriv(dev); @@ -936,19 +946,19 @@ static void setup_hw_rings(struct net_device *dev, int rxtx_flags) if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { if (rxtx_flags & NV_SETUP_RX_RING) { - writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr); + writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr); } if (rxtx_flags & NV_SETUP_TX_RING) { - writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); } } else { if (rxtx_flags & NV_SETUP_RX_RING) { - writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr); - writel((u32) (cpu_to_le64(np->ring_addr) >> 32), base + NvRegRxRingPhysAddrHigh); + writel(dma_low(np->ring_addr), base + NvRegRxRingPhysAddr); + writel(dma_high(np->ring_addr), base + NvRegRxRingPhysAddrHigh); } if (rxtx_flags & NV_SETUP_TX_RING) { - writel((u32) cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); - writel((u32) (cpu_to_le64(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh); + writel(dma_low(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + writel(dma_high(np->ring_addr + np->rx_ring_size*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddrHigh); } } } @@ -1571,8 +1581,8 @@ static int nv_alloc_rx_optimized(struct net_device *dev) skb_tailroom(skb), PCI_DMA_FROMDEVICE); np->put_rx_ctx->dma_len = skb_tailroom(skb); - np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32; - np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF; + np->put_rx.ex->bufhigh = cpu_to_le32(dma_high(np->put_rx_ctx->dma)); + np->put_rx.ex->buflow = cpu_to_le32(dma_low(np->put_rx_ctx->dma)); wmb(); np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); if (unlikely(np->put_rx.ex++ == np->last_rx.ex)) @@ -1937,8 +1947,8 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; - put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; - put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; + put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma)); + put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma)); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); tx_flags = NV_TX2_VALID; @@ -1963,8 +1973,8 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; - put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32; - put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF; + put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma)); + put_tx->buflow = cpu_to_le32(dma_low(np->put_tx_ctx->dma)); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; @@ -2680,8 +2690,8 @@ static void nv_set_multicast(struct net_device *dev) walk = dev->mc_list; while (walk != NULL) { u32 a, b; - a = le32_to_cpu(*(u32 *) walk->dmi_addr); - b = le16_to_cpu(*(u16 *) (&walk->dmi_addr[4])); + a = le32_to_cpu(*(__le32 *) walk->dmi_addr); + b = le16_to_cpu(*(__le16 *) (&walk->dmi_addr[4])); alwaysOn[0] &= a; alwaysOff[0] &= ~a; alwaysOn[1] &= b; @@ -4539,8 +4549,8 @@ static int nv_loopback_test(struct net_device *dev) np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr); np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra); } else { - np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32; - np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF; + np->tx_ring.ex[0].bufhigh = cpu_to_le32(dma_high(test_dma_addr)); + np->tx_ring.ex[0].buflow = cpu_to_le32(dma_low(test_dma_addr)); np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra); } writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index aec9ab17a9a5..230878b94190 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -37,24 +37,6 @@ #include "gianfar.h" -#define GFAR_ATTR(_name) \ -static ssize_t gfar_show_##_name(struct device *dev, \ - struct device_attribute *attr, char *buf); \ -static ssize_t gfar_set_##_name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count); \ -static DEVICE_ATTR(_name, 0644, gfar_show_##_name, gfar_set_##_name) - -#define GFAR_CREATE_FILE(_dev, _name) \ - device_create_file(&_dev->dev, &dev_attr_##_name) - -GFAR_ATTR(bd_stash); -GFAR_ATTR(rx_stash_size); -GFAR_ATTR(rx_stash_index); -GFAR_ATTR(fifo_threshold); -GFAR_ATTR(fifo_starve); -GFAR_ATTR(fifo_starve_off); - static ssize_t gfar_show_bd_stash(struct device *dev, struct device_attribute *attr, char *buf) { @@ -100,6 +82,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev, return count; } +DEVICE_ATTR(bd_stash, 0644, gfar_show_bd_stash, gfar_set_bd_stash); + static ssize_t gfar_show_rx_stash_size(struct device *dev, struct device_attribute *attr, char *buf) { @@ -146,6 +130,9 @@ static ssize_t gfar_set_rx_stash_size(struct device *dev, return count; } +DEVICE_ATTR(rx_stash_size, 0644, gfar_show_rx_stash_size, + gfar_set_rx_stash_size); + /* Stashing will only be enabled when rx_stash_size != 0 */ static ssize_t gfar_show_rx_stash_index(struct device *dev, struct device_attribute *attr, @@ -184,6 +171,9 @@ static ssize_t gfar_set_rx_stash_index(struct device *dev, return count; } +DEVICE_ATTR(rx_stash_index, 0644, gfar_show_rx_stash_index, + gfar_set_rx_stash_index); + static ssize_t gfar_show_fifo_threshold(struct device *dev, struct device_attribute *attr, char *buf) @@ -219,6 +209,9 @@ static ssize_t gfar_set_fifo_threshold(struct device *dev, return count; } +DEVICE_ATTR(fifo_threshold, 0644, gfar_show_fifo_threshold, + gfar_set_fifo_threshold); + static ssize_t gfar_show_fifo_starve(struct device *dev, struct device_attribute *attr, char *buf) { @@ -253,6 +246,8 @@ static ssize_t gfar_set_fifo_starve(struct device *dev, return count; } +DEVICE_ATTR(fifo_starve, 0644, gfar_show_fifo_starve, gfar_set_fifo_starve); + static ssize_t gfar_show_fifo_starve_off(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,9 +283,13 @@ static ssize_t gfar_set_fifo_starve_off(struct device *dev, return count; } +DEVICE_ATTR(fifo_starve_off, 0644, gfar_show_fifo_starve_off, + gfar_set_fifo_starve_off); + void gfar_init_sysfs(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); + int rc; /* Initialize the default values */ priv->rx_stash_size = DEFAULT_STASH_LENGTH; @@ -301,11 +300,12 @@ void gfar_init_sysfs(struct net_device *dev) priv->bd_stash_en = DEFAULT_BD_STASH; /* Create our sysfs files */ - GFAR_CREATE_FILE(dev, bd_stash); - GFAR_CREATE_FILE(dev, rx_stash_size); - GFAR_CREATE_FILE(dev, rx_stash_index); - GFAR_CREATE_FILE(dev, fifo_threshold); - GFAR_CREATE_FILE(dev, fifo_starve); - GFAR_CREATE_FILE(dev, fifo_starve_off); - + rc = device_create_file(&dev->dev, &dev_attr_bd_stash); + rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_size); + rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_index); + rc |= device_create_file(&dev->dev, &dev_attr_fifo_threshold); + rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve); + rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off); + if (rc) + dev_err(&dev->dev, "Error creating gianfar sysfs files.\n"); } diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 580cb4ab2af1..0a9b75139e0f 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -701,7 +701,7 @@ static void sixpack_close(struct tty_struct *tty) sp = tty->disc_data; tty->disc_data = NULL; write_unlock(&disc_data_lock); - if (sp == 0) + if (!sp) return; /* diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 803a3bdea0af..cfcd15af501e 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -821,7 +821,7 @@ static void mkiss_close(struct tty_struct *tty) tty->disc_data = NULL; write_unlock(&disc_data_lock); - if (ax == 0) + if (!ax) return; /* diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index 353d13e543ce..f90515935833 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -201,7 +201,6 @@ static void z8530_init(void); static void init_channel(struct scc_channel *scc); static void scc_key_trx (struct scc_channel *scc, char tx); -static irqreturn_t scc_isr(int irq, void *dev_id); static void scc_init_timer(struct scc_channel *scc); static int scc_net_alloc(const char *name, struct scc_channel *scc); @@ -629,6 +628,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector) static irqreturn_t scc_isr(int irq, void *dev_id) { + int chip_irq = (long) dev_id; unsigned char vector; struct scc_channel *scc; struct scc_ctrl *ctrl; @@ -665,7 +665,7 @@ static irqreturn_t scc_isr(int irq, void *dev_id) ctrl = SCC_ctrl; while (ctrl->chan_A) { - if (ctrl->irq != irq) + if (ctrl->irq != chip_irq) { ctrl++; continue; @@ -1732,7 +1732,9 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!Ivec[hwcfg.irq].used && hwcfg.irq) { - if (request_irq(hwcfg.irq, scc_isr, IRQF_DISABLED, "AX.25 SCC", NULL)) + if (request_irq(hwcfg.irq, scc_isr, + IRQF_DISABLED, "AX.25 SCC", + (void *)(long) hwcfg.irq)) printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq); else Ivec[hwcfg.irq].used = 1; diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 49421d1cd3a5..571dd80fb850 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1153,7 +1153,7 @@ static void hp100_init_pdls(struct net_device *dev) printk("hp100: %s: init pdls\n", dev->name); #endif - if (0 == lp->page_vaddr_algn) + if (!lp->page_vaddr_algn) printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n", dev->name); else { /* pageptr shall point into the DMA accessible memory region */ diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index fced441face6..e6c69f77259b 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1298,7 +1298,6 @@ static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev) return emac_xmit_finish(dev, len); } -#ifdef CONFIG_IBM_NEW_EMAC_TAH static inline int emac_xmit_split(struct emac_instance *dev, int slot, u32 pd, int len, int last, u16 base_ctrl) { @@ -1411,9 +1410,6 @@ static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev) DBG2(dev, "stopped TX queue" NL); return 1; } -#else -# define emac_start_xmit_sg emac_start_xmit -#endif /* !defined(CONFIG_IBM_NEW_EMAC_TAH) */ /* Tx lock BHs */ static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl) @@ -2684,13 +2680,8 @@ static int __devinit emac_probe(struct of_device *ofdev, /* Fill in the driver function table */ ndev->open = &emac_open; -#ifdef CONFIG_IBM_NEW_EMAC_TAH - if (dev->tah_dev) { - ndev->hard_start_xmit = &emac_start_xmit_sg; + if (dev->tah_dev) ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - } else -#endif - ndev->hard_start_xmit = &emac_start_xmit; ndev->tx_timeout = &emac_tx_timeout; ndev->watchdog_timeo = 5 * HZ; ndev->stop = &emac_close; @@ -2698,8 +2689,11 @@ static int __devinit emac_probe(struct of_device *ofdev, ndev->set_multicast_list = &emac_set_multicast_list; ndev->do_ioctl = &emac_ioctl; if (emac_phy_supports_gige(dev->phy_mode)) { + ndev->hard_start_xmit = &emac_start_xmit_sg; ndev->change_mtu = &emac_change_mtu; dev->commac.ops = &emac_commac_sg_ops; + } else { + ndev->hard_start_xmit = &emac_start_xmit; } SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops); diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 91d83aca6bc7..46e2c52c7862 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -83,7 +83,7 @@ History: #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/time.h> -#include <linux/mca-legacy.h> +#include <linux/mca.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -161,13 +161,13 @@ static void PrTime(void) /* deduce resources out of POS registers */ -static void getaddrs(int slot, int *base, int *memlen, int *iobase, - int *irq, ibmlana_medium * medium) +static void getaddrs(struct mca_device *mdev, int *base, int *memlen, + int *iobase, int *irq, ibmlana_medium *medium) { u_char pos0, pos1; - pos0 = mca_read_stored_pos(slot, 2); - pos1 = mca_read_stored_pos(slot, 3); + pos0 = mca_device_read_stored_pos(mdev, 2); + pos1 = mca_device_read_stored_pos(mdev, 3); *base = 0xc0000 + ((pos1 & 0xf0) << 9); *memlen = (pos1 & 0x01) ? 0x8000 : 0x4000; @@ -704,9 +704,9 @@ static void irqtxerr_handler(struct net_device *dev) /* general interrupt entry */ -static irqreturn_t irq_handler(int irq, void *device) +static irqreturn_t irq_handler(int dummy, void *device) { - struct net_device *dev = (struct net_device *) device; + struct net_device *dev = device; u16 ival; /* in case we're not meant... */ @@ -744,6 +744,7 @@ static irqreturn_t irq_handler(int irq, void *device) /* MCA info */ +#if 0 /* info available elsewhere, but this is kept for reference */ static int ibmlana_getinfo(char *buf, int slot, void *d) { int len = 0, i; @@ -771,6 +772,7 @@ static int ibmlana_getinfo(char *buf, int slot, void *d) return len; } +#endif /* open driver. Means also initialization and start of LANCE */ @@ -890,42 +892,52 @@ static void ibmlana_set_multicast_list(struct net_device *dev) * hardware check * ------------------------------------------------------------------------ */ +static int ibmlana_irq; +static int ibmlana_io; static int startslot; /* counts through slots when probing multiple devices */ -static int ibmlana_probe(struct net_device *dev) +static short ibmlana_adapter_ids[] __initdata = { + IBM_LANA_ID, + 0x0000 +}; + +static char *ibmlana_adapter_names[] __initdata = { + "IBM LAN Adapter/A", + NULL +}; + +static int ibmlana_init_one(struct device *kdev) { - int slot, z; + struct mca_device *mdev = to_mca_device(kdev); + struct net_device *dev; + int slot = mdev->slot, z, rc; int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium; DECLARE_MAC_BUF(mac); - /* can't work without an MCA bus ;-) */ - if (MCA_bus == 0) - return -ENODEV; + dev = alloc_etherdev(sizeof(ibmlana_priv)); + if (!dev) + return -ENOMEM; + + dev->irq = ibmlana_irq; + dev->base_addr = ibmlana_io; base = dev->mem_start; irq = dev->irq; - for (slot = startslot; (slot = mca_find_adapter(IBM_LANA_ID, slot)) != -1; slot++) { - /* deduce card addresses */ - getaddrs(slot, &base, &memlen, &iobase, &irq, &medium); - - /* slot already in use ? */ - if (mca_is_adapter_used(slot)) - continue; - /* were we looking for something different ? */ - if (dev->irq && dev->irq != irq) - continue; - if (dev->mem_start && dev->mem_start != base) - continue; - /* found something that matches */ - break; - } + /* deduce card addresses */ + getaddrs(mdev, &base, &memlen, &iobase, &irq, &medium); - /* nothing found ? */ - if (slot == -1) - return (base != 0 || irq != 0) ? -ENXIO : -ENODEV; + /* were we looking for something different ? */ + if (dev->irq && dev->irq != irq) { + rc = -ENODEV; + goto err_out; + } + if (dev->mem_start && dev->mem_start != base) { + rc = -ENODEV; + goto err_out; + } /* announce success */ printk(KERN_INFO "%s: IBM LAN Adapter/A found in slot %d\n", dev->name, slot + 1); @@ -934,16 +946,16 @@ static int ibmlana_probe(struct net_device *dev) if (!request_region(iobase, IBM_LANA_IORANGE, DRV_NAME)) { printk(KERN_ERR "%s: cannot allocate I/O range at %#x!\n", DRV_NAME, iobase); startslot = slot + 1; - return -EBUSY; + rc = -EBUSY; + goto err_out; } priv = netdev_priv(dev); priv->slot = slot; - priv->realirq = irq; + priv->realirq = mca_device_transform_irq(mdev, irq); priv->medium = medium; spin_lock_init(&priv->lock); - /* set base + irq for this device (irq not allocated so far) */ dev->irq = 0; @@ -955,22 +967,18 @@ static int ibmlana_probe(struct net_device *dev) if (!priv->base) { printk(KERN_ERR "%s: cannot remap memory!\n", DRV_NAME); startslot = slot + 1; - release_region(iobase, IBM_LANA_IORANGE); - return -EBUSY; + rc = -EBUSY; + goto err_out_reg; } - /* make procfs entries */ - mca_set_adapter_name(slot, "IBM LAN Adapter/A"); - mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmlana_getinfo, dev); - - mca_mark_as_used(slot); + mca_device_set_name(mdev, ibmlana_adapter_names[mdev->index]); + mca_device_set_claim(mdev, 1); /* set methods */ dev->open = ibmlana_open; dev->stop = ibmlana_close; dev->hard_start_xmit = ibmlana_tx; - dev->do_ioctl = NULL; dev->set_multicast_list = ibmlana_set_multicast_list; dev->flags |= IFF_MULTICAST; @@ -996,6 +1004,35 @@ static int ibmlana_probe(struct net_device *dev) startslot = slot + 1; + rc = register_netdev(dev); + if (rc) + goto err_out_claimed; + + dev_set_drvdata(kdev, dev); + return 0; + +err_out_claimed: + mca_device_set_claim(mdev, 0); + iounmap(priv->base); +err_out_reg: + release_region(iobase, IBM_LANA_IORANGE); +err_out: + free_netdev(dev); + return rc; +} + +static int ibmlana_remove_one(struct device *kdev) +{ + struct mca_device *mdev = to_mca_device(kdev); + struct net_device *dev = dev_get_drvdata(kdev); + ibmlana_priv *priv = netdev_priv(dev); + + unregister_netdev(dev); + /*DeinitBoard(dev); */ + release_region(dev->base_addr, IBM_LANA_IORANGE); + mca_device_set_claim(mdev, 0); + iounmap(priv->base); + free_netdev(dev); return 0; } @@ -1003,66 +1040,31 @@ static int ibmlana_probe(struct net_device *dev) * modularization support * ------------------------------------------------------------------------ */ -#ifdef MODULE - -#define DEVMAX 5 - -static struct net_device *moddevs[DEVMAX]; -static int irq; -static int io; - -module_param(irq, int, 0); -module_param(io, int, 0); +module_param_named(irq, ibmlana_irq, int, 0); +module_param_named(io, ibmlana_io, int, 0); MODULE_PARM_DESC(irq, "IBM LAN/A IRQ number"); MODULE_PARM_DESC(io, "IBM LAN/A I/O base address"); MODULE_LICENSE("GPL"); -int init_module(void) -{ - int z; +static struct mca_driver ibmlana_driver = { + .id_table = ibmlana_adapter_ids, + .driver = { + .name = "ibmlana", + .bus = &mca_bus_type, + .probe = ibmlana_init_one, + .remove = ibmlana_remove_one, + }, +}; - startslot = 0; - for (z = 0; z < DEVMAX; z++) { - struct net_device *dev = alloc_etherdev(sizeof(ibmlana_priv)); - if (!dev) - break; - dev->irq = irq; - dev->base_addr = io; - if (ibmlana_probe(dev)) { - free_netdev(dev); - break; - } - if (register_netdev(dev)) { - ibmlana_priv *priv = netdev_priv(dev); - release_region(dev->base_addr, IBM_LANA_IORANGE); - mca_mark_as_unused(priv->slot); - mca_set_adapter_name(priv->slot, ""); - mca_set_adapter_procfn(priv->slot, NULL, NULL); - iounmap(priv->base); - free_netdev(dev); - break; - } - moddevs[z] = dev; - } - return (z > 0) ? 0 : -EIO; +static int __init ibmlana_init_module(void) +{ + return mca_register_driver(&ibmlana_driver); } -void cleanup_module(void) +static void __exit ibmlana_cleanup_module(void) { - int z; - for (z = 0; z < DEVMAX; z++) { - struct net_device *dev = moddevs[z]; - if (dev) { - ibmlana_priv *priv = netdev_priv(dev); - unregister_netdev(dev); - /*DeinitBoard(dev); */ - release_region(dev->base_addr, IBM_LANA_IORANGE); - mca_mark_as_unused(priv->slot); - mca_set_adapter_name(priv->slot, ""); - mca_set_adapter_procfn(priv->slot, NULL, NULL); - iounmap(priv->base); - free_netdev(dev); - } - } + mca_unregister_driver(&ibmlana_driver); } -#endif /* MODULE */ + +module_init(ibmlana_init_module); +module_exit(ibmlana_cleanup_module); diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 7d7758f3ad8c..57772bebff56 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1179,13 +1179,15 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ for(i = 0; i<IbmVethNumBufferPools; i++) { struct kobject *kobj = &adapter->rx_buff_pool[i].kobj; + int error; + ibmveth_init_buffer_pool(&adapter->rx_buff_pool[i], i, pool_count[i], pool_size[i], pool_active[i]); - kobj->parent = &dev->dev.kobj; - kobject_set_name(kobj, "pool%d", i); - kobj->ktype = &ktype_veth_pool; - kobject_register(kobj); + error = kobject_init_and_add(kobj, &ktype_veth_pool, + &dev->dev.kobj, "pool%d", i); + if (!error) + kobject_uevent(kobj, KOBJ_ADD); } ibmveth_debug_printk("adapter @ 0x%p\n", adapter); @@ -1234,7 +1236,7 @@ static int __devexit ibmveth_remove(struct vio_dev *dev) int i; for(i = 0; i<IbmVethNumBufferPools; i++) - kobject_unregister(&adapter->rx_buff_pool[i].kobj); + kobject_put(&adapter->rx_buff_pool[i].kobj); unregister_netdev(netdev); diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile new file mode 100644 index 000000000000..1927b3fd6f05 --- /dev/null +++ b/drivers/net/igb/Makefile @@ -0,0 +1,37 @@ +################################################################################ +# +# Intel 82575 PCI-Express Ethernet Linux driver +# Copyright(c) 1999 - 2007 Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +# Contact Information: +# Linux NICS <linux.nics@intel.com> +# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> +# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 +# +################################################################################ + +# +# Makefile for the Intel(R) 82575 PCI-Express ethernet driver +# + +obj-$(CONFIG_IGB) += igb.o + +igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \ + e1000_mac.o e1000_nvm.o e1000_phy.o + diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c new file mode 100644 index 000000000000..cda3ec879090 --- /dev/null +++ b/drivers/net/igb/e1000_82575.c @@ -0,0 +1,1269 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* e1000_82575 + * e1000_82576 + */ + +#include <linux/types.h> +#include <linux/slab.h> + +#include "e1000_mac.h" +#include "e1000_82575.h" + +static s32 igb_get_invariants_82575(struct e1000_hw *); +static s32 igb_acquire_phy_82575(struct e1000_hw *); +static void igb_release_phy_82575(struct e1000_hw *); +static s32 igb_acquire_nvm_82575(struct e1000_hw *); +static void igb_release_nvm_82575(struct e1000_hw *); +static s32 igb_check_for_link_82575(struct e1000_hw *); +static s32 igb_get_cfg_done_82575(struct e1000_hw *); +static s32 igb_init_hw_82575(struct e1000_hw *); +static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *); +static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16 *); +static void igb_rar_set_82575(struct e1000_hw *, u8 *, u32); +static s32 igb_reset_hw_82575(struct e1000_hw *); +static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *, bool); +static s32 igb_setup_copper_link_82575(struct e1000_hw *); +static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *); +static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *, u32, u16); +static void igb_clear_hw_cntrs_82575(struct e1000_hw *); +static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *, u16); +static s32 igb_configure_pcs_link_82575(struct e1000_hw *); +static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *, u16 *, + u16 *); +static s32 igb_get_phy_id_82575(struct e1000_hw *); +static void igb_release_swfw_sync_82575(struct e1000_hw *, u16); +static bool igb_sgmii_active_82575(struct e1000_hw *); +static s32 igb_reset_init_script_82575(struct e1000_hw *); +static s32 igb_read_mac_addr_82575(struct e1000_hw *); + + +struct e1000_dev_spec_82575 { + bool sgmii_active; +}; + +static s32 igb_get_invariants_82575(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + struct e1000_nvm_info *nvm = &hw->nvm; + struct e1000_mac_info *mac = &hw->mac; + struct e1000_dev_spec_82575 *dev_spec; + u32 eecd; + s32 ret_val; + u16 size; + u32 ctrl_ext = 0; + + switch (hw->device_id) { + case E1000_DEV_ID_82575EB_COPPER: + case E1000_DEV_ID_82575EB_FIBER_SERDES: + case E1000_DEV_ID_82575GB_QUAD_COPPER: + mac->type = e1000_82575; + break; + default: + return -E1000_ERR_MAC_INIT; + break; + } + + /* MAC initialization */ + hw->dev_spec_size = sizeof(struct e1000_dev_spec_82575); + + /* Device-specific structure allocation */ + hw->dev_spec = kzalloc(hw->dev_spec_size, GFP_KERNEL); + + if (!hw->dev_spec) + return -ENOMEM; + + dev_spec = (struct e1000_dev_spec_82575 *)hw->dev_spec; + + /* Set media type */ + /* + * The 82575 uses bits 22:23 for link mode. The mode can be changed + * based on the EEPROM. We cannot rely upon device ID. There + * is no distinguishable difference between fiber and internal + * SerDes mode on the 82575. There can be an external PHY attached + * on the SGMII interface. For this, we'll set sgmii_active to true. + */ + phy->media_type = e1000_media_type_copper; + dev_spec->sgmii_active = false; + + ctrl_ext = rd32(E1000_CTRL_EXT); + if ((ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) == + E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES) { + hw->phy.media_type = e1000_media_type_internal_serdes; + ctrl_ext |= E1000_CTRL_I2C_ENA; + } else if (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII) { + dev_spec->sgmii_active = true; + ctrl_ext |= E1000_CTRL_I2C_ENA; + } else { + ctrl_ext &= ~E1000_CTRL_I2C_ENA; + } + wr32(E1000_CTRL_EXT, ctrl_ext); + + /* Set mta register count */ + mac->mta_reg_count = 128; + /* Set rar entry count */ + mac->rar_entry_count = E1000_RAR_ENTRIES_82575; + /* Set if part includes ASF firmware */ + mac->asf_firmware_present = true; + /* Set if manageability features are enabled. */ + mac->arc_subsystem_valid = + (rd32(E1000_FWSM) & E1000_FWSM_MODE_MASK) + ? true : false; + + /* physical interface link setup */ + mac->ops.setup_physical_interface = + (hw->phy.media_type == e1000_media_type_copper) + ? igb_setup_copper_link_82575 + : igb_setup_fiber_serdes_link_82575; + + /* NVM initialization */ + eecd = rd32(E1000_EECD); + + nvm->opcode_bits = 8; + nvm->delay_usec = 1; + switch (nvm->override) { + case e1000_nvm_override_spi_large: + nvm->page_size = 32; + nvm->address_bits = 16; + break; + case e1000_nvm_override_spi_small: + nvm->page_size = 8; + nvm->address_bits = 8; + break; + default: + nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; + nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; + break; + } + + nvm->type = e1000_nvm_eeprom_spi; + + size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> + E1000_EECD_SIZE_EX_SHIFT); + + /* + * Added to a constant, "size" becomes the left-shift value + * for setting word_size. + */ + size += NVM_WORD_SIZE_BASE_SHIFT; + nvm->word_size = 1 << size; + + /* setup PHY parameters */ + if (phy->media_type != e1000_media_type_copper) { + phy->type = e1000_phy_none; + return 0; + } + + phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; + phy->reset_delay_us = 100; + + /* PHY function pointers */ + if (igb_sgmii_active_82575(hw)) { + phy->ops.reset_phy = igb_phy_hw_reset_sgmii_82575; + phy->ops.read_phy_reg = igb_read_phy_reg_sgmii_82575; + phy->ops.write_phy_reg = igb_write_phy_reg_sgmii_82575; + } else { + phy->ops.reset_phy = igb_phy_hw_reset; + phy->ops.read_phy_reg = igb_read_phy_reg_igp; + phy->ops.write_phy_reg = igb_write_phy_reg_igp; + } + + /* Set phy->phy_addr and phy->id. */ + ret_val = igb_get_phy_id_82575(hw); + if (ret_val) + return ret_val; + + /* Verify phy id and set remaining function pointers */ + switch (phy->id) { + case M88E1111_I_PHY_ID: + phy->type = e1000_phy_m88; + phy->ops.get_phy_info = igb_get_phy_info_m88; + phy->ops.get_cable_length = igb_get_cable_length_m88; + phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; + break; + case IGP03E1000_E_PHY_ID: + phy->type = e1000_phy_igp_3; + phy->ops.get_phy_info = igb_get_phy_info_igp; + phy->ops.get_cable_length = igb_get_cable_length_igp_2; + phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp; + phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82575; + phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state; + break; + default: + return -E1000_ERR_PHY; + } + + return 0; +} + +/** + * e1000_acquire_phy_82575 - Acquire rights to access PHY + * @hw: pointer to the HW structure + * + * Acquire access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static s32 igb_acquire_phy_82575(struct e1000_hw *hw) +{ + u16 mask; + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + + return igb_acquire_swfw_sync_82575(hw, mask); +} + +/** + * e1000_release_phy_82575 - Release rights to access PHY + * @hw: pointer to the HW structure + * + * A wrapper to release access rights to the correct PHY. This is a + * function pointer entry point called by the api module. + **/ +static void igb_release_phy_82575(struct e1000_hw *hw) +{ + u16 mask; + + mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; + igb_release_swfw_sync_82575(hw, mask); +} + +/** + * e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the PHY register at offset using the serial gigabit media independent + * interface and stores the retrieved information in data. + **/ +static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, + u16 *data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, i2ccmd = 0; + + if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { + hw_dbg(hw, "PHY Address %u is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* + * Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | + (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | + (E1000_I2CCMD_OPCODE_READ)); + + wr32(E1000_I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + udelay(50); + i2ccmd = rd32(E1000_I2CCMD); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + hw_dbg(hw, "I2CCMD Read did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + hw_dbg(hw, "I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + /* Need to byte-swap the 16-bit value. */ + *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00); + + return 0; +} + +/** + * e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes the data to PHY register at the offset using the serial gigabit + * media independent interface. + **/ +static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, + u16 data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, i2ccmd = 0; + u16 phy_data_swapped; + + if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + return -E1000_ERR_PARAM; + } + + /* Swap the data bytes for the I2C interface */ + phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00); + + /* + * Set up Op-code, Phy Address, and register address in the I2CCMD + * register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | + (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | + E1000_I2CCMD_OPCODE_WRITE | + phy_data_swapped); + + wr32(E1000_I2CCMD, i2ccmd); + + /* Poll the ready bit to see if the I2C read completed */ + for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { + udelay(50); + i2ccmd = rd32(E1000_I2CCMD); + if (i2ccmd & E1000_I2CCMD_READY) + break; + } + if (!(i2ccmd & E1000_I2CCMD_READY)) { + hw_dbg(hw, "I2CCMD Write did not complete\n"); + return -E1000_ERR_PHY; + } + if (i2ccmd & E1000_I2CCMD_ERROR) { + hw_dbg(hw, "I2CCMD Error bit set\n"); + return -E1000_ERR_PHY; + } + + return 0; +} + +/** + * e1000_get_phy_id_82575 - Retreive PHY addr and id + * @hw: pointer to the HW structure + * + * Retreives the PHY address and ID for both PHY's which do and do not use + * sgmi interface. + **/ +static s32 igb_get_phy_id_82575(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 phy_id; + + /* + * For SGMII PHYs, we try the list of possible addresses until + * we find one that works. For non-SGMII PHYs + * (e.g. integrated copper PHYs), an address of 1 should + * work. The result of this function should mean phy->phy_addr + * and phy->id are set correctly. + */ + if (!(igb_sgmii_active_82575(hw))) { + phy->addr = 1; + ret_val = igb_get_phy_id(hw); + goto out; + } + + /* + * The address field in the I2CCMD register is 3 bits and 0 is invalid. + * Therefore, we need to test 1-7 + */ + for (phy->addr = 1; phy->addr < 8; phy->addr++) { + ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id); + if (ret_val == 0) { + hw_dbg(hw, "Vendor ID 0x%08X read at address %u\n", + phy_id, + phy->addr); + /* + * At the time of this writing, The M88 part is + * the only supported SGMII PHY product. + */ + if (phy_id == M88_VENDOR) + break; + } else { + hw_dbg(hw, "PHY address %u was unreadable\n", + phy->addr); + } + } + + /* A valid PHY type couldn't be found. */ + if (phy->addr == 8) { + phy->addr = 0; + ret_val = -E1000_ERR_PHY; + goto out; + } + + ret_val = igb_get_phy_id(hw); + +out: + return ret_val; +} + +/** + * e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset + * @hw: pointer to the HW structure + * + * Resets the PHY using the serial gigabit media independent interface. + **/ +static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw) +{ + s32 ret_val; + + /* + * This isn't a true "hard" reset, but is the only reset + * available to us at this time. + */ + + hw_dbg(hw, "Soft resetting SGMII attached PHY...\n"); + + /* + * SFP documentation requires the following to configure the SPF module + * to work on SGMII. No further documentation is given. + */ + ret_val = hw->phy.ops.write_phy_reg(hw, 0x1B, 0x8084); + if (ret_val) + goto out; + + ret_val = igb_phy_sw_reset(hw); + +out: + return ret_val; +} + +/** + * e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state + * @hw: pointer to the HW structure + * @active: true to enable LPLU, false to disable + * + * Sets the LPLU D0 state according to the active flag. When + * activating LPLU this function also disables smart speed + * and vice versa. LPLU will not be activated unless the + * device autonegotiation advertisement meets standards of + * either 10 or 10/100 or 10/100/1000 at all duplexes. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + &data); + if (ret_val) + goto out; + + if (active) { + data |= IGP02E1000_PM_D0_LPLU; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + goto out; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else { + data &= ~IGP02E1000_PM_D0_LPLU; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_acquire_nvm_82575 - Request for access to EEPROM + * @hw: pointer to the HW structure + * + * Acquire the necessary semaphores for exclussive access to the EEPROM. + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +static s32 igb_acquire_nvm_82575(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + if (ret_val) + goto out; + + ret_val = igb_acquire_nvm(hw); + + if (ret_val) + igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); + +out: + return ret_val; +} + +/** + * e1000_release_nvm_82575 - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit, + * then release the semaphores acquired. + **/ +static void igb_release_nvm_82575(struct e1000_hw *hw) +{ + igb_release_nvm(hw); + igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); +} + +/** + * e1000_acquire_swfw_sync_82575 - Acquire SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Acquire the SW/FW semaphore to access the PHY or NVM. The mask + * will also specify which port we're acquiring the lock for. + **/ +static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + u32 swmask = mask; + u32 fwmask = mask << 16; + s32 ret_val = 0; + s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ + + while (i < timeout) { + if (igb_get_hw_semaphore(hw)) { + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync = rd32(E1000_SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + /* + * Firmware currently using resource (fwmask) + * or other software thread using resource (swmask) + */ + igb_put_hw_semaphore(hw); + mdelay(5); + i++; + } + + if (i == timeout) { + hw_dbg(hw, "Can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -E1000_ERR_SWFW_SYNC; + goto out; + } + + swfw_sync |= swmask; + wr32(E1000_SW_FW_SYNC, swfw_sync); + + igb_put_hw_semaphore(hw); + +out: + return ret_val; +} + +/** + * e1000_release_swfw_sync_82575 - Release SW/FW semaphore + * @hw: pointer to the HW structure + * @mask: specifies which semaphore to acquire + * + * Release the SW/FW semaphore used to access the PHY or NVM. The mask + * will also specify which port we're releasing the lock for. + **/ +static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask) +{ + u32 swfw_sync; + + while (igb_get_hw_semaphore(hw) != 0); + /* Empty */ + + swfw_sync = rd32(E1000_SW_FW_SYNC); + swfw_sync &= ~mask; + wr32(E1000_SW_FW_SYNC, swfw_sync); + + igb_put_hw_semaphore(hw); +} + +/** + * e1000_get_cfg_done_82575 - Read config done bit + * @hw: pointer to the HW structure + * + * Read the management control register for the config done bit for + * completion status. NOTE: silicon which is EEPROM-less will fail trying + * to read the config done bit, so an error is *ONLY* logged and returns + * 0. If we were to return with error, EEPROM-less silicon + * would not be able to be reset or change link. + **/ +static s32 igb_get_cfg_done_82575(struct e1000_hw *hw) +{ + s32 timeout = PHY_CFG_TIMEOUT; + s32 ret_val = 0; + u32 mask = E1000_NVM_CFG_DONE_PORT_0; + + if (hw->bus.func == 1) + mask = E1000_NVM_CFG_DONE_PORT_1; + + while (timeout) { + if (rd32(E1000_EEMNGCTL) & mask) + break; + msleep(1); + timeout--; + } + if (!timeout) + hw_dbg(hw, "MNG configuration cycle has not completed.\n"); + + /* If EEPROM is not marked present, init the PHY manually */ + if (((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) && + (hw->phy.type == e1000_phy_igp_3)) + igb_phy_init_script_igp3(hw); + + return ret_val; +} + +/** + * e1000_check_for_link_82575 - Check for link + * @hw: pointer to the HW structure + * + * If sgmii is enabled, then use the pcs register to determine link, otherwise + * use the generic interface for determining link. + **/ +static s32 igb_check_for_link_82575(struct e1000_hw *hw) +{ + s32 ret_val; + u16 speed, duplex; + + /* SGMII link check is done through the PCS register. */ + if ((hw->phy.media_type != e1000_media_type_copper) || + (igb_sgmii_active_82575(hw))) + ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed, + &duplex); + else + ret_val = igb_check_for_copper_link(hw); + + return ret_val; +} + +/** + * e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Using the physical coding sub-layer (PCS), retreive the current speed and + * duplex, then store the values in the pointers provided. + **/ +static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 pcs; + + /* Set up defaults for the return values of this function */ + mac->serdes_has_link = false; + *speed = 0; + *duplex = 0; + + /* + * Read the PCS Status register for link state. For non-copper mode, + * the status register is not accurate. The PCS status register is + * used instead. + */ + pcs = rd32(E1000_PCS_LSTAT); + + /* + * The link up bit determines when link is up on autoneg. The sync ok + * gets set once both sides sync up and agree upon link. Stable link + * can be determined by checking for both link up and link sync ok + */ + if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) { + mac->serdes_has_link = true; + + /* Detect and store PCS speed */ + if (pcs & E1000_PCS_LSTS_SPEED_1000) { + *speed = SPEED_1000; + } else if (pcs & E1000_PCS_LSTS_SPEED_100) { + *speed = SPEED_100; + } else { + *speed = SPEED_10; + } + + /* Detect and store PCS duplex */ + if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) { + *duplex = FULL_DUPLEX; + } else { + *duplex = HALF_DUPLEX; + } + } + + return 0; +} + +/** + * e1000_rar_set_82575 - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. + **/ +static void igb_rar_set_82575(struct e1000_hw *hw, u8 *addr, u32 index) +{ + if (index < E1000_RAR_ENTRIES_82575) + igb_rar_set(hw, addr, index); + + return; +} + +/** + * e1000_reset_hw_82575 - Reset hardware + * @hw: pointer to the HW structure + * + * This resets the hardware into a known state. This is a + * function pointer entry point called by the api module. + **/ +static s32 igb_reset_hw_82575(struct e1000_hw *hw) +{ + u32 ctrl, icr; + s32 ret_val; + + /* + * Prevent the PCI-E bus from sticking if there is no TLP connection + * on the last TLP read/write transaction when MAC is reset. + */ + ret_val = igb_disable_pcie_master(hw); + if (ret_val) + hw_dbg(hw, "PCI-E Master disable polling has failed.\n"); + + hw_dbg(hw, "Masking off all interrupts\n"); + wr32(E1000_IMC, 0xffffffff); + + wr32(E1000_RCTL, 0); + wr32(E1000_TCTL, E1000_TCTL_PSP); + wrfl(); + + msleep(10); + + ctrl = rd32(E1000_CTRL); + + hw_dbg(hw, "Issuing a global reset to MAC\n"); + wr32(E1000_CTRL, ctrl | E1000_CTRL_RST); + + ret_val = igb_get_auto_rd_done(hw); + if (ret_val) { + /* + * When auto config read does not complete, do not + * return with an error. This can happen in situations + * where there is no eeprom and prevents getting link. + */ + hw_dbg(hw, "Auto Read Done did not complete\n"); + } + + /* If EEPROM is not present, run manual init scripts */ + if ((rd32(E1000_EECD) & E1000_EECD_PRES) == 0) + igb_reset_init_script_82575(hw); + + /* Clear any pending interrupt events. */ + wr32(E1000_IMC, 0xffffffff); + icr = rd32(E1000_ICR); + + igb_check_alt_mac_addr(hw); + + return ret_val; +} + +/** + * e1000_init_hw_82575 - Initialize hardware + * @hw: pointer to the HW structure + * + * This inits the hardware readying it for operation. + **/ +static s32 igb_init_hw_82575(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + u16 i, rar_count = mac->rar_entry_count; + + /* Initialize identification LED */ + ret_val = igb_id_led_init(hw); + if (ret_val) { + hw_dbg(hw, "Error initializing identification LED\n"); + /* This is not fatal and we should not stop init due to this */ + } + + /* Disabling VLAN filtering */ + hw_dbg(hw, "Initializing the IEEE VLAN\n"); + igb_clear_vfta(hw); + + /* Setup the receive address */ + igb_init_rx_addrs(hw, rar_count); + /* Zero out the Multicast HASH table */ + hw_dbg(hw, "Zeroing the MTA\n"); + for (i = 0; i < mac->mta_reg_count; i++) + array_wr32(E1000_MTA, i, 0); + + /* Setup link and flow control */ + ret_val = igb_setup_link(hw); + + /* + * Clear all of the statistics registers (clear on read). It is + * important that we do this after we have tried to establish link + * because the symbol error count will increment wildly if there + * is no link. + */ + igb_clear_hw_cntrs_82575(hw); + + return ret_val; +} + +/** + * e1000_setup_copper_link_82575 - Configure copper link settings + * @hw: pointer to the HW structure + * + * Configures the link for auto-neg or forced speed and duplex. Then we check + * for link, once link is established calls to configure collision distance + * and flow control are called. + **/ +static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) +{ + u32 ctrl, led_ctrl; + s32 ret_val; + bool link; + + ctrl = rd32(E1000_CTRL); + ctrl |= E1000_CTRL_SLU; + ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + wr32(E1000_CTRL, ctrl); + + switch (hw->phy.type) { + case e1000_phy_m88: + ret_val = igb_copper_link_setup_m88(hw); + break; + case e1000_phy_igp_3: + ret_val = igb_copper_link_setup_igp(hw); + /* Setup activity LED */ + led_ctrl = rd32(E1000_LEDCTL); + led_ctrl &= IGP_ACTIVITY_LED_MASK; + led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); + wr32(E1000_LEDCTL, led_ctrl); + break; + default: + ret_val = -E1000_ERR_PHY; + break; + } + + if (ret_val) + goto out; + + if (hw->mac.autoneg) { + /* + * Setup autoneg and flow control advertisement + * and perform autonegotiation. + */ + ret_val = igb_copper_link_autoneg(hw); + if (ret_val) + goto out; + } else { + /* + * PHY will be set to 10H, 10F, 100H or 100F + * depending on user settings. + */ + hw_dbg(hw, "Forcing Speed and Duplex\n"); + ret_val = igb_phy_force_speed_duplex(hw); + if (ret_val) { + hw_dbg(hw, "Error Forcing Speed and Duplex\n"); + goto out; + } + } + + ret_val = igb_configure_pcs_link_82575(hw); + if (ret_val) + goto out; + + /* + * Check link status. Wait up to 100 microseconds for link to become + * valid. + */ + ret_val = igb_phy_has_link(hw, + COPPER_LINK_UP_LIMIT, + 10, + &link); + if (ret_val) + goto out; + + if (link) { + hw_dbg(hw, "Valid link established!!!\n"); + /* Config the MAC and PHY after link is up */ + igb_config_collision_dist(hw); + ret_val = igb_config_fc_after_link_up(hw); + } else { + hw_dbg(hw, "Unable to establish link!!!\n"); + } + +out: + return ret_val; +} + +/** + * e1000_setup_fiber_serdes_link_82575 - Setup link for fiber/serdes + * @hw: pointer to the HW structure + * + * Configures speed and duplex for fiber and serdes links. + **/ +static s32 igb_setup_fiber_serdes_link_82575(struct e1000_hw *hw) +{ + u32 reg; + + /* + * On the 82575, SerDes loopback mode persists until it is + * explicitly turned off or a power cycle is performed. A read to + * the register does not indicate its status. Therefore, we ensure + * loopback mode is disabled during initialization. + */ + wr32(E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK); + + /* Force link up, set 1gb, set both sw defined pins */ + reg = rd32(E1000_CTRL); + reg |= E1000_CTRL_SLU | + E1000_CTRL_SPD_1000 | + E1000_CTRL_FRCSPD | + E1000_CTRL_SWDPIN0 | + E1000_CTRL_SWDPIN1; + wr32(E1000_CTRL, reg); + + /* Set switch control to serdes energy detect */ + reg = rd32(E1000_CONNSW); + reg |= E1000_CONNSW_ENRGSRC; + wr32(E1000_CONNSW, reg); + + /* + * New SerDes mode allows for forcing speed or autonegotiating speed + * at 1gb. Autoneg should be default set by most drivers. This is the + * mode that will be compatible with older link partners and switches. + * However, both are supported by the hardware and some drivers/tools. + */ + reg = rd32(E1000_PCS_LCTL); + + reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP | + E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); + + if (hw->mac.autoneg) { + /* Set PCS register for autoneg */ + reg |= E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */ + E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ + E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */ + E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */ + hw_dbg(hw, "Configuring Autoneg; PCS_LCTL = 0x%08X\n", reg); + } else { + /* Set PCS register for forced speed */ + reg |= E1000_PCS_LCTL_FLV_LINK_UP | /* Force link up */ + E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */ + E1000_PCS_LCTL_FDV_FULL | /* SerDes Full duplex */ + E1000_PCS_LCTL_FSD | /* Force Speed */ + E1000_PCS_LCTL_FORCE_LINK; /* Force Link */ + hw_dbg(hw, "Configuring Forced Link; PCS_LCTL = 0x%08X\n", reg); + } + wr32(E1000_PCS_LCTL, reg); + + return 0; +} + +/** + * e1000_configure_pcs_link_82575 - Configure PCS link + * @hw: pointer to the HW structure + * + * Configure the physical coding sub-layer (PCS) link. The PCS link is + * only used on copper connections where the serialized gigabit media + * independent interface (sgmii) is being used. Configures the link + * for auto-negotiation or forces speed/duplex. + **/ +static s32 igb_configure_pcs_link_82575(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 reg = 0; + + if (hw->phy.media_type != e1000_media_type_copper || + !(igb_sgmii_active_82575(hw))) + goto out; + + /* For SGMII, we need to issue a PCS autoneg restart */ + reg = rd32(E1000_PCS_LCTL); + + /* AN time out should be disabled for SGMII mode */ + reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT); + + if (mac->autoneg) { + /* Make sure forced speed and force link are not set */ + reg &= ~(E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); + + /* + * The PHY should be setup prior to calling this function. + * All we need to do is restart autoneg and enable autoneg. + */ + reg |= E1000_PCS_LCTL_AN_RESTART | E1000_PCS_LCTL_AN_ENABLE; + } else { + /* Set PCS regiseter for forced speed */ + + /* Turn off bits for full duplex, speed, and autoneg */ + reg &= ~(E1000_PCS_LCTL_FSV_1000 | + E1000_PCS_LCTL_FSV_100 | + E1000_PCS_LCTL_FDV_FULL | + E1000_PCS_LCTL_AN_ENABLE); + + /* Check for duplex first */ + if (mac->forced_speed_duplex & E1000_ALL_FULL_DUPLEX) + reg |= E1000_PCS_LCTL_FDV_FULL; + + /* Now set speed */ + if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) + reg |= E1000_PCS_LCTL_FSV_100; + + /* Force speed and force link */ + reg |= E1000_PCS_LCTL_FSD | + E1000_PCS_LCTL_FORCE_LINK | + E1000_PCS_LCTL_FLV_LINK_UP; + + hw_dbg(hw, + "Wrote 0x%08X to PCS_LCTL to configure forced link\n", + reg); + } + wr32(E1000_PCS_LCTL, reg); + +out: + return 0; +} + +/** + * e1000_sgmii_active_82575 - Return sgmii state + * @hw: pointer to the HW structure + * + * 82575 silicon has a serialized gigabit media independent interface (sgmii) + * which can be enabled for use in the embedded applications. Simply + * return the current state of the sgmii interface. + **/ +static bool igb_sgmii_active_82575(struct e1000_hw *hw) +{ + struct e1000_dev_spec_82575 *dev_spec; + bool ret_val; + + if (hw->mac.type != e1000_82575) { + ret_val = false; + goto out; + } + + dev_spec = (struct e1000_dev_spec_82575 *)hw->dev_spec; + + ret_val = dev_spec->sgmii_active; + +out: + return ret_val; +} + +/** + * e1000_reset_init_script_82575 - Inits HW defaults after reset + * @hw: pointer to the HW structure + * + * Inits recommended HW defaults after a reset when there is no EEPROM + * detected. This is only for the 82575. + **/ +static s32 igb_reset_init_script_82575(struct e1000_hw *hw) +{ + if (hw->mac.type == e1000_82575) { + hw_dbg(hw, "Running reset init script for 82575\n"); + /* SerDes configuration via SERDESCTRL */ + igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x00, 0x0C); + igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x01, 0x78); + igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x1B, 0x23); + igb_write_8bit_ctrl_reg(hw, E1000_SCTL, 0x23, 0x15); + + /* CCM configuration via CCMCTL register */ + igb_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x14, 0x00); + igb_write_8bit_ctrl_reg(hw, E1000_CCMCTL, 0x10, 0x00); + + /* PCIe lanes configuration */ + igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x00, 0xEC); + igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x61, 0xDF); + igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x34, 0x05); + igb_write_8bit_ctrl_reg(hw, E1000_GIOCTL, 0x2F, 0x81); + + /* PCIe PLL Configuration */ + igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x02, 0x47); + igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x14, 0x00); + igb_write_8bit_ctrl_reg(hw, E1000_SCCTL, 0x10, 0x00); + } + + return 0; +} + +/** + * e1000_read_mac_addr_82575 - Read device MAC address + * @hw: pointer to the HW structure + **/ +static s32 igb_read_mac_addr_82575(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + if (igb_check_alt_mac_addr(hw)) + ret_val = igb_read_mac_addr(hw); + + return ret_val; +} + +/** + * e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters + * @hw: pointer to the HW structure + * + * Clears the hardware counters by reading the counter registers. + **/ +static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw) +{ + u32 temp; + + igb_clear_hw_cntrs_base(hw); + + temp = rd32(E1000_PRC64); + temp = rd32(E1000_PRC127); + temp = rd32(E1000_PRC255); + temp = rd32(E1000_PRC511); + temp = rd32(E1000_PRC1023); + temp = rd32(E1000_PRC1522); + temp = rd32(E1000_PTC64); + temp = rd32(E1000_PTC127); + temp = rd32(E1000_PTC255); + temp = rd32(E1000_PTC511); + temp = rd32(E1000_PTC1023); + temp = rd32(E1000_PTC1522); + + temp = rd32(E1000_ALGNERRC); + temp = rd32(E1000_RXERRC); + temp = rd32(E1000_TNCRS); + temp = rd32(E1000_CEXTERR); + temp = rd32(E1000_TSCTC); + temp = rd32(E1000_TSCTFC); + + temp = rd32(E1000_MGTPRC); + temp = rd32(E1000_MGTPDC); + temp = rd32(E1000_MGTPTC); + + temp = rd32(E1000_IAC); + temp = rd32(E1000_ICRXOC); + + temp = rd32(E1000_ICRXPTC); + temp = rd32(E1000_ICRXATC); + temp = rd32(E1000_ICTXPTC); + temp = rd32(E1000_ICTXATC); + temp = rd32(E1000_ICTXQEC); + temp = rd32(E1000_ICTXQMTC); + temp = rd32(E1000_ICRXDMTC); + + temp = rd32(E1000_CBTMPC); + temp = rd32(E1000_HTDPMC); + temp = rd32(E1000_CBRMPC); + temp = rd32(E1000_RPTHC); + temp = rd32(E1000_HGPTC); + temp = rd32(E1000_HTCBDPC); + temp = rd32(E1000_HGORCL); + temp = rd32(E1000_HGORCH); + temp = rd32(E1000_HGOTCL); + temp = rd32(E1000_HGOTCH); + temp = rd32(E1000_LENERRS); + + /* This register should not be read in copper configurations */ + if (hw->phy.media_type == e1000_media_type_internal_serdes) + temp = rd32(E1000_SCVPC); +} + +static struct e1000_mac_operations e1000_mac_ops_82575 = { + .reset_hw = igb_reset_hw_82575, + .init_hw = igb_init_hw_82575, + .check_for_link = igb_check_for_link_82575, + .rar_set = igb_rar_set_82575, + .read_mac_addr = igb_read_mac_addr_82575, + .get_speed_and_duplex = igb_get_speed_and_duplex_copper, +}; + +static struct e1000_phy_operations e1000_phy_ops_82575 = { + .acquire_phy = igb_acquire_phy_82575, + .get_cfg_done = igb_get_cfg_done_82575, + .release_phy = igb_release_phy_82575, +}; + +static struct e1000_nvm_operations e1000_nvm_ops_82575 = { + .acquire_nvm = igb_acquire_nvm_82575, + .read_nvm = igb_read_nvm_eerd, + .release_nvm = igb_release_nvm_82575, + .write_nvm = igb_write_nvm_spi, +}; + +const struct e1000_info e1000_82575_info = { + .get_invariants = igb_get_invariants_82575, + .mac_ops = &e1000_mac_ops_82575, + .phy_ops = &e1000_phy_ops_82575, + .nvm_ops = &e1000_nvm_ops_82575, +}; + diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h new file mode 100644 index 000000000000..6604d96bd567 --- /dev/null +++ b/drivers/net/igb/e1000_82575.h @@ -0,0 +1,150 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_82575_H_ +#define _E1000_82575_H_ + +#define E1000_RAR_ENTRIES_82575 16 + +/* SRRCTL bit definitions */ +#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */ +#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */ +#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 +#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 + +#define E1000_MRQC_ENABLE_RSS_4Q 0x00000002 +#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 +#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 +#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 + +#define E1000_EICR_TX_QUEUE ( \ + E1000_EICR_TX_QUEUE0 | \ + E1000_EICR_TX_QUEUE1 | \ + E1000_EICR_TX_QUEUE2 | \ + E1000_EICR_TX_QUEUE3) + +#define E1000_EICR_RX_QUEUE ( \ + E1000_EICR_RX_QUEUE0 | \ + E1000_EICR_RX_QUEUE1 | \ + E1000_EICR_RX_QUEUE2 | \ + E1000_EICR_RX_QUEUE3) + +#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE +#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE + +/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */ + +/* Receive Descriptor - Advanced */ +union e1000_adv_rx_desc { + struct { + u64 pkt_addr; /* Packet buffer address */ + u64 hdr_addr; /* Header buffer address */ + } read; + struct { + struct { + struct { + u16 pkt_info; /* RSS type, Packet type */ + u16 hdr_info; /* Split Header, + * header buffer length */ + } lo_dword; + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; /* Packet length */ + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0 +#define E1000_RXDADV_HDRBUFLEN_SHIFT 5 + +/* RSS Hash results */ + +/* RSS Packet Types as indicated in the receive descriptor */ + +/* Transmit Descriptor - Advanced */ +union e1000_adv_tx_desc { + struct { + u64 buffer_addr; /* Address of descriptor's data buf */ + u32 cmd_type_len; + u32 olinfo_status; + } read; + struct { + u64 rsvd; /* Reserved */ + u32 nxtseq_seed; + u32 status; + } wb; +}; + +/* Adv Transmit Descriptor Config Masks */ +#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */ +#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ +#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */ +#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */ +#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ +#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ + +/* Context descriptors */ +struct e1000_adv_tx_context_desc { + u32 vlan_macip_lens; + u32 seqnum_seed; + u32 type_tucmd_mlhl; + u32 mss_l4len_idx; +}; + +#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ +#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ +#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ +/* IPSec Encrypt Enable for ESP */ +#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ +#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ +/* Adv ctxt IPSec SA IDX mask */ +/* Adv ctxt IPSec ESP len mask */ + +/* Additional Transmit Descriptor Control definitions */ +#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */ +/* Tx Queue Arbitration Priority 0=low, 1=high */ + +/* Additional Receive Descriptor Control definitions */ +#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */ + +/* Direct Cache Access (DCA) definitions */ + + + +#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */ + +#endif diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h new file mode 100644 index 000000000000..8da9ffedc425 --- /dev/null +++ b/drivers/net/igb/e1000_defines.h @@ -0,0 +1,772 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_DEFINES_H_ +#define _E1000_DEFINES_H_ + +/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ +#define REQ_TX_DESCRIPTOR_MULTIPLE 8 +#define REQ_RX_DESCRIPTOR_MULTIPLE 8 + +/* Definitions for power management and wakeup registers */ +/* Wake Up Control */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ + +/* Wake Up Filter Control */ +#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ +#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ +#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ +#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ +#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ +#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ +#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ +#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ +#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ +#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ +#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ +#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ +#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */ + +/* Wake Up Status */ + +/* Wake Up Packet Length */ + +/* Four Flexible Filters are supported */ +#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 + +/* Each Flexible Filter is at most 128 (0x80) bytes in length */ +#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 + + +/* Extended Device Control */ +#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ +#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */ +#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */ +#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ +#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ +#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000 +#define E1000_CTRL_EXT_EIAME 0x01000000 +#define E1000_CTRL_EXT_IRCA 0x00000001 +/* Interrupt delay cancellation */ +/* Driver loaded bit for FW */ +#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 +/* Interrupt acknowledge Auto-mask */ +/* Clear Interrupt timers after IMS clear */ +/* packet buffer parity error detection enabled */ +/* descriptor FIFO parity error detection enable */ +#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ +#define E1000_I2CCMD_REG_ADDR_SHIFT 16 +#define E1000_I2CCMD_PHY_ADDR_SHIFT 24 +#define E1000_I2CCMD_OPCODE_READ 0x08000000 +#define E1000_I2CCMD_OPCODE_WRITE 0x00000000 +#define E1000_I2CCMD_READY 0x20000000 +#define E1000_I2CCMD_ERROR 0x80000000 +#define E1000_MAX_SGMII_PHY_REG_ADDR 255 +#define E1000_I2CCMD_PHY_TIMEOUT 200 + +/* Receive Decriptor bit definitions */ +#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ +#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ +#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ +#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ +#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum caculated */ +#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ +#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ +#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ +#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ +#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ +#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ +#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ +#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ + +#define E1000_RXDEXT_STATERR_CE 0x01000000 +#define E1000_RXDEXT_STATERR_SE 0x02000000 +#define E1000_RXDEXT_STATERR_SEQ 0x04000000 +#define E1000_RXDEXT_STATERR_CXE 0x10000000 +#define E1000_RXDEXT_STATERR_TCPE 0x20000000 +#define E1000_RXDEXT_STATERR_IPE 0x40000000 +#define E1000_RXDEXT_STATERR_RXE 0x80000000 + +/* mask to determine if packets should be dropped due to frame errors */ +#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ + E1000_RXD_ERR_CE | \ + E1000_RXD_ERR_SE | \ + E1000_RXD_ERR_SEQ | \ + E1000_RXD_ERR_CXE | \ + E1000_RXD_ERR_RXE) + +/* Same mask, but for extended and packet split descriptors */ +#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ + E1000_RXDEXT_STATERR_CE | \ + E1000_RXDEXT_STATERR_SE | \ + E1000_RXDEXT_STATERR_SEQ | \ + E1000_RXDEXT_STATERR_CXE | \ + E1000_RXDEXT_STATERR_RXE) + +#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 +#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 +#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 + + +/* Management Control */ +#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ +#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ +#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ +/* Enable Neighbor Discovery Filtering */ +#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ +#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ +/* Enable MAC address filtering */ +#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 +/* Enable MNG packets to host memory */ +#define E1000_MANC_EN_MNG2HOST 0x00200000 +/* Enable IP address filtering */ + + +/* Receive Control */ +#define E1000_RCTL_EN 0x00000002 /* enable */ +#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ +#define E1000_RCTL_UPE 0x00000008 /* unicast promiscuous enable */ +#define E1000_RCTL_MPE 0x00000010 /* multicast promiscuous enab */ +#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ +#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ +#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ +#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ +#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ +#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ +#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ +#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ +#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ +#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ +#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ +/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ +#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ +#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ +#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ +#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ +#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ +#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ +#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ + +/* + * Use byte values for the following shift parameters + * Usage: + * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & + * E1000_PSRCTL_BSIZE0_MASK) | + * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & + * E1000_PSRCTL_BSIZE1_MASK) | + * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & + * E1000_PSRCTL_BSIZE2_MASK) | + * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; + * E1000_PSRCTL_BSIZE3_MASK)) + * where value0 = [128..16256], default=256 + * value1 = [1024..64512], default=4096 + * value2 = [0..64512], default=4096 + * value3 = [0..64512], default=0 + */ + +#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F +#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 +#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 +#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 + +#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ +#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ +#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ +#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ + +/* SWFW_SYNC Definitions */ +#define E1000_SWFW_EEP_SM 0x1 +#define E1000_SWFW_PHY0_SM 0x2 +#define E1000_SWFW_PHY1_SM 0x4 + +/* FACTPS Definitions */ +/* Device Control */ +#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ +#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */ +#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ +#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ +#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ +#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ +#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ +#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ +#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ +#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ +/* Defined polarity of Dock/Undock indication in SDP[0] */ +/* Reset both PHY ports, through PHYRST_N pin */ +/* enable link status from external LINK_0 and LINK_1 pins */ +#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ +#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ +#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ +#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ +#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ +#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ +#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ +#define E1000_CTRL_RST 0x04000000 /* Global reset */ +#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ +#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ +#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ +#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ +/* Initiate an interrupt to manageability engine */ +#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */ + +/* Bit definitions for the Management Data IO (MDIO) and Management Data + * Clock (MDC) pins in the Device Control Register. + */ + +#define E1000_CONNSW_ENRGSRC 0x4 +#define E1000_PCS_LCTL_FLV_LINK_UP 1 +#define E1000_PCS_LCTL_FSV_100 2 +#define E1000_PCS_LCTL_FSV_1000 4 +#define E1000_PCS_LCTL_FDV_FULL 8 +#define E1000_PCS_LCTL_FSD 0x10 +#define E1000_PCS_LCTL_FORCE_LINK 0x20 +#define E1000_PCS_LCTL_AN_ENABLE 0x10000 +#define E1000_PCS_LCTL_AN_RESTART 0x20000 +#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 + +#define E1000_PCS_LSTS_LINK_OK 1 +#define E1000_PCS_LSTS_SPEED_100 2 +#define E1000_PCS_LSTS_SPEED_1000 4 +#define E1000_PCS_LSTS_DUPLEX_FULL 8 +#define E1000_PCS_LSTS_SYNK_OK 0x10 + +/* Device Status */ +#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ +#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ +#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ +#define E1000_STATUS_FUNC_SHIFT 2 +#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ +#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ +#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ +#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ +/* Change in Dock/Undock state. Clear on write '0'. */ +/* Status of Master requests. */ +#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 +/* BMC external code execution disabled */ + +/* Constants used to intrepret the masked PCI-X bus speed. */ + +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define HALF_DUPLEX 1 +#define FULL_DUPLEX 2 + + +#define ADVERTISE_10_HALF 0x0001 +#define ADVERTISE_10_FULL 0x0002 +#define ADVERTISE_100_HALF 0x0004 +#define ADVERTISE_100_FULL 0x0008 +#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ +#define ADVERTISE_1000_FULL 0x0020 + +/* 1000/H is not supported, nor spec-compliant. */ +#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define E1000_ALL_NOT_GIG (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ + ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) +#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) +#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \ + ADVERTISE_1000_FULL) +#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) + +#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX + +/* LED Control */ +#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F +#define E1000_LEDCTL_LED0_MODE_SHIFT 0 +#define E1000_LEDCTL_LED0_IVRT 0x00000040 +#define E1000_LEDCTL_LED0_BLINK 0x00000080 + +#define E1000_LEDCTL_MODE_LED_ON 0xE +#define E1000_LEDCTL_MODE_LED_OFF 0xF + +/* Transmit Descriptor bit definitions */ +#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ +#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ +#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ +#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ +#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ +#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +/* Extended desc bits for Linksec and timesync */ + +/* Transmit Control */ +#define E1000_TCTL_EN 0x00000002 /* enable tx */ +#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ +#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ +#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ +#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ + +/* Transmit Arbitration Count */ + +/* SerDes Control */ +#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 + +/* Receive Checksum Control */ +#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ +#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ +#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ + +/* Header split receive */ + +/* Collision related configuration parameters */ +#define E1000_COLLISION_THRESHOLD 15 +#define E1000_CT_SHIFT 4 +#define E1000_COLLISION_DISTANCE 63 +#define E1000_COLD_SHIFT 12 + +/* Ethertype field values */ +#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ + +#define MAX_JUMBO_FRAME_SIZE 0x3F00 + +/* Extended Configuration Control and Size */ +#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 + +/* PBA constants */ +#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */ +#define E1000_PBA_24K 0x0018 +#define E1000_PBA_34K 0x0022 + +#define IFS_MAX 80 +#define IFS_MIN 40 +#define IFS_RATIO 4 +#define IFS_STEP 10 +#define MIN_NUM_XMITS 1000 + +/* SW Semaphore Register */ +#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ + +/* Interrupt Cause Read */ +#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ +#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ +#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ +#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ +#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ +#define E1000_ICR_RXO 0x00000040 /* rx overrun */ +#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ +#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ +#define E1000_ICR_RXCFG 0x00000400 /* RX /c/ ordered set */ +#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ +#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ +#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ +#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ +#define E1000_ICR_TXD_LOW 0x00008000 +#define E1000_ICR_SRPD 0x00010000 +#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ +#define E1000_ICR_MNG 0x00040000 /* Manageability event */ +#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ +/* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_INT_ASSERTED 0x80000000 +/* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 +/* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 +/* host arb read buffer parity error */ +#define E1000_ICR_HOST_ARB_PAR 0x00400000 +#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ +/* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 +/* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 +/* FW changed the status of DISSW bit in the FWSM */ +#define E1000_ICR_DSW 0x00000020 +/* LAN connected device generates an interrupt */ +#define E1000_ICR_PHYINT 0x00001000 +#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */ + +/* Extended Interrupt Cause Read */ +#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */ +#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */ +#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */ +#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */ +#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */ +#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */ +#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */ +#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */ +#define E1000_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ +#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ +/* TCP Timer */ + +/* + * This defines the bits that are set in the Interrupt Mask + * Set/Read Register. Each bit is documented below: + * o RXT0 = Receiver Timer Interrupt (ring 0) + * o TXDW = Transmit Descriptor Written Back + * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) + * o RXSEQ = Receive Sequence Error + * o LSC = Link Status Change + */ +#define IMS_ENABLE_MASK ( \ + E1000_IMS_RXT0 | \ + E1000_IMS_TXDW | \ + E1000_IMS_RXDMT0 | \ + E1000_IMS_RXSEQ | \ + E1000_IMS_LSC) + +/* Interrupt Mask Set */ +#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ +#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ +#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ +/* queue 0 Rx descriptor FIFO parity error */ +/* queue 0 Tx descriptor FIFO parity error */ +/* host arb read buffer parity error */ +/* packet buffer parity error */ +/* queue 1 Rx descriptor FIFO parity error */ +/* queue 1 Tx descriptor FIFO parity error */ + +/* Extended Interrupt Mask Set */ +#define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ +#define E1000_EIMS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ + +/* Interrupt Cause Set */ +#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ +#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ +/* queue 0 Rx descriptor FIFO parity error */ +/* queue 0 Tx descriptor FIFO parity error */ +/* host arb read buffer parity error */ +/* packet buffer parity error */ +/* queue 1 Rx descriptor FIFO parity error */ +/* queue 1 Tx descriptor FIFO parity error */ + +/* Extended Interrupt Cause Set */ + +/* Transmit Descriptor Control */ +/* Enable the counting of descriptors still to be processed. */ + +/* Flow Control Constants */ +#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 +#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 +#define FLOW_CONTROL_TYPE 0x8808 + +/* 802.1q VLAN Packet Size */ +#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */ +#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ + +/* Receive Address */ +/* + * Number of high/low register pairs in the RAR. The RAR (Receive Address + * Registers) holds the directed and multicast addresses that we monitor. + * Technically, we have 16 spots. However, we reserve one of these spots + * (RAR[15]) for our directed address used by controllers with + * manageability enabled, allowing us room for 15 multicast addresses. + */ +#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ + +/* Error Codes */ +#define E1000_ERR_NVM 1 +#define E1000_ERR_PHY 2 +#define E1000_ERR_CONFIG 3 +#define E1000_ERR_PARAM 4 +#define E1000_ERR_MAC_INIT 5 +#define E1000_ERR_RESET 9 +#define E1000_ERR_MASTER_REQUESTS_PENDING 10 +#define E1000_ERR_HOST_INTERFACE_COMMAND 11 +#define E1000_BLK_PHY_RESET 12 +#define E1000_ERR_SWFW_SYNC 13 +#define E1000_NOT_IMPLEMENTED 14 + +/* Loop limit on how long we wait for auto-negotiation to complete */ +#define COPPER_LINK_UP_LIMIT 10 +#define PHY_AUTO_NEG_LIMIT 45 +#define PHY_FORCE_LIMIT 20 +/* Number of 100 microseconds we wait for PCI Express master disable */ +#define MASTER_DISABLE_TIMEOUT 800 +/* Number of milliseconds we wait for PHY configuration done after MAC reset */ +#define PHY_CFG_TIMEOUT 100 +/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ +/* Number of milliseconds for NVM auto read done after MAC reset. */ +#define AUTO_READ_DONE_TIMEOUT 10 + +/* Flow Control */ +#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ + +/* Transmit Configuration Word */ +#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ + +/* Receive Configuration Word */ + +/* PCI Express Control */ +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR_TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) + +/* PHY Control Register */ +#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ +#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ +#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ +#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ +#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ +#define MII_CR_SPEED_1000 0x0040 +#define MII_CR_SPEED_100 0x2000 +#define MII_CR_SPEED_10 0x0000 + +/* PHY Status Register */ +#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ +#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ + +/* Autoneg Advertisement Register */ +#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ +#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ +#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ +#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ +#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ +#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ + +/* Link Partner Ability Register (Base Page) */ +#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ +#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ + +/* Autoneg Expansion Register */ + +/* 1000BASE-T Control Register */ +#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ +#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ + /* 0=DTE device */ +#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ + /* 0=Configure PHY as Slave */ +#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ + /* 0=Automatic Master/Slave config */ + +/* 1000BASE-T Status Register */ +#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ +#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ + + +/* PHY 1000 MII Register/Bit Definitions */ +/* PHY Registers defined by IEEE */ +#define PHY_CONTROL 0x00 /* Control Register */ +#define PHY_STATUS 0x01 /* Status Regiser */ +#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ +#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ +#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ +#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ +#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ +#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ + +/* NVM Control */ +#define E1000_EECD_SK 0x00000001 /* NVM Clock */ +#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ +#define E1000_EECD_DI 0x00000004 /* NVM Data In */ +#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ +#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ +#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ +#define E1000_EECD_PRES 0x00000100 /* NVM Present */ +/* NVM Addressing bits based on type 0=small, 1=large */ +#define E1000_EECD_ADDR_BITS 0x00000400 +#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ +#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ +#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ +#define E1000_EECD_SIZE_EX_SHIFT 11 + +/* Offset to data in NVM read/write registers */ +#define E1000_NVM_RW_REG_DATA 16 +#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ +#define E1000_NVM_RW_REG_START 1 /* Start operation */ +#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ +#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ + +/* NVM Word Offsets */ +#define NVM_ID_LED_SETTINGS 0x0004 +/* For SERDES output amplitude adjustment. */ +#define NVM_INIT_CONTROL2_REG 0x000F +#define NVM_INIT_CONTROL3_PORT_A 0x0024 +#define NVM_ALT_MAC_ADDR_PTR 0x0037 +#define NVM_CHECKSUM_REG 0x003F + +#define E1000_NVM_CFG_DONE_PORT_0 0x40000 /* MNG config cycle done */ +#define E1000_NVM_CFG_DONE_PORT_1 0x80000 /* ...for second port */ + +/* Mask bits for fields in Word 0x0f of the NVM */ +#define NVM_WORD0F_PAUSE_MASK 0x3000 +#define NVM_WORD0F_ASM_DIR 0x2000 + +/* Mask bits for fields in Word 0x1a of the NVM */ + +/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ +#define NVM_SUM 0xBABA + +#define NVM_PBA_OFFSET_0 8 +#define NVM_PBA_OFFSET_1 9 +#define NVM_WORD_SIZE_BASE_SHIFT 6 + +/* NVM Commands - Microwire */ + +/* NVM Commands - SPI */ +#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ +#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ +#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ +#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ +#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ + +/* SPI NVM Status Register */ +#define NVM_STATUS_RDY_SPI 0x01 + +/* Word definitions for ID LED Settings */ +#define ID_LED_RESERVED_0000 0x0000 +#define ID_LED_RESERVED_FFFF 0xFFFF +#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ + (ID_LED_OFF1_OFF2 << 8) | \ + (ID_LED_DEF1_DEF2 << 4) | \ + (ID_LED_DEF1_DEF2)) +#define ID_LED_DEF1_DEF2 0x1 +#define ID_LED_DEF1_ON2 0x2 +#define ID_LED_DEF1_OFF2 0x3 +#define ID_LED_ON1_DEF2 0x4 +#define ID_LED_ON1_ON2 0x5 +#define ID_LED_ON1_OFF2 0x6 +#define ID_LED_OFF1_DEF2 0x7 +#define ID_LED_OFF1_ON2 0x8 +#define ID_LED_OFF1_OFF2 0x9 + +#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF +#define IGP_ACTIVITY_LED_ENABLE 0x0300 +#define IGP_LED3_MODE 0x07000000 + +/* PCI/PCI-X/PCI-EX Config space */ +#define PCI_HEADER_TYPE_REGISTER 0x0E +#define PCIE_LINK_STATUS 0x12 + +#define PCI_HEADER_TYPE_MULTIFUNC 0x80 +#define PCIE_LINK_WIDTH_MASK 0x3F0 +#define PCIE_LINK_WIDTH_SHIFT 4 + +#define PHY_REVISION_MASK 0xFFFFFFF0 +#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ +#define MAX_PHY_MULTI_PAGE_REG 0xF + +/* Bit definitions for valid PHY IDs. */ +/* + * I = Integrated + * E = External + */ +#define M88E1111_I_PHY_ID 0x01410CC0 +#define IGP03E1000_E_PHY_ID 0x02A80390 +#define M88_VENDOR 0x0141 + +/* M88E1000 Specific Registers */ +#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ +#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ +#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ + +#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ +#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ + +/* M88E1000 PHY Specific Control Register */ +#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */ +/* 1=CLK125 low, 0=CLK125 toggling */ +#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ + /* Manual MDI configuration */ +#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ +/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ +#define M88E1000_PSCR_AUTO_X_1000T 0x0040 +/* Auto crossover enabled all speeds */ +#define M88E1000_PSCR_AUTO_X_MODE 0x0060 +/* + * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T RX Threshold + * 0=Normal 10BASE-T RX Threshold + */ +/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ +#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Transmit */ + +/* M88E1000 PHY Specific Status Register */ +#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ +#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ +#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ +/* + * 0 = <50M + * 1 = 50-80M + * 2 = 80-110M + * 3 = 110-140M + * 4 = >140M + */ +#define M88E1000_PSSR_CABLE_LENGTH 0x0380 +#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ +#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ + +#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 + +/* M88E1000 Extended PHY Specific Control Register */ +/* + * 1 = Lost lock detect enabled. + * Will assert lost lock and bring + * link down if idle not seen + * within 1ms in 1000BASE-T + */ +/* + * Number of times we will attempt to autonegotiate before downshifting if we + * are the master + */ +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 +#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 +/* + * Number of times we will attempt to autonegotiate before downshifting if we + * are the slave + */ +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 +#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 +#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ + +/* M88EC018 Rev 2 specific DownShift settings */ +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 +#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 + +/* MDI Control */ +#define E1000_MDIC_REG_SHIFT 16 +#define E1000_MDIC_PHY_SHIFT 21 +#define E1000_MDIC_OP_WRITE 0x04000000 +#define E1000_MDIC_OP_READ 0x08000000 +#define E1000_MDIC_READY 0x10000000 +#define E1000_MDIC_ERROR 0x40000000 + +/* SerDes Control */ +#define E1000_GEN_CTL_READY 0x80000000 +#define E1000_GEN_CTL_ADDRESS_SHIFT 8 +#define E1000_GEN_POLL_TIMEOUT 640 + +#endif diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h new file mode 100644 index 000000000000..161fb68764af --- /dev/null +++ b/drivers/net/igb/e1000_hw.h @@ -0,0 +1,599 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_HW_H_ +#define _E1000_HW_H_ + +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include "e1000_mac.h" +#include "e1000_regs.h" +#include "e1000_defines.h" + +struct e1000_hw; + +#define E1000_DEV_ID_82575EB_COPPER 0x10A7 +#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 +#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 + +#define E1000_REVISION_2 2 +#define E1000_REVISION_4 4 + +#define E1000_FUNC_1 1 + +enum e1000_mac_type { + e1000_undefined = 0, + e1000_82575, + e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ +}; + +enum e1000_media_type { + e1000_media_type_unknown = 0, + e1000_media_type_copper = 1, + e1000_media_type_fiber = 2, + e1000_media_type_internal_serdes = 3, + e1000_num_media_types +}; + +enum e1000_nvm_type { + e1000_nvm_unknown = 0, + e1000_nvm_none, + e1000_nvm_eeprom_spi, + e1000_nvm_eeprom_microwire, + e1000_nvm_flash_hw, + e1000_nvm_flash_sw +}; + +enum e1000_nvm_override { + e1000_nvm_override_none = 0, + e1000_nvm_override_spi_small, + e1000_nvm_override_spi_large, + e1000_nvm_override_microwire_small, + e1000_nvm_override_microwire_large +}; + +enum e1000_phy_type { + e1000_phy_unknown = 0, + e1000_phy_none, + e1000_phy_m88, + e1000_phy_igp, + e1000_phy_igp_2, + e1000_phy_gg82563, + e1000_phy_igp_3, + e1000_phy_ife, +}; + +enum e1000_bus_type { + e1000_bus_type_unknown = 0, + e1000_bus_type_pci, + e1000_bus_type_pcix, + e1000_bus_type_pci_express, + e1000_bus_type_reserved +}; + +enum e1000_bus_speed { + e1000_bus_speed_unknown = 0, + e1000_bus_speed_33, + e1000_bus_speed_66, + e1000_bus_speed_100, + e1000_bus_speed_120, + e1000_bus_speed_133, + e1000_bus_speed_2500, + e1000_bus_speed_5000, + e1000_bus_speed_reserved +}; + +enum e1000_bus_width { + e1000_bus_width_unknown = 0, + e1000_bus_width_pcie_x1, + e1000_bus_width_pcie_x2, + e1000_bus_width_pcie_x4 = 4, + e1000_bus_width_pcie_x8 = 8, + e1000_bus_width_32, + e1000_bus_width_64, + e1000_bus_width_reserved +}; + +enum e1000_1000t_rx_status { + e1000_1000t_rx_status_not_ok = 0, + e1000_1000t_rx_status_ok, + e1000_1000t_rx_status_undefined = 0xFF +}; + +enum e1000_rev_polarity { + e1000_rev_polarity_normal = 0, + e1000_rev_polarity_reversed, + e1000_rev_polarity_undefined = 0xFF +}; + +enum e1000_fc_type { + e1000_fc_none = 0, + e1000_fc_rx_pause, + e1000_fc_tx_pause, + e1000_fc_full, + e1000_fc_default = 0xFF +}; + + +/* Receive Descriptor */ +struct e1000_rx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + u16 length; /* Length of data DMAed into data buffer */ + u16 csum; /* Packet checksum */ + u8 status; /* Descriptor status */ + u8 errors; /* Descriptor Errors */ + u16 special; +}; + +/* Receive Descriptor - Extended */ +union e1000_rx_desc_extended { + struct { + u64 buffer_addr; + u64 reserved; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length; + u16 vlan; /* VLAN tag */ + } upper; + } wb; /* writeback */ +}; + +#define MAX_PS_BUFFERS 4 +/* Receive Descriptor - Packet Split */ +union e1000_rx_desc_packet_split { + struct { + /* one buffer for protocol header(s), three data buffers */ + u64 buffer_addr[MAX_PS_BUFFERS]; + } read; + struct { + struct { + u32 mrq; /* Multiple Rx Queues */ + union { + u32 rss; /* RSS Hash */ + struct { + u16 ip_id; /* IP id */ + u16 csum; /* Packet Checksum */ + } csum_ip; + } hi_dword; + } lower; + struct { + u32 status_error; /* ext status/error */ + u16 length0; /* length of buffer 0 */ + u16 vlan; /* VLAN tag */ + } middle; + struct { + u16 header_status; + u16 length[3]; /* length of buffers 1-3 */ + } upper; + u64 reserved; + } wb; /* writeback */ +}; + +/* Transmit Descriptor */ +struct e1000_tx_desc { + u64 buffer_addr; /* Address of the descriptor's data buffer */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 cso; /* Checksum offset */ + u8 cmd; /* Descriptor control */ + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 css; /* Checksum start */ + u16 special; + } fields; + } upper; +}; + +/* Offload Context Descriptor */ +struct e1000_context_desc { + union { + u32 ip_config; + struct { + u8 ipcss; /* IP checksum start */ + u8 ipcso; /* IP checksum offset */ + u16 ipcse; /* IP checksum end */ + } ip_fields; + } lower_setup; + union { + u32 tcp_config; + struct { + u8 tucss; /* TCP checksum start */ + u8 tucso; /* TCP checksum offset */ + u16 tucse; /* TCP checksum end */ + } tcp_fields; + } upper_setup; + u32 cmd_and_length; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 hdr_len; /* Header length */ + u16 mss; /* Maximum segment size */ + } fields; + } tcp_seg_setup; +}; + +/* Offload data descriptor */ +struct e1000_data_desc { + u64 buffer_addr; /* Address of the descriptor's buffer address */ + union { + u32 data; + struct { + u16 length; /* Data buffer length */ + u8 typ_len_ext; + u8 cmd; + } flags; + } lower; + union { + u32 data; + struct { + u8 status; /* Descriptor status */ + u8 popts; /* Packet Options */ + u16 special; + } fields; + } upper; +}; + +/* Statistics counters collected by the MAC */ +struct e1000_hw_stats { + u64 crcerrs; + u64 algnerrc; + u64 symerrs; + u64 rxerrc; + u64 mpc; + u64 scc; + u64 ecol; + u64 mcc; + u64 latecol; + u64 colc; + u64 dc; + u64 tncrs; + u64 sec; + u64 cexterr; + u64 rlec; + u64 xonrxc; + u64 xontxc; + u64 xoffrxc; + u64 xofftxc; + u64 fcruc; + u64 prc64; + u64 prc127; + u64 prc255; + u64 prc511; + u64 prc1023; + u64 prc1522; + u64 gprc; + u64 bprc; + u64 mprc; + u64 gptc; + u64 gorc; + u64 gotc; + u64 rnbc; + u64 ruc; + u64 rfc; + u64 roc; + u64 rjc; + u64 mgprc; + u64 mgpdc; + u64 mgptc; + u64 tor; + u64 tot; + u64 tpr; + u64 tpt; + u64 ptc64; + u64 ptc127; + u64 ptc255; + u64 ptc511; + u64 ptc1023; + u64 ptc1522; + u64 mptc; + u64 bptc; + u64 tsctc; + u64 tsctfc; + u64 iac; + u64 icrxptc; + u64 icrxatc; + u64 ictxptc; + u64 ictxatc; + u64 ictxqec; + u64 ictxqmtc; + u64 icrxdmtc; + u64 icrxoc; + u64 cbtmpc; + u64 htdpmc; + u64 cbrdpc; + u64 cbrmpc; + u64 rpthc; + u64 hgptc; + u64 htcbdpc; + u64 hgorc; + u64 hgotc; + u64 lenerrs; + u64 scvpc; + u64 hrmpc; +}; + +struct e1000_phy_stats { + u32 idle_errors; + u32 receive_errors; +}; + +struct e1000_host_mng_dhcp_cookie { + u32 signature; + u8 status; + u8 reserved0; + u16 vlan_id; + u32 reserved1; + u16 reserved2; + u8 reserved3; + u8 checksum; +}; + +/* Host Interface "Rev 1" */ +struct e1000_host_command_header { + u8 command_id; + u8 command_length; + u8 command_options; + u8 checksum; +}; + +#define E1000_HI_MAX_DATA_LENGTH 252 +struct e1000_host_command_info { + struct e1000_host_command_header command_header; + u8 command_data[E1000_HI_MAX_DATA_LENGTH]; +}; + +/* Host Interface "Rev 2" */ +struct e1000_host_mng_command_header { + u8 command_id; + u8 checksum; + u16 reserved1; + u16 reserved2; + u16 command_length; +}; + +#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 +struct e1000_host_mng_command_info { + struct e1000_host_mng_command_header command_header; + u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; +}; + +#include "e1000_mac.h" +#include "e1000_phy.h" +#include "e1000_nvm.h" + +struct e1000_mac_operations { + s32 (*check_for_link)(struct e1000_hw *); + s32 (*reset_hw)(struct e1000_hw *); + s32 (*init_hw)(struct e1000_hw *); + s32 (*setup_physical_interface)(struct e1000_hw *); + void (*rar_set)(struct e1000_hw *, u8 *, u32); + s32 (*read_mac_addr)(struct e1000_hw *); + s32 (*get_speed_and_duplex)(struct e1000_hw *, u16 *, u16 *); +}; + +struct e1000_phy_operations { + s32 (*acquire_phy)(struct e1000_hw *); + s32 (*force_speed_duplex)(struct e1000_hw *); + s32 (*get_cfg_done)(struct e1000_hw *hw); + s32 (*get_cable_length)(struct e1000_hw *); + s32 (*get_phy_info)(struct e1000_hw *); + s32 (*read_phy_reg)(struct e1000_hw *, u32, u16 *); + void (*release_phy)(struct e1000_hw *); + s32 (*reset_phy)(struct e1000_hw *); + s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); + s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); + s32 (*write_phy_reg)(struct e1000_hw *, u32, u16); +}; + +struct e1000_nvm_operations { + s32 (*acquire_nvm)(struct e1000_hw *); + s32 (*read_nvm)(struct e1000_hw *, u16, u16, u16 *); + void (*release_nvm)(struct e1000_hw *); + s32 (*write_nvm)(struct e1000_hw *, u16, u16, u16 *); +}; + +struct e1000_info { + s32 (*get_invariants)(struct e1000_hw *); + struct e1000_mac_operations *mac_ops; + struct e1000_phy_operations *phy_ops; + struct e1000_nvm_operations *nvm_ops; +}; + +extern const struct e1000_info e1000_82575_info; + +struct e1000_mac_info { + struct e1000_mac_operations ops; + + u8 addr[6]; + u8 perm_addr[6]; + + enum e1000_mac_type type; + + u32 collision_delta; + u32 ledctl_default; + u32 ledctl_mode1; + u32 ledctl_mode2; + u32 mc_filter_type; + u32 tx_packet_delta; + u32 txcw; + + u16 current_ifs_val; + u16 ifs_max_val; + u16 ifs_min_val; + u16 ifs_ratio; + u16 ifs_step_size; + u16 mta_reg_count; + u16 rar_entry_count; + + u8 forced_speed_duplex; + + bool adaptive_ifs; + bool arc_subsystem_valid; + bool asf_firmware_present; + bool autoneg; + bool autoneg_failed; + bool disable_av; + bool disable_hw_init_bits; + bool get_link_status; + bool ifs_params_forced; + bool in_ifs_mode; + bool report_tx_early; + bool serdes_has_link; + bool tx_pkt_filtering; +}; + +struct e1000_phy_info { + struct e1000_phy_operations ops; + + enum e1000_phy_type type; + + enum e1000_1000t_rx_status local_rx; + enum e1000_1000t_rx_status remote_rx; + enum e1000_ms_type ms_type; + enum e1000_ms_type original_ms_type; + enum e1000_rev_polarity cable_polarity; + enum e1000_smart_speed smart_speed; + + u32 addr; + u32 id; + u32 reset_delay_us; /* in usec */ + u32 revision; + + enum e1000_media_type media_type; + + u16 autoneg_advertised; + u16 autoneg_mask; + u16 cable_length; + u16 max_cable_length; + u16 min_cable_length; + + u8 mdix; + + bool disable_polarity_correction; + bool is_mdix; + bool polarity_correction; + bool reset_disable; + bool speed_downgraded; + bool autoneg_wait_to_complete; +}; + +struct e1000_nvm_info { + struct e1000_nvm_operations ops; + + enum e1000_nvm_type type; + enum e1000_nvm_override override; + + u32 flash_bank_size; + u32 flash_base_addr; + + u16 word_size; + u16 delay_usec; + u16 address_bits; + u16 opcode_bits; + u16 page_size; +}; + +struct e1000_bus_info { + enum e1000_bus_type type; + enum e1000_bus_speed speed; + enum e1000_bus_width width; + + u32 snoop; + + u16 func; + u16 pci_cmd_word; +}; + +struct e1000_fc_info { + u32 high_water; /* Flow control high-water mark */ + u32 low_water; /* Flow control low-water mark */ + u16 pause_time; /* Flow control pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + enum e1000_fc_type type; /* Type of flow control */ + enum e1000_fc_type original_type; +}; + +struct e1000_hw { + void *back; + void *dev_spec; + + u8 __iomem *hw_addr; + u8 __iomem *flash_address; + unsigned long io_base; + + struct e1000_mac_info mac; + struct e1000_fc_info fc; + struct e1000_phy_info phy; + struct e1000_nvm_info nvm; + struct e1000_bus_info bus; + struct e1000_host_mng_dhcp_cookie mng_cookie; + + u32 dev_spec_size; + + u16 device_id; + u16 subsystem_vendor_id; + u16 subsystem_device_id; + u16 vendor_id; + + u8 revision_id; +}; + +#ifdef DEBUG +extern char *igb_get_hw_dev_name(struct e1000_hw *hw); +#define hw_dbg(hw, format, arg...) \ + printk(KERN_DEBUG "%s: " format, igb_get_hw_dev_name(hw), ##arg) +#else +static inline int __attribute__ ((format (printf, 2, 3))) +hw_dbg(struct e1000_hw *hw, const char *format, ...) +{ + return 0; +} +#endif + +#endif diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c new file mode 100644 index 000000000000..3e84a3f0c1d8 --- /dev/null +++ b/drivers/net/igb/e1000_mac.c @@ -0,0 +1,1505 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include <linux/if_ether.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/netdevice.h> + +#include "e1000_mac.h" + +#include "igb.h" + +static s32 igb_set_default_fc(struct e1000_hw *hw); +static s32 igb_set_fc_watermarks(struct e1000_hw *hw); +static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); + +/** + * e1000_remove_device - Free device specific structure + * @hw: pointer to the HW structure + * + * If a device specific structure was allocated, this function will + * free it. + **/ +void igb_remove_device(struct e1000_hw *hw) +{ + /* Freeing the dev_spec member of e1000_hw structure */ + kfree(hw->dev_spec); +} + +static void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct igb_adapter *adapter = hw->back; + + pci_read_config_word(adapter->pdev, reg, value); +} + +static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) +{ + struct igb_adapter *adapter = hw->back; + u16 cap_offset; + + cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); + if (!cap_offset) + return -E1000_ERR_CONFIG; + + pci_read_config_word(adapter->pdev, cap_offset + reg, value); + + return 0; +} + +/** + * e1000_get_bus_info_pcie - Get PCIe bus information + * @hw: pointer to the HW structure + * + * Determines and stores the system bus information for a particular + * network interface. The following bus information is determined and stored: + * bus speed, bus width, type (PCIe), and PCIe function. + **/ +s32 igb_get_bus_info_pcie(struct e1000_hw *hw) +{ + struct e1000_bus_info *bus = &hw->bus; + s32 ret_val; + u32 status; + u16 pcie_link_status, pci_header_type; + + bus->type = e1000_bus_type_pci_express; + bus->speed = e1000_bus_speed_2500; + + ret_val = igb_read_pcie_cap_reg(hw, + PCIE_LINK_STATUS, + &pcie_link_status); + if (ret_val) + bus->width = e1000_bus_width_unknown; + else + bus->width = (enum e1000_bus_width)((pcie_link_status & + PCIE_LINK_WIDTH_MASK) >> + PCIE_LINK_WIDTH_SHIFT); + + igb_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); + if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { + status = rd32(E1000_STATUS); + bus->func = (status & E1000_STATUS_FUNC_MASK) + >> E1000_STATUS_FUNC_SHIFT; + } else { + bus->func = 0; + } + + return 0; +} + +/** + * e1000_clear_vfta - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + **/ +void igb_clear_vfta(struct e1000_hw *hw) +{ + u32 offset; + + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + array_wr32(E1000_VFTA, offset, 0); + wrfl(); + } +} + +/** + * e1000_write_vfta - Write value to VLAN filter table + * @hw: pointer to the HW structure + * @offset: register offset in VLAN filter table + * @value: register value written to VLAN filter table + * + * Writes value at the given offset in the register array which stores + * the VLAN filter table. + **/ +void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) +{ + array_wr32(E1000_VFTA, offset, value); + wrfl(); +} + +/** + * e1000_init_rx_addrs - Initialize receive address's + * @hw: pointer to the HW structure + * @rar_count: receive address registers + * + * Setups the receive address registers by setting the base receive address + * register to the devices MAC address and clearing all the other receive + * address registers to 0. + **/ +void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) +{ + u32 i; + + /* Setup the receive address */ + hw_dbg(hw, "Programming MAC Address into RAR[0]\n"); + + hw->mac.ops.rar_set(hw, hw->mac.addr, 0); + + /* Zero out the other (rar_entry_count - 1) receive addresses */ + hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1); + for (i = 1; i < rar_count; i++) { + array_wr32(E1000_RA, (i << 1), 0); + wrfl(); + array_wr32(E1000_RA, ((i << 1) + 1), 0); + wrfl(); + } +} + +/** + * e1000_check_alt_mac_addr - Check for alternate MAC addr + * @hw: pointer to the HW structure + * + * Checks the nvm for an alternate MAC address. An alternate MAC address + * can be setup by pre-boot software and must be treated like a permanent + * address and must override the actual permanent MAC address. If an + * alternate MAC address is fopund it is saved in the hw struct and + * prgrammed into RAR0 and the cuntion returns success, otherwise the + * fucntion returns an error. + **/ +s32 igb_check_alt_mac_addr(struct e1000_hw *hw) +{ + u32 i; + s32 ret_val = 0; + u16 offset, nvm_alt_mac_addr_offset, nvm_data; + u8 alt_mac_addr[ETH_ALEN]; + + ret_val = hw->nvm.ops.read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, + &nvm_alt_mac_addr_offset); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + + if (nvm_alt_mac_addr_offset == 0xFFFF) { + ret_val = -(E1000_NOT_IMPLEMENTED); + goto out; + } + + if (hw->bus.func == E1000_FUNC_1) + nvm_alt_mac_addr_offset += ETH_ALEN/sizeof(u16); + + for (i = 0; i < ETH_ALEN; i += 2) { + offset = nvm_alt_mac_addr_offset + (i >> 1); + ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + + alt_mac_addr[i] = (u8)(nvm_data & 0xFF); + alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); + } + + /* if multicast bit is set, the alternate address will not be used */ + if (alt_mac_addr[0] & 0x01) { + ret_val = -(E1000_NOT_IMPLEMENTED); + goto out; + } + + for (i = 0; i < ETH_ALEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i] = alt_mac_addr[i]; + + hw->mac.ops.rar_set(hw, hw->mac.perm_addr, 0); + +out: + return ret_val; +} + +/** + * e1000_rar_set - Set receive address register + * @hw: pointer to the HW structure + * @addr: pointer to the receive address + * @index: receive address array register + * + * Sets the receive address array register at index to the address passed + * in by addr. + **/ +void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) +{ + u32 rar_low, rar_high; + + /* + * HW expects these in little endian so we reverse the byte order + * from network order (big endian) to little endian + */ + rar_low = ((u32) addr[0] | + ((u32) addr[1] << 8) | + ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); + + rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); + + if (!hw->mac.disable_av) + rar_high |= E1000_RAH_AV; + + array_wr32(E1000_RA, (index << 1), rar_low); + array_wr32(E1000_RA, ((index << 1) + 1), rar_high); +} + +/** + * e1000_mta_set - Set multicast filter table address + * @hw: pointer to the HW structure + * @hash_value: determines the MTA register and bit to set + * + * The multicast table address is a register array of 32-bit registers. + * The hash_value is used to determine what register the bit is in, the + * current value is read, the new bit is OR'd in and the new value is + * written back into the register. + **/ +static void igb_mta_set(struct e1000_hw *hw, u32 hash_value) +{ + u32 hash_bit, hash_reg, mta; + + /* + * The MTA is a register array of 32-bit registers. It is + * treated like an array of (32*mta_reg_count) bits. We want to + * set bit BitArray[hash_value]. So we figure out what register + * the bit is in, read it, OR in the new bit, then write + * back the new value. The (hw->mac.mta_reg_count - 1) serves as a + * mask to bits 31:5 of the hash value which gives us the + * register we're modifying. The hash bit within that register + * is determined by the lower 5 bits of the hash value. + */ + hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); + hash_bit = hash_value & 0x1F; + + mta = array_rd32(E1000_MTA, hash_reg); + + mta |= (1 << hash_bit); + + array_wr32(E1000_MTA, hash_reg, mta); + wrfl(); +} + +/** + * e1000_update_mc_addr_list - Update Multicast addresses + * @hw: pointer to the HW structure + * @mc_addr_list: array of multicast addresses to program + * @mc_addr_count: number of multicast addresses to program + * @rar_used_count: the first RAR register free to program + * @rar_count: total number of supported Receive Address Registers + * + * Updates the Receive Address Registers and Multicast Table Array. + * The caller must have a packed mc_addr_list of multicast addresses. + * The parameter rar_count will usually be hw->mac.rar_entry_count + * unless there are workarounds that change this. + **/ +void igb_update_mc_addr_list(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count) +{ + u32 hash_value; + u32 i; + + /* + * Load the first set of multicast addresses into the exact + * filters (RAR). If there are not enough to fill the RAR + * array, clear the filters. + */ + for (i = rar_used_count; i < rar_count; i++) { + if (mc_addr_count) { + hw->mac.ops.rar_set(hw, mc_addr_list, i); + mc_addr_count--; + mc_addr_list += ETH_ALEN; + } else { + array_wr32(E1000_RA, i << 1, 0); + wrfl(); + array_wr32(E1000_RA, (i << 1) + 1, 0); + wrfl(); + } + } + + /* Clear the old settings from the MTA */ + hw_dbg(hw, "Clearing MTA\n"); + for (i = 0; i < hw->mac.mta_reg_count; i++) { + array_wr32(E1000_MTA, i, 0); + wrfl(); + } + + /* Load any remaining multicast addresses into the hash table. */ + for (; mc_addr_count > 0; mc_addr_count--) { + hash_value = igb_hash_mc_addr(hw, mc_addr_list); + hw_dbg(hw, "Hash value = 0x%03X\n", hash_value); + igb_mta_set(hw, hash_value); + mc_addr_list += ETH_ALEN; + } +} + +/** + * e1000_hash_mc_addr - Generate a multicast hash value + * @hw: pointer to the HW structure + * @mc_addr: pointer to a multicast address + * + * Generates a multicast address hash value which is used to determine + * the multicast filter table array address and new table value. See + * igb_mta_set() + **/ +static u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) +{ + u32 hash_value, hash_mask; + u8 bit_shift = 0; + + /* Register count multiplied by bits per register */ + hash_mask = (hw->mac.mta_reg_count * 32) - 1; + + /* + * For a mc_filter_type of 0, bit_shift is the number of left-shifts + * where 0xFF would still fall within the hash mask. + */ + while (hash_mask >> bit_shift != 0xFF) + bit_shift++; + + /* + * The portion of the address that is used for the hash table + * is determined by the mc_filter_type setting. + * The algorithm is such that there is a total of 8 bits of shifting. + * The bit_shift for a mc_filter_type of 0 represents the number of + * left-shifts where the MSB of mc_addr[5] would still fall within + * the hash_mask. Case 0 does this exactly. Since there are a total + * of 8 bits of shifting, then mc_addr[4] will shift right the + * remaining number of bits. Thus 8 - bit_shift. The rest of the + * cases are a variation of this algorithm...essentially raising the + * number of bits to shift mc_addr[5] left, while still keeping the + * 8-bit shifting total. + * + * For example, given the following Destination MAC Address and an + * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), + * we can see that the bit_shift for case 0 is 4. These are the hash + * values resulting from each mc_filter_type... + * [0] [1] [2] [3] [4] [5] + * 01 AA 00 12 34 56 + * LSB MSB + * + * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 + * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 + * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 + * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 + */ + switch (hw->mac.mc_filter_type) { + default: + case 0: + break; + case 1: + bit_shift += 1; + break; + case 2: + bit_shift += 2; + break; + case 3: + bit_shift += 4; + break; + } + + hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | + (((u16) mc_addr[5]) << bit_shift))); + + return hash_value; +} + +/** + * e1000_clear_hw_cntrs_base - Clear base hardware counters + * @hw: pointer to the HW structure + * + * Clears the base hardware counters by reading the counter registers. + **/ +void igb_clear_hw_cntrs_base(struct e1000_hw *hw) +{ + u32 temp; + + temp = rd32(E1000_CRCERRS); + temp = rd32(E1000_SYMERRS); + temp = rd32(E1000_MPC); + temp = rd32(E1000_SCC); + temp = rd32(E1000_ECOL); + temp = rd32(E1000_MCC); + temp = rd32(E1000_LATECOL); + temp = rd32(E1000_COLC); + temp = rd32(E1000_DC); + temp = rd32(E1000_SEC); + temp = rd32(E1000_RLEC); + temp = rd32(E1000_XONRXC); + temp = rd32(E1000_XONTXC); + temp = rd32(E1000_XOFFRXC); + temp = rd32(E1000_XOFFTXC); + temp = rd32(E1000_FCRUC); + temp = rd32(E1000_GPRC); + temp = rd32(E1000_BPRC); + temp = rd32(E1000_MPRC); + temp = rd32(E1000_GPTC); + temp = rd32(E1000_GORCL); + temp = rd32(E1000_GORCH); + temp = rd32(E1000_GOTCL); + temp = rd32(E1000_GOTCH); + temp = rd32(E1000_RNBC); + temp = rd32(E1000_RUC); + temp = rd32(E1000_RFC); + temp = rd32(E1000_ROC); + temp = rd32(E1000_RJC); + temp = rd32(E1000_TORL); + temp = rd32(E1000_TORH); + temp = rd32(E1000_TOTL); + temp = rd32(E1000_TOTH); + temp = rd32(E1000_TPR); + temp = rd32(E1000_TPT); + temp = rd32(E1000_MPTC); + temp = rd32(E1000_BPTC); +} + +/** + * e1000_check_for_copper_link - Check for link (Copper) + * @hw: pointer to the HW structure + * + * Checks to see of the link status of the hardware has changed. If a + * change in link status has been detected, then we read the PHY registers + * to get the current speed/duplex if link exists. + **/ +s32 igb_check_for_copper_link(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + bool link; + + /* + * We only want to go out to the PHY registers to see if Auto-Neg + * has completed and/or if our link status has changed. The + * get_link_status flag is set upon receiving a Link Status + * Change or Rx Sequence Error interrupt. + */ + if (!mac->get_link_status) { + ret_val = 0; + goto out; + } + + /* + * First we want to see if the MII Status Register reports + * link. If so, then we want to get the current speed/duplex + * of the PHY. + */ + ret_val = igb_phy_has_link(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) + goto out; /* No link detected */ + + mac->get_link_status = false; + + /* + * Check if there was DownShift, must be checked + * immediately after link-up + */ + igb_check_downshift(hw); + + /* + * If we are forcing speed/duplex, then we simply return since + * we have already determined whether we have link or not. + */ + if (!mac->autoneg) { + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + /* + * Auto-Neg is enabled. Auto Speed Detection takes care + * of MAC speed/duplex configuration. So we only need to + * configure Collision Distance in the MAC. + */ + igb_config_collision_dist(hw); + + /* + * Configure Flow Control now that Auto-Neg has completed. + * First, we need to restore the desired flow control + * settings because we may have had to re-autoneg with a + * different link partner. + */ + ret_val = igb_config_fc_after_link_up(hw); + if (ret_val) + hw_dbg(hw, "Error configuring flow control\n"); + +out: + return ret_val; +} + +/** + * e1000_setup_link - Setup flow control and link settings + * @hw: pointer to the HW structure + * + * Determines which flow control settings to use, then configures flow + * control. Calls the appropriate media-specific link configuration + * function. Assuming the adapter has a valid link partner, a valid link + * should be established. Assumes the hardware has previously been reset + * and the transmitter and receiver are not enabled. + **/ +s32 igb_setup_link(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + /* + * In the case of the phy reset being blocked, we already have a link. + * We do not need to set it up again. + */ + if (igb_check_reset_block(hw)) + goto out; + + ret_val = igb_set_default_fc(hw); + if (ret_val) + goto out; + + /* + * We want to save off the original Flow Control configuration just + * in case we get disconnected and then reconnected into a different + * hub or switch with different Flow Control capabilities. + */ + hw->fc.original_type = hw->fc.type; + + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); + + /* Call the necessary media_type subroutine to configure the link. */ + ret_val = hw->mac.ops.setup_physical_interface(hw); + if (ret_val) + goto out; + + /* + * Initialize the flow control address, type, and PAUSE timer + * registers to their default values. This is done even if flow + * control is disabled, because it does not hurt anything to + * initialize these registers. + */ + hw_dbg(hw, + "Initializing the Flow Control address, type and timer regs\n"); + wr32(E1000_FCT, FLOW_CONTROL_TYPE); + wr32(E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); + wr32(E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); + + wr32(E1000_FCTTV, hw->fc.pause_time); + + ret_val = igb_set_fc_watermarks(hw); + +out: + return ret_val; +} + +/** + * e1000_config_collision_dist - Configure collision distance + * @hw: pointer to the HW structure + * + * Configures the collision distance to the default value and is used + * during link setup. Currently no func pointer exists and all + * implementations are handled in the generic version of this function. + **/ +void igb_config_collision_dist(struct e1000_hw *hw) +{ + u32 tctl; + + tctl = rd32(E1000_TCTL); + + tctl &= ~E1000_TCTL_COLD; + tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; + + wr32(E1000_TCTL, tctl); + wrfl(); +} + +/** + * e1000_set_fc_watermarks - Set flow control high/low watermarks + * @hw: pointer to the HW structure + * + * Sets the flow control high/low threshold (watermark) registers. If + * flow control XON frame transmission is enabled, then set XON frame + * tansmission as well. + **/ +static s32 igb_set_fc_watermarks(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u32 fcrtl = 0, fcrth = 0; + + /* + * Set the flow control receive threshold registers. Normally, + * these registers will be set to a default threshold that may be + * adjusted later by the driver's runtime code. However, if the + * ability to transmit pause frames is not enabled, then these + * registers will be set to 0. + */ + if (hw->fc.type & e1000_fc_tx_pause) { + /* + * We need to set up the Receive Threshold high and low water + * marks as well as (optionally) enabling the transmission of + * XON frames. + */ + fcrtl = hw->fc.low_water; + if (hw->fc.send_xon) + fcrtl |= E1000_FCRTL_XONE; + + fcrth = hw->fc.high_water; + } + wr32(E1000_FCRTL, fcrtl); + wr32(E1000_FCRTH, fcrth); + + return ret_val; +} + +/** + * e1000_set_default_fc - Set flow control default values + * @hw: pointer to the HW structure + * + * Read the EEPROM for the default values for flow control and store the + * values. + **/ +static s32 igb_set_default_fc(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 nvm_data; + + /* + * Read and store word 0x0F of the EEPROM. This word contains bits + * that determine the hardware's default PAUSE (flow control) mode, + * a bit that determines whether the HW defaults to enabling or + * disabling auto-negotiation, and the direction of the + * SW defined pins. If there is no SW over-ride of the flow + * control setting, then the variable hw->fc will + * be initialized based on a value in the EEPROM. + */ + ret_val = hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, + &nvm_data); + + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + + if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) + hw->fc.type = e1000_fc_none; + else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == + NVM_WORD0F_ASM_DIR) + hw->fc.type = e1000_fc_tx_pause; + else + hw->fc.type = e1000_fc_full; + +out: + return ret_val; +} + +/** + * e1000_force_mac_fc - Force the MAC's flow control settings + * @hw: pointer to the HW structure + * + * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the + * device control register to reflect the adapter settings. TFCE and RFCE + * need to be explicitly set by software when a copper PHY is used because + * autonegotiation is managed by the PHY rather than the MAC. Software must + * also configure these bits when link is forced on a fiber connection. + **/ +s32 igb_force_mac_fc(struct e1000_hw *hw) +{ + u32 ctrl; + s32 ret_val = 0; + + ctrl = rd32(E1000_CTRL); + + /* + * Because we didn't get link via the internal auto-negotiation + * mechanism (we either forced link or we got link via PHY + * auto-neg), we have to manually enable/disable transmit an + * receive flow control. + * + * The "Case" statement below enables/disable flow control + * according to the "hw->fc.type" parameter. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause + * frames but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * frames but we do not receive pause frames). + * 3: Both Rx and TX flow control (symmetric) is enabled. + * other: No other values should be possible at this point. + */ + hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type); + + switch (hw->fc.type) { + case e1000_fc_none: + ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); + break; + case e1000_fc_rx_pause: + ctrl &= (~E1000_CTRL_TFCE); + ctrl |= E1000_CTRL_RFCE; + break; + case e1000_fc_tx_pause: + ctrl &= (~E1000_CTRL_RFCE); + ctrl |= E1000_CTRL_TFCE; + break; + case e1000_fc_full: + ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + wr32(E1000_CTRL, ctrl); + +out: + return ret_val; +} + +/** + * e1000_config_fc_after_link_up - Configures flow control after link + * @hw: pointer to the HW structure + * + * Checks the status of auto-negotiation after link up to ensure that the + * speed and duplex were not forced. If the link needed to be forced, then + * flow control needs to be forced also. If auto-negotiation is enabled + * and did not fail, then we configure flow control based on our link + * partner. + **/ +s32 igb_config_fc_after_link_up(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val = 0; + u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; + u16 speed, duplex; + + /* + * Check for the case where we have fiber media and auto-neg failed + * so we had to force link. In this case, we need to force the + * configuration of the MAC to match the "fc" parameter. + */ + if (mac->autoneg_failed) { + if (hw->phy.media_type == e1000_media_type_fiber || + hw->phy.media_type == e1000_media_type_internal_serdes) + ret_val = igb_force_mac_fc(hw); + } else { + if (hw->phy.media_type == e1000_media_type_copper) + ret_val = igb_force_mac_fc(hw); + } + + if (ret_val) { + hw_dbg(hw, "Error forcing flow control settings\n"); + goto out; + } + + /* + * Check for the case where we have copper media and auto-neg is + * enabled. In this case, we need to check and see if Auto-Neg + * has completed, and if so, how the PHY and link partner has + * flow control configured. + */ + if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { + /* + * Read the MII Status Register and check to see if AutoNeg + * has completed. We read this twice because this reg has + * some "sticky" (latched) bits. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, + &mii_status_reg); + if (ret_val) + goto out; + + if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { + hw_dbg(hw, "Copper PHY and Auto Neg " + "has not completed.\n"); + goto out; + } + + /* + * The AutoNeg process has completed, so we now need to + * read both the Auto Negotiation Advertisement + * Register (Address 4) and the Auto_Negotiation Base + * Page Ability Register (Address 5) to determine how + * flow control was negotiated. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_AUTONEG_ADV, + &mii_nway_adv_reg); + if (ret_val) + goto out; + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_LP_ABILITY, + &mii_nway_lp_ability_reg); + if (ret_val) + goto out; + + /* + * Two bits in the Auto Negotiation Advertisement Register + * (Address 4) and two bits in the Auto Negotiation Base + * Page Ability Register (Address 5) determine flow control + * for both the PHY and the link partner. The following + * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, + * 1999, describes these PAUSE resolution bits and how flow + * control is determined based upon these settings. + * NOTE: DC = Don't Care + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution + *-------|---------|-------|---------|-------------------- + * 0 | 0 | DC | DC | e1000_fc_none + * 0 | 1 | 0 | DC | e1000_fc_none + * 0 | 1 | 1 | 0 | e1000_fc_none + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + * 1 | 0 | 0 | DC | e1000_fc_none + * 1 | DC | 1 | DC | e1000_fc_full + * 1 | 1 | 0 | 0 | e1000_fc_none + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + * + * Are both PAUSE bits set to 1? If so, this implies + * Symmetric Flow Control is enabled at both ends. The + * ASM_DIR bits are irrelevant per the spec. + * + * For Symmetric Flow Control: + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | DC | 1 | DC | E1000_fc_full + * + */ + if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { + /* + * Now we need to check if the user selected RX ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.original_type == e1000_fc_full) { + hw->fc.type = e1000_fc_full; + hw_dbg(hw, "Flow Control = FULL.\r\n"); + } else { + hw->fc.type = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = " + "RX PAUSE frames only.\r\n"); + } + } + /* + * For receiving PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 0 | 1 | 1 | 1 | e1000_fc_tx_pause + */ + else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.type = e1000_fc_tx_pause; + hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n"); + } + /* + * For transmitting PAUSE frames ONLY. + * + * LOCAL DEVICE | LINK PARTNER + * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result + *-------|---------|-------|---------|-------------------- + * 1 | 1 | 0 | 1 | e1000_fc_rx_pause + */ + else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && + (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && + !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && + (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { + hw->fc.type = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + } + /* + * Per the IEEE spec, at this point flow control should be + * disabled. However, we want to consider that we could + * be connected to a legacy switch that doesn't advertise + * desired flow control, but can be forced on the link + * partner. So if we advertised no flow control, that is + * what we will resolve to. If we advertised some kind of + * receive capability (Rx Pause Only or Full Flow Control) + * and the link partner advertised none, we will configure + * ourselves to enable Rx Flow Control only. We can do + * this safely for two reasons: If the link partner really + * didn't want flow control enabled, and we enable Rx, no + * harm done since we won't be receiving any PAUSE frames + * anyway. If the intent on the link partner was to have + * flow control enabled, then by us enabling RX only, we + * can at least receive pause frames and process them. + * This is a good idea because in most cases, since we are + * predominantly a server NIC, more times than not we will + * be asked to delay transmission of packets than asking + * our link partner to pause transmission of frames. + */ + else if ((hw->fc.original_type == e1000_fc_none || + hw->fc.original_type == e1000_fc_tx_pause) || + hw->fc.strict_ieee) { + hw->fc.type = e1000_fc_none; + hw_dbg(hw, "Flow Control = NONE.\r\n"); + } else { + hw->fc.type = e1000_fc_rx_pause; + hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n"); + } + + /* + * Now we need to do one last check... If we auto- + * negotiated to HALF DUPLEX, flow control should not be + * enabled per IEEE 802.3 spec. + */ + ret_val = hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex); + if (ret_val) { + hw_dbg(hw, "Error getting link speed and duplex\n"); + goto out; + } + + if (duplex == HALF_DUPLEX) + hw->fc.type = e1000_fc_none; + + /* + * Now we call a subroutine to actually force the MAC + * controller to use the correct flow control settings. + */ + ret_val = igb_force_mac_fc(hw); + if (ret_val) { + hw_dbg(hw, "Error forcing flow control settings\n"); + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_get_speed_and_duplex_copper - Retreive current speed/duplex + * @hw: pointer to the HW structure + * @speed: stores the current speed + * @duplex: stores the current duplex + * + * Read the status register for the current speed/duplex and store the current + * speed and duplex for copper connections. + **/ +s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, + u16 *duplex) +{ + u32 status; + + status = rd32(E1000_STATUS); + if (status & E1000_STATUS_SPEED_1000) { + *speed = SPEED_1000; + hw_dbg(hw, "1000 Mbs, "); + } else if (status & E1000_STATUS_SPEED_100) { + *speed = SPEED_100; + hw_dbg(hw, "100 Mbs, "); + } else { + *speed = SPEED_10; + hw_dbg(hw, "10 Mbs, "); + } + + if (status & E1000_STATUS_FD) { + *duplex = FULL_DUPLEX; + hw_dbg(hw, "Full Duplex\n"); + } else { + *duplex = HALF_DUPLEX; + hw_dbg(hw, "Half Duplex\n"); + } + + return 0; +} + +/** + * e1000_get_hw_semaphore - Acquire hardware semaphore + * @hw: pointer to the HW structure + * + * Acquire the HW semaphore to access the PHY or NVM + **/ +s32 igb_get_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + s32 ret_val = 0; + s32 timeout = hw->nvm.word_size + 1; + s32 i = 0; + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = rd32(E1000_SWSM); + if (!(swsm & E1000_SWSM_SMBI)) + break; + + udelay(50); + i++; + } + + if (i == timeout) { + hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = rd32(E1000_SWSM); + wr32(E1000_SWSM, swsm | E1000_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (rd32(E1000_SWSM) & E1000_SWSM_SWESMBI) + break; + + udelay(50); + } + + if (i == timeout) { + /* Release semaphores */ + igb_put_hw_semaphore(hw); + hw_dbg(hw, "Driver can't access the NVM\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_put_hw_semaphore - Release hardware semaphore + * @hw: pointer to the HW structure + * + * Release hardware semaphore used to access the PHY or NVM + **/ +void igb_put_hw_semaphore(struct e1000_hw *hw) +{ + u32 swsm; + + swsm = rd32(E1000_SWSM); + + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + + wr32(E1000_SWSM, swsm); +} + +/** + * e1000_get_auto_rd_done - Check for auto read completion + * @hw: pointer to the HW structure + * + * Check EEPROM for Auto Read done bit. + **/ +s32 igb_get_auto_rd_done(struct e1000_hw *hw) +{ + s32 i = 0; + s32 ret_val = 0; + + + while (i < AUTO_READ_DONE_TIMEOUT) { + if (rd32(E1000_EECD) & E1000_EECD_AUTO_RD) + break; + msleep(1); + i++; + } + + if (i == AUTO_READ_DONE_TIMEOUT) { + hw_dbg(hw, "Auto read by HW from NVM has not completed.\n"); + ret_val = -E1000_ERR_RESET; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_valid_led_default - Verify a valid default LED config + * @hw: pointer to the HW structure + * @data: pointer to the NVM (EEPROM) + * + * Read the EEPROM for the current default LED configuration. If the + * LED configuration is not valid, set to a valid LED configuration. + **/ +static s32 igb_valid_led_default(struct e1000_hw *hw, u16 *data) +{ + s32 ret_val; + + ret_val = hw->nvm.ops.read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + + if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) + *data = ID_LED_DEFAULT; + +out: + return ret_val; +} + +/** + * e1000_id_led_init - + * @hw: pointer to the HW structure + * + **/ +s32 igb_id_led_init(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + s32 ret_val; + const u32 ledctl_mask = 0x000000FF; + const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; + const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; + u16 data, i, temp; + const u16 led_mask = 0x0F; + + ret_val = igb_valid_led_default(hw, &data); + if (ret_val) + goto out; + + mac->ledctl_default = rd32(E1000_LEDCTL); + mac->ledctl_mode1 = mac->ledctl_default; + mac->ledctl_mode2 = mac->ledctl_default; + + for (i = 0; i < 4; i++) { + temp = (data >> (i << 2)) & led_mask; + switch (temp) { + case ID_LED_ON1_DEF2: + case ID_LED_ON1_ON2: + case ID_LED_ON1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_on << (i << 3); + break; + case ID_LED_OFF1_DEF2: + case ID_LED_OFF1_ON2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode1 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + switch (temp) { + case ID_LED_DEF1_ON2: + case ID_LED_ON1_ON2: + case ID_LED_OFF1_ON2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_on << (i << 3); + break; + case ID_LED_DEF1_OFF2: + case ID_LED_ON1_OFF2: + case ID_LED_OFF1_OFF2: + mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); + mac->ledctl_mode2 |= ledctl_off << (i << 3); + break; + default: + /* Do nothing */ + break; + } + } + +out: + return ret_val; +} + +/** + * e1000_cleanup_led - Set LED config to default operation + * @hw: pointer to the HW structure + * + * Remove the current LED configuration and set the LED configuration + * to the default value, saved from the EEPROM. + **/ +s32 igb_cleanup_led(struct e1000_hw *hw) +{ + wr32(E1000_LEDCTL, hw->mac.ledctl_default); + return 0; +} + +/** + * e1000_blink_led - Blink LED + * @hw: pointer to the HW structure + * + * Blink the led's which are set to be on. + **/ +s32 igb_blink_led(struct e1000_hw *hw) +{ + u32 ledctl_blink = 0; + u32 i; + + if (hw->phy.media_type == e1000_media_type_fiber) { + /* always blink LED0 for PCI-E fiber */ + ledctl_blink = E1000_LEDCTL_LED0_BLINK | + (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); + } else { + /* + * set the blink bit for each LED that's "on" (0x0E) + * in ledctl_mode2 + */ + ledctl_blink = hw->mac.ledctl_mode2; + for (i = 0; i < 4; i++) + if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == + E1000_LEDCTL_MODE_LED_ON) + ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << + (i * 8)); + } + + wr32(E1000_LEDCTL, ledctl_blink); + + return 0; +} + +/** + * e1000_led_off - Turn LED off + * @hw: pointer to the HW structure + * + * Turn LED off. + **/ +s32 igb_led_off(struct e1000_hw *hw) +{ + u32 ctrl; + + switch (hw->phy.media_type) { + case e1000_media_type_fiber: + ctrl = rd32(E1000_CTRL); + ctrl |= E1000_CTRL_SWDPIN0; + ctrl |= E1000_CTRL_SWDPIO0; + wr32(E1000_CTRL, ctrl); + break; + case e1000_media_type_copper: + wr32(E1000_LEDCTL, hw->mac.ledctl_mode1); + break; + default: + break; + } + + return 0; +} + +/** + * e1000_disable_pcie_master - Disables PCI-express master access + * @hw: pointer to the HW structure + * + * Returns 0 (0) if successful, else returns -10 + * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued + * the master requests to be disabled. + * + * Disables PCI-Express master access and verifies there are no pending + * requests. + **/ +s32 igb_disable_pcie_master(struct e1000_hw *hw) +{ + u32 ctrl; + s32 timeout = MASTER_DISABLE_TIMEOUT; + s32 ret_val = 0; + + if (hw->bus.type != e1000_bus_type_pci_express) + goto out; + + ctrl = rd32(E1000_CTRL); + ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; + wr32(E1000_CTRL, ctrl); + + while (timeout) { + if (!(rd32(E1000_STATUS) & + E1000_STATUS_GIO_MASTER_ENABLE)) + break; + udelay(100); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "Master requests are pending.\n"); + ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_reset_adaptive - Reset Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Reset the Adaptive Interframe Spacing throttle to default values. + **/ +void igb_reset_adaptive(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + if (!mac->adaptive_ifs) { + hw_dbg(hw, "Not in Adaptive IFS mode!\n"); + goto out; + } + + if (!mac->ifs_params_forced) { + mac->current_ifs_val = 0; + mac->ifs_min_val = IFS_MIN; + mac->ifs_max_val = IFS_MAX; + mac->ifs_step_size = IFS_STEP; + mac->ifs_ratio = IFS_RATIO; + } + + mac->in_ifs_mode = false; + wr32(E1000_AIT, 0); +out: + return; +} + +/** + * e1000_update_adaptive - Update Adaptive Interframe Spacing + * @hw: pointer to the HW structure + * + * Update the Adaptive Interframe Spacing Throttle value based on the + * time between transmitted packets and time between collisions. + **/ +void igb_update_adaptive(struct e1000_hw *hw) +{ + struct e1000_mac_info *mac = &hw->mac; + + if (!mac->adaptive_ifs) { + hw_dbg(hw, "Not in Adaptive IFS mode!\n"); + goto out; + } + + if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { + if (mac->tx_packet_delta > MIN_NUM_XMITS) { + mac->in_ifs_mode = true; + if (mac->current_ifs_val < mac->ifs_max_val) { + if (!mac->current_ifs_val) + mac->current_ifs_val = mac->ifs_min_val; + else + mac->current_ifs_val += + mac->ifs_step_size; + wr32(E1000_AIT, + mac->current_ifs_val); + } + } + } else { + if (mac->in_ifs_mode && + (mac->tx_packet_delta <= MIN_NUM_XMITS)) { + mac->current_ifs_val = 0; + mac->in_ifs_mode = false; + wr32(E1000_AIT, 0); + } + } +out: + return; +} + +/** + * e1000_validate_mdi_setting - Verify MDI/MDIx settings + * @hw: pointer to the HW structure + * + * Verify that when not using auto-negotitation that MDI/MDIx is correctly + * set, which is forced to MDI mode only. + **/ +s32 igb_validate_mdi_setting(struct e1000_hw *hw) +{ + s32 ret_val = 0; + + if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { + hw_dbg(hw, "Invalid MDI setting detected\n"); + hw->phy.mdix = 1; + ret_val = -E1000_ERR_CONFIG; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_write_8bit_ctrl_reg - Write a 8bit CTRL register + * @hw: pointer to the HW structure + * @reg: 32bit register offset such as E1000_SCTL + * @offset: register offset to write to + * @data: data to write at register offset + * + * Writes an address/data control type register. There are several of these + * and they all have the format address << 8 | data and bit 31 is polled for + * completion. + **/ +s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, + u32 offset, u8 data) +{ + u32 i, regvalue = 0; + s32 ret_val = 0; + + /* Set up the address and data */ + regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT); + wr32(reg, regvalue); + + /* Poll the ready bit to see if the MDI read completed */ + for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { + udelay(5); + regvalue = rd32(reg); + if (regvalue & E1000_GEN_CTL_READY) + break; + } + if (!(regvalue & E1000_GEN_CTL_READY)) { + hw_dbg(hw, "Reg %08x did not indicate ready\n", reg); + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_enable_mng_pass_thru - Enable processing of ARP's + * @hw: pointer to the HW structure + * + * Verifies the hardware needs to allow ARPs to be processed by the host. + **/ +bool igb_enable_mng_pass_thru(struct e1000_hw *hw) +{ + u32 manc; + u32 fwsm, factps; + bool ret_val = false; + + if (!hw->mac.asf_firmware_present) + goto out; + + manc = rd32(E1000_MANC); + + if (!(manc & E1000_MANC_RCV_TCO_EN) || + !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) + goto out; + + if (hw->mac.arc_subsystem_valid) { + fwsm = rd32(E1000_FWSM); + factps = rd32(E1000_FACTPS); + + if (!(factps & E1000_FACTPS_MNGCG) && + ((fwsm & E1000_FWSM_MODE_MASK) == + (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { + ret_val = true; + goto out; + } + } else { + if ((manc & E1000_MANC_SMBUS_EN) && + !(manc & E1000_MANC_ASF_EN)) { + ret_val = true; + goto out; + } + } + +out: + return ret_val; +} diff --git a/drivers/net/igb/e1000_mac.h b/drivers/net/igb/e1000_mac.h new file mode 100644 index 000000000000..326b6592307b --- /dev/null +++ b/drivers/net/igb/e1000_mac.h @@ -0,0 +1,98 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_MAC_H_ +#define _E1000_MAC_H_ + +#include "e1000_hw.h" + +#include "e1000_phy.h" +#include "e1000_nvm.h" +#include "e1000_defines.h" + +/* + * Functions that should not be called directly from drivers but can be used + * by other files in this 'shared code' + */ +s32 igb_blink_led(struct e1000_hw *hw); +s32 igb_check_for_copper_link(struct e1000_hw *hw); +s32 igb_cleanup_led(struct e1000_hw *hw); +s32 igb_config_fc_after_link_up(struct e1000_hw *hw); +s32 igb_disable_pcie_master(struct e1000_hw *hw); +s32 igb_force_mac_fc(struct e1000_hw *hw); +s32 igb_get_auto_rd_done(struct e1000_hw *hw); +s32 igb_get_bus_info_pcie(struct e1000_hw *hw); +s32 igb_get_hw_semaphore(struct e1000_hw *hw); +s32 igb_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, + u16 *duplex); +s32 igb_id_led_init(struct e1000_hw *hw); +s32 igb_led_off(struct e1000_hw *hw); +void igb_update_mc_addr_list(struct e1000_hw *hw, + u8 *mc_addr_list, u32 mc_addr_count, + u32 rar_used_count, u32 rar_count); +s32 igb_setup_link(struct e1000_hw *hw); +s32 igb_validate_mdi_setting(struct e1000_hw *hw); +s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, + u32 offset, u8 data); + +void igb_clear_hw_cntrs_base(struct e1000_hw *hw); +void igb_clear_vfta(struct e1000_hw *hw); +void igb_config_collision_dist(struct e1000_hw *hw); +void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); +void igb_put_hw_semaphore(struct e1000_hw *hw); +void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); +s32 igb_check_alt_mac_addr(struct e1000_hw *hw); +void igb_remove_device(struct e1000_hw *hw); +void igb_reset_adaptive(struct e1000_hw *hw); +void igb_update_adaptive(struct e1000_hw *hw); +void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); + +bool igb_enable_mng_pass_thru(struct e1000_hw *hw); + +enum e1000_mng_mode { + e1000_mng_mode_none = 0, + e1000_mng_mode_asf, + e1000_mng_mode_pt, + e1000_mng_mode_ipmi, + e1000_mng_mode_host_if_only +}; + +#define E1000_FACTPS_MNGCG 0x20000000 + +#define E1000_FWSM_MODE_MASK 0xE +#define E1000_FWSM_MODE_SHIFT 1 + +#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 +#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 + +#define E1000_HICR_EN 0x01 /* Enable bit - RO */ +/* Driver sets this bit when done to put command in RAM */ +#define E1000_HICR_C 0x02 + +extern void e1000_init_function_pointers_82575(struct e1000_hw *hw); + +#endif diff --git a/drivers/net/igb/e1000_nvm.c b/drivers/net/igb/e1000_nvm.c new file mode 100644 index 000000000000..2897106fee92 --- /dev/null +++ b/drivers/net/igb/e1000_nvm.c @@ -0,0 +1,605 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include <linux/if_ether.h> +#include <linux/delay.h> + +#include "e1000_mac.h" +#include "e1000_nvm.h" + +/** + * e1000_raise_eec_clk - Raise EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Enable/Raise the EEPROM clock bit. + **/ +static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd | E1000_EECD_SK; + wr32(E1000_EECD, *eecd); + wrfl(); + udelay(hw->nvm.delay_usec); +} + +/** + * e1000_lower_eec_clk - Lower EEPROM clock + * @hw: pointer to the HW structure + * @eecd: pointer to the EEPROM + * + * Clear/Lower the EEPROM clock bit. + **/ +static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) +{ + *eecd = *eecd & ~E1000_EECD_SK; + wr32(E1000_EECD, *eecd); + wrfl(); + udelay(hw->nvm.delay_usec); +} + +/** + * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM + * @hw: pointer to the HW structure + * @data: data to send to the EEPROM + * @count: number of bits to shift out + * + * We need to shift 'count' bits out to the EEPROM. So, the value in the + * "data" parameter will be shifted out to the EEPROM one bit at a time. + * In order to do this, "data" must be broken down into bits. + **/ +static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = rd32(E1000_EECD); + u32 mask; + + mask = 0x01 << (count - 1); + if (nvm->type == e1000_nvm_eeprom_microwire) + eecd &= ~E1000_EECD_DO; + else if (nvm->type == e1000_nvm_eeprom_spi) + eecd |= E1000_EECD_DO; + + do { + eecd &= ~E1000_EECD_DI; + + if (data & mask) + eecd |= E1000_EECD_DI; + + wr32(E1000_EECD, eecd); + wrfl(); + + udelay(nvm->delay_usec); + + igb_raise_eec_clk(hw, &eecd); + igb_lower_eec_clk(hw, &eecd); + + mask >>= 1; + } while (mask); + + eecd &= ~E1000_EECD_DI; + wr32(E1000_EECD, eecd); +} + +/** + * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM + * @hw: pointer to the HW structure + * @count: number of bits to shift in + * + * In order to read a register from the EEPROM, we need to shift 'count' bits + * in from the EEPROM. Bits are "shifted in" by raising the clock input to + * the EEPROM (setting the SK bit), and then reading the value of the data out + * "DO" bit. During this "shifting in" process the data in "DI" bit should + * always be clear. + **/ +static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count) +{ + u32 eecd; + u32 i; + u16 data; + + eecd = rd32(E1000_EECD); + + eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); + data = 0; + + for (i = 0; i < count; i++) { + data <<= 1; + igb_raise_eec_clk(hw, &eecd); + + eecd = rd32(E1000_EECD); + + eecd &= ~E1000_EECD_DI; + if (eecd & E1000_EECD_DO) + data |= 1; + + igb_lower_eec_clk(hw, &eecd); + } + + return data; +} + +/** + * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion + * @hw: pointer to the HW structure + * @ee_reg: EEPROM flag for polling + * + * Polls the EEPROM status bit for either read or write completion based + * upon the value of 'ee_reg'. + **/ +static s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) +{ + u32 attempts = 100000; + u32 i, reg = 0; + s32 ret_val = -E1000_ERR_NVM; + + for (i = 0; i < attempts; i++) { + if (ee_reg == E1000_NVM_POLL_READ) + reg = rd32(E1000_EERD); + else + reg = rd32(E1000_EEWR); + + if (reg & E1000_NVM_RW_REG_DONE) { + ret_val = 0; + break; + } + + udelay(5); + } + + return ret_val; +} + +/** + * e1000_acquire_nvm - Generic request for access to EEPROM + * @hw: pointer to the HW structure + * + * Set the EEPROM access request bit and wait for EEPROM access grant bit. + * Return successful if access grant bit set, else clear the request for + * EEPROM access and return -E1000_ERR_NVM (-1). + **/ +s32 igb_acquire_nvm(struct e1000_hw *hw) +{ + u32 eecd = rd32(E1000_EECD); + s32 timeout = E1000_NVM_GRANT_ATTEMPTS; + s32 ret_val = 0; + + + wr32(E1000_EECD, eecd | E1000_EECD_REQ); + eecd = rd32(E1000_EECD); + + while (timeout) { + if (eecd & E1000_EECD_GNT) + break; + udelay(5); + eecd = rd32(E1000_EECD); + timeout--; + } + + if (!timeout) { + eecd &= ~E1000_EECD_REQ; + wr32(E1000_EECD, eecd); + hw_dbg(hw, "Could not acquire NVM grant\n"); + ret_val = -E1000_ERR_NVM; + } + + return ret_val; +} + +/** + * e1000_standby_nvm - Return EEPROM to standby state + * @hw: pointer to the HW structure + * + * Return the EEPROM to a standby state. + **/ +static void igb_standby_nvm(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = rd32(E1000_EECD); + + if (nvm->type == e1000_nvm_eeprom_microwire) { + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + wr32(E1000_EECD, eecd); + wrfl(); + udelay(nvm->delay_usec); + + igb_raise_eec_clk(hw, &eecd); + + /* Select EEPROM */ + eecd |= E1000_EECD_CS; + wr32(E1000_EECD, eecd); + wrfl(); + udelay(nvm->delay_usec); + + igb_lower_eec_clk(hw, &eecd); + } else if (nvm->type == e1000_nvm_eeprom_spi) { + /* Toggle CS to flush commands */ + eecd |= E1000_EECD_CS; + wr32(E1000_EECD, eecd); + wrfl(); + udelay(nvm->delay_usec); + eecd &= ~E1000_EECD_CS; + wr32(E1000_EECD, eecd); + wrfl(); + udelay(nvm->delay_usec); + } +} + +/** + * e1000_stop_nvm - Terminate EEPROM command + * @hw: pointer to the HW structure + * + * Terminates the current command by inverting the EEPROM's chip select pin. + **/ +static void e1000_stop_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + eecd = rd32(E1000_EECD); + if (hw->nvm.type == e1000_nvm_eeprom_spi) { + /* Pull CS high */ + eecd |= E1000_EECD_CS; + igb_lower_eec_clk(hw, &eecd); + } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) { + /* CS on Microcwire is active-high */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); + wr32(E1000_EECD, eecd); + igb_raise_eec_clk(hw, &eecd); + igb_lower_eec_clk(hw, &eecd); + } +} + +/** + * e1000_release_nvm - Release exclusive access to EEPROM + * @hw: pointer to the HW structure + * + * Stop any current commands to the EEPROM and clear the EEPROM request bit. + **/ +void igb_release_nvm(struct e1000_hw *hw) +{ + u32 eecd; + + e1000_stop_nvm(hw); + + eecd = rd32(E1000_EECD); + eecd &= ~E1000_EECD_REQ; + wr32(E1000_EECD, eecd); +} + +/** + * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write + * @hw: pointer to the HW structure + * + * Setups the EEPROM for reading and writing. + **/ +static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 eecd = rd32(E1000_EECD); + s32 ret_val = 0; + u16 timeout = 0; + u8 spi_stat_reg; + + + if (nvm->type == e1000_nvm_eeprom_microwire) { + /* Clear SK and DI */ + eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); + wr32(E1000_EECD, eecd); + /* Set CS */ + eecd |= E1000_EECD_CS; + wr32(E1000_EECD, eecd); + } else if (nvm->type == e1000_nvm_eeprom_spi) { + /* Clear SK and CS */ + eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); + wr32(E1000_EECD, eecd); + udelay(1); + timeout = NVM_MAX_RETRY_SPI; + + /* + * Read "Status Register" repeatedly until the LSB is cleared. + * The EEPROM will signal that the command has been completed + * by clearing bit 0 of the internal status register. If it's + * not cleared within 'timeout', then error out. + */ + while (timeout) { + igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, + hw->nvm.opcode_bits); + spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8); + if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) + break; + + udelay(5); + igb_standby_nvm(hw); + timeout--; + } + + if (!timeout) { + hw_dbg(hw, "SPI NVM Status error\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + } + +out: + return ret_val; +} + +/** + * e1000_read_nvm_eerd - Reads EEPROM using EERD register + * @hw: pointer to the HW structure + * @offset: offset of word in the EEPROM to read + * @words: number of words to read + * @data: word read from the EEPROM + * + * Reads a 16 bit word from the EEPROM using the EERD register. + **/ +s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + u32 i, eerd = 0; + s32 ret_val = 0; + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + for (i = 0; i < words; i++) { + eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + + E1000_NVM_RW_REG_START; + + wr32(E1000_EERD, eerd); + ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); + if (ret_val) + break; + + data[i] = (rd32(E1000_EERD) >> + E1000_NVM_RW_REG_DATA); + } + +out: + return ret_val; +} + +/** + * e1000_write_nvm_spi - Write to EEPROM using SPI + * @hw: pointer to the HW structure + * @offset: offset within the EEPROM to be written to + * @words: number of words to write + * @data: 16 bit word(s) to be written to the EEPROM + * + * Writes data to EEPROM at offset using SPI interface. + * + * If e1000_update_nvm_checksum is not called after this function , the + * EEPROM will most likley contain an invalid checksum. + **/ +s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) +{ + struct e1000_nvm_info *nvm = &hw->nvm; + s32 ret_val; + u16 widx = 0; + + /* + * A check for invalid values: offset too large, too many words, + * and not enough words. + */ + if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || + (words == 0)) { + hw_dbg(hw, "nvm parameter(s) out of bounds\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + + ret_val = hw->nvm.ops.acquire_nvm(hw); + if (ret_val) + goto out; + + msleep(10); + + while (widx < words) { + u8 write_opcode = NVM_WRITE_OPCODE_SPI; + + ret_val = igb_ready_nvm_eeprom(hw); + if (ret_val) + goto release; + + igb_standby_nvm(hw); + + /* Send the WRITE ENABLE command (8 bit opcode) */ + igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, + nvm->opcode_bits); + + igb_standby_nvm(hw); + + /* + * Some SPI eeproms use the 8th address bit embedded in the + * opcode + */ + if ((nvm->address_bits == 8) && (offset >= 128)) + write_opcode |= NVM_A8_OPCODE_SPI; + + /* Send the Write command (8-bit opcode + addr) */ + igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); + igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), + nvm->address_bits); + + /* Loop to allow for up to whole page write of eeprom */ + while (widx < words) { + u16 word_out = data[widx]; + word_out = (word_out >> 8) | (word_out << 8); + igb_shift_out_eec_bits(hw, word_out, 16); + widx++; + + if ((((offset + widx) * 2) % nvm->page_size) == 0) { + igb_standby_nvm(hw); + break; + } + } + } + + msleep(10); +release: + hw->nvm.ops.release_nvm(hw); + +out: + return ret_val; +} + +/** + * e1000_read_part_num - Read device part number + * @hw: pointer to the HW structure + * @part_num: pointer to device part number + * + * Reads the product board assembly (PBA) number from the EEPROM and stores + * the value in part_num. + **/ +s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num) +{ + s32 ret_val; + u16 nvm_data; + + ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + *part_num = (u32)(nvm_data << 16); + + ret_val = hw->nvm.ops.read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + *part_num |= nvm_data; + +out: + return ret_val; +} + +/** + * e1000_read_mac_addr - Read device MAC address + * @hw: pointer to the HW structure + * + * Reads the device MAC address from the EEPROM and stores the value. + * Since devices with two ports use the same EEPROM, we increment the + * last bit in the MAC address for the second port. + **/ +s32 igb_read_mac_addr(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 offset, nvm_data, i; + + for (i = 0; i < ETH_ALEN; i += 2) { + offset = i >> 1; + ret_val = hw->nvm.ops.read_nvm(hw, offset, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); + hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); + } + + /* Flip last bit of mac address if we're on second port */ + if (hw->bus.func == E1000_FUNC_1) + hw->mac.perm_addr[5] ^= 1; + + for (i = 0; i < ETH_ALEN; i++) + hw->mac.addr[i] = hw->mac.perm_addr[i]; + +out: + return ret_val; +} + +/** + * e1000_validate_nvm_checksum - Validate EEPROM checksum + * @hw: pointer to the HW structure + * + * Calculates the EEPROM checksum by reading/adding each word of the EEPROM + * and then verifies that the sum of the EEPROM is equal to 0xBABA. + **/ +s32 igb_validate_nvm_checksum(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 checksum = 0; + u16 i, nvm_data; + + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error\n"); + goto out; + } + checksum += nvm_data; + } + + if (checksum != (u16) NVM_SUM) { + hw_dbg(hw, "NVM Checksum Invalid\n"); + ret_val = -E1000_ERR_NVM; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_update_nvm_checksum - Update EEPROM checksum + * @hw: pointer to the HW structure + * + * Updates the EEPROM checksum by reading/adding each word of the EEPROM + * up to the checksum. Then calculates the EEPROM checksum and writes the + * value to the EEPROM. + **/ +s32 igb_update_nvm_checksum(struct e1000_hw *hw) +{ + s32 ret_val; + u16 checksum = 0; + u16 i, nvm_data; + + for (i = 0; i < NVM_CHECKSUM_REG; i++) { + ret_val = hw->nvm.ops.read_nvm(hw, i, 1, &nvm_data); + if (ret_val) { + hw_dbg(hw, "NVM Read Error while updating checksum.\n"); + goto out; + } + checksum += nvm_data; + } + checksum = (u16) NVM_SUM - checksum; + ret_val = hw->nvm.ops.write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum); + if (ret_val) + hw_dbg(hw, "NVM Write Error while updating checksum.\n"); + +out: + return ret_val; +} + diff --git a/drivers/net/igb/e1000_nvm.h b/drivers/net/igb/e1000_nvm.h new file mode 100644 index 000000000000..1041c34dcbe1 --- /dev/null +++ b/drivers/net/igb/e1000_nvm.h @@ -0,0 +1,40 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_NVM_H_ +#define _E1000_NVM_H_ + +s32 igb_acquire_nvm(struct e1000_hw *hw); +void igb_release_nvm(struct e1000_hw *hw); +s32 igb_read_mac_addr(struct e1000_hw *hw); +s32 igb_read_part_num(struct e1000_hw *hw, u32 *part_num); +s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); +s32 igb_validate_nvm_checksum(struct e1000_hw *hw); +s32 igb_update_nvm_checksum(struct e1000_hw *hw); + +#endif diff --git a/drivers/net/igb/e1000_phy.c b/drivers/net/igb/e1000_phy.c new file mode 100644 index 000000000000..08a86b107229 --- /dev/null +++ b/drivers/net/igb/e1000_phy.c @@ -0,0 +1,1807 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include <linux/if_ether.h> +#include <linux/delay.h> + +#include "e1000_mac.h" +#include "e1000_phy.h" + +static s32 igb_get_phy_cfg_done(struct e1000_hw *hw); +static void igb_release_phy(struct e1000_hw *hw); +static s32 igb_acquire_phy(struct e1000_hw *hw); +static s32 igb_phy_reset_dsp(struct e1000_hw *hw); +static s32 igb_phy_setup_autoneg(struct e1000_hw *hw); +static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, + u16 *phy_ctrl); +static s32 igb_wait_autoneg(struct e1000_hw *hw); + +/* Cable length tables */ +static const u16 e1000_m88_cable_length_table[] = + { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; +#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_m88_cable_length_table) / \ + sizeof(e1000_m88_cable_length_table[0])) + +static const u16 e1000_igp_2_cable_length_table[] = + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, + 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, + 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, + 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, + 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, + 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, + 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, + 104, 109, 114, 118, 121, 124}; +#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ + (sizeof(e1000_igp_2_cable_length_table) / \ + sizeof(e1000_igp_2_cable_length_table[0])) + +/** + * e1000_check_reset_block - Check if PHY reset is blocked + * @hw: pointer to the HW structure + * + * Read the PHY management control register and check whether a PHY reset + * is blocked. If a reset is not blocked return 0, otherwise + * return E1000_BLK_PHY_RESET (12). + **/ +s32 igb_check_reset_block(struct e1000_hw *hw) +{ + u32 manc; + + manc = rd32(E1000_MANC); + + return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? + E1000_BLK_PHY_RESET : 0; +} + +/** + * e1000_get_phy_id - Retrieve the PHY ID and revision + * @hw: pointer to the HW structure + * + * Reads the PHY registers and stores the PHY ID and possibly the PHY + * revision in the hardware structure. + **/ +s32 igb_get_phy_id(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 phy_id; + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_ID1, &phy_id); + if (ret_val) + goto out; + + phy->id = (u32)(phy_id << 16); + udelay(20); + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_ID2, &phy_id); + if (ret_val) + goto out; + + phy->id |= (u32)(phy_id & PHY_REVISION_MASK); + phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); + +out: + return ret_val; +} + +/** + * e1000_phy_reset_dsp - Reset PHY DSP + * @hw: pointer to the HW structure + * + * Reset the digital signal processor. + **/ +static s32 igb_phy_reset_dsp(struct e1000_hw *hw) +{ + s32 ret_val; + + ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0); + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_mdic - Read MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Reads the MDI control regsiter in the PHY at offset and stores the + * information read to data. + **/ +static s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + s32 ret_val = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + ret_val = -E1000_ERR_PARAM; + goto out; + } + + /* + * Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = ((offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_READ)); + + wr32(E1000_MDIC, mdic); + + /* + * Poll the ready bit to see if the MDI read completed + * Increasing the time out as testing showed failures with + * the lower time out + */ + for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { + udelay(50); + mdic = rd32(E1000_MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + hw_dbg(hw, "MDI Read did not complete\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + if (mdic & E1000_MDIC_ERROR) { + hw_dbg(hw, "MDI Error\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + *data = (u16) mdic; + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_mdic - Write MDI control register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write to register at offset + * + * Writes data to MDI control register in the PHY at offset. + **/ +static s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) +{ + struct e1000_phy_info *phy = &hw->phy; + u32 i, mdic = 0; + s32 ret_val = 0; + + if (offset > MAX_PHY_REG_ADDRESS) { + hw_dbg(hw, "PHY Address %d is out of range\n", offset); + ret_val = -E1000_ERR_PARAM; + goto out; + } + + /* + * Set up Op-code, Phy Address, and register offset in the MDI + * Control register. The MAC will take care of interfacing with the + * PHY to retrieve the desired data. + */ + mdic = (((u32)data) | + (offset << E1000_MDIC_REG_SHIFT) | + (phy->addr << E1000_MDIC_PHY_SHIFT) | + (E1000_MDIC_OP_WRITE)); + + wr32(E1000_MDIC, mdic); + + /* + * Poll the ready bit to see if the MDI read completed + * Increasing the time out as testing showed failures with + * the lower time out + */ + for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { + udelay(50); + mdic = rd32(E1000_MDIC); + if (mdic & E1000_MDIC_READY) + break; + } + if (!(mdic & E1000_MDIC_READY)) { + hw_dbg(hw, "MDI Write did not complete\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + if (mdic & E1000_MDIC_ERROR) { + hw_dbg(hw, "MDI Error\n"); + ret_val = -E1000_ERR_PHY; + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_read_phy_reg_igp - Read igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquires semaphore, if necessary, then reads the PHY register at offset + * and storing the retrieved information in data. Release any acquired + * semaphores before exiting. + **/ +s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) +{ + s32 ret_val; + + ret_val = igb_acquire_phy(hw); + if (ret_val) + goto out; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = igb_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + igb_release_phy(hw); + goto out; + } + } + + ret_val = igb_read_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + igb_release_phy(hw); + +out: + return ret_val; +} + +/** + * e1000_write_phy_reg_igp - Write igp PHY register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquires semaphore, if necessary, then writes the data to PHY register + * at the offset. Release any acquired semaphores before exiting. + **/ +s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) +{ + s32 ret_val; + + ret_val = igb_acquire_phy(hw); + if (ret_val) + goto out; + + if (offset > MAX_PHY_MULTI_PAGE_REG) { + ret_val = igb_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (u16)offset); + if (ret_val) { + igb_release_phy(hw); + goto out; + } + } + + ret_val = igb_write_phy_reg_mdic(hw, + MAX_PHY_REG_ADDRESS & offset, + data); + + igb_release_phy(hw); + +out: + return ret_val; +} + +/** + * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock + * and downshift values are set also. + **/ +s32 igb_copper_link_setup_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + + if (phy->reset_disable) { + ret_val = 0; + goto out; + } + + /* Enable CRS on TX. This must be set for half-duplex operation. */ + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + + /* + * Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + + switch (phy->mdix) { + case 1: + phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; + break; + case 2: + phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; + break; + case 3: + phy_data |= M88E1000_PSCR_AUTO_X_1000T; + break; + case 0: + default: + phy_data |= M88E1000_PSCR_AUTO_X_MODE; + break; + } + + /* + * Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; + if (phy->disable_polarity_correction == 1) + phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; + + ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; + + if (phy->revision < E1000_REVISION_4) { + /* + * Force TX_CLK in the Extended PHY Specific Control Register + * to 25MHz clock. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy_data |= M88E1000_EPSCR_TX_CLK_25; + + if ((phy->revision == E1000_REVISION_2) && + (phy->id == M88E1111_I_PHY_ID)) { + /* 82573L PHY - set the downshift counter to 5x. */ + phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; + phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; + } else { + /* Configure Master and Slave downshift values */ + phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); + phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | + M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); + } + ret_val = hw->phy.ops.write_phy_reg(hw, + M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; + } + + /* Commit the changes. */ + ret_val = igb_phy_sw_reset(hw); + if (ret_val) { + hw_dbg(hw, "Error committing the PHY changes\n"); + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_copper_link_setup_igp - Setup igp PHY's for copper link + * @hw: pointer to the HW structure + * + * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for + * igp PHY's. + **/ +s32 igb_copper_link_setup_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + if (phy->reset_disable) { + ret_val = 0; + goto out; + } + + ret_val = hw->phy.ops.reset_phy(hw); + if (ret_val) { + hw_dbg(hw, "Error resetting the PHY.\n"); + goto out; + } + + /* Wait 15ms for MAC to configure PHY from NVM settings. */ + msleep(15); + + /* + * The NVM settings will configure LPLU in D3 for + * non-IGP1 PHYs. + */ + if (phy->type == e1000_phy_igp) { + /* disable lplu d3 during driver init */ + if (hw->phy.ops.set_d3_lplu_state) + ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); + if (ret_val) { + hw_dbg(hw, "Error Disabling LPLU D3\n"); + goto out; + } + } + + /* disable lplu d0 during driver init */ + ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); + if (ret_val) { + hw_dbg(hw, "Error Disabling LPLU D0\n"); + goto out; + } + /* Configure mdi-mdix settings */ + ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCR_AUTO_MDIX; + + switch (phy->mdix) { + case 1: + data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 2: + data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; + break; + case 0: + default: + data |= IGP01E1000_PSCR_AUTO_MDIX; + break; + } + ret_val = hw->phy.ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, data); + if (ret_val) + goto out; + + /* set auto-master slave resolution settings */ + if (hw->mac.autoneg) { + /* + * when autonegotiation advertisement is only 1000Mbps then we + * should disable SmartSpeed and enable Auto MasterSlave + * resolution as hardware default. + */ + if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { + /* Disable SmartSpeed */ + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + + /* Set auto Master/Slave resolution process */ + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_CTRL, + &data); + if (ret_val) + goto out; + + data &= ~CR_1000T_MS_ENABLE; + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_1000T_CTRL, + data); + if (ret_val) + goto out; + } + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_CTRL, &data); + if (ret_val) + goto out; + + /* load defaults for future use */ + phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? + ((data & CR_1000T_MS_VALUE) ? + e1000_ms_force_master : + e1000_ms_force_slave) : + e1000_ms_auto; + + switch (phy->ms_type) { + case e1000_ms_force_master: + data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); + break; + case e1000_ms_force_slave: + data |= CR_1000T_MS_ENABLE; + data &= ~(CR_1000T_MS_VALUE); + break; + case e1000_ms_auto: + data &= ~CR_1000T_MS_ENABLE; + default: + break; + } + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_1000T_CTRL, data); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link + * @hw: pointer to the HW structure + * + * Performs initial bounds checking on autoneg advertisement parameter, then + * configure to advertise the full capability. Setup the PHY to autoneg + * and restart the negotiation process between the link partner. If + * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. + **/ +s32 igb_copper_link_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_ctrl; + + /* + * Perform some bounds checking on the autoneg advertisement + * parameter. + */ + phy->autoneg_advertised &= phy->autoneg_mask; + + /* + * If autoneg_advertised is zero, we assume it was not defaulted + * by the calling code so we set to advertise full capability. + */ + if (phy->autoneg_advertised == 0) + phy->autoneg_advertised = phy->autoneg_mask; + + hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n"); + ret_val = igb_phy_setup_autoneg(hw); + if (ret_val) { + hw_dbg(hw, "Error Setting up Auto-Negotiation\n"); + goto out; + } + hw_dbg(hw, "Restarting Auto-Neg\n"); + + /* + * Restart auto-negotiation by setting the Auto Neg Enable bit and + * the Auto Neg Restart bit in the PHY control register. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + goto out; + + phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + goto out; + + /* + * Does the user want to wait for Auto-Neg to complete here, or + * check at a later time (for example, callback routine). + */ + if (phy->autoneg_wait_to_complete) { + ret_val = igb_wait_autoneg(hw); + if (ret_val) { + hw_dbg(hw, "Error while waiting for " + "autoneg to complete\n"); + goto out; + } + } + + hw->mac.get_link_status = true; + +out: + return ret_val; +} + +/** + * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation + * @hw: pointer to the HW structure + * + * Reads the MII auto-neg advertisement register and/or the 1000T control + * register and if the PHY is already setup for auto-negotiation, then + * return successful. Otherwise, setup advertisement and flow control to + * the appropriate values for the wanted auto-negotiation. + **/ +static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 mii_autoneg_adv_reg; + u16 mii_1000t_ctrl_reg = 0; + + phy->autoneg_advertised &= phy->autoneg_mask; + + /* Read the MII Auto-Neg Advertisement Register (Address 4). */ + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_AUTONEG_ADV, + &mii_autoneg_adv_reg); + if (ret_val) + goto out; + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + /* Read the MII 1000Base-T Control Register (Address 9). */ + ret_val = hw->phy.ops.read_phy_reg(hw, + PHY_1000T_CTRL, + &mii_1000t_ctrl_reg); + if (ret_val) + goto out; + } + + /* + * Need to parse both autoneg_advertised and fc and set up + * the appropriate PHY registers. First we will parse for + * autoneg_advertised software override. Since we can advertise + * a plethora of combinations, we need to check each bit + * individually. + */ + + /* + * First we clear all the 10/100 mb speed bits in the Auto-Neg + * Advertisement Register (Address 4) and the 1000 mb speed bits in + * the 1000Base-T Control Register (Address 9). + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | + NWAY_AR_100TX_HD_CAPS | + NWAY_AR_10T_FD_CAPS | + NWAY_AR_10T_HD_CAPS); + mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); + + hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised); + + /* Do we want to advertise 10 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_HALF) { + hw_dbg(hw, "Advertise 10mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; + } + + /* Do we want to advertise 10 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_10_FULL) { + hw_dbg(hw, "Advertise 10mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; + } + + /* Do we want to advertise 100 Mb Half Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_HALF) { + hw_dbg(hw, "Advertise 100mb Half duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; + } + + /* Do we want to advertise 100 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_100_FULL) { + hw_dbg(hw, "Advertise 100mb Full duplex\n"); + mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; + } + + /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ + if (phy->autoneg_advertised & ADVERTISE_1000_HALF) + hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n"); + + /* Do we want to advertise 1000 Mb Full Duplex? */ + if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { + hw_dbg(hw, "Advertise 1000mb Full duplex\n"); + mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; + } + + /* + * Check for a software override of the flow control settings, and + * setup the PHY advertisement registers accordingly. If + * auto-negotiation is enabled, then software will have to set the + * "PAUSE" bits to the correct value in the Auto-Negotiation + * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- + * negotiation. + * + * The possible values of the "fc" parameter are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames + * but we do not support receiving pause frames). + * 3: Both Rx and TX flow control (symmetric) are enabled. + * other: No software override. The flow control configuration + * in the EEPROM is used. + */ + switch (hw->fc.type) { + case e1000_fc_none: + /* + * Flow control (RX & TX) is completely disabled by a + * software over-ride. + */ + mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_rx_pause: + /* + * RX Flow control is enabled, and TX Flow control is + * disabled, by a software over-ride. + * + * Since there really isn't a way to advertise that we are + * capable of RX Pause ONLY, we will advertise that we + * support both symmetric and asymmetric RX PAUSE. Later + * (in e1000_config_fc_after_link_up) we will disable the + * hw's ability to send PAUSE frames. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + case e1000_fc_tx_pause: + /* + * TX Flow control is enabled, and RX Flow control is + * disabled, by a software over-ride. + */ + mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; + mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; + break; + case e1000_fc_full: + /* + * Flow control (both RX and TX) is enabled by a software + * over-ride. + */ + mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); + break; + default: + hw_dbg(hw, "Flow control param set incorrectly\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_AUTONEG_ADV, + mii_autoneg_adv_reg); + if (ret_val) + goto out; + + hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); + + if (phy->autoneg_mask & ADVERTISE_1000_FULL) { + ret_val = hw->phy.ops.write_phy_reg(hw, + PHY_1000T_CTRL, + mii_1000t_ctrl_reg); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Waits for link and returns + * successful if link up is successful, else -E1000_ERR_PHY (-2). + **/ +s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + igb_phy_force_speed_duplex_setup(hw, &phy_data); + + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + /* + * Clear Auto-Crossover to force MDI manually. IGP requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; + phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; + + ret_val = hw->phy.ops.write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, + phy_data); + if (ret_val) + goto out; + + hw_dbg(hw, "IGP PSCR: %X\n", phy_data); + + udelay(1); + + if (phy->autoneg_wait_to_complete) { + hw_dbg(hw, + "Waiting for forced speed/duplex link on IGP phy.\n"); + + ret_val = igb_phy_has_link(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) + hw_dbg(hw, "Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = igb_phy_has_link(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY + * @hw: pointer to the HW structure + * + * Calls the PHY setup function to force speed and duplex. Clears the + * auto-crossover to force MDI manually. Resets the PHY to commit the + * changes. If time expires while waiting for link up, we reset the DSP. + * After reset, TX_CLK and CRS on TX must be set. Return successful upon + * successful completion, else return corresponding error code. + **/ +s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + /* + * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI + * forced whenever speed and duplex are forced. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; + + hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data); + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_data); + if (ret_val) + goto out; + + igb_phy_force_speed_duplex_setup(hw, &phy_data); + + /* Reset the phy to commit changes. */ + phy_data |= MII_CR_RESET; + + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_data); + if (ret_val) + goto out; + + udelay(1); + + if (phy->autoneg_wait_to_complete) { + hw_dbg(hw, + "Waiting for forced speed/duplex link on M88 phy.\n"); + + ret_val = igb_phy_has_link(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) { + /* + * We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = hw->phy.ops.write_phy_reg(hw, + M88E1000_PHY_PAGE_SELECT, + 0x001d); + if (ret_val) + goto out; + ret_val = igb_phy_reset_dsp(hw); + if (ret_val) + goto out; + } + + /* Try once more */ + ret_val = igb_phy_has_link(hw, PHY_FORCE_LIMIT, + 100000, &link); + if (ret_val) + goto out; + } + + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + /* + * Resetting the phy means we need to re-force TX_CLK in the + * Extended PHY Specific Control Register to 25MHz clock from + * the reset value of 2.5MHz. + */ + phy_data |= M88E1000_EPSCR_TX_CLK_25; + ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; + + /* + * In addition, we must re-enable CRS on Tx for both half and full + * duplex. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; + ret_val = hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + +out: + return ret_val; +} + +/** + * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex + * @hw: pointer to the HW structure + * @phy_ctrl: pointer to current value of PHY_CONTROL + * + * Forces speed and duplex on the PHY by doing the following: disable flow + * control, force speed/duplex on the MAC, disable auto speed detection, + * disable auto-negotiation, configure duplex, configure speed, configure + * the collision distance, write configuration to CTRL register. The + * caller must write to the PHY_CONTROL register for these settings to + * take affect. + **/ +static void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, + u16 *phy_ctrl) +{ + struct e1000_mac_info *mac = &hw->mac; + u32 ctrl; + + /* Turn off flow control when forcing speed/duplex */ + hw->fc.type = e1000_fc_none; + + /* Force speed/duplex on the mac */ + ctrl = rd32(E1000_CTRL); + ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); + ctrl &= ~E1000_CTRL_SPD_SEL; + + /* Disable Auto Speed Detection */ + ctrl &= ~E1000_CTRL_ASDE; + + /* Disable autoneg on the phy */ + *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; + + /* Forcing Full or Half Duplex? */ + if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { + ctrl &= ~E1000_CTRL_FD; + *phy_ctrl &= ~MII_CR_FULL_DUPLEX; + hw_dbg(hw, "Half Duplex\n"); + } else { + ctrl |= E1000_CTRL_FD; + *phy_ctrl |= MII_CR_FULL_DUPLEX; + hw_dbg(hw, "Full Duplex\n"); + } + + /* Forcing 10mb or 100mb? */ + if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { + ctrl |= E1000_CTRL_SPD_100; + *phy_ctrl |= MII_CR_SPEED_100; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); + hw_dbg(hw, "Forcing 100mb\n"); + } else { + ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); + *phy_ctrl |= MII_CR_SPEED_10; + *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); + hw_dbg(hw, "Forcing 10mb\n"); + } + + igb_config_collision_dist(hw); + + wr32(E1000_CTRL, ctrl); +} + +/** + * e1000_set_d3_lplu_state - Sets low power link up state for D3 + * @hw: pointer to the HW structure + * @active: boolean used to enable/disable lplu + * + * Success returns 0, Failure returns 1 + * + * The low power link up (lplu) state is set to the power management level D3 + * and SmartSpeed is disabled when active is true, else clear lplu for D3 + * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU + * is used during Dx states where the power conservation is most important. + * During driver activity, SmartSpeed should be enabled so performance is + * maintained. + **/ +s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = hw->phy.ops.read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, + &data); + if (ret_val) + goto out; + + if (!active) { + data &= ~IGP02E1000_PM_D3_LPLU; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + goto out; + /* + * LPLU and SmartSpeed are mutually exclusive. LPLU is used + * during Dx states where the power conservation is most + * important. During driver activity we should enable + * SmartSpeed, so performance is maintained. + */ + if (phy->smart_speed == e1000_smart_speed_on) { + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data |= IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } else if (phy->smart_speed == e1000_smart_speed_off) { + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + if (ret_val) + goto out; + } + } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || + (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || + (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { + data |= IGP02E1000_PM_D3_LPLU; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP02E1000_PHY_POWER_MGMT, + data); + if (ret_val) + goto out; + + /* When LPLU is enabled, we should disable SmartSpeed */ + ret_val = hw->phy.ops.read_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + &data); + if (ret_val) + goto out; + + data &= ~IGP01E1000_PSCFR_SMART_SPEED; + ret_val = hw->phy.ops.write_phy_reg(hw, + IGP01E1000_PHY_PORT_CONFIG, + data); + } + +out: + return ret_val; +} + +/** + * e1000_check_downshift - Checks whether a downshift in speed occured + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns 1 + * + * A downshift is detected by querying the PHY link health. + **/ +s32 igb_check_downshift(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + switch (phy->type) { + case e1000_phy_m88: + case e1000_phy_gg82563: + offset = M88E1000_PHY_SPEC_STATUS; + mask = M88E1000_PSSR_DOWNSHIFT; + break; + case e1000_phy_igp_2: + case e1000_phy_igp: + case e1000_phy_igp_3: + offset = IGP01E1000_PHY_LINK_HEALTH; + mask = IGP01E1000_PLHR_SS_DOWNGRADE; + break; + default: + /* speed downshift not supported */ + phy->speed_downgraded = false; + ret_val = 0; + goto out; + } + + ret_val = hw->phy.ops.read_phy_reg(hw, offset, &phy_data); + + if (!ret_val) + phy->speed_downgraded = (phy_data & mask) ? true : false; + +out: + return ret_val; +} + +/** + * e1000_check_polarity_m88 - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY specific status register. + **/ +static s32 igb_check_polarity_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &data); + + if (!ret_val) + phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** + * e1000_check_polarity_igp - Checks the polarity. + * @hw: pointer to the HW structure + * + * Success returns 0, Failure returns -E1000_ERR_PHY (-2) + * + * Polarity is determined based on the PHY port status register, and the + * current speed (since there is no polarity at 100Mbps). + **/ +static s32 igb_check_polarity_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data, offset, mask; + + /* + * Polarity is determined based on the speed of + * our connection. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, + &data); + if (ret_val) + goto out; + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + offset = IGP01E1000_PHY_PCS_INIT_REG; + mask = IGP01E1000_PHY_POLARITY_MASK; + } else { + /* + * This really only applies to 10Mbps since + * there is no polarity for 100Mbps (always 0). + */ + offset = IGP01E1000_PHY_PORT_STATUS; + mask = IGP01E1000_PSSR_POLARITY_REVERSED; + } + + ret_val = hw->phy.ops.read_phy_reg(hw, offset, &data); + + if (!ret_val) + phy->cable_polarity = (data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + +out: + return ret_val; +} + +/** + * e1000_wait_autoneg - Wait for auto-neg compeletion + * @hw: pointer to the HW structure + * + * Waits for auto-negotiation to complete or for the auto-negotiation time + * limit to expire, which ever happens first. + **/ +static s32 igb_wait_autoneg(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 i, phy_status; + + /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ + for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_AUTONEG_COMPLETE) + break; + msleep(100); + } + + /* + * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation + * has completed. + */ + return ret_val; +} + +/** + * e1000_phy_has_link - Polls PHY for link + * @hw: pointer to the HW structure + * @iterations: number of times to poll for link + * @usec_interval: delay between polling attempts + * @success: pointer to whether polling was successful or not + * + * Polls the PHY status register for link, 'iterations' number of times. + **/ +s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success) +{ + s32 ret_val = 0; + u16 i, phy_status; + + for (i = 0; i < iterations; i++) { + /* + * Some PHYs require the PHY_STATUS register to be read + * twice due to the link bit being sticky. No harm doing + * it across the board. + */ + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_STATUS, &phy_status); + if (ret_val) + break; + if (phy_status & MII_SR_LINK_STATUS) + break; + if (usec_interval >= 1000) + mdelay(usec_interval/1000); + else + udelay(usec_interval); + } + + *success = (i < iterations) ? true : false; + + return ret_val; +} + +/** + * e1000_get_cable_length_m88 - Determine cable length for m88 PHY + * @hw: pointer to the HW structure + * + * Reads the PHY specific status register to retrieve the cable length + * information. The cable length is determined by averaging the minimum and + * maximum values to get the "average" cable length. The m88 PHY has four + * possible cable length values, which are: + * Register Value Cable Length + * 0 < 50 meters + * 1 50 - 80 meters + * 2 80 - 110 meters + * 3 110 - 140 meters + * 4 > 140 meters + **/ +s32 igb_get_cable_length_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, index; + + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data); + if (ret_val) + goto out; + + index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT; + phy->min_cable_length = e1000_m88_cable_length_table[index]; + phy->max_cable_length = e1000_m88_cable_length_table[index+1]; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + +out: + return ret_val; +} + +/** + * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY + * @hw: pointer to the HW structure + * + * The automatic gain control (agc) normalizes the amplitude of the + * received signal, adjusting for the attenuation produced by the + * cable. By reading the AGC registers, which reperesent the + * cobination of course and fine gain value, the value can be put + * into a lookup table to obtain the approximate cable length + * for each channel. + **/ +s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 phy_data, i, agc_value = 0; + u16 cur_agc_index, max_agc_index = 0; + u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; + u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = + {IGP02E1000_PHY_AGC_A, + IGP02E1000_PHY_AGC_B, + IGP02E1000_PHY_AGC_C, + IGP02E1000_PHY_AGC_D}; + + /* Read the AGC registers for all channels */ + for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { + ret_val = hw->phy.ops.read_phy_reg(hw, agc_reg_array[i], + &phy_data); + if (ret_val) + goto out; + + /* + * Getting bits 15:9, which represent the combination of + * course and fine gain values. The result is a number + * that can be put into the lookup table to obtain the + * approximate cable length. + */ + cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & + IGP02E1000_AGC_LENGTH_MASK; + + /* Array index bound check. */ + if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || + (cur_agc_index == 0)) { + ret_val = -E1000_ERR_PHY; + goto out; + } + + /* Remove min & max AGC values from calculation. */ + if (e1000_igp_2_cable_length_table[min_agc_index] > + e1000_igp_2_cable_length_table[cur_agc_index]) + min_agc_index = cur_agc_index; + if (e1000_igp_2_cable_length_table[max_agc_index] < + e1000_igp_2_cable_length_table[cur_agc_index]) + max_agc_index = cur_agc_index; + + agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; + } + + agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + + e1000_igp_2_cable_length_table[max_agc_index]); + agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); + + /* Calculate cable length with the error range of +/- 10 meters. */ + phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? + (agc_value - IGP02E1000_AGC_RANGE) : 0; + phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; + + phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_m88 - Retrieve PHY information + * @hw: pointer to the HW structure + * + * Valid for only copper links. Read the PHY status register (sticky read) + * to verify that link is up. Read the PHY special control register to + * determine the polarity and 10base-T extended distance. Read the PHY + * special status register to determine MDI/MDIx and current speed. If + * speed is 1000, then determine cable length, local and remote receiver. + **/ +s32 igb_get_phy_info_m88(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data; + bool link; + + if (hw->phy.media_type != e1000_media_type_copper) { + hw_dbg(hw, "Phy info is only valid for copper media\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = igb_phy_has_link(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; + + phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) + ? true + : false; + + ret_val = igb_check_polarity_m88(hw); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, + &phy_data); + if (ret_val) + goto out; + + phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; + + if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS, + &phy_data); + if (ret_val) + goto out; + + phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + /* Set values to "undefined" */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_get_phy_info_igp - Retrieve igp PHY information + * @hw: pointer to the HW structure + * + * Read PHY status to determine if link is up. If link is up, then + * set/determine 10base-T extended distance and polarity correction. Read + * PHY port status to determine MDI/MDIx and speed. Based on the speed, + * determine on the cable length, local and remote receiver. + **/ +s32 igb_get_phy_info_igp(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = igb_phy_has_link(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + hw_dbg(hw, "Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + phy->polarity_correction = true; + + ret_val = igb_check_polarity_igp(hw); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, + &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; + + if ((data & IGP01E1000_PSSR_SPEED_MASK) == + IGP01E1000_PSSR_SPEED_1000MBPS) { + ret_val = hw->phy.ops.get_cable_length(hw); + if (ret_val) + goto out; + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS, + &data); + if (ret_val) + goto out; + + phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + + phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) + ? e1000_1000t_rx_status_ok + : e1000_1000t_rx_status_not_ok; + } else { + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + } + +out: + return ret_val; +} + +/** + * e1000_phy_sw_reset - PHY software reset + * @hw: pointer to the HW structure + * + * Does a software reset of the PHY by reading the PHY control register and + * setting/write the control register reset bit to the PHY. + **/ +s32 igb_phy_sw_reset(struct e1000_hw *hw) +{ + s32 ret_val; + u16 phy_ctrl; + + ret_val = hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_ctrl); + if (ret_val) + goto out; + + phy_ctrl |= MII_CR_RESET; + ret_val = hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_ctrl); + if (ret_val) + goto out; + + udelay(1); + +out: + return ret_val; +} + +/** + * e1000_phy_hw_reset - PHY hardware reset + * @hw: pointer to the HW structure + * + * Verify the reset block is not blocking us from resetting. Acquire + * semaphore (if necessary) and read/set/write the device control reset + * bit in the PHY. Wait the appropriate delay time for the device to + * reset and relase the semaphore (if necessary). + **/ +s32 igb_phy_hw_reset(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u32 ctrl; + + ret_val = igb_check_reset_block(hw); + if (ret_val) { + ret_val = 0; + goto out; + } + + ret_val = igb_acquire_phy(hw); + if (ret_val) + goto out; + + ctrl = rd32(E1000_CTRL); + wr32(E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); + wrfl(); + + udelay(phy->reset_delay_us); + + wr32(E1000_CTRL, ctrl); + wrfl(); + + udelay(150); + + igb_release_phy(hw); + + ret_val = igb_get_phy_cfg_done(hw); + +out: + return ret_val; +} + +/* Internal function pointers */ + +/** + * e1000_get_phy_cfg_done - Generic PHY configuration done + * @hw: pointer to the HW structure + * + * Return success if silicon family did not implement a family specific + * get_cfg_done function. + **/ +static s32 igb_get_phy_cfg_done(struct e1000_hw *hw) +{ + if (hw->phy.ops.get_cfg_done) + return hw->phy.ops.get_cfg_done(hw); + + return 0; +} + +/** + * e1000_release_phy - Generic release PHY + * @hw: pointer to the HW structure + * + * Return if silicon family does not require a semaphore when accessing the + * PHY. + **/ +static void igb_release_phy(struct e1000_hw *hw) +{ + if (hw->phy.ops.release_phy) + hw->phy.ops.release_phy(hw); +} + +/** + * e1000_acquire_phy - Generic acquire PHY + * @hw: pointer to the HW structure + * + * Return success if silicon family does not require a semaphore when + * accessing the PHY. + **/ +static s32 igb_acquire_phy(struct e1000_hw *hw) +{ + if (hw->phy.ops.acquire_phy) + return hw->phy.ops.acquire_phy(hw); + + return 0; +} + +/** + * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex + * @hw: pointer to the HW structure + * + * When the silicon family has not implemented a forced speed/duplex + * function for the PHY, simply return 0. + **/ +s32 igb_phy_force_speed_duplex(struct e1000_hw *hw) +{ + if (hw->phy.ops.force_speed_duplex) + return hw->phy.ops.force_speed_duplex(hw); + + return 0; +} + +/** + * e1000_phy_init_script_igp3 - Inits the IGP3 PHY + * @hw: pointer to the HW structure + * + * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. + **/ +s32 igb_phy_init_script_igp3(struct e1000_hw *hw) +{ + hw_dbg(hw, "Running IGP 3 PHY init script\n"); + + /* PHY init IGP 3 */ + /* Enable rise/fall, 10-mode work in class-A */ + hw->phy.ops.write_phy_reg(hw, 0x2F5B, 0x9018); + /* Remove all caps from Replica path filter */ + hw->phy.ops.write_phy_reg(hw, 0x2F52, 0x0000); + /* Bias trimming for ADC, AFE and Driver (Default) */ + hw->phy.ops.write_phy_reg(hw, 0x2FB1, 0x8B24); + /* Increase Hybrid poly bias */ + hw->phy.ops.write_phy_reg(hw, 0x2FB2, 0xF8F0); + /* Add 4% to TX amplitude in Giga mode */ + hw->phy.ops.write_phy_reg(hw, 0x2010, 0x10B0); + /* Disable trimming (TTT) */ + hw->phy.ops.write_phy_reg(hw, 0x2011, 0x0000); + /* Poly DC correction to 94.6% + 2% for all channels */ + hw->phy.ops.write_phy_reg(hw, 0x20DD, 0x249A); + /* ABS DC correction to 95.9% */ + hw->phy.ops.write_phy_reg(hw, 0x20DE, 0x00D3); + /* BG temp curve trim */ + hw->phy.ops.write_phy_reg(hw, 0x28B4, 0x04CE); + /* Increasing ADC OPAMP stage 1 currents to max */ + hw->phy.ops.write_phy_reg(hw, 0x2F70, 0x29E4); + /* Force 1000 ( required for enabling PHY regs configuration) */ + hw->phy.ops.write_phy_reg(hw, 0x0000, 0x0140); + /* Set upd_freq to 6 */ + hw->phy.ops.write_phy_reg(hw, 0x1F30, 0x1606); + /* Disable NPDFE */ + hw->phy.ops.write_phy_reg(hw, 0x1F31, 0xB814); + /* Disable adaptive fixed FFE (Default) */ + hw->phy.ops.write_phy_reg(hw, 0x1F35, 0x002A); + /* Enable FFE hysteresis */ + hw->phy.ops.write_phy_reg(hw, 0x1F3E, 0x0067); + /* Fixed FFE for short cable lengths */ + hw->phy.ops.write_phy_reg(hw, 0x1F54, 0x0065); + /* Fixed FFE for medium cable lengths */ + hw->phy.ops.write_phy_reg(hw, 0x1F55, 0x002A); + /* Fixed FFE for long cable lengths */ + hw->phy.ops.write_phy_reg(hw, 0x1F56, 0x002A); + /* Enable Adaptive Clip Threshold */ + hw->phy.ops.write_phy_reg(hw, 0x1F72, 0x3FB0); + /* AHT reset limit to 1 */ + hw->phy.ops.write_phy_reg(hw, 0x1F76, 0xC0FF); + /* Set AHT master delay to 127 msec */ + hw->phy.ops.write_phy_reg(hw, 0x1F77, 0x1DEC); + /* Set scan bits for AHT */ + hw->phy.ops.write_phy_reg(hw, 0x1F78, 0xF9EF); + /* Set AHT Preset bits */ + hw->phy.ops.write_phy_reg(hw, 0x1F79, 0x0210); + /* Change integ_factor of channel A to 3 */ + hw->phy.ops.write_phy_reg(hw, 0x1895, 0x0003); + /* Change prop_factor of channels BCD to 8 */ + hw->phy.ops.write_phy_reg(hw, 0x1796, 0x0008); + /* Change cg_icount + enable integbp for channels BCD */ + hw->phy.ops.write_phy_reg(hw, 0x1798, 0xD008); + /* + * Change cg_icount + enable integbp + change prop_factor_master + * to 8 for channel A + */ + hw->phy.ops.write_phy_reg(hw, 0x1898, 0xD918); + /* Disable AHT in Slave mode on channel A */ + hw->phy.ops.write_phy_reg(hw, 0x187A, 0x0800); + /* + * Enable LPLU and disable AN to 1000 in non-D0a states, + * Enable SPD+B2B + */ + hw->phy.ops.write_phy_reg(hw, 0x0019, 0x008D); + /* Enable restart AN on an1000_dis change */ + hw->phy.ops.write_phy_reg(hw, 0x001B, 0x2080); + /* Enable wh_fifo read clock in 10/100 modes */ + hw->phy.ops.write_phy_reg(hw, 0x0014, 0x0045); + /* Restart AN, Speed selection is 1000 */ + hw->phy.ops.write_phy_reg(hw, 0x0000, 0x1340); + + return 0; +} + diff --git a/drivers/net/igb/e1000_phy.h b/drivers/net/igb/e1000_phy.h new file mode 100644 index 000000000000..8f8fe0a780d1 --- /dev/null +++ b/drivers/net/igb/e1000_phy.h @@ -0,0 +1,98 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_PHY_H_ +#define _E1000_PHY_H_ + +enum e1000_ms_type { + e1000_ms_hw_default = 0, + e1000_ms_force_master, + e1000_ms_force_slave, + e1000_ms_auto +}; + +enum e1000_smart_speed { + e1000_smart_speed_default = 0, + e1000_smart_speed_on, + e1000_smart_speed_off +}; + +s32 igb_check_downshift(struct e1000_hw *hw); +s32 igb_check_reset_block(struct e1000_hw *hw); +s32 igb_copper_link_autoneg(struct e1000_hw *hw); +s32 igb_phy_force_speed_duplex(struct e1000_hw *hw); +s32 igb_copper_link_setup_igp(struct e1000_hw *hw); +s32 igb_copper_link_setup_m88(struct e1000_hw *hw); +s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw); +s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw); +s32 igb_get_cable_length_m88(struct e1000_hw *hw); +s32 igb_get_cable_length_igp_2(struct e1000_hw *hw); +s32 igb_get_phy_id(struct e1000_hw *hw); +s32 igb_get_phy_info_igp(struct e1000_hw *hw); +s32 igb_get_phy_info_m88(struct e1000_hw *hw); +s32 igb_phy_sw_reset(struct e1000_hw *hw); +s32 igb_phy_hw_reset(struct e1000_hw *hw); +s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); +s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active); +s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); +s32 igb_phy_has_link(struct e1000_hw *hw, u32 iterations, + u32 usec_interval, bool *success); +s32 igb_phy_init_script_igp3(struct e1000_hw *hw); + +/* IGP01E1000 Specific Registers */ +#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ +#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ +#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ +#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ +#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ +#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ +#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 +#define IGP01E1000_PHY_POLARITY_MASK 0x0078 +#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 +#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ +#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 + +/* Enable flexible speed on link-up */ +#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ +#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ +#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 +#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 +#define IGP01E1000_PSSR_MDIX 0x0008 +#define IGP01E1000_PSSR_SPEED_MASK 0xC000 +#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 +#define IGP02E1000_PHY_CHANNEL_NUM 4 +#define IGP02E1000_PHY_AGC_A 0x11B1 +#define IGP02E1000_PHY_AGC_B 0x12B1 +#define IGP02E1000_PHY_AGC_C 0x14B1 +#define IGP02E1000_PHY_AGC_D 0x18B1 +#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ +#define IGP02E1000_AGC_LENGTH_MASK 0x7F +#define IGP02E1000_AGC_RANGE 15 + +#define E1000_CABLE_LENGTH_UNDEFINED 0xFF + +#endif diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h new file mode 100644 index 000000000000..ff187b73c69e --- /dev/null +++ b/drivers/net/igb/e1000_regs.h @@ -0,0 +1,270 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _E1000_REGS_H_ +#define _E1000_REGS_H_ + +#define E1000_CTRL 0x00000 /* Device Control - RW */ +#define E1000_STATUS 0x00008 /* Device Status - RO */ +#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ +#define E1000_EERD 0x00014 /* EEPROM Read - RW */ +#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define E1000_MDIC 0x00020 /* MDI Control - RW */ +#define E1000_SCTL 0x00024 /* SerDes Control - RW */ +#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ +#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FCT 0x00030 /* Flow Control Type - RW */ +#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ +#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ +#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ +#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ +#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ +#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ +#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ +#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ +#define E1000_RCTL 0x00100 /* RX Control - RW */ +#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ +#define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ +#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */ +#define E1000_EITR(_n) (0x01680 + (0x4 * (_n))) +#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ +#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ +#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ +#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */ +#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */ +#define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */ +#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ +#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ +#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ +#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ +#define E1000_PBS 0x01008 /* Packet Buffer Size */ +#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ +#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ +#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ +#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ +#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */ +#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ +#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ +#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n))) +#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ +/* Split and Replication RX Control - RW */ +/* + * Convenience macros + * + * Note: "_n" is the queue number of the register to be written to. + * + * Example usage: + * E1000_RDBAL_REG(current_rx_queue) + */ +#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) \ + : (0x0C000 + ((_n) * 0x40))) +#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) \ + : (0x0C004 + ((_n) * 0x40))) +#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) \ + : (0x0C008 + ((_n) * 0x40))) +#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) \ + : (0x0C00C + ((_n) * 0x40))) +#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) \ + : (0x0C010 + ((_n) * 0x40))) +#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) \ + : (0x0C018 + ((_n) * 0x40))) +#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) \ + : (0x0C028 + ((_n) * 0x40))) +#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) \ + : (0x0E000 + ((_n) * 0x40))) +#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) \ + : (0x0E004 + ((_n) * 0x40))) +#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) \ + : (0x0E008 + ((_n) * 0x40))) +#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) \ + : (0x0E010 + ((_n) * 0x40))) +#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) \ + : (0x0E018 + ((_n) * 0x40))) +#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) \ + : (0x0E028 + ((_n) * 0x40))) +#define E1000_TARC(_n) (0x03840 + (_n << 8)) +#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8)) +#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8)) +#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) \ + : (0x0E038 + ((_n) * 0x40))) +#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) \ + : (0x0E03C + ((_n) * 0x40))) +#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */ +#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */ +#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */ +#define E1000_TDFPC 0x03430 /* TX Data FIFO Packet Count - RW */ +#define E1000_DTXCTL 0x03590 /* DMA TX Control - RW */ +#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ +#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ +#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ +#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ +#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ +#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ +#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ +#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ +#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ +#define E1000_COLC 0x04028 /* Collision Count - R/clr */ +#define E1000_DC 0x04030 /* Defer Count - R/clr */ +#define E1000_TNCRS 0x04034 /* TX-No CRS - R/clr */ +#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ +#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ +#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ +#define E1000_XONRXC 0x04048 /* XON RX Count - R/clr */ +#define E1000_XONTXC 0x0404C /* XON TX Count - R/clr */ +#define E1000_XOFFRXC 0x04050 /* XOFF RX Count - R/clr */ +#define E1000_XOFFTXC 0x04054 /* XOFF TX Count - R/clr */ +#define E1000_FCRUC 0x04058 /* Flow Control RX Unsupported Count- R/clr */ +#define E1000_PRC64 0x0405C /* Packets RX (64 bytes) - R/clr */ +#define E1000_PRC127 0x04060 /* Packets RX (65-127 bytes) - R/clr */ +#define E1000_PRC255 0x04064 /* Packets RX (128-255 bytes) - R/clr */ +#define E1000_PRC511 0x04068 /* Packets RX (255-511 bytes) - R/clr */ +#define E1000_PRC1023 0x0406C /* Packets RX (512-1023 bytes) - R/clr */ +#define E1000_PRC1522 0x04070 /* Packets RX (1024-1522 bytes) - R/clr */ +#define E1000_GPRC 0x04074 /* Good Packets RX Count - R/clr */ +#define E1000_BPRC 0x04078 /* Broadcast Packets RX Count - R/clr */ +#define E1000_MPRC 0x0407C /* Multicast Packets RX Count - R/clr */ +#define E1000_GPTC 0x04080 /* Good Packets TX Count - R/clr */ +#define E1000_GORCL 0x04088 /* Good Octets RX Count Low - R/clr */ +#define E1000_GORCH 0x0408C /* Good Octets RX Count High - R/clr */ +#define E1000_GOTCL 0x04090 /* Good Octets TX Count Low - R/clr */ +#define E1000_GOTCH 0x04094 /* Good Octets TX Count High - R/clr */ +#define E1000_RNBC 0x040A0 /* RX No Buffers Count - R/clr */ +#define E1000_RUC 0x040A4 /* RX Undersize Count - R/clr */ +#define E1000_RFC 0x040A8 /* RX Fragment Count - R/clr */ +#define E1000_ROC 0x040AC /* RX Oversize Count - R/clr */ +#define E1000_RJC 0x040B0 /* RX Jabber Count - R/clr */ +#define E1000_MGTPRC 0x040B4 /* Management Packets RX Count - R/clr */ +#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ +#define E1000_MGTPTC 0x040BC /* Management Packets TX Count - R/clr */ +#define E1000_TORL 0x040C0 /* Total Octets RX Low - R/clr */ +#define E1000_TORH 0x040C4 /* Total Octets RX High - R/clr */ +#define E1000_TOTL 0x040C8 /* Total Octets TX Low - R/clr */ +#define E1000_TOTH 0x040CC /* Total Octets TX High - R/clr */ +#define E1000_TPR 0x040D0 /* Total Packets RX - R/clr */ +#define E1000_TPT 0x040D4 /* Total Packets TX - R/clr */ +#define E1000_PTC64 0x040D8 /* Packets TX (64 bytes) - R/clr */ +#define E1000_PTC127 0x040DC /* Packets TX (65-127 bytes) - R/clr */ +#define E1000_PTC255 0x040E0 /* Packets TX (128-255 bytes) - R/clr */ +#define E1000_PTC511 0x040E4 /* Packets TX (256-511 bytes) - R/clr */ +#define E1000_PTC1023 0x040E8 /* Packets TX (512-1023 bytes) - R/clr */ +#define E1000_PTC1522 0x040EC /* Packets TX (1024-1522 Bytes) - R/clr */ +#define E1000_MPTC 0x040F0 /* Multicast Packets TX Count - R/clr */ +#define E1000_BPTC 0x040F4 /* Broadcast Packets TX Count - R/clr */ +#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context TX - R/clr */ +#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context TX Fail - R/clr */ +#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ +/* Interrupt Cause Rx Packet Timer Expire Count */ +#define E1000_ICRXPTC 0x04104 +/* Interrupt Cause Rx Absolute Timer Expire Count */ +#define E1000_ICRXATC 0x04108 +/* Interrupt Cause Tx Packet Timer Expire Count */ +#define E1000_ICTXPTC 0x0410C +/* Interrupt Cause Tx Absolute Timer Expire Count */ +#define E1000_ICTXATC 0x04110 +/* Interrupt Cause Tx Queue Empty Count */ +#define E1000_ICTXQEC 0x04118 +/* Interrupt Cause Tx Queue Minimum Threshold Count */ +#define E1000_ICTXQMTC 0x0411C +/* Interrupt Cause Rx Descriptor Minimum Threshold Count */ +#define E1000_ICRXDMTC 0x04120 +#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ +#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ +#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ +#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ +#define E1000_CBTMPC 0x0402C /* Circuit Breaker TX Packet Count */ +#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ +#define E1000_CBRMPC 0x040FC /* Circuit Breaker RX Packet Count */ +#define E1000_RPTHC 0x04104 /* Rx Packets To Host */ +#define E1000_HGPTC 0x04118 /* Host Good Packets TX Count */ +#define E1000_HTCBDPC 0x04124 /* Host TX Circuit Breaker Dropped Count */ +#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */ +#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */ +#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ +#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ +#define E1000_LENERRS 0x04138 /* Length Errors Count */ +#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ +#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */ +#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */ +#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */ +#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */ +#define E1000_RXCSUM 0x05000 /* RX Checksum Control - RW */ +#define E1000_RLPML 0x05004 /* RX Long Packet Max Length */ +#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ +#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ +#define E1000_RA 0x05400 /* Receive Address - RW Array */ +#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ +#define E1000_VMD_CTL 0x0581C /* VMDq Control - RW */ +#define E1000_WUC 0x05800 /* Wakeup Control - RW */ +#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ +#define E1000_WUS 0x05810 /* Wakeup Status - RO */ +#define E1000_MANC 0x05820 /* Management Control - RW */ +#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ +#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ +#define E1000_HOST_IF 0x08800 /* Host Interface */ + +#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ +#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ +#define E1000_CCMCTL 0x05B48 /* CCM Control Register */ +#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ +#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ +#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ +#define E1000_SWSM 0x05B50 /* SW Semaphore */ +#define E1000_FWSM 0x05B54 /* FW Semaphore */ +#define E1000_HICR 0x08F00 /* Host Inteface Control */ + +/* RSS registers */ +#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ +#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */ +#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/ +#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt RX VLAN Priority - RW */ +/* MSI-X Allocation Register (_i) - RW */ +#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) +/* MSI-X Table entry addr low reg 0 - RW */ +#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) +/* MSI-X Table entry addr upper reg 0 - RW */ +#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) +/* MSI-X Table entry message reg 0 - RW */ +#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) +/* MSI-X Table entry vector ctrl reg 0 - RW */ +#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) +/* Redirection Table - RW Array */ +#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) +#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */ + +#define E1000_REGISTER(a, reg) reg + +#define wr32(reg, value) (writel(value, hw->hw_addr + reg)) +#define rd32(reg) (readl(hw->hw_addr + reg)) +#define wrfl() ((void)rd32(E1000_STATUS)) + +#define array_wr32(reg, offset, value) \ + (writel(value, hw->hw_addr + reg + ((offset) << 2))) +#define array_rd32(reg, offset) \ + (readl(hw->hw_addr + reg + ((offset) << 2))) + +#endif diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h new file mode 100644 index 000000000000..6b2e7d351d65 --- /dev/null +++ b/drivers/net/igb/igb.h @@ -0,0 +1,300 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +/* Linux PRO/1000 Ethernet Driver main header file */ + +#ifndef _IGB_H_ +#define _IGB_H_ + +#include "e1000_mac.h" +#include "e1000_82575.h" + +struct igb_adapter; + +/* Interrupt defines */ +#define IGB_MAX_TX_CLEAN 72 + +#define IGB_MIN_DYN_ITR 3000 +#define IGB_MAX_DYN_ITR 96000 +#define IGB_START_ITR 6000 + +#define IGB_DYN_ITR_PACKET_THRESHOLD 2 +#define IGB_DYN_ITR_LENGTH_LOW 200 +#define IGB_DYN_ITR_LENGTH_HIGH 1000 + +/* TX/RX descriptor defines */ +#define IGB_DEFAULT_TXD 256 +#define IGB_MIN_TXD 80 +#define IGB_MAX_TXD 4096 + +#define IGB_DEFAULT_RXD 256 +#define IGB_MIN_RXD 80 +#define IGB_MAX_RXD 4096 + +#define IGB_DEFAULT_ITR 3 /* dynamic */ +#define IGB_MAX_ITR_USECS 10000 +#define IGB_MIN_ITR_USECS 10 + +/* Transmit and receive queues */ +#define IGB_MAX_RX_QUEUES 4 + +/* RX descriptor control thresholds. + * PTHRESH - MAC will consider prefetch if it has fewer than this number of + * descriptors available in its onboard memory. + * Setting this to 0 disables RX descriptor prefetch. + * HTHRESH - MAC will only prefetch if there are at least this many descriptors + * available in host memory. + * If PTHRESH is 0, this should also be 0. + * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back + * descriptors until either it has this many to write back, or the + * ITR timer expires. + */ +#define IGB_RX_PTHRESH 16 +#define IGB_RX_HTHRESH 8 +#define IGB_RX_WTHRESH 1 + +/* this is the size past which hardware will drop packets when setting LPE=0 */ +#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 + +/* Supported Rx Buffer Sizes */ +#define IGB_RXBUFFER_128 128 /* Used for packet split */ +#define IGB_RXBUFFER_256 256 /* Used for packet split */ +#define IGB_RXBUFFER_512 512 +#define IGB_RXBUFFER_1024 1024 +#define IGB_RXBUFFER_2048 2048 +#define IGB_RXBUFFER_4096 4096 +#define IGB_RXBUFFER_8192 8192 +#define IGB_RXBUFFER_16384 16384 + +/* Packet Buffer allocations */ + + +/* How many Tx Descriptors do we need to call netif_wake_queue ? */ +#define IGB_TX_QUEUE_WAKE 16 +/* How many Rx Buffers do we bundle into one write to the hardware ? */ +#define IGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */ + +#define AUTO_ALL_MODES 0 +#define IGB_EEPROM_APME 0x0400 + +#ifndef IGB_MASTER_SLAVE +/* Switch to override PHY master/slave setting */ +#define IGB_MASTER_SLAVE e1000_ms_hw_default +#endif + +#define IGB_MNG_VLAN_NONE -1 + +/* wrapper around a pointer to a socket buffer, + * so a DMA handle can be stored along with the buffer */ +struct igb_buffer { + struct sk_buff *skb; + dma_addr_t dma; + union { + /* TX */ + struct { + unsigned long time_stamp; + u32 length; + }; + /* RX */ + struct { + struct page *page; + u64 page_dma; + }; + }; +}; + +struct igb_queue_stats { + u64 packets; + u64 bytes; +}; + +struct igb_ring { + struct igb_adapter *adapter; /* backlink */ + void *desc; /* descriptor ring memory */ + dma_addr_t dma; /* phys address of the ring */ + unsigned int size; /* length of desc. ring in bytes */ + unsigned int count; /* number of desc. in the ring */ + u16 next_to_use; + u16 next_to_clean; + u16 head; + u16 tail; + struct igb_buffer *buffer_info; /* array of buffer info structs */ + + u32 eims_value; + u32 itr_val; + u16 itr_register; + u16 cpu; + + unsigned int total_bytes; + unsigned int total_packets; + + union { + /* TX */ + struct { + spinlock_t tx_clean_lock; + spinlock_t tx_lock; + bool detect_tx_hung; + }; + /* RX */ + struct { + /* arrays of page information for packet split */ + struct sk_buff *pending_skb; + int pending_skb_page; + int no_itr_adjust; + struct igb_queue_stats rx_stats; + struct napi_struct napi; + }; + }; + + char name[IFNAMSIZ + 5]; +}; + +#define IGB_DESC_UNUSED(R) \ + ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ + (R)->next_to_clean - (R)->next_to_use - 1) + +#define E1000_RX_DESC_ADV(R, i) \ + (&(((union e1000_adv_rx_desc *)((R).desc))[i])) +#define E1000_TX_DESC_ADV(R, i) \ + (&(((union e1000_adv_tx_desc *)((R).desc))[i])) +#define E1000_TX_CTXTDESC_ADV(R, i) \ + (&(((struct e1000_adv_tx_context_desc *)((R).desc))[i])) +#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) +#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) +#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) + +/* board specific private data structure */ + +struct igb_adapter { + struct timer_list watchdog_timer; + struct timer_list phy_info_timer; + struct vlan_group *vlgrp; + u16 mng_vlan_id; + u32 bd_number; + u32 rx_buffer_len; + u32 wol; + u32 en_mng_pt; + u16 link_speed; + u16 link_duplex; + unsigned int total_tx_bytes; + unsigned int total_tx_packets; + unsigned int total_rx_bytes; + unsigned int total_rx_packets; + /* Interrupt Throttle Rate */ + u32 itr; + u32 itr_setting; + u16 tx_itr; + u16 rx_itr; + int set_itr; + + struct work_struct reset_task; + struct work_struct watchdog_task; + bool fc_autoneg; + u8 tx_timeout_factor; + struct timer_list blink_timer; + unsigned long led_status; + + /* TX */ + struct igb_ring *tx_ring; /* One per active queue */ + unsigned int restart_queue; + unsigned long tx_queue_len; + u32 txd_cmd; + u32 gotc; + u64 gotc_old; + u64 tpt_old; + u64 colc_old; + u32 tx_timeout_count; + + /* RX */ + struct igb_ring *rx_ring; /* One per active queue */ + int num_tx_queues; + int num_rx_queues; + + u64 hw_csum_err; + u64 hw_csum_good; + u64 rx_hdr_split; + u32 alloc_rx_buff_failed; + bool rx_csum; + u32 gorc; + u64 gorc_old; + u16 rx_ps_hdr_size; + u32 max_frame_size; + u32 min_frame_size; + + /* OS defined structs */ + struct net_device *netdev; + struct napi_struct napi; + struct pci_dev *pdev; + struct net_device_stats net_stats; + + /* structs defined in e1000_hw.h */ + struct e1000_hw hw; + struct e1000_hw_stats stats; + struct e1000_phy_info phy_info; + struct e1000_phy_stats phy_stats; + + u32 test_icr; + struct igb_ring test_tx_ring; + struct igb_ring test_rx_ring; + + int msg_enable; + struct msix_entry *msix_entries; + u32 eims_enable_mask; + + /* to not mess up cache alignment, always add to the bottom */ + unsigned long state; + unsigned int msi_enabled; + + u32 eeprom_wol; +}; + +enum e1000_state_t { + __IGB_TESTING, + __IGB_RESETTING, + __IGB_DOWN +}; + +enum igb_boards { + board_82575, +}; + +extern char igb_driver_name[]; +extern char igb_driver_version[]; + +extern char *igb_get_hw_dev_name(struct e1000_hw *hw); +extern int igb_up(struct igb_adapter *); +extern void igb_down(struct igb_adapter *); +extern void igb_reinit_locked(struct igb_adapter *); +extern void igb_reset(struct igb_adapter *); +extern int igb_set_spd_dplx(struct igb_adapter *, u16); +extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *); +extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *); +extern void igb_update_stats(struct igb_adapter *); +extern void igb_set_ethtool_ops(struct net_device *); + +#endif /* _IGB_H_ */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c new file mode 100644 index 000000000000..f69721e4eaa1 --- /dev/null +++ b/drivers/net/igb/igb_ethtool.c @@ -0,0 +1,1927 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +/* ethtool support for igb */ + +#include <linux/vmalloc.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/if_ether.h> +#include <linux/ethtool.h> + +#include "igb.h" + +struct igb_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define IGB_STAT(m) sizeof(((struct igb_adapter *)0)->m), \ + offsetof(struct igb_adapter, m) +static const struct igb_stats igb_gstrings_stats[] = { + { "rx_packets", IGB_STAT(stats.gprc) }, + { "tx_packets", IGB_STAT(stats.gptc) }, + { "rx_bytes", IGB_STAT(stats.gorc) }, + { "tx_bytes", IGB_STAT(stats.gotc) }, + { "rx_broadcast", IGB_STAT(stats.bprc) }, + { "tx_broadcast", IGB_STAT(stats.bptc) }, + { "rx_multicast", IGB_STAT(stats.mprc) }, + { "tx_multicast", IGB_STAT(stats.mptc) }, + { "rx_errors", IGB_STAT(net_stats.rx_errors) }, + { "tx_errors", IGB_STAT(net_stats.tx_errors) }, + { "tx_dropped", IGB_STAT(net_stats.tx_dropped) }, + { "multicast", IGB_STAT(stats.mprc) }, + { "collisions", IGB_STAT(stats.colc) }, + { "rx_length_errors", IGB_STAT(net_stats.rx_length_errors) }, + { "rx_over_errors", IGB_STAT(net_stats.rx_over_errors) }, + { "rx_crc_errors", IGB_STAT(stats.crcerrs) }, + { "rx_frame_errors", IGB_STAT(net_stats.rx_frame_errors) }, + { "rx_no_buffer_count", IGB_STAT(stats.rnbc) }, + { "rx_missed_errors", IGB_STAT(stats.mpc) }, + { "tx_aborted_errors", IGB_STAT(stats.ecol) }, + { "tx_carrier_errors", IGB_STAT(stats.tncrs) }, + { "tx_fifo_errors", IGB_STAT(net_stats.tx_fifo_errors) }, + { "tx_heartbeat_errors", IGB_STAT(net_stats.tx_heartbeat_errors) }, + { "tx_window_errors", IGB_STAT(stats.latecol) }, + { "tx_abort_late_coll", IGB_STAT(stats.latecol) }, + { "tx_deferred_ok", IGB_STAT(stats.dc) }, + { "tx_single_coll_ok", IGB_STAT(stats.scc) }, + { "tx_multi_coll_ok", IGB_STAT(stats.mcc) }, + { "tx_timeout_count", IGB_STAT(tx_timeout_count) }, + { "tx_restart_queue", IGB_STAT(restart_queue) }, + { "rx_long_length_errors", IGB_STAT(stats.roc) }, + { "rx_short_length_errors", IGB_STAT(stats.ruc) }, + { "rx_align_errors", IGB_STAT(stats.algnerrc) }, + { "tx_tcp_seg_good", IGB_STAT(stats.tsctc) }, + { "tx_tcp_seg_failed", IGB_STAT(stats.tsctfc) }, + { "rx_flow_control_xon", IGB_STAT(stats.xonrxc) }, + { "rx_flow_control_xoff", IGB_STAT(stats.xoffrxc) }, + { "tx_flow_control_xon", IGB_STAT(stats.xontxc) }, + { "tx_flow_control_xoff", IGB_STAT(stats.xofftxc) }, + { "rx_long_byte_count", IGB_STAT(stats.gorc) }, + { "rx_csum_offload_good", IGB_STAT(hw_csum_good) }, + { "rx_csum_offload_errors", IGB_STAT(hw_csum_err) }, + { "rx_header_split", IGB_STAT(rx_hdr_split) }, + { "alloc_rx_buff_failed", IGB_STAT(alloc_rx_buff_failed) }, + { "tx_smbus", IGB_STAT(stats.mgptc) }, + { "rx_smbus", IGB_STAT(stats.mgprc) }, + { "dropped_smbus", IGB_STAT(stats.mgpdc) }, +}; + +#define IGB_QUEUE_STATS_LEN \ + ((((((struct igb_adapter *)netdev->priv)->num_rx_queues > 1) ? \ + ((struct igb_adapter *)netdev->priv)->num_rx_queues : 0) + \ + (((((struct igb_adapter *)netdev->priv)->num_tx_queues > 1) ? \ + ((struct igb_adapter *)netdev->priv)->num_tx_queues : 0))) * \ + (sizeof(struct igb_queue_stats) / sizeof(u64))) +#define IGB_GLOBAL_STATS_LEN \ + sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) +#define IGB_STATS_LEN (IGB_GLOBAL_STATS_LEN + IGB_QUEUE_STATS_LEN) +static const char igb_gstrings_test[][ETH_GSTRING_LEN] = { + "Register test (offline)", "Eeprom test (offline)", + "Interrupt test (offline)", "Loopback test (offline)", + "Link test (on/offline)" +}; +#define IGB_TEST_LEN sizeof(igb_gstrings_test) / ETH_GSTRING_LEN + +static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (hw->phy.media_type == e1000_media_type_copper) { + + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full| + SUPPORTED_Autoneg | + SUPPORTED_TP); + ecmd->advertising = ADVERTISED_TP; + + if (hw->mac.autoneg == 1) { + ecmd->advertising |= ADVERTISED_Autoneg; + /* the e1000 autoneg seems to match ethtool nicely */ + ecmd->advertising |= hw->phy.autoneg_advertised; + } + + ecmd->port = PORT_TP; + ecmd->phy_address = hw->phy.addr; + } else { + ecmd->supported = (SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg); + + ecmd->advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg); + + ecmd->port = PORT_FIBRE; + } + + ecmd->transceiver = XCVR_INTERNAL; + + if (rd32(E1000_STATUS) & E1000_STATUS_LU) { + + adapter->hw.mac.ops.get_speed_and_duplex(hw, + &adapter->link_speed, + &adapter->link_duplex); + ecmd->speed = adapter->link_speed; + + /* unfortunately FULL_DUPLEX != DUPLEX_FULL + * and HALF_DUPLEX != DUPLEX_HALF */ + + if (adapter->link_duplex == FULL_DUPLEX) + ecmd->duplex = DUPLEX_FULL; + else + ecmd->duplex = DUPLEX_HALF; + } else { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) || + hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + return 0; +} + +static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + /* When SoL/IDER sessions are active, autoneg/speed/duplex + * cannot be changed */ + if (igb_check_reset_block(hw)) { + dev_err(&adapter->pdev->dev, "Cannot change link " + "characteristics when SoL/IDER is active.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) + msleep(1); + + if (ecmd->autoneg == AUTONEG_ENABLE) { + hw->mac.autoneg = 1; + if (hw->phy.media_type == e1000_media_type_fiber) + hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full | + ADVERTISED_FIBRE | + ADVERTISED_Autoneg; + else + hw->phy.autoneg_advertised = ecmd->advertising | + ADVERTISED_TP | + ADVERTISED_Autoneg; + ecmd->advertising = hw->phy.autoneg_advertised; + } else + if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { + clear_bit(__IGB_RESETTING, &adapter->state); + return -EINVAL; + } + + /* reset the link */ + + if (netif_running(adapter->netdev)) { + igb_down(adapter); + igb_up(adapter); + } else + igb_reset(adapter); + + clear_bit(__IGB_RESETTING, &adapter->state); + return 0; +} + +static void igb_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + pause->autoneg = + (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); + + if (hw->fc.type == e1000_fc_rx_pause) + pause->rx_pause = 1; + else if (hw->fc.type == e1000_fc_tx_pause) + pause->tx_pause = 1; + else if (hw->fc.type == e1000_fc_full) { + pause->rx_pause = 1; + pause->tx_pause = 1; + } +} + +static int igb_set_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int retval = 0; + + adapter->fc_autoneg = pause->autoneg; + + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) + msleep(1); + + if (pause->rx_pause && pause->tx_pause) + hw->fc.type = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.type = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.type = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.type = e1000_fc_none; + + hw->fc.original_type = hw->fc.type; + + if (adapter->fc_autoneg == AUTONEG_ENABLE) { + if (netif_running(adapter->netdev)) { + igb_down(adapter); + igb_up(adapter); + } else + igb_reset(adapter); + } else + retval = ((hw->phy.media_type == e1000_media_type_fiber) ? + igb_setup_link(hw) : igb_force_mac_fc(hw)); + + clear_bit(__IGB_RESETTING, &adapter->state); + return retval; +} + +static u32 igb_get_rx_csum(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + return adapter->rx_csum; +} + +static int igb_set_rx_csum(struct net_device *netdev, u32 data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + adapter->rx_csum = data; + + return 0; +} + +static u32 igb_get_tx_csum(struct net_device *netdev) +{ + return (netdev->features & NETIF_F_HW_CSUM) != 0; +} + +static int igb_set_tx_csum(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_HW_CSUM; + else + netdev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} + +static int igb_set_tso(struct net_device *netdev, u32 data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + if (data) + netdev->features |= NETIF_F_TSO; + else + netdev->features &= ~NETIF_F_TSO; + + if (data) + netdev->features |= NETIF_F_TSO6; + else + netdev->features &= ~NETIF_F_TSO6; + + dev_info(&adapter->pdev->dev, "TSO is %s\n", + data ? "Enabled" : "Disabled"); + return 0; +} + +static u32 igb_get_msglevel(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + return adapter->msg_enable; +} + +static void igb_set_msglevel(struct net_device *netdev, u32 data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + adapter->msg_enable = data; +} + +static int igb_get_regs_len(struct net_device *netdev) +{ +#define IGB_REGS_LEN 551 + return IGB_REGS_LEN * sizeof(u32); +} + +static void igb_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 *regs_buff = p; + u8 i; + + memset(p, 0, IGB_REGS_LEN * sizeof(u32)); + + regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; + + /* General Registers */ + regs_buff[0] = rd32(E1000_CTRL); + regs_buff[1] = rd32(E1000_STATUS); + regs_buff[2] = rd32(E1000_CTRL_EXT); + regs_buff[3] = rd32(E1000_MDIC); + regs_buff[4] = rd32(E1000_SCTL); + regs_buff[5] = rd32(E1000_CONNSW); + regs_buff[6] = rd32(E1000_VET); + regs_buff[7] = rd32(E1000_LEDCTL); + regs_buff[8] = rd32(E1000_PBA); + regs_buff[9] = rd32(E1000_PBS); + regs_buff[10] = rd32(E1000_FRTIMER); + regs_buff[11] = rd32(E1000_TCPTIMER); + + /* NVM Register */ + regs_buff[12] = rd32(E1000_EECD); + + /* Interrupt */ + regs_buff[13] = rd32(E1000_EICR); + regs_buff[14] = rd32(E1000_EICS); + regs_buff[15] = rd32(E1000_EIMS); + regs_buff[16] = rd32(E1000_EIMC); + regs_buff[17] = rd32(E1000_EIAC); + regs_buff[18] = rd32(E1000_EIAM); + regs_buff[19] = rd32(E1000_ICR); + regs_buff[20] = rd32(E1000_ICS); + regs_buff[21] = rd32(E1000_IMS); + regs_buff[22] = rd32(E1000_IMC); + regs_buff[23] = rd32(E1000_IAC); + regs_buff[24] = rd32(E1000_IAM); + regs_buff[25] = rd32(E1000_IMIRVP); + + /* Flow Control */ + regs_buff[26] = rd32(E1000_FCAL); + regs_buff[27] = rd32(E1000_FCAH); + regs_buff[28] = rd32(E1000_FCTTV); + regs_buff[29] = rd32(E1000_FCRTL); + regs_buff[30] = rd32(E1000_FCRTH); + regs_buff[31] = rd32(E1000_FCRTV); + + /* Receive */ + regs_buff[32] = rd32(E1000_RCTL); + regs_buff[33] = rd32(E1000_RXCSUM); + regs_buff[34] = rd32(E1000_RLPML); + regs_buff[35] = rd32(E1000_RFCTL); + regs_buff[36] = rd32(E1000_MRQC); + regs_buff[37] = rd32(E1000_VMD_CTL); + + /* Transmit */ + regs_buff[38] = rd32(E1000_TCTL); + regs_buff[39] = rd32(E1000_TCTL_EXT); + regs_buff[40] = rd32(E1000_TIPG); + regs_buff[41] = rd32(E1000_DTXCTL); + + /* Wake Up */ + regs_buff[42] = rd32(E1000_WUC); + regs_buff[43] = rd32(E1000_WUFC); + regs_buff[44] = rd32(E1000_WUS); + regs_buff[45] = rd32(E1000_IPAV); + regs_buff[46] = rd32(E1000_WUPL); + + /* MAC */ + regs_buff[47] = rd32(E1000_PCS_CFG0); + regs_buff[48] = rd32(E1000_PCS_LCTL); + regs_buff[49] = rd32(E1000_PCS_LSTAT); + regs_buff[50] = rd32(E1000_PCS_ANADV); + regs_buff[51] = rd32(E1000_PCS_LPAB); + regs_buff[52] = rd32(E1000_PCS_NPTX); + regs_buff[53] = rd32(E1000_PCS_LPABNP); + + /* Statistics */ + regs_buff[54] = adapter->stats.crcerrs; + regs_buff[55] = adapter->stats.algnerrc; + regs_buff[56] = adapter->stats.symerrs; + regs_buff[57] = adapter->stats.rxerrc; + regs_buff[58] = adapter->stats.mpc; + regs_buff[59] = adapter->stats.scc; + regs_buff[60] = adapter->stats.ecol; + regs_buff[61] = adapter->stats.mcc; + regs_buff[62] = adapter->stats.latecol; + regs_buff[63] = adapter->stats.colc; + regs_buff[64] = adapter->stats.dc; + regs_buff[65] = adapter->stats.tncrs; + regs_buff[66] = adapter->stats.sec; + regs_buff[67] = adapter->stats.htdpmc; + regs_buff[68] = adapter->stats.rlec; + regs_buff[69] = adapter->stats.xonrxc; + regs_buff[70] = adapter->stats.xontxc; + regs_buff[71] = adapter->stats.xoffrxc; + regs_buff[72] = adapter->stats.xofftxc; + regs_buff[73] = adapter->stats.fcruc; + regs_buff[74] = adapter->stats.prc64; + regs_buff[75] = adapter->stats.prc127; + regs_buff[76] = adapter->stats.prc255; + regs_buff[77] = adapter->stats.prc511; + regs_buff[78] = adapter->stats.prc1023; + regs_buff[79] = adapter->stats.prc1522; + regs_buff[80] = adapter->stats.gprc; + regs_buff[81] = adapter->stats.bprc; + regs_buff[82] = adapter->stats.mprc; + regs_buff[83] = adapter->stats.gptc; + regs_buff[84] = adapter->stats.gorc; + regs_buff[86] = adapter->stats.gotc; + regs_buff[88] = adapter->stats.rnbc; + regs_buff[89] = adapter->stats.ruc; + regs_buff[90] = adapter->stats.rfc; + regs_buff[91] = adapter->stats.roc; + regs_buff[92] = adapter->stats.rjc; + regs_buff[93] = adapter->stats.mgprc; + regs_buff[94] = adapter->stats.mgpdc; + regs_buff[95] = adapter->stats.mgptc; + regs_buff[96] = adapter->stats.tor; + regs_buff[98] = adapter->stats.tot; + regs_buff[100] = adapter->stats.tpr; + regs_buff[101] = adapter->stats.tpt; + regs_buff[102] = adapter->stats.ptc64; + regs_buff[103] = adapter->stats.ptc127; + regs_buff[104] = adapter->stats.ptc255; + regs_buff[105] = adapter->stats.ptc511; + regs_buff[106] = adapter->stats.ptc1023; + regs_buff[107] = adapter->stats.ptc1522; + regs_buff[108] = adapter->stats.mptc; + regs_buff[109] = adapter->stats.bptc; + regs_buff[110] = adapter->stats.tsctc; + regs_buff[111] = adapter->stats.iac; + regs_buff[112] = adapter->stats.rpthc; + regs_buff[113] = adapter->stats.hgptc; + regs_buff[114] = adapter->stats.hgorc; + regs_buff[116] = adapter->stats.hgotc; + regs_buff[118] = adapter->stats.lenerrs; + regs_buff[119] = adapter->stats.scvpc; + regs_buff[120] = adapter->stats.hrmpc; + + /* These should probably be added to e1000_regs.h instead */ + #define E1000_PSRTYPE_REG(_i) (0x05480 + ((_i) * 4)) + #define E1000_RAL(_i) (0x05400 + ((_i) * 8)) + #define E1000_RAH(_i) (0x05404 + ((_i) * 8)) + #define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) + #define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) + #define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) + #define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8)) + #define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8)) + #define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8)) + + for (i = 0; i < 4; i++) + regs_buff[121 + i] = rd32(E1000_SRRCTL(i)); + for (i = 0; i < 4; i++) + regs_buff[125 + i] = rd32(E1000_PSRTYPE_REG(i)); + for (i = 0; i < 4; i++) + regs_buff[129 + i] = rd32(E1000_RDBAL(i)); + for (i = 0; i < 4; i++) + regs_buff[133 + i] = rd32(E1000_RDBAH(i)); + for (i = 0; i < 4; i++) + regs_buff[137 + i] = rd32(E1000_RDLEN(i)); + for (i = 0; i < 4; i++) + regs_buff[141 + i] = rd32(E1000_RDH(i)); + for (i = 0; i < 4; i++) + regs_buff[145 + i] = rd32(E1000_RDT(i)); + for (i = 0; i < 4; i++) + regs_buff[149 + i] = rd32(E1000_RXDCTL(i)); + + for (i = 0; i < 10; i++) + regs_buff[153 + i] = rd32(E1000_EITR(i)); + for (i = 0; i < 8; i++) + regs_buff[163 + i] = rd32(E1000_IMIR(i)); + for (i = 0; i < 8; i++) + regs_buff[171 + i] = rd32(E1000_IMIREXT(i)); + for (i = 0; i < 16; i++) + regs_buff[179 + i] = rd32(E1000_RAL(i)); + for (i = 0; i < 16; i++) + regs_buff[195 + i] = rd32(E1000_RAH(i)); + + for (i = 0; i < 4; i++) + regs_buff[211 + i] = rd32(E1000_TDBAL(i)); + for (i = 0; i < 4; i++) + regs_buff[215 + i] = rd32(E1000_TDBAH(i)); + for (i = 0; i < 4; i++) + regs_buff[219 + i] = rd32(E1000_TDLEN(i)); + for (i = 0; i < 4; i++) + regs_buff[223 + i] = rd32(E1000_TDH(i)); + for (i = 0; i < 4; i++) + regs_buff[227 + i] = rd32(E1000_TDT(i)); + for (i = 0; i < 4; i++) + regs_buff[231 + i] = rd32(E1000_TXDCTL(i)); + for (i = 0; i < 4; i++) + regs_buff[235 + i] = rd32(E1000_TDWBAL(i)); + for (i = 0; i < 4; i++) + regs_buff[239 + i] = rd32(E1000_TDWBAH(i)); + for (i = 0; i < 4; i++) + regs_buff[243 + i] = rd32(E1000_DCA_TXCTRL(i)); + + for (i = 0; i < 4; i++) + regs_buff[247 + i] = rd32(E1000_IP4AT_REG(i)); + for (i = 0; i < 4; i++) + regs_buff[251 + i] = rd32(E1000_IP6AT_REG(i)); + for (i = 0; i < 32; i++) + regs_buff[255 + i] = rd32(E1000_WUPM_REG(i)); + for (i = 0; i < 128; i++) + regs_buff[287 + i] = rd32(E1000_FFMT_REG(i)); + for (i = 0; i < 128; i++) + regs_buff[415 + i] = rd32(E1000_FFVT_REG(i)); + for (i = 0; i < 4; i++) + regs_buff[543 + i] = rd32(E1000_FFLT_REG(i)); + + regs_buff[547] = rd32(E1000_TDFH); + regs_buff[548] = rd32(E1000_TDFT); + regs_buff[549] = rd32(E1000_TDFHS); + regs_buff[550] = rd32(E1000_TDFPC); + +} + +static int igb_get_eeprom_len(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + return adapter->hw.nvm.word_size * 2; +} + +static int igb_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + int first_word, last_word; + int ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EINVAL; + + eeprom->magic = hw->vendor_id | (hw->device_id << 16); + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + + eeprom_buff = kmalloc(sizeof(u16) * + (last_word - first_word + 1), GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + if (hw->nvm.type == e1000_nvm_eeprom_spi) + ret_val = hw->nvm.ops.read_nvm(hw, first_word, + last_word - first_word + 1, + eeprom_buff); + else { + for (i = 0; i < last_word - first_word + 1; i++) { + ret_val = hw->nvm.ops.read_nvm(hw, first_word + i, 1, + &eeprom_buff[i]); + if (ret_val) + break; + } + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), + eeprom->len); + kfree(eeprom_buff); + + return ret_val; +} + +static int igb_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *eeprom, u8 *bytes) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u16 *eeprom_buff; + void *ptr; + int max_len, first_word, last_word, ret_val = 0; + u16 i; + + if (eeprom->len == 0) + return -EOPNOTSUPP; + + if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) + return -EFAULT; + + max_len = hw->nvm.word_size * 2; + + first_word = eeprom->offset >> 1; + last_word = (eeprom->offset + eeprom->len - 1) >> 1; + eeprom_buff = kmalloc(max_len, GFP_KERNEL); + if (!eeprom_buff) + return -ENOMEM; + + ptr = (void *)eeprom_buff; + + if (eeprom->offset & 1) { + /* need read/modify/write of first changed EEPROM word */ + /* only the second byte of the word is being modified */ + ret_val = hw->nvm.ops.read_nvm(hw, first_word, 1, + &eeprom_buff[0]); + ptr++; + } + if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) { + /* need read/modify/write of last changed EEPROM word */ + /* only the first byte of the word is being modified */ + ret_val = hw->nvm.ops.read_nvm(hw, last_word, 1, + &eeprom_buff[last_word - first_word]); + } + + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + + memcpy(ptr, bytes, eeprom->len); + + for (i = 0; i < last_word - first_word + 1; i++) + eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); + + ret_val = hw->nvm.ops.write_nvm(hw, first_word, + last_word - first_word + 1, eeprom_buff); + + /* Update the checksum over the first part of the EEPROM if needed + * and flush shadow RAM for 82573 controllers */ + if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG))) + igb_update_nvm_checksum(hw); + + kfree(eeprom_buff); + return ret_val; +} + +static void igb_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + char firmware_version[32]; + u16 eeprom_data; + + strncpy(drvinfo->driver, igb_driver_name, 32); + strncpy(drvinfo->version, igb_driver_version, 32); + + /* EEPROM image version # is reported as firmware version # for + * 82575 controllers */ + adapter->hw.nvm.ops.read_nvm(&adapter->hw, 5, 1, &eeprom_data); + sprintf(firmware_version, "%d.%d-%d", + (eeprom_data & 0xF000) >> 12, + (eeprom_data & 0x0FF0) >> 4, + eeprom_data & 0x000F); + + strncpy(drvinfo->fw_version, firmware_version, 32); + strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); + drvinfo->n_stats = IGB_STATS_LEN; + drvinfo->testinfo_len = IGB_TEST_LEN; + drvinfo->regdump_len = igb_get_regs_len(netdev); + drvinfo->eedump_len = igb_get_eeprom_len(netdev); +} + +static void igb_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct igb_ring *tx_ring = adapter->tx_ring; + struct igb_ring *rx_ring = adapter->rx_ring; + + ring->rx_max_pending = IGB_MAX_RXD; + ring->tx_max_pending = IGB_MAX_TXD; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->rx_pending = rx_ring->count; + ring->tx_pending = tx_ring->count; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; +} + +static int igb_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ring) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct igb_buffer *old_buf; + struct igb_buffer *old_rx_buf; + void *old_desc; + int i, err; + u32 new_rx_count, new_tx_count, old_size; + dma_addr_t old_dma; + + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + + new_rx_count = max(ring->rx_pending, (u32)IGB_MIN_RXD); + new_rx_count = min(new_rx_count, (u32)IGB_MAX_RXD); + new_rx_count = ALIGN(new_rx_count, REQ_RX_DESCRIPTOR_MULTIPLE); + + new_tx_count = max(ring->tx_pending, (u32)IGB_MIN_TXD); + new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD); + new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); + + if ((new_tx_count == adapter->tx_ring->count) && + (new_rx_count == adapter->rx_ring->count)) { + /* nothing to do */ + return 0; + } + + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(adapter->netdev)) + igb_down(adapter); + + /* + * We can't just free everything and then setup again, + * because the ISRs in MSI-X mode get passed pointers + * to the tx and rx ring structs. + */ + if (new_tx_count != adapter->tx_ring->count) { + for (i = 0; i < adapter->num_tx_queues; i++) { + /* Save existing descriptor ring */ + old_buf = adapter->tx_ring[i].buffer_info; + old_desc = adapter->tx_ring[i].desc; + old_size = adapter->tx_ring[i].size; + old_dma = adapter->tx_ring[i].dma; + /* Try to allocate a new one */ + adapter->tx_ring[i].buffer_info = NULL; + adapter->tx_ring[i].desc = NULL; + adapter->tx_ring[i].count = new_tx_count; + err = igb_setup_tx_resources(adapter, + &adapter->tx_ring[i]); + if (err) { + /* Restore the old one so at least + the adapter still works, even if + we failed the request */ + adapter->tx_ring[i].buffer_info = old_buf; + adapter->tx_ring[i].desc = old_desc; + adapter->tx_ring[i].size = old_size; + adapter->tx_ring[i].dma = old_dma; + goto err_setup; + } + /* Free the old buffer manually */ + vfree(old_buf); + pci_free_consistent(adapter->pdev, old_size, + old_desc, old_dma); + } + } + + if (new_rx_count != adapter->rx_ring->count) { + for (i = 0; i < adapter->num_rx_queues; i++) { + + old_rx_buf = adapter->rx_ring[i].buffer_info; + old_desc = adapter->rx_ring[i].desc; + old_size = adapter->rx_ring[i].size; + old_dma = adapter->rx_ring[i].dma; + + adapter->rx_ring[i].buffer_info = NULL; + adapter->rx_ring[i].desc = NULL; + adapter->rx_ring[i].dma = 0; + adapter->rx_ring[i].count = new_rx_count; + err = igb_setup_rx_resources(adapter, + &adapter->rx_ring[i]); + if (err) { + adapter->rx_ring[i].buffer_info = old_rx_buf; + adapter->rx_ring[i].desc = old_desc; + adapter->rx_ring[i].size = old_size; + adapter->rx_ring[i].dma = old_dma; + goto err_setup; + } + + vfree(old_rx_buf); + pci_free_consistent(adapter->pdev, old_size, old_desc, + old_dma); + } + } + + err = 0; +err_setup: + if (netif_running(adapter->netdev)) + igb_up(adapter); + + clear_bit(__IGB_RESETTING, &adapter->state); + return err; +} + +/* ethtool register test data */ +struct igb_reg_test { + u16 reg; + u8 array_len; + u8 test_type; + u32 mask; + u32 write; +}; + +/* In the hardware, registers are laid out either singly, in arrays + * spaced 0x100 bytes apart, or in contiguous tables. We assume + * most tests take place on arrays or single registers (handled + * as a single-element array) and special-case the tables. + * Table tests are always pattern tests. + * + * We also make provision for some required setup steps by specifying + * registers to be written without any read-back testing. + */ + +#define PATTERN_TEST 1 +#define SET_READ_TEST 2 +#define WRITE_NO_TEST 3 +#define TABLE32_TEST 4 +#define TABLE64_TEST_LO 5 +#define TABLE64_TEST_HI 6 + +/* default register test */ +static struct igb_reg_test reg_test_82575[] = { + { E1000_FCAL, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_FCAH, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_FCT, 1, PATTERN_TEST, 0x0000FFFF, 0xFFFFFFFF }, + { E1000_VET, 1, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_RDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + /* Enable all four RX queues before testing. */ + { E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, E1000_RXDCTL_QUEUE_ENABLE }, + /* RDH is read-only for 82575, only test RDT. */ + { E1000_RDT(0), 4, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_RXDCTL(0), 4, WRITE_NO_TEST, 0, 0 }, + { E1000_FCRTH, 1, PATTERN_TEST, 0x0000FFF0, 0x0000FFF0 }, + { E1000_FCTTV, 1, PATTERN_TEST, 0x0000FFFF, 0x0000FFFF }, + { E1000_TIPG, 1, PATTERN_TEST, 0x3FFFFFFF, 0x3FFFFFFF }, + { E1000_TDBAL(0), 4, PATTERN_TEST, 0xFFFFFF80, 0xFFFFFFFF }, + { E1000_TDBAH(0), 4, PATTERN_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_TDLEN(0), 4, PATTERN_TEST, 0x000FFF80, 0x000FFFFF }, + { E1000_RCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0x003FFFFB }, + { E1000_RCTL, 1, SET_READ_TEST, 0x04CFB3FE, 0xFFFFFFFF }, + { E1000_TCTL, 1, SET_READ_TEST, 0xFFFFFFFF, 0x00000000 }, + { E1000_TXCW, 1, PATTERN_TEST, 0xC000FFFF, 0x0000FFFF }, + { E1000_RA, 16, TABLE64_TEST_LO, 0xFFFFFFFF, 0xFFFFFFFF }, + { E1000_RA, 16, TABLE64_TEST_HI, 0x800FFFFF, 0xFFFFFFFF }, + { E1000_MTA, 128, TABLE32_TEST, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0, 0, 0, 0 } +}; + +static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data, + int reg, u32 mask, u32 write) +{ + u32 pat, val; + u32 _test[] = + {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + for (pat = 0; pat < ARRAY_SIZE(_test); pat++) { + writel((_test[pat] & write), (adapter->hw.hw_addr + reg)); + val = readl(adapter->hw.hw_addr + reg); + if (val != (_test[pat] & write & mask)) { + dev_err(&adapter->pdev->dev, "pattern test reg %04X " + "failed: got 0x%08X expected 0x%08X\n", + reg, val, (_test[pat] & write & mask)); + *data = reg; + return 1; + } + } + return 0; +} + +static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data, + int reg, u32 mask, u32 write) +{ + u32 val; + writel((write & mask), (adapter->hw.hw_addr + reg)); + val = readl(adapter->hw.hw_addr + reg); + if ((write & mask) != (val & mask)) { + dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:" + " got 0x%08X expected 0x%08X\n", reg, + (val & mask), (write & mask)); + *data = reg; + return 1; + } + return 0; +} + +#define REG_PATTERN_TEST(reg, mask, write) \ + do { \ + if (reg_pattern_test(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) + +#define REG_SET_AND_CHECK(reg, mask, write) \ + do { \ + if (reg_set_and_check(adapter, data, reg, mask, write)) \ + return 1; \ + } while (0) + +static int igb_reg_test(struct igb_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + struct igb_reg_test *test; + u32 value, before, after; + u32 i, toggle; + + toggle = 0x7FFFF3FF; + test = reg_test_82575; + + /* Because the status register is such a special case, + * we handle it separately from the rest of the register + * tests. Some bits are read-only, some toggle, and some + * are writable on newer MACs. + */ + before = rd32(E1000_STATUS); + value = (rd32(E1000_STATUS) & toggle); + wr32(E1000_STATUS, toggle); + after = rd32(E1000_STATUS) & toggle; + if (value != after) { + dev_err(&adapter->pdev->dev, "failed STATUS register test " + "got: 0x%08X expected: 0x%08X\n", after, value); + *data = 1; + return 1; + } + /* restore previous status */ + wr32(E1000_STATUS, before); + + /* Perform the remainder of the register test, looping through + * the test table until we either fail or reach the null entry. + */ + while (test->reg) { + for (i = 0; i < test->array_len; i++) { + switch (test->test_type) { + case PATTERN_TEST: + REG_PATTERN_TEST(test->reg + (i * 0x100), + test->mask, + test->write); + break; + case SET_READ_TEST: + REG_SET_AND_CHECK(test->reg + (i * 0x100), + test->mask, + test->write); + break; + case WRITE_NO_TEST: + writel(test->write, + (adapter->hw.hw_addr + test->reg) + + (i * 0x100)); + break; + case TABLE32_TEST: + REG_PATTERN_TEST(test->reg + (i * 4), + test->mask, + test->write); + break; + case TABLE64_TEST_LO: + REG_PATTERN_TEST(test->reg + (i * 8), + test->mask, + test->write); + break; + case TABLE64_TEST_HI: + REG_PATTERN_TEST((test->reg + 4) + (i * 8), + test->mask, + test->write); + break; + } + } + test++; + } + + *data = 0; + return 0; +} + +static int igb_eeprom_test(struct igb_adapter *adapter, u64 *data) +{ + u16 temp; + u16 checksum = 0; + u16 i; + + *data = 0; + /* Read and add up the contents of the EEPROM */ + for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { + if ((adapter->hw.nvm.ops.read_nvm(&adapter->hw, i, 1, &temp)) + < 0) { + *data = 1; + break; + } + checksum += temp; + } + + /* If Checksum is not Correct return error else test passed */ + if ((checksum != (u16) NVM_SUM) && !(*data)) + *data = 2; + + return *data; +} + +static irqreturn_t igb_test_intr(int irq, void *data) +{ + struct net_device *netdev = (struct net_device *) data; + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + adapter->test_icr |= rd32(E1000_ICR); + + return IRQ_HANDLED; +} + +static int igb_intr_test(struct igb_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 mask, i = 0, shared_int = true; + u32 irq = adapter->pdev->irq; + + *data = 0; + + /* Hook up test interrupt handler just for this test */ + if (adapter->msix_entries) { + /* NOTE: we don't test MSI-X interrupts here, yet */ + return 0; + } else if (adapter->msi_enabled) { + shared_int = false; + if (request_irq(irq, &igb_test_intr, 0, netdev->name, netdev)) { + *data = 1; + return -1; + } + } else if (!request_irq(irq, &igb_test_intr, IRQF_PROBE_SHARED, + netdev->name, netdev)) { + shared_int = false; + } else if (request_irq(irq, &igb_test_intr, IRQF_SHARED, + netdev->name, netdev)) { + *data = 1; + return -1; + } + dev_info(&adapter->pdev->dev, "testing %s interrupt\n", + (shared_int ? "shared" : "unshared")); + + /* Disable all the interrupts */ + wr32(E1000_IMC, 0xFFFFFFFF); + msleep(10); + + /* Test each interrupt */ + for (; i < 10; i++) { + /* Interrupt to test */ + mask = 1 << i; + + if (!shared_int) { + /* Disable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + wr32(E1000_IMC, ~mask & 0x00007FFF); + wr32(E1000_ICS, ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr & mask) { + *data = 3; + break; + } + } + + /* Enable the interrupt to be reported in + * the cause register and then force the same + * interrupt and see if one gets posted. If + * an interrupt was not posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + wr32(E1000_IMS, mask); + wr32(E1000_ICS, mask); + msleep(10); + + if (!(adapter->test_icr & mask)) { + *data = 4; + break; + } + + if (!shared_int) { + /* Disable the other interrupts to be reported in + * the cause register and then force the other + * interrupts and see if any get posted. If + * an interrupt was posted to the bus, the + * test failed. + */ + adapter->test_icr = 0; + wr32(E1000_IMC, ~mask & 0x00007FFF); + wr32(E1000_ICS, ~mask & 0x00007FFF); + msleep(10); + + if (adapter->test_icr) { + *data = 5; + break; + } + } + } + + /* Disable all the interrupts */ + wr32(E1000_IMC, 0xFFFFFFFF); + msleep(10); + + /* Unhook test interrupt handler */ + free_irq(irq, netdev); + + return *data; +} + +static void igb_free_desc_rings(struct igb_adapter *adapter) +{ + struct igb_ring *tx_ring = &adapter->test_tx_ring; + struct igb_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i; + + if (tx_ring->desc && tx_ring->buffer_info) { + for (i = 0; i < tx_ring->count; i++) { + struct igb_buffer *buf = &(tx_ring->buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, buf->length, + PCI_DMA_TODEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (rx_ring->desc && rx_ring->buffer_info) { + for (i = 0; i < rx_ring->count; i++) { + struct igb_buffer *buf = &(rx_ring->buffer_info[i]); + if (buf->dma) + pci_unmap_single(pdev, buf->dma, + IGB_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + if (buf->skb) + dev_kfree_skb(buf->skb); + } + } + + if (tx_ring->desc) { + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, + tx_ring->dma); + tx_ring->desc = NULL; + } + if (rx_ring->desc) { + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, + rx_ring->dma); + rx_ring->desc = NULL; + } + + kfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + kfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; + + return; +} + +static int igb_setup_desc_rings(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct igb_ring *tx_ring = &adapter->test_tx_ring; + struct igb_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + u32 rctl; + int i, ret_val; + + /* Setup Tx descriptor ring and Tx buffers */ + + if (!tx_ring->count) + tx_ring->count = IGB_DEFAULT_TXD; + + tx_ring->buffer_info = kcalloc(tx_ring->count, + sizeof(struct igb_buffer), + GFP_KERNEL); + if (!tx_ring->buffer_info) { + ret_val = 1; + goto err_nomem; + } + + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); + tx_ring->size = ALIGN(tx_ring->size, 4096); + tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma); + if (!tx_ring->desc) { + ret_val = 2; + goto err_nomem; + } + tx_ring->next_to_use = tx_ring->next_to_clean = 0; + + wr32(E1000_TDBAL(0), + ((u64) tx_ring->dma & 0x00000000FFFFFFFF)); + wr32(E1000_TDBAH(0), ((u64) tx_ring->dma >> 32)); + wr32(E1000_TDLEN(0), + tx_ring->count * sizeof(struct e1000_tx_desc)); + wr32(E1000_TDH(0), 0); + wr32(E1000_TDT(0), 0); + wr32(E1000_TCTL, + E1000_TCTL_PSP | E1000_TCTL_EN | + E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT | + E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); + + for (i = 0; i < tx_ring->count; i++) { + struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i); + struct sk_buff *skb; + unsigned int size = 1024; + + skb = alloc_skb(size, GFP_KERNEL); + if (!skb) { + ret_val = 3; + goto err_nomem; + } + skb_put(skb, size); + tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[i].length = skb->len; + tx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); + tx_desc->lower.data = cpu_to_le32(skb->len); + tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP | + E1000_TXD_CMD_IFCS | + E1000_TXD_CMD_RS); + tx_desc->upper.data = 0; + } + + /* Setup Rx descriptor ring and Rx buffers */ + + if (!rx_ring->count) + rx_ring->count = IGB_DEFAULT_RXD; + + rx_ring->buffer_info = kcalloc(rx_ring->count, + sizeof(struct igb_buffer), + GFP_KERNEL); + if (!rx_ring->buffer_info) { + ret_val = 4; + goto err_nomem; + } + + rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc); + rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, + &rx_ring->dma); + if (!rx_ring->desc) { + ret_val = 5; + goto err_nomem; + } + rx_ring->next_to_use = rx_ring->next_to_clean = 0; + + rctl = rd32(E1000_RCTL); + wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN); + wr32(E1000_RDBAL(0), + ((u64) rx_ring->dma & 0xFFFFFFFF)); + wr32(E1000_RDBAH(0), + ((u64) rx_ring->dma >> 32)); + wr32(E1000_RDLEN(0), rx_ring->size); + wr32(E1000_RDH(0), 0); + wr32(E1000_RDT(0), 0); + rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + wr32(E1000_RCTL, rctl); + wr32(E1000_SRRCTL(0), 0); + + for (i = 0; i < rx_ring->count; i++) { + struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i); + struct sk_buff *skb; + + skb = alloc_skb(IGB_RXBUFFER_2048 + NET_IP_ALIGN, + GFP_KERNEL); + if (!skb) { + ret_val = 6; + goto err_nomem; + } + skb_reserve(skb, NET_IP_ALIGN); + rx_ring->buffer_info[i].skb = skb; + rx_ring->buffer_info[i].dma = + pci_map_single(pdev, skb->data, IGB_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); + memset(skb->data, 0x00, skb->len); + } + + return 0; + +err_nomem: + igb_free_desc_rings(adapter); + return ret_val; +} + +static void igb_phy_disable_receiver(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + /* Write out to PHY registers 29 and 30 to disable the Receiver. */ + hw->phy.ops.write_phy_reg(hw, 29, 0x001F); + hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC); + hw->phy.ops.write_phy_reg(hw, 29, 0x001A); + hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0); +} + +static int igb_integrated_phy_loopback(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_reg = 0; + u32 stat_reg = 0; + + hw->mac.autoneg = false; + + if (hw->phy.type == e1000_phy_m88) { + /* Auto-MDI/MDIX Off */ + hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); + /* reset to update Auto-MDI/MDIX */ + hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140); + /* autoneg off */ + hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140); + } + + ctrl_reg = rd32(E1000_CTRL); + + /* force 1000, set loopback */ + hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140); + + /* Now set up the MAC to the same speed/duplex as the PHY. */ + ctrl_reg = rd32(E1000_CTRL); + ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */ + ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */ + E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */ + E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */ + E1000_CTRL_FD); /* Force Duplex to FULL */ + + if (hw->phy.media_type == e1000_media_type_copper && + hw->phy.type == e1000_phy_m88) + ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */ + else { + /* Set the ILOS bit on the fiber Nic if half duplex link is + * detected. */ + stat_reg = rd32(E1000_STATUS); + if ((stat_reg & E1000_STATUS_FD) == 0) + ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU); + } + + wr32(E1000_CTRL, ctrl_reg); + + /* Disable the receiver on the PHY so when a cable is plugged in, the + * PHY does not begin to autoneg when a cable is reconnected to the NIC. + */ + if (hw->phy.type == e1000_phy_m88) + igb_phy_disable_receiver(adapter); + + udelay(500); + + return 0; +} + +static int igb_set_phy_loopback(struct igb_adapter *adapter) +{ + return igb_integrated_phy_loopback(adapter); +} + +static int igb_setup_loopback_test(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + + if (hw->phy.media_type == e1000_media_type_fiber || + hw->phy.media_type == e1000_media_type_internal_serdes) { + rctl = rd32(E1000_RCTL); + rctl |= E1000_RCTL_LBM_TCVR; + wr32(E1000_RCTL, rctl); + return 0; + } else if (hw->phy.media_type == e1000_media_type_copper) { + return igb_set_phy_loopback(adapter); + } + + return 7; +} + +static void igb_loopback_cleanup(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + u16 phy_reg; + + rctl = rd32(E1000_RCTL); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); + wr32(E1000_RCTL, rctl); + + hw->mac.autoneg = true; + hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg); + if (phy_reg & MII_CR_LOOPBACK) { + phy_reg &= ~MII_CR_LOOPBACK; + hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg); + igb_phy_sw_reset(hw); + } +} + +static void igb_create_lbtest_frame(struct sk_buff *skb, + unsigned int frame_size) +{ + memset(skb->data, 0xFF, frame_size); + frame_size &= ~1; + memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1); + memset(&skb->data[frame_size / 2 + 10], 0xBE, 1); + memset(&skb->data[frame_size / 2 + 12], 0xAF, 1); +} + +static int igb_check_lbtest_frame(struct sk_buff *skb, unsigned int frame_size) +{ + frame_size &= ~1; + if (*(skb->data + 3) == 0xFF) + if ((*(skb->data + frame_size / 2 + 10) == 0xBE) && + (*(skb->data + frame_size / 2 + 12) == 0xAF)) + return 0; + return 13; +} + +static int igb_run_loopback_test(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct igb_ring *tx_ring = &adapter->test_tx_ring; + struct igb_ring *rx_ring = &adapter->test_rx_ring; + struct pci_dev *pdev = adapter->pdev; + int i, j, k, l, lc, good_cnt; + int ret_val = 0; + unsigned long time; + + wr32(E1000_RDT(0), rx_ring->count - 1); + + /* Calculate the loop count based on the largest descriptor ring + * The idea is to wrap the largest ring a number of times using 64 + * send/receive pairs during each loop + */ + + if (rx_ring->count <= tx_ring->count) + lc = ((tx_ring->count / 64) * 2) + 1; + else + lc = ((rx_ring->count / 64) * 2) + 1; + + k = l = 0; + for (j = 0; j <= lc; j++) { /* loop count loop */ + for (i = 0; i < 64; i++) { /* send the packets */ + igb_create_lbtest_frame(tx_ring->buffer_info[k].skb, + 1024); + pci_dma_sync_single_for_device(pdev, + tx_ring->buffer_info[k].dma, + tx_ring->buffer_info[k].length, + PCI_DMA_TODEVICE); + k++; + if (k == tx_ring->count) + k = 0; + } + wr32(E1000_TDT(0), k); + msleep(200); + time = jiffies; /* set the start time for the receive */ + good_cnt = 0; + do { /* receive the sent packets */ + pci_dma_sync_single_for_cpu(pdev, + rx_ring->buffer_info[l].dma, + IGB_RXBUFFER_2048, + PCI_DMA_FROMDEVICE); + + ret_val = igb_check_lbtest_frame( + rx_ring->buffer_info[l].skb, 1024); + if (!ret_val) + good_cnt++; + l++; + if (l == rx_ring->count) + l = 0; + /* time + 20 msecs (200 msecs on 2.4) is more than + * enough time to complete the receives, if it's + * exceeded, break and error off + */ + } while (good_cnt < 64 && jiffies < (time + 20)); + if (good_cnt != 64) { + ret_val = 13; /* ret_val is the same as mis-compare */ + break; + } + if (jiffies >= (time + 20)) { + ret_val = 14; /* error code for time out error */ + break; + } + } /* end loop count loop */ + return ret_val; +} + +static int igb_loopback_test(struct igb_adapter *adapter, u64 *data) +{ + /* PHY loopback cannot be performed if SoL/IDER + * sessions are active */ + if (igb_check_reset_block(&adapter->hw)) { + dev_err(&adapter->pdev->dev, + "Cannot do PHY loopback test " + "when SoL/IDER is active.\n"); + *data = 0; + goto out; + } + *data = igb_setup_desc_rings(adapter); + if (*data) + goto out; + *data = igb_setup_loopback_test(adapter); + if (*data) + goto err_loopback; + *data = igb_run_loopback_test(adapter); + igb_loopback_cleanup(adapter); + +err_loopback: + igb_free_desc_rings(adapter); +out: + return *data; +} + +static int igb_link_test(struct igb_adapter *adapter, u64 *data) +{ + struct e1000_hw *hw = &adapter->hw; + *data = 0; + if (hw->phy.media_type == e1000_media_type_internal_serdes) { + int i = 0; + hw->mac.serdes_has_link = false; + + /* On some blade server designs, link establishment + * could take as long as 2-3 minutes */ + do { + hw->mac.ops.check_for_link(&adapter->hw); + if (hw->mac.serdes_has_link) + return *data; + msleep(20); + } while (i++ < 3750); + + *data = 1; + } else { + hw->mac.ops.check_for_link(&adapter->hw); + if (hw->mac.autoneg) + msleep(4000); + + if (!(rd32(E1000_STATUS) & + E1000_STATUS_LU)) + *data = 1; + } + return *data; +} + +static void igb_diag_test(struct net_device *netdev, + struct ethtool_test *eth_test, u64 *data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + u16 autoneg_advertised; + u8 forced_speed_duplex, autoneg; + bool if_running = netif_running(netdev); + + set_bit(__IGB_TESTING, &adapter->state); + if (eth_test->flags == ETH_TEST_FL_OFFLINE) { + /* Offline tests */ + + /* save speed, duplex, autoneg settings */ + autoneg_advertised = adapter->hw.phy.autoneg_advertised; + forced_speed_duplex = adapter->hw.mac.forced_speed_duplex; + autoneg = adapter->hw.mac.autoneg; + + dev_info(&adapter->pdev->dev, "offline testing starting\n"); + + /* Link test performed before hardware reset so autoneg doesn't + * interfere with test result */ + if (igb_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + if (if_running) + /* indicate we're in test mode */ + dev_close(netdev); + else + igb_reset(adapter); + + if (igb_reg_test(adapter, &data[0])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + igb_reset(adapter); + if (igb_eeprom_test(adapter, &data[1])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + igb_reset(adapter); + if (igb_intr_test(adapter, &data[2])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + igb_reset(adapter); + if (igb_loopback_test(adapter, &data[3])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* restore speed, duplex, autoneg settings */ + adapter->hw.phy.autoneg_advertised = autoneg_advertised; + adapter->hw.mac.forced_speed_duplex = forced_speed_duplex; + adapter->hw.mac.autoneg = autoneg; + + /* force this routine to wait until autoneg complete/timeout */ + adapter->hw.phy.autoneg_wait_to_complete = true; + igb_reset(adapter); + adapter->hw.phy.autoneg_wait_to_complete = false; + + clear_bit(__IGB_TESTING, &adapter->state); + if (if_running) + dev_open(netdev); + } else { + dev_info(&adapter->pdev->dev, "online testing starting\n"); + /* Online tests */ + if (igb_link_test(adapter, &data[4])) + eth_test->flags |= ETH_TEST_FL_FAILED; + + /* Online tests aren't run; pass by default */ + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 0; + + clear_bit(__IGB_TESTING, &adapter->state); + } + msleep_interruptible(4 * 1000); +} + +static int igb_wol_exclusion(struct igb_adapter *adapter, + struct ethtool_wolinfo *wol) +{ + struct e1000_hw *hw = &adapter->hw; + int retval = 1; /* fail by default */ + + switch (hw->device_id) { + case E1000_DEV_ID_82575GB_QUAD_COPPER: + /* WoL not supported */ + wol->supported = 0; + break; + case E1000_DEV_ID_82575EB_FIBER_SERDES: + /* Wake events not supported on port B */ + if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) { + wol->supported = 0; + break; + } + /* return success for non excluded adapter ports */ + retval = 0; + break; + default: + /* dual port cards only support WoL on port A from now on + * unless it was enabled in the eeprom for port B + * so exclude FUNC_1 ports from having WoL enabled */ + if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1 && + !adapter->eeprom_wol) { + wol->supported = 0; + break; + } + + retval = 0; + } + + return retval; +} + +static void igb_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_UCAST | WAKE_MCAST | + WAKE_BCAST | WAKE_MAGIC; + wol->wolopts = 0; + + /* this function will set ->supported = 0 and return 1 if wol is not + * supported by this hardware */ + if (igb_wol_exclusion(adapter, wol)) + return; + + /* apply any specific unsupported masks here */ + switch (adapter->hw.device_id) { + default: + break; + } + + if (adapter->wol & E1000_WUFC_EX) + wol->wolopts |= WAKE_UCAST; + if (adapter->wol & E1000_WUFC_MC) + wol->wolopts |= WAKE_MCAST; + if (adapter->wol & E1000_WUFC_BC) + wol->wolopts |= WAKE_BCAST; + if (adapter->wol & E1000_WUFC_MAG) + wol->wolopts |= WAKE_MAGIC; + + return; +} + +static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE)) + return -EOPNOTSUPP; + + if (igb_wol_exclusion(adapter, wol)) + return wol->wolopts ? -EOPNOTSUPP : 0; + + switch (hw->device_id) { + default: + break; + } + + /* these settings will always override what we currently have */ + adapter->wol = 0; + + if (wol->wolopts & WAKE_UCAST) + adapter->wol |= E1000_WUFC_EX; + if (wol->wolopts & WAKE_MCAST) + adapter->wol |= E1000_WUFC_MC; + if (wol->wolopts & WAKE_BCAST) + adapter->wol |= E1000_WUFC_BC; + if (wol->wolopts & WAKE_MAGIC) + adapter->wol |= E1000_WUFC_MAG; + + return 0; +} + +/* toggle LED 4 times per second = 2 "blinks" per second */ +#define IGB_ID_INTERVAL (HZ/4) + +/* bit defines for adapter->led_status */ +#define IGB_LED_ON 0 + +static int igb_phys_id(struct net_device *netdev, u32 data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) + data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); + + igb_blink_led(hw); + msleep_interruptible(data * 1000); + + igb_led_off(hw); + clear_bit(IGB_LED_ON, &adapter->led_status); + igb_cleanup_led(hw); + + return 0; +} + +static int igb_set_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || + ((ec->rx_coalesce_usecs > 3) && + (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) || + (ec->rx_coalesce_usecs == 2)) + return -EINVAL; + + /* convert to rate of irq's per second */ + if (ec->rx_coalesce_usecs <= 3) + adapter->itr_setting = ec->rx_coalesce_usecs; + else + adapter->itr_setting = (1000000 / ec->rx_coalesce_usecs); + + if (netif_running(netdev)) + igb_reinit_locked(adapter); + + return 0; +} + +static int igb_get_coalesce(struct net_device *netdev, + struct ethtool_coalesce *ec) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + if (adapter->itr_setting <= 3) + ec->rx_coalesce_usecs = adapter->itr_setting; + else + ec->rx_coalesce_usecs = 1000000 / adapter->itr_setting; + + return 0; +} + + +static int igb_nway_reset(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + if (netif_running(netdev)) + igb_reinit_locked(adapter); + return 0; +} + +static int igb_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return IGB_STATS_LEN; + case ETH_SS_TEST: + return IGB_TEST_LEN; + default: + return -ENOTSUPP; + } +} + +static void igb_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + u64 *queue_stat; + int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); + int j; + int i; + + igb_update_stats(adapter); + for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { + char *p = (char *)adapter+igb_gstrings_stats[i].stat_offset; + data[i] = (igb_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + for (j = 0; j < adapter->num_rx_queues; j++) { + int k; + queue_stat = (u64 *)&adapter->rx_ring[j].rx_stats; + for (k = 0; k < stat_count; k++) + data[i + k] = queue_stat[k]; + i += k; + } +} + +static void igb_get_strings(struct net_device *netdev, u32 stringset, u8 *data) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_TEST: + memcpy(data, *igb_gstrings_test, + IGB_TEST_LEN*ETH_GSTRING_LEN); + break; + case ETH_SS_STATS: + for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { + memcpy(p, igb_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_tx_queues; i++) { + sprintf(p, "tx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + sprintf(p, "rx_queue_%u_packets", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_queue_%u_bytes", i); + p += ETH_GSTRING_LEN; + } +/* BUG_ON(p - data != IGB_STATS_LEN * ETH_GSTRING_LEN); */ + break; + } +} + +static struct ethtool_ops igb_ethtool_ops = { + .get_settings = igb_get_settings, + .set_settings = igb_set_settings, + .get_drvinfo = igb_get_drvinfo, + .get_regs_len = igb_get_regs_len, + .get_regs = igb_get_regs, + .get_wol = igb_get_wol, + .set_wol = igb_set_wol, + .get_msglevel = igb_get_msglevel, + .set_msglevel = igb_set_msglevel, + .nway_reset = igb_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = igb_get_eeprom_len, + .get_eeprom = igb_get_eeprom, + .set_eeprom = igb_set_eeprom, + .get_ringparam = igb_get_ringparam, + .set_ringparam = igb_set_ringparam, + .get_pauseparam = igb_get_pauseparam, + .set_pauseparam = igb_set_pauseparam, + .get_rx_csum = igb_get_rx_csum, + .set_rx_csum = igb_set_rx_csum, + .get_tx_csum = igb_get_tx_csum, + .set_tx_csum = igb_set_tx_csum, + .get_sg = ethtool_op_get_sg, + .set_sg = ethtool_op_set_sg, + .get_tso = ethtool_op_get_tso, + .set_tso = igb_set_tso, + .self_test = igb_diag_test, + .get_strings = igb_get_strings, + .phys_id = igb_phys_id, + .get_sset_count = igb_get_sset_count, + .get_ethtool_stats = igb_get_ethtool_stats, + .get_coalesce = igb_get_coalesce, + .set_coalesce = igb_set_coalesce, +}; + +void igb_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &igb_ethtool_ops); +} diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c new file mode 100644 index 000000000000..f3c144d5d72f --- /dev/null +++ b/drivers/net/igb/igb_main.c @@ -0,0 +1,4138 @@ +/******************************************************************************* + + Intel(R) Gigabit Ethernet Linux driver + Copyright(c) 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information: + e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/vmalloc.h> +#include <linux/pagemap.h> +#include <linux/netdevice.h> +#include <linux/tcp.h> +#include <linux/ipv6.h> +#include <net/checksum.h> +#include <net/ip6_checksum.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/if_vlan.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/if_ether.h> + +#include "igb.h" + +#define DRV_VERSION "1.0.8-k2" +char igb_driver_name[] = "igb"; +char igb_driver_version[] = DRV_VERSION; +static const char igb_driver_string[] = + "Intel(R) Gigabit Ethernet Network Driver"; +static const char igb_copyright[] = "Copyright (c) 2007 Intel Corporation."; + + +static const struct e1000_info *igb_info_tbl[] = { + [board_82575] = &e1000_82575_info, +}; + +static struct pci_device_id igb_pci_tbl[] = { + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 }, + /* required last entry */ + {0, } +}; + +MODULE_DEVICE_TABLE(pci, igb_pci_tbl); + +void igb_reset(struct igb_adapter *); +static int igb_setup_all_tx_resources(struct igb_adapter *); +static int igb_setup_all_rx_resources(struct igb_adapter *); +static void igb_free_all_tx_resources(struct igb_adapter *); +static void igb_free_all_rx_resources(struct igb_adapter *); +static void igb_free_tx_resources(struct igb_adapter *, struct igb_ring *); +static void igb_free_rx_resources(struct igb_adapter *, struct igb_ring *); +void igb_update_stats(struct igb_adapter *); +static int igb_probe(struct pci_dev *, const struct pci_device_id *); +static void __devexit igb_remove(struct pci_dev *pdev); +static int igb_sw_init(struct igb_adapter *); +static int igb_open(struct net_device *); +static int igb_close(struct net_device *); +static void igb_configure_tx(struct igb_adapter *); +static void igb_configure_rx(struct igb_adapter *); +static void igb_setup_rctl(struct igb_adapter *); +static void igb_clean_all_tx_rings(struct igb_adapter *); +static void igb_clean_all_rx_rings(struct igb_adapter *); +static void igb_clean_tx_ring(struct igb_adapter *, struct igb_ring *); +static void igb_clean_rx_ring(struct igb_adapter *, struct igb_ring *); +static void igb_set_multi(struct net_device *); +static void igb_update_phy_info(unsigned long); +static void igb_watchdog(unsigned long); +static void igb_watchdog_task(struct work_struct *); +static int igb_xmit_frame_ring_adv(struct sk_buff *, struct net_device *, + struct igb_ring *); +static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *); +static struct net_device_stats *igb_get_stats(struct net_device *); +static int igb_change_mtu(struct net_device *, int); +static int igb_set_mac(struct net_device *, void *); +static irqreturn_t igb_intr(int irq, void *); +static irqreturn_t igb_intr_msi(int irq, void *); +static irqreturn_t igb_msix_other(int irq, void *); +static irqreturn_t igb_msix_rx(int irq, void *); +static irqreturn_t igb_msix_tx(int irq, void *); +static int igb_clean_rx_ring_msix(struct napi_struct *, int); +static bool igb_clean_tx_irq(struct igb_adapter *, struct igb_ring *); +static int igb_clean(struct napi_struct *, int); +static bool igb_clean_rx_irq_adv(struct igb_adapter *, + struct igb_ring *, int *, int); +static void igb_alloc_rx_buffers_adv(struct igb_adapter *, + struct igb_ring *, int); +static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); +static void igb_tx_timeout(struct net_device *); +static void igb_reset_task(struct work_struct *); +static void igb_vlan_rx_register(struct net_device *, struct vlan_group *); +static void igb_vlan_rx_add_vid(struct net_device *, u16); +static void igb_vlan_rx_kill_vid(struct net_device *, u16); +static void igb_restore_vlan(struct igb_adapter *); + +static int igb_suspend(struct pci_dev *, pm_message_t); +#ifdef CONFIG_PM +static int igb_resume(struct pci_dev *); +#endif +static void igb_shutdown(struct pci_dev *); + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* for netdump / net console */ +static void igb_netpoll(struct net_device *); +#endif + +static pci_ers_result_t igb_io_error_detected(struct pci_dev *, + pci_channel_state_t); +static pci_ers_result_t igb_io_slot_reset(struct pci_dev *); +static void igb_io_resume(struct pci_dev *); + +static struct pci_error_handlers igb_err_handler = { + .error_detected = igb_io_error_detected, + .slot_reset = igb_io_slot_reset, + .resume = igb_io_resume, +}; + + +static struct pci_driver igb_driver = { + .name = igb_driver_name, + .id_table = igb_pci_tbl, + .probe = igb_probe, + .remove = __devexit_p(igb_remove), +#ifdef CONFIG_PM + /* Power Managment Hooks */ + .suspend = igb_suspend, + .resume = igb_resume, +#endif + .shutdown = igb_shutdown, + .err_handler = &igb_err_handler +}; + +MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>"); +MODULE_DESCRIPTION("Intel(R) Gigabit Ethernet Network Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +#ifdef DEBUG +/** + * igb_get_hw_dev_name - return device name string + * used by hardware layer to print debugging information + **/ +char *igb_get_hw_dev_name(struct e1000_hw *hw) +{ + struct igb_adapter *adapter = hw->back; + return adapter->netdev->name; +} +#endif + +/** + * igb_init_module - Driver Registration Routine + * + * igb_init_module is the first routine called when the driver is + * loaded. All it does is register with the PCI subsystem. + **/ +static int __init igb_init_module(void) +{ + int ret; + printk(KERN_INFO "%s - version %s\n", + igb_driver_string, igb_driver_version); + + printk(KERN_INFO "%s\n", igb_copyright); + + ret = pci_register_driver(&igb_driver); + return ret; +} + +module_init(igb_init_module); + +/** + * igb_exit_module - Driver Exit Cleanup Routine + * + * igb_exit_module is called just before the driver is removed + * from memory. + **/ +static void __exit igb_exit_module(void) +{ + pci_unregister_driver(&igb_driver); +} + +module_exit(igb_exit_module); + +/** + * igb_alloc_queues - Allocate memory for all rings + * @adapter: board private structure to initialize + * + * We allocate one ring per queue at run-time since we don't know the + * number of queues at compile-time. + **/ +static int igb_alloc_queues(struct igb_adapter *adapter) +{ + int i; + + adapter->tx_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct igb_ring), GFP_KERNEL); + if (!adapter->tx_ring) + return -ENOMEM; + + adapter->rx_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct igb_ring), GFP_KERNEL); + if (!adapter->rx_ring) { + kfree(adapter->tx_ring); + return -ENOMEM; + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igb_ring *ring = &(adapter->rx_ring[i]); + ring->adapter = adapter; + ring->itr_register = E1000_ITR; + + if (!ring->napi.poll) + netif_napi_add(adapter->netdev, &ring->napi, igb_clean, + adapter->napi.weight / + adapter->num_rx_queues); + } + return 0; +} + +#define IGB_N0_QUEUE -1 +static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue, + int tx_queue, int msix_vector) +{ + u32 msixbm = 0; + struct e1000_hw *hw = &adapter->hw; + /* The 82575 assigns vectors using a bitmask, which matches the + bitmask for the EICR/EIMS/EIMC registers. To assign one + or more queues to a vector, we write the appropriate bits + into the MSIXBM register for that vector. */ + if (rx_queue > IGB_N0_QUEUE) { + msixbm = E1000_EICR_RX_QUEUE0 << rx_queue; + adapter->rx_ring[rx_queue].eims_value = msixbm; + } + if (tx_queue > IGB_N0_QUEUE) { + msixbm |= E1000_EICR_TX_QUEUE0 << tx_queue; + adapter->tx_ring[tx_queue].eims_value = + E1000_EICR_TX_QUEUE0 << tx_queue; + } + array_wr32(E1000_MSIXBM(0), msix_vector, msixbm); +} + +/** + * igb_configure_msix - Configure MSI-X hardware + * + * igb_configure_msix sets up the hardware to properly + * generate MSI-X interrupts. + **/ +static void igb_configure_msix(struct igb_adapter *adapter) +{ + u32 tmp; + int i, vector = 0; + struct e1000_hw *hw = &adapter->hw; + + adapter->eims_enable_mask = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *tx_ring = &adapter->tx_ring[i]; + igb_assign_vector(adapter, IGB_N0_QUEUE, i, vector++); + adapter->eims_enable_mask |= tx_ring->eims_value; + if (tx_ring->itr_val) + writel(1000000000 / (tx_ring->itr_val * 256), + hw->hw_addr + tx_ring->itr_register); + else + writel(1, hw->hw_addr + tx_ring->itr_register); + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igb_ring *rx_ring = &adapter->rx_ring[i]; + igb_assign_vector(adapter, i, IGB_N0_QUEUE, vector++); + adapter->eims_enable_mask |= rx_ring->eims_value; + if (rx_ring->itr_val) + writel(1000000000 / (rx_ring->itr_val * 256), + hw->hw_addr + rx_ring->itr_register); + else + writel(1, hw->hw_addr + rx_ring->itr_register); + } + + + /* set vector for other causes, i.e. link changes */ + array_wr32(E1000_MSIXBM(0), vector++, + E1000_EIMS_OTHER); + + /* disable IAM for ICR interrupt bits */ + wr32(E1000_IAM, 0); + + tmp = rd32(E1000_CTRL_EXT); + /* enable MSI-X PBA support*/ + tmp |= E1000_CTRL_EXT_PBA_CLR; + + /* Auto-Mask interrupts upon ICR read. */ + tmp |= E1000_CTRL_EXT_EIAME; + tmp |= E1000_CTRL_EXT_IRCA; + + wr32(E1000_CTRL_EXT, tmp); + adapter->eims_enable_mask |= E1000_EIMS_OTHER; + + wrfl(); +} + +/** + * igb_request_msix - Initialize MSI-X interrupts + * + * igb_request_msix allocates MSI-X vectors and requests interrupts from the + * kernel. + **/ +static int igb_request_msix(struct igb_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i, err = 0, vector = 0; + + vector = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *ring = &(adapter->tx_ring[i]); + sprintf(ring->name, "%s-tx%d", netdev->name, i); + err = request_irq(adapter->msix_entries[vector].vector, + &igb_msix_tx, 0, ring->name, + &(adapter->tx_ring[i])); + if (err) + goto out; + ring->itr_register = E1000_EITR(0) + (vector << 2); + ring->itr_val = adapter->itr; + vector++; + } + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igb_ring *ring = &(adapter->rx_ring[i]); + if (strlen(netdev->name) < (IFNAMSIZ - 5)) + sprintf(ring->name, "%s-rx%d", netdev->name, i); + else + memcpy(ring->name, netdev->name, IFNAMSIZ); + err = request_irq(adapter->msix_entries[vector].vector, + &igb_msix_rx, 0, ring->name, + &(adapter->rx_ring[i])); + if (err) + goto out; + ring->itr_register = E1000_EITR(0) + (vector << 2); + ring->itr_val = adapter->itr; + vector++; + } + + err = request_irq(adapter->msix_entries[vector].vector, + &igb_msix_other, 0, netdev->name, netdev); + if (err) + goto out; + + adapter->napi.poll = igb_clean_rx_ring_msix; + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].napi.poll = adapter->napi.poll; + igb_configure_msix(adapter); + return 0; +out: + return err; +} + +static void igb_reset_interrupt_capability(struct igb_adapter *adapter) +{ + if (adapter->msix_entries) { + pci_disable_msix(adapter->pdev); + kfree(adapter->msix_entries); + adapter->msix_entries = NULL; + } else if (adapter->msi_enabled) + pci_disable_msi(adapter->pdev); + return; +} + + +/** + * igb_set_interrupt_capability - set MSI or MSI-X if supported + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +static void igb_set_interrupt_capability(struct igb_adapter *adapter) +{ + int err; + int numvecs, i; + + numvecs = adapter->num_tx_queues + adapter->num_rx_queues + 1; + adapter->msix_entries = kcalloc(numvecs, sizeof(struct msix_entry), + GFP_KERNEL); + if (!adapter->msix_entries) + goto msi_only; + + for (i = 0; i < numvecs; i++) + adapter->msix_entries[i].entry = i; + + err = pci_enable_msix(adapter->pdev, + adapter->msix_entries, + numvecs); + if (err == 0) + return; + + igb_reset_interrupt_capability(adapter); + + /* If we can't do MSI-X, try MSI */ +msi_only: + adapter->num_rx_queues = 1; + if (!pci_enable_msi(adapter->pdev)) + adapter->msi_enabled = 1; + return; +} + +/** + * igb_request_irq - initialize interrupts + * + * Attempts to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +static int igb_request_irq(struct igb_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + int err = 0; + + if (adapter->msix_entries) { + err = igb_request_msix(adapter); + if (!err) { + struct e1000_hw *hw = &adapter->hw; + /* enable IAM, auto-mask, + * DO NOT USE EIAME or IAME in legacy mode */ + wr32(E1000_IAM, IMS_ENABLE_MASK); + goto request_done; + } + /* fall back to MSI */ + igb_reset_interrupt_capability(adapter); + if (!pci_enable_msi(adapter->pdev)) + adapter->msi_enabled = 1; + igb_free_all_tx_resources(adapter); + igb_free_all_rx_resources(adapter); + adapter->num_rx_queues = 1; + igb_alloc_queues(adapter); + } + if (adapter->msi_enabled) { + err = request_irq(adapter->pdev->irq, &igb_intr_msi, 0, + netdev->name, netdev); + if (!err) + goto request_done; + /* fall back to legacy interrupts */ + igb_reset_interrupt_capability(adapter); + adapter->msi_enabled = 0; + } + + err = request_irq(adapter->pdev->irq, &igb_intr, IRQF_SHARED, + netdev->name, netdev); + + if (err) { + dev_err(&adapter->pdev->dev, "Error %d getting interrupt\n", + err); + goto request_done; + } + + /* enable IAM, auto-mask */ + wr32(E1000_IAM, IMS_ENABLE_MASK); + +request_done: + return err; +} + +static void igb_free_irq(struct igb_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + + if (adapter->msix_entries) { + int vector = 0, i; + + for (i = 0; i < adapter->num_tx_queues; i++) + free_irq(adapter->msix_entries[vector++].vector, + &(adapter->tx_ring[i])); + for (i = 0; i < adapter->num_rx_queues; i++) + free_irq(adapter->msix_entries[vector++].vector, + &(adapter->rx_ring[i])); + + free_irq(adapter->msix_entries[vector++].vector, netdev); + return; + } + + free_irq(adapter->pdev->irq, netdev); +} + +/** + * igb_irq_disable - Mask off interrupt generation on the NIC + * @adapter: board private structure + **/ +static void igb_irq_disable(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (adapter->msix_entries) { + wr32(E1000_EIMC, ~0); + wr32(E1000_EIAC, 0); + } + wr32(E1000_IMC, ~0); + wrfl(); + synchronize_irq(adapter->pdev->irq); +} + +/** + * igb_irq_enable - Enable default interrupt generation settings + * @adapter: board private structure + **/ +static void igb_irq_enable(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (adapter->msix_entries) { + wr32(E1000_EIMS, + adapter->eims_enable_mask); + wr32(E1000_EIAC, + adapter->eims_enable_mask); + wr32(E1000_IMS, E1000_IMS_LSC); + } else + wr32(E1000_IMS, IMS_ENABLE_MASK); +} + +static void igb_update_mng_vlan(struct igb_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + u16 vid = adapter->hw.mng_cookie.vlan_id; + u16 old_vid = adapter->mng_vlan_id; + if (adapter->vlgrp) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) { + if (adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { + igb_vlan_rx_add_vid(netdev, vid); + adapter->mng_vlan_id = vid; + } else + adapter->mng_vlan_id = IGB_MNG_VLAN_NONE; + + if ((old_vid != (u16)IGB_MNG_VLAN_NONE) && + (vid != old_vid) && + !vlan_group_get_device(adapter->vlgrp, old_vid)) + igb_vlan_rx_kill_vid(netdev, old_vid); + } else + adapter->mng_vlan_id = vid; + } +} + +/** + * igb_release_hw_control - release control of the h/w to f/w + * @adapter: address of board private structure + * + * igb_release_hw_control resets CTRL_EXT:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that the + * driver is no longer loaded. + * + **/ +static void igb_release_hw_control(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + + /* Let firmware take over control of h/w */ + ctrl_ext = rd32(E1000_CTRL_EXT); + wr32(E1000_CTRL_EXT, + ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD); +} + + +/** + * igb_get_hw_control - get control of the h/w from f/w + * @adapter: address of board private structure + * + * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit. + * For ASF and Pass Through versions of f/w this means that + * the driver is loaded. + * + **/ +static void igb_get_hw_control(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 ctrl_ext; + + /* Let firmware know the driver has taken over */ + ctrl_ext = rd32(E1000_CTRL_EXT); + wr32(E1000_CTRL_EXT, + ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); +} + +static void igb_init_manageability(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (adapter->en_mng_pt) { + u32 manc2h = rd32(E1000_MANC2H); + u32 manc = rd32(E1000_MANC); + + /* disable hardware interception of ARP */ + manc &= ~(E1000_MANC_ARP_EN); + + /* enable receiving management packets to the host */ + /* this will probably generate destination unreachable messages + * from the host OS, but the packets will be handled on SMBUS */ + manc |= E1000_MANC_EN_MNG2HOST; +#define E1000_MNG2HOST_PORT_623 (1 << 5) +#define E1000_MNG2HOST_PORT_664 (1 << 6) + manc2h |= E1000_MNG2HOST_PORT_623; + manc2h |= E1000_MNG2HOST_PORT_664; + wr32(E1000_MANC2H, manc2h); + + wr32(E1000_MANC, manc); + } +} + +static void igb_release_manageability(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (adapter->en_mng_pt) { + u32 manc = rd32(E1000_MANC); + + /* re-enable hardware interception of ARP */ + manc |= E1000_MANC_ARP_EN; + manc &= ~E1000_MANC_EN_MNG2HOST; + + /* don't explicitly have to mess with MANC2H since + * MANC has an enable disable that gates MANC2H */ + + /* XXX stop the hardware watchdog ? */ + wr32(E1000_MANC, manc); + } +} + +/** + * igb_configure - configure the hardware for RX and TX + * @adapter: private board structure + **/ +static void igb_configure(struct igb_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + + igb_get_hw_control(adapter); + igb_set_multi(netdev); + + igb_restore_vlan(adapter); + igb_init_manageability(adapter); + + igb_configure_tx(adapter); + igb_setup_rctl(adapter); + igb_configure_rx(adapter); + /* call IGB_DESC_UNUSED which always leaves + * at least 1 descriptor unused to make sure + * next_to_use != next_to_clean */ + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igb_ring *ring = &adapter->rx_ring[i]; + igb_alloc_rx_buffers_adv(adapter, ring, IGB_DESC_UNUSED(ring)); + } + + + adapter->tx_queue_len = netdev->tx_queue_len; +} + + +/** + * igb_up - Open the interface and prepare it to handle traffic + * @adapter: board private structure + **/ + +int igb_up(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + int i; + + /* hardware has been reset, we need to reload some things */ + igb_configure(adapter); + + clear_bit(__IGB_DOWN, &adapter->state); + + napi_enable(&adapter->napi); + + if (adapter->msix_entries) { + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->rx_ring[i].napi); + igb_configure_msix(adapter); + } + + /* Clear any pending interrupts. */ + rd32(E1000_ICR); + igb_irq_enable(adapter); + + /* Fire a link change interrupt to start the watchdog. */ + wr32(E1000_ICS, E1000_ICS_LSC); + return 0; +} + +void igb_down(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + u32 tctl, rctl; + int i; + + /* signal that we're down so the interrupt handler does not + * reschedule our watchdog timer */ + set_bit(__IGB_DOWN, &adapter->state); + + /* disable receives in the hardware */ + rctl = rd32(E1000_RCTL); + wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN); + /* flush and sleep below */ + + netif_stop_queue(netdev); + + /* disable transmits in the hardware */ + tctl = rd32(E1000_TCTL); + tctl &= ~E1000_TCTL_EN; + wr32(E1000_TCTL, tctl); + /* flush both disables and wait for them to finish */ + wrfl(); + msleep(10); + + napi_disable(&adapter->napi); + + if (adapter->msix_entries) + for (i = 0; i < adapter->num_rx_queues; i++) + napi_disable(&adapter->rx_ring[i].napi); + igb_irq_disable(adapter); + + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + netdev->tx_queue_len = adapter->tx_queue_len; + netif_carrier_off(netdev); + adapter->link_speed = 0; + adapter->link_duplex = 0; + + igb_reset(adapter); + igb_clean_all_tx_rings(adapter); + igb_clean_all_rx_rings(adapter); +} + +void igb_reinit_locked(struct igb_adapter *adapter) +{ + WARN_ON(in_interrupt()); + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) + msleep(1); + igb_down(adapter); + igb_up(adapter); + clear_bit(__IGB_RESETTING, &adapter->state); +} + +void igb_reset(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct e1000_fc_info *fc = &adapter->hw.fc; + u32 pba = 0, tx_space, min_tx_space, min_rx_space; + u16 hwm; + + /* Repartition Pba for greater than 9k mtu + * To take effect CTRL.RST is required. + */ + pba = E1000_PBA_34K; + + if (adapter->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN) { + /* adjust PBA for jumbo frames */ + wr32(E1000_PBA, pba); + + /* To maintain wire speed transmits, the Tx FIFO should be + * large enough to accommodate two full transmit packets, + * rounded up to the next 1KB and expressed in KB. Likewise, + * the Rx FIFO should be large enough to accommodate at least + * one full receive packet and is similarly rounded up and + * expressed in KB. */ + pba = rd32(E1000_PBA); + /* upper 16 bits has Tx packet buffer allocation size in KB */ + tx_space = pba >> 16; + /* lower 16 bits has Rx packet buffer allocation size in KB */ + pba &= 0xffff; + /* the tx fifo also stores 16 bytes of information about the tx + * but don't include ethernet FCS because hardware appends it */ + min_tx_space = (adapter->max_frame_size + + sizeof(struct e1000_tx_desc) - + ETH_FCS_LEN) * 2; + min_tx_space = ALIGN(min_tx_space, 1024); + min_tx_space >>= 10; + /* software strips receive CRC, so leave room for it */ + min_rx_space = adapter->max_frame_size; + min_rx_space = ALIGN(min_rx_space, 1024); + min_rx_space >>= 10; + + /* If current Tx allocation is less than the min Tx FIFO size, + * and the min Tx FIFO size is less than the current Rx FIFO + * allocation, take space away from current Rx allocation */ + if (tx_space < min_tx_space && + ((min_tx_space - tx_space) < pba)) { + pba = pba - (min_tx_space - tx_space); + + /* if short on rx space, rx wins and must trump tx + * adjustment */ + if (pba < min_rx_space) + pba = min_rx_space; + } + } + wr32(E1000_PBA, pba); + + /* flow control settings */ + /* The high water mark must be low enough to fit one full frame + * (or the size used for early receive) above it in the Rx FIFO. + * Set it to the lower of: + * - 90% of the Rx FIFO size, or + * - the full Rx FIFO size minus one full frame */ + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - adapter->max_frame_size)); + + fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ + fc->low_water = fc->high_water - 8; + fc->pause_time = 0xFFFF; + fc->send_xon = 1; + fc->type = fc->original_type; + + /* Allow time for pending master requests to run */ + adapter->hw.mac.ops.reset_hw(&adapter->hw); + wr32(E1000_WUC, 0); + + if (adapter->hw.mac.ops.init_hw(&adapter->hw)) + dev_err(&adapter->pdev->dev, "Hardware Error\n"); + + igb_update_mng_vlan(adapter); + + /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ + wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); + + igb_reset_adaptive(&adapter->hw); + adapter->hw.phy.ops.get_phy_info(&adapter->hw); + igb_release_manageability(adapter); +} + +/** + * igb_probe - Device Initialization Routine + * @pdev: PCI device information struct + * @ent: entry in igb_pci_tbl + * + * Returns 0 on success, negative on failure + * + * igb_probe initializes an adapter identified by a pci_dev structure. + * The OS initialization, configuring of the adapter private structure, + * and a hardware reset occur. + **/ +static int __devinit igb_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *netdev; + struct igb_adapter *adapter; + struct e1000_hw *hw; + const struct e1000_info *ei = igb_info_tbl[ent->driver_data]; + unsigned long mmio_start, mmio_len; + static int cards_found; + int i, err, pci_using_dac; + u16 eeprom_data = 0; + u16 eeprom_apme_mask = IGB_EEPROM_APME; + u32 part_num; + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_using_dac = 0; + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) { + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (!err) + pci_using_dac = 1; + } else { + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (err) { + dev_err(&pdev->dev, "No usable DMA " + "configuration, aborting\n"); + goto err_dma; + } + } + } + + err = pci_request_regions(pdev, igb_driver_name); + if (err) + goto err_pci_reg; + + pci_set_master(pdev); + + err = -ENOMEM; + netdev = alloc_etherdev(sizeof(struct igb_adapter)); + if (!netdev) + goto err_alloc_etherdev; + + SET_NETDEV_DEV(netdev, &pdev->dev); + + pci_set_drvdata(pdev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->pdev = pdev; + hw = &adapter->hw; + hw->back = adapter; + adapter->msg_enable = NETIF_MSG_DRV | NETIF_MSG_PROBE; + + mmio_start = pci_resource_start(pdev, 0); + mmio_len = pci_resource_len(pdev, 0); + + err = -EIO; + adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); + if (!adapter->hw.hw_addr) + goto err_ioremap; + + netdev->open = &igb_open; + netdev->stop = &igb_close; + netdev->get_stats = &igb_get_stats; + netdev->set_multicast_list = &igb_set_multi; + netdev->set_mac_address = &igb_set_mac; + netdev->change_mtu = &igb_change_mtu; + netdev->do_ioctl = &igb_ioctl; + igb_set_ethtool_ops(netdev); + netdev->tx_timeout = &igb_tx_timeout; + netdev->watchdog_timeo = 5 * HZ; + netif_napi_add(netdev, &adapter->napi, igb_clean, 64); + netdev->vlan_rx_register = igb_vlan_rx_register; + netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid; + netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = igb_netpoll; +#endif + netdev->hard_start_xmit = &igb_xmit_frame_adv; + + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); + + netdev->mem_start = mmio_start; + netdev->mem_end = mmio_start + mmio_len; + + adapter->bd_number = cards_found; + + /* PCI config space info */ + hw->vendor_id = pdev->vendor; + hw->device_id = pdev->device; + hw->revision_id = pdev->revision; + hw->subsystem_vendor_id = pdev->subsystem_vendor; + hw->subsystem_device_id = pdev->subsystem_device; + + /* setup the private structure */ + hw->back = adapter; + /* Copy the default MAC, PHY and NVM function pointers */ + memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops)); + memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops)); + memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops)); + /* Initialize skew-specific constants */ + err = ei->get_invariants(hw); + if (err) + goto err_hw_init; + + err = igb_sw_init(adapter); + if (err) + goto err_sw_init; + + igb_get_bus_info_pcie(hw); + + hw->phy.autoneg_wait_to_complete = false; + hw->mac.adaptive_ifs = true; + + /* Copper options */ + if (hw->phy.media_type == e1000_media_type_copper) { + hw->phy.mdix = AUTO_ALL_MODES; + hw->phy.disable_polarity_correction = false; + hw->phy.ms_type = e1000_ms_hw_default; + } + + if (igb_check_reset_block(hw)) + dev_info(&pdev->dev, + "PHY reset is blocked due to SOL/IDER session.\n"); + + netdev->features = NETIF_F_SG | + NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | + NETIF_F_HW_VLAN_RX | + NETIF_F_HW_VLAN_FILTER; + + netdev->features |= NETIF_F_TSO; + + netdev->features |= NETIF_F_TSO6; + if (pci_using_dac) + netdev->features |= NETIF_F_HIGHDMA; + + netdev->features |= NETIF_F_LLTX; + adapter->en_mng_pt = igb_enable_mng_pass_thru(&adapter->hw); + + /* before reading the NVM, reset the controller to put the device in a + * known good starting state */ + hw->mac.ops.reset_hw(hw); + + /* make sure the NVM is good */ + if (igb_validate_nvm_checksum(hw) < 0) { + dev_err(&pdev->dev, "The NVM Checksum Is Not Valid\n"); + err = -EIO; + goto err_eeprom; + } + + /* copy the MAC address out of the NVM */ + if (hw->mac.ops.read_mac_addr(hw)) + dev_err(&pdev->dev, "NVM Read Error\n"); + + memcpy(netdev->dev_addr, hw->mac.addr, netdev->addr_len); + memcpy(netdev->perm_addr, hw->mac.addr, netdev->addr_len); + + if (!is_valid_ether_addr(netdev->perm_addr)) { + dev_err(&pdev->dev, "Invalid MAC Address\n"); + err = -EIO; + goto err_eeprom; + } + + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &igb_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + + init_timer(&adapter->phy_info_timer); + adapter->phy_info_timer.function = &igb_update_phy_info; + adapter->phy_info_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->reset_task, igb_reset_task); + INIT_WORK(&adapter->watchdog_task, igb_watchdog_task); + + /* Initialize link & ring properties that are user-changeable */ + adapter->tx_ring->count = 256; + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].count = adapter->tx_ring->count; + adapter->rx_ring->count = 256; + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].count = adapter->rx_ring->count; + + adapter->fc_autoneg = true; + hw->mac.autoneg = true; + hw->phy.autoneg_advertised = 0x2f; + + hw->fc.original_type = e1000_fc_default; + hw->fc.type = e1000_fc_default; + + adapter->itr_setting = 3; + adapter->itr = IGB_START_ITR; + + igb_validate_mdi_setting(hw); + + adapter->rx_csum = 1; + + /* Initial Wake on LAN setting If APM wake is enabled in the EEPROM, + * enable the ACPI Magic Packet filter + */ + + if (hw->bus.func == 0 || + hw->device_id == E1000_DEV_ID_82575EB_COPPER) + hw->nvm.ops.read_nvm(hw, NVM_INIT_CONTROL3_PORT_A, 1, + &eeprom_data); + + if (eeprom_data & eeprom_apme_mask) + adapter->eeprom_wol |= E1000_WUFC_MAG; + + /* now that we have the eeprom settings, apply the special cases where + * the eeprom may be wrong or the board simply won't support wake on + * lan on a particular port */ + switch (pdev->device) { + case E1000_DEV_ID_82575GB_QUAD_COPPER: + adapter->eeprom_wol = 0; + break; + case E1000_DEV_ID_82575EB_FIBER_SERDES: + /* Wake events only supported on port A for dual fiber + * regardless of eeprom setting */ + if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1) + adapter->eeprom_wol = 0; + break; + } + + /* initialize the wol settings based on the eeprom settings */ + adapter->wol = adapter->eeprom_wol; + + /* reset the hardware with the new settings */ + igb_reset(adapter); + + /* let the f/w know that the h/w is now under the control of the + * driver. */ + igb_get_hw_control(adapter); + + /* tell the stack to leave us alone until igb_open() is called */ + netif_carrier_off(netdev); + netif_stop_queue(netdev); + + strcpy(netdev->name, "eth%d"); + err = register_netdev(netdev); + if (err) + goto err_register; + + dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); + /* print bus type/speed/width info */ + dev_info(&pdev->dev, + "%s: (PCIe:%s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", + netdev->name, + ((hw->bus.speed == e1000_bus_speed_2500) + ? "2.5Gb/s" : "unknown"), + ((hw->bus.width == e1000_bus_width_pcie_x4) + ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1) + ? "Width x1" : "unknown"), + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + + igb_read_part_num(hw, &part_num); + dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name, + (part_num >> 8), (part_num & 0xff)); + + dev_info(&pdev->dev, + "Using %s interrupts. %d rx queue(s), %d tx queue(s)\n", + adapter->msix_entries ? "MSI-X" : + adapter->msi_enabled ? "MSI" : "legacy", + adapter->num_rx_queues, adapter->num_tx_queues); + + cards_found++; + return 0; + +err_register: + igb_release_hw_control(adapter); +err_eeprom: + if (!igb_check_reset_block(hw)) + hw->phy.ops.reset_phy(hw); + + if (hw->flash_address) + iounmap(hw->flash_address); + + igb_remove_device(hw); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); +err_sw_init: +err_hw_init: + iounmap(hw->hw_addr); +err_ioremap: + free_netdev(netdev); +err_alloc_etherdev: + pci_release_regions(pdev); +err_pci_reg: +err_dma: + pci_disable_device(pdev); + return err; +} + +/** + * igb_remove - Device Removal Routine + * @pdev: PCI device information struct + * + * igb_remove is called by the PCI subsystem to alert the driver + * that it should release a PCI device. The could be caused by a + * Hot-Plug event, or because the driver is going to be removed from + * memory. + **/ +static void __devexit igb_remove(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igb_adapter *adapter = netdev_priv(netdev); + + /* flush_scheduled work may reschedule our watchdog task, so + * explicitly disable watchdog tasks from being rescheduled */ + set_bit(__IGB_DOWN, &adapter->state); + del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->phy_info_timer); + + flush_scheduled_work(); + + + igb_release_manageability(adapter); + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + igb_release_hw_control(adapter); + + unregister_netdev(netdev); + + if (!igb_check_reset_block(&adapter->hw)) + adapter->hw.phy.ops.reset_phy(&adapter->hw); + + igb_remove_device(&adapter->hw); + igb_reset_interrupt_capability(adapter); + + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + + iounmap(adapter->hw.hw_addr); + if (adapter->hw.flash_address) + iounmap(adapter->hw.flash_address); + pci_release_regions(pdev); + + free_netdev(netdev); + + pci_disable_device(pdev); +} + +/** + * igb_sw_init - Initialize general software structures (struct igb_adapter) + * @adapter: board private structure to initialize + * + * igb_sw_init initializes the Adapter private data structure. + * Fields are initialized based on PCI device information and + * OS network device settings (MTU size). + **/ +static int __devinit igb_sw_init(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + + pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + + adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; + adapter->rx_ps_hdr_size = 0; /* disable packet split */ + adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; + + /* Number of supported queues. */ + /* Having more queues than CPUs doesn't make sense. */ + adapter->num_tx_queues = 1; + adapter->num_rx_queues = min(IGB_MAX_RX_QUEUES, num_online_cpus()); + + igb_set_interrupt_capability(adapter); + + if (igb_alloc_queues(adapter)) { + dev_err(&pdev->dev, "Unable to allocate memory for queues\n"); + return -ENOMEM; + } + + /* Explicitly disable IRQ since the NIC can be in any state. */ + igb_irq_disable(adapter); + + set_bit(__IGB_DOWN, &adapter->state); + return 0; +} + +/** + * igb_open - Called when a network interface is made active + * @netdev: network interface device structure + * + * Returns 0 on success, negative value on failure + * + * The open entry point is called when a network interface is made + * active by the system (IFF_UP). At this point all resources needed + * for transmit and receive operations are allocated, the interrupt + * handler is registered with the OS, the watchdog timer is started, + * and the stack is notified that the interface is ready. + **/ +static int igb_open(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + int err; + int i; + + /* disallow open during test */ + if (test_bit(__IGB_TESTING, &adapter->state)) + return -EBUSY; + + /* allocate transmit descriptors */ + err = igb_setup_all_tx_resources(adapter); + if (err) + goto err_setup_tx; + + /* allocate receive descriptors */ + err = igb_setup_all_rx_resources(adapter); + if (err) + goto err_setup_rx; + + /* e1000_power_up_phy(adapter); */ + + adapter->mng_vlan_id = IGB_MNG_VLAN_NONE; + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN)) + igb_update_mng_vlan(adapter); + + /* before we allocate an interrupt, we must be ready to handle it. + * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt + * as soon as we call pci_request_irq, so we have to setup our + * clean_rx handler before we do so. */ + igb_configure(adapter); + + err = igb_request_irq(adapter); + if (err) + goto err_req_irq; + + /* From here on the code is the same as igb_up() */ + clear_bit(__IGB_DOWN, &adapter->state); + + napi_enable(&adapter->napi); + if (adapter->msix_entries) + for (i = 0; i < adapter->num_rx_queues; i++) + napi_enable(&adapter->rx_ring[i].napi); + + igb_irq_enable(adapter); + + /* Clear any pending interrupts. */ + rd32(E1000_ICR); + /* Fire a link status change interrupt to start the watchdog. */ + wr32(E1000_ICS, E1000_ICS_LSC); + + return 0; + +err_req_irq: + igb_release_hw_control(adapter); + /* e1000_power_down_phy(adapter); */ + igb_free_all_rx_resources(adapter); +err_setup_rx: + igb_free_all_tx_resources(adapter); +err_setup_tx: + igb_reset(adapter); + + return err; +} + +/** + * igb_close - Disables a network interface + * @netdev: network interface device structure + * + * Returns 0, this is not allowed to fail + * + * The close entry point is called when an interface is de-activated + * by the OS. The hardware is still under the driver's control, but + * needs to be disabled. A global MAC reset is issued to stop the + * hardware, and all transmit and receive resources are freed. + **/ +static int igb_close(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + WARN_ON(test_bit(__IGB_RESETTING, &adapter->state)); + igb_down(adapter); + + igb_free_irq(adapter); + + igb_free_all_tx_resources(adapter); + igb_free_all_rx_resources(adapter); + + /* kill manageability vlan ID if supported, but not if a vlan with + * the same ID is registered on the host OS (let 8021q kill it) */ + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + !(adapter->vlgrp && + vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) + igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + + return 0; +} + +/** + * igb_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: board private structure + * @tx_ring: tx descriptor ring (for a specific queue) to setup + * + * Return 0 on success, negative on failure + **/ + +int igb_setup_tx_resources(struct igb_adapter *adapter, + struct igb_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + int size; + + size = sizeof(struct igb_buffer) * tx_ring->count; + tx_ring->buffer_info = vmalloc(size); + if (!tx_ring->buffer_info) + goto err; + memset(tx_ring->buffer_info, 0, size); + + /* round up to nearest 4K */ + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc) + + sizeof(u32); + tx_ring->size = ALIGN(tx_ring->size, 4096); + + tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, + &tx_ring->dma); + + if (!tx_ring->desc) + goto err; + + tx_ring->adapter = adapter; + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + spin_lock_init(&tx_ring->tx_clean_lock); + spin_lock_init(&tx_ring->tx_lock); + return 0; + +err: + vfree(tx_ring->buffer_info); + dev_err(&adapter->pdev->dev, + "Unable to allocate memory for the transmit descriptor ring\n"); + return -ENOMEM; +} + +/** + * igb_setup_all_tx_resources - wrapper to allocate Tx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * Return 0 on success, negative on failure + **/ +static int igb_setup_all_tx_resources(struct igb_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + err = igb_setup_tx_resources(adapter, &adapter->tx_ring[i]); + if (err) { + dev_err(&adapter->pdev->dev, + "Allocation for Tx Queue %u failed\n", i); + for (i--; i >= 0; i--) + igb_free_tx_resources(adapter, + &adapter->tx_ring[i]); + break; + } + } + + return err; +} + +/** + * igb_configure_tx - Configure transmit Unit after Reset + * @adapter: board private structure + * + * Configure the Tx unit of the MAC after a reset. + **/ +static void igb_configure_tx(struct igb_adapter *adapter) +{ + u64 tdba, tdwba; + struct e1000_hw *hw = &adapter->hw; + u32 tctl; + u32 txdctl, txctrl; + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct igb_ring *ring = &(adapter->tx_ring[i]); + + wr32(E1000_TDLEN(i), + ring->count * sizeof(struct e1000_tx_desc)); + tdba = ring->dma; + wr32(E1000_TDBAL(i), + tdba & 0x00000000ffffffffULL); + wr32(E1000_TDBAH(i), tdba >> 32); + + tdwba = ring->dma + ring->count * sizeof(struct e1000_tx_desc); + tdwba |= 1; /* enable head wb */ + wr32(E1000_TDWBAL(i), + tdwba & 0x00000000ffffffffULL); + wr32(E1000_TDWBAH(i), tdwba >> 32); + + ring->head = E1000_TDH(i); + ring->tail = E1000_TDT(i); + writel(0, hw->hw_addr + ring->tail); + writel(0, hw->hw_addr + ring->head); + txdctl = rd32(E1000_TXDCTL(i)); + txdctl |= E1000_TXDCTL_QUEUE_ENABLE; + wr32(E1000_TXDCTL(i), txdctl); + + /* Turn off Relaxed Ordering on head write-backs. The + * writebacks MUST be delivered in order or it will + * completely screw up our bookeeping. + */ + txctrl = rd32(E1000_DCA_TXCTRL(i)); + txctrl &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN; + wr32(E1000_DCA_TXCTRL(i), txctrl); + } + + + + /* Use the default values for the Tx Inter Packet Gap (IPG) timer */ + + /* Program the Transmit Control Register */ + + tctl = rd32(E1000_TCTL); + tctl &= ~E1000_TCTL_CT; + tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | + (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); + + igb_config_collision_dist(hw); + + /* Setup Transmit Descriptor Settings for eop descriptor */ + adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS; + + /* Enable transmits */ + tctl |= E1000_TCTL_EN; + + wr32(E1000_TCTL, tctl); +} + +/** + * igb_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: board private structure + * @rx_ring: rx descriptor ring (for a specific queue) to setup + * + * Returns 0 on success, negative on failure + **/ + +int igb_setup_rx_resources(struct igb_adapter *adapter, + struct igb_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + int size, desc_len; + + size = sizeof(struct igb_buffer) * rx_ring->count; + rx_ring->buffer_info = vmalloc(size); + if (!rx_ring->buffer_info) + goto err; + memset(rx_ring->buffer_info, 0, size); + + desc_len = sizeof(union e1000_adv_rx_desc); + + /* Round up to nearest 4K */ + rx_ring->size = rx_ring->count * desc_len; + rx_ring->size = ALIGN(rx_ring->size, 4096); + + rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size, + &rx_ring->dma); + + if (!rx_ring->desc) + goto err; + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + rx_ring->pending_skb = NULL; + + rx_ring->adapter = adapter; + /* FIXME: do we want to setup ring->napi->poll here? */ + rx_ring->napi.poll = adapter->napi.poll; + + return 0; + +err: + vfree(rx_ring->buffer_info); + dev_err(&adapter->pdev->dev, "Unable to allocate memory for " + "the receive descriptor ring\n"); + return -ENOMEM; +} + +/** + * igb_setup_all_rx_resources - wrapper to allocate Rx resources + * (Descriptors) for all queues + * @adapter: board private structure + * + * Return 0 on success, negative on failure + **/ +static int igb_setup_all_rx_resources(struct igb_adapter *adapter) +{ + int i, err = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + err = igb_setup_rx_resources(adapter, &adapter->rx_ring[i]); + if (err) { + dev_err(&adapter->pdev->dev, + "Allocation for Rx Queue %u failed\n", i); + for (i--; i >= 0; i--) + igb_free_rx_resources(adapter, + &adapter->rx_ring[i]); + break; + } + } + + return err; +} + +/** + * igb_setup_rctl - configure the receive control registers + * @adapter: Board private structure + **/ +static void igb_setup_rctl(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + u32 rctl; + u32 srrctl = 0; + int i; + + rctl = rd32(E1000_RCTL); + + rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | + E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); + + /* disable the stripping of CRC because it breaks + * BMC firmware connected over SMBUS + rctl |= E1000_RCTL_SECRC; + */ + + rctl &= ~E1000_RCTL_SBP; + + if (adapter->netdev->mtu <= ETH_DATA_LEN) + rctl &= ~E1000_RCTL_LPE; + else + rctl |= E1000_RCTL_LPE; + if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) { + /* Setup buffer sizes */ + rctl &= ~E1000_RCTL_SZ_4096; + rctl |= E1000_RCTL_BSEX; + switch (adapter->rx_buffer_len) { + case IGB_RXBUFFER_256: + rctl |= E1000_RCTL_SZ_256; + rctl &= ~E1000_RCTL_BSEX; + break; + case IGB_RXBUFFER_512: + rctl |= E1000_RCTL_SZ_512; + rctl &= ~E1000_RCTL_BSEX; + break; + case IGB_RXBUFFER_1024: + rctl |= E1000_RCTL_SZ_1024; + rctl &= ~E1000_RCTL_BSEX; + break; + case IGB_RXBUFFER_2048: + default: + rctl |= E1000_RCTL_SZ_2048; + rctl &= ~E1000_RCTL_BSEX; + break; + case IGB_RXBUFFER_4096: + rctl |= E1000_RCTL_SZ_4096; + break; + case IGB_RXBUFFER_8192: + rctl |= E1000_RCTL_SZ_8192; + break; + case IGB_RXBUFFER_16384: + rctl |= E1000_RCTL_SZ_16384; + break; + } + } else { + rctl &= ~E1000_RCTL_BSEX; + srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT; + } + + /* 82575 and greater support packet-split where the protocol + * header is placed in skb->data and the packet data is + * placed in pages hanging off of skb_shinfo(skb)->nr_frags. + * In the case of a non-split, skb->data is linearly filled, + * followed by the page buffers. Therefore, skb->data is + * sized to hold the largest protocol header. + */ + /* allocations using alloc_page take too long for regular MTU + * so only enable packet split for jumbo frames */ + if (rctl & E1000_RCTL_LPE) { + adapter->rx_ps_hdr_size = IGB_RXBUFFER_128; + srrctl = adapter->rx_ps_hdr_size << + E1000_SRRCTL_BSIZEHDRSIZE_SHIFT; + /* buffer size is ALWAYS one page */ + srrctl |= PAGE_SIZE >> E1000_SRRCTL_BSIZEPKT_SHIFT; + srrctl |= E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS; + } else { + adapter->rx_ps_hdr_size = 0; + srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF; + } + + for (i = 0; i < adapter->num_rx_queues; i++) + wr32(E1000_SRRCTL(i), srrctl); + + wr32(E1000_RCTL, rctl); +} + +/** + * igb_configure_rx - Configure receive Unit after Reset + * @adapter: board private structure + * + * Configure the Rx unit of the MAC after a reset. + **/ +static void igb_configure_rx(struct igb_adapter *adapter) +{ + u64 rdba; + struct e1000_hw *hw = &adapter->hw; + u32 rctl, rxcsum; + u32 rxdctl; + int i; + + /* disable receives while setting up the descriptors */ + rctl = rd32(E1000_RCTL); + wr32(E1000_RCTL, rctl & ~E1000_RCTL_EN); + wrfl(); + mdelay(10); + + if (adapter->itr_setting > 3) + wr32(E1000_ITR, + 1000000000 / (adapter->itr * 256)); + + /* Setup the HW Rx Head and Tail Descriptor Pointers and + * the Base and Length of the Rx Descriptor Ring */ + for (i = 0; i < adapter->num_rx_queues; i++) { + struct igb_ring *ring = &(adapter->rx_ring[i]); + rdba = ring->dma; + wr32(E1000_RDBAL(i), + rdba & 0x00000000ffffffffULL); + wr32(E1000_RDBAH(i), rdba >> 32); + wr32(E1000_RDLEN(i), + ring->count * sizeof(union e1000_adv_rx_desc)); + + ring->head = E1000_RDH(i); + ring->tail = E1000_RDT(i); + writel(0, hw->hw_addr + ring->tail); + writel(0, hw->hw_addr + ring->head); + + rxdctl = rd32(E1000_RXDCTL(i)); + rxdctl |= E1000_RXDCTL_QUEUE_ENABLE; + rxdctl &= 0xFFF00000; + rxdctl |= IGB_RX_PTHRESH; + rxdctl |= IGB_RX_HTHRESH << 8; + rxdctl |= IGB_RX_WTHRESH << 16; + wr32(E1000_RXDCTL(i), rxdctl); + } + + if (adapter->num_rx_queues > 1) { + u32 random[10]; + u32 mrqc; + u32 j, shift; + union e1000_reta { + u32 dword; + u8 bytes[4]; + } reta; + + get_random_bytes(&random[0], 40); + + shift = 6; + for (j = 0; j < (32 * 4); j++) { + reta.bytes[j & 3] = + (j % adapter->num_rx_queues) << shift; + if ((j & 3) == 3) + writel(reta.dword, + hw->hw_addr + E1000_RETA(0) + (j & ~3)); + } + mrqc = E1000_MRQC_ENABLE_RSS_4Q; + + /* Fill out hash function seeds */ + for (j = 0; j < 10; j++) + array_wr32(E1000_RSSRK(0), j, random[j]); + + mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV4_TCP); + mrqc |= (E1000_MRQC_RSS_FIELD_IPV6 | + E1000_MRQC_RSS_FIELD_IPV6_TCP); + mrqc |= (E1000_MRQC_RSS_FIELD_IPV4_UDP | + E1000_MRQC_RSS_FIELD_IPV6_UDP); + mrqc |= (E1000_MRQC_RSS_FIELD_IPV6_UDP_EX | + E1000_MRQC_RSS_FIELD_IPV6_TCP_EX); + + + wr32(E1000_MRQC, mrqc); + + /* Multiqueue and raw packet checksumming are mutually + * exclusive. Note that this not the same as TCP/IP + * checksumming, which works fine. */ + rxcsum = rd32(E1000_RXCSUM); + rxcsum |= E1000_RXCSUM_PCSD; + wr32(E1000_RXCSUM, rxcsum); + } else { + /* Enable Receive Checksum Offload for TCP and UDP */ + rxcsum = rd32(E1000_RXCSUM); + if (adapter->rx_csum) { + rxcsum |= E1000_RXCSUM_TUOFL; + + /* Enable IPv4 payload checksum for UDP fragments + * Must be used in conjunction with packet-split. */ + if (adapter->rx_ps_hdr_size) + rxcsum |= E1000_RXCSUM_IPPCSE; + } else { + rxcsum &= ~E1000_RXCSUM_TUOFL; + /* don't need to clear IPPCSE as it defaults to 0 */ + } + wr32(E1000_RXCSUM, rxcsum); + } + + if (adapter->vlgrp) + wr32(E1000_RLPML, + adapter->max_frame_size + VLAN_TAG_SIZE); + else + wr32(E1000_RLPML, adapter->max_frame_size); + + /* Enable Receives */ + wr32(E1000_RCTL, rctl); +} + +/** + * igb_free_tx_resources - Free Tx Resources per Queue + * @adapter: board private structure + * @tx_ring: Tx descriptor ring for a specific queue + * + * Free all transmit software resources + **/ +static void igb_free_tx_resources(struct igb_adapter *adapter, + struct igb_ring *tx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + igb_clean_tx_ring(adapter, tx_ring); + + vfree(tx_ring->buffer_info); + tx_ring->buffer_info = NULL; + + pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma); + + tx_ring->desc = NULL; +} + +/** + * igb_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + **/ +static void igb_free_all_tx_resources(struct igb_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + igb_free_tx_resources(adapter, &adapter->tx_ring[i]); +} + +static void igb_unmap_and_free_tx_resource(struct igb_adapter *adapter, + struct igb_buffer *buffer_info) +{ + if (buffer_info->dma) { + pci_unmap_page(adapter->pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { + dev_kfree_skb_any(buffer_info->skb); + buffer_info->skb = NULL; + } + buffer_info->time_stamp = 0; + /* buffer_info must be completely set up in the transmit path */ +} + +/** + * igb_clean_tx_ring - Free Tx Buffers + * @adapter: board private structure + * @tx_ring: ring to be cleaned + **/ +static void igb_clean_tx_ring(struct igb_adapter *adapter, + struct igb_ring *tx_ring) +{ + struct igb_buffer *buffer_info; + unsigned long size; + unsigned int i; + + if (!tx_ring->buffer_info) + return; + /* Free all the Tx ring sk_buffs */ + + for (i = 0; i < tx_ring->count; i++) { + buffer_info = &tx_ring->buffer_info[i]; + igb_unmap_and_free_tx_resource(adapter, buffer_info); + } + + size = sizeof(struct igb_buffer) * tx_ring->count; + memset(tx_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + + memset(tx_ring->desc, 0, tx_ring->size); + + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + writel(0, adapter->hw.hw_addr + tx_ring->head); + writel(0, adapter->hw.hw_addr + tx_ring->tail); +} + +/** + * igb_clean_all_tx_rings - Free Tx Buffers for all queues + * @adapter: board private structure + **/ +static void igb_clean_all_tx_rings(struct igb_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + igb_clean_tx_ring(adapter, &adapter->tx_ring[i]); +} + +/** + * igb_free_rx_resources - Free Rx Resources + * @adapter: board private structure + * @rx_ring: ring to clean the resources from + * + * Free all receive software resources + **/ +static void igb_free_rx_resources(struct igb_adapter *adapter, + struct igb_ring *rx_ring) +{ + struct pci_dev *pdev = adapter->pdev; + + igb_clean_rx_ring(adapter, rx_ring); + + vfree(rx_ring->buffer_info); + rx_ring->buffer_info = NULL; + + pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); + + rx_ring->desc = NULL; +} + +/** + * igb_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + **/ +static void igb_free_all_rx_resources(struct igb_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + igb_free_rx_resources(adapter, &adapter->rx_ring[i]); +} + +/** + * igb_clean_rx_ring - Free Rx Buffers per Queue + * @adapter: board private structure + * @rx_ring: ring to free buffers from + **/ +static void igb_clean_rx_ring(struct igb_adapter *adapter, + struct igb_ring *rx_ring) +{ + struct igb_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; + unsigned long size; + unsigned int i; + + if (!rx_ring->buffer_info) + return; + /* Free all the Rx ring sk_buffs */ + for (i = 0; i < rx_ring->count; i++) { + buffer_info = &rx_ring->buffer_info[i]; + if (buffer_info->dma) { + if (adapter->rx_ps_hdr_size) + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_hdr_size, + PCI_DMA_FROMDEVICE); + else + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len, + PCI_DMA_FROMDEVICE); + buffer_info->dma = 0; + } + + if (buffer_info->skb) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + } + if (buffer_info->page) { + pci_unmap_page(pdev, buffer_info->page_dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + put_page(buffer_info->page); + buffer_info->page = NULL; + buffer_info->page_dma = 0; + } + } + + /* there also may be some cached data from a chained receive */ + if (rx_ring->pending_skb) { + dev_kfree_skb(rx_ring->pending_skb); + rx_ring->pending_skb = NULL; + } + + size = sizeof(struct igb_buffer) * rx_ring->count; + memset(rx_ring->buffer_info, 0, size); + + /* Zero out the descriptor ring */ + memset(rx_ring->desc, 0, rx_ring->size); + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + writel(0, adapter->hw.hw_addr + rx_ring->head); + writel(0, adapter->hw.hw_addr + rx_ring->tail); +} + +/** + * igb_clean_all_rx_rings - Free Rx Buffers for all queues + * @adapter: board private structure + **/ +static void igb_clean_all_rx_rings(struct igb_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + igb_clean_rx_ring(adapter, &adapter->rx_ring[i]); +} + +/** + * igb_set_mac - Change the Ethernet Address of the NIC + * @netdev: network interface device structure + * @p: pointer to an address structure + * + * Returns 0 on success, negative on failure + **/ +static int igb_set_mac(struct net_device *netdev, void *p) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); + memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len); + + adapter->hw.mac.ops.rar_set(&adapter->hw, adapter->hw.mac.addr, 0); + + return 0; +} + +/** + * igb_set_multi - Multicast and Promiscuous mode set + * @netdev: network interface device structure + * + * The set_multi entry point is called whenever the multicast address + * list or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper multicast, + * promiscuous mode, and all-multi behavior. + **/ +static void igb_set_multi(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + struct e1000_mac_info *mac = &hw->mac; + struct dev_mc_list *mc_ptr; + u8 *mta_list; + u32 rctl; + int i; + + /* Check for Promiscuous and All Multicast modes */ + + rctl = rd32(E1000_RCTL); + + if (netdev->flags & IFF_PROMISC) + rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); + else if (netdev->flags & IFF_ALLMULTI) { + rctl |= E1000_RCTL_MPE; + rctl &= ~E1000_RCTL_UPE; + } else + rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); + + wr32(E1000_RCTL, rctl); + + if (!netdev->mc_count) { + /* nothing to program, so clear mc list */ + igb_update_mc_addr_list(hw, NULL, 0, 1, + mac->rar_entry_count); + return; + } + + mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC); + if (!mta_list) + return; + + /* The shared function expects a packed array of only addresses. */ + mc_ptr = netdev->mc_list; + + for (i = 0; i < netdev->mc_count; i++) { + if (!mc_ptr) + break; + memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN); + mc_ptr = mc_ptr->next; + } + igb_update_mc_addr_list(hw, mta_list, i, 1, mac->rar_entry_count); + kfree(mta_list); +} + +/* Need to wait a few seconds after link up to get diagnostic information from + * the phy */ +static void igb_update_phy_info(unsigned long data) +{ + struct igb_adapter *adapter = (struct igb_adapter *) data; + adapter->hw.phy.ops.get_phy_info(&adapter->hw); +} + +/** + * igb_watchdog - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ +static void igb_watchdog(unsigned long data) +{ + struct igb_adapter *adapter = (struct igb_adapter *)data; + /* Do the rest outside of interrupt context */ + schedule_work(&adapter->watchdog_task); +} + +static void igb_watchdog_task(struct work_struct *work) +{ + struct igb_adapter *adapter = container_of(work, + struct igb_adapter, watchdog_task); + struct e1000_hw *hw = &adapter->hw; + + struct net_device *netdev = adapter->netdev; + struct igb_ring *tx_ring = adapter->tx_ring; + struct e1000_mac_info *mac = &adapter->hw.mac; + u32 link; + s32 ret_val; + + if ((netif_carrier_ok(netdev)) && + (rd32(E1000_STATUS) & E1000_STATUS_LU)) + goto link_up; + + ret_val = hw->mac.ops.check_for_link(&adapter->hw); + if ((ret_val == E1000_ERR_PHY) && + (hw->phy.type == e1000_phy_igp_3) && + (rd32(E1000_CTRL) & + E1000_PHY_CTRL_GBE_DISABLE)) + dev_info(&adapter->pdev->dev, + "Gigabit has been disabled, downgrading speed\n"); + + if ((hw->phy.media_type == e1000_media_type_internal_serdes) && + !(rd32(E1000_TXCW) & E1000_TXCW_ANE)) + link = mac->serdes_has_link; + else + link = rd32(E1000_STATUS) & + E1000_STATUS_LU; + + if (link) { + if (!netif_carrier_ok(netdev)) { + u32 ctrl; + hw->mac.ops.get_speed_and_duplex(&adapter->hw, + &adapter->link_speed, + &adapter->link_duplex); + + ctrl = rd32(E1000_CTRL); + dev_info(&adapter->pdev->dev, + "NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? + "Full Duplex" : "Half Duplex", + ((ctrl & E1000_CTRL_TFCE) && (ctrl & + E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl & + E1000_CTRL_RFCE) ? "RX" : ((ctrl & + E1000_CTRL_TFCE) ? "TX" : "None"))); + + /* tweak tx_queue_len according to speed/duplex and + * adjust the timeout factor */ + netdev->tx_queue_len = adapter->tx_queue_len; + adapter->tx_timeout_factor = 1; + switch (adapter->link_speed) { + case SPEED_10: + netdev->tx_queue_len = 10; + adapter->tx_timeout_factor = 14; + break; + case SPEED_100: + netdev->tx_queue_len = 100; + /* maybe add some timeout factor ? */ + break; + } + + netif_carrier_on(netdev); + netif_wake_queue(netdev); + + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + } + } else { + if (netif_carrier_ok(netdev)) { + adapter->link_speed = 0; + adapter->link_duplex = 0; + dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->phy_info_timer, + round_jiffies(jiffies + 2 * HZ)); + } + } + +link_up: + igb_update_stats(adapter); + + mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; + adapter->tpt_old = adapter->stats.tpt; + mac->collision_delta = adapter->stats.colc - adapter->colc_old; + adapter->colc_old = adapter->stats.colc; + + adapter->gorc = adapter->stats.gorc - adapter->gorc_old; + adapter->gorc_old = adapter->stats.gorc; + adapter->gotc = adapter->stats.gotc - adapter->gotc_old; + adapter->gotc_old = adapter->stats.gotc; + + igb_update_adaptive(&adapter->hw); + + if (!netif_carrier_ok(netdev)) { + if (IGB_DESC_UNUSED(tx_ring) + 1 < tx_ring->count) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + } + } + + /* Cause software interrupt to ensure rx ring is cleaned */ + wr32(E1000_ICS, E1000_ICS_RXDMT0); + + /* Force detection of hung controller every watchdog period */ + tx_ring->detect_tx_hung = true; + + /* Reset the timer */ + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 2 * HZ)); +} + +enum latency_range { + lowest_latency = 0, + low_latency = 1, + bulk_latency = 2, + latency_invalid = 255 +}; + + +static void igb_lower_rx_eitr(struct igb_adapter *adapter, + struct igb_ring *rx_ring) +{ + struct e1000_hw *hw = &adapter->hw; + int new_val; + + new_val = rx_ring->itr_val / 2; + if (new_val < IGB_MIN_DYN_ITR) + new_val = IGB_MIN_DYN_ITR; + + if (new_val != rx_ring->itr_val) { + rx_ring->itr_val = new_val; + wr32(rx_ring->itr_register, + 1000000000 / (new_val * 256)); + } +} + +static void igb_raise_rx_eitr(struct igb_adapter *adapter, + struct igb_ring *rx_ring) +{ + struct e1000_hw *hw = &adapter->hw; + int new_val; + + new_val = rx_ring->itr_val * 2; + if (new_val > IGB_MAX_DYN_ITR) + new_val = IGB_MAX_DYN_ITR; + + if (new_val != rx_ring->itr_val) { + rx_ring->itr_val = new_val; + wr32(rx_ring->itr_register, + 1000000000 / (new_val * 256)); + } +} + +/** + * igb_update_itr - update the dynamic ITR value based on statistics + * Stores a new ITR value based on packets and byte + * counts during the last interrupt. The advantage of per interrupt + * computation is faster updates and more accurate ITR for the current + * traffic pattern. Constants in this function were computed + * based on theoretical maximum wire speed and thresholds were set based + * on testing data as well as attempting to minimize response time + * while increasing bulk throughput. + * this functionality is controlled by the InterruptThrottleRate module + * parameter (see igb_param.c) + * NOTE: These calculations are only valid when operating in a single- + * queue environment. + * @adapter: pointer to adapter + * @itr_setting: current adapter->itr + * @packets: the number of packets during this measurement interval + * @bytes: the number of bytes during this measurement interval + **/ +static unsigned int igb_update_itr(struct igb_adapter *adapter, u16 itr_setting, + int packets, int bytes) +{ + unsigned int retval = itr_setting; + + if (packets == 0) + goto update_itr_done; + + switch (itr_setting) { + case lowest_latency: + /* handle TSO and jumbo frames */ + if (bytes/packets > 8000) + retval = bulk_latency; + else if ((packets < 5) && (bytes > 512)) + retval = low_latency; + break; + case low_latency: /* 50 usec aka 20000 ints/s */ + if (bytes > 10000) { + /* this if handles the TSO accounting */ + if (bytes/packets > 8000) { + retval = bulk_latency; + } else if ((packets < 10) || ((bytes/packets) > 1200)) { + retval = bulk_latency; + } else if ((packets > 35)) { + retval = lowest_latency; + } + } else if (bytes/packets > 2000) { + retval = bulk_latency; + } else if (packets <= 2 && bytes < 512) { + retval = lowest_latency; + } + break; + case bulk_latency: /* 250 usec aka 4000 ints/s */ + if (bytes > 25000) { + if (packets > 35) + retval = low_latency; + } else if (bytes < 6000) { + retval = low_latency; + } + break; + } + +update_itr_done: + return retval; +} + +static void igb_set_itr(struct igb_adapter *adapter, u16 itr_register, + int rx_only) +{ + u16 current_itr; + u32 new_itr = adapter->itr; + + /* for non-gigabit speeds, just fix the interrupt rate at 4000 */ + if (adapter->link_speed != SPEED_1000) { + current_itr = 0; + new_itr = 4000; + goto set_itr_now; + } + + adapter->rx_itr = igb_update_itr(adapter, + adapter->rx_itr, + adapter->rx_ring->total_packets, + adapter->rx_ring->total_bytes); + /* conservative mode (itr 3) eliminates the lowest_latency setting */ + if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency) + adapter->rx_itr = low_latency; + + if (!rx_only) { + adapter->tx_itr = igb_update_itr(adapter, + adapter->tx_itr, + adapter->tx_ring->total_packets, + adapter->tx_ring->total_bytes); + /* conservative mode (itr 3) eliminates the + * lowest_latency setting */ + if (adapter->itr_setting == 3 && + adapter->tx_itr == lowest_latency) + adapter->tx_itr = low_latency; + + current_itr = max(adapter->rx_itr, adapter->tx_itr); + } else { + current_itr = adapter->rx_itr; + } + + switch (current_itr) { + /* counts and packets in update_itr are dependent on these numbers */ + case lowest_latency: + new_itr = 70000; + break; + case low_latency: + new_itr = 20000; /* aka hwitr = ~200 */ + break; + case bulk_latency: + new_itr = 4000; + break; + default: + break; + } + +set_itr_now: + if (new_itr != adapter->itr) { + /* this attempts to bias the interrupt rate towards Bulk + * by adding intermediate steps when interrupt rate is + * increasing */ + new_itr = new_itr > adapter->itr ? + min(adapter->itr + (new_itr >> 2), new_itr) : + new_itr; + /* Don't write the value here; it resets the adapter's + * internal timer, and causes us to delay far longer than + * we should between interrupts. Instead, we write the ITR + * value at the beginning of the next interrupt so the timing + * ends up being correct. + */ + adapter->itr = new_itr; + adapter->set_itr = 1; + } + + return; +} + + +#define IGB_TX_FLAGS_CSUM 0x00000001 +#define IGB_TX_FLAGS_VLAN 0x00000002 +#define IGB_TX_FLAGS_TSO 0x00000004 +#define IGB_TX_FLAGS_IPV4 0x00000008 +#define IGB_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IGB_TX_FLAGS_VLAN_SHIFT 16 + +static inline int igb_tso_adv(struct igb_adapter *adapter, + struct igb_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags, u8 *hdr_len) +{ + struct e1000_adv_tx_context_desc *context_desc; + unsigned int i; + int err; + struct igb_buffer *buffer_info; + u32 info = 0, tu_cmd = 0; + u32 mss_l4len_idx, l4len; + *hdr_len = 0; + + if (skb_header_cloned(skb)) { + err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); + if (err) + return err; + } + + l4len = tcp_hdrlen(skb); + *hdr_len += l4len; + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *iph = ip_hdr(skb); + iph->tot_len = 0; + iph->check = 0; + tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr, + iph->daddr, 0, + IPPROTO_TCP, + 0); + } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0); + } + + i = tx_ring->next_to_use; + + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i); + /* VLAN MACLEN IPLEN */ + if (tx_flags & IGB_TX_FLAGS_VLAN) + info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK); + info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT); + *hdr_len += skb_network_offset(skb); + info |= skb_network_header_len(skb); + *hdr_len += skb_network_header_len(skb); + context_desc->vlan_macip_lens = cpu_to_le32(info); + + /* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */ + tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT); + + if (skb->protocol == htons(ETH_P_IP)) + tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + + context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd); + + /* MSS L4LEN IDX */ + mss_l4len_idx = (skb_shinfo(skb)->gso_size << E1000_ADVTXD_MSS_SHIFT); + mss_l4len_idx |= (l4len << E1000_ADVTXD_L4LEN_SHIFT); + + /* Context index must be unique per ring. Luckily, so is the interrupt + * mask value. */ + mss_l4len_idx |= tx_ring->eims_value >> 4; + + context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx); + context_desc->seqnum_seed = 0; + + buffer_info->time_stamp = jiffies; + buffer_info->dma = 0; + i++; + if (i == tx_ring->count) + i = 0; + + tx_ring->next_to_use = i; + + return true; +} + +static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, + struct igb_ring *tx_ring, + struct sk_buff *skb, u32 tx_flags) +{ + struct e1000_adv_tx_context_desc *context_desc; + unsigned int i; + struct igb_buffer *buffer_info; + u32 info = 0, tu_cmd = 0; + + if ((skb->ip_summed == CHECKSUM_PARTIAL) || + (tx_flags & IGB_TX_FLAGS_VLAN)) { + i = tx_ring->next_to_use; + buffer_info = &tx_ring->buffer_info[i]; + context_desc = E1000_TX_CTXTDESC_ADV(*tx_ring, i); + + if (tx_flags & IGB_TX_FLAGS_VLAN) + info |= (tx_flags & IGB_TX_FLAGS_VLAN_MASK); + info |= (skb_network_offset(skb) << E1000_ADVTXD_MACLEN_SHIFT); + if (skb->ip_summed == CHECKSUM_PARTIAL) + info |= skb_network_header_len(skb); + + context_desc->vlan_macip_lens = cpu_to_le32(info); + + tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT); + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb->protocol == htons(ETH_P_IP)) + tu_cmd |= E1000_ADVTXD_TUCMD_IPV4; + if (skb->sk && (skb->sk->sk_protocol == IPPROTO_TCP)) + tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP; + } + + context_desc->type_tucmd_mlhl = cpu_to_le32(tu_cmd); + context_desc->seqnum_seed = 0; + context_desc->mss_l4len_idx = + cpu_to_le32(tx_ring->eims_value >> 4); + + buffer_info->time_stamp = jiffies; + buffer_info->dma = 0; + + i++; + if (i == tx_ring->count) + i = 0; + tx_ring->next_to_use = i; + + return true; + } + + + return false; +} + +#define IGB_MAX_TXD_PWR 16 +#define IGB_MAX_DATA_PER_TXD (1<<IGB_MAX_TXD_PWR) + +static inline int igb_tx_map_adv(struct igb_adapter *adapter, + struct igb_ring *tx_ring, + struct sk_buff *skb) +{ + struct igb_buffer *buffer_info; + unsigned int len = skb_headlen(skb); + unsigned int count = 0, i; + unsigned int f; + + i = tx_ring->next_to_use; + + buffer_info = &tx_ring->buffer_info[i]; + BUG_ON(len >= IGB_MAX_DATA_PER_TXD); + buffer_info->length = len; + /* set time_stamp *before* dma to help avoid a possible race */ + buffer_info->time_stamp = jiffies; + buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len, + PCI_DMA_TODEVICE); + count++; + i++; + if (i == tx_ring->count) + i = 0; + + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { + struct skb_frag_struct *frag; + + frag = &skb_shinfo(skb)->frags[f]; + len = frag->size; + + buffer_info = &tx_ring->buffer_info[i]; + BUG_ON(len >= IGB_MAX_DATA_PER_TXD); + buffer_info->length = len; + buffer_info->time_stamp = jiffies; + buffer_info->dma = pci_map_page(adapter->pdev, + frag->page, + frag->page_offset, + len, + PCI_DMA_TODEVICE); + + count++; + i++; + if (i == tx_ring->count) + i = 0; + } + + i = (i == 0) ? tx_ring->count - 1 : i - 1; + tx_ring->buffer_info[i].skb = skb; + + return count; +} + +static inline void igb_tx_queue_adv(struct igb_adapter *adapter, + struct igb_ring *tx_ring, + int tx_flags, int count, u32 paylen, + u8 hdr_len) +{ + union e1000_adv_tx_desc *tx_desc = NULL; + struct igb_buffer *buffer_info; + u32 olinfo_status = 0, cmd_type_len; + unsigned int i; + + cmd_type_len = (E1000_ADVTXD_DTYP_DATA | E1000_ADVTXD_DCMD_IFCS | + E1000_ADVTXD_DCMD_DEXT); + + if (tx_flags & IGB_TX_FLAGS_VLAN) + cmd_type_len |= E1000_ADVTXD_DCMD_VLE; + + if (tx_flags & IGB_TX_FLAGS_TSO) { + cmd_type_len |= E1000_ADVTXD_DCMD_TSE; + + /* insert tcp checksum */ + olinfo_status |= E1000_TXD_POPTS_TXSM << 8; + + /* insert ip checksum */ + if (tx_flags & IGB_TX_FLAGS_IPV4) + olinfo_status |= E1000_TXD_POPTS_IXSM << 8; + + } else if (tx_flags & IGB_TX_FLAGS_CSUM) { + olinfo_status |= E1000_TXD_POPTS_TXSM << 8; + } + + if (tx_flags & (IGB_TX_FLAGS_CSUM | IGB_TX_FLAGS_TSO | + IGB_TX_FLAGS_VLAN)) + olinfo_status |= tx_ring->eims_value >> 4; + + olinfo_status |= ((paylen - hdr_len) << E1000_ADVTXD_PAYLEN_SHIFT); + + i = tx_ring->next_to_use; + while (count--) { + buffer_info = &tx_ring->buffer_info[i]; + tx_desc = E1000_TX_DESC_ADV(*tx_ring, i); + tx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma); + tx_desc->read.cmd_type_len = + cpu_to_le32(cmd_type_len | buffer_info->length); + tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status); + i++; + if (i == tx_ring->count) + i = 0; + } + + tx_desc->read.cmd_type_len |= cpu_to_le32(adapter->txd_cmd); + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + + tx_ring->next_to_use = i; + writel(i, adapter->hw.hw_addr + tx_ring->tail); + /* we need this if more than one processor can write to our tail + * at a time, it syncronizes IO on IA64/Altix systems */ + mmiowb(); +} + +static int __igb_maybe_stop_tx(struct net_device *netdev, + struct igb_ring *tx_ring, int size) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + netif_stop_queue(netdev); + /* Herbert's original patch had: + * smp_mb__after_netif_stop_queue(); + * but since that doesn't exist yet, just open code it. */ + smp_mb(); + + /* We need to check again in a case another CPU has just + * made room available. */ + if (IGB_DESC_UNUSED(tx_ring) < size) + return -EBUSY; + + /* A reprieve! */ + netif_start_queue(netdev); + ++adapter->restart_queue; + return 0; +} + +static int igb_maybe_stop_tx(struct net_device *netdev, + struct igb_ring *tx_ring, int size) +{ + if (IGB_DESC_UNUSED(tx_ring) >= size) + return 0; + return __igb_maybe_stop_tx(netdev, tx_ring, size); +} + +#define TXD_USE_COUNT(S) (((S) >> (IGB_MAX_TXD_PWR)) + 1) + +static int igb_xmit_frame_ring_adv(struct sk_buff *skb, + struct net_device *netdev, + struct igb_ring *tx_ring) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + unsigned int tx_flags = 0; + unsigned int len; + unsigned long irq_flags; + u8 hdr_len = 0; + int tso = 0; + + len = skb_headlen(skb); + + if (test_bit(__IGB_DOWN, &adapter->state)) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (skb->len <= 0) { + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + + if (!spin_trylock_irqsave(&tx_ring->tx_lock, irq_flags)) + /* Collision - tell upper layer to requeue */ + return NETDEV_TX_LOCKED; + + /* need: 1 descriptor per page, + * + 2 desc gap to keep tail from touching head, + * + 1 desc for skb->data, + * + 1 desc for context descriptor, + * otherwise try next time */ + if (igb_maybe_stop_tx(netdev, tx_ring, skb_shinfo(skb)->nr_frags + 4)) { + /* this is a hard error */ + spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); + return NETDEV_TX_BUSY; + } + + if (adapter->vlgrp && vlan_tx_tag_present(skb)) { + tx_flags |= IGB_TX_FLAGS_VLAN; + tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT); + } + + tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags, + &hdr_len) : 0; + + if (tso < 0) { + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); + return NETDEV_TX_OK; + } + + if (tso) + tx_flags |= IGB_TX_FLAGS_TSO; + else if (igb_tx_csum_adv(adapter, tx_ring, skb, tx_flags)) + if (skb->ip_summed == CHECKSUM_PARTIAL) + tx_flags |= IGB_TX_FLAGS_CSUM; + + if (skb->protocol == htons(ETH_P_IP)) + tx_flags |= IGB_TX_FLAGS_IPV4; + + igb_tx_queue_adv(adapter, tx_ring, tx_flags, + igb_tx_map_adv(adapter, tx_ring, skb), + skb->len, hdr_len); + + netdev->trans_start = jiffies; + + /* Make sure there is space in the ring for the next send. */ + igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4); + + spin_unlock_irqrestore(&tx_ring->tx_lock, irq_flags); + return NETDEV_TX_OK; +} + +static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct igb_ring *tx_ring = &adapter->tx_ring[0]; + + /* This goes back to the question of how to logically map a tx queue + * to a flow. Right now, performance is impacted slightly negatively + * if using multiple tx queues. If the stack breaks away from a + * single qdisc implementation, we can look at this again. */ + return (igb_xmit_frame_ring_adv(skb, netdev, tx_ring)); +} + +/** + * igb_tx_timeout - Respond to a Tx Hang + * @netdev: network interface device structure + **/ +static void igb_tx_timeout(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + /* Do the reset outside of interrupt context */ + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); + wr32(E1000_EICS, adapter->eims_enable_mask & + ~(E1000_EIMS_TCP_TIMER | E1000_EIMS_OTHER)); +} + +static void igb_reset_task(struct work_struct *work) +{ + struct igb_adapter *adapter; + adapter = container_of(work, struct igb_adapter, reset_task); + + igb_reinit_locked(adapter); +} + +/** + * igb_get_stats - Get System Network Statistics + * @netdev: network interface device structure + * + * Returns the address of the device statistics structure. + * The statistics are actually updated from the timer callback. + **/ +static struct net_device_stats * +igb_get_stats(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + + /* only return the current stats */ + return &adapter->net_stats; +} + +/** + * igb_change_mtu - Change the Maximum Transfer Unit + * @netdev: network interface device structure + * @new_mtu: new value for maximum frame size + * + * Returns 0 on success, negative on failure + **/ +static int igb_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + + if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || + (max_frame > MAX_JUMBO_FRAME_SIZE)) { + dev_err(&adapter->pdev->dev, "Invalid MTU setting\n"); + return -EINVAL; + } + +#define MAX_STD_JUMBO_FRAME_SIZE 9234 + if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { + dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n"); + return -EINVAL; + } + + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) + msleep(1); + /* igb_down has a dependency on max_frame_size */ + adapter->max_frame_size = max_frame; + if (netif_running(netdev)) + igb_down(adapter); + + /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN + * means we reserve 2 more, this pushes us to allocate from the next + * larger slab size. + * i.e. RXBUFFER_2048 --> size-4096 slab + */ + + if (max_frame <= IGB_RXBUFFER_256) + adapter->rx_buffer_len = IGB_RXBUFFER_256; + else if (max_frame <= IGB_RXBUFFER_512) + adapter->rx_buffer_len = IGB_RXBUFFER_512; + else if (max_frame <= IGB_RXBUFFER_1024) + adapter->rx_buffer_len = IGB_RXBUFFER_1024; + else if (max_frame <= IGB_RXBUFFER_2048) + adapter->rx_buffer_len = IGB_RXBUFFER_2048; + else + adapter->rx_buffer_len = IGB_RXBUFFER_4096; + /* adjust allocation if LPE protects us, and we aren't using SBP */ + if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) || + (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)) + adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; + + dev_info(&adapter->pdev->dev, "changing MTU from %d to %d\n", + netdev->mtu, new_mtu); + netdev->mtu = new_mtu; + + if (netif_running(netdev)) + igb_up(adapter); + else + igb_reset(adapter); + + clear_bit(__IGB_RESETTING, &adapter->state); + + return 0; +} + +/** + * igb_update_stats - Update the board statistics counters + * @adapter: board private structure + **/ + +void igb_update_stats(struct igb_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; + u16 phy_tmp; + +#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF + + /* + * Prevent stats update while adapter is being reset, or if the pci + * connection is down. + */ + if (adapter->link_speed == 0) + return; + if (pci_channel_offline(pdev)) + return; + + adapter->stats.crcerrs += rd32(E1000_CRCERRS); + adapter->stats.gprc += rd32(E1000_GPRC); + adapter->stats.gorc += rd32(E1000_GORCL); + rd32(E1000_GORCH); /* clear GORCL */ + adapter->stats.bprc += rd32(E1000_BPRC); + adapter->stats.mprc += rd32(E1000_MPRC); + adapter->stats.roc += rd32(E1000_ROC); + + adapter->stats.prc64 += rd32(E1000_PRC64); + adapter->stats.prc127 += rd32(E1000_PRC127); + adapter->stats.prc255 += rd32(E1000_PRC255); + adapter->stats.prc511 += rd32(E1000_PRC511); + adapter->stats.prc1023 += rd32(E1000_PRC1023); + adapter->stats.prc1522 += rd32(E1000_PRC1522); + adapter->stats.symerrs += rd32(E1000_SYMERRS); + adapter->stats.sec += rd32(E1000_SEC); + + adapter->stats.mpc += rd32(E1000_MPC); + adapter->stats.scc += rd32(E1000_SCC); + adapter->stats.ecol += rd32(E1000_ECOL); + adapter->stats.mcc += rd32(E1000_MCC); + adapter->stats.latecol += rd32(E1000_LATECOL); + adapter->stats.dc += rd32(E1000_DC); + adapter->stats.rlec += rd32(E1000_RLEC); + adapter->stats.xonrxc += rd32(E1000_XONRXC); + adapter->stats.xontxc += rd32(E1000_XONTXC); + adapter->stats.xoffrxc += rd32(E1000_XOFFRXC); + adapter->stats.xofftxc += rd32(E1000_XOFFTXC); + adapter->stats.fcruc += rd32(E1000_FCRUC); + adapter->stats.gptc += rd32(E1000_GPTC); + adapter->stats.gotc += rd32(E1000_GOTCL); + rd32(E1000_GOTCH); /* clear GOTCL */ + adapter->stats.rnbc += rd32(E1000_RNBC); + adapter->stats.ruc += rd32(E1000_RUC); + adapter->stats.rfc += rd32(E1000_RFC); + adapter->stats.rjc += rd32(E1000_RJC); + adapter->stats.tor += rd32(E1000_TORH); + adapter->stats.tot += rd32(E1000_TOTH); + adapter->stats.tpr += rd32(E1000_TPR); + + adapter->stats.ptc64 += rd32(E1000_PTC64); + adapter->stats.ptc127 += rd32(E1000_PTC127); + adapter->stats.ptc255 += rd32(E1000_PTC255); + adapter->stats.ptc511 += rd32(E1000_PTC511); + adapter->stats.ptc1023 += rd32(E1000_PTC1023); + adapter->stats.ptc1522 += rd32(E1000_PTC1522); + + adapter->stats.mptc += rd32(E1000_MPTC); + adapter->stats.bptc += rd32(E1000_BPTC); + + /* used for adaptive IFS */ + + hw->mac.tx_packet_delta = rd32(E1000_TPT); + adapter->stats.tpt += hw->mac.tx_packet_delta; + hw->mac.collision_delta = rd32(E1000_COLC); + adapter->stats.colc += hw->mac.collision_delta; + + adapter->stats.algnerrc += rd32(E1000_ALGNERRC); + adapter->stats.rxerrc += rd32(E1000_RXERRC); + adapter->stats.tncrs += rd32(E1000_TNCRS); + adapter->stats.tsctc += rd32(E1000_TSCTC); + adapter->stats.tsctfc += rd32(E1000_TSCTFC); + + adapter->stats.iac += rd32(E1000_IAC); + adapter->stats.icrxoc += rd32(E1000_ICRXOC); + adapter->stats.icrxptc += rd32(E1000_ICRXPTC); + adapter->stats.icrxatc += rd32(E1000_ICRXATC); + adapter->stats.ictxptc += rd32(E1000_ICTXPTC); + adapter->stats.ictxatc += rd32(E1000_ICTXATC); + adapter->stats.ictxqec += rd32(E1000_ICTXQEC); + adapter->stats.ictxqmtc += rd32(E1000_ICTXQMTC); + adapter->stats.icrxdmtc += rd32(E1000_ICRXDMTC); + + /* Fill out the OS statistics structure */ + adapter->net_stats.multicast = adapter->stats.mprc; + adapter->net_stats.collisions = adapter->stats.colc; + + /* Rx Errors */ + + /* RLEC on some newer hardware can be incorrect so build + * our own version based on RUC and ROC */ + adapter->net_stats.rx_errors = adapter->stats.rxerrc + + adapter->stats.crcerrs + adapter->stats.algnerrc + + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.cexterr; + adapter->net_stats.rx_length_errors = adapter->stats.ruc + + adapter->stats.roc; + adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; + adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; + adapter->net_stats.rx_missed_errors = adapter->stats.mpc; + + /* Tx Errors */ + adapter->net_stats.tx_errors = adapter->stats.ecol + + adapter->stats.latecol; + adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; + adapter->net_stats.tx_window_errors = adapter->stats.latecol; + adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; + + /* Tx Dropped needs to be maintained elsewhere */ + + /* Phy Stats */ + if (hw->phy.media_type == e1000_media_type_copper) { + if ((adapter->link_speed == SPEED_1000) && + (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS, + &phy_tmp))) { + phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; + adapter->phy_stats.idle_errors += phy_tmp; + } + } + + /* Management Stats */ + adapter->stats.mgptc += rd32(E1000_MGTPTC); + adapter->stats.mgprc += rd32(E1000_MGTPRC); + adapter->stats.mgpdc += rd32(E1000_MGTPDC); +} + + +static irqreturn_t igb_msix_other(int irq, void *data) +{ + struct net_device *netdev = data; + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 eicr; + /* disable interrupts from the "other" bit, avoid re-entry */ + wr32(E1000_EIMC, E1000_EIMS_OTHER); + + eicr = rd32(E1000_EICR); + + if (eicr & E1000_EIMS_OTHER) { + u32 icr = rd32(E1000_ICR); + /* reading ICR causes bit 31 of EICR to be cleared */ + if (!(icr & E1000_ICR_LSC)) + goto no_link_interrupt; + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + +no_link_interrupt: + wr32(E1000_IMS, E1000_IMS_LSC); + wr32(E1000_EIMS, E1000_EIMS_OTHER); + + return IRQ_HANDLED; +} + +static irqreturn_t igb_msix_tx(int irq, void *data) +{ + struct igb_ring *tx_ring = data; + struct igb_adapter *adapter = tx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + + if (!tx_ring->itr_val) + wr32(E1000_EIMC, tx_ring->eims_value); + + tx_ring->total_bytes = 0; + tx_ring->total_packets = 0; + if (!igb_clean_tx_irq(adapter, tx_ring)) + /* Ring was not completely cleaned, so fire another interrupt */ + wr32(E1000_EICS, tx_ring->eims_value); + + if (!tx_ring->itr_val) + wr32(E1000_EIMS, tx_ring->eims_value); + return IRQ_HANDLED; +} + +static irqreturn_t igb_msix_rx(int irq, void *data) +{ + struct igb_ring *rx_ring = data; + struct igb_adapter *adapter = rx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + + if (!rx_ring->itr_val) + wr32(E1000_EIMC, rx_ring->eims_value); + + if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) { + rx_ring->total_bytes = 0; + rx_ring->total_packets = 0; + rx_ring->no_itr_adjust = 0; + __netif_rx_schedule(adapter->netdev, &rx_ring->napi); + } else { + if (!rx_ring->no_itr_adjust) { + igb_lower_rx_eitr(adapter, rx_ring); + rx_ring->no_itr_adjust = 1; + } + } + + return IRQ_HANDLED; +} + + +/** + * igb_intr_msi - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t igb_intr_msi(int irq, void *data) +{ + struct net_device *netdev = data; + struct igb_adapter *adapter = netdev_priv(netdev); + struct napi_struct *napi = &adapter->napi; + struct e1000_hw *hw = &adapter->hw; + /* read ICR disables interrupts using IAM */ + u32 icr = rd32(E1000_ICR); + + /* Write the ITR value calculated at the end of the + * previous interrupt. + */ + if (adapter->set_itr) { + wr32(E1000_ITR, + 1000000000 / (adapter->itr * 256)); + adapter->set_itr = 0; + } + + /* read ICR disables interrupts using IAM */ + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + if (netif_rx_schedule_prep(netdev, napi)) { + adapter->tx_ring->total_bytes = 0; + adapter->tx_ring->total_packets = 0; + adapter->rx_ring->total_bytes = 0; + adapter->rx_ring->total_packets = 0; + __netif_rx_schedule(netdev, napi); + } + + return IRQ_HANDLED; +} + +/** + * igb_intr - Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t igb_intr(int irq, void *data) +{ + struct net_device *netdev = data; + struct igb_adapter *adapter = netdev_priv(netdev); + struct napi_struct *napi = &adapter->napi; + struct e1000_hw *hw = &adapter->hw; + /* Interrupt Auto-Mask...upon reading ICR, interrupts are masked. No + * need for the IMC write */ + u32 icr = rd32(E1000_ICR); + u32 eicr = 0; + if (!icr) + return IRQ_NONE; /* Not our interrupt */ + + /* Write the ITR value calculated at the end of the + * previous interrupt. + */ + if (adapter->set_itr) { + wr32(E1000_ITR, + 1000000000 / (adapter->itr * 256)); + adapter->set_itr = 0; + } + + /* IMS will not auto-mask if INT_ASSERTED is not set, and if it is + * not set, then the adapter didn't send an interrupt */ + if (!(icr & E1000_ICR_INT_ASSERTED)) + return IRQ_NONE; + + eicr = rd32(E1000_EICR); + + if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { + hw->mac.get_link_status = 1; + /* guard against interrupt when we're going down */ + if (!test_bit(__IGB_DOWN, &adapter->state)) + mod_timer(&adapter->watchdog_timer, jiffies + 1); + } + + if (netif_rx_schedule_prep(netdev, napi)) { + adapter->tx_ring->total_bytes = 0; + adapter->rx_ring->total_bytes = 0; + adapter->tx_ring->total_packets = 0; + adapter->rx_ring->total_packets = 0; + __netif_rx_schedule(netdev, napi); + } + + return IRQ_HANDLED; +} + +/** + * igb_clean - NAPI Rx polling callback + * @adapter: board private structure + **/ +static int igb_clean(struct napi_struct *napi, int budget) +{ + struct igb_adapter *adapter = container_of(napi, struct igb_adapter, + napi); + struct net_device *netdev = adapter->netdev; + int tx_clean_complete = 1, work_done = 0; + int i; + + /* Must NOT use netdev_priv macro here. */ + adapter = netdev->priv; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(netdev)) + goto quit_polling; + + /* igb_clean is called per-cpu. This lock protects tx_ring[i] from + * being cleaned by multiple cpus simultaneously. A failure obtaining + * the lock means tx_ring[i] is currently being cleaned anyway. */ + for (i = 0; i < adapter->num_tx_queues; i++) { + if (spin_trylock(&adapter->tx_ring[i].tx_clean_lock)) { + tx_clean_complete &= igb_clean_tx_irq(adapter, + &adapter->tx_ring[i]); + spin_unlock(&adapter->tx_ring[i].tx_clean_lock); + } + } + + for (i = 0; i < adapter->num_rx_queues; i++) + igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i], &work_done, + adapter->rx_ring[i].napi.weight); + + /* If no Tx and not enough Rx work done, exit the polling mode */ + if ((tx_clean_complete && (work_done < budget)) || + !netif_running(netdev)) { +quit_polling: + if (adapter->itr_setting & 3) + igb_set_itr(adapter, E1000_ITR, false); + netif_rx_complete(netdev, napi); + if (!test_bit(__IGB_DOWN, &adapter->state)) + igb_irq_enable(adapter); + return 0; + } + + return 1; +} + +static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) +{ + struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi); + struct igb_adapter *adapter = rx_ring->adapter; + struct e1000_hw *hw = &adapter->hw; + struct net_device *netdev = adapter->netdev; + int work_done = 0; + + /* Keep link state information with original netdev */ + if (!netif_carrier_ok(netdev)) + goto quit_polling; + + igb_clean_rx_irq_adv(adapter, rx_ring, &work_done, budget); + + + /* If not enough Rx work done, exit the polling mode */ + if ((work_done == 0) || !netif_running(netdev)) { +quit_polling: + netif_rx_complete(netdev, napi); + + wr32(E1000_EIMS, rx_ring->eims_value); + if ((adapter->itr_setting & 3) && !rx_ring->no_itr_adjust && + (rx_ring->total_packets > IGB_DYN_ITR_PACKET_THRESHOLD)) { + int mean_size = rx_ring->total_bytes / + rx_ring->total_packets; + if (mean_size < IGB_DYN_ITR_LENGTH_LOW) + igb_raise_rx_eitr(adapter, rx_ring); + else if (mean_size > IGB_DYN_ITR_LENGTH_HIGH) + igb_lower_rx_eitr(adapter, rx_ring); + } + return 0; + } + + return 1; +} +/** + * igb_clean_tx_irq - Reclaim resources after transmit completes + * @adapter: board private structure + * returns true if ring is completely cleaned + **/ +static bool igb_clean_tx_irq(struct igb_adapter *adapter, + struct igb_ring *tx_ring) +{ + struct net_device *netdev = adapter->netdev; + struct e1000_hw *hw = &adapter->hw; + struct e1000_tx_desc *tx_desc; + struct igb_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + u32 head, oldhead; + unsigned int count = 0; + bool cleaned = false; + bool retval = true; + unsigned int total_bytes = 0, total_packets = 0; + + rmb(); + head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc + + tx_ring->count); + head = le32_to_cpu(head); + i = tx_ring->next_to_clean; + while (1) { + while (i != head) { + cleaned = true; + tx_desc = E1000_TX_DESC(*tx_ring, i); + buffer_info = &tx_ring->buffer_info[i]; + skb = buffer_info->skb; + + if (skb) { + unsigned int segs, bytecount; + /* gso_segs is currently only valid for tcp */ + segs = skb_shinfo(skb)->gso_segs ?: 1; + /* multiply data chunks by size of headers */ + bytecount = ((segs - 1) * skb_headlen(skb)) + + skb->len; + total_packets += segs; + total_bytes += bytecount; + } + + igb_unmap_and_free_tx_resource(adapter, buffer_info); + tx_desc->upper.data = 0; + + i++; + if (i == tx_ring->count) + i = 0; + + count++; + if (count == IGB_MAX_TX_CLEAN) { + retval = false; + goto done_cleaning; + } + } + oldhead = head; + rmb(); + head = *(volatile u32 *)((struct e1000_tx_desc *)tx_ring->desc + + tx_ring->count); + head = le32_to_cpu(head); + if (head == oldhead) + goto done_cleaning; + } /* while (1) */ + +done_cleaning: + tx_ring->next_to_clean = i; + + if (unlikely(cleaned && + netif_carrier_ok(netdev) && + IGB_DESC_UNUSED(tx_ring) >= IGB_TX_QUEUE_WAKE)) { + /* Make sure that anybody stopping the queue after this + * sees the new next_to_clean. + */ + smp_mb(); + if (netif_queue_stopped(netdev) && + !(test_bit(__IGB_DOWN, &adapter->state))) { + netif_wake_queue(netdev); + ++adapter->restart_queue; + } + } + + if (tx_ring->detect_tx_hung) { + /* Detect a transmit hang in hardware, this serializes the + * check with the clearing of time_stamp and movement of i */ + tx_ring->detect_tx_hung = false; + if (tx_ring->buffer_info[i].time_stamp && + time_after(jiffies, tx_ring->buffer_info[i].time_stamp + + (adapter->tx_timeout_factor * HZ)) + && !(rd32(E1000_STATUS) & + E1000_STATUS_TXOFF)) { + + tx_desc = E1000_TX_DESC(*tx_ring, i); + /* detected Tx unit hang */ + dev_err(&adapter->pdev->dev, + "Detected Tx Unit Hang\n" + " Tx Queue <%lu>\n" + " TDH <%x>\n" + " TDT <%x>\n" + " next_to_use <%x>\n" + " next_to_clean <%x>\n" + " head (WB) <%x>\n" + "buffer_info[next_to_clean]\n" + " time_stamp <%lx>\n" + " jiffies <%lx>\n" + " desc.status <%x>\n", + (unsigned long)((tx_ring - adapter->tx_ring) / + sizeof(struct igb_ring)), + readl(adapter->hw.hw_addr + tx_ring->head), + readl(adapter->hw.hw_addr + tx_ring->tail), + tx_ring->next_to_use, + tx_ring->next_to_clean, + head, + tx_ring->buffer_info[i].time_stamp, + jiffies, + tx_desc->upper.fields.status); + netif_stop_queue(netdev); + } + } + tx_ring->total_bytes += total_bytes; + tx_ring->total_packets += total_packets; + adapter->net_stats.tx_bytes += total_bytes; + adapter->net_stats.tx_packets += total_packets; + return retval; +} + + +/** + * igb_receive_skb - helper function to handle rx indications + * @adapter: board private structure + * @status: descriptor status field as written by hardware + * @vlan: descriptor vlan field as written by hardware (no le/be conversion) + * @skb: pointer to sk_buff to be indicated to stack + **/ +static void igb_receive_skb(struct igb_adapter *adapter, u8 status, u16 vlan, + struct sk_buff *skb) +{ + if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) + vlan_hwaccel_receive_skb(skb, adapter->vlgrp, + le16_to_cpu(vlan) & + E1000_RXD_SPC_VLAN_MASK); + else + netif_receive_skb(skb); +} + + +static inline void igb_rx_checksum_adv(struct igb_adapter *adapter, + u32 status_err, struct sk_buff *skb) +{ + skb->ip_summed = CHECKSUM_NONE; + + /* Ignore Checksum bit is set or checksum is disabled through ethtool */ + if ((status_err & E1000_RXD_STAT_IXSM) || !adapter->rx_csum) + return; + /* TCP/UDP checksum error bit is set */ + if (status_err & + (E1000_RXDEXT_STATERR_TCPE | E1000_RXDEXT_STATERR_IPE)) { + /* let the stack verify checksum errors */ + adapter->hw_csum_err++; + return; + } + /* It must be a TCP or UDP packet with a valid checksum */ + if (status_err & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + adapter->hw_csum_good++; +} + +static bool igb_clean_rx_irq_adv(struct igb_adapter *adapter, + struct igb_ring *rx_ring, + int *work_done, int budget) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union e1000_adv_rx_desc *rx_desc , *next_rxd; + struct igb_buffer *buffer_info , *next_buffer; + struct sk_buff *skb; + unsigned int i, j; + u32 length, hlen, staterr; + bool cleaned = false; + int cleaned_count = 0; + unsigned int total_bytes = 0, total_packets = 0; + + i = rx_ring->next_to_clean; + rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + + while (staterr & E1000_RXD_STAT_DD) { + if (*work_done >= budget) + break; + (*work_done)++; + buffer_info = &rx_ring->buffer_info[i]; + + /* HW will not DMA in data larger than the given buffer, even + * if it parses the (NFS, of course) header to be larger. In + * that case, it fills the header buffer and spills the rest + * into the page. + */ + hlen = le16_to_cpu((rx_desc->wb.lower.lo_dword.hdr_info & + E1000_RXDADV_HDRBUFLEN_MASK) >> E1000_RXDADV_HDRBUFLEN_SHIFT); + if (hlen > adapter->rx_ps_hdr_size) + hlen = adapter->rx_ps_hdr_size; + + length = le16_to_cpu(rx_desc->wb.upper.length); + cleaned = true; + cleaned_count++; + + if (rx_ring->pending_skb != NULL) { + skb = rx_ring->pending_skb; + rx_ring->pending_skb = NULL; + j = rx_ring->pending_skb_page; + } else { + skb = buffer_info->skb; + prefetch(skb->data - NET_IP_ALIGN); + buffer_info->skb = NULL; + if (hlen) { + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_ps_hdr_size + + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, hlen); + } else { + pci_unmap_single(pdev, buffer_info->dma, + adapter->rx_buffer_len + + NET_IP_ALIGN, + PCI_DMA_FROMDEVICE); + skb_put(skb, length); + goto send_up; + } + j = 0; + } + + while (length) { + pci_unmap_page(pdev, buffer_info->page_dma, + PAGE_SIZE, PCI_DMA_FROMDEVICE); + buffer_info->page_dma = 0; + skb_fill_page_desc(skb, j, buffer_info->page, + 0, length); + buffer_info->page = NULL; + + skb->len += length; + skb->data_len += length; + skb->truesize += length; + rx_desc->wb.upper.status_error = 0; + if (staterr & E1000_RXD_STAT_EOP) + break; + + j++; + cleaned_count++; + i++; + if (i == rx_ring->count) + i = 0; + + buffer_info = &rx_ring->buffer_info[i]; + rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + length = le16_to_cpu(rx_desc->wb.upper.length); + if (!(staterr & E1000_RXD_STAT_DD)) { + rx_ring->pending_skb = skb; + rx_ring->pending_skb_page = j; + goto out; + } + } +send_up: + pskb_trim(skb, skb->len - 4); + i++; + if (i == rx_ring->count) + i = 0; + next_rxd = E1000_RX_DESC_ADV(*rx_ring, i); + prefetch(next_rxd); + next_buffer = &rx_ring->buffer_info[i]; + + if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) { + dev_kfree_skb_irq(skb); + goto next_desc; + } + rx_ring->no_itr_adjust |= (staterr & E1000_RXD_STAT_DYNINT); + + total_bytes += skb->len; + total_packets++; + + igb_rx_checksum_adv(adapter, staterr, skb); + + skb->protocol = eth_type_trans(skb, netdev); + + igb_receive_skb(adapter, staterr, rx_desc->wb.upper.vlan, skb); + + netdev->last_rx = jiffies; + +next_desc: + rx_desc->wb.upper.status_error = 0; + + /* return some buffers to hardware, one at a time is too slow */ + if (cleaned_count >= IGB_RX_BUFFER_WRITE) { + igb_alloc_rx_buffers_adv(adapter, rx_ring, + cleaned_count); + cleaned_count = 0; + } + + /* use prefetched values */ + rx_desc = next_rxd; + buffer_info = next_buffer; + + staterr = le32_to_cpu(rx_desc->wb.upper.status_error); + } +out: + rx_ring->next_to_clean = i; + cleaned_count = IGB_DESC_UNUSED(rx_ring); + + if (cleaned_count) + igb_alloc_rx_buffers_adv(adapter, rx_ring, cleaned_count); + + rx_ring->total_packets += total_packets; + rx_ring->total_bytes += total_bytes; + rx_ring->rx_stats.packets += total_packets; + rx_ring->rx_stats.bytes += total_bytes; + adapter->net_stats.rx_bytes += total_bytes; + adapter->net_stats.rx_packets += total_packets; + return cleaned; +} + + +/** + * igb_alloc_rx_buffers_adv - Replace used receive buffers; packet split + * @adapter: address of board private structure + **/ +static void igb_alloc_rx_buffers_adv(struct igb_adapter *adapter, + struct igb_ring *rx_ring, + int cleaned_count) +{ + struct net_device *netdev = adapter->netdev; + struct pci_dev *pdev = adapter->pdev; + union e1000_adv_rx_desc *rx_desc; + struct igb_buffer *buffer_info; + struct sk_buff *skb; + unsigned int i; + + i = rx_ring->next_to_use; + buffer_info = &rx_ring->buffer_info[i]; + + while (cleaned_count--) { + rx_desc = E1000_RX_DESC_ADV(*rx_ring, i); + + if (adapter->rx_ps_hdr_size && !buffer_info->page) { + buffer_info->page = alloc_page(GFP_ATOMIC); + if (!buffer_info->page) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + buffer_info->page_dma = + pci_map_page(pdev, + buffer_info->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + } + + if (!buffer_info->skb) { + int bufsz; + + if (adapter->rx_ps_hdr_size) + bufsz = adapter->rx_ps_hdr_size; + else + bufsz = adapter->rx_buffer_len; + bufsz += NET_IP_ALIGN; + skb = netdev_alloc_skb(netdev, bufsz); + + if (!skb) { + adapter->alloc_rx_buff_failed++; + goto no_buffers; + } + + /* Make buffer alignment 2 beyond a 16 byte boundary + * this will result in a 16 byte aligned IP header after + * the 14 byte MAC header is removed + */ + skb_reserve(skb, NET_IP_ALIGN); + + buffer_info->skb = skb; + buffer_info->dma = pci_map_single(pdev, skb->data, + bufsz, + PCI_DMA_FROMDEVICE); + + } + /* Refresh the desc even if buffer_addrs didn't change because + * each write-back erases this info. */ + if (adapter->rx_ps_hdr_size) { + rx_desc->read.pkt_addr = + cpu_to_le64(buffer_info->page_dma); + rx_desc->read.hdr_addr = cpu_to_le64(buffer_info->dma); + } else { + rx_desc->read.pkt_addr = + cpu_to_le64(buffer_info->dma); + rx_desc->read.hdr_addr = 0; + } + + i++; + if (i == rx_ring->count) + i = 0; + buffer_info = &rx_ring->buffer_info[i]; + } + +no_buffers: + if (rx_ring->next_to_use != i) { + rx_ring->next_to_use = i; + if (i == 0) + i = (rx_ring->count - 1); + else + i--; + + /* Force memory writes to complete before letting h/w + * know there are new descriptors to fetch. (Only + * applicable for weak-ordered memory model archs, + * such as IA-64). */ + wmb(); + writel(i, adapter->hw.hw_addr + rx_ring->tail); + } +} + +/** + * igb_mii_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ +static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct mii_ioctl_data *data = if_mii(ifr); + + if (adapter->hw.phy.media_type != e1000_media_type_copper) + return -EOPNOTSUPP; + + switch (cmd) { + case SIOCGMIIPHY: + data->phy_id = adapter->hw.phy.addr; + break; + case SIOCGMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw, + data->reg_num + & 0x1F, &data->val_out)) + return -EIO; + break; + case SIOCSMIIREG: + default: + return -EOPNOTSUPP; + } + return 0; +} + +/** + * igb_ioctl - + * @netdev: + * @ifreq: + * @cmd: + **/ +static int igb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + return igb_mii_ioctl(netdev, ifr, cmd); + default: + return -EOPNOTSUPP; + } +} + +static void igb_vlan_rx_register(struct net_device *netdev, + struct vlan_group *grp) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, rctl; + + igb_irq_disable(adapter); + adapter->vlgrp = grp; + + if (grp) { + /* enable VLAN tag insert/strip */ + ctrl = rd32(E1000_CTRL); + ctrl |= E1000_CTRL_VME; + wr32(E1000_CTRL, ctrl); + + /* enable VLAN receive filtering */ + rctl = rd32(E1000_RCTL); + rctl |= E1000_RCTL_VFE; + rctl &= ~E1000_RCTL_CFIEN; + wr32(E1000_RCTL, rctl); + igb_update_mng_vlan(adapter); + wr32(E1000_RLPML, + adapter->max_frame_size + VLAN_TAG_SIZE); + } else { + /* disable VLAN tag insert/strip */ + ctrl = rd32(E1000_CTRL); + ctrl &= ~E1000_CTRL_VME; + wr32(E1000_CTRL, ctrl); + + /* disable VLAN filtering */ + rctl = rd32(E1000_RCTL); + rctl &= ~E1000_RCTL_VFE; + wr32(E1000_RCTL, rctl); + if (adapter->mng_vlan_id != (u16)IGB_MNG_VLAN_NONE) { + igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); + adapter->mng_vlan_id = IGB_MNG_VLAN_NONE; + } + wr32(E1000_RLPML, + adapter->max_frame_size); + } + + if (!test_bit(__IGB_DOWN, &adapter->state)) + igb_irq_enable(adapter); +} + +static void igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) + return; + /* add VID to filter table */ + index = (vid >> 5) & 0x7F; + vfta = array_rd32(E1000_VFTA, index); + vfta |= (1 << (vid & 0x1F)); + igb_write_vfta(&adapter->hw, index, vfta); +} + +static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 vfta, index; + + igb_irq_disable(adapter); + vlan_group_set_device(adapter->vlgrp, vid, NULL); + + if (!test_bit(__IGB_DOWN, &adapter->state)) + igb_irq_enable(adapter); + + if ((adapter->hw.mng_cookie.status & + E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && + (vid == adapter->mng_vlan_id)) { + /* release control to f/w */ + igb_release_hw_control(adapter); + return; + } + + /* remove VID from filter table */ + index = (vid >> 5) & 0x7F; + vfta = array_rd32(E1000_VFTA, index); + vfta &= ~(1 << (vid & 0x1F)); + igb_write_vfta(&adapter->hw, index, vfta); +} + +static void igb_restore_vlan(struct igb_adapter *adapter) +{ + igb_vlan_rx_register(adapter->netdev, adapter->vlgrp); + + if (adapter->vlgrp) { + u16 vid; + for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) + continue; + igb_vlan_rx_add_vid(adapter->netdev, vid); + } + } +} + +int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx) +{ + struct e1000_mac_info *mac = &adapter->hw.mac; + + mac->autoneg = 0; + + /* Fiber NICs only allow 1000 gbps Full duplex */ + if ((adapter->hw.phy.media_type == e1000_media_type_fiber) && + spddplx != (SPEED_1000 + DUPLEX_FULL)) { + dev_err(&adapter->pdev->dev, + "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; + } + + switch (spddplx) { + case SPEED_10 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_10_HALF; + break; + case SPEED_10 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_10_FULL; + break; + case SPEED_100 + DUPLEX_HALF: + mac->forced_speed_duplex = ADVERTISE_100_HALF; + break; + case SPEED_100 + DUPLEX_FULL: + mac->forced_speed_duplex = ADVERTISE_100_FULL; + break; + case SPEED_1000 + DUPLEX_FULL: + mac->autoneg = 1; + adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL; + break; + case SPEED_1000 + DUPLEX_HALF: /* not supported */ + default: + dev_err(&adapter->pdev->dev, + "Unsupported Speed/Duplex configuration\n"); + return -EINVAL; + } + return 0; +} + + +static int igb_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, ctrl_ext, rctl, status; + u32 wufc = adapter->wol; +#ifdef CONFIG_PM + int retval = 0; +#endif + + netif_device_detach(netdev); + + if (netif_running(netdev)) { + WARN_ON(test_bit(__IGB_RESETTING, &adapter->state)); + igb_down(adapter); + igb_free_irq(adapter); + } + +#ifdef CONFIG_PM + retval = pci_save_state(pdev); + if (retval) + return retval; +#endif + + status = rd32(E1000_STATUS); + if (status & E1000_STATUS_LU) + wufc &= ~E1000_WUFC_LNKC; + + if (wufc) { + igb_setup_rctl(adapter); + igb_set_multi(netdev); + + /* turn on all-multi mode if wake on multicast is enabled */ + if (wufc & E1000_WUFC_MC) { + rctl = rd32(E1000_RCTL); + rctl |= E1000_RCTL_MPE; + wr32(E1000_RCTL, rctl); + } + + ctrl = rd32(E1000_CTRL); + /* advertise wake from D3Cold */ + #define E1000_CTRL_ADVD3WUC 0x00100000 + /* phy power management enable */ + #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000 + ctrl |= E1000_CTRL_ADVD3WUC; + wr32(E1000_CTRL, ctrl); + + if (adapter->hw.phy.media_type == e1000_media_type_fiber || + adapter->hw.phy.media_type == + e1000_media_type_internal_serdes) { + /* keep the laser running in D3 */ + ctrl_ext = rd32(E1000_CTRL_EXT); + ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA; + wr32(E1000_CTRL_EXT, ctrl_ext); + } + + /* Allow time for pending master requests to run */ + igb_disable_pcie_master(&adapter->hw); + + wr32(E1000_WUC, E1000_WUC_PME_EN); + wr32(E1000_WUFC, wufc); + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } else { + wr32(E1000_WUC, 0); + wr32(E1000_WUFC, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + } + + igb_release_manageability(adapter); + + /* make sure adapter isn't asleep if manageability is enabled */ + if (adapter->en_mng_pt) { + pci_enable_wake(pdev, PCI_D3hot, 1); + pci_enable_wake(pdev, PCI_D3cold, 1); + } + + /* Release control of h/w to f/w. If f/w is AMT enabled, this + * would have already happened in close and is redundant. */ + igb_release_hw_control(adapter); + + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +#ifdef CONFIG_PM +static int igb_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + err = pci_enable_device(pdev); + if (err) { + dev_err(&pdev->dev, + "igb: Cannot enable PCI device from suspend\n"); + return err; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + if (netif_running(netdev)) { + err = igb_request_irq(adapter); + if (err) + return err; + } + + /* e1000_power_up_phy(adapter); */ + + igb_reset(adapter); + wr32(E1000_WUS, ~0); + + igb_init_manageability(adapter); + + if (netif_running(netdev)) + igb_up(adapter); + + netif_device_attach(netdev); + + /* let the f/w know that the h/w is now under the control of the + * driver. */ + igb_get_hw_control(adapter); + + return 0; +} +#endif + +static void igb_shutdown(struct pci_dev *pdev) +{ + igb_suspend(pdev, PMSG_SUSPEND); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void igb_netpoll(struct net_device *netdev) +{ + struct igb_adapter *adapter = netdev_priv(netdev); + int i; + int work_done = 0; + + igb_irq_disable(adapter); + for (i = 0; i < adapter->num_tx_queues; i++) + igb_clean_tx_irq(adapter, &adapter->tx_ring[i]); + + for (i = 0; i < adapter->num_rx_queues; i++) + igb_clean_rx_irq_adv(adapter, &adapter->rx_ring[i], + &work_done, + adapter->rx_ring[i].napi.weight); + + igb_irq_enable(adapter); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +/** + * igb_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t igb_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igb_adapter *adapter = netdev_priv(netdev); + + netif_device_detach(netdev); + + if (netif_running(netdev)) + igb_down(adapter); + pci_disable_device(pdev); + + /* Request a slot slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * igb_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. Implementation + * resembles the first-half of the igb_resume routine. + */ +static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igb_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + pci_set_master(pdev); + + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); + + igb_reset(adapter); + wr32(E1000_WUS, ~0); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * igb_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. Implementation resembles the + * second-half of the igb_resume routine. + */ +static void igb_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct igb_adapter *adapter = netdev_priv(netdev); + + igb_init_manageability(adapter); + + if (netif_running(netdev)) { + if (igb_up(adapter)) { + dev_err(&pdev->dev, "igb_up failed after reset\n"); + return; + } + } + + netif_device_attach(netdev); + + /* let the f/w know that the h/w is now under the control of the + * driver. */ + igb_get_hw_control(adapter); + +} + +/* igb_main.c */ diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 50f0c17451b1..5e5d9b527ed1 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -34,9 +34,9 @@ IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \ IPG_AC_AUTO_INIT) -#define ipg_w32(val32,reg) iowrite32((val32), ioaddr + (reg)) -#define ipg_w16(val16,reg) iowrite16((val16), ioaddr + (reg)) -#define ipg_w8(val8,reg) iowrite8((val8), ioaddr + (reg)) +#define ipg_w32(val32, reg) iowrite32((val32), ioaddr + (reg)) +#define ipg_w16(val16, reg) iowrite16((val16), ioaddr + (reg)) +#define ipg_w8(val8, reg) iowrite8((val8), ioaddr + (reg)) #define ipg_r32(reg) ioread32(ioaddr + (reg)) #define ipg_r16(reg) ioread16(ioaddr + (reg)) @@ -51,24 +51,25 @@ enum { #define DRV_NAME "ipg" MODULE_AUTHOR("IC Plus Corp. 2003"); -MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver " - DrvVer); +MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver"); MODULE_LICENSE("GPL"); -//variable record -- index by leading revision/length -//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN +/* + * Variable record -- index by leading revision/length + * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN + */ static unsigned short DefaultPhyParam[] = { - // 11/12/03 IP1000A v1-3 rev=0x40 + /* 11/12/03 IP1000A v1-3 rev=0x40 */ /*-------------------------------------------------------------------------- (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2, 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6, 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700, --------------------------------------------------------------------------*/ - // 12/17/03 IP1000A v1-4 rev=0x40 + /* 12/17/03 IP1000A v1-4 rev=0x40 */ (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, 0x0000, 30, 0x005e, 9, 0x0700, - // 01/09/04 IP1000A v1-5 rev=0x41 + /* 01/09/04 IP1000A v1-5 rev=0x41 */ (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31, 0x0000, 30, 0x005e, 9, 0x0700, @@ -188,7 +189,7 @@ static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity) phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL); } -static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity) +static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity) { u16 bit_data; @@ -205,7 +206,7 @@ static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity) * Read a register from the Physical Layer device located * on the IPG NIC, using the IPG PHYCTRL register. */ -static int mdio_read(struct net_device * dev, int phy_id, int phy_reg) +static int mdio_read(struct net_device *dev, int phy_id, int phy_reg) { void __iomem *ioaddr = ipg_ioaddr(dev); /* @@ -374,7 +375,6 @@ static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val) } } -/* Set LED_Mode JES20040127EEPROM */ static void ipg_set_led_mode(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); @@ -384,19 +384,18 @@ static void ipg_set_led_mode(struct net_device *dev) mode = ipg_r32(ASIC_CTRL); mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED); - if ((sp->LED_Mode & 0x03) > 1) + if ((sp->led_mode & 0x03) > 1) mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */ - if ((sp->LED_Mode & 0x01) == 1) + if ((sp->led_mode & 0x01) == 1) mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */ - if ((sp->LED_Mode & 0x08) == 8) + if ((sp->led_mode & 0x08) == 8) mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */ ipg_w32(mode, ASIC_CTRL); } -/* Set PHYSet JES20040127EEPROM */ static void ipg_set_phy_set(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); @@ -405,7 +404,7 @@ static void ipg_set_phy_set(struct net_device *dev) physet = ipg_r8(PHY_SET); physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET); - physet |= ((sp->LED_Mode & 0x70) >> 4); + physet |= ((sp->led_mode & 0x70) >> 4); ipg_w8(physet, PHY_SET); } @@ -415,7 +414,7 @@ static int ipg_reset(struct net_device *dev, u32 resetflags) * register as specified by the 'resetflags' input * parameter. */ - void __iomem *ioaddr = ipg_ioaddr(dev); //JES20040127EEPROM: + void __iomem *ioaddr = ipg_ioaddr(dev); unsigned int timeout_count = 0; IPG_DEBUG_MSG("_reset\n"); @@ -430,10 +429,10 @@ static int ipg_reset(struct net_device *dev, u32 resetflags) if (++timeout_count > IPG_AC_RESET_TIMEOUT) return -ETIME; } - /* Set LED Mode in Asic Control JES20040127EEPROM */ + /* Set LED Mode in Asic Control */ ipg_set_led_mode(dev); - /* Set PHYSet Register Value JES20040127EEPROM */ + /* Set PHYSet Register Value */ ipg_set_phy_set(dev); return 0; } @@ -551,7 +550,7 @@ static int ipg_config_autoneg(struct net_device *dev) printk("\n"); } else { /* Configure IPG for half duplex operation. */ - printk(KERN_INFO "%s: setting half duplex, " + printk(KERN_INFO "%s: setting half duplex, " "no TX flow control, no RX flow control.\n", dev->name); mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD & @@ -736,7 +735,7 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry) skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN); if (!skb) { - sp->RxBuff[entry] = NULL; + sp->rx_buff[entry] = NULL; return -ENOMEM; } @@ -749,7 +748,7 @@ static int ipg_get_rxbuff(struct net_device *dev, int entry) skb->dev = dev; /* Save the address of the sk_buff structure. */ - sp->RxBuff[entry] = skb; + sp->rx_buff[entry] = skb; rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data, sp->rx_buf_sz, PCI_DMA_FROMDEVICE)); @@ -772,12 +771,12 @@ static int init_rfdlist(struct net_device *dev) for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { struct ipg_rx *rxfd = sp->rxd + i; - if (sp->RxBuff[i]) { + if (sp->rx_buff[i]) { pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - IPG_DEV_KFREE_SKB(sp->RxBuff[i]); - sp->RxBuff[i] = NULL; + dev_kfree_skb_irq(sp->rx_buff[i]); + sp->rx_buff[i] = NULL; } /* Clear out the RFS field. */ @@ -828,9 +827,9 @@ static void init_tfdlist(struct net_device *dev) txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); - if (sp->TxBuff[i]) { - IPG_DEV_KFREE_SKB(sp->TxBuff[i]); - sp->TxBuff[i] = NULL; + if (sp->tx_buff[i]) { + dev_kfree_skb_irq(sp->tx_buff[i]); + sp->tx_buff[i] = NULL; } txfd->next_desc = cpu_to_le64(sp->txd_map + @@ -847,7 +846,7 @@ static void init_tfdlist(struct net_device *dev) ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0); ipg_w32(0x00000000, TFD_LIST_PTR_1); - sp->ResetCurrentTFD = 1; + sp->reset_current_tfd = 1; } /* @@ -865,7 +864,7 @@ static void ipg_nic_txfree(struct net_device *dev) dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; for (released = 0; released < pending; released++) { - struct sk_buff *skb = sp->TxBuff[dirty]; + struct sk_buff *skb = sp->tx_buff[dirty]; struct ipg_tx *txfd = sp->txd + dirty; IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc); @@ -884,9 +883,9 @@ static void ipg_nic_txfree(struct net_device *dev) le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, skb->len, PCI_DMA_TODEVICE); - IPG_DEV_KFREE_SKB(skb); + dev_kfree_skb_irq(skb); - sp->TxBuff[dirty] = NULL; + sp->tx_buff[dirty] = NULL; } dirty = (dirty + 1) % IPG_TFDLIST_LENGTH; } @@ -1059,7 +1058,7 @@ static int ipg_nic_rxrestore(struct net_device *dev) unsigned int entry = dirty % IPG_RFDLIST_LENGTH; /* rx_copybreak may poke hole here and there. */ - if (sp->RxBuff[entry]) + if (sp->rx_buff[entry]) continue; /* Generate a new receive buffer to replace the @@ -1083,22 +1082,22 @@ static int ipg_nic_rxrestore(struct net_device *dev) #ifdef JUMBO_FRAME /* use jumboindex and jumbosize to control jumbo frame status - initial status is jumboindex=-1 and jumbosize=0 - 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. - 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving - 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump - previous receiving and need to continue dumping the current one -*/ + * initial status is jumboindex=-1 and jumbosize=0 + * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done. + * 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving + * 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump + * previous receiving and need to continue dumping the current one + */ enum { - NormalPacket, - ErrorPacket + NORMAL_PACKET, + ERROR_PACKET }; enum { - Frame_NoStart_NoEnd = 0, - Frame_WithStart = 1, - Frame_WithEnd = 10, - Frame_WithStart_WithEnd = 11 + FRAME_NO_START_NO_END = 0, + FRAME_WITH_START = 1, + FRAME_WITH_END = 10, + FRAME_WITH_START_WITH_END = 11 }; inline void ipg_nic_rx_free_skb(struct net_device *dev) @@ -1106,14 +1105,14 @@ inline void ipg_nic_rx_free_skb(struct net_device *dev) struct ipg_nic_private *sp = netdev_priv(dev); unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH; - if (sp->RxBuff[entry]) { + if (sp->rx_buff[entry]) { struct ipg_rx *rxfd = sp->rxd + entry; pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); - sp->RxBuff[entry] = NULL; + dev_kfree_skb_irq(sp->rx_buff[entry]); + sp->rx_buff[entry] = NULL; } } @@ -1121,12 +1120,12 @@ inline int ipg_nic_rx_check_frame_type(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH); - int type = Frame_NoStart_NoEnd; + int type = FRAME_NO_START_NO_END; if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) - type += Frame_WithStart; + type += FRAME_WITH_START; if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND) - type += Frame_WithEnd; + type += FRAME_WITH_END; return type; } @@ -1175,43 +1174,43 @@ inline int ipg_nic_rx_check_error(struct net_device *dev) * buffer since it is erroneous and we will * not pass it to higher layer processes. */ - if (sp->RxBuff[entry]) { + if (sp->rx_buff[entry]) { pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); - sp->RxBuff[entry] = NULL; + dev_kfree_skb_irq(sp->rx_buff[entry]); + sp->rx_buff[entry] = NULL; } - return ErrorPacket; + return ERROR_PACKET; } - return NormalPacket; + return NORMAL_PACKET; } static void ipg_nic_rx_with_start_and_end(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry) { - struct SJumbo *jumbo = &sp->Jumbo; + struct ipg_jumbo *jumbo = &sp->jumbo; struct sk_buff *skb; int framelen; - if (jumbo->FoundStart) { - IPG_DEV_KFREE_SKB(jumbo->skb); - jumbo->FoundStart = 0; - jumbo->CurrentSize = 0; + if (jumbo->found_start) { + dev_kfree_skb_irq(jumbo->skb); + jumbo->found_start = 0; + jumbo->current_size = 0; jumbo->skb = NULL; } - // 1: found error, 0 no error - if (ipg_nic_rx_check_error(dev) != NormalPacket) + /* 1: found error, 0 no error */ + if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET) return; - skb = sp->RxBuff[entry]; + skb = sp->rx_buff[entry]; if (!skb) return; - // accept this frame and send to upper layer + /* accept this frame and send to upper layer */ framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; if (framelen > IPG_RXFRAG_SIZE) framelen = IPG_RXFRAG_SIZE; @@ -1221,39 +1220,39 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev, skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); dev->last_rx = jiffies; - sp->RxBuff[entry] = NULL; + sp->rx_buff[entry] = NULL; } static void ipg_nic_rx_with_start(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry) { - struct SJumbo *jumbo = &sp->Jumbo; + struct ipg_jumbo *jumbo = &sp->jumbo; struct pci_dev *pdev = sp->pdev; struct sk_buff *skb; - // 1: found error, 0 no error - if (ipg_nic_rx_check_error(dev) != NormalPacket) + /* 1: found error, 0 no error */ + if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET) return; - // accept this frame and send to upper layer - skb = sp->RxBuff[entry]; + /* accept this frame and send to upper layer */ + skb = sp->rx_buff[entry]; if (!skb) return; - if (jumbo->FoundStart) - IPG_DEV_KFREE_SKB(jumbo->skb); + if (jumbo->found_start) + dev_kfree_skb_irq(jumbo->skb); pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN), sp->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb, IPG_RXFRAG_SIZE); - jumbo->FoundStart = 1; - jumbo->CurrentSize = IPG_RXFRAG_SIZE; + jumbo->found_start = 1; + jumbo->current_size = IPG_RXFRAG_SIZE; jumbo->skb = skb; - sp->RxBuff[entry] = NULL; + sp->rx_buff[entry] = NULL; dev->last_rx = jiffies; } @@ -1261,27 +1260,27 @@ static void ipg_nic_rx_with_end(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry) { - struct SJumbo *jumbo = &sp->Jumbo; + struct ipg_jumbo *jumbo = &sp->jumbo; - //1: found error, 0 no error - if (ipg_nic_rx_check_error(dev) == NormalPacket) { - struct sk_buff *skb = sp->RxBuff[entry]; + /* 1: found error, 0 no error */ + if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) { + struct sk_buff *skb = sp->rx_buff[entry]; if (!skb) return; - if (jumbo->FoundStart) { + if (jumbo->found_start) { int framelen, endframelen; framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN; - endframeLen = framelen - jumbo->CurrentSize; + endframeLen = framelen - jumbo->current_size; /* if (framelen > IPG_RXFRAG_SIZE) framelen=IPG_RXFRAG_SIZE; */ if (framelen > IPG_RXSUPPORT_SIZE) - IPG_DEV_KFREE_SKB(jumbo->skb); + dev_kfree_skb_irq(jumbo->skb); else { memcpy(skb_put(jumbo->skb, endframeLen), skb->data, endframeLen); @@ -1295,15 +1294,15 @@ static void ipg_nic_rx_with_end(struct net_device *dev, } dev->last_rx = jiffies; - jumbo->FoundStart = 0; - jumbo->CurrentSize = 0; + jumbo->found_start = 0; + jumbo->current_size = 0; jumbo->skb = NULL; ipg_nic_rx_free_skb(dev); } else { - IPG_DEV_KFREE_SKB(jumbo->skb); - jumbo->FoundStart = 0; - jumbo->CurrentSize = 0; + dev_kfree_skb_irq(jumbo->skb); + jumbo->found_start = 0; + jumbo->current_size = 0; jumbo->skb = NULL; } } @@ -1312,16 +1311,16 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev, struct ipg_nic_private *sp, struct ipg_rx *rxfd, unsigned entry) { - struct SJumbo *jumbo = &sp->Jumbo; + struct ipg_jumbo *jumbo = &sp->jumbo; - //1: found error, 0 no error - if (ipg_nic_rx_check_error(dev) == NormalPacket) { - struct sk_buff *skb = sp->RxBuff[entry]; + /* 1: found error, 0 no error */ + if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) { + struct sk_buff *skb = sp->rx_buff[entry]; if (skb) { - if (jumbo->FoundStart) { - jumbo->CurrentSize += IPG_RXFRAG_SIZE; - if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) { + if (jumbo->found_start) { + jumbo->current_size += IPG_RXFRAG_SIZE; + if (jumbo->current_size <= IPG_RXSUPPORT_SIZE) { memcpy(skb_put(jumbo->skb, IPG_RXFRAG_SIZE), skb->data, IPG_RXFRAG_SIZE); @@ -1331,9 +1330,9 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev, ipg_nic_rx_free_skb(dev); } } else { - IPG_DEV_KFREE_SKB(jumbo->skb); - jumbo->FoundStart = 0; - jumbo->CurrentSize = 0; + dev_kfree_skb_irq(jumbo->skb); + jumbo->found_start = 0; + jumbo->current_size = 0; jumbo->skb = NULL; } } @@ -1355,16 +1354,16 @@ static int ipg_nic_rx(struct net_device *dev) break; switch (ipg_nic_rx_check_frame_type(dev)) { - case Frame_WithStart_WithEnd: + case FRAME_WITH_START_WITH_END: ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry); break; - case Frame_WithStart: + case FRAME_WITH_START: ipg_nic_rx_with_start(dev, tp, rxfd, entry); break; - case Frame_WithEnd: + case FRAME_WITH_END: ipg_nic_rx_with_end(dev, tp, rxfd, entry); break; - case Frame_NoStart_NoEnd: + case FRAME_NO_START_NO_END: ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry); break; } @@ -1403,7 +1402,7 @@ static int ipg_nic_rx(struct net_device *dev) for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) { unsigned int entry = curr % IPG_RFDLIST_LENGTH; - struct sk_buff *skb = sp->RxBuff[entry]; + struct sk_buff *skb = sp->rx_buff[entry]; unsigned int framelen; rxfd = sp->rxd + entry; @@ -1472,7 +1471,7 @@ static int ipg_nic_rx(struct net_device *dev) le64_to_cpu(info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - IPG_DEV_KFREE_SKB(skb); + dev_kfree_skb_irq(skb); } } else { @@ -1484,35 +1483,13 @@ static int ipg_nic_rx(struct net_device *dev) /* Set the buffer's protocol field to Ethernet. */ skb->protocol = eth_type_trans(skb, dev); - /* If the frame contains an IP/TCP/UDP frame, - * determine if upper layer must check IP/TCP/UDP - * checksums. - * - * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM - * VERIFICATION FOR SILICON REVISIONS B3 - * AND EARLIER! - * - if ((le64_to_cpu(rxfd->rfs & - (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED | - IPG_RFS_IPDETECTED))) && - !(le64_to_cpu(rxfd->rfs & - (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR | - IPG_RFS_IPERROR)))) { - * Indicate IP checksums were performed - * by the IPG. - * - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else + /* The IPG encountered an error with (or + * there were no) IP/TCP/UDP checksums. + * This may or may not indicate an invalid + * IP/TCP/UDP frame was received. Let the + * upper layer decide. */ - { - /* The IPG encountered an error with (or - * there were no) IP/TCP/UDP checksums. - * This may or may not indicate an invalid - * IP/TCP/UDP frame was received. Let the - * upper layer decide. - */ - skb->ip_summed = CHECKSUM_NONE; - } + skb->ip_summed = CHECKSUM_NONE; /* Hand off frame for higher layer processing. * The function netif_rx() releases the sk_buff @@ -1527,7 +1504,7 @@ static int ipg_nic_rx(struct net_device *dev) } /* Assure RX buffer is not reused by IPG. */ - sp->RxBuff[entry] = NULL; + sp->rx_buff[entry] = NULL; } /* @@ -1561,15 +1538,15 @@ static int ipg_nic_rx(struct net_device *dev) * buffer since it is erroneous and we will * not pass it to higher layer processes. */ - if (sp->RxBuff[entry]) { + if (sp->rx_buff[entry]) { pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); - IPG_DEV_KFREE_SKB(sp->RxBuff[entry]); + dev_kfree_skb_irq(sp->rx_buff[entry]); } /* Assure RX buffer is not reused by IPG. */ - sp->RxBuff[entry] = NULL; + sp->rx_buff[entry] = NULL; } sp->rx_current = curr; @@ -1735,11 +1712,11 @@ static void ipg_rx_clear(struct ipg_nic_private *sp) unsigned int i; for (i = 0; i < IPG_RFDLIST_LENGTH; i++) { - if (sp->RxBuff[i]) { + if (sp->rx_buff[i]) { struct ipg_rx *rxfd = sp->rxd + i; - IPG_DEV_KFREE_SKB(sp->RxBuff[i]); - sp->RxBuff[i] = NULL; + dev_kfree_skb_irq(sp->rx_buff[i]); + sp->rx_buff[i] = NULL; pci_unmap_single(sp->pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN, sp->rx_buf_sz, PCI_DMA_FROMDEVICE); @@ -1752,16 +1729,16 @@ static void ipg_tx_clear(struct ipg_nic_private *sp) unsigned int i; for (i = 0; i < IPG_TFDLIST_LENGTH; i++) { - if (sp->TxBuff[i]) { + if (sp->tx_buff[i]) { struct ipg_tx *txfd = sp->txd + i; pci_unmap_single(sp->pdev, le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN, - sp->TxBuff[i]->len, PCI_DMA_TODEVICE); + sp->tx_buff[i]->len, PCI_DMA_TODEVICE); - IPG_DEV_KFREE_SKB(sp->TxBuff[i]); + dev_kfree_skb_irq(sp->tx_buff[i]); - sp->TxBuff[i] = NULL; + sp->tx_buff[i] = NULL; } } } @@ -1832,9 +1809,9 @@ static int ipg_nic_open(struct net_device *dev) #ifdef JUMBO_FRAME /* initialize JUMBO Frame control variable */ - sp->Jumbo.FoundStart = 0; - sp->Jumbo.CurrentSize = 0; - sp->Jumbo.skb = 0; + sp->jumbo.found_start = 0; + sp->jumbo.current_size = 0; + sp->jumbo.skb = 0; dev->mtu = IPG_TXFRAG_SIZE; #endif @@ -1909,14 +1886,14 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) if (sp->tenmbpsmode) netif_stop_queue(dev); - if (sp->ResetCurrentTFD) { - sp->ResetCurrentTFD = 0; + if (sp->reset_current_tfd) { + sp->reset_current_tfd = 0; entry = 0; } txfd = sp->txd + entry; - sp->TxBuff[entry] = skb; + sp->tx_buff[entry] = skb; /* Clear all TFC fields, except TFDDONE. */ txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE); @@ -2029,7 +2006,6 @@ static void ipg_set_phy_default_param(unsigned char rev, } } -/* JES20040127EEPROM */ static int read_eeprom(struct net_device *dev, int eep_addr) { void __iomem *ioaddr = ipg_ioaddr(dev); @@ -2096,9 +2072,9 @@ static int ipg_hw_init(struct net_device *dev) unsigned int i; int rc; - /* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */ + /* Read/Write and Reset EEPROM Value */ /* Read LED Mode Configuration from EEPROM */ - sp->LED_Mode = read_eeprom(dev, 6); + sp->led_mode = read_eeprom(dev, 6); /* Reset all functions within the IPG. Do not assert * RST_OUT as not compatible with some PHYs. @@ -2202,7 +2178,7 @@ static struct ethtool_ops ipg_ethtool_ops = { .nway_reset = ipg_nway_reset, }; -static void ipg_remove(struct pci_dev *pdev) +static void __devexit ipg_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct ipg_nic_private *sp = netdev_priv(dev); diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h index d5d092c9d0af..cda53887d4db 100644 --- a/drivers/net/ipg.h +++ b/drivers/net/ipg.h @@ -1,20 +1,8 @@ /* - * - * ipg.h - * * Include file for Gigabit Ethernet device driver for Network * Interface Cards (NICs) utilizing the Tamarack Microelectronics * Inc. IPG Gigabit or Triple Speed Ethernet Media Access * Controller. - * - * Craig Rich - * Sundance Technology, Inc. - * 1485 Saratoga Avenue - * Suite 200 - * San Jose, CA 95129 - * 408 873 4117 - * www.sundanceti.com - * craig_rich@sundanceti.com */ #ifndef __LINUX_IPG_H #define __LINUX_IPG_H @@ -35,11 +23,6 @@ #include <linux/skbuff.h> #include <linux/version.h> #include <asm/bitops.h> -/*#include <asm/spinlock.h>*/ - -#define DrvVer "2.09d" - -#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb) /* * Constants @@ -68,7 +51,7 @@ /* I/O register offsets. */ enum ipg_regs { DMA_CTRL = 0x00, - RX_DMA_STATUS = 0x08, // Unused + reserved + RX_DMA_STATUS = 0x08, /* Unused + reserved */ TFD_LIST_PTR_0 = 0x10, TFD_LIST_PTR_1 = 0x14, TX_DMA_BURST_THRESH = 0x18, @@ -81,22 +64,22 @@ enum ipg_regs { RX_DMA_POLL_PERIOD = 0x26, DEBUG_CTRL = 0x2c, ASIC_CTRL = 0x30, - FIFO_CTRL = 0x38, // Unused + FIFO_CTRL = 0x38, /* Unused */ FLOW_OFF_THRESH = 0x3c, FLOW_ON_THRESH = 0x3e, EEPROM_DATA = 0x48, EEPROM_CTRL = 0x4a, - EXPROM_ADDR = 0x4c, // Unused - EXPROM_DATA = 0x50, // Unused - WAKE_EVENT = 0x51, // Unused - COUNTDOWN = 0x54, // Unused + EXPROM_ADDR = 0x4c, /* Unused */ + EXPROM_DATA = 0x50, /* Unused */ + WAKE_EVENT = 0x51, /* Unused */ + COUNTDOWN = 0x54, /* Unused */ INT_STATUS_ACK = 0x5a, INT_ENABLE = 0x5c, - INT_STATUS = 0x5e, // Unused + INT_STATUS = 0x5e, /* Unused */ TX_STATUS = 0x60, MAC_CTRL = 0x6c, - VLAN_TAG = 0x70, // Unused - PHY_SET = 0x75, // JES20040127EEPROM + VLAN_TAG = 0x70, /* Unused */ + PHY_SET = 0x75, PHY_CTRL = 0x76, STATION_ADDRESS_0 = 0x78, STATION_ADDRESS_1 = 0x7a, @@ -107,11 +90,11 @@ enum ipg_regs { HASHTABLE_1 = 0x90, RMON_STATISTICS_MASK = 0x98, STATISTICS_MASK = 0x9c, - RX_JUMBO_FRAMES = 0xbc, // Unused - TCP_CHECKSUM_ERRORS = 0xc0, // Unused - IP_CHECKSUM_ERRORS = 0xc2, // Unused - UDP_CHECKSUM_ERRORS = 0xc4, // Unused - TX_JUMBO_FRAMES = 0xf4 // Unused + RX_JUMBO_FRAMES = 0xbc, /* Unused */ + TCP_CHECKSUM_ERRORS = 0xc0, /* Unused */ + IP_CHECKSUM_ERRORS = 0xc2, /* Unused */ + UDP_CHECKSUM_ERRORS = 0xc4, /* Unused */ + TX_JUMBO_FRAMES = 0xf4 /* Unused */ }; /* Ethernet MIB statistic register offsets. */ @@ -329,7 +312,7 @@ enum ipg_regs { #define IPG_RM_RECEIVEMULTICASTHASH 0x10 #define IPG_RM_RECEIVEIPMULTICAST 0x20 -/* PhySet JES20040127EEPROM*/ +/* PhySet */ #define IPG_PS_MEM_LENB9B 0x01 #define IPG_PS_MEM_LEN9 0x02 #define IPG_PS_NON_COMPDET 0x04 @@ -386,8 +369,8 @@ enum ipg_regs { #define IPG_AC_RST_OUT 0x01000000 #define IPG_AC_INT_REQUEST 0x02000000 #define IPG_AC_RESET_BUSY 0x04000000 -#define IPG_AC_LED_SPEED 0x08000000 //JES20040127EEPROM -#define IPG_AC_LED_MODE_BIT_1 0x20000000 //JES20040127EEPROM +#define IPG_AC_LED_SPEED 0x08000000 +#define IPG_AC_LED_MODE_BIT_1 0x20000000 /* EepromCtrl */ #define IPG_EC_RSVD_MASK 0x83FF @@ -490,38 +473,34 @@ enum ipg_regs { * Tune */ -/* Miscellaneous Constants. */ -#define TRUE 1 -#define FALSE 0 - /* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */ -#define IPG_APPEND_FCS_ON_TX TRUE +#define IPG_APPEND_FCS_ON_TX 1 /* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */ -#define IPG_STRIP_FCS_ON_RX TRUE +#define IPG_STRIP_FCS_ON_RX 1 /* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with * Ethernet errors. */ -#define IPG_DROP_ON_RX_ETH_ERRORS TRUE +#define IPG_DROP_ON_RX_ETH_ERRORS 1 /* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually * (via TFC). */ -#define IPG_INSERT_MANUAL_VLAN_TAG FALSE +#define IPG_INSERT_MANUAL_VLAN_TAG 0 /* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */ -#define IPG_ADD_IPCHECKSUM_ON_TX FALSE +#define IPG_ADD_IPCHECKSUM_ON_TX 0 /* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX. * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. */ -#define IPG_ADD_TCPCHECKSUM_ON_TX FALSE +#define IPG_ADD_TCPCHECKSUM_ON_TX 0 /* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX. * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER. */ -#define IPG_ADD_UDPCHECKSUM_ON_TX FALSE +#define IPG_ADD_UDPCHECKSUM_ON_TX 0 /* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx * constants as desired. @@ -611,7 +590,7 @@ enum ipg_regs { * Define larger if expecting jumbo frames. */ #ifdef JUMBO_FRAME -//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash +/* IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash */ #define IPG_TXFRAG_SIZE JUMBO_FRAME_SIZE #endif @@ -619,7 +598,7 @@ enum ipg_regs { * Define larger if expecting jumbo frames. */ #ifdef JUMBO_FRAME -//4088=4096-8 +/* 4088 = 4096 - 8 */ #define IPG_RXFRAG_SIZE __IPG_RXFRAG_SIZE #define IPG_RXSUPPORT_SIZE IPG_MAX_RXFRAME_SIZE #else @@ -647,9 +626,9 @@ enum ipg_regs { #define IPG_MINUSEDRFDSTOFREE 0x80 /* specify the jumbo frame maximum size - * per unit is 0x600 (the RxBuffer size that one RFD can carry) + * per unit is 0x600 (the rx_buffer size that one RFD can carry) */ -#define MAX_JUMBOSIZE 0x8 // max is 12K +#define MAX_JUMBOSIZE 0x8 /* max is 12K */ /* Key register values loaded at driver start up. */ @@ -753,8 +732,7 @@ enum ipg_regs { * Miscellaneous macros. */ -/* Marco for printing debug statements. -# define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */ +/* Marco for printing debug statements. */ #ifdef IPG_DEBUG # define IPG_DEBUG_MSG(args...) # define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args) @@ -789,11 +767,12 @@ struct ipg_rx { __le64 frag_info; }; -struct SJumbo { - int FoundStart; - int CurrentSize; +struct ipg_jumbo { + int found_start; + int current_size; struct sk_buff *skb; }; + /* Structure of IPG NIC specific data. */ struct ipg_nic_private { void __iomem *ioaddr; @@ -801,15 +780,14 @@ struct ipg_nic_private { struct ipg_rx *rxd; dma_addr_t txd_map; dma_addr_t rxd_map; - struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH]; - struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH]; + struct sk_buff *tx_buff[IPG_TFDLIST_LENGTH]; + struct sk_buff *rx_buff[IPG_RFDLIST_LENGTH]; unsigned int tx_current; unsigned int tx_dirty; unsigned int rx_current; unsigned int rx_dirty; -// Add by Grace 2005/05/19 #ifdef JUMBO_FRAME - struct SJumbo Jumbo; + struct ipg_jumbo jumbo; #endif unsigned int rx_buf_sz; struct pci_dev *pdev; @@ -818,13 +796,12 @@ struct ipg_nic_private { spinlock_t lock; int tenmbpsmode; - /*Jesse20040128EEPROM_VALUE */ - u16 LED_Mode; + u16 led_mode; u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */ struct mutex mii_mutex; struct mii_if_info mii_if; - int ResetCurrentTFD; + int reset_current_tfd; #ifdef IPG_DEBUG int RFDlistendCount; int RFDListCheckedCount; diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 65806956728a..ce816ba9c40d 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -190,147 +190,6 @@ config KS959_DONGLE To compile it as a module, choose M here: the module will be called ks959-sir. -comment "Old SIR device drivers" - -config IRPORT_SIR - tristate "IrPORT (IrDA serial driver)" - depends on IRDA && BROKEN_ON_SMP - ---help--- - Say Y here if you want to build support for the IrPORT IrDA device - driver. To compile it as a module, choose M here: the module will be - called irport. IrPORT can be used instead of IrTTY and sometimes - this can be better. One example is if your IrDA port does not - have echo-canceling, which will work OK with IrPORT since this - driver is working in half-duplex mode only. You don't need to use - irattach with IrPORT, but you just insert it the same way as FIR - drivers (insmod irport io=0x3e8 irq=11). Notice that IrPORT is a - SIR device driver which means that speed is limited to 115200 bps. - - If unsure, say Y. - -comment "Old Serial dongle support" - -config DONGLE_OLD - bool "Old Serial dongle support" - depends on IRPORT_SIR && BROKEN_ON_SMP - help - Say Y here if you have an infrared device that connects to your - computer's serial port. These devices are called dongles. Then say Y - or M to the driver for your particular dongle below. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about serial dongles. - -config ESI_DONGLE_OLD - tristate "ESI JetEye PC dongle" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the Extended Systems - JetEye PC dongle. To compile it as a module, choose M here. The ESI - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for ESI - dongles you will have to start irattach like this: - "irattach -d esi". - -config ACTISYS_DONGLE_OLD - tristate "ACTiSYS IR-220L and IR220L+ dongle" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the ACTiSYS IR-220L and - IR220L+ dongles. To compile it as a module, choose M here. The - ACTiSYS dongles attaches to the normal 9-pin serial port connector, - and can currently only be used by IrTTY. To activate support for - ACTiSYS dongles you will have to start irattach like this: - "irattach -d actisys" or "irattach -d actisys+". - -config TEKRAM_DONGLE_OLD - tristate "Tekram IrMate 210B dongle" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the Tekram IrMate 210B - dongle. To compile it as a module, choose M here. The Tekram dongle - attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Tekram - dongles you will have to start irattach like this: - "irattach -d tekram". - -config GIRBIL_DONGLE_OLD - tristate "Greenwich GIrBIL dongle" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the Greenwich GIrBIL - dongle. To compile it as a module, choose M here. The Greenwich - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Greenwich - dongles you will have to insert "irattach -d girbil" in the - /etc/irda/drivers script. - -config LITELINK_DONGLE_OLD - tristate "Parallax LiteLink dongle" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the Parallax Litelink - dongle. To compile it as a module, choose M here. The Parallax - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Parallax - dongles you will have to start irattach like this: - "irattach -d litelink". - -config MCP2120_DONGLE_OLD - tristate "Microchip MCP2120" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the Microchip MCP2120 - dongle. To compile it as a module, choose M here. The MCP2120 dongle - attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for MCP2120 - dongles you will have to insert "irattach -d mcp2120" in the - /etc/irda/drivers script. - - You must build this dongle yourself. For more information see: - <http://www.eyetap.org/~tangf/irda_sir_linux.html> - -config OLD_BELKIN_DONGLE_OLD - tristate "Old Belkin dongle" - depends on DONGLE_OLD && IRDA - help - Say Y here if you want to build support for the Adaptec Airport 1000 - and 2000 dongles. To compile it as a module, choose M here: the module - will be called old_belkin. Some information is contained in the - comments at the top of <file:drivers/net/irda/old_belkin.c>. - -config ACT200L_DONGLE_OLD - tristate "ACTiSYS IR-200L dongle (EXPERIMENTAL)" - depends on DONGLE_OLD && EXPERIMENTAL && IRDA - help - Say Y here if you want to build support for the ACTiSYS IR-200L - dongle. To compile it as a module, choose M here. The ACTiSYS - IR-200L dongle attaches to the normal 9-pin serial port connector, - and can currently only be used by IrTTY. To activate support for - ACTiSYS IR-200L dongles you will have to start irattach like this: - "irattach -d act200l". - -config MA600_DONGLE_OLD - tristate "Mobile Action MA600 dongle (EXPERIMENTAL)" - depends on DONGLE_OLD && EXPERIMENTAL && IRDA - ---help--- - Say Y here if you want to build support for the Mobile Action MA600 - dongle. To compile it as a module, choose M here. The MA600 dongle - attaches to the normal 9-pin serial port connector, and can - currently only be tested on IrCOMM. To activate support for MA600 - dongles you will have to insert "irattach -d ma600" in the - /etc/irda/drivers script. Note: irutils 0.9.15 requires no - modification. irutils 0.9.9 needs modification. For more - information, download the following tar gzip file. - - There is a pre-compiled module on - <http://engsvr.ust.hk/~eetwl95/ma600.html> - -config EP7211_IR - tristate "EP7211 I/R support" - depends on DONGLE_OLD && ARCH_EP7211 && IRDA - comment "FIR device drivers" config USB_IRDA diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index fefbb5909081..5d20fde32a24 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -5,8 +5,6 @@ # Rewritten to use lists instead of if-statements. # -# Old SIR drivers -obj-$(CONFIG_IRPORT_SIR) += irport.o # FIR drivers obj-$(CONFIG_USB_IRDA) += irda-usb.o obj-$(CONFIG_SIGMATEL_FIR) += stir4200.o @@ -20,21 +18,10 @@ obj-$(CONFIG_VLSI_FIR) += vlsi_ir.o obj-$(CONFIG_VIA_FIR) += via-ircc.o obj-$(CONFIG_PXA_FICP) += pxaficp_ir.o obj-$(CONFIG_MCS_FIR) += mcs7780.o -# Old dongle drivers for old SIR drivers -obj-$(CONFIG_ESI_DONGLE_OLD) += esi.o -obj-$(CONFIG_TEKRAM_DONGLE_OLD) += tekram.o -obj-$(CONFIG_ACTISYS_DONGLE_OLD) += actisys.o -obj-$(CONFIG_GIRBIL_DONGLE_OLD) += girbil.o -obj-$(CONFIG_LITELINK_DONGLE_OLD) += litelink.o -obj-$(CONFIG_OLD_BELKIN_DONGLE_OLD) += old_belkin.o -obj-$(CONFIG_MCP2120_DONGLE_OLD) += mcp2120.o -obj-$(CONFIG_ACT200L_DONGLE_OLD) += act200l.o -obj-$(CONFIG_MA600_DONGLE_OLD) += ma600.o -obj-$(CONFIG_EP7211_IR) += ep7211_ir.o obj-$(CONFIG_AU1000_FIR) += au1k_ir.o -# New SIR drivers +# SIR drivers obj-$(CONFIG_IRTTY_SIR) += irtty-sir.o sir-dev.o -# New dongles drivers for new SIR drivers +# dongle drivers for SIR drivers obj-$(CONFIG_ESI_DONGLE) += esi-sir.o obj-$(CONFIG_TEKRAM_DONGLE) += tekram-sir.o obj-$(CONFIG_ACTISYS_DONGLE) += actisys-sir.o diff --git a/drivers/net/irda/act200l.c b/drivers/net/irda/act200l.c deleted file mode 100644 index 756cd44e857a..000000000000 --- a/drivers/net/irda/act200l.c +++ /dev/null @@ -1,297 +0,0 @@ -/********************************************************************* - * - * Filename: act200l.c - * Version: 0.8 - * Description: Implementation for the ACTiSYS ACT-IR200L dongle - * Status: Experimental. - * Author: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp> - * Created at: Fri Aug 3 17:35:42 2001 - * Modified at: Fri Aug 17 10:22:40 2001 - * Modified by: SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp> - * - * Copyright (c) 2001 SHIMIZU Takuya, 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. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -static int act200l_reset(struct irda_task *task); -static void act200l_open(dongle_t *self, struct qos_info *qos); -static void act200l_close(dongle_t *self); -static int act200l_change_speed(struct irda_task *task); - -/* Regsiter 0: Control register #1 */ -#define ACT200L_REG0 0x00 -#define ACT200L_TXEN 0x01 /* Enable transmitter */ -#define ACT200L_RXEN 0x02 /* Enable receiver */ - -/* Register 1: Control register #2 */ -#define ACT200L_REG1 0x10 -#define ACT200L_LODB 0x01 /* Load new baud rate count value */ -#define ACT200L_WIDE 0x04 /* Expand the maximum allowable pulse */ - -/* Register 4: Output Power register */ -#define ACT200L_REG4 0x40 -#define ACT200L_OP0 0x01 /* Enable LED1C output */ -#define ACT200L_OP1 0x02 /* Enable LED2C output */ -#define ACT200L_BLKR 0x04 - -/* Register 5: Receive Mode register */ -#define ACT200L_REG5 0x50 -#define ACT200L_RWIDL 0x01 /* fixed 1.6us pulse mode */ - -/* Register 6: Receive Sensitivity register #1 */ -#define ACT200L_REG6 0x60 -#define ACT200L_RS0 0x01 /* receive threshold bit 0 */ -#define ACT200L_RS1 0x02 /* receive threshold bit 1 */ - -/* Register 7: Receive Sensitivity register #2 */ -#define ACT200L_REG7 0x70 -#define ACT200L_ENPOS 0x04 /* Ignore the falling edge */ - -/* Register 8,9: Baud Rate Dvider register #1,#2 */ -#define ACT200L_REG8 0x80 -#define ACT200L_REG9 0x90 - -#define ACT200L_2400 0x5f -#define ACT200L_9600 0x17 -#define ACT200L_19200 0x0b -#define ACT200L_38400 0x05 -#define ACT200L_57600 0x03 -#define ACT200L_115200 0x01 - -/* Register 13: Control register #3 */ -#define ACT200L_REG13 0xd0 -#define ACT200L_SHDW 0x01 /* Enable access to shadow registers */ - -/* Register 15: Status register */ -#define ACT200L_REG15 0xf0 - -/* Register 21: Control register #4 */ -#define ACT200L_REG21 0x50 -#define ACT200L_EXCK 0x02 /* Disable clock output driver */ -#define ACT200L_OSCL 0x04 /* oscillator in low power, medium accuracy mode */ - -static struct dongle_reg dongle = { - .type = IRDA_ACT200L_DONGLE, - .open = act200l_open, - .close = act200l_close, - .reset = act200l_reset, - .change_speed = act200l_change_speed, - .owner = THIS_MODULE, -}; - -static int __init act200l_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit act200l_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void act200l_open(dongle_t *self, struct qos_info *qos) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - /* Power on the dongle */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Set the speeds we can accept */ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x03; -} - -static void act200l_close(dongle_t *self) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - /* Power off the dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -/* - * Function act200l_change_speed (dev, speed) - * - * Set the speed for the ACTiSYS ACT-IR200L type dongle. - * - */ -static int act200l_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - __u8 control[3]; - int ret = 0; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - self->speed_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - if (irda_task_execute(self, act200l_reset, NULL, task, - (void *) speed)) - { - /* Dongle need more time to reset */ - irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); - - /* Give reset 1 sec to finish */ - ret = msecs_to_jiffies(1000); - } - break; - case IRDA_TASK_CHILD_WAIT: - IRDA_WARNING("%s(), resetting dongle timed out!\n", - __FUNCTION__); - ret = -1; - break; - case IRDA_TASK_CHILD_DONE: - /* Clear DTR and set RTS to enter command mode */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - - switch (speed) { - case 9600: - default: - control[0] = ACT200L_REG8 | (ACT200L_9600 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_9600 >> 4) & 0x0f); - break; - case 19200: - control[0] = ACT200L_REG8 | (ACT200L_19200 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_19200 >> 4) & 0x0f); - break; - case 38400: - control[0] = ACT200L_REG8 | (ACT200L_38400 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_38400 >> 4) & 0x0f); - break; - case 57600: - control[0] = ACT200L_REG8 | (ACT200L_57600 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_57600 >> 4) & 0x0f); - break; - case 115200: - control[0] = ACT200L_REG8 | (ACT200L_115200 & 0x0f); - control[1] = ACT200L_REG9 | ((ACT200L_115200 >> 4) & 0x0f); - break; - } - control[2] = ACT200L_REG1 | ACT200L_LODB | ACT200L_WIDE; - - /* Write control bytes */ - self->write(self->dev, control, 3); - irda_task_next_state(task, IRDA_TASK_WAIT); - ret = msecs_to_jiffies(5); - break; - case IRDA_TASK_WAIT: - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - ret = -1; - break; - } - return ret; -} - -/* - * Function act200l_reset (driver) - * - * Reset the ACTiSYS ACT-IR200L type dongle. - */ -static int act200l_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u8 control[9] = { - ACT200L_REG15, - ACT200L_REG13 | ACT200L_SHDW, - ACT200L_REG21 | ACT200L_EXCK | ACT200L_OSCL, - ACT200L_REG13, - ACT200L_REG7 | ACT200L_ENPOS, - ACT200L_REG6 | ACT200L_RS0 | ACT200L_RS1, - ACT200L_REG5 | ACT200L_RWIDL, - ACT200L_REG4 | ACT200L_OP0 | ACT200L_OP1 | ACT200L_BLKR, - ACT200L_REG0 | ACT200L_TXEN | ACT200L_RXEN - }; - int ret = 0; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - self->reset_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - /* Power on the dongle */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_WAIT1); - ret = msecs_to_jiffies(50); - break; - case IRDA_TASK_WAIT1: - /* Reset the dongle : set RTS low for 25 ms */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - - irda_task_next_state(task, IRDA_TASK_WAIT2); - ret = msecs_to_jiffies(50); - break; - case IRDA_TASK_WAIT2: - /* Clear DTR and set RTS to enter command mode */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - - /* Write control bytes */ - self->write(self->dev, control, 9); - irda_task_next_state(task, IRDA_TASK_WAIT3); - ret = msecs_to_jiffies(15); - break; - case IRDA_TASK_WAIT3: - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - ret = -1; - break; - } - return ret; -} - -MODULE_AUTHOR("SHIMIZU Takuya <tshimizu@ga2.so-net.ne.jp>"); -MODULE_DESCRIPTION("ACTiSYS ACT-IR200L dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-10"); /* IRDA_ACT200L_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize ACTiSYS ACT-IR200L module - * - */ -module_init(act200l_init); - -/* - * Function cleanup_module (void) - * - * Cleanup ACTiSYS ACT-IR200L module - * - */ -module_exit(act200l_cleanup); diff --git a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c deleted file mode 100644 index ae0b80a5680c..000000000000 --- a/drivers/net/irda/actisys.c +++ /dev/null @@ -1,288 +0,0 @@ -/********************************************************************* - * - * Filename: actisys.c - * Version: 1.0 - * Description: Implementation for the ACTiSYS IR-220L and IR-220L+ - * dongles - * Status: Beta. - * Authors: Dag Brattli <dagb@cs.uit.no> (initially) - * Jean Tourrilhes <jt@hpl.hp.com> (new version) - * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Fri Dec 17 09:10:43 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved. - * Copyright (c) 1999 Jean Tourrilhes - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -/* - * Changelog - * - * 0.8 -> 0.9999 - Jean - * o New initialisation procedure : much safer and correct - * o New procedure the change speed : much faster and simpler - * o Other cleanups & comments - * Thanks to Lichen Wang @ Actisys for his excellent help... - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -/* - * Define the timing of the pulses we send to the dongle (to reset it, and - * to toggle speeds). Basically, the limit here is the propagation speed of - * the signals through the serial port, the dongle being much faster. Any - * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can - * go through cleanly . If you are on the wild side, you can try to lower - * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!) - */ -#define MIN_DELAY 10 /* 10 us to be on the conservative side */ - -static int actisys_change_speed(struct irda_task *task); -static int actisys_reset(struct irda_task *task); -static void actisys_open(dongle_t *self, struct qos_info *qos); -static void actisys_close(dongle_t *self); - -/* These are the baudrates supported, in the order available */ -/* Note : the 220L doesn't support 38400, but we will fix that below */ -static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 }; -#define MAX_SPEEDS 5 - -static struct dongle_reg dongle = { - .type = IRDA_ACTISYS_DONGLE, - .open = actisys_open, - .close = actisys_close, - .reset = actisys_reset, - .change_speed = actisys_change_speed, - .owner = THIS_MODULE, -}; - -static struct dongle_reg dongle_plus = { - .type = IRDA_ACTISYS_PLUS_DONGLE, - .open = actisys_open, - .close = actisys_close, - .reset = actisys_reset, - .change_speed = actisys_change_speed, - .owner = THIS_MODULE, -}; - -/* - * Function actisys_change_speed (task) - * - * There is two model of Actisys dongle we are dealing with, - * the 220L and 220L+. At this point, only irattach knows with - * kind the user has requested (it was an argument on irattach - * command line). - * So, we register a dongle of each sort and let irattach - * pick the right one... - */ -static int __init actisys_init(void) -{ - int ret; - - /* First, register an Actisys 220L dongle */ - ret = irda_device_register_dongle(&dongle); - if (ret < 0) - return ret; - /* Now, register an Actisys 220L+ dongle */ - ret = irda_device_register_dongle(&dongle_plus); - if (ret < 0) { - irda_device_unregister_dongle(&dongle); - return ret; - } - return 0; -} - -static void __exit actisys_cleanup(void) -{ - /* We have to remove both dongles */ - irda_device_unregister_dongle(&dongle); - irda_device_unregister_dongle(&dongle_plus); -} - -static void actisys_open(dongle_t *self, struct qos_info *qos) -{ - /* Power on the dongle */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Set the speeds we can accept */ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - - /* Remove support for 38400 if this is not a 220L+ dongle */ - if (self->issue->type == IRDA_ACTISYS_DONGLE) - qos->baud_rate.bits &= ~IR_38400; - - qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ -} - -static void actisys_close(dongle_t *self) -{ - /* Power off the dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -/* - * Function actisys_change_speed (task) - * - * Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles. - * To cycle through the available baud rates, pulse RTS low for a few us. - * - * First, we reset the dongle to always start from a known state. - * Then, we cycle through the speeds by pulsing RTS low and then up. - * The dongle allow us to pulse quite fast, se we can set speed in one go, - * which is must faster ( < 100 us) and less complex than what is found - * in some other dongle drivers... - * Note that even if the new speed is the same as the current speed, - * we reassert the speed. This make sure that things are all right, - * and it's fast anyway... - * By the way, this function will work for both type of dongles, - * because the additional speed is at the end of the sequence... - */ -static int actisys_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; /* Target speed */ - int ret = 0; - int i = 0; - - IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__, speed, - self->speed); - - /* Go to a known state by reseting the dongle */ - - /* Reset the dongle : set DTR low for 10 us */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - udelay(MIN_DELAY); - - /* Go back to normal mode (we are now at 9600 b/s) */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* - * Now, we can set the speed requested. Send RTS pulses until we - * reach the target speed - */ - for (i=0; i<MAX_SPEEDS; i++) { - if (speed == baud_rates[i]) { - self->speed = baud_rates[i]; - break; - } - /* Make sure previous pulse is finished */ - udelay(MIN_DELAY); - - /* Set RTS low for 10 us */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - udelay(MIN_DELAY); - - /* Set RTS high for 10 us */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - } - - /* Check if life is sweet... */ - if (i >= MAX_SPEEDS) - ret = -1; /* This should not happen */ - - /* Basta lavoro, on se casse d'ici... */ - irda_task_next_state(task, IRDA_TASK_DONE); - - return ret; -} - -/* - * Function actisys_reset (task) - * - * Reset the Actisys type dongle. Warning, this function must only be - * called with a process context! - * - * We need to do two things in this function : - * o first make sure that the dongle is in a state where it can operate - * o second put the dongle in a know state - * - * The dongle is powered of the RTS and DTR lines. In the dongle, there - * is a big capacitor to accommodate the current spikes. This capacitor - * takes a least 50 ms to be charged. In theory, the Bios set those lines - * up, so by the time we arrive here we should be set. It doesn't hurt - * to be on the conservative side, so we will wait... - * Then, we set the speed to 9600 b/s to get in a known state (see in - * change_speed for details). It is needed because the IrDA stack - * has tried to set the speed immediately after our first return, - * so before we can be sure the dongle is up and running. - */ -static int actisys_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - int ret = 0; - - IRDA_ASSERT(task != NULL, return -1;); - - self->reset_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - /* Set both DTR & RTS to power up the dongle */ - /* In theory redundant with power up in actisys_open() */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Sleep 50 ms to make sure capacitor is charged */ - ret = msecs_to_jiffies(50); - irda_task_next_state(task, IRDA_TASK_WAIT); - break; - case IRDA_TASK_WAIT: - /* Reset the dongle : set DTR low for 10 us */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - udelay(MIN_DELAY); - - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - self->speed = 9600; /* That's the default */ - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - ret = -1; - break; - } - return ret; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-2"); /* IRDA_ACTISYS_DONGLE */ -MODULE_ALIAS("irda-dongle-3"); /* IRDA_ACTISYS_PLUS_DONGLE */ - - -/* - * Function init_module (void) - * - * Initialize Actisys module - * - */ -module_init(actisys_init); - -/* - * Function cleanup_module (void) - * - * Cleanup Actisys module - * - */ -module_exit(actisys_cleanup); diff --git a/drivers/net/irda/ep7211_ir.c b/drivers/net/irda/ep7211_ir.c deleted file mode 100644 index 4cba38f7e4a8..000000000000 --- a/drivers/net/irda/ep7211_ir.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * IR port driver for the Cirrus Logic EP7211 processor. - * - * Copyright 2001, Blue Mug Inc. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> -#include <linux/spinlock.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#include <asm/io.h> -#include <asm/hardware.h> - -#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ -#define MAX_DELAY 10000 /* 1 ms */ - -static void ep7211_ir_open(dongle_t *self, struct qos_info *qos); -static void ep7211_ir_close(dongle_t *self); -static int ep7211_ir_change_speed(struct irda_task *task); -static int ep7211_ir_reset(struct irda_task *task); - -static DEFINE_SPINLOCK(ep7211_lock); - -static struct dongle_reg dongle = { - .type = IRDA_EP7211_IR, - .open = ep7211_ir_open, - .close = ep7211_ir_close, - .reset = ep7211_ir_reset, - .change_speed = ep7211_ir_change_speed, - .owner = THIS_MODULE, -}; - -static void ep7211_ir_open(dongle_t *self, struct qos_info *qos) -{ - unsigned int syscon1, flags; - - spin_lock_irqsave(&ep7211_lock, flags); - - /* Turn on the SIR encoder. */ - syscon1 = clps_readl(SYSCON1); - syscon1 |= SYSCON1_SIREN; - clps_writel(syscon1, SYSCON1); - - /* XXX: We should disable modem status interrupts on the first - UART (interrupt #14). */ - - spin_unlock_irqrestore(&ep7211_lock, flags); -} - -static void ep7211_ir_close(dongle_t *self) -{ - unsigned int syscon1, flags; - - spin_lock_irqsave(&ep7211_lock, flags); - - /* Turn off the SIR encoder. */ - syscon1 = clps_readl(SYSCON1); - syscon1 &= ~SYSCON1_SIREN; - clps_writel(syscon1, SYSCON1); - - /* XXX: If we've disabled the modem status interrupts, we should - reset them back to their original state. */ - - spin_unlock_irqrestore(&ep7211_lock, flags); -} - -/* - * Function ep7211_ir_change_speed (task) - * - * Change speed of the EP7211 I/R port. We don't really have to do anything - * for the EP7211 as long as the rate is being changed at the serial port - * level. - */ -static int ep7211_ir_change_speed(struct irda_task *task) -{ - irda_task_next_state(task, IRDA_TASK_DONE); - return 0; -} - -/* - * Function ep7211_ir_reset (task) - * - * Reset the EP7211 I/R. We don't really have to do anything. - * - */ -static int ep7211_ir_reset(struct irda_task *task) -{ - irda_task_next_state(task, IRDA_TASK_DONE); - return 0; -} - -/* - * Function ep7211_ir_init(void) - * - * Initialize EP7211 I/R module - * - */ -static int __init ep7211_ir_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -/* - * Function ep7211_ir_cleanup(void) - * - * Cleanup EP7211 I/R module - * - */ -static void __exit ep7211_ir_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -MODULE_AUTHOR("Jon McClintock <jonm@bluemug.com>"); -MODULE_DESCRIPTION("EP7211 I/R driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-8"); /* IRDA_EP7211_IR */ - -module_init(ep7211_ir_init); -module_exit(ep7211_ir_cleanup); diff --git a/drivers/net/irda/esi.c b/drivers/net/irda/esi.c deleted file mode 100644 index d3a61af6402d..000000000000 --- a/drivers/net/irda/esi.c +++ /dev/null @@ -1,149 +0,0 @@ -/********************************************************************* - * - * Filename: esi.c - * Version: 1.5 - * Description: Driver for the Extended Systems JetEye PC dongle - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Fri Dec 17 09:14:04 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>, - * Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>, - * 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 <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -static void esi_open(dongle_t *self, struct qos_info *qos); -static void esi_close(dongle_t *self); -static int esi_change_speed(struct irda_task *task); -static int esi_reset(struct irda_task *task); - -static struct dongle_reg dongle = { - .type = IRDA_ESI_DONGLE, - .open = esi_open, - .close = esi_close, - .reset = esi_reset, - .change_speed = esi_change_speed, - .owner = THIS_MODULE, -}; - -static int __init esi_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit esi_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void esi_open(dongle_t *self, struct qos_info *qos) -{ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; - qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ -} - -static void esi_close(dongle_t *dongle) -{ - /* Power off dongle */ - dongle->set_dtr_rts(dongle->dev, FALSE, FALSE); -} - -/* - * Function esi_change_speed (task) - * - * Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle - * - */ -static int esi_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - int dtr, rts; - - switch (speed) { - case 19200: - dtr = TRUE; - rts = FALSE; - break; - case 115200: - dtr = rts = TRUE; - break; - case 9600: - default: - dtr = FALSE; - rts = TRUE; - break; - } - - /* Change speed of dongle */ - self->set_dtr_rts(self->dev, dtr, rts); - self->speed = speed; - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -/* - * Function esi_reset (task) - * - * Reset dongle; - * - */ -static int esi_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - - self->set_dtr_rts(self->dev, FALSE, FALSE); - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-1"); /* IRDA_ESI_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize ESI module - * - */ -module_init(esi_init); - -/* - * Function cleanup_module (void) - * - * Cleanup ESI module - * - */ -module_exit(esi_cleanup); - diff --git a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c deleted file mode 100644 index 1f57391a618b..000000000000 --- a/drivers/net/irda/girbil.c +++ /dev/null @@ -1,250 +0,0 @@ -/********************************************************************* - * - * Filename: girbil.c - * Version: 1.2 - * Description: Implementation for the Greenwich GIrBIL dongle - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sat Feb 6 21:02:33 1999 - * Modified at: Fri Dec 17 09:13:20 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -static int girbil_reset(struct irda_task *task); -static void girbil_open(dongle_t *self, struct qos_info *qos); -static void girbil_close(dongle_t *self); -static int girbil_change_speed(struct irda_task *task); - -/* Control register 1 */ -#define GIRBIL_TXEN 0x01 /* Enable transmitter */ -#define GIRBIL_RXEN 0x02 /* Enable receiver */ -#define GIRBIL_ECAN 0x04 /* Cancel self emmited data */ -#define GIRBIL_ECHO 0x08 /* Echo control characters */ - -/* LED Current Register (0x2) */ -#define GIRBIL_HIGH 0x20 -#define GIRBIL_MEDIUM 0x21 -#define GIRBIL_LOW 0x22 - -/* Baud register (0x3) */ -#define GIRBIL_2400 0x30 -#define GIRBIL_4800 0x31 -#define GIRBIL_9600 0x32 -#define GIRBIL_19200 0x33 -#define GIRBIL_38400 0x34 -#define GIRBIL_57600 0x35 -#define GIRBIL_115200 0x36 - -/* Mode register (0x4) */ -#define GIRBIL_IRDA 0x40 -#define GIRBIL_ASK 0x41 - -/* Control register 2 (0x5) */ -#define GIRBIL_LOAD 0x51 /* Load the new baud rate value */ - -static struct dongle_reg dongle = { - .type = IRDA_GIRBIL_DONGLE, - .open = girbil_open, - .close = girbil_close, - .reset = girbil_reset, - .change_speed = girbil_change_speed, - .owner = THIS_MODULE, -}; - -static int __init girbil_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit girbil_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void girbil_open(dongle_t *self, struct qos_info *qos) -{ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x03; -} - -static void girbil_close(dongle_t *self) -{ - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -/* - * Function girbil_change_speed (dev, speed) - * - * Set the speed for the Girbil type dongle. - * - */ -static int girbil_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - __u8 control[2]; - int ret = 0; - - self->speed_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - /* Need to reset the dongle and go to 9600 bps before - programming */ - if (irda_task_execute(self, girbil_reset, NULL, task, - (void *) speed)) - { - /* Dongle need more time to reset */ - irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); - - /* Give reset 1 sec to finish */ - ret = msecs_to_jiffies(1000); - } - break; - case IRDA_TASK_CHILD_WAIT: - IRDA_WARNING("%s(), resetting dongle timed out!\n", - __FUNCTION__); - ret = -1; - break; - case IRDA_TASK_CHILD_DONE: - /* Set DTR and Clear RTS to enter command mode */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - - switch (speed) { - case 9600: - default: - control[0] = GIRBIL_9600; - break; - case 19200: - control[0] = GIRBIL_19200; - break; - case 34800: - control[0] = GIRBIL_38400; - break; - case 57600: - control[0] = GIRBIL_57600; - break; - case 115200: - control[0] = GIRBIL_115200; - break; - } - control[1] = GIRBIL_LOAD; - - /* Write control bytes */ - self->write(self->dev, control, 2); - irda_task_next_state(task, IRDA_TASK_WAIT); - ret = msecs_to_jiffies(100); - break; - case IRDA_TASK_WAIT: - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - ret = -1; - break; - } - return ret; -} - -/* - * Function girbil_reset (driver) - * - * This function resets the girbil dongle. - * - * Algorithm: - * 0. set RTS, and wait at least 5 ms - * 1. clear RTS - */ -static int girbil_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u8 control = GIRBIL_TXEN | GIRBIL_RXEN; - int ret = 0; - - self->reset_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - /* Reset dongle */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - irda_task_next_state(task, IRDA_TASK_WAIT1); - /* Sleep at least 5 ms */ - ret = msecs_to_jiffies(20); - break; - case IRDA_TASK_WAIT1: - /* Set DTR and clear RTS to enter command mode */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - irda_task_next_state(task, IRDA_TASK_WAIT2); - ret = msecs_to_jiffies(20); - break; - case IRDA_TASK_WAIT2: - /* Write control byte */ - self->write(self->dev, &control, 1); - irda_task_next_state(task, IRDA_TASK_WAIT3); - ret = msecs_to_jiffies(20); - break; - case IRDA_TASK_WAIT3: - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - ret = -1; - break; - } - return ret; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Greenwich GIrBIL dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-4"); /* IRDA_GIRBIL_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize Girbil module - * - */ -module_init(girbil_init); - -/* - * Function cleanup_module (void) - * - * Cleanup Girbil module - * - */ -module_exit(girbil_cleanup); - diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c deleted file mode 100644 index c79caa5d3d71..000000000000 --- a/drivers/net/irda/irport.c +++ /dev/null @@ -1,1123 +0,0 @@ -/********************************************************************* - * - * Filename: irport.c - * Version: 1.0 - * Description: Half duplex serial port SIR driver for IrDA. - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Fri Jan 28 20:22:38 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * Sources: serial.c by Linus Torvalds - * - * Copyright (c) 1997, 1998, 1999-2000 Dag Brattli, All Rights Reserved. - * Copyright (c) 2000-2003 Jean Tourrilhes, 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 - * - * This driver is ment to be a small half duplex serial driver to be - * used for IR-chipsets that has a UART (16550) compatibility mode. - * Eventually it will replace irtty, because of irtty has some - * problems that is hard to get around when we don't have control - * over the serial driver. This driver may also be used by FIR - * drivers to handle SIR mode for them. - * - ********************************************************************/ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/skbuff.h> -#include <linux/serial_reg.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/rtnetlink.h> -#include <linux/bitops.h> - -#include <asm/system.h> -#include <asm/io.h> - -#include <net/irda/irda.h> -#include <net/irda/wrapper.h> -#include "irport.h" - -#define IO_EXTENT 8 - -/* - * Currently you'll need to set these values using insmod like this: - * insmod irport io=0x3e8 irq=11 - */ -static unsigned int io[] = { ~0, ~0, ~0, ~0 }; -static unsigned int irq[] = { 0, 0, 0, 0 }; - -static unsigned int qos_mtt_bits = 0x03; - -static struct irport_cb *dev_self[] = { NULL, NULL, NULL, NULL}; -static char *driver_name = "irport"; - -static inline void irport_write_wakeup(struct irport_cb *self); -static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len); -static inline void irport_receive(struct irport_cb *self); - -static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, - int cmd); -static inline int irport_is_receiving(struct irport_cb *self); -static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts); -static int irport_raw_write(struct net_device *dev, __u8 *buf, int len); -static struct net_device_stats *irport_net_get_stats(struct net_device *dev); -static int irport_change_speed_complete(struct irda_task *task); -static void irport_timeout(struct net_device *dev); - -static irqreturn_t irport_interrupt(int irq, void *dev_id); -static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev); -static void irport_change_speed(void *priv, __u32 speed); -static int irport_net_open(struct net_device *dev); -static int irport_net_close(struct net_device *dev); - -static struct irport_cb * -irport_open(int i, unsigned int iobase, unsigned int irq) -{ - struct net_device *dev; - struct irport_cb *self; - - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); - - /* Lock the port that we need */ - if (!request_region(iobase, IO_EXTENT, driver_name)) { - IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n", - __FUNCTION__, iobase); - goto err_out1; - } - - /* - * Allocate new instance of the driver - */ - dev = alloc_irdadev(sizeof(struct irport_cb)); - if (!dev) { - IRDA_ERROR("%s(), can't allocate memory for " - "irda device!\n", __FUNCTION__); - goto err_out2; - } - - self = dev->priv; - spin_lock_init(&self->lock); - - /* Need to store self somewhere */ - dev_self[i] = self; - self->priv = self; - self->index = i; - - /* Initialize IO */ - self->io.sir_base = iobase; - self->io.sir_ext = IO_EXTENT; - self->io.irq = irq; - self->io.fifo_size = 16; /* 16550A and compatible */ - - /* Initialize QoS for this device */ - irda_init_max_qos_capabilies(&self->qos); - - self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200; - - self->qos.min_turn_time.bits = qos_mtt_bits; - irda_qos_bits_to_value(&self->qos); - - /* Bootstrap ZeroCopy Rx */ - self->rx_buff.truesize = IRDA_SKB_MAX_MTU; - self->rx_buff.skb = __dev_alloc_skb(self->rx_buff.truesize, - GFP_KERNEL); - if (self->rx_buff.skb == NULL) { - IRDA_ERROR("%s(), can't allocate memory for " - "receive buffer!\n", __FUNCTION__); - goto err_out3; - } - skb_reserve(self->rx_buff.skb, 1); - self->rx_buff.head = self->rx_buff.skb->data; - /* No need to memset the buffer, unless you are really pedantic */ - - /* Finish setup the Rx buffer descriptor */ - self->rx_buff.in_frame = FALSE; - self->rx_buff.state = OUTSIDE_FRAME; - self->rx_buff.data = self->rx_buff.head; - - /* Specify how much memory we want */ - self->tx_buff.truesize = 4000; - - /* Allocate memory if needed */ - if (self->tx_buff.truesize > 0) { - self->tx_buff.head = kzalloc(self->tx_buff.truesize, - GFP_KERNEL); - if (self->tx_buff.head == NULL) { - IRDA_ERROR("%s(), can't allocate memory for " - "transmit buffer!\n", __FUNCTION__); - goto err_out4; - } - } - self->tx_buff.data = self->tx_buff.head; - - self->netdev = dev; - - /* May be overridden by piggyback drivers */ - self->interrupt = irport_interrupt; - self->change_speed = irport_change_speed; - - /* Override the network functions we need to use */ - dev->hard_start_xmit = irport_hard_xmit; - dev->tx_timeout = irport_timeout; - dev->watchdog_timeo = HZ; /* Allow time enough for speed change */ - dev->open = irport_net_open; - dev->stop = irport_net_close; - dev->get_stats = irport_net_get_stats; - dev->do_ioctl = irport_net_ioctl; - - /* Make ifconfig display some details */ - dev->base_addr = iobase; - dev->irq = irq; - - if (register_netdev(dev)) { - IRDA_ERROR("%s(), register_netdev() failed!\n", __FUNCTION__); - goto err_out5; - } - IRDA_MESSAGE("IrDA: Registered device %s (irport io=0x%X irq=%d)\n", - dev->name, iobase, irq); - - return self; - err_out5: - kfree(self->tx_buff.head); - err_out4: - kfree_skb(self->rx_buff.skb); - err_out3: - free_netdev(dev); - dev_self[i] = NULL; - err_out2: - release_region(iobase, IO_EXTENT); - err_out1: - return NULL; -} - -static int irport_close(struct irport_cb *self) -{ - IRDA_ASSERT(self != NULL, return -1;); - - /* We are not using any dongle anymore! */ - if (self->dongle) - irda_device_dongle_cleanup(self->dongle); - self->dongle = NULL; - - /* Remove netdevice */ - unregister_netdev(self->netdev); - - /* Release the IO-port that this driver is using */ - IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", - __FUNCTION__, self->io.sir_base); - release_region(self->io.sir_base, self->io.sir_ext); - - kfree(self->tx_buff.head); - - if (self->rx_buff.skb) - kfree_skb(self->rx_buff.skb); - self->rx_buff.skb = NULL; - - /* Remove ourselves */ - dev_self[self->index] = NULL; - free_netdev(self->netdev); - - return 0; -} - -static void irport_stop(struct irport_cb *self) -{ - int iobase; - - iobase = self->io.sir_base; - - /* We can't lock, we may be called from a FIR driver - Jean II */ - - /* We are not transmitting any more */ - self->transmitting = 0; - - /* Reset UART */ - outb(0, iobase+UART_MCR); - - /* Turn off interrupts */ - outb(0, iobase+UART_IER); -} - -static void irport_start(struct irport_cb *self) -{ - int iobase; - - iobase = self->io.sir_base; - - irport_stop(self); - - /* We can't lock, we may be called from a FIR driver - Jean II */ - - /* Initialize UART */ - outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */ - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR); - - /* Turn on interrups */ - outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER); -} - -/* - * Function irport_get_fcr (speed) - * - * Compute value of fcr - * - */ -static inline unsigned int irport_get_fcr(__u32 speed) -{ - unsigned int fcr; /* FIFO control reg */ - - /* Enable fifos */ - fcr = UART_FCR_ENABLE_FIFO; - - /* - * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and - * almost 1,7 ms at 19200 bps. At speeds above that we can just forget - * about this timeout since it will always be fast enough. - */ - if (speed < 38400) - fcr |= UART_FCR_TRIGGER_1; - else - //fcr |= UART_FCR_TRIGGER_14; - fcr |= UART_FCR_TRIGGER_8; - - return(fcr); -} - -/* - * Function irport_change_speed (self, speed) - * - * Set speed of IrDA port to specified baudrate - * - * This function should be called with irq off and spin-lock. - */ -static void irport_change_speed(void *priv, __u32 speed) -{ - struct irport_cb *self = (struct irport_cb *) priv; - int iobase; - unsigned int fcr; /* FIFO control reg */ - unsigned int lcr; /* Line control reg */ - int divisor; - - IRDA_ASSERT(self != NULL, return;); - IRDA_ASSERT(speed != 0, return;); - - IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n", - __FUNCTION__, speed, self->io.sir_base); - - /* We can't lock, we may be called from a FIR driver - Jean II */ - - iobase = self->io.sir_base; - - /* Update accounting for new speed */ - self->io.speed = speed; - - /* Turn off interrupts */ - outb(0, iobase+UART_IER); - - divisor = SPEED_MAX/speed; - - /* Get proper fifo configuration */ - fcr = irport_get_fcr(speed); - - /* IrDA ports use 8N1 */ - lcr = UART_LCR_WLEN8; - - outb(UART_LCR_DLAB | lcr, iobase+UART_LCR); /* Set DLAB */ - outb(divisor & 0xff, iobase+UART_DLL); /* Set speed */ - outb(divisor >> 8, iobase+UART_DLM); - outb(lcr, iobase+UART_LCR); /* Set 8N1 */ - outb(fcr, iobase+UART_FCR); /* Enable FIFO's */ - - /* Turn on interrups */ - /* This will generate a fatal interrupt storm. - * People calling us will do that properly - Jean II */ - //outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); -} - -/* - * Function __irport_change_speed (instance, state, param) - * - * State machine for changing speed of the device. We do it this way since - * we cannot use schedule_timeout() when we are in interrupt context - * - */ -static int __irport_change_speed(struct irda_task *task) -{ - struct irport_cb *self; - __u32 speed = (__u32) task->param; - unsigned long flags = 0; - int wasunlocked = 0; - int ret = 0; - - IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); - - self = (struct irport_cb *) task->instance; - - IRDA_ASSERT(self != NULL, return -1;); - - /* Locking notes : this function may be called from irq context with - * spinlock, via irport_write_wakeup(), or from non-interrupt without - * spinlock (from the task timer). Yuck ! - * This is ugly, and unsafe is the spinlock is not already acquired. - * This will be fixed when irda-task get rewritten. - * Jean II */ - if (!spin_is_locked(&self->lock)) { - spin_lock_irqsave(&self->lock, flags); - wasunlocked = 1; - } - - switch (task->state) { - case IRDA_TASK_INIT: - case IRDA_TASK_WAIT: - /* Are we ready to change speed yet? */ - if (self->tx_buff.len > 0) { - task->state = IRDA_TASK_WAIT; - - /* Try again later */ - ret = msecs_to_jiffies(20); - break; - } - - if (self->dongle) - irda_task_next_state(task, IRDA_TASK_CHILD_INIT); - else - irda_task_next_state(task, IRDA_TASK_CHILD_DONE); - break; - case IRDA_TASK_CHILD_INIT: - /* Go to default speed */ - self->change_speed(self->priv, 9600); - - /* Change speed of dongle */ - if (irda_task_execute(self->dongle, - self->dongle->issue->change_speed, - NULL, task, (void *) speed)) - { - /* Dongle need more time to change its speed */ - irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); - - /* Give dongle 1 sec to finish */ - ret = msecs_to_jiffies(1000); - } else - /* Child finished immediately */ - irda_task_next_state(task, IRDA_TASK_CHILD_DONE); - break; - case IRDA_TASK_CHILD_WAIT: - IRDA_WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__); - ret = -1; - break; - case IRDA_TASK_CHILD_DONE: - /* Finally we are ready to change the speed */ - self->change_speed(self->priv, speed); - - irda_task_next_state(task, IRDA_TASK_DONE); - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - ret = -1; - break; - } - /* Put stuff in the state we found them - Jean II */ - if(wasunlocked) { - spin_unlock_irqrestore(&self->lock, flags); - } - - return ret; -} - -/* - * Function irport_change_speed_complete (task) - * - * Called when the change speed operation completes - * - */ -static int irport_change_speed_complete(struct irda_task *task) -{ - struct irport_cb *self; - - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); - - self = (struct irport_cb *) task->instance; - - IRDA_ASSERT(self != NULL, return -1;); - IRDA_ASSERT(self->netdev != NULL, return -1;); - - /* Finished changing speed, so we are not busy any longer */ - /* Signal network layer so it can try to send the frame */ - - netif_wake_queue(self->netdev); - - return 0; -} - -/* - * Function irport_timeout (struct net_device *dev) - * - * The networking layer thinks we timed out. - * - */ - -static void irport_timeout(struct net_device *dev) -{ - struct irport_cb *self; - int iobase; - int iir, lsr; - unsigned long flags; - - self = (struct irport_cb *) dev->priv; - IRDA_ASSERT(self != NULL, return;); - iobase = self->io.sir_base; - - IRDA_WARNING("%s: transmit timed out, jiffies = %ld, trans_start = %ld\n", - dev->name, jiffies, dev->trans_start); - spin_lock_irqsave(&self->lock, flags); - - /* Debug what's happening... */ - - /* Get interrupt status */ - lsr = inb(iobase+UART_LSR); - /* Read interrupt register */ - iir = inb(iobase+UART_IIR); - IRDA_DEBUG(0, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", - __FUNCTION__, iir, lsr, iobase); - - IRDA_DEBUG(0, "%s(), transmitting=%d, remain=%d, done=%td\n", - __FUNCTION__, self->transmitting, self->tx_buff.len, - self->tx_buff.data - self->tx_buff.head); - - /* Now, restart the port */ - irport_start(self); - self->change_speed(self->priv, self->io.speed); - /* This will re-enable irqs */ - outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER); - dev->trans_start = jiffies; - spin_unlock_irqrestore(&self->lock, flags); - - netif_wake_queue(dev); -} - -/* - * Function irport_wait_hw_transmitter_finish () - * - * Wait for the real end of HW transmission - * - * The UART is a strict FIFO, and we get called only when we have finished - * pushing data to the FIFO, so the maximum amount of time we must wait - * is only for the FIFO to drain out. - * - * We use a simple calibrated loop. We may need to adjust the loop - * delay (udelay) to balance I/O traffic and latency. And we also need to - * adjust the maximum timeout. - * It would probably be better to wait for the proper interrupt, - * but it doesn't seem to be available. - * - * We can't use jiffies or kernel timers because : - * 1) We are called from the interrupt handler, which disable softirqs, - * so jiffies won't be increased - * 2) Jiffies granularity is usually very coarse (10ms), and we don't - * want to wait that long to detect stuck hardware. - * Jean II - */ - -static void irport_wait_hw_transmitter_finish(struct irport_cb *self) -{ - int iobase; - int count = 1000; /* 1 ms */ - - iobase = self->io.sir_base; - - /* Calibrated busy loop */ - while((count-- > 0) && !(inb(iobase+UART_LSR) & UART_LSR_TEMT)) - udelay(1); - - if(count == 0) - IRDA_DEBUG(0, "%s(): stuck transmitter\n", __FUNCTION__); -} - -/* - * Function irport_hard_start_xmit (struct sk_buff *skb, struct net_device *dev) - * - * Transmits the current frame until FIFO is full, then - * waits until the next transmitt interrupt, and continues until the - * frame is transmitted. - */ -static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct irport_cb *self; - unsigned long flags; - int iobase; - s32 speed; - - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); - - IRDA_ASSERT(dev != NULL, return 0;); - - self = (struct irport_cb *) dev->priv; - IRDA_ASSERT(self != NULL, return 0;); - - iobase = self->io.sir_base; - - netif_stop_queue(dev); - - /* Make sure tests & speed change are atomic */ - spin_lock_irqsave(&self->lock, flags); - - /* Check if we need to change the speed */ - speed = irda_get_next_speed(skb); - if ((speed != self->io.speed) && (speed != -1)) { - /* Check for empty frame */ - if (!skb->len) { - /* - * We send frames one by one in SIR mode (no - * pipelining), so at this point, if we were sending - * a previous frame, we just received the interrupt - * telling us it is finished (UART_IIR_THRI). - * Therefore, waiting for the transmitter to really - * finish draining the fifo won't take too long. - * And the interrupt handler is not expected to run. - * - Jean II */ - irport_wait_hw_transmitter_finish(self); - /* Better go there already locked - Jean II */ - irda_task_execute(self, __irport_change_speed, - irport_change_speed_complete, - NULL, (void *) speed); - dev->trans_start = jiffies; - spin_unlock_irqrestore(&self->lock, flags); - dev_kfree_skb(skb); - return 0; - } else - self->new_speed = speed; - } - - /* Init tx buffer */ - self->tx_buff.data = self->tx_buff.head; - - /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ - self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, - self->tx_buff.truesize); - - self->stats.tx_bytes += self->tx_buff.len; - - /* We are transmitting */ - self->transmitting = 1; - - /* Turn on transmit finished interrupt. Will fire immediately! */ - outb(UART_IER_THRI, iobase+UART_IER); - - dev->trans_start = jiffies; - spin_unlock_irqrestore(&self->lock, flags); - - dev_kfree_skb(skb); - - return 0; -} - -/* - * Function irport_write (driver) - * - * Fill Tx FIFO with transmit data - * - * Called only from irport_write_wakeup() - */ -static inline int irport_write(int iobase, int fifo_size, __u8 *buf, int len) -{ - int actual = 0; - - /* Fill FIFO with current frame */ - while ((actual < fifo_size) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual], iobase+UART_TX); - - actual++; - } - - return actual; -} - -/* - * Function irport_write_wakeup (tty) - * - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - * - * Called only from irport_interrupt() - * Make sure this function is *not* called while we are receiving, - * otherwise we will reset fifo and loose data :-( - */ -static inline void irport_write_wakeup(struct irport_cb *self) -{ - int actual = 0; - int iobase; - unsigned int fcr; - - IRDA_ASSERT(self != NULL, return;); - - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - - iobase = self->io.sir_base; - - /* Finished with frame? */ - if (self->tx_buff.len > 0) { - /* Write data left in transmit buffer */ - actual = irport_write(iobase, self->io.fifo_size, - self->tx_buff.data, self->tx_buff.len); - self->tx_buff.data += actual; - self->tx_buff.len -= actual; - } else { - /* - * Now serial buffer is almost free & we can start - * transmission of another packet. But first we must check - * if we need to change the speed of the hardware - */ - if (self->new_speed) { - irport_wait_hw_transmitter_finish(self); - irda_task_execute(self, __irport_change_speed, - irport_change_speed_complete, - NULL, (void *) self->new_speed); - self->new_speed = 0; - } else { - /* Tell network layer that we want more frames */ - netif_wake_queue(self->netdev); - } - self->stats.tx_packets++; - - /* - * Reset Rx FIFO to make sure that all reflected transmit data - * is discarded. This is needed for half duplex operation - */ - fcr = irport_get_fcr(self->io.speed); - fcr |= UART_FCR_CLEAR_RCVR; - outb(fcr, iobase+UART_FCR); - - /* Finished transmitting */ - self->transmitting = 0; - - /* Turn on receive interrupts */ - outb(UART_IER_RDI, iobase+UART_IER); - - IRDA_DEBUG(1, "%s() : finished Tx\n", __FUNCTION__); - } -} - -/* - * Function irport_receive (self) - * - * Receive one frame from the infrared port - * - * Called only from irport_interrupt() - */ -static inline void irport_receive(struct irport_cb *self) -{ - int boguscount = 0; - int iobase; - - IRDA_ASSERT(self != NULL, return;); - - iobase = self->io.sir_base; - - /* - * Receive all characters in Rx FIFO, unwrap and unstuff them. - * async_unwrap_char will deliver all found frames - */ - do { - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, - inb(iobase+UART_RX)); - - /* Make sure we don't stay here too long */ - if (boguscount++ > 32) { - IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__); - break; - } - } while (inb(iobase+UART_LSR) & UART_LSR_DR); -} - -/* - * Function irport_interrupt (irq, dev_id) - * - * Interrupt handler - */ -static irqreturn_t irport_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct irport_cb *self; - int boguscount = 0; - int iobase; - int iir, lsr; - int handled = 0; - - self = dev->priv; - - spin_lock(&self->lock); - - iobase = self->io.sir_base; - - /* Cut'n'paste interrupt routine from serial.c - * This version try to minimise latency and I/O operations. - * Simplified and modified to enforce half duplex operation. - * - Jean II */ - - /* Check status even is iir reg is cleared, more robust and - * eliminate a read on the I/O bus - Jean II */ - do { - /* Get interrupt status ; Clear interrupt */ - lsr = inb(iobase+UART_LSR); - - /* Are we receiving or transmitting ? */ - if(!self->transmitting) { - /* Received something ? */ - if (lsr & UART_LSR_DR) - irport_receive(self); - } else { - /* Room in Tx fifo ? */ - if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) - irport_write_wakeup(self); - } - - /* A bit hackish, but working as expected... Jean II */ - if(lsr & (UART_LSR_THRE | UART_LSR_TEMT | UART_LSR_DR)) - handled = 1; - - /* Make sure we don't stay here to long */ - if (boguscount++ > 10) { - IRDA_WARNING("%s() irq handler looping : lsr=%02x\n", - __FUNCTION__, lsr); - break; - } - - /* Read interrupt register */ - iir = inb(iobase+UART_IIR); - - /* Enable this debug only when no other options and at low - * bit rates, otherwise it may cause Rx overruns (lsr=63). - * - Jean II */ - IRDA_DEBUG(6, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", - __FUNCTION__, iir, lsr, iobase); - - /* As long as interrupt pending... */ - } while ((iir & UART_IIR_NO_INT) == 0); - - spin_unlock(&self->lock); - return IRQ_RETVAL(handled); -} - -/* - * Function irport_net_open (dev) - * - * Network device is taken up. Usually this is done by "ifconfig irda0 up" - * - */ -static int irport_net_open(struct net_device *dev) -{ - struct irport_cb *self; - int iobase; - char hwname[16]; - unsigned long flags; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - - IRDA_ASSERT(dev != NULL, return -1;); - self = (struct irport_cb *) dev->priv; - - iobase = self->io.sir_base; - - if (request_irq(self->io.irq, self->interrupt, 0, dev->name, - (void *) dev)) { - IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n", - __FUNCTION__, self->io.irq); - return -EAGAIN; - } - - spin_lock_irqsave(&self->lock, flags); - /* Init uart */ - irport_start(self); - /* Set 9600 bauds per default, including at the dongle */ - irda_task_execute(self, __irport_change_speed, - irport_change_speed_complete, - NULL, (void *) 9600); - spin_unlock_irqrestore(&self->lock, flags); - - - /* Give self a hardware name */ - sprintf(hwname, "SIR @ 0x%03x", self->io.sir_base); - - /* - * Open new IrLAP layer instance, now that everything should be - * initialized properly - */ - self->irlap = irlap_open(dev, &self->qos, hwname); - - /* Ready to play! */ - - netif_start_queue(dev); - - return 0; -} - -/* - * Function irport_net_close (self) - * - * Network device is taken down. Usually this is done by - * "ifconfig irda0 down" - */ -static int irport_net_close(struct net_device *dev) -{ - struct irport_cb *self; - int iobase; - unsigned long flags; - - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - - IRDA_ASSERT(dev != NULL, return -1;); - self = (struct irport_cb *) dev->priv; - - IRDA_ASSERT(self != NULL, return -1;); - - iobase = self->io.sir_base; - - /* Stop device */ - netif_stop_queue(dev); - - /* Stop and remove instance of IrLAP */ - if (self->irlap) - irlap_close(self->irlap); - self->irlap = NULL; - - spin_lock_irqsave(&self->lock, flags); - irport_stop(self); - spin_unlock_irqrestore(&self->lock, flags); - - free_irq(self->io.irq, dev); - - return 0; -} - -/* - * Function irport_is_receiving (self) - * - * Returns true is we are currently receiving data - * - */ -static inline int irport_is_receiving(struct irport_cb *self) -{ - return (self->rx_buff.state != OUTSIDE_FRAME); -} - -/* - * Function irport_set_dtr_rts (tty, dtr, rts) - * - * This function can be used by dongles etc. to set or reset the status - * of the dtr and rts lines - */ -static int irport_set_dtr_rts(struct net_device *dev, int dtr, int rts) -{ - struct irport_cb *self = dev->priv; - int iobase; - - IRDA_ASSERT(self != NULL, return -1;); - - iobase = self->io.sir_base; - - if (dtr) - dtr = UART_MCR_DTR; - if (rts) - rts = UART_MCR_RTS; - - outb(dtr|rts|UART_MCR_OUT2, iobase+UART_MCR); - - return 0; -} - -static int irport_raw_write(struct net_device *dev, __u8 *buf, int len) -{ - struct irport_cb *self = (struct irport_cb *) dev->priv; - int actual = 0; - int iobase; - - IRDA_ASSERT(self != NULL, return -1;); - - iobase = self->io.sir_base; - - /* Tx FIFO should be empty! */ - if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) { - IRDA_DEBUG( 0, "%s(), failed, fifo not empty!\n", __FUNCTION__); - return -1; - } - - /* Fill FIFO with current frame */ - while (actual < len) { - /* Transmit next byte */ - outb(buf[actual], iobase+UART_TX); - actual++; - } - - return actual; -} - -/* - * Function irport_net_ioctl (dev, rq, cmd) - * - * Process IOCTL commands for this device - * - */ -static int irport_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct if_irda_req *irq = (struct if_irda_req *) rq; - struct irport_cb *self; - dongle_t *dongle; - unsigned long flags; - int ret = 0; - - IRDA_ASSERT(dev != NULL, return -1;); - - self = dev->priv; - - IRDA_ASSERT(self != NULL, return -1;); - - IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd); - - switch (cmd) { - case SIOCSBANDWIDTH: /* Set bandwidth */ - if (!capable(CAP_NET_ADMIN)) - ret = -EPERM; - else - irda_task_execute(self, __irport_change_speed, NULL, - NULL, (void *) irq->ifr_baudrate); - break; - case SIOCSDONGLE: /* Set dongle */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - - /* Locking : - * irda_device_dongle_init() can't be locked. - * irda_task_execute() doesn't need to be locked. - * Jean II - */ - - /* Initialize dongle */ - dongle = irda_device_dongle_init(dev, irq->ifr_dongle); - if (!dongle) - break; - - dongle->set_mode = NULL; - dongle->read = NULL; - dongle->write = irport_raw_write; - dongle->set_dtr_rts = irport_set_dtr_rts; - - /* Now initialize the dongle! */ - dongle->issue->open(dongle, &self->qos); - - /* Reset dongle */ - irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, - NULL); - - /* Make dongle available to driver only now to avoid - * race conditions - Jean II */ - self->dongle = dongle; - break; - case SIOCSMEDIABUSY: /* Set media busy */ - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - - irda_device_set_media_busy(self->netdev, TRUE); - break; - case SIOCGRECEIVING: /* Check if we are receiving right now */ - irq->ifr_receiving = irport_is_receiving(self); - break; - case SIOCSDTRRTS: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - - /* No real need to lock... */ - spin_lock_irqsave(&self->lock, flags); - irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts); - spin_unlock_irqrestore(&self->lock, flags); - break; - default: - ret = -EOPNOTSUPP; - } - - return ret; -} - -static struct net_device_stats *irport_net_get_stats(struct net_device *dev) -{ - struct irport_cb *self = (struct irport_cb *) dev->priv; - - return &self->stats; -} - -static int __init irport_init(void) -{ - int i; - - for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) { - if (irport_open(i, io[i], irq[i]) != NULL) - return 0; - } - /* - * Maybe something failed, but we can still be usable for FIR drivers - */ - return 0; -} - -/* - * Function irport_cleanup () - * - * Close all configured ports - * - */ -static void __exit irport_cleanup(void) -{ - int i; - - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); - - for (i=0; i < ARRAY_SIZE(dev_self); i++) { - if (dev_self[i]) - irport_close(dev_self[i]); - } -} - -module_param_array(io, int, NULL, 0); -MODULE_PARM_DESC(io, "Base I/O addresses"); -module_param_array(irq, int, NULL, 0); -MODULE_PARM_DESC(irq, "IRQ lines"); - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode"); -MODULE_LICENSE("GPL"); - -module_init(irport_init); -module_exit(irport_cleanup); - diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h deleted file mode 100644 index 66fc2433e97d..000000000000 --- a/drivers/net/irda/irport.h +++ /dev/null @@ -1,80 +0,0 @@ -/********************************************************************* - * - * Filename: irport.h - * Version: 0.1 - * Description: Serial driver for IrDA - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Sun Aug 3 13:49:59 1997 - * Modified at: Fri Jan 14 10:21:10 2000 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1997, 1998-2000 Dag Brattli <dagb@cs.uit.no> - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRPORT_H -#define IRPORT_H - -#include <linux/netdevice.h> -#include <linux/skbuff.h> -#include <linux/types.h> -#include <linux/spinlock.h> - -#include <net/irda/irda_device.h> - -#define SPEED_DEFAULT 9600 -#define SPEED_MAX 115200 - -/* - * These are the supported serial types. - */ -#define PORT_UNKNOWN 0 -#define PORT_8250 1 -#define PORT_16450 2 -#define PORT_16550 3 -#define PORT_16550A 4 -#define PORT_CIRRUS 5 -#define PORT_16650 6 -#define PORT_MAX 6 - -#define FRAME_MAX_SIZE 2048 - -struct irport_cb { - struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; - - struct irlap_cb *irlap; /* The link layer we are attached to */ - - chipio_t io; /* IrDA controller information */ - iobuff_t tx_buff; /* Transmit buffer */ - iobuff_t rx_buff; /* Receive buffer */ - - struct qos_info qos; /* QoS capabilities for this device */ - dongle_t *dongle; /* Dongle driver */ - - __u32 flags; /* Interface flags */ - __u32 new_speed; - int mode; - int index; /* Instance index */ - int transmitting; /* Are we transmitting ? */ - - spinlock_t lock; /* For serializing operations */ - - /* For piggyback drivers */ - void *priv; - void (*change_speed)(void *priv, __u32 speed); - irqreturn_t (*interrupt)(int irq, void *dev_id); -}; - -#endif /* IRPORT_H */ diff --git a/drivers/net/irda/litelink.c b/drivers/net/irda/litelink.c deleted file mode 100644 index 7db11431d0f4..000000000000 --- a/drivers/net/irda/litelink.c +++ /dev/null @@ -1,179 +0,0 @@ -/********************************************************************* - * - * Filename: litelink.c - * Version: 1.1 - * Description: Driver for the Parallax LiteLink dongle - * Status: Stable - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Fri May 7 12:50:33 1999 - * Modified at: Fri Dec 17 09:14:23 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Dag Brattli, 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 <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ -#define MAX_DELAY 10000 /* 1 ms */ - -static void litelink_open(dongle_t *self, struct qos_info *qos); -static void litelink_close(dongle_t *self); -static int litelink_change_speed(struct irda_task *task); -static int litelink_reset(struct irda_task *task); - -/* These are the baudrates supported */ -static __u32 baud_rates[] = { 115200, 57600, 38400, 19200, 9600 }; - -static struct dongle_reg dongle = { - .type = IRDA_LITELINK_DONGLE, - .open = litelink_open, - .close = litelink_close, - .reset = litelink_reset, - .change_speed = litelink_change_speed, - .owner = THIS_MODULE, -}; - -static int __init litelink_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit litelink_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void litelink_open(dongle_t *self, struct qos_info *qos) -{ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */ -} - -static void litelink_close(dongle_t *self) -{ - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -/* - * Function litelink_change_speed (task) - * - * Change speed of the Litelink dongle. To cycle through the available - * baud rates, pulse RTS low for a few ms. - */ -static int litelink_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - int i; - - /* Clear RTS to reset dongle */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Cycle through avaiable baudrates until we reach the correct one */ - for (i=0; i<5 && baud_rates[i] != speed; i++) { - /* Set DTR, clear RTS */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Set DTR, Set RTS */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - } - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -/* - * Function litelink_reset (task) - * - * Reset the Litelink type dongle. - * - */ -static int litelink_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - - /* Power on dongle */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Clear RTS to reset dongle */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* This dongles speed defaults to 115200 bps */ - self->speed = 115200; - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Parallax Litelink dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-5"); /* IRDA_LITELINK_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize Litelink module - * - */ -module_init(litelink_init); - -/* - * Function cleanup_module (void) - * - * Cleanup Litelink module - * - */ -module_exit(litelink_cleanup); diff --git a/drivers/net/irda/ma600.c b/drivers/net/irda/ma600.c deleted file mode 100644 index f5e6836667fd..000000000000 --- a/drivers/net/irda/ma600.c +++ /dev/null @@ -1,354 +0,0 @@ -/********************************************************************* - * - * Filename: ma600.c - * Version: 0.1 - * Description: Implementation of the MA600 dongle - * Status: Experimental. - * Author: Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95 - * Created at: Sat Jun 10 20:02:35 2000 - * Modified at: - * Modified by: - * - * Note: very thanks to Mr. Maru Wang <maru@mobileaction.com.tw> for providing - * information on the MA600 dongle - * - * Copyright (c) 2000 Leung, 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 - * - ********************************************************************/ - -/* define this macro for release version */ -//#define NDEBUG - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -#ifndef NDEBUG - #undef IRDA_DEBUG - #define IRDA_DEBUG(n, args...) (printk(KERN_DEBUG args)) - - #undef ASSERT - #define ASSERT(expr, func) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n",\ - #expr,__FILE__,__FUNCTION__,__LINE__); \ - func} -#endif - -/* convert hex value to ascii hex */ -static const char hexTbl[] = "0123456789ABCDEF"; - - -static void ma600_open(dongle_t *self, struct qos_info *qos); -static void ma600_close(dongle_t *self); -static int ma600_change_speed(struct irda_task *task); -static int ma600_reset(struct irda_task *task); - -/* control byte for MA600 */ -#define MA600_9600 0x00 -#define MA600_19200 0x01 -#define MA600_38400 0x02 -#define MA600_57600 0x03 -#define MA600_115200 0x04 -#define MA600_DEV_ID1 0x05 -#define MA600_DEV_ID2 0x06 -#define MA600_2400 0x08 - -static struct dongle_reg dongle = { - .type = IRDA_MA600_DONGLE, - .open = ma600_open, - .close = ma600_close, - .reset = ma600_reset, - .change_speed = ma600_change_speed, - .owner = THIS_MODULE, -}; - -static int __init ma600_init(void) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - return irda_device_register_dongle(&dongle); -} - -static void __exit ma600_cleanup(void) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - irda_device_unregister_dongle(&dongle); -} - -/* - Power on: - (0) Clear RTS and DTR for 1 second - (1) Set RTS and DTR for 1 second - (2) 9600 bps now - Note: assume RTS, DTR are clear before -*/ -static void ma600_open(dongle_t *self, struct qos_info *qos) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - - qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400 - |IR_57600|IR_115200; - qos->min_turn_time.bits = 0x01; /* Needs at least 1 ms */ - irda_qos_bits_to_value(qos); - - //self->set_dtr_rts(self->dev, FALSE, FALSE); - // should wait 1 second - - self->set_dtr_rts(self->dev, TRUE, TRUE); - // should wait 1 second -} - -static void ma600_close(dongle_t *self) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -static __u8 get_control_byte(__u32 speed) -{ - __u8 byte; - - switch (speed) { - default: - case 115200: - byte = MA600_115200; - break; - case 57600: - byte = MA600_57600; - break; - case 38400: - byte = MA600_38400; - break; - case 19200: - byte = MA600_19200; - break; - case 9600: - byte = MA600_9600; - break; - case 2400: - byte = MA600_2400; - break; - } - - return byte; -} - -/* - * Function ma600_change_speed (dev, state, speed) - * - * Set the speed for the MA600 type dongle. Warning, this - * function must be called with a process context! - * - * Algorithm - * 1. Reset - * 2. clear RTS, set DTR and wait for 1ms - * 3. send Control Byte to the MA600 through TXD to set new baud rate - * wait until the stop bit of Control Byte is sent (for 9600 baud rate, - * it takes about 10 msec) - * 4. set RTS, set DTR (return to NORMAL Operation) - * 5. wait at least 10 ms, new setting (baud rate, etc) takes effect here - * after - */ -static int ma600_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - static __u8 byte; - __u8 byte_echo; - int ret = 0; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - - ASSERT(task != NULL, return -1;); - - if (self->speed_task && self->speed_task != task) { - IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__); - return msecs_to_jiffies(10); - } else { - self->speed_task = task; - } - - switch (task->state) { - case IRDA_TASK_INIT: - case IRDA_TASK_CHILD_INIT: - /* - * Need to reset the dongle and go to 9600 bps before - * programming - */ - if (irda_task_execute(self, ma600_reset, NULL, task, - (void *) speed)) { - /* Dongle need more time to reset */ - irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); - - /* give 1 second to finish */ - ret = msecs_to_jiffies(1000); - } else { - irda_task_next_state(task, IRDA_TASK_CHILD_DONE); - } - break; - - case IRDA_TASK_CHILD_WAIT: - IRDA_WARNING("%s(), resetting dongle timed out!\n", - __FUNCTION__); - ret = -1; - break; - - case IRDA_TASK_CHILD_DONE: - /* Set DTR, Clear RTS */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - - ret = msecs_to_jiffies(1); /* Sleep 1 ms */ - irda_task_next_state(task, IRDA_TASK_WAIT); - break; - - case IRDA_TASK_WAIT: - speed = (__u32) task->param; - byte = get_control_byte(speed); - - /* Write control byte */ - self->write(self->dev, &byte, sizeof(byte)); - - irda_task_next_state(task, IRDA_TASK_WAIT1); - - /* Wait at least 10 ms */ - ret = msecs_to_jiffies(15); - break; - - case IRDA_TASK_WAIT1: - /* Read control byte echo */ - self->read(self->dev, &byte_echo, sizeof(byte_echo)); - - if(byte != byte_echo) { - /* if control byte != echo, I don't know what to do */ - printk(KERN_WARNING "%s() control byte written != read!\n", __FUNCTION__); - printk(KERN_WARNING "control byte = 0x%c%c\n", - hexTbl[(byte>>4)&0x0f], hexTbl[byte&0x0f]); - printk(KERN_WARNING "byte echo = 0x%c%c\n", - hexTbl[(byte_echo>>4) & 0x0f], - hexTbl[byte_echo & 0x0f]); - #ifndef NDEBUG - } else { - IRDA_DEBUG(2, "%s() control byte write read OK\n", __FUNCTION__); - #endif - } - - /* Set DTR, Set RTS */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_WAIT2); - - /* Wait at least 10 ms */ - ret = msecs_to_jiffies(10); - break; - - case IRDA_TASK_WAIT2: - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - break; - - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - ret = -1; - break; - } - return ret; -} - -/* - * Function ma600_reset (driver) - * - * This function resets the ma600 dongle. Warning, this function - * must be called with a process context!! - * - * Algorithm: - * 0. DTR=0, RTS=1 and wait 10 ms - * 1. DTR=1, RTS=1 and wait 10 ms - * 2. 9600 bps now - */ -int ma600_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - int ret = 0; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - - ASSERT(task != NULL, return -1;); - - if (self->reset_task && self->reset_task != task) { - IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__); - return msecs_to_jiffies(10); - } else - self->reset_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - /* Clear DTR and Set RTS */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - irda_task_next_state(task, IRDA_TASK_WAIT1); - ret = msecs_to_jiffies(10); /* Sleep 10 ms */ - break; - case IRDA_TASK_WAIT1: - /* Set DTR and RTS */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - irda_task_next_state(task, IRDA_TASK_WAIT2); - ret = msecs_to_jiffies(10); /* Sleep 10 ms */ - break; - case IRDA_TASK_WAIT2: - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - ret = -1; - } - return ret; -} - -MODULE_AUTHOR("Leung <95Etwl@alumni.ee.ust.hk> http://www.engsvr.ust/~eetwl95"); -MODULE_DESCRIPTION("MA600 dongle driver version 0.1"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-11"); /* IRDA_MA600_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize MA600 module - * - */ -module_init(ma600_init); - -/* - * Function cleanup_module (void) - * - * Cleanup MA600 module - * - */ -module_exit(ma600_cleanup); - diff --git a/drivers/net/irda/mcp2120.c b/drivers/net/irda/mcp2120.c deleted file mode 100644 index 5e6199eeef4f..000000000000 --- a/drivers/net/irda/mcp2120.c +++ /dev/null @@ -1,240 +0,0 @@ -/********************************************************************* - * - * - * Filename: mcp2120.c - * Version: 1.0 - * Description: Implementation for the MCP2120 (Microchip) - * Status: Experimental. - * Author: Felix Tang (tangf@eyetap.org) - * Created at: Sun Mar 31 19:32:12 EST 2002 - * Based on code by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 2002 Felix Tang, 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. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -static int mcp2120_reset(struct irda_task *task); -static void mcp2120_open(dongle_t *self, struct qos_info *qos); -static void mcp2120_close(dongle_t *self); -static int mcp2120_change_speed(struct irda_task *task); - -#define MCP2120_9600 0x87 -#define MCP2120_19200 0x8B -#define MCP2120_38400 0x85 -#define MCP2120_57600 0x83 -#define MCP2120_115200 0x81 - -#define MCP2120_COMMIT 0x11 - -static struct dongle_reg dongle = { - .type = IRDA_MCP2120_DONGLE, - .open = mcp2120_open, - .close = mcp2120_close, - .reset = mcp2120_reset, - .change_speed = mcp2120_change_speed, - .owner = THIS_MODULE, -}; - -static int __init mcp2120_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit mcp2120_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void mcp2120_open(dongle_t *self, struct qos_info *qos) -{ - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x01; -} - -static void mcp2120_close(dongle_t *self) -{ - /* Power off dongle */ - /* reset and inhibit mcp2120 */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - //self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -/* - * Function mcp2120_change_speed (dev, speed) - * - * Set the speed for the MCP2120. - * - */ -static int mcp2120_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - __u8 control[2]; - int ret = 0; - - self->speed_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - /* Need to reset the dongle and go to 9600 bps before - programming */ - //printk("Dmcp2120_change_speed irda_task_init\n"); - if (irda_task_execute(self, mcp2120_reset, NULL, task, - (void *) speed)) - { - /* Dongle need more time to reset */ - irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); - - /* Give reset 1 sec to finish */ - ret = msecs_to_jiffies(1000); - } - break; - case IRDA_TASK_CHILD_WAIT: - IRDA_WARNING("%s(), resetting dongle timed out!\n", - __FUNCTION__); - ret = -1; - break; - case IRDA_TASK_CHILD_DONE: - /* Set DTR to enter command mode */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - udelay(500); - - switch (speed) { - case 9600: - default: - control[0] = MCP2120_9600; - //printk("mcp2120 9600\n"); - break; - case 19200: - control[0] = MCP2120_19200; - //printk("mcp2120 19200\n"); - break; - case 34800: - control[0] = MCP2120_38400; - //printk("mcp2120 38400\n"); - break; - case 57600: - control[0] = MCP2120_57600; - //printk("mcp2120 57600\n"); - break; - case 115200: - control[0] = MCP2120_115200; - //printk("mcp2120 115200\n"); - break; - } - control[1] = MCP2120_COMMIT; - - /* Write control bytes */ - self->write(self->dev, control, 2); - - irda_task_next_state(task, IRDA_TASK_WAIT); - ret = msecs_to_jiffies(100); - //printk("mcp2120_change_speed irda_child_done\n"); - break; - case IRDA_TASK_WAIT: - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, FALSE, FALSE); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - //printk("mcp2120_change_speed irda_task_wait\n"); - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - ret = -1; - break; - } - return ret; -} - -/* - * Function mcp2120_reset (driver) - * - * This function resets the mcp2120 dongle. - * - * Info: -set RTS to reset mcp2120 - * -set DTR to set mcp2120 software command mode - * -mcp2120 defaults to 9600 baud after reset - * - * Algorithm: - * 0. Set RTS to reset mcp2120. - * 1. Clear RTS and wait for device reset timer of 30 ms (max). - * - */ - - -static int mcp2120_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - int ret = 0; - - self->reset_task = task; - - switch (task->state) { - case IRDA_TASK_INIT: - //printk("mcp2120_reset irda_task_init\n"); - /* Reset dongle by setting RTS*/ - self->set_dtr_rts(self->dev, TRUE, TRUE); - irda_task_next_state(task, IRDA_TASK_WAIT1); - ret = msecs_to_jiffies(50); - break; - case IRDA_TASK_WAIT1: - //printk("mcp2120_reset irda_task_wait1\n"); - /* clear RTS and wait for at least 30 ms. */ - self->set_dtr_rts(self->dev, FALSE, FALSE); - irda_task_next_state(task, IRDA_TASK_WAIT2); - ret = msecs_to_jiffies(50); - break; - case IRDA_TASK_WAIT2: - //printk("mcp2120_reset irda_task_wait2\n"); - /* Go back to normal mode */ - self->set_dtr_rts(self->dev, FALSE, FALSE); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - ret = -1; - break; - } - return ret; -} - -MODULE_AUTHOR("Felix Tang <tangf@eyetap.org>"); -MODULE_DESCRIPTION("Microchip MCP2120"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-9"); /* IRDA_MCP2120_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize MCP2120 module - * - */ -module_init(mcp2120_init); - -/* - * Function cleanup_module (void) - * - * Cleanup MCP2120 module - * - */ -module_exit(mcp2120_cleanup); diff --git a/drivers/net/irda/old_belkin.c b/drivers/net/irda/old_belkin.c deleted file mode 100644 index 26f81fd28371..000000000000 --- a/drivers/net/irda/old_belkin.c +++ /dev/null @@ -1,164 +0,0 @@ -/********************************************************************* - * - * Filename: old_belkin.c - * Version: 1.1 - * Description: Driver for the Belkin (old) SmartBeam dongle - * Status: Experimental... - * Author: Jean Tourrilhes <jt@hpl.hp.com> - * Created at: 22/11/99 - * Modified at: Fri Dec 17 09:13:32 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1999 Jean Tourrilhes, 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 <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -/* - * Belkin is selling a dongle called the SmartBeam. - * In fact, there is two hardware version of this dongle, of course with - * the same name and looking the exactly same (grrr...). - * I guess that I've got the old one, because inside I don't have - * a jumper for IrDA/ASK... - * - * As far as I can make it from info on their web site, the old dongle - * support only 9600 b/s, which make our life much simpler as far as - * the driver is concerned, but you might not like it very much ;-) - * The new SmartBeam does 115 kb/s, and I've not tested it... - * - * Belkin claim that the correct driver for the old dongle (in Windows) - * is the generic Parallax 9500a driver, but the Linux LiteLink driver - * fails for me (probably because Linux-IrDA doesn't rate fallback), - * so I created this really dumb driver... - * - * In fact, this driver doesn't do much. The only thing it does is to - * prevent Linux-IrDA to use any other speed than 9600 b/s ;-) This - * driver is called "old_belkin" so that when the new SmartBeam is supported - * its driver can be called "belkin" instead of "new_belkin". - * - * Note : this driver was written without any info/help from Belkin, - * so a lot of info here might be totally wrong. Blame me ;-) - */ - -/* Let's guess */ -#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ - -static void old_belkin_open(dongle_t *self, struct qos_info *qos); -static void old_belkin_close(dongle_t *self); -static int old_belkin_change_speed(struct irda_task *task); -static int old_belkin_reset(struct irda_task *task); - -/* These are the baudrates supported */ -/* static __u32 baud_rates[] = { 9600 }; */ - -static struct dongle_reg dongle = { - .type = IRDA_OLD_BELKIN_DONGLE, - .open = old_belkin_open, - .close = old_belkin_close, - .reset = old_belkin_reset, - .change_speed = old_belkin_change_speed, - .owner = THIS_MODULE, -}; - -static int __init old_belkin_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit old_belkin_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void old_belkin_open(dongle_t *self, struct qos_info *qos) -{ - /* Not too fast, please... */ - qos->baud_rate.bits &= IR_9600; - /* Needs at least 10 ms (totally wild guess, can do probably better) */ - qos->min_turn_time.bits = 0x01; -} - -static void old_belkin_close(dongle_t *self) -{ - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); -} - -/* - * Function old_belkin_change_speed (task) - * - * With only one speed available, not much to do... - */ -static int old_belkin_change_speed(struct irda_task *task) -{ - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -/* - * Function old_belkin_reset (task) - * - * Reset the Old-Belkin type dongle. - * - */ -static int old_belkin_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - - /* Power on dongle */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Sleep a minimum of 15 us */ - udelay(MIN_DELAY); - - /* This dongles speed "defaults" to 9600 bps ;-) */ - self->speed = 9600; - - irda_task_next_state(task, IRDA_TASK_DONE); - - return 0; -} - -MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); -MODULE_DESCRIPTION("Belkin (old) SmartBeam dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-7"); /* IRDA_OLD_BELKIN_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize Old-Belkin module - * - */ -module_init(old_belkin_init); - -/* - * Function cleanup_module (void) - * - * Cleanup Old-Belkin module - * - */ -module_exit(old_belkin_cleanup); diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 7e7b5828214a..1f26da761e9f 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -1505,22 +1505,13 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id) +static irqreturn_t smsc_ircc_interrupt(int dummy, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; - struct smsc_ircc_cb *self; + struct net_device *dev = dev_id; + struct smsc_ircc_cb *self = netdev_priv(dev); int iobase, iir, lcra, lsr; irqreturn_t ret = IRQ_NONE; - if (dev == NULL) { - printk(KERN_WARNING "%s: irq %d for unknown device.\n", - driver_name, irq); - goto irq_ret; - } - - self = netdev_priv(dev); - IRDA_ASSERT(self != NULL, return IRQ_NONE;); - /* Serialise the interrupt handler in various CPUs, stop Tx path */ spin_lock(&self->lock); @@ -1565,7 +1556,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id) irq_ret_unlock: spin_unlock(&self->lock); - irq_ret: + return ret; } diff --git a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c deleted file mode 100644 index 9bfd2441adbf..000000000000 --- a/drivers/net/irda/tekram.c +++ /dev/null @@ -1,282 +0,0 @@ -/********************************************************************* - * - * Filename: tekram.c - * Version: 1.2 - * Description: Implementation of the Tekram IrMate IR-210B dongle - * Status: Experimental. - * Author: Dag Brattli <dagb@cs.uit.no> - * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Fri Dec 17 09:13:09 1999 - * Modified by: Dag Brattli <dagb@cs.uit.no> - * - * Copyright (c) 1998-1999 Dag Brattli, 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/tty.h> -#include <linux/init.h> - -#include <net/irda/irda.h> -#include <net/irda/irda_device.h> - -static void tekram_open(dongle_t *self, struct qos_info *qos); -static void tekram_close(dongle_t *self); -static int tekram_change_speed(struct irda_task *task); -static int tekram_reset(struct irda_task *task); - -#define TEKRAM_115200 0x00 -#define TEKRAM_57600 0x01 -#define TEKRAM_38400 0x02 -#define TEKRAM_19200 0x03 -#define TEKRAM_9600 0x04 - -#define TEKRAM_PW 0x10 /* Pulse select bit */ - -static struct dongle_reg dongle = { - .type = IRDA_TEKRAM_DONGLE, - .open = tekram_open, - .close = tekram_close, - .reset = tekram_reset, - .change_speed = tekram_change_speed, - .owner = THIS_MODULE, -}; - -static int __init tekram_init(void) -{ - return irda_device_register_dongle(&dongle); -} - -static void __exit tekram_cleanup(void) -{ - irda_device_unregister_dongle(&dongle); -} - -static void tekram_open(dongle_t *self, struct qos_info *qos) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ - irda_qos_bits_to_value(qos); -} - -static void tekram_close(dongle_t *self) -{ - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - /* Power off dongle */ - self->set_dtr_rts(self->dev, FALSE, FALSE); - - if (self->reset_task) - irda_task_delete(self->reset_task); - if (self->speed_task) - irda_task_delete(self->speed_task); -} - -/* - * Function tekram_change_speed (dev, state, speed) - * - * Set the speed for the Tekram IRMate 210 type dongle. Warning, this - * function must be called with a process context! - * - * Algorithm - * 1. clear DTR - * 2. set RTS, and wait at least 7 us - * 3. send Control Byte to the IR-210 through TXD to set new baud rate - * wait until the stop bit of Control Byte is sent (for 9600 baud rate, - * it takes about 100 msec) - * 5. clear RTS (return to NORMAL Operation) - * 6. wait at least 50 us, new setting (baud rate, etc) takes effect here - * after - */ -static int tekram_change_speed(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - __u32 speed = (__u32) task->param; - __u8 byte; - int ret = 0; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - IRDA_ASSERT(task != NULL, return -1;); - - if (self->speed_task && self->speed_task != task) { - IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ ); - return msecs_to_jiffies(10); - } else - self->speed_task = task; - - switch (speed) { - default: - case 9600: - byte = TEKRAM_PW|TEKRAM_9600; - break; - case 19200: - byte = TEKRAM_PW|TEKRAM_19200; - break; - case 38400: - byte = TEKRAM_PW|TEKRAM_38400; - break; - case 57600: - byte = TEKRAM_PW|TEKRAM_57600; - break; - case 115200: - byte = TEKRAM_115200; - break; - } - - switch (task->state) { - case IRDA_TASK_INIT: - case IRDA_TASK_CHILD_INIT: - /* - * Need to reset the dongle and go to 9600 bps before - * programming - */ - if (irda_task_execute(self, tekram_reset, NULL, task, - (void *) speed)) - { - /* Dongle need more time to reset */ - irda_task_next_state(task, IRDA_TASK_CHILD_WAIT); - - /* Give reset 1 sec to finish */ - ret = msecs_to_jiffies(1000); - } else - irda_task_next_state(task, IRDA_TASK_CHILD_DONE); - break; - case IRDA_TASK_CHILD_WAIT: - IRDA_WARNING("%s(), resetting dongle timed out!\n", - __FUNCTION__); - ret = -1; - break; - case IRDA_TASK_CHILD_DONE: - /* Set DTR, Clear RTS */ - self->set_dtr_rts(self->dev, TRUE, FALSE); - - /* Wait at least 7us */ - udelay(14); - - /* Write control byte */ - self->write(self->dev, &byte, 1); - - irda_task_next_state(task, IRDA_TASK_WAIT); - - /* Wait at least 100 ms */ - ret = msecs_to_jiffies(150); - break; - case IRDA_TASK_WAIT: - /* Set DTR, Set RTS */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->speed_task = NULL; - ret = -1; - break; - } - return ret; -} - -/* - * Function tekram_reset (driver) - * - * This function resets the tekram dongle. Warning, this function - * must be called with a process context!! - * - * Algorithm: - * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 ) - * 1. clear RTS - * 2. set DTR, and wait at least 1 ms - * 3. clear DTR to SPACE state, wait at least 50 us for further - * operation - */ -int tekram_reset(struct irda_task *task) -{ - dongle_t *self = (dongle_t *) task->instance; - int ret = 0; - - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); - - IRDA_ASSERT(task != NULL, return -1;); - - if (self->reset_task && self->reset_task != task) { - IRDA_DEBUG(0, "%s(), busy!\n", __FUNCTION__ ); - return msecs_to_jiffies(10); - } else - self->reset_task = task; - - /* Power off dongle */ - //self->set_dtr_rts(self->dev, FALSE, FALSE); - self->set_dtr_rts(self->dev, TRUE, TRUE); - - switch (task->state) { - case IRDA_TASK_INIT: - irda_task_next_state(task, IRDA_TASK_WAIT1); - - /* Sleep 50 ms */ - ret = msecs_to_jiffies(50); - break; - case IRDA_TASK_WAIT1: - /* Clear DTR, Set RTS */ - self->set_dtr_rts(self->dev, FALSE, TRUE); - - irda_task_next_state(task, IRDA_TASK_WAIT2); - - /* Should sleep 1 ms */ - ret = msecs_to_jiffies(1); - break; - case IRDA_TASK_WAIT2: - /* Set DTR, Set RTS */ - self->set_dtr_rts(self->dev, TRUE, TRUE); - - /* Wait at least 50 us */ - udelay(75); - - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - break; - default: - IRDA_ERROR("%s(), unknown state %d\n", - __FUNCTION__, task->state); - irda_task_next_state(task, IRDA_TASK_DONE); - self->reset_task = NULL; - ret = -1; - } - return ret; -} - -MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); -MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-0"); /* IRDA_TEKRAM_DONGLE */ - -/* - * Function init_module (void) - * - * Initialize Tekram module - * - */ -module_init(tekram_init); - -/* - * Function cleanup_module (void) - * - * Cleanup Tekram module - * - */ -module_exit(tekram_cleanup); diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 126ec7c8680e..58e128784585 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -1346,19 +1346,13 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) * An interrupt from the chip has arrived. Time to do some work * */ -static irqreturn_t via_ircc_interrupt(int irq, void *dev_id) +static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; - struct via_ircc_cb *self; + struct net_device *dev = dev_id; + struct via_ircc_cb *self = dev->priv; int iobase; u8 iHostIntType, iRxIntType, iTxIntType; - if (!dev) { - IRDA_WARNING("%s: irq %d for unknown device.\n", driver_name, - irq); - return IRQ_NONE; - } - self = (struct via_ircc_cb *) dev->priv; iobase = self->io.fir_base; spin_lock(&self->lock); iHostIntType = GetHostStatus(iobase); diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 97bd9dc2e52e..419861cbc65e 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -815,7 +815,7 @@ static int veth_init_connection(u8 rlp) { struct veth_lpar_connection *cnx; struct veth_msg *msgs; - int i, rc; + int i; if ( (rlp == this_lp) || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) @@ -844,11 +844,7 @@ static int veth_init_connection(u8 rlp) /* This gets us 1 reference, which is held on behalf of the driver * infrastructure. It's released at module unload. */ - kobject_init(&cnx->kobject); - cnx->kobject.ktype = &veth_lpar_connection_ktype; - rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp); - if (rc != 0) - return rc; + kobject_init(&cnx->kobject, &veth_lpar_connection_ktype); msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL); if (! msgs) { @@ -1087,11 +1083,8 @@ static struct net_device * __init veth_probe_one(int vlan, return NULL; } - kobject_init(&port->kobject); - port->kobject.parent = &dev->dev.kobj; - port->kobject.ktype = &veth_port_ktype; - kobject_set_name(&port->kobject, "veth_port"); - if (0 != kobject_add(&port->kobject)) + kobject_init(&port->kobject, &veth_port_ktype); + if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port")) veth_error("Failed adding port for %s to sysfs.\n", dev->name); veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n", @@ -1711,9 +1704,9 @@ static int __init veth_module_init(void) continue; kobj = &veth_cnx[i]->kobject; - kobj->parent = &veth_driver.driver.kobj; /* If the add failes, complain but otherwise continue */ - if (0 != kobject_add(kobj)) + if (0 != driver_add_kobj(&veth_driver.driver, kobj, + "cnx%.2d", veth_cnx[i]->remote_lp)) veth_error("cnx %d: Failed adding to sysfs.\n", i); } diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index 2c6367ace3cd..80a8b9888225 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -45,6 +45,8 @@ static boolean_t ixgb_link_reset(struct ixgb_hw *hw); static void ixgb_optics_reset(struct ixgb_hw *hw); +static void ixgb_optics_reset_bcm(struct ixgb_hw *hw); + static ixgb_phy_type ixgb_identify_phy(struct ixgb_hw *hw); static void ixgb_clear_hw_cntrs(struct ixgb_hw *hw); @@ -90,10 +92,20 @@ static uint32_t ixgb_mac_reset(struct ixgb_hw *hw) ASSERT(!(ctrl_reg & IXGB_CTRL0_RST)); #endif - if (hw->phy_type == ixgb_phy_type_txn17401) { - ixgb_optics_reset(hw); + if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID) { + ctrl_reg = /* Enable interrupt from XFP and SerDes */ + IXGB_CTRL1_GPI0_EN | + IXGB_CTRL1_SDP6_DIR | + IXGB_CTRL1_SDP7_DIR | + IXGB_CTRL1_SDP6 | + IXGB_CTRL1_SDP7; + IXGB_WRITE_REG(hw, CTRL1, ctrl_reg); + ixgb_optics_reset_bcm(hw); } + if (hw->phy_type == ixgb_phy_type_txn17401) + ixgb_optics_reset(hw); + return ctrl_reg; } @@ -253,6 +265,10 @@ ixgb_identify_phy(struct ixgb_hw *hw) break; } + /* update phy type for sun specific board */ + if (hw->subsystem_vendor_id == SUN_SUBVENDOR_ID) + phy_type = ixgb_phy_type_bcm; + return (phy_type); } @@ -1225,3 +1241,65 @@ ixgb_optics_reset(struct ixgb_hw *hw) return; } + +/****************************************************************************** + * Resets the 10GbE optics module for Sun variant NIC. + * + * hw - Struct containing variables accessed by shared code + *****************************************************************************/ + +#define IXGB_BCM8704_USER_PMD_TX_CTRL_REG 0xC803 +#define IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL 0x0164 +#define IXGB_BCM8704_USER_CTRL_REG 0xC800 +#define IXGB_BCM8704_USER_CTRL_REG_VAL 0x7FBF +#define IXGB_BCM8704_USER_DEV3_ADDR 0x0003 +#define IXGB_SUN_PHY_ADDRESS 0x0000 +#define IXGB_SUN_PHY_RESET_DELAY 305 + +static void +ixgb_optics_reset_bcm(struct ixgb_hw *hw) +{ + u32 ctrl = IXGB_READ_REG(hw, CTRL0); + ctrl &= ~IXGB_CTRL0_SDP2; + ctrl |= IXGB_CTRL0_SDP3; + IXGB_WRITE_REG(hw, CTRL0, ctrl); + + /* SerDes needs extra delay */ + msleep(IXGB_SUN_PHY_RESET_DELAY); + + /* Broadcom 7408L configuration */ + /* Reference clock config */ + ixgb_write_phy_reg(hw, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG_VAL); + /* we must read the registers twice */ + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_PMD_TX_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + + ixgb_write_phy_reg(hw, + IXGB_BCM8704_USER_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR, + IXGB_BCM8704_USER_CTRL_REG_VAL); + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + ixgb_read_phy_reg(hw, + IXGB_BCM8704_USER_CTRL_REG, + IXGB_SUN_PHY_ADDRESS, + IXGB_BCM8704_USER_DEV3_ADDR); + + /* SerDes needs extra delay */ + msleep(IXGB_SUN_PHY_RESET_DELAY); + + return; +} diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index af5643324ee3..4f176ff2b786 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -44,7 +44,8 @@ typedef enum { ixgb_phy_type_g6005, /* 850nm, MM fiber, XPAK transceiver */ ixgb_phy_type_g6104, /* 1310nm, SM fiber, XPAK transceiver */ ixgb_phy_type_txn17201, /* 850nm, MM fiber, XPAK transceiver */ - ixgb_phy_type_txn17401 /* 1310nm, SM fiber, XENPAK transceiver */ + ixgb_phy_type_txn17401, /* 1310nm, SM fiber, XENPAK transceiver */ + ixgb_phy_type_bcm /* SUN specific board */ } ixgb_phy_type; /* XPAK transceiver vendors, for the SR adapters */ @@ -534,12 +535,12 @@ typedef enum { * in which case the structure must be packed in some compiler-specific * manner. */ struct ixgb_rx_desc { - uint64_t buff_addr; - uint16_t length; - uint16_t reserved; + __le64 buff_addr; + __le16 length; + __le16 reserved; uint8_t status; uint8_t errors; - uint16_t special; + __le16 special; }; #define IXGB_RX_DESC_STATUS_DD 0x01 @@ -567,11 +568,11 @@ struct ixgb_rx_desc { * in which case the structure must be packed in some compiler-specific * manner. */ struct ixgb_tx_desc { - uint64_t buff_addr; - uint32_t cmd_type_len; + __le64 buff_addr; + __le32 cmd_type_len; uint8_t status; uint8_t popts; - uint16_t vlan; + __le16 vlan; }; #define IXGB_TX_DESC_LENGTH_MASK 0x000FFFFF @@ -596,14 +597,14 @@ struct ixgb_tx_desc { struct ixgb_context_desc { uint8_t ipcss; uint8_t ipcso; - uint16_t ipcse; + __le16 ipcse; uint8_t tucss; uint8_t tucso; - uint16_t tucse; - uint32_t cmd_type_len; + __le16 tucse; + __le32 cmd_type_len; uint8_t status; uint8_t hdr_len; - uint16_t mss; + __le16 mss; }; #define IXGB_CONTEXT_DESC_CMD_TCP 0x01000000 diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h index 4376e7e8fbef..180d20e793a5 100644 --- a/drivers/net/ixgb/ixgb_ids.h +++ b/drivers/net/ixgb/ixgb_ids.h @@ -35,7 +35,8 @@ #define INTEL_VENDOR_ID 0x8086 #define INTEL_SUBVENDOR_ID 0x8086 - +#define SUN_VENDOR_ID 0x108E +#define SUN_SUBVENDOR_ID 0x108E #define IXGB_DEVICE_ID_82597EX 0x1048 #define IXGB_DEVICE_ID_82597EX_SR 0x1A48 @@ -46,6 +47,7 @@ #define IXGB_DEVICE_ID_82597EX_CX4 0x109E #define IXGB_SUBDEVICE_ID_A00C 0xA00C #define IXGB_SUBDEVICE_ID_A01C 0xA01C +#define IXGB_SUBDEVICE_ID_7036 0x7036 #endif /* #ifndef _IXGB_IDS_H_ */ /* End of File */ diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 4f63839051b0..269e6f805f47 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "1.0.126-k2"DRIVERNAPI +#define DRV_VERSION "1.0.126-k4"DRIVERNAPI const char ixgb_driver_version[] = DRV_VERSION; static const char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation."; @@ -212,9 +212,11 @@ static void ixgb_irq_enable(struct ixgb_adapter *adapter) { if(atomic_dec_and_test(&adapter->irq_sem)) { - IXGB_WRITE_REG(&adapter->hw, IMS, - IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | IXGB_INT_TXDW | - IXGB_INT_LSC); + u32 val = IXGB_INT_RXT0 | IXGB_INT_RXDMT0 | + IXGB_INT_TXDW | IXGB_INT_LSC; + if (adapter->hw.subsystem_vendor_id == SUN_SUBVENDOR_ID) + val |= IXGB_INT_GPI0; + IXGB_WRITE_REG(&adapter->hw, IMS, val); IXGB_WRITE_FLUSH(&adapter->hw); } } diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index bc51432b8d26..a021a6e72641 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -234,14 +234,10 @@ enum ixbge_state_t { }; enum ixgbe_boards { - board_82598AF, - board_82598EB, - board_82598AT, + board_82598, }; -extern struct ixgbe_info ixgbe_82598AF_info; -extern struct ixgbe_info ixgbe_82598EB_info; -extern struct ixgbe_info ixgbe_82598AT_info; +extern struct ixgbe_info ixgbe_82598_info; extern char ixgbe_driver_name[]; extern const char ixgbe_driver_version[]; diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 4d64673164ca..6321b059ce13 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -50,8 +50,6 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed, bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw); -static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed, - bool *link_up); static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, bool autoneg, bool autoneg_wait_to_complete); @@ -64,6 +62,28 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES; hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES; + /* PHY ops are filled in by default properly for Fiber only */ + if (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper) { + hw->mac.ops.setup_link = &ixgbe_setup_copper_link_82598; + hw->mac.ops.setup_link_speed = &ixgbe_setup_copper_link_speed_82598; + hw->mac.ops.get_link_settings = + &ixgbe_get_copper_link_settings_82598; + + /* Call PHY identify routine to get the phy type */ + ixgbe_identify_phy(hw); + + switch (hw->phy.type) { + case ixgbe_phy_tn: + hw->phy.ops.setup_link = &ixgbe_setup_tnx_phy_link; + hw->phy.ops.check_link = &ixgbe_check_tnx_phy_link; + hw->phy.ops.setup_link_speed = + &ixgbe_setup_tnx_phy_link_speed; + break; + default: + break; + } + } + return 0; } @@ -206,6 +226,7 @@ static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw) autoc_reg |= hw->mac.link_mode_select; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + IXGBE_WRITE_FLUSH(hw); msleep(50); } @@ -314,7 +335,7 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, * ixgbe_hw This will write the AUTOC register based on the new * stored values */ - hw->phy.ops.setup(hw); + hw->mac.ops.setup_link(hw); } return status; @@ -332,72 +353,18 @@ static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, **/ static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw) { - s32 status; - u32 speed = 0; - bool link_up = false; - - /* Set up MAC */ - hw->phy.ops.setup(hw); + s32 status = 0; /* Restart autonegotiation on PHY */ - status = hw->phy.ops.setup(hw); - - /* Synchronize MAC to PHY speed */ - if (status == 0) - status = hw->phy.ops.check(hw, &speed, &link_up); - - return status; -} + if (hw->phy.ops.setup_link) + status = hw->phy.ops.setup_link(hw); -/** - * ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings - * @hw: pointer to hardware structure - * @speed: pointer to link speed - * @link_up: true if link is up, false otherwise - * - * Reads the mac link, phy link, and synchronizes the MAC to PHY. - **/ -static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed, - bool *link_up) -{ - s32 status; - u32 phy_speed = 0; - bool phy_link = false; + /* Set MAC to KX/KX4 autoneg, which defaultis to Parallel detection */ + hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; - /* This is the speed and link the MAC is set at */ - hw->phy.ops.check(hw, speed, link_up); - - /* - * Check current speed and link status of the PHY register. - * This is a vendor specific register and may have to - * be changed for other copper PHYs. - */ - status = hw->phy.ops.check(hw, &phy_speed, &phy_link); - - if ((status == 0) && (phy_link)) { - /* - * Check current link status of the MACs link's register - * matches that of the speed in the PHY register - */ - if (*speed != phy_speed) { - /* - * The copper PHY requires 82598 attach type to be XAUI - * for 10G and BX for 1G - */ - hw->mac.link_attach_type = - (IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX); - - /* Synchronize the MAC speed to the PHY speed */ - status = hw->phy.ops.setup_speed(hw, phy_speed, false, - false); - if (status == 0) - hw->phy.ops.check(hw, speed, link_up); - else - status = IXGBE_ERR_LINK_SETUP; - } - } else { - *link_up = phy_link; - } + /* Set up MAC */ + hw->mac.ops.setup_link(hw); return status; } @@ -415,16 +382,19 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed, bool autoneg, bool autoneg_wait_to_complete) { - s32 status; - bool link_up = 0; + s32 status = 0; /* Setup the PHY according to input speed */ - status = hw->phy.ops.setup_speed(hw, speed, autoneg, - autoneg_wait_to_complete); + if (hw->phy.ops.setup_link_speed) + status = hw->phy.ops.setup_link_speed(hw, speed, autoneg, + autoneg_wait_to_complete); + + /* Set MAC to KX/KX4 autoneg, which defaults to Parallel detection */ + hw->mac.link_attach_type = (IXGBE_AUTOC_10G_KX4 | IXGBE_AUTOC_1G_KX); + hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN; - /* Synchronize MAC to PHY speed */ - if (status == 0) - status = hw->phy.ops.check(hw, &speed, &link_up); + /* Set up MAC */ + hw->mac.ops.setup_link(hw); return status; } @@ -542,47 +512,15 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) static struct ixgbe_mac_operations mac_ops_82598 = { .reset = &ixgbe_reset_hw_82598, .get_media_type = &ixgbe_get_media_type_82598, + .setup_link = &ixgbe_setup_mac_link_82598, + .check_link = &ixgbe_check_mac_link_82598, + .setup_link_speed = &ixgbe_setup_mac_link_speed_82598, + .get_link_settings = &ixgbe_get_link_settings_82598, }; -static struct ixgbe_phy_operations phy_ops_82598EB = { - .setup = &ixgbe_setup_copper_link_82598, - .check = &ixgbe_check_copper_link_82598, - .setup_speed = &ixgbe_setup_copper_link_speed_82598, - .get_settings = &ixgbe_get_copper_link_settings_82598, -}; - -struct ixgbe_info ixgbe_82598EB_info = { - .mac = ixgbe_mac_82598EB, - .get_invariants = &ixgbe_get_invariants_82598, - .mac_ops = &mac_ops_82598, - .phy_ops = &phy_ops_82598EB, -}; - -static struct ixgbe_phy_operations phy_ops_82598AT = { - .setup = &ixgbe_setup_tnx_phy_link, - .check = &ixgbe_check_tnx_phy_link, - .setup_speed = &ixgbe_setup_tnx_phy_link_speed, - .get_settings = &ixgbe_get_copper_link_settings_82598, -}; - -struct ixgbe_info ixgbe_82598AT_info = { - .mac = ixgbe_mac_82598EB, - .get_invariants = &ixgbe_get_invariants_82598, - .mac_ops = &mac_ops_82598, - .phy_ops = &phy_ops_82598AT, -}; - -static struct ixgbe_phy_operations phy_ops_82598AF = { - .setup = &ixgbe_setup_mac_link_82598, - .check = &ixgbe_check_mac_link_82598, - .setup_speed = &ixgbe_setup_mac_link_speed_82598, - .get_settings = &ixgbe_get_link_settings_82598, -}; - -struct ixgbe_info ixgbe_82598AF_info = { +struct ixgbe_info ixgbe_82598_info = { .mac = ixgbe_mac_82598EB, .get_invariants = &ixgbe_get_invariants_82598, .mac_ops = &mac_ops_82598, - .phy_ops = &phy_ops_82598AF, }; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 512e3b22ed08..7fd6aeb1b021 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -74,7 +74,7 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw) ixgbe_clear_vfta(hw); /* Set up link */ - hw->phy.ops.setup(hw); + hw->mac.ops.setup_link(hw); /* Clear statistics registers */ ixgbe_clear_hw_cntrs(hw); @@ -83,6 +83,7 @@ s32 ixgbe_start_hw(struct ixgbe_hw *hw) ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS; IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + IXGBE_WRITE_FLUSH(hw); /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -297,6 +298,7 @@ s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index) led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index); IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); return 0; } @@ -314,6 +316,7 @@ s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index) led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index); IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); + IXGBE_WRITE_FLUSH(hw); return 0; } @@ -496,6 +499,7 @@ static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw) /* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */ swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI); IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm); + IXGBE_WRITE_FLUSH(hw); } /** @@ -950,7 +954,7 @@ s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num) u32 rmcs_reg; if (packetbuf_num < 0 || packetbuf_num > 7) - hw_dbg(hw, "Invalid packet buffer number [%d], expected range" + hw_dbg(hw, "Invalid packet buffer number [%d], expected range " "is 0-7\n", packetbuf_num); frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); @@ -1132,7 +1136,7 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) } /** - * ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register + * ixgbe_read_analog_reg8 - Reads 8 bit Atlas analog register * @hw: pointer to hardware structure * @reg: analog register to read * @val: read value @@ -1154,7 +1158,7 @@ s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val) } /** - * ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register + * ixgbe_write_analog_reg8 - Writes 8 bit Atlas analog register * @hw: pointer to hardware structure * @reg: atlas register to write * @val: value to write diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index a4e576a0c543..36353447716d 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -96,8 +96,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) -#define IXGBE_GLOBAL_STATS_LEN \ - sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats) +#define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) #define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) static int ixgbe_get_settings(struct net_device *netdev, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index a4265bc1cebb..3732dd6c4b2a 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -54,9 +54,7 @@ static const char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation."; static const struct ixgbe_info *ixgbe_info_tbl[] = { - [board_82598AF] = &ixgbe_82598AF_info, - [board_82598EB] = &ixgbe_82598EB_info, - [board_82598AT] = &ixgbe_82598AT_info, + [board_82598] = &ixgbe_82598_info, }; /* ixgbe_pci_tbl - PCI Device ID Table @@ -69,13 +67,13 @@ static const struct ixgbe_info *ixgbe_info_tbl[] = { */ static struct pci_device_id ixgbe_pci_tbl[] = { {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT), - board_82598AF }, + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), - board_82598AF }, + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT), - board_82598AT }, + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), - board_82598EB }, + board_82598 }, /* required last entry */ {0, } @@ -734,7 +732,7 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues) { struct net_device *netdev = adapter->netdev; int flags, err; - irqreturn_t(*handler) (int, void *) = &ixgbe_intr; + irq_handler_t handler = ixgbe_intr; flags = IRQF_SHARED; @@ -1570,8 +1568,8 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) dev_err(&pdev->dev, "HW Init failed\n"); return -EIO; } - if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true, - false)) { + if (hw->mac.ops.setup_link_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true, + false)) { dev_err(&pdev->dev, "Link Speed setup failed\n"); return -EIO; } @@ -2038,7 +2036,7 @@ static void ixgbe_watchdog(unsigned long data) bool link_up; u32 link_speed = 0; - adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up); + adapter->hw.mac.ops.check_link(&adapter->hw, &(link_speed), &link_up); if (link_up) { if (!netif_carrier_ok(netdev)) { @@ -2108,7 +2106,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, l4len = tcp_hdrlen(skb); *hdr_len += l4len; - if (skb->protocol == ntohs(ETH_P_IP)) { + if (skb->protocol == htons(ETH_P_IP)) { struct iphdr *iph = ip_hdr(skb); iph->tot_len = 0; iph->check = 0; @@ -2149,7 +2147,7 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT | IXGBE_ADVTXD_DTYP_CTXT); - if (skb->protocol == ntohs(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); @@ -2204,7 +2202,7 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, IXGBE_ADVTXD_DTYP_CTXT); if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb->protocol == ntohs(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; if (skb->sk->sk_protocol == IPPROTO_TCP) @@ -2404,7 +2402,7 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT); } - if (skb->protocol == ntohs(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) tx_flags |= IXGBE_TX_FLAGS_IPV4; first = tx_ring->next_to_use; tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len); @@ -2606,7 +2604,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* Setup hw api */ memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops)); - memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); err = ii->get_invariants(hw); if (err) diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index 199e8f670f3a..aa3ea72e678e 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -31,7 +31,6 @@ #include "ixgbe_type.h" -s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw); s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw); s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up); s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg, diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index fdcde16a2a99..1ad7cb9c25a8 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -1003,19 +1003,19 @@ struct ixgbe_legacy_tx_desc { u64 buffer_addr; /* Address of the descriptor's data buffer */ union { - u32 data; + __le32 data; struct { - u16 length; /* Data buffer length */ + __le16 length; /* Data buffer length */ u8 cso; /* Checksum offset */ u8 cmd; /* Descriptor control */ } flags; } lower; union { - u32 data; + __le32 data; struct { u8 status; /* Descriptor status */ u8 css; /* Checksum start */ - u16 vlan; + __le16 vlan; } fields; } upper; }; @@ -1023,61 +1023,61 @@ struct ixgbe_legacy_tx_desc { /* Transmit Descriptor - Advanced */ union ixgbe_adv_tx_desc { struct { - u64 buffer_addr; /* Address of descriptor's data buf */ - u32 cmd_type_len; - u32 olinfo_status; + __le64 buffer_addr; /* Address of descriptor's data buf */ + __le32 cmd_type_len; + __le32 olinfo_status; } read; struct { - u64 rsvd; /* Reserved */ - u32 nxtseq_seed; - u32 status; + __le64 rsvd; /* Reserved */ + __le32 nxtseq_seed; + __le32 status; } wb; }; /* Receive Descriptor - Legacy */ struct ixgbe_legacy_rx_desc { - u64 buffer_addr; /* Address of the descriptor's data buffer */ - u16 length; /* Length of data DMAed into data buffer */ + __le64 buffer_addr; /* Address of the descriptor's data buffer */ + __le16 length; /* Length of data DMAed into data buffer */ u16 csum; /* Packet checksum */ u8 status; /* Descriptor status */ u8 errors; /* Descriptor Errors */ - u16 vlan; + __le16 vlan; }; /* Receive Descriptor - Advanced */ union ixgbe_adv_rx_desc { struct { - u64 pkt_addr; /* Packet buffer address */ - u64 hdr_addr; /* Header buffer address */ + __le64 pkt_addr; /* Packet buffer address */ + __le64 hdr_addr; /* Header buffer address */ } read; struct { struct { struct { - u16 pkt_info; /* RSS type, Packet type */ - u16 hdr_info; /* Split Header, header len */ + __le16 pkt_info; /* RSS type, Packet type */ + __le16 hdr_info; /* Split Header, header len */ } lo_dword; union { - u32 rss; /* RSS Hash */ + __le32 rss; /* RSS Hash */ struct { - u16 ip_id; /* IP id */ + __le16 ip_id; /* IP id */ u16 csum; /* Packet Checksum */ } csum_ip; } hi_dword; } lower; struct { - u32 status_error; /* ext status/error */ - u16 length; /* Packet length */ - u16 vlan; /* VLAN tag */ + __le32 status_error; /* ext status/error */ + __le16 length; /* Packet length */ + __le16 vlan; /* VLAN tag */ } upper; } wb; /* writeback */ }; /* Context descriptors */ struct ixgbe_adv_tx_context_desc { - u32 vlan_macip_lens; - u32 seqnum_seed; - u32 type_tucmd_mlhl; - u32 mss_l4len_idx; + __le32 vlan_macip_lens; + __le32 seqnum_seed; + __le32 type_tucmd_mlhl; + __le32 mss_l4len_idx; }; /* Adv Transmit Descriptor Config Masks */ @@ -1244,13 +1244,16 @@ struct ixgbe_hw; struct ixgbe_mac_operations { s32 (*reset)(struct ixgbe_hw *); enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *); + s32 (*setup_link)(struct ixgbe_hw *); + s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *); + s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool); + s32 (*get_link_settings)(struct ixgbe_hw *, u32 *, bool *); }; struct ixgbe_phy_operations { - s32 (*setup)(struct ixgbe_hw *); - s32 (*check)(struct ixgbe_hw *, u32 *, bool *); - s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool); - s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *); + s32 (*setup_link)(struct ixgbe_hw *); + s32 (*check_link)(struct ixgbe_hw *, u32 *, bool *); + s32 (*setup_link_speed)(struct ixgbe_hw *, u32, bool, bool); }; struct ixgbe_mac_info { @@ -1267,7 +1270,6 @@ struct ixgbe_mac_info { bool link_settings_loaded; }; - struct ixgbe_eeprom_info { enum ixgbe_eeprom_type type; u16 word_size; @@ -1290,7 +1292,6 @@ struct ixgbe_info { enum ixgbe_mac_type mac; s32 (*get_invariants)(struct ixgbe_hw *); struct ixgbe_mac_operations *mac_ops; - struct ixgbe_phy_operations *phy_ops; }; struct ixgbe_hw { diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index fa147cd5d68c..f2a6e7132241 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -64,8 +64,6 @@ struct pcpu_lstats { unsigned long bytes; }; -#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) - /* KISS: just allocate small chunks and copy bits. * * So, in fact, this is documentation, explaining what we expect diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index c5095ecd8b11..591a7e4220c7 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -1144,14 +1144,13 @@ i596_handle_CU_completion(struct net_device *dev, } static irqreturn_t -i596_interrupt (int irq, void *dev_instance) { - struct net_device *dev = (struct net_device *) dev_instance; - struct i596_private *lp; +i596_interrupt(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct i596_private *lp = dev->priv; unsigned short status, ack_cmd = 0; int frames_in = 0; - lp = (struct i596_private *) dev->priv; - /* * The 82596 examines the command, performs the required action, * and then clears the SCB command word. diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index a19b5958cee9..2a66e5b7cebc 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -289,7 +289,7 @@ struct net_device * __init mac89x0_probe(int unit) err = register_netdev(dev); if (err) goto out1; - return 0; + return NULL; out1: nubus_writew(0, dev->base_addr + ADD_PORT); out: diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 95ebe72f320f..451acdca2a21 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -409,7 +409,7 @@ static inline void mace_clean_rings(struct mace_data *mp) /* free some skb's */ for (i = 0; i < N_RX_RING; ++i) { - if (mp->rx_bufs[i] != 0) { + if (mp->rx_bufs[i] != NULL) { dev_kfree_skb(mp->rx_bufs[i]); mp->rx_bufs[i] = NULL; } @@ -441,7 +441,7 @@ static int mace_open(struct net_device *dev) cp = mp->rx_cmds; for (i = 0; i < N_RX_RING - 1; ++i) { skb = dev_alloc_skb(RX_BUFLEN + 2); - if (skb == 0) { + if (!skb) { data = dummy_buf; } else { skb_reserve(skb, 2); /* so IP header lands on 4-byte bdry */ @@ -903,7 +903,7 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) out_le16(&cp->command, DBDMA_STOP); /* got a packet, have a look at it */ skb = mp->rx_bufs[i]; - if (skb == 0) { + if (!skb) { ++dev->stats.rx_dropped; } else if (nb > 8) { data = skb->data; @@ -953,9 +953,9 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) break; cp = mp->rx_cmds + i; skb = mp->rx_bufs[i]; - if (skb == 0) { + if (!skb) { skb = dev_alloc_skb(RX_BUFLEN + 2); - if (skb != 0) { + if (skb) { skb_reserve(skb, 2); mp->rx_bufs[i] = skb; } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index e8dc2f44fec9..6ef6b8b39e71 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -73,8 +73,6 @@ static void macvlan_broadcast(struct sk_buff *skb, for (i = 0; i < MACVLAN_HASH_SIZE; i++) { hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { dev = vlan->dev; - if (unlikely(!(dev->flags & IFF_UP))) - continue; nskb = skb_clone(skb, GFP_ATOMIC); if (nskb == NULL) { @@ -215,6 +213,29 @@ static int macvlan_stop(struct net_device *dev) return 0; } +static int macvlan_set_mac_address(struct net_device *dev, void *p) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + struct sockaddr *addr = p; + int err; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + if (!(dev->flags & IFF_UP)) + goto out; + + err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN); + if (err < 0) + return err; + dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN); + +out: + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); + return 0; +} + static void macvlan_change_rx_flags(struct net_device *dev, int change) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -302,6 +323,7 @@ static void macvlan_setup(struct net_device *dev) dev->stop = macvlan_stop; dev->change_mtu = macvlan_change_mtu; dev->change_rx_flags = macvlan_change_rx_flags; + dev->set_mac_address = macvlan_set_mac_address; dev->set_multicast_list = macvlan_set_multicast_list; dev->hard_start_xmit = macvlan_hard_start_xmit; dev->destructor = free_netdev; @@ -353,7 +375,7 @@ static void macvlan_transfer_operstate(struct net_device *dev) if (!netif_carrier_ok(dev)) netif_carrier_on(dev); } else { - if (netif_carrier_ok(lowerdev)) + if (netif_carrier_ok(dev)) netif_carrier_off(dev); } } diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c index 50648738d679..535a4461d88c 100644 --- a/drivers/net/mlx4/fw.c +++ b/drivers/net/mlx4/fw.c @@ -202,7 +202,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_EQ_OFFSET); dev_cap->reserved_eqs = 1 << (field & 0xf); MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_EQ_OFFSET); - dev_cap->max_eqs = 1 << (field & 0x7); + dev_cap->max_eqs = 1 << (field & 0xf); MLX4_GET(field, outbox, QUERY_DEV_CAP_RSVD_MTT_OFFSET); dev_cap->reserved_mtts = 1 << (field >> 4); MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MRW_SZ_OFFSET); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index c90958f6d3fe..cead81e80f0c 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -185,7 +185,7 @@ struct myri10ge_priv { dma_addr_t fw_stats_bus; struct pci_dev *pdev; int msi_enabled; - __be32 link_state; + u32 link_state; unsigned int rdma_tags_available; int intr_coal_delay; __be32 __iomem *intr_coal_delay_ptr; @@ -576,7 +576,7 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp) int status; /* find running firmware header */ - hdr_offset = ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET)); + hdr_offset = swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET)); if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) { dev_err(dev, "Running firmware has bad header offset (%d)\n", @@ -1053,7 +1053,10 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, rx_frags[0].size -= MXGEFW_PAD; len -= MXGEFW_PAD; lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags, - len, len, (void *)(unsigned long)csum, csum); + len, len, + /* opaque, will come back in get_frag_header */ + (void *)(__force unsigned long)csum, + csum); return 1; } @@ -1431,7 +1434,7 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { }; #define MYRI10GE_NET_STATS_LEN 21 -#define MYRI10GE_STATS_LEN sizeof(myri10ge_gstrings_stats) / ETH_GSTRING_LEN +#define MYRI10GE_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_stats) static void myri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) @@ -1786,7 +1789,8 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, struct iphdr *iph; u8 *va = page_address(frag->page) + frag->page_offset; unsigned long ll_hlen; - __wsum csum = (__wsum) (unsigned long)priv; + /* passed opaque through lro_receive_frags() */ + __wsum csum = (__force __wsum) (unsigned long)priv; /* find the mac header, aborting if not IPv4 */ @@ -1967,7 +1971,7 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_rings; } - mgp->link_state = htonl(~0U); + mgp->link_state = ~0U; mgp->rdma_tags_available = 15; lro_mgr = &mgp->rx_done.lro_mgr; diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 5ffbb8891647..31e047dd7bb3 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -306,9 +306,11 @@ static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) { + struct net_device *dev = nt->np.dev; + DECLARE_MAC_BUF(mac); return snprintf(buf, PAGE_SIZE, "%s\n", - print_mac(mac, nt->np.local_mac)); + print_mac(mac, dev->dev_addr)); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) @@ -667,7 +669,7 @@ static int netconsole_netdev_event(struct notifier_block *this, struct netconsole_target *nt; struct net_device *dev = ptr; - if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME)) + if (!(event == NETDEV_CHANGENAME)) goto done; spin_lock_irqsave(&target_list_lock, flags); @@ -675,10 +677,6 @@ static int netconsole_netdev_event(struct notifier_block *this, netconsole_target_get(nt); if (nt->np.dev == dev) { switch (event) { - case NETDEV_CHANGEADDR: - memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); - break; - case NETDEV_CHANGENAME: strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); break; diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index a8f63c47b3cd..2bc5eaae141f 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -113,8 +113,8 @@ #define FLUSH_SCHEDULED_WORK() flush_workqueue(netxen_workq) extern struct workqueue_struct *netxen_workq; -/* - * normalize a 64MB crb address to 32MB PCI window +/* + * normalize a 64MB crb address to 32MB PCI window * To use NETXEN_CRB_NORMALIZE, window _must_ be set to 1 */ #define NETXEN_CRB_NORMAL(reg) \ @@ -736,11 +736,11 @@ struct netxen_skb_frag { (config_word) &= ~__tmask; \ (config_word) |= (((__tvalue) << (start)) & __tmask); \ } - + #define _netxen_clear_bits(config_word, start, bits) {\ unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \ (config_word) &= ~__tmask; \ -} +} /* Following defines are for the state of the buffers */ #define NETXEN_BUFFER_FREE 0 @@ -879,7 +879,7 @@ struct netxen_dummy_dma { struct netxen_adapter { struct netxen_hardware_context ahw; - + struct netxen_adapter *master; struct net_device *netdev; struct pci_dev *pdev; @@ -898,7 +898,7 @@ struct netxen_adapter { u32 curr_window; u32 cmd_producer; - u32 *cmd_consumer; + __le32 *cmd_consumer; u32 last_cmd_consumer; u32 max_tx_desc_count; @@ -916,7 +916,7 @@ struct netxen_adapter { u32 temp; struct netxen_adapter_stats stats; - + u16 portno; u16 link_speed; u16 link_duplex; @@ -1018,14 +1018,8 @@ int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter); -int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter); void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter); void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter); -void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, - long enable); -void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, - long enable); int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, __u32 * readval); int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, @@ -1048,7 +1042,6 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, int len); void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, int data); -int netxen_nic_erase_pxe(struct netxen_adapter *adapter); /* Functions from netxen_nic_init.c */ void netxen_free_adapter_offload(struct netxen_adapter *adapter); @@ -1057,9 +1050,9 @@ int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val); int netxen_load_firmware(struct netxen_adapter *adapter); int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose); int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); -int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, +int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, u8 *bytes, size_t size); -int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, +int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, u8 *bytes, size_t size); int netxen_flash_unlock(struct netxen_adapter *adapter); int netxen_backup_crbinit(struct netxen_adapter *adapter); @@ -1067,15 +1060,10 @@ int netxen_flash_erase_secondary(struct netxen_adapter *adapter); int netxen_flash_erase_primary(struct netxen_adapter *adapter); void netxen_halt_pegs(struct netxen_adapter *adapter); -int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data); int netxen_rom_se(struct netxen_adapter *adapter, int addr); -int netxen_do_rom_se(struct netxen_adapter *adapter, int addr); /* Functions from netxen_nic_isr.c */ int netxen_nic_link_ok(struct netxen_adapter *adapter); -void netxen_nic_isr_other(struct netxen_adapter *adapter); -void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link); -void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable); void netxen_initialize_adapter_sw(struct netxen_adapter *adapter); void netxen_initialize_adapter_hw(struct netxen_adapter *adapter); void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr, @@ -1092,8 +1080,6 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter); void netxen_watchdog_task(struct work_struct *work); void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid); -void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, u32 ctx, - u32 ringid); int netxen_process_cmd_ring(unsigned long data); u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max); void netxen_nic_set_multi(struct net_device *netdev); @@ -1209,7 +1195,7 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter) int netxen_is_flash_supported(struct netxen_adapter *adapter); -int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]); +int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 mac[]); extern void netxen_change_ringparam(struct netxen_adapter *adapter); extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp); diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index cfb847b0cae3..7a876f4b8db2 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -86,7 +86,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = { "Link_Test_on_offline" }; -#define NETXEN_NIC_TEST_LEN sizeof(netxen_nic_gstrings_test) / ETH_GSTRING_LEN +#define NETXEN_NIC_TEST_LEN ARRAY_SIZE(netxen_nic_gstrings_test) #define NETXEN_NIC_REGS_COUNT 42 #define NETXEN_NIC_REGS_LEN (NETXEN_NIC_REGS_COUNT * sizeof(__le32)) @@ -423,11 +423,11 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (eeprom->len == 0) return -EINVAL; - eeprom->magic = (adapter->pdev)->vendor | + eeprom->magic = (adapter->pdev)->vendor | ((adapter->pdev)->device << 16); offset = eeprom->offset; - ret = netxen_rom_fast_read_words(adapter, offset, bytes, + ret = netxen_rom_fast_read_words(adapter, offset, bytes, eeprom->len); if (ret < 0) return ret; @@ -453,16 +453,16 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, netxen_nic_driver_name); return ret; } - printk(KERN_INFO "%s: flash unlocked. \n", + printk(KERN_INFO "%s: flash unlocked. \n", netxen_nic_driver_name); last_schedule_time = jiffies; ret = netxen_flash_erase_secondary(adapter); if (ret != FLASH_SUCCESS) { - printk(KERN_ERR "%s: Flash erase failed.\n", + printk(KERN_ERR "%s: Flash erase failed.\n", netxen_nic_driver_name); return ret; } - printk(KERN_INFO "%s: secondary flash erased successfully.\n", + printk(KERN_INFO "%s: secondary flash erased successfully.\n", netxen_nic_driver_name); flash_start = 1; return 0; @@ -471,7 +471,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (offset == NETXEN_BOOTLD_START) { ret = netxen_flash_erase_primary(adapter); if (ret != FLASH_SUCCESS) { - printk(KERN_ERR "%s: Flash erase failed.\n", + printk(KERN_ERR "%s: Flash erase failed.\n", netxen_nic_driver_name); return ret; } @@ -483,16 +483,16 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, if (ret != FLASH_SUCCESS) return ret; - printk(KERN_INFO "%s: primary flash erased successfully\n", + printk(KERN_INFO "%s: primary flash erased successfully\n", netxen_nic_driver_name); ret = netxen_backup_crbinit(adapter); if (ret != FLASH_SUCCESS) { - printk(KERN_ERR "%s: CRBinit backup failed.\n", + printk(KERN_ERR "%s: CRBinit backup failed.\n", netxen_nic_driver_name); return ret; } - printk(KERN_INFO "%s: CRBinit backup done.\n", + printk(KERN_INFO "%s: CRBinit backup done.\n", netxen_nic_driver_name); ready_to_flash = 1; } @@ -570,7 +570,7 @@ netxen_nic_get_pauseparam(struct net_device *dev, else pause->tx_pause = !(netxen_xg_get_xg1_mask(val)); } else { - printk(KERN_ERR"%s: Unknown board type: %x\n", + printk(KERN_ERR"%s: Unknown board type: %x\n", netxen_nic_driver_name, adapter->ahw.board_type); } } @@ -589,7 +589,7 @@ netxen_nic_set_pauseparam(struct net_device *dev, /* set flow control */ netxen_nic_read_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), &val); - + if (pause->rx_pause) netxen_gb_rx_flowctl(val); else @@ -642,10 +642,10 @@ netxen_nic_set_pauseparam(struct net_device *dev, else netxen_xg_set_xg1_mask(val); } - netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); + netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); } else { printk(KERN_ERR "%s: Unknown board type: %x\n", - netxen_nic_driver_name, + netxen_nic_driver_name, adapter->ahw.board_type); } return 0; diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 2c19b8df98fa..01355701bf8e 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -33,7 +33,6 @@ #include "netxen_nic.h" #include "netxen_nic_hw.h" -#define DEFINE_GLOBAL_RECV_CRB #include "netxen_nic_phan_reg.h" @@ -161,7 +160,7 @@ struct netxen_recv_crb recv_crb_registers[] = { }, /* Jumbo frames */ { - /* crb_rcv_producer_offset: */ + /* crb_rcv_producer_offset: */ NETXEN_NIC_REG(0x1f8), /* crb_rcv_consumer_offset: */ NETXEN_NIC_REG(0x1fc), @@ -210,7 +209,7 @@ struct netxen_recv_crb recv_crb_registers[] = { }, /* Jumbo frames */ { - /* crb_rcv_producer_offset: */ + /* crb_rcv_producer_offset: */ NETXEN_NIC_REG(0x23c), /* crb_rcv_consumer_offset: */ NETXEN_NIC_REG(0x240), @@ -244,12 +243,15 @@ struct netxen_recv_crb recv_crb_registers[] = { }, }; -u64 ctx_addr_sig_regs[][3] = { +static u64 ctx_addr_sig_regs[][3] = { {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} }; +#define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0]) +#define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2]) +#define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1]) /* PCI Windowing for DDR regions. */ @@ -279,8 +281,8 @@ u64 ctx_addr_sig_regs[][3] = { #define NETXEN_NIC_WINDOW_MARGIN 0x100000 -unsigned long netxen_nic_pci_set_window(struct netxen_adapter *adapter, - unsigned long long addr); +static unsigned long netxen_nic_pci_set_window(struct netxen_adapter *adapter, + unsigned long long addr); void netxen_free_hw_resources(struct netxen_adapter *adapter); int netxen_nic_set_mac(struct net_device *netdev, void *p) @@ -417,7 +419,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) adapter->ctx_desc->cmd_consumer_offset = cpu_to_le64(adapter->ctx_desc_phys_addr + sizeof(struct netxen_ring_ctx)); - adapter->cmd_consumer = (uint32_t *) (((char *)addr) + + adapter->cmd_consumer = (__le32 *) (((char *)addr) + sizeof(struct netxen_ring_ctx)); addr = netxen_alloc(adapter->ahw.pdev, @@ -584,35 +586,35 @@ int netxen_is_flash_supported(struct netxen_adapter *adapter) } static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, - int size, u32 * buf) + int size, __le32 * buf) { int i, addr; - u32 *ptr32; + __le32 *ptr32; + u32 v; addr = base; ptr32 = buf; for (i = 0; i < size / sizeof(u32); i++) { - if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) + if (netxen_rom_fast_read(adapter, addr, &v) == -1) return -1; - *ptr32 = cpu_to_le32(*ptr32); + *ptr32 = cpu_to_le32(v); ptr32++; addr += sizeof(u32); } if ((char *)buf + size > (char *)ptr32) { - u32 local; - - if (netxen_rom_fast_read(adapter, addr, &local) == -1) + __le32 local; + if (netxen_rom_fast_read(adapter, addr, &v) == -1) return -1; - local = cpu_to_le32(local); + local = cpu_to_le32(v); memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32); } return 0; } -int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]) +int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 mac[]) { - u32 *pmac = (u32 *) & mac[0]; + __le32 *pmac = (__le32 *) & mac[0]; if (netxen_get_flash_block(adapter, NETXEN_USER_START + @@ -621,7 +623,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]) FLASH_NUM_PORTS * sizeof(u64), pmac) == -1) { return -1; } - if (*mac == ~0ULL) { + if (*mac == cpu_to_le64(~0ULL)) { if (netxen_get_flash_block(adapter, NETXEN_USER_START_OLD + offsetof(struct netxen_user_old_info, @@ -629,7 +631,7 @@ int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]) FLASH_NUM_PORTS * sizeof(u64), pmac) == -1) return -1; - if (*mac == ~0ULL) + if (*mac == cpu_to_le64(~0ULL)) return -1; } return 0; @@ -664,7 +666,7 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3)); break; default: - printk(KERN_INFO "Changing the window for PCI function" + printk(KERN_INFO "Changing the window for PCI function " "%d\n", adapter->ahw.pci_func); offset = PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); @@ -886,11 +888,10 @@ void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 * value) netxen_nic_pci_change_crbwindow(adapter, 1); } -int netxen_pci_set_window_warning_count = 0; +static int netxen_pci_set_window_warning_count; -unsigned long -netxen_nic_pci_set_window(struct netxen_adapter *adapter, - unsigned long long addr) +static unsigned long netxen_nic_pci_set_window(struct netxen_adapter *adapter, + unsigned long long addr) { static int ddr_mn_window = -1; static int qdr_sn_window = -1; @@ -952,16 +953,18 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter, return addr; } +#if 0 int netxen_nic_erase_pxe(struct netxen_adapter *adapter) { if (netxen_rom_fast_write(adapter, NETXEN_PXE_START, 0) == -1) { - printk(KERN_ERR "%s: erase pxe failed\n", + printk(KERN_ERR "%s: erase pxe failed\n", netxen_nic_driver_name); return -1; } return 0; } +#endif /* 0 */ int netxen_nic_get_board_info(struct netxen_adapter *adapter) { @@ -1036,9 +1039,9 @@ int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu) { new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE; if (physical_port[adapter->portnum] == 0) - netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, + netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu); - else + else netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu); return 0; diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index 245bf13c7ba2..a3ea1dd98c41 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h @@ -235,7 +235,7 @@ typedef enum { ((config_word) |= 1 << 0) #define netxen_xg_set_xg1_mask(config_word) \ ((config_word) |= 1 << 3) - + #define netxen_xg_get_xg0_mask(config_word) \ _netxen_crb_get_bit((config_word), 0) #define netxen_xg_get_xg1_mask(config_word) \ @@ -273,7 +273,7 @@ typedef enum { _netxen_crb_get_bit((config_word), 4) #define netxen_gb_get_gb3_mask(config_word) \ _netxen_crb_get_bit((config_word), 6) - + #define netxen_gb_unset_gb0_mask(config_word) \ ((config_word) &= ~(1 << 0)) #define netxen_gb_unset_gb1_mask(config_word) \ @@ -437,7 +437,7 @@ typedef enum { /* * NIU GB Drop CRC Register - * + * * Bit 0 : drop_gb0 => 1:drop pkts with bad CRCs, 0:pass them on * Bit 1 : drop_gb1 => 1:drop pkts with bad CRCs, 0:pass them on * Bit 2 : drop_gb2 => 1:drop pkts with bad CRCs, 0:pass them on @@ -480,7 +480,7 @@ typedef enum { /* * MAC Control Register - * + * * Bit 0-1 : id_pool0 * Bit 2 : enable_xtnd0 * Bit 4-5 : id_pool1 @@ -515,20 +515,16 @@ typedef enum { ((config) |= (((val) & 0x0f) << 28)) /* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, netxen_niu_prom_mode_t mode); int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, netxen_niu_prom_mode_t mode); -/* get/set the MAC address for a given MAC */ -int netxen_niu_macaddr_get(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t * addr); +/* set the MAC address for a given MAC */ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, netxen_ethernet_macaddr_t addr); -/* XG versons */ -int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t * addr); +/* XG version */ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, netxen_ethernet_macaddr_t addr); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 485ff9398910..9e38bcb3fba9 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -54,13 +54,17 @@ static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM]; #define NETXEN_NIC_XDMA_RESET 0x8000ff -static inline void -netxen_nic_locked_write_reg(struct netxen_adapter *adapter, - unsigned long off, int *data) +static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, + uint32_t ctx, uint32_t ringid); + +#if 0 +static void netxen_nic_locked_write_reg(struct netxen_adapter *adapter, + unsigned long off, int *data) { void __iomem *addr = pci_base_offset(adapter, off); writel(*data, addr); } +#endif /* 0 */ static void crb_addr_transform_setup(void) { @@ -255,7 +259,7 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) * netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB * address to external PCI CRB address. */ -u32 netxen_decode_crb_addr(u32 addr) +static u32 netxen_decode_crb_addr(u32 addr) { int i; u32 base_addr, offset, pci_base; @@ -282,7 +286,7 @@ static long rom_max_timeout = 100; static long rom_lock_timeout = 10000; static long rom_write_timeout = 700; -static inline int rom_lock(struct netxen_adapter *adapter) +static int rom_lock(struct netxen_adapter *adapter) { int iter; u32 done = 0; @@ -312,7 +316,7 @@ static inline int rom_lock(struct netxen_adapter *adapter) return 0; } -int netxen_wait_rom_done(struct netxen_adapter *adapter) +static int netxen_wait_rom_done(struct netxen_adapter *adapter) { long timeout = 0; long done = 0; @@ -329,7 +333,7 @@ int netxen_wait_rom_done(struct netxen_adapter *adapter) return 0; } -static inline int netxen_rom_wren(struct netxen_adapter *adapter) +static int netxen_rom_wren(struct netxen_adapter *adapter) { /* Set write enable latch in ROM status register */ netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0); @@ -341,15 +345,15 @@ static inline int netxen_rom_wren(struct netxen_adapter *adapter) return 0; } -static inline unsigned int netxen_rdcrbreg(struct netxen_adapter *adapter, - unsigned int addr) +static unsigned int netxen_rdcrbreg(struct netxen_adapter *adapter, + unsigned int addr) { unsigned int data = 0xdeaddead; data = netxen_nic_reg_read(adapter, addr); return data; } -static inline int netxen_do_rom_rdsr(struct netxen_adapter *adapter) +static int netxen_do_rom_rdsr(struct netxen_adapter *adapter) { netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR); @@ -359,7 +363,7 @@ static inline int netxen_do_rom_rdsr(struct netxen_adapter *adapter) return netxen_rdcrbreg(adapter, NETXEN_ROMUSB_ROM_RDATA); } -static inline void netxen_rom_unlock(struct netxen_adapter *adapter) +static void netxen_rom_unlock(struct netxen_adapter *adapter) { u32 val; @@ -368,7 +372,7 @@ static inline void netxen_rom_unlock(struct netxen_adapter *adapter) } -int netxen_rom_wip_poll(struct netxen_adapter *adapter) +static int netxen_rom_wip_poll(struct netxen_adapter *adapter) { long timeout = 0; long wip = 1; @@ -385,8 +389,8 @@ int netxen_rom_wip_poll(struct netxen_adapter *adapter) return 0; } -static inline int do_rom_fast_write(struct netxen_adapter *adapter, int addr, - int data) +static int do_rom_fast_write(struct netxen_adapter *adapter, int addr, + int data) { if (netxen_rom_wren(adapter)) { return -1; @@ -404,8 +408,8 @@ static inline int do_rom_fast_write(struct netxen_adapter *adapter, int addr, return netxen_rom_wip_poll(adapter); } -static inline int -do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) +static int do_rom_fast_read(struct netxen_adapter *adapter, + int addr, int *valp) { cond_resched(); @@ -427,18 +431,18 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) return 0; } -static inline int -do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, - u8 *bytes, size_t size) +static int do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, + u8 *bytes, size_t size) { int addridx; int ret = 0; for (addridx = addr; addridx < (addr + size); addridx += 4) { - ret = do_rom_fast_read(adapter, addridx, (int *)bytes); + int v; + ret = do_rom_fast_read(adapter, addridx, &v); if (ret != 0) break; - *(int *)bytes = cpu_to_le32(*(int *)bytes); + *(__le32 *)bytes = cpu_to_le32(v); bytes += 4; } @@ -446,7 +450,7 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, } int -netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, +netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, u8 *bytes, size_t size) { int ret; @@ -473,6 +477,7 @@ int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp) return ret; } +#if 0 int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data) { int ret = 0; @@ -484,9 +489,10 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data) netxen_rom_unlock(adapter); return ret; } +#endif /* 0 */ -static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, - int addr, u8 *bytes, size_t size) +static int do_rom_fast_write_words(struct netxen_adapter *adapter, + int addr, u8 *bytes, size_t size) { int addridx = addr; int ret = 0; @@ -496,11 +502,11 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, int timeout = 0; int data; - data = le32_to_cpu((*(u32*)bytes)); + data = le32_to_cpu((*(__le32*)bytes)); ret = do_rom_fast_write(adapter, addridx, data); if (ret < 0) return ret; - + while(1) { int data1; @@ -513,7 +519,7 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, if (timeout++ >= rom_write_timeout) { if (last_attempt++ < 4) { - ret = do_rom_fast_write(adapter, + ret = do_rom_fast_write(adapter, addridx, data); if (ret < 0) return ret; @@ -533,7 +539,7 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, return ret; } -int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, +int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, u8 *bytes, size_t size) { int ret = 0; @@ -548,7 +554,7 @@ int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, return ret; } -int netxen_rom_wrsr(struct netxen_adapter *adapter, int data) +static int netxen_rom_wrsr(struct netxen_adapter *adapter, int data) { int ret; @@ -557,7 +563,7 @@ int netxen_rom_wrsr(struct netxen_adapter *adapter, int data) return ret; netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data); - netxen_crb_writelit_adapter(adapter, + netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1); ret = netxen_wait_rom_done(adapter); @@ -567,7 +573,7 @@ int netxen_rom_wrsr(struct netxen_adapter *adapter, int data) return netxen_rom_wip_poll(adapter); } -int netxen_rom_rdsr(struct netxen_adapter *adapter) +static int netxen_rom_rdsr(struct netxen_adapter *adapter) { int ret; @@ -587,7 +593,7 @@ int netxen_backup_crbinit(struct netxen_adapter *adapter) char *buffer = kmalloc(NETXEN_FLASH_SECTOR_SIZE, GFP_KERNEL); if (!buffer) - return -ENOMEM; + return -ENOMEM; /* unlock sector 63 */ val = netxen_rom_rdsr(adapter); val = val & 0xe3; @@ -600,12 +606,12 @@ int netxen_backup_crbinit(struct netxen_adapter *adapter) goto out_kfree; /* copy sector 0 to sector 63 */ - ret = netxen_rom_fast_read_words(adapter, NETXEN_CRBINIT_START, + ret = netxen_rom_fast_read_words(adapter, NETXEN_CRBINIT_START, buffer, NETXEN_FLASH_SECTOR_SIZE); if (ret != FLASH_SUCCESS) goto out_kfree; - ret = netxen_rom_fast_write_words(adapter, NETXEN_FIXED_START, + ret = netxen_rom_fast_write_words(adapter, NETXEN_FIXED_START, buffer, NETXEN_FLASH_SECTOR_SIZE); if (ret != FLASH_SUCCESS) goto out_kfree; @@ -632,7 +638,7 @@ out_kfree: return ret; } -int netxen_do_rom_se(struct netxen_adapter *adapter, int addr) +static int netxen_do_rom_se(struct netxen_adapter *adapter, int addr) { netxen_rom_wren(adapter); netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr); @@ -646,16 +652,16 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr) return netxen_rom_wip_poll(adapter); } -void check_erased_flash(struct netxen_adapter *adapter, int addr) +static void check_erased_flash(struct netxen_adapter *adapter, int addr) { int i; int val; int count = 0, erased_errors = 0; int range; - range = (addr == NETXEN_USER_START) ? + range = (addr == NETXEN_USER_START) ? NETXEN_FIXED_START : addr + NETXEN_FLASH_SECTOR_SIZE; - + for (i = addr; i < range; i += 4) { netxen_rom_fast_read(adapter, i, &val); if (val != 0xffffffff) @@ -682,8 +688,8 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr) return ret; } -int -netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end) +static int netxen_flash_erase_sections(struct netxen_adapter *adapter, + int start, int end) { int ret = FLASH_SUCCESS; int i; @@ -990,7 +996,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter) return 0; } -static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) +static int netxen_nic_check_temp(struct netxen_adapter *adapter) { struct net_device *netdev = adapter->netdev; uint32_t temp, temp_state, temp_val; @@ -1064,9 +1070,8 @@ void netxen_watchdog_task(struct work_struct *work) * and if the number of receives exceeds RX_BUFFERS_REFILL, then we * invoke the routine to send more rx buffers to the Phantom... */ -void -netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, - struct status_desc *desc) +static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, + struct status_desc *desc) { struct pci_dev *pdev = adapter->pdev; struct net_device *netdev = adapter->netdev; @@ -1103,8 +1108,8 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, } if (buffer->lro_current_frags != buffer->lro_expected_frags) { if (buffer->lro_expected_frags != 0) { - printk("LRO: (refhandle:%x) recv frag." - "wait for last. flags: %x expected:%d" + printk("LRO: (refhandle:%x) recv frag. " + "wait for last. flags: %x expected:%d " "have:%d\n", index, netxen_get_sts_desc_lro_last_frag(desc), buffer->lro_expected_frags, @@ -1458,8 +1463,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) } } -void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, - uint32_t ringid) +static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, + uint32_t ctx, uint32_t ringid) { struct pci_dev *pdev = adapter->ahw.pdev; struct sk_buff *skb; @@ -1491,7 +1496,7 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, count++; /* now there should be no failure */ pdesc = &rcv_desc->desc_head[producer]; skb_reserve(skb, 2); - /* + /* * This will be setup when we receive the * buffer after it has been filled * skb->dev = netdev; diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c index b2de6b6c2a7f..48a404aa66ce 100644 --- a/drivers/net/netxen/netxen_nic_isr.c +++ b/drivers/net/netxen/netxen_nic_isr.c @@ -48,7 +48,7 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) /* total packets received */ stats->rx_packets = adapter->stats.no_rcv; /* total packets transmitted */ - stats->tx_packets = adapter->stats.xmitedframes + + stats->tx_packets = adapter->stats.xmitedframes + adapter->stats.xmitfinished; /* total bytes received */ stats->rx_bytes = adapter->stats.rxbytes; @@ -66,7 +66,8 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) return stats; } -void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link) +static void netxen_indicate_link_status(struct netxen_adapter *adapter, + u32 link) { struct net_device *netdev = adapter->netdev; @@ -76,13 +77,14 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link) netif_carrier_off(netdev); } +#if 0 void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) { __u32 int_src; /* This should clear the interrupt source */ if (adapter->phy_read) - adapter->phy_read(adapter, + adapter->phy_read(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, &int_src); if (int_src == 0) { @@ -111,7 +113,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); if (adapter->phy_read - && adapter->phy_read(adapter, + && adapter->phy_read(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) == 0) { if (netxen_get_phy_int_link_status_changed(int_src)) { @@ -125,7 +127,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) netxen_nic_driver_name, adapter->netdev->name); } - netxen_indicate_link_status(adapter, + netxen_indicate_link_status(adapter, netxen_get_phy_link (status)); } @@ -134,8 +136,9 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) if (adapter->enable_phy_interrupts) adapter->enable_phy_interrupts(adapter); } +#endif /* 0 */ -void netxen_nic_isr_other(struct netxen_adapter *adapter) +static void netxen_nic_isr_other(struct netxen_adapter *adapter) { int portno = adapter->portnum; u32 val, linkup, qg_linksup; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 263b55e36c7a..9737eae5ef11 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -89,8 +89,8 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); struct workqueue_struct *netxen_workq; static void netxen_watchdog(unsigned long); -static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, - uint32_t crb_producer) +static void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, + uint32_t crb_producer) { switch (adapter->portnum) { case 0: @@ -118,8 +118,8 @@ static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter } } -static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, - u32 crb_consumer) +static void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, + u32 crb_consumer) { switch (adapter->portnum) { case 0: @@ -148,7 +148,6 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter } #define ADAPTER_LIST_SIZE 12 -int netxen_cards_found; static void netxen_nic_disable_int(struct netxen_adapter *adapter) { @@ -278,7 +277,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct netxen_recv_context *recv_ctx = NULL; struct netxen_rcv_desc_ctx *rcv_desc = NULL; struct netxen_cmd_buffer *cmd_buf_arr = NULL; - u64 mac_addr[FLASH_NUM_PORTS + 1]; + __le64 mac_addr[FLASH_NUM_PORTS + 1]; int valid_mac = 0; u32 val; int pci_func_id = PCI_FUNC(pdev->devfn); @@ -287,7 +286,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO "%s \n", netxen_nic_driver_string); if (pdev->class != 0x020000) { - printk(KERN_ERR"NetXen function %d, class %x will not" + printk(KERN_ERR"NetXen function %d, class %x will not " "be enabled.\n",pci_func_id, pdev->class); return -ENODEV; } @@ -351,12 +350,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) first_page_group_start = 0; first_page_group_end = 0; } else { - err = -EIO; + err = -EIO; goto err_out_free_netdev; } - if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) || - (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) { + if ((!mem_ptr0 && mem_len == NETXEN_PCI_128MB_SIZE) || + !mem_ptr1 || !mem_ptr2) { DPRINTK(ERR, "Cannot remap adapter memory aborting.:" "0 -> %p, 1 -> %p, 2 -> %p\n", @@ -411,7 +410,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->open = netxen_nic_open; netdev->stop = netxen_nic_close; netdev->hard_start_xmit = netxen_nic_xmit_frame; - netdev->get_stats = netxen_nic_get_stats; + netdev->get_stats = netxen_nic_get_stats; netdev->set_multicast_list = netxen_nic_set_multi; netdev->set_mac_address = netxen_nic_set_mac; netdev->change_mtu = netxen_nic_change_mtu; @@ -458,8 +457,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST; if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) || - (adapter->ahw.boardcfg.board_type == - NETXEN_BRDTYPE_P2_SB31_2G)) + (adapter->ahw.boardcfg.board_type == + NETXEN_BRDTYPE_P2_SB31_2G)) adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; else adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; @@ -511,7 +510,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) vmalloc(RCV_BUFFSIZE); if (rcv_desc->rx_buf_arr == NULL) { - printk(KERN_ERR "%s: Could not allocate" + printk(KERN_ERR "%s: Could not allocate " "rcv_desc->rx_buf_arr memory:%d\n", netxen_nic_driver_name, (int)RCV_BUFFSIZE); @@ -584,9 +583,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (adapter->portnum == 0) { err = netxen_initialize_adapter_offload(adapter); - if (err) + if (err) goto err_out_free_rx_buffer; - val = readl(NETXEN_CRB_NORMALIZE(adapter, + val = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc))); if (val == 0x55555555) { /* This is the first boot after power up */ @@ -620,7 +619,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* * Tell the hardware our version number. */ - i = (_NETXEN_NIC_LINUX_MAJOR << 16) + i = (_NETXEN_NIC_LINUX_MAJOR << 16) | ((_NETXEN_NIC_LINUX_MINOR << 8)) | (_NETXEN_NIC_LINUX_SUBVERSION); writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION)); @@ -660,7 +659,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) break; case NETXEN_NIC_XGBE: - printk(KERN_INFO "%s: XGbE board initialized\n", + printk(KERN_INFO "%s: XGbE board initialized\n", netxen_nic_driver_name); break; } @@ -931,7 +930,7 @@ static int netxen_nic_close(struct net_device *netdev) buffrag++; if (buffrag->dma) { pci_unmap_page(adapter->pdev, buffrag->dma, - buffrag->length, + buffrag->length, PCI_DMA_TODEVICE); buffrag->dma = 0ULL; } @@ -981,7 +980,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) } if (frag_count > MAX_BUFFERS_PER_CMD) { - printk("%s: %s netxen_nic_xmit_frame: frag_count (%d)" + printk("%s: %s netxen_nic_xmit_frame: frag_count (%d) " "too large, can handle only %d frags\n", netxen_nic_driver_name, netdev->name, frag_count, MAX_BUFFERS_PER_CMD); @@ -1195,7 +1194,7 @@ static void netxen_tx_timeout(struct net_device *netdev) static void netxen_tx_timeout_task(struct work_struct *work) { - struct netxen_adapter *adapter = + struct netxen_adapter *adapter = container_of(work, struct netxen_adapter, tx_timeout_task); printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", @@ -1338,7 +1337,7 @@ static struct pci_driver netxen_driver = { static int __init netxen_init_module(void) { - if ((netxen_workq = create_singlethread_workqueue("netxen")) == 0) + if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL) return -ENOMEM; return pci_register_driver(&netxen_driver); diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index d04ecb77d08c..1c852a76c80d 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -40,7 +40,7 @@ static long phy_lock_timeout = 100000000; -static inline int phy_lock(struct netxen_adapter *adapter) +static int phy_lock(struct netxen_adapter *adapter) { int i; int done = 0, timeout = 0; @@ -68,14 +68,14 @@ static inline int phy_lock(struct netxen_adapter *adapter) return 0; } -static inline int phy_unlock(struct netxen_adapter *adapter) +static int phy_unlock(struct netxen_adapter *adapter) { readl(pci_base_offset(adapter, NETXEN_PCIE_REG(PCIE_SEM3_UNLOCK))); return 0; } -/* +/* * netxen_niu_gbe_phy_read - read a register from the GbE PHY via * mii management interface. * @@ -88,7 +88,7 @@ static inline int phy_unlock(struct netxen_adapter *adapter) * -1 on error * */ -int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, +int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, __u32 * readval) { long timeout = 0; @@ -171,7 +171,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, return result; } -/* +/* * netxen_niu_gbe_phy_write - write a register to the GbE PHY via * mii management interface. * @@ -184,7 +184,7 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, * -1 on error * */ -int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, +int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, __u32 val) { long timeout = 0; @@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) netxen_set_phy_int_speed_changed(enable); if (0 != - netxen_niu_gbe_phy_write(adapter, + netxen_niu_gbe_phy_write(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, enable)) result = -EIO; @@ -300,17 +300,19 @@ int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter) return result; } +#if 0 int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter) { netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); return 0; } +#endif /* 0 */ -int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) +static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) { int result = 0; if (0 != - netxen_niu_gbe_phy_write(adapter, + netxen_niu_gbe_phy_write(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, -EIO)) result = -EIO; @@ -318,12 +320,12 @@ int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) return result; } -/* +/* * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC * */ -void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, - int port, long enable) +static void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, + int port, long enable) { netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), @@ -342,9 +344,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); if (enable) { - /* - * Do NOT enable flow control until a suitable solution for - * shutting down pause frames is found. + /* + * Do NOT enable flow control until a suitable solution for + * shutting down pause frames is found. */ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), @@ -357,11 +359,11 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); } -/* +/* * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC */ -void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, - int port, long enable) +static void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, + int port, long enable) { netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2); netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), @@ -380,9 +382,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7); if (enable) { - /* - * Do NOT enable flow control until a suitable solution for - * shutting down pause frames is found. + /* + * Do NOT enable flow control until a suitable solution for + * shutting down pause frames is found. */ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), @@ -464,7 +466,8 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) return 0; } -/* +#if 0 +/* * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts * @param enable 0 means don't enable the port * 1 means enable (or re-enable) the port @@ -544,8 +547,8 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, port, enable); } else { - printk(KERN_ERR PFX "ERROR reading" - "PHY status. Illegal speed.\n"); + printk(KERN_ERR PFX "ERROR reading " + "PHY status. Invalid speed.\n"); result = -1; } } else { @@ -559,13 +562,14 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, } return result; } +#endif /* 0 */ /* * Return the current station MAC address. * Note that the passed-in value must already be in network byte order. */ -int netxen_niu_macaddr_get(struct netxen_adapter *adapter, - netxen_ethernet_macaddr_t * addr) +static int netxen_niu_macaddr_get(struct netxen_adapter *adapter, + netxen_ethernet_macaddr_t * addr) { u32 stationhigh; u32 stationlow; @@ -619,7 +623,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) return -2; - netxen_niu_macaddr_get(adapter, + netxen_niu_macaddr_get(adapter, (netxen_ethernet_macaddr_t *) mac_addr); if (memcmp(mac_addr, addr, 6) == 0) break; @@ -636,6 +640,7 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, return 0; } +#if 0 /* Enable a GbE interface */ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, int port, netxen_niu_gbe_ifmode_t mode) @@ -713,6 +718,7 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, return -EIO; return 0; } +#endif /* 0 */ /* Disable a GbE interface */ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) @@ -747,7 +753,7 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) } /* Set promiscuous mode for a GbE interface */ -int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, +int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, netxen_niu_prom_mode_t mode) { __u32 reg; @@ -853,6 +859,7 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, return 0; } +#if 0 /* * Return the current station MAC address. * Note that the passed-in value must already be in network byte order. @@ -883,6 +890,7 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, return 0; } +#endif /* 0 */ int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, netxen_niu_prom_mode_t mode) diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 10fe6fafa6f6..ffa3b7215ce8 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -1,7 +1,7 @@ /* * Copyright (C) 2003 - 2006 NetXen, Inc. * All rights reserved. - * + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -16,10 +16,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. - * + * * The full GNU General Public License is included in this distribution * in the file called LICENSE. - * + * * Contact Information: * info@netxen.com * NetXen, @@ -30,7 +30,7 @@ #ifndef __NIC_PHAN_REG_H_ #define __NIC_PHAN_REG_H_ -/* +/* * CRB Registers or queue message done only at initialization time. */ #define NIC_CRB_BASE NETXEN_CAM_RAM(0x200) @@ -165,14 +165,7 @@ struct netxen_recv_crb { u32 crb_status_ring_size; }; -#if defined(DEFINE_GLOBAL_RECV_CRB) -#else extern struct netxen_recv_crb recv_crb_registers[]; -extern u64 ctx_addr_sig_regs[][3]; -#endif /* DEFINE_GLOBAL_RECEIVE_CRB */ -#define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0]) -#define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2]) -#define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1]) /* * Temperature control. diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 5f6beabf2d17..2fe14b0c5c67 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7588,12 +7588,10 @@ static void __devinit niu_assign_netdev_ops(struct net_device *dev) static void __devinit niu_device_announce(struct niu *np) { struct net_device *dev = np->dev; - int i; + DECLARE_MAC_BUF(mac); - pr_info("%s: NIU Ethernet ", dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? '\n' : ':'); + pr_info("%s: NIU Ethernet %s\n", + dev->name, print_mac(mac, dev->dev_addr)); pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n", dev->name, diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index ea71f6d82661..b42c05f84be1 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -611,8 +611,7 @@ static inline int rx_refill(struct net_device *ndev, gfp_t gfp) return i ? 0 : -ENOMEM; } -static void FASTCALL(rx_refill_atomic(struct net_device *ndev)); -static void fastcall rx_refill_atomic(struct net_device *ndev) +static void rx_refill_atomic(struct net_device *ndev) { rx_refill(ndev, GFP_ATOMIC); } @@ -633,8 +632,7 @@ static inline void clear_rx_desc(struct ns83820 *dev, unsigned i) build_rx_desc(dev, dev->rx_info.descs + (DESC_SIZE * i), 0, 0, CMDSTS_OWN, 0); } -static void FASTCALL(phy_intr(struct net_device *ndev)); -static void fastcall phy_intr(struct net_device *ndev) +static void phy_intr(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); static const char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; @@ -832,8 +830,7 @@ static void ns83820_cleanup_rx(struct ns83820 *dev) } } -static void FASTCALL(ns83820_rx_kick(struct net_device *ndev)); -static void fastcall ns83820_rx_kick(struct net_device *ndev) +static void ns83820_rx_kick(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); /*if (nr_rx_empty(dev) >= NR_RX_DESC/4)*/ { @@ -854,8 +851,7 @@ static void fastcall ns83820_rx_kick(struct net_device *ndev) /* rx_irq * */ -static void FASTCALL(rx_irq(struct net_device *ndev)); -static void fastcall rx_irq(struct net_device *ndev) +static void rx_irq(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); struct rx_info *info = &dev->rx_info; diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 816a59e801b2..bb88a41b7591 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -32,9 +32,11 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <net/checksum.h> +#include <linux/inet_lro.h> #include <asm/irq.h> #include <asm/firmware.h> +#include <asm/pasemi_dma.h> #include "pasemi_mac.h" @@ -55,9 +57,11 @@ /* Must be a power of two */ -#define RX_RING_SIZE 4096 +#define RX_RING_SIZE 2048 #define TX_RING_SIZE 4096 +#define LRO_MAX_AGGR 64 + #define DEFAULT_MSG_ENABLE \ (NETIF_MSG_DRV | \ NETIF_MSG_PROBE | \ @@ -68,11 +72,11 @@ NETIF_MSG_RX_ERR | \ NETIF_MSG_TX_ERR) -#define TX_RING(mac, num) ((mac)->tx->ring[(num) & (TX_RING_SIZE-1)]) -#define TX_RING_INFO(mac, num) ((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)]) -#define RX_RING(mac, num) ((mac)->rx->ring[(num) & (RX_RING_SIZE-1)]) -#define RX_RING_INFO(mac, num) ((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)]) -#define RX_BUFF(mac, num) ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)]) +#define TX_DESC(tx, num) ((tx)->chan.ring_virt[(num) & (TX_RING_SIZE-1)]) +#define TX_DESC_INFO(tx, num) ((tx)->ring_info[(num) & (TX_RING_SIZE-1)]) +#define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) +#define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) +#define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ & ((ring)->size - 1)) @@ -88,8 +92,6 @@ static int debug = -1; /* -1 == use DEFAULT_MSG_ENABLE as value */ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); -static struct pasdma_status *dma_status; - static int translation_enabled(void) { #if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) @@ -99,32 +101,78 @@ static int translation_enabled(void) #endif } -static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg, - unsigned int val) +static void write_iob_reg(unsigned int reg, unsigned int val) { - out_le32(mac->iob_regs+reg, val); + pasemi_write_iob_reg(reg, val); } -static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg) +static unsigned int read_mac_reg(const struct pasemi_mac *mac, unsigned int reg) { - return in_le32(mac->regs+reg); + return pasemi_read_mac_reg(mac->dma_if, reg); } -static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg, +static void write_mac_reg(const struct pasemi_mac *mac, unsigned int reg, unsigned int val) { - out_le32(mac->regs+reg, val); + pasemi_write_mac_reg(mac->dma_if, reg, val); } -static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg) +static unsigned int read_dma_reg(unsigned int reg) { - return in_le32(mac->dma_regs+reg); + return pasemi_read_dma_reg(reg); } -static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg, - unsigned int val) +static void write_dma_reg(unsigned int reg, unsigned int val) +{ + pasemi_write_dma_reg(reg, val); +} + +static struct pasemi_mac_rxring *rx_ring(const struct pasemi_mac *mac) { - out_le32(mac->dma_regs+reg, val); + return mac->rx; +} + +static struct pasemi_mac_txring *tx_ring(const struct pasemi_mac *mac) +{ + return mac->tx; +} + +static inline void prefetch_skb(const struct sk_buff *skb) +{ + const void *d = skb; + + prefetch(d); + prefetch(d+64); + prefetch(d+128); + prefetch(d+192); +} + +static int mac_to_intf(struct pasemi_mac *mac) +{ + struct pci_dev *pdev = mac->pdev; + u32 tmp; + int nintf, off, i, j; + int devfn = pdev->devfn; + + tmp = read_dma_reg(PAS_DMA_CAP_IFI); + nintf = (tmp & PAS_DMA_CAP_IFI_NIN_M) >> PAS_DMA_CAP_IFI_NIN_S; + off = (tmp & PAS_DMA_CAP_IFI_IOFF_M) >> PAS_DMA_CAP_IFI_IOFF_S; + + /* IOFF contains the offset to the registers containing the + * DMA interface-to-MAC-pci-id mappings, and NIN contains number + * of total interfaces. Each register contains 4 devfns. + * Just do a linear search until we find the devfn of the MAC + * we're trying to look up. + */ + + for (i = 0; i < (nintf+3)/4; i++) { + tmp = read_dma_reg(off+4*i); + for (j = 0; j < 4; j++) { + if (((tmp >> (8*j)) & 0xff) == devfn) + return i*4 + j; + } + } + return -1; } static int pasemi_get_mac_addr(struct pasemi_mac *mac) @@ -161,7 +209,6 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac) return -ENOENT; } - if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) { dev_warn(&pdev->dev, @@ -174,21 +221,51 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac) return 0; } +static int get_skb_hdr(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *data) +{ + u64 macrx = (u64) data; + unsigned int ip_len; + struct iphdr *iph; + + /* IPv4 header checksum failed */ + if ((macrx & XCT_MACRX_HTY_M) != XCT_MACRX_HTY_IPV4_OK) + return -1; + + /* non tcp packet */ + skb_reset_network_header(skb); + iph = ip_hdr(skb); + if (iph->protocol != IPPROTO_TCP) + return -1; + + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + *tcph = tcp_hdr(skb); + + /* check if ip header and tcp header are complete */ + if (iph->tot_len < ip_len + tcp_hdrlen(skb)) + return -1; + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *iphdr = iph; + + return 0; +} + static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, + const int nfrags, struct sk_buff *skb, - dma_addr_t *dmas) + const dma_addr_t *dmas) { int f; - int nfrags = skb_shinfo(skb)->nr_frags; + struct pci_dev *pdev = mac->dma_pdev; - pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb), - PCI_DMA_TODEVICE); + pci_unmap_single(pdev, dmas[0], skb_headlen(skb), PCI_DMA_TODEVICE); for (f = 0; f < nfrags; f++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[f]; - pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size, - PCI_DMA_TODEVICE); + pci_unmap_page(pdev, dmas[f+1], frag->size, PCI_DMA_TODEVICE); } dev_kfree_skb_irq(skb); @@ -198,17 +275,21 @@ static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, return (nfrags + 3) & ~1; } -static int pasemi_mac_setup_rx_resources(struct net_device *dev) +static int pasemi_mac_setup_rx_resources(const struct net_device *dev) { struct pasemi_mac_rxring *ring; struct pasemi_mac *mac = netdev_priv(dev); - int chan_id = mac->dma_rxch; + int chno; unsigned int cfg; - ring = kzalloc(sizeof(*ring), GFP_KERNEL); + ring = pasemi_dma_alloc_chan(RXCHAN, sizeof(struct pasemi_mac_rxring), + offsetof(struct pasemi_mac_rxring, chan)); - if (!ring) - goto out_ring; + if (!ring) { + dev_err(&mac->pdev->dev, "Can't allocate RX channel\n"); + goto out_chan; + } + chno = ring->chan.chno; spin_lock_init(&ring->lock); @@ -220,85 +301,80 @@ static int pasemi_mac_setup_rx_resources(struct net_device *dev) goto out_ring_info; /* Allocate descriptors */ - ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(u64), - &ring->dma, GFP_KERNEL); - - if (!ring->ring) + if (pasemi_dma_alloc_ring(&ring->chan, RX_RING_SIZE)) goto out_ring_desc; - memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64)); - ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), &ring->buf_dma, GFP_KERNEL); if (!ring->buffers) - goto out_buffers; + goto out_ring_desc; memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64)); - write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma)); + write_dma_reg(PAS_DMA_RXCHAN_BASEL(chno), + PAS_DMA_RXCHAN_BASEL_BRBL(ring->chan.ring_dma)); - write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id), - PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) | - PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3)); + write_dma_reg(PAS_DMA_RXCHAN_BASEU(chno), + PAS_DMA_RXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32) | + PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3)); cfg = PAS_DMA_RXCHAN_CFG_HBU(2); if (translation_enabled()) cfg |= PAS_DMA_RXCHAN_CFG_CTR; - write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg); + write_dma_reg(PAS_DMA_RXCHAN_CFG(chno), cfg); - write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if), - PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma)); + write_dma_reg(PAS_DMA_RXINT_BASEL(mac->dma_if), + PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma)); - write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if), - PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) | - PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); + write_dma_reg(PAS_DMA_RXINT_BASEU(mac->dma_if), + PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) | + PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3)); - cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 | + cfg = PAS_DMA_RXINT_CFG_DHL(2) | PAS_DMA_RXINT_CFG_L2 | PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP | PAS_DMA_RXINT_CFG_HEN; if (translation_enabled()) cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR; - write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg); + write_dma_reg(PAS_DMA_RXINT_CFG(mac->dma_if), cfg); ring->next_to_fill = 0; ring->next_to_clean = 0; - - snprintf(ring->irq_name, sizeof(ring->irq_name), - "%s rx", dev->name); + ring->mac = mac; mac->rx = ring; return 0; -out_buffers: - dma_free_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(u64), - mac->rx->ring, mac->rx->dma); out_ring_desc: kfree(ring->ring_info); out_ring_info: - kfree(ring); -out_ring: + pasemi_dma_free_chan(&ring->chan); +out_chan: return -ENOMEM; } - -static int pasemi_mac_setup_tx_resources(struct net_device *dev) +static struct pasemi_mac_txring * +pasemi_mac_setup_tx_resources(const struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); u32 val; - int chan_id = mac->dma_txch; struct pasemi_mac_txring *ring; unsigned int cfg; + int chno; + + ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_txring), + offsetof(struct pasemi_mac_txring, chan)); - ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (!ring) - goto out_ring; + if (!ring) { + dev_err(&mac->pdev->dev, "Can't allocate TX channel\n"); + goto out_chan; + } + + chno = ring->chan.chno; spin_lock_init(&ring->lock); @@ -309,20 +385,15 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) goto out_ring_info; /* Allocate descriptors */ - ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev, - TX_RING_SIZE * sizeof(u64), - &ring->dma, GFP_KERNEL); - if (!ring->ring) + if (pasemi_dma_alloc_ring(&ring->chan, TX_RING_SIZE)) goto out_ring_desc; - memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64)); - - write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id), - PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma)); - val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32); + write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno), + PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma)); + val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32); val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3); - write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val); + write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val); cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | @@ -332,71 +403,64 @@ static int pasemi_mac_setup_tx_resources(struct net_device *dev) if (translation_enabled()) cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; - write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg); + write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg); ring->next_to_fill = 0; ring->next_to_clean = 0; + ring->mac = mac; - snprintf(ring->irq_name, sizeof(ring->irq_name), - "%s tx", dev->name); - mac->tx = ring; - - return 0; + return ring; out_ring_desc: kfree(ring->ring_info); out_ring_info: - kfree(ring); -out_ring: - return -ENOMEM; + pasemi_dma_free_chan(&ring->chan); +out_chan: + return NULL; } -static void pasemi_mac_free_tx_resources(struct net_device *dev) +static void pasemi_mac_free_tx_resources(struct pasemi_mac *mac) { - struct pasemi_mac *mac = netdev_priv(dev); + struct pasemi_mac_txring *txring = tx_ring(mac); unsigned int i, j; struct pasemi_mac_buffer *info; dma_addr_t dmas[MAX_SKB_FRAGS+1]; - int freed; + int freed, nfrags; int start, limit; - start = mac->tx->next_to_clean; - limit = mac->tx->next_to_fill; + start = txring->next_to_clean; + limit = txring->next_to_fill; /* Compensate for when fill has wrapped and clean has not */ if (start > limit) limit += TX_RING_SIZE; for (i = start; i < limit; i += freed) { - info = &TX_RING_INFO(mac, i+1); + info = &txring->ring_info[(i+1) & (TX_RING_SIZE-1)]; if (info->dma && info->skb) { - for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++) - dmas[j] = TX_RING_INFO(mac, i+1+j).dma; - freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas); + nfrags = skb_shinfo(info->skb)->nr_frags; + for (j = 0; j <= nfrags; j++) + dmas[j] = txring->ring_info[(i+1+j) & + (TX_RING_SIZE-1)].dma; + freed = pasemi_mac_unmap_tx_skb(mac, nfrags, + info->skb, dmas); } else freed = 2; } - for (i = 0; i < TX_RING_SIZE; i++) - TX_RING(mac, i) = 0; - - dma_free_coherent(&mac->dma_pdev->dev, - TX_RING_SIZE * sizeof(u64), - mac->tx->ring, mac->tx->dma); + kfree(txring->ring_info); + pasemi_dma_free_chan(&txring->chan); - kfree(mac->tx->ring_info); - kfree(mac->tx); - mac->tx = NULL; } -static void pasemi_mac_free_rx_resources(struct net_device *dev) +static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac) { - struct pasemi_mac *mac = netdev_priv(dev); + struct pasemi_mac_rxring *rx = rx_ring(mac); unsigned int i; struct pasemi_mac_buffer *info; for (i = 0; i < RX_RING_SIZE; i++) { - info = &RX_RING_INFO(mac, i); + info = &RX_DESC_INFO(rx, i); if (info->skb && info->dma) { pci_unmap_single(mac->dma_pdev, info->dma, @@ -409,45 +473,38 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev) } for (i = 0; i < RX_RING_SIZE; i++) - RX_RING(mac, i) = 0; - - dma_free_coherent(&mac->dma_pdev->dev, - RX_RING_SIZE * sizeof(u64), - mac->rx->ring, mac->rx->dma); + RX_DESC(rx, i) = 0; dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), - mac->rx->buffers, mac->rx->buf_dma); + rx_ring(mac)->buffers, rx_ring(mac)->buf_dma); - kfree(mac->rx->ring_info); - kfree(mac->rx); + kfree(rx_ring(mac)->ring_info); + pasemi_dma_free_chan(&rx_ring(mac)->chan); mac->rx = NULL; } -static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) +static void pasemi_mac_replenish_rx_ring(const struct net_device *dev, + const int limit) { - struct pasemi_mac *mac = netdev_priv(dev); + const struct pasemi_mac *mac = netdev_priv(dev); + struct pasemi_mac_rxring *rx = rx_ring(mac); int fill, count; if (limit <= 0) return; - fill = mac->rx->next_to_fill; + fill = rx_ring(mac)->next_to_fill; for (count = 0; count < limit; count++) { - struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill); - u64 *buff = &RX_BUFF(mac, fill); + struct pasemi_mac_buffer *info = &RX_DESC_INFO(rx, fill); + u64 *buff = &RX_BUFF(rx, fill); struct sk_buff *skb; dma_addr_t dma; /* Entry in use? */ WARN_ON(*buff); - /* skb might still be in there for recycle on short receives */ - if (info->skb) - skb = info->skb; - else { - skb = dev_alloc_skb(BUF_SIZE); - skb_reserve(skb, LOCAL_SKB_ALIGN); - } + skb = dev_alloc_skb(BUF_SIZE); + skb_reserve(skb, LOCAL_SKB_ALIGN); if (unlikely(!skb)) break; @@ -469,94 +526,108 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit) wmb(); - write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count); + write_dma_reg(PAS_DMA_RXINT_INCR(mac->dma_if), count); - mac->rx->next_to_fill = (mac->rx->next_to_fill + count) & + rx_ring(mac)->next_to_fill = (rx_ring(mac)->next_to_fill + count) & (RX_RING_SIZE - 1); } -static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac) +static void pasemi_mac_restart_rx_intr(const struct pasemi_mac *mac) { + struct pasemi_mac_rxring *rx = rx_ring(mac); unsigned int reg, pcnt; /* Re-enable packet count interrupts: finally * ack the packet count interrupt we got in rx_intr. */ - pcnt = *mac->rx_status & PAS_STATUS_PCNT_M; + pcnt = *rx->chan.status & PAS_STATUS_PCNT_M; reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC; - write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); + if (*rx->chan.status & PAS_STATUS_TIMER) + reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; + + write_iob_reg(PAS_IOB_DMA_RXCH_RESET(mac->rx->chan.chno), reg); } -static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac) +static void pasemi_mac_restart_tx_intr(const struct pasemi_mac *mac) { unsigned int reg, pcnt; /* Re-enable packet count interrupts */ - pcnt = *mac->tx_status & PAS_STATUS_PCNT_M; + pcnt = *tx_ring(mac)->chan.status & PAS_STATUS_PCNT_M; reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC; - write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); + write_iob_reg(PAS_IOB_DMA_TXCH_RESET(tx_ring(mac)->chan.chno), reg); } -static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx) +static inline void pasemi_mac_rx_error(const struct pasemi_mac *mac, + const u64 macrx) { unsigned int rcmdsta, ccmdsta; + struct pasemi_dmachan *chan = &rx_ring(mac)->chan; if (!netif_msg_rx_err(mac)) return; - rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); - ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + ccmdsta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(chan->chno)); printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n", - macrx, *mac->rx_status); + macrx, *chan->status); printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n", rcmdsta, ccmdsta); } -static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx) +static inline void pasemi_mac_tx_error(const struct pasemi_mac *mac, + const u64 mactx) { unsigned int cmdsta; + struct pasemi_dmachan *chan = &tx_ring(mac)->chan; if (!netif_msg_tx_err(mac)) return; - cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + cmdsta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(chan->chno)); printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\ - "tx status 0x%016lx\n", mactx, *mac->tx_status); + "tx status 0x%016lx\n", mactx, *chan->status); printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta); } -static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) +static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx, + const int limit) { + const struct pasemi_dmachan *chan = &rx->chan; + struct pasemi_mac *mac = rx->mac; + struct pci_dev *pdev = mac->dma_pdev; unsigned int n; - int count; + int count, buf_index, tot_bytes, packets; struct pasemi_mac_buffer *info; struct sk_buff *skb; unsigned int len; - u64 macrx; + u64 macrx, eval; dma_addr_t dma; - int buf_index; - u64 eval; - spin_lock(&mac->rx->lock); + tot_bytes = 0; + packets = 0; - n = mac->rx->next_to_clean; + spin_lock(&rx->lock); - prefetch(&RX_RING(mac, n)); + n = rx->next_to_clean; + + prefetch(&RX_DESC(rx, n)); for (count = 0; count < limit; count++) { - macrx = RX_RING(mac, n); + macrx = RX_DESC(rx, n); + prefetch(&RX_DESC(rx, n+4)); if ((macrx & XCT_MACRX_E) || - (*mac->rx_status & PAS_STATUS_ERROR)) + (*chan->status & PAS_STATUS_ERROR)) pasemi_mac_rx_error(mac, macrx); if (!(macrx & XCT_MACRX_O)) @@ -566,21 +637,21 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) BUG_ON(!(macrx & XCT_MACRX_RR_8BRES)); - eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >> + eval = (RX_DESC(rx, n+1) & XCT_RXRES_8B_EVAL_M) >> XCT_RXRES_8B_EVAL_S; buf_index = eval-1; - dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M); - info = &RX_RING_INFO(mac, buf_index); + dma = (RX_DESC(rx, n+2) & XCT_PTR_ADDR_M); + info = &RX_DESC_INFO(rx, buf_index); skb = info->skb; - prefetch(skb); - prefetch(&skb->data_len); + prefetch_skb(skb); len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; - pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE); + pci_unmap_single(pdev, dma, BUF_SIZE-LOCAL_SKB_ALIGN, + PCI_DMA_FROMDEVICE); if (macrx & XCT_MACRX_CRC) { /* CRC error flagged */ @@ -590,26 +661,9 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) goto next; } - if (len < 256) { - struct sk_buff *new_skb; - - new_skb = netdev_alloc_skb(mac->netdev, - len + LOCAL_SKB_ALIGN); - if (new_skb) { - skb_reserve(new_skb, LOCAL_SKB_ALIGN); - memcpy(new_skb->data, skb->data, len); - /* save the skb in buffer_info as good */ - skb = new_skb; - } - /* else just continue with the old one */ - } else - info->skb = NULL; - + info->skb = NULL; info->dma = 0; - /* Don't include CRC */ - skb_put(skb, len-4); - if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) { skb->ip_summed = CHECKSUM_UNNECESSARY; skb->csum = (macrx & XCT_MACRX_CSUM_M) >> @@ -617,41 +671,49 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit) } else skb->ip_summed = CHECKSUM_NONE; - mac->netdev->stats.rx_bytes += len; - mac->netdev->stats.rx_packets++; + packets++; + tot_bytes += len; + + /* Don't include CRC */ + skb_put(skb, len-4); skb->protocol = eth_type_trans(skb, mac->netdev); - netif_receive_skb(skb); + lro_receive_skb(&mac->lro_mgr, skb, (void *)macrx); next: - RX_RING(mac, n) = 0; - RX_RING(mac, n+1) = 0; + RX_DESC(rx, n) = 0; + RX_DESC(rx, n+1) = 0; /* Need to zero it out since hardware doesn't, since the * replenish loop uses it to tell when it's done. */ - RX_BUFF(mac, buf_index) = 0; + RX_BUFF(rx, buf_index) = 0; n += 4; } if (n > RX_RING_SIZE) { /* Errata 5971 workaround: L2 target of headers */ - write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0); + write_iob_reg(PAS_IOB_COM_PKTHDRCNT, 0); n &= (RX_RING_SIZE-1); } - mac->rx->next_to_clean = n; + rx_ring(mac)->next_to_clean = n; + + lro_flush_all(&mac->lro_mgr); /* Increase is in number of 16-byte entries, and since each descriptor * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with * count*2. */ - write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1); + write_dma_reg(PAS_DMA_RXCHAN_INCR(mac->rx->chan.chno), count << 1); pasemi_mac_replenish_rx_ring(mac->netdev, count); - spin_unlock(&mac->rx->lock); + mac->netdev->stats.rx_bytes += tot_bytes; + mac->netdev->stats.rx_packets += packets; + + spin_unlock(&rx_ring(mac)->lock); return count; } @@ -659,8 +721,10 @@ next: /* Can't make this too large or we blow the kernel stack limits */ #define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS) -static int pasemi_mac_clean_tx(struct pasemi_mac *mac) +static int pasemi_mac_clean_tx(struct pasemi_mac_txring *txring) { + struct pasemi_dmachan *chan = &txring->chan; + struct pasemi_mac *mac = txring->mac; int i, j; unsigned int start, descr_count, buf_count, batch_limit; unsigned int ring_limit; @@ -668,14 +732,18 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac) unsigned long flags; struct sk_buff *skbs[TX_CLEAN_BATCHSIZE]; dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1]; + int nf[TX_CLEAN_BATCHSIZE]; + int nr_frags; total_count = 0; batch_limit = TX_CLEAN_BATCHSIZE; restart: - spin_lock_irqsave(&mac->tx->lock, flags); + spin_lock_irqsave(&txring->lock, flags); + + start = txring->next_to_clean; + ring_limit = txring->next_to_fill; - start = mac->tx->next_to_clean; - ring_limit = mac->tx->next_to_fill; + prefetch(&TX_DESC_INFO(txring, start+1).skb); /* Compensate for when fill has wrapped but clean has not */ if (start > ring_limit) @@ -687,41 +755,45 @@ restart: for (i = start; descr_count < batch_limit && i < ring_limit; i += buf_count) { - u64 mactx = TX_RING(mac, i); + u64 mactx = TX_DESC(txring, i); struct sk_buff *skb; + skb = TX_DESC_INFO(txring, i+1).skb; + nr_frags = TX_DESC_INFO(txring, i).dma; + if ((mactx & XCT_MACTX_E) || - (*mac->tx_status & PAS_STATUS_ERROR)) + (*chan->status & PAS_STATUS_ERROR)) pasemi_mac_tx_error(mac, mactx); if (unlikely(mactx & XCT_MACTX_O)) /* Not yet transmitted */ break; - skb = TX_RING_INFO(mac, i+1).skb; - skbs[descr_count] = skb; - - buf_count = 2 + skb_shinfo(skb)->nr_frags; - for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++) - dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma; - - TX_RING(mac, i) = 0; - TX_RING(mac, i+1) = 0; - + buf_count = 2 + nr_frags; /* Since we always fill with an even number of entries, make * sure we skip any unused one at the end as well. */ if (buf_count & 1) buf_count++; + + for (j = 0; j <= nr_frags; j++) + dmas[descr_count][j] = TX_DESC_INFO(txring, i+1+j).dma; + + skbs[descr_count] = skb; + nf[descr_count] = nr_frags; + + TX_DESC(txring, i) = 0; + TX_DESC(txring, i+1) = 0; + descr_count++; } - mac->tx->next_to_clean = i & (TX_RING_SIZE-1); + txring->next_to_clean = i & (TX_RING_SIZE-1); - spin_unlock_irqrestore(&mac->tx->lock, flags); + spin_unlock_irqrestore(&txring->lock, flags); netif_wake_queue(mac->netdev); for (i = 0; i < descr_count; i++) - pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]); + pasemi_mac_unmap_tx_skb(mac, nf[i], skbs[i], dmas[i]); total_count += descr_count; @@ -735,11 +807,13 @@ restart: static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) { - struct net_device *dev = data; - struct pasemi_mac *mac = netdev_priv(dev); + const struct pasemi_mac_rxring *rxring = data; + struct pasemi_mac *mac = rxring->mac; + struct net_device *dev = mac->netdev; + const struct pasemi_dmachan *chan = &rxring->chan; unsigned int reg; - if (!(*mac->rx_status & PAS_STATUS_CAUSE_M)) + if (!(*chan->status & PAS_STATUS_CAUSE_M)) return IRQ_NONE; /* Don't reset packet count so it won't fire again but clear @@ -747,45 +821,77 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) */ reg = 0; - if (*mac->rx_status & PAS_STATUS_SOFT) + if (*chan->status & PAS_STATUS_SOFT) reg |= PAS_IOB_DMA_RXCH_RESET_SINTC; - if (*mac->rx_status & PAS_STATUS_ERROR) + if (*chan->status & PAS_STATUS_ERROR) reg |= PAS_IOB_DMA_RXCH_RESET_DINTC; - if (*mac->rx_status & PAS_STATUS_TIMER) - reg |= PAS_IOB_DMA_RXCH_RESET_TINTC; netif_rx_schedule(dev, &mac->napi); - write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg); + write_iob_reg(PAS_IOB_DMA_RXCH_RESET(chan->chno), reg); return IRQ_HANDLED; } -static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) +#define TX_CLEAN_INTERVAL HZ + +static void pasemi_mac_tx_timer(unsigned long data) { - struct net_device *dev = data; - struct pasemi_mac *mac = netdev_priv(dev); - unsigned int reg, pcnt; + struct pasemi_mac_txring *txring = (struct pasemi_mac_txring *)data; + struct pasemi_mac *mac = txring->mac; - if (!(*mac->tx_status & PAS_STATUS_CAUSE_M)) - return IRQ_NONE; + pasemi_mac_clean_tx(txring); + + mod_timer(&txring->clean_timer, jiffies + TX_CLEAN_INTERVAL); - pasemi_mac_clean_tx(mac); + pasemi_mac_restart_tx_intr(mac); +} - pcnt = *mac->tx_status & PAS_STATUS_PCNT_M; +static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) +{ + struct pasemi_mac_txring *txring = data; + const struct pasemi_dmachan *chan = &txring->chan; + struct pasemi_mac *mac = txring->mac; + unsigned int reg; - reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC; + if (!(*chan->status & PAS_STATUS_CAUSE_M)) + return IRQ_NONE; - if (*mac->tx_status & PAS_STATUS_SOFT) + reg = 0; + + if (*chan->status & PAS_STATUS_SOFT) reg |= PAS_IOB_DMA_TXCH_RESET_SINTC; - if (*mac->tx_status & PAS_STATUS_ERROR) + if (*chan->status & PAS_STATUS_ERROR) reg |= PAS_IOB_DMA_TXCH_RESET_DINTC; - write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg); + mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2); + + netif_rx_schedule(mac->netdev, &mac->napi); + + if (reg) + write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg); return IRQ_HANDLED; } +static void pasemi_mac_intf_disable(struct pasemi_mac *mac) +{ + unsigned int flags; + + flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); + flags &= ~PAS_MAC_CFG_PCFG_PE; + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); +} + +static void pasemi_mac_intf_enable(struct pasemi_mac *mac) +{ + unsigned int flags; + + flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); + flags |= PAS_MAC_CFG_PCFG_PE; + write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); +} + static void pasemi_adjust_link(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); @@ -801,11 +907,14 @@ static void pasemi_adjust_link(struct net_device *dev) printk(KERN_INFO "%s: Link is down.\n", dev->name); netif_carrier_off(dev); + pasemi_mac_intf_disable(mac); mac->link = 0; return; - } else + } else { + pasemi_mac_intf_enable(mac); netif_carrier_on(dev); + } flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M | @@ -897,15 +1006,14 @@ err: static int pasemi_mac_open(struct net_device *dev) { struct pasemi_mac *mac = netdev_priv(dev); - int base_irq; unsigned int flags; int ret; /* enable rx section */ - write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); + write_dma_reg(PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); /* enable tx section */ - write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); + write_dma_reg(PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | @@ -913,62 +1021,59 @@ static int pasemi_mac_open(struct net_device *dev) write_mac_reg(mac, PAS_MAC_CFG_TXP, flags); - write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch), - PAS_IOB_DMA_RXCH_CFG_CNTTH(0)); + ret = pasemi_mac_setup_rx_resources(dev); + if (ret) + goto out_rx_resources; - write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch), - PAS_IOB_DMA_TXCH_CFG_CNTTH(128)); + mac->tx = pasemi_mac_setup_tx_resources(dev); - /* Clear out any residual packet count state from firmware */ - pasemi_mac_restart_rx_intr(mac); - pasemi_mac_restart_tx_intr(mac); + if (!mac->tx) + goto out_tx_ring; - /* 0xffffff is max value, about 16ms */ - write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG, - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff)); + /* 0x3ff with 33MHz clock is about 31us */ + write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, + PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); - ret = pasemi_mac_setup_rx_resources(dev); - if (ret) - goto out_rx_resources; + write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno), + PAS_IOB_DMA_RXCH_CFG_CNTTH(256)); - ret = pasemi_mac_setup_tx_resources(dev); - if (ret) - goto out_tx_resources; + write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno), + PAS_IOB_DMA_TXCH_CFG_CNTTH(32)); write_mac_reg(mac, PAS_MAC_IPC_CHNL, - PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) | - PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch)); + PAS_MAC_IPC_CHNL_DCHNO(mac->rx->chan.chno) | + PAS_MAC_IPC_CHNL_BCH(mac->rx->chan.chno)); /* enable rx if */ - write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), - PAS_DMA_RXINT_RCMDSTA_EN | - PAS_DMA_RXINT_RCMDSTA_DROPS_M | - PAS_DMA_RXINT_RCMDSTA_BP | - PAS_DMA_RXINT_RCMDSTA_OO | - PAS_DMA_RXINT_RCMDSTA_BT); + write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + PAS_DMA_RXINT_RCMDSTA_EN | + PAS_DMA_RXINT_RCMDSTA_DROPS_M | + PAS_DMA_RXINT_RCMDSTA_BP | + PAS_DMA_RXINT_RCMDSTA_OO | + PAS_DMA_RXINT_RCMDSTA_BT); /* enable rx channel */ - write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), - PAS_DMA_RXCHAN_CCMDSTA_EN | - PAS_DMA_RXCHAN_CCMDSTA_DU | - PAS_DMA_RXCHAN_CCMDSTA_OD | - PAS_DMA_RXCHAN_CCMDSTA_FD | - PAS_DMA_RXCHAN_CCMDSTA_DT); + pasemi_dma_start_chan(&rx_ring(mac)->chan, PAS_DMA_RXCHAN_CCMDSTA_DU | + PAS_DMA_RXCHAN_CCMDSTA_OD | + PAS_DMA_RXCHAN_CCMDSTA_FD | + PAS_DMA_RXCHAN_CCMDSTA_DT); /* enable tx channel */ - write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), - PAS_DMA_TXCHAN_TCMDSTA_EN | - PAS_DMA_TXCHAN_TCMDSTA_SZ | - PAS_DMA_TXCHAN_TCMDSTA_DB | - PAS_DMA_TXCHAN_TCMDSTA_DE | - PAS_DMA_TXCHAN_TCMDSTA_DA); + pasemi_dma_start_chan(&tx_ring(mac)->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ | + PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | + PAS_DMA_TXCHAN_TCMDSTA_DA); pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE); - write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1); + write_dma_reg(PAS_DMA_RXCHAN_INCR(rx_ring(mac)->chan.chno), + RX_RING_SIZE>>1); + + /* Clear out any residual packet count state from firmware */ + pasemi_mac_restart_rx_intr(mac); + pasemi_mac_restart_tx_intr(mac); - flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE | - PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; + flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE; if (mac->type == MAC_TYPE_GMAC) flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G; @@ -979,55 +1084,63 @@ static int pasemi_mac_open(struct net_device *dev) write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); ret = pasemi_mac_phy_init(dev); - /* Some configs don't have PHYs (XAUI etc), so don't complain about - * failed init due to -ENODEV. - */ - if (ret && ret != -ENODEV) - dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret); + if (ret) { + /* Since we won't get link notification, just enable RX */ + pasemi_mac_intf_enable(mac); + if (mac->type == MAC_TYPE_GMAC) { + /* Warn for missing PHY on SGMII (1Gig) ports */ + dev_warn(&mac->pdev->dev, + "PHY init failed: %d.\n", ret); + dev_warn(&mac->pdev->dev, + "Defaulting to 1Gbit full duplex\n"); + } + } netif_start_queue(dev); napi_enable(&mac->napi); - /* Interrupts are a bit different for our DMA controller: While - * it's got one a regular PCI device header, the interrupt there - * is really the base of the range it's using. Each tx and rx - * channel has it's own interrupt source. - */ - - base_irq = virq_to_hw(mac->dma_pdev->irq); + snprintf(mac->tx_irq_name, sizeof(mac->tx_irq_name), "%s tx", + dev->name); - mac->tx_irq = irq_create_mapping(NULL, base_irq + mac->dma_txch); - mac->rx_irq = irq_create_mapping(NULL, base_irq + 20 + mac->dma_txch); - - ret = request_irq(mac->tx_irq, &pasemi_mac_tx_intr, IRQF_DISABLED, - mac->tx->irq_name, dev); + ret = request_irq(mac->tx->chan.irq, &pasemi_mac_tx_intr, IRQF_DISABLED, + mac->tx_irq_name, mac->tx); if (ret) { dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", - base_irq + mac->dma_txch, ret); + mac->tx->chan.irq, ret); goto out_tx_int; } - ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED, - mac->rx->irq_name, dev); + snprintf(mac->rx_irq_name, sizeof(mac->rx_irq_name), "%s rx", + dev->name); + + ret = request_irq(mac->rx->chan.irq, &pasemi_mac_rx_intr, IRQF_DISABLED, + mac->rx_irq_name, mac->rx); if (ret) { dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n", - base_irq + 20 + mac->dma_rxch, ret); + mac->rx->chan.irq, ret); goto out_rx_int; } if (mac->phydev) phy_start(mac->phydev); + init_timer(&mac->tx->clean_timer); + mac->tx->clean_timer.function = pasemi_mac_tx_timer; + mac->tx->clean_timer.data = (unsigned long)mac->tx; + mac->tx->clean_timer.expires = jiffies+HZ; + add_timer(&mac->tx->clean_timer); + return 0; out_rx_int: - free_irq(mac->tx_irq, dev); + free_irq(mac->tx->chan.irq, mac->tx); out_tx_int: napi_disable(&mac->napi); netif_stop_queue(dev); - pasemi_mac_free_tx_resources(dev); -out_tx_resources: - pasemi_mac_free_rx_resources(dev); +out_tx_ring: + if (mac->tx) + pasemi_mac_free_tx_resources(mac); + pasemi_mac_free_rx_resources(mac); out_rx_resources: return ret; @@ -1040,46 +1153,53 @@ static int pasemi_mac_close(struct net_device *dev) struct pasemi_mac *mac = netdev_priv(dev); unsigned int sta; int retries; + int rxch, txch; + + rxch = rx_ring(mac)->chan.chno; + txch = tx_ring(mac)->chan.chno; if (mac->phydev) { phy_stop(mac->phydev); phy_disconnect(mac->phydev); } + del_timer_sync(&mac->tx->clean_timer); + netif_stop_queue(dev); napi_disable(&mac->napi); - sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); if (sta & (PAS_DMA_RXINT_RCMDSTA_BP | PAS_DMA_RXINT_RCMDSTA_OO | PAS_DMA_RXINT_RCMDSTA_BT)) printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta); - sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch)); if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU | PAS_DMA_RXCHAN_CCMDSTA_OD | PAS_DMA_RXCHAN_CCMDSTA_FD | PAS_DMA_RXCHAN_CCMDSTA_DT)) printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta); - sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); - if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ | - PAS_DMA_TXCHAN_TCMDSTA_DB | - PAS_DMA_TXCHAN_TCMDSTA_DE | - PAS_DMA_TXCHAN_TCMDSTA_DA)) + sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch)); + if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ | PAS_DMA_TXCHAN_TCMDSTA_DB | + PAS_DMA_TXCHAN_TCMDSTA_DE | PAS_DMA_TXCHAN_TCMDSTA_DA)) printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta); /* Clean out any pending buffers */ - pasemi_mac_clean_tx(mac); - pasemi_mac_clean_rx(mac, RX_RING_SIZE); + pasemi_mac_clean_tx(tx_ring(mac)); + pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); /* Disable interface */ - write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST); - write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST); - write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST); + write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), + PAS_DMA_TXCHAN_TCMDSTA_ST); + write_dma_reg( PAS_DMA_RXINT_RCMDSTA(mac->dma_if), + PAS_DMA_RXINT_RCMDSTA_ST); + write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), + PAS_DMA_RXCHAN_CCMDSTA_ST); for (retries = 0; retries < MAX_RETRIES; retries++) { - sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch)); + sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(rxch)); if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)) break; cond_resched(); @@ -1089,7 +1209,7 @@ static int pasemi_mac_close(struct net_device *dev) dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch)); + sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch)); if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)) break; cond_resched(); @@ -1099,7 +1219,7 @@ static int pasemi_mac_close(struct net_device *dev) dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); for (retries = 0; retries < MAX_RETRIES; retries++) { - sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); + sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT)) break; cond_resched(); @@ -1112,16 +1232,16 @@ static int pasemi_mac_close(struct net_device *dev) * stopping, since you can't disable when active. */ - write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0); - write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0); - write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); + write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0); + write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0); + write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); - free_irq(mac->tx_irq, dev); - free_irq(mac->rx_irq, dev); + free_irq(mac->tx->chan.irq, mac->tx); + free_irq(mac->rx->chan.irq, mac->rx); /* Free resources */ - pasemi_mac_free_rx_resources(dev); - pasemi_mac_free_tx_resources(dev); + pasemi_mac_free_rx_resources(mac); + pasemi_mac_free_tx_resources(mac); return 0; } @@ -1135,6 +1255,7 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) unsigned int map_size[MAX_SKB_FRAGS+1]; unsigned long flags; int i, nfrags; + int fill; dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; @@ -1178,10 +1299,12 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) mactx = dflags | XCT_MACTX_LLEN(skb->len); - txring = mac->tx; + txring = tx_ring(mac); spin_lock_irqsave(&txring->lock, flags); + fill = txring->next_to_fill; + /* Avoid stepping on the same cache line that the DMA controller * is currently about to send, so leave at least 8 words available. * Total free space needed is mactx + fragments + 8 @@ -1192,13 +1315,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) goto out_err; } - TX_RING(mac, txring->next_to_fill) = mactx; - txring->next_to_fill++; - TX_RING_INFO(mac, txring->next_to_fill).skb = skb; + TX_DESC(txring, fill) = mactx; + TX_DESC_INFO(txring, fill).dma = nfrags; + fill++; + TX_DESC_INFO(txring, fill).skb = skb; for (i = 0; i <= nfrags; i++) { - TX_RING(mac, txring->next_to_fill+i) = - XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); - TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i]; + TX_DESC(txring, fill+i) = + XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); + TX_DESC_INFO(txring, fill+i).dma = map[i]; } /* We have to add an even number of 8-byte entries to the ring @@ -1208,15 +1332,14 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) if (nfrags & 1) nfrags++; - txring->next_to_fill = (txring->next_to_fill + nfrags + 1) & - (TX_RING_SIZE-1); + txring->next_to_fill = (fill + nfrags + 1) & (TX_RING_SIZE-1); dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; spin_unlock_irqrestore(&txring->lock, flags); - write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1); + write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), (nfrags+2) >> 1); return NETDEV_TX_OK; @@ -1232,7 +1355,7 @@ out_err_nolock: static void pasemi_mac_set_rx_mode(struct net_device *dev) { - struct pasemi_mac *mac = netdev_priv(dev); + const struct pasemi_mac *mac = netdev_priv(dev); unsigned int flags; flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); @@ -1253,88 +1376,21 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) struct net_device *dev = mac->netdev; int pkts; - pasemi_mac_clean_tx(mac); - pkts = pasemi_mac_clean_rx(mac, budget); + pasemi_mac_clean_tx(tx_ring(mac)); + pkts = pasemi_mac_clean_rx(rx_ring(mac), budget); if (pkts < budget) { /* all done, no more packets present */ netif_rx_complete(dev, napi); pasemi_mac_restart_rx_intr(mac); + pasemi_mac_restart_tx_intr(mac); } return pkts; } -static void __iomem * __devinit map_onedev(struct pci_dev *p, int index) -{ - struct device_node *dn; - void __iomem *ret; - - dn = pci_device_to_OF_node(p); - if (!dn) - goto fallback; - - ret = of_iomap(dn, index); - if (!ret) - goto fallback; - - return ret; -fallback: - /* This is hardcoded and ugly, but we have some firmware versions - * that don't provide the register space in the device tree. Luckily - * they are at well-known locations so we can just do the math here. - */ - return ioremap(0xe0000000 + (p->devfn << 12), 0x2000); -} - -static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac) -{ - struct resource res; - struct device_node *dn; - int err; - - mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); - if (!mac->dma_pdev) { - dev_err(&mac->pdev->dev, "Can't find DMA Controller\n"); - return -ENODEV; - } - - mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); - if (!mac->iob_pdev) { - dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n"); - return -ENODEV; - } - - mac->regs = map_onedev(mac->pdev, 0); - mac->dma_regs = map_onedev(mac->dma_pdev, 0); - mac->iob_regs = map_onedev(mac->iob_pdev, 0); - - if (!mac->regs || !mac->dma_regs || !mac->iob_regs) { - dev_err(&mac->pdev->dev, "Can't map registers\n"); - return -ENODEV; - } - - /* The dma status structure is located in the I/O bridge, and - * is cache coherent. - */ - if (!dma_status) { - dn = pci_device_to_OF_node(mac->iob_pdev); - if (dn) - err = of_address_to_resource(dn, 1, &res); - if (!dn || err) { - /* Fallback for old firmware */ - res.start = 0xfd800000; - res.end = res.start + 0x1000; - } - dma_status = __ioremap(res.start, res.end-res.start, 0); - } - - return 0; -} - static int __devinit pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int index = 0; struct net_device *dev; struct pasemi_mac *mac; int err; @@ -1362,20 +1418,46 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); - dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG; + dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG | + NETIF_F_HIGHDMA; - /* These should come out of the device tree eventually */ - mac->dma_txch = index; - mac->dma_rxch = index; + mac->lro_mgr.max_aggr = LRO_MAX_AGGR; + mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; + mac->lro_mgr.lro_arr = mac->lro_desc; + mac->lro_mgr.get_skb_header = get_skb_hdr; + mac->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + mac->lro_mgr.dev = mac->netdev; + mac->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + mac->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; - /* We probe GMAC before XAUI, but the DMA interfaces are - * in XAUI, GMAC order. - */ - if (index < 4) - mac->dma_if = index + 2; - else - mac->dma_if = index - 4; - index++; + + mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL); + if (!mac->dma_pdev) { + dev_err(&mac->pdev->dev, "Can't find DMA Controller\n"); + err = -ENODEV; + goto out; + } + + mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); + if (!mac->iob_pdev) { + dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n"); + err = -ENODEV; + goto out; + } + + /* get mac addr from device tree */ + if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) { + err = -ENODEV; + goto out; + } + memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr)); + + mac->dma_if = mac_to_intf(mac); + if (mac->dma_if < 0) { + dev_err(&mac->pdev->dev, "Can't map DMA interface\n"); + err = -ENODEV; + goto out; + } switch (pdev->device) { case 0xa005: @@ -1389,25 +1471,14 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out; } - /* get mac addr from device tree */ - if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) { - err = -ENODEV; - goto out; - } - memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr)); - dev->open = pasemi_mac_open; dev->stop = pasemi_mac_close; dev->hard_start_xmit = pasemi_mac_start_tx; dev->set_multicast_list = pasemi_mac_set_rx_mode; - err = pasemi_mac_map_regs(mac); if (err) goto out; - mac->rx_status = &dma_status->rx_sta[mac->dma_rxch]; - mac->tx_status = &dma_status->tx_sta[mac->dma_txch]; - mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE); /* Enable most messages by default */ @@ -1420,11 +1491,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err); goto out; } else if netif_msg_probe(mac) - printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, " - "hw addr %s\n", + printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %s\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", - mac->dma_if, mac->dma_txch, mac->dma_rxch, - print_mac(mac_buf, dev->dev_addr)); + mac->dma_if, print_mac(mac_buf, dev->dev_addr)); return err; @@ -1433,12 +1502,6 @@ out: pci_dev_put(mac->iob_pdev); if (mac->dma_pdev) pci_dev_put(mac->dma_pdev); - if (mac->dma_regs) - iounmap(mac->dma_regs); - if (mac->iob_regs) - iounmap(mac->iob_regs); - if (mac->regs) - iounmap(mac->regs); free_netdev(dev); out_disable_device: @@ -1463,9 +1526,8 @@ static void __devexit pasemi_mac_remove(struct pci_dev *pdev) pci_dev_put(mac->dma_pdev); pci_dev_put(mac->iob_pdev); - iounmap(mac->regs); - iounmap(mac->dma_regs); - iounmap(mac->iob_regs); + pasemi_dma_free_chan(&mac->tx->chan); + pasemi_dma_free_chan(&mac->rx->chan); pci_set_drvdata(pdev, NULL); free_netdev(netdev); @@ -1489,12 +1551,16 @@ static struct pci_driver pasemi_mac_driver = { static void __exit pasemi_mac_cleanup_module(void) { pci_unregister_driver(&pasemi_mac_driver); - __iounmap(dma_status); - dma_status = NULL; } int pasemi_mac_init_module(void) { + int err; + + err = pasemi_dma_init(); + if (err) + return err; + return pci_register_driver(&pasemi_mac_driver); } diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 60368df72634..8bee2a664c83 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h @@ -26,60 +26,55 @@ #include <linux/spinlock.h> #include <linux/phy.h> +#define MAX_LRO_DESCRIPTORS 8 + struct pasemi_mac_txring { + struct pasemi_dmachan chan; /* Must be first */ spinlock_t lock; - u64 *ring; - dma_addr_t dma; unsigned int size; unsigned int next_to_fill; unsigned int next_to_clean; struct pasemi_mac_buffer *ring_info; - char irq_name[10]; /* "eth%d tx" */ + struct pasemi_mac *mac; /* Needed in intr handler */ + struct timer_list clean_timer; }; struct pasemi_mac_rxring { + struct pasemi_dmachan chan; /* Must be first */ spinlock_t lock; - u64 *ring; /* RX channel descriptor ring */ - dma_addr_t dma; u64 *buffers; /* RX interface buffer ring */ dma_addr_t buf_dma; unsigned int size; unsigned int next_to_fill; unsigned int next_to_clean; struct pasemi_mac_buffer *ring_info; - char irq_name[10]; /* "eth%d rx" */ + struct pasemi_mac *mac; /* Needed in intr handler */ }; struct pasemi_mac { struct net_device *netdev; - void __iomem *regs; - void __iomem *dma_regs; - void __iomem *iob_regs; struct pci_dev *pdev; struct pci_dev *dma_pdev; struct pci_dev *iob_pdev; struct phy_device *phydev; struct napi_struct napi; - /* Pointer to the cacheable per-channel status registers */ - u64 *rx_status; - u64 *tx_status; - u8 type; #define MAC_TYPE_GMAC 1 #define MAC_TYPE_XAUI 2 - u32 dma_txch; u32 dma_if; - u32 dma_rxch; u8 mac_addr[6]; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS]; struct timer_list rxtimer; + unsigned int lro_max_aggr; struct pasemi_mac_txring *tx; struct pasemi_mac_rxring *rx; - unsigned long tx_irq; - unsigned long rx_irq; + char tx_irq_name[10]; /* "eth%d tx" */ + char rx_irq_name[10]; /* "eth%d rx" */ int link; int speed; int duplex; @@ -95,11 +90,8 @@ struct pasemi_mac_buffer { }; -/* status register layout in IOB region, at 0xfb800000 */ -struct pasdma_status { - u64 rx_sta[64]; - u64 tx_sta[20]; -}; +/* PCI register offsets and formats */ + /* MAC CFG register offsets */ enum { @@ -173,333 +165,4 @@ enum { #define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \ PAS_MAC_IPC_CHNL_BCH_M) -/* All these registers live in the PCI configuration space for the DMA PCI - * device. Use the normal PCI config access functions for them. - */ -enum { - PAS_DMA_COM_TXCMD = 0x100, /* Transmit Command Register */ - PAS_DMA_COM_TXSTA = 0x104, /* Transmit Status Register */ - PAS_DMA_COM_RXCMD = 0x108, /* Receive Command Register */ - PAS_DMA_COM_RXSTA = 0x10c, /* Receive Status Register */ -}; -#define PAS_DMA_COM_TXCMD_EN 0x00000001 /* enable */ -#define PAS_DMA_COM_TXSTA_ACT 0x00000001 /* active */ -#define PAS_DMA_COM_RXCMD_EN 0x00000001 /* enable */ -#define PAS_DMA_COM_RXSTA_ACT 0x00000001 /* active */ - - -/* Per-interface and per-channel registers */ -#define _PAS_DMA_RXINT_STRIDE 0x20 -#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE) -#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001 -#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002 -#define PAS_DMA_RXINT_RCMDSTA_MBT 0x00000008 -#define PAS_DMA_RXINT_RCMDSTA_MDR 0x00000010 -#define PAS_DMA_RXINT_RCMDSTA_MOO 0x00000020 -#define PAS_DMA_RXINT_RCMDSTA_MBP 0x00000040 -#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800 -#define PAS_DMA_RXINT_RCMDSTA_DR 0x00001000 -#define PAS_DMA_RXINT_RCMDSTA_OO 0x00002000 -#define PAS_DMA_RXINT_RCMDSTA_BP 0x00004000 -#define PAS_DMA_RXINT_RCMDSTA_TB 0x00008000 -#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000 -#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000 -#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17 -#define PAS_DMA_RXINT_CFG(i) (0x204+(i)*_PAS_DMA_RXINT_STRIDE) -#define PAS_DMA_RXINT_CFG_RBP 0x80000000 -#define PAS_DMA_RXINT_CFG_ITRR 0x40000000 -#define PAS_DMA_RXINT_CFG_DHL_M 0x07000000 -#define PAS_DMA_RXINT_CFG_DHL_S 24 -#define PAS_DMA_RXINT_CFG_DHL(x) (((x) << PAS_DMA_RXINT_CFG_DHL_S) & \ - PAS_DMA_RXINT_CFG_DHL_M) -#define PAS_DMA_RXINT_CFG_ITR 0x00400000 -#define PAS_DMA_RXINT_CFG_LW 0x00200000 -#define PAS_DMA_RXINT_CFG_L2 0x00100000 -#define PAS_DMA_RXINT_CFG_HEN 0x00080000 -#define PAS_DMA_RXINT_CFG_WIF 0x00000002 -#define PAS_DMA_RXINT_CFG_WIL 0x00000001 - -#define PAS_DMA_RXINT_INCR(i) (0x210+(i)*_PAS_DMA_RXINT_STRIDE) -#define PAS_DMA_RXINT_INCR_INCR_M 0x0000ffff -#define PAS_DMA_RXINT_INCR_INCR_S 0 -#define PAS_DMA_RXINT_INCR_INCR(x) ((x) & 0x0000ffff) -#define PAS_DMA_RXINT_BASEL(i) (0x218+(i)*_PAS_DMA_RXINT_STRIDE) -#define PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f) -#define PAS_DMA_RXINT_BASEU(i) (0x21c+(i)*_PAS_DMA_RXINT_STRIDE) -#define PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff) -#define PAS_DMA_RXINT_BASEU_SIZ_M 0x3fff0000 /* # of cache lines worth of buffer ring */ -#define PAS_DMA_RXINT_BASEU_SIZ_S 16 /* 0 = 16K */ -#define PAS_DMA_RXINT_BASEU_SIZ(x) (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \ - PAS_DMA_RXINT_BASEU_SIZ_M) - - -#define _PAS_DMA_TXCHAN_STRIDE 0x20 /* Size per channel */ -#define _PAS_DMA_TXCHAN_TCMDSTA 0x300 /* Command / Status */ -#define _PAS_DMA_TXCHAN_CFG 0x304 /* Configuration */ -#define _PAS_DMA_TXCHAN_DSCRBU 0x308 /* Descriptor BU Allocation */ -#define _PAS_DMA_TXCHAN_INCR 0x310 /* Descriptor increment */ -#define _PAS_DMA_TXCHAN_CNT 0x314 /* Descriptor count/offset */ -#define _PAS_DMA_TXCHAN_BASEL 0x318 /* Descriptor ring base (low) */ -#define _PAS_DMA_TXCHAN_BASEU 0x31c /* (high) */ -#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE) -#define PAS_DMA_TXCHAN_TCMDSTA_EN 0x00000001 /* Enabled */ -#define PAS_DMA_TXCHAN_TCMDSTA_ST 0x00000002 /* Stop interface */ -#define PAS_DMA_TXCHAN_TCMDSTA_ACT 0x00010000 /* Active */ -#define PAS_DMA_TXCHAN_TCMDSTA_SZ 0x00000800 -#define PAS_DMA_TXCHAN_TCMDSTA_DB 0x00000400 -#define PAS_DMA_TXCHAN_TCMDSTA_DE 0x00000200 -#define PAS_DMA_TXCHAN_TCMDSTA_DA 0x00000100 -#define PAS_DMA_TXCHAN_CFG(c) (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE) -#define PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000 /* Type = interface */ -#define PAS_DMA_TXCHAN_CFG_TATTR_M 0x0000003c -#define PAS_DMA_TXCHAN_CFG_TATTR_S 2 -#define PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \ - PAS_DMA_TXCHAN_CFG_TATTR_M) -#define PAS_DMA_TXCHAN_CFG_WT_M 0x000001c0 -#define PAS_DMA_TXCHAN_CFG_WT_S 6 -#define PAS_DMA_TXCHAN_CFG_WT(x) (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \ - PAS_DMA_TXCHAN_CFG_WT_M) -#define PAS_DMA_TXCHAN_CFG_TRD 0x00010000 /* translate data */ -#define PAS_DMA_TXCHAN_CFG_TRR 0x00008000 /* translate rings */ -#define PAS_DMA_TXCHAN_CFG_UP 0x00004000 /* update tx descr when sent */ -#define PAS_DMA_TXCHAN_CFG_CL 0x00002000 /* Clean last line */ -#define PAS_DMA_TXCHAN_CFG_CF 0x00001000 /* Clean first line */ -#define PAS_DMA_TXCHAN_INCR(c) (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE) -#define PAS_DMA_TXCHAN_BASEL(c) (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE) -#define PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0 -#define PAS_DMA_TXCHAN_BASEL_BRBL_S 0 -#define PAS_DMA_TXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \ - PAS_DMA_TXCHAN_BASEL_BRBL_M) -#define PAS_DMA_TXCHAN_BASEU(c) (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE) -#define PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff -#define PAS_DMA_TXCHAN_BASEU_BRBH_S 0 -#define PAS_DMA_TXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \ - PAS_DMA_TXCHAN_BASEU_BRBH_M) -/* # of cache lines worth of buffer ring */ -#define PAS_DMA_TXCHAN_BASEU_SIZ_M 0x3fff0000 -#define PAS_DMA_TXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ -#define PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \ - PAS_DMA_TXCHAN_BASEU_SIZ_M) - -#define _PAS_DMA_RXCHAN_STRIDE 0x20 /* Size per channel */ -#define _PAS_DMA_RXCHAN_CCMDSTA 0x800 /* Command / Status */ -#define _PAS_DMA_RXCHAN_CFG 0x804 /* Configuration */ -#define _PAS_DMA_RXCHAN_INCR 0x810 /* Descriptor increment */ -#define _PAS_DMA_RXCHAN_CNT 0x814 /* Descriptor count/offset */ -#define _PAS_DMA_RXCHAN_BASEL 0x818 /* Descriptor ring base (low) */ -#define _PAS_DMA_RXCHAN_BASEU 0x81c /* (high) */ -#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE) -#define PAS_DMA_RXCHAN_CCMDSTA_EN 0x00000001 /* Enabled */ -#define PAS_DMA_RXCHAN_CCMDSTA_ST 0x00000002 /* Stop interface */ -#define PAS_DMA_RXCHAN_CCMDSTA_ACT 0x00010000 /* Active */ -#define PAS_DMA_RXCHAN_CCMDSTA_DU 0x00020000 -#define PAS_DMA_RXCHAN_CCMDSTA_OD 0x00002000 -#define PAS_DMA_RXCHAN_CCMDSTA_FD 0x00001000 -#define PAS_DMA_RXCHAN_CCMDSTA_DT 0x00000800 -#define PAS_DMA_RXCHAN_CFG(c) (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE) -#define PAS_DMA_RXCHAN_CFG_CTR 0x00000400 -#define PAS_DMA_RXCHAN_CFG_HBU_M 0x00000380 -#define PAS_DMA_RXCHAN_CFG_HBU_S 7 -#define PAS_DMA_RXCHAN_CFG_HBU(x) (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \ - PAS_DMA_RXCHAN_CFG_HBU_M) -#define PAS_DMA_RXCHAN_INCR(c) (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE) -#define PAS_DMA_RXCHAN_BASEL(c) (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE) -#define PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0 -#define PAS_DMA_RXCHAN_BASEL_BRBL_S 0 -#define PAS_DMA_RXCHAN_BASEL_BRBL(x) (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \ - PAS_DMA_RXCHAN_BASEL_BRBL_M) -#define PAS_DMA_RXCHAN_BASEU(c) (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE) -#define PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff -#define PAS_DMA_RXCHAN_BASEU_BRBH_S 0 -#define PAS_DMA_RXCHAN_BASEU_BRBH(x) (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \ - PAS_DMA_RXCHAN_BASEU_BRBH_M) -/* # of cache lines worth of buffer ring */ -#define PAS_DMA_RXCHAN_BASEU_SIZ_M 0x3fff0000 -#define PAS_DMA_RXCHAN_BASEU_SIZ_S 16 /* 0 = 16K */ -#define PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \ - PAS_DMA_RXCHAN_BASEU_SIZ_M) - -#define PAS_STATUS_PCNT_M 0x000000000000ffffull -#define PAS_STATUS_PCNT_S 0 -#define PAS_STATUS_DCNT_M 0x00000000ffff0000ull -#define PAS_STATUS_DCNT_S 16 -#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull -#define PAS_STATUS_BPCNT_S 32 -#define PAS_STATUS_CAUSE_M 0xf000000000000000ull -#define PAS_STATUS_TIMER 0x1000000000000000ull -#define PAS_STATUS_ERROR 0x2000000000000000ull -#define PAS_STATUS_SOFT 0x4000000000000000ull -#define PAS_STATUS_INT 0x8000000000000000ull - -#define PAS_IOB_COM_PKTHDRCNT 0x120 -#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M 0x0fff0000 -#define PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S 16 -#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M 0x00000fff -#define PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S 0 - -#define PAS_IOB_DMA_RXCH_CFG(i) (0x1100 + (i)*4) -#define PAS_IOB_DMA_RXCH_CFG_CNTTH_M 0x00000fff -#define PAS_IOB_DMA_RXCH_CFG_CNTTH_S 0 -#define PAS_IOB_DMA_RXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \ - PAS_IOB_DMA_RXCH_CFG_CNTTH_M) -#define PAS_IOB_DMA_TXCH_CFG(i) (0x1200 + (i)*4) -#define PAS_IOB_DMA_TXCH_CFG_CNTTH_M 0x00000fff -#define PAS_IOB_DMA_TXCH_CFG_CNTTH_S 0 -#define PAS_IOB_DMA_TXCH_CFG_CNTTH(x) (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \ - PAS_IOB_DMA_TXCH_CFG_CNTTH_M) -#define PAS_IOB_DMA_RXCH_STAT(i) (0x1300 + (i)*4) -#define PAS_IOB_DMA_RXCH_STAT_INTGEN 0x00001000 -#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_M 0x00000fff -#define PAS_IOB_DMA_RXCH_STAT_CNTDEL_S 0 -#define PAS_IOB_DMA_RXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\ - PAS_IOB_DMA_RXCH_STAT_CNTDEL_M) -#define PAS_IOB_DMA_TXCH_STAT(i) (0x1400 + (i)*4) -#define PAS_IOB_DMA_TXCH_STAT_INTGEN 0x00001000 -#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_M 0x00000fff -#define PAS_IOB_DMA_TXCH_STAT_CNTDEL_S 0 -#define PAS_IOB_DMA_TXCH_STAT_CNTDEL(x) (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\ - PAS_IOB_DMA_TXCH_STAT_CNTDEL_M) -#define PAS_IOB_DMA_RXCH_RESET(i) (0x1500 + (i)*4) -#define PAS_IOB_DMA_RXCH_RESET_PCNT_M 0xffff0000 -#define PAS_IOB_DMA_RXCH_RESET_PCNT_S 16 -#define PAS_IOB_DMA_RXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \ - PAS_IOB_DMA_RXCH_RESET_PCNT_M) -#define PAS_IOB_DMA_RXCH_RESET_PCNTRST 0x00000020 -#define PAS_IOB_DMA_RXCH_RESET_DCNTRST 0x00000010 -#define PAS_IOB_DMA_RXCH_RESET_TINTC 0x00000008 -#define PAS_IOB_DMA_RXCH_RESET_DINTC 0x00000004 -#define PAS_IOB_DMA_RXCH_RESET_SINTC 0x00000002 -#define PAS_IOB_DMA_RXCH_RESET_PINTC 0x00000001 -#define PAS_IOB_DMA_TXCH_RESET(i) (0x1600 + (i)*4) -#define PAS_IOB_DMA_TXCH_RESET_PCNT_M 0xffff0000 -#define PAS_IOB_DMA_TXCH_RESET_PCNT_S 16 -#define PAS_IOB_DMA_TXCH_RESET_PCNT(x) (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \ - PAS_IOB_DMA_TXCH_RESET_PCNT_M) -#define PAS_IOB_DMA_TXCH_RESET_PCNTRST 0x00000020 -#define PAS_IOB_DMA_TXCH_RESET_DCNTRST 0x00000010 -#define PAS_IOB_DMA_TXCH_RESET_TINTC 0x00000008 -#define PAS_IOB_DMA_TXCH_RESET_DINTC 0x00000004 -#define PAS_IOB_DMA_TXCH_RESET_SINTC 0x00000002 -#define PAS_IOB_DMA_TXCH_RESET_PINTC 0x00000001 - -#define PAS_IOB_DMA_COM_TIMEOUTCFG 0x1700 -#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M 0x00ffffff -#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S 0 -#define PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x) (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \ - PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M) - -/* Transmit descriptor fields */ -#define XCT_MACTX_T 0x8000000000000000ull -#define XCT_MACTX_ST 0x4000000000000000ull -#define XCT_MACTX_NORES 0x0000000000000000ull -#define XCT_MACTX_8BRES 0x1000000000000000ull -#define XCT_MACTX_24BRES 0x2000000000000000ull -#define XCT_MACTX_40BRES 0x3000000000000000ull -#define XCT_MACTX_I 0x0800000000000000ull -#define XCT_MACTX_O 0x0400000000000000ull -#define XCT_MACTX_E 0x0200000000000000ull -#define XCT_MACTX_VLAN_M 0x0180000000000000ull -#define XCT_MACTX_VLAN_NOP 0x0000000000000000ull -#define XCT_MACTX_VLAN_REMOVE 0x0080000000000000ull -#define XCT_MACTX_VLAN_INSERT 0x0100000000000000ull -#define XCT_MACTX_VLAN_REPLACE 0x0180000000000000ull -#define XCT_MACTX_CRC_M 0x0060000000000000ull -#define XCT_MACTX_CRC_NOP 0x0000000000000000ull -#define XCT_MACTX_CRC_INSERT 0x0020000000000000ull -#define XCT_MACTX_CRC_PAD 0x0040000000000000ull -#define XCT_MACTX_CRC_REPLACE 0x0060000000000000ull -#define XCT_MACTX_SS 0x0010000000000000ull -#define XCT_MACTX_LLEN_M 0x00007fff00000000ull -#define XCT_MACTX_LLEN_S 32ull -#define XCT_MACTX_LLEN(x) ((((long)(x)) << XCT_MACTX_LLEN_S) & \ - XCT_MACTX_LLEN_M) -#define XCT_MACTX_IPH_M 0x00000000f8000000ull -#define XCT_MACTX_IPH_S 27ull -#define XCT_MACTX_IPH(x) ((((long)(x)) << XCT_MACTX_IPH_S) & \ - XCT_MACTX_IPH_M) -#define XCT_MACTX_IPO_M 0x0000000007c00000ull -#define XCT_MACTX_IPO_S 22ull -#define XCT_MACTX_IPO(x) ((((long)(x)) << XCT_MACTX_IPO_S) & \ - XCT_MACTX_IPO_M) -#define XCT_MACTX_CSUM_M 0x0000000000000060ull -#define XCT_MACTX_CSUM_NOP 0x0000000000000000ull -#define XCT_MACTX_CSUM_TCP 0x0000000000000040ull -#define XCT_MACTX_CSUM_UDP 0x0000000000000060ull -#define XCT_MACTX_V6 0x0000000000000010ull -#define XCT_MACTX_C 0x0000000000000004ull -#define XCT_MACTX_AL2 0x0000000000000002ull - -/* Receive descriptor fields */ -#define XCT_MACRX_T 0x8000000000000000ull -#define XCT_MACRX_ST 0x4000000000000000ull -#define XCT_MACRX_RR_M 0x3000000000000000ull -#define XCT_MACRX_RR_NORES 0x0000000000000000ull -#define XCT_MACRX_RR_8BRES 0x1000000000000000ull -#define XCT_MACRX_O 0x0400000000000000ull -#define XCT_MACRX_E 0x0200000000000000ull -#define XCT_MACRX_FF 0x0100000000000000ull -#define XCT_MACRX_PF 0x0080000000000000ull -#define XCT_MACRX_OB 0x0040000000000000ull -#define XCT_MACRX_OD 0x0020000000000000ull -#define XCT_MACRX_FS 0x0010000000000000ull -#define XCT_MACRX_NB_M 0x000fc00000000000ull -#define XCT_MACRX_NB_S 46ULL -#define XCT_MACRX_NB(x) ((((long)(x)) << XCT_MACRX_NB_S) & \ - XCT_MACRX_NB_M) -#define XCT_MACRX_LLEN_M 0x00003fff00000000ull -#define XCT_MACRX_LLEN_S 32ULL -#define XCT_MACRX_LLEN(x) ((((long)(x)) << XCT_MACRX_LLEN_S) & \ - XCT_MACRX_LLEN_M) -#define XCT_MACRX_CRC 0x0000000080000000ull -#define XCT_MACRX_LEN_M 0x0000000060000000ull -#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull -#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull -#define XCT_MACRX_LEN_TRUNC 0x0000000060000000ull -#define XCT_MACRX_CAST_M 0x0000000018000000ull -#define XCT_MACRX_CAST_UNI 0x0000000000000000ull -#define XCT_MACRX_CAST_MULTI 0x0000000008000000ull -#define XCT_MACRX_CAST_BROAD 0x0000000010000000ull -#define XCT_MACRX_CAST_PAUSE 0x0000000018000000ull -#define XCT_MACRX_VLC_M 0x0000000006000000ull -#define XCT_MACRX_FM 0x0000000001000000ull -#define XCT_MACRX_HTY_M 0x0000000000c00000ull -#define XCT_MACRX_HTY_IPV4_OK 0x0000000000000000ull -#define XCT_MACRX_HTY_IPV6 0x0000000000400000ull -#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull -#define XCT_MACRX_HTY_NONIP 0x0000000000c00000ull -#define XCT_MACRX_IPP_M 0x00000000003f0000ull -#define XCT_MACRX_IPP_S 16 -#define XCT_MACRX_CSUM_M 0x000000000000ffffull -#define XCT_MACRX_CSUM_S 0 - -#define XCT_PTR_T 0x8000000000000000ull -#define XCT_PTR_LEN_M 0x7ffff00000000000ull -#define XCT_PTR_LEN_S 44 -#define XCT_PTR_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & \ - XCT_PTR_LEN_M) -#define XCT_PTR_ADDR_M 0x00000fffffffffffull -#define XCT_PTR_ADDR_S 0 -#define XCT_PTR_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & \ - XCT_PTR_ADDR_M) - -/* Receive interface 8byte result fields */ -#define XCT_RXRES_8B_L4O_M 0xff00000000000000ull -#define XCT_RXRES_8B_L4O_S 56 -#define XCT_RXRES_8B_RULE_M 0x00ffff0000000000ull -#define XCT_RXRES_8B_RULE_S 40 -#define XCT_RXRES_8B_EVAL_M 0x000000ffff000000ull -#define XCT_RXRES_8B_EVAL_S 24 -#define XCT_RXRES_8B_HTYPE_M 0x0000000000f00000ull -#define XCT_RXRES_8B_HASH_M 0x00000000000fffffull -#define XCT_RXRES_8B_HASH_S 0 - -/* Receive interface buffer fields */ -#define XCT_RXB_LEN_M 0x0ffff00000000000ull -#define XCT_RXB_LEN_S 44 -#define XCT_RXB_LEN(x) ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M) -#define XCT_RXB_ADDR_M 0x00000fffffffffffull -#define XCT_RXB_ADDR_S 0 -#define XCT_RXB_ADDR(x) ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M) - - #endif /* PASEMI_MAC_H */ diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 8d910a372f89..6d342f6c14f6 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1040,15 +1040,13 @@ void ei_tx_timeout(struct net_device *dev) /* Ugly but a reset can be slow, yet must be protected */ - disable_irq_nosync(dev->irq); - spin_lock(&ei_local->page_lock); + spin_lock_irqsave(&ei_local->page_lock, flags); /* Try to restart the card. Perhaps the user has fixed something. */ ei_reset_8390(dev); AX88190_init(dev, 1); - spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); + spin_unlock_irqrestore(&ei_local->page_lock, flags); netif_wake_queue(dev); } @@ -1085,9 +1083,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) * Slow phase with lock held. */ - disable_irq_nosync(dev->irq); - - spin_lock(&ei_local->page_lock); + spin_lock_irqsave(&ei_local->page_lock, flags); ei_local->irqlock = 1; @@ -1125,8 +1121,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) ei_local->irqlock = 0; netif_stop_queue(dev); outb_p(ENISR_ALL, e8390_base + EN0_IMR); - spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); + spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->stat.tx_errors++; return 1; } @@ -1172,8 +1167,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); - spin_unlock(&ei_local->page_lock); - enable_irq(dev->irq); + spin_unlock_irqrestore(&ei_local->page_lock, flags); dev_kfree_skb (skb); ei_local->stat.tx_bytes += send_length; diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 8c719b4df544..949c6df74c97 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -731,18 +731,13 @@ module_exit(exit_fmvj18x_cs); /*====================================================================*/ -static irqreturn_t fjn_interrupt(int irq, void *dev_id) +static irqreturn_t fjn_interrupt(int dummy, void *dev_id) { struct net_device *dev = dev_id; local_info_t *lp = netdev_priv(dev); kio_addr_t ioaddr; unsigned short tx_stat, rx_stat; - if (lp == NULL) { - printk(KERN_NOTICE "fjn_interrupt(): irq %d for " - "unknown device.\n", irq); - return IRQ_NONE; - } ioaddr = dev->base_addr; /* avoid multiple interrupts */ diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 51bbd582f16c..9ba56aa26a1b 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -38,6 +38,7 @@ #include <linux/delay.h> #include <linux/ethtool.h> #include <linux/netdevice.h> +#include <linux/log2.h> #include "../8390.h" #include <pcmcia/cs_types.h> @@ -1484,8 +1485,7 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg, window_size = 32 * 1024; /* Make sure it's a power of two. */ - while ((window_size & (window_size - 1)) != 0) - window_size += window_size & ~(window_size - 1); + window_size = roundup_pow_of_two(window_size); /* Allocate a memory window */ req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 90498ffe26f2..c4b74e9fed20 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -137,7 +137,7 @@ static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { "Loopback test (offline)" }; -#define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) +#define PCNET32_TEST_LEN ARRAY_SIZE(pcnet32_gstrings_test) #define PCNET32_NUM_REGS 136 diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 57c98669984d..fee3d7b1feba 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -106,6 +106,7 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n" #include <linux/if_plip.h> #include <linux/workqueue.h> #include <linux/spinlock.h> +#include <linux/completion.h> #include <linux/parport.h> #include <linux/bitops.h> @@ -114,7 +115,6 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n" #include <asm/system.h> #include <asm/irq.h> #include <asm/byteorder.h> -#include <asm/semaphore.h> /* Maximum number of devices to support. */ #define PLIP_MAX 8 @@ -221,7 +221,7 @@ struct net_local { int should_relinquish; spinlock_t lock; atomic_t kill_timer; - struct semaphore killed_timer_sem; + struct completion killed_timer_cmp; }; static inline void enable_parport_interrupts (struct net_device *dev) @@ -385,7 +385,7 @@ plip_timer_bh(struct work_struct *work) schedule_delayed_work(&nl->timer, 1); } else { - up (&nl->killed_timer_sem); + complete(&nl->killed_timer_cmp); } } @@ -1112,9 +1112,9 @@ plip_close(struct net_device *dev) if (dev->irq == -1) { - init_MUTEX_LOCKED (&nl->killed_timer_sem); + init_completion(&nl->killed_timer_cmp); atomic_set (&nl->kill_timer, 1); - down (&nl->killed_timer_sem); + wait_for_completion(&nl->killed_timer_cmp); } #ifdef NOTDEF diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index eb98b661efba..034c1c650bcb 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -206,7 +206,7 @@ static void z_comp_reset(void *arg) * Returns the length of the compressed packet, or 0 if the * packet is incompressible. */ -int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, +static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, int isize, int osize) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -435,7 +435,7 @@ static void z_decomp_reset(void *arg) * bug, so we return DECOMP_FATALERROR for them in order to turn off * compression, even though they are detected by inspecting the input. */ -int z_decompress(void *arg, unsigned char *ibuf, int isize, +static int z_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf, int osize) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 4f690378bb77..4dc5b4b7a561 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1871,7 +1871,7 @@ ppp_mp_insert(struct ppp *ppp, struct sk_buff *skb) * complete packet, or we get to the sequence number for a fragment * which hasn't arrived but might still do so. */ -struct sk_buff * +static struct sk_buff * ppp_mp_reconstruct(struct ppp *ppp) { u32 seq = ppp->nextseq; diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index f0c6a1926a02..0d80fa546719 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -42,9 +42,9 @@ #include <linux/if_ppp.h> #include <linux/ppp_channel.h> #include <linux/spinlock.h> +#include <linux/completion.h> #include <linux/init.h> #include <asm/uaccess.h> -#include <asm/semaphore.h> #define PPP_VERSION "2.4.2" @@ -70,7 +70,7 @@ struct syncppp { struct tasklet_struct tsk; atomic_t refcnt; - struct semaphore dead_sem; + struct completion dead_cmp; struct ppp_channel chan; /* interface to generic ppp layer */ }; @@ -195,7 +195,7 @@ static struct syncppp *sp_get(struct tty_struct *tty) static void sp_put(struct syncppp *ap) { if (atomic_dec_and_test(&ap->refcnt)) - up(&ap->dead_sem); + complete(&ap->dead_cmp); } /* @@ -225,7 +225,7 @@ ppp_sync_open(struct tty_struct *tty) tasklet_init(&ap->tsk, ppp_sync_process, (unsigned long) ap); atomic_set(&ap->refcnt, 1); - init_MUTEX_LOCKED(&ap->dead_sem); + init_completion(&ap->dead_cmp); ap->chan.private = ap; ap->chan.ops = &sync_ops; @@ -273,7 +273,7 @@ ppp_sync_close(struct tty_struct *tty) * by the time it returns. */ if (!atomic_dec_and_test(&ap->refcnt)) - down(&ap->dead_sem); + wait_for_completion(&ap->dead_cmp); tasklet_kill(&ap->tsk); ppp_unregister_channel(&ap->chan); @@ -560,7 +560,7 @@ static void ppp_sync_process(unsigned long arg) * Procedures for encapsulation and framing. */ -struct sk_buff* +static struct sk_buff* ppp_sync_txmunge(struct syncppp *ap, struct sk_buff *skb) { int proto; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index a005d8f4c38e..ac0ac98b19cd 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -989,6 +989,7 @@ out: } static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(pppoe_hash_lock) { loff_t l = *pos; @@ -1022,6 +1023,7 @@ out: } static void pppoe_seq_stop(struct seq_file *seq, void *v) + __releases(pppoe_hash_lock) { read_unlock_bh(&pppoe_hash_lock); } diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index a7556cd2df79..1b51bb668d39 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -2489,7 +2489,7 @@ static void __exit pppol2tp_exit(void) module_init(pppol2tp_init); module_exit(pppol2tp_exit); -MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>," +MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>, " "James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("PPP over L2TP over UDP"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index cf0774de6c41..a6aeb9d60443 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -540,20 +540,12 @@ static void eeprom_readword(struct ql3_adapter *qdev, fm93c56a_deselect(qdev); } -static void ql_swap_mac_addr(u8 * macAddress) -{ -#ifdef __BIG_ENDIAN - u8 temp; - temp = macAddress[0]; - macAddress[0] = macAddress[1]; - macAddress[1] = temp; - temp = macAddress[2]; - macAddress[2] = macAddress[3]; - macAddress[3] = temp; - temp = macAddress[4]; - macAddress[4] = macAddress[5]; - macAddress[5] = temp; -#endif +static void ql_set_mac_addr(struct net_device *ndev, u16 *addr) +{ + __le16 *p = (__le16 *)ndev->dev_addr; + p[0] = cpu_to_le16(addr[0]); + p[1] = cpu_to_le16(addr[1]); + p[2] = cpu_to_le16(addr[2]); } static int ql_get_nvram_params(struct ql3_adapter *qdev) @@ -590,18 +582,6 @@ static int ql_get_nvram_params(struct ql3_adapter *qdev) return -1; } - /* - * We have a problem with endianness for the MAC addresses - * and the two 8-bit values version, and numPorts. We - * have to swap them on big endian systems. - */ - ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress); - ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress); - ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress); - ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress); - pEEPROMData = (u16 *) & qdev->nvram_data.version; - *pEEPROMData = le16_to_cpu(*pEEPROMData); - spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return checksum; } @@ -711,7 +691,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, if (ql_wait_for_mii_ready(qdev)) { if (netif_msg_link(qdev)) printk(KERN_WARNING PFX - "%s: Timed out waiting for management port to" + "%s: Timed out waiting for management port to " "get free before issuing command.\n", qdev->ndev->name); return -1; @@ -3035,7 +3015,7 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev) LS_64BITS(qdev->shadow_reg_phy_addr); qdev->prsp_producer_index = - (u32 *) (((u8 *) qdev->preq_consumer_index) + 8); + (__le32 *) (((u8 *) qdev->preq_consumer_index) + 8); qdev->rsp_producer_index_phy_addr_high = qdev->req_consumer_index_phy_addr_high; qdev->rsp_producer_index_phy_addr_low = @@ -3215,7 +3195,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES); /* Response Queue Registers */ - *((u16 *) (qdev->prsp_producer_index)) = 0; + *((__le16 *) (qdev->prsp_producer_index)) = 0; qdev->rsp_consumer_index = 0; qdev->rsp_current = qdev->rsp_q_virt_addr; @@ -3548,7 +3528,7 @@ static void ql_set_mac_info(struct ql3_adapter *qdev) qdev->ndev->name,value); break; } - qdev->numPorts = qdev->nvram_data.numPorts; + qdev->numPorts = qdev->nvram_data.version_and_numPorts >> 8; } static void ql_display_dev_info(struct net_device *ndev) @@ -4051,12 +4031,10 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, /* Validate and set parameters */ if (qdev->mac_index) { ndev->mtu = qdev->nvram_data.macCfg_port1.etherMtu_mac ; - memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress, - ETH_ALEN); + ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn2.macAddress); } else { ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ; - memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress, - ETH_ALEN); + ql_set_mac_addr(ndev, qdev->nvram_data.funcCfg_fn0.macAddress); } memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index d0ffb30ef371..58a086fddec6 100644 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -50,7 +50,7 @@ struct ob_mac_iocb_req { #define OB_3032MAC_IOCB_REQ_UC 0x01 u8 reserved0; - __le32 transaction_id; + u32 transaction_id; /* opaque for hardware */ __le16 data_len; u8 ip_hdr_off; u8 ip_hdr_len; @@ -86,7 +86,7 @@ struct ob_mac_iocb_rsp { #define OB_MAC_IOCB_RSP_I 0x01 __le16 reserved0; - __le32 transaction_id; + u32 transaction_id; /* opaque for hardware */ __le32 reserved1; __le32 reserved2; }; @@ -953,8 +953,8 @@ struct eeprom_bios_cfg { */ struct eeprom_function_cfg { u8 reserved[30]; - u8 macAddress[6]; - u8 macAddressSecondary[6]; + u16 macAddress[3]; + u16 macAddressSecondary[3]; u16 subsysVendorId; u16 subsysDeviceId; @@ -965,8 +965,7 @@ struct eeprom_function_cfg { */ struct eeprom_data { u8 asicId[4]; - u8 version; - u8 numPorts; + u16 version_and_numPorts; /* together to avoid endianness crap */ u16 boardId; #define EEPROM_BOARDID_STR_SIZE 16 @@ -1056,31 +1055,31 @@ struct eeprom_data { */ struct lrg_buf_q_entry { - u32 addr0_lower; + __le32 addr0_lower; #define IAL_LAST_ENTRY 0x00000001 #define IAL_CONT_ENTRY 0x00000002 #define IAL_FLAG_MASK 0x00000003 - u32 addr0_upper; - u32 addr1_lower; - u32 addr1_upper; - u32 addr2_lower; - u32 addr2_upper; - u32 addr3_lower; - u32 addr3_upper; - u32 addr4_lower; - u32 addr4_upper; - u32 addr5_lower; - u32 addr5_upper; - u32 addr6_lower; - u32 addr6_upper; - u32 addr7_lower; - u32 addr7_upper; + __le32 addr0_upper; + __le32 addr1_lower; + __le32 addr1_upper; + __le32 addr2_lower; + __le32 addr2_upper; + __le32 addr3_lower; + __le32 addr3_upper; + __le32 addr4_lower; + __le32 addr4_upper; + __le32 addr5_lower; + __le32 addr5_upper; + __le32 addr6_lower; + __le32 addr6_upper; + __le32 addr7_lower; + __le32 addr7_upper; }; struct bufq_addr_element { - u32 addr_low; - u32 addr_high; + __le32 addr_low; + __le32 addr_high; }; #define QL_NO_RESET 0 @@ -1116,9 +1115,9 @@ struct ql_rcv_buf_cb { #define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1) struct oal_entry { - u32 dma_lo; - u32 dma_hi; - u32 len; + __le32 dma_lo; + __le32 dma_hi; + __le32 len; #define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */ #define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */ }; @@ -1223,7 +1222,7 @@ struct ql3_adapter { struct net_rsp_iocb *rsp_current; u16 rsp_consumer_index; u16 reserved_06; - volatile u32 *prsp_producer_index; + volatile __le32 *prsp_producer_index; u32 rsp_producer_index_phy_addr_high; u32 rsp_producer_index_phy_addr_low; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c new file mode 100644 index 000000000000..2334f4ebf907 --- /dev/null +++ b/drivers/net/r6040.c @@ -0,0 +1,1096 @@ +/* + * RDC R6040 Fast Ethernet MAC support + * + * Copyright (C) 2004 Sten Wang <sten.wang@rdc.com.tw> + * Copyright (C) 2007 + * Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> + * Florian Fainelli <florian@openwrt.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/moduleparam.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/crc32.h> +#include <linux/spinlock.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/uaccess.h> + +#include <asm/processor.h> + +#define DRV_NAME "r6040" +#define DRV_VERSION "0.16" +#define DRV_RELDATE "10Nov2007" + +/* PHY CHIP Address */ +#define PHY1_ADDR 1 /* For MAC1 */ +#define PHY2_ADDR 2 /* For MAC2 */ +#define PHY_MODE 0x3100 /* PHY CHIP Register 0 */ +#define PHY_CAP 0x01E1 /* PHY CHIP Register 4 */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (6000 * HZ / 1000) +#define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ + +/* RDC MAC I/O Size */ +#define R6040_IO_SIZE 256 + +/* MAX RDC MAC */ +#define MAX_MAC 2 + +/* MAC registers */ +#define MCR0 0x00 /* Control register 0 */ +#define MCR1 0x04 /* Control register 1 */ +#define MAC_RST 0x0001 /* Reset the MAC */ +#define MBCR 0x08 /* Bus control */ +#define MT_ICR 0x0C /* TX interrupt control */ +#define MR_ICR 0x10 /* RX interrupt control */ +#define MTPR 0x14 /* TX poll command register */ +#define MR_BSR 0x18 /* RX buffer size */ +#define MR_DCR 0x1A /* RX descriptor control */ +#define MLSR 0x1C /* Last status */ +#define MMDIO 0x20 /* MDIO control register */ +#define MDIO_WRITE 0x4000 /* MDIO write */ +#define MDIO_READ 0x2000 /* MDIO read */ +#define MMRD 0x24 /* MDIO read data register */ +#define MMWD 0x28 /* MDIO write data register */ +#define MTD_SA0 0x2C /* TX descriptor start address 0 */ +#define MTD_SA1 0x30 /* TX descriptor start address 1 */ +#define MRD_SA0 0x34 /* RX descriptor start address 0 */ +#define MRD_SA1 0x38 /* RX descriptor start address 1 */ +#define MISR 0x3C /* Status register */ +#define MIER 0x40 /* INT enable register */ +#define MSK_INT 0x0000 /* Mask off interrupts */ +#define ME_CISR 0x44 /* Event counter INT status */ +#define ME_CIER 0x48 /* Event counter INT enable */ +#define MR_CNT 0x50 /* Successfully received packet counter */ +#define ME_CNT0 0x52 /* Event counter 0 */ +#define ME_CNT1 0x54 /* Event counter 1 */ +#define ME_CNT2 0x56 /* Event counter 2 */ +#define ME_CNT3 0x58 /* Event counter 3 */ +#define MT_CNT 0x5A /* Successfully transmit packet counter */ +#define ME_CNT4 0x5C /* Event counter 4 */ +#define MP_CNT 0x5E /* Pause frame counter register */ +#define MAR0 0x60 /* Hash table 0 */ +#define MAR1 0x62 /* Hash table 1 */ +#define MAR2 0x64 /* Hash table 2 */ +#define MAR3 0x66 /* Hash table 3 */ +#define MID_0L 0x68 /* Multicast address MID0 Low */ +#define MID_0M 0x6A /* Multicast address MID0 Medium */ +#define MID_0H 0x6C /* Multicast address MID0 High */ +#define MID_1L 0x70 /* MID1 Low */ +#define MID_1M 0x72 /* MID1 Medium */ +#define MID_1H 0x74 /* MID1 High */ +#define MID_2L 0x78 /* MID2 Low */ +#define MID_2M 0x7A /* MID2 Medium */ +#define MID_2H 0x7C /* MID2 High */ +#define MID_3L 0x80 /* MID3 Low */ +#define MID_3M 0x82 /* MID3 Medium */ +#define MID_3H 0x84 /* MID3 High */ +#define PHY_CC 0x88 /* PHY status change configuration register */ +#define PHY_ST 0x8A /* PHY status register */ +#define MAC_SM 0xAC /* MAC status machine */ +#define MAC_ID 0xBE /* Identifier register */ + +#define TX_DCNT 0x80 /* TX descriptor count */ +#define RX_DCNT 0x80 /* RX descriptor count */ +#define MAX_BUF_SIZE 0x600 +#define RX_DESC_SIZE (RX_DCNT * sizeof(struct r6040_descriptor)) +#define TX_DESC_SIZE (TX_DCNT * sizeof(struct r6040_descriptor)) +#define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */ +#define MCAST_MAX 4 /* Max number multicast addresses to filter */ + +/* PHY settings */ +#define ICPLUS_PHY_ID 0x0243 + +MODULE_AUTHOR("Sten Wang <sten.wang@rdc.com.tw>," + "Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>," + "Florian Fainelli <florian@openwrt.org>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RDC R6040 NAPI PCI FastEthernet driver"); + +#define RX_INT 0x0001 +#define TX_INT 0x0010 +#define RX_NO_DESC_INT 0x0002 +#define INT_MASK (RX_INT | TX_INT) + +struct r6040_descriptor { + u16 status, len; /* 0-3 */ + __le32 buf; /* 4-7 */ + __le32 ndesc; /* 8-B */ + u32 rev1; /* C-F */ + char *vbufp; /* 10-13 */ + struct r6040_descriptor *vndescp; /* 14-17 */ + struct sk_buff *skb_ptr; /* 18-1B */ + u32 rev2; /* 1C-1F */ +} __attribute__((aligned(32))); + +struct r6040_private { + spinlock_t lock; /* driver lock */ + struct timer_list timer; + struct pci_dev *pdev; + struct r6040_descriptor *rx_insert_ptr; + struct r6040_descriptor *rx_remove_ptr; + struct r6040_descriptor *tx_insert_ptr; + struct r6040_descriptor *tx_remove_ptr; + struct r6040_descriptor *rx_ring; + struct r6040_descriptor *tx_ring; + dma_addr_t rx_ring_dma; + dma_addr_t tx_ring_dma; + u16 tx_free_desc, rx_free_desc, phy_addr, phy_mode; + u16 mcr0, mcr1; + u16 switch_sig; + struct net_device *dev; + struct mii_if_info mii_if; + struct napi_struct napi; + struct net_device_stats stats; + u16 napi_rx_running; + void __iomem *base; +}; + +static char version[] __devinitdata = KERN_INFO DRV_NAME + ": RDC R6040 NAPI net driver," + "version "DRV_VERSION " (" DRV_RELDATE ")\n"; + +static int phy_table[] = { PHY1_ADDR, PHY2_ADDR }; + +/* Read a word data from PHY Chip */ +static int phy_read(void __iomem *ioaddr, int phy_addr, int reg) +{ + int limit = 2048; + u16 cmd; + + iowrite16(MDIO_READ + reg + (phy_addr << 8), ioaddr + MMDIO); + /* Wait for the read bit to be cleared */ + while (limit--) { + cmd = ioread16(ioaddr + MMDIO); + if (cmd & MDIO_READ) + break; + } + + return ioread16(ioaddr + MMRD); +} + +/* Write a word data from PHY Chip */ +static void phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val) +{ + int limit = 2048; + u16 cmd; + + iowrite16(val, ioaddr + MMWD); + /* Write the command to the MDIO bus */ + iowrite16(MDIO_WRITE + reg + (phy_addr << 8), ioaddr + MMDIO); + /* Wait for the write bit to be cleared */ + while (limit--) { + cmd = ioread16(ioaddr + MMDIO); + if (cmd & MDIO_WRITE) + break; + } +} + +static int mdio_read(struct net_device *dev, int mii_id, int reg) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + + return (phy_read(ioaddr, lp->phy_addr, reg)); +} + +static void mdio_write(struct net_device *dev, int mii_id, int reg, int val) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + + phy_write(ioaddr, lp->phy_addr, reg, val); +} + +static void r6040_tx_timeout(struct net_device *dev) +{ + struct r6040_private *priv = netdev_priv(dev); + + disable_irq(dev->irq); + napi_disable(&priv->napi); + spin_lock(&priv->lock); + dev->stats.tx_errors++; + spin_unlock(&priv->lock); + + netif_stop_queue(dev); +} + +/* Allocate skb buffer for rx descriptor */ +static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev) +{ + struct r6040_descriptor *descptr; + void __iomem *ioaddr = lp->base; + + descptr = lp->rx_insert_ptr; + while (lp->rx_free_desc < RX_DCNT) { + descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); + + if (!descptr->skb_ptr) + break; + descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, + descptr->skb_ptr->data, + MAX_BUF_SIZE, PCI_DMA_FROMDEVICE)); + descptr->status = 0x8000; + descptr = descptr->vndescp; + lp->rx_free_desc++; + /* Trigger RX DMA */ + iowrite16(lp->mcr0 | 0x0002, ioaddr); + } + lp->rx_insert_ptr = descptr; +} + + +static struct net_device_stats *r6040_get_stats(struct net_device *dev) +{ + struct r6040_private *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + priv->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); + priv->stats.multicast += ioread8(ioaddr + ME_CNT0); + spin_unlock_irqrestore(&priv->lock, flags); + + return &priv->stats; +} + +/* Stop RDC MAC and Free the allocated resource */ +static void r6040_down(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + struct pci_dev *pdev = lp->pdev; + int i; + int limit = 2048; + u16 *adrp; + u16 cmd; + + /* Stop MAC */ + iowrite16(MSK_INT, ioaddr + MIER); /* Mask Off Interrupt */ + iowrite16(MAC_RST, ioaddr + MCR1); /* Reset RDC MAC */ + while (limit--) { + cmd = ioread16(ioaddr + MCR1); + if (cmd & 0x1) + break; + } + + /* Restore MAC Address to MIDx */ + adrp = (u16 *) dev->dev_addr; + iowrite16(adrp[0], ioaddr + MID_0L); + iowrite16(adrp[1], ioaddr + MID_0M); + iowrite16(adrp[2], ioaddr + MID_0H); + free_irq(dev->irq, dev); + /* Free RX buffer */ + for (i = 0; i < RX_DCNT; i++) { + if (lp->rx_insert_ptr->skb_ptr) { + pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, + MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); + lp->rx_insert_ptr->skb_ptr = NULL; + } + lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; + } + + /* Free TX buffer */ + for (i = 0; i < TX_DCNT; i++) { + if (lp->tx_insert_ptr->skb_ptr) { + pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, + MAX_BUF_SIZE, PCI_DMA_TODEVICE); + dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); + lp->rx_insert_ptr->skb_ptr = NULL; + } + lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; + } + + /* Free Descriptor memory */ + pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma); + pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma); +} + +static int r6040_close(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + + /* deleted timer */ + del_timer_sync(&lp->timer); + + spin_lock_irq(&lp->lock); + netif_stop_queue(dev); + r6040_down(dev); + spin_unlock_irq(&lp->lock); + + return 0; +} + +/* Status of PHY CHIP */ +static int phy_mode_chk(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + int phy_dat; + + /* PHY Link Status Check */ + phy_dat = phy_read(ioaddr, lp->phy_addr, 1); + if (!(phy_dat & 0x4)) + phy_dat = 0x8000; /* Link Failed, full duplex */ + + /* PHY Chip Auto-Negotiation Status */ + phy_dat = phy_read(ioaddr, lp->phy_addr, 1); + if (phy_dat & 0x0020) { + /* Auto Negotiation Mode */ + phy_dat = phy_read(ioaddr, lp->phy_addr, 5); + phy_dat &= phy_read(ioaddr, lp->phy_addr, 4); + if (phy_dat & 0x140) + /* Force full duplex */ + phy_dat = 0x8000; + else + phy_dat = 0; + } else { + /* Force Mode */ + phy_dat = phy_read(ioaddr, lp->phy_addr, 0); + if (phy_dat & 0x100) + phy_dat = 0x8000; + else + phy_dat = 0x0000; + } + + return phy_dat; +}; + +static void r6040_set_carrier(struct mii_if_info *mii) +{ + if (phy_mode_chk(mii->dev)) { + /* autoneg is off: Link is always assumed to be up */ + if (!netif_carrier_ok(mii->dev)) + netif_carrier_on(mii->dev); + } else + phy_mode_chk(mii->dev); +} + +static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct r6040_private *lp = netdev_priv(dev); + struct mii_ioctl_data *data = if_mii(rq); + int rc; + + if (!netif_running(dev)) + return -EINVAL; + spin_lock_irq(&lp->lock); + rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL); + spin_unlock_irq(&lp->lock); + r6040_set_carrier(&lp->mii_if); + return rc; +} + +static int r6040_rx(struct net_device *dev, int limit) +{ + struct r6040_private *priv = netdev_priv(dev); + int count; + void __iomem *ioaddr = priv->base; + u16 err; + + for (count = 0; count < limit; ++count) { + struct r6040_descriptor *descptr = priv->rx_remove_ptr; + struct sk_buff *skb_ptr; + + /* Disable RX interrupt */ + iowrite16(ioread16(ioaddr + MIER) & (~RX_INT), ioaddr + MIER); + descptr = priv->rx_remove_ptr; + + /* Check for errors */ + err = ioread16(ioaddr + MLSR); + if (err & 0x0400) priv->stats.rx_errors++; + /* RX FIFO over-run */ + if (err & 0x8000) priv->stats.rx_fifo_errors++; + /* RX descriptor unavailable */ + if (err & 0x0080) priv->stats.rx_frame_errors++; + /* Received packet with length over buffer lenght */ + if (err & 0x0020) priv->stats.rx_over_errors++; + /* Received packet with too long or short */ + if (err & (0x0010|0x0008)) priv->stats.rx_length_errors++; + /* Received packet with CRC errors */ + if (err & 0x0004) { + spin_lock(&priv->lock); + priv->stats.rx_crc_errors++; + spin_unlock(&priv->lock); + } + + while (priv->rx_free_desc) { + /* No RX packet */ + if (descptr->status & 0x8000) + break; + skb_ptr = descptr->skb_ptr; + if (!skb_ptr) { + printk(KERN_ERR "%s: Inconsistent RX" + "descriptor chain\n", + dev->name); + break; + } + descptr->skb_ptr = NULL; + skb_ptr->dev = priv->dev; + /* Do not count the CRC */ + skb_put(skb_ptr, descptr->len - 4); + pci_unmap_single(priv->pdev, descptr->buf, + MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); + skb_ptr->protocol = eth_type_trans(skb_ptr, priv->dev); + /* Send to upper layer */ + netif_receive_skb(skb_ptr); + dev->last_rx = jiffies; + priv->dev->stats.rx_packets++; + priv->dev->stats.rx_bytes += descptr->len; + /* To next descriptor */ + descptr = descptr->vndescp; + priv->rx_free_desc--; + } + priv->rx_remove_ptr = descptr; + } + /* Allocate new RX buffer */ + if (priv->rx_free_desc < RX_DCNT) + rx_buf_alloc(priv, priv->dev); + + return count; +} + +static void r6040_tx(struct net_device *dev) +{ + struct r6040_private *priv = netdev_priv(dev); + struct r6040_descriptor *descptr; + void __iomem *ioaddr = priv->base; + struct sk_buff *skb_ptr; + u16 err; + + spin_lock(&priv->lock); + descptr = priv->tx_remove_ptr; + while (priv->tx_free_desc < TX_DCNT) { + /* Check for errors */ + err = ioread16(ioaddr + MLSR); + + if (err & 0x0200) priv->stats.rx_fifo_errors++; + if (err & (0x2000 | 0x4000)) priv->stats.tx_carrier_errors++; + + if (descptr->status & 0x8000) + break; /* Not complte */ + skb_ptr = descptr->skb_ptr; + pci_unmap_single(priv->pdev, descptr->buf, + skb_ptr->len, PCI_DMA_TODEVICE); + /* Free buffer */ + dev_kfree_skb_irq(skb_ptr); + descptr->skb_ptr = NULL; + /* To next descriptor */ + descptr = descptr->vndescp; + priv->tx_free_desc++; + } + priv->tx_remove_ptr = descptr; + + if (priv->tx_free_desc) + netif_wake_queue(dev); + spin_unlock(&priv->lock); +} + +static int r6040_poll(struct napi_struct *napi, int budget) +{ + struct r6040_private *priv = + container_of(napi, struct r6040_private, napi); + struct net_device *dev = priv->dev; + void __iomem *ioaddr = priv->base; + int work_done; + + work_done = r6040_rx(dev, budget); + + if (work_done < budget) { + netif_rx_complete(dev, napi); + /* Enable RX interrupt */ + iowrite16(ioread16(ioaddr + MIER) | RX_INT, ioaddr + MIER); + } + return work_done; +} + +/* The RDC interrupt handler. */ +static irqreturn_t r6040_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + u16 status; + int handled = 1; + + /* Mask off RDC MAC interrupt */ + iowrite16(MSK_INT, ioaddr + MIER); + /* Read MISR status and clear */ + status = ioread16(ioaddr + MISR); + + if (status == 0x0000 || status == 0xffff) + return IRQ_NONE; + + /* RX interrupt request */ + if (status & 0x01) { + netif_rx_schedule(dev, &lp->napi); + iowrite16(TX_INT, ioaddr + MIER); + } + + /* TX interrupt request */ + if (status & 0x10) + r6040_tx(dev); + + return IRQ_RETVAL(handled); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void r6040_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + r6040_interrupt(dev->irq, dev); + enable_irq(dev->irq); +} +#endif + +static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, + dma_addr_t desc_dma, int size) +{ + struct r6040_descriptor *desc = desc_ring; + dma_addr_t mapping = desc_dma; + + while (size-- > 0) { + mapping += sizeof(sizeof(*desc)); + desc->ndesc = cpu_to_le32(mapping); + desc->vndescp = desc + 1; + desc++; + } + desc--; + desc->ndesc = cpu_to_le32(desc_dma); + desc->vndescp = desc_ring; +} + +/* Init RDC MAC */ +static void r6040_up(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + + /* Initialize */ + lp->tx_free_desc = TX_DCNT; + lp->rx_free_desc = 0; + /* Init descriptor */ + lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring; + lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring; + /* Init TX descriptor */ + r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT); + + /* Init RX descriptor */ + r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT); + + /* Allocate buffer for RX descriptor */ + rx_buf_alloc(lp, dev); + + /* + * TX and RX descriptor start registers. + * Lower 16-bits to MxD_SA0. Higher 16-bits to MxD_SA1. + */ + iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); + iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); + + iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0); + iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1); + + /* Buffer Size Register */ + iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); + /* Read the PHY ID */ + lp->switch_sig = phy_read(ioaddr, 0, 2); + + if (lp->switch_sig == ICPLUS_PHY_ID) { + phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */ + lp->phy_mode = 0x8000; + } else { + /* PHY Mode Check */ + phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP); + phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE); + + if (PHY_MODE == 0x3100) + lp->phy_mode = phy_mode_chk(dev); + else + lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; + } + /* MAC Bus Control Register */ + iowrite16(MBCR_DEFAULT, ioaddr + MBCR); + + /* MAC TX/RX Enable */ + lp->mcr0 |= lp->phy_mode; + iowrite16(lp->mcr0, ioaddr); + + /* set interrupt waiting time and packet numbers */ + iowrite16(0x0F06, ioaddr + MT_ICR); + iowrite16(0x0F06, ioaddr + MR_ICR); + + /* improve performance (by RDC guys) */ + phy_write(ioaddr, 30, 17, (phy_read(ioaddr, 30, 17) | 0x4000)); + phy_write(ioaddr, 30, 17, ~((~phy_read(ioaddr, 30, 17)) | 0x2000)); + phy_write(ioaddr, 0, 19, 0x0000); + phy_write(ioaddr, 0, 30, 0x01F0); + + /* Interrupt Mask Register */ + iowrite16(INT_MASK, ioaddr + MIER); +} + +/* + A periodic timer routine + Polling PHY Chip Link Status +*/ +static void r6040_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + u16 phy_mode; + + /* Polling PHY Chip Status */ + if (PHY_MODE == 0x3100) + phy_mode = phy_mode_chk(dev); + else + phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0; + + if (phy_mode != lp->phy_mode) { + lp->phy_mode = phy_mode; + lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode; + iowrite16(lp->mcr0, ioaddr); + printk(KERN_INFO "Link Change %x \n", ioread16(ioaddr)); + } + + /* Timer active again */ + lp->timer.expires = TIMER_WUT; + add_timer(&lp->timer); +} + +/* Read/set MAC address routines */ +static void r6040_mac_address(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + u16 *adrp; + + /* MAC operation register */ + iowrite16(0x01, ioaddr + MCR1); /* Reset MAC */ + iowrite16(2, ioaddr + MAC_SM); /* Reset internal state machine */ + iowrite16(0, ioaddr + MAC_SM); + udelay(5000); + + /* Restore MAC Address */ + adrp = (u16 *) dev->dev_addr; + iowrite16(adrp[0], ioaddr + MID_0L); + iowrite16(adrp[1], ioaddr + MID_0M); + iowrite16(adrp[2], ioaddr + MID_0H); +} + +static int r6040_open(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + int ret; + + /* Request IRQ and Register interrupt handler */ + ret = request_irq(dev->irq, &r6040_interrupt, + IRQF_SHARED, dev->name, dev); + if (ret) + return ret; + + /* Set MAC address */ + r6040_mac_address(dev); + + /* Allocate Descriptor memory */ + lp->rx_ring = + pci_alloc_consistent(lp->pdev, RX_DESC_SIZE, &lp->rx_ring_dma); + if (!lp->rx_ring) + return -ENOMEM; + + lp->tx_ring = + pci_alloc_consistent(lp->pdev, TX_DESC_SIZE, &lp->tx_ring_dma); + if (!lp->tx_ring) { + pci_free_consistent(lp->pdev, RX_DESC_SIZE, lp->rx_ring, + lp->rx_ring_dma); + return -ENOMEM; + } + + r6040_up(dev); + + napi_enable(&lp->napi); + netif_start_queue(dev); + + if (lp->switch_sig != ICPLUS_PHY_ID) { + /* set and active a timer process */ + init_timer(&lp->timer); + lp->timer.expires = TIMER_WUT; + lp->timer.data = (unsigned long)dev; + lp->timer.function = &r6040_timer; + add_timer(&lp->timer); + } + return 0; +} + +static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + struct r6040_descriptor *descptr; + void __iomem *ioaddr = lp->base; + unsigned long flags; + int ret = NETDEV_TX_OK; + + /* Critical Section */ + spin_lock_irqsave(&lp->lock, flags); + + /* TX resource check */ + if (!lp->tx_free_desc) { + spin_unlock_irqrestore(&lp->lock, flags); + netif_stop_queue(dev); + printk(KERN_ERR DRV_NAME ": no tx descriptor\n"); + ret = NETDEV_TX_BUSY; + return ret; + } + + /* Statistic Counter */ + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + /* Set TX descriptor & Transmit it */ + lp->tx_free_desc--; + descptr = lp->tx_insert_ptr; + if (skb->len < MISR) + descptr->len = MISR; + else + descptr->len = skb->len; + + descptr->skb_ptr = skb; + descptr->buf = cpu_to_le32(pci_map_single(lp->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE)); + descptr->status = 0x8000; + /* Trigger the MAC to check the TX descriptor */ + iowrite16(0x01, ioaddr + MTPR); + lp->tx_insert_ptr = descptr->vndescp; + + /* If no tx resource, stop */ + if (!lp->tx_free_desc) + netif_stop_queue(dev); + + dev->trans_start = jiffies; + spin_unlock_irqrestore(&lp->lock, flags); + return ret; +} + +static void r6040_multicast_list(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + u16 *adrp; + u16 reg; + unsigned long flags; + struct dev_mc_list *dmi = dev->mc_list; + int i; + + /* MAC Address */ + adrp = (u16 *)dev->dev_addr; + iowrite16(adrp[0], ioaddr + MID_0L); + iowrite16(adrp[1], ioaddr + MID_0M); + iowrite16(adrp[2], ioaddr + MID_0H); + + /* Promiscous Mode */ + spin_lock_irqsave(&lp->lock, flags); + + /* Clear AMCP & PROM bits */ + reg = ioread16(ioaddr) & ~0x0120; + if (dev->flags & IFF_PROMISC) { + reg |= 0x0020; + lp->mcr0 |= 0x0020; + } + /* Too many multicast addresses + * accept all traffic */ + else if ((dev->mc_count > MCAST_MAX) + || (dev->flags & IFF_ALLMULTI)) + reg |= 0x0020; + + iowrite16(reg, ioaddr); + spin_unlock_irqrestore(&lp->lock, flags); + + /* Build the hash table */ + if (dev->mc_count > MCAST_MAX) { + u16 hash_table[4]; + u32 crc; + + for (i = 0; i < 4; i++) + hash_table[i] = 0; + + for (i = 0; i < dev->mc_count; i++) { + char *addrs = dmi->dmi_addr; + + dmi = dmi->next; + + if (!(*addrs & 1)) + continue; + + crc = ether_crc_le(6, addrs); + crc >>= 26; + hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf)); + } + /* Write the index of the hash table */ + for (i = 0; i < 4; i++) + iowrite16(hash_table[i] << 14, ioaddr + MCR1); + /* Fill the MAC hash tables with their values */ + iowrite16(hash_table[0], ioaddr + MAR0); + iowrite16(hash_table[1], ioaddr + MAR1); + iowrite16(hash_table[2], ioaddr + MAR2); + iowrite16(hash_table[3], ioaddr + MAR3); + } + /* Multicast Address 1~4 case */ + for (i = 0, dmi; (i < dev->mc_count) && (i < MCAST_MAX); i++) { + adrp = (u16 *)dmi->dmi_addr; + iowrite16(adrp[0], ioaddr + MID_1L + 8*i); + iowrite16(adrp[1], ioaddr + MID_1M + 8*i); + iowrite16(adrp[2], ioaddr + MID_1H + 8*i); + dmi = dmi->next; + } + for (i = dev->mc_count; i < MCAST_MAX; i++) { + iowrite16(0xffff, ioaddr + MID_0L + 8*i); + iowrite16(0xffff, ioaddr + MID_0M + 8*i); + iowrite16(0xffff, ioaddr + MID_0H + 8*i); + } +} + +static void netdev_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct r6040_private *rp = netdev_priv(dev); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(rp->pdev)); +} + +static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct r6040_private *rp = netdev_priv(dev); + int rc; + + spin_lock_irq(&rp->lock); + rc = mii_ethtool_gset(&rp->mii_if, cmd); + spin_unlock_irq(&rp->lock); + + return rc; +} + +static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct r6040_private *rp = netdev_priv(dev); + int rc; + + spin_lock_irq(&rp->lock); + rc = mii_ethtool_sset(&rp->mii_if, cmd); + spin_unlock_irq(&rp->lock); + r6040_set_carrier(&rp->mii_if); + + return rc; +} + +static u32 netdev_get_link(struct net_device *dev) +{ + struct r6040_private *rp = netdev_priv(dev); + + return mii_link_ok(&rp->mii_if); +} + +static struct ethtool_ops netdev_ethtool_ops = { + .get_drvinfo = netdev_get_drvinfo, + .get_settings = netdev_get_settings, + .set_settings = netdev_set_settings, + .get_link = netdev_get_link, +}; + +static int __devinit r6040_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct r6040_private *lp; + void __iomem *ioaddr; + int err, io_size = R6040_IO_SIZE; + static int card_idx = -1; + int bar = 0; + long pioaddr; + u16 *adrp; + + printk(KERN_INFO "%s\n", version); + + err = pci_enable_device(pdev); + if (err) + return err; + + /* this should always be supported */ + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses" + "not supported by the card\n"); + return -ENODEV; + } + if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses" + "not supported by the card\n"); + return -ENODEV; + } + + /* IO Size check */ + if (pci_resource_len(pdev, 0) < io_size) { + printk(KERN_ERR "Insufficient PCI resources, aborting\n"); + return -EIO; + } + + pioaddr = pci_resource_start(pdev, 0); /* IO map base address */ + pci_set_master(pdev); + + dev = alloc_etherdev(sizeof(struct r6040_private)); + if (!dev) { + printk(KERN_ERR "Failed to allocate etherdev\n"); + return -ENOMEM; + } + SET_NETDEV_DEV(dev, &pdev->dev); + lp = netdev_priv(dev); + lp->pdev = pdev; + + if (pci_request_regions(pdev, DRV_NAME)) { + printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); + err = -ENODEV; + goto err_out_disable; + } + + ioaddr = pci_iomap(pdev, bar, io_size); + if (!ioaddr) { + printk(KERN_ERR "ioremap failed for device %s\n", + pci_name(pdev)); + return -EIO; + } + + /* Init system & device */ + lp->base = ioaddr; + dev->irq = pdev->irq; + + spin_lock_init(&lp->lock); + pci_set_drvdata(pdev, dev); + + /* Set MAC address */ + card_idx++; + + adrp = (u16 *)dev->dev_addr; + adrp[0] = ioread16(ioaddr + MID_0L); + adrp[1] = ioread16(ioaddr + MID_0M); + adrp[2] = ioread16(ioaddr + MID_0H); + + /* Link new device into r6040_root_dev */ + lp->pdev = pdev; + + /* Init RDC private data */ + lp->mcr0 = 0x1002; + lp->phy_addr = phy_table[card_idx]; + lp->switch_sig = 0; + + /* The RDC-specific entries in the device structure. */ + dev->open = &r6040_open; + dev->hard_start_xmit = &r6040_start_xmit; + dev->stop = &r6040_close; + dev->get_stats = r6040_get_stats; + dev->set_multicast_list = &r6040_multicast_list; + dev->do_ioctl = &r6040_ioctl; + dev->ethtool_ops = &netdev_ethtool_ops; + dev->tx_timeout = &r6040_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = r6040_poll_controller; +#endif + netif_napi_add(dev, &lp->napi, r6040_poll, 64); + lp->mii_if.dev = dev; + lp->mii_if.mdio_read = mdio_read; + lp->mii_if.mdio_write = mdio_write; + lp->mii_if.phy_id = lp->phy_addr; + lp->mii_if.phy_id_mask = 0x1f; + lp->mii_if.reg_num_mask = 0x1f; + + /* Register net device. After this dev->name assign */ + err = register_netdev(dev); + if (err) { + printk(KERN_ERR DRV_NAME ": Failed to register net device\n"); + goto err_out_res; + } + return 0; + +err_out_res: + pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + free_netdev(dev); + + return err; +} + +static void __devexit r6040_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + unregister_netdev(dev); + pci_release_regions(pdev); + free_netdev(dev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + + +static struct pci_device_id r6040_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_RDC, 0x6040) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, r6040_pci_tbl); + +static struct pci_driver r6040_driver = { + .name = DRV_NAME, + .id_table = r6040_pci_tbl, + .probe = r6040_init_one, + .remove = __devexit_p(r6040_remove_one), +}; + + +static int __init r6040_init(void) +{ + return pci_register_driver(&r6040_driver); +} + + +static void __exit r6040_cleanup(void) +{ + pci_unregister_driver(&r6040_driver); +} + +module_init(r6040_init); +module_exit(r6040_cleanup); diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 55a590ab1e17..3dd8f1342f70 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -877,7 +877,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx) dev->name); goto drop; case E_FLG_SYN_ERR: - printk(KERN_WARNING "%s: Flag sync. lost during" + printk(KERN_WARNING "%s: Flag sync. lost during " "packet\n", dev->name); goto drop; case E_RX_INV_BUF: diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index f25264f2638e..2109508c047a 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -723,11 +723,17 @@ struct XENA_dev_config { u64 rmac_cfg_key; #define RMAC_CFG_KEY(val) vBIT(val,0,16) -#define MAX_MAC_ADDRESSES 16 -#define MAX_MC_ADDRESSES 32 /* Multicast addresses */ -#define MAC_MAC_ADDR_START_OFFSET 0 -#define MAC_MC_ADDR_START_OFFSET 16 -#define MAC_MC_ALL_MC_ADDR_OFFSET 63 /* enables all multicast pkts */ +#define S2IO_MAC_ADDR_START_OFFSET 0 + +#define S2IO_XENA_MAX_MC_ADDRESSES 64 /* multicast addresses */ +#define S2IO_HERC_MAX_MC_ADDRESSES 256 + +#define S2IO_XENA_MAX_MAC_ADDRESSES 16 +#define S2IO_HERC_MAX_MAC_ADDRESSES 64 + +#define S2IO_XENA_MC_ADDR_START_OFFSET 16 +#define S2IO_HERC_MC_ADDR_START_OFFSET 64 + u64 rmac_addr_cmd_mem; #define RMAC_ADDR_CMD_MEM_WE s2BIT(7) #define RMAC_ADDR_CMD_MEM_RD 0 diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index f2ba944e035e..5fab7d7b5d74 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.17" +#define DRV_VERSION "2.0.26.15-2" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -335,10 +335,9 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"mc_err_cnt"} }; -#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN -#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \ - ETH_GSTRING_LEN -#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN +#define S2IO_XENA_STAT_LEN ARRAY_SIZE(ethtool_xena_stats_keys) +#define S2IO_ENHANCED_STAT_LEN ARRAY_SIZE(ethtool_enhanced_stats_keys) +#define S2IO_DRIVER_STAT_LEN ARRAY_SIZE(ethtool_driver_stats_keys) #define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN ) #define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN ) @@ -346,7 +345,7 @@ static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { #define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN ) #define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN ) -#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN +#define S2IO_TEST_LEN ARRAY_SIZE(s2io_gstrings) #define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN #define S2IO_TIMER_CONF(timer, handle, arg, exp) \ @@ -369,12 +368,19 @@ static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) static void s2io_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { + int i; struct s2io_nic *nic = dev->priv; - unsigned long flags; + unsigned long flags[MAX_TX_FIFOS]; + struct mac_info *mac_control = &nic->mac_control; + struct config_param *config = &nic->config; + + for (i = 0; i < config->tx_fifo_num; i++) + spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags[i]); - spin_lock_irqsave(&nic->tx_lock, flags); nic->vlgrp = grp; - spin_unlock_irqrestore(&nic->tx_lock, flags); + for (i = config->tx_fifo_num - 1; i >= 0; i--) + spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, + flags[i]); } /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ @@ -566,6 +572,21 @@ static int init_shared_mem(struct s2io_nic *nic) return -EINVAL; } + size = 0; + for (i = 0; i < config->tx_fifo_num; i++) { + size = config->tx_cfg[i].fifo_len; + /* + * Legal values are from 2 to 8192 + */ + if (size < 2) { + DBG_PRINT(ERR_DBG, "s2io: Invalid fifo len (%d)", size); + DBG_PRINT(ERR_DBG, "for fifo %d\n", i); + DBG_PRINT(ERR_DBG, "s2io: Legal values for fifo len" + "are 2 to 8192\n"); + return -EINVAL; + } + } + lst_size = (sizeof(struct TxD) * config->max_txds); lst_per_page = PAGE_SIZE / lst_size; @@ -640,10 +661,14 @@ static int init_shared_mem(struct s2io_nic *nic) } } - nic->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL); - if (!nic->ufo_in_band_v) - return -ENOMEM; - mem_allocated += (size * sizeof(u64)); + for (i = 0; i < config->tx_fifo_num; i++) { + size = config->tx_cfg[i].fifo_len; + mac_control->fifos[i].ufo_in_band_v + = kcalloc(size, sizeof(u64), GFP_KERNEL); + if (!mac_control->fifos[i].ufo_in_band_v) + return -ENOMEM; + mem_allocated += (size * sizeof(u64)); + } /* Allocation and initialization of RXDs in Rings */ size = 0; @@ -830,7 +855,6 @@ static int init_shared_mem(struct s2io_nic *nic) static void free_shared_mem(struct s2io_nic *nic) { int i, j, blk_cnt, size; - u32 ufo_size = 0; void *tmp_v_addr; dma_addr_t tmp_p_addr; struct mac_info *mac_control; @@ -851,7 +875,6 @@ static void free_shared_mem(struct s2io_nic *nic) lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { - ufo_size += config->tx_cfg[i].fifo_len; page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, lst_per_page); for (j = 0; j < page_num; j++) { @@ -941,18 +964,21 @@ static void free_shared_mem(struct s2io_nic *nic) } } + for (i = 0; i < nic->config.tx_fifo_num; i++) { + if (mac_control->fifos[i].ufo_in_band_v) { + nic->mac_control.stats_info->sw_stat.mem_freed + += (config->tx_cfg[i].fifo_len * sizeof(u64)); + kfree(mac_control->fifos[i].ufo_in_band_v); + } + } + if (mac_control->stats_mem) { + nic->mac_control.stats_info->sw_stat.mem_freed += + mac_control->stats_mem_sz; pci_free_consistent(nic->pdev, mac_control->stats_mem_sz, mac_control->stats_mem, mac_control->stats_mem_phy); - nic->mac_control.stats_info->sw_stat.mem_freed += - mac_control->stats_mem_sz; - } - if (nic->ufo_in_band_v) { - kfree(nic->ufo_in_band_v); - nic->mac_control.stats_info->sw_stat.mem_freed - += (ufo_size * sizeof(u64)); } } @@ -1053,8 +1079,67 @@ static int s2io_print_pci_mode(struct s2io_nic *nic) } /** + * init_tti - Initialization transmit traffic interrupt scheme + * @nic: device private variable + * @link: link status (UP/DOWN) used to enable/disable continuous + * transmit interrupts + * Description: The function configures transmit traffic interrupts + * Return Value: SUCCESS on success and + * '-1' on failure + */ + +int init_tti(struct s2io_nic *nic, int link) +{ + struct XENA_dev_config __iomem *bar0 = nic->bar0; + register u64 val64 = 0; + int i; + struct config_param *config; + + config = &nic->config; + + for (i = 0; i < config->tx_fifo_num; i++) { + /* + * TTI Initialization. Default Tx timer gets us about + * 250 interrupts per sec. Continuous interrupts are enabled + * by default. + */ + if (nic->device_type == XFRAME_II_DEVICE) { + int count = (nic->config.bus_speed * 125)/2; + val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count); + } else + val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); + + val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | + TTI_DATA1_MEM_TX_URNG_B(0x10) | + TTI_DATA1_MEM_TX_URNG_C(0x30) | + TTI_DATA1_MEM_TX_TIMER_AC_EN; + + if (use_continuous_tx_intrs && (link == LINK_UP)) + val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; + writeq(val64, &bar0->tti_data1_mem); + + val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | + TTI_DATA2_MEM_TX_UFC_B(0x20) | + TTI_DATA2_MEM_TX_UFC_C(0x40) | + TTI_DATA2_MEM_TX_UFC_D(0x80); + + writeq(val64, &bar0->tti_data2_mem); + + val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD | + TTI_CMD_MEM_OFFSET(i); + writeq(val64, &bar0->tti_command_mem); + + if (wait_for_cmd_complete(&bar0->tti_command_mem, + TTI_CMD_MEM_STROBE_NEW_CMD, S2IO_BIT_RESET) != SUCCESS) + return FAILURE; + } + + return SUCCESS; +} + +/** * init_nic - Initialization of hardware - * @nic: device peivate variable + * @nic: device private variable * Description: The function sequentially configures every block * of the H/W from their reset values. * Return Value: SUCCESS on success and @@ -1159,9 +1244,9 @@ static int init_nic(struct s2io_nic *nic) for (i = 0, j = 0; i < config->tx_fifo_num; i++) { val64 |= - vBIT(config->tx_cfg[i].fifo_len - 1, ((i * 32) + 19), + vBIT(config->tx_cfg[i].fifo_len - 1, ((j * 32) + 19), 13) | vBIT(config->tx_cfg[i].fifo_priority, - ((i * 32) + 5), 3); + ((j * 32) + 5), 3); if (i == (config->tx_fifo_num - 1)) { if (i % 2 == 0) @@ -1172,17 +1257,25 @@ static int init_nic(struct s2io_nic *nic) case 1: writeq(val64, &bar0->tx_fifo_partition_0); val64 = 0; + j = 0; break; case 3: writeq(val64, &bar0->tx_fifo_partition_1); val64 = 0; + j = 0; break; case 5: writeq(val64, &bar0->tx_fifo_partition_2); val64 = 0; + j = 0; break; case 7: writeq(val64, &bar0->tx_fifo_partition_3); + val64 = 0; + j = 0; + break; + default: + j++; break; } } @@ -1268,11 +1361,11 @@ static int init_nic(struct s2io_nic *nic) /* * Filling Tx round robin registers - * as per the number of FIFOs + * as per the number of FIFOs for equal scheduling priority */ switch (config->tx_fifo_num) { case 1: - val64 = 0x0000000000000000ULL; + val64 = 0x0; writeq(val64, &bar0->tx_w_round_robin_0); writeq(val64, &bar0->tx_w_round_robin_1); writeq(val64, &bar0->tx_w_round_robin_2); @@ -1280,87 +1373,78 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->tx_w_round_robin_4); break; case 2: - val64 = 0x0000010000010000ULL; + val64 = 0x0001000100010001ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0100000100000100ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0001000001000001ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0000010000010000ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0100000000000000ULL; + val64 = 0x0001000100000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; case 3: - val64 = 0x0001000102000001ULL; + val64 = 0x0001020001020001ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0001020000010001ULL; + val64 = 0x0200010200010200ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0200000100010200ULL; + val64 = 0x0102000102000102ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0001000102000001ULL; + val64 = 0x0001020001020001ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0001020000000000ULL; + val64 = 0x0200010200000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; case 4: - val64 = 0x0001020300010200ULL; + val64 = 0x0001020300010203ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0100000102030001ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0200010000010203ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0001020001000001ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0203000100000000ULL; + val64 = 0x0001020300000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; case 5: - val64 = 0x0001000203000102ULL; + val64 = 0x0001020304000102ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0001020001030004ULL; + val64 = 0x0304000102030400ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0001000203000102ULL; + val64 = 0x0102030400010203ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0001020001030004ULL; + val64 = 0x0400010203040001ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0001000000000000ULL; + val64 = 0x0203040000000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; case 6: - val64 = 0x0001020304000102ULL; + val64 = 0x0001020304050001ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0304050001020001ULL; + val64 = 0x0203040500010203ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0203000100000102ULL; + val64 = 0x0405000102030405ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0304000102030405ULL; + val64 = 0x0001020304050001ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0001000200000000ULL; + val64 = 0x0203040500000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; case 7: - val64 = 0x0001020001020300ULL; + val64 = 0x0001020304050600ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0102030400010203ULL; + val64 = 0x0102030405060001ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0405060001020001ULL; + val64 = 0x0203040506000102ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0304050000010200ULL; + val64 = 0x0304050600010203ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0102030000000000ULL; + val64 = 0x0405060000000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; case 8: - val64 = 0x0001020300040105ULL; + val64 = 0x0001020304050607ULL; writeq(val64, &bar0->tx_w_round_robin_0); - val64 = 0x0200030106000204ULL; writeq(val64, &bar0->tx_w_round_robin_1); - val64 = 0x0103000502010007ULL; writeq(val64, &bar0->tx_w_round_robin_2); - val64 = 0x0304010002060500ULL; writeq(val64, &bar0->tx_w_round_robin_3); - val64 = 0x0103020400000000ULL; + val64 = 0x0001020300000000ULL; writeq(val64, &bar0->tx_w_round_robin_4); break; } @@ -1537,58 +1621,14 @@ static int init_nic(struct s2io_nic *nic) MAC_RX_LINK_UTIL_VAL(rmac_util_period); writeq(val64, &bar0->mac_link_util); - /* * Initializing the Transmit and Receive Traffic Interrupt * Scheme. */ - /* - * TTI Initialization. Default Tx timer gets us about - * 250 interrupts per sec. Continuous interrupts are enabled - * by default. - */ - if (nic->device_type == XFRAME_II_DEVICE) { - int count = (nic->config.bus_speed * 125)/2; - val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count); - } else { - - val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); - } - val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | - TTI_DATA1_MEM_TX_URNG_B(0x10) | - TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN; - if (use_continuous_tx_intrs) - val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; - writeq(val64, &bar0->tti_data1_mem); - - val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | - TTI_DATA2_MEM_TX_UFC_B(0x20) | - TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80); - writeq(val64, &bar0->tti_data2_mem); - - val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; - writeq(val64, &bar0->tti_command_mem); - /* - * Once the operation completes, the Strobe bit of the command - * register will be reset. We poll for this particular condition - * We wait for a maximum of 500ms for the operation to complete, - * if it's not complete by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->tti_command_mem); - if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n", - dev->name); - return -ENODEV; - } - msleep(50); - time++; - } + /* Initialize TTI */ + if (SUCCESS != init_tti(nic, nic->last_link_state)) + return -ENODEV; /* RTI Initialization */ if (nic->device_type == XFRAME_II_DEVICE) { @@ -2242,7 +2282,7 @@ static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \ u16 j, frg_cnt; txds = txdlp; - if (txds->Host_Control == (u64)(long)nic->ufo_in_band_v) { + if (txds->Host_Control == (u64)(long)fifo_data->ufo_in_band_v) { pci_unmap_single(nic->pdev, (dma_addr_t) txds->Buffer_Pointer, sizeof(u64), PCI_DMA_TODEVICE); @@ -2297,6 +2337,8 @@ static void free_tx_buffers(struct s2io_nic *nic) config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { + unsigned long flags; + spin_lock_irqsave(&mac_control->fifos[i].tx_lock, flags); for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) { txdp = (struct TxD *) \ mac_control->fifos[i].list_info[j].list_virt_addr; @@ -2313,6 +2355,7 @@ static void free_tx_buffers(struct s2io_nic *nic) dev->name, cnt, i); mac_control->fifos[i].tx_curr_get_info.offset = 0; mac_control->fifos[i].tx_curr_put_info.offset = 0; + spin_unlock_irqrestore(&mac_control->fifos[i].tx_lock, flags); } } @@ -2933,8 +2976,12 @@ static void tx_intr_handler(struct fifo_info *fifo_data) struct tx_curr_get_info get_info, put_info; struct sk_buff *skb; struct TxD *txdlp; + unsigned long flags = 0; u8 err_mask; + if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags)) + return; + get_info = fifo_data->tx_curr_get_info; memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info)); txdlp = (struct TxD *) fifo_data->list_info[get_info.offset]. @@ -2983,6 +3030,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset); if (skb == NULL) { + spin_unlock_irqrestore(&fifo_data->tx_lock, flags); DBG_PRINT(ERR_DBG, "%s: Null skb ", __FUNCTION__); DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); @@ -3003,10 +3051,10 @@ static void tx_intr_handler(struct fifo_info *fifo_data) get_info.offset; } - spin_lock(&nic->tx_lock); if (netif_queue_stopped(dev)) netif_wake_queue(dev); - spin_unlock(&nic->tx_lock); + + spin_unlock_irqrestore(&fifo_data->tx_lock, flags); } /** @@ -3376,6 +3424,9 @@ static void s2io_reset(struct s2io_nic * sp) /* Set swapper to enable I/O register access */ s2io_set_swapper(sp); + /* restore mac_addr entries */ + do_s2io_restore_unicast_mc(sp); + /* Restore the MSIX table entries from local variables */ restore_xmsi_data(sp); @@ -3434,9 +3485,6 @@ static void s2io_reset(struct s2io_nic * sp) writeq(val64, &bar0->pcc_err_reg); } - /* restore the previously assigned mac address */ - do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); - sp->device_enabled_once = FALSE; } @@ -3773,7 +3821,7 @@ static int s2io_test_msi(struct s2io_nic *sp) if (!sp->msi_detected) { /* MSI(X) test failed, go back to INTx mode */ - DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated" + DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " "using MSI(X) during test\n", sp->dev->name, pci_name(pdev)); @@ -3921,6 +3969,9 @@ hw_init_failed: static int s2io_close(struct net_device *dev) { struct s2io_nic *sp = dev->priv; + struct config_param *config = &sp->config; + u64 tmp64; + int offset; /* Return if the device is already closed * * Can happen when s2io_card_up failed in change_mtu * @@ -3929,6 +3980,14 @@ static int s2io_close(struct net_device *dev) return 0; netif_stop_queue(dev); + + /* delete all populated mac entries */ + for (offset = 1; offset < config->max_mc_addr; offset++) { + tmp64 = do_s2io_read_unicast_mc(sp, offset); + if (tmp64 != S2IO_DISABLE_MAC_ENTRY) + do_s2io_delete_unicast_mc(sp, tmp64); + } + /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); @@ -3955,9 +4014,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) register u64 val64; struct TxD *txdp; struct TxFIFO_element __iomem *tx_fifo; - unsigned long flags; + unsigned long flags = 0; u16 vlan_tag = 0; int vlan_priority = 0; + struct fifo_info *fifo = NULL; struct mac_info *mac_control; struct config_param *config; int offload_type; @@ -3972,13 +4032,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); dev_kfree_skb_any(skb); return 0; -} + } - spin_lock_irqsave(&sp->tx_lock, flags); if (!is_s2io_card_up(sp)) { DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); - spin_unlock_irqrestore(&sp->tx_lock, flags); dev_kfree_skb(skb); return 0; } @@ -3991,19 +4049,20 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) queue = config->fifo_mapping[vlan_priority]; } - put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset; - get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset; - txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off]. - list_virt_addr; + fifo = &mac_control->fifos[queue]; + spin_lock_irqsave(&fifo->tx_lock, flags); + put_off = (u16) fifo->tx_curr_put_info.offset; + get_off = (u16) fifo->tx_curr_get_info.offset; + txdp = (struct TxD *) fifo->list_info[put_off].list_virt_addr; - queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; + queue_len = fifo->tx_curr_put_info.fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n"); netif_stop_queue(dev); dev_kfree_skb(skb); - spin_unlock_irqrestore(&sp->tx_lock, flags); + spin_unlock_irqrestore(&fifo->tx_lock, flags); return 0; } @@ -4019,7 +4078,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } txdp->Control_1 |= TXD_GATHER_CODE_FIRST; txdp->Control_1 |= TXD_LIST_OWN_XENA; - txdp->Control_2 |= config->tx_intr_type; + txdp->Control_2 |= TXD_INT_NUMBER(fifo->fifo_no); if (sp->vlgrp && vlan_tx_tag_present(skb)) { txdp->Control_2 |= TXD_VLAN_ENABLE; @@ -4036,15 +4095,15 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_1 |= TXD_UFO_MSS(ufo_size); txdp->Control_1 |= TXD_BUFFER0_SIZE(8); #ifdef __BIG_ENDIAN - sp->ufo_in_band_v[put_off] = + fifo->ufo_in_band_v[put_off] = (u64)skb_shinfo(skb)->ip6_frag_id; #else - sp->ufo_in_band_v[put_off] = + fifo->ufo_in_band_v[put_off] = (u64)skb_shinfo(skb)->ip6_frag_id << 32; #endif - txdp->Host_Control = (unsigned long)sp->ufo_in_band_v; + txdp->Host_Control = (unsigned long)fifo->ufo_in_band_v; txdp->Buffer_Pointer = pci_map_single(sp->pdev, - sp->ufo_in_band_v, + fifo->ufo_in_band_v, sizeof(u64), PCI_DMA_TODEVICE); if((txdp->Buffer_Pointer == 0) || (txdp->Buffer_Pointer == DMA_ERROR_CODE)) @@ -4084,7 +4143,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) frg_cnt++; /* as Txd0 was used for inband header */ tx_fifo = mac_control->tx_FIFO_start[queue]; - val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr; + val64 = fifo->list_info[put_off].list_phy_addr; writeq(val64, &tx_fifo->TxDL_Pointer); val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST | @@ -4097,9 +4156,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) mmiowb(); put_off++; - if (put_off == mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1) + if (put_off == fifo->tx_curr_put_info.fifo_len + 1) put_off = 0; - mac_control->fifos[queue].tx_curr_put_info.offset = put_off; + fifo->tx_curr_put_info.offset = put_off; /* Avoid "put" pointer going beyond "get" pointer */ if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { @@ -4111,7 +4170,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) } mac_control->stats_info->sw_stat.mem_allocated += skb->truesize; dev->trans_start = jiffies; - spin_unlock_irqrestore(&sp->tx_lock, flags); + spin_unlock_irqrestore(&fifo->tx_lock, flags); return 0; pci_map_failed: @@ -4119,7 +4178,7 @@ pci_map_failed: netif_stop_queue(dev); stats->mem_freed += skb->truesize; dev_kfree_skb(skb); - spin_unlock_irqrestore(&sp->tx_lock, flags); + spin_unlock_irqrestore(&fifo->tx_lock, flags); return 0; } @@ -4729,8 +4788,9 @@ static void s2io_set_multicast(struct net_device *dev) struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 0xfeffffffffffULL; - u64 dis_addr = 0xffffffffffffULL, mac_addr = 0; + u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0; void __iomem *add; + struct config_param *config = &sp->config; if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) { /* Enable all Multicast addresses */ @@ -4740,7 +4800,7 @@ static void s2io_set_multicast(struct net_device *dev) &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(MAC_MC_ALL_MC_ADDR_OFFSET); + RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, @@ -4748,7 +4808,7 @@ static void s2io_set_multicast(struct net_device *dev) S2IO_BIT_RESET); sp->m_cast_flg = 1; - sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET; + sp->all_multi_pos = config->max_mc_addr - 1; } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) { /* Disable all Multicast addresses */ writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), @@ -4817,7 +4877,7 @@ static void s2io_set_multicast(struct net_device *dev) /* Update individual M_CAST address list */ if ((!sp->m_cast_flg) && dev->mc_count) { if (dev->mc_count > - (MAX_ADDRS_SUPPORTED - MAC_MC_ADDR_START_OFFSET - 1)) { + (config->max_mc_addr - config->max_mac_addr)) { DBG_PRINT(ERR_DBG, "%s: No more Rx filters ", dev->name); DBG_PRINT(ERR_DBG, "can be added, please enable "); @@ -4837,7 +4897,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET - (MAC_MC_ADDR_START_OFFSET + i); + (config->mc_start_offset + i); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ @@ -4869,7 +4929,7 @@ static void s2io_set_multicast(struct net_device *dev) val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET - (i + MAC_MC_ADDR_START_OFFSET); + (i + config->mc_start_offset); writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait for command completes */ @@ -4885,8 +4945,78 @@ static void s2io_set_multicast(struct net_device *dev) } } -/* add unicast MAC address to CAM */ -static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off) +/* read from CAM unicast & multicast addresses and store it in + * def_mac_addr structure + */ +void do_s2io_store_unicast_mc(struct s2io_nic *sp) +{ + int offset; + u64 mac_addr = 0x0; + struct config_param *config = &sp->config; + + /* store unicast & multicast mac addresses */ + for (offset = 0; offset < config->max_mc_addr; offset++) { + mac_addr = do_s2io_read_unicast_mc(sp, offset); + /* if read fails disable the entry */ + if (mac_addr == FAILURE) + mac_addr = S2IO_DISABLE_MAC_ENTRY; + do_s2io_copy_mac_addr(sp, offset, mac_addr); + } +} + +/* restore unicast & multicast MAC to CAM from def_mac_addr structure */ +static void do_s2io_restore_unicast_mc(struct s2io_nic *sp) +{ + int offset; + struct config_param *config = &sp->config; + /* restore unicast mac address */ + for (offset = 0; offset < config->max_mac_addr; offset++) + do_s2io_prog_unicast(sp->dev, + sp->def_mac_addr[offset].mac_addr); + + /* restore multicast mac address */ + for (offset = config->mc_start_offset; + offset < config->max_mc_addr; offset++) + do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr); +} + +/* add a multicast MAC address to CAM */ +static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr) +{ + int i; + u64 mac_addr = 0; + struct config_param *config = &sp->config; + + for (i = 0; i < ETH_ALEN; i++) { + mac_addr <<= 8; + mac_addr |= addr[i]; + } + if ((0ULL == mac_addr) || (mac_addr == S2IO_DISABLE_MAC_ENTRY)) + return SUCCESS; + + /* check if the multicast mac already preset in CAM */ + for (i = config->mc_start_offset; i < config->max_mc_addr; i++) { + u64 tmp64; + tmp64 = do_s2io_read_unicast_mc(sp, i); + if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ + break; + + if (tmp64 == mac_addr) + return SUCCESS; + } + if (i == config->max_mc_addr) { + DBG_PRINT(ERR_DBG, + "CAM full no space left for multicast MAC\n"); + return FAILURE; + } + /* Update the internal structure with this new mac address */ + do_s2io_copy_mac_addr(sp, i, mac_addr); + + return (do_s2io_add_mac(sp, mac_addr, i)); +} + +/* add MAC address to CAM */ +static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off) { u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0; @@ -4903,15 +5033,62 @@ static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off) if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { - DBG_PRINT(INFO_DBG, "add_mac_addr failed\n"); + DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n"); return FAILURE; } return SUCCESS; } +/* deletes a specified unicast/multicast mac entry from CAM */ +static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) +{ + int offset; + u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, tmp64; + struct config_param *config = &sp->config; + + for (offset = 1; + offset < config->max_mc_addr; offset++) { + tmp64 = do_s2io_read_unicast_mc(sp, offset); + if (tmp64 == addr) { + /* disable the entry by writing 0xffffffffffffULL */ + if (do_s2io_add_mac(sp, dis_addr, offset) == FAILURE) + return FAILURE; + /* store the new mac list from CAM */ + do_s2io_store_unicast_mc(sp); + return SUCCESS; + } + } + DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n", + (unsigned long long)addr); + return FAILURE; +} + +/* read mac entries from CAM */ +static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset) +{ + u64 tmp64 = 0xffffffffffff0000ULL, val64; + struct XENA_dev_config __iomem *bar0 = sp->bar0; + + /* read mac addr */ + val64 = + RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | + RMAC_ADDR_CMD_MEM_OFFSET(offset); + writeq(val64, &bar0->rmac_addr_cmd_mem); + + /* Wait till command completes */ + if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { + DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n"); + return FAILURE; + } + tmp64 = readq(&bar0->rmac_addr_data0_mem); + return (tmp64 >> 16); +} /** * s2io_set_mac_addr driver entry point */ + static int s2io_set_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; @@ -4924,7 +5101,6 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) /* store the MAC address in CAM */ return (do_s2io_prog_unicast(dev, dev->dev_addr)); } - /** * do_s2io_prog_unicast - Programs the Xframe mac address * @dev : pointer to the device structure. @@ -4934,11 +5110,14 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure. */ + static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) { struct s2io_nic *sp = dev->priv; register u64 mac_addr = 0, perm_addr = 0; int i; + u64 tmp64; + struct config_param *config = &sp->config; /* * Set the new MAC address as the new unicast filter and reflect this @@ -4956,9 +5135,26 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) if (mac_addr == perm_addr) return SUCCESS; + /* check if the mac already preset in CAM */ + for (i = 1; i < config->max_mac_addr; i++) { + tmp64 = do_s2io_read_unicast_mc(sp, i); + if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ + break; + + if (tmp64 == mac_addr) { + DBG_PRINT(INFO_DBG, + "MAC addr:0x%llx already present in CAM\n", + (unsigned long long)mac_addr); + return SUCCESS; + } + } + if (i == config->max_mac_addr) { + DBG_PRINT(ERR_DBG, "CAM full no space left for Unicast MAC\n"); + return FAILURE; + } /* Update the internal structure with this new mac address */ - do_s2io_copy_mac_addr(sp, 0, mac_addr); - return (do_s2io_add_unicast(sp, mac_addr, 0)); + do_s2io_copy_mac_addr(sp, i, mac_addr); + return (do_s2io_add_mac(sp, mac_addr, i)); } /** @@ -6721,7 +6917,7 @@ static int s2io_add_isr(struct s2io_nic * sp) /* If either data or addr is zero print it */ if(!(sp->msix_info[i].addr && sp->msix_info[i].data)) { - DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx" + DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx " "Data:0x%lx\n",sp->desc[i], (unsigned long long) sp->msix_info[i].addr, @@ -6739,7 +6935,7 @@ static int s2io_add_isr(struct s2io_nic * sp) /* If either data or addr is zero print it */ if(!(sp->msix_info[i].addr && sp->msix_info[i].data)) { - DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx" + DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx " "Data:0x%lx\n",sp->desc[i], (unsigned long long) sp->msix_info[i].addr, @@ -6848,10 +7044,8 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) if (do_io) s2io_reset(sp); - spin_lock_irqsave(&sp->tx_lock, flags); /* Free all Tx buffers */ free_tx_buffers(sp); - spin_unlock_irqrestore(&sp->tx_lock, flags); /* Free all Rx buffers */ spin_lock_irqsave(&sp->rx_lock, flags); @@ -7263,6 +7457,7 @@ static void s2io_link(struct s2io_nic * sp, int link) struct net_device *dev = (struct net_device *) sp->dev; if (link != sp->last_link_state) { + init_tti(sp, link); if (link == LINK_DOWN) { DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); netif_carrier_off(dev); @@ -7315,12 +7510,18 @@ static void s2io_init_pci(struct s2io_nic * sp) static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) { - if ( tx_fifo_num > 8) { - DBG_PRINT(ERR_DBG, "s2io: Requested number of Tx fifos not " - "supported\n"); - DBG_PRINT(ERR_DBG, "s2io: Default to 8 Tx fifos\n"); - tx_fifo_num = 8; + if ((tx_fifo_num > MAX_TX_FIFOS) || + (tx_fifo_num < FIFO_DEFAULT_NUM)) { + DBG_PRINT(ERR_DBG, "s2io: Requested number of tx fifos " + "(%d) not supported\n", tx_fifo_num); + tx_fifo_num = + ((tx_fifo_num > MAX_TX_FIFOS)? MAX_TX_FIFOS : + ((tx_fifo_num < FIFO_DEFAULT_NUM) ? FIFO_DEFAULT_NUM : + tx_fifo_num)); + DBG_PRINT(ERR_DBG, "s2io: Default to %d ", tx_fifo_num); + DBG_PRINT(ERR_DBG, "tx fifos\n"); } + if ( rx_ring_num > 8) { DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not " "supported\n"); @@ -7355,7 +7556,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) /** * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS * or Traffic class respectively. - * @nic: device peivate variable + * @nic: device private variable * Description: The function configures the receive steering to * desired receive ring. * Return Value: SUCCESS on success and @@ -7652,7 +7853,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) */ bar0 = sp->bar0; val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | - RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET); + RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); writeq(val64, &bar0->rmac_addr_cmd_mem); wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET); @@ -7672,6 +7873,20 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN); + /* initialize number of multicast & unicast MAC entries variables */ + if (sp->device_type == XFRAME_I_DEVICE) { + config->max_mc_addr = S2IO_XENA_MAX_MC_ADDRESSES; + config->max_mac_addr = S2IO_XENA_MAX_MAC_ADDRESSES; + config->mc_start_offset = S2IO_XENA_MC_ADDR_START_OFFSET; + } else if (sp->device_type == XFRAME_II_DEVICE) { + config->max_mc_addr = S2IO_HERC_MAX_MC_ADDRESSES; + config->max_mac_addr = S2IO_HERC_MAX_MAC_ADDRESSES; + config->mc_start_offset = S2IO_HERC_MC_ADDR_START_OFFSET; + } + + /* store mac addresses from CAM to s2io_nic structure */ + do_s2io_store_unicast_mc(sp); + /* Store the values of the MSIX table in the s2io_nic structure */ store_xmsi_data(sp); /* reset Nic and bring it to known state */ @@ -7685,7 +7900,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->state = 0; /* Initialize spinlocks */ - spin_lock_init(&sp->tx_lock); + for (i = 0; i < sp->config.tx_fifo_num; i++) + spin_lock_init(&mac_control->fifos[i].tx_lock); if (!napi) spin_lock_init(&sp->put_lock); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index cc1797a071aa..9f6016c6f135 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -31,6 +31,7 @@ #define SUCCESS 0 #define FAILURE -1 #define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL +#define S2IO_DISABLE_MAC_ENTRY 0xFFFFFFFFFFFFULL #define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100 #define S2IO_BIT_RESET 1 #define S2IO_BIT_SET 2 @@ -359,6 +360,8 @@ struct stat_block { #define MAX_TX_FIFOS 8 #define MAX_RX_RINGS 8 +#define FIFO_DEFAULT_NUM 1 + #define MAX_RX_DESC_1 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 127 ) #define MAX_RX_DESC_2 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 ) #define MAX_RX_DESC_3 (MAX_RX_RINGS * MAX_RX_BLOCKS_PER_RING * 85 ) @@ -458,6 +461,9 @@ struct config_param { #define MAX_MTU_JUMBO (MAX_PYLD_JUMBO+18) #define MAX_MTU_JUMBO_VLAN (MAX_PYLD_JUMBO+22) u16 bus_speed; + int max_mc_addr; /* xena=64 herc=256 */ + int max_mac_addr; /* xena=16 herc=64 */ + int mc_start_offset; /* xena=16 herc=64 */ }; /* Structure representing MAC Addrs */ @@ -715,8 +721,14 @@ struct fifo_info { */ struct tx_curr_get_info tx_curr_get_info; + /* Per fifo lock */ + spinlock_t tx_lock; + + /* Per fifo UFO in band structure */ + u64 *ufo_in_band_v; + struct s2io_nic *nic; -}; +} ____cacheline_aligned; /* Information related to the Tx and Rx FIFOs and Rings of Xena * is maintained in this structure. @@ -826,7 +838,7 @@ struct s2io_nic { #define MAX_MAC_SUPPORTED 16 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED - struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; + struct mac_addr def_mac_addr[256]; struct net_device_stats stats; int high_dma_flag; @@ -844,7 +856,6 @@ struct s2io_nic { atomic_t rx_bufs_left[MAX_RX_RINGS]; - spinlock_t tx_lock; spinlock_t put_lock; #define PROMISC 1 @@ -853,7 +864,7 @@ struct s2io_nic { #define MAX_ADDRS_SUPPORTED 64 u16 usr_addr_count; u16 mc_addr_count; - struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED]; + struct usr_addr usr_addrs[256]; u16 m_cast_flg; u16 all_multi_pos; @@ -911,7 +922,6 @@ struct s2io_nic { volatile unsigned long state; spinlock_t rx_lock; u64 general_int_mask; - u64 *ufo_in_band_v; #define VPD_STRING_LEN 80 u8 product_name[VPD_STRING_LEN]; u8 serial_num[VPD_STRING_LEN]; @@ -1066,6 +1076,12 @@ static int s2io_add_isr(struct s2io_nic * sp); static void s2io_rem_isr(struct s2io_nic * sp); static void restore_xmsi_data(struct s2io_nic *nic); +static void do_s2io_store_unicast_mc(struct s2io_nic *sp); +static void do_s2io_restore_unicast_mc(struct s2io_nic *sp); +static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset); +static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr); +static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int offset); +static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr); static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro, diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index ff4056310356..78994ede0cb0 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -12,7 +12,6 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/interrupt.h> -#include <linux/slab.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/netdevice.h> @@ -53,14 +52,27 @@ static char *sgiseeqstr = "SGI Seeq8003"; sp->tx_old + (SEEQ_TX_BUFFERS - 1) - sp->tx_new : \ sp->tx_old - sp->tx_new - 1) +#define VIRT_TO_DMA(sp, v) ((sp)->srings_dma + \ + (dma_addr_t)((unsigned long)(v) - \ + (unsigned long)((sp)->rx_desc))) + +/* Copy frames shorter than rx_copybreak, otherwise pass on up in + * a full sized sk_buff. Value of 100 stolen from tulip.c (!alpha). + */ +static int rx_copybreak = 100; + +#define PAD_SIZE (128 - sizeof(struct hpc_dma_desc) - sizeof(void *)) + struct sgiseeq_rx_desc { volatile struct hpc_dma_desc rdma; - volatile signed int buf_vaddr; + u8 padding[PAD_SIZE]; + struct sk_buff *skb; }; struct sgiseeq_tx_desc { volatile struct hpc_dma_desc tdma; - volatile signed int buf_vaddr; + u8 padding[PAD_SIZE]; + struct sk_buff *skb; }; /* @@ -96,6 +108,18 @@ struct sgiseeq_private { spinlock_t tx_lock; }; +static inline void dma_sync_desc_cpu(struct net_device *dev, void *addr) +{ + dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc), + DMA_FROM_DEVICE); +} + +static inline void dma_sync_desc_dev(struct net_device *dev, void *addr) +{ + dma_cache_sync(dev->dev.parent, addr, sizeof(struct sgiseeq_rx_desc), + DMA_TO_DEVICE); +} + static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs) { hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ; @@ -163,35 +187,55 @@ static int seeq_init_ring(struct net_device *dev) /* Setup tx ring. */ for(i = 0; i < SEEQ_TX_BUFFERS; i++) { - if (!sp->tx_desc[i].tdma.pbuf) { - unsigned long buffer; - - buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - sp->tx_desc[i].buf_vaddr = CKSEG1ADDR(buffer); - sp->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer); - } sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT; + dma_sync_desc_dev(dev, &sp->tx_desc[i]); } /* And now the rx ring. */ for (i = 0; i < SEEQ_RX_BUFFERS; i++) { - if (!sp->rx_desc[i].rdma.pbuf) { - unsigned long buffer; + if (!sp->rx_desc[i].skb) { + dma_addr_t dma_addr; + struct sk_buff *skb = netdev_alloc_skb(dev, PKT_BUF_SZ); - buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); - if (!buffer) + if (skb == NULL) return -ENOMEM; - sp->rx_desc[i].buf_vaddr = CKSEG1ADDR(buffer); - sp->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer); + skb_reserve(skb, 2); + dma_addr = dma_map_single(dev->dev.parent, + skb->data - 2, + PKT_BUF_SZ, DMA_FROM_DEVICE); + sp->rx_desc[i].skb = skb; + sp->rx_desc[i].rdma.pbuf = dma_addr; } sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT; + dma_sync_desc_dev(dev, &sp->rx_desc[i]); } sp->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR; + dma_sync_desc_dev(dev, &sp->rx_desc[i - 1]); return 0; } +static void seeq_purge_ring(struct net_device *dev) +{ + struct sgiseeq_private *sp = netdev_priv(dev); + int i; + + /* clear tx ring. */ + for (i = 0; i < SEEQ_TX_BUFFERS; i++) { + if (sp->tx_desc[i].skb) { + dev_kfree_skb(sp->tx_desc[i].skb); + sp->tx_desc[i].skb = NULL; + } + } + + /* And now the rx ring. */ + for (i = 0; i < SEEQ_RX_BUFFERS; i++) { + if (sp->rx_desc[i].skb) { + dev_kfree_skb(sp->rx_desc[i].skb); + sp->rx_desc[i].skb = NULL; + } + } +} + #ifdef DEBUG static struct sgiseeq_private *gpriv; static struct net_device *gdev; @@ -258,8 +302,8 @@ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp, sregs->tstat = TSTAT_INIT_SEEQ; } - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc); - hregs->tx_ndptr = CPHYSADDR(sp->tx_desc); + hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc); + hregs->tx_ndptr = VIRT_TO_DMA(sp, sp->tx_desc); seeq_go(sp, hregs, sregs); return 0; @@ -283,69 +327,90 @@ static inline void rx_maybe_restart(struct sgiseeq_private *sp, struct sgiseeq_regs *sregs) { if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) { - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc + sp->rx_new); + hregs->rx_ndptr = VIRT_TO_DMA(sp, sp->rx_desc + sp->rx_new); seeq_go(sp, hregs, sregs); } } -#define for_each_rx(rd, sp) for((rd) = &(sp)->rx_desc[(sp)->rx_new]; \ - !((rd)->rdma.cntinfo & HPCDMA_OWN); \ - (rd) = &(sp)->rx_desc[(sp)->rx_new]) - static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp, struct hpc3_ethregs *hregs, struct sgiseeq_regs *sregs) { struct sgiseeq_rx_desc *rd; struct sk_buff *skb = NULL; + struct sk_buff *newskb; unsigned char pkt_status; - unsigned char *pkt_pointer = NULL; int len = 0; unsigned int orig_end = PREV_RX(sp->rx_new); /* Service every received packet. */ - for_each_rx(rd, sp) { + rd = &sp->rx_desc[sp->rx_new]; + dma_sync_desc_cpu(dev, rd); + while (!(rd->rdma.cntinfo & HPCDMA_OWN)) { len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3; - pkt_pointer = (unsigned char *)(long)rd->buf_vaddr; - pkt_status = pkt_pointer[len + 2]; - + dma_unmap_single(dev->dev.parent, rd->rdma.pbuf, + PKT_BUF_SZ, DMA_FROM_DEVICE); + pkt_status = rd->skb->data[len]; if (pkt_status & SEEQ_RSTAT_FIG) { /* Packet is OK. */ - skb = dev_alloc_skb(len + 2); - - if (skb) { - skb_reserve(skb, 2); - skb_put(skb, len); - - /* Copy out of kseg1 to avoid silly cache flush. */ - skb_copy_to_linear_data(skb, pkt_pointer + 2, len); - skb->protocol = eth_type_trans(skb, dev); - - /* We don't want to receive our own packets */ - if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) { + /* We don't want to receive our own packets */ + if (memcmp(rd->skb->data + 6, dev->dev_addr, ETH_ALEN)) { + if (len > rx_copybreak) { + skb = rd->skb; + newskb = netdev_alloc_skb(dev, PKT_BUF_SZ); + if (!newskb) { + newskb = skb; + skb = NULL; + goto memory_squeeze; + } + skb_reserve(newskb, 2); + } else { + skb = netdev_alloc_skb(dev, len + 2); + if (skb) { + skb_reserve(skb, 2); + skb_copy_to_linear_data(skb, rd->skb->data, len); + } + newskb = rd->skb; + } +memory_squeeze: + if (skb) { + skb_put(skb, len); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } else { - /* Silently drop my own packets */ - dev_kfree_skb_irq(skb); + printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", + dev->name); + dev->stats.rx_dropped++; } } else { - printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", - dev->name); - dev->stats.rx_dropped++; + /* Silently drop my own packets */ + newskb = rd->skb; } } else { record_rx_errors(dev, pkt_status); + newskb = rd->skb; } + rd->skb = newskb; + rd->rdma.pbuf = dma_map_single(dev->dev.parent, + newskb->data - 2, + PKT_BUF_SZ, DMA_FROM_DEVICE); /* Return the entry to the ring pool. */ rd->rdma.cntinfo = RCNTINFO_INIT; sp->rx_new = NEXT_RX(sp->rx_new); + dma_sync_desc_dev(dev, rd); + rd = &sp->rx_desc[sp->rx_new]; + dma_sync_desc_cpu(dev, rd); } + dma_sync_desc_cpu(dev, &sp->rx_desc[orig_end]); sp->rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR); + dma_sync_desc_dev(dev, &sp->rx_desc[orig_end]); + dma_sync_desc_cpu(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]); sp->rx_desc[PREV_RX(sp->rx_new)].rdma.cntinfo |= HPCDMA_EOR; + dma_sync_desc_dev(dev, &sp->rx_desc[PREV_RX(sp->rx_new)]); rx_maybe_restart(sp, hregs, sregs); } @@ -358,20 +423,29 @@ static inline void tx_maybe_reset_collisions(struct sgiseeq_private *sp, } } -static inline void kick_tx(struct sgiseeq_tx_desc *td, +static inline void kick_tx(struct net_device *dev, + struct sgiseeq_private *sp, struct hpc3_ethregs *hregs) { + struct sgiseeq_tx_desc *td; + int i = sp->tx_old; + /* If the HPC aint doin nothin, and there are more packets * with ETXD cleared and XIU set we must make very certain * that we restart the HPC else we risk locking up the * adapter. The following code is only safe iff the HPCDMA * is not active! */ + td = &sp->tx_desc[i]; + dma_sync_desc_cpu(dev, td); while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) == - (HPCDMA_XIU | HPCDMA_ETXD)) - td = (struct sgiseeq_tx_desc *)(long) CKSEG1ADDR(td->tdma.pnext); + (HPCDMA_XIU | HPCDMA_ETXD)) { + i = NEXT_TX(i); + td = &sp->tx_desc[i]; + dma_sync_desc_cpu(dev, td); + } if (td->tdma.cntinfo & HPCDMA_XIU) { - hregs->tx_ndptr = CPHYSADDR(td); + hregs->tx_ndptr = VIRT_TO_DMA(sp, td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } } @@ -400,11 +474,12 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) { td = &sp->tx_desc[j]; + dma_sync_desc_cpu(dev, td); if (!(td->tdma.cntinfo & (HPCDMA_XIU))) break; if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) { if (!(status & HPC3_ETXCTRL_ACTIVE)) { - hregs->tx_ndptr = CPHYSADDR(td); + hregs->tx_ndptr = VIRT_TO_DMA(sp, td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } break; @@ -413,6 +488,11 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp sp->tx_old = NEXT_TX(sp->tx_old); td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE); td->tdma.cntinfo |= HPCDMA_EOX; + if (td->skb) { + dev_kfree_skb_any(td->skb); + td->skb = NULL; + } + dma_sync_desc_dev(dev, td); } } @@ -480,6 +560,7 @@ static int sgiseeq_close(struct net_device *dev) /* Shutdown the Seeq. */ reset_hpc3_and_seeq(sp->hregs, sregs); free_irq(irq, dev); + seeq_purge_ring(dev); return 0; } @@ -506,16 +587,22 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) struct hpc3_ethregs *hregs = sp->hregs; unsigned long flags; struct sgiseeq_tx_desc *td; - int skblen, len, entry; + int len, entry; spin_lock_irqsave(&sp->tx_lock, flags); /* Setup... */ - skblen = skb->len; - len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; + len = skb->len; + if (len < ETH_ZLEN) { + if (skb_padto(skb, ETH_ZLEN)) + return 0; + len = ETH_ZLEN; + } + dev->stats.tx_bytes += len; entry = sp->tx_new; td = &sp->tx_desc[entry]; + dma_sync_desc_cpu(dev, td); /* Create entry. There are so many races with adding a new * descriptor to the chain: @@ -530,25 +617,27 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) * entry and the HPC got to the end of the chain before we * added this new entry and restarted it. */ - skb_copy_from_linear_data(skb, (char *)(long)td->buf_vaddr, skblen); - if (len != skblen) - memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen); + td->skb = skb; + td->tdma.pbuf = dma_map_single(dev->dev.parent, skb->data, + len, DMA_TO_DEVICE); td->tdma.cntinfo = (len & HPCDMA_BCNT) | HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX; + dma_sync_desc_dev(dev, td); if (sp->tx_old != sp->tx_new) { struct sgiseeq_tx_desc *backend; backend = &sp->tx_desc[PREV_TX(sp->tx_new)]; + dma_sync_desc_cpu(dev, backend); backend->tdma.cntinfo &= ~HPCDMA_EOX; + dma_sync_desc_dev(dev, backend); } sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */ /* Maybe kick the HPC back into motion. */ if (!(hregs->tx_ctrl & HPC3_ETXCTRL_ACTIVE)) - kick_tx(&sp->tx_desc[sp->tx_old], hregs); + kick_tx(dev, sp, hregs); dev->trans_start = jiffies; - dev_kfree_skb(skb); if (!TX_BUFFS_AVAIL(sp)) netif_stop_queue(dev); @@ -586,33 +675,41 @@ static void sgiseeq_set_multicast(struct net_device *dev) sgiseeq_reset(dev); } -static inline void setup_tx_ring(struct sgiseeq_tx_desc *buf, int nbufs) +static inline void setup_tx_ring(struct net_device *dev, + struct sgiseeq_tx_desc *buf, + int nbufs) { + struct sgiseeq_private *sp = netdev_priv(dev); int i = 0; while (i < (nbufs - 1)) { - buf[i].tdma.pnext = CPHYSADDR(buf + i + 1); + buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf + i + 1); buf[i].tdma.pbuf = 0; + dma_sync_desc_dev(dev, &buf[i]); i++; } - buf[i].tdma.pnext = CPHYSADDR(buf); + buf[i].tdma.pnext = VIRT_TO_DMA(sp, buf); + dma_sync_desc_dev(dev, &buf[i]); } -static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) +static inline void setup_rx_ring(struct net_device *dev, + struct sgiseeq_rx_desc *buf, + int nbufs) { + struct sgiseeq_private *sp = netdev_priv(dev); int i = 0; while (i < (nbufs - 1)) { - buf[i].rdma.pnext = CPHYSADDR(buf + i + 1); + buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf + i + 1); buf[i].rdma.pbuf = 0; + dma_sync_desc_dev(dev, &buf[i]); i++; } buf[i].rdma.pbuf = 0; - buf[i].rdma.pnext = CPHYSADDR(buf); + buf[i].rdma.pnext = VIRT_TO_DMA(sp, buf); + dma_sync_desc_dev(dev, &buf[i]); } -#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) - static int __init sgiseeq_probe(struct platform_device *pdev) { struct sgiseeq_platform_data *pd = pdev->dev.platform_data; @@ -621,7 +718,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev) unsigned int irq = pd->irq; struct sgiseeq_private *sp; struct net_device *dev; - int err, i; + int err; DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof (struct sgiseeq_private)); @@ -635,7 +732,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev) sp = netdev_priv(dev); /* Make private data page aligned */ - sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings), + sr = dma_alloc_noncoherent(&pdev->dev, sizeof(*sp->srings), &sp->srings_dma, GFP_KERNEL); if (!sr) { printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n"); @@ -647,8 +744,8 @@ static int __init sgiseeq_probe(struct platform_device *pdev) sp->tx_desc = sp->srings->txvector; /* A couple calculations now, saves many cycles later. */ - setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); - setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); + setup_rx_ring(dev, sp->rx_desc, SEEQ_RX_BUFFERS); + setup_tx_ring(dev, sp->tx_desc, SEEQ_TX_BUFFERS); memcpy(dev->dev_addr, pd->mac, ETH_ALEN); @@ -716,8 +813,8 @@ static int __exit sgiseeq_remove(struct platform_device *pdev) struct sgiseeq_private *sp = netdev_priv(dev); unregister_netdev(dev); - dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings, - sp->srings_dma); + dma_free_noncoherent(&pdev->dev, sizeof(*sp->srings), sp->srings, + sp->srings_dma); free_netdev(dev); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c deleted file mode 100644 index 228f650250f6..000000000000 --- a/drivers/net/shaper.c +++ /dev/null @@ -1,603 +0,0 @@ -/* - * Simple traffic shaper for Linux NET3. - * - * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. - * http://www.redhat.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide - * warranty for any of this software. This material is provided - * "AS-IS" and at no charge. - * - * - * Algorithm: - * - * Queue Frame: - * Compute time length of frame at regulated speed - * Add frame to queue at appropriate point - * Adjust time length computation for followup frames - * Any frame that falls outside of its boundaries is freed - * - * We work to the following constants - * - * SHAPER_QLEN Maximum queued frames - * SHAPER_LATENCY Bounding latency on a frame. Leaving this latency - * window drops the frame. This stops us queueing - * frames for a long time and confusing a remote - * host. - * SHAPER_MAXSLIP Maximum time a priority frame may jump forward. - * That bounds the penalty we will inflict on low - * priority traffic. - * SHAPER_BURST Time range we call "now" in order to reduce - * system load. The more we make this the burstier - * the behaviour, the better local performance you - * get through packet clustering on routers and the - * worse the remote end gets to judge rtts. - * - * This is designed to handle lower speed links ( < 200K/second or so). We - * run off a 100-150Hz base clock typically. This gives us a resolution at - * 200Kbit/second of about 2Kbit or 256 bytes. Above that our timer - * resolution may start to cause much more burstiness in the traffic. We - * could avoid a lot of that by calling kick_shaper() at the end of the - * tied device transmissions. If you run above about 100K second you - * may need to tune the supposed speed rate for the right values. - * - * BUGS: - * Downing the interface under the shaper before the shaper - * will render your machine defunct. Don't for now shape over - * PPP or SLIP therefore! - * This will be fixed in BETA4 - * - * Update History : - * - * bh_atomic() SMP races fixes and rewritten the locking code to - * be SMP safe and irq-mask friendly. - * NOTE: we can't use start_bh_atomic() in kick_shaper() - * because it's going to be recalled from an irq handler, - * and synchronize_bh() is a nono if called from irq context. - * 1999 Andrea Arcangeli - * - * Device statistics (tx_pakets, tx_bytes, - * tx_drops: queue_over_time and collisions: max_queue_exceded) - * 1999/06/18 Jordi Murgo <savage@apostols.org> - * - * Use skb->cb for private data. - * 2000/03 Andi Kleen - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/if_arp.h> -#include <linux/init.h> -#include <linux/if_shaper.h> -#include <linux/jiffies.h> - -#include <net/dst.h> -#include <net/arp.h> -#include <net/net_namespace.h> - -struct shaper_cb { - unsigned long shapeclock; /* Time it should go out */ - unsigned long shapestamp; /* Stamp for shaper */ - __u32 shapelatency; /* Latency on frame */ - __u32 shapelen; /* Frame length in clocks */ - __u16 shapepend; /* Pending */ -}; -#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb)) - -static int sh_debug; /* Debug flag */ - -#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" - -static void shaper_kick(struct shaper *sh); - -/* - * Compute clocks on a buffer - */ - -static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb) -{ - int t=skb->len/shaper->bytespertick; - return t; -} - -/* - * Set the speed of a shaper. We compute this in bytes per tick since - * thats how the machine wants to run. Quoted input is in bits per second - * as is traditional (note not BAUD). We assume 8 bit bytes. - */ - -static void shaper_setspeed(struct shaper *shaper, int bitspersec) -{ - shaper->bitspersec=bitspersec; - shaper->bytespertick=(bitspersec/HZ)/8; - if(!shaper->bytespertick) - shaper->bytespertick++; -} - -/* - * Throw a frame at a shaper. - */ - - -static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct shaper *shaper = dev->priv; - struct sk_buff *ptr; - - spin_lock(&shaper->lock); - ptr=shaper->sendq.prev; - - /* - * Set up our packet details - */ - - SHAPERCB(skb)->shapelatency=0; - SHAPERCB(skb)->shapeclock=shaper->recovery; - if(time_before(SHAPERCB(skb)->shapeclock, jiffies)) - SHAPERCB(skb)->shapeclock=jiffies; - skb->priority=0; /* short term bug fix */ - SHAPERCB(skb)->shapestamp=jiffies; - - /* - * Time slots for this packet. - */ - - SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb); - - { - struct sk_buff *tmp; - /* - * Up our shape clock by the time pending on the queue - * (Should keep this in the shaper as a variable..) - */ - for(tmp=skb_peek(&shaper->sendq); tmp!=NULL && - tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next) - SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen; - /* - * Queue over time. Spill packet. - */ - if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) { - dev_kfree_skb(skb); - dev->stats.tx_dropped++; - } else - skb_queue_tail(&shaper->sendq, skb); - } - - if(sh_debug) - printk("Frame queued.\n"); - if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN) - { - ptr=skb_dequeue(&shaper->sendq); - dev_kfree_skb(ptr); - dev->stats.collisions++; - } - shaper_kick(shaper); - spin_unlock(&shaper->lock); - return 0; -} - -/* - * Transmit from a shaper - */ - -static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb) -{ - struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC); - if(sh_debug) - printk("Kick frame on %p\n",newskb); - if(newskb) - { - newskb->dev=shaper->dev; - newskb->priority=2; - if(sh_debug) - printk("Kick new frame to %s, %d\n", - shaper->dev->name,newskb->priority); - dev_queue_xmit(newskb); - - shaper->dev->stats.tx_bytes += skb->len; - shaper->dev->stats.tx_packets++; - - if(sh_debug) - printk("Kicked new frame out.\n"); - dev_kfree_skb(skb); - } -} - -/* - * Timer handler for shaping clock - */ - -static void shaper_timer(unsigned long data) -{ - struct shaper *shaper = (struct shaper *)data; - - spin_lock(&shaper->lock); - shaper_kick(shaper); - spin_unlock(&shaper->lock); -} - -/* - * Kick a shaper queue and try and do something sensible with the - * queue. - */ - -static void shaper_kick(struct shaper *shaper) -{ - struct sk_buff *skb; - - /* - * Walk the list (may be empty) - */ - - while((skb=skb_peek(&shaper->sendq))!=NULL) - { - /* - * Each packet due to go out by now (within an error - * of SHAPER_BURST) gets kicked onto the link - */ - - if(sh_debug) - printk("Clock = %ld, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies); - if(time_before_eq(SHAPERCB(skb)->shapeclock, jiffies + SHAPER_BURST)) - { - /* - * Pull the frame and get interrupts back on. - */ - - skb_unlink(skb, &shaper->sendq); - if (shaper->recovery < - SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen) - shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen; - /* - * Pass on to the physical target device via - * our low level packet thrower. - */ - - SHAPERCB(skb)->shapepend=0; - shaper_queue_xmit(shaper, skb); /* Fire */ - } - else - break; - } - - /* - * Next kick. - */ - - if(skb!=NULL) - mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); -} - - -/* - * Bring the interface up. We just disallow this until a - * bind. - */ - -static int shaper_open(struct net_device *dev) -{ - struct shaper *shaper=dev->priv; - - /* - * Can't open until attached. - * Also can't open until speed is set, or we'll get - * a division by zero. - */ - - if(shaper->dev==NULL) - return -ENODEV; - if(shaper->bitspersec==0) - return -EINVAL; - return 0; -} - -/* - * Closing a shaper flushes the queues. - */ - -static int shaper_close(struct net_device *dev) -{ - struct shaper *shaper=dev->priv; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&shaper->sendq)) != NULL) - dev_kfree_skb(skb); - - spin_lock_bh(&shaper->lock); - shaper_kick(shaper); - spin_unlock_bh(&shaper->lock); - - del_timer_sync(&shaper->timer); - return 0; -} - -/* - * Revectored calls. We alter the parameters and call the functions - * for our attached device. This enables us to bandwidth allocate after - * ARP and other resolutions and not before. - */ - -static int shaper_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned len) -{ - struct shaper *sh=dev->priv; - int v; - if(sh_debug) - printk("Shaper header\n"); - skb->dev = sh->dev; - v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len); - skb->dev = dev; - return v; -} - -static int shaper_rebuild_header(struct sk_buff *skb) -{ - struct shaper *sh=skb->dev->priv; - struct net_device *dev=skb->dev; - int v; - if(sh_debug) - printk("Shaper rebuild header\n"); - skb->dev=sh->dev; - v = sh->dev->header_ops->rebuild(skb); - skb->dev=dev; - return v; -} - -#if 0 -static int shaper_cache(struct neighbour *neigh, struct hh_cache *hh) -{ - struct shaper *sh=neigh->dev->priv; - struct net_device *tmp; - int ret; - if(sh_debug) - printk("Shaper header cache bind\n"); - tmp=neigh->dev; - neigh->dev=sh->dev; - ret=sh->hard_header_cache(neigh,hh); - neigh->dev=tmp; - return ret; -} - -static void shaper_cache_update(struct hh_cache *hh, struct net_device *dev, - unsigned char *haddr) -{ - struct shaper *sh=dev->priv; - if(sh_debug) - printk("Shaper cache update\n"); - sh->header_cache_update(hh, sh->dev, haddr); -} -#endif - -#ifdef CONFIG_INET - -static int shaper_neigh_setup(struct neighbour *n) -{ -#ifdef CONFIG_INET - if (n->nud_state == NUD_NONE) { - n->ops = &arp_broken_ops; - n->output = n->ops->output; - } -#endif - return 0; -} - -static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ -#ifdef CONFIG_INET - if (p->tbl->family == AF_INET) { - p->neigh_setup = shaper_neigh_setup; - p->ucast_probes = 0; - p->mcast_probes = 0; - } -#endif - return 0; -} - -#else /* !(CONFIG_INET) */ - -static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ - return 0; -} - -#endif - -static const struct header_ops shaper_ops = { - .create = shaper_header, - .rebuild = shaper_rebuild_header, -}; - -static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev) -{ - sh->dev = dev; - sh->get_stats=dev->get_stats; - - shdev->neigh_setup = shaper_neigh_setup_dev; - shdev->hard_header_len=dev->hard_header_len; - shdev->type=dev->type; - shdev->addr_len=dev->addr_len; - shdev->mtu=dev->mtu; - sh->bitspersec=0; - return 0; -} - -static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_ifru; - struct shaper *sh=dev->priv; - - if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED) - { - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - } - - switch(ss->ss_cmd) - { - case SHAPER_SET_DEV: - { - struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name); - if(them==NULL) - return -ENODEV; - if(sh->dev) - return -EBUSY; - return shaper_attach(dev,dev->priv, them); - } - case SHAPER_GET_DEV: - if(sh->dev==NULL) - return -ENODEV; - strcpy(ss->ss_name, sh->dev->name); - return 0; - case SHAPER_SET_SPEED: - shaper_setspeed(sh,ss->ss_speed); - return 0; - case SHAPER_GET_SPEED: - ss->ss_speed=sh->bitspersec; - return 0; - default: - return -EINVAL; - } -} - -static void shaper_init_priv(struct net_device *dev) -{ - struct shaper *sh = dev->priv; - - skb_queue_head_init(&sh->sendq); - init_timer(&sh->timer); - sh->timer.function=shaper_timer; - sh->timer.data=(unsigned long)sh; - spin_lock_init(&sh->lock); -} - -/* - * Add a shaper device to the system - */ - -static void __init shaper_setup(struct net_device *dev) -{ - /* - * Set up the shaper. - */ - - shaper_init_priv(dev); - - dev->open = shaper_open; - dev->stop = shaper_close; - dev->hard_start_xmit = shaper_start_xmit; - dev->set_multicast_list = NULL; - - /* - * Intialise the packet queues - */ - - /* - * Handlers for when we attach to a device. - */ - - dev->neigh_setup = shaper_neigh_setup_dev; - dev->do_ioctl = shaper_ioctl; - dev->hard_header_len = 0; - dev->type = ARPHRD_ETHER; /* initially */ - dev->set_mac_address = NULL; - dev->mtu = 1500; - dev->addr_len = 0; - dev->tx_queue_len = 10; - dev->flags = 0; -} - -static int shapers = 1; -#ifdef MODULE - -module_param(shapers, int, 0); -MODULE_PARM_DESC(shapers, "Traffic shaper: maximum number of shapers"); - -#else /* MODULE */ - -static int __init set_num_shapers(char *str) -{ - shapers = simple_strtol(str, NULL, 0); - return 1; -} - -__setup("shapers=", set_num_shapers); - -#endif /* MODULE */ - -static struct net_device **devs; - -static unsigned int shapers_registered = 0; - -static int __init shaper_init(void) -{ - int i; - size_t alloc_size; - struct net_device *dev; - char name[IFNAMSIZ]; - - if (shapers < 1) - return -ENODEV; - - alloc_size = sizeof(*dev) * shapers; - devs = kzalloc(alloc_size, GFP_KERNEL); - if (!devs) - return -ENOMEM; - - for (i = 0; i < shapers; i++) { - - snprintf(name, IFNAMSIZ, "shaper%d", i); - dev = alloc_netdev(sizeof(struct shaper), name, - shaper_setup); - if (!dev) - break; - - if (register_netdev(dev)) { - free_netdev(dev); - break; - } - - devs[i] = dev; - shapers_registered++; - } - - if (!shapers_registered) { - kfree(devs); - devs = NULL; - } - - return (shapers_registered ? 0 : -ENODEV); -} - -static void __exit shaper_exit (void) -{ - int i; - - for (i = 0; i < shapers_registered; i++) { - if (devs[i]) { - unregister_netdev(devs[i]); - free_netdev(devs[i]); - } - } - - kfree(devs); - devs = NULL; -} - -module_init(shaper_init); -module_exit(shaper_exit); -MODULE_LICENSE("GPL"); - diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 7eab072ae792..b570402f7fed 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -372,7 +372,7 @@ static void __mdio_cmd(void __iomem *ioaddr, u32 ctl) msleep(1); } - if (i > 999) + if (i > 99) printk(KERN_ERR PFX "PHY command failed !\n"); } @@ -847,10 +847,8 @@ static void sis190_soft_reset(void __iomem *ioaddr) { SIS_W32(IntrControl, 0x8000); SIS_PCI_COMMIT(); - msleep(1); SIS_W32(IntrControl, 0x0); sis190_asic_down(ioaddr); - msleep(1); } static void sis190_hw_start(struct net_device *dev) @@ -1041,8 +1039,6 @@ static int sis190_open(struct net_device *dev) if (rc < 0) goto err_free_rx_1; - INIT_WORK(&tp->phy_task, sis190_phy_task); - sis190_request_timer(dev); rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev); @@ -1549,28 +1545,31 @@ static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, } /** - * sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model + * sis190_get_mac_addr_from_apc - Get MAC address for SiS96x model * @pdev: PCI device * @dev: network device to get address for * - * SiS965 model, use APC CMOS RAM to store MAC address. + * SiS96x model, use APC CMOS RAM to store MAC address. * APC CMOS RAM is accessed through ISA bridge. * MAC address is read into @net_dev->dev_addr. */ static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev, struct net_device *dev) { + static const u16 __devinitdata ids[] = { 0x0965, 0x0966, 0x0968 }; struct sis190_private *tp = netdev_priv(dev); struct pci_dev *isa_bridge; u8 reg, tmp8; - int i; + unsigned int i; net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n", pci_name(pdev)); - isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL); - if (!isa_bridge) - isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0966, NULL); + for (i = 0; i < ARRAY_SIZE(ids); i++) { + isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, ids[i], NULL); + if (isa_bridge) + break; + } if (!isa_bridge) { net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n", diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 0857d2c88aa0..ec95e493ac1c 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -419,7 +419,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, i = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK); if(i){ - printk(KERN_ERR "sis900.c: architecture does not support" + printk(KERN_ERR "sis900.c: architecture does not support " "32bit PCI busmaster DMA\n"); return i; } @@ -1667,7 +1667,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) /* something strange happened !!! */ if (status & HIBERR) { if(netif_msg_intr(sis_priv)) - printk(KERN_INFO "%s: Abnormal interrupt," + printk(KERN_INFO "%s: Abnormal interrupt, " "status %#8.8x.\n", net_dev->name, status); break; } @@ -1820,7 +1820,7 @@ refill_rx_ring: * how the hardware will react to this kind * of degenerated buffer */ if (netif_msg_rx_err(sis_priv)) - printk(KERN_INFO "%s: Memory squeeze," + printk(KERN_INFO "%s: Memory squeeze, " "deferring packet.\n", net_dev->name); net_dev->stats.rx_dropped++; diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c index 0a6f67a7a395..fde45083eb7b 100644 --- a/drivers/net/sk98lin/skgemib.c +++ b/drivers/net/sk98lin/skgemib.c @@ -82,7 +82,7 @@ PNMI_STATIC int DiagActions(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id, /* defines *******************************************************************/ -#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0])) +#define ID_TABLE_SIZE ARRAY_SIZE(IdTable) /* global variables **********************************************************/ diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c index b36dd9ac6b29..876bb2158fa6 100644 --- a/drivers/net/sk98lin/skgepnmi.c +++ b/drivers/net/sk98lin/skgepnmi.c @@ -383,23 +383,11 @@ int Level) /* Initialization level */ SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG); SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL, - ("CounterOffset struct size (%d) differs from" + ("CounterOffset struct size (%d) differs from " "SK_PNMI_MAX_IDX (%d)\n", SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX)); } - if (SK_PNMI_MAX_IDX != - (sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) { - - SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG); - - SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL, - ("StatAddr table size (%d) differs from " - "SK_PNMI_MAX_IDX (%d)\n", - (sizeof(StatAddr) / - (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)), - SK_PNMI_MAX_IDX)); - } #endif /* SK_PNMI_CHECK */ break; diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c index 3e7aa49afd00..e5ee6d63ba4e 100644 --- a/drivers/net/sk98lin/skgesirq.c +++ b/drivers/net/sk98lin/skgesirq.c @@ -892,7 +892,7 @@ int Port) /* Which port should be checked */ */ RxCts = 0; - for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) { + for (i = 0; i < ARRAY_SIZE(SkGeRxRegs); i++) { (void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp); diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c index 438f424e6361..8a430a366547 100644 --- a/drivers/net/skfp/hwmtm.c +++ b/drivers/net/skfp/hwmtm.c @@ -1746,7 +1746,7 @@ static void queue_llc_rx(struct s_smc *smc, SMbuf *mb) DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ; smc->os.hwm.queued_rx_frames++ ; mb->sm_next = (SMbuf *)NULL ; - if (smc->os.hwm.llc_rx_pipe == 0) { + if (smc->os.hwm.llc_rx_pipe == NULL) { smc->os.hwm.llc_rx_pipe = mb ; } else { @@ -1786,7 +1786,7 @@ static void queue_txd_mb(struct s_smc *smc, SMbuf *mb) DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ; smc->os.hwm.queued_txd_mb++ ; mb->sm_next = (SMbuf *)NULL ; - if (smc->os.hwm.txd_tx_pipe == 0) { + if (smc->os.hwm.txd_tx_pipe == NULL) { smc->os.hwm.txd_tx_pipe = mb ; } else { diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c index ced2c8f76be7..ffbfb1b79f97 100644 --- a/drivers/net/skfp/smt.c +++ b/drivers/net/skfp/smt.c @@ -712,7 +712,7 @@ void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs) smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; DB_SMT("SMT: received ECF reply from %s\n", addr_to_string(&sm->smt_source),0) ; - if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) { + if (sm_to_para(smc,sm,SMT_P_ECHODATA) == NULL) { DB_SMT("SMT: ECHODATA missing\n",0,0) ; break ; } diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index bc15940ce1bc..626190eb91e7 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.20" +#define DRV_VERSION "1.21" #define PFX DRV_NAME " " /* @@ -64,7 +64,6 @@ #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) #define RX_MAX_PENDING (RX_LE_SIZE/6 - 2) #define RX_DEF_PENDING RX_MAX_PENDING -#define RX_SKB_ALIGN 8 #define TX_RING_SIZE 512 #define TX_DEF_PENDING (TX_RING_SIZE - 1) @@ -135,6 +134,8 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436C) }, /* 88E8072 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436D) }, /* 88E8055 */ + { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4370) }, /* 88E8075 */ { 0 } }; @@ -548,6 +549,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: + case CHIP_ID_YUKON_SUPR: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* select page 3 to access LED control register */ @@ -714,23 +716,33 @@ static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) { struct net_device *dev = hw->dev[port]; - if (dev->mtu <= ETH_DATA_LEN) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_DIS | TX_STFW_ENA); + if ( (hw->chip_id == CHIP_ID_YUKON_EX && + hw->chip_rev != CHIP_REV_YU_EX_A0) || + hw->chip_id == CHIP_ID_YUKON_FE_P || + hw->chip_id == CHIP_ID_YUKON_SUPR) { + /* Yukon-Extreme B0 and further Extreme devices */ + /* enable Store & Forward mode for TX */ - else if (hw->chip_id != CHIP_ID_YUKON_EC_U) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_STFW_ENA | TX_JUMBO_ENA); - else { - /* set Tx GMAC FIFO Almost Empty Threshold */ - sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), - (ECU_JUMBO_WM << 16) | ECU_AE_THR); + if (dev->mtu <= ETH_DATA_LEN) + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_ENA | TX_STFW_DIS); + else + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_ENA| TX_STFW_ENA); + } else { + if (dev->mtu <= ETH_DATA_LEN) + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_ENA); + else { + /* set Tx GMAC FIFO Almost Empty Threshold */ + sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), + (ECU_JUMBO_WM << 16) | ECU_AE_THR); - /* Can't do offload because of lack of store/forward */ - dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_STFW_DIS); + + /* Can't do offload because of lack of store/forward */ + dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); + } } } @@ -1174,24 +1186,32 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp /* * Allocate an skb for receiving. If the MTU is large enough * make the skb non-linear with a fragment list of pages. - * - * It appears the hardware has a bug in the FIFO logic that - * cause it to hang if the FIFO gets overrun and the receive buffer - * is not 64 byte aligned. The buffer returned from netdev_alloc_skb is - * aligned except if slab debugging is enabled. */ static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2) { struct sk_buff *skb; - unsigned long p; int i; - skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + RX_SKB_ALIGN); - if (!skb) - goto nomem; - - p = (unsigned long) skb->data; - skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p); + if (sky2->hw->flags & SKY2_HW_FIFO_HANG_CHECK) { + unsigned char *start; + /* + * Workaround for a bug in FIFO that cause hang + * if the FIFO if the receive buffer is not 64 byte aligned. + * The buffer returned from netdev_alloc_skb is + * aligned except if slab debugging is enabled. + */ + skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + 8); + if (!skb) + goto nomem; + start = PTR_ALIGN(skb->data, 8); + skb_reserve(skb, start - skb->data); + } else { + skb = netdev_alloc_skb(sky2->netdev, + sky2->rx_data_size + NET_IP_ALIGN); + if (!skb) + goto nomem; + skb_reserve(skb, NET_IP_ALIGN); + } for (i = 0; i < sky2->rx_nfrags; i++) { struct page *page = alloc_page(GFP_ATOMIC); @@ -1227,7 +1247,7 @@ static int sky2_rx_start(struct sky2_port *sky2) struct sky2_hw *hw = sky2->hw; struct rx_ring_info *re; unsigned rxq = rxqaddr[sky2->port]; - unsigned i, size, space, thresh; + unsigned i, size, thresh; sky2->rx_put = sky2->rx_next = 0; sky2_qset(hw, rxq); @@ -1254,28 +1274,18 @@ static int sky2_rx_start(struct sky2_port *sky2) /* Stopping point for hardware truncation */ thresh = (size - 8) / sizeof(u32); - /* Account for overhead of skb - to avoid order > 0 allocation */ - space = SKB_DATA_ALIGN(size) + NET_SKB_PAD - + sizeof(struct skb_shared_info); - - sky2->rx_nfrags = space >> PAGE_SHIFT; + sky2->rx_nfrags = size >> PAGE_SHIFT; BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr)); - if (sky2->rx_nfrags != 0) { - /* Compute residue after pages */ - space = sky2->rx_nfrags << PAGE_SHIFT; + /* Compute residue after pages */ + size -= sky2->rx_nfrags << PAGE_SHIFT; - if (space < size) - size -= space; - else - size = 0; + /* Optimize to handle small packets and headers */ + if (size < copybreak) + size = copybreak; + if (size < ETH_HLEN) + size = ETH_HLEN; - /* Optimize to handle small packets and headers */ - if (size < copybreak) - size = copybreak; - if (size < ETH_HLEN) - size = ETH_HLEN; - } sky2->rx_data_size = size; /* Fill Rx ring */ @@ -2663,6 +2673,7 @@ static u32 sky2_mhz(const struct sky2_hw *hw) case CHIP_ID_YUKON_EC: case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: + case CHIP_ID_YUKON_SUPR: return 125; case CHIP_ID_YUKON_FE: @@ -2746,6 +2757,15 @@ static int __devinit sky2_init(struct sky2_hw *hw) | SKY2_HW_AUTO_TX_SUM | SKY2_HW_ADV_POWER_CTL; break; + + case CHIP_ID_YUKON_SUPR: + hw->flags = SKY2_HW_GIGABIT + | SKY2_HW_NEWER_PHY + | SKY2_HW_NEW_LE + | SKY2_HW_AUTO_TX_SUM + | SKY2_HW_ADV_POWER_CTL; + break; + default: dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", hw->chip_id); @@ -2816,7 +2836,8 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); - if (hw->chip_id == CHIP_ID_YUKON_EX) + if (hw->chip_id == CHIP_ID_YUKON_EX || + hw->chip_id == CHIP_ID_YUKON_SUPR) sky2_write16(hw, SK_REG(i, GMAC_CTRL), GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON | GMC_BYP_RETR_ON); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index ffe9b8a50a1b..2bced1a0898f 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -425,12 +425,13 @@ enum { /* B2_CHIP_ID 8 bit Chip Identification Number */ enum { - CHIP_ID_YUKON_XL = 0xb3, /* Chip ID for YUKON-2 XL */ - CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */ - CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */ - CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */ - CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */ - CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */ + CHIP_ID_YUKON_XL = 0xb3, /* YUKON-2 XL */ + CHIP_ID_YUKON_EC_U = 0xb4, /* YUKON-2 EC Ultra */ + CHIP_ID_YUKON_EX = 0xb5, /* YUKON-2 Extreme */ + CHIP_ID_YUKON_EC = 0xb6, /* YUKON-2 EC */ + CHIP_ID_YUKON_FE = 0xb7, /* YUKON-2 FE */ + CHIP_ID_YUKON_FE_P = 0xb8, /* YUKON-2 FE+ */ + CHIP_ID_YUKON_SUPR = 0xb9, /* YUKON-2 Supreme */ }; enum yukon_ec_rev { CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index 0adab709ab68..d640c0f5470b 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -174,7 +174,7 @@ put16(unsigned char *cp, unsigned short x) /* Encode a number */ -unsigned char * +static unsigned char * encode(unsigned char *cp, unsigned short n) { if(n >= 256 || n == 0){ @@ -199,7 +199,7 @@ pull16(unsigned char **cpp) } /* Decode a number */ -long +static long decode(unsigned char **cpp) { register int x; @@ -233,6 +233,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, register unsigned char *cp = new_seq; struct iphdr *ip; struct tcphdr *th, *oth; + __sum16 csum; /* @@ -428,7 +429,7 @@ found: /* Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ - deltaA = ntohs(th->check); + csum = th->check; memcpy(&cs->cs_ip,ip,20); memcpy(&cs->cs_tcp,th,20); /* We want to use the original packet as our compressed packet. @@ -449,7 +450,8 @@ found: *cpp = ocp; *cp++ = changes; } - cp = put16(cp,(short)deltaA); /* Write TCP checksum */ + *(__sum16 *)cp = csum; + cp += 2; /* deltaS is now the size of the change section of the compressed header */ memcpy(cp,new_seq,deltaS); /* Write list of deltas */ memcpy(cp+deltaS,icp+hlen,isize-hlen); @@ -519,10 +521,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) thp = &cs->cs_tcp; ip = &cs->cs_ip; - if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */ - goto bad; - } - thp->check = htons(x); + thp->check = *(__sum16 *)cp; + cp += 2; thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; /* diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 251a3ce376ac..5a55ede352f4 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -11,9 +11,11 @@ * Fixes: * Alan Cox : Sanity checks and avoid tx overruns. * Has a new sl->mtu field. - * Alan Cox : Found cause of overrun. ifconfig sl0 mtu upwards. - * Driver now spots this and grows/shrinks its buffers(hack!). - * Memory leak if you run out of memory setting up a slip driver fixed. + * Alan Cox : Found cause of overrun. ifconfig sl0 + * mtu upwards. Driver now spots this + * and grows/shrinks its buffers(hack!). + * Memory leak if you run out of memory + * setting up a slip driver fixed. * Matt Dillon : Printable slip (borrowed from NET2E) * Pauline Middelink : Slip driver fixes. * Alan Cox : Honours the old SL_COMPRESSED flag @@ -29,7 +31,8 @@ * buffering from 4096 to 256 bytes. * Improving SLIP response time. * CONFIG_SLIP_MODE_SLIP6. - * ifconfig sl? up & down now works correctly. + * ifconfig sl? up & down now works + * correctly. * Modularization. * Alan Cox : Oops - fix AX.25 buffer lengths * Dmitry Gorodchanin : Even more cleanups. Preserve CSLIP @@ -43,15 +46,18 @@ * device entries, just reg./unreg. them * as they are needed. We kfree() them * at module cleanup. - * With MODULE-loading ``insmod'', user can - * issue parameter: slip_maxdev=1024 - * (Or how much he/she wants.. Default is 256) - * * Stanislav Voronyi : Slip line checking, with ideas taken - * from multislip BSDI driver which was written - * by Igor Chechik, RELCOM Corp. Only algorithms - * have been ported to Linux SLIP driver. + * With MODULE-loading ``insmod'', user + * can issue parameter: slip_maxdev=1024 + * (Or how much he/she wants.. Default + * is 256) + * Stanislav Voronyi : Slip line checking, with ideas taken + * from multislip BSDI driver which was + * written by Igor Chechik, RELCOM Corp. + * Only algorithms have been ported to + * Linux SLIP driver. * Vitaly E. Lavrov : Sane behaviour on tty hangup. - * Alexey Kuznetsov : Cleanup interfaces to tty&netdevice modules. + * Alexey Kuznetsov : Cleanup interfaces to tty & netdevice + * modules. */ #define SL_CHECK_TRANSMIT @@ -99,7 +105,7 @@ static void slip_unesc6(struct slip *sl, unsigned char c); #ifdef CONFIG_SLIP_SMART static void sl_keepalive(unsigned long sls); static void sl_outfill(unsigned long sls); -static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd); +static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); #endif /******************************** @@ -117,15 +123,14 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd); Allocate channel buffers. */ -static int -sl_alloc_bufs(struct slip *sl, int mtu) +static int sl_alloc_bufs(struct slip *sl, int mtu) { int err = -ENOBUFS; unsigned long len; - char * rbuff = NULL; - char * xbuff = NULL; + char *rbuff = NULL; + char *xbuff = NULL; #ifdef SL_INCLUDE_CSLIP - char * cbuff = NULL; + char *cbuff = NULL; struct slcompress *slcomp = NULL; #endif @@ -195,8 +200,7 @@ err_exit: } /* Free a SLIP channel buffers. */ -static void -sl_free_bufs(struct slip *sl) +static void sl_free_bufs(struct slip *sl) { /* Free all SLIP frame buffers. */ kfree(xchg(&sl->rbuff, NULL)); @@ -248,7 +252,6 @@ static int sl_realloc_bufs(struct slip *sl, int mtu) } goto done; } - spin_lock_bh(&sl->lock); err = -ENODEV; @@ -298,23 +301,20 @@ done: /* Set the "sending" flag. This must be atomic hence the set_bit. */ -static inline void -sl_lock(struct slip *sl) +static inline void sl_lock(struct slip *sl) { netif_stop_queue(sl->dev); } /* Clear the "sending" flag. This must be atomic, hence the ASM. */ -static inline void -sl_unlock(struct slip *sl) +static inline void sl_unlock(struct slip *sl) { netif_wake_queue(sl->dev); } /* Send one completely decapsulated IP datagram to the IP layer. */ -static void -sl_bump(struct slip *sl) +static void sl_bump(struct slip *sl) { struct sk_buff *skb; int count; @@ -322,22 +322,22 @@ sl_bump(struct slip *sl) count = sl->rcount; #ifdef SL_INCLUDE_CSLIP if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { - unsigned char c; - if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) { + unsigned char c = sl->rbuff[0]; + if (c & SL_TYPE_COMPRESSED_TCP) { /* ignore compressed packets when CSLIP is off */ if (!(sl->mode & SL_MODE_CSLIP)) { printk(KERN_WARNING "%s: compressed packet ignored\n", sl->dev->name); return; } - /* make sure we've reserved enough space for uncompress to use */ + /* make sure we've reserved enough space for uncompress + to use */ if (count + 80 > sl->buffsize) { sl->rx_over_errors++; return; } count = slhc_uncompress(sl->slcomp, sl->rbuff, count); - if (count <= 0) { + if (count <= 0) return; - } } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { if (!(sl->mode & SL_MODE_CSLIP)) { /* turn on header compression */ @@ -346,33 +346,31 @@ sl_bump(struct slip *sl) printk(KERN_INFO "%s: header compression turned on\n", sl->dev->name); } sl->rbuff[0] &= 0x4f; - if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) { + if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) return; - } } } #endif /* SL_INCLUDE_CSLIP */ - sl->rx_bytes+=count; + sl->rx_bytes += count; skb = dev_alloc_skb(count); - if (skb == NULL) { + if (skb == NULL) { printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name); sl->rx_dropped++; return; } skb->dev = sl->dev; - memcpy(skb_put(skb,count), sl->rbuff, count); + memcpy(skb_put(skb, count), sl->rbuff, count); skb_reset_mac_header(skb); - skb->protocol=htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); netif_rx(skb); sl->dev->last_rx = jiffies; sl->rx_packets++; } /* Encapsulate one IP datagram and stuff into a TTY queue. */ -static void -sl_encaps(struct slip *sl, unsigned char *icp, int len) +static void sl_encaps(struct slip *sl, unsigned char *icp, int len) { unsigned char *p; int actual, count; @@ -386,12 +384,11 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len) p = icp; #ifdef SL_INCLUDE_CSLIP - if (sl->mode & SL_MODE_CSLIP) { + if (sl->mode & SL_MODE_CSLIP) len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); - } #endif #ifdef CONFIG_SLIP_MODE_SLIP6 - if(sl->mode & SL_MODE_SLIP6) + if (sl->mode & SL_MODE_SLIP6) count = slip_esc6(p, (unsigned char *) sl->xbuff, len); else #endif @@ -425,12 +422,12 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len) static void slip_write_wakeup(struct tty_struct *tty) { int actual; - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl = tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) { + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) return; - } + if (sl->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ @@ -463,15 +460,15 @@ static void sl_tx_timeout(struct net_device *dev) /* 20 sec timeout not reached */ goto out; } - printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? - "bad line quality" : "driver error"); + printk(KERN_WARNING "%s: transmit timed out, %s?\n", + dev->name, + (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? + "bad line quality" : "driver error"); sl->xleft = 0; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); sl_unlock(sl); #endif } - out: spin_unlock(&sl->lock); } @@ -484,7 +481,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) struct slip *sl = netdev_priv(dev); spin_lock(&sl->lock); - if (!netif_running(dev)) { + if (!netif_running(dev)) { spin_unlock(&sl->lock); printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); @@ -497,7 +494,7 @@ sl_xmit(struct sk_buff *skb, struct net_device *dev) } sl_lock(sl); - sl->tx_bytes+=skb->len; + sl->tx_bytes += skb->len; sl_encaps(sl, skb->data, skb->len); spin_unlock(&sl->lock); @@ -536,7 +533,7 @@ static int sl_open(struct net_device *dev) { struct slip *sl = netdev_priv(dev); - if (sl->tty==NULL) + if (sl->tty == NULL) return -ENODEV; sl->flags &= (1 << SLF_INUSE); @@ -657,20 +654,19 @@ static void sl_setup(struct net_device *dev) * in parallel */ -static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl = tty->disc_data; - if (!sl || sl->magic != SLIP_MAGIC || - !netif_running(sl->dev)) + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) return; /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) sl->rx_errors++; - } cp++; continue; } @@ -688,7 +684,6 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, ch ************************************/ /* Collect hanged up channels */ - static void sl_sync(void) { int i; @@ -696,21 +691,21 @@ static void sl_sync(void) struct slip *sl; for (i = 0; i < slip_maxdev; i++) { - if ((dev = slip_devs[i]) == NULL) + dev = slip_devs[i]; + if (dev == NULL) break; sl = netdev_priv(dev); if (sl->tty || sl->leased) continue; - if (dev->flags&IFF_UP) + if (dev->flags & IFF_UP) dev_close(dev); } } /* Find a free SLIP channel, and link in this `tty' line. */ -static struct slip * -sl_alloc(dev_t line) +static struct slip *sl_alloc(dev_t line) { int i; int sel = -1; @@ -805,15 +800,15 @@ sl_alloc(dev_t line) spin_lock_init(&sl->lock); sl->mode = SL_MODE_DEFAULT; #ifdef CONFIG_SLIP_SMART - init_timer(&sl->keepalive_timer); /* initialize timer_list struct */ - sl->keepalive_timer.data=(unsigned long)sl; - sl->keepalive_timer.function=sl_keepalive; + /* initialize timer_list struct */ + init_timer(&sl->keepalive_timer); + sl->keepalive_timer.data = (unsigned long)sl; + sl->keepalive_timer.function = sl_keepalive; init_timer(&sl->outfill_timer); - sl->outfill_timer.data=(unsigned long)sl; - sl->outfill_timer.function=sl_outfill; + sl->outfill_timer.data = (unsigned long)sl; + sl->outfill_timer.function = sl_outfill; #endif slip_devs[i] = dev; - return sl; } @@ -832,7 +827,7 @@ static int slip_open(struct tty_struct *tty) struct slip *sl; int err; - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; /* RTnetlink lock is misused here to serialize concurrent @@ -844,7 +839,7 @@ static int slip_open(struct tty_struct *tty) /* Collect hanged up channels. */ sl_sync(); - sl = (struct slip *) tty->disc_data; + sl = tty->disc_data; err = -EEXIST; /* First make sure we're not already connected. */ @@ -853,7 +848,8 @@ static int slip_open(struct tty_struct *tty) /* OK. Find a free SLIP channel to use. */ err = -ENFILE; - if ((sl = sl_alloc(tty_devnum(tty))) == NULL) + sl = sl_alloc(tty_devnum(tty)); + if (sl == NULL) goto err_exit; sl->tty = tty; @@ -863,23 +859,25 @@ static int slip_open(struct tty_struct *tty) if (!test_bit(SLF_INUSE, &sl->flags)) { /* Perform the low-level SLIP initialization. */ - if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0) + err = sl_alloc_bufs(sl, SL_MTU); + if (err) goto err_free_chan; set_bit(SLF_INUSE, &sl->flags); - if ((err = register_netdevice(sl->dev))) + err = register_netdevice(sl->dev); + if (err) goto err_free_bufs; } #ifdef CONFIG_SLIP_SMART if (sl->keepalive) { - sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; - add_timer (&sl->keepalive_timer); + sl->keepalive_timer.expires = jiffies + sl->keepalive * HZ; + add_timer(&sl->keepalive_timer); } if (sl->outfill) { - sl->outfill_timer.expires=jiffies+sl->outfill*HZ; - add_timer (&sl->outfill_timer); + sl->outfill_timer.expires = jiffies + sl->outfill * HZ; + add_timer(&sl->outfill_timer); } #endif @@ -928,10 +926,9 @@ err_exit: * This means flushing out any pending queues, and then returning. This * call is serialized against other ldisc functions. */ -static void -slip_close(struct tty_struct *tty) +static void slip_close(struct tty_struct *tty) { - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty) @@ -955,8 +952,7 @@ slip_close(struct tty_struct *tty) * STANDARD SLIP ENCAPSULATION * ************************************************************************/ -static int -slip_esc(unsigned char *s, unsigned char *d, int len) +static int slip_esc(unsigned char *s, unsigned char *d, int len) { unsigned char *ptr = d; unsigned char c; @@ -975,16 +971,16 @@ slip_esc(unsigned char *s, unsigned char *d, int len) */ while (len-- > 0) { - switch(c = *s++) { - case END: + switch (c = *s++) { + case END: *ptr++ = ESC; *ptr++ = ESC_END; break; - case ESC: + case ESC: *ptr++ = ESC; *ptr++ = ESC_ESC; break; - default: + default: *ptr++ = c; break; } @@ -996,33 +992,31 @@ slip_esc(unsigned char *s, unsigned char *d, int len) static void slip_unesc(struct slip *sl, unsigned char s) { - switch(s) { - case END: + switch (s) { + case END: #ifdef CONFIG_SLIP_SMART /* drop keeptest bit = VSV */ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); #endif - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) + && (sl->rcount > 2)) sl_bump(sl); - } clear_bit(SLF_ESCAPE, &sl->flags); sl->rcount = 0; return; - case ESC: + case ESC: set_bit(SLF_ESCAPE, &sl->flags); return; - case ESC_ESC: - if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { + case ESC_ESC: + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) s = ESC; - } break; - case ESC_END: - if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) { + case ESC_END: + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) s = END; - } break; } if (!test_bit(SLF_ERROR, &sl->flags)) { @@ -1041,8 +1035,7 @@ static void slip_unesc(struct slip *sl, unsigned char s) * 6 BIT SLIP ENCAPSULATION * ************************************************************************/ -int -slip_esc6(unsigned char *s, unsigned char *d, int len) +static int slip_esc6(unsigned char *s, unsigned char *d, int len) { unsigned char *ptr = d; unsigned char c; @@ -1079,8 +1072,7 @@ slip_esc6(unsigned char *s, unsigned char *d, int len) return ptr - d; } -void -slip_unesc6(struct slip *sl, unsigned char s) +static void slip_unesc6(struct slip *sl, unsigned char s) { unsigned char c; @@ -1091,13 +1083,13 @@ slip_unesc6(struct slip *sl, unsigned char s) clear_bit(SLF_KEEPTEST, &sl->flags); #endif - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) + && (sl->rcount > 2)) sl_bump(sl); - } sl->rcount = 0; sl->xbits = 0; sl->xdata = 0; - } else if (s >= 0x30 && s < 0x70) { + } else if (s >= 0x30 && s < 0x70) { sl->xdata = (sl->xdata << 6) | ((s - 0x30) & 0x3F); sl->xbits += 6; if (sl->xbits >= 8) { @@ -1112,24 +1104,24 @@ slip_unesc6(struct slip *sl, unsigned char s) set_bit(SLF_ERROR, &sl->flags); } } - } + } } #endif /* CONFIG_SLIP_MODE_SLIP6 */ /* Perform I/O control on an active SLIP channel. */ -static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) +static int slip_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl = tty->disc_data; unsigned int tmp; int __user *p = (int __user *)arg; /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC) { + if (!sl || sl->magic != SLIP_MAGIC) return -EINVAL; - } - switch(cmd) { - case SIOCGIFNAME: + switch (cmd) { + case SIOCGIFNAME: tmp = strlen(sl->dev->name) + 1; if (copy_to_user((void __user *)arg, sl->dev->name, tmp)) return -EFAULT; @@ -1144,34 +1136,31 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm if (get_user(tmp, p)) return -EFAULT; #ifndef SL_INCLUDE_CSLIP - if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) { + if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) return -EINVAL; - } #else if ((tmp & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) == - (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { + (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) /* return -EINVAL; */ tmp &= ~SL_MODE_ADAPTIVE; - } #endif #ifndef CONFIG_SLIP_MODE_SLIP6 - if (tmp & SL_MODE_SLIP6) { + if (tmp & SL_MODE_SLIP6) return -EINVAL; - } #endif sl->mode = tmp; - sl->dev->type = ARPHRD_SLIP+sl->mode; + sl->dev->type = ARPHRD_SLIP + sl->mode; return 0; - case SIOCSIFHWADDR: + case SIOCSIFHWADDR: return -EINVAL; #ifdef CONFIG_SLIP_SMART /* VSV changes start here */ - case SIOCSKEEPALIVE: + case SIOCSKEEPALIVE: if (get_user(tmp, p)) return -EFAULT; - if (tmp > 255) /* max for unchar */ + if (tmp > 255) /* max for unchar */ return -EINVAL; spin_lock_bh(&sl->lock); @@ -1179,40 +1168,42 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm spin_unlock_bh(&sl->lock); return -ENODEV; } - if ((sl->keepalive = (unchar) tmp) != 0) { - mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); + sl->keepalive = (u8)tmp; + if (sl->keepalive != 0) { + mod_timer(&sl->keepalive_timer, + jiffies + sl->keepalive * HZ); set_bit(SLF_KEEPTEST, &sl->flags); - } else { - del_timer (&sl->keepalive_timer); - } + } else + del_timer(&sl->keepalive_timer); spin_unlock_bh(&sl->lock); return 0; - case SIOCGKEEPALIVE: + case SIOCGKEEPALIVE: if (put_user(sl->keepalive, p)) return -EFAULT; return 0; - case SIOCSOUTFILL: + case SIOCSOUTFILL: if (get_user(tmp, p)) return -EFAULT; - if (tmp > 255) /* max for unchar */ + if (tmp > 255) /* max for unchar */ return -EINVAL; spin_lock_bh(&sl->lock); if (!sl->tty) { spin_unlock_bh(&sl->lock); return -ENODEV; } - if ((sl->outfill = (unchar) tmp) != 0){ - mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); + sl->outfill = (u8)tmp; + if (sl->outfill != 0) { + mod_timer(&sl->outfill_timer, + jiffies + sl->outfill * HZ); set_bit(SLF_OUTWAIT, &sl->flags); - } else { - del_timer (&sl->outfill_timer); - } + } else + del_timer(&sl->outfill_timer); spin_unlock_bh(&sl->lock); - return 0; + return 0; - case SIOCGOUTFILL: + case SIOCGOUTFILL: if (put_user(sl->outfill, p)) return -EFAULT; return 0; @@ -1229,7 +1220,7 @@ static int slip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm to allow get/set outfill/keepalive parameter by ifconfig */ -static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) +static int sl_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct slip *sl = netdev_priv(dev); unsigned long *p = (unsigned long *)&rq->ifr_ifru; @@ -1244,58 +1235,61 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd) return -ENODEV; } - switch(cmd){ - case SIOCSKEEPALIVE: + switch (cmd) { + case SIOCSKEEPALIVE: /* max for unchar */ - if ((unsigned)*p > 255) { + if ((unsigned)*p > 255) { spin_unlock_bh(&sl->lock); return -EINVAL; } - sl->keepalive = (unchar) *p; + sl->keepalive = (u8)*p; if (sl->keepalive != 0) { - sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; - mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); + sl->keepalive_timer.expires = + jiffies + sl->keepalive * HZ; + mod_timer(&sl->keepalive_timer, + jiffies + sl->keepalive * HZ); set_bit(SLF_KEEPTEST, &sl->flags); - } else { - del_timer(&sl->keepalive_timer); - } + } else + del_timer(&sl->keepalive_timer); break; - case SIOCGKEEPALIVE: + case SIOCGKEEPALIVE: *p = sl->keepalive; break; - case SIOCSOUTFILL: - if ((unsigned)*p > 255) { /* max for unchar */ + case SIOCSOUTFILL: + if ((unsigned)*p > 255) { /* max for unchar */ spin_unlock_bh(&sl->lock); return -EINVAL; } - if ((sl->outfill = (unchar)*p) != 0){ - mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); + sl->outfill = (u8)*p; + if (sl->outfill != 0) { + mod_timer(&sl->outfill_timer, + jiffies + sl->outfill * HZ); set_bit(SLF_OUTWAIT, &sl->flags); - } else { - del_timer (&sl->outfill_timer); - } - break; + } else + del_timer(&sl->outfill_timer); + break; - case SIOCGOUTFILL: + case SIOCGOUTFILL: *p = sl->outfill; break; - case SIOCSLEASE: + case SIOCSLEASE: /* Resolve race condition, when ioctl'ing hanged up and opened by another process device. */ - if (sl->tty != current->signal->tty && sl->pid != current->pid) { + if (sl->tty != current->signal->tty && + sl->pid != current->pid) { spin_unlock_bh(&sl->lock); return -EPERM; } sl->leased = 0; - if (*p) + if (*p) sl->leased = 1; - break; + break; - case SIOCGLEASE: + case SIOCGLEASE: *p = sl->leased; }; spin_unlock_bh(&sl->lock); @@ -1327,7 +1321,7 @@ static int __init slip_init(void) " (6 bit encapsulation enabled)" #endif ".\n", - SLIP_VERSION, slip_maxdev ); + SLIP_VERSION, slip_maxdev); #if defined(SL_INCLUDE_CSLIP) printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n"); #endif @@ -1335,14 +1329,16 @@ static int __init slip_init(void) printk(KERN_INFO "SLIP linefill/keepalive option.\n"); #endif - slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); + slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, + GFP_KERNEL); if (!slip_devs) { - printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); + printk(KERN_ERR "SLIP: Can't allocate slip devices array.\n"); return -ENOMEM; } /* Fill in our line protocol discipline, and register it */ - if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { + status = tty_register_ldisc(N_SLIP, &sl_ldisc); + if (status != 0) { printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); kfree(slip_devs); } @@ -1402,10 +1398,9 @@ static void __exit slip_exit(void) kfree(slip_devs); slip_devs = NULL; - if ((i = tty_unregister_ldisc(N_SLIP))) - { + i = tty_unregister_ldisc(N_SLIP); + if (i != 0) printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); - } } module_init(slip_init); @@ -1419,17 +1414,15 @@ module_exit(slip_exit); static void sl_outfill(unsigned long sls) { - struct slip *sl=(struct slip *)sls; + struct slip *sl = (struct slip *)sls; spin_lock(&sl->lock); if (sl->tty == NULL) goto out; - if(sl->outfill) - { - if( test_bit(SLF_OUTWAIT, &sl->flags) ) - { + if (sl->outfill) { + if (test_bit(SLF_OUTWAIT, &sl->flags)) { /* no packets were transmitted, do outfill */ #ifdef CONFIG_SLIP_MODE_SLIP6 unsigned char s = (sl->mode & SL_MODE_SLIP6)?0x70:END; @@ -1437,13 +1430,11 @@ static void sl_outfill(unsigned long sls) unsigned char s = END; #endif /* put END into tty queue. Is it right ??? */ - if (!netif_queue_stopped(sl->dev)) - { + if (!netif_queue_stopped(sl->dev)) { /* if device busy no outfill */ sl->tty->driver->write(sl->tty, &s, 1); } - } - else + } else set_bit(SLF_OUTWAIT, &sl->flags); mod_timer(&sl->outfill_timer, jiffies+sl->outfill*HZ); @@ -1454,31 +1445,29 @@ out: static void sl_keepalive(unsigned long sls) { - struct slip *sl=(struct slip *)sls; + struct slip *sl = (struct slip *)sls; spin_lock(&sl->lock); if (sl->tty == NULL) goto out; - if( sl->keepalive) - { - if(test_bit(SLF_KEEPTEST, &sl->flags)) - { + if (sl->keepalive) { + if (test_bit(SLF_KEEPTEST, &sl->flags)) { /* keepalive still high :(, we must hangup */ - if( sl->outfill ) /* outfill timer must be deleted too */ + if (sl->outfill) + /* outfill timer must be deleted too */ (void)del_timer(&sl->outfill_timer); printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); - tty_hangup(sl->tty); /* this must hangup tty & close slip */ + /* this must hangup tty & close slip */ + tty_hangup(sl->tty); /* I think we need not something else */ goto out; - } - else + } else set_bit(SLF_KEEPTEST, &sl->flags); mod_timer(&sl->keepalive_timer, jiffies+sl->keepalive*HZ); } - out: spin_unlock(&sl->lock); } diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index cb2698de5190..de67744c4a2a 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -906,7 +906,7 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) SMC_SELECT_BANK(1); base_address_register = inw( ioaddr + BASE ); if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) { - printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)." + printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). " "Probably not a SMC chip\n", ioaddr, base_address_register >> 3 & 0x3E0 ); /* well, the base address register didn't match. Must not have diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 7da7589d45dd..4020e9e955b3 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1775,7 +1775,8 @@ static int __init smc_findirq(void __iomem *ioaddr) * o actually GRAB the irq. * o GRAB the region */ -static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) +static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr, + unsigned long irq_flags) { struct smc_local *lp = netdev_priv(dev); static int version_printed = 0; @@ -1941,7 +1942,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr) } /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, SMC_IRQ_FLAGS, dev->name, dev); + retval = request_irq(dev->irq, &smc_interrupt, irq_flags, dev->name, dev); if (retval) goto err_out; @@ -2123,8 +2124,9 @@ static void smc_release_datacs(struct platform_device *pdev, struct net_device * static int smc_drv_probe(struct platform_device *pdev) { struct net_device *ndev; - struct resource *res; + struct resource *res, *ires; unsigned int __iomem *addr; + unsigned long irq_flags = SMC_IRQ_FLAGS; int ret; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); @@ -2150,12 +2152,17 @@ static int smc_drv_probe(struct platform_device *pdev) SET_NETDEV_DEV(ndev, &pdev->dev); ndev->dma = (unsigned char)-1; - ndev->irq = platform_get_irq(pdev, 0); - if (ndev->irq < 0) { + + ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!ires) { ret = -ENODEV; goto out_free_netdev; } + ndev->irq = ires->start; + if (SMC_IRQ_FLAGS == -1) + irq_flags = ires->flags & IRQF_TRIGGER_MASK; + ret = smc_request_attrib(pdev); if (ret) goto out_free_netdev; @@ -2181,7 +2188,7 @@ static int smc_drv_probe(struct platform_device *pdev) #endif platform_set_drvdata(pdev, ndev); - ret = smc_probe(ndev, addr); + ret = smc_probe(ndev, addr, irq_flags); if (ret != 0) goto out_iounmap; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 07b7f7120e37..271c28dc9baa 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -54,6 +54,7 @@ #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) +#define SMC_IRQ_FLAGS (-1) /* from resource */ #elif defined(CONFIG_BLACKFIN) @@ -158,7 +159,7 @@ #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) -#define SMC_IRQ_FLAGS (0) +#define SMC_IRQ_FLAGS (-1) #elif defined(CONFIG_SA1100_ASSABET) @@ -177,6 +178,7 @@ #define SMC_outb(v, a, r) writeb(v, (a) + (r)) #define SMC_insb(a, r, p, l) readsb((a) + (r), p, (l)) #define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l)) +#define SMC_IRQ_FLAGS (-1) /* from resource */ #elif defined(CONFIG_MACH_LOGICPD_PXA270) @@ -194,7 +196,8 @@ #elif defined(CONFIG_ARCH_INNOKOM) || \ defined(CONFIG_MACH_MAINSTONE) || \ defined(CONFIG_ARCH_PXA_IDP) || \ - defined(CONFIG_ARCH_RAMSES) + defined(CONFIG_ARCH_RAMSES) || \ + defined(CONFIG_ARCH_PCM027) #define SMC_CAN_USE_8BIT 1 #define SMC_CAN_USE_16BIT 1 @@ -210,6 +213,7 @@ #define SMC_outl(v, a, r) writel(v, (a) + (r)) #define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) #define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) +#define SMC_IRQ_FLAGS (-1) /* from resource */ /* We actually can't write halfwords properly if not word aligned */ static inline void @@ -238,6 +242,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) #define SMC_outb(v, a, r) writeb(v, (a) + (r)) #define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_IRQ_FLAGS (-1) /* from resource */ #elif defined(CONFIG_ARCH_OMAP) @@ -252,17 +257,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_outw(v, a, r) writew(v, (a) + (r)) #define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) #define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) - -#include <asm/mach-types.h> -#include <asm/arch/cpu.h> - -#define SMC_IRQ_FLAGS (( \ - machine_is_omap_h2() \ - || machine_is_omap_h3() \ - || machine_is_omap_h4() \ - || (machine_is_omap_innovator() && !cpu_is_omap1510()) \ - ) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING) - +#define SMC_IRQ_FLAGS (-1) /* from resource */ #elif defined(CONFIG_SH_SH4202_MICRODEV) @@ -453,8 +448,7 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_outl(v, a, r) writel(v, (a) + (r)) #define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) #define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) - -#define SMC_IRQ_FLAGS (0) +#define SMC_IRQ_FLAGS (-1) /* from resource */ #else diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 0a6186d4a48e..7d5561b8241c 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -1596,9 +1596,7 @@ static const struct ethtool_ops ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct netdev_private *np = netdev_priv(dev); - void __iomem *ioaddr = np->base; int rc; - int i; if (!netif_running(dev)) return -EINVAL; @@ -1606,30 +1604,6 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irq(&np->lock); rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL); spin_unlock_irq(&np->lock); - switch (cmd) { - case SIOCDEVPRIVATE: - for (i=0; i<TX_RING_SIZE; i++) { - printk(KERN_DEBUG "%02x %08llx %08x %08x(%02x) %08x %08x\n", i, - (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)), - le32_to_cpu(np->tx_ring[i].next_desc), - le32_to_cpu(np->tx_ring[i].status), - (le32_to_cpu(np->tx_ring[i].status) >> 2) - & 0xff, - le32_to_cpu(np->tx_ring[i].frag[0].addr), - le32_to_cpu(np->tx_ring[i].frag[0].length)); - } - printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", - ioread32(np->base + TxListPtr), - netif_queue_stopped(dev)); - printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", - np->cur_tx, np->cur_tx % TX_RING_SIZE, - np->dirty_tx, np->dirty_tx % TX_RING_SIZE); - printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx); - printk(KERN_DEBUG "cur_task=%d\n", np->cur_task); - printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus)); - return 0; - } - return rc; } diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 68872142530b..97212799c513 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -758,6 +758,7 @@ static int gem_rx(struct gem *gp, int work_to_do) { int entry, drops, work_done = 0; u32 done; + __sum16 csum; if (netif_msg_rx_status(gp)) printk(KERN_DEBUG "%s: rx interrupt, done: %d, rx_new: %d\n", @@ -769,7 +770,7 @@ static int gem_rx(struct gem *gp, int work_to_do) for (;;) { struct gem_rxd *rxd = &gp->init_block->rxd[entry]; struct sk_buff *skb; - u64 status = cpu_to_le64(rxd->status_word); + u64 status = le64_to_cpu(rxd->status_word); dma_addr_t dma_addr; int len; @@ -811,7 +812,7 @@ static int gem_rx(struct gem *gp, int work_to_do) goto next; } - dma_addr = cpu_to_le64(rxd->buffer); + dma_addr = le64_to_cpu(rxd->buffer); if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; @@ -853,7 +854,8 @@ static int gem_rx(struct gem *gp, int work_to_do) skb = copy_skb; } - skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff); + csum = (__force __sum16)htons((status & RXDCTRL_TCPCSUM) ^ 0xffff); + skb->csum = csum_unfold(csum); skb->ip_summed = CHECKSUM_COMPLETE; skb->protocol = eth_type_trans(skb, gp->dev); @@ -3054,7 +3056,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, netif_carrier_off(dev); gp->regs = ioremap(gemreg_base, gemreg_len); - if (gp->regs == 0UL) { + if (!gp->regs) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); err = -EIO; diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index 76d760acc9e2..f7a02917ce5e 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -828,8 +828,8 @@ * DMA mappings for a transmitted packet. */ struct gem_txd { - u64 control_word; - u64 buffer; + __le64 control_word; + __le64 buffer; }; #define TXDCTRL_BUFSZ 0x0000000000007fffULL /* Buffer Size */ @@ -863,8 +863,8 @@ struct gem_txd { * by the host driver just as in the TX descriptor case above. */ struct gem_rxd { - u64 status_word; - u64 buffer; + __le64 status_word; + __le64 buffer; }; #define RXDCTRL_TCPCSUM 0x000000000000ffffULL /* TCP Pseudo-CSUM */ diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 9cc13dd8a821..b4e7f30ea4e8 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -194,21 +194,21 @@ static u32 sbus_hme_read32(void __iomem *reg) static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) { - rxd->rx_addr = addr; + rxd->rx_addr = (__force hme32)addr; wmb(); - rxd->rx_flags = flags; + rxd->rx_flags = (__force hme32)flags; } static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) { - txd->tx_addr = addr; + txd->tx_addr = (__force hme32)addr; wmb(); - txd->tx_flags = flags; + txd->tx_flags = (__force hme32)flags; } -static u32 sbus_hme_read_desc32(u32 *p) +static u32 sbus_hme_read_desc32(hme32 *p) { - return *p; + return (__force u32)*p; } static void pci_hme_write32(void __iomem *reg, u32 val) @@ -223,21 +223,21 @@ static u32 pci_hme_read32(void __iomem *reg) static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) { - rxd->rx_addr = cpu_to_le32(addr); + rxd->rx_addr = (__force hme32)cpu_to_le32(addr); wmb(); - rxd->rx_flags = cpu_to_le32(flags); + rxd->rx_flags = (__force hme32)cpu_to_le32(flags); } static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) { - txd->tx_addr = cpu_to_le32(addr); + txd->tx_addr = (__force hme32)cpu_to_le32(addr); wmb(); - txd->tx_flags = cpu_to_le32(flags); + txd->tx_flags = (__force hme32)cpu_to_le32(flags); } -static u32 pci_hme_read_desc32(u32 *p) +static u32 pci_hme_read_desc32(hme32 *p) { - return cpu_to_le32p(p); + return le32_to_cpup((__le32 *)p); } #define hme_write32(__hp, __reg, __val) \ @@ -266,16 +266,16 @@ static u32 pci_hme_read_desc32(u32 *p) #define hme_read32(__hp, __reg) \ sbus_readl(__reg) #define hme_write_rxd(__hp, __rxd, __flags, __addr) \ -do { (__rxd)->rx_addr = (__addr); \ +do { (__rxd)->rx_addr = (__force hme32)(u32)(__addr); \ wmb(); \ - (__rxd)->rx_flags = (__flags); \ + (__rxd)->rx_flags = (__force hme32)(u32)(__flags); \ } while(0) #define hme_write_txd(__hp, __txd, __flags, __addr) \ -do { (__txd)->tx_addr = (__addr); \ +do { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ wmb(); \ - (__txd)->tx_flags = (__flags); \ + (__txd)->tx_flags = (__force hme32)(u32)(__flags); \ } while(0) -#define hme_read_desc32(__hp, __p) (*(__p)) +#define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) #define hme_dma_map(__hp, __ptr, __size, __dir) \ sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ @@ -291,16 +291,19 @@ do { (__txd)->tx_addr = (__addr); \ #define hme_read32(__hp, __reg) \ readl(__reg) #define hme_write_rxd(__hp, __rxd, __flags, __addr) \ -do { (__rxd)->rx_addr = cpu_to_le32(__addr); \ +do { (__rxd)->rx_addr = (__force hme32)cpu_to_le32(__addr); \ wmb(); \ - (__rxd)->rx_flags = cpu_to_le32(__flags); \ + (__rxd)->rx_flags = (__force hme32)cpu_to_le32(__flags); \ } while(0) #define hme_write_txd(__hp, __txd, __flags, __addr) \ -do { (__txd)->tx_addr = cpu_to_le32(__addr); \ +do { (__txd)->tx_addr = (__force hme32)cpu_to_le32(__addr); \ wmb(); \ - (__txd)->tx_flags = cpu_to_le32(__flags); \ + (__txd)->tx_flags = (__force hme32)cpu_to_le32(__flags); \ } while(0) -#define hme_read_desc32(__hp, __p) cpu_to_le32p(__p) +static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) +{ + return le32_to_cpup((__le32 *)p); +} #define hme_dma_map(__hp, __ptr, __size, __dir) \ pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ @@ -2075,7 +2078,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) } /* This card is _fucking_ hot... */ - skb->csum = ntohs(csum ^ 0xffff); + skb->csum = csum_unfold(~(__force __sum16)htons(csum)); skb->ip_summed = CHECKSUM_COMPLETE; RXD(("len=%d csum=%4x]", len, csum)); @@ -3057,7 +3060,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, goto err_out_clear_quattro; } - if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == 0) { + if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == NULL) { printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); goto err_out_free_res; } diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h index 90f446db9ba2..4da5539fac7b 100644 --- a/drivers/net/sunhme.h +++ b/drivers/net/sunhme.h @@ -302,9 +302,11 @@ * Always write the address first before setting the ownership * bits to avoid races with the hardware scanning the ring. */ +typedef u32 __bitwise__ hme32; + struct happy_meal_rxd { - u32 rx_flags; - u32 rx_addr; + hme32 rx_flags; + hme32 rx_addr; }; #define RXFLAG_OWN 0x80000000 /* 1 = hardware, 0 = software */ @@ -313,8 +315,8 @@ struct happy_meal_rxd { #define RXFLAG_CSUM 0x0000ffff /* HW computed checksum */ struct happy_meal_txd { - u32 tx_flags; - u32 tx_addr; + hme32 tx_flags; + hme32 tx_addr; }; #define TXFLAG_OWN 0x80000000 /* 1 = hardware, 0 = software */ @@ -400,7 +402,7 @@ struct happy_meal { struct hmeal_init_block *happy_block; /* RX and TX descriptors (CPU addr) */ #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) - u32 (*read_desc32)(u32 *); + u32 (*read_desc32)(hme32 *); void (*write_txd)(struct happy_meal_txd *, u32, u32); void (*write_rxd)(struct happy_meal_rxd *, u32, u32); u32 (*dma_map)(void *, void *, long, int); diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index ff1028a597df..4a0035f7a842 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1149,6 +1149,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, struct vnet *vp; const u64 *rmac; int len, i, err, switch_port; + DECLARE_MAC_BUF(mac); print_version(); @@ -1213,12 +1214,9 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, dev_set_drvdata(&vdev->dev, port); - printk(KERN_INFO "%s: PORT ( remote-mac ", vp->dev->name); - for (i = 0; i < 6; i++) - printk("%2.2x%c", port->raddr[i], i == 5 ? ' ' : ':'); - if (switch_port) - printk("switch-port "); - printk(")\n"); + printk(KERN_INFO "%s: PORT ( remote-mac %s%s )\n", + vp->dev->name, print_mac(mac, port->raddr), + switch_port ? " switch-port" : ""); vio_port_up(&port->vio); diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 21230c97b2a0..17585e5eed53 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -621,7 +621,7 @@ err: static void __init bdx_firmware_endianess(void) { int i; - for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++) + for (i = 0; i < ARRAY_SIZE(s_firmLoad); i++) s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]); } @@ -2174,8 +2174,7 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) strlcat(drvinfo->bus_info, pci_name(priv->pdev), sizeof(drvinfo->bus_info)); - drvinfo->n_stats = ((priv->stats_flag) ? - (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0); + drvinfo->n_stats = ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0); drvinfo->testinfo_len = 0; drvinfo->regdump_len = 0; drvinfo->eedump_len = 0; @@ -2375,10 +2374,9 @@ static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) static int bdx_get_stats_count(struct net_device *netdev) { struct bdx_priv *priv = netdev->priv; - BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN + BDX_ASSERT(ARRAY_SIZE(bdx_stat_names) != sizeof(struct bdx_stats) / sizeof(u64)); - return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) - : 0); + return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0); } /* diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 22eb7c8c1a25..db606b603884 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.86" -#define DRV_MODULE_RELDATE "November 9, 2007" +#define DRV_MODULE_VERSION "3.87" +#define DRV_MODULE_RELDATE "December 20, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -1602,68 +1602,113 @@ static void tg3_link_report(struct tg3 *tp) (tp->link_config.active_duplex == DUPLEX_FULL ? "full" : "half")); - printk(KERN_INFO PFX "%s: Flow control is %s for TX and " - "%s for RX.\n", + printk(KERN_INFO PFX + "%s: Flow control is %s for TX and %s for RX.\n", tp->dev->name, - (tp->tg3_flags & TG3_FLAG_TX_PAUSE) ? "on" : "off", - (tp->tg3_flags & TG3_FLAG_RX_PAUSE) ? "on" : "off"); + (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? + "on" : "off", + (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? + "on" : "off"); } } -static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) +static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) { - u32 new_tg3_flags = 0; - u32 old_rx_mode = tp->rx_mode; - u32 old_tx_mode = tp->tx_mode; + u16 miireg; - if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) { + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_PAUSE_CAP; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_PAUSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + else + miireg = 0; - /* Convert 1000BaseX flow control bits to 1000BaseT - * bits before resolving flow control. - */ - if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) { - local_adv &= ~(ADVERTISE_PAUSE_CAP | - ADVERTISE_PAUSE_ASYM); - remote_adv &= ~(LPA_PAUSE_CAP | LPA_PAUSE_ASYM); - - if (local_adv & ADVERTISE_1000XPAUSE) - local_adv |= ADVERTISE_PAUSE_CAP; - if (local_adv & ADVERTISE_1000XPSE_ASYM) - local_adv |= ADVERTISE_PAUSE_ASYM; - if (remote_adv & LPA_1000XPAUSE) - remote_adv |= LPA_PAUSE_CAP; - if (remote_adv & LPA_1000XPAUSE_ASYM) - remote_adv |= LPA_PAUSE_ASYM; - } - - if (local_adv & ADVERTISE_PAUSE_CAP) { - if (local_adv & ADVERTISE_PAUSE_ASYM) { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); - else if (remote_adv & LPA_PAUSE_ASYM) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE); - } else { - if (remote_adv & LPA_PAUSE_CAP) - new_tg3_flags |= - (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); - } - } else if (local_adv & ADVERTISE_PAUSE_ASYM) { - if ((remote_adv & LPA_PAUSE_CAP) && - (remote_adv & LPA_PAUSE_ASYM)) - new_tg3_flags |= TG3_FLAG_TX_PAUSE; + return miireg; +} + +static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) +{ + u16 miireg; + + if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + miireg = ADVERTISE_1000XPAUSE; + else if (flow_ctrl & TG3_FLOW_CTRL_TX) + miireg = ADVERTISE_1000XPSE_ASYM; + else if (flow_ctrl & TG3_FLOW_CTRL_RX) + miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; + else + miireg = 0; + + return miireg; +} + +static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_PAUSE_CAP) { + if (lcladv & ADVERTISE_PAUSE_ASYM) { + if (rmtadv & LPA_PAUSE_CAP) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + else if (rmtadv & LPA_PAUSE_ASYM) + cap = TG3_FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_PAUSE_CAP) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_PAUSE_ASYM) { + if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) + cap = TG3_FLOW_CTRL_TX; + } + + return cap; +} + +static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_1000XPAUSE) { + if (lcladv & ADVERTISE_1000XPSE_ASYM) { + if (rmtadv & LPA_1000XPAUSE) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + else if (rmtadv & LPA_1000XPAUSE_ASYM) + cap = TG3_FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_1000XPAUSE) + cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; } + } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { + if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) + cap = TG3_FLOW_CTRL_TX; + } - tp->tg3_flags &= ~(TG3_FLAG_RX_PAUSE | TG3_FLAG_TX_PAUSE); - tp->tg3_flags |= new_tg3_flags; + return cap; +} + +static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv) +{ + u8 new_tg3_flags = 0; + u32 old_rx_mode = tp->rx_mode; + u32 old_tx_mode = tp->tx_mode; + + if (tp->link_config.autoneg == AUTONEG_ENABLE && + (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) + new_tg3_flags = tg3_resolve_flowctrl_1000X(local_adv, + remote_adv); + else + new_tg3_flags = tg3_resolve_flowctrl_1000T(local_adv, + remote_adv); } else { - new_tg3_flags = tp->tg3_flags; + new_tg3_flags = tp->link_config.flowctrl; } - if (new_tg3_flags & TG3_FLAG_RX_PAUSE) + tp->link_config.active_flowctrl = new_tg3_flags; + + if (new_tg3_flags & TG3_FLOW_CTRL_RX) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; else tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; @@ -1672,7 +1717,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv tw32_f(MAC_RX_MODE, tp->rx_mode); } - if (new_tg3_flags & TG3_FLAG_TX_PAUSE) + if (new_tg3_flags & TG3_FLOW_CTRL_TX) tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; else tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; @@ -1752,7 +1797,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) ~(ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full); - new_adv = (ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + new_adv = ADVERTISE_CSMA; if (tp->link_config.advertising & ADVERTISED_10baseT_Half) new_adv |= ADVERTISE_10HALF; if (tp->link_config.advertising & ADVERTISED_10baseT_Full) @@ -1761,6 +1806,9 @@ static void tg3_phy_copper_begin(struct tg3 *tp) new_adv |= ADVERTISE_100HALF; if (tp->link_config.advertising & ADVERTISED_100baseT_Full) new_adv |= ADVERTISE_100FULL; + + new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); + tg3_writephy(tp, MII_ADVERTISE, new_adv); if (tp->link_config.advertising & @@ -1780,9 +1828,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp) tg3_writephy(tp, MII_TG3_CTRL, 0); } } else { + new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); + new_adv |= ADVERTISE_CSMA; + /* Asking for a specific link mode. */ if (tp->link_config.speed == SPEED_1000) { - new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; tg3_writephy(tp, MII_ADVERTISE, new_adv); if (tp->link_config.duplex == DUPLEX_FULL) @@ -1793,11 +1843,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp) tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) new_adv |= (MII_TG3_CTRL_AS_MASTER | MII_TG3_CTRL_ENABLE_AS_MASTER); - tg3_writephy(tp, MII_TG3_CTRL, new_adv); } else { - tg3_writephy(tp, MII_TG3_CTRL, 0); - - new_adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP; if (tp->link_config.speed == SPEED_100) { if (tp->link_config.duplex == DUPLEX_FULL) new_adv |= ADVERTISE_100FULL; @@ -1810,7 +1856,11 @@ static void tg3_phy_copper_begin(struct tg3 *tp) new_adv |= ADVERTISE_10HALF; } tg3_writephy(tp, MII_ADVERTISE, new_adv); + + new_adv = 0; } + + tg3_writephy(tp, MII_TG3_CTRL, new_adv); } if (tp->link_config.autoneg == AUTONEG_DISABLE && @@ -1926,10 +1976,44 @@ static int tg3_copper_is_advertising_all(struct tg3 *tp, u32 mask) return 1; } +static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv) +{ + u32 curadv, reqadv; + + if (tg3_readphy(tp, MII_ADVERTISE, lcladv)) + return 1; + + curadv = *lcladv & (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + reqadv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); + + if (tp->link_config.active_duplex == DUPLEX_FULL) { + if (curadv != reqadv) + return 0; + + if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) + tg3_readphy(tp, MII_LPA, rmtadv); + } else { + /* Reprogram the advertisement register, even if it + * does not affect the current link. If the link + * gets renegotiated in the future, we can save an + * additional renegotiation cycle by advertising + * it correctly in the first place. + */ + if (curadv != reqadv) { + *lcladv &= ~(ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + tg3_writephy(tp, MII_ADVERTISE, *lcladv | reqadv); + } + } + + return 1; +} + static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) { int current_link_up; u32 bmsr, dummy; + u32 lcl_adv, rmt_adv; u16 current_speed; u8 current_duplex; int i, err; @@ -2072,56 +2156,35 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset) udelay(10); } - if (tp->link_config.autoneg == AUTONEG_ENABLE) { - if (bmcr & BMCR_ANENABLE) { - current_link_up = 1; + lcl_adv = 0; + rmt_adv = 0; - /* Force autoneg restart if we are exiting - * low power mode. - */ - if (!tg3_copper_is_advertising_all(tp, - tp->link_config.advertising)) - current_link_up = 0; - } else { - current_link_up = 0; + tp->link_config.active_speed = current_speed; + tp->link_config.active_duplex = current_duplex; + + if (tp->link_config.autoneg == AUTONEG_ENABLE) { + if ((bmcr & BMCR_ANENABLE) && + tg3_copper_is_advertising_all(tp, + tp->link_config.advertising)) { + if (tg3_adv_1000T_flowctrl_ok(tp, &lcl_adv, + &rmt_adv)) + current_link_up = 1; } } else { if (!(bmcr & BMCR_ANENABLE) && tp->link_config.speed == current_speed && - tp->link_config.duplex == current_duplex) { + tp->link_config.duplex == current_duplex && + tp->link_config.flowctrl == + tp->link_config.active_flowctrl) { current_link_up = 1; - } else { - current_link_up = 0; } } - tp->link_config.active_speed = current_speed; - tp->link_config.active_duplex = current_duplex; + if (current_link_up == 1 && + tp->link_config.active_duplex == DUPLEX_FULL) + tg3_setup_flow_control(tp, lcl_adv, rmt_adv); } - if (current_link_up == 1 && - (tp->link_config.active_duplex == DUPLEX_FULL) && - (tp->link_config.autoneg == AUTONEG_ENABLE)) { - u32 local_adv, remote_adv; - - if (tg3_readphy(tp, MII_ADVERTISE, &local_adv)) - local_adv = 0; - local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - - if (tg3_readphy(tp, MII_LPA, &remote_adv)) - remote_adv = 0; - - remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM); - - /* If we are not advertising full pause capability, - * something is wrong. Bring the link down and reconfigure. - */ - if (local_adv != ADVERTISE_PAUSE_CAP) { - current_link_up = 0; - } else { - tg3_setup_flow_control(tp, local_adv, remote_adv); - } - } relink: if (current_link_up == 0 || tp->link_config.phy_is_low_power) { u32 tmp; @@ -2270,6 +2333,7 @@ struct tg3_fiber_aneginfo { static int tg3_fiber_aneg_smachine(struct tg3 *tp, struct tg3_fiber_aneginfo *ap) { + u16 flowctrl; unsigned long delta; u32 rx_cfg_reg; int ret; @@ -2369,7 +2433,12 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, case ANEG_STATE_ABILITY_DETECT_INIT: ap->flags &= ~(MR_TOGGLE_TX); - ap->txconfig = (ANEG_CFG_FD | ANEG_CFG_PS1); + ap->txconfig = ANEG_CFG_FD; + flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl); + if (flowctrl & ADVERTISE_1000XPAUSE) + ap->txconfig |= ANEG_CFG_PS1; + if (flowctrl & ADVERTISE_1000XPSE_ASYM) + ap->txconfig |= ANEG_CFG_PS2; tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32_f(MAC_MODE, tp->mac_mode); @@ -2515,7 +2584,7 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, return ret; } -static int fiber_autoneg(struct tg3 *tp, u32 *flags) +static int fiber_autoneg(struct tg3 *tp, u32 *txflags, u32 *rxflags) { int res = 0; struct tg3_fiber_aneginfo aninfo; @@ -2549,7 +2618,8 @@ static int fiber_autoneg(struct tg3 *tp, u32 *flags) tw32_f(MAC_MODE, tp->mac_mode); udelay(40); - *flags = aninfo.flags; + *txflags = aninfo.txconfig; + *rxflags = aninfo.flags; if (status == ANEG_DONE && (aninfo.flags & (MR_AN_COMPLETE | MR_LINK_OK | @@ -2611,6 +2681,7 @@ static void tg3_init_bcm8002(struct tg3 *tp) static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) { + u16 flowctrl; u32 sg_dig_ctrl, sg_dig_status; u32 serdes_cfg, expected_sg_dig_ctrl; int workaround, port_a; @@ -2636,7 +2707,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) sg_dig_ctrl = tr32(SG_DIG_CTRL); if (tp->link_config.autoneg != AUTONEG_ENABLE) { - if (sg_dig_ctrl & (1 << 31)) { + if (sg_dig_ctrl & SG_DIG_USING_HW_AUTONEG) { if (workaround) { u32 val = serdes_cfg; @@ -2646,7 +2717,8 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) val |= 0x4010000; tw32_f(MAC_SERDES_CFG, val); } - tw32_f(SG_DIG_CTRL, 0x01388400); + + tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP); } if (mac_status & MAC_STATUS_PCS_SYNCED) { tg3_setup_flow_control(tp, 0, 0); @@ -2656,13 +2728,13 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) } /* Want auto-negotiation. */ - expected_sg_dig_ctrl = 0x81388400; + expected_sg_dig_ctrl = SG_DIG_USING_HW_AUTONEG | SG_DIG_COMMON_SETUP; - /* Pause capability */ - expected_sg_dig_ctrl |= (1 << 11); - - /* Asymettric pause */ - expected_sg_dig_ctrl |= (1 << 12); + flowctrl = tg3_advert_flowctrl_1000X(tp->link_config.flowctrl); + if (flowctrl & ADVERTISE_1000XPAUSE) + expected_sg_dig_ctrl |= SG_DIG_PAUSE_CAP; + if (flowctrl & ADVERTISE_1000XPSE_ASYM) + expected_sg_dig_ctrl |= SG_DIG_ASYM_PAUSE; if (sg_dig_ctrl != expected_sg_dig_ctrl) { if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) && @@ -2677,7 +2749,7 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status) restart_autoneg: if (workaround) tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000); - tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30)); + tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | SG_DIG_SOFT_RESET); udelay(5); tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl); @@ -2688,22 +2760,25 @@ restart_autoneg: sg_dig_status = tr32(SG_DIG_STATUS); mac_status = tr32(MAC_STATUS); - if ((sg_dig_status & (1 << 1)) && + if ((sg_dig_status & SG_DIG_AUTONEG_COMPLETE) && (mac_status & MAC_STATUS_PCS_SYNCED)) { - u32 local_adv, remote_adv; + u32 local_adv = 0, remote_adv = 0; + + if (sg_dig_ctrl & SG_DIG_PAUSE_CAP) + local_adv |= ADVERTISE_1000XPAUSE; + if (sg_dig_ctrl & SG_DIG_ASYM_PAUSE) + local_adv |= ADVERTISE_1000XPSE_ASYM; - local_adv = ADVERTISE_PAUSE_CAP; - remote_adv = 0; - if (sg_dig_status & (1 << 19)) - remote_adv |= LPA_PAUSE_CAP; - if (sg_dig_status & (1 << 20)) - remote_adv |= LPA_PAUSE_ASYM; + if (sg_dig_status & SG_DIG_PARTNER_PAUSE_CAPABLE) + remote_adv |= LPA_1000XPAUSE; + if (sg_dig_status & SG_DIG_PARTNER_ASYM_PAUSE) + remote_adv |= LPA_1000XPAUSE_ASYM; tg3_setup_flow_control(tp, local_adv, remote_adv); current_link_up = 1; tp->serdes_counter = 0; tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; - } else if (!(sg_dig_status & (1 << 1))) { + } else if (!(sg_dig_status & SG_DIG_AUTONEG_COMPLETE)) { if (tp->serdes_counter) tp->serdes_counter--; else { @@ -2718,7 +2793,7 @@ restart_autoneg: tw32_f(MAC_SERDES_CFG, val); } - tw32_f(SG_DIG_CTRL, 0x01388400); + tw32_f(SG_DIG_CTRL, SG_DIG_COMMON_SETUP); udelay(40); /* Link parallel detection - link is up */ @@ -2754,18 +2829,21 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) goto out; if (tp->link_config.autoneg == AUTONEG_ENABLE) { - u32 flags; + u32 txflags, rxflags; int i; - if (fiber_autoneg(tp, &flags)) { - u32 local_adv, remote_adv; + if (fiber_autoneg(tp, &txflags, &rxflags)) { + u32 local_adv = 0, remote_adv = 0; + + if (txflags & ANEG_CFG_PS1) + local_adv |= ADVERTISE_1000XPAUSE; + if (txflags & ANEG_CFG_PS2) + local_adv |= ADVERTISE_1000XPSE_ASYM; - local_adv = ADVERTISE_PAUSE_CAP; - remote_adv = 0; - if (flags & MR_LP_ADV_SYM_PAUSE) - remote_adv |= LPA_PAUSE_CAP; - if (flags & MR_LP_ADV_ASYM_PAUSE) - remote_adv |= LPA_PAUSE_ASYM; + if (rxflags & MR_LP_ADV_SYM_PAUSE) + remote_adv |= LPA_1000XPAUSE; + if (rxflags & MR_LP_ADV_ASYM_PAUSE) + remote_adv |= LPA_1000XPAUSE_ASYM; tg3_setup_flow_control(tp, local_adv, remote_adv); @@ -2789,6 +2867,8 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status) !(mac_status & MAC_STATUS_RCVD_CFG)) current_link_up = 1; } else { + tg3_setup_flow_control(tp, 0, 0); + /* Forcing 1000FD link up. */ current_link_up = 1; @@ -2812,9 +2892,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) int current_link_up; int i; - orig_pause_cfg = - (tp->tg3_flags & (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE)); + orig_pause_cfg = tp->link_config.active_flowctrl; orig_active_speed = tp->link_config.active_speed; orig_active_duplex = tp->link_config.active_duplex; @@ -2903,9 +2981,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset) netif_carrier_off(tp->dev); tg3_link_report(tp); } else { - u32 now_pause_cfg = - tp->tg3_flags & (TG3_FLAG_RX_PAUSE | - TG3_FLAG_TX_PAUSE); + u32 now_pause_cfg = tp->link_config.active_flowctrl; if (orig_pause_cfg != now_pause_cfg || orig_active_speed != tp->link_config.active_speed || orig_active_duplex != tp->link_config.active_duplex) @@ -2921,6 +2997,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) u32 bmsr, bmcr; u16 current_speed; u8 current_duplex; + u32 local_adv, remote_adv; tp->mac_mode |= MAC_MODE_PORT_MODE_GMII; tw32_f(MAC_MODE, tp->mac_mode); @@ -2954,7 +3031,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) err |= tg3_readphy(tp, MII_BMCR, &bmcr); if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset && - (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) { + (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) && + tp->link_config.flowctrl == tp->link_config.active_flowctrl) { /* do nothing, just check for link up at the end */ } else if (tp->link_config.autoneg == AUTONEG_ENABLE) { u32 adv, new_adv; @@ -2965,8 +3043,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) ADVERTISE_1000XPSE_ASYM | ADVERTISE_SLCT); - /* Always advertise symmetric PAUSE just like copper */ - new_adv |= ADVERTISE_1000XPAUSE; + new_adv |= tg3_advert_flowctrl_1000X(tp->link_config.flowctrl); if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) new_adv |= ADVERTISE_1000XHALF; @@ -3037,8 +3114,11 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) else current_duplex = DUPLEX_HALF; + local_adv = 0; + remote_adv = 0; + if (bmcr & BMCR_ANENABLE) { - u32 local_adv, remote_adv, common; + u32 common; err |= tg3_readphy(tp, MII_ADVERTISE, &local_adv); err |= tg3_readphy(tp, MII_LPA, &remote_adv); @@ -3049,15 +3129,15 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) current_duplex = DUPLEX_FULL; else current_duplex = DUPLEX_HALF; - - tg3_setup_flow_control(tp, local_adv, - remote_adv); } else current_link_up = 0; } } + if (current_link_up == 1 && current_duplex == DUPLEX_FULL) + tg3_setup_flow_control(tp, local_adv, remote_adv); + tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX; if (tp->link_config.active_duplex == DUPLEX_HALF) tp->mac_mode |= MAC_MODE_HALF_DUPLEX; @@ -8569,8 +8649,16 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam struct tg3 *tp = netdev_priv(dev); epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; - epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0; - epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0; + + if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) + epause->rx_pause = 1; + else + epause->rx_pause = 0; + + if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) + epause->tx_pause = 1; + else + epause->tx_pause = 0; } static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) @@ -8590,13 +8678,13 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam else tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; if (epause->rx_pause) - tp->tg3_flags |= TG3_FLAG_RX_PAUSE; + tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; else - tp->tg3_flags &= ~TG3_FLAG_RX_PAUSE; + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; if (epause->tx_pause) - tp->tg3_flags |= TG3_FLAG_TX_PAUSE; + tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; else - tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; + tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -12361,9 +12449,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, unsigned long tg3reg_base, tg3reg_len; struct net_device *dev; struct tg3 *tp; - int i, err, pm_cap; + int err, pm_cap; char str[40]; u64 dma_mask, persist_dma_mask; + DECLARE_MAC_BUF(mac); if (tg3_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -12586,7 +12675,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3reg_len = pci_resource_len(pdev, 2); tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len); - if (tp->aperegs == 0UL) { + if (!tp->aperegs) { printk(KERN_ERR PFX "Cannot map APE registers, " "aborting.\n"); err = -ENOMEM; @@ -12630,6 +12719,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, /* flow control autonegotiation is default behavior */ tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; + tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; tg3_init_coal(tp); @@ -12642,7 +12732,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ", + printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] " + "(%s) %s Ethernet %s\n", dev->name, tp->board_part_number, tp->pci_chip_rev_id, @@ -12650,11 +12741,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tg3_bus_string(tp, str), ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" : ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" : - "10/100/1000Base-T"))); - - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i], - i == 5 ? '\n' : ':'); + "10/100/1000Base-T")), + print_mac(mac, dev->dev_addr)); printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n", diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index da18fb220712..3938eb35ce8c 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -545,6 +545,8 @@ #define SG_DIG_FIBER_MODE 0x00008000 #define SG_DIG_REMOTE_FAULT_MASK 0x00006000 #define SG_DIG_PAUSE_MASK 0x00001800 +#define SG_DIG_PAUSE_CAP 0x00000800 +#define SG_DIG_ASYM_PAUSE 0x00001000 #define SG_DIG_GBIC_ENABLE 0x00000400 #define SG_DIG_CHECK_END_ENABLE 0x00000200 #define SG_DIG_SGMII_AUTONEG_TIMER 0x00000100 @@ -556,6 +558,11 @@ #define SG_DIG_AUTONEG_LOW_ENABLE 0x00000004 #define SG_DIG_REMOTE_LOOPBACK 0x00000002 #define SG_DIG_LOOPBACK 0x00000001 +#define SG_DIG_COMMON_SETUP (SG_DIG_CRC16_CLEAR_N | \ + SG_DIG_LOCAL_DUPLEX_STATUS | \ + SG_DIG_LOCAL_LINK_STATUS | \ + (0x2 << SG_DIG_SPEED_STATUS_SHIFT) | \ + SG_DIG_FIBER_MODE | SG_DIG_GBIC_ENABLE) #define SG_DIG_STATUS 0x000005b4 #define SG_DIG_CRC16_BUS_MASK 0xffff0000 #define SG_DIG_PARTNER_FAULT_MASK 0x00600000 /* If !MRADV_CRC16_SELECT */ @@ -2103,13 +2110,18 @@ struct tg3_link_config { u16 speed; u8 duplex; u8 autoneg; + u8 flowctrl; +#define TG3_FLOW_CTRL_TX 0x01 +#define TG3_FLOW_CTRL_RX 0x02 /* Describes what we actually have. */ - u16 active_speed; + u8 active_flowctrl; + u8 active_duplex; #define SPEED_INVALID 0xffff #define DUPLEX_INVALID 0xff #define AUTONEG_INVALID 0xff + u16 active_speed; /* When we go in and out of low power mode we need * to swap with this state. @@ -2337,8 +2349,6 @@ struct tg3 { #define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000 #define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000 -#define TG3_FLAG_RX_PAUSE 0x00008000 -#define TG3_FLAG_TX_PAUSE 0x00010000 #define TG3_FLAG_PCIX_MODE 0x00020000 #define TG3_FLAG_PCI_HIGH_SPEED 0x00040000 #define TG3_FLAG_PCI_32BIT 0x00080000 diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 74c1f0f189f5..e7b4adc5c4e7 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -357,7 +357,7 @@ static int __devinit olympic_init(struct net_device *dev) if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { t=jiffies; - while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { + while (!(readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE)) { schedule() ; if(time_after(jiffies, t + 2*HZ)) { printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; @@ -671,7 +671,7 @@ static int olympic_open(struct net_device *dev) writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */ for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) - olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef; + olympic_priv->olympic_tx_ring[i].buffer=cpu_to_le32(0xdeadbeef); olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; olympic_priv->tx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_tx_ring, @@ -897,7 +897,7 @@ static void olympic_freemem(struct net_device *dev) dev_kfree_skb_irq(olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received]); olympic_priv->rx_ring_skb[olympic_priv->rx_status_last_received] = NULL; } - if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != 0xdeadbeef) { + if (olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer != cpu_to_le32(0xdeadbeef)) { pci_unmap_single(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[olympic_priv->rx_status_last_received].buffer), olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE); @@ -983,7 +983,7 @@ static irqreturn_t olympic_interrupt(int irq, void *dev_id) le32_to_cpu(olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer), olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]->len,PCI_DMA_TODEVICE); dev_kfree_skb_irq(olympic_priv->tx_ring_skb[olympic_priv->tx_ring_last_status]); - olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=0xdeadbeef; + olympic_priv->olympic_tx_ring[olympic_priv->tx_ring_last_status].buffer=cpu_to_le32(0xdeadbeef); olympic_priv->olympic_tx_status_ring[olympic_priv->tx_ring_last_status].status=0; } netif_wake_queue(dev); @@ -1432,7 +1432,7 @@ static void olympic_arb_cmd(struct net_device *dev) buffer_len = swab16(readw(buf_ptr+offsetof(struct mac_receive_buffer,buffer_length))); memcpy_fromio(skb_put(mac_frame, buffer_len), frame_data , buffer_len ) ; next_ptr=readw(buf_ptr+offsetof(struct mac_receive_buffer,next)); - } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + ntohs(next_ptr))); + } while (next_ptr && (buf_ptr=olympic_priv->olympic_lap + swab16(next_ptr))); mac_frame->protocol = tr_type_trans(mac_frame, dev); diff --git a/drivers/net/tokenring/olympic.h b/drivers/net/tokenring/olympic.h index 2fc59c997468..c91956310fb2 100644 --- a/drivers/net/tokenring/olympic.h +++ b/drivers/net/tokenring/olympic.h @@ -216,31 +216,31 @@ /* xxxx These structures are all little endian in hardware. */ struct olympic_tx_desc { - u32 buffer; - u32 status_length; + __le32 buffer; + __le32 status_length; }; struct olympic_tx_status { - u32 status; + __le32 status; }; struct olympic_rx_desc { - u32 buffer; - u32 res_length; + __le32 buffer; + __le32 res_length; }; struct olympic_rx_status { - u32 fragmentcnt_framelen; - u32 status_buffercnt; + __le32 fragmentcnt_framelen; + __le32 status_buffercnt; }; /* xxxx END These structures are all little endian in hardware. */ /* xxxx There may be more, but I'm pretty sure about these */ struct mac_receive_buffer { - u16 next ; + __le16 next ; u8 padding ; u8 frame_status ; - u16 buffer_length ; + __le16 buffer_length ; u8 frame_data ; }; diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index 93da3a36cde8..8909050b8ea7 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -2310,7 +2310,7 @@ static irqreturn_t smctr_interrupt(int irq, void *dev_id) && (tp->acb_head->subcmd == RW_TRC_STATUS_BLOCK)) { - if(tp->ptr_bcn_type != 0) + if(tp->ptr_bcn_type) { *(tp->ptr_bcn_type) = (__u32)((SBlock *)tp->misc_command_data)->BCN_Type; @@ -2980,7 +2980,7 @@ static int smctr_load_firmware(struct net_device *dev) return (UCODE_PRESENT); /* Verify the firmware exists and is there in the right amount. */ - if((tp->ptr_ucode == 0L) + if (!tp->ptr_ucode || (*(tp->ptr_ucode + UCODE_VERSION_OFFSET) < UCODE_VERSION)) { return (UCODE_NOT_PRESENT); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 6e8b18a3b3cc..6c6fc325c8f9 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -4168,7 +4168,7 @@ de4x5_bad_srom(struct de4x5_private *lp) { int i, status = 0; - for (i=0; i<sizeof(enet_det)/ETH_ALEN; i++) { + for (i = 0; i < ARRAY_SIZE(enet_det); i++) { if (!de4x5_strncmp((char *)&lp->srom, (char *)&enet_det[i], 3) && !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) { if (i == 0) { @@ -4188,7 +4188,7 @@ de4x5_strncmp(char *a, char *b, int n) { int ret=0; - for (;n && !ret;n--) { + for (;n && !ret; n--) { ret = *a++ - *b++; } diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index b4891caeae5a..656200472fa1 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -1909,7 +1909,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db) if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) { /* SROM V4.01 */ /* Get NIC support media mode */ - db->NIC_capability = le16_to_cpup((__le16 *)srom + 34/2); + db->NIC_capability = le16_to_cpup((__le16 *) (srom + 34)); db->PHY_reg4 = 0; for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) { switch( db->NIC_capability & tmp_reg ) { @@ -1921,8 +1921,8 @@ static void dmfe_parse_srom(struct dmfe_board_info * db) } /* Media Mode Force or not check */ - dmfe_mode = le32_to_cpup((__le32 *)srom + 34/4) & - le32_to_cpup((__le32 *)srom + 36/4); + dmfe_mode = (le32_to_cpup((__le32 *) (srom + 34)) & + le32_to_cpup((__le32 *) (srom + 36))); switch(dmfe_mode) { case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */ case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */ diff --git a/drivers/net/tun.c b/drivers/net/tun.c index f8b8c71187a0..46339f6bcd00 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -292,17 +292,6 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, return count; } -static inline size_t iov_total(const struct iovec *iv, unsigned long count) -{ - unsigned long i; - size_t len; - - for (i = 0, len = 0; i < count; i++) - len += iv[i].iov_len; - - return len; -} - static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, unsigned long count, loff_t pos) { @@ -313,7 +302,7 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv, DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count); - return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count)); + return tun_get_user(tun, (struct iovec *) iv, iov_length(iv, count)); } /* Put packet to the user space buffer */ @@ -364,7 +353,7 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name); - len = iov_total(iv, count); + len = iov_length(iv, count); if (len < 0) return -EINVAL; @@ -517,7 +506,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) /* Be promiscuous by default to maintain previous behaviour. */ tun->if_flags = IFF_PROMISC; /* Generate random Ethernet address. */ - *(u16 *)tun->dev_addr = htons(0x00FF); + *(__be16 *)tun->dev_addr = htons(0x00FF); get_random_bytes(tun->dev_addr + sizeof(u16), 4); memset(tun->chr_filter, 0, sizeof tun->chr_filter); diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 8d456e379a86..4ffd8739f8b7 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3614,9 +3614,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) ugeth_vdbg("%s: IN", __FUNCTION__); - if (!ugeth) - return IRQ_NONE; - uccf = ugeth->uccf; ug_info = ugeth->ug_info; diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index 1ffdd106f4c4..633a511d6cb6 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -101,17 +101,16 @@ static void dm_write_async_callback(struct urb *urb) usb_free_urb(urb); } -static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) +static void dm_write_async_helper(struct usbnet *dev, u8 reg, u8 value, + u16 length, void *data) { struct usb_ctrlrequest *req; struct urb *urb; int status; - devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); - urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { - deverr(dev, "Error allocating URB in dm_write_async!"); + deverr(dev, "Error allocating URB in dm_write_async_helper!"); return; } @@ -123,8 +122,8 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) } req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = DM_WRITE_REGS; - req->wValue = 0; + req->bRequest = length ? DM_WRITE_REGS : DM_WRITE_REG; + req->wValue = cpu_to_le16(value); req->wIndex = cpu_to_le16(reg); req->wLength = cpu_to_le16(length); @@ -142,45 +141,19 @@ static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) } } -static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) +static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) { - struct usb_ctrlrequest *req; - struct urb *urb; - int status; + devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); + dm_write_async_helper(dev, reg, 0, length, data); +} + +static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) +{ devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x", reg, value); - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - deverr(dev, "Error allocating URB in dm_write_async!"); - return; - } - - req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); - if (!req) { - deverr(dev, "Failed to allocate memory for control request"); - usb_free_urb(urb); - return; - } - - req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - req->bRequest = DM_WRITE_REG; - req->wValue = cpu_to_le16(value); - req->wIndex = cpu_to_le16(reg); - req->wLength = 0; - - usb_fill_control_urb(urb, dev->udev, - usb_sndctrlpipe(dev->udev, 0), - (void *)req, NULL, 0, dm_write_async_callback, req); - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - deverr(dev, "Error submitting the control message: status=%d", - status); - kfree(req); - usb_free_urb(urb); - } + dm_write_async_helper(dev, reg, value, 0, NULL); } static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 07263cd93f9c..87c180b563d3 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1338,7 +1338,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) if (debug > 2 && ioread8(ioaddr+ChipCmd) & CmdTxOn) printk(KERN_WARNING "%s: " - "rhine_interrupt() Tx engine" + "rhine_interrupt() Tx engine " "still on.\n", dev->name); } rhine_tx(dev); diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index ff37bf437a99..1d706eae3052 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -395,8 +395,7 @@ static int __init cosa_init(void) goto out_chrdev; } for (i=0; i<nr_cards; i++) { - class_device_create(cosa_class, NULL, MKDEV(cosa_major, i), - NULL, "cosa%d", i); + device_create(cosa_class, NULL, MKDEV(cosa_major, i), "cosa%d", i); } err = 0; goto out; @@ -415,7 +414,7 @@ static void __exit cosa_exit(void) printk(KERN_INFO "Unloading the cosa module\n"); for (i=0; i<nr_cards; i++) - class_device_destroy(cosa_class, MKDEV(cosa_major, i)); + device_destroy(cosa_class, MKDEV(cosa_major, i)); class_destroy(cosa_class); for (cosa=cosa_cards; nr_cards--; cosa++) { /* Clean up the per-channel data */ diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 12dae8e24844..cf27bf40d36e 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -1498,9 +1498,9 @@ do_bottom_half_rx(struct fst_card_info *card) * Dev_id is our fst_card_info pointer */ static irqreturn_t -fst_intr(int irq, void *dev_id) +fst_intr(int dummy, void *dev_id) { - struct fst_card_info *card; + struct fst_card_info *card = dev_id; struct fst_port_info *port; int rdidx; /* Event buffer indices */ int wridx; @@ -1509,17 +1509,12 @@ fst_intr(int irq, void *dev_id) unsigned int do_card_interrupt; unsigned int int_retry_count; - if ((card = dev_id) == NULL) { - dbg(DBG_INTR, "intr: spurious %d\n", irq); - return IRQ_NONE; - } - /* * Check to see if the interrupt was for this card * return if not * Note that the call to clear the interrupt is important */ - dbg(DBG_INTR, "intr: %d %p\n", irq, card); + dbg(DBG_INTR, "intr: %d %p\n", card->irq, card); if (card->state != FST_RUNNING) { printk_err ("Interrupt received for card %d in a non running state (%d)\n", diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 3caeb528eace..519e1550e2e7 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -42,7 +42,7 @@ static inline struct ppp_state* state(hdlc_device *hdlc) static int ppp_open(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - void *old_ioctl; + int (*old_ioctl)(struct net_device *, struct ifreq *, int); int result; dev->priv = &state(hdlc)->syncppp_ptr; diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c index 1a69a9aaa9b9..8895394e6006 100644 --- a/drivers/net/wan/hdlc_raw_eth.c +++ b/drivers/net/wan/hdlc_raw_eth.c @@ -59,7 +59,7 @@ static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr) raw_hdlc_proto new_settings; hdlc_device *hdlc = dev_to_hdlc(dev); int result; - void *old_ch_mtu; + int (*old_ch_mtu)(struct net_device *, int); int old_qlen; switch (ifr->ifr_settings.type) { diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 37c52e131750..6635ecef36e5 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -491,13 +491,13 @@ int lmc_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) /*fold00*/ int pos; int timeout = 500000; - if(xc.data == 0x0){ + if (!xc.data) { ret = -EINVAL; break; } data = kmalloc(xc.len, GFP_KERNEL); - if(data == 0x0){ + if (!data) { printk(KERN_WARNING "%s: Failed to allocate memory for copy\n", dev->name); ret = -ENOMEM; break; @@ -1643,7 +1643,7 @@ static int lmc_rx (struct net_device *dev) /*fold00*/ * just allocate an skb buff and continue. */ - if(skb == 0x0){ + if (!skb) { nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); if (nsb) { sc->lmc_rxq[i] = nsb; diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index c9c878cd5c72..8aa461c941ce 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -1219,10 +1219,6 @@ lmc_t1_watchdog (lmc_softc_t * const sc) static void lmc_set_protocol (lmc_softc_t * const sc, lmc_ctl_t * ctl) { - if (ctl == 0) - { - sc->ictl.keepalive_onoff = LMC_CTL_ON; - - return; - } + if (!ctl) + sc->ictl.keepalive_onoff = LMC_CTL_ON; } diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index 426c0678d983..85315758198d 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -208,7 +208,7 @@ void lmc_proto_close(lmc_softc_t *sc) /*FOLD00*/ lmc_trace(sc->lmc_device, "lmc_proto_close out"); } -unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ +__be16 lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ { lmc_trace(sc->lmc_device, "lmc_proto_type in"); switch(sc->if_type){ diff --git a/drivers/net/wan/lmc/lmc_proto.h b/drivers/net/wan/lmc/lmc_proto.h index 080a55773349..ccaa69e8b3c7 100644 --- a/drivers/net/wan/lmc/lmc_proto.h +++ b/drivers/net/wan/lmc/lmc_proto.h @@ -8,7 +8,7 @@ void lmc_proto_reopen(lmc_softc_t *sc); int lmc_proto_ioctl(lmc_softc_t *sc, struct ifreq *ifr, int cmd); void lmc_proto_open(lmc_softc_t *sc); void lmc_proto_close(lmc_softc_t *sc); -unsigned short lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb); +__be16 lmc_proto_type(lmc_softc_t *sc, struct sk_buff *skb); void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb); int lmc_skb_rawpackets(char *buf, char **start, off_t offset, int len, int unused); diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 99fee2f1d019..57914fbd41d3 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -2365,17 +2365,17 @@ static void falc_intr(pc300_t * card) static irqreturn_t cpc_intr(int irq, void *dev_id) { - pc300_t *card; + pc300_t *card = dev_id; volatile ucchar plx_status; - if ((card = (pc300_t *) dev_id) == 0) { + if (!card) { #ifdef PC300_DEBUG_INTR printk("cpc_intr: spurious intr %d\n", irq); #endif return IRQ_NONE; /* spurious intr */ } - if (card->hw.rambase == 0) { + if (!card->hw.rambase) { #ifdef PC300_DEBUG_INTR printk("cpc_intr: spurious intr2 %d\n", irq); #endif @@ -3648,7 +3648,7 @@ static void __devexit cpc_remove_one(struct pci_dev *pdev) { pc300_t *card = pci_get_drvdata(pdev); - if (card->hw.rambase != 0) { + if (card->hw.rambase) { int i; /* Disable interrupts on the PCI bridge */ diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index e24a7b095dd6..63abfd72542d 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -313,7 +313,7 @@ static int cpc_tty_open(struct tty_struct *tty, struct file *flip) if (cpc_tty->num_open == 0) { /* first open of this tty */ if (!cpc_tty_area[port].buf_tx){ cpc_tty_area[port].buf_tx = kmalloc(CPC_TTY_MAX_MTU,GFP_KERNEL); - if (cpc_tty_area[port].buf_tx == 0){ + if (!cpc_tty_area[port].buf_tx) { CPC_TTY_DBG("%s: error in memory allocation\n",cpc_tty->name); return -ENOMEM; } @@ -678,7 +678,7 @@ static void cpc_tty_rx_work(struct work_struct *work) for (j=0; j < CPC_TTY_NPORTS; j++) { cpc_tty = &cpc_tty_area[port]; - if ((buf=cpc_tty->buf_rx.first) != 0) { + if ((buf=cpc_tty->buf_rx.first) != NULL) { if (cpc_tty->tty) { ld = tty_ldisc_ref(cpc_tty->tty); if (ld) { @@ -784,7 +784,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev) } new = kmalloc(rx_len + sizeof(st_cpc_rx_buf), GFP_ATOMIC); - if (new == 0) { + if (!new) { cpc_tty_rx_disc_frame(pc300chan); continue; } @@ -863,7 +863,7 @@ void cpc_tty_receive(pc300dev_t *pc300dev) } new->size = rx_len; new->next = NULL; - if (cpc_tty->buf_rx.first == 0) { + if (cpc_tty->buf_rx.first == NULL) { cpc_tty->buf_rx.first = new; cpc_tty->buf_rx.last = new; } else { @@ -891,7 +891,7 @@ static void cpc_tty_tx_work(struct work_struct *work) CPC_TTY_DBG("%s: cpc_tty_tx_work init\n",cpc_tty->name); - if ((tty = cpc_tty->tty) == 0) { + if ((tty = cpc_tty->tty) == NULL) { CPC_TTY_DBG("%s: the interface is not opened\n",cpc_tty->name); return; } @@ -1027,7 +1027,7 @@ void cpc_tty_unregister_service(pc300dev_t *pc300dev) ulong flags; int res; - if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == 0) { + if ((cpc_tty= (st_cpc_tty_area *) pc300dev->cpc_tty) == NULL) { CPC_TTY_DBG("%s: interface is not TTY\n", pc300dev->dev->name); return; } diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 2e8b5c2de887..15d5c58e57bc 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -391,8 +391,8 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) spin_lock_init( &nl->lock ); /* store MAC address (generate if that isn't known) */ - *(u16 *)dev->dev_addr = htons( 0x00ff ); - *(u32 *)(dev->dev_addr + 2) = htonl( 0x01000000 | + *(__be16 *)dev->dev_addr = htons( 0x00ff ); + *(__be32 *)(dev->dev_addr + 2) = htonl( 0x01000000 | ( (mac[num] ? mac[num] : (u32)((long)dev->priv)) & 0x00ffffff) ); /* store link settings (speed, receive level ) */ diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 05df0a345b60..73e2f2780932 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -867,7 +867,7 @@ static void sdla_receive(struct net_device *dev) spin_unlock_irqrestore(&sdla_lock, flags); } -static irqreturn_t sdla_isr(int irq, void *dev_id) +static irqreturn_t sdla_isr(int dummy, void *dev_id) { struct net_device *dev; struct frad_local *flp; @@ -879,7 +879,8 @@ static irqreturn_t sdla_isr(int irq, void *dev_id) if (!flp->initialized) { - printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", dev->name, irq); + printk(KERN_WARNING "%s: irq %d for uninitialized device.\n", + dev->name, dev->irq); return IRQ_NONE; } diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 8e320b76ae0e..d4aab8a28b61 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -715,7 +715,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, } for (i = 0; i < sizeof(firmware); i += 4) - writel(htonl(*(u32*)(firmware + i)), mem + PDM_OFFSET + i); + writel(ntohl(*(__be32*)(firmware + i)), mem + PDM_OFFSET + i); for (i = 0; i < ports; i++) writel(card->status_address + @@ -743,7 +743,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, }while (time_after(timeout, jiffies)); if (!stat) { - printk(KERN_WARNING "wanXL %s: timeout while initializing card" + printk(KERN_WARNING "wanXL %s: timeout while initializing card " "firmware\n", pci_name(pdev)); wanxl_pci_remove_one(pdev); return -ENODEV; diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 2c08c0a5a0df..f372960904b2 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -545,6 +545,62 @@ config USB_ZD1201 To compile this driver as a module, choose M here: the module will be called zd1201. +config RTL8180 + tristate "Realtek 8180/8185 PCI support" + depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL + select EEPROM_93CX6 + ---help--- + This is a driver for RTL8180 and RTL8185 based cards. + These are PCI based chips found in cards such as: + + (RTL8185 802.11g) + A-Link WL54PC + + (RTL8180 802.11b) + Belkin F5D6020 v3 + Belkin F5D6020 v3 + Dlink DWL-610 + Dlink DWL-510 + Netgear MA521 + Level-One WPC-0101 + Acer Aspire 1357 LMi + VCTnet PC-11B1 + Ovislink AirLive WL-1120PCM + Mentor WL-PCI + Linksys WPC11 v4 + TrendNET TEW-288PI + D-Link DWL-520 Rev D + Repotec RP-WP7126 + TP-Link TL-WN250/251 + Zonet ZEW1000 + Longshine LCS-8031-R + HomeLine HLW-PCC200 + GigaFast WF721-AEX + Planet WL-3553 + Encore ENLWI-PCI1-NT + TrendNET TEW-266PC + Gigabyte GN-WLMR101 + Siemens-fujitsu Amilo D1840W + Edimax EW-7126 + PheeNet WL-11PCIR + Tonze PC-2100T + Planet WL-8303 + Dlink DWL-650 v M1 + Edimax EW-7106 + Q-Tec 770WC + Topcom Skyr@cer 4011b + Roper FreeLan 802.11b (edition 2004) + Wistron Neweb Corp CB-200B + Pentagram HorNET + QTec 775WC + TwinMOS Booming B Series + Micronet SP906BB + Sweex LC700010 + Surecom EP-9428 + Safecom SWLCR-1100 + + Thanks to Realtek for their support! + config RTL8187 tristate "Realtek 8187 USB support" depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL @@ -648,6 +704,23 @@ config P54_PCI If you choose to build a module, it'll be called p54pci. +config ATH5K + tristate "Atheros 5xxx wireless cards support" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + ---help--- + This module adds support for wireless adapters based on + Atheros 5xxx chipset. + + Currently the following chip versions are supported: + + MAC: AR5211 AR5212 + PHY: RF5111/2111 RF5112/2112 RF5413/2413 + + This driver uses the kernel's mac80211 subsystem. + + If you choose to build a module, it'll be called ath5k. Say M if + unsure. + source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/bcm43xx/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 6f32b53ee128..6af7b158624e 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -47,14 +47,20 @@ obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o obj-$(CONFIG_USB_ZD1201) += zd1201.o obj-$(CONFIG_LIBERTAS) += libertas/ +rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o + +obj-$(CONFIG_RTL8180) += rtl8180.o obj-$(CONFIG_RTL8187) += rtl8187.o obj-$(CONFIG_ADM8211) += adm8211.o -obj-$(CONFIG_IWLWIFI) += iwlwifi/ +obj-$(CONFIG_IWL3945) += iwlwifi/ +obj-$(CONFIG_IWL4965) += iwlwifi/ obj-$(CONFIG_RT2X00) += rt2x00/ obj-$(CONFIG_P54_COMMON) += p54common.o obj-$(CONFIG_P54_USB) += p54usb.o obj-$(CONFIG_P54_PCI) += p54pci.o + +obj-$(CONFIG_ATH5K) += ath5k/ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 5bf7913aadda..79796186713e 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -104,7 +104,7 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) if (!priv->eeprom) return -ENOMEM; - eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words); + eeprom_93cx6_multiread(&eeprom, 0, (__le16 *)priv->eeprom, words); cr49 = le16_to_cpu(priv->eeprom->cr49); priv->rf_type = (cr49 >> 3) & 0x7; @@ -1312,7 +1312,8 @@ static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) return 0; } -static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id, +static int adm8211_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct adm8211_priv *priv = dev->priv; @@ -1867,9 +1868,9 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_iounmap; } - *(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0)); - *(u16 *)&perm_addr[4] = - le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF); + *(__le32 *)perm_addr = cpu_to_le32(ADM8211_CSR_READ(PAR0)); + *(__le16 *)&perm_addr[4] = + cpu_to_le16(ADM8211_CSR_READ(PAR1) & 0xFFFF); if (!is_valid_ether_addr(perm_addr)) { printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n", diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 074055e18c5c..932d6b1c9d0b 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -38,6 +38,7 @@ #include <linux/crypto.h> #include <asm/io.h> #include <asm/system.h> +#include <asm/unaligned.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -500,140 +501,143 @@ typedef struct { /* This structure came from an email sent to me from an engineer at aironet for inclusion into this driver */ typedef struct { - u16 len; - u16 kindex; + __le16 len; + __le16 kindex; u8 mac[ETH_ALEN]; - u16 klen; + __le16 klen; u8 key[16]; } WepKeyRid; /* These structures are from the Aironet's PC4500 Developers Manual */ typedef struct { - u16 len; + __le16 len; u8 ssid[32]; } Ssid; typedef struct { - u16 len; + __le16 len; Ssid ssids[3]; } SsidRid; typedef struct { - u16 len; - u16 modulation; -#define MOD_DEFAULT 0 -#define MOD_CCK 1 -#define MOD_MOK 2 + __le16 len; + __le16 modulation; +#define MOD_DEFAULT cpu_to_le16(0) +#define MOD_CCK cpu_to_le16(1) +#define MOD_MOK cpu_to_le16(2) } ModulationRid; typedef struct { - u16 len; /* sizeof(ConfigRid) */ - u16 opmode; /* operating mode */ -#define MODE_STA_IBSS 0 -#define MODE_STA_ESS 1 -#define MODE_AP 2 -#define MODE_AP_RPTR 3 -#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */ -#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */ -#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */ -#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */ -#define MODE_ANTENNA_ALIGN (1<<11) /* enable antenna alignment */ -#define MODE_ETHER_LLC (1<<12) /* enable ethernet LLC */ -#define MODE_LEAF_NODE (1<<13) /* enable leaf node bridge */ -#define MODE_CF_POLLABLE (1<<14) /* enable CF pollable */ -#define MODE_MIC (1<<15) /* enable MIC */ - u16 rmode; /* receive mode */ -#define RXMODE_BC_MC_ADDR 0 -#define RXMODE_BC_ADDR 1 /* ignore multicasts */ -#define RXMODE_ADDR 2 /* ignore multicast and broadcast */ -#define RXMODE_RFMON 3 /* wireless monitor mode */ -#define RXMODE_RFMON_ANYBSS 4 -#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */ -#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */ -#define RXMODE_NORMALIZED_RSSI (1<<9) /* return normalized RSSI */ - u16 fragThresh; - u16 rtsThres; + __le16 len; /* sizeof(ConfigRid) */ + __le16 opmode; /* operating mode */ +#define MODE_STA_IBSS cpu_to_le16(0) +#define MODE_STA_ESS cpu_to_le16(1) +#define MODE_AP cpu_to_le16(2) +#define MODE_AP_RPTR cpu_to_le16(3) +#define MODE_CFG_MASK cpu_to_le16(0xff) +#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */ +#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */ +#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extenstions */ +#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */ +#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */ +#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */ +#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */ +#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */ +#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */ + __le16 rmode; /* receive mode */ +#define RXMODE_BC_MC_ADDR cpu_to_le16(0) +#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */ +#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */ +#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */ +#define RXMODE_RFMON_ANYBSS cpu_to_le16(4) +#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */ +#define RXMODE_MASK cpu_to_le16(255) +#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */ +#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER) +#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */ + __le16 fragThresh; + __le16 rtsThres; u8 macAddr[ETH_ALEN]; u8 rates[8]; - u16 shortRetryLimit; - u16 longRetryLimit; - u16 txLifetime; /* in kusec */ - u16 rxLifetime; /* in kusec */ - u16 stationary; - u16 ordering; - u16 u16deviceType; /* for overriding device type */ - u16 cfpRate; - u16 cfpDuration; - u16 _reserved1[3]; + __le16 shortRetryLimit; + __le16 longRetryLimit; + __le16 txLifetime; /* in kusec */ + __le16 rxLifetime; /* in kusec */ + __le16 stationary; + __le16 ordering; + __le16 u16deviceType; /* for overriding device type */ + __le16 cfpRate; + __le16 cfpDuration; + __le16 _reserved1[3]; /*---------- Scanning/Associating ----------*/ - u16 scanMode; -#define SCANMODE_ACTIVE 0 -#define SCANMODE_PASSIVE 1 -#define SCANMODE_AIROSCAN 2 - u16 probeDelay; /* in kusec */ - u16 probeEnergyTimeout; /* in kusec */ - u16 probeResponseTimeout; - u16 beaconListenTimeout; - u16 joinNetTimeout; - u16 authTimeout; - u16 authType; -#define AUTH_OPEN 0x1 -#define AUTH_ENCRYPT 0x101 -#define AUTH_SHAREDKEY 0x102 -#define AUTH_ALLOW_UNENCRYPTED 0x200 - u16 associationTimeout; - u16 specifiedApTimeout; - u16 offlineScanInterval; - u16 offlineScanDuration; - u16 linkLossDelay; - u16 maxBeaconLostTime; - u16 refreshInterval; -#define DISABLE_REFRESH 0xFFFF - u16 _reserved1a[1]; + __le16 scanMode; +#define SCANMODE_ACTIVE cpu_to_le16(0) +#define SCANMODE_PASSIVE cpu_to_le16(1) +#define SCANMODE_AIROSCAN cpu_to_le16(2) + __le16 probeDelay; /* in kusec */ + __le16 probeEnergyTimeout; /* in kusec */ + __le16 probeResponseTimeout; + __le16 beaconListenTimeout; + __le16 joinNetTimeout; + __le16 authTimeout; + __le16 authType; +#define AUTH_OPEN cpu_to_le16(0x1) +#define AUTH_ENCRYPT cpu_to_le16(0x101) +#define AUTH_SHAREDKEY cpu_to_le16(0x102) +#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200) + __le16 associationTimeout; + __le16 specifiedApTimeout; + __le16 offlineScanInterval; + __le16 offlineScanDuration; + __le16 linkLossDelay; + __le16 maxBeaconLostTime; + __le16 refreshInterval; +#define DISABLE_REFRESH cpu_to_le16(0xFFFF) + __le16 _reserved1a[1]; /*---------- Power save operation ----------*/ - u16 powerSaveMode; -#define POWERSAVE_CAM 0 -#define POWERSAVE_PSP 1 -#define POWERSAVE_PSPCAM 2 - u16 sleepForDtims; - u16 listenInterval; - u16 fastListenInterval; - u16 listenDecay; - u16 fastListenDelay; - u16 _reserved2[2]; + __le16 powerSaveMode; +#define POWERSAVE_CAM cpu_to_le16(0) +#define POWERSAVE_PSP cpu_to_le16(1) +#define POWERSAVE_PSPCAM cpu_to_le16(2) + __le16 sleepForDtims; + __le16 listenInterval; + __le16 fastListenInterval; + __le16 listenDecay; + __le16 fastListenDelay; + __le16 _reserved2[2]; /*---------- Ap/Ibss config items ----------*/ - u16 beaconPeriod; - u16 atimDuration; - u16 hopPeriod; - u16 channelSet; - u16 channel; - u16 dtimPeriod; - u16 bridgeDistance; - u16 radioID; + __le16 beaconPeriod; + __le16 atimDuration; + __le16 hopPeriod; + __le16 channelSet; + __le16 channel; + __le16 dtimPeriod; + __le16 bridgeDistance; + __le16 radioID; /*---------- Radio configuration ----------*/ - u16 radioType; -#define RADIOTYPE_DEFAULT 0 -#define RADIOTYPE_802_11 1 -#define RADIOTYPE_LEGACY 2 + __le16 radioType; +#define RADIOTYPE_DEFAULT cpu_to_le16(0) +#define RADIOTYPE_802_11 cpu_to_le16(1) +#define RADIOTYPE_LEGACY cpu_to_le16(2) u8 rxDiversity; u8 txDiversity; - u16 txPower; + __le16 txPower; #define TXPOWER_DEFAULT 0 - u16 rssiThreshold; + __le16 rssiThreshold; #define RSSI_DEFAULT 0 - u16 modulation; -#define PREAMBLE_AUTO 0 -#define PREAMBLE_LONG 1 -#define PREAMBLE_SHORT 2 - u16 preamble; - u16 homeProduct; - u16 radioSpecific; + __le16 modulation; +#define PREAMBLE_AUTO cpu_to_le16(0) +#define PREAMBLE_LONG cpu_to_le16(1) +#define PREAMBLE_SHORT cpu_to_le16(2) + __le16 preamble; + __le16 homeProduct; + __le16 radioSpecific; /*---------- Aironet Extensions ----------*/ u8 nodeName[16]; - u16 arlThreshold; - u16 arlDecay; - u16 arlDelay; - u16 _reserved4[1]; + __le16 arlThreshold; + __le16 arlDecay; + __le16 arlDelay; + __le16 _reserved4[1]; /*---------- Aironet Extensions ----------*/ u8 magicAction; #define MAGIC_ACTION_STSCHG 1 @@ -643,34 +647,34 @@ typedef struct { #define MAGIC_SWITCH_TO_PSP (0<<10) #define MAGIC_STAY_IN_CAM (1<<10) u8 magicControl; - u16 autoWake; + __le16 autoWake; } ConfigRid; typedef struct { - u16 len; + __le16 len; u8 mac[ETH_ALEN]; - u16 mode; - u16 errorCode; - u16 sigQuality; - u16 SSIDlen; + __le16 mode; + __le16 errorCode; + __le16 sigQuality; + __le16 SSIDlen; char SSID[32]; char apName[16]; u8 bssid[4][ETH_ALEN]; - u16 beaconPeriod; - u16 dimPeriod; - u16 atimDuration; - u16 hopPeriod; - u16 channelSet; - u16 channel; - u16 hopsToBackbone; - u16 apTotalLoad; - u16 generatedLoad; - u16 accumulatedArl; - u16 signalQuality; - u16 currentXmitRate; - u16 apDevExtensions; - u16 normalizedSignalStrength; - u16 shortPreamble; + __le16 beaconPeriod; + __le16 dimPeriod; + __le16 atimDuration; + __le16 hopPeriod; + __le16 channelSet; + __le16 channel; + __le16 hopsToBackbone; + __le16 apTotalLoad; + __le16 generatedLoad; + __le16 accumulatedArl; + __le16 signalQuality; + __le16 currentXmitRate; + __le16 apDevExtensions; + __le16 normalizedSignalStrength; + __le16 shortPreamble; u8 apIP[4]; u8 noisePercent; /* Noise percent in last second */ u8 noisedBm; /* Noise dBm in last second */ @@ -678,9 +682,9 @@ typedef struct { u8 noiseAvedBm; /* Noise dBm in last minute */ u8 noiseMaxPercent; /* Highest noise percent in last minute */ u8 noiseMaxdBm; /* Highest noise dbm in last minute */ - u16 load; + __le16 load; u8 carrier[4]; - u16 assocStatus; + __le16 assocStatus; #define STAT_NOPACKETS 0 #define STAT_NOCARRIERSET 10 #define STAT_GOTCARRIERSET 11 @@ -705,82 +709,82 @@ typedef struct { } StatusRid; typedef struct { - u16 len; - u16 spacer; - u32 vals[100]; + __le16 len; + __le16 spacer; + __le32 vals[100]; } StatsRid; typedef struct { - u16 len; + __le16 len; u8 ap[4][ETH_ALEN]; } APListRid; typedef struct { - u16 len; + __le16 len; char oui[3]; char zero; - u16 prodNum; + __le16 prodNum; char manName[32]; char prodName[16]; char prodVer[8]; char factoryAddr[ETH_ALEN]; char aironetAddr[ETH_ALEN]; - u16 radioType; - u16 country; + __le16 radioType; + __le16 country; char callid[ETH_ALEN]; char supportedRates[8]; char rxDiversity; char txDiversity; - u16 txPowerLevels[8]; - u16 hardVer; - u16 hardCap; - u16 tempRange; - u16 softVer; - u16 softSubVer; - u16 interfaceVer; - u16 softCap; - u16 bootBlockVer; - u16 requiredHard; - u16 extSoftCap; + __le16 txPowerLevels[8]; + __le16 hardVer; + __le16 hardCap; + __le16 tempRange; + __le16 softVer; + __le16 softSubVer; + __le16 interfaceVer; + __le16 softCap; + __le16 bootBlockVer; + __le16 requiredHard; + __le16 extSoftCap; } CapabilityRid; /* Only present on firmware >= 5.30.17 */ typedef struct { - u16 unknown[4]; + __le16 unknown[4]; u8 fixed[12]; /* WLAN management frame */ u8 iep[624]; } BSSListRidExtra; typedef struct { - u16 len; - u16 index; /* First is 0 and 0xffff means end of list */ + __le16 len; + __le16 index; /* First is 0 and 0xffff means end of list */ #define RADIO_FH 1 /* Frequency hopping radio type */ #define RADIO_DS 2 /* Direct sequence radio type */ #define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ - u16 radioType; + __le16 radioType; u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ u8 zero; u8 ssidLen; u8 ssid[32]; - u16 dBm; -#define CAP_ESS (1<<0) -#define CAP_IBSS (1<<1) -#define CAP_PRIVACY (1<<4) -#define CAP_SHORTHDR (1<<5) - u16 cap; - u16 beaconInterval; + __le16 dBm; +#define CAP_ESS cpu_to_le16(1<<0) +#define CAP_IBSS cpu_to_le16(1<<1) +#define CAP_PRIVACY cpu_to_le16(1<<4) +#define CAP_SHORTHDR cpu_to_le16(1<<5) + __le16 cap; + __le16 beaconInterval; u8 rates[8]; /* Same as rates for config rid */ struct { /* For frequency hopping only */ - u16 dwell; + __le16 dwell; u8 hopSet; u8 hopPattern; u8 hopIndex; u8 fill; } fh; - u16 dsChannel; - u16 atimWindow; + __le16 dsChannel; + __le16 atimWindow; /* Only present on firmware >= 5.30.17 */ BSSListRidExtra extra; @@ -811,7 +815,7 @@ typedef struct { } MICRid; typedef struct { - u16 typelen; + __be16 typelen; union { u8 snap[8]; @@ -823,8 +827,8 @@ typedef struct { u8 fieldtype[2]; } llc; } u; - u32 mic; - u32 seq; + __be32 mic; + __be32 seq; } MICBuffer; typedef struct { @@ -943,7 +947,7 @@ typedef struct { int position; // current position (byte offset) in message union { u8 d8[4]; - u32 d32; + __be32 d32; } part; // saves partial message word across update() calls } emmh32_context; @@ -1100,11 +1104,11 @@ static void enable_interrupts(struct airo_info*); static void disable_interrupts(struct airo_info*); static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp); static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); -static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, +static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, int whichbap); -static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, +static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, int whichbap); -static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen, +static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen, int whichbap); static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); @@ -1187,7 +1191,7 @@ struct airo_info { #define JOB_WSTATS 8 #define JOB_SCAN_RESULTS 9 unsigned long jobs; - int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, + int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen, int whichbap); unsigned short *flash; tdsRssiEntry *rssi; @@ -1235,8 +1239,9 @@ struct airo_info { BSSListElement *networks; }; -static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, - int whichbap) { +static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, + int whichbap) +{ return ai->bap_read(ai, pu16Dst, bytelen, whichbap); } @@ -1635,7 +1640,7 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, crypto_cipher_encrypt_one(tfm, plain, plain); cipher = plain; for (j = 0; (j < 16) && (i < ARRAY_SIZE(context->coeff)); ) { - context->coeff[i++] = ntohl(*(u32 *)&cipher[j]); + context->coeff[i++] = ntohl(*(__be32 *)&cipher[j]); j += 4; } } @@ -1668,12 +1673,12 @@ static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) context->position++; len--; } while (byte_position < 4); - MIC_ACCUM(htonl(context->part.d32)); + MIC_ACCUM(ntohl(context->part.d32)); } /* deal with full 32-bit words */ while (len >= 4) { - MIC_ACCUM(htonl(*(u32 *)pOctets)); + MIC_ACCUM(ntohl(*(__be32 *)pOctets)); context->position += 4; pOctets += 4; len -= 4; @@ -1706,7 +1711,7 @@ static void emmh32_final(emmh32_context *context, u8 digest[4]) byte_position = context->position & 3; if (byte_position) { /* have a partial word in part to deal with */ - val = htonl(context->part.d32); + val = ntohl(context->part.d32); MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ } @@ -1726,8 +1731,8 @@ static void emmh32_final(emmh32_context *context, u8 digest[4]) } static int readBSSListRid(struct airo_info *ai, int first, - BSSListRid *list) { - int rc; + BSSListRid *list) +{ Cmd cmd; Resp rsp; @@ -1744,75 +1749,43 @@ static int readBSSListRid(struct airo_info *ai, int first, schedule_timeout_uninterruptible(3 * HZ); ai->list_bss_task = NULL; } - rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext, + return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext, list, ai->bssListRidLen, 1); - - list->len = le16_to_cpu(list->len); - list->index = le16_to_cpu(list->index); - list->radioType = le16_to_cpu(list->radioType); - list->cap = le16_to_cpu(list->cap); - list->beaconInterval = le16_to_cpu(list->beaconInterval); - list->fh.dwell = le16_to_cpu(list->fh.dwell); - list->dsChannel = le16_to_cpu(list->dsChannel); - list->atimWindow = le16_to_cpu(list->atimWindow); - list->dBm = le16_to_cpu(list->dBm); - return rc; } -static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp, int lock) { - int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, +static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock) +{ + return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, wkr, sizeof(*wkr), lock); - - wkr->len = le16_to_cpu(wkr->len); - wkr->kindex = le16_to_cpu(wkr->kindex); - wkr->klen = le16_to_cpu(wkr->klen); - return rc; } -/* In the writeXXXRid routines we copy the rids so that we don't screwup - * the originals when we endian them... */ -static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lock) { - int rc; - WepKeyRid wkr = *pwkr; - wkr.len = cpu_to_le16(wkr.len); - wkr.kindex = cpu_to_le16(wkr.kindex); - wkr.klen = cpu_to_le16(wkr.klen); - rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock); - if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); +static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock) +{ + int rc; + rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock); + if (rc!=SUCCESS) + airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); if (perm) { - rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock); - if (rc!=SUCCESS) { + rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock); + if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); - } } return rc; } -static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) { - int i; - int rc = PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); - - ssidr->len = le16_to_cpu(ssidr->len); - for(i = 0; i < 3; i++) { - ssidr->ssids[i].len = le16_to_cpu(ssidr->ssids[i].len); - } - return rc; +static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) +{ + return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); } -static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) { - int rc; - int i; - SsidRid ssidr = *pssidr; - ssidr.len = cpu_to_le16(ssidr.len); - for(i = 0; i < 3; i++) { - ssidr.ssids[i].len = cpu_to_le16(ssidr.ssids[i].len); - } - rc = PC4500_writerid(ai, RID_SSID, &ssidr, sizeof(ssidr), lock); - return rc; +static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) +{ + return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock); } -static int readConfigRid(struct airo_info*ai, int lock) { + +static int readConfigRid(struct airo_info *ai, int lock) +{ int rc; - u16 *s; ConfigRid cfg; if (ai->config.len) @@ -1822,24 +1795,12 @@ static int readConfigRid(struct airo_info*ai, int lock) { if (rc != SUCCESS) return rc; - for(s = &cfg.len; s <= &cfg.rtsThres; s++) *s = le16_to_cpu(*s); - - for(s = &cfg.shortRetryLimit; s <= &cfg.radioType; s++) - *s = le16_to_cpu(*s); - - for(s = &cfg.txPower; s <= &cfg.radioSpecific; s++) - *s = le16_to_cpu(*s); - - for(s = &cfg.arlThreshold; s <= &cfg._reserved4[0]; s++) - *s = cpu_to_le16(*s); - - for(s = &cfg.autoWake; s <= &cfg.autoWake; s++) - *s = cpu_to_le16(*s); - ai->config = cfg; return SUCCESS; } -static inline void checkThrottle(struct airo_info *ai) { + +static inline void checkThrottle(struct airo_info *ai) +{ int i; /* Old hardware had a limit on encryption speed */ if (ai->config.authType != AUTH_OPEN && maxencrypt) { @@ -1850,8 +1811,9 @@ static inline void checkThrottle(struct airo_info *ai) { } } } -static int writeConfigRid(struct airo_info*ai, int lock) { - u16 *s; + +static int writeConfigRid(struct airo_info *ai, int lock) +{ ConfigRid cfgr; if (!test_bit (FLAG_COMMIT, &ai->flags)) @@ -1862,70 +1824,37 @@ static int writeConfigRid(struct airo_info*ai, int lock) { checkThrottle(ai); cfgr = ai->config; - if ((cfgr.opmode & 0xFF) == MODE_STA_IBSS) + if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS) set_bit(FLAG_ADHOC, &ai->flags); else clear_bit(FLAG_ADHOC, &ai->flags); - for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s); - - for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++) - *s = cpu_to_le16(*s); - - for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++) - *s = cpu_to_le16(*s); - - for(s = &cfgr.arlThreshold; s <= &cfgr._reserved4[0]; s++) - *s = cpu_to_le16(*s); - - for(s = &cfgr.autoWake; s <= &cfgr.autoWake; s++) - *s = cpu_to_le16(*s); - return PC4500_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); } -static int readStatusRid(struct airo_info*ai, StatusRid *statr, int lock) { - int rc = PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); - u16 *s; - statr->len = le16_to_cpu(statr->len); - for(s = &statr->mode; s <= &statr->SSIDlen; s++) *s = le16_to_cpu(*s); - - for(s = &statr->beaconPeriod; s <= &statr->shortPreamble; s++) - *s = le16_to_cpu(*s); - statr->load = le16_to_cpu(statr->load); - statr->assocStatus = le16_to_cpu(statr->assocStatus); - return rc; +static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock) +{ + return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); } -static int readAPListRid(struct airo_info*ai, APListRid *aplr) { - int rc = PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1); - aplr->len = le16_to_cpu(aplr->len); - return rc; + +static int readAPListRid(struct airo_info *ai, APListRid *aplr) +{ + return PC4500_readrid(ai, RID_APLIST, aplr, sizeof(*aplr), 1); } -static int writeAPListRid(struct airo_info*ai, APListRid *aplr, int lock) { - int rc; - aplr->len = cpu_to_le16(aplr->len); - rc = PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); - return rc; + +static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock) +{ + return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); } -static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr, int lock) { - int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); - u16 *s; - capr->len = le16_to_cpu(capr->len); - capr->prodNum = le16_to_cpu(capr->prodNum); - capr->radioType = le16_to_cpu(capr->radioType); - capr->country = le16_to_cpu(capr->country); - for(s = &capr->txPowerLevels[0]; s <= &capr->requiredHard; s++) - *s = le16_to_cpu(*s); - return rc; +static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock) +{ + return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); } -static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) { - int rc = PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); - u32 *i; - sr->len = le16_to_cpu(sr->len); - for(i = &sr->vals[0]; i <= &sr->vals[99]; i++) *i = le32_to_cpu(*i); - return rc; +static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) +{ + return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); } static void try_auto_wep(struct airo_info *ai) @@ -2026,13 +1955,14 @@ static int mpi_send_packet (struct net_device *dev) { struct sk_buff *skb; unsigned char *buffer; - s16 len, *payloadLen; + s16 len; + __le16 *payloadLen; struct airo_info *ai = dev->priv; u8 *sendbuf; /* get a packet to send */ - if ((skb = skb_dequeue(&ai->txq)) == 0) { + if ((skb = skb_dequeue(&ai->txq)) == NULL) { airo_print_err(dev->name, "%s: Dequeue'd zero in send_packet()", __FUNCTION__); @@ -2059,7 +1989,7 @@ static int mpi_send_packet (struct net_device *dev) memcpy((char *)ai->txfids[0].virtual_host_addr, (char *)&wifictlhdr8023, sizeof(wifictlhdr8023)); - payloadLen = (s16 *)(ai->txfids[0].virtual_host_addr + + payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr + sizeof(wifictlhdr8023)); sendbuf = ai->txfids[0].virtual_host_addr + sizeof(wifictlhdr8023) + 2 ; @@ -2069,7 +1999,7 @@ static int mpi_send_packet (struct net_device *dev) * we don't need to account for it in the length */ if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((u16 *)buffer)[6]) != 0x888E)) { + (ntohs(((__be16 *)buffer)[6]) != 0x888E)) { MICBuffer pMic; if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS) @@ -2104,7 +2034,7 @@ static int mpi_send_packet (struct net_device *dev) static void get_tx_error(struct airo_info *ai, s32 fid) { - u16 status; + __le16 status; if (fid < 0) status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status; @@ -2135,7 +2065,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid) /* Faster to skip over useless data than to do * another bap_setup(). We are at offset 0x6 and * need to go to 0x18 and read 6 bytes - Jean II */ - bap_read(ai, (u16 *) junk, 0x18, BAP0); + bap_read(ai, (__le16 *) junk, 0x18, BAP0); /* Copy 802.11 dest address. * We use the 802.11 header because the frame may @@ -2289,9 +2219,10 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { return 0; } -static void airo_read_stats(struct airo_info *ai) { +static void airo_read_stats(struct airo_info *ai) +{ StatsRid stats_rid; - u32 *vals = stats_rid.vals; + __le32 *vals = stats_rid.vals; clear_bit(JOB_STATS, &ai->jobs); if (ai->power.event) { @@ -2301,20 +2232,23 @@ static void airo_read_stats(struct airo_info *ai) { readStatsRid(ai, &stats_rid, RID_STATS, 0); up(&ai->sem); - ai->stats.rx_packets = vals[43] + vals[44] + vals[45]; - ai->stats.tx_packets = vals[39] + vals[40] + vals[41]; - ai->stats.rx_bytes = vals[92]; - ai->stats.tx_bytes = vals[91]; - ai->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4]; - ai->stats.tx_errors = vals[42] + ai->stats.tx_fifo_errors; - ai->stats.multicast = vals[43]; - ai->stats.collisions = vals[89]; + ai->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + + le32_to_cpu(vals[45]); + ai->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + + le32_to_cpu(vals[41]); + ai->stats.rx_bytes = le32_to_cpu(vals[92]); + ai->stats.tx_bytes = le32_to_cpu(vals[91]); + ai->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + + le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); + ai->stats.tx_errors = le32_to_cpu(vals[42]) + ai->stats.tx_fifo_errors; + ai->stats.multicast = le32_to_cpu(vals[43]); + ai->stats.collisions = le32_to_cpu(vals[89]); /* detailed rx_errors: */ - ai->stats.rx_length_errors = vals[3]; - ai->stats.rx_crc_errors = vals[4]; - ai->stats.rx_frame_errors = vals[2]; - ai->stats.rx_fifo_errors = vals[0]; + ai->stats.rx_length_errors = le32_to_cpu(vals[3]); + ai->stats.rx_crc_errors = le32_to_cpu(vals[4]); + ai->stats.rx_frame_errors = le32_to_cpu(vals[2]); + ai->stats.rx_fifo_errors = le32_to_cpu(vals[0]); } static struct net_device_stats *airo_get_stats(struct net_device *dev) @@ -2801,8 +2735,9 @@ static int airo_test_wpa_capable(struct airo_info *ai) if (status != SUCCESS) return 0; /* Only firmware versions 5.30.17 or better can do WPA */ - if ((cap_rid.softVer > 0x530) - || ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) { + if (le16_to_cpu(cap_rid.softVer) > 0x530 + || (le16_to_cpu(cap_rid.softVer) == 0x530 + && le16_to_cpu(cap_rid.softSubVer) >= 17)) { airo_print_info("", "WPA is supported."); return 1; } @@ -3037,14 +2972,14 @@ static void airo_process_scan_results (struct airo_info *ai) { /* Try to read the first entry of the scan result */ rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0); - if((rc) || (bss.index == 0xffff)) { + if((rc) || (bss.index == cpu_to_le16(0xffff))) { /* No scan results */ goto out; } /* Read and parse all entries */ tmp_net = NULL; - while((!rc) && (bss.index != 0xffff)) { + while((!rc) && (bss.index != cpu_to_le16(0xffff))) { /* Grab a network off the free list */ if (!list_empty(&ai->network_free_list)) { tmp_net = list_entry(ai->network_free_list.next, @@ -3177,8 +3112,24 @@ static int airo_thread(void *data) { return 0; } -static irqreturn_t airo_interrupt ( int irq, void* dev_id) { - struct net_device *dev = (struct net_device *)dev_id; +static int header_len(__le16 ctl) +{ + u16 fc = le16_to_cpu(ctl); + switch (fc & 0xc) { + case 4: + if ((fc & 0xe0) == 0xc0) + return 10; /* one-address control packet */ + return 16; /* two-address control packet */ + case 8: + if ((fc & 0x300) == 0x300) + return 30; /* WDS packet */ + } + return 24; +} + +static irqreturn_t airo_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; u16 status; u16 fid; struct airo_info *apriv = dev->priv; @@ -3281,19 +3232,20 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { /* Check to see if there is something to receive */ if ( status & EV_RX ) { struct sk_buff *skb = NULL; - u16 fc, len, hdrlen = 0; + __le16 fc, v; + u16 len, hdrlen = 0; #pragma pack(1) struct { - u16 status, len; + __le16 status, len; u8 rssi[2]; u8 rate; u8 freq; - u16 tmp[4]; + __le16 tmp[4]; } hdr; #pragma pack() u16 gap; - u16 tmpbuf[4]; - u16 *buffer; + __le16 tmpbuf[4]; + __le16 *buffer; if (test_bit(FLAG_MPI,&apriv->flags)) { if (test_bit(FLAG_802_11, &apriv->flags)) @@ -3309,7 +3261,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { /* Get the packet length */ if (test_bit(FLAG_802_11, &apriv->flags)) { bap_setup (apriv, fid, 4, BAP0); - bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0); + bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0); /* Bad CRC. Ignore packet */ if (le16_to_cpu(hdr.status) & 2) hdr.len = 0; @@ -3317,7 +3269,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { hdr.len = 0; } else { bap_setup (apriv, fid, 0x36, BAP0); - bap_read (apriv, (u16*)&hdr.len, 2, BAP0); + bap_read (apriv, &hdr.len, 2, BAP0); } len = le16_to_cpu(hdr.len); @@ -3329,23 +3281,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { goto badrx; if (test_bit(FLAG_802_11, &apriv->flags)) { - bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0); - fc = le16_to_cpu(fc); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - hdrlen = 10; - else - hdrlen = 16; - break; - case 8: - if ((fc&0x300)==0x300){ - hdrlen = 30; - break; - } - default: - hdrlen = 24; - } + bap_read (apriv, &fc, sizeof(fc), BAP0); + hdrlen = header_len(fc); } else hdrlen = ETH_ALEN * 2; @@ -3355,15 +3292,15 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { goto badrx; } skb_reserve(skb, 2); /* This way the IP header is aligned */ - buffer = (u16*)skb_put (skb, len + hdrlen); + buffer = (__le16*)skb_put (skb, len + hdrlen); if (test_bit(FLAG_802_11, &apriv->flags)) { buffer[0] = fc; bap_read (apriv, buffer + 1, hdrlen - 2, BAP0); if (hdrlen == 24) bap_read (apriv, tmpbuf, 6, BAP0); - bap_read (apriv, &gap, sizeof(gap), BAP0); - gap = le16_to_cpu(gap); + bap_read (apriv, &v, sizeof(v), BAP0); + gap = le16_to_cpu(v); if (gap) { if (gap <= 8) { bap_read (apriv, tmpbuf, gap, BAP0); @@ -3377,7 +3314,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id) { MICBuffer micbuf; bap_read (apriv, buffer, ETH_ALEN*2, BAP0); if (apriv->micstats.enabled) { - bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0); + bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0); if (ntohs(micbuf.typelen) > 0x05DC) bap_setup (apriv, fid, 0x44, BAP0); else { @@ -3405,7 +3342,7 @@ badrx: if (!test_bit(FLAG_802_11, &apriv->flags)) { sa = (char*)buffer + 6; bap_setup (apriv, fid, 8, BAP0); - bap_read (apriv, (u16*)hdr.rssi, 2, BAP0); + bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0); } else sa = (char*)buffer + 10; wstats.qual = hdr.rssi[0]; @@ -3676,14 +3613,15 @@ void mpi_receive_802_11 (struct airo_info *ai) { RxFid rxd; struct sk_buff *skb = NULL; - u16 fc, len, hdrlen = 0; + u16 len, hdrlen = 0; + __le16 fc; #pragma pack(1) struct { - u16 status, len; + __le16 status, len; u8 rssi[2]; u8 rate; u8 freq; - u16 tmp[4]; + __le16 tmp[4]; } hdr; #pragma pack() u16 gap; @@ -3706,23 +3644,8 @@ void mpi_receive_802_11 (struct airo_info *ai) if (len == 0) goto badrx; - memcpy ((char *)&fc, ptr, sizeof(fc)); - fc = le16_to_cpu(fc); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - hdrlen = 10; - else - hdrlen = 16; - break; - case 8: - if ((fc&0x300)==0x300){ - hdrlen = 30; - break; - } - default: - hdrlen = 24; - } + fc = get_unaligned((__le16 *)ptr); + hdrlen = header_len(fc); skb = dev_alloc_skb( len + hdrlen + 2 ); if ( !skb ) { @@ -3734,9 +3657,8 @@ void mpi_receive_802_11 (struct airo_info *ai) ptr += hdrlen; if (hdrlen == 24) ptr += 6; - memcpy ((char *)&gap, ptr, sizeof(gap)); - ptr += sizeof(gap); - gap = le16_to_cpu(gap); + gap = le16_to_cpu(get_unaligned((__le16 *)ptr)); + ptr += sizeof(__le16); if (gap) { if (gap <= 8) ptr += gap; @@ -3788,7 +3710,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) int status; int i; SsidRid mySsid; - u16 lastindex; + __le16 lastindex; WepKeyRid wkr; int rc; @@ -3850,7 +3772,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) else { kfree(ai->rssi); ai->rssi = NULL; - if (cap_rid.softCap & 8) + if (cap_rid.softCap & cpu_to_le16(8)) ai->config.rmode |= RXMODE_NORMALIZED_RSSI; else airo_print_warn(ai->dev->name, "unknown received signal " @@ -3860,8 +3782,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) ai->config.authType = AUTH_OPEN; ai->config.modulation = MOD_CCK; - if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) && - (micsetup(ai) == SUCCESS)) { + if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) && + (cap_rid.extSoftCap & cpu_to_le16(1)) && + micsetup(ai) == SUCCESS) { ai->config.opmode |= MODE_MIC; set_bit(FLAG_MIC_CAPABLE, &ai->flags); } @@ -3897,13 +3820,13 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) if ( ssids[0] ) { int i; for( i = 0; i < 3 && ssids[i]; i++ ) { - mySsid.ssids[i].len = strlen(ssids[i]); - if ( mySsid.ssids[i].len > 32 ) - mySsid.ssids[i].len = 32; - memcpy(mySsid.ssids[i].ssid, ssids[i], - mySsid.ssids[i].len); + size_t len = strlen(ssids[i]); + if (len > 32) + len = 32; + mySsid.ssids[i].len = cpu_to_le16(len); + memcpy(mySsid.ssids[i].ssid, ssids[i], len); } - mySsid.len = sizeof(mySsid); + mySsid.len = cpu_to_le16(sizeof(mySsid)); } status = writeConfigRid(ai, lock); @@ -3923,7 +3846,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) rc = readWepKeyRid(ai, &wkr, 1, lock); if (rc == SUCCESS) do { lastindex = wkr.kindex; - if (wkr.kindex == 0xffff) { + if (wkr.kindex == cpu_to_le16(0xffff)) { ai->defindex = wkr.mac[0]; } rc = readWepKeyRid(ai, &wkr, 0, lock); @@ -4038,7 +3961,7 @@ static u16 aux_setup(struct airo_info *ai, u16 page, } /* requires call to bap_setup() first */ -static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst, +static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, int whichbap) { u16 len; @@ -4075,7 +3998,7 @@ static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst, /* requires call to bap_setup() first */ -static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, +static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, int whichbap) { bytelen = (bytelen + 1) & (~1); // round up to even value @@ -4087,7 +4010,7 @@ static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, } /* requires call to bap_setup() first */ -static int bap_write(struct airo_info *ai, const u16 *pu16Src, +static int bap_write(struct airo_info *ai, const __le16 *pu16Src, int bytelen, int whichbap) { bytelen = (bytelen + 1) & (~1); // round up to even value @@ -4163,7 +4086,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in // read the rid length field bap_read(ai, pBuf, 2, BAP1); // length for remaining part of rid - len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2; + len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2; if ( len <= 2 ) { airo_print_err(ai->dev->name, @@ -4173,7 +4096,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in goto done; } // read remainder of the rid - rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1); + rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1); } done: if (lock) @@ -4189,7 +4112,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, u16 status; int rc = SUCCESS; - *(u16*)pBuf = cpu_to_le16((u16)len); + *(__le16*)pBuf = cpu_to_le16((u16)len); if (lock) { if (down_interruptible(&ai->sem)) @@ -4263,7 +4186,7 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) Cmd cmd; Resp rsp; u16 txFid; - u16 txControl; + __le16 txControl; cmd.cmd = CMD_ALLOCATETX; cmd.parm0 = lenPayload; @@ -4317,7 +4240,7 @@ done: Make sure the BAP1 spinlock is held when this is called. */ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) { - u16 payloadLen; + __le16 payloadLen; Cmd cmd; Resp rsp; int miclen = 0; @@ -4333,7 +4256,7 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) len -= ETH_ALEN * 2; if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && - (ntohs(((u16 *)pPacket)[6]) != 0x888E)) { + (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) { if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS) return ERROR; miclen = sizeof(pMic); @@ -4345,10 +4268,10 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) * we have to subtract the 12 bytes for the addresses off */ payloadLen = cpu_to_le16(len + miclen); bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); - bap_write(ai, (const u16*)pPacket, sizeof(etherHead), BAP1); + bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1); if (miclen) - bap_write(ai, (const u16*)&pMic, miclen, BAP1); - bap_write(ai, (const u16*)(pPacket + sizeof(etherHead)), len, BAP1); + bap_write(ai, (__le16*)&pMic, miclen, BAP1); + bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1); // issue the transmit command memset( &cmd, 0, sizeof( cmd ) ); cmd.cmd = CMD_TRANSMIT; @@ -4360,35 +4283,17 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) { - u16 fc, payloadLen; + __le16 fc, payloadLen; Cmd cmd; Resp rsp; int hdrlen; - struct { - u8 addr4[ETH_ALEN]; - u16 gaplen; - u8 gap[6]; - } gap; + static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6}; + /* padding of header to full size + le16 gaplen (6) + gaplen bytes */ u16 txFid = len; len >>= 16; - gap.gaplen = 6; - fc = le16_to_cpu(*(const u16*)pPacket); - switch (fc & 0xc) { - case 4: - if ((fc & 0xe0) == 0xc0) - hdrlen = 10; - else - hdrlen = 16; - break; - case 8: - if ((fc&0x300)==0x300){ - hdrlen = 30; - break; - } - default: - hdrlen = 24; - } + fc = *(__le16*)pPacket; + hdrlen = header_len(fc); if (len < hdrlen) { airo_print_warn(ai->dev->name, "Short packet %d", len); @@ -4403,11 +4308,10 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) payloadLen = cpu_to_le16(len-hdrlen); bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1); if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR; - bap_write(ai, (const u16*)pPacket, hdrlen, BAP1); - bap_write(ai, hdrlen == 30 ? - (const u16*)&gap.gaplen : (const u16*)&gap, 38 - hdrlen, BAP1); + bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1); + bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1); - bap_write(ai, (const u16*)(pPacket + hdrlen), len - hdrlen, BAP1); + bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1); // issue the transmit command memset( &cmd, 0, sizeof( cmd ) ); cmd.cmd = CMD_TRANSMIT; @@ -4722,13 +4626,15 @@ static ssize_t proc_write( struct file *file, return len; } -static int proc_status_open( struct inode *inode, struct file *file ) { +static int proc_status_open(struct inode *inode, struct file *file) +{ struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; struct airo_info *apriv = dev->priv; CapabilityRid cap_rid; StatusRid status_rid; + u16 mode; int i; if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) @@ -4742,16 +4648,18 @@ static int proc_status_open( struct inode *inode, struct file *file ) { readStatusRid(apriv, &status_rid, 1); readCapabilityRid(apriv, &cap_rid, 1); + mode = le16_to_cpu(status_rid.mode); + i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", - status_rid.mode & 1 ? "CFG ": "", - status_rid.mode & 2 ? "ACT ": "", - status_rid.mode & 0x10 ? "SYN ": "", - status_rid.mode & 0x20 ? "LNK ": "", - status_rid.mode & 0x40 ? "LEAP ": "", - status_rid.mode & 0x80 ? "PRIV ": "", - status_rid.mode & 0x100 ? "KEY ": "", - status_rid.mode & 0x200 ? "WEP ": "", - status_rid.mode & 0x8000 ? "ERR ": ""); + mode & 1 ? "CFG ": "", + mode & 2 ? "ACT ": "", + mode & 0x10 ? "SYN ": "", + mode & 0x20 ? "LNK ": "", + mode & 0x40 ? "LEAP ": "", + mode & 0x80 ? "PRIV ": "", + mode & 0x100 ? "KEY ": "", + mode & 0x200 ? "WEP ": "", + mode & 0x8000 ? "ERR ": ""); sprintf( data->rbuffer+i, "Mode: %x\n" "Signal Strength: %d\n" "Signal Quality: %d\n" @@ -4764,24 +4672,24 @@ static int proc_status_open( struct inode *inode, struct file *file ) { "Radio type: %x\nCountry: %x\nHardware Version: %x\n" "Software Version: %x\nSoftware Subversion: %x\n" "Boot block version: %x\n", - (int)status_rid.mode, - (int)status_rid.normalizedSignalStrength, - (int)status_rid.signalQuality, - (int)status_rid.SSIDlen, + le16_to_cpu(status_rid.mode), + le16_to_cpu(status_rid.normalizedSignalStrength), + le16_to_cpu(status_rid.signalQuality), + le16_to_cpu(status_rid.SSIDlen), status_rid.SSID, status_rid.apName, - (int)status_rid.channel, - (int)status_rid.currentXmitRate/2, + le16_to_cpu(status_rid.channel), + le16_to_cpu(status_rid.currentXmitRate) / 2, version, cap_rid.prodName, cap_rid.manName, cap_rid.prodVer, - cap_rid.radioType, - cap_rid.country, - cap_rid.hardVer, - (int)cap_rid.softVer, - (int)cap_rid.softSubVer, - (int)cap_rid.bootBlockVer ); + le16_to_cpu(cap_rid.radioType), + le16_to_cpu(cap_rid.country), + le16_to_cpu(cap_rid.hardVer), + le16_to_cpu(cap_rid.softVer), + le16_to_cpu(cap_rid.softSubVer), + le16_to_cpu(cap_rid.bootBlockVer)); data->readlen = strlen( data->rbuffer ); return 0; } @@ -4801,14 +4709,16 @@ static int proc_stats_open( struct inode *inode, struct file *file ) { static int proc_stats_rid_open( struct inode *inode, struct file *file, - u16 rid ) { + u16 rid ) +{ struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; struct airo_info *apriv = dev->priv; StatsRid stats; int i, j; - u32 *vals = stats.vals; + __le32 *vals = stats.vals; + int len = le16_to_cpu(stats.len); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -4821,17 +4731,17 @@ static int proc_stats_rid_open( struct inode *inode, readStatsRid(apriv, &stats, rid, 1); j = 0; - for(i=0; statsLabels[i]!=(char *)-1 && - i*4<stats.len; i++){ + for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) { if (!statsLabels[i]) continue; if (j+strlen(statsLabels[i])+16>4096) { airo_print_warn(apriv->dev->name, "Potentially disasterous buffer overflow averted!"); break; } - j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]); + j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], + le32_to_cpu(vals[i])); } - if (i*4>=stats.len){ + if (i*4 >= len) { airo_print_warn(apriv->dev->name, "Got a short rid"); } data->readlen = j; @@ -4856,7 +4766,14 @@ static int airo_config_commit(struct net_device *dev, struct iw_request_info *info, void *zwrq, char *extra); -static void proc_config_on_close( struct inode *inode, struct file *file ) { +static inline int sniffing_mode(struct airo_info *ai) +{ + return le16_to_cpu(ai->config.rmode & RXMODE_MASK) >= + le16_to_cpu(RXMODE_RFMON); +} + +static void proc_config_on_close(struct inode *inode, struct file *file) +{ struct proc_data *data = file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; @@ -4873,16 +4790,16 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { /*** Mode processing */ if ( !strncmp( line, "Mode: ", 6 ) ) { line += 6; - if ((ai->config.rmode & 0xff) >= RXMODE_RFMON) - set_bit (FLAG_RESET, &ai->flags); - ai->config.rmode &= 0xfe00; + if (sniffing_mode(ai)) + set_bit (FLAG_RESET, &ai->flags); + ai->config.rmode &= ~RXMODE_FULL_MASK; clear_bit (FLAG_802_11, &ai->flags); - ai->config.opmode &= 0xFF00; + ai->config.opmode &= ~MODE_CFG_MASK; ai->config.scanMode = SCANMODE_ACTIVE; if ( line[0] == 'a' ) { - ai->config.opmode |= 0; + ai->config.opmode |= MODE_STA_IBSS; } else { - ai->config.opmode |= 1; + ai->config.opmode |= MODE_STA_ESS; if ( line[0] == 'r' ) { ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; ai->config.scanMode = SCANMODE_PASSIVE; @@ -4948,7 +4865,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 9; v = get_dec_u16(line, &i, i+3); if ( v != -1 ) { - ai->config.channelSet = (u16)v; + ai->config.channelSet = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } } else if ( !strncmp( line, "XmitPower: ", 11 ) ) { @@ -4956,20 +4873,20 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 11; v = get_dec_u16(line, &i, i+3); if ( v != -1 ) { - ai->config.txPower = (u16)v; + ai->config.txPower = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } } else if ( !strncmp( line, "WEP: ", 5 ) ) { line += 5; switch( line[0] ) { case 's': - ai->config.authType = (u16)AUTH_SHAREDKEY; + ai->config.authType = AUTH_SHAREDKEY; break; case 'e': - ai->config.authType = (u16)AUTH_ENCRYPT; + ai->config.authType = AUTH_ENCRYPT; break; default: - ai->config.authType = (u16)AUTH_OPEN; + ai->config.authType = AUTH_OPEN; break; } set_bit (FLAG_COMMIT, &ai->flags); @@ -4979,7 +4896,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 16; v = get_dec_u16(line, &i, 3); v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.longRetryLimit = (u16)v; + ai->config.longRetryLimit = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) { int v, i = 0; @@ -4987,7 +4904,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 17; v = get_dec_u16(line, &i, 3); v = (v<0) ? 0 : ((v>255) ? 255 : v); - ai->config.shortRetryLimit = (u16)v; + ai->config.shortRetryLimit = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) { int v, i = 0; @@ -4995,7 +4912,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 14; v = get_dec_u16(line, &i, 4); v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); - ai->config.rtsThres = (u16)v; + ai->config.rtsThres = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) { int v, i = 0; @@ -5003,7 +4920,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 16; v = get_dec_u16(line, &i, 5); v = (v<0) ? 0 : v; - ai->config.txLifetime = (u16)v; + ai->config.txLifetime = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) { int v, i = 0; @@ -5011,7 +4928,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 16; v = get_dec_u16(line, &i, 5); v = (v<0) ? 0 : v; - ai->config.rxLifetime = (u16)v; + ai->config.rxLifetime = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "TXDiversity: ", 13 ) ) { ai->config.txDiversity = @@ -5030,7 +4947,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { v = get_dec_u16(line, &i, 4); v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); v = v & 0xfffe; /* Make sure its even */ - ai->config.fragThresh = (u16)v; + ai->config.fragThresh = cpu_to_le16(v); set_bit (FLAG_COMMIT, &ai->flags); } else if (!strncmp(line, "Modulation: ", 12)) { line += 12; @@ -5057,8 +4974,9 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { airo_config_commit(dev, NULL, NULL, NULL); } -static char *get_rmode(u16 mode) { - switch(mode&0xff) { +static char *get_rmode(__le16 mode) +{ + switch(mode & RXMODE_MASK) { case RXMODE_RFMON: return "rfmon"; case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon"; case RXMODE_LANMON: return "lanmon"; @@ -5066,12 +4984,14 @@ static char *get_rmode(u16 mode) { return "ESS"; } -static int proc_config_open( struct inode *inode, struct file *file ) { +static int proc_config_open(struct inode *inode, struct file *file) +{ struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; struct airo_info *ai = dev->priv; int i; + __le16 mode; if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5090,6 +5010,7 @@ static int proc_config_open( struct inode *inode, struct file *file ) { readConfigRid(ai, 1); + mode = ai->config.opmode & MODE_CFG_MASK; i = sprintf( data->rbuffer, "Mode: %s\n" "Radio: %s\n" @@ -5098,15 +5019,16 @@ static int proc_config_open( struct inode *inode, struct file *file ) { "DataRates: %d %d %d %d %d %d %d %d\n" "Channel: %d\n" "XmitPower: %d\n", - (ai->config.opmode & 0xFF) == 0 ? "adhoc" : - (ai->config.opmode & 0xFF) == 1 ? get_rmode(ai->config.rmode): - (ai->config.opmode & 0xFF) == 2 ? "AP" : - (ai->config.opmode & 0xFF) == 3 ? "AP RPTR" : "Error", + mode == MODE_STA_IBSS ? "adhoc" : + mode == MODE_STA_ESS ? get_rmode(ai->config.rmode): + mode == MODE_AP ? "AP" : + mode == MODE_AP_RPTR ? "AP RPTR" : "Error", test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on", ai->config.nodeName, - ai->config.powerSaveMode == 0 ? "CAM" : - ai->config.powerSaveMode == 1 ? "PSP" : - ai->config.powerSaveMode == 2 ? "PSPCAM" : "Error", + ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" : + ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" : + ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" : + "Error", (int)ai->config.rates[0], (int)ai->config.rates[1], (int)ai->config.rates[2], @@ -5115,8 +5037,8 @@ static int proc_config_open( struct inode *inode, struct file *file ) { (int)ai->config.rates[5], (int)ai->config.rates[6], (int)ai->config.rates[7], - (int)ai->config.channelSet, - (int)ai->config.txPower + le16_to_cpu(ai->config.channelSet), + le16_to_cpu(ai->config.txPower) ); sprintf( data->rbuffer + i, "LongRetryLimit: %d\n" @@ -5130,19 +5052,19 @@ static int proc_config_open( struct inode *inode, struct file *file ) { "WEP: %s\n" "Modulation: %s\n" "Preamble: %s\n", - (int)ai->config.longRetryLimit, - (int)ai->config.shortRetryLimit, - (int)ai->config.rtsThres, - (int)ai->config.txLifetime, - (int)ai->config.rxLifetime, + le16_to_cpu(ai->config.longRetryLimit), + le16_to_cpu(ai->config.shortRetryLimit), + le16_to_cpu(ai->config.rtsThres), + le16_to_cpu(ai->config.txLifetime), + le16_to_cpu(ai->config.rxLifetime), ai->config.txDiversity == 1 ? "left" : ai->config.txDiversity == 2 ? "right" : "both", ai->config.rxDiversity == 1 ? "left" : ai->config.rxDiversity == 2 ? "right" : "both", - (int)ai->config.fragThresh, + le16_to_cpu(ai->config.fragThresh), ai->config.authType == AUTH_ENCRYPT ? "encrypt" : ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open", - ai->config.modulation == 0 ? "default" : + ai->config.modulation == MOD_DEFAULT ? "default" : ai->config.modulation == MOD_CCK ? "cck" : ai->config.modulation == MOD_MOK ? "mok" : "error", ai->config.preamble == PREAMBLE_AUTO ? "auto" : @@ -5153,34 +5075,38 @@ static int proc_config_open( struct inode *inode, struct file *file ) { return 0; } -static void proc_SSID_on_close( struct inode *inode, struct file *file ) { +static void proc_SSID_on_close(struct inode *inode, struct file *file) +{ struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; struct airo_info *ai = dev->priv; SsidRid SSID_rid; int i; - int offset = 0; + char *p = data->wbuffer; + char *end = p + data->writelen; - if ( !data->writelen ) return; + if (!data->writelen) + return; - memset( &SSID_rid, 0, sizeof( SSID_rid ) ); + *end = '\n'; /* sentinel; we have space for it */ - for( i = 0; i < 3; i++ ) { - int j; - for( j = 0; j+offset < data->writelen && j < 32 && - data->wbuffer[offset+j] != '\n'; j++ ) { - SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j]; - } - if ( j == 0 ) break; - SSID_rid.ssids[i].len = j; - offset += j; - while( data->wbuffer[offset] != '\n' && - offset < data->writelen ) offset++; - offset++; + memset(&SSID_rid, 0, sizeof(SSID_rid)); + + for (i = 0; i < 3 && p < end; i++) { + int j = 0; + /* copy up to 32 characters from this line */ + while (*p != '\n' && j < 32) + SSID_rid.ssids[i].ssid[j++] = *p++; + if (j == 0) + break; + SSID_rid.ssids[i].len = cpu_to_le16(j); + /* skip to the beginning of the next line */ + while (*p++ != '\n') + ; } if (i) - SSID_rid.len = sizeof(SSID_rid); + SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); disable_MAC(ai, 1); writeSsidRid(ai, &SSID_rid, 1); enable_MAC(ai, 1); @@ -5204,7 +5130,7 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) { if ( !data->writelen ) return; memset( &APList_rid, 0, sizeof(APList_rid) ); - APList_rid.len = sizeof(APList_rid); + APList_rid.len = cpu_to_le16(sizeof(APList_rid)); for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) { int j; @@ -5244,39 +5170,40 @@ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data, static int get_wep_key(struct airo_info *ai, u16 index) { WepKeyRid wkr; int rc; - u16 lastindex; + __le16 lastindex; rc = readWepKeyRid(ai, &wkr, 1, 1); if (rc == SUCCESS) do { lastindex = wkr.kindex; - if (wkr.kindex == index) { + if (wkr.kindex == cpu_to_le16(index)) { if (index == 0xffff) { return wkr.mac[0]; } - return wkr.klen; + return le16_to_cpu(wkr.klen); } readWepKeyRid(ai, &wkr, 0, 1); - } while(lastindex != wkr.kindex); + } while (lastindex != wkr.kindex); return -1; } static int set_wep_key(struct airo_info *ai, u16 index, - const char *key, u16 keylen, int perm, int lock ) { + const char *key, u16 keylen, int perm, int lock ) +{ static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; WepKeyRid wkr; memset(&wkr, 0, sizeof(wkr)); if (keylen == 0) { // We are selecting which key to use - wkr.len = sizeof(wkr); - wkr.kindex = 0xffff; + wkr.len = cpu_to_le16(sizeof(wkr)); + wkr.kindex = cpu_to_le16(0xffff); wkr.mac[0] = (char)index; if (perm) ai->defindex = (char)index; } else { // We are actually setting the key - wkr.len = sizeof(wkr); - wkr.kindex = index; - wkr.klen = keylen; + wkr.len = cpu_to_le16(sizeof(wkr)); + wkr.kindex = cpu_to_le16(index); + wkr.klen = cpu_to_le16(keylen); memcpy( wkr.key, key, keylen ); memcpy( wkr.mac, macaddr, ETH_ALEN ); } @@ -5328,14 +5255,15 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { set_wep_key(ai, index, key, i/3, 1, 1); } -static int proc_wepkey_open( struct inode *inode, struct file *file ) { +static int proc_wepkey_open( struct inode *inode, struct file *file ) +{ struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; struct airo_info *ai = dev->priv; char *ptr; WepKeyRid wkr; - u16 lastindex; + __le16 lastindex; int j=0; int rc; @@ -5361,12 +5289,13 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) { rc = readWepKeyRid(ai, &wkr, 1, 1); if (rc == SUCCESS) do { lastindex = wkr.kindex; - if (wkr.kindex == 0xffff) { + if (wkr.kindex == cpu_to_le16(0xffff)) { j += sprintf(ptr+j, "Tx key = %d\n", (int)wkr.mac[0]); } else { j += sprintf(ptr+j, "Key %d set with length = %d\n", - (int)wkr.kindex, (int)wkr.klen); + le16_to_cpu(wkr.kindex), + le16_to_cpu(wkr.klen)); } readWepKeyRid(ai, &wkr, 0, 1); } while((lastindex != wkr.kindex) && (j < 180-30)); @@ -5375,7 +5304,8 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) { return 0; } -static int proc_SSID_open( struct inode *inode, struct file *file ) { +static int proc_SSID_open(struct inode *inode, struct file *file) +{ struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; @@ -5393,7 +5323,8 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) { } data->writelen = 0; data->maxwritelen = 33*3; - if ((data->wbuffer = kzalloc( 33*3, GFP_KERNEL )) == NULL) { + /* allocate maxwritelen + 1; we'll want a sentinel */ + if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) { kfree (data->rbuffer); kfree (file->private_data); return -ENOMEM; @@ -5402,14 +5333,15 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) { readSsidRid(ai, &SSID_rid); ptr = data->rbuffer; - for( i = 0; i < 3; i++ ) { + for (i = 0; i < 3; i++) { int j; - if ( !SSID_rid.ssids[i].len ) break; - for( j = 0; j < 32 && - j < SSID_rid.ssids[i].len && - SSID_rid.ssids[i].ssid[j]; j++ ) { + size_t len = le16_to_cpu(SSID_rid.ssids[i].len); + if (!len) + break; + if (len > 32) + len = 32; + for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++) *ptr++ = SSID_rid.ssids[i].ssid[j]; - } *ptr++ = '\n'; } *ptr = '\0'; @@ -5505,14 +5437,14 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { Since it is a rare condition, we'll just live with it, otherwise we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); - while(rc == 0 && BSSList_rid.index != 0xffff) { + while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { ptr += sprintf(ptr, "%s %*s rssi = %d", print_mac(mac, BSSList_rid.bssid), (int)BSSList_rid.ssidLen, BSSList_rid.ssid, - (int)BSSList_rid.dBm); + le16_to_cpu(BSSList_rid.dBm)); ptr += sprintf(ptr, " channel = %d %s %s %s %s\n", - (int)BSSList_rid.dsChannel, + le16_to_cpu(BSSList_rid.dsChannel), BSSList_rid.cap & CAP_ESS ? "ESS" : "", BSSList_rid.cap & CAP_IBSS ? "adhoc" : "", BSSList_rid.cap & CAP_PRIVACY ? "wep" : "", @@ -5780,21 +5712,27 @@ static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm) static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid) { int quality = 0; + u16 sq; - if ((status_rid->mode & 0x3f) == 0x3f && (cap_rid->hardCap & 8)) { - if (memcmp(cap_rid->prodName, "350", 3)) - if (status_rid->signalQuality > 0x20) - quality = 0; - else - quality = 0x20 - status_rid->signalQuality; + if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f)) + return 0; + + if (!(cap_rid->hardCap & cpu_to_le16(8))) + return 0; + + sq = le16_to_cpu(status_rid->signalQuality); + if (memcmp(cap_rid->prodName, "350", 3)) + if (sq > 0x20) + quality = 0; else - if (status_rid->signalQuality > 0xb0) - quality = 0; - else if (status_rid->signalQuality < 0x10) - quality = 0xa0; - else - quality = 0xb0 - status_rid->signalQuality; - } + quality = 0x20 - sq; + else + if (sq > 0xb0) + quality = 0; + else if (sq < 0x10) + quality = 0xa0; + else + quality = 0xb0 - sq; return quality; } @@ -5852,7 +5790,7 @@ static int airo_set_freq(struct net_device *dev, } else { readConfigRid(local, 1); /* Yes ! We can set it !!! */ - local->config.channelSet = (u16) channel; + local->config.channelSet = cpu_to_le16(channel); set_bit (FLAG_COMMIT, &local->flags); } } @@ -5873,12 +5811,12 @@ static int airo_get_freq(struct net_device *dev, int ch; readConfigRid(local, 1); - if ((local->config.opmode & 0xFF) == MODE_STA_ESS) + if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS) status_rid.channel = local->config.channelSet; else readStatusRid(local, &status_rid, 1); - ch = (int)status_rid.channel; + ch = le16_to_cpu(status_rid.channel); if((ch > 0) && (ch < 15)) { fwrq->m = frequency_list[ch - 1] * 100000; fwrq->e = 1; @@ -5925,9 +5863,9 @@ static int airo_set_essid(struct net_device *dev, memset(SSID_rid.ssids[index].ssid, 0, sizeof(SSID_rid.ssids[index].ssid)); memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length); - SSID_rid.ssids[index].len = dwrq->length; + SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length); } - SSID_rid.len = sizeof(SSID_rid); + SSID_rid.len = cpu_to_le16(sizeof(SSID_rid)); /* Write it to the card */ disable_MAC(local, 1); writeSsidRid(local, &SSID_rid, 1); @@ -5954,11 +5892,11 @@ static int airo_get_essid(struct net_device *dev, * get the relevant SSID from the SSID list... */ /* Get the current SSID */ - memcpy(extra, status_rid.SSID, status_rid.SSIDlen); + memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen)); /* If none, we may want to get the one that was set */ /* Push it out ! */ - dwrq->length = status_rid.SSIDlen; + dwrq->length = le16_to_cpu(status_rid.SSIDlen); dwrq->flags = 1; /* active */ return 0; @@ -5992,7 +5930,7 @@ static int airo_set_wap(struct net_device *dev, up(&local->sem); } else { memset(&APList_rid, 0, sizeof(APList_rid)); - APList_rid.len = sizeof(APList_rid); + APList_rid.len = cpu_to_le16(sizeof(APList_rid)); memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN); disable_MAC(local, 1); writeAPListRid(local, &APList_rid, 1); @@ -6148,7 +6086,7 @@ static int airo_get_rate(struct net_device *dev, readStatusRid(local, &status_rid, 1); - vwrq->value = status_rid.currentXmitRate * 500000; + vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000; /* If more than one rate, set auto */ readConfigRid(local, 1); vwrq->fixed = (local->config.rates[1] == 0); @@ -6174,7 +6112,7 @@ static int airo_set_rts(struct net_device *dev, return -EINVAL; } readConfigRid(local, 1); - local->config.rtsThres = rthr; + local->config.rtsThres = cpu_to_le16(rthr); set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ @@ -6192,7 +6130,7 @@ static int airo_get_rts(struct net_device *dev, struct airo_info *local = dev->priv; readConfigRid(local, 1); - vwrq->value = local->config.rtsThres; + vwrq->value = le16_to_cpu(local->config.rtsThres); vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); vwrq->fixed = 1; @@ -6218,7 +6156,7 @@ static int airo_set_frag(struct net_device *dev, } fthr &= ~0x1; /* Get an even value - is it really needed ??? */ readConfigRid(local, 1); - local->config.fragThresh = (u16)fthr; + local->config.fragThresh = cpu_to_le16(fthr); set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ @@ -6236,7 +6174,7 @@ static int airo_get_frag(struct net_device *dev, struct airo_info *local = dev->priv; readConfigRid(local, 1); - vwrq->value = local->config.fragThresh; + vwrq->value = le16_to_cpu(local->config.fragThresh); vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); vwrq->fixed = 1; @@ -6256,42 +6194,42 @@ static int airo_set_mode(struct net_device *dev, int reset = 0; readConfigRid(local, 1); - if ((local->config.rmode & 0xff) >= RXMODE_RFMON) + if (sniffing_mode(local)) reset = 1; switch(*uwrq) { case IW_MODE_ADHOC: - local->config.opmode &= 0xFF00; + local->config.opmode &= ~MODE_CFG_MASK; local->config.opmode |= MODE_STA_IBSS; - local->config.rmode &= 0xfe00; + local->config.rmode &= ~RXMODE_FULL_MASK; local->config.scanMode = SCANMODE_ACTIVE; clear_bit (FLAG_802_11, &local->flags); break; case IW_MODE_INFRA: - local->config.opmode &= 0xFF00; + local->config.opmode &= ~MODE_CFG_MASK; local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= 0xfe00; + local->config.rmode &= ~RXMODE_FULL_MASK; local->config.scanMode = SCANMODE_ACTIVE; clear_bit (FLAG_802_11, &local->flags); break; case IW_MODE_MASTER: - local->config.opmode &= 0xFF00; + local->config.opmode &= ~MODE_CFG_MASK; local->config.opmode |= MODE_AP; - local->config.rmode &= 0xfe00; + local->config.rmode &= ~RXMODE_FULL_MASK; local->config.scanMode = SCANMODE_ACTIVE; clear_bit (FLAG_802_11, &local->flags); break; case IW_MODE_REPEAT: - local->config.opmode &= 0xFF00; + local->config.opmode &= ~MODE_CFG_MASK; local->config.opmode |= MODE_AP_RPTR; - local->config.rmode &= 0xfe00; + local->config.rmode &= ~RXMODE_FULL_MASK; local->config.scanMode = SCANMODE_ACTIVE; clear_bit (FLAG_802_11, &local->flags); break; case IW_MODE_MONITOR: - local->config.opmode &= 0xFF00; + local->config.opmode &= ~MODE_CFG_MASK; local->config.opmode |= MODE_STA_ESS; - local->config.rmode &= 0xfe00; + local->config.rmode &= ~RXMODE_FULL_MASK; local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; local->config.scanMode = SCANMODE_PASSIVE; set_bit (FLAG_802_11, &local->flags); @@ -6319,7 +6257,7 @@ static int airo_get_mode(struct net_device *dev, readConfigRid(local, 1); /* If not managed, assume it's ad-hoc */ - switch (local->config.opmode & 0xFF) { + switch (local->config.opmode & MODE_CFG_MASK) { case MODE_STA_ESS: *uwrq = IW_MODE_INFRA; break; @@ -6336,6 +6274,13 @@ static int airo_get_mode(struct net_device *dev, return 0; } +static inline int valid_index(CapabilityRid *p, int index) +{ + if (index < 0) + return 0; + return index < (p->softCap & cpu_to_le16(0x80) ? 4 : 1); +} + /*------------------------------------------------------------------*/ /* * Wireless Handler : set Encryption Key @@ -6348,12 +6293,12 @@ static int airo_set_encode(struct net_device *dev, struct airo_info *local = dev->priv; CapabilityRid cap_rid; /* Card capability info */ int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 ); - u16 currentAuthType = local->config.authType; + __le16 currentAuthType = local->config.authType; /* Is WEP supported ? */ readCapabilityRid(local, &cap_rid, 1); /* Older firmware doesn't support this... - if(!(cap_rid.softCap & 2)) { + if(!(cap_rid.softCap & cpu_to_le16(2))) { return -EOPNOTSUPP; } */ readConfigRid(local, 1); @@ -6373,7 +6318,7 @@ static int airo_set_encode(struct net_device *dev, return -EINVAL; } /* Check the index (none -> use current) */ - if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4:1))) + if (!valid_index(&cap_rid, index)) index = current_index; /* Set the length */ if (dwrq->length > MIN_KEY_SIZE) @@ -6403,13 +6348,12 @@ static int airo_set_encode(struct net_device *dev, } else { /* Do we want to just set the transmit key index ? */ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; - if ((index >= 0) && (index < ((cap_rid.softCap & 0x80)?4:1))) { + if (valid_index(&cap_rid, index)) { set_wep_key(local, index, NULL, 0, perm, 1); } else /* Don't complain if only change the mode */ - if(!dwrq->flags & IW_ENCODE_MODE) { + if (!(dwrq->flags & IW_ENCODE_MODE)) return -EINVAL; - } } /* Read the flags */ if(dwrq->flags & IW_ENCODE_DISABLED) @@ -6439,7 +6383,7 @@ static int airo_get_encode(struct net_device *dev, /* Is it supported ? */ readCapabilityRid(local, &cap_rid, 1); - if(!(cap_rid.softCap & 2)) { + if(!(cap_rid.softCap & cpu_to_le16(2))) { return -EOPNOTSUPP; } readConfigRid(local, 1); @@ -6461,7 +6405,7 @@ static int airo_get_encode(struct net_device *dev, memset(extra, 0, 16); /* Which key do we want ? -1 -> tx index */ - if ((index < 0) || (index >= ((cap_rid.softCap & 0x80) ? 4 : 1))) + if (!valid_index(&cap_rid, index)) index = get_wep_key(local, 0xffff); dwrq->flags |= index + 1; /* Copy the key to the user buffer */ @@ -6486,14 +6430,14 @@ static int airo_set_encodeext(struct net_device *dev, struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 ); - u16 currentAuthType = local->config.authType; + __le16 currentAuthType = local->config.authType; int idx, key_len, alg = ext->alg, set_key = 1; wep_key_t key; /* Is WEP supported ? */ readCapabilityRid(local, &cap_rid, 1); /* Older firmware doesn't support this... - if(!(cap_rid.softCap & 2)) { + if(!(cap_rid.softCap & cpu_to_le16(2))) { return -EOPNOTSUPP; } */ readConfigRid(local, 1); @@ -6501,7 +6445,7 @@ static int airo_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1)) + if (!valid_index(&cap_rid, idx - 1)) return -EINVAL; idx--; } else @@ -6575,7 +6519,7 @@ static int airo_get_encodeext(struct net_device *dev, /* Is it supported ? */ readCapabilityRid(local, &cap_rid, 1); - if(!(cap_rid.softCap & 2)) { + if(!(cap_rid.softCap & cpu_to_le16(2))) { return -EOPNOTSUPP; } readConfigRid(local, 1); @@ -6586,7 +6530,7 @@ static int airo_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1)) + if (!valid_index(&cap_rid, idx - 1)) return -EINVAL; idx--; } else @@ -6632,7 +6576,7 @@ static int airo_set_auth(struct net_device *dev, { struct airo_info *local = dev->priv; struct iw_param *param = &wrqu->param; - u16 currentAuthType = local->config.authType; + __le16 currentAuthType = local->config.authType; switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: @@ -6700,7 +6644,7 @@ static int airo_get_auth(struct net_device *dev, { struct airo_info *local = dev->priv; struct iw_param *param = &wrqu->param; - u16 currentAuthType = local->config.authType; + __le16 currentAuthType = local->config.authType; switch (param->flags & IW_AUTH_INDEX) { case IW_AUTH_DROP_UNENCRYPTED: @@ -6751,6 +6695,7 @@ static int airo_set_txpow(struct net_device *dev, CapabilityRid cap_rid; /* Card capability info */ int i; int rc = -EINVAL; + __le16 v = cpu_to_le16(vwrq->value); readCapabilityRid(local, &cap_rid, 1); @@ -6764,9 +6709,9 @@ static int airo_set_txpow(struct net_device *dev, } clear_bit (FLAG_RADIO_OFF, &local->flags); for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++) - if ((vwrq->value==cap_rid.txPowerLevels[i])) { + if (v == cap_rid.txPowerLevels[i]) { readConfigRid(local, 1); - local->config.txPower = vwrq->value; + local->config.txPower = v; set_bit (FLAG_COMMIT, &local->flags); rc = -EINPROGRESS; /* Call commit handler */ break; @@ -6786,7 +6731,7 @@ static int airo_get_txpow(struct net_device *dev, struct airo_info *local = dev->priv; readConfigRid(local, 1); - vwrq->value = local->config.txPower; + vwrq->value = le16_to_cpu(local->config.txPower); vwrq->fixed = 1; /* No power control */ vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags); vwrq->flags = IW_TXPOW_MWATT; @@ -6811,20 +6756,21 @@ static int airo_set_retry(struct net_device *dev, } readConfigRid(local, 1); if(vwrq->flags & IW_RETRY_LIMIT) { + __le16 v = cpu_to_le16(vwrq->value); if(vwrq->flags & IW_RETRY_LONG) - local->config.longRetryLimit = vwrq->value; + local->config.longRetryLimit = v; else if (vwrq->flags & IW_RETRY_SHORT) - local->config.shortRetryLimit = vwrq->value; + local->config.shortRetryLimit = v; else { /* No modifier : set both */ - local->config.longRetryLimit = vwrq->value; - local->config.shortRetryLimit = vwrq->value; + local->config.longRetryLimit = v; + local->config.shortRetryLimit = v; } set_bit (FLAG_COMMIT, &local->flags); rc = -EINPROGRESS; /* Call commit handler */ } if(vwrq->flags & IW_RETRY_LIFETIME) { - local->config.txLifetime = vwrq->value / 1024; + local->config.txLifetime = cpu_to_le16(vwrq->value / 1024); set_bit (FLAG_COMMIT, &local->flags); rc = -EINPROGRESS; /* Call commit handler */ } @@ -6848,14 +6794,14 @@ static int airo_get_retry(struct net_device *dev, /* Note : by default, display the min retry number */ if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { vwrq->flags = IW_RETRY_LIFETIME; - vwrq->value = (int)local->config.txLifetime * 1024; + vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024; } else if((vwrq->flags & IW_RETRY_LONG)) { vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - vwrq->value = (int)local->config.longRetryLimit; + vwrq->value = le16_to_cpu(local->config.longRetryLimit); } else { vwrq->flags = IW_RETRY_LIMIT; - vwrq->value = (int)local->config.shortRetryLimit; - if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit) + vwrq->value = le16_to_cpu(local->config.shortRetryLimit); + if(local->config.shortRetryLimit != local->config.longRetryLimit) vwrq->flags |= IW_RETRY_SHORT; } @@ -6936,16 +6882,17 @@ static int airo_get_range(struct net_device *dev, range->min_frag = 256; range->max_frag = AIRO_DEF_MTU; - if(cap_rid.softCap & 2) { + if(cap_rid.softCap & cpu_to_le16(2)) { // WEP: RC4 40 bits range->encoding_size[0] = 5; // RC4 ~128 bits - if (cap_rid.softCap & 0x100) { + if (cap_rid.softCap & cpu_to_le16(0x100)) { range->encoding_size[1] = 13; range->num_encoding_sizes = 2; } else range->num_encoding_sizes = 1; - range->max_encoding_tokens = (cap_rid.softCap & 0x80) ? 4 : 1; + range->max_encoding_tokens = + cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1; } else { range->num_encoding_sizes = 0; range->max_encoding_tokens = 0; @@ -6960,7 +6907,7 @@ static int airo_get_range(struct net_device *dev, /* Transmit Power - values are in mW */ for(i = 0 ; i < 8 ; i++) { - range->txpower[i] = cap_rid.txPowerLevels[i]; + range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]); if(range->txpower[i] == 0) break; } @@ -6999,38 +6946,37 @@ static int airo_set_power(struct net_device *dev, readConfigRid(local, 1); if (vwrq->disabled) { - if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { + if (sniffing_mode(local)) return -EINVAL; - } local->config.powerSaveMode = POWERSAVE_CAM; - local->config.rmode &= 0xFF00; + local->config.rmode &= ~RXMODE_MASK; local->config.rmode |= RXMODE_BC_MC_ADDR; set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ } if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - local->config.fastListenDelay = (vwrq->value + 500) / 1024; + local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024); local->config.powerSaveMode = POWERSAVE_PSPCAM; set_bit (FLAG_COMMIT, &local->flags); } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { - local->config.fastListenInterval = local->config.listenInterval = (vwrq->value + 500) / 1024; + local->config.fastListenInterval = + local->config.listenInterval = + cpu_to_le16((vwrq->value + 500) / 1024); local->config.powerSaveMode = POWERSAVE_PSPCAM; set_bit (FLAG_COMMIT, &local->flags); } switch (vwrq->flags & IW_POWER_MODE) { case IW_POWER_UNICAST_R: - if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { + if (sniffing_mode(local)) return -EINVAL; - } - local->config.rmode &= 0xFF00; + local->config.rmode &= ~RXMODE_MASK; local->config.rmode |= RXMODE_ADDR; set_bit (FLAG_COMMIT, &local->flags); break; case IW_POWER_ALL_R: - if ((local->config.rmode & 0xFF) >= RXMODE_RFMON) { + if (sniffing_mode(local)) return -EINVAL; - } - local->config.rmode &= 0xFF00; + local->config.rmode &= ~RXMODE_MASK; local->config.rmode |= RXMODE_BC_MC_ADDR; set_bit (FLAG_COMMIT, &local->flags); case IW_POWER_ON: @@ -7054,20 +7000,20 @@ static int airo_get_power(struct net_device *dev, char *extra) { struct airo_info *local = dev->priv; - int mode; + __le16 mode; readConfigRid(local, 1); mode = local->config.powerSaveMode; if ((vwrq->disabled = (mode == POWERSAVE_CAM))) return 0; if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - vwrq->value = (int)local->config.fastListenDelay * 1024; + vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024; vwrq->flags = IW_POWER_TIMEOUT; } else { - vwrq->value = (int)local->config.fastListenInterval * 1024; + vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024; vwrq->flags = IW_POWER_PERIOD; } - if ((local->config.rmode & 0xFF) == RXMODE_ADDR) + if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR) vwrq->flags |= IW_POWER_UNICAST_R; else vwrq->flags |= IW_POWER_ALL_R; @@ -7087,7 +7033,8 @@ static int airo_set_sens(struct net_device *dev, struct airo_info *local = dev->priv; readConfigRid(local, 1); - local->config.rssiThreshold = vwrq->disabled ? RSSI_DEFAULT : vwrq->value; + local->config.rssiThreshold = + cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value); set_bit (FLAG_COMMIT, &local->flags); return -EINPROGRESS; /* Call commit handler */ @@ -7105,7 +7052,7 @@ static int airo_get_sens(struct net_device *dev, struct airo_info *local = dev->priv; readConfigRid(local, 1); - vwrq->value = local->config.rssiThreshold; + vwrq->value = le16_to_cpu(local->config.rssiThreshold); vwrq->disabled = (vwrq->value == 0); vwrq->fixed = 1; @@ -7130,26 +7077,28 @@ static int airo_get_aplist(struct net_device *dev, int loseSync = capable(CAP_NET_ADMIN) ? 1: -1; for (i = 0; i < IW_MAX_AP; i++) { + u16 dBm; if (readBSSListRid(local, loseSync, &BSSList)) break; loseSync = 0; memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN); address[i].sa_family = ARPHRD_ETHER; + dBm = le16_to_cpu(BSSList.dBm); if (local->rssi) { - qual[i].level = 0x100 - BSSList.dBm; - qual[i].qual = airo_dbm_to_pct( local->rssi, BSSList.dBm ); + qual[i].level = 0x100 - dBm; + qual[i].qual = airo_dbm_to_pct(local->rssi, dBm); qual[i].updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_DBM; } else { - qual[i].level = (BSSList.dBm + 321) / 2; + qual[i].level = (dBm + 321) / 2; qual[i].qual = 0; qual[i].updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED | IW_QUAL_DBM; } qual[i].noise = local->wstats.qual.noise; - if (BSSList.index == 0xffff) + if (BSSList.index == cpu_to_le16(0xffff)) break; } if (!i) { @@ -7240,10 +7189,11 @@ static inline char *airo_translate_scan(struct net_device *dev, { struct airo_info *ai = dev->priv; struct iw_event iwe; /* Temporary buffer */ - u16 capabilities; + __le16 capabilities; char * current_val; /* For rates */ int i; char * buf; + u16 dBm; /* First entry *MUST* be the AP MAC address */ iwe.cmd = SIOCGIWAP; @@ -7263,7 +7213,7 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Add mode */ iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(bss->cap); + capabilities = bss->cap; if(capabilities & (CAP_ESS | CAP_IBSS)) { if(capabilities & CAP_ESS) iwe.u.mode = IW_MODE_MASTER; @@ -7282,16 +7232,18 @@ static inline char *airo_translate_scan(struct net_device *dev, iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + dBm = le16_to_cpu(bss->dBm); + /* Add quality statistics */ iwe.cmd = IWEVQUAL; if (ai->rssi) { - iwe.u.qual.level = 0x100 - bss->dBm; - iwe.u.qual.qual = airo_dbm_to_pct( ai->rssi, bss->dBm ); + iwe.u.qual.level = 0x100 - dBm; + iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm); iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_DBM; } else { - iwe.u.qual.level = (bss->dBm + 321) / 2; + iwe.u.qual.level = (dBm + 321) / 2; iwe.u.qual.qual = 0; iwe.u.qual.updated = IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_UPDATED @@ -7670,7 +7622,7 @@ static void airo_read_wireless_stats(struct airo_info *local) StatusRid status_rid; StatsRid stats_rid; CapabilityRid cap_rid; - u32 *vals = stats_rid.vals; + __le32 *vals = stats_rid.vals; /* Get stats out of the card */ clear_bit(JOB_WSTATS, &local->jobs); @@ -7684,18 +7636,22 @@ static void airo_read_wireless_stats(struct airo_info *local) up(&local->sem); /* The status */ - local->wstats.status = status_rid.mode; + local->wstats.status = le16_to_cpu(status_rid.mode); /* Signal quality and co */ if (local->rssi) { - local->wstats.qual.level = airo_rssi_to_dbm( local->rssi, status_rid.sigQuality ); + local->wstats.qual.level = + airo_rssi_to_dbm(local->rssi, + le16_to_cpu(status_rid.sigQuality)); /* normalizedSignalStrength appears to be a percentage */ - local->wstats.qual.qual = status_rid.normalizedSignalStrength; + local->wstats.qual.qual = + le16_to_cpu(status_rid.normalizedSignalStrength); } else { - local->wstats.qual.level = (status_rid.normalizedSignalStrength + 321) / 2; + local->wstats.qual.level = + (le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2; local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid); } - if (status_rid.len >= 124) { + if (le16_to_cpu(status_rid.len) >= 124) { local->wstats.qual.noise = 0x100 - status_rid.noisedBm; local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; } else { @@ -7705,12 +7661,15 @@ static void airo_read_wireless_stats(struct airo_info *local) /* Packets discarded in the wireless adapter due to wireless * specific problems */ - local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */ - local->wstats.discard.code = vals[6];/* RxWepErr */ - local->wstats.discard.fragment = vals[30]; - local->wstats.discard.retries = vals[10]; - local->wstats.discard.misc = vals[1] + vals[32]; - local->wstats.miss.beacon = vals[34]; + local->wstats.discard.nwid = le32_to_cpu(vals[56]) + + le32_to_cpu(vals[57]) + + le32_to_cpu(vals[58]); /* SSID Mismatch */ + local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */ + local->wstats.discard.fragment = le32_to_cpu(vals[30]); + local->wstats.discard.retries = le32_to_cpu(vals[10]); + local->wstats.discard.misc = le32_to_cpu(vals[1]) + + le32_to_cpu(vals[32]); + local->wstats.miss.beacon = le32_to_cpu(vals[34]); } static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) @@ -7896,7 +7855,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) cfg->opmode |= MODE_MIC; - if ((cfg->opmode & 0xFF) == MODE_STA_IBSS) + if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS) set_bit (FLAG_ADHOC, &ai->flags); else clear_bit (FLAG_ADHOC, &ai->flags); diff --git a/drivers/net/wireless/ath5k/Makefile b/drivers/net/wireless/ath5k/Makefile new file mode 100644 index 000000000000..321641f99e13 --- /dev/null +++ b/drivers/net/wireless/ath5k/Makefile @@ -0,0 +1,2 @@ +ath5k-objs = base.o hw.o regdom.o initvals.o phy.o debug.o +obj-$(CONFIG_ATH5K) += ath5k.o diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h new file mode 100644 index 000000000000..c79066b38d3b --- /dev/null +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -0,0 +1,1173 @@ +/* + * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ATH5K_H +#define _ATH5K_H + +/* Set this to 1 to disable regulatory domain restrictions for channel tests. + * WARNING: This is for debuging only and has side effects (eg. scan takes too + * long and results timeouts). It's also illegal to tune to some of the + * supported frequencies in some countries, so use this at your own risk, + * you've been warned. */ +#define CHAN_DEBUG 0 + +#include <linux/io.h> +#include <linux/types.h> +#include <net/mac80211.h> + +#include "hw.h" +#include "regdom.h" + +/* PCI IDs */ +#define PCI_DEVICE_ID_ATHEROS_AR5210 0x0007 /* AR5210 */ +#define PCI_DEVICE_ID_ATHEROS_AR5311 0x0011 /* AR5311 */ +#define PCI_DEVICE_ID_ATHEROS_AR5211 0x0012 /* AR5211 */ +#define PCI_DEVICE_ID_ATHEROS_AR5212 0x0013 /* AR5212 */ +#define PCI_DEVICE_ID_3COM_3CRDAG675 0x0013 /* 3CRDAG675 (Atheros AR5212) */ +#define PCI_DEVICE_ID_3COM_2_3CRPAG175 0x0013 /* 3CRPAG175 (Atheros AR5212) */ +#define PCI_DEVICE_ID_ATHEROS_AR5210_AP 0x0207 /* AR5210 (Early) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_IBM 0x1014 /* AR5212 (IBM MiniPCI) */ +#define PCI_DEVICE_ID_ATHEROS_AR5210_DEFAULT 0x1107 /* AR5210 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_DEFAULT 0x1113 /* AR5212 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_DEFAULT 0x1112 /* AR5211 (no eeprom) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_FPGA 0xf013 /* AR5212 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_LEGACY 0xff12 /* AR5211 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5211_FPGA11B 0xf11b /* AR5211 (emulation board) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */ +#define PCI_DEVICE_ID_ATHEROS_AR5312_REV8 0x0058 /* AR5312 WMAC (AP43-030) */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0014 0x0014 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0015 0x0015 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0016 0x0016 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0017 0x0017 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0018 0x0018 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR5212_0019 0x0019 /* AR5212 compatible */ +#define PCI_DEVICE_ID_ATHEROS_AR2413 0x001a /* AR2413 (Griffin-lite) */ +#define PCI_DEVICE_ID_ATHEROS_AR5413 0x001b /* AR5413 (Eagle) */ +#define PCI_DEVICE_ID_ATHEROS_AR5424 0x001c /* AR5424 (Condor PCI-E) */ +#define PCI_DEVICE_ID_ATHEROS_AR5416 0x0023 /* AR5416 */ +#define PCI_DEVICE_ID_ATHEROS_AR5418 0x0024 /* AR5418 */ + +/****************************\ + GENERIC DRIVER DEFINITIONS +\****************************/ + +#define ATH5K_PRINTF(fmt, ...) printk("%s: " fmt, __func__, ##__VA_ARGS__) + +#define ATH5K_PRINTK(_sc, _level, _fmt, ...) \ + printk(_level "ath5k %s: " _fmt, \ + ((_sc) && (_sc)->hw) ? wiphy_name((_sc)->hw->wiphy) : "", \ + ##__VA_ARGS__) + +#define ATH5K_PRINTK_LIMIT(_sc, _level, _fmt, ...) do { \ + if (net_ratelimit()) \ + ATH5K_PRINTK(_sc, _level, _fmt, ##__VA_ARGS__); \ + } while (0) + +#define ATH5K_INFO(_sc, _fmt, ...) \ + ATH5K_PRINTK(_sc, KERN_INFO, _fmt, ##__VA_ARGS__) + +#define ATH5K_WARN(_sc, _fmt, ...) \ + ATH5K_PRINTK_LIMIT(_sc, KERN_WARNING, _fmt, ##__VA_ARGS__) + +#define ATH5K_ERR(_sc, _fmt, ...) \ + ATH5K_PRINTK_LIMIT(_sc, KERN_ERR, _fmt, ##__VA_ARGS__) + +/* + * Some tuneable values (these should be changeable by the user) + */ +#define AR5K_TUNE_DMA_BEACON_RESP 2 +#define AR5K_TUNE_SW_BEACON_RESP 10 +#define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 +#define AR5K_TUNE_RADAR_ALERT false +#define AR5K_TUNE_MIN_TX_FIFO_THRES 1 +#define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_LEN / 64) + 1) +#define AR5K_TUNE_REGISTER_TIMEOUT 20000 +/* Register for RSSI threshold has a mask of 0xff, so 255 seems to + * be the max value. */ +#define AR5K_TUNE_RSSI_THRES 129 +/* This must be set when setting the RSSI threshold otherwise it can + * prevent a reset. If AR5K_RSSI_THR is read after writing to it + * the BMISS_THRES will be seen as 0, seems harware doesn't keep + * track of it. Max value depends on harware. For AR5210 this is just 7. + * For AR5211+ this seems to be up to 255. */ +#define AR5K_TUNE_BMISS_THRES 7 +#define AR5K_TUNE_REGISTER_DWELL_TIME 20000 +#define AR5K_TUNE_BEACON_INTERVAL 100 +#define AR5K_TUNE_AIFS 2 +#define AR5K_TUNE_AIFS_11B 2 +#define AR5K_TUNE_AIFS_XR 0 +#define AR5K_TUNE_CWMIN 15 +#define AR5K_TUNE_CWMIN_11B 31 +#define AR5K_TUNE_CWMIN_XR 3 +#define AR5K_TUNE_CWMAX 1023 +#define AR5K_TUNE_CWMAX_11B 1023 +#define AR5K_TUNE_CWMAX_XR 7 +#define AR5K_TUNE_NOISE_FLOOR -72 +#define AR5K_TUNE_MAX_TXPOWER 60 +#define AR5K_TUNE_DEFAULT_TXPOWER 30 +#define AR5K_TUNE_TPC_TXPOWER true +#define AR5K_TUNE_ANT_DIVERSITY true +#define AR5K_TUNE_HWTXTRIES 4 + +/* token to use for aifs, cwmin, cwmax in MadWiFi */ +#define AR5K_TXQ_USEDEFAULT ((u32) -1) + +/* GENERIC CHIPSET DEFINITIONS */ + +/* MAC Chips */ +enum ath5k_version { + AR5K_AR5210 = 0, + AR5K_AR5211 = 1, + AR5K_AR5212 = 2, +}; + +/* PHY Chips */ +enum ath5k_radio { + AR5K_RF5110 = 0, + AR5K_RF5111 = 1, + AR5K_RF5112 = 2, + AR5K_RF5413 = 3, +}; + +/* + * Common silicon revision/version values + */ + +enum ath5k_srev_type { + AR5K_VERSION_VER, + AR5K_VERSION_RAD, +}; + +struct ath5k_srev_name { + const char *sr_name; + enum ath5k_srev_type sr_type; + u_int sr_val; +}; + +#define AR5K_SREV_UNKNOWN 0xffff + +#define AR5K_SREV_VER_AR5210 0x00 +#define AR5K_SREV_VER_AR5311 0x10 +#define AR5K_SREV_VER_AR5311A 0x20 +#define AR5K_SREV_VER_AR5311B 0x30 +#define AR5K_SREV_VER_AR5211 0x40 +#define AR5K_SREV_VER_AR5212 0x50 +#define AR5K_SREV_VER_AR5213 0x55 +#define AR5K_SREV_VER_AR5213A 0x59 +#define AR5K_SREV_VER_AR2424 0xa0 +#define AR5K_SREV_VER_AR5424 0xa3 +#define AR5K_SREV_VER_AR5413 0xa4 +#define AR5K_SREV_VER_AR5414 0xa5 +#define AR5K_SREV_VER_AR5416 0xc0 /* ? */ +#define AR5K_SREV_VER_AR5418 0xca + +#define AR5K_SREV_RAD_5110 0x00 +#define AR5K_SREV_RAD_5111 0x10 +#define AR5K_SREV_RAD_5111A 0x15 +#define AR5K_SREV_RAD_2111 0x20 +#define AR5K_SREV_RAD_5112 0x30 +#define AR5K_SREV_RAD_5112A 0x35 +#define AR5K_SREV_RAD_2112 0x40 +#define AR5K_SREV_RAD_2112A 0x45 +#define AR5K_SREV_RAD_SC1 0x63 /* Found on 5413/5414 */ +#define AR5K_SREV_RAD_SC2 0xa2 /* Found on 2424/5424 */ +#define AR5K_SREV_RAD_5133 0xc0 /* MIMO found on 5418 */ + +/* IEEE defs */ + +#define IEEE80211_MAX_LEN 2500 + +/* TODO add support to mac80211 for vendor-specific rates and modes */ + +/* + * Some of this information is based on Documentation from: + * + * http://madwifi.org/wiki/ChipsetFeatures/SuperAG + * + * Modulation for Atheros' eXtended Range - range enhancing extension that is + * supposed to double the distance an Atheros client device can keep a + * connection with an Atheros access point. This is achieved by increasing + * the receiver sensitivity up to, -105dBm, which is about 20dB above what + * the 802.11 specifications demand. In addition, new (proprietary) data rates + * are introduced: 3, 2, 1, 0.5 and 0.25 MBit/s. + * + * Please note that can you either use XR or TURBO but you cannot use both, + * they are exclusive. + * + */ +#define MODULATION_XR 0x00000200 +/* + * Modulation for Atheros' Turbo G and Turbo A, its supposed to provide a + * throughput transmission speed up to 40Mbit/s-60Mbit/s at a 108Mbit/s + * signaling rate achieved through the bonding of two 54Mbit/s 802.11g + * channels. To use this feature your Access Point must also suport it. + * There is also a distinction between "static" and "dynamic" turbo modes: + * + * - Static: is the dumb version: devices set to this mode stick to it until + * the mode is turned off. + * - Dynamic: is the intelligent version, the network decides itself if it + * is ok to use turbo. As soon as traffic is detected on adjacent channels + * (which would get used in turbo mode), or when a non-turbo station joins + * the network, turbo mode won't be used until the situation changes again. + * Dynamic mode is achieved by Atheros' Adaptive Radio (AR) feature which + * monitors the used radio band in order to decide whether turbo mode may + * be used or not. + * + * This article claims Super G sticks to bonding of channels 5 and 6 for + * USA: + * + * http://www.pcworld.com/article/id,113428-page,1/article.html + * + * The channel bonding seems to be driver specific though. In addition to + * deciding what channels will be used, these "Turbo" modes are accomplished + * by also enabling the following features: + * + * - Bursting: allows multiple frames to be sent at once, rather than pausing + * after each frame. Bursting is a standards-compliant feature that can be + * used with any Access Point. + * - Fast frames: increases the amount of information that can be sent per + * frame, also resulting in a reduction of transmission overhead. It is a + * proprietary feature that needs to be supported by the Access Point. + * - Compression: data frames are compressed in real time using a Lempel Ziv + * algorithm. This is done transparently. Once this feature is enabled, + * compression and decompression takes place inside the chipset, without + * putting additional load on the host CPU. + * + */ +#define MODULATION_TURBO 0x00000080 + +enum ath5k_vendor_mode { + MODE_ATHEROS_TURBO = NUM_IEEE80211_MODES+1, + MODE_ATHEROS_TURBOG +}; + +/* Number of supported mac80211 enum ieee80211_phymode modes by this driver */ +#define NUM_DRIVER_MODES 3 + +/* adding this flag to rate_code enables short preamble, see ar5212_reg.h */ +#define AR5K_SET_SHORT_PREAMBLE 0x04 + +#define HAS_SHPREAMBLE(_ix) (rt->rates[_ix].modulation == IEEE80211_RATE_CCK_2) +#define SHPREAMBLE_FLAG(_ix) (HAS_SHPREAMBLE(_ix) ? AR5K_SET_SHORT_PREAMBLE : 0) + +/****************\ + TX DEFINITIONS +\****************/ + +/* + * Tx Descriptor + */ +struct ath5k_tx_status { + u16 ts_seqnum; + u16 ts_tstamp; + u8 ts_status; + u8 ts_rate; + s8 ts_rssi; + u8 ts_shortretry; + u8 ts_longretry; + u8 ts_virtcol; + u8 ts_antenna; +}; + +#define AR5K_TXSTAT_ALTRATE 0x80 +#define AR5K_TXERR_XRETRY 0x01 +#define AR5K_TXERR_FILT 0x02 +#define AR5K_TXERR_FIFO 0x04 + +/** + * enum ath5k_tx_queue - Queue types used to classify tx queues. + * @AR5K_TX_QUEUE_INACTIVE: q is unused -- see ath5k_hw_release_tx_queue + * @AR5K_TX_QUEUE_DATA: A normal data queue + * @AR5K_TX_QUEUE_XR_DATA: An XR-data queue + * @AR5K_TX_QUEUE_BEACON: The beacon queue + * @AR5K_TX_QUEUE_CAB: The after-beacon queue + * @AR5K_TX_QUEUE_UAPSD: Unscheduled Automatic Power Save Delivery queue + */ +enum ath5k_tx_queue { + AR5K_TX_QUEUE_INACTIVE = 0, + AR5K_TX_QUEUE_DATA, + AR5K_TX_QUEUE_XR_DATA, + AR5K_TX_QUEUE_BEACON, + AR5K_TX_QUEUE_CAB, + AR5K_TX_QUEUE_UAPSD, +}; + +#define AR5K_NUM_TX_QUEUES 10 +#define AR5K_NUM_TX_QUEUES_NOQCU 2 + +/* + * Queue syb-types to classify normal data queues. + * These are the 4 Access Categories as defined in + * WME spec. 0 is the lowest priority and 4 is the + * highest. Normal data that hasn't been classified + * goes to the Best Effort AC. + */ +enum ath5k_tx_queue_subtype { + AR5K_WME_AC_BK = 0, /*Background traffic*/ + AR5K_WME_AC_BE, /*Best-effort (normal) traffic)*/ + AR5K_WME_AC_VI, /*Video traffic*/ + AR5K_WME_AC_VO, /*Voice traffic*/ +}; + +/* + * Queue ID numbers as returned by the hw functions, each number + * represents a hw queue. If hw does not support hw queues + * (eg 5210) all data goes in one queue. These match + * d80211 definitions (net80211/MadWiFi don't use them). + */ +enum ath5k_tx_queue_id { + AR5K_TX_QUEUE_ID_NOQCU_DATA = 0, + AR5K_TX_QUEUE_ID_NOQCU_BEACON = 1, + AR5K_TX_QUEUE_ID_DATA_MIN = 0, /*IEEE80211_TX_QUEUE_DATA0*/ + AR5K_TX_QUEUE_ID_DATA_MAX = 4, /*IEEE80211_TX_QUEUE_DATA4*/ + AR5K_TX_QUEUE_ID_DATA_SVP = 5, /*IEEE80211_TX_QUEUE_SVP - Spectralink Voice Protocol*/ + AR5K_TX_QUEUE_ID_CAB = 6, /*IEEE80211_TX_QUEUE_AFTER_BEACON*/ + AR5K_TX_QUEUE_ID_BEACON = 7, /*IEEE80211_TX_QUEUE_BEACON*/ + AR5K_TX_QUEUE_ID_UAPSD = 8, + AR5K_TX_QUEUE_ID_XR_DATA = 9, +}; + + +/* + * Flags to set hw queue's parameters... + */ +#define AR5K_TXQ_FLAG_TXOKINT_ENABLE 0x0001 /* Enable TXOK interrupt */ +#define AR5K_TXQ_FLAG_TXERRINT_ENABLE 0x0002 /* Enable TXERR interrupt */ +#define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ +#define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ +#define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ +#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */ +#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/ +#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */ +#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */ +#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/ + +/* + * A struct to hold tx queue's parameters + */ +struct ath5k_txq_info { + enum ath5k_tx_queue tqi_type; + enum ath5k_tx_queue_subtype tqi_subtype; + u16 tqi_flags; /* Tx queue flags (see above) */ + u32 tqi_aifs; /* Arbitrated Interframe Space */ + s32 tqi_cw_min; /* Minimum Contention Window */ + s32 tqi_cw_max; /* Maximum Contention Window */ + u32 tqi_cbr_period; /* Constant bit rate period */ + u32 tqi_cbr_overflow_limit; + u32 tqi_burst_time; + u32 tqi_ready_time; /* Not used */ +}; + +/* + * Transmit packet types. + * These are not fully used inside OpenHAL yet + */ +enum ath5k_pkt_type { + AR5K_PKT_TYPE_NORMAL = 0, + AR5K_PKT_TYPE_ATIM = 1, + AR5K_PKT_TYPE_PSPOLL = 2, + AR5K_PKT_TYPE_BEACON = 3, + AR5K_PKT_TYPE_PROBE_RESP = 4, + AR5K_PKT_TYPE_PIFS = 5, +}; + +/* + * TX power and TPC settings + */ +#define AR5K_TXPOWER_OFDM(_r, _v) ( \ + ((0 & 1) << ((_v) + 6)) | \ + (((ah->ah_txpower.txp_rates[(_r)]) & 0x3f) << (_v)) \ +) + +#define AR5K_TXPOWER_CCK(_r, _v) ( \ + (ah->ah_txpower.txp_rates[(_r)] & 0x3f) << (_v) \ +) + +/* + * DMA size definitions (2^n+2) + */ +enum ath5k_dmasize { + AR5K_DMASIZE_4B = 0, + AR5K_DMASIZE_8B, + AR5K_DMASIZE_16B, + AR5K_DMASIZE_32B, + AR5K_DMASIZE_64B, + AR5K_DMASIZE_128B, + AR5K_DMASIZE_256B, + AR5K_DMASIZE_512B +}; + + +/****************\ + RX DEFINITIONS +\****************/ + +/* + * Rx Descriptor + */ +struct ath5k_rx_status { + u16 rs_datalen; + u16 rs_tstamp; + u8 rs_status; + u8 rs_phyerr; + s8 rs_rssi; + u8 rs_keyix; + u8 rs_rate; + u8 rs_antenna; + u8 rs_more; +}; + +#define AR5K_RXERR_CRC 0x01 +#define AR5K_RXERR_PHY 0x02 +#define AR5K_RXERR_FIFO 0x04 +#define AR5K_RXERR_DECRYPT 0x08 +#define AR5K_RXERR_MIC 0x10 +#define AR5K_RXKEYIX_INVALID ((u8) - 1) +#define AR5K_TXKEYIX_INVALID ((u32) - 1) + +struct ath5k_mib_stats { + u32 ackrcv_bad; + u32 rts_bad; + u32 rts_good; + u32 fcs_bad; + u32 beacons; +}; + + + + +/**************************\ + BEACON TIMERS DEFINITIONS +\**************************/ + +#define AR5K_BEACON_PERIOD 0x0000ffff +#define AR5K_BEACON_ENA 0x00800000 /*enable beacon xmit*/ +#define AR5K_BEACON_RESET_TSF 0x01000000 /*force a TSF reset*/ + +#if 0 +/** + * struct ath5k_beacon_state - Per-station beacon timer state. + * @bs_interval: in TU's, can also include the above flags + * @bs_cfp_max_duration: if non-zero hw is setup to coexist with a + * Point Coordination Function capable AP + */ +struct ath5k_beacon_state { + u32 bs_next_beacon; + u32 bs_next_dtim; + u32 bs_interval; + u8 bs_dtim_period; + u8 bs_cfp_period; + u16 bs_cfp_max_duration; + u16 bs_cfp_du_remain; + u16 bs_tim_offset; + u16 bs_sleep_duration; + u16 bs_bmiss_threshold; + u32 bs_cfp_next; +}; +#endif + + +/* + * TSF to TU conversion: + * + * TSF is a 64bit value in usec (microseconds). + * TU is a 32bit value and defined by IEEE802.11 (page 6) as "A measurement of + * time equal to 1024 usec", so it's roughly milliseconds (usec / 1024). + */ +#define TSF_TO_TU(_tsf) (u32)((_tsf) >> 10) + + + +/********************\ + COMMON DEFINITIONS +\********************/ + +/* + * Atheros descriptor + */ +struct ath5k_desc { + u32 ds_link; + u32 ds_data; + u32 ds_ctl0; + u32 ds_ctl1; + u32 ds_hw[4]; + + union { + struct ath5k_rx_status rx; + struct ath5k_tx_status tx; + } ds_us; + +#define ds_rxstat ds_us.rx +#define ds_txstat ds_us.tx + +} __packed; + +#define AR5K_RXDESC_INTREQ 0x0020 + +#define AR5K_TXDESC_CLRDMASK 0x0001 +#define AR5K_TXDESC_NOACK 0x0002 /*[5211+]*/ +#define AR5K_TXDESC_RTSENA 0x0004 +#define AR5K_TXDESC_CTSENA 0x0008 +#define AR5K_TXDESC_INTREQ 0x0010 +#define AR5K_TXDESC_VEOL 0x0020 /*[5211+]*/ + +#define AR5K_SLOT_TIME_9 396 +#define AR5K_SLOT_TIME_20 880 +#define AR5K_SLOT_TIME_MAX 0xffff + +/* channel_flags */ +#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */ +#define CHANNEL_TURBO 0x0010 /* Turbo Channel */ +#define CHANNEL_CCK 0x0020 /* CCK channel */ +#define CHANNEL_OFDM 0x0040 /* OFDM channel */ +#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */ +#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */ +#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */ +#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ +#define CHANNEL_XR 0x0800 /* XR channel */ + +#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) +#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_TG (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_108A CHANNEL_T +#define CHANNEL_108G CHANNEL_TG +#define CHANNEL_X (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR) + +#define CHANNEL_ALL (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \ + CHANNEL_TURBO) + +#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL & ~CHANNEL_TURBO) +#define CHANNEL_MODES CHANNEL_ALL + +/* + * Used internaly in OpenHAL (ar5211.c/ar5212.c + * for reset_tx_queue). Also see struct struct ieee80211_channel. + */ +#define IS_CHAN_XR(_c) ((_c.val & CHANNEL_XR) != 0) +#define IS_CHAN_B(_c) ((_c.val & CHANNEL_B) != 0) + +/* + * The following structure will be used to map 2GHz channels to + * 5GHz Atheros channels. + */ +struct ath5k_athchan_2ghz { + u32 a2_flags; + u16 a2_athchan; +}; + +/* + * Rate definitions + * TODO: Clean them up or move them on mac80211 -most of these infos are + * used by the rate control algorytm on MadWiFi. + */ + +/* Max number of rates on the rate table and what it seems + * Atheros hardware supports */ +#define AR5K_MAX_RATES 32 + +/** + * struct ath5k_rate - rate structure + * @valid: is this a valid rate for the current mode + * @modulation: respective mac80211 modulation + * @rate_kbps: rate in kbit/s + * @rate_code: hardware rate value, used in &struct ath5k_desc, on RX on + * &struct ath5k_rx_status.rs_rate and on TX on + * &struct ath5k_tx_status.ts_rate. Seems the ar5xxx harware supports + * up to 32 rates, indexed by 1-32. This means we really only need + * 6 bits for the rate_code. + * @dot11_rate: respective IEEE-802.11 rate value + * @control_rate: index of rate assumed to be used to send control frames. + * This can be used to set override the value on the rate duration + * registers. This is only useful if we can override in the harware at + * what rate we want to send control frames at. Note that IEEE-802.11 + * Ch. 9.6 (after IEEE 802.11g changes) defines the rate at which we + * should send ACK/CTS, if we change this value we can be breaking + * the spec. + * + * This structure is used to get the RX rate or set the TX rate on the + * hardware descriptors. It is also used for internal modulation control + * and settings. + * + * On RX after the &struct ath5k_desc is parsed by the appropriate + * ah_proc_rx_desc() the respective hardware rate value is set in + * &struct ath5k_rx_status.rs_rate. On TX the desired rate is set in + * &struct ath5k_tx_status.ts_rate which is later used to setup the + * &struct ath5k_desc correctly. This is the hardware rate map we are + * aware of: + * + * rate_code 1 2 3 4 5 6 7 8 + * rate_kbps 3000 1000 ? ? ? 2000 500 48000 + * + * rate_code 9 10 11 12 13 14 15 16 + * rate_kbps 24000 12000 6000 54000 36000 18000 9000 ? + * + * rate_code 17 18 19 20 21 22 23 24 + * rate_kbps ? ? ? ? ? ? ? 11000 + * + * rate_code 25 26 27 28 29 30 31 32 + * rate_kbps 5500 2000 1000 ? ? ? ? ? + * + */ +struct ath5k_rate { + u8 valid; + u32 modulation; + u16 rate_kbps; + u8 rate_code; + u8 dot11_rate; + u8 control_rate; +}; + +/* XXX: GRR all this stuff to get leds blinking ??? (check out setcurmode) */ +struct ath5k_rate_table { + u16 rate_count; + u8 rate_code_to_index[AR5K_MAX_RATES]; /* Back-mapping */ + struct ath5k_rate rates[AR5K_MAX_RATES]; +}; + +/* + * Rate tables... + */ +#define AR5K_RATES_11A { 8, { \ + 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ + 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ + 255, 255, 255, 255, 255, 255, 255, 255 }, { \ + { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 0 }, \ + { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 0 }, \ + { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 2 }, \ + { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 2 }, \ + { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 4 }, \ + { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 4 }, \ + { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 4 }, \ + { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 4 } } \ +} + +#define AR5K_RATES_11B { 4, { \ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, \ + 3, 2, 1, 0, 255, 255, 255, 255 }, { \ + { 1, IEEE80211_RATE_CCK, 1000, 27, 130, 0 }, \ + { 1, IEEE80211_RATE_CCK_2, 2000, 26, 132, 1 }, \ + { 1, IEEE80211_RATE_CCK_2, 5500, 25, 139, 1 }, \ + { 1, IEEE80211_RATE_CCK_2, 11000, 24, 150, 1 } } \ +} + +#define AR5K_RATES_11G { 12, { \ + 255, 255, 255, 255, 255, 255, 255, 255, 10, 8, 6, 4, \ + 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ + 3, 2, 1, 0, 255, 255, 255, 255 }, { \ + { 1, IEEE80211_RATE_CCK, 1000, 27, 2, 0 }, \ + { 1, IEEE80211_RATE_CCK_2, 2000, 26, 4, 1 }, \ + { 1, IEEE80211_RATE_CCK_2, 5500, 25, 11, 1 }, \ + { 1, IEEE80211_RATE_CCK_2, 11000, 24, 22, 1 }, \ + { 0, IEEE80211_RATE_OFDM, 6000, 11, 12, 4 }, \ + { 0, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \ + { 1, IEEE80211_RATE_OFDM, 12000, 10, 24, 6 }, \ + { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \ + { 1, IEEE80211_RATE_OFDM, 24000, 9, 48, 8 }, \ + { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \ + { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \ + { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \ +} + +#define AR5K_RATES_TURBO { 8, { \ + 255, 255, 255, 255, 255, 255, 255, 255, 6, 4, 2, 0, \ + 7, 5, 3, 1, 255, 255, 255, 255, 255, 255, 255, 255, \ + 255, 255, 255, 255, 255, 255, 255, 255 }, { \ + { 1, MODULATION_TURBO, 6000, 11, 140, 0 }, \ + { 1, MODULATION_TURBO, 9000, 15, 18, 0 }, \ + { 1, MODULATION_TURBO, 12000, 10, 152, 2 }, \ + { 1, MODULATION_TURBO, 18000, 14, 36, 2 }, \ + { 1, MODULATION_TURBO, 24000, 9, 176, 4 }, \ + { 1, MODULATION_TURBO, 36000, 13, 72, 4 }, \ + { 1, MODULATION_TURBO, 48000, 8, 96, 4 }, \ + { 1, MODULATION_TURBO, 54000, 12, 108, 4 } } \ +} + +#define AR5K_RATES_XR { 12, { \ + 255, 3, 1, 255, 255, 255, 2, 0, 10, 8, 6, 4, \ + 11, 9, 7, 5, 255, 255, 255, 255, 255, 255, 255, 255, \ + 255, 255, 255, 255, 255, 255, 255, 255 }, { \ + { 1, MODULATION_XR, 500, 7, 129, 0 }, \ + { 1, MODULATION_XR, 1000, 2, 139, 1 }, \ + { 1, MODULATION_XR, 2000, 6, 150, 2 }, \ + { 1, MODULATION_XR, 3000, 1, 150, 3 }, \ + { 1, IEEE80211_RATE_OFDM, 6000, 11, 140, 4 }, \ + { 1, IEEE80211_RATE_OFDM, 9000, 15, 18, 4 }, \ + { 1, IEEE80211_RATE_OFDM, 12000, 10, 152, 6 }, \ + { 1, IEEE80211_RATE_OFDM, 18000, 14, 36, 6 }, \ + { 1, IEEE80211_RATE_OFDM, 24000, 9, 176, 8 }, \ + { 1, IEEE80211_RATE_OFDM, 36000, 13, 72, 8 }, \ + { 1, IEEE80211_RATE_OFDM, 48000, 8, 96, 8 }, \ + { 1, IEEE80211_RATE_OFDM, 54000, 12, 108, 8 } } \ +} + +/* + * Crypto definitions + */ + +#define AR5K_KEYCACHE_SIZE 8 + +/***********************\ + HW RELATED DEFINITIONS +\***********************/ + +/* + * Misc definitions + */ +#define AR5K_RSSI_EP_MULTIPLIER (1<<7) + +#define AR5K_ASSERT_ENTRY(_e, _s) do { \ + if (_e >= _s) \ + return (false); \ +} while (0) + + +enum ath5k_ant_setting { + AR5K_ANT_VARIABLE = 0, /* variable by programming */ + AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ + AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ + AR5K_ANT_MAX = 3, +}; + +/* + * Hardware interrupt abstraction + */ + +/** + * enum ath5k_int - Hardware interrupt masks helpers + * + * @AR5K_INT_RX: mask to identify received frame interrupts, of type + * AR5K_ISR_RXOK or AR5K_ISR_RXERR + * @AR5K_INT_RXDESC: Request RX descriptor/Read RX descriptor (?) + * @AR5K_INT_RXNOFRM: No frame received (?) + * @AR5K_INT_RXEOL: received End Of List for VEOL (Virtual End Of List). The + * Queue Control Unit (QCU) signals an EOL interrupt only if a descriptor's + * LinkPtr is NULL. For more details, refer to: + * http://www.freepatentsonline.com/20030225739.html + * @AR5K_INT_RXORN: Indicates we got RX overrun (eg. no more descriptors). + * Note that Rx overrun is not always fatal, on some chips we can continue + * operation without reseting the card, that's why int_fatal is not + * common for all chips. + * @AR5K_INT_TX: mask to identify received frame interrupts, of type + * AR5K_ISR_TXOK or AR5K_ISR_TXERR + * @AR5K_INT_TXDESC: Request TX descriptor/Read TX status descriptor (?) + * @AR5K_INT_TXURN: received when we should increase the TX trigger threshold + * We currently do increments on interrupt by + * (AR5K_TUNE_MAX_TX_FIFO_THRES - current_trigger_level) / 2 + * @AR5K_INT_MIB: Indicates the Management Information Base counters should be + * checked. We should do this with ath5k_hw_update_mib_counters() but + * it seems we should also then do some noise immunity work. + * @AR5K_INT_RXPHY: RX PHY Error + * @AR5K_INT_RXKCM: ?? + * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a + * beacon that must be handled in software. The alternative is if you + * have VEOL support, in that case you let the hardware deal with things. + * @AR5K_INT_BMISS: If in STA mode this indicates we have stopped seeing + * beacons from the AP have associated with, we should probably try to + * reassociate. When in IBSS mode this might mean we have not received + * any beacons from any local stations. Note that every station in an + * IBSS schedules to send beacons at the Target Beacon Transmission Time + * (TBTT) with a random backoff. + * @AR5K_INT_BNR: Beacon Not Ready interrupt - ?? + * @AR5K_INT_GPIO: GPIO interrupt is used for RF Kill, disabled for now + * until properly handled + * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA + * errors. These types of errors we can enable seem to be of type + * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. + * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER + * @AR5K_INT_NOCARD: signals the card has been removed + * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same + * bit value + * + * These are mapped to take advantage of some common bits + * between the MACs, to be able to set intr properties + * easier. Some of them are not used yet inside hw.c. Most map + * to the respective hw interrupt value as they are common amogst different + * MACs. + */ +enum ath5k_int { + AR5K_INT_RX = 0x00000001, /* Not common */ + AR5K_INT_RXDESC = 0x00000002, + AR5K_INT_RXNOFRM = 0x00000008, + AR5K_INT_RXEOL = 0x00000010, + AR5K_INT_RXORN = 0x00000020, + AR5K_INT_TX = 0x00000040, /* Not common */ + AR5K_INT_TXDESC = 0x00000080, + AR5K_INT_TXURN = 0x00000800, + AR5K_INT_MIB = 0x00001000, + AR5K_INT_RXPHY = 0x00004000, + AR5K_INT_RXKCM = 0x00008000, + AR5K_INT_SWBA = 0x00010000, + AR5K_INT_BMISS = 0x00040000, + AR5K_INT_BNR = 0x00100000, /* Not common */ + AR5K_INT_GPIO = 0x01000000, + AR5K_INT_FATAL = 0x40000000, /* Not common */ + AR5K_INT_GLOBAL = 0x80000000, + + AR5K_INT_COMMON = AR5K_INT_RXNOFRM + | AR5K_INT_RXDESC + | AR5K_INT_RXEOL + | AR5K_INT_RXORN + | AR5K_INT_TXURN + | AR5K_INT_TXDESC + | AR5K_INT_MIB + | AR5K_INT_RXPHY + | AR5K_INT_RXKCM + | AR5K_INT_SWBA + | AR5K_INT_BMISS + | AR5K_INT_GPIO, + AR5K_INT_NOCARD = 0xffffffff +}; + +/* + * Power management + */ +enum ath5k_power_mode { + AR5K_PM_UNDEFINED = 0, + AR5K_PM_AUTO, + AR5K_PM_AWAKE, + AR5K_PM_FULL_SLEEP, + AR5K_PM_NETWORK_SLEEP, +}; + +/* + * These match net80211 definitions (not used in + * d80211). + */ +#define AR5K_LED_INIT 0 /*IEEE80211_S_INIT*/ +#define AR5K_LED_SCAN 1 /*IEEE80211_S_SCAN*/ +#define AR5K_LED_AUTH 2 /*IEEE80211_S_AUTH*/ +#define AR5K_LED_ASSOC 3 /*IEEE80211_S_ASSOC*/ +#define AR5K_LED_RUN 4 /*IEEE80211_S_RUN*/ + +/* GPIO-controlled software LED */ +#define AR5K_SOFTLED_PIN 0 +#define AR5K_SOFTLED_ON 0 +#define AR5K_SOFTLED_OFF 1 + +/* + * Chipset capabilities -see ath5k_hw_get_capability- + * get_capability function is not yet fully implemented + * in OpenHAL so most of these don't work yet... + */ +enum ath5k_capability_type { + AR5K_CAP_REG_DMN = 0, /* Used to get current reg. domain id */ + AR5K_CAP_TKIP_MIC = 2, /* Can handle TKIP MIC in hardware */ + AR5K_CAP_TKIP_SPLIT = 3, /* TKIP uses split keys */ + AR5K_CAP_PHYCOUNTERS = 4, /* PHY error counters */ + AR5K_CAP_DIVERSITY = 5, /* Supports fast diversity */ + AR5K_CAP_NUM_TXQUEUES = 6, /* Used to get max number of hw txqueues */ + AR5K_CAP_VEOL = 7, /* Supports virtual EOL */ + AR5K_CAP_COMPRESSION = 8, /* Supports compression */ + AR5K_CAP_BURST = 9, /* Supports packet bursting */ + AR5K_CAP_FASTFRAME = 10, /* Supports fast frames */ + AR5K_CAP_TXPOW = 11, /* Used to get global tx power limit */ + AR5K_CAP_TPC = 12, /* Can do per-packet tx power control (needed for 802.11a) */ + AR5K_CAP_BSSIDMASK = 13, /* Supports bssid mask */ + AR5K_CAP_MCAST_KEYSRCH = 14, /* Supports multicast key search */ + AR5K_CAP_TSF_ADJUST = 15, /* Supports beacon tsf adjust */ + AR5K_CAP_XR = 16, /* Supports XR mode */ + AR5K_CAP_WME_TKIPMIC = 17, /* Supports TKIP MIC when using WMM */ + AR5K_CAP_CHAN_HALFRATE = 18, /* Supports half rate channels */ + AR5K_CAP_CHAN_QUARTERRATE = 19, /* Supports quarter rate channels */ + AR5K_CAP_RFSILENT = 20, /* Supports RFsilent */ +}; + +struct ath5k_capabilities { + /* + * Supported PHY modes + * (ie. CHANNEL_A, CHANNEL_B, ...) + */ + DECLARE_BITMAP(cap_mode, NUM_DRIVER_MODES); + + /* + * Frequency range (without regulation restrictions) + */ + struct { + u16 range_2ghz_min; + u16 range_2ghz_max; + u16 range_5ghz_min; + u16 range_5ghz_max; + } cap_range; + + /* + * Active regulation domain settings + */ + struct { + enum ath5k_regdom reg_current; + enum ath5k_regdom reg_hw; + } cap_regdomain; + + /* + * Values stored in the EEPROM (some of them...) + */ + struct ath5k_eeprom_info cap_eeprom; + + /* + * Queue information + */ + struct { + u8 q_tx_num; + } cap_queues; +}; + + +/***************************************\ + HARDWARE ABSTRACTION LAYER STRUCTURE +\***************************************/ + +/* + * Misc defines + */ + +#define AR5K_MAX_GPIO 10 +#define AR5K_MAX_RF_BANKS 8 + +struct ath5k_hw { + u32 ah_magic; + + struct ath5k_softc *ah_sc; + void __iomem *ah_iobase; + + enum ath5k_int ah_imr; + + enum ieee80211_if_types ah_op_mode; + enum ath5k_power_mode ah_power_mode; + struct ieee80211_channel ah_current_channel; + bool ah_turbo; + bool ah_calibration; + bool ah_running; + bool ah_single_chip; + enum ath5k_rfgain ah_rf_gain; + + u32 ah_mac_srev; + u16 ah_mac_version; + u16 ah_mac_revision; + u16 ah_phy_revision; + u16 ah_radio_5ghz_revision; + u16 ah_radio_2ghz_revision; + + enum ath5k_version ah_version; + enum ath5k_radio ah_radio; + u32 ah_phy; + + bool ah_5ghz; + bool ah_2ghz; + +#define ah_regdomain ah_capabilities.cap_regdomain.reg_current +#define ah_regdomain_hw ah_capabilities.cap_regdomain.reg_hw +#define ah_modes ah_capabilities.cap_mode +#define ah_ee_version ah_capabilities.cap_eeprom.ee_version + + u32 ah_atim_window; + u32 ah_aifs; + u32 ah_cw_min; + u32 ah_cw_max; + bool ah_software_retry; + u32 ah_limit_tx_retries; + + u32 ah_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; + bool ah_ant_diversity; + + u8 ah_sta_id[ETH_ALEN]; + + /* Current BSSID we are trying to assoc to / creating. + * This is passed by mac80211 on config_interface() and cached here for + * use in resets */ + u8 ah_bssid[ETH_ALEN]; + + u32 ah_gpio[AR5K_MAX_GPIO]; + int ah_gpio_npins; + + struct ath5k_capabilities ah_capabilities; + + struct ath5k_txq_info ah_txq[AR5K_NUM_TX_QUEUES]; + u32 ah_txq_status; + u32 ah_txq_imr_txok; + u32 ah_txq_imr_txerr; + u32 ah_txq_imr_txurn; + u32 ah_txq_imr_txdesc; + u32 ah_txq_imr_txeol; + u32 *ah_rf_banks; + size_t ah_rf_banks_size; + struct ath5k_gain ah_gain; + u32 ah_offset[AR5K_MAX_RF_BANKS]; + + struct { + u16 txp_pcdac[AR5K_EEPROM_POWER_TABLE_SIZE]; + u16 txp_rates[AR5K_MAX_RATES]; + s16 txp_min; + s16 txp_max; + bool txp_tpc; + s16 txp_ofdm; + } ah_txpower; + + struct { + bool r_enabled; + int r_last_alert; + struct ieee80211_channel r_last_channel; + } ah_radar; + + /* noise floor from last periodic calibration */ + s32 ah_noise_floor; + + /* + * Function pointers + */ + int (*ah_setup_tx_desc)(struct ath5k_hw *, struct ath5k_desc *, + unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned int); + bool (*ah_setup_xtx_desc)(struct ath5k_hw *, struct ath5k_desc *, + unsigned int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int); + int (*ah_proc_tx_desc)(struct ath5k_hw *, struct ath5k_desc *); + int (*ah_proc_rx_desc)(struct ath5k_hw *, struct ath5k_desc *); +}; + +/* + * Prototypes + */ + +/* General Functions */ +extern int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, bool is_set); +/* Attach/Detach Functions */ +extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version); +extern const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, unsigned int mode); +extern void ath5k_hw_detach(struct ath5k_hw *ah); +/* Reset Functions */ +extern int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, struct ieee80211_channel *channel, bool change_channel); +/* Power management functions */ +extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration); +/* DMA Related Functions */ +extern void ath5k_hw_start_rx(struct ath5k_hw *ah); +extern int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah); +extern u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah); +extern void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr); +extern int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue); +extern int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue); +extern u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue); +extern int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr); +extern int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase); +/* Interrupt handling */ +extern bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah); +extern int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask); +extern enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask); +/* EEPROM access functions */ +extern int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain); +/* Protocol Control Unit Functions */ +extern int ath5k_hw_set_opmode(struct ath5k_hw *ah); +/* BSSID Functions */ +extern void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac); +extern int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac); +extern void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id); +extern int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask); +/* Receive start/stop functions */ +extern void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah); +extern void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah); +/* RX Filter functions */ +extern void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1); +extern int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index); +extern int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index); +extern u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah); +extern void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter); +/* Beacon related functions */ +extern u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah); +extern u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah); +extern void ath5k_hw_reset_tsf(struct ath5k_hw *ah); +extern void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval); +#if 0 +extern int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, const struct ath5k_beacon_state *state); +extern void ath5k_hw_reset_beacon(struct ath5k_hw *ah); +extern int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr); +#endif +extern void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, struct ath5k_mib_stats *statistics); +/* ACK bit rate */ +void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high); +/* ACK/CTS Timeouts */ +extern int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout); +extern unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah); +extern int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout); +extern unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah); +/* Key table (WEP) functions */ +extern int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry); +extern int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry); +extern int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac); +extern int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac); +/* Queue Control Unit, DFS Control Unit Functions */ +extern int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, struct ath5k_txq_info *queue_info); +extern int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, const struct ath5k_txq_info *queue_info); +extern int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, struct ath5k_txq_info *queue_info); +extern void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue); +extern int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue); +extern u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue); +extern int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time); +extern unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah); +/* Hardware Descriptor Functions */ +extern int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u32 size, unsigned int flags); +/* GPIO Functions */ +extern void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state); +extern int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio); +extern int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio); +extern u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio); +extern int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val); +extern void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, u32 interrupt_level); +/* Regulatory Domain/Channels Setup */ +extern u16 ath5k_get_regdomain(struct ath5k_hw *ah); +/* Misc functions */ +extern int ath5k_hw_get_capability(struct ath5k_hw *ah, enum ath5k_capability_type cap_type, u32 capability, u32 *result); + + +/* Initial register settings functions */ +extern int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); +/* Initialize RF */ +extern int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int mode); +extern int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq); +extern enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah); +extern int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah); + + +/* PHY/RF channel functions */ +extern bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); +extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel); +/* PHY calibration */ +extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); +extern int ath5k_hw_phy_disable(struct ath5k_hw *ah); +/* Misc PHY functions */ +extern u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); +extern void ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant); +extern unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah); +extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); +/* TX power setup */ +extern int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, unsigned int txpower); +extern int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power); + + +static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg) +{ + return ioread32(ah->ah_iobase + reg); +} + +static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg) +{ + iowrite32(val, ah->ah_iobase + reg); +} + +#endif diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c new file mode 100644 index 000000000000..72bcf321d1ce --- /dev/null +++ b/drivers/net/wireless/ath5k/base.c @@ -0,0 +1,2974 @@ +/*- + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2006 Devicescape Software, Inc. + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/if.h> +#include <linux/netdevice.h> +#include <linux/cache.h> +#include <linux/pci.h> +#include <linux/ethtool.h> +#include <linux/uaccess.h> + +#include <net/ieee80211_radiotap.h> + +#include <asm/unaligned.h> + +#include "base.h" +#include "reg.h" +#include "debug.h" + +/* unaligned little endian access */ +#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) +#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) + +enum { + ATH_LED_TX, + ATH_LED_RX, +}; + +static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ + + +/******************\ +* Internal defines * +\******************/ + +/* Module info */ +MODULE_AUTHOR("Jiri Slaby"); +MODULE_AUTHOR("Nick Kossifidis"); +MODULE_DESCRIPTION("Support for 5xxx series of Atheros 802.11 wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION("0.1.1 (EXPERIMENTAL)"); + + +/* Known PCI ids */ +static struct pci_device_id ath5k_pci_id_table[] __devinitdata = { + { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */ + { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */ + { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/ + { PCI_VDEVICE(ATHEROS, 0x0012), .driver_data = AR5K_AR5211 }, /* 5211 */ + { PCI_VDEVICE(ATHEROS, 0x0013), .driver_data = AR5K_AR5212 }, /* 5212 */ + { PCI_VDEVICE(3COM_2, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 5212 */ + { PCI_VDEVICE(3COM, 0x0013), .driver_data = AR5K_AR5212 }, /* 3com 3CRDAG675 5212 */ + { PCI_VDEVICE(ATHEROS, 0x1014), .driver_data = AR5K_AR5212 }, /* IBM minipci 5212 */ + { PCI_VDEVICE(ATHEROS, 0x0014), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0015), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0016), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0017), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0018), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x0019), .driver_data = AR5K_AR5212 }, /* 5212 combatible */ + { PCI_VDEVICE(ATHEROS, 0x001a), .driver_data = AR5K_AR5212 }, /* 2413 Griffin-lite */ + { PCI_VDEVICE(ATHEROS, 0x001b), .driver_data = AR5K_AR5212 }, /* 5413 Eagle */ + { PCI_VDEVICE(ATHEROS, 0x001c), .driver_data = AR5K_AR5212 }, /* 5424 Condor (PCI-E)*/ + { PCI_VDEVICE(ATHEROS, 0x0023), .driver_data = AR5K_AR5212 }, /* 5416 */ + { PCI_VDEVICE(ATHEROS, 0x0024), .driver_data = AR5K_AR5212 }, /* 5418 */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table); + +/* Known SREVs */ +static struct ath5k_srev_name srev_names[] = { + { "5210", AR5K_VERSION_VER, AR5K_SREV_VER_AR5210 }, + { "5311", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311 }, + { "5311A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311A }, + { "5311B", AR5K_VERSION_VER, AR5K_SREV_VER_AR5311B }, + { "5211", AR5K_VERSION_VER, AR5K_SREV_VER_AR5211 }, + { "5212", AR5K_VERSION_VER, AR5K_SREV_VER_AR5212 }, + { "5213", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213 }, + { "5213A", AR5K_VERSION_VER, AR5K_SREV_VER_AR5213A }, + { "2424", AR5K_VERSION_VER, AR5K_SREV_VER_AR2424 }, + { "5424", AR5K_VERSION_VER, AR5K_SREV_VER_AR5424 }, + { "5413", AR5K_VERSION_VER, AR5K_SREV_VER_AR5413 }, + { "5414", AR5K_VERSION_VER, AR5K_SREV_VER_AR5414 }, + { "5416", AR5K_VERSION_VER, AR5K_SREV_VER_AR5416 }, + { "5418", AR5K_VERSION_VER, AR5K_SREV_VER_AR5418 }, + { "xxxxx", AR5K_VERSION_VER, AR5K_SREV_UNKNOWN }, + { "5110", AR5K_VERSION_RAD, AR5K_SREV_RAD_5110 }, + { "5111", AR5K_VERSION_RAD, AR5K_SREV_RAD_5111 }, + { "2111", AR5K_VERSION_RAD, AR5K_SREV_RAD_2111 }, + { "5112", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112 }, + { "5112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_5112A }, + { "2112", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112 }, + { "2112A", AR5K_VERSION_RAD, AR5K_SREV_RAD_2112A }, + { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC1 }, + { "SChip", AR5K_VERSION_RAD, AR5K_SREV_RAD_SC2 }, + { "5133", AR5K_VERSION_RAD, AR5K_SREV_RAD_5133 }, + { "xxxxx", AR5K_VERSION_RAD, AR5K_SREV_UNKNOWN }, +}; + +/* + * Prototypes - PCI stack related functions + */ +static int __devinit ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id); +static void __devexit ath5k_pci_remove(struct pci_dev *pdev); +#ifdef CONFIG_PM +static int ath5k_pci_suspend(struct pci_dev *pdev, + pm_message_t state); +static int ath5k_pci_resume(struct pci_dev *pdev); +#else +#define ath5k_pci_suspend NULL +#define ath5k_pci_resume NULL +#endif /* CONFIG_PM */ + +static struct pci_driver ath5k_pci_drv_id = { + .name = "ath5k_pci", + .id_table = ath5k_pci_id_table, + .probe = ath5k_pci_probe, + .remove = __devexit_p(ath5k_pci_remove), + .suspend = ath5k_pci_suspend, + .resume = ath5k_pci_resume, +}; + + + +/* + * Prototypes - MAC 802.11 stack related functions + */ +static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl); +static int ath5k_reset(struct ieee80211_hw *hw); +static int ath5k_start(struct ieee80211_hw *hw); +static void ath5k_stop(struct ieee80211_hw *hw); +static int ath5k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +static void ath5k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf); +static int ath5k_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf); +static void ath5k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist); +static int ath5k_set_key(struct ieee80211_hw *hw, + enum set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key); +static int ath5k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats); +static int ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats); +static u64 ath5k_get_tsf(struct ieee80211_hw *hw); +static void ath5k_reset_tsf(struct ieee80211_hw *hw); +static int ath5k_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl); + +static struct ieee80211_ops ath5k_hw_ops = { + .tx = ath5k_tx, + .start = ath5k_start, + .stop = ath5k_stop, + .add_interface = ath5k_add_interface, + .remove_interface = ath5k_remove_interface, + .config = ath5k_config, + .config_interface = ath5k_config_interface, + .configure_filter = ath5k_configure_filter, + .set_key = ath5k_set_key, + .get_stats = ath5k_get_stats, + .conf_tx = NULL, + .get_tx_stats = ath5k_get_tx_stats, + .get_tsf = ath5k_get_tsf, + .reset_tsf = ath5k_reset_tsf, + .beacon_update = ath5k_beacon_update, +}; + +/* + * Prototypes - Internal functions + */ +/* Attach detach */ +static int ath5k_attach(struct pci_dev *pdev, + struct ieee80211_hw *hw); +static void ath5k_detach(struct pci_dev *pdev, + struct ieee80211_hw *hw); +/* Channel/mode setup */ +static inline short ath5k_ieee2mhz(short chan); +static unsigned int ath5k_copy_rates(struct ieee80211_rate *rates, + const struct ath5k_rate_table *rt, + unsigned int max); +static unsigned int ath5k_copy_channels(struct ath5k_hw *ah, + struct ieee80211_channel *channels, + unsigned int mode, + unsigned int max); +static int ath5k_getchannels(struct ieee80211_hw *hw); +static int ath5k_chan_set(struct ath5k_softc *sc, + struct ieee80211_channel *chan); +static void ath5k_setcurmode(struct ath5k_softc *sc, + unsigned int mode); +static void ath5k_mode_setup(struct ath5k_softc *sc); +/* Descriptor setup */ +static int ath5k_desc_alloc(struct ath5k_softc *sc, + struct pci_dev *pdev); +static void ath5k_desc_free(struct ath5k_softc *sc, + struct pci_dev *pdev); +/* Buffers setup */ +static int ath5k_rxbuf_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf); +static int ath5k_txbuf_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl); + +static inline void ath5k_txbuf_free(struct ath5k_softc *sc, + struct ath5k_buf *bf) +{ + BUG_ON(!bf); + if (!bf->skb) + return; + pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(bf->skb); + bf->skb = NULL; +} + +/* Queues setup */ +static struct ath5k_txq *ath5k_txq_setup(struct ath5k_softc *sc, + int qtype, int subtype); +static int ath5k_beaconq_setup(struct ath5k_hw *ah); +static int ath5k_beaconq_config(struct ath5k_softc *sc); +static void ath5k_txq_drainq(struct ath5k_softc *sc, + struct ath5k_txq *txq); +static void ath5k_txq_cleanup(struct ath5k_softc *sc); +static void ath5k_txq_release(struct ath5k_softc *sc); +/* Rx handling */ +static int ath5k_rx_start(struct ath5k_softc *sc); +static void ath5k_rx_stop(struct ath5k_softc *sc); +static unsigned int ath5k_rx_decrypted(struct ath5k_softc *sc, + struct ath5k_desc *ds, + struct sk_buff *skb); +static void ath5k_tasklet_rx(unsigned long data); +/* Tx handling */ +static void ath5k_tx_processq(struct ath5k_softc *sc, + struct ath5k_txq *txq); +static void ath5k_tasklet_tx(unsigned long data); +/* Beacon handling */ +static int ath5k_beacon_setup(struct ath5k_softc *sc, + struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl); +static void ath5k_beacon_send(struct ath5k_softc *sc); +static void ath5k_beacon_config(struct ath5k_softc *sc); +static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf); + +static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp) +{ + u64 tsf = ath5k_hw_get_tsf64(ah); + + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + + return (tsf & ~0x7fff) | rstamp; +} + +/* Interrupt handling */ +static int ath5k_init(struct ath5k_softc *sc); +static int ath5k_stop_locked(struct ath5k_softc *sc); +static int ath5k_stop_hw(struct ath5k_softc *sc); +static irqreturn_t ath5k_intr(int irq, void *dev_id); +static void ath5k_tasklet_reset(unsigned long data); + +static void ath5k_calibrate(unsigned long data); +/* LED functions */ +static void ath5k_led_off(unsigned long data); +static void ath5k_led_blink(struct ath5k_softc *sc, + unsigned int on, + unsigned int off); +static void ath5k_led_event(struct ath5k_softc *sc, + int event); + + +/* + * Module init/exit functions + */ +static int __init +init_ath5k_pci(void) +{ + int ret; + + ath5k_debug_init(); + + ret = pci_register_driver(&ath5k_pci_drv_id); + if (ret) { + printk(KERN_ERR "ath5k_pci: can't register pci driver\n"); + return ret; + } + + return 0; +} + +static void __exit +exit_ath5k_pci(void) +{ + pci_unregister_driver(&ath5k_pci_drv_id); + + ath5k_debug_finish(); +} + +module_init(init_ath5k_pci); +module_exit(exit_ath5k_pci); + + +/********************\ +* PCI Initialization * +\********************/ + +static const char * +ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) +{ + const char *name = "xxxxx"; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(srev_names); i++) { + if (srev_names[i].sr_type != type) + continue; + if ((val & 0xff) < srev_names[i + 1].sr_val) { + name = srev_names[i].sr_name; + break; + } + } + + return name; +} + +static int __devinit +ath5k_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *mem; + struct ath5k_softc *sc; + struct ieee80211_hw *hw; + int ret; + u8 csz; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "can't enable device\n"); + goto err; + } + + /* XXX 32-bit addressing only */ + ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (ret) { + dev_err(&pdev->dev, "32-bit DMA not available\n"); + goto err_dis; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES / sizeof(u32); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + /* Enable bus mastering */ + pci_set_master(pdev); + + /* + * Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state. + */ + pci_write_config_byte(pdev, 0x41, 0); + + ret = pci_request_region(pdev, 0, "ath5k"); + if (ret) { + dev_err(&pdev->dev, "cannot reserve PCI memory region\n"); + goto err_dis; + } + + mem = pci_iomap(pdev, 0, 0); + if (!mem) { + dev_err(&pdev->dev, "cannot remap PCI memory region\n") ; + ret = -EIO; + goto err_reg; + } + + /* + * Allocate hw (mac80211 main struct) + * and hw->priv (driver private data) + */ + hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops); + if (hw == NULL) { + dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n"); + ret = -ENOMEM; + goto err_map; + } + + dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy)); + + /* Initialize driver private data */ + SET_IEEE80211_DEV(hw, &pdev->dev); + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; + hw->extra_tx_headroom = 2; + hw->channel_change_time = 5000; + /* these names are misleading */ + hw->max_rssi = -110; /* signal in dBm */ + hw->max_noise = -110; /* noise in dBm */ + hw->max_signal = 100; /* we will provide a percentage based on rssi */ + sc = hw->priv; + sc->hw = hw; + sc->pdev = pdev; + + ath5k_debug_init_device(sc); + + /* + * Mark the device as detached to avoid processing + * interrupts until setup is complete. + */ + __set_bit(ATH_STAT_INVALID, sc->status); + + sc->iobase = mem; /* So we can unmap it on detach */ + sc->cachelsz = csz * sizeof(u32); /* convert to bytes */ + sc->opmode = IEEE80211_IF_TYPE_STA; + mutex_init(&sc->lock); + spin_lock_init(&sc->rxbuflock); + spin_lock_init(&sc->txbuflock); + + /* 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) { + ATH5K_ERR(sc, "request_irq failed\n"); + goto err_free; + } + + /* Initialize device */ + sc->ah = ath5k_hw_attach(sc, id->driver_data); + if (IS_ERR(sc->ah)) { + ret = PTR_ERR(sc->ah); + goto err_irq; + } + + /* Finish private driver data initialization */ + ret = ath5k_attach(pdev, hw); + if (ret) + goto err_ah; + + ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n", + ath5k_chip_name(AR5K_VERSION_VER,sc->ah->ah_mac_srev), + sc->ah->ah_mac_srev, + sc->ah->ah_phy_revision); + + if(!sc->ah->ah_single_chip){ + /* Single chip radio (!RF5111) */ + if(sc->ah->ah_radio_5ghz_revision && !sc->ah->ah_radio_2ghz_revision) { + /* No 5GHz support -> report 2GHz radio */ + if(!test_bit(MODE_IEEE80211A, sc->ah->ah_capabilities.cap_mode)){ + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* No 2GHz support (5110 and some 5Ghz only cards) -> report 5Ghz radio */ + } else if(!test_bit(MODE_IEEE80211B, sc->ah->ah_capabilities.cap_mode)){ + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + /* Multiband radio */ + } else { + ATH5K_INFO(sc, "RF%s multiband radio found" + " (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + } + } + /* Multi chip radio (RF5111 - RF2111) -> report both 2GHz/5GHz radios */ + else if(sc->ah->ah_radio_5ghz_revision && sc->ah->ah_radio_2ghz_revision){ + ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_5ghz_revision), + sc->ah->ah_radio_5ghz_revision); + ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n", + ath5k_chip_name(AR5K_VERSION_RAD,sc->ah->ah_radio_2ghz_revision), + sc->ah->ah_radio_2ghz_revision); + } + } + + + /* ready to process interrupts */ + __clear_bit(ATH_STAT_INVALID, sc->status); + + return 0; +err_ah: + ath5k_hw_detach(sc->ah); +err_irq: + free_irq(pdev->irq, sc); +err_free: + pci_disable_msi(pdev); + ieee80211_free_hw(hw); +err_map: + pci_iounmap(pdev, mem); +err_reg: + pci_release_region(pdev, 0); +err_dis: + pci_disable_device(pdev); +err: + return ret; +} + +static void __devexit +ath5k_pci_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + + ath5k_debug_finish_device(sc); + 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); + ieee80211_free_hw(hw); +} + +#ifdef CONFIG_PM +static int +ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + + if (test_bit(ATH_STAT_LEDSOFT, sc->status)) + ath5k_hw_set_gpio(sc->ah, sc->led_pin, 1); + + ath5k_stop_hw(sc); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; +} + +static int +ath5k_pci_resume(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + int i, err; + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + 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 + * PCI Tx retries from interfering with C3 CPU state + */ + pci_write_config_byte(pdev, 0x41, 0); + + ath5k_init(sc); + if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { + ath5k_hw_set_gpio_output(ah, sc->led_pin); + ath5k_hw_set_gpio(ah, sc->led_pin, 0); + } + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up or resume. + * + * FIXME: This may need to be revisited when mac80211 becomes + * aware of suspend/resume. + */ + for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) + ath5k_hw_reset_key(ah, i); + + return 0; +} +#endif /* CONFIG_PM */ + + + +/***********************\ +* Driver Initialization * +\***********************/ + +static int +ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + u8 mac[ETH_ALEN]; + unsigned int i; + int ret; + + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); + + /* + * Check if the MAC has multi-rate retry support. + * We do this by trying to setup a fake extended + * descriptor. MAC's that don't have support will + * return false w/o doing anything. MAC's that do + * support it will return true w/o doing anything. + */ + if (ah->ah_setup_xtx_desc(ah, NULL, 0, 0, 0, 0, 0, 0)) + __set_bit(ATH_STAT_MRRETRY, sc->status); + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < AR5K_KEYTABLE_SIZE; i++) + ath5k_hw_reset_key(ah, i); + + /* + * Collect the channel list. The 802.11 layer + * is resposible for filtering this list based + * on settings like the phy mode and regulatory + * domain restrictions. + */ + ret = ath5k_getchannels(hw); + if (ret) { + ATH5K_ERR(sc, "can't get channels\n"); + goto err; + } + + /* NB: setup here so ath5k_rate_update is happy */ + if (test_bit(MODE_IEEE80211A, ah->ah_modes)) + ath5k_setcurmode(sc, MODE_IEEE80211A); + else + ath5k_setcurmode(sc, MODE_IEEE80211B); + + /* + * Allocate tx+rx descriptors and populate the lists. + */ + ret = ath5k_desc_alloc(sc, pdev); + if (ret) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + goto err; + } + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that hw functions handle reseting + * these queues at the needed time. + */ + ret = ath5k_beaconq_setup(ah); + if (ret < 0) { + ATH5K_ERR(sc, "can't setup a beacon xmit queue\n"); + goto err_desc; + } + sc->bhalq = ret; + + sc->txq = ath5k_txq_setup(sc, AR5K_TX_QUEUE_DATA, AR5K_WME_AC_BK); + if (IS_ERR(sc->txq)) { + ATH5K_ERR(sc, "can't setup xmit queue\n"); + ret = PTR_ERR(sc->txq); + goto err_bhal; + } + + tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); + tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); + tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); + setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); + setup_timer(&sc->led_tim, ath5k_led_off, (unsigned long)sc); + + sc->led_on = 0; /* low true */ + /* + * Auto-enable soft led processing for IBM cards and for + * 5211 minipci cards. + */ + if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM || + pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) { + __set_bit(ATH_STAT_LEDSOFT, sc->status); + sc->led_pin = 0; + } + /* 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 = 0; + } + if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { + ath5k_hw_set_gpio_output(ah, sc->led_pin); + ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); + } + + ath5k_hw_get_lladdr(ah, mac); + SET_IEEE80211_PERM_ADDR(hw, mac); + /* All MAC address bits matter for ACKs */ + memset(sc->bssidmask, 0xff, ETH_ALEN); + ath5k_hw_set_bssid_mask(sc->ah, sc->bssidmask); + + ret = ieee80211_register_hw(hw); + if (ret) { + ATH5K_ERR(sc, "can't register ieee80211 hw\n"); + goto err_queues; + } + + return 0; +err_queues: + ath5k_txq_release(sc); +err_bhal: + ath5k_hw_release_tx_queue(ah, sc->bhalq); +err_desc: + ath5k_desc_free(sc, pdev); +err: + return ret; +} + +static void +ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * NB: the order of these is important: + * o call the 802.11 layer before detaching ath5k_hw to + * insure callbacks into the driver to delete global + * key cache entries can be handled + * o reclaim the tx queue data structures after calling + * the 802.11 layer as we'll get called back to reclaim + * node state and potentially want to use them + * o to cleanup the tx queues the hal is called, so detach + * it last + * XXX: ??? detach ath5k_hw ??? + * Other than that, it's straightforward... + */ + ieee80211_unregister_hw(hw); + ath5k_desc_free(sc, pdev); + ath5k_txq_release(sc); + ath5k_hw_release_tx_queue(sc->ah, sc->bhalq); + + /* + * NB: can't reclaim these until after ieee80211_ifdetach + * returns because we'll get called back to reclaim node + * state and potentially want to use them. + */ +} + + + + +/********************\ +* Channel/mode setup * +\********************/ + +/* + * Convert IEEE channel number to MHz frequency. + */ +static inline short +ath5k_ieee2mhz(short chan) +{ + if (chan <= 14 || chan >= 27) + return ieee80211chan2mhz(chan); + else + return 2212 + chan * 20; +} + +static unsigned int +ath5k_copy_rates(struct ieee80211_rate *rates, + const struct ath5k_rate_table *rt, + unsigned int max) +{ + unsigned int i, count; + + if (rt == NULL) + return 0; + + for (i = 0, count = 0; i < rt->rate_count && max > 0; i++) { + if (!rt->rates[i].valid) + continue; + rates->rate = rt->rates[i].rate_kbps / 100; + rates->val = rt->rates[i].rate_code; + rates->flags = rt->rates[i].modulation; + rates++; + count++; + max--; + } + + return count; +} + +static unsigned int +ath5k_copy_channels(struct ath5k_hw *ah, + struct ieee80211_channel *channels, + unsigned int mode, + unsigned int max) +{ + static const struct { unsigned int mode, mask, chan; } map[] = { + [MODE_IEEE80211A] = { CHANNEL_OFDM, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_A }, + [MODE_ATHEROS_TURBO] = { CHANNEL_OFDM|CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_T }, + [MODE_IEEE80211B] = { CHANNEL_CCK, CHANNEL_CCK, CHANNEL_B }, + [MODE_IEEE80211G] = { CHANNEL_OFDM, CHANNEL_OFDM, CHANNEL_G }, + [MODE_ATHEROS_TURBOG] = { CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_OFDM | CHANNEL_TURBO, CHANNEL_TG }, + }; + static const struct ath5k_regchannel chans_2ghz[] = + IEEE80211_CHANNELS_2GHZ; + static const struct ath5k_regchannel chans_5ghz[] = + IEEE80211_CHANNELS_5GHZ; + const struct ath5k_regchannel *chans; + enum ath5k_regdom dmn; + unsigned int i, count, size, chfreq, all, f, ch; + + if (!test_bit(mode, ah->ah_modes)) + return 0; + + all = ah->ah_regdomain == DMN_DEFAULT || CHAN_DEBUG == 1; + + switch (mode) { + case MODE_IEEE80211A: + case MODE_ATHEROS_TURBO: + /* 1..220, but 2GHz frequencies are filtered by check_channel */ + size = all ? 220 : ARRAY_SIZE(chans_5ghz); + chans = chans_5ghz; + dmn = ath5k_regdom2flag(ah->ah_regdomain, + IEEE80211_CHANNELS_5GHZ_MIN); + chfreq = CHANNEL_5GHZ; + break; + case MODE_IEEE80211B: + case MODE_IEEE80211G: + case MODE_ATHEROS_TURBOG: + size = all ? 26 : ARRAY_SIZE(chans_2ghz); + chans = chans_2ghz; + dmn = ath5k_regdom2flag(ah->ah_regdomain, + IEEE80211_CHANNELS_2GHZ_MIN); + chfreq = CHANNEL_2GHZ; + break; + default: + ATH5K_WARN(ah->ah_sc, "bad mode, not copying channels\n"); + return 0; + } + + for (i = 0, count = 0; i < size && max > 0; i++) { + ch = all ? i + 1 : chans[i].chan; + f = ath5k_ieee2mhz(ch); + /* Check if channel is supported by the chipset */ + if (!ath5k_channel_ok(ah, f, chfreq)) + continue; + + /* Match regulation domain */ + if (!all && !(IEEE80211_DMN(chans[i].domain) & + IEEE80211_DMN(dmn))) + continue; + + if (!all && (chans[i].mode & map[mode].mask) != map[mode].mode) + continue; + + /* Write channel and increment counter */ + channels->chan = ch; + channels->freq = f; + channels->val = map[mode].chan; + channels++; + count++; + max--; + } + + return count; +} + +/* Only tries to register modes our EEPROM says it can support */ +#define REGISTER_MODE(m) do { \ + ret = ath5k_register_mode(hw, m); \ + if (ret) \ + return ret; \ +} while (0) \ + +static inline int +ath5k_register_mode(struct ieee80211_hw *hw, u8 m) +{ + struct ath5k_softc *sc = hw->priv; + struct ieee80211_hw_mode *modes = sc->modes; + unsigned int i; + int ret; + + if (!test_bit(m, sc->ah->ah_capabilities.cap_mode)) + return 0; + + for (i = 0; i < NUM_DRIVER_MODES; i++) { + if (modes[i].mode != m || !modes[i].num_channels) + continue; + ret = ieee80211_register_hwmode(hw, &modes[i]); + if (ret) { + ATH5K_ERR(sc, "can't register hwmode %u\n", m); + return ret; + } + return 0; + } + BUG(); +} + +static int +ath5k_getchannels(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + struct ieee80211_hw_mode *modes = sc->modes; + unsigned int i, max_r, max_c; + int ret; + + BUILD_BUG_ON(ARRAY_SIZE(sc->modes) < 3); + + /* The order here does not matter */ + modes[0].mode = MODE_IEEE80211G; + modes[1].mode = MODE_IEEE80211B; + modes[2].mode = MODE_IEEE80211A; + + max_r = ARRAY_SIZE(sc->rates); + max_c = ARRAY_SIZE(sc->channels); + + for (i = 0; i < NUM_DRIVER_MODES; i++) { + struct ieee80211_hw_mode *mode = &modes[i]; + const struct ath5k_rate_table *hw_rates; + + if (i == 0) { + modes[0].rates = sc->rates; + modes->channels = sc->channels; + } else { + struct ieee80211_hw_mode *prev_mode = &modes[i-1]; + int prev_num_r = prev_mode->num_rates; + int prev_num_c = prev_mode->num_channels; + mode->rates = &prev_mode->rates[prev_num_r]; + mode->channels = &prev_mode->channels[prev_num_c]; + } + + hw_rates = ath5k_hw_get_rate_table(ah, mode->mode); + mode->num_rates = ath5k_copy_rates(mode->rates, hw_rates, + max_r); + mode->num_channels = ath5k_copy_channels(ah, mode->channels, + mode->mode, max_c); + max_r -= mode->num_rates; + max_c -= mode->num_channels; + } + + /* We try to register all modes this driver supports. We don't bother + * with MODE_IEEE80211B for AR5212 as MODE_IEEE80211G already accounts + * for that as per mac80211. Then, REGISTER_MODE() will will actually + * check the eeprom reading for more reliable capability information. + * Order matters here as per mac80211's latest preference. This will + * all hopefullly soon go away. */ + + REGISTER_MODE(MODE_IEEE80211G); + if (ah->ah_version != AR5K_AR5212) + REGISTER_MODE(MODE_IEEE80211B); + REGISTER_MODE(MODE_IEEE80211A); + + ath5k_debug_dump_modes(sc, modes); + + return ret; +} + +/* + * Set/change channels. If the channel is really being changed, + * it's done by reseting the chip. To accomplish this we must + * first cleanup any pending DMA, then restart stuff after a la + * ath5k_init. + */ +static int +ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan) +{ + struct ath5k_hw *ah = sc->ah; + int ret; + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "%u (%u MHz) -> %u (%u MHz)\n", + sc->curchan->chan, sc->curchan->freq, + chan->chan, chan->freq); + + if (chan->freq != sc->curchan->freq || chan->val != sc->curchan->val) { + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath5k_hw_set_intr(ah, 0); /* disable interrupts */ + ath5k_txq_cleanup(sc); /* clear pending tx frames */ + ath5k_rx_stop(sc); /* turn off frame recv */ + ret = ath5k_hw_reset(ah, sc->opmode, chan, true); + if (ret) { + ATH5K_ERR(sc, "%s: unable to reset channel %u " + "(%u Mhz)\n", __func__, chan->chan, chan->freq); + return ret; + } + sc->curchan = chan; + ath5k_hw_set_txpower_limit(sc->ah, 0); + + /* + * Re-enable rx framework. + */ + ret = ath5k_rx_start(sc); + if (ret) { + ATH5K_ERR(sc, "%s: unable to restart recv logic\n", + __func__); + return ret; + } + + /* + * Change channels and update the h/w rate map + * if we're switching; e.g. 11a to 11b/g. + * + * XXX needed? + */ +/* ath5k_chan_change(sc, chan); */ + + ath5k_beacon_config(sc); + /* + * Re-enable interrupts. + */ + ath5k_hw_set_intr(ah, sc->imask); + } + + return 0; +} + +static void +ath5k_setcurmode(struct ath5k_softc *sc, unsigned int mode) +{ + if (unlikely(test_bit(ATH_STAT_LEDSOFT, sc->status))) { + /* from Atheros NDIS driver, w/ permission */ + static const struct { + u16 rate; /* tx/rx 802.11 rate */ + u16 timeOn; /* LED on time (ms) */ + u16 timeOff; /* LED off time (ms) */ + } blinkrates[] = { + { 108, 40, 10 }, + { 96, 44, 11 }, + { 72, 50, 13 }, + { 48, 57, 14 }, + { 36, 67, 16 }, + { 24, 80, 20 }, + { 22, 100, 25 }, + { 18, 133, 34 }, + { 12, 160, 40 }, + { 10, 200, 50 }, + { 6, 240, 58 }, + { 4, 267, 66 }, + { 2, 400, 100 }, + { 0, 500, 130 } + }; + const struct ath5k_rate_table *rt = + ath5k_hw_get_rate_table(sc->ah, mode); + unsigned int i, j; + + BUG_ON(rt == NULL); + + memset(sc->hwmap, 0, sizeof(sc->hwmap)); + for (i = 0; i < 32; i++) { + u8 ix = rt->rate_code_to_index[i]; + if (ix == 0xff) { + sc->hwmap[i].ledon = msecs_to_jiffies(500); + sc->hwmap[i].ledoff = msecs_to_jiffies(130); + continue; + } + sc->hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD; + if (SHPREAMBLE_FLAG(ix) || rt->rates[ix].modulation == + IEEE80211_RATE_OFDM) + sc->hwmap[i].txflags |= + IEEE80211_RADIOTAP_F_SHORTPRE; + /* receive frames include FCS */ + sc->hwmap[i].rxflags = sc->hwmap[i].txflags | + IEEE80211_RADIOTAP_F_FCS; + /* setup blink rate table to avoid per-packet lookup */ + for (j = 0; j < ARRAY_SIZE(blinkrates) - 1; j++) + if (blinkrates[j].rate == /* XXX why 7f? */ + (rt->rates[ix].dot11_rate&0x7f)) + break; + + sc->hwmap[i].ledon = msecs_to_jiffies(blinkrates[j]. + timeOn); + sc->hwmap[i].ledoff = msecs_to_jiffies(blinkrates[j]. + timeOff); + } + } + + sc->curmode = mode; +} + +static void +ath5k_mode_setup(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + u32 rfilt; + + /* configure rx filter */ + rfilt = sc->filter_flags; + ath5k_hw_set_rx_filter(ah, rfilt); + + if (ath5k_hw_hasbssidmask(ah)) + ath5k_hw_set_bssid_mask(ah, sc->bssidmask); + + /* configure operational mode */ + ath5k_hw_set_opmode(ah); + + ath5k_hw_set_mcast_filter(ah, 0, 0); + ATH5K_DBG(sc, ATH5K_DEBUG_MODE, "RX filter 0x%x\n", rfilt); +} + + + + +/***************\ +* Buffers setup * +\***************/ + +static int +ath5k_rxbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) +{ + struct ath5k_hw *ah = sc->ah; + struct sk_buff *skb = bf->skb; + struct ath5k_desc *ds; + + if (likely(skb == NULL)) { + unsigned int off; + + /* + * Allocate buffer with headroom_needed space for the + * fake physical layer header at the start. + */ + skb = dev_alloc_skb(sc->rxbufsize + sc->cachelsz - 1); + if (unlikely(skb == NULL)) { + ATH5K_ERR(sc, "can't alloc skbuff of size %u\n", + sc->rxbufsize + sc->cachelsz - 1); + return -ENOMEM; + } + /* + * Cache-line-align. This is important (for the + * 5210 at least) as not doing so causes bogus data + * in rx'd frames. + */ + off = ((unsigned long)skb->data) % sc->cachelsz; + if (off != 0) + skb_reserve(skb, sc->cachelsz - off); + + bf->skb = skb; + bf->skbaddr = pci_map_single(sc->pdev, + skb->data, sc->rxbufsize, PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(bf->skbaddr))) { + ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__); + dev_kfree_skb(skb); + bf->skb = NULL; + return -ENOMEM; + } + } + + /* + * Setup descriptors. For receive we always terminate + * the descriptor list with a self-linked entry so we'll + * not get overrun under high load (as can happen with a + * 5212 when ANI processing enables PHY error frames). + * + * To insure the last descriptor is self-linked we create + * each descriptor as self-linked and add it to the end. As + * each additional descriptor is added the previous self-linked + * entry is ``fixed'' naturally. This should be safe even + * if DMA is happening. When processing RX interrupts we + * never remove/process the last, self-linked, entry on the + * descriptor list. This insures the hardware always has + * someplace to write a new frame. + */ + ds = bf->desc; + ds->ds_link = bf->daddr; /* link to self */ + ds->ds_data = bf->skbaddr; + ath5k_hw_setup_rx_desc(ah, ds, + skb_tailroom(skb), /* buffer size */ + 0); + + if (sc->rxlink != NULL) + *sc->rxlink = bf->daddr; + sc->rxlink = &ds->ds_link; + return 0; +} + +static int +ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq *txq = sc->txq; + struct ath5k_desc *ds = bf->desc; + struct sk_buff *skb = bf->skb; + unsigned int pktlen, flags, keyidx = AR5K_TXKEYIX_INVALID; + int ret; + + flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK; + bf->ctl = *ctl; + /* XXX endianness */ + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + + if (ctl->flags & IEEE80211_TXCTL_NO_ACK) + flags |= AR5K_TXDESC_NOACK; + + pktlen = skb->len + FCS_LEN; + + if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { + keyidx = ctl->key_idx; + pktlen += ctl->icv_len; + } + + ret = ah->ah_setup_tx_desc(ah, ds, pktlen, + ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, + (ctl->power_level * 2), ctl->tx_rate, ctl->retry_limit, keyidx, 0, flags, 0, 0); + if (ret) + goto err_unmap; + + ds->ds_link = 0; + ds->ds_data = bf->skbaddr; + + spin_lock_bh(&txq->lock); + list_add_tail(&bf->list, &txq->q); + sc->tx_stats.data[txq->qnum].len++; + if (txq->link == NULL) /* is this first packet? */ + ath5k_hw_put_tx_buf(ah, txq->qnum, bf->daddr); + else /* no, so only link it */ + *txq->link = bf->daddr; + + txq->link = &ds->ds_link; + ath5k_hw_tx_start(ah, txq->qnum); + spin_unlock_bh(&txq->lock); + + return 0; +err_unmap: + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); + return ret; +} + +/*******************\ +* Descriptors setup * +\*******************/ + +static int +ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev) +{ + struct ath5k_desc *ds; + struct ath5k_buf *bf; + dma_addr_t da; + unsigned int i; + int ret; + + /* allocate descriptors */ + sc->desc_len = sizeof(struct ath5k_desc) * + (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1); + sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr); + if (sc->desc == NULL) { + ATH5K_ERR(sc, "can't allocate descriptors\n"); + ret = -ENOMEM; + goto err; + } + ds = sc->desc; + da = sc->desc_daddr; + ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "DMA map: %p (%zu) -> %llx\n", + ds, sc->desc_len, (unsigned long long)sc->desc_daddr); + + bf = kcalloc(1 + ATH_TXBUF + ATH_RXBUF + ATH_BCBUF, + sizeof(struct ath5k_buf), GFP_KERNEL); + if (bf == NULL) { + ATH5K_ERR(sc, "can't allocate bufptr\n"); + ret = -ENOMEM; + goto err_free; + } + sc->bufptr = bf; + + INIT_LIST_HEAD(&sc->rxbuf); + for (i = 0; i < ATH_RXBUF; i++, bf++, ds++, da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->rxbuf); + } + + INIT_LIST_HEAD(&sc->txbuf); + sc->txbuf_len = ATH_TXBUF; + for (i = 0; i < ATH_TXBUF; i++, bf++, ds++, + da += sizeof(*ds)) { + bf->desc = ds; + bf->daddr = da; + list_add_tail(&bf->list, &sc->txbuf); + } + + /* beacon buffer */ + bf->desc = ds; + bf->daddr = da; + sc->bbuf = bf; + + return 0; +err_free: + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); +err: + sc->desc = NULL; + return ret; +} + +static void +ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev) +{ + struct ath5k_buf *bf; + + ath5k_txbuf_free(sc, sc->bbuf); + list_for_each_entry(bf, &sc->txbuf, list) + ath5k_txbuf_free(sc, bf); + list_for_each_entry(bf, &sc->rxbuf, list) + ath5k_txbuf_free(sc, bf); + + /* Free memory associated with all descriptors */ + pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr); + + kfree(sc->bufptr); + sc->bufptr = NULL; +} + + + + + +/**************\ +* Queues setup * +\**************/ + +static struct ath5k_txq * +ath5k_txq_setup(struct ath5k_softc *sc, + int qtype, int subtype) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq *txq; + struct ath5k_txq_info qi = { + .tqi_subtype = subtype, + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT + }; + int qnum; + + /* + * Enable interrupts only for EOL and DESC conditions. + * We mark tx descriptors to receive a DESC interrupt + * when a tx queue gets deep; otherwise waiting for the + * EOL to reap descriptors. Note that this is done to + * reduce interrupt load and this only defers reaping + * descriptors, never transmitting frames. Aside from + * reducing interrupts this also permits more concurrency. + * The only potential downside is if the tx queue backs + * up in which case the top half of the kernel may backup + * due to a lack of tx descriptors. + */ + qi.tqi_flags = AR5K_TXQ_FLAG_TXEOLINT_ENABLE | + AR5K_TXQ_FLAG_TXDESCINT_ENABLE; + qnum = ath5k_hw_setup_tx_queue(ah, qtype, &qi); + if (qnum < 0) { + /* + * NB: don't print a message, this happens + * normally on parts with too few tx queues + */ + return ERR_PTR(qnum); + } + if (qnum >= ARRAY_SIZE(sc->txqs)) { + ATH5K_ERR(sc, "hw qnum %u out of range, max %tu!\n", + qnum, ARRAY_SIZE(sc->txqs)); + ath5k_hw_release_tx_queue(ah, qnum); + return ERR_PTR(-EINVAL); + } + txq = &sc->txqs[qnum]; + if (!txq->setup) { + txq->qnum = qnum; + txq->link = NULL; + INIT_LIST_HEAD(&txq->q); + spin_lock_init(&txq->lock); + txq->setup = true; + } + return &sc->txqs[qnum]; +} + +static int +ath5k_beaconq_setup(struct ath5k_hw *ah) +{ + struct ath5k_txq_info qi = { + .tqi_aifs = AR5K_TXQ_USEDEFAULT, + .tqi_cw_min = AR5K_TXQ_USEDEFAULT, + .tqi_cw_max = AR5K_TXQ_USEDEFAULT, + /* NB: for dynamic turbo, don't enable any other interrupts */ + .tqi_flags = AR5K_TXQ_FLAG_TXDESCINT_ENABLE + }; + + return ath5k_hw_setup_tx_queue(ah, AR5K_TX_QUEUE_BEACON, &qi); +} + +static int +ath5k_beaconq_config(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_txq_info qi; + int ret; + + ret = ath5k_hw_get_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) + return ret; + if (sc->opmode == IEEE80211_IF_TYPE_AP) { + /* + * Always burst out beacon and CAB traffic + * (aifs = cwmin = cwmax = 0) + */ + qi.tqi_aifs = 0; + qi.tqi_cw_min = 0; + qi.tqi_cw_max = 0; + } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + /* + * Adhoc mode; backoff between 0 and (2 * cw_min). + */ + qi.tqi_aifs = 0; + qi.tqi_cw_min = 0; + qi.tqi_cw_max = 2 * ah->ah_cw_min; + } + + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "beacon queueprops tqi_aifs:%d tqi_cw_min:%d tqi_cw_max:%d\n", + qi.tqi_aifs, qi.tqi_cw_min, qi.tqi_cw_max); + + ret = ath5k_hw_setup_tx_queueprops(ah, sc->bhalq, &qi); + if (ret) { + ATH5K_ERR(sc, "%s: unable to update parameters for beacon " + "hardware queue!\n", __func__); + return ret; + } + + return ath5k_hw_reset_tx_queue(ah, sc->bhalq); /* push to h/w */; +} + +static void +ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq) +{ + struct ath5k_buf *bf, *bf0; + + /* + * NB: this assumes output has been stopped and + * we do not need to block ath5k_tx_tasklet + */ + spin_lock_bh(&txq->lock); + list_for_each_entry_safe(bf, bf0, &txq->q, list) { + ath5k_debug_printtxbuf(sc, bf, !sc->ah->ah_proc_tx_desc(sc->ah, + bf->desc)); + + ath5k_txbuf_free(sc, bf); + + spin_lock_bh(&sc->txbuflock); + sc->tx_stats.data[txq->qnum].len--; + list_move_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_bh(&sc->txbuflock); + } + txq->link = NULL; + spin_unlock_bh(&txq->lock); +} + +/* + * Drain the transmit queues and reclaim resources. + */ +static void +ath5k_txq_cleanup(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + unsigned int i; + + /* XXX return value */ + if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) { + /* don't touch the hardware if marked invalid */ + ath5k_hw_stop_tx_dma(ah, sc->bhalq); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n", + ath5k_hw_get_tx_buf(ah, sc->bhalq)); + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) + if (sc->txqs[i].setup) { + ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum); + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, " + "link %p\n", + sc->txqs[i].qnum, + ath5k_hw_get_tx_buf(ah, + sc->txqs[i].qnum), + sc->txqs[i].link); + } + } + ieee80211_start_queues(sc->hw); /* XXX move to callers */ + + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) + if (sc->txqs[i].setup) + ath5k_txq_drainq(sc, &sc->txqs[i]); +} + +static void +ath5k_txq_release(struct ath5k_softc *sc) +{ + struct ath5k_txq *txq = sc->txqs; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sc->txqs); i++, txq++) + if (txq->setup) { + ath5k_hw_release_tx_queue(sc->ah, txq->qnum); + txq->setup = false; + } +} + + + + +/*************\ +* RX Handling * +\*************/ + +/* + * Enable the receive h/w following a reset. + */ +static int +ath5k_rx_start(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + struct ath5k_buf *bf; + int ret; + + sc->rxbufsize = roundup(IEEE80211_MAX_LEN, sc->cachelsz); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "cachelsz %u rxbufsize %u\n", + sc->cachelsz, sc->rxbufsize); + + sc->rxlink = NULL; + + spin_lock_bh(&sc->rxbuflock); + list_for_each_entry(bf, &sc->rxbuf, list) { + ret = ath5k_rxbuf_setup(sc, bf); + if (ret != 0) { + spin_unlock_bh(&sc->rxbuflock); + goto err; + } + } + bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); + spin_unlock_bh(&sc->rxbuflock); + + ath5k_hw_put_rx_buf(ah, bf->daddr); + ath5k_hw_start_rx(ah); /* enable recv descriptors */ + ath5k_mode_setup(sc); /* set filters, etc. */ + ath5k_hw_start_rx_pcu(ah); /* re-enable PCU/DMA engine */ + + return 0; +err: + return ret; +} + +/* + * Disable the receive h/w in preparation for a reset. + */ +static void +ath5k_rx_stop(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + + 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); + + sc->rxlink = NULL; /* just in case */ +} + +static unsigned int +ath5k_rx_decrypted(struct ath5k_softc *sc, struct ath5k_desc *ds, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (void *)skb->data; + unsigned int keyix, hlen = ieee80211_get_hdrlen_from_skb(skb); + + if (!(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && + ds->ds_rxstat.rs_keyix != AR5K_RXKEYIX_INVALID) + return RX_FLAG_DECRYPTED; + + /* Apparently when a default key is used to decrypt the packet + the hw does not set the index used to decrypt. In such cases + get the index from the packet. */ + if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) && + !(ds->ds_rxstat.rs_status & AR5K_RXERR_DECRYPT) && + skb->len >= hlen + 4) { + keyix = skb->data[hlen + 3] >> 6; + + if (test_bit(keyix, sc->keymap)) + return RX_FLAG_DECRYPTED; + } + + return 0; +} + + +static void +ath5k_check_ibss_hw_merge(struct ath5k_softc *sc, struct sk_buff *skb) +{ + u32 hw_tu; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + if ((mgmt->frame_control & IEEE80211_FCTL_FTYPE) == + IEEE80211_FTYPE_MGMT && + (mgmt->frame_control & IEEE80211_FCTL_STYPE) == + IEEE80211_STYPE_BEACON && + mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS && + memcmp(mgmt->bssid, sc->ah->ah_bssid, ETH_ALEN) == 0) { + /* + * Received an IBSS beacon with the same BSSID. Hardware might + * have updated the TSF, check if we need to update timers. + */ + hw_tu = TSF_TO_TU(ath5k_hw_get_tsf64(sc->ah)); + if (hw_tu >= sc->nexttbtt) { + ath5k_beacon_update_timers(sc, + mgmt->u.beacon.timestamp); + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "detected HW merge from received beacon\n"); + } + } +} + + +static void +ath5k_tasklet_rx(unsigned long data) +{ + struct ieee80211_rx_status rxs = {}; + struct sk_buff *skb; + struct ath5k_softc *sc = (void *)data; + struct ath5k_buf *bf; + struct ath5k_desc *ds; + u16 len; + u8 stat; + int ret; + int hdrlen; + int pad; + + spin_lock(&sc->rxbuflock); + do { + 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; + ds = bf->desc; + + /* TODO only one segment */ + 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; + + ret = sc->ah->ah_proc_rx_desc(sc->ah, ds); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, "error in processing rx descriptor\n"); + return; + } + + if (unlikely(ds->ds_rxstat.rs_more)) { + ATH5K_WARN(sc, "unsupported jumbo\n"); + goto next; + } + + stat = ds->ds_rxstat.rs_status; + if (unlikely(stat)) { + if (stat & AR5K_RXERR_PHY) + goto next; + if (stat & AR5K_RXERR_DECRYPT) { + /* + * Decrypt error. If the error occurred + * because there was no hardware key, then + * let the frame through so the upper layers + * can process it. This is necessary for 5210 + * parts which have no way to setup a ``clear'' + * key cache entry. + * + * XXX do key cache faulting + */ + if (ds->ds_rxstat.rs_keyix == + AR5K_RXKEYIX_INVALID && + !(stat & AR5K_RXERR_CRC)) + goto accept; + } + if (stat & AR5K_RXERR_MIC) { + rxs.flag |= RX_FLAG_MMIC_ERROR; + goto accept; + } + + /* let crypto-error packets fall through in MNTR */ + if ((stat & ~(AR5K_RXERR_DECRYPT|AR5K_RXERR_MIC)) || + sc->opmode != IEEE80211_IF_TYPE_MNTR) + goto next; + } +accept: + len = ds->ds_rxstat.rs_datalen; + pci_dma_sync_single_for_cpu(sc->pdev, bf->skbaddr, len, + PCI_DMA_FROMDEVICE); + pci_unmap_single(sc->pdev, bf->skbaddr, sc->rxbufsize, + PCI_DMA_FROMDEVICE); + bf->skb = NULL; + + skb_put(skb, len); + + /* + * the hardware adds a padding to 4 byte boundaries between + * the header and the payload data if the header length is + * not multiples of 4 - remove it + */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + pad = hdrlen % 4; + memmove(skb->data + pad, skb->data, hdrlen); + skb_pull(skb, pad); + } + + /* + * always extend the mac timestamp, since this information is + * also needed for proper IBSS merging. + * + * XXX: it might be too late to do it here, since rs_tstamp is + * 15bit only. that means TSF extension has to be done within + * 32768usec (about 32ms). it might be necessary to move this to + * the interrupt handler, like it is done in madwifi. + */ + rxs.mactime = ath5k_extend_tsf(sc->ah, ds->ds_rxstat.rs_tstamp); + rxs.flag |= RX_FLAG_TSFT; + + rxs.freq = sc->curchan->freq; + rxs.channel = sc->curchan->chan; + rxs.phymode = sc->curmode; + + /* + * signal quality: + * the names here are misleading and the usage of these + * values by iwconfig makes it even worse + */ + /* noise floor in dBm, from the last noise calibration */ + rxs.noise = sc->ah->ah_noise_floor; + /* signal level in dBm */ + rxs.ssi = rxs.noise + ds->ds_rxstat.rs_rssi; + /* + * "signal" is actually displayed as Link Quality by iwconfig + * we provide a percentage based on rssi (assuming max rssi 64) + */ + rxs.signal = ds->ds_rxstat.rs_rssi * 100 / 64; + + rxs.antenna = ds->ds_rxstat.rs_antenna; + rxs.rate = ds->ds_rxstat.rs_rate; + rxs.flag |= ath5k_rx_decrypted(sc, ds, skb); + + ath5k_debug_dump_skb(sc, skb, "RX ", 0); + + /* check beacons in IBSS mode */ + if (sc->opmode == IEEE80211_IF_TYPE_IBSS) + ath5k_check_ibss_hw_merge(sc, skb); + + __ieee80211_rx(sc->hw, skb, &rxs); + sc->led_rxrate = ds->ds_rxstat.rs_rate; + ath5k_led_event(sc, ATH_LED_RX); +next: + list_move_tail(&bf->list, &sc->rxbuf); + } while (ath5k_rxbuf_setup(sc, bf) == 0); + spin_unlock(&sc->rxbuflock); +} + + + + +/*************\ +* TX Handling * +\*************/ + +static void +ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) +{ + struct ieee80211_tx_status txs = {}; + struct ath5k_buf *bf, *bf0; + struct ath5k_desc *ds; + struct sk_buff *skb; + int ret; + + spin_lock(&txq->lock); + 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); + if (unlikely(ret == -EINPROGRESS)) + break; + else if (unlikely(ret)) { + ATH5K_ERR(sc, "error %d while processing queue %u\n", + ret, txq->qnum); + break; + } + + skb = bf->skb; + bf->skb = NULL; + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, + PCI_DMA_TODEVICE); + + txs.control = bf->ctl; + txs.retry_count = ds->ds_txstat.ts_shortretry + + ds->ds_txstat.ts_longretry / 6; + if (unlikely(ds->ds_txstat.ts_status)) { + sc->ll_stats.dot11ACKFailureCount++; + if (ds->ds_txstat.ts_status & AR5K_TXERR_XRETRY) + txs.excessive_retries = 1; + else if (ds->ds_txstat.ts_status & AR5K_TXERR_FILT) + txs.flags |= IEEE80211_TX_STATUS_TX_FILTERED; + } else { + txs.flags |= IEEE80211_TX_STATUS_ACK; + txs.ack_signal = ds->ds_txstat.ts_rssi; + } + + ieee80211_tx_status(sc->hw, skb, &txs); + sc->tx_stats.data[txq->qnum].count++; + + spin_lock(&sc->txbuflock); + sc->tx_stats.data[txq->qnum].len--; + list_move_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock(&sc->txbuflock); + } + if (likely(list_empty(&txq->q))) + txq->link = NULL; + spin_unlock(&txq->lock); + if (sc->txbuf_len > ATH_TXBUF / 5) + ieee80211_wake_queues(sc->hw); +} + +static void +ath5k_tasklet_tx(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + + ath5k_tx_processq(sc, sc->txq); + + ath5k_led_event(sc, ATH_LED_TX); +} + + + + +/*****************\ +* Beacon handling * +\*****************/ + +/* + * Setup the beacon frame for transmit. + */ +static int +ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, + struct ieee80211_tx_control *ctl) +{ + struct sk_buff *skb = bf->skb; + struct ath5k_hw *ah = sc->ah; + struct ath5k_desc *ds; + int ret, antenna = 0; + u32 flags; + + bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] " + "skbaddr %llx\n", skb, skb->data, skb->len, + (unsigned long long)bf->skbaddr); + if (pci_dma_mapping_error(bf->skbaddr)) { + ATH5K_ERR(sc, "beacon DMA mapping failed\n"); + return -EIO; + } + + ds = bf->desc; + + flags = AR5K_TXDESC_NOACK; + if (sc->opmode == IEEE80211_IF_TYPE_IBSS && ath5k_hw_hasveol(ah)) { + ds->ds_link = bf->daddr; /* self-linked */ + flags |= AR5K_TXDESC_VEOL; + /* + * Let hardware handle antenna switching if txantenna is not set + */ + } else { + ds->ds_link = 0; + /* + * Switch antenna every 4 beacons if txantenna is not set + * XXX assumes two antennas + */ + if (antenna == 0) + antenna = sc->bsent & 4 ? 2 : 1; + } + + ds->ds_data = bf->skbaddr; + ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN, + ieee80211_get_hdrlen_from_skb(skb), + AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1, + AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); + if (ret) + goto err_unmap; + + return 0; +err_unmap: + pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); + return ret; +} + +/* + * Transmit a beacon frame at SWBA. Dynamic updates to the + * frame contents are done as needed and the slot time is + * also adjusted based on current state. + * + * this is usually called from interrupt context (ath5k_intr()) + * but also from ath5k_beacon_config() in IBSS mode which in turn + * can be called from a tasklet and user context + */ +static void +ath5k_beacon_send(struct ath5k_softc *sc) +{ + struct ath5k_buf *bf = sc->bbuf; + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "in beacon_send\n"); + + if (unlikely(bf->skb == NULL || sc->opmode == IEEE80211_IF_TYPE_STA || + sc->opmode == IEEE80211_IF_TYPE_MNTR)) { + ATH5K_WARN(sc, "bf=%p bf_skb=%p\n", bf, bf ? bf->skb : NULL); + return; + } + /* + * Check if the previous beacon has gone out. If + * not don't don't try to post another, skip this + * period and wait for the next. Missed beacons + * indicate a problem and should not occur. If we + * miss too many consecutive beacons reset the device. + */ + if (unlikely(ath5k_hw_num_tx_pending(ah, sc->bhalq) != 0)) { + sc->bmisscount++; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, + "missed %u consecutive beacons\n", sc->bmisscount); + if (sc->bmisscount > 3) { /* NB: 3 is a guess */ + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, + "stuck beacon time (%u missed)\n", + sc->bmisscount); + tasklet_schedule(&sc->restq); + } + return; + } + if (unlikely(sc->bmisscount != 0)) { + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, + "resume beacon xmit after %u misses\n", + sc->bmisscount); + sc->bmisscount = 0; + } + + /* + * Stop any current dma and put the new frame on the queue. + * This should never fail since we check above that no frames + * are still pending on the queue. + */ + if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) { + 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); + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON_PROC, "TXDP[%u] = %llx (%p)\n", + sc->bhalq, (unsigned long long)bf->daddr, bf->desc); + + sc->bsent++; +} + + +/** + * ath5k_beacon_update_timers - update beacon timers + * + * @sc: struct ath5k_softc pointer we are operating on + * @bc_tsf: the timestamp of the beacon. 0 to reset the TSF. -1 to perform a + * beacon timer update based on the current HW TSF. + * + * Calculate the next target beacon transmit time (TBTT) based on the timestamp + * of a received beacon or the current local hardware TSF and write it to the + * beacon timer registers. + * + * This is called in a variety of situations, e.g. when a beacon is received, + * when a HW merge has been detected, but also when an new IBSS is created or + * when we otherwise know we have to update the timers, but we keep it in this + * function to have it all together in one place. + */ +static void +ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) +{ + struct ath5k_hw *ah = sc->ah; + u32 nexttbtt, intval, hw_tu, bc_tu; + u64 hw_tsf; + + intval = sc->bintval & AR5K_BEACON_PERIOD; + if (WARN_ON(!intval)) + return; + + /* beacon TSF converted to TU */ + bc_tu = TSF_TO_TU(bc_tsf); + + /* current TSF converted to TU */ + hw_tsf = ath5k_hw_get_tsf64(ah); + hw_tu = TSF_TO_TU(hw_tsf); + +#define FUDGE 3 + /* we use FUDGE to make sure the next TBTT is ahead of the current TU */ + if (bc_tsf == -1) { + /* + * no beacons received, called internally. + * just need to refresh timers based on HW TSF. + */ + nexttbtt = roundup(hw_tu + FUDGE, intval); + } else if (bc_tsf == 0) { + /* + * no beacon received, probably called by ath5k_reset_tsf(). + * reset TSF to start with 0. + */ + nexttbtt = intval; + intval |= AR5K_BEACON_RESET_TSF; + } else if (bc_tsf > hw_tsf) { + /* + * beacon received, SW merge happend but HW TSF not yet updated. + * not possible to reconfigure timers yet, but next time we + * receive a beacon with the same BSSID, the hardware will + * automatically update the TSF and then we need to reconfigure + * the timers. + */ + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "need to wait for HW TSF sync\n"); + return; + } else { + /* + * most important case for beacon synchronization between STA. + * + * beacon received and HW TSF has been already updated by HW. + * update next TBTT based on the TSF of the beacon, but make + * sure it is ahead of our local TSF timer. + */ + nexttbtt = bc_tu + roundup(hw_tu + FUDGE - bc_tu, intval); + } +#undef FUDGE + + sc->nexttbtt = nexttbtt; + + intval |= AR5K_BEACON_ENA; + ath5k_hw_init_beacon(ah, nexttbtt, intval); + + /* + * debugging output last in order to preserve the time critical aspect + * of this function + */ + if (bc_tsf == -1) + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "reconfigured timers based on HW TSF\n"); + else if (bc_tsf == 0) + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "reset HW TSF and timers\n"); + else + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "updated timers based on beacon TSF\n"); + + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, + "bc_tsf %llx hw_tsf %llx bc_tu %u hw_tu %u nexttbtt %u\n", + bc_tsf, hw_tsf, bc_tu, hw_tu, nexttbtt); + ATH5K_DBG_UNLIMIT(sc, ATH5K_DEBUG_BEACON, "intval %u %s %s\n", + intval & AR5K_BEACON_PERIOD, + intval & AR5K_BEACON_ENA ? "AR5K_BEACON_ENA" : "", + intval & AR5K_BEACON_RESET_TSF ? "AR5K_BEACON_RESET_TSF" : ""); +} + + +/** + * ath5k_beacon_config - Configure the beacon queues and interrupts + * + * @sc: struct ath5k_softc pointer we are operating on + * + * When operating in station mode we want to receive a BMISS interrupt when we + * stop seeing beacons from the AP we've associated with so we can look for + * another AP to associate with. + * + * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA + * interrupts to detect HW merges only. + * + * AP mode is missing. + */ +static void +ath5k_beacon_config(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + + ath5k_hw_set_intr(ah, 0); + sc->bmisscount = 0; + + if (sc->opmode == IEEE80211_IF_TYPE_STA) { + sc->imask |= AR5K_INT_BMISS; + } else if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + /* + * In IBSS mode we use a self-linked tx descriptor and let the + * hardware send the beacons automatically. We have to load it + * only once here. + * We use the SWBA interrupt only to keep track of the beacon + * timers in order to detect HW merges (automatic TSF updates). + */ + ath5k_beaconq_config(sc); + + sc->imask |= AR5K_INT_SWBA; + + if (ath5k_hw_hasveol(ah)) + ath5k_beacon_send(sc); + } + /* TODO else AP */ + + ath5k_hw_set_intr(ah, sc->imask); +} + + +/********************\ +* Interrupt handling * +\********************/ + +static int +ath5k_init(struct ath5k_softc *sc) +{ + int ret; + + mutex_lock(&sc->lock); + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); + + /* + * Stop anything previously setup. This is safe + * no matter this is the first time through or not. + */ + ath5k_stop_locked(sc); + + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + sc->curchan = sc->hw->conf.chan; + ret = ath5k_hw_reset(sc->ah, sc->opmode, sc->curchan, false); + if (ret) { + ATH5K_ERR(sc, "unable to reset hardware: %d\n", ret); + goto done; + } + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath5k_hw_set_txpower_limit(sc->ah, 0); + + /* + * Setup the hardware after reset: the key cache + * is filled as needed and the receive engine is + * set going. Frame transmit is handled entirely + * in the frame output path; there's nothing to do + * here except setup the interrupt mask. + */ + ret = ath5k_rx_start(sc); + if (ret) + goto done; + + /* + * Enable interrupts. + */ + sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL; + + ath5k_hw_set_intr(sc->ah, sc->imask); + /* Set ack to be sent at low bit-rates */ + ath5k_hw_set_ack_bitrate_high(sc->ah, false); + + mod_timer(&sc->calib_tim, round_jiffies(jiffies + + msecs_to_jiffies(ath5k_calinterval * 1000))); + + ret = 0; +done: + mutex_unlock(&sc->lock); + return ret; +} + +static int +ath5k_stop_locked(struct ath5k_softc *sc) +{ + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "invalid %u\n", + test_bit(ATH_STAT_INVALID, sc->status)); + + /* + * Shutdown the hardware and driver: + * stop output from above + * disable interrupts + * turn off timers + * turn off the radio + * clear transmit machinery + * clear receive machinery + * drain and release tx queues + * reclaim beacon resources + * power down hardware + * + * Note that some of this work is not possible if the + * hardware is gone (invalid). + */ + ieee80211_stop_queues(sc->hw); + + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + if (test_bit(ATH_STAT_LEDSOFT, sc->status)) { + del_timer_sync(&sc->led_tim); + ath5k_hw_set_gpio(ah, sc->led_pin, !sc->led_on); + __clear_bit(ATH_STAT_LEDBLINKING, sc->status); + } + ath5k_hw_set_intr(ah, 0); + } + ath5k_txq_cleanup(sc); + if (!test_bit(ATH_STAT_INVALID, sc->status)) { + ath5k_rx_stop(sc); + ath5k_hw_phy_disable(ah); + } else + sc->rxlink = NULL; + + return 0; +} + +/* + * Stop the device, grabbing the top-level lock to protect + * against concurrent entry through ath5k_init (which can happen + * if another thread does a system call and the thread doing the + * stop is preempted). + */ +static int +ath5k_stop_hw(struct ath5k_softc *sc) +{ + int ret; + + mutex_lock(&sc->lock); + ret = ath5k_stop_locked(sc); + if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) { + /* + * Set the chip in full sleep mode. Note that we are + * careful to do this only when bringing the interface + * completely to a stop. When the chip is in this state + * it must be carefully woken up or references to + * registers in the PCI clock domain may freeze the bus + * (and system). This varies by chip and is mostly an + * issue with newer parts that go to sleep more quickly. + */ + if (sc->ah->ah_mac_srev >= 0x78) { + /* + * XXX + * don't put newer MAC revisions > 7.8 to sleep because + * of the above mentioned problems + */ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, " + "not putting device to sleep\n"); + } else { + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, + "putting device to full sleep\n"); + ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0); + } + } + ath5k_txbuf_free(sc, sc->bbuf); + mutex_unlock(&sc->lock); + + del_timer_sync(&sc->calib_tim); + + return ret; +} + +static irqreturn_t +ath5k_intr(int irq, void *dev_id) +{ + struct ath5k_softc *sc = dev_id; + struct ath5k_hw *ah = sc->ah; + enum ath5k_int status; + unsigned int counter = 1000; + + if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) || + !ath5k_hw_is_intr_pending(ah))) + return IRQ_NONE; + + do { + /* + * Figure out the reason(s) for the interrupt. Note + * that get_isr returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath5k_hw_get_isr(ah, &status); /* NB: clears IRQ too */ + ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n", + status, sc->imask); + status &= sc->imask; /* discard unasked for bits */ + if (unlikely(status & AR5K_INT_FATAL)) { + /* + * Fatal errors are unrecoverable. + * Typically these are caused by DMA errors. + */ + tasklet_schedule(&sc->restq); + } else if (unlikely(status & AR5K_INT_RXORN)) { + tasklet_schedule(&sc->restq); + } else { + if (status & AR5K_INT_SWBA) { + /* + * Software beacon alert--time to send a beacon. + * Handle beacon transmission directly; deferring + * this is too slow to meet timing constraints + * under load. + * + * In IBSS mode we use this interrupt just to + * keep track of the next TBTT (target beacon + * transmission time) in order to detect hardware + * merges (TSF updates). + */ + if (sc->opmode == IEEE80211_IF_TYPE_IBSS) { + /* XXX: only if VEOL suppported */ + u64 tsf = ath5k_hw_get_tsf64(ah); + sc->nexttbtt += sc->bintval; + ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, + "SWBA nexttbtt: %x hw_tu: %x " + "TSF: %llx\n", + sc->nexttbtt, + TSF_TO_TU(tsf), tsf); + } else { + ath5k_beacon_send(sc); + } + } + if (status & AR5K_INT_RXEOL) { + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work at + * least on older hardware revs. + */ + sc->rxlink = NULL; + } + if (status & AR5K_INT_TXURN) { + /* bump tx trigger level */ + ath5k_hw_update_tx_triglevel(ah, true); + } + if (status & AR5K_INT_RX) + tasklet_schedule(&sc->rxtq); + if (status & AR5K_INT_TX) + tasklet_schedule(&sc->txtq); + if (status & AR5K_INT_BMISS) { + } + if (status & AR5K_INT_MIB) { + /* TODO */ + } + } + } while (ath5k_hw_is_intr_pending(ah) && counter-- > 0); + + if (unlikely(!counter)) + ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); + + return IRQ_HANDLED; +} + +static void +ath5k_tasklet_reset(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + + ath5k_reset(sc->hw); +} + +/* + * Periodically recalibrate the PHY to account + * for temperature/environment changes. + */ +static void +ath5k_calibrate(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + struct ath5k_hw *ah = sc->ah; + + ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", + sc->curchan->chan, sc->curchan->val); + + if (ath5k_hw_get_rf_gain(ah) == AR5K_RFGAIN_NEED_CHANGE) { + /* + * Rfgain is out of bounds, reset the chip + * to load new gain values. + */ + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "calibration, resetting\n"); + ath5k_reset(sc->hw); + } + if (ath5k_hw_phy_calibrate(ah, sc->curchan)) + ATH5K_ERR(sc, "calibration of channel %u failed\n", + sc->curchan->chan); + + mod_timer(&sc->calib_tim, round_jiffies(jiffies + + msecs_to_jiffies(ath5k_calinterval * 1000))); +} + + + +/***************\ +* LED functions * +\***************/ + +static void +ath5k_led_off(unsigned long data) +{ + struct ath5k_softc *sc = (void *)data; + + if (test_bit(ATH_STAT_LEDENDBLINK, sc->status)) + __clear_bit(ATH_STAT_LEDBLINKING, sc->status); + else { + __set_bit(ATH_STAT_LEDENDBLINK, sc->status); + ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on); + mod_timer(&sc->led_tim, jiffies + sc->led_off); + } +} + +/* + * Blink the LED according to the specified on/off times. + */ +static void +ath5k_led_blink(struct ath5k_softc *sc, unsigned int on, + unsigned int off) +{ + ATH5K_DBG(sc, ATH5K_DEBUG_LED, "on %u off %u\n", on, off); + ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on); + __set_bit(ATH_STAT_LEDBLINKING, sc->status); + __clear_bit(ATH_STAT_LEDENDBLINK, sc->status); + sc->led_off = off; + mod_timer(&sc->led_tim, jiffies + on); +} + +static void +ath5k_led_event(struct ath5k_softc *sc, int event) +{ + if (likely(!test_bit(ATH_STAT_LEDSOFT, sc->status))) + return; + if (unlikely(test_bit(ATH_STAT_LEDBLINKING, sc->status))) + return; /* don't interrupt active blink */ + switch (event) { + case ATH_LED_TX: + ath5k_led_blink(sc, sc->hwmap[sc->led_txrate].ledon, + sc->hwmap[sc->led_txrate].ledoff); + break; + case ATH_LED_RX: + ath5k_led_blink(sc, sc->hwmap[sc->led_rxrate].ledon, + sc->hwmap[sc->led_rxrate].ledoff); + break; + } +} + + + + +/********************\ +* Mac80211 functions * +\********************/ + +static int +ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_buf *bf; + unsigned long flags; + int hdrlen; + int pad; + + ath5k_debug_dump_skb(sc, skb, "TX ", 1); + + if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + ATH5K_DBG(sc, ATH5K_DEBUG_XMIT, "tx in monitor (scan?)\n"); + + /* + * the hardware expects the header padded to 4 byte boundaries + * if this is not the case we add the padding after the header + */ + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + if (hdrlen & 3) { + pad = hdrlen % 4; + if (skb_headroom(skb) < pad) { + ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" + " headroom to pad %d\n", hdrlen, pad); + return -1; + } + skb_push(skb, pad); + memmove(skb->data, skb->data+pad, hdrlen); + } + + sc->led_txrate = ctl->tx_rate; + + spin_lock_irqsave(&sc->txbuflock, flags); + if (list_empty(&sc->txbuf)) { + ATH5K_ERR(sc, "no further txbuf available, dropping packet\n"); + spin_unlock_irqrestore(&sc->txbuflock, flags); + ieee80211_stop_queue(hw, ctl->queue); + return -1; + } + bf = list_first_entry(&sc->txbuf, struct ath5k_buf, list); + list_del(&bf->list); + sc->txbuf_len--; + if (list_empty(&sc->txbuf)) + ieee80211_stop_queues(hw); + spin_unlock_irqrestore(&sc->txbuflock, flags); + + bf->skb = skb; + + if (ath5k_txbuf_setup(sc, bf, ctl)) { + bf->skb = NULL; + spin_lock_irqsave(&sc->txbuflock, flags); + list_add_tail(&bf->list, &sc->txbuf); + sc->txbuf_len++; + spin_unlock_irqrestore(&sc->txbuflock, flags); + dev_kfree_skb_any(skb); + return 0; + } + + return 0; +} + +static int +ath5k_reset(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + int ret; + + ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n"); + /* + * Convert to a hw channel description with the flags + * constrained to reflect the current operating mode. + */ + sc->curchan = hw->conf.chan; + + ath5k_hw_set_intr(ah, 0); + ath5k_txq_cleanup(sc); + ath5k_rx_stop(sc); + + ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true); + if (unlikely(ret)) { + ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret); + goto err; + } + ath5k_hw_set_txpower_limit(sc->ah, 0); + + ret = ath5k_rx_start(sc); + if (unlikely(ret)) { + ATH5K_ERR(sc, "can't start recv logic\n"); + goto err; + } + /* + * We may be doing a reset in response to an ioctl + * that changes the channel so update any state that + * might change as a result. + * + * XXX needed? + */ +/* ath5k_chan_change(sc, c); */ + ath5k_beacon_config(sc); + /* intrs are started by ath5k_beacon_config */ + + ieee80211_wake_queues(hw); + + return 0; +err: + return ret; +} + +static int ath5k_start(struct ieee80211_hw *hw) +{ + return ath5k_init(hw->priv); +} + +static void ath5k_stop(struct ieee80211_hw *hw) +{ + ath5k_stop_hw(hw->priv); +} + +static int ath5k_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + int ret; + + mutex_lock(&sc->lock); + if (sc->vif) { + ret = 0; + goto end; + } + + sc->vif = conf->vif; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_MNTR: + sc->opmode = conf->type; + break; + default: + ret = -EOPNOTSUPP; + goto end; + } + ret = 0; +end: + mutex_unlock(&sc->lock); + return ret; +} + +static void +ath5k_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + + mutex_lock(&sc->lock); + if (sc->vif != conf->vif) + goto end; + + sc->vif = NULL; +end: + mutex_unlock(&sc->lock); +} + +static int +ath5k_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + + sc->bintval = conf->beacon_int; + ath5k_setcurmode(sc, conf->phymode); + + return ath5k_chan_set(sc, conf->chan); +} + +static int +ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + int ret; + + /* Set to a reasonable value. Note that this will + * be set to mac80211's value at ath5k_config(). */ + sc->bintval = 1000; + mutex_lock(&sc->lock); + if (sc->vif != vif) { + ret = -EIO; + goto unlock; + } + if (conf->bssid) { + /* Cache for later use during resets */ + memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); + /* 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); + } + mutex_unlock(&sc->lock); + + return ath5k_reset(hw); +unlock: + mutex_unlock(&sc->lock); + return ret; +} + +#define SUPPORTED_FIF_FLAGS \ + FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | \ + FIF_PLCPFAIL | FIF_CONTROL | FIF_OTHER_BSS | \ + FIF_BCN_PRBRESP_PROMISC +/* + * o always accept unicast, broadcast, and multicast traffic + * o multicast traffic for all BSSIDs will be enabled if mac80211 + * says it should be + * o maintain current state of phy ofdm or phy cck error reception. + * If the hardware detects any of these type of errors then + * ath5k_hw_get_rx_filter() will pass to us the respective + * hardware filters to be able to receive these type of frames. + * o probe request frames are accepted only when operating in + * hostap, adhoc, or monitor modes + * o enable promiscuous mode according to the interface state + * o accept beacons: + * - when operating in adhoc mode so the 802.11 layer creates + * node table entries for peers, + * - when operating in station mode for collecting rssi data when + * the station is otherwise quiet, or + * - when scanning + */ +static void ath5k_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct ath5k_softc *sc = hw->priv; + struct ath5k_hw *ah = sc->ah; + u32 mfilt[2], val, rfilt; + u8 pos; + int i; + + mfilt[0] = 0; + mfilt[1] = 0; + + /* Only deal with supported flags */ + changed_flags &= SUPPORTED_FIF_FLAGS; + *new_flags &= SUPPORTED_FIF_FLAGS; + + /* If HW detects any phy or radar errors, leave those filters on. + * Also, always enable Unicast, Broadcasts and Multicast + * XXX: move unicast, bssid broadcasts and multicast to mac80211 */ + rfilt = (ath5k_hw_get_rx_filter(ah) & (AR5K_RX_FILTER_PHYERR)) | + (AR5K_RX_FILTER_UCAST | AR5K_RX_FILTER_BCAST | + AR5K_RX_FILTER_MCAST); + + if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) { + if (*new_flags & FIF_PROMISC_IN_BSS) { + rfilt |= AR5K_RX_FILTER_PROM; + __set_bit(ATH_STAT_PROMISC, sc->status); + } + else + __clear_bit(ATH_STAT_PROMISC, sc->status); + } + + /* Note, AR5K_RX_FILTER_MCAST is already enabled */ + if (*new_flags & FIF_ALLMULTI) { + mfilt[0] = ~0; + mfilt[1] = ~0; + } else { + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + /* calculate XOR of eight 6-bit values */ + val = LE_READ_4(mclist->dmi_addr + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = LE_READ_4(mclist->dmi_addr + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + /* XXX: we might be able to just do this instead, + * but not sure, needs testing, if we do use this we'd + * neet to inform below to not reset the mcast */ + /* ath5k_hw_set_mcast_filterindex(ah, + * mclist->dmi_addr[5]); */ + mclist = mclist->next; + } + } + + /* This is the best we can do */ + if (*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL)) + rfilt |= AR5K_RX_FILTER_PHYERR; + + /* FIF_BCN_PRBRESP_PROMISC really means to enable beacons + * and probes for any BSSID, this needs testing */ + if (*new_flags & FIF_BCN_PRBRESP_PROMISC) + rfilt |= AR5K_RX_FILTER_BEACON | AR5K_RX_FILTER_PROBEREQ; + + /* FIF_CONTROL doc says that if FIF_PROMISC_IN_BSS is not + * set we should only pass on control frames for this + * station. This needs testing. I believe right now this + * enables *all* control frames, which is OK.. but + * but we should see if we can improve on granularity */ + if (*new_flags & FIF_CONTROL) + rfilt |= AR5K_RX_FILTER_CONTROL; + + /* Additional settings per mode -- this is per ath5k */ + + /* XXX move these to mac80211, and add a beacon IFF flag to mac80211 */ + + if (sc->opmode == IEEE80211_IF_TYPE_MNTR) + rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; + if (sc->opmode != IEEE80211_IF_TYPE_STA) + rfilt |= AR5K_RX_FILTER_PROBEREQ; + if (sc->opmode != IEEE80211_IF_TYPE_AP && + test_bit(ATH_STAT_PROMISC, sc->status)) + rfilt |= AR5K_RX_FILTER_PROM; + if (sc->opmode == IEEE80211_IF_TYPE_STA || + sc->opmode == IEEE80211_IF_TYPE_IBSS) { + rfilt |= AR5K_RX_FILTER_BEACON; + } + + /* Set filters */ + ath5k_hw_set_rx_filter(ah,rfilt); + + /* Set multicast bits */ + ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); + /* Set the cached hw filter flags, this will alter actually + * be set in HW */ + sc->filter_flags = rfilt; +} + +static int +ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + const u8 *local_addr, const u8 *addr, + struct ieee80211_key_conf *key) +{ + struct ath5k_softc *sc = hw->priv; + int ret = 0; + + switch(key->alg) { + case ALG_WEP: + break; + case ALG_TKIP: + case ALG_CCMP: + return -EOPNOTSUPP; + default: + WARN_ON(1); + return -EINVAL; + } + + mutex_lock(&sc->lock); + + switch (cmd) { + case SET_KEY: + ret = ath5k_hw_set_key(sc->ah, key->keyidx, key, addr); + if (ret) { + ATH5K_ERR(sc, "can't set the key\n"); + goto unlock; + } + __set_bit(key->keyidx, sc->keymap); + key->hw_key_idx = key->keyidx; + break; + case DISABLE_KEY: + ath5k_hw_reset_key(sc->ah, key->keyidx); + __clear_bit(key->keyidx, sc->keymap); + break; + default: + ret = -EINVAL; + goto unlock; + } + +unlock: + mutex_unlock(&sc->lock); + return ret; +} + +static int +ath5k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ath5k_softc *sc = hw->priv; + + memcpy(stats, &sc->ll_stats, sizeof(sc->ll_stats)); + + return 0; +} + +static int +ath5k_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) +{ + struct ath5k_softc *sc = hw->priv; + + memcpy(stats, &sc->tx_stats, sizeof(sc->tx_stats)); + + return 0; +} + +static u64 +ath5k_get_tsf(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + return ath5k_hw_get_tsf64(sc->ah); +} + +static void +ath5k_reset_tsf(struct ieee80211_hw *hw) +{ + struct ath5k_softc *sc = hw->priv; + + /* + * in IBSS mode we need to update the beacon timers too. + * this will also reset the TSF if we call it with 0 + */ + if (sc->opmode == IEEE80211_IF_TYPE_IBSS) + ath5k_beacon_update_timers(sc, 0); + else + ath5k_hw_reset_tsf(sc->ah); +} + +static int +ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *ctl) +{ + struct ath5k_softc *sc = hw->priv; + int ret; + + ath5k_debug_dump_skb(sc, skb, "BC ", 1); + + mutex_lock(&sc->lock); + + if (sc->opmode != IEEE80211_IF_TYPE_IBSS) { + ret = -EIO; + goto end; + } + + ath5k_txbuf_free(sc, sc->bbuf); + sc->bbuf->skb = skb; + ret = ath5k_beacon_setup(sc, sc->bbuf, ctl); + if (ret) + sc->bbuf->skb = NULL; + else + ath5k_beacon_config(sc); + +end: + mutex_unlock(&sc->lock); + return ret; +} + diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h new file mode 100644 index 000000000000..8287ae787f12 --- /dev/null +++ b/drivers/net/wireless/ath5k/base.h @@ -0,0 +1,179 @@ +/*- + * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_ATH_ATHVAR_H +#define _DEV_ATH_ATHVAR_H + +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/wireless.h> +#include <linux/if_ether.h> + +#include "ath5k.h" +#include "debug.h" + +#define ATH_RXBUF 40 /* number of RX buffers */ +#define ATH_TXBUF 200 /* number of TX buffers */ +#define ATH_BCBUF 1 /* number of beacon buffers */ + +struct ath5k_buf { + struct list_head list; + unsigned int flags; /* tx 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 */ + dma_addr_t skbaddr;/* physical addr of skb data */ + struct ieee80211_tx_control ctl; +}; + +/* + * Data transmit queue state. One of these exists for each + * hardware transmit queue. Packets sent to us from above + * are assigned to queues based on their priority. Not all + * devices support a complete set of hardware transmit queues. + * For those devices the array sc_ac2q will map multiple + * priorities to fewer hardware queues (typically all to one + * hardware queue). + */ +struct ath5k_txq { + unsigned int qnum; /* hardware q number */ + u32 *link; /* link ptr in last TX desc */ + struct list_head q; /* transmit queue */ + spinlock_t lock; /* lock on q and link */ + bool setup; +}; + +#if CHAN_DEBUG +#define ATH_CHAN_MAX (26+26+26+200+200) +#else +#define ATH_CHAN_MAX (14+14+14+252+20) /* XXX what's the max? */ +#endif + +/* Software Carrier, keeps track of the driver state + * associated with an instance of a device */ +struct ath5k_softc { + struct pci_dev *pdev; /* for dma mapping */ + void __iomem *iobase; /* address of the device */ + struct mutex lock; /* dev-level lock */ + struct ieee80211_tx_queue_stats tx_stats; + struct ieee80211_low_level_stats ll_stats; + struct ieee80211_hw *hw; /* IEEE 802.11 common */ + struct ieee80211_hw_mode modes[NUM_DRIVER_MODES]; + struct ieee80211_channel channels[ATH_CHAN_MAX]; + struct ieee80211_rate rates[AR5K_MAX_RATES * NUM_DRIVER_MODES]; + enum ieee80211_if_types opmode; + struct ath5k_hw *ah; /* Atheros HW */ + +#if ATH5K_DEBUG + struct ath5k_dbg_info debug; /* debug info */ +#endif + + struct ath5k_buf *bufptr; /* allocated buffer ptr */ + struct ath5k_desc *desc; /* TX/RX descriptors */ + dma_addr_t desc_daddr; /* DMA (physical) address */ + size_t desc_len; /* size of TX/RX descriptors */ + u16 cachelsz; /* cache line size */ + + DECLARE_BITMAP(status, 6); +#define ATH_STAT_INVALID 0 /* disable hardware accesses */ +#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ +#define ATH_STAT_PROMISC 2 +#define ATH_STAT_LEDBLINKING 3 /* LED blink operation active */ +#define ATH_STAT_LEDENDBLINK 4 /* finish LED blink operation */ +#define ATH_STAT_LEDSOFT 5 /* enable LED gpio status */ + + unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ + unsigned int curmode; /* current phy mode */ + struct ieee80211_channel *curchan; /* current h/w channel */ + + struct ieee80211_vif *vif; + + struct { + u8 rxflags; /* radiotap rx flags */ + u8 txflags; /* radiotap tx flags */ + u16 ledon; /* softled on time */ + u16 ledoff; /* softled off time */ + } hwmap[32]; /* h/w rate ix mappings */ + + enum ath5k_int imask; /* interrupt mask copy */ + + DECLARE_BITMAP(keymap, AR5K_KEYCACHE_SIZE); /* key use bit map */ + + u8 bssidmask[ETH_ALEN]; + + unsigned int led_pin, /* GPIO pin for driving LED */ + led_on, /* pin setting for LED on */ + led_off; /* off time for current blink */ + struct timer_list led_tim; /* led off timer */ + u8 led_rxrate; /* current rx rate for LED */ + u8 led_txrate; /* current tx rate for LED */ + + struct tasklet_struct restq; /* reset tasklet */ + + unsigned int rxbufsize; /* rx size based on mtu */ + struct list_head rxbuf; /* receive buffer */ + spinlock_t rxbuflock; + u32 *rxlink; /* link ptr in last RX desc */ + struct tasklet_struct rxtq; /* rx intr tasklet */ + + struct list_head txbuf; /* transmit buffer */ + spinlock_t txbuflock; + unsigned int txbuf_len; /* buf count in txbuf list */ + struct ath5k_txq txqs[2]; /* beacon and tx */ + + struct ath5k_txq *txq; /* beacon and tx*/ + struct tasklet_struct txtq; /* tx intr tasklet */ + + struct ath5k_buf *bbuf; /* beacon buffer */ + unsigned int bhalq, /* SW q for outgoing beacons */ + bmisscount, /* missed beacon transmits */ + bintval, /* beacon interval in TU */ + bsent; + unsigned int nexttbtt; /* next beacon time in TU */ + + struct timer_list calib_tim; /* calibration timer */ +}; + +#define ath5k_hw_hasbssidmask(_ah) \ + (ath5k_hw_get_capability(_ah, AR5K_CAP_BSSIDMASK, 0, NULL) == 0) +#define ath5k_hw_hasveol(_ah) \ + (ath5k_hw_get_capability(_ah, AR5K_CAP_VEOL, 0, NULL) == 0) + +#endif diff --git a/drivers/net/wireless/ath5k/debug.c b/drivers/net/wireless/ath5k/debug.c new file mode 100644 index 000000000000..4ba649e20269 --- /dev/null +++ b/drivers/net/wireless/ath5k/debug.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com> + * + * This file is free software: you may copy, redistribute 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 file 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 <http://www.gnu.org/licenses/>. + * + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2006 Devicescape Software, Inc. + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "debug.h" +#include "base.h" + +static unsigned int ath5k_debug; +module_param_named(debug, ath5k_debug, uint, 0); + + +#if ATH5K_DEBUG + +#include <linux/seq_file.h> +#include "reg.h" + +static struct dentry *ath5k_global_debugfs; + +static int ath5k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + + +/* debugfs: registers */ + +struct reg { + char *name; + int addr; +}; + +#define REG_STRUCT_INIT(r) { #r, r } + +/* just a few random registers, might want to add more */ +static struct reg regs[] = { + REG_STRUCT_INIT(AR5K_CR), + REG_STRUCT_INIT(AR5K_RXDP), + REG_STRUCT_INIT(AR5K_CFG), + REG_STRUCT_INIT(AR5K_IER), + REG_STRUCT_INIT(AR5K_BCR), + REG_STRUCT_INIT(AR5K_RTSD0), + REG_STRUCT_INIT(AR5K_RTSD1), + REG_STRUCT_INIT(AR5K_TXCFG), + REG_STRUCT_INIT(AR5K_RXCFG), + REG_STRUCT_INIT(AR5K_RXJLA), + REG_STRUCT_INIT(AR5K_MIBC), + REG_STRUCT_INIT(AR5K_TOPS), + REG_STRUCT_INIT(AR5K_RXNOFRM), + REG_STRUCT_INIT(AR5K_TXNOFRM), + REG_STRUCT_INIT(AR5K_RPGTO), + REG_STRUCT_INIT(AR5K_RFCNT), + REG_STRUCT_INIT(AR5K_MISC), + REG_STRUCT_INIT(AR5K_QCUDCU_CLKGT), + REG_STRUCT_INIT(AR5K_ISR), + REG_STRUCT_INIT(AR5K_PISR), + REG_STRUCT_INIT(AR5K_SISR0), + REG_STRUCT_INIT(AR5K_SISR1), + REG_STRUCT_INIT(AR5K_SISR2), + REG_STRUCT_INIT(AR5K_SISR3), + REG_STRUCT_INIT(AR5K_SISR4), + REG_STRUCT_INIT(AR5K_IMR), + REG_STRUCT_INIT(AR5K_PIMR), + REG_STRUCT_INIT(AR5K_SIMR0), + REG_STRUCT_INIT(AR5K_SIMR1), + REG_STRUCT_INIT(AR5K_SIMR2), + REG_STRUCT_INIT(AR5K_SIMR3), + REG_STRUCT_INIT(AR5K_SIMR4), + REG_STRUCT_INIT(AR5K_DCM_ADDR), + REG_STRUCT_INIT(AR5K_DCCFG), + REG_STRUCT_INIT(AR5K_CCFG), + REG_STRUCT_INIT(AR5K_CPC0), + REG_STRUCT_INIT(AR5K_CPC1), + REG_STRUCT_INIT(AR5K_CPC2), + REG_STRUCT_INIT(AR5K_CPC3), + REG_STRUCT_INIT(AR5K_CPCORN), + REG_STRUCT_INIT(AR5K_RESET_CTL), + REG_STRUCT_INIT(AR5K_SLEEP_CTL), + REG_STRUCT_INIT(AR5K_INTPEND), + REG_STRUCT_INIT(AR5K_SFR), + REG_STRUCT_INIT(AR5K_PCICFG), + REG_STRUCT_INIT(AR5K_GPIOCR), + REG_STRUCT_INIT(AR5K_GPIODO), + REG_STRUCT_INIT(AR5K_SREV), +}; + +static void *reg_start(struct seq_file *seq, loff_t *pos) +{ + return *pos < ARRAY_SIZE(regs) ? ®s[*pos] : NULL; +} + +static void reg_stop(struct seq_file *seq, void *p) +{ + /* nothing to do */ +} + +static void *reg_next(struct seq_file *seq, void *p, loff_t *pos) +{ + ++*pos; + return *pos < ARRAY_SIZE(regs) ? ®s[*pos] : NULL; +} + +static int reg_show(struct seq_file *seq, void *p) +{ + struct ath5k_softc *sc = seq->private; + struct reg *r = p; + seq_printf(seq, "%-25s0x%08x\n", r->name, + ath5k_hw_reg_read(sc->ah, r->addr)); + return 0; +} + +static struct seq_operations register_seq_ops = { + .start = reg_start, + .next = reg_next, + .stop = reg_stop, + .show = reg_show +}; + +static int open_file_registers(struct inode *inode, struct file *file) +{ + struct seq_file *s; + int res; + res = seq_open(file, ®ister_seq_ops); + if (res == 0) { + s = file->private_data; + s->private = inode->i_private; + } + return res; +} + +static const struct file_operations fops_registers = { + .open = open_file_registers, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .owner = THIS_MODULE, +}; + + +/* debugfs: TSF */ + +static ssize_t read_file_tsf(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + char buf[100]; + snprintf(buf, 100, "0x%016llx\n", ath5k_hw_get_tsf64(sc->ah)); + return simple_read_from_buffer(user_buf, count, ppos, buf, 19); +} + +static ssize_t write_file_tsf(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + if (strncmp(userbuf, "reset", 5) == 0) { + ath5k_hw_reset_tsf(sc->ah); + printk(KERN_INFO "debugfs reset TSF\n"); + } + return count; +} + +static const struct file_operations fops_tsf = { + .read = read_file_tsf, + .write = write_file_tsf, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* debugfs: beacons */ + +static ssize_t read_file_beacon(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + char buf[1000]; + int len = 0; + unsigned int v; + u64 tsf; + + v = ath5k_hw_reg_read(sc->ah, AR5K_BEACON); + len += snprintf(buf+len, sizeof(buf)-len, + "%-24s0x%08x\tintval: %d\tTIM: 0x%x\n", + "AR5K_BEACON", v, v & AR5K_BEACON_PERIOD, + (v & AR5K_BEACON_TIM) >> AR5K_BEACON_TIM_S); + + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n", + "AR5K_LAST_TSTP", ath5k_hw_reg_read(sc->ah, AR5K_LAST_TSTP)); + + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\n\n", + "AR5K_BEACON_CNT", ath5k_hw_reg_read(sc->ah, AR5K_BEACON_CNT)); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER0); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER0 (TBTT)", v, v); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER1); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER1 (DMA)", v, v >> 3); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER2); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER2 (SWBA)", v, v >> 3); + + v = ath5k_hw_reg_read(sc->ah, AR5K_TIMER3); + len += snprintf(buf+len, sizeof(buf)-len, "%-24s0x%08x\tTU: %08x\n", + "AR5K_TIMER3 (ATIM)", v, v); + + tsf = ath5k_hw_get_tsf64(sc->ah); + len += snprintf(buf+len, sizeof(buf)-len, + "TSF\t\t0x%016llx\tTU: %08x\n", tsf, TSF_TO_TU(tsf)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t write_file_beacon(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + struct ath5k_hw *ah = sc->ah; + + if (strncmp(userbuf, "disable", 7) == 0) { + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); + printk(KERN_INFO "debugfs disable beacons\n"); + } else if (strncmp(userbuf, "enable", 6) == 0) { + AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE); + printk(KERN_INFO "debugfs enable beacons\n"); + } + return count; +} + +static const struct file_operations fops_beacon = { + .read = read_file_beacon, + .write = write_file_beacon, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* debugfs: reset */ + +static ssize_t write_file_reset(struct file *file, + const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct ath5k_softc *sc = file->private_data; + tasklet_schedule(&sc->restq); + return count; +} + +static const struct file_operations fops_reset = { + .write = write_file_reset, + .open = ath5k_debugfs_open, + .owner = THIS_MODULE, +}; + + +/* init */ + +void +ath5k_debug_init(void) +{ + ath5k_global_debugfs = debugfs_create_dir("ath5k", NULL); +} + +void +ath5k_debug_init_device(struct ath5k_softc *sc) +{ + sc->debug.level = ath5k_debug; + sc->debug.debugfs_phydir = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + ath5k_global_debugfs); + sc->debug.debugfs_debug = debugfs_create_u32("debug", + 0666, sc->debug.debugfs_phydir, &sc->debug.level); + + sc->debug.debugfs_registers = debugfs_create_file("registers", 0444, + sc->debug.debugfs_phydir, + sc, &fops_registers); + + sc->debug.debugfs_tsf = debugfs_create_file("tsf", 0666, + sc->debug.debugfs_phydir, + sc, &fops_tsf); + + sc->debug.debugfs_beacon = debugfs_create_file("beacon", 0666, + sc->debug.debugfs_phydir, + sc, &fops_beacon); + + sc->debug.debugfs_reset = debugfs_create_file("reset", 0222, + sc->debug.debugfs_phydir, + sc, &fops_reset); +} + +void +ath5k_debug_finish(void) +{ + debugfs_remove(ath5k_global_debugfs); +} + +void +ath5k_debug_finish_device(struct ath5k_softc *sc) +{ + debugfs_remove(sc->debug.debugfs_debug); + debugfs_remove(sc->debug.debugfs_registers); + debugfs_remove(sc->debug.debugfs_tsf); + debugfs_remove(sc->debug.debugfs_beacon); + debugfs_remove(sc->debug.debugfs_reset); + debugfs_remove(sc->debug.debugfs_phydir); +} + + +/* functions used in other places */ + +void +ath5k_debug_dump_modes(struct ath5k_softc *sc, struct ieee80211_hw_mode *modes) +{ + unsigned int m, i; + + if (likely(!(sc->debug.level & ATH5K_DEBUG_DUMPMODES))) + return; + + for (m = 0; m < NUM_DRIVER_MODES; m++) { + printk(KERN_DEBUG "Mode %u: channels %d, rates %d\n", m, + modes[m].num_channels, modes[m].num_rates); + printk(KERN_DEBUG " channels:\n"); + for (i = 0; i < modes[m].num_channels; i++) + printk(KERN_DEBUG " %3d %d %.4x %.4x\n", + modes[m].channels[i].chan, + modes[m].channels[i].freq, + modes[m].channels[i].val, + modes[m].channels[i].flag); + printk(KERN_DEBUG " rates:\n"); + for (i = 0; i < modes[m].num_rates; i++) + printk(KERN_DEBUG " %4d %.4x %.4x %.4x\n", + modes[m].rates[i].rate, + modes[m].rates[i].val, + modes[m].rates[i].flags, + modes[m].rates[i].val2); + } +} + +static inline void +ath5k_debug_printrxbuf(struct ath5k_buf *bf, int done) +{ + struct ath5k_desc *ds = bf->desc; + + printk(KERN_DEBUG "R (%p %llx) %08x %08x %08x %08x %08x %08x %c\n", + ds, (unsigned long long)bf->daddr, + ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, + ds->ds_hw[0], ds->ds_hw[1], + !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); +} + +void +ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) +{ + struct ath5k_desc *ds; + struct ath5k_buf *bf; + int status; + + if (likely(!(sc->debug.level & + (ATH5K_DEBUG_RESET | ATH5K_DEBUG_FATAL)))) + return; + + printk(KERN_DEBUG "rx queue %x, link %p\n", + ath5k_hw_get_rx_buf(ah), sc->rxlink); + + spin_lock_bh(&sc->rxbuflock); + list_for_each_entry(bf, &sc->rxbuf, list) { + ds = bf->desc; + status = ah->ah_proc_rx_desc(ah, ds); + if (!status || (sc->debug.level & ATH5K_DEBUG_FATAL)) + ath5k_debug_printrxbuf(bf, status == 0); + } + spin_unlock_bh(&sc->rxbuflock); +} + +void +ath5k_debug_dump_skb(struct ath5k_softc *sc, + struct sk_buff *skb, const char *prefix, int tx) +{ + char buf[16]; + + if (likely(!((tx && (sc->debug.level & ATH5K_DEBUG_DUMP_TX)) || + (!tx && (sc->debug.level & ATH5K_DEBUG_DUMP_RX))))) + return; + + snprintf(buf, sizeof(buf), "%s %s", wiphy_name(sc->hw->wiphy), prefix); + + print_hex_dump_bytes(buf, DUMP_PREFIX_NONE, skb->data, + min(200U, skb->len)); + + printk(KERN_DEBUG "\n"); +} + +void +ath5k_debug_printtxbuf(struct ath5k_softc *sc, + struct ath5k_buf *bf, int done) +{ + struct ath5k_desc *ds = bf->desc; + + if (likely(!(sc->debug.level & ATH5K_DEBUG_RESET))) + return; + + printk(KERN_DEBUG "T (%p %llx) %08x %08x %08x %08x %08x %08x %08x " + "%08x %c\n", ds, (unsigned long long)bf->daddr, ds->ds_link, + ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, + ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3], + !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'); +} + +#endif /* if ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath5k/debug.h b/drivers/net/wireless/ath5k/debug.h new file mode 100644 index 000000000000..2b491cbc8c80 --- /dev/null +++ b/drivers/net/wireless/ath5k/debug.h @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2007 Bruno Randolf <bruno@thinktube.com> + * + * This file is free software: you may copy, redistribute 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 file 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 <http://www.gnu.org/licenses/>. + * + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting + * Copyright (c) 2004-2005 Atheros Communications, Inc. + * Copyright (c) 2006 Devicescape Software, Inc. + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.edu> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef _ATH5K_DEBUG_H +#define _ATH5K_DEBUG_H + +/* set this to 1 for debugging output */ +#ifndef ATH5K_DEBUG +#define ATH5K_DEBUG 0 +#endif + +struct ath5k_softc; +struct ath5k_hw; +struct ieee80211_hw_mode; +struct sk_buff; +struct ath5k_buf; + +struct ath5k_dbg_info { + unsigned int level; /* debug level */ + /* debugfs entries */ + struct dentry *debugfs_phydir; + struct dentry *debugfs_debug; + struct dentry *debugfs_registers; + struct dentry *debugfs_tsf; + struct dentry *debugfs_beacon; + struct dentry *debugfs_reset; +}; + +/** + * enum ath5k_debug_level - ath5k debug level + * + * @ATH5K_DEBUG_RESET: reset processing + * @ATH5K_DEBUG_INTR: interrupt handling + * @ATH5K_DEBUG_MODE: mode init/setup + * @ATH5K_DEBUG_XMIT: basic xmit operation + * @ATH5K_DEBUG_BEACON: beacon handling + * @ATH5K_DEBUG_BEACON_PROC: beacon ISR proc + * @ATH5K_DEBUG_CALIBRATE: periodic calibration + * @ATH5K_DEBUG_TXPOWER: transmit power setting + * @ATH5K_DEBUG_LED: led management + * @ATH5K_DEBUG_DUMP_RX: print received skb content + * @ATH5K_DEBUG_DUMP_TX: print transmit skb content + * @ATH5K_DEBUG_DUMPMODES: dump modes + * @ATH5K_DEBUG_TRACE: trace function calls + * @ATH5K_DEBUG_FATAL: fatal errors + * @ATH5K_DEBUG_ANY: show at any debug level + * + * The debug level is used to control the amount and type of debugging output + * we want to see. The debug level is given in calls to ATH5K_DBG to specify + * where the message should appear, and the user can control the debugging + * messages he wants to see, either by the module parameter 'debug' on module + * load, or dynamically by using debugfs 'ath5k/phyX/debug'. these levels can + * be combined together by bitwise OR. + */ +enum ath5k_debug_level { + ATH5K_DEBUG_RESET = 0x00000001, + ATH5K_DEBUG_INTR = 0x00000002, + ATH5K_DEBUG_MODE = 0x00000004, + ATH5K_DEBUG_XMIT = 0x00000008, + ATH5K_DEBUG_BEACON = 0x00000010, + ATH5K_DEBUG_BEACON_PROC = 0x00000020, + ATH5K_DEBUG_CALIBRATE = 0x00000100, + ATH5K_DEBUG_TXPOWER = 0x00000200, + ATH5K_DEBUG_LED = 0x00000400, + ATH5K_DEBUG_DUMP_RX = 0x00001000, + ATH5K_DEBUG_DUMP_TX = 0x00002000, + ATH5K_DEBUG_DUMPMODES = 0x00004000, + ATH5K_DEBUG_TRACE = 0x00010000, + ATH5K_DEBUG_FATAL = 0x80000000, + ATH5K_DEBUG_ANY = 0xffffffff +}; + +#if ATH5K_DEBUG + +#define ATH5K_TRACE(_sc) do { \ + if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \ + printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \ + } while (0) + +#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \ + if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \ + ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +#define ATH5K_DBG_UNLIMIT(_sc, _m, _fmt, ...) do { \ + if (unlikely((_sc)->debug.level & (_m))) \ + ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +void +ath5k_debug_init(void); + +void +ath5k_debug_init_device(struct ath5k_softc *sc); + +void +ath5k_debug_finish(void); + +void +ath5k_debug_finish_device(struct ath5k_softc *sc); + +void +ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah); + +void +ath5k_debug_dump_modes(struct ath5k_softc *sc, + struct ieee80211_hw_mode *modes); + +void +ath5k_debug_dump_skb(struct ath5k_softc *sc, + struct sk_buff *skb, const char *prefix, int tx); + +void +ath5k_debug_printtxbuf(struct ath5k_softc *sc, + struct ath5k_buf *bf, int done); + +#else /* no debugging */ + +#define ATH5K_TRACE(_sc) /* empty */ + +static inline void __attribute__ ((format (printf, 3, 4))) +ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {} + +static inline void __attribute__ ((format (printf, 3, 4))) +ATH5K_DBG_UNLIMIT(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) +{} + +static inline void +ath5k_debug_init(void) {} + +static inline void +ath5k_debug_init_device(struct ath5k_softc *sc) {} + +static inline void +ath5k_debug_finish(void) {} + +static inline void +ath5k_debug_finish_device(struct ath5k_softc *sc) {} + +static inline void +ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {} + +static inline void +ath5k_debug_dump_modes(struct ath5k_softc *sc, + struct ieee80211_hw_mode *modes) {} + +static inline void +ath5k_debug_dump_skb(struct ath5k_softc *sc, + struct sk_buff *skb, const char *prefix, int tx) {} + +static inline void +ath5k_debug_printtxbuf(struct ath5k_softc *sc, + struct ath5k_buf *bf, int done) {} + +#endif /* if ATH5K_DEBUG */ + +#endif /* ifndef _ATH5K_DEBUG_H */ diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c new file mode 100644 index 000000000000..3a4bf4035a23 --- /dev/null +++ b/drivers/net/wireless/ath5k/hw.c @@ -0,0 +1,4351 @@ + /* + * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org> + * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu> + * Copyright (c) 2007 Pavel Roskin <proski@gnu.org> + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* + * HW related functions for Atheros Wireless LAN devices. + */ + +#include <linux/pci.h> +#include <linux/delay.h> + +#include "reg.h" +#include "base.h" +#include "debug.h" + +/*Rate tables*/ +static const struct ath5k_rate_table ath5k_rt_11a = AR5K_RATES_11A; +static const struct ath5k_rate_table ath5k_rt_11b = AR5K_RATES_11B; +static const struct ath5k_rate_table ath5k_rt_11g = AR5K_RATES_11G; +static const struct ath5k_rate_table ath5k_rt_turbo = AR5K_RATES_TURBO; +static const struct ath5k_rate_table ath5k_rt_xr = AR5K_RATES_XR; + +/*Prototypes*/ +static int ath5k_hw_nic_reset(struct ath5k_hw *, u32); +static int ath5k_hw_nic_wakeup(struct ath5k_hw *, int, bool); +static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, + unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int); +static bool ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *, struct ath5k_desc *, + unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, + unsigned int); +static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *, struct ath5k_desc *); +static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *, struct ath5k_desc *, + unsigned int, unsigned int, enum ath5k_pkt_type, unsigned int, + unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, + unsigned int, unsigned int); +static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *, struct ath5k_desc *); +static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *, struct ath5k_desc *); +static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *, struct ath5k_desc *); +static int ath5k_hw_get_capabilities(struct ath5k_hw *); + +static int ath5k_eeprom_init(struct ath5k_hw *); +static int ath5k_eeprom_read_mac(struct ath5k_hw *, u8 *); + +static int ath5k_hw_enable_pspoll(struct ath5k_hw *, u8 *, u16); +static int ath5k_hw_disable_pspoll(struct ath5k_hw *); + +/* + * Enable to overwrite the country code (use "00" for debug) + */ +#if 0 +#define COUNTRYCODE "00" +#endif + +/*******************\ + General Functions +\*******************/ + +/* + * Functions used internaly + */ + +static inline unsigned int ath5k_hw_htoclock(unsigned int usec, bool turbo) +{ + return turbo == true ? (usec * 80) : (usec * 40); +} + +static inline unsigned int ath5k_hw_clocktoh(unsigned int clock, bool turbo) +{ + return turbo == true ? (clock / 80) : (clock / 40); +} + +/* + * Check if a register write has been completed + */ +int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val, + bool is_set) +{ + int i; + u32 data; + + for (i = AR5K_TUNE_REGISTER_TIMEOUT; i > 0; i--) { + data = ath5k_hw_reg_read(ah, reg); + if ((is_set == true) && (data & flag)) + break; + else if ((data & flag) == val) + break; + udelay(15); + } + + return (i <= 0) ? -EAGAIN : 0; +} + + +/***************************************\ + Attach/Detach Functions +\***************************************/ + +/* + * Check if the device is supported and initialize the needed structs + */ +struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) +{ + struct ath5k_hw *ah; + u8 mac[ETH_ALEN]; + int ret; + u32 srev; + + /*If we passed the test malloc a ath5k_hw struct*/ + ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL); + if (ah == NULL) { + ret = -ENOMEM; + ATH5K_ERR(sc, "out of memory\n"); + goto err; + } + + ah->ah_sc = sc; + ah->ah_iobase = sc->iobase; + + /* + * HW information + */ + + /* Get reg domain from eeprom */ + ath5k_get_regdomain(ah); + + ah->ah_op_mode = IEEE80211_IF_TYPE_STA; + ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; + ah->ah_turbo = false; + ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; + ah->ah_imr = 0; + ah->ah_atim_window = 0; + ah->ah_aifs = AR5K_TUNE_AIFS; + ah->ah_cw_min = AR5K_TUNE_CWMIN; + ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY; + ah->ah_software_retry = false; + ah->ah_ant_diversity = AR5K_TUNE_ANT_DIVERSITY; + + /* + * Set the mac revision based on the pci id + */ + ah->ah_version = mac_version; + + /*Fill the ath5k_hw struct with the needed functions*/ + if (ah->ah_version == AR5K_AR5212) + ah->ah_magic = AR5K_EEPROM_MAGIC_5212; + else if (ah->ah_version == AR5K_AR5211) + ah->ah_magic = AR5K_EEPROM_MAGIC_5211; + + if (ah->ah_version == AR5K_AR5212) { + ah->ah_setup_tx_desc = ath5k_hw_setup_4word_tx_desc; + ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; + ah->ah_proc_tx_desc = ath5k_hw_proc_4word_tx_status; + } else { + ah->ah_setup_tx_desc = ath5k_hw_setup_2word_tx_desc; + ah->ah_setup_xtx_desc = ath5k_hw_setup_xr_tx_desc; + ah->ah_proc_tx_desc = ath5k_hw_proc_2word_tx_status; + } + + if (ah->ah_version == AR5K_AR5212) + ah->ah_proc_rx_desc = ath5k_hw_proc_new_rx_status; + else if (ah->ah_version <= AR5K_AR5211) + ah->ah_proc_rx_desc = ath5k_hw_proc_old_rx_status; + + /* Bring device out of sleep and reset it's units */ + ret = ath5k_hw_nic_wakeup(ah, AR5K_INIT_MODE, true); + if (ret) + goto err_free; + + /* Get MAC, PHY and RADIO revisions */ + srev = ath5k_hw_reg_read(ah, AR5K_SREV); + ah->ah_mac_srev = srev; + ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); + ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); + ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & + 0xffffffff; + ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_5GHZ); + + if (ah->ah_version == AR5K_AR5210) + ah->ah_radio_2ghz_revision = 0; + else + ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, + CHANNEL_2GHZ); + + /* Return on unsuported chips (unsupported eeprom etc) */ + if(srev >= AR5K_SREV_VER_AR5416){ + ATH5K_ERR(sc, "Device not yet supported.\n"); + ret = -ENODEV; + goto err_free; + } + + /* Identify single chip solutions */ + if((srev <= AR5K_SREV_VER_AR5414) && + (srev >= AR5K_SREV_VER_AR2424)) { + ah->ah_single_chip = true; + } else { + ah->ah_single_chip = false; + } + + /* Single chip radio */ + if (ah->ah_radio_2ghz_revision == ah->ah_radio_5ghz_revision) + ah->ah_radio_2ghz_revision = 0; + + /* Identify the radio chip*/ + if (ah->ah_version == AR5K_AR5210) { + ah->ah_radio = AR5K_RF5110; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) { + ah->ah_radio = AR5K_RF5111; + } else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) { + ah->ah_radio = AR5K_RF5112; + } else { + ah->ah_radio = AR5K_RF5413; + } + + ah->ah_phy = AR5K_PHY(0); + + /* + * Get card capabilities, values, ... + */ + + ret = ath5k_eeprom_init(ah); + if (ret) { + ATH5K_ERR(sc, "unable to init EEPROM\n"); + goto err_free; + } + + /* Get misc capabilities */ + ret = ath5k_hw_get_capabilities(ah); + if (ret) { + ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n", + sc->pdev->device); + goto err_free; + } + + /* Get MAC address */ + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_free; + } + + ath5k_hw_set_lladdr(ah, mac); + /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ + memset(ah->ah_bssid, 0xff, ETH_ALEN); + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + ath5k_hw_set_opmode(ah); + + ath5k_hw_set_rfgain_opt(ah); + + return ah; +err_free: + kfree(ah); +err: + return ERR_PTR(ret); +} + +/* + * Bring up MAC + PHY Chips + */ +static int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) +{ + u32 turbo, mode, clock; + int ret; + + turbo = 0; + mode = 0; + clock = 0; + + ATH5K_TRACE(ah->ah_sc); + + /* Wakeup the device */ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n"); + return ret; + } + + if (ah->ah_version != AR5K_AR5210) { + /* + * Get channel mode flags + */ + + if (ah->ah_radio >= AR5K_RF5112) { + mode = AR5K_PHY_MODE_RAD_RF5112; + clock = AR5K_PHY_PLL_RF5112; + } else { + mode = AR5K_PHY_MODE_RAD_RF5111; /*Zero*/ + clock = AR5K_PHY_PLL_RF5111; /*Zero*/ + } + + if (flags & CHANNEL_2GHZ) { + mode |= AR5K_PHY_MODE_FREQ_2GHZ; + clock |= AR5K_PHY_PLL_44MHZ; + + if (flags & CHANNEL_CCK) { + mode |= AR5K_PHY_MODE_MOD_CCK; + } else if (flags & CHANNEL_OFDM) { + /* XXX Dynamic OFDM/CCK is not supported by the + * AR5211 so we set MOD_OFDM for plain g (no + * CCK headers) operation. We need to test + * this, 5211 might support ofdm-only g after + * all, there are also initial register values + * in the code for g mode (see initvals.c). */ + if (ah->ah_version == AR5K_AR5211) + mode |= AR5K_PHY_MODE_MOD_OFDM; + else + mode |= AR5K_PHY_MODE_MOD_DYN; + } else { + ATH5K_ERR(ah->ah_sc, + "invalid radio modulation mode\n"); + return -EINVAL; + } + } else if (flags & CHANNEL_5GHZ) { + mode |= AR5K_PHY_MODE_FREQ_5GHZ; + clock |= AR5K_PHY_PLL_40MHZ; + + if (flags & CHANNEL_OFDM) + mode |= AR5K_PHY_MODE_MOD_OFDM; + else { + ATH5K_ERR(ah->ah_sc, + "invalid radio modulation mode\n"); + return -EINVAL; + } + } else { + ATH5K_ERR(ah->ah_sc, "invalid radio frequency mode\n"); + return -EINVAL; + } + + if (flags & CHANNEL_TURBO) + turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT; + } else { /* Reset the device */ + + /* ...enable Atheros turbo mode if requested */ + if (flags & CHANNEL_TURBO) + ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE, + AR5K_PHY_TURBO); + } + + /* ...reset chipset and PCI device */ + if (ah->ah_single_chip == false && ath5k_hw_nic_reset(ah, + AR5K_RESET_CTL_CHIP | AR5K_RESET_CTL_PCI)) { + ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip + PCI\n"); + return -EIO; + } + + if (ah->ah_version == AR5K_AR5210) + udelay(2300); + + /* ...wakeup again!*/ + ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); + if (ret) { + ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n"); + return ret; + } + + /* ...final warm reset */ + if (ath5k_hw_nic_reset(ah, 0)) { + ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n"); + return -EIO; + } + + if (ah->ah_version != AR5K_AR5210) { + /* ...set the PHY operating mode */ + ath5k_hw_reg_write(ah, clock, AR5K_PHY_PLL); + udelay(300); + + ath5k_hw_reg_write(ah, mode, AR5K_PHY_MODE); + ath5k_hw_reg_write(ah, turbo, AR5K_PHY_TURBO); + } + + return 0; +} + +/* + * Get the rate table for a specific operation mode + */ +const struct ath5k_rate_table *ath5k_hw_get_rate_table(struct ath5k_hw *ah, + unsigned int mode) +{ + ATH5K_TRACE(ah->ah_sc); + + if (!test_bit(mode, ah->ah_capabilities.cap_mode)) + return NULL; + + /* Get rate tables */ + switch (mode) { + case MODE_IEEE80211A: + return &ath5k_rt_11a; + case MODE_ATHEROS_TURBO: + return &ath5k_rt_turbo; + case MODE_IEEE80211B: + return &ath5k_rt_11b; + case MODE_IEEE80211G: + return &ath5k_rt_11g; + case MODE_ATHEROS_TURBOG: + return &ath5k_rt_xr; + } + + return NULL; +} + +/* + * Free the ath5k_hw struct + */ +void ath5k_hw_detach(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_rf_banks != NULL) + kfree(ah->ah_rf_banks); + + /* assume interrupts are down */ + kfree(ah); +} + +/****************************\ + Reset function and helpers +\****************************/ + +/** + * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212 + * + * @ah: the &struct ath5k_hw + * @channel: the currently set channel upon reset + * + * Write the OFDM timings for the AR5212 upon reset. This is a helper for + * ath5k_hw_reset(). This seems to tune the PLL a specified frequency + * depending on the bandwidth of the channel. + * + */ +static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + /* Get exponent and mantissa and set it */ + u32 coef_scaled, coef_exp, coef_man, + ds_coef_exp, ds_coef_man, clock; + + if (!(ah->ah_version == AR5K_AR5212) || + !(channel->val & CHANNEL_OFDM)) + BUG(); + + /* Seems there are two PLLs, one for baseband sampling and one + * for tuning. Tuning basebands are 40 MHz or 80MHz when in + * turbo. */ + clock = channel->val & CHANNEL_TURBO ? 80 : 40; + coef_scaled = ((5 * (clock << 24)) / 2) / + channel->freq; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + if (!coef_exp) + return -EINVAL; + + coef_exp = 14 - (coef_exp - 24); + coef_man = coef_scaled + + (1 << (24 - coef_exp - 1)); + ds_coef_man = coef_man >> (24 - coef_exp); + ds_coef_exp = coef_exp - 16; + + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, + AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man); + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3, + AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp); + + return 0; +} + +/** + * ath5k_hw_write_rate_duration - set rate duration during hw resets + * + * @ah: the &struct ath5k_hw + * @driver_mode: one of enum ieee80211_phymode or our one of our own + * vendor modes + * + * Write the rate duration table for the current mode upon hw reset. This + * is a helper for ath5k_hw_reset(). It seems all this is doing is setting + * an ACK timeout for the hardware for the current mode for each rate. The + * rates which are capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, + * and 11Mbps) have another register for the short preamble ACK timeout + * calculation. + * + */ +static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah, + unsigned int driver_mode) +{ + struct ath5k_softc *sc = ah->ah_sc; + const struct ath5k_rate_table *rt; + unsigned int i; + + /* Get rate table for the current operating mode */ + rt = ath5k_hw_get_rate_table(ah, + driver_mode); + + /* Write rate duration table */ + for (i = 0; i < rt->rate_count; i++) { + const struct ath5k_rate *rate, *control_rate; + u32 reg; + u16 tx_time; + + rate = &rt->rates[i]; + control_rate = &rt->rates[rate->control_rate]; + + /* Set ACK timeout */ + reg = AR5K_RATE_DUR(rate->rate_code); + + /* An ACK frame consists of 10 bytes. If you add the FCS, + * which ieee80211_generic_frame_duration() adds, + * its 14 bytes. Note we use the control rate and not the + * actual rate for this rate. See mac80211 tx.c + * ieee80211_duration() for a brief description of + * what rate we should choose to TX ACKs. */ + tx_time = ieee80211_generic_frame_duration(sc->hw, + sc->vif, 10, control_rate->rate_kbps/100); + + ath5k_hw_reg_write(ah, tx_time, reg); + + if (!HAS_SHPREAMBLE(i)) + continue; + + /* + * We're not distinguishing short preamble here, + * This is true, all we'll get is a longer value here + * which is not necessarilly bad. We could use + * export ieee80211_frame_duration() but that needs to be + * fixed first to be properly used by mac802111 drivers: + * + * - remove erp stuff and let the routine figure ofdm + * erp rates + * - remove passing argument ieee80211_local as + * drivers don't have access to it + * - move drivers using ieee80211_generic_frame_duration() + * to this + */ + ath5k_hw_reg_write(ah, tx_time, + reg + (AR5K_SET_SHORT_PREAMBLE << 2)); + } +} + +/* + * Main reset function + */ +int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode, + struct ieee80211_channel *channel, bool change_channel) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 data, s_seq, s_ant, s_led[3]; + unsigned int i, mode, freq, ee_mode, ant[2], driver_mode = -1; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + s_seq = 0; + s_ant = 0; + ee_mode = 0; + freq = 0; + mode = 0; + + /* + * Save some registers before a reset + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + if (change_channel == true) { + /* Seq number for queue 0 -do this for all queues ? */ + s_seq = ath5k_hw_reg_read(ah, + AR5K_QUEUE_DFS_SEQNUM(0)); + /*Default antenna*/ + s_ant = ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + } + } + + /*GPIOs*/ + s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) & AR5K_PCICFG_LEDSTATE; + s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR); + s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO); + + if (change_channel == true && ah->ah_rf_banks != NULL) + ath5k_hw_get_rf_gain(ah); + + + /*Wakeup the device*/ + ret = ath5k_hw_nic_wakeup(ah, channel->val, false); + if (ret) + return ret; + + /* + * Initialize operating mode + */ + ah->ah_op_mode = op_mode; + + /* + * 5111/5112 Settings + * 5210 only comes with RF5110 + */ + if (ah->ah_version != AR5K_AR5210) { + if (ah->ah_radio != AR5K_RF5111 && + ah->ah_radio != AR5K_RF5112 && + ah->ah_radio != AR5K_RF5413) { + ATH5K_ERR(ah->ah_sc, + "invalid phy radio: %u\n", ah->ah_radio); + return -EINVAL; + } + + switch (channel->val & CHANNEL_MODES) { + case CHANNEL_A: + mode = AR5K_INI_VAL_11A; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + driver_mode = MODE_IEEE80211A; + break; + case CHANNEL_G: + mode = AR5K_INI_VAL_11G; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11G; + driver_mode = MODE_IEEE80211G; + break; + case CHANNEL_B: + mode = AR5K_INI_VAL_11B; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11B; + driver_mode = MODE_IEEE80211B; + break; + case CHANNEL_T: + mode = AR5K_INI_VAL_11A_TURBO; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + driver_mode = MODE_ATHEROS_TURBO; + break; + /*Is this ok on 5211 too ?*/ + case CHANNEL_TG: + mode = AR5K_INI_VAL_11G_TURBO; + freq = AR5K_INI_RFGAIN_2GHZ; + ee_mode = AR5K_EEPROM_MODE_11G; + driver_mode = MODE_ATHEROS_TURBOG; + break; + case CHANNEL_XR: + if (ah->ah_version == AR5K_AR5211) { + ATH5K_ERR(ah->ah_sc, + "XR mode not available on 5211"); + return -EINVAL; + } + mode = AR5K_INI_VAL_XR; + freq = AR5K_INI_RFGAIN_5GHZ; + ee_mode = AR5K_EEPROM_MODE_11A; + driver_mode = MODE_IEEE80211A; + break; + default: + ATH5K_ERR(ah->ah_sc, + "invalid channel: %d\n", channel->freq); + return -EINVAL; + } + + /* PHY access enable */ + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + + } + + ret = ath5k_hw_write_initvals(ah, mode, change_channel); + if (ret) + return ret; + + /* + * 5211/5212 Specific + */ + if (ah->ah_version != AR5K_AR5210) { + /* + * Write initial RF gain settings + * This should work for both 5111/5112 + */ + ret = ath5k_hw_rfgain(ah, freq); + if (ret) + return ret; + + mdelay(1); + + /* + * Write some more initial register settings + */ + if (ah->ah_version > AR5K_AR5211){ /* found on 5213+ */ + ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11)); + + if (channel->val == CHANNEL_G) + ath5k_hw_reg_write(ah, 0x00f80d80, AR5K_PHY(83)); /* 0x00fc0ec0 */ + else + ath5k_hw_reg_write(ah, 0x00000000, AR5K_PHY(83)); + + ath5k_hw_reg_write(ah, 0x000001b5, 0xa228); /* 0x000009b5 */ + ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); + ath5k_hw_reg_write(ah, 0x0000000f, 0x8060); + ath5k_hw_reg_write(ah, 0x00000000, 0xa254); + ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL); + } + + /* Fix for first revision of the RF5112 RF chipset */ + if (ah->ah_radio >= AR5K_RF5112 && + ah->ah_radio_5ghz_revision < + AR5K_SREV_RAD_5112A) { + ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, + AR5K_PHY_CCKTXCTL); + if (channel->val & CHANNEL_5GHZ) + data = 0xffb81020; + else + data = 0xffb80d20; + ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL); + } + + /* + * Set TX power (FIXME) + */ + ret = ath5k_hw_txpower(ah, channel, AR5K_TUNE_DEFAULT_TXPOWER); + if (ret) + return ret; + + /* Write rate duration table only on AR5212 and if + * virtual interface has already been brought up + * XXX: rethink this after new mode changes to + * mac80211 are integrated */ + if (ah->ah_version == AR5K_AR5212 && + ah->ah_sc->vif != NULL) + ath5k_hw_write_rate_duration(ah, driver_mode); + + /* + * Write RF registers + * TODO:Does this work on 5211 (5111) ? + */ + ret = ath5k_hw_rfregs(ah, channel, mode); + if (ret) + return ret; + + /* + * Configure additional registers + */ + + /* Write OFDM timings on 5212*/ + if (ah->ah_version == AR5K_AR5212 && + channel->val & CHANNEL_OFDM) { + ret = ath5k_hw_write_ofdm_timings(ah, channel); + if (ret) + return ret; + } + + /*Enable/disable 802.11b mode on 5111 + (enable 2111 frequency converter + CCK)*/ + if (ah->ah_radio == AR5K_RF5111) { + if (driver_mode == MODE_IEEE80211B) + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_B_MODE); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_B_MODE); + } + + /* + * Set channel and calibrate the PHY + */ + ret = ath5k_hw_channel(ah, channel); + if (ret) + return ret; + + /* Set antenna mode */ + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44), + ah->ah_antenna[ee_mode][0], 0xfffffc06); + + /* + * In case a fixed antenna was set as default + * write the same settings on both AR5K_PHY_ANT_SWITCH_TABLE + * registers. + */ + if (s_ant != 0){ + if (s_ant == AR5K_ANT_FIXED_A) /* 1 - Main */ + ant[0] = ant[1] = AR5K_ANT_FIXED_A; + else /* 2 - Aux */ + ant[0] = ant[1] = AR5K_ANT_FIXED_B; + } else { + ant[0] = AR5K_ANT_FIXED_A; + ant[1] = AR5K_ANT_FIXED_B; + } + + ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[0]], + AR5K_PHY_ANT_SWITCH_TABLE_0); + ath5k_hw_reg_write(ah, ah->ah_antenna[ee_mode][ant[1]], + AR5K_PHY_ANT_SWITCH_TABLE_1); + + /* Commit values from EEPROM */ + if (ah->ah_radio == AR5K_RF5111) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, + AR5K_PHY_FRAME_CTL_TX_CLIP, ee->ee_tx_clip); + + ath5k_hw_reg_write(ah, + AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]), + AR5K_PHY(0x5a)); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11), + (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, + 0xffffc07f); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12), + (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, + 0xfffc0fff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14), + (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | + ((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00), + 0xffff0000); + + ath5k_hw_reg_write(ah, + (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)); + + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a), + ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19), + (ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff); + AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, + AR5K_PHY_IQ_CORR_ENABLE | + (ee->ee_i_cal[ee_mode] << AR5K_PHY_IQ_CORR_Q_I_COFF_S) | + ee->ee_q_cal[ee_mode]); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + AR5K_REG_WRITE_BITS(ah, AR5K_PHY_GAIN_2GHZ, + AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX, + ee->ee_margin_tx_rx[ee_mode]); + + } else { + mdelay(1); + /* Disable phy and wait */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); + mdelay(1); + } + + /* + * Restore saved values + */ + /*DCU/Antenna selection not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, s_seq, AR5K_QUEUE_DFS_SEQNUM(0)); + ath5k_hw_reg_write(ah, s_ant, AR5K_DEFAULT_ANTENNA); + } + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, s_led[0]); + ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR); + ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO); + + /* + * Misc + */ + /* XXX: add ah->aid once mac80211 gives this to us */ + ath5k_hw_set_associd(ah, ah->ah_bssid, 0); + + ath5k_hw_set_opmode(ah); + /*PISR/SISR Not available on 5210*/ + if (ah->ah_version != AR5K_AR5210) { + ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR); + /* If we later allow tuning for this, store into sc structure */ + data = AR5K_TUNE_RSSI_THRES | + AR5K_TUNE_BMISS_THRES << AR5K_RSSI_THR_BMISS_S; + ath5k_hw_reg_write(ah, data, AR5K_RSSI_THR); + } + + /* + * Set Rx/Tx DMA Configuration + *(passing dma size not available on 5210) + */ + if (ah->ah_version != AR5K_AR5210) { + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_SDMAMR, + AR5K_DMASIZE_512B | AR5K_TXCFG_DMASIZE); + AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_SDMAMW, + AR5K_DMASIZE_512B); + } + + /* + * Enable the PHY and wait until completion + */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + + /* + * 5111/5112 Specific + */ + if (ah->ah_version != AR5K_AR5210) { + data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & + AR5K_PHY_RX_DELAY_M; + data = (channel->val & CHANNEL_CCK) ? + ((data << 2) / 22) : (data / 10); + + udelay(100 + data); + } else { + mdelay(1); + } + + /* + * Enable calibration and wait until completion + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL); + + if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL, 0, false)) { + ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", + channel->freq); + return -EAGAIN; + } + + ret = ath5k_hw_noise_floor_calibration(ah, channel->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 (!(driver_mode == MODE_IEEE80211B)) { + 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 + */ + for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { + /*No QCU on 5210*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(i), i); + + ret = ath5k_hw_reset_tx_queue(ah, i); + if (ret) { + ATH5K_ERR(ah->ah_sc, + "failed to reset TX queue #%d\n", i); + return ret; + } + } + + /* Pre-enable interrupts on 5211/5212*/ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_set_intr(ah, AR5K_INT_RX | AR5K_INT_TX | + AR5K_INT_FATAL); + + /* + * Set RF kill flags if supported by the device (read from the EEPROM) + * Disable gpio_intr for now since it results system hang. + * TODO: Handle this in ath5k_intr + */ +#if 0 + if (AR5K_EEPROM_HDR_RFKILL(ah->ah_capabilities.cap_eeprom.ee_header)) { + ath5k_hw_set_gpio_input(ah, 0); + ah->ah_gpio[0] = ath5k_hw_get_gpio(ah, 0); + if (ah->ah_gpio[0] == 0) + ath5k_hw_set_gpio_intr(ah, 0, 1); + else + ath5k_hw_set_gpio_intr(ah, 0, 0); + } +#endif + + /* + * Set the 32MHz reference clock on 5212 phy clock sleep register + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, AR5K_PHY_SCR_32MHZ, AR5K_PHY_SCR); + ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT); + ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ, AR5K_PHY_SCAL); + 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_radio == AR5K_RF5111 ? + AR5K_PHY_SPENDING_RF5111 : AR5K_PHY_SPENDING_RF5112, + AR5K_PHY_SPENDING); + } + + /* + * Disable beacons and reset the register + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_ENABLE | + AR5K_BEACON_RESET_TSF); + + return 0; +} + +/* + * Reset chipset + */ +static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val) +{ + int ret; + u32 mask = val ? val : ~0U; + + ATH5K_TRACE(ah->ah_sc); + + /* Read-and-clear RX Descriptor Pointer*/ + ath5k_hw_reg_read(ah, AR5K_RXDP); + + /* + * Reset the device and wait until success + */ + ath5k_hw_reg_write(ah, val, AR5K_RESET_CTL); + + /* Wait at least 128 PCI clocks */ + udelay(15); + + if (ah->ah_version == AR5K_AR5210) { + val &= AR5K_RESET_CTL_CHIP; + mask &= AR5K_RESET_CTL_CHIP; + } else { + val &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; + mask &= AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_BASEBAND; + } + + ret = ath5k_hw_register_timeout(ah, AR5K_RESET_CTL, mask, val, false); + + /* + * Reset configuration register (for hw byte-swap). Note that this + * is only set for big endian. We do the necessary magic in + * AR5K_INIT_CFG. + */ + if ((val & AR5K_RESET_CTL_PCU) == 0) + ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG); + + return ret; +} + +/* + * Power management functions + */ + +/* + * Sleep control + */ +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; + + ATH5K_TRACE(ah->ah_sc); + staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1); + + switch (mode) { + case AR5K_PM_AUTO: + staid &= ~AR5K_STA_ID1_DEFAULT_ANTENNA; + /* fallthrough */ + case AR5K_PM_NETWORK_SLEEP: + if (set_chip == true) + ath5k_hw_reg_write(ah, + AR5K_SLEEP_CTL_SLE | sleep_duration, + AR5K_SLEEP_CTL); + + staid |= AR5K_STA_ID1_PWR_SV; + break; + + case AR5K_PM_FULL_SLEEP: + if (set_chip == true) + ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_SLP, + AR5K_SLEEP_CTL); + + staid |= AR5K_STA_ID1_PWR_SV; + break; + + case AR5K_PM_AWAKE: + if (set_chip == false) + goto commit; + + ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, + AR5K_SLEEP_CTL); + + for (i = 5000; i > 0; i--) { + /* Check if the chip did wake up */ + if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) & + AR5K_PCICFG_SPWR_DN) == 0) + break; + + /* Wait a bit and retry */ + udelay(200); + ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE, + AR5K_SLEEP_CTL); + } + + /* Fail if the chip didn't wake up */ + if (i <= 0) + return -EIO; + + staid &= ~AR5K_STA_ID1_PWR_SV; + break; + + default: + return -EINVAL; + } + +commit: + ah->ah_power_mode = mode; + ath5k_hw_reg_write(ah, staid, AR5K_STA_ID1); + + return 0; +} + +/***********************\ + DMA Related Functions +\***********************/ + +/* + * Receive functions + */ + +/* + * Start DMA receive + */ +void ath5k_hw_start_rx(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR); +} + +/* + * Stop DMA receive + */ +int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah) +{ + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR); + + /* + * It may take some time to disable the DMA receive unit + */ + for (i = 2000; i > 0 && + (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0; + i--) + udelay(10); + + return i ? 0 : -EBUSY; +} + +/* + * Get the address of the RX Descriptor + */ +u32 ath5k_hw_get_rx_buf(struct ath5k_hw *ah) +{ + return ath5k_hw_reg_read(ah, AR5K_RXDP); +} + +/* + * Set the address of the RX Descriptor + */ +void ath5k_hw_put_rx_buf(struct ath5k_hw *ah, u32 phys_addr) +{ + ATH5K_TRACE(ah->ah_sc); + + /*TODO:Shouldn't we check if RX is enabled first ?*/ + ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP); +} + +/* + * Transmit functions + */ + +/* + * Start DMA transmit for a specific queue + * (see also QCU/DCU functions) + */ +int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue) +{ + u32 tx_queue; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + if (ah->ah_version == AR5K_AR5210) { + tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); + + /* + * Set the queue by type on 5210 + */ + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_queue |= AR5K_CR_TXE0 & ~AR5K_CR_TXD0; + break; + case AR5K_TX_QUEUE_BEACON: + tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, + AR5K_BSR); + break; + case AR5K_TX_QUEUE_CAB: + tx_queue |= AR5K_CR_TXE1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1FV | AR5K_BCR_TQ1V | + AR5K_BCR_BDMAE, AR5K_BSR); + break; + default: + return -EINVAL; + } + /* Start queue */ + ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + } else { + /* Return if queue is disabled */ + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue)) + return -EIO; + + /* Start queue */ + AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXE, queue); + } + + return 0; +} + +/* + * Stop DMA transmit for a specific queue + * (see also QCU/DCU functions) + */ +int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue) +{ + unsigned int i = 100; + u32 tx_queue, pending; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + if (ah->ah_version == AR5K_AR5210) { + tx_queue = ath5k_hw_reg_read(ah, AR5K_CR); + + /* + * Set by queue type + */ + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_queue |= AR5K_CR_TXD0 & ~AR5K_CR_TXE0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + /* XXX Fix me... */ + tx_queue |= AR5K_CR_TXD1 & ~AR5K_CR_TXD1; + ath5k_hw_reg_write(ah, 0, AR5K_BSR); + break; + default: + return -EINVAL; + } + + /* Stop queue */ + ath5k_hw_reg_write(ah, tx_queue, AR5K_CR); + } else { + /* + * Schedule TX disable and wait until queue is empty + */ + AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue); + + /*Check for pending frames*/ + do { + pending = ath5k_hw_reg_read(ah, + AR5K_QUEUE_STATUS(queue)) & + AR5K_QCU_STS_FRMPENDCNT; + udelay(100); + } while (--i && pending); + + /* Clear register */ + ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD); + } + + /* TODO: Check for success else return error */ + return 0; +} + +/* + * Get the address of the TX Descriptor for a specific queue + * (see also QCU/DCU functions) + */ +u32 ath5k_hw_get_tx_buf(struct ath5k_hw *ah, unsigned int queue) +{ + u16 tx_reg; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* + * Get the transmit queue descriptor pointer from the selected queue + */ + /*5210 doesn't have QCU*/ + if (ah->ah_version == AR5K_AR5210) { + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_reg = AR5K_NOQCU_TXDP0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + tx_reg = AR5K_NOQCU_TXDP1; + break; + default: + return 0xffffffff; + } + } else { + tx_reg = AR5K_QUEUE_TXDP(queue); + } + + return ath5k_hw_reg_read(ah, tx_reg); +} + +/* + * Set the address of the TX Descriptor for a specific queue + * (see also QCU/DCU functions) + */ +int ath5k_hw_put_tx_buf(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr) +{ + u16 tx_reg; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* + * Set the transmit queue descriptor pointer register by type + * on 5210 + */ + if (ah->ah_version == AR5K_AR5210) { + switch (ah->ah_txq[queue].tqi_type) { + case AR5K_TX_QUEUE_DATA: + tx_reg = AR5K_NOQCU_TXDP0; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + tx_reg = AR5K_NOQCU_TXDP1; + break; + default: + return -EINVAL; + } + } else { + /* + * Set the transmit queue descriptor pointer for + * the selected queue on QCU for 5211+ + * (this won't work if the queue is still active) + */ + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue)) + return -EIO; + + tx_reg = AR5K_QUEUE_TXDP(queue); + } + + /* Set descriptor pointer */ + ath5k_hw_reg_write(ah, phys_addr, tx_reg); + + return 0; +} + +/* + * Update tx trigger level + */ +int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase) +{ + u32 trigger_level, imr; + int ret = -EIO; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Disable interrupts by setting the mask + */ + imr = ath5k_hw_set_intr(ah, ah->ah_imr & ~AR5K_INT_GLOBAL); + + /*TODO: Boundary check on trigger_level*/ + trigger_level = AR5K_REG_MS(ath5k_hw_reg_read(ah, AR5K_TXCFG), + AR5K_TXCFG_TXFULL); + + if (increase == false) { + if (--trigger_level < AR5K_TUNE_MIN_TX_FIFO_THRES) + goto done; + } else + trigger_level += + ((AR5K_TUNE_MAX_TX_FIFO_THRES - trigger_level) / 2); + + /* + * Update trigger level on success + */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, trigger_level, AR5K_TRIG_LVL); + else + AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, + AR5K_TXCFG_TXFULL, trigger_level); + + ret = 0; + +done: + /* + * Restore interrupt mask + */ + ath5k_hw_set_intr(ah, imr); + + return ret; +} + +/* + * Interrupt handling + */ + +/* + * Check if we have pending interrupts + */ +bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_reg_read(ah, AR5K_INTPEND); +} + +/* + * Get interrupt mask (ISR) + */ +int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) +{ + u32 data; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Read interrupt status from the Interrupt Status register + * on 5210 + */ + if (ah->ah_version == AR5K_AR5210) { + data = ath5k_hw_reg_read(ah, AR5K_ISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } + } else { + /* + * Read interrupt status from the Read-And-Clear shadow register + * Note: PISR/SISR Not available on 5210 + */ + data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + } + + /* + * Get abstract interrupt mask (driver-compatible) + */ + *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; + + if (unlikely(data == AR5K_INT_NOCARD)) + return -ENODEV; + + if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) + *interrupt_mask |= AR5K_INT_RX; + + if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR + | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) + *interrupt_mask |= AR5K_INT_TX; + + if (ah->ah_version != AR5K_AR5210) { + /*HIU = Host Interface Unit (PCI etc)*/ + if (unlikely(data & (AR5K_ISR_HIUERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /*Beacon Not Ready*/ + if (unlikely(data & (AR5K_ISR_BNR))) + *interrupt_mask |= AR5K_INT_BNR; + } + + /* + * XXX: BMISS interrupts may occur after association. + * I found this on 5210 code but it needs testing. If this is + * true we should disable them before assoc and re-enable them + * after a successfull assoc + some jiffies. + */ +#if 0 + interrupt_mask &= ~AR5K_INT_BMISS; +#endif + + /* + * In case we didn't handle anything, + * print the register value. + */ + if (unlikely(*interrupt_mask == 0 && net_ratelimit())) + ATH5K_PRINTF("0x%08x\n", data); + + return 0; +} + +/* + * Set interrupt mask + */ +enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask) +{ + enum ath5k_int old_mask, int_mask; + + /* + * Disable card interrupts to prevent any race conditions + * (they will be re-enabled afterwards). + */ + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + + old_mask = ah->ah_imr; + + /* + * Add additional, chipset-dependent interrupt mask flags + * and write them to the IMR (interrupt mask register). + */ + int_mask = new_mask & AR5K_INT_COMMON; + + if (new_mask & AR5K_INT_RX) + int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | + AR5K_IMR_RXDESC; + + if (new_mask & AR5K_INT_TX) + int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | + AR5K_IMR_TXURN; + + if (ah->ah_version != AR5K_AR5210) { + if (new_mask & AR5K_INT_FATAL) { + int_mask |= AR5K_IMR_HIUERR; + AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | + AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); + } + } + + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + + /* Store new interrupt mask */ + ah->ah_imr = new_mask; + + /* ..re-enable interrupts */ + ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); + + return old_mask; +} + + +/*************************\ + EEPROM access functions +\*************************/ + +/* + * Read from eeprom + */ +static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) +{ + u32 status, timeout; + + ATH5K_TRACE(ah->ah_sc); + /* + * Initialize EEPROM access + */ + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); + (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset)); + } else { + ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); + AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, + AR5K_EEPROM_CMD_READ); + } + + for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { + status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); + if (status & AR5K_EEPROM_STAT_RDDONE) { + if (status & AR5K_EEPROM_STAT_RDERR) + return -EIO; + *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) & + 0xffff); + return 0; + } + udelay(15); + } + + return -ETIMEDOUT; +} + +/* + * Write to eeprom - currently disabled, use at your own risk + */ +static int ath5k_hw_eeprom_write(struct ath5k_hw *ah, u32 offset, u16 data) +{ +#if 0 + u32 status, timeout; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Initialize eeprom access + */ + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE); + } else { + AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, + AR5K_EEPROM_CMD_RESET); + } + + /* + * Write data to data register + */ + + if (ah->ah_version == AR5K_AR5210) { + ath5k_hw_reg_write(ah, data, AR5K_EEPROM_BASE + (4 * offset)); + } else { + ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE); + ath5k_hw_reg_write(ah, data, AR5K_EEPROM_DATA); + AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD, + AR5K_EEPROM_CMD_WRITE); + } + + /* + * Check status + */ + + for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) { + status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS); + if (status & AR5K_EEPROM_STAT_WRDONE) { + if (status & AR5K_EEPROM_STAT_WRERR) + return EIO; + return 0; + } + udelay(15); + } +#endif + ATH5K_ERR(ah->ah_sc, "EEPROM Write is disabled!"); + return -EIO; +} + +/* + * Translate binary channel representation in EEPROM to frequency + */ +static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, unsigned int mode) +{ + u16 val; + + if (bin == AR5K_EEPROM_CHANNEL_DIS) + return bin; + + if (mode == AR5K_EEPROM_MODE_11A) { + if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + val = (5 * bin) + 4800; + else + val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : + (bin * 10) + 5100; + } else { + if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + val = bin + 2300; + else + val = bin + 2400; + } + + return val; +} + +/* + * Read antenna infos from eeprom + */ +static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, + unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 o = *offset; + u16 val; + int ret, i = 0; + + AR5K_EEPROM_READ(o++, val); + ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; + ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] = (val >> 10) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 4) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 2) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 14) & 0x3; + ee->ee_ant_control[mode][i++] = (val >> 8) & 0x3f; + ee->ee_ant_control[mode][i++] = (val >> 2) & 0x3f; + ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ant_control[mode][i++] |= (val >> 12) & 0xf; + ee->ee_ant_control[mode][i++] = (val >> 6) & 0x3f; + ee->ee_ant_control[mode][i++] = val & 0x3f; + + /* Get antenna modes */ + ah->ah_antenna[mode][0] = + (ee->ee_ant_control[mode][0] << 4) | 0x1; + ah->ah_antenna[mode][AR5K_ANT_FIXED_A] = + ee->ee_ant_control[mode][1] | + (ee->ee_ant_control[mode][2] << 6) | + (ee->ee_ant_control[mode][3] << 12) | + (ee->ee_ant_control[mode][4] << 18) | + (ee->ee_ant_control[mode][5] << 24); + ah->ah_antenna[mode][AR5K_ANT_FIXED_B] = + ee->ee_ant_control[mode][6] | + (ee->ee_ant_control[mode][7] << 6) | + (ee->ee_ant_control[mode][8] << 12) | + (ee->ee_ant_control[mode][9] << 18) | + (ee->ee_ant_control[mode][10] << 24); + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Read supported modes from eeprom + */ +static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, + unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 o = *offset; + u16 val; + int ret; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; + ee->ee_thr_62[mode] = val & 0xff; + + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_thr_62[mode] = mode == AR5K_EEPROM_MODE_11A ? 15 : 28; + + AR5K_EEPROM_READ(o++, val); + ee->ee_tx_end2xpa_disable[mode] = (val >> 8) & 0xff; + ee->ee_tx_frm2xpa_enable[mode] = val & 0xff; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pga_desired_size[mode] = (val >> 8) & 0xff; + + if ((val & 0xff) & 0x80) + ee->ee_noise_floor_thr[mode] = -((((val & 0xff) ^ 0xff)) + 1); + else + ee->ee_noise_floor_thr[mode] = val & 0xff; + + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) + ee->ee_noise_floor_thr[mode] = + mode == AR5K_EEPROM_MODE_11A ? -54 : -1; + + AR5K_EEPROM_READ(o++, val); + ee->ee_xlna_gain[mode] = (val >> 5) & 0xff; + ee->ee_x_gain[mode] = (val >> 1) & 0xf; + ee->ee_xpd[mode] = val & 0x1; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) + ee->ee_fixed_bias[mode] = (val >> 13) & 0x1; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(o++, val); + ee->ee_false_detect[mode] = (val >> 6) & 0x7f; + + if (mode == AR5K_EEPROM_MODE_11A) + ee->ee_xr_power[mode] = val & 0x3f; + else { + ee->ee_ob[mode][0] = val & 0x7; + ee->ee_db[mode][0] = (val >> 3) & 0x7; + } + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_4) { + ee->ee_i_gain[mode] = AR5K_EEPROM_I_GAIN; + ee->ee_cck_ofdm_power_delta = AR5K_EEPROM_CCK_OFDM_DELTA; + } else { + ee->ee_i_gain[mode] = (val >> 13) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_gain[mode] |= (val << 3) & 0x38; + + if (mode == AR5K_EEPROM_MODE_11G) + ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && + mode == AR5K_EEPROM_MODE_11A) { + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && + mode == AR5K_EEPROM_MODE_11G) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + + /* return new offset */ + *offset = o; + + return 0; +} + +/* + * Initialize eeprom & capabilities structs + */ +static int ath5k_eeprom_init(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + unsigned int mode, i; + int ret; + u32 offset; + u16 val; + + /* Initial TX thermal adjustment values */ + ee->ee_tx_clip = 4; + ee->ee_pwd_84 = ee->ee_pwd_90 = 1; + ee->ee_gain_select = 1; + + /* + * Read values from EEPROM and store them in the capability structure + */ + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + + /* Return if we have an old EEPROM */ + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) + return 0; + +#ifdef notyet + /* + * Validate the checksum of the EEPROM date. There are some + * devices with invalid EEPROMs. + */ + for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { + AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); + cksum ^= val; + } + if (cksum != AR5K_EEPROM_INFO_CKSUM) { + ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); + return -EIO; + } +#endif + + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), + ee_ant_gain); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; + } + + /* + * Get conformance test limit values + */ + offset = AR5K_EEPROM_CTL(ah->ah_ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); + + for (i = 0; i < ee->ee_ctls; i++) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctl[i + 1] = val & 0xff; + } + + /* + * Get values for 802.11a (5GHz) + */ + mode = AR5K_EEPROM_MODE_11A; + + ee->ee_turbo_max_power[mode] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + ee->ee_ob[mode][3] = (val >> 5) & 0x7; + ee->ee_db[mode][3] = (val >> 2) & 0x7; + ee->ee_ob[mode][2] = (val << 1) & 0x7; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_ob[mode][2] |= (val >> 15) & 0x1; + ee->ee_db[mode][2] = (val >> 12) & 0x7; + ee->ee_ob[mode][1] = (val >> 9) & 0x7; + ee->ee_db[mode][1] = (val >> 6) & 0x7; + ee->ee_ob[mode][0] = (val >> 3) & 0x7; + ee->ee_db[mode][0] = val & 0x7; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + } + + /* + * Get values for 802.11b (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11B; + offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][0] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + ee->ee_cal_pier[mode][1] = + ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][2] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + } + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + /* + * Get values for 802.11g (2.4GHz) + */ + mode = AR5K_EEPROM_MODE_11G; + offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][0] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + ee->ee_cal_pier[mode][1] = + ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + + AR5K_EEPROM_READ(offset++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_cal_pier[mode][2] = + ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + } + + /* + * Read 5GHz EEPROM channels + */ + + return 0; +} + +/* + * Read the MAC address from eeprom + */ +static int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac) +{ + u8 mac_d[ETH_ALEN]; + u32 total, offset; + u16 data; + int octet, ret; + + memset(mac, 0, ETH_ALEN); + memset(mac_d, 0, ETH_ALEN); + + ret = ath5k_hw_eeprom_read(ah, 0x20, &data); + if (ret) + return ret; + + for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { + ret = ath5k_hw_eeprom_read(ah, offset, &data); + if (ret) + return ret; + + total += data; + mac_d[octet + 1] = data & 0xff; + mac_d[octet] = data >> 8; + octet += 2; + } + + memcpy(mac, mac_d, ETH_ALEN); + + if (!total || total == 3 * 0xffff) + return -EINVAL; + + return 0; +} + +/* + * Read/Write regulatory domain + */ +static bool ath5k_eeprom_regulation_domain(struct ath5k_hw *ah, bool write, + enum ath5k_regdom *regdomain) +{ + u16 ee_regdomain; + + /* Read current value */ + if (write != true) { + ee_regdomain = ah->ah_capabilities.cap_eeprom.ee_regdomain; + *regdomain = ath5k_regdom_to_ieee(ee_regdomain); + return true; + } + + ee_regdomain = ath5k_regdom_from_ieee(*regdomain); + + /* Try to write a new value */ + if (ah->ah_capabilities.cap_eeprom.ee_protect & + AR5K_EEPROM_PROTECT_WR_128_191) + return false; + if (ath5k_hw_eeprom_write(ah, AR5K_EEPROM_REG_DOMAIN, ee_regdomain)!=0) + return false; + + ah->ah_capabilities.cap_eeprom.ee_regdomain = ee_regdomain; + + return true; +} + +/* + * Use the above to write a new regulatory domain + */ +int ath5k_hw_set_regdomain(struct ath5k_hw *ah, u16 regdomain) +{ + enum ath5k_regdom ieee_regdomain; + + ieee_regdomain = ath5k_regdom_to_ieee(regdomain); + + if (ath5k_eeprom_regulation_domain(ah, true, &ieee_regdomain) == true) + return 0; + + return -EIO; +} + +/* + * Fill the capabilities struct + */ +static int ath5k_hw_get_capabilities(struct ath5k_hw *ah) +{ + u16 ee_header; + + ATH5K_TRACE(ah->ah_sc); + /* Capabilities stored in the EEPROM */ + ee_header = ah->ah_capabilities.cap_eeprom.ee_header; + + if (ah->ah_version == AR5K_AR5210) { + /* + * Set radio capabilities + * (The AR5110 only supports the middle 5GHz band) + */ + ah->ah_capabilities.cap_range.range_5ghz_min = 5120; + ah->ah_capabilities.cap_range.range_5ghz_max = 5430; + ah->ah_capabilities.cap_range.range_2ghz_min = 0; + ah->ah_capabilities.cap_range.range_2ghz_max = 0; + + /* Set supported modes */ + __set_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode); + __set_bit(MODE_ATHEROS_TURBO, ah->ah_capabilities.cap_mode); + } else { + /* + * XXX The tranceiver supports frequencies from 4920 to 6100GHz + * XXX and from 2312 to 2732GHz. There are problems with the + * XXX current ieee80211 implementation because the IEEE + * XXX channel mapping does not support negative channel + * XXX numbers (2312MHz is channel -19). Of course, this + * XXX doesn't matter because these channels are out of range + * XXX but some regulation domains like MKK (Japan) will + * XXX support frequencies somewhere around 4.8GHz. + */ + + /* + * Set radio capabilities + */ + + if (AR5K_EEPROM_HDR_11A(ee_header)) { + ah->ah_capabilities.cap_range.range_5ghz_min = 5005; /* 4920 */ + ah->ah_capabilities.cap_range.range_5ghz_max = 6100; + + /* Set supported modes */ + __set_bit(MODE_IEEE80211A, + ah->ah_capabilities.cap_mode); + __set_bit(MODE_ATHEROS_TURBO, + ah->ah_capabilities.cap_mode); + if (ah->ah_version == AR5K_AR5212) + __set_bit(MODE_ATHEROS_TURBOG, + ah->ah_capabilities.cap_mode); + } + + /* Enable 802.11b if a 2GHz capable radio (2111/5112) is + * connected */ + if (AR5K_EEPROM_HDR_11B(ee_header) || + AR5K_EEPROM_HDR_11G(ee_header)) { + ah->ah_capabilities.cap_range.range_2ghz_min = 2412; /* 2312 */ + ah->ah_capabilities.cap_range.range_2ghz_max = 2732; + + if (AR5K_EEPROM_HDR_11B(ee_header)) + __set_bit(MODE_IEEE80211B, + ah->ah_capabilities.cap_mode); + + if (AR5K_EEPROM_HDR_11G(ee_header)) + __set_bit(MODE_IEEE80211G, + ah->ah_capabilities.cap_mode); + } + } + + /* GPIO */ + ah->ah_gpio_npins = AR5K_NUM_GPIO; + + /* Set number of supported TX queues */ + if (ah->ah_version == AR5K_AR5210) + ah->ah_capabilities.cap_queues.q_tx_num = + AR5K_NUM_TX_QUEUES_NOQCU; + else + ah->ah_capabilities.cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES; + + return 0; +} + +/*********************************\ + Protocol Control Unit Functions +\*********************************/ + +/* + * Set Operation mode + */ +int ath5k_hw_set_opmode(struct ath5k_hw *ah) +{ + u32 pcu_reg, beacon_reg, low_id, high_id; + + pcu_reg = 0; + beacon_reg = 0; + + ATH5K_TRACE(ah->ah_sc); + + switch (ah->ah_op_mode) { + case IEEE80211_IF_TYPE_IBSS: + pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + beacon_reg |= AR5K_BCR_ADHOC; + break; + + case IEEE80211_IF_TYPE_AP: + pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + beacon_reg |= AR5K_BCR_AP; + break; + + case IEEE80211_IF_TYPE_STA: + pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_PWR_SV : 0); + case IEEE80211_IF_TYPE_MNTR: + pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | + (ah->ah_version == AR5K_AR5210 ? + AR5K_STA_ID1_NO_PSPOLL : 0); + break; + + default: + return -EINVAL; + } + + /* + * Set PCU registers + */ + low_id = AR5K_LOW_ID(ah->ah_sta_id); + high_id = AR5K_HIGH_ID(ah->ah_sta_id); + ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); + ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); + + /* + * Set Beacon Control Register on 5210 + */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR); + + return 0; +} + +/* + * BSSID Functions + */ + +/* + * Get station id + */ +void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) +{ + ATH5K_TRACE(ah->ah_sc); + memcpy(mac, ah->ah_sta_id, ETH_ALEN); +} + +/* + * Set station id + */ +int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) +{ + u32 low_id, high_id; + + ATH5K_TRACE(ah->ah_sc); + /* Set new station ID */ + memcpy(ah->ah_sta_id, mac, ETH_ALEN); + + low_id = AR5K_LOW_ID(mac); + high_id = AR5K_HIGH_ID(mac); + + ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); + ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); + + return 0; +} + +/* + * Set BSSID + */ +void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) +{ + u32 low_id, high_id; + u16 tim_offset = 0; + + /* + * Set simple BSSID mask on 5212 + */ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, 0xfffffff, AR5K_BSS_IDM1); + } + + /* + * Set BSSID which triggers the "SME Join" operation + */ + low_id = AR5K_LOW_ID(bssid); + high_id = AR5K_HIGH_ID(bssid); + ath5k_hw_reg_write(ah, low_id, AR5K_BSS_ID0); + ath5k_hw_reg_write(ah, high_id | ((assoc_id & 0x3fff) << + AR5K_BSS_ID1_AID_S), AR5K_BSS_ID1); + + if (assoc_id == 0) { + ath5k_hw_disable_pspoll(ah); + return; + } + + AR5K_REG_WRITE_BITS(ah, AR5K_BEACON, AR5K_BEACON_TIM, + tim_offset ? tim_offset + 4 : 0); + + ath5k_hw_enable_pspoll(ah, NULL, 0); +} +/** + * ath5k_hw_set_bssid_mask - set common bits we should listen to + * + * The bssid_mask is a utility used by AR5212 hardware to inform the hardware + * which bits of the interface's MAC address should be looked at when trying + * to decide which packets to ACK. In station mode every bit matters. In AP + * mode with a single BSS every bit matters as well. In AP mode with + * multiple BSSes not every bit matters. + * + * @ah: the &struct ath5k_hw + * @mask: the bssid_mask, a u8 array of size ETH_ALEN + * + * Note that this is a simple filter and *does* not filter out all + * relevant frames. Some non-relevant frames will get through, probability + * jocks are welcomed to compute. + * + * When handling multiple BSSes (or VAPs) you can get the BSSID mask by + * computing the set of: + * + * ~ ( MAC XOR BSSID ) + * + * When you do this you are essentially computing the common bits. Later it + * is assumed the harware will "and" (&) the BSSID mask with the MAC address + * to obtain the relevant bits which should match on the destination frame. + * + * Simple example: on your card you have have two BSSes you have created with + * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. + * There is another BSSID-03 but you are not part of it. For simplicity's sake, + * assuming only 4 bits for a mac address and for BSSIDs you can then have: + * + * \ + * MAC: 0001 | + * BSSID-01: 0100 | --> Belongs to us + * BSSID-02: 1001 | + * / + * ------------------- + * BSSID-03: 0110 | --> External + * ------------------- + * + * Our bssid_mask would then be: + * + * On loop iteration for BSSID-01: + * ~(0001 ^ 0100) -> ~(0101) + * -> 1010 + * bssid_mask = 1010 + * + * On loop iteration for BSSID-02: + * bssid_mask &= ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(0001 ^ 1001) + * bssid_mask = (1010) & ~(1001) + * bssid_mask = (1010) & (0110) + * bssid_mask = 0010 + * + * A bssid_mask of 0010 means "only pay attention to the second least + * significant bit". This is because its the only bit common + * amongst the MAC and all BSSIDs we support. To findout what the real + * common bit is we can simply "&" the bssid_mask now with any BSSID we have + * or our MAC address (we assume the hardware uses the MAC address). + * + * Now, suppose there's an incoming frame for BSSID-03: + * + * IFRAME-01: 0110 + * + * An easy eye-inspeciton of this already should tell you that this frame + * will not pass our check. This is beacuse the bssid_mask tells the + * hardware to only look at the second least significant bit and the + * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB + * as 1, which does not match 0. + * + * So with IFRAME-01 we *assume* the hardware will do: + * + * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; + * --> allow = (0010) == 0000 ? 1 : 0; + * --> allow = 0 + * + * Lets now test a frame that should work: + * + * IFRAME-02: 0001 (we should allow) + * + * allow = (0001 & 1010) == 1010 + * + * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; + * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; + * --> allow = (0010) == (0010) + * --> allow = 1 + * + * Other examples: + * + * IFRAME-03: 0100 --> allowed + * IFRAME-04: 1001 --> allowed + * IFRAME-05: 1101 --> allowed but its not for us!!! + * + */ +int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) +{ + u32 low_id, high_id; + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5212) { + low_id = AR5K_LOW_ID(mask); + high_id = AR5K_HIGH_ID(mask); + + ath5k_hw_reg_write(ah, low_id, AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, high_id, AR5K_BSS_IDM1); + + return 0; + } + + return -EIO; +} + +/* + * Receive start/stop functions + */ + +/* + * Start receive on PCU + */ +void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); +} + +/* + * Stop receive on PCU + */ +void ath5k_hw_stop_pcu_recv(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX); +} + +/* + * RX Filter functions + */ + +/* + * Set multicast filter + */ +void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1) +{ + ATH5K_TRACE(ah->ah_sc); + /* Set the multicat filter */ + ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0); + ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1); +} + +/* + * Set multicast filter by index + */ +int ath5k_hw_set_mcast_filterindex(struct ath5k_hw *ah, u32 index) +{ + + ATH5K_TRACE(ah->ah_sc); + if (index >= 64) + return -EINVAL; + else if (index >= 32) + AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER1, + (1 << (index - 32))); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); + + return 0; +} + +/* + * Clear Multicast filter by index + */ +int ath5k_hw_clear_mcast_filter_idx(struct ath5k_hw *ah, u32 index) +{ + + ATH5K_TRACE(ah->ah_sc); + if (index >= 64) + return -EINVAL; + else if (index >= 32) + AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER1, + (1 << (index - 32))); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_MCAST_FILTER0, (1 << index)); + + return 0; +} + +/* + * Get current rx filter + */ +u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah) +{ + u32 data, filter = 0; + + ATH5K_TRACE(ah->ah_sc); + filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER); + + /*Radar detection for 5212*/ + if (ah->ah_version == AR5K_AR5212) { + data = ath5k_hw_reg_read(ah, AR5K_PHY_ERR_FIL); + + if (data & AR5K_PHY_ERR_FIL_RADAR) + filter |= AR5K_RX_FILTER_RADARERR; + if (data & (AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK)) + filter |= AR5K_RX_FILTER_PHYERR; + } + + return filter; +} + +/* + * Set rx filter + */ +void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) +{ + u32 data = 0; + + ATH5K_TRACE(ah->ah_sc); + + /* Set PHY error filter register on 5212*/ + if (ah->ah_version == AR5K_AR5212) { + if (filter & AR5K_RX_FILTER_RADARERR) + data |= AR5K_PHY_ERR_FIL_RADAR; + if (filter & AR5K_RX_FILTER_PHYERR) + data |= AR5K_PHY_ERR_FIL_OFDM | AR5K_PHY_ERR_FIL_CCK; + } + + /* + * The AR5210 uses promiscous mode to detect radar activity + */ + if (ah->ah_version == AR5K_AR5210 && + (filter & AR5K_RX_FILTER_RADARERR)) { + filter &= ~AR5K_RX_FILTER_RADARERR; + filter |= AR5K_RX_FILTER_PROM; + } + + /*Zero length DMA*/ + if (data) + AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); + + /*Write RX Filter register*/ + ath5k_hw_reg_write(ah, filter & 0xff, AR5K_RX_FILTER); + + /*Write PHY error filter register on 5212*/ + if (ah->ah_version == AR5K_AR5212) + ath5k_hw_reg_write(ah, data, AR5K_PHY_ERR_FIL); + +} + +/* + * Beacon related functions + */ + +/* + * Get a 32bit TSF + */ +u32 ath5k_hw_get_tsf32(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_reg_read(ah, AR5K_TSF_L32); +} + +/* + * Get the full 64bit TSF + */ +u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah) +{ + u64 tsf = ath5k_hw_reg_read(ah, AR5K_TSF_U32); + ATH5K_TRACE(ah->ah_sc); + + return ath5k_hw_reg_read(ah, AR5K_TSF_L32) | (tsf << 32); +} + +/* + * Force a TSF reset + */ +void ath5k_hw_reset_tsf(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_REG_ENABLE_BITS(ah, AR5K_BEACON, AR5K_BEACON_RESET_TSF); +} + +/* + * Initialize beacon timers + */ +void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) +{ + u32 timer1, timer2, timer3; + + ATH5K_TRACE(ah->ah_sc); + /* + * Set the additional timers by mode + */ + switch (ah->ah_op_mode) { + case IEEE80211_IF_TYPE_STA: + if (ah->ah_version == AR5K_AR5210) { + timer1 = 0xffffffff; + timer2 = 0xffffffff; + } else { + timer1 = 0x0000ffff; + timer2 = 0x0007ffff; + } + break; + + default: + timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; + timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + } + + timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); + + /* + * Set the beacon register and enable all timers. + * (next beacon, DMA beacon, software beacon, ATIM window time) + */ + ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); + ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); + ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); + + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | + AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), + AR5K_BEACON); +} + +#if 0 +/* + * Set beacon timers + */ +int ath5k_hw_set_beacon_timers(struct ath5k_hw *ah, + const struct ath5k_beacon_state *state) +{ + u32 cfp_period, next_cfp, dtim, interval, next_beacon; + + /* + * TODO: should be changed through *state + * review struct ath5k_beacon_state struct + * + * XXX: These are used for cfp period bellow, are they + * ok ? Is it O.K. for tsf here to be 0 or should we use + * get_tsf ? + */ + u32 dtim_count = 0; /* XXX */ + u32 cfp_count = 0; /* XXX */ + u32 tsf = 0; /* XXX */ + + ATH5K_TRACE(ah->ah_sc); + /* Return on an invalid beacon state */ + if (state->bs_interval < 1) + return -EINVAL; + + interval = state->bs_interval; + dtim = state->bs_dtim_period; + + /* + * PCF support? + */ + if (state->bs_cfp_period > 0) { + /* + * Enable PCF mode and set the CFP + * (Contention Free Period) and timer registers + */ + cfp_period = state->bs_cfp_period * state->bs_dtim_period * + state->bs_interval; + next_cfp = (cfp_count * state->bs_dtim_period + dtim_count) * + state->bs_interval; + + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_PCF); + ath5k_hw_reg_write(ah, cfp_period, AR5K_CFP_PERIOD); + ath5k_hw_reg_write(ah, state->bs_cfp_max_duration, + AR5K_CFP_DUR); + ath5k_hw_reg_write(ah, (tsf + (next_cfp == 0 ? cfp_period : + next_cfp)) << 3, AR5K_TIMER2); + } else { + /* Disable PCF mode */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | + AR5K_STA_ID1_PCF); + } + + /* + * Enable the beacon timer register + */ + ath5k_hw_reg_write(ah, state->bs_next_beacon, AR5K_TIMER0); + + /* + * Start the beacon timers + */ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_BEACON) &~ + (AR5K_BEACON_PERIOD | AR5K_BEACON_TIM)) | + AR5K_REG_SM(state->bs_tim_offset ? state->bs_tim_offset + 4 : 0, + AR5K_BEACON_TIM) | AR5K_REG_SM(state->bs_interval, + AR5K_BEACON_PERIOD), AR5K_BEACON); + + /* + * Write new beacon miss threshold, if it appears to be valid + * XXX: Figure out right values for min <= bs_bmiss_threshold <= max + * and return if its not in range. We can test this by reading value and + * setting value to a largest value and seeing which values register. + */ + + AR5K_REG_WRITE_BITS(ah, AR5K_RSSI_THR, AR5K_RSSI_THR_BMISS, + state->bs_bmiss_threshold); + + /* + * Set sleep control register + * XXX: Didn't find this in 5210 code but since this register + * exists also in ar5k's 5210 headers i leave it as common code. + */ + AR5K_REG_WRITE_BITS(ah, AR5K_SLEEP_CTL, AR5K_SLEEP_CTL_SLDUR, + (state->bs_sleep_duration - 3) << 3); + + /* + * Set enhanced sleep registers on 5212 + */ + if (ah->ah_version == AR5K_AR5212) { + if (state->bs_sleep_duration > state->bs_interval && + roundup(state->bs_sleep_duration, interval) == + state->bs_sleep_duration) + interval = state->bs_sleep_duration; + + if (state->bs_sleep_duration > dtim && (dtim == 0 || + roundup(state->bs_sleep_duration, dtim) == + state->bs_sleep_duration)) + dtim = state->bs_sleep_duration; + + if (interval > dtim) + return -EINVAL; + + next_beacon = interval == dtim ? state->bs_next_dtim : + state->bs_next_beacon; + + ath5k_hw_reg_write(ah, + AR5K_REG_SM((state->bs_next_dtim - 3) << 3, + AR5K_SLEEP0_NEXT_DTIM) | + AR5K_REG_SM(10, AR5K_SLEEP0_CABTO) | + AR5K_SLEEP0_ENH_SLEEP_EN | + AR5K_SLEEP0_ASSUME_DTIM, AR5K_SLEEP0); + + ath5k_hw_reg_write(ah, AR5K_REG_SM((next_beacon - 3) << 3, + AR5K_SLEEP1_NEXT_TIM) | + AR5K_REG_SM(10, AR5K_SLEEP1_BEACON_TO), AR5K_SLEEP1); + + ath5k_hw_reg_write(ah, + AR5K_REG_SM(interval, AR5K_SLEEP2_TIM_PER) | + AR5K_REG_SM(dtim, AR5K_SLEEP2_DTIM_PER), AR5K_SLEEP2); + } + + return 0; +} + +/* + * Reset beacon timers + */ +void ath5k_hw_reset_beacon(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /* + * Disable beacon timer + */ + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + + /* + * Disable some beacon register values + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_DEFAULT_ANTENNA | AR5K_STA_ID1_PCF); + ath5k_hw_reg_write(ah, AR5K_BEACON_PERIOD, AR5K_BEACON); +} + +/* + * Wait for beacon queue to finish + */ +int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) +{ + unsigned int i; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + /* 5210 doesn't have QCU*/ + if (ah->ah_version == AR5K_AR5210) { + /* + * Wait for beaconn queue to finish by checking + * Control Register and Beacon Status Register. + */ + for (i = AR5K_TUNE_BEACON_INTERVAL / 2; i > 0; i--) { + if (!(ath5k_hw_reg_read(ah, AR5K_BSR) & AR5K_BSR_TXQ1F) + || + !(ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_BSR_TXQ1F)) + break; + udelay(10); + } + + /* Timeout... */ + if (i <= 0) { + /* + * Re-schedule the beacon queue + */ + ath5k_hw_reg_write(ah, phys_addr, AR5K_NOQCU_TXDP1); + ath5k_hw_reg_write(ah, AR5K_BCR_TQ1V | AR5K_BCR_BDMAE, + AR5K_BCR); + + return -EIO; + } + ret = 0; + } else { + /*5211/5212*/ + ret = ath5k_hw_register_timeout(ah, + AR5K_QUEUE_STATUS(AR5K_TX_QUEUE_ID_BEACON), + AR5K_QCU_STS_FRMPENDCNT, 0, false); + + if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, AR5K_TX_QUEUE_ID_BEACON)) + return -EIO; + } + + return ret; +} +#endif + +/* + * Update mib counters (statistics) + */ +void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, + struct ath5k_mib_stats *statistics) +{ + ATH5K_TRACE(ah->ah_sc); + /* Read-And-Clear */ + statistics->ackrcv_bad += ath5k_hw_reg_read(ah, AR5K_ACK_FAIL); + statistics->rts_bad += ath5k_hw_reg_read(ah, AR5K_RTS_FAIL); + statistics->rts_good += ath5k_hw_reg_read(ah, AR5K_RTS_OK); + statistics->fcs_bad += ath5k_hw_reg_read(ah, AR5K_FCS_FAIL); + statistics->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT); + + /* Reset profile count registers on 5212*/ + if (ah->ah_version == AR5K_AR5212) { + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_TX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RX); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); + ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); + } +} + +/** ath5k_hw_set_ack_bitrate - set bitrate for ACKs + * + * @ah: the &struct ath5k_hw + * @high: determines if to use low bit rate or now + */ +void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high) +{ + if (ah->ah_version != AR5K_AR5212) + return; + else { + u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB; + if (high) + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val); + } +} + + +/* + * ACK/CTS Timeouts + */ + +/* + * Set ACK timeout on PCU + */ +int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout) +{ + ATH5K_TRACE(ah->ah_sc); + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK), + ah->ah_turbo) <= timeout) + return -EINVAL; + + AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_ACK, + ath5k_hw_htoclock(timeout, ah->ah_turbo)); + + return 0; +} + +/* + * Read the ACK timeout from PCU + */ +unsigned int ath5k_hw_get_ack_timeout(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_ACK), ah->ah_turbo); +} + +/* + * Set CTS timeout on PCU + */ +int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout) +{ + ATH5K_TRACE(ah->ah_sc); + if (ath5k_hw_clocktoh(AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS), + ah->ah_turbo) <= timeout) + return -EINVAL; + + AR5K_REG_WRITE_BITS(ah, AR5K_TIME_OUT, AR5K_TIME_OUT_CTS, + ath5k_hw_htoclock(timeout, ah->ah_turbo)); + + return 0; +} + +/* + * Read CTS timeout from PCU + */ +unsigned int ath5k_hw_get_cts_timeout(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + return ath5k_hw_clocktoh(AR5K_REG_MS(ath5k_hw_reg_read(ah, + AR5K_TIME_OUT), AR5K_TIME_OUT_CTS), ah->ah_turbo); +} + +/* + * Key table (WEP) functions + */ + +int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) +{ + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + + /* Set NULL encryption on non-5210*/ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(entry)); + + return 0; +} + +int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + /* Check the validation flag at the end of the entry */ + return ath5k_hw_reg_read(ah, AR5K_KEYTABLE_MAC1(entry)) & + AR5K_KEYTABLE_VALID; +} + +int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, + const struct ieee80211_key_conf *key, const u8 *mac) +{ + unsigned int i; + __le32 key_v[5] = {}; + u32 keytype; + + ATH5K_TRACE(ah->ah_sc); + + /* key->keylen comes in from mac80211 in bytes */ + + if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + return -EOPNOTSUPP; + + switch (key->keylen) { + /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ + case 40 / 8: + memcpy(&key_v[0], key->key, 5); + keytype = AR5K_KEYTABLE_TYPE_40; + break; + + /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ + case 104 / 8: + memcpy(&key_v[0], &key->key[0], 6); + memcpy(&key_v[2], &key->key[6], 6); + memcpy(&key_v[4], &key->key[12], 1); + keytype = AR5K_KEYTABLE_TYPE_104; + break; + /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ + case 128 / 8: + memcpy(&key_v[0], &key->key[0], 6); + memcpy(&key_v[2], &key->key[6], 6); + memcpy(&key_v[4], &key->key[12], 4); + keytype = AR5K_KEYTABLE_TYPE_128; + break; + + default: + return -EINVAL; /* shouldn't happen */ + } + + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(entry, i)); + + ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); + + return ath5k_hw_set_key_lladdr(ah, entry, mac); +} + +int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac) +{ + u32 low_id, high_id; + + ATH5K_TRACE(ah->ah_sc); + /* Invalid entry (key table overflow) */ + AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + + /* MAC may be NULL if it's a broadcast key. In this case no need to + * to compute AR5K_LOW_ID and AR5K_HIGH_ID as we already know it. */ + if (unlikely(mac == NULL)) { + low_id = 0xffffffff; + high_id = 0xffff | AR5K_KEYTABLE_VALID; + } else { + low_id = AR5K_LOW_ID(mac); + high_id = AR5K_HIGH_ID(mac) | AR5K_KEYTABLE_VALID; + } + + ath5k_hw_reg_write(ah, low_id, AR5K_KEYTABLE_MAC0(entry)); + ath5k_hw_reg_write(ah, high_id, AR5K_KEYTABLE_MAC1(entry)); + + return 0; +} + + +/********************************************\ +Queue Control Unit, DFS Control Unit Functions +\********************************************/ + +/* + * Initialize a transmit queue + */ +int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, + struct ath5k_txq_info *queue_info) +{ + unsigned int queue; + int ret; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Get queue by type + */ + /*5210 only has 2 queues*/ + if (ah->ah_version == AR5K_AR5210) { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: + queue = AR5K_TX_QUEUE_ID_NOQCU_DATA; + break; + case AR5K_TX_QUEUE_BEACON: + case AR5K_TX_QUEUE_CAB: + queue = AR5K_TX_QUEUE_ID_NOQCU_BEACON; + break; + default: + return -EINVAL; + } + } else { + switch (queue_type) { + case AR5K_TX_QUEUE_DATA: + for (queue = AR5K_TX_QUEUE_ID_DATA_MIN; + ah->ah_txq[queue].tqi_type != + AR5K_TX_QUEUE_INACTIVE; queue++) { + + if (queue > AR5K_TX_QUEUE_ID_DATA_MAX) + return -EINVAL; + } + break; + case AR5K_TX_QUEUE_UAPSD: + queue = AR5K_TX_QUEUE_ID_UAPSD; + break; + case AR5K_TX_QUEUE_BEACON: + queue = AR5K_TX_QUEUE_ID_BEACON; + break; + case AR5K_TX_QUEUE_CAB: + queue = AR5K_TX_QUEUE_ID_CAB; + break; + case AR5K_TX_QUEUE_XR_DATA: + if (ah->ah_version != AR5K_AR5212) + ATH5K_ERR(ah->ah_sc, + "XR data queues only supported in" + " 5212!\n"); + queue = AR5K_TX_QUEUE_ID_XR_DATA; + break; + default: + return -EINVAL; + } + } + + /* + * Setup internal queue structure + */ + memset(&ah->ah_txq[queue], 0, sizeof(struct ath5k_txq_info)); + ah->ah_txq[queue].tqi_type = queue_type; + + if (queue_info != NULL) { + queue_info->tqi_type = queue_type; + ret = ath5k_hw_setup_tx_queueprops(ah, queue, queue_info); + if (ret) + return ret; + } + /* + * We use ah_txq_status to hold a temp value for + * the Secondary interrupt mask registers on 5211+ + * check out ath5k_hw_reset_tx_queue + */ + AR5K_Q_ENABLE_BITS(ah->ah_txq_status, queue); + + return queue; +} + +/* + * Setup a transmit queue + */ +int ath5k_hw_setup_tx_queueprops(struct ath5k_hw *ah, int queue, + const struct ath5k_txq_info *queue_info) +{ + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return -EIO; + + memcpy(&ah->ah_txq[queue], queue_info, sizeof(struct ath5k_txq_info)); + + /*XXX: Is this supported on 5210 ?*/ + if ((queue_info->tqi_type == AR5K_TX_QUEUE_DATA && + ((queue_info->tqi_subtype == AR5K_WME_AC_VI) || + (queue_info->tqi_subtype == AR5K_WME_AC_VO))) || + queue_info->tqi_type == AR5K_TX_QUEUE_UAPSD) + ah->ah_txq[queue].tqi_flags |= AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS; + + return 0; +} + +/* + * Get properties for a specific transmit queue + */ +int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue, + struct ath5k_txq_info *queue_info) +{ + ATH5K_TRACE(ah->ah_sc); + memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info)); + return 0; +} + +/* + * Set a transmit queue inactive + */ +void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue) +{ + ATH5K_TRACE(ah->ah_sc); + if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num)) + return; + + /* This queue will be skipped in further operations */ + ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE; + /*For SIMR setup*/ + AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue); +} + +/* + * Set DFS params for a transmit queue + */ +int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) +{ + u32 cw_min, cw_max, retry_lg, retry_sh; + struct ath5k_txq_info *tq = &ah->ah_txq[queue]; + + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + tq = &ah->ah_txq[queue]; + + if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE) + return 0; + + if (ah->ah_version == AR5K_AR5210) { + /* Only handle data queues, others will be ignored */ + if (tq->tqi_type != AR5K_TX_QUEUE_DATA) + return 0; + + /* Set Slot time */ + ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME, + AR5K_SLOT_TIME); + /* Set ACK_CTS timeout */ + ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + AR5K_INIT_ACK_CTS_TIMEOUT_TURBO : + AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME); + /* Set Transmit Latency */ + ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + AR5K_INIT_TRANSMIT_LATENCY_TURBO : + AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210); + /* Set IFS0 */ + if (ah->ah_turbo == true) + ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO + + (ah->ah_aifs + tq->tqi_aifs) * + AR5K_INIT_SLOT_TIME_TURBO) << + AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO, + AR5K_IFS0); + else + ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS + + (ah->ah_aifs + tq->tqi_aifs) * + AR5K_INIT_SLOT_TIME) << AR5K_IFS0_DIFS_S) | + AR5K_INIT_SIFS, AR5K_IFS0); + + /* Set IFS1 */ + ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + AR5K_INIT_PROTO_TIME_CNTRL_TURBO : + AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1); + /* Set PHY register 0x9844 (??) */ + ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 : + (ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C, + AR5K_PHY(17)); + /* Set Frame Control Register */ + ath5k_hw_reg_write(ah, ah->ah_turbo == true ? + (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE | + AR5K_PHY_TURBO_SHORT | 0x2020) : + (AR5K_PHY_FRAME_CTL_INI | 0x1020), + AR5K_PHY_FRAME_CTL_5210); + } + + /* + * Calculate cwmin/max by channel mode + */ + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX; + ah->ah_aifs = AR5K_TUNE_AIFS; + /*XR is only supported on 5212*/ + if (IS_CHAN_XR(ah->ah_current_channel) && + ah->ah_version == AR5K_AR5212) { + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_XR; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_XR; + ah->ah_aifs = AR5K_TUNE_AIFS_XR; + /*B mode is not supported on 5210*/ + } else if (IS_CHAN_B(ah->ah_current_channel) && + ah->ah_version != AR5K_AR5210) { + cw_min = ah->ah_cw_min = AR5K_TUNE_CWMIN_11B; + cw_max = ah->ah_cw_max = AR5K_TUNE_CWMAX_11B; + ah->ah_aifs = AR5K_TUNE_AIFS_11B; + } + + cw_min = 1; + while (cw_min < ah->ah_cw_min) + cw_min = (cw_min << 1) | 1; + + cw_min = tq->tqi_cw_min < 0 ? (cw_min >> (-tq->tqi_cw_min)) : + ((cw_min << tq->tqi_cw_min) + (1 << tq->tqi_cw_min) - 1); + cw_max = tq->tqi_cw_max < 0 ? (cw_max >> (-tq->tqi_cw_max)) : + ((cw_max << tq->tqi_cw_max) + (1 << tq->tqi_cw_max) - 1); + + /* + * Calculate and set retry limits + */ + if (ah->ah_software_retry == true) { + /* XXX Need to test this */ + retry_lg = ah->ah_limit_tx_retries; + retry_sh = retry_lg = retry_lg > AR5K_DCU_RETRY_LMT_SH_RETRY ? + AR5K_DCU_RETRY_LMT_SH_RETRY : retry_lg; + } else { + retry_lg = AR5K_INIT_LG_RETRY; + retry_sh = AR5K_INIT_SH_RETRY; + } + + /*No QCU/DCU [5210]*/ + if (ah->ah_version == AR5K_AR5210) { + ath5k_hw_reg_write(ah, + (cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S) + | AR5K_REG_SM(AR5K_INIT_SLG_RETRY, + AR5K_NODCU_RETRY_LMT_SLG_RETRY) + | AR5K_REG_SM(AR5K_INIT_SSH_RETRY, + AR5K_NODCU_RETRY_LMT_SSH_RETRY) + | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY) + | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY), + AR5K_NODCU_RETRY_LMT); + } else { + /*QCU/DCU [5211+]*/ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(AR5K_INIT_SLG_RETRY, + AR5K_DCU_RETRY_LMT_SLG_RETRY) | + AR5K_REG_SM(AR5K_INIT_SSH_RETRY, + AR5K_DCU_RETRY_LMT_SSH_RETRY) | + AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) | + AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY), + AR5K_QUEUE_DFS_RETRY_LIMIT(queue)); + + /*===Rest is also for QCU/DCU only [5211+]===*/ + + /* + * Set initial content window (cw_min/cw_max) + * and arbitrated interframe space (aifs)... + */ + ath5k_hw_reg_write(ah, + AR5K_REG_SM(cw_min, AR5K_DCU_LCL_IFS_CW_MIN) | + AR5K_REG_SM(cw_max, AR5K_DCU_LCL_IFS_CW_MAX) | + AR5K_REG_SM(ah->ah_aifs + tq->tqi_aifs, + AR5K_DCU_LCL_IFS_AIFS), + AR5K_QUEUE_DFS_LOCAL_IFS(queue)); + + /* + * Set misc registers + */ + ath5k_hw_reg_write(ah, AR5K_QCU_MISC_DCU_EARLY, + AR5K_QUEUE_MISC(queue)); + + if (tq->tqi_cbr_period) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period, + AR5K_QCU_CBRCFG_INTVAL) | + AR5K_REG_SM(tq->tqi_cbr_overflow_limit, + AR5K_QCU_CBRCFG_ORN_THRES), + AR5K_QUEUE_CBRCFG(queue)); + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_CBR); + if (tq->tqi_cbr_overflow_limit) + AR5K_REG_ENABLE_BITS(ah, + AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_CBR_THRES_ENABLE); + } + + if (tq->tqi_ready_time) + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time, + AR5K_QCU_RDYTIMECFG_INTVAL) | + AR5K_QCU_RDYTIMECFG_ENABLE, + AR5K_QUEUE_RDYTIMECFG(queue)); + + if (tq->tqi_burst_time) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time, + AR5K_DCU_CHAN_TIME_DUR) | + AR5K_DCU_CHAN_TIME_ENABLE, + AR5K_QUEUE_DFS_CHANNEL_TIME(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); + } + + if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE) + ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS, + AR5K_QUEUE_DFS_MISC(queue)); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) + ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG, + AR5K_QUEUE_DFS_MISC(queue)); + + /* + * Set registers by queue type + */ + switch (tq->tqi_type) { + case AR5K_TX_QUEUE_BEACON: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_CBREXP_BCN | + AR5K_QCU_MISC_BCN_ENABLE); + + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << + AR5K_DCU_MISC_ARBLOCK_CTL_S) | + AR5K_DCU_MISC_POST_FR_BKOFF_DIS | + AR5K_DCU_MISC_BCN_ENABLE); + + ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL - + (AR5K_TUNE_SW_BEACON_RESP - + AR5K_TUNE_DMA_BEACON_RESP) - + AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) | + AR5K_QCU_RDYTIMECFG_ENABLE, + AR5K_QUEUE_RDYTIMECFG(queue)); + break; + + case AR5K_TX_QUEUE_CAB: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_FRSHED_DBA_GT | + AR5K_QCU_MISC_CBREXP | + AR5K_QCU_MISC_CBREXP_BCN); + + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue), + (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL << + AR5K_DCU_MISC_ARBLOCK_CTL_S)); + break; + + case AR5K_TX_QUEUE_UAPSD: + AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue), + AR5K_QCU_MISC_CBREXP); + break; + + case AR5K_TX_QUEUE_DATA: + default: + break; + } + + /* + * Enable interrupts for this tx queue + * in the secondary interrupt mask registers + */ + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); + + + /* Update secondary interrupt mask registers */ + ah->ah_txq_imr_txok &= ah->ah_txq_status; + ah->ah_txq_imr_txerr &= ah->ah_txq_status; + ah->ah_txq_imr_txurn &= ah->ah_txq_status; + ah->ah_txq_imr_txdesc &= ah->ah_txq_status; + ah->ah_txq_imr_txeol &= ah->ah_txq_status; + + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, + AR5K_SIMR0_QCU_TXOK) | + AR5K_REG_SM(ah->ah_txq_imr_txdesc, + AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr, + AR5K_SIMR1_QCU_TXERR) | + AR5K_REG_SM(ah->ah_txq_imr_txeol, + AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, + AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); + } + + return 0; +} + +/* + * Get number of pending frames + * for a specific queue [5211+] + */ +u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue) { + ATH5K_TRACE(ah->ah_sc); + AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); + + /* Return if queue is declared inactive */ + if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE) + return false; + + /* XXX: How about AR5K_CFG_TXCNT ? */ + if (ah->ah_version == AR5K_AR5210) + return false; + + return AR5K_QUEUE_STATUS(queue) & AR5K_QCU_STS_FRMPENDCNT; +} + +/* + * Set slot time + */ +int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time) +{ + ATH5K_TRACE(ah->ah_sc); + if (slot_time < AR5K_SLOT_TIME_9 || slot_time > AR5K_SLOT_TIME_MAX) + return -EINVAL; + + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, ath5k_hw_htoclock(slot_time, + ah->ah_turbo), AR5K_SLOT_TIME); + else + ath5k_hw_reg_write(ah, slot_time, AR5K_DCU_GBL_IFS_SLOT); + + return 0; +} + +/* + * Get slot time + */ +unsigned int ath5k_hw_get_slot_time(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + if (ah->ah_version == AR5K_AR5210) + return ath5k_hw_clocktoh(ath5k_hw_reg_read(ah, + AR5K_SLOT_TIME) & 0xffff, ah->ah_turbo); + else + return ath5k_hw_reg_read(ah, AR5K_DCU_GBL_IFS_SLOT) & 0xffff; +} + + +/******************************\ + Hardware Descriptor Functions +\******************************/ + +/* + * TX Descriptor + */ + +/* + * Initialize the 2-word tx descriptor on 5210/5211 + */ +static int +ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int pkt_len, unsigned int hdr_len, enum ath5k_pkt_type type, + unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, + unsigned int key_index, unsigned int antenna_mode, unsigned int flags, + unsigned int rtscts_rate, unsigned int rtscts_duration) +{ + u32 frame_type; + struct ath5k_hw_2w_tx_desc *tx_desc; + unsigned int buff_len; + + tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; + + /* + * Validate input + * - Zero retries don't make sense. + * - A zero rate will put the HW into a mode where it continously sends + * noise on the channel, so it is important to avoid this. + */ + if (unlikely(tx_tries0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero retries\n"); + WARN_ON(1); + return -EINVAL; + } + if (unlikely(tx_rate0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + /* Clear status descriptor */ + memset(desc->ds_hw, 0, sizeof(struct ath5k_hw_tx_status)); + + /* Initialize control descriptor */ + tx_desc->tx_control_0 = 0; + tx_desc->tx_control_1 = 0; + + /* Setup control descriptor */ + + /* Verify and set frame length */ + if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + + tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + buff_len = pkt_len - FCS_LEN; + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + if(type == AR5K_PKT_TYPE_BEACON) + buff_len = roundup(buff_len, 4); + + if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + + tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; + + /* + * Verify and set header length + * XXX: I only found that on 5210 code, does it work on 5211 ? + */ + if (ah->ah_version == AR5K_AR5210) { + if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN) + return -EINVAL; + tx_desc->tx_control_0 |= + AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN); + } + + /*Diferences between 5210-5211*/ + if (ah->ah_version == AR5K_AR5210) { + switch (type) { + case AR5K_PKT_TYPE_BEACON: + case AR5K_PKT_TYPE_PROBE_RESP: + frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; + case AR5K_PKT_TYPE_PIFS: + frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; + default: + frame_type = type /*<< 2 ?*/; + } + + tx_desc->tx_control_0 |= + AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE) | + AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + } else { + tx_desc->tx_control_0 |= + AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | + AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); + tx_desc->tx_control_1 |= + AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE); + } +#define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) \ + tx_desc->tx_control_##_c |= \ + AR5K_2W_TX_DESC_CTL##_c##_##_flag + + _TX_FLAGS(0, CLRDMASK); + _TX_FLAGS(0, VEOL); + _TX_FLAGS(0, INTREQ); + _TX_FLAGS(0, RTSENA); + _TX_FLAGS(1, NOACK); + +#undef _TX_FLAGS + + /* + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { + tx_desc->tx_control_0 |= + AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_desc->tx_control_1 |= + AR5K_REG_SM(key_index, + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + } + + /* + * RTS/CTS Duration [5210 ?] + */ + if ((ah->ah_version == AR5K_AR5210) && + (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) + tx_desc->tx_control_1 |= rtscts_duration & + AR5K_2W_TX_DESC_CTL1_RTS_DURATION; + + return 0; +} + +/* + * Initialize the 4-word tx descriptor on 5212 + */ +static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, + struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, + enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, + unsigned int tx_tries0, unsigned int key_index, + unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, + unsigned int rtscts_duration) +{ + struct ath5k_hw_4w_tx_desc *tx_desc; + struct ath5k_hw_tx_status *tx_status; + unsigned int buff_len; + + ATH5K_TRACE(ah->ah_sc); + tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; + tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; + + /* + * Validate input + * - Zero retries don't make sense. + * - A zero rate will put the HW into a mode where it continously sends + * noise on the channel, so it is important to avoid this. + */ + if (unlikely(tx_tries0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero retries\n"); + WARN_ON(1); + return -EINVAL; + } + if (unlikely(tx_rate0 == 0)) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + /* Clear status descriptor */ + memset(tx_status, 0, sizeof(struct ath5k_hw_tx_status)); + + /* Initialize control descriptor */ + tx_desc->tx_control_0 = 0; + tx_desc->tx_control_1 = 0; + tx_desc->tx_control_2 = 0; + tx_desc->tx_control_3 = 0; + + /* Setup control descriptor */ + + /* Verify and set frame length */ + if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) + return -EINVAL; + + tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + + /* Verify and set buffer length */ + buff_len = pkt_len - FCS_LEN; + + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + if(type == AR5K_PKT_TYPE_BEACON) + buff_len = roundup(buff_len, 4); + + if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) + return -EINVAL; + + tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + + tx_desc->tx_control_0 |= + AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | + AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); + tx_desc->tx_control_1 |= AR5K_REG_SM(type, + AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); + tx_desc->tx_control_2 = AR5K_REG_SM(tx_tries0 + AR5K_TUNE_HWTXTRIES, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); + tx_desc->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + +#define _TX_FLAGS(_c, _flag) \ + if (flags & AR5K_TXDESC_##_flag) \ + tx_desc->tx_control_##_c |= \ + AR5K_4W_TX_DESC_CTL##_c##_##_flag + + _TX_FLAGS(0, CLRDMASK); + _TX_FLAGS(0, VEOL); + _TX_FLAGS(0, INTREQ); + _TX_FLAGS(0, RTSENA); + _TX_FLAGS(0, CTSENA); + _TX_FLAGS(1, NOACK); + +#undef _TX_FLAGS + + /* + * WEP crap + */ + if (key_index != AR5K_TXKEYIX_INVALID) { + tx_desc->tx_control_0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; + tx_desc->tx_control_1 |= AR5K_REG_SM(key_index, + AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX); + } + + /* + * RTS/CTS + */ + if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { + if ((flags & AR5K_TXDESC_RTSENA) && + (flags & AR5K_TXDESC_CTSENA)) + return -EINVAL; + tx_desc->tx_control_2 |= rtscts_duration & + AR5K_4W_TX_DESC_CTL2_RTS_DURATION; + tx_desc->tx_control_3 |= AR5K_REG_SM(rtscts_rate, + AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); + } + + return 0; +} + +/* + * Initialize a 4-word multirate tx descriptor on 5212 + */ +static bool +ath5k_hw_setup_xr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, + unsigned int tx_rate3, u_int tx_tries3) +{ + struct ath5k_hw_4w_tx_desc *tx_desc; + + /* + * Rates can be 0 as long as the retry count is 0 too. + * A zero rate and nonzero retry count will put the HW into a mode where + * it continously sends noise on the channel, so it is important to + * avoid this. + */ + if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || + (tx_rate2 == 0 && tx_tries2 != 0) || + (tx_rate3 == 0 && tx_tries3 != 0))) { + ATH5K_ERR(ah->ah_sc, "zero rate\n"); + WARN_ON(1); + return -EINVAL; + } + + if (ah->ah_version == AR5K_AR5212) { + tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; + +#define _XTX_TRIES(_n) \ + if (tx_tries##_n) { \ + tx_desc->tx_control_2 |= \ + AR5K_REG_SM(tx_tries##_n, \ + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ + tx_desc->tx_control_3 |= \ + AR5K_REG_SM(tx_rate##_n, \ + AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ + } + + _XTX_TRIES(1); + _XTX_TRIES(2); + _XTX_TRIES(3); + +#undef _XTX_TRIES + + return true; + } + + return false; +} + +/* + * Proccess the tx status descriptor on 5210/5211 + */ +static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc) +{ + struct ath5k_hw_tx_status *tx_status; + struct ath5k_hw_2w_tx_desc *tx_desc; + + tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; + tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[0]; + + /* No frame has been send or error */ + if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) + return -EINPROGRESS; + + /* + * Get descriptor status + */ + desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); + desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + /*TODO: desc->ds_us.tx.ts_virtcol + test*/ + desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); + desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + desc->ds_us.tx.ts_antenna = 1; + desc->ds_us.tx.ts_status = 0; + desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_0, + AR5K_2W_TX_DESC_CTL0_XMIT_RATE); + + if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ + if (tx_status->tx_status_0 & + AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; + } + + return 0; +} + +/* + * Proccess a tx descriptor on 5212 + */ +static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc) +{ + struct ath5k_hw_tx_status *tx_status; + struct ath5k_hw_4w_tx_desc *tx_desc; + + ATH5K_TRACE(ah->ah_sc); + tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; + tx_status = (struct ath5k_hw_tx_status *)&desc->ds_hw[2]; + + /* No frame has been send or error */ + if (unlikely((tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE) == 0)) + return -EINPROGRESS; + + /* + * Get descriptor status + */ + desc->ds_us.tx.ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP); + desc->ds_us.tx.ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT); + desc->ds_us.tx.ts_longretry = AR5K_REG_MS(tx_status->tx_status_0, + AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT); + desc->ds_us.tx.ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_SEQ_NUM); + desc->ds_us.tx.ts_rssi = AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH); + desc->ds_us.tx.ts_antenna = (tx_status->tx_status_1 & + AR5K_DESC_TX_STATUS1_XMIT_ANTENNA) ? 2 : 1; + desc->ds_us.tx.ts_status = 0; + + switch (AR5K_REG_MS(tx_status->tx_status_1, + AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX)) { + case 0: + desc->ds_us.tx.ts_rate = tx_desc->tx_control_3 & + AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; + break; + case 1: + desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE1); + desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1); + break; + case 2: + desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE2); + desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2); + break; + case 3: + desc->ds_us.tx.ts_rate = AR5K_REG_MS(tx_desc->tx_control_3, + AR5K_4W_TX_DESC_CTL3_XMIT_RATE3); + desc->ds_us.tx.ts_longretry +=AR5K_REG_MS(tx_desc->tx_control_2, + AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3); + break; + } + + if ((tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK) == 0){ + if (tx_status->tx_status_0 & + AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES) + desc->ds_us.tx.ts_status |= AR5K_TXERR_XRETRY; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN) + desc->ds_us.tx.ts_status |= AR5K_TXERR_FIFO; + + if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED) + desc->ds_us.tx.ts_status |= AR5K_TXERR_FILT; + } + + return 0; +} + +/* + * RX Descriptor + */ + +/* + * Initialize an rx descriptor + */ +int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, + u32 size, unsigned int flags) +{ + struct ath5k_rx_desc *rx_desc; + + ATH5K_TRACE(ah->ah_sc); + rx_desc = (struct ath5k_rx_desc *)&desc->ds_ctl0; + + /* + *Clear ds_hw + * If we don't clean the status descriptor, + * while scanning we get too many results, + * most of them virtual, after some secs + * of scanning system hangs. M.F. + */ + memset(desc->ds_hw, 0, sizeof(desc->ds_hw)); + + /*Initialize rx descriptor*/ + rx_desc->rx_control_0 = 0; + rx_desc->rx_control_1 = 0; + + /* Setup descriptor */ + rx_desc->rx_control_1 = size & AR5K_DESC_RX_CTL1_BUF_LEN; + if (unlikely(rx_desc->rx_control_1 != size)) + return -EINVAL; + + if (flags & AR5K_RXDESC_INTREQ) + rx_desc->rx_control_1 |= AR5K_DESC_RX_CTL1_INTREQ; + + return 0; +} + +/* + * Proccess the rx status descriptor on 5210/5211 + */ +static int ath5k_hw_proc_old_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc) +{ + struct ath5k_hw_old_rx_status *rx_status; + + rx_status = (struct ath5k_hw_old_rx_status *)&desc->ds_hw[0]; + + /* No frame received / not ready */ + if (unlikely((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_DONE) + == 0)) + return -EINPROGRESS; + + /* + * Frame receive status + */ + desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & + AR5K_OLD_RX_DESC_STATUS0_DATA_LEN; + desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL); + desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE); + desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & + AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA; + desc->ds_us.rx.rs_more = rx_status->rx_status_0 & + AR5K_OLD_RX_DESC_STATUS0_MORE; + desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + desc->ds_us.rx.rs_status = 0; + + /* + * Key table status + */ + if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID) + desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX); + else + desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; + + /* + * Receive/descriptor errors + */ + if ((rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK) + == 0) { + if (rx_status->rx_status_1 & AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR) + desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; + + if (rx_status->rx_status_1 & + AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN) + desc->ds_us.rx.rs_status |= AR5K_RXERR_FIFO; + + if (rx_status->rx_status_1 & + AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR) { + desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; + desc->ds_us.rx.rs_phyerr = + AR5K_REG_MS(rx_status->rx_status_1, + AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR); + } + + if (rx_status->rx_status_1 & + AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; + } + + return 0; +} + +/* + * Proccess the rx status descriptor on 5212 + */ +static int ath5k_hw_proc_new_rx_status(struct ath5k_hw *ah, + struct ath5k_desc *desc) +{ + struct ath5k_hw_new_rx_status *rx_status; + struct ath5k_hw_rx_error *rx_err; + + ATH5K_TRACE(ah->ah_sc); + rx_status = (struct ath5k_hw_new_rx_status *)&desc->ds_hw[0]; + + /* Overlay on error */ + rx_err = (struct ath5k_hw_rx_error *)&desc->ds_hw[0]; + + /* No frame received / not ready */ + if (unlikely((rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_DONE) + == 0)) + return -EINPROGRESS; + + /* + * Frame receive status + */ + desc->ds_us.rx.rs_datalen = rx_status->rx_status_0 & + AR5K_NEW_RX_DESC_STATUS0_DATA_LEN; + desc->ds_us.rx.rs_rssi = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL); + desc->ds_us.rx.rs_rate = AR5K_REG_MS(rx_status->rx_status_0, + AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE); + desc->ds_us.rx.rs_antenna = rx_status->rx_status_0 & + AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA; + desc->ds_us.rx.rs_more = rx_status->rx_status_0 & + AR5K_NEW_RX_DESC_STATUS0_MORE; + desc->ds_us.rx.rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP); + desc->ds_us.rx.rs_status = 0; + + /* + * Key table status + */ + if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID) + desc->ds_us.rx.rs_keyix = AR5K_REG_MS(rx_status->rx_status_1, + AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX); + else + desc->ds_us.rx.rs_keyix = AR5K_RXKEYIX_INVALID; + + /* + * Receive/descriptor errors + */ + if ((rx_status->rx_status_1 & + AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK) == 0) { + if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR) + desc->ds_us.rx.rs_status |= AR5K_RXERR_CRC; + + if (rx_status->rx_status_1 & + AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR) { + desc->ds_us.rx.rs_status |= AR5K_RXERR_PHY; + desc->ds_us.rx.rs_phyerr = + AR5K_REG_MS(rx_err->rx_error_1, + AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE); + } + + if (rx_status->rx_status_1 & + AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR) + desc->ds_us.rx.rs_status |= AR5K_RXERR_DECRYPT; + + if (rx_status->rx_status_1 & AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR) + desc->ds_us.rx.rs_status |= AR5K_RXERR_MIC; + } + + return 0; +} + + +/****************\ + GPIO Functions +\****************/ + +/* + * Set led state + */ +void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) +{ + u32 led; + /*5210 has different led mode handling*/ + u32 led_5210; + + ATH5K_TRACE(ah->ah_sc); + + /*Reset led status*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, + AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); + else + AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); + + /* + * Some blinking values, define at your wish + */ + switch (state) { + case AR5K_LED_SCAN: + case AR5K_LED_AUTH: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; + led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; + break; + + case AR5K_LED_INIT: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; + led_5210 = AR5K_PCICFG_LED_PEND; + break; + + case AR5K_LED_ASSOC: + case AR5K_LED_RUN: + led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; + led_5210 = AR5K_PCICFG_LED_ASSOC; + break; + + default: + led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; + led_5210 = AR5K_PCICFG_LED_PEND; + break; + } + + /*Write new status to the register*/ + if (ah->ah_version != AR5K_AR5210) + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); + else + AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); +} + +/* + * Set GPIO outputs + */ +int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ + AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); + + return 0; +} + +/* + * Set GPIO inputs + */ +int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, AR5K_GPIOCR) &~ + AR5K_GPIOCR_OUT(gpio)) | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); + + return 0; +} + +/* + * Get GPIO state + */ +u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) +{ + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return 0xffffffff; + + /* GPIO input magic */ + return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & + 0x1; +} + +/* + * Set GPIO state + */ +int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) +{ + u32 data; + ATH5K_TRACE(ah->ah_sc); + + if (gpio > AR5K_NUM_GPIO) + return -EINVAL; + + /* GPIO output magic */ + data = ath5k_hw_reg_read(ah, AR5K_GPIODO); + + data &= ~(1 << gpio); + data |= (val & 1) << gpio; + + ath5k_hw_reg_write(ah, data, AR5K_GPIODO); + + return 0; +} + +/* + * Initialize the GPIO interrupt (RFKill switch) + */ +void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, + u32 interrupt_level) +{ + u32 data; + + ATH5K_TRACE(ah->ah_sc); + if (gpio > AR5K_NUM_GPIO) + return; + + /* + * Set the GPIO interrupt + */ + data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & + ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | + AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | + (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); + + ath5k_hw_reg_write(ah, interrupt_level ? data : + (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); + + ah->ah_imr |= AR5K_IMR_GPIO; + + /* Enable GPIO interrupts */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); +} + + +/*********************************\ + Regulatory Domain/Channels Setup +\*********************************/ + +u16 ath5k_get_regdomain(struct ath5k_hw *ah) +{ + u16 regdomain; + enum ath5k_regdom ieee_regdomain; +#ifdef COUNTRYCODE + u16 code; +#endif + + ath5k_eeprom_regulation_domain(ah, false, &ieee_regdomain); + ah->ah_capabilities.cap_regdomain.reg_hw = ieee_regdomain; + +#ifdef COUNTRYCODE + /* + * Get the regulation domain by country code. This will ignore + * the settings found in the EEPROM. + */ + code = ieee80211_name2countrycode(COUNTRYCODE); + ieee_regdomain = ieee80211_countrycode2regdomain(code); +#endif + + regdomain = ath5k_regdom_from_ieee(ieee_regdomain); + ah->ah_capabilities.cap_regdomain.reg_current = regdomain; + + return regdomain; +} + + +/****************\ + Misc functions +\****************/ + +int ath5k_hw_get_capability(struct ath5k_hw *ah, + enum ath5k_capability_type cap_type, + u32 capability, u32 *result) +{ + ATH5K_TRACE(ah->ah_sc); + + switch (cap_type) { + case AR5K_CAP_NUM_TXQUEUES: + if (result) { + if (ah->ah_version == AR5K_AR5210) + *result = AR5K_NUM_TX_QUEUES_NOQCU; + else + *result = AR5K_NUM_TX_QUEUES; + goto yes; + } + case AR5K_CAP_VEOL: + goto yes; + case AR5K_CAP_COMPRESSION: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + case AR5K_CAP_BURST: + goto yes; + case AR5K_CAP_TPC: + goto yes; + case AR5K_CAP_BSSIDMASK: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + case AR5K_CAP_XR: + if (ah->ah_version == AR5K_AR5212) + goto yes; + else + goto no; + default: + goto no; + } + +no: + return -EINVAL; +yes: + return 0; +} + +static int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, + u16 assoc_id) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); + return 0; + } + + return -EIO; +} + +static int ath5k_hw_disable_pspoll(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_version == AR5K_AR5210) { + AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, + AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA); + return 0; + } + + return -EIO; +} diff --git a/drivers/net/wireless/ath5k/hw.h b/drivers/net/wireless/ath5k/hw.h new file mode 100644 index 000000000000..d9a7c0973f53 --- /dev/null +++ b/drivers/net/wireless/ath5k/hw.h @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2004-2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006-2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007 Matthew W. S. Bell <mentor@madwifi.org> + * Copyright (c) 2007 Luis Rodriguez <mcgrof@winlab.rutgers.edu> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/delay.h> + +/* + * Gain settings + */ + +enum ath5k_rfgain { + AR5K_RFGAIN_INACTIVE = 0, + AR5K_RFGAIN_READ_REQUESTED, + AR5K_RFGAIN_NEED_CHANGE, +}; + +#define AR5K_GAIN_CRN_FIX_BITS_5111 4 +#define AR5K_GAIN_CRN_FIX_BITS_5112 7 +#define AR5K_GAIN_CRN_MAX_FIX_BITS AR5K_GAIN_CRN_FIX_BITS_5112 +#define AR5K_GAIN_DYN_ADJUST_HI_MARGIN 15 +#define AR5K_GAIN_DYN_ADJUST_LO_MARGIN 20 +#define AR5K_GAIN_CCK_PROBE_CORR 5 +#define AR5K_GAIN_CCK_OFDM_GAIN_DELTA 15 +#define AR5K_GAIN_STEP_COUNT 10 +#define AR5K_GAIN_PARAM_TX_CLIP 0 +#define AR5K_GAIN_PARAM_PD_90 1 +#define AR5K_GAIN_PARAM_PD_84 2 +#define AR5K_GAIN_PARAM_GAIN_SEL 3 +#define AR5K_GAIN_PARAM_MIX_ORN 0 +#define AR5K_GAIN_PARAM_PD_138 1 +#define AR5K_GAIN_PARAM_PD_137 2 +#define AR5K_GAIN_PARAM_PD_136 3 +#define AR5K_GAIN_PARAM_PD_132 4 +#define AR5K_GAIN_PARAM_PD_131 5 +#define AR5K_GAIN_PARAM_PD_130 6 +#define AR5K_GAIN_CHECK_ADJUST(_g) \ + ((_g)->g_current <= (_g)->g_low || (_g)->g_current >= (_g)->g_high) + +struct ath5k_gain_opt_step { + s16 gos_param[AR5K_GAIN_CRN_MAX_FIX_BITS]; + s32 gos_gain; +}; + +struct ath5k_gain { + u32 g_step_idx; + u32 g_current; + u32 g_target; + u32 g_low; + u32 g_high; + u32 g_f_corr; + u32 g_active; + const struct ath5k_gain_opt_step *g_step; +}; + + +/* + * HW SPECIFIC STRUCTS + */ + +/* Some EEPROM defines */ +#define AR5K_EEPROM_EEP_SCALE 100 +#define AR5K_EEPROM_EEP_DELTA 10 +#define AR5K_EEPROM_N_MODES 3 +#define AR5K_EEPROM_N_5GHZ_CHAN 10 +#define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_TEST_FREQ 8 +#define AR5K_EEPROM_N_EDGES 8 +#define AR5K_EEPROM_N_INTERCEPTS 11 +#define AR5K_EEPROM_FREQ_M(_v) AR5K_EEPROM_OFF(_v, 0x7f, 0xff) +#define AR5K_EEPROM_PCDAC_M 0x3f +#define AR5K_EEPROM_PCDAC_START 1 +#define AR5K_EEPROM_PCDAC_STOP 63 +#define AR5K_EEPROM_PCDAC_STEP 1 +#define AR5K_EEPROM_NON_EDGE_M 0x40 +#define AR5K_EEPROM_CHANNEL_POWER 8 +#define AR5K_EEPROM_N_OBDB 4 +#define AR5K_EEPROM_OBDB_DIS 0xffff +#define AR5K_EEPROM_CHANNEL_DIS 0xff +#define AR5K_EEPROM_SCALE_OC_DELTA(_x) (((_x) * 2) / 10) +#define AR5K_EEPROM_N_CTLS(_v) AR5K_EEPROM_OFF(_v, 16, 32) +#define AR5K_EEPROM_MAX_CTLS 32 +#define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 +#define AR5K_EEPROM_N_XPD0_POINTS 4 +#define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 +#define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 +#define AR5K_EEPROM_POWER_M 0x3f +#define AR5K_EEPROM_POWER_MIN 0 +#define AR5K_EEPROM_POWER_MAX 3150 +#define AR5K_EEPROM_POWER_STEP 50 +#define AR5K_EEPROM_POWER_TABLE_SIZE 64 +#define AR5K_EEPROM_N_POWER_LOC_11B 4 +#define AR5K_EEPROM_N_POWER_LOC_11G 6 +#define AR5K_EEPROM_I_GAIN 10 +#define AR5K_EEPROM_CCK_OFDM_DELTA 15 +#define AR5K_EEPROM_N_IQ_CAL 2 + +/* Struct to hold EEPROM calibration data */ +struct ath5k_eeprom_info { + u16 ee_magic; + u16 ee_protect; + u16 ee_regdomain; + u16 ee_version; + u16 ee_header; + u16 ee_ant_gain; + u16 ee_misc0; + u16 ee_misc1; + u16 ee_cck_ofdm_gain_delta; + u16 ee_cck_ofdm_power_delta; + u16 ee_scaled_cck_delta; + + /* Used for tx thermal adjustment (eeprom_init, rfregs) */ + u16 ee_tx_clip; + u16 ee_pwd_84; + u16 ee_pwd_90; + u16 ee_gain_select; + + /* RF Calibration settings (reset, rfregs) */ + u16 ee_i_cal[AR5K_EEPROM_N_MODES]; + u16 ee_q_cal[AR5K_EEPROM_N_MODES]; + u16 ee_fixed_bias[AR5K_EEPROM_N_MODES]; + u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; + u16 ee_xr_power[AR5K_EEPROM_N_MODES]; + u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; + u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; + u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; + u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; + u16 ee_tx_end2xlna_enable[AR5K_EEPROM_N_MODES]; + u16 ee_tx_end2xpa_disable[AR5K_EEPROM_N_MODES]; + u16 ee_tx_frm2xpa_enable[AR5K_EEPROM_N_MODES]; + u16 ee_thr_62[AR5K_EEPROM_N_MODES]; + u16 ee_xlna_gain[AR5K_EEPROM_N_MODES]; + u16 ee_xpd[AR5K_EEPROM_N_MODES]; + u16 ee_x_gain[AR5K_EEPROM_N_MODES]; + u16 ee_i_gain[AR5K_EEPROM_N_MODES]; + u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; + + /* Unused */ + u16 ee_false_detect[AR5K_EEPROM_N_MODES]; + u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; + u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ + + /* Conformance test limits (Unused) */ + u16 ee_ctls; + u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; + + /* Noise Floor Calibration settings */ + s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; + s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; + s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; +}; + +/* + * Internal RX/TX descriptor structures + * (rX: reserved fields possibily used by future versions of the ar5k chipset) + */ + +struct ath5k_rx_desc { + u32 rx_control_0; /* RX control word 0 */ + +#define AR5K_DESC_RX_CTL0 0x00000000 + + u32 rx_control_1; /* RX control word 1 */ + +#define AR5K_DESC_RX_CTL1_BUF_LEN 0x00000fff +#define AR5K_DESC_RX_CTL1_INTREQ 0x00002000 +} __packed; + +/* + * 5210/5211 rx status descriptor + */ +struct ath5k_hw_old_rx_status { + u32 rx_status_0; /* RX status word 0 */ + +#define AR5K_OLD_RX_DESC_STATUS0_DATA_LEN 0x00000fff +#define AR5K_OLD_RX_DESC_STATUS0_MORE 0x00001000 +#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE 0x00078000 +#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x07f80000 +#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 19 +#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA 0x38000000 +#define AR5K_OLD_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 27 + + u32 rx_status_1; /* RX status word 1 */ + +#define AR5K_OLD_RX_DESC_STATUS1_DONE 0x00000001 +#define AR5K_OLD_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 +#define AR5K_OLD_RX_DESC_STATUS1_CRC_ERROR 0x00000004 +#define AR5K_OLD_RX_DESC_STATUS1_FIFO_OVERRUN 0x00000008 +#define AR5K_OLD_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000010 +#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR 0x000000e0 +#define AR5K_OLD_RX_DESC_STATUS1_PHY_ERROR_S 5 +#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX 0x00007e00 +#define AR5K_OLD_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x0fff8000 +#define AR5K_OLD_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 15 +#define AR5K_OLD_RX_DESC_STATUS1_KEY_CACHE_MISS 0x10000000 +} __packed; + +/* + * 5212 rx status descriptor + */ +struct ath5k_hw_new_rx_status { + u32 rx_status_0; /* RX status word 0 */ + +#define AR5K_NEW_RX_DESC_STATUS0_DATA_LEN 0x00000fff +#define AR5K_NEW_RX_DESC_STATUS0_MORE 0x00001000 +#define AR5K_NEW_RX_DESC_STATUS0_DECOMP_CRC_ERROR 0x00002000 +#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE 0x000f8000 +#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_RATE_S 15 +#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL 0x0ff00000 +#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_SIGNAL_S 20 +#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA 0xf0000000 +#define AR5K_NEW_RX_DESC_STATUS0_RECEIVE_ANTENNA_S 28 + + u32 rx_status_1; /* RX status word 1 */ + +#define AR5K_NEW_RX_DESC_STATUS1_DONE 0x00000001 +#define AR5K_NEW_RX_DESC_STATUS1_FRAME_RECEIVE_OK 0x00000002 +#define AR5K_NEW_RX_DESC_STATUS1_CRC_ERROR 0x00000004 +#define AR5K_NEW_RX_DESC_STATUS1_DECRYPT_CRC_ERROR 0x00000008 +#define AR5K_NEW_RX_DESC_STATUS1_PHY_ERROR 0x00000010 +#define AR5K_NEW_RX_DESC_STATUS1_MIC_ERROR 0x00000020 +#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_VALID 0x00000100 +#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX 0x0000fe00 +#define AR5K_NEW_RX_DESC_STATUS1_KEY_INDEX_S 9 +#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP 0x7fff0000 +#define AR5K_NEW_RX_DESC_STATUS1_RECEIVE_TIMESTAMP_S 16 +#define AR5K_NEW_RX_DESC_STATUS1_KEY_CACHE_MISS 0x80000000 +} __packed; + +struct ath5k_hw_rx_error { + u32 rx_error_0; /* RX error word 0 */ + +#define AR5K_RX_DESC_ERROR0 0x00000000 + + u32 rx_error_1; /* RX error word 1 */ + +#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE 0x0000ff00 +#define AR5K_RX_DESC_ERROR1_PHY_ERROR_CODE_S 8 +} __packed; + +#define AR5K_DESC_RX_PHY_ERROR_NONE 0x00 +#define AR5K_DESC_RX_PHY_ERROR_TIMING 0x20 +#define AR5K_DESC_RX_PHY_ERROR_PARITY 0x40 +#define AR5K_DESC_RX_PHY_ERROR_RATE 0x60 +#define AR5K_DESC_RX_PHY_ERROR_LENGTH 0x80 +#define AR5K_DESC_RX_PHY_ERROR_64QAM 0xa0 +#define AR5K_DESC_RX_PHY_ERROR_SERVICE 0xc0 +#define AR5K_DESC_RX_PHY_ERROR_TRANSMITOVR 0xe0 + +struct ath5k_hw_2w_tx_desc { + u32 tx_control_0; /* TX control word 0 */ + +#define AR5K_2W_TX_DESC_CTL0_FRAME_LEN 0x00000fff +#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN 0x0003f000 /*[5210 ?]*/ +#define AR5K_2W_TX_DESC_CTL0_HEADER_LEN_S 12 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE 0x003c0000 +#define AR5K_2W_TX_DESC_CTL0_XMIT_RATE_S 18 +#define AR5K_2W_TX_DESC_CTL0_RTSENA 0x00400000 +#define AR5K_2W_TX_DESC_CTL0_CLRDMASK 0x01000000 +#define AR5K_2W_TX_DESC_CTL0_LONG_PACKET 0x00800000 /*[5210]*/ +#define AR5K_2W_TX_DESC_CTL0_VEOL 0x00800000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE 0x1c000000 /*[5210]*/ +#define AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_S 26 +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 0x02000000 +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211 0x1e000000 +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT (ah->ah_version == AR5K_AR5210 ? \ + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5210 : \ + AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_5211) +#define AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 +#define AR5K_2W_TX_DESC_CTL0_INTREQ 0x20000000 +#define AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 + + u32 tx_control_1; /* TX control word 1 */ + +#define AR5K_2W_TX_DESC_CTL1_BUF_LEN 0x00000fff +#define AR5K_2W_TX_DESC_CTL1_MORE 0x00001000 +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 0x0007e000 +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211 0x000fe000 +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX (ah->ah_version == AR5K_AR5210 ? \ + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5210 : \ + AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_5211) +#define AR5K_2W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 +#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE 0x00700000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_S 20 +#define AR5K_2W_TX_DESC_CTL1_NOACK 0x00800000 /*[5211]*/ +#define AR5K_2W_TX_DESC_CTL1_RTS_DURATION 0xfff80000 /*[5210 ?]*/ +} __packed; + +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NORMAL 0x00 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_ATIM 0x04 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PSPOLL 0x08 +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY 0x0c +#define AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS 0x10 + +/* + * 5212 4-word tx control descriptor + */ +struct ath5k_hw_4w_tx_desc { + u32 tx_control_0; /* TX control word 0 */ + +#define AR5K_4W_TX_DESC_CTL0_FRAME_LEN 0x00000fff +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER 0x003f0000 +#define AR5K_4W_TX_DESC_CTL0_XMIT_POWER_S 16 +#define AR5K_4W_TX_DESC_CTL0_RTSENA 0x00400000 +#define AR5K_4W_TX_DESC_CTL0_VEOL 0x00800000 +#define AR5K_4W_TX_DESC_CTL0_CLRDMASK 0x01000000 +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT 0x1e000000 +#define AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT_S 25 +#define AR5K_4W_TX_DESC_CTL0_INTREQ 0x20000000 +#define AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID 0x40000000 +#define AR5K_4W_TX_DESC_CTL0_CTSENA 0x80000000 + + u32 tx_control_1; /* TX control word 1 */ + +#define AR5K_4W_TX_DESC_CTL1_BUF_LEN 0x00000fff +#define AR5K_4W_TX_DESC_CTL1_MORE 0x00001000 +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX 0x000fe000 +#define AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_INDEX_S 13 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE 0x00f00000 +#define AR5K_4W_TX_DESC_CTL1_FRAME_TYPE_S 20 +#define AR5K_4W_TX_DESC_CTL1_NOACK 0x01000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC 0x06000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_PROC_S 25 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN 0x18000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_IV_LEN_S 27 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN 0x60000000 +#define AR5K_4W_TX_DESC_CTL1_COMP_ICV_LEN_S 29 + + u32 tx_control_2; /* TX control word 2 */ + +#define AR5K_4W_TX_DESC_CTL2_RTS_DURATION 0x00007fff +#define AR5K_4W_TX_DESC_CTL2_DURATION_UPDATE_ENABLE 0x00008000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0 0x000f0000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0_S 16 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1 0x00f00000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1_S 20 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2 0x0f000000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2_S 24 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3 0xf0000000 +#define AR5K_4W_TX_DESC_CTL2_XMIT_TRIES3_S 28 + + u32 tx_control_3; /* TX control word 3 */ + +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE0 0x0000001f +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1 0x000003e0 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE1_S 5 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2 0x00007c00 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE2_S 10 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3 0x000f8000 +#define AR5K_4W_TX_DESC_CTL3_XMIT_RATE3_S 15 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE 0x01f00000 +#define AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE_S 20 +} __packed; + +/* + * Common tx status descriptor + */ +struct ath5k_hw_tx_status { + u32 tx_status_0; /* TX status word 0 */ + +#define AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK 0x00000001 +#define AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES 0x00000002 +#define AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN 0x00000004 +#define AR5K_DESC_TX_STATUS0_FILTERED 0x00000008 +/*??? +#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_RTS_FAIL_COUNT_S 4 +*/ +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT 0x000000f0 +#define AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT_S 4 +/*??? +#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_DATA_FAIL_COUNT_S 8 +*/ +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT 0x00000f00 +#define AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT_S 8 +#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT 0x0000f000 +#define AR5K_DESC_TX_STATUS0_VIRT_COLL_COUNT_S 12 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP 0xffff0000 +#define AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP_S 16 + + u32 tx_status_1; /* TX status word 1 */ + +#define AR5K_DESC_TX_STATUS1_DONE 0x00000001 +#define AR5K_DESC_TX_STATUS1_SEQ_NUM 0x00001ffe +#define AR5K_DESC_TX_STATUS1_SEQ_NUM_S 1 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH 0x001fe000 +#define AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH_S 13 +#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX 0x00600000 +#define AR5K_DESC_TX_STATUS1_FINAL_TS_INDEX_S 21 +#define AR5K_DESC_TX_STATUS1_COMP_SUCCESS 0x00800000 +#define AR5K_DESC_TX_STATUS1_XMIT_ANTENNA 0x01000000 +} __packed; + + +/* + * AR5K REGISTER ACCESS + */ + +/*Swap RX/TX Descriptor for big endian archs*/ +#if defined(__BIG_ENDIAN) +#define AR5K_INIT_CFG ( \ + AR5K_CFG_SWTD | AR5K_CFG_SWRD \ +) +#else +#define AR5K_INIT_CFG 0x00000000 +#endif + +/*#define AR5K_REG_READ(_reg) ath5k_hw_reg_read(ah, _reg) + +#define AR5K_REG_WRITE(_reg, _val) ath5k_hw_reg_write(ah, _val, _reg)*/ + +#define AR5K_REG_SM(_val, _flags) \ + (((_val) << _flags##_S) & (_flags)) + +#define AR5K_REG_MS(_val, _flags) \ + (((_val) & (_flags)) >> _flags##_S) + +/* Some registers can hold multiple values of interest. For this + * reason when we want to write to these registers we must first + * retrieve the values which we do not want to clear (lets call this + * old_data) and then set the register with this and our new_value: + * ( old_data | new_value) */ +#define AR5K_REG_WRITE_BITS(ah, _reg, _flags, _val) \ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & ~(_flags)) | \ + (((_val) << _flags##_S) & (_flags)), _reg) + +#define AR5K_REG_MASKED_BITS(ah, _reg, _flags, _mask) \ + ath5k_hw_reg_write(ah, (ath5k_hw_reg_read(ah, _reg) & \ + (_mask)) | (_flags), _reg) + +#define AR5K_REG_ENABLE_BITS(ah, _reg, _flags) \ + ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) | (_flags), _reg) + +#define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ + ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) + +#define AR5K_PHY_WRITE(ah, _reg, _val) \ + ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) + +#define AR5K_PHY_READ(ah, _reg) \ + ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) + +#define AR5K_REG_WAIT(_i) do { \ + if (_i % 64) \ + udelay(1); \ +} while (0) + +#define AR5K_EEPROM_READ(_o, _v) do { \ + if ((ret = ath5k_hw_eeprom_read(ah, (_o), &(_v))) != 0) \ + return (ret); \ +} while (0) + +#define AR5K_EEPROM_READ_HDR(_o, _v) \ + AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ + +/* Read status of selected queue */ +#define AR5K_REG_READ_Q(ah, _reg, _queue) \ + (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ + +#define AR5K_REG_WRITE_Q(ah, _reg, _queue) \ + ath5k_hw_reg_write(ah, (1 << _queue), _reg) + +#define AR5K_Q_ENABLE_BITS(_reg, _queue) do { \ + _reg |= 1 << _queue; \ +} while (0) + +#define AR5K_Q_DISABLE_BITS(_reg, _queue) do { \ + _reg &= ~(1 << _queue); \ +} while (0) + +#define AR5K_LOW_ID(_a)( \ +(_a)[0] | (_a)[1] << 8 | (_a)[2] << 16 | (_a)[3] << 24 \ +) + +#define AR5K_HIGH_ID(_a) ((_a)[4] | (_a)[5] << 8) + +/* + * Initial register values + */ + +/* + * Common initial register values + */ +#define AR5K_INIT_MODE CHANNEL_B + +#define AR5K_INIT_TX_LATENCY 502 +#define AR5K_INIT_USEC 39 +#define AR5K_INIT_USEC_TURBO 79 +#define AR5K_INIT_USEC_32 31 +#define AR5K_INIT_CARR_SENSE_EN 1 +#define AR5K_INIT_PROG_IFS 920 +#define AR5K_INIT_PROG_IFS_TURBO 960 +#define AR5K_INIT_EIFS 3440 +#define AR5K_INIT_EIFS_TURBO 6880 +#define AR5K_INIT_SLOT_TIME 396 +#define AR5K_INIT_SLOT_TIME_TURBO 480 +#define AR5K_INIT_ACK_CTS_TIMEOUT 1024 +#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO 0x08000800 +#define AR5K_INIT_SIFS 560 +#define AR5K_INIT_SIFS_TURBO 480 +#define AR5K_INIT_SH_RETRY 10 +#define AR5K_INIT_LG_RETRY AR5K_INIT_SH_RETRY +#define AR5K_INIT_SSH_RETRY 32 +#define AR5K_INIT_SLG_RETRY AR5K_INIT_SSH_RETRY +#define AR5K_INIT_TX_RETRY 10 +#define AR5K_INIT_TOPS 8 +#define AR5K_INIT_RXNOFRM 8 +#define AR5K_INIT_RPGTO 0 +#define AR5K_INIT_TXNOFRM 0 +#define AR5K_INIT_BEACON_PERIOD 65535 +#define AR5K_INIT_TIM_OFFSET 0 +#define AR5K_INIT_BEACON_EN 0 +#define AR5K_INIT_RESET_TSF 0 + +#define AR5K_INIT_TRANSMIT_LATENCY ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC) \ +) +#define AR5K_INIT_TRANSMIT_LATENCY_TURBO ( \ + (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) | \ + (AR5K_INIT_USEC_TURBO) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) | \ + (AR5K_INIT_PROG_IFS) \ +) +#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO ( \ + (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \ + (AR5K_INIT_PROG_IFS_TURBO) \ +) +#define AR5K_INIT_BEACON_CONTROL ( \ + (AR5K_INIT_RESET_TSF << 24) | (AR5K_INIT_BEACON_EN << 23) | \ + (AR5K_INIT_TIM_OFFSET << 16) | (AR5K_INIT_BEACON_PERIOD) \ +) + +/* + * Non-common initial register values which have to be loaded into the + * card at boot time and after each reset. + */ + +/* Register dumps are done per operation mode */ +#define AR5K_INI_RFGAIN_5GHZ 0 +#define AR5K_INI_RFGAIN_2GHZ 1 + +#define AR5K_INI_VAL_11A 0 +#define AR5K_INI_VAL_11A_TURBO 1 +#define AR5K_INI_VAL_11B 2 +#define AR5K_INI_VAL_11G 3 +#define AR5K_INI_VAL_11G_TURBO 4 +#define AR5K_INI_VAL_XR 0 +#define AR5K_INI_VAL_MAX 5 + +#define AR5K_RF5111_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS +#define AR5K_RF5112_INI_RF_MAX_BANKS AR5K_MAX_RF_BANKS + +static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) +{ + u32 retval = 0, bit, i; + + for (i = 0; i < bits; i++) { + bit = (val >> i) & 1; + retval = (retval << 1) | bit; + } + + return retval; +} diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c new file mode 100644 index 000000000000..2c22f1d4ee64 --- /dev/null +++ b/drivers/net/wireless/ath5k/initvals.c @@ -0,0 +1,1347 @@ +/* + * Initial register settings functions + * + * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "ath5k.h" +#include "base.h" +#include "reg.h" + +/* + * MAC/PHY REGISTERS + */ + + +/* + * Mode-independent initial register writes + */ + +struct ath5k_ini { + u16 ini_register; + u32 ini_value; + + enum { + AR5K_INI_WRITE = 0, /* Default */ + AR5K_INI_READ = 1, /* Cleared on read */ + } ini_mode; +}; + +/* + * Mode specific initial register values + */ + +struct ath5k_ini_mode { + u16 mode_register; + u32 mode_value[5]; +}; + +/* Initial register settings for AR5210 */ +static const struct ath5k_ini ar5210_ini[] = { + /* PCU and MAC registers */ + { AR5K_NOQCU_TXDP0, 0 }, + { AR5K_NOQCU_TXDP1, 0 }, + { AR5K_RXDP, 0 }, + { AR5K_CR, 0 }, + { AR5K_ISR, 0, AR5K_INI_READ }, + { AR5K_IMR, 0 }, + { AR5K_IER, AR5K_IER_DISABLE }, + { AR5K_BSR, 0, AR5K_INI_READ }, + { AR5K_TXCFG, AR5K_DMASIZE_128B }, + { AR5K_RXCFG, AR5K_DMASIZE_128B }, + { AR5K_CFG, AR5K_INIT_CFG }, + { AR5K_TOPS, AR5K_INIT_TOPS }, + { AR5K_RXNOFRM, AR5K_INIT_RXNOFRM }, + { AR5K_RPGTO, AR5K_INIT_RPGTO }, + { AR5K_TXNOFRM, AR5K_INIT_TXNOFRM }, + { AR5K_SFR, 0 }, + { AR5K_MIBC, 0 }, + { AR5K_MISC, 0 }, + { AR5K_RX_FILTER_5210, 0 }, + { AR5K_MCAST_FILTER0_5210, 0 }, + { AR5K_MCAST_FILTER1_5210, 0 }, + { AR5K_TX_MASK0, 0 }, + { AR5K_TX_MASK1, 0 }, + { AR5K_CLR_TMASK, 0 }, + { AR5K_TRIG_LVL, AR5K_TUNE_MIN_TX_FIFO_THRES }, + { AR5K_DIAG_SW_5210, 0 }, + { AR5K_RSSI_THR, AR5K_TUNE_RSSI_THRES }, + { AR5K_TSF_L32_5210, 0 }, + { AR5K_TIMER0_5210, 0 }, + { AR5K_TIMER1_5210, 0xffffffff }, + { AR5K_TIMER2_5210, 0xffffffff }, + { AR5K_TIMER3_5210, 1 }, + { AR5K_CFP_DUR_5210, 0 }, + { AR5K_CFP_PERIOD_5210, 0 }, + /* PHY registers */ + { AR5K_PHY(0), 0x00000047 }, + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY(3), 0x09848ea6 }, + { AR5K_PHY(4), 0x3d32e000 }, + { AR5K_PHY(5), 0x0000076b }, + { AR5K_PHY_ACT, AR5K_PHY_ACT_DISABLE }, + { AR5K_PHY(8), 0x02020200 }, + { AR5K_PHY(9), 0x00000e0e }, + { AR5K_PHY(10), 0x0a020201 }, + { AR5K_PHY(11), 0x00036ffc }, + { AR5K_PHY(12), 0x00000000 }, + { AR5K_PHY(13), 0x00000e0e }, + { AR5K_PHY(14), 0x00000007 }, + { AR5K_PHY(15), 0x00020100 }, + { AR5K_PHY(16), 0x89630000 }, + { AR5K_PHY(17), 0x1372169c }, + { AR5K_PHY(18), 0x0018b633 }, + { AR5K_PHY(19), 0x1284613c }, + { AR5K_PHY(20), 0x0de8b8e0 }, + { AR5K_PHY(21), 0x00074859 }, + { AR5K_PHY(22), 0x7e80beba }, + { AR5K_PHY(23), 0x313a665e }, + { AR5K_PHY_AGCCTL, 0x00001d08 }, + { AR5K_PHY(25), 0x0001ce00 }, + { AR5K_PHY(26), 0x409a4190 }, + { AR5K_PHY(28), 0x0000000f }, + { AR5K_PHY(29), 0x00000080 }, + { AR5K_PHY(30), 0x00000004 }, + { AR5K_PHY(31), 0x00000018 }, /* 0x987c */ + { AR5K_PHY(64), 0x00000000 }, /* 0x9900 */ + { AR5K_PHY(65), 0x00000000 }, + { AR5K_PHY(66), 0x00000000 }, + { AR5K_PHY(67), 0x00800000 }, + { AR5K_PHY(68), 0x00000003 }, + /* BB gain table (64bytes) */ + { AR5K_BB_GAIN(0), 0x00000000 }, + { AR5K_BB_GAIN(1), 0x00000020 }, + { AR5K_BB_GAIN(2), 0x00000010 }, + { AR5K_BB_GAIN(3), 0x00000030 }, + { AR5K_BB_GAIN(4), 0x00000008 }, + { AR5K_BB_GAIN(5), 0x00000028 }, + { AR5K_BB_GAIN(6), 0x00000028 }, + { AR5K_BB_GAIN(7), 0x00000004 }, + { AR5K_BB_GAIN(8), 0x00000024 }, + { AR5K_BB_GAIN(9), 0x00000014 }, + { AR5K_BB_GAIN(10), 0x00000034 }, + { AR5K_BB_GAIN(11), 0x0000000c }, + { AR5K_BB_GAIN(12), 0x0000002c }, + { AR5K_BB_GAIN(13), 0x00000002 }, + { AR5K_BB_GAIN(14), 0x00000022 }, + { AR5K_BB_GAIN(15), 0x00000012 }, + { AR5K_BB_GAIN(16), 0x00000032 }, + { AR5K_BB_GAIN(17), 0x0000000a }, + { AR5K_BB_GAIN(18), 0x0000002a }, + { AR5K_BB_GAIN(19), 0x00000001 }, + { AR5K_BB_GAIN(20), 0x00000021 }, + { AR5K_BB_GAIN(21), 0x00000011 }, + { AR5K_BB_GAIN(22), 0x00000031 }, + { AR5K_BB_GAIN(23), 0x00000009 }, + { AR5K_BB_GAIN(24), 0x00000029 }, + { AR5K_BB_GAIN(25), 0x00000005 }, + { AR5K_BB_GAIN(26), 0x00000025 }, + { AR5K_BB_GAIN(27), 0x00000015 }, + { AR5K_BB_GAIN(28), 0x00000035 }, + { AR5K_BB_GAIN(29), 0x0000000d }, + { AR5K_BB_GAIN(30), 0x0000002d }, + { AR5K_BB_GAIN(31), 0x00000003 }, + { AR5K_BB_GAIN(32), 0x00000023 }, + { AR5K_BB_GAIN(33), 0x00000013 }, + { AR5K_BB_GAIN(34), 0x00000033 }, + { AR5K_BB_GAIN(35), 0x0000000b }, + { AR5K_BB_GAIN(36), 0x0000002b }, + { AR5K_BB_GAIN(37), 0x00000007 }, + { AR5K_BB_GAIN(38), 0x00000027 }, + { AR5K_BB_GAIN(39), 0x00000017 }, + { AR5K_BB_GAIN(40), 0x00000037 }, + { AR5K_BB_GAIN(41), 0x0000000f }, + { AR5K_BB_GAIN(42), 0x0000002f }, + { AR5K_BB_GAIN(43), 0x0000002f }, + { AR5K_BB_GAIN(44), 0x0000002f }, + { AR5K_BB_GAIN(45), 0x0000002f }, + { AR5K_BB_GAIN(46), 0x0000002f }, + { AR5K_BB_GAIN(47), 0x0000002f }, + { AR5K_BB_GAIN(48), 0x0000002f }, + { AR5K_BB_GAIN(49), 0x0000002f }, + { AR5K_BB_GAIN(50), 0x0000002f }, + { AR5K_BB_GAIN(51), 0x0000002f }, + { AR5K_BB_GAIN(52), 0x0000002f }, + { AR5K_BB_GAIN(53), 0x0000002f }, + { AR5K_BB_GAIN(54), 0x0000002f }, + { AR5K_BB_GAIN(55), 0x0000002f }, + { AR5K_BB_GAIN(56), 0x0000002f }, + { AR5K_BB_GAIN(57), 0x0000002f }, + { AR5K_BB_GAIN(58), 0x0000002f }, + { AR5K_BB_GAIN(59), 0x0000002f }, + { AR5K_BB_GAIN(60), 0x0000002f }, + { AR5K_BB_GAIN(61), 0x0000002f }, + { AR5K_BB_GAIN(62), 0x0000002f }, + { AR5K_BB_GAIN(63), 0x0000002f }, + /* 5110 RF gain table (64btes) */ + { AR5K_RF_GAIN(0), 0x0000001d }, + { AR5K_RF_GAIN(1), 0x0000005d }, + { AR5K_RF_GAIN(2), 0x0000009d }, + { AR5K_RF_GAIN(3), 0x000000dd }, + { AR5K_RF_GAIN(4), 0x0000011d }, + { AR5K_RF_GAIN(5), 0x00000021 }, + { AR5K_RF_GAIN(6), 0x00000061 }, + { AR5K_RF_GAIN(7), 0x000000a1 }, + { AR5K_RF_GAIN(8), 0x000000e1 }, + { AR5K_RF_GAIN(9), 0x00000031 }, + { AR5K_RF_GAIN(10), 0x00000071 }, + { AR5K_RF_GAIN(11), 0x000000b1 }, + { AR5K_RF_GAIN(12), 0x0000001c }, + { AR5K_RF_GAIN(13), 0x0000005c }, + { AR5K_RF_GAIN(14), 0x00000029 }, + { AR5K_RF_GAIN(15), 0x00000069 }, + { AR5K_RF_GAIN(16), 0x000000a9 }, + { AR5K_RF_GAIN(17), 0x00000020 }, + { AR5K_RF_GAIN(18), 0x00000019 }, + { AR5K_RF_GAIN(19), 0x00000059 }, + { AR5K_RF_GAIN(20), 0x00000099 }, + { AR5K_RF_GAIN(21), 0x00000030 }, + { AR5K_RF_GAIN(22), 0x00000005 }, + { AR5K_RF_GAIN(23), 0x00000025 }, + { AR5K_RF_GAIN(24), 0x00000065 }, + { AR5K_RF_GAIN(25), 0x000000a5 }, + { AR5K_RF_GAIN(26), 0x00000028 }, + { AR5K_RF_GAIN(27), 0x00000068 }, + { AR5K_RF_GAIN(28), 0x0000001f }, + { AR5K_RF_GAIN(29), 0x0000001e }, + { AR5K_RF_GAIN(30), 0x00000018 }, + { AR5K_RF_GAIN(31), 0x00000058 }, + { AR5K_RF_GAIN(32), 0x00000098 }, + { AR5K_RF_GAIN(33), 0x00000003 }, + { AR5K_RF_GAIN(34), 0x00000004 }, + { AR5K_RF_GAIN(35), 0x00000044 }, + { AR5K_RF_GAIN(36), 0x00000084 }, + { AR5K_RF_GAIN(37), 0x00000013 }, + { AR5K_RF_GAIN(38), 0x00000012 }, + { AR5K_RF_GAIN(39), 0x00000052 }, + { AR5K_RF_GAIN(40), 0x00000092 }, + { AR5K_RF_GAIN(41), 0x000000d2 }, + { AR5K_RF_GAIN(42), 0x0000002b }, + { AR5K_RF_GAIN(43), 0x0000002a }, + { AR5K_RF_GAIN(44), 0x0000006a }, + { AR5K_RF_GAIN(45), 0x000000aa }, + { AR5K_RF_GAIN(46), 0x0000001b }, + { AR5K_RF_GAIN(47), 0x0000001a }, + { AR5K_RF_GAIN(48), 0x0000005a }, + { AR5K_RF_GAIN(49), 0x0000009a }, + { AR5K_RF_GAIN(50), 0x000000da }, + { AR5K_RF_GAIN(51), 0x00000006 }, + { AR5K_RF_GAIN(52), 0x00000006 }, + { AR5K_RF_GAIN(53), 0x00000006 }, + { AR5K_RF_GAIN(54), 0x00000006 }, + { AR5K_RF_GAIN(55), 0x00000006 }, + { AR5K_RF_GAIN(56), 0x00000006 }, + { AR5K_RF_GAIN(57), 0x00000006 }, + { AR5K_RF_GAIN(58), 0x00000006 }, + { AR5K_RF_GAIN(59), 0x00000006 }, + { AR5K_RF_GAIN(60), 0x00000006 }, + { AR5K_RF_GAIN(61), 0x00000006 }, + { AR5K_RF_GAIN(62), 0x00000006 }, + { AR5K_RF_GAIN(63), 0x00000006 }, + /* PHY activation */ + { AR5K_PHY(53), 0x00000020 }, + { AR5K_PHY(51), 0x00000004 }, + { AR5K_PHY(50), 0x00060106 }, + { AR5K_PHY(39), 0x0000006d }, + { AR5K_PHY(48), 0x00000000 }, + { AR5K_PHY(52), 0x00000014 }, + { AR5K_PHY_ACT, AR5K_PHY_ACT_ENABLE }, +}; + +/* Initial register settings for AR5211 */ +static const struct ath5k_ini ar5211_ini[] = { + { AR5K_RXDP, 0x00000000 }, + { AR5K_RTSD0, 0x84849c9c }, + { AR5K_RTSD1, 0x7c7c7c7c }, + { AR5K_RXCFG, 0x00000005 }, + { AR5K_MIBC, 0x00000000 }, + { AR5K_TOPS, 0x00000008 }, + { AR5K_RXNOFRM, 0x00000008 }, + { AR5K_TXNOFRM, 0x00000010 }, + { AR5K_RPGTO, 0x00000000 }, + { AR5K_RFCNT, 0x0000001f }, + { AR5K_QUEUE_TXDP(0), 0x00000000 }, + { AR5K_QUEUE_TXDP(1), 0x00000000 }, + { AR5K_QUEUE_TXDP(2), 0x00000000 }, + { AR5K_QUEUE_TXDP(3), 0x00000000 }, + { AR5K_QUEUE_TXDP(4), 0x00000000 }, + { AR5K_QUEUE_TXDP(5), 0x00000000 }, + { AR5K_QUEUE_TXDP(6), 0x00000000 }, + { AR5K_QUEUE_TXDP(7), 0x00000000 }, + { AR5K_QUEUE_TXDP(8), 0x00000000 }, + { AR5K_QUEUE_TXDP(9), 0x00000000 }, + { AR5K_DCU_FP, 0x00000000 }, + { AR5K_STA_ID1, 0x00000000 }, + { AR5K_BSS_ID0, 0x00000000 }, + { AR5K_BSS_ID1, 0x00000000 }, + { AR5K_RSSI_THR, 0x00000000 }, + { AR5K_CFP_PERIOD_5211, 0x00000000 }, + { AR5K_TIMER0_5211, 0x00000030 }, + { AR5K_TIMER1_5211, 0x0007ffff }, + { AR5K_TIMER2_5211, 0x01ffffff }, + { AR5K_TIMER3_5211, 0x00000031 }, + { AR5K_CFP_DUR_5211, 0x00000000 }, + { AR5K_RX_FILTER_5211, 0x00000000 }, + { AR5K_MCAST_FILTER0_5211, 0x00000000 }, + { AR5K_MCAST_FILTER1_5211, 0x00000002 }, + { AR5K_DIAG_SW_5211, 0x00000000 }, + { AR5K_ADDAC_TEST, 0x00000000 }, + { AR5K_DEFAULT_ANTENNA, 0x00000000 }, + /* PHY registers */ + { AR5K_PHY_AGC, 0x00000000 }, + { AR5K_PHY(3), 0x2d849093 }, + { AR5K_PHY(4), 0x7d32e000 }, + { AR5K_PHY(5), 0x00000f6b }, + { AR5K_PHY_ACT, 0x00000000 }, + { AR5K_PHY(11), 0x00026ffe }, + { AR5K_PHY(12), 0x00000000 }, + { AR5K_PHY(15), 0x00020100 }, + { AR5K_PHY(16), 0x206a017a }, + { AR5K_PHY(19), 0x1284613c }, + { AR5K_PHY(21), 0x00000859 }, + { AR5K_PHY(26), 0x409a4190 }, /* 0x9868 */ + { AR5K_PHY(27), 0x050cb081 }, + { AR5K_PHY(28), 0x0000000f }, + { AR5K_PHY(29), 0x00000080 }, + { AR5K_PHY(30), 0x0000000c }, + { AR5K_PHY(64), 0x00000000 }, + { AR5K_PHY(65), 0x00000000 }, + { AR5K_PHY(66), 0x00000000 }, + { AR5K_PHY(67), 0x00800000 }, + { AR5K_PHY(68), 0x00000001 }, + { AR5K_PHY(71), 0x0000092a }, + { AR5K_PHY_IQ, 0x00000000 }, + { AR5K_PHY(73), 0x00058a05 }, + { AR5K_PHY(74), 0x00000001 }, + { AR5K_PHY(75), 0x00000000 }, + { AR5K_PHY_PAPD_PROBE, 0x00000000 }, + { AR5K_PHY(77), 0x00000000 }, /* 0x9934 */ + { AR5K_PHY(78), 0x00000000 }, /* 0x9938 */ + { AR5K_PHY(79), 0x0000003f }, /* 0x993c */ + { AR5K_PHY(80), 0x00000004 }, + { AR5K_PHY(82), 0x00000000 }, + { AR5K_PHY(83), 0x00000000 }, + { AR5K_PHY(84), 0x00000000 }, + { AR5K_PHY_RADAR, 0x5d50f14c }, + { AR5K_PHY(86), 0x00000018 }, + { AR5K_PHY(87), 0x004b6a8e }, + /* Initial Power table (32bytes) + * common on all cards/modes. + * Note: Table is rewritten during + * txpower setup later using calibration + * data etc. so next write is non-common + { AR5K_PHY_PCDAC_TXPOWER(1), 0x06ff05ff }, + { AR5K_PHY_PCDAC_TXPOWER(2), 0x07ff07ff }, + { AR5K_PHY_PCDAC_TXPOWER(3), 0x08ff08ff }, + { AR5K_PHY_PCDAC_TXPOWER(4), 0x09ff09ff }, + { AR5K_PHY_PCDAC_TXPOWER(5), 0x0aff0aff }, + { AR5K_PHY_PCDAC_TXPOWER(6), 0x0bff0bff }, + { AR5K_PHY_PCDAC_TXPOWER(7), 0x0cff0cff }, + { AR5K_PHY_PCDAC_TXPOWER(8), 0x0dff0dff }, + { AR5K_PHY_PCDAC_TXPOWER(9), 0x0fff0eff }, + { AR5K_PHY_PCDAC_TXPOWER(10), 0x12ff12ff }, + { AR5K_PHY_PCDAC_TXPOWER(11), 0x14ff13ff }, + { AR5K_PHY_PCDAC_TXPOWER(12), 0x16ff15ff }, + { AR5K_PHY_PCDAC_TXPOWER(13), 0x19ff17ff }, + { AR5K_PHY_PCDAC_TXPOWER(14), 0x1bff1aff }, + { AR5K_PHY_PCDAC_TXPOWER(15), 0x1eff1dff }, + { AR5K_PHY_PCDAC_TXPOWER(16), 0x23ff20ff }, + { AR5K_PHY_PCDAC_TXPOWER(17), 0x27ff25ff }, + { AR5K_PHY_PCDAC_TXPOWER(18), 0x2cff29ff }, + { AR5K_PHY_PCDAC_TXPOWER(19), 0x31ff2fff }, + { AR5K_PHY_PCDAC_TXPOWER(20), 0x37ff34ff }, + { AR5K_PHY_PCDAC_TXPOWER(21), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(22), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(23), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(24), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(25), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(26), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(27), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(28), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(29), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(30), 0x3aff3aff }, + { AR5K_PHY_PCDAC_TXPOWER(31), 0x3aff3aff },*/ + { AR5K_PHY_CCKTXCTL, 0x00000000 }, + { AR5K_PHY(642), 0x503e4646 }, + { AR5K_PHY_GAIN_2GHZ, 0x6480416c }, + { AR5K_PHY(644), 0x0199a003 }, + { AR5K_PHY(645), 0x044cd610 }, + { AR5K_PHY(646), 0x13800040 }, + { AR5K_PHY(647), 0x1be00060 }, + { AR5K_PHY(648), 0x0c53800a }, + { AR5K_PHY(649), 0x0014df3b }, + { AR5K_PHY(650), 0x000001b5 }, + { AR5K_PHY(651), 0x00000020 }, +}; + +/* Initial mode-specific settings for AR5211 + * XXX: how about g / gTurbo ? RF5111 supports it, how about AR5211 ? + * Maybe 5211 supports OFDM-only g but we need to test it ! + */ +static const struct ath5k_ini_mode ar5211_ini_mode[] = { + { AR5K_TXCFG, + /* a aTurbo b */ + { 0x00000015, 0x00000015, 0x0000001d } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(0), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(1), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(2), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(3), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(4), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(5), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(6), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(7), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(8), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(9), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f } }, + { AR5K_DCU_GBL_IFS_SLOT, + { 0x00000168, 0x000001e0, 0x000001b8 } }, + { AR5K_DCU_GBL_IFS_SIFS, + { 0x00000230, 0x000001e0, 0x000000b0 } }, + { AR5K_DCU_GBL_IFS_EIFS, + { 0x00000d98, 0x00001180, 0x00001f48 } }, + { AR5K_DCU_GBL_IFS_MISC, + { 0x0000a0e0, 0x00014068, 0x00005880 } }, + { AR5K_TIME_OUT, + { 0x04000400, 0x08000800, 0x20003000 } }, + { AR5K_USEC_5211, + { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95 } }, + { AR5K_PHY_TURBO, + { 0x00000000, 0x00000003, 0x00000000 } }, + { AR5K_PHY(8), + { 0x02020200, 0x02020200, 0x02010200 } }, + { AR5K_PHY(9), + { 0x00000e0e, 0x00000e0e, 0x00000707 } }, + { AR5K_PHY(10), + { 0x0a020001, 0x0a020001, 0x05010000 } }, + { AR5K_PHY(13), + { 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY(14), + { 0x00000007, 0x00000007, 0x0000000b } }, + { AR5K_PHY(17), + { 0x1372169c, 0x137216a5, 0x137216a8 } }, + { AR5K_PHY(18), + { 0x0018ba67, 0x0018ba67, 0x0018ba69 } }, + { AR5K_PHY(20), + { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x31375d5e, 0x31375d5e, 0x313a5d5e } }, + { AR5K_PHY_AGCCTL, + { 0x0000bd10, 0x0000bd10, 0x0000bd38 } }, + { AR5K_PHY_NF, + { 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, + { AR5K_PHY_RX_DELAY, + { 0x00002710, 0x00002710, 0x0000157c } }, + { AR5K_PHY(70), + { 0x00000190, 0x00000190, 0x00000084 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0x6fe01020, 0x6fe01020, 0x6fe00920 } }, + { AR5K_PHY_PCDAC_TXPOWER_BASE_5211, + { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff } }, + { AR5K_RF_BUFFER_CONTROL_4, + { 0x00000010, 0x00000014, 0x00000010 } }, +}; + +/* Initial register settings for AR5212 */ +static const struct ath5k_ini ar5212_ini[] = { + { AR5K_RXDP, 0x00000000 }, + { AR5K_RXCFG, 0x00000005 }, + { AR5K_MIBC, 0x00000000 }, + { AR5K_TOPS, 0x00000008 }, + { AR5K_RXNOFRM, 0x00000008 }, + { AR5K_TXNOFRM, 0x00000010 }, + { AR5K_RPGTO, 0x00000000 }, + { AR5K_RFCNT, 0x0000001f }, + { AR5K_QUEUE_TXDP(0), 0x00000000 }, + { AR5K_QUEUE_TXDP(1), 0x00000000 }, + { AR5K_QUEUE_TXDP(2), 0x00000000 }, + { AR5K_QUEUE_TXDP(3), 0x00000000 }, + { AR5K_QUEUE_TXDP(4), 0x00000000 }, + { AR5K_QUEUE_TXDP(5), 0x00000000 }, + { AR5K_QUEUE_TXDP(6), 0x00000000 }, + { AR5K_QUEUE_TXDP(7), 0x00000000 }, + { AR5K_QUEUE_TXDP(8), 0x00000000 }, + { AR5K_QUEUE_TXDP(9), 0x00000000 }, + { AR5K_DCU_FP, 0x00000000 }, + { AR5K_DCU_TXP, 0x00000000 }, + { AR5K_DCU_TX_FILTER, 0x00000000 }, + /* Unknown table */ + { 0x1078, 0x00000000 }, + { 0x10b8, 0x00000000 }, + { 0x10f8, 0x00000000 }, + { 0x1138, 0x00000000 }, + { 0x1178, 0x00000000 }, + { 0x11b8, 0x00000000 }, + { 0x11f8, 0x00000000 }, + { 0x1238, 0x00000000 }, + { 0x1278, 0x00000000 }, + { 0x12b8, 0x00000000 }, + { 0x12f8, 0x00000000 }, + { 0x1338, 0x00000000 }, + { 0x1378, 0x00000000 }, + { 0x13b8, 0x00000000 }, + { 0x13f8, 0x00000000 }, + { 0x1438, 0x00000000 }, + { 0x1478, 0x00000000 }, + { 0x14b8, 0x00000000 }, + { 0x14f8, 0x00000000 }, + { 0x1538, 0x00000000 }, + { 0x1578, 0x00000000 }, + { 0x15b8, 0x00000000 }, + { 0x15f8, 0x00000000 }, + { 0x1638, 0x00000000 }, + { 0x1678, 0x00000000 }, + { 0x16b8, 0x00000000 }, + { 0x16f8, 0x00000000 }, + { 0x1738, 0x00000000 }, + { 0x1778, 0x00000000 }, + { 0x17b8, 0x00000000 }, + { 0x17f8, 0x00000000 }, + { 0x103c, 0x00000000 }, + { 0x107c, 0x00000000 }, + { 0x10bc, 0x00000000 }, + { 0x10fc, 0x00000000 }, + { 0x113c, 0x00000000 }, + { 0x117c, 0x00000000 }, + { 0x11bc, 0x00000000 }, + { 0x11fc, 0x00000000 }, + { 0x123c, 0x00000000 }, + { 0x127c, 0x00000000 }, + { 0x12bc, 0x00000000 }, + { 0x12fc, 0x00000000 }, + { 0x133c, 0x00000000 }, + { 0x137c, 0x00000000 }, + { 0x13bc, 0x00000000 }, + { 0x13fc, 0x00000000 }, + { 0x143c, 0x00000000 }, + { 0x147c, 0x00000000 }, + { AR5K_DCU_TX_FILTER_CLR, 0x00000000 }, + { AR5K_DCU_TX_FILTER_SET, 0x00000000 }, + { AR5K_STA_ID1, 0x00000000 }, + { AR5K_BSS_ID0, 0x00000000 }, + { AR5K_BSS_ID1, 0x00000000 }, + /*{ AR5K_RSSI_THR, 0x00000000 },*/ /* Found on SuperAG cards */ + { AR5K_BEACON_5211, 0x00000000 }, /* Found on SuperAG cards */ + { AR5K_CFP_PERIOD_5211, 0x00000000 }, /* Found on SuperAG cards */ + { AR5K_TIMER0_5211, 0x00000030 }, /* Found on SuperAG cards */ + { AR5K_TIMER1_5211, 0x0007ffff }, /* Found on SuperAG cards */ + { AR5K_TIMER2_5211, 0x01ffffff }, /* Found on SuperAG cards */ + { AR5K_TIMER3_5211, 0x00000031 }, /* Found on SuperAG cards */ + { AR5K_CFP_DUR_5211, 0x00000000 }, /* Found on SuperAG cards */ + { AR5K_RX_FILTER_5211, 0x00000000 }, + { AR5K_DIAG_SW_5211, 0x00000000 }, + { AR5K_ADDAC_TEST, 0x00000000 }, + { AR5K_DEFAULT_ANTENNA, 0x00000000 }, + { 0x8080, 0x00000000 }, + /*{ 0x805c, 0xffffc7ff },*/ /* Old value */ + { 0x805c, 0x000fc78f }, + { AR5K_NAV_5211, 0x00000000 }, /* Not found on recent */ + { AR5K_RTS_OK_5211, 0x00000000 }, /* dumps but it makes */ + { AR5K_RTS_FAIL_5211, 0x00000000 }, /* sense to reset counters */ + { AR5K_ACK_FAIL_5211, 0x00000000 }, /* since pcu registers */ + { AR5K_FCS_FAIL_5211, 0x00000000 }, /* are skiped during chan*/ + { AR5K_BEACON_CNT_5211, 0x00000000 }, /* change */ + { AR5K_XRMODE, 0x2a82301a }, + { AR5K_XRDELAY, 0x05dc01e0 }, + { AR5K_XRTIMEOUT, 0x1f402710 }, + { AR5K_XRCHIRP, 0x01f40000 }, + { AR5K_XRSTOMP, 0x00001e1c }, + { AR5K_SLEEP0, 0x0002aaaa }, /* Found on SuperAG cards */ + { AR5K_SLEEP1, 0x02005555 }, /* Found on SuperAG cards */ + { AR5K_SLEEP2, 0x00000000 }, /* Found on SuperAG cards */ + { AR5K_BSS_IDM0, 0xffffffff }, + { AR5K_BSS_IDM1, 0x0000ffff }, + { AR5K_TXPC, 0x00000000 }, + { AR5K_PROFCNT_TX, 0x00000000 }, + { AR5K_PROFCNT_RX, 0x00000000 }, + { AR5K_PROFCNT_RXCLR, 0x00000000 }, + { AR5K_PROFCNT_CYCLE, 0x00000000 }, + { 0x80fc, 0x00000088 }, + { AR5K_RATE_DUR(0), 0x00000000 }, + { AR5K_RATE_DUR(1), 0x0000008c }, + { AR5K_RATE_DUR(2), 0x000000e4 }, + { AR5K_RATE_DUR(3), 0x000002d5 }, + { AR5K_RATE_DUR(4), 0x00000000 }, + { AR5K_RATE_DUR(5), 0x00000000 }, + { AR5K_RATE_DUR(6), 0x000000a0 }, + { AR5K_RATE_DUR(7), 0x000001c9 }, + { AR5K_RATE_DUR(8), 0x0000002c }, + { AR5K_RATE_DUR(9), 0x0000002c }, + { AR5K_RATE_DUR(10), 0x00000030 }, + { AR5K_RATE_DUR(11), 0x0000003c }, + { AR5K_RATE_DUR(12), 0x0000002c }, + { AR5K_RATE_DUR(13), 0x0000002c }, + { AR5K_RATE_DUR(14), 0x00000030 }, + { AR5K_RATE_DUR(15), 0x0000003c }, + { AR5K_RATE_DUR(16), 0x00000000 }, + { AR5K_RATE_DUR(17), 0x00000000 }, + { AR5K_RATE_DUR(18), 0x00000000 }, + { AR5K_RATE_DUR(19), 0x00000000 }, + { AR5K_RATE_DUR(20), 0x00000000 }, + { AR5K_RATE_DUR(21), 0x00000000 }, + { AR5K_RATE_DUR(22), 0x00000000 }, + { AR5K_RATE_DUR(23), 0x00000000 }, + { AR5K_RATE_DUR(24), 0x000000d5 }, + { AR5K_RATE_DUR(25), 0x000000df }, + { AR5K_RATE_DUR(26), 0x00000102 }, + { AR5K_RATE_DUR(27), 0x0000013a }, + { AR5K_RATE_DUR(28), 0x00000075 }, + { AR5K_RATE_DUR(29), 0x0000007f }, + { AR5K_RATE_DUR(30), 0x000000a2 }, + { AR5K_RATE_DUR(31), 0x00000000 }, + { 0x8100, 0x00010002}, + { AR5K_TSF_PARM, 0x00000001 }, + { 0x8108, 0x000000c0 }, + { AR5K_PHY_ERR_FIL, 0x00000000 }, + { 0x8110, 0x00000168 }, + { 0x8114, 0x00000000 }, + /* Some kind of table + * also notice ...03<-02<-01<-00) */ + { 0x87c0, 0x03020100 }, + { 0x87c4, 0x07060504 }, + { 0x87c8, 0x0b0a0908 }, + { 0x87cc, 0x0f0e0d0c }, + { 0x87d0, 0x13121110 }, + { 0x87d4, 0x17161514 }, + { 0x87d8, 0x1b1a1918 }, + { 0x87dc, 0x1f1e1d1c }, + /* loop ? */ + { 0x87e0, 0x03020100 }, + { 0x87e4, 0x07060504 }, + { 0x87e8, 0x0b0a0908 }, + { 0x87ec, 0x0f0e0d0c }, + { 0x87f0, 0x13121110 }, + { 0x87f4, 0x17161514 }, + { 0x87f8, 0x1b1a1918 }, + { 0x87fc, 0x1f1e1d1c }, + /* PHY registers */ + /*{ AR5K_PHY_AGC, 0x00000000 },*/ + { AR5K_PHY(3), 0xad848e19 }, + { AR5K_PHY(4), 0x7d28e000 }, + { AR5K_PHY_TIMING_3, 0x9c0a9f6b }, + { AR5K_PHY_ACT, 0x00000000 }, + /*{ AR5K_PHY(11), 0x00022ffe },*/ + /*{ AR5K_PHY(15), 0x00020100 },*/ + { AR5K_PHY(16), 0x206a017a }, + /*{ AR5K_PHY(19), 0x1284613c },*/ + { AR5K_PHY(21), 0x00000859 }, + { AR5K_PHY(64), 0x00000000 }, + { AR5K_PHY(65), 0x00000000 }, + { AR5K_PHY(66), 0x00000000 }, + { AR5K_PHY(67), 0x00800000 }, + { AR5K_PHY(68), 0x00000001 }, + /*{ AR5K_PHY(71), 0x0000092a },*/ /* Old value */ + { AR5K_PHY(71), 0x00000c80 }, + { AR5K_PHY_IQ, 0x05100000 }, + { AR5K_PHY(74), 0x00000001 }, + { AR5K_PHY(75), 0x00000004 }, + { AR5K_PHY_TXPOWER_RATE1, 0x1e1f2022 }, + { AR5K_PHY_TXPOWER_RATE2, 0x0a0b0c0d }, + { AR5K_PHY_TXPOWER_RATE_MAX, 0x0000003f }, + /*{ AR5K_PHY(80), 0x00000004 },*/ + { AR5K_PHY(82), 0x9280b212 }, + { AR5K_PHY_RADAR, 0x5d50e188 }, + /*{ AR5K_PHY(86), 0x000000ff },*/ + { AR5K_PHY(87), 0x004b6a8e }, + { AR5K_PHY(90), 0x000003ce }, + { AR5K_PHY(92), 0x192fb515 }, + /*{ AR5K_PHY(93), 0x00000000 },*/ + { AR5K_PHY(94), 0x00000001 }, + { AR5K_PHY(95), 0x00000000 }, + /*{ AR5K_PHY(644), 0x0080a333 },*/ /* Old value */ + /*{ AR5K_PHY(645), 0x00206c10 },*/ /* Old value */ + { AR5K_PHY(644), 0x00806333 }, + { AR5K_PHY(645), 0x00106c10 }, + { AR5K_PHY(646), 0x009c4060 }, + /*{ AR5K_PHY(647), 0x1483800a },*/ /* Old value */ + { AR5K_PHY(647), 0x1483800a }, + { AR5K_PHY(648), 0x01831061 }, + { AR5K_PHY(649), 0x00000400 }, + /*{ AR5K_PHY(650), 0x000001b5 },*/ + { AR5K_PHY(651), 0x00000000 }, + { AR5K_PHY_TXPOWER_RATE3, 0x20202020 }, + { AR5K_PHY_TXPOWER_RATE2, 0x20202020 }, + /*{ AR5K_PHY(655), 0x13c889af },*/ + { AR5K_PHY(656), 0x38490a20 }, + { AR5K_PHY(657), 0x00007bb6 }, + { AR5K_PHY(658), 0x0fff3ffc }, + /*{ AR5K_PHY_CCKTXCTL, 0x00000000 },*/ +}; + +/* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */ +static const struct ath5k_ini_mode ar5212_ini_mode_start[] = { + { AR5K_PHY(640), + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00000008, 0x00000008, 0x0000000b, 0x0000000e, 0x0000000e } }, + { AR5K_PHY(0), + { 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(0), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(1), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(2), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(3), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(4), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(5), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(6), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(7), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(8), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_QUEUE_DFS_LOCAL_IFS(9), + { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } }, + { AR5K_DCU_GBL_IFS_SIFS, + { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } }, + { AR5K_DCU_GBL_IFS_SLOT, + { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } }, + { AR5K_DCU_GBL_IFS_EIFS, + { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } }, + { AR5K_DCU_GBL_IFS_MISC, + { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } }, + { AR5K_TIME_OUT, + { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } }, + { AR5K_PHY_TURBO, + { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } }, + { AR5K_PHY(8), + { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } }, + { AR5K_PHY(9), + { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY(17), + { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } }, + { AR5K_PHY_AGCCTL, + { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d18 } }, + { AR5K_PHY_NF, + { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } }, + { AR5K_PHY(26), + { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } }, + { AR5K_PHY(70), + { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } }, + { AR5K_PHY(73), + { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } }, + { 0xa230, + { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } }, +}; + +/* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */ +/* New dump pending */ +static const struct ath5k_ini_mode ar5212_rf5111_ini_mode_end[] = { + { AR5K_PHY(640), /* This one differs from ar5212_ini_mode_start ! */ + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00000000, 0x00000000, 0x00000003, 0x00000006, 0x00000006 } }, + { AR5K_TXCFG, + { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, + { AR5K_USEC_5211, + { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } }, + { AR5K_PHY(10), + { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY(13), + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY(14), + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY(18), + { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } }, + { AR5K_PHY(20), + { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } }, + { AR5K_PHY(27), + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } }, + { AR5K_PHY_RX_DELAY, + { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } }, + { 0xa21c, + { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, + { AR5K_DCU_FP, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_AGC, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(11), + { 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } }, + { AR5K_PHY(15), + { 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } }, + { AR5K_PHY(19), + { 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } }, + { AR5K_PHY_PAPD_PROBE, + { 0x00004883, 0x00004883, 0x00004883, 0x00004883, 0x00004883 } }, + { AR5K_PHY(80), + { 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } }, + { AR5K_PHY(86), + { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } }, + { AR5K_PHY(93), + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_SPENDING, + { 0x00000018, 0x00000018, 0x00000018, 0x00000018, 0x00000018 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(642), + { 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { 0xa23c, + { 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } }, +}; + +/* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */ +/* XXX: No dumps for turbog yet, but i found settings from old values so it should be ok */ +static const struct ath5k_ini_mode ar5212_rf5112_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g (DYN) gTurbo */ + { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } }, + { AR5K_USEC_5211, + { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY(10), + { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY(13), + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY(14), + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY(18), + { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } }, + { AR5K_PHY(20), + { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } }, + { AR5K_PHY_SIG, + { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7ee80d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } }, + { AR5K_PHY(27), + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } }, + { AR5K_PHY(642), + { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } }, + { 0xa21c, + { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } }, + { AR5K_DCU_FP, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_AGC, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(11), + { 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe, 0x00022ffe } }, + { AR5K_PHY(15), + { 0x00020100, 0x00020100, 0x00020100, 0x00020100, 0x00020100 } }, + { AR5K_PHY(19), + { 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c, 0x1284613c } }, + { AR5K_PHY_PAPD_PROBE, + { 0x00004882, 0x00004882, 0x00004882, 0x00004882, 0x00004882 } }, + { AR5K_PHY(80), + { 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 } }, + { AR5K_PHY(86), + { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } }, + { AR5K_PHY(93), + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa228, + { 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5, 0x000001b5 } }, + { 0xa23c, + { 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af } }, +}; + +/* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */ +/* XXX: No dumps for turbog yet, so turbog is the same with g here with some + * minor tweaking based on dumps from other chips */ +static const struct ath5k_ini_mode rf5413_ini_mode_end[] = { + { AR5K_TXCFG, + /* a/XR aTurbo b g gTurbo */ + { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } }, + { AR5K_USEC_5211, + { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } }, + { AR5K_PHY(10), + { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } }, + { AR5K_PHY(13), + { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } }, + { AR5K_PHY(14), + { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } }, + { AR5K_PHY(18), + { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } }, + { AR5K_PHY(20), + { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } }, + { AR5K_PHY_SIG, + { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } }, + { AR5K_PHY_AGCCOARSE, + { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } }, + { AR5K_PHY(27), + { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } }, + { AR5K_PHY_RX_DELAY, + { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } }, + { AR5K_PHY_FRAME_CTL_5211, + { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } }, + { AR5K_PHY_CCKTXCTL, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(642), + { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } }, + { AR5K_PHY_GAIN_2GHZ, + { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } }, + { 0xa21c, + { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } }, + { 0xa300, + { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } }, + { 0xa304, + { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } }, + { 0xa308, + { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } }, + { 0xa30c, + { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } }, + { 0xa310, + { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } }, + { 0xa314, + { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } }, + { 0xa318, + { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } }, + { 0xa31c, + { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } }, + { 0xa320, + { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } }, + { 0xa324, + { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } }, + { 0xa328, + { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } }, + { 0xa32c, + { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } }, + { 0xa330, + { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } }, + { 0xa334, + { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } }, + { AR5K_DCU_FP, + { 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0, 0x000003e0 } }, + { 0x4068, + { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } }, + { 0x8060, + { 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f } }, + { 0x809c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x80a0, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8118, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x811c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8120, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8124, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8128, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x812c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8130, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8134, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8138, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x813c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0x8140, + { 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9, 0x800003f9 } }, + { 0x8144, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY_AGC, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(11), + { 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } }, + { AR5K_PHY(15), + { 0x00200400, 0x00200400, 0x00200400, 0x00200400, 0x00200400 } }, + { AR5K_PHY(19), + { 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c } }, + { AR5K_PHY_SCR, + { 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f } }, + { AR5K_PHY_SLMT, + { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, + { AR5K_PHY_SCAL, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, + { AR5K_PHY(86), + { 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff } }, + { AR5K_PHY(96), + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(97), + { 0x02800000, 0x02800000, 0x02800000, 0x02800000, 0x02800000 } }, + { AR5K_PHY(104), + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(120), + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { AR5K_PHY(121), + { 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa } }, + { AR5K_PHY(122), + { 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478, 0x3c466478 } }, + { AR5K_PHY(123), + { 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa } }, + { AR5K_PHY_SCLOCK, + { 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c } }, + { AR5K_PHY_SDELAY, + { 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff } }, + { AR5K_PHY_SPENDING, + { 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000014 } }, + { 0xa228, + { 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5 } }, + { 0xa23c, + { 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af, 0x93c889af } }, + { 0xa24c, + { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } }, + { 0xa250, + { 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000 } }, + { 0xa254, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa258, + { 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380 } }, + { 0xa25c, + { 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01 } }, + { 0xa260, + { 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01, 0x5f690f01 } }, + { 0xa264, + { 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11 } }, + { 0xa268, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa26c, + { 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a, 0x0c30c16a } }, + { 0xa270, + { 0x00820820, 0x00820820, 0x00820820, 0x00820820, 0x00820820 } }, + { 0xa274, + { 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa, 0x081b7caa } }, + { 0xa278, + { 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce } }, + { 0xa27c, + { 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce } }, + { 0xa338, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa33c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa340, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa344, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0xa348, + { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } }, + { 0xa34c, + { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } }, + { 0xa350, + { 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff } }, + { 0xa354, + { 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff } }, + { 0xa358, + { 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f } }, + { 0xa35c, + { 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f } }, + { 0xa360, + { 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207 } }, + { 0xa364, + { 0x17601685, 0x17601685, 0x17601685, 0x17601685, 0x17601685 } }, + { 0xa368, + { 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104 } }, + { 0xa36c, + { 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03 } }, + { 0xa370, + { 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883 } }, + { 0xa374, + { 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803 } }, + { 0xa378, + { 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682 } }, + { 0xa37c, + { 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482 } }, + { 0xa380, + { 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba } }, + { 0xa384, + { 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0 } }, +}; + +/* + * Initial BaseBand Gain settings for RF5111/5112 (AR5210 comes with + * RF5110 only so initial BB Gain settings are included in AR5K_AR5210_INI) + */ + +/* RF5111 Initial BaseBand Gain settings */ +static const struct ath5k_ini rf5111_ini_bbgain[] = { + { AR5K_BB_GAIN(0), 0x00000000 }, + { AR5K_BB_GAIN(1), 0x00000020 }, + { AR5K_BB_GAIN(2), 0x00000010 }, + { AR5K_BB_GAIN(3), 0x00000030 }, + { AR5K_BB_GAIN(4), 0x00000008 }, + { AR5K_BB_GAIN(5), 0x00000028 }, + { AR5K_BB_GAIN(6), 0x00000004 }, + { AR5K_BB_GAIN(7), 0x00000024 }, + { AR5K_BB_GAIN(8), 0x00000014 }, + { AR5K_BB_GAIN(9), 0x00000034 }, + { AR5K_BB_GAIN(10), 0x0000000c }, + { AR5K_BB_GAIN(11), 0x0000002c }, + { AR5K_BB_GAIN(12), 0x00000002 }, + { AR5K_BB_GAIN(13), 0x00000022 }, + { AR5K_BB_GAIN(14), 0x00000012 }, + { AR5K_BB_GAIN(15), 0x00000032 }, + { AR5K_BB_GAIN(16), 0x0000000a }, + { AR5K_BB_GAIN(17), 0x0000002a }, + { AR5K_BB_GAIN(18), 0x00000006 }, + { AR5K_BB_GAIN(19), 0x00000026 }, + { AR5K_BB_GAIN(20), 0x00000016 }, + { AR5K_BB_GAIN(21), 0x00000036 }, + { AR5K_BB_GAIN(22), 0x0000000e }, + { AR5K_BB_GAIN(23), 0x0000002e }, + { AR5K_BB_GAIN(24), 0x00000001 }, + { AR5K_BB_GAIN(25), 0x00000021 }, + { AR5K_BB_GAIN(26), 0x00000011 }, + { AR5K_BB_GAIN(27), 0x00000031 }, + { AR5K_BB_GAIN(28), 0x00000009 }, + { AR5K_BB_GAIN(29), 0x00000029 }, + { AR5K_BB_GAIN(30), 0x00000005 }, + { AR5K_BB_GAIN(31), 0x00000025 }, + { AR5K_BB_GAIN(32), 0x00000015 }, + { AR5K_BB_GAIN(33), 0x00000035 }, + { AR5K_BB_GAIN(34), 0x0000000d }, + { AR5K_BB_GAIN(35), 0x0000002d }, + { AR5K_BB_GAIN(36), 0x00000003 }, + { AR5K_BB_GAIN(37), 0x00000023 }, + { AR5K_BB_GAIN(38), 0x00000013 }, + { AR5K_BB_GAIN(39), 0x00000033 }, + { AR5K_BB_GAIN(40), 0x0000000b }, + { AR5K_BB_GAIN(41), 0x0000002b }, + { AR5K_BB_GAIN(42), 0x0000002b }, + { AR5K_BB_GAIN(43), 0x0000002b }, + { AR5K_BB_GAIN(44), 0x0000002b }, + { AR5K_BB_GAIN(45), 0x0000002b }, + { AR5K_BB_GAIN(46), 0x0000002b }, + { AR5K_BB_GAIN(47), 0x0000002b }, + { AR5K_BB_GAIN(48), 0x0000002b }, + { AR5K_BB_GAIN(49), 0x0000002b }, + { AR5K_BB_GAIN(50), 0x0000002b }, + { AR5K_BB_GAIN(51), 0x0000002b }, + { AR5K_BB_GAIN(52), 0x0000002b }, + { AR5K_BB_GAIN(53), 0x0000002b }, + { AR5K_BB_GAIN(54), 0x0000002b }, + { AR5K_BB_GAIN(55), 0x0000002b }, + { AR5K_BB_GAIN(56), 0x0000002b }, + { AR5K_BB_GAIN(57), 0x0000002b }, + { AR5K_BB_GAIN(58), 0x0000002b }, + { AR5K_BB_GAIN(59), 0x0000002b }, + { AR5K_BB_GAIN(60), 0x0000002b }, + { AR5K_BB_GAIN(61), 0x0000002b }, + { AR5K_BB_GAIN(62), 0x00000002 }, + { AR5K_BB_GAIN(63), 0x00000016 }, +}; + +/* RF5112 Initial BaseBand Gain settings (Same for RF5413/5414) */ +static const struct ath5k_ini rf5112_ini_bbgain[] = { + { AR5K_BB_GAIN(0), 0x00000000 }, + { AR5K_BB_GAIN(1), 0x00000001 }, + { AR5K_BB_GAIN(2), 0x00000002 }, + { AR5K_BB_GAIN(3), 0x00000003 }, + { AR5K_BB_GAIN(4), 0x00000004 }, + { AR5K_BB_GAIN(5), 0x00000005 }, + { AR5K_BB_GAIN(6), 0x00000008 }, + { AR5K_BB_GAIN(7), 0x00000009 }, + { AR5K_BB_GAIN(8), 0x0000000a }, + { AR5K_BB_GAIN(9), 0x0000000b }, + { AR5K_BB_GAIN(10), 0x0000000c }, + { AR5K_BB_GAIN(11), 0x0000000d }, + { AR5K_BB_GAIN(12), 0x00000010 }, + { AR5K_BB_GAIN(13), 0x00000011 }, + { AR5K_BB_GAIN(14), 0x00000012 }, + { AR5K_BB_GAIN(15), 0x00000013 }, + { AR5K_BB_GAIN(16), 0x00000014 }, + { AR5K_BB_GAIN(17), 0x00000015 }, + { AR5K_BB_GAIN(18), 0x00000018 }, + { AR5K_BB_GAIN(19), 0x00000019 }, + { AR5K_BB_GAIN(20), 0x0000001a }, + { AR5K_BB_GAIN(21), 0x0000001b }, + { AR5K_BB_GAIN(22), 0x0000001c }, + { AR5K_BB_GAIN(23), 0x0000001d }, + { AR5K_BB_GAIN(24), 0x00000020 }, + { AR5K_BB_GAIN(25), 0x00000021 }, + { AR5K_BB_GAIN(26), 0x00000022 }, + { AR5K_BB_GAIN(27), 0x00000023 }, + { AR5K_BB_GAIN(28), 0x00000024 }, + { AR5K_BB_GAIN(29), 0x00000025 }, + { AR5K_BB_GAIN(30), 0x00000028 }, + { AR5K_BB_GAIN(31), 0x00000029 }, + { AR5K_BB_GAIN(32), 0x0000002a }, + { AR5K_BB_GAIN(33), 0x0000002b }, + { AR5K_BB_GAIN(34), 0x0000002c }, + { AR5K_BB_GAIN(35), 0x0000002d }, + { AR5K_BB_GAIN(36), 0x00000030 }, + { AR5K_BB_GAIN(37), 0x00000031 }, + { AR5K_BB_GAIN(38), 0x00000032 }, + { AR5K_BB_GAIN(39), 0x00000033 }, + { AR5K_BB_GAIN(40), 0x00000034 }, + { AR5K_BB_GAIN(41), 0x00000035 }, + { AR5K_BB_GAIN(42), 0x00000035 }, + { AR5K_BB_GAIN(43), 0x00000035 }, + { AR5K_BB_GAIN(44), 0x00000035 }, + { AR5K_BB_GAIN(45), 0x00000035 }, + { AR5K_BB_GAIN(46), 0x00000035 }, + { AR5K_BB_GAIN(47), 0x00000035 }, + { AR5K_BB_GAIN(48), 0x00000035 }, + { AR5K_BB_GAIN(49), 0x00000035 }, + { AR5K_BB_GAIN(50), 0x00000035 }, + { AR5K_BB_GAIN(51), 0x00000035 }, + { AR5K_BB_GAIN(52), 0x00000035 }, + { AR5K_BB_GAIN(53), 0x00000035 }, + { AR5K_BB_GAIN(54), 0x00000035 }, + { AR5K_BB_GAIN(55), 0x00000035 }, + { AR5K_BB_GAIN(56), 0x00000035 }, + { AR5K_BB_GAIN(57), 0x00000035 }, + { AR5K_BB_GAIN(58), 0x00000035 }, + { AR5K_BB_GAIN(59), 0x00000035 }, + { AR5K_BB_GAIN(60), 0x00000035 }, + { AR5K_BB_GAIN(61), 0x00000035 }, + { AR5K_BB_GAIN(62), 0x00000010 }, + { AR5K_BB_GAIN(63), 0x0000001a }, +}; + + +/* + * Write initial register dump + */ +static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size, + const struct ath5k_ini *ini_regs, bool change_channel) +{ + unsigned int i; + + /* Write initial registers */ + for (i = 0; i < size; i++) { + /* On channel change there is + * no need to mess with PCU */ + if (change_channel && + ini_regs[i].ini_register >= AR5K_PCU_MIN && + ini_regs[i].ini_register <= AR5K_PCU_MAX) + continue; + + switch (ini_regs[i].ini_mode) { + case AR5K_INI_READ: + /* Cleared on read */ + ath5k_hw_reg_read(ah, ini_regs[i].ini_register); + break; + case AR5K_INI_WRITE: + default: + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, ini_regs[i].ini_value, + ini_regs[i].ini_register); + } + } +} + +static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah, + unsigned int size, const struct ath5k_ini_mode *ini_mode, + u8 mode) +{ + unsigned int i; + + for (i = 0; i < size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, ini_mode[i].mode_value[mode], + (u32)ini_mode[i].mode_register); + } + +} + +int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) +{ + /* + * Write initial register settings + */ + + /* For AR5212 and combatible */ + if (ah->ah_version == AR5K_AR5212){ + + /* First set of mode-specific settings */ + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(ar5212_ini_mode_start), + ar5212_ini_mode_start, mode); + + /* + * Write initial settings common for all modes + */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini), + ar5212_ini, change_channel); + + /* Second set of mode-specific settings */ + if (ah->ah_radio == AR5K_RF5111){ + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(ar5212_rf5111_ini_mode_end), + ar5212_rf5111_ini_mode_end, mode); + /* Baseband gain table */ + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5111_ini_bbgain), + rf5111_ini_bbgain, change_channel); + } else if (ah->ah_radio == AR5K_RF5112){ + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(ar5212_rf5112_ini_mode_end), + ar5212_rf5112_ini_mode_end, mode); + /* Baseband gain table */ + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + } else if (ah->ah_radio == AR5K_RF5413){ + ath5k_hw_ini_mode_registers(ah, + ARRAY_SIZE(rf5413_ini_mode_end), + rf5413_ini_mode_end, mode); + /* Baseband gain table */ + ath5k_hw_ini_registers(ah, + ARRAY_SIZE(rf5112_ini_bbgain), + rf5112_ini_bbgain, change_channel); + } + /* For AR5211 */ + } else if (ah->ah_version == AR5K_AR5211) { + + if(mode > 2){ /* AR5K_INI_VAL_11B */ + ATH5K_ERR(ah->ah_sc,"unsupported channel mode: %d\n", mode); + return -EINVAL; + } + + /* Mode-specific settings */ + ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode), + ar5211_ini_mode, mode); + + /* + * Write initial settings common for all modes + */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini), + ar5211_ini, change_channel); + + /* AR5211 only comes with 5111 */ + + /* Baseband gain table */ + ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), + rf5111_ini_bbgain, change_channel); + /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */ + } else if (ah->ah_version == AR5K_AR5210) { + ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini), + ar5210_ini, change_channel); + } + + return 0; +} diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c new file mode 100644 index 000000000000..b95941797141 --- /dev/null +++ b/drivers/net/wireless/ath5k/phy.c @@ -0,0 +1,2071 @@ +/* + * PHY functions + * + * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006, 2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include <linux/delay.h> + +#include "ath5k.h" +#include "reg.h" +#include "base.h" + +/* Struct to hold initial RF register values (RF Banks) */ +struct ath5k_ini_rf { + u8 rf_bank; /* check out ath5k_reg.h */ + u16 rf_register; /* register address */ + u32 rf_value[5]; /* register value for different modes (above) */ +}; + +/* + * Mode-specific RF Gain table (64bytes) for RF5111/5112 + * (RF5110 only comes with AR5210 and only supports a/turbo a mode so initial + * RF Gain values are included in AR5K_AR5210_INI) + */ +struct ath5k_ini_rfgain { + u16 rfg_register; /* RF Gain register address */ + u32 rfg_value[2]; /* [freq (see below)] */ +}; + +struct ath5k_gain_opt { + u32 go_default; + u32 go_steps_count; + const struct ath5k_gain_opt_step go_step[AR5K_GAIN_STEP_COUNT]; +}; + +/* RF5111 mode-specific init registers */ +static const struct ath5k_ini_rf rfregs_5111[] = { + { 0, 0x989c, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 0, 0x989c, + { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } }, + { 0, 0x989c, + { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } }, + { 0, 0x98d4, + { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } }, + { 1, 0x98d4, + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d4, + { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } }, + { 3, 0x98d8, + { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } }, + { 6, 0x989c, + { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } }, + { 6, 0x989c, + { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } }, + { 6, 0x989c, + { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } }, + { 6, 0x989c, + { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } }, + { 6, 0x989c, + { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } }, + { 6, 0x98d4, + { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } }, + { 7, 0x989c, + { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } }, + { 7, 0x989c, + { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } }, + { 7, 0x989c, + { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, + { 7, 0x989c, + { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } }, + { 7, 0x989c, + { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } }, + { 7, 0x989c, + { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } }, + { 7, 0x989c, + { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } }, +}; + +/* Initial RF Gain settings for RF5111 */ +static const struct ath5k_ini_rfgain rfgain_5111[] = { + /* 5Ghz 2Ghz */ + { AR5K_RF_GAIN(0), { 0x000001a9, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x000001e9, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000029, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x00000069, 0x00000150 } }, + { AR5K_RF_GAIN(4), { 0x00000199, 0x00000190 } }, + { AR5K_RF_GAIN(5), { 0x000001d9, 0x000001d0 } }, + { AR5K_RF_GAIN(6), { 0x00000019, 0x00000010 } }, + { AR5K_RF_GAIN(7), { 0x00000059, 0x00000044 } }, + { AR5K_RF_GAIN(8), { 0x00000099, 0x00000084 } }, + { AR5K_RF_GAIN(9), { 0x000001a5, 0x00000148 } }, + { AR5K_RF_GAIN(10), { 0x000001e5, 0x00000188 } }, + { AR5K_RF_GAIN(11), { 0x00000025, 0x000001c8 } }, + { AR5K_RF_GAIN(12), { 0x000001c8, 0x00000014 } }, + { AR5K_RF_GAIN(13), { 0x00000008, 0x00000042 } }, + { AR5K_RF_GAIN(14), { 0x00000048, 0x00000082 } }, + { AR5K_RF_GAIN(15), { 0x00000088, 0x00000178 } }, + { AR5K_RF_GAIN(16), { 0x00000198, 0x000001b8 } }, + { AR5K_RF_GAIN(17), { 0x000001d8, 0x000001f8 } }, + { AR5K_RF_GAIN(18), { 0x00000018, 0x00000012 } }, + { AR5K_RF_GAIN(19), { 0x00000058, 0x00000052 } }, + { AR5K_RF_GAIN(20), { 0x00000098, 0x00000092 } }, + { AR5K_RF_GAIN(21), { 0x000001a4, 0x0000017c } }, + { AR5K_RF_GAIN(22), { 0x000001e4, 0x000001bc } }, + { AR5K_RF_GAIN(23), { 0x00000024, 0x000001fc } }, + { AR5K_RF_GAIN(24), { 0x00000064, 0x0000000a } }, + { AR5K_RF_GAIN(25), { 0x000000a4, 0x0000004a } }, + { AR5K_RF_GAIN(26), { 0x000000e4, 0x0000008a } }, + { AR5K_RF_GAIN(27), { 0x0000010a, 0x0000015a } }, + { AR5K_RF_GAIN(28), { 0x0000014a, 0x0000019a } }, + { AR5K_RF_GAIN(29), { 0x0000018a, 0x000001da } }, + { AR5K_RF_GAIN(30), { 0x000001ca, 0x0000000e } }, + { AR5K_RF_GAIN(31), { 0x0000000a, 0x0000004e } }, + { AR5K_RF_GAIN(32), { 0x0000004a, 0x0000008e } }, + { AR5K_RF_GAIN(33), { 0x0000008a, 0x0000015e } }, + { AR5K_RF_GAIN(34), { 0x000001ba, 0x0000019e } }, + { AR5K_RF_GAIN(35), { 0x000001fa, 0x000001de } }, + { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000009 } }, + { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000049 } }, + { AR5K_RF_GAIN(38), { 0x00000186, 0x00000089 } }, + { AR5K_RF_GAIN(39), { 0x000001c6, 0x00000179 } }, + { AR5K_RF_GAIN(40), { 0x00000006, 0x000001b9 } }, + { AR5K_RF_GAIN(41), { 0x00000046, 0x000001f9 } }, + { AR5K_RF_GAIN(42), { 0x00000086, 0x00000039 } }, + { AR5K_RF_GAIN(43), { 0x000000c6, 0x00000079 } }, + { AR5K_RF_GAIN(44), { 0x000000c6, 0x000000b9 } }, + { AR5K_RF_GAIN(45), { 0x000000c6, 0x000001bd } }, + { AR5K_RF_GAIN(46), { 0x000000c6, 0x000001fd } }, + { AR5K_RF_GAIN(47), { 0x000000c6, 0x0000003d } }, + { AR5K_RF_GAIN(48), { 0x000000c6, 0x0000007d } }, + { AR5K_RF_GAIN(49), { 0x000000c6, 0x000000bd } }, + { AR5K_RF_GAIN(50), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(51), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(52), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(53), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(54), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(55), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(56), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(57), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(58), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(59), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(60), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(61), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(62), { 0x000000c6, 0x000000fd } }, + { AR5K_RF_GAIN(63), { 0x000000c6, 0x000000fd } }, +}; + +static const struct ath5k_gain_opt rfgain_opt_5111 = { + 4, + 9, + { + { { 4, 1, 1, 1 }, 6 }, + { { 4, 0, 1, 1 }, 4 }, + { { 3, 1, 1, 1 }, 3 }, + { { 4, 0, 0, 1 }, 1 }, + { { 4, 1, 1, 0 }, 0 }, + { { 4, 0, 1, 0 }, -2 }, + { { 3, 1, 1, 0 }, -3 }, + { { 4, 0, 0, 0 }, -4 }, + { { 2, 1, 1, 0 }, -6 } + } +}; + +/* RF5112 mode-specific init registers */ +static const struct ath5k_ini_rf rfregs_5112[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, + { 3, 0x98dc, + { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } }, + { 6, 0x989c, + { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } }, + { 6, 0x989c, + { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } }, + { 6, 0x989c, + { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } }, + { 6, 0x989c, + { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } }, + { 6, 0x989c, + { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, + { 6, 0x989c, + { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, + { 6, 0x989c, + { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } }, + { 6, 0x989c, + { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } }, + { 6, 0x989c, + { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, + { 6, 0x989c, + { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, + { 6, 0x989c, + { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } }, + { 6, 0x989c, + { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } }, + { 6, 0x989c, + { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, + { 6, 0x989c, + { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } }, + { 6, 0x989c, + { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, + { 6, 0x989c, + { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, + { 6, 0x989c, + { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } }, + { 6, 0x989c, + { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } }, + { 6, 0x989c, + { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } }, + { 6, 0x989c, + { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } }, + { 6, 0x989c, + { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } }, + { 6, 0x989c, + { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } }, + { 6, 0x989c, + { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } }, + { 6, 0x989c, + { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } }, + { 6, 0x989c, + { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } }, + { 6, 0x989c, + { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } }, + { 6, 0x989c, + { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } }, + { 6, 0x989c, + { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } }, + { 6, 0x989c, + { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } }, + { 6, 0x98d0, + { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } }, + { 7, 0x989c, + { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, + { 7, 0x989c, + { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, + { 7, 0x989c, + { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } }, + { 7, 0x989c, + { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, + { 7, 0x989c, + { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } }, + { 7, 0x989c, + { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, + { 7, 0x989c, + { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, + { 7, 0x989c, + { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } }, + { 7, 0x989c, + { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } }, + { 7, 0x989c, + { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, + { 7, 0x989c, + { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, + { 7, 0x989c, + { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, + { 7, 0x98c4, + { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, +}; + +/* RF5112A mode-specific init registers */ +static const struct ath5k_ini_rf rfregs_5112a[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } }, + { 3, 0x98dc, + { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } }, + { 6, 0x989c, + { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } }, + { 6, 0x989c, + { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } }, + { 6, 0x989c, + { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } }, + { 6, 0x989c, + { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } }, + { 6, 0x989c, + { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } }, + { 6, 0x989c, + { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } }, + { 6, 0x989c, + { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } }, + { 6, 0x989c, + { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } }, + { 6, 0x989c, + { 0x00190000, 0x00190000, 0x00190000, 0x00190000, 0x00190000 } }, + { 6, 0x989c, + { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } }, + { 6, 0x989c, + { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } }, + { 6, 0x989c, + { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } }, + { 6, 0x989c, + { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } }, + { 6, 0x989c, + { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, 0x989c, + { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } }, + { 6, 0x989c, + { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } }, + { 6, 0x989c, + { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } }, + { 6, 0x989c, + { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } }, + { 6, 0x989c, + { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } }, + { 6, 0x989c, + { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } }, + { 6, 0x989c, + { 0x00020080, 0x00020080, 0x00020080, 0x00020080, 0x00020080 } }, + { 6, 0x989c, + { 0x00080009, 0x00080009, 0x00080009, 0x00080009, 0x00080009 } }, + { 6, 0x989c, + { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } }, + { 6, 0x989c, + { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } }, + { 6, 0x989c, + { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } }, + { 6, 0x989c, + { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } }, + { 6, 0x989c, + { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } }, + { 6, 0x98d8, + { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } }, + { 7, 0x989c, + { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } }, + { 7, 0x989c, + { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } }, + { 7, 0x989c, + { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } }, + { 7, 0x989c, + { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } }, + { 7, 0x989c, + { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } }, + { 7, 0x989c, + { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } }, + { 7, 0x989c, + { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } }, + { 7, 0x989c, + { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } }, + { 7, 0x989c, + { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } }, + { 7, 0x989c, + { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } }, + { 7, 0x989c, + { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } }, + { 7, 0x989c, + { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } }, + { 7, 0x98c4, + { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } }, +}; + + +static const struct ath5k_ini_rf rfregs_2112a[] = { + { 1, AR5K_RF_BUFFER_CONTROL_4, + /* mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020 } }, + { 2, AR5K_RF_BUFFER_CONTROL_3, + { 0x03060408, 0x03060408, 0x03070408 } }, + { 3, AR5K_RF_BUFFER_CONTROL_6, + { 0x00e020c0, 0x00e020c0, 0x00e020c0 } }, + { 6, AR5K_RF_BUFFER, + { 0x0a000000, 0x0a000000, 0x0a000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00800000, 0x00800000, 0x00800000 } }, + { 6, AR5K_RF_BUFFER, + { 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00010000, 0x00010000, 0x00010000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00180000, 0x00180000, 0x00180000 } }, + { 6, AR5K_RF_BUFFER, + { 0x006e0000, 0x006e0000, 0x006e0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00c70000, 0x00c70000, 0x00c70000 } }, + { 6, AR5K_RF_BUFFER, + { 0x004b0000, 0x004b0000, 0x004b0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x04480000, 0x04480000, 0x04480000 } }, + { 6, AR5K_RF_BUFFER, + { 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00e40000, 0x00e40000, 0x00e40000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00fc0000, 0x00fc0000, 0x00fc0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x043f0000, 0x043f0000, 0x043f0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x0c0c0000, 0x0c0c0000, 0x0c0c0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x02190000, 0x02190000, 0x02190000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00240000, 0x00240000, 0x00240000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00b40000, 0x00b40000, 0x00b40000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00990000, 0x00990000, 0x00990000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00500000, 0x00500000, 0x00500000 } }, + { 6, AR5K_RF_BUFFER, + { 0x002a0000, 0x002a0000, 0x002a0000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00120000, 0x00120000, 0x00120000 } }, + { 6, AR5K_RF_BUFFER, + { 0xc0320000, 0xc0320000, 0xc0320000 } }, + { 6, AR5K_RF_BUFFER, + { 0x01740000, 0x01740000, 0x01740000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00110000, 0x00110000, 0x00110000 } }, + { 6, AR5K_RF_BUFFER, + { 0x86280000, 0x86280000, 0x86280000 } }, + { 6, AR5K_RF_BUFFER, + { 0x31840000, 0x31840000, 0x31840000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00f20080, 0x00f20080, 0x00f20080 } }, + { 6, AR5K_RF_BUFFER, + { 0x00070019, 0x00070019, 0x00070019 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x00000000, 0x00000000, 0x00000000 } }, + { 6, AR5K_RF_BUFFER, + { 0x000000b2, 0x000000b2, 0x000000b2 } }, + { 6, AR5K_RF_BUFFER, + { 0x00b02184, 0x00b02184, 0x00b02184 } }, + { 6, AR5K_RF_BUFFER, + { 0x004125a4, 0x004125a4, 0x004125a4 } }, + { 6, AR5K_RF_BUFFER, + { 0x00119220, 0x00119220, 0x00119220 } }, + { 6, AR5K_RF_BUFFER, + { 0x001a4800, 0x001a4800, 0x001a4800 } }, + { 6, AR5K_RF_BUFFER_CONTROL_5, + { 0x000b0230, 0x000b0230, 0x000b0230 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000094, 0x00000094, 0x00000094 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000091, 0x00000091, 0x00000091 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000012, 0x00000012, 0x00000012 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000080, 0x00000080, 0x00000080 } }, + { 7, AR5K_RF_BUFFER, + { 0x000000d9, 0x000000d9, 0x000000d9 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000060, 0x00000060, 0x00000060 } }, + { 7, AR5K_RF_BUFFER, + { 0x000000f0, 0x000000f0, 0x000000f0 } }, + { 7, AR5K_RF_BUFFER, + { 0x000000a2, 0x000000a2, 0x000000a2 } }, + { 7, AR5K_RF_BUFFER, + { 0x00000052, 0x00000052, 0x00000052 } }, + { 7, AR5K_RF_BUFFER, + { 0x000000d4, 0x000000d4, 0x000000d4 } }, + { 7, AR5K_RF_BUFFER, + { 0x000014cc, 0x000014cc, 0x000014cc } }, + { 7, AR5K_RF_BUFFER, + { 0x0000048c, 0x0000048c, 0x0000048c } }, + { 7, AR5K_RF_BUFFER_CONTROL_1, + { 0x00000003, 0x00000003, 0x00000003 } }, +}; + +/* RF5413/5414 mode-specific init registers */ +static const struct ath5k_ini_rf rfregs_5413[] = { + { 1, 0x98d4, + /* mode a/XR mode aTurbo mode b mode g mode gTurbo */ + { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } }, + { 2, 0x98d0, + { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } }, + { 3, 0x98dc, + { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } }, + { 6, 0x989c, + { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } }, + { 6, 0x989c, + { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } }, + { 6, 0x989c, + { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } }, + { 6, 0x989c, + { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } }, + { 6, 0x989c, + { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, + { 6, 0x989c, + { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } }, + { 6, 0x989c, + { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } }, + { 6, 0x989c, + { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } }, + { 6, 0x989c, + { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } }, + { 6, 0x989c, + { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } }, + { 6, 0x989c, + { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } }, + { 6, 0x989c, + { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } }, + { 6, 0x989c, + { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } }, + { 6, 0x989c, + { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } }, + { 6, 0x989c, + { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } }, + { 6, 0x989c, + { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } }, + { 6, 0x989c, + { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } }, + { 6, 0x989c, + { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } }, + { 6, 0x989c, + { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } }, + { 6, 0x989c, + { 0x00510040, 0x00510040, 0x005100a0, 0x005100a0, 0x005100a0 } }, + { 6, 0x989c, + { 0x0050006a, 0x0050006a, 0x005000dd, 0x005000dd, 0x005000dd } }, + { 6, 0x989c, + { 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } }, + { 6, 0x989c, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { 6, 0x989c, + { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } }, + { 6, 0x989c, + { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00003600 } }, + { 6, 0x98c8, + { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } }, + { 7, 0x989c, + { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } }, + { 7, 0x989c, + { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } }, + { 7, 0x98cc, + { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } }, +}; + + +/* Initial RF Gain settings for RF5112 */ +static const struct ath5k_ini_rfgain rfgain_5112[] = { + /* 5Ghz 2Ghz */ + { AR5K_RF_GAIN(0), { 0x00000007, 0x00000007 } }, + { AR5K_RF_GAIN(1), { 0x00000047, 0x00000047 } }, + { AR5K_RF_GAIN(2), { 0x00000087, 0x00000087 } }, + { AR5K_RF_GAIN(3), { 0x000001a0, 0x000001a0 } }, + { AR5K_RF_GAIN(4), { 0x000001e0, 0x000001e0 } }, + { AR5K_RF_GAIN(5), { 0x00000020, 0x00000020 } }, + { AR5K_RF_GAIN(6), { 0x00000060, 0x00000060 } }, + { AR5K_RF_GAIN(7), { 0x000001a1, 0x000001a1 } }, + { AR5K_RF_GAIN(8), { 0x000001e1, 0x000001e1 } }, + { AR5K_RF_GAIN(9), { 0x00000021, 0x00000021 } }, + { AR5K_RF_GAIN(10), { 0x00000061, 0x00000061 } }, + { AR5K_RF_GAIN(11), { 0x00000162, 0x00000162 } }, + { AR5K_RF_GAIN(12), { 0x000001a2, 0x000001a2 } }, + { AR5K_RF_GAIN(13), { 0x000001e2, 0x000001e2 } }, + { AR5K_RF_GAIN(14), { 0x00000022, 0x00000022 } }, + { AR5K_RF_GAIN(15), { 0x00000062, 0x00000062 } }, + { AR5K_RF_GAIN(16), { 0x00000163, 0x00000163 } }, + { AR5K_RF_GAIN(17), { 0x000001a3, 0x000001a3 } }, + { AR5K_RF_GAIN(18), { 0x000001e3, 0x000001e3 } }, + { AR5K_RF_GAIN(19), { 0x00000023, 0x00000023 } }, + { AR5K_RF_GAIN(20), { 0x00000063, 0x00000063 } }, + { AR5K_RF_GAIN(21), { 0x00000184, 0x00000184 } }, + { AR5K_RF_GAIN(22), { 0x000001c4, 0x000001c4 } }, + { AR5K_RF_GAIN(23), { 0x00000004, 0x00000004 } }, + { AR5K_RF_GAIN(24), { 0x000001ea, 0x0000000b } }, + { AR5K_RF_GAIN(25), { 0x0000002a, 0x0000004b } }, + { AR5K_RF_GAIN(26), { 0x0000006a, 0x0000008b } }, + { AR5K_RF_GAIN(27), { 0x000000aa, 0x000001ac } }, + { AR5K_RF_GAIN(28), { 0x000001ab, 0x000001ec } }, + { AR5K_RF_GAIN(29), { 0x000001eb, 0x0000002c } }, + { AR5K_RF_GAIN(30), { 0x0000002b, 0x00000012 } }, + { AR5K_RF_GAIN(31), { 0x0000006b, 0x00000052 } }, + { AR5K_RF_GAIN(32), { 0x000000ab, 0x00000092 } }, + { AR5K_RF_GAIN(33), { 0x000001ac, 0x00000193 } }, + { AR5K_RF_GAIN(34), { 0x000001ec, 0x000001d3 } }, + { AR5K_RF_GAIN(35), { 0x0000002c, 0x00000013 } }, + { AR5K_RF_GAIN(36), { 0x0000003a, 0x00000053 } }, + { AR5K_RF_GAIN(37), { 0x0000007a, 0x00000093 } }, + { AR5K_RF_GAIN(38), { 0x000000ba, 0x00000194 } }, + { AR5K_RF_GAIN(39), { 0x000001bb, 0x000001d4 } }, + { AR5K_RF_GAIN(40), { 0x000001fb, 0x00000014 } }, + { AR5K_RF_GAIN(41), { 0x0000003b, 0x0000003a } }, + { AR5K_RF_GAIN(42), { 0x0000007b, 0x0000007a } }, + { AR5K_RF_GAIN(43), { 0x000000bb, 0x000000ba } }, + { AR5K_RF_GAIN(44), { 0x000001bc, 0x000001bb } }, + { AR5K_RF_GAIN(45), { 0x000001fc, 0x000001fb } }, + { AR5K_RF_GAIN(46), { 0x0000003c, 0x0000003b } }, + { AR5K_RF_GAIN(47), { 0x0000007c, 0x0000007b } }, + { AR5K_RF_GAIN(48), { 0x000000bc, 0x000000bb } }, + { AR5K_RF_GAIN(49), { 0x000000fc, 0x000001bc } }, + { AR5K_RF_GAIN(50), { 0x000000fc, 0x000001fc } }, + { AR5K_RF_GAIN(51), { 0x000000fc, 0x0000003c } }, + { AR5K_RF_GAIN(52), { 0x000000fc, 0x0000007c } }, + { AR5K_RF_GAIN(53), { 0x000000fc, 0x000000bc } }, + { AR5K_RF_GAIN(54), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(55), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(56), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(57), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(58), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(59), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(60), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(61), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(62), { 0x000000fc, 0x000000fc } }, + { AR5K_RF_GAIN(63), { 0x000000fc, 0x000000fc } }, +}; + +/* Initial RF Gain settings for RF5413 */ +static const struct ath5k_ini_rfgain rfgain_5413[] = { + /* 5Ghz 2Ghz */ + { AR5K_RF_GAIN(0), { 0x00000000, 0x00000000 } }, + { AR5K_RF_GAIN(1), { 0x00000040, 0x00000040 } }, + { AR5K_RF_GAIN(2), { 0x00000080, 0x00000080 } }, + { AR5K_RF_GAIN(3), { 0x000001a1, 0x00000161 } }, + { AR5K_RF_GAIN(4), { 0x000001e1, 0x000001a1 } }, + { AR5K_RF_GAIN(5), { 0x00000021, 0x000001e1 } }, + { AR5K_RF_GAIN(6), { 0x00000061, 0x00000021 } }, + { AR5K_RF_GAIN(7), { 0x00000188, 0x00000061 } }, + { AR5K_RF_GAIN(8), { 0x000001c8, 0x00000188 } }, + { AR5K_RF_GAIN(9), { 0x00000008, 0x000001c8 } }, + { AR5K_RF_GAIN(10), { 0x00000048, 0x00000008 } }, + { AR5K_RF_GAIN(11), { 0x00000088, 0x00000048 } }, + { AR5K_RF_GAIN(12), { 0x000001a9, 0x00000088 } }, + { AR5K_RF_GAIN(13), { 0x000001e9, 0x00000169 } }, + { AR5K_RF_GAIN(14), { 0x00000029, 0x000001a9 } }, + { AR5K_RF_GAIN(15), { 0x00000069, 0x000001e9 } }, + { AR5K_RF_GAIN(16), { 0x000001d0, 0x00000029 } }, + { AR5K_RF_GAIN(17), { 0x00000010, 0x00000069 } }, + { AR5K_RF_GAIN(18), { 0x00000050, 0x00000190 } }, + { AR5K_RF_GAIN(19), { 0x00000090, 0x000001d0 } }, + { AR5K_RF_GAIN(20), { 0x000001b1, 0x00000010 } }, + { AR5K_RF_GAIN(21), { 0x000001f1, 0x00000050 } }, + { AR5K_RF_GAIN(22), { 0x00000031, 0x00000090 } }, + { AR5K_RF_GAIN(23), { 0x00000071, 0x00000171 } }, + { AR5K_RF_GAIN(24), { 0x000001b8, 0x000001b1 } }, + { AR5K_RF_GAIN(25), { 0x000001f8, 0x000001f1 } }, + { AR5K_RF_GAIN(26), { 0x00000038, 0x00000031 } }, + { AR5K_RF_GAIN(27), { 0x00000078, 0x00000071 } }, + { AR5K_RF_GAIN(28), { 0x00000199, 0x00000198 } }, + { AR5K_RF_GAIN(29), { 0x000001d9, 0x000001d8 } }, + { AR5K_RF_GAIN(30), { 0x00000019, 0x00000018 } }, + { AR5K_RF_GAIN(31), { 0x00000059, 0x00000058 } }, + { AR5K_RF_GAIN(32), { 0x00000099, 0x00000098 } }, + { AR5K_RF_GAIN(33), { 0x000000d9, 0x00000179 } }, + { AR5K_RF_GAIN(34), { 0x000000f9, 0x000001b9 } }, + { AR5K_RF_GAIN(35), { 0x000000f9, 0x000001f9 } }, + { AR5K_RF_GAIN(36), { 0x000000f9, 0x00000039 } }, + { AR5K_RF_GAIN(37), { 0x000000f9, 0x00000079 } }, + { AR5K_RF_GAIN(38), { 0x000000f9, 0x000000b9 } }, + { AR5K_RF_GAIN(39), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(40), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(41), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(42), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(43), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(44), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(45), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(46), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(47), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(48), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(49), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(50), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(51), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(52), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(53), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(54), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(55), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(56), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(57), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(58), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(59), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(60), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(61), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(62), { 0x000000f9, 0x000000f9 } }, + { AR5K_RF_GAIN(63), { 0x000000f9, 0x000000f9 } }, +}; + +static const struct ath5k_gain_opt rfgain_opt_5112 = { + 1, + 8, + { + { { 3, 0, 0, 0, 0, 0, 0 }, 6 }, + { { 2, 0, 0, 0, 0, 0, 0 }, 0 }, + { { 1, 0, 0, 0, 0, 0, 0 }, -3 }, + { { 0, 0, 0, 0, 0, 0, 0 }, -6 }, + { { 0, 1, 1, 0, 0, 0, 0 }, -8 }, + { { 0, 1, 1, 0, 1, 1, 0 }, -10 }, + { { 0, 1, 0, 1, 1, 1, 0 }, -13 }, + { { 0, 1, 0, 1, 1, 0, 1 }, -16 }, + } +}; + +/* + * Used to modify RF Banks before writing them to AR5K_RF_BUFFER + */ +static unsigned int ath5k_hw_rfregs_op(u32 *rf, u32 offset, u32 reg, u32 bits, + u32 first, u32 col, bool set) +{ + u32 mask, entry, last, data, shift, position; + s32 left; + int i; + + data = 0; + + if (rf == NULL) + /* should not happen */ + return 0; + + if (!(col <= 3 && bits <= 32 && first + bits <= 319)) { + ATH5K_PRINTF("invalid values at offset %u\n", offset); + return 0; + } + + entry = ((first - 1) / 8) + offset; + position = (first - 1) % 8; + + if (set == true) + data = ath5k_hw_bitswap(reg, bits); + + for (i = shift = 0, left = bits; left > 0; position = 0, entry++, i++) { + last = (position + left > 8) ? 8 : position + left; + mask = (((1 << last) - 1) ^ ((1 << position) - 1)) << (col * 8); + + if (set == true) { + rf[entry] &= ~mask; + rf[entry] |= ((data << position) << (col * 8)) & mask; + data >>= (8 - position); + } else { + data = (((rf[entry] & mask) >> (col * 8)) >> position) + << shift; + shift += last - position; + } + + left -= 8 - position; + } + + data = set == true ? 1 : ath5k_hw_bitswap(data, bits); + + return data; +} + +static u32 ath5k_hw_rfregs_gainf_corr(struct ath5k_hw *ah) +{ + u32 mix, step; + u32 *rf; + + if (ah->ah_rf_banks == NULL) + return 0; + + rf = ah->ah_rf_banks; + ah->ah_gain.g_f_corr = 0; + + if (ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, false) != 1) + return 0; + + step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 4, 32, 0, false); + mix = ah->ah_gain.g_step->gos_param[0]; + + switch (mix) { + case 3: + ah->ah_gain.g_f_corr = step * 2; + break; + case 2: + ah->ah_gain.g_f_corr = (step - 5) * 2; + break; + case 1: + ah->ah_gain.g_f_corr = step; + break; + default: + ah->ah_gain.g_f_corr = 0; + break; + } + + return ah->ah_gain.g_f_corr; +} + +static bool ath5k_hw_rfregs_gain_readback(struct ath5k_hw *ah) +{ + u32 step, mix, level[4]; + u32 *rf; + + if (ah->ah_rf_banks == NULL) + return false; + + rf = ah->ah_rf_banks; + + if (ah->ah_radio == AR5K_RF5111) { + step = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 6, 37, 0, + false); + level[0] = 0; + level[1] = (step == 0x3f) ? 0x32 : step + 4; + level[2] = (step != 0x3f) ? 0x40 : level[0]; + level[3] = level[2] + 0x32; + + ah->ah_gain.g_high = level[3] - + (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_HI_MARGIN : -5); + ah->ah_gain.g_low = level[0] + + (step == 0x3f ? AR5K_GAIN_DYN_ADJUST_LO_MARGIN : 0); + } else { + mix = ath5k_hw_rfregs_op(rf, ah->ah_offset[7], 0, 1, 36, 0, + false); + level[0] = level[2] = 0; + + if (mix == 1) { + level[1] = level[3] = 83; + } else { + level[1] = level[3] = 107; + ah->ah_gain.g_high = 55; + } + } + + return (ah->ah_gain.g_current >= level[0] && + ah->ah_gain.g_current <= level[1]) || + (ah->ah_gain.g_current >= level[2] && + ah->ah_gain.g_current <= level[3]); +} + +static s32 ath5k_hw_rfregs_gain_adjust(struct ath5k_hw *ah) +{ + const struct ath5k_gain_opt *go; + int ret = 0; + + switch (ah->ah_radio) { + case AR5K_RF5111: + go = &rfgain_opt_5111; + break; + case AR5K_RF5112: + case AR5K_RF5413: /* ??? */ + go = &rfgain_opt_5112; + break; + default: + return 0; + } + + ah->ah_gain.g_step = &go->go_step[ah->ah_gain.g_step_idx]; + + if (ah->ah_gain.g_current >= ah->ah_gain.g_high) { + if (ah->ah_gain.g_step_idx == 0) + return -1; + for (ah->ah_gain.g_target = ah->ah_gain.g_current; + ah->ah_gain.g_target >= ah->ah_gain.g_high && + ah->ah_gain.g_step_idx > 0; + ah->ah_gain.g_step = + &go->go_step[ah->ah_gain.g_step_idx]) + ah->ah_gain.g_target -= 2 * + (go->go_step[--(ah->ah_gain.g_step_idx)].gos_gain - + ah->ah_gain.g_step->gos_gain); + + ret = 1; + goto done; + } + + if (ah->ah_gain.g_current <= ah->ah_gain.g_low) { + if (ah->ah_gain.g_step_idx == (go->go_steps_count - 1)) + return -2; + for (ah->ah_gain.g_target = ah->ah_gain.g_current; + ah->ah_gain.g_target <= ah->ah_gain.g_low && + ah->ah_gain.g_step_idx < go->go_steps_count-1; + ah->ah_gain.g_step = + &go->go_step[ah->ah_gain.g_step_idx]) + ah->ah_gain.g_target -= 2 * + (go->go_step[++ah->ah_gain.g_step_idx].gos_gain - + ah->ah_gain.g_step->gos_gain); + + ret = 2; + goto done; + } + +done: + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "ret %d, gain step %u, current gain %u, target gain %u\n", + ret, ah->ah_gain.g_step_idx, ah->ah_gain.g_current, + ah->ah_gain.g_target); + + return ret; +} + +/* + * Read EEPROM Calibration data, modify RF Banks and Initialize RF5111 + */ +static int ath5k_hw_rf5111_rfregs(struct ath5k_hw *ah, + struct ieee80211_channel *channel, unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 *rf; + const unsigned int rf_size = ARRAY_SIZE(rfregs_5111); + unsigned int i; + int obdb = -1, bank = -1; + u32 ee_mode; + + AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); + + rf = ah->ah_rf_banks; + + /* Copy values to modify them */ + for (i = 0; i < rf_size; i++) { + if (rfregs_5111[i].rf_bank >= AR5K_RF5111_INI_RF_MAX_BANKS) { + ATH5K_ERR(ah->ah_sc, "invalid bank\n"); + return -EINVAL; + } + + if (bank != rfregs_5111[i].rf_bank) { + bank = rfregs_5111[i].rf_bank; + ah->ah_offset[bank] = i; + } + + rf[i] = rfregs_5111[i].rf_value[mode]; + } + + /* Modify bank 0 */ + if (channel->val & CHANNEL_2GHZ) { + if (channel->val & CHANNEL_CCK) + ee_mode = AR5K_EEPROM_MODE_11B; + else + ee_mode = AR5K_EEPROM_MODE_11G; + obdb = 0; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0], + ee->ee_ob[ee_mode][obdb], 3, 119, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[0], + ee->ee_ob[ee_mode][obdb], 3, 122, 0, true)) + return -EINVAL; + + obdb = 1; + /* Modify bank 6 */ + } else { + /* For 11a, Turbo and XR */ + ee_mode = AR5K_EEPROM_MODE_11A; + obdb = channel->freq >= 5725 ? 3 : + (channel->freq >= 5500 ? 2 : + (channel->freq >= 5260 ? 1 : + (channel->freq > 4000 ? 0 : -1))); + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_pwd_84, 1, 51, 3, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_pwd_90, 1, 45, 3, true)) + return -EINVAL; + } + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + !ee->ee_xpd[ee_mode], 1, 95, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_x_gain[ee_mode], 4, 96, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ? + ee->ee_ob[ee_mode][obdb] : 0, 3, 104, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], obdb >= 0 ? + ee->ee_db[ee_mode][obdb] : 0, 3, 107, 0, true)) + return -EINVAL; + + /* Modify bank 7 */ + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], + ee->ee_i_gain[ee_mode], 6, 29, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], + ee->ee_xpd[ee_mode], 1, 4, 0, true)) + return -EINVAL; + + /* Write RF values */ + for (i = 0; i < rf_size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, rf[i], rfregs_5111[i].rf_register); + } + + return 0; +} + +/* + * Read EEPROM Calibration data, modify RF Banks and Initialize RF5112 + */ +static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, + struct ieee80211_channel *channel, unsigned int mode) +{ + const struct ath5k_ini_rf *rf_ini; + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 *rf; + unsigned int rf_size, i; + int obdb = -1, bank = -1; + u32 ee_mode; + + AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); + + rf = ah->ah_rf_banks; + + if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_2112A + && !test_bit(MODE_IEEE80211A, ah->ah_capabilities.cap_mode)){ + rf_ini = rfregs_2112a; + rf_size = ARRAY_SIZE(rfregs_5112a); + if (mode < 2) { + ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode); + return -EINVAL; + } + mode = mode - 2; /*no a/turboa modes for 2112*/ + } else if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) { + rf_ini = rfregs_5112a; + rf_size = ARRAY_SIZE(rfregs_5112a); + } else { + rf_ini = rfregs_5112; + rf_size = ARRAY_SIZE(rfregs_5112); + } + + /* Copy values to modify them */ + for (i = 0; i < rf_size; i++) { + if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) { + ATH5K_ERR(ah->ah_sc, "invalid bank\n"); + return -EINVAL; + } + + if (bank != rf_ini[i].rf_bank) { + bank = rf_ini[i].rf_bank; + ah->ah_offset[bank] = i; + } + + rf[i] = rf_ini[i].rf_value[mode]; + } + + /* Modify bank 6 */ + if (channel->val & CHANNEL_2GHZ) { + if (channel->val & CHANNEL_OFDM) + ee_mode = AR5K_EEPROM_MODE_11G; + else + ee_mode = AR5K_EEPROM_MODE_11B; + obdb = 0; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_ob[ee_mode][obdb], 3, 287, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_ob[ee_mode][obdb], 3, 290, 0, true)) + return -EINVAL; + } else { + /* For 11a, Turbo and XR */ + ee_mode = AR5K_EEPROM_MODE_11A; + obdb = channel->freq >= 5725 ? 3 : + (channel->freq >= 5500 ? 2 : + (channel->freq >= 5260 ? 1 : + (channel->freq > 4000 ? 0 : -1))); + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_ob[ee_mode][obdb], 3, 279, 0, true)) + return -EINVAL; + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_ob[ee_mode][obdb], 3, 282, 0, true)) + return -EINVAL; + } + + ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_x_gain[ee_mode], 2, 270, 0, true); + ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_x_gain[ee_mode], 2, 257, 0, true); + + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[6], + ee->ee_xpd[ee_mode], 1, 302, 0, true)) + return -EINVAL; + + /* Modify bank 7 */ + if (!ath5k_hw_rfregs_op(rf, ah->ah_offset[7], + ee->ee_i_gain[ee_mode], 6, 14, 0, true)) + return -EINVAL; + + /* Write RF values */ + for (i = 0; i < rf_size; i++) + ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register); + + return 0; +} + +/* + * Initialize RF5413/5414 + */ +static int ath5k_hw_rf5413_rfregs(struct ath5k_hw *ah, + struct ieee80211_channel *channel, unsigned int mode) +{ + const struct ath5k_ini_rf *rf_ini; + u32 *rf; + unsigned int rf_size, i; + int bank = -1; + + AR5K_ASSERT_ENTRY(mode, AR5K_INI_VAL_MAX); + + rf = ah->ah_rf_banks; + + rf_ini = rfregs_5413; + rf_size = ARRAY_SIZE(rfregs_5413); + + /* Copy values to modify them */ + for (i = 0; i < rf_size; i++) { + if (rf_ini[i].rf_bank >= AR5K_RF5112_INI_RF_MAX_BANKS) { + ATH5K_ERR(ah->ah_sc, "invalid bank\n"); + return -EINVAL; + } + + if (bank != rf_ini[i].rf_bank) { + bank = rf_ini[i].rf_bank; + ah->ah_offset[bank] = i; + } + + rf[i] = rf_ini[i].rf_value[mode]; + } + + /* + * After compairing dumps from different cards + * we get the same RF_BUFFER settings (diff returns + * 0 lines). It seems that RF_BUFFER settings are static + * and are written unmodified (no EEPROM stuff + * is used because calibration data would be + * different between different cards and would result + * different RF_BUFFER settings) + */ + + /* Write RF values */ + for (i = 0; i < rf_size; i++) + ath5k_hw_reg_write(ah, rf[i], rf_ini[i].rf_register); + + return 0; +} + +/* + * Initialize RF + */ +int ath5k_hw_rfregs(struct ath5k_hw *ah, struct ieee80211_channel *channel, + unsigned int mode) +{ + int (*func)(struct ath5k_hw *, struct ieee80211_channel *, unsigned int); + int ret; + + switch (ah->ah_radio) { + case AR5K_RF5111: + ah->ah_rf_banks_size = sizeof(rfregs_5111); + func = ath5k_hw_rf5111_rfregs; + break; + case AR5K_RF5112: + if (ah->ah_radio_5ghz_revision >= AR5K_SREV_RAD_5112A) + ah->ah_rf_banks_size = sizeof(rfregs_5112a); + else + ah->ah_rf_banks_size = sizeof(rfregs_5112); + func = ath5k_hw_rf5112_rfregs; + break; + case AR5K_RF5413: + ah->ah_rf_banks_size = sizeof(rfregs_5413); + func = ath5k_hw_rf5413_rfregs; + break; + default: + return -EINVAL; + } + + if (ah->ah_rf_banks == NULL) { + /* XXX do extra checks? */ + ah->ah_rf_banks = kmalloc(ah->ah_rf_banks_size, GFP_KERNEL); + if (ah->ah_rf_banks == NULL) { + ATH5K_ERR(ah->ah_sc, "out of memory\n"); + return -ENOMEM; + } + } + + ret = func(ah, channel, mode); + if (!ret) + ah->ah_rf_gain = AR5K_RFGAIN_INACTIVE; + + return ret; +} + +int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq) +{ + const struct ath5k_ini_rfgain *ath5k_rfg; + unsigned int i, size; + + switch (ah->ah_radio) { + case AR5K_RF5111: + ath5k_rfg = rfgain_5111; + size = ARRAY_SIZE(rfgain_5111); + break; + case AR5K_RF5112: + ath5k_rfg = rfgain_5112; + size = ARRAY_SIZE(rfgain_5112); + break; + case AR5K_RF5413: + ath5k_rfg = rfgain_5413; + size = ARRAY_SIZE(rfgain_5413); + break; + default: + return -EINVAL; + } + + switch (freq) { + case AR5K_INI_RFGAIN_2GHZ: + case AR5K_INI_RFGAIN_5GHZ: + break; + default: + return -EINVAL; + } + + for (i = 0; i < size; i++) { + AR5K_REG_WAIT(i); + ath5k_hw_reg_write(ah, ath5k_rfg[i].rfg_value[freq], + (u32)ath5k_rfg[i].rfg_register); + } + + return 0; +} + +enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah) +{ + u32 data, type; + + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_rf_banks == NULL || !ah->ah_gain.g_active || + ah->ah_version <= AR5K_AR5211) + return AR5K_RFGAIN_INACTIVE; + + if (ah->ah_rf_gain != AR5K_RFGAIN_READ_REQUESTED) + goto done; + + data = ath5k_hw_reg_read(ah, AR5K_PHY_PAPD_PROBE); + + if (!(data & AR5K_PHY_PAPD_PROBE_TX_NEXT)) { + ah->ah_gain.g_current = data >> AR5K_PHY_PAPD_PROBE_GAINF_S; + type = AR5K_REG_MS(data, AR5K_PHY_PAPD_PROBE_TYPE); + + if (type == AR5K_PHY_PAPD_PROBE_TYPE_CCK) + ah->ah_gain.g_current += AR5K_GAIN_CCK_PROBE_CORR; + + if (ah->ah_radio >= AR5K_RF5112) { + ath5k_hw_rfregs_gainf_corr(ah); + ah->ah_gain.g_current = + ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ? + (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : + 0; + } + + if (ath5k_hw_rfregs_gain_readback(ah) && + AR5K_GAIN_CHECK_ADJUST(&ah->ah_gain) && + ath5k_hw_rfregs_gain_adjust(ah)) + ah->ah_rf_gain = AR5K_RFGAIN_NEED_CHANGE; + } + +done: + return ah->ah_rf_gain; +} + +int ath5k_hw_set_rfgain_opt(struct ath5k_hw *ah) +{ + /* Initialize the gain optimization values */ + switch (ah->ah_radio) { + case AR5K_RF5111: + ah->ah_gain.g_step_idx = rfgain_opt_5111.go_default; + ah->ah_gain.g_step = + &rfgain_opt_5111.go_step[ah->ah_gain.g_step_idx]; + ah->ah_gain.g_low = 20; + ah->ah_gain.g_high = 35; + ah->ah_gain.g_active = 1; + break; + case AR5K_RF5112: + case AR5K_RF5413: /* ??? */ + ah->ah_gain.g_step_idx = rfgain_opt_5112.go_default; + ah->ah_gain.g_step = + &rfgain_opt_5112.go_step[ah->ah_gain.g_step_idx]; + ah->ah_gain.g_low = 20; + ah->ah_gain.g_high = 85; + ah->ah_gain.g_active = 1; + break; + default: + return -EINVAL; + } + + return 0; +} + +/**************************\ + PHY/RF channel functions +\**************************/ + +/* + * Check if a channel is supported + */ +bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) +{ + /* Check if the channel is in our supported range */ + if (flags & CHANNEL_2GHZ) { + if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && + (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) + return true; + } else if (flags & CHANNEL_5GHZ) + if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && + (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) + return true; + + return false; +} + +/* + * Convertion needed for RF5110 + */ +static u32 ath5k_hw_rf5110_chan2athchan(struct ieee80211_channel *channel) +{ + u32 athchan; + + /* + * Convert IEEE channel/MHz to an internal channel value used + * by the AR5210 chipset. This has not been verified with + * newer chipsets like the AR5212A who have a completely + * different RF/PHY part. + */ + athchan = (ath5k_hw_bitswap((channel->chan - 24) / 2, 5) << 1) | + (1 << 6) | 0x1; + + return athchan; +} + +/* + * Set channel on RF5110 + */ +static int ath5k_hw_rf5110_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 data; + + /* + * Set the channel and wait + */ + data = ath5k_hw_rf5110_chan2athchan(channel); + ath5k_hw_reg_write(ah, data, AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, 0, AR5K_RF_BUFFER_CONTROL_0); + mdelay(1); + + return 0; +} + +/* + * Convertion needed for 5111 + */ +static int ath5k_hw_rf5111_chan2athchan(unsigned int ieee, + struct ath5k_athchan_2ghz *athchan) +{ + int channel; + + /* Cast this value to catch negative channel numbers (>= -19) */ + channel = (int)ieee; + + /* + * Map 2GHz IEEE channel to 5GHz Atheros channel + */ + if (channel <= 13) { + athchan->a2_athchan = 115 + channel; + athchan->a2_flags = 0x46; + } else if (channel == 14) { + athchan->a2_athchan = 124; + athchan->a2_flags = 0x44; + } else if (channel >= 15 && channel <= 26) { + athchan->a2_athchan = ((channel - 14) * 4) + 132; + athchan->a2_flags = 0x46; + } else + return -EINVAL; + + return 0; +} + +/* + * Set channel on 5111 + */ +static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + struct ath5k_athchan_2ghz ath5k_channel_2ghz; + unsigned int ath5k_channel = channel->chan; + u32 data0, data1, clock; + int ret; + + /* + * Set the channel on the RF5111 radio + */ + data0 = data1 = 0; + + if (channel->val & CHANNEL_2GHZ) { + /* Map 2GHz channel to 5GHz Atheros channel ID */ + ret = ath5k_hw_rf5111_chan2athchan(channel->chan, + &ath5k_channel_2ghz); + if (ret) + return ret; + + ath5k_channel = ath5k_channel_2ghz.a2_athchan; + data0 = ((ath5k_hw_bitswap(ath5k_channel_2ghz.a2_flags, 8) & 0xff) + << 5) | (1 << 4); + } + + if (ath5k_channel < 145 || !(ath5k_channel & 1)) { + clock = 1; + data1 = ((ath5k_hw_bitswap(ath5k_channel - 24, 8) & 0xff) << 2) | + (clock << 1) | (1 << 10) | 1; + } else { + clock = 0; + data1 = ((ath5k_hw_bitswap((ath5k_channel - 24) / 2, 8) & 0xff) + << 2) | (clock << 1) | (1 << 10) | 1; + } + + ath5k_hw_reg_write(ah, (data1 & 0xff) | ((data0 & 0xff) << 8), + AR5K_RF_BUFFER); + ath5k_hw_reg_write(ah, ((data1 >> 8) & 0xff) | (data0 & 0xff00), + AR5K_RF_BUFFER_CONTROL_3); + + return 0; +} + +/* + * Set channel on 5112 and newer + */ +static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 data, data0, data1, data2; + u16 c; + + data = data0 = data1 = data2 = 0; + c = channel->freq; + + /* + * Set the channel on the RF5112 or newer + */ + if (c < 4800) { + if (!((c - 2224) % 5)) { + data0 = ((2 * (c - 704)) - 3040) / 10; + data1 = 1; + } else if (!((c - 2192) % 5)) { + data0 = ((2 * (c - 672)) - 3040) / 10; + data1 = 0; + } else + return -EINVAL; + + data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8); + } else { + if (!(c % 20) && c >= 5120) { + data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8); + data2 = ath5k_hw_bitswap(3, 2); + } else if (!(c % 10)) { + data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8); + data2 = ath5k_hw_bitswap(2, 2); + } else if (!(c % 5)) { + data0 = ath5k_hw_bitswap((c - 4800) / 5, 8); + data2 = ath5k_hw_bitswap(1, 2); + } else + return -EINVAL; + } + + data = (data0 << 4) | (data1 << 1) | (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 + */ +int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel) +{ + int ret; + + /* + * Check bounds supported by the PHY + * (don't care about regulation restrictions at this point) + */ + if ((channel->freq < ah->ah_capabilities.cap_range.range_2ghz_min || + channel->freq > ah->ah_capabilities.cap_range.range_2ghz_max) && + (channel->freq < ah->ah_capabilities.cap_range.range_5ghz_min || + channel->freq > ah->ah_capabilities.cap_range.range_5ghz_max)) { + ATH5K_ERR(ah->ah_sc, + "channel out of supported range (%u MHz)\n", + channel->freq); + return -EINVAL; + } + + /* + * Set the channel and wait + */ + switch (ah->ah_radio) { + case AR5K_RF5110: + ret = ath5k_hw_rf5110_channel(ah, channel); + break; + case AR5K_RF5111: + ret = ath5k_hw_rf5111_channel(ah, channel); + break; + default: + ret = ath5k_hw_rf5112_channel(ah, channel); + break; + } + + if (ret) + return ret; + + ah->ah_current_channel.freq = channel->freq; + ah->ah_current_channel.val = channel->val; + ah->ah_turbo = channel->val == CHANNEL_T ? true : false; + + return 0; +} + +/*****************\ + PHY calibration +\*****************/ + +/** + * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration + * + * @ah: struct ath5k_hw pointer we are operating on + * @freq: the channel frequency, just used for error logging + * + * This function performs a noise floor calibration of the PHY and waits for + * it to complete. Then the noise floor value is compared to some maximum + * noise floor we consider valid. + * + * Note that this is different from what the madwifi HAL does: it reads the + * noise floor and afterwards initiates the calibration. Since the noise floor + * calibration can take some time to finish, depending on the current channel + * use, that avoids the occasional timeout warnings we are seeing now. + * + * See the following link for an Atheros patent on noise floor calibration: + * 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 + * + */ +int +ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq) +{ + int ret; + unsigned int i; + s32 noise_floor; + + /* + * Enable noise floor calibration and wait until completion + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF); + + ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_NF, 0, false); + if (ret) { + ATH5K_ERR(ah->ah_sc, + "noise floor calibration timeout (%uMHz)\n", freq); + return ret; + } + + /* Wait until the noise floor is calibrated and read the value */ + for (i = 20; i > 0; i--) { + mdelay(1); + noise_floor = ath5k_hw_reg_read(ah, AR5K_PHY_NF); + noise_floor = AR5K_PHY_NF_RVAL(noise_floor); + if (noise_floor & AR5K_PHY_NF_ACTIVE) { + noise_floor = AR5K_PHY_NF_AVAL(noise_floor); + + if (noise_floor <= AR5K_TUNE_NOISE_FLOOR) + break; + } + } + + ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_CALIBRATE, + "noise floor %d\n", noise_floor); + + if (noise_floor > AR5K_TUNE_NOISE_FLOOR) { + ATH5K_ERR(ah->ah_sc, + "noise floor calibration failed (%uMHz)\n", freq); + return -EIO; + } + + ah->ah_noise_floor = noise_floor; + + return 0; +} + +/* + * Perform a PHY calibration on RF5110 + * -Fix BPSK/QAM Constellation (I/Q correction) + * -Calculate Noise Floor + */ +static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + u32 phy_sig, phy_agc, phy_sat, beacon; + int ret; + + /* + * Disable beacons and RX/TX queues, wait + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5210, + AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + beacon = ath5k_hw_reg_read(ah, AR5K_BEACON_5210); + ath5k_hw_reg_write(ah, beacon & ~AR5K_BEACON_ENABLE, AR5K_BEACON_5210); + + udelay(2300); + + /* + * Set the channel (with AGC turned off) + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + udelay(10); + ret = ath5k_hw_channel(ah, channel); + + /* + * Activate PHY and wait + */ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT); + mdelay(1); + + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + + if (ret) + return ret; + + /* + * Calibrate the radio chip + */ + + /* Remember normal state */ + phy_sig = ath5k_hw_reg_read(ah, AR5K_PHY_SIG); + phy_agc = ath5k_hw_reg_read(ah, AR5K_PHY_AGCCOARSE); + phy_sat = ath5k_hw_reg_read(ah, AR5K_PHY_ADCSAT); + + /* Update radio registers */ + ath5k_hw_reg_write(ah, (phy_sig & ~(AR5K_PHY_SIG_FIRPWR)) | + AR5K_REG_SM(-1, AR5K_PHY_SIG_FIRPWR), AR5K_PHY_SIG); + + ath5k_hw_reg_write(ah, (phy_agc & ~(AR5K_PHY_AGCCOARSE_HI | + AR5K_PHY_AGCCOARSE_LO)) | + AR5K_REG_SM(-1, AR5K_PHY_AGCCOARSE_HI) | + AR5K_REG_SM(-127, AR5K_PHY_AGCCOARSE_LO), AR5K_PHY_AGCCOARSE); + + ath5k_hw_reg_write(ah, (phy_sat & ~(AR5K_PHY_ADCSAT_ICNT | + AR5K_PHY_ADCSAT_THR)) | + AR5K_REG_SM(2, AR5K_PHY_ADCSAT_ICNT) | + AR5K_REG_SM(12, AR5K_PHY_ADCSAT_THR), AR5K_PHY_ADCSAT); + + udelay(20); + + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + udelay(10); + ath5k_hw_reg_write(ah, AR5K_PHY_RFSTG_DISABLE, AR5K_PHY_RFSTG); + AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_AGC, AR5K_PHY_AGC_DISABLE); + + mdelay(1); + + /* + * Enable calibration and wait until completion + */ + AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL, AR5K_PHY_AGCCTL_CAL); + + ret = ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL, + AR5K_PHY_AGCCTL_CAL, 0, false); + + /* Reset to normal state */ + ath5k_hw_reg_write(ah, phy_sig, AR5K_PHY_SIG); + ath5k_hw_reg_write(ah, phy_agc, AR5K_PHY_AGCCOARSE); + ath5k_hw_reg_write(ah, phy_sat, AR5K_PHY_ADCSAT); + + if (ret) { + ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n", + channel->freq); + return ret; + } + + ret = ath5k_hw_noise_floor_calibration(ah, channel->freq); + if (ret) + return ret; + + /* + * Re-enable RX/TX and beacons + */ + AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5210, + AR5K_DIAG_SW_DIS_TX | AR5K_DIAG_SW_DIS_RX_5210); + ath5k_hw_reg_write(ah, beacon, AR5K_BEACON_5210); + + return 0; +} + +/* + * Perform a PHY calibration on RF5111/5112 + */ +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; + ATH5K_TRACE(ah->ah_sc); + + if (ah->ah_calibration == false || + ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN) + goto done; + + ah->ah_calibration = false; + + 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; + + 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 */ + 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)); + +done: + ath5k_hw_noise_floor_calibration(ah, channel->freq); + + /* Request RF gain */ + if (channel->val & CHANNEL_5GHZ) { + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txpower.txp_max, + AR5K_PHY_PAPD_PROBE_TXPOWER) | + AR5K_PHY_PAPD_PROBE_TX_NEXT, AR5K_PHY_PAPD_PROBE); + ah->ah_rf_gain = AR5K_RFGAIN_READ_REQUESTED; + } + + return 0; +} + +/* + * Perform a PHY calibration + */ +int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, + struct ieee80211_channel *channel) +{ + int ret; + + if (ah->ah_radio == AR5K_RF5110) + ret = ath5k_hw_rf5110_calibrate(ah, channel); + else + ret = ath5k_hw_rf511x_calibrate(ah, channel); + + return ret; +} + +int ath5k_hw_phy_disable(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /*Just a try M.F.*/ + ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT); + + return 0; +} + +/********************\ + Misc PHY functions +\********************/ + +/* + * Get the PHY Chip revision + */ +u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) +{ + unsigned int i; + u32 srev; + u16 ret; + + ATH5K_TRACE(ah->ah_sc); + + /* + * Set the radio chip access register + */ + switch (chan) { + case CHANNEL_2GHZ: + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); + break; + case CHANNEL_5GHZ: + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + break; + default: + return 0; + } + + mdelay(2); + + /* ...wait until PHY is ready and read the selected radio revision */ + ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34)); + + for (i = 0; i < 8; i++) + ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20)); + + if (ah->ah_version == AR5K_AR5210) { + srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf; + ret = (u16)ath5k_hw_bitswap(srev, 4) + 1; + } else { + srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff; + ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) | + ((srev & 0x0f) << 4), 8); + } + + /* Reset to the 5GHz mode */ + ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); + + return ret; +} + +void /*TODO:Boundary check*/ +ath5k_hw_set_def_antenna(struct ath5k_hw *ah, unsigned int ant) +{ + ATH5K_TRACE(ah->ah_sc); + /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) + ath5k_hw_reg_write(ah, ant, AR5K_DEFAULT_ANTENNA); +} + +unsigned int ath5k_hw_get_def_antenna(struct ath5k_hw *ah) +{ + ATH5K_TRACE(ah->ah_sc); + /*Just a try M.F.*/ + if (ah->ah_version != AR5K_AR5210) + return ath5k_hw_reg_read(ah, AR5K_DEFAULT_ANTENNA); + + return false; /*XXX: What do we return for 5210 ?*/ +} + +/* + * TX power setup + */ + +/* + * Initialize the tx power table (not fully implemented) + */ +static void ath5k_txpower_table(struct ath5k_hw *ah, + struct ieee80211_channel *channel, s16 max_power) +{ + unsigned int i, min, max, n; + u16 txpower, *rates; + + rates = ah->ah_txpower.txp_rates; + + txpower = AR5K_TUNE_DEFAULT_TXPOWER * 2; + if (max_power > txpower) + txpower = max_power > AR5K_TUNE_MAX_TXPOWER ? + AR5K_TUNE_MAX_TXPOWER : max_power; + + for (i = 0; i < AR5K_MAX_RATES; i++) + rates[i] = txpower; + + /* XXX setup target powers by rate */ + + ah->ah_txpower.txp_min = rates[7]; + ah->ah_txpower.txp_max = rates[0]; + ah->ah_txpower.txp_ofdm = rates[0]; + + /* Calculate the power table */ + n = ARRAY_SIZE(ah->ah_txpower.txp_pcdac); + min = AR5K_EEPROM_PCDAC_START; + max = AR5K_EEPROM_PCDAC_STOP; + for (i = 0; i < n; i += AR5K_EEPROM_PCDAC_STEP) + ah->ah_txpower.txp_pcdac[i] = +#ifdef notyet + min + ((i * (max - min)) / n); +#else + min; +#endif +} + +/* + * Set transmition power + */ +int /*O.K. - txpower_table is unimplemented so this doesn't work*/ +ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel, + unsigned int txpower) +{ + bool tpc = ah->ah_txpower.txp_tpc; + unsigned int i; + + ATH5K_TRACE(ah->ah_sc); + if (txpower > AR5K_TUNE_MAX_TXPOWER) { + ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower); + return -EINVAL; + } + + /* Reset TX power values */ + memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower)); + ah->ah_txpower.txp_tpc = tpc; + + /* Initialize TX power table */ + ath5k_txpower_table(ah, channel, txpower); + + /* + * Write TX power values + */ + for (i = 0; i < (AR5K_EEPROM_POWER_TABLE_SIZE / 2); i++) { + ath5k_hw_reg_write(ah, + ((((ah->ah_txpower.txp_pcdac[(i << 1) + 1] << 8) | 0xff) & 0xffff) << 16) | + (((ah->ah_txpower.txp_pcdac[(i << 1) ] << 8) | 0xff) & 0xffff), + AR5K_PHY_PCDAC_TXPOWER(i)); + } + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(3, 24) | + AR5K_TXPOWER_OFDM(2, 16) | AR5K_TXPOWER_OFDM(1, 8) | + AR5K_TXPOWER_OFDM(0, 0), AR5K_PHY_TXPOWER_RATE1); + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_OFDM(7, 24) | + AR5K_TXPOWER_OFDM(6, 16) | AR5K_TXPOWER_OFDM(5, 8) | + AR5K_TXPOWER_OFDM(4, 0), AR5K_PHY_TXPOWER_RATE2); + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(10, 24) | + AR5K_TXPOWER_CCK(9, 16) | AR5K_TXPOWER_CCK(15, 8) | + AR5K_TXPOWER_CCK(8, 0), AR5K_PHY_TXPOWER_RATE3); + + ath5k_hw_reg_write(ah, AR5K_TXPOWER_CCK(14, 24) | + AR5K_TXPOWER_CCK(13, 16) | AR5K_TXPOWER_CCK(12, 8) | + AR5K_TXPOWER_CCK(11, 0), AR5K_PHY_TXPOWER_RATE4); + + if (ah->ah_txpower.txp_tpc == true) + ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE | + AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); + else + ath5k_hw_reg_write(ah, AR5K_PHY_TXPOWER_RATE_MAX | + AR5K_TUNE_MAX_TXPOWER, AR5K_PHY_TXPOWER_RATE_MAX); + + return 0; +} + +int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, unsigned int power) +{ + /*Just a try M.F.*/ + struct ieee80211_channel *channel = &ah->ah_current_channel; + + ATH5K_TRACE(ah->ah_sc); + ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER, + "changing txpower to %d\n", power); + + return ath5k_hw_txpower(ah, channel, power); +} diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h new file mode 100644 index 000000000000..2f41c8398602 --- /dev/null +++ b/drivers/net/wireless/ath5k/reg.h @@ -0,0 +1,1987 @@ +/* + * Copyright (c) 2007 Nick Kossifidis <mickflemm@gmail.com> + * Copyright (c) 2004, 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2007 Michael Taylor <mike.taylor@apprion.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/* + * Register values for Atheros 5210/5211/5212 cards from OpenBSD's ar5k + * maintained by Reyk Floeter + * + * I tried to document those registers by looking at ar5k code, some + * 802.11 (802.11e mostly) papers and by reading various public available + * Atheros presentations and papers like these: + * + * 5210 - http://nova.stanford.edu/~bbaas/ps/isscc2002_slides.pdf + * http://www.it.iitb.ac.in/~janak/wifire/01222734.pdf + * + * 5211 - http://www.hotchips.org/archives/hc14/3_Tue/16_mcfarland.pdf + */ + + + +/*====MAC DMA REGISTERS====*/ + +/* + * AR5210-Specific TXDP registers + * 5210 has only 2 transmit queues so no DCU/QCU, just + * 2 transmit descriptor pointers... + */ +#define AR5K_NOQCU_TXDP0 0x0000 /* Queue 0 - data */ +#define AR5K_NOQCU_TXDP1 0x0004 /* Queue 1 - beacons */ + +/* + * Mac Control Register + */ +#define AR5K_CR 0x0008 /* Register Address */ +#define AR5K_CR_TXE0 0x00000001 /* TX Enable for queue 0 on 5210 */ +#define AR5K_CR_TXE1 0x00000002 /* TX Enable for queue 1 on 5210 */ +#define AR5K_CR_RXE 0x00000004 /* RX Enable */ +#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 + +/* + * RX Descriptor Pointer register + */ +#define AR5K_RXDP 0x000c + +/* + * Configuration and status register + */ +#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_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_PHY_OK 0x00000100 /* [5211+] */ +#define AR5K_CFG_EEBS 0x00000200 /* EEPROM is busy */ +#define AR5K_CFG_CLKGD 0x00000400 /* Clock gated (?) */ +#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_S 17 + +/* + * Interrupt enable register + */ +#define AR5K_IER 0x0024 /* Register Address */ +#define AR5K_IER_DISABLE 0x00000000 /* Disable card interrupts */ +#define AR5K_IER_ENABLE 0x00000001 /* Enable card interrupts */ + + +/* + * 0x0028 is Beacon Control Register on 5210 + * and first RTS duration register on 5211 + */ + +/* + * Beacon control register [5210] + */ +#define AR5K_BCR 0x0028 /* Register Address */ +#define AR5K_BCR_AP 0x00000000 /* AP mode */ +#define AR5K_BCR_ADHOC 0x00000001 /* Ad-Hoc mode */ +#define AR5K_BCR_BDMAE 0x00000002 /* DMA enable */ +#define AR5K_BCR_TQ1FV 0x00000004 /* Use Queue1 for CAB traffic */ +#define AR5K_BCR_TQ1V 0x00000008 /* Use Queue1 for Beacon traffic */ +#define AR5K_BCR_BCGET 0x00000010 + +/* + * First RTS duration register [5211] + */ +#define AR5K_RTSD0 0x0028 /* Register Address */ +#define AR5K_RTSD0_6 0x000000ff /* 6Mb RTS duration mask (?) */ +#define AR5K_RTSD0_6_S 0 /* 6Mb RTS duration shift (?) */ +#define AR5K_RTSD0_9 0x0000ff00 /* 9Mb*/ +#define AR5K_RTSD0_9_S 8 +#define AR5K_RTSD0_12 0x00ff0000 /* 12Mb*/ +#define AR5K_RTSD0_12_S 16 +#define AR5K_RTSD0_18 0xff000000 /* 16Mb*/ +#define AR5K_RTSD0_18_S 24 + + +/* + * 0x002c is Beacon Status Register on 5210 + * and second RTS duration register on 5211 + */ + +/* + * Beacon status register [5210] + * + * As i can see in ar5k_ar5210_tx_start Reyk uses some of the values of BCR + * for this register, so i guess TQ1V,TQ1FV and BDMAE have the same meaning + * here and SNP/SNAP means "snapshot" (so this register gets synced with BCR). + * So SNAPPEDBCRVALID sould also stand for "snapped BCR -values- valid", so i + * renamed it to SNAPSHOTSVALID to make more sense. I realy have no idea what + * else can it be. I also renamed SNPBCMD to SNPADHOC to match BCR. + */ +#define AR5K_BSR 0x002c /* Register Address */ +#define AR5K_BSR_BDLYSW 0x00000001 /* SW Beacon delay (?) */ +#define AR5K_BSR_BDLYDMA 0x00000002 /* DMA Beacon delay (?) */ +#define AR5K_BSR_TXQ1F 0x00000004 /* Beacon queue (1) finished */ +#define AR5K_BSR_ATIMDLY 0x00000008 /* ATIM delay (?) */ +#define AR5K_BSR_SNPADHOC 0x00000100 /* Ad-hoc mode set (?) */ +#define AR5K_BSR_SNPBDMAE 0x00000200 /* Beacon DMA enabled (?) */ +#define AR5K_BSR_SNPTQ1FV 0x00000400 /* Queue1 is used for CAB traffic (?) */ +#define AR5K_BSR_SNPTQ1V 0x00000800 /* Queue1 is used for Beacon traffic (?) */ +#define AR5K_BSR_SNAPSHOTSVALID 0x00001000 /* BCR snapshots are valid (?) */ +#define AR5K_BSR_SWBA_CNT 0x00ff0000 + +/* + * Second RTS duration register [5211] + */ +#define AR5K_RTSD1 0x002c /* Register Address */ +#define AR5K_RTSD1_24 0x000000ff /* 24Mb */ +#define AR5K_RTSD1_24_S 0 +#define AR5K_RTSD1_36 0x0000ff00 /* 36Mb */ +#define AR5K_RTSD1_36_S 8 +#define AR5K_RTSD1_48 0x00ff0000 /* 48Mb */ +#define AR5K_RTSD1_48_S 16 +#define AR5K_RTSD1_54 0xff000000 /* 54Mb */ +#define AR5K_RTSD1_54_S 24 + + +/* + * 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+] */ + +/* + * Receive configuration register + */ +#define AR5K_RXCFG 0x0034 /* Register Address */ +#define AR5K_RXCFG_SDMAMW 0x00000007 /* DMA size */ +#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+] */ + +/* + * Receive jumbo descriptor last address register + * Only found in 5211 (?) + */ +#define AR5K_RXJLA 0x0038 + +/* + * 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 + +/* + * Timeout prescale register + */ +#define AR5K_TOPS 0x0044 +#define AR5K_TOPS_M 0x0000ffff /* [5211+] (?) */ + +/* + * Receive timeout register (no frame received) + */ +#define AR5K_RXNOFRM 0x0048 +#define AR5K_RXNOFRM_M 0x000003ff /* [5211+] (?) */ + +/* + * Transmit timeout register (no frame sent) + */ +#define AR5K_TXNOFRM 0x004c +#define AR5K_TXNOFRM_M 0x000003ff /* [5211+] (?) */ +#define AR5K_TXNOFRM_QCU 0x000ffc00 /* [5211+] (?) */ + +/* + * Receive frame gap timeout register + */ +#define AR5K_RPGTO 0x0050 +#define AR5K_RPGTO_M 0x000003ff /* [5211+] (?) */ + +/* + * Receive frame count limit register + */ +#define AR5K_RFCNT 0x0054 +#define AR5K_RFCNT_M 0x0000001f /* [5211+] (?) */ +#define AR5K_RFCNT_RFCL 0x0000000f /* [5210] */ + +/* + * Misc settings register + */ +#define AR5K_MISC 0x0058 /* Register Address */ +#define AR5K_MISC_DMA_OBS_M 0x000001e0 +#define AR5K_MISC_DMA_OBS_S 5 +#define AR5K_MISC_MISC_OBS_M 0x00000e00 +#define AR5K_MISC_MISC_OBS_S 9 +#define AR5K_MISC_MAC_OBS_LSB_M 0x00007000 +#define AR5K_MISC_MAC_OBS_LSB_S 12 +#define AR5K_MISC_MAC_OBS_MSB_M 0x00038000 +#define AR5K_MISC_MAC_OBS_MSB_S 15 +#define AR5K_MISC_LED_DECAY 0x001c0000 /* [5210] */ +#define AR5K_MISC_LED_BLINK 0x00e00000 /* [5210] */ + +/* + * QCU/DCU clock gating register (5311) + */ +#define AR5K_QCUDCU_CLKGT 0x005c /* Register Address (?) */ +#define AR5K_QCUDCU_CLKGT_QCU 0x0000ffff /* Mask for QCU clock */ +#define AR5K_QCUDCU_CLKGT_DCU 0x07ff0000 /* Mask for DCU clock */ + +/* + * Interrupt Status Registers + * + * For 5210 there is only one status register but for + * 5211/5212 we have one primary and 4 secondary registers. + * So we have AR5K_ISR for 5210 and AR5K_PISR /SISRx for 5211/5212. + * Most of these bits are common for all chipsets. + */ +#define AR5K_ISR 0x001c /* Register Address [5210] */ +#define AR5K_PISR 0x0080 /* Register Address [5211+] */ +#define AR5K_ISR_RXOK 0x00000001 /* Frame successfuly recieved */ +#define AR5K_ISR_RXDESC 0x00000002 /* RX descriptor request */ +#define AR5K_ISR_RXERR 0x00000004 /* Receive error */ +#define AR5K_ISR_RXNOFRM 0x00000008 /* No frame received (receive timeout) */ +#define AR5K_ISR_RXEOL 0x00000010 /* Empty RX descriptor */ +#define AR5K_ISR_RXORN 0x00000020 /* Receive FIFO overrun */ +#define AR5K_ISR_TXOK 0x00000040 /* Frame successfuly transmited */ +#define AR5K_ISR_TXDESC 0x00000080 /* TX descriptor request */ +#define AR5K_ISR_TXERR 0x00000100 /* Transmit error */ +#define AR5K_ISR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout) */ +#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_RXPHY 0x00004000 /* PHY error */ +#define AR5K_ISR_RXKCM 0x00008000 +#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_TIM 0x00800000 /* [5210] */ +#define AR5K_ISR_BCNMISC 0x00800000 /* [5212+] */ +#define AR5K_ISR_GPIO 0x01000000 /* GPIO (rf kill)*/ +#define AR5K_ISR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ +#define AR5K_ISR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ +#define AR5K_ISR_QTRIG 0x08000000 /* [5211+] */ + +/* + * Secondary status registers [5211+] (0 - 4) + * + * I guess from the names that these give the status for each + * queue, that's why only masks are defined here, haven't got + * any info about them (couldn't find them anywhere in ar5k code). + */ +#define AR5K_SISR0 0x0084 /* Register Address [5211+] */ +#define AR5K_SISR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ +#define AR5K_SISR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ + +#define AR5K_SISR1 0x0088 /* Register Address [5211+] */ +#define AR5K_SISR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ +#define AR5K_SISR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ + +#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_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 0x20000000 /* [5212+] */ + +#define AR5K_SISR3 0x0090 /* Register Address [5211+] */ +#define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ +#define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ + +#define AR5K_SISR4 0x0094 /* Register Address [5211+] */ +#define AR5K_SISR4_QTRIG 0x000003ff /* Mask for QTRIG */ + +/* + * Shadow read-and-clear interrupt status registers [5211+] + */ +#define AR5K_RAC_PISR 0x00c0 /* Read and clear PISR */ +#define AR5K_RAC_SISR0 0x00c4 /* Read and clear SISR0 */ +#define AR5K_RAC_SISR1 0x00c8 /* Read and clear SISR1 */ +#define AR5K_RAC_SISR2 0x00cc /* Read and clear SISR2 */ +#define AR5K_RAC_SISR3 0x00d0 /* Read and clear SISR3 */ +#define AR5K_RAC_SISR4 0x00d4 /* Read and clear SISR4 */ + +/* + * Interrupt Mask Registers + * + * As whith ISRs 5210 has one IMR (AR5K_IMR) and 5211/5212 has one primary + * (AR5K_PIMR) and 4 secondary IMRs (AR5K_SIMRx). Note that ISR/IMR flags match. + */ +#define AR5K_IMR 0x0020 /* Register Address [5210] */ +#define AR5K_PIMR 0x00a0 /* Register Address [5211+] */ +#define AR5K_IMR_RXOK 0x00000001 /* Frame successfuly recieved*/ +#define AR5K_IMR_RXDESC 0x00000002 /* RX descriptor request*/ +#define AR5K_IMR_RXERR 0x00000004 /* Receive error*/ +#define AR5K_IMR_RXNOFRM 0x00000008 /* No frame received (receive timeout)*/ +#define AR5K_IMR_RXEOL 0x00000010 /* Empty RX descriptor*/ +#define AR5K_IMR_RXORN 0x00000020 /* Receive FIFO overrun*/ +#define AR5K_IMR_TXOK 0x00000040 /* Frame successfuly transmited*/ +#define AR5K_IMR_TXDESC 0x00000080 /* TX descriptor request*/ +#define AR5K_IMR_TXERR 0x00000100 /* Transmit error*/ +#define AR5K_IMR_TXNOFRM 0x00000200 /* No frame transmited (transmit timeout)*/ +#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_RXPHY 0x00004000 /* PHY error*/ +#define AR5K_IMR_RXKCM 0x00008000 +#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_TIM 0x00800000 /* [5211+] */ +#define AR5K_IMR_BCNMISC 0x00800000 /* [5212+] */ +#define AR5K_IMR_GPIO 0x01000000 /* GPIO (rf kill)*/ +#define AR5K_IMR_QCBRORN 0x02000000 /* CBR overrun (?) [5211+] */ +#define AR5K_IMR_QCBRURN 0x04000000 /* CBR underrun (?) [5211+] */ +#define AR5K_IMR_QTRIG 0x08000000 /* [5211+] */ + +/* + * Secondary interrupt mask registers [5211+] (0 - 4) + */ +#define AR5K_SIMR0 0x00a4 /* Register Address [5211+] */ +#define AR5K_SIMR0_QCU_TXOK 0x000003ff /* Mask for QCU_TXOK */ +#define AR5K_SIMR0_QCU_TXOK_S 0 +#define AR5K_SIMR0_QCU_TXDESC 0x03ff0000 /* Mask for QCU_TXDESC */ +#define AR5K_SIMR0_QCU_TXDESC_S 16 + +#define AR5K_SIMR1 0x00a8 /* Register Address [5211+] */ +#define AR5K_SIMR1_QCU_TXERR 0x000003ff /* Mask for QCU_TXERR */ +#define AR5K_SIMR1_QCU_TXERR_S 0 +#define AR5K_SIMR1_QCU_TXEOL 0x03ff0000 /* Mask for QCU_TXEOL */ +#define AR5K_SIMR1_QCU_TXEOL_S 16 + +#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_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 0x20000000 /* [5212+] */ + +#define AR5K_SIMR3 0x00b0 /* Register Address [5211+] */ +#define AR5K_SIMR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ +#define AR5K_SIMR3_QCBRORN_S 0 +#define AR5K_SIMR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ +#define AR5K_SIMR3_QCBRURN_S 16 + +#define AR5K_SIMR4 0x00b4 /* Register Address [5211+] */ +#define AR5K_SIMR4_QTRIG 0x000003ff /* Mask for QTRIG */ +#define AR5K_SIMR4_QTRIG_S 0 + + +/* + * Decompression mask registers [5212+] + */ +#define AR5K_DCM_ADDR 0x0400 /*Decompression mask address (?)*/ +#define AR5K_DCM_DATA 0x0404 /*Decompression mask data (?)*/ + +/* + * Decompression configuration registers [5212+] + */ +#define AR5K_DCCFG 0x0420 + +/* + * Compression configuration registers [5212+] + */ +#define AR5K_CCFG 0x0600 +#define AR5K_CCFG_CUP 0x0604 + +/* + * Compression performance counter registers [5212+] + */ +#define AR5K_CPC0 0x0610 /* Compression performance counter 0 */ +#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 (?) */ + + +/* + * Queue control unit (QCU) registers [5211+] + * + * Card has 12 TX Queues but i see that only 0-9 are used (?) + * both in binary HAL (see ah.h) and ar5k. Each queue has it's own + * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) + * configuration register (0x08c0 - 0x08ec), a ready time configuration + * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - + * 0x09ec) and a status register (0x0a00 - 0x0a2c). We also have some + * global registers, QCU transmit enable/disable and "one shot arm (?)" + * 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?) + */ + +/* + * Generic QCU Register access macros + */ +#define AR5K_QUEUE_REG(_r, _q) (((_q) << 2) + _r) +#define AR5K_QCU_GLOBAL_READ(_r, _q) (AR5K_REG_READ(_r) & (1 << _q)) +#define AR5K_QCU_GLOBAL_WRITE(_r, _q) AR5K_REG_WRITE(_r, (1 << _q)) + +/* + * QCU Transmit descriptor pointer registers + */ +#define AR5K_QCU_TXDP_BASE 0x0800 /* Register Address - Queue0 TXDP */ +#define AR5K_QUEUE_TXDP(_q) AR5K_QUEUE_REG(AR5K_QCU_TXDP_BASE, _q) + +/* + * QCU Transmit enable register + */ +#define AR5K_QCU_TXE 0x0840 +#define AR5K_ENABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXE, _q) +#define AR5K_QUEUE_ENABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXE, _q) + +/* + * QCU Transmit disable register + */ +#define AR5K_QCU_TXD 0x0880 +#define AR5K_DISABLE_QUEUE(_q) AR5K_QCU_GLOBAL_WRITE(AR5K_QCU_TXD, _q) +#define AR5K_QUEUE_DISABLED(_q) AR5K_QCU_GLOBAL_READ(AR5K_QCU_TXD, _q) + +/* + * QCU Constant Bit Rate configuration registers + */ +#define AR5K_QCU_CBRCFG_BASE 0x08c0 /* Register Address - Queue0 CBRCFG */ +#define AR5K_QCU_CBRCFG_INTVAL 0x00ffffff /* CBR Interval mask */ +#define AR5K_QCU_CBRCFG_INTVAL_S 0 +#define AR5K_QCU_CBRCFG_ORN_THRES 0xff000000 /* CBR overrun threshold mask */ +#define AR5K_QCU_CBRCFG_ORN_THRES_S 24 +#define AR5K_QUEUE_CBRCFG(_q) AR5K_QUEUE_REG(AR5K_QCU_CBRCFG_BASE, _q) + +/* + * QCU Ready time configuration registers + */ +#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) + +/* + * QCU one shot arm set registers + */ +#define AR5K_QCU_ONESHOTARM_SET 0x0940 /* Register Address -QCU "one shot arm set (?)" */ +#define AR5K_QCU_ONESHOTARM_SET_M 0x0000ffff + +/* + * QCU one shot arm clear registers + */ +#define AR5K_QCU_ONESHOTARM_CLEAR 0x0980 /* Register Address -QCU "one shot arm clear (?)" */ +#define AR5K_QCU_ONESHOTARM_CLEAR_M 0x0000ffff + +/* + * QCU misc registers + */ +#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_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_QUEUE_MISC(_q) AR5K_QUEUE_REG(AR5K_QCU_MISC_BASE, _q) + + +/* + * QCU status registers + */ +#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_QUEUE_STATUS(_q) AR5K_QUEUE_REG(AR5K_QCU_STS_BASE, _q) + +/* + * QCU ready time shutdown register + */ +#define AR5K_QCU_RDYTIMESHDN 0x0a40 +#define AR5K_QCU_RDYTIMESHDN_M 0x000003ff + +/* + * QCU compression buffer base registers [5212+] + */ +#define AR5K_QCU_CBB_SELECT 0x0b00 +#define AR5K_QCU_CBB_ADDR 0x0b04 + +/* + * QCU compression buffer configuration register [5212+] + */ +#define AR5K_QCU_CBCFG 0x0b08 + + + +/* + * Distributed Coordination Function (DCF) control unit (DCU) + * registers [5211+] + * + * These registers control the various characteristics of each queue + * for 802.11e (WME) combatibility so they go together with + * QCU registers in pairs. For each queue we have a QCU mask register, + * (0x1000 - 0x102c), a local-IFS settings register (0x1040 - 0x106c), + * a retry limit register (0x1080 - 0x10ac), a channel time register + * (0x10c0 - 0x10ec), a misc-settings register (0x1100 - 0x112c) and + * a sequence number register (0x1140 - 0x116c). It seems that "global" + * registers here afect all queues (see use of DCU_GBL_IFS_SLOT in ar5k). + * We use the same macros here for easier register access. + * + */ + +/* + * DCU QCU mask registers + */ +#define AR5K_DCU_QCUMASK_BASE 0x1000 /* Register Address -Queue0 DCU_QCUMASK */ +#define AR5K_DCU_QCUMASK_M 0x000003ff +#define AR5K_QUEUE_QCUMASK(_q) AR5K_QUEUE_REG(AR5K_DCU_QCUMASK_BASE, _q) + +/* + * DCU local Inter Frame Space settings register + */ +#define AR5K_DCU_LCL_IFS_BASE 0x1040 /* Register Address -Queue0 DCU_LCL_IFS */ +#define AR5K_DCU_LCL_IFS_CW_MIN 0x000003ff /* Minimum Contention Window */ +#define AR5K_DCU_LCL_IFS_CW_MIN_S 0 +#define AR5K_DCU_LCL_IFS_CW_MAX 0x000ffc00 /* Maximum Contention Window */ +#define AR5K_DCU_LCL_IFS_CW_MAX_S 10 +#define AR5K_DCU_LCL_IFS_AIFS 0x0ff00000 /* Arbitrated Interframe Space */ +#define AR5K_DCU_LCL_IFS_AIFS_S 20 +#define AR5K_QUEUE_DFS_LOCAL_IFS(_q) AR5K_QUEUE_REG(AR5K_DCU_LCL_IFS_BASE, _q) + +/* + * DCU retry limit registers + */ +#define AR5K_DCU_RETRY_LMT_BASE 0x1080 /* Register Address -Queue0 DCU_RETRY_LMT */ +#define AR5K_DCU_RETRY_LMT_SH_RETRY 0x0000000f /* Short retry limit mask */ +#define AR5K_DCU_RETRY_LMT_SH_RETRY_S 0 +#define AR5K_DCU_RETRY_LMT_LG_RETRY 0x000000f0 /* Long retry limit mask */ +#define AR5K_DCU_RETRY_LMT_LG_RETRY_S 4 +#define AR5K_DCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask (?) */ +#define AR5K_DCU_RETRY_LMT_SSH_RETRY_S 8 +#define AR5K_DCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask (?) */ +#define AR5K_DCU_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_QUEUE_DFS_RETRY_LIMIT(_q) AR5K_QUEUE_REG(AR5K_DCU_RETRY_LMT_BASE, _q) + +/* + * DCU channel time registers + */ +#define AR5K_DCU_CHAN_TIME_BASE 0x10c0 /* Register Address -Queue0 DCU_CHAN_TIME */ +#define AR5K_DCU_CHAN_TIME_DUR 0x000fffff /* Channel time duration */ +#define AR5K_DCU_CHAN_TIME_DUR_S 0 +#define AR5K_DCU_CHAN_TIME_ENABLE 0x00100000 /* Enable channel time */ +#define AR5K_QUEUE_DFS_CHANNEL_TIME(_q) AR5K_QUEUE_REG(AR5K_DCU_CHAN_TIME_BASE, _q) + +/* + * DCU misc registers [5211+] + * + * For some of the registers i couldn't find in the code + * (only backoff stuff is there realy) i tried to match the + * names with 802.11e parameters etc, so i guess VIRTCOL here + * means Virtual Collision and HCFPOLL means Hybrid Coordination + * factor Poll (CF- Poll). Arbiter lockout control controls the + * behaviour on low priority queues when we have multiple queues + * with pending frames. Intra-frame lockout means we wait until + * the queue's current frame transmits (with post frame backoff and bursting) + * before we transmit anything else and global lockout means we + * wait for the whole queue to finish before higher priority queues + * can transmit (this is used on beacon and CAB queues). + * 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_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_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_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_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_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_QUEUE_DFS_SEQNUM(_q) AR5K_QUEUE_REG(AR5K_DCU_SEQNUM_BASE, _q) + +/* + * DCU global IFS SIFS registers + */ +#define AR5K_DCU_GBL_IFS_SIFS 0x1030 +#define AR5K_DCU_GBL_IFS_SIFS_M 0x0000ffff + +/* + * DCU global IFS slot interval registers + */ +#define AR5K_DCU_GBL_IFS_SLOT 0x1070 +#define AR5K_DCU_GBL_IFS_SLOT_M 0x0000ffff + +/* + * DCU global IFS EIFS registers + */ +#define AR5K_DCU_GBL_IFS_EIFS 0x10b0 +#define AR5K_DCU_GBL_IFS_EIFS_M 0x0000ffff + +/* + * DCU global IFS misc registers + */ +#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 + +/* + * DCU frame prefetch control register + */ +#define AR5K_DCU_FP 0x1230 + +/* + * 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 (?) */ + +/* + * DCU transmit filter register + */ +#define AR5K_DCU_TX_FILTER 0x1038 + +/* + * DCU clear transmit filter register + */ +#define AR5K_DCU_TX_FILTER_CLR 0x143c + +/* + * DCU set transmit filter register + */ +#define AR5K_DCU_TX_FILTER_SET 0x147c + +/* + * 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 */ +#define AR5K_RESET_CTL_DMA 0x00000002 /* DMA (Rx/Tx) reset [5210] */ +#define AR5K_RESET_CTL_BASEBAND 0x00000002 /* Baseband reset [5211+] */ +#define AR5K_RESET_CTL_MAC 0x00000004 /* MAC reset (PCU+Baseband ?) [5210] */ +#define AR5K_RESET_CTL_PHY 0x00000008 /* PHY reset [5210] */ +#define AR5K_RESET_CTL_PCI 0x00000010 /* PCI Core reset (interrupts etc) */ +#define AR5K_RESET_CTL_CHIP (AR5K_RESET_CTL_PCU | AR5K_RESET_CTL_DMA | \ + AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_PHY) + +/* + * Sleep control register + */ +#define AR5K_SLEEP_CTL 0x4004 /* Register Address */ +#define AR5K_SLEEP_CTL_SLDUR 0x0000ffff /* Sleep duration mask */ +#define AR5K_SLEEP_CTL_SLDUR_S 0 +#define AR5K_SLEEP_CTL_SLE 0x00030000 /* Sleep enable mask */ +#define AR5K_SLEEP_CTL_SLE_S 16 +#define AR5K_SLEEP_CTL_SLE_WAKE 0x00000000 /* Force chip awake */ +#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+] */ + +/* + * Interrupt pending register + */ +#define AR5K_INTPEND 0x4008 +#define AR5K_INTPEND_M 0x00000001 + +/* + * Sleep force register + */ +#define AR5K_SFR 0x400c +#define AR5K_SFR_M 0x00000001 + +/* + * PCI configuration register + */ +#define AR5K_PCICFG 0x4010 /* Register Address */ +#define AR5K_PCICFG_EEAE 0x00000001 /* Eeprom access enable [5210] */ +#define AR5K_PCICFG_CLKRUNEN 0x00000004 /* CLKRUN enable [5211+] */ +#define AR5K_PCICFG_EESIZE 0x00000018 /* Mask for EEPROM size [5211+] */ +#define AR5K_PCICFG_EESIZE_S 3 +#define AR5K_PCICFG_EESIZE_4K 0 /* 4K */ +#define AR5K_PCICFG_EESIZE_8K 1 /* 8K */ +#define AR5K_PCICFG_EESIZE_16K 2 /* 16K */ +#define AR5K_PCICFG_EESIZE_FAIL 3 /* Failed to get size (?) [5211+] */ +#define AR5K_PCICFG_LED 0x00000060 /* Led status [5211+] */ +#define AR5K_PCICFG_LED_NONE 0x00000000 /* Default [5211+] */ +#define AR5K_PCICFG_LED_PEND 0x00000020 /* Scan / Auth pending */ +#define AR5K_PCICFG_LED_ASSOC 0x00000040 /* Associated */ +#define AR5K_PCICFG_BUS_SEL 0x00000380 /* Mask for "bus select" [5211+] (?) */ +#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_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_S 20 +#define AR5K_PCICFG_LEDSLOW 0x00800000 /* Slow led blink rate (?) [5211+] */ +#define AR5K_PCICFG_LEDSTATE \ + (AR5K_PCICFG_LED | AR5K_PCICFG_LEDMODE | \ + AR5K_PCICFG_LEDBLINK | AR5K_PCICFG_LEDSLOW) + +/* + * "General Purpose Input/Output" (GPIO) control register + * + * I'm not sure about this but after looking at the code + * for all chipsets here is what i got. + * + * We have 6 GPIOs (pins), each GPIO has 4 modes (2 bits) + * Mode 0 -> always input + * Mode 1 -> output when GPIODO for this GPIO is set to 0 + * Mode 2 -> output when GPIODO for this GPIO is set to 1 + * Mode 3 -> always output + * + * For more infos check out get_gpio/set_gpio and + * set_gpio_input/set_gpio_output functs. + * For more infos on gpio interrupt check out set_gpio_intr. + */ +#define AR5K_NUM_GPIO 6 + +#define AR5K_GPIOCR 0x4014 /* Register Address */ +#define AR5K_GPIOCR_INT_ENA 0x00008000 /* Enable GPIO interrupt */ +#define AR5K_GPIOCR_INT_SELL 0x00000000 /* Generate interrupt when pin is off (?) */ +#define AR5K_GPIOCR_INT_SELH 0x00010000 /* Generate interrupt when pin is on */ +#define AR5K_GPIOCR_IN(n) (0 << ((n) * 2)) /* Mode 0 for pin n */ +#define AR5K_GPIOCR_OUT0(n) (1 << ((n) * 2)) /* Mode 1 for pin n */ +#define AR5K_GPIOCR_OUT1(n) (2 << ((n) * 2)) /* Mode 2 for pin n */ +#define AR5K_GPIOCR_OUT(n) (3 << ((n) * 2)) /* Mode 3 for pin n */ +#define AR5K_GPIOCR_INT_SEL(n) ((n) << 12) /* Interrupt for GPIO pin n */ + +/* + * "General Purpose Input/Output" (GPIO) data output register + */ +#define AR5K_GPIODO 0x4018 + +/* + * "General Purpose Input/Output" (GPIO) data input register + */ +#define AR5K_GPIODI 0x401c +#define AR5K_GPIODI_M 0x0000002f + + +/* + * Silicon revision register + */ +#define AR5K_SREV 0x4020 /* Register Address */ +#define AR5K_SREV_REV 0x0000000f /* Mask for revision */ +#define AR5K_SREV_REV_S 0 +#define AR5K_SREV_VER 0x000000ff /* Mask for version */ +#define AR5K_SREV_VER_S 4 + + + +/*====EEPROM REGISTERS====*/ + +/* + * EEPROM access registers + * + * Here we got a difference between 5210/5211-12 + * read data register for 5210 is at 0x6800 and + * status register is at 0x6c00. There is also + * no eeprom command register on 5210 and the + * offsets are different. + * + * To read eeprom data for a specific offset: + * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) + * read AR5K_EEPROM_BASE +(4 * offset) + * check the eeprom status register + * and read eeprom data register. + * + * 5211 - write offset to AR5K_EEPROM_BASE + * 5212 write AR5K_EEPROM_CMD_READ on AR5K_EEPROM_CMD + * check the eeprom status register + * and read eeprom data register. + * + * To write eeprom data for a specific offset: + * 5210 - enable eeprom access (AR5K_PCICFG_EEAE) + * write data to AR5K_EEPROM_BASE +(4 * offset) + * check the eeprom status register + * 5211 - write AR5K_EEPROM_CMD_RESET on AR5K_EEPROM_CMD + * 5212 write offset to AR5K_EEPROM_BASE + * write data to data register + * write AR5K_EEPROM_CMD_WRITE on AR5K_EEPROM_CMD + * check the eeprom status register + * + * For more infos check eeprom_* functs and the ar5k.c + * file posted in madwifi-devel mailing list. + * http://sourceforge.net/mailarchive/message.php?msg_id=8966525 + * + */ +#define AR5K_EEPROM_BASE 0x6000 + +/* + * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE) + */ +#define AR5K_EEPROM_MAGIC 0x003d /* EEPROM Magic number */ +#define AR5K_EEPROM_MAGIC_VALUE 0x5aa5 /* Default - found on EEPROM */ +#define AR5K_EEPROM_MAGIC_5212 0x0000145c /* 5212 */ +#define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ +#define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ + +#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ +#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ +#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 +#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ +#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 +#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ +#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 +#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ +#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 +#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ +#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 +#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ +#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 +#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ +#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 +#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ +#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) +#define AR5K_EEPROM_INFO_CKSUM 0xffff +#define AR5K_EEPROM_INFO(_n) (AR5K_EEPROM_INFO_BASE + (_n)) + +#define AR5K_EEPROM_VERSION AR5K_EEPROM_INFO(1) /* EEPROM Version */ +#define AR5K_EEPROM_VERSION_3_0 0x3000 /* No idea what's going on before this version */ +#define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ +#define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ +#define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ +#define AR5K_EEPROM_VERSION_4_3 0x4003 +#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_MODE_11A 0 +#define AR5K_EEPROM_MODE_11B 1 +#define AR5K_EEPROM_MODE_11G 2 + +#define AR5K_EEPROM_HDR AR5K_EEPROM_INFO(2) /* Header that contains the device caps */ +#define AR5K_EEPROM_HDR_11A(_v) (((_v) >> AR5K_EEPROM_MODE_11A) & 0x1) +#define AR5K_EEPROM_HDR_11B(_v) (((_v) >> AR5K_EEPROM_MODE_11B) & 0x1) +#define AR5K_EEPROM_HDR_11G(_v) (((_v) >> AR5K_EEPROM_MODE_11G) & 0x1) +#define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ +#define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ +#define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ +#define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ + +#define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c +#define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 +#define AR5K_EEPROM_RFKILL_POLARITY 0x00000002 +#define AR5K_EEPROM_RFKILL_POLARITY_S 1 + +/* Newer EEPROMs are using a different offset */ +#define AR5K_EEPROM_OFF(_v, _v3_0, _v3_3) \ + (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) + +#define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) +#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) + +/* calibration settings */ +#define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) +#define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) +#define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) +#define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ + +/* [3.1 - 3.3] */ +#define AR5K_EEPROM_OBDB0_2GHZ 0x00ec +#define AR5K_EEPROM_OBDB1_2GHZ 0x00ed + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 0x00c4 +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) +#define AR5K_EEPROM_MISC1 0x00c5 +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) + +/* + * EEPROM data register + */ +#define AR5K_EEPROM_DATA_5211 0x6004 +#define AR5K_EEPROM_DATA_5210 0x6800 +#define AR5K_EEPROM_DATA (ah->ah_version == AR5K_AR5210 ? \ + AR5K_EEPROM_DATA_5210 : AR5K_EEPROM_DATA_5211) + +/* + * EEPROM command register + */ +#define AR5K_EEPROM_CMD 0x6008 /* Register Addres */ +#define AR5K_EEPROM_CMD_READ 0x00000001 /* EEPROM read */ +#define AR5K_EEPROM_CMD_WRITE 0x00000002 /* EEPROM write */ +#define AR5K_EEPROM_CMD_RESET 0x00000004 /* EEPROM reset */ + +/* + * EEPROM status register + */ +#define AR5K_EEPROM_STAT_5210 0x6c00 /* Register Address [5210] */ +#define AR5K_EEPROM_STAT_5211 0x600c /* Register Address [5211+] */ +#define AR5K_EEPROM_STATUS (ah->ah_version == AR5K_AR5210 ? \ + AR5K_EEPROM_STAT_5210 : AR5K_EEPROM_STAT_5211) +#define AR5K_EEPROM_STAT_RDERR 0x00000001 /* EEPROM read failed */ +#define AR5K_EEPROM_STAT_RDDONE 0x00000002 /* EEPROM read successful */ +#define AR5K_EEPROM_STAT_WRERR 0x00000004 /* EEPROM write failed */ +#define AR5K_EEPROM_STAT_WRDONE 0x00000008 /* EEPROM write successful */ + +/* + * EEPROM config register (?) + */ +#define AR5K_EEPROM_CFG 0x6010 + + + +/* + * Protocol Control Unit (PCU) registers + */ +/* + * Used for checking initial register writes + * during channel reset (see reset func) + */ +#define AR5K_PCU_MIN 0x8000 +#define AR5K_PCU_MAX 0x8fff + +/* + * First station id register (MAC address in lower 32 bits) + */ +#define AR5K_STA_ID0 0x8000 + +/* + * Second station id register (MAC address in upper 16 bits) + */ +#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_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+] */ +#define AR5K_STA_ID1_PCF_5210 0x00200000 /* Enable PCF on [5210]*/ +#define AR5K_STA_ID1_PCF (ah->ah_version == AR5K_AR5210 ? \ + 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_BASE_RATE_11B 0x02000000 /* Use 11b base rate (for ACK/CTS ?) [5211+] */ + +/* + * First BSSID register (MAC address, lower 32bits) + */ +#define AR5K_BSS_ID0 0x8008 + +/* + * Second BSSID register (MAC address in upper 16 bits) + * + * AID: Association ID + */ +#define AR5K_BSS_ID1 0x800c +#define AR5K_BSS_ID1_AID 0xffff0000 +#define AR5K_BSS_ID1_AID_S 16 + +/* + * Backoff slot time register + */ +#define AR5K_SLOT_TIME 0x8010 + +/* + * ACK/CTS timeout register + */ +#define AR5K_TIME_OUT 0x8014 /* Register Address */ +#define AR5K_TIME_OUT_ACK 0x00001fff /* ACK timeout mask */ +#define AR5K_TIME_OUT_ACK_S 0 +#define AR5K_TIME_OUT_CTS 0x1fff0000 /* CTS timeout mask */ +#define AR5K_TIME_OUT_CTS_S 16 + +/* + * RSSI threshold register + */ +#define AR5K_RSSI_THR 0x8018 /* Register Address */ +#define AR5K_RSSI_THR_M 0x000000ff /* Mask for RSSI threshold [5211+] */ +#define AR5K_RSSI_THR_BMISS_5210 0x00000700 /* Mask for Beacon Missed threshold [5210] */ +#define AR5K_RSSI_THR_BMISS_5210_S 8 +#define AR5K_RSSI_THR_BMISS_5211 0x0000ff00 /* Mask for Beacon Missed threshold [5211+] */ +#define AR5K_RSSI_THR_BMISS_5211_S 8 +#define AR5K_RSSI_THR_BMISS (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RSSI_THR_BMISS_5210 : AR5K_RSSI_THR_BMISS_5211) +#define AR5K_RSSI_THR_BMISS_S 8 + +/* + * 5210 has more PCU registers because there is no QCU/DCU + * so queue parameters are set here, this way a lot common + * registers have different address for 5210. To make things + * easier we define a macro based on ah->ah_version for common + * registers with different addresses and common flags. + */ + +/* + * Retry limit register + * + * 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_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 */ +#define AR5K_NODCU_RETRY_LMT_LG_RETRY_S 4 +#define AR5K_NODCU_RETRY_LMT_SSH_RETRY 0x00003f00 /* Station short retry limit mask */ +#define AR5K_NODCU_RETRY_LMT_SSH_RETRY_S 8 +#define AR5K_NODCU_RETRY_LMT_SLG_RETRY 0x000fc000 /* Station long retry limit mask */ +#define AR5K_NODCU_RETRY_LMT_SLG_RETRY_S 14 +#define AR5K_NODCU_RETRY_LMT_CW_MIN 0x3ff00000 /* Minimum contention window mask */ +#define AR5K_NODCU_RETRY_LMT_CW_MIN_S 20 + +/* + * Transmit latency register + */ +#define AR5K_USEC_5210 0x8020 /* Register Address [5210] */ +#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_S 0 +#define AR5K_USEC_32 0x00003f80 +#define AR5K_USEC_32_S 7 +#define AR5K_USEC_TX_LATENCY_5211 0x007fc000 +#define AR5K_USEC_TX_LATENCY_5211_S 14 +#define AR5K_USEC_RX_LATENCY_5211 0x1f800000 +#define AR5K_USEC_RX_LATENCY_5211_S 23 +#define AR5K_USEC_TX_LATENCY_5210 0x000fc000 /* also for 5311 */ +#define AR5K_USEC_TX_LATENCY_5210_S 14 +#define AR5K_USEC_RX_LATENCY_5210 0x03f00000 /* also for 5311 */ +#define AR5K_USEC_RX_LATENCY_5210_S 20 + +/* + * PCU beacon control register + */ +#define AR5K_BEACON_5210 0x8024 +#define AR5K_BEACON_5211 0x8020 +#define AR5K_BEACON (ah->ah_version == AR5K_AR5210 ? \ + AR5K_BEACON_5210 : AR5K_BEACON_5211) +#define AR5K_BEACON_PERIOD 0x0000ffff +#define AR5K_BEACON_PERIOD_S 0 +#define AR5K_BEACON_TIM 0x007f0000 +#define AR5K_BEACON_TIM_S 16 +#define AR5K_BEACON_ENABLE 0x00800000 +#define AR5K_BEACON_RESET_TSF 0x01000000 + +/* + * CFP period register + */ +#define AR5K_CFP_PERIOD_5210 0x8028 +#define AR5K_CFP_PERIOD_5211 0x8024 +#define AR5K_CFP_PERIOD (ah->ah_version == AR5K_AR5210 ? \ + AR5K_CFP_PERIOD_5210 : AR5K_CFP_PERIOD_5211) + +/* + * Next beacon time register + */ +#define AR5K_TIMER0_5210 0x802c +#define AR5K_TIMER0_5211 0x8028 +#define AR5K_TIMER0 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER0_5210 : AR5K_TIMER0_5211) + +/* + * Next DMA beacon alert register + */ +#define AR5K_TIMER1_5210 0x8030 +#define AR5K_TIMER1_5211 0x802c +#define AR5K_TIMER1 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER1_5210 : AR5K_TIMER1_5211) + +/* + * Next software beacon alert register + */ +#define AR5K_TIMER2_5210 0x8034 +#define AR5K_TIMER2_5211 0x8030 +#define AR5K_TIMER2 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER2_5210 : AR5K_TIMER2_5211) + +/* + * Next ATIM window time register + */ +#define AR5K_TIMER3_5210 0x8038 +#define AR5K_TIMER3_5211 0x8034 +#define AR5K_TIMER3 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TIMER3_5210 : AR5K_TIMER3_5211) + + +/* + * 5210 First inter frame spacing register (IFS) + */ +#define AR5K_IFS0 0x8040 +#define AR5K_IFS0_SIFS 0x000007ff +#define AR5K_IFS0_SIFS_S 0 +#define AR5K_IFS0_DIFS 0x007ff800 +#define AR5K_IFS0_DIFS_S 11 + +/* + * 5210 Second inter frame spacing register (IFS) + */ +#define AR5K_IFS1 0x8044 +#define AR5K_IFS1_PIFS 0x00000fff +#define AR5K_IFS1_PIFS_S 0 +#define AR5K_IFS1_EIFS 0x03fff000 +#define AR5K_IFS1_EIFS_S 12 +#define AR5K_IFS1_CS_EN 0x04000000 + + +/* + * CFP duration register + */ +#define AR5K_CFP_DUR_5210 0x8048 +#define AR5K_CFP_DUR_5211 0x8038 +#define AR5K_CFP_DUR (ah->ah_version == AR5K_AR5210 ? \ + AR5K_CFP_DUR_5210 : AR5K_CFP_DUR_5211) + +/* + * 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+] */ +#define AR5K_RX_FILTER (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RX_FILTER_5210 : AR5K_RX_FILTER_5211) +#define AR5K_RX_FILTER_UCAST 0x00000001 /* Don't filter unicast frames */ +#define AR5K_RX_FILTER_MCAST 0x00000002 /* Don't filter multicast frames */ +#define AR5K_RX_FILTER_BCAST 0x00000004 /* Don't filter broadcast frames */ +#define AR5K_RX_FILTER_CONTROL 0x00000008 /* Don't filter control frames */ +#define AR5K_RX_FILTER_BEACON 0x00000010 /* Don't filter beacon frames */ +#define AR5K_RX_FILTER_PROM 0x00000020 /* Set promiscuous mode */ +#define AR5K_RX_FILTER_XRPOLL 0x00000040 /* Don't filter XR poll frame [5212+] */ +#define AR5K_RX_FILTER_PROBEREQ 0x00000080 /* Don't filter probe requests [5212+] */ +#define AR5K_RX_FILTER_PHYERR_5212 0x00000100 /* Don't filter phy errors [5212+] */ +#define AR5K_RX_FILTER_RADARERR_5212 0x00000200 /* Don't filter phy radar errors [5212+] */ +#define AR5K_RX_FILTER_PHYERR_5211 0x00000040 /* [5211] */ +#define AR5K_RX_FILTER_RADARERR_5211 0x00000080 /* [5211] */ +#define AR5K_RX_FILTER_PHYERR \ + ((ah->ah_version == AR5K_AR5211 ? \ + AR5K_RX_FILTER_PHYERR_5211 : AR5K_RX_FILTER_PHYERR_5212)) +#define AR5K_RX_FILTER_RADARERR \ + ((ah->ah_version == AR5K_AR5211 ? \ + AR5K_RX_FILTER_RADARERR_5211 : AR5K_RX_FILTER_RADARERR_5212)) + +/* + * Multicast filter register (lower 32 bits) + */ +#define AR5K_MCAST_FILTER0_5210 0x8050 +#define AR5K_MCAST_FILTER0_5211 0x8040 +#define AR5K_MCAST_FILTER0 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_MCAST_FILTER0_5210 : AR5K_MCAST_FILTER0_5211) + +/* + * Multicast filter register (higher 16 bits) + */ +#define AR5K_MCAST_FILTER1_5210 0x8054 +#define AR5K_MCAST_FILTER1_5211 0x8044 +#define AR5K_MCAST_FILTER1 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_MCAST_FILTER1_5210 : AR5K_MCAST_FILTER1_5211) + + +/* + * Transmit mask register (lower 32 bits) [5210] + */ +#define AR5K_TX_MASK0 0x8058 + +/* + * Transmit mask register (higher 16 bits) [5210] + */ +#define AR5K_TX_MASK1 0x805c + +/* + * Clear transmit mask [5210] + */ +#define AR5K_CLR_TMASK 0x8060 + +/* + * Trigger level register (before transmission) [5210] + */ +#define AR5K_TRIG_LVL 0x8064 + + +/* + * PCU control register + * + * Only DIS_RX is used in the code, the rest i guess are + * for tweaking/diagnostics. + */ +#define AR5K_DIAG_SW_5210 0x8068 /* Register Address [5210] */ +#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_TX 0x00000020 /* Disable transmit [5210] */ +#define AR5K_DIAG_SW_DIS_RX_5210 0x00000040 /* Disable recieve */ +#define AR5K_DIAG_SW_DIS_RX_5211 0x00000020 +#define AR5K_DIAG_SW_DIS_RX (ah->ah_version == AR5K_AR5210 ? \ + AR5K_DIAG_SW_DIS_RX_5210 : AR5K_DIAG_SW_DIS_RX_5211) +#define AR5K_DIAG_SW_LOOP_BACK_5210 0x00000080 /* Loopback (i guess it goes with DIS_TX) [5210] */ +#define AR5K_DIAG_SW_LOOP_BACK_5211 0x00000040 +#define AR5K_DIAG_SW_LOOP_BACK (ah->ah_version == AR5K_AR5210 ? \ + AR5K_DIAG_SW_LOOP_BACK_5210 : AR5K_DIAG_SW_LOOP_BACK_5211) +#define AR5K_DIAG_SW_CORR_FCS_5210 0x00000100 +#define AR5K_DIAG_SW_CORR_FCS_5211 0x00000080 +#define AR5K_DIAG_SW_CORR_FCS (ah->ah_version == AR5K_AR5210 ? \ + AR5K_DIAG_SW_CORR_FCS_5210 : AR5K_DIAG_SW_CORR_FCS_5211) +#define AR5K_DIAG_SW_CHAN_INFO_5210 0x00000200 +#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_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_S 10 +#define AR5K_DIAG_SW_DIS_SEQ_INC 0x00040000 /* Disable seqnum increment (?)[5210] */ +#define AR5K_DIAG_SW_FRAME_NV0_5210 0x00080000 +#define AR5K_DIAG_SW_FRAME_NV0_5211 0x00020000 +#define AR5K_DIAG_SW_FRAME_NV0 (ah->ah_version == AR5K_AR5210 ? \ + 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 + +/* + * TSF (clock) register (lower 32 bits) + */ +#define AR5K_TSF_L32_5210 0x806c +#define AR5K_TSF_L32_5211 0x804c +#define AR5K_TSF_L32 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TSF_L32_5210 : AR5K_TSF_L32_5211) + +/* + * TSF (clock) register (higher 32 bits) + */ +#define AR5K_TSF_U32_5210 0x8070 +#define AR5K_TSF_U32_5211 0x8050 +#define AR5K_TSF_U32 (ah->ah_version == AR5K_AR5210 ? \ + AR5K_TSF_U32_5210 : AR5K_TSF_U32_5211) + +/* + * Last beacon timestamp register + */ +#define AR5K_LAST_TSTP 0x8080 + +/* + * ADDAC test register [5211+] + */ +#define AR5K_ADDAC_TEST 0x8054 +#define AR5K_ADDAC_TEST_TXCONT 0x00000001 + +/* + * Default antenna register [5211+] + */ +#define AR5K_DEFAULT_ANTENNA 0x8058 + + + +/* + * Retry count register [5210] + */ +#define AR5K_RETRY_CNT 0x8084 /* Register Address [5210] */ +#define AR5K_RETRY_CNT_SSH 0x0000003f /* Station short retry count (?) */ +#define AR5K_RETRY_CNT_SLG 0x00000fc0 /* Station long retry count (?) */ + +/* + * Back-off status register [5210] + */ +#define AR5K_BACKOFF 0x8088 /* Register Address [5210] */ +#define AR5K_BACKOFF_CW 0x000003ff /* Backoff Contention Window (?) */ +#define AR5K_BACKOFF_CNT 0x03ff0000 /* Backoff count (?) */ + + + +/* + * NAV register (current) + */ +#define AR5K_NAV_5210 0x808c +#define AR5K_NAV_5211 0x8084 +#define AR5K_NAV (ah->ah_version == AR5K_AR5210 ? \ + AR5K_NAV_5210 : AR5K_NAV_5211) + +/* + * RTS success register + */ +#define AR5K_RTS_OK_5210 0x8090 +#define AR5K_RTS_OK_5211 0x8088 +#define AR5K_RTS_OK (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RTS_OK_5210 : AR5K_RTS_OK_5211) + +/* + * RTS failure register + */ +#define AR5K_RTS_FAIL_5210 0x8094 +#define AR5K_RTS_FAIL_5211 0x808c +#define AR5K_RTS_FAIL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_RTS_FAIL_5210 : AR5K_RTS_FAIL_5211) + +/* + * ACK failure register + */ +#define AR5K_ACK_FAIL_5210 0x8098 +#define AR5K_ACK_FAIL_5211 0x8090 +#define AR5K_ACK_FAIL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_ACK_FAIL_5210 : AR5K_ACK_FAIL_5211) + +/* + * FCS failure register + */ +#define AR5K_FCS_FAIL_5210 0x809c +#define AR5K_FCS_FAIL_5211 0x8094 +#define AR5K_FCS_FAIL (ah->ah_version == AR5K_AR5210 ? \ + AR5K_FCS_FAIL_5210 : AR5K_FCS_FAIL_5211) + +/* + * Beacon count register + */ +#define AR5K_BEACON_CNT_5210 0x80a0 +#define AR5K_BEACON_CNT_5211 0x8098 +#define AR5K_BEACON_CNT (ah->ah_version == AR5K_AR5210 ? \ + AR5K_BEACON_CNT_5210 : AR5K_BEACON_CNT_5211) + + +/*===5212 Specific PCU registers===*/ + +/* + * XR (eXtended Range) mode register + */ +#define AR5K_XRMODE 0x80c0 +#define AR5K_XRMODE_POLL_TYPE_M 0x0000003f +#define AR5K_XRMODE_POLL_TYPE_S 0 +#define AR5K_XRMODE_POLL_SUBTYPE_M 0x0000003c +#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_FRAME_HOLD_S 20 + +/* + * XR delay register + */ +#define AR5K_XRDELAY 0x80c4 +#define AR5K_XRDELAY_SLOT_DELAY_M 0x0000ffff +#define AR5K_XRDELAY_SLOT_DELAY_S 0 +#define AR5K_XRDELAY_CHIRP_DELAY_M 0xffff0000 +#define AR5K_XRDELAY_CHIRP_DELAY_S 16 + +/* + * XR timeout register + */ +#define AR5K_XRTIMEOUT 0x80c8 +#define AR5K_XRTIMEOUT_CHIRP_M 0x0000ffff +#define AR5K_XRTIMEOUT_CHIRP_S 0 +#define AR5K_XRTIMEOUT_POLL_M 0xffff0000 +#define AR5K_XRTIMEOUT_POLL_S 16 + +/* + * XR chirp register + */ +#define AR5K_XRCHIRP 0x80cc +#define AR5K_XRCHIRP_SEND 0x00000001 +#define AR5K_XRCHIRP_GAP 0xffff0000 + +/* + * XR stomp register + */ +#define AR5K_XRSTOMP 0x80d0 +#define AR5K_XRSTOMP_TX 0x00000001 +#define AR5K_XRSTOMP_RX_ABORT 0x00000002 +#define AR5K_XRSTOMP_RSSI_THRES 0x0000ff00 + +/* + * First enhanced sleep register + */ +#define AR5K_SLEEP0 0x80d4 +#define AR5K_SLEEP0_NEXT_DTIM 0x0007ffff +#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_CABTO_S 24 + +/* + * Second enhanced sleep register + */ +#define AR5K_SLEEP1 0x80d8 +#define AR5K_SLEEP1_NEXT_TIM 0x0007ffff +#define AR5K_SLEEP1_NEXT_TIM_S 0 +#define AR5K_SLEEP1_BEACON_TO 0xff000000 +#define AR5K_SLEEP1_BEACON_TO_S 24 + +/* + * Third enhanced sleep register + */ +#define AR5K_SLEEP2 0x80dc +#define AR5K_SLEEP2_TIM_PER 0x0000ffff +#define AR5K_SLEEP2_TIM_PER_S 0 +#define AR5K_SLEEP2_DTIM_PER 0xffff0000 +#define AR5K_SLEEP2_DTIM_PER_S 16 + +/* + * BSSID mask registers + */ +#define AR5K_BSS_IDM0 0x80e0 +#define AR5K_BSS_IDM1 0x80e4 + +/* + * TX power control (TPC) register + */ +#define AR5K_TXPC 0x80e8 +#define AR5K_TXPC_ACK_M 0x0000003f +#define AR5K_TXPC_ACK_S 0 +#define AR5K_TXPC_CTS_M 0x00003f00 +#define AR5K_TXPC_CTS_S 8 +#define AR5K_TXPC_CHIRP_M 0x003f0000 +#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 + +/* + * TSF parameter register + */ +#define AR5K_TSF_PARM 0x8104 +#define AR5K_TSF_PARM_INC_M 0x000000ff +#define AR5K_TSF_PARM_INC_S 0 + +/* + * 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 + +/* + * Rate duration register + */ +#define AR5K_RATE_DUR_BASE 0x8700 +#define AR5K_RATE_DUR(_n) (AR5K_RATE_DUR_BASE + ((_n) << 2)) + +/*===5212 end===*/ + +/* + * Key table (WEP) register + */ +#define AR5K_KEYTABLE_0_5210 0x9000 +#define AR5K_KEYTABLE_0_5211 0x8800 +#define AR5K_KEYTABLE_5210(_n) (AR5K_KEYTABLE_0_5210 + ((_n) << 5)) +#define AR5K_KEYTABLE_5211(_n) (AR5K_KEYTABLE_0_5211 + ((_n) << 5)) +#define AR5K_KEYTABLE(_n) (ah->ah_version == AR5K_AR5210 ? \ + AR5K_KEYTABLE_5210(_n) : AR5K_KEYTABLE_5211(_n)) +#define AR5K_KEYTABLE_OFF(_n, x) (AR5K_KEYTABLE(_n) + (x << 2)) +#define AR5K_KEYTABLE_TYPE(_n) AR5K_KEYTABLE_OFF(_n, 5) +#define AR5K_KEYTABLE_TYPE_40 0x00000000 +#define AR5K_KEYTABLE_TYPE_104 0x00000001 +#define AR5K_KEYTABLE_TYPE_128 0x00000003 +#define AR5K_KEYTABLE_TYPE_TKIP 0x00000004 /* [5212+] */ +#define AR5K_KEYTABLE_TYPE_AES 0x00000005 /* [5211+] */ +#define AR5K_KEYTABLE_TYPE_CCM 0x00000006 /* [5212+] */ +#define AR5K_KEYTABLE_TYPE_NULL 0x00000007 /* [5211+] */ +#define AR5K_KEYTABLE_ANTENNA 0x00000008 /* [5212+] */ +#define AR5K_KEYTABLE_MAC0(_n) AR5K_KEYTABLE_OFF(_n, 6) +#define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) +#define AR5K_KEYTABLE_VALID 0x00008000 + +/* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit + * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit + * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit + * + * Some vendors have introduced bigger WEP keys to address + * security vulnerabilities in WEP. This includes: + * + * WEP 232-bit = 232-bit entered key + 24 bit IV = 256-bit + * + * We can expand this if we find ar5k Atheros cards with a larger + * key table size. + */ +#define AR5K_KEYTABLE_SIZE_5210 64 +#define AR5K_KEYTABLE_SIZE_5211 128 +#define AR5K_KEYTABLE_SIZE (ah->ah_version == AR5K_AR5210 ? \ + AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211) + + +/*===PHY REGISTERS===*/ + +/* + * PHY register + */ +#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 + +/* + * PHY frame control register [5110] /turbo mode register [5111+] + * + * There is another frame control register for [5111+] + * at address 0x9944 (see below) but the 2 first flags + * are common here between 5110 frame control register + * and [5111+] turbo mode register, so this also works as + * 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 + +/* + * PHY agility command register + */ +#define AR5K_PHY_AGC 0x9808 +#define AR5K_PHY_AGC_DISABLE 0x08000000 + +/* + * PHY timing register [5112+] + */ +#define AR5K_PHY_TIMING_3 0x9814 +#define AR5K_PHY_TIMING_3_DSC_MAN 0xfffe0000 +#define AR5K_PHY_TIMING_3_DSC_MAN_S 17 +#define AR5K_PHY_TIMING_3_DSC_EXP 0x0001e000 +#define AR5K_PHY_TIMING_3_DSC_EXP_S 13 + +/* + * PHY chip revision register + */ +#define AR5K_PHY_CHIP_ID 0x9818 + +/* + * PHY activation register + */ +#define AR5K_PHY_ACT 0x981c +#define AR5K_PHY_ACT_ENABLE 0x00000001 +#define AR5K_PHY_ACT_DISABLE 0x00000002 + +/* + * PHY signal register + */ +#define AR5K_PHY_SIG 0x9858 +#define AR5K_PHY_SIG_FIRSTEP 0x0003f000 +#define AR5K_PHY_SIG_FIRSTEP_S 12 +#define AR5K_PHY_SIG_FIRPWR 0x03fc0000 +#define AR5K_PHY_SIG_FIRPWR_S 18 + +/* + * PHY coarse agility control register + */ +#define AR5K_PHY_AGCCOARSE 0x985c +#define AR5K_PHY_AGCCOARSE_LO 0x00007f80 +#define AR5K_PHY_AGCCOARSE_LO_S 7 +#define AR5K_PHY_AGCCOARSE_HI 0x003f8000 +#define AR5K_PHY_AGCCOARSE_HI_S 15 + +/* + * PHY agility control register + */ +#define AR5K_PHY_AGCCTL 0x9860 /* Register address */ +#define AR5K_PHY_AGCCTL_CAL 0x00000001 /* Enable PHY calibration */ +#define AR5K_PHY_AGCCTL_NF 0x00000002 /* Enable Noise Floor calibration */ + +/* + * 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_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)) + +/* + * PHY ADC saturation register [5110] + */ +#define AR5K_PHY_ADCSAT 0x9868 +#define AR5K_PHY_ADCSAT_ICNT 0x0001f800 +#define AR5K_PHY_ADCSAT_ICNT_S 11 +#define AR5K_PHY_ADCSAT_THR 0x000007e0 +#define AR5K_PHY_ADCSAT_THR_S 5 + +/* + * PHY sleep registers [5112+] + */ +#define AR5K_PHY_SCR 0x9870 +#define AR5K_PHY_SCR_32MHZ 0x0000001f +#define AR5K_PHY_SLMT 0x9874 +#define AR5K_PHY_SLMT_32MHZ 0x0000007f +#define AR5K_PHY_SCAL 0x9878 +#define AR5K_PHY_SCAL_32MHZ 0x0000000e + +/* + * PHY PLL (Phase Locked Loop) control register + */ +#define AR5K_PHY_PLL 0x987c +#define AR5K_PHY_PLL_20MHZ 0x13 /* For half rate (?) [5111+] */ +#define AR5K_PHY_PLL_40MHZ_5211 0x18 /* For 802.11a */ +#define AR5K_PHY_PLL_40MHZ_5212 0x000000aa +#define AR5K_PHY_PLL_40MHZ (ah->ah_version == AR5K_AR5211 ? \ + AR5K_PHY_PLL_40MHZ_5211 : AR5K_PHY_PLL_40MHZ_5212) +#define AR5K_PHY_PLL_44MHZ_5211 0x19 /* For 802.11b/g */ +#define AR5K_PHY_PLL_44MHZ_5212 0x000000ab +#define AR5K_PHY_PLL_44MHZ (ah->ah_version == AR5K_AR5211 ? \ + AR5K_PHY_PLL_44MHZ_5211 : AR5K_PHY_PLL_44MHZ_5212) +#define AR5K_PHY_PLL_RF5111 0x00000000 +#define AR5K_PHY_PLL_RF5112 0x00000040 + +/* + * RF Buffer register + * + * There are some special control registers on the RF chip + * that hold various operation settings related mostly to + * the analog parts (channel, gain adjustment etc). + * + * We don't write on those registers directly but + * we send a data packet on the buffer register and + * then write on another special register to notify hw + * to apply the settings. This is done so that control registers + * can be dynamicaly programmed during operation and the settings + * are applied faster on the hw. + * + * We sent such data packets during rf initialization and channel change + * through ath5k_hw_rf*_rfregs and ath5k_hw_rf*_channel functions. + * + * The data packets we send during initializadion are inside ath5k_ini_rf + * struct (see ath5k_hw.h) and each one is related to an "rf register bank". + * We use *rfregs functions to modify them acording to current operation + * mode and eeprom values and pass them all together to the chip. + * + * It's obvious from the code that 0x989c is the buffer register but + * for the other special registers that we write to after sending each + * packet, i have no idea. So i'll name them BUFFER_CONTROL_X registers + * for now. It's interesting that they are also used for some other operations. + * + * Also check out hw.h and U.S. Patent 6677779 B1 (about buffer + * registers and control registers): + * + * http://www.google.com/patents?id=qNURAAAAEBAJ + */ + +#define AR5K_RF_BUFFER 0x989c +#define AR5K_RF_BUFFER_CONTROL_0 0x98c0 /* Channel on 5110 */ +#define AR5K_RF_BUFFER_CONTROL_1 0x98c4 /* Bank 7 on 5112 */ +#define AR5K_RF_BUFFER_CONTROL_2 0x98cc /* Bank 7 on 5111 */ + +#define AR5K_RF_BUFFER_CONTROL_3 0x98d0 /* Bank 2 on 5112 */ + /* Channel set on 5111 */ + /* Used to read radio revision*/ + +#define AR5K_RF_BUFFER_CONTROL_4 0x98d4 /* RF Stage register on 5110 */ + /* Bank 0,1,2,6 on 5111 */ + /* Bank 1 on 5112 */ + /* Used during activation on 5111 */ + +#define AR5K_RF_BUFFER_CONTROL_5 0x98d8 /* Bank 3 on 5111 */ + /* Used during activation on 5111 */ + /* Channel on 5112 */ + /* Bank 6 on 5112 */ + +#define AR5K_RF_BUFFER_CONTROL_6 0x98dc /* Bank 3 on 5112 */ + +/* + * PHY RF stage register [5210] + */ +#define AR5K_PHY_RFSTG 0x98d4 +#define AR5K_PHY_RFSTG_DISABLE 0x00000021 + +/* + * PHY receiver delay register [5111+] + */ +#define AR5K_PHY_RX_DELAY 0x9914 +#define AR5K_PHY_RX_DELAY_M 0x00003fff + +/* + * PHY timing I(nphase) Q(adrature) control register [5111+] + */ +#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_S 12 +#define AR5K_PHY_IQ_RUN 0x00010000 /* Run i/q calibration */ + + +/* + * PHY PAPD probe register [5111+ (?)] + * Is this only present in 5212 ? + * Because it's always 0 in 5211 initialization code + */ +#define AR5K_PHY_PAPD_PROBE 0x9930 +#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_TYPE 0x01800000 /* [5112+] */ +#define AR5K_PHY_PAPD_PROBE_TYPE_S 23 +#define AR5K_PHY_PAPD_PROBE_TYPE_OFDM 0 +#define AR5K_PHY_PAPD_PROBE_TYPE_XR 1 +#define AR5K_PHY_PAPD_PROBE_TYPE_CCK 2 +#define AR5K_PHY_PAPD_PROBE_GAINF 0xfe000000 +#define AR5K_PHY_PAPD_PROBE_GAINF_S 25 +#define AR5K_PHY_PAPD_PROBE_INI_5111 0x00004883 /* [5212+] */ +#define AR5K_PHY_PAPD_PROBE_INI_5112 0x00004882 /* [5212+] */ + + +/* + * PHY TX rate power registers [5112+] + */ +#define AR5K_PHY_TXPOWER_RATE1 0x9934 +#define AR5K_PHY_TXPOWER_RATE2 0x9938 +#define AR5K_PHY_TXPOWER_RATE_MAX 0x993c +#define AR5K_PHY_TXPOWER_RATE_MAX_TPC_ENABLE 0x00000040 +#define AR5K_PHY_TXPOWER_RATE3 0xa234 +#define AR5K_PHY_TXPOWER_RATE4 0xa238 + +/* + * PHY frame control register [5111+] + */ +#define AR5K_PHY_FRAME_CTL_5210 0x9804 +#define AR5K_PHY_FRAME_CTL_5211 0x9944 +#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_S 3 +/*---[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_SERVICE_ERR 0x20000000 +#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 | \ + AR5K_PHY_FRAME_CTL_ILLRATE_ERR | \ + AR5K_PHY_FRAME_CTL_PARITY_ERR | \ + AR5K_PHY_FRAME_CTL_TIMING_ERR + +/* + * PHY radar detection register [5111+] + */ +#define AR5K_PHY_RADAR 0x9954 + +/* Radar enable ........ ........ ........ .......1 */ +#define AR5K_PHY_RADAR_ENABLE 0x00000001 +#define AR5K_PHY_RADAR_DISABLE 0x00000000 +#define AR5K_PHY_RADAR_ENABLE_S 0 + +/* This is the value found on the card .1.111.1 .1.1.... 111....1 1...1... +at power on. */ +#define AR5K_PHY_RADAR_PWONDEF_AR5213 0x5d50e188 + +/* This is the value found on the card .1.1.111 ..11...1 .1...1.1 1...11.1 +after DFS is enabled */ +#define AR5K_PHY_RADAR_ENABLED_AR5213 0x5731458d + +/* Finite Impulse Response (FIR) filter .1111111 ........ ........ ........ + * power out threshold. + * 7-bits, standard power range {0..127} in 1/2 dBm units. */ +#define AR5K_PHY_RADAR_FIRPWROUTTHR 0x7f000000 +#define AR5K_PHY_RADAR_FIRPWROUTTHR_S 24 + +/* Radar RSSI/SNR threshold. ........ 111111.. ........ ........ + * 6-bits, dBm range {0..63} in dBm units. */ +#define AR5K_PHY_RADAR_RADARRSSITHR 0x00fc0000 +#define AR5K_PHY_RADAR_RADARRSSITHR_S 18 + +/* Pulse height threshold ........ ......11 1111.... ........ + * 6-bits, dBm range {0..63} in dBm units. */ +#define AR5K_PHY_RADAR_PULSEHEIGHTTHR 0x0003f000 +#define AR5K_PHY_RADAR_PULSEHEIGHTTHR_S 12 + +/* Pulse RSSI/SNR threshold ........ ........ ....1111 11...... + * 6-bits, dBm range {0..63} in dBm units. */ +#define AR5K_PHY_RADAR_PULSERSSITHR 0x00000fc0 +#define AR5K_PHY_RADAR_PULSERSSITHR_S 6 + +/* Inband threshold ........ ........ ........ ..11111. + * 5-bits, units unknown {0..31} (? MHz ?) */ +#define AR5K_PHY_RADAR_INBANDTHR 0x0000003e +#define AR5K_PHY_RADAR_INBANDTHR_S 1 + +/* + * PHY antenna switch table registers [5110] + */ +#define AR5K_PHY_ANT_SWITCH_TABLE_0 0x9960 +#define AR5K_PHY_ANT_SWITCH_TABLE_1 0x9964 + +/* + * PHY clock sleep registers [5112+] + */ +#define AR5K_PHY_SCLOCK 0x99f0 +#define AR5K_PHY_SCLOCK_32MHZ 0x0000000c +#define AR5K_PHY_SDELAY 0x99f4 +#define AR5K_PHY_SDELAY_32MHZ 0x000000ff +#define AR5K_PHY_SPENDING 0x99f8 +#define AR5K_PHY_SPENDING_RF5111 0x00000018 +#define AR5K_PHY_SPENDING_RF5112 0x00000014 + +/* + * Misc PHY/radio registers [5110 - 5111] + */ +#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(_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_CORR 0x9c18 /* I/Q Correlation */ + +/* + * PHY current RSSI register [5111+] + */ +#define AR5K_PHY_CURRENT_RSSI 0x9c1c + +/* + * 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 :\ + 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_MOD_OFDM 0 +#define AR5K_PHY_MODE_MOD_CCK 1 +#define AR5K_PHY_MODE_FREQ 0x00000002 /* Freq mode mask */ +#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_RAD 0x00000008 /* [5212+] */ +#define AR5K_PHY_MODE_RAD_RF5111 0 +#define AR5K_PHY_MODE_RAD_RF5112 8 +#define AR5K_PHY_MODE_XR 0x00000010 /* [5112+] */ + +/* + * PHY CCK transmit control register [5111+ (?)] + */ +#define AR5K_PHY_CCKTXCTL 0xa204 +#define AR5K_PHY_CCKTXCTL_WORLD 0x00000000 +#define AR5K_PHY_CCKTXCTL_JAPAN 0x00000010 + +/* + * PHY 2GHz gain register [5111+] + */ +#define AR5K_PHY_GAIN_2GHZ 0xa20c +#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX 0x00fc0000 +#define AR5K_PHY_GAIN_2GHZ_MARGIN_TXRX_S 18 +#define AR5K_PHY_GAIN_2GHZ_INI_5111 0x6480416c diff --git a/drivers/net/wireless/ath5k/regdom.c b/drivers/net/wireless/ath5k/regdom.c new file mode 100644 index 000000000000..e851957dacfd --- /dev/null +++ b/drivers/net/wireless/ath5k/regdom.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Basic regulation domain extensions for the IEEE 802.11 stack + */ + +#include <linux/kernel.h> +#include <linux/string.h> + +#include "regdom.h" + +static const struct ath5k_regdommap { + enum ath5k_regdom dmn; + enum ath5k_regdom dmn5; + enum ath5k_regdom dmn2; +} r_map[] = { + { DMN_DEFAULT, DMN_DEBUG, DMN_DEBUG }, + { DMN_NULL_WORLD, DMN_NULL, DMN_WORLD }, + { DMN_NULL_ETSIB, DMN_NULL, DMN_ETSIB }, + { DMN_NULL_ETSIC, DMN_NULL, DMN_ETSIC }, + { DMN_FCC1_FCCA, DMN_FCC1, DMN_FCCA }, + { DMN_FCC1_WORLD, DMN_FCC1, DMN_WORLD }, + { DMN_FCC2_FCCA, DMN_FCC2, DMN_FCCA }, + { DMN_FCC2_WORLD, DMN_FCC2, DMN_WORLD }, + { DMN_FCC2_ETSIC, DMN_FCC2, DMN_ETSIC }, + { DMN_FRANCE_NULL, DMN_ETSI3, DMN_ETSI3 }, + { DMN_FCC3_FCCA, DMN_FCC3, DMN_WORLD }, + { DMN_ETSI1_WORLD, DMN_ETSI1, DMN_WORLD }, + { DMN_ETSI3_ETSIA, DMN_ETSI3, DMN_WORLD }, + { DMN_ETSI2_WORLD, DMN_ETSI2, DMN_WORLD }, + { DMN_ETSI3_WORLD, DMN_ETSI3, DMN_WORLD }, + { DMN_ETSI4_WORLD, DMN_ETSI4, DMN_WORLD }, + { DMN_ETSI4_ETSIC, DMN_ETSI4, DMN_ETSIC }, + { DMN_ETSI5_WORLD, DMN_ETSI5, DMN_WORLD }, + { DMN_ETSI6_WORLD, DMN_ETSI6, DMN_WORLD }, + { DMN_ETSI_NULL, DMN_ETSI1, DMN_ETSI1 }, + { DMN_MKK1_MKKA, DMN_MKK1, DMN_MKKA }, + { DMN_MKK1_MKKB, DMN_MKK1, DMN_MKKA }, + { DMN_APL4_WORLD, DMN_APL4, DMN_WORLD }, + { DMN_MKK2_MKKA, DMN_MKK2, DMN_MKKA }, + { DMN_APL_NULL, DMN_APL1, DMN_NULL }, + { DMN_APL2_WORLD, DMN_APL2, DMN_WORLD }, + { DMN_APL2_APLC, DMN_APL2, DMN_WORLD }, + { DMN_APL3_WORLD, DMN_APL3, DMN_WORLD }, + { DMN_MKK1_FCCA, DMN_MKK1, DMN_FCCA }, + { DMN_APL2_APLD, DMN_APL2, DMN_APLD }, + { DMN_MKK1_MKKA1, DMN_MKK1, DMN_MKKA }, + { DMN_MKK1_MKKA2, DMN_MKK1, DMN_MKKA }, + { DMN_APL1_WORLD, DMN_APL1, DMN_WORLD }, + { DMN_APL1_FCCA, DMN_APL1, DMN_FCCA }, + { DMN_APL1_APLA, DMN_APL1, DMN_WORLD }, + { DMN_APL1_ETSIC, DMN_APL1, DMN_ETSIC }, + { DMN_APL2_ETSIC, DMN_APL2, DMN_ETSIC }, + { DMN_APL5_WORLD, DMN_APL5, DMN_WORLD }, + { DMN_WOR0_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WOR1_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WOR2_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WOR3_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WOR4_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WOR5_ETSIC, DMN_WORLD, DMN_WORLD }, + { DMN_WOR01_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WOR02_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_EU1_WORLD, DMN_ETSI1, DMN_WORLD }, + { DMN_WOR9_WORLD, DMN_WORLD, DMN_WORLD }, + { DMN_WORA_WORLD, DMN_WORLD, DMN_WORLD }, +}; + +enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom dmn, u16 mhz) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(r_map); i++) { + if (r_map[i].dmn == dmn) { + if (mhz >= 2000 && mhz <= 3000) + return r_map[i].dmn2; + if (mhz >= IEEE80211_CHANNELS_5GHZ_MIN && + mhz <= IEEE80211_CHANNELS_5GHZ_MAX) + return r_map[i].dmn5; + } + } + + return DMN_DEBUG; +} + +u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee) +{ + u32 regdomain = (u32)ieee; + + /* + * Use the default regulation domain if the value is empty + * or not supported by the net80211 regulation code. + */ + if (ath5k_regdom2flag(regdomain, IEEE80211_CHANNELS_5GHZ_MIN) == + DMN_DEBUG) + return (u16)AR5K_TUNE_REGDOMAIN; + + /* It is supported, just return the value */ + return regdomain; +} + +enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain) +{ + enum ath5k_regdom ieee = (enum ath5k_regdom)regdomain; + + return ieee; +} + diff --git a/drivers/net/wireless/ath5k/regdom.h b/drivers/net/wireless/ath5k/regdom.h new file mode 100644 index 000000000000..f7d3c66e594e --- /dev/null +++ b/drivers/net/wireless/ath5k/regdom.h @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IEEE80211_REGDOMAIN_H_ +#define _IEEE80211_REGDOMAIN_H_ + +#include <linux/types.h> + +/* Default regulation domain if stored value EEPROM value is invalid */ +#define AR5K_TUNE_REGDOMAIN DMN_FCC2_FCCA /* Canada */ +#define AR5K_TUNE_CTRY CTRY_DEFAULT + + +enum ath5k_regdom { + DMN_DEFAULT = 0x00, + DMN_NULL_WORLD = 0x03, + DMN_NULL_ETSIB = 0x07, + DMN_NULL_ETSIC = 0x08, + DMN_FCC1_FCCA = 0x10, + DMN_FCC1_WORLD = 0x11, + DMN_FCC2_FCCA = 0x20, + DMN_FCC2_WORLD = 0x21, + DMN_FCC2_ETSIC = 0x22, + DMN_FRANCE_NULL = 0x31, + DMN_FCC3_FCCA = 0x3A, + DMN_ETSI1_WORLD = 0x37, + DMN_ETSI3_ETSIA = 0x32, + DMN_ETSI2_WORLD = 0x35, + DMN_ETSI3_WORLD = 0x36, + DMN_ETSI4_WORLD = 0x30, + DMN_ETSI4_ETSIC = 0x38, + DMN_ETSI5_WORLD = 0x39, + DMN_ETSI6_WORLD = 0x34, + DMN_ETSI_NULL = 0x33, + DMN_MKK1_MKKA = 0x40, + DMN_MKK1_MKKB = 0x41, + DMN_APL4_WORLD = 0x42, + DMN_MKK2_MKKA = 0x43, + DMN_APL_NULL = 0x44, + DMN_APL2_WORLD = 0x45, + DMN_APL2_APLC = 0x46, + DMN_APL3_WORLD = 0x47, + DMN_MKK1_FCCA = 0x48, + DMN_APL2_APLD = 0x49, + DMN_MKK1_MKKA1 = 0x4A, + DMN_MKK1_MKKA2 = 0x4B, + DMN_APL1_WORLD = 0x52, + DMN_APL1_FCCA = 0x53, + DMN_APL1_APLA = 0x54, + DMN_APL1_ETSIC = 0x55, + DMN_APL2_ETSIC = 0x56, + DMN_APL5_WORLD = 0x58, + DMN_WOR0_WORLD = 0x60, + DMN_WOR1_WORLD = 0x61, + DMN_WOR2_WORLD = 0x62, + DMN_WOR3_WORLD = 0x63, + DMN_WOR4_WORLD = 0x64, + DMN_WOR5_ETSIC = 0x65, + DMN_WOR01_WORLD = 0x66, + DMN_WOR02_WORLD = 0x67, + DMN_EU1_WORLD = 0x68, + DMN_WOR9_WORLD = 0x69, + DMN_WORA_WORLD = 0x6A, + + DMN_APL1 = 0xf0000001, + DMN_APL2 = 0xf0000002, + DMN_APL3 = 0xf0000004, + DMN_APL4 = 0xf0000008, + DMN_APL5 = 0xf0000010, + DMN_ETSI1 = 0xf0000020, + DMN_ETSI2 = 0xf0000040, + DMN_ETSI3 = 0xf0000080, + DMN_ETSI4 = 0xf0000100, + DMN_ETSI5 = 0xf0000200, + DMN_ETSI6 = 0xf0000400, + DMN_ETSIA = 0xf0000800, + DMN_ETSIB = 0xf0001000, + DMN_ETSIC = 0xf0002000, + DMN_FCC1 = 0xf0004000, + DMN_FCC2 = 0xf0008000, + DMN_FCC3 = 0xf0010000, + DMN_FCCA = 0xf0020000, + DMN_APLD = 0xf0040000, + DMN_MKK1 = 0xf0080000, + DMN_MKK2 = 0xf0100000, + DMN_MKKA = 0xf0200000, + DMN_NULL = 0xf0400000, + DMN_WORLD = 0xf0800000, + DMN_DEBUG = 0xf1000000 /* used for debugging */ +}; + +#define IEEE80211_DMN(_d) ((_d) & ~0xf0000000) + +enum ath5k_countrycode { + CTRY_DEFAULT = 0, /* Default domain (NA) */ + CTRY_ALBANIA = 8, /* Albania */ + CTRY_ALGERIA = 12, /* Algeria */ + CTRY_ARGENTINA = 32, /* Argentina */ + CTRY_ARMENIA = 51, /* Armenia */ + CTRY_AUSTRALIA = 36, /* Australia */ + CTRY_AUSTRIA = 40, /* Austria */ + CTRY_AZERBAIJAN = 31, /* Azerbaijan */ + CTRY_BAHRAIN = 48, /* Bahrain */ + CTRY_BELARUS = 112, /* Belarus */ + CTRY_BELGIUM = 56, /* Belgium */ + CTRY_BELIZE = 84, /* Belize */ + CTRY_BOLIVIA = 68, /* Bolivia */ + CTRY_BRAZIL = 76, /* Brazil */ + CTRY_BRUNEI_DARUSSALAM = 96, /* Brunei Darussalam */ + CTRY_BULGARIA = 100, /* Bulgaria */ + CTRY_CANADA = 124, /* Canada */ + CTRY_CHILE = 152, /* Chile */ + CTRY_CHINA = 156, /* People's Republic of China */ + CTRY_COLOMBIA = 170, /* Colombia */ + CTRY_COSTA_RICA = 188, /* Costa Rica */ + CTRY_CROATIA = 191, /* Croatia */ + CTRY_CYPRUS = 196, /* Cyprus */ + CTRY_CZECH = 203, /* Czech Republic */ + CTRY_DENMARK = 208, /* Denmark */ + CTRY_DOMINICAN_REPUBLIC = 214, /* Dominican Republic */ + CTRY_ECUADOR = 218, /* Ecuador */ + CTRY_EGYPT = 818, /* Egypt */ + CTRY_EL_SALVADOR = 222, /* El Salvador */ + CTRY_ESTONIA = 233, /* Estonia */ + CTRY_FAEROE_ISLANDS = 234, /* Faeroe Islands */ + CTRY_FINLAND = 246, /* Finland */ + CTRY_FRANCE = 250, /* France */ + CTRY_FRANCE2 = 255, /* France2 */ + CTRY_GEORGIA = 268, /* Georgia */ + CTRY_GERMANY = 276, /* Germany */ + CTRY_GREECE = 300, /* Greece */ + CTRY_GUATEMALA = 320, /* Guatemala */ + CTRY_HONDURAS = 340, /* Honduras */ + CTRY_HONG_KONG = 344, /* Hong Kong S.A.R., P.R.C. */ + CTRY_HUNGARY = 348, /* Hungary */ + CTRY_ICELAND = 352, /* Iceland */ + CTRY_INDIA = 356, /* India */ + CTRY_INDONESIA = 360, /* Indonesia */ + CTRY_IRAN = 364, /* Iran */ + CTRY_IRAQ = 368, /* Iraq */ + CTRY_IRELAND = 372, /* Ireland */ + CTRY_ISRAEL = 376, /* Israel */ + CTRY_ITALY = 380, /* Italy */ + CTRY_JAMAICA = 388, /* Jamaica */ + CTRY_JAPAN = 392, /* Japan */ + CTRY_JAPAN1 = 393, /* Japan (JP1) */ + CTRY_JAPAN2 = 394, /* Japan (JP0) */ + CTRY_JAPAN3 = 395, /* Japan (JP1-1) */ + CTRY_JAPAN4 = 396, /* Japan (JE1) */ + CTRY_JAPAN5 = 397, /* Japan (JE2) */ + CTRY_JORDAN = 400, /* Jordan */ + CTRY_KAZAKHSTAN = 398, /* Kazakhstan */ + CTRY_KENYA = 404, /* Kenya */ + CTRY_KOREA_NORTH = 408, /* North Korea */ + CTRY_KOREA_ROC = 410, /* South Korea */ + CTRY_KOREA_ROC2 = 411, /* South Korea */ + CTRY_KUWAIT = 414, /* Kuwait */ + CTRY_LATVIA = 428, /* Latvia */ + CTRY_LEBANON = 422, /* Lebanon */ + CTRY_LIBYA = 434, /* Libya */ + CTRY_LIECHTENSTEIN = 438, /* Liechtenstein */ + CTRY_LITHUANIA = 440, /* Lithuania */ + CTRY_LUXEMBOURG = 442, /* Luxembourg */ + CTRY_MACAU = 446, /* Macau */ + CTRY_MACEDONIA = 807, /* Republic of Macedonia */ + CTRY_MALAYSIA = 458, /* Malaysia */ + CTRY_MEXICO = 484, /* Mexico */ + CTRY_MONACO = 492, /* Principality of Monaco */ + CTRY_MOROCCO = 504, /* Morocco */ + CTRY_NETHERLANDS = 528, /* Netherlands */ + CTRY_NEW_ZEALAND = 554, /* New Zealand */ + CTRY_NICARAGUA = 558, /* Nicaragua */ + CTRY_NORWAY = 578, /* Norway */ + CTRY_OMAN = 512, /* Oman */ + CTRY_PAKISTAN = 586, /* Islamic Republic of Pakistan */ + CTRY_PANAMA = 591, /* Panama */ + CTRY_PARAGUAY = 600, /* Paraguay */ + CTRY_PERU = 604, /* Peru */ + CTRY_PHILIPPINES = 608, /* Republic of the Philippines */ + CTRY_POLAND = 616, /* Poland */ + CTRY_PORTUGAL = 620, /* Portugal */ + CTRY_PUERTO_RICO = 630, /* Puerto Rico */ + CTRY_QATAR = 634, /* Qatar */ + CTRY_ROMANIA = 642, /* Romania */ + CTRY_RUSSIA = 643, /* Russia */ + CTRY_SAUDI_ARABIA = 682, /* Saudi Arabia */ + CTRY_SINGAPORE = 702, /* Singapore */ + CTRY_SLOVAKIA = 703, /* Slovak Republic */ + CTRY_SLOVENIA = 705, /* Slovenia */ + CTRY_SOUTH_AFRICA = 710, /* South Africa */ + CTRY_SPAIN = 724, /* Spain */ + CTRY_SRI_LANKA = 728, /* Sri Lanka */ + CTRY_SWEDEN = 752, /* Sweden */ + CTRY_SWITZERLAND = 756, /* Switzerland */ + CTRY_SYRIA = 760, /* Syria */ + CTRY_TAIWAN = 158, /* Taiwan */ + CTRY_THAILAND = 764, /* Thailand */ + CTRY_TRINIDAD_Y_TOBAGO = 780, /* Trinidad y Tobago */ + CTRY_TUNISIA = 788, /* Tunisia */ + CTRY_TURKEY = 792, /* Turkey */ + CTRY_UAE = 784, /* U.A.E. */ + CTRY_UKRAINE = 804, /* Ukraine */ + CTRY_UNITED_KINGDOM = 826, /* United Kingdom */ + CTRY_UNITED_STATES = 840, /* United States */ + CTRY_URUGUAY = 858, /* Uruguay */ + CTRY_UZBEKISTAN = 860, /* Uzbekistan */ + CTRY_VENEZUELA = 862, /* Venezuela */ + CTRY_VIET_NAM = 704, /* Viet Nam */ + CTRY_YEMEN = 887, /* Yemen */ + CTRY_ZIMBABWE = 716, /* Zimbabwe */ +}; + +#define IEEE80211_CHANNELS_2GHZ_MIN 2412 /* 2GHz channel 1 */ +#define IEEE80211_CHANNELS_2GHZ_MAX 2732 /* 2GHz channel 26 */ +#define IEEE80211_CHANNELS_5GHZ_MIN 5005 /* 5GHz channel 1 */ +#define IEEE80211_CHANNELS_5GHZ_MAX 6100 /* 5GHz channel 220 */ + +struct ath5k_regchannel { + u16 chan; + enum ath5k_regdom domain; + u32 mode; +}; + +#define IEEE80211_CHANNELS_2GHZ { \ +/*2412*/ { 1, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2417*/ { 2, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2422*/ { 3, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2427*/ { 4, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2432*/ { 5, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2437*/ { 6, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2442*/ { 7, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2447*/ { 8, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2452*/ { 9, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2457*/ { 10, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2462*/ { 11, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2467*/ { 12, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2472*/ { 13, DMN_APLD, CHANNEL_CCK|CHANNEL_OFDM }, \ + \ +/*2432*/ { 5, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2437*/ { 6, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*2442*/ { 7, DMN_ETSIB, CHANNEL_CCK|CHANNEL_OFDM }, \ + \ +/*2412*/ { 1, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2417*/ { 2, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2422*/ { 3, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2427*/ { 4, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2432*/ { 5, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2437*/ { 6, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*2442*/ { 7, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2447*/ { 8, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2452*/ { 9, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2457*/ { 10, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2462*/ { 11, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2467*/ { 12, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2472*/ { 13, DMN_ETSIC, CHANNEL_CCK|CHANNEL_OFDM }, \ + \ +/*2412*/ { 1, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2417*/ { 2, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2422*/ { 3, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2427*/ { 4, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2432*/ { 5, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2437*/ { 6, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*2442*/ { 7, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2447*/ { 8, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2452*/ { 9, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2457*/ { 10, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2462*/ { 11, DMN_FCCA, CHANNEL_CCK|CHANNEL_OFDM }, \ + \ +/*2412*/ { 1, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2417*/ { 2, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2422*/ { 3, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2427*/ { 4, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2432*/ { 5, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2437*/ { 6, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2442*/ { 7, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2447*/ { 8, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2452*/ { 9, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2457*/ { 10, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2462*/ { 11, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2467*/ { 12, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2472*/ { 13, DMN_MKKA, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2484*/ { 14, DMN_MKKA, CHANNEL_CCK }, \ + \ +/*2412*/ { 1, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2417*/ { 2, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2422*/ { 3, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2427*/ { 4, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2432*/ { 5, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2437*/ { 6, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*2442*/ { 7, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2447*/ { 8, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2452*/ { 9, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2457*/ { 10, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2462*/ { 11, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2467*/ { 12, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +/*2472*/ { 13, DMN_WORLD, CHANNEL_CCK|CHANNEL_OFDM }, \ +} + +#define IEEE80211_CHANNELS_5GHZ { \ +/*5745*/ { 149, DMN_APL1, CHANNEL_OFDM }, \ +/*5765*/ { 153, DMN_APL1, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_APL1, CHANNEL_OFDM }, \ +/*5805*/ { 161, DMN_APL1, CHANNEL_OFDM }, \ +/*5825*/ { 165, DMN_APL1, CHANNEL_OFDM }, \ + \ +/*5745*/ { 149, DMN_APL2, CHANNEL_OFDM }, \ +/*5765*/ { 153, DMN_APL2, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_APL2, CHANNEL_OFDM }, \ +/*5805*/ { 161, DMN_APL2, CHANNEL_OFDM }, \ + \ +/*5280*/ { 56, DMN_APL3, CHANNEL_OFDM }, \ +/*5300*/ { 60, DMN_APL3, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_APL3, CHANNEL_OFDM }, \ +/*5745*/ { 149, DMN_APL3, CHANNEL_OFDM }, \ +/*5765*/ { 153, DMN_APL3, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_APL3, CHANNEL_OFDM }, \ +/*5805*/ { 161, DMN_APL3, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_APL4, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_APL4, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_APL4, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_APL4, CHANNEL_OFDM }, \ +/*5745*/ { 149, DMN_APL4, CHANNEL_OFDM }, \ +/*5765*/ { 153, DMN_APL4, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_APL4, CHANNEL_OFDM }, \ +/*5805*/ { 161, DMN_APL4, CHANNEL_OFDM }, \ +/*5825*/ { 165, DMN_APL4, CHANNEL_OFDM }, \ + \ +/*5745*/ { 149, DMN_APL5, CHANNEL_OFDM }, \ +/*5765*/ { 153, DMN_APL5, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_APL5, CHANNEL_OFDM }, \ +/*5805*/ { 161, DMN_APL5, CHANNEL_OFDM }, \ +/*5825*/ { 165, DMN_APL5, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5260*/ { 52, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5300*/ { 60, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5500*/ { 100, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5520*/ { 104, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5540*/ { 108, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5560*/ { 112, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5580*/ { 116, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5600*/ { 120, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5620*/ { 124, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5640*/ { 128, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5660*/ { 132, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5680*/ { 136, DMN_ETSI1, CHANNEL_OFDM }, \ +/*5700*/ { 140, DMN_ETSI1, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_ETSI2, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_ETSI2, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_ETSI2, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_ETSI2, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5260*/ { 52, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5300*/ { 60, DMN_ETSI3, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_ETSI3, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5260*/ { 52, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5300*/ { 60, DMN_ETSI4, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_ETSI4, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_ETSI5, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_ETSI5, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_ETSI5, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_ETSI5, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5260*/ { 52, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5500*/ { 100, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5520*/ { 104, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5540*/ { 108, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5560*/ { 112, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5580*/ { 116, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5600*/ { 120, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5620*/ { 124, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5640*/ { 128, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5660*/ { 132, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5680*/ { 136, DMN_ETSI6, CHANNEL_OFDM }, \ +/*5700*/ { 140, DMN_ETSI6, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_FCC1, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_FCC1, CHANNEL_OFDM }, \ +/*5210*/ { 42, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5220*/ { 44, DMN_FCC1, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_FCC1, CHANNEL_OFDM }, \ +/*5250*/ { 50, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5260*/ { 52, DMN_FCC1, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_FCC1, CHANNEL_OFDM }, \ +/*5290*/ { 58, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5300*/ { 60, DMN_FCC1, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_FCC1, CHANNEL_OFDM }, \ +/*5745*/ { 149, DMN_FCC1, CHANNEL_OFDM }, \ +/*5760*/ { 152, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5765*/ { 153, DMN_FCC1, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_FCC1, CHANNEL_OFDM }, \ +/*5800*/ { 160, DMN_FCC1, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5805*/ { 161, DMN_FCC1, CHANNEL_OFDM }, \ +/*5825*/ { 165, DMN_FCC1, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_FCC2, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_FCC2, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_FCC2, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_FCC2, CHANNEL_OFDM }, \ +/*5260*/ { 52, DMN_FCC2, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_FCC2, CHANNEL_OFDM }, \ +/*5300*/ { 60, DMN_FCC2, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_FCC2, CHANNEL_OFDM }, \ +/*5745*/ { 149, DMN_FCC2, CHANNEL_OFDM }, \ +/*5765*/ { 153, DMN_FCC2, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_FCC2, CHANNEL_OFDM }, \ +/*5805*/ { 161, DMN_FCC2, CHANNEL_OFDM }, \ +/*5825*/ { 165, DMN_FCC2, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_FCC3, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_FCC3, CHANNEL_OFDM }, \ +/*5210*/ { 42, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5220*/ { 44, DMN_FCC3, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_FCC3, CHANNEL_OFDM }, \ +/*5250*/ { 50, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5260*/ { 52, DMN_FCC3, CHANNEL_OFDM }, \ +/*5280*/ { 56, DMN_FCC3, CHANNEL_OFDM }, \ +/*5290*/ { 58, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5300*/ { 60, DMN_FCC3, CHANNEL_OFDM }, \ +/*5320*/ { 64, DMN_FCC3, CHANNEL_OFDM }, \ +/*5500*/ { 100, DMN_FCC3, CHANNEL_OFDM }, \ +/*5520*/ { 104, DMN_FCC3, CHANNEL_OFDM }, \ +/*5540*/ { 108, DMN_FCC3, CHANNEL_OFDM }, \ +/*5560*/ { 112, DMN_FCC3, CHANNEL_OFDM }, \ +/*5580*/ { 116, DMN_FCC3, CHANNEL_OFDM }, \ +/*5600*/ { 120, DMN_FCC3, CHANNEL_OFDM }, \ +/*5620*/ { 124, DMN_FCC3, CHANNEL_OFDM }, \ +/*5640*/ { 128, DMN_FCC3, CHANNEL_OFDM }, \ +/*5660*/ { 132, DMN_FCC3, CHANNEL_OFDM }, \ +/*5680*/ { 136, DMN_FCC3, CHANNEL_OFDM }, \ +/*5700*/ { 140, DMN_FCC3, CHANNEL_OFDM }, \ +/*5745*/ { 149, DMN_FCC3, CHANNEL_OFDM }, \ +/*5760*/ { 152, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5765*/ { 153, DMN_FCC3, CHANNEL_OFDM }, \ +/*5785*/ { 157, DMN_FCC3, CHANNEL_OFDM }, \ +/*5800*/ { 160, DMN_FCC3, CHANNEL_OFDM|CHANNEL_TURBO }, \ +/*5805*/ { 161, DMN_FCC3, CHANNEL_OFDM }, \ +/*5825*/ { 165, DMN_FCC3, CHANNEL_OFDM }, \ + \ +/*5170*/ { 34, DMN_MKK1, CHANNEL_OFDM }, \ +/*5190*/ { 38, DMN_MKK1, CHANNEL_OFDM }, \ +/*5210*/ { 42, DMN_MKK1, CHANNEL_OFDM }, \ +/*5230*/ { 46, DMN_MKK1, CHANNEL_OFDM }, \ + \ +/*5040*/ { 8, DMN_MKK2, CHANNEL_OFDM }, \ +/*5060*/ { 12, DMN_MKK2, CHANNEL_OFDM }, \ +/*5080*/ { 16, DMN_MKK2, CHANNEL_OFDM }, \ +/*5170*/ { 34, DMN_MKK2, CHANNEL_OFDM }, \ +/*5190*/ { 38, DMN_MKK2, CHANNEL_OFDM }, \ +/*5210*/ { 42, DMN_MKK2, CHANNEL_OFDM }, \ +/*5230*/ { 46, DMN_MKK2, CHANNEL_OFDM }, \ + \ +/*5180*/ { 36, DMN_WORLD, CHANNEL_OFDM }, \ +/*5200*/ { 40, DMN_WORLD, CHANNEL_OFDM }, \ +/*5220*/ { 44, DMN_WORLD, CHANNEL_OFDM }, \ +/*5240*/ { 48, DMN_WORLD, CHANNEL_OFDM }, \ +} + +enum ath5k_regdom ath5k_regdom2flag(enum ath5k_regdom, u16); +u16 ath5k_regdom_from_ieee(enum ath5k_regdom ieee); +enum ath5k_regdom ath5k_regdom_to_ieee(u16 regdomain); + +#endif diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 059ce3f07dba..63ec7a70ee76 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -1759,9 +1759,8 @@ static int atmel_set_encode(struct net_device *dev, priv->default_key = index; } else /* Don't complain if only change the mode */ - if (!dwrq->flags & IW_ENCODE_MODE) { + if (!(dwrq->flags & IW_ENCODE_MODE)) return -EINVAL; - } } /* Read the flags */ if (dwrq->flags & IW_ENCODE_DISABLED) { @@ -2676,9 +2675,9 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } struct auth_body { - u16 alg; - u16 trans_seq; - u16 status; + __le16 alg; + __le16 trans_seq; + __le16 status; u8 el_id; u8 chall_text_len; u8 chall_text[253]; @@ -2713,9 +2712,9 @@ static void atmel_scan(struct atmel_private *priv, int specific_ssid) u8 SSID[MAX_SSID_LENGTH]; u8 scan_type; u8 channel; - u16 BSS_type; - u16 min_channel_time; - u16 max_channel_time; + __le16 BSS_type; + __le16 min_channel_time; + __le16 max_channel_time; u8 options; u8 SSID_size; } cmd; @@ -2758,7 +2757,7 @@ static void join(struct atmel_private *priv, int type) u8 SSID[MAX_SSID_LENGTH]; u8 BSS_type; /* this is a short in a scan command - weird */ u8 channel; - u16 timeout; + __le16 timeout; u8 SSID_size; u8 reserved; } cmd; @@ -2863,8 +2862,8 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) int bodysize; struct ieee80211_hdr_4addr header; struct ass_req_format { - u16 capability; - u16 listen_interval; + __le16 capability; + __le16 listen_interval; u8 ap[6]; /* nothing after here directly accessible */ u8 ssid_el_id; u8 ssid_len; @@ -3085,9 +3084,9 @@ static void authenticate(struct atmel_private *priv, u16 frame_len) static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) { struct ass_resp_format { - u16 capability; - u16 status; - u16 ass_id; + __le16 capability; + __le16 status; + __le16 ass_id; u8 el_id; u8 length; u8 rates[4]; @@ -3294,9 +3293,9 @@ static void atmel_management_frame(struct atmel_private *priv, never let an engineer loose with a data structure design. */ { struct beacon_format { - u64 timestamp; - u16 interval; - u16 capability; + __le64 timestamp; + __le16 interval; + __le16 capability; u8 ssid_el_id; u8 ssid_length; /* ssid here */ diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index fdbc351ac333..1a2141dabdc7 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -61,6 +61,16 @@ config B43_PCMCIA If unsure, say N. +config B43_NPHY + bool "Pre IEEE 802.11n support (BROKEN)" + depends on B43 && EXPERIMENTAL && BROKEN + ---help--- + Support for the IEEE 802.11n draft. + + THIS IS BROKEN AND DOES NOT WORK YET. + + SAY N. + # This config option automatically enables b43 LEDS support, # if it's possible. config B43_LEDS @@ -83,51 +93,3 @@ config B43_DEBUG Say Y, if you want to find out why the driver does not work for you. - -config B43_DMA - bool - depends on B43 -config B43_PIO - bool - depends on B43 - -choice - prompt "Broadcom 43xx data transfer mode" - depends on B43 - default B43_DMA_AND_PIO_MODE - -config B43_DMA_AND_PIO_MODE - bool "DMA + PIO" - select B43_DMA - select B43_PIO - ---help--- - Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) - data transfer modes. - The actually used mode is selectable through the module - parameter "pio". If the module parameter is pio=0, DMA is used. - Otherwise PIO is used. DMA is default. - - If unsure, choose this option. - -config B43_DMA_MODE - bool "DMA (Direct Memory Access) only" - select B43_DMA - ---help--- - Only include Direct Memory Access (DMA). - This reduces the size of the driver module, by omitting the PIO code. - -config B43_PIO_MODE - bool "PIO (Programmed I/O) only" - select B43_PIO - ---help--- - Only include Programmed I/O (PIO). - This reduces the size of the driver module, by omitting the DMA code. - Please note that PIO transfers are slow (compared to DMA). - - Also note that not all devices of the 43xx series support PIO. - The 4306 (Apple Airport Extreme and others) supports PIO, while - the 4318 is known to _not_ support PIO. - - Only use PIO, if DMA does not work for you. - -endchoice diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 485e59e2dfab..ac1329dba045 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile @@ -1,20 +1,16 @@ -# b43 core b43-y += main.o b43-y += tables.o +b43-y += tables_nphy.o b43-y += phy.o +b43-y += nphy.o b43-y += sysfs.o b43-y += xmit.o b43-y += lo.o -# b43 RFKILL button support +b43-y += wa.o +b43-y += dma.o b43-$(CONFIG_B43_RFKILL) += rfkill.o -# b43 LED support b43-$(CONFIG_B43_LEDS) += leds.o -# b43 PCMCIA support b43-$(CONFIG_B43_PCMCIA) += pcmcia.o -# b43 debugging b43-$(CONFIG_B43_DEBUG) += debugfs.o -# b43 DMA and PIO -b43-$(CONFIG_B43_DMA) += dma.o -b43-$(CONFIG_B43_PIO) += pio.o obj-$(CONFIG_B43) += b43.o diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 7b6fc1ab2b90..32a24f5c4fa6 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -35,8 +35,8 @@ #define B43_MMIO_DMA4_IRQ_MASK 0x44 #define B43_MMIO_DMA5_REASON 0x48 #define B43_MMIO_DMA5_IRQ_MASK 0x4C -#define B43_MMIO_MACCTL 0x120 -#define B43_MMIO_STATUS2_BITFIELD 0x124 +#define B43_MMIO_MACCTL 0x120 /* MAC control */ +#define B43_MMIO_MACCMD 0x124 /* MAC command */ #define B43_MMIO_GEN_IRQ_REASON 0x128 #define B43_MMIO_GEN_IRQ_MASK 0x12C #define B43_MMIO_RAM_CONTROL 0x130 @@ -50,6 +50,9 @@ #define B43_MMIO_XMITSTAT_1 0x174 #define B43_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ #define B43_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ +#define B43_MMIO_TSF_CFP_REP 0x188 +#define B43_MMIO_TSF_CFP_START 0x18C +#define B43_MMIO_TSF_CFP_MAXDUR 0x190 /* 32-bit DMA */ #define B43_MMIO_DMA32_BASE0 0x200 @@ -65,11 +68,6 @@ #define B43_MMIO_DMA64_BASE3 0x2C0 #define B43_MMIO_DMA64_BASE4 0x300 #define B43_MMIO_DMA64_BASE5 0x340 -/* PIO */ -#define B43_MMIO_PIO1_BASE 0x300 -#define B43_MMIO_PIO2_BASE 0x310 -#define B43_MMIO_PIO3_BASE 0x320 -#define B43_MMIO_PIO4_BASE 0x330 #define B43_MMIO_PHY_VER 0x3E0 #define B43_MMIO_PHY_RADIO 0x3E2 @@ -88,6 +86,8 @@ #define B43_MMIO_RADIO_HWENABLED_LO 0x49A #define B43_MMIO_GPIO_CONTROL 0x49C #define B43_MMIO_GPIO_MASK 0x49E +#define B43_MMIO_TSF_CFP_START_LOW 0x604 +#define B43_MMIO_TSF_CFP_START_HIGH 0x606 #define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */ #define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */ #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ @@ -170,14 +170,17 @@ enum { #define B43_SHM_SH_SLOTT 0x0010 /* Slot time */ #define B43_SHM_SH_DTIMPER 0x0012 /* DTIM period */ #define B43_SHM_SH_NOSLPZNATDTIM 0x004C /* NOSLPZNAT DTIM */ -/* SHM_SHARED beacon variables */ +/* SHM_SHARED beacon/AP variables */ #define B43_SHM_SH_BTL0 0x0018 /* Beacon template length 0 */ #define B43_SHM_SH_BTL1 0x001A /* Beacon template length 1 */ #define B43_SHM_SH_BTSFOFF 0x001C /* Beacon TSF offset */ #define B43_SHM_SH_TIMBPOS 0x001E /* TIM B position in beacon */ +#define B43_SHM_SH_DTIMP 0x0012 /* DTIP period */ +#define B43_SHM_SH_MCASTCOOKIE 0x00A8 /* Last bcast/mcast frame ID */ #define B43_SHM_SH_SFFBLIM 0x0044 /* Short frame fallback retry limit */ #define B43_SHM_SH_LFFBLIM 0x0046 /* Long frame fallback retry limit */ #define B43_SHM_SH_BEACPHYCTL 0x0054 /* Beacon PHY TX control word (see PHY TX control) */ +#define B43_SHM_SH_EXTNPHYCTL 0x00B0 /* Extended bytes for beacon PHY control (N) */ /* SHM_SHARED ACK/CTS control */ #define B43_SHM_SH_ACKCTSPHYCTL 0x0022 /* ACK/CTS PHY control word (see PHY TX control) */ /* SHM_SHARED probe response variables */ @@ -321,17 +324,29 @@ enum { #define B43_MACCTL_DISCPMQ 0x40000000 /* Discard Power Management Queue */ #define B43_MACCTL_GMODE 0x80000000 /* G Mode */ -/* 802.11 core specific TM State Low flags */ +/* MAC Command bitfield */ +#define B43_MACCMD_BEACON0_VALID 0x00000001 /* Beacon 0 in template RAM is busy/valid */ +#define B43_MACCMD_BEACON1_VALID 0x00000002 /* Beacon 1 in template RAM is busy/valid */ +#define B43_MACCMD_DFQ_VALID 0x00000004 /* Directed frame queue valid (IBSS PS mode, ATIM) */ +#define B43_MACCMD_CCA 0x00000008 /* Clear channel assessment */ +#define B43_MACCMD_BGNOISE 0x00000010 /* Background noise */ + +/* 802.11 core specific TM State Low (SSB_TMSLOW) flags */ #define B43_TMSLOW_GMODE 0x20000000 /* G Mode Enable */ -#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select */ +#define B43_TMSLOW_PHYCLKSPEED 0x00C00000 /* PHY clock speed mask (N-PHY only) */ +#define B43_TMSLOW_PHYCLKSPEED_40MHZ 0x00000000 /* 40 MHz PHY */ +#define B43_TMSLOW_PHYCLKSPEED_80MHZ 0x00400000 /* 80 MHz PHY */ +#define B43_TMSLOW_PHYCLKSPEED_160MHZ 0x00800000 /* 160 MHz PHY */ +#define B43_TMSLOW_PLLREFSEL 0x00200000 /* PLL Frequency Reference Select (rev >= 5) */ #define B43_TMSLOW_MACPHYCLKEN 0x00100000 /* MAC PHY Clock Control Enable (rev >= 5) */ #define B43_TMSLOW_PHYRESET 0x00080000 /* PHY Reset */ #define B43_TMSLOW_PHYCLKEN 0x00040000 /* PHY Clock Enable */ -/* 802.11 core specific TM State High flags */ +/* 802.11 core specific TM State High (SSB_TMSHIGH) flags */ +#define B43_TMSHIGH_DUALBAND_PHY 0x00080000 /* Dualband PHY available */ #define B43_TMSHIGH_FCLOCK 0x00040000 /* Fast Clock Available (rev >= 5) */ -#define B43_TMSHIGH_APHY 0x00020000 /* A-PHY available (rev >= 5) */ -#define B43_TMSHIGH_GPHY 0x00010000 /* G-PHY available (rev >= 5) */ +#define B43_TMSHIGH_HAVE_5GHZ_PHY 0x00020000 /* 5 GHz PHY available (rev >= 5) */ +#define B43_TMSHIGH_HAVE_2GHZ_PHY 0x00010000 /* 2.4 GHz PHY available (rev >= 5) */ /* Generic-Interrupt reasons. */ #define B43_IRQ_MAC_SUSPENDED 0x00000001 @@ -393,6 +408,8 @@ enum { #define B43_DEFAULT_SHORT_RETRY_LIMIT 7 #define B43_DEFAULT_LONG_RETRY_LIMIT 4 +#define B43_PHY_TX_BADNESS_LIMIT 1000 + /* Max size of a security key */ #define B43_SEC_KEYSIZE 16 /* Security algorithms. */ @@ -462,7 +479,6 @@ struct b43_phy { u16 radio_ver; /* Radio version */ u8 radio_rev; /* Radio revision */ - bool locked; /* Only used in b43_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ /* ACI (adjacent channel interference) flags. */ @@ -499,11 +515,6 @@ struct b43_phy { s16 lna_gain; /* LNA */ s16 pga_gain; /* PGA */ - /* PHY lock for core.rev < 3 - * This lock is only used by b43_phy_{un}lock() - */ - spinlock_t lock; - /* Desired TX power level (in dBm). * This is set by the user and adjusted in b43_phy_xmitpower(). */ u8 power_level; @@ -514,9 +525,7 @@ struct b43_phy { struct b43_bbatt bbatt; struct b43_rfatt rfatt; u8 tx_control; /* B43_TXCTL_XXX */ -#ifdef CONFIG_B43_DEBUG - bool manual_txpower_control; /* Manual TX-power control enabled? */ -#endif + /* Hardware Power Control enabled? */ bool hardware_power_control; @@ -544,6 +553,26 @@ struct b43_phy { u16 lofcal; u16 initval; //FIXME rename? + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + + /* The device does address auto increment for the OFDM tables. + * We cache the previously used address here and omit the address + * write on the next table access, if possible. */ + u16 ofdmtab_addr; /* The address currently set in hardware. */ + enum { /* The last data flow direction. */ + B43_OFDMTAB_DIRECTION_UNKNOWN = 0, + B43_OFDMTAB_DIRECTION_READ, + B43_OFDMTAB_DIRECTION_WRITE, + } ofdmtab_addr_direction; + +#if B43_DEBUG + /* Manual TX-power control enabled? */ + bool manual_txpower_control; + /* PHY registers locked by b43_phy_lock()? */ + bool phy_locked; +#endif /* B43_DEBUG */ }; /* Data structures for DMA transmission, per 80211 core. */ @@ -559,14 +588,6 @@ struct b43_dma { struct b43_dmaring *rx_ring3; /* only available on core.rev < 5 */ }; -/* Data structures for PIO transmission, per 80211 core. */ -struct b43_pio { - struct b43_pioqueue *queue0; - struct b43_pioqueue *queue1; - struct b43_pioqueue *queue2; - struct b43_pioqueue *queue3; -}; - /* Context information for a noise calculation (Link Quality). */ struct b43_noise_calculation { u8 channel_at_start; @@ -599,18 +620,18 @@ struct b43_wl { /* Pointer to the ieee80211 hardware data structure */ struct ieee80211_hw *hw; - spinlock_t irq_lock; struct mutex mutex; + spinlock_t irq_lock; + /* Lock for LEDs access. */ spinlock_t leds_lock; + /* Lock for SHM access. */ + spinlock_t shm_lock; /* We can only have one operating interface (802.11 core) * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface from the ieee80211 - * subsystem. Do not modify. - */ - int if_id; + struct ieee80211_vif *vif; /* The MAC address of the operating interface. */ u8 mac_addr[ETH_ALEN]; /* Current BSSID */ @@ -634,18 +655,33 @@ struct b43_wl { /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; + + bool radiotap_enabled; + + /* The beacon we are currently using (AP or IBSS mode). + * This beacon stuff is protected by the irq_lock. */ + struct sk_buff *current_beacon; + bool beacon0_uploaded; + bool beacon1_uploaded; +}; + +/* In-memory representation of a cached microcode file. */ +struct b43_firmware_file { + const char *filename; + const struct firmware *data; }; /* Pointers to the firmware data and meta information about it. */ struct b43_firmware { /* Microcode */ - const struct firmware *ucode; + struct b43_firmware_file ucode; /* PCM code */ - const struct firmware *pcm; + struct b43_firmware_file pcm; /* Initial MMIO values for the firmware */ - const struct firmware *initvals; + struct b43_firmware_file initvals; /* Initial MMIO values for the firmware, band-specific */ - const struct firmware *initvals_band; + struct b43_firmware_file initvals_band; + /* Firmware revision */ u16 rev; /* Firmware patchlevel */ @@ -683,21 +719,17 @@ struct b43_wldev { /* Saved init status for handling suspend. */ int suspend_init_status; - bool __using_pio; /* Internal, use b43_using_pio(). */ bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ - bool reg124_set_0x4; /* Some variable to keep track of IRQ stuff. */ + bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool short_preamble; /* TRUE, if short preamble is enabled. */ bool short_slot; /* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ /* PHY/Radio device. */ struct b43_phy phy; - union { - /* DMA engines. */ - struct b43_dma dma; - /* PIO engines. */ - struct b43_pio pio; - }; + + /* DMA engines. */ + struct b43_dma dma; /* Various statistics about the physical device. */ struct b43_stats stats; @@ -732,9 +764,6 @@ struct b43_wldev { u8 max_nr_keys; struct b43_key key[58]; - /* Cached beacon template while uploading the template. */ - struct sk_buff *cached_beacon; - /* Firmware data */ struct b43_firmware fw; @@ -752,28 +781,6 @@ static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) return hw->priv; } -/* Helper function, which returns a boolean. - * TRUE, if PIO is used; FALSE, if DMA is used. - */ -#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) -static inline int b43_using_pio(struct b43_wldev *dev) -{ - return dev->__using_pio; -} -#elif defined(CONFIG_B43_DMA) -static inline int b43_using_pio(struct b43_wldev *dev) -{ - return 0; -} -#elif defined(CONFIG_B43_PIO) -static inline int b43_using_pio(struct b43_wldev *dev) -{ - return 1; -} -#else -# error "Using neither DMA nor PIO? Confused..." -#endif - static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev) { struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index ef0075d9f9cb..e38ed0fe72e9 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -34,7 +34,6 @@ #include "main.h" #include "debugfs.h" #include "dma.h" -#include "pio.h" #include "xmit.h" @@ -223,8 +222,6 @@ out: static int txpower_g_write_file(struct b43_wldev *dev, const char *buf, size_t count) { - unsigned long phy_flags; - if (dev->phy.type != B43_PHYTYPE_G) return -ENODEV; if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) { @@ -248,12 +245,12 @@ static int txpower_g_write_file(struct b43_wldev *dev, dev->phy.tx_control |= B43_TXCTL_PA2DB; if (pa3db) dev->phy.tx_control |= B43_TXCTL_PA3DB; - b43_phy_lock(dev, phy_flags); + b43_phy_lock(dev); b43_radio_lock(dev); b43_set_txpower_g(dev, &dev->phy.bbatt, &dev->phy.rfatt, dev->phy.tx_control); b43_radio_unlock(dev); - b43_phy_unlock(dev, phy_flags); + b43_phy_unlock(dev); } return 0; @@ -352,7 +349,7 @@ static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf, struct b43_wldev *dev; struct b43_debugfs_fops *dfops; struct b43_dfs_file *dfile; - ssize_t ret; + ssize_t uninitialized_var(ret); char *buf; const size_t bufsize = 1024 * 128; const size_t buforder = get_order(bufsize); diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 5e8f8ac0f1dd..3e73d2a523aa 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -37,6 +37,8 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/skbuff.h> +#include <linux/etherdevice.h> + /* 32bit DMA ops. */ static @@ -165,7 +167,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring, addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) >> SSB_DMA_TRANSLATION_SHIFT; - addrhi |= ssb_dma_translation(ring->dev->dev); + addrhi |= (ssb_dma_translation(ring->dev->dev) << 1); if (slot == ring->nr_slots - 1) ctl0 |= B43_DMA64_DCTL0_DTABLEEND; if (start) @@ -315,26 +317,24 @@ static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev, case 3: ring = dev->dma.tx_ring0; break; - case 4: - ring = dev->dma.tx_ring4; - break; - case 5: - ring = dev->dma.tx_ring5; - break; } return ring; } -/* Bcm43xx-ring to mac80211-queue mapping */ +/* b43-ring to mac80211-queue mapping */ static inline int txring_to_priority(struct b43_dmaring *ring) { - static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, }; + static const u8 idx_to_prio[] = { 3, 2, 1, 0, }; + unsigned int index; /*FIXME: have only one queue, for now */ return 0; - return idx_to_prio[ring->index]; + index = ring->index; + if (B43_WARN_ON(index >= ARRAY_SIZE(idx_to_prio))) + index = 0; + return idx_to_prio[index]; } u16 b43_dmacontroller_base(int dma64bit, int controller_idx) @@ -426,9 +426,21 @@ static inline static int alloc_ringmemory(struct b43_dmaring *ring) { struct device *dev = ring->dev->dev->dev; - + gfp_t flags = GFP_KERNEL; + + /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K + * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing + * has shown that 4K is sufficient for the latter as long as the buffer + * does not cross an 8K boundary. + * + * For unknown reasons - possibly a hardware error - the BCM4311 rev + * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, + * which accounts for the GFP_DMA flag below. + */ + if (ring->dma64) + flags |= GFP_DMA; ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE, - &(ring->dmabase), GFP_KERNEL); + &(ring->dmabase), flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; @@ -483,7 +495,7 @@ int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) return 0; } -/* Reset the RX DMA channel */ +/* Reset the TX DMA channel */ int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64) { int i; @@ -647,7 +659,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring) b43_dma_write(ring, B43_DMA64_TXRINGHI, ((ringbase >> 32) & ~SSB_DMA_TRANSLATION_MASK) - | trans); + | (trans << 1)); } else { u32 ringbase = (u32) (ring->dmabase); @@ -680,8 +692,9 @@ static int dmacontroller_setup(struct b43_dmaring *ring) b43_dma_write(ring, B43_DMA64_RXRINGHI, ((ringbase >> 32) & ~SSB_DMA_TRANSLATION_MASK) - | trans); - b43_dma_write(ring, B43_DMA64_RXINDEX, 200); + | (trans << 1)); + b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots * + sizeof(struct b43_dmadesc64)); } else { u32 ringbase = (u32) (ring->dmabase); @@ -695,11 +708,12 @@ static int dmacontroller_setup(struct b43_dmaring *ring) b43_dma_write(ring, B43_DMA32_RXRING, (ringbase & ~SSB_DMA_TRANSLATION_MASK) | trans); - b43_dma_write(ring, B43_DMA32_RXINDEX, 200); + b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots * + sizeof(struct b43_dmadesc32)); } } - out: +out: return err; } @@ -793,7 +807,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, goto err_kfree_ring; if (for_tx) { ring->txhdr_cache = kcalloc(nr_slots, - sizeof(struct b43_txhdr_fw4), + b43_txhdr_size(dev), GFP_KERNEL); if (!ring->txhdr_cache) goto err_kfree_meta; @@ -801,22 +815,21 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, /* test for ability to dma to txhdr_cache */ dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache, - sizeof(struct b43_txhdr_fw4), + b43_txhdr_size(dev), DMA_TO_DEVICE); if (dma_mapping_error(dma_test)) { /* ugh realloc */ kfree(ring->txhdr_cache); ring->txhdr_cache = kcalloc(nr_slots, - sizeof(struct - b43_txhdr_fw4), + b43_txhdr_size(dev), GFP_KERNEL | GFP_DMA); if (!ring->txhdr_cache) goto err_kfree_meta; dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache, - sizeof(struct b43_txhdr_fw4), + b43_txhdr_size(dev), DMA_TO_DEVICE); if (dma_mapping_error(dma_test)) @@ -824,7 +837,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, } dma_unmap_single(dev->dev->dev, - dma_test, sizeof(struct b43_txhdr_fw4), + dma_test, b43_txhdr_size(dev), DMA_TO_DEVICE); } @@ -901,11 +914,7 @@ static void b43_destroy_dmaring(struct b43_dmaring *ring) void b43_dma_free(struct b43_wldev *dev) { - struct b43_dma *dma; - - if (b43_using_pio(dev)) - return; - dma = &dev->dma; + struct b43_dma *dma = &dev->dma; b43_destroy_dmaring(dma->rx_ring3); dma->rx_ring3 = NULL; @@ -940,16 +949,11 @@ int b43_dma_init(struct b43_wldev *dev) err = ssb_dma_set_mask(dev->dev, dmamask); if (err) { -#ifdef B43_PIO - b43warn(dev->wl, "DMA for this device not supported. " - "Falling back to PIO\n"); - dev->__using_pio = 1; - return -EAGAIN; -#else - b43err(dev->wl, "DMA for this device not supported and " - "no PIO support compiled in\n"); + b43err(dev->wl, "The machine/kernel does not support " + "the required DMA mask (0x%08X%08X)\n", + (unsigned int)((dmamask & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(dmamask & 0x00000000FFFFFFFFULL)); return -EOPNOTSUPP; -#endif } err = -ENOMEM; @@ -1038,26 +1042,30 @@ static u16 generate_cookie(struct b43_dmaring *ring, int slot) * in the lower 12 bits. * Note that the cookie must never be 0, as this * is a special value used in RX path. + * It can also not be 0xFFFF because that is special + * for multicast frames. */ switch (ring->index) { case 0: - cookie = 0xA000; + cookie = 0x1000; break; case 1: - cookie = 0xB000; + cookie = 0x2000; break; case 2: - cookie = 0xC000; + cookie = 0x3000; break; case 3: - cookie = 0xD000; + cookie = 0x4000; break; case 4: - cookie = 0xE000; + cookie = 0x5000; break; case 5: - cookie = 0xF000; + cookie = 0x6000; break; + default: + B43_WARN_ON(1); } B43_WARN_ON(slot & ~0x0FFF); cookie |= (u16) slot; @@ -1073,22 +1081,22 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot) struct b43_dmaring *ring = NULL; switch (cookie & 0xF000) { - case 0xA000: + case 0x1000: ring = dma->tx_ring0; break; - case 0xB000: + case 0x2000: ring = dma->tx_ring1; break; - case 0xC000: + case 0x3000: ring = dma->tx_ring2; break; - case 0xD000: + case 0x4000: ring = dma->tx_ring3; break; - case 0xE000: + case 0x5000: ring = dma->tx_ring4; break; - case 0xF000: + case 0x6000: ring = dma->tx_ring5; break; default: @@ -1112,6 +1120,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring, struct b43_dmadesc_meta *meta; struct b43_dmadesc_meta *meta_hdr; struct sk_buff *bounce_skb; + u16 cookie; + size_t hdrsize = b43_txhdr_size(ring->dev); #define SLOTS_PER_PACKET 2 B43_WARN_ON(skb_shinfo(skb)->nr_frags); @@ -1121,17 +1131,17 @@ static int dma_tx_fragment(struct b43_dmaring *ring, desc = ops->idx2desc(ring, slot, &meta_hdr); memset(meta_hdr, 0, sizeof(*meta_hdr)); - header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]); + header = &(ring->txhdr_cache[slot * hdrsize]); + cookie = generate_cookie(ring, slot); b43_generate_txhdr(ring->dev, header, - skb->data, skb->len, ctl, - generate_cookie(ring, slot)); + skb->data, skb->len, ctl, cookie); meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, - sizeof(struct b43_txhdr_fw4), 1); + hdrsize, 1); if (dma_mapping_error(meta_hdr->dmaaddr)) return -EIO; ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, - sizeof(struct b43_txhdr_fw4), 1, 0, 0); + hdrsize, 1, 0, 0); /* Get a slot for the payload. */ slot = request_slot(ring); @@ -1164,16 +1174,22 @@ static int dma_tx_fragment(struct b43_dmaring *ring, ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); + if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + /* Tell the firmware about the cookie of the last + * mcast frame, so it can clear the more-data bit in it. */ + b43_shm_write16(ring->dev, B43_SHM_SHARED, + B43_SHM_SH_MCASTCOOKIE, cookie); + } /* Now transfer the whole frame. */ wmb(); ops->poke_tx(ring, next_slot(ring, slot)); return 0; - out_free_bounce: +out_free_bounce: dev_kfree_skb_any(skb); - out_unmap_hdr: +out_unmap_hdr: unmap_descbuffer(ring, meta_hdr->dmaaddr, - sizeof(struct b43_txhdr_fw4), 1); + hdrsize, 1); return err; } @@ -1202,10 +1218,27 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { struct b43_dmaring *ring; + struct ieee80211_hdr *hdr; int err = 0; unsigned long flags; - ring = priority_to_txring(dev, ctl->queue); + if (unlikely(skb->len < 2 + 2 + 6)) { + /* Too short, this can't be a valid frame. */ + return -EINVAL; + } + + hdr = (struct ieee80211_hdr *)skb->data; + if (ctl->flags & IEEE80211_TXCTL_SEND_AFTER_DTIM) { + /* The multicast ring will be sent after the DTIM */ + ring = dev->dma.tx_ring4; + /* Set the more-data bit. Ucode will clear it on + * the last frame for us. */ + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } else { + /* Decide by priority where to put this frame. */ + ring = priority_to_txring(dev, ctl->queue); + } + spin_lock_irqsave(&ring->lock, flags); B43_WARN_ON(!ring->tx); if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) { @@ -1233,7 +1266,7 @@ int b43_dma_tx(struct b43_wldev *dev, b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index); } } - out_unlock: +out_unlock: spin_unlock_irqrestore(&ring->lock, flags); return err; @@ -1265,7 +1298,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, 1); else unmap_descbuffer(ring, meta->dmaaddr, - sizeof(struct b43_txhdr_fw4), 1); + b43_txhdr_size(dev), 1); if (meta->is_last_fragment) { B43_WARN_ON(!meta->skb); diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index 3eed185be725..58db03ac536e 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -170,8 +170,6 @@ struct b43_dmadesc_generic { #define B43_DMA0_RX_BUFFERSIZE (2304 + 100) #define B43_DMA3_RX_BUFFERSIZE 16 -#ifdef CONFIG_B43_DMA - struct sk_buff; struct b43_private; struct b43_txstatus; @@ -286,52 +284,4 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, void b43_dma_rx(struct b43_dmaring *ring); -#else /* CONFIG_B43_DMA */ - -static inline int b43_dma_init(struct b43_wldev *dev) -{ - return 0; -} -static inline void b43_dma_free(struct b43_wldev *dev) -{ -} -static inline - int b43_dmacontroller_rx_reset(struct b43_wldev *dev, - u16 dmacontroller_mmio_base, int dma64) -{ - return 0; -} -static inline - int b43_dmacontroller_tx_reset(struct b43_wldev *dev, - u16 dmacontroller_mmio_base, int dma64) -{ - return 0; -} -static inline - void b43_dma_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ -} -static inline - int b43_dma_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - return 0; -} -static inline - void b43_dma_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ -} -static inline void b43_dma_rx(struct b43_dmaring *ring) -{ -} -static inline void b43_dma_tx_suspend(struct b43_wldev *dev) -{ -} -static inline void b43_dma_tx_resume(struct b43_wldev *dev) -{ -} - -#endif /* CONFIG_B43_DMA */ #endif /* B43_DMA_H_ */ diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 6c0e2b9f7760..4b590d8c65ff 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c @@ -4,7 +4,7 @@ LED control Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -190,10 +190,10 @@ void b43_leds_init(struct b43_wldev *dev) enum b43_led_behaviour behaviour; bool activelow; - sprom[0] = bus->sprom.r1.gpio0; - sprom[1] = bus->sprom.r1.gpio1; - sprom[2] = bus->sprom.r1.gpio2; - sprom[3] = bus->sprom.r1.gpio3; + sprom[0] = bus->sprom.gpio0; + sprom[1] = bus->sprom.gpio1; + sprom[2] = bus->sprom.gpio2; + sprom[3] = bus->sprom.gpio3; for (i = 0; i < 4; i++) { if (sprom[i] == 0xFF) { diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index b14a1753a0d7..d890f366a23b 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -5,7 +5,7 @@ G PHY LO (LocalOscillator) Measuring and Control routines Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005, 2006 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -264,8 +264,8 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev, rfover |= pga; rfover |= lna; rfover |= trsw_rx; - if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) && - phy->rev > 6) + if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) + && phy->rev > 6) rfover |= B43_PHY_RFOVERVAL_EXTLNA; b43_phy_write(dev, B43_PHY_PGACTL, 0xE300); @@ -555,20 +555,20 @@ struct lo_g_saved_values { u16 phy_extg_01; u16 phy_dacctl_hwpctl; u16 phy_dacctl; - u16 phy_base_14; + u16 phy_cck_14; u16 phy_hpwr_tssictl; u16 phy_analogover; u16 phy_analogoverval; u16 phy_rfover; u16 phy_rfoverval; u16 phy_classctl; - u16 phy_base_3E; + u16 phy_cck_3E; u16 phy_crs0; u16 phy_pgactl; - u16 phy_base_2A; + u16 phy_cck_2A; u16 phy_syncctl; - u16 phy_base_30; - u16 phy_base_06; + u16 phy_cck_30; + u16 phy_cck_06; /* Radio registers */ u16 radio_43; @@ -588,7 +588,7 @@ static void lo_measure_setup(struct b43_wldev *dev, sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK); sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01)); sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL); - sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14)); + sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14)); sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, @@ -600,14 +600,14 @@ static void lo_measure_setup(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_DACCTL, b43_phy_read(dev, B43_PHY_DACCTL) | 0x40); - b43_phy_write(dev, B43_PHY_BASE(0x14), - b43_phy_read(dev, B43_PHY_BASE(0x14)) + b43_phy_write(dev, B43_PHY_CCK(0x14), + b43_phy_read(dev, B43_PHY_CCK(0x14)) | 0x200); } if (phy->type == B43_PHYTYPE_B && phy->radio_ver == 0x2050 && phy->radio_rev < 6) { - b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410); - b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820); + b43_phy_write(dev, B43_PHY_CCK(0x16), 0x410); + b43_phy_write(dev, B43_PHY_CCK(0x17), 0x820); } if (!lo->rebuild && b43_has_hardware_pctl(phy)) lo_read_power_vector(dev); @@ -618,7 +618,7 @@ static void lo_measure_setup(struct b43_wldev *dev, sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL); sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL); - sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E)); + sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E)); sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0); b43_phy_write(dev, B43_PHY_CLASSCTL, @@ -634,7 +634,7 @@ static void lo_measure_setup(struct b43_wldev *dev, & 0xFFFC); if (phy->type == B43_PHYTYPE_G) { if ((phy->rev >= 7) && - (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + (sprom->boardflags_lo & B43_BFL_EXTLNA)) { b43_phy_write(dev, B43_PHY_RFOVER, 0x933); } else { b43_phy_write(dev, B43_PHY_RFOVER, 0x133); @@ -642,14 +642,14 @@ static void lo_measure_setup(struct b43_wldev *dev, } else { b43_phy_write(dev, B43_PHY_RFOVER, 0); } - b43_phy_write(dev, B43_PHY_BASE(0x3E), 0); + b43_phy_write(dev, B43_PHY_CCK(0x3E), 0); } sav->reg_3F4 = b43_read16(dev, 0x3F4); sav->reg_3E2 = b43_read16(dev, 0x3E2); sav->radio_43 = b43_radio_read16(dev, 0x43); sav->radio_7A = b43_radio_read16(dev, 0x7A); sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); - sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A)); + sav->phy_cck_2A = b43_phy_read(dev, B43_PHY_CCK(0x2A)); sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL); sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL); @@ -658,10 +658,10 @@ static void lo_measure_setup(struct b43_wldev *dev, sav->radio_52 &= 0x00F0; } if (phy->type == B43_PHYTYPE_B) { - sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); - sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06)); - b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF); - b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F); + sav->phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); + sav->phy_cck_06 = b43_phy_read(dev, B43_PHY_CCK(0x06)); + b43_phy_write(dev, B43_PHY_CCK(0x30), 0x00FF); + b43_phy_write(dev, B43_PHY_CCK(0x06), 0x3F3F); } else { b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000); @@ -670,7 +670,7 @@ static void lo_measure_setup(struct b43_wldev *dev, & 0xF000); tmp = - (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E); + (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_CCK(0x2E); b43_phy_write(dev, tmp, 0x007F); tmp = sav->phy_syncctl; @@ -678,26 +678,26 @@ static void lo_measure_setup(struct b43_wldev *dev, tmp = sav->radio_7A; b43_radio_write16(dev, 0x007A, tmp & 0xFFF0); - b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3); + b43_phy_write(dev, B43_PHY_CCK(0x2A), 0x8A3); if (phy->type == B43_PHYTYPE_G || (phy->type == B43_PHYTYPE_B && phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) { - b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1003); } else - b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x0802); if (phy->rev >= 2) b43_dummy_transmission(dev); b43_radio_selectchannel(dev, 6, 0); b43_radio_read16(dev, 0x51); /* dummy read */ if (phy->type == B43_PHYTYPE_G) - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0); if (lo->rebuild) lo_measure_txctl_values(dev); if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) { b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078); } else { if (phy->type == B43_PHYTYPE_B) - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); else b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); } @@ -732,17 +732,17 @@ static void lo_measure_restore(struct b43_wldev *dev, } if (phy->type == B43_PHYTYPE_G) { if (phy->rev >= 3) - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0xC078); else - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8078); if (phy->rev >= 2) - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0202); else - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x0101); } b43_write16(dev, 0x3F4, sav->reg_3F4); b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl); - b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A); + b43_phy_write(dev, B43_PHY_CCK(0x2A), sav->phy_cck_2A); b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl); b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl); b43_radio_write16(dev, 0x43, sav->radio_43); @@ -755,8 +755,8 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_write16(dev, 0x3E2, sav->reg_3E2); if (phy->type == B43_PHYTYPE_B && phy->radio_ver == 0x2050 && phy->radio_rev <= 5) { - b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30); - b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06); + b43_phy_write(dev, B43_PHY_CCK(0x30), sav->phy_cck_30); + b43_phy_write(dev, B43_PHY_CCK(0x06), sav->phy_cck_06); } if (phy->rev >= 2) { b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover); @@ -765,7 +765,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl); b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover); b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval); - b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E); + b43_phy_write(dev, B43_PHY_CCK(0x3E), sav->phy_cck_3E); b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0); } if (b43_has_hardware_pctl(phy)) { @@ -773,7 +773,7 @@ static void lo_measure_restore(struct b43_wldev *dev, b43_phy_write(dev, B43_PHY_LO_MASK, tmp); b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01); b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl); - b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14); + b43_phy_write(dev, B43_PHY_CCK(0x14), sav->phy_cck_14); b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl); } b43_radio_selectchannel(dev, sav->old_channel, 1); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1c93b4f4bfe3..88d2c15d3fbe 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -46,7 +46,6 @@ #include "debugfs.h" #include "phy.h" #include "dma.h" -#include "pio.h" #include "sysfs.h" #include "xmit.h" #include "lo.h" @@ -58,31 +57,12 @@ MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); -extern char *nvram_get(char *name); - -#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO) -static int modparam_pio; -module_param_named(pio, modparam_pio, int, 0444); -MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); -#elif defined(CONFIG_B43_DMA) -# define modparam_pio 0 -#elif defined(CONFIG_B43_PIO) -# define modparam_pio 1 -#endif static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); -static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT; -module_param_named(short_retry, modparam_short_retry, int, 0444); -MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); - -static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; -module_param_named(long_retry, modparam_long_retry, int, 0444); -MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); @@ -101,6 +81,8 @@ static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), SSB_DEVTABLE_END }; @@ -150,7 +132,7 @@ static struct ieee80211_rate __b43_ratetable[] = { .power_level = 0xFF, \ .antenna_max = 0xFF, \ } -static struct ieee80211_channel b43_bg_chantable[] = { +static struct ieee80211_channel b43_2ghz_chantable[] = { CHANTAB_ENT(1, 2412), CHANTAB_ENT(2, 2417), CHANTAB_ENT(3, 2422), @@ -166,9 +148,10 @@ static struct ieee80211_channel b43_bg_chantable[] = { CHANTAB_ENT(13, 2472), CHANTAB_ENT(14, 2484), }; +#define b43_2ghz_chantable_size ARRAY_SIZE(b43_2ghz_chantable) -#define b43_bg_chantable_size ARRAY_SIZE(b43_bg_chantable) -static struct ieee80211_channel b43_a_chantable[] = { +#if 0 +static struct ieee80211_channel b43_5ghz_chantable[] = { CHANTAB_ENT(36, 5180), CHANTAB_ENT(40, 5200), CHANTAB_ENT(44, 5220), @@ -183,8 +166,8 @@ static struct ieee80211_channel b43_a_chantable[] = { CHANTAB_ENT(161, 5805), CHANTAB_ENT(165, 5825), }; - -#define b43_a_chantable_size ARRAY_SIZE(b43_a_chantable) +#define b43_5ghz_chantable_size ARRAY_SIZE(b43_5ghz_chantable) +#endif static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); @@ -269,13 +252,12 @@ static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val) b43_write32(dev, B43_MMIO_RAM_DATA, val); } -static inline - void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset) +static inline void b43_shm_control_word(struct b43_wldev *dev, + u16 routing, u16 offset) { u32 control; /* "offset" is the WORD offset. */ - control = routing; control <<= 16; control |= offset; @@ -284,8 +266,11 @@ static inline u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) { + struct b43_wl *wl = dev->wl; + unsigned long flags; u32 ret; + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -296,20 +281,25 @@ u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, (offset >> 2) + 1); ret |= b43_read16(dev, B43_MMIO_SHM_DATA); - return ret; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); ret = b43_read32(dev, B43_MMIO_SHM_DATA); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); return ret; } u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) { + struct b43_wl *wl = dev->wl; + unsigned long flags; u16 ret; + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { @@ -317,55 +307,63 @@ u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset) b43_shm_control_word(dev, routing, offset >> 2); ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED); - return ret; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); ret = b43_read16(dev, B43_MMIO_SHM_DATA); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); return ret; } void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value) { + struct b43_wl *wl = dev->wl; + unsigned long flags; + + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, (value >> 16) & 0xffff); - mmiowb(); b43_shm_control_word(dev, routing, (offset >> 2) + 1); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff); - return; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); - mmiowb(); b43_write32(dev, B43_MMIO_SHM_DATA, value); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); } void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value) { + struct b43_wl *wl = dev->wl; + unsigned long flags; + + spin_lock_irqsave(&wl->shm_lock, flags); if (routing == B43_SHM_SHARED) { B43_WARN_ON(offset & 0x0001); if (offset & 0x0003) { /* Unaligned access */ b43_shm_control_word(dev, routing, offset >> 2); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value); - return; + goto out; } offset >>= 2; } b43_shm_control_word(dev, routing, offset); - mmiowb(); b43_write16(dev, B43_MMIO_SHM_DATA, value); +out: + spin_unlock_irqrestore(&wl->shm_lock, flags); } /* Read HostFlags */ @@ -1012,9 +1010,8 @@ static void b43_jssi_write(struct b43_wldev *dev, u32 jssi) static void b43_generate_noise_sample(struct b43_wldev *dev) { b43_jssi_write(dev, 0x7F7F7F7F); - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, - b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) - | (1 << 4)); + b43_write32(dev, B43_MMIO_MACCMD, + b43_read32(dev, B43_MMIO_MACCMD) | B43_MACCMD_BGNOISE); B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel); } @@ -1100,18 +1097,18 @@ static void handle_irq_tbtt_indication(struct b43_wldev *dev) if (1 /*FIXME: the last PSpoll frame was sent successfully */ ) b43_power_saving_ctl_bits(dev, 0); } - dev->reg124_set_0x4 = 0; if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS)) - dev->reg124_set_0x4 = 1; + dev->dfq_valid = 1; } static void handle_irq_atim_end(struct b43_wldev *dev) { - if (!dev->reg124_set_0x4 /*FIXME rename this variable */ ) - return; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, - b43_read32(dev, B43_MMIO_STATUS2_BITFIELD) - | 0x4); + if (dev->dfq_valid) { + b43_write32(dev, B43_MMIO_MACCMD, + b43_read32(dev, B43_MMIO_MACCMD) + | B43_MACCMD_DFQ_VALID); + dev->dfq_valid = 0; + } } static void handle_irq_pmq(struct b43_wldev *dev) @@ -1166,15 +1163,59 @@ static void b43_write_beacon_template(struct b43_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate) { - int len; - const u8 *data; + unsigned int i, len, variable_len; + const struct ieee80211_mgmt *bcn; + const u8 *ie; + bool tim_found = 0; - B43_WARN_ON(!dev->cached_beacon); - len = min((size_t) dev->cached_beacon->len, + bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); + len = min((size_t) dev->wl->current_beacon->len, 0x200 - sizeof(struct b43_plcp_hdr6)); - data = (const u8 *)(dev->cached_beacon->data); - b43_write_template_common(dev, data, + + b43_write_template_common(dev, (const u8 *)bcn, len, ram_offset, shm_size_offset, rate); + + /* Find the position of the TIM and the DTIM_period value + * and write them to SHM. */ + ie = bcn->u.beacon.variable; + variable_len = len - offsetof(struct ieee80211_mgmt, u.beacon.variable); + for (i = 0; i < variable_len - 2; ) { + uint8_t ie_id, ie_len; + + ie_id = ie[i]; + ie_len = ie[i + 1]; + if (ie_id == 5) { + u16 tim_position; + u16 dtim_period; + /* This is the TIM Information Element */ + + /* Check whether the ie_len is in the beacon data range. */ + if (variable_len < ie_len + 2 + i) + break; + /* A valid TIM is at least 4 bytes long. */ + if (ie_len < 4) + break; + tim_found = 1; + + tim_position = sizeof(struct b43_plcp_hdr6); + tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable); + tim_position += i; + + dtim_period = ie[i + 3]; + + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_TIMBPOS, tim_position); + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_DTIMPER, dtim_period); + break; + } + i += ie_len + 2; + } + if (!tim_found) { + b43warn(dev->wl, "Did not find a valid TIM IE in " + "the beacon template packet. AP or IBSS operation " + "may be broken.\n"); + } } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, @@ -1187,7 +1228,7 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev, plcp.data = 0; b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, size, + dev->wl->vif, size, B43_RATE_TO_BASE100KBPS(rate)); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); @@ -1202,40 +1243,43 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev, * 2) Patching duration field * 3) Stripping TIM */ -static u8 *b43_generate_probe_resp(struct b43_wldev *dev, - u16 * dest_size, u8 rate) +static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, + u16 *dest_size, u8 rate) { const u8 *src_data; u8 *dest_data; u16 src_size, elem_size, src_pos, dest_pos; __le16 dur; struct ieee80211_hdr *hdr; + size_t ie_start; - B43_WARN_ON(!dev->cached_beacon); - src_size = dev->cached_beacon->len; - src_data = (const u8 *)dev->cached_beacon->data; + src_size = dev->wl->current_beacon->len; + src_data = (const u8 *)dev->wl->current_beacon->data; - if (unlikely(src_size < 0x24)) { - b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n"); + /* Get the start offset of the variable IEs in the packet. */ + ie_start = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + B43_WARN_ON(ie_start != offsetof(struct ieee80211_mgmt, u.beacon.variable)); + + if (B43_WARN_ON(src_size < ie_start)) return NULL; - } dest_data = kmalloc(src_size, GFP_ATOMIC); if (unlikely(!dest_data)) return NULL; - /* 0x24 is offset of first variable-len Information-Element - * in beacon frame. - */ - memcpy(dest_data, src_data, 0x24); - src_pos = dest_pos = 0x24; - for (; src_pos < src_size - 2; src_pos += elem_size) { + /* Copy the static data and all Information Elements, except the TIM. */ + memcpy(dest_data, src_data, ie_start); + src_pos = ie_start; + dest_pos = ie_start; + for ( ; src_pos < src_size - 2; src_pos += elem_size) { elem_size = src_data[src_pos + 1] + 2; - if (src_data[src_pos] != 0x05) { /* TIM */ - memcpy(dest_data + dest_pos, src_data + src_pos, - elem_size); - dest_pos += elem_size; + if (src_data[src_pos] == 5) { + /* This is the TIM. */ + continue; } + memcpy(dest_data + dest_pos, src_data + src_pos, + elem_size); + dest_pos += elem_size; } *dest_size = dest_pos; hdr = (struct ieee80211_hdr *)dest_data; @@ -1244,7 +1288,7 @@ static u8 *b43_generate_probe_resp(struct b43_wldev *dev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, *dest_size, + dev->wl->vif, *dest_size, B43_RATE_TO_BASE100KBPS(rate)); hdr->duration_id = dur; @@ -1255,11 +1299,10 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, u16 ram_offset, u16 shm_size_offset, u8 rate) { - u8 *probe_resp_data; + const u8 *probe_resp_data; u16 size; - B43_WARN_ON(!dev->cached_beacon); - size = dev->cached_beacon->len; + size = dev->wl->current_beacon->len; probe_resp_data = b43_generate_probe_resp(dev, &size, rate); if (unlikely(!probe_resp_data)) return; @@ -1278,39 +1321,21 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, kfree(probe_resp_data); } -static int b43_refresh_cached_beacon(struct b43_wldev *dev, - struct sk_buff *beacon) -{ - if (dev->cached_beacon) - kfree_skb(dev->cached_beacon); - dev->cached_beacon = beacon; - - return 0; -} - -static void b43_update_templates(struct b43_wldev *dev) +/* Asynchronously update the packet templates in template RAM. + * Locking: Requires wl->irq_lock to be locked. */ +static void b43_update_templates(struct b43_wl *wl, struct sk_buff *beacon) { - u32 status; - - B43_WARN_ON(!dev->cached_beacon); + /* This is the top half of the ansynchronous beacon update. + * The bottom half is the beacon IRQ. + * Beacon update must be asynchronous to avoid sending an + * invalid beacon. This can happen for example, if the firmware + * transmits a beacon while we are updating it. */ - b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); - b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); - b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB); - - status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); - status |= 0x03; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); -} - -static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon) -{ - int err; - - err = b43_refresh_cached_beacon(dev, beacon); - if (unlikely(err)) - return; - b43_update_templates(dev); + if (wl->current_beacon) + dev_kfree_skb_any(wl->current_beacon); + wl->current_beacon = beacon; + wl->beacon0_uploaded = 0; + wl->beacon1_uploaded = 0; } static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) @@ -1346,33 +1371,34 @@ static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) static void handle_irq_beacon(struct b43_wldev *dev) { - u32 status; + struct b43_wl *wl = dev->wl; + u32 cmd; - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + if (!b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) return; - dev->irq_savedstate &= ~B43_IRQ_BEACON; - status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD); + /* This is the bottom half of the asynchronous beacon update. */ - if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) { - /* ACK beacon IRQ. */ - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON); - dev->irq_savedstate |= B43_IRQ_BEACON; - if (dev->cached_beacon) - kfree_skb(dev->cached_beacon); - dev->cached_beacon = NULL; - return; - } - if (!(status & 0x1)) { - b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); - status |= 0x1; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + cmd = b43_read32(dev, B43_MMIO_MACCMD); + if (!(cmd & B43_MACCMD_BEACON0_VALID)) { + if (!wl->beacon0_uploaded) { + b43_write_beacon_template(dev, 0x68, 0x18, + B43_CCK_RATE_1MB); + b43_write_probe_resp_template(dev, 0x268, 0x4A, + B43_CCK_RATE_11MB); + wl->beacon0_uploaded = 1; + } + cmd |= B43_MACCMD_BEACON0_VALID; } - if (!(status & 0x2)) { - b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB); - status |= 0x2; - b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status); + if (!(cmd & B43_MACCMD_BEACON1_VALID)) { + if (!wl->beacon1_uploaded) { + b43_write_beacon_template(dev, 0x468, 0x1A, + B43_CCK_RATE_1MB); + wl->beacon1_uploaded = 1; + } + cmd |= B43_MACCMD_BEACON1_VALID; } + b43_write32(dev, B43_MMIO_MACCMD, cmd); } static void handle_irq_ucode_debug(struct b43_wldev *dev) @@ -1402,8 +1428,17 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) if (unlikely(reason & B43_IRQ_MAC_TXERR)) b43err(dev->wl, "MAC transmission error\n"); - if (unlikely(reason & B43_IRQ_PHY_TXERR)) + if (unlikely(reason & B43_IRQ_PHY_TXERR)) { b43err(dev->wl, "PHY transmission error\n"); + rmb(); + if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) { + atomic_set(&dev->phy.txerr_cnt, + B43_PHY_TX_BADNESS_LIMIT); + b43err(dev->wl, "Too many PHY TX errors, " + "restarting the controller\n"); + b43_controller_restart(dev, "PHY TX errors"); + } + } if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK | B43_DMAIRQ_NONFATALMASK))) { @@ -1445,20 +1480,12 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) handle_irq_noise(dev); /* Check the DMA reason registers for received data. */ - if (dma_reason[0] & B43_DMAIRQ_RX_DONE) { - if (b43_using_pio(dev)) - b43_pio_rx(dev->pio.queue0); - else - b43_dma_rx(dev->dma.rx_ring0); - } + if (dma_reason[0] & B43_DMAIRQ_RX_DONE) + b43_dma_rx(dev->dma.rx_ring0); + if (dma_reason[3] & B43_DMAIRQ_RX_DONE) + b43_dma_rx(dev->dma.rx_ring3); B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); - if (dma_reason[3] & B43_DMAIRQ_RX_DONE) { - if (b43_using_pio(dev)) - b43_pio_rx(dev->pio.queue3); - else - b43_dma_rx(dev->dma.rx_ring3); - } B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); @@ -1470,29 +1497,8 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) spin_unlock_irqrestore(&dev->wl->irq_lock, flags); } -static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx) -{ - u16 rxctl; - - rxctl = b43_read16(dev, base + B43_PIO_RXCTL); - if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE) - dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE; - else - dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE; -} - static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason) { - if (b43_using_pio(dev) && - (dev->dev->id.revision < 3) && - (!(reason & B43_IRQ_PIO_WORKAROUND))) { - /* Apply a PIO specific workaround to the dma_reasons */ - pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0); - pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1); - pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2); - pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3); - } - b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason); b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]); @@ -1551,54 +1557,73 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id) return ret; } +static void do_release_fw(struct b43_firmware_file *fw) +{ + release_firmware(fw->data); + fw->data = NULL; + fw->filename = NULL; +} + static void b43_release_firmware(struct b43_wldev *dev) { - release_firmware(dev->fw.ucode); - dev->fw.ucode = NULL; - release_firmware(dev->fw.pcm); - dev->fw.pcm = NULL; - release_firmware(dev->fw.initvals); - dev->fw.initvals = NULL; - release_firmware(dev->fw.initvals_band); - dev->fw.initvals_band = NULL; + do_release_fw(&dev->fw.ucode); + do_release_fw(&dev->fw.pcm); + do_release_fw(&dev->fw.initvals); + do_release_fw(&dev->fw.initvals_band); } -static void b43_print_fw_helptext(struct b43_wl *wl) +static void b43_print_fw_helptext(struct b43_wl *wl, bool error) { - b43err(wl, "You must go to " + const char *text; + + text = "You must go to " "http://linuxwireless.org/en/users/Drivers/b43#devicefirmware " - "and download the correct firmware (version 4).\n"); + "and download the latest firmware (version 4).\n"; + if (error) + b43err(wl, text); + else + b43warn(wl, text); } static int do_request_fw(struct b43_wldev *dev, const char *name, - const struct firmware **fw) + struct b43_firmware_file *fw) { char path[sizeof(modparam_fwpostfix) + 32]; + const struct firmware *blob; struct b43_fw_header *hdr; u32 size; int err; - if (!name) + if (!name) { + /* Don't fetch anything. Free possibly cached firmware. */ + do_release_fw(fw); return 0; + } + if (fw->filename) { + if (strcmp(fw->filename, name) == 0) + return 0; /* Already have this fw. */ + /* Free the cached firmware first. */ + do_release_fw(fw); + } snprintf(path, ARRAY_SIZE(path), "b43%s/%s.fw", modparam_fwpostfix, name); - err = request_firmware(fw, path, dev->dev->dev); + err = request_firmware(&blob, path, dev->dev->dev); if (err) { b43err(dev->wl, "Firmware file \"%s\" not found " "or load failed.\n", path); return err; } - if ((*fw)->size < sizeof(struct b43_fw_header)) + if (blob->size < sizeof(struct b43_fw_header)) goto err_format; - hdr = (struct b43_fw_header *)((*fw)->data); + hdr = (struct b43_fw_header *)(blob->data); switch (hdr->type) { case B43_FW_TYPE_UCODE: case B43_FW_TYPE_PCM: size = be32_to_cpu(hdr->size); - if (size != (*fw)->size - sizeof(struct b43_fw_header)) + if (size != blob->size - sizeof(struct b43_fw_header)) goto err_format; /* fallthrough */ case B43_FW_TYPE_IV: @@ -1609,10 +1634,15 @@ static int do_request_fw(struct b43_wldev *dev, goto err_format; } - return err; + fw->data = blob; + fw->filename = name; + + return 0; err_format: b43err(dev->wl, "Firmware file \"%s\" format error.\n", path); + release_firmware(blob); + return -EPROTO; } @@ -1624,90 +1654,101 @@ static int b43_request_firmware(struct b43_wldev *dev) u32 tmshigh; int err; + /* Get microcode */ tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); - if (!fw->ucode) { + if ((rev >= 5) && (rev <= 10)) + filename = "ucode5"; + else if ((rev >= 11) && (rev <= 12)) + filename = "ucode11"; + else if (rev >= 13) + filename = "ucode13"; + else + goto err_no_ucode; + err = do_request_fw(dev, filename, &fw->ucode); + if (err) + goto err_load; + + /* Get PCM code */ + if ((rev >= 5) && (rev <= 10)) + filename = "pcm5"; + else if (rev >= 11) + filename = NULL; + else + goto err_no_pcm; + err = do_request_fw(dev, filename, &fw->pcm); + if (err) + goto err_load; + + /* Get initvals */ + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) + filename = "a0g1initvals5"; + else + filename = "a0g0initvals5"; + } else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) - filename = "ucode5"; - else if ((rev >= 11) && (rev <= 12)) - filename = "ucode11"; + filename = "b0g0initvals5"; else if (rev >= 13) - filename = "ucode13"; + filename = "lp0initvals13"; else - goto err_no_ucode; - err = do_request_fw(dev, filename, &fw->ucode); - if (err) - goto err_load; + goto err_no_initvals; + break; + case B43_PHYTYPE_N: + if ((rev >= 11) && (rev <= 12)) + filename = "n0initvals11"; + else + goto err_no_initvals; + break; + default: + goto err_no_initvals; } - if (!fw->pcm) { + err = do_request_fw(dev, filename, &fw->initvals); + if (err) + goto err_load; + + /* Get bandswitch initvals */ + switch (dev->phy.type) { + case B43_PHYTYPE_A: + if ((rev >= 5) && (rev <= 10)) { + if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY) + filename = "a0g1bsinitvals5"; + else + filename = "a0g0bsinitvals5"; + } else if (rev >= 11) + filename = NULL; + else + goto err_no_initvals; + break; + case B43_PHYTYPE_G: if ((rev >= 5) && (rev <= 10)) - filename = "pcm5"; + filename = "b0g0bsinitvals5"; else if (rev >= 11) filename = NULL; else - goto err_no_pcm; - err = do_request_fw(dev, filename, &fw->pcm); - if (err) - goto err_load; - } - if (!fw->initvals) { - switch (dev->phy.type) { - case B43_PHYTYPE_A: - if ((rev >= 5) && (rev <= 10)) { - if (tmshigh & B43_TMSHIGH_GPHY) - filename = "a0g1initvals5"; - else - filename = "a0g0initvals5"; - } else - goto err_no_initvals; - break; - case B43_PHYTYPE_G: - if ((rev >= 5) && (rev <= 10)) - filename = "b0g0initvals5"; - else if (rev >= 13) - filename = "lp0initvals13"; - else - goto err_no_initvals; - break; - default: goto err_no_initvals; - } - err = do_request_fw(dev, filename, &fw->initvals); - if (err) - goto err_load; - } - if (!fw->initvals_band) { - switch (dev->phy.type) { - case B43_PHYTYPE_A: - if ((rev >= 5) && (rev <= 10)) { - if (tmshigh & B43_TMSHIGH_GPHY) - filename = "a0g1bsinitvals5"; - else - filename = "a0g0bsinitvals5"; - } else if (rev >= 11) - filename = NULL; - else - goto err_no_initvals; - break; - case B43_PHYTYPE_G: - if ((rev >= 5) && (rev <= 10)) - filename = "b0g0bsinitvals5"; - else if (rev >= 11) - filename = NULL; - else - goto err_no_initvals; - break; - default: + break; + case B43_PHYTYPE_N: + if ((rev >= 11) && (rev <= 12)) + filename = "n0bsinitvals11"; + else goto err_no_initvals; - } - err = do_request_fw(dev, filename, &fw->initvals_band); - if (err) - goto err_load; + break; + default: + goto err_no_initvals; } + err = do_request_fw(dev, filename, &fw->initvals_band); + if (err) + goto err_load; return 0; err_load: - b43_print_fw_helptext(dev->wl); + b43_print_fw_helptext(dev->wl, 1); goto error; err_no_ucode: @@ -1737,22 +1778,33 @@ static int b43_upload_microcode(struct b43_wldev *dev) const __be32 *data; unsigned int i, len; u16 fwrev, fwpatch, fwdate, fwtime; - u32 tmp; + u32 tmp, macctl; int err = 0; + /* Jump the microcode PSM to offset 0 */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_PSM_RUN); + macctl |= B43_MACCTL_PSM_JMP0; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + /* Zero out all microcode PSM registers and shared memory. */ + for (i = 0; i < 64; i++) + b43_shm_write16(dev, B43_SHM_SCRATCH, i, 0); + for (i = 0; i < 4096; i += 2) + b43_shm_write16(dev, B43_SHM_SHARED, i, 0); + /* Upload Microcode. */ - data = (__be32 *) (dev->fw.ucode->data + hdr_len); - len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32); + data = (__be32 *) (dev->fw.ucode.data->data + hdr_len); + len = (dev->fw.ucode.data->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000); for (i = 0; i < len; i++) { b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); } - if (dev->fw.pcm) { + if (dev->fw.pcm.data) { /* Upload PCM data. */ - data = (__be32 *) (dev->fw.pcm->data + hdr_len); - len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32); + data = (__be32 *) (dev->fw.pcm.data->data + hdr_len); + len = (dev->fw.pcm.data->size - hdr_len) / sizeof(__be32); b43_shm_control_word(dev, B43_SHM_HW, 0x01EA); b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000); /* No need for autoinc bit in SHM_HW */ @@ -1764,9 +1816,12 @@ static int b43_upload_microcode(struct b43_wldev *dev) } b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL); - b43_write32(dev, B43_MMIO_MACCTL, - B43_MACCTL_PSM_RUN | - B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA); + + /* Start the microcode PSM */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_PSM_JMP0; + macctl |= B43_MACCTL_PSM_RUN; + b43_write32(dev, B43_MMIO_MACCTL, macctl); /* Wait for the microcode to load and respond */ i = 0; @@ -1775,13 +1830,17 @@ static int b43_upload_microcode(struct b43_wldev *dev) if (tmp == B43_IRQ_MAC_SUSPENDED) break; i++; - if (i >= 50) { + if (i >= 20) { b43err(dev->wl, "Microcode not responding\n"); - b43_print_fw_helptext(dev->wl); + b43_print_fw_helptext(dev->wl, 1); err = -ENODEV; - goto out; + goto error; + } + msleep_interruptible(50); + if (signal_pending(current)) { + err = -EINTR; + goto error; } - udelay(10); } b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); /* dummy read */ @@ -1795,10 +1854,9 @@ static int b43_upload_microcode(struct b43_wldev *dev) b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from " "binary drivers older than version 4.x is unsupported. " "You must upgrade your firmware files.\n"); - b43_print_fw_helptext(dev->wl); - b43_write32(dev, B43_MMIO_MACCTL, 0); + b43_print_fw_helptext(dev->wl, 1); err = -EOPNOTSUPP; - goto out; + goto error; } b43dbg(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -1809,7 +1867,20 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.rev = fwrev; dev->fw.patch = fwpatch; - out: + if (b43_is_old_txhdr_format(dev)) { + b43warn(dev->wl, "You are using an old firmware image. " + "Support for old firmware will be removed in July 2008.\n"); + b43_print_fw_helptext(dev->wl, 0); + } + + return 0; + +error: + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_PSM_RUN; + macctl |= B43_MACCTL_PSM_JMP0; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + return err; } @@ -1869,7 +1940,7 @@ static int b43_write_initvals(struct b43_wldev *dev, err_format: b43err(dev->wl, "Initial Values Firmware file-format error.\n"); - b43_print_fw_helptext(dev->wl); + b43_print_fw_helptext(dev->wl, 1); return -EPROTO; } @@ -1883,19 +1954,19 @@ static int b43_upload_initvals(struct b43_wldev *dev) size_t count; int err; - hdr = (const struct b43_fw_header *)(fw->initvals->data); - ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len); + hdr = (const struct b43_fw_header *)(fw->initvals.data->data); + ivals = (const struct b43_iv *)(fw->initvals.data->data + hdr_len); count = be32_to_cpu(hdr->size); err = b43_write_initvals(dev, ivals, count, - fw->initvals->size - hdr_len); + fw->initvals.data->size - hdr_len); if (err) goto out; - if (fw->initvals_band) { - hdr = (const struct b43_fw_header *)(fw->initvals_band->data); - ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len); + if (fw->initvals_band.data) { + hdr = (const struct b43_fw_header *)(fw->initvals_band.data->data); + ivals = (const struct b43_iv *)(fw->initvals_band.data->data + hdr_len); count = be32_to_cpu(hdr->size); err = b43_write_initvals(dev, ivals, count, - fw->initvals_band->size - hdr_len); + fw->initvals_band.data->size - hdr_len); if (err) goto out; } @@ -1932,7 +2003,7 @@ static int b43_gpio_init(struct b43_wldev *dev) mask |= 0x0180; set |= 0x0180; } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) { b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 0x0200); @@ -2102,6 +2173,7 @@ static void b43_rate_memory_init(struct b43_wldev *dev) switch (dev->phy.type) { case B43_PHYTYPE_A: case B43_PHYTYPE_G: + case B43_PHYTYPE_N: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); @@ -2131,13 +2203,19 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) switch (antenna) { case B43_ANTENNA0: - ant |= B43_TX4_PHY_ANT0; + ant |= B43_TXH_PHY_ANT0; break; case B43_ANTENNA1: - ant |= B43_TX4_PHY_ANT1; + ant |= B43_TXH_PHY_ANT1; + break; + case B43_ANTENNA2: + ant |= B43_TXH_PHY_ANT2; + break; + case B43_ANTENNA3: + ant |= B43_TXH_PHY_ANT3; break; case B43_ANTENNA_AUTO: - ant |= B43_TX4_PHY_ANTLAST; + ant |= B43_TXH_PHY_ANT01AUTO; break; default: B43_WARN_ON(1); @@ -2147,15 +2225,15 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna) /* For Beacons */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); - tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp); /* For ACK/CTS */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL); - tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp); /* For Probe Resposes */ tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL); - tmp = (tmp & ~B43_TX4_PHY_ANT) | ant; + tmp = (tmp & ~B43_TXH_PHY_ANT) | ant; b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp); } @@ -2174,11 +2252,15 @@ static int b43_chip_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; int err, tmp; - u32 value32; + u32 value32, macctl; u16 value16; - b43_write32(dev, B43_MMIO_MACCTL, - B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED); + /* Initialize the MAC control */ + macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED; + if (dev->phy.gmode) + macctl |= B43_MACCTL_GMODE; + macctl |= B43_MACCTL_INFRA; + b43_write32(dev, B43_MMIO_MACCTL, macctl); err = b43_request_firmware(dev); if (err) @@ -2223,14 +2305,6 @@ static int b43_chip_init(struct b43_wldev *dev) b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | B43_MACCTL_INFRA); - if (b43_using_pio(dev)) { - b43_write32(dev, 0x0210, 0x00000100); - b43_write32(dev, 0x0230, 0x00000100); - b43_write32(dev, 0x0250, 0x00000100); - b43_write32(dev, 0x0270, 0x00000100); - b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000); - } - /* Probe Response Timeout value */ /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000); @@ -2292,9 +2366,11 @@ static void b43_periodic_every60sec(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + if (phy->type != B43_PHYTYPE_G) + return; if (!b43_has_hardware_pctl(phy)) b43_lo_g_ctl_mark_all_unused(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_mac_suspend(dev); b43_calc_nrssi_slope(dev); if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) { @@ -2346,6 +2422,9 @@ static void b43_periodic_every15sec(struct b43_wldev *dev) } b43_phy_xmitpower(dev); //FIXME: unless scanning? //TODO for APHY (temperature?) + + atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); + wmb(); } static void do_periodic_work(struct b43_wldev *dev) @@ -2403,32 +2482,42 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev) queue_delayed_work(dev->wl->hw->workqueue, work, 0); } -/* Validate access to the chip (SHM) */ +/* Check if communication with the device works correctly. */ static int b43_validate_chipaccess(struct b43_wldev *dev) { - u32 value; - u32 shm_backup; + u32 v, backup; - shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); - b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA); - if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) - goto error; + backup = b43_shm_read32(dev, B43_SHM_SHARED, 0); + + /* Check for read/write and endianness problems. */ b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55); if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55) goto error; - b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup); - - value = b43_read32(dev, B43_MMIO_MACCTL); - if ((value | B43_MACCTL_GMODE) != - (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED)) + b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA); + if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA) goto error; - value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON); - if (value) + b43_shm_write32(dev, B43_SHM_SHARED, 0, backup); + + if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) { + /* The 32bit register shadows the two 16bit registers + * with update sideeffects. Validate this. */ + b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA); + b43_write32(dev, B43_MMIO_TSF_CFP_START, 0xCCCCBBBB); + if (b43_read16(dev, B43_MMIO_TSF_CFP_START_LOW) != 0xBBBB) + goto error; + if (b43_read16(dev, B43_MMIO_TSF_CFP_START_HIGH) != 0xCCCC) + goto error; + } + b43_write32(dev, B43_MMIO_TSF_CFP_START, 0); + + v = b43_read32(dev, B43_MMIO_MACCTL); + v |= B43_MACCTL_GMODE; + if (v != (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED)) goto error; return 0; - error: +error: b43err(dev->wl, "Failed to validate the chipaccess\n"); return -ENODEV; } @@ -2491,40 +2580,35 @@ static int b43_rng_init(struct b43_wl *wl) return err; } -static int b43_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) +static int b43_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; int err = -ENODEV; - unsigned long flags; if (unlikely(!dev)) goto out; if (unlikely(b43_status(dev) < B43_STAT_STARTED)) goto out; /* DMA-TX is done without a global lock. */ - if (b43_using_pio(dev)) { - spin_lock_irqsave(&wl->irq_lock, flags); - err = b43_pio_tx(dev, skb, ctl); - spin_unlock_irqrestore(&wl->irq_lock, flags); - } else - err = b43_dma_tx(dev, skb, ctl); - out: + err = b43_dma_tx(dev, skb, ctl); +out: if (unlikely(err)) return NETDEV_TX_BUSY; return NETDEV_TX_OK; } -static int b43_conf_tx(struct ieee80211_hw *hw, - int queue, - const struct ieee80211_tx_queue_params *params) +static int b43_op_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) { return 0; } -static int b43_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) +static int b43_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2535,19 +2619,16 @@ static int b43_get_tx_stats(struct ieee80211_hw *hw, goto out; spin_lock_irqsave(&wl->irq_lock, flags); if (likely(b43_status(dev) >= B43_STAT_STARTED)) { - if (b43_using_pio(dev)) - b43_pio_get_tx_stats(dev, stats); - else - b43_dma_get_tx_stats(dev, stats); + b43_dma_get_tx_stats(dev, stats); err = 0; } spin_unlock_irqrestore(&wl->irq_lock, flags); - out: +out: return err; } -static int b43_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int b43_op_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { struct b43_wl *wl = hw_to_b43_wl(hw); unsigned long flags; @@ -2686,8 +2767,36 @@ static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode) return err; } -static int b43_antenna_from_ieee80211(u8 antenna) +/* Check if the use of the antenna that ieee80211 told us to + * use is possible. This will fall back to DEFAULT. + * "antenna_nr" is the antenna identifier we got from ieee80211. */ +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, + u8 antenna_nr) +{ + u8 antenna_mask; + + if (antenna_nr == 0) { + /* Zero means "use default antenna". That's always OK. */ + return 0; + } + + /* Get the mask of available antennas. */ + if (dev->phy.gmode) + antenna_mask = dev->dev->bus->sprom.ant_available_bg; + else + antenna_mask = dev->dev->bus->sprom.ant_available_a; + + if (!(antenna_mask & (1 << (antenna_nr - 1)))) { + /* This antenna is not available. Fall back to default. */ + return 0; + } + + return antenna_nr; +} + +static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) { + antenna = b43_ieee80211_antenna_sanitize(dev, antenna); switch (antenna) { case 0: /* default/diversity */ return B43_ANTENNA_DEFAULT; @@ -2695,26 +2804,26 @@ static int b43_antenna_from_ieee80211(u8 antenna) return B43_ANTENNA0; case 2: /* Antenna 1 */ return B43_ANTENNA1; + case 3: /* Antenna 2 */ + return B43_ANTENNA2; + case 4: /* Antenna 3 */ + return B43_ANTENNA3; default: return B43_ANTENNA_DEFAULT; } } -static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; unsigned long flags; unsigned int new_phymode = 0xFFFF; - int antenna_tx; - int antenna_rx; + int antenna; int err = 0; u32 savedirqs; - antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx); - antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx); - mutex_lock(&wl->mutex); /* Switch the PHY mode (if necessary). */ @@ -2764,6 +2873,8 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) b43_short_slot_timing_disable(dev); } + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + /* Adjust the desired TX power level. */ if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { @@ -2773,8 +2884,10 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } /* Antennas for RX and management frame TX. */ - b43_mgmtframe_txantenna(dev, antenna_tx); - b43_set_rx_antenna(dev, antenna_rx); + antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); + b43_mgmtframe_txantenna(dev, antenna); + antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); + b43_set_rx_antenna(dev, antenna); /* Update templates for AP mode. */ if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) @@ -2805,23 +2918,30 @@ static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) return err; } -static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev = wl->current_dev; + struct b43_wldev *dev; unsigned long flags; u8 algorithm; u8 index; - int err = -EINVAL; + int err; DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ - if (!dev) - return -ENODEV; + mutex_lock(&wl->mutex); + spin_lock_irqsave(&wl->irq_lock, flags); + + dev = wl->current_dev; + err = -ENODEV; + if (!dev || b43_status(dev) < B43_STAT_INITIALIZED) + goto out_unlock; + + err = -EINVAL; switch (key->alg) { case ALG_WEP: if (key->keylen == 5) @@ -2837,20 +2957,11 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; default: B43_WARN_ON(1); - goto out; + goto out_unlock; } - index = (u8) (key->keyidx); if (index > 3) - goto out; - - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - - if (b43_status(dev) < B43_STAT_INITIALIZED) { - err = -ENODEV; goto out_unlock; - } switch (cmd) { case SET_KEY: @@ -2896,7 +3007,6 @@ static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, out_unlock: spin_unlock_irqrestore(&wl->irq_lock, flags); mutex_unlock(&wl->mutex); -out: if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " "mac: %s\n", @@ -2906,9 +3016,9 @@ out: return err; } -static void b43_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, unsigned int *fflags, - int mc_count, struct dev_addr_list *mc_list) +static void b43_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, unsigned int *fflags, + int mc_count, struct dev_addr_list *mc_list) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2943,8 +3053,9 @@ static void b43_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43_config_interface(struct ieee80211_hw *hw, - int if_id, struct ieee80211_if_conf *conf) +static int b43_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -2954,7 +3065,7 @@ static int b43_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - B43_WARN_ON(wl->if_id != if_id); + B43_WARN_ON(wl->vif != vif); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else @@ -2964,7 +3075,7 @@ static int b43_config_interface(struct ieee80211_hw *hw, B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP); b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->beacon) - b43_refresh_templates(dev, conf->beacon); + b43_update_templates(wl, conf->beacon); } b43_write_mac_bssid_templates(dev); } @@ -3067,9 +3178,15 @@ static int b43_phy_versioning(struct b43_wldev *dev) unsupported = 1; break; case B43_PHYTYPE_G: - if (phy_rev > 8) + if (phy_rev > 9) unsupported = 1; break; +#ifdef CONFIG_B43_NPHY + case B43_PHYTYPE_N: + if (phy_rev > 1) + unsupported = 1; + break; +#endif default: unsupported = 1; }; @@ -3092,14 +3209,15 @@ static int b43_phy_versioning(struct b43_wldev *dev) tmp = 0x5205017F; } else { b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); - tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH); - tmp <<= 16; + tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID); - tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW); + tmp |= (u32)b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH) << 16; } radio_manuf = (tmp & 0x00000FFF); radio_ver = (tmp & 0x0FFFF000) >> 12; radio_rev = (tmp & 0xF0000000) >> 28; + if (radio_manuf != 0x17F /* Broadcom */) + unsupported = 1; switch (phy_type) { case B43_PHYTYPE_A: if (radio_ver != 0x2060) @@ -3117,6 +3235,10 @@ static int b43_phy_versioning(struct b43_wldev *dev) if (radio_ver != 0x2050) unsupported = 1; break; + case B43_PHYTYPE_N: + if (radio_ver != 0x2055) + unsupported = 1; + break; default: B43_WARN_ON(1); } @@ -3149,9 +3271,6 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - /* Flags */ - phy->locked = 0; - phy->aci_enable = 0; phy->aci_wlan_automatic = 0; phy->aci_hw_rssi = 0; @@ -3178,17 +3297,22 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev, phy->lofcal = 0xFFFF; phy->initval = 0xFFFF; - spin_lock_init(&phy->lock); phy->interfmode = B43_INTERFMODE_NONE; phy->channel = 0xFF; phy->hardware_power_control = !!modparam_hwpctl; + + /* PHY TX errors counter. */ + atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT); + + /* OFDM-table address caching. */ + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_UNKNOWN; } static void setup_struct_wldev_for_init(struct b43_wldev *dev) { - /* Flags */ - dev->reg124_set_0x4 = 0; + dev->dfq_valid = 0; + /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ dev->radio_hw_enable = 1; @@ -3214,13 +3338,13 @@ static void b43_bluetooth_coext_enable(struct b43_wldev *dev) struct ssb_sprom *sprom = &dev->dev->bus->sprom; u32 hf; - if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST)) + if (!(sprom->boardflags_lo & B43_BFL_BTCOEXIST)) return; if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode) return; hf = b43_hf_read(dev); - if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD) + if (sprom->boardflags_lo & B43_BFL_BTCMOD) hf |= B43_HF_BTCOEXALT; else hf |= B43_HF_BTCOEX; @@ -3259,20 +3383,42 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } +/* Write the short and long frame retry limit values. */ +static void b43_set_retry_limits(struct b43_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, + short_retry); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, + long_retry); +} + /* Shutdown a wireless core */ /* Locking: wl->mutex */ static void b43_wireless_core_exit(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; + u32 macctl; B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED); if (b43_status(dev) != B43_STAT_INITIALIZED) return; b43_set_status(dev, B43_STAT_UNINIT); + /* Stop the microcode PSM. */ + macctl = b43_read32(dev, B43_MMIO_MACCTL); + macctl &= ~B43_MACCTL_PSM_RUN; + macctl |= B43_MACCTL_PSM_JMP0; + b43_write32(dev, B43_MMIO_MACCTL, macctl); + b43_leds_exit(dev); b43_rng_exit(dev->wl); - b43_pio_free(dev); b43_dma_free(dev); b43_chip_exit(dev); b43_radio_turn_off(dev, 1); @@ -3281,6 +3427,11 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) kfree(phy->tssi2dbm); kfree(phy->lo_control); phy->lo_control = NULL; + if (dev->wl->current_beacon) { + dev_kfree_skb_any(dev->wl->current_beacon); + dev->wl->current_beacon = NULL; + } + ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(dev->dev->bus); } @@ -3335,7 +3486,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) hf |= B43_HF_SYMW; if (phy->rev == 1) hf |= B43_HF_GDCW; - if (sprom->r1.boardflags_lo & B43_BFL_PACTRL) + if (sprom->boardflags_lo & B43_BFL_PACTRL) hf |= B43_HF_OFDMPABOOST; } else if (phy->type == B43_PHYTYPE_B) { hf |= B43_HF_SYMW; @@ -3344,15 +3495,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev) } b43_hf_write(dev, hf); - /* Short/Long Retry Limit. - * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. - */ - tmp = limit_value(modparam_short_retry, 0, 0xF); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp); - tmp = limit_value(modparam_long_retry, 0, 0xF); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp); - + b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT, + B43_DEFAULT_LONG_RETRY_LIMIT); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2); @@ -3373,17 +3517,10 @@ static int b43_wireless_core_init(struct b43_wldev *dev) /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); - do { - if (b43_using_pio(dev)) { - err = b43_pio_init(dev); - } else { - err = b43_dma_init(dev); - if (!err) - b43_qos_init(dev); - } - } while (err == -EAGAIN); + err = b43_dma_init(dev); if (err) goto err_chip_exit; + b43_qos_init(dev); //FIXME #if 1 @@ -3421,8 +3558,8 @@ out: return err; } -static int b43_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static int b43_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -3445,7 +3582,7 @@ static int b43_add_interface(struct ieee80211_hw *hw, dev = wl->current_dev; wl->operating = 1; - wl->if_id = conf->if_id; + wl->vif = conf->vif; wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); @@ -3461,8 +3598,8 @@ static int b43_add_interface(struct ieee80211_hw *hw, return err; } -static void b43_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static void b43_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3473,7 +3610,8 @@ static void b43_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); B43_WARN_ON(!wl->operating); - B43_WARN_ON(wl->if_id != conf->if_id); + B43_WARN_ON(wl->vif != conf->vif); + wl->vif = NULL; wl->operating = 0; @@ -3486,7 +3624,7 @@ static void b43_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int b43_start(struct ieee80211_hw *hw) +static int b43_op_start(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3521,7 +3659,7 @@ static int b43_start(struct ieee80211_hw *hw) return err; } -static void b43_stop(struct ieee80211_hw *hw) +static void b43_op_stop(struct ieee80211_hw *hw) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -3535,19 +3673,76 @@ static void b43_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } +static int b43_op_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry_limit, u32 long_retry_limit) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + int err = 0; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) { + err = -ENODEV; + goto out_unlock; + } + b43_set_retry_limits(dev, short_retry_limit, long_retry_limit); +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, int aid, int set) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct sk_buff *beacon; + unsigned long flags; + + /* We could modify the existing beacon and set the aid bit in + * the TIM field, but that would probably require resizing and + * moving of data within the beacon template. + * Simply request a new beacon and let mac80211 do the hard work. */ + beacon = ieee80211_beacon_get(hw, wl->vif, NULL); + if (unlikely(!beacon)) + return -ENOMEM; + spin_lock_irqsave(&wl->irq_lock, flags); + b43_update_templates(wl, beacon); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + +static int b43_op_ibss_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *beacon, + struct ieee80211_tx_control *ctl) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + unsigned long flags; + + spin_lock_irqsave(&wl->irq_lock, flags); + b43_update_templates(wl, beacon); + spin_unlock_irqrestore(&wl->irq_lock, flags); + + return 0; +} + static const struct ieee80211_ops b43_hw_ops = { - .tx = b43_tx, - .conf_tx = b43_conf_tx, - .add_interface = b43_add_interface, - .remove_interface = b43_remove_interface, - .config = b43_dev_config, - .config_interface = b43_config_interface, - .configure_filter = b43_configure_filter, - .set_key = b43_dev_set_key, - .get_stats = b43_get_stats, - .get_tx_stats = b43_get_tx_stats, - .start = b43_start, - .stop = b43_stop, + .tx = b43_op_tx, + .conf_tx = b43_op_conf_tx, + .add_interface = b43_op_add_interface, + .remove_interface = b43_op_remove_interface, + .config = b43_op_config, + .config_interface = b43_op_config_interface, + .configure_filter = b43_op_configure_filter, + .set_key = b43_op_set_key, + .get_stats = b43_op_get_stats, + .get_tx_stats = b43_op_get_tx_stats, + .start = b43_op_start, + .stop = b43_op_stop, + .set_retry_limit = b43_op_set_retry_limit, + .set_tim = b43_op_beacon_set_tim, + .beacon_update = b43_op_ibss_beacon_update, }; /* Hard-reset the chip. Do not call this directly. @@ -3592,72 +3787,30 @@ static void b43_chip_reset(struct work_struct *work) } static int b43_setup_modes(struct b43_wldev *dev, - int have_aphy, int have_bphy, int have_gphy) + bool have_2ghz_phy, bool have_5ghz_phy) { struct ieee80211_hw *hw = dev->wl->hw; struct ieee80211_hw_mode *mode; struct b43_phy *phy = &dev->phy; - int cnt = 0; int err; -/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */ - have_aphy = 0; - - phy->possible_phymodes = 0; - for (; 1; cnt++) { - if (have_aphy) { - B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211A; - mode->num_channels = b43_a_chantable_size; - mode->channels = b43_a_chantable; - mode->num_rates = b43_a_ratetable_size; - mode->rates = b43_a_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43_PHYMODE_A; - have_aphy = 0; - continue; - } - if (have_bphy) { - B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211B; - mode->num_channels = b43_bg_chantable_size; - mode->channels = b43_bg_chantable; - mode->num_rates = b43_b_ratetable_size; - mode->rates = b43_b_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43_PHYMODE_B; - have_bphy = 0; - continue; - } - if (have_gphy) { - B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211G; - mode->num_channels = b43_bg_chantable_size; - mode->channels = b43_bg_chantable; - mode->num_rates = b43_g_ratetable_size; - mode->rates = b43_g_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43_PHYMODE_G; - have_gphy = 0; - continue; - } - break; - } + /* XXX: This function will go away soon, when mac80211 + * band stuff is rewritten. So this is just a hack. + * For now we always claim GPHY mode, as there is no + * support for NPHY and APHY in the device, yet. + * This assumption is OK, as any B, N or A PHY will already + * have died a horrible sanity check death earlier. */ + + mode = &phy->hwmodes[0]; + mode->mode = MODE_IEEE80211G; + mode->num_channels = b43_2ghz_chantable_size; + mode->channels = b43_2ghz_chantable; + mode->num_rates = b43_g_ratetable_size; + mode->rates = b43_g_ratetable; + err = ieee80211_register_hwmode(hw, mode); + if (err) + return err; + phy->possible_phymodes |= B43_PHYMODE_G; return 0; } @@ -3675,7 +3828,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) struct ssb_bus *bus = dev->dev->bus; struct pci_dev *pdev = bus->host_pci; int err; - int have_aphy = 0, have_bphy = 0, have_gphy = 0; + bool have_2ghz_phy = 0, have_5ghz_phy = 0; u32 tmp; /* Do NOT do any device initialization here. @@ -3695,17 +3848,12 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) u32 tmshigh; tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH); - have_aphy = !!(tmshigh & B43_TMSHIGH_APHY); - have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY); - if (!have_aphy && !have_gphy) - have_bphy = 1; - } else if (dev->dev->id.revision == 4) { - have_gphy = 1; - have_aphy = 1; + have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY); + have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY); } else - have_bphy = 1; + B43_WARN_ON(1); - dev->phy.gmode = (have_gphy || have_bphy); + dev->phy.gmode = have_2ghz_phy; tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); @@ -3717,31 +3865,34 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) (pdev->device != 0x4312 && pdev->device != 0x4319 && pdev->device != 0x4324)) { /* No multiband support. */ - have_aphy = 0; - have_bphy = 0; - have_gphy = 0; + have_2ghz_phy = 0; + have_5ghz_phy = 0; switch (dev->phy.type) { case B43_PHYTYPE_A: - have_aphy = 1; - break; - case B43_PHYTYPE_B: - have_bphy = 1; + have_5ghz_phy = 1; break; case B43_PHYTYPE_G: - have_gphy = 1; + case B43_PHYTYPE_N: + have_2ghz_phy = 1; break; default: B43_WARN_ON(1); } } - dev->phy.gmode = (have_gphy || have_bphy); + if (dev->phy.type == B43_PHYTYPE_A) { + /* FIXME */ + b43err(wl, "IEEE 802.11a devices are unsupported\n"); + err = -EOPNOTSUPP; + goto err_powerdown; + } + dev->phy.gmode = have_2ghz_phy; tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; b43_wireless_core_reset(dev, tmp); err = b43_validate_chipaccess(dev); if (err) goto err_powerdown; - err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); + err = b43_setup_modes(dev, have_2ghz_phy, have_5ghz_phy); if (err) goto err_powerdown; @@ -3812,8 +3963,6 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl) tasklet_init(&wldev->isr_tasklet, (void (*)(unsigned long))b43_interrupt_tasklet, (unsigned long)wldev); - if (modparam_pio) - wldev->__using_pio = 1; INIT_LIST_HEAD(&wldev->list); err = b43_wireless_core_attach(wldev); @@ -3838,20 +3987,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) - bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST; + bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST; if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) - bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL; - - /* Handle case when gain is not set in sprom */ - if (bus->sprom.r1.antenna_gain_a == 0xFF) - bus->sprom.r1.antenna_gain_a = 2; - if (bus->sprom.r1.antenna_gain_bg == 0xFF) - bus->sprom.r1.antenna_gain_bg = 2; - - /* Convert Antennagain values to Q5.2 */ - bus->sprom.r1.antenna_gain_a <<= 2; - bus->sprom.r1.antenna_gain_bg <<= 2; + bus->sprom.boardflags_lo |= B43_BFL_PACTRL; } static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl) @@ -3878,16 +4017,17 @@ static int b43_wireless_init(struct ssb_device *dev) } /* fill hw info */ - hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE | + IEEE80211_HW_RX_INCLUDES_FCS; hw->max_signal = 100; hw->max_rssi = -110; hw->max_noise = -110; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); - if (is_valid_ether_addr(sprom->r1.et1mac)) - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + if (is_valid_ether_addr(sprom->et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); else - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); /* Get and initialize struct b43_wl */ wl = hw_to_b43_wl(hw); @@ -3895,6 +4035,7 @@ static int b43_wireless_init(struct ssb_device *dev) wl->hw = hw; spin_lock_init(&wl->irq_lock); spin_lock_init(&wl->leds_lock); + spin_lock_init(&wl->shm_lock); mutex_init(&wl->mutex); INIT_LIST_HEAD(&wl->devlist); diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h index 08e2e56e48f4..2d52d9de9305 100644 --- a/drivers/net/wireless/b43/main.h +++ b/drivers/net/wireless/b43/main.h @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mb@bu3sch.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -84,6 +84,9 @@ static inline int b43_is_ofdm_rate(int rate) return !b43_is_cck_rate(rate); } +u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, + u8 antenna_nr); + void b43_tsf_read(struct b43_wldev *dev, u64 * tsf); void b43_tsf_write(struct b43_wldev *dev, u64 tsf); diff --git a/drivers/net/wireless/b43/nphy.c b/drivers/net/wireless/b43/nphy.c new file mode 100644 index 000000000000..705131ef4bfa --- /dev/null +++ b/drivers/net/wireless/b43/nphy.c @@ -0,0 +1,489 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n PHY support + + Copyright (c) 2008 Michael Buesch <mb@bu3sch.de> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include <linux/delay.h> +#include <linux/types.h> + +#include "b43.h" +#include "nphy.h" +#include "tables_nphy.h" + +#include <linux/delay.h> + + +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) +{//TODO +} + +void b43_nphy_xmitpower(struct b43_wldev *dev) +{//TODO +} + +static void b43_chantab_radio_upload(struct b43_wldev *dev, + const struct b43_nphy_channeltab_entry *e) +{ + b43_radio_write16(dev, B2055_PLL_REF, e->radio_pll_ref); + b43_radio_write16(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0); + b43_radio_write16(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1); + b43_radio_write16(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail); + b43_radio_write16(dev, B2055_VCO_CAL1, e->radio_vco_cal1); + b43_radio_write16(dev, B2055_VCO_CAL2, e->radio_vco_cal2); + b43_radio_write16(dev, B2055_PLL_LFC1, e->radio_pll_lfc1); + b43_radio_write16(dev, B2055_PLL_LFR1, e->radio_pll_lfr1); + b43_radio_write16(dev, B2055_PLL_LFC2, e->radio_pll_lfc2); + b43_radio_write16(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf); + b43_radio_write16(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1); + b43_radio_write16(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2); + b43_radio_write16(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune); + b43_radio_write16(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune); + b43_radio_write16(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1); + b43_radio_write16(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn); + b43_radio_write16(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim); + b43_radio_write16(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune); + b43_radio_write16(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune); + b43_radio_write16(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1); + b43_radio_write16(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn); + b43_radio_write16(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim); +} + +static void b43_chantab_phy_upload(struct b43_wldev *dev, + const struct b43_nphy_channeltab_entry *e) +{ + b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a); + b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2); + b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3); + b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4); + b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5); + b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6); +} + +static void b43_nphy_tx_power_fix(struct b43_wldev *dev) +{ + //TODO +} + +/* Tune the hardware to a new channel. Don't call this directly. + * Use b43_radio_selectchannel() */ +int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel) +{ + const struct b43_nphy_channeltab_entry *tabent; + + tabent = b43_nphy_get_chantabent(dev, channel); + if (!tabent) + return -ESRCH; + + //FIXME enable/disable band select upper20 in RXCTL + if (0 /*FIXME 5Ghz*/) + b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x20); + else + b43_radio_maskset(dev, B2055_MASTER1, 0xFF8F, 0x50); + b43_chantab_radio_upload(dev, tabent); + udelay(50); + b43_radio_write16(dev, B2055_VCO_CAL10, 5); + b43_radio_write16(dev, B2055_VCO_CAL10, 45); + b43_radio_write16(dev, B2055_VCO_CAL10, 65); + udelay(300); + if (0 /*FIXME 5Ghz*/) + b43_phy_set(dev, B43_NPHY_BANDCTL, B43_NPHY_BANDCTL_5GHZ); + else + b43_phy_mask(dev, B43_NPHY_BANDCTL, ~B43_NPHY_BANDCTL_5GHZ); + b43_chantab_phy_upload(dev, tabent); + b43_nphy_tx_power_fix(dev); + + return 0; +} + +static void b43_radio_init2055_pre(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_PORFORCE); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_CHIP0PU | + B43_NPHY_RFCTL_CMD_OEPORFORCE); + b43_phy_set(dev, B43_NPHY_RFCTL_CMD, + B43_NPHY_RFCTL_CMD_PORFORCE); +} + +static void b43_radio_init2055_post(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = &(dev->dev->bus->sprom); + struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo); + int i; + u16 val; + + b43_radio_mask(dev, B2055_MASTER1, 0xFFF3); + msleep(1); + if ((sprom->revision != 4) || !(sprom->boardflags_hi & 0x0002)) { + if ((binfo->vendor != PCI_VENDOR_ID_BROADCOM) || + (binfo->type != 0x46D) || + (binfo->rev < 0x41)) { + b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); + b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F); + msleep(1); + } + } + b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0x3F, 0x2C); + msleep(1); + b43_radio_write16(dev, B2055_CAL_MISC, 0x3C); + msleep(1); + b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE); + msleep(1); + b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80); + msleep(1); + b43_radio_set(dev, B2055_CAL_MISC, 0x1); + msleep(1); + b43_radio_set(dev, B2055_CAL_MISC, 0x40); + msleep(1); + for (i = 0; i < 100; i++) { + val = b43_radio_read16(dev, B2055_CAL_COUT2); + if (val & 0x80) + break; + udelay(10); + } + msleep(1); + b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F); + msleep(1); + b43_radio_selectchannel(dev, dev->phy.channel, 0); + b43_radio_write16(dev, B2055_C1_RX_BB_LPF, 0x9); + b43_radio_write16(dev, B2055_C2_RX_BB_LPF, 0x9); + b43_radio_write16(dev, B2055_C1_RX_BB_MIDACHP, 0x83); + b43_radio_write16(dev, B2055_C2_RX_BB_MIDACHP, 0x83); +} + +/* Initialize a Broadcom 2055 N-radio */ +static void b43_radio_init2055(struct b43_wldev *dev) +{ + b43_radio_init2055_pre(dev); + if (b43_status(dev) < B43_STAT_INITIALIZED) + b2055_upload_inittab(dev, 0, 1); + else + b2055_upload_inittab(dev, 0/*FIXME on 5ghz band*/, 0); + b43_radio_init2055_post(dev); +} + +void b43_nphy_radio_turn_on(struct b43_wldev *dev) +{ + b43_radio_init2055(dev); +} + +void b43_nphy_radio_turn_off(struct b43_wldev *dev) +{ + b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, + ~B43_NPHY_RFCTL_CMD_EN); +} + +#define ntab_upload(dev, offset, data) do { \ + unsigned int i; \ + for (i = 0; i < (offset##_SIZE); i++) \ + b43_ntab_write(dev, (offset) + i, (data)[i]); \ + } while (0) + +/* Upload the N-PHY tables. */ +static void b43_nphy_tables_init(struct b43_wldev *dev) +{ + /* Static tables */ + ntab_upload(dev, B43_NTAB_FRAMESTRUCT, b43_ntab_framestruct); + ntab_upload(dev, B43_NTAB_FRAMELT, b43_ntab_framelookup); + ntab_upload(dev, B43_NTAB_TMAP, b43_ntab_tmap); + ntab_upload(dev, B43_NTAB_TDTRN, b43_ntab_tdtrn); + ntab_upload(dev, B43_NTAB_INTLEVEL, b43_ntab_intlevel); + ntab_upload(dev, B43_NTAB_PILOT, b43_ntab_pilot); + ntab_upload(dev, B43_NTAB_PILOTLT, b43_ntab_pilotlt); + ntab_upload(dev, B43_NTAB_TDI20A0, b43_ntab_tdi20a0); + ntab_upload(dev, B43_NTAB_TDI20A1, b43_ntab_tdi20a1); + ntab_upload(dev, B43_NTAB_TDI40A0, b43_ntab_tdi40a0); + ntab_upload(dev, B43_NTAB_TDI40A1, b43_ntab_tdi40a1); + ntab_upload(dev, B43_NTAB_BDI, b43_ntab_bdi); + ntab_upload(dev, B43_NTAB_CHANEST, b43_ntab_channelest); + ntab_upload(dev, B43_NTAB_MCS, b43_ntab_mcs); + + /* Volatile tables */ + ntab_upload(dev, B43_NTAB_NOISEVAR10, b43_ntab_noisevar10); + ntab_upload(dev, B43_NTAB_NOISEVAR11, b43_ntab_noisevar11); + ntab_upload(dev, B43_NTAB_C0_ESTPLT, b43_ntab_estimatepowerlt0); + ntab_upload(dev, B43_NTAB_C1_ESTPLT, b43_ntab_estimatepowerlt1); + ntab_upload(dev, B43_NTAB_C0_ADJPLT, b43_ntab_adjustpower0); + ntab_upload(dev, B43_NTAB_C1_ADJPLT, b43_ntab_adjustpower1); + ntab_upload(dev, B43_NTAB_C0_GAINCTL, b43_ntab_gainctl0); + ntab_upload(dev, B43_NTAB_C1_GAINCTL, b43_ntab_gainctl1); + ntab_upload(dev, B43_NTAB_C0_IQLT, b43_ntab_iqlt0); + ntab_upload(dev, B43_NTAB_C1_IQLT, b43_ntab_iqlt1); + ntab_upload(dev, B43_NTAB_C0_LOFEEDTH, b43_ntab_loftlt0); + ntab_upload(dev, B43_NTAB_C1_LOFEEDTH, b43_ntab_loftlt1); +} + +static void b43_nphy_workarounds(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + unsigned int i; + + b43_phy_set(dev, B43_NPHY_IQFLIP, + B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + //FIXME the following condition is different in the specs. + if (1 /* FIXME band is 2.4GHz */) { + b43_phy_set(dev, B43_NPHY_CLASSCTL, + B43_NPHY_CLASSCTL_CCKEN); + } else { + b43_phy_mask(dev, B43_NPHY_CLASSCTL, + ~B43_NPHY_CLASSCTL_CCKEN); + } + b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); + b43_phy_write(dev, B43_NPHY_TXFRAMEDELAY, 8); + + /* Fixup some tables */ + b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0xA); + b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0); + b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x800); + b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x800); + + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); + + //TODO set RF sequence + + /* Set narrowband clip threshold */ + b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 66); + b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 66); + + /* Set wideband clip 2 threshold */ + b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES, + ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES, + ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, + 21 << B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT); + + /* Set Clip 2 detect */ + b43_phy_set(dev, B43_NPHY_C1_CGAINI, + B43_NPHY_C1_CGAINI_CL2DETECT); + b43_phy_set(dev, B43_NPHY_C2_CGAINI, + B43_NPHY_C2_CGAINI_CL2DETECT); + + if (0 /*FIXME*/) { + /* Set dwell lengths */ + b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 43); + b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 9); + b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 9); + + /* Set gain backoff */ + b43_phy_maskset(dev, B43_NPHY_C1_CGAINI, + ~B43_NPHY_C1_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_CGAINI, + ~B43_NPHY_C2_CGAINI_GAINBKOFF, + 1 << B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT); + + /* Set HPVGA2 index */ + b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, + ~B43_NPHY_C1_INITGAIN_HPVGA2, + 6 << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, + ~B43_NPHY_C2_INITGAIN_HPVGA2, + 6 << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT); + + //FIXME verify that the specs really mean to use autoinc here. + for (i = 0; i < 3; i++) + b43_ntab_write(dev, B43_NTAB16(7, 0x106) + i, 0x673); + } + + /* Set minimum gain value */ + b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, + ~B43_NPHY_C1_MINGAIN, + 23 << B43_NPHY_C1_MINGAIN_SHIFT); + b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, + ~B43_NPHY_C2_MINGAIN, + 23 << B43_NPHY_C2_MINGAIN_SHIFT); + + if (phy->rev < 2) { + b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, + ~B43_NPHY_SCRAM_SIGCTL_SCM); + } + + /* Set phase track alpha and beta */ + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); +} + +static void b43_nphy_reset_cca(struct b43_wldev *dev) +{ + u16 bbcfg; + + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | SSB_TMSLOW_FGC); + bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); + b43_phy_set(dev, B43_NPHY_BBCFG, B43_NPHY_BBCFG_RSTCCA); + b43_phy_write(dev, B43_NPHY_BBCFG, + bbcfg & ~B43_NPHY_BBCFG_RSTCCA); + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) & ~SSB_TMSLOW_FGC); +} + +enum b43_nphy_rf_sequence { + B43_RFSEQ_RX2TX, + B43_RFSEQ_TX2RX, + B43_RFSEQ_RESET2RX, + B43_RFSEQ_UPDATE_GAINH, + B43_RFSEQ_UPDATE_GAINL, + B43_RFSEQ_UPDATE_GAINU, +}; + +static void b43_nphy_force_rf_sequence(struct b43_wldev *dev, + enum b43_nphy_rf_sequence seq) +{ + static const u16 trigger[] = { + [B43_RFSEQ_RX2TX] = B43_NPHY_RFSEQTR_RX2TX, + [B43_RFSEQ_TX2RX] = B43_NPHY_RFSEQTR_TX2RX, + [B43_RFSEQ_RESET2RX] = B43_NPHY_RFSEQTR_RST2RX, + [B43_RFSEQ_UPDATE_GAINH] = B43_NPHY_RFSEQTR_UPGH, + [B43_RFSEQ_UPDATE_GAINL] = B43_NPHY_RFSEQTR_UPGL, + [B43_RFSEQ_UPDATE_GAINU] = B43_NPHY_RFSEQTR_UPGU, + }; + int i; + + B43_WARN_ON(seq >= ARRAY_SIZE(trigger)); + + b43_phy_set(dev, B43_NPHY_RFSEQMODE, + B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER); + b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]); + for (i = 0; i < 200; i++) { + if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq])) + goto ok; + msleep(1); + } + b43err(dev->wl, "RF sequence status timeout\n"); +ok: + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER)); +} + +static void b43_nphy_bphy_init(struct b43_wldev *dev) +{ + unsigned int i; + u16 val; + + val = 0x1E1F; + for (i = 0; i < 14; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); + val -= 0x202; + } + val = 0x3E3F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x97 + i), val); + val -= 0x202; + } + b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); +} + +/* RSSI Calibration */ +static void b43_nphy_rssi_cal(struct b43_wldev *dev, u8 type) +{ + //TODO +} + +int b43_phy_initn(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 tmp; + + //TODO: Spectral management + b43_nphy_tables_init(dev); + + /* Clear all overrides */ + b43_phy_write(dev, B43_NPHY_RFCTL_OVER, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC3, 0); + b43_phy_write(dev, B43_NPHY_RFCTL_INTC4, 0); + b43_phy_mask(dev, B43_NPHY_RFSEQMODE, + ~(B43_NPHY_RFSEQMODE_CAOVER | + B43_NPHY_RFSEQMODE_TROVER)); + b43_phy_write(dev, B43_NPHY_AFECTL_OVER, 0); + + tmp = (phy->rev < 2) ? 64 : 59; + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, + ~B43_NPHY_BPHY_CTL3_SCALE, + tmp << B43_NPHY_BPHY_CTL3_SCALE_SHIFT); + + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); + b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); + + b43_phy_write(dev, B43_NPHY_TXREALFD, 184); + b43_phy_write(dev, B43_NPHY_MIMO_CRSTXEXT, 200); + b43_phy_write(dev, B43_NPHY_PLOAD_CSENSE_EXTLEN, 80); + b43_phy_write(dev, B43_NPHY_C2_BCLIPBKOFF, 511); + + //TODO MIMO-Config + //TODO Update TX/RX chain + + if (phy->rev < 2) { + b43_phy_write(dev, B43_NPHY_DUP40_GFBL, 0xAA8); + b43_phy_write(dev, B43_NPHY_DUP40_BL, 0x9A4); + } + b43_nphy_workarounds(dev); + b43_nphy_reset_cca(dev); + + ssb_write32(dev->dev, SSB_TMSLOW, + ssb_read32(dev->dev, SSB_TMSLOW) | B43_TMSLOW_MACPHYCLKEN); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX); + b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); + + b43_phy_read(dev, B43_NPHY_CLASSCTL); /* dummy read */ + //TODO read core1/2 clip1 thres regs + + if (1 /* FIXME Band is 2.4GHz */) + b43_nphy_bphy_init(dev); + //TODO disable TX power control + //TODO Fix the TX power settings + //TODO Init periodic calibration with reason 3 + b43_nphy_rssi_cal(dev, 2); + b43_nphy_rssi_cal(dev, 0); + b43_nphy_rssi_cal(dev, 1); + //TODO get TX gain + //TODO init superswitch + //TODO calibrate LO + //TODO idle TSSI TX pctl + //TODO TX power control power setup + //TODO table writes + //TODO TX power control coefficients + //TODO enable TX power control + //TODO control antenna selection + //TODO init radar detection + //TODO reset channel if changed + + b43err(dev->wl, "IEEE 802.11n devices are not supported, yet.\n"); + return 0; +} diff --git a/drivers/net/wireless/b43/nphy.h b/drivers/net/wireless/b43/nphy.h new file mode 100644 index 000000000000..5d95118b8193 --- /dev/null +++ b/drivers/net/wireless/b43/nphy.h @@ -0,0 +1,932 @@ +#ifndef B43_NPHY_H_ +#define B43_NPHY_H_ + +#include "phy.h" + + +/* N-PHY registers. */ + +#define B43_NPHY_BBCFG B43_PHY_N(0x001) /* BB config */ +#define B43_NPHY_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_NPHY_BBCFG_RSTRX 0x8000 /* Reset RX */ +#define B43_NPHY_CHANNEL B43_PHY_N(0x005) /* Channel */ +#define B43_NPHY_TXERR B43_PHY_N(0x007) /* TX error */ +#define B43_NPHY_BANDCTL B43_PHY_N(0x009) /* Band control */ +#define B43_NPHY_BANDCTL_5GHZ 0x0001 /* Use the 5GHz band */ +#define B43_NPHY_4WI_ADDR B43_PHY_N(0x00B) /* Four-wire bus address */ +#define B43_NPHY_4WI_DATAHI B43_PHY_N(0x00C) /* Four-wire bus data high */ +#define B43_NPHY_4WI_DATALO B43_PHY_N(0x00D) /* Four-wire bus data low */ +#define B43_NPHY_BIST_STAT0 B43_PHY_N(0x00E) /* Built-in self test status 0 */ +#define B43_NPHY_BIST_STAT1 B43_PHY_N(0x00F) /* Built-in self test status 1 */ + +#define B43_NPHY_C1_DESPWR B43_PHY_N(0x018) /* Core 1 desired power */ +#define B43_NPHY_C1_CCK_DESPWR B43_PHY_N(0x019) /* Core 1 CCK desired power */ +#define B43_NPHY_C1_BCLIPBKOFF B43_PHY_N(0x01A) /* Core 1 barely clip backoff */ +#define B43_NPHY_C1_CCK_BCLIPBKOFF B43_PHY_N(0x01B) /* Core 1 CCK barely clip backoff */ +#define B43_NPHY_C1_CGAINI B43_PHY_N(0x01C) /* Core 1 compute gain info */ +#define B43_NPHY_C1_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C1_CGAINI_GAINBKOFF_SHIFT 0 +#define B43_NPHY_C1_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ +#define B43_NPHY_C1_CGAINI_CLIPGBKOFF_SHIFT 5 +#define B43_NPHY_C1_CGAINI_GAINSTEP 0x1C00 /* Gain step */ +#define B43_NPHY_C1_CGAINI_GAINSTEP_SHIFT 10 +#define B43_NPHY_C1_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ +#define B43_NPHY_C1_CCK_CGAINI B43_PHY_N(0x01D) /* Core 1 CCK compute gain info */ +#define B43_NPHY_C1_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C1_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ +#define B43_NPHY_C1_MINMAX_GAIN B43_PHY_N(0x01E) /* Core 1 min/max gain */ +#define B43_NPHY_C1_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C1_MINGAIN_SHIFT 0 +#define B43_NPHY_C1_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C1_MAXGAIN_SHIFT 8 +#define B43_NPHY_C1_CCK_MINMAX_GAIN B43_PHY_N(0x01F) /* Core 1 CCK min/max gain */ +#define B43_NPHY_C1_CCK_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C1_CCK_MINGAIN_SHIFT 0 +#define B43_NPHY_C1_CCK_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C1_CCK_MAXGAIN_SHIFT 8 +#define B43_NPHY_C1_INITGAIN B43_PHY_N(0x020) /* Core 1 initial gain code */ +#define B43_NPHY_C1_INITGAIN_EXTLNA 0x0001 /* External LNA index */ +#define B43_NPHY_C1_INITGAIN_LNA 0x0006 /* LNA index */ +#define B43_NPHY_C1_INITGAIN_LNAIDX_SHIFT 1 +#define B43_NPHY_C1_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ +#define B43_NPHY_C1_INITGAIN_HPVGA1_SHIFT 3 +#define B43_NPHY_C1_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ +#define B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT 7 +#define B43_NPHY_C1_INITGAIN_TRRX 0x1000 /* TR RX index */ +#define B43_NPHY_C1_INITGAIN_TRTX 0x2000 /* TR TX index */ +#define B43_NPHY_C1_CLIP1_HIGAIN B43_PHY_N(0x021) /* Core 1 clip1 high gain code */ +#define B43_NPHY_C1_CLIP1_MEDGAIN B43_PHY_N(0x022) /* Core 1 clip1 medium gain code */ +#define B43_NPHY_C1_CLIP1_LOGAIN B43_PHY_N(0x023) /* Core 1 clip1 low gain code */ +#define B43_NPHY_C1_CLIP2_GAIN B43_PHY_N(0x024) /* Core 1 clip2 gain code */ +#define B43_NPHY_C1_FILTERGAIN B43_PHY_N(0x025) /* Core 1 filter gain */ +#define B43_NPHY_C1_LPF_QHPF_BW B43_PHY_N(0x026) /* Core 1 LPF Q HP F bandwidth */ +#define B43_NPHY_C1_CLIPWBTHRES B43_PHY_N(0x027) /* Core 1 clip wideband threshold */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP2_SHIFT 0 +#define B43_NPHY_C1_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ +#define B43_NPHY_C1_CLIPWBTHRES_CLIP1_SHIFT 6 +#define B43_NPHY_C1_W1THRES B43_PHY_N(0x028) /* Core 1 W1 threshold */ +#define B43_NPHY_C1_EDTHRES B43_PHY_N(0x029) /* Core 1 ED threshold */ +#define B43_NPHY_C1_SMSIGTHRES B43_PHY_N(0x02A) /* Core 1 small sig threshold */ +#define B43_NPHY_C1_NBCLIPTHRES B43_PHY_N(0x02B) /* Core 1 NB clip threshold */ +#define B43_NPHY_C1_CLIP1THRES B43_PHY_N(0x02C) /* Core 1 clip1 threshold */ +#define B43_NPHY_C1_CLIP2THRES B43_PHY_N(0x02D) /* Core 1 clip2 threshold */ + +#define B43_NPHY_C2_DESPWR B43_PHY_N(0x02E) /* Core 2 desired power */ +#define B43_NPHY_C2_CCK_DESPWR B43_PHY_N(0x02F) /* Core 2 CCK desired power */ +#define B43_NPHY_C2_BCLIPBKOFF B43_PHY_N(0x030) /* Core 2 barely clip backoff */ +#define B43_NPHY_C2_CCK_BCLIPBKOFF B43_PHY_N(0x031) /* Core 2 CCK barely clip backoff */ +#define B43_NPHY_C2_CGAINI B43_PHY_N(0x032) /* Core 2 compute gain info */ +#define B43_NPHY_C2_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C2_CGAINI_GAINBKOFF_SHIFT 0 +#define B43_NPHY_C2_CGAINI_CLIPGBKOFF 0x03E0 /* Clip gain backoff */ +#define B43_NPHY_C2_CGAINI_CLIPGBKOFF_SHIFT 5 +#define B43_NPHY_C2_CGAINI_GAINSTEP 0x1C00 /* Gain step */ +#define B43_NPHY_C2_CGAINI_GAINSTEP_SHIFT 10 +#define B43_NPHY_C2_CGAINI_CL2DETECT 0x2000 /* Clip 2 detect mask */ +#define B43_NPHY_C2_CCK_CGAINI B43_PHY_N(0x033) /* Core 2 CCK compute gain info */ +#define B43_NPHY_C2_CCK_CGAINI_GAINBKOFF 0x001F /* Gain backoff */ +#define B43_NPHY_C2_CCK_CGAINI_CLIPGBKOFF 0x01E0 /* CCK barely clip gain backoff */ +#define B43_NPHY_C2_MINMAX_GAIN B43_PHY_N(0x034) /* Core 2 min/max gain */ +#define B43_NPHY_C2_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C2_MINGAIN_SHIFT 0 +#define B43_NPHY_C2_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C2_MAXGAIN_SHIFT 8 +#define B43_NPHY_C2_CCK_MINMAX_GAIN B43_PHY_N(0x035) /* Core 2 CCK min/max gain */ +#define B43_NPHY_C2_CCK_MINGAIN 0x00FF /* Minimum gain */ +#define B43_NPHY_C2_CCK_MINGAIN_SHIFT 0 +#define B43_NPHY_C2_CCK_MAXGAIN 0xFF00 /* Maximum gain */ +#define B43_NPHY_C2_CCK_MAXGAIN_SHIFT 8 +#define B43_NPHY_C2_INITGAIN B43_PHY_N(0x036) /* Core 2 initial gain code */ +#define B43_NPHY_C2_INITGAIN_EXTLNA 0x0001 /* External LNA index */ +#define B43_NPHY_C2_INITGAIN_LNA 0x0006 /* LNA index */ +#define B43_NPHY_C2_INITGAIN_LNAIDX_SHIFT 1 +#define B43_NPHY_C2_INITGAIN_HPVGA1 0x0078 /* HPVGA1 index */ +#define B43_NPHY_C2_INITGAIN_HPVGA1_SHIFT 3 +#define B43_NPHY_C2_INITGAIN_HPVGA2 0x0F80 /* HPVGA2 index */ +#define B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT 7 +#define B43_NPHY_C2_INITGAIN_TRRX 0x1000 /* TR RX index */ +#define B43_NPHY_C2_INITGAIN_TRTX 0x2000 /* TR TX index */ +#define B43_NPHY_C2_CLIP1_HIGAIN B43_PHY_N(0x037) /* Core 2 clip1 high gain code */ +#define B43_NPHY_C2_CLIP1_MEDGAIN B43_PHY_N(0x038) /* Core 2 clip1 medium gain code */ +#define B43_NPHY_C2_CLIP1_LOGAIN B43_PHY_N(0x039) /* Core 2 clip1 low gain code */ +#define B43_NPHY_C2_CLIP2_GAIN B43_PHY_N(0x03A) /* Core 2 clip2 gain code */ +#define B43_NPHY_C2_FILTERGAIN B43_PHY_N(0x03B) /* Core 2 filter gain */ +#define B43_NPHY_C2_LPF_QHPF_BW B43_PHY_N(0x03C) /* Core 2 LPF Q HP F bandwidth */ +#define B43_NPHY_C2_CLIPWBTHRES B43_PHY_N(0x03D) /* Core 2 clip wideband threshold */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP2 0x003F /* Clip 2 */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP2_SHIFT 0 +#define B43_NPHY_C2_CLIPWBTHRES_CLIP1 0x0FC0 /* Clip 1 */ +#define B43_NPHY_C2_CLIPWBTHRES_CLIP1_SHIFT 6 +#define B43_NPHY_C2_W1THRES B43_PHY_N(0x03E) /* Core 2 W1 threshold */ +#define B43_NPHY_C2_EDTHRES B43_PHY_N(0x03F) /* Core 2 ED threshold */ +#define B43_NPHY_C2_SMSIGTHRES B43_PHY_N(0x040) /* Core 2 small sig threshold */ +#define B43_NPHY_C2_NBCLIPTHRES B43_PHY_N(0x041) /* Core 2 NB clip threshold */ +#define B43_NPHY_C2_CLIP1THRES B43_PHY_N(0x042) /* Core 2 clip1 threshold */ +#define B43_NPHY_C2_CLIP2THRES B43_PHY_N(0x043) /* Core 2 clip2 threshold */ + +#define B43_NPHY_CRS_THRES1 B43_PHY_N(0x044) /* CRS threshold 1 */ +#define B43_NPHY_CRS_THRES2 B43_PHY_N(0x045) /* CRS threshold 2 */ +#define B43_NPHY_CRS_THRES3 B43_PHY_N(0x046) /* CRS threshold 3 */ +#define B43_NPHY_CRSCTL B43_PHY_N(0x047) /* CRS control */ +#define B43_NPHY_DCFADDR B43_PHY_N(0x048) /* DC filter address */ +#define B43_NPHY_RXF20_NUM0 B43_PHY_N(0x049) /* RX filter 20 numerator 0 */ +#define B43_NPHY_RXF20_NUM1 B43_PHY_N(0x04A) /* RX filter 20 numerator 1 */ +#define B43_NPHY_RXF20_NUM2 B43_PHY_N(0x04B) /* RX filter 20 numerator 2 */ +#define B43_NPHY_RXF20_DENOM0 B43_PHY_N(0x04C) /* RX filter 20 denominator 0 */ +#define B43_NPHY_RXF20_DENOM1 B43_PHY_N(0x04D) /* RX filter 20 denominator 1 */ +#define B43_NPHY_RXF20_NUM10 B43_PHY_N(0x04E) /* RX filter 20 numerator 10 */ +#define B43_NPHY_RXF20_NUM11 B43_PHY_N(0x04F) /* RX filter 20 numerator 11 */ +#define B43_NPHY_RXF20_NUM12 B43_PHY_N(0x050) /* RX filter 20 numerator 12 */ +#define B43_NPHY_RXF20_DENOM10 B43_PHY_N(0x051) /* RX filter 20 denominator 10 */ +#define B43_NPHY_RXF20_DENOM11 B43_PHY_N(0x052) /* RX filter 20 denominator 11 */ +#define B43_NPHY_RXF40_NUM0 B43_PHY_N(0x053) /* RX filter 40 numerator 0 */ +#define B43_NPHY_RXF40_NUM1 B43_PHY_N(0x054) /* RX filter 40 numerator 1 */ +#define B43_NPHY_RXF40_NUM2 B43_PHY_N(0x055) /* RX filter 40 numerator 2 */ +#define B43_NPHY_RXF40_DENOM0 B43_PHY_N(0x056) /* RX filter 40 denominator 0 */ +#define B43_NPHY_RXF40_DENOM1 B43_PHY_N(0x057) /* RX filter 40 denominator 1 */ +#define B43_NPHY_RXF40_NUM10 B43_PHY_N(0x058) /* RX filter 40 numerator 10 */ +#define B43_NPHY_RXF40_NUM11 B43_PHY_N(0x059) /* RX filter 40 numerator 11 */ +#define B43_NPHY_RXF40_NUM12 B43_PHY_N(0x05A) /* RX filter 40 numerator 12 */ +#define B43_NPHY_RXF40_DENOM10 B43_PHY_N(0x05B) /* RX filter 40 denominator 10 */ +#define B43_NPHY_RXF40_DENOM11 B43_PHY_N(0x05C) /* RX filter 40 denominator 11 */ +#define B43_NPHY_PPROC_RSTLEN B43_PHY_N(0x060) /* Packet processing reset length */ +#define B43_NPHY_INITCARR_DLEN B43_PHY_N(0x061) /* Initial carrier detection length */ +#define B43_NPHY_CLIP1CARR_DLEN B43_PHY_N(0x062) /* Clip1 carrier detection length */ +#define B43_NPHY_CLIP2CARR_DLEN B43_PHY_N(0x063) /* Clip2 carrier detection length */ +#define B43_NPHY_INITGAIN_SLEN B43_PHY_N(0x064) /* Initial gain settle length */ +#define B43_NPHY_CLIP1GAIN_SLEN B43_PHY_N(0x065) /* Clip1 gain settle length */ +#define B43_NPHY_CLIP2GAIN_SLEN B43_PHY_N(0x066) /* Clip2 gain settle length */ +#define B43_NPHY_PACKGAIN_SLEN B43_PHY_N(0x067) /* Packet gain settle length */ +#define B43_NPHY_CARRSRC_TLEN B43_PHY_N(0x068) /* Carrier search timeout length */ +#define B43_NPHY_TISRC_TLEN B43_PHY_N(0x069) /* Timing search timeout length */ +#define B43_NPHY_ENDROP_TLEN B43_PHY_N(0x06A) /* Energy drop timeout length */ +#define B43_NPHY_CLIP1_NBDWELL_LEN B43_PHY_N(0x06B) /* Clip1 NB dwell length */ +#define B43_NPHY_CLIP2_NBDWELL_LEN B43_PHY_N(0x06C) /* Clip2 NB dwell length */ +#define B43_NPHY_W1CLIP1_DWELL_LEN B43_PHY_N(0x06D) /* W1 clip1 dwell length */ +#define B43_NPHY_W1CLIP2_DWELL_LEN B43_PHY_N(0x06E) /* W1 clip2 dwell length */ +#define B43_NPHY_W2CLIP1_DWELL_LEN B43_PHY_N(0x06F) /* W2 clip1 dwell length */ +#define B43_NPHY_PLOAD_CSENSE_EXTLEN B43_PHY_N(0x070) /* Payload carrier sense extension length */ +#define B43_NPHY_EDROP_CSENSE_EXTLEN B43_PHY_N(0x071) /* Energy drop carrier sense extension length */ +#define B43_NPHY_TABLE_ADDR B43_PHY_N(0x072) /* Table address */ +#define B43_NPHY_TABLE_DATALO B43_PHY_N(0x073) /* Table data low */ +#define B43_NPHY_TABLE_DATAHI B43_PHY_N(0x074) /* Table data high */ +#define B43_NPHY_WWISE_LENIDX B43_PHY_N(0x075) /* WWiSE length index */ +#define B43_NPHY_TGNSYNC_LENIDX B43_PHY_N(0x076) /* TGNsync length index */ +#define B43_NPHY_TXMACIF_HOLDOFF B43_PHY_N(0x077) /* TX MAC IF Hold off */ +#define B43_NPHY_RFCTL_CMD B43_PHY_N(0x078) /* RF control (command) */ +#define B43_NPHY_RFCTL_CMD_START 0x0001 /* Start sequence */ +#define B43_NPHY_RFCTL_CMD_RXTX 0x0002 /* RX/TX */ +#define B43_NPHY_RFCTL_CMD_CORESEL 0x0038 /* Core select */ +#define B43_NPHY_RFCTL_CMD_CORESEL_SHIFT 3 +#define B43_NPHY_RFCTL_CMD_PORFORCE 0x0040 /* POR force */ +#define B43_NPHY_RFCTL_CMD_OEPORFORCE 0x0080 /* OE POR force */ +#define B43_NPHY_RFCTL_CMD_RXEN 0x0100 /* RX enable */ +#define B43_NPHY_RFCTL_CMD_TXEN 0x0200 /* TX enable */ +#define B43_NPHY_RFCTL_CMD_CHIP0PU 0x0400 /* Chip0 PU */ +#define B43_NPHY_RFCTL_CMD_EN 0x0800 /* Radio enabled */ +#define B43_NPHY_RFCTL_CMD_SEQENCORE 0xF000 /* Seq en core */ +#define B43_NPHY_RFCTL_CMD_SEQENCORE_SHIFT 12 +#define B43_NPHY_RFCTL_RSSIO1 B43_PHY_N(0x07A) /* RF control (RSSI others 1) */ +#define B43_NPHY_RFCTL_RSSIO1_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO1_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO1_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO1_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO1_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO1_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO1_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG1 B43_PHY_N(0x07B) /* RF control (RX gain 1) */ +#define B43_NPHY_RFCTL_TXG1 B43_PHY_N(0x07C) /* RF control (TX gain 1) */ +#define B43_NPHY_RFCTL_RSSIO2 B43_PHY_N(0x07D) /* RF control (RSSI others 2) */ +#define B43_NPHY_RFCTL_RSSIO2_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO2_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO2_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO2_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO2_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO2_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO2_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG2 B43_PHY_N(0x07E) /* RF control (RX gain 2) */ +#define B43_NPHY_RFCTL_TXG2 B43_PHY_N(0x07F) /* RF control (TX gain 2) */ +#define B43_NPHY_RFCTL_RSSIO3 B43_PHY_N(0x080) /* RF control (RSSI others 3) */ +#define B43_NPHY_RFCTL_RSSIO3_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO3_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO3_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO3_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO3_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO3_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO3_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG3 B43_PHY_N(0x081) /* RF control (RX gain 3) */ +#define B43_NPHY_RFCTL_TXG3 B43_PHY_N(0x082) /* RF control (TX gain 3) */ +#define B43_NPHY_RFCTL_RSSIO4 B43_PHY_N(0x083) /* RF control (RSSI others 4) */ +#define B43_NPHY_RFCTL_RSSIO4_RXPD 0x0001 /* RX PD */ +#define B43_NPHY_RFCTL_RSSIO4_TXPD 0x0002 /* TX PD */ +#define B43_NPHY_RFCTL_RSSIO4_PAPD 0x0004 /* PA PD */ +#define B43_NPHY_RFCTL_RSSIO4_RSSICTL 0x0030 /* RSSI control */ +#define B43_NPHY_RFCTL_RSSIO4_LPFBW 0x00C0 /* LPF bandwidth */ +#define B43_NPHY_RFCTL_RSSIO4_HPFBWHI 0x0100 /* HPF bandwidth high */ +#define B43_NPHY_RFCTL_RSSIO4_HIQDISCO 0x0200 /* HIQ dis core */ +#define B43_NPHY_RFCTL_RXG4 B43_PHY_N(0x084) /* RF control (RX gain 4) */ +#define B43_NPHY_RFCTL_TXG4 B43_PHY_N(0x085) /* RF control (TX gain 4) */ +#define B43_NPHY_C1_TXIQ_COMP_OFF B43_PHY_N(0x087) /* Core 1 TX I/Q comp offset */ +#define B43_NPHY_C2_TXIQ_COMP_OFF B43_PHY_N(0x088) /* Core 2 TX I/Q comp offset */ +#define B43_NPHY_C1_TXCTL B43_PHY_N(0x08B) /* Core 1 TX control */ +#define B43_NPHY_C2_TXCTL B43_PHY_N(0x08C) /* Core 2 TX control */ +#define B43_NPHY_SCRAM_SIGCTL B43_PHY_N(0x090) /* Scram signal control */ +#define B43_NPHY_SCRAM_SIGCTL_INITST 0x007F /* Initial state value */ +#define B43_NPHY_SCRAM_SIGCTL_INITST_SHIFT 0 +#define B43_NPHY_SCRAM_SIGCTL_SCM 0x0080 /* Scram control mode */ +#define B43_NPHY_SCRAM_SIGCTL_SICE 0x0100 /* Scram index control enable */ +#define B43_NPHY_SCRAM_SIGCTL_START 0xFE00 /* Scram start bit */ +#define B43_NPHY_SCRAM_SIGCTL_START_SHIFT 9 +#define B43_NPHY_RFCTL_INTC1 B43_PHY_N(0x091) /* RF control (intc 1) */ +#define B43_NPHY_RFCTL_INTC2 B43_PHY_N(0x092) /* RF control (intc 2) */ +#define B43_NPHY_RFCTL_INTC3 B43_PHY_N(0x093) /* RF control (intc 3) */ +#define B43_NPHY_RFCTL_INTC4 B43_PHY_N(0x094) /* RF control (intc 4) */ +#define B43_NPHY_NRDTO_WWISE B43_PHY_N(0x095) /* # datatones WWiSE */ +#define B43_NPHY_NRDTO_TGNSYNC B43_PHY_N(0x096) /* # datatones TGNsync */ +#define B43_NPHY_SIGFMOD_WWISE B43_PHY_N(0x097) /* Signal field mod WWiSE */ +#define B43_NPHY_LEG_SIGFMOD_11N B43_PHY_N(0x098) /* Legacy signal field mod 11n */ +#define B43_NPHY_HT_SIGFMOD_11N B43_PHY_N(0x099) /* HT signal field mod 11n */ +#define B43_NPHY_C1_RXIQ_COMPA0 B43_PHY_N(0x09A) /* Core 1 RX I/Q comp A0 */ +#define B43_NPHY_C1_RXIQ_COMPB0 B43_PHY_N(0x09B) /* Core 1 RX I/Q comp B0 */ +#define B43_NPHY_C2_RXIQ_COMPA1 B43_PHY_N(0x09C) /* Core 2 RX I/Q comp A1 */ +#define B43_NPHY_C2_RXIQ_COMPB1 B43_PHY_N(0x09D) /* Core 2 RX I/Q comp B1 */ +#define B43_NPHY_RXCTL B43_PHY_N(0x0A0) /* RX control */ +#define B43_NPHY_RXCTL_BSELU20 0x0010 /* Band select upper 20 */ +#define B43_NPHY_RXCTL_RIFSEN 0x0080 /* RIFS enable */ +#define B43_NPHY_RFSEQMODE B43_PHY_N(0x0A1) /* RF seq mode */ +#define B43_NPHY_RFSEQMODE_CAOVER 0x0001 /* Core active override */ +#define B43_NPHY_RFSEQMODE_TROVER 0x0002 /* Trigger override */ +#define B43_NPHY_RFSEQCA B43_PHY_N(0x0A2) /* RF seq core active */ +#define B43_NPHY_RFSEQCA_TXEN 0x000F /* TX enable */ +#define B43_NPHY_RFSEQCA_TXEN_SHIFT 0 +#define B43_NPHY_RFSEQCA_RXEN 0x00F0 /* RX enable */ +#define B43_NPHY_RFSEQCA_RXEN_SHIFT 4 +#define B43_NPHY_RFSEQCA_TXDIS 0x0F00 /* TX disable */ +#define B43_NPHY_RFSEQCA_TXDIS_SHIFT 8 +#define B43_NPHY_RFSEQCA_RXDIS 0xF000 /* RX disable */ +#define B43_NPHY_RFSEQCA_RXDIS_SHIFT 12 +#define B43_NPHY_RFSEQTR B43_PHY_N(0x0A3) /* RF seq trigger */ +#define B43_NPHY_RFSEQTR_RX2TX 0x0001 /* RX2TX */ +#define B43_NPHY_RFSEQTR_TX2RX 0x0002 /* TX2RX */ +#define B43_NPHY_RFSEQTR_UPGH 0x0004 /* Update gain H */ +#define B43_NPHY_RFSEQTR_UPGL 0x0008 /* Update gain L */ +#define B43_NPHY_RFSEQTR_UPGU 0x0010 /* Update gain U */ +#define B43_NPHY_RFSEQTR_RST2RX 0x0020 /* Reset to RX */ +#define B43_NPHY_RFSEQST B43_PHY_N(0x0A4) /* RF seq status. Values same as trigger. */ +#define B43_NPHY_AFECTL_OVER B43_PHY_N(0x0A5) /* AFE control override */ +#define B43_NPHY_AFECTL_C1 B43_PHY_N(0x0A6) /* AFE control core 1 */ +#define B43_NPHY_AFECTL_C2 B43_PHY_N(0x0A7) /* AFE control core 2 */ +#define B43_NPHY_AFECTL_C3 B43_PHY_N(0x0A8) /* AFE control core 3 */ +#define B43_NPHY_AFECTL_C4 B43_PHY_N(0x0A9) /* AFE control core 4 */ +#define B43_NPHY_AFECTL_DACGAIN1 B43_PHY_N(0x0AA) /* AFE control DAC gain 1 */ +#define B43_NPHY_AFECTL_DACGAIN2 B43_PHY_N(0x0AB) /* AFE control DAC gain 2 */ +#define B43_NPHY_AFECTL_DACGAIN3 B43_PHY_N(0x0AC) /* AFE control DAC gain 3 */ +#define B43_NPHY_AFECTL_DACGAIN4 B43_PHY_N(0x0AD) /* AFE control DAC gain 4 */ +#define B43_NPHY_STR_ADDR1 B43_PHY_N(0x0AE) /* STR address 1 */ +#define B43_NPHY_STR_ADDR2 B43_PHY_N(0x0AF) /* STR address 2 */ +#define B43_NPHY_CLASSCTL B43_PHY_N(0x0B0) /* Classifier control */ +#define B43_NPHY_CLASSCTL_CCKEN 0x0001 /* CCK enable */ +#define B43_NPHY_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */ +#define B43_NPHY_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */ +#define B43_NPHY_IQFLIP B43_PHY_N(0x0B1) /* I/Q flip */ +#define B43_NPHY_IQFLIP_ADC1 0x0001 /* ADC1 */ +#define B43_NPHY_IQFLIP_ADC2 0x0010 /* ADC2 */ +#define B43_NPHY_SISO_SNR_THRES B43_PHY_N(0x0B2) /* SISO SNR threshold */ +#define B43_NPHY_SIGMA_N_MULT B43_PHY_N(0x0B3) /* Sigma N multiplier */ +#define B43_NPHY_TXMACDELAY B43_PHY_N(0x0B4) /* TX MAC delay */ +#define B43_NPHY_TXFRAMEDELAY B43_PHY_N(0x0B5) /* TX frame delay */ +#define B43_NPHY_MLPARM B43_PHY_N(0x0B6) /* ML parameters */ +#define B43_NPHY_MLCTL B43_PHY_N(0x0B7) /* ML control */ +#define B43_NPHY_WWISE_20NCYCDAT B43_PHY_N(0x0B8) /* WWiSE 20 N cyc data */ +#define B43_NPHY_WWISE_40NCYCDAT B43_PHY_N(0x0B9) /* WWiSE 40 N cyc data */ +#define B43_NPHY_TGNSYNC_20NCYCDAT B43_PHY_N(0x0BA) /* TGNsync 20 N cyc data */ +#define B43_NPHY_TGNSYNC_40NCYCDAT B43_PHY_N(0x0BB) /* TGNsync 40 N cyc data */ +#define B43_NPHY_INITSWIZP B43_PHY_N(0x0BC) /* Initial swizzle pattern */ +#define B43_NPHY_TXTAILCNT B43_PHY_N(0x0BD) /* TX tail count value */ +#define B43_NPHY_BPHY_CTL1 B43_PHY_N(0x0BE) /* B PHY control 1 */ +#define B43_NPHY_BPHY_CTL2 B43_PHY_N(0x0BF) /* B PHY control 2 */ +#define B43_NPHY_BPHY_CTL2_LUT 0x001F /* LUT index */ +#define B43_NPHY_BPHY_CTL2_LUT_SHIFT 0 +#define B43_NPHY_BPHY_CTL2_MACDEL 0x7FE0 /* MAC delay */ +#define B43_NPHY_BPHY_CTL2_MACDEL_SHIFT 5 +#define B43_NPHY_IQLOCAL_CMD B43_PHY_N(0x0C0) /* I/Q LO cal command */ +#define B43_NPHY_IQLOCAL_CMD_EN 0x8000 +#define B43_NPHY_IQLOCAL_CMDNNUM B43_PHY_N(0x0C1) /* I/Q LO cal command N num */ +#define B43_NPHY_IQLOCAL_CMDGCTL B43_PHY_N(0x0C2) /* I/Q LO cal command G control */ +#define B43_NPHY_SAMP_CMD B43_PHY_N(0x0C3) /* Sample command */ +#define B43_NPHY_SAMP_CMD_STOP 0x0002 /* Stop */ +#define B43_NPHY_SAMP_LOOPCNT B43_PHY_N(0x0C4) /* Sample loop count */ +#define B43_NPHY_SAMP_WAITCNT B43_PHY_N(0x0C5) /* Sample wait count */ +#define B43_NPHY_SAMP_DEPCNT B43_PHY_N(0x0C6) /* Sample depth count */ +#define B43_NPHY_SAMP_STAT B43_PHY_N(0x0C7) /* Sample status */ +#define B43_NPHY_GPIO_LOOEN B43_PHY_N(0x0C8) /* GPIO low out enable */ +#define B43_NPHY_GPIO_HIOEN B43_PHY_N(0x0C9) /* GPIO high out enable */ +#define B43_NPHY_GPIO_SEL B43_PHY_N(0x0CA) /* GPIO select */ +#define B43_NPHY_GPIO_CLKCTL B43_PHY_N(0x0CB) /* GPIO clock control */ +#define B43_NPHY_TXF_20CO_AS0 B43_PHY_N(0x0CC) /* TX filter 20 coeff A stage 0 */ +#define B43_NPHY_TXF_20CO_AS1 B43_PHY_N(0x0CD) /* TX filter 20 coeff A stage 1 */ +#define B43_NPHY_TXF_20CO_AS2 B43_PHY_N(0x0CE) /* TX filter 20 coeff A stage 2 */ +#define B43_NPHY_TXF_20CO_B32S0 B43_PHY_N(0x0CF) /* TX filter 20 coeff B32 stage 0 */ +#define B43_NPHY_TXF_20CO_B1S0 B43_PHY_N(0x0D0) /* TX filter 20 coeff B1 stage 0 */ +#define B43_NPHY_TXF_20CO_B32S1 B43_PHY_N(0x0D1) /* TX filter 20 coeff B32 stage 1 */ +#define B43_NPHY_TXF_20CO_B1S1 B43_PHY_N(0x0D2) /* TX filter 20 coeff B1 stage 1 */ +#define B43_NPHY_TXF_20CO_B32S2 B43_PHY_N(0x0D3) /* TX filter 20 coeff B32 stage 2 */ +#define B43_NPHY_TXF_20CO_B1S2 B43_PHY_N(0x0D4) /* TX filter 20 coeff B1 stage 2 */ +#define B43_NPHY_SIGFLDTOL B43_PHY_N(0x0D5) /* Signal fld tolerance */ +#define B43_NPHY_TXSERFLD B43_PHY_N(0x0D6) /* TX service field */ +#define B43_NPHY_AFESEQ_RX2TX_PUD B43_PHY_N(0x0D7) /* AFE seq RX2TX power up/down delay */ +#define B43_NPHY_AFESEQ_TX2RX_PUD B43_PHY_N(0x0D8) /* AFE seq TX2RX power up/down delay */ +#define B43_NPHY_TGNSYNC_SCRAMI0 B43_PHY_N(0x0D9) /* TGNsync scram init 0 */ +#define B43_NPHY_TGNSYNC_SCRAMI1 B43_PHY_N(0x0DA) /* TGNsync scram init 1 */ +#define B43_NPHY_INITSWIZPATTLEG B43_PHY_N(0x0DB) /* Initial swizzle pattern leg */ +#define B43_NPHY_BPHY_CTL3 B43_PHY_N(0x0DC) /* B PHY control 3 */ +#define B43_NPHY_BPHY_CTL3_SCALE 0x00FF /* Scale */ +#define B43_NPHY_BPHY_CTL3_SCALE_SHIFT 0 +#define B43_NPHY_BPHY_CTL3_FSC 0xFF00 /* Frame start count value */ +#define B43_NPHY_BPHY_CTL3_FSC_SHIFT 8 +#define B43_NPHY_BPHY_CTL4 B43_PHY_N(0x0DD) /* B PHY control 4 */ +#define B43_NPHY_C1_TXBBMULT B43_PHY_N(0x0DE) /* Core 1 TX BB multiplier */ +#define B43_NPHY_C2_TXBBMULT B43_PHY_N(0x0DF) /* Core 2 TX BB multiplier */ +#define B43_NPHY_TXF_40CO_AS0 B43_PHY_N(0x0E1) /* TX filter 40 coeff A stage 0 */ +#define B43_NPHY_TXF_40CO_AS1 B43_PHY_N(0x0E2) /* TX filter 40 coeff A stage 1 */ +#define B43_NPHY_TXF_40CO_AS2 B43_PHY_N(0x0E3) /* TX filter 40 coeff A stage 2 */ +#define B43_NPHY_TXF_40CO_B32S0 B43_PHY_N(0x0E4) /* TX filter 40 coeff B32 stage 0 */ +#define B43_NPHY_TXF_40CO_B1S0 B43_PHY_N(0x0E5) /* TX filter 40 coeff B1 stage 0 */ +#define B43_NPHY_TXF_40CO_B32S1 B43_PHY_N(0x0E6) /* TX filter 40 coeff B32 stage 1 */ +#define B43_NPHY_TXF_40CO_B1S1 B43_PHY_N(0x0E7) /* TX filter 40 coeff B1 stage 1 */ +#define B43_NPHY_TXF_40CO_B32S2 B43_PHY_N(0x0E8) /* TX filter 40 coeff B32 stage 2 */ +#define B43_NPHY_TXF_40CO_B1S2 B43_PHY_N(0x0E9) /* TX filter 40 coeff B1 stage 2 */ +#define B43_NPHY_BIST_STAT2 B43_PHY_N(0x0EA) /* BIST status 2 */ +#define B43_NPHY_BIST_STAT3 B43_PHY_N(0x0EB) /* BIST status 3 */ +#define B43_NPHY_RFCTL_OVER B43_PHY_N(0x0EC) /* RF control override */ +#define B43_NPHY_MIMOCFG B43_PHY_N(0x0ED) /* MIMO config */ +#define B43_NPHY_MIMOCFG_GFMIX 0x0004 /* Greenfield or mixed mode */ +#define B43_NPHY_MIMOCFG_AUTO 0x0100 /* Greenfield/mixed mode auto */ +#define B43_NPHY_RADAR_BLNKCTL B43_PHY_N(0x0EE) /* Radar blank control */ +#define B43_NPHY_A0RADAR_FIFOCTL B43_PHY_N(0x0EF) /* Antenna 0 radar FIFO control */ +#define B43_NPHY_A1RADAR_FIFOCTL B43_PHY_N(0x0F0) /* Antenna 1 radar FIFO control */ +#define B43_NPHY_A0RADAR_FIFODAT B43_PHY_N(0x0F1) /* Antenna 0 radar FIFO data */ +#define B43_NPHY_A1RADAR_FIFODAT B43_PHY_N(0x0F2) /* Antenna 1 radar FIFO data */ +#define B43_NPHY_RADAR_THRES0 B43_PHY_N(0x0F3) /* Radar threshold 0 */ +#define B43_NPHY_RADAR_THRES1 B43_PHY_N(0x0F4) /* Radar threshold 1 */ +#define B43_NPHY_RADAR_THRES0R B43_PHY_N(0x0F5) /* Radar threshold 0R */ +#define B43_NPHY_RADAR_THRES1R B43_PHY_N(0x0F6) /* Radar threshold 1R */ +#define B43_NPHY_CSEN_20IN40_DLEN B43_PHY_N(0x0F7) /* Carrier sense 20 in 40 dwell length */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO1 B43_PHY_N(0x0F8) /* RF control LUT TRSW lower 1 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP1 B43_PHY_N(0x0F9) /* RF control LUT TRSW upper 1 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO2 B43_PHY_N(0x0FA) /* RF control LUT TRSW lower 2 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP2 B43_PHY_N(0x0FB) /* RF control LUT TRSW upper 2 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO3 B43_PHY_N(0x0FC) /* RF control LUT TRSW lower 3 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP3 B43_PHY_N(0x0FD) /* RF control LUT TRSW upper 3 */ +#define B43_NPHY_RFCTL_LUT_TRSW_LO4 B43_PHY_N(0x0FE) /* RF control LUT TRSW lower 4 */ +#define B43_NPHY_RFCTL_LUT_TRSW_UP4 B43_PHY_N(0x0FF) /* RF control LUT TRSW upper 4 */ +#define B43_NPHY_RFCTL_LUT_LNAPA1 B43_PHY_N(0x100) /* RF control LUT LNA PA 1 */ +#define B43_NPHY_RFCTL_LUT_LNAPA2 B43_PHY_N(0x101) /* RF control LUT LNA PA 2 */ +#define B43_NPHY_RFCTL_LUT_LNAPA3 B43_PHY_N(0x102) /* RF control LUT LNA PA 3 */ +#define B43_NPHY_RFCTL_LUT_LNAPA4 B43_PHY_N(0x103) /* RF control LUT LNA PA 4 */ +#define B43_NPHY_TGNSYNC_CRCM0 B43_PHY_N(0x104) /* TGNsync CRC mask 0 */ +#define B43_NPHY_TGNSYNC_CRCM1 B43_PHY_N(0x105) /* TGNsync CRC mask 1 */ +#define B43_NPHY_TGNSYNC_CRCM2 B43_PHY_N(0x106) /* TGNsync CRC mask 2 */ +#define B43_NPHY_TGNSYNC_CRCM3 B43_PHY_N(0x107) /* TGNsync CRC mask 3 */ +#define B43_NPHY_TGNSYNC_CRCM4 B43_PHY_N(0x108) /* TGNsync CRC mask 4 */ +#define B43_NPHY_CRCPOLY B43_PHY_N(0x109) /* CRC polynomial */ +#define B43_NPHY_SIGCNT B43_PHY_N(0x10A) /* # sig count */ +#define B43_NPHY_SIGSTARTBIT_CTL B43_PHY_N(0x10B) /* Sig start bit control */ +#define B43_NPHY_CRCPOLY_ORDER B43_PHY_N(0x10C) /* CRC polynomial order */ +#define B43_NPHY_RFCTL_CST0 B43_PHY_N(0x10D) /* RF control core swap table 0 */ +#define B43_NPHY_RFCTL_CST1 B43_PHY_N(0x10E) /* RF control core swap table 1 */ +#define B43_NPHY_RFCTL_CST2O B43_PHY_N(0x10F) /* RF control core swap table 2 + others */ +#define B43_NPHY_BPHY_CTL5 B43_PHY_N(0x111) /* B PHY control 5 */ +#define B43_NPHY_RFSEQ_LPFBW B43_PHY_N(0x112) /* RF seq LPF bandwidth */ +#define B43_NPHY_TSSIBIAS1 B43_PHY_N(0x114) /* TSSI bias val 1 */ +#define B43_NPHY_TSSIBIAS2 B43_PHY_N(0x115) /* TSSI bias val 2 */ +#define B43_NPHY_TSSIBIAS_BIAS 0x00FF /* Bias */ +#define B43_NPHY_TSSIBIAS_BIAS_SHIFT 0 +#define B43_NPHY_TSSIBIAS_VAL 0xFF00 /* Value */ +#define B43_NPHY_TSSIBIAS_VAL_SHIFT 8 +#define B43_NPHY_ESTPWR1 B43_PHY_N(0x118) /* Estimated power 1 */ +#define B43_NPHY_ESTPWR2 B43_PHY_N(0x119) /* Estimated power 2 */ +#define B43_NPHY_ESTPWR_PWR 0x00FF /* Estimated power */ +#define B43_NPHY_ESTPWR_PWR_SHIFT 0 +#define B43_NPHY_ESTPWR_VALID 0x0100 /* Estimated power valid */ +#define B43_NPHY_TSSI_MAXTXFDT B43_PHY_N(0x11C) /* TSSI max TX frame delay time */ +#define B43_NPHY_TSSI_MAXTXFDT_VAL 0x00FF /* max TX frame delay time */ +#define B43_NPHY_TSSI_MAXTXFDT_VAL_SHIFT 0 +#define B43_NPHY_TSSI_MAXTDT B43_PHY_N(0x11D) /* TSSI max TSSI delay time */ +#define B43_NPHY_TSSI_MAXTDT_VAL 0x00FF /* max TSSI delay time */ +#define B43_NPHY_TSSI_MAXTDT_VAL_SHIFT 0 +#define B43_NPHY_ITSSI1 B43_PHY_N(0x11E) /* TSSI idle 1 */ +#define B43_NPHY_ITSSI2 B43_PHY_N(0x11F) /* TSSI idle 2 */ +#define B43_NPHY_ITSSI_VAL 0x00FF /* Idle TSSI */ +#define B43_NPHY_ITSSI_VAL_SHIFT 0 +#define B43_NPHY_TSSIMODE B43_PHY_N(0x122) /* TSSI mode */ +#define B43_NPHY_TSSIMODE_EN 0x0001 /* TSSI enable */ +#define B43_NPHY_TSSIMODE_PDEN 0x0002 /* Power det enable */ +#define B43_NPHY_RXMACIFM B43_PHY_N(0x123) /* RX Macif mode */ +#define B43_NPHY_CRSIT_COCNT_LO B43_PHY_N(0x124) /* CRS idle time CRS-on count (low) */ +#define B43_NPHY_CRSIT_COCNT_HI B43_PHY_N(0x125) /* CRS idle time CRS-on count (high) */ +#define B43_NPHY_CRSIT_MTCNT_LO B43_PHY_N(0x126) /* CRS idle time measure time count (low) */ +#define B43_NPHY_CRSIT_MTCNT_HI B43_PHY_N(0x127) /* CRS idle time measure time count (high) */ +#define B43_NPHY_SAMTWC B43_PHY_N(0x128) /* Sample tail wait count */ +#define B43_NPHY_IQEST_CMD B43_PHY_N(0x129) /* I/Q estimate command */ +#define B43_NPHY_IQEST_CMD_START 0x0001 /* Start */ +#define B43_NPHY_IQEST_CMD_MODE 0x0002 /* Mode */ +#define B43_NPHY_IQEST_WT B43_PHY_N(0x12A) /* I/Q estimate wait time */ +#define B43_NPHY_IQEST_WT_VAL 0x00FF /* Wait time */ +#define B43_NPHY_IQEST_WT_VAL_SHIFT 0 +#define B43_NPHY_IQEST_SAMCNT B43_PHY_N(0x12B) /* I/Q estimate sample count */ +#define B43_NPHY_IQEST_IQACC_LO0 B43_PHY_N(0x12C) /* I/Q estimate I/Q acc lo 0 */ +#define B43_NPHY_IQEST_IQACC_HI0 B43_PHY_N(0x12D) /* I/Q estimate I/Q acc hi 0 */ +#define B43_NPHY_IQEST_IPACC_LO0 B43_PHY_N(0x12E) /* I/Q estimate I power acc lo 0 */ +#define B43_NPHY_IQEST_IPACC_HI0 B43_PHY_N(0x12F) /* I/Q estimate I power acc hi 0 */ +#define B43_NPHY_IQEST_QPACC_LO0 B43_PHY_N(0x130) /* I/Q estimate Q power acc lo 0 */ +#define B43_NPHY_IQEST_QPACC_HI0 B43_PHY_N(0x131) /* I/Q estimate Q power acc hi 0 */ +#define B43_NPHY_IQEST_IQACC_LO1 B43_PHY_N(0x134) /* I/Q estimate I/Q acc lo 1 */ +#define B43_NPHY_IQEST_IQACC_HI1 B43_PHY_N(0x135) /* I/Q estimate I/Q acc hi 1 */ +#define B43_NPHY_IQEST_IPACC_LO1 B43_PHY_N(0x136) /* I/Q estimate I power acc lo 1 */ +#define B43_NPHY_IQEST_IPACC_HI1 B43_PHY_N(0x137) /* I/Q estimate I power acc hi 1 */ +#define B43_NPHY_IQEST_QPACC_LO1 B43_PHY_N(0x138) /* I/Q estimate Q power acc lo 1 */ +#define B43_NPHY_IQEST_QPACC_HI1 B43_PHY_N(0x139) /* I/Q estimate Q power acc hi 1 */ +#define B43_NPHY_MIMO_CRSTXEXT B43_PHY_N(0x13A) /* MIMO PHY CRS TX extension */ +#define B43_NPHY_PWRDET1 B43_PHY_N(0x13B) /* Power det 1 */ +#define B43_NPHY_PWRDET2 B43_PHY_N(0x13C) /* Power det 2 */ +#define B43_NPHY_MAXRSSI_DTIME B43_PHY_N(0x13F) /* RSSI max RSSI delay time */ +#define B43_NPHY_PIL_DW0 B43_PHY_N(0x141) /* Pilot data weight 0 */ +#define B43_NPHY_PIL_DW1 B43_PHY_N(0x142) /* Pilot data weight 1 */ +#define B43_NPHY_PIL_DW2 B43_PHY_N(0x143) /* Pilot data weight 2 */ +#define B43_NPHY_PIL_DW_BPSK 0x000F /* BPSK */ +#define B43_NPHY_PIL_DW_BPSK_SHIFT 0 +#define B43_NPHY_PIL_DW_QPSK 0x00F0 /* QPSK */ +#define B43_NPHY_PIL_DW_QPSK_SHIFT 4 +#define B43_NPHY_PIL_DW_16QAM 0x0F00 /* 16-QAM */ +#define B43_NPHY_PIL_DW_16QAM_SHIFT 8 +#define B43_NPHY_PIL_DW_64QAM 0xF000 /* 64-QAM */ +#define B43_NPHY_PIL_DW_64QAM_SHIFT 12 +#define B43_NPHY_FMDEM_CFG B43_PHY_N(0x144) /* FM demodulation config */ +#define B43_NPHY_PHASETR_A0 B43_PHY_N(0x145) /* Phase track alpha 0 */ +#define B43_NPHY_PHASETR_A1 B43_PHY_N(0x146) /* Phase track alpha 1 */ +#define B43_NPHY_PHASETR_A2 B43_PHY_N(0x147) /* Phase track alpha 2 */ +#define B43_NPHY_PHASETR_B0 B43_PHY_N(0x148) /* Phase track beta 0 */ +#define B43_NPHY_PHASETR_B1 B43_PHY_N(0x149) /* Phase track beta 1 */ +#define B43_NPHY_PHASETR_B2 B43_PHY_N(0x14A) /* Phase track beta 2 */ +#define B43_NPHY_PHASETR_CHG0 B43_PHY_N(0x14B) /* Phase track change 0 */ +#define B43_NPHY_PHASETR_CHG1 B43_PHY_N(0x14C) /* Phase track change 1 */ +#define B43_NPHY_PHASETW_OFF B43_PHY_N(0x14D) /* Phase track offset */ +#define B43_NPHY_RFCTL_DBG B43_PHY_N(0x14E) /* RF control debug */ +#define B43_NPHY_CCK_SHIFTB_REF B43_PHY_N(0x150) /* CCK shiftbits reference var */ +#define B43_NPHY_OVER_DGAIN0 B43_PHY_N(0x152) /* Override digital gain 0 */ +#define B43_NPHY_OVER_DGAIN1 B43_PHY_N(0x153) /* Override digital gain 1 */ +#define B43_NPHY_OVER_DGAIN_FDGV 0x0007 /* Force digital gain value */ +#define B43_NPHY_OVER_DGAIN_FDGV_SHIFT 0 +#define B43_NPHY_OVER_DGAIN_FDGEN 0x0008 /* Force digital gain enable */ +#define B43_NPHY_OVER_DGAIN_CCKDGECV 0xFF00 /* CCK digital gain enable count value */ +#define B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT 8 +#define B43_NPHY_BIST_STAT4 B43_PHY_N(0x156) /* BIST status 4 */ +#define B43_NPHY_RADAR_MAL B43_PHY_N(0x157) /* Radar MA length */ +#define B43_NPHY_RADAR_SRCCTL B43_PHY_N(0x158) /* Radar search control */ +#define B43_NPHY_VLD_DTSIG B43_PHY_N(0x159) /* VLD data tones sig */ +#define B43_NPHY_VLD_DTDAT B43_PHY_N(0x15A) /* VLD data tones data */ +#define B43_NPHY_C1_BPHY_RXIQCA0 B43_PHY_N(0x15B) /* Core 1 B PHY RX I/Q comp A0 */ +#define B43_NPHY_C1_BPHY_RXIQCB0 B43_PHY_N(0x15C) /* Core 1 B PHY RX I/Q comp B0 */ +#define B43_NPHY_C2_BPHY_RXIQCA1 B43_PHY_N(0x15D) /* Core 2 B PHY RX I/Q comp A1 */ +#define B43_NPHY_C2_BPHY_RXIQCB1 B43_PHY_N(0x15E) /* Core 2 B PHY RX I/Q comp B1 */ +#define B43_NPHY_FREQGAIN0 B43_PHY_N(0x160) /* Frequency gain 0 */ +#define B43_NPHY_FREQGAIN1 B43_PHY_N(0x161) /* Frequency gain 1 */ +#define B43_NPHY_FREQGAIN2 B43_PHY_N(0x162) /* Frequency gain 2 */ +#define B43_NPHY_FREQGAIN3 B43_PHY_N(0x163) /* Frequency gain 3 */ +#define B43_NPHY_FREQGAIN4 B43_PHY_N(0x164) /* Frequency gain 4 */ +#define B43_NPHY_FREQGAIN5 B43_PHY_N(0x165) /* Frequency gain 5 */ +#define B43_NPHY_FREQGAIN6 B43_PHY_N(0x166) /* Frequency gain 6 */ +#define B43_NPHY_FREQGAIN7 B43_PHY_N(0x167) /* Frequency gain 7 */ +#define B43_NPHY_FREQGAIN_BYPASS B43_PHY_N(0x168) /* Frequency gain bypass */ +#define B43_NPHY_TRLOSS B43_PHY_N(0x169) /* TR loss value */ +#define B43_NPHY_C1_ADCCLIP B43_PHY_N(0x16A) /* Core 1 ADC clip */ +#define B43_NPHY_C2_ADCCLIP B43_PHY_N(0x16B) /* Core 2 ADC clip */ +#define B43_NPHY_LTRN_OFFGAIN B43_PHY_N(0x16F) /* LTRN offset gain */ +#define B43_NPHY_LTRN_OFF B43_PHY_N(0x170) /* LTRN offset */ +#define B43_NPHY_NRDATAT_WWISE20SIG B43_PHY_N(0x171) /* # data tones WWiSE 20 sig */ +#define B43_NPHY_NRDATAT_WWISE40SIG B43_PHY_N(0x172) /* # data tones WWiSE 40 sig */ +#define B43_NPHY_NRDATAT_TGNSYNC20SIG B43_PHY_N(0x173) /* # data tones TGNsync 20 sig */ +#define B43_NPHY_NRDATAT_TGNSYNC40SIG B43_PHY_N(0x174) /* # data tones TGNsync 40 sig */ +#define B43_NPHY_WWISE_CRCM0 B43_PHY_N(0x175) /* WWiSE CRC mask 0 */ +#define B43_NPHY_WWISE_CRCM1 B43_PHY_N(0x176) /* WWiSE CRC mask 1 */ +#define B43_NPHY_WWISE_CRCM2 B43_PHY_N(0x177) /* WWiSE CRC mask 2 */ +#define B43_NPHY_WWISE_CRCM3 B43_PHY_N(0x178) /* WWiSE CRC mask 3 */ +#define B43_NPHY_WWISE_CRCM4 B43_PHY_N(0x179) /* WWiSE CRC mask 4 */ +#define B43_NPHY_CHANEST_CDDSH B43_PHY_N(0x17A) /* Channel estimate CDD shift */ +#define B43_NPHY_HTAGC_WCNT B43_PHY_N(0x17B) /* HT ADC wait counters */ +#define B43_NPHY_SQPARM B43_PHY_N(0x17C) /* SQ params */ +#define B43_NPHY_MCSDUP6M B43_PHY_N(0x17D) /* MCS dup 6M */ +#define B43_NPHY_NDATAT_DUP40 B43_PHY_N(0x17E) /* # data tones dup 40 */ +#define B43_NPHY_DUP40_TGNSYNC_CYCD B43_PHY_N(0x17F) /* Dup40 TGNsync cycle data */ +#define B43_NPHY_DUP40_GFBL B43_PHY_N(0x180) /* Dup40 GF format BL address */ +#define B43_NPHY_DUP40_BL B43_PHY_N(0x181) /* Dup40 format BL address */ +#define B43_NPHY_LEGDUP_FTA B43_PHY_N(0x182) /* Legacy dup frm table address */ +#define B43_NPHY_PACPROC_DBG B43_PHY_N(0x183) /* Packet processing debug */ +#define B43_NPHY_PIL_CYC1 B43_PHY_N(0x184) /* Pilot cycle counter 1 */ +#define B43_NPHY_PIL_CYC2 B43_PHY_N(0x185) /* Pilot cycle counter 2 */ +#define B43_NPHY_TXF_20CO_S0A1 B43_PHY_N(0x186) /* TX filter 20 coeff stage 0 A1 */ +#define B43_NPHY_TXF_20CO_S0A2 B43_PHY_N(0x187) /* TX filter 20 coeff stage 0 A2 */ +#define B43_NPHY_TXF_20CO_S1A1 B43_PHY_N(0x188) /* TX filter 20 coeff stage 1 A1 */ +#define B43_NPHY_TXF_20CO_S1A2 B43_PHY_N(0x189) /* TX filter 20 coeff stage 1 A2 */ +#define B43_NPHY_TXF_20CO_S2A1 B43_PHY_N(0x18A) /* TX filter 20 coeff stage 2 A1 */ +#define B43_NPHY_TXF_20CO_S2A2 B43_PHY_N(0x18B) /* TX filter 20 coeff stage 2 A2 */ +#define B43_NPHY_TXF_20CO_S0B1 B43_PHY_N(0x18C) /* TX filter 20 coeff stage 0 B1 */ +#define B43_NPHY_TXF_20CO_S0B2 B43_PHY_N(0x18D) /* TX filter 20 coeff stage 0 B2 */ +#define B43_NPHY_TXF_20CO_S0B3 B43_PHY_N(0x18E) /* TX filter 20 coeff stage 0 B3 */ +#define B43_NPHY_TXF_20CO_S1B1 B43_PHY_N(0x18F) /* TX filter 20 coeff stage 1 B1 */ +#define B43_NPHY_TXF_20CO_S1B2 B43_PHY_N(0x190) /* TX filter 20 coeff stage 1 B2 */ +#define B43_NPHY_TXF_20CO_S1B3 B43_PHY_N(0x191) /* TX filter 20 coeff stage 1 B3 */ +#define B43_NPHY_TXF_20CO_S2B1 B43_PHY_N(0x192) /* TX filter 20 coeff stage 2 B1 */ +#define B43_NPHY_TXF_20CO_S2B2 B43_PHY_N(0x193) /* TX filter 20 coeff stage 2 B2 */ +#define B43_NPHY_TXF_20CO_S2B3 B43_PHY_N(0x194) /* TX filter 20 coeff stage 2 B3 */ +#define B43_NPHY_TXF_40CO_S0A1 B43_PHY_N(0x195) /* TX filter 40 coeff stage 0 A1 */ +#define B43_NPHY_TXF_40CO_S0A2 B43_PHY_N(0x196) /* TX filter 40 coeff stage 0 A2 */ +#define B43_NPHY_TXF_40CO_S1A1 B43_PHY_N(0x197) /* TX filter 40 coeff stage 1 A1 */ +#define B43_NPHY_TXF_40CO_S1A2 B43_PHY_N(0x198) /* TX filter 40 coeff stage 1 A2 */ +#define B43_NPHY_TXF_40CO_S2A1 B43_PHY_N(0x199) /* TX filter 40 coeff stage 2 A1 */ +#define B43_NPHY_TXF_40CO_S2A2 B43_PHY_N(0x19A) /* TX filter 40 coeff stage 2 A2 */ +#define B43_NPHY_TXF_40CO_S0B1 B43_PHY_N(0x19B) /* TX filter 40 coeff stage 0 B1 */ +#define B43_NPHY_TXF_40CO_S0B2 B43_PHY_N(0x19C) /* TX filter 40 coeff stage 0 B2 */ +#define B43_NPHY_TXF_40CO_S0B3 B43_PHY_N(0x19D) /* TX filter 40 coeff stage 0 B3 */ +#define B43_NPHY_TXF_40CO_S1B1 B43_PHY_N(0x19E) /* TX filter 40 coeff stage 1 B1 */ +#define B43_NPHY_TXF_40CO_S1B2 B43_PHY_N(0x19F) /* TX filter 40 coeff stage 1 B2 */ +#define B43_NPHY_TXF_40CO_S1B3 B43_PHY_N(0x1A0) /* TX filter 40 coeff stage 1 B3 */ +#define B43_NPHY_TXF_40CO_S2B1 B43_PHY_N(0x1A1) /* TX filter 40 coeff stage 2 B1 */ +#define B43_NPHY_TXF_40CO_S2B2 B43_PHY_N(0x1A2) /* TX filter 40 coeff stage 2 B2 */ +#define B43_NPHY_TXF_40CO_S2B3 B43_PHY_N(0x1A3) /* TX filter 40 coeff stage 2 B3 */ +#define B43_NPHY_RSSIMC_0I_RSSI_X B43_PHY_N(0x1A4) /* RSSI multiplication coefficient 0 I RSSI X */ +#define B43_NPHY_RSSIMC_0I_RSSI_Y B43_PHY_N(0x1A5) /* RSSI multiplication coefficient 0 I RSSI Y */ +#define B43_NPHY_RSSIMC_0I_RSSI_Z B43_PHY_N(0x1A6) /* RSSI multiplication coefficient 0 I RSSI Z */ +#define B43_NPHY_RSSIMC_0I_TBD B43_PHY_N(0x1A7) /* RSSI multiplication coefficient 0 I TBD */ +#define B43_NPHY_RSSIMC_0I_PWRDET B43_PHY_N(0x1A8) /* RSSI multiplication coefficient 0 I power det */ +#define B43_NPHY_RSSIMC_0I_TSSI B43_PHY_N(0x1A9) /* RSSI multiplication coefficient 0 I TSSI */ +#define B43_NPHY_RSSIMC_0Q_RSSI_X B43_PHY_N(0x1AA) /* RSSI multiplication coefficient 0 Q RSSI X */ +#define B43_NPHY_RSSIMC_0Q_RSSI_Y B43_PHY_N(0x1AB) /* RSSI multiplication coefficient 0 Q RSSI Y */ +#define B43_NPHY_RSSIMC_0Q_RSSI_Z B43_PHY_N(0x1AC) /* RSSI multiplication coefficient 0 Q RSSI Z */ +#define B43_NPHY_RSSIMC_0Q_TBD B43_PHY_N(0x1AD) /* RSSI multiplication coefficient 0 Q TBD */ +#define B43_NPHY_RSSIMC_0Q_PWRDET B43_PHY_N(0x1AE) /* RSSI multiplication coefficient 0 Q power det */ +#define B43_NPHY_RSSIMC_0Q_TSSI B43_PHY_N(0x1AF) /* RSSI multiplication coefficient 0 Q TSSI */ +#define B43_NPHY_RSSIMC_1I_RSSI_X B43_PHY_N(0x1B0) /* RSSI multiplication coefficient 1 I RSSI X */ +#define B43_NPHY_RSSIMC_1I_RSSI_Y B43_PHY_N(0x1B1) /* RSSI multiplication coefficient 1 I RSSI Y */ +#define B43_NPHY_RSSIMC_1I_RSSI_Z B43_PHY_N(0x1B2) /* RSSI multiplication coefficient 1 I RSSI Z */ +#define B43_NPHY_RSSIMC_1I_TBD B43_PHY_N(0x1B3) /* RSSI multiplication coefficient 1 I TBD */ +#define B43_NPHY_RSSIMC_1I_PWRDET B43_PHY_N(0x1B4) /* RSSI multiplication coefficient 1 I power det */ +#define B43_NPHY_RSSIMC_1I_TSSI B43_PHY_N(0x1B5) /* RSSI multiplication coefficient 1 I TSSI */ +#define B43_NPHY_RSSIMC_1Q_RSSI_X B43_PHY_N(0x1B6) /* RSSI multiplication coefficient 1 Q RSSI X */ +#define B43_NPHY_RSSIMC_1Q_RSSI_Y B43_PHY_N(0x1B7) /* RSSI multiplication coefficient 1 Q RSSI Y */ +#define B43_NPHY_RSSIMC_1Q_RSSI_Z B43_PHY_N(0x1B8) /* RSSI multiplication coefficient 1 Q RSSI Z */ +#define B43_NPHY_RSSIMC_1Q_TBD B43_PHY_N(0x1B9) /* RSSI multiplication coefficient 1 Q TBD */ +#define B43_NPHY_RSSIMC_1Q_PWRDET B43_PHY_N(0x1BA) /* RSSI multiplication coefficient 1 Q power det */ +#define B43_NPHY_RSSIMC_1Q_TSSI B43_PHY_N(0x1BB) /* RSSI multiplication coefficient 1 Q TSSI */ +#define B43_NPHY_SAMC_WCNT B43_PHY_N(0x1BC) /* Sample collect wait counter */ +#define B43_NPHY_PTHROUGH_CNT B43_PHY_N(0x1BD) /* Pass-through counter */ +#define B43_NPHY_LTRN_OFF_G20L B43_PHY_N(0x1C4) /* LTRN offset gain 20L */ +#define B43_NPHY_LTRN_OFF_20L B43_PHY_N(0x1C5) /* LTRN offset 20L */ +#define B43_NPHY_LTRN_OFF_G20U B43_PHY_N(0x1C6) /* LTRN offset gain 20U */ +#define B43_NPHY_LTRN_OFF_20U B43_PHY_N(0x1C7) /* LTRN offset 20U */ +#define B43_NPHY_DSSSCCK_GAINSL B43_PHY_N(0x1C8) /* DSSS/CCK gain settle length */ +#define B43_NPHY_GPIO_LOOUT B43_PHY_N(0x1C9) /* GPIO low out */ +#define B43_NPHY_GPIO_HIOUT B43_PHY_N(0x1CA) /* GPIO high out */ +#define B43_NPHY_CRS_CHECK B43_PHY_N(0x1CB) /* CRS check */ +#define B43_NPHY_ML_LOGSS_RAT B43_PHY_N(0x1CC) /* ML/logss ratio */ +#define B43_NPHY_DUPSCALE B43_PHY_N(0x1CD) /* Dup scale */ +#define B43_NPHY_BW1A B43_PHY_N(0x1CE) /* BW 1A */ +#define B43_NPHY_BW2 B43_PHY_N(0x1CF) /* BW 2 */ +#define B43_NPHY_BW3 B43_PHY_N(0x1D0) /* BW 3 */ +#define B43_NPHY_BW4 B43_PHY_N(0x1D1) /* BW 4 */ +#define B43_NPHY_BW5 B43_PHY_N(0x1D2) /* BW 5 */ +#define B43_NPHY_BW6 B43_PHY_N(0x1D3) /* BW 6 */ +#define B43_NPHY_COALEN0 B43_PHY_N(0x1D4) /* Coarse length 0 */ +#define B43_NPHY_COALEN1 B43_PHY_N(0x1D5) /* Coarse length 1 */ +#define B43_NPHY_CRSTHRES_1U B43_PHY_N(0x1D6) /* CRS threshold 1 U */ +#define B43_NPHY_CRSTHRES_2U B43_PHY_N(0x1D7) /* CRS threshold 2 U */ +#define B43_NPHY_CRSTHRES_3U B43_PHY_N(0x1D8) /* CRS threshold 3 U */ +#define B43_NPHY_CRSCTL_U B43_PHY_N(0x1D9) /* CRS control U */ +#define B43_NPHY_CRSTHRES_1L B43_PHY_N(0x1DA) /* CRS threshold 1 L */ +#define B43_NPHY_CRSTHRES_2L B43_PHY_N(0x1DB) /* CRS threshold 2 L */ +#define B43_NPHY_CRSTHRES_3L B43_PHY_N(0x1DC) /* CRS threshold 3 L */ +#define B43_NPHY_CRSCTL_L B43_PHY_N(0x1DD) /* CRS control L */ +#define B43_NPHY_STRA_1U B43_PHY_N(0x1DE) /* STR address 1 U */ +#define B43_NPHY_STRA_2U B43_PHY_N(0x1DF) /* STR address 2 U */ +#define B43_NPHY_STRA_1L B43_PHY_N(0x1E0) /* STR address 1 L */ +#define B43_NPHY_STRA_2L B43_PHY_N(0x1E1) /* STR address 2 L */ +#define B43_NPHY_CRSCHECK1 B43_PHY_N(0x1E2) /* CRS check 1 */ +#define B43_NPHY_CRSCHECK2 B43_PHY_N(0x1E3) /* CRS check 2 */ +#define B43_NPHY_CRSCHECK3 B43_PHY_N(0x1E4) /* CRS check 3 */ +#define B43_NPHY_JMPSTP0 B43_PHY_N(0x1E5) /* Jump step 0 */ +#define B43_NPHY_JMPSTP1 B43_PHY_N(0x1E6) /* Jump step 1 */ +#define B43_NPHY_TXPCTL_CMD B43_PHY_N(0x1E7) /* TX power control command */ +#define B43_NPHY_TXPCTL_CMD_INIT 0x007F /* Init */ +#define B43_NPHY_TXPCTL_CMD_INIT_SHIFT 0 +#define B43_NPHY_TXPCTL_CMD_COEFF 0x2000 /* Power control coefficients */ +#define B43_NPHY_TXPCTL_CMD_HWPCTLEN 0x4000 /* Hardware TX power control enable */ +#define B43_NPHY_TXPCTL_CMD_PCTLEN 0x8000 /* TX power control enable */ +#define B43_NPHY_TXPCTL_N B43_PHY_N(0x1E8) /* TX power control N num */ +#define B43_NPHY_TXPCTL_N_TSSID 0x00FF /* N TSSI delay */ +#define B43_NPHY_TXPCTL_N_TSSID_SHIFT 0 +#define B43_NPHY_TXPCTL_N_NPTIL2 0x0700 /* N PT integer log2 */ +#define B43_NPHY_TXPCTL_N_NPTIL2_SHIFT 8 +#define B43_NPHY_TXPCTL_ITSSI B43_PHY_N(0x1E9) /* TX power control idle TSSI */ +#define B43_NPHY_TXPCTL_ITSSI_0 0x003F /* Idle TSSI 0 */ +#define B43_NPHY_TXPCTL_ITSSI_0_SHIFT 0 +#define B43_NPHY_TXPCTL_ITSSI_1 0x3F00 /* Idle TSSI 1 */ +#define B43_NPHY_TXPCTL_ITSSI_1_SHIFT 8 +#define B43_NPHY_TXPCTL_ITSSI_BINF 0x8000 /* Raw TSSI offset bin format */ +#define B43_NPHY_TXPCTL_TPWR B43_PHY_N(0x1EA) /* TX power control target power */ +#define B43_NPHY_TXPCTL_TPWR_0 0x00FF /* Power 0 */ +#define B43_NPHY_TXPCTL_TPWR_0_SHIFT 0 +#define B43_NPHY_TXPCTL_TPWR_1 0xFF00 /* Power 1 */ +#define B43_NPHY_TXPCTL_TPWR_1_SHIFT 8 +#define B43_NPHY_TXPCTL_BIDX B43_PHY_N(0x1EB) /* TX power control base index */ +#define B43_NPHY_TXPCTL_BIDX_0 0x007F /* uC base index 0 */ +#define B43_NPHY_TXPCTL_BIDX_0_SHIFT 0 +#define B43_NPHY_TXPCTL_BIDX_1 0x7F00 /* uC base index 1 */ +#define B43_NPHY_TXPCTL_BIDX_1_SHIFT 8 +#define B43_NPHY_TXPCTL_BIDX_LOAD 0x8000 /* Load base index */ +#define B43_NPHY_TXPCTL_PIDX B43_PHY_N(0x1EC) /* TX power control power index */ +#define B43_NPHY_TXPCTL_PIDX_0 0x007F /* uC power index 0 */ +#define B43_NPHY_TXPCTL_PIDX_0_SHIFT 0 +#define B43_NPHY_TXPCTL_PIDX_1 0x7F00 /* uC power index 1 */ +#define B43_NPHY_TXPCTL_PIDX_1_SHIFT 8 +#define B43_NPHY_C1_TXPCTL_STAT B43_PHY_N(0x1ED) /* Core 1 TX power control status */ +#define B43_NPHY_C2_TXPCTL_STAT B43_PHY_N(0x1EE) /* Core 2 TX power control status */ +#define B43_NPHY_TXPCTL_STAT_EST 0x00FF /* Estimated power */ +#define B43_NPHY_TXPCTL_STAT_EST_SHIFT 0 +#define B43_NPHY_TXPCTL_STAT_BIDX 0x7F00 /* Base index */ +#define B43_NPHY_TXPCTL_STAT_BIDX_SHIFT 8 +#define B43_NPHY_TXPCTL_STAT_ESTVALID 0x8000 /* Estimated power valid */ +#define B43_NPHY_SMALLSGS_LEN B43_PHY_N(0x1EF) /* Small sig gain settle length */ +#define B43_NPHY_PHYSTAT_GAIN0 B43_PHY_N(0x1F0) /* PHY stats gain info 0 */ +#define B43_NPHY_PHYSTAT_GAIN1 B43_PHY_N(0x1F1) /* PHY stats gain info 1 */ +#define B43_NPHY_PHYSTAT_FREQEST B43_PHY_N(0x1F2) /* PHY stats frequency estimate */ +#define B43_NPHY_PHYSTAT_ADVRET B43_PHY_N(0x1F3) /* PHY stats ADV retard */ +#define B43_NPHY_PHYLB_MODE B43_PHY_N(0x1F4) /* PHY loopback mode */ +#define B43_NPHY_TONE_MIDX20_1 B43_PHY_N(0x1F5) /* Tone map index 20/1 */ +#define B43_NPHY_TONE_MIDX20_2 B43_PHY_N(0x1F6) /* Tone map index 20/2 */ +#define B43_NPHY_TONE_MIDX20_3 B43_PHY_N(0x1F7) /* Tone map index 20/3 */ +#define B43_NPHY_TONE_MIDX40_1 B43_PHY_N(0x1F8) /* Tone map index 40/1 */ +#define B43_NPHY_TONE_MIDX40_2 B43_PHY_N(0x1F9) /* Tone map index 40/2 */ +#define B43_NPHY_TONE_MIDX40_3 B43_PHY_N(0x1FA) /* Tone map index 40/3 */ +#define B43_NPHY_TONE_MIDX40_4 B43_PHY_N(0x1FB) /* Tone map index 40/4 */ +#define B43_NPHY_PILTONE_MIDX1 B43_PHY_N(0x1FC) /* Pilot tone map index 1 */ +#define B43_NPHY_PILTONE_MIDX2 B43_PHY_N(0x1FD) /* Pilot tone map index 2 */ +#define B43_NPHY_PILTONE_MIDX3 B43_PHY_N(0x1FE) /* Pilot tone map index 3 */ +#define B43_NPHY_TXRIFS_FRDEL B43_PHY_N(0x1FF) /* TX RIFS frame delay */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_40M B43_PHY_N(0x200) /* AFE seq rx2tx power up/down delay 40M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_40M B43_PHY_N(0x201) /* AFE seq tx2rx power up/down delay 40M */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_20M B43_PHY_N(0x202) /* AFE seq rx2tx power up/down delay 20M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_20M B43_PHY_N(0x203) /* AFE seq tx2rx power up/down delay 20M */ +#define B43_NPHY_RX_SIGCTL B43_PHY_N(0x204) /* RX signal control */ +#define B43_NPHY_RXPIL_CYCNT0 B43_PHY_N(0x205) /* RX pilot cycle counter 0 */ +#define B43_NPHY_RXPIL_CYCNT1 B43_PHY_N(0x206) /* RX pilot cycle counter 1 */ +#define B43_NPHY_RXPIL_CYCNT2 B43_PHY_N(0x207) /* RX pilot cycle counter 2 */ +#define B43_NPHY_AFESEQ_RX2TX_PUD_10M B43_PHY_N(0x208) /* AFE seq rx2tx power up/down delay 10M */ +#define B43_NPHY_AFESEQ_TX2RX_PUD_10M B43_PHY_N(0x209) /* AFE seq tx2rx power up/down delay 10M */ +#define B43_NPHY_DSSSCCK_CRSEXTL B43_PHY_N(0x20A) /* DSSS/CCK CRS extension length */ +#define B43_NPHY_ML_LOGSS_RATSLOPE B43_PHY_N(0x20B) /* ML/logss ratio slope */ +#define B43_NPHY_RIFS_SRCTL B43_PHY_N(0x20C) /* RIFS search timeout length */ +#define B43_NPHY_TXREALFD B43_PHY_N(0x20D) /* TX real frame delay */ +#define B43_NPHY_HPANT_SWTHRES B43_PHY_N(0x20E) /* High power antenna switch threshold */ +#define B43_NPHY_EDCRS_ASSTHRES0 B43_PHY_N(0x210) /* ED CRS assert threshold 0 */ +#define B43_NPHY_EDCRS_ASSTHRES1 B43_PHY_N(0x211) /* ED CRS assert threshold 1 */ +#define B43_NPHY_EDCRS_DEASSTHRES0 B43_PHY_N(0x212) /* ED CRS deassert threshold 0 */ +#define B43_NPHY_EDCRS_DEASSTHRES1 B43_PHY_N(0x213) /* ED CRS deassert threshold 1 */ +#define B43_NPHY_STR_WTIME20U B43_PHY_N(0x214) /* STR wait time 20U */ +#define B43_NPHY_STR_WTIME20L B43_PHY_N(0x215) /* STR wait time 20L */ +#define B43_NPHY_TONE_MIDX657M B43_PHY_N(0x216) /* Tone map index 657M */ +#define B43_NPHY_HTSIGTONES B43_PHY_N(0x217) /* HT signal tones */ +#define B43_NPHY_RSSI1 B43_PHY_N(0x219) /* RSSI value 1 */ +#define B43_NPHY_RSSI2 B43_PHY_N(0x21A) /* RSSI value 2 */ +#define B43_NPHY_CHAN_ESTHANG B43_PHY_N(0x21D) /* Channel estimate hang */ +#define B43_NPHY_FINERX2_CGC B43_PHY_N(0x221) /* Fine RX 2 clock gate control */ +#define B43_NPHY_FINERX2_CGC_DECGC 0x0008 /* Decode gated clocks */ +#define B43_NPHY_TXPCTL_INIT B43_PHY_N(0x222) /* TX power controll init */ +#define B43_NPHY_TXPCTL_INIT_PIDXI1 0x00FF /* Power index init 1 */ +#define B43_NPHY_TXPCTL_INIT_PIDXI1_SHIFT 0 + + + +/* Broadcom 2055 radio registers */ + +#define B2055_GEN_SPARE 0x00 /* GEN spare */ +#define B2055_SP_PINPD 0x02 /* SP PIN PD */ +#define B2055_C1_SP_RSSI 0x03 /* SP RSSI Core 1 */ +#define B2055_C1_SP_PDMISC 0x04 /* SP PD MISC Core 1 */ +#define B2055_C2_SP_RSSI 0x05 /* SP RSSI Core 2 */ +#define B2055_C2_SP_PDMISC 0x06 /* SP PD MISC Core 2 */ +#define B2055_C1_SP_RXGC1 0x07 /* SP RX GC1 Core 1 */ +#define B2055_C1_SP_RXGC2 0x08 /* SP RX GC2 Core 1 */ +#define B2055_C2_SP_RXGC1 0x09 /* SP RX GC1 Core 2 */ +#define B2055_C2_SP_RXGC2 0x0A /* SP RX GC2 Core 2 */ +#define B2055_C1_SP_LPFBWSEL 0x0B /* SP LPF BW select Core 1 */ +#define B2055_C2_SP_LPFBWSEL 0x0C /* SP LPF BW select Core 2 */ +#define B2055_C1_SP_TXGC1 0x0D /* SP TX GC1 Core 1 */ +#define B2055_C1_SP_TXGC2 0x0E /* SP TX GC2 Core 1 */ +#define B2055_C2_SP_TXGC1 0x0F /* SP TX GC1 Core 2 */ +#define B2055_C2_SP_TXGC2 0x10 /* SP TX GC2 Core 2 */ +#define B2055_MASTER1 0x11 /* Master control 1 */ +#define B2055_MASTER2 0x12 /* Master control 2 */ +#define B2055_PD_LGEN 0x13 /* PD LGEN */ +#define B2055_PD_PLLTS 0x14 /* PD PLL TS */ +#define B2055_C1_PD_LGBUF 0x15 /* PD Core 1 LGBUF */ +#define B2055_C1_PD_TX 0x16 /* PD Core 1 TX */ +#define B2055_C1_PD_RXTX 0x17 /* PD Core 1 RXTX */ +#define B2055_C1_PD_RSSIMISC 0x18 /* PD Core 1 RSSI MISC */ +#define B2055_C2_PD_LGBUF 0x19 /* PD Core 2 LGBUF */ +#define B2055_C2_PD_TX 0x1A /* PD Core 2 TX */ +#define B2055_C2_PD_RXTX 0x1B /* PD Core 2 RXTX */ +#define B2055_C2_PD_RSSIMISC 0x1C /* PD Core 2 RSSI MISC */ +#define B2055_PWRDET_LGEN 0x1D /* PWRDET LGEN */ +#define B2055_C1_PWRDET_LGBUF 0x1E /* PWRDET LGBUF Core 1 */ +#define B2055_C1_PWRDET_RXTX 0x1F /* PWRDET RXTX Core 1 */ +#define B2055_C2_PWRDET_LGBUF 0x20 /* PWRDET LGBUF Core 2 */ +#define B2055_C2_PWRDET_RXTX 0x21 /* PWRDET RXTX Core 2 */ +#define B2055_RRCCAL_CS 0x22 /* RRCCAL Control spare */ +#define B2055_RRCCAL_NOPTSEL 0x23 /* RRCCAL N OPT SEL */ +#define B2055_CAL_MISC 0x24 /* CAL MISC */ +#define B2055_CAL_COUT 0x25 /* CAL Counter out */ +#define B2055_CAL_COUT2 0x26 /* CAL Counter out 2 */ +#define B2055_CAL_CVARCTL 0x27 /* CAL CVAR Control */ +#define B2055_CAL_RVARCTL 0x28 /* CAL RVAR Control */ +#define B2055_CAL_LPOCTL 0x29 /* CAL LPO Control */ +#define B2055_CAL_TS 0x2A /* CAL TS */ +#define B2055_CAL_RCCALRTS 0x2B /* CAL RCCAL READ TS */ +#define B2055_CAL_RCALRTS 0x2C /* CAL RCAL READ TS */ +#define B2055_PADDRV 0x2D /* PAD driver */ +#define B2055_XOCTL1 0x2E /* XO Control 1 */ +#define B2055_XOCTL2 0x2F /* XO Control 2 */ +#define B2055_XOREGUL 0x30 /* XO Regulator */ +#define B2055_XOMISC 0x31 /* XO misc */ +#define B2055_PLL_LFC1 0x32 /* PLL LF C1 */ +#define B2055_PLL_CALVTH 0x33 /* PLL CAL VTH */ +#define B2055_PLL_LFC2 0x34 /* PLL LF C2 */ +#define B2055_PLL_REF 0x35 /* PLL reference */ +#define B2055_PLL_LFR1 0x36 /* PLL LF R1 */ +#define B2055_PLL_PFDCP 0x37 /* PLL PFD CP */ +#define B2055_PLL_IDAC_CPOPAMP 0x38 /* PLL IDAC CPOPAMP */ +#define B2055_PLL_CPREG 0x39 /* PLL CP Regulator */ +#define B2055_PLL_RCAL 0x3A /* PLL RCAL */ +#define B2055_RF_PLLMOD0 0x3B /* RF PLL MOD0 */ +#define B2055_RF_PLLMOD1 0x3C /* RF PLL MOD1 */ +#define B2055_RF_MMDIDAC1 0x3D /* RF MMD IDAC 1 */ +#define B2055_RF_MMDIDAC0 0x3E /* RF MMD IDAC 0 */ +#define B2055_RF_MMDSP 0x3F /* RF MMD spare */ +#define B2055_VCO_CAL1 0x40 /* VCO cal 1 */ +#define B2055_VCO_CAL2 0x41 /* VCO cal 2 */ +#define B2055_VCO_CAL3 0x42 /* VCO cal 3 */ +#define B2055_VCO_CAL4 0x43 /* VCO cal 4 */ +#define B2055_VCO_CAL5 0x44 /* VCO cal 5 */ +#define B2055_VCO_CAL6 0x45 /* VCO cal 6 */ +#define B2055_VCO_CAL7 0x46 /* VCO cal 7 */ +#define B2055_VCO_CAL8 0x47 /* VCO cal 8 */ +#define B2055_VCO_CAL9 0x48 /* VCO cal 9 */ +#define B2055_VCO_CAL10 0x49 /* VCO cal 10 */ +#define B2055_VCO_CAL11 0x4A /* VCO cal 11 */ +#define B2055_VCO_CAL12 0x4B /* VCO cal 12 */ +#define B2055_VCO_CAL13 0x4C /* VCO cal 13 */ +#define B2055_VCO_CAL14 0x4D /* VCO cal 14 */ +#define B2055_VCO_CAL15 0x4E /* VCO cal 15 */ +#define B2055_VCO_CAL16 0x4F /* VCO cal 16 */ +#define B2055_VCO_KVCO 0x50 /* VCO KVCO */ +#define B2055_VCO_CAPTAIL 0x51 /* VCO CAP TAIL */ +#define B2055_VCO_IDACVCO 0x52 /* VCO IDAC VCO */ +#define B2055_VCO_REG 0x53 /* VCO Regulator */ +#define B2055_PLL_RFVTH 0x54 /* PLL RF VTH */ +#define B2055_LGBUF_CENBUF 0x55 /* LGBUF CEN BUF */ +#define B2055_LGEN_TUNE1 0x56 /* LGEN tune 1 */ +#define B2055_LGEN_TUNE2 0x57 /* LGEN tune 2 */ +#define B2055_LGEN_IDAC1 0x58 /* LGEN IDAC 1 */ +#define B2055_LGEN_IDAC2 0x59 /* LGEN IDAC 2 */ +#define B2055_LGEN_BIASC 0x5A /* LGEN BIAS counter */ +#define B2055_LGEN_BIASIDAC 0x5B /* LGEN BIAS IDAC */ +#define B2055_LGEN_RCAL 0x5C /* LGEN RCAL */ +#define B2055_LGEN_DIV 0x5D /* LGEN div */ +#define B2055_LGEN_SPARE2 0x5E /* LGEN spare 2 */ +#define B2055_C1_LGBUF_ATUNE 0x5F /* Core 1 LGBUF A tune */ +#define B2055_C1_LGBUF_GTUNE 0x60 /* Core 1 LGBUF G tune */ +#define B2055_C1_LGBUF_DIV 0x61 /* Core 1 LGBUF div */ +#define B2055_C1_LGBUF_AIDAC 0x62 /* Core 1 LGBUF A IDAC */ +#define B2055_C1_LGBUF_GIDAC 0x63 /* Core 1 LGBUF G IDAC */ +#define B2055_C1_LGBUF_IDACFO 0x64 /* Core 1 LGBUF IDAC filter override */ +#define B2055_C1_LGBUF_SPARE 0x65 /* Core 1 LGBUF spare */ +#define B2055_C1_RX_RFSPC1 0x66 /* Core 1 RX RF SPC1 */ +#define B2055_C1_RX_RFR1 0x67 /* Core 1 RX RF reg 1 */ +#define B2055_C1_RX_RFR2 0x68 /* Core 1 RX RF reg 2 */ +#define B2055_C1_RX_RFRCAL 0x69 /* Core 1 RX RF RCAL */ +#define B2055_C1_RX_BB_BLCMP 0x6A /* Core 1 RX Baseband BUFI LPF CMP */ +#define B2055_C1_RX_BB_LPF 0x6B /* Core 1 RX Baseband LPF */ +#define B2055_C1_RX_BB_MIDACHP 0x6C /* Core 1 RX Baseband MIDAC High-pass */ +#define B2055_C1_RX_BB_VGA1IDAC 0x6D /* Core 1 RX Baseband VGA1 IDAC */ +#define B2055_C1_RX_BB_VGA2IDAC 0x6E /* Core 1 RX Baseband VGA2 IDAC */ +#define B2055_C1_RX_BB_VGA3IDAC 0x6F /* Core 1 RX Baseband VGA3 IDAC */ +#define B2055_C1_RX_BB_BUFOCTL 0x70 /* Core 1 RX Baseband BUFO Control */ +#define B2055_C1_RX_BB_RCCALCTL 0x71 /* Core 1 RX Baseband RCCAL Control */ +#define B2055_C1_RX_BB_RSSICTL1 0x72 /* Core 1 RX Baseband RSSI Control 1 */ +#define B2055_C1_RX_BB_RSSICTL2 0x73 /* Core 1 RX Baseband RSSI Control 2 */ +#define B2055_C1_RX_BB_RSSICTL3 0x74 /* Core 1 RX Baseband RSSI Control 3 */ +#define B2055_C1_RX_BB_RSSICTL4 0x75 /* Core 1 RX Baseband RSSI Control 4 */ +#define B2055_C1_RX_BB_RSSICTL5 0x76 /* Core 1 RX Baseband RSSI Control 5 */ +#define B2055_C1_RX_BB_REG 0x77 /* Core 1 RX Baseband Regulator */ +#define B2055_C1_RX_BB_SPARE1 0x78 /* Core 1 RX Baseband spare 1 */ +#define B2055_C1_RX_TXBBRCAL 0x79 /* Core 1 RX TX BB RCAL */ +#define B2055_C1_TX_RF_SPGA 0x7A /* Core 1 TX RF SGM PGA */ +#define B2055_C1_TX_RF_SPAD 0x7B /* Core 1 TX RF SGM PAD */ +#define B2055_C1_TX_RF_CNTPGA1 0x7C /* Core 1 TX RF counter PGA 1 */ +#define B2055_C1_TX_RF_CNTPAD1 0x7D /* Core 1 TX RF counter PAD 1 */ +#define B2055_C1_TX_RF_PGAIDAC 0x7E /* Core 1 TX RF PGA IDAC */ +#define B2055_C1_TX_PGAPADTN 0x7F /* Core 1 TX PGA PAD TN */ +#define B2055_C1_TX_PADIDAC1 0x80 /* Core 1 TX PAD IDAC 1 */ +#define B2055_C1_TX_PADIDAC2 0x81 /* Core 1 TX PAD IDAC 2 */ +#define B2055_C1_TX_MXBGTRIM 0x82 /* Core 1 TX MX B/G TRIM */ +#define B2055_C1_TX_RF_RCAL 0x83 /* Core 1 TX RF RCAL */ +#define B2055_C1_TX_RF_PADTSSI1 0x84 /* Core 1 TX RF PAD TSSI1 */ +#define B2055_C1_TX_RF_PADTSSI2 0x85 /* Core 1 TX RF PAD TSSI2 */ +#define B2055_C1_TX_RF_SPARE 0x86 /* Core 1 TX RF spare */ +#define B2055_C1_TX_RF_IQCAL1 0x87 /* Core 1 TX RF I/Q CAL 1 */ +#define B2055_C1_TX_RF_IQCAL2 0x88 /* Core 1 TX RF I/Q CAL 2 */ +#define B2055_C1_TXBB_RCCAL 0x89 /* Core 1 TXBB RC CAL Control */ +#define B2055_C1_TXBB_LPF1 0x8A /* Core 1 TXBB LPF 1 */ +#define B2055_C1_TX_VOSCNCL 0x8B /* Core 1 TX VOS CNCL */ +#define B2055_C1_TX_LPF_MXGMIDAC 0x8C /* Core 1 TX LPF MXGM IDAC */ +#define B2055_C1_TX_BB_MXGM 0x8D /* Core 1 TX BB MXGM */ +#define B2055_C2_LGBUF_ATUNE 0x8E /* Core 2 LGBUF A tune */ +#define B2055_C2_LGBUF_GTUNE 0x8F /* Core 2 LGBUF G tune */ +#define B2055_C2_LGBUF_DIV 0x90 /* Core 2 LGBUF div */ +#define B2055_C2_LGBUF_AIDAC 0x91 /* Core 2 LGBUF A IDAC */ +#define B2055_C2_LGBUF_GIDAC 0x92 /* Core 2 LGBUF G IDAC */ +#define B2055_C2_LGBUF_IDACFO 0x93 /* Core 2 LGBUF IDAC filter override */ +#define B2055_C2_LGBUF_SPARE 0x94 /* Core 2 LGBUF spare */ +#define B2055_C2_RX_RFSPC1 0x95 /* Core 2 RX RF SPC1 */ +#define B2055_C2_RX_RFR1 0x96 /* Core 2 RX RF reg 1 */ +#define B2055_C2_RX_RFR2 0x97 /* Core 2 RX RF reg 2 */ +#define B2055_C2_RX_RFRCAL 0x98 /* Core 2 RX RF RCAL */ +#define B2055_C2_RX_BB_BLCMP 0x99 /* Core 2 RX Baseband BUFI LPF CMP */ +#define B2055_C2_RX_BB_LPF 0x9A /* Core 2 RX Baseband LPF */ +#define B2055_C2_RX_BB_MIDACHP 0x9B /* Core 2 RX Baseband MIDAC High-pass */ +#define B2055_C2_RX_BB_VGA1IDAC 0x9C /* Core 2 RX Baseband VGA1 IDAC */ +#define B2055_C2_RX_BB_VGA2IDAC 0x9D /* Core 2 RX Baseband VGA2 IDAC */ +#define B2055_C2_RX_BB_VGA3IDAC 0x9E /* Core 2 RX Baseband VGA3 IDAC */ +#define B2055_C2_RX_BB_BUFOCTL 0x9F /* Core 2 RX Baseband BUFO Control */ +#define B2055_C2_RX_BB_RCCALCTL 0xA0 /* Core 2 RX Baseband RCCAL Control */ +#define B2055_C2_RX_BB_RSSICTL1 0xA1 /* Core 2 RX Baseband RSSI Control 1 */ +#define B2055_C2_RX_BB_RSSICTL2 0xA2 /* Core 2 RX Baseband RSSI Control 2 */ +#define B2055_C2_RX_BB_RSSICTL3 0xA3 /* Core 2 RX Baseband RSSI Control 3 */ +#define B2055_C2_RX_BB_RSSICTL4 0xA4 /* Core 2 RX Baseband RSSI Control 4 */ +#define B2055_C2_RX_BB_RSSICTL5 0xA5 /* Core 2 RX Baseband RSSI Control 5 */ +#define B2055_C2_RX_BB_REG 0xA6 /* Core 2 RX Baseband Regulator */ +#define B2055_C2_RX_BB_SPARE1 0xA7 /* Core 2 RX Baseband spare 1 */ +#define B2055_C2_RX_TXBBRCAL 0xA8 /* Core 2 RX TX BB RCAL */ +#define B2055_C2_TX_RF_SPGA 0xA9 /* Core 2 TX RF SGM PGA */ +#define B2055_C2_TX_RF_SPAD 0xAA /* Core 2 TX RF SGM PAD */ +#define B2055_C2_TX_RF_CNTPGA1 0xAB /* Core 2 TX RF counter PGA 1 */ +#define B2055_C2_TX_RF_CNTPAD1 0xAC /* Core 2 TX RF counter PAD 1 */ +#define B2055_C2_TX_RF_PGAIDAC 0xAD /* Core 2 TX RF PGA IDAC */ +#define B2055_C2_TX_PGAPADTN 0xAE /* Core 2 TX PGA PAD TN */ +#define B2055_C2_TX_PADIDAC1 0xAF /* Core 2 TX PAD IDAC 1 */ +#define B2055_C2_TX_PADIDAC2 0xB0 /* Core 2 TX PAD IDAC 2 */ +#define B2055_C2_TX_MXBGTRIM 0xB1 /* Core 2 TX MX B/G TRIM */ +#define B2055_C2_TX_RF_RCAL 0xB2 /* Core 2 TX RF RCAL */ +#define B2055_C2_TX_RF_PADTSSI1 0xB3 /* Core 2 TX RF PAD TSSI1 */ +#define B2055_C2_TX_RF_PADTSSI2 0xB4 /* Core 2 TX RF PAD TSSI2 */ +#define B2055_C2_TX_RF_SPARE 0xB5 /* Core 2 TX RF spare */ +#define B2055_C2_TX_RF_IQCAL1 0xB6 /* Core 2 TX RF I/Q CAL 1 */ +#define B2055_C2_TX_RF_IQCAL2 0xB7 /* Core 2 TX RF I/Q CAL 2 */ +#define B2055_C2_TXBB_RCCAL 0xB8 /* Core 2 TXBB RC CAL Control */ +#define B2055_C2_TXBB_LPF1 0xB9 /* Core 2 TXBB LPF 1 */ +#define B2055_C2_TX_VOSCNCL 0xBA /* Core 2 TX VOS CNCL */ +#define B2055_C2_TX_LPF_MXGMIDAC 0xBB /* Core 2 TX LPF MXGM IDAC */ +#define B2055_C2_TX_BB_MXGM 0xBC /* Core 2 TX BB MXGM */ +#define B2055_PRG_GCHP21 0xBD /* PRG GC HPVGA23 21 */ +#define B2055_PRG_GCHP22 0xBE /* PRG GC HPVGA23 22 */ +#define B2055_PRG_GCHP23 0xBF /* PRG GC HPVGA23 23 */ +#define B2055_PRG_GCHP24 0xC0 /* PRG GC HPVGA23 24 */ +#define B2055_PRG_GCHP25 0xC1 /* PRG GC HPVGA23 25 */ +#define B2055_PRG_GCHP26 0xC2 /* PRG GC HPVGA23 26 */ +#define B2055_PRG_GCHP27 0xC3 /* PRG GC HPVGA23 27 */ +#define B2055_PRG_GCHP28 0xC4 /* PRG GC HPVGA23 28 */ +#define B2055_PRG_GCHP29 0xC5 /* PRG GC HPVGA23 29 */ +#define B2055_PRG_GCHP30 0xC6 /* PRG GC HPVGA23 30 */ +#define B2055_C1_LNA_GAINBST 0xCD /* Core 1 LNA GAINBST */ +#define B2055_C1_B0NB_RSSIVCM 0xD2 /* Core 1 B0 narrow-band RSSI VCM */ +#define B2055_C1_GENSPARE2 0xD6 /* Core 1 GEN spare 2 */ +#define B2055_C2_LNA_GAINBST 0xD9 /* Core 2 LNA GAINBST */ +#define B2055_C2_B0NB_RSSIVCM 0xDE /* Core 2 B0 narrow-band RSSI VCM */ +#define B2055_C2_GENSPARE2 0xE2 /* Core 2 GEN spare 2 */ + + + +struct b43_wldev; + +int b43_phy_initn(struct b43_wldev *dev); + +void b43_nphy_radio_turn_on(struct b43_wldev *dev); +void b43_nphy_radio_turn_off(struct b43_wldev *dev); + +int b43_nphy_selectchannel(struct b43_wldev *dev, u8 channel); + +void b43_nphy_xmitpower(struct b43_wldev *dev); +void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna); + +#endif /* B43_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c index 7ff091e69f05..71507b260b6d 100644 --- a/drivers/net/wireless/b43/phy.c +++ b/drivers/net/wireless/b43/phy.c @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -31,9 +31,12 @@ #include "b43.h" #include "phy.h" +#include "nphy.h" #include "main.h" #include "tables.h" #include "lo.h" +#include "wa.h" + static const s8 b43_tssi2dbm_b_table[] = { 0x4D, 0x4C, 0x4B, 0x4A, @@ -225,42 +228,30 @@ static void b43_shm_clear_tssi(struct b43_wldev *dev) } } -void b43_raw_phy_lock(struct b43_wldev *dev) +/* Lock the PHY registers against concurrent access from the microcode. + * This lock is nonrecursive. */ +void b43_phy_lock(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - - B43_WARN_ON(!irqs_disabled()); - - /* We had a check for MACCTL==0 here, but I think that doesn't - * make sense, as MACCTL is never 0 when this is called. - * --mb */ - B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0); +#if B43_DEBUG + B43_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); - if (dev->dev->id.revision < 3) { - b43_mac_suspend(dev); - spin_lock(&phy->lock); - } else { - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); - } - phy->locked = 1; + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, B43_PS_AWAKE); } -void b43_raw_phy_unlock(struct b43_wldev *dev) +void b43_phy_unlock(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; +#if B43_DEBUG + B43_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif + B43_WARN_ON(dev->dev->id.revision < 3); - B43_WARN_ON(!irqs_disabled()); - if (dev->dev->id.revision < 3) { - if (phy->locked) { - spin_unlock(&phy->lock); - b43_mac_enable(dev); - } - } else { - if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) - b43_power_saving_ctl_bits(dev, 0); - } - phy->locked = 0; + if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) + b43_power_saving_ctl_bits(dev, 0); } /* Different PHYs require different register routing flags. @@ -271,15 +262,30 @@ static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy, { if (phy->type == B43_PHYTYPE_A) { /* OFDM registers are base-registers for the A-PHY. */ - offset &= ~B43_PHYROUTE_OFDM_GPHY; + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_OFDM_GPHY) { + offset &= ~B43_PHYROUTE; + offset |= B43_PHYROUTE_BASE; + } } - if (offset & B43_PHYROUTE_EXT_GPHY) { + +#if B43_DEBUG + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_EXT_GPHY) { /* Ext-G registers are only available on G-PHYs */ if (phy->type != B43_PHYTYPE_G) { - b43dbg(dev->wl, "EXT-G PHY access at " - "0x%04X on %u type PHY\n", offset, phy->type); + b43err(dev->wl, "Invalid EXT-G PHY access at " + "0x%04X on PHY type %u\n", offset, phy->type); + dump_stack(); } } + if ((offset & B43_PHYROUTE) == B43_PHYROUTE_N_BMODE) { + /* N-BMODE registers are only available on N-PHYs */ + if (phy->type != B43_PHYTYPE_N) { + b43err(dev->wl, "Invalid N-BMODE PHY access at " + "0x%04X on PHY type %u\n", offset, phy->type); + dump_stack(); + } + } +#endif /* B43_DEBUG */ return offset; } @@ -299,11 +305,26 @@ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val) offset = adjust_phyreg_for_phytype(phy, offset, dev); b43_write16(dev, B43_MMIO_PHY_CONTROL, offset); - mmiowb(); b43_write16(dev, B43_MMIO_PHY_DATA, val); } -static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower); +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) & mask); +} + +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_phy_write(dev, offset, + b43_phy_read(dev, offset) | set); +} + +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_phy_write(dev, offset, + (b43_phy_read(dev, offset) & mask) | set); +} /* Adjust the transmission power output (G-PHY) */ void b43_set_txpower_g(struct b43_wldev *dev, @@ -763,366 +784,96 @@ static void b43_phy_init_pctl(struct b43_wldev *dev) b43_shm_clear_tssi(dev); } -static void b43_phy_agcsetup(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; - u16 offset = 0x0000; - - if (phy->rev == 1) - offset = 0x4C00; - - b43_ofdmtab_write16(dev, offset, 0, 0x00FE); - b43_ofdmtab_write16(dev, offset, 1, 0x000D); - b43_ofdmtab_write16(dev, offset, 2, 0x0013); - b43_ofdmtab_write16(dev, offset, 3, 0x0019); - - if (phy->rev == 1) { - b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710); - b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83); - b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83); - b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D); - b43_phy_write(dev, 0x0455, 0x0004); - } - - b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5) - & 0x00FF) | 0x5700); - b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) - & 0xFF80) | 0x000F); - b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A) - & 0xC07F) | 0x2B80); - b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) - & 0xF0FF) | 0x0300); - - b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) - | 0x0008); - - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xFFF0) | 0x0008); - b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1) - & 0xF0FF) | 0x0600); - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xF0FF) | 0x0700); - b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0) - & 0xF0FF) | 0x0100); - - if (phy->rev == 1) { - b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2) - & 0xFFF0) | 0x0007); - } - - b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) - & 0xFF00) | 0x001C); - b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488) - & 0xC0FF) | 0x0200); - b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) - & 0xFF00) | 0x001C); - b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) - & 0xFF00) | 0x0020); - b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489) - & 0xC0FF) | 0x0200); - b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482) - & 0xFF00) | 0x002E); - b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496) - & 0x00FF) | 0x1A00); - b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) - & 0xFF00) | 0x0028); - b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481) - & 0x00FF) | 0x2C00); - - if (phy->rev == 1) { - b43_phy_write(dev, 0x0430, 0x092B); - b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B) - & 0xFFE1) | 0x0002); - } else { - b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B) - & 0xFFE1); - b43_phy_write(dev, 0x041F, 0x287A); - b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) - & 0xFFF0) | 0x0004); - } - - if (phy->rev >= 6) { - b43_phy_write(dev, 0x0422, 0x287A); - b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420) - & 0x0FFF) | 0x3000); - } - - b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8) - & 0x8080) | 0x7874); - b43_phy_write(dev, 0x048E, 0x1C00); - - offset = 0x0800; - if (phy->rev == 1) { - offset = 0x5400; - b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB) - & 0xF0FF) | 0x0600); - b43_phy_write(dev, 0x048B, 0x005E); - b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C) - & 0xFF00) | 0x001E); - b43_phy_write(dev, 0x048D, 0x0002); - } - b43_ofdmtab_write16(dev, offset, 0, 0x00); - b43_ofdmtab_write16(dev, offset, 1, 0x07); - b43_ofdmtab_write16(dev, offset, 2, 0x10); - b43_ofdmtab_write16(dev, offset, 3, 0x1C); - - if (phy->rev >= 6) { - b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) - & 0xFFFC); - b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426) - & 0xEFFF); - } -} - -static void b43_phy_setupg(struct b43_wldev *dev) +static void b43_phy_rssiagc(struct b43_wldev *dev, u8 enable) { - struct ssb_bus *bus = dev->dev->bus; - struct b43_phy *phy = &dev->phy; - u16 i; - - B43_WARN_ON(phy->type != B43_PHYTYPE_G); - if (phy->rev == 1) { - b43_phy_write(dev, 0x0406, 0x4F19); - b43_phy_write(dev, B43_PHY_G_CRS, - (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) | - 0x0340); - b43_phy_write(dev, 0x042C, 0x005A); - b43_phy_write(dev, 0x0427, 0x001A); - - for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5800, i, - b43_tab_finefreqg[i]); - for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]); - for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) - b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]); - } else { - /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ - b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654); - - if (phy->rev == 2) { - b43_phy_write(dev, 0x04C0, 0x1861); - b43_phy_write(dev, 0x04C1, 0x0271); - } else if (phy->rev > 2) { - b43_phy_write(dev, 0x04C0, 0x0098); - b43_phy_write(dev, 0x04C1, 0x0070); - b43_phy_write(dev, 0x04C9, 0x0080); - } - b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800); - - for (i = 0; i < 64; i++) - b43_ofdmtab_write16(dev, 0x4000, i, i); - for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]); - } - - if (phy->rev <= 2) - for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1400, i, - b43_tab_noisescaleg1[i]); - else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200)) - for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1400, i, - b43_tab_noisescaleg3[i]); - else - for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1400, i, - b43_tab_noisescaleg2[i]); - - if (phy->rev == 2) - for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5000, i, - b43_tab_sigmasqr1[i]); - else if ((phy->rev > 2) && (phy->rev <= 8)) - for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5000, i, - b43_tab_sigmasqr2[i]); - - if (phy->rev == 1) { - for (i = 0; i < B43_TAB_RETARD_SIZE; i++) - b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); - for (i = 4; i < 20; i++) - b43_ofdmtab_write16(dev, 0x5400, i, 0x0020); - b43_phy_agcsetup(dev); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306) && - (bus->boardinfo.rev == 0x17)) - return; - - b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002); - b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001); - } else { - for (i = 0; i < 0x20; i++) - b43_ofdmtab_write16(dev, 0x1000, i, 0x0820); - b43_phy_agcsetup(dev); - b43_phy_read(dev, 0x0400); /* dummy read */ - b43_phy_write(dev, 0x0403, 0x1000); - b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); - - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - (bus->boardinfo.type == SSB_BOARD_BU4306) && - (bus->boardinfo.rev == 0x17)) - return; - - b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002); - b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001); - } -} - -/* Initialize the noisescaletable for APHY */ -static void b43_phy_init_noisescaletbl(struct b43_wldev *dev) -{ - struct b43_phy *phy = &dev->phy; int i; - for (i = 0; i < 12; i++) { - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + if (dev->phy.rev < 3) { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, 0xFFF8); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0xFFF8); + } else - b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); - } - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x6700); - else - b43_ofdmtab_write16(dev, 0x1400, i, 0x2300); - for (i = 0; i < 11; i++) { - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x6767); + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) { + b43_ofdmtab_write16(dev, + B43_OFDMTAB_LNAHPFGAIN1, i, b43_tab_rssiagc1[i]); + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc1[i]); + } + } else { + if (enable) + for (i = 0; i < B43_TAB_RSSIAGC1_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, 0x0820); else - b43_ofdmtab_write16(dev, 0x1400, i, 0x2323); + for (i = 0; i < B43_TAB_RSSIAGC2_SIZE; i++) + b43_ofdmtab_write16(dev, + B43_OFDMTAB_WRSSI, i, b43_tab_rssiagc2[i]); } - if (phy->rev == 2) - b43_ofdmtab_write16(dev, 0x1400, i, 0x0067); - else - b43_ofdmtab_write16(dev, 0x1400, i, 0x0023); } -static void b43_phy_setupa(struct b43_wldev *dev) +static void b43_phy_ww(struct b43_wldev *dev) { - struct b43_phy *phy = &dev->phy; - u16 i; - - B43_WARN_ON(phy->type != B43_PHYTYPE_A); - switch (phy->rev) { - case 2: - b43_phy_write(dev, 0x008E, 0x3800); - b43_phy_write(dev, 0x0035, 0x03FF); - b43_phy_write(dev, 0x0036, 0x0400); - - b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); - - b43_phy_write(dev, 0x001C, 0x0FF9); - b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); - b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF); - b43_radio_write16(dev, 0x0002, 0x07BF); - - b43_phy_write(dev, 0x0024, 0x4680); - b43_phy_write(dev, 0x0020, 0x0003); - b43_phy_write(dev, 0x001D, 0x0F40); - b43_phy_write(dev, 0x001F, 0x1C00); - - b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) - & 0x00FF) | 0x0400); - b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) - & 0xFBFF); - b43_phy_write(dev, 0x008E, 0x58C1); - - b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); - b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); - - b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013); - b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015); - b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015); - b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019); - - b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); - - for (i = 0; i < 16; i++) - b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F); - - b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044); - b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201); - b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040); - b43_ofdmtab_write16(dev, 0x3001, 0, - (b43_ofdmtab_read16(dev, 0x3001, 0) & - 0x0010) | 0x0008); - - for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) - b43_ofdmtab_write16(dev, 0x5800, i, - b43_tab_finefreqa[i]); - for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]); - for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) - b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]); - b43_phy_init_noisescaletbl(dev); - for (i = 0; i < B43_TAB_RETARD_SIZE; i++) - b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]); - break; - case 3: - for (i = 0; i < 64; i++) - b43_ofdmtab_write16(dev, 0x4000, i, i); - - b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051); - - b43_phy_write(dev, 0x001C, 0x0FF9); - b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F); - b43_radio_write16(dev, 0x0002, 0x07BF); - - b43_phy_write(dev, 0x0024, 0x4680); - b43_phy_write(dev, 0x0020, 0x0003); - b43_phy_write(dev, 0x001D, 0x0F40); - b43_phy_write(dev, 0x001F, 0x1C00); - b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A) - & 0x00FF) | 0x0400); - - b43_ofdmtab_write16(dev, 0x3000, 1, - (b43_ofdmtab_read16(dev, 0x3000, 1) - & 0x0010) | 0x0008); - for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) { - b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]); - } - b43_phy_init_noisescaletbl(dev); - for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { - b43_ofdmtab_write16(dev, 0x5000, i, - b43_tab_sigmasqr1[i]); - } - - b43_phy_write(dev, 0x0003, 0x1808); - - b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A); - b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030); - b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A); - - b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013); - b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015); - b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015); - b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019); - - b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003); - b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007); + u16 b, curr_s, best_s = 0xFFFF; + int i; - b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F); - b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014); - break; - default: - B43_WARN_ON(1); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x0009, + b43_radio_read16(dev, 0x0009) | 0x0080); + b43_radio_write16(dev, 0x0012, + (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002); + b43_wa_initgains(dev); + b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5); + b = b43_phy_read(dev, B43_PHY_PWRDOWN); + b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) | 0x0004); + for (i = 0x10; i <= 0x20; i++) { + b43_radio_write16(dev, 0x0013, i); + curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF; + if (!curr_s) { + best_s = 0x0000; + break; + } else if (curr_s >= 0x0080) + curr_s = 0x0100 - curr_s; + if (curr_s < best_s) + best_s = curr_s; } + b43_phy_write(dev, B43_PHY_PWRDOWN, b); + b43_radio_write16(dev, 0x0004, + b43_radio_read16(dev, 0x0004) & 0xFFFB); + b43_radio_write16(dev, 0x0013, best_s); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC); + b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80); + b43_phy_write(dev, B43_PHY_OFDM(0xB6), 0x1C00); + b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0); + b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0); + b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF); + b43_phy_write(dev, B43_PHY_OFDM(0xBB), + (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053); + b43_phy_write(dev, B43_PHY_OFDM61, + (b43_phy_read(dev, B43_PHY_OFDM61 & 0xFE1F)) | 0x0120); + b43_phy_write(dev, B43_PHY_OFDM(0x13), + (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000); + b43_phy_write(dev, B43_PHY_OFDM(0x14), + (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017); + for (i = 0; i < 6; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0D, 0x000E); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013); + b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030); + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); } /* Initialize APHY. This is also called for the GPHY in some cases. */ @@ -1130,64 +881,54 @@ static void b43_phy_inita(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->bus; struct b43_phy *phy = &dev->phy; - u16 tval; might_sleep(); - if (phy->type == B43_PHYTYPE_A) { - b43_phy_setupa(dev); - } else { - b43_phy_setupg(dev); - if (phy->gmode && - (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)) - b43_phy_write(dev, 0x046E, 0x03CF); - return; + if (phy->rev >= 6) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000); + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010); + else + b43_phy_write(dev, B43_PHY_ENCORE, + b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010); } - b43_phy_write(dev, B43_PHY_A_CRS, - (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340); - b43_phy_write(dev, 0x0034, 0x0001); + b43_wa_all(dev); - //TODO: RSSI AGC - b43_phy_write(dev, B43_PHY_A_CRS, - b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14)); - b43_radio_init2060(dev); + if (phy->type == B43_PHYTYPE_A) { + if (phy->gmode && (phy->rev < 3)) + b43_phy_write(dev, 0x0034, + b43_phy_read(dev, 0x0034) | 0x0001); + b43_phy_rssiagc(dev, 0); - if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && - ((bus->boardinfo.type == SSB_BOARD_BU4306) || - (bus->boardinfo.type == SSB_BOARD_BU4309))) { - if (phy->lofcal == 0xFFFF) { - //TODO: LOF Cal - b43_radio_set_tx_iq(dev); - } else - b43_radio_write16(dev, 0x001E, phy->lofcal); - } + b43_phy_write(dev, B43_PHY_CRS0, + b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN); - b43_phy_write(dev, 0x007A, 0xF111); + b43_radio_init2060(dev); - if (phy->cur_idle_tssi == 0) { - b43_radio_write16(dev, 0x0019, 0x0000); - b43_radio_write16(dev, 0x0017, 0x0020); - - tval = b43_ofdmtab_read16(dev, 0x3001, 0); - if (phy->rev == 1) { - b43_ofdmtab_write16(dev, 0x3001, 0, - (b43_ofdmtab_read16(dev, 0x3001, 0) - & 0xFF87) - | 0x0058); - } else { - b43_ofdmtab_write16(dev, 0x3001, 0, - (b43_ofdmtab_read16(dev, 0x3001, 0) - & 0xFFC3) - | 0x002C); + if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) && + ((bus->boardinfo.type == SSB_BOARD_BU4306) || + (bus->boardinfo.type == SSB_BOARD_BU4309))) { + ; //TODO: A PHY LO } - b43_dummy_transmission(dev); - phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL); - b43_ofdmtab_write16(dev, 0x3001, 0, tval); - b43_radio_set_txpower_a(dev, 0x0018); + if (phy->rev >= 3) + b43_phy_ww(dev); + + hardware_pctl_init_aphy(dev); + + //TODO: radar detection + } + + if ((phy->type == B43_PHYTYPE_G) && + (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) { + b43_phy_write(dev, B43_PHY_OFDM(0x6E), + (b43_phy_read(dev, B43_PHY_OFDM(0x6E)) + & 0xE000) | 0x3CF); } - b43_shm_clear_tssi(dev); } static void b43_phy_initb2(struct b43_wldev *dev) @@ -1286,7 +1027,7 @@ static void b43_phy_initb4(struct b43_wldev *dev) if (phy->radio_ver == 0x2050) b43_phy_write(dev, 0x002A, 0x88C2); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_calc_nrssi_slope(dev); b43_calc_nrssi_threshold(dev); } @@ -1433,7 +1174,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_radio_write16(dev, 0x5A, 0x88); b43_radio_write16(dev, 0x5B, 0x6B); b43_radio_write16(dev, 0x5C, 0x0F); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) { b43_radio_write16(dev, 0x5D, 0xFA); b43_radio_write16(dev, 0x5E, 0xD8); } else { @@ -1525,7 +1266,7 @@ static void b43_phy_initb6(struct b43_wldev *dev) b43_phy_write(dev, 0x0062, 0x0007); b43_radio_init2050(dev); b43_lo_g_measure(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI) { b43_calc_nrssi_slope(dev); b43_calc_nrssi_threshold(dev); } @@ -1552,14 +1293,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER); backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL); } - backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A)); - backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59)); - backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58)); - backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A)); - backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03)); + backup_phy[6] = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + backup_phy[7] = b43_phy_read(dev, B43_PHY_CCK(0x59)); + backup_phy[8] = b43_phy_read(dev, B43_PHY_CCK(0x58)); + backup_phy[9] = b43_phy_read(dev, B43_PHY_CCK(0x0A)); + backup_phy[10] = b43_phy_read(dev, B43_PHY_CCK(0x03)); backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK); backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL); - backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B)); + backup_phy[13] = b43_phy_read(dev, B43_PHY_CCK(0x2B)); backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL); backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE); backup_bband = phy->bbatt.att; @@ -1601,12 +1342,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) (b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFCF) | 0x10); - b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780); - b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); - b43_phy_write(dev, B43_PHY_BASE(0x0A), - b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000); + b43_phy_write(dev, B43_PHY_CCK(0x0A), + b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000); if (phy->rev != 1) { /* Not in specs, but needed to prevent PPC machine check */ b43_phy_write(dev, B43_PHY_ANALOGOVER, b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004); @@ -1614,8 +1355,8 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_read(dev, B43_PHY_ANALOGOVERVAL) & 0xFFFB); } - b43_phy_write(dev, B43_PHY_BASE(0x03), - (b43_phy_read(dev, B43_PHY_BASE(0x03)) + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) & 0xFF9F) | 0x40); if (phy->radio_rev == 8) { @@ -1633,11 +1374,11 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020); b43_phy_write(dev, B43_PHY_LO_CTL, 0); - b43_phy_write(dev, B43_PHY_BASE(0x2B), - (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) & 0xFFC0) | 0x01); - b43_phy_write(dev, B43_PHY_BASE(0x2B), - (b43_phy_read(dev, B43_PHY_BASE(0x2B)) + b43_phy_write(dev, B43_PHY_CCK(0x2B), + (b43_phy_read(dev, B43_PHY_CCK(0x2B)) & 0xC0FF) | 0x800); b43_phy_write(dev, B43_PHY_RFOVER, @@ -1645,7 +1386,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_RFOVERVAL, b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) { + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) { if (phy->rev >= 7) { b43_phy_write(dev, B43_PHY_RFOVER, b43_phy_read(dev, B43_PHY_RFOVER) @@ -1708,14 +1449,14 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]); b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]); } - b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]); - b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]); - b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]); - b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]); - b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]); + b43_phy_write(dev, B43_PHY_CCK(0x5A), backup_phy[6]); + b43_phy_write(dev, B43_PHY_CCK(0x59), backup_phy[7]); + b43_phy_write(dev, B43_PHY_CCK(0x58), backup_phy[8]); + b43_phy_write(dev, B43_PHY_CCK(0x0A), backup_phy[9]); + b43_phy_write(dev, B43_PHY_CCK(0x03), backup_phy[10]); b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]); b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]); - b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]); + b43_phy_write(dev, B43_PHY_CCK(0x2B), backup_phy[13]); b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]); b43_phy_set_baseband_attenuation(dev, backup_bband); @@ -1807,26 +1548,26 @@ static void b43_phy_initg(struct b43_wldev *dev) | phy->lo_control->tx_bias); } if (phy->rev >= 6) { - b43_phy_write(dev, B43_PHY_BASE(0x36), - (b43_phy_read(dev, B43_PHY_BASE(0x36)) + b43_phy_write(dev, B43_PHY_CCK(0x36), + (b43_phy_read(dev, B43_PHY_CCK(0x36)) & 0x0FFF) | (phy->lo_control-> tx_bias << 12)); } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075); + if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075); else - b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F); + b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F); if (phy->rev < 2) - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x101); else - b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202); + b43_phy_write(dev, B43_PHY_CCK(0x2F), 0x202); } if (phy->gmode || phy->rev >= 2) { b43_lo_g_adjust(dev); b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078); } - if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { /* The specs state to update the NRSSI LT with * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. @@ -1995,7 +1736,6 @@ void b43_phy_xmitpower(struct b43_wldev *dev) int rfatt_delta, bbatt_delta; int rfatt, bbatt; u8 tx_control; - unsigned long phylock_flags; tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058); v0 = (s8) (tmp & 0x00FF); @@ -2036,16 +1776,15 @@ void b43_phy_xmitpower(struct b43_wldev *dev) estimated_pwr = b43_phy_estimate_power_out(dev, average); - max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; - if ((dev->dev->bus->sprom.r1. - boardflags_lo & B43_BFL_PACTRL) - && (phy->type == B43_PHYTYPE_G)) + max_pwr = dev->dev->bus->sprom.maxpwr_bg; + if ((dev->dev->bus->sprom.boardflags_lo + & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G)) max_pwr -= 0x3; if (unlikely(max_pwr <= 0)) { b43warn(dev->wl, "Invalid max-TX-power value in SPROM.\n"); max_pwr = 60; /* fake it */ - dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + dev->dev->bus->sprom.maxpwr_bg = max_pwr; } /*TODO: @@ -2103,7 +1842,7 @@ void b43_phy_xmitpower(struct b43_wldev *dev) B43_TXCTL_TXMIX; rfatt += 2; bbatt += 2; - } else if (dev->dev->bus->sprom.r1. + } else if (dev->dev->bus->sprom. boardflags_lo & B43_BFL_PACTRL) { bbatt += 4 * (rfatt - 2); @@ -2127,15 +1866,18 @@ void b43_phy_xmitpower(struct b43_wldev *dev) phy->bbatt.att = bbatt; /* Adjust the hardware */ - b43_phy_lock(dev, phylock_flags); + b43_phy_lock(dev); b43_radio_lock(dev); b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control); b43_lo_g_ctl_mark_cur_used(dev); b43_radio_unlock(dev); - b43_phy_unlock(dev, phylock_flags); + b43_phy_unlock(dev); break; } + case B43_PHYTYPE_N: + b43_nphy_xmitpower(dev); + break; default: B43_WARN_ON(1); } @@ -2179,13 +1921,13 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) s8 *dyn_tssi2dbm; if (phy->type == B43_PHYTYPE_A) { - pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0); - pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1); - pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2); + pab0 = (s16) (dev->dev->bus->sprom.pa1b0); + pab1 = (s16) (dev->dev->bus->sprom.pa1b1); + pab2 = (s16) (dev->dev->bus->sprom.pa1b2); } else { - pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0); - pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1); - pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2); + pab0 = (s16) (dev->dev->bus->sprom.pa0b0); + pab1 = (s16) (dev->dev->bus->sprom.pa0b1); + pab2 = (s16) (dev->dev->bus->sprom.pa0b2); } if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { @@ -2198,17 +1940,17 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) pab0 != -1 && pab1 != -1 && pab2 != -1) { /* The pabX values are set in SPROM. Use them. */ if (phy->type == B43_PHYTYPE_A) { - if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 && - (s8) dev->dev->bus->sprom.r1.itssi_a != -1) + if ((s8) dev->dev->bus->sprom.itssi_a != 0 && + (s8) dev->dev->bus->sprom.itssi_a != -1) phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.r1.itssi_a); + (s8) (dev->dev->bus->sprom.itssi_a); else phy->tgt_idle_tssi = 62; } else { - if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 && - (s8) dev->dev->bus->sprom.r1.itssi_bg != -1) + if ((s8) dev->dev->bus->sprom.itssi_bg != 0 && + (s8) dev->dev->bus->sprom.itssi_bg != -1) phy->tgt_idle_tssi = - (s8) (dev->dev->bus->sprom.r1.itssi_bg); + (s8) (dev->dev->bus->sprom.itssi_bg); else phy->tgt_idle_tssi = 62; } @@ -2255,41 +1997,44 @@ int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev) int b43_phy_init(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; - int err = -ENODEV; + bool unsupported = 0; + int err = 0; switch (phy->type) { case B43_PHYTYPE_A: - if (phy->rev == 2 || phy->rev == 3) { + if (phy->rev == 2 || phy->rev == 3) b43_phy_inita(dev); - err = 0; - } + else + unsupported = 1; break; case B43_PHYTYPE_B: switch (phy->rev) { case 2: b43_phy_initb2(dev); - err = 0; break; case 4: b43_phy_initb4(dev); - err = 0; break; case 5: b43_phy_initb5(dev); - err = 0; break; case 6: b43_phy_initb6(dev); - err = 0; break; + default: + unsupported = 1; } break; case B43_PHYTYPE_G: b43_phy_initg(dev); - err = 0; break; + case B43_PHYTYPE_N: + err = b43_phy_initn(dev); + break; + default: + unsupported = 1; } - if (err) + if (unsupported) b43err(dev->wl, "Unknown PHYTYPE found\n"); return err; @@ -2392,6 +2137,9 @@ void b43_set_rx_antenna(struct b43_wldev *dev, int antenna) << B43_PHY_BBANDCFG_RXANT_SHIFT; b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp); break; + case B43_PHYTYPE_N: + b43_nphy_set_rxantenna(dev, antenna); + break; default: B43_WARN_ON(1); } @@ -2421,6 +2169,7 @@ void b43_radio_lock(struct b43_wldev *dev) u32 macctl; macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK); macctl |= B43_MACCTL_RADIOLOCK; b43_write32(dev, B43_MMIO_MACCTL, macctl); /* Commit the write and wait for the device @@ -2437,6 +2186,7 @@ void b43_radio_unlock(struct b43_wldev *dev) b43_read16(dev, B43_MMIO_PHY_VER); /* unlock */ macctl = b43_read32(dev, B43_MMIO_MACCTL); + B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK)); macctl &= ~B43_MACCTL_RADIOLOCK; b43_write32(dev, B43_MMIO_MACCTL, macctl); } @@ -2445,9 +2195,12 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) { struct b43_phy *phy = &dev->phy; + /* Offset 1 is a 32-bit register. */ + B43_WARN_ON(offset == 1); + switch (phy->type) { case B43_PHYTYPE_A: - offset |= 0x0040; + offset |= 0x40; break; case B43_PHYTYPE_B: if (phy->radio_ver == 0x2053) { @@ -2463,6 +2216,14 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) case B43_PHYTYPE_G: offset |= 0x80; break; + case B43_PHYTYPE_N: + offset |= 0x100; + break; + case B43_PHYTYPE_LP: + /* No adjustment required. */ + break; + default: + B43_WARN_ON(1); } b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); @@ -2471,11 +2232,31 @@ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset) void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val) { + /* Offset 1 is a 32-bit register. */ + B43_WARN_ON(offset == 1); + b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset); - mmiowb(); b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val); } +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) & mask); +} + +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set) +{ + b43_radio_write16(dev, offset, + b43_radio_read16(dev, offset) | set); +} + +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) +{ + b43_radio_write16(dev, offset, + (b43_radio_read16(dev, offset) & mask) | set); +} + static void b43_set_all_gains(struct b43_wldev *dev, s16 first, s16 second, s16 third) { @@ -2605,12 +2386,11 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev) u8 ret[13]; unsigned int channel = phy->channel; unsigned int i, j, start, end; - unsigned long phylock_flags; if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0))) return 0; - b43_phy_lock(dev, phylock_flags); + b43_phy_lock(dev); b43_radio_lock(dev); b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC); b43_phy_write(dev, B43_PHY_G_CRS, @@ -2639,7 +2419,7 @@ u8 b43_radio_aci_scan(struct b43_wldev * dev) ret[j] = 1; } b43_radio_unlock(dev); - b43_phy_unlock(dev, phylock_flags); + b43_phy_unlock(dev); return ret[channel - 1]; } @@ -3114,7 +2894,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) if (phy->radio_ver != 0x2050) return; if (! - (dev->dev->bus->sprom.r1. + (dev->dev->bus->sprom. boardflags_lo & B43_BFL_RSSI)) return; @@ -3145,7 +2925,7 @@ void b43_calc_nrssi_threshold(struct b43_wldev *dev) } case B43_PHYTYPE_G: if (!phy->gmode || - !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) { + !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) { tmp16 = b43_nrssi_hw_read(dev, 0x20); if (tmp16 >= 0x20) tmp16 -= 0x40; @@ -3667,7 +3447,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev, } if ((phy->rev < 7) || - !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { if (phy_register == B43_PHY_RFOVER) { return 0x1B3; } else if (phy_register == B43_PHY_RFOVERVAL) { @@ -3707,7 +3487,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev, } } else { if ((phy->rev < 7) || - !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) { + !(sprom->boardflags_lo & B43_BFL_EXTLNA)) { if (phy_register == B43_PHY_RFOVER) { return 0x1B3; } else if (phy_register == B43_PHY_RFOVERVAL) { @@ -3757,10 +3537,10 @@ struct init2050_saved_values { u16 radio_52; /* PHY registers */ u16 phy_pgactl; - u16 phy_base_5A; - u16 phy_base_59; - u16 phy_base_58; - u16 phy_base_30; + u16 phy_cck_5A; + u16 phy_cck_59; + u16 phy_cck_58; + u16 phy_cck_30; u16 phy_rfover; u16 phy_rfoverval; u16 phy_analogover; @@ -3788,15 +3568,15 @@ u16 b43_radio_init2050(struct b43_wldev *dev) sav.radio_51 = b43_radio_read16(dev, 0x51); sav.radio_52 = b43_radio_read16(dev, 0x52); sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL); - sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A)); - sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59)); - sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58)); + sav.phy_cck_5A = b43_phy_read(dev, B43_PHY_CCK(0x5A)); + sav.phy_cck_59 = b43_phy_read(dev, B43_PHY_CCK(0x59)); + sav.phy_cck_58 = b43_phy_read(dev, B43_PHY_CCK(0x58)); if (phy->type == B43_PHYTYPE_B) { - sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30)); + sav.phy_cck_30 = b43_phy_read(dev, B43_PHY_CCK(0x30)); sav.reg_3EC = b43_read16(dev, 0x3EC); - b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF); + b43_phy_write(dev, B43_PHY_CCK(0x30), 0xFF); b43_write16(dev, 0x3EC, 0x3F3F); } else if (phy->gmode || phy->rev >= 2) { sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER); @@ -3847,8 +3627,8 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_write16(dev, 0x03E6, 0x0122); } else { if (phy->analog >= 2) { - b43_phy_write(dev, B43_PHY_BASE(0x03), - (b43_phy_read(dev, B43_PHY_BASE(0x03)) + b43_phy_write(dev, B43_PHY_CCK(0x03), + (b43_phy_read(dev, B43_PHY_CCK(0x03)) & 0xFFBF) | 0x40); } b43_write16(dev, B43_MMIO_CHANNEL_EXT, @@ -3865,7 +3645,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) LPD(0, 1, 1))); } b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF); - b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403); + b43_phy_write(dev, B43_PHY_CCK(0x2B), 0x1403); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, B43_PHY_RFOVERVAL, @@ -3881,12 +3661,12 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43) & 0xFFF0) | 0x0009); } - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); for (i = 0; i < 16; i++) { - b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480); - b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0480); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3912,7 +3692,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); udelay(20); tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3923,7 +3703,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) } udelay(10); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); tmp1++; tmp1 >>= 9; @@ -3932,9 +3712,9 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_radio_write16(dev, 0x78, radio78); udelay(10); for (j = 0; j < 16; j++) { - b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80); - b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D); + b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0D80); + b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3963,7 +3743,7 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0); udelay(10); tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE); - b43_phy_write(dev, B43_PHY_BASE(0x58), 0); + b43_phy_write(dev, B43_PHY_CCK(0x58), 0); if (phy->gmode || phy->rev >= 2) { b43_phy_write(dev, B43_PHY_RFOVERVAL, radio2050_rfover_val(dev, @@ -3984,16 +3764,16 @@ u16 b43_radio_init2050(struct b43_wldev *dev) b43_radio_write16(dev, 0x51, sav.radio_51); b43_radio_write16(dev, 0x52, sav.radio_52); b43_radio_write16(dev, 0x43, sav.radio_43); - b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A); - b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59); - b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58); + b43_phy_write(dev, B43_PHY_CCK(0x5A), sav.phy_cck_5A); + b43_phy_write(dev, B43_PHY_CCK(0x59), sav.phy_cck_59); + b43_phy_write(dev, B43_PHY_CCK(0x58), sav.phy_cck_58); b43_write16(dev, 0x3E6, sav.reg_3E6); if (phy->analog != 0) b43_write16(dev, 0x3F4, sav.reg_3F4); b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl); b43_synth_pu_workaround(dev, phy->channel); if (phy->type == B43_PHYTYPE_B) { - b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30); + b43_phy_write(dev, B43_PHY_CCK(0x30), sav.phy_cck_30); b43_write16(dev, 0x3EC, sav.reg_3EC); } else if (phy->gmode) { b43_write16(dev, B43_MMIO_PHY_RADIO, @@ -4103,7 +3883,8 @@ int b43_radio_selectchannel(struct b43_wldev *dev, struct b43_phy *phy = &dev->phy; u16 r8, tmp; u16 freq; - u16 channelcookie; + u16 channelcookie, savedcookie; + int err = 0; if (channel == 0xFF) { switch (phy->type) { @@ -4114,6 +3895,10 @@ int b43_radio_selectchannel(struct b43_wldev *dev, case B43_PHYTYPE_G: channel = B43_DEFAULT_CHANNEL_BG; break; + case B43_PHYTYPE_N: + //FIXME check if we are on 2.4GHz or 5GHz and set a default channel. + channel = 1; + break; default: B43_WARN_ON(1); } @@ -4123,13 +3908,18 @@ int b43_radio_selectchannel(struct b43_wldev *dev, * firmware from sending ghost packets. */ channelcookie = channel; - if (phy->type == B43_PHYTYPE_A) + if (0 /*FIXME on 5Ghz */) channelcookie |= 0x100; + //FIXME set 40Mhz flag if required + savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie); - if (phy->type == B43_PHYTYPE_A) { - if (channel > 200) - return -EINVAL; + switch (phy->type) { + case B43_PHYTYPE_A: + if (channel > 200) { + err = -EINVAL; + goto out; + } freq = channel2freq_a(channel); r8 = b43_radio_read16(dev, 0x0008); @@ -4176,9 +3966,12 @@ int b43_radio_selectchannel(struct b43_wldev *dev, b43_radio_set_tx_iq(dev); //TODO: TSSI2dbm workaround b43_phy_xmitpower(dev); //FIXME correct? - } else { - if ((channel < 1) || (channel > 14)) - return -EINVAL; + break; + case B43_PHYTYPE_G: + if ((channel < 1) || (channel > 14)) { + err = -EINVAL; + goto out; + } if (synthetic_pu_workaround) b43_synth_pu_workaround(dev, channel); @@ -4186,7 +3979,7 @@ int b43_radio_selectchannel(struct b43_wldev *dev, b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel)); if (channel == 14) { - if (dev->dev->bus->sprom.r1.country_code == + if (dev->dev->bus->sprom.country_code == SSB_SPROM1CCODE_JAPAN) b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACPR); @@ -4201,110 +3994,25 @@ int b43_radio_selectchannel(struct b43_wldev *dev, b43_read16(dev, B43_MMIO_CHANNEL_EXT) & 0xF7BF); } + break; + case B43_PHYTYPE_N: + err = b43_nphy_selectchannel(dev, channel); + if (err) + goto out; + break; + default: + B43_WARN_ON(1); } phy->channel = channel; /* Wait for the radio to tune to the channel and stabilize. */ msleep(8); - - return 0; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ -static u16 b43_get_txgain_base_band(u16 txpower) -{ - u16 ret; - - B43_WARN_ON(txpower > 63); - - if (txpower >= 54) - ret = 2; - else if (txpower >= 49) - ret = 4; - else if (txpower >= 44) - ret = 5; - else - ret = 6; - - return ret; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ -static u16 b43_get_txgain_freq_power_amp(u16 txpower) -{ - u16 ret; - - B43_WARN_ON(txpower > 63); - - if (txpower >= 32) - ret = 0; - else if (txpower >= 25) - ret = 1; - else if (txpower >= 20) - ret = 2; - else if (txpower >= 12) - ret = 3; - else - ret = 4; - - return ret; -} - -/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ -static u16 b43_get_txgain_dac(u16 txpower) -{ - u16 ret; - - B43_WARN_ON(txpower > 63); - - if (txpower >= 54) - ret = txpower - 53; - else if (txpower >= 49) - ret = txpower - 42; - else if (txpower >= 44) - ret = txpower - 37; - else if (txpower >= 32) - ret = txpower - 32; - else if (txpower >= 25) - ret = txpower - 20; - else if (txpower >= 20) - ret = txpower - 13; - else if (txpower >= 12) - ret = txpower - 8; - else - ret = txpower; - - return ret; -} - -static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower) -{ - struct b43_phy *phy = &dev->phy; - u16 pamp, base, dac, t; - - txpower = limit_value(txpower, 0, 63); - - pamp = b43_get_txgain_freq_power_amp(txpower); - pamp <<= 5; - pamp &= 0x00E0; - b43_phy_write(dev, 0x0019, pamp); - - base = b43_get_txgain_base_band(txpower); - base &= 0x000F; - b43_phy_write(dev, 0x0017, base | 0x0020); - - t = b43_ofdmtab_read16(dev, 0x3000, 1); - t &= 0x0007; - - dac = b43_get_txgain_dac(txpower); - dac <<= 3; - dac |= t; - - b43_ofdmtab_write16(dev, 0x3000, 1, dac); - - phy->txpwr_offset = txpower; - - //TODO: FuncPlaceholder (Adjust BB loft cancel) +out: + if (err) { + b43_shm_write16(dev, B43_SHM_SHARED, + B43_SHM_SH_CHAN, savedcookie); + } + return err; } void b43_radio_turn_on(struct b43_wldev *dev) @@ -4344,6 +4052,9 @@ void b43_radio_turn_on(struct b43_wldev *dev) err |= b43_radio_selectchannel(dev, channel, 0); B43_WARN_ON(err); break; + case B43_PHYTYPE_N: + b43_nphy_radio_turn_on(dev); + break; default: B43_WARN_ON(1); } @@ -4357,13 +4068,17 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force) if (!phy->radio_on && !force) return; - if (phy->type == B43_PHYTYPE_A) { + switch (phy->type) { + case B43_PHYTYPE_N: + b43_nphy_radio_turn_off(dev); + break; + case B43_PHYTYPE_A: b43_radio_write16(dev, 0x0004, 0x00FF); b43_radio_write16(dev, 0x0005, 0x00FB); b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008); b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008); - } - if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) { + break; + case B43_PHYTYPE_G: { u16 rfover, rfoverval; rfover = b43_phy_read(dev, B43_PHY_RFOVER); @@ -4375,7 +4090,10 @@ void b43_radio_turn_off(struct b43_wldev *dev, bool force) } b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C); b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73); - } else - b43_phy_write(dev, 0x0015, 0xAA00); + break; + } + default: + B43_WARN_ON(1); + } phy->radio_on = 0; } diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h index c64d74504fc0..6d165d822175 100644 --- a/drivers/net/wireless/b43/phy.h +++ b/drivers/net/wireless/b43/phy.h @@ -9,14 +9,21 @@ struct b43_phy; /*** PHY Registers ***/ /* Routing */ -#define B43_PHYROUTE_OFDM_GPHY 0x400 -#define B43_PHYROUTE_EXT_GPHY 0x800 - -/* Base registers. */ -#define B43_PHY_BASE(reg) (reg) -/* OFDM (A) registers of a G-PHY */ +#define B43_PHYROUTE 0x0C00 /* PHY register routing bits mask */ +#define B43_PHYROUTE_BASE 0x0000 /* Base registers */ +#define B43_PHYROUTE_OFDM_GPHY 0x0400 /* OFDM register routing for G-PHYs */ +#define B43_PHYROUTE_EXT_GPHY 0x0800 /* Extended G-PHY registers */ +#define B43_PHYROUTE_N_BMODE 0x0C00 /* N-PHY BMODE registers */ + +/* CCK (B-PHY) registers. */ +#define B43_PHY_CCK(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY registers. */ +#define B43_PHY_N(reg) ((reg) | B43_PHYROUTE_BASE) +/* N-PHY BMODE registers. */ +#define B43_PHY_N_BMODE(reg) ((reg) | B43_PHYROUTE_N_BMODE) +/* OFDM (A-PHY) registers. */ #define B43_PHY_OFDM(reg) ((reg) | B43_PHYROUTE_OFDM_GPHY) -/* Extended G-PHY registers */ +/* Extended G-PHY registers. */ #define B43_PHY_EXTG(reg) ((reg) | B43_PHYROUTE_EXT_GPHY) /* OFDM (A) PHY Registers */ @@ -25,10 +32,13 @@ struct b43_phy; #define B43_PHY_BBANDCFG_RXANT 0x180 /* RX Antenna selection */ #define B43_PHY_BBANDCFG_RXANT_SHIFT 7 #define B43_PHY_PWRDOWN B43_PHY_OFDM(0x03) /* Powerdown */ -#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 */ +#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0x06) /* CRS Threshold 1 (phy.rev 1 only) */ #define B43_PHY_LNAHPFCTL B43_PHY_OFDM(0x1C) /* LNA/HPF control */ +#define B43_PHY_LPFGAINCTL B43_PHY_OFDM(0x20) /* LPF Gain control */ #define B43_PHY_ADIVRELATED B43_PHY_OFDM(0x27) /* FIXME rename */ #define B43_PHY_CRS0 B43_PHY_OFDM(0x29) +#define B43_PHY_CRS0_EN 0x4000 +#define B43_PHY_PEAK_COUNT B43_PHY_OFDM(0x30) #define B43_PHY_ANTDWELL B43_PHY_OFDM(0x2B) /* Antenna dwell */ #define B43_PHY_ANTDWELL_AUTODIV1 0x0100 /* Automatic RX diversity start antenna */ #define B43_PHY_ENCORE B43_PHY_OFDM(0x49) /* "Encore" (RangeMax / BroadRange) */ @@ -37,6 +47,7 @@ struct b43_phy; #define B43_PHY_OFDM61 B43_PHY_OFDM(0x61) /* FIXME rename */ #define B43_PHY_OFDM61_10 0x0010 /* FIXME rename */ #define B43_PHY_IQBAL B43_PHY_OFDM(0x69) /* I/Q balance */ +#define B43_PHY_BBTXDC_BIAS B43_PHY_OFDM(0x6B) /* Baseband TX DC bias */ #define B43_PHY_OTABLECTL B43_PHY_OFDM(0x72) /* OFDM table control (see below) */ #define B43_PHY_OTABLEOFF 0x03FF /* OFDM table offset (see below) */ #define B43_PHY_OTABLENR 0xFC00 /* OFDM table number (see below) */ @@ -44,6 +55,9 @@ struct b43_phy; #define B43_PHY_OTABLEI B43_PHY_OFDM(0x73) /* OFDM table data I */ #define B43_PHY_OTABLEQ B43_PHY_OFDM(0x74) /* OFDM table data Q */ #define B43_PHY_HPWR_TSSICTL B43_PHY_OFDM(0x78) /* Hardware power TSSI control */ +#define B43_PHY_ADCCTL B43_PHY_OFDM(0x7A) /* ADC control */ +#define B43_PHY_IDLE_TSSI B43_PHY_OFDM(0x7B) +#define B43_PHY_A_TEMP_SENSE B43_PHY_OFDM(0x7C) /* A PHY temperature sense */ #define B43_PHY_NRSSITHRES B43_PHY_OFDM(0x8A) /* NRSSI threshold */ #define B43_PHY_ANTWRSETT B43_PHY_OFDM(0x8C) /* Antenna WR settle */ #define B43_PHY_ANTWRSETT_ARXDIV 0x2000 /* Automatic RX diversity enabled */ @@ -54,33 +68,35 @@ struct b43_phy; #define B43_PHY_N1N2GAIN B43_PHY_OFDM(0xA2) #define B43_PHY_CLIPTHRES B43_PHY_OFDM(0xA3) #define B43_PHY_CLIPN1P2THRES B43_PHY_OFDM(0xA4) +#define B43_PHY_CCKSHIFTBITS_WA B43_PHY_OFDM(0xA5) /* CCK shiftbits workaround, FIXME rename */ +#define B43_PHY_CCKSHIFTBITS B43_PHY_OFDM(0xA7) /* FIXME rename */ #define B43_PHY_DIVSRCHIDX B43_PHY_OFDM(0xA8) /* Divider search gain/index */ #define B43_PHY_CLIPP2THRES B43_PHY_OFDM(0xA9) #define B43_PHY_CLIPP3THRES B43_PHY_OFDM(0xAA) #define B43_PHY_DIVP1P2GAIN B43_PHY_OFDM(0xAB) #define B43_PHY_DIVSRCHGAINBACK B43_PHY_OFDM(0xAD) /* Divider search gain back */ #define B43_PHY_DIVSRCHGAINCHNG B43_PHY_OFDM(0xAE) /* Divider search gain change */ -#define B43_PHY_CRSTHRES1_R1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (rev 1 only) */ -#define B43_PHY_CRSTHRES2_R1 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (rev 1 only) */ +#define B43_PHY_CRSTHRES1 B43_PHY_OFDM(0xC0) /* CRS Threshold 1 (phy.rev >= 2 only) */ +#define B43_PHY_CRSTHRES2 B43_PHY_OFDM(0xC1) /* CRS Threshold 2 (phy.rev >= 2 only) */ #define B43_PHY_TSSIP_LTBASE B43_PHY_OFDM(0x380) /* TSSI power lookup table base */ #define B43_PHY_DC_LTBASE B43_PHY_OFDM(0x3A0) /* DC lookup table base */ #define B43_PHY_GAIN_LTBASE B43_PHY_OFDM(0x3C0) /* Gain lookup table base */ /* CCK (B) PHY Registers */ -#define B43_PHY_VERSION_CCK B43_PHY_BASE(0x00) /* Versioning register for B-PHY */ -#define B43_PHY_CCKBBANDCFG B43_PHY_BASE(0x01) /* Contains antenna 0/1 control bit */ -#define B43_PHY_PGACTL B43_PHY_BASE(0x15) /* PGA control */ +#define B43_PHY_VERSION_CCK B43_PHY_CCK(0x00) /* Versioning register for B-PHY */ +#define B43_PHY_CCKBBANDCFG B43_PHY_CCK(0x01) /* Contains antenna 0/1 control bit */ +#define B43_PHY_PGACTL B43_PHY_CCK(0x15) /* PGA control */ #define B43_PHY_PGACTL_LPF 0x1000 /* Low pass filter (?) */ #define B43_PHY_PGACTL_LOWBANDW 0x0040 /* Low bandwidth flag */ #define B43_PHY_PGACTL_UNKNOWN 0xEFA0 -#define B43_PHY_FBCTL1 B43_PHY_BASE(0x18) /* Frequency bandwidth control 1 */ -#define B43_PHY_ITSSI B43_PHY_BASE(0x29) /* Idle TSSI */ -#define B43_PHY_LO_LEAKAGE B43_PHY_BASE(0x2D) /* Measured LO leakage */ -#define B43_PHY_ENERGY B43_PHY_BASE(0x33) /* Energy */ -#define B43_PHY_SYNCCTL B43_PHY_BASE(0x35) -#define B43_PHY_FBCTL2 B43_PHY_BASE(0x38) /* Frequency bandwidth control 2 */ -#define B43_PHY_DACCTL B43_PHY_BASE(0x60) /* DAC control */ -#define B43_PHY_RCCALOVER B43_PHY_BASE(0x78) /* RC calibration override */ +#define B43_PHY_FBCTL1 B43_PHY_CCK(0x18) /* Frequency bandwidth control 1 */ +#define B43_PHY_ITSSI B43_PHY_CCK(0x29) /* Idle TSSI */ +#define B43_PHY_LO_LEAKAGE B43_PHY_CCK(0x2D) /* Measured LO leakage */ +#define B43_PHY_ENERGY B43_PHY_CCK(0x33) /* Energy */ +#define B43_PHY_SYNCCTL B43_PHY_CCK(0x35) +#define B43_PHY_FBCTL2 B43_PHY_CCK(0x38) /* Frequency bandwidth control 2 */ +#define B43_PHY_DACCTL B43_PHY_CCK(0x60) /* DAC control */ +#define B43_PHY_RCCALOVER B43_PHY_CCK(0x78) /* RC calibration override */ /* Extended G-PHY Registers */ #define B43_PHY_CLASSCTL B43_PHY_EXTG(0x02) /* Classify control */ @@ -125,13 +141,14 @@ struct b43_phy; #define B43_OFDMTAB_DC B43_OFDMTAB(0x0E, 7) #define B43_OFDMTAB_PWRDYN2 B43_OFDMTAB(0x0E, 12) #define B43_OFDMTAB_LNAGAIN B43_OFDMTAB(0x0E, 13) -//TODO +#define B43_OFDMTAB_UNKNOWN_0F B43_OFDMTAB(0x0F, 0) //TODO rename +#define B43_OFDMTAB_UNKNOWN_APHY B43_OFDMTAB(0x0F, 7) //TODO rename #define B43_OFDMTAB_LPFGAIN B43_OFDMTAB(0x0F, 12) #define B43_OFDMTAB_RSSI B43_OFDMTAB(0x10, 0) -//TODO +#define B43_OFDMTAB_UNKNOWN_11 B43_OFDMTAB(0x11, 4) //TODO rename #define B43_OFDMTAB_AGC1_R1 B43_OFDMTAB(0x13, 0) -#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO rename -#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 1) +#define B43_OFDMTAB_GAINX_R1 B43_OFDMTAB(0x14, 0) //TODO remove! +#define B43_OFDMTAB_MINSIGSQ B43_OFDMTAB(0x14, 0) #define B43_OFDMTAB_AGC3_R1 B43_OFDMTAB(0x15, 0) #define B43_OFDMTAB_WRSSI_R1 B43_OFDMTAB(0x15, 4) #define B43_OFDMTAB_TSSI B43_OFDMTAB(0x15, 0) @@ -163,6 +180,8 @@ enum { B43_ANTENNA1, /* Antenna 0 */ B43_ANTENNA_AUTO1, /* Automatic, starting with antenna 1 */ B43_ANTENNA_AUTO0, /* Automatic, starting with antenna 0 */ + B43_ANTENNA2, + B43_ANTENNA3 = 8, B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0, B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO, @@ -182,21 +201,21 @@ enum { #define B43_PHYVER_TYPE_SHIFT 8 #define B43_PHYVER_VERSION 0x00FF -void b43_raw_phy_lock(struct b43_wldev *dev); -#define b43_phy_lock(dev, flags) \ - do { \ - local_irq_save(flags); \ - b43_raw_phy_lock(dev); \ - } while (0) -void b43_raw_phy_unlock(struct b43_wldev *dev); -#define b43_phy_unlock(dev, flags) \ - do { \ - b43_raw_phy_unlock(dev); \ - local_irq_restore(flags); \ - } while (0) +void b43_phy_lock(struct b43_wldev *dev); +void b43_phy_unlock(struct b43_wldev *dev); + +/* Read a value from a PHY register */ u16 b43_phy_read(struct b43_wldev *dev, u16 offset); +/* Write a value to a PHY register */ void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val); +/* Mask a PHY register with a mask */ +void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask); +/* OR a PHY register with a bitmap */ +void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set); +/* Mask and OR a PHY register with a mask and bitmap */ +void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev); @@ -260,8 +279,18 @@ extern const u8 b43_radio_channel_codes_bg[]; void b43_radio_lock(struct b43_wldev *dev); void b43_radio_unlock(struct b43_wldev *dev); + +/* Read a value from a 16bit radio register */ u16 b43_radio_read16(struct b43_wldev *dev, u16 offset); +/* Write a value to a 16bit radio register */ void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val); +/* Mask a 16bit radio register with a mask */ +void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask); +/* OR a 16bit radio register with a bitmap */ +void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set); +/* Mask and OR a PHY register with a mask and bitmap */ +void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set); + u16 b43_radio_init2050(struct b43_wldev *dev); void b43_radio_init2060(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c deleted file mode 100644 index 67752a28eb9c..000000000000 --- a/drivers/net/wireless/b43/pio.c +++ /dev/null @@ -1,652 +0,0 @@ -/* - - Broadcom B43 wireless driver - - PIO Transmission - - Copyright (c) 2005 Michael Buesch <mb@bu3sch.de> - - 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; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - -#include "b43.h" -#include "pio.h" -#include "main.h" -#include "xmit.h" - -#include <linux/delay.h> - -static void tx_start(struct b43_pioqueue *queue) -{ - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT); -} - -static void tx_octet(struct b43_pioqueue *queue, u8 octet) -{ - if (queue->need_workarounds) { - b43_pio_write(queue, B43_PIO_TXDATA, octet); - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); - } else { - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO); - b43_pio_write(queue, B43_PIO_TXDATA, octet); - } -} - -static u16 tx_get_next_word(const u8 * txhdr, - const u8 * packet, - size_t txhdr_size, unsigned int *pos) -{ - const u8 *source; - unsigned int i = *pos; - u16 ret; - - if (i < txhdr_size) { - source = txhdr; - } else { - source = packet; - i -= txhdr_size; - } - ret = le16_to_cpu(*((__le16 *)(source + i))); - *pos += 2; - - return ret; -} - -static void tx_data(struct b43_pioqueue *queue, - u8 * txhdr, const u8 * packet, unsigned int octets) -{ - u16 data; - unsigned int i = 0; - - if (queue->need_workarounds) { - data = tx_get_next_word(txhdr, packet, - sizeof(struct b43_txhdr_fw4), &i); - b43_pio_write(queue, B43_PIO_TXDATA, data); - } - b43_pio_write(queue, B43_PIO_TXCTL, - B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI); - while (i < octets - 1) { - data = tx_get_next_word(txhdr, packet, - sizeof(struct b43_txhdr_fw4), &i); - b43_pio_write(queue, B43_PIO_TXDATA, data); - } - if (octets % 2) - tx_octet(queue, - packet[octets - sizeof(struct b43_txhdr_fw4) - 1]); -} - -static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb) -{ - if (queue->need_workarounds) { - b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]); - b43_pio_write(queue, B43_PIO_TXCTL, - B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE); - } else { - b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE); - } -} - -static u16 generate_cookie(struct b43_pioqueue *queue, - struct b43_pio_txpacket *packet) -{ - u16 cookie = 0x0000; - u16 packetindex; - - /* We use the upper 4 bits for the PIO - * controller ID and the lower 12 bits - * for the packet index (in the cache). - */ - switch (queue->mmio_base) { - case B43_MMIO_PIO1_BASE: - break; - case B43_MMIO_PIO2_BASE: - cookie = 0x1000; - break; - case B43_MMIO_PIO3_BASE: - cookie = 0x2000; - break; - case B43_MMIO_PIO4_BASE: - cookie = 0x3000; - break; - default: - B43_WARN_ON(1); - } - packetindex = packet->index; - B43_WARN_ON(packetindex & ~0x0FFF); - cookie |= (u16) packetindex; - - return cookie; -} - -static -struct b43_pioqueue *parse_cookie(struct b43_wldev *dev, - u16 cookie, struct b43_pio_txpacket **packet) -{ - struct b43_pio *pio = &dev->pio; - struct b43_pioqueue *queue = NULL; - int packetindex; - - switch (cookie & 0xF000) { - case 0x0000: - queue = pio->queue0; - break; - case 0x1000: - queue = pio->queue1; - break; - case 0x2000: - queue = pio->queue2; - break; - case 0x3000: - queue = pio->queue3; - break; - default: - B43_WARN_ON(1); - } - packetindex = (cookie & 0x0FFF); - B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS)); - *packet = &(queue->tx_packets_cache[packetindex]); - - return queue; -} - -union txhdr_union { - struct b43_txhdr_fw4 txhdr_fw4; -}; - -static void pio_tx_write_fragment(struct b43_pioqueue *queue, - struct sk_buff *skb, - struct b43_pio_txpacket *packet, - size_t txhdr_size) -{ - union txhdr_union txhdr_data; - u8 *txhdr = NULL; - unsigned int octets; - - txhdr = (u8 *) (&txhdr_data.txhdr_fw4); - - B43_WARN_ON(skb_shinfo(skb)->nr_frags); - b43_generate_txhdr(queue->dev, - txhdr, skb->data, skb->len, - &packet->txstat.control, - generate_cookie(queue, packet)); - - tx_start(queue); - octets = skb->len + txhdr_size; - if (queue->need_workarounds) - octets--; - tx_data(queue, txhdr, (u8 *) skb->data, octets); - tx_complete(queue, skb); -} - -static void free_txpacket(struct b43_pio_txpacket *packet) -{ - struct b43_pioqueue *queue = packet->queue; - - if (packet->skb) - dev_kfree_skb_any(packet->skb); - list_move(&packet->list, &queue->txfree); - queue->nr_txfree++; -} - -static int pio_tx_packet(struct b43_pio_txpacket *packet) -{ - struct b43_pioqueue *queue = packet->queue; - struct sk_buff *skb = packet->skb; - u16 octets; - - octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4); - if (queue->tx_devq_size < octets) { - b43warn(queue->dev->wl, "PIO queue too small. " - "Dropping packet.\n"); - /* Drop it silently (return success) */ - free_txpacket(packet); - return 0; - } - B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS); - B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size); - /* Check if there is sufficient free space on the device - * TX queue. If not, return and let the TX tasklet - * retry later. - */ - if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS) - return -EBUSY; - if (queue->tx_devq_used + octets > queue->tx_devq_size) - return -EBUSY; - /* Now poke the device. */ - pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4)); - - /* Account for the packet size. - * (We must not overflow the device TX queue) - */ - queue->tx_devq_packets++; - queue->tx_devq_used += octets; - - /* Transmission started, everything ok, move the - * packet to the txrunning list. - */ - list_move_tail(&packet->list, &queue->txrunning); - - return 0; -} - -static void tx_tasklet(unsigned long d) -{ - struct b43_pioqueue *queue = (struct b43_pioqueue *)d; - struct b43_wldev *dev = queue->dev; - unsigned long flags; - struct b43_pio_txpacket *packet, *tmp_packet; - int err; - u16 txctl; - - spin_lock_irqsave(&dev->wl->irq_lock, flags); - if (queue->tx_frozen) - goto out_unlock; - txctl = b43_pio_read(queue, B43_PIO_TXCTL); - if (txctl & B43_PIO_TXCTL_SUSPEND) - goto out_unlock; - - list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { - /* Try to transmit the packet. This can fail, if - * the device queue is full. In case of failure, the - * packet is left in the txqueue. - * If transmission succeed, the packet is moved to txrunning. - * If it is impossible to transmit the packet, it - * is dropped. - */ - err = pio_tx_packet(packet); - if (err) - break; - } - out_unlock: - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); -} - -static void setup_txqueues(struct b43_pioqueue *queue) -{ - struct b43_pio_txpacket *packet; - int i; - - queue->nr_txfree = B43_PIO_MAXTXPACKETS; - for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) { - packet = &(queue->tx_packets_cache[i]); - - packet->queue = queue; - INIT_LIST_HEAD(&packet->list); - packet->index = i; - - list_add(&packet->list, &queue->txfree); - } -} - -static -struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev, - u16 pio_mmio_base) -{ - struct b43_pioqueue *queue; - u16 qsize; - - queue = kzalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) - goto out; - - queue->dev = dev; - queue->mmio_base = pio_mmio_base; - queue->need_workarounds = (dev->dev->id.revision < 3); - - INIT_LIST_HEAD(&queue->txfree); - INIT_LIST_HEAD(&queue->txqueue); - INIT_LIST_HEAD(&queue->txrunning); - tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue); - - b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) - & ~B43_MACCTL_BE); - - qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE); - if (qsize == 0) { - b43err(dev->wl, "This card does not support PIO " - "operation mode. Please use DMA mode " - "(module parameter pio=0).\n"); - goto err_freequeue; - } - if (qsize <= B43_PIO_TXQADJUST) { - b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize); - goto err_freequeue; - } - qsize -= B43_PIO_TXQADJUST; - queue->tx_devq_size = qsize; - - setup_txqueues(queue); - - out: - return queue; - - err_freequeue: - kfree(queue); - queue = NULL; - goto out; -} - -static void cancel_transfers(struct b43_pioqueue *queue) -{ - struct b43_pio_txpacket *packet, *tmp_packet; - - tasklet_disable(&queue->txtask); - - list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) - free_txpacket(packet); - list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) - free_txpacket(packet); -} - -static void b43_destroy_pioqueue(struct b43_pioqueue *queue) -{ - if (!queue) - return; - - cancel_transfers(queue); - kfree(queue); -} - -void b43_pio_free(struct b43_wldev *dev) -{ - struct b43_pio *pio; - - if (!b43_using_pio(dev)) - return; - pio = &dev->pio; - - b43_destroy_pioqueue(pio->queue3); - pio->queue3 = NULL; - b43_destroy_pioqueue(pio->queue2); - pio->queue2 = NULL; - b43_destroy_pioqueue(pio->queue1); - pio->queue1 = NULL; - b43_destroy_pioqueue(pio->queue0); - pio->queue0 = NULL; -} - -int b43_pio_init(struct b43_wldev *dev) -{ - struct b43_pio *pio = &dev->pio; - struct b43_pioqueue *queue; - int err = -ENOMEM; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE); - if (!queue) - goto out; - pio->queue0 = queue; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE); - if (!queue) - goto err_destroy0; - pio->queue1 = queue; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE); - if (!queue) - goto err_destroy1; - pio->queue2 = queue; - - queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE); - if (!queue) - goto err_destroy2; - pio->queue3 = queue; - - if (dev->dev->id.revision < 3) - dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND; - - b43dbg(dev->wl, "PIO initialized\n"); - err = 0; - out: - return err; - - err_destroy2: - b43_destroy_pioqueue(pio->queue2); - pio->queue2 = NULL; - err_destroy1: - b43_destroy_pioqueue(pio->queue1); - pio->queue1 = NULL; - err_destroy0: - b43_destroy_pioqueue(pio->queue0); - pio->queue0 = NULL; - goto out; -} - -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - struct b43_pioqueue *queue = dev->pio.queue1; - struct b43_pio_txpacket *packet; - - B43_WARN_ON(queue->tx_suspended); - B43_WARN_ON(list_empty(&queue->txfree)); - - packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list); - packet->skb = skb; - - memset(&packet->txstat, 0, sizeof(packet->txstat)); - memcpy(&packet->txstat.control, ctl, sizeof(*ctl)); - - list_move_tail(&packet->list, &queue->txqueue); - queue->nr_txfree--; - queue->nr_tx_packets++; - B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS); - - tasklet_schedule(&queue->txtask); - - return 0; -} - -void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ - struct b43_pioqueue *queue; - struct b43_pio_txpacket *packet; - - queue = parse_cookie(dev, status->cookie, &packet); - if (B43_WARN_ON(!queue)) - return; - - queue->tx_devq_packets--; - queue->tx_devq_used -= - (packet->skb->len + sizeof(struct b43_txhdr_fw4)); - - if (status->acked) { - packet->txstat.flags |= IEEE80211_TX_STATUS_ACK; - } else { - if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK)) - packet->txstat.excessive_retries = 1; - } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - packet->txstat.retry_count = 0; - } else - packet->txstat.retry_count = status->frame_count - 1; - ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb, - &(packet->txstat)); - packet->skb = NULL; - - free_txpacket(packet); - /* If there are packets on the txqueue, poke the tasklet - * to transmit them. - */ - if (!list_empty(&queue->txqueue)) - tasklet_schedule(&queue->txtask); -} - -void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ - struct b43_pio *pio = &dev->pio; - struct b43_pioqueue *queue; - struct ieee80211_tx_queue_stats_data *data; - - queue = pio->queue1; - data = &(stats->data[0]); - data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree; - data->limit = B43_PIO_MAXTXPACKETS; - data->count = queue->nr_tx_packets; -} - -static void pio_rx_error(struct b43_pioqueue *queue, - int clear_buffers, const char *error) -{ - int i; - - b43err(queue->dev->wl, "PIO RX error: %s\n", error); - b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY); - if (clear_buffers) { - B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE); - for (i = 0; i < 15; i++) { - /* Dummy read. */ - b43_pio_read(queue, B43_PIO_RXDATA); - } - } -} - -void b43_pio_rx(struct b43_pioqueue *queue) -{ - __le16 preamble[21] = { 0 }; - struct b43_rxhdr_fw4 *rxhdr; - u16 tmp, len; - u32 macstat; - int i, preamble_readwords; - struct sk_buff *skb; - - tmp = b43_pio_read(queue, B43_PIO_RXCTL); - if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE)) - return; - b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE); - - for (i = 0; i < 10; i++) { - tmp = b43_pio_read(queue, B43_PIO_RXCTL); - if (tmp & B43_PIO_RXCTL_READY) - goto data_ready; - udelay(10); - } - b43dbg(queue->dev->wl, "PIO RX timed out\n"); - return; -data_ready: - - len = b43_pio_read(queue, B43_PIO_RXDATA); - if (unlikely(len > 0x700)) { - pio_rx_error(queue, 0, "len > 0x700"); - return; - } - if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) { - pio_rx_error(queue, 0, "len == 0"); - return; - } - preamble[0] = cpu_to_le16(len); - if (queue->mmio_base == B43_MMIO_PIO4_BASE) - preamble_readwords = 14 / sizeof(u16); - else - preamble_readwords = 18 / sizeof(u16); - for (i = 0; i < preamble_readwords; i++) { - tmp = b43_pio_read(queue, B43_PIO_RXDATA); - preamble[i + 1] = cpu_to_le16(tmp); - } - rxhdr = (struct b43_rxhdr_fw4 *)preamble; - macstat = le32_to_cpu(rxhdr->mac_status); - if (macstat & B43_RX_MAC_FCSERR) { - pio_rx_error(queue, - (queue->mmio_base == B43_MMIO_PIO1_BASE), - "Frame FCS error"); - return; - } - if (queue->mmio_base == B43_MMIO_PIO4_BASE) { - /* We received an xmit status. */ - struct b43_hwtxstatus *hw; - - hw = (struct b43_hwtxstatus *)(preamble + 1); - b43_handle_hwtxstatus(queue->dev, hw); - - return; - } - - skb = dev_alloc_skb(len); - if (unlikely(!skb)) { - pio_rx_error(queue, 1, "OOM"); - return; - } - skb_put(skb, len); - for (i = 0; i < len - 1; i += 2) { - tmp = b43_pio_read(queue, B43_PIO_RXDATA); - *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); - } - if (len % 2) { - tmp = b43_pio_read(queue, B43_PIO_RXDATA); - skb->data[len - 1] = (tmp & 0x00FF); -/* The specs say the following is required, but - * it is wrong and corrupts the PLCP. If we don't do - * this, the PLCP seems to be correct. So ifdef it out for now. - */ -#if 0 - if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME) - skb->data[2] = (tmp & 0xFF00) >> 8; - else - skb->data[0] = (tmp & 0xFF00) >> 8; -#endif - } - b43_rx(queue->dev, skb, rxhdr); -} - -void b43_pio_tx_suspend(struct b43_pioqueue *queue) -{ - b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE); - b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) - | B43_PIO_TXCTL_SUSPEND); -} - -void b43_pio_tx_resume(struct b43_pioqueue *queue) -{ - b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL) - & ~B43_PIO_TXCTL_SUSPEND); - b43_power_saving_ctl_bits(queue->dev, 0); - tasklet_schedule(&queue->txtask); -} - -void b43_pio_freeze_txqueues(struct b43_wldev *dev) -{ - struct b43_pio *pio; - - B43_WARN_ON(!b43_using_pio(dev)); - pio = &dev->pio; - pio->queue0->tx_frozen = 1; - pio->queue1->tx_frozen = 1; - pio->queue2->tx_frozen = 1; - pio->queue3->tx_frozen = 1; -} - -void b43_pio_thaw_txqueues(struct b43_wldev *dev) -{ - struct b43_pio *pio; - - B43_WARN_ON(!b43_using_pio(dev)); - pio = &dev->pio; - pio->queue0->tx_frozen = 0; - pio->queue1->tx_frozen = 0; - pio->queue2->tx_frozen = 0; - pio->queue3->tx_frozen = 0; - if (!list_empty(&pio->queue0->txqueue)) - tasklet_schedule(&pio->queue0->txtask); - if (!list_empty(&pio->queue1->txqueue)) - tasklet_schedule(&pio->queue1->txtask); - if (!list_empty(&pio->queue2->txqueue)) - tasklet_schedule(&pio->queue2->txtask); - if (!list_empty(&pio->queue3->txqueue)) - tasklet_schedule(&pio->queue3->txtask); -} diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h deleted file mode 100644 index 3488f2447bbf..000000000000 --- a/drivers/net/wireless/b43/pio.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef B43_PIO_H_ -#define B43_PIO_H_ - -#include "b43.h" - -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/list.h> -#include <linux/skbuff.h> - -#define B43_PIO_TXCTL 0x00 -#define B43_PIO_TXDATA 0x02 -#define B43_PIO_TXQBUFSIZE 0x04 -#define B43_PIO_RXCTL 0x08 -#define B43_PIO_RXDATA 0x0A - -#define B43_PIO_TXCTL_WRITELO (1 << 0) -#define B43_PIO_TXCTL_WRITEHI (1 << 1) -#define B43_PIO_TXCTL_COMPLETE (1 << 2) -#define B43_PIO_TXCTL_INIT (1 << 3) -#define B43_PIO_TXCTL_SUSPEND (1 << 7) - -#define B43_PIO_RXCTL_DATAAVAILABLE (1 << 0) -#define B43_PIO_RXCTL_READY (1 << 1) - -/* PIO constants */ -#define B43_PIO_MAXTXDEVQPACKETS 31 -#define B43_PIO_TXQADJUST 80 - -/* PIO tuning knobs */ -#define B43_PIO_MAXTXPACKETS 256 - -#ifdef CONFIG_B43_PIO - -struct b43_pioqueue; -struct b43_xmitstatus; - -struct b43_pio_txpacket { - struct b43_pioqueue *queue; - struct sk_buff *skb; - struct ieee80211_tx_status txstat; - struct list_head list; - u16 index; /* Index in the tx_packets_cache */ -}; - -struct b43_pioqueue { - struct b43_wldev *dev; - u16 mmio_base; - - bool tx_suspended; - bool tx_frozen; - bool need_workarounds; /* Workarounds needed for core.rev < 3 */ - - /* Adjusted size of the device internal TX buffer. */ - u16 tx_devq_size; - /* Used octets of the device internal TX buffer. */ - u16 tx_devq_used; - /* Used packet slots in the device internal TX buffer. */ - u8 tx_devq_packets; - /* Packets from the txfree list can - * be taken on incoming TX requests. - */ - struct list_head txfree; - unsigned int nr_txfree; - /* Packets on the txqueue are queued, - * but not completely written to the chip, yet. - */ - struct list_head txqueue; - /* Packets on the txrunning queue are completely - * posted to the device. We are waiting for the txstatus. - */ - struct list_head txrunning; - /* Total number or packets sent. - * (This counter can obviously wrap). - */ - unsigned int nr_tx_packets; - struct tasklet_struct txtask; - struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS]; -}; - -static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset) -{ - return b43_read16(queue->dev, queue->mmio_base + offset); -} - -static inline - void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value) -{ - b43_write16(queue->dev, queue->mmio_base + offset, value); - mmiowb(); -} - -int b43_pio_init(struct b43_wldev *dev); -void b43_pio_free(struct b43_wldev *dev); - -int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl); -void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status); -void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats); -void b43_pio_rx(struct b43_pioqueue *queue); - -/* Suspend TX queue in hardware. */ -void b43_pio_tx_suspend(struct b43_pioqueue *queue); -void b43_pio_tx_resume(struct b43_pioqueue *queue); -/* Suspend (freeze) the TX tasklet (software level). */ -void b43_pio_freeze_txqueues(struct b43_wldev *dev); -void b43_pio_thaw_txqueues(struct b43_wldev *dev); - -#else /* CONFIG_B43_PIO */ - -static inline int b43_pio_init(struct b43_wldev *dev) -{ - return 0; -} -static inline void b43_pio_free(struct b43_wldev *dev) -{ -} -static inline - int b43_pio_tx(struct b43_wldev *dev, - struct sk_buff *skb, struct ieee80211_tx_control *ctl) -{ - return 0; -} -static inline - void b43_pio_handle_txstatus(struct b43_wldev *dev, - const struct b43_txstatus *status) -{ -} -static inline - void b43_pio_get_tx_stats(struct b43_wldev *dev, - struct ieee80211_tx_queue_stats *stats) -{ -} -static inline void b43_pio_rx(struct b43_pioqueue *queue) -{ -} -static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue) -{ -} -static inline void b43_pio_tx_resume(struct b43_pioqueue *queue) -{ -} -static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev) -{ -} -static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev) -{ -} - -#endif /* CONFIG_B43_PIO */ -#endif /* B43_PIO_H_ */ diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c index 15a87183a572..3f5ea06bf13c 100644 --- a/drivers/net/wireless/b43/tables.c +++ b/drivers/net/wireless/b43/tables.c @@ -3,7 +3,7 @@ Broadcom B43 wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -229,7 +229,7 @@ const u16 b43_tab_noisea2[] = { }; const u16 b43_tab_noisea3[] = { - 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x5E5E, 0x5E5E, 0x5E5E, 0x3F48, 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, }; @@ -243,6 +243,26 @@ const u16 b43_tab_noiseg2[] = { 0x0000, 0x0000, 0x0000, 0x0000, }; +const u16 b43_tab_noisescalea2[] = { + 0x6767, 0x6767, 0x6767, 0x6767, /* 0 */ + 0x6767, 0x6767, 0x6767, 0x6767, + 0x6767, 0x6767, 0x6767, 0x6767, + 0x6767, 0x6700, 0x6767, 0x6767, + 0x6767, 0x6767, 0x6767, 0x6767, /* 16 */ + 0x6767, 0x6767, 0x6767, 0x6767, + 0x6767, 0x6767, 0x0067, +}; + +const u16 b43_tab_noisescalea3[] = { + 0x2323, 0x2323, 0x2323, 0x2323, /* 0 */ + 0x2323, 0x2323, 0x2323, 0x2323, + 0x2323, 0x2323, 0x2323, 0x2323, + 0x2323, 0x2300, 0x2323, 0x2323, + 0x2323, 0x2323, 0x2323, 0x2323, /* 16 */ + 0x2323, 0x2323, 0x2323, 0x2323, + 0x2323, 0x2323, 0x0023, +}; + const u16 b43_tab_noisescaleg1[] = { 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ 0x2F2D, 0x2A2A, 0x2527, 0x1F21, @@ -254,7 +274,7 @@ const u16 b43_tab_noisescaleg1[] = { }; const u16 b43_tab_noisescaleg2[] = { - 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xD8DD, 0xCBD4, 0xBCC0, 0xB6B7, /* 0 */ 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, 0x969B, 0x9195, 0x8F8F, 0x8A8A, 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, @@ -307,6 +327,28 @@ const u16 b43_tab_sigmasqr2[] = { 0x00DE, }; +const u16 b43_tab_rssiagc1[] = { + 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, /* 0 */ + 0xFFF8, 0xFFF9, 0xFFFC, 0xFFFE, + 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, + 0xFFF8, 0xFFF8, 0xFFF8, 0xFFF8, +}; + +const u16 b43_tab_rssiagc2[] = { + 0x0820, 0x0820, 0x0920, 0x0C38, /* 0 */ + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, /* 16 */ + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, /* 32 */ + 0x0820, 0x0820, 0x0820, 0x0820, + 0x0820, 0x0820, 0x0920, 0x0A38, + 0x0820, 0x0820, 0x0820, 0x0820, +}; + static inline void assert_sizes(void) { BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor)); @@ -317,36 +359,73 @@ static inline void assert_sizes(void) BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3)); BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1)); BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2)); - BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != + ARRAY_SIZE(b43_tab_noisescalea2)); + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != + ARRAY_SIZE(b43_tab_noisescalea3)); + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != ARRAY_SIZE(b43_tab_noisescaleg1)); - BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != ARRAY_SIZE(b43_tab_noisescaleg2)); - BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE != + BUILD_BUG_ON(B43_TAB_NOISESCALE_SIZE != ARRAY_SIZE(b43_tab_noisescaleg3)); BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1)); BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2)); + BUILD_BUG_ON(B43_TAB_RSSIAGC1_SIZE != ARRAY_SIZE(b43_tab_rssiagc1)); + BUILD_BUG_ON(B43_TAB_RSSIAGC2_SIZE != ARRAY_SIZE(b43_tab_rssiagc2)); } u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset) { - assert_sizes(); + struct b43_phy *phy = &dev->phy; + u16 addr; + + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + } + phy->ofdmtab_addr = addr; - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); return b43_phy_read(dev, B43_PHY_OTABLEI); + + /* Some compiletime assertions... */ + assert_sizes(); } void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table, u16 offset, u16 value) { - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + struct b43_phy *phy = &dev->phy; + u16 addr; + + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + } + phy->ofdmtab_addr = addr; b43_phy_write(dev, B43_PHY_OTABLEI, value); } u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) { + struct b43_phy *phy = &dev->phy; u32 ret; + u16 addr; - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_READ) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_READ; + } + phy->ofdmtab_addr = addr; ret = b43_phy_read(dev, B43_PHY_OTABLEQ); ret <<= 16; ret |= b43_phy_read(dev, B43_PHY_OTABLEI); @@ -357,7 +436,18 @@ u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset) void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table, u16 offset, u32 value) { - b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset); + struct b43_phy *phy = &dev->phy; + u16 addr; + + addr = table + offset; + if ((phy->ofdmtab_addr_direction != B43_OFDMTAB_DIRECTION_WRITE) || + (addr - 1 != phy->ofdmtab_addr)) { + /* The hardware has a different address in memory. Update it. */ + b43_phy_write(dev, B43_PHY_OTABLECTL, addr); + phy->ofdmtab_addr_direction = B43_OFDMTAB_DIRECTION_WRITE; + } + phy->ofdmtab_addr = addr; + b43_phy_write(dev, B43_PHY_OTABLEI, value); b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16)); } diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h index 64635d7b518c..80e73c7cbac5 100644 --- a/drivers/net/wireless/b43/tables.h +++ b/drivers/net/wireless/b43/tables.h @@ -1,9 +1,9 @@ #ifndef B43_TABLES_H_ #define B43_TABLES_H_ -#define B43_TAB_ROTOR_SIZE 53 +#define B43_TAB_ROTOR_SIZE 53 extern const u32 b43_tab_rotor[]; -#define B43_TAB_RETARD_SIZE 53 +#define B43_TAB_RETARD_SIZE 53 extern const u32 b43_tab_retard[]; #define B43_TAB_FINEFREQA_SIZE 256 extern const u16 b43_tab_finefreqa[]; @@ -17,12 +17,18 @@ extern const u16 b43_tab_noisea3[]; extern const u16 b43_tab_noiseg1[]; #define B43_TAB_NOISEG2_SIZE 8 extern const u16 b43_tab_noiseg2[]; -#define B43_TAB_NOISESCALEG_SIZE 27 +#define B43_TAB_NOISESCALE_SIZE 27 +extern const u16 b43_tab_noisescalea2[]; +extern const u16 b43_tab_noisescalea3[]; extern const u16 b43_tab_noisescaleg1[]; extern const u16 b43_tab_noisescaleg2[]; extern const u16 b43_tab_noisescaleg3[]; #define B43_TAB_SIGMASQR_SIZE 53 extern const u16 b43_tab_sigmasqr1[]; extern const u16 b43_tab_sigmasqr2[]; +#define B43_TAB_RSSIAGC1_SIZE 16 +extern const u16 b43_tab_rssiagc1[]; +#define B43_TAB_RSSIAGC2_SIZE 48 +extern const u16 b43_tab_rssiagc2[]; #endif /* B43_TABLES_H_ */ diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c new file mode 100644 index 000000000000..2aa57551786a --- /dev/null +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -0,0 +1,2476 @@ +/* + + Broadcom B43 wireless driver + IEEE 802.11n PHY and radio device data tables + + Copyright (c) 2008 Michael Buesch <mb@bu3sch.de> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "tables_nphy.h" +#include "phy.h" +#include "nphy.h" + + +struct b2055_inittab_entry { + /* Value to write if we use the 5GHz band. */ + u16 ghz5; + /* Value to write if we use the 2.4GHz band. */ + u16 ghz2; + /* Flags */ + u8 flags; +#define B2055_INITTAB_ENTRY_OK 0x01 +#define B2055_INITTAB_UPLOAD 0x02 +}; +#define UPLOAD .flags = B2055_INITTAB_ENTRY_OK | B2055_INITTAB_UPLOAD +#define NOUPLOAD .flags = B2055_INITTAB_ENTRY_OK + +static const struct b2055_inittab_entry b2055_inittab [] = { + [B2055_SP_PINPD] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_C1_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, + [B2055_C2_SP_RSSI] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_SP_PDMISC] = { .ghz5 = 0x0027, .ghz2 = 0x0027, NOUPLOAD, }, + [B2055_C1_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, + [B2055_C1_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2055_C2_SP_RXGC1] = { .ghz5 = 0x007F, .ghz2 = 0x007F, UPLOAD, }, + [B2055_C2_SP_RXGC2] = { .ghz5 = 0x0007, .ghz2 = 0x0007, UPLOAD, }, + [B2055_C1_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C2_SP_LPFBWSEL] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C1_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, + [B2055_C1_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, + [B2055_C2_SP_TXGC1] = { .ghz5 = 0x004F, .ghz2 = 0x004F, UPLOAD, }, + [B2055_C2_SP_TXGC2] = { .ghz5 = 0x0005, .ghz2 = 0x0005, UPLOAD, }, + [B2055_MASTER1] = { .ghz5 = 0x00D0, .ghz2 = 0x00D0, NOUPLOAD, }, + [B2055_MASTER2] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_PD_LGEN] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PD_PLLTS] = { .ghz5 = 0x0040, .ghz2 = 0x0040, NOUPLOAD, }, + [B2055_C1_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_LGBUF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_TX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_RXTX] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_PD_RSSIMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PWRDET_LGEN] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_C1_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_C1_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_C2_PWRDET_LGBUF] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_C2_PWRDET_RXTX] = { .ghz5 = 0x00C0, .ghz2 = 0x00C0, NOUPLOAD, }, + [B2055_RRCCAL_CS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_RRCCAL_NOPTSEL] = { .ghz5 = 0x002C, .ghz2 = 0x002C, NOUPLOAD, }, + [B2055_CAL_MISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_COUT] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_COUT2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_CVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RVARCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_LPOCTL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_TS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RCCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_CAL_RCALRTS] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PADDRV] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_XOCTL1] = { .ghz5 = 0x0038, .ghz2 = 0x0038, NOUPLOAD, }, + [B2055_XOCTL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_XOREGUL] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2055_XOMISC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PLL_LFC1] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_PLL_CALVTH] = { .ghz5 = 0x0087, .ghz2 = 0x0087, NOUPLOAD, }, + [B2055_PLL_LFC2] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, + [B2055_PLL_REF] = { .ghz5 = 0x0070, .ghz2 = 0x0070, NOUPLOAD, }, + [B2055_PLL_LFR1] = { .ghz5 = 0x0011, .ghz2 = 0x0011, NOUPLOAD, }, + [B2055_PLL_PFDCP] = { .ghz5 = 0x0018, .ghz2 = 0x0018, UPLOAD, }, + [B2055_PLL_IDAC_CPOPAMP] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_PLL_CPREG] = { .ghz5 = 0x0004, .ghz2 = 0x0004, UPLOAD, }, + [B2055_PLL_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_RF_PLLMOD0] = { .ghz5 = 0x009E, .ghz2 = 0x009E, NOUPLOAD, }, + [B2055_RF_PLLMOD1] = { .ghz5 = 0x0009, .ghz2 = 0x0009, NOUPLOAD, }, + [B2055_RF_MMDIDAC1] = { .ghz5 = 0x00C8, .ghz2 = 0x00C8, UPLOAD, }, + [B2055_RF_MMDIDAC0] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_RF_MMDSP] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL3] = { .ghz5 = 0x0001, .ghz2 = 0x0001, NOUPLOAD, }, + [B2055_VCO_CAL4] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_VCO_CAL5] = { .ghz5 = 0x0096, .ghz2 = 0x0096, NOUPLOAD, }, + [B2055_VCO_CAL6] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, + [B2055_VCO_CAL7] = { .ghz5 = 0x003E, .ghz2 = 0x003E, NOUPLOAD, }, + [B2055_VCO_CAL8] = { .ghz5 = 0x0013, .ghz2 = 0x0013, NOUPLOAD, }, + [B2055_VCO_CAL9] = { .ghz5 = 0x0002, .ghz2 = 0x0002, NOUPLOAD, }, + [B2055_VCO_CAL10] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_VCO_CAL11] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_VCO_CAL12] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL13] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL14] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL15] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_CAL16] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_VCO_KVCO] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_VCO_CAPTAIL] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_VCO_IDACVCO] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_VCO_REG] = { .ghz5 = 0x0084, .ghz2 = 0x0084, UPLOAD, }, + [B2055_PLL_RFVTH] = { .ghz5 = 0x00C3, .ghz2 = 0x00C3, NOUPLOAD, }, + [B2055_LGBUF_CENBUF] = { .ghz5 = 0x008F, .ghz2 = 0x008F, NOUPLOAD, }, + [B2055_LGEN_TUNE1] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_LGEN_TUNE2] = { .ghz5 = 0x00FF, .ghz2 = 0x00FF, NOUPLOAD, }, + [B2055_LGEN_IDAC1] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_LGEN_IDAC2] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_LGEN_BIASC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_LGEN_BIASIDAC] = { .ghz5 = 0x00CC, .ghz2 = 0x00CC, NOUPLOAD, }, + [B2055_LGEN_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_LGEN_DIV] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_LGEN_SPARE2] = { .ghz5 = 0x0080, .ghz2 = 0x0080, NOUPLOAD, }, + [B2055_C1_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, + [B2055_C1_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, + [B2055_C1_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, + [B2055_C1_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, + [B2055_C1_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C1_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, + [B2055_C1_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, + [B2055_C1_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C1_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C1_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, + [B2055_C1_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, + [B2055_C1_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C1_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C1_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C1_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C1_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, + [B2055_C1_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, + [B2055_C1_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C1_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, + [B2055_C1_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, + [B2055_C1_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C1_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C1_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C1_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C1_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C1_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C1_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_C1_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, + [B2055_C1_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, + [B2055_C1_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LGBUF_ATUNE] = { .ghz5 = 0x00F8, .ghz2 = 0x00F8, NOUPLOAD, }, + [B2055_C2_LGBUF_GTUNE] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_DIV] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_AIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0008, UPLOAD, }, + [B2055_C2_LGBUF_GIDAC] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_LGBUF_IDACFO] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LGBUF_SPARE] = { .ghz5 = 0x0001, .ghz2 = 0x0001, UPLOAD, }, + [B2055_C2_RX_RFSPC1] = { .ghz5 = 0x008A, .ghz2 = 0x008A, NOUPLOAD, }, + [B2055_C2_RX_RFR1] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C2_RX_RFR2] = { .ghz5 = 0x0083, .ghz2 = 0x0083, NOUPLOAD, }, + [B2055_C2_RX_RFRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_RX_BB_BLCMP] = { .ghz5 = 0x00A0, .ghz2 = 0x00A0, NOUPLOAD, }, + [B2055_C2_RX_BB_LPF] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C2_RX_BB_MIDACHP] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C2_RX_BB_VGA1IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_VGA2IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_VGA3IDAC] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_BUFOCTL] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_RX_BB_RCCALCTL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_RX_BB_RSSICTL1] = { .ghz5 = 0x006A, .ghz2 = 0x006A, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL2] = { .ghz5 = 0x00AB, .ghz2 = 0x00AB, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL3] = { .ghz5 = 0x0013, .ghz2 = 0x0013, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL4] = { .ghz5 = 0x00C1, .ghz2 = 0x00C1, UPLOAD, }, + [B2055_C2_RX_BB_RSSICTL5] = { .ghz5 = 0x00AA, .ghz2 = 0x00AA, UPLOAD, }, + [B2055_C2_RX_BB_REG] = { .ghz5 = 0x0087, .ghz2 = 0x0087, UPLOAD, }, + [B2055_C2_RX_BB_SPARE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_RX_TXBBRCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_TX_RF_SPGA] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C2_TX_RF_SPAD] = { .ghz5 = 0x0007, .ghz2 = 0x0007, NOUPLOAD, }, + [B2055_C2_TX_RF_CNTPGA1] = { .ghz5 = 0x0015, .ghz2 = 0x0015, NOUPLOAD, }, + [B2055_C2_TX_RF_CNTPAD1] = { .ghz5 = 0x0055, .ghz2 = 0x0055, NOUPLOAD, }, + [B2055_C2_TX_RF_PGAIDAC] = { .ghz5 = 0x0097, .ghz2 = 0x0097, UPLOAD, }, + [B2055_C2_TX_PGAPADTN] = { .ghz5 = 0x0008, .ghz2 = 0x0008, NOUPLOAD, }, + [B2055_C2_TX_PADIDAC1] = { .ghz5 = 0x0014, .ghz2 = 0x0014, UPLOAD, }, + [B2055_C2_TX_PADIDAC2] = { .ghz5 = 0x0033, .ghz2 = 0x0033, NOUPLOAD, }, + [B2055_C2_TX_MXBGTRIM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [B2055_C2_TX_RF_RCAL] = { .ghz5 = 0x0006, .ghz2 = 0x0006, NOUPLOAD, }, + [B2055_C2_TX_RF_PADTSSI1] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C2_TX_RF_PADTSSI2] = { .ghz5 = 0x000A, .ghz2 = 0x000A, NOUPLOAD, }, + [B2055_C2_TX_RF_SPARE] = { .ghz5 = 0x0003, .ghz2 = 0x0003, UPLOAD, }, + [B2055_C2_TX_RF_IQCAL1] = { .ghz5 = 0x002A, .ghz2 = 0x002A, NOUPLOAD, }, + [B2055_C2_TX_RF_IQCAL2] = { .ghz5 = 0x00A4, .ghz2 = 0x00A4, NOUPLOAD, }, + [B2055_C2_TXBB_RCCAL] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_TXBB_LPF1] = { .ghz5 = 0x0028, .ghz2 = 0x0028, NOUPLOAD, }, + [B2055_C2_TX_VOSCNCL] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_TX_LPF_MXGMIDAC] = { .ghz5 = 0x004A, .ghz2 = 0x004A, NOUPLOAD, }, + [B2055_C2_TX_BB_MXGM] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_PRG_GCHP21] = { .ghz5 = 0x0071, .ghz2 = 0x0071, NOUPLOAD, }, + [B2055_PRG_GCHP22] = { .ghz5 = 0x0072, .ghz2 = 0x0072, NOUPLOAD, }, + [B2055_PRG_GCHP23] = { .ghz5 = 0x0073, .ghz2 = 0x0073, NOUPLOAD, }, + [B2055_PRG_GCHP24] = { .ghz5 = 0x0074, .ghz2 = 0x0074, NOUPLOAD, }, + [B2055_PRG_GCHP25] = { .ghz5 = 0x0075, .ghz2 = 0x0075, NOUPLOAD, }, + [B2055_PRG_GCHP26] = { .ghz5 = 0x0076, .ghz2 = 0x0076, NOUPLOAD, }, + [B2055_PRG_GCHP27] = { .ghz5 = 0x0077, .ghz2 = 0x0077, NOUPLOAD, }, + [B2055_PRG_GCHP28] = { .ghz5 = 0x0078, .ghz2 = 0x0078, NOUPLOAD, }, + [B2055_PRG_GCHP29] = { .ghz5 = 0x0079, .ghz2 = 0x0079, NOUPLOAD, }, + [B2055_PRG_GCHP30] = { .ghz5 = 0x007A, .ghz2 = 0x007A, NOUPLOAD, }, + [0xC7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xC8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xC9] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCE] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xCF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD1] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C1_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [0xD3] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD4] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD5] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C1_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD7] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xD8] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_LNA_GAINBST] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDA] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDB] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDC] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xDD] = { .ghz5 = 0x0018, .ghz2 = 0x0018, NOUPLOAD, }, + [B2055_C2_B0NB_RSSIVCM] = { .ghz5 = 0x0088, .ghz2 = 0x0088, NOUPLOAD, }, + [0xDF] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xE0] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [0xE1] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, + [B2055_C2_GENSPARE2] = { .ghz5 = 0x0000, .ghz2 = 0x0000, NOUPLOAD, }, +}; + + +void b2055_upload_inittab(struct b43_wldev *dev, + bool ghz5, bool ignore_uploadflag) +{ + const struct b2055_inittab_entry *e; + unsigned int i; + u16 value; + + for (i = 0; i < ARRAY_SIZE(b2055_inittab); i++) { + e = &(b2055_inittab[i]); + if (!(e->flags & B2055_INITTAB_ENTRY_OK)) + continue; + if ((e->flags & B2055_INITTAB_UPLOAD) || ignore_uploadflag) { + if (ghz5) + value = e->ghz5; + else + value = e->ghz2; + b43_radio_write16(dev, i, value); + } + } +} + + +#define RADIOREGS(r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, \ + r12, r13, r14, r15, r16, r17, r18, r19, r20, r21) \ + .radio_pll_ref = r0, \ + .radio_rf_pllmod0 = r1, \ + .radio_rf_pllmod1 = r2, \ + .radio_vco_captail = r3, \ + .radio_vco_cal1 = r4, \ + .radio_vco_cal2 = r5, \ + .radio_pll_lfc1 = r6, \ + .radio_pll_lfr1 = r7, \ + .radio_pll_lfc2 = r8, \ + .radio_lgbuf_cenbuf = r9, \ + .radio_lgen_tune1 = r10, \ + .radio_lgen_tune2 = r11, \ + .radio_c1_lgbuf_atune = r12, \ + .radio_c1_lgbuf_gtune = r13, \ + .radio_c1_rx_rfr1 = r14, \ + .radio_c1_tx_pgapadtn = r15, \ + .radio_c1_tx_mxbgtrim = r16, \ + .radio_c2_lgbuf_atune = r17, \ + .radio_c2_lgbuf_gtune = r18, \ + .radio_c2_rx_rfr1 = r19, \ + .radio_c2_tx_pgapadtn = r20, \ + .radio_c2_tx_mxbgtrim = r21 + +#define PHYREGS(r0, r1, r2, r3, r4, r5) \ + .phy_bw1a = r0, \ + .phy_bw2 = r1, \ + .phy_bw3 = r2, \ + .phy_bw4 = r3, \ + .phy_bw5 = r4, \ + .phy_bw6 = r5 + +static const struct b43_nphy_channeltab_entry b43_nphy_channeltab[] = { + { .channel = 184, + .freq = 4920, /* MHz */ + .unk2 = 3280, + RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xB407, 0xB007, 0xAC07, 0x1402, 0x1502, 0x1602), + }, + { .channel = 186, + .freq = 4930, /* MHz */ + .unk2 = 3287, + RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xB807, 0xB407, 0xB007, 0x1302, 0x1402, 0x1502), + }, + { .channel = 188, + .freq = 4940, /* MHz */ + .unk2 = 3293, + RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xBC07, 0xB807, 0xB407, 0x1202, 0x1302, 0x1402), + }, + { .channel = 190, + .freq = 4950, /* MHz */ + .unk2 = 3300, + RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC007, 0xBC07, 0xB807, 0x1102, 0x1202, 0x1302), + }, + { .channel = 192, + .freq = 4960, /* MHz */ + .unk2 = 3307, + RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC407, 0xC007, 0xBC07, 0x0F02, 0x1102, 0x1202), + }, + { .channel = 194, + .freq = 4970, /* MHz */ + .unk2 = 3313, + RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xC807, 0xC407, 0xC007, 0x0E02, 0x0F02, 0x1102), + }, + { .channel = 196, + .freq = 4980, /* MHz */ + .unk2 = 3320, + RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xCC07, 0xC807, 0xC407, 0x0D02, 0x0E02, 0x0F02), + }, + { .channel = 198, + .freq = 4990, /* MHz */ + .unk2 = 3327, + RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD007, 0xCC07, 0xC807, 0x0C02, 0x0D02, 0x0E02), + }, + { .channel = 200, + .freq = 5000, /* MHz */ + .unk2 = 3333, + RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD407, 0xD007, 0xCC07, 0x0B02, 0x0C02, 0x0D02), + }, + { .channel = 202, + .freq = 5010, /* MHz */ + .unk2 = 3340, + RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xD807, 0xD407, 0xD007, 0x0A02, 0x0B02, 0x0C02), + }, + { .channel = 204, + .freq = 5020, /* MHz */ + .unk2 = 3347, + RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xDC07, 0xD807, 0xD407, 0x0902, 0x0A02, 0x0B02), + }, + { .channel = 206, + .freq = 5030, /* MHz */ + .unk2 = 3353, + RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE007, 0xDC07, 0xD807, 0x0802, 0x0902, 0x0A02), + }, + { .channel = 208, + .freq = 5040, /* MHz */ + .unk2 = 3360, + RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE407, 0xE007, 0xDC07, 0x0702, 0x0802, 0x0902), + }, + { .channel = 210, + .freq = 5050, /* MHz */ + .unk2 = 3367, + RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, + 0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F), + PHYREGS(0xE807, 0xE407, 0xE007, 0x0602, 0x0702, 0x0802), + }, + { .channel = 212, + .freq = 5060, /* MHz */ + .unk2 = 3373, + RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, + 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), + PHYREGS(0xEC07, 0xE807, 0xE407, 0x0502, 0x0602, 0x0702), + }, + { .channel = 214, + .freq = 5070, /* MHz */ + .unk2 = 3380, + RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, + 0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E), + PHYREGS(0xF007, 0xEC07, 0xE807, 0x0402, 0x0502, 0x0602), + }, + { .channel = 216, + .freq = 5080, /* MHz */ + .unk2 = 3387, + RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, + 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), + PHYREGS(0xF407, 0xF007, 0xEC07, 0x0302, 0x0402, 0x0502), + }, + { .channel = 218, + .freq = 5090, /* MHz */ + .unk2 = 3393, + RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, + 0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D), + PHYREGS(0xF807, 0xF407, 0xF007, 0x0202, 0x0302, 0x0402), + }, + { .channel = 220, + .freq = 5100, /* MHz */ + .unk2 = 3400, + RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, + 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), + PHYREGS(0xFC07, 0xF807, 0xF407, 0x0102, 0x0202, 0x0302), + }, + { .channel = 222, + .freq = 5110, /* MHz */ + .unk2 = 3407, + RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, + 0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D), + PHYREGS(0x0008, 0xFC07, 0xF807, 0x0002, 0x0102, 0x0202), + }, + { .channel = 224, + .freq = 5120, /* MHz */ + .unk2 = 3413, + RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, + 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), + PHYREGS(0x0408, 0x0008, 0xFC07, 0xFF01, 0x0002, 0x0102), + }, + { .channel = 226, + .freq = 5130, /* MHz */ + .unk2 = 3420, + RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, + 0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C), + PHYREGS(0x0808, 0x0408, 0x0008, 0xFE01, 0xFF01, 0x0002), + }, + { .channel = 228, + .freq = 5140, /* MHz */ + .unk2 = 3427, + RADIOREGS(0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, + 0x8B, 0xDD, 0x00, 0x0C, 0x0E, 0x8B), + PHYREGS(0x0C08, 0x0808, 0x0408, 0xFD01, 0xFE01, 0xFF01), + }, + { .channel = 32, + .freq = 5160, /* MHz */ + .unk2 = 3440, + RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, + 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), + PHYREGS(0x1408, 0x1008, 0x0C08, 0xFB01, 0xFC01, 0xFD01), + }, + { .channel = 34, + .freq = 5170, /* MHz */ + .unk2 = 3447, + RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, + 0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A), + PHYREGS(0x1808, 0x1408, 0x1008, 0xFA01, 0xFB01, 0xFC01), + }, + { .channel = 36, + .freq = 5180, /* MHz */ + .unk2 = 3453, + RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, + 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), + PHYREGS(0x1C08, 0x1808, 0x1408, 0xF901, 0xFA01, 0xFB01), + }, + { .channel = 38, + .freq = 5190, /* MHz */ + .unk2 = 3460, + RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, + 0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89), + PHYREGS(0x2008, 0x1C08, 0x1808, 0xF801, 0xF901, 0xFA01), + }, + { .channel = 40, + .freq = 5200, /* MHz */ + .unk2 = 3467, + RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, + 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), + PHYREGS(0x2408, 0x2008, 0x1C08, 0xF701, 0xF801, 0xF901), + }, + { .channel = 42, + .freq = 5210, /* MHz */ + .unk2 = 3473, + RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, + 0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89), + PHYREGS(0x2808, 0x2408, 0x2008, 0xF601, 0xF701, 0xF801), + }, + { .channel = 44, + .freq = 5220, /* MHz */ + .unk2 = 3480, + RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, + 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), + PHYREGS(0x2C08, 0x2808, 0x2408, 0xF501, 0xF601, 0xF701), + }, + { .channel = 46, + .freq = 5230, /* MHz */ + .unk2 = 3487, + RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, + 0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88), + PHYREGS(0x3008, 0x2C08, 0x2808, 0xF401, 0xF501, 0xF601), + }, + { .channel = 48, + .freq = 5240, /* MHz */ + .unk2 = 3493, + RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, + 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), + PHYREGS(0x3408, 0x3008, 0x2C08, 0xF301, 0xF401, 0xF501), + }, + { .channel = 50, + .freq = 5250, /* MHz */ + .unk2 = 3500, + RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, + 0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87), + PHYREGS(0x3808, 0x3408, 0x3008, 0xF201, 0xF301, 0xF401), + }, + { .channel = 52, + .freq = 5260, /* MHz */ + .unk2 = 3507, + RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, + 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), + PHYREGS(0x3C08, 0x3808, 0x3408, 0xF101, 0xF201, 0xF301), + }, + { .channel = 54, + .freq = 5270, /* MHz */ + .unk2 = 3513, + RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, + 0x87, 0xAA, 0x00, 0x08, 0x09, 0x87), + PHYREGS(0x4008, 0x3C08, 0x3808, 0xF001, 0xF101, 0xF201), + }, + { .channel = 56, + .freq = 5280, /* MHz */ + .unk2 = 3520, + RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, + 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), + PHYREGS(0x4408, 0x4008, 0x3C08, 0xF001, 0xF001, 0xF101), + }, + { .channel = 58, + .freq = 5290, /* MHz */ + .unk2 = 3527, + RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, + 0x86, 0x99, 0x00, 0x08, 0x08, 0x86), + PHYREGS(0x4808, 0x4408, 0x4008, 0xEF01, 0xF001, 0xF001), + }, + { .channel = 60, + .freq = 5300, /* MHz */ + .unk2 = 3533, + RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, + 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), + PHYREGS(0x4C08, 0x4808, 0x4408, 0xEE01, 0xEF01, 0xF001), + }, + { .channel = 62, + .freq = 5310, /* MHz */ + .unk2 = 3540, + RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, + 0x85, 0x99, 0x00, 0x08, 0x07, 0x85), + PHYREGS(0x5008, 0x4C08, 0x4808, 0xED01, 0xEE01, 0xEF01), + }, + { .channel = 64, + .freq = 5320, /* MHz */ + .unk2 = 3547, + RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, + 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), + PHYREGS(0x5408, 0x5008, 0x4C08, 0xEC01, 0xED01, 0xEE01), + }, + { .channel = 66, + .freq = 5330, /* MHz */ + .unk2 = 3553, + RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, + 0x84, 0x88, 0x00, 0x07, 0x07, 0x84), + PHYREGS(0x5808, 0x5408, 0x5008, 0xEB01, 0xEC01, 0xED01), + }, + { .channel = 68, + .freq = 5340, /* MHz */ + .unk2 = 3560, + RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, + 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), + PHYREGS(0x5C08, 0x5808, 0x5408, 0xEA01, 0xEB01, 0xEC01), + }, + { .channel = 70, + .freq = 5350, /* MHz */ + .unk2 = 3567, + RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, + 0x84, 0x88, 0x00, 0x07, 0x06, 0x84), + PHYREGS(0x6008, 0x5C08, 0x5808, 0xE901, 0xEA01, 0xEB01), + }, + { .channel = 72, + .freq = 5360, /* MHz */ + .unk2 = 3573, + RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, + 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), + PHYREGS(0x6408, 0x6008, 0x5C08, 0xE801, 0xE901, 0xEA01), + }, + { .channel = 74, + .freq = 5370, /* MHz */ + .unk2 = 3580, + RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, + 0x83, 0x77, 0x00, 0x06, 0x05, 0x83), + PHYREGS(0x6808, 0x6408, 0x6008, 0xE701, 0xE801, 0xE901), + }, + { .channel = 76, + .freq = 5380, /* MHz */ + .unk2 = 3587, + RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, + 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), + PHYREGS(0x6C08, 0x6808, 0x6408, 0xE601, 0xE701, 0xE801), + }, + { .channel = 78, + .freq = 5390, /* MHz */ + .unk2 = 3593, + RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, + 0x82, 0x77, 0x00, 0x06, 0x04, 0x82), + PHYREGS(0x7008, 0x6C08, 0x6808, 0xE501, 0xE601, 0xE701), + }, + { .channel = 80, + .freq = 5400, /* MHz */ + .unk2 = 3600, + RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, + 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), + PHYREGS(0x7408, 0x7008, 0x6C08, 0xE501, 0xE501, 0xE601), + }, + { .channel = 82, + .freq = 5410, /* MHz */ + .unk2 = 3607, + RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, + 0x81, 0x66, 0x00, 0x05, 0x04, 0x81), + PHYREGS(0x7808, 0x7408, 0x7008, 0xE401, 0xE501, 0xE501), + }, + { .channel = 84, + .freq = 5420, /* MHz */ + .unk2 = 3613, + RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, + 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), + PHYREGS(0x7C08, 0x7808, 0x7408, 0xE301, 0xE401, 0xE501), + }, + { .channel = 86, + .freq = 5430, /* MHz */ + .unk2 = 3620, + RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, + 0x80, 0x66, 0x00, 0x05, 0x03, 0x80), + PHYREGS(0x8008, 0x7C08, 0x7808, 0xE201, 0xE301, 0xE401), + }, + { .channel = 88, + .freq = 5440, /* MHz */ + .unk2 = 3627, + RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, + 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), + PHYREGS(0x8408, 0x8008, 0x7C08, 0xE101, 0xE201, 0xE301), + }, + { .channel = 90, + .freq = 5450, /* MHz */ + .unk2 = 3633, + RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, + 0x80, 0x55, 0x00, 0x04, 0x02, 0x80), + PHYREGS(0x8808, 0x8408, 0x8008, 0xE001, 0xE101, 0xE201), + }, + { .channel = 92, + .freq = 5460, /* MHz */ + .unk2 = 3640, + RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, + 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), + PHYREGS(0x8C08, 0x8808, 0x8408, 0xDF01, 0xE001, 0xE101), + }, + { .channel = 94, + .freq = 5470, /* MHz */ + .unk2 = 3647, + RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, + 0x80, 0x55, 0x00, 0x04, 0x01, 0x80), + PHYREGS(0x9008, 0x8C08, 0x8808, 0xDE01, 0xDF01, 0xE001), + }, + { .channel = 96, + .freq = 5480, /* MHz */ + .unk2 = 3653, + RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9408, 0x9008, 0x8C08, 0xDD01, 0xDE01, 0xDF01), + }, + { .channel = 98, + .freq = 5490, /* MHz */ + .unk2 = 3660, + RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9808, 0x9408, 0x9008, 0xDD01, 0xDD01, 0xDE01), + }, + { .channel = 100, + .freq = 5500, /* MHz */ + .unk2 = 3667, + RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0x9C08, 0x9808, 0x9408, 0xDC01, 0xDD01, 0xDD01), + }, + { .channel = 102, + .freq = 5510, /* MHz */ + .unk2 = 3673, + RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, + 0x80, 0x44, 0x00, 0x03, 0x00, 0x80), + PHYREGS(0xA008, 0x9C08, 0x9808, 0xDB01, 0xDC01, 0xDD01), + }, + { .channel = 104, + .freq = 5520, /* MHz */ + .unk2 = 3680, + RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xA408, 0xA008, 0x9C08, 0xDA01, 0xDB01, 0xDC01), + }, + { .channel = 106, + .freq = 5530, /* MHz */ + .unk2 = 3687, + RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xA808, 0xA408, 0xA008, 0xD901, 0xDA01, 0xDB01), + }, + { .channel = 108, + .freq = 5540, /* MHz */ + .unk2 = 3693, + RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xAC08, 0xA808, 0xA408, 0xD801, 0xD901, 0xDA01), + }, + { .channel = 110, + .freq = 5550, /* MHz */ + .unk2 = 3700, + RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x80, 0x33, 0x00, 0x02, 0x00, 0x80), + PHYREGS(0xB008, 0xAC08, 0xA808, 0xD701, 0xD801, 0xD901), + }, + { .channel = 112, + .freq = 5560, /* MHz */ + .unk2 = 3707, + RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xB408, 0xB008, 0xAC08, 0xD701, 0xD701, 0xD801), + }, + { .channel = 114, + .freq = 5570, /* MHz */ + .unk2 = 3713, + RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xB808, 0xB408, 0xB008, 0xD601, 0xD701, 0xD701), + }, + { .channel = 116, + .freq = 5580, /* MHz */ + .unk2 = 3720, + RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xBC08, 0xB808, 0xB408, 0xD501, 0xD601, 0xD701), + }, + { .channel = 118, + .freq = 5590, /* MHz */ + .unk2 = 3727, + RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, + 0x80, 0x22, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC008, 0xBC08, 0xB808, 0xD401, 0xD501, 0xD601), + }, + { .channel = 120, + .freq = 5600, /* MHz */ + .unk2 = 3733, + RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC408, 0xC008, 0xBC08, 0xD301, 0xD401, 0xD501), + }, + { .channel = 122, + .freq = 5610, /* MHz */ + .unk2 = 3740, + RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x80, 0x11, 0x00, 0x01, 0x00, 0x80), + PHYREGS(0xC808, 0xC408, 0xC008, 0xD201, 0xD301, 0xD401), + }, + { .channel = 124, + .freq = 5620, /* MHz */ + .unk2 = 3747, + RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xCC08, 0xC808, 0xC408, 0xD201, 0xD201, 0xD301), + }, + { .channel = 126, + .freq = 5630, /* MHz */ + .unk2 = 3753, + RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x80, 0x11, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD008, 0xCC08, 0xC808, 0xD101, 0xD201, 0xD201), + }, + { .channel = 128, + .freq = 5640, /* MHz */ + .unk2 = 3760, + RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD408, 0xD008, 0xCC08, 0xD001, 0xD101, 0xD201), + }, + { .channel = 130, + .freq = 5650, /* MHz */ + .unk2 = 3767, + RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xD808, 0xD408, 0xD008, 0xCF01, 0xD001, 0xD101), + }, + { .channel = 132, + .freq = 5660, /* MHz */ + .unk2 = 3773, + RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xDC08, 0xD808, 0xD408, 0xCE01, 0xCF01, 0xD001), + }, + { .channel = 134, + .freq = 5670, /* MHz */ + .unk2 = 3780, + RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE008, 0xDC08, 0xD808, 0xCE01, 0xCE01, 0xCF01), + }, + { .channel = 136, + .freq = 5680, /* MHz */ + .unk2 = 3787, + RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE408, 0xE008, 0xDC08, 0xCD01, 0xCE01, 0xCE01), + }, + { .channel = 138, + .freq = 5690, /* MHz */ + .unk2 = 3793, + RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xE808, 0xE408, 0xE008, 0xCC01, 0xCD01, 0xCE01), + }, + { .channel = 140, + .freq = 5700, /* MHz */ + .unk2 = 3800, + RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xEC08, 0xE808, 0xE408, 0xCB01, 0xCC01, 0xCD01), + }, + { .channel = 142, + .freq = 5710, /* MHz */ + .unk2 = 3807, + RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF008, 0xEC08, 0xE808, 0xCA01, 0xCB01, 0xCC01), + }, + { .channel = 144, + .freq = 5720, /* MHz */ + .unk2 = 3813, + RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF408, 0xF008, 0xEC08, 0xC901, 0xCA01, 0xCB01), + }, + { .channel = 145, + .freq = 5725, /* MHz */ + .unk2 = 3817, + RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF608, 0xF208, 0xEE08, 0xC901, 0xCA01, 0xCB01), + }, + { .channel = 146, + .freq = 5730, /* MHz */ + .unk2 = 3820, + RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xF808, 0xF408, 0xF008, 0xC901, 0xC901, 0xCA01), + }, + { .channel = 147, + .freq = 5735, /* MHz */ + .unk2 = 3823, + RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFA08, 0xF608, 0xF208, 0xC801, 0xC901, 0xCA01), + }, + { .channel = 148, + .freq = 5740, /* MHz */ + .unk2 = 3827, + RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFC08, 0xF808, 0xF408, 0xC801, 0xC901, 0xC901), + }, + { .channel = 149, + .freq = 5745, /* MHz */ + .unk2 = 3830, + RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0xFE08, 0xFA08, 0xF608, 0xC801, 0xC801, 0xC901), + }, + { .channel = 150, + .freq = 5750, /* MHz */ + .unk2 = 3833, + RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0009, 0xFC08, 0xF808, 0xC701, 0xC801, 0xC901), + }, + { .channel = 151, + .freq = 5755, /* MHz */ + .unk2 = 3837, + RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0209, 0xFE08, 0xFA08, 0xC701, 0xC801, 0xC801), + }, + { .channel = 152, + .freq = 5760, /* MHz */ + .unk2 = 3840, + RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0409, 0x0009, 0xFC08, 0xC601, 0xC701, 0xC801), + }, + { .channel = 153, + .freq = 5765, /* MHz */ + .unk2 = 3843, + RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0609, 0x0209, 0xFE08, 0xC601, 0xC701, 0xC801), + }, + { .channel = 154, + .freq = 5770, /* MHz */ + .unk2 = 3847, + RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0809, 0x0409, 0x0009, 0xC601, 0xC601, 0xC701), + }, + { .channel = 155, + .freq = 5775, /* MHz */ + .unk2 = 3850, + RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0A09, 0x0609, 0x0209, 0xC501, 0xC601, 0xC701), + }, + { .channel = 156, + .freq = 5780, /* MHz */ + .unk2 = 3853, + RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0C09, 0x0809, 0x0409, 0xC501, 0xC601, 0xC601), + }, + { .channel = 157, + .freq = 5785, /* MHz */ + .unk2 = 3857, + RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x0E09, 0x0A09, 0x0609, 0xC401, 0xC501, 0xC601), + }, + { .channel = 158, + .freq = 5790, /* MHz */ + .unk2 = 3860, + RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1009, 0x0C09, 0x0809, 0xC401, 0xC501, 0xC601), + }, + { .channel = 159, + .freq = 5795, /* MHz */ + .unk2 = 3863, + RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1209, 0x0E09, 0x0A09, 0xC401, 0xC401, 0xC501), + }, + { .channel = 160, + .freq = 5800, /* MHz */ + .unk2 = 3867, + RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1409, 0x1009, 0x0C09, 0xC301, 0xC401, 0xC501), + }, + { .channel = 161, + .freq = 5805, /* MHz */ + .unk2 = 3870, + RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1609, 0x1209, 0x0E09, 0xC301, 0xC401, 0xC401), + }, + { .channel = 162, + .freq = 5810, /* MHz */ + .unk2 = 3873, + RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1809, 0x1409, 0x1009, 0xC201, 0xC301, 0xC401), + }, + { .channel = 163, + .freq = 5815, /* MHz */ + .unk2 = 3877, + RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1A09, 0x1609, 0x1209, 0xC201, 0xC301, 0xC401), + }, + { .channel = 164, + .freq = 5820, /* MHz */ + .unk2 = 3880, + RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1C09, 0x1809, 0x1409, 0xC201, 0xC201, 0xC301), + }, + { .channel = 165, + .freq = 5825, /* MHz */ + .unk2 = 3883, + RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x1E09, 0x1A09, 0x1609, 0xC101, 0xC201, 0xC301), + }, + { .channel = 166, + .freq = 5830, /* MHz */ + .unk2 = 3887, + RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2009, 0x1C09, 0x1809, 0xC101, 0xC201, 0xC201), + }, + { .channel = 168, + .freq = 5840, /* MHz */ + .unk2 = 3893, + RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2409, 0x2009, 0x1C09, 0xC001, 0xC101, 0xC201), + }, + { .channel = 170, + .freq = 5850, /* MHz */ + .unk2 = 3900, + RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2809, 0x2409, 0x2009, 0xBF01, 0xC001, 0xC101), + }, + { .channel = 172, + .freq = 5860, /* MHz */ + .unk2 = 3907, + RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x2C09, 0x2809, 0x2409, 0xBF01, 0xBF01, 0xC001), + }, + { .channel = 174, + .freq = 5870, /* MHz */ + .unk2 = 3913, + RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3009, 0x2C09, 0x2809, 0xBE01, 0xBF01, 0xBF01), + }, + { .channel = 176, + .freq = 5880, /* MHz */ + .unk2 = 3920, + RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3409, 0x3009, 0x2C09, 0xBD01, 0xBE01, 0xBF01), + }, + { .channel = 178, + .freq = 5890, /* MHz */ + .unk2 = 3927, + RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3809, 0x3409, 0x3009, 0xBC01, 0xBD01, 0xBE01), + }, + { .channel = 180, + .freq = 5900, /* MHz */ + .unk2 = 3933, + RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x3C09, 0x3809, 0x3409, 0xBC01, 0xBC01, 0xBD01), + }, + { .channel = 182, + .freq = 5910, /* MHz */ + .unk2 = 3940, + RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x80), + PHYREGS(0x4009, 0x3C09, 0x3809, 0xBB01, 0xBC01, 0xBC01), + }, + { .channel = 1, + .freq = 2412, /* MHz */ + .unk2 = 3216, + RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, + 0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80), + PHYREGS(0xC903, 0xC503, 0xC103, 0x3A04, 0x3F04, 0x4304), + }, + { .channel = 2, + .freq = 2417, /* MHz */ + .unk2 = 3223, + RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, + 0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80), + PHYREGS(0xCB03, 0xC703, 0xC303, 0x3804, 0x3D04, 0x4104), + }, + { .channel = 3, + .freq = 2422, /* MHz */ + .unk2 = 3229, + RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, + 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), + PHYREGS(0xCD03, 0xC903, 0xC503, 0x3604, 0x3A04, 0x3F04), + }, + { .channel = 4, + .freq = 2427, /* MHz */ + .unk2 = 3236, + RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, + 0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80), + PHYREGS(0xCF03, 0xCB03, 0xC703, 0x3404, 0x3804, 0x3D04), + }, + { .channel = 5, + .freq = 2432, /* MHz */ + .unk2 = 3243, + RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, + 0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80), + PHYREGS(0xD103, 0xCD03, 0xC903, 0x3104, 0x3604, 0x3A04), + }, + { .channel = 6, + .freq = 2437, /* MHz */ + .unk2 = 3249, + RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, + 0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80), + PHYREGS(0xD303, 0xCF03, 0xCB03, 0x2F04, 0x3404, 0x3804), + }, + { .channel = 7, + .freq = 2442, /* MHz */ + .unk2 = 3256, + RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, + 0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80), + PHYREGS(0xD503, 0xD103, 0xCD03, 0x2D04, 0x3104, 0x3604), + }, + { .channel = 8, + .freq = 2447, /* MHz */ + .unk2 = 3263, + RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, + 0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80), + PHYREGS(0xD703, 0xD303, 0xCF03, 0x2B04, 0x2F04, 0x3404), + }, + { .channel = 9, + .freq = 2452, /* MHz */ + .unk2 = 3269, + RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, + 0x80, 0xFF, 0x88, 0x09, 0x06, 0x80), + PHYREGS(0xD903, 0xD503, 0xD103, 0x2904, 0x2D04, 0x3104), + }, + { .channel = 10, + .freq = 2457, /* MHz */ + .unk2 = 3276, + RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, + 0x80, 0xFF, 0x88, 0x08, 0x05, 0x80), + PHYREGS(0xDB03, 0xD703, 0xD303, 0x2704, 0x2B04, 0x2F04), + }, + { .channel = 11, + .freq = 2462, /* MHz */ + .unk2 = 3283, + RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, + 0x80, 0xFF, 0x88, 0x08, 0x04, 0x80), + PHYREGS(0xDD03, 0xD903, 0xD503, 0x2404, 0x2904, 0x2D04), + }, + { .channel = 12, + .freq = 2467, /* MHz */ + .unk2 = 3289, + RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, + 0x80, 0xFF, 0x88, 0x08, 0x03, 0x80), + PHYREGS(0xDF03, 0xDB03, 0xD703, 0x2204, 0x2704, 0x2B04), + }, + { .channel = 13, + .freq = 2472, /* MHz */ + .unk2 = 3296, + RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, + 0x80, 0xFF, 0x88, 0x07, 0x03, 0x80), + PHYREGS(0xE103, 0xDD03, 0xD903, 0x2004, 0x2404, 0x2904), + }, + { .channel = 14, + .freq = 2484, /* MHz */ + .unk2 = 3312, + RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, + 0x80, 0xFF, 0x88, 0x07, 0x01, 0x80), + PHYREGS(0xE603, 0xE203, 0xDE03, 0x1B04, 0x1F04, 0x2404), + }, +}; + +const struct b43_nphy_channeltab_entry * +b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel) +{ + const struct b43_nphy_channeltab_entry *e; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(b43_nphy_channeltab); i++) { + e = &(b43_nphy_channeltab[i]); + if (e->channel == channel) + return e; + } + + return NULL; +} + + +const u8 b43_ntab_adjustpower0[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, +}; + +const u8 b43_ntab_adjustpower1[] = { + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, + 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, +}; + +const u16 b43_ntab_bdi[] = { + 0x0070, 0x0126, 0x012C, 0x0246, 0x048D, 0x04D2, +}; + +const u32 b43_ntab_channelest[] = { + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x44444444, 0x44444444, 0x44444444, 0x44444444, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, + 0x10101010, 0x10101010, 0x10101010, 0x10101010, +}; + +const u8 b43_ntab_estimatepowerlt0[] = { + 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, + 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, + 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, + 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, +}; + +const u8 b43_ntab_estimatepowerlt1[] = { + 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, + 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, + 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, + 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, + 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, + 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, +}; + +const u8 b43_ntab_framelookup[] = { + 0x02, 0x04, 0x14, 0x14, 0x03, 0x05, 0x16, 0x16, + 0x0A, 0x0C, 0x1C, 0x1C, 0x0B, 0x0D, 0x1E, 0x1E, + 0x06, 0x08, 0x18, 0x18, 0x07, 0x09, 0x1A, 0x1A, + 0x0E, 0x10, 0x20, 0x28, 0x0F, 0x11, 0x22, 0x2A, +}; + +const u32 b43_ntab_framestruct[] = { + 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, + 0x09804506, 0x00100030, 0x09804507, 0x00100030, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028, + 0x0980450E, 0x00100038, 0x0980450F, 0x00100038, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A04, 0x00100000, 0x11008A05, 0x00100020, + 0x1980C506, 0x00100030, 0x21810506, 0x00100030, + 0x21810506, 0x00100030, 0x01800504, 0x00100030, + 0x11808505, 0x00100030, 0x29814507, 0x01100030, + 0x00000A04, 0x00100000, 0x11008A05, 0x00100020, + 0x21810506, 0x00100030, 0x21810506, 0x00100030, + 0x29814507, 0x01100030, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x1980C50E, 0x00100038, 0x2181050E, 0x00100038, + 0x2181050E, 0x00100038, 0x0180050C, 0x00100038, + 0x1180850D, 0x00100038, 0x2981450F, 0x01100038, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x2181050E, 0x00100038, 0x2181050E, 0x00100038, + 0x2981450F, 0x01100038, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, + 0x1980C506, 0x00100030, 0x1980C506, 0x00100030, + 0x11808504, 0x00100030, 0x3981CA05, 0x00100030, + 0x29814507, 0x01100030, 0x00000000, 0x00000000, + 0x10008A04, 0x00100000, 0x3981CA05, 0x00100030, + 0x1980C506, 0x00100030, 0x29814507, 0x01100030, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A0C, 0x00100008, 0x01000A0D, 0x00100028, + 0x1980C50E, 0x00100038, 0x1980C50E, 0x00100038, + 0x1180850C, 0x00100038, 0x3981CA0D, 0x00100038, + 0x2981450F, 0x01100038, 0x00000000, 0x00000000, + 0x10008A0C, 0x00100008, 0x3981CA0D, 0x00100038, + 0x1980C50E, 0x00100038, 0x2981450F, 0x01100038, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x00100000, 0x02001405, 0x00100040, + 0x0B004A06, 0x01900060, 0x13008A06, 0x01900060, + 0x13008A06, 0x01900060, 0x43020A04, 0x00100060, + 0x1B00CA05, 0x00100060, 0x23010A07, 0x01500060, + 0x40021404, 0x00100000, 0x1A00D405, 0x00100040, + 0x13008A06, 0x01900060, 0x13008A06, 0x01900060, + 0x23010A07, 0x01500060, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x0200140D, 0x00100050, + 0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070, + 0x1B00CA0D, 0x00100070, 0x23010A0F, 0x01500070, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x23010A0F, 0x01500070, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x50029404, 0x00100000, 0x32019405, 0x00100040, + 0x0B004A06, 0x01900060, 0x0B004A06, 0x01900060, + 0x5B02CA04, 0x00100060, 0x3B01D405, 0x00100060, + 0x23010A07, 0x01500060, 0x00000000, 0x00000000, + 0x5802D404, 0x00100000, 0x3B01D405, 0x00100060, + 0x0B004A06, 0x01900060, 0x23010A07, 0x01500060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x5002940C, 0x00100010, 0x3201940D, 0x00100050, + 0x0B004A0E, 0x01900070, 0x0B004A0E, 0x01900070, + 0x5B02CA0C, 0x00100070, 0x3B01D40D, 0x00100070, + 0x23010A0F, 0x01500070, 0x00000000, 0x00000000, + 0x5802D40C, 0x00100010, 0x3B01D40D, 0x00100070, + 0x0B004A0E, 0x01900070, 0x23010A0F, 0x01500070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x000F4800, 0x62031405, 0x00100040, + 0x53028A06, 0x01900060, 0x53028A07, 0x01900060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x000F4810, 0x6203140D, 0x00100050, + 0x53028A0E, 0x01900070, 0x53028A0F, 0x01900070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x1980C50E, 0x00100038, 0x2181050E, 0x00100038, + 0x2181050E, 0x00100038, 0x0180050C, 0x00100038, + 0x1180850D, 0x00100038, 0x1181850D, 0x00100038, + 0x2981450F, 0x01100038, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000A0C, 0x00100008, 0x11008A0D, 0x00100028, + 0x2181050E, 0x00100038, 0x2181050E, 0x00100038, + 0x1181850D, 0x00100038, 0x2981450F, 0x01100038, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x08004A04, 0x00100000, 0x01000A05, 0x00100020, + 0x0180C506, 0x00100030, 0x0180C506, 0x00100030, + 0x2180C50C, 0x00100030, 0x49820A0D, 0x0016A130, + 0x41824A0D, 0x0016A130, 0x2981450F, 0x01100030, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2000CA0C, 0x00100000, 0x49820A0D, 0x0016A130, + 0x1980C50E, 0x00100030, 0x41824A0D, 0x0016A130, + 0x2981450F, 0x01100030, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x0200140D, 0x00100050, + 0x0B004A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x13008A0E, 0x01900070, 0x43020A0C, 0x00100070, + 0x1B00CA0D, 0x00100070, 0x1B014A0D, 0x00100070, + 0x23010A0F, 0x01500070, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x13008A0E, 0x01900070, 0x13008A0E, 0x01900070, + 0x1B014A0D, 0x00100070, 0x23010A0F, 0x01500070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x50029404, 0x00100000, 0x32019405, 0x00100040, + 0x03004A06, 0x01900060, 0x03004A06, 0x01900060, + 0x6B030A0C, 0x00100060, 0x4B02140D, 0x0016A160, + 0x4302540D, 0x0016A160, 0x23010A0F, 0x01500060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6B03140C, 0x00100060, 0x4B02140D, 0x0016A160, + 0x0B004A0E, 0x01900060, 0x4302540D, 0x0016A160, + 0x23010A0F, 0x01500060, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x00100000, 0x1A00D405, 0x00100040, + 0x53028A06, 0x01900060, 0x5B02CA06, 0x01900060, + 0x5B02CA06, 0x01900060, 0x43020A04, 0x00100060, + 0x1B00CA05, 0x00100060, 0x53028A07, 0x0190C060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x53028A0E, 0x01900070, 0x5B02CA0E, 0x01900070, + 0x5B02CA0E, 0x01900070, 0x43020A0C, 0x00100070, + 0x1B00CA0D, 0x00100070, 0x53028A0F, 0x0190C070, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x40021404, 0x00100000, 0x1A00D405, 0x00100040, + 0x5B02CA06, 0x01900060, 0x5B02CA06, 0x01900060, + 0x53028A07, 0x0190C060, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x4002140C, 0x00100010, 0x1A00D40D, 0x00100050, + 0x5B02CA0E, 0x01900070, 0x5B02CA0E, 0x01900070, + 0x53028A0F, 0x0190C070, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_gainctl0[] = { + 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, + 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, + 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, + 0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38, + 0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336, + 0x006B0435, 0x006A0535, 0x00690634, 0x00680734, + 0x00670833, 0x00660933, 0x00650A32, 0x00640B32, + 0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30, + 0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E, + 0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C, + 0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A, + 0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28, + 0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326, + 0x004B0425, 0x004A0525, 0x00490624, 0x00480724, + 0x00470823, 0x00460923, 0x00450A22, 0x00440B22, + 0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20, + 0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E, + 0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C, + 0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A, + 0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18, + 0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316, + 0x002B0415, 0x002A0515, 0x00290614, 0x00280714, + 0x00270813, 0x00260913, 0x00250A12, 0x00240B12, + 0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10, + 0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E, + 0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C, + 0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A, + 0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08, + 0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306, + 0x000B0405, 0x000A0505, 0x00090604, 0x00080704, + 0x00070803, 0x00060903, 0x00050A02, 0x00040B02, + 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, +}; + +const u32 b43_ntab_gainctl1[] = { + 0x007F003F, 0x007E013F, 0x007D023E, 0x007C033E, + 0x007B043D, 0x007A053D, 0x0079063C, 0x0078073C, + 0x0077083B, 0x0076093B, 0x00750A3A, 0x00740B3A, + 0x00730C39, 0x00720D39, 0x00710E38, 0x00700F38, + 0x006F0037, 0x006E0137, 0x006D0236, 0x006C0336, + 0x006B0435, 0x006A0535, 0x00690634, 0x00680734, + 0x00670833, 0x00660933, 0x00650A32, 0x00640B32, + 0x00630C31, 0x00620D31, 0x00610E30, 0x00600F30, + 0x005F002F, 0x005E012F, 0x005D022E, 0x005C032E, + 0x005B042D, 0x005A052D, 0x0059062C, 0x0058072C, + 0x0057082B, 0x0056092B, 0x00550A2A, 0x00540B2A, + 0x00530C29, 0x00520D29, 0x00510E28, 0x00500F28, + 0x004F0027, 0x004E0127, 0x004D0226, 0x004C0326, + 0x004B0425, 0x004A0525, 0x00490624, 0x00480724, + 0x00470823, 0x00460923, 0x00450A22, 0x00440B22, + 0x00430C21, 0x00420D21, 0x00410E20, 0x00400F20, + 0x003F001F, 0x003E011F, 0x003D021E, 0x003C031E, + 0x003B041D, 0x003A051D, 0x0039061C, 0x0038071C, + 0x0037081B, 0x0036091B, 0x00350A1A, 0x00340B1A, + 0x00330C19, 0x00320D19, 0x00310E18, 0x00300F18, + 0x002F0017, 0x002E0117, 0x002D0216, 0x002C0316, + 0x002B0415, 0x002A0515, 0x00290614, 0x00280714, + 0x00270813, 0x00260913, 0x00250A12, 0x00240B12, + 0x00230C11, 0x00220D11, 0x00210E10, 0x00200F10, + 0x001F000F, 0x001E010F, 0x001D020E, 0x001C030E, + 0x001B040D, 0x001A050D, 0x0019060C, 0x0018070C, + 0x0017080B, 0x0016090B, 0x00150A0A, 0x00140B0A, + 0x00130C09, 0x00120D09, 0x00110E08, 0x00100F08, + 0x000F0007, 0x000E0107, 0x000D0206, 0x000C0306, + 0x000B0405, 0x000A0505, 0x00090604, 0x00080704, + 0x00070803, 0x00060903, 0x00050A02, 0x00040B02, + 0x00030C01, 0x00020D01, 0x00010E00, 0x00000F00, +}; + +const u32 b43_ntab_intlevel[] = { + 0x00802070, 0x0671188D, 0x0A60192C, 0x0A300E46, + 0x00C1188D, 0x080024D2, 0x00000070, +}; + +const u32 b43_ntab_iqlt0[] = { + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, +}; + +const u32 b43_ntab_iqlt1[] = { + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, + 0x0000007F, 0x0000007F, 0x0000007F, 0x0000007F, +}; + +const u16 b43_ntab_loftlt0[] = { + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, +}; + +const u16 b43_ntab_loftlt1[] = { + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, 0x0000, 0x0101, 0x0002, 0x0103, + 0x0000, 0x0101, 0x0002, 0x0103, 0x0000, 0x0101, + 0x0002, 0x0103, +}; + +const u8 b43_ntab_mcs[] = { + 0x00, 0x08, 0x0A, 0x10, 0x12, 0x19, 0x1A, 0x1C, + 0x40, 0x48, 0x4A, 0x50, 0x52, 0x59, 0x5A, 0x5C, + 0x80, 0x88, 0x8A, 0x90, 0x92, 0x99, 0x9A, 0x9C, + 0xC0, 0xC8, 0xCA, 0xD0, 0xD2, 0xD9, 0xDA, 0xDC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x04, 0x08, 0x09, 0x0A, 0x0C, + 0x10, 0x11, 0x12, 0x14, 0x18, 0x19, 0x1A, 0x1C, + 0x20, 0x21, 0x22, 0x24, 0x40, 0x41, 0x42, 0x44, + 0x48, 0x49, 0x4A, 0x4C, 0x50, 0x51, 0x52, 0x54, + 0x58, 0x59, 0x5A, 0x5C, 0x60, 0x61, 0x62, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const u32 b43_ntab_noisevar10[] = { + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, +}; + +const u32 b43_ntab_noisevar11[] = { + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, + 0x020C020C, 0x0000014D, 0x020C020C, 0x0000014D, +}; + +const u16 b43_ntab_pilot[] = { + 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, 0xFF08, + 0xFF08, 0xFF08, 0x80D5, 0x80D5, 0x80D5, 0x80D5, + 0x80D5, 0x80D5, 0x80D5, 0x80D5, 0xFF0A, 0xFF82, + 0xFFA0, 0xFF28, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, + 0xFF82, 0xFFA0, 0xFF28, 0xFF0A, 0xFFFF, 0xFFFF, + 0xFFFF, 0xFFFF, 0xF83F, 0xFA1F, 0xFA97, 0xFAB5, + 0xF2BD, 0xF0BF, 0xFFFF, 0xFFFF, 0xF017, 0xF815, + 0xF215, 0xF095, 0xF035, 0xF01D, 0xFFFF, 0xFFFF, + 0xFF08, 0xFF02, 0xFF80, 0xFF20, 0xFF08, 0xFF02, + 0xFF80, 0xFF20, 0xF01F, 0xF817, 0xFA15, 0xF295, + 0xF0B5, 0xF03D, 0xFFFF, 0xFFFF, 0xF82A, 0xFA0A, + 0xFA82, 0xFAA0, 0xF2A8, 0xF0AA, 0xFFFF, 0xFFFF, + 0xF002, 0xF800, 0xF200, 0xF080, 0xF020, 0xF008, + 0xFFFF, 0xFFFF, 0xF00A, 0xF802, 0xFA00, 0xF280, + 0xF0A0, 0xF028, 0xFFFF, 0xFFFF, +}; + +const u32 b43_ntab_pilotlt[] = { + 0x76540123, 0x62407351, 0x76543201, 0x76540213, + 0x76540123, 0x76430521, +}; + +const u32 b43_ntab_tdi20a0[] = { + 0x00091226, 0x000A1429, 0x000B56AD, 0x000C58B0, + 0x000D5AB3, 0x000E9CB6, 0x000F9EBA, 0x0000C13D, + 0x00020301, 0x00030504, 0x00040708, 0x0005090B, + 0x00064B8E, 0x00095291, 0x000A5494, 0x000B9718, + 0x000C9927, 0x000D9B2A, 0x000EDD2E, 0x000FDF31, + 0x000101B4, 0x000243B7, 0x000345BB, 0x000447BE, + 0x00058982, 0x00068C05, 0x00099309, 0x000A950C, + 0x000BD78F, 0x000CD992, 0x000DDB96, 0x000F1D99, + 0x00005FA8, 0x0001422C, 0x0002842F, 0x00038632, + 0x00048835, 0x0005CA38, 0x0006CCBC, 0x0009D3BF, + 0x000B1603, 0x000C1806, 0x000D1A0A, 0x000E1C0D, + 0x000F5E10, 0x00008093, 0x00018297, 0x0002C49A, + 0x0003C680, 0x0004C880, 0x00060B00, 0x00070D00, + 0x00000000, 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdi20a1[] = { + 0x00014B26, 0x00028D29, 0x000393AD, 0x00049630, + 0x0005D833, 0x0006DA36, 0x00099C3A, 0x000A9E3D, + 0x000BC081, 0x000CC284, 0x000DC488, 0x000F068B, + 0x0000488E, 0x00018B91, 0x0002D214, 0x0003D418, + 0x0004D6A7, 0x000618AA, 0x00071AAE, 0x0009DCB1, + 0x000B1EB4, 0x000C0137, 0x000D033B, 0x000E053E, + 0x000F4702, 0x00008905, 0x00020C09, 0x0003128C, + 0x0004148F, 0x00051712, 0x00065916, 0x00091B19, + 0x000A1D28, 0x000B5F2C, 0x000C41AF, 0x000D43B2, + 0x000E85B5, 0x000F87B8, 0x0000C9BC, 0x00024CBF, + 0x00035303, 0x00045506, 0x0005978A, 0x0006998D, + 0x00095B90, 0x000A5D93, 0x000B9F97, 0x000C821A, + 0x000D8400, 0x000EC600, 0x000FC800, 0x00010A00, + 0x00000000, 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdi40a0[] = { + 0x0011A346, 0x00136CCF, 0x0014F5D9, 0x001641E2, + 0x0017CB6B, 0x00195475, 0x001B2383, 0x001CAD0C, + 0x001E7616, 0x0000821F, 0x00020BA8, 0x0003D4B2, + 0x00056447, 0x00072DD0, 0x0008B6DA, 0x000A02E3, + 0x000B8C6C, 0x000D15F6, 0x0011E484, 0x0013AE0D, + 0x00153717, 0x00168320, 0x00180CA9, 0x00199633, + 0x001B6548, 0x001CEED1, 0x001EB7DB, 0x0000C3E4, + 0x00024D6D, 0x000416F7, 0x0005A585, 0x00076F0F, + 0x0008F818, 0x000A4421, 0x000BCDAB, 0x000D9734, + 0x00122649, 0x0013EFD2, 0x001578DC, 0x0016C4E5, + 0x00184E6E, 0x001A17F8, 0x001BA686, 0x001D3010, + 0x001EF999, 0x00010522, 0x00028EAC, 0x00045835, + 0x0005E74A, 0x0007B0D3, 0x00093A5D, 0x000A85E6, + 0x000C0F6F, 0x000DD8F9, 0x00126787, 0x00143111, + 0x0015BA9A, 0x00170623, 0x00188FAD, 0x001A5936, + 0x001BE84B, 0x001DB1D4, 0x001F3B5E, 0x000146E7, + 0x00031070, 0x000499FA, 0x00062888, 0x0007F212, + 0x00097B9B, 0x000AC7A4, 0x000C50AE, 0x000E1A37, + 0x0012A94C, 0x001472D5, 0x0015FC5F, 0x00174868, + 0x0018D171, 0x001A9AFB, 0x001C2989, 0x001DF313, + 0x001F7C9C, 0x000188A5, 0x000351AF, 0x0004DB38, + 0x0006AA4D, 0x000833D7, 0x0009BD60, 0x000B0969, + 0x000C9273, 0x000E5BFC, 0x00132A8A, 0x0014B414, + 0x00163D9D, 0x001789A6, 0x001912B0, 0x001ADC39, + 0x001C6BCE, 0x001E34D8, 0x001FBE61, 0x0001CA6A, + 0x00039374, 0x00051CFD, 0x0006EC0B, 0x00087515, + 0x0009FE9E, 0x000B4AA7, 0x000CD3B1, 0x000E9D3A, + 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdi40a1[] = { + 0x001EDB36, 0x000129CA, 0x0002B353, 0x00047CDD, + 0x0005C8E6, 0x000791EF, 0x00091BF9, 0x000AAA07, + 0x000C3391, 0x000DFD1A, 0x00120923, 0x0013D22D, + 0x00155C37, 0x0016EACB, 0x00187454, 0x001A3DDE, + 0x001B89E7, 0x001D12F0, 0x001F1CFA, 0x00016B88, + 0x00033492, 0x0004BE1B, 0x00060A24, 0x0007D32E, + 0x00095D38, 0x000AEC4C, 0x000C7555, 0x000E3EDF, + 0x00124AE8, 0x001413F1, 0x0015A37B, 0x00172C89, + 0x0018B593, 0x001A419C, 0x001BCB25, 0x001D942F, + 0x001F63B9, 0x0001AD4D, 0x00037657, 0x0004C260, + 0x00068BE9, 0x000814F3, 0x0009A47C, 0x000B2D8A, + 0x000CB694, 0x000E429D, 0x00128C26, 0x001455B0, + 0x0015E4BA, 0x00176E4E, 0x0018F758, 0x001A8361, + 0x001C0CEA, 0x001DD674, 0x001FA57D, 0x0001EE8B, + 0x0003B795, 0x0005039E, 0x0006CD27, 0x000856B1, + 0x0009E5C6, 0x000B6F4F, 0x000CF859, 0x000E8462, + 0x00130DEB, 0x00149775, 0x00162603, 0x0017AF8C, + 0x00193896, 0x001AC49F, 0x001C4E28, 0x001E17B2, + 0x0000A6C7, 0x00023050, 0x0003F9DA, 0x00054563, + 0x00070EEC, 0x00089876, 0x000A2704, 0x000BB08D, + 0x000D3A17, 0x001185A0, 0x00134F29, 0x0014D8B3, + 0x001667C8, 0x0017F151, 0x00197ADB, 0x001B0664, + 0x001C8FED, 0x001E5977, 0x0000E805, 0x0002718F, + 0x00043B18, 0x000586A1, 0x0007502B, 0x0008D9B4, + 0x000A68C9, 0x000BF252, 0x000DBBDC, 0x0011C7E5, + 0x001390EE, 0x00151A78, 0x0016A906, 0x00183290, + 0x0019BC19, 0x001B4822, 0x001CD12C, 0x001E9AB5, + 0x00000000, 0x00000000, +}; + +const u32 b43_ntab_tdtrn[] = { + 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, + 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, + 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, + 0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050, + 0x061C061C, 0x0050EE68, 0xF592FE36, 0xFE5212F6, + 0x00000C38, 0xFE5212F6, 0xF592FE36, 0x0050EE68, + 0x061C061C, 0xEE680050, 0xFE36F592, 0x12F6FE52, + 0x0C380000, 0x12F6FE52, 0xFE36F592, 0xEE680050, + 0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246, + 0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C, + 0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61, + 0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D, + 0x05E305E3, 0x004DEF0C, 0xF5F3FE47, 0xFE611246, + 0x00000BC7, 0xFE611246, 0xF5F3FE47, 0x004DEF0C, + 0x05E305E3, 0xEF0C004D, 0xFE47F5F3, 0x1246FE61, + 0x0BC70000, 0x1246FE61, 0xFE47F5F3, 0xEF0C004D, + 0xFA58FA58, 0xF895043B, 0xFF4C09C0, 0xFBC6FFA8, + 0xFB84F384, 0x0798F6F9, 0x05760122, 0x058409F6, + 0x0B500000, 0x05B7F542, 0x08860432, 0x06DDFEE7, + 0xFB84F384, 0xF9D90664, 0xF7E8025C, 0x00FFF7BD, + 0x05A805A8, 0xF7BD00FF, 0x025CF7E8, 0x0664F9D9, + 0xF384FB84, 0xFEE706DD, 0x04320886, 0xF54205B7, + 0x00000B50, 0x09F60584, 0x01220576, 0xF6F90798, + 0xF384FB84, 0xFFA8FBC6, 0x09C0FF4C, 0x043BF895, + 0x02D402D4, 0x07DE0270, 0xFC96079C, 0xF90AFE94, + 0xFE00FF2C, 0x02D4065D, 0x092A0096, 0x0014FBB8, + 0xFD2CFD2C, 0x076AFB3C, 0x0096F752, 0xF991FD87, + 0xFB2C0200, 0xFEB8F960, 0x08E0FC96, 0x049802A8, + 0xFD2CFD2C, 0x02A80498, 0xFC9608E0, 0xF960FEB8, + 0x0200FB2C, 0xFD87F991, 0xF7520096, 0xFB3C076A, + 0xFD2CFD2C, 0xFBB80014, 0x0096092A, 0x065D02D4, + 0xFF2CFE00, 0xFE94F90A, 0x079CFC96, 0x027007DE, + 0x02D402D4, 0x027007DE, 0x079CFC96, 0xFE94F90A, + 0xFF2CFE00, 0x065D02D4, 0x0096092A, 0xFBB80014, + 0xFD2CFD2C, 0xFB3C076A, 0xF7520096, 0xFD87F991, + 0x0200FB2C, 0xF960FEB8, 0xFC9608E0, 0x02A80498, + 0xFD2CFD2C, 0x049802A8, 0x08E0FC96, 0xFEB8F960, + 0xFB2C0200, 0xF991FD87, 0x0096F752, 0x076AFB3C, + 0xFD2CFD2C, 0x0014FBB8, 0x092A0096, 0x02D4065D, + 0xFE00FF2C, 0xF90AFE94, 0xFC96079C, 0x07DE0270, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D, + 0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF, + 0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8, + 0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7, + 0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3, + 0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841, + 0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608, + 0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759, + 0x062A0000, 0xFEFA0759, 0x08B80908, 0xF396FC2D, + 0xF9D6045C, 0xFC4EF608, 0xF748F596, 0x07B207BF, + 0x062A062A, 0xF84EF841, 0xF748F596, 0x03B209F8, + 0xF9D6045C, 0x0C6A03D3, 0x08B80908, 0x0106F8A7, + 0x062A0000, 0xFEFAF8A7, 0x08B8F6F8, 0xF39603D3, + 0xF9D6FBA4, 0xFC4E09F8, 0xF7480A6A, 0x07B2F841, + 0x062AF9D6, 0xF84E07BF, 0xF7480A6A, 0x03B2F608, + 0xF9D6FBA4, 0x0C6AFC2D, 0x08B8F6F8, 0x01060759, + 0x061C061C, 0xFF30009D, 0xFFB21141, 0xFD87FB54, + 0xF65DFE59, 0x02EEF99E, 0x0166F03C, 0xFFF809B6, + 0x000008A4, 0x000AF42B, 0x00EFF577, 0xFA840BF2, + 0xFC02FF51, 0x08260F67, 0xFFF0036F, 0x0842F9C3, + 0x00000000, 0x063DF7BE, 0xFC910010, 0xF099F7DA, + 0x00AF03FE, 0xF40E057C, 0x0A89FF11, 0x0BD5FFF6, + 0xF75C0000, 0xF64A0008, 0x0FC4FE9A, 0x0662FD12, + 0x01A709A3, 0x04AC0279, 0xEEBF004E, 0xFF6300D0, + 0xF9E4F9E4, 0x00D0FF63, 0x004EEEBF, 0x027904AC, + 0x09A301A7, 0xFD120662, 0xFE9A0FC4, 0x0008F64A, + 0x0000F75C, 0xFFF60BD5, 0xFF110A89, 0x057CF40E, + 0x03FE00AF, 0xF7DAF099, 0x0010FC91, 0xF7BE063D, + 0x00000000, 0xF9C30842, 0x036FFFF0, 0x0F670826, + 0xFF51FC02, 0x0BF2FA84, 0xF57700EF, 0xF42B000A, + 0x08A40000, 0x09B6FFF8, 0xF03C0166, 0xF99E02EE, + 0xFE59F65D, 0xFB54FD87, 0x1141FFB2, 0x009DFF30, + 0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59, + 0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766, + 0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986, + 0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB, + 0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7, + 0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A, + 0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A, + 0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705, + 0x05E30000, 0xFF060705, 0x085408A0, 0xF425FC59, + 0xFA1D042A, 0xFC78F67A, 0xF7ACF60E, 0x075A0766, + 0x05E305E3, 0xF8A6F89A, 0xF7ACF60E, 0x03880986, + 0xFA1D042A, 0x0BDB03A7, 0x085408A0, 0x00FAF8FB, + 0x05E30000, 0xFF06F8FB, 0x0854F760, 0xF42503A7, + 0xFA1DFBD6, 0xFC780986, 0xF7AC09F2, 0x075AF89A, + 0x05E3FA1D, 0xF8A60766, 0xF7AC09F2, 0x0388F67A, + 0xFA1DFBD6, 0x0BDBFC59, 0x0854F760, 0x00FA0705, + 0xFA58FA58, 0xF8F0FE00, 0x0448073D, 0xFDC9FE46, + 0xF9910258, 0x089D0407, 0xFD5CF71A, 0x02AFFDE0, + 0x083E0496, 0xFF5A0740, 0xFF7AFD97, 0x00FE01F1, + 0x0009082E, 0xFA94FF75, 0xFECDF8EA, 0xFFB0F693, + 0xFD2CFA58, 0x0433FF16, 0xFBA405DD, 0xFA610341, + 0x06A606CB, 0x0039FD2D, 0x0677FA97, 0x01FA05E0, + 0xF896003E, 0x075A068B, 0x012CFC3E, 0xFA23F98D, + 0xFC7CFD43, 0xFF90FC0D, 0x01C10982, 0x00C601D6, + 0xFD2CFD2C, 0x01D600C6, 0x098201C1, 0xFC0DFF90, + 0xFD43FC7C, 0xF98DFA23, 0xFC3E012C, 0x068B075A, + 0x003EF896, 0x05E001FA, 0xFA970677, 0xFD2D0039, + 0x06CB06A6, 0x0341FA61, 0x05DDFBA4, 0xFF160433, + 0xFA58FD2C, 0xF693FFB0, 0xF8EAFECD, 0xFF75FA94, + 0x082E0009, 0x01F100FE, 0xFD97FF7A, 0x0740FF5A, + 0x0496083E, 0xFDE002AF, 0xF71AFD5C, 0x0407089D, + 0x0258F991, 0xFE46FDC9, 0x073D0448, 0xFE00F8F0, + 0xFD2CFD2C, 0xFCE00500, 0xFC09FDDC, 0xFE680157, + 0x04C70571, 0xFC3AFF21, 0xFCD70228, 0x056D0277, + 0x0200FE00, 0x0022F927, 0xFE3C032B, 0xFC44FF3C, + 0x03E9FBDB, 0x04570313, 0x04C9FF5C, 0x000D03B8, + 0xFA580000, 0xFBE900D2, 0xF9D0FE0B, 0x0125FDF9, + 0x042501BF, 0x0328FA2B, 0xFFA902F0, 0xFA250157, + 0x0200FE00, 0x03740438, 0xFF0405FD, 0x030CFE52, + 0x0037FB39, 0xFF6904C5, 0x04F8FD23, 0xFD31FC1B, + 0xFD2CFD2C, 0xFC1BFD31, 0xFD2304F8, 0x04C5FF69, + 0xFB390037, 0xFE52030C, 0x05FDFF04, 0x04380374, + 0xFE000200, 0x0157FA25, 0x02F0FFA9, 0xFA2B0328, + 0x01BF0425, 0xFDF90125, 0xFE0BF9D0, 0x00D2FBE9, + 0x0000FA58, 0x03B8000D, 0xFF5C04C9, 0x03130457, + 0xFBDB03E9, 0xFF3CFC44, 0x032BFE3C, 0xF9270022, + 0xFE000200, 0x0277056D, 0x0228FCD7, 0xFF21FC3A, + 0x057104C7, 0x0157FE68, 0xFDDCFC09, 0x0500FCE0, + 0xFD2CFD2C, 0x0500FCE0, 0xFDDCFC09, 0x0157FE68, + 0x057104C7, 0xFF21FC3A, 0x0228FCD7, 0x0277056D, + 0xFE000200, 0xF9270022, 0x032BFE3C, 0xFF3CFC44, + 0xFBDB03E9, 0x03130457, 0xFF5C04C9, 0x03B8000D, + 0x0000FA58, 0x00D2FBE9, 0xFE0BF9D0, 0xFDF90125, + 0x01BF0425, 0xFA2B0328, 0x02F0FFA9, 0x0157FA25, + 0xFE000200, 0x04380374, 0x05FDFF04, 0xFE52030C, + 0xFB390037, 0x04C5FF69, 0xFD2304F8, 0xFC1BFD31, + 0xFD2CFD2C, 0xFD31FC1B, 0x04F8FD23, 0xFF6904C5, + 0x0037FB39, 0x030CFE52, 0xFF0405FD, 0x03740438, + 0x0200FE00, 0xFA250157, 0xFFA902F0, 0x0328FA2B, + 0x042501BF, 0x0125FDF9, 0xF9D0FE0B, 0xFBE900D2, + 0xFA580000, 0x000D03B8, 0x04C9FF5C, 0x04570313, + 0x03E9FBDB, 0xFC44FF3C, 0xFE3C032B, 0x0022F927, + 0x0200FE00, 0x056D0277, 0xFCD70228, 0xFC3AFF21, + 0x04C70571, 0xFE680157, 0xFC09FDDC, 0xFCE00500, + 0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E, + 0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C, + 0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926, + 0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942, + 0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382, + 0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4, + 0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA, + 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, + 0x05A80000, 0xFF1006BE, 0x0800084A, 0xF49CFC7E, + 0xFA580400, 0xFC9CF6DA, 0xF800F672, 0x0710071C, + 0x05A805A8, 0xF8F0F8E4, 0xF800F672, 0x03640926, + 0xFA580400, 0x0B640382, 0x0800084A, 0x00F0F942, + 0x05A80000, 0xFF10F942, 0x0800F7B6, 0xF49C0382, + 0xFA58FC00, 0xFC9C0926, 0xF800098E, 0x0710F8E4, + 0x05A8FA58, 0xF8F0071C, 0xF800098E, 0x0364F6DA, + 0xFA58FC00, 0x0B64FC7E, 0x0800F7B6, 0x00F006BE, +}; + +const u32 b43_ntab_tmap[] = { + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, + 0x11000000, 0x1111F111, 0x11111111, 0x111111F1, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x000AA888, + 0x88880000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA2222220, 0x22222222, 0x22C22222, 0x00000222, + 0x22000000, 0x2222A222, 0x22222222, 0x222222A2, + 0xF1111110, 0x11111111, 0x11F11111, 0x00011111, + 0x11110000, 0x1111F111, 0x11111111, 0x111111F1, + 0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00088AAA, + 0xAAAA0000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A, + 0xAAA8AAA0, 0x8AAA8AAA, 0xAA8A8A8A, 0x000AAA88, + 0x8AAA0000, 0xAAA8A888, 0x8AA88A8A, 0x8A88A888, + 0x08080A00, 0x0A08080A, 0x080A0A08, 0x00080808, + 0x080A0000, 0x080A0808, 0x080A0808, 0x0A0A0A08, + 0xA0A0A0A0, 0x80A0A080, 0x8080A0A0, 0x00008080, + 0x80A00000, 0x80A080A0, 0xA080A0A0, 0x8080A0A0, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x99999000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9, + 0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888, + 0x22000000, 0x2222B222, 0x22222222, 0x222222B2, + 0xB2222220, 0x22222222, 0x22D22222, 0x00000222, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x33000000, 0x3333B333, 0x33333333, 0x333333B3, + 0xB3333330, 0x33333333, 0x33D33333, 0x00000333, + 0x22000000, 0x2222A222, 0x22222222, 0x222222A2, + 0xA2222220, 0x22222222, 0x22C22222, 0x00000222, + 0x99B99B00, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9, + 0x9B99BB99, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888, + 0x22222200, 0x2222F222, 0x22222222, 0x222222F2, + 0x22222222, 0x22222222, 0x22F22222, 0x00000222, + 0x11000000, 0x1111F111, 0x11111111, 0x11111111, + 0xF1111111, 0x11111111, 0x11F11111, 0x01111111, + 0xBB9BB900, 0xB9B9BB99, 0xB99BBBBB, 0xBBBB9B9B, + 0xB9BB99BB, 0xB99999B9, 0xB9B9B99B, 0x00000BBB, + 0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A, + 0xA8AA88AA, 0xA88888A8, 0xA8A8A88A, 0x0A888AAA, + 0xAA000000, 0xA8A8AA88, 0xA88AAAAA, 0xAAAA8A8A, + 0xA8AA88A0, 0xA88888A8, 0xA8A8A88A, 0x00000AAA, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0xBBBBBB00, 0x999BBBBB, 0x9BB99B9B, 0xB9B9B9BB, + 0xB9B99BBB, 0xB9B9B9BB, 0xB9BB9B99, 0x00000999, + 0x8A000000, 0xAA88A888, 0xA88888AA, 0xA88A8A88, + 0xA88AA88A, 0x88A8AAAA, 0xA8AA8AAA, 0x0888A88A, + 0x0B0B0B00, 0x090B0B0B, 0x0B090B0B, 0x0909090B, + 0x09090B0B, 0x09090B0B, 0x09090B09, 0x00000909, + 0x0A000000, 0x0A080808, 0x080A080A, 0x080A0A08, + 0x080A080A, 0x0808080A, 0x0A0A0A08, 0x0808080A, + 0xB0B0B000, 0x9090B0B0, 0x90B09090, 0xB0B0B090, + 0xB0B090B0, 0x90B0B0B0, 0xB0B09090, 0x00000090, + 0x80000000, 0xA080A080, 0xA08080A0, 0xA0808080, + 0xA080A080, 0x80A0A0A0, 0xA0A080A0, 0x00A0A0A0, + 0x22000000, 0x2222F222, 0x22222222, 0x222222F2, + 0xF2222220, 0x22222222, 0x22F22222, 0x00000222, + 0x11000000, 0x1111F111, 0x11111111, 0x111111F1, + 0xF1111110, 0x11111111, 0x11F11111, 0x00000111, + 0x33000000, 0x3333F333, 0x33333333, 0x333333F3, + 0xF3333330, 0x33333333, 0x33F33333, 0x00000333, + 0x22000000, 0x2222F222, 0x22222222, 0x222222F2, + 0xF2222220, 0x22222222, 0x22F22222, 0x00000222, + 0x99000000, 0x9B9B99BB, 0x9BB99999, 0x9999B9B9, + 0x9B99BB90, 0x9BBBBB9B, 0x9B9B9BB9, 0x00000999, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88888000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00AAA888, + 0x88A88A00, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA88, 0x8AAAAA8A, 0x8A8A8AA8, 0x08AAA888, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x11000000, 0x1111A111, 0x11111111, 0x111111A1, + 0xA1111110, 0x11111111, 0x11C11111, 0x00000111, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x88000000, 0x8A8A88AA, 0x8AA88888, 0x8888A8A8, + 0x8A88AA80, 0x8AAAAA8A, 0x8A8A8AA8, 0x00000888, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static inline void assert_ntab_array_sizes(void) +{ +#undef check +#define check(table, size) \ + BUILD_BUG_ON(ARRAY_SIZE(b43_ntab_##table) != B43_NTAB_##size##_SIZE) + + check(adjustpower0, C0_ADJPLT); + check(adjustpower1, C1_ADJPLT); + check(bdi, BDI); + check(channelest, CHANEST); + check(estimatepowerlt0, C0_ESTPLT); + check(estimatepowerlt1, C1_ESTPLT); + check(framelookup, FRAMELT); + check(framestruct, FRAMESTRUCT); + check(gainctl0, C0_GAINCTL); + check(gainctl1, C1_GAINCTL); + check(intlevel, INTLEVEL); + check(iqlt0, C0_IQLT); + check(iqlt1, C1_IQLT); + check(loftlt0, C0_LOFEEDTH); + check(loftlt1, C1_LOFEEDTH); + check(mcs, MCS); + check(noisevar10, NOISEVAR10); + check(noisevar11, NOISEVAR11); + check(pilot, PILOT); + check(pilotlt, PILOTLT); + check(tdi20a0, TDI20A0); + check(tdi20a1, TDI20A1); + check(tdi40a0, TDI40A0); + check(tdi40a1, TDI40A1); + check(tdtrn, TDTRN); + check(tmap, TMAP); + +#undef check +} + +void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value) +{ + u32 type; + + type = offset & B43_NTAB_TYPEMASK; + offset &= 0xFFFF; + + switch (type) { + case B43_NTAB_8BIT: + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); + break; + case B43_NTAB_16BIT: + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value); + break; + case B43_NTAB_32BIT: + b43_phy_write(dev, B43_NPHY_TABLE_ADDR, offset); + b43_phy_write(dev, B43_NPHY_TABLE_DATAHI, value >> 16); + b43_phy_write(dev, B43_NPHY_TABLE_DATALO, value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + + return; + + /* Some compiletime assertions... */ + assert_ntab_array_sizes(); +} diff --git a/drivers/net/wireless/b43/tables_nphy.h b/drivers/net/wireless/b43/tables_nphy.h new file mode 100644 index 000000000000..4d498b053ec7 --- /dev/null +++ b/drivers/net/wireless/b43/tables_nphy.h @@ -0,0 +1,159 @@ +#ifndef B43_TABLES_NPHY_H_ +#define B43_TABLES_NPHY_H_ + +#include <linux/types.h> + + +struct b43_nphy_channeltab_entry { + /* The channel number */ + u8 channel; + /* Radio register values on channelswitch */ + u8 radio_pll_ref; + u8 radio_rf_pllmod0; + u8 radio_rf_pllmod1; + u8 radio_vco_captail; + u8 radio_vco_cal1; + u8 radio_vco_cal2; + u8 radio_pll_lfc1; + u8 radio_pll_lfr1; + u8 radio_pll_lfc2; + u8 radio_lgbuf_cenbuf; + u8 radio_lgen_tune1; + u8 radio_lgen_tune2; + u8 radio_c1_lgbuf_atune; + u8 radio_c1_lgbuf_gtune; + u8 radio_c1_rx_rfr1; + u8 radio_c1_tx_pgapadtn; + u8 radio_c1_tx_mxbgtrim; + u8 radio_c2_lgbuf_atune; + u8 radio_c2_lgbuf_gtune; + u8 radio_c2_rx_rfr1; + u8 radio_c2_tx_pgapadtn; + u8 radio_c2_tx_mxbgtrim; + /* PHY register values on channelswitch */ + u16 phy_bw1a; + u16 phy_bw2; + u16 phy_bw3; + u16 phy_bw4; + u16 phy_bw5; + u16 phy_bw6; + /* The channel frequency in MHz */ + u16 freq; + /* An unknown value */ + u16 unk2; +}; + + +struct b43_wldev; + +/* Upload the default register value table. + * If "ghz5" is true, we upload the 5Ghz table. Otherwise the 2.4Ghz + * table is uploaded. If "ignore_uploadflag" is true, we upload any value + * and ignore the "UPLOAD" flag. */ +void b2055_upload_inittab(struct b43_wldev *dev, + bool ghz5, bool ignore_uploadflag); + + +/* Get the NPHY Channel Switch Table entry for a channel number. + * Returns NULL on failure to find an entry. */ +const struct b43_nphy_channeltab_entry * +b43_nphy_get_chantabent(struct b43_wldev *dev, u8 channel); + + +/* The N-PHY tables. */ + +#define B43_NTAB_TYPEMASK 0xF0000000 +#define B43_NTAB_8BIT 0x10000000 +#define B43_NTAB_16BIT 0x20000000 +#define B43_NTAB_32BIT 0x30000000 +#define B43_NTAB8(table, offset) (((table) << 10) | (offset) | B43_NTAB_8BIT) +#define B43_NTAB16(table, offset) (((table) << 10) | (offset) | B43_NTAB_16BIT) +#define B43_NTAB32(table, offset) (((table) << 10) | (offset) | B43_NTAB_32BIT) + +/* Static N-PHY tables */ +#define B43_NTAB_FRAMESTRUCT B43_NTAB32(0x0A, 0x000) /* Frame Struct Table */ +#define B43_NTAB_FRAMESTRUCT_SIZE 832 +#define B43_NTAB_FRAMELT B43_NTAB8 (0x18, 0x000) /* Frame Lookup Table */ +#define B43_NTAB_FRAMELT_SIZE 32 +#define B43_NTAB_TMAP B43_NTAB32(0x0C, 0x000) /* T Map Table */ +#define B43_NTAB_TMAP_SIZE 448 +#define B43_NTAB_TDTRN B43_NTAB32(0x0E, 0x000) /* TDTRN Table */ +#define B43_NTAB_TDTRN_SIZE 704 +#define B43_NTAB_INTLEVEL B43_NTAB32(0x0D, 0x000) /* Int Level Table */ +#define B43_NTAB_INTLEVEL_SIZE 7 +#define B43_NTAB_PILOT B43_NTAB16(0x0B, 0x000) /* Pilot Table */ +#define B43_NTAB_PILOT_SIZE 88 +#define B43_NTAB_PILOTLT B43_NTAB32(0x14, 0x000) /* Pilot Lookup Table */ +#define B43_NTAB_PILOTLT_SIZE 6 +#define B43_NTAB_TDI20A0 B43_NTAB32(0x13, 0x080) /* TDI Table 20 Antenna 0 */ +#define B43_NTAB_TDI20A0_SIZE 55 +#define B43_NTAB_TDI20A1 B43_NTAB32(0x13, 0x100) /* TDI Table 20 Antenna 1 */ +#define B43_NTAB_TDI20A1_SIZE 55 +#define B43_NTAB_TDI40A0 B43_NTAB32(0x13, 0x280) /* TDI Table 40 Antenna 0 */ +#define B43_NTAB_TDI40A0_SIZE 110 +#define B43_NTAB_TDI40A1 B43_NTAB32(0x13, 0x300) /* TDI Table 40 Antenna 1 */ +#define B43_NTAB_TDI40A1_SIZE 110 +#define B43_NTAB_BDI B43_NTAB16(0x15, 0x000) /* BDI Table */ +#define B43_NTAB_BDI_SIZE 6 +#define B43_NTAB_CHANEST B43_NTAB32(0x16, 0x000) /* Channel Estimate Table */ +#define B43_NTAB_CHANEST_SIZE 96 +#define B43_NTAB_MCS B43_NTAB8 (0x12, 0x000) /* MCS Table */ +#define B43_NTAB_MCS_SIZE 128 + +/* Volatile N-PHY tables */ +#define B43_NTAB_NOISEVAR10 B43_NTAB32(0x10, 0x000) /* Noise Var Table 10 */ +#define B43_NTAB_NOISEVAR10_SIZE 256 +#define B43_NTAB_NOISEVAR11 B43_NTAB32(0x10, 0x080) /* Noise Var Table 11 */ +#define B43_NTAB_NOISEVAR11_SIZE 256 +#define B43_NTAB_C0_ESTPLT B43_NTAB8 (0x1A, 0x000) /* Estimate Power Lookup Table Core 0 */ +#define B43_NTAB_C0_ESTPLT_SIZE 64 +#define B43_NTAB_C1_ESTPLT B43_NTAB8 (0x1B, 0x000) /* Estimate Power Lookup Table Core 1 */ +#define B43_NTAB_C1_ESTPLT_SIZE 64 +#define B43_NTAB_C0_ADJPLT B43_NTAB8 (0x1A, 0x040) /* Adjust Power Lookup Table Core 0 */ +#define B43_NTAB_C0_ADJPLT_SIZE 128 +#define B43_NTAB_C1_ADJPLT B43_NTAB8 (0x1B, 0x040) /* Adjust Power Lookup Table Core 1 */ +#define B43_NTAB_C1_ADJPLT_SIZE 128 +#define B43_NTAB_C0_GAINCTL B43_NTAB32(0x1A, 0x0C0) /* Gain Control Lookup Table Core 0 */ +#define B43_NTAB_C0_GAINCTL_SIZE 128 +#define B43_NTAB_C1_GAINCTL B43_NTAB32(0x1B, 0x0C0) /* Gain Control Lookup Table Core 1 */ +#define B43_NTAB_C1_GAINCTL_SIZE 128 +#define B43_NTAB_C0_IQLT B43_NTAB32(0x1A, 0x140) /* IQ Lookup Table Core 0 */ +#define B43_NTAB_C0_IQLT_SIZE 128 +#define B43_NTAB_C1_IQLT B43_NTAB32(0x1B, 0x140) /* IQ Lookup Table Core 1 */ +#define B43_NTAB_C1_IQLT_SIZE 128 +#define B43_NTAB_C0_LOFEEDTH B43_NTAB16(0x1A, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 0 */ +#define B43_NTAB_C0_LOFEEDTH_SIZE 128 +#define B43_NTAB_C1_LOFEEDTH B43_NTAB16(0x1B, 0x1C0) /* Local Oscillator Feed Through Lookup Table Core 1 */ +#define B43_NTAB_C1_LOFEEDTH_SIZE 128 + +void b43_ntab_write(struct b43_wldev *dev, u32 offset, u32 value); + +extern const u8 b43_ntab_adjustpower0[]; +extern const u8 b43_ntab_adjustpower1[]; +extern const u16 b43_ntab_bdi[]; +extern const u32 b43_ntab_channelest[]; +extern const u8 b43_ntab_estimatepowerlt0[]; +extern const u8 b43_ntab_estimatepowerlt1[]; +extern const u8 b43_ntab_framelookup[]; +extern const u32 b43_ntab_framestruct[]; +extern const u32 b43_ntab_gainctl0[]; +extern const u32 b43_ntab_gainctl1[]; +extern const u32 b43_ntab_intlevel[]; +extern const u32 b43_ntab_iqlt0[]; +extern const u32 b43_ntab_iqlt1[]; +extern const u16 b43_ntab_loftlt0[]; +extern const u16 b43_ntab_loftlt1[]; +extern const u8 b43_ntab_mcs[]; +extern const u32 b43_ntab_noisevar10[]; +extern const u32 b43_ntab_noisevar11[]; +extern const u16 b43_ntab_pilot[]; +extern const u32 b43_ntab_pilotlt[]; +extern const u32 b43_ntab_tdi20a0[]; +extern const u32 b43_ntab_tdi20a1[]; +extern const u32 b43_ntab_tdi40a0[]; +extern const u32 b43_ntab_tdi40a1[]; +extern const u32 b43_ntab_tdtrn[]; +extern const u32 b43_ntab_tmap[]; + + +#endif /* B43_TABLES_NPHY_H_ */ diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c new file mode 100644 index 000000000000..e632125cb772 --- /dev/null +++ b/drivers/net/wireless/b43/wa.c @@ -0,0 +1,674 @@ +/* + + Broadcom B43 wireless driver + + PHY workarounds. + + Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> + Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "b43.h" +#include "main.h" +#include "tables.h" +#include "phy.h" +#include "wa.h" + +static void b43_wa_papd(struct b43_wldev *dev) +{ + u16 backup; + + backup = b43_ofdmtab_read16(dev, B43_OFDMTAB_PWRDYN2, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, 7); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 0, 0); + b43_dummy_transmission(dev); + b43_ofdmtab_write16(dev, B43_OFDMTAB_PWRDYN2, 0, backup); +} + +static void b43_wa_auxclipthr(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x3800); +} + +static void b43_wa_afcdac(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x0035, 0x03FF); + b43_phy_write(dev, 0x0036, 0x0400); +} + +static void b43_wa_txdc_offset(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 0, 0x0051); +} + +void b43_wa_initgains(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9); + b43_phy_write(dev, B43_PHY_LPFGAINCTL, + b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F); + if (phy->rev <= 2) + b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF); + b43_radio_write16(dev, 0x0002, 0x1FBF); + + b43_phy_write(dev, 0x0024, 0x4680); + b43_phy_write(dev, 0x0020, 0x0003); + b43_phy_write(dev, 0x001D, 0x0F40); + b43_phy_write(dev, 0x001F, 0x1C00); + if (phy->rev <= 3) + b43_phy_write(dev, 0x002A, + (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400); + else if (phy->rev == 5) { + b43_phy_write(dev, 0x002A, + (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00); + b43_phy_write(dev, 0x00CC, 0x2121); + } + if (phy->rev >= 3) + b43_phy_write(dev, 0x00BA, 0x3ED5); +} + +static void b43_wa_divider(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100); + b43_phy_write(dev, 0x008E, 0x58C1); +} + +static void b43_wa_gt(struct b43_wldev *dev) /* Gain table. */ +{ + if (dev->phy.rev <= 2) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 0, 15); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 1, 31); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 2, 42); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 3, 48); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN2, 4, 58); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 0, 3); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 1, 3); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN1, 2, 7); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 0, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 1, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 3, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 4, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 5, 21); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAIN0, 6, 25); + } +} + +static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */ +{ + int i; + + if (0 /* FIXME: For APHY.rev=2 this might be needed */) { + for (i = 0; i < 8; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8); + for (i = 8; i < 16; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8); + } else { + for (i = 0; i < 64; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i); + } +} + +static void b43_wa_analog(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + u16 ofdmrev; + + ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION; + if (ofdmrev > 2) { + if (phy->type == B43_PHYTYPE_A) + b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1808); + else + b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044); + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201); + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040); + } +} + +static void b43_wa_dac(struct b43_wldev *dev) +{ + if (dev->phy.analog == 1) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, + (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0034) | 0x0008); + else + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, + (b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 1) & ~0x0078) | 0x0010); +} + +static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */ +{ + int i; + + if (dev->phy.type == B43_PHYTYPE_A) + for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqa[i]); + else + for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, b43_tab_finefreqg[i]); +} + +static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */ +{ + struct b43_phy *phy = &dev->phy; + int i; + + if (phy->type == B43_PHYTYPE_A) { + if (phy->rev == 2) + for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea2[i]); + else + for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noisea3[i]); + } else { + if (phy->rev == 1) + for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg1[i]); + else + for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, b43_tab_noiseg2[i]); + } +} + +static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ +{ + int i; + + for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) + b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]); +} + +static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */ +{ + struct b43_phy *phy = &dev->phy; + int i; + + if (phy->type == B43_PHYTYPE_A) { + if (phy->rev <= 1) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, 0); + else if (phy->rev == 2) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescalea2[i]); + else if (phy->rev == 3) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescalea3[i]); + else + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg3[i]); + } else { + if (phy->rev >= 6) { + if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg3[i]); + else + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg2[i]); + } else { + for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) + b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, + i, b43_tab_noisescaleg1[i]); + } + } +} + +static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */ +{ + int i; + + for (i = 0; i < B43_TAB_RETARD_SIZE; i++) + b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD, + i, b43_tab_retard[i]); +} + +static void b43_wa_txlna_gain(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 13, 0x0000); +} + +static void b43_wa_crs_reset(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x002C, 0x0064); +} + +static void b43_wa_2060txlna_gain(struct b43_wldev *dev) +{ + b43_hf_write(dev, b43_hf_read(dev) | + B43_HF_2060W); +} + +static void b43_wa_lms(struct b43_wldev *dev) +{ + b43_phy_write(dev, 0x0055, + (b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004); +} + +static void b43_wa_mixedsignal(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 1, 3); +} + +static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */ +{ + struct b43_phy *phy = &dev->phy; + int i; + const u16 *tab; + + if (phy->type == B43_PHYTYPE_A) { + tab = b43_tab_sigmasqr1; + } else if (phy->type == B43_PHYTYPE_G) { + tab = b43_tab_sigmasqr2; + } else { + B43_WARN_ON(1); + return; + } + + for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ, + i, tab[i]); + } +} + +static void b43_wa_iqadc(struct b43_wldev *dev) +{ + if (dev->phy.analog == 4) + b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 0, + b43_ofdmtab_read16(dev, B43_OFDMTAB_DAC, 0) & ~0xF000); +} + +static void b43_wa_crs_ed(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19); + } else if (phy->rev == 2) { + b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861); + b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271); + b43_phy_write(dev, B43_PHY_ANTDWELL, + b43_phy_read(dev, B43_PHY_ANTDWELL) + | 0x0800); + } else { + b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098); + b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070); + b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080); + b43_phy_write(dev, B43_PHY_ANTDWELL, + b43_phy_read(dev, B43_PHY_ANTDWELL) + | 0x0800); + } +} + +static void b43_wa_crs_thr(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_CRS0, + (b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000); +} + +static void b43_wa_crs_blank(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A); +} + +static void b43_wa_cck_shiftbits(struct b43_wldev *dev) +{ + b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026); +} + +static void b43_wa_wrssi_offset(struct b43_wldev *dev) +{ + int i; + + if (dev->phy.rev == 1) { + for (i = 0; i < 16; i++) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1, + i, 0x0020); + } + } else { + for (i = 0; i < 32; i++) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI, + i, 0x0820); + } + } +} + +static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20); +} + +static void b43_wa_altagc(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->rev == 1) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D); + b43_phy_write(dev, B43_PHY_LMS, 4); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25); + } + + b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA, + (b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700); + b43_phy_write(dev, B43_PHY_OFDM(0x1A), + (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F); + b43_phy_write(dev, B43_PHY_OFDM(0x1A), + (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80); + b43_phy_write(dev, B43_PHY_ANTWRSETT, + (b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300); + b43_radio_write16(dev, 0x7A, + b43_radio_read16(dev, 0x7A) | 0x0008); + b43_phy_write(dev, B43_PHY_N1P1GAIN, + (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008); + b43_phy_write(dev, B43_PHY_P1P2GAIN, + (b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600); + b43_phy_write(dev, B43_PHY_N1N2GAIN, + (b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700); + b43_phy_write(dev, B43_PHY_N1P1GAIN, + (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100); + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_N1N2GAIN, + (b43_phy_read(dev, B43_PHY_N1N2GAIN) + & ~0x000F) | 0x0007); + } + b43_phy_write(dev, B43_PHY_OFDM(0x88), + (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C); + b43_phy_write(dev, B43_PHY_OFDM(0x88), + (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200); + b43_phy_write(dev, B43_PHY_OFDM(0x96), + (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C); + b43_phy_write(dev, B43_PHY_OFDM(0x89), + (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020); + b43_phy_write(dev, B43_PHY_OFDM(0x89), + (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200); + b43_phy_write(dev, B43_PHY_OFDM(0x82), + (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E); + b43_phy_write(dev, B43_PHY_OFDM(0x96), + (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00); + b43_phy_write(dev, B43_PHY_OFDM(0x81), + (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028); + b43_phy_write(dev, B43_PHY_OFDM(0x81), + (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00); + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B); + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + (b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002); + } else { + b43_phy_write(dev, B43_PHY_OFDM(0x1B), + b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E); + b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A); + b43_phy_write(dev, B43_PHY_LPFGAINCTL, + (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004); + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A); + b43_phy_write(dev, B43_PHY_LPFGAINCTL, + (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000); + } + } + b43_phy_write(dev, B43_PHY_DIVSRCHIDX, + (b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874); + b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00); + if (phy->rev == 1) { + b43_phy_write(dev, B43_PHY_DIVP1P2GAIN, + (b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600); + b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E); + b43_phy_write(dev, B43_PHY_ANTWRSETT, + (b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E); + b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16); + b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28); + } + if (phy->rev >= 6) { + b43_phy_write(dev, B43_PHY_OFDM(0x26), + b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003); + b43_phy_write(dev, B43_PHY_OFDM(0x26), + b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000); + } + b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */ +} + +static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */ +{ + b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0xC480); +} + +static void b43_wa_cpll_nonpilot(struct b43_wldev *dev) +{ + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0); +} + +static void b43_wa_rssi_adc(struct b43_wldev *dev) +{ + if (dev->phy.analog == 4) + b43_phy_write(dev, 0x00DC, 0x7454); +} + +static void b43_wa_boards_a(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + + if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM && + bus->boardinfo.type == SSB_BOARD_BU4306 && + bus->boardinfo.rev < 0x30) { + b43_phy_write(dev, 0x0010, 0xE000); + b43_phy_write(dev, 0x0013, 0x0140); + b43_phy_write(dev, 0x0014, 0x0280); + } else { + if (bus->boardinfo.type == SSB_BOARD_MP4318 && + bus->boardinfo.rev < 0x20) { + b43_phy_write(dev, 0x0013, 0x0210); + b43_phy_write(dev, 0x0014, 0x0840); + } else { + b43_phy_write(dev, 0x0013, 0x0140); + b43_phy_write(dev, 0x0014, 0x0280); + } + if (dev->phy.rev <= 4) + b43_phy_write(dev, 0x0010, 0xE000); + else + b43_phy_write(dev, 0x0010, 0x2000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_DC, 1, 0x0039); + b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_APHY, 7, 0x0040); + } +} + +static void b43_wa_boards_g(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct b43_phy *phy = &dev->phy; + + if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM || + bus->boardinfo.type != SSB_BOARD_BU4306 || + bus->boardinfo.rev != 0x17) { + if (phy->rev < 2) { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001); + } else { + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001); + if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) && + (phy->rev >= 7)) { + b43_phy_write(dev, B43_PHY_EXTG(0x11), + b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000); + b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002); + } + } + } + if (bus->sprom.boardflags_lo & B43_BFL_FEM) { + b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120); + b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480); + } +} + +void b43_wa_all(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + if (phy->type == B43_PHYTYPE_A) { + switch (phy->rev) { + case 2: + b43_wa_papd(dev); + b43_wa_auxclipthr(dev); + b43_wa_afcdac(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_divider(dev); + b43_wa_gt(dev); + b43_wa_rssi_lt(dev); + b43_wa_analog(dev); + b43_wa_dac(dev); + b43_wa_fft(dev); + b43_wa_nft(dev); + b43_wa_rt(dev); + b43_wa_nst(dev); + b43_wa_art(dev); + b43_wa_txlna_gain(dev); + b43_wa_crs_reset(dev); + b43_wa_2060txlna_gain(dev); + b43_wa_lms(dev); + break; + case 3: + b43_wa_papd(dev); + b43_wa_mixedsignal(dev); + b43_wa_rssi_lt(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_dac(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_analog(dev); + b43_wa_gt(dev); + b43_wa_txpuoff_rxpuon(dev); + b43_wa_txlna_gain(dev); + break; + case 5: + b43_wa_iqadc(dev); + case 6: + b43_wa_papd(dev); + b43_wa_rssi_lt(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_dac(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_analog(dev); + b43_wa_gt(dev); + b43_wa_txpuoff_rxpuon(dev); + b43_wa_txlna_gain(dev); + break; + case 7: + b43_wa_iqadc(dev); + b43_wa_papd(dev); + b43_wa_rssi_lt(dev); + b43_wa_txdc_offset(dev); + b43_wa_initgains(dev); + b43_wa_dac(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_analog(dev); + b43_wa_gt(dev); + b43_wa_txpuoff_rxpuon(dev); + b43_wa_txlna_gain(dev); + b43_wa_rssi_adc(dev); + default: + B43_WARN_ON(1); + } + b43_wa_boards_a(dev); + } else if (phy->type == B43_PHYTYPE_G) { + switch (phy->rev) { + case 1://XXX review rev1 + b43_wa_crs_ed(dev); + b43_wa_crs_thr(dev); + b43_wa_crs_blank(dev); + b43_wa_cck_shiftbits(dev); + b43_wa_fft(dev); + b43_wa_nft(dev); + b43_wa_rt(dev); + b43_wa_nst(dev); + b43_wa_art(dev); + b43_wa_wrssi_offset(dev); + b43_wa_altagc(dev); + break; + case 2: + case 6: + case 7: + case 8: + case 9: + b43_wa_tr_ltov(dev); + b43_wa_crs_ed(dev); + b43_wa_rssi_lt(dev); + b43_wa_nft(dev); + b43_wa_nst(dev); + b43_wa_msst(dev); + b43_wa_wrssi_offset(dev); + b43_wa_altagc(dev); + b43_wa_analog(dev); + b43_wa_txpuoff_rxpuon(dev); + break; + default: + B43_WARN_ON(1); + } + b43_wa_boards_g(dev); + } else { /* No N PHY support so far */ + B43_WARN_ON(1); + } + + b43_wa_cpll_nonpilot(dev); +} diff --git a/drivers/net/wireless/b43/wa.h b/drivers/net/wireless/b43/wa.h new file mode 100644 index 000000000000..e163c5e56e81 --- /dev/null +++ b/drivers/net/wireless/b43/wa.h @@ -0,0 +1,7 @@ +#ifndef B43_WA_H_ +#define B43_WA_H_ + +void b43_wa_initgains(struct b43_wldev *dev); +void b43_wa_all(struct b43_wldev *dev); + +#endif /* B43_WA_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 3307ba1856b1..3fc53e8b4416 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -5,7 +5,7 @@ Transmission (TX/RX) related functions. Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (C) 2005 Stefano Brivio <st3@riseup.net> + Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -30,7 +30,7 @@ #include "xmit.h" #include "phy.h" #include "dma.h" -#include "pio.h" + /* Extract the bitrate out of a CCK PLCP header. */ static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) @@ -177,13 +177,15 @@ static u8 b43_calc_fallback_rate(u8 bitrate) return 0; } -static void generate_txhdr_fw4(struct b43_wldev *dev, - struct b43_txhdr_fw4 *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, - u16 cookie) +/* Generate a TX data header. */ +void b43_generate_txhdr(struct b43_wldev *dev, + u8 *_txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const struct ieee80211_tx_control *txctl, + u16 cookie) { + struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; const struct b43_phy *phy = &dev->phy; const struct ieee80211_hdr *wlhdr = (const struct ieee80211_hdr *)fragment_data; @@ -221,7 +223,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, } else { int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_len, fbrate_base100kbps); } @@ -241,23 +243,30 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, plcp_fragment_len += txctl->icv_len; key_idx = b43_kidx_to_fw(dev, key_idx); - mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) & - B43_TX4_MAC_KEYIDX; - mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) & - B43_TX4_MAC_KEYALG; + mac_ctl |= (key_idx << B43_TXH_MAC_KEYIDX_SHIFT) & + B43_TXH_MAC_KEYIDX; + mac_ctl |= (key->algorithm << B43_TXH_MAC_KEYALG_SHIFT) & + B43_TXH_MAC_KEYALG; wlhdr_len = ieee80211_get_hdrlen(fctl); iv_len = min((size_t) txctl->iv_len, ARRAY_SIZE(txhdr->iv)); memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp), - plcp_fragment_len, rate); + if (b43_is_old_txhdr_format(dev)) { + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), + plcp_fragment_len, rate); + } else { + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp), + plcp_fragment_len, rate); + } b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), plcp_fragment_len, rate_fb); /* Extra Frame Types */ if (rate_fb_ofdm) - extra_ft |= B43_TX4_EFT_FBOFDM; + extra_ft |= B43_TXH_EFT_FB_OFDM; + else + extra_ft |= B43_TXH_EFT_FB_CCK; /* Set channel radio code. Note that the micrcode ORs 0x100 to * this value before comparing it to the value in SHM, if this @@ -267,18 +276,27 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) - phy_ctl |= B43_TX4_PHY_OFDM; + phy_ctl |= B43_TXH_PHY_ENC_OFDM; + else + phy_ctl |= B43_TXH_PHY_ENC_CCK; if (dev->short_preamble) - phy_ctl |= B43_TX4_PHY_SHORTPRMBL; - switch (txctl->antenna_sel_tx) { - case 0: - phy_ctl |= B43_TX4_PHY_ANTLAST; + phy_ctl |= B43_TXH_PHY_SHORTPRMBL; + + switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { + case 0: /* Default */ + phy_ctl |= B43_TXH_PHY_ANT01AUTO; + break; + case 1: /* Antenna 0 */ + phy_ctl |= B43_TXH_PHY_ANT0; break; - case 1: - phy_ctl |= B43_TX4_PHY_ANT0; + case 2: /* Antenna 1 */ + phy_ctl |= B43_TXH_PHY_ANT1; break; - case 2: - phy_ctl |= B43_TX4_PHY_ANT1; + case 3: /* Antenna 2 */ + phy_ctl |= B43_TXH_PHY_ANT2; + break; + case 4: /* Antenna 3 */ + phy_ctl |= B43_TXH_PHY_ANT3; break; default: B43_WARN_ON(1); @@ -286,14 +304,16 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, /* MAC control */ if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK)) - mac_ctl |= B43_TX4_MAC_ACK; + mac_ctl |= B43_TXH_MAC_ACK; if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL))) - mac_ctl |= B43_TX4_MAC_HWSEQ; + mac_ctl |= B43_TXH_MAC_HWSEQ; if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT) - mac_ctl |= B43_TX4_MAC_STMSDU; + mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) - mac_ctl |= B43_TX4_MAC_5GHZ; + mac_ctl |= B43_TXH_MAC_5GHZ; + if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + mac_ctl |= B43_TXH_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -302,6 +322,7 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; + struct b43_plcp_hdr6 *plcp; rts_rate = txctl->rts_cts_rate; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); @@ -309,59 +330,84 @@ static void generate_txhdr_fw4(struct b43_wldev *dev, rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { - ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id, + struct ieee80211_cts *cts; + + if (b43_is_old_txhdr_format(dev)) { + cts = (struct ieee80211_cts *) + (txhdr->old_format.rts_frame); + } else { + cts = (struct ieee80211_cts *) + (txhdr->new_format.rts_frame); + } + ieee80211_ctstoself_get(dev->wl->hw, txctl->vif, fragment_data, fragment_len, - txctl, - (struct ieee80211_cts *)(txhdr-> - rts_frame)); - mac_ctl |= B43_TX4_MAC_SENDCTS; + txctl, cts); + mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { - ieee80211_rts_get(dev->wl->hw, dev->wl->if_id, - fragment_data, fragment_len, txctl, - (struct ieee80211_rts *)(txhdr-> - rts_frame)); - mac_ctl |= B43_TX4_MAC_SENDRTS; + struct ieee80211_rts *rts; + + if (b43_is_old_txhdr_format(dev)) { + rts = (struct ieee80211_rts *) + (txhdr->old_format.rts_frame); + } else { + rts = (struct ieee80211_rts *) + (txhdr->new_format.rts_frame); + } + ieee80211_rts_get(dev->wl->hw, txctl->vif, + fragment_data, fragment_len, + txctl, rts); + mac_ctl |= B43_TXH_MAC_SENDRTS; len = sizeof(struct ieee80211_rts); } len += FCS_LEN; - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> - rts_plcp), len, - rts_rate); - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr-> - rts_plcp_fb), + + /* Generate the PLCP headers for the RTS/CTS frame */ + if (b43_is_old_txhdr_format(dev)) + plcp = &txhdr->old_format.rts_plcp; + else + plcp = &txhdr->new_format.rts_plcp; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, + len, rts_rate); + plcp = &txhdr->rts_plcp_fb; + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, len, rts_rate_fb); - hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); + + if (b43_is_old_txhdr_format(dev)) { + hdr = (struct ieee80211_hdr *) + (&txhdr->old_format.rts_frame); + } else { + hdr = (struct ieee80211_hdr *) + (&txhdr->new_format.rts_frame); + } txhdr->rts_dur_fb = hdr->duration_id; + if (rts_rate_ofdm) { - extra_ft |= B43_TX4_EFT_RTSOFDM; + extra_ft |= B43_TXH_EFT_RTS_OFDM; txhdr->phy_rate_rts = b43_plcp_get_ratecode_ofdm(rts_rate); - } else + } else { + extra_ft |= B43_TXH_EFT_RTS_CCK; txhdr->phy_rate_rts = b43_plcp_get_ratecode_cck(rts_rate); + } if (rts_rate_fb_ofdm) - extra_ft |= B43_TX4_EFT_RTSFBOFDM; - mac_ctl |= B43_TX4_MAC_LONGFRAME; + extra_ft |= B43_TXH_EFT_RTSFB_OFDM; + else + extra_ft |= B43_TXH_EFT_RTSFB_CCK; } /* Magic cookie */ - txhdr->cookie = cpu_to_le16(cookie); + if (b43_is_old_txhdr_format(dev)) + txhdr->old_format.cookie = cpu_to_le16(cookie); + else + txhdr->new_format.cookie = cpu_to_le16(cookie); /* Apply the bitfields */ txhdr->mac_ctl = cpu_to_le32(mac_ctl); txhdr->phy_ctl = cpu_to_le16(phy_ctl); txhdr->extra_ft = extra_ft; -} -void b43_generate_txhdr(struct b43_wldev *dev, - u8 * txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const struct ieee80211_tx_control *txctl, u16 cookie) -{ - generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr, - fragment_data, fragment_len, txctl, cookie); } static s8 b43_rssi_postprocess(struct b43_wldev *dev, @@ -384,7 +430,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev, else tmp -= 3; } else { - if (dev->dev->bus->sprom.r1. + if (dev->dev->bus->sprom. boardflags_lo & B43_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; @@ -488,7 +534,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } wlhdr = (struct ieee80211_hdr *)(skb->data); fctl = le16_to_cpu(wlhdr->frame_control); - skb_trim(skb, skb->len - FCS_LEN); if (macstat & B43_RX_MAC_DEC) { unsigned int keyidx; @@ -525,7 +570,24 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) else status.rate = b43_plcp_get_bitrate_cck(plcp); status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); - status.mactime = mactime; + + /* + * If monitors are present get full 64-bit timestamp. This + * code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY + * received the first symbol. + */ + if (dev->wl->radiotap_enabled) { + u16 low_mactime_now; + + b43_tsf_read(dev, &status.mactime); + low_mactime_now = status.mactime; + status.mactime = status.mactime & ~0xFFFFULL; + status.mactime += mactime; + if (low_mactime_now <= mactime) + status.mactime -= 0x10000; + status.flag |= RX_FLAG_TSFT; + } chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; switch (chanstat & B43_RX_CHAN_PHYTYPE) { @@ -586,10 +648,7 @@ void b43_handle_txstatus(struct b43_wldev *dev, dev->wl->ieee_stats.dot11RTSSuccessCount++; } - if (b43_using_pio(dev)) - b43_pio_handle_txstatus(dev, status); - else - b43_dma_handle_txstatus(dev, status); + b43_dma_handle_txstatus(dev, status); } /* Handle TX status report as received through DMA/PIO queues */ @@ -618,19 +677,13 @@ void b43_handle_hwtxstatus(struct b43_wldev *dev, /* Stop any TX operation on the device (suspend the hardware queues) */ void b43_tx_suspend(struct b43_wldev *dev) { - if (b43_using_pio(dev)) - b43_pio_freeze_txqueues(dev); - else - b43_dma_tx_suspend(dev); + b43_dma_tx_suspend(dev); } /* Resume any TX operation on the device (resume the hardware queues) */ void b43_tx_resume(struct b43_wldev *dev) { - if (b43_using_pio(dev)) - b43_pio_thaw_txqueues(dev); - else - b43_dma_tx_resume(dev); + b43_dma_tx_resume(dev); } #if 0 diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 6dc079382f7f..ca2a2ab8654c 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -19,68 +19,160 @@ _b43_declare_plcp_hdr(6); #undef _b43_declare_plcp_hdr /* TX header for v4 firmware */ -struct b43_txhdr_fw4 { - __le32 mac_ctl; /* MAC TX control */ - __le16 mac_frame_ctl; /* Copy of the FrameControl field */ +struct b43_txhdr { + __le32 mac_ctl; /* MAC TX control */ + __le16 mac_frame_ctl; /* Copy of the FrameControl field */ __le16 tx_fes_time_norm; /* TX FES Time Normal */ - __le16 phy_ctl; /* PHY TX control */ - __le16 phy_ctl_0; /* Unused */ - __le16 phy_ctl_1; /* Unused */ - __le16 phy_ctl_rts_0; /* Unused */ - __le16 phy_ctl_rts_1; /* Unused */ - __u8 phy_rate; /* PHY rate */ - __u8 phy_rate_rts; /* PHY rate for RTS/CTS */ - __u8 extra_ft; /* Extra Frame Types */ - __u8 chan_radio_code; /* Channel Radio Code */ - __u8 iv[16]; /* Encryption IV */ - __u8 tx_receiver[6]; /* TX Frame Receiver address */ - __le16 tx_fes_time_fb; /* TX FES Time Fallback */ - struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP */ - __le16 rts_dur_fb; /* RTS fallback duration */ - struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP */ - __le16 dur_fb; /* Fallback duration */ - __le16 mm_dur_time; /* Unused */ - __le16 mm_dur_time_fb; /* Unused */ - __le32 time_stamp; /* Timestamp */ - PAD_BYTES(2); - __le16 cookie; /* TX frame cookie */ - __le16 tx_status; /* TX status */ - struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP */ - __u8 rts_frame[16]; /* The RTS frame (if used) */ - PAD_BYTES(2); - struct b43_plcp_hdr6 plcp; /* Main PLCP */ + __le16 phy_ctl; /* PHY TX control */ + __le16 phy_ctl1; /* PHY TX control word 1 */ + __le16 phy_ctl1_fb; /* PHY TX control word 1 for fallback rates */ + __le16 phy_ctl1_rts; /* PHY TX control word 1 RTS */ + __le16 phy_ctl1_rts_fb; /* PHY TX control word 1 RTS for fallback rates */ + __u8 phy_rate; /* PHY rate */ + __u8 phy_rate_rts; /* PHY rate for RTS/CTS */ + __u8 extra_ft; /* Extra Frame Types */ + __u8 chan_radio_code; /* Channel Radio Code */ + __u8 iv[16]; /* Encryption IV */ + __u8 tx_receiver[6]; /* TX Frame Receiver address */ + __le16 tx_fes_time_fb; /* TX FES Time Fallback */ + struct b43_plcp_hdr6 rts_plcp_fb; /* RTS fallback PLCP header */ + __le16 rts_dur_fb; /* RTS fallback duration */ + struct b43_plcp_hdr6 plcp_fb; /* Fallback PLCP header */ + __le16 dur_fb; /* Fallback duration */ + __le16 mimo_modelen; /* MIMO mode length */ + __le16 mimo_ratelen_fb; /* MIMO fallback rate length */ + __le32 timeout; /* Timeout */ + + union { + /* The new r410 format. */ + struct { + __le16 mimo_antenna; /* MIMO antenna select */ + __le16 preload_size; /* Preload size */ + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP header */ + } new_format __attribute__ ((__packed__)); + + /* The old r351 format. */ + struct { + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP header */ + } old_format __attribute__ ((__packed__)); + + } __attribute__ ((__packed__)); } __attribute__ ((__packed__)); /* MAC TX control */ -#define B43_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */ -#define B43_TX4_MAC_KEYIDX_SHIFT 20 -#define B43_TX4_MAC_KEYALG 0x00070000 /* Security key algorithm */ -#define B43_TX4_MAC_KEYALG_SHIFT 16 -#define B43_TX4_MAC_LIFETIME 0x00001000 -#define B43_TX4_MAC_FRAMEBURST 0x00000800 -#define B43_TX4_MAC_SENDCTS 0x00000400 -#define B43_TX4_MAC_AMPDU 0x00000300 -#define B43_TX4_MAC_AMPDU_SHIFT 8 -#define B43_TX4_MAC_5GHZ 0x00000080 -#define B43_TX4_MAC_IGNPMQ 0x00000020 -#define B43_TX4_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ -#define B43_TX4_MAC_STMSDU 0x00000008 /* Start MSDU */ -#define B43_TX4_MAC_SENDRTS 0x00000004 -#define B43_TX4_MAC_LONGFRAME 0x00000002 -#define B43_TX4_MAC_ACK 0x00000001 +#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */ +#define B43_TXH_MAC_KEYIDX 0x0FF00000 /* Security key index */ +#define B43_TXH_MAC_KEYIDX_SHIFT 20 +#define B43_TXH_MAC_KEYALG 0x00070000 /* Security key algorithm */ +#define B43_TXH_MAC_KEYALG_SHIFT 16 +#define B43_TXH_MAC_AMIC 0x00008000 /* AMIC */ +#define B43_TXH_MAC_RIFS 0x00004000 /* Use RIFS */ +#define B43_TXH_MAC_LIFETIME 0x00002000 /* Lifetime */ +#define B43_TXH_MAC_FRAMEBURST 0x00001000 /* Frameburst */ +#define B43_TXH_MAC_SENDCTS 0x00000800 /* Send CTS-to-self */ +#define B43_TXH_MAC_AMPDU 0x00000600 /* AMPDU status */ +#define B43_TXH_MAC_AMPDU_MPDU 0x00000000 /* Regular MPDU, not an AMPDU */ +#define B43_TXH_MAC_AMPDU_FIRST 0x00000200 /* First MPDU or AMPDU */ +#define B43_TXH_MAC_AMPDU_INTER 0x00000400 /* Intermediate MPDU or AMPDU */ +#define B43_TXH_MAC_AMPDU_LAST 0x00000600 /* Last (or only) MPDU of AMPDU */ +#define B43_TXH_MAC_40MHZ 0x00000100 /* Use 40 MHz bandwidth */ +#define B43_TXH_MAC_5GHZ 0x00000080 /* 5GHz band */ +#define B43_TXH_MAC_DFCS 0x00000040 /* DFCS */ +#define B43_TXH_MAC_IGNPMQ 0x00000020 /* Ignore PMQ */ +#define B43_TXH_MAC_HWSEQ 0x00000010 /* Use Hardware Sequence Number */ +#define B43_TXH_MAC_STMSDU 0x00000008 /* Start MSDU */ +#define B43_TXH_MAC_SENDRTS 0x00000004 /* Send RTS */ +#define B43_TXH_MAC_LONGFRAME 0x00000002 /* Long frame */ +#define B43_TXH_MAC_ACK 0x00000001 /* Immediate ACK */ /* Extra Frame Types */ -#define B43_TX4_EFT_FBOFDM 0x0001 /* Data frame fallback rate type */ -#define B43_TX4_EFT_RTSOFDM 0x0004 /* RTS/CTS rate type */ -#define B43_TX4_EFT_RTSFBOFDM 0x0010 /* RTS/CTS fallback rate type */ +#define B43_TXH_EFT_FB 0x03 /* Data frame fallback encoding */ +#define B43_TXH_EFT_FB_CCK 0x00 /* CCK */ +#define B43_TXH_EFT_FB_OFDM 0x01 /* OFDM */ +#define B43_TXH_EFT_FB_EWC 0x02 /* EWC */ +#define B43_TXH_EFT_FB_N 0x03 /* N */ +#define B43_TXH_EFT_RTS 0x0C /* RTS/CTS encoding */ +#define B43_TXH_EFT_RTS_CCK 0x00 /* CCK */ +#define B43_TXH_EFT_RTS_OFDM 0x04 /* OFDM */ +#define B43_TXH_EFT_RTS_EWC 0x08 /* EWC */ +#define B43_TXH_EFT_RTS_N 0x0C /* N */ +#define B43_TXH_EFT_RTSFB 0x30 /* RTS/CTS fallback encoding */ +#define B43_TXH_EFT_RTSFB_CCK 0x00 /* CCK */ +#define B43_TXH_EFT_RTSFB_OFDM 0x10 /* OFDM */ +#define B43_TXH_EFT_RTSFB_EWC 0x20 /* EWC */ +#define B43_TXH_EFT_RTSFB_N 0x30 /* N */ /* PHY TX control word */ -#define B43_TX4_PHY_OFDM 0x0001 /* Data frame rate type */ -#define B43_TX4_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ -#define B43_TX4_PHY_ANT 0x03C0 /* Antenna selection */ -#define B43_TX4_PHY_ANT0 0x0000 /* Use antenna 0 */ -#define B43_TX4_PHY_ANT1 0x0100 /* Use antenna 1 */ -#define B43_TX4_PHY_ANTLAST 0x0300 /* Use last used antenna */ +#define B43_TXH_PHY_ENC 0x0003 /* Data frame encoding */ +#define B43_TXH_PHY_ENC_CCK 0x0000 /* CCK */ +#define B43_TXH_PHY_ENC_OFDM 0x0001 /* OFDM */ +#define B43_TXH_PHY_ENC_EWC 0x0002 /* EWC */ +#define B43_TXH_PHY_ENC_N 0x0003 /* N */ +#define B43_TXH_PHY_SHORTPRMBL 0x0010 /* Use short preamble */ +#define B43_TXH_PHY_ANT 0x03C0 /* Antenna selection */ +#define B43_TXH_PHY_ANT0 0x0000 /* Use antenna 0 */ +#define B43_TXH_PHY_ANT1 0x0040 /* Use antenna 1 */ +#define B43_TXH_PHY_ANT01AUTO 0x00C0 /* Use antenna 0/1 auto */ +#define B43_TXH_PHY_ANT2 0x0100 /* Use antenna 2 */ +#define B43_TXH_PHY_ANT3 0x0200 /* Use antenna 3 */ +#define B43_TXH_PHY_TXPWR 0xFC00 /* TX power */ +#define B43_TXH_PHY_TXPWR_SHIFT 10 + +/* PHY TX control word 1 */ +#define B43_TXH_PHY1_BW 0x0007 /* Bandwidth */ +#define B43_TXH_PHY1_BW_10 0x0000 /* 10 MHz */ +#define B43_TXH_PHY1_BW_10U 0x0001 /* 10 MHz upper */ +#define B43_TXH_PHY1_BW_20 0x0002 /* 20 MHz */ +#define B43_TXH_PHY1_BW_20U 0x0003 /* 20 MHz upper */ +#define B43_TXH_PHY1_BW_40 0x0004 /* 40 MHz */ +#define B43_TXH_PHY1_BW_40DUP 0x0005 /* 50 MHz duplicate */ +#define B43_TXH_PHY1_MODE 0x0038 /* Mode */ +#define B43_TXH_PHY1_MODE_SISO 0x0000 /* SISO */ +#define B43_TXH_PHY1_MODE_CDD 0x0008 /* CDD */ +#define B43_TXH_PHY1_MODE_STBC 0x0010 /* STBC */ +#define B43_TXH_PHY1_MODE_SDM 0x0018 /* SDM */ +#define B43_TXH_PHY1_CRATE 0x0700 /* Coding rate */ +#define B43_TXH_PHY1_CRATE_1_2 0x0000 /* 1/2 */ +#define B43_TXH_PHY1_CRATE_2_3 0x0100 /* 2/3 */ +#define B43_TXH_PHY1_CRATE_3_4 0x0200 /* 3/4 */ +#define B43_TXH_PHY1_CRATE_4_5 0x0300 /* 4/5 */ +#define B43_TXH_PHY1_CRATE_5_6 0x0400 /* 5/6 */ +#define B43_TXH_PHY1_CRATE_7_8 0x0600 /* 7/8 */ +#define B43_TXH_PHY1_MODUL 0x3800 /* Modulation scheme */ +#define B43_TXH_PHY1_MODUL_BPSK 0x0000 /* BPSK */ +#define B43_TXH_PHY1_MODUL_QPSK 0x0800 /* QPSK */ +#define B43_TXH_PHY1_MODUL_QAM16 0x1000 /* QAM16 */ +#define B43_TXH_PHY1_MODUL_QAM64 0x1800 /* QAM64 */ +#define B43_TXH_PHY1_MODUL_QAM256 0x2000 /* QAM256 */ + + +/* r351 firmware compatibility stuff. */ +static inline +bool b43_is_old_txhdr_format(struct b43_wldev *dev) +{ + return (dev->fw.rev <= 351); +} + +static inline +size_t b43_txhdr_size(struct b43_wldev *dev) +{ + if (b43_is_old_txhdr_format(dev)) + return 100 + sizeof(struct b43_plcp_hdr6); + return 104 + sizeof(struct b43_plcp_hdr6); +} + void b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 7e23ec23fc98..6745579ba96d 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -34,6 +34,22 @@ config B43LEGACY_PCICORE_AUTOSELECT select SSB_DRIVER_PCICORE default y +# LED support +# This config option automatically enables b43legacy LEDS support, +# if it's possible. +config B43LEGACY_LEDS + bool + depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) + default y + +# RFKILL support +# This config option automatically enables b43legacy RFKILL support, +# if it's possible. +config B43LEGACY_RFKILL + bool + depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) + default y + config B43LEGACY_DEBUG bool "Broadcom 43xx-legacy debugging" depends on B43LEGACY diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index ec3a2482bbad..80cdb73bd140 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -1,14 +1,19 @@ -obj-$(CONFIG_B43LEGACY) += b43legacy.o -b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o +# b43legacy core +b43legacy-y += main.o +b43legacy-y += ilt.o +b43legacy-y += phy.o +b43legacy-y += radio.o +b43legacy-y += sysfs.o +b43legacy-y += xmit.o +# b43 RFKILL button support +b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o +# b43legacy LED support +b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o +# b43legacy debugging +b43legacy-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o +# b43legacy DMA and PIO +b43legacy-$(CONFIG_B43LEGACY_DMA) += dma.o +b43legacy-$(CONFIG_B43LEGACY_PIO) += pio.o -b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o -b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o +obj-$(CONFIG_B43LEGACY) += b43legacy.o -b43legacy-objs := main.o \ - ilt.o \ - leds.o \ - phy.o \ - radio.o \ - sysfs.o \ - xmit.o \ - $(b43legacy-obj-y) diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index afe145cec067..93419adb925e 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -19,6 +19,7 @@ #include "debugfs.h" #include "leds.h" +#include "rfkill.h" #include "phy.h" @@ -275,6 +276,8 @@ #define B43legacy_DEFAULT_SHORT_RETRY_LIMIT 7 #define B43legacy_DEFAULT_LONG_RETRY_LIMIT 4 +#define B43legacy_PHY_TX_BADNESS_LIMIT 1000 + /* Max size of a security key */ #define B43legacy_SEC_KEYSIZE 16 /* Security algorithms. */ @@ -412,7 +415,6 @@ struct b43legacy_phy { u8 calibrated:1; u8 radio_rev; /* Radio revision */ - bool locked; /* Only used in b43legacy_phy_{un}lock() */ bool dyn_tssi_tbl; /* tssi2dbm is kmalloc()ed. */ /* ACI (adjacent channel interference) flags. */ @@ -455,11 +457,6 @@ struct b43legacy_phy { s16 lna_gain; /* LNA */ s16 pga_gain; /* PGA */ - /* PHY lock for core.rev < 3 - * This lock is only used by b43legacy_phy_{un}lock() - */ - spinlock_t lock; - /* Desired TX power level (in dBm). This is set by the user and * adjusted in b43legacy_phy_xmitpower(). */ u8 power_level; @@ -483,9 +480,6 @@ struct b43legacy_phy { u16 txpwr_offset; }; -#ifdef CONFIG_B43LEGACY_DEBUG - bool manual_txpower_control; /* Manual TX-power control enabled? */ -#endif /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code. @@ -510,6 +504,16 @@ struct b43legacy_phy { u16 lofcal; u16 initval; + + /* PHY TX errors counter. */ + atomic_t txerr_cnt; + +#if B43legacy_DEBUG + /* Manual TX-power control enabled? */ + bool manual_txpower_control; + /* PHY registers locked by b43legacy_phy_lock()? */ + bool phy_locked; +#endif /* B43legacy_DEBUG */ }; /* Data structures for DMA transmission, per 80211 core. */ @@ -571,10 +575,7 @@ struct b43legacy_wl { * at a time. General information about this interface follows. */ - /* Opaque ID of the operating interface from the ieee80211 - * subsystem. Do not modify. - */ - int if_id; + struct ieee80211_vif *vif; /* MAC address (can be NULL). */ u8 mac_addr[ETH_ALEN]; /* Current BSSID (can be NULL). */ @@ -592,9 +593,14 @@ struct b43legacy_wl { u8 rng_initialized; char rng_name[30 + 1]; + /* The RF-kill button */ + struct b43legacy_rfkill rfkill; + /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; + + bool radiotap_enabled; }; /* Pointers to the firmware data and meta information about it. */ @@ -663,8 +669,11 @@ struct b43legacy_wldev { /* Various statistics about the physical device. */ struct b43legacy_stats stats; -#define B43legacy_NR_LEDS 4 - struct b43legacy_led leds[B43legacy_NR_LEDS]; + /* The device LEDs. */ + struct b43legacy_led led_tx; + struct b43legacy_led led_rx; + struct b43legacy_led led_assoc; + struct b43legacy_led led_radio; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 619b4534ef09..03ce0821a60e 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -209,7 +209,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, struct b43legacy_wldev *dev; struct b43legacy_debugfs_fops *dfops; struct b43legacy_dfs_file *dfile; - ssize_t ret = 0; + ssize_t uninitialized_var(ret); char *buf; const size_t bufsize = 1024 * 128; const size_t buforder = get_order(bufsize); diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c index 247fc780ffdb..a849078aea69 100644 --- a/drivers/net/wireless/b43legacy/ilt.c +++ b/drivers/net/wireless/b43legacy/ilt.c @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index a584ea810502..cacb786d9713 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -1,13 +1,13 @@ /* - Broadcom B43legacy wireless driver + Broadcom B43 wireless driver + LED control Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> - Michael Buesch <mb@bu3sch.de> - Danny van Dyk <kugelfang@gentoo.org> - Andreas Jaggi <andreas.jaggi@waterwave.ch> - Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> + Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> + Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> + Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 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 @@ -26,273 +26,216 @@ */ -#include "leds.h" #include "b43legacy.h" -#include "main.h" - -static void b43legacy_led_changestate(struct b43legacy_led *led) -{ - struct b43legacy_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; +#include "leds.h" - B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); - B43legacy_WARN_ON(!led->blink_interval); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - ledctl ^= (1 << index); - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); -} -static void b43legacy_led_blink(unsigned long d) +static void b43legacy_led_turn_on(struct b43legacy_wldev *dev, u8 led_index, + bool activelow) { - struct b43legacy_led *led = (struct b43legacy_led *)d; - struct b43legacy_wldev *dev = led->dev; + struct b43legacy_wl *wl = dev->wl; unsigned long flags; + u16 ctl; - spin_lock_irqsave(&dev->wl->leds_lock, flags); - if (led->blink_interval) { - b43legacy_led_changestate(led); - mod_timer(&led->blink_timer, jiffies + led->blink_interval); - } - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + if (activelow) + ctl &= ~(1 << led_index); + else + ctl |= (1 << led_index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43legacy_led_blink_start(struct b43legacy_led *led, - unsigned long interval) +static void b43legacy_led_turn_off(struct b43legacy_wldev *dev, u8 led_index, + bool activelow) { - if (led->blink_interval) - return; - led->blink_interval = interval; - b43legacy_led_changestate(led); - led->blink_timer.expires = jiffies + interval; - add_timer(&led->blink_timer); + struct b43legacy_wl *wl = dev->wl; + unsigned long flags; + u16 ctl; + + spin_lock_irqsave(&wl->leds_lock, flags); + ctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); + if (activelow) + ctl |= (1 << led_index); + else + ctl &= ~(1 << led_index); + b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ctl); + spin_unlock_irqrestore(&wl->leds_lock, flags); } -static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync) +/* Callback from the LED subsystem. */ +static void b43legacy_led_brightness_set(struct led_classdev *led_dev, + enum led_brightness brightness) { + struct b43legacy_led *led = container_of(led_dev, struct b43legacy_led, + led_dev); struct b43legacy_wldev *dev = led->dev; - const int index = led->index; - u16 ledctl; + bool radio_enabled; - if (!led->blink_interval) - return; - if (unlikely(sync)) - del_timer_sync(&led->blink_timer); - else - del_timer(&led->blink_timer); - led->blink_interval = 0; + /* Checking the radio-enabled status here is slightly racy, + * but we want to avoid the locking overhead and we don't care + * whether the LED has the wrong state for a second. */ + radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); - /* Make sure the LED is turned off. */ - B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - if (led->activelow) - ledctl |= (1 << index); + if (brightness == LED_OFF || !radio_enabled) + b43legacy_led_turn_off(dev, led->index, led->activelow); else - ledctl &= ~(1 << index); - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); + b43legacy_led_turn_on(dev, led->index, led->activelow); } -static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev, - struct b43legacy_led *led, - int led_index) +static int b43legacy_register_led(struct b43legacy_wldev *dev, + struct b43legacy_led *led, + const char *name, char *default_trigger, + u8 led_index, bool activelow) { - struct ssb_bus *bus = dev->dev->bus; + int err; + + b43legacy_led_turn_off(dev, led_index, activelow); + if (led->dev) + return -EEXIST; + if (!default_trigger) + return -EINVAL; + led->dev = dev; + led->index = led_index; + led->activelow = activelow; + strncpy(led->name, name, sizeof(led->name)); + + led->led_dev.name = led->name; + led->led_dev.default_trigger = default_trigger; + led->led_dev.brightness_set = b43legacy_led_brightness_set; + + err = led_classdev_register(dev->dev->dev, &led->led_dev); + if (err) { + b43legacywarn(dev->wl, "LEDs: Failed to register %s\n", name); + led->dev = NULL; + return err; + } + return 0; +} - /* This function is called, if the behaviour (and activelow) - * information for a LED is missing in the SPROM. - * We hardcode the behaviour values for various devices here. - * Note that the B43legacy_LED_TEST_XXX behaviour values can - * be used to figure out which led is mapped to which index. - */ +static void b43legacy_unregister_led(struct b43legacy_led *led) +{ + if (!led->dev) + return; + led_classdev_unregister(&led->led_dev); + b43legacy_led_turn_off(led->dev, led->index, led->activelow); + led->dev = NULL; +} + +static void b43legacy_map_led(struct b43legacy_wldev *dev, + u8 led_index, + enum b43legacy_led_behaviour behaviour, + bool activelow) +{ + struct ieee80211_hw *hw = dev->wl->hw; + char name[B43legacy_LED_MAX_NAME_LEN + 1]; - switch (led_index) { - case 0: - led->behaviour = B43legacy_LED_ACTIVITY; - led->activelow = 1; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = B43legacy_LED_RADIO_ALL; + /* Map the b43 specific LED behaviour value to the + * generic LED triggers. */ + switch (behaviour) { + case B43legacy_LED_INACTIVE: break; - case 1: - led->behaviour = B43legacy_LED_RADIO_B; - if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) - led->behaviour = B43legacy_LED_ASSOC; + case B43legacy_LED_OFF: + b43legacy_led_turn_off(dev, led_index, activelow); break; - case 2: - led->behaviour = B43legacy_LED_RADIO_A; + case B43legacy_LED_ON: + b43legacy_led_turn_on(dev, led_index, activelow); break; - case 3: - led->behaviour = B43legacy_LED_OFF; + case B43legacy_LED_ACTIVITY: + case B43legacy_LED_TRANSFER: + case B43legacy_LED_APTRANSFER: + snprintf(name, sizeof(name), + "b43legacy-%s:tx", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_tx, name, + ieee80211_get_tx_led_name(hw), + led_index, activelow); + snprintf(name, sizeof(name), + "b43legacy-%s:rx", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_rx, name, + ieee80211_get_rx_led_name(hw), + led_index, activelow); + break; + case B43legacy_LED_RADIO_ALL: + case B43legacy_LED_RADIO_A: + case B43legacy_LED_RADIO_B: + case B43legacy_LED_MODE_BG: + snprintf(name, sizeof(name), + "b43legacy-%s:radio", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_radio, name, + b43legacy_rfkill_led_name(dev), + led_index, activelow); + /* Sync the RF-kill LED state with the switch state. */ + if (dev->radio_hw_enable) + b43legacy_led_turn_on(dev, led_index, activelow); + break; + case B43legacy_LED_WEIRD: + case B43legacy_LED_ASSOC: + snprintf(name, sizeof(name), + "b43legacy-%s:assoc", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_assoc, name, + ieee80211_get_assoc_led_name(hw), + led_index, activelow); break; default: - B43legacy_BUG_ON(1); + b43legacywarn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n", + behaviour); + break; } } -int b43legacy_leds_init(struct b43legacy_wldev *dev) +void b43legacy_leds_init(struct b43legacy_wldev *dev) { - struct b43legacy_led *led; + struct ssb_bus *bus = dev->dev->bus; u8 sprom[4]; int i; - - sprom[0] = dev->dev->bus->sprom.r1.gpio0; - sprom[1] = dev->dev->bus->sprom.r1.gpio1; - sprom[2] = dev->dev->bus->sprom.r1.gpio2; - sprom[3] = dev->dev->bus->sprom.r1.gpio3; - - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - led->index = i; - led->dev = dev; - setup_timer(&led->blink_timer, - b43legacy_led_blink, - (unsigned long)led); - - if (sprom[i] == 0xFF) - b43legacy_led_init_hardcoded(dev, led, i); - else { - led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; - led->activelow = !!(sprom[i] & - B43legacy_LED_ACTIVELOW); + enum b43legacy_led_behaviour behaviour; + bool activelow; + + sprom[0] = bus->sprom.gpio0; + sprom[1] = bus->sprom.gpio1; + sprom[2] = bus->sprom.gpio2; + sprom[3] = bus->sprom.gpio3; + + for (i = 0; i < 4; i++) { + if (sprom[i] == 0xFF) { + /* There is no LED information in the SPROM + * for this LED. Hardcode it here. */ + activelow = 0; + switch (i) { + case 0: + behaviour = B43legacy_LED_ACTIVITY; + activelow = 1; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) + behaviour = B43legacy_LED_RADIO_ALL; + break; + case 1: + behaviour = B43legacy_LED_RADIO_B; + if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) + behaviour = B43legacy_LED_ASSOC; + break; + case 2: + behaviour = B43legacy_LED_RADIO_A; + break; + case 3: + behaviour = B43legacy_LED_OFF; + break; + default: + B43legacy_WARN_ON(1); + return; + } + } else { + behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; + activelow = !!(sprom[i] & B43legacy_LED_ACTIVELOW); } + b43legacy_map_led(dev, i, behaviour, activelow); } - - return 0; } void b43legacy_leds_exit(struct b43legacy_wldev *dev) { - struct b43legacy_led *led; - int i; - - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - b43legacy_led_blink_stop(led, 1); - } - b43legacy_leds_switch_all(dev, 0); -} - -void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) -{ - struct b43legacy_led *led; - struct b43legacy_phy *phy = &dev->phy; - const int transferring = (jiffies - dev->stats.last_tx) - < B43legacy_LED_XFER_THRES; - int i; - int turn_on; - unsigned long interval = 0; - u16 ledctl; - unsigned long flags; - bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - - turn_on = 0; - switch (led->behaviour) { - case B43legacy_LED_INACTIVE: - continue; - case B43legacy_LED_OFF: - break; - case B43legacy_LED_ON: - turn_on = 1; - break; - case B43legacy_LED_ACTIVITY: - turn_on = activity; - break; - case B43legacy_LED_RADIO_ALL: - turn_on = radio_enabled; - break; - case B43legacy_LED_RADIO_A: - break; - case B43legacy_LED_RADIO_B: - turn_on = radio_enabled; - break; - case B43legacy_LED_MODE_BG: - if (phy->type == B43legacy_PHYTYPE_G && radio_enabled) - turn_on = 1; - break; - case B43legacy_LED_TRANSFER: - if (transferring) - b43legacy_led_blink_start(led, - B43legacy_LEDBLINK_MEDIUM); - else - b43legacy_led_blink_stop(led, 0); - continue; - case B43legacy_LED_APTRANSFER: - if (b43legacy_is_mode(dev->wl, - IEEE80211_IF_TYPE_AP)) { - if (transferring) { - interval = B43legacy_LEDBLINK_FAST; - turn_on = 1; - } - } else { - turn_on = 1; - if (transferring) - interval = B43legacy_LEDBLINK_FAST; - else - turn_on = 0; - } - if (turn_on) - b43legacy_led_blink_start(led, interval); - else - b43legacy_led_blink_stop(led, 0); - continue; - case B43legacy_LED_WEIRD: - break; - case B43legacy_LED_ASSOC: - turn_on = 1; -#ifdef CONFIG_B43LEGACY_DEBUG - case B43legacy_LED_TEST_BLINKSLOW: - b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW); - continue; - case B43legacy_LED_TEST_BLINKMEDIUM: - b43legacy_led_blink_start(led, - B43legacy_LEDBLINK_MEDIUM); - continue; - case B43legacy_LED_TEST_BLINKFAST: - b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST); - continue; -#endif /* CONFIG_B43LEGACY_DEBUG */ - default: - B43legacy_BUG_ON(1); - }; - - if (led->activelow) - turn_on = !turn_on; - if (turn_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); -} - -void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on) -{ - struct b43legacy_led *led; - u16 ledctl; - int i; - int bit_on; - unsigned long flags; - - spin_lock_irqsave(&dev->wl->leds_lock, flags); - ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); - for (i = 0; i < B43legacy_NR_LEDS; i++) { - led = &(dev->leds[i]); - if (led->behaviour == B43legacy_LED_INACTIVE) - continue; - if (on) - bit_on = led->activelow ? 0 : 1; - else - bit_on = led->activelow ? 1 : 0; - if (bit_on) - ledctl |= (1 << i); - else - ledctl &= ~(1 << i); - } - b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); - spin_unlock_irqrestore(&dev->wl->leds_lock, flags); + b43legacy_unregister_led(&dev->led_tx); + b43legacy_unregister_led(&dev->led_rx); + b43legacy_unregister_led(&dev->led_assoc); + b43legacy_unregister_led(&dev->led_radio); } diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h index b989f503e684..82167a90088f 100644 --- a/drivers/net/wireless/b43legacy/leds.h +++ b/drivers/net/wireless/b43legacy/leds.h @@ -1,30 +1,33 @@ #ifndef B43legacy_LEDS_H_ #define B43legacy_LEDS_H_ +struct b43legacy_wldev; + +#ifdef CONFIG_B43LEGACY_LEDS + #include <linux/types.h> -#include <linux/timer.h> +#include <linux/leds.h> +#define B43legacy_LED_MAX_NAME_LEN 31 + struct b43legacy_led { - u8 behaviour; - bool activelow; - /* Index in the "leds" array in b43legacy_wldev */ - u8 index; struct b43legacy_wldev *dev; - struct timer_list blink_timer; - unsigned long blink_interval; + /* The LED class device */ + struct led_classdev led_dev; + /* The index number of the LED. */ + u8 index; + /* If activelow is true, the LED is ON if the + * bit is switched off. */ + bool activelow; + /* The unique name string for this LED device. */ + char name[B43legacy_LED_MAX_NAME_LEN + 1]; }; -/* Delay between state changes when blinking in jiffies */ -#define B43legacy_LEDBLINK_SLOW (HZ / 1) -#define B43legacy_LEDBLINK_MEDIUM (HZ / 4) -#define B43legacy_LEDBLINK_FAST (HZ / 8) - -#define B43legacy_LED_XFER_THRES (HZ / 100) - #define B43legacy_LED_BEHAVIOUR 0x7F #define B43legacy_LED_ACTIVELOW 0x80 -enum { /* LED behaviour values */ +/* LED behaviour values */ +enum b43legacy_led_behaviour { B43legacy_LED_OFF, B43legacy_LED_ON, B43legacy_LED_ACTIVITY, @@ -37,20 +40,24 @@ enum { /* LED behaviour values */ B43legacy_LED_WEIRD, B43legacy_LED_ASSOC, B43legacy_LED_INACTIVE, - - /* Behaviour values for testing. - * With these values it is easier to figure out - * the real behaviour of leds, in case the SPROM - * is missing information. - */ - B43legacy_LED_TEST_BLINKSLOW, - B43legacy_LED_TEST_BLINKMEDIUM, - B43legacy_LED_TEST_BLINKFAST, }; -int b43legacy_leds_init(struct b43legacy_wldev *dev); +void b43legacy_leds_init(struct b43legacy_wldev *dev); void b43legacy_leds_exit(struct b43legacy_wldev *dev); -void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity); -void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on); + +#else /* CONFIG_B43EGACY_LEDS */ +/* LED support disabled */ + +struct b43legacy_led { + /* empty */ +}; + +static inline void b43legacy_leds_init(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_leds_exit(struct b43legacy_wldev *dev) +{ +} +#endif /* CONFIG_B43LEGACY_LEDS */ #endif /* B43legacy_LEDS_H_ */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 32d5e1785bda..4ed4243feeaa 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3,7 +3,7 @@ * Broadcom B43legacy wireless driver * * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> - * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + * Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -75,18 +75,6 @@ module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames" " Preemption"); -static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT; -module_param_named(short_retry, modparam_short_retry, int, 0444); -MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); - -static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT; -module_param_named(long_retry, modparam_long_retry, int, 0444); -MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); - -static int modparam_noleds; -module_param_named(noleds, modparam_noleds, int, 0444); -MODULE_PARM_DESC(noleds, "Turn off all LED activity"); - static char modparam_fwpostfix[16]; module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); @@ -988,7 +976,7 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, plcp.data = 0; b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + dev->wl->vif, size, B43legacy_RATE_TO_100KBPS(rate)); /* Write PLCP in two parts and timing for packet transfer */ @@ -1054,7 +1042,7 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + dev->wl->vif, *dest_size, B43legacy_RATE_TO_100KBPS(rate)); hdr->duration_id = dur; @@ -1217,7 +1205,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; u32 merged_dma_reason = 0; int i; - int activity = 0; unsigned long flags; spin_lock_irqsave(&dev->wl->irq_lock, flags); @@ -1234,8 +1221,15 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) if (unlikely(reason & B43legacy_IRQ_MAC_TXERR)) b43legacyerr(dev->wl, "MAC transmission error\n"); - if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) + if (unlikely(reason & B43legacy_IRQ_PHY_TXERR)) { b43legacyerr(dev->wl, "PHY transmission error\n"); + rmb(); + if (unlikely(atomic_dec_and_test(&dev->phy.txerr_cnt))) { + b43legacyerr(dev->wl, "Too many PHY TX errors, " + "restarting the controller\n"); + b43legacy_controller_restart(dev, "PHY TX errors"); + } + } if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK | B43legacy_DMAIRQ_NONFATALMASK))) { @@ -1281,7 +1275,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) b43legacy_pio_rx(dev->pio.queue0); else b43legacy_dma_rx(dev->dma.rx_ring0); - /* We intentionally don't set "activity" to 1, here. */ } B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE); @@ -1290,20 +1283,13 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev) b43legacy_pio_rx(dev->pio.queue3); else b43legacy_dma_rx(dev->dma.rx_ring3); - activity = 1; } B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE); B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE); - if (reason & B43legacy_IRQ_TX_OK) { + if (reason & B43legacy_IRQ_TX_OK) handle_irq_transmit_status(dev); - activity = 1; - /* TODO: In AP mode, this also causes sending of powersave - responses. */ - } - if (!modparam_noleds) - b43legacy_leds_update(dev, activity); b43legacy_interrupt_enable(dev, dev->irq_savedstate); mmiowb(); spin_unlock_irqrestore(&dev->wl->irq_lock, flags); @@ -1755,7 +1741,6 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) B43legacy_MMIO_STATUS_BITFIELD) & 0xFFFF3FFF); - b43legacy_leds_switch_all(dev, 0); b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, b43legacy_read16(dev, B43legacy_MMIO_GPIO_MASK) @@ -1767,7 +1752,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) mask |= 0x0060; set |= 0x0060; } - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) { b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK, b43legacy_read16(dev, B43legacy_MMIO_GPIO_MASK) @@ -1811,6 +1796,7 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) { dev->mac_suspended--; B43legacy_WARN_ON(dev->mac_suspended < 0); + B43legacy_WARN_ON(irqs_disabled()); if (dev->mac_suspended == 0) { b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, b43legacy_read32(dev, @@ -1822,6 +1808,11 @@ void b43legacy_mac_enable(struct b43legacy_wldev *dev) b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); b43legacy_power_saving_ctl_bits(dev, -1, -1); + + /* Re-enable IRQs. */ + spin_lock_irq(&dev->wl->irq_lock); + b43legacy_interrupt_enable(dev, dev->irq_savedstate); + spin_unlock_irq(&dev->wl->irq_lock); } } @@ -1831,20 +1822,31 @@ void b43legacy_mac_suspend(struct b43legacy_wldev *dev) int i; u32 tmp; + might_sleep(); + B43legacy_WARN_ON(irqs_disabled()); B43legacy_WARN_ON(dev->mac_suspended < 0); + if (dev->mac_suspended == 0) { + /* Mask IRQs before suspending MAC. Otherwise + * the MAC stays busy and won't suspend. */ + spin_lock_irq(&dev->wl->irq_lock); + tmp = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irq(&dev->wl->irq_lock); + b43legacy_synchronize_irq(dev); + dev->irq_savedstate = tmp; + b43legacy_power_saving_ctl_bits(dev, -1, 1); b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) & ~B43legacy_SBF_MAC_ENABLED); b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); - for (i = 10000; i; i--) { + for (i = 40; i; i--) { tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON); if (tmp & B43legacy_IRQ_MAC_SUSPENDED) goto out; - udelay(1); + msleep(1); } b43legacyerr(dev->wl, "MAC suspend failed\n"); } @@ -1989,27 +1991,10 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, B43legacy_SHM_SH_PRPHYCTL, tmp); } -/* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) -{ - if (dev->phy.rev >= 3) { - if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; -} - /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { - b43legacy_radio_turn_off(dev); - if (!modparam_noleds) - b43legacy_leds_exit(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_gpio_cleanup(dev); /* firmware is released later */ } @@ -2039,9 +2024,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) err = b43legacy_gpio_init(dev); if (err) goto out; /* firmware is released later */ + err = b43legacy_upload_initvals(dev); if (err) - goto err_gpio_cleanup; + goto err_gpio_clean; b43legacy_radio_turn_on(dev); b43legacy_write16(dev, 0x03E6, 0x0000); @@ -2113,14 +2099,17 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev) b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY, dev->dev->bus->chipco.fast_pwrup_delay); + /* PHY TX errors counter. */ + atomic_set(&phy->txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT); + B43legacy_WARN_ON(err != 0); b43legacydbg(dev->wl, "Chip initialized\n"); out: return err; err_radio_off: - b43legacy_radio_turn_off(dev); -err_gpio_cleanup: + b43legacy_radio_turn_off(dev, 1); +err_gpio_clean: b43legacy_gpio_cleanup(dev); goto out; } @@ -2140,7 +2129,7 @@ static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev) { b43legacy_phy_lo_mark_all_unused(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_mac_suspend(dev); b43legacy_calc_nrssi_slope(dev); b43legacy_mac_enable(dev); @@ -2156,20 +2145,9 @@ static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev) static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) { b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */ -} - -static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) -{ - bool radio_hw_enable; - /* check if radio hardware enabled status changed */ - radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); - if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { - dev->radio_hw_enable = radio_hw_enable; - b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable) ? "enabled" : "disabled"); - b43legacy_leds_update(dev, 0); - } + atomic_set(&dev->phy.txerr_cnt, B43legacy_PHY_TX_BADNESS_LIMIT); + wmb(); } static void do_periodic_work(struct b43legacy_wldev *dev) @@ -2177,94 +2155,45 @@ static void do_periodic_work(struct b43legacy_wldev *dev) unsigned int state; state = dev->periodic_state; - if (state % 120 == 0) + if (state % 8 == 0) b43legacy_periodic_every120sec(dev); - if (state % 60 == 0) + if (state % 4 == 0) b43legacy_periodic_every60sec(dev); - if (state % 30 == 0) + if (state % 2 == 0) b43legacy_periodic_every30sec(dev); - if (state % 15 == 0) - b43legacy_periodic_every15sec(dev); - b43legacy_periodic_every1sec(dev); + b43legacy_periodic_every15sec(dev); } -/* Estimate a "Badness" value based on the periodic work - * state-machine state. "Badness" is worse (bigger), if the - * periodic work will take longer. +/* Periodic work locking policy: + * The whole periodic work handler is protected by + * wl->mutex. If another lock is needed somewhere in the + * pwork callchain, it's aquired in-place, where it's needed. */ -static int estimate_periodic_work_badness(unsigned int state) -{ - int badness = 0; - - if (state % 120 == 0) /* every 120 sec */ - badness += 10; - if (state % 60 == 0) /* every 60 sec */ - badness += 5; - if (state % 30 == 0) /* every 30 sec */ - badness += 1; - if (state % 15 == 0) /* every 15 sec */ - badness += 1; - -#define BADNESS_LIMIT 4 - return badness; -} - static void b43legacy_periodic_work_handler(struct work_struct *work) { - struct b43legacy_wldev *dev = - container_of(work, struct b43legacy_wldev, - periodic_work.work); - unsigned long flags; + struct b43legacy_wldev *dev = container_of(work, struct b43legacy_wldev, + periodic_work.work); + struct b43legacy_wl *wl = dev->wl; unsigned long delay; - u32 savedirqs = 0; - int badness; - mutex_lock(&dev->wl->mutex); + mutex_lock(&wl->mutex); if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED)) goto out; if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP)) goto out_requeue; - badness = estimate_periodic_work_badness(dev->periodic_state); - if (badness > BADNESS_LIMIT) { - spin_lock_irqsave(&dev->wl->irq_lock, flags); - /* Suspend TX as we don't want to transmit packets while - * we recalibrate the hardware. */ - b43legacy_tx_suspend(dev); - savedirqs = b43legacy_interrupt_disable(dev, - B43legacy_IRQ_ALL); - /* Periodic work will take a long time, so we want it to - * be preemtible and release the spinlock. */ - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - b43legacy_synchronize_irq(dev); - - do_periodic_work(dev); + do_periodic_work(dev); - spin_lock_irqsave(&dev->wl->irq_lock, flags); - b43legacy_interrupt_enable(dev, savedirqs); - b43legacy_tx_resume(dev); - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } else { - /* Take the global driver lock. This will lock any operation. */ - spin_lock_irqsave(&dev->wl->irq_lock, flags); - - do_periodic_work(dev); - - mmiowb(); - spin_unlock_irqrestore(&dev->wl->irq_lock, flags); - } dev->periodic_state++; out_requeue: if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else - delay = round_jiffies_relative(HZ); - queue_delayed_work(dev->wl->hw->workqueue, - &dev->periodic_work, delay); + delay = round_jiffies_relative(HZ * 15); + queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay); out: - mutex_unlock(&dev->wl->mutex); + mutex_unlock(&wl->mutex); } static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev) @@ -2366,9 +2295,9 @@ static int b43legacy_rng_init(struct b43legacy_wl *wl) return err; } -static int b43legacy_tx(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_control *ctl) +static int b43legacy_op_tx(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_control *ctl) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2392,15 +2321,15 @@ out: return NETDEV_TX_OK; } -static int b43legacy_conf_tx(struct ieee80211_hw *hw, - int queue, - const struct ieee80211_tx_queue_params *params) +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, + int queue, + const struct ieee80211_tx_queue_params *params) { return 0; } -static int b43legacy_get_tx_stats(struct ieee80211_hw *hw, - struct ieee80211_tx_queue_stats *stats) +static int b43legacy_op_get_tx_stats(struct ieee80211_hw *hw, + struct ieee80211_tx_queue_stats *stats) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2422,8 +2351,8 @@ out: return err; } -static int b43legacy_get_stats(struct ieee80211_hw *hw, - struct ieee80211_low_level_stats *stats) +static int b43legacy_op_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); unsigned long flags; @@ -2572,8 +2501,8 @@ static int b43legacy_antenna_from_ieee80211(u8 antenna) } } -static int b43legacy_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int b43legacy_op_dev_config(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -2634,6 +2563,8 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, b43legacy_short_slot_timing_disable(dev); } + dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + /* Adjust the desired TX power level. */ if (conf->power_level != 0) { if (conf->power_level != phy->power_level) { @@ -2660,7 +2591,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, " physically off. Press the" " button to turn it on.\n"); } else { - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 0); b43legacyinfo(dev->wl, "Radio turned off by" " software\n"); } @@ -2676,37 +2607,11 @@ out_unlock_mutex: return err; } -static int b43legacy_dev_set_key(struct ieee80211_hw *hw, - enum set_key_cmd cmd, - const u8 *local_addr, const u8 *addr, - struct ieee80211_key_conf *key) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev = wl->current_dev; - unsigned long flags; - int err = -EOPNOTSUPP; - DECLARE_MAC_BUF(mac); - - if (!dev) - return -ENODEV; - mutex_lock(&wl->mutex); - spin_lock_irqsave(&wl->irq_lock, flags); - - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { - err = -ENODEV; - } - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); - b43legacydbg(wl, "Using software based encryption for " - "mac: %s\n", print_mac(mac, addr)); - return err; -} - -static void b43legacy_configure_filter(struct ieee80211_hw *hw, - unsigned int changed, - unsigned int *fflags, - int mc_count, - struct dev_addr_list *mc_list) +static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed, + unsigned int *fflags, + int mc_count, + struct dev_addr_list *mc_list) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2741,9 +2646,9 @@ static void b43legacy_configure_filter(struct ieee80211_hw *hw, spin_unlock_irqrestore(&wl->irq_lock, flags); } -static int b43legacy_config_interface(struct ieee80211_hw *hw, - int if_id, - struct ieee80211_if_conf *conf) +static int b43legacy_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -2753,7 +2658,7 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw, return -ENODEV; mutex_lock(&wl->mutex); spin_lock_irqsave(&wl->irq_lock, flags); - B43legacy_WARN_ON(wl->if_id != if_id); + B43legacy_WARN_ON(wl->vif != vif); if (conf->bssid) memcpy(wl->bssid, conf->bssid, ETH_ALEN); else @@ -2942,8 +2847,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig)); memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos)); - /* Flags */ - phy->locked = 0; /* Assume the radio is enabled. If it's not enabled, the state will * immediately get fixed on the first periodic work run. */ dev->radio_hw_enable = 1; @@ -2976,7 +2879,6 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev, phy->lofcal = 0xFFFF; phy->initval = 0xFFFF; - spin_lock_init(&phy->lock); phy->interfmode = B43legacy_INTERFMODE_NONE; phy->channel = 0xFF; } @@ -3029,6 +2931,20 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } +/* Write the short and long frame retry limit values. */ +static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); +} + /* Shutdown a wireless core */ /* Locking: wl->mutex */ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) @@ -3047,11 +2963,12 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev) cancel_work_sync(&dev->restart_work); mutex_lock(&wl->mutex); + b43legacy_leds_exit(dev); b43legacy_rng_exit(dev->wl); b43legacy_pio_free(dev); b43legacy_dma_free(dev); b43legacy_chip_exit(dev); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); if (phy->dyn_tssi_tbl) kfree(phy->tssi2dbm); @@ -3093,7 +3010,6 @@ static void prepare_phy_data_for_init(struct b43legacy_wldev *dev) /* Flags */ phy->calibrated = 0; - phy->locked = 0; if (phy->_lo_pairs) memset(phy->_lo_pairs, 0, @@ -3153,7 +3069,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) hf |= B43legacy_HF_SYMW; if (phy->rev == 1) hf |= B43legacy_HF_GDCW; - if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL) + if (sprom->boardflags_lo & B43legacy_BFL_PACTRL) hf |= B43legacy_HF_OFDMPABOOST; } else if (phy->type == B43legacy_PHYTYPE_B) { hf |= B43legacy_HF_SYMW; @@ -3162,16 +3078,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) } b43legacy_hf_write(dev, hf); - /* Short/Long Retry Limit. - * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. - */ - tmp = limit_value(modparam_short_retry, 0, 0xF); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, - 0x0006, tmp); - tmp = limit_value(modparam_long_retry, 0, 0xF); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, - 0x0007, tmp); + b43legacy_set_retry_limits(dev, + B43legacy_DEFAULT_SHORT_RETRY_LIMIT, + B43legacy_DEFAULT_LONG_RETRY_LIMIT); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0044, 3); @@ -3223,6 +3132,7 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev) b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); + b43legacy_leds_init(dev); out: return err; @@ -3239,8 +3149,8 @@ err_kfree_lo_control: return err; } -static int b43legacy_add_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static int b43legacy_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; @@ -3263,7 +3173,7 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, dev = wl->current_dev; wl->operating = 1; - wl->if_id = conf->if_id; + wl->vif = conf->vif; wl->if_type = conf->type; memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); @@ -3279,8 +3189,8 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw, return err; } -static void b43legacy_remove_interface(struct ieee80211_hw *hw, - struct ieee80211_if_init_conf *conf) +static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; @@ -3291,7 +3201,8 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); B43legacy_WARN_ON(!wl->operating); - B43legacy_WARN_ON(wl->if_id != conf->if_id); + B43legacy_WARN_ON(wl->vif != conf->vif); + wl->vif = NULL; wl->operating = 0; @@ -3304,13 +3215,17 @@ static void b43legacy_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&wl->mutex); } -static int b43legacy_start(struct ieee80211_hw *hw) +static int b43legacy_op_start(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; int did_init = 0; int err = 0; + /* First register RFkill. + * LEDs that are registered later depend on it. */ + b43legacy_rfkill_init(dev); + mutex_lock(&wl->mutex); if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { @@ -3335,11 +3250,13 @@ out_mutex_unlock: return err; } -static void b43legacy_stop(struct ieee80211_hw *hw) +static void b43legacy_op_stop(struct ieee80211_hw *hw) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev = wl->current_dev; + b43legacy_rfkill_exit(dev); + mutex_lock(&wl->mutex); if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) b43legacy_wireless_core_stop(dev); @@ -3347,20 +3264,41 @@ static void b43legacy_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } +static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw, + u32 short_retry_limit, + u32 long_retry_limit) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + int err = 0; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (unlikely(!dev || + (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) { + err = -ENODEV; + goto out_unlock; + } + b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit); +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} static const struct ieee80211_ops b43legacy_hw_ops = { - .tx = b43legacy_tx, - .conf_tx = b43legacy_conf_tx, - .add_interface = b43legacy_add_interface, - .remove_interface = b43legacy_remove_interface, - .config = b43legacy_dev_config, - .config_interface = b43legacy_config_interface, - .set_key = b43legacy_dev_set_key, - .configure_filter = b43legacy_configure_filter, - .get_stats = b43legacy_get_stats, - .get_tx_stats = b43legacy_get_tx_stats, - .start = b43legacy_start, - .stop = b43legacy_stop, + .tx = b43legacy_op_tx, + .conf_tx = b43legacy_op_conf_tx, + .add_interface = b43legacy_op_add_interface, + .remove_interface = b43legacy_op_remove_interface, + .config = b43legacy_op_dev_config, + .config_interface = b43legacy_op_config_interface, + .configure_filter = b43legacy_op_configure_filter, + .get_stats = b43legacy_op_get_stats, + .get_tx_stats = b43legacy_op_get_tx_stats, + .start = b43legacy_op_start, + .stop = b43legacy_op_stop, + .set_retry_limit = b43legacy_op_set_retry_limit, }; /* Hard-reset the chip. Do not call this directly. @@ -3498,18 +3436,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) else have_bphy = 1; - /* Initialize LEDs structs. */ - err = b43legacy_leds_init(dev); - if (err) - goto err_powerdown; - dev->phy.gmode = (have_gphy || have_bphy); tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0; b43legacy_wireless_core_reset(dev, tmp); err = b43legacy_phy_versioning(dev); if (err) - goto err_leds_exit; + goto err_powerdown; /* Check if this device supports multiband. */ if (!pdev || (pdev->device != 0x4312 && @@ -3535,17 +3468,17 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) err = b43legacy_validate_chipaccess(dev); if (err) - goto err_leds_exit; + goto err_powerdown; err = b43legacy_setup_modes(dev, have_bphy, have_gphy); if (err) - goto err_leds_exit; + goto err_powerdown; /* Now set some default "current_dev" */ if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43legacy_chip_reset); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); @@ -3553,8 +3486,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) out: return err; -err_leds_exit: - b43legacy_leds_exit(dev); err_powerdown: ssb_bus_may_powerdown(bus); return err; @@ -3637,12 +3568,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus) if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) - bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL; - - /* Convert Antennagain values to Q5.2 */ - if (bus->sprom.r1.antenna_gain_bg == 0xFF) - bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */ - bus->sprom.r1.antenna_gain_bg <<= 2; + bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL; } static void b43legacy_wireless_exit(struct ssb_device *dev, @@ -3677,10 +3603,10 @@ static int b43legacy_wireless_init(struct ssb_device *dev) hw->max_noise = -110; hw->queues = 1; /* FIXME: hardware has more queues */ SET_IEEE80211_DEV(hw, dev->dev); - if (is_valid_ether_addr(sprom->r1.et1mac)) - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac); + if (is_valid_ether_addr(sprom->et1mac)) + SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); else - SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac); + SET_IEEE80211_PERM_ADDR(hw, sprom->il0mac); /* Get and initialize struct b43legacy_wl */ wl = hw_to_b43legacy_wl(hw); diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h index 68435c50d8e0..1f0e2e379b02 100644 --- a/drivers/net/wireless/b43legacy/main.h +++ b/drivers/net/wireless/b43legacy/main.h @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Copyright (c) 2005 Stefano Brivio <st3@riseup.net> + Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 491e518e4aeb..c16febbdbf5d 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -91,40 +91,36 @@ void b43legacy_voluntary_preempt(void) #endif /* CONFIG_PREEMPT */ } -void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev) +/* Lock the PHY registers against concurrent access from the microcode. + * This lock is nonrecursive. */ +void b43legacy_phy_lock(struct b43legacy_wldev *dev) { - struct b43legacy_phy *phy = &dev->phy; +#if B43legacy_DEBUG + B43legacy_WARN_ON(dev->phy.phy_locked); + dev->phy.phy_locked = 1; +#endif - B43legacy_WARN_ON(!irqs_disabled()); - if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) { - phy->locked = 0; - return; - } if (dev->dev->id.revision < 3) { b43legacy_mac_suspend(dev); - spin_lock(&phy->lock); } else { if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, 1); } - phy->locked = 1; } -void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev) +void b43legacy_phy_unlock(struct b43legacy_wldev *dev) { - struct b43legacy_phy *phy = &dev->phy; +#if B43legacy_DEBUG + B43legacy_WARN_ON(!dev->phy.phy_locked); + dev->phy.phy_locked = 0; +#endif - B43legacy_WARN_ON(!irqs_disabled()); if (dev->dev->id.revision < 3) { - if (phy->locked) { - spin_unlock(&phy->lock); - b43legacy_mac_enable(dev); - } + b43legacy_mac_enable(dev); } else { if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) b43legacy_power_saving_ctl_bits(dev, -1, -1); } - phy->locked = 0; } u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset) @@ -441,7 +437,7 @@ static void b43legacy_phy_inita(struct b43legacy_wldev *dev) might_sleep(); b43legacy_phy_setupg(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) b43legacy_phy_write(dev, 0x046E, 0x03CF); } @@ -543,7 +539,7 @@ static void b43legacy_phy_initb4(struct b43legacy_wldev *dev) if (phy->radio_ver == 0x2050) b43legacy_phy_write(dev, 0x002A, 0x88C2); b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_calc_nrssi_slope(dev); b43legacy_calc_nrssi_threshold(dev); } @@ -699,7 +695,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_radio_write16(dev, 0x005A, 0x0088); b43legacy_radio_write16(dev, 0x005B, 0x006B); b43legacy_radio_write16(dev, 0x005C, 0x000F); - if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) { + if (dev->dev->bus->sprom.boardflags_lo & 0x8000) { b43legacy_radio_write16(dev, 0x005D, 0x00FA); b43legacy_radio_write16(dev, 0x005E, 0x00D8); } else { @@ -797,7 +793,7 @@ static void b43legacy_phy_initb6(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0062, 0x0007); b43legacy_radio_init2050(dev); b43legacy_phy_lo_g_measure(dev); - if (dev->dev->bus->sprom.r1.boardflags_lo & + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { b43legacy_calc_nrssi_slope(dev); b43legacy_calc_nrssi_threshold(dev); @@ -921,7 +917,7 @@ static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev) b43legacy_phy_read(dev, 0x0811) | 0x0100); b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) & 0xCFFF); - if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) { + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) { if (phy->rev >= 7) { b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) @@ -1072,7 +1068,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0036, (b43legacy_phy_read(dev, 0x0036) & 0x0FFF) | (phy->txctl2 << 12)); - if (dev->dev->bus->sprom.r1.boardflags_lo & + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) b43legacy_phy_write(dev, 0x002E, 0x8075); else @@ -1087,7 +1083,7 @@ static void b43legacy_phy_initg(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x080F, 0x8078); } - if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) { + if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) { /* The specs state to update the NRSSI LT with * the value 0x7FFFFFFF here. I think that is some weird * compiler optimization in the original driver. @@ -1789,7 +1785,6 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) s16 baseband_att_delta; s16 radio_attenuation; s16 baseband_attenuation; - unsigned long phylock_flags; if (phy->savedpctlreg == 0xFFFF) return; @@ -1838,9 +1833,9 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) estimated_pwr = b43legacy_phy_estimate_power_out(dev, average); - max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg; + max_pwr = dev->dev->bus->sprom.maxpwr_bg; - if ((dev->dev->bus->sprom.r1.boardflags_lo + if ((dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) && (phy->type == B43legacy_PHYTYPE_G)) max_pwr -= 0x3; @@ -1848,7 +1843,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM." "\n"); max_pwr = 74; /* fake it */ - dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr; + dev->dev->bus->sprom.maxpwr_bg = max_pwr; } /* Use regulatory information to get the maximum power. @@ -1858,7 +1853,8 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) * and 1.5 dBm (a safety factor??). The result is in Q5.2 format * which accounts for the factor of 4 */ #define REG_MAX_PWR 20 - max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg + max_pwr = min(REG_MAX_PWR * 4 + - dev->dev->bus->sprom.antenna_gain.ghz24.a0 - 0x6, max_pwr); /* find the desired power in Q5.2 - power_level is in dBm @@ -1918,7 +1914,7 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) txpower = 3; radio_attenuation += 2; baseband_attenuation += 2; - } else if (dev->dev->bus->sprom.r1.boardflags_lo + } else if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_PACTRL) { baseband_attenuation += 4 * (radio_attenuation - 2); @@ -1943,13 +1939,13 @@ void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev) phy->bbatt = baseband_attenuation; /* Adjust the hardware */ - b43legacy_phy_lock(dev, phylock_flags); + b43legacy_phy_lock(dev); b43legacy_radio_lock(dev); b43legacy_radio_set_txpower_bg(dev, baseband_attenuation, radio_attenuation, txpower); b43legacy_phy_lo_mark_current_used(dev); b43legacy_radio_unlock(dev); - b43legacy_phy_unlock(dev, phylock_flags); + b43legacy_phy_unlock(dev); } static inline @@ -2000,9 +1996,9 @@ int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B || phy->type == B43legacy_PHYTYPE_G)); - pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0); - pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1); - pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2); + pab0 = (s16)(dev->dev->bus->sprom.pa0b0); + pab1 = (s16)(dev->dev->bus->sprom.pa0b1); + pab2 = (s16)(dev->dev->bus->sprom.pa0b2); if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) { phy->idle_tssi = 0x34; @@ -2013,9 +2009,10 @@ int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev) if (pab0 != 0 && pab1 != 0 && pab2 != 0 && pab0 != -1 && pab1 != -1 && pab2 != -1) { /* The pabX values are set in SPROM. Use them. */ - if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 && - (s8)dev->dev->bus->sprom.r1.itssi_bg != -1) - phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg); + if ((s8)dev->dev->bus->sprom.itssi_bg != 0 && + (s8)dev->dev->bus->sprom.itssi_bg != -1) + phy->idle_tssi = (s8)(dev->dev->bus->sprom. + itssi_bg); else phy->idle_tssi = 62; dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h index f11b4271714c..ecbe409f9a94 100644 --- a/drivers/net/wireless/b43legacy/phy.h +++ b/drivers/net/wireless/b43legacy/phy.h @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -171,18 +171,8 @@ void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt); struct b43legacy_wldev; -void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev); -#define b43legacy_phy_lock(bcm, flags) \ - do { \ - local_irq_save(flags); \ - b43legacy_raw_phy_lock(bcm); \ - } while (0) -void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev); -#define b43legacy_phy_unlock(bcm, flags) \ - do { \ - b43legacy_raw_phy_unlock(bcm); \ - local_irq_restore(flags); \ - } while (0) +void b43legacy_phy_lock(struct b43legacy_wldev *dev); +void b43legacy_phy_unlock(struct b43legacy_wldev *dev); /* Card uses the loopback gain stuff */ #define has_loopback_gain(phy) \ diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index a361dee664af..318a270cf9b4 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -92,6 +92,7 @@ void b43legacy_radio_lock(struct b43legacy_wldev *dev) u32 status; status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + B43legacy_WARN_ON(status & B43legacy_SBF_RADIOREG_LOCK); status |= B43legacy_SBF_RADIOREG_LOCK; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); mmiowb(); @@ -104,6 +105,7 @@ void b43legacy_radio_unlock(struct b43legacy_wldev *dev) b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */ status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); + B43legacy_WARN_ON(!(status & B43legacy_SBF_RADIOREG_LOCK)); status &= ~B43legacy_SBF_RADIOREG_LOCK; b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status); mmiowb(); @@ -284,12 +286,11 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) unsigned int j; unsigned int start; unsigned int end; - unsigned long phylock_flags; if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0))) return 0; - b43legacy_phy_lock(dev, phylock_flags); + b43legacy_phy_lock(dev); b43legacy_radio_lock(dev); b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802) & 0xFFFC); @@ -323,7 +324,7 @@ u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) ret[j] = 1; } b43legacy_radio_unlock(dev); - b43legacy_phy_unlock(dev, phylock_flags); + b43legacy_phy_unlock(dev); return ret[channel - 1]; } @@ -827,7 +828,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) case B43legacy_PHYTYPE_B: { if (phy->radio_ver != 0x2050) return; - if (!(dev->dev->bus->sprom.r1.boardflags_lo & + if (!(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) return; @@ -857,7 +858,7 @@ void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) } case B43legacy_PHYTYPE_G: if (!phy->gmode || - !(dev->dev->bus->sprom.r1.boardflags_lo & + !(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI)) { tmp16 = b43legacy_nrssi_hw_read(dev, 0x20); if (tmp16 >= 0x20) @@ -1406,7 +1407,7 @@ static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) if (!phy->gmode) return 0; if (!has_loopback_gain(phy)) { - if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo + if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA)) { switch (lpd) { case LPD(0, 1, 1): @@ -1459,7 +1460,7 @@ static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) } loop_or = (loop << 8) | extern_lna_control; - if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo + if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA) { if (extern_lna_control) loop_or |= 0x8000; @@ -1550,7 +1551,7 @@ u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev) b43legacy_get_812_value(dev, LPD(0, 1, 1))); if (phy->rev < 7 || - !(dev->dev->bus->sprom.r1.boardflags_lo + !(dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_EXTLNA)) b43legacy_phy_write(dev, 0x0811, 0x01B3); else @@ -1786,7 +1787,7 @@ int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, channel2freq_bg(channel)); if (channel == 14) { - if (dev->dev->bus->sprom.r1.country_code == 5) /* JAPAN) */ + if (dev->dev->bus->sprom.country_code == 5) /* JAPAN) */ b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, B43legacy_UCODEFLAGS_OFFSET, b43legacy_shm_read32(dev, @@ -2113,21 +2114,25 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) B43legacy_BUG_ON(1); } phy->radio_on = 1; - b43legacy_leds_update(dev, 0); } -void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force) { struct b43legacy_phy *phy = &dev->phy; + if (!phy->radio_on && !force) + return; + if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { u16 rfover, rfoverval; rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER); rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL); - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + if (!force) { + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + } b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, rfoverval & 0xFF73); @@ -2135,7 +2140,6 @@ void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) b43legacy_phy_write(dev, 0x0015, 0xAA00); phy->radio_on = 0; b43legacydbg(dev->wl, "Radio initialized\n"); - b43legacy_leds_update(dev, 0); } void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev) diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h index 6c6a203439e1..ec4de2811c52 100644 --- a/drivers/net/wireless/b43legacy/radio.h +++ b/drivers/net/wireless/b43legacy/radio.h @@ -3,7 +3,7 @@ Broadcom B43legacy wireless driver Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, - Stefano Brivio <st3@riseup.net> + Stefano Brivio <stefano.brivio@polimi.it> Michael Buesch <mbuesch@freenet.de> Danny van Dyk <kugelfang@gentoo.org> Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -61,7 +61,7 @@ void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val); u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev); void b43legacy_radio_turn_on(struct b43legacy_wldev *dev); -void b43legacy_radio_turn_off(struct b43legacy_wldev *dev); +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force); int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, int synthetic_pu_workaround); diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c new file mode 100644 index 000000000000..d178dfbb1c9f --- /dev/null +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -0,0 +1,205 @@ +/* + + Broadcom B43 wireless driver + RFKILL support + + Copyright (c) 2007 Michael Buesch <mb@bu3sch.de> + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "rfkill.h" +#include "radio.h" +#include "b43legacy.h" + +#include <linux/kmod.h> + + +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) +{ + if (dev->phy.rev >= 3) { + if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; + } + return 0; +} + +/* The poll callback for the hardware button. */ +static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) +{ + struct b43legacy_wldev *dev = poll_dev->private; + struct b43legacy_wl *wl = dev->wl; + bool enabled; + bool report_change = 0; + + mutex_lock(&wl->mutex); + if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { + mutex_unlock(&wl->mutex); + return; + } + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { + dev->radio_hw_enable = enabled; + report_change = 1; + b43legacyinfo(wl, "Radio hardware status changed to %s\n", + enabled ? "ENABLED" : "DISABLED"); + } + mutex_unlock(&wl->mutex); + + /* send the radio switch event to the system - note both a key press + * and a release are required */ + if (unlikely(report_change)) { + input_report_key(poll_dev->input, KEY_WLAN, 1); + input_report_key(poll_dev->input, KEY_WLAN, 0); + } +} + +/* Called when the RFKILL toggled in software. + * This is called without locking. */ +static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state) +{ + struct b43legacy_wldev *dev = data; + struct b43legacy_wl *wl = dev->wl; + int err = -EBUSY; + + if (!wl->rfkill.registered) + return 0; + + mutex_lock(&wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) + goto out_unlock; + err = 0; + switch (state) { + case RFKILL_STATE_ON: + if (!dev->radio_hw_enable) { + /* No luck. We can't toggle the hardware RF-kill + * button from software. */ + err = -EBUSY; + goto out_unlock; + } + if (!dev->phy.radio_on) + b43legacy_radio_turn_on(dev); + break; + case RFKILL_STATE_OFF: + if (dev->phy.radio_on) + b43legacy_radio_turn_off(dev, 0); + break; + } + +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->registered) + return NULL; + return rfkill_get_led_name(rfk->rfkill); +} + +void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct b43legacy_rfkill *rfk = &(wl->rfkill); + int err; + + rfk->registered = 0; + + rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); + if (!rfk->rfkill) + goto out_error; + snprintf(rfk->name, sizeof(rfk->name), + "b43legacy-%s", wiphy_name(wl->hw->wiphy)); + rfk->rfkill->name = rfk->name; + rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->data = dev; + rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; + rfk->rfkill->user_claim_unsupported = 1; + + rfk->poll_dev = input_allocate_polled_device(); + if (!rfk->poll_dev) { + rfkill_free(rfk->rfkill); + goto err_freed_rfk; + } + + rfk->poll_dev->private = dev; + rfk->poll_dev->poll = b43legacy_rfkill_poll; + rfk->poll_dev->poll_interval = 1000; /* msecs */ + + rfk->poll_dev->input->name = rfk->name; + rfk->poll_dev->input->id.bustype = BUS_HOST; + rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; + rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + + err = rfkill_register(rfk->rfkill); + if (err) + goto err_free_polldev; + +#ifdef CONFIG_RFKILL_INPUT_MODULE + /* B43legacy RF-kill isn't useful without the rfkill-input subsystem. + * Try to load the module. */ + err = request_module("rfkill-input"); + if (err) + b43legacywarn(wl, "Failed to load the rfkill-input module." + "The built-in radio LED will not work.\n"); +#endif /* CONFIG_RFKILL_INPUT */ + + err = input_register_polled_device(rfk->poll_dev); + if (err) + goto err_unreg_rfk; + + rfk->registered = 1; + + return; +err_unreg_rfk: + rfkill_unregister(rfk->rfkill); +err_free_polldev: + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; +err_freed_rfk: + rfk->rfkill = NULL; +out_error: + rfk->registered = 0; + b43legacywarn(wl, "RF-kill button init failed\n"); +} + +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->registered) + return; + rfk->registered = 0; + + input_unregister_polled_device(rfk->poll_dev); + rfkill_unregister(rfk->rfkill); + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; + rfk->rfkill = NULL; +} + diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h new file mode 100644 index 000000000000..11150a8032f0 --- /dev/null +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -0,0 +1,59 @@ +#ifndef B43legacy_RFKILL_H_ +#define B43legacy_RFKILL_H_ + +struct b43legacy_wldev; + +#ifdef CONFIG_B43LEGACY_RFKILL + +#include <linux/rfkill.h> +#include <linux/workqueue.h> +#include <linux/input-polldev.h> + + + +struct b43legacy_rfkill { + /* The RFKILL subsystem data structure */ + struct rfkill *rfkill; + /* The poll device for the RFKILL input button */ + struct input_polled_dev *poll_dev; + /* Did initialization succeed? Used for freeing. */ + bool registered; + /* The unique name of this rfkill switch */ + char name[sizeof("b43legacy-phy4294967295")]; +}; + +/* The init function returns void, because we are not interested + * in failing the b43 init process when rfkill init failed. */ +void b43legacy_rfkill_init(struct b43legacy_wldev *dev); +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); + +char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); + + +#else /* CONFIG_B43LEGACY_RFKILL */ +/* No RFKILL support. */ + +struct b43legacy_rfkill { + /* empty */ +}; + +static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +{ +} +static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +{ + return NULL; +} + +#endif /* CONFIG_B43LEGACY_RFKILL */ + +#endif /* B43legacy_RFKILL_H_ */ diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index fa1e65687a63..e20c552442d5 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -5,7 +5,7 @@ Transmission (TX/RX) related functions. Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> - Copyright (C) 2005 Stefano Brivio <st3@riseup.net> + Copyright (C) 2005 Stefano Brivio <stefano.brivio@polimi.it> Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de> Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -223,7 +223,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, } else { int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_len, fbrate_base100kbps); } @@ -290,6 +290,8 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; + if (txctl->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT) + mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; /* Generate the RTS or CTS-to-self frame */ if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -310,7 +312,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_data, fragment_len, txctl, (struct ieee80211_cts *) @@ -319,7 +321,7 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, len = sizeof(struct ieee80211_cts); } else { ieee80211_rts_get(dev->wl->hw, - dev->wl->if_id, + txctl->vif, fragment_data, fragment_len, txctl, (struct ieee80211_rts *) (txhdr->rts_frame)); @@ -335,7 +337,6 @@ static void generate_txhdr_fw3(struct b43legacy_wldev *dev, len, rts_rate_fb); hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame); txhdr->rts_dur_fb = hdr->duration_id; - mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; } /* Magic cookie */ @@ -378,7 +379,7 @@ static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev, else tmp -= 3; } else { - if (dev->dev->bus->sprom.r1.boardflags_lo + if (dev->dev->bus->sprom.boardflags_lo & B43legacy_BFL_RSSI) { if (in_rssi > 63) in_rssi = 63; @@ -531,7 +532,24 @@ void b43legacy_rx(struct b43legacy_wldev *dev, else status.rate = b43legacy_plcp_get_bitrate_cck(plcp); status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT); - status.mactime = mactime; + + /* + * If monitors are present get full 64-bit timestamp. This + * code assumes we get to process the packet within 16 bits + * of timestamp, i.e. about 65 milliseconds after the PHY + * received the first symbol. + */ + if (dev->wl->radiotap_enabled) { + u16 low_mactime_now; + + b43legacy_tsf_read(dev, &status.mactime); + low_mactime_now = status.mactime; + status.mactime = status.mactime & ~0xFFFFULL; + status.mactime += mactime; + if (low_mactime_now <= mactime) + status.mactime -= 0x10000; + status.flag |= RX_FLAG_TSFT; + } chanid = (chanstat & B43legacy_RX_CHAN_ID) >> B43legacy_RX_CHAN_ID_SHIFT; diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index ce397e4284f4..0159701e8456 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -1,12 +1,15 @@ config BCM43XX - tristate "Broadcom BCM43xx wireless support" + tristate "Broadcom BCM43xx wireless support (DEPRECATED)" depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL select WIRELESS_EXT select FW_LOADER select HW_RANDOM ---help--- - This is an experimental driver for the Broadcom 43xx wireless chip, - found in the Apple Airport Extreme and various other devices. + This is an experimental driver for the Broadcom 43xx wireless + chip, found in the Apple Airport Extreme and various other + devices. This driver is deprecated and will be removed + from the kernel in the near future. It has been replaced + by the b43 and b43legacy drivers. config BCM43XX_DEBUG bool "Broadcom BCM43xx debugging (RECOMMENDED)" diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 5fdbf24d2443..2ebd2edf5862 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -481,9 +481,9 @@ struct bcm43xx_dmaring; struct bcm43xx_pioqueue; struct bcm43xx_initval { - u16 offset; - u16 size; - u32 value; + __be16 offset; + __be16 size; + __be32 value; } __attribute__((__packed__)); /* Values for bcm430x_sprominfo.locale */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 45683437a98d..b96a325b6ec8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -793,27 +793,27 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) /* il0macaddr */ value = sprom[BCM43xx_SPROM_IL0MACADDR + 0]; - *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); value = sprom[BCM43xx_SPROM_IL0MACADDR + 1]; - *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); value = sprom[BCM43xx_SPROM_IL0MACADDR + 2]; - *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); /* et0macaddr */ value = sprom[BCM43xx_SPROM_ET0MACADDR + 0]; - *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); value = sprom[BCM43xx_SPROM_ET0MACADDR + 1]; - *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); value = sprom[BCM43xx_SPROM_ET0MACADDR + 2]; - *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); /* et1macaddr */ value = sprom[BCM43xx_SPROM_ET1MACADDR + 0]; - *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); value = sprom[BCM43xx_SPROM_ET1MACADDR + 1]; - *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); value = sprom[BCM43xx_SPROM_ET1MACADDR + 2]; - *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); + *(((__be16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); /* ethernet phy settings */ value = sprom[BCM43xx_SPROM_ETHPHY]; @@ -1059,7 +1059,7 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) } static void key_write(struct bcm43xx_private *bcm, - u8 index, u8 algorithm, const u16 *key) + u8 index, u8 algorithm, const __le16 *key) { unsigned int i, basic_wep = 0; u32 offset; @@ -1077,7 +1077,7 @@ static void key_write(struct bcm43xx_private *bcm, /* Write key payload, 8 little endian words */ offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { - value = cpu_to_le16(key[i]); + value = le16_to_cpu(key[i]); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + (i * 2), value); @@ -1091,7 +1091,7 @@ static void key_write(struct bcm43xx_private *bcm, } static void keymac_write(struct bcm43xx_private *bcm, - u8 index, const u32 *addr) + u8 index, const __be32 *addr) { /* for keys 0-3 there is no associated mac address */ if (index < 4) @@ -1102,11 +1102,11 @@ static void keymac_write(struct bcm43xx_private *bcm, bcm43xx_shm_write32(bcm, BCM43xx_SHM_HWMAC, index * 2, - cpu_to_be32(*addr)); + be32_to_cpu(*addr)); bcm43xx_shm_write16(bcm, BCM43xx_SHM_HWMAC, (index * 2) + 1, - cpu_to_be16(*((u16 *)(addr + 1)))); + be16_to_cpu(*((__be16 *)(addr + 1)))); } else { if (index < 8) { TODO(); /* Put them in the macaddress filter */ @@ -1133,8 +1133,8 @@ static int bcm43xx_key_write(struct bcm43xx_private *bcm, return -EINVAL; memcpy(key, _key, key_len); - key_write(bcm, index, algorithm, (const u16 *)key); - keymac_write(bcm, index, (const u32 *)mac_addr); + key_write(bcm, index, algorithm, (const __le16 *)key); + keymac_write(bcm, index, (const __be32 *)mac_addr); bcm->key[index].algorithm = algorithm; @@ -1143,7 +1143,7 @@ static int bcm43xx_key_write(struct bcm43xx_private *bcm, static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) { - static const u32 zero_mac[2] = { 0 }; + static const __be32 zero_mac[2] = { 0 }; unsigned int i,j, nr_keys = 54; u16 offset; @@ -2011,11 +2011,11 @@ err_noinitval: static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); - const u32 *data; + const __be32 *data; unsigned int i, len; /* Upload Microcode. */ - data = (u32 *)(phy->ucode->data); + data = (__be32 *)(phy->ucode->data); len = phy->ucode->size / sizeof(u32); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); for (i = 0; i < len; i++) { @@ -2025,7 +2025,7 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) } /* Upload PCM data. */ - data = (u32 *)(phy->pcm->data); + data = (__be32 *)(phy->pcm->data); len = phy->pcm->size / sizeof(u32); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index c60c1743ea06..76ab109cd2db 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -68,7 +68,7 @@ static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, source = packet; i -= sizeof(*txhdr); } - ret = le16_to_cpu( *((u16 *)(source + i)) ); + ret = le16_to_cpu( *((__le16 *)(source + i)) ); *pos += 2; return ret; @@ -526,7 +526,7 @@ static void pio_rx_error(struct bcm43xx_pioqueue *queue, void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) { - u16 preamble[21] = { 0 }; + __le16 preamble[21] = { 0 }; struct bcm43xx_rxhdr *rxhdr; u16 tmp, len, rxflags2; int i, preamble_readwords; @@ -601,7 +601,7 @@ data_ready: skb_put(skb, len); for (i = 0; i < len - 1; i += 2) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - *((u16 *)(skb->data + i)) = cpu_to_le16(tmp); + *((__le16 *)(skb->data + i)) = cpu_to_le16(tmp); } if (len % 2) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 3e2462671690..f79fe11f9e81 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -122,10 +122,10 @@ static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, __u8 *raw = plcp->raw; if (ofdm_modulation) { - *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); + u32 val = bcm43xx_plcp_get_ratecode_ofdm(bitrate); assert(!(octets & 0xF000)); - *data |= (octets << 5); - *data = cpu_to_le32(*data); + val |= (octets << 5); + *data = cpu_to_le32(val); } else { u32 plen; diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index cc1ee7f4f5f8..d6b9362a3d5c 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -5,52 +5,52 @@ #include <net/ieee80211_crypt.h> struct hostap_ieee80211_mgmt { - u16 frame_control; - u16 duration; + __le16 frame_control; + __le16 duration; u8 da[6]; u8 sa[6]; u8 bssid[6]; - u16 seq_ctrl; + __le16 seq_ctrl; union { struct { - u16 auth_alg; - u16 auth_transaction; - u16 status_code; + __le16 auth_alg; + __le16 auth_transaction; + __le16 status_code; /* possibly followed by Challenge text */ u8 variable[0]; } __attribute__ ((packed)) auth; struct { - u16 reason_code; + __le16 reason_code; } __attribute__ ((packed)) deauth; struct { - u16 capab_info; - u16 listen_interval; + __le16 capab_info; + __le16 listen_interval; /* followed by SSID and Supported rates */ u8 variable[0]; } __attribute__ ((packed)) assoc_req; struct { - u16 capab_info; - u16 status_code; - u16 aid; + __le16 capab_info; + __le16 status_code; + __le16 aid; /* followed by Supported rates */ u8 variable[0]; } __attribute__ ((packed)) assoc_resp, reassoc_resp; struct { - u16 capab_info; - u16 listen_interval; + __le16 capab_info; + __le16 listen_interval; u8 current_ap[6]; /* followed by SSID and Supported rates */ u8 variable[0]; } __attribute__ ((packed)) reassoc_req; struct { - u16 reason_code; + __le16 reason_code; } __attribute__ ((packed)) disassoc; struct { } __attribute__ ((packed)) probe_req; struct { u8 timestamp[8]; - u16 beacon_int; - u16 capab_info; + __le16 beacon_int; + __le16 capab_info; /* followed by some of SSID, Supported rates, * FH Params, DS Params, CF Params, IBSS Params, TIM */ u8 variable[0]; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index ef084df3d48e..49978bdb4324 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1039,7 +1039,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); } else { - u16 len; + __be16 len; /* Leave Ethernet header part of hdr and full payload */ skb_pull(skb, hdrlen); len = htons(skb->len); diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 6bbdb76b32df..ad040a3bb8a7 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -258,7 +258,7 @@ static void ap_handle_timer(unsigned long data) sta->addr, ap->tx_callback_poll); } else { int deauth = sta->timeout_next == STA_DEAUTH; - u16 resp; + __le16 resp; PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s" "(last=%lu, jiffies=%lu)\n", local->dev->name, @@ -300,13 +300,13 @@ void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, int resend) { u8 addr[ETH_ALEN]; - u16 resp; + __le16 resp; int i; PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); memset(addr, 0xff, ETH_ALEN); - resp = __constant_cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); + resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); /* deauth message sent; try to resend it few times; the message is * broadcast, so it may be delayed until next DTIM; there is not much @@ -462,7 +462,7 @@ void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) { struct sta_info *sta; - u16 resp; + __le16 resp; spin_lock_bh(&ap->sta_table_lock); sta = ap_get_sta(ap, mac); @@ -628,7 +628,8 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) struct ap_data *ap = data; struct net_device *dev = ap->local->dev; struct ieee80211_hdr_4addr *hdr; - u16 fc, *pos, auth_alg, auth_transaction, status; + u16 fc, auth_alg, auth_transaction, status; + __le16 *pos; struct sta_info *sta = NULL; char *txt = NULL; DECLARE_MAC_BUF(mac); @@ -649,7 +650,7 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) return; } - pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); auth_alg = le16_to_cpu(*pos++); auth_transaction = le16_to_cpu(*pos++); status = le16_to_cpu(*pos++); @@ -698,7 +699,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) struct ap_data *ap = data; struct net_device *dev = ap->local->dev; struct ieee80211_hdr_4addr *hdr; - u16 fc, *pos, status; + u16 fc, status; + __le16 *pos; struct sta_info *sta = NULL; char *txt = NULL; DECLARE_MAC_BUF(mac); @@ -736,7 +738,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) goto done; } - pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); pos++; status = le16_to_cpu(*pos++); if (status == WLAN_STATUS_SUCCESS) { @@ -1298,7 +1300,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, struct ap_data *ap = local->ap; char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; int len, olen; - u16 auth_alg, auth_transaction, status_code, *pos; + u16 auth_alg, auth_transaction, status_code; + __le16 *pos; u16 resp = WLAN_STATUS_SUCCESS, fc; struct sta_info *sta = NULL; struct ieee80211_crypt_data *crypt; @@ -1332,7 +1335,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, crypt = local->crypt[idx]; } - pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); auth_alg = __le16_to_cpu(*pos); pos++; auth_transaction = __le16_to_cpu(*pos); @@ -1465,7 +1468,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, } fail: - pos = (u16 *) body; + pos = (__le16 *) body; *pos = cpu_to_le16(auth_alg); pos++; *pos = cpu_to_le16(auth_transaction + 1); @@ -1510,7 +1513,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char body[12], *p, *lpos; int len, left; - u16 *pos; + __le16 *pos; u16 resp = WLAN_STATUS_SUCCESS; struct sta_info *sta = NULL; int send_deauth = 0; @@ -1540,7 +1543,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, atomic_inc(&sta->users); spin_unlock_bh(&local->ap->sta_table_lock); - pos = (u16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); + pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); sta->capability = __le16_to_cpu(*pos); pos++; left -= 2; sta->listen_interval = __le16_to_cpu(*pos); @@ -1636,25 +1639,24 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } fail: - pos = (u16 *) body; + pos = (__le16 *) body; if (send_deauth) { - *pos = __constant_cpu_to_le16( - WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); + *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); pos++; } else { /* FIX: CF-Pollable and CF-PollReq should be set to match the * values in beacons/probe responses */ /* FIX: how about privacy and WEP? */ /* capability */ - *pos = __constant_cpu_to_le16(WLAN_CAPABILITY_ESS); + *pos = cpu_to_le16(WLAN_CAPABILITY_ESS); pos++; /* status_code */ - *pos = __cpu_to_le16(resp); + *pos = cpu_to_le16(resp); pos++; - *pos = __cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | + *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | BIT(14) | BIT(15)); /* AID */ pos++; @@ -1681,7 +1683,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, 0x96 : 0x16; (*lpos)++; } - pos = (u16 *) p; + pos = (__le16 *) p; } prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | @@ -1718,7 +1720,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); int len; - u16 reason_code, *pos; + u16 reason_code; + __le16 *pos; struct sta_info *sta = NULL; DECLARE_MAC_BUF(mac); @@ -1729,8 +1732,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, return; } - pos = (u16 *) body; - reason_code = __le16_to_cpu(*pos); + pos = (__le16 *) body; + reason_code = le16_to_cpu(*pos); PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, " "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len, @@ -1760,7 +1763,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len; - u16 reason_code, *pos; + u16 reason_code; + __le16 *pos; struct sta_info *sta = NULL; DECLARE_MAC_BUF(mac); @@ -1771,8 +1775,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, return; } - pos = (u16 *) body; - reason_code = __le16_to_cpu(*pos); + pos = (__le16 *) body; + reason_code = le16_to_cpu(*pos); PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, " "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len, @@ -1817,7 +1821,7 @@ static void ap_handle_dropped_data(local_info_t *local, { struct net_device *dev = local->dev; struct sta_info *sta; - u16 reason; + __le16 reason; spin_lock_bh(&local->ap->sta_table_lock); sta = ap_get_sta(local->ap, hdr->addr2); @@ -1831,8 +1835,7 @@ static void ap_handle_dropped_data(local_info_t *local, return; } - reason = __constant_cpu_to_le16( - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), @@ -1892,7 +1895,7 @@ static void handle_pspoll(local_info_t *local, return; } - aid = __le16_to_cpu(hdr->duration_id); + aid = le16_to_cpu(hdr->duration_id); if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); return; @@ -1998,7 +2001,8 @@ static void handle_beacon(local_info_t *local, struct sk_buff *skb, struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data; char *body = skb->data + IEEE80211_MGMT_HDR_LEN; int len, left; - u16 *pos, beacon_int, capability; + u16 beacon_int, capability; + __le16 *pos; char *ssid = NULL; unsigned char *supp_rates = NULL; int ssid_len = 0, supp_rates_len = 0; @@ -2013,16 +2017,16 @@ static void handle_beacon(local_info_t *local, struct sk_buff *skb, return; } - pos = (u16 *) body; + pos = (__le16 *) body; left = len; /* Timestamp (8 octets) */ pos += 4; left -= 8; /* Beacon interval (2 octets) */ - beacon_int = __le16_to_cpu(*pos); + beacon_int = le16_to_cpu(*pos); pos++; left -= 2; /* Capability information (2 octets) */ - capability = __le16_to_cpu(*pos); + capability = le16_to_cpu(*pos); pos++; left -= 2; if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index 517f89845144..b470c743c2d1 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -188,10 +188,10 @@ struct hfa384x_comp_ident { - u16 id; - u16 variant; - u16 major; - u16 minor; + __le16 id; + __le16 variant; + __le16 major; + __le16 minor; } __attribute__ ((packed)); #define HFA384X_COMP_ID_PRI 0x15 @@ -200,33 +200,33 @@ struct hfa384x_comp_ident struct hfa384x_sup_range { - u16 role; - u16 id; - u16 variant; - u16 bottom; - u16 top; + __le16 role; + __le16 id; + __le16 variant; + __le16 bottom; + __le16 top; } __attribute__ ((packed)); struct hfa384x_build_id { - u16 pri_seq; - u16 sec_seq; + __le16 pri_seq; + __le16 sec_seq; } __attribute__ ((packed)); /* FD01 - Download Buffer */ struct hfa384x_rid_download_buffer { - u16 page; - u16 offset; - u16 length; + __le16 page; + __le16 offset; + __le16 length; } __attribute__ ((packed)); /* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ struct hfa384x_comms_quality { - u16 comm_qual; /* 0 .. 92 */ - u16 signal_level; /* 27 .. 154 */ - u16 noise_level; /* 27 .. 154 */ + __le16 comm_qual; /* 0 .. 92 */ + __le16 signal_level; /* 27 .. 154 */ + __le16 noise_level; /* 27 .. 154 */ } __attribute__ ((packed)); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 877d3bdd37a0..07593803065a 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -845,15 +845,13 @@ static struct pcmcia_device_id hostap_cs_ids[] = { 0x4b801a17), PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), - PCMCIA_DEVICE_PROD_ID1234( + PCMCIA_DEVICE_PROD_ID123( "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", - "Eval-RevA", - 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), + 0x4b801a17, 0x6345a0bf, 0xc9049a39), /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ - PCMCIA_DEVICE_PROD_ID1234( + PCMCIA_DEVICE_PROD_ID123( "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", - "A3", - 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52), + 0x1a424a1c, 0x6ea57632, 0xdd97a26b), PCMCIA_DEVICE_PROD_ID123( "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", 0xe6ec52ce, 0x08649af2, 0x4b74baa0), @@ -890,10 +888,9 @@ static struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_PROD_ID123( "corega", "WL PCCL-11", "ISL37300P", 0xa21501a, 0x59868926, 0xc9049a39), - PCMCIA_DEVICE_PROD_ID1234( + PCMCIA_DEVICE_PROD_ID123( "The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", - "RevA", - 0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194), + 0xa5f472c2, 0x9c05598d, 0xc9049a39), PCMCIA_DEVICE_NULL }; MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); diff --git a/drivers/net/wireless/hostap/hostap_download.c b/drivers/net/wireless/hostap/hostap_download.c index c7678e67697d..89d3849abfe0 100644 --- a/drivers/net/wireless/hostap/hostap_download.c +++ b/drivers/net/wireless/hostap/hostap_download.c @@ -100,7 +100,7 @@ static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, #ifdef PRISM2_PCI { - u16 *pos = (u16 *) buf; + __le16 *pos = (__le16 *) buf; while (len > 0) { *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); len -= 2; @@ -131,7 +131,7 @@ static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, #ifdef PRISM2_PCI { - u16 *pos = (u16 *) buf; + __le16 *pos = (__le16 *) buf; while (len > 0) { HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); len -= 2; @@ -147,7 +147,7 @@ static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, static int prism2_pda_ok(u8 *buf) { - u16 *pda = (u16 *) buf; + __le16 *pda = (__le16 *) buf; int pos; u16 len, pdr; @@ -544,9 +544,9 @@ static int prism2_download_nonvolatile(local_info_t *local, struct net_device *dev = local->dev; int ret = 0, i; struct { - u16 page; - u16 offset; - u16 len; + __le16 page; + __le16 offset; + __le16 len; } dlbuffer; u32 bufaddr; @@ -565,14 +565,12 @@ static int prism2_download_nonvolatile(local_info_t *local, goto out; } - dlbuffer.page = le16_to_cpu(dlbuffer.page); - dlbuffer.offset = le16_to_cpu(dlbuffer.offset); - dlbuffer.len = le16_to_cpu(dlbuffer.len); - printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", - dlbuffer.len, dlbuffer.page, dlbuffer.offset); + le16_to_cpu(dlbuffer.len), + le16_to_cpu(dlbuffer.page), + le16_to_cpu(dlbuffer.offset)); - bufaddr = (dlbuffer.page << 7) + dlbuffer.offset; + bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset); local->hw_downloading = 1; diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index c592641e914e..7be68db6f300 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -1075,7 +1075,7 @@ static int prism2_setup_rids(struct net_device *dev) { struct hostap_interface *iface; local_info_t *local; - u16 tmp; + __le16 tmp; int ret = 0; iface = netdev_priv(dev); @@ -1084,11 +1084,11 @@ static int prism2_setup_rids(struct net_device *dev) hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); if (!local->fw_ap) { - tmp = hostap_get_porttype(local); - ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp); + u16 tmp1 = hostap_get_porttype(local); + ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1); if (ret) { printk("%s: Port type setting to %d failed\n", - dev->name, tmp); + dev->name, tmp1); goto fail; } } @@ -1117,7 +1117,7 @@ static int prism2_setup_rids(struct net_device *dev) ret = -EINVAL; goto fail; } - local->channel_mask = __le16_to_cpu(tmp); + local->channel_mask = le16_to_cpu(tmp); if (local->channel < 1 || local->channel > 14 || !(local->channel_mask & (1 << (local->channel - 1)))) { @@ -1852,7 +1852,7 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) tx_control = local->tx_control; if (meta->tx_cb_idx) { tx_control |= HFA384X_TX_CTRL_TX_OK; - txdesc.sw_support = cpu_to_le16(meta->tx_cb_idx); + txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx); } txdesc.tx_control = cpu_to_le16(tx_control); txdesc.tx_rate = meta->rate; @@ -2190,7 +2190,7 @@ static void hostap_tx_callback(local_info_t *local, return; } - sw_support = le16_to_cpu(txdesc->sw_support); + sw_support = le32_to_cpu(txdesc->sw_support); spin_lock(&local->lock); cb = local->tx_callback; @@ -2448,18 +2448,16 @@ static void prism2_info(local_info_t *local) goto out; } - le16_to_cpus(&info.len); - le16_to_cpus(&info.type); - left = (info.len - 1) * 2; + left = (le16_to_cpu(info.len) - 1) * 2; - if (info.len & 0x8000 || info.len == 0 || left > 2060) { + if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) { /* data register seems to give 0x8000 in some error cases even * though busy bit is not set in offset register; * in addition, length must be at least 1 due to type field */ spin_unlock(&local->baplock); printk(KERN_DEBUG "%s: Received info frame with invalid " - "length 0x%04x (type 0x%04x)\n", dev->name, info.len, - info.type); + "length 0x%04x (type 0x%04x)\n", dev->name, + le16_to_cpu(info.len), le16_to_cpu(info.type)); goto out; } @@ -2476,8 +2474,8 @@ static void prism2_info(local_info_t *local) { spin_unlock(&local->baplock); printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, " - "len=0x%04x, type=0x%04x\n", - dev->name, fid, info.len, info.type); + "len=0x%04x, type=0x%04x\n", dev->name, fid, + le16_to_cpu(info.len), le16_to_cpu(info.type)); dev_kfree_skb(skb); goto out; } @@ -2624,7 +2622,7 @@ static void prism2_check_magic(local_info_t *local) /* Called only from hardware IRQ */ static irqreturn_t prism2_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; + struct net_device *dev = dev_id; struct hostap_interface *iface; local_info_t *local; int events = 0; diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 636f4b2382ea..7cd3fb79230e 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -303,7 +303,7 @@ static void prism2_info_hostscanresults(local_info_t *local, int i, result_size, copy_len, new_count; struct hfa384x_hostscan_result *results, *prev; unsigned long flags; - u16 *pos; + __le16 *pos; u8 *ptr; wake_up_interruptible(&local->hostscan_wq); @@ -314,7 +314,7 @@ static void prism2_info_hostscanresults(local_info_t *local, return; } - pos = (u16 *) buf; + pos = (__le16 *) buf; copy_len = result_size = le16_to_cpu(*pos); if (result_size == 0) { printk(KERN_DEBUG "%s: invalid result_size (0) in " @@ -373,7 +373,7 @@ void hostap_info_process(local_info_t *local, struct sk_buff *skb) buf = skb->data + sizeof(*info); left = skb->len - sizeof(*info); - switch (info->type) { + switch (le16_to_cpu(info->type)) { case HFA384X_INFO_COMMTALLIES: prism2_info_commtallies(local, buf, left); break; @@ -395,7 +395,8 @@ void hostap_info_process(local_info_t *local, struct sk_buff *skb) #ifndef PRISM2_NO_DEBUG default: PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n", - local->dev->name, info->len, info->type); + local->dev->name, le16_to_cpu(info->len), + le16_to_cpu(info->type)); PDEBUG(DEBUG_EXTRA, "Unknown info frame:"); for (i = 0; i < (left < 100 ? left : 100); i++) PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index d8f5efcfcab9..0ca0bfeb0ada 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -84,7 +84,7 @@ static int prism2_get_datarates(struct net_device *dev, u8 *rates) if (len < 2) return 0; - val = le16_to_cpu(*(u16 *) buf); /* string length */ + val = le16_to_cpu(*(__le16 *) buf); /* string length */ if (len - 2 < val || val > 10) return 0; @@ -496,7 +496,7 @@ static int prism2_ioctl_giwsens(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - u16 val; + __le16 val; iface = netdev_priv(dev); local = iface->local; @@ -506,7 +506,7 @@ static int prism2_ioctl_giwsens(struct net_device *dev, 0) return -EINVAL; - sens->value = __le16_to_cpu(val); + sens->value = le16_to_cpu(val); sens->fixed = 1; return 0; @@ -561,17 +561,17 @@ static int prism2_ioctl_siwrts(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - u16 val; + __le16 val; iface = netdev_priv(dev); local = iface->local; if (rts->disabled) - val = __constant_cpu_to_le16(2347); + val = cpu_to_le16(2347); else if (rts->value < 0 || rts->value > 2347) return -EINVAL; else - val = __cpu_to_le16(rts->value); + val = cpu_to_le16(rts->value); if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) || local->func->reset_port(dev)) @@ -588,7 +588,7 @@ static int prism2_ioctl_giwrts(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - u16 val; + __le16 val; iface = netdev_priv(dev); local = iface->local; @@ -597,7 +597,7 @@ static int prism2_ioctl_giwrts(struct net_device *dev, 0) return -EINVAL; - rts->value = __le16_to_cpu(val); + rts->value = le16_to_cpu(val); rts->disabled = (rts->value == 2347); rts->fixed = 1; @@ -611,17 +611,17 @@ static int prism2_ioctl_siwfrag(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - u16 val; + __le16 val; iface = netdev_priv(dev); local = iface->local; if (rts->disabled) - val = __constant_cpu_to_le16(2346); + val = cpu_to_le16(2346); else if (rts->value < 256 || rts->value > 2346) return -EINVAL; else - val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */ + val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */ local->fragm_threshold = rts->value & ~0x1; if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val, @@ -638,7 +638,7 @@ static int prism2_ioctl_giwfrag(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - u16 val; + __le16 val; iface = netdev_priv(dev); local = iface->local; @@ -647,7 +647,7 @@ static int prism2_ioctl_giwfrag(struct net_device *dev, &val, 2, 1) < 0) return -EINVAL; - rts->value = __le16_to_cpu(val); + rts->value = le16_to_cpu(val); rts->disabled = (rts->value == 2346); rts->fixed = 1; @@ -718,8 +718,8 @@ static int prism2_ioctl_siwap(struct net_device *dev, if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) { struct hfa384x_scan_request scan_req; memset(&scan_req, 0, sizeof(scan_req)); - scan_req.channel_list = __constant_cpu_to_le16(0x3fff); - scan_req.txrate = __constant_cpu_to_le16(HFA384X_RATES_1MBPS); + scan_req.channel_list = cpu_to_le16(0x3fff); + scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS); if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req, sizeof(scan_req))) { printk(KERN_DEBUG "%s: ScanResults request failed - " @@ -812,7 +812,7 @@ static int prism2_ioctl_giwnickn(struct net_device *dev, len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME, &name, MAX_NAME_LEN + 2, 0); - val = __le16_to_cpu(*(u16 *) name); + val = le16_to_cpu(*(__le16 *) name); if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN) return -EOPNOTSUPP; @@ -963,7 +963,7 @@ static int prism2_ioctl_giwessid(struct net_device *dev, memset(ssid, 0, sizeof(ssid)); len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID, &ssid, MAX_SSID_LEN + 2, 0); - val = __le16_to_cpu(*(u16 *) ssid); + val = le16_to_cpu(*(__le16 *) ssid); if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) { return -EOPNOTSUPP; } @@ -1089,6 +1089,9 @@ static int prism2_ioctl_giwrange(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) + range->scan_capa = IW_SCAN_CAPA_ESSID; + return 0; } @@ -1316,7 +1319,7 @@ static int prism2_ioctl_giwpower(struct net_device *dev, #else /* PRISM2_NO_STATION_MODES */ struct hostap_interface *iface; local_info_t *local; - u16 enable, mcast; + __le16 enable, mcast; iface = netdev_priv(dev); local = iface->local; @@ -1325,7 +1328,7 @@ static int prism2_ioctl_giwpower(struct net_device *dev, < 0) return -EINVAL; - if (!__le16_to_cpu(enable)) { + if (!le16_to_cpu(enable)) { rrq->disabled = 1; return 0; } @@ -1333,29 +1336,29 @@ static int prism2_ioctl_giwpower(struct net_device *dev, rrq->disabled = 0; if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - u16 timeout; + __le16 timeout; if (local->func->get_rid(dev, HFA384X_RID_CNFPMHOLDOVERDURATION, &timeout, 2, 1) < 0) return -EINVAL; rrq->flags = IW_POWER_TIMEOUT; - rrq->value = __le16_to_cpu(timeout) * 1024; + rrq->value = le16_to_cpu(timeout) * 1024; } else { - u16 period; + __le16 period; if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION, &period, 2, 1) < 0) return -EINVAL; rrq->flags = IW_POWER_PERIOD; - rrq->value = __le16_to_cpu(period) * 1024; + rrq->value = le16_to_cpu(period) * 1024; } if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast, 2, 1) < 0) return -EINVAL; - if (__le16_to_cpu(mcast)) + if (le16_to_cpu(mcast)) rrq->flags |= IW_POWER_ALL_R; else rrq->flags |= IW_POWER_UNICAST_R; @@ -1432,7 +1435,7 @@ static int prism2_ioctl_giwretry(struct net_device *dev, { struct hostap_interface *iface; local_info_t *local; - u16 shortretry, longretry, lifetime, altretry; + __le16 shortretry, longretry, lifetime, altretry; iface = netdev_priv(dev); local = iface->local; @@ -1445,15 +1448,11 @@ static int prism2_ioctl_giwretry(struct net_device *dev, &lifetime, 2, 1) < 0) return -EINVAL; - le16_to_cpus(&shortretry); - le16_to_cpus(&longretry); - le16_to_cpus(&lifetime); - rrq->disabled = 0; if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { rrq->flags = IW_RETRY_LIFETIME; - rrq->value = lifetime * 1024; + rrq->value = le16_to_cpu(lifetime) * 1024; } else { if (local->manual_retry_count >= 0) { rrq->flags = IW_RETRY_LIMIT; @@ -1465,10 +1464,10 @@ static int prism2_ioctl_giwretry(struct net_device *dev, rrq->value = local->manual_retry_count; } else if ((rrq->flags & IW_RETRY_LONG)) { rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; - rrq->value = longretry; + rrq->value = le16_to_cpu(longretry); } else { rrq->flags = IW_RETRY_LIMIT; - rrq->value = shortretry; + rrq->value = le16_to_cpu(shortretry); if (shortretry != longretry) rrq->flags |= IW_RETRY_SHORT; } @@ -3098,7 +3097,7 @@ static int prism2_set_genericelement(struct net_device *dev, u8 *elem, if (buf == NULL) return -ENOMEM; - *((u16 *) buf) = cpu_to_le16(len); + *((__le16 *) buf) = cpu_to_le16(len); memcpy(buf + 2, elem, len); kfree(local->generic_elem); @@ -3758,7 +3757,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev, struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; struct iw_mlme *mlme = (struct iw_mlme *) extra; - u16 reason; + __le16 reason; reason = cpu_to_le16(mlme->reason_code); @@ -3780,7 +3779,7 @@ static int prism2_ioctl_siwmlme(struct net_device *dev, static int prism2_ioctl_mlme(local_info_t *local, struct prism2_hostapd_param *param) { - u16 reason; + __le16 reason; reason = cpu_to_le16(param->u.mlme.reason_code); switch (param->u.mlme.cmd) { diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 17c58e9bdad5..20d387f6658c 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -296,7 +296,7 @@ int hostap_tx_callback_unregister(local_info_t *local, u16 idx) int hostap_set_word(struct net_device *dev, int rid, u16 val) { struct hostap_interface *iface; - u16 tmp = cpu_to_le16(val); + __le16 tmp = cpu_to_le16(val); iface = netdev_priv(dev); return iface->local->func->set_rid(dev, rid, &tmp, 2); } @@ -1095,15 +1095,15 @@ int prism2_sta_deauth(local_info_t *local, u16 reason) { union iwreq_data wrqu; int ret; + __le16 val = cpu_to_le16(reason); if (local->iw_mode != IW_MODE_INFRA || memcmp(local->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 || memcmp(local->bssid, "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0) return 0; - reason = cpu_to_le16(reason); ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH, - (u8 *) &reason, 2); + (u8 *) &val, 2); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL); return ret; diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index fc876ba18572..3a874fc621d3 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -128,8 +128,8 @@ static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) #define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) #define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) #define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), cpu_to_le16((v))) -#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw_debug(dev, (a))) +#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v))) +#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a))) #else /* PRISM2_IO_DEBUG */ @@ -173,8 +173,8 @@ static inline u16 hfa384x_inw(struct net_device *dev, int a) #define HFA384X_INB(a) hfa384x_inb(dev, (a)) #define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v)) #define HFA384X_INW(a) hfa384x_inw(dev, (a)) -#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), cpu_to_le16((v))) -#define HFA384X_INW_DATA(a) (u16) le16_to_cpu(hfa384x_inw(dev, (a))) +#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v))) +#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a))) #endif /* PRISM2_IO_DEBUG */ @@ -183,10 +183,10 @@ static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, int len) { u16 d_off; - u16 *pos; + __le16 *pos; d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; + pos = (__le16 *) buf; for ( ; len > 1; len -= 2) *pos++ = HFA384X_INW_DATA(d_off); @@ -201,10 +201,10 @@ static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) { u16 d_off; - u16 *pos; + __le16 *pos; d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; - pos = (u16 *) buf; + pos = (__le16 *) buf; for ( ; len > 1; len -= 2) HFA384X_OUTW_DATA(*pos++, d_off); diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index e6516a186d0e..15445bce2ac7 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -39,20 +39,20 @@ struct linux_wlan_ng_prism_hdr { } __attribute__ ((packed)); struct linux_wlan_ng_cap_hdr { - u32 version; - u32 length; - u64 mactime; - u64 hosttime; - u32 phytype; - u32 channel; - u32 datarate; - u32 antenna; - u32 priority; - u32 ssi_type; - s32 ssi_signal; - s32 ssi_noise; - u32 preamble; - u32 encoding; + __be32 version; + __be32 length; + __be64 mactime; + __be64 hosttime; + __be32 phytype; + __be32 channel; + __be32 datarate; + __be32 antenna; + __be32 priority; + __be32 ssi_type; + __be32 ssi_signal; + __be32 ssi_noise; + __be32 preamble; + __be32 encoding; } __attribute__ ((packed)); #define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */ @@ -60,28 +60,28 @@ struct linux_wlan_ng_cap_hdr { struct hfa384x_rx_frame { /* HFA384X RX frame descriptor */ - u16 status; /* HFA384X_RX_STATUS_ flags */ - u32 time; /* timestamp, 1 microsecond resolution */ + __le16 status; /* HFA384X_RX_STATUS_ flags */ + __le32 time; /* timestamp, 1 microsecond resolution */ u8 silence; /* 27 .. 154; seems to be 0 */ u8 signal; /* 27 .. 154 */ u8 rate; /* 10, 20, 55, or 110 */ u8 rxflow; - u32 reserved; + __le32 reserved; /* 802.11 */ - u16 frame_control; - u16 duration_id; + __le16 frame_control; + __le16 duration_id; u8 addr1[6]; u8 addr2[6]; u8 addr3[6]; - u16 seq_ctrl; + __le16 seq_ctrl; u8 addr4[6]; - u16 data_len; + __le16 data_len; /* 802.3 */ u8 dst_addr[6]; u8 src_addr[6]; - u16 len; + __be16 len; /* followed by frame data; max 2304 bytes */ } __attribute__ ((packed)); @@ -89,28 +89,28 @@ struct hfa384x_rx_frame { struct hfa384x_tx_frame { /* HFA384X TX frame descriptor */ - u16 status; /* HFA384X_TX_STATUS_ flags */ - u16 reserved1; - u16 reserved2; - u32 sw_support; + __le16 status; /* HFA384X_TX_STATUS_ flags */ + __le16 reserved1; + __le16 reserved2; + __le32 sw_support; u8 retry_count; /* not yet implemented */ u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */ - u16 tx_control; /* HFA384X_TX_CTRL_ flags */ + __le16 tx_control; /* HFA384X_TX_CTRL_ flags */ /* 802.11 */ - u16 frame_control; /* parts not used */ - u16 duration_id; + __le16 frame_control; /* parts not used */ + __le16 duration_id; u8 addr1[6]; u8 addr2[6]; /* filled by firmware */ u8 addr3[6]; - u16 seq_ctrl; /* filled by firmware */ + __le16 seq_ctrl; /* filled by firmware */ u8 addr4[6]; - u16 data_len; + __le16 data_len; /* 802.3 */ u8 dst_addr[6]; u8 src_addr[6]; - u16 len; + __be16 len; /* followed by frame data; max 2304 bytes */ } __attribute__ ((packed)); @@ -118,8 +118,8 @@ struct hfa384x_tx_frame { struct hfa384x_rid_hdr { - u16 len; - u16 rid; + __le16 len; + __le16 rid; } __attribute__ ((packed)); @@ -130,78 +130,78 @@ struct hfa384x_rid_hdr #define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100 struct hfa384x_scan_request { - u16 channel_list; - u16 txrate; /* HFA384X_RATES_* */ + __le16 channel_list; + __le16 txrate; /* HFA384X_RATES_* */ } __attribute__ ((packed)); struct hfa384x_hostscan_request { - u16 channel_list; - u16 txrate; - u16 target_ssid_len; + __le16 channel_list; + __le16 txrate; + __le16 target_ssid_len; u8 target_ssid[32]; } __attribute__ ((packed)); struct hfa384x_join_request { u8 bssid[6]; - u16 channel; + __le16 channel; } __attribute__ ((packed)); struct hfa384x_info_frame { - u16 len; - u16 type; + __le16 len; + __le16 type; } __attribute__ ((packed)); struct hfa384x_comm_tallies { - u16 tx_unicast_frames; - u16 tx_multicast_frames; - u16 tx_fragments; - u16 tx_unicast_octets; - u16 tx_multicast_octets; - u16 tx_deferred_transmissions; - u16 tx_single_retry_frames; - u16 tx_multiple_retry_frames; - u16 tx_retry_limit_exceeded; - u16 tx_discards; - u16 rx_unicast_frames; - u16 rx_multicast_frames; - u16 rx_fragments; - u16 rx_unicast_octets; - u16 rx_multicast_octets; - u16 rx_fcs_errors; - u16 rx_discards_no_buffer; - u16 tx_discards_wrong_sa; - u16 rx_discards_wep_undecryptable; - u16 rx_message_in_msg_fragments; - u16 rx_message_in_bad_msg_fragments; + __le16 tx_unicast_frames; + __le16 tx_multicast_frames; + __le16 tx_fragments; + __le16 tx_unicast_octets; + __le16 tx_multicast_octets; + __le16 tx_deferred_transmissions; + __le16 tx_single_retry_frames; + __le16 tx_multiple_retry_frames; + __le16 tx_retry_limit_exceeded; + __le16 tx_discards; + __le16 rx_unicast_frames; + __le16 rx_multicast_frames; + __le16 rx_fragments; + __le16 rx_unicast_octets; + __le16 rx_multicast_octets; + __le16 rx_fcs_errors; + __le16 rx_discards_no_buffer; + __le16 tx_discards_wrong_sa; + __le16 rx_discards_wep_undecryptable; + __le16 rx_message_in_msg_fragments; + __le16 rx_message_in_bad_msg_fragments; } __attribute__ ((packed)); struct hfa384x_comm_tallies32 { - u32 tx_unicast_frames; - u32 tx_multicast_frames; - u32 tx_fragments; - u32 tx_unicast_octets; - u32 tx_multicast_octets; - u32 tx_deferred_transmissions; - u32 tx_single_retry_frames; - u32 tx_multiple_retry_frames; - u32 tx_retry_limit_exceeded; - u32 tx_discards; - u32 rx_unicast_frames; - u32 rx_multicast_frames; - u32 rx_fragments; - u32 rx_unicast_octets; - u32 rx_multicast_octets; - u32 rx_fcs_errors; - u32 rx_discards_no_buffer; - u32 tx_discards_wrong_sa; - u32 rx_discards_wep_undecryptable; - u32 rx_message_in_msg_fragments; - u32 rx_message_in_bad_msg_fragments; + __le32 tx_unicast_frames; + __le32 tx_multicast_frames; + __le32 tx_fragments; + __le32 tx_unicast_octets; + __le32 tx_multicast_octets; + __le32 tx_deferred_transmissions; + __le32 tx_single_retry_frames; + __le32 tx_multiple_retry_frames; + __le32 tx_retry_limit_exceeded; + __le32 tx_discards; + __le32 rx_unicast_frames; + __le32 rx_multicast_frames; + __le32 rx_fragments; + __le32 rx_unicast_octets; + __le32 rx_multicast_octets; + __le32 rx_fcs_errors; + __le32 rx_discards_no_buffer; + __le32 tx_discards_wrong_sa; + __le32 rx_discards_wep_undecryptable; + __le32 rx_message_in_msg_fragments; + __le32 rx_message_in_bad_msg_fragments; } __attribute__ ((packed)); struct hfa384x_scan_result_hdr { - u16 reserved; - u16 scan_reason; + __le16 reserved; + __le16 scan_reason; #define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */ #define HFA384X_SCAN_HOST_INITIATED 1 #define HFA384X_SCAN_FIRMWARE_INITIATED 2 @@ -211,30 +211,30 @@ struct hfa384x_scan_result_hdr { #define HFA384X_SCAN_MAX_RESULTS 32 struct hfa384x_scan_result { - u16 chid; - u16 anl; - u16 sl; + __le16 chid; + __le16 anl; + __le16 sl; u8 bssid[6]; - u16 beacon_interval; - u16 capability; - u16 ssid_len; + __le16 beacon_interval; + __le16 capability; + __le16 ssid_len; u8 ssid[32]; u8 sup_rates[10]; - u16 rate; + __le16 rate; } __attribute__ ((packed)); struct hfa384x_hostscan_result { - u16 chid; - u16 anl; - u16 sl; + __le16 chid; + __le16 anl; + __le16 sl; u8 bssid[6]; - u16 beacon_interval; - u16 capability; - u16 ssid_len; + __le16 beacon_interval; + __le16 capability; + __le16 ssid_len; u8 ssid[32]; u8 sup_rates[10]; - u16 rate; - u16 atim; + __le16 rate; + __le16 atim; } __attribute__ ((packed)); struct comm_tallies_sums { diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index fc6cdd8086c1..2ab107f45793 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -2509,9 +2509,9 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total hdr+data */ + ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */ - ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL; + ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM; @@ -2558,7 +2558,7 @@ static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) #ifdef CONFIG_IPW2100_MONITOR return 0; #else - switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) { + switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { case IEEE80211_FTYPE_MGMT: case IEEE80211_FTYPE_CTL: return 0; @@ -2677,7 +2677,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) #endif if (stats.len < sizeof(struct ieee80211_hdr_3addr)) break; - switch (WLAN_FC_GET_TYPE(u->rx_data.header.frame_ctl)) { + switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { case IEEE80211_FTYPE_MGMT: ieee80211_rx_mgt(priv->ieee, &u->rx_data.header, &stats); @@ -6591,8 +6591,7 @@ static const long ipw2100_frequencies[] = { 2472, 2484 }; -#define FREQ_COUNT (sizeof(ipw2100_frequencies) / \ - sizeof(ipw2100_frequencies[0])) +#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies) static const long ipw2100_rates_11b[] = { 1000000, @@ -7796,7 +7795,7 @@ static int ipw2100_wx_set_mlme(struct net_device *dev, { struct ipw2100_priv *priv = ieee80211_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; - u16 reason; + __le16 reason; reason = cpu_to_le16(mlme->reason_code); diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 003f73f89efa..3e6ad7b92c83 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2352,27 +2352,13 @@ static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) static int ipw_send_associate(struct ipw_priv *priv, struct ipw_associate *associate) { - struct ipw_associate tmp_associate; - if (!priv || !associate) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(&tmp_associate, associate, sizeof(*associate)); - tmp_associate.policy_support = - cpu_to_le16(tmp_associate.policy_support); - tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw); - tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw); - tmp_associate.capability = cpu_to_le16(tmp_associate.capability); - tmp_associate.listen_interval = - cpu_to_le16(tmp_associate.listen_interval); - tmp_associate.beacon_interval = - cpu_to_le16(tmp_associate.beacon_interval); - tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); - - return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate), - &tmp_associate); + return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate), + associate); } static int ipw_send_supported_rates(struct ipw_priv *priv, @@ -2403,14 +2389,13 @@ static int ipw_set_random_seed(struct ipw_priv *priv) static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) { + __le32 v = cpu_to_le32(phy_off); if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - phy_off = cpu_to_le32(phy_off); - return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off), - &phy_off); + return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v); } static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) @@ -2499,7 +2484,7 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) { - u32 param; + __le32 param; if (!priv) { IPW_ERROR("Invalid args\n"); @@ -2510,17 +2495,16 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) * level */ switch (mode) { case IPW_POWER_BATTERY: - param = IPW_POWER_INDEX_3; + param = cpu_to_le32(IPW_POWER_INDEX_3); break; case IPW_POWER_AC: - param = IPW_POWER_MODE_CAM; + param = cpu_to_le32(IPW_POWER_MODE_CAM); break; default: - param = mode; + param = cpu_to_le32(mode); break; } - param = cpu_to_le32(param); return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), ¶m); } @@ -2654,13 +2638,13 @@ static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) static void ipw_eeprom_init_sram(struct ipw_priv *priv) { int i; - u16 *eeprom = (u16 *) priv->eeprom; + __le16 *eeprom = (__le16 *) priv->eeprom; IPW_DEBUG_TRACE(">>\n"); /* read entire contents of eeprom into private buffer */ for (i = 0; i < 128; i++) - eeprom[i] = le16_to_cpu(eeprom_read_u16(priv, (u8) i)); + eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i)); /* If the data looks correct, then copy it to our private @@ -3040,17 +3024,17 @@ static void ipw_arc_release(struct ipw_priv *priv) } struct fw_chunk { - u32 address; - u32 length; + __le32 address; + __le32 length; }; static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) { int rc = 0, i, addr; u8 cr = 0; - u16 *image; + __le16 *image; - image = (u16 *) data; + image = (__le16 *) data; IPW_DEBUG_TRACE(">> \n"); @@ -3097,7 +3081,7 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) /* load new ipw uCode */ for (i = 0; i < len / 2; i++) ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE, - cpu_to_le16(image[i])); + le16_to_cpu(image[i])); /* enable DINO */ ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0); @@ -3116,11 +3100,11 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) if (cr & DINO_RXFIFO_DATA) { /* alive_command_responce size is NOT multiple of 4 */ - u32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4]; + __le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4]; for (i = 0; i < ARRAY_SIZE(response_buffer); i++) response_buffer[i] = - le32_to_cpu(ipw_read_reg32(priv, + cpu_to_le32(ipw_read_reg32(priv, IPW_BASEBAND_RX_FIFO_READ)); memcpy(&priv->dino_alive, response_buffer, sizeof(priv->dino_alive)); @@ -4170,7 +4154,7 @@ static void ipw_gather_stats(struct ipw_priv *priv) priv->last_missed_beacons = priv->missed_beacons; if (priv->assoc_request.beacon_interval) { missed_beacons_percent = missed_beacons_delta * - (HZ * priv->assoc_request.beacon_interval) / + (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) / (IPW_STATS_INTERVAL * 10); } else { missed_beacons_percent = 0; @@ -4396,9 +4380,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { DECLARE_MAC_BUF(mac); + u16 size = le16_to_cpu(notif->size); notif->size = le16_to_cpu(notif->size); - IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size); + IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size); switch (notif->subtype) { case HOST_NOTIFICATION_STATUS_ASSOCIATED:{ @@ -4433,9 +4418,9 @@ static void ipw_rx_notification(struct ipw_priv *priv, workqueue, &priv-> adhoc_check, - priv-> + le16_to_cpu(priv-> assoc_request. - beacon_interval); + beacon_interval)); break; } @@ -4453,20 +4438,17 @@ static void ipw_rx_notification(struct ipw_priv *priv, if ((sizeof (struct ieee80211_assoc_response) - <= notif->size) - && (notif->size <= 2314)) { + <= size) + && (size <= 2314)) { struct ieee80211_rx_stats stats = { - .len = - notif-> - size - 1, + .len = size - 1, }; IPW_DEBUG_QOS ("QoS Associate " - "size %d\n", - notif->size); + "size %d\n", size); ieee80211_rx_mgt(priv-> ieee, (struct @@ -4671,20 +4653,20 @@ static void ipw_rx_notification(struct ipw_priv *priv, struct notif_channel_result *x = ¬if->u.channel_result; - if (notif->size == sizeof(*x)) { + if (size == sizeof(*x)) { IPW_DEBUG_SCAN("Scan result for channel %d\n", x->channel_num); } else { IPW_DEBUG_SCAN("Scan result of wrong size %d " "(should be %zd)\n", - notif->size, sizeof(*x)); + size, sizeof(*x)); } break; } case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{ struct notif_scan_complete *x = ¬if->u.scan_complete; - if (notif->size == sizeof(*x)) { + if (size == sizeof(*x)) { IPW_DEBUG_SCAN ("Scan completed: type %d, %d channels, " "%d status\n", x->scan_type, @@ -4692,7 +4674,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, } else { IPW_ERROR("Scan completed of wrong size %d " "(should be %zd)\n", - notif->size, sizeof(*x)); + size, sizeof(*x)); } priv->status &= @@ -4758,13 +4740,13 @@ static void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{ struct notif_frag_length *x = ¬if->u.frag_len; - if (notif->size == sizeof(*x)) + if (size == sizeof(*x)) IPW_ERROR("Frag length: %d\n", le16_to_cpu(x->frag_length)); else IPW_ERROR("Frag length of wrong size %d " "(should be %zd)\n", - notif->size, sizeof(*x)); + size, sizeof(*x)); break; } @@ -4772,7 +4754,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, struct notif_link_deterioration *x = ¬if->u.link_deterioration; - if (notif->size == sizeof(*x)) { + if (size == sizeof(*x)) { IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, "link deterioration: type %d, cnt %d\n", x->silence_notification_type, @@ -4782,7 +4764,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, } else { IPW_ERROR("Link Deterioration of wrong size %d " "(should be %zd)\n", - notif->size, sizeof(*x)); + size, sizeof(*x)); } break; } @@ -4798,10 +4780,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_STATUS_BEACON_STATE:{ struct notif_beacon_state *x = ¬if->u.beacon_state; - if (notif->size != sizeof(*x)) { + if (size != sizeof(*x)) { IPW_ERROR ("Beacon state of wrong size %d (should " - "be %zd)\n", notif->size, sizeof(*x)); + "be %zd)\n", size, sizeof(*x)); break; } @@ -4816,7 +4798,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{ struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key; - if (notif->size == sizeof(*x)) { + if (size == sizeof(*x)) { IPW_ERROR("TGi Tx Key: state 0x%02x sec type " "0x%02x station %d\n", x->key_state, x->security_type, @@ -4826,14 +4808,14 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_ERROR ("TGi Tx Key of wrong size %d (should be %zd)\n", - notif->size, sizeof(*x)); + size, sizeof(*x)); break; } case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{ struct notif_calibration *x = ¬if->u.calibration; - if (notif->size == sizeof(*x)) { + if (size == sizeof(*x)) { memcpy(&priv->calib, x, sizeof(*x)); IPW_DEBUG_INFO("TODO: Calibration\n"); break; @@ -4841,12 +4823,12 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_ERROR ("Calibration of wrong size %d (should be %zd)\n", - notif->size, sizeof(*x)); + size, sizeof(*x)); break; } case HOST_NOTIFICATION_NOISE_STATS:{ - if (notif->size == sizeof(u32)) { + if (size == sizeof(u32)) { priv->exp_avg_noise = exponential_average(priv->exp_avg_noise, (u8) (le32_to_cpu(notif->u.noise.value) & 0xff), @@ -4856,14 +4838,14 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_ERROR ("Noise stat is wrong size %d (should be %zd)\n", - notif->size, sizeof(u32)); + size, sizeof(u32)); break; } default: IPW_DEBUG_NOTIF("Unknown notification: " "subtype=%d,flags=0x%2x,size=%d\n", - notif->subtype, notif->flags, notif->size); + notif->subtype, notif->flags, size); } } @@ -6048,7 +6030,7 @@ static void ipw_adhoc_check(void *data) } queue_delayed_work(priv->workqueue, &priv->adhoc_check, - priv->assoc_request.beacon_interval); + le16_to_cpu(priv->assoc_request.beacon_interval)); } static void ipw_bg_adhoc_check(struct work_struct *work) @@ -6767,7 +6749,7 @@ static int ipw_wx_set_mlme(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_mlme *mlme = (struct iw_mlme *)extra; - u16 reason; + __le16 reason; reason = cpu_to_le16(mlme->reason_code); @@ -6904,7 +6886,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, burst_duration = ipw_qos_get_burst_duration(priv); for (i = 0; i < QOS_QUEUE_NUM; i++) qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] = - (u16)burst_duration; + cpu_to_le16(burst_duration); } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { if (type == IEEE_B) { IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", @@ -6936,20 +6918,11 @@ static int ipw_qos_activate(struct ipw_priv *priv, burst_duration = ipw_qos_get_burst_duration(priv); for (i = 0; i < QOS_QUEUE_NUM; i++) qos_parameters[QOS_PARAM_SET_ACTIVE]. - tx_op_limit[i] = (u16)burst_duration; + tx_op_limit[i] = cpu_to_le16(burst_duration); } } IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); - for (i = 0; i < 3; i++) { - int j; - for (j = 0; j < QOS_QUEUE_NUM; j++) { - qos_parameters[i].cw_min[j] = cpu_to_le16(qos_parameters[i].cw_min[j]); - qos_parameters[i].cw_max[j] = cpu_to_le16(qos_parameters[i].cw_max[j]); - qos_parameters[i].tx_op_limit[j] = cpu_to_le16(qos_parameters[i].tx_op_limit[j]); - } - } - err = ipw_send_qos_params_command(priv, (struct ieee80211_qos_parameters *) &(qos_parameters[0])); @@ -7300,7 +7273,7 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->assoc_request.auth_type = AUTH_OPEN; if (priv->ieee->wpa_ie_len) { - priv->assoc_request.policy_support = 0x02; /* RSN active */ + priv->assoc_request.policy_support = cpu_to_le16(0x02); /* RSN active */ ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, priv->ieee->wpa_ie_len); } @@ -7317,7 +7290,7 @@ static int ipw_associate_network(struct ipw_priv *priv, else if (network->mode & priv->ieee->mode & IEEE_B) priv->assoc_request.ieee_mode = IPW_B_MODE; - priv->assoc_request.capability = network->capability; + priv->assoc_request.capability = cpu_to_le16(network->capability); if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && !(priv->config & CFG_PREAMBLE_LONG)) { priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE; @@ -7326,13 +7299,13 @@ static int ipw_associate_network(struct ipw_priv *priv, /* Clear the short preamble if we won't be supporting it */ priv->assoc_request.capability &= - ~WLAN_CAPABILITY_SHORT_PREAMBLE; + ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); } /* Clear capability bits that aren't used in Ad Hoc */ if (priv->ieee->iw_mode == IW_MODE_ADHOC) priv->assoc_request.capability &= - ~WLAN_CAPABILITY_SHORT_SLOT_TIME; + ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME); IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", @@ -7354,7 +7327,7 @@ static int ipw_associate_network(struct ipw_priv *priv, '1' + priv->ieee->sec.active_key : '.', priv->capability & CAP_PRIVACY_ON ? '.' : ' '); - priv->assoc_request.beacon_interval = network->beacon_interval; + priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval); if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) { priv->assoc_request.assoc_type = HC_IBSS_START; @@ -7365,21 +7338,21 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->assoc_request.assoc_type = HC_REASSOCIATE; else priv->assoc_request.assoc_type = HC_ASSOCIATE; - priv->assoc_request.assoc_tsf_msw = network->time_stamp[1]; - priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; + priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]); + priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]); } memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN); if (priv->ieee->iw_mode == IW_MODE_ADHOC) { memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); - priv->assoc_request.atim_window = network->atim_window; + priv->assoc_request.atim_window = cpu_to_le16(network->atim_window); } else { memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN); priv->assoc_request.atim_window = 0; } - priv->assoc_request.listen_interval = network->listen_interval; + priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval); err = ipw_send_ssid(priv, priv->essid, priv->essid_len); if (err) { @@ -7768,11 +7741,11 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ + ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total header+data */ /* Big bitfield of all the fields we provide in radiotap */ - ipw_rt->rt_hdr.it_present = - ((1 << IEEE80211_RADIOTAP_TSFT) | + ipw_rt->rt_hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_TSFT) | (1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | @@ -7801,7 +7774,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); } else { /* 802.11g */ ipw_rt->rt_chbitmask = - (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); + cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); } /* set the rate in multiples of 500k/s */ @@ -7982,14 +7955,14 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = sizeof(*ipw_rt); /* total header+data */ + ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */ /* Set the size of the skb to the size of the frame */ - skb_put(skb, ipw_rt->rt_hdr.it_len + len); + skb_put(skb, sizeof(*ipw_rt) + len); /* Big bitfield of all the fields we provide in radiotap */ - ipw_rt->rt_hdr.it_present = - ((1 << IEEE80211_RADIOTAP_TSFT) | + ipw_rt->rt_hdr.it_present = cpu_to_le32( + (1 << IEEE80211_RADIOTAP_TSFT) | (1 << IEEE80211_RADIOTAP_FLAGS) | (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | @@ -8018,7 +7991,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); } else { /* 802.11g */ ipw_rt->rt_chbitmask = - (IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); + cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); } /* set the rate in multiples of 500k/s */ @@ -8912,6 +8885,8 @@ static int ipw_wx_get_range(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE; + IPW_DEBUG_WX("GET Range\n"); return 0; } @@ -10348,7 +10323,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, tfd->u.data.chunk_ptr[i] = cpu_to_le32(pci_map_single (priv->pci_dev, skb->data, - tfd->u.data.chunk_len[i], + remaining_bytes, PCI_DMA_TODEVICE)); tfd->u.data.num_chunks = @@ -10443,24 +10418,24 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION; rt_hdr->it_pad = 0; rt_hdr->it_present = 0; /* after all, it's just an idea */ - rt_hdr->it_present |= (1 << IEEE80211_RADIOTAP_CHANNEL); + rt_hdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL); - *(u16*)skb_put(dst, sizeof(u16)) = cpu_to_le16( + *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16( ieee80211chan2mhz(priv->channel)); if (priv->channel > 14) /* 802.11a */ - *(u16*)skb_put(dst, sizeof(u16)) = + *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ); else if (priv->ieee->mode == IEEE_B) /* 802.11b */ - *(u16*)skb_put(dst, sizeof(u16)) = + *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ); else /* 802.11g */ - *(u16*)skb_put(dst, sizeof(u16)) = + *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ); - rt_hdr->it_len = dst->len; + rt_hdr->it_len = cpu_to_le16(dst->len); skb_copy_from_linear_data(src, skb_put(dst, len), len); @@ -10873,9 +10848,9 @@ static void shim__set_security(struct net_device *dev, #if 0 if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) && (((priv->assoc_request.capability & - WLAN_CAPABILITY_PRIVACY) && !sec->enabled) || + cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) || (!(priv->assoc_request.capability & - WLAN_CAPABILITY_PRIVACY) && sec->enabled))) { + cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) { IPW_DEBUG_ASSOC("Disassociating due to capability " "change.\n"); ipw_disassociate(priv); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index bec8e37a1738..fdc187e0769d 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -267,25 +267,25 @@ enum connection_manager_assoc_states { #define CW_MIN_CCK 31 #define CW_MAX_CCK 1023 -#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM -#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM -#define QOS_TX2_CW_MIN_OFDM ( (CW_MIN_OFDM + 1) / 2 - 1 ) -#define QOS_TX3_CW_MIN_OFDM ( (CW_MIN_OFDM + 1) / 4 - 1 ) - -#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK -#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK -#define QOS_TX2_CW_MIN_CCK ( (CW_MIN_CCK + 1) / 2 - 1 ) -#define QOS_TX3_CW_MIN_CCK ( (CW_MIN_CCK + 1) / 4 - 1 ) - -#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM -#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM -#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM -#define QOS_TX3_CW_MAX_OFDM ( (CW_MIN_OFDM + 1) / 2 - 1 ) - -#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK -#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK -#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK -#define QOS_TX3_CW_MAX_CCK ( (CW_MIN_CCK + 1) / 2 - 1 ) +#define QOS_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define QOS_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define QOS_TX2_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1) +#define QOS_TX3_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1) + +#define QOS_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define QOS_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define QOS_TX2_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1) +#define QOS_TX3_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/4 - 1) + +#define QOS_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define QOS_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define QOS_TX2_CW_MAX_OFDM cpu_to_le16(CW_MIN_OFDM) +#define QOS_TX3_CW_MAX_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1) + +#define QOS_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define QOS_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define QOS_TX2_CW_MAX_CCK cpu_to_le16(CW_MIN_CCK) +#define QOS_TX3_CW_MAX_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1) #define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE) #define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE) @@ -299,33 +299,33 @@ enum connection_manager_assoc_states { #define QOS_TX0_TXOP_LIMIT_CCK 0 #define QOS_TX1_TXOP_LIMIT_CCK 0 -#define QOS_TX2_TXOP_LIMIT_CCK 6016 -#define QOS_TX3_TXOP_LIMIT_CCK 3264 +#define QOS_TX2_TXOP_LIMIT_CCK cpu_to_le16(6016) +#define QOS_TX3_TXOP_LIMIT_CCK cpu_to_le16(3264) #define QOS_TX0_TXOP_LIMIT_OFDM 0 #define QOS_TX1_TXOP_LIMIT_OFDM 0 -#define QOS_TX2_TXOP_LIMIT_OFDM 3008 -#define QOS_TX3_TXOP_LIMIT_OFDM 1504 +#define QOS_TX2_TXOP_LIMIT_OFDM cpu_to_le16(3008) +#define QOS_TX3_TXOP_LIMIT_OFDM cpu_to_le16(1504) -#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM -#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM -#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM -#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM +#define DEF_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define DEF_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define DEF_TX2_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) +#define DEF_TX3_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM) -#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK -#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK -#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK -#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK +#define DEF_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define DEF_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define DEF_TX2_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) +#define DEF_TX3_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK) -#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM -#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM -#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM -#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM +#define DEF_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define DEF_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define DEF_TX2_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) +#define DEF_TX3_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM) -#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK -#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK -#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK -#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK +#define DEF_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define DEF_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define DEF_TX2_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) +#define DEF_TX3_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK) #define DEF_TX0_AIFS 0 #define DEF_TX1_AIFS 0 @@ -388,18 +388,18 @@ struct clx2_queue { } __attribute__ ((packed)); struct machdr32 { - u16 frame_ctl; + __le16 frame_ctl; u16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; u8 addr3[MACADRR_BYTE_LEN]; u16 seq_ctrl; // more endians! u8 addr4[MACADRR_BYTE_LEN]; - u16 qos_ctrl; + __le16 qos_ctrl; } __attribute__ ((packed)); struct machdr30 { - u16 frame_ctl; + __le16 frame_ctl; u16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; @@ -409,17 +409,17 @@ struct machdr30 { } __attribute__ ((packed)); struct machdr26 { - u16 frame_ctl; + __le16 frame_ctl; u16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; u8 addr3[MACADRR_BYTE_LEN]; u16 seq_ctrl; // more endians! - u16 qos_ctrl; + __le16 qos_ctrl; } __attribute__ ((packed)); struct machdr24 { - u16 frame_ctl; + __le16 frame_ctl; u16 duration; // watch out for endians! u8 addr1[MACADRR_BYTE_LEN]; u8 addr2[MACADRR_BYTE_LEN]; @@ -466,15 +466,15 @@ struct tfd_command { struct tfd_data { /* Header */ - u32 work_area_ptr; + __le32 work_area_ptr; u8 station_number; /* 0 for BSS */ u8 reserved1; - u16 reserved2; + __le16 reserved2; /* Tx Parameters */ u8 cmd_id; u8 seq_num; - u16 len; + __le16 len; u8 priority; u8 tx_flags; u8 tx_flags_ext; @@ -482,11 +482,11 @@ struct tfd_data { u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH]; u8 rate; u8 antenna; - u16 next_packet_duration; - u16 next_frag_len; - u16 back_off_counter; //////txop; + __le16 next_packet_duration; + __le16 next_frag_len; + __le16 back_off_counter; //////txop; u8 retrylimit; - u16 cwcurrent; + __le16 cwcurrent; u8 reserved3; /* 802.11 MAC Header */ @@ -498,9 +498,9 @@ struct tfd_data { } tfd; /* Payload DMA info */ - u32 num_chunks; - u32 chunk_ptr[NUM_TFD_CHUNKS]; - u16 chunk_len[NUM_TFD_CHUNKS]; + __le32 num_chunks; + __le32 chunk_ptr[NUM_TFD_CHUNKS]; + __le16 chunk_len[NUM_TFD_CHUNKS]; } __attribute__ ((packed)); struct txrx_control_flags { @@ -547,14 +547,14 @@ struct clx2_tx_queue { // Used for passing to driver number of successes and failures per rate struct rate_histogram { union { - u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; - u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; - u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; } success; union { - u32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; - u32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; - u32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; } failed; } __attribute__ ((packed)); @@ -602,13 +602,13 @@ struct notif_scan_complete { } __attribute__ ((packed)); struct notif_frag_length { - u16 frag_length; - u16 reserved; + __le16 frag_length; + __le16 reserved; } __attribute__ ((packed)); struct notif_beacon_state { - u32 state; - u32 number; + __le32 state; + __le32 number; } __attribute__ ((packed)); struct notif_tgi_tx_key { @@ -627,7 +627,7 @@ struct notif_link_deterioration { u8 modulation; struct rate_histogram histogram; u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */ - u16 silence_count; + __le16 silence_count; } __attribute__ ((packed)); struct notif_association { @@ -645,14 +645,14 @@ struct notif_calibration { } __attribute__ ((packed)); struct notif_noise { - u32 value; + __le32 value; } __attribute__ ((packed)); struct ipw_rx_notification { u8 reserved[8]; u8 subtype; u8 flags; - u16 size; + __le16 size; union { struct notif_association assoc; struct notif_authenticate auth; @@ -669,7 +669,7 @@ struct ipw_rx_notification { } __attribute__ ((packed)); struct ipw_rx_frame { - u32 reserved1; + __le32 reserved1; u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER u8 received_channel; // The channel that this frame was received on. // Note that for .11b this does not have to be @@ -680,14 +680,14 @@ struct ipw_rx_frame { u8 rssi; u8 agc; u8 rssi_dbm; - u16 signal; - u16 noise; + __le16 signal; + __le16 noise; u8 antennaAndPhy; u8 control; // control bit should be on in bg u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate // is identical) u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen - u16 length; + __le16 length; u8 data[0]; } __attribute__ ((packed)); @@ -827,14 +827,14 @@ struct ipw_tgi_tx_key { u8 station_index; u8 flags; u8 key[16]; - u32 tx_counter[2]; + __le32 tx_counter[2]; } __attribute__ ((packed)); #define IPW_SCAN_CHANNELS 54 struct ipw_scan_request { u8 scan_type; - u16 dwell_time; + __le16 dwell_time; u8 channels_list[IPW_SCAN_CHANNELS]; u8 channels_reserved[3]; } __attribute__ ((packed)); @@ -849,11 +849,11 @@ enum { }; struct ipw_scan_request_ext { - u32 full_scan_index; + __le32 full_scan_index; u8 channels_list[IPW_SCAN_CHANNELS]; u8 scan_type[IPW_SCAN_CHANNELS / 2]; u8 reserved; - u16 dwell_time[IPW_SCAN_TYPES]; + __le16 dwell_time[IPW_SCAN_TYPES]; } __attribute__ ((packed)); static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) @@ -881,20 +881,20 @@ struct ipw_associate { u8 auth_type:4, auth_key:4; u8 assoc_type; u8 reserved; - u16 policy_support; + __le16 policy_support; u8 preamble_length; u8 ieee_mode; u8 bssid[ETH_ALEN]; - u32 assoc_tsf_msw; - u32 assoc_tsf_lsw; - u16 capability; - u16 listen_interval; - u16 beacon_interval; + __le32 assoc_tsf_msw; + __le32 assoc_tsf_lsw; + __le16 capability; + __le16 listen_interval; + __le16 beacon_interval; u8 dest[ETH_ALEN]; - u16 atim_window; + __le16 atim_window; u8 smr; u8 reserved1; - u16 reserved2; + __le16 reserved2; } __attribute__ ((packed)); struct ipw_supported_rates { @@ -906,13 +906,13 @@ struct ipw_supported_rates { } __attribute__ ((packed)); struct ipw_rts_threshold { - u16 rts_threshold; - u16 reserved; + __le16 rts_threshold; + __le16 reserved; } __attribute__ ((packed)); struct ipw_frag_threshold { - u16 frag_threshold; - u16 reserved; + __le16 frag_threshold; + __le16 reserved; } __attribute__ ((packed)); struct ipw_retry_limit { @@ -931,7 +931,7 @@ struct ipw_dino_config { struct ipw_aironet_info { u8 id; u8 length; - u16 reserved; + __le16 reserved; } __attribute__ ((packed)); struct ipw_rx_key { @@ -977,12 +977,12 @@ struct ipw_tx_power { struct ipw_rsn_capabilities { u8 id; u8 length; - u16 version; + __le16 version; } __attribute__ ((packed)); struct ipw_sensitivity_calib { - u16 beacon_rssi_raw; - u16 reserved; + __le16 beacon_rssi_raw; + __le16 reserved; } __attribute__ ((packed)); /** @@ -1156,8 +1156,8 @@ struct ipw_rt_hdr { u64 rt_tsf; /* TSF */ u8 rt_flags; /* radiotap packet flags */ u8 rt_rate; /* rate in 500kb/s */ - u16 rt_channel; /* channel in mhz */ - u16 rt_chbitmask; /* channel bitfield */ + __le16 rt_channel; /* channel in mhz */ + __le16 rt_chbitmask; /* channel bitfield */ s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ s8 rt_dbmnoise; u8 rt_antenna; /* antenna number */ @@ -1759,7 +1759,7 @@ enum { #define HC_IBSS_RECONF 4 #define HC_DISASSOC_QUIET 5 -#define HC_QOS_SUPPORT_ASSOC 0x01 +#define HC_QOS_SUPPORT_ASSOC cpu_to_le16(0x01) #define IPW_RATE_CAPABILITIES 1 #define IPW_RATE_CONNECT 0 diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index 8d52a26c248a..d1af938b9aa6 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,24 +1,64 @@ -config IWLWIFI - bool "Intel Wireless WiFi Link Drivers" +config IWL4965 + tristate "Intel Wireless WiFi 4965AGN" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER - default n ---help--- - Select to enable drivers based on the iwlwifi project. This - project provides a common foundation for Intel's wireless - drivers designed to use the mac80211 subsystem. - - See <file:Documentation/networking/README.iwlwifi> for - information on the capabilities currently enabled in this - driver and for tips for debugging issues and problems. - -config IWLWIFI_DEBUG - bool "Enable full debugging output in iwlwifi drivers" - depends on IWLWIFI - default y + Select to build the driver supporting the: + + Intel Wireless WiFi Link 4965AGN + + This driver uses the kernel's mac80211 subsystem. + + In order to use this driver, you will need a microcode (uCode) + image for it. You can obtain the microcode from: + + <http://intellinuxwireless.org/>. + + The microcode is typically installed in /lib/firmware. You can + look in the hotplug script /etc/hotplug/firmware.agent to + determine which directory FIRMWARE_DIR is set to when the script + runs. + + If you want to compile the driver as a module ( = code which can be + inserted in and remvoed from the running kernel whenever you want), + say M here and read <file:Documentation/kbuild/modules.txt>. The + module will be called iwl4965.ko. + +config IWL4965_QOS + bool "Enable Wireless QoS in iwl4965 driver" + depends on IWL4965 ---help--- - This option will enable debug tracing output for the iwlwifi - drivers. + This option will enable wireless quality of service (QoS) for the + iwl4965 driver. + +config IWL4965_HT + bool "Enable 802.11n HT features in iwl4965 driver" + depends on EXPERIMENTAL + depends on IWL4965 && IWL4965_QOS + depends on n + ---help--- + This option enables IEEE 802.11n High Throughput features + for the iwl4965 driver. + +config IWL4965_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwl4965 driver" + depends on IWL4965 + ---help--- + This option will enable spectrum measurement for the iwl4965 driver. + +config IWL4965_SENSITIVITY + bool "Enable Sensitivity Calibration in iwl4965 driver" + depends on IWL4965 + ---help--- + This option will enable sensitivity calibration for the iwl4965 + driver. + +config IWL4965_DEBUG + bool "Enable full debugging output in iwl4965 driver" + depends on IWL4965 + ---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 @@ -33,96 +73,74 @@ config IWLWIFI_DEBUG % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level You can find the list of debug mask values in: - drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h + 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 IWLWIFI_SENSITIVITY - bool "Enable Sensitivity Calibration in iwlwifi drivers" - depends on IWLWIFI - default y - ---help--- - This option will enable sensitivity calibration for the iwlwifi - drivers. - -config IWLWIFI_SPECTRUM_MEASUREMENT - bool "Enable Spectrum Measurement in iwlwifi drivers" - depends on IWLWIFI - default y - ---help--- - This option will enable spectrum measurement for the iwlwifi drivers. - -config IWLWIFI_QOS - bool "Enable Wireless QoS in iwlwifi drivers" - depends on IWLWIFI - default y - ---help--- - This option will enable wireless quality of service (QoS) for the - iwlwifi drivers. - -config IWLWIFI_HT - bool "Enable 802.11n HT features in iwlwifi drivers" - depends on EXPERIMENTAL - depends on IWLWIFI && MAC80211_HT - default n - ---help--- - This option enables IEEE 802.11n High Throughput features - for the iwlwifi drivers. - -config IWL4965 - tristate "Intel Wireless WiFi 4965AGN" - depends on m && IWLWIFI && EXPERIMENTAL - default m +config IWL3945 + tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" + depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select FW_LOADER ---help--- Select to build the driver supporting the: - Intel Wireless WiFi Link 4965AGN + Intel PRO/Wireless 3945ABG/BG Network Connection This driver uses the kernel's mac80211 subsystem. - See <file:Documentation/networking/README.iwlwifi> for - information on the capabilities currently enabled in this - driver and for tips for debugging any issues or problems. - In order to use this driver, you will need a microcode (uCode) image for it. You can obtain the microcode from: <http://intellinuxwireless.org/>. - See the above referenced README.iwlwifi for information on where - to install the microcode images. + The microcode is typically installed in /lib/firmware. You can + look in the hotplug script /etc/hotplug/firmware.agent to + determine which directory FIRMWARE_DIR is set to when the script + runs. If you want to compile the driver as a module ( = code which can be inserted in and remvoed from the running kernel whenever you want), say M here and read <file:Documentation/kbuild/modules.txt>. The - module will be called iwl4965.ko. + module will be called iwl3945.ko. -config IWL3945 - tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" - depends on m && IWLWIFI && EXPERIMENTAL - default m +config IWL3945_QOS + bool "Enable Wireless QoS in iwl3945 driver" + depends on IWL3945 ---help--- - Select to build the driver supporting the: + This option will enable wireless quality of service (QoS) for the + iwl3945 driver. - Intel PRO/Wireless 3945ABG/BG Network Connection +config IWL3945_SPECTRUM_MEASUREMENT + bool "Enable Spectrum Measurement in iwl3945 drivers" + depends on IWL3945 + ---help--- + This option will enable spectrum measurement for the iwl3945 driver. - This driver uses the kernel's mac80211 subsystem. +config IWL3945_DEBUG + bool "Enable full debugging output in iwl3945 driver" + depends on IWL3945 + ---help--- + This option will enable debug tracing output for the iwl3945 + 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 - See <file:Documentation/networking/README.iwlwifi> for - information on the capabilities currently enabled in this - driver and for tips for debugging any issues or problems. + /sys/bus/pci/drivers/${DRIVER}/debug_level - In order to use this driver, you will need a microcode (uCode) - image for it. You can obtain the microcode from: + This entry will only exist if this option is enabled. - <http://intellinuxwireless.org/>. + To set a value, simply echo an 8-byte hex value to the same file: + + % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level - See the above referenced README.iwlwifi for information on where - to install the microcode images. + You can find the list of debug mask values in: + drivers/net/wireless/iwlwifi/iwl-3945-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. - If you want to compile the driver as a module ( = code which can be - inserted in and remvoed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt>. The - module will be called iwl3945.ko. diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 9de8d7f6efa3..46bb2c7d11dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -8,7 +8,7 @@ * Copyright(c) 2005 - 2007 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 Geeral Public License as + * 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 @@ -60,9 +60,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +/* + * Please use this file (iwl-3945-commands.h) only for uCode API definitions. + * Please use iwl-3945-hw.h for hardware-related definitions. + * Please use iwl-3945.h for driver implementation definitions. + */ -#ifndef __iwl_commands_h__ -#define __iwl_commands_h__ +#ifndef __iwl_3945_commands_h__ +#define __iwl_3945_commands_h__ enum { REPLY_ALIVE = 0x1, @@ -80,9 +85,7 @@ enum { REPLY_REMOVE_ALL_STA = 0x1a, /* not used */ /* RX, TX, LEDs */ -#if IWL == 3945 REPLY_3945_RX = 0x1b, /* 3945 only */ -#endif REPLY_TX = 0x1c, REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, @@ -118,10 +121,10 @@ enum { REPLY_TX_PWR_TABLE_CMD = 0x97, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* BT config command */ + /* Bluetooth device coexistance config command */ REPLY_BT_CONFIG = 0x9b, - /* 4965 Statistics */ + /* Statistics */ REPLY_STATISTICS_CMD = 0x9c, STATISTICS_NOTIFICATION = 0x9d, @@ -132,46 +135,85 @@ enum { /* Missed beacons notification */ MISSED_BEACONS_NOTIFICATION = 0xa2, -#if IWL == 4965 - REPLY_CT_KILL_CONFIG_CMD = 0xa4, - SENSITIVITY_CMD = 0xa8, - REPLY_PHY_CALIBRATION_CMD = 0xb0, - REPLY_RX_PHY_CMD = 0xc0, - REPLY_RX_MPDU_CMD = 0xc1, - REPLY_4965_RX = 0xc3, - REPLY_COMPRESSED_BA = 0xc5, -#endif REPLY_MAX = 0xff }; /****************************************************************************** * (0) - * Header + * Commonly used structures and definitions: + * Command header, txpower * *****************************************************************************/ +/* iwl3945_cmd_header flags value */ #define IWL_CMD_FAILED_MSK 0x40 -struct iwl_cmd_header { - u8 cmd; - u8 flags; - /* We have 15 LSB to use as we please (MSB indicates - * a frame Rx'd from the HW). We encode the following - * information into the sequence field: +/** + * struct iwl3945_cmd_header + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + */ +struct iwl3945_cmd_header { + u8 cmd; /* Command ID: REPLY_RXON, etc. */ + u8 flags; /* IWL_CMD_* */ + /* + * The driver sets up the sequence number to values of its chosing. + * uCode does not use this value, but passes it back to the driver + * when sending the response to each driver-originated command, so + * the driver can match the response to the command. Since the values + * don't get used by uCode, the driver may set up an arbitrary format. * - * 0:7 index in fifo - * 8:13 fifo selection - * 14:14 bit indicating if this packet references the 'extra' - * storage at the end of the memory queue - * 15:15 (Rx indication) + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For + * example, uCode issues REPLY_3945_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. * + * The Linux driver uses the following format: + * + * 0:7 index/position within Tx queue + * 8:13 Tx queue selection + * 14:14 driver sets this to indicate command is in the 'huge' + * storage at the end of the command buffers, i.e. scan cmd + * 15:15 uCode sets this in uCode-originated response/notification */ __le16 sequence; - /* command data follows immediately */ + /* command or response/notification data follows immediately */ u8 data[0]; } __attribute__ ((packed)); +/** + * struct iwl3945_tx_power + * + * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH + * + * Each entry contains two values: + * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained + * linear value that multiplies the output of the digital signal processor, + * before being sent to the analog radio. + * 2) Radio gain. This sets the analog gain of the radio Tx path. + * It is a coarser setting, and behaves in a logarithmic (dB) fashion. + * + * Driver obtains values from struct iwl3945_tx_power power_gain_table[][]. + */ +struct iwl3945_tx_power { + u8 tx_gain; /* gain for analog radio */ + u8 dsp_atten; /* gain for DSP */ +} __attribute__ ((packed)); + +/** + * struct iwl3945_power_per_rate + * + * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + */ +struct iwl3945_power_per_rate { + u8 rate; /* plcp */ + struct iwl3945_tx_power tpc; + u8 reserved; +} __attribute__ ((packed)); + /****************************************************************************** * (0a) * Alive and Error Commands & Responses: @@ -182,15 +224,22 @@ struct iwl_cmd_header { #define INITIALIZE_SUBTYPE (9) /* - * REPLY_ALIVE = 0x1 (response only, not a command) + * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) + * + * uCode issues this "initialize alive" notification once the initialization + * uCode image has completed its work, and is ready to load the runtime image. + * This is the *first* "alive" notification that the driver will receive after + * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. + * + * See comments documenting "BSM" (bootstrap state machine). */ -struct iwl_alive_resp { +struct iwl3945_init_alive_resp { u8 ucode_minor; u8 ucode_major; __le16 reserved1; u8 sw_rev[8]; u8 ver_type; - u8 ver_subtype; + u8 ver_subtype; /* "9" for initialize alive */ __le16 reserved2; __le32 log_event_table_ptr; __le32 error_event_table_ptr; @@ -198,29 +247,41 @@ struct iwl_alive_resp { __le32 is_valid; } __attribute__ ((packed)); -struct iwl_init_alive_resp { + +/** + * REPLY_ALIVE = 0x1 (response only, not a command) + * + * uCode issues this "alive" notification once the runtime image is ready + * to receive commands from the driver. This is the *second* "alive" + * notification that the driver will receive after rebooting uCode; + * this "alive" is indicated by subtype field != 9. + * + * See comments documenting "BSM" (bootstrap state machine). + * + * This response includes two pointers to structures within the device's + * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging: + * + * 1) log_event_table_ptr indicates base of the event log. This traces + * a 256-entry history of uCode execution within a circular buffer. + * + * 2) error_event_table_ptr indicates base of the error log. This contains + * information about any uCode error that occurs. + * + * The Linux driver can print both logs to the system log when a uCode error + * occurs. + */ +struct iwl3945_alive_resp { u8 ucode_minor; u8 ucode_major; __le16 reserved1; u8 sw_rev[8]; u8 ver_type; - u8 ver_subtype; + u8 ver_subtype; /* not "9" for runtime alive */ __le16 reserved2; - __le32 log_event_table_ptr; - __le32 error_event_table_ptr; + __le32 log_event_table_ptr; /* SRAM address for event log */ + __le32 error_event_table_ptr; /* SRAM address for error log */ __le32 timestamp; __le32 is_valid; - -#if IWL == 4965 - /* calibration values from "initialize" uCode */ - __le32 voltage; /* signed */ - __le32 therm_r1[2]; /* signed 1st for normal, 2nd for FAT channel */ - __le32 therm_r2[2]; /* signed */ - __le32 therm_r3[2]; /* signed */ - __le32 therm_r4[2]; /* signed */ - __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, - * 2 Tx chains */ -#endif } __attribute__ ((packed)); union tsf { @@ -232,14 +293,12 @@ union tsf { /* * REPLY_ERROR = 0x2 (response only, not a command) */ -struct iwl_error_resp { +struct iwl3945_error_resp { __le32 error_type; u8 cmd_id; u8 reserved1; __le16 bad_cmd_seq_num; -#if IWL == 3945 __le16 reserved2; -#endif __le32 error_info; union tsf timestamp; } __attribute__ ((packed)); @@ -300,10 +359,24 @@ enum { /* transfer to host non bssid beacons in associated state */ #define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) -/* +/** * REPLY_RXON = 0x10 (command, has simple generic response) + * + * RXON tunes the radio tuner to a service channel, and sets up a number + * of parameters that are used primarily for Rx, but also for Tx operations. + * + * NOTE: When tuning to a new channel, driver must set the + * RXON_FILTER_ASSOC_MSK to 0. This will clear station-dependent + * info within the device, including the station tables, tx retry + * rate tables, and txpower tables. Driver must build a new station + * table and txpower table before transmitting anything on the RXON + * channel. + * + * NOTE: All RXONs wipe clean the internal txpower table. Driver must + * issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10), + * regardless of whether RXON_FILTER_ASSOC_MSK is set. */ -struct iwl_rxon_cmd { +struct iwl3945_rxon_cmd { u8 node_addr[6]; __le16 reserved1; u8 bssid_addr[6]; @@ -312,45 +385,31 @@ struct iwl_rxon_cmd { __le16 reserved3; u8 dev_type; u8 air_propagation; -#if IWL == 3945 __le16 reserved4; -#elif IWL == 4965 - __le16 rx_chain; -#endif u8 ofdm_basic_rates; u8 cck_basic_rates; __le16 assoc_id; __le32 flags; __le32 filter_flags; __le16 channel; -#if IWL == 3945 __le16 reserved5; -#elif IWL == 4965 - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; -#endif } __attribute__ ((packed)); /* * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) */ -struct iwl_rxon_assoc_cmd { +struct iwl3945_rxon_assoc_cmd { __le32 flags; __le32 filter_flags; u8 ofdm_basic_rates; u8 cck_basic_rates; -#if IWL == 4965 - u8 ofdm_ht_single_stream_basic_rates; - u8 ofdm_ht_dual_stream_basic_rates; - __le16 rx_chain_select_flags; -#endif __le16 reserved; } __attribute__ ((packed)); /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) */ -struct iwl_rxon_time_cmd { +struct iwl3945_rxon_time_cmd { union tsf timestamp; __le16 beacon_interval; __le16 atim_window; @@ -359,52 +418,23 @@ struct iwl_rxon_time_cmd { __le16 reserved; } __attribute__ ((packed)); -struct iwl_tx_power { - u8 tx_gain; /* gain for analog radio */ - u8 dsp_atten; /* gain for DSP */ -} __attribute__ ((packed)); - -#if IWL == 3945 -struct iwl_power_per_rate { - u8 rate; /* plcp */ - struct iwl_tx_power tpc; - u8 reserved; -} __attribute__ ((packed)); - -#elif IWL == 4965 -#define POWER_TABLE_NUM_ENTRIES 33 -#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 -#define POWER_TABLE_CCK_ENTRY 32 -struct tx_power_dual_stream { - __le32 dw; -} __attribute__ ((packed)); - -struct iwl_tx_power_db { - struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; -} __attribute__ ((packed)); -#endif - /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl_channel_switch_cmd { +struct iwl3945_channel_switch_cmd { u8 band; u8 expect_beacon; __le16 channel; __le32 rxon_flags; __le32 rxon_filter_flags; __le32 switch_time; -#if IWL == 3945 - struct iwl_power_per_rate power[IWL_MAX_RATES]; -#elif IWL == 4965 - struct iwl_tx_power_db tx_power; -#endif + struct iwl3945_power_per_rate power[IWL_MAX_RATES]; } __attribute__ ((packed)); /* * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) */ -struct iwl_csa_notification { +struct iwl3945_csa_notification { __le16 band; __le16 channel; __le32 status; /* 0 - OK, 1 - fail */ @@ -415,7 +445,24 @@ struct iwl_csa_notification { * Quality-of-Service (QOS) Commands & Responses: * *****************************************************************************/ -struct iwl_ac_qos { + +/** + * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM + * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd + * + * @cw_min: Contention window, start value in numbers of slots. + * Should be a power-of-2, minus 1. Device's default is 0x0f. + * @cw_max: Contention window, max value in numbers of slots. + * Should be a power-of-2, minus 1. Device's default is 0x3f. + * @aifsn: Number of slots in Arbitration Interframe Space (before + * performing random backoff timing prior to Tx). Device default 1. + * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. + * + * Device will automatically increase contention window by (2*CW) + 1 for each + * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW + * value, to cap the CW value. + */ +struct iwl3945_ac_qos { __le16 cw_min; __le16 cw_max; u8 aifsn; @@ -428,18 +475,18 @@ struct iwl_ac_qos { #define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) #define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) -/* - * TXFIFO Queue number defines - */ -/* number of Access categories (AC) (EDCA), queues 0..3 */ +/* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 /* * REPLY_QOS_PARAM = 0x13 (command, has simple generic response) + * + * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs + * 0: Background, 1: Best Effort, 2: Video, 3: Voice. */ -struct iwl_qosparam_cmd { +struct iwl3945_qosparam_cmd { __le32 qos_flags; - struct iwl_ac_qos ac[AC_NUM]; + struct iwl3945_ac_qos ac[AC_NUM]; } __attribute__ ((packed)); /****************************************************************************** @@ -450,24 +497,21 @@ struct iwl_qosparam_cmd { /* * Multi station support */ + +/* Special, dedicated locations within device's station table */ #define IWL_AP_ID 0 #define IWL_MULTICAST_ID 1 #define IWL_STA_ID 2 - #define IWL3945_BROADCAST_ID 24 #define IWL3945_STATION_COUNT 25 -#define IWL4965_BROADCAST_ID 31 -#define IWL4965_STATION_COUNT 32 - #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#if IWL == 3945 -#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1<<2); -#endif -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1<<8); +#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1 << 2); +#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); +/* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ @@ -480,13 +524,10 @@ struct iwl_qosparam_cmd { #define STA_KEY_FLG_KEYID_POS 8 #define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) -/* modify flags */ +/* Flags indicate whether to modify vs. don't change various station params */ #define STA_MODIFY_KEY_MASK 0x01 #define STA_MODIFY_TID_DISABLE_TX 0x02 #define STA_MODIFY_TX_RATE_MSK 0x04 -#define STA_MODIFY_ADDBA_TID_MSK 0x08 -#define STA_MODIFY_DELBA_TID_MSK 0x10 -#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) /* * Antenna masks: @@ -500,7 +541,7 @@ struct iwl_qosparam_cmd { #define RATE_MCS_ANT_B_MSK 0x8000 #define RATE_MCS_ANT_AB_MSK 0xc000 -struct iwl_keyinfo { +struct iwl3945_keyinfo { __le16 key_flags; u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ u8 reserved1; @@ -509,6 +550,18 @@ struct iwl_keyinfo { u8 key[16]; /* 16-byte unicast decryption key */ } __attribute__ ((packed)); +/** + * struct sta_id_modify + * @addr[ETH_ALEN]: station's MAC address + * @sta_id: index of station in uCode's station table + * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change + * + * Driver selects unused table index when adding new station, + * or the index to a pre-existing station entry when modifying that station. + * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP). + * + * modify_mask flags select which parameters to modify vs. leave alone. + */ struct sta_id_modify { u8 addr[ETH_ALEN]; __le16 reserved1; @@ -519,36 +572,67 @@ struct sta_id_modify { /* * REPLY_ADD_STA = 0x18 (command) + * + * The device contains an internal table of per-station information, + * with info on security keys, aggregation parameters, and Tx rates for + * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD, + * 3945 uses REPLY_RATE_SCALE to set up rate tables). + * + * REPLY_ADD_STA sets up the table entry for one station, either creating + * a new entry, or modifying a pre-existing one. + * + * NOTE: RXON command (without "associated" bit set) wipes the station table + * clean. Moving into RF_KILL state does this also. Driver must set up + * new station table before transmitting anything on the RXON channel + * (except active scans or active measurements; those commands carry + * their own txpower/rate setup data). + * + * When getting started on a new channel, driver must set up the + * IWL_BROADCAST_ID entry (last entry in the table). For a client + * station in a BSS, once an AP is selected, driver sets up the AP STA + * in the IWL_AP_ID entry (1st entry in the table). BROADCAST and AP + * are all that are needed for a BSS client station. If the device is + * used as AP, or in an IBSS network, driver must set up station table + * entries for all STAs in network, starting with index IWL_STA_ID. */ -struct iwl_addsta_cmd { - u8 mode; +struct iwl3945_addsta_cmd { + u8 mode; /* 1: modify existing, 0: add new station */ u8 reserved[3]; struct sta_id_modify sta; - struct iwl_keyinfo key; - __le32 station_flags; - __le32 station_flags_msk; + struct iwl3945_keyinfo key; + __le32 station_flags; /* STA_FLG_* */ + __le32 station_flags_msk; /* STA_FLG_* */ + + /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) + * corresponding to bit (e.g. bit 5 controls TID 5). + * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ __le16 tid_disable_tx; -#if IWL == 3945 + __le16 rate_n_flags; -#else - __le16 reserved1; -#endif + + /* TID for which to add block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ u8 add_immediate_ba_tid; + + /* TID for which to remove block-ack support. + * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ u8 remove_immediate_ba_tid; + + /* Starting Sequence Number for added block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ __le16 add_immediate_ba_ssn; -#if IWL == 4965 - __le32 reserved2; -#endif } __attribute__ ((packed)); +#define ADD_STA_SUCCESS_MSK 0x1 +#define ADD_STA_NO_ROOM_IN_TABLE 0x2 +#define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 /* * REPLY_ADD_STA = 0x18 (response) */ -struct iwl_add_sta_resp { - u8 status; +struct iwl3945_add_sta_resp { + u8 status; /* ADD_STA_* */ } __attribute__ ((packed)); -#define ADD_STA_SUCCESS_MSK 0x1 /****************************************************************************** * (4) @@ -556,7 +640,7 @@ struct iwl_add_sta_resp { * *****************************************************************************/ -struct iwl_rx_frame_stats { +struct iwl3945_rx_frame_stats { u8 phy_count; u8 id; u8 rssi; @@ -566,7 +650,7 @@ struct iwl_rx_frame_stats { u8 payload[0]; } __attribute__ ((packed)); -struct iwl_rx_frame_hdr { +struct iwl3945_rx_frame_hdr { __le16 channel; __le16 phy_flags; u8 reserved1; @@ -596,7 +680,7 @@ struct iwl_rx_frame_hdr { #define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) #define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) -struct iwl_rx_frame_end { +struct iwl3945_rx_frame_end { __le32 status; __le64 timestamp; __le32 beacon_timestamp; @@ -610,10 +694,10 @@ struct iwl_rx_frame_end { * The actual offsets of the hdr and end are dynamic based on * stats.phy_count */ -struct iwl_rx_frame { - struct iwl_rx_frame_stats stats; - struct iwl_rx_frame_hdr hdr; - struct iwl_rx_frame_end end; +struct iwl3945_rx_frame { + struct iwl3945_rx_frame_stats stats; + struct iwl3945_rx_frame_hdr hdr; + struct iwl3945_rx_frame_end end; } __attribute__ ((packed)); /* Fixed (non-configurable) rx data from phy */ @@ -659,36 +743,86 @@ struct iwl4965_rx_mpdu_res_start { * (5) * Tx Commands & Responses: * + * Driver must place each REPLY_TX command into one of the prioritized Tx + * queues in host DRAM, shared between driver and device. When the device's + * Tx scheduler and uCode are preparing to transmit, the device pulls the + * Tx command over the PCI bus via one of the device's Tx DMA channels, + * to fill an internal FIFO from which data will be transmitted. + * + * uCode handles all timing and protocol related to control frames + * (RTS/CTS/ACK), based on flags in the Tx command. + * + * uCode handles retrying Tx when an ACK is expected but not received. + * This includes trying lower data rates than the one requested in the Tx + * command, as set up by the REPLY_RATE_SCALE (for 3945) or + * REPLY_TX_LINK_QUALITY_CMD (4965). + * + * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD. + * This command must be executed after every RXON command, before Tx can occur. *****************************************************************************/ -/* Tx flags */ +/* REPLY_TX Tx flags field */ + +/* 1: Use Request-To-Send protocol before this frame. + * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ #define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) + +/* 1: Transmit Clear-To-Send to self before this frame. + * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. + * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ #define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) + +/* 1: Expect ACK from receiving station + * 0: Don't expect ACK (MAC header's duration field s/b 0) + * Set this for unicast frames, but not broadcast/multicast. */ #define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) + +/* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). + * Tx command's initial_rate_index indicates first rate to try; + * uCode walks through table for additional Tx attempts. + * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. + * This rate will be used for all Tx attempts; it will not be scaled. */ #define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) + +/* 1: Expect immediate block-ack. + * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ #define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) + +/* 1: Frame requires full Tx-Op protection. + * Set this if either RTS or CTS Tx Flag gets set. */ #define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) + +/* Tx antenna selection field; used only for 3945, reserved (0) for 4965. + * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ #define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) #define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) #define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) -/* ucode ignores BT priority for this frame */ +/* 1: Ignore Bluetooth priority for this frame. + * 0: Delay Tx until Bluetooth device is done (normal usage). */ #define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) -/* ucode overrides sequence control */ +/* 1: uCode overrides sequence control field in MAC header. + * 0: Driver provides sequence control field in MAC header. + * Set this for management frames, non-QOS data frames, non-unicast frames, + * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ #define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) -/* signal that this frame is non-last MPDU */ +/* 1: This frame is non-last MPDU; more fragments are coming. + * 0: Last fragment, or not using fragmentation. */ #define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) -/* calculate TSF in outgoing frame */ +/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. + * 0: No TSF required in outgoing frame. + * Set this for transmitting beacons and probe responses. */ #define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) -/* activate TX calibration. */ -#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17) - -/* signals that 2 bytes pad was inserted - after the MAC header */ +/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword + * alignment of frame's payload data field. + * 0: No pad + * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 + * field (but not both). Driver must align frame data (i.e. data following + * MAC header) to DWORD boundary. */ #define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) /* HCCA-AP - disable duration overwriting. */ @@ -705,68 +839,65 @@ struct iwl4965_rx_mpdu_res_start { #define TX_CMD_SEC_KEY128 0x08 /* - * TX command Frame life time - */ - -struct iwl_dram_scratch { - u8 try_cnt; - u8 bt_kill_cnt; - __le16 reserved; -} __attribute__ ((packed)); - -/* * REPLY_TX = 0x1c (command) */ -struct iwl_tx_cmd { +struct iwl3945_tx_cmd { + /* + * MPDU byte count: + * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, + * + 8 byte IV for CCM or TKIP (not used for WEP) + * + Data payload + * + 8-byte MIC (not used for CCM/WEP) + * NOTE: Does not include Tx command bytes, post-MAC pad bytes, + * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i + * Range: 14-2342 bytes. + */ __le16 len; + + /* + * MPDU or MSDU byte count for next frame. + * Used for fragmentation and bursting, but not 11n aggregation. + * Same as "len", but for next frame. Set to 0 if not applicable. + */ __le16 next_frame_len; - __le32 tx_flags; -#if IWL == 3945 + + __le32 tx_flags; /* TX_CMD_FLG_* */ + u8 rate; + + /* Index of recipient station in uCode's station table */ u8 sta_id; u8 tid_tspec; -#elif IWL == 4965 - struct iwl_dram_scratch scratch; - __le32 rate_n_flags; - u8 sta_id; -#endif u8 sec_ctl; -#if IWL == 4965 - u8 initial_rate_index; - u8 reserved; -#endif u8 key[16]; -#if IWL == 3945 union { u8 byte[8]; __le16 word[4]; __le32 dw[2]; } tkip_mic; __le32 next_frame_info; -#elif IWL == 4965 - __le16 next_frame_flags; - __le16 reserved2; -#endif union { __le32 life_time; __le32 attempt; } stop_time; -#if IWL == 3945 u8 supp_rates[2]; -#elif IWL == 4965 - __le32 dram_lsb_ptr; - u8 dram_msb_ptr; -#endif u8 rts_retry_limit; /*byte 50 */ u8 data_retry_limit; /*byte 51 */ -#if IWL == 4965 - u8 tid_tspec; -#endif union { __le16 pm_frame_timeout; __le16 attempt_duration; } timeout; + + /* + * Duration of EDCA burst Tx Opportunity, in 32-usec units. + * Set this if txop time is not specified by HCCA protocol (e.g. by AP). + */ __le16 driver_txop; + + /* + * MAC header goes here, followed by 2 bytes padding if MAC header + * length is 26 or 30 bytes, followed by payload data + */ u8 payload[0]; struct ieee80211_hdr hdr[0]; } __attribute__ ((packed)); @@ -838,104 +969,36 @@ enum { TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; -/* ******************************* - * TX aggregation state - ******************************* */ - -enum { - AGG_TX_STATE_TRANSMITTED = 0x00, - AGG_TX_STATE_UNDERRUN_MSK = 0x01, - AGG_TX_STATE_BT_PRIO_MSK = 0x02, - AGG_TX_STATE_FEW_BYTES_MSK = 0x04, - AGG_TX_STATE_ABORT_MSK = 0x08, - AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10, - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20, - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40, - AGG_TX_STATE_SCD_QUERY_MSK = 0x80, - AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100, - AGG_TX_STATE_RESPONSE_MSK = 0x1ff, - AGG_TX_STATE_DUMP_TX_MSK = 0x200, - AGG_TX_STATE_DELAY_TX_MSK = 0x400 -}; - -#define AGG_TX_STATE_LAST_SENT_MSK \ -(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) - -#define AGG_TX_STATE_TRY_CNT_POS 12 -#define AGG_TX_STATE_TRY_CNT_MSK 0xf000 - -#define AGG_TX_STATE_SEQ_NUM_POS 16 -#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 - /* * REPLY_TX = 0x1c (response) */ -#if IWL == 4965 -struct iwl_tx_resp { - u8 frame_count; /* 1 no aggregation, >1 aggregation */ - u8 bt_kill_count; - u8 failure_rts; - u8 failure_frame; - __le32 rate_n_flags; - __le16 wireless_media_time; - __le16 reserved; - __le32 pa_power1; - __le32 pa_power2; - __le32 status; /* TX status (for aggregation status of 1st frame) */ -} __attribute__ ((packed)); - -#elif IWL == 3945 -struct iwl_tx_resp { +struct iwl3945_tx_resp { u8 failure_rts; u8 failure_frame; u8 bt_kill_count; u8 rate; __le32 wireless_media_time; - __le32 status; /* TX status (for aggregation status of 1st frame) */ -} __attribute__ ((packed)); -#endif - -/* - * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) - */ -struct iwl_compressed_ba_resp { - __le32 sta_addr_lo32; - __le16 sta_addr_hi16; - __le16 reserved; - u8 sta_id; - u8 tid; - __le16 ba_seq_ctl; - __le32 ba_bitmap0; - __le32 ba_bitmap1; - __le16 scd_flow; - __le16 scd_ssn; + __le32 status; /* TX status */ } __attribute__ ((packed)); /* * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) */ -struct iwl_txpowertable_cmd { +struct iwl3945_txpowertable_cmd { u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ u8 reserved; __le16 channel; -#if IWL == 3945 - struct iwl_power_per_rate power[IWL_MAX_RATES]; -#elif IWL == 4965 - struct iwl_tx_power_db tx_power; -#endif + struct iwl3945_power_per_rate power[IWL_MAX_RATES]; } __attribute__ ((packed)); -#if IWL == 3945 -struct iwl_rate_scaling_info { +struct iwl3945_rate_scaling_info { __le16 rate_n_flags; u8 try_cnt; u8 next_rate_index; } __attribute__ ((packed)); /** - * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response + * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response * * REPLY_RATE_SCALE = 0x47 (command, has simple generic response) * @@ -947,61 +1010,22 @@ struct iwl_rate_scaling_info { * For example, if you set 9MB (PLCP 0x0f) as the first * rate in the rate table, the bit mask for that rate * when passed through ofdm_basic_rates on the REPLY_RXON - * command would be bit 0 (1<<0) + * command would be bit 0 (1 << 0) */ -struct iwl_rate_scaling_cmd { +struct iwl3945_rate_scaling_cmd { u8 table_id; u8 reserved[3]; - struct iwl_rate_scaling_info table[IWL_MAX_RATES]; -} __attribute__ ((packed)); - -#elif IWL == 4965 - -/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ -#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1<<0) - -#define LINK_QUAL_AC_NUM AC_NUM -#define LINK_QUAL_MAX_RETRY_NUM 16 - -#define LINK_QUAL_ANT_A_MSK (1<<0) -#define LINK_QUAL_ANT_B_MSK (1<<1) -#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK) - -struct iwl_link_qual_general_params { - u8 flags; - u8 mimo_delimiter; - u8 single_stream_ant_msk; - u8 dual_stream_ant_msk; - u8 start_rate_index[LINK_QUAL_AC_NUM]; -} __attribute__ ((packed)); - -struct iwl_link_qual_agg_params { - __le16 agg_time_limit; - u8 agg_dis_start_th; - u8 agg_frame_cnt_limit; - __le32 reserved; -} __attribute__ ((packed)); - -/* - * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) - */ -struct iwl_link_quality_cmd { - u8 sta_id; - u8 reserved1; - __le16 control; - struct iwl_link_qual_general_params general_params; - struct iwl_link_qual_agg_params agg_params; - struct { - __le32 rate_n_flags; - } rs_table[LINK_QUAL_MAX_RETRY_NUM]; - __le32 reserved2; + struct iwl3945_rate_scaling_info table[IWL_MAX_RATES]; } __attribute__ ((packed)); -#endif /* * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) + * + * 3945 and 4965 support hardware handshake with Bluetooth device on + * same platform. Bluetooth device alerts wireless device when it will Tx; + * wireless device can delay or kill its own Tx to accomodate. */ -struct iwl_bt_cmd { +struct iwl3945_bt_cmd { u8 flags; u8 lead_time; u8 max_kill; @@ -1027,18 +1051,18 @@ struct iwl_bt_cmd { RXON_FILTER_ASSOC_MSK | \ RXON_FILTER_BCON_AWARE_MSK) -struct iwl_measure_channel { +struct iwl3945_measure_channel { __le32 duration; /* measurement duration in extended beacon * format */ u8 channel; /* channel to measure */ - u8 type; /* see enum iwl_measure_type */ + u8 type; /* see enum iwl3945_measure_type */ __le16 reserved; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) */ -struct iwl_spectrum_cmd { +struct iwl3945_spectrum_cmd { __le16 len; /* number of bytes starting from token */ u8 token; /* token id */ u8 id; /* measurement id -- 0 or 1 */ @@ -1051,13 +1075,13 @@ struct iwl_spectrum_cmd { __le32 filter_flags; /* rxon filter flags */ __le16 channel_count; /* minimum 1, maximum 10 */ __le16 reserved3; - struct iwl_measure_channel channels[10]; + struct iwl3945_measure_channel channels[10]; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) */ -struct iwl_spectrum_resp { +struct iwl3945_spectrum_resp { u8 token; u8 id; /* id of the prior command replaced, or 0xff */ __le16 status; /* 0 - command will be handled @@ -1065,12 +1089,12 @@ struct iwl_spectrum_resp { * measurement) */ } __attribute__ ((packed)); -enum iwl_measurement_state { +enum iwl3945_measurement_state { IWL_MEASUREMENT_START = 0, IWL_MEASUREMENT_STOP = 1, }; -enum iwl_measurement_status { +enum iwl3945_measurement_status { IWL_MEASUREMENT_OK = 0, IWL_MEASUREMENT_CONCURRENT = 1, IWL_MEASUREMENT_CSA_CONFLICT = 2, @@ -1083,18 +1107,18 @@ enum iwl_measurement_status { #define NUM_ELEMENTS_IN_HISTOGRAM 8 -struct iwl_measurement_histogram { +struct iwl3945_measurement_histogram { __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ } __attribute__ ((packed)); /* clear channel availability counters */ -struct iwl_measurement_cca_counters { +struct iwl3945_measurement_cca_counters { __le32 ofdm; __le32 cck; } __attribute__ ((packed)); -enum iwl_measure_type { +enum iwl3945_measure_type { IWL_MEASURE_BASIC = (1 << 0), IWL_MEASURE_CHANNEL_LOAD = (1 << 1), IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), @@ -1107,7 +1131,7 @@ enum iwl_measure_type { /* * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) */ -struct iwl_spectrum_notification { +struct iwl3945_spectrum_notification { u8 id; /* measurement id -- 0 or 1 */ u8 token; u8 channel_index; /* index in measurement channel list */ @@ -1115,7 +1139,7 @@ struct iwl_spectrum_notification { __le32 start_time; /* lower 32-bits of TSF */ u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ u8 channel; - u8 type; /* see enum iwl_measurement_type */ + u8 type; /* see enum iwl3945_measurement_type */ u8 reserved1; /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only * valid if applicable for measurement type requested. */ @@ -1125,9 +1149,9 @@ struct iwl_spectrum_notification { u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - * unidentified */ u8 reserved2[3]; - struct iwl_measurement_histogram histogram; + struct iwl3945_measurement_histogram histogram; __le32 stop_time; /* lower 32-bits of TSF */ - __le32 status; /* see iwl_measurement_status */ + __le32 status; /* see iwl3945_measurement_status */ } __attribute__ ((packed)); /****************************************************************************** @@ -1137,7 +1161,7 @@ struct iwl_spectrum_notification { *****************************************************************************/ /** - * struct iwl_powertable_cmd - Power Table Command + * struct iwl3945_powertable_cmd - Power Table Command * @flags: See below: * * POWER_TABLE_CMD = 0x77 (command, has simple generic response) @@ -1166,41 +1190,21 @@ struct iwl_spectrum_notification { */ #define IWL_POWER_VEC_SIZE 5 - -#if IWL == 3945 - -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1<<0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1<<2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1<<3) -struct iwl_powertable_cmd { +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1 << 2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1 << 3) +struct iwl3945_powertable_cmd { __le32 flags; __le32 rx_data_timeout; __le32 tx_data_timeout; __le32 sleep_interval[IWL_POWER_VEC_SIZE]; } __attribute__((packed)); -#elif IWL == 4965 - -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1<<0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1<<2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1<<3) - -struct iwl_powertable_cmd { - __le16 flags; - u8 keep_alive_seconds; - u8 debug_flags; - __le32 rx_data_timeout; - __le32 tx_data_timeout; - __le32 sleep_interval[IWL_POWER_VEC_SIZE]; - __le32 keep_alive_beacons; -} __attribute__ ((packed)); -#endif - /* * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) * 3945 and 4965 identical. */ -struct iwl_sleep_notification { +struct iwl3945_sleep_notification { u8 pm_sleep_mode; u8 pm_wakeup_src; __le16 reserved; @@ -1230,14 +1234,14 @@ enum { #define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ #define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ #define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ -struct iwl_card_state_cmd { +struct iwl3945_card_state_cmd { __le32 status; /* CARD_STATE_CMD_* request new power state */ } __attribute__ ((packed)); /* * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) */ -struct iwl_card_state_notif { +struct iwl3945_card_state_notif { __le32 flags; } __attribute__ ((packed)); @@ -1246,7 +1250,7 @@ struct iwl_card_state_notif { #define RF_CARD_DISABLED 0x04 #define RXON_CARD_DISABLED 0x10 -struct iwl_ct_kill_config { +struct iwl3945_ct_kill_config { __le32 reserved; __le32 critical_temperature_M; __le32 critical_temperature_R; @@ -1258,21 +1262,48 @@ struct iwl_ct_kill_config { * *****************************************************************************/ -struct iwl_scan_channel { - /* type is defined as: - * 0:0 active (0 - passive) - * 1:4 SSID direct - * If 1 is set then corresponding SSID IE is transmitted in probe +/** + * struct iwl3945_scan_channel - entry in REPLY_SCAN_CMD channel table + * + * One for each channel in the scan list. + * Each channel can independently select: + * 1) SSID for directed active scans + * 2) Txpower setting (for rate specified within Tx command) + * 3) How long to stay on-channel (behavior may be modified by quiet_time, + * quiet_plcp_th, good_CRC_th) + * + * To avoid uCode errors, make sure the following are true (see comments + * under struct iwl3945_scan_cmd about max_out_time and quiet_time): + * 1) If using passive_dwell (i.e. passive_dwell != 0): + * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) + * 2) quiet_time <= active_dwell + * 3) If restricting off-channel time (i.e. max_out_time !=0): + * passive_dwell < max_out_time + * active_dwell < max_out_time + */ +struct iwl3945_scan_channel { + /* + * type is defined as: + * 0:0 1 = active, 0 = passive + * 1:4 SSID direct bit map; if a bit is set, then corresponding + * SSID IE is transmitted in probe request. * 5:7 reserved */ u8 type; - u8 channel; - struct iwl_tx_power tpc; - __le16 active_dwell; - __le16 passive_dwell; + u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */ + struct iwl3945_tx_power tpc; + __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ + __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ } __attribute__ ((packed)); -struct iwl_ssid_ie { +/** + * struct iwl3945_ssid_ie - directed scan network information element + * + * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field + * in struct iwl3945_scan_channel; each channel may select different ssids from + * among the 4 entries. SSID IEs get transmitted in reverse order of entry. + */ +struct iwl3945_ssid_ie { u8 id; u8 len; u8 ssid[32]; @@ -1285,44 +1316,98 @@ struct iwl_ssid_ie { /* * REPLY_SCAN_CMD = 0x80 (command) + * + * The hardware scan command is very powerful; the driver can set it up to + * maintain (relatively) normal network traffic while doing a scan in the + * background. The max_out_time and suspend_time control the ratio of how + * long the device stays on an associated network channel ("service channel") + * vs. how long it's away from the service channel, tuned to other channels + * for scanning. + * + * max_out_time is the max time off-channel (in usec), and suspend_time + * is how long (in "extended beacon" format) that the scan is "suspended" + * after returning to the service channel. That is, suspend_time is the + * time that we stay on the service channel, doing normal work, between + * scan segments. The driver may set these parameters differently to support + * scanning when associated vs. not associated, and light vs. heavy traffic + * loads when associated. + * + * After receiving this command, the device's scan engine does the following; + * + * 1) Sends SCAN_START notification to driver + * 2) Checks to see if it has time to do scan for one channel + * 3) Sends NULL packet, with power-save (PS) bit set to 1, + * to tell AP that we're going off-channel + * 4) Tunes to first channel in scan list, does active or passive scan + * 5) Sends SCAN_RESULT notification to driver + * 6) Checks to see if it has time to do scan on *next* channel in list + * 7) Repeats 4-6 until it no longer has time to scan the next channel + * before max_out_time expires + * 8) Returns to service channel + * 9) Sends NULL packet with PS=0 to tell AP that we're back + * 10) Stays on service channel until suspend_time expires + * 11) Repeats entire process 2-10 until list is complete + * 12) Sends SCAN_COMPLETE notification + * + * For fast, efficient scans, the scan command also has support for staying on + * a channel for just a short time, if doing active scanning and getting no + * responses to the transmitted probe request. This time is controlled by + * quiet_time, and the number of received packets below which a channel is + * considered "quiet" is controlled by quiet_plcp_threshold. + * + * For active scanning on channels that have regulatory restrictions against + * blindly transmitting, the scan can listen before transmitting, to make sure + * that there is already legitimate activity on the channel. If enough + * packets are cleanly received on the channel (controlled by good_CRC_th, + * typical value 1), the scan engine starts transmitting probe requests. + * + * Driver must use separate scan commands for 2.4 vs. 5 GHz bands. + * + * To avoid uCode errors, see timing restrictions described under + * struct iwl3945_scan_channel. */ -struct iwl_scan_cmd { +struct iwl3945_scan_cmd { __le16 len; u8 reserved0; - u8 channel_count; - __le16 quiet_time; /* dwell only this long on quiet chnl - * (active scan) */ - __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ - __le16 good_CRC_th; /* passive -> active promotion threshold */ -#if IWL == 3945 + u8 channel_count; /* # channels in channel list */ + __le16 quiet_time; /* dwell only this # millisecs on quiet channel + * (only for active scan) */ + __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ + __le16 good_CRC_th; /* passive -> active promotion threshold */ __le16 reserved1; -#elif IWL == 4965 - __le16 rx_chain; -#endif - __le32 max_out_time; /* max usec to be out of associated (service) - * chnl */ - __le32 suspend_time; /* pause scan this long when returning to svc - * chnl. - * 3945 -- 31:24 # beacons, 19:0 additional usec, - * 4965 -- 31:22 # beacons, 21:0 additional usec. - */ - __le32 flags; - __le32 filter_flags; + __le32 max_out_time; /* max usec to be away from associated (service) + * channel */ + __le32 suspend_time; /* pause scan this long (in "extended beacon + * format") when returning to service channel: + * 3945; 31:24 # beacons, 19:0 additional usec, + * 4965; 31:22 # beacons, 21:0 additional usec. + */ + __le32 flags; /* RXON_FLG_* */ + __le32 filter_flags; /* RXON_FILTER_* */ + + /* For active scans (set to all-0s for passive scans). + * Does not include payload. Must specify Tx rate; no rate scaling. */ + struct iwl3945_tx_cmd tx_cmd; + + /* For directed active scans (set to all-0s otherwise) */ + struct iwl3945_ssid_ie direct_scan[PROBE_OPTION_MAX]; - struct iwl_tx_cmd tx_cmd; - struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; - - u8 data[0]; /* - * The channels start after the probe request payload and are of type: + * Probe request frame, followed by channel list. * - * struct iwl_scan_channel channels[0]; + * Size of probe request frame is specified by byte count in tx_cmd. + * Channel list follows immediately after probe request frame. + * Number of channels in list is specified by channel_count. + * Each channel in list is of type: * - * NOTE: Only one band of channels can be scanned per pass. You - * can not mix 2.4GHz channels and 5.2GHz channels and must - * request a scan multiple times (not concurrently) + * struct iwl3945_scan_channel channels[0]; * + * NOTE: Only one band of channels can be scanned per pass. You + * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait + * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) + * before requesting another scan. */ + u8 data[0]; } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ @@ -1333,14 +1418,14 @@ struct iwl_scan_cmd { /* * REPLY_SCAN_CMD = 0x80 (response) */ -struct iwl_scanreq_notification { +struct iwl3945_scanreq_notification { __le32 status; /* 1: okay, 2: cannot fulfill request */ } __attribute__ ((packed)); /* * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) */ -struct iwl_scanstart_notification { +struct iwl3945_scanstart_notification { __le32 tsf_low; __le32 tsf_high; __le32 beacon_timer; @@ -1357,7 +1442,7 @@ struct iwl_scanstart_notification { /* * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) */ -struct iwl_scanresults_notification { +struct iwl3945_scanresults_notification { u8 channel; u8 band; u8 reserved[2]; @@ -1369,7 +1454,7 @@ struct iwl_scanresults_notification { /* * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) */ -struct iwl_scancomplete_notification { +struct iwl3945_scancomplete_notification { u8 scanned_channels; u8 status; u8 reserved; @@ -1388,8 +1473,8 @@ struct iwl_scancomplete_notification { /* * BEACON_NOTIFICATION = 0x90 (notification only, not a command) */ -struct iwl_beacon_notif { - struct iwl_tx_resp beacon_notify_hdr; +struct iwl3945_beacon_notif { + struct iwl3945_tx_resp beacon_notify_hdr; __le32 low_tsf; __le32 high_tsf; __le32 ibss_mgr_status; @@ -1398,8 +1483,8 @@ struct iwl_beacon_notif { /* * REPLY_TX_BEACON = 0x91 (command, has simple generic response) */ -struct iwl_tx_beacon_cmd { - struct iwl_tx_cmd tx; +struct iwl3945_tx_beacon_cmd { + struct iwl3945_tx_cmd tx; __le16 tim_idx; u8 tim_size; u8 reserved1; @@ -1450,30 +1535,8 @@ struct statistics_rx_phy { __le32 rxe_frame_limit_overrun; __le32 sent_ack_cnt; __le32 sent_cts_cnt; -#if IWL == 4965 - __le32 sent_ba_rsp_cnt; - __le32 dsp_self_kill; - __le32 mh_format_err; - __le32 re_acq_main_rssi_sum; - __le32 reserved3; -#endif } __attribute__ ((packed)); -#if IWL == 4965 -struct statistics_rx_ht_phy { - __le32 plcp_err; - __le32 overrun_err; - __le32 early_overrun_err; - __le32 crc32_good; - __le32 crc32_err; - __le32 mh_format_err; - __le32 agg_crc32_good; - __le32 agg_mpdu_cnt; - __le32 agg_cnt; - __le32 reserved2; -} __attribute__ ((packed)); -#endif - struct statistics_rx_non_phy { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ @@ -1483,57 +1546,13 @@ struct statistics_rx_non_phy { * filtering process */ __le32 non_channel_beacons; /* beacons with our bss id but not on * our serving channel */ -#if IWL == 4965 - __le32 channel_beacons; /* beacons with our bss id and in our - * serving channel */ - __le32 num_missed_bcon; /* number of missed beacons */ - __le32 adc_rx_saturation_time; /* count in 0.8us units the time the - * ADC was in saturation */ - __le32 ina_detection_search_time;/* total time (in 0.8us) searched - * for INA */ - __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ - __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ - __le32 interference_data_flag; /* flag for interference data - * availability. 1 when data is - * available. */ - __le32 channel_load; /* counts RX Enable time */ - __le32 dsp_false_alarms; /* DSP false alarm (both OFDM - * and CCK) counter */ - __le32 beacon_rssi_a; - __le32 beacon_rssi_b; - __le32 beacon_rssi_c; - __le32 beacon_energy_a; - __le32 beacon_energy_b; - __le32 beacon_energy_c; -#endif } __attribute__ ((packed)); struct statistics_rx { struct statistics_rx_phy ofdm; struct statistics_rx_phy cck; struct statistics_rx_non_phy general; -#if IWL == 4965 - struct statistics_rx_ht_phy ofdm_ht; -#endif -} __attribute__ ((packed)); - -#if IWL == 4965 -struct statistics_tx_non_phy_agg { - __le32 ba_timeout; - __le32 ba_reschedule_frames; - __le32 scd_query_agg_frame_cnt; - __le32 scd_query_no_agg; - __le32 scd_query_agg; - __le32 scd_query_mismatch; - __le32 frame_not_ready; - __le32 underrun; - __le32 bt_prio_kill; - __le32 rx_ba_rsp_cnt; - __le32 reserved2; - __le32 reserved3; } __attribute__ ((packed)); -#endif struct statistics_tx { __le32 preamble_cnt; @@ -1545,14 +1564,6 @@ struct statistics_tx { __le32 ack_timeout; __le32 expected_ack_cnt; __le32 actual_ack_cnt; -#if IWL == 4965 - __le32 dump_msdu_cnt; - __le32 burst_abort_next_frame_mismatch_cnt; - __le32 burst_abort_missing_next_frame_cnt; - __le32 cts_timeout_collision; - __le32 ack_or_ba_timeout_collision; - struct statistics_tx_non_phy_agg agg; -#endif } __attribute__ ((packed)); struct statistics_dbg { @@ -1566,29 +1577,16 @@ struct statistics_div { __le32 tx_on_b; __le32 exec_time; __le32 probe_time; -#if IWL == 4965 - __le32 reserved1; - __le32 reserved2; -#endif } __attribute__ ((packed)); struct statistics_general { __le32 temperature; -#if IWL == 4965 - __le32 temperature_m; -#endif struct statistics_dbg dbg; __le32 sleep_time; __le32 slots_out; __le32 slots_idle; __le32 ttl_timestamp; struct statistics_div div; -#if IWL == 4965 - __le32 rx_enable_counter; - __le32 reserved1; - __le32 reserved2; - __le32 reserved3; -#endif } __attribute__ ((packed)); /* @@ -1608,7 +1606,7 @@ struct statistics_general { */ #define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ #define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ -struct iwl_statistics_cmd { +struct iwl3945_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -1629,7 +1627,7 @@ struct iwl_statistics_cmd { */ #define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) #define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) -struct iwl_notif_statistics { +struct iwl3945_notif_statistics { __le32 flag; struct statistics_rx rx; struct statistics_tx tx; @@ -1644,7 +1642,7 @@ struct iwl_notif_statistics { * then this notification will be sent. */ #define CONSECUTIVE_MISSED_BCONS_TH 20 -struct iwl_missed_beacon_notif { +struct iwl3945_missed_beacon_notif { __le32 consequtive_missed_beacons; __le32 total_missed_becons; __le32 num_expected_beacons; @@ -1660,12 +1658,12 @@ struct iwl_missed_beacon_notif { #define PHY_CALIBRATE_DIFF_GAIN_CMD (7) #define HD_TABLE_SIZE (11) -struct iwl_sensitivity_cmd { +struct iwl3945_sensitivity_cmd { __le16 control; __le16 table[HD_TABLE_SIZE]; } __attribute__ ((packed)); -struct iwl_calibration_cmd { +struct iwl3945_calibration_cmd { u8 opCode; u8 flags; __le16 reserved; @@ -1688,7 +1686,7 @@ struct iwl_calibration_cmd { * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), * this command turns it on or off, or sets up a periodic blinking cycle. */ -struct iwl_led_cmd { +struct iwl3945_led_cmd { __le32 interval; /* "interval" in uSec */ u8 id; /* 1: Activity, 2: Link, 3: Tech */ u8 off; /* # intervals off while blinking; @@ -1704,31 +1702,27 @@ struct iwl_led_cmd { * *****************************************************************************/ -struct iwl_rx_packet { +struct iwl3945_rx_packet { __le32 len; - struct iwl_cmd_header hdr; + struct iwl3945_cmd_header hdr; union { - struct iwl_alive_resp alive_frame; - struct iwl_rx_frame rx_frame; - struct iwl_tx_resp tx_resp; - struct iwl_spectrum_notification spectrum_notif; - struct iwl_csa_notification csa_notif; - struct iwl_error_resp err_resp; - struct iwl_card_state_notif card_state_notif; - struct iwl_beacon_notif beacon_status; - struct iwl_add_sta_resp add_sta; - struct iwl_sleep_notification sleep_notif; - struct iwl_spectrum_resp spectrum; - struct iwl_notif_statistics stats; -#if IWL == 4965 - struct iwl_compressed_ba_resp compressed_ba; - struct iwl_missed_beacon_notif missed_beacon; -#endif + struct iwl3945_alive_resp alive_frame; + struct iwl3945_rx_frame rx_frame; + struct iwl3945_tx_resp tx_resp; + struct iwl3945_spectrum_notification spectrum_notif; + struct iwl3945_csa_notification csa_notif; + struct iwl3945_error_resp err_resp; + struct iwl3945_card_state_notif card_state_notif; + struct iwl3945_beacon_notif beacon_status; + struct iwl3945_add_sta_resp add_sta; + struct iwl3945_sleep_notification sleep_notif; + struct iwl3945_spectrum_resp spectrum; + struct iwl3945_notif_statistics stats; __le32 status; u8 raw[0]; } u; } __attribute__ ((packed)); -#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl_rx_frame)) +#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame)) -#endif /* __iwl_commands_h__ */ +#endif /* __iwl3945_3945_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index 72318d78957e..f853c6b9f76e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -26,18 +26,18 @@ * *****************************************************************************/ -#ifndef __iwl_debug_h__ -#define __iwl_debug_h__ +#ifndef __iwl3945_debug_h__ +#define __iwl3945_debug_h__ -#ifdef CONFIG_IWLWIFI_DEBUG -extern u32 iwl_debug_level; +#ifdef CONFIG_IWL3945_DEBUG +extern u32 iwl3945_debug_level; #define IWL_DEBUG(level, fmt, args...) \ -do { if (iwl_debug_level & (level)) \ +do { if (iwl3945_debug_level & (level)) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) #define IWL_DEBUG_LIMIT(level, fmt, args...) \ -do { if ((iwl_debug_level & (level)) && net_ratelimit()) \ +do { if ((iwl3945_debug_level & (level)) && net_ratelimit()) \ printk(KERN_ERR DRV_NAME": %c %s " fmt, \ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) #else @@ -47,7 +47,7 @@ static inline void IWL_DEBUG(int level, const char *fmt, ...) static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) { } -#endif /* CONFIG_IWLWIFI_DEBUG */ +#endif /* CONFIG_IWL3945_DEBUG */ /* * To use the debug system; @@ -68,51 +68,51 @@ static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) * * % cat /proc/net/iwl/debug_level * - * you simply need to add your entry to the iwl_debug_levels array. + * you simply need to add your entry to the iwl3945_debug_levels array. * * If you do not see debug_level in /proc/net/iwl then you do not have - * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration + * CONFIG_IWL3945_DEBUG defined in your kernel configuration * */ -#define IWL_DL_INFO (1<<0) -#define IWL_DL_MAC80211 (1<<1) -#define IWL_DL_HOST_COMMAND (1<<2) -#define IWL_DL_STATE (1<<3) +#define IWL_DL_INFO (1 << 0) +#define IWL_DL_MAC80211 (1 << 1) +#define IWL_DL_HOST_COMMAND (1 << 2) +#define IWL_DL_STATE (1 << 3) -#define IWL_DL_RADIO (1<<7) -#define IWL_DL_POWER (1<<8) -#define IWL_DL_TEMP (1<<9) +#define IWL_DL_RADIO (1 << 7) +#define IWL_DL_POWER (1 << 8) +#define IWL_DL_TEMP (1 << 9) -#define IWL_DL_NOTIF (1<<10) -#define IWL_DL_SCAN (1<<11) -#define IWL_DL_ASSOC (1<<12) -#define IWL_DL_DROP (1<<13) +#define IWL_DL_NOTIF (1 << 10) +#define IWL_DL_SCAN (1 << 11) +#define IWL_DL_ASSOC (1 << 12) +#define IWL_DL_DROP (1 << 13) -#define IWL_DL_TXPOWER (1<<14) +#define IWL_DL_TXPOWER (1 << 14) -#define IWL_DL_AP (1<<15) +#define IWL_DL_AP (1 << 15) -#define IWL_DL_FW (1<<16) -#define IWL_DL_RF_KILL (1<<17) -#define IWL_DL_FW_ERRORS (1<<18) +#define IWL_DL_FW (1 << 16) +#define IWL_DL_RF_KILL (1 << 17) +#define IWL_DL_FW_ERRORS (1 << 18) -#define IWL_DL_LED (1<<19) +#define IWL_DL_LED (1 << 19) -#define IWL_DL_RATE (1<<20) +#define IWL_DL_RATE (1 << 20) -#define IWL_DL_CALIB (1<<21) -#define IWL_DL_WEP (1<<22) -#define IWL_DL_TX (1<<23) -#define IWL_DL_RX (1<<24) -#define IWL_DL_ISR (1<<25) -#define IWL_DL_HT (1<<26) -#define IWL_DL_IO (1<<27) -#define IWL_DL_11H (1<<28) +#define IWL_DL_CALIB (1 << 21) +#define IWL_DL_WEP (1 << 22) +#define IWL_DL_TX (1 << 23) +#define IWL_DL_RX (1 << 24) +#define IWL_DL_ISR (1 << 25) +#define IWL_DL_HT (1 << 26) +#define IWL_DL_IO (1 << 27) +#define IWL_DL_11H (1 << 28) -#define IWL_DL_STATS (1<<29) -#define IWL_DL_TX_REPLY (1<<30) -#define IWL_DL_QOS (1<<31) +#define IWL_DL_STATS (1 << 29) +#define IWL_DL_TX_REPLY (1 << 30) +#define IWL_DL_QOS (1 << 31) #define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) #define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index fb5f0649f4f6..6e0187393af4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -8,7 +8,7 @@ * Copyright(c) 2005 - 2007 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 Geeral Public License as + * 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 @@ -60,58 +60,646 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +/* + * Please use this file (iwl-3945-hw.h) only for hardware-related definitions. + * Please use iwl-3945-commands.h for uCode API definitions. + * Please use iwl-3945.h for driver implementation definitions. + */ #ifndef __iwl_3945_hw__ #define __iwl_3945_hw__ -#define IWL_RX_BUF_SIZE 3000 -/* card static random access memory (SRAM) for processor data and instructs */ +/* + * uCode queue management definitions ... + * Queue #4 is the command queue for 3945 and 4965. + */ +#define IWL_CMD_QUEUE_NUM 4 + +/* Tx rates */ +#define IWL_CCK_RATES 4 +#define IWL_OFDM_RATES 8 +#define IWL_HT_RATES 0 +#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) + +/* Time constants */ +#define SHORT_SLOT_TIME 9 +#define LONG_SLOT_TIME 20 + +/* RSSI to dBm */ +#define IWL_RSSI_OFFSET 95 + +/* + * EEPROM related constants, enums, and structures. + */ + +/* + * EEPROM access time values: + * + * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, + * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit + * CSR_EEPROM_REG_BIT_CMD (0x2). + * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). + * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. + * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. + */ +#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ +#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ + +/* + * Regulatory channel usage flags in EEPROM struct iwl_eeprom_channel.flags. + * + * IBSS and/or AP operation is allowed *only* on those channels with + * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because + * RADAR detection is not supported by the 3945 driver, but is a + * requirement for establishing a new network for legal operation on channels + * requiring RADAR detection or restricting ACTIVE scanning. + * + * NOTE: "WIDE" flag indicates that 20 MHz channel is supported; + * 3945 does not support FAT 40 MHz-wide channels. + * + * NOTE: Using a channel inappropriately will result in a uCode error! + */ +enum { + EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ + EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ + /* Bit 2 Reserved */ + EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ + EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ + EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ + EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ +}; + +/* SKU Capabilities */ +#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) +#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) +#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7) + +/* *regulatory* channel data from eeprom, one for each channel */ +struct iwl3945_eeprom_channel { + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ +} __attribute__ ((packed)); + +/* + * Mapping of a Tx power level, at factory calibration temperature, + * to a radio/DSP gain table index. + * One for each of 5 "sample" power levels in each band. + * v_det is measured at the factory, using the 3945's built-in power amplifier + * (PA) output voltage detector. This same detector is used during Tx of + * long packets in normal operation to provide feedback as to proper output + * level. + * Data copied from EEPROM. + * DO NOT ALTER THIS STRUCTURE!!! + */ +struct iwl3945_eeprom_txpower_sample { + u8 gain_index; /* index into power (gain) setup table ... */ + s8 power; /* ... for this pwr level for this chnl group */ + u16 v_det; /* PA output voltage */ +} __attribute__ ((packed)); + +/* + * Mappings of Tx power levels -> nominal radio/DSP gain table indexes. + * One for each channel group (a.k.a. "band") (1 for BG, 4 for A). + * Tx power setup code interpolates between the 5 "sample" power levels + * to determine the nominal setup for a requested power level. + * Data copied from EEPROM. + * DO NOT ALTER THIS STRUCTURE!!! + */ +struct iwl3945_eeprom_txpower_group { + struct iwl3945_eeprom_txpower_sample samples[5]; /* 5 power levels */ + s32 a, b, c, d, e; /* coefficients for voltage->power + * formula (signed) */ + s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on + * frequency (signed) */ + s8 saturation_power; /* highest power possible by h/w in this + * band */ + u8 group_channel; /* "representative" channel # in this band */ + s16 temperature; /* h/w temperature at factory calib this band + * (signed) */ +} __attribute__ ((packed)); + +/* + * Temperature-based Tx-power compensation data, not band-specific. + * These coefficients are use to modify a/b/c/d/e coeffs based on + * difference between current temperature and factory calib temperature. + * Data copied from EEPROM. + */ +struct iwl3945_eeprom_temperature_corr { + u32 Ta; + u32 Tb; + u32 Tc; + u32 Td; + u32 Te; +} __attribute__ ((packed)); + +/* + * EEPROM map + */ +struct iwl3945_eeprom { + u8 reserved0[16]; +#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ + u16 device_id; /* abs.ofs: 16 */ + u8 reserved1[2]; +#define EEPROM_PMC (2*0x0A) /* 2 bytes */ + u16 pmc; /* abs.ofs: 20 */ + u8 reserved2[20]; +#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ + u8 mac_address[6]; /* abs.ofs: 42 */ + u8 reserved3[58]; +#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ + u16 board_revision; /* abs.ofs: 106 */ + u8 reserved4[11]; +#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ + u8 board_pba_number[9]; /* abs.ofs: 119 */ + u8 reserved5[8]; +#define EEPROM_VERSION (2*0x44) /* 2 bytes */ + u16 version; /* abs.ofs: 136 */ +#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ + u8 sku_cap; /* abs.ofs: 138 */ +#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ + u8 leds_mode; /* abs.ofs: 139 */ +#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ + u16 oem_mode; +#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ + u16 wowlan_mode; /* abs.ofs: 142 */ +#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ + u16 leds_time_interval; /* abs.ofs: 144 */ +#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ + u8 leds_off_time; /* abs.ofs: 146 */ +#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ + u8 leds_on_time; /* abs.ofs: 147 */ +#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ + u8 almgor_m_version; /* abs.ofs: 148 */ +#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ + u8 antenna_switch_type; /* abs.ofs: 149 */ + u8 reserved6[42]; +#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ + u8 sku_id[4]; /* abs.ofs: 192 */ + +/* + * Per-channel regulatory data. + * + * Each channel that *might* be supported by 3945 or 4965 has a fixed location + * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory + * txpower (MSB). + * + * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * channels (only for 4965, not supported by 3945) appear later in the EEPROM. + * + * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + */ +#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ + u16 band_1_count; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ + struct iwl3945_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ + +/* + * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, + * 5.0 GHz channels 7, 8, 11, 12, 16 + * (4915-5080MHz) (none of these is ever supported) + */ +#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ + u16 band_2_count; /* abs.ofs: 226 */ +#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ + struct iwl3945_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ + +/* + * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 + * (5170-5320MHz) + */ +#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ + u16 band_3_count; /* abs.ofs: 254 */ +#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ + struct iwl3945_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ + +/* + * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 + * (5500-5700MHz) + */ +#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ + u16 band_4_count; /* abs.ofs: 280 */ +#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ + struct iwl3945_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ + +/* + * 5.7 GHz channels 145, 149, 153, 157, 161, 165 + * (5725-5825MHz) + */ +#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ + u16 band_5_count; /* abs.ofs: 304 */ +#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ + struct iwl3945_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ + + u8 reserved9[194]; + +/* + * 3945 Txpower calibration data. + */ +#define EEPROM_TXPOWER_CALIB_GROUP0 0x200 +#define EEPROM_TXPOWER_CALIB_GROUP1 0x240 +#define EEPROM_TXPOWER_CALIB_GROUP2 0x280 +#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0 +#define EEPROM_TXPOWER_CALIB_GROUP4 0x300 +#define IWL_NUM_TX_CALIB_GROUPS 5 + struct iwl3945_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS]; +/* abs.ofs: 512 */ +#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340 + struct iwl3945_eeprom_temperature_corr corrections; /* abs.ofs: 832 */ + u8 reserved16[172]; /* fill out to full 1024 byte block */ +} __attribute__ ((packed)); + +#define IWL_EEPROM_IMAGE_SIZE 1024 + +/* End of EEPROM */ + + +#include "iwl-3945-commands.h" + +#define PCI_LINK_CTRL 0x0F0 +#define PCI_POWER_SOURCE 0x0C8 +#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) + +/*=== CSR (control and status registers) ===*/ +#define CSR_BASE (0x000) + +#define CSR_SW_VER (CSR_BASE+0x000) +#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ +#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ +#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ +#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ +#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ +#define CSR_GP_CNTRL (CSR_BASE+0x024) + +/* + * Hardware revision info + * Bit fields: + * 31-8: Reserved + * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 + * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D + * 1-0: "Dash" value, as in A-1, etc. + */ +#define CSR_HW_REV (CSR_BASE+0x028) + +/* EEPROM reads */ +#define CSR_EEPROM_REG (CSR_BASE+0x02c) +#define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GP_UCODE (CSR_BASE+0x044) +#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) +#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) +#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) +#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) + +/* Analog phase-lock-loop configuration (3945 only) + * Set bit 24. */ +#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) + +/* Bits for CSR_HW_IF_CONFIG_REG */ +#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200) +#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) +#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) +#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) +#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) + +/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), + * acknowledged (reset) by host writing "1" to flagged bits. */ +#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ +#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ +#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ +#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ +#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */ +#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ +#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ +#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ +#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ + +#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ + CSR_INT_BIT_HW_ERR | \ + CSR_INT_BIT_FH_TX | \ + CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_RF_KILL | \ + CSR_INT_BIT_SW_RX | \ + CSR_INT_BIT_WAKEUP | \ + CSR_INT_BIT_ALIVE) + +/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ +#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ +#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ +#define CSR_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */ +#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ +#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ +#define CSR_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */ +#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ +#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ + +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL2 | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) + +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \ + CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) + + +/* RESET */ +#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) +#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) +#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) +#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) +#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) + +/* GP (general purpose) CONTROL */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) +#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) +#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) +#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) + +#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) + +#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) +#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) + + +/* EEPROM REG */ +#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) +#define CSR_EEPROM_REG_BIT_CMD (0x00000002) + +/* EEPROM GP */ +#define CSR_EEPROM_GP_VALID_MSK (0x00000006) +#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) +#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) + +/* UCODE DRV GP */ +#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) +#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) +#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) +#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) + +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER + +/* GI Chicken Bits */ +#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) +#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) + +/* CSR_ANA_PLL_CFG */ +#define CSR_ANA_PLL_CFG_SH (0x00880300) + +/*=== HBUS (Host-side Bus) ===*/ +#define HBUS_BASE (0x400) + +/* + * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM + * structures, error log, event log, verifying uCode load). + * First write to address register, then read from or write to data register + * to complete the job. Once the address register is set up, accesses to + * data registers auto-increment the address by one dword. + * Bit usage for address registers (read or write): + * 0-31: memory address within device + */ +#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) +#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) +#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) +#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) + +/* + * Registers for accessing device's internal peripheral registers + * (e.g. SCD, BSM, etc.). First write to address register, + * then read from or write to data register to complete the job. + * Bit usage for address registers (read or write): + * 0-15: register address (offset) within device + * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) + */ +#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) +#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) +#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) +#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) + +/* + * Per-Tx-queue write pointer (index, really!) (3945 and 4965). + * Indicates index to next TFD that driver will fill (1 past latest filled). + * Bit usage: + * 0-7: queue write index + * 11-8: queue selector + */ +#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) + +/* SCD (3945 Tx Frame Scheduler) */ +#define SCD_BASE (CSR_BASE + 0x2E00) + +#define SCD_MODE_REG (SCD_BASE + 0x000) +#define SCD_ARASTAT_REG (SCD_BASE + 0x004) +#define SCD_TXFACT_REG (SCD_BASE + 0x010) +#define SCD_TXF4MF_REG (SCD_BASE + 0x014) +#define SCD_TXF5MF_REG (SCD_BASE + 0x020) +#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C) +#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030) + +/*=== FH (data Flow Handler) ===*/ +#define FH_BASE (0x800) + +#define FH_CBCC_TABLE (FH_BASE+0x140) +#define FH_TFDB_TABLE (FH_BASE+0x180) +#define FH_RCSR_TABLE (FH_BASE+0x400) +#define FH_RSSR_TABLE (FH_BASE+0x4c0) +#define FH_TCSR_TABLE (FH_BASE+0x500) +#define FH_TSSR_TABLE (FH_BASE+0x680) + +/* TFDB (Transmit Frame Buffer Descriptor) */ +#define FH_TFDB(_channel, buf) \ + (FH_TFDB_TABLE+((_channel)*2+(buf))*0x28) +#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \ + (FH_TFDB_TABLE + 0x50 * _channel) +/* CBCC _channel is [0,2] */ +#define FH_CBCC(_channel) (FH_CBCC_TABLE+(_channel)*0x8) +#define FH_CBCC_CTRL(_channel) (FH_CBCC(_channel)+0x00) +#define FH_CBCC_BASE(_channel) (FH_CBCC(_channel)+0x04) + +/* RCSR _channel is [0,2] */ +#define FH_RCSR(_channel) (FH_RCSR_TABLE+(_channel)*0x40) +#define FH_RCSR_CONFIG(_channel) (FH_RCSR(_channel)+0x00) +#define FH_RCSR_RBD_BASE(_channel) (FH_RCSR(_channel)+0x04) +#define FH_RCSR_WPTR(_channel) (FH_RCSR(_channel)+0x20) +#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24) + +#define FH_RSCSR_CHNL0_WPTR (FH_RCSR_WPTR(0)) + +/* RSSR */ +#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) +#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) +/* TCSR */ +#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) +#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) +#define FH_TCSR_CREDIT(_channel) (FH_TCSR(_channel)+0x04) +#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08) +/* TSSR */ +#define FH_TSSR_CBB_BASE (FH_TSSR_TABLE+0x000) +#define FH_TSSR_MSG_CONFIG (FH_TSSR_TABLE+0x008) +#define FH_TSSR_TX_STATUS (FH_TSSR_TABLE+0x010) + + +/* DBM */ + +#define ALM_FH_SRVC_CHNL (6) + +#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20) +#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4) + +#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000) + +#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) + +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) + +#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000) + +#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) + +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) +#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) + +#define ALM_TB_MAX_BYTES_COUNT (0xFFF0) + +#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \ + ((1LU << _channel) << 24) +#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \ + ((1LU << _channel) << 16) + +#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \ + (ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \ + ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel)) +#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ +#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ + +#define TFD_QUEUE_MIN 0 +#define TFD_QUEUE_MAX 6 +#define TFD_QUEUE_SIZE_MAX (256) + +#define IWL_NUM_SCAN_RATES (2) + +#define IWL_DEFAULT_TX_RETRY 15 + +/*********************************************/ + +#define RFD_SIZE 4 +#define NUM_TFD_CHUNKS 4 + +#define RX_QUEUE_SIZE 256 +#define RX_QUEUE_MASK 255 +#define RX_QUEUE_SIZE_LOG 8 + +#define U32_PAD(n) ((4-(n))&0x3) + +#define TFD_CTL_COUNT_SET(n) (n << 24) +#define TFD_CTL_COUNT_GET(ctl) ((ctl >> 24) & 7) +#define TFD_CTL_PAD_SET(n) (n << 28) +#define TFD_CTL_PAD_GET(ctl) (ctl >> 28) + +#define TFD_TX_CMD_SLOTS 256 +#define TFD_CMD_SLOTS 32 + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl3945_cmd) - \ + sizeof(struct iwl3945_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +/* Sizes and addresses for instruction and data memory (SRAM) in + * 3945's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ +#define RTC_INST_LOWER_BOUND (0x000000) #define ALM_RTC_INST_UPPER_BOUND (0x014000) + +#define RTC_DATA_LOWER_BOUND (0x800000) #define ALM_RTC_DATA_UPPER_BOUND (0x808000) #define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) #define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) -#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE #define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE #define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE + +/* Size of uCode instruction memory in bootstrap state machine */ +#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE + #define IWL_MAX_NUM_QUEUES 8 -static inline int iwl_hw_valid_rtc_data_addr(u32 addr) +static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr) { return (addr >= RTC_DATA_LOWER_BOUND) && (addr < ALM_RTC_DATA_UPPER_BOUND); } -/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE - * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */ -struct iwl_shared { +/* Base physical address of iwl3945_shared is provided to FH_TSSR_CBB_BASE + * and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */ +struct iwl3945_shared { __le32 tx_base_ptr[8]; __le32 rx_read_ptr[3]; } __attribute__ ((packed)); -struct iwl_tfd_frame_data { +struct iwl3945_tfd_frame_data { __le32 addr; __le32 len; } __attribute__ ((packed)); -struct iwl_tfd_frame { +struct iwl3945_tfd_frame { __le32 control_flags; - struct iwl_tfd_frame_data pa[4]; + struct iwl3945_tfd_frame_data pa[4]; u8 reserved[28]; } __attribute__ ((packed)); -static inline u8 iwl_hw_get_rate(__le16 rate_n_flags) +static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags) { return le16_to_cpu(rate_n_flags) & 0xFF; } -static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags) +static inline u16 iwl3945_hw_get_rate_n_flags(__le16 rate_n_flags) { return le16_to_cpu(rate_n_flags); } -static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) +static inline __le16 iwl3945_hw_set_rate_n_flags(u8 rate, u16 flags) { return cpu_to_le16((u16)rate|flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h new file mode 100644 index 000000000000..75e20d0a20d1 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -0,0 +1,431 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * 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 <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl3945_io_h__ +#define __iwl3945_io_h__ + +#include <linux/io.h> + +#include "iwl-3945-debug.h" + +/* + * IO, register, and NIC memory access functions + * + * NOTE on naming convention and macro usage for these + * + * A single _ prefix before a an access function means that no state + * check or debug information is printed when that function is called. + * + * A double __ prefix before an access function means that state is checked + * and the current line number is printed in addition to any other debug output. + * + * The non-prefixed name is the #define that maps the caller into a + * #define that provides the caller's __LINE__ to the double prefix version. + * + * If you wish to call the function without any debug or state checking, + * you should use the single _ prefix version (as is used by dependent IO + * routines, for example _iwl3945_read_direct32 calls the non-check version of + * _iwl3945_read32.) + * + * These declarations are *extremely* useful in quickly isolating code deltas + * which result in misconfiguring of the hardware I/O. In combination with + * git-bisect and the IO debug level you can quickly determine the specific + * commit which breaks the IO sequence to the hardware. + * + */ + +#define _iwl3945_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_write32(const char *f, u32 l, struct iwl3945_priv *iwl, + u32 ofs, u32 val) +{ + IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); + _iwl3945_write32(iwl, ofs, val); +} +#define iwl3945_write32(iwl, ofs, val) \ + __iwl3945_write32(__FILE__, __LINE__, iwl, ofs, val) +#else +#define iwl3945_write32(iwl, ofs, val) _iwl3945_write32(iwl, ofs, val) +#endif + +#define _iwl3945_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWL3945_DEBUG +static inline u32 __iwl3945_read32(char *f, u32 l, struct iwl3945_priv *iwl, u32 ofs) +{ + IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); + return _iwl3945_read32(iwl, ofs); +} +#define iwl3945_read32(iwl, ofs) __iwl3945_read32(__FILE__, __LINE__, iwl, ofs) +#else +#define iwl3945_read32(p, o) _iwl3945_read32(p, o) +#endif + +static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask)) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} +#ifdef CONFIG_IWL3945_DEBUG +static inline int __iwl3945_poll_bit(const char *f, u32 l, + struct iwl3945_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout); + if (unlikely(ret == -ETIMEDOUT)) + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", + addr, bits, mask, f, l); + else + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", + addr, bits, mask, ret, f, l); + return ret; +} +#define iwl3945_poll_bit(iwl, addr, bits, mask, timeout) \ + __iwl3945_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) +#else +#define iwl3945_poll_bit(p, a, b, m, t) _iwl3945_poll_bit(p, a, b, m, t) +#endif + +static inline void _iwl3945_set_bit(struct iwl3945_priv *priv, u32 reg, u32 mask) +{ + _iwl3945_write32(priv, reg, _iwl3945_read32(priv, reg) | mask); +} +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_set_bit(const char *f, u32 l, + struct iwl3945_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl3945_read32(priv, reg) | mask; + IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl3945_write32(priv, reg, val); +} +#define iwl3945_set_bit(p, r, m) __iwl3945_set_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl3945_set_bit(p, r, m) _iwl3945_set_bit(p, r, m) +#endif + +static inline void _iwl3945_clear_bit(struct iwl3945_priv *priv, u32 reg, u32 mask) +{ + _iwl3945_write32(priv, reg, _iwl3945_read32(priv, reg) & ~mask); +} +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_clear_bit(const char *f, u32 l, + struct iwl3945_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl3945_read32(priv, reg) & ~mask; + IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl3945_write32(priv, reg, val); +} +#define iwl3945_clear_bit(p, r, m) __iwl3945_clear_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl3945_clear_bit(p, r, m) _iwl3945_clear_bit(p, r, m) +#endif + +static inline int _iwl3945_grab_nic_access(struct iwl3945_priv *priv) +{ + int ret; + u32 gp_ctl; + +#ifdef CONFIG_IWL3945_DEBUG + if (atomic_read(&priv->restrict_refcnt)) + return 0; +#endif + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("WARNING: Requesting MAC access during RFKILL " + "wakes up NIC\n"); + + /* 10 msec allows time for NIC to complete its data save */ + gp_ctl = _iwl3945_read32(priv, CSR_GP_CNTRL); + if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { + IWL_DEBUG_RF_KILL("Wait for complete power-down, " + "gpctl = 0x%08x\n", gp_ctl); + mdelay(10); + } else + IWL_DEBUG_RF_KILL("power-down complete, " + "gpctl = 0x%08x\n", gp_ctl); + } + + /* this bit wakes up the NIC */ + _iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + ret = _iwl3945_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); + if (ret < 0) { + IWL_ERROR("MAC is in deep sleep!\n"); + return -EIO; + } + +#ifdef CONFIG_IWL3945_DEBUG + atomic_inc(&priv->restrict_refcnt); +#endif + return 0; +} + +#ifdef CONFIG_IWL3945_DEBUG +static inline int __iwl3945_grab_nic_access(const char *f, u32 l, + struct iwl3945_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt)) + IWL_DEBUG_INFO("Grabbing access while already held at " + "line %d.\n", l); + + IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l); + return _iwl3945_grab_nic_access(priv); +} +#define iwl3945_grab_nic_access(priv) \ + __iwl3945_grab_nic_access(__FILE__, __LINE__, priv) +#else +#define iwl3945_grab_nic_access(priv) \ + _iwl3945_grab_nic_access(priv) +#endif + +static inline void _iwl3945_release_nic_access(struct iwl3945_priv *priv) +{ +#ifdef CONFIG_IWL3945_DEBUG + if (atomic_dec_and_test(&priv->restrict_refcnt)) +#endif + _iwl3945_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_release_nic_access(const char *f, u32 l, + struct iwl3945_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt) <= 0) + IWL_ERROR("Release unheld nic access at line %d.\n", l); + + IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l); + _iwl3945_release_nic_access(priv); +} +#define iwl3945_release_nic_access(priv) \ + __iwl3945_release_nic_access(__FILE__, __LINE__, priv) +#else +#define iwl3945_release_nic_access(priv) \ + _iwl3945_release_nic_access(priv) +#endif + +static inline u32 _iwl3945_read_direct32(struct iwl3945_priv *priv, u32 reg) +{ + return _iwl3945_read32(priv, reg); +} +#ifdef CONFIG_IWL3945_DEBUG +static inline u32 __iwl3945_read_direct32(const char *f, u32 l, + struct iwl3945_priv *priv, u32 reg) +{ + u32 value = _iwl3945_read_direct32(priv, reg); + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s %d\n", f, l); + IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, + f, l); + return value; +} +#define iwl3945_read_direct32(priv, reg) \ + __iwl3945_read_direct32(__FILE__, __LINE__, priv, reg) +#else +#define iwl3945_read_direct32 _iwl3945_read_direct32 +#endif + +static inline void _iwl3945_write_direct32(struct iwl3945_priv *priv, + u32 reg, u32 value) +{ + _iwl3945_write32(priv, reg, value); +} +#ifdef CONFIG_IWL3945_DEBUG +static void __iwl3945_write_direct32(u32 line, + struct iwl3945_priv *priv, u32 reg, u32 value) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + _iwl3945_write_direct32(priv, reg, value); +} +#define iwl3945_write_direct32(priv, reg, value) \ + __iwl3945_write_direct32(__LINE__, priv, reg, value) +#else +#define iwl3945_write_direct32 _iwl3945_write_direct32 +#endif + +static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv, + u32 reg, u32 len, u32 *values) +{ + u32 count = sizeof(u32); + + if ((priv != NULL) && (values != NULL)) { + for (; 0 < len; len -= count, reg += count, values++) + _iwl3945_write_direct32(priv, reg, *values); + } +} + +static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl3945_read_direct32(priv, addr) & mask) == mask) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} + +#ifdef CONFIG_IWL3945_DEBUG +static inline int __iwl3945_poll_direct_bit(const char *f, u32 l, + struct iwl3945_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int ret = _iwl3945_poll_direct_bit(priv, addr, mask, timeout); + + if (unlikely(ret == -ETIMEDOUT)) + IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - " + "timedout - %s %d\n", addr, mask, f, l); + else + IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " + "- %s %d\n", addr, mask, ret, f, l); + return ret; +} +#define iwl3945_poll_direct_bit(iwl, addr, mask, timeout) \ + __iwl3945_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) +#else +#define iwl3945_poll_direct_bit _iwl3945_poll_direct_bit +#endif + +static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg) +{ + _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT); +} +#ifdef CONFIG_IWL3945_DEBUG +static inline u32 __iwl3945_read_prph(u32 line, struct iwl3945_priv *priv, u32 reg) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + return _iwl3945_read_prph(priv, reg); +} + +#define iwl3945_read_prph(priv, reg) \ + __iwl3945_read_prph(__LINE__, priv, reg) +#else +#define iwl3945_read_prph _iwl3945_read_prph +#endif + +static inline void _iwl3945_write_prph(struct iwl3945_priv *priv, + u32 addr, u32 val) +{ + _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); +} +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_write_prph(u32 line, struct iwl3945_priv *priv, + u32 addr, u32 val) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access from line %d\n", line); + _iwl3945_write_prph(priv, addr, val); +} + +#define iwl3945_write_prph(priv, addr, val) \ + __iwl3945_write_prph(__LINE__, priv, addr, val); +#else +#define iwl3945_write_prph _iwl3945_write_prph +#endif + +#define _iwl3945_set_bits_prph(priv, reg, mask) \ + _iwl3945_write_prph(priv, reg, (_iwl3945_read_prph(priv, reg) | mask)) +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_set_bits_prph(u32 line, struct iwl3945_priv *priv, + u32 reg, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + + _iwl3945_set_bits_prph(priv, reg, mask); +} +#define iwl3945_set_bits_prph(priv, reg, mask) \ + __iwl3945_set_bits_prph(__LINE__, priv, reg, mask) +#else +#define iwl3945_set_bits_prph _iwl3945_set_bits_prph +#endif + +#define _iwl3945_set_bits_mask_prph(priv, reg, bits, mask) \ + _iwl3945_write_prph(priv, reg, ((_iwl3945_read_prph(priv, reg) & mask) | bits)) + +#ifdef CONFIG_IWL3945_DEBUG +static inline void __iwl3945_set_bits_mask_prph(u32 line, + struct iwl3945_priv *priv, u32 reg, u32 bits, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + _iwl3945_set_bits_mask_prph(priv, reg, bits, mask); +} +#define iwl3945_set_bits_mask_prph(priv, reg, bits, mask) \ + __iwl3945_set_bits_mask_prph(__LINE__, priv, reg, bits, mask) +#else +#define iwl3945_set_bits_mask_prph _iwl3945_set_bits_mask_prph +#endif + +static inline void iwl3945_clear_bits_prph(struct iwl3945_priv + *priv, u32 reg, u32 mask) +{ + u32 val = _iwl3945_read_prph(priv, reg); + _iwl3945_write_prph(priv, reg, (val & ~mask)); +} + +static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr) +{ + iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT); +} + +static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val) +{ + iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); +} + +static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 addr, + u32 len, u32 *values) +{ + iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + for (; 0 < len; len -= sizeof(u32), values++) + iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index c48b1b537d2b..80d31ae51e77 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -37,15 +37,13 @@ #include <linux/workqueue.h> -#define IWL 3945 - #include "../net/mac80211/ieee80211_rate.h" -#include "iwlwifi.h" +#include "iwl-3945.h" #define RS_NAME "iwl-3945-rs" -struct iwl_rate_scale_data { +struct iwl3945_rate_scale_data { u64 data; s32 success_counter; s32 success_ratio; @@ -54,7 +52,7 @@ struct iwl_rate_scale_data { unsigned long stamp; }; -struct iwl_rate_scale_priv { +struct iwl3945_rs_sta { spinlock_t lock; s32 *expected_tpt; unsigned long last_partial_flush; @@ -67,31 +65,31 @@ struct iwl_rate_scale_priv { u8 start_rate; u8 ibss_sta_added; struct timer_list rate_scale_flush; - struct iwl_rate_scale_data win[IWL_RATE_COUNT]; + struct iwl3945_rate_scale_data win[IWL_RATE_COUNT]; }; -static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = { +static s32 iwl3945_expected_tpt_g[IWL_RATE_COUNT] = { 7, 13, 35, 58, 0, 0, 76, 104, 130, 168, 191, 202 }; -static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = { +static s32 iwl3945_expected_tpt_g_prot[IWL_RATE_COUNT] = { 7, 13, 35, 58, 0, 0, 0, 80, 93, 113, 123, 125 }; -static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = { +static s32 iwl3945_expected_tpt_a[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186 }; -static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = { +static s32 iwl3945_expected_tpt_b[IWL_RATE_COUNT] = { 7, 13, 35, 58, 0, 0, 0, 0, 0, 0, 0, 0 }; -struct iwl_tpt_entry { +struct iwl3945_tpt_entry { s8 min_rssi; u8 index; }; -static struct iwl_tpt_entry iwl_tpt_table_a[] = { +static struct iwl3945_tpt_entry iwl3945_tpt_table_a[] = { {-60, IWL_RATE_54M_INDEX}, {-64, IWL_RATE_48M_INDEX}, {-72, IWL_RATE_36M_INDEX}, @@ -102,7 +100,7 @@ static struct iwl_tpt_entry iwl_tpt_table_a[] = { {-89, IWL_RATE_6M_INDEX} }; -static struct iwl_tpt_entry iwl_tpt_table_b[] = { +static struct iwl3945_tpt_entry iwl3945_tpt_table_b[] = { {-86, IWL_RATE_11M_INDEX}, {-88, IWL_RATE_5M_INDEX}, {-90, IWL_RATE_2M_INDEX}, @@ -110,7 +108,7 @@ static struct iwl_tpt_entry iwl_tpt_table_b[] = { }; -static struct iwl_tpt_entry iwl_tpt_table_g[] = { +static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { {-60, IWL_RATE_54M_INDEX}, {-64, IWL_RATE_48M_INDEX}, {-68, IWL_RATE_36M_INDEX}, @@ -131,30 +129,30 @@ static struct iwl_tpt_entry iwl_tpt_table_g[] = { #define IWL_RATE_MIN_SUCCESS_TH 8 #define IWL_RATE_DECREASE_TH 1920 -static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode) +static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode) { u32 index = 0; u32 table_size = 0; - struct iwl_tpt_entry *tpt_table = NULL; + struct iwl3945_tpt_entry *tpt_table = NULL; if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) rssi = IWL_MIN_RSSI_VAL; switch (mode) { case MODE_IEEE80211G: - tpt_table = iwl_tpt_table_g; - table_size = ARRAY_SIZE(iwl_tpt_table_g); + tpt_table = iwl3945_tpt_table_g; + table_size = ARRAY_SIZE(iwl3945_tpt_table_g); break; case MODE_IEEE80211A: - tpt_table = iwl_tpt_table_a; - table_size = ARRAY_SIZE(iwl_tpt_table_a); + tpt_table = iwl3945_tpt_table_a; + table_size = ARRAY_SIZE(iwl3945_tpt_table_a); break; default: case MODE_IEEE80211B: - tpt_table = iwl_tpt_table_b; - table_size = ARRAY_SIZE(iwl_tpt_table_b); + tpt_table = iwl3945_tpt_table_b; + table_size = ARRAY_SIZE(iwl3945_tpt_table_b); break; } @@ -166,7 +164,7 @@ static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode) return tpt_table[index].index; } -static void iwl_clear_window(struct iwl_rate_scale_data *window) +static void iwl3945_clear_window(struct iwl3945_rate_scale_data *window) { window->data = 0; window->success_counter = 0; @@ -177,13 +175,13 @@ static void iwl_clear_window(struct iwl_rate_scale_data *window) } /** - * iwl_rate_scale_flush_windows - flush out the rate scale windows + * iwl3945_rate_scale_flush_windows - flush out the rate scale windows * * Returns the number of windows that have gathered data but were * not flushed. If there were any that were not flushed, then * reschedule the rate flushing routine. */ -static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv) +static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta) { int unflushed = 0; int i; @@ -195,19 +193,19 @@ static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv) * since we flushed, clear out the gathered statistics */ for (i = 0; i < IWL_RATE_COUNT; i++) { - if (!rs_priv->win[i].counter) + if (!rs_sta->win[i].counter) continue; - spin_lock_irqsave(&rs_priv->lock, flags); - if (time_after(jiffies, rs_priv->win[i].stamp + + spin_lock_irqsave(&rs_sta->lock, flags); + if (time_after(jiffies, rs_sta->win[i].stamp + IWL_RATE_WIN_FLUSH)) { IWL_DEBUG_RATE("flushing %d samples of rate " "index %d\n", - rs_priv->win[i].counter, i); - iwl_clear_window(&rs_priv->win[i]); + rs_sta->win[i].counter, i); + iwl3945_clear_window(&rs_sta->win[i]); } else unflushed++; - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); } return unflushed; @@ -216,30 +214,30 @@ static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv) #define IWL_RATE_FLUSH_MAX 5000 /* msec */ #define IWL_RATE_FLUSH_MIN 50 /* msec */ -static void iwl_bg_rate_scale_flush(unsigned long data) +static void iwl3945_bg_rate_scale_flush(unsigned long data) { - struct iwl_rate_scale_priv *rs_priv = (void *)data; + struct iwl3945_rs_sta *rs_sta = (void *)data; int unflushed = 0; unsigned long flags; u32 packet_count, duration, pps; IWL_DEBUG_RATE("enter\n"); - unflushed = iwl_rate_scale_flush_windows(rs_priv); + unflushed = iwl3945_rate_scale_flush_windows(rs_sta); - spin_lock_irqsave(&rs_priv->lock, flags); + spin_lock_irqsave(&rs_sta->lock, flags); - rs_priv->flush_pending = 0; + rs_sta->flush_pending = 0; /* Number of packets Rx'd since last time this timer ran */ - packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1; + packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1; - rs_priv->last_tx_packets = rs_priv->tx_packets + 1; + rs_sta->last_tx_packets = rs_sta->tx_packets + 1; if (unflushed) { duration = - jiffies_to_msecs(jiffies - rs_priv->last_partial_flush); -/* duration = jiffies_to_msecs(rs_priv->flush_time); */ + jiffies_to_msecs(jiffies - rs_sta->last_partial_flush); +/* duration = jiffies_to_msecs(rs_sta->flush_time); */ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", packet_count, duration); @@ -257,36 +255,36 @@ static void iwl_bg_rate_scale_flush(unsigned long data) } else duration = IWL_RATE_FLUSH_MAX; - rs_priv->flush_time = msecs_to_jiffies(duration); + rs_sta->flush_time = msecs_to_jiffies(duration); IWL_DEBUG_RATE("new flush period: %d msec ave %d\n", duration, packet_count); - mod_timer(&rs_priv->rate_scale_flush, jiffies + - rs_priv->flush_time); + mod_timer(&rs_sta->rate_scale_flush, jiffies + + rs_sta->flush_time); - rs_priv->last_partial_flush = jiffies; + rs_sta->last_partial_flush = jiffies; } /* If there weren't any unflushed entries, we don't schedule the timer * to run again */ - rs_priv->last_flush = jiffies; + rs_sta->last_flush = jiffies; - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); IWL_DEBUG_RATE("leave\n"); } /** - * iwl_collect_tx_data - Update the success/failure sliding window + * iwl3945_collect_tx_data - Update the success/failure sliding window * * We keep a sliding window of the last 64 packets transmitted * at this rate. window->data contains the bitmask of successful * packets. */ -static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, - struct iwl_rate_scale_data *window, +static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, + struct iwl3945_rate_scale_data *window, int success, int retries) { unsigned long flags; @@ -297,7 +295,7 @@ static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, } while (retries--) { - spin_lock_irqsave(&rs_priv->lock, flags); + spin_lock_irqsave(&rs_sta->lock, flags); /* If we have filled up the window then subtract one from the * success counter if the high-bit is counting toward @@ -325,7 +323,7 @@ static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv, /* Tag this window as having been updated */ window->stamp = jiffies; - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); } } @@ -362,7 +360,7 @@ static void *rs_alloc(struct ieee80211_local *local) return local->hw.priv; } -/* rate scale requires free function to be implmented */ +/* rate scale requires free function to be implemented */ static void rs_free(void *priv) { return; @@ -375,49 +373,49 @@ static void rs_clear(void *priv) static void *rs_alloc_sta(void *priv, gfp_t gfp) { - struct iwl_rate_scale_priv *rs_priv; + struct iwl3945_rs_sta *rs_sta; int i; IWL_DEBUG_RATE("enter\n"); - rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); - if (!rs_priv) { + rs_sta = kzalloc(sizeof(struct iwl3945_rs_sta), gfp); + if (!rs_sta) { IWL_DEBUG_RATE("leave: ENOMEM\n"); return NULL; } - spin_lock_init(&rs_priv->lock); + spin_lock_init(&rs_sta->lock); - rs_priv->start_rate = IWL_RATE_INVALID; + rs_sta->start_rate = IWL_RATE_INVALID; /* default to just 802.11b */ - rs_priv->expected_tpt = iwl_expected_tpt_b; + rs_sta->expected_tpt = iwl3945_expected_tpt_b; - rs_priv->last_partial_flush = jiffies; - rs_priv->last_flush = jiffies; - rs_priv->flush_time = IWL_RATE_FLUSH; - rs_priv->last_tx_packets = 0; - rs_priv->ibss_sta_added = 0; + rs_sta->last_partial_flush = jiffies; + rs_sta->last_flush = jiffies; + rs_sta->flush_time = IWL_RATE_FLUSH; + rs_sta->last_tx_packets = 0; + rs_sta->ibss_sta_added = 0; - init_timer(&rs_priv->rate_scale_flush); - rs_priv->rate_scale_flush.data = (unsigned long)rs_priv; - rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush; + init_timer(&rs_sta->rate_scale_flush); + rs_sta->rate_scale_flush.data = (unsigned long)rs_sta; + rs_sta->rate_scale_flush.function = &iwl3945_bg_rate_scale_flush; for (i = 0; i < IWL_RATE_COUNT; i++) - iwl_clear_window(&rs_priv->win[i]); + iwl3945_clear_window(&rs_sta->win[i]); IWL_DEBUG_RATE("leave\n"); - return rs_priv; + return rs_sta; } static void rs_free_sta(void *priv, void *priv_sta) { - struct iwl_rate_scale_priv *rs_priv = priv_sta; + struct iwl3945_rs_sta *rs_sta = priv_sta; IWL_DEBUG_RATE("enter\n"); - del_timer_sync(&rs_priv->rate_scale_flush); - kfree(rs_priv); + del_timer_sync(&rs_sta->rate_scale_flush); + kfree(rs_sta); IWL_DEBUG_RATE("leave\n"); } @@ -427,9 +425,9 @@ static void rs_free_sta(void *priv, void *priv_sta) * for A and B mode we need to overright prev * value */ -static int rs_adjust_next_rate(struct iwl_priv *priv, int rate) +static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) { - int next_rate = iwl_get_prev_ieee_rate(rate); + int next_rate = iwl3945_get_prev_ieee_rate(rate); switch (priv->phymode) { case MODE_IEEE80211A: @@ -451,7 +449,7 @@ static int rs_adjust_next_rate(struct iwl_priv *priv, int rate) /** * rs_tx_status - Update rate control values based on Tx results * - * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by + * NOTE: Uses iwl3945_priv->retry_rate for the # of retries attempted by * the hardware for each rate. */ static void rs_tx_status(void *priv_rate, @@ -464,9 +462,9 @@ static void rs_tx_status(void *priv_rate, unsigned long flags; struct sta_info *sta; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iwl_rate_scale_priv *rs_priv; + struct iwl3945_rs_sta *rs_sta; IWL_DEBUG_RATE("enter\n"); @@ -487,9 +485,9 @@ static void rs_tx_status(void *priv_rate, return; } - rs_priv = (void *)sta->rate_ctrl_priv; + rs_sta = (void *)sta->rate_ctrl_priv; - rs_priv->tx_packets++; + rs_sta->tx_packets++; scale_rate_index = first_index; last_index = first_index; @@ -516,8 +514,8 @@ static void rs_tx_status(void *priv_rate, /* Update this rate accounting for as many retries * as was used for it (per current_count) */ - iwl_collect_tx_data(rs_priv, - &rs_priv->win[scale_rate_index], + iwl3945_collect_tx_data(rs_sta, + &rs_sta->win[scale_rate_index], 0, current_count); IWL_DEBUG_RATE("Update rate %d for %d retries.\n", scale_rate_index, current_count); @@ -535,25 +533,25 @@ static void rs_tx_status(void *priv_rate, last_index, (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ? "success" : "failure"); - iwl_collect_tx_data(rs_priv, - &rs_priv->win[last_index], + iwl3945_collect_tx_data(rs_sta, + &rs_sta->win[last_index], tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush * again */ - spin_lock_irqsave(&rs_priv->lock, flags); + spin_lock_irqsave(&rs_sta->lock, flags); - if (!rs_priv->flush_pending && - time_after(jiffies, rs_priv->last_partial_flush + - rs_priv->flush_time)) { + if (!rs_sta->flush_pending && + time_after(jiffies, rs_sta->last_partial_flush + + rs_sta->flush_time)) { - rs_priv->flush_pending = 1; - mod_timer(&rs_priv->rate_scale_flush, - jiffies + rs_priv->flush_time); + rs_sta->flush_pending = 1; + mod_timer(&rs_sta->rate_scale_flush, + jiffies + rs_sta->flush_time); } - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); sta_info_put(sta); @@ -562,29 +560,13 @@ static void rs_tx_status(void *priv_rate, return; } -static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local - *local) -{ - struct ieee80211_hw_mode *mode = local->oper_hw_mode; - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - if (rate->flags & IEEE80211_RATE_SUPPORTED) - return rate; - } - - return &mode->rates[0]; -} - -static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv, +static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, u8 index, u16 rate_mask, int phymode) { u8 high = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID; - /* 802.11A walks to the next literal adjascent rate in + /* 802.11A walks to the next literal adjacent rate in * the rate table */ if (unlikely(phymode == MODE_IEEE80211A)) { int i; @@ -613,10 +595,10 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv, low = index; while (low != IWL_RATE_INVALID) { - if (rs_priv->tgg) - low = iwl_rates[low].prev_rs_tgg; + if (rs_sta->tgg) + low = iwl3945_rates[low].prev_rs_tgg; else - low = iwl_rates[low].prev_rs; + low = iwl3945_rates[low].prev_rs; if (low == IWL_RATE_INVALID) break; if (rate_mask & (1 << low)) @@ -626,10 +608,10 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv, high = index; while (high != IWL_RATE_INVALID) { - if (rs_priv->tgg) - high = iwl_rates[high].next_rs_tgg; + if (rs_sta->tgg) + high = iwl3945_rates[high].next_rs_tgg; else - high = iwl_rates[high].next_rs; + high = iwl3945_rates[high].next_rs; if (high == IWL_RATE_INVALID) break; if (rate_mask & (1 << high)) @@ -656,17 +638,16 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv, * rate table and must reference the driver allocated rate table * */ -static struct ieee80211_rate *rs_get_rate(void *priv_rate, - struct net_device *dev, - struct sk_buff *skb, - struct rate_control_extra *extra) +static void rs_get_rate(void *priv_rate, struct net_device *dev, + struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct rate_selection *sel) { u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; int index; - struct iwl_rate_scale_priv *rs_priv; - struct iwl_rate_scale_data *window = NULL; + struct iwl3945_rs_sta *rs_sta; + struct iwl3945_rate_scale_data *window = NULL; int current_tpt = IWL_INVALID_VALUE; int low_tpt = IWL_INVALID_VALUE; int high_tpt = IWL_INVALID_VALUE; @@ -677,31 +658,24 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct sta_info *sta; u16 fc, rate_mask; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; DECLARE_MAC_BUF(mac); IWL_DEBUG_RATE("enter\n"); - memset(extra, 0, sizeof(*extra)); + sta = sta_info_get(local, hdr->addr1); + /* Send management frames and broadcast/multicast data using lowest + * rate. */ fc = le16_to_cpu(hdr->frame_control); - if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || - (is_multicast_ether_addr(hdr->addr1))) { - /* Send management frames and broadcast/multicast data using - * lowest rate. */ - /* TODO: this could probably be improved.. */ - IWL_DEBUG_RATE("leave: lowest rate (not data or is " - "multicast)\n"); - - return iwl_get_lowest_rate(local); - } - - sta = sta_info_get(local, hdr->addr1); - if (!sta || !sta->rate_ctrl_priv) { + if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || + is_multicast_ether_addr(hdr->addr1) || + !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); + sel->rate = rate_lowest(local, local->oper_hw_mode, sta); if (sta) sta_info_put(sta); - return NULL; + return; } rate_mask = sta->supp_rates; @@ -710,37 +684,37 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, if (priv->phymode == (u8) MODE_IEEE80211A) rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; - rs_priv = (void *)sta->rate_ctrl_priv; + rs_sta = (void *)sta->rate_ctrl_priv; if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !rs_priv->ibss_sta_added) { - u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + !rs_sta->ibss_sta_added) { + u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, hdr->addr1)); - sta_id = iwl_add_station(priv, + sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } if (sta_id != IWL_INVALID_STATION) - rs_priv->ibss_sta_added = 1; + rs_sta->ibss_sta_added = 1; } - spin_lock_irqsave(&rs_priv->lock, flags); + spin_lock_irqsave(&rs_sta->lock, flags); - if (rs_priv->start_rate != IWL_RATE_INVALID) { - index = rs_priv->start_rate; - rs_priv->start_rate = IWL_RATE_INVALID; + if (rs_sta->start_rate != IWL_RATE_INVALID) { + index = rs_sta->start_rate; + rs_sta->start_rate = IWL_RATE_INVALID; } - window = &(rs_priv->win[index]); + window = &(rs_sta->win[index]); fail_count = window->counter - window->success_counter; if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { window->average_tpt = IWL_INVALID_VALUE; - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " "counter: %d, success_counter: %d, " @@ -748,27 +722,27 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, index, window->counter, window->success_counter, - rs_priv->expected_tpt ? "not " : ""); + rs_sta->expected_tpt ? "not " : ""); goto out; } window->average_tpt = ((window->success_ratio * - rs_priv->expected_tpt[index] + 64) / 128); + rs_sta->expected_tpt[index] + 64) / 128); current_tpt = window->average_tpt; - high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask, + high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, local->hw.conf.phymode); low = high_low & 0xff; high = (high_low >> 8) & 0xff; if (low != IWL_RATE_INVALID) - low_tpt = rs_priv->win[low].average_tpt; + low_tpt = rs_sta->win[low].average_tpt; if (high != IWL_RATE_INVALID) - high_tpt = rs_priv->win[high].average_tpt; + high_tpt = rs_sta->win[high].average_tpt; - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); scale_action = 1; @@ -846,7 +820,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate, IWL_DEBUG_RATE("leave: %d\n", index); - return &priv->ieee_rates[index]; + sel->rate = &priv->ieee_rates[index]; } static struct rate_control_ops rs_ops = { @@ -862,11 +836,11 @@ static struct rate_control_ops rs_ops = { .free_sta = rs_free_sta, }; -int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +int iwl3945_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_rate_scale_priv *rs_priv; + struct iwl3945_priv *priv = hw->priv; + struct iwl3945_rs_sta *rs_sta; struct sta_info *sta; unsigned long flags; int count = 0, i; @@ -884,28 +858,29 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) return sprintf(buf, "station %d not found\n", sta_id); } - rs_priv = (void *)sta->rate_ctrl_priv; - spin_lock_irqsave(&rs_priv->lock, flags); + rs_sta = (void *)sta->rate_ctrl_priv; + spin_lock_irqsave(&rs_sta->lock, flags); i = IWL_RATE_54M_INDEX; while (1) { u64 mask; int j; count += - sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2); + sprintf(&buf[count], " %2dMbs: ", iwl3945_rates[i].ieee / 2); mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) buf[count++] = - (rs_priv->win[i].data & mask) ? '1' : '0'; + (rs_sta->win[i].data & mask) ? '1' : '0'; - samples += rs_priv->win[i].counter; - good += rs_priv->win[i].success_counter; - success += rs_priv->win[i].success_counter * iwl_rates[i].ieee; + samples += rs_sta->win[i].counter; + good += rs_sta->win[i].success_counter; + success += rs_sta->win[i].success_counter * + iwl3945_rates[i].ieee; - if (rs_priv->win[i].stamp) { + if (rs_sta->win[i].stamp) { int delta = - jiffies_to_msecs(now - rs_priv->win[i].stamp); + jiffies_to_msecs(now - rs_sta->win[i].stamp); if (delta > max_time) max_time = delta; @@ -914,18 +889,18 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) } else buf[count++] = '\n'; - j = iwl_get_prev_ieee_rate(i); + j = iwl3945_get_prev_ieee_rate(i); if (j == i) break; i = j; } - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); sta_info_put(sta); /* Display the average rate of all samples taken. * * NOTE: We multiple # of samples by 2 since the IEEE measurement - * added from iwl_rates is actually 2X the rate */ + * added from iwl3945_rates is actually 2X the rate */ if (samples) count += sprintf( &buf[count], @@ -939,13 +914,13 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) return count; } -void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) +void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; s32 rssi = 0; unsigned long flags; struct ieee80211_local *local = hw_to_local(hw); - struct iwl_rate_scale_priv *rs_priv; + struct iwl3945_rs_sta *rs_sta; struct sta_info *sta; IWL_DEBUG_RATE("enter\n"); @@ -965,33 +940,33 @@ void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) return; } - rs_priv = (void *)sta->rate_ctrl_priv; + rs_sta = (void *)sta->rate_ctrl_priv; - spin_lock_irqsave(&rs_priv->lock, flags); + spin_lock_irqsave(&rs_sta->lock, flags); - rs_priv->tgg = 0; + rs_sta->tgg = 0; switch (priv->phymode) { case MODE_IEEE80211G: if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) { - rs_priv->tgg = 1; - rs_priv->expected_tpt = iwl_expected_tpt_g_prot; + rs_sta->tgg = 1; + rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot; } else - rs_priv->expected_tpt = iwl_expected_tpt_g; + rs_sta->expected_tpt = iwl3945_expected_tpt_g; break; case MODE_IEEE80211A: - rs_priv->expected_tpt = iwl_expected_tpt_a; + rs_sta->expected_tpt = iwl3945_expected_tpt_a; break; default: IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n"); case MODE_IEEE80211B: - rs_priv->expected_tpt = iwl_expected_tpt_b; + rs_sta->expected_tpt = iwl3945_expected_tpt_b; break; } sta_info_put(sta); - spin_unlock_irqrestore(&rs_priv->lock, flags); + spin_unlock_irqrestore(&rs_sta->lock, flags); rssi = priv->last_rx_rssi; if (rssi == 0) @@ -999,19 +974,20 @@ void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi); - rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode); + rs_sta->start_rate = + iwl3945_get_rate_index_by_rssi(rssi, priv->phymode); IWL_DEBUG_RATE("leave: rssi %d assign rate index: " - "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate, - iwl_rates[rs_priv->start_rate].plcp); + "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, + iwl3945_rates[rs_sta->start_rate].plcp); } -void iwl_rate_control_register(struct ieee80211_hw *hw) +void iwl3945_rate_control_register(struct ieee80211_hw *hw) { ieee80211_rate_control_register(&rs_ops); } -void iwl_rate_control_unregister(struct ieee80211_hw *hw) +void iwl3945_rate_control_unregister(struct ieee80211_hw *hw) { ieee80211_rate_control_unregister(&rs_ops); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index bec4d3ffca1d..d5e9220f871d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -27,9 +27,9 @@ #ifndef __iwl_3945_rs_h__ #define __iwl_3945_rs_h__ -struct iwl_rate_info { - u8 plcp; - u8 ieee; +struct iwl3945_rate_info { + u8 plcp; /* uCode API: IWL_RATE_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 */ @@ -38,9 +38,12 @@ struct iwl_rate_info { u8 next_rs_tgg; /* next rate used in TGG rs algo */ u8 table_rs_index; /* index in rate scale table cmd */ u8 prev_table_rs; /* prev in rate table cmd */ - }; +/* + * These serve as indexes into + * struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT]; + */ enum { IWL_RATE_1M_INDEX = 0, IWL_RATE_2M_INDEX, @@ -83,19 +86,20 @@ enum { }; /* #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_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) - +#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_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) + +/* 3945 uCode API values for (legacy) bit rates, both OFDM and CCK */ enum { IWL_RATE_6M_PLCP = 13, IWL_RATE_9M_PLCP = 15, @@ -111,6 +115,7 @@ enum { IWL_RATE_11M_PLCP = 110, }; +/* MAC header values for bit rates */ enum { IWL_RATE_6M_IEEE = 12, IWL_RATE_9M_IEEE = 18, @@ -152,18 +157,18 @@ enum { (IWL_OFDM_BASIC_RATES_MASK | \ IWL_CCK_BASIC_RATES_MASK) -#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1) +#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 -extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; +extern const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT]; -static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) +static inline u8 iwl3945_get_prev_ieee_rate(u8 rate_index) { - u8 rate = iwl_rates[rate_index].prev_ieee; + u8 rate = iwl3945_rates[rate_index].prev_ieee; if (rate == IWL_RATE_INVALID) rate = rate_index; @@ -171,40 +176,40 @@ static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) } /** - * iwl_fill_rs_info - Fill an output text buffer with the rate representation + * iwl3945_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 alogirthm and is not meant to be + * the performance of the rate control algorithm and is not meant to be * parsed software. */ -extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); +extern int iwl3945_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); /** - * iwl_rate_scale_init - Initialize the rate scale table based on assoc info + * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info * - * The specific througput table used is based on the type of network + * The specific throughput table used is based on the type of network * the associated with, including A, B, G, and G w/ TGG protection */ -extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); +extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); /** - * iwl_rate_control_register - Register the rate control algorithm callbacks + * iwl3945_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 - * iwl_rate_control_register in order to register the rate control callbacks + * iwl3945_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 void iwl_rate_control_register(struct ieee80211_hw *hw); +extern void iwl3945_rate_control_register(struct ieee80211_hw *hw); /** - * iwl_rate_control_unregister - Unregister the rate control callbacks + * iwl3945_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 iwl_rate_control_unregister(struct ieee80211_hw *hw); +extern void iwl3945_rate_control_unregister(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 3a45fe99a83e..76c4ed1135f2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -35,15 +35,12 @@ #include <linux/netdevice.h> #include <linux/wireless.h> #include <linux/firmware.h> -#include <net/mac80211.h> - #include <linux/etherdevice.h> +#include <asm/unaligned.h> +#include <net/mac80211.h> -#define IWL 3945 - -#include "iwlwifi.h" -#include "iwl-helpers.h" #include "iwl-3945.h" +#include "iwl-helpers.h" #include "iwl-3945-rs.h" #define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np) \ @@ -66,7 +63,7 @@ * maps to IWL_RATE_INVALID * */ -const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { +const struct iwl3945_rate_info iwl3945_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2), /* 1mbps */ IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5), /* 2mbps */ IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11), /*5.5mbps */ @@ -81,12 +78,12 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */ }; -/* 1 = enable the iwl_disable_events() function */ +/* 1 = enable the iwl3945_disable_events() function */ #define IWL_EVT_DISABLE (0) #define IWL_EVT_DISABLE_SIZE (1532/32) /** - * iwl_disable_events - Disable selected events in uCode event log + * iwl3945_disable_events - Disable selected events in uCode event log * * Disable an event by writing "1"s into "disable" * bitmap in SRAM. Bit position corresponds to Event # (id/type). @@ -94,9 +91,9 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { * Use for only special debugging. This function is just a placeholder as-is, * you'll need to provide the special bits! ... * ... and set IWL_EVT_DISABLE to 1. */ -void iwl_disable_events(struct iwl_priv *priv) +void iwl3945_disable_events(struct iwl3945_priv *priv) { - int rc; + int ret; int i; u32 base; /* SRAM address of event log header */ u32 disable_ptr; /* SRAM address of event-disable bitmap array */ @@ -152,32 +149,31 @@ void iwl_disable_events(struct iwl_priv *priv) }; base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!iwl_hw_valid_rtc_data_addr(base)) { + if (!iwl3945_hw_valid_rtc_data_addr(base)) { IWL_ERROR("Invalid event log pointer 0x%08X\n", base); return; } - rc = iwl_grab_restricted_access(priv); - if (rc) { + ret = iwl3945_grab_nic_access(priv); + if (ret) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } - disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32))); - array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32))); - iwl_release_restricted_access(priv); + disable_ptr = iwl3945_read_targ_mem(priv, base + (4 * sizeof(u32))); + array_size = iwl3945_read_targ_mem(priv, base + (5 * sizeof(u32))); + iwl3945_release_nic_access(priv); if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) { IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n", disable_ptr); - rc = iwl_grab_restricted_access(priv); + ret = iwl3945_grab_nic_access(priv); for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++) - iwl_write_restricted_mem(priv, - disable_ptr + - (i * sizeof(u32)), - evt_disable[i]); + iwl3945_write_targ_mem(priv, + disable_ptr + (i * sizeof(u32)), + evt_disable[i]); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } else { IWL_DEBUG_INFO("Selected uCode log events may be disabled\n"); IWL_DEBUG_INFO(" by writing \"1\"s into disable bitmap\n"); @@ -198,7 +194,7 @@ void iwl_disable_events(struct iwl_priv *priv) * IWL_ANTENNA_MAIN - Force MAIN antenna * IWL_ANTENNA_AUX - Force AUX antenna */ -__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) +__le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv) { switch (priv->antenna) { case IWL_ANTENNA_DIVERSITY: @@ -230,11 +226,11 @@ __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv) * *****************************************************************************/ -void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n", - (int)sizeof(struct iwl_notif_statistics), + (int)sizeof(struct iwl3945_notif_statistics), le32_to_cpu(pkt->len)); memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics)); @@ -242,15 +238,107 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) priv->last_statistics_time = jiffies; } -static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data, - struct iwl_rx_mem_buffer *rxb, - struct ieee80211_rx_status *stats, - u16 phy_flags) +void iwl3945_add_radiotap(struct iwl3945_priv *priv, struct sk_buff *skb, + struct iwl3945_rx_frame_hdr *rx_hdr, + struct ieee80211_rx_status *stats) +{ + /* First cache any information we need before we overwrite + * the information provided in the skb from the hardware */ + s8 signal = stats->ssi; + s8 noise = 0; + int rate = stats->rate; + u64 tsf = stats->mactime; + __le16 phy_flags_hw = rx_hdr->phy_flags; + + struct iwl3945_rt_rx_hdr { + struct ieee80211_radiotap_header rt_hdr; + __le64 rt_tsf; /* TSF */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channelMHz; /* channel in MHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + } __attribute__ ((packed)) *iwl3945_rt; + + if (skb_headroom(skb) < sizeof(*iwl3945_rt)) { + if (net_ratelimit()) + printk(KERN_ERR "not enough headroom [%d] for " + "radiotap head [%zd]\n", + skb_headroom(skb), sizeof(*iwl3945_rt)); + return; + } + + /* put radiotap header in front of 802.11 header and data */ + iwl3945_rt = (void *)skb_push(skb, sizeof(*iwl3945_rt)); + + /* initialise radiotap header */ + iwl3945_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl3945_rt->rt_hdr.it_pad = 0; + + /* total header + data */ + put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)), + &iwl3945_rt->rt_hdr.it_len); + + /* Indicate all the fields we add to the radiotap header */ + put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)), + &iwl3945_rt->rt_hdr.it_present); + + /* Zero the flags, we'll add to them as we go */ + iwl3945_rt->rt_flags = 0; + + put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf); + + iwl3945_rt->rt_dbmsignal = signal; + iwl3945_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ), + &iwl3945_rt->rt_chbitmask); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ), + &iwl3945_rt->rt_chbitmask); + else /* 802.11g */ + put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_2GHZ), + &iwl3945_rt->rt_chbitmask); + + rate = iwl3945_rate_index_from_plcp(rate); + if (rate == -1) + iwl3945_rt->rt_rate = 0; + else + iwl3945_rt->rt_rate = iwl3945_rates[rate].ieee; + + /* antenna number */ + iwl3945_rt->rt_antenna = + le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if we have it */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl3945_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + stats->flag |= RX_FLAG_RADIOTAP; +} + +static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data, + struct iwl3945_rx_mem_buffer *rxb, + struct ieee80211_rx_status *stats) { struct ieee80211_hdr *hdr; - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; + 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); /* We received data from the HW, so stop the watchdog */ @@ -265,15 +353,6 @@ static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data, ("Dropping packet while interface is not open.\n"); return; } - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - if (iwl_param_hwcrypto) - iwl_set_decrypted_flag(priv, rxb->skb, - le32_to_cpu(rx_end->status), - stats); - iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt), - len, stats, phy_flags); - return; - } skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt); /* Set the size of the skb to the size of the frame */ @@ -281,23 +360,27 @@ static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data, hdr = (void *)rxb->skb->data; - if (iwl_param_hwcrypto) - iwl_set_decrypted_flag(priv, rxb->skb, + if (iwl3945_param_hwcrypto) + iwl3945_set_decrypted_flag(priv, rxb->skb, le32_to_cpu(rx_end->status), stats); + if (priv->add_radiotap) + iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); + ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); rxb->skb = NULL; } -static void iwl3945_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) + +static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); struct ieee80211_hdr *header; - u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags); u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg); u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff); struct ieee80211_rx_status stats = { @@ -327,7 +410,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, } if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags); + iwl3945_handle_data_packet(priv, 1, rxb, &stats); return; } @@ -351,14 +434,14 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, * Calculate stats.signal (quality indicator in %) based on SNR. */ if (rx_stats_noise_diff) { snr = rx_stats_sig_avg / rx_stats_noise_diff; - stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr); - stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise); + stats.noise = stats.ssi - iwl3945_calc_db_from_ratio(snr); + stats.signal = iwl3945_calc_sig_qual(stats.ssi, stats.noise); /* If noise info not available, calculate signal quality indicator (%) * using just the dBm signal level. */ } else { stats.noise = priv->last_rx_noise; - stats.signal = iwl_calc_sig_qual(stats.ssi, 0); + stats.signal = iwl3945_calc_sig_qual(stats.ssi, 0); } @@ -368,24 +451,24 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, stats.freq = ieee80211chan2mhz(stats.channel); - /* can be covered by iwl_report_frame() in most cases */ + /* can be covered by iwl3945_report_frame() in most cases */ /* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); - network_packet = iwl_is_network_packet(priv, header); + network_packet = iwl3945_is_network_packet(priv, header); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_STATS && net_ratelimit()) +#ifdef CONFIG_IWL3945_DEBUG + if (iwl3945_debug_level & IWL_DL_STATS && net_ratelimit()) IWL_DEBUG_STATS ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", network_packet ? '*' : ' ', stats.channel, stats.ssi, stats.ssi, stats.ssi, stats.rate); - if (iwl_debug_level & (IWL_DL_RX)) + if (iwl3945_debug_level & (IWL_DL_RX)) /* Set "1" to report good data frames in groups of 100 */ - iwl_report_frame(priv, pkt, header, 1); + iwl3945_report_frame(priv, pkt, header, 1); #endif if (network_packet) { @@ -437,15 +520,20 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, break; /* - * TODO: There is no callback function from upper - * stack to inform us when associated status. this - * work around to sniff assoc_resp management frame - * and finish the association process. + * TODO: Use the new callback function from + * mac80211 instead of sniffing these packets. */ case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP:{ struct ieee80211_mgmt *mgnt = (struct ieee80211_mgmt *)header; + + /* We have just associated, give some + * time for the 4-way handshake if + * any. Don't start scan too early. */ + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + priv->assoc_id = (~((1 << 15) | (1 << 14)) & le16_to_cpu(mgnt->u. assoc_resp.aid)); @@ -474,7 +562,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, } } - iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags); + iwl3945_handle_data_packet(priv, 0, rxb, &stats); break; case IEEE80211_FTYPE_CTL: @@ -485,25 +573,24 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, DECLARE_MAC_BUF(mac2); DECLARE_MAC_BUF(mac3); - if (unlikely(is_duplicate_packet(priv, header))) + if (unlikely(iwl3945_is_duplicate_packet(priv, header))) IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", print_mac(mac1, header->addr1), print_mac(mac2, header->addr2), print_mac(mac3, header->addr3)); else - iwl3945_handle_data_packet(priv, 1, rxb, &stats, - phy_flags); + iwl3945_handle_data_packet(priv, 1, rxb, &stats); break; } } } -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, +int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *ptr, dma_addr_t addr, u16 len) { int count; u32 pad; - struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr; + struct iwl3945_tfd_frame *tfd = (struct iwl3945_tfd_frame *)ptr; count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags)); pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags)); @@ -526,14 +613,14 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, } /** - * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used] + * iwl3945_hw_txq_free_tfd - Free one TFD, those at index [txq->q.read_ptr] * * Does NOT advance any indexes */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq) { - struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; - struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used]; + struct iwl3945_tfd_frame *bd_tmp = (struct iwl3945_tfd_frame *)&txq->bd[0]; + struct iwl3945_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; struct pci_dev *dev = priv->pci_dev; int i; int counter; @@ -556,19 +643,19 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) for (i = 1; i < counter; i++) { pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr), le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE); - if (txq->txb[txq->q.last_used].skb[0]) { - struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0]; - if (txq->txb[txq->q.last_used].skb[0]) { + if (txq->txb[txq->q.read_ptr].skb[0]) { + struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0]; + if (txq->txb[txq->q.read_ptr].skb[0]) { /* Can be called from interrupt context */ dev_kfree_skb_any(skb); - txq->txb[txq->q.last_used].skb[0] = NULL; + txq->txb[txq->q.read_ptr].skb[0] = NULL; } } } return 0; } -u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) +u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) { int i; int ret = IWL_INVALID_STATION; @@ -592,11 +679,11 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) } /** - * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: + * iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD: * */ -void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, +void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { @@ -609,7 +696,7 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, __le32 tx_flags; u16 fc = le16_to_cpu(hdr->frame_control); - rate = iwl_rates[rate_index].plcp; + rate = iwl3945_rates[rate_index].plcp; tx_flags = cmd->cmd.tx.tx_flags; /* We need to figure out how to get the sta->supp_rates while @@ -676,10 +763,10 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]); } -u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) +u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id, u16 tx_rate, u8 flags) { unsigned long flags_spin; - struct iwl_station_entry *station; + struct iwl3945_station_entry *station; if (sta_id == IWL_INVALID_STATION) return IWL_INVALID_STATION; @@ -694,34 +781,19 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags) spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_station(priv, &station->sta, flags); + iwl3945_send_add_station(priv, &station->sta, flags); IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n", sta_id, tx_rate); return sta_id; } -void iwl_hw_card_show_info(struct iwl_priv *priv) -{ - IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n", - ((priv->eeprom.board_revision >> 8) & 0x0F), - ((priv->eeprom.board_revision >> 8) >> 4), - (priv->eeprom.board_revision & 0x00FF)); - - IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n", - (int)sizeof(priv->eeprom.board_pba_number), - priv->eeprom.board_pba_number); - - IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n", - priv->eeprom.antenna_switch_type); -} - -static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +static int iwl3945_nic_set_pwr_src(struct iwl3945_priv *priv, int pwr_max) { int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; @@ -733,23 +805,23 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, &val); if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) { - iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VAUX, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); - iwl_poll_bit(priv, CSR_GPIO_IN, + iwl3945_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VAUX_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); } else - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } else { - iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG, + iwl3945_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_restricted_access(priv); - iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, + iwl3945_release_nic_access(priv); + iwl3945_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC, CSR_GPIO_IN_BIT_AUX_POWER, 5000); /* uS */ } spin_unlock_irqrestore(&priv->lock, flags); @@ -757,24 +829,24 @@ static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) return rc; } -static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +static int iwl3945_rx_init(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq) { int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr); - iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0), + iwl3945_write_direct32(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr); + iwl3945_write_direct32(priv, FH_RCSR_RPTR_ADDR(0), priv->hw_setting.shared_phys + - offsetof(struct iwl_shared, rx_read_ptr[0])); - iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0); - iwl_write_restricted(priv, FH_RCSR_CONFIG(0), + offsetof(struct iwl3945_shared, rx_read_ptr[0])); + iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), 0); + iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE | ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE | ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN | @@ -785,44 +857,44 @@ static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH); /* fake read to flush all prev I/O */ - iwl_read_restricted(priv, FH_RSSR_CTRL); + iwl3945_read_direct32(priv, FH_RSSR_CTRL); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -static int iwl3945_tx_reset(struct iwl_priv *priv) +static int iwl3945_tx_reset(struct iwl3945_priv *priv) { int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } /* bypass mode */ - iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2); + iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0x2); /* RA 0 is active */ - iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01); + iwl3945_write_prph(priv, ALM_SCD_ARASTAT_REG, 0x01); /* all 6 fifo are active */ - iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f); + iwl3945_write_prph(priv, ALM_SCD_TXFACT_REG, 0x3f); - iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000); - iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002); - iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004); - iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005); + iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_1_REG, 0x010000); + iwl3945_write_prph(priv, ALM_SCD_SBYP_MODE_2_REG, 0x030002); + iwl3945_write_prph(priv, ALM_SCD_TXF4MF_REG, 0x000004); + iwl3945_write_prph(priv, ALM_SCD_TXF5MF_REG, 0x000005); - iwl_write_restricted(priv, FH_TSSR_CBB_BASE, + iwl3945_write_direct32(priv, FH_TSSR_CBB_BASE, priv->hw_setting.shared_phys); - iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG, + iwl3945_write_direct32(priv, FH_TSSR_MSG_CONFIG, ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON | ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON | ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B | @@ -831,7 +903,7 @@ static int iwl3945_tx_reset(struct iwl_priv *priv) ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH | ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -842,12 +914,12 @@ static int iwl3945_tx_reset(struct iwl_priv *priv) * * Destroys all DMA structures and initialize them again */ -static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) +static int iwl3945_txq_ctx_reset(struct iwl3945_priv *priv) { int rc; int txq_id, slots_num; - iwl_hw_txq_ctx_free(priv); + iwl3945_hw_txq_ctx_free(priv); /* Tx CMD queue */ rc = iwl3945_tx_reset(priv); @@ -858,7 +930,7 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, + rc = iwl3945_tx_queue_init(priv, &priv->txq[txq_id], slots_num, txq_id); if (rc) { IWL_ERROR("Tx %d queue init failed\n", txq_id); @@ -869,26 +941,26 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv) return rc; error: - iwl_hw_txq_ctx_free(priv); + iwl3945_hw_txq_ctx_free(priv); return rc; } -int iwl_hw_nic_init(struct iwl_priv *priv) +int iwl3945_hw_nic_init(struct iwl3945_priv *priv) { u8 rev_id; int rc; unsigned long flags; - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl3945_rx_queue *rxq = &priv->rxq; - iwl_power_init_handle(priv); + iwl3945_power_init_handle(priv); spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24)); - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + iwl3945_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24)); + iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = 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 (rc < 0) { @@ -897,18 +969,18 @@ int iwl_hw_nic_init(struct iwl_priv *priv) return rc; } - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + iwl3945_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); udelay(20); - iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + iwl3945_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); /* Determine HW type */ @@ -924,25 +996,17 @@ int iwl_hw_nic_init(struct iwl_priv *priv) IWL_DEBUG_INFO("RTP type \n"); else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) { IWL_DEBUG_INFO("ALM-MB type\n"); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB); } else { IWL_DEBUG_INFO("ALM-MM type\n"); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM); } - spin_unlock_irqrestore(&priv->lock, flags); - - /* Initialize the EEPROM */ - rc = iwl_eeprom_init(priv); - if (rc) - return rc; - - spin_lock_irqsave(&priv->lock, flags); if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) { IWL_DEBUG_INFO("SKU OP mode is mrc\n"); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC); } else IWL_DEBUG_INFO("SKU OP mode is basic\n"); @@ -950,24 +1014,24 @@ int iwl_hw_nic_init(struct iwl_priv *priv) if ((priv->eeprom.board_revision & 0xF0) == 0xD0) { IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", priv->eeprom.board_revision); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); } else { IWL_DEBUG_INFO("3945ABG revision is 0x%X\n", priv->eeprom.board_revision); - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_clear_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE); } if (priv->eeprom.almgor_m_version <= 1) { - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A); IWL_DEBUG_INFO("Card M type A version is 0x%X\n", priv->eeprom.almgor_m_version); } else { IWL_DEBUG_INFO("Card M type B version is 0x%X\n", priv->eeprom.almgor_m_version); - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl3945_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B); } spin_unlock_irqrestore(&priv->lock, flags); @@ -980,15 +1044,15 @@ int iwl_hw_nic_init(struct iwl_priv *priv) /* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) { - rc = iwl_rx_queue_alloc(priv); + rc = iwl3945_rx_queue_alloc(priv); if (rc) { IWL_ERROR("Unable to initialize Rx queue\n"); return -ENOMEM; } } else - iwl_rx_queue_reset(priv, rxq); + iwl3945_rx_queue_reset(priv, rxq); - iwl_rx_replenish(priv); + iwl3945_rx_replenish(priv); iwl3945_rx_init(priv, rxq); @@ -996,16 +1060,16 @@ int iwl_hw_nic_init(struct iwl_priv *priv) /* Look at using this instead: rxq->need_update = 1; - iwl_rx_queue_update_write_ptr(priv, rxq); + iwl3945_rx_queue_update_write_ptr(priv, rxq); */ - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7); - iwl_release_restricted_access(priv); + iwl3945_write_direct32(priv, FH_RCSR_WPTR(0), rxq->write & ~7); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -1019,49 +1083,49 @@ int iwl_hw_nic_init(struct iwl_priv *priv) } /** - * iwl_hw_txq_ctx_free - Free TXQ Context + * iwl3945_hw_txq_ctx_free - Free TXQ Context * * Destroy all TX DMA queues and structures */ -void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +void iwl3945_hw_txq_ctx_free(struct iwl3945_priv *priv) { int txq_id; /* Tx queues */ for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) - iwl_tx_queue_free(priv, &priv->txq[txq_id]); + iwl3945_tx_queue_free(priv, &priv->txq[txq_id]); } -void iwl_hw_txq_ctx_stop(struct iwl_priv *priv) +void iwl3945_hw_txq_ctx_stop(struct iwl3945_priv *priv) { int queue; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_restricted_access(priv)) { + if (iwl3945_grab_nic_access(priv)) { spin_unlock_irqrestore(&priv->lock, flags); - iwl_hw_txq_ctx_free(priv); + iwl3945_hw_txq_ctx_free(priv); return; } /* stop SCD */ - iwl_write_restricted_reg(priv, SCD_MODE_REG, 0); + iwl3945_write_prph(priv, ALM_SCD_MODE_REG, 0); /* reset TFD queues */ for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) { - iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0); - iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS, + iwl3945_write_direct32(priv, FH_TCSR_CONFIG(queue), 0x0); + iwl3945_poll_direct_bit(priv, FH_TSSR_TX_STATUS, ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue), 1000); } - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - iwl_hw_txq_ctx_free(priv); + iwl3945_hw_txq_ctx_free(priv); } -int iwl_hw_nic_stop_master(struct iwl_priv *priv) +int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv) { int rc = 0; u32 reg_val; @@ -1070,16 +1134,16 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - reg_val = iwl_read32(priv, CSR_GP_CNTRL); + reg_val = iwl3945_read32(priv, CSR_GP_CNTRL); if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { - rc = iwl_poll_bit(priv, CSR_RESET, + rc = iwl3945_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { @@ -1094,47 +1158,47 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv) return rc; } -int iwl_hw_nic_reset(struct iwl_priv *priv) +int iwl3945_hw_nic_reset(struct iwl3945_priv *priv) { int rc; unsigned long flags; - iwl_hw_nic_stop_master(priv); + iwl3945_hw_nic_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (!rc) { - iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, + iwl3945_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); - iwl_set_bit(priv, CSR_GP_CNTRL, + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0); - iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG, + iwl3945_write_prph(priv, APMG_RTC_INT_MSK_REG, 0x0); + iwl3945_write_prph(priv, APMG_RTC_INT_STT_REG, 0xFFFFFFFF); /* enable DMA */ - iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + iwl3945_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); - iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + iwl3945_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + iwl3945_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } /* Clear the 'host command active' bit... */ @@ -1147,41 +1211,43 @@ int iwl_hw_nic_reset(struct iwl_priv *priv) } /** - * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table - */ -static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) + * iwl3945_hw_reg_adjust_power_by_temp + * return index delta into power gain settings table +*/ +static int iwl3945_hw_reg_adjust_power_by_temp(int new_reading, int old_reading) { return (new_reading - old_reading) * (-11) / 100; } /** - * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range + * iwl3945_hw_reg_temp_out_of_range - Keep temperature in sane range */ -static inline int iwl_hw_reg_temp_out_of_range(int temperature) +static inline int iwl3945_hw_reg_temp_out_of_range(int temperature) { return (((temperature < -260) || (temperature > 25)) ? 1 : 0); } -int iwl_hw_get_temperature(struct iwl_priv *priv) +int iwl3945_hw_get_temperature(struct iwl3945_priv *priv) { - return iwl_read32(priv, CSR_UCODE_DRV_GP2); + return iwl3945_read32(priv, CSR_UCODE_DRV_GP2); } /** - * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC - */ -static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv) + * iwl3945_hw_reg_txpower_get_temperature + * get the current temperature by reading from NIC +*/ +static int iwl3945_hw_reg_txpower_get_temperature(struct iwl3945_priv *priv) { int temperature; - temperature = iwl_hw_get_temperature(priv); + temperature = iwl3945_hw_get_temperature(priv); /* driver's okay range is -260 to +25. * human readable okay range is 0 to +285 */ IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT); /* handle insane temp reading */ - if (iwl_hw_reg_temp_out_of_range(temperature)) { + if (iwl3945_hw_reg_temp_out_of_range(temperature)) { IWL_ERROR("Error bad temperature value %d\n", temperature); /* if really really hot(?), @@ -1206,11 +1272,11 @@ static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv) * records new temperature in tx_mgr->temperature. * replaces tx_mgr->last_temperature *only* if calib needed * (assumes caller will actually do the calibration!). */ -static int is_temp_calib_needed(struct iwl_priv *priv) +static int is_temp_calib_needed(struct iwl3945_priv *priv) { int temp_diff; - priv->temperature = iwl_hw_reg_txpower_get_temperature(priv); + priv->temperature = iwl3945_hw_reg_txpower_get_temperature(priv); temp_diff = priv->temperature - priv->last_temperature; /* get absolute value */ @@ -1242,7 +1308,7 @@ static int is_temp_calib_needed(struct iwl_priv *priv) /* radio and DSP power table, each step is 1/2 dB. * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */ -static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = { +static struct iwl3945_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = { { {251, 127}, /* 2.4 GHz, highest power */ {251, 127}, @@ -1403,7 +1469,7 @@ static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = { {3, 120} } /* 5.x GHz, lowest power */ }; -static inline u8 iwl_hw_reg_fix_power_index(int index) +static inline u8 iwl3945_hw_reg_fix_power_index(int index) { if (index < 0) return 0; @@ -1416,17 +1482,17 @@ static inline u8 iwl_hw_reg_fix_power_index(int index) #define REG_RECALIB_PERIOD (60) /** - * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests + * iwl3945_hw_reg_set_scan_power - Set Tx power for scan probe requests * * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK) * or 6 Mbit (OFDM) rates. */ -static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index, +static void iwl3945_hw_reg_set_scan_power(struct iwl3945_priv *priv, u32 scan_tbl_index, s32 rate_index, const s8 *clip_pwrs, - struct iwl_channel_info *ch_info, + struct iwl3945_channel_info *ch_info, int band_index) { - struct iwl_scan_power_info *scan_power_info; + struct iwl3945_scan_power_info *scan_power_info; s8 power; u8 power_index; @@ -1462,7 +1528,7 @@ static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index, * of the table. */ /* don't exceed table bounds for "real" setting */ - power_index = iwl_hw_reg_fix_power_index(power_index); + power_index = iwl3945_hw_reg_fix_power_index(power_index); scan_power_info->power_table_index = power_index; scan_power_info->tpc.tx_gain = @@ -1472,21 +1538,21 @@ static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index, } /** - * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings + * iwl3945_hw_reg_send_txpower - fill in Tx Power command with gain settings * * Configures power settings for all rates for the current channel, * using values from channel info struct, and send to NIC */ -int iwl_hw_reg_send_txpower(struct iwl_priv *priv) +int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv) { int rate_idx, i; - const struct iwl_channel_info *ch_info = NULL; - struct iwl_txpowertable_cmd txpower = { + const struct iwl3945_channel_info *ch_info = NULL; + struct iwl3945_txpowertable_cmd txpower = { .channel = priv->active_rxon.channel, }; txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1; - ch_info = iwl_get_channel_info(priv, + ch_info = iwl3945_get_channel_info(priv, priv->phymode, le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) { @@ -1508,7 +1574,7 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) rate_idx <= IWL_LAST_OFDM_RATE; rate_idx++, i++) { txpower.power[i].tpc = ch_info->power_info[i].tpc; - txpower.power[i].rate = iwl_rates[rate_idx].plcp; + txpower.power[i].rate = iwl3945_rates[rate_idx].plcp; IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n", le16_to_cpu(txpower.channel), @@ -1521,7 +1587,7 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) for (rate_idx = IWL_FIRST_CCK_RATE; rate_idx <= IWL_LAST_CCK_RATE; rate_idx++, i++) { txpower.power[i].tpc = ch_info->power_info[i].tpc; - txpower.power[i].rate = iwl_rates[rate_idx].plcp; + txpower.power[i].rate = iwl3945_rates[rate_idx].plcp; IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n", le16_to_cpu(txpower.channel), @@ -1531,13 +1597,13 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) txpower.power[i].rate); } - return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, - sizeof(struct iwl_txpowertable_cmd), &txpower); + return iwl3945_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, + sizeof(struct iwl3945_txpowertable_cmd), &txpower); } /** - * iwl_hw_reg_set_new_power - Configures power tables at new levels + * iwl3945_hw_reg_set_new_power - Configures power tables at new levels * @ch_info: Channel to update. Uses power_info.requested_power. * * Replace requested_power and base_power_index ch_info fields for @@ -1552,10 +1618,10 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) * properly fill out the scan powers, and actual h/w gain settings, * and send changes to NIC */ -static int iwl_hw_reg_set_new_power(struct iwl_priv *priv, - struct iwl_channel_info *ch_info) +static int iwl3945_hw_reg_set_new_power(struct iwl3945_priv *priv, + struct iwl3945_channel_info *ch_info) { - struct iwl_channel_power_info *power_info; + struct iwl3945_channel_power_info *power_info; int power_changed = 0; int i; const s8 *clip_pwrs; @@ -1595,7 +1661,7 @@ static int iwl_hw_reg_set_new_power(struct iwl_priv *priv, ch_info->power_info[IWL_RATE_12M_INDEX_TABLE]. requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF; - /* do all CCK rates' iwl_channel_power_info structures */ + /* do all CCK rates' iwl3945_channel_power_info structures */ for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) { power_info->requested_power = power; power_info->base_power_index = @@ -1609,13 +1675,13 @@ static int iwl_hw_reg_set_new_power(struct iwl_priv *priv, } /** - * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel + * iwl3945_hw_reg_get_ch_txpower_limit - returns new power limit for channel * * NOTE: Returned power limit may be less (but not more) than requested, * based strictly on regulatory (eeprom and spectrum mgt) limitations * (no consideration for h/w clipping limitations). */ -static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info) +static int iwl3945_hw_reg_get_ch_txpower_limit(struct iwl3945_channel_info *ch_info) { s8 max_power; @@ -1634,7 +1700,7 @@ static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info) } /** - * iwl_hw_reg_comp_txpower_temp - Compensate for temperature + * iwl3945_hw_reg_comp_txpower_temp - Compensate for temperature * * Compensate txpower settings of *all* channels for temperature. * This only accounts for the difference between current temperature @@ -1643,9 +1709,9 @@ static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info) * * If RxOn is "associated", this sends the new Txpower to NIC! */ -static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv) +static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv) { - struct iwl_channel_info *ch_info = NULL; + struct iwl3945_channel_info *ch_info = NULL; int delta_index; const s8 *clip_pwrs; /* array of h/w max power levels for each rate */ u8 a_band; @@ -1666,7 +1732,7 @@ static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv) /* get power index adjustment based on curr and factory * temps */ - delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, + delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, ref_temp); /* set tx power value for all rates, OFDM and CCK */ @@ -1679,7 +1745,7 @@ static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv) power_idx += delta_index; /* stay within table range */ - power_idx = iwl_hw_reg_fix_power_index(power_idx); + power_idx = iwl3945_hw_reg_fix_power_index(power_idx); ch_info->power_info[rate_index]. power_table_index = (u8) power_idx; ch_info->power_info[rate_index].tpc = @@ -1694,19 +1760,19 @@ static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv) scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { s32 actual_index = (scan_tbl_index == 0) ? IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE; - iwl_hw_reg_set_scan_power(priv, scan_tbl_index, + iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index, actual_index, clip_pwrs, ch_info, a_band); } } /* send Txpower command for current channel to ucode */ - return iwl_hw_reg_send_txpower(priv); + return iwl3945_hw_reg_send_txpower(priv); } -int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +int iwl3945_hw_reg_set_txpower(struct iwl3945_priv *priv, s8 power) { - struct iwl_channel_info *ch_info; + struct iwl3945_channel_info *ch_info; s8 max_power; u8 a_band; u8 i; @@ -1728,26 +1794,26 @@ int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) /* find minimum power of all user and regulatory constraints * (does not consider h/w clipping limitations) */ - max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info); + max_power = iwl3945_hw_reg_get_ch_txpower_limit(ch_info); max_power = min(power, max_power); if (max_power != ch_info->curr_txpow) { ch_info->curr_txpow = max_power; /* this considers the h/w clipping limitations */ - iwl_hw_reg_set_new_power(priv, ch_info); + iwl3945_hw_reg_set_new_power(priv, ch_info); } } /* update txpower settings for all channels, * send to NIC if associated. */ is_temp_calib_needed(priv); - iwl_hw_reg_comp_txpower_temp(priv); + iwl3945_hw_reg_comp_txpower_temp(priv); return 0; } /* will add 3945 channel switch cmd handling later */ -int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) +int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel) { return 0; } @@ -1762,26 +1828,26 @@ int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) * -- send new set of gain settings to NIC * NOTE: This should continue working, even when we're not associated, * so we can keep our internal table of scan powers current. */ -void iwl3945_reg_txpower_periodic(struct iwl_priv *priv) +void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv) { /* This will kick in the "brute force" - * iwl_hw_reg_comp_txpower_temp() below */ + * iwl3945_hw_reg_comp_txpower_temp() below */ if (!is_temp_calib_needed(priv)) goto reschedule; /* Set up a new set of temp-adjusted TxPowers, send to NIC. * This is based *only* on current temperature, * ignoring any previous power measurements */ - iwl_hw_reg_comp_txpower_temp(priv); + iwl3945_hw_reg_comp_txpower_temp(priv); reschedule: queue_delayed_work(priv->workqueue, &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ); } -void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) +static void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, + struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv, thermal_periodic.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -1793,7 +1859,7 @@ void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) } /** - * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4) + * iwl3945_hw_reg_get_ch_grp_index - find the channel-group index (0-4) * for the channel. * * This function is used when initializing channel-info structs. @@ -1803,10 +1869,10 @@ void iwl3945_bg_reg_txpower_periodic(struct work_struct *work) * on A-band, EEPROM's "group frequency" entries represent the top * channel in each group 1-4. Group 5 All B/G channels are in group 0. */ -static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv, - const struct iwl_channel_info *ch_info) +static u16 iwl3945_hw_reg_get_ch_grp_index(struct iwl3945_priv *priv, + const struct iwl3945_channel_info *ch_info) { - struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0]; + struct iwl3945_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0]; u8 group; u16 group_index = 0; /* based on factory calib frequencies */ u8 grp_channel; @@ -1832,20 +1898,20 @@ static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv, } /** - * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index + * iwl3945_hw_reg_get_matched_power_index - Interpolate to get nominal index * * Interpolate to get nominal (i.e. at factory calibration temperature) index * into radio/DSP gain settings table for requested power. */ -static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv, +static int iwl3945_hw_reg_get_matched_power_index(struct iwl3945_priv *priv, s8 requested_power, s32 setting_index, s32 *new_index) { - const struct iwl_eeprom_txpower_group *chnl_grp = NULL; + const struct iwl3945_eeprom_txpower_group *chnl_grp = NULL; s32 index0, index1; s32 power = 2 * requested_power; s32 i; - const struct iwl_eeprom_txpower_sample *samples; + const struct iwl3945_eeprom_txpower_sample *samples; s32 gains0, gains1; s32 res; s32 denominator; @@ -1885,11 +1951,11 @@ static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv, return 0; } -static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv) +static void iwl3945_hw_reg_init_channel_groups(struct iwl3945_priv *priv) { u32 i; s32 rate_index; - const struct iwl_eeprom_txpower_group *group; + const struct iwl3945_eeprom_txpower_group *group; IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n"); @@ -1965,10 +2031,10 @@ static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv) * * This does *not* write values to NIC, just sets up our internal table. */ -int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) +int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv) { - struct iwl_channel_info *ch_info = NULL; - struct iwl_channel_power_info *pwr_info; + struct iwl3945_channel_info *ch_info = NULL; + struct iwl3945_channel_power_info *pwr_info; int delta_index; u8 rate_index; u8 scan_tbl_index; @@ -1981,10 +2047,10 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) /* save temperature reference, * so we can determine next time to calibrate */ - temperature = iwl_hw_reg_txpower_get_temperature(priv); + temperature = iwl3945_hw_reg_txpower_get_temperature(priv); priv->last_temperature = temperature; - iwl_hw_reg_init_channel_groups(priv); + iwl3945_hw_reg_init_channel_groups(priv); /* initialize Tx power info for each and every channel, 2.4 and 5.x */ for (i = 0, ch_info = priv->channel_info; i < priv->channel_count; @@ -1995,14 +2061,14 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) /* find this channel's channel group (*not* "band") index */ ch_info->group_index = - iwl_hw_reg_get_ch_grp_index(priv, ch_info); + iwl3945_hw_reg_get_ch_grp_index(priv, ch_info); /* Get this chnlgrp's rate->max/clip-powers table */ clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers; /* calculate power index *adjustment* value according to * diff between current temperature and factory temperature */ - delta_index = iwl_hw_reg_adjust_power_by_temp(temperature, + delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, priv->eeprom.groups[ch_info->group_index]. temperature); @@ -2025,7 +2091,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) /* get base (i.e. at factory-measured temperature) * power table index for this rate's power */ - rc = iwl_hw_reg_get_matched_power_index(priv, pwr, + rc = iwl3945_hw_reg_get_matched_power_index(priv, pwr, ch_info->group_index, &power_idx); if (rc) { @@ -2038,9 +2104,9 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) power_idx += delta_index; /* stay within range of gain table */ - power_idx = iwl_hw_reg_fix_power_index(power_idx); + power_idx = iwl3945_hw_reg_fix_power_index(power_idx); - /* fill 1 OFDM rate's iwl_channel_power_info struct */ + /* fill 1 OFDM rate's iwl3945_channel_power_info struct */ pwr_info->requested_power = pwr; pwr_info->power_table_index = (u8) power_idx; pwr_info->tpc.tx_gain = @@ -2059,11 +2125,11 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) IWL_CCK_FROM_OFDM_INDEX_DIFF; /* stay within table range */ - pwr_index = iwl_hw_reg_fix_power_index(pwr_index); + pwr_index = iwl3945_hw_reg_fix_power_index(pwr_index); gain = power_gain_table[a_band][pwr_index].tx_gain; dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten; - /* fill each CCK rate's iwl_channel_power_info structure + /* fill each CCK rate's iwl3945_channel_power_info structure * NOTE: All CCK-rate Txpwrs are the same for a given chnl! * NOTE: CCK rates start at end of OFDM rates! */ for (rate_index = 0; @@ -2081,7 +2147,7 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) { s32 actual_index = (scan_tbl_index == 0) ? IWL_RATE_1M_INDEX_TABLE : IWL_RATE_6M_INDEX_TABLE; - iwl_hw_reg_set_scan_power(priv, scan_tbl_index, + iwl3945_hw_reg_set_scan_power(priv, scan_tbl_index, actual_index, clip_pwrs, ch_info, a_band); } } @@ -2089,66 +2155,66 @@ int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv) return 0; } -int iwl_hw_rxq_stop(struct iwl_priv *priv) +int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv) { int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0); - rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); + iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0); + rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) +int iwl3945_hw_tx_queue_init(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq) { int rc; unsigned long flags; int txq_id = txq->q.id; - struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + struct iwl3945_shared *shared_data = priv->hw_setting.shared_virt; shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr); spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0); - iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0); + iwl3945_write_direct32(priv, FH_CBCC_CTRL(txq_id), 0); + iwl3945_write_direct32(priv, FH_CBCC_BASE(txq_id), 0); - iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id), + iwl3945_write_direct32(priv, FH_TCSR_CONFIG(txq_id), ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT | ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF | ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD | ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL | ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); /* fake read to flush all prev. writes */ - iwl_read32(priv, FH_TSSR_CBB_BASE); + iwl3945_read32(priv, FH_TSSR_CBB_BASE); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -int iwl_hw_get_rx_read(struct iwl_priv *priv) +int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv) { - struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + struct iwl3945_shared *shared_data = priv->hw_setting.shared_virt; return le32_to_cpu(shared_data->rx_read_ptr[0]); } @@ -2156,22 +2222,22 @@ int iwl_hw_get_rx_read(struct iwl_priv *priv) /** * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table */ -int iwl3945_init_hw_rate_table(struct iwl_priv *priv) +int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) { int rc, i, index, prev_index; - struct iwl_rate_scaling_cmd rate_cmd = { + struct iwl3945_rate_scaling_cmd rate_cmd = { .reserved = {0, 0, 0}, }; - struct iwl_rate_scaling_info *table = rate_cmd.table; + struct iwl3945_rate_scaling_info *table = rate_cmd.table; - for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) { - index = iwl_rates[i].table_rs_index; + for (i = 0; i < ARRAY_SIZE(iwl3945_rates); i++) { + index = iwl3945_rates[i].table_rs_index; table[index].rate_n_flags = - iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0); + iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0); table[index].try_cnt = priv->retry_rate; - prev_index = iwl_get_prev_ieee_rate(i); - table[index].next_rate_index = iwl_rates[prev_index].table_rs_index; + prev_index = iwl3945_get_prev_ieee_rate(i); + table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index; } switch (priv->phymode) { @@ -2180,14 +2246,14 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv) /* If one of the following CCK rates is used, * have it fall back to the 6M OFDM rate */ for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index; + table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; /* Don't fall back to CCK rates */ table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE; /* Don't drop out of OFDM rates */ table[IWL_RATE_6M_INDEX_TABLE].next_rate_index = - iwl_rates[IWL_FIRST_OFDM_RATE].table_rs_index; + iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; break; case MODE_IEEE80211B: @@ -2195,7 +2261,7 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv) /* If an OFDM rate is used, have it fall back to the * 1M CCK rates */ for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl_rates[IWL_FIRST_CCK_RATE].table_rs_index; + table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index; /* CCK shouldn't fall back to OFDM... */ table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE; @@ -2208,25 +2274,26 @@ int iwl3945_init_hw_rate_table(struct iwl_priv *priv) /* Update the rate scaling for control frame Tx */ rate_cmd.table_id = 0; - rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), + rc = iwl3945_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), &rate_cmd); if (rc) return rc; /* Update the rate scaling for data frame Tx */ rate_cmd.table_id = 1; - return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), + return iwl3945_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd), &rate_cmd); } -int iwl_hw_set_hw_setting(struct iwl_priv *priv) +/* Called when initializing driver */ +int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv) { memset((void *)&priv->hw_setting, 0, - sizeof(struct iwl_driver_hw_info)); + sizeof(struct iwl3945_driver_hw_info)); priv->hw_setting.shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl_shared), + sizeof(struct iwl3945_shared), &priv->hw_setting.shared_phys); if (!priv->hw_setting.shared_virt) { @@ -2236,31 +2303,31 @@ int iwl_hw_set_hw_setting(struct iwl_priv *priv) } priv->hw_setting.ac_queue_count = AC_NUM; - priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE; - priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); + priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE; + priv->hw_setting.max_pkt_size = 2342; + priv->hw_setting.tx_cmd_len = sizeof(struct iwl3945_tx_cmd); priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; - priv->hw_setting.cck_flag = 0; priv->hw_setting.max_stations = IWL3945_STATION_COUNT; priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID; return 0; } -unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate) +unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, + struct iwl3945_frame *frame, u8 rate) { - struct iwl_tx_beacon_cmd *tx_beacon_cmd; + struct iwl3945_tx_beacon_cmd *tx_beacon_cmd; unsigned int frame_size; - tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u; + tx_beacon_cmd = (struct iwl3945_tx_beacon_cmd *)&frame->u; memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd)); tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID; tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - frame_size = iwl_fill_beacon_frame(priv, + frame_size = iwl3945_fill_beacon_frame(priv, tx_beacon_cmd->frame, - BROADCAST_ADDR, + iwl3945_broadcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -2277,35 +2344,43 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.supp_rates[1] = (IWL_CCK_BASIC_RATES_MASK & 0xF); - return (sizeof(struct iwl_tx_beacon_cmd) + frame_size); + return (sizeof(struct iwl3945_tx_beacon_cmd) + frame_size); } -void iwl_hw_rx_handler_setup(struct iwl_priv *priv) +void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv) { priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx; } -void iwl_hw_setup_deferred_work(struct iwl_priv *priv) +void iwl3945_hw_setup_deferred_work(struct iwl3945_priv *priv) { INIT_DELAYED_WORK(&priv->thermal_periodic, iwl3945_bg_reg_txpower_periodic); } -void iwl_hw_cancel_deferred_work(struct iwl_priv *priv) +void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv) { cancel_delayed_work(&priv->thermal_periodic); } -struct pci_device_id iwl_hw_card_ids[] = { - {0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +struct pci_device_id iwl3945_hw_card_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4222)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4227)}, {0} }; -inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) +/* + * Clear the OWNER_MSK, to establish driver (instead of uCode running on + * embedded controller) as EEPROM reader; each read is a series of pulses + * to/from the EEPROM chip, not a single event, so even reads could conflict + * if they weren't arbitrated by some ownership mechanism. Here, the driver + * simply claims ownership, which should be safe when this function is called + * (i.e. before loading uCode!). + */ +inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv) { - _iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK); + _iwl3945_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK); return 0; } -MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); +MODULE_DEVICE_TABLE(pci, iwl3945_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 813902e9f8c2..20b925f57e35 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -23,19 +23,955 @@ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ +/* + * Please use this file (iwl-3945.h) for driver implementation definitions. + * Please use iwl-3945-commands.h for uCode API definitions. + * Please use iwl-3945-hw.h for hardware-related definitions. + */ #ifndef __iwl_3945_h__ #define __iwl_3945_h__ +#include <linux/pci.h> /* for struct pci_device_id */ +#include <linux/kernel.h> +#include <net/ieee80211_radiotap.h> + +/* Hardware specific file defines the PCI IDs table for that hardware module */ +extern struct pci_device_id iwl3945_hw_card_ids[]; + +#define DRV_NAME "iwl3945" +#include "iwl-3945-hw.h" +#include "iwl-prph.h" +#include "iwl-3945-debug.h" + +/* Default noise level to report when noise measurement is not available. + * This may be because we're: + * 1) Not associated (4965, no beacon statistics being sent to driver) + * 2) Scanning (noise measurement does not apply to associated channel) + * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) + * Use default noise value of -127 ... this is below the range of measurable + * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. + * Also, -127 works better than 0 when averaging frames with/without + * noise info (e.g. averaging might be done in app); measured dBm values are + * always negative ... using a negative value as the default keeps all + * averages within an s8's (used in some apps) range of negative values. */ +#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) + +/* Module parameters accessible from iwl-*.c */ +extern int iwl3945_param_hwcrypto; +extern int iwl3945_param_queues_num; + +enum iwl3945_antenna { + IWL_ANTENNA_DIVERSITY, + IWL_ANTENNA_MAIN, + IWL_ANTENNA_AUX +}; + +/* + * RTS threshold here is total size [2347] minus 4 FCS bytes + * Per spec: + * a value of 0 means RTS on all data/management packets + * a value > max MSDU size means no RTS + * else RTS for data/management frames where MPDU is larger + * than RTS value. + */ +#define IWL_RX_BUF_SIZE 3000U +#define DEFAULT_RTS_THRESHOLD 2347U +#define MIN_RTS_THRESHOLD 0U +#define MAX_RTS_THRESHOLD 2347U +#define MAX_MSDU_SIZE 2304U +#define MAX_MPDU_SIZE 2346U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +struct iwl3945_rx_mem_buffer { + dma_addr_t dma_addr; + struct sk_buff *skb; + struct list_head list; +}; + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +struct iwl3945_queue { + int n_bd; /* number of BDs in this queue */ + int write_ptr; /* 1-st empty entry (index) host_w*/ + int read_ptr; /* last used entry (index) host_r*/ + dma_addr_t dma_addr; /* physical addr for BD's */ + int n_window; /* safe queue window */ + u32 id; + int low_mark; /* low watermark, resume queue if free + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +} __attribute__ ((packed)); + +#define MAX_NUM_OF_TBS (20) + +/* One for each TFD */ +struct iwl3945_tx_info { + struct ieee80211_tx_status status; + struct sk_buff *skb[MAX_NUM_OF_TBS]; +}; + +/** + * struct iwl3945_tx_queue - Tx Queue for DMA + * @q: generic Rx/Tx queue descriptor + * @bd: base of circular buffer of TFDs + * @cmd: array of command/Tx buffers + * @dma_addr_cmd: physical address of cmd/tx buffer array + * @txb: array of per-TFD driver data + * @need_update: indicates need to update read/write index + * + * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame + * descriptors) and required locking structures. + */ +struct iwl3945_tx_queue { + struct iwl3945_queue q; + struct iwl3945_tfd_frame *bd; + struct iwl3945_cmd *cmd; + dma_addr_t dma_addr_cmd; + struct iwl3945_tx_info *txb; + int need_update; + int active; +}; + +#define IWL_NUM_SCAN_RATES (2) + +struct iwl3945_channel_tgd_info { + u8 type; + s8 max_power; +}; + +struct iwl3945_channel_tgh_info { + s64 last_radar_time; +}; + +/* current Tx power values to use, one for each rate for each channel. + * requested power is limited by: + * -- regulatory EEPROM limits for this channel + * -- hardware capabilities (clip-powers) + * -- spectrum management + * -- user preference (e.g. iwconfig) + * when requested power is set, base power index must also be set. */ +struct iwl3945_channel_power_info { + struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 base_power_index; /* gain index for power at factory temp. */ + s8 requested_power; /* power (dBm) requested for this chnl/rate */ +}; + +/* current scan Tx power values to use, one for each scan rate for each + * channel. */ +struct iwl3945_scan_power_info { + struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ +}; + +/* + * One for each channel, holds all channel setup data + * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant + * with one another! + */ +#define IWL4965_MAX_RATE (33) + +struct iwl3945_channel_info { + struct iwl3945_channel_tgd_info tgd; + struct iwl3945_channel_tgh_info tgh; + struct iwl3945_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl3945_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ + + u8 channel; /* channel number */ + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 min_power; /* always 0 */ + s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ + + u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ + u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ + u8 phymode; /* MODE_IEEE80211{A,B,G} */ + + /* Radio/DSP gain settings for each "normal" data Tx rate. + * These include, in addition to RF and DSP gain, a few fields for + * remembering/modifying gain settings (indexes). */ + struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE]; + + /* Radio/DSP gain settings for each scan rate, for directed scans. */ + struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; +}; + +struct iwl3945_clip_group { + /* maximum power level to prevent clipping for each rate, derived by + * us from this band's saturation power in EEPROM */ + const s8 clip_powers[IWL_MAX_RATES]; +}; + +#include "iwl-3945-rs.h" + +#define IWL_TX_FIFO_AC0 0 +#define IWL_TX_FIFO_AC1 1 +#define IWL_TX_FIFO_AC2 2 +#define IWL_TX_FIFO_AC3 3 +#define IWL_TX_FIFO_HCCA_1 5 +#define IWL_TX_FIFO_HCCA_2 6 +#define IWL_TX_FIFO_NONE 7 + +/* Minimum number of queues. MAX_NUM is defined in hw specific files */ +#define IWL_MIN_NUM_QUEUES 4 + +/* Power management (not Tx power) structures */ + +struct iwl3945_power_vec_entry { + struct iwl3945_powertable_cmd cmd; + u8 no_dtim; +}; +#define IWL_POWER_RANGE_0 (0) +#define IWL_POWER_RANGE_1 (1) + +#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_LIMIT 0x07 +#define IWL_POWER_MASK 0x0F +#define IWL_POWER_ENABLED 0x10 +#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) + +struct iwl3945_power_mgr { + spinlock_t lock; + struct iwl3945_power_vec_entry pwr_range_0[IWL_POWER_AC]; + struct iwl3945_power_vec_entry pwr_range_1[IWL_POWER_AC]; + u8 active_index; + u32 dtim_val; +}; + +#define IEEE80211_DATA_LEN 2304 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +struct iwl3945_frame { + union { + struct ieee80211_hdr frame; + struct iwl3945_tx_beacon_cmd beacon; + u8 raw[IEEE80211_FRAME_LEN]; + u8 cmd[360]; + } u; + struct list_head list; +}; + +#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) +#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) +#define SEQ_TO_INDEX(x) (x & 0xff) +#define INDEX_TO_SEQ(x) (x & 0xff) +#define SEQ_HUGE_FRAME (0x4000) +#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +enum { + /* CMD_SIZE_NORMAL = 0, */ + CMD_SIZE_HUGE = (1 << 0), + /* CMD_SYNC = 0, */ + CMD_ASYNC = (1 << 1), + /* CMD_NO_SKB = 0, */ + CMD_WANT_SKB = (1 << 2), +}; + +struct iwl3945_cmd; +struct iwl3945_priv; + +struct iwl3945_cmd_meta { + struct iwl3945_cmd_meta *source; + union { + struct sk_buff *skb; + int (*callback)(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, struct sk_buff *skb); + } __attribute__ ((packed)) u; + + /* The CMD_SIZE_HUGE flag bit indicates that the command + * structure is stored at the end of the shared queue memory. */ + u32 flags; + +} __attribute__ ((packed)); + +/** + * struct iwl3945_cmd + * + * For allocation of the command and tx queues, this establishes the overall + * size of the largest command we send to uCode, except for a scan command + * (which is relatively huge; space is allocated separately). + */ +struct iwl3945_cmd { + struct iwl3945_cmd_meta meta; + struct iwl3945_cmd_header hdr; + union { + struct iwl3945_addsta_cmd addsta; + struct iwl3945_led_cmd led; + u32 flags; + u8 val8; + u16 val16; + u32 val32; + struct iwl3945_bt_cmd bt; + struct iwl3945_rxon_time_cmd rxon_time; + struct iwl3945_powertable_cmd powertable; + struct iwl3945_qosparam_cmd qosparam; + struct iwl3945_tx_cmd tx; + struct iwl3945_tx_beacon_cmd tx_beacon; + struct iwl3945_rxon_assoc_cmd rxon_assoc; + u8 *indirect; + u8 payload[360]; + } __attribute__ ((packed)) cmd; +} __attribute__ ((packed)); + +struct iwl3945_host_cmd { + u8 id; + u16 len; + struct iwl3945_cmd_meta meta; + const void *data; +}; + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl3945_cmd) - \ + sizeof(struct iwl3945_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/** + * struct iwl3945_rx_queue - Rx queue + * @processed: Internal index to last handled Rx packet + * @read: Shared index to newest available Rx buffer + * @write: Shared index to oldest written Rx packet + * @free_count: Number of pre-allocated buffers in rx_free + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB + * @need_update: flag to indicate we need to update read/write index + * + * NOTE: rx_free and rx_used are used as a FIFO for iwl3945_rx_mem_buffers + */ +struct iwl3945_rx_queue { + __le32 *bd; + dma_addr_t dma_addr; + struct iwl3945_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl3945_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 processed; + u32 read; + u32 write; + u32 free_count; + struct list_head rx_free; + struct list_head rx_used; + int need_update; + spinlock_t lock; +}; + +#define IWL_SUPPORTED_RATES_IE_LEN 8 + +#define SCAN_INTERVAL 100 + +#define MAX_A_CHANNELS 252 +#define MIN_A_CHANNELS 7 + +#define MAX_B_CHANNELS 14 +#define MIN_B_CHANNELS 1 + +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +#define STATUS_INT_ENABLED 1 +#define STATUS_RF_KILL_HW 2 +#define STATUS_RF_KILL_SW 3 +#define STATUS_INIT 4 +#define STATUS_ALIVE 5 +#define STATUS_READY 6 +#define STATUS_TEMPERATURE 7 +#define STATUS_GEO_CONFIGURED 8 +#define STATUS_EXIT_PENDING 9 +#define STATUS_IN_SUSPEND 10 +#define STATUS_STATISTICS 11 +#define STATUS_SCANNING 12 +#define STATUS_SCAN_ABORTING 13 +#define STATUS_SCAN_HW 14 +#define STATUS_POWER_PMI 15 +#define STATUS_FW_ERROR 16 +#define STATUS_CONF_PENDING 17 + +#define MAX_TID_COUNT 9 + +#define IWL_INVALID_RATE 0xFF +#define IWL_INVALID_VALUE -1 + +struct iwl3945_tid_data { + u16 seq_number; +}; + +struct iwl3945_hw_key { + enum ieee80211_key_alg alg; + int keylen; + u8 key[32]; +}; + +union iwl3945_ht_rate_supp { + u16 rates; + struct { + u8 siso_rate; + u8 mimo_rate; + }; +}; + +#ifdef CONFIG_IWL3945_QOS + +union iwl3945_qos_capabity { + struct { + u8 edca_count:4; /* bit 0-3 */ + u8 q_ack:1; /* bit 4 */ + u8 queue_request:1; /* bit 5 */ + u8 txop_request:1; /* bit 6 */ + u8 reserved:1; /* bit 7 */ + } q_AP; + struct { + u8 acvo_APSD:1; /* bit 0 */ + u8 acvi_APSD:1; /* bit 1 */ + u8 ac_bk_APSD:1; /* bit 2 */ + u8 ac_be_APSD:1; /* bit 3 */ + u8 q_ack:1; /* bit 4 */ + u8 max_len:2; /* bit 5-6 */ + u8 more_data_ack:1; /* bit 7 */ + } q_STA; + u8 val; +}; + +/* QoS structures */ +struct iwl3945_qos_info { + int qos_enable; + int qos_active; + union iwl3945_qos_capabity qos_cap; + struct iwl3945_qosparam_cmd def_qos_parm; +}; +#endif /*CONFIG_IWL3945_QOS */ + +#define STA_PS_STATUS_WAKE 0 +#define STA_PS_STATUS_SLEEP 1 + +struct iwl3945_station_entry { + struct iwl3945_addsta_cmd sta; + struct iwl3945_tid_data tid[MAX_TID_COUNT]; + union { + struct { + u8 rate; + u8 flags; + } s; + u16 rate_n_flags; + } current_rate; + u8 used; + u8 ps_status; + struct iwl3945_hw_key keyinfo; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + void *v_addr; /* access by driver */ + dma_addr_t p_addr; /* access by card's busmaster DMA */ + u32 len; /* bytes */ +}; + +/* uCode file layout */ +struct iwl3945_ucode { + __le32 ver; /* major/minor/subminor */ + __le32 inst_size; /* bytes of runtime instructions */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of initialization instructions */ + __le32 init_data_size; /* bytes of initialization data */ + __le32 boot_size; /* bytes of bootstrap instructions */ + u8 data[0]; /* data in same order as "size" elements */ +}; + +#define IWL_IBSS_MAC_HASH_SIZE 32 + +struct iwl3945_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +/** + * struct iwl3945_driver_hw_info + * @max_txq_num: Max # Tx queues supported + * @ac_queue_count: # Tx queues for EDCA Access Categories (AC) + * @tx_cmd_len: Size of Tx command (but not including frame itself) + * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) + * @rx_buf_size: + * @max_pkt_size: + * @max_rxq_log: Log-base-2 of max_rxq_size + * @max_stations: + * @bcast_sta_id: + * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status + * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status + */ +struct iwl3945_driver_hw_info { + u16 max_txq_num; + u16 ac_queue_count; + u16 tx_cmd_len; + u16 max_rxq_size; + u32 rx_buf_size; + u32 max_pkt_size; + u16 max_rxq_log; + u8 max_stations; + u8 bcast_sta_id; + void *shared_virt; + dma_addr_t shared_phys; +}; + +#define IWL_RX_HDR(x) ((struct iwl3945_rx_frame_hdr *)(\ + x->u.rx_frame.stats.payload + \ + x->u.rx_frame.stats.phy_count)) +#define IWL_RX_END(x) ((struct iwl3945_rx_frame_end *)(\ + IWL_RX_HDR(x)->payload + \ + le16_to_cpu(IWL_RX_HDR(x)->len))) +#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) +#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) + + +/****************************************************************************** + * + * Functions implemented in iwl-base.c which are forward declared here + * for use by iwl-*.c + * + *****************************************************************************/ +struct iwl3945_addsta_cmd; +extern int iwl3945_send_add_station(struct iwl3945_priv *priv, + struct iwl3945_addsta_cmd *sta, u8 flags); +extern u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *bssid, + int is_ap, u8 flags); +extern int iwl3945_is_network_packet(struct iwl3945_priv *priv, + struct ieee80211_hdr *header); +extern int iwl3945_power_init_handle(struct iwl3945_priv *priv); +extern int iwl3945_eeprom_init(struct iwl3945_priv *priv); +#ifdef CONFIG_IWL3945_DEBUG +extern void iwl3945_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, + struct ieee80211_hdr *header, int group100); +#else +static inline void iwl3945_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) {} +#endif +extern void iwl3945_handle_data_packet_monitor(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags); +extern int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, + struct ieee80211_hdr *header); +extern int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv); +extern void iwl3945_rx_queue_reset(struct iwl3945_priv *priv, + struct iwl3945_rx_queue *rxq); +extern int iwl3945_calc_db_from_ratio(int sig_ratio); +extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm); +extern int iwl3945_tx_queue_init(struct iwl3945_priv *priv, + struct iwl3945_tx_queue *txq, int count, u32 id); +extern void iwl3945_rx_replenish(void *data); +extern void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq); +extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, + const void *data); +extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv, + struct iwl3945_host_cmd *cmd); +extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left); +extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, + struct iwl3945_rx_queue *q); +extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv); +extern void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb, + u32 decrypt_res, + struct ieee80211_rx_status *stats); +extern const u8 iwl3945_broadcast_addr[ETH_ALEN]; + +/* + * Currently used by iwl-3945-rs... look at restructuring so that it doesn't + * call this... todo... fix that. +*/ +extern u8 iwl3945_sync_station(struct iwl3945_priv *priv, int sta_id, + u16 tx_rate, u8 flags); + +/****************************************************************************** + * + * Functions implemented in iwl-[34]*.c which are forward declared here + * for use by iwl-base.c + * + * NOTE: The implementation of these functions are hardware specific + * which is why they are in the hardware specific files (vs. iwl-base.c) + * + * Naming convention -- + * iwl3945_ <-- Its part of iwlwifi (should be changed to iwl3945_) + * iwl3945_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) + * iwl3945_bg_ <-- Called from work queue context + * iwl3945_mac_ <-- mac80211 callback + * + ****************************************************************************/ +extern void iwl3945_hw_rx_handler_setup(struct iwl3945_priv *priv); +extern void iwl3945_hw_setup_deferred_work(struct iwl3945_priv *priv); +extern void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv); +extern int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv); +extern int iwl3945_hw_set_hw_setting(struct iwl3945_priv *priv); +extern int iwl3945_hw_nic_init(struct iwl3945_priv *priv); +extern int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv); +extern void iwl3945_hw_txq_ctx_free(struct iwl3945_priv *priv); +extern void iwl3945_hw_txq_ctx_stop(struct iwl3945_priv *priv); +extern int iwl3945_hw_nic_reset(struct iwl3945_priv *priv); +extern int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl3945_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +extern int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq); +extern int iwl3945_hw_get_temperature(struct iwl3945_priv *priv); +extern int iwl3945_hw_tx_queue_init(struct iwl3945_priv *priv, + struct iwl3945_tx_queue *txq); +extern unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, + struct iwl3945_frame *frame, u8 rate); +extern int iwl3945_hw_get_rx_read(struct iwl3945_priv *priv); +extern void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); +extern int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv); +extern int iwl3945_hw_reg_set_txpower(struct iwl3945_priv *priv, s8 power); +extern void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb); +extern void iwl3945_disable_events(struct iwl3945_priv *priv); +extern int iwl4965_get_temperature(const struct iwl3945_priv *priv); + +/** + * iwl3945_hw_find_station - Find station id for a given BSSID + * @bssid: MAC address of station ID to find + * + * NOTE: This should not be hardware specific but the code has + * not yet been merged into a single common layer for managing the + * station tables. + */ +extern u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *bssid); + +extern int iwl3945_hw_channel_switch(struct iwl3945_priv *priv, u16 channel); + /* * Forward declare iwl-3945.c functions for iwl-base.c */ -extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv); -extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv); -extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv); -extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv); -extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work); -extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv); -extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, +extern int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv); +extern __le32 iwl3945_get_antenna_flags(const struct iwl3945_priv *priv); +extern int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv); +extern void iwl3945_reg_txpower_periodic(struct iwl3945_priv *priv); +extern int iwl3945_txpower_set_from_eeprom(struct iwl3945_priv *priv); +extern u8 iwl3945_sync_sta(struct iwl3945_priv *priv, int sta_id, u16 tx_rate, u8 flags); + + +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT + +enum { + MEASUREMENT_READY = (1 << 0), + MEASUREMENT_ACTIVE = (1 << 1), +}; + +#endif + +struct iwl3945_priv { + + /* ieee device used by generic ieee processing code */ + struct ieee80211_hw *hw; + struct ieee80211_channel *ieee_channels; + struct ieee80211_rate *ieee_rates; + + /* temporary frame storage list */ + struct list_head free_frames; + int frames_count; + + u8 phymode; + int alloc_rxb_skb; + bool add_radiotap; + + void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb); + + const struct ieee80211_hw_mode *modes; + +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT + /* spectrum measurement report caching */ + struct iwl3945_spectrum_notification measure_report; + u8 measurement_status; +#endif + /* ucode beacon time */ + u32 ucode_beacon_time; + + /* we allocate array of iwl3945_channel_info for NIC's valid channels. + * Access via channel # using indirect index array */ + struct iwl3945_channel_info *channel_info; /* channel info array */ + u8 channel_count; /* # of channels */ + + /* each calibration channel group in the EEPROM has a derived + * clip setting for each rate. */ + const struct iwl3945_clip_group clip_groups[5]; + + /* thermal calibration */ + s32 temperature; /* degrees Kelvin */ + s32 last_temperature; + + /* Scan related variables */ + unsigned long last_scan_jiffies; + unsigned long next_scan_jiffies; + unsigned long scan_start; + unsigned long scan_pass_start; + unsigned long scan_start_tsf; + int scan_bands; + int one_direct_scan; + u8 direct_ssid_len; + u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct iwl3945_scan_cmd *scan; + u8 only_active_channel; + + /* spinlock */ + spinlock_t lock; /* protect general shared data */ + spinlock_t hcmd_lock; /* protect hcmd */ + struct mutex mutex; + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + + /* pci hardware address support */ + void __iomem *hw_base; + + /* uCode images, save to reload in case of failure */ + struct fw_desc ucode_code; /* runtime inst */ + struct fw_desc ucode_data; /* runtime data original */ + struct fw_desc ucode_data_backup; /* runtime data save/restore */ + struct fw_desc ucode_init; /* initialization inst */ + struct fw_desc ucode_init_data; /* initialization data */ + struct fw_desc ucode_boot; /* bootstrap inst */ + + + struct iwl3945_rxon_time_cmd rxon_timing; + + /* We declare this const so it can only be + * changed via explicit cast within the + * routines that actually update the physical + * hardware */ + const struct iwl3945_rxon_cmd active_rxon; + struct iwl3945_rxon_cmd staging_rxon; + + int error_recovering; + struct iwl3945_rxon_cmd recovery_rxon; + + /* 1st responses from initialize and runtime uCode images. + * 4965's initialize alive response contains some calibration data. */ + struct iwl3945_init_alive_resp card_alive_init; + struct iwl3945_alive_resp card_alive; + +#ifdef LED + /* LED related variables */ + struct iwl3945_activity_blink activity; + unsigned long led_packets; + int led_state; +#endif + + u16 active_rate; + u16 active_rate_basic; + + u8 call_post_assoc_from_beacon; + u8 assoc_station_added; + /* Rate scaling data */ + s8 data_retry_limit; + u8 retry_rate; + + wait_queue_head_t wait_command_queue; + + int activity_timer_active; + + /* Rx and Tx DMA processing queues */ + struct iwl3945_rx_queue rxq; + struct iwl3945_tx_queue txq[IWL_MAX_NUM_QUEUES]; + + unsigned long status; + u32 config; + + int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_noise; /* From beacon statistics */ + + struct iwl3945_power_mgr power_data; + + struct iwl3945_notif_statistics statistics; + unsigned long last_statistics_time; + + /* context information */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u16 rates_mask; + + u32 power_mode; + u32 antenna; + u8 bssid[ETH_ALEN]; + u16 rts_threshold; + u8 mac_addr[ETH_ALEN]; + + /*station table variables */ + spinlock_t sta_lock; + int num_stations; + struct iwl3945_station_entry stations[IWL_STATION_COUNT]; + + /* Indication if ieee80211_ops->open has been called */ + int is_open; + + u8 mac80211_registered; + int is_abg; + + u32 notif_missed_beacons; + + /* Rx'd packet timing information */ + u32 last_beacon_time; + u64 last_tsf; + + /* Duplicate packet detection */ + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + + /* Hash table for finding stations in IBSS network */ + struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; + + /* eeprom */ + struct iwl3945_eeprom eeprom; + + int iw_mode; + + struct sk_buff *ibss_beacon; + + /* Last Rx'd beacon timestamp */ + u32 timestamp0; + u32 timestamp1; + u16 beacon_int; + struct iwl3945_driver_hw_info hw_setting; + struct ieee80211_vif *vif; + + /* Current association information needed to configure the + * hardware */ + u16 assoc_id; + u16 assoc_capability; + u8 ps_mode; + +#ifdef CONFIG_IWL3945_QOS + struct iwl3945_qos_info qos_data; +#endif /*CONFIG_IWL3945_QOS */ + + struct workqueue_struct *workqueue; + + struct work_struct up; + struct work_struct restart; + struct work_struct calibrated_work; + struct work_struct scan_completed; + struct work_struct rx_replenish; + struct work_struct rf_kill; + struct work_struct abort_scan; + struct work_struct update_link_led; + struct work_struct auth_work; + struct work_struct report_work; + struct work_struct request_scan; + struct work_struct beacon_update; + + struct tasklet_struct irq_tasklet; + + struct delayed_work init_alive_start; + struct delayed_work alive_start; + struct delayed_work activity_timer; + struct delayed_work thermal_periodic; + struct delayed_work gather_stats; + struct delayed_work scan_check; + struct delayed_work post_associate; + +#define IWL_DEFAULT_TX_POWER 0x0F + s8 user_txpower_limit; + s8 max_channel_txpower_limit; + +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif + +#ifdef CONFIG_IWL3945_DEBUG + /* debugging info */ + u32 framecnt_to_us; + atomic_t restrict_refcnt; +#endif +}; /*iwl3945_priv */ + +static inline int iwl3945_is_associated(struct iwl3945_priv *priv) +{ + return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; +} + +static inline int is_channel_valid(const struct iwl3945_channel_info *ch_info) +{ + if (ch_info == NULL) + return 0; + return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; +} + +static inline int is_channel_narrow(const struct iwl3945_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; +} + +static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; +} + +static inline u8 is_channel_a_band(const struct iwl3945_channel_info *ch_info) +{ + return ch_info->phymode == MODE_IEEE80211A; +} + +static inline u8 is_channel_bg_band(const struct iwl3945_channel_info *ch_info) +{ + return ((ch_info->phymode == MODE_IEEE80211B) || + (ch_info->phymode == MODE_IEEE80211G)); +} + +static inline int is_channel_passive(const struct iwl3945_channel_info *ch) +{ + return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; +} + +static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) +{ + return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; +} + +static inline int iwl3945_rate_index_from_plcp(int plcp) +{ + int i; + + for (i = 0; i < IWL_RATE_COUNT; i++) + if (iwl3945_rates[i].plcp == plcp) + return i; + return -1; +} + +extern const struct iwl3945_channel_info *iwl3945_get_channel_info( + const struct iwl3945_priv *priv, int phymode, u16 channel); + +/* Requires full declaration of iwl3945_priv before including */ +#include "iwl-3945-io.h" + #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h new file mode 100644 index 000000000000..f3470c896d9a --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h @@ -0,0 +1,2651 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2005 - 2007 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.GPL. + * + * Contact Information: + * James P. Ketrenos <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +/* + * Please use this file (iwl-4965-commands.h) only for uCode API definitions. + * Please use iwl-4965-hw.h for hardware-related definitions. + * Please use iwl-4965.h for driver implementation definitions. + */ + +#ifndef __iwl4965_commands_h__ +#define __iwl4965_commands_h__ + +enum { + REPLY_ALIVE = 0x1, + REPLY_ERROR = 0x2, + + /* RXON and QOS commands */ + REPLY_RXON = 0x10, + REPLY_RXON_ASSOC = 0x11, + REPLY_QOS_PARAM = 0x13, + REPLY_RXON_TIMING = 0x14, + + /* Multi-Station support */ + REPLY_ADD_STA = 0x18, + REPLY_REMOVE_STA = 0x19, /* not used */ + REPLY_REMOVE_ALL_STA = 0x1a, /* not used */ + + /* RX, TX, LEDs */ + REPLY_TX = 0x1c, + REPLY_RATE_SCALE = 0x47, /* 3945 only */ + REPLY_LEDS_CMD = 0x48, + REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */ + + /* 802.11h related */ + RADAR_NOTIFICATION = 0x70, /* not used */ + REPLY_QUIET_CMD = 0x71, /* not used */ + REPLY_CHANNEL_SWITCH = 0x72, + CHANNEL_SWITCH_NOTIFICATION = 0x73, + REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74, + SPECTRUM_MEASURE_NOTIFICATION = 0x75, + + /* Power Management */ + POWER_TABLE_CMD = 0x77, + PM_SLEEP_NOTIFICATION = 0x7A, + PM_DEBUG_STATISTIC_NOTIFIC = 0x7B, + + /* Scan commands and notifications */ + REPLY_SCAN_CMD = 0x80, + REPLY_SCAN_ABORT_CMD = 0x81, + SCAN_START_NOTIFICATION = 0x82, + SCAN_RESULTS_NOTIFICATION = 0x83, + SCAN_COMPLETE_NOTIFICATION = 0x84, + + /* IBSS/AP commands */ + BEACON_NOTIFICATION = 0x90, + REPLY_TX_BEACON = 0x91, + WHO_IS_AWAKE_NOTIFICATION = 0x94, /* not used */ + + /* Miscellaneous commands */ + QUIET_NOTIFICATION = 0x96, /* not used */ + REPLY_TX_PWR_TABLE_CMD = 0x97, + MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ + + /* Bluetooth device coexistance config command */ + REPLY_BT_CONFIG = 0x9b, + + /* Statistics */ + REPLY_STATISTICS_CMD = 0x9c, + STATISTICS_NOTIFICATION = 0x9d, + + /* RF-KILL commands and notifications */ + REPLY_CARD_STATE_CMD = 0xa0, + CARD_STATE_NOTIFICATION = 0xa1, + + /* Missed beacons notification */ + MISSED_BEACONS_NOTIFICATION = 0xa2, + + REPLY_CT_KILL_CONFIG_CMD = 0xa4, + SENSITIVITY_CMD = 0xa8, + REPLY_PHY_CALIBRATION_CMD = 0xb0, + REPLY_RX_PHY_CMD = 0xc0, + REPLY_RX_MPDU_CMD = 0xc1, + REPLY_4965_RX = 0xc3, + REPLY_COMPRESSED_BA = 0xc5, + REPLY_MAX = 0xff +}; + +/****************************************************************************** + * (0) + * Commonly used structures and definitions: + * Command header, rate_n_flags, txpower + * + *****************************************************************************/ + +/* iwl4965_cmd_header flags value */ +#define IWL_CMD_FAILED_MSK 0x40 + +/** + * struct iwl4965_cmd_header + * + * This header format appears in the beginning of each command sent from the + * driver, and each response/notification received from uCode. + */ +struct iwl4965_cmd_header { + u8 cmd; /* Command ID: REPLY_RXON, etc. */ + u8 flags; /* IWL_CMD_* */ + /* + * The driver sets up the sequence number to values of its chosing. + * uCode does not use this value, but passes it back to the driver + * when sending the response to each driver-originated command, so + * the driver can match the response to the command. Since the values + * don't get used by uCode, the driver may set up an arbitrary format. + * + * There is one exception: uCode sets bit 15 when it originates + * the response/notification, i.e. when the response/notification + * is not a direct response to a command sent by the driver. For + * example, uCode issues REPLY_3945_RX when it sends a received frame + * to the driver; it is not a direct response to any driver command. + * + * The Linux driver uses the following format: + * + * 0:7 index/position within Tx queue + * 8:13 Tx queue selection + * 14:14 driver sets this to indicate command is in the 'huge' + * storage at the end of the command buffers, i.e. scan cmd + * 15:15 uCode sets this in uCode-originated response/notification + */ + __le16 sequence; + + /* command or response/notification data follows immediately */ + u8 data[0]; +} __attribute__ ((packed)); + +/** + * 4965 rate_n_flags bit fields + * + * rate_n_flags format is used in following 4965 commands: + * REPLY_4965_RX (response only) + * REPLY_TX (both command and response) + * REPLY_TX_LINK_QUALITY_CMD + * + * High-throughput (HT) rate format for bits 7:0 (bit 8 must be "1"): + * 2-0: 0) 6 Mbps + * 1) 12 Mbps + * 2) 18 Mbps + * 3) 24 Mbps + * 4) 36 Mbps + * 5) 48 Mbps + * 6) 54 Mbps + * 7) 60 Mbps + * + * 3: 0) Single stream (SISO) + * 1) Dual stream (MIMO) + * + * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data + * + * Legacy OFDM rate format for bits 7:0 (bit 8 must be "0", bit 9 "0"): + * 3-0: 0xD) 6 Mbps + * 0xF) 9 Mbps + * 0x5) 12 Mbps + * 0x7) 18 Mbps + * 0x9) 24 Mbps + * 0xB) 36 Mbps + * 0x1) 48 Mbps + * 0x3) 54 Mbps + * + * Legacy CCK rate format for bits 7:0 (bit 8 must be "0", bit 9 "1"): + * 3-0: 10) 1 Mbps + * 20) 2 Mbps + * 55) 5.5 Mbps + * 110) 11 Mbps + */ +#define RATE_MCS_CODE_MSK 0x7 +#define RATE_MCS_MIMO_POS 3 +#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_HT_DUP_POS 5 +#define RATE_MCS_HT_DUP_MSK 0x20 + +/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */ +#define RATE_MCS_FLAGS_POS 8 +#define RATE_MCS_HT_POS 8 +#define RATE_MCS_HT_MSK 0x100 + +/* Bit 9: (1) CCK, (0) OFDM. HT (bit 8) must be "0" for this bit to be valid */ +#define RATE_MCS_CCK_POS 9 +#define RATE_MCS_CCK_MSK 0x200 + +/* Bit 10: (1) Use Green Field preamble */ +#define RATE_MCS_GF_POS 10 +#define RATE_MCS_GF_MSK 0x400 + +/* Bit 11: (1) Use 40Mhz FAT chnl width, (0) use 20 MHz legacy chnl width */ +#define RATE_MCS_FAT_POS 11 +#define RATE_MCS_FAT_MSK 0x800 + +/* Bit 12: (1) Duplicate data on both 20MHz chnls. FAT (bit 11) must be set. */ +#define RATE_MCS_DUP_POS 12 +#define RATE_MCS_DUP_MSK 0x1000 + +/* Bit 13: (1) Short guard interval (0.4 usec), (0) normal GI (0.8 usec) */ +#define RATE_MCS_SGI_POS 13 +#define RATE_MCS_SGI_MSK 0x2000 + +/** + * rate_n_flags Tx antenna masks (4965 has 2 transmitters): + * bit14:15 01 B inactive, A active + * 10 B active, A inactive + * 11 Both active + */ +#define RATE_MCS_ANT_A_POS 14 +#define RATE_MCS_ANT_B_POS 15 +#define RATE_MCS_ANT_A_MSK 0x4000 +#define RATE_MCS_ANT_B_MSK 0x8000 +#define RATE_MCS_ANT_AB_MSK 0xc000 + + +/** + * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD + * + * Scan uses only one transmitter, so only one analog/dsp gain pair is needed. + */ +struct iwl4965_tx_power { + u8 tx_gain; /* gain for analog radio */ + u8 dsp_atten; /* gain for DSP */ +} __attribute__ ((packed)); + +#define POWER_TABLE_NUM_ENTRIES 33 +#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 +#define POWER_TABLE_CCK_ENTRY 32 + +/** + * union iwl4965_tx_power_dual_stream + * + * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + * Use __le32 version (struct tx_power_dual_stream) when building command. + * + * Driver provides radio gain and DSP attenuation settings to device in pairs, + * one value for each transmitter chain. The first value is for transmitter A, + * second for transmitter B. + * + * For SISO bit rates, both values in a pair should be identical. + * For MIMO rates, one value may be different from the other, + * in order to balance the Tx output between the two transmitters. + * + * See more details in doc for TXPOWER in iwl-4965-hw.h. + */ +union iwl4965_tx_power_dual_stream { + struct { + u8 radio_tx_gain[2]; + u8 dsp_predis_atten[2]; + } s; + u32 dw; +}; + +/** + * struct tx_power_dual_stream + * + * Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + * + * Same format as iwl_tx_power_dual_stream, but __le32 + */ +struct tx_power_dual_stream { + __le32 dw; +} __attribute__ ((packed)); + +/** + * struct iwl4965_tx_power_db + * + * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH + */ +struct iwl4965_tx_power_db { + struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES]; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (0a) + * Alive and Error Commands & Responses: + * + *****************************************************************************/ + +#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define INITIALIZE_SUBTYPE (9) + +/* + * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command) + * + * uCode issues this "initialize alive" notification once the initialization + * uCode image has completed its work, and is ready to load the runtime image. + * This is the *first* "alive" notification that the driver will receive after + * rebooting uCode; the "initialize" alive is indicated by subtype field == 9. + * + * See comments documenting "BSM" (bootstrap state machine). + * + * For 4965, this notification contains important calibration data for + * calculating txpower settings: + * + * 1) Power supply voltage indication. The voltage sensor outputs higher + * values for lower voltage, and vice versa. + * + * 2) Temperature measurement parameters, for each of two channel widths + * (20 MHz and 40 MHz) supported by the radios. Temperature sensing + * is done via one of the receiver chains, and channel width influences + * the results. + * + * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation, + * for each of 5 frequency ranges. + */ +struct iwl4965_init_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; /* "9" for initialize alive */ + __le16 reserved2; + __le32 log_event_table_ptr; + __le32 error_event_table_ptr; + __le32 timestamp; + __le32 is_valid; + + /* calibration values from "initialize" uCode */ + __le32 voltage; /* signed, higher value is lower voltage */ + __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for FAT channel*/ + __le32 therm_r2[2]; /* signed */ + __le32 therm_r3[2]; /* signed */ + __le32 therm_r4[2]; /* signed */ + __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups, + * 2 Tx chains */ +} __attribute__ ((packed)); + + +/** + * REPLY_ALIVE = 0x1 (response only, not a command) + * + * uCode issues this "alive" notification once the runtime image is ready + * to receive commands from the driver. This is the *second* "alive" + * notification that the driver will receive after rebooting uCode; + * this "alive" is indicated by subtype field != 9. + * + * See comments documenting "BSM" (bootstrap state machine). + * + * This response includes two pointers to structures within the device's + * data SRAM (access via HBUS_TARG_MEM_* regs) that are useful for debugging: + * + * 1) log_event_table_ptr indicates base of the event log. This traces + * a 256-entry history of uCode execution within a circular buffer. + * Its header format is: + * + * __le32 log_size; log capacity (in number of entries) + * __le32 type; (1) timestamp with each entry, (0) no timestamp + * __le32 wraps; # times uCode has wrapped to top of circular buffer + * __le32 write_index; next circular buffer entry that uCode would fill + * + * The header is followed by the circular buffer of log entries. Entries + * with timestamps have the following format: + * + * __le32 event_id; range 0 - 1500 + * __le32 timestamp; low 32 bits of TSF (of network, if associated) + * __le32 data; event_id-specific data value + * + * Entries without timestamps contain only event_id and data. + * + * 2) error_event_table_ptr indicates base of the error log. This contains + * information about any uCode error that occurs. For 4965, the format + * of the error log is: + * + * __le32 valid; (nonzero) valid, (0) log is empty + * __le32 error_id; type of error + * __le32 pc; program counter + * __le32 blink1; branch link + * __le32 blink2; branch link + * __le32 ilink1; interrupt link + * __le32 ilink2; interrupt link + * __le32 data1; error-specific data + * __le32 data2; error-specific data + * __le32 line; source code line of error + * __le32 bcon_time; beacon timer + * __le32 tsf_low; network timestamp function timer + * __le32 tsf_hi; network timestamp function timer + * + * The Linux driver can print both logs to the system log when a uCode error + * occurs. + */ +struct iwl4965_alive_resp { + u8 ucode_minor; + u8 ucode_major; + __le16 reserved1; + u8 sw_rev[8]; + u8 ver_type; + u8 ver_subtype; /* not "9" for runtime alive */ + __le16 reserved2; + __le32 log_event_table_ptr; /* SRAM address for event log */ + __le32 error_event_table_ptr; /* SRAM address for error log */ + __le32 timestamp; + __le32 is_valid; +} __attribute__ ((packed)); + + +union tsf { + u8 byte[8]; + __le16 word[4]; + __le32 dw[2]; +}; + +/* + * REPLY_ERROR = 0x2 (response only, not a command) + */ +struct iwl4965_error_resp { + __le32 error_type; + u8 cmd_id; + u8 reserved1; + __le16 bad_cmd_seq_num; + __le32 error_info; + union tsf timestamp; +} __attribute__ ((packed)); + +/****************************************************************************** + * (1) + * RXON Commands & Responses: + * + *****************************************************************************/ + +/* + * Rx config defines & structure + */ +/* rx_config device types */ +enum { + RXON_DEV_TYPE_AP = 1, + RXON_DEV_TYPE_ESS = 3, + RXON_DEV_TYPE_IBSS = 4, + RXON_DEV_TYPE_SNIFFER = 6, +}; + + +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0) +#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1) +#define RXON_RX_CHAIN_VALID_POS (1) +#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7 << 4) +#define RXON_RX_CHAIN_FORCE_SEL_POS (4) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7 << 7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) +#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3 << 10) +#define RXON_RX_CHAIN_CNT_POS (10) +#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3 << 12) +#define RXON_RX_CHAIN_MIMO_CNT_POS (12) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1 << 14) +#define RXON_RX_CHAIN_MIMO_FORCE_POS (14) + +/* rx_config flags */ +/* band & modulation selection */ +#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +/* auto detection enable */ +#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +/* TGg protection when tx */ +#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +/* cck short slot & preamble */ +#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +/* antenna selection */ +#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +/* radar detection enable */ +#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +/* rx response to host with 8-byte TSF +* (according to ON_AIR deassertion) */ +#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) + + +/* HT flags */ +#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1 << 22) + +#define RXON_FLG_HT_OPERATING_MODE_POS (23) + +#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1 << 23) +#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23) + +#define RXON_FLG_CHANNEL_MODE_POS (25) +#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) + +/* rx_config filter flags */ +/* accept all data frames */ +#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +/* pass control & management to host */ +#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +/* accept multi-cast */ +#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +/* don't decrypt uni-cast frames */ +#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +/* don't decrypt multi-cast frames */ +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +/* STA is associated */ +#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +/* transfer to host non bssid beacons in associated state */ +#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) + +/** + * REPLY_RXON = 0x10 (command, has simple generic response) + * + * RXON tunes the radio tuner to a service channel, and sets up a number + * of parameters that are used primarily for Rx, but also for Tx operations. + * + * NOTE: When tuning to a new channel, driver must set the + * RXON_FILTER_ASSOC_MSK to 0. This will clear station-dependent + * info within the device, including the station tables, tx retry + * rate tables, and txpower tables. Driver must build a new station + * table and txpower table before transmitting anything on the RXON + * channel. + * + * NOTE: All RXONs wipe clean the internal txpower table. Driver must + * issue a new REPLY_TX_PWR_TABLE_CMD after each REPLY_RXON (0x10), + * regardless of whether RXON_FILTER_ASSOC_MSK is set. + */ +struct iwl4965_rxon_cmd { + u8 node_addr[6]; + __le16 reserved1; + u8 bssid_addr[6]; + __le16 reserved2; + u8 wlap_bssid_addr[6]; + __le16 reserved3; + u8 dev_type; + u8 air_propagation; + __le16 rx_chain; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + __le16 assoc_id; + __le32 flags; + __le32 filter_flags; + __le16 channel; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; +} __attribute__ ((packed)); + +/* + * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response) + */ +struct iwl4965_rxon_assoc_cmd { + __le32 flags; + __le32 filter_flags; + u8 ofdm_basic_rates; + u8 cck_basic_rates; + u8 ofdm_ht_single_stream_basic_rates; + u8 ofdm_ht_dual_stream_basic_rates; + __le16 rx_chain_select_flags; + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) + */ +struct iwl4965_rxon_time_cmd { + union tsf timestamp; + __le16 beacon_interval; + __le16 atim_window; + __le32 beacon_init_val; + __le16 listen_interval; + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) + */ +struct iwl4965_channel_switch_cmd { + u8 band; + u8 expect_beacon; + __le16 channel; + __le32 rxon_flags; + __le32 rxon_filter_flags; + __le32 switch_time; + struct iwl4965_tx_power_db tx_power; +} __attribute__ ((packed)); + +/* + * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) + */ +struct iwl4965_csa_notification { + __le16 band; + __le16 channel; + __le32 status; /* 0 - OK, 1 - fail */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (2) + * Quality-of-Service (QOS) Commands & Responses: + * + *****************************************************************************/ + +/** + * struct iwl_ac_qos -- QOS timing params for REPLY_QOS_PARAM + * One for each of 4 EDCA access categories in struct iwl_qosparam_cmd + * + * @cw_min: Contention window, start value in numbers of slots. + * Should be a power-of-2, minus 1. Device's default is 0x0f. + * @cw_max: Contention window, max value in numbers of slots. + * Should be a power-of-2, minus 1. Device's default is 0x3f. + * @aifsn: Number of slots in Arbitration Interframe Space (before + * performing random backoff timing prior to Tx). Device default 1. + * @edca_txop: Length of Tx opportunity, in uSecs. Device default is 0. + * + * Device will automatically increase contention window by (2*CW) + 1 for each + * transmission retry. Device uses cw_max as a bit mask, ANDed with new CW + * value, to cap the CW value. + */ +struct iwl4965_ac_qos { + __le16 cw_min; + __le16 cw_max; + u8 aifsn; + u8 reserved1; + __le16 edca_txop; +} __attribute__ ((packed)); + +/* QoS flags defines */ +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) + +/* Number of Access Categories (AC) (EDCA), queues 0..3 */ +#define AC_NUM 4 + +/* + * REPLY_QOS_PARAM = 0x13 (command, has simple generic response) + * + * This command sets up timings for each of the 4 prioritized EDCA Tx FIFOs + * 0: Background, 1: Best Effort, 2: Video, 3: Voice. + */ +struct iwl4965_qosparam_cmd { + __le32 qos_flags; + struct iwl4965_ac_qos ac[AC_NUM]; +} __attribute__ ((packed)); + +/****************************************************************************** + * (3) + * Add/Modify Stations Commands & Responses: + * + *****************************************************************************/ +/* + * Multi station support + */ + +/* Special, dedicated locations within device's station table */ +#define IWL_AP_ID 0 +#define IWL_MULTICAST_ID 1 +#define IWL_STA_ID 2 +#define IWL4965_BROADCAST_ID 31 +#define IWL4965_STATION_COUNT 32 + +#define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ +#define IWL_INVALID_STATION 255 + +#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); +#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_MAX_AGG_SIZE_POS (19) +#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_AGG_MPDU_DENSITY_POS (23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) + +/* Use in mode field. 1: modify existing entry, 0: add new station entry */ +#define STA_CONTROL_MODIFY_MSK 0x01 + +/* key flags __le16*/ +#define STA_KEY_FLG_ENCRYPT_MSK __constant_cpu_to_le16(0x7) +#define STA_KEY_FLG_NO_ENC __constant_cpu_to_le16(0x0) +#define STA_KEY_FLG_WEP __constant_cpu_to_le16(0x1) +#define STA_KEY_FLG_CCMP __constant_cpu_to_le16(0x2) +#define STA_KEY_FLG_TKIP __constant_cpu_to_le16(0x3) + +#define STA_KEY_FLG_KEYID_POS 8 +#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) + +/* Flags indicate whether to modify vs. don't change various station params */ +#define STA_MODIFY_KEY_MASK 0x01 +#define STA_MODIFY_TID_DISABLE_TX 0x02 +#define STA_MODIFY_TX_RATE_MSK 0x04 +#define STA_MODIFY_ADDBA_TID_MSK 0x08 +#define STA_MODIFY_DELBA_TID_MSK 0x10 + +/* Receiver address (actually, Rx station's index into station table), + * combined with Traffic ID (QOS priority), in format used by Tx Scheduler */ +#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid)) + +struct iwl4965_keyinfo { + __le16 key_flags; + u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */ + u8 reserved1; + __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */ + __le16 reserved2; + u8 key[16]; /* 16-byte unicast decryption key */ +} __attribute__ ((packed)); + +/** + * struct sta_id_modify + * @addr[ETH_ALEN]: station's MAC address + * @sta_id: index of station in uCode's station table + * @modify_mask: STA_MODIFY_*, 1: modify, 0: don't change + * + * Driver selects unused table index when adding new station, + * or the index to a pre-existing station entry when modifying that station. + * Some indexes have special purposes (IWL_AP_ID, index 0, is for AP). + * + * modify_mask flags select which parameters to modify vs. leave alone. + */ +struct sta_id_modify { + u8 addr[ETH_ALEN]; + __le16 reserved1; + u8 sta_id; + u8 modify_mask; + __le16 reserved2; +} __attribute__ ((packed)); + +/* + * REPLY_ADD_STA = 0x18 (command) + * + * The device contains an internal table of per-station information, + * with info on security keys, aggregation parameters, and Tx rates for + * initial Tx attempt and any retries (4965 uses REPLY_TX_LINK_QUALITY_CMD, + * 3945 uses REPLY_RATE_SCALE to set up rate tables). + * + * REPLY_ADD_STA sets up the table entry for one station, either creating + * a new entry, or modifying a pre-existing one. + * + * NOTE: RXON command (without "associated" bit set) wipes the station table + * clean. Moving into RF_KILL state does this also. Driver must set up + * new station table before transmitting anything on the RXON channel + * (except active scans or active measurements; those commands carry + * their own txpower/rate setup data). + * + * When getting started on a new channel, driver must set up the + * IWL_BROADCAST_ID entry (last entry in the table). For a client + * station in a BSS, once an AP is selected, driver sets up the AP STA + * in the IWL_AP_ID entry (1st entry in the table). BROADCAST and AP + * are all that are needed for a BSS client station. If the device is + * used as AP, or in an IBSS network, driver must set up station table + * entries for all STAs in network, starting with index IWL_STA_ID. + */ +struct iwl4965_addsta_cmd { + u8 mode; /* 1: modify existing, 0: add new station */ + u8 reserved[3]; + struct sta_id_modify sta; + struct iwl4965_keyinfo key; + __le32 station_flags; /* STA_FLG_* */ + __le32 station_flags_msk; /* STA_FLG_* */ + + /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID) + * corresponding to bit (e.g. bit 5 controls TID 5). + * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */ + __le16 tid_disable_tx; + + __le16 reserved1; + + /* TID for which to add block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + u8 add_immediate_ba_tid; + + /* TID for which to remove block-ack support. + * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */ + u8 remove_immediate_ba_tid; + + /* Starting Sequence Number for added block-ack support. + * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */ + __le16 add_immediate_ba_ssn; + + __le32 reserved2; +} __attribute__ ((packed)); + +#define ADD_STA_SUCCESS_MSK 0x1 +#define ADD_STA_NO_ROOM_IN_TABLE 0x2 +#define ADD_STA_NO_BLOCK_ACK_RESOURCE 0x4 +#define ADD_STA_MODIFY_NON_EXIST_STA 0x8 +/* + * REPLY_ADD_STA = 0x18 (response) + */ +struct iwl4965_add_sta_resp { + u8 status; /* ADD_STA_* */ +} __attribute__ ((packed)); + + +/****************************************************************************** + * (4) + * Rx Responses: + * + *****************************************************************************/ + +struct iwl4965_rx_frame_stats { + u8 phy_count; + u8 id; + u8 rssi; + u8 agc; + __le16 sig_avg; + __le16 noise_diff; + u8 payload[0]; +} __attribute__ ((packed)); + +struct iwl4965_rx_frame_hdr { + __le16 channel; + __le16 phy_flags; + u8 reserved1; + u8 rate; + __le16 len; + u8 payload[0]; +} __attribute__ ((packed)); + +#define RX_RES_STATUS_NO_CRC32_ERROR __constant_cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW __constant_cpu_to_le32(1 << 1) + +#define RX_RES_PHY_FLAGS_BAND_24_MSK __constant_cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK __constant_cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK __constant_cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK __constant_cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK __constant_cpu_to_le16(0xf0) + +#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) +#define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) +#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8) +#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8) +#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8) + +#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11) +#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11) +#define RX_RES_STATUS_DECRYPT_OK (0x3 << 11) +#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11) +#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11) + +struct iwl4965_rx_frame_end { + __le32 status; + __le64 timestamp; + __le32 beacon_timestamp; +} __attribute__ ((packed)); + +/* + * REPLY_3945_RX = 0x1b (response only, not a command) + * + * NOTE: DO NOT dereference from casts to this structure + * It is provided only for calculating minimum data set size. + * The actual offsets of the hdr and end are dynamic based on + * stats.phy_count + */ +struct iwl4965_rx_frame { + struct iwl4965_rx_frame_stats stats; + struct iwl4965_rx_frame_hdr hdr; + struct iwl4965_rx_frame_end end; +} __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) +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 */ + u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */ + u8 pad[0]; +} __attribute__ ((packed)); + +/* + * REPLY_4965_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 { + 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 */ + u8 reserved1; + __le64 timestamp; /* TSF at on air rise */ + __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; + __le32 rate_n_flags; /* RATE_MCS_* */ + __le16 byte_count; /* frame's byte-count */ + __le16 reserved3; +} __attribute__ ((packed)); + +struct iwl4965_rx_mpdu_res_start { + __le16 byte_count; + __le16 reserved; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (5) + * Tx Commands & Responses: + * + * Driver must place each REPLY_TX command into one of the prioritized Tx + * queues in host DRAM, shared between driver and device (see comments for + * SCD registers and Tx/Rx Queues). When the device's Tx scheduler and uCode + * are preparing to transmit, the device pulls the Tx command over the PCI + * bus via one of the device's Tx DMA channels, to fill an internal FIFO + * from which data will be transmitted. + * + * uCode handles all timing and protocol related to control frames + * (RTS/CTS/ACK), based on flags in the Tx command. uCode and Tx scheduler + * handle reception of block-acks; uCode updates the host driver via + * REPLY_COMPRESSED_BA (4965). + * + * uCode handles retrying Tx when an ACK is expected but not received. + * This includes trying lower data rates than the one requested in the Tx + * command, as set up by the REPLY_RATE_SCALE (for 3945) or + * REPLY_TX_LINK_QUALITY_CMD (4965). + * + * Driver sets up transmit power for various rates via REPLY_TX_PWR_TABLE_CMD. + * This command must be executed after every RXON command, before Tx can occur. + *****************************************************************************/ + +/* REPLY_TX Tx flags field */ + +/* 1: Use Request-To-Send protocol before this frame. + * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ +#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) + +/* 1: Transmit Clear-To-Send to self before this frame. + * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. + * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ +#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) + +/* 1: Expect ACK from receiving station + * 0: Don't expect ACK (MAC header's duration field s/b 0) + * Set this for unicast frames, but not broadcast/multicast. */ +#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) + +/* For 4965: + * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). + * Tx command's initial_rate_index indicates first rate to try; + * uCode walks through table for additional Tx attempts. + * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. + * This rate will be used for all Tx attempts; it will not be scaled. */ +#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) + +/* 1: Expect immediate block-ack. + * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ +#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) + +/* 1: Frame requires full Tx-Op protection. + * Set this if either RTS or CTS Tx Flag gets set. */ +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) + +/* Tx antenna selection field; used only for 3945, reserved (0) for 4965. + * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ +#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) + +/* 1: Ignore Bluetooth priority for this frame. + * 0: Delay Tx until Bluetooth device is done (normal usage). */ +#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) + +/* 1: uCode overrides sequence control field in MAC header. + * 0: Driver provides sequence control field in MAC header. + * Set this for management frames, non-QOS data frames, non-unicast frames, + * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ +#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) + +/* 1: This frame is non-last MPDU; more fragments are coming. + * 0: Last fragment, or not using fragmentation. */ +#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) + +/* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. + * 0: No TSF required in outgoing frame. + * Set this for transmitting beacons and probe responses. */ +#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) + +/* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword + * alignment of frame's payload data field. + * 0: No pad + * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 + * field (but not both). Driver must align frame data (i.e. data following + * MAC header) to DWORD boundary. */ +#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) + +/* HCCA-AP - disable duration overwriting. */ +#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) + + +/* + * TX command security control + */ +#define TX_CMD_SEC_WEP 0x01 +#define TX_CMD_SEC_CCM 0x02 +#define TX_CMD_SEC_TKIP 0x03 +#define TX_CMD_SEC_MSK 0x03 +#define TX_CMD_SEC_SHIFT 6 +#define TX_CMD_SEC_KEY128 0x08 + +/* + * 4965 uCode updates these Tx attempt count values in host DRAM. + * Used for managing Tx retries when expecting block-acks. + * Driver should set these fields to 0. + */ +struct iwl4965_dram_scratch { + u8 try_cnt; /* Tx attempts */ + u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */ + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX = 0x1c (command) + */ +struct iwl4965_tx_cmd { + /* + * MPDU byte count: + * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size, + * + 8 byte IV for CCM or TKIP (not used for WEP) + * + Data payload + * + 8-byte MIC (not used for CCM/WEP) + * NOTE: Does not include Tx command bytes, post-MAC pad bytes, + * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i + * Range: 14-2342 bytes. + */ + __le16 len; + + /* + * MPDU or MSDU byte count for next frame. + * Used for fragmentation and bursting, but not 11n aggregation. + * Same as "len", but for next frame. Set to 0 if not applicable. + */ + __le16 next_frame_len; + + __le32 tx_flags; /* TX_CMD_FLG_* */ + + /* 4965's uCode may modify this field of the Tx command (in host DRAM!). + * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */ + struct iwl4965_dram_scratch scratch; + + /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */ + __le32 rate_n_flags; /* RATE_MCS_* */ + + /* Index of destination station in uCode's station table */ + u8 sta_id; + + /* Type of security encryption: CCM or TKIP */ + u8 sec_ctl; /* TX_CMD_SEC_* */ + + /* + * Index into rate table (see REPLY_TX_LINK_QUALITY_CMD) for initial + * Tx attempt, if TX_CMD_FLG_STA_RATE_MSK is set. Normally "0" for + * data frames, this field may be used to selectively reduce initial + * rate (via non-0 value) for special frames (e.g. management), while + * still supporting rate scaling for all frames. + */ + u8 initial_rate_index; + u8 reserved; + u8 key[16]; + __le16 next_frame_flags; + __le16 reserved2; + union { + __le32 life_time; + __le32 attempt; + } stop_time; + + /* Host DRAM physical address pointer to "scratch" in this command. + * Must be dword aligned. "0" in dram_lsb_ptr disables usage. */ + __le32 dram_lsb_ptr; + u8 dram_msb_ptr; + + u8 rts_retry_limit; /*byte 50 */ + u8 data_retry_limit; /*byte 51 */ + u8 tid_tspec; + union { + __le16 pm_frame_timeout; + __le16 attempt_duration; + } timeout; + + /* + * Duration of EDCA burst Tx Opportunity, in 32-usec units. + * Set this if txop time is not specified by HCCA protocol (e.g. by AP). + */ + __le16 driver_txop; + + /* + * MAC header goes here, followed by 2 bytes padding if MAC header + * length is 26 or 30 bytes, followed by payload data + */ + u8 payload[0]; + struct ieee80211_hdr hdr[0]; +} __attribute__ ((packed)); + +/* TX command response is sent after *all* transmission attempts. + * + * NOTES: + * + * TX_STATUS_FAIL_NEXT_FRAG + * + * If the fragment flag in the MAC header for the frame being transmitted + * is set and there is insufficient time to transmit the next frame, the + * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'. + * + * TX_STATUS_FIFO_UNDERRUN + * + * Indicates the host did not provide bytes to the FIFO fast enough while + * a TX was in progress. + * + * TX_STATUS_FAIL_MGMNT_ABORT + * + * This status is only possible if the ABORT ON MGMT RX parameter was + * set to true with the TX command. + * + * If the MSB of the status parameter is set then an abort sequence is + * required. This sequence consists of the host activating the TX Abort + * control line, and then waiting for the TX Abort command response. This + * indicates that a the device is no longer in a transmit state, and that the + * command FIFO has been cleared. The host must then deactivate the TX Abort + * control line. Receiving is still allowed in this case. + */ +enum { + TX_STATUS_SUCCESS = 0x01, + TX_STATUS_DIRECT_DONE = 0x02, + TX_STATUS_FAIL_SHORT_LIMIT = 0x82, + TX_STATUS_FAIL_LONG_LIMIT = 0x83, + TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84, + TX_STATUS_FAIL_MGMNT_ABORT = 0x85, + TX_STATUS_FAIL_NEXT_FRAG = 0x86, + TX_STATUS_FAIL_LIFE_EXPIRE = 0x87, + TX_STATUS_FAIL_DEST_PS = 0x88, + TX_STATUS_FAIL_ABORTED = 0x89, + TX_STATUS_FAIL_BT_RETRY = 0x8a, + TX_STATUS_FAIL_STA_INVALID = 0x8b, + TX_STATUS_FAIL_FRAG_DROPPED = 0x8c, + TX_STATUS_FAIL_TID_DISABLE = 0x8d, + TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e, + TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f, + TX_STATUS_FAIL_TX_LOCKED = 0x90, + TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91, +}; + +#define TX_PACKET_MODE_REGULAR 0x0000 +#define TX_PACKET_MODE_BURST_SEQ 0x0100 +#define TX_PACKET_MODE_BURST_FIRST 0x0200 + +enum { + TX_POWER_PA_NOT_ACTIVE = 0x0, +}; + +enum { + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_DELAY_MSK = 0x00000040, + TX_STATUS_ABORT_MSK = 0x00000080, + TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ + TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ + TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ +}; + +/* ******************************* + * TX aggregation status + ******************************* */ + +enum { + AGG_TX_STATE_TRANSMITTED = 0x00, + AGG_TX_STATE_UNDERRUN_MSK = 0x01, + AGG_TX_STATE_BT_PRIO_MSK = 0x02, + AGG_TX_STATE_FEW_BYTES_MSK = 0x04, + AGG_TX_STATE_ABORT_MSK = 0x08, + AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10, + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20, + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40, + AGG_TX_STATE_SCD_QUERY_MSK = 0x80, + AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100, + AGG_TX_STATE_RESPONSE_MSK = 0x1ff, + AGG_TX_STATE_DUMP_TX_MSK = 0x200, + AGG_TX_STATE_DELAY_TX_MSK = 0x400 +}; + +#define AGG_TX_STATE_LAST_SENT_MSK \ +(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) + +/* # tx attempts for first frame in aggregation */ +#define AGG_TX_STATE_TRY_CNT_POS 12 +#define AGG_TX_STATE_TRY_CNT_MSK 0xf000 + +/* Command ID and sequence number of Tx command for this frame */ +#define AGG_TX_STATE_SEQ_NUM_POS 16 +#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000 + +/* + * REPLY_TX = 0x1c (response) + * + * This response may be in one of two slightly different formats, indicated + * by the frame_count field: + * + * 1) No aggregation (frame_count == 1). This reports Tx results for + * a single frame. Multiple attempts, at various bit rates, may have + * been made for this frame. + * + * 2) Aggregation (frame_count > 1). This reports Tx results for + * 2 or more frames that used block-acknowledge. All frames were + * transmitted at same rate. Rate scaling may have been used if first + * frame in this new agg block failed in previous agg block(s). + * + * Note that, for aggregation, ACK (block-ack) status is not delivered here; + * block-ack has not been received by the time the 4965 records this status. + * This status relates to reasons the tx might have been blocked or aborted + * within the sending station (this 4965), rather than whether it was + * received successfully by the destination station. + */ +struct iwl4965_tx_resp { + u8 frame_count; /* 1 no aggregation, >1 aggregation */ + u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ + u8 failure_rts; /* # failures due to unsuccessful RTS */ + u8 failure_frame; /* # failures due to no ACK (unused for agg) */ + + /* For non-agg: Rate at which frame was successful. + * For agg: Rate at which all frames were transmitted. */ + __le32 rate_n_flags; /* RATE_MCS_* */ + + /* For non-agg: RTS + CTS + frame tx attempts time + ACK. + * For agg: RTS + CTS + aggregation tx time + block-ack time. */ + __le16 wireless_media_time; /* uSecs */ + + __le16 reserved; + __le32 pa_power1; /* RF power amplifier measurement (not used) */ + __le32 pa_power2; + + /* + * For non-agg: frame status TX_STATUS_* + * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status + * fields follow this one, up to frame_count. + * Bit fields: + * 11- 0: AGG_TX_STATE_* status code + * 15-12: Retry count for 1st frame in aggregation (retries + * occur if tx failed for this frame when it was a + * member of a previous aggregation block). If rate + * scaling is used, retry count indicates the rate + * table entry used for all frames in the new agg. + * 31-16: Sequence # for this frame's Tx cmd (not SSN!) + */ + __le32 status; /* TX status (for aggregation status of 1st frame) */ +} __attribute__ ((packed)); + +/* + * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command) + * + * Reports Block-Acknowledge from recipient station + */ +struct iwl4965_compressed_ba_resp { + __le32 sta_addr_lo32; + __le16 sta_addr_hi16; + __le16 reserved; + + /* Index of recipient (BA-sending) station in uCode's station table */ + u8 sta_id; + u8 tid; + __le16 ba_seq_ctl; + __le32 ba_bitmap0; + __le32 ba_bitmap1; + __le16 scd_flow; + __le16 scd_ssn; +} __attribute__ ((packed)); + +/* + * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response) + * + * See details under "TXPOWER" in iwl-4965-hw.h. + */ +struct iwl4965_txpowertable_cmd { + u8 band; /* 0: 5 GHz, 1: 2.4 GHz */ + u8 reserved; + __le16 channel; + struct iwl4965_tx_power_db tx_power; +} __attribute__ ((packed)); + +/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */ +#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0) + +/* # of EDCA prioritized tx fifos */ +#define LINK_QUAL_AC_NUM AC_NUM + +/* # entries in rate scale table to support Tx retries */ +#define LINK_QUAL_MAX_RETRY_NUM 16 + +/* Tx antenna selection values */ +#define LINK_QUAL_ANT_A_MSK (1 << 0) +#define LINK_QUAL_ANT_B_MSK (1 << 1) +#define LINK_QUAL_ANT_MSK (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK) + + +/** + * struct iwl4965_link_qual_general_params + * + * Used in REPLY_TX_LINK_QUALITY_CMD + */ +struct iwl4965_link_qual_general_params { + u8 flags; + + /* No entries at or above this (driver chosen) index contain MIMO */ + u8 mimo_delimiter; + + /* Best single antenna to use for single stream (legacy, SISO). */ + u8 single_stream_ant_msk; /* LINK_QUAL_ANT_* */ + + /* Best antennas to use for MIMO (unused for 4965, assumes both). */ + u8 dual_stream_ant_msk; /* LINK_QUAL_ANT_* */ + + /* + * If driver needs to use different initial rates for different + * EDCA QOS access categories (as implemented by tx fifos 0-3), + * this table will set that up, by indicating the indexes in the + * rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table at which to start. + * Otherwise, driver should set all entries to 0. + * + * Entry usage: + * 0 = Background, 1 = Best Effort (normal), 2 = Video, 3 = Voice + * TX FIFOs above 3 use same value (typically 0) as TX FIFO 3. + */ + u8 start_rate_index[LINK_QUAL_AC_NUM]; +} __attribute__ ((packed)); + +/** + * struct iwl4965_link_qual_agg_params + * + * Used in REPLY_TX_LINK_QUALITY_CMD + */ +struct iwl4965_link_qual_agg_params { + + /* Maximum number of uSec in aggregation. + * Driver should set this to 4000 (4 milliseconds). */ + __le16 agg_time_limit; + + /* + * Number of Tx retries allowed for a frame, before that frame will + * no longer be considered for the start of an aggregation sequence + * (scheduler will then try to tx it as single frame). + * Driver should set this to 3. + */ + u8 agg_dis_start_th; + + /* + * Maximum number of frames in aggregation. + * 0 = no limit (default). 1 = no aggregation. + * Other values = max # frames in aggregation. + */ + u8 agg_frame_cnt_limit; + + __le32 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response) + * + * For 4965 only; 3945 uses REPLY_RATE_SCALE. + * + * Each station in the 4965's internal station table has its own table of 16 + * Tx rates and modulation modes (e.g. legacy/SISO/MIMO) for retrying Tx when + * an ACK is not received. This command replaces the entire table for + * one station. + * + * NOTE: Station must already be in 4965's station table. Use REPLY_ADD_STA. + * + * The rate scaling procedures described below work well. Of course, other + * procedures are possible, and may work better for particular environments. + * + * + * FILLING THE RATE TABLE + * + * Given a particular initial rate and mode, as determined by the rate + * scaling algorithm described below, the Linux driver uses the following + * formula to fill the rs_table[LINK_QUAL_MAX_RETRY_NUM] rate table in the + * Link Quality command: + * + * + * 1) If using High-throughput (HT) (SISO or MIMO) initial rate: + * a) Use this same initial rate for first 3 entries. + * b) Find next lower available rate using same mode (SISO or MIMO), + * use for next 3 entries. If no lower rate available, switch to + * legacy mode (no FAT channel, no MIMO, no short guard interval). + * c) If using MIMO, set command's mimo_delimiter to number of entries + * using MIMO (3 or 6). + * d) After trying 2 HT rates, switch to legacy mode (no FAT channel, + * no MIMO, no short guard interval), at the next lower bit rate + * (e.g. if second HT bit rate was 54, try 48 legacy), and follow + * legacy procedure for remaining table entries. + * + * 2) If using legacy initial rate: + * a) Use the initial rate for only one entry. + * b) For each following entry, reduce the rate to next lower available + * rate, until reaching the lowest available rate. + * c) When reducing rate, also switch antenna selection. + * d) Once lowest available rate is reached, repeat this rate until + * rate table is filled (16 entries), switching antenna each entry. + * + * + * ACCUMULATING HISTORY + * + * The rate scaling algorithm for 4965, as implemented in Linux driver, uses + * two sets of frame Tx success history: One for the current/active modulation + * mode, and one for a speculative/search mode that is being attempted. If the + * speculative mode turns out to be more effective (i.e. actual transfer + * rate is better), then the driver continues to use the speculative mode + * as the new current active mode. + * + * Each history set contains, separately for each possible rate, data for a + * sliding window of the 62 most recent tx attempts at that rate. The data + * includes a shifting bitmap of success(1)/failure(0), and sums of successful + * and attempted frames, from which the driver can additionally calculate a + * success ratio (success / attempted) and number of failures + * (attempted - success), and control the size of the window (attempted). + * The driver uses the bit map to remove successes from the success sum, as + * the oldest tx attempts fall out of the window. + * + * When the 4965 makes multiple tx attempts for a given frame, each attempt + * might be at a different rate, and have different modulation characteristics + * (e.g. antenna, fat channel, short guard interval), as set up in the rate + * scaling table in the Link Quality command. The driver must determine + * which rate table entry was used for each tx attempt, to determine which + * rate-specific history to update, and record only those attempts that + * match the modulation characteristics of the history set. + * + * When using block-ack (aggregation), all frames are transmitted at the same + * rate, since there is no per-attempt acknowledgement from the destination + * station. The Tx response struct iwl_tx_resp indicates the Tx rate in + * rate_n_flags field. After receiving a block-ack, the driver can update + * history for the entire block all at once. + * + * + * FINDING BEST STARTING RATE: + * + * When working with a selected initial modulation mode (see below), the + * driver attempts to find a best initial rate. The initial rate is the + * first entry in the Link Quality command's rate table. + * + * 1) Calculate actual throughput (success ratio * expected throughput, see + * table below) for current initial rate. Do this only if enough frames + * have been attempted to make the value meaningful: at least 6 failed + * tx attempts, or at least 8 successes. If not enough, don't try rate + * scaling yet. + * + * 2) Find available rates adjacent to current initial rate. Available means: + * a) supported by hardware && + * b) supported by association && + * c) within any constraints selected by user + * + * 3) Gather measured throughputs for adjacent rates. These might not have + * enough history to calculate a throughput. That's okay, we might try + * using one of them anyway! + * + * 4) Try decreasing rate if, for current rate: + * a) success ratio is < 15% || + * b) lower adjacent rate has better measured throughput || + * c) higher adjacent rate has worse throughput, and lower is unmeasured + * + * As a sanity check, if decrease was determined above, leave rate + * unchanged if: + * a) lower rate unavailable + * b) success ratio at current rate > 85% (very good) + * c) current measured throughput is better than expected throughput + * of lower rate (under perfect 100% tx conditions, see table below) + * + * 5) Try increasing rate if, for current rate: + * a) success ratio is < 15% || + * b) both adjacent rates' throughputs are unmeasured (try it!) || + * b) higher adjacent rate has better measured throughput || + * c) lower adjacent rate has worse throughput, and higher is unmeasured + * + * As a sanity check, if increase was determined above, leave rate + * unchanged if: + * a) success ratio at current rate < 70%. This is not particularly + * good performance; higher rate is sure to have poorer success. + * + * 6) Re-evaluate the rate after each tx frame. If working with block- + * acknowledge, history and statistics may be calculated for the entire + * block (including prior history that fits within the history windows), + * before re-evaluation. + * + * FINDING BEST STARTING MODULATION MODE: + * + * After working with a modulation mode for a "while" (and doing rate scaling), + * the driver searches for a new initial mode in an attempt to improve + * throughput. The "while" is measured by numbers of attempted frames: + * + * For legacy mode, search for new mode after: + * 480 successful frames, or 160 failed frames + * For high-throughput modes (SISO or MIMO), search for new mode after: + * 4500 successful frames, or 400 failed frames + * + * Mode switch possibilities are (3 for each mode): + * + * For legacy: + * Change antenna, try SISO (if HT association), try MIMO (if HT association) + * For SISO: + * Change antenna, try MIMO, try shortened guard interval (SGI) + * For MIMO: + * Try SISO antenna A, SISO antenna B, try shortened guard interval (SGI) + * + * When trying a new mode, use the same bit rate as the old/current mode when + * trying antenna switches and shortened guard interval. When switching to + * SISO from MIMO or legacy, or to MIMO from SISO or legacy, use a rate + * for which the expected throughput (under perfect conditions) is about the + * same or slightly better than the actual measured throughput delivered by + * the old/current mode. + * + * Actual throughput can be estimated by multiplying the expected throughput + * by the success ratio (successful / attempted tx frames). Frame size is + * not considered in this calculation; it assumes that frame size will average + * out to be fairly consistent over several samples. The following are + * metric values for expected throughput assuming 100% success ratio. + * Only G band has support for CCK rates: + * + * RATE: 1 2 5 11 6 9 12 18 24 36 48 54 60 + * + * G: 7 13 35 58 40 57 72 98 121 154 177 186 186 + * A: 0 0 0 0 40 57 72 98 121 154 177 186 186 + * SISO 20MHz: 0 0 0 0 42 42 76 102 124 159 183 193 202 + * SGI SISO 20MHz: 0 0 0 0 46 46 82 110 132 168 192 202 211 + * MIMO 20MHz: 0 0 0 0 74 74 123 155 179 214 236 244 251 + * SGI MIMO 20MHz: 0 0 0 0 81 81 131 164 188 222 243 251 257 + * SISO 40MHz: 0 0 0 0 77 77 127 160 184 220 242 250 257 + * SGI SISO 40MHz: 0 0 0 0 83 83 135 169 193 229 250 257 264 + * MIMO 40MHz: 0 0 0 0 123 123 182 214 235 264 279 285 289 + * SGI MIMO 40MHz: 0 0 0 0 131 131 191 222 242 270 284 289 293 + * + * After the new mode has been tried for a short while (minimum of 6 failed + * frames or 8 successful frames), compare success ratio and actual throughput + * estimate of the new mode with the old. If either is better with the new + * mode, continue to use the new mode. + * + * Continue comparing modes until all 3 possibilities have been tried. + * If moving from legacy to HT, try all 3 possibilities from the new HT + * mode. After trying all 3, a best mode is found. Continue to use this mode + * for the longer "while" described above (e.g. 480 successful frames for + * legacy), and then repeat the search process. + * + */ +struct iwl4965_link_quality_cmd { + + /* Index of destination/recipient station in uCode's station table */ + u8 sta_id; + u8 reserved1; + __le16 control; /* not used */ + struct iwl4965_link_qual_general_params general_params; + struct iwl4965_link_qual_agg_params agg_params; + + /* + * Rate info; when using rate-scaling, Tx command's initial_rate_index + * specifies 1st Tx rate attempted, via index into this table. + * 4965 works its way through table when retrying Tx. + */ + struct { + __le32 rate_n_flags; /* RATE_MCS_*, IWL_RATE_* */ + } rs_table[LINK_QUAL_MAX_RETRY_NUM]; + __le32 reserved2; +} __attribute__ ((packed)); + +/* + * REPLY_BT_CONFIG = 0x9b (command, has simple generic response) + * + * 3945 and 4965 support hardware handshake with Bluetooth device on + * same platform. Bluetooth device alerts wireless device when it will Tx; + * wireless device can delay or kill its own Tx to accomodate. + */ +struct iwl4965_bt_cmd { + u8 flags; + u8 lead_time; + u8 max_kill; + u8 reserved; + __le32 kill_ack_mask; + __le32 kill_cts_mask; +} __attribute__ ((packed)); + +/****************************************************************************** + * (6) + * Spectrum Management (802.11h) Commands, Responses, Notifications: + * + *****************************************************************************/ + +/* + * Spectrum Management + */ +#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK | \ + RXON_FILTER_CTL2HOST_MSK | \ + RXON_FILTER_ACCEPT_GRP_MSK | \ + RXON_FILTER_DIS_DECRYPT_MSK | \ + RXON_FILTER_DIS_GRP_DECRYPT_MSK | \ + RXON_FILTER_ASSOC_MSK | \ + RXON_FILTER_BCON_AWARE_MSK) + +struct iwl4965_measure_channel { + __le32 duration; /* measurement duration in extended beacon + * format */ + u8 channel; /* channel to measure */ + u8 type; /* see enum iwl4965_measure_type */ + __le16 reserved; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) + */ +struct iwl4965_spectrum_cmd { + __le16 len; /* number of bytes starting from token */ + u8 token; /* token id */ + u8 id; /* measurement id -- 0 or 1 */ + u8 origin; /* 0 = TGh, 1 = other, 2 = TGk */ + u8 periodic; /* 1 = periodic */ + __le16 path_loss_timeout; + __le32 start_time; /* start time in extended beacon format */ + __le32 reserved2; + __le32 flags; /* rxon flags */ + __le32 filter_flags; /* rxon filter flags */ + __le16 channel_count; /* minimum 1, maximum 10 */ + __le16 reserved3; + struct iwl4965_measure_channel channels[10]; +} __attribute__ ((packed)); + +/* + * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) + */ +struct iwl4965_spectrum_resp { + u8 token; + u8 id; /* id of the prior command replaced, or 0xff */ + __le16 status; /* 0 - command will be handled + * 1 - cannot handle (conflicts with another + * measurement) */ +} __attribute__ ((packed)); + +enum iwl4965_measurement_state { + IWL_MEASUREMENT_START = 0, + IWL_MEASUREMENT_STOP = 1, +}; + +enum iwl4965_measurement_status { + IWL_MEASUREMENT_OK = 0, + IWL_MEASUREMENT_CONCURRENT = 1, + IWL_MEASUREMENT_CSA_CONFLICT = 2, + IWL_MEASUREMENT_TGH_CONFLICT = 3, + /* 4-5 reserved */ + IWL_MEASUREMENT_STOPPED = 6, + IWL_MEASUREMENT_TIMEOUT = 7, + IWL_MEASUREMENT_PERIODIC_FAILED = 8, +}; + +#define NUM_ELEMENTS_IN_HISTOGRAM 8 + +struct iwl4965_measurement_histogram { + __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ + __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ +} __attribute__ ((packed)); + +/* clear channel availability counters */ +struct iwl4965_measurement_cca_counters { + __le32 ofdm; + __le32 cck; +} __attribute__ ((packed)); + +enum iwl4965_measure_type { + IWL_MEASURE_BASIC = (1 << 0), + IWL_MEASURE_CHANNEL_LOAD = (1 << 1), + IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), + IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3), + IWL_MEASURE_FRAME = (1 << 4), + /* bits 5:6 are reserved */ + IWL_MEASURE_IDLE = (1 << 7), +}; + +/* + * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) + */ +struct iwl4965_spectrum_notification { + u8 id; /* measurement id -- 0 or 1 */ + u8 token; + u8 channel_index; /* index in measurement channel list */ + u8 state; /* 0 - start, 1 - stop */ + __le32 start_time; /* lower 32-bits of TSF */ + u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ + u8 channel; + u8 type; /* see enum iwl4965_measurement_type */ + u8 reserved1; + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + * valid if applicable for measurement type requested. */ + __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ + __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ + __le32 cca_time; /* channel load time in usecs */ + u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - + * unidentified */ + u8 reserved2[3]; + struct iwl4965_measurement_histogram histogram; + __le32 stop_time; /* lower 32-bits of TSF */ + __le32 status; /* see iwl4965_measurement_status */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (7) + * Power Management Commands, Responses, Notifications: + * + *****************************************************************************/ + +/** + * struct iwl4965_powertable_cmd - Power Table Command + * @flags: See below: + * + * POWER_TABLE_CMD = 0x77 (command, has simple generic response) + * + * PM allow: + * bit 0 - '0' Driver not allow power management + * '1' Driver allow PM (use rest of parameters) + * uCode send sleep notifications: + * bit 1 - '0' Don't send sleep notification + * '1' send sleep notification (SEND_PM_NOTIFICATION) + * Sleep over DTIM + * bit 2 - '0' PM have to walk up every DTIM + * '1' PM could sleep over DTIM till listen Interval. + * PCI power managed + * bit 3 - '0' (PCI_LINK_CTRL & 0x1) + * '1' !(PCI_LINK_CTRL & 0x1) + * Force sleep Modes + * bit 31/30- '00' use both mac/xtal sleeps + * '01' force Mac sleep + * '10' force xtal sleep + * '11' Illegal set + * + * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then + * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * for every DTIM. + */ +#define IWL_POWER_VEC_SIZE 5 + +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) +#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) + +struct iwl4965_powertable_cmd { + __le16 flags; + u8 keep_alive_seconds; + u8 debug_flags; + __le32 rx_data_timeout; + __le32 tx_data_timeout; + __le32 sleep_interval[IWL_POWER_VEC_SIZE]; + __le32 keep_alive_beacons; +} __attribute__ ((packed)); + +/* + * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) + * 3945 and 4965 identical. + */ +struct iwl4965_sleep_notification { + u8 pm_sleep_mode; + u8 pm_wakeup_src; + __le16 reserved; + __le32 sleep_time; + __le32 tsf_low; + __le32 bcon_timer; +} __attribute__ ((packed)); + +/* Sleep states. 3945 and 4965 identical. */ +enum { + IWL_PM_NO_SLEEP = 0, + IWL_PM_SLP_MAC = 1, + IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2, + IWL_PM_SLP_FULL_MAC_CARD_STATE = 3, + IWL_PM_SLP_PHY = 4, + IWL_PM_SLP_REPENT = 5, + IWL_PM_WAKEUP_BY_TIMER = 6, + IWL_PM_WAKEUP_BY_DRIVER = 7, + IWL_PM_WAKEUP_BY_RFKILL = 8, + /* 3 reserved */ + IWL_PM_NUM_OF_MODES = 12, +}; + +/* + * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response) + */ +#define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ +#define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ +#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ +struct iwl4965_card_state_cmd { + __le32 status; /* CARD_STATE_CMD_* request new power state */ +} __attribute__ ((packed)); + +/* + * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) + */ +struct iwl4965_card_state_notif { + __le32 flags; +} __attribute__ ((packed)); + +#define HW_CARD_DISABLED 0x01 +#define SW_CARD_DISABLED 0x02 +#define RF_CARD_DISABLED 0x04 +#define RXON_CARD_DISABLED 0x10 + +struct iwl4965_ct_kill_config { + __le32 reserved; + __le32 critical_temperature_M; + __le32 critical_temperature_R; +} __attribute__ ((packed)); + +/****************************************************************************** + * (8) + * Scan Commands, Responses, Notifications: + * + *****************************************************************************/ + +/** + * struct iwl4965_scan_channel - entry in REPLY_SCAN_CMD channel table + * + * One for each channel in the scan list. + * Each channel can independently select: + * 1) SSID for directed active scans + * 2) Txpower setting (for rate specified within Tx command) + * 3) How long to stay on-channel (behavior may be modified by quiet_time, + * quiet_plcp_th, good_CRC_th) + * + * To avoid uCode errors, make sure the following are true (see comments + * under struct iwl4965_scan_cmd about max_out_time and quiet_time): + * 1) If using passive_dwell (i.e. passive_dwell != 0): + * active_dwell <= passive_dwell (< max_out_time if max_out_time != 0) + * 2) quiet_time <= active_dwell + * 3) If restricting off-channel time (i.e. max_out_time !=0): + * passive_dwell < max_out_time + * active_dwell < max_out_time + */ +struct iwl4965_scan_channel { + /* + * type is defined as: + * 0:0 1 = active, 0 = passive + * 1:4 SSID direct bit map; if a bit is set, then corresponding + * SSID IE is transmitted in probe request. + * 5:7 reserved + */ + u8 type; + u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */ + struct iwl4965_tx_power tpc; + __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ + __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ +} __attribute__ ((packed)); + +/** + * struct iwl4965_ssid_ie - directed scan network information element + * + * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field + * in struct iwl4965_scan_channel; each channel may select different ssids from + * among the 4 entries. SSID IEs get transmitted in reverse order of entry. + */ +struct iwl4965_ssid_ie { + u8 id; + u8 len; + u8 ssid[32]; +} __attribute__ ((packed)); + +#define PROBE_OPTION_MAX 0x4 +#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define IWL_MAX_SCAN_SIZE 1024 + +/* + * REPLY_SCAN_CMD = 0x80 (command) + * + * The hardware scan command is very powerful; the driver can set it up to + * maintain (relatively) normal network traffic while doing a scan in the + * background. The max_out_time and suspend_time control the ratio of how + * long the device stays on an associated network channel ("service channel") + * vs. how long it's away from the service channel, i.e. tuned to other channels + * for scanning. + * + * max_out_time is the max time off-channel (in usec), and suspend_time + * is how long (in "extended beacon" format) that the scan is "suspended" + * after returning to the service channel. That is, suspend_time is the + * time that we stay on the service channel, doing normal work, between + * scan segments. The driver may set these parameters differently to support + * scanning when associated vs. not associated, and light vs. heavy traffic + * loads when associated. + * + * After receiving this command, the device's scan engine does the following; + * + * 1) Sends SCAN_START notification to driver + * 2) Checks to see if it has time to do scan for one channel + * 3) Sends NULL packet, with power-save (PS) bit set to 1, + * to tell AP that we're going off-channel + * 4) Tunes to first channel in scan list, does active or passive scan + * 5) Sends SCAN_RESULT notification to driver + * 6) Checks to see if it has time to do scan on *next* channel in list + * 7) Repeats 4-6 until it no longer has time to scan the next channel + * before max_out_time expires + * 8) Returns to service channel + * 9) Sends NULL packet with PS=0 to tell AP that we're back + * 10) Stays on service channel until suspend_time expires + * 11) Repeats entire process 2-10 until list is complete + * 12) Sends SCAN_COMPLETE notification + * + * For fast, efficient scans, the scan command also has support for staying on + * a channel for just a short time, if doing active scanning and getting no + * responses to the transmitted probe request. This time is controlled by + * quiet_time, and the number of received packets below which a channel is + * considered "quiet" is controlled by quiet_plcp_threshold. + * + * For active scanning on channels that have regulatory restrictions against + * blindly transmitting, the scan can listen before transmitting, to make sure + * that there is already legitimate activity on the channel. If enough + * packets are cleanly received on the channel (controlled by good_CRC_th, + * typical value 1), the scan engine starts transmitting probe requests. + * + * Driver must use separate scan commands for 2.4 vs. 5 GHz bands. + * + * To avoid uCode errors, see timing restrictions described under + * struct iwl4965_scan_channel. + */ +struct iwl4965_scan_cmd { + __le16 len; + u8 reserved0; + u8 channel_count; /* # channels in channel list */ + __le16 quiet_time; /* dwell only this # millisecs on quiet channel + * (only for active scan) */ + __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */ + __le16 good_CRC_th; /* passive -> active promotion threshold */ + __le16 rx_chain; /* RXON_RX_CHAIN_* */ + __le32 max_out_time; /* max usec to be away from associated (service) + * channel */ + __le32 suspend_time; /* pause scan this long (in "extended beacon + * format") when returning to service chnl: + * 3945; 31:24 # beacons, 19:0 additional usec, + * 4965; 31:22 # beacons, 21:0 additional usec. + */ + __le32 flags; /* RXON_FLG_* */ + __le32 filter_flags; /* RXON_FILTER_* */ + + /* For active scans (set to all-0s for passive scans). + * Does not include payload. Must specify Tx rate; no rate scaling. */ + struct iwl4965_tx_cmd tx_cmd; + + /* For directed active scans (set to all-0s otherwise) */ + struct iwl4965_ssid_ie direct_scan[PROBE_OPTION_MAX]; + + /* + * Probe request frame, followed by channel list. + * + * Size of probe request frame is specified by byte count in tx_cmd. + * Channel list follows immediately after probe request frame. + * Number of channels in list is specified by channel_count. + * Each channel in list is of type: + * + * struct iwl4965_scan_channel channels[0]; + * + * NOTE: Only one band of channels can be scanned per pass. You + * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait + * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION) + * before requesting another scan. + */ + u8 data[0]; +} __attribute__ ((packed)); + +/* Can abort will notify by complete notification with abort status. */ +#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +/* complete notification statuses */ +#define ABORT_STATUS 0x2 + +/* + * REPLY_SCAN_CMD = 0x80 (response) + */ +struct iwl4965_scanreq_notification { + __le32 status; /* 1: okay, 2: cannot fulfill request */ +} __attribute__ ((packed)); + +/* + * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command) + */ +struct iwl4965_scanstart_notification { + __le32 tsf_low; + __le32 tsf_high; + __le32 beacon_timer; + u8 channel; + u8 band; + u8 reserved[2]; + __le32 status; +} __attribute__ ((packed)); + +#define SCAN_OWNER_STATUS 0x1; +#define MEASURE_OWNER_STATUS 0x2; + +#define NUMBER_OF_STATISTICS 1 /* first __le32 is good CRC */ +/* + * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command) + */ +struct iwl4965_scanresults_notification { + u8 channel; + u8 band; + u8 reserved[2]; + __le32 tsf_low; + __le32 tsf_high; + __le32 statistics[NUMBER_OF_STATISTICS]; +} __attribute__ ((packed)); + +/* + * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command) + */ +struct iwl4965_scancomplete_notification { + u8 scanned_channels; + u8 status; + u8 reserved; + u8 last_channel; + __le32 tsf_low; + __le32 tsf_high; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (9) + * IBSS/AP Commands and Notifications: + * + *****************************************************************************/ + +/* + * BEACON_NOTIFICATION = 0x90 (notification only, not a command) + */ +struct iwl4965_beacon_notif { + struct iwl4965_tx_resp beacon_notify_hdr; + __le32 low_tsf; + __le32 high_tsf; + __le32 ibss_mgr_status; +} __attribute__ ((packed)); + +/* + * REPLY_TX_BEACON = 0x91 (command, has simple generic response) + */ +struct iwl4965_tx_beacon_cmd { + struct iwl4965_tx_cmd tx; + __le16 tim_idx; + u8 tim_size; + u8 reserved1; + struct ieee80211_hdr frame[0]; /* beacon frame */ +} __attribute__ ((packed)); + +/****************************************************************************** + * (10) + * Statistics Commands and Notifications: + * + *****************************************************************************/ + +#define IWL_TEMP_CONVERT 260 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/* Used for passing to driver number of successes and failures per rate */ +struct rate_histogram { + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } success; + union { + __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS]; + __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS]; + __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS]; + } failed; +} __attribute__ ((packed)); + +/* statistics command response */ + +struct statistics_rx_phy { + __le32 ina_cnt; + __le32 fina_cnt; + __le32 plcp_err; + __le32 crc32_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 false_alarm_cnt; + __le32 fina_sync_err_cnt; + __le32 sfd_timeout; + __le32 fina_timeout; + __le32 unresponded_rts; + __le32 rxe_frame_limit_overrun; + __le32 sent_ack_cnt; + __le32 sent_cts_cnt; + __le32 sent_ba_rsp_cnt; + __le32 dsp_self_kill; + __le32 mh_format_err; + __le32 re_acq_main_rssi_sum; + __le32 reserved3; +} __attribute__ ((packed)); + +struct statistics_rx_ht_phy { + __le32 plcp_err; + __le32 overrun_err; + __le32 early_overrun_err; + __le32 crc32_good; + __le32 crc32_err; + __le32 mh_format_err; + __le32 agg_crc32_good; + __le32 agg_mpdu_cnt; + __le32 agg_cnt; + __le32 reserved2; +} __attribute__ ((packed)); + +struct statistics_rx_non_phy { + __le32 bogus_cts; /* CTS received when not expecting CTS */ + __le32 bogus_ack; /* ACK received when not expecting ACK */ + __le32 non_bssid_frames; /* number of frames with BSSID that + * doesn't belong to the STA BSSID */ + __le32 filtered_frames; /* count frames that were dumped in the + * filtering process */ + __le32 non_channel_beacons; /* beacons with our bss id but not on + * our serving channel */ + __le32 channel_beacons; /* beacons with our bss id and in our + * serving channel */ + __le32 num_missed_bcon; /* number of missed beacons */ + __le32 adc_rx_saturation_time; /* count in 0.8us units the time the + * ADC was in saturation */ + __le32 ina_detection_search_time;/* total time (in 0.8us) searched + * for INA */ + __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */ + __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */ + __le32 interference_data_flag; /* flag for interference data + * availability. 1 when data is + * available. */ + __le32 channel_load; /* counts RX Enable time in uSec */ + __le32 dsp_false_alarms; /* DSP false alarm (both OFDM + * and CCK) counter */ + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 beacon_rssi_c; + __le32 beacon_energy_a; + __le32 beacon_energy_b; + __le32 beacon_energy_c; +} __attribute__ ((packed)); + +struct statistics_rx { + struct statistics_rx_phy ofdm; + struct statistics_rx_phy cck; + struct statistics_rx_non_phy general; + struct statistics_rx_ht_phy ofdm_ht; +} __attribute__ ((packed)); + +struct statistics_tx_non_phy_agg { + __le32 ba_timeout; + __le32 ba_reschedule_frames; + __le32 scd_query_agg_frame_cnt; + __le32 scd_query_no_agg; + __le32 scd_query_agg; + __le32 scd_query_mismatch; + __le32 frame_not_ready; + __le32 underrun; + __le32 bt_prio_kill; + __le32 rx_ba_rsp_cnt; + __le32 reserved2; + __le32 reserved3; +} __attribute__ ((packed)); + +struct statistics_tx { + __le32 preamble_cnt; + __le32 rx_detected_cnt; + __le32 bt_prio_defer_cnt; + __le32 bt_prio_kill_cnt; + __le32 few_bytes_cnt; + __le32 cts_timeout; + __le32 ack_timeout; + __le32 expected_ack_cnt; + __le32 actual_ack_cnt; + __le32 dump_msdu_cnt; + __le32 burst_abort_next_frame_mismatch_cnt; + __le32 burst_abort_missing_next_frame_cnt; + __le32 cts_timeout_collision; + __le32 ack_or_ba_timeout_collision; + struct statistics_tx_non_phy_agg agg; +} __attribute__ ((packed)); + +struct statistics_dbg { + __le32 burst_check; + __le32 burst_count; + __le32 reserved[4]; +} __attribute__ ((packed)); + +struct statistics_div { + __le32 tx_on_a; + __le32 tx_on_b; + __le32 exec_time; + __le32 probe_time; + __le32 reserved1; + __le32 reserved2; +} __attribute__ ((packed)); + +struct statistics_general { + __le32 temperature; + __le32 temperature_m; + struct statistics_dbg dbg; + __le32 sleep_time; + __le32 slots_out; + __le32 slots_idle; + __le32 ttl_timestamp; + struct statistics_div div; + __le32 rx_enable_counter; + __le32 reserved1; + __le32 reserved2; + __le32 reserved3; +} __attribute__ ((packed)); + +/* + * REPLY_STATISTICS_CMD = 0x9c, + * 3945 and 4965 identical. + * + * This command triggers an immediate response containing uCode statistics. + * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below. + * + * If the CLEAR_STATS configuration flag is set, uCode will clear its + * internal copy of the statistics (counters) after issuing the response. + * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below). + * + * If the DISABLE_NOTIF configuration flag is set, uCode will not issue + * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag + * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. + */ +#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +struct iwl4965_statistics_cmd { + __le32 configuration_flags; /* IWL_STATS_CONF_* */ +} __attribute__ ((packed)); + +/* + * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command) + * + * By default, uCode issues this notification after receiving a beacon + * while associated. To disable this behavior, set DISABLE_NOTIF flag in the + * REPLY_STATISTICS_CMD 0x9c, above. + * + * Statistics counters continue to increment beacon after beacon, but are + * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD + * 0x9c with CLEAR_STATS bit set (see above). + * + * uCode also issues this notification during scans. uCode clears statistics + * appropriately so that each notification contains statistics for only the + * one channel that has just been scanned. + */ +#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +struct iwl4965_notif_statistics { + __le32 flag; + struct statistics_rx rx; + struct statistics_tx tx; + struct statistics_general general; +} __attribute__ ((packed)); + + +/* + * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command) + */ +/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row, + * then this notification will be sent. */ +#define CONSECUTIVE_MISSED_BCONS_TH 20 + +struct iwl4965_missed_beacon_notif { + __le32 consequtive_missed_beacons; + __le32 total_missed_becons; + __le32 num_expected_beacons; + __le32 num_recvd_beacons; +} __attribute__ ((packed)); + + +/****************************************************************************** + * (11) + * Rx Calibration Commands: + * + * With the uCode used for open source drivers, most Tx calibration (except + * for Tx Power) and most Rx calibration is done by uCode during the + * "initialize" phase of uCode boot. Driver must calibrate only: + * + * 1) Tx power (depends on temperature), described elsewhere + * 2) Receiver gain balance (optimize MIMO, and detect disconnected antennas) + * 3) Receiver sensitivity (to optimize signal detection) + * + *****************************************************************************/ + +/** + * SENSITIVITY_CMD = 0xa8 (command, has simple generic response) + * + * This command sets up the Rx signal detector for a sensitivity level that + * is high enough to lock onto all signals within the associated network, + * but low enough to ignore signals that are below a certain threshold, so as + * not to have too many "false alarms". False alarms are signals that the + * Rx DSP tries to lock onto, but then discards after determining that they + * are noise. + * + * The optimum number of false alarms is between 5 and 50 per 200 TUs + * (200 * 1024 uSecs, i.e. 204.8 milliseconds) of actual Rx time (i.e. + * time listening, not transmitting). Driver must adjust sensitivity so that + * the ratio of actual false alarms to actual Rx time falls within this range. + * + * While associated, uCode delivers STATISTICS_NOTIFICATIONs after each + * received beacon. These provide information to the driver to analyze the + * sensitivity. Don't analyze statistics that come in from scanning, or any + * other non-associated-network source. Pertinent statistics include: + * + * From "general" statistics (struct statistics_rx_non_phy): + * + * (beacon_energy_[abc] & 0x0FF00) >> 8 (unsigned, higher value is lower level) + * Measure of energy of desired signal. Used for establishing a level + * below which the device does not detect signals. + * + * (beacon_silence_rssi_[abc] & 0x0FF00) >> 8 (unsigned, units in dB) + * Measure of background noise in silent period after beacon. + * + * channel_load + * uSecs of actual Rx time during beacon period (varies according to + * how much time was spent transmitting). + * + * From "cck" and "ofdm" statistics (struct statistics_rx_phy), separately: + * + * false_alarm_cnt + * Signal locks abandoned early (before phy-level header). + * + * plcp_err + * Signal locks abandoned late (during phy-level header). + * + * NOTE: Both false_alarm_cnt and plcp_err increment monotonically from + * beacon to beacon, i.e. each value is an accumulation of all errors + * before and including the latest beacon. Values will wrap around to 0 + * after counting up to 2^32 - 1. Driver must differentiate vs. + * previous beacon's values to determine # false alarms in the current + * beacon period. + * + * Total number of false alarms = false_alarms + plcp_errs + * + * For OFDM, adjust the following table entries in struct iwl_sensitivity_cmd + * (notice that the start points for OFDM are at or close to settings for + * maximum sensitivity): + * + * START / MIN / MAX + * HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX 90 / 85 / 120 + * HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX 170 / 170 / 210 + * HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX 105 / 105 / 140 + * HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX 220 / 220 / 270 + * + * If actual rate of OFDM false alarms (+ plcp_errors) is too high + * (greater than 50 for each 204.8 msecs listening), reduce sensitivity + * by *adding* 1 to all 4 of the table entries above, up to the max for + * each entry. Conversely, if false alarm rate is too low (less than 5 + * for each 204.8 msecs listening), *subtract* 1 from each entry to + * increase sensitivity. + * + * For CCK sensitivity, keep track of the following: + * + * 1). 20-beacon history of maximum background noise, indicated by + * (beacon_silence_rssi_[abc] & 0x0FF00), units in dB, across the + * 3 receivers. For any given beacon, the "silence reference" is + * the maximum of last 60 samples (20 beacons * 3 receivers). + * + * 2). 10-beacon history of strongest signal level, as indicated + * by (beacon_energy_[abc] & 0x0FF00) >> 8, across the 3 receivers, + * i.e. the strength of the signal through the best receiver at the + * moment. These measurements are "upside down", with lower values + * for stronger signals, so max energy will be *minimum* value. + * + * Then for any given beacon, the driver must determine the *weakest* + * of the strongest signals; this is the minimum level that needs to be + * successfully detected, when using the best receiver at the moment. + * "Max cck energy" is the maximum (higher value means lower energy!) + * of the last 10 minima. Once this is determined, driver must add + * a little margin by adding "6" to it. + * + * 3). Number of consecutive beacon periods with too few false alarms. + * Reset this to 0 at the first beacon period that falls within the + * "good" range (5 to 50 false alarms per 204.8 milliseconds rx). + * + * Then, adjust the following CCK table entries in struct iwl_sensitivity_cmd + * (notice that the start points for CCK are at maximum sensitivity): + * + * START / MIN / MAX + * HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX 125 / 125 / 200 + * HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX 200 / 200 / 400 + * HD_MIN_ENERGY_CCK_DET_INDEX 100 / 0 / 100 + * + * If actual rate of CCK false alarms (+ plcp_errors) is too high + * (greater than 50 for each 204.8 msecs listening), method for reducing + * sensitivity is: + * + * 1) *Add* 3 to value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX, + * up to max 400. + * + * 2) If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is < 160, + * sensitivity has been reduced a significant amount; bring it up to + * a moderate 161. Otherwise, *add* 3, up to max 200. + * + * 3) a) If current value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX is > 160, + * sensitivity has been reduced only a moderate or small amount; + * *subtract* 2 from value in HD_MIN_ENERGY_CCK_DET_INDEX, + * down to min 0. Otherwise (if gain has been significantly reduced), + * don't change the HD_MIN_ENERGY_CCK_DET_INDEX value. + * + * b) Save a snapshot of the "silence reference". + * + * If actual rate of CCK false alarms (+ plcp_errors) is too low + * (less than 5 for each 204.8 msecs listening), method for increasing + * sensitivity is used only if: + * + * 1a) Previous beacon did not have too many false alarms + * 1b) AND difference between previous "silence reference" and current + * "silence reference" (prev - current) is 2 or more, + * OR 2) 100 or more consecutive beacon periods have had rate of + * less than 5 false alarms per 204.8 milliseconds rx time. + * + * Method for increasing sensitivity: + * + * 1) *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX, + * down to min 125. + * + * 2) *Subtract* 3 from value in HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX, + * down to min 200. + * + * 3) *Add* 2 to value in HD_MIN_ENERGY_CCK_DET_INDEX, up to max 100. + * + * If actual rate of CCK false alarms (+ plcp_errors) is within good range + * (between 5 and 50 for each 204.8 msecs listening): + * + * 1) Save a snapshot of the silence reference. + * + * 2) If previous beacon had too many CCK false alarms (+ plcp_errors), + * give some extra margin to energy threshold by *subtracting* 8 + * from value in HD_MIN_ENERGY_CCK_DET_INDEX. + * + * For all cases (too few, too many, good range), make sure that the CCK + * detection threshold (energy) is below the energy level for robust + * detection over the past 10 beacon periods, the "Max cck energy". + * Lower values mean higher energy; this means making sure that the value + * in HD_MIN_ENERGY_CCK_DET_INDEX is at or *above* "Max cck energy". + * + * Driver should set the following entries to fixed values: + * + * HD_MIN_ENERGY_OFDM_DET_INDEX 100 + * HD_BARKER_CORR_TH_ADD_MIN_INDEX 190 + * HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX 390 + * HD_OFDM_ENERGY_TH_IN_INDEX 62 + */ + +/* + * Table entries in SENSITIVITY_CMD (struct iwl4965_sensitivity_cmd) + */ +#define HD_TABLE_SIZE (11) /* number of entries */ +#define HD_MIN_ENERGY_CCK_DET_INDEX (0) /* table indexes */ +#define HD_MIN_ENERGY_OFDM_DET_INDEX (1) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2) +#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5) +#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6) +#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7) +#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8) +#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) +#define HD_OFDM_ENERGY_TH_IN_INDEX (10) + +/* Control field in struct iwl4965_sensitivity_cmd */ +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) + +/** + * struct iwl4965_sensitivity_cmd + * @control: (1) updates working table, (0) updates default table + * @table: energy threshold values, use HD_* as index into table + * + * Always use "1" in "control" to update uCode's working table and DSP. + */ +struct iwl4965_sensitivity_cmd { + __le16 control; /* always use "1" */ + __le16 table[HD_TABLE_SIZE]; /* use HD_* as index */ +} __attribute__ ((packed)); + + +/** + * REPLY_PHY_CALIBRATION_CMD = 0xb0 (command, has simple generic response) + * + * This command sets the relative gains of 4965's 3 radio receiver chains. + * + * After the first association, driver should accumulate signal and noise + * statistics from the STATISTICS_NOTIFICATIONs that follow the first 20 + * beacons from the associated network (don't collect statistics that come + * in from scanning, or any other non-network source). + * + * DISCONNECTED ANTENNA: + * + * Driver should determine which antennas are actually connected, by comparing + * average beacon signal levels for the 3 Rx chains. Accumulate (add) the + * following values over 20 beacons, one accumulator for each of the chains + * a/b/c, from struct statistics_rx_non_phy: + * + * beacon_rssi_[abc] & 0x0FF (unsigned, units in dB) + * + * Find the strongest signal from among a/b/c. Compare the other two to the + * strongest. If any signal is more than 15 dB (times 20, unless you + * divide the accumulated values by 20) below the strongest, the driver + * considers that antenna to be disconnected, and should not try to use that + * antenna/chain for Rx or Tx. If both A and B seem to be disconnected, + * driver should declare the stronger one as connected, and attempt to use it + * (A and B are the only 2 Tx chains!). + * + * + * RX BALANCE: + * + * Driver should balance the 3 receivers (but just the ones that are connected + * to antennas, see above) for gain, by comparing the average signal levels + * detected during the silence after each beacon (background noise). + * Accumulate (add) the following values over 20 beacons, one accumulator for + * each of the chains a/b/c, from struct statistics_rx_non_phy: + * + * beacon_silence_rssi_[abc] & 0x0FF (unsigned, units in dB) + * + * Find the weakest background noise level from among a/b/c. This Rx chain + * will be the reference, with 0 gain adjustment. Attenuate other channels by + * finding noise difference: + * + * (accum_noise[i] - accum_noise[reference]) / 30 + * + * The "30" adjusts the dB in the 20 accumulated samples to units of 1.5 dB. + * For use in diff_gain_[abc] fields of struct iwl_calibration_cmd, the + * driver should limit the difference results to a range of 0-3 (0-4.5 dB), + * and set bit 2 to indicate "reduce gain". The value for the reference + * (weakest) chain should be "0". + * + * diff_gain_[abc] bit fields: + * 2: (1) reduce gain, (0) increase gain + * 1-0: amount of gain, units of 1.5 dB + */ + +/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ +#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) + +struct iwl4965_calibration_cmd { + u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ + u8 flags; /* not used */ + __le16 reserved; + s8 diff_gain_a; /* see above */ + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +/****************************************************************************** + * (12) + * Miscellaneous Commands: + * + *****************************************************************************/ + +/* + * LEDs Command & Response + * REPLY_LEDS_CMD = 0x48 (command, has simple generic response) + * + * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field), + * this command turns it on or off, or sets up a periodic blinking cycle. + */ +struct iwl4965_led_cmd { + __le32 interval; /* "interval" in uSec */ + u8 id; /* 1: Activity, 2: Link, 3: Tech */ + u8 off; /* # intervals off while blinking; + * "0", with >0 "on" value, turns LED on */ + u8 on; /* # intervals on while blinking; + * "0", regardless of "off", turns LED off */ + u8 reserved; +} __attribute__ ((packed)); + +/****************************************************************************** + * (13) + * Union of all expected notifications/responses: + * + *****************************************************************************/ + +struct iwl4965_rx_packet { + __le32 len; + struct iwl4965_cmd_header hdr; + union { + struct iwl4965_alive_resp alive_frame; + struct iwl4965_rx_frame rx_frame; + struct iwl4965_tx_resp tx_resp; + struct iwl4965_spectrum_notification spectrum_notif; + struct iwl4965_csa_notification csa_notif; + struct iwl4965_error_resp err_resp; + struct iwl4965_card_state_notif card_state_notif; + struct iwl4965_beacon_notif beacon_status; + struct iwl4965_add_sta_resp add_sta; + struct iwl4965_sleep_notification sleep_notif; + struct iwl4965_spectrum_resp spectrum; + struct iwl4965_notif_statistics stats; + struct iwl4965_compressed_ba_resp compressed_ba; + struct iwl4965_missed_beacon_notif missed_beacon; + __le32 status; + u8 raw[0]; + } u; +} __attribute__ ((packed)); + +#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) + +#endif /* __iwl4965_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-debug.h b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h new file mode 100644 index 000000000000..36696bbf170c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-debug.h @@ -0,0 +1,152 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * 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 <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl4965_debug_h__ +#define __iwl4965_debug_h__ + +#ifdef CONFIG_IWL4965_DEBUG +extern u32 iwl4965_debug_level; +#define IWL_DEBUG(level, fmt, args...) \ +do { if (iwl4965_debug_level & (level)) \ + printk(KERN_ERR DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) + +#define IWL_DEBUG_LIMIT(level, fmt, args...) \ +do { if ((iwl4965_debug_level & (level)) && net_ratelimit()) \ + printk(KERN_ERR DRV_NAME": %c %s " fmt, \ + in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0) +#else +static inline void IWL_DEBUG(int level, const char *fmt, ...) +{ +} +static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...) +{ +} +#endif /* CONFIG_IWL4965_DEBUG */ + +/* + * To use the debug system; + * + * If you are defining a new debug classification, simply add it to the #define + * list here in the form of: + * + * #define IWL_DL_xxxx VALUE + * + * shifting value to the left one bit from the previous entry. xxxx should be + * the name of the classification (for example, WEP) + * + * You then need to either add a IWL_xxxx_DEBUG() macro definition for your + * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want + * to send output to that classification. + * + * To add your debug level to the list of levels seen when you perform + * + * % cat /proc/net/iwl/debug_level + * + * you simply need to add your entry to the iwl4965_debug_levels array. + * + * If you do not see debug_level in /proc/net/iwl then you do not have + * CONFIG_IWL4965_DEBUG defined in your kernel configuration + * + */ + +#define IWL_DL_INFO (1 << 0) +#define IWL_DL_MAC80211 (1 << 1) +#define IWL_DL_HOST_COMMAND (1 << 2) +#define IWL_DL_STATE (1 << 3) + +#define IWL_DL_RADIO (1 << 7) +#define IWL_DL_POWER (1 << 8) +#define IWL_DL_TEMP (1 << 9) + +#define IWL_DL_NOTIF (1 << 10) +#define IWL_DL_SCAN (1 << 11) +#define IWL_DL_ASSOC (1 << 12) +#define IWL_DL_DROP (1 << 13) + +#define IWL_DL_TXPOWER (1 << 14) + +#define IWL_DL_AP (1 << 15) + +#define IWL_DL_FW (1 << 16) +#define IWL_DL_RF_KILL (1 << 17) +#define IWL_DL_FW_ERRORS (1 << 18) + +#define IWL_DL_LED (1 << 19) + +#define IWL_DL_RATE (1 << 20) + +#define IWL_DL_CALIB (1 << 21) +#define IWL_DL_WEP (1 << 22) +#define IWL_DL_TX (1 << 23) +#define IWL_DL_RX (1 << 24) +#define IWL_DL_ISR (1 << 25) +#define IWL_DL_HT (1 << 26) +#define IWL_DL_IO (1 << 27) +#define IWL_DL_11H (1 << 28) + +#define IWL_DL_STATS (1 << 29) +#define IWL_DL_TX_REPLY (1 << 30) +#define IWL_DL_QOS (1 << 31) + +#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a) +#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a) +#define IWL_DEBUG_INFO(f, a...) IWL_DEBUG(IWL_DL_INFO, f, ## a) + +#define IWL_DEBUG_MAC80211(f, a...) IWL_DEBUG(IWL_DL_MAC80211, f, ## a) +#define IWL_DEBUG_TEMP(f, a...) IWL_DEBUG(IWL_DL_TEMP, f, ## a) +#define IWL_DEBUG_SCAN(f, a...) IWL_DEBUG(IWL_DL_SCAN, f, ## a) +#define IWL_DEBUG_RX(f, a...) IWL_DEBUG(IWL_DL_RX, f, ## a) +#define IWL_DEBUG_TX(f, a...) IWL_DEBUG(IWL_DL_TX, f, ## a) +#define IWL_DEBUG_ISR(f, a...) IWL_DEBUG(IWL_DL_ISR, f, ## a) +#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a) +#define IWL_DEBUG_WEP(f, a...) IWL_DEBUG(IWL_DL_WEP, f, ## a) +#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a) +#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a) +#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a) +#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a) +#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a) +#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a) +#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a) +#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a) +#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a) +#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a) +#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a) +#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a) +#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) +#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \ + IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a) +#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a) +#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a) +#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a) +#define IWL_DEBUG_QOS(f, a...) IWL_DEBUG(IWL_DL_QOS, f, ## a) +#define IWL_DEBUG_RADIO(f, a...) IWL_DEBUG(IWL_DL_RADIO, f, ## a) +#define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a) +#define IWL_DEBUG_11H(f, a...) IWL_DEBUG(IWL_DL_11H, f, ## a) + +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index 99a19ef4c743..ff71c09ab1a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -8,7 +8,7 @@ * Copyright(c) 2005 - 2007 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 Geeral Public License as + * 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 @@ -60,48 +60,618 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +/* + * Please use this file (iwl-4965-hw.h) only for hardware-related definitions. + * Use iwl-4965-commands.h for uCode API definitions. + * Use iwl-4965.h for driver implementation definitions. + */ #ifndef __iwl_4965_hw_h__ #define __iwl_4965_hw_h__ -#define IWL_RX_BUF_SIZE (4 * 1024) -#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE +/* + * uCode queue management definitions ... + * Queue #4 is the command queue for 3945 and 4965; map it to Tx FIFO chnl 4. + * The first queue used for block-ack aggregation is #7 (4965 only). + * All block-ack aggregation queues should map to Tx DMA/FIFO channel 7. + */ +#define IWL_CMD_QUEUE_NUM 4 +#define IWL_CMD_FIFO_NUM 4 +#define IWL_BACK_QUEUE_FIRST_ID 7 + +/* Tx rates */ +#define IWL_CCK_RATES 4 +#define IWL_OFDM_RATES 8 +#define IWL_HT_RATES 16 +#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) + +/* Time constants */ +#define SHORT_SLOT_TIME 9 +#define LONG_SLOT_TIME 20 + +/* RSSI to dBm */ +#define IWL_RSSI_OFFSET 44 + +/* + * EEPROM related constants, enums, and structures. + */ + +/* + * EEPROM access time values: + * + * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG, + * then clearing (with subsequent read/modify/write) CSR_EEPROM_REG bit + * CSR_EEPROM_REG_BIT_CMD (0x2). + * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). + * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. + * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. + */ +#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ +#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ + +/* + * Regulatory channel usage flags in EEPROM struct iwl4965_eeprom_channel.flags. + * + * IBSS and/or AP operation is allowed *only* on those channels with + * (VALID && IBSS && ACTIVE && !RADAR). This restriction is in place because + * RADAR detection is not supported by the 4965 driver, but is a + * requirement for establishing a new network for legal operation on channels + * requiring RADAR detection or restricting ACTIVE scanning. + * + * NOTE: "WIDE" flag does not indicate anything about "FAT" 40 MHz channels. + * It only indicates that 20 MHz channel use is supported; FAT channel + * usage is indicated by a separate set of regulatory flags for each + * FAT channel pair. + * + * NOTE: Using a channel inappropriately will result in a uCode error! + */ +enum { + EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ + EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ + /* Bit 2 Reserved */ + EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ + EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ + EEPROM_CHANNEL_WIDE = (1 << 5), /* 20 MHz channel okay */ + EEPROM_CHANNEL_NARROW = (1 << 6), /* 10 MHz channel (not used) */ + EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ +}; + +/* SKU Capabilities */ +#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) +#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) + +/* *regulatory* channel data format in eeprom, one for each channel. + * There are separate entries for FAT (40 MHz) vs. normal (20 MHz) channels. */ +struct iwl4965_eeprom_channel { + u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */ + s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ +} __attribute__ ((packed)); + +/* 4965 has two radio transmitters (and 3 radio receivers) */ +#define EEPROM_TX_POWER_TX_CHAINS (2) + +/* 4965 has room for up to 8 sets of txpower calibration data */ +#define EEPROM_TX_POWER_BANDS (8) + +/* 4965 factory calibration measures txpower gain settings for + * each of 3 target output levels */ +#define EEPROM_TX_POWER_MEASUREMENTS (3) + +/* 4965 driver does not work with txpower calibration version < 5. + * Look for this in calib_version member of struct iwl4965_eeprom. */ +#define EEPROM_TX_POWER_VERSION_NEW (5) + + +/* + * 4965 factory calibration data for one txpower level, on one channel, + * measured on one of the 2 tx chains (radio transmitter and associated + * antenna). EEPROM contains: + * + * 1) Temperature (degrees Celsius) of device when measurement was made. + * + * 2) Gain table index used to achieve the target measurement power. + * This refers to the "well-known" gain tables (see iwl-4965-hw.h). + * + * 3) Actual measured output power, in half-dBm ("34" = 17 dBm). + * + * 4) RF power amplifier detector level measurement (not used). + */ +struct iwl4965_eeprom_calib_measure { + u8 temperature; /* Device temperature (Celsius) */ + u8 gain_idx; /* Index into gain table */ + u8 actual_pow; /* Measured RF output power, half-dBm */ + s8 pa_det; /* Power amp detector level (not used) */ +} __attribute__ ((packed)); + + +/* + * 4965 measurement set for one channel. EEPROM contains: + * + * 1) Channel number measured + * + * 2) Measurements for each of 3 power levels for each of 2 radio transmitters + * (a.k.a. "tx chains") (6 measurements altogether) + */ +struct iwl4965_eeprom_calib_ch_info { + u8 ch_num; + struct iwl4965_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] + [EEPROM_TX_POWER_MEASUREMENTS]; +} __attribute__ ((packed)); + +/* + * 4965 txpower subband info. + * + * For each frequency subband, EEPROM contains the following: + * + * 1) First and last channels within range of the subband. "0" values + * indicate that this sample set is not being used. + * + * 2) Sample measurement sets for 2 channels close to the range endpoints. + */ +struct iwl4965_eeprom_calib_subband_info { + u8 ch_from; /* channel number of lowest channel in subband */ + u8 ch_to; /* channel number of highest channel in subband */ + struct iwl4965_eeprom_calib_ch_info ch1; + struct iwl4965_eeprom_calib_ch_info ch2; +} __attribute__ ((packed)); + + +/* + * 4965 txpower calibration info. EEPROM contains: + * + * 1) Factory-measured saturation power levels (maximum levels at which + * tx power amplifier can output a signal without too much distortion). + * There is one level for 2.4 GHz band and one for 5 GHz band. These + * values apply to all channels within each of the bands. + * + * 2) Factory-measured power supply voltage level. This is assumed to be + * constant (i.e. same value applies to all channels/bands) while the + * factory measurements are being made. + * + * 3) Up to 8 sets of factory-measured txpower calibration values. + * These are for different frequency ranges, since txpower gain + * characteristics of the analog radio circuitry vary with frequency. + * + * Not all sets need to be filled with data; + * struct iwl4965_eeprom_calib_subband_info contains range of channels + * (0 if unused) for each set of data. + */ +struct iwl4965_eeprom_calib_info { + u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */ + u8 saturation_power52; /* half-dBm */ + s16 voltage; /* signed */ + struct iwl4965_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; +} __attribute__ ((packed)); + + +/* + * 4965 EEPROM map + */ +struct iwl4965_eeprom { + u8 reserved0[16]; +#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ + u16 device_id; /* abs.ofs: 16 */ + u8 reserved1[2]; +#define EEPROM_PMC (2*0x0A) /* 2 bytes */ + u16 pmc; /* abs.ofs: 20 */ + u8 reserved2[20]; +#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ + u8 mac_address[6]; /* abs.ofs: 42 */ + u8 reserved3[58]; +#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ + u16 board_revision; /* abs.ofs: 106 */ + u8 reserved4[11]; +#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ + u8 board_pba_number[9]; /* abs.ofs: 119 */ + u8 reserved5[8]; +#define EEPROM_VERSION (2*0x44) /* 2 bytes */ + u16 version; /* abs.ofs: 136 */ +#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ + u8 sku_cap; /* abs.ofs: 138 */ +#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ + u8 leds_mode; /* abs.ofs: 139 */ +#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ + u16 oem_mode; +#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ + u16 wowlan_mode; /* abs.ofs: 142 */ +#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ + u16 leds_time_interval; /* abs.ofs: 144 */ +#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ + u8 leds_off_time; /* abs.ofs: 146 */ +#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ + u8 leds_on_time; /* abs.ofs: 147 */ +#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ + u8 almgor_m_version; /* abs.ofs: 148 */ +#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ + u8 antenna_switch_type; /* abs.ofs: 149 */ + u8 reserved6[8]; +#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ + u16 board_revision_4965; /* abs.ofs: 158 */ + u8 reserved7[13]; +#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ + u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ + u8 reserved8[10]; +#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ + u8 sku_id[4]; /* abs.ofs: 192 */ + +/* + * Per-channel regulatory data. + * + * Each channel that *might* be supported by 3945 or 4965 has a fixed location + * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory + * txpower (MSB). + * + * Entries immediately below are for 20 MHz channel width. FAT (40 MHz) + * channels (only for 4965, not supported by 3945) appear later in the EEPROM. + * + * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 + */ +#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ + u16 band_1_count; /* abs.ofs: 196 */ +#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ + struct iwl4965_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ + +/* + * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196, + * 5.0 GHz channels 7, 8, 11, 12, 16 + * (4915-5080MHz) (none of these is ever supported) + */ +#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ + u16 band_2_count; /* abs.ofs: 226 */ +#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ + struct iwl4965_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ + +/* + * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 + * (5170-5320MHz) + */ +#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ + u16 band_3_count; /* abs.ofs: 254 */ +#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ + struct iwl4965_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ + +/* + * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 + * (5500-5700MHz) + */ +#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ + u16 band_4_count; /* abs.ofs: 280 */ +#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ + struct iwl4965_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ + +/* + * 5.7 GHz channels 145, 149, 153, 157, 161, 165 + * (5725-5825MHz) + */ +#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ + u16 band_5_count; /* abs.ofs: 304 */ +#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ + struct iwl4965_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ + + u8 reserved10[2]; + + +/* + * 2.4 GHz FAT channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11) + * + * The channel listed is the center of the lower 20 MHz half of the channel. + * The overall center frequency is actually 2 channels (10 MHz) above that, + * and the upper half of each FAT channel is centered 4 channels (20 MHz) away + * from the lower half; e.g. the upper half of FAT channel 1 is channel 5, + * and the overall FAT channel width centers on channel 3. + * + * NOTE: The RXON command uses 20 MHz channel numbers to specify the + * control channel to which to tune. RXON also specifies whether the + * control channel is the upper or lower half of a FAT channel. + * + * NOTE: 4965 does not support FAT channels on 2.4 GHz. + */ +#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ + struct iwl4965_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ + u8 reserved11[2]; + +/* + * 5.2 GHz FAT channels 36 (40), 44 (48), 52 (56), 60 (64), + * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161) + */ +#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ + struct iwl4965_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ + u8 reserved12[6]; + +/* + * 4965 driver requires txpower calibration format version 5 or greater. + * Driver does not work with txpower calibration version < 5. + * This value is simply a 16-bit number, no major/minor versions here. + */ +#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ + u16 calib_version; /* abs.ofs: 364 */ + u8 reserved13[2]; + u8 reserved14[96]; /* abs.ofs: 368 */ + +/* + * 4965 Txpower calibration data. + */ +#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ + struct iwl4965_eeprom_calib_info calib_info; /* abs.ofs: 464 */ + + u8 reserved16[140]; /* fill out to full 1024 byte block */ + + +} __attribute__ ((packed)); + +#define IWL_EEPROM_IMAGE_SIZE 1024 + +/* End of EEPROM */ + +#include "iwl-4965-commands.h" + +#define PCI_LINK_CTRL 0x0F0 +#define PCI_POWER_SOURCE 0x0C8 +#define PCI_REG_WUM8 0x0E8 +#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) + +/*=== CSR (control and status registers) ===*/ +#define CSR_BASE (0x000) + +#define CSR_SW_VER (CSR_BASE+0x000) +#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ +#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ +#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ +#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ +#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ +#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ +#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ +#define CSR_GP_CNTRL (CSR_BASE+0x024) + +/* + * Hardware revision info + * Bit fields: + * 31-8: Reserved + * 7-4: Type of device: 0x0 = 4965, 0xd = 3945 + * 3-2: Revision step: 0 = A, 1 = B, 2 = C, 3 = D + * 1-0: "Dash" value, as in A-1, etc. + * + * NOTE: Revision step affects calculation of CCK txpower for 4965. + */ +#define CSR_HW_REV (CSR_BASE+0x028) + +/* EEPROM reads */ +#define CSR_EEPROM_REG (CSR_BASE+0x02c) +#define CSR_EEPROM_GP (CSR_BASE+0x030) +#define CSR_GP_UCODE (CSR_BASE+0x044) +#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) +#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) +#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) +#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) +#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) + +/* + * Indicates hardware rev, to determine CCK backoff for txpower calculation. + * Bit fields: + * 3-2: 0 = A, 1 = B, 2 = C, 3 = D step + */ +#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) + +/* Hardware interface configuration bits */ +#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010) +#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) +#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) +#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) +#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) + +/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), + * acknowledged (reset) by host writing "1" to flagged bits. */ +#define CSR_INT_BIT_FH_RX (1 << 31) /* Rx DMA, cmd responses, FH_INT[17:16] */ +#define CSR_INT_BIT_HW_ERR (1 << 29) /* DMA hardware error FH_INT[31] */ +#define CSR_INT_BIT_DNLD (1 << 28) /* uCode Download */ +#define CSR_INT_BIT_FH_TX (1 << 27) /* Tx DMA FH_INT[1:0] */ +#define CSR_INT_BIT_MAC_CLK_ACTV (1 << 26) /* NIC controller's clock toggled on/off */ +#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */ +#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */ +#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */ +#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */ +#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */ +#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */ + +#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ + CSR_INT_BIT_HW_ERR | \ + CSR_INT_BIT_FH_TX | \ + CSR_INT_BIT_SW_ERR | \ + CSR_INT_BIT_RF_KILL | \ + CSR_INT_BIT_SW_RX | \ + CSR_INT_BIT_WAKEUP | \ + CSR_INT_BIT_ALIVE) + +/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ +#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ +#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */ +#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */ +#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */ +#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */ +#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */ + +#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ + CSR_FH_INT_BIT_RX_CHNL1 | \ + CSR_FH_INT_BIT_RX_CHNL0) + +#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \ + CSR_FH_INT_BIT_TX_CHNL0) + + +/* RESET */ +#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) +#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) +#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) +#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) +#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) + +/* GP (general purpose) CONTROL */ +#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) +#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) +#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) +#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) + +#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) + +#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) +#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) +#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) + + +/* EEPROM REG */ +#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) +#define CSR_EEPROM_REG_BIT_CMD (0x00000002) + +/* EEPROM GP */ +#define CSR_EEPROM_GP_VALID_MSK (0x00000006) +#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) +#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) + +/* UCODE DRV GP */ +#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) +#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) +#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) +#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) + +/* GPIO */ +#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) +#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) +#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER + +/* GI Chicken Bits */ +#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) +#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) + +/*=== HBUS (Host-side Bus) ===*/ +#define HBUS_BASE (0x400) + +/* + * Registers for accessing device's internal SRAM memory (e.g. SCD SRAM + * structures, error log, event log, verifying uCode load). + * First write to address register, then read from or write to data register + * to complete the job. Once the address register is set up, accesses to + * data registers auto-increment the address by one dword. + * Bit usage for address registers (read or write): + * 0-31: memory address within device + */ +#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) +#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) +#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) +#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) + +/* + * Registers for accessing device's internal peripheral registers + * (e.g. SCD, BSM, etc.). First write to address register, + * then read from or write to data register to complete the job. + * Bit usage for address registers (read or write): + * 0-15: register address (offset) within device + * 24-25: (# bytes - 1) to read or write (e.g. 3 for dword) + */ +#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) +#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) +#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) +#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) + +/* + * Per-Tx-queue write pointer (index, really!) (3945 and 4965). + * Driver sets this to indicate index to next TFD that driver will fill + * (1 past latest filled). + * Bit usage: + * 0-7: queue write index (0-255) + * 11-8: queue selector (0-15) + */ +#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) + +#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) + +#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) + +#define TFD_QUEUE_SIZE_MAX (256) + +#define IWL_NUM_SCAN_RATES (2) + +#define IWL_DEFAULT_TX_RETRY 15 + +#define RX_QUEUE_SIZE 256 +#define RX_QUEUE_MASK 255 +#define RX_QUEUE_SIZE_LOG 8 + +#define TFD_TX_CMD_SLOTS 256 +#define TFD_CMD_SLOTS 32 + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \ + sizeof(struct iwl4965_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +/* Size of one Rx buffer in host DRAM */ +#define IWL_RX_BUF_SIZE_4K (4 * 1024) +#define IWL_RX_BUF_SIZE_8K (8 * 1024) + +/* Sizes and addresses for instruction and data memory (SRAM) in + * 4965's embedded processor. Driver access is via HBUS_TARG_MEM_* regs. */ +#define RTC_INST_LOWER_BOUND (0x000000) #define KDR_RTC_INST_UPPER_BOUND (0x018000) + +#define RTC_DATA_LOWER_BOUND (0x800000) #define KDR_RTC_DATA_UPPER_BOUND (0x80A000) + #define KDR_RTC_INST_SIZE (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) #define KDR_RTC_DATA_SIZE (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) #define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE #define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE -static inline int iwl_hw_valid_rtc_data_addr(u32 addr) +/* Size of uCode instruction memory in bootstrap state machine */ +#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE + +static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) { return (addr >= RTC_DATA_LOWER_BOUND) && (addr < KDR_RTC_DATA_UPPER_BOUND); } -/********************* START TXPOWER *****************************************/ -enum { - HT_IE_EXT_CHANNEL_NONE = 0, - HT_IE_EXT_CHANNEL_ABOVE, - HT_IE_EXT_CHANNEL_INVALID, - HT_IE_EXT_CHANNEL_BELOW, - HT_IE_EXT_CHANNEL_MAX -}; - -enum { - CALIB_CH_GROUP_1 = 0, - CALIB_CH_GROUP_2 = 1, - CALIB_CH_GROUP_3 = 2, - CALIB_CH_GROUP_4 = 3, - CALIB_CH_GROUP_5 = 4, - CALIB_CH_GROUP_MAX -}; +/********************* START TEMPERATURE *************************************/ -/* Temperature calibration offset is 3% 0C in Kelvin */ +/** + * 4965 temperature calculation. + * + * The driver must calculate the device temperature before calculating + * a txpower setting (amplifier gain is temperature dependent). The + * calculation uses 4 measurements, 3 of which (R1, R2, R3) are calibration + * values used for the life of the driver, and one of which (R4) is the + * real-time temperature indicator. + * + * uCode provides all 4 values to the driver via the "initialize alive" + * notification (see struct iwl4965_init_alive_resp). After the runtime uCode + * image loads, uCode updates the R4 value via statistics notifications + * (see STATISTICS_NOTIFICATION), which occur after each received beacon + * when associated, or can be requested via REPLY_STATISTICS_CMD. + * + * NOTE: uCode provides the R4 value as a 23-bit signed value. Driver + * must sign-extend to 32 bits before applying formula below. + * + * Formula: + * + * degrees Kelvin = ((97 * 259 * (R4 - R2) / (R3 - R1)) / 100) + 8 + * + * NOTE: The basic formula is 259 * (R4-R2) / (R3-R1). The 97/100 is + * an additional correction, which should be centered around 0 degrees + * Celsius (273 degrees Kelvin). The 8 (3 percent of 273) compensates for + * centering the 97/100 correction around 0 degrees K. + * + * Add 273 to Kelvin value to find degrees Celsius, for comparing current + * temperature with factory-measured temperatures when calculating txpower + * settings. + */ #define TEMPERATURE_CALIB_KELVIN_OFFSET 8 #define TEMPERATURE_CALIB_A_VAL 259 +/* Limit range of calculated temperature to be between these Kelvin values */ #define IWL_TX_POWER_TEMPERATURE_MIN (263) #define IWL_TX_POWER_TEMPERATURE_MAX (410) @@ -109,228 +679,875 @@ enum { (((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \ ((t) > IWL_TX_POWER_TEMPERATURE_MAX)) -#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300) +/********************* END TEMPERATURE ***************************************/ -#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2) +/********************* START TXPOWER *****************************************/ -#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6) +/** + * 4965 txpower calculations rely on information from three sources: + * + * 1) EEPROM + * 2) "initialize" alive notification + * 3) statistics notifications + * + * EEPROM data consists of: + * + * 1) Regulatory information (max txpower and channel usage flags) is provided + * separately for each channel that can possibly supported by 4965. + * 40 MHz wide (.11n fat) channels are listed separately from 20 MHz + * (legacy) channels. + * + * See struct iwl4965_eeprom_channel for format, and struct iwl4965_eeprom + * for locations in EEPROM. + * + * 2) Factory txpower calibration information is provided separately for + * sub-bands of contiguous channels. 2.4GHz has just one sub-band, + * but 5 GHz has several sub-bands. + * + * In addition, per-band (2.4 and 5 Ghz) saturation txpowers are provided. + * + * See struct iwl4965_eeprom_calib_info (and the tree of structures + * contained within it) for format, and struct iwl4965_eeprom for + * locations in EEPROM. + * + * "Initialization alive" notification (see struct iwl4965_init_alive_resp) + * consists of: + * + * 1) Temperature calculation parameters. + * + * 2) Power supply voltage measurement. + * + * 3) Tx gain compensation to balance 2 transmitters for MIMO use. + * + * Statistics notifications deliver: + * + * 1) Current values for temperature param R4. + */ + +/** + * To calculate a txpower setting for a given desired target txpower, channel, + * modulation bit rate, and transmitter chain (4965 has 2 transmitters to + * support MIMO and transmit diversity), driver must do the following: + * + * 1) Compare desired txpower vs. (EEPROM) regulatory limit for this channel. + * Do not exceed regulatory limit; reduce target txpower if necessary. + * + * If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31), + * 2 transmitters will be used simultaneously; driver must reduce the + * regulatory limit by 3 dB (half-power) for each transmitter, so the + * combined total output of the 2 transmitters is within regulatory limits. + * + * + * 2) Compare target txpower vs. (EEPROM) saturation txpower *reduced by + * backoff for this bit rate*. Do not exceed (saturation - backoff[rate]); + * reduce target txpower if necessary. + * + * Backoff values below are in 1/2 dB units (equivalent to steps in + * txpower gain tables): + * + * OFDM 6 - 36 MBit: 10 steps (5 dB) + * OFDM 48 MBit: 15 steps (7.5 dB) + * OFDM 54 MBit: 17 steps (8.5 dB) + * OFDM 60 MBit: 20 steps (10 dB) + * CCK all rates: 10 steps (5 dB) + * + * Backoff values apply to saturation txpower on a per-transmitter basis; + * when using MIMO (2 transmitters), each transmitter uses the same + * saturation level provided in EEPROM, and the same backoff values; + * no reduction (such as with regulatory txpower limits) is required. + * + * Saturation and Backoff values apply equally to 20 Mhz (legacy) channel + * widths and 40 Mhz (.11n fat) channel widths; there is no separate + * factory measurement for fat channels. + * + * The result of this step is the final target txpower. The rest of + * the steps figure out the proper settings for the device to achieve + * that target txpower. + * + * + * 3) Determine (EEPROM) calibration subband for the target channel, by + * comparing against first and last channels in each subband + * (see struct iwl4965_eeprom_calib_subband_info). + * + * + * 4) Linearly interpolate (EEPROM) factory calibration measurement sets, + * referencing the 2 factory-measured (sample) channels within the subband. + * + * Interpolation is based on difference between target channel's frequency + * and the sample channels' frequencies. Since channel numbers are based + * on frequency (5 MHz between each channel number), this is equivalent + * to interpolating based on channel number differences. + * + * Note that the sample channels may or may not be the channels at the + * edges of the subband. The target channel may be "outside" of the + * span of the sampled channels. + * + * Driver may choose the pair (for 2 Tx chains) of measurements (see + * struct iwl4965_eeprom_calib_ch_info) for which the actual measured + * txpower comes closest to the desired txpower. Usually, though, + * the middle set of measurements is closest to the regulatory limits, + * and is therefore a good choice for all txpower calculations (this + * assumes that high accuracy is needed for maximizing legal txpower, + * while lower txpower configurations do not need as much accuracy). + * + * Driver should interpolate both members of the chosen measurement pair, + * i.e. for both Tx chains (radio transmitters), unless the driver knows + * that only one of the chains will be used (e.g. only one tx antenna + * connected, but this should be unusual). The rate scaling algorithm + * switches antennas to find best performance, so both Tx chains will + * be used (although only one at a time) even for non-MIMO transmissions. + * + * Driver should interpolate factory values for temperature, gain table + * index, and actual power. The power amplifier detector values are + * not used by the driver. + * + * Sanity check: If the target channel happens to be one of the sample + * channels, the results should agree with the sample channel's + * measurements! + * + * + * 5) Find difference between desired txpower and (interpolated) + * factory-measured txpower. Using (interpolated) factory gain table index + * (shown elsewhere) as a starting point, adjust this index lower to + * increase txpower, or higher to decrease txpower, until the target + * txpower is reached. Each step in the gain table is 1/2 dB. + * + * For example, if factory measured txpower is 16 dBm, and target txpower + * is 13 dBm, add 6 steps to the factory gain index to reduce txpower + * by 3 dB. + * + * + * 6) Find difference between current device temperature and (interpolated) + * factory-measured temperature for sub-band. Factory values are in + * degrees Celsius. To calculate current temperature, see comments for + * "4965 temperature calculation". + * + * If current temperature is higher than factory temperature, driver must + * increase gain (lower gain table index), and vice versa. + * + * Temperature affects gain differently for different channels: + * + * 2.4 GHz all channels: 3.5 degrees per half-dB step + * 5 GHz channels 34-43: 4.5 degrees per half-dB step + * 5 GHz channels >= 44: 4.0 degrees per half-dB step + * + * NOTE: Temperature can increase rapidly when transmitting, especially + * with heavy traffic at high txpowers. Driver should update + * temperature calculations often under these conditions to + * maintain strong txpower in the face of rising temperature. + * + * + * 7) Find difference between current power supply voltage indicator + * (from "initialize alive") and factory-measured power supply voltage + * indicator (EEPROM). + * + * If the current voltage is higher (indicator is lower) than factory + * voltage, gain should be reduced (gain table index increased) by: + * + * (eeprom - current) / 7 + * + * If the current voltage is lower (indicator is higher) than factory + * voltage, gain should be increased (gain table index decreased) by: + * + * 2 * (current - eeprom) / 7 + * + * If number of index steps in either direction turns out to be > 2, + * something is wrong ... just use 0. + * + * NOTE: Voltage compensation is independent of band/channel. + * + * NOTE: "Initialize" uCode measures current voltage, which is assumed + * to be constant after this initial measurement. Voltage + * compensation for txpower (number of steps in gain table) + * may be calculated once and used until the next uCode bootload. + * + * + * 8) If setting up txpowers for MIMO rates (rate indexes 8-15, 24-31), + * adjust txpower for each transmitter chain, so txpower is balanced + * between the two chains. There are 5 pairs of tx_atten[group][chain] + * values in "initialize alive", one pair for each of 5 channel ranges: + * + * Group 0: 5 GHz channel 34-43 + * Group 1: 5 GHz channel 44-70 + * Group 2: 5 GHz channel 71-124 + * Group 3: 5 GHz channel 125-200 + * Group 4: 2.4 GHz all channels + * + * Add the tx_atten[group][chain] value to the index for the target chain. + * The values are signed, but are in pairs of 0 and a non-negative number, + * so as to reduce gain (if necessary) of the "hotter" channel. This + * avoids any need to double-check for regulatory compliance after + * this step. + * + * + * 9) If setting up for a CCK rate, lower the gain by adding a CCK compensation + * value to the index: + * + * Hardware rev B: 9 steps (4.5 dB) + * Hardware rev C: 5 steps (2.5 dB) + * + * Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG, + * bits [3:2], 1 = B, 2 = C. + * + * NOTE: This compensation is in addition to any saturation backoff that + * might have been applied in an earlier step. + * + * + * 10) Select the gain table, based on band (2.4 vs 5 GHz). + * + * Limit the adjusted index to stay within the table! + * + * + * 11) Read gain table entries for DSP and radio gain, place into appropriate + * location(s) in command (struct iwl4965_txpowertable_cmd). + */ +/* Limit range of txpower output target to be between these values */ #define IWL_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm = 1 milliwatt */ #define IWL_TX_POWER_TARGET_POWER_MAX (16) /* 16 dBm */ -/* timeout equivalent to 3 minutes */ -#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000 - -#define IWL_TX_POWER_CCK_COMPENSATION (9) - -#define MIN_TX_GAIN_INDEX (0) -#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9) -#define MAX_TX_GAIN_INDEX_52GHZ (98) -#define MIN_TX_GAIN_52GHZ (98) -#define MAX_TX_GAIN_INDEX_24GHZ (98) -#define MIN_TX_GAIN_24GHZ (98) -#define MAX_TX_GAIN (0) -#define MAX_TX_GAIN_52GHZ_EXT (-9) +/** + * When MIMO is used (2 transmitters operating simultaneously), driver should + * limit each transmitter to deliver a max of 3 dB below the regulatory limit + * for the device. That is, use half power for each transmitter, so total + * txpower is within regulatory limits. + * + * The value "6" represents number of steps in gain table to reduce power 3 dB. + * Each step is 1/2 dB. + */ +#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6) +/** + * CCK gain compensation. + * + * When calculating txpowers for CCK, after making sure that the target power + * is within regulatory and saturation limits, driver must additionally + * back off gain by adding these values to the gain table index. + * + * Hardware rev for 4965 can be determined by reading CSR_HW_REV_WA_REG, + * bits [3:2], 1 = B, 2 = C. + */ +#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) +#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) + +/* + * 4965 power supply voltage compensation for txpower + */ +#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V (7) + +/** + * Gain tables. + * + * The following tables contain pair of values for setting txpower, i.e. + * gain settings for the output of the device's digital signal processor (DSP), + * and for the analog gain structure of the transmitter. + * + * Each entry in the gain tables represents a step of 1/2 dB. Note that these + * are *relative* steps, not indications of absolute output power. Output + * power varies with temperature, voltage, and channel frequency, and also + * requires consideration of average power (to satisfy regulatory constraints), + * and peak power (to avoid distortion of the output signal). + * + * Each entry contains two values: + * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained + * linear value that multiplies the output of the digital signal processor, + * before being sent to the analog radio. + * 2) Radio gain. This sets the analog gain of the radio Tx path. + * It is a coarser setting, and behaves in a logarithmic (dB) fashion. + * + * EEPROM contains factory calibration data for txpower. This maps actual + * measured txpower levels to gain settings in the "well known" tables + * below ("well-known" means here that both factory calibration *and* the + * driver work with the same table). + * + * There are separate tables for 2.4 GHz and 5 GHz bands. The 5 GHz table + * has an extension (into negative indexes), in case the driver needs to + * boost power setting for high device temperatures (higher than would be + * present during factory calibration). A 5 Ghz EEPROM index of "40" + * corresponds to the 49th entry in the table used by the driver. + */ +#define MIN_TX_GAIN_INDEX (0) /* highest gain, lowest idx, 2.4 */ +#define MIN_TX_GAIN_INDEX_52GHZ_EXT (-9) /* highest gain, lowest idx, 5 */ + +/** + * 2.4 GHz gain table + * + * Index Dsp gain Radio gain + * 0 110 0x3f (highest gain) + * 1 104 0x3f + * 2 98 0x3f + * 3 110 0x3e + * 4 104 0x3e + * 5 98 0x3e + * 6 110 0x3d + * 7 104 0x3d + * 8 98 0x3d + * 9 110 0x3c + * 10 104 0x3c + * 11 98 0x3c + * 12 110 0x3b + * 13 104 0x3b + * 14 98 0x3b + * 15 110 0x3a + * 16 104 0x3a + * 17 98 0x3a + * 18 110 0x39 + * 19 104 0x39 + * 20 98 0x39 + * 21 110 0x38 + * 22 104 0x38 + * 23 98 0x38 + * 24 110 0x37 + * 25 104 0x37 + * 26 98 0x37 + * 27 110 0x36 + * 28 104 0x36 + * 29 98 0x36 + * 30 110 0x35 + * 31 104 0x35 + * 32 98 0x35 + * 33 110 0x34 + * 34 104 0x34 + * 35 98 0x34 + * 36 110 0x33 + * 37 104 0x33 + * 38 98 0x33 + * 39 110 0x32 + * 40 104 0x32 + * 41 98 0x32 + * 42 110 0x31 + * 43 104 0x31 + * 44 98 0x31 + * 45 110 0x30 + * 46 104 0x30 + * 47 98 0x30 + * 48 110 0x6 + * 49 104 0x6 + * 50 98 0x6 + * 51 110 0x5 + * 52 104 0x5 + * 53 98 0x5 + * 54 110 0x4 + * 55 104 0x4 + * 56 98 0x4 + * 57 110 0x3 + * 58 104 0x3 + * 59 98 0x3 + * 60 110 0x2 + * 61 104 0x2 + * 62 98 0x2 + * 63 110 0x1 + * 64 104 0x1 + * 65 98 0x1 + * 66 110 0x0 + * 67 104 0x0 + * 68 98 0x0 + * 69 97 0 + * 70 96 0 + * 71 95 0 + * 72 94 0 + * 73 93 0 + * 74 92 0 + * 75 91 0 + * 76 90 0 + * 77 89 0 + * 78 88 0 + * 79 87 0 + * 80 86 0 + * 81 85 0 + * 82 84 0 + * 83 83 0 + * 84 82 0 + * 85 81 0 + * 86 80 0 + * 87 79 0 + * 88 78 0 + * 89 77 0 + * 90 76 0 + * 91 75 0 + * 92 74 0 + * 93 73 0 + * 94 72 0 + * 95 71 0 + * 96 70 0 + * 97 69 0 + * 98 68 0 + */ + +/** + * 5 GHz gain table + * + * Index Dsp gain Radio gain + * -9 123 0x3F (highest gain) + * -8 117 0x3F + * -7 110 0x3F + * -6 104 0x3F + * -5 98 0x3F + * -4 110 0x3E + * -3 104 0x3E + * -2 98 0x3E + * -1 110 0x3D + * 0 104 0x3D + * 1 98 0x3D + * 2 110 0x3C + * 3 104 0x3C + * 4 98 0x3C + * 5 110 0x3B + * 6 104 0x3B + * 7 98 0x3B + * 8 110 0x3A + * 9 104 0x3A + * 10 98 0x3A + * 11 110 0x39 + * 12 104 0x39 + * 13 98 0x39 + * 14 110 0x38 + * 15 104 0x38 + * 16 98 0x38 + * 17 110 0x37 + * 18 104 0x37 + * 19 98 0x37 + * 20 110 0x36 + * 21 104 0x36 + * 22 98 0x36 + * 23 110 0x35 + * 24 104 0x35 + * 25 98 0x35 + * 26 110 0x34 + * 27 104 0x34 + * 28 98 0x34 + * 29 110 0x33 + * 30 104 0x33 + * 31 98 0x33 + * 32 110 0x32 + * 33 104 0x32 + * 34 98 0x32 + * 35 110 0x31 + * 36 104 0x31 + * 37 98 0x31 + * 38 110 0x30 + * 39 104 0x30 + * 40 98 0x30 + * 41 110 0x25 + * 42 104 0x25 + * 43 98 0x25 + * 44 110 0x24 + * 45 104 0x24 + * 46 98 0x24 + * 47 110 0x23 + * 48 104 0x23 + * 49 98 0x23 + * 50 110 0x22 + * 51 104 0x18 + * 52 98 0x18 + * 53 110 0x17 + * 54 104 0x17 + * 55 98 0x17 + * 56 110 0x16 + * 57 104 0x16 + * 58 98 0x16 + * 59 110 0x15 + * 60 104 0x15 + * 61 98 0x15 + * 62 110 0x14 + * 63 104 0x14 + * 64 98 0x14 + * 65 110 0x13 + * 66 104 0x13 + * 67 98 0x13 + * 68 110 0x12 + * 69 104 0x08 + * 70 98 0x08 + * 71 110 0x07 + * 72 104 0x07 + * 73 98 0x07 + * 74 110 0x06 + * 75 104 0x06 + * 76 98 0x06 + * 77 110 0x05 + * 78 104 0x05 + * 79 98 0x05 + * 80 110 0x04 + * 81 104 0x04 + * 82 98 0x04 + * 83 110 0x03 + * 84 104 0x03 + * 85 98 0x03 + * 86 110 0x02 + * 87 104 0x02 + * 88 98 0x02 + * 89 110 0x01 + * 90 104 0x01 + * 91 98 0x01 + * 92 110 0x00 + * 93 104 0x00 + * 94 98 0x00 + * 95 93 0x00 + * 96 88 0x00 + * 97 83 0x00 + * 98 78 0x00 + */ + + +/** + * Sanity checks and default values for EEPROM regulatory levels. + * If EEPROM values fall outside MIN/MAX range, use default values. + * + * Regulatory limits refer to the maximum average txpower allowed by + * regulatory agencies in the geographies in which the device is meant + * to be operated. These limits are SKU-specific (i.e. geography-specific), + * and channel-specific; each channel has an individual regulatory limit + * listed in the EEPROM. + * + * Units are in half-dBm (i.e. "34" means 17 dBm). + */ #define IWL_TX_POWER_DEFAULT_REGULATORY_24 (34) #define IWL_TX_POWER_DEFAULT_REGULATORY_52 (34) #define IWL_TX_POWER_REGULATORY_MIN (0) #define IWL_TX_POWER_REGULATORY_MAX (34) + +/** + * Sanity checks and default values for EEPROM saturation levels. + * If EEPROM values fall outside MIN/MAX range, use default values. + * + * Saturation is the highest level that the output power amplifier can produce + * without significant clipping distortion. This is a "peak" power level. + * Different types of modulation (i.e. various "rates", and OFDM vs. CCK) + * require differing amounts of backoff, relative to their average power output, + * in order to avoid clipping distortion. + * + * Driver must make sure that it is violating neither the saturation limit, + * nor the regulatory limit, when calculating Tx power settings for various + * rates. + * + * Units are in half-dBm (i.e. "38" means 19 dBm). + */ #define IWL_TX_POWER_DEFAULT_SATURATION_24 (38) #define IWL_TX_POWER_DEFAULT_SATURATION_52 (38) #define IWL_TX_POWER_SATURATION_MIN (20) #define IWL_TX_POWER_SATURATION_MAX (50) -/* dv *0.4 = dt; so that 5 degrees temperature diff equals - * 12.5 in voltage diff */ -#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9 - -#define IWL_INVALID_CHANNEL (0xffffffff) -#define IWL_TX_POWER_REGITRY_BIT (2) - -#define MIN_IWL_TX_POWER_CALIB_DUR (100) -#define IWL_CCK_FROM_OFDM_POWER_DIFF (-5) -#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9) - -/* Number of entries in the gain table */ -#define POWER_GAIN_NUM_ENTRIES 78 -#define TX_POW_MAX_SESSION_NUM 5 -/* timeout equivalent to 3 minutes */ -#define TX_IWL_TIMELIMIT_NOCALIB 1800000000 - -/* Kedron TX_CALIB_STATES */ -#define IWL_TX_CALIB_STATE_SEND_TX 0x00000001 -#define IWL_TX_CALIB_WAIT_TX_RESPONSE 0x00000002 -#define IWL_TX_CALIB_ENABLED 0x00000004 -#define IWL_TX_CALIB_XVT_ON 0x00000008 -#define IWL_TX_CALIB_TEMPERATURE_CORRECT 0x00000010 -#define IWL_TX_CALIB_WORKING_WITH_XVT 0x00000020 -#define IWL_TX_CALIB_XVT_PERIODICAL 0x00000040 - -#define NUM_IWL_TX_CALIB_SETTINS 5 /* Number of tx correction groups */ - -#define IWL_MIN_POWER_IN_VP_TABLE 1 /* 0.5dBm multiplied by 2 */ -#define IWL_MAX_POWER_IN_VP_TABLE 40 /* 20dBm - multiplied by 2 (because - * entries are for each 0.5dBm) */ -#define IWL_STEP_IN_VP_TABLE 1 /* 0.5dB - multiplied by 2 */ -#define IWL_NUM_POINTS_IN_VPTABLE \ - (1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE) - -#define MIN_TX_GAIN_INDEX (0) -#define MAX_TX_GAIN_INDEX_52GHZ (98) -#define MIN_TX_GAIN_52GHZ (98) -#define MAX_TX_GAIN_INDEX_24GHZ (98) -#define MIN_TX_GAIN_24GHZ (98) -#define MAX_TX_GAIN (0) - -/* First and last channels of all groups */ +/** + * Channel groups used for Tx Attenuation calibration (MIMO tx channel balance) + * and thermal Txpower calibration. + * + * When calculating txpower, driver must compensate for current device + * temperature; higher temperature requires higher gain. Driver must calculate + * current temperature (see "4965 temperature calculation"), then compare vs. + * factory calibration temperature in EEPROM; if current temperature is higher + * than factory temperature, driver must *increase* gain by proportions shown + * in table below. If current temperature is lower than factory, driver must + * *decrease* gain. + * + * Different frequency ranges require different compensation, as shown below. + */ +/* Group 0, 5.2 GHz ch 34-43: 4.5 degrees per 1/2 dB. */ #define CALIB_IWL_TX_ATTEN_GR1_FCH 34 #define CALIB_IWL_TX_ATTEN_GR1_LCH 43 + +/* Group 1, 5.3 GHz ch 44-70: 4.0 degrees per 1/2 dB. */ #define CALIB_IWL_TX_ATTEN_GR2_FCH 44 #define CALIB_IWL_TX_ATTEN_GR2_LCH 70 + +/* Group 2, 5.5 GHz ch 71-124: 4.0 degrees per 1/2 dB. */ #define CALIB_IWL_TX_ATTEN_GR3_FCH 71 #define CALIB_IWL_TX_ATTEN_GR3_LCH 124 + +/* Group 3, 5.7 GHz ch 125-200: 4.0 degrees per 1/2 dB. */ #define CALIB_IWL_TX_ATTEN_GR4_FCH 125 #define CALIB_IWL_TX_ATTEN_GR4_LCH 200 + +/* Group 4, 2.4 GHz all channels: 3.5 degrees per 1/2 dB. */ #define CALIB_IWL_TX_ATTEN_GR5_FCH 1 #define CALIB_IWL_TX_ATTEN_GR5_LCH 20 - -union iwl_tx_power_dual_stream { - struct { - u8 radio_tx_gain[2]; - u8 dsp_predis_atten[2]; - } s; - u32 dw; +enum { + CALIB_CH_GROUP_1 = 0, + CALIB_CH_GROUP_2 = 1, + CALIB_CH_GROUP_3 = 2, + CALIB_CH_GROUP_4 = 3, + CALIB_CH_GROUP_5 = 4, + CALIB_CH_GROUP_MAX }; /********************* END TXPOWER *****************************************/ -/* HT flags */ -#define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) -#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1<<22) - -#define RXON_FLG_HT_OPERATING_MODE_POS (23) - -#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1<<23) -#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2<<23) - -#define RXON_FLG_CHANNEL_MODE_POS (25) -#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3<<25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1<<25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2<<25) - -#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1<<0) -#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7<<1) -#define RXON_RX_CHAIN_VALID_POS (1) -#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7<<4) -#define RXON_RX_CHAIN_FORCE_SEL_POS (4) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7<<7) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3<<10) -#define RXON_RX_CHAIN_CNT_POS (10) -#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3<<12) -#define RXON_RX_CHAIN_MIMO_CNT_POS (12) -#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1<<14) -#define RXON_RX_CHAIN_MIMO_FORCE_POS (14) - - -#define MCS_DUP_6M_PLCP 0x20 - -/* OFDM HT rate masks */ -/* ***************************************** */ -#define R_MCS_6M_MSK 0x1 -#define R_MCS_12M_MSK 0x2 -#define R_MCS_18M_MSK 0x4 -#define R_MCS_24M_MSK 0x8 -#define R_MCS_36M_MSK 0x10 -#define R_MCS_48M_MSK 0x20 -#define R_MCS_54M_MSK 0x40 -#define R_MCS_60M_MSK 0x80 -#define R_MCS_12M_DUAL_MSK 0x100 -#define R_MCS_24M_DUAL_MSK 0x200 -#define R_MCS_36M_DUAL_MSK 0x400 -#define R_MCS_48M_DUAL_MSK 0x800 - -#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) -#define is_siso(tbl) (((tbl) == LQ_SISO)) -#define is_mimo(tbl) (((tbl) == LQ_MIMO)) -#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)) - +/****************************/ /* Flow Handler Definitions */ +/****************************/ -/**********************/ -/* Addresses */ -/**********************/ - +/** + * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) + * Addresses are offsets from device's PCI hardware base address. + */ #define FH_MEM_LOWER_BOUND (0x1000) #define FH_MEM_UPPER_BOUND (0x1EF0) -#define IWL_FH_REGS_LOWER_BOUND (0x1000) -#define IWL_FH_REGS_UPPER_BOUND (0x2000) - +/** + * Keep-Warm (KW) buffer base address. + * + * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the + * host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency + * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host + * from going into a power-savings mode that would cause higher DRAM latency, + * and possible data over/under-runs, before all Tx/Rx is complete. + * + * Driver loads IWL_FH_KW_MEM_ADDR_REG with the physical address (bits 35:4) + * of the buffer, which must be 4K aligned. Once this is set up, the 4965 + * automatically invokes keep-warm accesses when normal accesses might not + * be sufficient to maintain fast DRAM response. + * + * Bit fields: + * 31-0: Keep-warm buffer physical base address [35:4], must be 4K aligned + */ #define IWL_FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) -/* CBBC Area - Circular buffers base address cache pointers table */ + +/** + * TFD Circular Buffers Base (CBBC) addresses + * + * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident + * circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs) + * (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04 + * bytes from one another. Each TFD circular buffer in DRAM must be 256-byte + * aligned (address bits 0-7 must be 0). + * + * Bit fields in each pointer register: + * 27-0: TFD CB physical base address [35:8], must be 256-byte aligned + */ #define FH_MEM_CBBC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) #define FH_MEM_CBBC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xA10) -/* queues 0 - 15 */ + +/* Find TFD CB base pointer for given queue (range 0-15). */ #define FH_MEM_CBBC_QUEUE(x) (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4) -/* RSCSR Area */ + +/** + * Rx SRAM Control and Status Registers (RSCSR) + * + * These registers provide handshake between driver and 4965 for the Rx queue + * (this queue handles *all* command responses, notifications, Rx data, etc. + * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx + * queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can + * concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer + * Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1 + * mapping between RBDs and RBs. + * + * Driver must allocate host DRAM memory for the following, and set the + * physical address of each into 4965 registers: + * + * 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256 + * entries (although any power of 2, up to 4096, is selectable by driver). + * Each entry (1 dword) points to a receive buffer (RB) of consistent size + * (typically 4K, although 8K or 16K are also selectable by driver). + * Driver sets up RB size and number of RBDs in the CB via Rx config + * register FH_MEM_RCSR_CHNL0_CONFIG_REG. + * + * Bit fields within one RBD: + * 27-0: Receive Buffer physical address bits [35:8], 256-byte aligned + * + * Driver sets physical address [35:8] of base of RBD circular buffer + * into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0]. + * + * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers + * (RBs) have been filled, via a "write pointer", actually the index of + * the RB's corresponding RBD within the circular buffer. Driver sets + * physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0]. + * + * Bit fields in lower dword of Rx status buffer (upper dword not used + * by driver; see struct iwl4965_shared, val0): + * 31-12: Not used by driver + * 11- 0: Index of last filled Rx buffer descriptor + * (4965 writes, driver reads this value) + * + * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must + * enter pointers to these RBs into contiguous RBD circular buffer entries, + * and update the 4965's "write" index register, FH_RSCSR_CHNL0_RBDCB_WPTR_REG. + * + * This "write" index corresponds to the *next* RBD that the driver will make + * available, i.e. one RBD past the tail of the ready-to-fill RBDs within + * the circular buffer. This value should initially be 0 (before preparing any + * RBs), should be 8 after preparing the first 8 RBs (for example), and must + * wrap back to 0 at the end of the circular buffer (but don't wrap before + * "read" index has advanced past 1! See below). + * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8. + * + * As the 4965 fills RBs (referenced from contiguous RBDs within the circular + * buffer), it updates the Rx status buffer in host DRAM, 2) described above, + * to tell the driver the index of the latest filled RBD. The driver must + * read this "read" index from DRAM after receiving an Rx interrupt from 4965. + * + * The driver must also internally keep track of a third index, which is the + * next RBD to process. When receiving an Rx interrupt, driver should process + * all filled but unprocessed RBs up to, but not including, the RB + * corresponding to the "read" index. For example, if "read" index becomes "1", + * driver may process the RB pointed to by RBD 0. Depending on volume of + * traffic, there may be many RBs to process. + * + * If read index == write index, 4965 thinks there is no room to put new data. + * Due to this, the maximum number of filled RBs is 255, instead of 256. To + * be safe, make sure that there is a gap of at least 2 RBDs between "write" + * and "read" indexes; that is, make sure that there are no more than 254 + * buffers waiting to be filled. + */ #define FH_MEM_RSCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xBC0) #define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) #define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) +/** + * Physical base address of 8-byte Rx Status buffer. + * Bit fields: + * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. + */ #define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) + +/** + * Physical base address of Rx Buffer Descriptor Circular Buffer. + * Bit fields: + * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. + */ #define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) + +/** + * Rx write pointer (index, really!). + * Bit fields: + * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. + * NOTE: For 256-entry circular buffer, use only bits [7:0]. + */ #define FH_RSCSR_CHNL0_RBDCB_WPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x008) +#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) + -/* RCSR Area - Registers address map */ +/** + * Rx Config/Status Registers (RCSR) + * Rx Config Reg for channel 0 (only channel used) + * + * Driver must initialize FH_MEM_RCSR_CHNL0_CONFIG_REG as follows for + * normal operation (see bit fields). + * + * Clearing FH_MEM_RCSR_CHNL0_CONFIG_REG to 0 turns off Rx DMA. + * Driver should poll FH_MEM_RSSR_RX_STATUS_REG for + * FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (bit 24) before continuing. + * + * Bit fields: + * 31-30: Rx DMA channel enable: '00' off/pause, '01' pause at end of frame, + * '10' operate normally + * 29-24: reserved + * 23-20: # RBDs in circular buffer = 2^value; use "8" for 256 RBDs (normal), + * min "5" for 32 RBDs, max "12" for 4096 RBDs. + * 19-18: reserved + * 17-16: size of each receive buffer; '00' 4K (normal), '01' 8K, + * '10' 12K, '11' 16K. + * 15-14: reserved + * 13-12: IRQ destination; '00' none, '01' host driver (normal operation) + * 11- 4: timeout for closing Rx buffer and interrupting host (units 32 usec) + * typical value 0x10 (about 1/2 msec) + * 3- 0: reserved + */ #define FH_MEM_RCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) #define FH_MEM_RCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xCC0) #define FH_MEM_RCSR_CHNL0 (FH_MEM_RCSR_LOWER_BOUND) #define FH_MEM_RCSR_CHNL0_CONFIG_REG (FH_MEM_RCSR_CHNL0) -/* RSSR Area - Rx shared ctrl & status registers */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */ +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */ +#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */ +#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ +#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ + +#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) +#define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_BITSHIFT (4) +#define RX_RB_TIMEOUT (0x10) + +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) +#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) + +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K (0x00010000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_12K (0x00020000) +#define FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_16K (0x00030000) + +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) +#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) + + +/** + * Rx Shared Status Registers (RSSR) + * + * After stopping Rx DMA channel (writing 0 to FH_MEM_RCSR_CHNL0_CONFIG_REG), + * driver must poll FH_MEM_RSSR_RX_STATUS_REG until Rx channel is idle. + * + * Bit fields: + * 24: 1 = Channel 0 is idle + * + * FH_MEM_RSSR_SHARED_CTRL_REG and FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV contain + * default values that should not be altered by the driver. + */ #define FH_MEM_RSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xC40) #define FH_MEM_RSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) + #define FH_MEM_RSSR_SHARED_CTRL_REG (FH_MEM_RSSR_LOWER_BOUND) #define FH_MEM_RSSR_RX_STATUS_REG (FH_MEM_RSSR_LOWER_BOUND + 0x004) #define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV (FH_MEM_RSSR_LOWER_BOUND + 0x008) -/* TCSR */ -#define IWL_FH_TCSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xD00) -#define IWL_FH_TCSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xE60) +#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) + -#define IWL_FH_TCSR_CHNL_NUM (7) +/** + * Transmit DMA Channel Control/Status Registers (TCSR) + * + * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels + * supported in hardware (don't confuse these with the 16 Tx queues in DRAM, + * which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes. + * + * To use a Tx DMA channel, driver must initialize its + * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl) with: + * + * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + * IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL + * + * All other bits should be 0. + * + * Bit fields: + * 31-30: Tx DMA channel enable: '00' off/pause, '01' pause at end of frame, + * '10' operate normally + * 29- 4: Reserved, set to "0" + * 3: Enable internal DMA requests (1, normal operation), disable (0) + * 2- 0: Reserved, set to "0" + */ +#define IWL_FH_TCSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xD00) +#define IWL_FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) + +/* Find Control/Status reg for given Tx DMA/FIFO channel */ #define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ (IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl) -/* TSSR Area - Tx shared status registers */ -/* TSSR */ -#define IWL_FH_TSSR_LOWER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEA0) -#define IWL_FH_TSSR_UPPER_BOUND (IWL_FH_REGS_LOWER_BOUND + 0xEC0) - -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG (IWL_FH_TSSR_LOWER_BOUND + 0x008) -#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010) - -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B (0x00000000) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B (0x00000800) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B (0x00000C00) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) +/** + * Tx Shared Status Registers (TSSR) + * + * After stopping Tx DMA channel (writing 0 to + * IWL_FH_TCSR_CHNL_TX_CONFIG_REG(chnl)), driver must poll + * IWL_FH_TSSR_TX_STATUS_REG until selected Tx channel is idle + * (channel's buffers empty | no pending requests). + * + * Bit fields: + * 31-24: 1 = Channel buffers empty (channel 7:0) + * 23-16: 1 = No pending requests (channel 7:0) + */ +#define IWL_FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) +#define IWL_FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) -#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) +#define IWL_FH_TSSR_TX_STATUS_REG (IWL_FH_TSSR_LOWER_BOUND + 0x010) #define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) \ ((1 << (_chnl)) << 24) @@ -341,147 +1558,347 @@ union iwl_tx_power_dual_stream { (IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) -/* TCSR: tx_config register values */ -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC (0x00000002) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) - -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) -#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) - -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) - -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) - -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) -#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) - -/* RCSR: channel 0 rx_config register defines */ -#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK (0xC0000000) /* bits 30-31 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK (0x00F00000) /* bits 20-23 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK (0x00030000) /* bits 16-17 */ -#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */ -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK (0x00001000) /* bit 12 */ -#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK (0x00000FF0) /* bit 4-11 */ - -#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT (20) -#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT (16) - -/* RCSR: rx_config register values */ -#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL (0x00000000) -#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL (0x40000000) -#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL (0x80000000) - -#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K (0x00000000) - -/* RCSR channel 0 config register values */ -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) -#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) - -/* RSCSR: defs used in normal mode */ -#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK (0x00000FFF) /* bits 0-11 */ +/********************* START TX SCHEDULER *************************************/ +/** + * 4965 Tx Scheduler + * + * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs + * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in + * host DRAM. It steers each frame's Tx command (which contains the frame + * data) into one of up to 7 prioritized Tx DMA FIFO channels within the + * device. A queue maps to only one (selectable by driver) Tx DMA channel, + * but one DMA channel may take input from several queues. + * + * Tx DMA channels have dedicated purposes. For 4965, they are used as follows: + * + * 0 -- EDCA BK (background) frames, lowest priority + * 1 -- EDCA BE (best effort) frames, normal priority + * 2 -- EDCA VI (video) frames, higher priority + * 3 -- EDCA VO (voice) and management frames, highest priority + * 4 -- Commands (e.g. RXON, etc.) + * 5 -- HCCA short frames + * 6 -- HCCA long frames + * 7 -- not used by driver (device-internal only) + * + * Driver should normally map queues 0-6 to Tx DMA/FIFO channels 0-6. + * In addition, driver can map queues 7-15 to Tx DMA/FIFO channels 0-3 to + * support 11n aggregation via EDCA DMA channels. + * + * The driver sets up each queue to work in one of two modes: + * + * 1) Scheduler-Ack, in which the scheduler automatically supports a + * block-ack (BA) window of up to 64 TFDs. In this mode, each queue + * contains TFDs for a unique combination of Recipient Address (RA) + * and Traffic Identifier (TID), that is, traffic of a given + * Quality-Of-Service (QOS) priority, destined for a single station. + * + * In scheduler-ack mode, the scheduler keeps track of the Tx status of + * each frame within the BA window, including whether it's been transmitted, + * and whether it's been acknowledged by the receiving station. The device + * automatically processes block-acks received from the receiving STA, + * and reschedules un-acked frames to be retransmitted (successful + * Tx completion may end up being out-of-order). + * + * The driver must maintain the queue's Byte Count table in host DRAM + * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode. + * This mode does not support fragmentation. + * + * 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order. + * The device may automatically retry Tx, but will retry only one frame + * at a time, until receiving ACK from receiving station, or reaching + * retry limit and giving up. + * + * The command queue (#4) must use this mode! + * This mode does not require use of the Byte Count table in host DRAM. + * + * Driver controls scheduler operation via 3 means: + * 1) Scheduler registers + * 2) Shared scheduler data base in internal 4956 SRAM + * 3) Shared data in host DRAM + * + * Initialization: + * + * When loading, driver should allocate memory for: + * 1) 16 TFD circular buffers, each with space for (typically) 256 TFDs. + * 2) 16 Byte Count circular buffers in 16 KBytes contiguous memory + * (1024 bytes for each queue). + * + * After receiving "Alive" response from uCode, driver must initialize + * the scheduler (especially for queue #4, the command queue, otherwise + * the driver can't issue commands!): + */ + +/** + * Max Tx window size is the max number of contiguous TFDs that the scheduler + * can keep track of at one time when creating block-ack chains of frames. + * Note that "64" matches the number of ack bits in a block-ack packet. + * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize + * SCD_CONTEXT_QUEUE_OFFSET(x) values. + */ #define SCD_WIN_SIZE 64 #define SCD_FRAME_LIMIT 64 -/* memory mapped registers */ +/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */ #define SCD_START_OFFSET 0xa02c00 +/* + * 4965 tells driver SRAM address for internal scheduler structs via this reg. + * Value is valid only after "Alive" response from uCode. + */ #define SCD_SRAM_BASE_ADDR (SCD_START_OFFSET + 0x0) + +/* + * Driver may need to update queue-empty bits after changing queue's + * write and read pointers (indexes) during (re-)initialization (i.e. when + * scheduler is not tracking what's happening). + * Bit fields: + * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit + * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty + * NOTE: This register is not used by Linux driver. + */ #define SCD_EMPTY_BITS (SCD_START_OFFSET + 0x4) + +/* + * Physical base address of array of byte count (BC) circular buffers (CBs). + * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode. + * This register points to BC CB for queue 0, must be on 1024-byte boundary. + * Others are spaced by 1024 bytes. + * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad. + * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff). + * Bit fields: + * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned. + */ #define SCD_DRAM_BASE_ADDR (SCD_START_OFFSET + 0x10) -#define SCD_AIT (SCD_START_OFFSET + 0x18) + +/* + * Enables any/all Tx DMA/FIFO channels. + * Scheduler generates requests for only the active channels. + * Set this to 0xff to enable all 8 channels (normal usage). + * Bit fields: + * 7- 0: Enable (1), disable (0), one bit for each channel 0-7 + */ #define SCD_TXFACT (SCD_START_OFFSET + 0x1c) + +/* Mask to enable contiguous Tx DMA/FIFO channels between "lo" and "hi". */ +#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ + ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) + +/* + * Queue (x) Write Pointers (indexes, really!), one for each Tx queue. + * Initialized and updated by driver as new TFDs are added to queue. + * NOTE: If using Block Ack, index must correspond to frame's + * Start Sequence Number; index = (SSN & 0xff) + * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses? + */ #define SCD_QUEUE_WRPTR(x) (SCD_START_OFFSET + 0x24 + (x) * 4) -#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4) -#define SCD_SETQUEUENUM (SCD_START_OFFSET + 0xa4) -#define SCD_SET_TXSTAT_TXED (SCD_START_OFFSET + 0xa8) -#define SCD_SET_TXSTAT_DONE (SCD_START_OFFSET + 0xac) -#define SCD_SET_TXSTAT_NOT_SCHD (SCD_START_OFFSET + 0xb0) -#define SCD_DECREASE_CREDIT (SCD_START_OFFSET + 0xb4) -#define SCD_DECREASE_SCREDIT (SCD_START_OFFSET + 0xb8) -#define SCD_LOAD_CREDIT (SCD_START_OFFSET + 0xbc) -#define SCD_LOAD_SCREDIT (SCD_START_OFFSET + 0xc0) -#define SCD_BAR (SCD_START_OFFSET + 0xc4) -#define SCD_BAR_DW0 (SCD_START_OFFSET + 0xc8) -#define SCD_BAR_DW1 (SCD_START_OFFSET + 0xcc) -#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0) -#define SCD_QUERY_REQ (SCD_START_OFFSET + 0xd8) -#define SCD_QUERY_RES (SCD_START_OFFSET + 0xdc) -#define SCD_PENDING_FRAMES (SCD_START_OFFSET + 0xe0) -#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4) -#define SCD_INTERRUPT_THRESHOLD (SCD_START_OFFSET + 0xe8) -#define SCD_QUERY_MIN_FRAME_SIZE (SCD_START_OFFSET + 0x100) -#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4) -/* SRAM structures */ -#define SCD_CONTEXT_DATA_OFFSET 0x380 -#define SCD_TX_STTS_BITMAP_OFFSET 0x400 -#define SCD_TRANSLATE_TBL_OFFSET 0x500 -#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) -#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ - ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) +/* + * Queue (x) Read Pointers (indexes, really!), one for each Tx queue. + * For FIFO mode, index indicates next frame to transmit. + * For Scheduler-ACK mode, index indicates first frame in Tx window. + * Initialized by driver, updated by scheduler. + */ +#define SCD_QUEUE_RDPTR(x) (SCD_START_OFFSET + 0x64 + (x) * 4) -#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \ - ((1<<(hi))|((1<<(hi))-(1<<(lo)))) +/* + * Select which queues work in chain mode (1) vs. not (0). + * Use chain mode to build chains of aggregated frames. + * Bit fields: + * 31-16: Reserved + * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time + * NOTE: If driver sets up queue for chain mode, it should be also set up + * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x). + */ +#define SCD_QUEUECHAIN_SEL (SCD_START_OFFSET + 0xd0) +/* + * Select which queues interrupt driver when scheduler increments + * a queue's read pointer (index). + * Bit fields: + * 31-16: Reserved + * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled + * NOTE: This functionality is apparently a no-op; driver relies on interrupts + * from Rx queue to read Tx command responses and update Tx queues. + */ +#define SCD_INTERRUPT_MASK (SCD_START_OFFSET + 0xe4) -#define SCD_MODE_REG_BIT_SEARCH_MODE (1<<0) -#define SCD_MODE_REG_BIT_SBYP_MODE (1<<1) +/* + * Queue search status registers. One for each queue. + * Sets up queue mode and assigns queue to Tx DMA channel. + * Bit fields: + * 19-10: Write mask/enable bits for bits 0-9 + * 9: Driver should init to "0" + * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0). + * Driver should init to "1" for aggregation mode, or "0" otherwise. + * 7-6: Driver should init to "0" + * 5: Window Size Left; indicates whether scheduler can request + * another TFD, based on window size, etc. Driver should init + * this bit to "1" for aggregation mode, or "0" for non-agg. + * 4-1: Tx FIFO to use (range 0-7). + * 0: Queue is active (1), not active (0). + * Other bits should be written as "0" + * + * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled + * via SCD_QUEUECHAIN_SEL. + */ +#define SCD_QUEUE_STATUS_BITS(x) (SCD_START_OFFSET + 0x104 + (x) * 4) -#define SCD_TXFIFO_POS_TID (0) -#define SCD_TXFIFO_POS_RA (4) +/* Bit field positions */ #define SCD_QUEUE_STTS_REG_POS_ACTIVE (0) #define SCD_QUEUE_STTS_REG_POS_TXF (1) #define SCD_QUEUE_STTS_REG_POS_WSL (5) #define SCD_QUEUE_STTS_REG_POS_SCD_ACK (8) + +/* Write masks */ #define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10) #define SCD_QUEUE_STTS_REG_MSK (0x0007FC00) -#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) +/** + * 4965 internal SRAM structures for scheduler, shared with driver ... + * + * Driver should clear and initialize the following areas after receiving + * "Alive" response from 4965 uCode, i.e. after initial + * uCode load, or after a uCode load done for error recovery: + * + * SCD_CONTEXT_DATA_OFFSET (size 128 bytes) + * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes) + * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes) + * + * Driver accesses SRAM via HBUS_TARG_MEM_* registers. + * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR. + * All OFFSET values must be added to this base address. + */ + +/* + * Queue context. One 8-byte entry for each of 16 queues. + * + * Driver should clear this entire area (size 0x80) to 0 after receiving + * "Alive" notification from uCode. Additionally, driver should init + * each queue's entry as follows: + * + * LS Dword bit fields: + * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64. + * + * MS Dword bit fields: + * 16-22: Frame limit. Driver should init to 10 (0xa). + * + * Driver should init all other bits to 0. + * + * Init must be done after driver receives "Alive" response from 4965 uCode, + * and when setting up queue for aggregation. + */ +#define SCD_CONTEXT_DATA_OFFSET 0x380 +#define SCD_CONTEXT_QUEUE_OFFSET(x) (SCD_CONTEXT_DATA_OFFSET + ((x) * 8)) #define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0) #define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F) -#define SCD_QUEUE_CTX_REG1_CREDIT_POS (8) -#define SCD_QUEUE_CTX_REG1_CREDIT_MSK (0x00FFFF00) -#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS (24) -#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK (0xFF000000) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16) #define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000) -#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R (0x00000010) -#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00) -#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100) -#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200) +/* + * Tx Status Bitmap + * + * Driver should clear this entire area (size 0x100) to 0 after receiving + * "Alive" notification from uCode. Area is used only by device itself; + * no other support (besides clearing) is required from driver. + */ +#define SCD_TX_STTS_BITMAP_OFFSET 0x400 -static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) +/* + * RAxTID to queue translation mapping. + * + * When queue is in Scheduler-ACK mode, frames placed in a that queue must be + * for only one combination of receiver address (RA) and traffic ID (TID), i.e. + * one QOS priority level destined for one station (for this wireless link, + * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit + * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK + * mode, the device ignores the mapping value. + * + * Bit fields, for each 16-bit map: + * 15-9: Reserved, set to 0 + * 8-4: Index into device's station table for recipient station + * 3-0: Traffic ID (tid), range 0-15 + * + * Driver should clear this entire area (size 32 bytes) to 0 after receiving + * "Alive" notification from uCode. To update a 16-bit map value, driver + * must read a dword-aligned value from device SRAM, replace the 16-bit map + * value of interest, and write the dword value back into device SRAM. + */ +#define SCD_TRANSLATE_TBL_OFFSET 0x500 + +/* Find translation table dword to read/write for given queue */ +#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \ + ((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc) + +#define SCD_TXFIFO_POS_TID (0) +#define SCD_TXFIFO_POS_RA (4) +#define SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF) + +/*********************** END TX SCHEDULER *************************************/ + +static inline u8 iwl4965_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; } -static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags) +static inline u16 iwl4965_hw_get_rate_n_flags(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFFFF; } -static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags) +static inline __le32 iwl4965_hw_set_rate_n_flags(u8 rate, u16 flags) { return cpu_to_le32(flags|(u16)rate); } -struct iwl_tfd_frame_data { + +/** + * Tx/Rx Queues + * + * Most communication between driver and 4965 is via queues of data buffers. + * For example, all commands that the driver issues to device's embedded + * controller (uCode) are via the command queue (one of the Tx queues). All + * uCode command responses/replies/notifications, including Rx frames, are + * conveyed from uCode to driver via the Rx queue. + * + * Most support for these queues, including handshake support, resides in + * structures in host DRAM, shared between the driver and the device. When + * allocating this memory, the driver must make sure that data written by + * the host CPU updates DRAM immediately (and does not get "stuck" in CPU's + * cache memory), so DRAM and cache are consistent, and the device can + * immediately see changes made by the driver. + * + * 4965 supports up to 16 DRAM-based Tx queues, and services these queues via + * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array + * in DRAM containing 256 Transmit Frame Descriptors (TFDs). + */ +#define IWL4965_MAX_WIN_SIZE 64 +#define IWL4965_QUEUE_SIZE 256 +#define IWL4965_NUM_FIFOS 7 +#define IWL_MAX_NUM_QUEUES 16 + + +/** + * struct iwl4965_tfd_frame_data + * + * Describes up to 2 buffers containing (contiguous) portions of a Tx frame. + * Each buffer must be on dword boundary. + * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers, + * may be filled within a TFD (iwl_tfd_frame). + * + * Bit fields in tb1_addr: + * 31- 0: Tx buffer 1 address bits [31:0] + * + * Bit fields in val1: + * 31-16: Tx buffer 2 address bits [15:0] + * 15- 4: Tx buffer 1 length (bytes) + * 3- 0: Tx buffer 1 address bits [32:32] + * + * Bit fields in val2: + * 31-20: Tx buffer 2 length (bytes) + * 19- 0: Tx buffer 2 address bits [35:16] + */ +struct iwl4965_tfd_frame_data { __le32 tb1_addr; __le32 val1; @@ -509,7 +1926,36 @@ struct iwl_tfd_frame_data { #define IWL_tb2_len_SYM val2 } __attribute__ ((packed)); -struct iwl_tfd_frame { + +/** + * struct iwl4965_tfd_frame + * + * Transmit Frame Descriptor (TFD) + * + * 4965 supports up to 16 Tx queues resident in host DRAM. + * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. + * Both driver and device share these circular buffers, each of which must be + * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965. + * + * Driver must indicate the physical address of the base of each + * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers. + * + * Each TFD contains pointer/size information for up to 20 data buffers + * in host DRAM. These buffers collectively contain the (one) frame described + * by the TFD. Each buffer must be a single contiguous block of memory within + * itself, but buffers may be scattered in host DRAM. Each buffer has max size + * of (4K - 4). The 4965 concatenates all of a TFD's buffers into a single + * Tx frame, up to 8 KBytes in size. + * + * Bit fields in the control dword (val0): + * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound + * 29: reserved + * 28-24: # Transmit Buffer Descriptors in TFD + * 23- 0: reserved + * + * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. + */ +struct iwl4965_tfd_frame { __le32 val0; /* __le32 rsvd1:24; */ /* __le32 num_tbs:5; */ @@ -518,15 +1964,20 @@ struct iwl_tfd_frame { #define IWL_num_tbs_SYM val0 /* __le32 rsvd2:1; */ /* __le32 padding:2; */ - struct iwl_tfd_frame_data pa[10]; + struct iwl4965_tfd_frame_data pa[10]; __le32 reserved; } __attribute__ ((packed)); -#define IWL4965_MAX_WIN_SIZE 64 -#define IWL4965_QUEUE_SIZE 256 -#define IWL4965_NUM_FIFOS 7 -#define IWL_MAX_NUM_QUEUES 16 +/** + * struct iwl4965_queue_byte_cnt_entry + * + * Byte Count Table Entry + * + * Bit fields: + * 15-12: reserved + * 11- 0: total to-be-transmitted byte count of frame (does not include command) + */ struct iwl4965_queue_byte_cnt_entry { __le16 val; /* __le16 byte_cnt:12; */ @@ -536,6 +1987,25 @@ struct iwl4965_queue_byte_cnt_entry { /* __le16 rsvd:4; */ } __attribute__ ((packed)); + +/** + * struct iwl4965_sched_queue_byte_cnt_tbl + * + * Byte Count table + * + * Each Tx queue uses a byte-count table containing 320 entries: + * one 16-bit entry for each of 256 TFDs, plus an additional 64 entries that + * duplicate the first 64 entries (to avoid wrap-around within a Tx window; + * max Tx window is 64 TFDs). + * + * When driver sets up a new TFD, it must also enter the total byte count + * of the frame to be transmitted into the corresponding entry in the byte + * count table for the chosen Tx queue. If the TFD index is 0-63, the driver + * must duplicate the byte count entry in corresponding index 256-319. + * + * "dont_care" padding puts each byte count table on a 1024-byte boundary; + * 4965 assumes tables are separated by 1024 bytes. + */ struct iwl4965_sched_queue_byte_cnt_tbl { struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE]; @@ -544,9 +2014,31 @@ struct iwl4965_sched_queue_byte_cnt_tbl { sizeof(__le16)]; } __attribute__ ((packed)); -/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR - * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ -struct iwl_shared { + +/** + * struct iwl4965_shared - handshake area for Tx and Rx + * + * For convenience in allocating memory, this structure combines 2 areas of + * DRAM which must be shared between driver and 4965. These do not need to + * be combined, if better allocation would result from keeping them separate: + * + * 1) The Tx byte count tables occupy 1024 bytes each (16 KBytes total for + * 16 queues). Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find + * the first of these tables. 4965 assumes tables are 1024 bytes apart. + * + * 2) The Rx status (val0 and val1) occupies only 8 bytes. Driver uses + * FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area. + * Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD) + * that has been filled by the 4965. + * + * Bit fields val0: + * 31-12: Not used + * 11- 0: Index of last filled Rx buffer descriptor (4965 writes, driver reads) + * + * Bit fields val1: + * 31- 0: Not used + */ +struct iwl4965_shared { struct iwl4965_sched_queue_byte_cnt_tbl queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES]; __le32 val0; @@ -578,4 +2070,4 @@ struct iwl_shared { __le32 padding2; } __attribute__ ((packed)); -#endif /* __iwl_4965_hw_h__ */ +#endif /* __iwl4965_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-io.h b/drivers/net/wireless/iwlwifi/iwl-4965-io.h new file mode 100644 index 000000000000..34a0b57eea0c --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-4965-io.h @@ -0,0 +1,431 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project. + * + * 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 <ipw2100-admin@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#ifndef __iwl4965_io_h__ +#define __iwl4965_io_h__ + +#include <linux/io.h> + +#include "iwl-4965-debug.h" + +/* + * IO, register, and NIC memory access functions + * + * NOTE on naming convention and macro usage for these + * + * A single _ prefix before a an access function means that no state + * check or debug information is printed when that function is called. + * + * A double __ prefix before an access function means that state is checked + * and the current line number is printed in addition to any other debug output. + * + * The non-prefixed name is the #define that maps the caller into a + * #define that provides the caller's __LINE__ to the double prefix version. + * + * If you wish to call the function without any debug or state checking, + * you should use the single _ prefix version (as is used by dependent IO + * routines, for example _iwl4965_read_direct32 calls the non-check version of + * _iwl4965_read32.) + * + * These declarations are *extremely* useful in quickly isolating code deltas + * which result in misconfiguring of the hardware I/O. In combination with + * git-bisect and the IO debug level you can quickly determine the specific + * commit which breaks the IO sequence to the hardware. + * + */ + +#define _iwl4965_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_write32(const char *f, u32 l, struct iwl4965_priv *iwl, + u32 ofs, u32 val) +{ + IWL_DEBUG_IO("write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l); + _iwl4965_write32(iwl, ofs, val); +} +#define iwl4965_write32(iwl, ofs, val) \ + __iwl4965_write32(__FILE__, __LINE__, iwl, ofs, val) +#else +#define iwl4965_write32(iwl, ofs, val) _iwl4965_write32(iwl, ofs, val) +#endif + +#define _iwl4965_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) +#ifdef CONFIG_IWL4965_DEBUG +static inline u32 __iwl4965_read32(char *f, u32 l, struct iwl4965_priv *iwl, u32 ofs) +{ + IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); + return _iwl4965_read32(iwl, ofs); +} +#define iwl4965_read32(iwl, ofs) __iwl4965_read32(__FILE__, __LINE__, iwl, ofs) +#else +#define iwl4965_read32(p, o) _iwl4965_read32(p, o) +#endif + +static inline int _iwl4965_poll_bit(struct iwl4965_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl4965_read32(priv, addr) & mask) == (bits & mask)) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} +#ifdef CONFIG_IWL4965_DEBUG +static inline int __iwl4965_poll_bit(const char *f, u32 l, + struct iwl4965_priv *priv, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int ret = _iwl4965_poll_bit(priv, addr, bits, mask, timeout); + if (unlikely(ret == -ETIMEDOUT)) + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", + addr, bits, mask, f, l); + else + IWL_DEBUG_IO + ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", + addr, bits, mask, ret, f, l); + return ret; +} +#define iwl4965_poll_bit(iwl, addr, bits, mask, timeout) \ + __iwl4965_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) +#else +#define iwl4965_poll_bit(p, a, b, m, t) _iwl4965_poll_bit(p, a, b, m, t) +#endif + +static inline void _iwl4965_set_bit(struct iwl4965_priv *priv, u32 reg, u32 mask) +{ + _iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) | mask); +} +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_set_bit(const char *f, u32 l, + struct iwl4965_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl4965_read32(priv, reg) | mask; + IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl4965_write32(priv, reg, val); +} +#define iwl4965_set_bit(p, r, m) __iwl4965_set_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl4965_set_bit(p, r, m) _iwl4965_set_bit(p, r, m) +#endif + +static inline void _iwl4965_clear_bit(struct iwl4965_priv *priv, u32 reg, u32 mask) +{ + _iwl4965_write32(priv, reg, _iwl4965_read32(priv, reg) & ~mask); +} +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_clear_bit(const char *f, u32 l, + struct iwl4965_priv *priv, u32 reg, u32 mask) +{ + u32 val = _iwl4965_read32(priv, reg) & ~mask; + IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); + _iwl4965_write32(priv, reg, val); +} +#define iwl4965_clear_bit(p, r, m) __iwl4965_clear_bit(__FILE__, __LINE__, p, r, m) +#else +#define iwl4965_clear_bit(p, r, m) _iwl4965_clear_bit(p, r, m) +#endif + +static inline int _iwl4965_grab_nic_access(struct iwl4965_priv *priv) +{ + int ret; + u32 gp_ctl; + +#ifdef CONFIG_IWL4965_DEBUG + if (atomic_read(&priv->restrict_refcnt)) + return 0; +#endif + if (test_bit(STATUS_RF_KILL_HW, &priv->status) || + test_bit(STATUS_RF_KILL_SW, &priv->status)) { + IWL_WARNING("WARNING: Requesting MAC access during RFKILL " + "wakes up NIC\n"); + + /* 10 msec allows time for NIC to complete its data save */ + gp_ctl = _iwl4965_read32(priv, CSR_GP_CNTRL); + if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { + IWL_DEBUG_RF_KILL("Wait for complete power-down, " + "gpctl = 0x%08x\n", gp_ctl); + mdelay(10); + } else + IWL_DEBUG_RF_KILL("power-down complete, " + "gpctl = 0x%08x\n", gp_ctl); + } + + /* this bit wakes up the NIC */ + _iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + ret = _iwl4965_poll_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); + if (ret < 0) { + IWL_ERROR("MAC is in deep sleep!\n"); + return -EIO; + } + +#ifdef CONFIG_IWL4965_DEBUG + atomic_inc(&priv->restrict_refcnt); +#endif + return 0; +} + +#ifdef CONFIG_IWL4965_DEBUG +static inline int __iwl4965_grab_nic_access(const char *f, u32 l, + struct iwl4965_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt)) + IWL_DEBUG_INFO("Grabbing access while already held at " + "line %d.\n", l); + + IWL_DEBUG_IO("grabbing nic access - %s %d\n", f, l); + return _iwl4965_grab_nic_access(priv); +} +#define iwl4965_grab_nic_access(priv) \ + __iwl4965_grab_nic_access(__FILE__, __LINE__, priv) +#else +#define iwl4965_grab_nic_access(priv) \ + _iwl4965_grab_nic_access(priv) +#endif + +static inline void _iwl4965_release_nic_access(struct iwl4965_priv *priv) +{ +#ifdef CONFIG_IWL4965_DEBUG + if (atomic_dec_and_test(&priv->restrict_refcnt)) +#endif + _iwl4965_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); +} +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_release_nic_access(const char *f, u32 l, + struct iwl4965_priv *priv) +{ + if (atomic_read(&priv->restrict_refcnt) <= 0) + IWL_ERROR("Release unheld nic access at line %d.\n", l); + + IWL_DEBUG_IO("releasing nic access - %s %d\n", f, l); + _iwl4965_release_nic_access(priv); +} +#define iwl4965_release_nic_access(priv) \ + __iwl4965_release_nic_access(__FILE__, __LINE__, priv) +#else +#define iwl4965_release_nic_access(priv) \ + _iwl4965_release_nic_access(priv) +#endif + +static inline u32 _iwl4965_read_direct32(struct iwl4965_priv *priv, u32 reg) +{ + return _iwl4965_read32(priv, reg); +} +#ifdef CONFIG_IWL4965_DEBUG +static inline u32 __iwl4965_read_direct32(const char *f, u32 l, + struct iwl4965_priv *priv, u32 reg) +{ + u32 value = _iwl4965_read_direct32(priv, reg); + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from %s %d\n", f, l); + IWL_DEBUG_IO("read_direct32(0x%4X) = 0x%08x - %s %d \n", reg, value, + f, l); + return value; +} +#define iwl4965_read_direct32(priv, reg) \ + __iwl4965_read_direct32(__FILE__, __LINE__, priv, reg) +#else +#define iwl4965_read_direct32 _iwl4965_read_direct32 +#endif + +static inline void _iwl4965_write_direct32(struct iwl4965_priv *priv, + u32 reg, u32 value) +{ + _iwl4965_write32(priv, reg, value); +} +#ifdef CONFIG_IWL4965_DEBUG +static void __iwl4965_write_direct32(u32 line, + struct iwl4965_priv *priv, u32 reg, u32 value) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + _iwl4965_write_direct32(priv, reg, value); +} +#define iwl4965_write_direct32(priv, reg, value) \ + __iwl4965_write_direct32(__LINE__, priv, reg, value) +#else +#define iwl4965_write_direct32 _iwl4965_write_direct32 +#endif + +static inline void iwl4965_write_reg_buf(struct iwl4965_priv *priv, + u32 reg, u32 len, u32 *values) +{ + u32 count = sizeof(u32); + + if ((priv != NULL) && (values != NULL)) { + for (; 0 < len; len -= count, reg += count, values++) + _iwl4965_write_direct32(priv, reg, *values); + } +} + +static inline int _iwl4965_poll_direct_bit(struct iwl4965_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int i = 0; + + do { + if ((_iwl4965_read_direct32(priv, addr) & mask) == mask) + return i; + mdelay(10); + i += 10; + } while (i < timeout); + + return -ETIMEDOUT; +} + +#ifdef CONFIG_IWL4965_DEBUG +static inline int __iwl4965_poll_direct_bit(const char *f, u32 l, + struct iwl4965_priv *priv, + u32 addr, u32 mask, int timeout) +{ + int ret = _iwl4965_poll_direct_bit(priv, addr, mask, timeout); + + if (unlikely(ret == -ETIMEDOUT)) + IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) - " + "timedout - %s %d\n", addr, mask, f, l); + else + IWL_DEBUG_IO("poll_direct_bit(0x%08X, 0x%08X) = 0x%08X " + "- %s %d\n", addr, mask, ret, f, l); + return ret; +} +#define iwl4965_poll_direct_bit(iwl, addr, mask, timeout) \ + __iwl4965_poll_direct_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) +#else +#define iwl4965_poll_direct_bit _iwl4965_poll_direct_bit +#endif + +static inline u32 _iwl4965_read_prph(struct iwl4965_priv *priv, u32 reg) +{ + _iwl4965_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + return _iwl4965_read_direct32(priv, HBUS_TARG_PRPH_RDAT); +} +#ifdef CONFIG_IWL4965_DEBUG +static inline u32 __iwl4965_read_prph(u32 line, struct iwl4965_priv *priv, u32 reg) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + return _iwl4965_read_prph(priv, reg); +} + +#define iwl4965_read_prph(priv, reg) \ + __iwl4965_read_prph(__LINE__, priv, reg) +#else +#define iwl4965_read_prph _iwl4965_read_prph +#endif + +static inline void _iwl4965_write_prph(struct iwl4965_priv *priv, + u32 addr, u32 val) +{ + _iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WADDR, + ((addr & 0x0000FFFF) | (3 << 24))); + _iwl4965_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); +} +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_write_prph(u32 line, struct iwl4965_priv *priv, + u32 addr, u32 val) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access from line %d\n", line); + _iwl4965_write_prph(priv, addr, val); +} + +#define iwl4965_write_prph(priv, addr, val) \ + __iwl4965_write_prph(__LINE__, priv, addr, val); +#else +#define iwl4965_write_prph _iwl4965_write_prph +#endif + +#define _iwl4965_set_bits_prph(priv, reg, mask) \ + _iwl4965_write_prph(priv, reg, (_iwl4965_read_prph(priv, reg) | mask)) +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_set_bits_prph(u32 line, struct iwl4965_priv *priv, + u32 reg, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + + _iwl4965_set_bits_prph(priv, reg, mask); +} +#define iwl4965_set_bits_prph(priv, reg, mask) \ + __iwl4965_set_bits_prph(__LINE__, priv, reg, mask) +#else +#define iwl4965_set_bits_prph _iwl4965_set_bits_prph +#endif + +#define _iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \ + _iwl4965_write_prph(priv, reg, ((_iwl4965_read_prph(priv, reg) & mask) | bits)) + +#ifdef CONFIG_IWL4965_DEBUG +static inline void __iwl4965_set_bits_mask_prph(u32 line, + struct iwl4965_priv *priv, u32 reg, u32 bits, u32 mask) +{ + if (!atomic_read(&priv->restrict_refcnt)) + IWL_ERROR("Nic access not held from line %d\n", line); + _iwl4965_set_bits_mask_prph(priv, reg, bits, mask); +} +#define iwl4965_set_bits_mask_prph(priv, reg, bits, mask) \ + __iwl4965_set_bits_mask_prph(__LINE__, priv, reg, bits, mask) +#else +#define iwl4965_set_bits_mask_prph _iwl4965_set_bits_mask_prph +#endif + +static inline void iwl4965_clear_bits_prph(struct iwl4965_priv + *priv, u32 reg, u32 mask) +{ + u32 val = _iwl4965_read_prph(priv, reg); + _iwl4965_write_prph(priv, reg, (val & ~mask)); +} + +static inline u32 iwl4965_read_targ_mem(struct iwl4965_priv *priv, u32 addr) +{ + iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + return iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT); +} + +static inline void iwl4965_write_targ_mem(struct iwl4965_priv *priv, u32 addr, u32 val) +{ + iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); +} + +static inline void iwl4965_write_targ_mem_buf(struct iwl4965_priv *priv, u32 addr, + u32 len, u32 *values) +{ + iwl4965_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + for (; 0 < len; len -= sizeof(u32), values++) + iwl4965_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); +} +#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 8dc78c0bf1ff..d06462264147 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -36,11 +36,9 @@ #include <linux/workqueue.h> -#define IWL 4965 - #include "../net/mac80211/ieee80211_rate.h" -#include "iwlwifi.h" +#include "iwl-4965.h" #include "iwl-helpers.h" #define RS_NAME "iwl-4965-rs" @@ -49,13 +47,12 @@ #define IWL_NUMBER_TRY 1 #define IWL_HT_NUMBER_TRY 3 -#define IWL_RATE_MAX_WINDOW 62 -#define IWL_RATE_HIGH_TH 10880 -#define IWL_RATE_MIN_FAILURE_TH 6 -#define IWL_RATE_MIN_SUCCESS_TH 8 -#define IWL_RATE_DECREASE_TH 1920 -#define IWL_RATE_INCREASE_TH 8960 -#define IWL_RATE_SCALE_FLUSH_INTVL (2*HZ) /*2 seconds */ +#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, @@ -67,83 +64,109 @@ static u8 rs_ht_to_legacy[] = { IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX }; -struct iwl_rate { +struct iwl4965_rate { u32 rate_n_flags; } __attribute__ ((packed)); -struct iwl_rate_scale_data { - u64 data; - s32 success_counter; - s32 success_ratio; - s32 counter; - s32 average_tpt; +/** + * 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 iwl_scale_tbl_info { - enum iwl_table_type lq_type; - enum iwl_antenna_type antenna_type; - u8 is_SGI; - u8 is_fat; - u8 is_dup; - u8 action; - s32 *expected_tpt; - struct iwl_rate current_rate; - struct iwl_rate_scale_data win[IWL_RATE_COUNT]; +/** + * struct iwl4965_scale_tbl_info -- tx params and success history for all rates + * + * There are two of these in struct iwl_rate_scale_priv, + * one for "active", and one for "search". + */ +struct iwl4965_scale_tbl_info { + enum iwl4965_table_type lq_type; + enum iwl4965_antenna_type antenna_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. */ + struct iwl4965_rate current_rate; /* rate_n_flags, uCode API format */ + struct iwl4965_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */ }; -struct iwl_rate_scale_priv { - u8 active_tbl; - u8 enable_counter; - u8 stay_in_tbl; - u8 search_better_tbl; +/** + * struct iwl_rate_scale_priv -- 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; - u32 max_success_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; - u32 total_success; - u32 flush_timer; - u8 action_counter; + 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 antenna; u8 valid_antenna; u8 is_green; u8 is_dup; u8 phymode; u8 ibss_sta_added; + + /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ u32 supp_rates; u16 active_rate; u16 active_siso_rate; u16 active_mimo_rate; u16 active_rate_basic; - struct iwl_link_quality_cmd lq; - struct iwl_scale_tbl_info lq_info[LQ_SIZE]; + + struct iwl4965_link_quality_cmd lq; + struct iwl4965_scale_tbl_info lq_info[LQ_SIZE]; /* "active", "search" */ #ifdef CONFIG_MAC80211_DEBUGFS struct dentry *rs_sta_dbgfs_scale_table_file; struct dentry *rs_sta_dbgfs_stats_table_file; - struct iwl_rate dbg_fixed; - struct iwl_priv *drv; + struct iwl4965_rate dbg_fixed; + struct iwl4965_priv *drv; #endif }; -static void rs_rate_scale_perform(struct iwl_priv *priv, +static void rs_rate_scale_perform(struct iwl4965_priv *priv, struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta); -static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, - struct iwl_rate *tx_mcs, - struct iwl_link_quality_cmd *tbl); +static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, + struct iwl4965_rate *tx_mcs, + struct iwl4965_link_quality_cmd *tbl); #ifdef CONFIG_MAC80211_DEBUGFS -static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, - struct iwl_rate *mcs, int index); +static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, + struct iwl4965_rate *mcs, int index); #else -static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, - struct iwl_rate *mcs, int index) +static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, + struct iwl4965_rate *mcs, 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). + */ static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -184,36 +207,34 @@ static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = { 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293 }; -static int iwl_lq_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) +static int iwl4965_lq_sync_callback(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct sk_buff *skb) { /*We didn't cache the SKB; let the caller free it */ return 1; } -static inline u8 iwl_rate_get_rate(u32 rate_n_flags) +static inline u8 iwl4965_rate_get_rate(u32 rate_n_flags) { return (u8)(rate_n_flags & 0xFF); } -static int rs_send_lq_cmd(struct iwl_priv *priv, - struct iwl_link_quality_cmd *lq, u8 flags) +static int rs_send_lq_cmd(struct iwl4965_priv *priv, + struct iwl4965_link_quality_cmd *lq, u8 flags) { -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG int i; #endif - int rc = -1; - - struct iwl_host_cmd cmd = { + struct iwl4965_host_cmd cmd = { .id = REPLY_TX_LINK_QUALITY_CMD, - .len = sizeof(struct iwl_link_quality_cmd), + .len = sizeof(struct iwl4965_link_quality_cmd), .meta.flags = flags, .data = lq, }; if ((lq->sta_id == 0xFF) && (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) - return rc; + return -EINVAL; if (lq->sta_id == 0xFF) lq->sta_id = IWL_AP_ID; @@ -222,23 +243,23 @@ static int rs_send_lq_cmd(struct iwl_priv *priv, IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk, lq->general_params.dual_stream_ant_msk); -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) IWL_DEBUG_RATE("lq index %d 0x%X\n", i, lq->rs_table[i].rate_n_flags); #endif if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_lq_sync_callback; + cmd.meta.u.callback = iwl4965_lq_sync_callback; - if (iwl_is_associated(priv) && priv->assoc_station_added && + if (iwl4965_is_associated(priv) && priv->assoc_station_added && priv->lq_mngr.lq_ready) - rc = iwl_send_cmd(priv, &cmd); + return iwl4965_send_cmd(priv, &cmd); - return rc; + return 0; } -static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) +static void rs_rate_scale_clear_window(struct iwl4965_rate_scale_data *window) { window->data = 0; window->success_counter = 0; @@ -246,29 +267,38 @@ static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) window->counter = 0; window->average_tpt = IWL_INVALID_VALUE; window->stamp = 0; - - return 0; } -static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, +/** + * 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, u32 status) { - int rc = 0; - struct iwl_rate_scale_data *window = NULL; + struct iwl4965_rate_scale_data *window = NULL; u64 mask; u8 win_size = IWL_RATE_MAX_WINDOW; s32 fail_count; - if (scale_index < 0) - return -1; - - if (scale_index >= IWL_RATE_COUNT) - return -1; + 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!). + */ if (window->counter >= win_size) { - window->counter = win_size - 1; mask = 1; mask = (mask << (win_size - 1)); @@ -278,7 +308,11 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, } } + /* Increment frames-attempted counter */ window->counter = window->counter + 1; + + /* Shift bitmap by one frame (throw away oldest history), + * OR in "1", and increment "success" if this frame was successful. */ mask = window->data; window->data = (mask << 1); if (status != 0) { @@ -286,6 +320,7 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, window->data |= 0x1; } + /* Calculate current success ratio, avoid divide-by-0! */ if (window->counter > 0) window->success_ratio = 128 * (100 * window->success_counter) / window->counter; @@ -294,37 +329,40 @@ static int rs_collect_tx_data(struct iwl_rate_scale_data *windows, 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 rc; + return 0; } -int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate, - struct iwl_scale_tbl_info *tbl, +/* + * Fill uCode API rate_n_flags field, based on "search" or "active" table. + */ +static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, + struct iwl4965_scale_tbl_info *tbl, int index, u8 use_green) { - int rc = 0; - if (is_legacy(tbl->lq_type)) { - mcs_rate->rate_n_flags = iwl_rates[index].plcp; + mcs_rate->rate_n_flags = iwl4965_rates[index].plcp; if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE) mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK; } else if (is_siso(tbl->lq_type)) { if (index > IWL_LAST_OFDM_RATE) index = IWL_LAST_OFDM_RATE; - mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso | + mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_siso | RATE_MCS_HT_MSK; } else { if (index > IWL_LAST_OFDM_RATE) index = IWL_LAST_OFDM_RATE; - mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo | + mcs_rate->rate_n_flags = iwl4965_rates[index].plcp_mimo | RATE_MCS_HT_MSK; } @@ -343,7 +381,7 @@ int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate, } if (is_legacy(tbl->lq_type)) - return rc; + return; if (tbl->is_fat) { if (tbl->is_dup) @@ -359,27 +397,31 @@ int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate, if (is_siso(tbl->lq_type)) mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK; } - return rc; } -static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate, - int phymode, struct iwl_scale_tbl_info *tbl, +/* + * Interpret uCode API's rate_n_flags format, + * fill "search" or "active" tx mode table. + */ +static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, + int phymode, struct iwl4965_scale_tbl_info *tbl, int *rate_idx) { int index; u32 ant_msk; - index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags); + index = iwl4965_rate_index_from_plcp(mcs_rate->rate_n_flags); if (index == IWL_RATE_INVALID) { *rate_idx = -1; - return -1; + return -EINVAL; } - tbl->is_SGI = 0; + tbl->is_SGI = 0; /* default legacy setup */ tbl->is_fat = 0; tbl->is_dup = 0; - tbl->antenna_type = ANT_BOTH; + tbl->antenna_type = ANT_BOTH; /* default MIMO setup */ + /* legacy rate format */ if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) { ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK); @@ -399,7 +441,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate, } *rate_idx = index; - } else if (iwl_rate_get_rate(mcs_rate->rate_n_flags) + /* HT rate format, SISO (might be 20 MHz legacy or 40 MHz fat width) */ + } else if (iwl4965_rate_get_rate(mcs_rate->rate_n_flags) <= IWL_RATE_SISO_60M_PLCP) { tbl->lq_type = LQ_SISO; @@ -423,6 +466,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate, tbl->is_dup = 1; *rate_idx = index; + + /* HT rate format, MIMO (might be 20 MHz legacy or 40 MHz fat width) */ } else { tbl->lq_type = LQ_MIMO; if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK) @@ -439,8 +484,8 @@ static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate, return 0; } -static inline void rs_toggle_antenna(struct iwl_rate *new_rate, - struct iwl_scale_tbl_info *tbl) +static inline void rs_toggle_antenna(struct iwl4965_rate *new_rate, + struct iwl4965_scale_tbl_info *tbl) { if (tbl->antenna_type == ANT_AUX) { tbl->antenna_type = ANT_MAIN; @@ -453,18 +498,15 @@ static inline void rs_toggle_antenna(struct iwl_rate *new_rate, } } -static inline s8 rs_use_green(struct iwl_priv *priv) +static inline u8 rs_use_green(struct iwl4965_priv *priv, + struct ieee80211_conf *conf) { - s8 rc = 0; -#ifdef CONFIG_IWLWIFI_HT - if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) - return 0; - - if ((priv->current_assoc_ht.is_green_field) && - !(priv->current_assoc_ht.operating_mode & 0x4)) - rc = 1; -#endif /*CONFIG_IWLWIFI_HT */ - return rc; +#ifdef CONFIG_IWL4965_HT + return ((conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + priv->current_ht_config.is_green_field && + !priv->current_ht_config.non_GF_STA_present); +#endif /* CONFIG_IWL4965_HT */ + return 0; } /** @@ -474,23 +516,24 @@ static inline s8 rs_use_green(struct iwl_priv *priv) * basic available rates. * */ -static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data, +static void rs_get_supported_rates(struct iwl4965_lq_sta *lq_sta, struct ieee80211_hdr *hdr, - enum iwl_table_type rate_type, + enum iwl4965_table_type rate_type, u16 *data_rate) { if (is_legacy(rate_type)) - *data_rate = lq_data->active_rate; + *data_rate = lq_sta->active_rate; else { if (is_siso(rate_type)) - *data_rate = lq_data->active_siso_rate; + *data_rate = lq_sta->active_siso_rate; else - *data_rate = lq_data->active_mimo_rate; + *data_rate = lq_sta->active_mimo_rate; } if (hdr && is_multicast_ether_addr(hdr->addr1) && - lq_data->active_rate_basic) - *data_rate = lq_data->active_rate_basic; + lq_sta->active_rate_basic) { + *data_rate = lq_sta->active_rate_basic; + } } static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) @@ -498,7 +541,7 @@ static u16 rs_get_adjacent_rate(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 adjascent rate in + /* 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; @@ -527,7 +570,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) low = index; while (low != IWL_RATE_INVALID) { - low = iwl_rates[low].prev_rs; + low = iwl4965_rates[low].prev_rs; if (low == IWL_RATE_INVALID) break; if (rate_mask & (1 << low)) @@ -537,7 +580,7 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) high = index; while (high != IWL_RATE_INVALID) { - high = iwl_rates[high].next_rs; + high = iwl4965_rates[high].next_rs; if (high == IWL_RATE_INVALID) break; if (rate_mask & (1 << high)) @@ -548,15 +591,15 @@ static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type) return (high << 8) | low; } -static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, - struct iwl_scale_tbl_info *tbl, u8 scale_index, - u8 ht_possible, struct iwl_rate *mcs_rate) +static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, + struct iwl4965_scale_tbl_info *tbl, u8 scale_index, + u8 ht_possible, struct iwl4965_rate *mcs_rate) { s32 low; u16 rate_mask; u16 high_low; u8 switch_to_legacy = 0; - u8 is_green = lq_data->is_green; + 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) @@ -564,7 +607,7 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { switch_to_legacy = 1; scale_index = rs_ht_to_legacy[scale_index]; - if (lq_data->phymode == MODE_IEEE80211A) + if (lq_sta->phymode == MODE_IEEE80211A) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; @@ -577,22 +620,22 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, tbl->is_SGI = 0; } - rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask); + rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask); - /* mask with station rate restriction */ + /* Mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { - if (lq_data->phymode == (u8) MODE_IEEE80211A) + /* supp_rates has no CCK bits in A mode */ + if (lq_sta->phymode == (u8) MODE_IEEE80211A) rate_mask = (u16)(rate_mask & - (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); + (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); else - rate_mask = (u16)(rate_mask & lq_data->supp_rates); + rate_mask = (u16)(rate_mask & lq_sta->supp_rates); } - /* if we did switched from HT to legacy check current rate */ - if ((switch_to_legacy) && - (rate_mask & (1 << scale_index))) { + /* If we switched from HT to legacy, check current rate */ + if (switch_to_legacy && (rate_mask & (1 << scale_index))) { rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); - return 0; + return; } high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type); @@ -602,29 +645,29 @@ static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data, rs_mcs_from_tbl(mcs_rate, tbl, low, is_green); else rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green); - - return 0; } -static void rs_tx_status(void *priv_rate, - struct net_device *dev, +/* + * mac80211 sends us Tx status + */ +static void rs_tx_status(void *priv_rate, struct net_device *dev, struct sk_buff *skb, struct ieee80211_tx_status *tx_resp) { int status; u8 retries; int rs_index, index = 0; - struct iwl_rate_scale_priv *lq; - struct iwl_link_quality_cmd *table; + struct iwl4965_lq_sta *lq_sta; + struct iwl4965_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 iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iwl_rate_scale_data *window = NULL; - struct iwl_rate_scale_data *search_win = NULL; - struct iwl_rate tx_mcs; - struct iwl_scale_tbl_info tbl_type; - struct iwl_scale_tbl_info *curr_tbl, *search_tbl; + struct iwl4965_rate_scale_data *window = NULL; + struct iwl4965_rate_scale_data *search_win = NULL; + struct iwl4965_rate tx_mcs; + struct iwl4965_scale_tbl_info tbl_type; + struct iwl4965_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; u16 fc = le16_to_cpu(hdr->frame_control); s32 tpt = 0; @@ -648,27 +691,32 @@ static void rs_tx_status(void *priv_rate, return; } - lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; if (!priv->lq_mngr.lq_ready) return; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !lq_sta->ibss_sta_added) return; - table = &lq->lq; - active_index = lq->active_tbl; + table = &lq_sta->lq; + active_index = lq_sta->active_tbl; - lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx); - if (!lq->antenna) - lq->antenna = lq->valid_antenna; + /* Get mac80211 antenna info */ + lq_sta->antenna = + (lq_sta->valid_antenna & local->hw.conf.antenna_sel_tx); + if (!lq_sta->antenna) + lq_sta->antenna = lq_sta->valid_antenna; - lq->antenna = lq->valid_antenna; - curr_tbl = &(lq->lq_info[active_index]); - search_tbl = &(lq->lq_info[(1 - active_index)]); - window = (struct iwl_rate_scale_data *) + /* Ignore mac80211 antenna info for now */ + lq_sta->antenna = lq_sta->valid_antenna; + + 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 iwl_rate_scale_data *) + search_win = (struct iwl4965_rate_scale_data *) &(search_tbl->win[0]); tx_mcs.rate_n_flags = tx_resp->control.tx_rate; @@ -682,6 +730,14 @@ static void rs_tx_status(void *priv_rate, return; } + /* + * 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). + */ if (retries && (tx_mcs.rate_n_flags != le32_to_cpu(table->rs_table[0].rate_n_flags))) { @@ -692,12 +748,17 @@ static void rs_tx_status(void *priv_rate, return; } + /* 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_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, &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.antenna_type == search_tbl->antenna_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { @@ -705,8 +766,10 @@ static void rs_tx_status(void *priv_rate, tpt = search_tbl->expected_tpt[rs_index]; else tpt = 0; - rs_collect_tx_data(search_win, - rs_index, tpt, 0); + rs_collect_tx_data(search_win, rs_index, tpt, 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.antenna_type == curr_tbl->antenna_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { @@ -716,13 +779,21 @@ static void rs_tx_status(void *priv_rate, tpt = 0; rs_collect_tx_data(window, rs_index, tpt, 0); } - if (lq->stay_in_tbl) - lq->total_failed++; + + /* 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. + */ if (!tx_resp->retry_count) tx_mcs.rate_n_flags = tx_resp->control.tx_rate; else @@ -732,11 +803,14 @@ static void rs_tx_status(void *priv_rate, rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, &tbl_type, &rs_index); + /* Update frame history window with "success" if Tx got ACKed ... */ if (tx_resp->flags & IEEE80211_TX_STATUS_ACK) status = 1; else status = 0; + /* If type matches "search" table, + * add final tx status to "search" history */ if ((tbl_type.lq_type == search_tbl->lq_type) && (tbl_type.antenna_type == search_tbl->antenna_type) && (tbl_type.is_SGI == search_tbl->is_SGI)) { @@ -746,6 +820,9 @@ static void rs_tx_status(void *priv_rate, tpt = 0; rs_collect_tx_data(search_win, rs_index, tpt, 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.antenna_type == curr_tbl->antenna_type) && (tbl_type.is_SGI == curr_tbl->is_SGI)) { @@ -756,67 +833,77 @@ static void rs_tx_status(void *priv_rate, rs_collect_tx_data(window, rs_index, tpt, status); } - if (lq->stay_in_tbl) { + /* 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 (status) - lq->total_success++; + lq_sta->total_success++; else - lq->total_failed++; + lq_sta->total_failed++; } + /* See if there's a better rate or modulation mode to try. */ rs_rate_scale_perform(priv, dev, hdr, sta); sta_info_put(sta); return; } static u8 rs_is_ant_connected(u8 valid_antenna, - enum iwl_antenna_type antenna_type) + enum iwl4965_antenna_type antenna_type) { if (antenna_type == ANT_AUX) return ((valid_antenna & 0x2) ? 1:0); else if (antenna_type == ANT_MAIN) return ((valid_antenna & 0x1) ? 1:0); - else if (antenna_type == ANT_BOTH) { - if ((valid_antenna & 0x3) == 0x3) - return 1; - else - return 0; - } + else if (antenna_type == ANT_BOTH) + return ((valid_antenna & 0x3) == 0x3); return 1; } static u8 rs_is_other_ant_connected(u8 valid_antenna, - enum iwl_antenna_type antenna_type) + enum iwl4965_antenna_type antenna_type) { if (antenna_type == ANT_AUX) - return (rs_is_ant_connected(valid_antenna, ANT_MAIN)); + return rs_is_ant_connected(valid_antenna, ANT_MAIN); else - return (rs_is_ant_connected(valid_antenna, ANT_AUX)); + return rs_is_ant_connected(valid_antenna, ANT_AUX); return 0; } +/* + * 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(u8 is_legacy, - struct iwl_rate_scale_priv *lq_data) + struct iwl4965_lq_sta *lq_sta) { IWL_DEBUG_HT("we are staying in the same table\n"); - lq_data->stay_in_tbl = 1; + lq_sta->stay_in_tbl = 1; /* only place this gets set */ if (is_legacy) { - lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT; - lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT; - lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT; + 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_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT; - lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT; - lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT; + 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_data->table_count = 0; - lq_data->total_failed = 0; - lq_data->total_success = 0; + lq_sta->table_count = 0; + lq_sta->total_failed = 0; + lq_sta->total_success = 0; } -static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, - struct iwl_scale_tbl_info *tbl) +/* + * Find correct throughput table for given mode of modulation + */ +static void rs_get_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)) @@ -824,7 +911,7 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, else tbl->expected_tpt = expected_tpt_A; } else if (is_siso(tbl->lq_type)) { - if (tbl->is_fat && !lq_data->is_dup) + if (tbl->is_fat && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_siso40MHzSGI; else @@ -835,7 +922,7 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, tbl->expected_tpt = expected_tpt_siso20MHz; } else if (is_mimo(tbl->lq_type)) { - if (tbl->is_fat && !lq_data->is_dup) + if (tbl->is_fat && !lq_sta->is_dup) if (tbl->is_SGI) tbl->expected_tpt = expected_tpt_mimo40MHzSGI; else @@ -848,18 +935,34 @@ static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data, tbl->expected_tpt = expected_tpt_G; } -#ifdef CONFIG_IWLWIFI_HT -static s32 rs_get_best_rate(struct iwl_priv *priv, - struct iwl_rate_scale_priv *lq_data, - struct iwl_scale_tbl_info *tbl, +#ifdef CONFIG_IWL4965_HT +/* + * 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 iwl4965_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct iwl4965_scale_tbl_info *tbl, /* "search" */ u16 rate_mask, s8 index, s8 rate) { - struct iwl_scale_tbl_info *active_tbl = - &(lq_data->lq_info[lq_data->active_tbl]); - s32 new_rate, high, low, start_hi; + /* "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 *tpt_tbl = tbl->expected_tpt; 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; new_rate = high = low = start_hi = IWL_RATE_INVALID; @@ -870,28 +973,60 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, low = high_low & 0xff; high = (high_low >> 8) & 0xff; - if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) && + /* + * 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 { new_rate = rate; break; @@ -901,58 +1036,64 @@ static s32 rs_get_best_rate(struct iwl_priv *priv, return new_rate; } -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT */ static inline u8 rs_is_both_ant_supp(u8 valid_antenna) { return (rs_is_ant_connected(valid_antenna, ANT_BOTH)); } -static int rs_switch_to_mimo(struct iwl_priv *priv, - struct iwl_rate_scale_priv *lq_data, - struct iwl_scale_tbl_info *tbl, int index) +/* + * Set up search table for MIMO + */ +static int rs_switch_to_mimo(struct iwl4965_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, + struct iwl4965_scale_tbl_info *tbl, int index) { - int rc = -1; -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT u16 rate_mask; s32 rate; - s8 is_green = lq_data->is_green; + s8 is_green = lq_sta->is_green; - if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || + !sta->ht_info.ht_supported) return -1; IWL_DEBUG_HT("LQ: try to switch to MIMO\n"); tbl->lq_type = LQ_MIMO; - rs_get_supported_rates(lq_data, NULL, tbl->lq_type, + rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask); - if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) + if (priv->current_ht_config.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC) return -1; - if (!rs_is_both_ant_supp(lq_data->antenna)) + /* Need both Tx chains/antennas to support MIMO */ + if (!rs_is_both_ant_supp(lq_sta->antenna)) return -1; - rc = 0; - tbl->is_dup = lq_data->is_dup; + tbl->is_dup = lq_sta->is_dup; tbl->action = 0; - if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) + if (priv->current_ht_config.supported_chan_width + == IWL_CHANNEL_WIDTH_40MHZ) tbl->is_fat = 1; else tbl->is_fat = 0; if (tbl->is_fat) { - if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) + if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; - } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) + } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; - rs_get_expected_tpt_table(lq_data, tbl); + rs_get_expected_tpt_table(lq_sta, tbl); - rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) @@ -961,43 +1102,49 @@ static int rs_switch_to_mimo(struct iwl_priv *priv, IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate.rate_n_flags, is_green); - -#endif /*CONFIG_IWLWIFI_HT */ - return rc; + return 0; +#else + return -1; +#endif /*CONFIG_IWL4965_HT */ } -static int rs_switch_to_siso(struct iwl_priv *priv, - struct iwl_rate_scale_priv *lq_data, - struct iwl_scale_tbl_info *tbl, int index) +/* + * Set up search table for SISO + */ +static int rs_switch_to_siso(struct iwl4965_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, + struct iwl4965_scale_tbl_info *tbl, int index) { - int rc = -1; -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT u16 rate_mask; - u8 is_green = lq_data->is_green; + u8 is_green = lq_sta->is_green; s32 rate; IWL_DEBUG_HT("LQ: try to switch to SISO\n"); - if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht) + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || + !sta->ht_info.ht_supported) return -1; - rc = 0; - tbl->is_dup = lq_data->is_dup; + tbl->is_dup = lq_sta->is_dup; tbl->lq_type = LQ_SISO; tbl->action = 0; - rs_get_supported_rates(lq_data, NULL, tbl->lq_type, + rs_get_supported_rates(lq_sta, NULL, tbl->lq_type, &rate_mask); - if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ) + if (priv->current_ht_config.supported_chan_width + == IWL_CHANNEL_WIDTH_40MHZ) tbl->is_fat = 1; else tbl->is_fat = 0; if (tbl->is_fat) { - if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY) + if (priv->current_ht_config.sgf & HT_SHORT_GI_40MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; - } else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY) + } else if (priv->current_ht_config.sgf & HT_SHORT_GI_20MHZ_ONLY) tbl->is_SGI = 1; else tbl->is_SGI = 0; @@ -1005,8 +1152,8 @@ static int rs_switch_to_siso(struct iwl_priv *priv, if (is_green) tbl->is_SGI = 0; - rs_get_expected_tpt_table(lq_data, tbl); - rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index); + rs_get_expected_tpt_table(lq_sta, tbl); + rate = rs_get_best_rate(priv, lq_sta, tbl, rate_mask, index, index); IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask); if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) { @@ -1017,23 +1164,30 @@ static int rs_switch_to_siso(struct iwl_priv *priv, rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green); IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n", tbl->current_rate.rate_n_flags, is_green); + return 0; +#else + return -1; -#endif /*CONFIG_IWLWIFI_HT */ - return rc; +#endif /*CONFIG_IWL4965_HT */ } -static int rs_move_legacy_other(struct iwl_priv *priv, - struct iwl_rate_scale_priv *lq_data, +/* + * Try to switch to new modulation mode from legacy + */ +static int rs_move_legacy_other(struct iwl4965_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, int index) { - int rc = 0; - struct iwl_scale_tbl_info *tbl = - &(lq_data->lq_info[lq_data->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_data->lq_info[(1 - lq_data->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)); + int ret = 0; + 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; for (; ;) { @@ -1042,52 +1196,59 @@ static int rs_move_legacy_other(struct iwl_priv *priv, IWL_DEBUG_HT("LQ Legacy switch Antenna\n"); search_tbl->lq_type = LQ_NONE; - lq_data->action_counter++; + lq_sta->action_counter++; + + /* Don't change antenna if success has been great */ if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - if (!rs_is_other_ant_connected(lq_data->antenna, + + /* Don't change antenna if other one is not connected */ + if (!rs_is_other_ant_connected(lq_sta->antenna, tbl->antenna_type)) break; + /* Set up search table to try other antenna */ memcpy(search_tbl, tbl, sz); rs_toggle_antenna(&(search_tbl->current_rate), search_tbl); - rs_get_expected_tpt_table(lq_data, search_tbl); - lq_data->search_better_tbl = 1; + rs_get_expected_tpt_table(lq_sta, search_tbl); + lq_sta->search_better_tbl = 1; goto out; case IWL_LEGACY_SWITCH_SISO: IWL_DEBUG_HT("LQ: Legacy switch to SISO\n"); + + /* Set up search table to try SISO */ memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_SISO; search_tbl->is_SGI = 0; search_tbl->is_fat = 0; - rc = rs_switch_to_siso(priv, lq_data, search_tbl, - index); - if (!rc) { - lq_data->search_better_tbl = 1; - lq_data->action_counter = 0; - } - if (!rc) + 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_MIMO: IWL_DEBUG_HT("LQ: Legacy switch MIMO\n"); + + /* Set up search table to try MIMO */ memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_MIMO; search_tbl->is_SGI = 0; search_tbl->is_fat = 0; search_tbl->antenna_type = ANT_BOTH; - rc = rs_switch_to_mimo(priv, lq_data, search_tbl, - index); - if (!rc) { - lq_data->search_better_tbl = 1; - lq_data->action_counter = 0; - } - if (!rc) + ret = rs_switch_to_mimo(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++; @@ -1108,30 +1269,35 @@ static int rs_move_legacy_other(struct iwl_priv *priv, } -static int rs_move_siso_to_other(struct iwl_priv *priv, - struct iwl_rate_scale_priv *lq_data, +/* + * Try to switch to new modulation mode from SISO + */ +static int rs_move_siso_to_other(struct iwl4965_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, int index) { - int rc = -1; - u8 is_green = lq_data->is_green; - struct iwl_scale_tbl_info *tbl = - &(lq_data->lq_info[lq_data->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_data->lq_info[(1 - lq_data->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)); + int ret; + 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; for (;;) { - lq_data->action_counter++; + lq_sta->action_counter++; switch (tbl->action) { case IWL_SISO_SWITCH_ANTENNA: IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n"); search_tbl->lq_type = LQ_NONE; if (window->success_ratio >= IWL_RS_GOOD_RATIO) break; - if (!rs_is_other_ant_connected(lq_data->antenna, + if (!rs_is_other_ant_connected(lq_sta->antenna, tbl->antenna_type)) break; @@ -1139,7 +1305,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, search_tbl->action = IWL_SISO_SWITCH_MIMO; rs_toggle_antenna(&(search_tbl->current_rate), search_tbl); - lq_data->search_better_tbl = 1; + lq_sta->search_better_tbl = 1; goto out; @@ -1150,13 +1316,12 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, search_tbl->is_SGI = 0; search_tbl->is_fat = 0; search_tbl->antenna_type = ANT_BOTH; - rc = rs_switch_to_mimo(priv, lq_data, search_tbl, - index); - if (!rc) - lq_data->search_better_tbl = 1; - - if (!rc) + ret = rs_switch_to_mimo(priv, lq_sta, conf, sta, + search_tbl, index); + if (!ret) { + lq_sta->search_better_tbl = 1; goto out; + } break; case IWL_SISO_SWITCH_GI: IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n"); @@ -1168,17 +1333,17 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, search_tbl->is_SGI = 1; else break; - lq_data->search_better_tbl = 1; + lq_sta->search_better_tbl = 1; if ((tbl->lq_type == LQ_SISO) && (tbl->is_SGI)) { - s32 tpt = lq_data->last_tpt / 100; + s32 tpt = lq_sta->last_tpt / 100; if (((!tbl->is_fat) && (tpt >= expected_tpt_siso20MHz[index])) || ((tbl->is_fat) && (tpt >= expected_tpt_siso40MHz[index]))) - lq_data->search_better_tbl = 0; + lq_sta->search_better_tbl = 0; } - rs_get_expected_tpt_table(lq_data, search_tbl); + rs_get_expected_tpt_table(lq_sta, search_tbl); rs_mcs_from_tbl(&search_tbl->current_rate, search_tbl, index, is_green); goto out; @@ -1199,26 +1364,33 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, return 0; } -static int rs_move_mimo_to_other(struct iwl_priv *priv, - struct iwl_rate_scale_priv *lq_data, +/* + * Try to switch to new modulation mode from MIMO + */ +static int rs_move_mimo_to_other(struct iwl4965_priv *priv, + struct iwl4965_lq_sta *lq_sta, + struct ieee80211_conf *conf, + struct sta_info *sta, int index) { - int rc = -1; - s8 is_green = lq_data->is_green; - struct iwl_scale_tbl_info *tbl = - &(lq_data->lq_info[lq_data->active_tbl]); - struct iwl_scale_tbl_info *search_tbl = - &(lq_data->lq_info[(1 - lq_data->active_tbl)]); - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); + int ret; + 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; for (;;) { - lq_data->action_counter++; + lq_sta->action_counter++; switch (tbl->action) { case IWL_MIMO_SWITCH_ANTENNA_A: case IWL_MIMO_SWITCH_ANTENNA_B: IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n"); + + /* Set up new search table for SISO */ memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_SISO; search_tbl->is_SGI = 0; @@ -1228,16 +1400,18 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, else search_tbl->antenna_type = ANT_AUX; - rc = rs_switch_to_siso(priv, lq_data, search_tbl, - index); - if (!rc) { - lq_data->search_better_tbl = 1; + 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: IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n"); + + /* Set up new search table for MIMO */ memcpy(search_tbl, tbl, sz); search_tbl->lq_type = LQ_MIMO; search_tbl->antenna_type = ANT_BOTH; @@ -1246,17 +1420,24 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, search_tbl->is_SGI = 0; else search_tbl->is_SGI = 1; - lq_data->search_better_tbl = 1; + lq_sta->search_better_tbl = 1; + + /* + * 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->lq_type == LQ_MIMO) && (tbl->is_SGI)) { - s32 tpt = lq_data->last_tpt / 100; + s32 tpt = lq_sta->last_tpt / 100; if (((!tbl->is_fat) && (tpt >= expected_tpt_mimo20MHz[index])) || ((tbl->is_fat) && (tpt >= expected_tpt_mimo40MHz[index]))) - lq_data->search_better_tbl = 0; + lq_sta->search_better_tbl = 0; } - rs_get_expected_tpt_table(lq_data, search_tbl); + rs_get_expected_tpt_table(lq_sta, search_tbl); rs_mcs_from_tbl(&search_tbl->current_rate, search_tbl, index, is_green); goto out; @@ -1279,43 +1460,71 @@ static int rs_move_mimo_to_other(struct iwl_priv *priv, } -static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data) +/* + * 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 iwl_scale_tbl_info *tbl; + struct iwl4965_scale_tbl_info *tbl; int i; int active_tbl; int flush_interval_passed = 0; - active_tbl = lq_data->active_tbl; + active_tbl = lq_sta->active_tbl; - tbl = &(lq_data->lq_info[active_tbl]); + tbl = &(lq_sta->lq_info[active_tbl]); - if (lq_data->stay_in_tbl) { + /* If we've been disallowing search, see if we should now allow it */ + if (lq_sta->stay_in_tbl) { - if (lq_data->flush_timer) + /* Elapsed time using current modulation mode */ + if (lq_sta->flush_timer) flush_interval_passed = time_after(jiffies, - (unsigned long)(lq_data->flush_timer + + (unsigned long)(lq_sta->flush_timer + IWL_RATE_SCALE_FLUSH_INTVL)); + /* For now, disable the elapsed time criterion */ flush_interval_passed = 0; - if ((lq_data->total_failed > lq_data->max_failure_limit) || - (lq_data->total_success > lq_data->max_success_limit) || - ((!lq_data->search_better_tbl) && (lq_data->flush_timer) + + /* + * 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_HT("LQ: stay is expired %d %d %d\n:", - lq_data->total_failed, - lq_data->total_success, + lq_sta->total_failed, + lq_sta->total_success, flush_interval_passed); - lq_data->stay_in_tbl = 0; - lq_data->total_failed = 0; - lq_data->total_success = 0; - lq_data->flush_timer = 0; - } else if (lq_data->table_count > 0) { - lq_data->table_count++; - if (lq_data->table_count >= - lq_data->table_count_limit) { - lq_data->table_count = 0; + + /* 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_HT("LQ: stay in table clear win\n"); for (i = 0; i < IWL_RATE_COUNT; i++) @@ -1324,23 +1533,32 @@ static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data) } } - if (!lq_data->stay_in_tbl) { + /* 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])); } } } -static void rs_rate_scale_perform(struct iwl_priv *priv, +/* + * Do rate scaling and search for new modulation mode. + */ +static void rs_rate_scale_perform(struct iwl4965_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; + 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; @@ -1348,10 +1566,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, s8 scale_action = 0; u16 fc, rate_mask; u8 update_lq = 0; - struct iwl_rate_scale_priv *lq_data; - struct iwl_scale_tbl_info *tbl, *tbl1; + struct iwl4965_lq_sta *lq_sta; + struct iwl4965_scale_tbl_info *tbl, *tbl1; u16 rate_scale_index_msk = 0; - struct iwl_rate mcs_rate; + struct iwl4965_rate mcs_rate; u8 is_green = 0; u8 active_tbl = 0; u8 done_search = 0; @@ -1374,34 +1592,42 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE("still rate scaling not ready\n"); return; } - lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - if (!lq_data->search_better_tbl) - active_tbl = lq_data->active_tbl; + /* + * 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_data->active_tbl; + active_tbl = 1 - lq_sta->active_tbl; - tbl = &(lq_data->lq_info[active_tbl]); - is_green = lq_data->is_green; + tbl = &(lq_sta->lq_info[active_tbl]); + is_green = lq_sta->is_green; + /* current tx rate */ index = sta->last_txrate; IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, tbl->lq_type); - rs_get_supported_rates(lq_data, hdr, tbl->lq_type, + /* rates available for this association, and for modulation mode */ + rs_get_supported_rates(lq_sta, hdr, tbl->lq_type, &rate_mask); IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask); /* mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { - if (lq_data->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->phymode == (u8) MODE_IEEE80211A) + /* supp_rates has no CCK bits in A mode */ rate_scale_index_msk = (u16) (rate_mask & - (lq_data->supp_rates << IWL_FIRST_OFDM_RATE)); + (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); else rate_scale_index_msk = (u16) (rate_mask & - lq_data->supp_rates); + lq_sta->supp_rates); } else rate_scale_index_msk = rate_mask; @@ -1409,11 +1635,13 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, if (!rate_scale_index_msk) rate_scale_index_msk = rate_mask; + /* If current rate is no longer supported on current association, + * or user changed preferences for rates, find a new supported rate. */ if (index < 0 || !((1 << index) & rate_scale_index_msk)) { index = IWL_INVALID_VALUE; update_lq = 1; - /* get the lowest availabe rate */ + /* get the highest available rate */ for (i = 0; i <= IWL_RATE_COUNT; i++) { if ((1 << i) & rate_scale_index_msk) index = i; @@ -1425,11 +1653,19 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, } } + /* Get expected throughput table and history window for current rate */ if (!tbl->expected_tpt) - rs_get_expected_tpt_table(lq_data, tbl); + rs_get_expected_tpt_table(lq_sta, tbl); 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)) @@ -1437,82 +1673,118 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, 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; - rs_stay_in_table(lq_data); + + /* Should we stay with this modulation mode, + * or search for a new one? */ + rs_stay_in_table(lq_sta); + + /* Set up new rate table in uCode, if needed */ if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); - rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } goto out; + /* Else we have enough samples; calculate estimate of + * actual average throughput */ } else window->average_tpt = ((window->success_ratio * tbl->expected_tpt[index] + 64) / 128); - if (lq_data->search_better_tbl) { + /* If we are searching for better modulation mode, check success. */ + if (lq_sta->search_better_tbl) { int success_limit = IWL_RATE_SCALE_SWITCH; + /* 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->success_ratio > success_limit) || - (window->average_tpt > lq_data->last_tpt)) { + (window->average_tpt > lq_sta->last_tpt)) { if (!is_legacy(tbl->lq_type)) { IWL_DEBUG_HT("LQ: we are switching to HT" " rate suc %d current tpt %d" " old tpt %d\n", window->success_ratio, window->average_tpt, - lq_data->last_tpt); - lq_data->enable_counter = 1; + lq_sta->last_tpt); + lq_sta->enable_counter = 1; } - lq_data->active_tbl = active_tbl; + /* 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 { + /* Nullify "search" table */ tbl->lq_type = LQ_NONE; - active_tbl = lq_data->active_tbl; - tbl = &(lq_data->lq_info[active_tbl]); - index = iwl_rate_index_from_plcp( + /* 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 = iwl4965_rate_index_from_plcp( tbl->current_rate.rate_n_flags); + current_tpt = lq_sta->last_tpt; + /* Need to set up a new rate table in uCode */ update_lq = 1; - current_tpt = lq_data->last_tpt; IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n"); } - lq_data->search_better_tbl = 0; - done_search = 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(index, rate_scale_index_msk, tbl->lq_type); low = high_low & 0xff; high = (high_low >> 8) & 0xff; + /* 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; - + /* Assume rate increase */ scale_action = 1; + /* Too many failures, decrease rate */ if ((window->success_ratio <= 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)) 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) scale_action = 1; else { @@ -1520,7 +1792,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, ("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"); @@ -1530,23 +1805,30 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, } } + /* Sanity check; asked for decrease, but success rate or throughput + * has been good at old rate. Don't change it. */ if (scale_action == -1) { if ((low != IWL_RATE_INVALID) && ((window->success_ratio > IWL_RATE_HIGH_TH) || (current_tpt > (100 * tbl->expected_tpt[low])))) scale_action = 0; + + /* Sanity check; asked for increase, but success rate has not been great + * even at old rate, higher rate will be worse. Don't change it. */ } else if ((scale_action == 1) && (window->success_ratio < IWL_RATE_INCREASE_TH)) 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; @@ -1554,6 +1836,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, break; case 0: + /* No change */ default: break; } @@ -1563,65 +1846,97 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, index, scale_action, low, high, tbl->lq_type); lq_update: + /* Replace uCode's rate table for the destination station. */ if (update_lq) { rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green); - rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq); - rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } - rs_stay_in_table(lq_data); - if (!update_lq && !done_search && !lq_data->stay_in_tbl) { - lq_data->last_tpt = current_tpt; + /* 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) { + /* 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_data, index); + rs_move_legacy_other(priv, lq_sta, conf, sta, index); else if (is_siso(tbl->lq_type)) - rs_move_siso_to_other(priv, lq_data, index); + rs_move_siso_to_other(priv, lq_sta, conf, sta, index); else - rs_move_mimo_to_other(priv, lq_data, index); + rs_move_mimo_to_other(priv, lq_sta, conf, sta, index); - if (lq_data->search_better_tbl) { - tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]); + /* 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])); - index = iwl_rate_index_from_plcp( + /* Use new "search" start rate */ + index = iwl4965_rate_index_from_plcp( tbl->current_rate.rate_n_flags); IWL_DEBUG_HT("Switch current mcs: %X index: %d\n", tbl->current_rate.rate_n_flags, index); - rs_fill_link_cmd(lq_data, &tbl->current_rate, - &lq_data->lq); - rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC); + rs_fill_link_cmd(lq_sta, &tbl->current_rate, + &lq_sta->lq); + rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); } - tbl1 = &(lq_data->lq_info[lq_data->active_tbl]); + /* 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) && -#ifdef CONFIG_IWLWIFI_HT - !priv->current_assoc_ht.is_ht && +#ifdef CONFIG_IWL4965_HT + (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && #endif - (lq_data->action_counter >= 1)) { - lq_data->action_counter = 0; + (lq_sta->action_counter >= 1)) { + lq_sta->action_counter = 0; IWL_DEBUG_HT("LQ: STAY in legacy table\n"); - rs_set_stay_in_table(1, lq_data); + rs_set_stay_in_table(1, lq_sta); } - if (lq_data->enable_counter && - (lq_data->action_counter >= IWL_ACTION_LIMIT)) { -#ifdef CONFIG_IWLWIFI_HT_AGG - if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) && + /* 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)) { +#ifdef CONFIG_IWL4965_HT_AGG + /* If appropriate, set up aggregation! */ + if ((lq_sta->last_tpt > TID_AGG_TPT_THREHOLD) && (priv->lq_mngr.agg_ctrl.auto_agg)) { priv->lq_mngr.agg_ctrl.tid_retry = TID_ALL_SPECIFIED; schedule_work(&priv->agg_work); } -#endif /*CONFIG_IWLWIFI_HT_AGG */ - lq_data->action_counter = 0; - rs_set_stay_in_table(0, lq_data); +#endif /*CONFIG_IWL4965_HT_AGG */ + lq_sta->action_counter = 0; + rs_set_stay_in_table(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_data->flush_timer)) - lq_data->flush_timer = jiffies; + if ((!update_lq) && (!done_search) && (!lq_sta->flush_timer)) + lq_sta->flush_timer = jiffies; } out: @@ -1632,7 +1947,7 @@ out: /* sta->txrate is an index to A mode rates which start * at IWL_FIRST_OFDM_RATE */ - if (lq_data->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->phymode == (u8) MODE_IEEE80211A) sta->txrate = i - IWL_FIRST_OFDM_RATE; else sta->txrate = i; @@ -1641,38 +1956,39 @@ out: } -static void rs_initialize_lq(struct iwl_priv *priv, +static void rs_initialize_lq(struct iwl4965_priv *priv, + struct ieee80211_conf *conf, struct sta_info *sta) { int i; - struct iwl_rate_scale_priv *lq; - struct iwl_scale_tbl_info *tbl; + struct iwl4965_lq_sta *lq_sta; + struct iwl4965_scale_tbl_info *tbl; u8 active_tbl = 0; int rate_idx; - u8 use_green = rs_use_green(priv); - struct iwl_rate mcs_rate; + u8 use_green = rs_use_green(priv, conf); + struct iwl4965_rate mcs_rate; if (!sta || !sta->rate_ctrl_priv) goto out; - lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; i = sta->last_txrate; - if ((lq->lq.sta_id == 0xff) && + if ((lq_sta->lq.sta_id == 0xff) && (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) goto out; - if (!lq->search_better_tbl) - active_tbl = lq->active_tbl; + if (!lq_sta->search_better_tbl) + active_tbl = lq_sta->active_tbl; else - active_tbl = 1 - lq->active_tbl; + active_tbl = 1 - lq_sta->active_tbl; - tbl = &(lq->lq_info[active_tbl]); + tbl = &(lq_sta->lq_info[active_tbl]); if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - mcs_rate.rate_n_flags = iwl_rates[i].plcp ; + mcs_rate.rate_n_flags = iwl4965_rates[i].plcp ; mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK; mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK; @@ -1686,114 +2002,95 @@ static void rs_initialize_lq(struct iwl_priv *priv, rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green); tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags; - rs_get_expected_tpt_table(lq, tbl); - rs_fill_link_cmd(lq, &mcs_rate, &lq->lq); - rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC); + rs_get_expected_tpt_table(lq_sta, tbl); + rs_fill_link_cmd(lq_sta, &mcs_rate, &lq_sta->lq); + rs_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); out: return; } -static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local - *local) -{ - struct ieee80211_hw_mode *mode = local->oper_hw_mode; - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - if (rate->flags & IEEE80211_RATE_SUPPORTED) - return rate; - } - - return &mode->rates[0]; -} - -static struct ieee80211_rate *rs_get_rate(void *priv_rate, - struct net_device *dev, - struct sk_buff *skb, - struct rate_control_extra - *extra) +static void rs_get_rate(void *priv_rate, struct net_device *dev, + struct ieee80211_hw_mode *mode, 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; u16 fc; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct iwl_rate_scale_priv *lq; + struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; + struct iwl4965_lq_sta *lq_sta; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); - memset(extra, 0, sizeof(*extra)); - - fc = le16_to_cpu(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 rs_get_lowest_rate(local); - } - sta = sta_info_get(local, hdr->addr1); - if (!sta || !sta->rate_ctrl_priv) { + /* Send management frames and broadcast/multicast data using lowest + * rate. */ + fc = le16_to_cpu(hdr->frame_control); + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta || !sta->rate_ctrl_priv) { + sel->rate = rate_lowest(local, local->oper_hw_mode, sta); if (sta) sta_info_put(sta); - return rs_get_lowest_rate(local); + return; } - lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv; + lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; i = sta->last_txrate; - if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) { - u8 sta_id = iwl_hw_find_station(priv, hdr->addr1); + if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && + !lq_sta->ibss_sta_added) { + u8 sta_id = iwl4965_hw_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(priv, - hdr->addr1, 0, CMD_ASYNC); + sta_id = iwl4965_add_station_flags(priv, hdr->addr1, + 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { - lq->lq.sta_id = sta_id; - lq->lq.rs_table[0].rate_n_flags = 0; - lq->ibss_sta_added = 1; - rs_initialize_lq(priv, sta); + 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 (!lq->ibss_sta_added) + if (!lq_sta->ibss_sta_added) goto done; } done: + if ((i < 0) || (i > IWL_RATE_COUNT)) { + sel->rate = rate_lowest(local, local->oper_hw_mode, sta); + return; + } sta_info_put(sta); - if ((i < 0) || (i > IWL_RATE_COUNT)) - return rs_get_lowest_rate(local); - return &priv->ieee_rates[i]; + sel->rate = &priv->ieee_rates[i]; } static void *rs_alloc_sta(void *priv, gfp_t gfp) { - struct iwl_rate_scale_priv *crl; + struct iwl4965_lq_sta *lq_sta; int i, j; IWL_DEBUG_RATE("create station rate scale window\n"); - crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp); + lq_sta = kzalloc(sizeof(struct iwl4965_lq_sta), gfp); - if (crl == NULL) + if (lq_sta == NULL) return NULL; - crl->lq.sta_id = 0xff; + 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(&(crl->lq_info[j].win[i])); + rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); - return crl; + return lq_sta; } static void rs_rate_init(void *priv_rate, void *priv_sta, @@ -1801,16 +2098,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, struct sta_info *sta) { int i, j; + struct ieee80211_conf *conf = &local->hw.conf; struct ieee80211_hw_mode *mode = local->oper_hw_mode; - struct iwl_priv *priv = (struct iwl_priv *)priv_rate; - struct iwl_rate_scale_priv *crl = priv_sta; + struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; + struct iwl4965_lq_sta *lq_sta = priv_sta; - crl->flush_timer = 0; - crl->supp_rates = sta->supp_rates; + lq_sta->flush_timer = 0; + lq_sta->supp_rates = sta->supp_rates; sta->txrate = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) - rs_rate_scale_clear_window(&(crl->lq_info[j].win[i])); + rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); IWL_DEBUG_RATE("rate scale global init\n"); /* TODO: what is a good starting rate for STA? About middle? Maybe not @@ -1818,9 +2116,9 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - crl->ibss_sta_added = 0; + lq_sta->ibss_sta_added = 0; if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { - u8 sta_id = iwl_hw_find_station(priv, sta->addr); + u8 sta_id = iwl4965_hw_find_station(priv, sta->addr); DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ @@ -1830,77 +2128,89 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_RATE("LQ: ADD station %s\n", print_mac(mac, sta->addr)); - sta_id = iwl_add_station(priv, - sta->addr, 0, CMD_ASYNC); + sta_id = iwl4965_add_station_flags(priv, sta->addr, + 0, CMD_ASYNC, NULL); } if ((sta_id != IWL_INVALID_STATION)) { - crl->lq.sta_id = sta_id; - crl->lq.rs_table[0].rate_n_flags = 0; + 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 < mode->num_rates; i++) { if ((sta->supp_rates & BIT(i)) && (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) sta->txrate = i; } sta->last_txrate = sta->txrate; - /* For MODE_IEEE80211A mode cck rate are at end - * rate table - */ + /* For MODE_IEEE80211A, cck rates are at end of rate table */ if (local->hw.conf.phymode == MODE_IEEE80211A) sta->last_txrate += IWL_FIRST_OFDM_RATE; - crl->is_dup = priv->is_dup; - crl->valid_antenna = priv->valid_antenna; - crl->antenna = priv->antenna; - crl->is_green = rs_use_green(priv); - crl->active_rate = priv->active_rate; - crl->active_rate &= ~(0x1000); - crl->active_rate_basic = priv->active_rate_basic; - crl->phymode = priv->phymode; -#ifdef CONFIG_IWLWIFI_HT - crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1); - crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1); - crl->active_siso_rate &= ~((u16)0x2); - crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE; - - crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1); - crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1); - crl->active_mimo_rate &= ~((u16)0x2); - crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE; - IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate, - crl->active_mimo_rate); -#endif /*CONFIG_IWLWIFI_HT*/ + lq_sta->is_dup = 0; + lq_sta->valid_antenna = priv->valid_antenna; + lq_sta->antenna = priv->antenna; + lq_sta->is_green = rs_use_green(priv, conf); + lq_sta->active_rate = priv->active_rate; + lq_sta->active_rate &= ~(0x1000); + lq_sta->active_rate_basic = priv->active_rate_basic; + lq_sta->phymode = priv->phymode; +#ifdef CONFIG_IWL4965_HT + /* + * 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 = (priv->current_ht_config.supp_mcs_set[0] << 1); + lq_sta->active_siso_rate |= + (priv->current_ht_config.supp_mcs_set[0] & 0x1); + lq_sta->active_siso_rate &= ~((u16)0x2); + lq_sta->active_siso_rate = + lq_sta->active_siso_rate << IWL_FIRST_OFDM_RATE; + + /* Same here */ + lq_sta->active_mimo_rate = (priv->current_ht_config.supp_mcs_set[1] << 1); + lq_sta->active_mimo_rate |= + (priv->current_ht_config.supp_mcs_set[1] & 0x1); + lq_sta->active_mimo_rate &= ~((u16)0x2); + lq_sta->active_mimo_rate = + lq_sta->active_mimo_rate << IWL_FIRST_OFDM_RATE; + IWL_DEBUG_HT("SISO RATE 0x%X MIMO RATE 0x%X\n", + lq_sta->active_siso_rate, + lq_sta->active_mimo_rate); +#endif /*CONFIG_IWL4965_HT*/ #ifdef CONFIG_MAC80211_DEBUGFS - crl->drv = priv; + lq_sta->drv = priv; #endif if (priv->assoc_station_added) priv->lq_mngr.lq_ready = 1; - rs_initialize_lq(priv, sta); + rs_initialize_lq(priv, conf, sta); } -static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, - struct iwl_rate *tx_mcs, - struct iwl_link_quality_cmd *lq_cmd) +static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, + struct iwl4965_rate *tx_mcs, + struct iwl4965_link_quality_cmd *lq_cmd) { int index = 0; int rate_idx; int repeat_rate = 0; u8 ant_toggle_count = 0; u8 use_ht_possible = 1; - struct iwl_rate new_rate; - struct iwl_scale_tbl_info tbl_type = { 0 }; + struct iwl4965_rate new_rate; + struct iwl4965_scale_tbl_info tbl_type = { 0 }; - rs_dbgfs_set_mcs(lq_data, tx_mcs, index); + /* Override starting rate (index 0) if needed for debug purposes */ + rs_dbgfs_set_mcs(lq_sta, tx_mcs, index); - rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode, + /* Interpret rate_n_flags */ + rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->phymode, &tbl_type, &rate_idx); + /* How many times should we repeat the initial rate? */ if (is_legacy(tbl_type.lq_type)) { ant_toggle_count = 1; repeat_rate = IWL_NUMBER_TRY; @@ -1909,19 +2219,27 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, 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(tx_mcs->rate_n_flags); new_rate.rate_n_flags = tx_mcs->rate_n_flags; if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN)) - lq_cmd->general_params.single_stream_ant_msk = 1; + lq_cmd->general_params.single_stream_ant_msk + = LINK_QUAL_ANT_A_MSK; else - lq_cmd->general_params.single_stream_ant_msk = 2; + lq_cmd->general_params.single_stream_ant_msk + = LINK_QUAL_ANT_B_MSK; index++; repeat_rate--; + /* 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_count < @@ -1933,22 +2251,30 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, } } - rs_dbgfs_set_mcs(lq_data, &new_rate, index); + /* 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.rate_n_flags); repeat_rate--; index++; } - rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type, + rs_get_tbl_info_from_mcs(&new_rate, lq_sta->phymode, &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; - rs_get_lower_rate(lq_data, &tbl_type, rate_idx, + /* Get next rate */ + rs_get_lower_rate(lq_sta, &tbl_type, rate_idx, use_ht_possible, &new_rate); + /* How many times should we repeat the next rate? */ if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE) ant_toggle_count++; @@ -1960,9 +2286,14 @@ static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data, } 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; - rs_dbgfs_set_mcs(lq_data, &new_rate, index); + /* 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.rate_n_flags); @@ -1987,27 +2318,27 @@ static void rs_free(void *priv_rate) static void rs_clear(void *priv_rate) { - struct iwl_priv *priv = (struct iwl_priv *) priv_rate; + struct iwl4965_priv *priv = (struct iwl4965_priv *) priv_rate; IWL_DEBUG_RATE("enter\n"); priv->lq_mngr.lq_ready = 0; -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG if (priv->lq_mngr.agg_ctrl.granted_ba) iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED); -#endif /*CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /*CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ IWL_DEBUG_RATE("leave\n"); } static void rs_free_sta(void *priv, void *priv_sta) { - struct iwl_rate_scale_priv *rs_priv = priv_sta; + struct iwl4965_lq_sta *lq_sta = priv_sta; IWL_DEBUG_RATE("enter\n"); - kfree(rs_priv); + kfree(lq_sta); IWL_DEBUG_RATE("leave\n"); } @@ -2018,19 +2349,19 @@ 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_rate_scale_priv *rs_priv, - struct iwl_rate *mcs, int index) +static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, + struct iwl4965_rate *mcs, int index) { u32 base_rate; - if (rs_priv->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->phymode == (u8) MODE_IEEE80211A) base_rate = 0x800D; else base_rate = 0x820A; - if (rs_priv->dbg_fixed.rate_n_flags) { + if (lq_sta->dbg_fixed.rate_n_flags) { if (index < 12) - mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags; + mcs->rate_n_flags = lq_sta->dbg_fixed.rate_n_flags; else mcs->rate_n_flags = base_rate; IWL_DEBUG_RATE("Fixed rate ON\n"); @@ -2043,7 +2374,7 @@ static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv, 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_rate_scale_priv *rs_priv = file->private_data; + struct iwl4965_lq_sta *lq_sta = file->private_data; char buf[64]; int buf_size; u32 parsed_rate; @@ -2054,20 +2385,20 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file, return -EFAULT; if (sscanf(buf, "%x", &parsed_rate) == 1) - rs_priv->dbg_fixed.rate_n_flags = parsed_rate; + lq_sta->dbg_fixed.rate_n_flags = parsed_rate; else - rs_priv->dbg_fixed.rate_n_flags = 0; + lq_sta->dbg_fixed.rate_n_flags = 0; - rs_priv->active_rate = 0x0FFF; - rs_priv->active_siso_rate = 0x1FD0; - rs_priv->active_mimo_rate = 0x1FD0; + lq_sta->active_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ + lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ + lq_sta->active_mimo_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ IWL_DEBUG_RATE("sta_id %d rate 0x%X\n", - rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags); + lq_sta->lq.sta_id, lq_sta->dbg_fixed.rate_n_flags); - if (rs_priv->dbg_fixed.rate_n_flags) { - rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq); - rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC); + if (lq_sta->dbg_fixed.rate_n_flags) { + rs_fill_link_cmd(lq_sta, &lq_sta->dbg_fixed, &lq_sta->lq); + rs_send_lq_cmd(lq_sta->drv, &lq_sta->lq, CMD_ASYNC); } return count; @@ -2080,38 +2411,38 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, int desc = 0; int i = 0; - struct iwl_rate_scale_priv *rs_priv = file->private_data; + struct iwl4965_lq_sta *lq_sta = file->private_data; - desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id); + 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", - rs_priv->total_failed, rs_priv->total_success, - rs_priv->active_rate); + lq_sta->total_failed, lq_sta->total_success, + lq_sta->active_rate); desc += sprintf(buff+desc, "fixed rate 0x%X\n", - rs_priv->dbg_fixed.rate_n_flags); + lq_sta->dbg_fixed.rate_n_flags); desc += sprintf(buff+desc, "general:" "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n", - rs_priv->lq.general_params.flags, - rs_priv->lq.general_params.mimo_delimiter, - rs_priv->lq.general_params.single_stream_ant_msk, - rs_priv->lq.general_params.dual_stream_ant_msk); + 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(rs_priv->lq.agg_params.agg_time_limit), - rs_priv->lq.agg_params.agg_dis_start_th, - rs_priv->lq.agg_params.agg_frame_cnt_limit); + 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", - rs_priv->lq.general_params.start_rate_index[0], - rs_priv->lq.general_params.start_rate_index[1], - rs_priv->lq.general_params.start_rate_index[2], - rs_priv->lq.general_params.start_rate_index[3]); + 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(rs_priv->lq.rs_table[i].rate_n_flags)); + i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags)); return simple_read_from_buffer(user_buf, count, ppos, buff, desc); } @@ -2128,22 +2459,22 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, int desc = 0; int i, j; - struct iwl_rate_scale_priv *rs_priv = file->private_data; + 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", - rs_priv->active_tbl == i?"*":"x", - rs_priv->lq_info[i].lq_type, - rs_priv->lq_info[i].is_SGI, - rs_priv->lq_info[i].is_fat, - rs_priv->lq_info[i].is_dup, - rs_priv->lq_info[i].current_rate.rate_n_flags); + 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.rate_n_flags); for (j = 0; j < IWL_RATE_COUNT; j++) { desc += sprintf(buff+desc, - "counter=%d success=%d %%=%d\n", - rs_priv->lq_info[i].win[j].counter, - rs_priv->lq_info[i].win[j].success_counter, - rs_priv->lq_info[i].win[j].success_ratio); + "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); @@ -2157,20 +2488,20 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = { static void rs_add_debugfs(void *priv, void *priv_sta, struct dentry *dir) { - struct iwl_rate_scale_priv *rs_priv = priv_sta; - rs_priv->rs_sta_dbgfs_scale_table_file = + struct iwl4965_lq_sta *lq_sta = priv_sta; + lq_sta->rs_sta_dbgfs_scale_table_file = debugfs_create_file("rate_scale_table", 0600, dir, - rs_priv, &rs_sta_dbgfs_scale_table_ops); - rs_priv->rs_sta_dbgfs_stats_table_file = + lq_sta, &rs_sta_dbgfs_scale_table_ops); + lq_sta->rs_sta_dbgfs_stats_table_file = debugfs_create_file("rate_stats_table", 0600, dir, - rs_priv, &rs_sta_dbgfs_stats_table_ops); + lq_sta, &rs_sta_dbgfs_stats_table_ops); } static void rs_remove_debugfs(void *priv, void *priv_sta) { - struct iwl_rate_scale_priv *rs_priv = priv_sta; - debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file); - debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file); + 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); } #endif @@ -2191,13 +2522,13 @@ static struct rate_control_ops rs_ops = { #endif }; -int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) +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_rate_scale_priv *rs_priv; + struct iwl4965_priv *priv = hw->priv; + struct iwl4965_lq_sta *lq_sta; struct sta_info *sta; - int count = 0, i; + int cnt = 0, i; u32 samples = 0, success = 0, good = 0; unsigned long now = jiffies; u32 max_time = 0; @@ -2213,10 +2544,10 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) return sprintf(buf, "station %d not found\n", sta_id); } - rs_priv = (void *)sta->rate_ctrl_priv; + lq_sta = (void *)sta->rate_ctrl_priv; - lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type; - antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type; + lq_type = lq_sta->lq_info[lq_sta->active_tbl].lq_type; + antenna = lq_sta->lq_info[lq_sta->active_tbl].antenna_type; if (is_legacy(lq_type)) i = IWL_RATE_54M_INDEX; @@ -2225,35 +2556,35 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) while (1) { u64 mask; int j; - int active = rs_priv->active_tbl; + int active = lq_sta->active_tbl; - count += - sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2); + cnt += + sprintf(&buf[cnt], " %2dMbs: ", iwl4965_rates[i].ieee / 2); mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1)); for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1) - buf[count++] = - (rs_priv->lq_info[active].win[i].data & mask) + buf[cnt++] = + (lq_sta->lq_info[active].win[i].data & mask) ? '1' : '0'; - samples += rs_priv->lq_info[active].win[i].counter; - good += rs_priv->lq_info[active].win[i].success_counter; - success += rs_priv->lq_info[active].win[i].success_counter * - iwl_rates[i].ieee; + 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 * + iwl4965_rates[i].ieee; - if (rs_priv->lq_info[active].win[i].stamp) { + if (lq_sta->lq_info[active].win[i].stamp) { int delta = jiffies_to_msecs(now - - rs_priv->lq_info[active].win[i].stamp); + lq_sta->lq_info[active].win[i].stamp); if (delta > max_time) max_time = delta; - count += sprintf(&buf[count], "%5dms\n", delta); + cnt += sprintf(&buf[cnt], "%5dms\n", delta); } else - buf[count++] = '\n'; + buf[cnt++] = '\n'; - j = iwl_get_prev_ieee_rate(i); + j = iwl4965_get_prev_ieee_rate(i); if (j == i) break; i = j; @@ -2261,37 +2592,38 @@ int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) /* Display the average rate of all samples taken. * - * NOTE: We multiple # of samples by 2 since the IEEE measurement - * added from iwl_rates is actually 2X the rate */ + * NOTE: We multiply # of samples by 2 since the IEEE measurement + * added from iwl4965_rates is actually 2X the rate */ if (samples) - count += sprintf(&buf[count], + 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 - count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n"); - count += sprintf(&buf[count], "\nrate scale type %d anntena %d " + 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, - rs_priv->search_better_tbl, sta->last_txrate); + lq_sta->search_better_tbl, sta->last_txrate); sta_info_put(sta); - return count; + return cnt; } -void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) +void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; priv->lq_mngr.lq_ready = 1; } -void iwl_rate_control_register(struct ieee80211_hw *hw) +void iwl4965_rate_control_register(struct ieee80211_hw *hw) { ieee80211_rate_control_register(&rs_ops); } -void iwl_rate_control_unregister(struct ieee80211_hw *hw) +void iwl4965_rate_control_unregister(struct ieee80211_hw *hw) { 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 index c6325f72df68..55f707382787 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h @@ -29,11 +29,11 @@ #include "iwl-4965.h" -struct iwl_rate_info { - u8 plcp; - u8 plcp_siso; - u8 plcp_mimo; - u8 ieee; +struct iwl4965_rate_info { + u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ + u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ + u8 plcp_mimo; /* uCode API: IWL_RATE_MIMO_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 */ @@ -42,6 +42,10 @@ struct iwl_rate_info { u8 next_rs_tgg; /* next rate used in TGG rs algo */ }; +/* + * These serve as indexes into + * struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; + */ enum { IWL_RATE_1M_INDEX = 0, IWL_RATE_2M_INDEX, @@ -69,20 +73,21 @@ enum { }; /* #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) - +#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, @@ -99,7 +104,7 @@ enum { IWL_RATE_11M_PLCP = 110, }; -/* OFDM HT rate plcp */ +/* 4965 uCode API values for OFDM high-throughput (HT) bit rates */ enum { IWL_RATE_SISO_6M_PLCP = 0, IWL_RATE_SISO_12M_PLCP = 1, @@ -121,6 +126,7 @@ enum { IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP, }; +/* MAC header values for bit rates */ enum { IWL_RATE_6M_IEEE = 12, IWL_RATE_9M_IEEE = 18, @@ -163,20 +169,15 @@ enum { (IWL_OFDM_BASIC_RATES_MASK | \ IWL_CCK_BASIC_RATES_MASK) -#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1) +#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 -#define IWL_LEGACY_SWITCH_ANTENNA 0 -#define IWL_LEGACY_SWITCH_SISO 1 -#define IWL_LEGACY_SWITCH_MIMO 2 - -#define IWL_RS_GOOD_RATIO 12800 - -#define IWL_ACTION_LIMIT 3 +/* 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 @@ -185,82 +186,104 @@ enum { #define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500 #define IWL_NONE_LEGACY_TABLE_COUNT 1500 -#define IWL_RATE_SCALE_SWITCH (10880) +/* 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_MIMO 2 + +/* possible actions when in siso mode */ #define IWL_SISO_SWITCH_ANTENNA 0 #define IWL_SISO_SWITCH_MIMO 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 -#define LQ_SIZE 2 +#define IWL_ACTION_LIMIT 3 /* # possible actions */ + +#define LQ_SIZE 2 /* 2 mode tables: "Active" and "Search" */ -extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT]; +extern const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT]; -enum iwl_table_type { +enum iwl4965_table_type { LQ_NONE, - LQ_G, + LQ_G, /* legacy types */ LQ_A, - LQ_SISO, + LQ_SISO, /* high-throughput types */ LQ_MIMO, LQ_MAX, }; -enum iwl_antenna_type { +#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A)) +#define is_siso(tbl) (((tbl) == LQ_SISO)) +#define is_mimo(tbl) (((tbl) == LQ_MIMO)) +#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)) + +/* 4965 has 2 antennas/chains for Tx (but 3 for Rx) */ +enum iwl4965_antenna_type { ANT_NONE, ANT_MAIN, ANT_AUX, ANT_BOTH, }; -static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) +static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) { - u8 rate = iwl_rates[rate_index].prev_ieee; + u8 rate = iwl4965_rates[rate_index].prev_ieee; if (rate == IWL_RATE_INVALID) rate = rate_index; return rate; } -extern int iwl_rate_index_from_plcp(int plcp); +extern int iwl4965_rate_index_from_plcp(int plcp); /** - * iwl_fill_rs_info - Fill an output text buffer with the rate representation + * 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 alogirthm and is not meant to be + * the performance of the rate control algorithm and is not meant to be * parsed software. */ -extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); +extern int iwl4965_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id); /** - * iwl_rate_scale_init - Initialize the rate scale table based on assoc info + * iwl4965_rate_scale_init - Initialize the rate scale table based on assoc info * - * The specific througput table used is based on the type of network + * The specific throughput table used is based on the type of network * the associated with, including A, B, G, and G w/ TGG protection */ -extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); +extern void iwl4965_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id); /** - * iwl_rate_control_register - Register the rate control algorithm callbacks + * 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 - * iwl_rate_control_register in order to register the rate control callbacks + * 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 void iwl_rate_control_register(struct ieee80211_hw *hw); +extern void iwl4965_rate_control_register(struct ieee80211_hw *hw); /** - * iwl_rate_control_unregister - Unregister the rate control callbacks + * 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 iwl_rate_control_unregister(struct ieee80211_hw *hw); +extern void iwl4965_rate_control_unregister(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 891f90d2f019..04db34ba814b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -36,13 +36,13 @@ #include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> +#include <asm/unaligned.h> -#define IWL 4965 - -#include "iwlwifi.h" #include "iwl-4965.h" #include "iwl-helpers.h" +static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv); + #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ [IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP, \ IWL_RATE_SISO_##s##M_PLCP, \ @@ -63,7 +63,7 @@ * maps to IWL_RATE_INVALID * */ -const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { +const struct iwl4965_rate_info iwl4965_rates[IWL_RATE_COUNT] = { IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2), /* 1mbps */ IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5), /* 2mbps */ IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11), /*5.5mbps */ @@ -85,16 +85,16 @@ static int is_fat_channel(__le32 rxon_flags) (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); } -static u8 is_single_stream(struct iwl_priv *priv) +static u8 is_single_stream(struct iwl4965_priv *priv) { -#ifdef CONFIG_IWLWIFI_HT - if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht || - (priv->active_rate_ht[1] == 0) || +#ifdef CONFIG_IWL4965_HT + if (!priv->current_ht_config.is_ht || + (priv->current_ht_config.supp_mcs_set[1] == 0) || (priv->ps_mode == IWL_MIMO_PS_STATIC)) return 1; #else return 1; -#endif /*CONFIG_IWLWIFI_HT */ +#endif /*CONFIG_IWL4965_HT */ return 0; } @@ -104,7 +104,7 @@ static u8 is_single_stream(struct iwl_priv *priv) * MIMO (dual stream) requires at least 2, but works better with 3. * This does not determine *which* chains to use, just how many. */ -static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, +static int iwl4965_get_rx_chain_counter(struct iwl4965_priv *priv, u8 *idle_state, u8 *rx_state) { u8 is_single = is_single_stream(priv); @@ -133,32 +133,32 @@ static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv, return 0; } -int iwl_hw_rxq_stop(struct iwl_priv *priv) +int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv) { int rc; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - /* stop HW */ - iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + /* stop Rx DMA */ + iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + rc = iwl4965_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, (1 << 24), 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) +u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *addr) { int i; int start = 0; @@ -190,104 +190,114 @@ u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr) return ret; } -static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max) +static int iwl4965_nic_set_pwr_src(struct iwl4965_priv *priv, int pwr_max) { - int rc = 0; + int ret; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); - if (rc) { + ret = iwl4965_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } if (!pwr_max) { u32 val; - rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE, + 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_restricted_reg( - priv, APMG_PS_CTRL_REG, + iwl4965_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_restricted_reg( - priv, APMG_PS_CTRL_REG, + iwl4965_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~APMG_PS_CTRL_MSK_PWR_SRC); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } -static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +static int iwl4965_rx_init(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq) { int rc; unsigned long flags; + unsigned int rb_size; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - /* stop HW */ - iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + if (iwl4965_param_amsdu_size_8K) + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; + else + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; + + /* Stop Rx DMA */ + iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + /* Reset driver's Rx queue write index */ + iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + /* Tell device where to find RBD circular buffer in DRAM */ + iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, rxq->dma_addr >> 8); - iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, + /* Tell device where in DRAM to update its Rx status */ + iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, (priv->hw_setting.shared_phys + - offsetof(struct iwl_shared, val0)) >> 4); + offsetof(struct iwl4965_shared, val0)) >> 4); - iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, + /* Enable Rx DMA, enable host interrupt, Rx buffer size 4k, 256 RBDs */ + iwl4965_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K | + rb_size | /*0x10 << 4 | */ (RX_QUEUE_SIZE_LOG << FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT)); /* - * iwl_write32(priv,CSR_INT_COAL_REG,0); + * iwl4965_write32(priv,CSR_INT_COAL_REG,0); */ - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -static int iwl4965_kw_init(struct iwl_priv *priv) +/* Tell 4965 where to find the "keep warm" buffer */ +static int iwl4965_kw_init(struct iwl4965_priv *priv) { unsigned long flags; int rc; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) goto out; - iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG, + iwl4965_write_direct32(priv, IWL_FH_KW_MEM_ADDR_REG, priv->kw.dma_addr >> 4); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); out: spin_unlock_irqrestore(&priv->lock, flags); return rc; } -static int iwl4965_kw_alloc(struct iwl_priv *priv) +static int iwl4965_kw_alloc(struct iwl4965_priv *priv) { struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; + struct iwl4965_kw *kw = &priv->kw; kw->size = IWL4965_KW_SIZE; /* TBW need set somewhere else */ kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); @@ -300,14 +310,19 @@ static int iwl4965_kw_alloc(struct iwl_priv *priv) #define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") -int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel, - const struct iwl_eeprom_channel *eeprom_ch, +/** + * iwl4965_set_fat_chan_info - Copy fat channel info into driver's priv. + * + * Does not set up a command, or touch hardware. + */ +int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel, + const struct iwl4965_eeprom_channel *eeprom_ch, u8 fat_extension_channel) { - struct iwl_channel_info *ch_info; + struct iwl4965_channel_info *ch_info; - ch_info = (struct iwl_channel_info *) - iwl_get_channel_info(priv, phymode, channel); + ch_info = (struct iwl4965_channel_info *) + iwl4965_get_channel_info(priv, phymode, channel); if (!is_channel_valid(ch_info)) return -1; @@ -340,10 +355,13 @@ int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel, return 0; } -static void iwl4965_kw_free(struct iwl_priv *priv) +/** + * iwl4965_kw_free - Free the "keep warm" buffer + */ +static void iwl4965_kw_free(struct iwl4965_priv *priv) { struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; + struct iwl4965_kw *kw = &priv->kw; if (kw->v_addr) { pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); @@ -358,7 +376,7 @@ static void iwl4965_kw_free(struct iwl_priv *priv) * @param priv * @return error code */ -static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) +static int iwl4965_txq_ctx_reset(struct iwl4965_priv *priv) { int rc = 0; int txq_id, slots_num; @@ -366,9 +384,10 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) iwl4965_kw_free(priv); - iwl_hw_txq_ctx_free(priv); + /* Free all tx/cmd queues and keep-warm buffer */ + iwl4965_hw_txq_ctx_free(priv); - /* Tx CMD queue */ + /* Alloc keep-warm buffer */ rc = iwl4965_kw_alloc(priv); if (rc) { IWL_ERROR("Keep Warm allocation failed"); @@ -377,28 +396,31 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (unlikely(rc)) { IWL_ERROR("TX reset failed"); spin_unlock_irqrestore(&priv->lock, flags); goto error_reset; } - iwl_write_restricted_reg(priv, SCD_TXFACT, 0); - iwl_release_restricted_access(priv); + /* Turn off all Tx DMA channels */ + iwl4965_write_prph(priv, KDR_SCD_TXFACT, 0); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); + /* Tell 4965 where to find the keep-warm buffer */ rc = iwl4965_kw_init(priv); if (rc) { IWL_ERROR("kw_init failed\n"); goto error_reset; } - /* Tx queue(s) */ + /* Alloc and init all (default 16) Tx queues, + * including the command queue (#4) */ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num, + rc = iwl4965_tx_queue_init(priv, &priv->txq[txq_id], slots_num, txq_id); if (rc) { IWL_ERROR("Tx %d queue init failed\n", txq_id); @@ -409,32 +431,32 @@ static int iwl4965_txq_ctx_reset(struct iwl_priv *priv) return rc; error: - iwl_hw_txq_ctx_free(priv); + iwl4965_hw_txq_ctx_free(priv); error_reset: iwl4965_kw_free(priv); error_kw: return rc; } -int iwl_hw_nic_init(struct iwl_priv *priv) +int iwl4965_hw_nic_init(struct iwl4965_priv *priv) { int rc; unsigned long flags; - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl4965_rx_queue *rxq = &priv->rxq; u8 rev_id; u32 val; u8 val_link; - iwl_power_init_handle(priv); + iwl4965_power_init_handle(priv); /* nic_init */ spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_GP_CNTRL, + iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl4965_poll_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (rc < 0) { @@ -443,26 +465,26 @@ int iwl_hw_nic_init(struct iwl_priv *priv) return rc; } - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); + iwl4965_read_prph(priv, APMG_CLK_CTRL_REG); - iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG, + iwl4965_write_prph(priv, APMG_CLK_CTRL_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); - iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG); + iwl4965_read_prph(priv, APMG_CLK_CTRL_REG); udelay(20); - iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_restricted_access(priv); - iwl_write32(priv, CSR_INT_COALESCING, 512 / 32); + iwl4965_release_nic_access(priv); + iwl4965_write32(priv, CSR_INT_COALESCING, 512 / 32); spin_unlock_irqrestore(&priv->lock, flags); /* Determine HW type */ @@ -484,11 +506,6 @@ int iwl_hw_nic_init(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); - /* Read the EEPROM */ - rc = iwl_eeprom_init(priv); - if (rc) - return rc; - if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) { IWL_ERROR("Older EEPROM detected! Aborting.\n"); return -EINVAL; @@ -503,51 +520,53 @@ int iwl_hw_nic_init(struct iwl_priv *priv) /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | + iwl4965_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R | CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); return rc; } - iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG); - iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + iwl4965_read_prph(priv, APMG_PS_CTRL_REG); + iwl4965_set_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG, + iwl4965_clear_bits_prph(priv, APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - iwl_hw_card_show_info(priv); + iwl4965_hw_card_show_info(priv); /* end nic_init */ /* Allocate the RX queue, or reset if it is already allocated */ if (!rxq->bd) { - rc = iwl_rx_queue_alloc(priv); + rc = iwl4965_rx_queue_alloc(priv); if (rc) { IWL_ERROR("Unable to initialize Rx queue\n"); return -ENOMEM; } } else - iwl_rx_queue_reset(priv, rxq); + iwl4965_rx_queue_reset(priv, rxq); - iwl_rx_replenish(priv); + iwl4965_rx_replenish(priv); iwl4965_rx_init(priv, rxq); spin_lock_irqsave(&priv->lock, flags); rxq->need_update = 1; - iwl_rx_queue_update_write_ptr(priv, rxq); + iwl4965_rx_queue_update_write_ptr(priv, rxq); spin_unlock_irqrestore(&priv->lock, flags); + + /* Allocate and init all Tx and Command queues */ rc = iwl4965_txq_ctx_reset(priv); if (rc) return rc; @@ -563,7 +582,7 @@ int iwl_hw_nic_init(struct iwl_priv *priv) return 0; } -int iwl_hw_nic_stop_master(struct iwl_priv *priv) +int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv) { int rc = 0; u32 reg_val; @@ -572,16 +591,16 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); /* set stop master bit */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - reg_val = iwl_read32(priv, CSR_GP_CNTRL); + reg_val = iwl4965_read32(priv, CSR_GP_CNTRL); if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE == (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE)) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { - rc = iwl_poll_bit(priv, CSR_RESET, + rc = iwl4965_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { @@ -596,65 +615,69 @@ int iwl_hw_nic_stop_master(struct iwl_priv *priv) return rc; } -void iwl_hw_txq_ctx_stop(struct iwl_priv *priv) +/** + * iwl4965_hw_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory + */ +void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv) { int txq_id; unsigned long flags; - /* reset TFD queues */ + /* Stop each Tx DMA channel, and wait for it to be idle */ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) { spin_lock_irqsave(&priv->lock, flags); - if (iwl_grab_restricted_access(priv)) { + if (iwl4965_grab_nic_access(priv)) { spin_unlock_irqrestore(&priv->lock, flags); continue; } - iwl_write_restricted(priv, + iwl4965_write_direct32(priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); - iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, + iwl4965_poll_direct_bit(priv, IWL_FH_TSSR_TX_STATUS_REG, IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE (txq_id), 200); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); } - iwl_hw_txq_ctx_free(priv); + /* Deallocate memory for all Tx queues */ + iwl4965_hw_txq_ctx_free(priv); } -int iwl_hw_nic_reset(struct iwl_priv *priv) +int iwl4965_hw_nic_reset(struct iwl4965_priv *priv) { int rc = 0; unsigned long flags; - iwl_hw_nic_stop_master(priv); + iwl4965_hw_nic_stop_master(priv); spin_lock_irqsave(&priv->lock, flags); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl_poll_bit(priv, CSR_RESET, + iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + rc = iwl4965_poll_bit(priv, CSR_RESET, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); udelay(10); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (!rc) { - iwl_write_restricted_reg(priv, APMG_CLK_EN_REG, + iwl4965_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT); udelay(10); - iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG, + iwl4965_set_bits_prph(priv, APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); } clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -684,7 +707,7 @@ int iwl_hw_nic_reset(struct iwl_priv *priv) */ static void iwl4965_bg_statistics_periodic(unsigned long data) { - struct iwl_priv *priv = (struct iwl_priv *)data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)data; queue_work(priv->workqueue, &priv->statistics_work); } @@ -692,27 +715,27 @@ static void iwl4965_bg_statistics_periodic(unsigned long data) /** * iwl4965_bg_statistics_work - Send the statistics request to the hardware. * - * This is queued by iwl_bg_statistics_periodic. + * This is queued by iwl4965_bg_statistics_periodic. */ static void iwl4965_bg_statistics_work(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, + struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, statistics_work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_send_statistics_request(priv); + iwl4965_send_statistics_request(priv); mutex_unlock(&priv->mutex); } #define CT_LIMIT_CONST 259 #define TM_CT_KILL_THRESHOLD 110 -void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) +void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv) { - struct iwl_ct_kill_config cmd; + struct iwl4965_ct_kill_config cmd; u32 R1, R2, R3; u32 temp_th; u32 crit_temperature; @@ -720,7 +743,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) int rc = 0; spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); spin_unlock_irqrestore(&priv->lock, flags); @@ -738,7 +761,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2; cmd.critical_temperature_R = cpu_to_le32(crit_temperature); - rc = iwl_send_cmd_pdu(priv, + rc = iwl4965_send_cmd_pdu(priv, REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd); if (rc) IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n"); @@ -746,7 +769,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n"); } -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY /* "false alarms" are signals that our DSP tries to lock onto, * but then determines that they are either noise, or transmissions @@ -756,7 +779,7 @@ void iwl4965_rf_kill_ct_config(struct iwl_priv *priv) * enough to receive all of our own network traffic, but not so * high that our DSP gets too busy trying to lock onto non-network * activity/noise. */ -static int iwl4965_sens_energy_cck(struct iwl_priv *priv, +static int iwl4965_sens_energy_cck(struct iwl4965_priv *priv, u32 norm_fa, u32 rx_enable_time, struct statistics_general_data *rx_info) @@ -782,7 +805,7 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv, u32 false_alarms = norm_fa * 200 * 1024; u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; - struct iwl_sensitivity_data *data = NULL; + struct iwl4965_sensitivity_data *data = NULL; data = &(priv->sensitivity_data); @@ -792,11 +815,11 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv, * This is background noise, which may include transmissions from other * networks, measured during silence before our network's beacon */ silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a & - ALL_BAND_FILTER)>>8); + ALL_BAND_FILTER) >> 8); silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b & - ALL_BAND_FILTER)>>8); + ALL_BAND_FILTER) >> 8); silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c & - ALL_BAND_FILTER)>>8); + ALL_BAND_FILTER) >> 8); val = max(silence_rssi_b, silence_rssi_c); max_silence_rssi = max(silence_rssi_a, (u8) val); @@ -947,7 +970,7 @@ static int iwl4965_sens_energy_cck(struct iwl_priv *priv, } -static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, +static int iwl4965_sens_auto_corr_ofdm(struct iwl4965_priv *priv, u32 norm_fa, u32 rx_enable_time) { @@ -955,7 +978,7 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, u32 false_alarms = norm_fa * 200 * 1024; u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; - struct iwl_sensitivity_data *data = NULL; + struct iwl4965_sensitivity_data *data = NULL; data = &(priv->sensitivity_data); @@ -1012,22 +1035,22 @@ static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv, return 0; } -static int iwl_sensitivity_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) +static int iwl4965_sensitivity_callback(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct sk_buff *skb) { /* We didn't cache the SKB; let the caller free it */ return 1; } /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ -static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) +static int iwl4965_sensitivity_write(struct iwl4965_priv *priv, u8 flags) { int rc = 0; - struct iwl_sensitivity_cmd cmd ; - struct iwl_sensitivity_data *data = NULL; - struct iwl_host_cmd cmd_out = { + struct iwl4965_sensitivity_cmd cmd ; + struct iwl4965_sensitivity_data *data = NULL; + struct iwl4965_host_cmd cmd_out = { .id = SENSITIVITY_CMD, - .len = sizeof(struct iwl_sensitivity_cmd), + .len = sizeof(struct iwl4965_sensitivity_cmd), .meta.flags = flags, .data = &cmd, }; @@ -1071,10 +1094,11 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) data->auto_corr_cck, data->auto_corr_cck_mrc, data->nrg_th_cck); + /* Update uCode's "work" table, and copy it to DSP */ cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; if (flags & CMD_ASYNC) - cmd_out.meta.u.callback = iwl_sensitivity_callback; + cmd_out.meta.u.callback = iwl4965_sensitivity_callback; /* Don't send command to uCode if nothing has changed */ if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]), @@ -1087,7 +1111,7 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE); - rc = iwl_send_cmd(priv, &cmd_out); + rc = iwl4965_send_cmd(priv, &cmd_out); if (!rc) { IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n"); return rc; @@ -1096,11 +1120,11 @@ static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags) return 0; } -void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) +void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force) { int rc = 0; int i; - struct iwl_sensitivity_data *data = NULL; + struct iwl4965_sensitivity_data *data = NULL; IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n"); @@ -1110,7 +1134,7 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) /* Clear driver's sensitivity algo data */ data = &(priv->sensitivity_data); - memset(data, 0, sizeof(struct iwl_sensitivity_data)); + memset(data, 0, sizeof(struct iwl4965_sensitivity_data)); data->num_in_cck_no_fa = 0; data->nrg_curr_state = IWL_FA_TOO_MANY; @@ -1154,21 +1178,21 @@ void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force) /* Reset differential Rx gains in NIC to prepare for chain noise calibration. * Called after every association, but this runs only once! * ... once chain noise is calibrated the first time, it's good forever. */ -void iwl4965_chain_noise_reset(struct iwl_priv *priv) +void iwl4965_chain_noise_reset(struct iwl4965_priv *priv) { - struct iwl_chain_noise_data *data = NULL; + struct iwl4965_chain_noise_data *data = NULL; int rc = 0; data = &(priv->chain_noise_data); - if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl_calibration_cmd cmd; + if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl4965_is_associated(priv)) { + struct iwl4965_calibration_cmd cmd; memset(&cmd, 0, sizeof(cmd)); cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; - rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd); msleep(4); data->state = IWL_CHAIN_NOISE_ACCUMULATE; @@ -1183,10 +1207,10 @@ void iwl4965_chain_noise_reset(struct iwl_priv *priv) * 1) Which antennas are connected. * 2) Differential rx gain settings to balance the 3 receivers. */ -static void iwl4965_noise_calibration(struct iwl_priv *priv, - struct iwl_notif_statistics *stat_resp) +static void iwl4965_noise_calibration(struct iwl4965_priv *priv, + struct iwl4965_notif_statistics *stat_resp) { - struct iwl_chain_noise_data *data = NULL; + struct iwl4965_chain_noise_data *data = NULL; int rc = 0; u32 chain_noise_a; @@ -1385,7 +1409,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv, /* Differential gain gets sent to uCode only once */ if (!data->radio_write) { - struct iwl_calibration_cmd cmd; + struct iwl4965_calibration_cmd cmd; data->radio_write = 1; memset(&cmd, 0, sizeof(cmd)); @@ -1393,7 +1417,7 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv, cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; - rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + rc = iwl4965_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, sizeof(cmd), &cmd); if (rc) IWL_DEBUG_CALIB("fail sending cmd " @@ -1416,8 +1440,8 @@ static void iwl4965_noise_calibration(struct iwl_priv *priv, return; } -static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, - struct iwl_notif_statistics *resp) +static void iwl4965_sensitivity_calibration(struct iwl4965_priv *priv, + struct iwl4965_notif_statistics *resp) { int rc = 0; u32 rx_enable_time; @@ -1427,7 +1451,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, u32 bad_plcp_ofdm; u32 norm_fa_ofdm; u32 norm_fa_cck; - struct iwl_sensitivity_data *data = NULL; + struct iwl4965_sensitivity_data *data = NULL; struct statistics_rx_non_phy *rx_info = &(resp->rx.general); struct statistics_rx *statistics = &(resp->rx); unsigned long flags; @@ -1435,7 +1459,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, data = &(priv->sensitivity_data); - if (!iwl_is_associated(priv)) { + if (!iwl4965_is_associated(priv)) { IWL_DEBUG_CALIB("<< - not associated\n"); return; } @@ -1523,7 +1547,7 @@ static void iwl4965_sensitivity_calibration(struct iwl_priv *priv, static void iwl4965_bg_sensitivity_work(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, + struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, sensitivity_work); mutex_lock(&priv->mutex); @@ -1549,11 +1573,11 @@ static void iwl4965_bg_sensitivity_work(struct work_struct *work) mutex_unlock(&priv->mutex); return; } -#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ +#endif /*CONFIG_IWL4965_SENSITIVITY*/ static void iwl4965_bg_txpower_work(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, + struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, txpower_work); /* If a scan happened to start before we got here @@ -1569,7 +1593,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* Regardless of if we are assocaited, we must reconfigure the * TX power since frames can be sent on non-radar channels while * not associated */ - iwl_hw_reg_send_txpower(priv); + iwl4965_hw_reg_send_txpower(priv); /* Update last_temperature to keep is_calib_needed from running * when it isn't needed... */ @@ -1581,24 +1605,31 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) /* * Acquire priv->lock before calling this function ! */ -static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index) +static void iwl4965_set_wr_ptrs(struct iwl4965_priv *priv, int txq_id, u32 index) { - iwl_write_restricted(priv, HBUS_TARG_WRPTR, + iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, (index & 0xff) | (txq_id << 8)); - iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index); + iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(txq_id), index); } -/* - * Acquire priv->lock before calling this function ! +/** + * iwl4965_tx_queue_set_status - (optionally) start Tx/Cmd queue + * @tx_fifo_id: Tx DMA/FIFO channel (range 0-7) that the queue will feed + * @scd_retry: (1) Indicates queue will be used in aggregation mode + * + * NOTE: Acquire priv->lock before calling this function ! */ -static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, - struct iwl_tx_queue *txq, +static void iwl4965_tx_queue_set_status(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq, int tx_fifo_id, int scd_retry) { int txq_id = txq->q.id; + + /* Find out whether to activate Tx queue */ int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; - iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id), + /* Set up and activate */ + iwl4965_write_prph(priv, KDR_SCD_QUEUE_STATUS_BITS(txq_id), (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) | @@ -1608,7 +1639,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, txq->sched_retry = scd_retry; IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n", - active ? "Activete" : "Deactivate", + active ? "Activate" : "Deactivate", scd_retry ? "BA" : "AC", txq_id, tx_fifo_id); } @@ -1622,17 +1653,17 @@ static const u16 default_queue_to_tx_fifo[] = { IWL_TX_FIFO_HCCA_2 }; -static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id) +static inline void iwl4965_txq_ctx_activate(struct iwl4965_priv *priv, int txq_id) { set_bit(txq_id, &priv->txq_ctx_active_msk); } -static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) +static inline void iwl4965_txq_ctx_deactivate(struct iwl4965_priv *priv, int txq_id) { clear_bit(txq_id, &priv->txq_ctx_active_msk); } -int iwl4965_alive_notify(struct iwl_priv *priv) +int iwl4965_alive_notify(struct iwl4965_priv *priv) { u32 a; int i = 0; @@ -1641,45 +1672,55 @@ int iwl4965_alive_notify(struct iwl_priv *priv) spin_lock_irqsave(&priv->lock, flags); -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY memset(&(priv->sensitivity_data), 0, - sizeof(struct iwl_sensitivity_data)); + sizeof(struct iwl4965_sensitivity_data)); memset(&(priv->chain_noise_data), 0, - sizeof(struct iwl_chain_noise_data)); + sizeof(struct iwl4965_chain_noise_data)); for (i = 0; i < NUM_RX_CHAINS; i++) priv->chain_noise_data.delta_gain_code[i] = CHAIN_NOISE_DELTA_GAIN_INIT_VAL; -#endif /* CONFIG_IWLWIFI_SENSITIVITY*/ - rc = iwl_grab_restricted_access(priv); +#endif /* CONFIG_IWL4965_SENSITIVITY*/ + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR); + /* Clear 4965's internal Tx Scheduler data base */ + priv->scd_base_addr = iwl4965_read_prph(priv, KDR_SCD_SRAM_BASE_ADDR); a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET; for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4) - iwl_write_restricted_mem(priv, a, 0); + iwl4965_write_targ_mem(priv, a, 0); for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4) - iwl_write_restricted_mem(priv, a, 0); + iwl4965_write_targ_mem(priv, a, 0); for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4) - iwl_write_restricted_mem(priv, a, 0); + iwl4965_write_targ_mem(priv, a, 0); - iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR, + /* Tel 4965 where to find Tx byte count tables */ + iwl4965_write_prph(priv, KDR_SCD_DRAM_BASE_ADDR, (priv->hw_setting.shared_phys + - offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10); - iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0); + offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); - /* initiate the queues */ + /* Disable chain mode for all queues */ + iwl4965_write_prph(priv, KDR_SCD_QUEUECHAIN_SEL, 0); + + /* Initialize each Tx queue (including the command queue) */ for (i = 0; i < priv->hw_setting.max_txq_num; i++) { - iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0); - iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); - iwl_write_restricted_mem(priv, priv->scd_base_addr + + + /* TFD circular buffer read/write indexes */ + iwl4965_write_prph(priv, KDR_SCD_QUEUE_RDPTR(i), 0); + iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); + + /* Max Tx Window size for Scheduler-ACK mode */ + iwl4965_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(i), (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); - iwl_write_restricted_mem(priv, priv->scd_base_addr + + + /* Frame limit */ + iwl4965_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(i) + sizeof(u32), (SCD_FRAME_LIMIT << @@ -1687,87 +1728,98 @@ int iwl4965_alive_notify(struct iwl_priv *priv) SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); } - iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK, + iwl4965_write_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << priv->hw_setting.max_txq_num) - 1); - iwl_write_restricted_reg(priv, SCD_TXFACT, + /* Activate all Tx DMA/FIFO channels */ + iwl4965_write_prph(priv, KDR_SCD_TXFACT, SCD_TXFACT_REG_TXFIFO_MASK(0, 7)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); - /* map qos queues to fifos one-to-one */ + + /* Map each Tx/cmd queue to its corresponding fifo */ for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { int ac = default_queue_to_tx_fifo[i]; iwl4965_txq_ctx_activate(priv, i); iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0); } - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -int iwl_hw_set_hw_setting(struct iwl_priv *priv) +/** + * iwl4965_hw_set_hw_setting + * + * Called when initializing driver + */ +int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv) { + /* Allocate area for Tx byte count tables and Rx queue status */ priv->hw_setting.shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl_shared), + sizeof(struct iwl4965_shared), &priv->hw_setting.shared_phys); if (!priv->hw_setting.shared_virt) return -1; - memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared)); + memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl4965_shared)); - priv->hw_setting.max_txq_num = iwl_param_queues_num; + priv->hw_setting.max_txq_num = iwl4965_param_queues_num; priv->hw_setting.ac_queue_count = AC_NUM; - - priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK; - priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd); + priv->hw_setting.tx_cmd_len = sizeof(struct iwl4965_tx_cmd); priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE; priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG; - + if (iwl4965_param_amsdu_size_8K) + priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_8K; + else + priv->hw_setting.rx_buf_size = IWL_RX_BUF_SIZE_4K; + priv->hw_setting.max_pkt_size = priv->hw_setting.rx_buf_size - 256; priv->hw_setting.max_stations = IWL4965_STATION_COUNT; priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID; return 0; } /** - * iwl_hw_txq_ctx_free - Free TXQ Context + * iwl4965_hw_txq_ctx_free - Free TXQ Context * * Destroy all TX DMA queues and structures */ -void iwl_hw_txq_ctx_free(struct iwl_priv *priv) +void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv) { int txq_id; /* Tx queues */ for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, &priv->txq[txq_id]); + iwl4965_tx_queue_free(priv, &priv->txq[txq_id]); + /* Keep-warm buffer */ iwl4965_kw_free(priv); } /** - * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used] + * iwl4965_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] * - * Does NOT advance any indexes + * Does NOT advance any TFD circular buffer read/write indexes + * Does NOT free the TFD itself (which is within circular buffer) */ -int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) { - struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; - struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used]; + struct iwl4965_tfd_frame *bd_tmp = (struct iwl4965_tfd_frame *)&txq->bd[0]; + struct iwl4965_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; struct pci_dev *dev = priv->pci_dev; int i; int counter = 0; int index, is_odd; - /* classify bd */ + /* Host command buffers stay mapped in memory, nothing to clean */ if (txq->q.id == IWL_CMD_QUEUE_NUM) - /* nothing to cleanup after for host commands */ return 0; - /* sanity check */ + /* Sanity check on number of chunks */ counter = IWL_GET_BITS(*bd, num_tbs); if (counter > MAX_NUM_OF_TBS) { IWL_ERROR("Too many chunks: %i\n", counter); @@ -1775,8 +1827,8 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) return 0; } - /* unmap chunks if any */ - + /* Unmap chunks, if any. + * TFD info for odd chunks is different format than for even chunks. */ for (i = 0; i < counter; i++) { index = i / 2; is_odd = i & 0x1; @@ -1796,19 +1848,20 @@ int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) IWL_GET_BITS(bd->pa[index], tb1_len), PCI_DMA_TODEVICE); - if (txq->txb[txq->q.last_used].skb[i]) { - struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i]; + /* Free SKB, if any, for this chunk */ + if (txq->txb[txq->q.read_ptr].skb[i]) { + struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; dev_kfree_skb(skb); - txq->txb[txq->q.last_used].skb[i] = NULL; + txq->txb[txq->q.read_ptr].skb[i] = NULL; } } return 0; } -int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power) +int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power) { - IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n"); + IWL_ERROR("TODO: Implement iwl4965_hw_reg_set_txpower!\n"); return -EINVAL; } @@ -1830,6 +1883,17 @@ static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res) return 1; } +/** + * iwl4965_get_voltage_compensation - Power supply voltage comp for txpower + * + * Determines power supply voltage compensation for txpower calculations. + * Returns number of 1/2-dB steps to subtract from gain table index, + * to compensate for difference between power supply voltage during + * factory measurements, vs. current power supply voltage. + * + * Voltage indication is higher for lower voltage. + * Lower voltage requires more gain (lower gain table index). + */ static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, s32 current_voltage) { @@ -1850,12 +1914,12 @@ static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, return comp; } -static const struct iwl_channel_info * -iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel) +static const struct iwl4965_channel_info * +iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, u8 phymode, u16 channel) { - const struct iwl_channel_info *ch_info; + const struct iwl4965_channel_info *ch_info; - ch_info = iwl_get_channel_info(priv, phymode, channel); + ch_info = iwl4965_get_channel_info(priv, phymode, channel); if (!is_channel_valid(ch_info)) return NULL; @@ -1889,7 +1953,7 @@ static s32 iwl4965_get_tx_atten_grp(u16 channel) return -1; } -static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel) +static u32 iwl4965_get_sub_band(const struct iwl4965_priv *priv, u32 channel) { s32 b = -1; @@ -1917,15 +1981,23 @@ static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2) } } -static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel, - struct iwl_eeprom_calib_ch_info *chan_info) +/** + * iwl4965_interpolate_chan - Interpolate factory measurements for one channel + * + * Interpolates factory measurements from the two sample channels within a + * sub-band, to apply to channel of interest. Interpolation is proportional to + * differences in channel frequencies, which is proportional to differences + * in channel number. + */ +static int iwl4965_interpolate_chan(struct iwl4965_priv *priv, u32 channel, + struct iwl4965_eeprom_calib_ch_info *chan_info) { s32 s = -1; u32 c; u32 m; - const struct iwl_eeprom_calib_measure *m1; - const struct iwl_eeprom_calib_measure *m2; - struct iwl_eeprom_calib_measure *omeas; + const struct iwl4965_eeprom_calib_measure *m1; + const struct iwl4965_eeprom_calib_measure *m2; + struct iwl4965_eeprom_calib_measure *omeas; u32 ch_i1; u32 ch_i2; @@ -2000,7 +2072,7 @@ static s32 back_off_table[] = { /* Thermal compensation values for txpower for various frequency ranges ... * ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */ -static struct iwl_txpower_comp_entry { +static struct iwl4965_txpower_comp_entry { s32 degrees_per_05db_a; s32 degrees_per_05db_a_denom; } tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = { @@ -2250,9 +2322,9 @@ static const struct gain_entry gain_table[2][108] = { } }; -static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, +static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 channel, u8 is_fat, u8 ctrl_chan_high, - struct iwl_tx_power_db *tx_power_tbl) + struct iwl4965_tx_power_db *tx_power_tbl) { u8 saturation_power; s32 target_power; @@ -2264,9 +2336,9 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, s32 txatten_grp = CALIB_CH_GROUP_MAX; int i; int c; - const struct iwl_channel_info *ch_info = NULL; - struct iwl_eeprom_calib_ch_info ch_eeprom_info; - const struct iwl_eeprom_calib_measure *measurement; + const struct iwl4965_channel_info *ch_info = NULL; + struct iwl4965_eeprom_calib_ch_info ch_eeprom_info; + const struct iwl4965_eeprom_calib_measure *measurement; s16 voltage; s32 init_voltage; s32 voltage_compensation; @@ -2405,7 +2477,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, /* for each of 33 bit-rates (including 1 for CCK) */ for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) { u8 is_mimo_rate; - union iwl_tx_power_dual_stream tx_power; + union iwl4965_tx_power_dual_stream tx_power; /* for mimo, reduce each chain's txpower by half * (3dB, 6 steps), so total output power is regulatory @@ -2502,14 +2574,14 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel, } /** - * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit + * iwl4965_hw_reg_send_txpower - Configure the TXPOWER level user limit * * Uses the active RXON for channel, band, and characteristics (fat, high) * The power limit is taken from priv->user_txpower_limit. */ -int iwl_hw_reg_send_txpower(struct iwl_priv *priv) +int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv) { - struct iwl_txpowertable_cmd cmd = { 0 }; + struct iwl4965_txpowertable_cmd cmd = { 0 }; int rc = 0; u8 band = 0; u8 is_fat = 0; @@ -2541,23 +2613,23 @@ int iwl_hw_reg_send_txpower(struct iwl_priv *priv) if (rc) return rc; - rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); + rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd); return rc; } -int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) +int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel) { int rc; u8 band = 0; u8 is_fat = 0; u8 ctrl_chan_high = 0; - struct iwl_channel_switch_cmd cmd = { 0 }; - const struct iwl_channel_info *ch_info; + struct iwl4965_channel_switch_cmd cmd = { 0 }; + const struct iwl4965_channel_info *ch_info; band = ((priv->phymode == MODE_IEEE80211B) || (priv->phymode == MODE_IEEE80211G)); - ch_info = iwl_get_channel_info(priv, priv->phymode, channel); + ch_info = iwl4965_get_channel_info(priv, priv->phymode, channel); is_fat = is_fat_channel(priv->staging_rxon.flags); @@ -2583,32 +2655,36 @@ int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel) return rc; } - rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); + rc = iwl4965_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd); return rc; } #define RTS_HCCA_RETRY_LIMIT 3 #define RTS_DFAULT_RETRY_LIMIT 60 -void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, +void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int sta_id, int is_hcca) { - u8 rate; + struct iwl4965_tx_cmd *tx = &cmd->cmd.tx; u8 rts_retry_limit = 0; u8 data_retry_limit = 0; - __le32 tx_flags; u16 fc = le16_to_cpu(hdr->frame_control); + u8 rate_plcp; + u16 rate_flags = 0; + int rate_idx = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); - tx_flags = cmd->cmd.tx.tx_flags; - - rate = iwl_rates[ctrl->tx_rate].plcp; + rate_plcp = iwl4965_rates[rate_idx].plcp; rts_retry_limit = (is_hcca) ? RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT; + if ((rate_idx >= IWL_FIRST_CCK_RATE) && (rate_idx <= IWL_LAST_CCK_RATE)) + rate_flags |= RATE_MCS_CCK_MSK; + + if (ieee80211_is_probe_response(fc)) { data_retry_limit = 3; if (data_retry_limit < rts_retry_limit) @@ -2619,44 +2695,56 @@ void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, if (priv->data_retry_limit != -1) data_retry_limit = priv->data_retry_limit; - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + + if (ieee80211_is_data(fc)) { + tx->initial_rate_index = 0; + tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; + } else { switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_AUTH: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_ASSOC_REQ: case IEEE80211_STYPE_REASSOC_REQ: - if (tx_flags & TX_CMD_FLG_RTS_MSK) { - tx_flags &= ~TX_CMD_FLG_RTS_MSK; - tx_flags |= TX_CMD_FLG_CTS_MSK; + if (tx->tx_flags & TX_CMD_FLG_RTS_MSK) { + tx->tx_flags &= ~TX_CMD_FLG_RTS_MSK; + tx->tx_flags |= TX_CMD_FLG_CTS_MSK; } break; default: break; } + + /* Alternate between antenna A and B for successive frames */ + if (priv->use_ant_b_for_management_frame) { + priv->use_ant_b_for_management_frame = 0; + rate_flags |= RATE_MCS_ANT_B_MSK; + } else { + priv->use_ant_b_for_management_frame = 1; + rate_flags |= RATE_MCS_ANT_A_MSK; + } } - cmd->cmd.tx.rts_retry_limit = rts_retry_limit; - cmd->cmd.tx.data_retry_limit = data_retry_limit; - cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0); - cmd->cmd.tx.tx_flags = tx_flags; + tx->rts_retry_limit = rts_retry_limit; + tx->data_retry_limit = data_retry_limit; + tx->rate_n_flags = iwl4965_hw_set_rate_n_flags(rate_plcp, rate_flags); } -int iwl_hw_get_rx_read(struct iwl_priv *priv) +int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv) { - struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt; return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num); } -int iwl_hw_get_temperature(struct iwl_priv *priv) +int iwl4965_hw_get_temperature(struct iwl4965_priv *priv) { return priv->temperature; } -unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate) +unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, + struct iwl4965_frame *frame, u8 rate) { - struct iwl_tx_beacon_cmd *tx_beacon_cmd; + struct iwl4965_tx_beacon_cmd *tx_beacon_cmd; unsigned int frame_size; tx_beacon_cmd = &frame->u.beacon; @@ -2665,9 +2753,9 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID; tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - frame_size = iwl_fill_beacon_frame(priv, + frame_size = iwl4965_fill_beacon_frame(priv, tx_beacon_cmd->frame, - BROADCAST_ADDR, + iwl4965_broadcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -2675,53 +2763,59 @@ unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, 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); + iwl4965_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); + iwl4965_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); } -int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) +/* + * Tell 4965 where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * + * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA + * channels supported in hardware. + */ +int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) { int rc; unsigned long flags; int txq_id = txq->q.id; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } - iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id), + /* Circular buffer (TFD queue in DRAM) physical base address */ + iwl4965_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); - iwl_write_restricted( + + /* Enable DMA channel, using same id as for TFD queue */ + iwl4965_write_direct32( priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr) -{ - return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; -} - -int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, +int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *ptr, dma_addr_t addr, u16 len) { int index, is_odd; - struct iwl_tfd_frame *tfd = ptr; + struct iwl4965_tfd_frame *tfd = ptr; u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + /* Each TFD can point to a maximum 20 Tx buffers */ if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) { IWL_ERROR("Error can not send more than %d chunks\n", MAX_NUM_OF_TBS); @@ -2734,7 +2828,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, if (!is_odd) { tfd->pa[index].tb1_addr = cpu_to_le32(addr); IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl4965_get_dma_hi_address(addr)); + iwl_get_dma_hi_address(addr)); IWL_SET_BITS(tfd->pa[index], tb1_len, len); } else { IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, @@ -2748,7 +2842,7 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, return 0; } -void iwl_hw_card_show_info(struct iwl_priv *priv) +static void iwl4965_hw_card_show_info(struct iwl4965_priv *priv) { u16 hw_version = priv->eeprom.board_revision_4965; @@ -2763,32 +2857,41 @@ void iwl_hw_card_show_info(struct iwl_priv *priv) #define IWL_TX_CRC_SIZE 4 #define IWL_TX_DELIMITER_SIZE 4 -int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq, u16 byte_cnt) +/** + * iwl4965_tx_queue_update_wr_ptr - Set up entry in Tx byte-count array + */ +int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq, u16 byte_cnt) { int len; int txq_id = txq->q.id; - struct iwl_shared *shared_data = priv->hw_setting.shared_virt; + struct iwl4965_shared *shared_data = priv->hw_setting.shared_virt; if (txq->need_update == 0) return 0; len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + /* Set up byte count within first 256 entries */ IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.first_empty], byte_cnt, len); + tfd_offset[txq->q.write_ptr], byte_cnt, len); - if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE) + /* If within first 64 entries, duplicate at end */ + if (txq->q.write_ptr < IWL4965_MAX_WIN_SIZE) IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty], + tfd_offset[IWL4965_QUEUE_SIZE + txq->q.write_ptr], byte_cnt, len); return 0; } -/* Set up Rx receiver/antenna/chain usage in "staging" RXON image. - * This should not be used for scan command ... it puts data in wrong place. */ -void iwl4965_set_rxon_chain(struct iwl_priv *priv) +/** + * iwl4965_set_rxon_chain - Set up Rx chain usage in "staging" RXON image + * + * Selects how many and which Rx receivers/antennas/chains to use. + * This should not be used for scan command ... it puts data in wrong place. + */ +void iwl4965_set_rxon_chain(struct iwl4965_priv *priv) { u8 is_single = is_single_stream(priv); u8 idle_state, rx_state; @@ -2819,19 +2922,19 @@ void iwl4965_set_rxon_chain(struct iwl_priv *priv) IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain); } -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG /* get the traffic load value for tid */ -static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid) +static u32 iwl4965_tl_get_load(struct iwl4965_priv *priv, u8 tid) { u32 load = 0; u32 current_time = jiffies_to_msecs(jiffies); u32 time_diff; s32 index; unsigned long flags; - struct iwl_traffic_load *tid_ptr = NULL; + struct iwl4965_traffic_load *tid_ptr = NULL; if (tid >= TID_MAX_LOAD_COUNT) return 0; @@ -2872,13 +2975,13 @@ static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid) increment traffic load value for tid and also remove any old values if passed the certian time period */ -static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid) +static void iwl4965_tl_add_packet(struct iwl4965_priv *priv, u8 tid) { u32 current_time = jiffies_to_msecs(jiffies); u32 time_diff; s32 index; unsigned long flags; - struct iwl_traffic_load *tid_ptr = NULL; + struct iwl4965_traffic_load *tid_ptr = NULL; if (tid >= TID_MAX_LOAD_COUNT) return; @@ -2935,14 +3038,19 @@ enum HT_STATUS { BA_STATUS_ACTIVE, }; -static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv) +/** + * iwl4964_tl_ba_avail - Find out if an unused aggregation queue is available + */ +static u8 iwl4964_tl_ba_avail(struct iwl4965_priv *priv) { int i; - struct iwl_lq_mngr *lq; + struct iwl4965_lq_mngr *lq; u8 count = 0; u16 msk; - lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); + + /* Find out how many agg queues are in use */ for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) { msk = 1 << i; if ((lq->agg_ctrl.granted_ba & msk) || @@ -2956,10 +3064,10 @@ static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv) return 0; } -static void iwl4965_ba_status(struct iwl_priv *priv, +static void iwl4965_ba_status(struct iwl4965_priv *priv, u8 tid, enum HT_STATUS status); -static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length, +static int iwl4965_perform_addba(struct iwl4965_priv *priv, u8 tid, u32 length, u32 ba_timeout) { int rc; @@ -2971,7 +3079,7 @@ static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length, return rc; } -static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid) +static int iwl4965_perform_delba(struct iwl4965_priv *priv, u8 tid) { int rc; @@ -2982,8 +3090,8 @@ static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid) return rc; } -static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv, - struct iwl_lq_mngr *lq, +static void iwl4965_turn_on_agg_for_tid(struct iwl4965_priv *priv, + struct iwl4965_lq_mngr *lq, u8 auto_agg, u8 tid) { u32 tid_msk = (1 << tid); @@ -3030,12 +3138,12 @@ static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); } -static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid) +static void iwl4965_turn_on_agg(struct iwl4965_priv *priv, u8 tid) { - struct iwl_lq_mngr *lq; + struct iwl4965_lq_mngr *lq; unsigned long flags; - lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); if ((tid < TID_MAX_LOAD_COUNT)) iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg, @@ -3055,13 +3163,13 @@ static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid) } -void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid) +void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid) { u32 tid_msk; - struct iwl_lq_mngr *lq; + struct iwl4965_lq_mngr *lq; unsigned long flags; - lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); if ((tid < TID_MAX_LOAD_COUNT)) { tid_msk = 1 << tid; @@ -3084,14 +3192,17 @@ void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid) } } -static void iwl4965_ba_status(struct iwl_priv *priv, +/** + * iwl4965_ba_status - Update driver's link quality mgr with tid's HT status + */ +static void iwl4965_ba_status(struct iwl4965_priv *priv, u8 tid, enum HT_STATUS status) { - struct iwl_lq_mngr *lq; + struct iwl4965_lq_mngr *lq; u32 tid_msk = (1 << tid); unsigned long flags; - lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); if ((tid >= TID_MAX_LOAD_COUNT)) goto out; @@ -3124,14 +3235,14 @@ static void iwl4965_ba_status(struct iwl_priv *priv, static void iwl4965_bg_agg_work(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, + struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, agg_work); u32 tid; u32 retry_tid; u32 tid_msk; unsigned long flags; - struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr); + struct iwl4965_lq_mngr *lq = (struct iwl4965_lq_mngr *)&(priv->lq_mngr); spin_lock_irqsave(&priv->lq_mngr.lock, flags); retry_tid = lq->agg_ctrl.tid_retry; @@ -3154,90 +3265,13 @@ static void iwl4965_bg_agg_work(struct work_struct *work) spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); return; } -#endif /*CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ -int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, - u8 sta_id, dma_addr_t txcmd_phys, - struct ieee80211_hdr *hdr, u8 hdr_len, - struct ieee80211_tx_control *ctrl, void *sta_in) +/* TODO: move this functionality to rate scaling */ +void iwl4965_tl_get_stats(struct iwl4965_priv *priv, + struct ieee80211_hdr *hdr) { - struct iwl_tx_cmd cmd; - struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0]; - dma_addr_t scratch_phys; - u8 unicast = 0; - u8 is_data = 1; - u16 fc; - u16 rate_flags; - int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG - __le16 *qc; -#endif /*CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ - - unicast = !is_multicast_ether_addr(hdr->addr1); - - fc = le16_to_cpu(hdr->frame_control); - if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - is_data = 0; - - memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd)); - memset(tx, 0, sizeof(struct iwl_tx_cmd)); - memcpy(tx->hdr, hdr, hdr_len); - - tx->len = cmd.len; - tx->driver_txop = cmd.driver_txop; - tx->stop_time.life_time = cmd.stop_time.life_time; - tx->tx_flags = cmd.tx_flags; - tx->sta_id = cmd.sta_id; - tx->tid_tspec = cmd.tid_tspec; - tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout; - tx->next_frame_len = cmd.next_frame_len; - - tx->sec_ctl = cmd.sec_ctl; - memcpy(&(tx->key[0]), &(cmd.key[0]), 16); - tx->tx_flags = cmd.tx_flags; - - tx->rts_retry_limit = cmd.rts_retry_limit; - tx->data_retry_limit = cmd.data_retry_limit; - - scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch); - tx->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys); - - /* Hard coded to start at the highest retry fallback position - * until the 4965 specific rate control algorithm is tied in */ - tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1; - - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags = RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags = RATE_MCS_ANT_A_MSK; - } + __le16 *qc = ieee80211_get_qos_ctrl(hdr); - if (!unicast || !is_data) { - if ((rate_index >= IWL_FIRST_CCK_RATE) && - (rate_index <= IWL_LAST_CCK_RATE)) - rate_flags |= RATE_MCS_CCK_MSK; - } else { - tx->initial_rate_index = 0; - tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK; - } - - tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp, - rate_flags); - - if (ieee80211_is_back_request(fc)) - tx->tx_flags |= TX_CMD_FLG_ACK_MSK | - TX_CMD_FLG_IMM_BA_RSP_MASK; -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG - qc = ieee80211_get_qos_ctrl(hdr); if (qc && (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) { u8 tid = 0; @@ -3255,11 +3289,11 @@ int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, spin_unlock_irqrestore(&priv->lq_mngr.lock, flags); schedule_work(&priv->agg_work); } -#endif -#endif - return 0; } +#endif /*CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ + /** * sign_extend - Sign extend a value using specified bit as sign-bit * @@ -3282,7 +3316,7 @@ static s32 sign_extend(u32 oper, int index) * * A return of <0 indicates bogus data in the statistics */ -int iwl4965_get_temperature(const struct iwl_priv *priv) +int iwl4965_get_temperature(const struct iwl4965_priv *priv) { s32 temperature; s32 vt; @@ -3305,11 +3339,12 @@ int iwl4965_get_temperature(const struct iwl_priv *priv) } /* - * Temperature is only 23 bits so sign extend out to 32 + * Temperature is only 23 bits, so sign extend out to 32. * * NOTE If we haven't received a statistics notification yet * with an updated temperature, use R4 provided to us in the - * ALIVE response. */ + * "initialize" ALIVE response. + */ if (!test_bit(STATUS_TEMPERATURE, &priv->status)) vt = sign_extend(R4, 23); else @@ -3349,7 +3384,7 @@ int iwl4965_get_temperature(const struct iwl_priv *priv) * Assumes caller will replace priv->last_temperature once calibration * executed. */ -static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) +static int iwl4965_is_temp_calib_needed(struct iwl4965_priv *priv) { int temp_diff; @@ -3382,7 +3417,7 @@ static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv) /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl4965_rx_calc_noise(struct iwl_priv *priv) +static void iwl4965_rx_calc_noise(struct iwl4965_priv *priv) { struct statistics_rx_non_phy *rx_info = &(priv->statistics.rx.general); @@ -3419,9 +3454,9 @@ static void iwl4965_rx_calc_noise(struct iwl_priv *priv) priv->last_rx_noise); } -void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; int change; s32 temp; @@ -3448,7 +3483,7 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { iwl4965_rx_calc_noise(priv); -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY queue_work(priv->workqueue, &priv->sensitivity_work); #endif } @@ -3483,12 +3518,117 @@ void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) queue_work(priv->workqueue, &priv->txpower_work); } -static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, +static void iwl4965_add_radiotap(struct iwl4965_priv *priv, + struct sk_buff *skb, + struct iwl4965_rx_phy_res *rx_start, + struct ieee80211_rx_status *stats, + u32 ampdu_status) +{ + s8 signal = stats->ssi; + s8 noise = 0; + int rate = stats->rate; + u64 tsf = stats->mactime; + __le16 phy_flags_hw = rx_start->phy_flags; + struct iwl4965_rt_rx_hdr { + struct ieee80211_radiotap_header rt_hdr; + __le64 rt_tsf; /* TSF */ + u8 rt_flags; /* radiotap packet flags */ + u8 rt_rate; /* rate in 500kb/s */ + __le16 rt_channelMHz; /* channel in MHz */ + __le16 rt_chbitmask; /* channel bitfield */ + s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ + s8 rt_dbmnoise; + u8 rt_antenna; /* antenna number */ + } __attribute__ ((packed)) *iwl4965_rt; + + /* TODO: We won't have enough headroom for HT frames. Fix it later. */ + if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { + if (net_ratelimit()) + printk(KERN_ERR "not enough headroom [%d] for " + "radiotap head [%zd]\n", + skb_headroom(skb), sizeof(*iwl4965_rt)); + return; + } + + /* put radiotap header in front of 802.11 header and data */ + iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); + + /* initialise radiotap header */ + iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + iwl4965_rt->rt_hdr.it_pad = 0; + + /* total header + data */ + put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), + &iwl4965_rt->rt_hdr.it_len); + + /* Indicate all the fields we add to the radiotap header */ + put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA)), + &iwl4965_rt->rt_hdr.it_present); + + /* Zero the flags, we'll add to them as we go */ + iwl4965_rt->rt_flags = 0; + + put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); + + iwl4965_rt->rt_dbmsignal = signal; + iwl4965_rt->rt_dbmnoise = noise; + + /* Convert the channel frequency and set the flags */ + put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); + if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) + put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ), + &iwl4965_rt->rt_chbitmask); + else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) + put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | + IEEE80211_CHAN_2GHZ), + &iwl4965_rt->rt_chbitmask); + else /* 802.11g */ + put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_2GHZ), + &iwl4965_rt->rt_chbitmask); + + rate = iwl4965_rate_index_from_plcp(rate); + if (rate == -1) + iwl4965_rt->rt_rate = 0; + else + iwl4965_rt->rt_rate = iwl4965_rates[rate].ieee; + + /* + * "antenna number" + * + * It seems that the antenna field in the phy flags value + * is actually a bitfield. This is undefined by radiotap, + * it wants an actual antenna number but I always get "7" + * for most legacy frames I receive indicating that the + * same frame was received on all three RX chains. + * + * I think this field should be removed in favour of a + * new 802.11n radiotap field "RX chains" that is defined + * as a bitmask. + */ + iwl4965_rt->rt_antenna = + le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; + + /* set the preamble flag if appropriate */ + if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) + iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + + stats->flag |= RX_FLAG_RADIOTAP; +} + +static void iwl4965_handle_data_packet(struct iwl4965_priv *priv, int is_data, int include_phy, - struct iwl_rx_mem_buffer *rxb, + struct iwl4965_rx_mem_buffer *rxb, struct ieee80211_rx_status *stats) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (struct iwl4965_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 ieee80211_hdr *hdr; @@ -3524,9 +3664,8 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, rx_start->byte_count = amsdu->byte_count; rx_end = (__le32 *) (((u8 *) hdr) + len); } - if (len > 2342 || len < 16) { - IWL_DEBUG_DROP("byte count out of range [16,2342]" - " : %d\n", len); + if (len > priv->hw_setting.max_pkt_size || len < 16) { + IWL_WARNING("byte count out of range [16,4K] : %d\n", len); return; } @@ -3544,26 +3683,21 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data, return; } - if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { - if (iwl_param_hwcrypto) - iwl_set_decrypted_flag(priv, rxb->skb, - ampdu_status, stats); - iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0); - return; - } - stats->flag = 0; hdr = (struct ieee80211_hdr *)rxb->skb->data; - if (iwl_param_hwcrypto) - iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); + if (iwl4965_param_hwcrypto) + iwl4965_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats); + + if (priv->add_radiotap) + iwl4965_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); priv->alloc_rxb_skb--; rxb->skb = NULL; #ifdef LED priv->led_packets += len; - iwl_setup_activity_timer(priv); + iwl4965_setup_activity_timer(priv); #endif } @@ -3601,7 +3735,7 @@ static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp) return (max_rssi - agc - IWL_RSSI_OFFSET); } -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT /* Parsed Information Elements */ struct ieee802_11_elems { @@ -3673,9 +3807,37 @@ static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems) return 0; } -#endif /* CONFIG_IWLWIFI_HT */ -static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, int mode) +{ + ht_info->cap = 0; + memset(ht_info->supp_mcs_set, 0, 16); + + ht_info->ht_supported = 1; + + if (mode == MODE_IEEE80211A) { + ht_info->cap |= (u16)IEEE80211_HT_CAP_SUP_WIDTH; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_40; + ht_info->supp_mcs_set[4] = 0x01; + } + ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (u16)(IEEE80211_HT_CAP_MIMO_PS & + (IWL_MIMO_PS_NONE << 2)); + if (iwl4965_param_amsdu_size_8K) { + printk(KERN_DEBUG "iwl4965 in A-MSDU 8K support mode\n"); + ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; + } + + ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; + ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; + + ht_info->supp_mcs_set[0] = 0xFF; + ht_info->supp_mcs_set[1] = 0xFF; +} +#endif /* CONFIG_IWL4965_HT */ + +static void iwl4965_sta_modify_ps_wake(struct iwl4965_priv *priv, int sta_id) { unsigned long flags; @@ -3686,13 +3848,13 @@ static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +static void iwl4965_update_ps_mode(struct iwl4965_priv *priv, u16 ps_bit, u8 *addr) { /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_hw_find_station(priv, addr); + u8 sta_id = iwl4965_hw_find_station(priv, addr); if (sta_id != IWL_INVALID_STATION) { u8 sta_awake = priv->stations[sta_id]. @@ -3707,12 +3869,14 @@ static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) } } +#define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) + /* Called for REPLY_4965_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -static void iwl4965_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; /* Use phy data (Rx signal strength, etc.) contained within * this rx packet for legacy frames, * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ @@ -3731,11 +3895,8 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? MODE_IEEE80211G : MODE_IEEE80211A, .antenna = 0, - .rate = iwl_hw_get_rate(rx_start->rate_n_flags), + .rate = iwl4965_hw_get_rate(rx_start->rate_n_flags), .flag = 0, -#ifdef CONFIG_IWLWIFI_HT_AGG - .ordered = 0 -#endif /* CONFIG_IWLWIFI_HT_AGG */ }; u8 network_packet; @@ -3794,32 +3955,32 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, * which are gathered only when associated, and indicate noise * only for the associated network channel ... * Ignore these noise values while scanning (other channels) */ - if (iwl_is_associated(priv) && + if (iwl4965_is_associated(priv) && !test_bit(STATUS_SCANNING, &priv->status)) { stats.noise = priv->last_rx_noise; - stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise); + stats.signal = iwl4965_calc_sig_qual(stats.ssi, stats.noise); } else { stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; - stats.signal = iwl_calc_sig_qual(stats.ssi, 0); + stats.signal = iwl4965_calc_sig_qual(stats.ssi, 0); } /* Reset beacon noise level if not associated. */ - if (!iwl_is_associated(priv)) + if (!iwl4965_is_associated(priv)) priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; -#ifdef CONFIG_IWLWIFI_DEBUG - /* TODO: Parts of iwl_report_frame are broken for 4965 */ - if (iwl_debug_level & (IWL_DL_RX)) +#ifdef CONFIG_IWL4965_DEBUG + /* TODO: Parts of iwl4965_report_frame are broken for 4965 */ + if (iwl4965_debug_level & (IWL_DL_RX)) /* Set "1" to report good data frames in groups of 100 */ - iwl_report_frame(priv, pkt, header, 1); + iwl4965_report_frame(priv, pkt, header, 1); - if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS)) + if (iwl4965_debug_level & (IWL_DL_RX | IWL_DL_STATS)) IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n", stats.ssi, stats.noise, stats.signal, (long unsigned int)le64_to_cpu(rx_start->timestamp)); #endif - network_packet = iwl_is_network_packet(priv, header); + network_packet = iwl4965_is_network_packet(priv, header); if (network_packet) { priv->last_rx_rssi = stats.ssi; priv->last_beacon_time = priv->ucode_beacon_time; @@ -3863,27 +4024,31 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, break; /* - * TODO: There is no callback function from upper - * stack to inform us when associated status. this - * work around to sniff assoc_resp management frame - * and finish the association process. + * TODO: Use the new callback function from + * mac80211 instead of sniffing these packets. */ case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: if (network_packet) { -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT u8 *pos = NULL; struct ieee802_11_elems elems; -#endif /*CONFIG_IWLWIFI_HT */ +#endif /*CONFIG_IWL4965_HT */ struct ieee80211_mgmt *mgnt = (struct ieee80211_mgmt *)header; + /* We have just associated, give some + * time for the 4-way handshake if + * any. Don't start scan too early. */ + priv->next_scan_jiffies = jiffies + + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; + priv->assoc_id = (~((1 << 15) | (1 << 14)) & le16_to_cpu(mgnt->u.assoc_resp.aid)); priv->assoc_capability = le16_to_cpu( mgnt->u.assoc_resp.capab_info); -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT pos = mgnt->u.assoc_resp.variable; if (!parse_elems(pos, len - (pos - (u8 *) mgnt), @@ -3892,7 +4057,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, elems.ht_cap_param) break; } -#endif /*CONFIG_IWLWIFI_HT */ +#endif /*CONFIG_IWL4965_HT */ /* assoc_id is 0 no association */ if (!priv->assoc_id) break; @@ -3907,7 +4072,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, case IEEE80211_STYPE_PROBE_REQ: if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && - !iwl_is_associated(priv)) { + !iwl4965_is_associated(priv)) { DECLARE_MAC_BUF(mac1); DECLARE_MAC_BUF(mac2); DECLARE_MAC_BUF(mac3); @@ -3924,7 +4089,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, break; case IEEE80211_FTYPE_CTL: -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT switch (fc & IEEE80211_FCTL_STYPE) { case IEEE80211_STYPE_BACK_REQ: IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); @@ -3935,7 +4100,6 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, break; } #endif - break; case IEEE80211_FTYPE_DATA: { @@ -3953,7 +4117,7 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, print_mac(mac1, header->addr1), print_mac(mac2, header->addr2), print_mac(mac3, header->addr3)); - else if (unlikely(is_duplicate_packet(priv, header))) + else if (unlikely(iwl4965_is_duplicate_packet(priv, header))) IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", print_mac(mac1, header->addr1), print_mac(mac2, header->addr2), @@ -3971,22 +4135,22 @@ static void iwl4965_rx_reply_rx(struct iwl_priv *priv, /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_reply_rx_phy(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)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)); } -static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_missed_beacon_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_SENSITIVITY - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_missed_beacon_notif *missed_beacon; +#ifdef CONFIG_IWL4965_SENSITIVITY + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { @@ -3999,13 +4163,18 @@ static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv, if (unlikely(!test_bit(STATUS_SCANNING, &priv->status))) queue_work(priv->workqueue, &priv->sensitivity_work); } -#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ +#endif /*CONFIG_IWL4965_SENSITIVITY*/ } -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG -static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx, +/** + * iwl4965_set_tx_status - Update driver's record of one Tx frame's status + * + * This will get sent to mac80211. + */ +static void iwl4965_set_tx_status(struct iwl4965_priv *priv, int txq_id, int idx, u32 status, u32 retry_count, u32 rate) { struct ieee80211_tx_status *tx_status = @@ -4017,24 +4186,34 @@ static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx, } -static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, +/** + * iwl4965_sta_modify_enable_tid_tx - Enable Tx for this TID in station table + */ +static void iwl4965_sta_modify_enable_tid_tx(struct iwl4965_priv *priv, int sta_id, int tid) { unsigned long flags; + /* Remove "disable" flag, to enable Tx for this TID */ spin_lock_irqsave(&priv->sta_lock, flags); priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwl_compressed_ba_resp* +/** + * iwl4965_tx_status_reply_compressed_ba - Update tx status from block-ack + * + * Go through block-ack's bitmap of ACK'd frames, update driver's record of + * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. + */ +static int iwl4965_tx_status_reply_compressed_ba(struct iwl4965_priv *priv, + struct iwl4965_ht_agg *agg, + struct iwl4965_compressed_ba_resp* ba_resp) { @@ -4048,16 +4227,20 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, IWL_ERROR("Received BA when not expected\n"); return -EINVAL; } + + /* Mark that the expected block-ack response arrived */ agg->wait_for_ba = 0; IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl); - sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4); - if (sh < 0) /* tbw something is wrong with indeces */ + + /* Calculate shift to align block-ack bits with our Tx window bits */ + sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl >> 4); + if (sh < 0) /* tbw something is wrong with indices */ sh += 0x100; - /* don't use 64 bits for now */ + /* don't use 64-bit values for now */ bitmap0 = resp_bitmap0 >> sh; bitmap1 = resp_bitmap1 >> sh; - bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh); + bitmap0 |= (resp_bitmap1 & ((1 << sh) | ((1 << sh) - 1))) << (32 - sh); if (agg->frame_count > (64 - sh)) { IWL_DEBUG_TX_REPLY("more frames than bitmap size"); @@ -4065,10 +4248,12 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, } /* check for success or failure according to the - * transmitted bitmap and back bitmap */ + * transmitted bitmap and block-ack bitmap */ bitmap0 &= agg->bitmap0; bitmap1 &= agg->bitmap1; + /* For each frame attempted in aggregation, + * update driver's record of tx frame's status. */ for (i = 0; i < agg->frame_count ; i++) { int idx = (agg->start_idx + i) & 0xff; ack = bitmap0 & (1 << i); @@ -4084,20 +4269,36 @@ static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv, return 0; } -static inline int iwl_queue_dec_wrap(int index, int n_bd) +/** + * iwl4965_queue_dec_wrap - Decrement queue index, wrap back to end if needed + * @index -- current index + * @n_bd -- total number of entries in queue (s/b power of 2) + */ +static inline int iwl4965_queue_dec_wrap(int index, int n_bd) { return (index == 0) ? n_bd - 1 : index - 1; } -static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +/** + * iwl4965_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA + * + * Handles block-acknowledge notification from device, which reports success + * of frames sent via aggregation. + */ +static void iwl4965_rx_reply_compressed_ba(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; int index; - struct iwl_tx_queue *txq = NULL; - struct iwl_ht_agg *agg; + struct iwl4965_tx_queue *txq = NULL; + struct iwl4965_ht_agg *agg; + + /* "flow" corresponds to Tx queue */ u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow); + + /* "ssn" is start of block-ack Tx window, corresponds to index + * (in Tx queue's circular buffer) of first TFD/frame in window */ u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) { @@ -4107,9 +4308,11 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, txq = &priv->txq[ba_resp_scd_flow]; agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; - index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); - /* TODO: Need to get this copy more sefely - now good for debug */ + /* Find index just before block-ack window */ + index = iwl4965_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); + + /* TODO: Need to get this copy more safely - now good for debug */ /* { DECLARE_MAC_BUF(mac); @@ -4132,23 +4335,36 @@ static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv, agg->bitmap0); } */ + + /* Update driver's record of ACK vs. not for each frame in window */ iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp); - /* releases all the TFDs until the SSN */ - if (txq->q.last_used != (ba_resp_scd_ssn & 0xff)) - iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index); + + /* Release all TFDs before the SSN, i.e. all TFDs in front of + * block-ack window (we assume that they've been successfully + * transmitted ... if not, it's too late anyway). */ + if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) + iwl4965_tx_queue_reclaim(priv, ba_resp_scd_flow, index); } -static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) +/** + * iwl4965_tx_queue_stop_scheduler - Stop queue, but keep configuration + */ +static void iwl4965_tx_queue_stop_scheduler(struct iwl4965_priv *priv, u16 txq_id) { - iwl_write_restricted_reg(priv, - SCD_QUEUE_STATUS_BITS(txq_id), + /* Simply stop the queue, but don't change any configuration; + * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ + iwl4965_write_prph(priv, + KDR_SCD_QUEUE_STATUS_BITS(txq_id), (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } -static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, +/** + * iwl4965_tx_queue_set_q2ratid - Map unique receiver/tid combination to a queue + */ +static int iwl4965_tx_queue_set_q2ratid(struct iwl4965_priv *priv, u16 ra_tid, u16 txq_id) { u32 tbl_dw_addr; @@ -4160,22 +4376,25 @@ static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, tbl_dw_addr = priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id); - tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr); + tbl_dw = iwl4965_read_targ_mem(priv, tbl_dw_addr); if (txq_id & 0x1) tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); else tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); - iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw); + iwl4965_write_targ_mem(priv, tbl_dw_addr, tbl_dw); return 0; } /** - * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID + * iwl4965_tx_queue_agg_enable - Set up & enable aggregation for selected queue + * + * NOTE: txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID, + * i.e. it must be one of the higher queues used for aggregation */ -static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, +static int iwl4965_tx_queue_agg_enable(struct iwl4965_priv *priv, int txq_id, int tx_fifo, int sta_id, int tid, u16 ssn_idx) { @@ -4189,43 +4408,48 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + /* Modify device's station table to Tx this TID */ + iwl4965_sta_modify_enable_tid_tx(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } + /* Stop this Tx queue before configuring it */ iwl4965_tx_queue_stop_scheduler(priv, txq_id); + /* Map receiver-address / traffic-ID to this queue */ iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id); + /* Set this queue as a chain-building queue */ + iwl4965_set_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id)); - iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id)); - - priv->txq[txq_id].q.last_used = (ssn_idx & 0xff); - priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff); - - /* supposes that ssn_idx is valid (!= 0xFFF) */ + /* Place first TFD at index corresponding to start sequence number. + * Assumes that ssn_idx is valid (!= 0xFFF) */ + priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); + priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); - iwl_write_restricted_mem(priv, + /* Set up Tx window size and frame limit for this queue */ + iwl4965_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id), (SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) & SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK); - iwl_write_restricted_mem(priv, priv->scd_base_addr + + iwl4965_write_targ_mem(priv, priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), (SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK); - iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl4965_set_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id)); + /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; @@ -4234,7 +4458,7 @@ static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id, /** * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID */ -static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, +static int iwl4965_tx_queue_agg_disable(struct iwl4965_priv *priv, u16 txq_id, u16 ssn_idx, u8 tx_fifo) { unsigned long flags; @@ -4247,7 +4471,7 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, } spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; @@ -4255,56 +4479,50 @@ static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id, iwl4965_tx_queue_stop_scheduler(priv, txq_id); - iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id)); + iwl4965_clear_bits_prph(priv, KDR_SCD_QUEUECHAIN_SEL, (1 << txq_id)); - priv->txq[txq_id].q.last_used = (ssn_idx & 0xff); - priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff); + priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); + priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); /* supposes that ssn_idx is valid (!= 0xFFF) */ iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx); - iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl4965_clear_bits_prph(priv, KDR_SCD_INTERRUPT_MASK, (1 << txq_id)); iwl4965_txq_ctx_deactivate(priv, txq_id); iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); return 0; } -#endif/* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ -/* - * RATE SCALE CODE - */ -int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates) -{ - return 0; -} - +#endif/* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ /** * iwl4965_add_station - Initialize a station's hardware rate table * - * The uCode contains a table of fallback rates and retries per rate + * The uCode's station table contains a table of fallback rates * for automatic fallback during transmission. * - * NOTE: This initializes the table for a single retry per data rate - * which is not optimal. Setting up an intelligent retry per rate - * requires feedback from transmission, which isn't exposed through - * rc80211_simple which is what this driver is currently using. + * 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 + * rc80211_simple. * + * NOTE: Run REPLY_ADD_STA command to set up station table entry, before + * calling this function (which runs REPLY_TX_LINK_QUALITY_CMD, + * which requires station table entry to exist). */ -void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) { int i, r; - struct iwl_link_quality_cmd link_cmd = { + struct iwl4965_link_quality_cmd link_cmd = { .reserved1 = 0, }; u16 rate_flags; - /* Set up the rate scaling to start at 54M and fallback - * all the way to 1M in IEEE order and then spin on IEEE */ + /* Set up the rate scaling to start at selected rate, fall back + * all the way down to 1M in IEEE order, and then spin on 1M */ if (is_ap) r = IWL_RATE_54M_INDEX; else if (priv->phymode == MODE_IEEE80211A) @@ -4317,11 +4535,13 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; + /* Use Tx antenna B only */ rate_flags |= RATE_MCS_ANT_B_MSK; rate_flags &= ~RATE_MCS_ANT_A_MSK; + link_cmd.rs_table[i].rate_n_flags = - iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - r = iwl_get_prev_ieee_rate(r); + iwl4965_hw_set_rate_n_flags(iwl4965_rates[r].plcp, rate_flags); + r = iwl4965_get_prev_ieee_rate(r); } link_cmd.general_params.single_stream_ant_msk = 2; @@ -4332,18 +4552,18 @@ void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) /* Update the rate scaling for control frame Tx to AP */ link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID; - iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), + iwl4965_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd), &link_cmd); } -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT -static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode, +static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode, u16 channel, u8 extension_chan_offset) { - const struct iwl_channel_info *ch_info; + const struct iwl4965_channel_info *ch_info; - ch_info = iwl_get_channel_info(priv, phymode, channel); + ch_info = iwl4965_get_channel_info(priv, phymode, channel); if (!is_channel_valid(ch_info)) return 0; @@ -4357,36 +4577,37 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode, return 0; } -static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - const struct sta_ht_info *ht_info) +static u8 iwl4965_is_fat_tx_allowed(struct iwl4965_priv *priv, + struct ieee80211_ht_info *sta_ht_inf) { + struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; - if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) + if ((!iwl_ht_conf->is_ht) || + (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || + (iwl_ht_conf->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)) return 0; - if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) - return 0; - - if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO) - return 0; + if (sta_ht_inf) { + if ((!sta_ht_inf->ht_supported) || + (!sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH)) + return 0; + } - /* no fat tx allowed on 2.4GHZ */ - if (priv->phymode != MODE_IEEE80211A) - return 0; - return (iwl_is_channel_extension(priv, priv->phymode, - ht_info->control_channel, - ht_info->extension_chan_offset)); + return (iwl4965_is_channel_extension(priv, priv->phymode, + iwl_ht_conf->control_channel, + iwl_ht_conf->extension_chan_offset)); } -void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) +void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, struct iwl_ht_info *ht_info) { - struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; u32 val; if (!ht_info->is_ht) return; - if (iwl_is_fat_tx_allowed(priv, ht_info)) + /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ + if (iwl4965_is_fat_tx_allowed(priv, NULL)) rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; else rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | @@ -4400,7 +4621,7 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) return; } - /* Note: control channel is oposit to extension channel */ + /* Note: control channel is opposite of extension channel */ switch (ht_info->extension_chan_offset) { case IWL_EXT_CHANNEL_OFFSET_ABOVE: rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); @@ -4416,66 +4637,56 @@ void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info) break; } - val = ht_info->operating_mode; + val = ht_info->ht_protection; rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); - priv->active_rate_ht[0] = ht_info->supp_rates[0]; - priv->active_rate_ht[1] = ht_info->supp_rates[1]; iwl4965_set_rxon_chain(priv); IWL_DEBUG_ASSOC("supported HT rate 0x%X %X " "rxon flags 0x%X operation mode :0x%X " "extension channel offset 0x%x " "control chan %d\n", - priv->active_rate_ht[0], priv->active_rate_ht[1], - le32_to_cpu(rxon->flags), ht_info->operating_mode, + ht_info->supp_mcs_set[0], ht_info->supp_mcs_set[1], + le32_to_cpu(rxon->flags), ht_info->ht_protection, ht_info->extension_chan_offset, ht_info->control_channel); return; } -void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index) +void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_inf) { __le32 sta_flags; - struct sta_ht_info *ht_info = &priv->current_assoc_ht; - priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ; - if (!ht_info->is_ht) + if (!sta_ht_inf || !sta_ht_inf->ht_supported) goto done; sta_flags = priv->stations[index].sta.station_flags; - if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC) + if (((sta_ht_inf->cap & IEEE80211_HT_CAP_MIMO_PS >> 2)) + == IWL_MIMO_PS_DYNAMIC) sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; else sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK; sta_flags |= cpu_to_le32( - (u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); sta_flags |= cpu_to_le32( - (u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - - sta_flags &= (~STA_FLG_FAT_EN_MSK); - ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ; - ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ; + (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - if (iwl_is_fat_tx_allowed(priv, ht_info)) { + if (iwl4965_is_fat_tx_allowed(priv, sta_ht_inf)) sta_flags |= STA_FLG_FAT_EN_MSK; - ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ; - if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ) - ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ; - } - priv->current_channel_width = ht_info->tx_chan_width; + else + sta_flags &= (~STA_FLG_FAT_EN_MSK); + priv->stations[index].sta.station_flags = sta_flags; done: return; } -#ifdef CONFIG_IWLWIFI_HT_AGG - -static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, +static void iwl4965_sta_modify_add_ba_tid(struct iwl4965_priv *priv, int sta_id, int tid, u16 ssn) { unsigned long flags; @@ -4488,10 +4699,10 @@ static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, +static void iwl4965_sta_modify_del_ba_tid(struct iwl4965_priv *priv, int sta_id, int tid) { unsigned long flags; @@ -4503,9 +4714,39 @@ static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv, priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 ssn) +{ + struct iwl4965_priv *priv = hw->priv; + int sta_id; + DECLARE_MAC_BUF(mac); + + IWL_DEBUG_HT("A-MPDU action on da=%s tid=%d ", + print_mac(mac, addr), tid); + sta_id = iwl4965_hw_find_station(priv, addr); + switch (action) { + case IEEE80211_AMPDU_RX_START: + IWL_DEBUG_HT("start Rx\n"); + iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, ssn); + break; + case IEEE80211_AMPDU_RX_STOP: + IWL_DEBUG_HT("stop Rx\n"); + iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); + break; + default: + IWL_DEBUG_HT("unknown\n"); + return -EINVAL; + break; + } + return 0; } +#ifdef CONFIG_IWL4965_HT_AGG + static const u16 default_tid_to_tx_fifo[] = { IWL_TX_FIFO_AC1, IWL_TX_FIFO_AC0, @@ -4526,7 +4767,13 @@ static const u16 default_tid_to_tx_fifo[] = { IWL_TX_FIFO_AC3 }; -static int iwl_txq_ctx_activate_free(struct iwl_priv *priv) +/* + * Find first available (lowest unused) Tx Queue, mark it "active". + * Called only when finding queue for aggregation. + * Should never return anything < 7, because they should already + * be in use as EDCA AC (0-3), Command (4), HCCA (5, 6). + */ +static int iwl4965_txq_ctx_activate_free(struct iwl4965_priv *priv) { int txq_id; @@ -4536,55 +4783,65 @@ static int iwl_txq_ctx_activate_free(struct iwl_priv *priv) return -1; } -int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, +int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, u16 *start_seq_num) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; int sta_id; int tx_fifo; int txq_id; int ssn = -1; unsigned long flags; - struct iwl_tid_data *tid_data; + struct iwl4965_tid_data *tid_data; DECLARE_MAC_BUF(mac); + /* Determine Tx DMA/FIFO channel for this Traffic ID */ if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s" + IWL_WARNING("iwl-AGG iwl4965_mac_ht_tx_agg_start on da=%s" " tid=%d\n", print_mac(mac, da), tid); - sta_id = iwl_hw_find_station(priv, da); + /* Get index into station table */ + sta_id = iwl4965_hw_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) return -ENXIO; - txq_id = iwl_txq_ctx_activate_free(priv); + /* Find available Tx queue for aggregation */ + txq_id = iwl4965_txq_ctx_activate_free(priv); if (txq_id == -1) return -ENXIO; spin_lock_irqsave(&priv->sta_lock, flags); tid_data = &priv->stations[sta_id].tid[tid]; + + /* Get starting sequence number for 1st frame in block ack window. + * We'll use least signif byte as 1st frame's index into Tx queue. */ ssn = SEQ_TO_SN(tid_data->seq_number); tid_data->agg.txq_id = txq_id; spin_unlock_irqrestore(&priv->sta_lock, flags); *start_seq_num = ssn; + + /* Update driver's link quality manager */ iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE); + + /* Set up and enable aggregation for selected Tx queue and FIFO */ return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo, sta_id, tid, ssn); } -int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, +int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, int generator) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; int tx_fifo_id, txq_id, sta_id, ssn = -1; - struct iwl_tid_data *tid_data; + struct iwl4965_tid_data *tid_data; int rc; DECLARE_MAC_BUF(mac); @@ -4598,7 +4855,7 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, else return -EINVAL; - sta_id = iwl_hw_find_station(priv, da); + sta_id = iwl4965_hw_find_station(priv, da); if (sta_id == IWL_INVALID_STATION) return -ENXIO; @@ -4613,45 +4870,18 @@ int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, return rc; iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA); - IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n", + IWL_DEBUG_INFO("iwl4965_mac_ht_tx_agg_stop on da=%s tid=%d\n", print_mac(mac, da), tid); return 0; } -int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, - u16 tid, u16 start_seq_num) -{ - struct iwl_priv *priv = hw->priv; - int sta_id; - DECLARE_MAC_BUF(mac); - IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s" - " tid=%d\n", print_mac(mac, da), tid); - sta_id = iwl_hw_find_station(priv, da); - iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num); - return 0; -} - -int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, - u16 tid, int generator) -{ - struct iwl_priv *priv = hw->priv; - int sta_id; - DECLARE_MAC_BUF(mac); - - IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n", - print_mac(mac, da), tid); - sta_id = iwl_hw_find_station(priv, da); - iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid); - return 0; -} - -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ /* Set up 4965-specific Rx frame reply handlers */ -void iwl_hw_rx_handler_setup(struct iwl_priv *priv) +void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv) { /* Legacy Rx frames */ priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx; @@ -4663,57 +4893,66 @@ void iwl_hw_rx_handler_setup(struct iwl_priv *priv) priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl4965_rx_missed_beacon_notif; -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba; -#endif /* CONFIG_IWLWIFI_AGG */ -#endif /* CONFIG_IWLWIFI */ +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ } -void iwl_hw_setup_deferred_work(struct iwl_priv *priv) +void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv) { INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work); INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work); -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work); #endif -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work); -#endif /* CONFIG_IWLWIFI_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ init_timer(&priv->statistics_periodic); priv->statistics_periodic.data = (unsigned long)priv; priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; } -void iwl_hw_cancel_deferred_work(struct iwl_priv *priv) +void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv) { del_timer_sync(&priv->statistics_periodic); cancel_delayed_work(&priv->init_alive_start); } -struct pci_device_id iwl_hw_card_ids[] = { - {0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, +struct pci_device_id iwl4965_hw_card_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4229)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x4230)}, {0} }; -int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) +/* + * The device's EEPROM semaphore prevents conflicts between driver and uCode + * when accessing the EEPROM; each access is a series of pulses to/from the + * EEPROM chip, not a single event, so even reads could conflict if they + * weren't arbitrated by the semaphore. + */ +int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv) { u16 count; int rc; for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + /* Request semaphore */ + iwl4965_set_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); - rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + + /* See if we got it */ + rc = iwl4965_poll_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); if (rc >= 0) { - IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n", + IWL_DEBUG_IO("Acquired semaphore after %d tries.\n", count+1); return rc; } @@ -4722,11 +4961,11 @@ int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv) return rc; } -inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv) +inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv) { - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl4965_clear_bit(priv, CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); } -MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); +MODULE_DEVICE_TABLE(pci, iwl4965_hw_card_ids); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 4c700812b45b..78bc148c9f7f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -23,64 +23,777 @@ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ +/* + * Please use this file (iwl-4965.h) for driver implementation definitions. + * Please use iwl-4965-commands.h for uCode API definitions. + * Please use iwl-4965-hw.h for hardware-related definitions. + */ + #ifndef __iwl_4965_h__ #define __iwl_4965_h__ -struct iwl_priv; -struct sta_ht_info; +#include <linux/pci.h> /* for struct pci_device_id */ +#include <linux/kernel.h> +#include <net/ieee80211_radiotap.h> + +/* Hardware specific file defines the PCI IDs table for that hardware module */ +extern struct pci_device_id iwl4965_hw_card_ids[]; + +#define DRV_NAME "iwl4965" +#include "iwl-4965-hw.h" +#include "iwl-prph.h" +#include "iwl-4965-debug.h" + +/* Default noise level to report when noise measurement is not available. + * This may be because we're: + * 1) Not associated (4965, no beacon statistics being sent to driver) + * 2) Scanning (noise measurement does not apply to associated channel) + * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) + * Use default noise value of -127 ... this is below the range of measurable + * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. + * Also, -127 works better than 0 when averaging frames with/without + * noise info (e.g. averaging might be done in app); measured dBm values are + * always negative ... using a negative value as the default keeps all + * averages within an s8's (used in some apps) range of negative values. */ +#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) + +/* Module parameters accessible from iwl-*.c */ +extern int iwl4965_param_hwcrypto; +extern int iwl4965_param_queues_num; +extern int iwl4965_param_amsdu_size_8K; + +enum iwl4965_antenna { + IWL_ANTENNA_DIVERSITY, + IWL_ANTENNA_MAIN, + IWL_ANTENNA_AUX +}; + +/* + * RTS threshold here is total size [2347] minus 4 FCS bytes + * Per spec: + * a value of 0 means RTS on all data/management packets + * a value > max MSDU size means no RTS + * else RTS for data/management frames where MPDU is larger + * than RTS value. + */ +#define DEFAULT_RTS_THRESHOLD 2347U +#define MIN_RTS_THRESHOLD 0U +#define MAX_RTS_THRESHOLD 2347U +#define MAX_MSDU_SIZE 2304U +#define MAX_MPDU_SIZE 2346U +#define DEFAULT_BEACON_INTERVAL 100U +#define DEFAULT_SHORT_RETRY_LIMIT 7U +#define DEFAULT_LONG_RETRY_LIMIT 4U + +struct iwl4965_rx_mem_buffer { + dma_addr_t dma_addr; + struct sk_buff *skb; + struct list_head list; +}; + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues + */ +struct iwl4965_queue { + int n_bd; /* number of BDs in this queue */ + int write_ptr; /* 1-st empty entry (index) host_w*/ + int read_ptr; /* last used entry (index) host_r*/ + dma_addr_t dma_addr; /* physical addr for BD's */ + int n_window; /* safe queue window */ + u32 id; + int low_mark; /* low watermark, resume queue if free + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +} __attribute__ ((packed)); + +#define MAX_NUM_OF_TBS (20) + +/* One for each TFD */ +struct iwl4965_tx_info { + struct ieee80211_tx_status status; + struct sk_buff *skb[MAX_NUM_OF_TBS]; +}; + +/** + * struct iwl4965_tx_queue - Tx Queue for DMA + * @q: generic Rx/Tx queue descriptor + * @bd: base of circular buffer of TFDs + * @cmd: array of command/Tx buffers + * @dma_addr_cmd: physical address of cmd/tx buffer array + * @txb: array of per-TFD driver data + * @need_update: indicates need to update read/write index + * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled + * + * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame + * descriptors) and required locking structures. + */ +struct iwl4965_tx_queue { + struct iwl4965_queue q; + struct iwl4965_tfd_frame *bd; + struct iwl4965_cmd *cmd; + dma_addr_t dma_addr_cmd; + struct iwl4965_tx_info *txb; + int need_update; + int sched_retry; + int active; +}; + +#define IWL_NUM_SCAN_RATES (2) + +struct iwl4965_channel_tgd_info { + u8 type; + s8 max_power; +}; + +struct iwl4965_channel_tgh_info { + s64 last_radar_time; +}; + +/* current Tx power values to use, one for each rate for each channel. + * requested power is limited by: + * -- regulatory EEPROM limits for this channel + * -- hardware capabilities (clip-powers) + * -- spectrum management + * -- user preference (e.g. iwconfig) + * when requested power is set, base power index must also be set. */ +struct iwl4965_channel_power_info { + struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 base_power_index; /* gain index for power at factory temp. */ + s8 requested_power; /* power (dBm) requested for this chnl/rate */ +}; + +/* current scan Tx power values to use, one for each scan rate for each + * channel. */ +struct iwl4965_scan_power_info { + struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */ + s8 power_table_index; /* actual (compenst'd) index into gain table */ + s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ +}; + +/* For fat_extension_channel */ +enum { + HT_IE_EXT_CHANNEL_NONE = 0, + HT_IE_EXT_CHANNEL_ABOVE, + HT_IE_EXT_CHANNEL_INVALID, + HT_IE_EXT_CHANNEL_BELOW, + HT_IE_EXT_CHANNEL_MAX +}; + +/* + * One for each channel, holds all channel setup data + * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant + * with one another! + */ +#define IWL4965_MAX_RATE (33) + +struct iwl4965_channel_info { + struct iwl4965_channel_tgd_info tgd; + struct iwl4965_channel_tgh_info tgh; + struct iwl4965_eeprom_channel eeprom; /* EEPROM regulatory limit */ + struct iwl4965_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for + * FAT channel */ + + u8 channel; /* channel number */ + u8 flags; /* flags copied from EEPROM */ + s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) limit */ + s8 min_power; /* always 0 */ + s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ + + u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ + u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ + u8 phymode; /* MODE_IEEE80211{A,B,G} */ + + /* Radio/DSP gain settings for each "normal" data Tx rate. + * These include, in addition to RF and DSP gain, a few fields for + * remembering/modifying gain settings (indexes). */ + struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE]; + + /* FAT channel info */ + s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ + s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ + s8 fat_min_power; /* always 0 */ + s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ + u8 fat_flags; /* flags copied from EEPROM */ + u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ + + /* Radio/DSP gain settings for each scan rate, for directed scans. */ + struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; +}; + +struct iwl4965_clip_group { + /* maximum power level to prevent clipping for each rate, derived by + * us from this band's saturation power in EEPROM */ + const s8 clip_powers[IWL_MAX_RATES]; +}; + +#include "iwl-4965-rs.h" + +#define IWL_TX_FIFO_AC0 0 +#define IWL_TX_FIFO_AC1 1 +#define IWL_TX_FIFO_AC2 2 +#define IWL_TX_FIFO_AC3 3 +#define IWL_TX_FIFO_HCCA_1 5 +#define IWL_TX_FIFO_HCCA_2 6 +#define IWL_TX_FIFO_NONE 7 + +/* Minimum number of queues. MAX_NUM is defined in hw specific files */ +#define IWL_MIN_NUM_QUEUES 4 + +/* Power management (not Tx power) structures */ + +struct iwl4965_power_vec_entry { + struct iwl4965_powertable_cmd cmd; + u8 no_dtim; +}; +#define IWL_POWER_RANGE_0 (0) +#define IWL_POWER_RANGE_1 (1) + +#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_LIMIT 0x07 +#define IWL_POWER_MASK 0x0F +#define IWL_POWER_ENABLED 0x10 +#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) + +struct iwl4965_power_mgr { + spinlock_t lock; + struct iwl4965_power_vec_entry pwr_range_0[IWL_POWER_AC]; + struct iwl4965_power_vec_entry pwr_range_1[IWL_POWER_AC]; + u8 active_index; + u32 dtim_val; +}; + +#define IEEE80211_DATA_LEN 2304 +#define IEEE80211_4ADDR_LEN 30 +#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) +#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) + +struct iwl4965_frame { + union { + struct ieee80211_hdr frame; + struct iwl4965_tx_beacon_cmd beacon; + u8 raw[IEEE80211_FRAME_LEN]; + u8 cmd[360]; + } u; + struct list_head list; +}; + +#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) +#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) +#define SEQ_TO_INDEX(x) (x & 0xff) +#define INDEX_TO_SEQ(x) (x & 0xff) +#define SEQ_HUGE_FRAME (0x4000) +#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +enum { + /* CMD_SIZE_NORMAL = 0, */ + CMD_SIZE_HUGE = (1 << 0), + /* CMD_SYNC = 0, */ + CMD_ASYNC = (1 << 1), + /* CMD_NO_SKB = 0, */ + CMD_WANT_SKB = (1 << 2), +}; + +struct iwl4965_cmd; +struct iwl4965_priv; + +struct iwl4965_cmd_meta { + struct iwl4965_cmd_meta *source; + union { + struct sk_buff *skb; + int (*callback)(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct sk_buff *skb); + } __attribute__ ((packed)) u; + + /* The CMD_SIZE_HUGE flag bit indicates that the command + * structure is stored at the end of the shared queue memory. */ + u32 flags; + +} __attribute__ ((packed)); + +/** + * struct iwl4965_cmd + * + * For allocation of the command and tx queues, this establishes the overall + * size of the largest command we send to uCode, except for a scan command + * (which is relatively huge; space is allocated separately). + */ +struct iwl4965_cmd { + struct iwl4965_cmd_meta meta; /* driver data */ + struct iwl4965_cmd_header hdr; /* uCode API */ + union { + struct iwl4965_addsta_cmd addsta; + struct iwl4965_led_cmd led; + u32 flags; + u8 val8; + u16 val16; + u32 val32; + struct iwl4965_bt_cmd bt; + struct iwl4965_rxon_time_cmd rxon_time; + struct iwl4965_powertable_cmd powertable; + struct iwl4965_qosparam_cmd qosparam; + struct iwl4965_tx_cmd tx; + struct iwl4965_tx_beacon_cmd tx_beacon; + struct iwl4965_rxon_assoc_cmd rxon_assoc; + u8 *indirect; + u8 payload[360]; + } __attribute__ ((packed)) cmd; +} __attribute__ ((packed)); + +struct iwl4965_host_cmd { + u8 id; + u16 len; + struct iwl4965_cmd_meta meta; + const void *data; +}; + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl4965_cmd) - \ + sizeof(struct iwl4965_cmd_meta)) + +/* + * RX related structures and functions + */ +#define RX_FREE_BUFFERS 64 +#define RX_LOW_WATERMARK 8 + +#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 +#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 +#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 + +/** + * struct iwl4965_rx_queue - Rx queue + * @processed: Internal index to last handled Rx packet + * @read: Shared index to newest available Rx buffer + * @write: Shared index to oldest written Rx packet + * @free_count: Number of pre-allocated buffers in rx_free + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB + * @need_update: flag to indicate we need to update read/write index + * + * NOTE: rx_free and rx_used are used as a FIFO for iwl4965_rx_mem_buffers + */ +struct iwl4965_rx_queue { + __le32 *bd; + dma_addr_t dma_addr; + struct iwl4965_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl4965_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 processed; + u32 read; + u32 write; + u32 free_count; + struct list_head rx_free; + struct list_head rx_used; + int need_update; + spinlock_t lock; +}; + +#define IWL_SUPPORTED_RATES_IE_LEN 8 + +#define SCAN_INTERVAL 100 + +#define MAX_A_CHANNELS 252 +#define MIN_A_CHANNELS 7 + +#define MAX_B_CHANNELS 14 +#define MIN_B_CHANNELS 1 + +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +#define STATUS_INT_ENABLED 1 +#define STATUS_RF_KILL_HW 2 +#define STATUS_RF_KILL_SW 3 +#define STATUS_INIT 4 +#define STATUS_ALIVE 5 +#define STATUS_READY 6 +#define STATUS_TEMPERATURE 7 +#define STATUS_GEO_CONFIGURED 8 +#define STATUS_EXIT_PENDING 9 +#define STATUS_IN_SUSPEND 10 +#define STATUS_STATISTICS 11 +#define STATUS_SCANNING 12 +#define STATUS_SCAN_ABORTING 13 +#define STATUS_SCAN_HW 14 +#define STATUS_POWER_PMI 15 +#define STATUS_FW_ERROR 16 +#define STATUS_CONF_PENDING 17 + +#define MAX_TID_COUNT 9 + +#define IWL_INVALID_RATE 0xFF +#define IWL_INVALID_VALUE -1 + +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG +/** + * struct iwl4965_ht_agg -- aggregation status while waiting for block-ack + * @txq_id: Tx queue used for Tx attempt + * @frame_count: # frames attempted by Tx command + * @wait_for_ba: Expect block-ack before next Tx reply + * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window + * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window + * @bitmap1: High order, one bit for each frame pending ACK in Tx window + * @rate_n_flags: Rate at which Tx was attempted + * + * If REPLY_TX indicates that aggregation was attempted, driver must wait + * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info + * until block ack arrives. + */ +struct iwl4965_ht_agg { + u16 txq_id; + u16 frame_count; + u16 wait_for_ba; + u16 start_idx; + u32 bitmap0; + u32 bitmap1; + u32 rate_n_flags; +}; +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ + +struct iwl4965_tid_data { + u16 seq_number; +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG + struct iwl4965_ht_agg agg; +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ +}; + +struct iwl4965_hw_key { + enum ieee80211_key_alg alg; + int keylen; + u8 key[32]; +}; + +union iwl4965_ht_rate_supp { + u16 rates; + struct { + u8 siso_rate; + u8 mimo_rate; + }; +}; + +#ifdef CONFIG_IWL4965_HT +#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) +#define CFG_HT_MPDU_DENSITY_2USEC (0x5) +#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC + +struct iwl_ht_info { + /* self configuration data */ + u8 is_ht; + u8 supported_chan_width; + u16 tx_mimo_ps_mode; + u8 is_green_field; + u8 sgf; /* HT_SHORT_GI_* short guard interval */ + u8 max_amsdu_size; + u8 ampdu_factor; + u8 mpdu_density; + u8 supp_mcs_set[16]; + /* BSS related data */ + u8 control_channel; + u8 extension_chan_offset; + u8 tx_chan_width; + u8 ht_protection; + u8 non_GF_STA_present; +}; +#endif /*CONFIG_IWL4965_HT */ + +#ifdef CONFIG_IWL4965_QOS + +union iwl4965_qos_capabity { + struct { + u8 edca_count:4; /* bit 0-3 */ + u8 q_ack:1; /* bit 4 */ + u8 queue_request:1; /* bit 5 */ + u8 txop_request:1; /* bit 6 */ + u8 reserved:1; /* bit 7 */ + } q_AP; + struct { + u8 acvo_APSD:1; /* bit 0 */ + u8 acvi_APSD:1; /* bit 1 */ + u8 ac_bk_APSD:1; /* bit 2 */ + u8 ac_be_APSD:1; /* bit 3 */ + u8 q_ack:1; /* bit 4 */ + u8 max_len:2; /* bit 5-6 */ + u8 more_data_ack:1; /* bit 7 */ + } q_STA; + u8 val; +}; + +/* QoS structures */ +struct iwl4965_qos_info { + int qos_enable; + int qos_active; + union iwl4965_qos_capabity qos_cap; + struct iwl4965_qosparam_cmd def_qos_parm; +}; +#endif /*CONFIG_IWL4965_QOS */ + +#define STA_PS_STATUS_WAKE 0 +#define STA_PS_STATUS_SLEEP 1 + +struct iwl4965_station_entry { + struct iwl4965_addsta_cmd sta; + struct iwl4965_tid_data tid[MAX_TID_COUNT]; + u8 used; + u8 ps_status; + struct iwl4965_hw_key keyinfo; +}; + +/* one for each uCode image (inst/data, boot/init/runtime) */ +struct fw_desc { + void *v_addr; /* access by driver */ + dma_addr_t p_addr; /* access by card's busmaster DMA */ + u32 len; /* bytes */ +}; + +/* uCode file layout */ +struct iwl4965_ucode { + __le32 ver; /* major/minor/subminor */ + __le32 inst_size; /* bytes of runtime instructions */ + __le32 data_size; /* bytes of runtime data */ + __le32 init_size; /* bytes of initialization instructions */ + __le32 init_data_size; /* bytes of initialization data */ + __le32 boot_size; /* bytes of bootstrap instructions */ + u8 data[0]; /* data in same order as "size" elements */ +}; + +#define IWL_IBSS_MAC_HASH_SIZE 32 + +struct iwl4965_ibss_seq { + u8 mac[ETH_ALEN]; + u16 seq_num; + u16 frag_num; + unsigned long packet_time; + struct list_head list; +}; + +/** + * struct iwl4965_driver_hw_info + * @max_txq_num: Max # Tx queues supported + * @ac_queue_count: # Tx queues for EDCA Access Categories (AC) + * @tx_cmd_len: Size of Tx command (but not including frame itself) + * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) + * @rx_buffer_size: + * @max_rxq_log: Log-base-2 of max_rxq_size + * @max_stations: + * @bcast_sta_id: + * @shared_virt: Pointer to driver/uCode shared Tx Byte Counts and Rx status + * @shared_phys: Physical Pointer to Tx Byte Counts and Rx status + */ +struct iwl4965_driver_hw_info { + u16 max_txq_num; + u16 ac_queue_count; + u16 tx_cmd_len; + u16 max_rxq_size; + u32 rx_buf_size; + u32 max_pkt_size; + u16 max_rxq_log; + u8 max_stations; + u8 bcast_sta_id; + void *shared_virt; + dma_addr_t shared_phys; +}; + +#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) +#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) + + +#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ + x->u.rx_frame.stats.payload + \ + x->u.rx_frame.stats.phy_count)) +#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\ + IWL_RX_HDR(x)->payload + \ + le16_to_cpu(IWL_RX_HDR(x)->len))) +#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) +#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) + + +/****************************************************************************** + * + * Functions implemented in iwl-base.c which are forward declared here + * for use by iwl-*.c + * + *****************************************************************************/ +struct iwl4965_addsta_cmd; +extern int iwl4965_send_add_station(struct iwl4965_priv *priv, + struct iwl4965_addsta_cmd *sta, u8 flags); +extern u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, + int is_ap, u8 flags, void *ht_data); +extern int iwl4965_is_network_packet(struct iwl4965_priv *priv, + struct ieee80211_hdr *header); +extern int iwl4965_power_init_handle(struct iwl4965_priv *priv); +extern int iwl4965_eeprom_init(struct iwl4965_priv *priv); +#ifdef CONFIG_IWL4965_DEBUG +extern void iwl4965_report_frame(struct iwl4965_priv *priv, + struct iwl4965_rx_packet *pkt, + struct ieee80211_hdr *header, int group100); +#else +static inline void iwl4965_report_frame(struct iwl4965_priv *priv, + struct iwl4965_rx_packet *pkt, + struct ieee80211_hdr *header, + int group100) {} +#endif +extern void iwl4965_handle_data_packet_monitor(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb, + void *data, short len, + struct ieee80211_rx_status *stats, + u16 phy_flags); +extern int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv, + struct ieee80211_hdr *header); +extern int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv); +extern void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, + struct iwl4965_rx_queue *rxq); +extern int iwl4965_calc_db_from_ratio(int sig_ratio); +extern int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm); +extern int iwl4965_tx_queue_init(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq, int count, u32 id); +extern void iwl4965_rx_replenish(void *data); +extern void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq); +extern int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len, + const void *data); +extern int __must_check iwl4965_send_cmd(struct iwl4965_priv *priv, + struct iwl4965_host_cmd *cmd); +extern unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv, + struct ieee80211_hdr *hdr, + const u8 *dest, int left); +extern int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, + struct iwl4965_rx_queue *q); +extern int iwl4965_send_statistics_request(struct iwl4965_priv *priv); +extern void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb, + u32 decrypt_res, + struct ieee80211_rx_status *stats); +extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); + +extern const u8 iwl4965_broadcast_addr[ETH_ALEN]; + +/* + * Currently used by iwl-3945-rs... look at restructuring so that it doesn't + * call this... todo... fix that. +*/ +extern u8 iwl4965_sync_station(struct iwl4965_priv *priv, int sta_id, + u16 tx_rate, u8 flags); + +/****************************************************************************** + * + * Functions implemented in iwl-[34]*.c which are forward declared here + * for use by iwl-base.c + * + * NOTE: The implementation of these functions are hardware specific + * which is why they are in the hardware specific files (vs. iwl-base.c) + * + * Naming convention -- + * iwl4965_ <-- Its part of iwlwifi (should be changed to iwl4965_) + * iwl4965_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) + * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) + * iwl4965_bg_ <-- Called from work queue context + * iwl4965_mac_ <-- mac80211 callback + * + ****************************************************************************/ +extern void iwl4965_hw_rx_handler_setup(struct iwl4965_priv *priv); +extern void iwl4965_hw_setup_deferred_work(struct iwl4965_priv *priv); +extern void iwl4965_hw_cancel_deferred_work(struct iwl4965_priv *priv); +extern int iwl4965_hw_rxq_stop(struct iwl4965_priv *priv); +extern int iwl4965_hw_set_hw_setting(struct iwl4965_priv *priv); +extern int iwl4965_hw_nic_init(struct iwl4965_priv *priv); +extern int iwl4965_hw_nic_stop_master(struct iwl4965_priv *priv); +extern void iwl4965_hw_txq_ctx_free(struct iwl4965_priv *priv); +extern void iwl4965_hw_txq_ctx_stop(struct iwl4965_priv *priv); +extern int iwl4965_hw_nic_reset(struct iwl4965_priv *priv); +extern int iwl4965_hw_txq_attach_buf_to_tfd(struct iwl4965_priv *priv, void *tfd, + dma_addr_t addr, u16 len); +extern int iwl4965_hw_txq_free_tfd(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq); +extern int iwl4965_hw_get_temperature(struct iwl4965_priv *priv); +extern int iwl4965_hw_tx_queue_init(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq); +extern unsigned int iwl4965_hw_get_beacon_cmd(struct iwl4965_priv *priv, + struct iwl4965_frame *frame, u8 rate); +extern int iwl4965_hw_get_rx_read(struct iwl4965_priv *priv); +extern void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, + struct ieee80211_tx_control *ctrl, + struct ieee80211_hdr *hdr, + int sta_id, int tx_id); +extern int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv); +extern int iwl4965_hw_reg_set_txpower(struct iwl4965_priv *priv, s8 power); +extern void iwl4965_hw_rx_statistics(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb); +extern void iwl4965_disable_events(struct iwl4965_priv *priv); +extern int iwl4965_get_temperature(const struct iwl4965_priv *priv); + +/** + * iwl4965_hw_find_station - Find station id for a given BSSID + * @bssid: MAC address of station ID to find + * + * NOTE: This should not be hardware specific but the code has + * not yet been merged into a single common layer for managing the + * station tables. + */ +extern u8 iwl4965_hw_find_station(struct iwl4965_priv *priv, const u8 *bssid); + +extern int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel); +extern int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index); + +struct iwl4965_priv; /* * Forward declare iwl-4965.c functions for iwl-base.c */ -extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv); -extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv); +extern int iwl4965_eeprom_acquire_semaphore(struct iwl4965_priv *priv); +extern void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv); -extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq, +extern int iwl4965_tx_queue_update_wr_ptr(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq, u16 byte_cnt); -extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, +extern void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap); -extern void iwl4965_set_rxon_ht(struct iwl_priv *priv, - struct sta_ht_info *ht_info); - -extern void iwl4965_set_rxon_chain(struct iwl_priv *priv); -extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd, - u8 sta_id, dma_addr_t txcmd_phys, - struct ieee80211_hdr *hdr, u8 hdr_len, - struct ieee80211_tx_control *ctrl, void *sta_in); -extern int iwl4965_init_hw_rates(struct iwl_priv *priv, - struct ieee80211_rate *rates); -extern int iwl4965_alive_notify(struct iwl_priv *priv); -extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode); -extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index); - -extern void iwl4965_chain_noise_reset(struct iwl_priv *priv); -extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, +extern void iwl4965_set_rxon_chain(struct iwl4965_priv *priv); +extern int iwl4965_alive_notify(struct iwl4965_priv *priv); +extern void iwl4965_update_rate_scaling(struct iwl4965_priv *priv, u8 mode); +extern void iwl4965_chain_noise_reset(struct iwl4965_priv *priv); +extern void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force); -extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, +extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel, - const struct iwl_eeprom_channel *eeprom_ch, + const struct iwl4965_eeprom_channel *eeprom_ch, u8 fat_extension_channel); -extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv); +extern void iwl4965_rf_kill_ct_config(struct iwl4965_priv *priv); -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG -extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, +#ifdef CONFIG_IWL4965_HT +extern void iwl4965_init_ht_hw_capab(struct ieee80211_ht_info *ht_info, + int mode); +extern void iwl4965_set_rxon_ht(struct iwl4965_priv *priv, + struct iwl_ht_info *ht_info); +extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index, + struct ieee80211_ht_info *sta_ht_inf); +extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, + enum ieee80211_ampdu_mlme_action action, + const u8 *addr, u16 tid, u16 ssn); +#ifdef CONFIG_IWL4965_HT_AGG +extern int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, u16 *start_seq_num); -extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da, - u16 tid, u16 start_seq_num); -extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da, +extern int iwl4965_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid, int generator); -extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, - u16 tid, int generator); -extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid); -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /*CONFIG_IWLWIFI_HT */ +extern void iwl4965_turn_off_agg(struct iwl4965_priv *priv, u8 tid); +extern void iwl4965_tl_get_stats(struct iwl4965_priv *priv, + struct ieee80211_hdr *hdr); +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /*CONFIG_IWL4965_HT */ /* Structures, enum, and defines specific to the 4965 */ #define IWL4965_KW_SIZE 0x1000 /*4k */ -struct iwl_kw { +struct iwl4965_kw { dma_addr_t dma_addr; void *v_addr; size_t size; @@ -120,21 +833,9 @@ struct iwl_kw { #define NRG_NUM_PREV_STAT_L 20 #define NUM_RX_CHAINS (3) -#define TX_POWER_IWL_ILLEGAL_VDET -100000 #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 -#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18 -#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34 -#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17 -#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20 -#define TX_POWER_IWL_NOMINAL_POWER 26 -#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1 -#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V 7 -#define TX_POWER_IWL_DEGREES_PER_VDET_CODE 11 -#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1 -#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9) -#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5) - -struct iwl_traffic_load { + +struct iwl4965_traffic_load { unsigned long time_stamp; u32 packet_count[TID_QUEUE_MAX_SIZE]; u8 queue_count; @@ -142,8 +843,13 @@ struct iwl_traffic_load { u32 total; }; -#ifdef CONFIG_IWLWIFI_HT_AGG -struct iwl_agg_control { +#ifdef CONFIG_IWL4965_HT_AGG +/** + * struct iwl4965_agg_control + * @requested_ba: bit map of tids requesting aggregation/block-ack + * @granted_ba: bit map of tids granted aggregation/block-ack + */ +struct iwl4965_agg_control { unsigned long next_retry; u32 wait_for_agg_status; u32 tid_retry; @@ -152,13 +858,13 @@ struct iwl_agg_control { u8 auto_agg; u32 tid_traffic_load_threshold; u32 ba_timeout; - struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT]; + struct iwl4965_traffic_load traffic_load[TID_MAX_LOAD_COUNT]; }; -#endif /*CONFIG_IWLWIFI_HT_AGG */ +#endif /*CONFIG_IWL4965_HT_AGG */ -struct iwl_lq_mngr { -#ifdef CONFIG_IWLWIFI_HT_AGG - struct iwl_agg_control agg_ctrl; +struct iwl4965_lq_mngr { +#ifdef CONFIG_IWL4965_HT_AGG + struct iwl4965_agg_control agg_ctrl; #endif spinlock_t lock; s32 max_window_size; @@ -179,22 +885,6 @@ struct iwl_lq_mngr { #define CAL_NUM_OF_BEACONS 20 #define MAXIMUM_ALLOWED_PATHLOSS 15 -/* Param table within SENSITIVITY_CMD */ -#define HD_MIN_ENERGY_CCK_DET_INDEX (0) -#define HD_MIN_ENERGY_OFDM_DET_INDEX (1) -#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX (2) -#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX (3) -#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX (4) -#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX (5) -#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX (6) -#define HD_BARKER_CORR_TH_ADD_MIN_INDEX (7) -#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX (8) -#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX (9) -#define HD_OFDM_ENERGY_TH_IN_INDEX (10) - -#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) -#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) - #define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3 #define MAX_FA_OFDM 50 @@ -222,8 +912,6 @@ struct iwl_lq_mngr { #define AUTO_CORR_STEP_CCK 3 #define AUTO_CORR_MAX_TH_CCK 160 -#define NRG_ALG 0 -#define AUTO_CORR_ALG 1 #define NRG_DIFF 2 #define NRG_STEP_CCK 2 #define NRG_MARGIN 8 @@ -239,24 +927,24 @@ struct iwl_lq_mngr { #define IN_BAND_FILTER 0xFF #define MIN_AVERAGE_NOISE_MAX_VALUE 0xFFFFFFFF -enum iwl_false_alarm_state { +enum iwl4965_false_alarm_state { IWL_FA_TOO_MANY = 0, IWL_FA_TOO_FEW = 1, IWL_FA_GOOD_RANGE = 2, }; -enum iwl_chain_noise_state { +enum iwl4965_chain_noise_state { IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */ IWL_CHAIN_NOISE_ACCUMULATE = 1, IWL_CHAIN_NOISE_CALIBRATED = 2, }; -enum iwl_sensitivity_state { +enum iwl4965_sensitivity_state { IWL_SENS_CALIB_ALLOWED = 0, IWL_SENS_CALIB_NEED_REINIT = 1, }; -enum iwl_calib_enabled_state { +enum iwl4965_calib_enabled_state { IWL_CALIB_DISABLED = 0, /* must be 0 */ IWL_CALIB_ENABLED = 1, }; @@ -271,7 +959,7 @@ struct statistics_general_data { }; /* Sensitivity calib data */ -struct iwl_sensitivity_data { +struct iwl4965_sensitivity_data { u32 auto_corr_ofdm; u32 auto_corr_ofdm_mrc; u32 auto_corr_ofdm_x1; @@ -300,7 +988,7 @@ struct iwl_sensitivity_data { }; /* Chain noise (differential Rx gain) calib data */ -struct iwl_chain_noise_data { +struct iwl4965_chain_noise_data { u8 state; u16 beacon_count; u32 chain_noise_a; @@ -314,28 +1002,323 @@ struct iwl_chain_noise_data { u8 radio_write; }; -/* IWL4965 */ -#define RATE_MCS_CODE_MSK 0x7 -#define RATE_MCS_MIMO_POS 3 -#define RATE_MCS_MIMO_MSK 0x8 -#define RATE_MCS_HT_DUP_POS 5 -#define RATE_MCS_HT_DUP_MSK 0x20 -#define RATE_MCS_FLAGS_POS 8 -#define RATE_MCS_HT_POS 8 -#define RATE_MCS_HT_MSK 0x100 -#define RATE_MCS_CCK_POS 9 -#define RATE_MCS_CCK_MSK 0x200 -#define RATE_MCS_GF_POS 10 -#define RATE_MCS_GF_MSK 0x400 - -#define RATE_MCS_FAT_POS 11 -#define RATE_MCS_FAT_MSK 0x800 -#define RATE_MCS_DUP_POS 12 -#define RATE_MCS_DUP_MSK 0x1000 -#define RATE_MCS_SGI_POS 13 -#define RATE_MCS_SGI_MSK 0x2000 - -#define EEPROM_SEM_TIMEOUT 10 -#define EEPROM_SEM_RETRY_LIMIT 1000 - -#endif /* __iwl_4965_h__ */ +#define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ +#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 + +struct iwl4965_priv { + + /* ieee device used by generic ieee processing code */ + struct ieee80211_hw *hw; + struct ieee80211_channel *ieee_channels; + struct ieee80211_rate *ieee_rates; + + /* temporary frame storage list */ + struct list_head free_frames; + int frames_count; + + u8 phymode; + int alloc_rxb_skb; + bool add_radiotap; + + void (*rx_handlers[REPLY_MAX])(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb); + + const struct ieee80211_hw_mode *modes; + +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + /* spectrum measurement report caching */ + struct iwl4965_spectrum_notification measure_report; + u8 measurement_status; +#endif + /* ucode beacon time */ + u32 ucode_beacon_time; + + /* we allocate array of iwl4965_channel_info for NIC's valid channels. + * Access via channel # using indirect index array */ + struct iwl4965_channel_info *channel_info; /* channel info array */ + u8 channel_count; /* # of channels */ + + /* each calibration channel group in the EEPROM has a derived + * clip setting for each rate. */ + const struct iwl4965_clip_group clip_groups[5]; + + /* thermal calibration */ + s32 temperature; /* degrees Kelvin */ + s32 last_temperature; + + /* Scan related variables */ + unsigned long last_scan_jiffies; + unsigned long next_scan_jiffies; + unsigned long scan_start; + unsigned long scan_pass_start; + unsigned long scan_start_tsf; + int scan_bands; + int one_direct_scan; + u8 direct_ssid_len; + u8 direct_ssid[IW_ESSID_MAX_SIZE]; + struct iwl4965_scan_cmd *scan; + u8 only_active_channel; + + /* spinlock */ + spinlock_t lock; /* protect general shared data */ + spinlock_t hcmd_lock; /* protect hcmd */ + struct mutex mutex; + + /* basic pci-network driver stuff */ + struct pci_dev *pci_dev; + + /* pci hardware address support */ + void __iomem *hw_base; + + /* uCode images, save to reload in case of failure */ + struct fw_desc ucode_code; /* runtime inst */ + struct fw_desc ucode_data; /* runtime data original */ + struct fw_desc ucode_data_backup; /* runtime data save/restore */ + struct fw_desc ucode_init; /* initialization inst */ + struct fw_desc ucode_init_data; /* initialization data */ + struct fw_desc ucode_boot; /* bootstrap inst */ + + + struct iwl4965_rxon_time_cmd rxon_timing; + + /* We declare this const so it can only be + * changed via explicit cast within the + * routines that actually update the physical + * hardware */ + const struct iwl4965_rxon_cmd active_rxon; + struct iwl4965_rxon_cmd staging_rxon; + + int error_recovering; + struct iwl4965_rxon_cmd recovery_rxon; + + /* 1st responses from initialize and runtime uCode images. + * 4965's initialize alive response contains some calibration data. */ + struct iwl4965_init_alive_resp card_alive_init; + struct iwl4965_alive_resp card_alive; + +#ifdef LED + /* LED related variables */ + struct iwl4965_activity_blink activity; + unsigned long led_packets; + int led_state; +#endif + + u16 active_rate; + u16 active_rate_basic; + + u8 call_post_assoc_from_beacon; + u8 assoc_station_added; + u8 use_ant_b_for_management_frame; /* Tx antenna selection */ + u8 valid_antenna; /* Bit mask of antennas actually connected */ +#ifdef CONFIG_IWL4965_SENSITIVITY + struct iwl4965_sensitivity_data sensitivity_data; + struct iwl4965_chain_noise_data chain_noise_data; + u8 start_calib; + __le16 sensitivity_tbl[HD_TABLE_SIZE]; +#endif /*CONFIG_IWL4965_SENSITIVITY*/ + +#ifdef CONFIG_IWL4965_HT + struct iwl_ht_info current_ht_config; +#endif + u8 last_phy_res[100]; + + /* Rate scaling data */ + struct iwl4965_lq_mngr lq_mngr; + + /* Rate scaling data */ + s8 data_retry_limit; + u8 retry_rate; + + wait_queue_head_t wait_command_queue; + + int activity_timer_active; + + /* Rx and Tx DMA processing queues */ + struct iwl4965_rx_queue rxq; + struct iwl4965_tx_queue txq[IWL_MAX_NUM_QUEUES]; + unsigned long txq_ctx_active_msk; + struct iwl4965_kw kw; /* keep warm address */ + u32 scd_base_addr; /* scheduler sram base address */ + + unsigned long status; + u32 config; + + int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_noise; /* From beacon statistics */ + + struct iwl4965_power_mgr power_data; + + struct iwl4965_notif_statistics statistics; + unsigned long last_statistics_time; + + /* context information */ + u8 essid[IW_ESSID_MAX_SIZE]; + u8 essid_len; + u16 rates_mask; + + u32 power_mode; + u32 antenna; + u8 bssid[ETH_ALEN]; + u16 rts_threshold; + u8 mac_addr[ETH_ALEN]; + + /*station table variables */ + spinlock_t sta_lock; + int num_stations; + struct iwl4965_station_entry stations[IWL_STATION_COUNT]; + + /* Indication if ieee80211_ops->open has been called */ + int is_open; + + u8 mac80211_registered; + int is_abg; + + u32 notif_missed_beacons; + + /* Rx'd packet timing information */ + u32 last_beacon_time; + u64 last_tsf; + + /* Duplicate packet detection */ + u16 last_seq_num; + u16 last_frag_num; + unsigned long last_packet_time; + + /* Hash table for finding stations in IBSS network */ + struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; + + /* eeprom */ + struct iwl4965_eeprom eeprom; + + int iw_mode; + + struct sk_buff *ibss_beacon; + + /* Last Rx'd beacon timestamp */ + u32 timestamp0; + u32 timestamp1; + u16 beacon_int; + struct iwl4965_driver_hw_info hw_setting; + struct ieee80211_vif *vif; + + /* Current association information needed to configure the + * hardware */ + u16 assoc_id; + u16 assoc_capability; + u8 ps_mode; + +#ifdef CONFIG_IWL4965_QOS + struct iwl4965_qos_info qos_data; +#endif /*CONFIG_IWL4965_QOS */ + + struct workqueue_struct *workqueue; + + struct work_struct up; + struct work_struct restart; + struct work_struct calibrated_work; + struct work_struct scan_completed; + struct work_struct rx_replenish; + struct work_struct rf_kill; + struct work_struct abort_scan; + struct work_struct update_link_led; + struct work_struct auth_work; + struct work_struct report_work; + struct work_struct request_scan; + struct work_struct beacon_update; + + struct tasklet_struct irq_tasklet; + + struct delayed_work init_alive_start; + struct delayed_work alive_start; + struct delayed_work activity_timer; + struct delayed_work thermal_periodic; + struct delayed_work gather_stats; + struct delayed_work scan_check; + struct delayed_work post_associate; + +#define IWL_DEFAULT_TX_POWER 0x0F + s8 user_txpower_limit; + s8 max_channel_txpower_limit; + +#ifdef CONFIG_PM + u32 pm_state[16]; +#endif + +#ifdef CONFIG_IWL4965_DEBUG + /* debugging info */ + u32 framecnt_to_us; + atomic_t restrict_refcnt; +#endif + + struct work_struct txpower_work; +#ifdef CONFIG_IWL4965_SENSITIVITY + struct work_struct sensitivity_work; +#endif + struct work_struct statistics_work; + struct timer_list statistics_periodic; + +#ifdef CONFIG_IWL4965_HT_AGG + struct work_struct agg_work; +#endif +}; /*iwl4965_priv */ + +static inline int iwl4965_is_associated(struct iwl4965_priv *priv) +{ + return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; +} + +static inline int is_channel_valid(const struct iwl4965_channel_info *ch_info) +{ + if (ch_info == NULL) + return 0; + return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; +} + +static inline int is_channel_narrow(const struct iwl4965_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; +} + +static inline int is_channel_radar(const struct iwl4965_channel_info *ch_info) +{ + return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; +} + +static inline u8 is_channel_a_band(const struct iwl4965_channel_info *ch_info) +{ + return ch_info->phymode == MODE_IEEE80211A; +} + +static inline u8 is_channel_bg_band(const struct iwl4965_channel_info *ch_info) +{ + return ((ch_info->phymode == MODE_IEEE80211B) || + (ch_info->phymode == MODE_IEEE80211G)); +} + +static inline int is_channel_passive(const struct iwl4965_channel_info *ch) +{ + return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; +} + +static inline int is_channel_ibss(const struct iwl4965_channel_info *ch) +{ + return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; +} + +extern const struct iwl4965_channel_info *iwl4965_get_channel_info( + const struct iwl4965_priv *priv, int phymode, u16 channel); + +/* Requires full declaration of iwl4965_priv before including */ +#include "iwl-4965-io.h" + +#endif /* __iwl4965_4965_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h deleted file mode 100644 index 023c3f240cea..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-channel.h +++ /dev/null @@ -1,161 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2005 - 2007 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 <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -#ifndef __iwl_channel_h__ -#define __iwl_channel_h__ - -#define IWL_NUM_SCAN_RATES (2) - -struct iwl_channel_tgd_info { - u8 type; - s8 max_power; -}; - -struct iwl_channel_tgh_info { - s64 last_radar_time; -}; - -/* current Tx power values to use, one for each rate for each channel. - * requested power is limited by: - * -- regulatory EEPROM limits for this channel - * -- hardware capabilities (clip-powers) - * -- spectrum management - * -- user preference (e.g. iwconfig) - * when requested power is set, base power index must also be set. */ -struct iwl_channel_power_info { - struct iwl_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 base_power_index; /* gain index for power at factory temp. */ - s8 requested_power; /* power (dBm) requested for this chnl/rate */ -}; - -/* current scan Tx power values to use, one for each scan rate for each - * channel. */ -struct iwl_scan_power_info { - struct iwl_tx_power tpc; /* actual radio and DSP gain settings */ - s8 power_table_index; /* actual (compenst'd) index into gain table */ - s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */ -}; - -/* Channel unlock period is 15 seconds. If no beacon or probe response - * has been received within 15 seconds on a locked channel then the channel - * remains locked. */ -#define TX_UNLOCK_PERIOD 15 - -/* CSA lock period is 15 seconds. If a CSA has been received on a channel in - * the last 15 seconds, the channel is locked */ -#define CSA_LOCK_PERIOD 15 -/* - * One for each channel, holds all channel setup data - * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant - * with one another! - */ -#define IWL4965_MAX_RATE (33) - -struct iwl_channel_info { - struct iwl_channel_tgd_info tgd; - struct iwl_channel_tgh_info tgh; - struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */ - struct iwl_eeprom_channel fat_eeprom; /* EEPROM regulatory limit for - * FAT channel */ - - u8 channel; /* channel number */ - u8 flags; /* flags copied from EEPROM */ - s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 min_power; /* always 0 */ - s8 scan_power; /* (dBm) regul. eeprom, direct scans, any rate */ - - u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ - u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ - u8 phymode; /* MODE_IEEE80211{A,B,G} */ - - /* Radio/DSP gain settings for each "normal" data Tx rate. - * These include, in addition to RF and DSP gain, a few fields for - * remembering/modifying gain settings (indexes). */ - struct iwl_channel_power_info power_info[IWL4965_MAX_RATE]; - -#if IWL == 4965 - /* FAT channel info */ - s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ - s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ - s8 fat_min_power; /* always 0 */ - s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ - u8 fat_flags; /* flags copied from EEPROM */ - u8 fat_extension_channel; -#endif - - /* Radio/DSP gain settings for each scan rate, for directed scans. */ - struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES]; -}; - -struct iwl_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - -static inline int is_channel_valid(const struct iwl_channel_info *ch_info) -{ - if (ch_info == NULL) - return 0; - return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0; -} - -static inline int is_channel_narrow(const struct iwl_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0; -} - -static inline int is_channel_radar(const struct iwl_channel_info *ch_info) -{ - return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0; -} - -static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info) -{ - return ch_info->phymode == MODE_IEEE80211A; -} - -static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info) -{ - return ((ch_info->phymode == MODE_IEEE80211B) || - (ch_info->phymode == MODE_IEEE80211G)); -} - -static inline int is_channel_passive(const struct iwl_channel_info *ch) -{ - return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0; -} - -static inline int is_channel_ibss(const struct iwl_channel_info *ch) -{ - return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; -} - -extern const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, int phymode, u16 channel); - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h deleted file mode 100644 index e473c97e3f4f..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ /dev/null @@ -1,336 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2005 - 2007 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 Geeral 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.GPL. - * - * Contact Information: - * James P. Ketrenos <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ - -#ifndef __iwl_eeprom_h__ -#define __iwl_eeprom_h__ - -/* - * This file defines EEPROM related constants, enums, and inline functions. - * - */ - -#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ -#define IWL_EEPROM_ACCESS_DELAY 10 /* uSec */ -/* EEPROM field values */ -#define ANTENNA_SWITCH_NORMAL 0 -#define ANTENNA_SWITCH_INVERSE 1 - -enum { - EEPROM_CHANNEL_VALID = (1 << 0), /* usable for this SKU/geo */ - EEPROM_CHANNEL_IBSS = (1 << 1), /* usable as an IBSS channel */ - /* Bit 2 Reserved */ - EEPROM_CHANNEL_ACTIVE = (1 << 3), /* active scanning allowed */ - EEPROM_CHANNEL_RADAR = (1 << 4), /* radar detection required */ - EEPROM_CHANNEL_WIDE = (1 << 5), - EEPROM_CHANNEL_NARROW = (1 << 6), - EEPROM_CHANNEL_DFS = (1 << 7), /* dynamic freq selection candidate */ -}; - -/* EEPROM field lengths */ -#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11 - -/* EEPROM field lengths */ -#define EEPROM_BOARD_PBA_NUMBER_LENGTH 11 -#define EEPROM_REGULATORY_SKU_ID_LENGTH 4 -#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH 14 -#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH 13 -#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH 12 -#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH 11 -#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH 6 - -#if IWL == 3945 -#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \ - EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH) -#elif IWL == 4965 -#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7 -#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11 -#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \ - EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \ - EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH) -#endif - -#define EEPROM_REGULATORY_NUMBER_OF_BANDS 5 - -/* SKU Capabilities */ -#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0) -#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1) -#define EEPROM_SKU_CAP_OP_MODE_MRC (1 << 7) - -/* *regulatory* channel data from eeprom, one for each channel */ -struct iwl_eeprom_channel { - u8 flags; /* flags copied from EEPROM */ - s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */ -} __attribute__ ((packed)); - -/* - * Mapping of a Tx power level, at factory calibration temperature, - * to a radio/DSP gain table index. - * One for each of 5 "sample" power levels in each band. - * v_det is measured at the factory, using the 3945's built-in power amplifier - * (PA) output voltage detector. This same detector is used during Tx of - * long packets in normal operation to provide feedback as to proper output - * level. - * Data copied from EEPROM. - */ -struct iwl_eeprom_txpower_sample { - u8 gain_index; /* index into power (gain) setup table ... */ - s8 power; /* ... for this pwr level for this chnl group */ - u16 v_det; /* PA output voltage */ -} __attribute__ ((packed)); - -/* - * Mappings of Tx power levels -> nominal radio/DSP gain table indexes. - * One for each channel group (a.k.a. "band") (1 for BG, 4 for A). - * Tx power setup code interpolates between the 5 "sample" power levels - * to determine the nominal setup for a requested power level. - * Data copied from EEPROM. - * DO NOT ALTER THIS STRUCTURE!!! - */ -struct iwl_eeprom_txpower_group { - struct iwl_eeprom_txpower_sample samples[5]; /* 5 power levels */ - s32 a, b, c, d, e; /* coefficients for voltage->power - * formula (signed) */ - s32 Fa, Fb, Fc, Fd, Fe; /* these modify coeffs based on - * frequency (signed) */ - s8 saturation_power; /* highest power possible by h/w in this - * band */ - u8 group_channel; /* "representative" channel # in this band */ - s16 temperature; /* h/w temperature at factory calib this band - * (signed) */ -} __attribute__ ((packed)); - -/* - * Temperature-based Tx-power compensation data, not band-specific. - * These coefficients are use to modify a/b/c/d/e coeffs based on - * difference between current temperature and factory calib temperature. - * Data copied from EEPROM. - */ -struct iwl_eeprom_temperature_corr { - u32 Ta; - u32 Tb; - u32 Tc; - u32 Td; - u32 Te; -} __attribute__ ((packed)); - -#if IWL == 4965 -#define EEPROM_TX_POWER_TX_CHAINS (2) -#define EEPROM_TX_POWER_BANDS (8) -#define EEPROM_TX_POWER_MEASUREMENTS (3) -#define EEPROM_TX_POWER_VERSION (2) -#define EEPROM_TX_POWER_VERSION_NEW (5) - -struct iwl_eeprom_calib_measure { - u8 temperature; - u8 gain_idx; - u8 actual_pow; - s8 pa_det; -} __attribute__ ((packed)); - -struct iwl_eeprom_calib_ch_info { - u8 ch_num; - struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS] - [EEPROM_TX_POWER_MEASUREMENTS]; -} __attribute__ ((packed)); - -struct iwl_eeprom_calib_subband_info { - u8 ch_from; - u8 ch_to; - struct iwl_eeprom_calib_ch_info ch1; - struct iwl_eeprom_calib_ch_info ch2; -} __attribute__ ((packed)); - -struct iwl_eeprom_calib_info { - u8 saturation_power24; - u8 saturation_power52; - s16 voltage; /* signed */ - struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS]; -} __attribute__ ((packed)); - -#endif - -struct iwl_eeprom { - u8 reserved0[16]; -#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ - u16 device_id; /* abs.ofs: 16 */ - u8 reserved1[2]; -#define EEPROM_PMC (2*0x0A) /* 2 bytes */ - u16 pmc; /* abs.ofs: 20 */ - u8 reserved2[20]; -#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ - u8 mac_address[6]; /* abs.ofs: 42 */ - u8 reserved3[58]; -#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ - u16 board_revision; /* abs.ofs: 106 */ - u8 reserved4[11]; -#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ - u8 board_pba_number[9]; /* abs.ofs: 119 */ - u8 reserved5[8]; -#define EEPROM_VERSION (2*0x44) /* 2 bytes */ - u16 version; /* abs.ofs: 136 */ -#define EEPROM_SKU_CAP (2*0x45) /* 1 bytes */ - u8 sku_cap; /* abs.ofs: 138 */ -#define EEPROM_LEDS_MODE (2*0x45+1) /* 1 bytes */ - u8 leds_mode; /* abs.ofs: 139 */ -#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ - u16 oem_mode; -#define EEPROM_WOWLAN_MODE (2*0x47) /* 2 bytes */ - u16 wowlan_mode; /* abs.ofs: 142 */ -#define EEPROM_LEDS_TIME_INTERVAL (2*0x48) /* 2 bytes */ - u16 leds_time_interval; /* abs.ofs: 144 */ -#define EEPROM_LEDS_OFF_TIME (2*0x49) /* 1 bytes */ - u8 leds_off_time; /* abs.ofs: 146 */ -#define EEPROM_LEDS_ON_TIME (2*0x49+1) /* 1 bytes */ - u8 leds_on_time; /* abs.ofs: 147 */ -#define EEPROM_ALMGOR_M_VERSION (2*0x4A) /* 1 bytes */ - u8 almgor_m_version; /* abs.ofs: 148 */ -#define EEPROM_ANTENNA_SWITCH_TYPE (2*0x4A+1) /* 1 bytes */ - u8 antenna_switch_type; /* abs.ofs: 149 */ -#if IWL == 3945 - u8 reserved6[42]; -#else - u8 reserved6[8]; -#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */ - u16 board_revision_4965; /* abs.ofs: 158 */ - u8 reserved7[13]; -#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */ - u8 board_pba_number_4965[9]; /* abs.ofs: 173 */ - u8 reserved8[10]; -#endif -#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */ - u8 sku_id[4]; /* abs.ofs: 192 */ -#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */ - u16 band_1_count; /* abs.ofs: 196 */ -#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */ - struct iwl_eeprom_channel band_1_channels[14]; /* abs.ofs: 196 */ -#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */ - u16 band_2_count; /* abs.ofs: 226 */ -#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */ - struct iwl_eeprom_channel band_2_channels[13]; /* abs.ofs: 228 */ -#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */ - u16 band_3_count; /* abs.ofs: 254 */ -#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */ - struct iwl_eeprom_channel band_3_channels[12]; /* abs.ofs: 256 */ -#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */ - u16 band_4_count; /* abs.ofs: 280 */ -#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */ - struct iwl_eeprom_channel band_4_channels[11]; /* abs.ofs: 282 */ -#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */ - u16 band_5_count; /* abs.ofs: 304 */ -#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */ - struct iwl_eeprom_channel band_5_channels[6]; /* abs.ofs: 306 */ - -/* From here on out the EEPROM diverges between the 4965 and the 3945 */ -#if IWL == 3945 - - u8 reserved9[194]; - -#define EEPROM_TXPOWER_CALIB_GROUP0 0x200 -#define EEPROM_TXPOWER_CALIB_GROUP1 0x240 -#define EEPROM_TXPOWER_CALIB_GROUP2 0x280 -#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0 -#define EEPROM_TXPOWER_CALIB_GROUP4 0x300 -#define IWL_NUM_TX_CALIB_GROUPS 5 - struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS]; -/* abs.ofs: 512 */ -#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340 - struct iwl_eeprom_temperature_corr corrections; /* abs.ofs: 832 */ - u8 reserved16[172]; /* fill out to full 1024 byte block */ - -/* 4965AGN adds fat channel support */ -#elif IWL == 4965 - - u8 reserved10[2]; -#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0) /* 14 bytes */ - struct iwl_eeprom_channel band_24_channels[7]; /* abs.ofs: 320 */ - u8 reserved11[2]; -#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8) /* 22 bytes */ - struct iwl_eeprom_channel band_52_channels[11]; /* abs.ofs: 336 */ - u8 reserved12[6]; -#define EEPROM_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */ - u16 calib_version; /* abs.ofs: 364 */ - u8 reserved13[2]; -#define EEPROM_SATURATION_POWER_OFFSET (2*0xB8) /* 2 bytes */ - u16 satruation_power; /* abs.ofs: 368 */ - u8 reserved14[94]; -#define EEPROM_IWL_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */ - struct iwl_eeprom_calib_info calib_info; /* abs.ofs: 464 */ - - u8 reserved16[140]; /* fill out to full 1024 byte block */ - -#endif - -} __attribute__ ((packed)); - -#define IWL_EEPROM_IMAGE_SIZE 1024 - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index e2a8d95ad9cd..cd2eb1848310 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -252,4 +252,27 @@ static inline unsigned long elapsed_jiffies(unsigned long start, return end + (MAX_JIFFY_OFFSET - start); } +static inline u8 iwl_get_dma_hi_address(dma_addr_t addr) +{ + return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; +} + +/* TODO: Move fw_desc functions to iwl-pci.ko */ +static inline void iwl_free_fw_desc(struct pci_dev *pci_dev, + struct fw_desc *desc) +{ + if (desc->v_addr) + pci_free_consistent(pci_dev, desc->len, + desc->v_addr, desc->p_addr); + desc->v_addr = NULL; + desc->len = 0; +} + +static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev, + struct fw_desc *desc) +{ + desc->v_addr = pci_alloc_consistent(pci_dev, desc->len, &desc->p_addr); + return (desc->v_addr != NULL) ? 0 : -ENOMEM; +} + #endif /* __iwl_helpers_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h deleted file mode 100644 index 1aa6fcd39a5e..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-hw.h +++ /dev/null @@ -1,537 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2005 - 2007 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 Geeral 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.GPL. - * - * Contact Information: - * James P. Ketrenos <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -#ifndef __iwlwifi_hw_h__ -#define __iwlwifi_hw_h__ - -/* - * This file defines hardware constants common to 3945 and 4965. - * - * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h, - * although this file contains a few definitions for which the .c - * implementation is the same for 3945 and 4965, except for the value of - * a constant. - * - * uCode API constants are defined in iwl-commands.h. - * - * NOTE: DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE - * - * The iwl-*hw.h (and files they include) files should remain OS/driver - * implementation independent, declaring only the hardware interface. - */ - -/* uCode queue management definitions */ -#define IWL_CMD_QUEUE_NUM 4 -#define IWL_CMD_FIFO_NUM 4 -#define IWL_BACK_QUEUE_FIRST_ID 7 - -/* Tx rates */ -#define IWL_CCK_RATES 4 -#define IWL_OFDM_RATES 8 - -#if IWL == 3945 -#define IWL_HT_RATES 0 -#elif IWL == 4965 -#define IWL_HT_RATES 16 -#endif - -#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) - -/* Time constants */ -#define SHORT_SLOT_TIME 9 -#define LONG_SLOT_TIME 20 - -/* RSSI to dBm */ -#if IWL == 3945 -#define IWL_RSSI_OFFSET 95 -#elif IWL == 4965 -#define IWL_RSSI_OFFSET 44 -#endif - -#include "iwl-eeprom.h" -#include "iwl-commands.h" - -#define PCI_LINK_CTRL 0x0F0 -#define PCI_POWER_SOURCE 0x0C8 -#define PCI_REG_WUM8 0x0E8 -#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) - -/*=== CSR (control and status registers) ===*/ -#define CSR_BASE (0x000) - -#define CSR_SW_VER (CSR_BASE+0x000) -#define CSR_HW_IF_CONFIG_REG (CSR_BASE+0x000) /* hardware interface config */ -#define CSR_INT_COALESCING (CSR_BASE+0x004) /* accum ints, 32-usec units */ -#define CSR_INT (CSR_BASE+0x008) /* host interrupt status/ack */ -#define CSR_INT_MASK (CSR_BASE+0x00c) /* host interrupt enable */ -#define CSR_FH_INT_STATUS (CSR_BASE+0x010) /* busmaster int status/ack*/ -#define CSR_GPIO_IN (CSR_BASE+0x018) /* read external chip pins */ -#define CSR_RESET (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/ -#define CSR_GP_CNTRL (CSR_BASE+0x024) -#define CSR_HW_REV (CSR_BASE+0x028) -#define CSR_EEPROM_REG (CSR_BASE+0x02c) -#define CSR_EEPROM_GP (CSR_BASE+0x030) -#define CSR_GP_UCODE (CSR_BASE+0x044) -#define CSR_UCODE_DRV_GP1 (CSR_BASE+0x054) -#define CSR_UCODE_DRV_GP1_SET (CSR_BASE+0x058) -#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) -#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) -#define CSR_LED_REG (CSR_BASE+0x094) -#define CSR_DRAM_INT_TBL_CTL (CSR_BASE+0x0A0) -#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) -#define CSR_ANA_PLL_CFG (CSR_BASE+0x20c) -#define CSR_HW_REV_WA_REG (CSR_BASE+0x22C) - -/* HW I/F configuration */ -#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB (0x00000100) -#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM (0x00000200) -#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400) -#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800) -#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000) -#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000) -#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000) - -/* interrupt flags in INTA, set by uCode or hardware (e.g. dma), - * acknowledged (reset) by host writing "1" to flagged bits. */ -#define CSR_INT_BIT_FH_RX (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */ -#define CSR_INT_BIT_HW_ERR (1<<29) /* DMA hardware error FH_INT[31] */ -#define CSR_INT_BIT_DNLD (1<<28) /* uCode Download */ -#define CSR_INT_BIT_FH_TX (1<<27) /* Tx DMA FH_INT[1:0] */ -#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */ -#define CSR_INT_BIT_SW_ERR (1<<25) /* uCode error */ -#define CSR_INT_BIT_RF_KILL (1<<7) /* HW RFKILL switch GP_CNTRL[27] toggled */ -#define CSR_INT_BIT_CT_KILL (1<<6) /* Critical temp (chip too hot) rfkill */ -#define CSR_INT_BIT_SW_RX (1<<3) /* Rx, command responses, 3945 */ -#define CSR_INT_BIT_WAKEUP (1<<1) /* NIC controller waking up (pwr mgmt) */ -#define CSR_INT_BIT_ALIVE (1<<0) /* uCode interrupts once it initializes */ - -#define CSR_INI_SET_MASK (CSR_INT_BIT_FH_RX | \ - CSR_INT_BIT_HW_ERR | \ - CSR_INT_BIT_FH_TX | \ - CSR_INT_BIT_SW_ERR | \ - CSR_INT_BIT_RF_KILL | \ - CSR_INT_BIT_SW_RX | \ - CSR_INT_BIT_WAKEUP | \ - CSR_INT_BIT_ALIVE) - -/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ -#define CSR_FH_INT_BIT_ERR (1<<31) /* Error */ -#define CSR_FH_INT_BIT_HI_PRIOR (1<<30) /* High priority Rx, bypass coalescing */ -#define CSR_FH_INT_BIT_RX_CHNL2 (1<<18) /* Rx channel 2 (3945 only) */ -#define CSR_FH_INT_BIT_RX_CHNL1 (1<<17) /* Rx channel 1 */ -#define CSR_FH_INT_BIT_RX_CHNL0 (1<<16) /* Rx channel 0 */ -#define CSR_FH_INT_BIT_TX_CHNL6 (1<<6) /* Tx channel 6 (3945 only) */ -#define CSR_FH_INT_BIT_TX_CHNL1 (1<<1) /* Tx channel 1 */ -#define CSR_FH_INT_BIT_TX_CHNL0 (1<<0) /* Tx channel 0 */ - -#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \ - CSR_FH_INT_BIT_RX_CHNL2 | \ - CSR_FH_INT_BIT_RX_CHNL1 | \ - CSR_FH_INT_BIT_RX_CHNL0) - -#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL6 | \ - CSR_FH_INT_BIT_TX_CHNL1 | \ - CSR_FH_INT_BIT_TX_CHNL0 ) - - -/* RESET */ -#define CSR_RESET_REG_FLAG_NEVO_RESET (0x00000001) -#define CSR_RESET_REG_FLAG_FORCE_NMI (0x00000002) -#define CSR_RESET_REG_FLAG_SW_RESET (0x00000080) -#define CSR_RESET_REG_FLAG_MASTER_DISABLED (0x00000100) -#define CSR_RESET_REG_FLAG_STOP_MASTER (0x00000200) - -/* GP (general purpose) CONTROL */ -#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY (0x00000001) -#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE (0x00000004) -#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ (0x00000008) -#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP (0x00000010) - -#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN (0x00000001) - -#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE (0x07000000) -#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE (0x04000000) -#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW (0x08000000) - - -/* EEPROM REG */ -#define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) -#define CSR_EEPROM_REG_BIT_CMD (0x00000002) - -/* EEPROM GP */ -#define CSR_EEPROM_GP_VALID_MSK (0x00000006) -#define CSR_EEPROM_GP_BAD_SIGNATURE (0x00000000) -#define CSR_EEPROM_GP_IF_OWNER_MSK (0x00000180) - -/* UCODE DRV GP */ -#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP (0x00000001) -#define CSR_UCODE_SW_BIT_RFKILL (0x00000002) -#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED (0x00000004) -#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT (0x00000008) - -/* GPIO */ -#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200) -#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC (0x00000000) -#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC CSR_GPIO_IN_BIT_AUX_POWER - -/* GI Chicken Bits */ -#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) -#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) - -/* CSR_ANA_PLL_CFG */ -#define CSR_ANA_PLL_CFG_SH (0x00880300) - -#define CSR_LED_REG_TRUN_ON (0x00000078) -#define CSR_LED_REG_TRUN_OFF (0x00000038) -#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF) - -/* DRAM_INT_TBL_CTRL */ -#define CSR_DRAM_INT_TBL_CTRL_EN (1<<31) -#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK (1<<27) - -/*=== HBUS (Host-side Bus) ===*/ -#define HBUS_BASE (0x400) - -#define HBUS_TARG_MEM_RADDR (HBUS_BASE+0x00c) -#define HBUS_TARG_MEM_WADDR (HBUS_BASE+0x010) -#define HBUS_TARG_MEM_WDAT (HBUS_BASE+0x018) -#define HBUS_TARG_MEM_RDAT (HBUS_BASE+0x01c) -#define HBUS_TARG_PRPH_WADDR (HBUS_BASE+0x044) -#define HBUS_TARG_PRPH_RADDR (HBUS_BASE+0x048) -#define HBUS_TARG_PRPH_WDAT (HBUS_BASE+0x04c) -#define HBUS_TARG_PRPH_RDAT (HBUS_BASE+0x050) -#define HBUS_TARG_WRPTR (HBUS_BASE+0x060) - -#define HBUS_TARG_MBX_C (HBUS_BASE+0x030) - - -/* SCD (Scheduler) */ -#define SCD_BASE (CSR_BASE + 0x2E00) - -#define SCD_MODE_REG (SCD_BASE + 0x000) -#define SCD_ARASTAT_REG (SCD_BASE + 0x004) -#define SCD_TXFACT_REG (SCD_BASE + 0x010) -#define SCD_TXF4MF_REG (SCD_BASE + 0x014) -#define SCD_TXF5MF_REG (SCD_BASE + 0x020) -#define SCD_SBYP_MODE_1_REG (SCD_BASE + 0x02C) -#define SCD_SBYP_MODE_2_REG (SCD_BASE + 0x030) - -/*=== FH (data Flow Handler) ===*/ -#define FH_BASE (0x800) - -#define FH_CBCC_TABLE (FH_BASE+0x140) -#define FH_TFDB_TABLE (FH_BASE+0x180) -#define FH_RCSR_TABLE (FH_BASE+0x400) -#define FH_RSSR_TABLE (FH_BASE+0x4c0) -#define FH_TCSR_TABLE (FH_BASE+0x500) -#define FH_TSSR_TABLE (FH_BASE+0x680) - -/* TFDB (Transmit Frame Buffer Descriptor) */ -#define FH_TFDB(_channel, buf) \ - (FH_TFDB_TABLE+((_channel)*2+(buf))*0x28) -#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \ - (FH_TFDB_TABLE + 0x50 * _channel) -/* CBCC _channel is [0,2] */ -#define FH_CBCC(_channel) (FH_CBCC_TABLE+(_channel)*0x8) -#define FH_CBCC_CTRL(_channel) (FH_CBCC(_channel)+0x00) -#define FH_CBCC_BASE(_channel) (FH_CBCC(_channel)+0x04) - -/* RCSR _channel is [0,2] */ -#define FH_RCSR(_channel) (FH_RCSR_TABLE+(_channel)*0x40) -#define FH_RCSR_CONFIG(_channel) (FH_RCSR(_channel)+0x00) -#define FH_RCSR_RBD_BASE(_channel) (FH_RCSR(_channel)+0x04) -#define FH_RCSR_WPTR(_channel) (FH_RCSR(_channel)+0x20) -#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24) - -#if IWL == 3945 -#define FH_RSCSR_CHNL0_WPTR (FH_RCSR_WPTR(0)) -#elif IWL == 4965 -#define FH_RSCSR_CHNL0_WPTR (FH_RSCSR_CHNL0_RBDCB_WPTR_REG) -#endif - -/* RSSR */ -#define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) -#define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) -/* TCSR */ -#define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) -#define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) -#define FH_TCSR_CREDIT(_channel) (FH_TCSR(_channel)+0x04) -#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08) -/* TSSR */ -#define FH_TSSR_CBB_BASE (FH_TSSR_TABLE+0x000) -#define FH_TSSR_MSG_CONFIG (FH_TSSR_TABLE+0x008) -#define FH_TSSR_TX_STATUS (FH_TSSR_TABLE+0x010) -/* 18 - reserved */ - -/* card static random access memory (SRAM) for processor data and instructs */ -#define RTC_INST_LOWER_BOUND (0x000000) -#define RTC_DATA_LOWER_BOUND (0x800000) - - -/* DBM */ - -#define ALM_FH_SRVC_CHNL (6) - -#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE (20) -#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH (4) - -#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN (0x08000000) - -#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE (0x80000000) - -#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE (0x20000000) - -#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 (0x01000000) - -#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST (0x00001000) - -#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH (0x00000000) - -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER (0x00000001) - -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) - -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) - -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) - -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) - -#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00004000) - -#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR (0x00000001) - -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON (0xFF000000) -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON (0x00FF0000) - -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B (0x00000400) - -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON (0x00000100) -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON (0x00000080) - -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH (0x00000020) -#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH (0x00000005) - -#define ALM_TB_MAX_BYTES_COUNT (0xFFF0) - -#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \ - ((1LU << _channel) << 24) -#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \ - ((1LU << _channel) << 16) - -#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \ - (ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \ - ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel)) -#define PCI_CFG_REV_ID_BIT_BASIC_SKU (0x40) /* bit 6 */ -#define PCI_CFG_REV_ID_BIT_RTP (0x80) /* bit 7 */ - -#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - -#define TFD_QUEUE_MIN 0 -#define TFD_QUEUE_MAX 6 -#define TFD_QUEUE_SIZE_MAX (256) - -/* spectrum and channel data structures */ -#define IWL_NUM_SCAN_RATES (2) - -#define IWL_SCAN_FLAG_24GHZ (1<<0) -#define IWL_SCAN_FLAG_52GHZ (1<<1) -#define IWL_SCAN_FLAG_ACTIVE (1<<2) -#define IWL_SCAN_FLAG_DIRECT (1<<3) - -#define IWL_MAX_CMD_SIZE 1024 - -#define IWL_DEFAULT_TX_RETRY 15 -#define IWL_MAX_TX_RETRY 16 - -/*********************************************/ - -#define RFD_SIZE 4 -#define NUM_TFD_CHUNKS 4 - -#define RX_QUEUE_SIZE 256 -#define RX_QUEUE_MASK 255 -#define RX_QUEUE_SIZE_LOG 8 - -/* QoS definitions */ - -#define CW_MIN_OFDM 15 -#define CW_MAX_OFDM 1023 -#define CW_MIN_CCK 31 -#define CW_MAX_CCK 1023 - -#define QOS_TX0_CW_MIN_OFDM CW_MIN_OFDM -#define QOS_TX1_CW_MIN_OFDM CW_MIN_OFDM -#define QOS_TX2_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 2 - 1) -#define QOS_TX3_CW_MIN_OFDM ((CW_MIN_OFDM + 1) / 4 - 1) - -#define QOS_TX0_CW_MIN_CCK CW_MIN_CCK -#define QOS_TX1_CW_MIN_CCK CW_MIN_CCK -#define QOS_TX2_CW_MIN_CCK ((CW_MIN_CCK + 1) / 2 - 1) -#define QOS_TX3_CW_MIN_CCK ((CW_MIN_CCK + 1) / 4 - 1) - -#define QOS_TX0_CW_MAX_OFDM CW_MAX_OFDM -#define QOS_TX1_CW_MAX_OFDM CW_MAX_OFDM -#define QOS_TX2_CW_MAX_OFDM CW_MIN_OFDM -#define QOS_TX3_CW_MAX_OFDM ((CW_MIN_OFDM + 1) / 2 - 1) - -#define QOS_TX0_CW_MAX_CCK CW_MAX_CCK -#define QOS_TX1_CW_MAX_CCK CW_MAX_CCK -#define QOS_TX2_CW_MAX_CCK CW_MIN_CCK -#define QOS_TX3_CW_MAX_CCK ((CW_MIN_CCK + 1) / 2 - 1) - -#define QOS_TX0_AIFS 3 -#define QOS_TX1_AIFS 7 -#define QOS_TX2_AIFS 2 -#define QOS_TX3_AIFS 2 - -#define QOS_TX0_ACM 0 -#define QOS_TX1_ACM 0 -#define QOS_TX2_ACM 0 -#define QOS_TX3_ACM 0 - -#define QOS_TX0_TXOP_LIMIT_CCK 0 -#define QOS_TX1_TXOP_LIMIT_CCK 0 -#define QOS_TX2_TXOP_LIMIT_CCK 6016 -#define QOS_TX3_TXOP_LIMIT_CCK 3264 - -#define QOS_TX0_TXOP_LIMIT_OFDM 0 -#define QOS_TX1_TXOP_LIMIT_OFDM 0 -#define QOS_TX2_TXOP_LIMIT_OFDM 3008 -#define QOS_TX3_TXOP_LIMIT_OFDM 1504 - -#define DEF_TX0_CW_MIN_OFDM CW_MIN_OFDM -#define DEF_TX1_CW_MIN_OFDM CW_MIN_OFDM -#define DEF_TX2_CW_MIN_OFDM CW_MIN_OFDM -#define DEF_TX3_CW_MIN_OFDM CW_MIN_OFDM - -#define DEF_TX0_CW_MIN_CCK CW_MIN_CCK -#define DEF_TX1_CW_MIN_CCK CW_MIN_CCK -#define DEF_TX2_CW_MIN_CCK CW_MIN_CCK -#define DEF_TX3_CW_MIN_CCK CW_MIN_CCK - -#define DEF_TX0_CW_MAX_OFDM CW_MAX_OFDM -#define DEF_TX1_CW_MAX_OFDM CW_MAX_OFDM -#define DEF_TX2_CW_MAX_OFDM CW_MAX_OFDM -#define DEF_TX3_CW_MAX_OFDM CW_MAX_OFDM - -#define DEF_TX0_CW_MAX_CCK CW_MAX_CCK -#define DEF_TX1_CW_MAX_CCK CW_MAX_CCK -#define DEF_TX2_CW_MAX_CCK CW_MAX_CCK -#define DEF_TX3_CW_MAX_CCK CW_MAX_CCK - -#define DEF_TX0_AIFS (2) -#define DEF_TX1_AIFS (2) -#define DEF_TX2_AIFS (2) -#define DEF_TX3_AIFS (2) - -#define DEF_TX0_ACM 0 -#define DEF_TX1_ACM 0 -#define DEF_TX2_ACM 0 -#define DEF_TX3_ACM 0 - -#define DEF_TX0_TXOP_LIMIT_CCK 0 -#define DEF_TX1_TXOP_LIMIT_CCK 0 -#define DEF_TX2_TXOP_LIMIT_CCK 0 -#define DEF_TX3_TXOP_LIMIT_CCK 0 - -#define DEF_TX0_TXOP_LIMIT_OFDM 0 -#define DEF_TX1_TXOP_LIMIT_OFDM 0 -#define DEF_TX2_TXOP_LIMIT_OFDM 0 -#define DEF_TX3_TXOP_LIMIT_OFDM 0 - -#define QOS_QOS_SETS 3 -#define QOS_PARAM_SET_ACTIVE 0 -#define QOS_PARAM_SET_DEF_CCK 1 -#define QOS_PARAM_SET_DEF_OFDM 2 - -#define CTRL_QOS_NO_ACK (0x0020) -#define DCT_FLAG_EXT_QOS_ENABLED (0x10) - -#define U32_PAD(n) ((4-(n))&0x3) - -/* - * Generic queue structure - * - * Contains common data for Rx and Tx queues - */ -#define TFD_CTL_COUNT_SET(n) (n<<24) -#define TFD_CTL_COUNT_GET(ctl) ((ctl>>24) & 7) -#define TFD_CTL_PAD_SET(n) (n<<28) -#define TFD_CTL_PAD_GET(ctl) (ctl>>28) - -#define TFD_TX_CMD_SLOTS 256 -#define TFD_CMD_SLOTS 32 - -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ - sizeof(struct iwl_cmd_meta)) - -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - -#endif /* __iwlwifi_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h deleted file mode 100644 index 8a8b96fcf48d..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ /dev/null @@ -1,470 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project. - * - * 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 <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_io_h__ -#define __iwl_io_h__ - -#include <linux/io.h> - -#include "iwl-debug.h" - -/* - * IO, register, and NIC memory access functions - * - * NOTE on naming convention and macro usage for these - * - * A single _ prefix before a an access function means that no state - * check or debug information is printed when that function is called. - * - * A double __ prefix before an access function means that state is checked - * (in the case of *restricted calls) and the current line number is printed - * in addition to any other debug output. - * - * The non-prefixed name is the #define that maps the caller into a - * #define that provides the caller's __LINE__ to the double prefix version. - * - * If you wish to call the function without any debug or state checking, - * you should use the single _ prefix version (as is used by dependent IO - * routines, for example _iwl_read_restricted calls the non-check version of - * _iwl_read32.) - * - * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with - * git-bisect and the IO debug level you can quickly determine the specific - * commit which breaks the IO sequence to the hardware. - * - */ - -#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl, - u32 ofs, u32 val) -{ - IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n", - (u32) (ofs), (u32) (val), f, l); - _iwl_write32(iwl, ofs, val); -} -#define iwl_write32(iwl, ofs, val) \ - __iwl_write32(__FILE__, __LINE__, iwl, ofs, val) -#else -#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val) -#endif - -#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs) -{ - IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l); - return _iwl_read32(iwl, ofs); -} -#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs) -#else -#define iwl_read32(p, o) _iwl_read32(p, o) -#endif - -static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int i = 0; - - do { - if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout); - if (unlikely(rc == -ETIMEDOUT)) - IWL_DEBUG_IO - ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n", - addr, bits, mask, f, l); - else - IWL_DEBUG_IO - ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n", - addr, bits, mask, rc, f, l); - return rc; -} -#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \ - __iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout) -#else -#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t) -#endif - -static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) | mask; - IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m) -#else -#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m) -#endif - -static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) -{ - _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_clear_bit(const char *f, u32 l, - struct iwl_priv *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read32(priv, reg) & ~mask; - IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val); - _iwl_write32(priv, reg, val); -} -#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m) -#else -#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m) -#endif - -static inline int _iwl_grab_restricted_access(struct iwl_priv *priv) -{ - int rc; - u32 gp_ctl; - -#ifdef CONFIG_IWLWIFI_DEBUG - if (atomic_read(&priv->restrict_refcnt)) - return 0; -#endif - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status)) { - IWL_WARNING("WARNING: Requesting MAC access during RFKILL " - "wakes up NIC\n"); - - /* 10 msec allows time for NIC to complete its data save */ - gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL); - if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) { - IWL_DEBUG_RF_KILL("Wait for complete power-down, " - "gpctl = 0x%08x\n", gp_ctl); - mdelay(10); - } else - IWL_DEBUG_RF_KILL("power-down complete, " - "gpctl = 0x%08x\n", gp_ctl); - } - - /* this bit wakes up the NIC */ - _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - rc = _iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, - (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | - CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50); - if (rc < 0) { - IWL_ERROR("MAC is in deep sleep!\n"); - return -EIO; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - atomic_inc(&priv->restrict_refcnt); -#endif - return 0; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_grab_restricted_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - if (atomic_read(&priv->restrict_refcnt)) - IWL_DEBUG_INFO("Grabbing access while already held at " - "line %d.\n", l); - - IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l); - - return _iwl_grab_restricted_access(priv); -} -#define iwl_grab_restricted_access(priv) \ - __iwl_grab_restricted_access(__FILE__, __LINE__, priv) -#else -#define iwl_grab_restricted_access(priv) \ - _iwl_grab_restricted_access(priv) -#endif - -static inline void _iwl_release_restricted_access(struct iwl_priv *priv) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - if (atomic_dec_and_test(&priv->restrict_refcnt)) -#endif - _iwl_clear_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_release_restricted_access(const char *f, u32 l, - struct iwl_priv *priv) -{ - if (atomic_read(&priv->restrict_refcnt) <= 0) - IWL_ERROR("Release unheld restricted access at line %d.\n", l); - - IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l); - _iwl_release_restricted_access(priv); -} -#define iwl_release_restricted_access(priv) \ - __iwl_release_restricted_access(__FILE__, __LINE__, priv) -#else -#define iwl_release_restricted_access(priv) \ - _iwl_release_restricted_access(priv) -#endif - -static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg) -{ - return _iwl_read32(priv, reg); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_restricted(const char *f, u32 l, - struct iwl_priv *priv, u32 reg) -{ - u32 value = _iwl_read_restricted(priv, reg); - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Unrestricted access from %s %d\n", f, l); - IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value, - f, l); - return value; -} -#define iwl_read_restricted(priv, reg) \ - __iwl_read_restricted(__FILE__, __LINE__, priv, reg) -#else -#define iwl_read_restricted _iwl_read_restricted -#endif - -static inline void _iwl_write_restricted(struct iwl_priv *priv, - u32 reg, u32 value) -{ - _iwl_write32(priv, reg, value); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static void __iwl_write_restricted(u32 line, - struct iwl_priv *priv, u32 reg, u32 value) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Unrestricted access from line %d\n", line); - _iwl_write_restricted(priv, reg, value); -} -#define iwl_write_restricted(priv, reg, value) \ - __iwl_write_restricted(__LINE__, priv, reg, value) -#else -#define iwl_write_restricted _iwl_write_restricted -#endif - -static inline void iwl_write_buffer_restricted(struct iwl_priv *priv, - u32 reg, u32 len, u32 *values) -{ - u32 count = sizeof(u32); - - if ((priv != NULL) && (values != NULL)) { - for (; 0 < len; len -= count, reg += count, values++) - _iwl_write_restricted(priv, reg, *values); - } -} - -static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int i = 0; - - do { - if ((_iwl_read_restricted(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static inline int __iwl_poll_restricted_bit(const char *f, u32 l, - struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) -{ - int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout); - - if (unlikely(rc == -ETIMEDOUT)) - IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - " - "timedout - %s %d\n", addr, mask, f, l); - else - IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X " - "- %s %d\n", addr, mask, rc, f, l); - return rc; -} -#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \ - __iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout) -#else -#define iwl_poll_restricted_bit _iwl_poll_restricted_bit -#endif - -static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg) -{ - _iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); - return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline u32 __iwl_read_restricted_reg(u32 line, - struct iwl_priv *priv, u32 reg) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Unrestricted access from line %d\n", line); - return _iwl_read_restricted_reg(priv, reg); -} - -#define iwl_read_restricted_reg(priv, reg) \ - __iwl_read_restricted_reg(__LINE__, priv, reg) -#else -#define iwl_read_restricted_reg _iwl_read_restricted_reg -#endif - -static inline void _iwl_write_restricted_reg(struct iwl_priv *priv, - u32 addr, u32 val) -{ - _iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR, - ((addr & 0x0000FFFF) | (3 << 24))); - _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val); -} -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_write_restricted_reg(u32 line, - struct iwl_priv *priv, - u32 addr, u32 val) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Unrestricted access from line %d\n", line); - _iwl_write_restricted_reg(priv, addr, val); -} - -#define iwl_write_restricted_reg(priv, addr, val) \ - __iwl_write_restricted_reg(__LINE__, priv, addr, val); -#else -#define iwl_write_restricted_reg _iwl_write_restricted_reg -#endif - -#define _iwl_set_bits_restricted_reg(priv, reg, mask) \ - _iwl_write_restricted_reg(priv, reg, \ - (_iwl_read_restricted_reg(priv, reg) | mask)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv - *priv, u32 reg, u32 mask) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Unrestricted access from line %d\n", line); - _iwl_set_bits_restricted_reg(priv, reg, mask); -} -#define iwl_set_bits_restricted_reg(priv, reg, mask) \ - __iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask) -#else -#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg -#endif - -#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \ - _iwl_write_restricted_reg( \ - priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits)) -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void __iwl_set_bits_mask_restricted_reg(u32 line, - struct iwl_priv *priv, u32 reg, u32 bits, u32 mask) -{ - if (!atomic_read(&priv->restrict_refcnt)) - IWL_ERROR("Unrestricted access from line %d\n", line); - _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask); -} - -#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \ - __iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask) -#else -#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg -#endif - -static inline void iwl_clear_bits_restricted_reg(struct iwl_priv - *priv, u32 reg, u32 mask) -{ - u32 val = _iwl_read_restricted_reg(priv, reg); - _iwl_write_restricted_reg(priv, reg, (val & ~mask)); -} - -static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr) -{ - iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr); - return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); -} - -static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr, - u32 val) -{ - iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr); - iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val); -} - -static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr, - u32 len, u32 *values) -{ - iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr); - for (; 0 < len; len -= sizeof(u32), values++) - iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values); -} - -static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg, - u32 len, u8 *values) -{ - u32 reg_offset = reg; - u32 aligment = reg & 0x3; - - /* write any non-dword-aligned stuff at the beginning */ - if (len < sizeof(u32)) { - if ((aligment + len) <= sizeof(u32)) { - u8 size; - u32 value = 0; - size = len - 1; - memcpy(&value, values, len); - reg_offset = (reg_offset & 0x0000FFFF); - - _iwl_write_restricted(priv, - HBUS_TARG_PRPH_WADDR, - (reg_offset | (size << 24))); - _iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, - value); - } - - return; - } - - /* now write all the dword-aligned stuff */ - for (; reg_offset < (reg + len); - reg_offset += sizeof(u32), values += sizeof(u32)) - _iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values)); -} - -#endif diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h deleted file mode 100644 index 6b490d08fea9..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-priv.h +++ /dev/null @@ -1,308 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2007 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 <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_priv_h__ -#define __iwl_priv_h__ - -#include <linux/workqueue.h> - -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT - -enum { - MEASUREMENT_READY = (1 << 0), - MEASUREMENT_ACTIVE = (1 << 1), -}; - -#endif - -struct iwl_priv { - - /* ieee device used by generic ieee processing code */ - struct ieee80211_hw *hw; - struct ieee80211_channel *ieee_channels; - struct ieee80211_rate *ieee_rates; - - /* temporary frame storage list */ - struct list_head free_frames; - int frames_count; - - u8 phymode; - int alloc_rxb_skb; - - void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); - - const struct ieee80211_hw_mode *modes; - -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT - /* spectrum measurement report caching */ - struct iwl_spectrum_notification measure_report; - u8 measurement_status; -#endif - /* ucode beacon time */ - u32 ucode_beacon_time; - - /* we allocate array of iwl_channel_info for NIC's valid channels. - * Access via channel # using indirect index array */ - struct iwl_channel_info *channel_info; /* channel info array */ - u8 channel_count; /* # of channels */ - - /* each calibration channel group in the EEPROM has a derived - * clip setting for each rate. */ - const struct iwl_clip_group clip_groups[5]; - - /* thermal calibration */ - s32 temperature; /* degrees Kelvin */ - s32 last_temperature; - - /* Scan related variables */ - unsigned long last_scan_jiffies; - unsigned long scan_start; - unsigned long scan_pass_start; - unsigned long scan_start_tsf; - int scan_bands; - int one_direct_scan; - u8 direct_ssid_len; - u8 direct_ssid[IW_ESSID_MAX_SIZE]; - struct iwl_scan_cmd *scan; - u8 only_active_channel; - - /* spinlock */ - spinlock_t lock; /* protect general shared data */ - spinlock_t hcmd_lock; /* protect hcmd */ - struct mutex mutex; - - /* basic pci-network driver stuff */ - struct pci_dev *pci_dev; - - /* pci hardware address support */ - void __iomem *hw_base; - - /* uCode images, save to reload in case of failure */ - struct fw_image_desc ucode_code; /* runtime inst */ - struct fw_image_desc ucode_data; /* runtime data original */ - struct fw_image_desc ucode_data_backup; /* runtime data save/restore */ - struct fw_image_desc ucode_init; /* initialization inst */ - struct fw_image_desc ucode_init_data; /* initialization data */ - struct fw_image_desc ucode_boot; /* bootstrap inst */ - - - struct iwl_rxon_time_cmd rxon_timing; - - /* We declare this const so it can only be - * changed via explicit cast within the - * routines that actually update the physical - * hardware */ - const struct iwl_rxon_cmd active_rxon; - struct iwl_rxon_cmd staging_rxon; - - int error_recovering; - struct iwl_rxon_cmd recovery_rxon; - - /* 1st responses from initialize and runtime uCode images. - * 4965's initialize alive response contains some calibration data. */ - struct iwl_init_alive_resp card_alive_init; - struct iwl_alive_resp card_alive; - -#ifdef LED - /* LED related variables */ - struct iwl_activity_blink activity; - unsigned long led_packets; - int led_state; -#endif - - u16 active_rate; - u16 active_rate_basic; - - u8 call_post_assoc_from_beacon; - u8 assoc_station_added; -#if IWL == 4965 - u8 use_ant_b_for_management_frame; /* Tx antenna selection */ - /* HT variables */ - u8 is_dup; - u8 is_ht_enabled; - u8 channel_width; /* 0=20MHZ, 1=40MHZ */ - u8 current_channel_width; - u8 valid_antenna; /* Bit mask of antennas actually connected */ -#ifdef CONFIG_IWLWIFI_SENSITIVITY - struct iwl_sensitivity_data sensitivity_data; - struct iwl_chain_noise_data chain_noise_data; - u8 start_calib; - __le16 sensitivity_tbl[HD_TABLE_SIZE]; -#endif /*CONFIG_IWLWIFI_SENSITIVITY*/ - -#ifdef CONFIG_IWLWIFI_HT - struct sta_ht_info current_assoc_ht; -#endif - u8 active_rate_ht[2]; - u8 last_phy_res[100]; - - /* Rate scaling data */ - struct iwl_lq_mngr lq_mngr; -#endif - - /* Rate scaling data */ - s8 data_retry_limit; - u8 retry_rate; - - wait_queue_head_t wait_command_queue; - - int activity_timer_active; - - /* Rx and Tx DMA processing queues */ - struct iwl_rx_queue rxq; - struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; -#if IWL == 4965 - unsigned long txq_ctx_active_msk; - struct iwl_kw kw; /* keep warm address */ - u32 scd_base_addr; /* scheduler sram base address */ -#endif - - unsigned long status; - u32 config; - - int last_rx_rssi; /* From Rx packet statisitics */ - int last_rx_noise; /* From beacon statistics */ - - struct iwl_power_mgr power_data; - - struct iwl_notif_statistics statistics; - unsigned long last_statistics_time; - - /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; - u16 rates_mask; - - u32 power_mode; - u32 antenna; - u8 bssid[ETH_ALEN]; - u16 rts_threshold; - u8 mac_addr[ETH_ALEN]; - - /*station table variables */ - spinlock_t sta_lock; - int num_stations; - struct iwl_station_entry stations[IWL_STATION_COUNT]; - - /* Indication if ieee80211_ops->open has been called */ - int is_open; - - u8 mac80211_registered; - int is_abg; - - u32 notif_missed_beacons; - - /* Rx'd packet timing information */ - u32 last_beacon_time; - u64 last_tsf; - - /* Duplicate packet detection */ - u16 last_seq_num; - u16 last_frag_num; - unsigned long last_packet_time; - struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE]; - - /* eeprom */ - struct iwl_eeprom eeprom; - - int iw_mode; - - struct sk_buff *ibss_beacon; - - /* Last Rx'd beacon timestamp */ - u32 timestamp0; - u32 timestamp1; - u16 beacon_int; - struct iwl_driver_hw_info hw_setting; - int interface_id; - - /* Current association information needed to configure the - * hardware */ - u16 assoc_id; - u16 assoc_capability; - u8 ps_mode; - -#ifdef CONFIG_IWLWIFI_QOS - struct iwl_qos_info qos_data; -#endif /*CONFIG_IWLWIFI_QOS */ - - struct workqueue_struct *workqueue; - - struct work_struct up; - struct work_struct restart; - struct work_struct calibrated_work; - struct work_struct scan_completed; - struct work_struct rx_replenish; - struct work_struct rf_kill; - struct work_struct abort_scan; - struct work_struct update_link_led; - struct work_struct auth_work; - struct work_struct report_work; - struct work_struct request_scan; - struct work_struct beacon_update; - - struct tasklet_struct irq_tasklet; - - struct delayed_work init_alive_start; - struct delayed_work alive_start; - struct delayed_work activity_timer; - struct delayed_work thermal_periodic; - struct delayed_work gather_stats; - struct delayed_work scan_check; - struct delayed_work post_associate; - -#define IWL_DEFAULT_TX_POWER 0x0F - s8 user_txpower_limit; - s8 max_channel_txpower_limit; - u32 cck_power_index_compensation; - -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif - -#ifdef CONFIG_IWLWIFI_DEBUG - /* debugging info */ - u32 framecnt_to_us; - atomic_t restrict_refcnt; -#endif - -#if IWL == 4965 - struct work_struct txpower_work; -#ifdef CONFIG_IWLWIFI_SENSITIVITY - struct work_struct sensitivity_work; -#endif - struct work_struct statistics_work; - struct timer_list statistics_periodic; - -#ifdef CONFIG_IWLWIFI_HT_AGG - struct work_struct agg_work; -#endif - -#endif /* 4965 */ -}; /*iwl_priv */ - -#endif /* __iwl_priv_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 0df41148eadc..4ba121634877 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -8,7 +8,7 @@ * Copyright(c) 2005 - 2007 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 Geeral Public License as + * 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 @@ -63,7 +63,10 @@ #ifndef __iwl_prph_h__ #define __iwl_prph_h__ - +/* + * Registers in this file are internal, not PCI bus memory mapped. + * Driver accesses these via HBUS_TARG_PRPH_* registers. + */ #define PRPH_BASE (0x00000) #define PRPH_END (0xFFFFF) @@ -226,4 +229,58 @@ #define BSM_SRAM_SIZE (1024) /* bytes */ +/* 3945 Tx scheduler registers */ +#define ALM_SCD_BASE (PRPH_BASE + 0x2E00) +#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000) +#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004) +#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010) +#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014) +#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020) +#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C) +#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030) + +/* + * 4965 Tx Scheduler registers. + * Details are documented in iwl-4965-hw.h + */ +#define KDR_SCD_BASE (PRPH_BASE + 0xa02c00) + +#define KDR_SCD_SRAM_BASE_ADDR (KDR_SCD_BASE + 0x0) +#define KDR_SCD_EMPTY_BITS (KDR_SCD_BASE + 0x4) +#define KDR_SCD_DRAM_BASE_ADDR (KDR_SCD_BASE + 0x10) +#define KDR_SCD_AIT (KDR_SCD_BASE + 0x18) +#define KDR_SCD_TXFACT (KDR_SCD_BASE + 0x1c) +#define KDR_SCD_QUEUE_WRPTR(x) (KDR_SCD_BASE + 0x24 + (x) * 4) +#define KDR_SCD_QUEUE_RDPTR(x) (KDR_SCD_BASE + 0x64 + (x) * 4) +#define KDR_SCD_SETQUEUENUM (KDR_SCD_BASE + 0xa4) +#define KDR_SCD_SET_TXSTAT_TXED (KDR_SCD_BASE + 0xa8) +#define KDR_SCD_SET_TXSTAT_DONE (KDR_SCD_BASE + 0xac) +#define KDR_SCD_SET_TXSTAT_NOT_SCHD (KDR_SCD_BASE + 0xb0) +#define KDR_SCD_DECREASE_CREDIT (KDR_SCD_BASE + 0xb4) +#define KDR_SCD_DECREASE_SCREDIT (KDR_SCD_BASE + 0xb8) +#define KDR_SCD_LOAD_CREDIT (KDR_SCD_BASE + 0xbc) +#define KDR_SCD_LOAD_SCREDIT (KDR_SCD_BASE + 0xc0) +#define KDR_SCD_BAR (KDR_SCD_BASE + 0xc4) +#define KDR_SCD_BAR_DW0 (KDR_SCD_BASE + 0xc8) +#define KDR_SCD_BAR_DW1 (KDR_SCD_BASE + 0xcc) +#define KDR_SCD_QUEUECHAIN_SEL (KDR_SCD_BASE + 0xd0) +#define KDR_SCD_QUERY_REQ (KDR_SCD_BASE + 0xd8) +#define KDR_SCD_QUERY_RES (KDR_SCD_BASE + 0xdc) +#define KDR_SCD_PENDING_FRAMES (KDR_SCD_BASE + 0xe0) +#define KDR_SCD_INTERRUPT_MASK (KDR_SCD_BASE + 0xe4) +#define KDR_SCD_INTERRUPT_THRESHOLD (KDR_SCD_BASE + 0xe8) +#define KDR_SCD_QUERY_MIN_FRAME_SIZE (KDR_SCD_BASE + 0x100) +#define KDR_SCD_QUEUE_STATUS_BITS(x) (KDR_SCD_BASE + 0x104 + (x) * 4) + +/* SP SCD */ +#define SHL_SCD_BASE (PRPH_BASE + 0xa02c00) + +#define SHL_SCD_AIT (SHL_SCD_BASE + 0x0c) +#define SHL_SCD_TXFACT (SHL_SCD_BASE + 0x10) +#define SHL_SCD_QUEUE_WRPTR(x) (SHL_SCD_BASE + 0x18 + (x) * 4) +#define SHL_SCD_QUEUE_RDPTR(x) (SHL_SCD_BASE + 0x68 + (x) * 4) +#define SHL_SCD_QUEUECHAIN_SEL (SHL_SCD_BASE + 0xe8) +#define SHL_SCD_AGGR_SEL (SHL_SCD_BASE + 0x248) +#define SHL_SCD_INTERRUPT_MASK (SHL_SCD_BASE + 0x108) + #endif /* __iwl_prph_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 1a6b0e0edf6f..748ac1222abb 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -27,16 +27,6 @@ * *****************************************************************************/ -/* - * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets - * by defining IWL to either 3945 or 4965. The Makefile used when building - * the base targets will create base-3945.o and base-4965.o - * - * The eventual goal is to move as many of the #if IWL / #endif blocks out of - * this file and into the hardware specific implementation files (iwl-XXXX.c) - * and leave only the common (non #ifdef sprinkled) code in this file - */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/version.h> @@ -56,16 +46,16 @@ #include <asm/div64.h> -#define IWL 3945 - -#include "iwlwifi.h" #include "iwl-3945.h" #include "iwl-helpers.h" -#ifdef CONFIG_IWLWIFI_DEBUG -u32 iwl_debug_level; +#ifdef CONFIG_IWL3945_DEBUG +u32 iwl3945_debug_level; #endif +static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, + struct iwl3945_tx_queue *txq); + /****************************************************************************** * * module boiler plate @@ -73,13 +63,13 @@ u32 iwl_debug_level; ******************************************************************************/ /* module parameters */ -int iwl_param_disable_hw_scan; -int iwl_param_debug; -int iwl_param_disable; /* def: enable radio */ -int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ -int iwl_param_hwcrypto; /* def: using software encryption */ -int iwl_param_qos_enable = 1; -int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; +static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */ +static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ +static int iwl3945_param_disable; /* def: 0 = enable radio */ +static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ +static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */ +int iwl3945_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 8 Tx queues */ /* * module name, copyright, version, etc. @@ -89,19 +79,19 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; #define DRV_DESCRIPTION \ "Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux" -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL3945_DEBUG #define VD "d" #else #define VD #endif -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT #define VS "s" #else #define VS #endif -#define IWLWIFI_VERSION "1.1.17k" VD VS +#define IWLWIFI_VERSION "1.2.23k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION @@ -116,7 +106,7 @@ MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); -__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) +static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) { u16 fc = le16_to_cpu(hdr->frame_control); int hdr_len = ieee80211_get_hdrlen(fc); @@ -126,8 +116,8 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl_get_hw_mode( - struct iwl_priv *priv, int mode) +static const struct ieee80211_hw_mode *iwl3945_get_hw_mode( + struct iwl3945_priv *priv, int mode) { int i; @@ -138,7 +128,7 @@ static const struct ieee80211_hw_mode *iwl_get_hw_mode( return NULL; } -static int iwl_is_empty_essid(const char *essid, int essid_len) +static int iwl3945_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ if (essid_len == 1 && essid[0] == ' ') @@ -154,13 +144,13 @@ static int iwl_is_empty_essid(const char *essid, int essid_len) return 1; } -static const char *iwl_escape_essid(const char *essid, u8 essid_len) +static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) { static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; const char *s = essid; char *d = escaped; - if (iwl_is_empty_essid(essid, essid_len)) { + if (iwl3945_is_empty_essid(essid, essid_len)) { memcpy(escaped, "<hidden>", sizeof("<hidden>")); return escaped; } @@ -178,10 +168,10 @@ static const char *iwl_escape_essid(const char *essid, u8 essid_len) return escaped; } -static void iwl_print_hex_dump(int level, void *p, u32 len) +static void iwl3945_print_hex_dump(int level, void *p, u32 len) { -#ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_debug_level & level)) +#ifdef CONFIG_IWL3945_DEBUG + if (!(iwl3945_debug_level & level)) return; print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, @@ -194,24 +184,31 @@ static void iwl_print_hex_dump(int level, void *p, u32 len) * * Theory of operation * - * A queue is a circular buffers with 'Read' and 'Write' pointers. - * 2 empty entries always kept in the buffer to protect from overflow. + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. * * For Tx queue, there are low mark and high mark limits. If, after queuing * the packet for Tx, free space become < low mark, Tx queue stopped. When * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IWL operates with six queues, one receive queue in the device's - * sram, one transmit queue for sending commands to the device firmware, - * and four transmit queues for data. + * The 3945 operates with six queues: One receive queue, one transmit queue + * (#4) for sending commands to the device firmware, and four transmit queues + * (#0-3) for data tx via EDCA. An additional 2 HCCA queues are unused. ***************************************************/ -static int iwl_queue_space(const struct iwl_queue *q) +static int iwl3945_queue_space(const struct iwl3945_queue *q) { - int s = q->last_used - q->first_empty; + int s = q->read_ptr - q->write_ptr; - if (q->last_used > q->first_empty) + if (q->read_ptr > q->write_ptr) s -= q->n_bd; if (s <= 0) @@ -223,42 +220,55 @@ static int iwl_queue_space(const struct iwl_queue *q) return s; } -/* XXX: n_bd must be power-of-two size */ -static inline int iwl_queue_inc_wrap(int index, int n_bd) +/** + * iwl3945_queue_inc_wrap - increment queue index, wrap back to beginning + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl3945_queue_inc_wrap(int index, int n_bd) { return ++index & (n_bd - 1); } -/* XXX: n_bd must be power-of-two size */ -static inline int iwl_queue_dec_wrap(int index, int n_bd) +/** + * iwl3945_queue_dec_wrap - increment queue index, wrap back to end + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl3945_queue_dec_wrap(int index, int n_bd) { return --index & (n_bd - 1); } -static inline int x2_queue_used(const struct iwl_queue *q, int i) +static inline int x2_queue_used(const struct iwl3945_queue *q, int i) { - return q->first_empty > q->last_used ? - (i >= q->last_used && i < q->first_empty) : - !(i < q->last_used && i >= q->first_empty); + return q->write_ptr > q->read_ptr ? + (i >= q->read_ptr && i < q->write_ptr) : + !(i < q->read_ptr && i >= q->write_ptr); } -static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +static inline u8 get_cmd_index(struct iwl3945_queue *q, u32 index, int is_huge) { + /* This is for scan command, the big buffer at end of command array */ if (is_huge) - return q->n_window; + return q->n_window; /* must be power of 2 */ + /* Otherwise, use normal size buffers */ return index & (q->n_window - 1); } -static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, +/** + * iwl3945_queue_init - Initialize queue's high/low-water and read/write indexes + */ +static int iwl3945_queue_init(struct iwl3945_priv *priv, struct iwl3945_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; q->n_window = slots_num; q->id = id; - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ + /* count must be power-of-two size, otherwise iwl3945_queue_inc_wrap + * and iwl3945_queue_dec_wrap are broken. */ BUG_ON(!is_power_of_2(count)); /* slots_num must be power-of-two size, otherwise @@ -273,27 +283,34 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, if (q->high_mark < 2) q->high_mark = 2; - q->first_empty = q->last_used = 0; + q->write_ptr = q->read_ptr = 0; return 0; } -static int iwl_tx_queue_alloc(struct iwl_priv *priv, - struct iwl_tx_queue *txq, u32 id) +/** + * iwl3945_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue + */ +static int iwl3945_tx_queue_alloc(struct iwl3945_priv *priv, + struct iwl3945_tx_queue *txq, u32 id) { struct pci_dev *dev = priv->pci_dev; + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ if (id != IWL_CMD_QUEUE_NUM) { txq->txb = kmalloc(sizeof(txq->txb[0]) * TFD_QUEUE_SIZE_MAX, GFP_KERNEL); if (!txq->txb) { - IWL_ERROR("kmalloc for auxilary BD " + IWL_ERROR("kmalloc for auxiliary BD " "structures failed\n"); goto error; } } else txq->txb = NULL; + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ txq->bd = pci_alloc_consistent(dev, sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, &txq->q.dma_addr); @@ -316,24 +333,33 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, return -ENOMEM; } -int iwl_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, int slots_num, u32 txq_id) +/** + * iwl3945_tx_queue_init - Allocate and initialize one tx/cmd queue + */ +int iwl3945_tx_queue_init(struct iwl3945_priv *priv, + struct iwl3945_tx_queue *txq, int slots_num, u32 txq_id) { struct pci_dev *dev = priv->pci_dev; int len; int rc = 0; - /* alocate command space + one big command for scan since scan - * command is very huge the system will not have two scan at the - * same time */ - len = sizeof(struct iwl_cmd) * slots_num; + /* + * Alloc buffer array for commands (Tx or other types of commands). + * For the command queue (#4), allocate command space + one big + * command for scan, since scan command is very huge; the system will + * not have two scans at the same time, so only one is needed. + * For data Tx queues (all other queues), no super-size command + * space is needed. + */ + len = sizeof(struct iwl3945_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; - rc = iwl_tx_queue_alloc(priv, txq, txq_id); + /* Alloc driver data array and TFD circular buffer */ + rc = iwl3945_tx_queue_alloc(priv, txq, txq_id); if (rc) { pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); @@ -342,26 +368,29 @@ int iwl_tx_queue_init(struct iwl_priv *priv, txq->need_update = 0; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + * iwl3945_queue_inc_wrap and iwl3945_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - iwl_hw_tx_queue_init(priv, txq); + /* Initialize queue high/low-water, head/tail indexes */ + iwl3945_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + /* Tell device where to find queue, enable DMA channel. */ + iwl3945_hw_tx_queue_init(priv, txq); return 0; } /** - * iwl_tx_queue_free - Deallocate DMA queue. + * iwl3945_tx_queue_free - Deallocate DMA queue. * @txq: Transmit queue to deallocate. * * Empty queue by removing and destroying all BD's. - * Free all buffers. txq itself is not freed. - * + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. */ -void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +void iwl3945_tx_queue_free(struct iwl3945_priv *priv, struct iwl3945_tx_queue *txq) { - struct iwl_queue *q = &txq->q; + struct iwl3945_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; int len; @@ -369,44 +398,47 @@ void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) return; /* first, empty all BD's */ - for (; q->first_empty != q->last_used; - q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) - iwl_hw_txq_free_tfd(priv, txq); + for (; q->write_ptr != q->read_ptr; + q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) + iwl3945_hw_txq_free_tfd(priv, txq); - len = sizeof(struct iwl_cmd) * q->n_window; + len = sizeof(struct iwl3945_cmd) * q->n_window; if (q->id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; + /* De-alloc array of command/tx buffers */ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - /* free buffers belonging to queue itself */ + /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + pci_free_consistent(dev, sizeof(struct iwl3945_tfd_frame) * 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; } - /* 0 fill whole structure */ + /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } -const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +const u8 iwl3945_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /*************** STATION TABLE MANAGEMENT **** - * - * NOTE: This needs to be overhauled to better synchronize between - * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c - * - * mac80211 should also be examined to determine if sta_info is duplicating + * mac80211 should be examined to determine if sta_info is duplicating * the functionality provided here */ /**************************************************************/ -#if 0 /* temparary disable till we add real remove station */ -static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +#if 0 /* temporary disable till we add real remove station */ +/** + * iwl3945_remove_station - Remove driver's knowledge of station. + * + * NOTE: This does not remove station from device's station table. + */ +static u8 iwl3945_remove_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; int i; @@ -442,7 +474,13 @@ out: return 0; } #endif -static void iwl_clear_stations_table(struct iwl_priv *priv) + +/** + * iwl3945_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ +static void iwl3945_clear_stations_table(struct iwl3945_priv *priv) { unsigned long flags; @@ -454,12 +492,14 @@ static void iwl_clear_stations_table(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->sta_lock, flags); } - -u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +/** + * iwl3945_add_station - Add station to station tables in driver and device + */ +u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 flags) { int i; int index = IWL_INVALID_STATION; - struct iwl_station_entry *station; + struct iwl3945_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); u8 rate; @@ -482,7 +522,7 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) index = i; } - /* These twh conditions has the same outcome but keep them separate + /* These two conditions has the same outcome but keep them separate since they have different meaning */ if (unlikely(index == IWL_INVALID_STATION)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); @@ -500,30 +540,35 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) station->used = 1; priv->num_stations++; - memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + /* Set up the REPLY_ADD_STA command to send to device */ + memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; station->sta.sta.sta_id = index; station->sta.station_flags = 0; - rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP : - IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag; + if (priv->phymode == MODE_IEEE80211A) + rate = IWL_RATE_6M_PLCP; + else + rate = IWL_RATE_1M_PLCP; /* Turn on both antennas for the station... */ station->sta.rate_n_flags = - iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); + iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK); station->current_rate.rate_n_flags = le16_to_cpu(station->sta.rate_n_flags); spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_station(priv, &station->sta, flags); + + /* Add station to device's station table */ + iwl3945_send_add_station(priv, &station->sta, flags); return index; } /*************** DRIVER STATUS FUNCTIONS *****/ -static inline int iwl_is_ready(struct iwl_priv *priv) +static inline int iwl3945_is_ready(struct iwl3945_priv *priv) { /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are * set but EXIT_PENDING is not */ @@ -532,29 +577,29 @@ static inline int iwl_is_ready(struct iwl_priv *priv) !test_bit(STATUS_EXIT_PENDING, &priv->status); } -static inline int iwl_is_alive(struct iwl_priv *priv) +static inline int iwl3945_is_alive(struct iwl3945_priv *priv) { return test_bit(STATUS_ALIVE, &priv->status); } -static inline int iwl_is_init(struct iwl_priv *priv) +static inline int iwl3945_is_init(struct iwl3945_priv *priv) { return test_bit(STATUS_INIT, &priv->status); } -static inline int iwl_is_rfkill(struct iwl_priv *priv) +static inline int iwl3945_is_rfkill(struct iwl3945_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status) || test_bit(STATUS_RF_KILL_SW, &priv->status); } -static inline int iwl_is_ready_rf(struct iwl_priv *priv) +static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv) { - if (iwl_is_rfkill(priv)) + if (iwl3945_is_rfkill(priv)) return 0; - return iwl_is_ready(priv); + return iwl3945_is_ready(priv); } /*************** HOST COMMAND QUEUE FUNCTIONS *****/ @@ -613,7 +658,7 @@ static const char *get_cmd_string(u8 cmd) #define HOST_COMPLETE_TIMEOUT (HZ / 2) /** - * iwl_enqueue_hcmd - enqueue a uCode command + * iwl3945_enqueue_hcmd - enqueue a uCode command * @priv: device private data point * @cmd: a point to the ucode command structure * @@ -621,13 +666,13 @@ static const char *get_cmd_string(u8 cmd) * failed. On success, it turns the index (> 0) of command in the * command queue. */ -static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd) { - struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; + struct iwl3945_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl3945_queue *q = &txq->q; + struct iwl3945_tfd_frame *tfd; u32 *control_flags; - struct iwl_cmd *out_cmd; + struct iwl3945_cmd *out_cmd; u32 idx; u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); dma_addr_t phys_addr; @@ -642,19 +687,19 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; } spin_lock_irqsave(&priv->hcmd_lock, flags); - tfd = &txq->bd[q->first_empty]; + tfd = &txq->bd[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); + idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); out_cmd = &txq->cmd[idx]; out_cmd->hdr.cmd = cmd->id; @@ -666,13 +711,13 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.flags = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | - INDEX_TO_SEQ(q->first_empty)); + 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); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + offsetof(struct iwl3945_cmd, hdr); + iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); pad = U32_PAD(cmd->len); count = TFD_CTL_COUNT_GET(*control_flags); @@ -682,17 +727,19 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) "%d bytes at %d[%d]:%d\n", get_cmd_string(out_cmd->hdr.cmd), out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); + fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); txq->need_update = 1; - q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); - ret = iwl_tx_queue_update_write_ptr(priv, txq); + + /* Increment and update queue's write index */ + q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); + ret = iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); return ret ? ret : idx; } -int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl3945_send_cmd_async(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd) { int ret; @@ -707,16 +754,16 @@ int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; - ret = iwl_enqueue_hcmd(priv, cmd); + ret = iwl3945_enqueue_hcmd(priv, cmd); if (ret < 0) { - IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } return 0; } -int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl3945_send_cmd_sync(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd) { int cmd_idx; int ret; @@ -738,10 +785,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; - cmd_idx = iwl_enqueue_hcmd(priv, cmd); + cmd_idx = iwl3945_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; - IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + IWL_ERROR("Error sending %s: iwl3945_enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); goto out; } @@ -785,7 +832,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) cancel: if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl_cmd *qcmd; + struct iwl3945_cmd *qcmd; /* Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes @@ -804,47 +851,43 @@ out: return ret; } -int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +int iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd) { - /* A command can not be asynchronous AND expect an SKB to be set. */ - BUG_ON((cmd->meta.flags & CMD_ASYNC) && - (cmd->meta.flags & CMD_WANT_SKB)); - if (cmd->meta.flags & CMD_ASYNC) - return iwl_send_cmd_async(priv, cmd); + return iwl3945_send_cmd_async(priv, cmd); - return iwl_send_cmd_sync(priv, cmd); + return iwl3945_send_cmd_sync(priv, cmd); } -int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, const void *data) { - struct iwl_host_cmd cmd = { + struct iwl3945_host_cmd cmd = { .id = id, .len = len, .data = data, }; - return iwl_send_cmd_sync(priv, &cmd); + return iwl3945_send_cmd_sync(priv, &cmd); } -static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) +static int __must_check iwl3945_send_cmd_u32(struct iwl3945_priv *priv, u8 id, u32 val) { - struct iwl_host_cmd cmd = { + struct iwl3945_host_cmd cmd = { .id = id, .len = sizeof(val), .data = &val, }; - return iwl_send_cmd_sync(priv, &cmd); + return iwl3945_send_cmd_sync(priv, &cmd); } -int iwl_send_statistics_request(struct iwl_priv *priv) +int iwl3945_send_statistics_request(struct iwl3945_priv *priv) { - return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); + return iwl3945_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); } /** - * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON + * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz * @channel: Any channel valid for the requested phymode @@ -853,9 +896,9 @@ int iwl_send_statistics_request(struct iwl_priv *priv) * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) +static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel) { - if (!iwl_get_channel_info(priv, phymode, channel)) { + if (!iwl3945_get_channel_info(priv, phymode, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", channel, phymode); return -EINVAL; @@ -879,13 +922,13 @@ static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) } /** - * iwl_check_rxon_cmd - validate RXON structure is valid + * iwl3945_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 iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +static int iwl3945_check_rxon_cmd(struct iwl3945_rxon_cmd *rxon) { int error = 0; int counter = 1; @@ -951,21 +994,21 @@ static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) le16_to_cpu(rxon->channel)); if (error) { - IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); + IWL_ERROR("Not a valid iwl3945_rxon_assoc_cmd field values\n"); return -1; } return 0; } /** - * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit - * @priv: staging_rxon is comapred to active_rxon + * iwl3945_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 sufficient to require a new - * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 - * to indicate a new tune is required. + * 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 iwl_full_rxon_required(struct iwl_priv *priv) +static int iwl3945_full_rxon_required(struct iwl3945_priv *priv) { /* These items are only settable from the full RXON command */ @@ -1000,19 +1043,19 @@ static int iwl_full_rxon_required(struct iwl_priv *priv) return 0; } -static int iwl_send_rxon_assoc(struct iwl_priv *priv) +static int iwl3945_send_rxon_assoc(struct iwl3945_priv *priv) { int rc = 0; - struct iwl_rx_packet *res = NULL; - struct iwl_rxon_assoc_cmd rxon_assoc; - struct iwl_host_cmd cmd = { + struct iwl3945_rx_packet *res = NULL; + struct iwl3945_rxon_assoc_cmd rxon_assoc; + struct iwl3945_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), .meta.flags = CMD_WANT_SKB, .data = &rxon_assoc, }; - const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + const struct iwl3945_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl3945_rxon_cmd *rxon2 = &priv->active_rxon; if ((rxon1->flags == rxon2->flags) && (rxon1->filter_flags == rxon2->filter_flags) && @@ -1028,11 +1071,11 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv) rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates; rxon_assoc.reserved = 0; - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl3945_send_cmd_sync(priv, &cmd); if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; @@ -1045,21 +1088,21 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv) } /** - * iwl_commit_rxon - commit staging_rxon to hardware + * iwl3945_commit_rxon - commit staging_rxon to hardware * - * The RXON command in staging_rxon is commited to the hardware and + * 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 iwl_commit_rxon(struct iwl_priv *priv) +static int iwl3945_commit_rxon(struct iwl3945_priv *priv) { /* cast away the const for active_rxon in this function */ - struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; int rc = 0; DECLARE_MAC_BUF(mac); - if (!iwl_is_alive(priv)) + if (!iwl3945_is_alive(priv)) return -1; /* always get timestamp with Rx frame */ @@ -1070,17 +1113,17 @@ static int iwl_commit_rxon(struct iwl_priv *priv) ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK); priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv); - rc = iwl_check_rxon_cmd(&priv->staging_rxon); + rc = iwl3945_check_rxon_cmd(&priv->staging_rxon); if (rc) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } /* If we don't need to send a full RXON, we can use - * iwl_rxon_assoc_cmd which is used to reconfigure filter + * iwl3945_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); + if (!iwl3945_full_rxon_required(priv)) { + rc = iwl3945_send_rxon_assoc(priv); if (rc) { IWL_ERROR("Error setting RXON_ASSOC " "configuration (%d).\n", rc); @@ -1096,13 +1139,13 @@ static int iwl_commit_rxon(struct iwl_priv *priv) * 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) && + if (iwl3945_is_associated(priv) && (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), + rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl3945_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set @@ -1125,8 +1168,8 @@ static int iwl_commit_rxon(struct iwl_priv *priv) print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl3945_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); return rc; @@ -1134,18 +1177,18 @@ static int iwl_commit_rxon(struct iwl_priv *priv) memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); - iwl_clear_stations_table(priv); + iwl3945_clear_stations_table(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 */ - rc = iwl_hw_reg_send_txpower(priv); + rc = iwl3945_hw_reg_send_txpower(priv); if (rc) { IWL_ERROR("Error setting Tx power (%d).\n", rc); return rc; } /* Add the broadcast address so we can send broadcast frames */ - if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) == + if (iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -1153,9 +1196,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv) /* 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 (iwl_is_associated(priv) && + if (iwl3945_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) - if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0) + if (iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; @@ -1172,9 +1215,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv) return 0; } -static int iwl_send_bt_config(struct iwl_priv *priv) +static int iwl3945_send_bt_config(struct iwl3945_priv *priv) { - struct iwl_bt_cmd bt_cmd = { + struct iwl3945_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, @@ -1182,15 +1225,15 @@ static int iwl_send_bt_config(struct iwl_priv *priv) .kill_cts_mask = 0, }; - return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl_bt_cmd), &bt_cmd); + return iwl3945_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl3945_bt_cmd), &bt_cmd); } -static int iwl_send_scan_abort(struct iwl_priv *priv) +static int iwl3945_send_scan_abort(struct iwl3945_priv *priv) { int rc = 0; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { + struct iwl3945_rx_packet *res; + struct iwl3945_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, }; @@ -1203,13 +1246,13 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return 0; } - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl3945_send_cmd_sync(priv, &cmd); if (rc) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return rc; } - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be @@ -1227,8 +1270,8 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return rc; } -static int iwl_card_state_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, +static int iwl3945_card_state_sync_callback(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, struct sk_buff *skb) { return 1; @@ -1237,16 +1280,16 @@ static int iwl_card_state_sync_callback(struct iwl_priv *priv, /* * CARD_STATE_CMD * - * Use: Sets the internal card state to enable, disable, or halt + * Use: Sets the device's internal card state to enable, disable, or halt * * When in the 'enable' state the card operates as normal. * When in the 'disable' state, the card enters into a low power mode. * When in the 'halt' state, the card is shut down and must be fully * restarted to come back on. */ -static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +static int iwl3945_send_card_state(struct iwl3945_priv *priv, u32 flags, u8 meta_flag) { - struct iwl_host_cmd cmd = { + struct iwl3945_host_cmd cmd = { .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, @@ -1254,22 +1297,22 @@ static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) }; if (meta_flag & CMD_ASYNC) - cmd.meta.u.callback = iwl_card_state_sync_callback; + cmd.meta.u.callback = iwl3945_card_state_sync_callback; - return iwl_send_cmd(priv, &cmd); + return iwl3945_send_cmd(priv, &cmd); } -static int iwl_add_sta_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) +static int iwl3945_add_sta_sync_callback(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, struct sk_buff *skb) { - struct iwl_rx_packet *res = NULL; + struct iwl3945_rx_packet *res = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); return 1; } - res = (struct iwl_rx_packet *)skb->data; + res = (struct iwl3945_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -1287,29 +1330,29 @@ static int iwl_add_sta_sync_callback(struct iwl_priv *priv, return 1; } -int iwl_send_add_station(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags) +int iwl3945_send_add_station(struct iwl3945_priv *priv, + struct iwl3945_addsta_cmd *sta, u8 flags) { - struct iwl_rx_packet *res = NULL; + struct iwl3945_rx_packet *res = NULL; int rc = 0; - struct iwl_host_cmd cmd = { + struct iwl3945_host_cmd cmd = { .id = REPLY_ADD_STA, - .len = sizeof(struct iwl_addsta_cmd), + .len = sizeof(struct iwl3945_addsta_cmd), .meta.flags = flags, .data = sta, }; if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_add_sta_sync_callback; + cmd.meta.u.callback = iwl3945_add_sta_sync_callback; else cmd.meta.flags |= CMD_WANT_SKB; - rc = iwl_send_cmd(priv, &cmd); + rc = iwl3945_send_cmd(priv, &cmd); if (rc || (flags & CMD_ASYNC)) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl3945_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -1334,7 +1377,7 @@ int iwl_send_add_station(struct iwl_priv *priv, return rc; } -static int iwl_update_sta_key_info(struct iwl_priv *priv, +static int iwl3945_update_sta_key_info(struct iwl3945_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) { @@ -1350,7 +1393,6 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv, break; case ALG_TKIP: case ALG_WEP: - return -EINVAL; default: return -EINVAL; } @@ -1369,28 +1411,28 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0); return 0; } -static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) +static int iwl3945_clear_sta_key_info(struct iwl3945_priv *priv, u8 sta_id) { unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); - memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl3945_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl3945_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + iwl3945_send_add_station(priv, &priv->stations[sta_id].sta, 0); return 0; } -static void iwl_clear_free_frames(struct iwl_priv *priv) +static void iwl3945_clear_free_frames(struct iwl3945_priv *priv) { struct list_head *element; @@ -1400,7 +1442,7 @@ static void iwl_clear_free_frames(struct iwl_priv *priv) while (!list_empty(&priv->free_frames)) { element = priv->free_frames.next; list_del(element); - kfree(list_entry(element, struct iwl_frame, list)); + kfree(list_entry(element, struct iwl3945_frame, list)); priv->frames_count--; } @@ -1411,9 +1453,9 @@ static void iwl_clear_free_frames(struct iwl_priv *priv) } } -static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +static struct iwl3945_frame *iwl3945_get_free_frame(struct iwl3945_priv *priv) { - struct iwl_frame *frame; + struct iwl3945_frame *frame; struct list_head *element; if (list_empty(&priv->free_frames)) { frame = kzalloc(sizeof(*frame), GFP_KERNEL); @@ -1428,21 +1470,21 @@ static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) element = priv->free_frames.next; list_del(element); - return list_entry(element, struct iwl_frame, list); + return list_entry(element, struct iwl3945_frame, list); } -static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame *frame) { memset(frame, 0, sizeof(*frame)); list_add(&frame->list, &priv->free_frames); } -unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, +unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left) { - if (!iwl_is_associated(priv) || !priv->ibss_beacon || + if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && (priv->iw_mode != IEEE80211_IF_TYPE_AP))) return 0; @@ -1455,37 +1497,27 @@ unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -static int iwl_rate_index_from_plcp(int plcp) -{ - int i = 0; - - for (i = 0; i < IWL_RATE_COUNT; i++) - if (iwl_rates[i].plcp == plcp) - return i; - return -1; -} - -static u8 iwl_rate_get_lowest_plcp(int rate_mask) +static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) { u8 i; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl_rates[i].next_ieee) { + i = iwl3945_rates[i].next_ieee) { if (rate_mask & (1 << i)) - return iwl_rates[i].plcp; + return iwl3945_rates[i].plcp; } return IWL_RATE_INVALID; } -static int iwl_send_beacon_cmd(struct iwl_priv *priv) +static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) { - struct iwl_frame *frame; + struct iwl3945_frame *frame; unsigned int frame_size; int rc; u8 rate; - frame = iwl_get_free_frame(priv); + frame = iwl3945_get_free_frame(priv); if (!frame) { IWL_ERROR("Could not obtain free frame buffer for beacon " @@ -1494,22 +1526,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) } if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & + rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xFF0); if (rate == IWL_INVALID_RATE) rate = IWL_RATE_6M_PLCP; } else { - rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); + rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); if (rate == IWL_INVALID_RATE) rate = IWL_RATE_1M_PLCP; } - frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate); - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + rc = iwl3945_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); - iwl_free_frame(priv, frame); + iwl3945_free_frame(priv, frame); return rc; } @@ -1520,22 +1552,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) +static void get_eeprom_mac(struct iwl3945_priv *priv, u8 *mac) { memcpy(mac, priv->eeprom.mac_address, 6); } /** - * iwl_eeprom_init - read EEPROM contents + * iwl3945_eeprom_init - read EEPROM contents * - * Load the EEPROM from adapter into priv->eeprom + * Load the EEPROM contents from adapter into priv->eeprom * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv) +int iwl3945_eeprom_init(struct iwl3945_priv *priv) { - u16 *e = (u16 *)&priv->eeprom; - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + __le16 *e = (__le16 *)&priv->eeprom; + u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP); u32 r; int sz = sizeof(priv->eeprom); int rc; @@ -1553,20 +1585,21 @@ int iwl_eeprom_init(struct iwl_priv *priv) return -ENOENT; } - rc = iwl_eeprom_aqcuire_semaphore(priv); + /* Make sure driver (instead of uCode) is allowed to read EEPROM */ + rc = iwl3945_eeprom_acquire_semaphore(priv); if (rc < 0) { - IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); + IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); return -ENOENT; } /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + _iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl_read_restricted(priv, CSR_EEPROM_REG); + r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); if (r & CSR_EEPROM_REG_READ_VALID_MSK) break; udelay(IWL_EEPROM_ACCESS_DELAY); @@ -1576,7 +1609,7 @@ int iwl_eeprom_init(struct iwl_priv *priv) IWL_ERROR("Time out reading EEPROM[%d]", addr); return -ETIMEDOUT; } - e[addr / 2] = le16_to_cpu(r >> 16); + e[addr / 2] = cpu_to_le16(r >> 16); } return 0; @@ -1587,22 +1620,17 @@ int iwl_eeprom_init(struct iwl_priv *priv) * Misc. internal state and helper functions * ******************************************************************************/ -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL3945_DEBUG /** - * iwl_report_frame - dump frame to syslog during debug sessions + * iwl3945_report_frame - dump frame to syslog during debug sessions * - * hack this function to show different aspects of received frames, + * You may hack this function to show different aspects of received frames, * including selective frame dumps. * group100 parameter selects whether to show 1 out of 100 good frames. - * - * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type - * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) - * is 3945-specific and gives bad output for 4965. Need to split the - * functionality, keep common stuff here. */ -void iwl_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, +void iwl3945_report_frame(struct iwl3945_priv *priv, + struct iwl3945_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { u32 to_us; @@ -1624,9 +1652,9 @@ void iwl_report_frame(struct iwl_priv *priv, u8 agc; u16 sig_avg; u16 noise_diff; - struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt); u8 *data = IWL_RX_DATA(pkt); /* MAC header */ @@ -1702,11 +1730,11 @@ void iwl_report_frame(struct iwl_priv *priv, else title = "Frame"; - rate = iwl_rate_index_from_plcp(rate_sym); + rate = iwl3945_rate_index_from_plcp(rate_sym); if (rate == -1) rate = 0; else - rate = iwl_rates[rate].ieee / 2; + rate = iwl3945_rates[rate].ieee / 2; /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -1728,25 +1756,25 @@ void iwl_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); + iwl3945_print_hex_dump(IWL_DL_RX, data, length); } #endif -static void iwl_unset_hw_setting(struct iwl_priv *priv) +static void iwl3945_unset_hw_setting(struct iwl3945_priv *priv) { if (priv->hw_setting.shared_virt) pci_free_consistent(priv->pci_dev, - sizeof(struct iwl_shared), + sizeof(struct iwl3945_shared), priv->hw_setting.shared_virt, priv->hw_setting.shared_phys); } /** - * iwl_supported_rate_to_ie - fill in the supported rate in IE field + * iwl3945_supported_rate_to_ie - fill in the supported rate in IE field * * return : set the bit for each supported rate insert in ie */ -static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, +static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate, u16 basic_rate, int *left) { u16 ret_rates = 0, bit; @@ -1757,7 +1785,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { if (bit & supported_rate) { ret_rates |= bit; - rates[*cnt] = iwl_rates[i].ieee | + rates[*cnt] = iwl3945_rates[i].ieee | ((bit & basic_rate) ? 0x80 : 0x00); (*cnt)++; (*left)--; @@ -1771,9 +1799,9 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, } /** - * iwl_fill_probe_req - fill in all required fields and IE for probe request + * iwl3945_fill_probe_req - fill in all required fields and IE for probe request */ -static u16 iwl_fill_probe_req(struct iwl_priv *priv, +static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, struct ieee80211_mgmt *frame, int left, int is_direct) { @@ -1789,9 +1817,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, len += 24; frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->da, iwl3945_broadcast_addr, ETH_ALEN); memcpy(frame->sa, priv->mac_addr, ETH_ALEN); - memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->bssid, iwl3945_broadcast_addr, ETH_ALEN); frame->seq_ctrl = 0; /* fill in our indirect SSID IE */ @@ -1834,11 +1862,11 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; cck_rates = IWL_CCK_RATES_MASK & active_rates; - ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, + ret_rates = iwl3945_supported_rate_to_ie(pos, cck_rates, priv->active_rate_basic, &left); active_rates &= ~ret_rates; - ret_rates = iwl_supported_rate_to_ie(pos, active_rates, + ret_rates = iwl3945_supported_rate_to_ie(pos, active_rates, priv->active_rate_basic, &left); active_rates &= ~ret_rates; @@ -1855,7 +1883,7 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, /* ... fill it in... */ *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos = 0; - iwl_supported_rate_to_ie(pos, active_rates, + iwl3945_supported_rate_to_ie(pos, active_rates, priv->active_rate_basic, &left); if (*pos > 0) len += 2 + *pos; @@ -1867,16 +1895,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, /* * QoS support */ -#ifdef CONFIG_IWLWIFI_QOS -static int iwl_send_qos_params_command(struct iwl_priv *priv, - struct iwl_qosparam_cmd *qos) +#ifdef CONFIG_IWL3945_QOS +static int iwl3945_send_qos_params_command(struct iwl3945_priv *priv, + struct iwl3945_qosparam_cmd *qos) { - return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, - sizeof(struct iwl_qosparam_cmd), qos); + return iwl3945_send_cmd_pdu(priv, REPLY_QOS_PARAM, + sizeof(struct iwl3945_qosparam_cmd), qos); } -static void iwl_reset_qos(struct iwl_priv *priv) +static void iwl3945_reset_qos(struct iwl3945_priv *priv) { u16 cw_min = 15; u16 cw_max = 1023; @@ -1963,13 +1991,10 @@ static void iwl_reset_qos(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) { unsigned long flags; - if (priv == NULL) - return; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -1990,16 +2015,16 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) spin_unlock_irqrestore(&priv->lock, flags); - if (force || iwl_is_associated(priv)) { + if (force || iwl3945_is_associated(priv)) { IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", priv->qos_data.qos_active); - iwl_send_qos_params_command(priv, + iwl3945_send_qos_params_command(priv, &(priv->qos_data.def_qos_parm)); } } -#endif /* CONFIG_IWLWIFI_QOS */ +#endif /* CONFIG_IWL3945_QOS */ /* * Power management (not Tx power!) functions */ @@ -2017,7 +2042,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) /* 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 iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, @@ -2027,7 +2052,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { }; /* for tim > 10 */ -static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { +static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, @@ -2040,11 +2065,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; -int iwl_power_init_handle(struct iwl_priv *priv) +int iwl3945_power_init_handle(struct iwl3945_priv *priv) { int rc = 0, i; - struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + struct iwl3945_power_mgr *pow_data; + int size = sizeof(struct iwl3945_power_vec_entry) * IWL_POWER_AC; u16 pci_pm; IWL_DEBUG_POWER("Initialize power \n"); @@ -2063,7 +2088,7 @@ int iwl_power_init_handle(struct iwl_priv *priv) if (rc != 0) return 0; else { - struct iwl_powertable_cmd *cmd; + struct iwl3945_powertable_cmd *cmd; IWL_DEBUG_POWER("adjust power command flags\n"); @@ -2079,15 +2104,15 @@ int iwl_power_init_handle(struct iwl_priv *priv) return rc; } -static int iwl_update_power_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, u32 mode) +static int iwl3945_update_power_cmd(struct iwl3945_priv *priv, + struct iwl3945_powertable_cmd *cmd, u32 mode) { int rc = 0, i; u8 skip; u32 max_sleep = 0; - struct iwl_power_vec_entry *range; + struct iwl3945_power_vec_entry *range; u8 period = 0; - struct iwl_power_mgr *pow_data; + struct iwl3945_power_mgr *pow_data; if (mode > IWL_POWER_INDEX_5) { IWL_DEBUG_POWER("Error invalid power mode \n"); @@ -2100,7 +2125,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, else range = &pow_data->pwr_range_1[1]; - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl3945_powertable_cmd)); #ifdef IWL_MAC80211_DISABLE if (priv->assoc_network != NULL) { @@ -2143,14 +2168,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, return rc; } -static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) +static int iwl3945_send_power_mode(struct iwl3945_priv *priv, u32 mode) { - u32 final_mode = mode; + u32 uninitialized_var(final_mode); int rc; - struct iwl_powertable_cmd cmd; + struct iwl3945_powertable_cmd cmd; /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuosly aware mode"), + * if plugged into AC power, set to CAM ("continuously aware mode"), * else user level */ switch (mode) { case IWL_POWER_BATTERY: @@ -2164,9 +2189,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) break; } - iwl_update_power_cmd(priv, &cmd, final_mode); + iwl3945_update_power_cmd(priv, &cmd, final_mode); - rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + rc = iwl3945_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); @@ -2176,7 +2201,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) return rc; } -int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +int iwl3945_is_network_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header) { /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ @@ -2206,7 +2231,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -const char *iwl_get_tx_fail_reason(u32 status) +static const char *iwl3945_get_tx_fail_reason(u32 status) { switch (status & TX_STATUS_MSK) { case TX_STATUS_SUCCESS: @@ -2233,11 +2258,11 @@ const char *iwl_get_tx_fail_reason(u32 status) } /** - * iwl_scan_cancel - Cancel any currently executing HW scan + * iwl3945_scan_cancel - Cancel any currently executing HW scan * * NOTE: priv->mutex is not required before calling this function */ -static int iwl_scan_cancel(struct iwl_priv *priv) +static int iwl3945_scan_cancel(struct iwl3945_priv *priv) { if (!test_bit(STATUS_SCAN_HW, &priv->status)) { clear_bit(STATUS_SCANNING, &priv->status); @@ -2260,17 +2285,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv) } /** - * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * iwl3945_scan_cancel_timeout - Cancel any currently executing HW scan * @ms: amount of time to wait (in milliseconds) for scan to abort * * NOTE: priv->mutex must be held before calling this function */ -static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +static int iwl3945_scan_cancel_timeout(struct iwl3945_priv *priv, unsigned long ms) { unsigned long now = jiffies; int ret; - ret = iwl_scan_cancel(priv); + ret = iwl3945_scan_cancel(priv); if (ret && ms) { mutex_unlock(&priv->mutex); while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && @@ -2284,7 +2309,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) return ret; } -static void iwl_sequence_reset(struct iwl_priv *priv) +static void iwl3945_sequence_reset(struct iwl3945_priv *priv) { /* Reset ieee stats */ @@ -2295,13 +2320,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv) priv->last_frag_num = -1; priv->last_packet_time = 0; - iwl_scan_cancel(priv); + iwl3945_scan_cancel(priv); } #define MAX_UCODE_BEACON_INTERVAL 1024 #define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) -static __le16 iwl_adjust_beacon_interval(u16 beacon_val) +static __le16 iwl3945_adjust_beacon_interval(u16 beacon_val) { u16 new_val = 0; u16 beacon_factor = 0; @@ -2314,7 +2339,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val) return cpu_to_le16(new_val); } -static void iwl_setup_rxon_timing(struct iwl_priv *priv) +static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) { u64 interval_tm_unit; u64 tsf, result; @@ -2344,14 +2369,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); priv->rxon_timing.beacon_interval = - iwl_adjust_beacon_interval( + iwl3945_adjust_beacon_interval( le16_to_cpu(priv->rxon_timing.beacon_interval)); } priv->rxon_timing.atim_window = 0; } else { priv->rxon_timing.beacon_interval = - iwl_adjust_beacon_interval(conf->beacon_int); + iwl3945_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; @@ -2370,14 +2395,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl_scan_initiate(struct iwl_priv *priv) +static int iwl3945_scan_initiate(struct iwl3945_priv *priv) { if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("APs don't scan.\n"); return 0; } - if (!iwl_is_ready_rf(priv)) { + if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; } @@ -2404,9 +2429,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv) return 0; } -static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +static int iwl3945_set_rxon_hwcrypto(struct iwl3945_priv *priv, int hw_decrypt) { - struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl3945_rxon_cmd *rxon = &priv->staging_rxon; if (hw_decrypt) rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; @@ -2416,7 +2441,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) return 0; } -static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) +static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode) { if (phymode == MODE_IEEE80211A) { priv->staging_rxon.flags &= @@ -2424,7 +2449,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) | RXON_FLG_CCK_MSK); priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; } else { - /* Copied from iwl_bg_post_associate() */ + /* Copied from iwl3945_bg_post_associate() */ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; else @@ -2440,11 +2465,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) } /* - * initilize rxon structure with default values fromm eeprom + * initialize rxon structure with default values from eeprom */ -static void iwl_connection_init_rx_config(struct iwl_priv *priv) +static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) { - const struct iwl_channel_info *ch_info; + const struct iwl3945_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); @@ -2481,7 +2506,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl_get_channel_info(priv, priv->phymode, + ch_info = iwl3945_get_channel_info(priv, priv->phymode, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2501,7 +2526,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv) else priv->phymode = MODE_IEEE80211G; - iwl_set_flags_for_phymode(priv, priv->phymode); + iwl3945_set_flags_for_phymode(priv, priv->phymode); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2509,15 +2534,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv) (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; } -static int iwl_set_mode(struct iwl_priv *priv, int mode) +static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) { - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - if (mode == IEEE80211_IF_TYPE_IBSS) { - const struct iwl_channel_info *ch_info; + const struct iwl3945_channel_info *ch_info; - ch_info = iwl_get_channel_info(priv, + ch_info = iwl3945_get_channel_info(priv, priv->phymode, le16_to_cpu(priv->staging_rxon.channel)); @@ -2528,32 +2550,36 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode) } } + priv->iw_mode = mode; + + iwl3945_connection_init_rx_config(priv); + memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); + + iwl3945_clear_stations_table(priv); + + /* dont commit rxon if rf-kill is on*/ + if (!iwl3945_is_ready_rf(priv)) + return -EAGAIN; + cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { + if (iwl3945_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; } - priv->iw_mode = mode; - - iwl_connection_init_rx_config(priv); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - - iwl_clear_stations_table(priv); - - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); return 0; } -static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, +static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, struct ieee80211_tx_control *ctl, - struct iwl_cmd *cmd, + struct iwl3945_cmd *cmd, struct sk_buff *skb_frag, int last_frag) { - struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + struct iwl3945_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -2596,8 +2622,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, /* * handle build REPLY_TX command notification. */ -static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, +static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, + struct iwl3945_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) @@ -2645,11 +2671,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - cmd->cmd.tx.timeout.pm_frame_timeout = - cpu_to_le16(3); + cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else - cmd->cmd.tx.timeout.pm_frame_timeout = - cpu_to_le16(2); + cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); } else cmd->cmd.tx.timeout.pm_frame_timeout = 0; @@ -2658,41 +2682,44 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, cmd->cmd.tx.next_frame_len = 0; } -static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +/** + * iwl3945_get_sta_id - Find station's index within station table + */ +static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); - /* If this frame is broadcast or not data then use the broadcast - * station id */ + /* If this frame is broadcast or management, use broadcast station id */ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || is_multicast_ether_addr(hdr->addr1)) return priv->hw_setting.bcast_sta_id; switch (priv->iw_mode) { - /* If this frame is part of a BSS network (we're a station), then - * we use the AP's station id */ + /* If we are a client station in a BSS network, use the special + * AP station entry (that's the only station we communicate with) */ case IEEE80211_IF_TYPE_STA: return IWL_AP_ID; /* If we are an AP, then find the station, or use BCAST */ case IEEE80211_IF_TYPE_AP: - sta_id = iwl_hw_find_station(priv, hdr->addr1); + sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_setting.bcast_sta_id; - /* If this frame is part of a IBSS network, then we use the - * target specific station id */ + /* If this frame is going out to an IBSS network, find the station, + * or create a new station table entry */ case IEEE80211_IF_TYPE_IBSS: { DECLARE_MAC_BUF(mac); - sta_id = iwl_hw_find_station(priv, hdr->addr1); + /* Create new station table entry */ + sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; - sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2700,11 +2727,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", print_mac(mac, hdr->addr1)); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; } default: - IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); + IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); return priv->hw_setting.bcast_sta_id; } } @@ -2712,18 +2739,18 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* * start REPLY_TX command process */ -static int iwl_tx_skb(struct iwl_priv *priv, +static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_tfd_frame *tfd; + struct iwl3945_tfd_frame *tfd; u32 *control_flags; int txq_id = ctl->queue; - struct iwl_tx_queue *txq = NULL; - struct iwl_queue *q = NULL; + struct iwl3945_tx_queue *txq = NULL; + struct iwl3945_queue *q = NULL; dma_addr_t phys_addr; dma_addr_t txcmd_phys; - struct iwl_cmd *out_cmd = NULL; + struct iwl3945_cmd *out_cmd = NULL; u16 len, idx, len_org; u8 id, hdr_len, unicast; u8 sta_id; @@ -2735,13 +2762,13 @@ static int iwl_tx_skb(struct iwl_priv *priv, int rc; spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { + if (iwl3945_is_rfkill(priv)) { IWL_DEBUG_DROP("Dropping - RF KILL\n"); goto drop_unlock; } - if (!priv->interface_id) { - IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + if (!priv->vif) { + IWL_DEBUG_DROP("Dropping - !priv->vif\n"); goto drop_unlock; } @@ -2755,7 +2782,7 @@ static int iwl_tx_skb(struct iwl_priv *priv, fc = le16_to_cpu(hdr->frame_control); -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL3945_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX("Sending AUTH frame\n"); else if (ieee80211_is_assoc_request(fc)) @@ -2764,16 +2791,19 @@ static int iwl_tx_skb(struct iwl_priv *priv, IWL_DEBUG_TX("Sending REASSOC frame\n"); #endif - if (!iwl_is_associated(priv) && + /* drop all data frame if we are not associated */ + if (!iwl3945_is_associated(priv) && !priv->assoc_id && ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { - IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; } spin_unlock_irqrestore(&priv->lock, flags); hdr_len = ieee80211_get_hdrlen(fc); - sta_id = iwl_get_sta_id(priv, hdr); + + /* Find (or create) index into station table for destination station */ + sta_id = iwl3945_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { DECLARE_MAC_BUF(mac); @@ -2794,32 +2824,54 @@ static int iwl_tx_skb(struct iwl_priv *priv, __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); seq_number += 0x10; } + + /* Descriptor for chosen Tx queue */ txq = &priv->txq[txq_id]; q = &txq->q; spin_lock_irqsave(&priv->lock, flags); - tfd = &txq->bd[q->first_empty]; + /* Set up first empty TFD within this queue's circular TFD buffer */ + tfd = &txq->bd[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->first_empty, 0); + idx = get_cmd_index(q, q->write_ptr, 0); - memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->first_empty].skb[0] = skb; - memcpy(&(txq->txb[q->first_empty].status.control), + /* Set up driver data for this TFD */ + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl3945_tx_info)); + txq->txb[q->write_ptr].skb[0] = skb; + memcpy(&(txq->txb[q->write_ptr].status.control), ctl, sizeof(struct ieee80211_tx_control)); + + /* Init first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + + /* + * Set up the Tx-command (not MAC!) header. + * Store the chosen Tx queue and TFD index within the sequence field; + * after Tx, uCode's Tx response will return this value so driver can + * locate the frame within the tx queue and do post-tx processing. + */ out_cmd->hdr.cmd = REPLY_TX; out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->first_empty))); - /* copy frags header */ + INDEX_TO_SEQ(q->write_ptr))); + + /* Copy MAC header from skb into command buffer */ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); - /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ len = priv->hw_setting.tx_cmd_len + - sizeof(struct iwl_cmd_header) + hdr_len; + sizeof(struct iwl3945_cmd_header) + hdr_len; len_org = len; len = (len + 3) & ~3; @@ -2829,37 +2881,45 @@ static int iwl_tx_skb(struct iwl_priv *priv, else len_org = 0; - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + - offsetof(struct iwl_cmd, hdr); + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl3945_cmd) * idx + + offsetof(struct iwl3945_cmd, hdr); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + /* Add buffer containing Tx command and MAC(!) header to TFD's + * first entry */ + iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + iwl3945_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); - /* 802.11 null functions have no payload... */ + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ len = skb->len - hdr_len; if (len) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, len, PCI_DMA_TODEVICE); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + iwl3945_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); } - /* If there is no payload, then only one TFD is used */ if (!len) + /* If there is no payload, then we use only one Tx buffer */ *control_flags = TFD_CTL_COUNT_SET(1); else + /* Else use 2 buffers. + * Tell 3945 about any padding after MAC header */ *control_flags = TFD_CTL_COUNT_SET(2) | TFD_CTL_PAD_SET(U32_PAD(len)); + /* Total # bytes to be transmitted */ len = (u16)skb->len; out_cmd->cmd.tx.len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + iwl3945_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + iwl3945_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK; out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK; @@ -2875,25 +2935,26 @@ static int iwl_tx_skb(struct iwl_priv *priv, txq->need_update = 0; } - iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + iwl3945_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, sizeof(out_cmd->cmd.tx)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + iwl3945_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, ieee80211_get_hdrlen(fc)); - q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); - rc = iwl_tx_queue_update_write_ptr(priv, txq); + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl3945_queue_inc_wrap(q->write_ptr, q->n_bd); + rc = iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); if (rc) return rc; - if ((iwl_queue_space(q) < q->high_mark) + if ((iwl3945_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); txq->need_update = 1; - iwl_tx_queue_update_write_ptr(priv, txq); + iwl3945_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } @@ -2908,13 +2969,13 @@ drop: return -1; } -static void iwl_set_rate(struct iwl_priv *priv) +static void iwl3945_set_rate(struct iwl3945_priv *priv) { const struct ieee80211_hw_mode *hw = NULL; struct ieee80211_rate *rate; int i; - hw = iwl_get_hw_mode(priv, priv->phymode); + hw = iwl3945_get_hw_mode(priv, priv->phymode); if (!hw) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; @@ -2932,7 +2993,7 @@ static void iwl_set_rate(struct iwl_priv *priv) if ((rate->val < IWL_RATE_COUNT) && (rate->flags & IEEE80211_RATE_SUPPORTED)) { IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl_rates[rate->val].plcp, + rate->val, iwl3945_rates[rate->val].plcp, (rate->flags & IEEE80211_RATE_BASIC) ? "*" : ""); priv->active_rate |= (1 << rate->val); @@ -2940,7 +3001,7 @@ static void iwl_set_rate(struct iwl_priv *priv) priv->active_rate_basic |= (1 << rate->val); } else IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl_rates[rate->val].plcp); + rate->val, iwl3945_rates[rate->val].plcp); } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -2969,7 +3030,7 @@ static void iwl_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +static void iwl3945_radio_kill_sw(struct iwl3945_priv *priv, int disable_radio) { unsigned long flags; @@ -2980,21 +3041,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) disable_radio ? "OFF" : "ON"); if (disable_radio) { - iwl_scan_cancel(priv); + iwl3945_scan_cancel(priv); /* FIXME: This is a workaround for AP */ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); spin_unlock_irqrestore(&priv->lock, flags); - iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + iwl3945_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); set_bit(STATUS_RF_KILL_SW, &priv->status); } return; } spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); clear_bit(STATUS_RF_KILL_SW, &priv->status); spin_unlock_irqrestore(&priv->lock, flags); @@ -3003,9 +3064,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) msleep(10); spin_lock_irqsave(&priv->lock, flags); - iwl_read32(priv, CSR_UCODE_DRV_GP1); - if (!iwl_grab_restricted_access(priv)) - iwl_release_restricted_access(priv); + iwl3945_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl3945_grab_nic_access(priv)) + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { @@ -3018,7 +3079,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) return; } -void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, +void iwl3945_set_decrypted_flag(struct iwl3945_priv *priv, struct sk_buff *skb, u32 decrypt_res, struct ieee80211_rx_status *stats) { u16 fc = @@ -3050,97 +3111,9 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, } } -void iwl_handle_data_packet_monitor(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags) -{ - struct iwl_rt_rx_hdr *iwl_rt; - - /* First cache any information we need before we overwrite - * the information provided in the skb from the hardware */ - s8 signal = stats->ssi; - s8 noise = 0; - int rate = stats->rate; - u64 tsf = stats->mactime; - __le16 phy_flags_hw = cpu_to_le16(phy_flags); - - /* We received data from the HW, so stop the watchdog */ - if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) { - IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); - return; - } - - /* copy the frame data to write after where the radiotap header goes */ - iwl_rt = (void *)rxb->skb->data; - memmove(iwl_rt->payload, data, len); - - iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */ - - /* total header + data */ - iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt)); - - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, sizeof(*iwl_rt) + len); - - /* Big bitfield of all the fields we provide in radiotap */ - iwl_rt->rt_hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)); - - /* Zero the flags, we'll add to them as we go */ - iwl_rt->rt_flags = 0; - - iwl_rt->rt_tsf = cpu_to_le64(tsf); - - /* Convert to dBm */ - iwl_rt->rt_dbmsignal = signal; - iwl_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - iwl_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - iwl_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); - else /* 802.11g */ - iwl_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); - - rate = iwl_rate_index_from_plcp(rate); - if (rate == -1) - iwl_rt->rt_rate = 0; - else - iwl_rt->rt_rate = iwl_rates[rate].ieee; - - /* antenna number */ - iwl_rt->rt_antenna = - le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; - - /* set the preamble flag if we have it */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - - stats->flag |= RX_FLAG_RADIOTAP; - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); - rxb->skb = NULL; -} - - #define IWL_PACKET_RETRY_TIME HZ -int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +int iwl3945_is_duplicate_packet(struct iwl3945_priv *priv, struct ieee80211_hdr *header) { u16 sc = le16_to_cpu(header->seq_ctrl); u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; @@ -3151,29 +3124,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) switch (priv->iw_mode) { case IEEE80211_IF_TYPE_IBSS:{ struct list_head *p; - struct iwl_ibss_seq *entry = NULL; + struct iwl3945_ibss_seq *entry = NULL; u8 *mac = header->addr2; int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); __list_for_each(p, &priv->ibss_mac_hash[index]) { - entry = - list_entry(p, struct iwl_ibss_seq, list); + entry = list_entry(p, struct iwl3945_ibss_seq, list); if (!compare_ether_addr(entry->mac, mac)) break; } if (p == &priv->ibss_mac_hash[index]) { entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) { - IWL_ERROR - ("Cannot malloc new mac entry\n"); + IWL_ERROR("Cannot malloc new mac entry\n"); return 0; } memcpy(entry->mac, mac, ETH_ALEN); entry->seq_num = seq; entry->frag_num = frag; entry->packet_time = jiffies; - list_add(&entry->list, - &priv->ibss_mac_hash[index]); + list_add(&entry->list, &priv->ibss_mac_hash[index]); return 0; } last_seq = &entry->seq_num; @@ -3207,7 +3177,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) return 1; } -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT #include "iwl-spectrum.h" @@ -3222,7 +3192,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) * the lower 3 bytes is the time in usec within one beacon interval */ -static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +static u32 iwl3945_usecs_to_beacons(u32 usec, u32 beacon_interval) { u32 quot; u32 rem; @@ -3241,7 +3211,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) * the same as HW timer counter counting down */ -static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +static __le32 iwl3945_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; @@ -3260,13 +3230,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) return cpu_to_le32(res); } -static int iwl_get_measurement(struct iwl_priv *priv, +static int iwl3945_get_measurement(struct iwl3945_priv *priv, struct ieee80211_measurement_params *params, u8 type) { - struct iwl_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { + struct iwl3945_spectrum_cmd spectrum; + struct iwl3945_rx_packet *res; + struct iwl3945_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, .meta.flags = CMD_WANT_SKB, @@ -3276,9 +3246,9 @@ static int iwl_get_measurement(struct iwl_priv *priv, int spectrum_resp_status; int duration = le16_to_cpu(params->duration); - if (iwl_is_associated(priv)) + if (iwl3945_is_associated(priv)) add_time = - iwl_usecs_to_beacons( + iwl3945_usecs_to_beacons( le64_to_cpu(params->start_time) - priv->last_tsf, le16_to_cpu(priv->rxon_timing.beacon_interval)); @@ -3291,9 +3261,9 @@ static int iwl_get_measurement(struct iwl_priv *priv, cmd.len = sizeof(spectrum); spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - if (iwl_is_associated(priv)) + if (iwl3945_is_associated(priv)) spectrum.start_time = - iwl_add_beacon_time(priv->last_beacon_time, + iwl3945_add_beacon_time(priv->last_beacon_time, add_time, le16_to_cpu(priv->rxon_timing.beacon_interval)); else @@ -3306,11 +3276,11 @@ static int iwl_get_measurement(struct iwl_priv *priv, spectrum.flags |= RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl3945_send_cmd_sync(priv, &cmd); if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl3945_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; @@ -3320,9 +3290,8 @@ static int iwl_get_measurement(struct iwl_priv *priv, 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); + IWL_DEBUG_INFO("Replaced existing measurement: %d\n", + res->u.spectrum.id); priv->measurement_status &= ~MEASUREMENT_READY; } priv->measurement_status |= MEASUREMENT_ACTIVE; @@ -3340,8 +3309,8 @@ static int iwl_get_measurement(struct iwl_priv *priv, } #endif -static void iwl_txstatus_to_ieee(struct iwl_priv *priv, - struct iwl_tx_info *tx_sta) +static void iwl3945_txstatus_to_ieee(struct iwl3945_priv *priv, + struct iwl3945_tx_info *tx_sta) { tx_sta->status.ack_signal = 0; @@ -3360,41 +3329,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv, } /** - * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. + * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd * - * When FW advances 'R' index, all entries between old and - * new 'R' index need to be reclaimed. As result, some free space - * forms. If there is enough free space (> low mark), wake Tx queue. + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. As result, some free space forms. If there is + * enough free space (> low mark), wake the stack that feeds us. */ -int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +static int iwl3945_tx_queue_reclaim(struct iwl3945_priv *priv, int txq_id, int index) { - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; + struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; + struct iwl3945_queue *q = &txq->q; int nfreed = 0; if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->first_empty, q->last_used); + index, q->n_bd, q->write_ptr, q->read_ptr); return 0; } - for (index = iwl_queue_inc_wrap(index, q->n_bd); - q->last_used != index; - q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) { + for (index = iwl3945_queue_inc_wrap(index, q->n_bd); + q->read_ptr != index; + q->read_ptr = iwl3945_queue_inc_wrap(q->read_ptr, q->n_bd)) { if (txq_id != IWL_CMD_QUEUE_NUM) { - iwl_txstatus_to_ieee(priv, - &(txq->txb[txq->q.last_used])); - iwl_hw_txq_free_tfd(priv, txq); + iwl3945_txstatus_to_ieee(priv, + &(txq->txb[txq->q.read_ptr])); + iwl3945_hw_txq_free_tfd(priv, txq); } else if (nfreed > 1) { IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, - q->first_empty, q->last_used); + q->write_ptr, q->read_ptr); queue_work(priv->workqueue, &priv->restart); } nfreed++; } - if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && + if (iwl3945_queue_space(q) > q->low_mark && (txq_id >= 0) && (txq_id != IWL_CMD_QUEUE_NUM) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); @@ -3403,7 +3372,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) return nfreed; } -static int iwl_is_tx_success(u32 status) +static int iwl3945_is_tx_success(u32 status) { return (status & 0xFF) == 0x1; } @@ -3413,27 +3382,30 @@ static int iwl_is_tx_success(u32 status) * Generic RX handler implementations * ******************************************************************************/ -static void iwl_rx_reply_tx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +/** + * iwl3945_rx_reply_tx - Handle Tx response + */ +static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); - struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl3945_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_status *tx_status; - struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.first_empty, - txq->q.last_used); + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); return; } - tx_status = &(txq->txb[txq->q.last_used].status); + tx_status = &(txq->txb[txq->q.read_ptr].status); tx_status->retry_count = tx_resp->failure_frame; tx_status->queue_number = status; @@ -3441,28 +3413,28 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv, tx_status->queue_length |= tx_resp->failure_rts; tx_status->flags = - iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate); + tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate); IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", - txq_id, iwl_get_tx_fail_reason(status), status, + txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); if (index != -1) - iwl_tx_queue_reclaim(priv, txq_id, index); + iwl3945_tx_queue_reclaim(priv, txq_id, index); if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_reply_alive(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_alive_resp *palive; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_alive_resp *palive; struct delayed_work *pwork; palive = &pkt->u.alive_frame; @@ -3476,14 +3448,14 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_DEBUG_INFO("Initialization Alive received.\n"); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); + sizeof(struct iwl3945_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)); + sizeof(struct iwl3945_alive_resp)); pwork = &priv->alive_start; - iwl_disable_events(priv); + iwl3945_disable_events(priv); } /* We delay the ALIVE response by 5ms to @@ -3495,19 +3467,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl_rx_reply_add_sta(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_reply_add_sta(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); return; } -static void iwl_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_reply_error(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " "seq 0x%04X ser 0x%08X\n", @@ -3520,23 +3492,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_csa(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; - struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rxon_cmd *rxon = (void *)&priv->active_rxon; + struct iwl3945_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 iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_spectrum_measure_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, @@ -3549,35 +3521,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, #endif } -static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_pm_sleep_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); +#ifdef CONFIG_IWL3945_DEBUG + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_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 iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_pm_debug_statistics_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (void *)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(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl3945_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } -static void iwl_bg_beacon_update(struct work_struct *work) +static void iwl3945_bg_beacon_update(struct work_struct *work) { - struct iwl_priv *priv = - container_of(work, struct iwl_priv, beacon_update); + struct iwl3945_priv *priv = + container_of(work, struct iwl3945_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->interface_id, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -3592,15 +3564,15 @@ static void iwl_bg_beacon_update(struct work_struct *work) priv->ibss_beacon = beacon; mutex_unlock(&priv->mutex); - iwl_send_beacon_cmd(priv); + iwl3945_send_beacon_cmd(priv); } -static void iwl_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_beacon_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status); +#ifdef CONFIG_IWL3945_DEBUG + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_beacon_notif *beacon = &(pkt->u.beacon_status); u8 rate = beacon->beacon_notify_hdr.rate; IWL_DEBUG_RX("beacon status %x retries %d iss %d " @@ -3618,25 +3590,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, } /* Service response to REPLY_SCAN_CMD (0x80) */ -static void iwl_rx_reply_scan(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_reply_scan(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scanreq_notification *notif = - (struct iwl_scanreq_notification *)pkt->u.raw; +#ifdef CONFIG_IWL3945_DEBUG + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_scanreq_notification *notif = + (struct iwl3945_scanreq_notification *)pkt->u.raw; IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); #endif } /* Service SCAN_START_NOTIFICATION (0x82) */ -static void iwl_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_scan_start_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scanstart_notification *notif = - (struct iwl_scanstart_notification *)pkt->u.raw; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_scanstart_notification *notif = + (struct iwl3945_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); IWL_DEBUG_SCAN("Scan start: " "%d [802.11%s] " @@ -3648,12 +3620,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static void iwl_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_scan_results_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scanresults_notification *notif = - (struct iwl_scanresults_notification *)pkt->u.raw; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_scanresults_notification *notif = + (struct iwl3945_scanresults_notification *)pkt->u.raw; IWL_DEBUG_SCAN("Scan ch.res: " "%d [802.11%s] " @@ -3669,14 +3641,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, (priv->last_scan_jiffies, jiffies))); priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_scan_complete_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", scan_notif->scanned_channels, @@ -3711,6 +3684,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, } priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; IWL_DEBUG_INFO("Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); @@ -3729,10 +3703,10 @@ reschedule: /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_rx_card_state_notif(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (void *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -3740,7 +3714,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, (flags & HW_CARD_DISABLED) ? "Kill" : "On", (flags & SW_CARD_DISABLED) ? "Kill" : "On"); - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl3945_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); if (flags & HW_CARD_DISABLED) @@ -3754,7 +3728,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, else clear_bit(STATUS_RF_KILL_SW, &priv->status); - iwl_scan_cancel(priv); + iwl3945_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) || @@ -3766,7 +3740,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, } /** - * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * iwl3945_setup_rx_handlers - Initialize Rx handler callbacks * * Setup the RX handlers for each of the reply types sent from the uCode * to the host. @@ -3774,61 +3748,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, * 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) +static void iwl3945_setup_rx_handlers(struct iwl3945_priv *priv) { - priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta; - priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive; + priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta; + priv->rx_handlers[REPLY_ERROR] = iwl3945_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl3945_rx_csa; priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + iwl3945_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl3945_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; - - /* NOTE: iwl_rx_statistics is different based on whether - * the build is for the 3945 or the 4965. See the - * corresponding implementation in iwl-XXXX.c - * - * The same handler is used for both the REPLY to a - * discrete statistics request from the host as well as - * for the periodic statistics notification from the uCode + iwl3945_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_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_hw_rx_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics; + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics; - priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; - priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[REPLY_SCAN_CMD] = iwl3945_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl3945_rx_scan_start_notif; priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = - iwl_rx_scan_results_notif; + iwl3945_rx_scan_results_notif; priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = - iwl_rx_scan_complete_notif; - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; - priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx; + iwl3945_rx_scan_complete_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif; + priv->rx_handlers[REPLY_TX] = iwl3945_rx_reply_tx; - /* Setup hardware specific Rx handlers */ - iwl_hw_rx_handler_setup(priv); + /* Set up hardware specific Rx handlers */ + iwl3945_hw_rx_handler_setup(priv); } /** - * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim * * If an Rx buffer has an async callback associated with it the callback * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ -static void iwl_tx_cmd_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl3945_tx_cmd_complete(struct iwl3945_priv *priv, + struct iwl3945_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl3945_rx_packet *pkt = (struct iwl3945_rx_packet *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); int huge = sequence & SEQ_HUGE_FRAME; int cmd_index; - struct iwl_cmd *cmd; + struct iwl3945_cmd *cmd; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -3849,7 +3820,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl_tx_queue_reclaim(priv, txq_id, index); + iwl3945_tx_queue_reclaim(priv, txq_id, index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -3879,10 +3850,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, * The queue is empty (no good data) if WRITE = READ - 1, and is full if * WRITE = READ. * - * During initialization the host sets up the READ queue position to the first + * During initialization, the host sets up the READ queue position to the first * INDEX position, and WRITE to the last (READ - 1 wrapped) * - * When the firmware places a packet in a buffer it will advance the READ index + * When the firmware places a packet in a buffer, it will advance the READ index * and fire the RX interrupt. The driver can then query the READ index and * process as many packets as possible, moving the WRITE index forward as it * resets the Rx queue buffers with new memory. @@ -3890,8 +3861,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, * The management in the driver is as follows: * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replensish the iwl->rxq->rx_free. - * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * to replenish the iwl->rxq->rx_free. + * + In iwl3945_rx_replenish (scheduled) if 'processed' != 'read' then the * iwl->rxq is replenished and the READ INDEX is updated (updating the * 'processed' and 'read' driver indexes as well) * + A received packet is processed and handed to the kernel network stack, @@ -3904,28 +3875,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, * * Driver sequence: * - * iwl_rx_queue_alloc() Allocates rx_free - * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_rx_queue_restock - * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * iwl3945_rx_queue_alloc() Allocates rx_free + * iwl3945_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl3945_rx_queue_restock + * iwl3945_rx_queue_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl_rx_replenish + * are available, schedules iwl3945_rx_replenish * * -- enable interrupts -- - * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * ISR - iwl3945_rx() Detach iwl3945_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. - * Calls iwl_rx_queue_restock to refill any empty + * Calls iwl3945_rx_queue_restock to refill any empty * slots. * ... * */ /** - * iwl_rx_queue_space - Return number of free slots available in queue. + * iwl3945_rx_queue_space - Return number of free slots available in queue. */ -static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +static int iwl3945_rx_queue_space(const struct iwl3945_rx_queue *q) { int s = q->read - q->write; if (s <= 0) @@ -3938,15 +3909,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q) } /** - * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue - * - * NOTE: This function has 3945 and 4965 specific code sections - * but is declared in base due to the majority of the - * implementation being the same (only a numeric constant is - * different) - * + * iwl3945_rx_queue_update_write_ptr - Update the write pointer for the RX queue */ -int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q) { u32 reg = 0; int rc = 0; @@ -3957,24 +3922,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) if (q->need_update == 0) goto exit_unlock; + /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl3945_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - iwl_set_bit(priv, CSR_GP_CNTRL, + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; } - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) goto exit_unlock; - iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR, + /* Device expects a multiple of 8 */ + iwl3945_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); + + /* Else device is assumed to be awake */ } else - iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + /* Device expects a multiple of 8 */ + iwl3945_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); q->need_update = 0; @@ -3985,42 +3955,43 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) } /** - * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. - * - * NOTE: This function has 3945 and 4965 specific code paths in it. + * iwl3945_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr */ -static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, +static inline __le32 iwl3945_dma_addr2rbd_ptr(struct iwl3945_priv *priv, dma_addr_t dma_addr) { return cpu_to_le32((u32)dma_addr); } /** - * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * iwl3945_rx_queue_restock - refill RX queue from pre-allocated pool * - * If there are slots in the RX queue that need to be restocked, + * If there are slots in the RX queue that need to be restocked, * and we have free pre-allocated buffers, fill the ranks as much - * as we can pulling from rx_free. + * as we can, pulling from rx_free. * * This moves the 'write' index forward to catch up with 'processed', and * also updates the memory address in the firmware to reference the new * target buffer. */ -int iwl_rx_queue_restock(struct iwl_priv *priv) +static int iwl3945_rx_queue_restock(struct iwl3945_priv *priv) { - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl3945_rx_queue *rxq = &priv->rxq; struct list_head *element; - struct iwl_rx_mem_buffer *rxb; + struct iwl3945_rx_mem_buffer *rxb; unsigned long flags; int write, rc; spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; - while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + while ((iwl3945_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + /* Get next free Rx buffer, remove from free list */ element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list); list_del(element); - rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + + /* Point to Rx buffer via next RBD in circular buffer */ + rxq->bd[rxq->write] = iwl3945_dma_addr2rbd_ptr(priv, rxb->dma_addr); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -4032,13 +4003,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->rx_replenish); - /* If we've added more space for the firmware to place data, tell it */ + /* If we've added more space for the firmware to place data, tell it. + * Increment device's write pointer in multiples of 8. */ if ((write != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - rc = iwl_rx_queue_update_write_ptr(priv, rxq); + rc = iwl3945_rx_queue_update_write_ptr(priv, rxq); if (rc) return rc; } @@ -4047,24 +4019,25 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) } /** - * iwl_rx_replensih - Move all used packet from rx_used to rx_free + * iwl3945_rx_replenish - Move all used packet from rx_used to rx_free * * When moving to rx_free an SKB is allocated for the slot. * - * Also restock the Rx queue via iwl_rx_queue_restock. - * This is called as a scheduled work item (except for during intialization) + * Also restock the Rx queue via iwl3945_rx_queue_restock. + * This is called as a scheduled work item (except for during initialization) */ -void iwl_rx_replenish(void *data) +static void iwl3945_rx_allocate(struct iwl3945_priv *priv) { - struct iwl_priv *priv = data; - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl3945_rx_queue *rxq = &priv->rxq; struct list_head *element; - struct iwl_rx_mem_buffer *rxb; + struct iwl3945_rx_mem_buffer *rxb; unsigned long flags; spin_lock_irqsave(&rxq->lock, flags); while (!list_empty(&rxq->rx_used)) { element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb = list_entry(element, struct iwl3945_rx_mem_buffer, list); + + /* Alloc a new receive buffer */ rxb->skb = alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); if (!rxb->skb) { @@ -4076,8 +4049,19 @@ void iwl_rx_replenish(void *data) * more buffers it will schedule replenish */ break; } + + /* If radiotap head is required, reserve some headroom here. + * The physical head count is a variable rx_stats->phy_count. + * We reserve 4 bytes here. Plus these extra bytes, the + * headroom of the physical head should be enough for the + * radiotap head that iwl3945 supported. See iwl3945_rt. + */ + skb_reserve(rxb->skb, 4); + priv->alloc_rxb_skb++; list_del(element); + + /* Get physical address of RB/SKB */ rxb->dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); @@ -4085,18 +4069,38 @@ void iwl_rx_replenish(void *data) rxq->free_count++; } spin_unlock_irqrestore(&rxq->lock, flags); +} + +/* + * this should be called while priv->lock is locked + */ +static void __iwl3945_rx_replenish(void *data) +{ + struct iwl3945_priv *priv = data; + + iwl3945_rx_allocate(priv); + iwl3945_rx_queue_restock(priv); +} + + +void iwl3945_rx_replenish(void *data) +{ + struct iwl3945_priv *priv = data; + unsigned long flags; + + iwl3945_rx_allocate(priv); spin_lock_irqsave(&priv->lock, flags); - iwl_rx_queue_restock(priv); + iwl3945_rx_queue_restock(priv); spin_unlock_irqrestore(&priv->lock, flags); } /* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to * non NULL it is unmapped and freed */ -void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +static void iwl3945_rx_queue_free(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq) { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { @@ -4113,21 +4117,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rxq->bd = NULL; } -int iwl_rx_queue_alloc(struct iwl_priv *priv) +int iwl3945_rx_queue_alloc(struct iwl3945_priv *priv) { - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl3945_rx_queue *rxq = &priv->rxq; struct pci_dev *dev = priv->pci_dev; int i; spin_lock_init(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); + + /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; @@ -4136,7 +4144,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) return 0; } -void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +void iwl3945_rx_queue_reset(struct iwl3945_priv *priv, struct iwl3945_rx_queue *rxq) { unsigned long flags; int i; @@ -4183,7 +4191,7 @@ static u8 ratio2dB[100] = { /* Calculates a relative dB value from a ratio of linear * (i.e. not dB) signal levels. * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ -int iwl_calc_db_from_ratio(int sig_ratio) +int iwl3945_calc_db_from_ratio(int sig_ratio) { /* Anything above 1000:1 just report as 60 dB */ if (sig_ratio > 1000) @@ -4209,7 +4217,7 @@ int iwl_calc_db_from_ratio(int sig_ratio) /* Calculate an indication of rx signal quality (a percentage, not dBm!). * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info * about formulas used below. */ -int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm) { int sig_qual; int degradation = PERFECT_RSSI - rssi_dbm; @@ -4244,24 +4252,30 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) } /** - * iwl_rx_handle - Main entry function for receiving responses from the uCode + * iwl3945_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. */ -static void iwl_rx_handle(struct iwl_priv *priv) +static void iwl3945_rx_handle(struct iwl3945_priv *priv) { - struct iwl_rx_mem_buffer *rxb; - struct iwl_rx_packet *pkt; - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl3945_rx_mem_buffer *rxb; + struct iwl3945_rx_packet *pkt; + struct iwl3945_rx_queue *rxq = &priv->rxq; u32 r, i; int reclaim; unsigned long flags; + u8 fill_rx = 0; + u32 count = 0; - r = iwl_hw_get_rx_read(priv); + /* uCode's read index (stored in shared DRAM) indicates the last Rx + * buffer that the driver may process (last buffer filled by ucode). */ + r = iwl3945_hw_get_rx_read(priv); i = rxq->read; + if (iwl3945_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; /* Rx interrupt, but nothing sent from uCode */ if (i == r) IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); @@ -4269,7 +4283,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) while (i != r) { rxb = rxq->queue[i]; - /* If an RXB doesn't have a queue slot associated with it + /* 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); @@ -4279,7 +4293,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; + pkt = (struct iwl3945_rx_packet *)rxb->skb->data; /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. @@ -4293,7 +4307,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) /* Based on type of command response or notification, * handle those that need handling via function in - * rx_handlers table. See iwl_setup_rx_handlers() */ + * rx_handlers table. See iwl3945_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d, %s, 0x%02x\n", r, i, @@ -4308,11 +4322,11 @@ static void iwl_rx_handle(struct iwl_priv *priv) } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, - * and fire off the (possibly) blocking iwl_send_cmd() + /* Invoke any callbacks, transfer the skb to caller, and + * fire off the (possibly) blocking iwl3945_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) - iwl_tx_cmd_complete(priv, rxb); + iwl3945_tx_cmd_complete(priv, rxb); else IWL_WARNING("Claim null rxb?\n"); } @@ -4332,15 +4346,28 @@ static void iwl_rx_handle(struct iwl_priv *priv) 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 won't assert. */ + if (fill_rx) { + count++; + if (count >= 8) { + priv->rxq.read = i; + __iwl3945_rx_replenish(priv); + count = 0; + } + } } /* Backtrack one entry */ priv->rxq.read = i; - iwl_rx_queue_restock(priv); + iwl3945_rx_queue_restock(priv); } -int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq) +/** + * iwl3945_tx_queue_update_write_ptr - Send new write index to hardware + */ +static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, + struct iwl3945_tx_queue *txq) { u32 reg = 0; int rc = 0; @@ -4354,41 +4381,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, /* wake up nic if it's powered down ... * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl3945_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); - iwl_set_bit(priv, CSR_GP_CNTRL, + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return rc; } /* restore this queue's parameters in nic hardware. */ - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) return rc; - iwl_write_restricted(priv, HBUS_TARG_WRPTR, - txq->q.first_empty | (txq_id << 8)); - iwl_release_restricted_access(priv); + iwl3945_write_direct32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + iwl3945_release_nic_access(priv); /* else not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ } else - iwl_write32(priv, HBUS_TARG_WRPTR, - txq->q.first_empty | (txq_id << 8)); + iwl3945_write32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); txq->need_update = 0; return rc; } -#ifdef CONFIG_IWLWIFI_DEBUG -static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) +#ifdef CONFIG_IWL3945_DEBUG +static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) { DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl3945_print_hex_dump(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", @@ -4405,24 +4432,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) } #endif -static void iwl_enable_interrupts(struct iwl_priv *priv) +static void iwl3945_enable_interrupts(struct iwl3945_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); + iwl3945_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); } -static inline void iwl_disable_interrupts(struct iwl_priv *priv) +static inline void iwl3945_disable_interrupts(struct iwl3945_priv *priv) { clear_bit(STATUS_INT_ENABLED, &priv->status); /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); + iwl3945_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); + iwl3945_write32(priv, CSR_INT, 0xffffffff); + iwl3945_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); IWL_DEBUG_ISR("Disabled interrupts\n"); } @@ -4449,7 +4476,7 @@ static const char *desc_lookup(int i) #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) -static void iwl_dump_nic_error_log(struct iwl_priv *priv) +static void iwl3945_dump_nic_error_log(struct iwl3945_priv *priv) { u32 i; u32 desc, time, count, base, data1; @@ -4458,18 +4485,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - if (!iwl_hw_valid_rtc_data_addr(base)) { + if (!iwl3945_hw_valid_rtc_data_addr(base)) { IWL_ERROR("Not valid error log pointer 0x%08X\n", base); return; } - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } - count = iwl_read_restricted_mem(priv, base); + count = iwl3945_read_targ_mem(priv, base); if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERROR("Start IWL Error Log Dump:\n"); @@ -4482,19 +4509,19 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) for (i = ERROR_START_OFFSET; i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET; i += ERROR_ELEM_SIZE) { - desc = iwl_read_restricted_mem(priv, base + i); + desc = iwl3945_read_targ_mem(priv, base + i); time = - iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32)); + iwl3945_read_targ_mem(priv, base + i + 1 * sizeof(u32)); blink1 = - iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32)); + iwl3945_read_targ_mem(priv, base + i + 2 * sizeof(u32)); blink2 = - iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32)); + iwl3945_read_targ_mem(priv, base + i + 3 * sizeof(u32)); ilink1 = - iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32)); + iwl3945_read_targ_mem(priv, base + i + 4 * sizeof(u32)); ilink2 = - iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32)); + iwl3945_read_targ_mem(priv, base + i + 5 * sizeof(u32)); data1 = - iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32)); + iwl3945_read_targ_mem(priv, base + i + 6 * sizeof(u32)); IWL_ERROR ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n", @@ -4502,18 +4529,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) ilink1, ilink2, data1); } - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } -#define EVENT_START_OFFSET (4 * sizeof(u32)) +#define EVENT_START_OFFSET (6 * sizeof(u32)) /** - * iwl_print_event_log - Dump error event log to syslog + * iwl3945_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl_grab_restricted_access() already obtained! + * NOTE: Must be called with iwl3945_grab_nic_access() already obtained! */ -static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, +static void iwl3945_print_event_log(struct iwl3945_priv *priv, u32 start_idx, u32 num_events, u32 mode) { u32 i; @@ -4537,21 +4564,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read_restricted_mem(priv, ptr); + ev = iwl3945_read_targ_mem(priv, ptr); ptr += sizeof(u32); - time = iwl_read_restricted_mem(priv, ptr); + time = iwl3945_read_targ_mem(priv, ptr); ptr += sizeof(u32); if (mode == 0) IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ else { - data = iwl_read_restricted_mem(priv, ptr); + data = iwl3945_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); } } } -static void iwl_dump_nic_event_log(struct iwl_priv *priv) +static void iwl3945_dump_nic_event_log(struct iwl3945_priv *priv) { int rc; u32 base; /* SRAM byte address of event log header */ @@ -4562,29 +4589,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 size; /* # entries that we'll print */ base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!iwl_hw_valid_rtc_data_addr(base)) { + if (!iwl3945_hw_valid_rtc_data_addr(base)) { IWL_ERROR("Invalid event log pointer 0x%08X\n", base); return; } - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } /* event log header */ - capacity = iwl_read_restricted_mem(priv, base); - mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32))); + capacity = iwl3945_read_targ_mem(priv, base); + mode = iwl3945_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl3945_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl3945_read_targ_mem(priv, base + (3 * sizeof(u32))); size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ if (size == 0) { IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); return; } @@ -4594,31 +4621,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) /* if uCode has wrapped back to top of log, start at the oldest entry, * i.e the next one that uCode would fill. */ if (num_wraps) - iwl_print_event_log(priv, next_entry, + iwl3945_print_event_log(priv, next_entry, capacity - next_entry, mode); /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); + iwl3945_print_event_log(priv, 0, next_entry, mode); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } /** - * iwl_irq_handle_error - called for HW or SW error interrupt from card + * iwl3945_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl_irq_handle_error(struct iwl_priv *priv) +static void iwl3945_irq_handle_error(struct iwl3945_priv *priv) { - /* Set the FW error flag -- cleared on iwl_down */ + /* Set the FW error flag -- cleared on iwl3945_down */ set_bit(STATUS_FW_ERROR, &priv->status); /* Cancel currently queued command. */ clear_bit(STATUS_HCMD_ACTIVE, &priv->status); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_FW_ERRORS) { - iwl_dump_nic_error_log(priv); - iwl_dump_nic_event_log(priv); - iwl_print_rx_config_cmd(&priv->staging_rxon); +#ifdef CONFIG_IWL3945_DEBUG + if (iwl3945_debug_level & IWL_DL_FW_ERRORS) { + iwl3945_dump_nic_error_log(priv); + iwl3945_dump_nic_event_log(priv); + iwl3945_print_rx_config_cmd(&priv->staging_rxon); } #endif @@ -4632,7 +4659,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv) IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); - if (iwl_is_associated(priv)) { + if (iwl3945_is_associated(priv)) { memcpy(&priv->recovery_rxon, &priv->active_rxon, sizeof(priv->recovery_rxon)); priv->error_recovering = 1; @@ -4641,16 +4668,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv) } } -static void iwl_error_recovery(struct iwl_priv *priv) +static void iwl3945_error_recovery(struct iwl3945_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; - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); - iwl_add_station(priv, priv->bssid, 1, 0); + iwl3945_add_station(priv, priv->bssid, 1, 0); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -4658,12 +4685,12 @@ static void iwl_error_recovery(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl_irq_tasklet(struct iwl_priv *priv) +static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) { u32 inta, handled = 0; u32 inta_fh; unsigned long flags; -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL3945_DEBUG u32 inta_mask; #endif @@ -4672,18 +4699,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* 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); + inta = iwl3945_read32(priv, CSR_INT); + iwl3945_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); + inta_fh = iwl3945_read32(priv, CSR_FH_INT_STATUS); + iwl3945_write32(priv, CSR_FH_INT_STATUS, inta_fh); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ +#ifdef CONFIG_IWL3945_DEBUG + if (iwl3945_debug_level & IWL_DL_ISR) { + /* just for debug */ + inta_mask = iwl3945_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); } @@ -4703,9 +4731,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) IWL_ERROR("Microcode HW error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); + iwl3945_disable_interrupts(priv); - iwl_irq_handle_error(priv); + iwl3945_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -4714,8 +4742,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) return; } -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { +#ifdef CONFIG_IWL3945_DEBUG + if (iwl3945_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_MAC_CLK_ACTV) IWL_DEBUG_ISR("Microcode started or stopped.\n"); @@ -4731,7 +4759,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* HW RF KILL switch toggled (4965 only) */ if (inta & CSR_INT_BIT_RF_KILL) { int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & + if (!(iwl3945_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; @@ -4761,20 +4789,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", inta); - iwl_irq_handle_error(priv); + iwl3945_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_tx_queue_update_write_ptr(priv, &priv->txq[0]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]); + iwl3945_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[0]); + iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[1]); + iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[2]); + iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[3]); + iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[4]); + iwl3945_tx_queue_update_write_ptr(priv, &priv->txq[5]); handled |= CSR_INT_BIT_WAKEUP; } @@ -4783,19 +4811,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * 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); + iwl3945_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"); - iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted(priv, + iwl3945_write32(priv, CSR_FH_INT_STATUS, (1 << 6)); + if (!iwl3945_grab_nic_access(priv)) { + iwl3945_write_direct32(priv, FH_TCSR_CREDIT (ALM_FH_SRVC_CHNL), 0x0); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } handled |= CSR_INT_BIT_FH_TX; } @@ -4810,13 +4838,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - iwl_enable_interrupts(priv); + iwl3945_enable_interrupts(priv); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_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); +#ifdef CONFIG_IWL3945_DEBUG + if (iwl3945_debug_level & (IWL_DL_ISR)) { + inta = iwl3945_read32(priv, CSR_INT); + inta_mask = iwl3945_read32(priv, CSR_INT_MASK); + inta_fh = iwl3945_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); } @@ -4824,9 +4852,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static irqreturn_t iwl_isr(int irq, void *data) +static irqreturn_t iwl3945_isr(int irq, void *data) { - struct iwl_priv *priv = data; + struct iwl3945_priv *priv = data; u32 inta, inta_mask; u32 inta_fh; if (!priv) @@ -4838,12 +4866,12 @@ static irqreturn_t iwl_isr(int irq, void *data) * 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); + inta_mask = iwl3945_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl3945_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); + inta = iwl3945_read32(priv, CSR_INT); + inta_fh = iwl3945_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, @@ -4862,7 +4890,7 @@ static irqreturn_t iwl_isr(int irq, void *data) IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); - /* iwl_irq_tasklet() will service interrupts and re-enable them */ + /* iwl3945_irq_tasklet() will service interrupts and re-enable them */ tasklet_schedule(&priv->irq_tasklet); unplugged: spin_unlock(&priv->lock); @@ -4871,18 +4899,18 @@ unplugged: none: /* re-enable interrupts here since we don't have anything to service. */ - iwl_enable_interrupts(priv); + iwl3945_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } /************************** EEPROM BANDS **************************** * - * The iwl_eeprom_band definitions below provide the mapping from the + * The iwl3945_eeprom_band definitions below provide the mapping from the * EEPROM contents to the specific channel number supported for each * band. * - * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * For example, iwl3945_priv->eeprom.band_3_channels[4] from the band_3 * definition below maps to physical channel 42 in the 5.2GHz spectrum. * The specific geography and calibration information for that channel * is contained in the eeprom map itself. @@ -4908,58 +4936,58 @@ unplugged: *********************************************************************/ /* 2.4 GHz */ -static const u8 iwl_eeprom_band_1[14] = { +static const u8 iwl3945_eeprom_band_1[14] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; /* 5.2 GHz bands */ -static const u8 iwl_eeprom_band_2[] = { +static const u8 iwl3945_eeprom_band_2[] = { /* 4915-5080MHz */ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 }; -static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */ +static const u8 iwl3945_eeprom_band_3[] = { /* 5170-5320MHz */ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 }; -static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ +static const u8 iwl3945_eeprom_band_4[] = { /* 5500-5700MHz */ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 }; -static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ +static const u8 iwl3945_eeprom_band_5[] = { /* 5725-5825MHz */ 145, 149, 153, 157, 161, 165 }; -static void iwl_init_band_reference(const struct iwl_priv *priv, int band, +static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int band, int *eeprom_ch_count, - const struct iwl_eeprom_channel + const struct iwl3945_eeprom_channel **eeprom_ch_info, const u8 **eeprom_ch_index) { switch (band) { case 1: /* 2.4GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_1); *eeprom_ch_info = priv->eeprom.band_1_channels; - *eeprom_ch_index = iwl_eeprom_band_1; + *eeprom_ch_index = iwl3945_eeprom_band_1; break; - case 2: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + case 2: /* 4.9GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_2); *eeprom_ch_info = priv->eeprom.band_2_channels; - *eeprom_ch_index = iwl_eeprom_band_2; + *eeprom_ch_index = iwl3945_eeprom_band_2; break; case 3: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_3); *eeprom_ch_info = priv->eeprom.band_3_channels; - *eeprom_ch_index = iwl_eeprom_band_3; + *eeprom_ch_index = iwl3945_eeprom_band_3; break; - case 4: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + case 4: /* 5.5GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_4); *eeprom_ch_info = priv->eeprom.band_4_channels; - *eeprom_ch_index = iwl_eeprom_band_4; + *eeprom_ch_index = iwl3945_eeprom_band_4; break; - case 5: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + case 5: /* 5.7GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl3945_eeprom_band_5); *eeprom_ch_info = priv->eeprom.band_5_channels; - *eeprom_ch_index = iwl_eeprom_band_5; + *eeprom_ch_index = iwl3945_eeprom_band_5; break; default: BUG(); @@ -4967,7 +4995,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band, } } -const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, +/** + * iwl3945_get_channel_info - Find driver's private channel info + * + * Based on band and channel number. + */ +const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv, int phymode, u16 channel) { int i; @@ -4994,13 +5027,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") -static int iwl_init_channel_map(struct iwl_priv *priv) +/** + * iwl3945_init_channel_map - Set up driver's info for all possible channels + */ +static int iwl3945_init_channel_map(struct iwl3945_priv *priv) { int eeprom_ch_count = 0; const u8 *eeprom_ch_index = NULL; - const struct iwl_eeprom_channel *eeprom_ch_info = NULL; + const struct iwl3945_eeprom_channel *eeprom_ch_info = NULL; int band, ch; - struct iwl_channel_info *ch_info; + struct iwl3945_channel_info *ch_info; if (priv->channel_count) { IWL_DEBUG_INFO("Channel map already initialized.\n"); @@ -5016,15 +5052,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv) IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); priv->channel_count = - ARRAY_SIZE(iwl_eeprom_band_1) + - ARRAY_SIZE(iwl_eeprom_band_2) + - ARRAY_SIZE(iwl_eeprom_band_3) + - ARRAY_SIZE(iwl_eeprom_band_4) + - ARRAY_SIZE(iwl_eeprom_band_5); + ARRAY_SIZE(iwl3945_eeprom_band_1) + + ARRAY_SIZE(iwl3945_eeprom_band_2) + + ARRAY_SIZE(iwl3945_eeprom_band_3) + + ARRAY_SIZE(iwl3945_eeprom_band_4) + + ARRAY_SIZE(iwl3945_eeprom_band_5); IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); - priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_info = kzalloc(sizeof(struct iwl3945_channel_info) * priv->channel_count, GFP_KERNEL); if (!priv->channel_info) { IWL_ERROR("Could not allocate channel_info\n"); @@ -5039,7 +5075,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv) * what just in the EEPROM) */ for (band = 1; band <= 5; band++) { - iwl_init_band_reference(priv, band, &eeprom_ch_count, + iwl3945_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); /* Loop through each band adding each of the channels */ @@ -5103,6 +5139,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv) } } + /* Set up txpower settings in driver for all channels */ if (iwl3945_txpower_set_from_eeprom(priv)) return -EIO; @@ -5132,7 +5169,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) +static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode) { if (phymode == MODE_IEEE80211A) return IWL_ACTIVE_DWELL_TIME_52; @@ -5140,14 +5177,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) +static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode) { - u16 active = iwl_get_active_dwell_time(priv, phymode); + u16 active = iwl3945_get_active_dwell_time(priv, phymode); u16 passive = (phymode != MODE_IEEE80211A) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; - if (iwl_is_associated(priv)) { + if (iwl3945_is_associated(priv)) { /* If we're associated, we clamp the maximum passive * dwell time to be 98% of the beacon interval (minus * 2 * channel tune time) */ @@ -5163,30 +5200,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) return passive; } -static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, +static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, u8 is_active, u8 direct_mask, - struct iwl_scan_channel *scan_ch) + struct iwl3945_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; const struct ieee80211_hw_mode *hw_mode; - const struct iwl_channel_info *ch_info; + const struct iwl3945_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl_get_hw_mode(priv, phymode); + hw_mode = iwl3945_get_hw_mode(priv, phymode); if (!hw_mode) return 0; channels = hw_mode->channels; - active_dwell = iwl_get_active_dwell_time(priv, phymode); - passive_dwell = iwl_get_passive_dwell_time(priv, phymode); + active_dwell = iwl3945_get_active_dwell_time(priv, phymode); + passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode); for (i = 0, added = 0; i < hw_mode->num_channels; i++) { if (channels[i].chan == le16_to_cpu(priv->active_rxon.channel)) { - if (iwl_is_associated(priv)) { + if (iwl3945_is_associated(priv)) { IWL_DEBUG_SCAN ("Skipping current channel %d\n", le16_to_cpu(priv->active_rxon.channel)); @@ -5197,7 +5234,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, scan_ch->channel = channels[i].chan; - ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel); + ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", scan_ch->channel); @@ -5219,7 +5256,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* Set power levels to defaults */ + /* Set txpower levels to defaults */ scan_ch->tpc.dsp_atten = 110; /* scan_pwr_info->tpc.dsp_atten; */ @@ -5229,8 +5266,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level - scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + * power level: + * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3; */ } @@ -5248,7 +5285,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, return added; } -static void iwl_reset_channel_flag(struct iwl_priv *priv) +static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv) { int i, j; for (i = 0; i < 3; i++) { @@ -5258,13 +5295,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv) } } -static void iwl_init_hw_rates(struct iwl_priv *priv, +static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl_rates[i].ieee * 5; + rates[i].rate = iwl3945_rates[i].ieee * 5; rates[i].val = i; /* Rate scaling will work on indexes */ rates[i].val2 = i; rates[i].flags = IEEE80211_RATE_SUPPORTED; @@ -5276,7 +5313,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv, * If CCK 1M then set rate flag to CCK else CCK_2 * which is CCK | PREAMBLE2 */ - rates[i].flags |= (iwl_rates[i].plcp == 10) ? + rates[i].flags |= (iwl3945_rates[i].plcp == 10) ? IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; } @@ -5287,11 +5324,11 @@ static void iwl_init_hw_rates(struct iwl_priv *priv, } /** - * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + * iwl3945_init_geos - Initialize mac80211's geo/channel info based from eeprom */ -static int iwl_init_geos(struct iwl_priv *priv) +static int iwl3945_init_geos(struct iwl3945_priv *priv) { - struct iwl_channel_info *ch; + struct iwl3945_channel_info *ch; struct ieee80211_hw_mode *modes; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; @@ -5337,7 +5374,7 @@ static int iwl_init_geos(struct iwl_priv *priv) /* 5.2GHz channels start after the 2.4GHz channels */ modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; modes[A].rates = &rates[4]; modes[A].num_rates = 8; /* just OFDM */ modes[A].num_channels = 0; @@ -5357,7 +5394,7 @@ static int iwl_init_geos(struct iwl_priv *priv) priv->ieee_channels = channels; priv->ieee_rates = rates; - iwl_init_hw_rates(priv, rates); + iwl3945_init_hw_rates(priv, rates); for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { ch = &priv->channel_info[i]; @@ -5440,57 +5477,21 @@ static int iwl_init_geos(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl3945_dealloc_ucode_pci(struct iwl3945_priv *priv) { - if (priv->ucode_code.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_code.len, - priv->ucode_code.v_addr, - priv->ucode_code.p_addr); - priv->ucode_code.v_addr = NULL; - } - if (priv->ucode_data.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_data.len, - priv->ucode_data.v_addr, - priv->ucode_data.p_addr); - priv->ucode_data.v_addr = NULL; - } - if (priv->ucode_data_backup.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_data_backup.len, - priv->ucode_data_backup.v_addr, - priv->ucode_data_backup.p_addr); - priv->ucode_data_backup.v_addr = NULL; - } - if (priv->ucode_init.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_init.len, - priv->ucode_init.v_addr, - priv->ucode_init.p_addr); - priv->ucode_init.v_addr = NULL; - } - if (priv->ucode_init_data.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_init_data.len, - priv->ucode_init_data.v_addr, - priv->ucode_init_data.p_addr); - priv->ucode_init_data.v_addr = NULL; - } - if (priv->ucode_boot.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_boot.len, - priv->ucode_boot.v_addr, - priv->ucode_boot.p_addr); - priv->ucode_boot.v_addr = NULL; - } + 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); } /** - * iwl_verify_inst_full - verify runtime uCode image in card vs. host, + * iwl3945_verify_inst_full - verify runtime uCode image in card vs. host, * looking at all data. */ -static int iwl_verify_inst_full(struct iwl_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; @@ -5499,18 +5500,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) return rc; - iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); errcnt = 0; for (; len > 0; len -= sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + val = _iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERROR("uCode INST section is invalid at " "offset 0x%x, is 0x%x, s/b 0x%x\n", @@ -5522,22 +5523,21 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) } } - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); if (!errcnt) - IWL_DEBUG_INFO - ("ucode image in INSTRUCTION memory is good\n"); + IWL_DEBUG_INFO("ucode image in INSTRUCTION memory is good\n"); return rc; } /** - * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * iwl3945_verify_inst_sparse - verify runtime uCode image in card vs. host, * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +static int iwl3945_verify_inst_sparse(struct iwl3945_priv *priv, __le32 *image, u32 len) { u32 val; int rc = 0; @@ -5546,7 +5546,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) return rc; @@ -5554,9 +5554,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, + iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + RTC_INST_LOWER_BOUND); - val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + val = _iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { #if 0 /* Enable this if you want to see details */ IWL_ERROR("uCode INST section is invalid at " @@ -5570,17 +5570,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) } } - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); return rc; } /** - * iwl_verify_ucode - determine which instruction image is in SRAM, + * iwl3945_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_priv *priv) +static int iwl3945_verify_ucode(struct iwl3945_priv *priv) { __le32 *image; u32 len; @@ -5589,7 +5589,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv) /* Try bootstrap */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; - rc = iwl_verify_inst_sparse(priv, image, len); + rc = iwl3945_verify_inst_sparse(priv, image, len); if (rc == 0) { IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); return 0; @@ -5598,7 +5598,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv) /* Try initialize */ image = (__le32 *)priv->ucode_init.v_addr; len = priv->ucode_init.len; - rc = iwl_verify_inst_sparse(priv, image, len); + rc = iwl3945_verify_inst_sparse(priv, image, len); if (rc == 0) { IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); return 0; @@ -5607,7 +5607,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv) /* Try runtime/protocol */ image = (__le32 *)priv->ucode_code.v_addr; len = priv->ucode_code.len; - rc = iwl_verify_inst_sparse(priv, image, len); + rc = iwl3945_verify_inst_sparse(priv, image, len); if (rc == 0) { IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); return 0; @@ -5615,18 +5615,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv) IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - /* Show first several data entries in instruction SRAM. - * Selection of bootstrap image is arbitrary. */ + /* Since nothing seems to match, show first several data entries in + * instruction SRAM, so maybe visual inspection will give a clue. + * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; - rc = iwl_verify_inst_full(priv, image, len); + rc = iwl3945_verify_inst_full(priv, image, len); return rc; } /* check contents of special bootstrap uCode SRAM */ -static int iwl_verify_bsm(struct iwl_priv *priv) +static int iwl3945_verify_bsm(struct iwl3945_priv *priv) { __le32 *image = priv->ucode_boot.v_addr; u32 len = priv->ucode_boot.len; @@ -5636,11 +5637,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO("Begin verify bsm\n"); /* verify BSM SRAM contents */ - val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG); + 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 ++) { - val = iwl_read_restricted_reg(priv, reg); + val = iwl3945_read_prph(priv, reg); if (val != le32_to_cpu(*image)) { IWL_ERROR("BSM uCode verification failed at " "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", @@ -5657,7 +5658,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv) } /** - * iwl_load_bsm - Load bootstrap instructions + * iwl3945_load_bsm - Load bootstrap instructions * * BSM operation: * @@ -5688,7 +5689,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv) * the runtime uCode instructions and the backup data cache into SRAM, * and re-launches the runtime uCode from where it left off. */ -static int iwl_load_bsm(struct iwl_priv *priv) +static int iwl3945_load_bsm(struct iwl3945_priv *priv) { __le32 *image = priv->ucode_boot.v_addr; u32 len = priv->ucode_boot.len; @@ -5708,8 +5709,8 @@ static int iwl_load_bsm(struct iwl_priv *priv) return -EINVAL; /* Tell bootstrap uCode where to find the "Initialize" uCode - * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. - * NOTE: iwl_initialize_alive_start() will replace these values, + * in host DRAM ... host DRAM physical address bits 31:0 for 3945. + * NOTE: iwl3945_initialize_alive_start() will replace these values, * after the "initialize" uCode has run, to point to * runtime/protocol instructions and backup data cache. */ pinst = priv->ucode_init.p_addr; @@ -5717,42 +5718,42 @@ static int iwl_load_bsm(struct iwl_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) return rc; - iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + iwl3945_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl3945_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); /* Fill BSM memory with bootstrap instructions */ for (reg_offset = BSM_SRAM_LOWER_BOUND; reg_offset < BSM_SRAM_LOWER_BOUND + len; reg_offset += sizeof(u32), image++) - _iwl_write_restricted_reg(priv, reg_offset, + _iwl3945_write_prph(priv, reg_offset, le32_to_cpu(*image)); - rc = iwl_verify_bsm(priv); + rc = iwl3945_verify_bsm(priv); if (rc) { - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); return rc; } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ - iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0); - iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG, + iwl3945_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl3945_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND); - iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + iwl3945_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); /* Load bootstrap code into instruction SRAM now, * to prepare to load "initialize" uCode */ - iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + iwl3945_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START); /* Wait for load of bootstrap uCode to finish */ for (i = 0; i < 100; i++) { - done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG); + done = iwl3945_read_prph(priv, BSM_WR_CTRL_REG); if (!(done & BSM_WR_CTRL_REG_BIT_START)) break; udelay(10); @@ -5766,29 +5767,29 @@ static int iwl_load_bsm(struct iwl_priv *priv) /* Enable future boot loads whenever power management unit triggers it * (e.g. when powering back up after power-save shutdown) */ - iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + iwl3945_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); return 0; } -static void iwl_nic_start(struct iwl_priv *priv) +static void iwl3945_nic_start(struct iwl3945_priv *priv) { /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl3945_write32(priv, CSR_RESET, 0); } /** - * iwl_read_ucode - Read uCode images from disk file. + * iwl3945_read_ucode - Read uCode images from disk file. * * Copy into buffers for card to fetch via bus-mastering */ -static int iwl_read_ucode(struct iwl_priv *priv) +static int iwl3945_read_ucode(struct iwl3945_priv *priv) { - struct iwl_ucode *ucode; - int rc = 0; + struct iwl3945_ucode *ucode; + int ret = 0; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode"; @@ -5798,9 +5799,10 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (rc < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + 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; } @@ -5810,7 +5812,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { IWL_ERROR("File size way too small!\n"); - rc = -EINVAL; + ret = -EINVAL; goto err_release; } @@ -5825,16 +5827,11 @@ static int iwl_read_ucode(struct iwl_priv *priv) 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); + 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) + @@ -5843,43 +5840,40 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO("uCode file size %d too small\n", (int)ucode_raw->size); - rc = -EINVAL; + ret = -EINVAL; goto err_release; } /* Verify that uCode images will fit in card's SRAM */ if (inst_size > IWL_MAX_INST_SIZE) { - IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", - (int)inst_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", + inst_size); + ret = -EINVAL; goto err_release; } if (data_size > IWL_MAX_DATA_SIZE) { - IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", - (int)data_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", + data_size); + ret = -EINVAL; goto err_release; } if (init_size > IWL_MAX_INST_SIZE) { - IWL_DEBUG_INFO - ("uCode init instr len %d too large to fit in card\n", - (int)init_size); - rc = -EINVAL; + 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 > IWL_MAX_DATA_SIZE) { - IWL_DEBUG_INFO - ("uCode init data len %d too large to fit in card\n", - (int)init_data_size); - rc = -EINVAL; + 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 > IWL_MAX_BSM_SIZE) { - IWL_DEBUG_INFO - ("uCode boot instr len %d too large to fit in bsm\n", - (int)boot_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode boot instr len %d too large to fit in\n", + boot_size); + ret = -EINVAL; goto err_release; } @@ -5889,66 +5883,54 @@ static int iwl_read_ucode(struct iwl_priv *priv) * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ priv->ucode_code.len = inst_size; - priv->ucode_code.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_code.len, - &(priv->ucode_code.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); priv->ucode_data.len = data_size; - priv->ucode_data.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_data.len, - &(priv->ucode_data.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); priv->ucode_data_backup.len = data_size; - priv->ucode_data_backup.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_data_backup.len, - &(priv->ucode_data_backup.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); + if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || + !priv->ucode_data_backup.v_addr) + goto err_pci_alloc; /* Initialization instructions and data */ - priv->ucode_init.len = init_size; - priv->ucode_init.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_init.len, - &(priv->ucode_init.p_addr)); - - priv->ucode_init_data.len = init_data_size; - priv->ucode_init_data.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_init_data.len, - &(priv->ucode_init_data.p_addr)); + 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) */ - priv->ucode_boot.len = boot_size; - priv->ucode_boot.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_boot.len, - &(priv->ucode_boot.p_addr)); + if (boot_size) { + priv->ucode_boot.len = boot_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || - !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) - goto err_pci_alloc; + 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 %d\n", - (int)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 iwl_up() */ + * NOTE: Copy into backup buffer will be done in iwl3945_up() */ src = &ucode->data[inst_size]; len = priv->ucode_data.len; - IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n", - (int)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); @@ -5956,8 +5938,8 @@ static int iwl_read_ucode(struct iwl_priv *priv) 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 %d\n", - (int)len); + IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", + len); memcpy(priv->ucode_init.v_addr, src, len); } @@ -5983,19 +5965,19 @@ static int iwl_read_ucode(struct iwl_priv *priv) err_pci_alloc: IWL_ERROR("failed to allocate pci memory\n"); - rc = -ENOMEM; - iwl_dealloc_ucode_pci(priv); + ret = -ENOMEM; + iwl3945_dealloc_ucode_pci(priv); err_release: release_firmware(ucode_raw); error: - return rc; + return ret; } /** - * iwl_set_ucode_ptrs - Set uCode address location + * iwl3945_set_ucode_ptrs - Set uCode address location * * Tell initialization uCode where to find runtime uCode. * @@ -6003,7 +5985,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) * We need to replace them to load runtime uCode inst and data, * and to save runtime data when powering down. */ -static int iwl_set_ucode_ptrs(struct iwl_priv *priv) +static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; @@ -6015,24 +5997,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv) pdata = priv->ucode_data_backup.p_addr; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } /* Tell bootstrap uCode where to find image to load */ - iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + iwl3945_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl3945_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); /* Inst bytecount must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ - iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, + iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -6042,17 +6024,13 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv) } /** - * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved + * iwl3945_init_alive_start - Called after REPLY_ALIVE notification received * * Called after REPLY_ALIVE notification received from "initialize" uCode. * - * The 4965 "initialize" ALIVE reply contains calibration data for: - * Voltage, temperature, and MIMO tx gain correction, now stored in priv - * (3945 does not contain this data). - * * Tell "initialize" uCode to go ahead and load the runtime uCode. -*/ -static void iwl_init_alive_start(struct iwl_priv *priv) + */ +static void iwl3945_init_alive_start(struct iwl3945_priv *priv) { /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { @@ -6065,7 +6043,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv) /* Bootstrap uCode has loaded initialize uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { + if (iwl3945_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); @@ -6076,7 +6054,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv) * load and launch runtime uCode, which will send us another "Alive" * notification. */ IWL_DEBUG_INFO("Initialization Alive received.\n"); - if (iwl_set_ucode_ptrs(priv)) { + if (iwl3945_set_ucode_ptrs(priv)) { /* Runtime instruction load won't happen; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); @@ -6090,11 +6068,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv) /** - * iwl_alive_start - called after REPLY_ALIVE notification received + * iwl3945_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's - * Alive gets handled by iwl_init_alive_start()). + * Alive gets handled by iwl3945_init_alive_start()). */ -static void iwl_alive_start(struct iwl_priv *priv) +static void iwl3945_alive_start(struct iwl3945_priv *priv) { int rc = 0; int thermal_spin = 0; @@ -6112,30 +6090,30 @@ static void iwl_alive_start(struct iwl_priv *priv) /* 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)) { + if (iwl3945_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); + iwl3945_clear_stations_table(priv); - rc = iwl_grab_restricted_access(priv); + rc = iwl3945_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read rfkill status from adapter\n"); return; } - rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG); + rfkill = iwl3945_read_prph(priv, APMG_RFKILL_REG); IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); if (rfkill & 0x1) { clear_bit(STATUS_RF_KILL_HW, &priv->status); /* if rfkill is not on, then wait for thermal * sensor in adapter to kick in */ - while (iwl_hw_get_temperature(priv) == 0) { + while (iwl3945_hw_get_temperature(priv) == 0) { thermal_spin++; udelay(10); } @@ -6146,68 +6124,49 @@ static void iwl_alive_start(struct iwl_priv *priv) } else set_bit(STATUS_RF_KILL_HW, &priv->status); - /* After the ALIVE response, we can process host commands */ + /* After the ALIVE response, we can send commands to 3945 uCode */ set_bit(STATUS_ALIVE, &priv->status); /* Clear out the uCode error bit if it is set */ clear_bit(STATUS_FW_ERROR, &priv->status); - rc = iwl_init_channel_map(priv); + rc = iwl3945_init_channel_map(priv); if (rc) { IWL_ERROR("initializing regulatory failed: %d\n", rc); return; } - iwl_init_geos(priv); + iwl3945_init_geos(priv); + iwl3945_reset_channel_flag(priv); - if (iwl_is_rfkill(priv)) + if (iwl3945_is_rfkill(priv)) return; - if (!priv->mac80211_registered) { - /* Unlock so any user space entry points can call back into - * the driver without a deadlock... */ - mutex_unlock(&priv->mutex); - iwl_rate_control_register(priv->hw); - rc = ieee80211_register_hw(priv->hw); - priv->hw->conf.beacon_int = 100; - mutex_lock(&priv->mutex); - - if (rc) { - iwl_rate_control_unregister(priv->hw); - IWL_ERROR("Failed to register network " - "device (error %d)\n", rc); - return; - } - - priv->mac80211_registered = 1; - - iwl_reset_channel_flag(priv); - } else - ieee80211_start_queues(priv->hw); + ieee80211_start_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); + iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); - if (iwl_is_associated(priv)) { - struct iwl_rxon_cmd *active_rxon = - (struct iwl_rxon_cmd *)(&priv->active_rxon); + if (iwl3945_is_associated(priv)) { + struct iwl3945_rxon_cmd *active_rxon = + (struct iwl3945_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 */ - iwl_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } - /* Configure BT coexistence */ - iwl_send_bt_config(priv); + /* Configure Bluetooth device coexistence support */ + iwl3945_send_bt_config(priv); /* Configure the adapter for unassociated operation */ - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ priv->notif_missed_beacons = 0; @@ -6216,9 +6175,10 @@ static void iwl_alive_start(struct iwl_priv *priv) iwl3945_reg_txpower_periodic(priv); IWL_DEBUG_INFO("ALIVE processing complete.\n"); + wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) - iwl_error_recovery(priv); + iwl3945_error_recovery(priv); return; @@ -6226,9 +6186,9 @@ static void iwl_alive_start(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->restart); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv); +static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv); -static void __iwl_down(struct iwl_priv *priv) +static void __iwl3945_down(struct iwl3945_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); @@ -6241,7 +6201,7 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_clear_stations_table(priv); + iwl3945_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -6252,17 +6212,17 @@ static void __iwl_down(struct iwl_priv *priv) 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); + iwl3945_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); /* tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); + iwl3945_disable_interrupts(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl_init() then + /* If we have not previously called iwl3945_init() then * clear all bits but the RF Kill and SUSPEND bits and return */ - if (!iwl_is_init(priv)) { + if (!iwl3945_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) << @@ -6284,51 +6244,50 @@ static void __iwl_down(struct iwl_priv *priv) STATUS_FW_ERROR; spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl3945_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock_irqrestore(&priv->lock, flags); - iwl_hw_txq_ctx_stop(priv); - iwl_hw_rxq_stop(priv); + iwl3945_hw_txq_ctx_stop(priv); + iwl3945_hw_rxq_stop(priv); spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + if (!iwl3945_grab_nic_access(priv)) { + iwl3945_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_restricted_access(priv); + iwl3945_release_nic_access(priv); } spin_unlock_irqrestore(&priv->lock, flags); udelay(5); - iwl_hw_nic_stop_master(priv); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - iwl_hw_nic_reset(priv); + iwl3945_hw_nic_stop_master(priv); + iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl3945_hw_nic_reset(priv); exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + memset(&priv->card_alive, 0, sizeof(struct iwl3945_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); + iwl3945_clear_free_frames(priv); } -static void iwl_down(struct iwl_priv *priv) +static void iwl3945_down(struct iwl3945_priv *priv) { mutex_lock(&priv->mutex); - __iwl_down(priv); + __iwl3945_down(priv); mutex_unlock(&priv->mutex); - iwl_cancel_deferred_work(priv); + iwl3945_cancel_deferred_work(priv); } #define MAX_HW_RESTARTS 5 -static int __iwl_up(struct iwl_priv *priv) +static int __iwl3945_up(struct iwl3945_priv *priv) { - DECLARE_MAC_BUF(mac); int rc, i; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { @@ -6339,44 +6298,65 @@ static int __iwl_up(struct iwl_priv *priv) if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { IWL_WARNING("Radio disabled by SW RF kill (module " "parameter)\n"); - return 0; + return -ENODEV; } - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl3945_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_WARNING("Radio disabled by HW RF Kill switch\n"); + return -ENODEV; + } + } - rc = iwl_hw_nic_init(priv); + if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { + IWL_ERROR("ucode not available for device bringup\n"); + return -EIO; + } + + iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); + + rc = iwl3945_hw_nic_init(priv); if (rc) { IWL_ERROR("Unable to int nic\n"); return rc; } /* 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, + iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl3945_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); - iwl_enable_interrupts(priv); + iwl3945_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl3945_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); + iwl3945_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl3945_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); + 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)) + return 0; for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl_clear_stations_table(priv); + iwl3945_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, * prepare to load the "initialize" uCode */ - rc = iwl_load_bsm(priv); + rc = iwl3945_load_bsm(priv); if (rc) { IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc); @@ -6384,14 +6364,7 @@ static int __iwl_up(struct iwl_priv *priv) } /* start card; "initialize" will load runtime ucode */ - iwl_nic_start(priv); - - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_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); + iwl3945_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -6399,7 +6372,7 @@ static int __iwl_up(struct iwl_priv *priv) } set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl_down(priv); + __iwl3945_down(priv); /* tried to restart and config the device for as long as our * patience could withstand */ @@ -6414,35 +6387,35 @@ static int __iwl_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl_bg_init_alive_start(struct work_struct *data) +static void iwl3945_bg_init_alive_start(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); + struct iwl3945_priv *priv = + container_of(data, struct iwl3945_priv, init_alive_start.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_init_alive_start(priv); + iwl3945_init_alive_start(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_alive_start(struct work_struct *data) +static void iwl3945_bg_alive_start(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); + struct iwl3945_priv *priv = + container_of(data, struct iwl3945_priv, alive_start.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_alive_start(priv); + iwl3945_alive_start(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_rf_kill(struct work_struct *work) +static void iwl3945_bg_rf_kill(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv, rf_kill); wake_up_interruptible(&priv->wait_command_queue); @@ -6451,7 +6424,7 @@ static void iwl_bg_rf_kill(struct work_struct *work) mutex_lock(&priv->mutex); - if (!iwl_is_rfkill(priv)) { + if (!iwl3945_is_rfkill(priv)) { IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, "HW and/or SW RF Kill no longer active, restarting " "device\n"); @@ -6472,10 +6445,10 @@ static void iwl_bg_rf_kill(struct work_struct *work) #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) -static void iwl_bg_scan_check(struct work_struct *data) +static void iwl3945_bg_scan_check(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, scan_check.work); + struct iwl3945_priv *priv = + container_of(data, struct iwl3945_priv, scan_check.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6488,22 +6461,22 @@ static void iwl_bg_scan_check(struct work_struct *data) jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - iwl_send_scan_abort(priv); + iwl3945_send_scan_abort(priv); } mutex_unlock(&priv->mutex); } -static void iwl_bg_request_scan(struct work_struct *data) +static void iwl3945_bg_request_scan(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, request_scan); - struct iwl_host_cmd cmd = { + struct iwl3945_priv *priv = + container_of(data, struct iwl3945_priv, request_scan); + struct iwl3945_host_cmd cmd = { .id = REPLY_SCAN_CMD, - .len = sizeof(struct iwl_scan_cmd), + .len = sizeof(struct iwl3945_scan_cmd), .meta.flags = CMD_SIZE_HUGE, }; int rc = 0; - struct iwl_scan_cmd *scan; + struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u8 direct_mask; int phymode; @@ -6512,7 +6485,7 @@ static void iwl_bg_request_scan(struct work_struct *data) mutex_lock(&priv->mutex); - if (!iwl_is_ready(priv)) { + if (!iwl3945_is_ready(priv)) { IWL_WARNING("request scan called when driver not ready.\n"); goto done; } @@ -6541,7 +6514,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } - if (iwl_is_rfkill(priv)) { + if (iwl3945_is_rfkill(priv)) { IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); goto done; } @@ -6557,7 +6530,7 @@ static void iwl_bg_request_scan(struct work_struct *data) } if (!priv->scan) { - priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + priv->scan = kmalloc(sizeof(struct iwl3945_scan_cmd) + IWL_MAX_SCAN_SIZE, GFP_KERNEL); if (!priv->scan) { rc = -ENOMEM; @@ -6565,12 +6538,12 @@ static void iwl_bg_request_scan(struct work_struct *data) } } scan = priv->scan; - memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + memset(scan, 0, sizeof(struct iwl3945_scan_cmd) + IWL_MAX_SCAN_SIZE); scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - if (iwl_is_associated(priv)) { + if (iwl3945_is_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; @@ -6607,14 +6580,14 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->one_direct_scan) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s'\n", - iwl_escape_essid(priv->direct_ssid, + iwl3945_escape_essid(priv->direct_ssid, priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); direct_mask = 1; - } else if (!iwl_is_associated(priv) && priv->essid_len) { + } else if (!iwl3945_is_associated(priv) && priv->essid_len) { scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); @@ -6625,7 +6598,7 @@ static void iwl_bg_request_scan(struct work_struct *data) /* We don't build a direct scan probe request; the uCode will do * that based on the direct_mask added to each channel entry */ scan->tx_cmd.len = cpu_to_le16( - iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, + iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; @@ -6661,23 +6634,23 @@ static void iwl_bg_request_scan(struct work_struct *data) if (direct_mask) IWL_DEBUG_SCAN ("Initiating direct scan for %s.\n", - iwl_escape_essid(priv->essid, priv->essid_len)); + iwl3945_escape_essid(priv->essid, priv->essid_len)); else IWL_DEBUG_SCAN("Initiating indirect scan.\n"); scan->channel_count = - iwl_get_channels_for_scan( + iwl3945_get_channels_for_scan( priv, phymode, 1, /* active */ direct_mask, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); cmd.len += le16_to_cpu(scan->tx_cmd.len) + - scan->channel_count * sizeof(struct iwl_scan_channel); + scan->channel_count * sizeof(struct iwl3945_scan_channel); cmd.data = scan; scan->len = cpu_to_le16(cmd.len); set_bit(STATUS_SCAN_HW, &priv->status); - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl3945_send_cmd_sync(priv, &cmd); if (rc) goto done; @@ -6688,50 +6661,52 @@ static void iwl_bg_request_scan(struct work_struct *data) return; done: - /* inform mac80211 sacn aborted */ + /* inform mac80211 scan aborted */ queue_work(priv->workqueue, &priv->scan_completed); mutex_unlock(&priv->mutex); } -static void iwl_bg_up(struct work_struct *data) +static void iwl3945_bg_up(struct work_struct *data) { - struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, up); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - __iwl_up(priv); + __iwl3945_up(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_restart(struct work_struct *data) +static void iwl3945_bg_restart(struct work_struct *data) { - struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, restart); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl_down(priv); + iwl3945_down(priv); queue_work(priv->workqueue, &priv->up); } -static void iwl_bg_rx_replenish(struct work_struct *data) +static void iwl3945_bg_rx_replenish(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, rx_replenish); + struct iwl3945_priv *priv = + container_of(data, struct iwl3945_priv, rx_replenish); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_rx_replenish(priv); + iwl3945_rx_replenish(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_post_associate(struct work_struct *data) +#define IWL_DELAY_NEXT_SCAN (HZ*2) + +static void iwl3945_bg_post_associate(struct work_struct *data) { - struct iwl_priv *priv = container_of(data, struct iwl_priv, + struct iwl3945_priv *priv = container_of(data, struct iwl3945_priv, post_associate.work); int rc = 0; @@ -6753,20 +6728,20 @@ static void iwl_bg_post_associate(struct work_struct *data) mutex_lock(&priv->mutex); - if (!priv->interface_id || !priv->is_open) { + if (!priv->vif || !priv->is_open) { mutex_unlock(&priv->mutex); return; } - iwl_scan_cancel_timeout(priv, 200); + iwl3945_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); - memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl_setup_rxon_timing(priv); - rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + memset(&priv->rxon_timing, 0, sizeof(struct iwl3945_rxon_time_cmd)); + iwl3945_setup_rxon_timing(priv); + rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (rc) IWL_WARNING("REPLY_RXON_TIMING failed - " @@ -6795,75 +6770,81 @@ static void iwl_bg_post_associate(struct work_struct *data) } - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); switch (priv->iw_mode) { case IEEE80211_IF_TYPE_STA: - iwl_rate_scale_init(priv->hw, IWL_AP_ID); + iwl3945_rate_scale_init(priv->hw, IWL_AP_ID); break; case IEEE80211_IF_TYPE_IBSS: /* clear out the station table */ - iwl_clear_stations_table(priv); + iwl3945_clear_stations_table(priv); - iwl_add_station(priv, BROADCAST_ADDR, 0, 0); - iwl_add_station(priv, priv->bssid, 0, 0); + iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); + iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->phymode == MODE_IEEE80211A)? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, CMD_ASYNC); - iwl_rate_scale_init(priv->hw, IWL_STA_ID); - iwl_send_beacon_cmd(priv); + iwl3945_rate_scale_init(priv->hw, IWL_STA_ID); + iwl3945_send_beacon_cmd(priv); break; default: IWL_ERROR("%s Should not be called in %d mode\n", - __FUNCTION__, priv->iw_mode); + __FUNCTION__, priv->iw_mode); break; } - iwl_sequence_reset(priv); + iwl3945_sequence_reset(priv); -#ifdef CONFIG_IWLWIFI_QOS - iwl_activate_qos(priv, 0); -#endif /* CONFIG_IWLWIFI_QOS */ +#ifdef CONFIG_IWL3945_QOS + iwl3945_activate_qos(priv, 0); +#endif /* CONFIG_IWL3945_QOS */ + /* we have just associated, don't start scan too early */ + priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; mutex_unlock(&priv->mutex); } -static void iwl_bg_abort_scan(struct work_struct *work) +static void iwl3945_bg_abort_scan(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, - abort_scan); + struct iwl3945_priv *priv = container_of(work, struct iwl3945_priv, abort_scan); - if (!iwl_is_ready(priv)) + if (!iwl3945_is_ready(priv)) return; mutex_lock(&priv->mutex); set_bit(STATUS_SCAN_ABORTING, &priv->status); - iwl_send_scan_abort(priv); + iwl3945_send_scan_abort(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_scan_completed(struct work_struct *work) +static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + +static void iwl3945_bg_scan_completed(struct work_struct *work) { - struct iwl_priv *priv = - container_of(work, struct iwl_priv, scan_completed); + struct iwl3945_priv *priv = + container_of(work, struct iwl3945_priv, scan_completed); IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n"); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + if (test_bit(STATUS_CONF_PENDING, &priv->status)) + iwl3945_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_hw_reg_send_txpower(priv); + iwl3945_hw_reg_send_txpower(priv); mutex_unlock(&priv->mutex); } @@ -6873,50 +6854,123 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_start(struct ieee80211_hw *hw) +#define UCODE_READY_TIMEOUT (2 * HZ) + +static int iwl3945_mac_start(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_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, iwl3945_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); - priv->is_open = 1; + memset(&priv->staging_rxon, 0, sizeof(struct iwl3945_rxon_cmd)); + /* fetch ucode file from disk, alloc and copy to bus-master buffers ... + * ucode filename and max sizes are card-specific. */ - if (!iwl_is_rfkill(priv)) - ieee80211_start_queues(priv->hw); + if (!priv->ucode_code.len) { + ret = iwl3945_read_ucode(priv); + if (ret) { + IWL_ERROR("Could not read microcode: %d\n", ret); + mutex_unlock(&priv->mutex); + goto out_release_irq; + } + } + + ret = __iwl3945_up(priv); mutex_unlock(&priv->mutex); + + if (ret) + goto out_release_irq; + + IWL_DEBUG_INFO("Start UP work.\n"); + + if (test_bit(STATUS_IN_SUSPEND, &priv->status)) + return 0; + + /* Wait for START_ALIVE from 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("Wait for 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 iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl3945_mac_stop(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); + if (!priv->is_open) { + IWL_DEBUG_MAC80211("leave - skip\n"); + return; + } - mutex_lock(&priv->mutex); - /* stop mac, cancel any scan request and clear - * RXON_FILTER_ASSOC_MSK BIT - */ priv->is_open = 0; - iwl_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - mutex_unlock(&priv->mutex); + + if (iwl3945_is_ready_rf(priv)) { + /* stop mac, cancel any scan request and clear + * RXON_FILTER_ASSOC_MSK BIT + */ + mutex_lock(&priv->mutex); + iwl3945_scan_cancel_timeout(priv, 100); + cancel_delayed_work(&priv->post_associate); + mutex_unlock(&priv->mutex); + } + + iwl3945_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 iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, +static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); @@ -6928,29 +6982,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ctl->tx_rate); - if (iwl_tx_skb(priv, skb, ctl)) + if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); return 0; } -static int iwl_mac_add_interface(struct ieee80211_hw *hw, +static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; unsigned long flags; DECLARE_MAC_BUF(mac); - IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); - if (priv->interface_id) { - IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + if (priv->vif) { + IWL_DEBUG_MAC80211("leave - vif != NULL\n"); return -EOPNOTSUPP; } spin_lock_irqsave(&priv->lock, flags); - priv->interface_id = conf->if_id; + priv->vif = conf->vif; spin_unlock_irqrestore(&priv->lock, flags); @@ -6961,106 +7015,108 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw, memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - iwl_set_mode(priv, conf->type); + if (iwl3945_is_ready(priv)) + iwl3945_set_mode(priv, conf->type); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); return 0; } /** - * iwl_mac_config - mac80211 config callback + * iwl3945_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 iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { - struct iwl_priv *priv = hw->priv; - const struct iwl_channel_info *ch_info; + struct iwl3945_priv *priv = hw->priv; + const struct iwl3945_channel_info *ch_info; unsigned long flags; + int ret = 0; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); - if (!iwl_is_ready(priv)) { + priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + + if (!iwl3945_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return -EIO; + ret = -EIO; + goto out; } - /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only - * what is exposed through include/ declrations */ - if (unlikely(!iwl_param_disable_hw_scan && + if (unlikely(!iwl3945_param_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; } spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", conf->channel, conf->phymode); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); - mutex_unlock(&priv->mutex); - return -EINVAL; + ret = -EINVAL; + goto out; } - iwl_set_rxon_channel(priv, conf->phymode, conf->channel); + iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel); - iwl_set_flags_for_phymode(priv, conf->phymode); + iwl3945_set_flags_for_phymode(priv, conf->phymode); /* The list of supported rates and rate mask can be different * for each phymode; since the phymode may have changed, reset * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); + iwl3945_set_rate(priv); spin_unlock_irqrestore(&priv->lock, flags); #ifdef IEEE80211_CONF_CHANNEL_SWITCH if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl_hw_channel_switch(priv, conf->channel); - mutex_unlock(&priv->mutex); - return 0; + iwl3945_hw_channel_switch(priv, conf->channel); + goto out; } #endif - iwl_radio_kill_sw(priv, !conf->radio_enabled); + iwl3945_radio_kill_sw(priv, !conf->radio_enabled); if (!conf->radio_enabled) { IWL_DEBUG_MAC80211("leave - radio disabled\n"); - mutex_unlock(&priv->mutex); - return 0; + goto out; } - if (iwl_is_rfkill(priv)) { + if (iwl3945_is_rfkill(priv)) { IWL_DEBUG_MAC80211("leave - RF kill\n"); - mutex_unlock(&priv->mutex); - return -EIO; + ret = -EIO; + goto out; } - iwl_set_rate(priv); + iwl3945_set_rate(priv); if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl_commit_rxon(priv); + iwl3945_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 0; + return ret; } -static void iwl_config_ap(struct iwl_priv *priv) +static void iwl3945_config_ap(struct iwl3945_priv *priv) { int rc = 0; @@ -7072,12 +7128,12 @@ static void iwl_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); /* RXON Timing */ - memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl_setup_rxon_timing(priv); - rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + memset(&priv->rxon_timing, 0, sizeof(struct iwl3945_rxon_time_cmd)); + iwl3945_setup_rxon_timing(priv); + rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (rc) IWL_WARNING("REPLY_RXON_TIMING failed - " @@ -7107,20 +7163,21 @@ static void iwl_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - iwl_add_station(priv, BROADCAST_ADDR, 0, 0); + iwl3945_commit_rxon(priv); + iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); } - iwl_send_beacon_cmd(priv); + iwl3945_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... */ } -static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, +static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7137,9 +7194,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } + if (!iwl3945_is_alive(priv)) + return -EAGAIN; + mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); @@ -7156,8 +7215,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } - if (priv->interface_id != if_id) { - IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); + if (priv->vif != vif) { + IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); mutex_unlock(&priv->mutex); return 0; } @@ -7175,11 +7234,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, priv->ibss_beacon = conf->beacon; } + if (iwl3945_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)) { + if (iwl3945_scan_cancel_timeout(priv, 100)) { IWL_WARNING("Aborted scan still in progress " "after 100ms\n"); IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); @@ -7195,20 +7257,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl_config_ap(priv); + iwl3945_config_ap(priv); else { - rc = iwl_commit_rxon(priv); + rc = iwl3945_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl_add_station(priv, + iwl3945_add_station(priv, priv->active_rxon.bssid_addr, 1, 0); } } else { - iwl_scan_cancel_timeout(priv, 100); + iwl3945_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); } + done: spin_lock_irqsave(&priv->lock, flags); if (!conf->ssid_len) memset(priv->essid, 0, IW_ESSID_MAX_SIZE); @@ -7224,34 +7287,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } -static void iwl_configure_filter(struct ieee80211_hw *hw, +static void iwl3945_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { /* * XXX: dummy - * see also iwl_connection_init_rx_config + * see also iwl3945_connection_init_rx_config */ *total_flags = 0; } -static void iwl_mac_remove_interface(struct ieee80211_hw *hw, +static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - - if (priv->interface_id == conf->if_id) { - priv->interface_id = 0; + if (iwl3945_is_ready_rf(priv)) { + iwl3945_scan_cancel_timeout(priv, 100); + cancel_delayed_work(&priv->post_associate); + priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; + iwl3945_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; @@ -7259,22 +7323,20 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211("leave\n"); - } -#define IWL_DELAY_NEXT_SCAN (HZ*2) -static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) { int rc = 0; unsigned long flags; - struct iwl_priv *priv = hw->priv; + struct iwl3945_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)) { + if (!iwl3945_is_ready_rf(priv)) { rc = -EIO; IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); goto out_unlock; @@ -7286,17 +7348,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) 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)) { + 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); + IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", + iwl3945_escape_essid(ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) @@ -7305,7 +7371,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } else priv->one_direct_scan = 0; - rc = iwl_scan_initiate(priv); + rc = iwl3945_scan_initiate(priv); IWL_DEBUG_MAC80211("leave\n"); @@ -7316,17 +7382,17 @@ out_unlock: return rc; } -static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int iwl3945_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; + struct iwl3945_priv *priv = hw->priv; int rc = 0; u8 sta_id; IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_param_hwcrypto) { + if (!iwl3945_param_hwcrypto) { IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -7335,7 +7401,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* only support pairwise keys */ return -EOPNOTSUPP; - sta_id = iwl_hw_find_station(priv, addr); + sta_id = iwl3945_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { DECLARE_MAC_BUF(mac); @@ -7346,24 +7412,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); + iwl3945_scan_cancel_timeout(priv, 100); switch (cmd) { case SET_KEY: - rc = iwl_update_sta_key_info(priv, key, sta_id); + rc = iwl3945_update_sta_key_info(priv, key, sta_id); if (!rc) { - iwl_set_rxon_hwcrypto(priv, 1); - iwl_commit_rxon(priv); + iwl3945_set_rxon_hwcrypto(priv, 1); + iwl3945_commit_rxon(priv); key->hw_key_idx = sta_id; IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; } break; case DISABLE_KEY: - rc = iwl_clear_sta_key_info(priv, sta_id); + rc = iwl3945_clear_sta_key_info(priv, sta_id); if (!rc) { - iwl_set_rxon_hwcrypto(priv, 0); - iwl_commit_rxon(priv); + iwl3945_set_rxon_hwcrypto(priv, 0); + iwl3945_commit_rxon(priv); IWL_DEBUG_MAC80211("disable hwcrypto key\n"); } break; @@ -7377,18 +7443,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return rc; } -static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, +static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { - struct iwl_priv *priv = hw->priv; -#ifdef CONFIG_IWLWIFI_QOS + struct iwl3945_priv *priv = hw->priv; +#ifdef CONFIG_IWL3945_QOS unsigned long flags; int q; -#endif /* CONFIG_IWL_QOS */ +#endif /* CONFIG_IWL3945_QOS */ IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); return -EIO; } @@ -7398,7 +7464,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, return 0; } -#ifdef CONFIG_IWLWIFI_QOS +#ifdef CONFIG_IWL3945_QOS if (!priv->qos_data.qos_enable) { priv->qos_data.qos_active = 0; IWL_DEBUG_MAC80211("leave - qos not enabled\n"); @@ -7421,30 +7487,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, mutex_lock(&priv->mutex); 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); + iwl3945_activate_qos(priv, 1); + else if (priv->assoc_id && iwl3945_is_associated(priv)) + iwl3945_activate_qos(priv, 0); mutex_unlock(&priv->mutex); -#endif /*CONFIG_IWLWIFI_QOS */ +#endif /*CONFIG_IWL3945_QOS */ IWL_DEBUG_MAC80211("leave\n"); return 0; } -static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, +static int iwl3945_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; + struct iwl3945_tx_queue *txq; + struct iwl3945_queue *q; unsigned long flags; IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); return -EIO; } @@ -7454,7 +7520,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, for (i = 0; i < AC_NUM; i++) { txq = &priv->txq[i]; q = &txq->q; - avail = iwl_queue_space(q); + avail = iwl3945_queue_space(q); stats->data[i].len = q->n_window - avail; stats->data[i].limit = q->n_window - q->high_mark; @@ -7468,7 +7534,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, return 0; } -static int iwl_mac_get_stats(struct ieee80211_hw *hw, +static int iwl3945_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { IWL_DEBUG_MAC80211("enter\n"); @@ -7477,7 +7543,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) +static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw) { IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("leave\n"); @@ -7485,16 +7551,16 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) return 0; } -static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; unsigned long flags; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); -#ifdef CONFIG_IWLWIFI_QOS - iwl_reset_qos(priv); +#ifdef CONFIG_IWL3945_QOS + iwl3945_reset_qos(priv); #endif cancel_delayed_work(&priv->post_associate); @@ -7517,13 +7583,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) spin_unlock_irqrestore(&priv->lock, flags); + if (!iwl3945_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); + iwl3945_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); } /* Per mac80211.h: This is only used in IBSS mode... */ @@ -7534,15 +7606,9 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) return; } - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - priv->only_active_channel = 0; - iwl_set_rate(priv); + iwl3945_set_rate(priv); mutex_unlock(&priv->mutex); @@ -7550,16 +7616,16 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) } -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct iwl_priv *priv = hw->priv; + struct iwl3945_priv *priv = hw->priv; unsigned long flags; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); mutex_unlock(&priv->mutex); return -EIO; @@ -7583,8 +7649,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWLWIFI_QOS - iwl_reset_qos(priv); +#ifdef CONFIG_IWL3945_QOS + iwl3945_reset_qos(priv); #endif queue_work(priv->workqueue, &priv->post_associate.work); @@ -7600,7 +7666,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * *****************************************************************************/ -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL3945_DEBUG /* * The following adds a new attribute to the sysfs representation @@ -7612,7 +7678,7 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, static ssize_t show_debug_level(struct device_driver *d, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + return sprintf(buf, "0x%08X\n", iwl3945_debug_level); } static ssize_t store_debug_level(struct device_driver *d, const char *buf, size_t count) @@ -7625,7 +7691,7 @@ static ssize_t store_debug_level(struct device_driver *d, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + iwl3945_debug_level = val; return strnlen(buf, count); } @@ -7633,7 +7699,7 @@ static ssize_t store_debug_level(struct device_driver *d, static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, store_debug_level); -#endif /* CONFIG_IWLWIFI_DEBUG */ +#endif /* CONFIG_IWL3945_DEBUG */ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, char *buf) @@ -7644,7 +7710,7 @@ static ssize_t show_rf_kill(struct device *d, * 2 - HW based RF kill active * 3 - Both HW and SW based RF kill active */ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); @@ -7655,10 +7721,10 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; mutex_lock(&priv->mutex); - iwl_radio_kill_sw(priv, buf[0] == '1'); + iwl3945_radio_kill_sw(priv, buf[0] == '1'); mutex_unlock(&priv->mutex); return count; @@ -7669,12 +7735,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - if (!iwl_is_alive(priv)) + if (!iwl3945_is_alive(priv)) return -EAGAIN; - return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv)); + return sprintf(buf, "%d\n", iwl3945_hw_get_temperature(priv)); } static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); @@ -7683,15 +7749,15 @@ static ssize_t show_rs_window(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; - return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID); + struct iwl3945_priv *priv = d->driver_data; + return iwl3945_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) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; return sprintf(buf, "%d\n", priv->user_txpower_limit); } @@ -7699,7 +7765,7 @@ 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; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; char *p = (char *)buf; u32 val; @@ -7708,7 +7774,7 @@ static ssize_t store_tx_power(struct device *d, printk(KERN_INFO DRV_NAME ": %s is not in decimal form.\n", buf); else - iwl_hw_reg_set_txpower(priv, val); + iwl3945_hw_reg_set_txpower(priv, val); return count; } @@ -7718,7 +7784,7 @@ 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; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -7727,19 +7793,19 @@ 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; + struct iwl3945_priv *priv = (struct iwl3945_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)) + if (iwl3945_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); - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -7752,7 +7818,7 @@ 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; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -7762,20 +7828,20 @@ 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; + struct iwl3945_priv *priv = (struct iwl3945_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)) + if (iwl3945_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); - iwl_commit_rxon(priv); + iwl3945_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -7789,20 +7855,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, static ssize_t show_tune(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", (priv->phymode << 8) | le16_to_cpu(priv->active_rxon.channel)); } -static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode); +static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode); static ssize_t store_tune(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; char *p = (char *)buf; u16 tune = simple_strtoul(p, &p, 0); u8 phymode = (tune >> 8) & 0xff; @@ -7813,9 +7879,9 @@ static ssize_t store_tune(struct device *d, mutex_lock(&priv->mutex); if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || (priv->phymode != phymode)) { - const struct iwl_channel_info *ch_info; + const struct iwl3945_channel_info *ch_info; - ch_info = iwl_get_channel_info(priv, phymode, channel); + ch_info = iwl3945_get_channel_info(priv, phymode, channel); if (!ch_info) { IWL_WARNING("Requested invalid phymode/channel " "combination: %d %d\n", phymode, channel); @@ -7824,18 +7890,18 @@ static ssize_t store_tune(struct device *d, } /* Cancel any currently running scans... */ - if (iwl_scan_cancel_timeout(priv, 100)) + if (iwl3945_scan_cancel_timeout(priv, 100)) IWL_WARNING("Could not cancel scan.\n"); else { IWL_DEBUG_INFO("Committing phymode and " "rxon.channel = %d %d\n", phymode, channel); - iwl_set_rxon_channel(priv, phymode, channel); - iwl_set_flags_for_phymode(priv, phymode); + iwl3945_set_rxon_channel(priv, phymode, channel); + iwl3945_set_flags_for_phymode(priv, phymode); - iwl_set_rate(priv); - iwl_commit_rxon(priv); + iwl3945_set_rate(priv); + iwl3945_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -7845,13 +7911,13 @@ static ssize_t store_tune(struct device *d, static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL3945_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 iwl_spectrum_notification measure_report; + 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; unsigned long flags; @@ -7883,7 +7949,7 @@ 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 iwl3945_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), @@ -7909,19 +7975,19 @@ static ssize_t store_measurement(struct device *d, IWL_DEBUG_INFO("Invoking measurement of type %d on " "channel %d (for '%s')\n", type, params.channel, buf); - iwl_get_measurement(priv, ¶ms, type); + iwl3945_get_measurement(priv, ¶ms, type); return count; } static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); -#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */ +#endif /* CONFIG_IWL3945_SPECTRUM_MEASUREMENT */ static ssize_t show_rate(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl3945_priv *priv = dev_get_drvdata(d); unsigned long flags; int i; @@ -7932,13 +7998,13 @@ static ssize_t show_rate(struct device *d, i = priv->stations[IWL_STA_ID].current_rate.s.rate; spin_unlock_irqrestore(&priv->sta_lock, flags); - i = iwl_rate_index_from_plcp(i); + i = iwl3945_rate_index_from_plcp(i); if (i == -1) return sprintf(buf, "0\n"); return sprintf(buf, "%d%s\n", - (iwl_rates[i].ieee >> 1), - (iwl_rates[i].ieee & 0x1) ? ".5" : ""); + (iwl3945_rates[i].ieee >> 1), + (iwl3945_rates[i].ieee & 0x1) ? ".5" : ""); } static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL); @@ -7947,7 +8013,7 @@ 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); + struct iwl3945_priv *priv = dev_get_drvdata(d); priv->retry_rate = simple_strtoul(buf, NULL, 0); if (priv->retry_rate <= 0) @@ -7959,7 +8025,7 @@ static ssize_t store_retry_rate(struct device *d, static ssize_t show_retry_rate(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl3945_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%d", priv->retry_rate); } @@ -7970,14 +8036,14 @@ 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); + struct iwl3945_priv *priv = dev_get_drvdata(d); int rc; int mode; mode = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); - if (!iwl_is_ready(priv)) { + if (!iwl3945_is_ready(priv)) { rc = -EAGAIN; goto out; } @@ -7988,7 +8054,7 @@ static ssize_t store_power_level(struct device *d, mode |= IWL_POWER_ENABLED; if (mode != priv->power_mode) { - rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode)); + rc = iwl3945_send_power_mode(priv, IWL_POWER_LEVEL(mode)); if (rc) { IWL_DEBUG_MAC80211("failed setting power mode.\n"); goto out; @@ -8024,7 +8090,7 @@ static const s32 period_duration[] = { static ssize_t show_power_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl3945_priv *priv = dev_get_drvdata(d); int level = IWL_POWER_LEVEL(priv->power_mode); char *p = buf; @@ -8059,18 +8125,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_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 iwl3945_priv *priv = dev_get_drvdata(d); int len = 0, i; struct ieee80211_channel *channels = NULL; const struct ieee80211_hw_mode *hw_mode = NULL; int count = 0; - if (!iwl_is_ready(priv)) + if (!iwl3945_is_ready(priv)) return -EAGAIN; - hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G); + hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G); if (!hw_mode) - hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B); + hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B); if (hw_mode) { channels = hw_mode->channels; count = hw_mode->num_channels; @@ -8097,7 +8163,7 @@ static ssize_t show_channels(struct device *d, flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? "active/passive" : "passive only"); - hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A); + hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A); if (hw_mode) { channels = hw_mode->channels; count = hw_mode->num_channels; @@ -8133,17 +8199,17 @@ 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); + 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; int rc = 0; - if (!iwl_is_alive(priv)) + if (!iwl3945_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv); + rc = iwl3945_send_statistics_request(priv); mutex_unlock(&priv->mutex); if (rc) { @@ -8171,9 +8237,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); static ssize_t show_antenna(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl3945_priv *priv = dev_get_drvdata(d); - if (!iwl_is_alive(priv)) + if (!iwl3945_is_alive(priv)) return -EAGAIN; return sprintf(buf, "%d\n", priv->antenna); @@ -8184,7 +8250,7 @@ static ssize_t store_antenna(struct device *d, const char *buf, size_t count) { int ant; - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl3945_priv *priv = dev_get_drvdata(d); if (count == 0) return 0; @@ -8196,7 +8262,7 @@ static ssize_t store_antenna(struct device *d, if ((ant >= 0) && (ant <= 2)) { IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); - priv->antenna = (enum iwl_antenna)ant; + priv->antenna = (enum iwl3945_antenna)ant; } else IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); @@ -8209,8 +8275,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); 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)) + struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; + if (!iwl3945_is_alive(priv)) return -EAGAIN; return sprintf(buf, "0x%08x\n", (int)priv->status); } @@ -8224,7 +8290,7 @@ static ssize_t dump_error_log(struct device *d, char *p = (char *)buf; if (p[0] == '1') - iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data); + iwl3945_dump_nic_error_log((struct iwl3945_priv *)d->driver_data); return strnlen(buf, count); } @@ -8238,7 +8304,7 @@ static ssize_t dump_event_log(struct device *d, char *p = (char *)buf; if (p[0] == '1') - iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data); + iwl3945_dump_nic_event_log((struct iwl3945_priv *)d->driver_data); return strnlen(buf, count); } @@ -8251,34 +8317,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); * *****************************************************************************/ -static void iwl_setup_deferred_work(struct iwl_priv *priv) +static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) { priv->workqueue = create_workqueue(DRV_NAME); init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl_bg_up); - INIT_WORK(&priv->restart, iwl_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); - INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); - INIT_WORK(&priv->request_scan, iwl_bg_request_scan); - INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); - INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); - INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); - INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); - - iwl_hw_setup_deferred_work(priv); + INIT_WORK(&priv->up, iwl3945_bg_up); + INIT_WORK(&priv->restart, iwl3945_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl3945_bg_rx_replenish); + INIT_WORK(&priv->scan_completed, iwl3945_bg_scan_completed); + INIT_WORK(&priv->request_scan, iwl3945_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); + INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); + INIT_DELAYED_WORK(&priv->post_associate, iwl3945_bg_post_associate); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); + + iwl3945_hw_setup_deferred_work(priv); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); + iwl3945_irq_tasklet, (unsigned long)priv); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv) +static void iwl3945_cancel_deferred_work(struct iwl3945_priv *priv) { - iwl_hw_cancel_deferred_work(priv); + iwl3945_hw_cancel_deferred_work(priv); cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); @@ -8287,14 +8353,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->beacon_update); } -static struct attribute *iwl_sysfs_entries[] = { +static struct attribute *iwl3945_sysfs_entries[] = { &dev_attr_antenna.attr, &dev_attr_channels.attr, &dev_attr_dump_errors.attr, &dev_attr_dump_events.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, #endif &dev_attr_power_level.attr, @@ -8311,45 +8377,48 @@ static struct attribute *iwl_sysfs_entries[] = { NULL }; -static struct attribute_group iwl_attribute_group = { +static struct attribute_group iwl3945_attribute_group = { .name = NULL, /* put in device directory */ - .attrs = iwl_sysfs_entries, + .attrs = iwl3945_sysfs_entries, }; -static struct ieee80211_ops iwl_hw_ops = { - .tx = iwl_mac_tx, - .start = iwl_mac_start, - .stop = iwl_mac_stop, - .add_interface = iwl_mac_add_interface, - .remove_interface = iwl_mac_remove_interface, - .config = iwl_mac_config, - .config_interface = iwl_mac_config_interface, - .configure_filter = iwl_configure_filter, - .set_key = iwl_mac_set_key, - .get_stats = iwl_mac_get_stats, - .get_tx_stats = iwl_mac_get_tx_stats, - .conf_tx = iwl_mac_conf_tx, - .get_tsf = iwl_mac_get_tsf, - .reset_tsf = iwl_mac_reset_tsf, - .beacon_update = iwl_mac_beacon_update, - .hw_scan = iwl_mac_hw_scan +static struct ieee80211_ops iwl3945_hw_ops = { + .tx = iwl3945_mac_tx, + .start = iwl3945_mac_start, + .stop = iwl3945_mac_stop, + .add_interface = iwl3945_mac_add_interface, + .remove_interface = iwl3945_mac_remove_interface, + .config = iwl3945_mac_config, + .config_interface = iwl3945_mac_config_interface, + .configure_filter = iwl3945_configure_filter, + .set_key = iwl3945_mac_set_key, + .get_stats = iwl3945_mac_get_stats, + .get_tx_stats = iwl3945_mac_get_tx_stats, + .conf_tx = iwl3945_mac_conf_tx, + .get_tsf = iwl3945_mac_get_tsf, + .reset_tsf = iwl3945_mac_reset_tsf, + .beacon_update = iwl3945_mac_beacon_update, + .hw_scan = iwl3945_mac_hw_scan }; -static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; u32 pci_id; - struct iwl_priv *priv; + struct iwl3945_priv *priv; struct ieee80211_hw *hw; int i; + DECLARE_MAC_BUF(mac); - if (iwl_param_disable_hw_scan) { + /* Disabling hardware scan means that mac80211 will perform scans + * "the hard way", rather than using device's scan. */ + if (iwl3945_param_disable_hw_scan) { IWL_DEBUG_INFO("Disabling hw_scan\n"); - iwl_hw_ops.hw_scan = NULL; + iwl3945_hw_ops.hw_scan = NULL; } - if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) || - (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) { + if ((iwl3945_param_queues_num > IWL_MAX_NUM_QUEUES) || + (iwl3945_param_queues_num < IWL_MIN_NUM_QUEUES)) { IWL_ERROR("invalid queues_num, should be between %d and %d\n", IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); err = -EINVAL; @@ -8358,7 +8427,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* mac80211 allocates memory for this device instance, including * space for this driver's private structure */ - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops); + hw = ieee80211_alloc_hw(sizeof(struct iwl3945_priv), &iwl3945_hw_ops); if (hw == NULL) { IWL_ERROR("Can not allocate network device\n"); err = -ENOMEM; @@ -8373,9 +8442,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->hw = hw; priv->pci_dev = pdev; - priv->antenna = (enum iwl_antenna)iwl_param_antenna; -#ifdef CONFIG_IWLWIFI_DEBUG - iwl_debug_level = iwl_param_debug; + + /* Select antenna (may be helpful if only one antenna is connected) */ + priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; +#ifdef CONFIG_IWL3945_DEBUG + iwl3945_debug_level = iwl3945_param_debug; atomic_set(&priv->restrict_refcnt, 0); #endif priv->retry_rate = 1; @@ -8394,6 +8465,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Tell mac80211 our Tx characteristics */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + /* 4 EDCA QOS priorities */ hw->queues = 4; spin_lock_init(&priv->lock); @@ -8414,7 +8486,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - iwl_clear_stations_table(priv); + /* Clear the driver's (not device's) station table */ + iwl3945_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -8433,9 +8506,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = pci_request_regions(pdev, DRV_NAME); if (err) goto out_pci_disable_device; + /* 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); + priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -8448,7 +8523,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Initialize module parameter values here */ - if (iwl_param_disable) { + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (iwl3945_param_disable) { set_bit(STATUS_RF_KILL_SW, &priv->status); IWL_DEBUG_INFO("Radio disabled.\n"); } @@ -8483,78 +8559,82 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->is_abg ? "A" : ""); /* Device-specific setup */ - if (iwl_hw_set_hw_setting(priv)) { + if (iwl3945_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); - mutex_unlock(&priv->mutex); goto out_iounmap; } -#ifdef CONFIG_IWLWIFI_QOS - if (iwl_param_qos_enable) +#ifdef CONFIG_IWL3945_QOS + if (iwl3945_param_qos_enable) priv->qos_data.qos_enable = 1; - iwl_reset_qos(priv); + iwl3945_reset_qos(priv); priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; -#endif /* CONFIG_IWLWIFI_QOS */ +#endif /* CONFIG_IWL3945_QOS */ - iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6); - iwl_setup_deferred_work(priv); - iwl_setup_rx_handlers(priv); + iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl3945_setup_deferred_work(priv); + iwl3945_setup_rx_handlers(priv); priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; - pci_enable_msi(pdev); + iwl3945_disable_interrupts(priv); - err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); - if (err) { - IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); - goto out_disable_msi; - } - - mutex_lock(&priv->mutex); - - err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); + err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - mutex_unlock(&priv->mutex); goto out_release_irq; } - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - err = iwl_read_ucode(priv); + /* 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"); + goto out_remove_sysfs; + } + /* Read the EEPROM */ + err = iwl3945_eeprom_init(priv); if (err) { - IWL_ERROR("Could not read microcode: %d\n", err); - mutex_unlock(&priv->mutex); - goto out_pci_alloc; + IWL_ERROR("Unable to init EEPROM\n"); + goto out_remove_sysfs; } + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_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); - mutex_unlock(&priv->mutex); - - IWL_DEBUG_INFO("Queing UP work.\n"); + iwl3945_rate_control_register(priv->hw); + err = ieee80211_register_hw(priv->hw); + if (err) { + IWL_ERROR("Failed to register network device (error %d)\n", err); + goto out_remove_sysfs; + } - queue_work(priv->workqueue, &priv->up); + priv->hw->conf.beacon_int = 100; + priv->mac80211_registered = 1; + pci_save_state(pdev); + pci_disable_device(pdev); return 0; - out_pci_alloc: - iwl_dealloc_ucode_pci(priv); - - sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); out_release_irq: - free_irq(pdev->irq, priv); - - out_disable_msi: - pci_disable_msi(pdev); destroy_workqueue(priv->workqueue); priv->workqueue = NULL; - iwl_unset_hw_setting(priv); + iwl3945_unset_hw_setting(priv); out_iounmap: pci_iounmap(pdev, priv->hw_base); @@ -8569,9 +8649,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } -static void iwl_pci_remove(struct pci_dev *pdev) +static void iwl3945_pci_remove(struct pci_dev *pdev) { - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl3945_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; int i; @@ -8582,43 +8662,41 @@ static void iwl_pci_remove(struct pci_dev *pdev) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_down(priv); + iwl3945_down(priv); /* Free MAC hash list for ADHOC */ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { list_del(p); - kfree(list_entry(p, struct iwl_ibss_seq, list)); + kfree(list_entry(p, struct iwl3945_ibss_seq, list)); } } - sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); - iwl_dealloc_ucode_pci(priv); + iwl3945_dealloc_ucode_pci(priv); if (priv->rxq.bd) - iwl_rx_queue_free(priv, &priv->rxq); - iwl_hw_txq_ctx_free(priv); + iwl3945_rx_queue_free(priv, &priv->rxq); + iwl3945_hw_txq_ctx_free(priv); - iwl_unset_hw_setting(priv); - iwl_clear_stations_table(priv); + iwl3945_unset_hw_setting(priv); + iwl3945_clear_stations_table(priv); if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); - iwl_rate_control_unregister(priv->hw); + iwl3945_rate_control_unregister(priv->hw); } /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); - /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes + /* ieee80211_unregister_hw calls iwl3945_mac_stop, which flushes * priv->workqueue... so we can't take down the workqueue * until now... */ destroy_workqueue(priv->workqueue); priv->workqueue = NULL; - free_irq(pdev->irq, priv); - pci_disable_msi(pdev); pci_iounmap(pdev, priv->hw_base); pci_release_regions(pdev); pci_disable_device(pdev); @@ -8637,93 +8715,31 @@ static void iwl_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM -static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int iwl3945_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct iwl_priv *priv = pci_get_drvdata(pdev); - - set_bit(STATUS_IN_SUSPEND, &priv->status); - - /* Take down the device; powers it off, etc. */ - iwl_down(priv); + struct iwl3945_priv *priv = pci_get_drvdata(pdev); - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); + if (priv->is_open) { + set_bit(STATUS_IN_SUSPEND, &priv->status); + iwl3945_mac_stop(priv->hw); + priv->is_open = 1; + } - pci_save_state(pdev); - pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0; } -static void iwl_resume(struct iwl_priv *priv) +static int iwl3945_pci_resume(struct pci_dev *pdev) { - unsigned long flags; - - /* The following it a temporary work around due to the - * suspend / resume not fully initializing the NIC correctly. - * Without all of the following, resume will not attempt to take - * down the NIC (it shouldn't really need to) and will just try - * and bring the NIC back up. However that fails during the - * ucode verification process. This then causes iwl_down to be - * called *after* iwl_hw_nic_init() has succeeded -- which - * then lets the next init sequence succeed. So, we've - * replicated all of that NIC init code here... */ - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - iwl_hw_nic_init(priv); - - 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); - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - 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); - - /* tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_restricted_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); - - udelay(5); - - iwl_hw_nic_reset(priv); - - /* Bring the device back up */ - clear_bit(STATUS_IN_SUSPEND, &priv->status); - queue_work(priv->workqueue, &priv->up); -} - -static int iwl_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - int err; - - printk(KERN_INFO "Coming out of suspend...\n"); + struct iwl3945_priv *priv = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - pci_restore_state(pdev); - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries - * from interfering with C3 CPU state. pci_restore_state won't help - * here since it only restores the first 64 bytes pci config header. - */ - pci_write_config_byte(pdev, 0x41, 0x00); - - iwl_resume(priv); + if (priv->is_open) + iwl3945_mac_start(priv->hw); + clear_bit(STATUS_IN_SUSPEND, &priv->status); return 0; } @@ -8735,33 +8751,33 @@ static int iwl_pci_resume(struct pci_dev *pdev) * *****************************************************************************/ -static struct pci_driver iwl_driver = { +static struct pci_driver iwl3945_driver = { .name = DRV_NAME, - .id_table = iwl_hw_card_ids, - .probe = iwl_pci_probe, - .remove = __devexit_p(iwl_pci_remove), + .id_table = iwl3945_hw_card_ids, + .probe = iwl3945_pci_probe, + .remove = __devexit_p(iwl3945_pci_remove), #ifdef CONFIG_PM - .suspend = iwl_pci_suspend, - .resume = iwl_pci_resume, + .suspend = iwl3945_pci_suspend, + .resume = iwl3945_pci_resume, #endif }; -static int __init iwl_init(void) +static int __init iwl3945_init(void) { int ret; printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n"); printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n"); - ret = pci_register_driver(&iwl_driver); + ret = pci_register_driver(&iwl3945_driver); if (ret) { IWL_ERROR("Unable to initialize PCI module\n"); return ret; } -#ifdef CONFIG_IWLWIFI_DEBUG - ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); +#ifdef CONFIG_IWL3945_DEBUG + ret = driver_create_file(&iwl3945_driver.driver, &driver_attr_debug_level); if (ret) { IWL_ERROR("Unable to create driver sysfs file\n"); - pci_unregister_driver(&iwl_driver); + pci_unregister_driver(&iwl3945_driver); return ret; } #endif @@ -8769,32 +8785,32 @@ static int __init iwl_init(void) return ret; } -static void __exit iwl_exit(void) +static void __exit iwl3945_exit(void) { -#ifdef CONFIG_IWLWIFI_DEBUG - driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); +#ifdef CONFIG_IWL3945_DEBUG + driver_remove_file(&iwl3945_driver.driver, &driver_attr_debug_level); #endif - pci_unregister_driver(&iwl_driver); + pci_unregister_driver(&iwl3945_driver); } -module_param_named(antenna, iwl_param_antenna, int, 0444); +module_param_named(antenna, iwl3945_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl_param_disable, int, 0444); +module_param_named(disable, iwl3945_param_disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); -module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444); +module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "using hardware crypto engine (default 0 [software])\n"); -module_param_named(debug, iwl_param_debug, int, 0444); +module_param_named(debug, iwl3945_param_debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); -module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444); +module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -module_param_named(queues_num, iwl_param_queues_num, int, 0444); +module_param_named(queues_num, iwl3945_param_queues_num, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); /* QoS */ -module_param_named(qos_enable, iwl_param_qos_enable, int, 0444); +module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444); MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); -module_exit(iwl_exit); -module_init(iwl_init); +module_exit(iwl3945_exit); +module_init(iwl3945_init); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 6cd57c220631..c86da5cd1df1 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -27,16 +27,6 @@ * *****************************************************************************/ -/* - * NOTE: This file (iwl-base.c) is used to build to multiple hardware targets - * by defining IWL to either 3945 or 4965. The Makefile used when building - * the base targets will create base-3945.o and base-4965.o - * - * The eventual goal is to move as many of the #if IWL / #endif blocks out of - * this file and into the hardware specific implementation files (iwl-XXXX.c) - * and leave only the common (non #ifdef sprinkled) code in this file - */ - #include <linux/kernel.h> #include <linux/module.h> #include <linux/version.h> @@ -51,21 +41,20 @@ #include <linux/etherdevice.h> #include <linux/if_arp.h> -#include <net/ieee80211_radiotap.h> #include <net/mac80211.h> #include <asm/div64.h> -#define IWL 4965 - -#include "iwlwifi.h" #include "iwl-4965.h" #include "iwl-helpers.h" -#ifdef CONFIG_IWLWIFI_DEBUG -u32 iwl_debug_level; +#ifdef CONFIG_IWL4965_DEBUG +u32 iwl4965_debug_level; #endif +static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq); + /****************************************************************************** * * module boiler plate @@ -73,13 +62,14 @@ u32 iwl_debug_level; ******************************************************************************/ /* module parameters */ -int iwl_param_disable_hw_scan; -int iwl_param_debug; -int iwl_param_disable; /* def: enable radio */ -int iwl_param_antenna; /* def: 0 = both antennas (use diversity) */ -int iwl_param_hwcrypto; /* def: using software encryption */ -int iwl_param_qos_enable = 1; -int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; +static int iwl4965_param_disable_hw_scan; /* def: 0 = use 4965's h/w scan */ +static int iwl4965_param_debug; /* def: 0 = minimal debug log messages */ +static int iwl4965_param_disable; /* def: enable radio */ +static int iwl4965_param_antenna; /* def: 0 = both antennas (use diversity) */ +int iwl4965_param_hwcrypto; /* def: using software encryption */ +static int iwl4965_param_qos_enable = 1; /* def: 1 = use quality of service */ +int iwl4965_param_queues_num = IWL_MAX_NUM_QUEUES; /* def: 16 Tx queues */ +int iwl4965_param_amsdu_size_8K; /* def: enable 8K amsdu size */ /* * module name, copyright, version, etc. @@ -88,19 +78,19 @@ int iwl_param_queues_num = IWL_MAX_NUM_QUEUES; #define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link 4965AGN driver for Linux" -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG #define VD "d" #else #define VD #endif -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT #define VS "s" #else #define VS #endif -#define IWLWIFI_VERSION "1.1.17k" VD VS +#define IWLWIFI_VERSION "1.2.23k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2007 Intel Corporation" #define DRV_VERSION IWLWIFI_VERSION @@ -125,8 +115,8 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl_get_hw_mode( - struct iwl_priv *priv, int mode) +static const struct ieee80211_hw_mode *iwl4965_get_hw_mode( + struct iwl4965_priv *priv, int mode) { int i; @@ -137,7 +127,7 @@ static const struct ieee80211_hw_mode *iwl_get_hw_mode( return NULL; } -static int iwl_is_empty_essid(const char *essid, int essid_len) +static int iwl4965_is_empty_essid(const char *essid, int essid_len) { /* Single white space is for Linksys APs */ if (essid_len == 1 && essid[0] == ' ') @@ -153,13 +143,13 @@ static int iwl_is_empty_essid(const char *essid, int essid_len) return 1; } -static const char *iwl_escape_essid(const char *essid, u8 essid_len) +static const char *iwl4965_escape_essid(const char *essid, u8 essid_len) { static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; const char *s = essid; char *d = escaped; - if (iwl_is_empty_essid(essid, essid_len)) { + if (iwl4965_is_empty_essid(essid, essid_len)) { memcpy(escaped, "<hidden>", sizeof("<hidden>")); return escaped; } @@ -177,10 +167,10 @@ static const char *iwl_escape_essid(const char *essid, u8 essid_len) return escaped; } -static void iwl_print_hex_dump(int level, void *p, u32 len) +static void iwl4965_print_hex_dump(int level, void *p, u32 len) { -#ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_debug_level & level)) +#ifdef CONFIG_IWL4965_DEBUG + if (!(iwl4965_debug_level & level)) return; print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, @@ -193,24 +183,33 @@ static void iwl_print_hex_dump(int level, void *p, u32 len) * * Theory of operation * - * A queue is a circular buffers with 'Read' and 'Write' pointers. - * 2 empty entries always kept in the buffer to protect from overflow. + * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer + * of buffer descriptors, each of which points to one or more data buffers for + * the device to read from or fill. Driver and device exchange status of each + * queue via "read" and "write" pointers. Driver keeps minimum of 2 empty + * entries in each circular buffer, to protect against confusing empty and full + * queue states. + * + * The device reads or writes the data in the queues via the device's several + * DMA/FIFO channels. Each queue is mapped to a single DMA channel. * * For Tx queue, there are low mark and high mark limits. If, after queuing * the packet for Tx, free space become < low mark, Tx queue stopped. When * reclaiming packets (on 'tx done IRQ), if free space become > high mark, * Tx queue resumed. * - * The IWL operates with six queues, one receive queue in the device's - * sram, one transmit queue for sending commands to the device firmware, - * and four transmit queues for data. + * The 4965 operates with up to 17 queues: One receive queue, one transmit + * queue (#4) for sending commands to the device firmware, and 15 other + * Tx queues that may be mapped to prioritized Tx DMA/FIFO channels. + * + * See more detailed info in iwl-4965-hw.h. ***************************************************/ -static int iwl_queue_space(const struct iwl_queue *q) +static int iwl4965_queue_space(const struct iwl4965_queue *q) { - int s = q->last_used - q->first_empty; + int s = q->read_ptr - q->write_ptr; - if (q->last_used > q->first_empty) + if (q->read_ptr > q->write_ptr) s -= q->n_bd; if (s <= 0) @@ -222,42 +221,55 @@ static int iwl_queue_space(const struct iwl_queue *q) return s; } -/* XXX: n_bd must be power-of-two size */ -static inline int iwl_queue_inc_wrap(int index, int n_bd) +/** + * iwl4965_queue_inc_wrap - increment queue index, wrap back to beginning + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl4965_queue_inc_wrap(int index, int n_bd) { return ++index & (n_bd - 1); } -/* XXX: n_bd must be power-of-two size */ -static inline int iwl_queue_dec_wrap(int index, int n_bd) +/** + * iwl4965_queue_dec_wrap - decrement queue index, wrap back to end + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl4965_queue_dec_wrap(int index, int n_bd) { return --index & (n_bd - 1); } -static inline int x2_queue_used(const struct iwl_queue *q, int i) +static inline int x2_queue_used(const struct iwl4965_queue *q, int i) { - return q->first_empty > q->last_used ? - (i >= q->last_used && i < q->first_empty) : - !(i < q->last_used && i >= q->first_empty); + return q->write_ptr > q->read_ptr ? + (i >= q->read_ptr && i < q->write_ptr) : + !(i < q->read_ptr && i >= q->write_ptr); } -static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) +static inline u8 get_cmd_index(struct iwl4965_queue *q, u32 index, int is_huge) { + /* This is for scan command, the big buffer at end of command array */ if (is_huge) - return q->n_window; + return q->n_window; /* must be power of 2 */ + /* Otherwise, use normal size buffers */ return index & (q->n_window - 1); } -static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, +/** + * iwl4965_queue_init - Initialize queue's high/low-water and read/write indexes + */ +static int iwl4965_queue_init(struct iwl4965_priv *priv, struct iwl4965_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; q->n_window = slots_num; q->id = id; - /* count must be power-of-two size, otherwise iwl_queue_inc_wrap - * and iwl_queue_dec_wrap are broken. */ + /* count must be power-of-two size, otherwise iwl4965_queue_inc_wrap + * and iwl4965_queue_dec_wrap are broken. */ BUG_ON(!is_power_of_2(count)); /* slots_num must be power-of-two size, otherwise @@ -272,27 +284,34 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, if (q->high_mark < 2) q->high_mark = 2; - q->first_empty = q->last_used = 0; + q->write_ptr = q->read_ptr = 0; return 0; } -static int iwl_tx_queue_alloc(struct iwl_priv *priv, - struct iwl_tx_queue *txq, u32 id) +/** + * iwl4965_tx_queue_alloc - Alloc driver data and TFD CB for one Tx/cmd queue + */ +static int iwl4965_tx_queue_alloc(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq, u32 id) { struct pci_dev *dev = priv->pci_dev; + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ if (id != IWL_CMD_QUEUE_NUM) { txq->txb = kmalloc(sizeof(txq->txb[0]) * TFD_QUEUE_SIZE_MAX, GFP_KERNEL); if (!txq->txb) { - IWL_ERROR("kmalloc for auxilary BD " + IWL_ERROR("kmalloc for auxiliary BD " "structures failed\n"); goto error; } } else txq->txb = NULL; + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ txq->bd = pci_alloc_consistent(dev, sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, &txq->q.dma_addr); @@ -315,24 +334,33 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, return -ENOMEM; } -int iwl_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, int slots_num, u32 txq_id) +/** + * iwl4965_tx_queue_init - Allocate and initialize one tx/cmd queue + */ +int iwl4965_tx_queue_init(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq, int slots_num, u32 txq_id) { struct pci_dev *dev = priv->pci_dev; int len; int rc = 0; - /* alocate command space + one big command for scan since scan - * command is very huge the system will not have two scan at the - * same time */ - len = sizeof(struct iwl_cmd) * slots_num; + /* + * Alloc buffer array for commands (Tx or other types of commands). + * For the command queue (#4), allocate command space + one big + * command for scan, since scan command is very huge; the system will + * not have two scans at the same time, so only one is needed. + * For normal Tx queues (all other queues), no super-size command + * space is needed. + */ + len = sizeof(struct iwl4965_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; - rc = iwl_tx_queue_alloc(priv, txq, txq_id); + /* Alloc driver data array and TFD circular buffer */ + rc = iwl4965_tx_queue_alloc(priv, txq, txq_id); if (rc) { pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); @@ -341,26 +369,29 @@ int iwl_tx_queue_init(struct iwl_priv *priv, txq->need_update = 0; /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + * iwl4965_queue_inc_wrap and iwl4965_queue_dec_wrap are broken. */ BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); - iwl_hw_tx_queue_init(priv, txq); + /* Initialize queue's high/low-water marks, and head/tail indexes */ + iwl4965_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id); + + /* Tell device where to find queue */ + iwl4965_hw_tx_queue_init(priv, txq); return 0; } /** - * iwl_tx_queue_free - Deallocate DMA queue. + * iwl4965_tx_queue_free - Deallocate DMA queue. * @txq: Transmit queue to deallocate. * * Empty queue by removing and destroying all BD's. - * Free all buffers. txq itself is not freed. - * + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. */ -void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) +void iwl4965_tx_queue_free(struct iwl4965_priv *priv, struct iwl4965_tx_queue *txq) { - struct iwl_queue *q = &txq->q; + struct iwl4965_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; int len; @@ -368,45 +399,48 @@ void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq) return; /* first, empty all BD's */ - for (; q->first_empty != q->last_used; - q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) - iwl_hw_txq_free_tfd(priv, txq); + for (; q->write_ptr != q->read_ptr; + q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) + iwl4965_hw_txq_free_tfd(priv, txq); - len = sizeof(struct iwl_cmd) * q->n_window; + len = sizeof(struct iwl4965_cmd) * q->n_window; if (q->id == IWL_CMD_QUEUE_NUM) len += IWL_MAX_SCAN_SIZE; + /* De-alloc array of command/tx buffers */ pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd); - /* free buffers belonging to queue itself */ + /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * + pci_free_consistent(dev, sizeof(struct iwl4965_tfd_frame) * 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; } - /* 0 fill whole structure */ + /* 0-fill queue descriptor structure */ memset(txq, 0, sizeof(*txq)); } -const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +const u8 iwl4965_broadcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /*************** STATION TABLE MANAGEMENT **** - * - * NOTE: This needs to be overhauled to better synchronize between - * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c - * - * mac80211 should also be examined to determine if sta_info is duplicating + * mac80211 should be examined to determine if sta_info is duplicating * the functionality provided here */ /**************************************************************/ -#if 0 /* temparary disable till we add real remove station */ -static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) +#if 0 /* temporary disable till we add real remove station */ +/** + * iwl4965_remove_station - Remove driver's knowledge of station. + * + * NOTE: This does not remove station from device's station table. + */ +static u8 iwl4965_remove_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) { int index = IWL_INVALID_STATION; int i; @@ -443,7 +477,12 @@ out: } #endif -static void iwl_clear_stations_table(struct iwl_priv *priv) +/** + * iwl4965_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ +static void iwl4965_clear_stations_table(struct iwl4965_priv *priv) { unsigned long flags; @@ -455,11 +494,15 @@ static void iwl_clear_stations_table(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->sta_lock, flags); } -u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) +/** + * iwl4965_add_station_flags - Add station to tables in driver and device + */ +u8 iwl4965_add_station_flags(struct iwl4965_priv *priv, const u8 *addr, + int is_ap, u8 flags, void *ht_data) { int i; int index = IWL_INVALID_STATION; - struct iwl_station_entry *station; + struct iwl4965_station_entry *station; unsigned long flags_spin; DECLARE_MAC_BUF(mac); @@ -482,8 +525,8 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) } - /* These twh conditions has the same outcome but keep them separate - since they have different meaning */ + /* These two conditions have the same outcome, but keep them separate + since they have different meanings */ if (unlikely(index == IWL_INVALID_STATION)) { spin_unlock_irqrestore(&priv->sta_lock, flags_spin); return index; @@ -501,28 +544,32 @@ u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags) station->used = 1; priv->num_stations++; - memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + /* Set up the REPLY_ADD_STA command to send to device */ + memset(&station->sta, 0, sizeof(struct iwl4965_addsta_cmd)); memcpy(station->sta.sta.addr, addr, ETH_ALEN); station->sta.mode = 0; station->sta.sta.sta_id = index; station->sta.station_flags = 0; -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT /* BCAST station and IBSS stations do not work in HT mode */ if (index != priv->hw_setting.bcast_sta_id && priv->iw_mode != IEEE80211_IF_TYPE_IBSS) - iwl4965_set_ht_add_station(priv, index); -#endif /*CONFIG_IWLWIFI_HT*/ + iwl4965_set_ht_add_station(priv, index, + (struct ieee80211_ht_info *) ht_data); +#endif /*CONFIG_IWL4965_HT*/ spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - iwl_send_add_station(priv, &station->sta, flags); + + /* Add station to device's station table */ + iwl4965_send_add_station(priv, &station->sta, flags); return index; } /*************** DRIVER STATUS FUNCTIONS *****/ -static inline int iwl_is_ready(struct iwl_priv *priv) +static inline int iwl4965_is_ready(struct iwl4965_priv *priv) { /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are * set but EXIT_PENDING is not */ @@ -531,29 +578,29 @@ static inline int iwl_is_ready(struct iwl_priv *priv) !test_bit(STATUS_EXIT_PENDING, &priv->status); } -static inline int iwl_is_alive(struct iwl_priv *priv) +static inline int iwl4965_is_alive(struct iwl4965_priv *priv) { return test_bit(STATUS_ALIVE, &priv->status); } -static inline int iwl_is_init(struct iwl_priv *priv) +static inline int iwl4965_is_init(struct iwl4965_priv *priv) { return test_bit(STATUS_INIT, &priv->status); } -static inline int iwl_is_rfkill(struct iwl_priv *priv) +static inline int iwl4965_is_rfkill(struct iwl4965_priv *priv) { return test_bit(STATUS_RF_KILL_HW, &priv->status) || test_bit(STATUS_RF_KILL_SW, &priv->status); } -static inline int iwl_is_ready_rf(struct iwl_priv *priv) +static inline int iwl4965_is_ready_rf(struct iwl4965_priv *priv) { - if (iwl_is_rfkill(priv)) + if (iwl4965_is_rfkill(priv)) return 0; - return iwl_is_ready(priv); + return iwl4965_is_ready(priv); } /*************** HOST COMMAND QUEUE FUNCTIONS *****/ @@ -618,7 +665,7 @@ static const char *get_cmd_string(u8 cmd) #define HOST_COMPLETE_TIMEOUT (HZ / 2) /** - * iwl_enqueue_hcmd - enqueue a uCode command + * iwl4965_enqueue_hcmd - enqueue a uCode command * @priv: device private data point * @cmd: a point to the ucode command structure * @@ -626,13 +673,13 @@ static const char *get_cmd_string(u8 cmd) * failed. On success, it turns the index (> 0) of command in the * command queue. */ -static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) { - struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; - struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; + struct iwl4965_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl4965_queue *q = &txq->q; + struct iwl4965_tfd_frame *tfd; u32 *control_flags; - struct iwl_cmd *out_cmd; + struct iwl4965_cmd *out_cmd; u32 idx; u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr)); dma_addr_t phys_addr; @@ -645,19 +692,19 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); - if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { + if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; } spin_lock_irqsave(&priv->hcmd_lock, flags); - tfd = &txq->bd[q->first_empty]; + tfd = &txq->bd[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE); + idx = get_cmd_index(q, q->write_ptr, cmd->meta.flags & CMD_SIZE_HUGE); out_cmd = &txq->cmd[idx]; out_cmd->hdr.cmd = cmd->id; @@ -669,30 +716,34 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.flags = 0; out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) | - INDEX_TO_SEQ(q->first_empty)); + 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); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); + offsetof(struct iwl4965_cmd, hdr); + iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, " "%d bytes at %d[%d]:%d\n", get_cmd_string(out_cmd->hdr.cmd), out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), - fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM); + fix_size, q->write_ptr, idx, IWL_CMD_QUEUE_NUM); txq->need_update = 1; + + /* Set up entry in queue's byte count circular buffer */ ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0); - q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); - iwl_tx_queue_update_write_ptr(priv, txq); + + /* Increment and update queue's write index */ + q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd); + iwl4965_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->hcmd_lock, flags); return ret ? ret : idx; } -int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl4965_send_cmd_async(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) { int ret; @@ -707,16 +758,16 @@ int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return -EBUSY; - ret = iwl_enqueue_hcmd(priv, cmd); + ret = iwl4965_enqueue_hcmd(priv, cmd); if (ret < 0) { - IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } return 0; } -int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl4965_send_cmd_sync(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) { int cmd_idx; int ret; @@ -738,10 +789,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (cmd->meta.flags & CMD_WANT_SKB) cmd->meta.source = &cmd->meta; - cmd_idx = iwl_enqueue_hcmd(priv, cmd); + cmd_idx = iwl4965_enqueue_hcmd(priv, cmd); if (cmd_idx < 0) { ret = cmd_idx; - IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n", + IWL_ERROR("Error sending %s: iwl4965_enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); goto out; } @@ -785,7 +836,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) cancel: if (cmd->meta.flags & CMD_WANT_SKB) { - struct iwl_cmd *qcmd; + struct iwl4965_cmd *qcmd; /* Cancel the CMD_WANT_SKB flag for the cmd in the * TX cmd queue. Otherwise in case the cmd comes @@ -804,64 +855,75 @@ out: return ret; } -int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +int iwl4965_send_cmd(struct iwl4965_priv *priv, struct iwl4965_host_cmd *cmd) { - /* A command can not be asynchronous AND expect an SKB to be set. */ - BUG_ON((cmd->meta.flags & CMD_ASYNC) && - (cmd->meta.flags & CMD_WANT_SKB)); - if (cmd->meta.flags & CMD_ASYNC) - return iwl_send_cmd_async(priv, cmd); + return iwl4965_send_cmd_async(priv, cmd); - return iwl_send_cmd_sync(priv, cmd); + return iwl4965_send_cmd_sync(priv, cmd); } -int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data) +int iwl4965_send_cmd_pdu(struct iwl4965_priv *priv, u8 id, u16 len, const void *data) { - struct iwl_host_cmd cmd = { + struct iwl4965_host_cmd cmd = { .id = id, .len = len, .data = data, }; - return iwl_send_cmd_sync(priv, &cmd); + return iwl4965_send_cmd_sync(priv, &cmd); } -static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val) +static int __must_check iwl4965_send_cmd_u32(struct iwl4965_priv *priv, u8 id, u32 val) { - struct iwl_host_cmd cmd = { + struct iwl4965_host_cmd cmd = { .id = id, .len = sizeof(val), .data = &val, }; - return iwl_send_cmd_sync(priv, &cmd); + return iwl4965_send_cmd_sync(priv, &cmd); } -int iwl_send_statistics_request(struct iwl_priv *priv) +int iwl4965_send_statistics_request(struct iwl4965_priv *priv) { - return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); + return iwl4965_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0); } /** - * iwl_rxon_add_station - add station into station table. + * iwl4965_rxon_add_station - add station into station table. * * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling the this fnction -*/ -static int iwl_rxon_add_station(struct iwl_priv *priv, + * NOTE: mutex must be held before calling this fnction + */ +static int iwl4965_rxon_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) { u8 sta_id; - sta_id = iwl_add_station(priv, addr, is_ap, 0); + /* Add station to device's station table */ +#ifdef CONFIG_IWL4965_HT + struct ieee80211_conf *conf = &priv->hw->conf; + struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; + + if ((is_ap) && + (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && + (priv->iw_mode == IEEE80211_IF_TYPE_STA)) + sta_id = iwl4965_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); + else +#endif /* CONFIG_IWL4965_HT */ + sta_id = iwl4965_add_station_flags(priv, addr, is_ap, + 0, NULL); + + /* Set up default rate scaling table in device's station table */ iwl4965_add_station(priv, addr, is_ap); return sta_id; } /** - * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON + * iwl4965_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz * @channel: Any channel valid for the requested phymode @@ -870,9 +932,10 @@ static int iwl_rxon_add_station(struct iwl_priv *priv, * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) +static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode, + u16 channel) { - if (!iwl_get_channel_info(priv, phymode, channel)) { + if (!iwl4965_get_channel_info(priv, phymode, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", channel, phymode); return -EINVAL; @@ -896,13 +959,13 @@ static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel) } /** - * iwl_check_rxon_cmd - validate RXON structure is valid + * 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 iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +static int iwl4965_check_rxon_cmd(struct iwl4965_rxon_cmd *rxon) { int error = 0; int counter = 1; @@ -962,21 +1025,21 @@ static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon) le16_to_cpu(rxon->channel)); if (error) { - IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n"); + IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); return -1; } return 0; } /** - * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit - * @priv: staging_rxon is comapred to active_rxon + * 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 sufficient to require a new - * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1 - * to indicate a new tune is required. + * 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 iwl_full_rxon_required(struct iwl_priv *priv) +static int iwl4965_full_rxon_required(struct iwl4965_priv *priv) { /* These items are only settable from the full RXON command */ @@ -1016,19 +1079,19 @@ static int iwl_full_rxon_required(struct iwl_priv *priv) return 0; } -static int iwl_send_rxon_assoc(struct iwl_priv *priv) +static int iwl4965_send_rxon_assoc(struct iwl4965_priv *priv) { int rc = 0; - struct iwl_rx_packet *res = NULL; - struct iwl_rxon_assoc_cmd rxon_assoc; - struct iwl_host_cmd cmd = { + struct iwl4965_rx_packet *res = NULL; + struct iwl4965_rxon_assoc_cmd rxon_assoc; + struct iwl4965_host_cmd cmd = { .id = REPLY_RXON_ASSOC, .len = sizeof(rxon_assoc), .meta.flags = CMD_WANT_SKB, .data = &rxon_assoc, }; - const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon; - const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon; + const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon; + const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon; if ((rxon1->flags == rxon2->flags) && (rxon1->filter_flags == rxon2->filter_flags) && @@ -1054,11 +1117,11 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv) priv->staging_rxon.ofdm_ht_dual_stream_basic_rates; rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain; - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl4965_send_cmd_sync(priv, &cmd); if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n"); rc = -EIO; @@ -1071,37 +1134,37 @@ static int iwl_send_rxon_assoc(struct iwl_priv *priv) } /** - * iwl_commit_rxon - commit staging_rxon to hardware + * iwl4965_commit_rxon - commit staging_rxon to hardware * - * The RXON command in staging_rxon is commited to the hardware and + * 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 iwl_commit_rxon(struct iwl_priv *priv) +static int iwl4965_commit_rxon(struct iwl4965_priv *priv) { /* cast away the const for active_rxon in this function */ - struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; + struct iwl4965_rxon_cmd *active_rxon = (void *)&priv->active_rxon; DECLARE_MAC_BUF(mac); int rc = 0; - if (!iwl_is_alive(priv)) + if (!iwl4965_is_alive(priv)) return -1; /* always get timestamp with Rx frame */ priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK; - rc = iwl_check_rxon_cmd(&priv->staging_rxon); + rc = iwl4965_check_rxon_cmd(&priv->staging_rxon); if (rc) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } /* If we don't need to send a full RXON, we can use - * iwl_rxon_assoc_cmd which is used to reconfigure filter + * iwl4965_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ - if (!iwl_full_rxon_required(priv)) { - rc = iwl_send_rxon_assoc(priv); + if (!iwl4965_full_rxon_required(priv)) { + rc = iwl4965_send_rxon_assoc(priv); if (rc) { IWL_ERROR("Error setting RXON_ASSOC " "configuration (%d).\n", rc); @@ -1116,25 +1179,25 @@ static int iwl_commit_rxon(struct iwl_priv *priv) /* station table will be cleared */ priv->assoc_station_added = 0; -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; if (!priv->error_recovering) priv->start_calib = 0; iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWLWIFI_SENSITIVITY */ +#endif /* CONFIG_IWL4965_SENSITIVITY */ /* 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) && + if (iwl4965_is_associated(priv) && (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) { IWL_DEBUG_INFO("Toggling associated bit on current RXON\n"); active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), + rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl4965_rxon_cmd), &priv->active_rxon); /* If the mask clearing failed then we set @@ -1157,35 +1220,35 @@ static int iwl_commit_rxon(struct iwl_priv *priv) print_mac(mac, priv->staging_rxon.bssid_addr)); /* Apply the new configuration */ - rc = iwl_send_cmd_pdu(priv, REPLY_RXON, - sizeof(struct iwl_rxon_cmd), &priv->staging_rxon); + rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON, + sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon); if (rc) { IWL_ERROR("Error setting new configuration (%d).\n", rc); return rc; } - iwl_clear_stations_table(priv); + iwl4965_clear_stations_table(priv); -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY if (!priv->error_recovering) priv->start_calib = 0; priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT; iwl4965_init_sensitivity(priv, CMD_ASYNC, 1); -#endif /* CONFIG_IWLWIFI_SENSITIVITY */ +#endif /* CONFIG_IWL4965_SENSITIVITY */ memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon)); /* 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 */ - rc = iwl_hw_reg_send_txpower(priv); + rc = iwl4965_hw_reg_send_txpower(priv); if (rc) { IWL_ERROR("Error setting Tx power (%d).\n", rc); return rc; } /* Add the broadcast address so we can send broadcast frames */ - if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) == + if (iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0) == IWL_INVALID_STATION) { IWL_ERROR("Error adding BROADCAST address for transmit.\n"); return -EIO; @@ -1193,9 +1256,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv) /* 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 (iwl_is_associated(priv) && + if (iwl4965_is_associated(priv) && (priv->iw_mode == IEEE80211_IF_TYPE_STA)) { - if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) + if (iwl4965_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1) == IWL_INVALID_STATION) { IWL_ERROR("Error adding AP address for transmit.\n"); return -EIO; @@ -1206,9 +1269,9 @@ static int iwl_commit_rxon(struct iwl_priv *priv) return 0; } -static int iwl_send_bt_config(struct iwl_priv *priv) +static int iwl4965_send_bt_config(struct iwl4965_priv *priv) { - struct iwl_bt_cmd bt_cmd = { + struct iwl4965_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, @@ -1216,15 +1279,15 @@ static int iwl_send_bt_config(struct iwl_priv *priv) .kill_cts_mask = 0, }; - return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl_bt_cmd), &bt_cmd); + return iwl4965_send_cmd_pdu(priv, REPLY_BT_CONFIG, + sizeof(struct iwl4965_bt_cmd), &bt_cmd); } -static int iwl_send_scan_abort(struct iwl_priv *priv) +static int iwl4965_send_scan_abort(struct iwl4965_priv *priv) { int rc = 0; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { + struct iwl4965_rx_packet *res; + struct iwl4965_host_cmd cmd = { .id = REPLY_SCAN_ABORT_CMD, .meta.flags = CMD_WANT_SKB, }; @@ -1237,13 +1300,13 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return 0; } - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl4965_send_cmd_sync(priv, &cmd); if (rc) { clear_bit(STATUS_SCAN_ABORTING, &priv->status); return rc; } - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; if (res->u.status != CAN_ABORT_STATUS) { /* The scan abort will return 1 for success or * 2 for "failure". A failure condition can be @@ -1261,8 +1324,8 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) return rc; } -static int iwl_card_state_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, +static int iwl4965_card_state_sync_callback(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct sk_buff *skb) { return 1; @@ -1271,16 +1334,16 @@ static int iwl_card_state_sync_callback(struct iwl_priv *priv, /* * CARD_STATE_CMD * - * Use: Sets the internal card state to enable, disable, or halt + * Use: Sets the device's internal card state to enable, disable, or halt * * When in the 'enable' state the card operates as normal. * When in the 'disable' state, the card enters into a low power mode. * When in the 'halt' state, the card is shut down and must be fully * restarted to come back on. */ -static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) +static int iwl4965_send_card_state(struct iwl4965_priv *priv, u32 flags, u8 meta_flag) { - struct iwl_host_cmd cmd = { + struct iwl4965_host_cmd cmd = { .id = REPLY_CARD_STATE_CMD, .len = sizeof(u32), .data = &flags, @@ -1288,22 +1351,22 @@ static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag) }; if (meta_flag & CMD_ASYNC) - cmd.meta.u.callback = iwl_card_state_sync_callback; + cmd.meta.u.callback = iwl4965_card_state_sync_callback; - return iwl_send_cmd(priv, &cmd); + return iwl4965_send_cmd(priv, &cmd); } -static int iwl_add_sta_sync_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) +static int iwl4965_add_sta_sync_callback(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct sk_buff *skb) { - struct iwl_rx_packet *res = NULL; + struct iwl4965_rx_packet *res = NULL; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); return 1; } - res = (struct iwl_rx_packet *)skb->data; + res = (struct iwl4965_rx_packet *)skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -1321,29 +1384,29 @@ static int iwl_add_sta_sync_callback(struct iwl_priv *priv, return 1; } -int iwl_send_add_station(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags) +int iwl4965_send_add_station(struct iwl4965_priv *priv, + struct iwl4965_addsta_cmd *sta, u8 flags) { - struct iwl_rx_packet *res = NULL; + struct iwl4965_rx_packet *res = NULL; int rc = 0; - struct iwl_host_cmd cmd = { + struct iwl4965_host_cmd cmd = { .id = REPLY_ADD_STA, - .len = sizeof(struct iwl_addsta_cmd), + .len = sizeof(struct iwl4965_addsta_cmd), .meta.flags = flags, .data = sta, }; if (flags & CMD_ASYNC) - cmd.meta.u.callback = iwl_add_sta_sync_callback; + cmd.meta.u.callback = iwl4965_add_sta_sync_callback; else cmd.meta.flags |= CMD_WANT_SKB; - rc = iwl_send_cmd(priv, &cmd); + rc = iwl4965_send_cmd(priv, &cmd); if (rc || (flags & CMD_ASYNC)) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data; if (res->hdr.flags & IWL_CMD_FAILED_MSK) { IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n", res->hdr.flags); @@ -1368,7 +1431,7 @@ int iwl_send_add_station(struct iwl_priv *priv, return rc; } -static int iwl_update_sta_key_info(struct iwl_priv *priv, +static int iwl4965_update_sta_key_info(struct iwl4965_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) { @@ -1384,7 +1447,6 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv, break; case ALG_TKIP: case ALG_WEP: - return -EINVAL; default: return -EINVAL; } @@ -1403,28 +1465,28 @@ static int iwl_update_sta_key_info(struct iwl_priv *priv, spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n"); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); return 0; } -static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id) +static int iwl4965_clear_sta_key_info(struct iwl4965_priv *priv, u8 sta_id) { unsigned long flags; spin_lock_irqsave(&priv->sta_lock, flags); - memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key)); - memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo)); + memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key)); + memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo)); priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; spin_unlock_irqrestore(&priv->sta_lock, flags); IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n"); - iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0); + iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0); return 0; } -static void iwl_clear_free_frames(struct iwl_priv *priv) +static void iwl4965_clear_free_frames(struct iwl4965_priv *priv) { struct list_head *element; @@ -1434,7 +1496,7 @@ static void iwl_clear_free_frames(struct iwl_priv *priv) while (!list_empty(&priv->free_frames)) { element = priv->free_frames.next; list_del(element); - kfree(list_entry(element, struct iwl_frame, list)); + kfree(list_entry(element, struct iwl4965_frame, list)); priv->frames_count--; } @@ -1445,9 +1507,9 @@ static void iwl_clear_free_frames(struct iwl_priv *priv) } } -static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) +static struct iwl4965_frame *iwl4965_get_free_frame(struct iwl4965_priv *priv) { - struct iwl_frame *frame; + struct iwl4965_frame *frame; struct list_head *element; if (list_empty(&priv->free_frames)) { frame = kzalloc(sizeof(*frame), GFP_KERNEL); @@ -1462,21 +1524,21 @@ static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv) element = priv->free_frames.next; list_del(element); - return list_entry(element, struct iwl_frame, list); + return list_entry(element, struct iwl4965_frame, list); } -static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) +static void iwl4965_free_frame(struct iwl4965_priv *priv, struct iwl4965_frame *frame) { memset(frame, 0, sizeof(*frame)); list_add(&frame->list, &priv->free_frames); } -unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, +unsigned int iwl4965_fill_beacon_frame(struct iwl4965_priv *priv, struct ieee80211_hdr *hdr, const u8 *dest, int left) { - if (!iwl_is_associated(priv) || !priv->ibss_beacon || + if (!iwl4965_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) && (priv->iw_mode != IEEE80211_IF_TYPE_AP))) return 0; @@ -1489,10 +1551,11 @@ unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -int iwl_rate_index_from_plcp(int plcp) +int iwl4965_rate_index_from_plcp(int plcp) { int i = 0; + /* 4965 HT rate format */ if (plcp & RATE_MCS_HT_MSK) { i = (plcp & 0xff); @@ -1506,35 +1569,37 @@ int iwl_rate_index_from_plcp(int plcp) if ((i >= IWL_FIRST_OFDM_RATE) && (i <= IWL_LAST_OFDM_RATE)) return i; + + /* 4965 legacy rate format, search for match in table */ } else { - for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) - if (iwl_rates[i].plcp == (plcp &0xFF)) + for (i = 0; i < ARRAY_SIZE(iwl4965_rates); i++) + if (iwl4965_rates[i].plcp == (plcp &0xFF)) return i; } return -1; } -static u8 iwl_rate_get_lowest_plcp(int rate_mask) +static u8 iwl4965_rate_get_lowest_plcp(int rate_mask) { u8 i; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; - i = iwl_rates[i].next_ieee) { + i = iwl4965_rates[i].next_ieee) { if (rate_mask & (1 << i)) - return iwl_rates[i].plcp; + return iwl4965_rates[i].plcp; } return IWL_RATE_INVALID; } -static int iwl_send_beacon_cmd(struct iwl_priv *priv) +static int iwl4965_send_beacon_cmd(struct iwl4965_priv *priv) { - struct iwl_frame *frame; + struct iwl4965_frame *frame; unsigned int frame_size; int rc; u8 rate; - frame = iwl_get_free_frame(priv); + frame = iwl4965_get_free_frame(priv); if (!frame) { IWL_ERROR("Could not obtain free frame buffer for beacon " @@ -1543,22 +1608,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) } if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & + rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xFF0); if (rate == IWL_INVALID_RATE) rate = IWL_RATE_6M_PLCP; } else { - rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); + rate = iwl4965_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); if (rate == IWL_INVALID_RATE) rate = IWL_RATE_1M_PLCP; } - frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); - rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, + rc = iwl4965_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); - iwl_free_frame(priv, frame); + iwl4965_free_frame(priv, frame); return rc; } @@ -1569,22 +1634,22 @@ static int iwl_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac) +static void get_eeprom_mac(struct iwl4965_priv *priv, u8 *mac) { memcpy(mac, priv->eeprom.mac_address, 6); } /** - * iwl_eeprom_init - read EEPROM contents + * iwl4965_eeprom_init - read EEPROM contents * - * Load the EEPROM from adapter into priv->eeprom + * Load the EEPROM contents from adapter into priv->eeprom * * NOTE: This routine uses the non-debug IO access functions. */ -int iwl_eeprom_init(struct iwl_priv *priv) +int iwl4965_eeprom_init(struct iwl4965_priv *priv) { - u16 *e = (u16 *)&priv->eeprom; - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + __le16 *e = (__le16 *)&priv->eeprom; + u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP); u32 r; int sz = sizeof(priv->eeprom); int rc; @@ -1602,20 +1667,21 @@ int iwl_eeprom_init(struct iwl_priv *priv) return -ENOENT; } - rc = iwl_eeprom_aqcuire_semaphore(priv); + /* Make sure driver (instead of uCode) is allowed to read EEPROM */ + rc = iwl4965_eeprom_acquire_semaphore(priv); if (rc < 0) { - IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n"); + IWL_ERROR("Failed to acquire EEPROM semaphore.\n"); return -ENOENT; } /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + _iwl4965_write32(priv, CSR_EEPROM_REG, addr << 1); + _iwl4965_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT; i += IWL_EEPROM_ACCESS_DELAY) { - r = _iwl_read_restricted(priv, CSR_EEPROM_REG); + r = _iwl4965_read_direct32(priv, CSR_EEPROM_REG); if (r & CSR_EEPROM_REG_READ_VALID_MSK) break; udelay(IWL_EEPROM_ACCESS_DELAY); @@ -1626,12 +1692,12 @@ int iwl_eeprom_init(struct iwl_priv *priv) rc = -ETIMEDOUT; goto done; } - e[addr / 2] = le16_to_cpu(r >> 16); + e[addr / 2] = cpu_to_le16(r >> 16); } rc = 0; done: - iwl_eeprom_release_semaphore(priv); + iwl4965_eeprom_release_semaphore(priv); return rc; } @@ -1640,22 +1706,20 @@ done: * Misc. internal state and helper functions * ******************************************************************************/ -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG /** - * iwl_report_frame - dump frame to syslog during debug sessions + * iwl4965_report_frame - dump frame to syslog during debug sessions * - * hack this function to show different aspects of received frames, + * You may hack this function to show different aspects of received frames, * including selective frame dumps. * group100 parameter selects whether to show 1 out of 100 good frames. * - * TODO: ieee80211_hdr stuff is common to 3945 and 4965, so frame type - * info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats) - * is 3945-specific and gives bad output for 4965. Need to split the - * functionality, keep common stuff here. + * TODO: This was originally written for 3945, need to audit for + * proper operation with 4965. */ -void iwl_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, +void iwl4965_report_frame(struct iwl4965_priv *priv, + struct iwl4965_rx_packet *pkt, struct ieee80211_hdr *header, int group100) { u32 to_us; @@ -1677,9 +1741,9 @@ void iwl_report_frame(struct iwl_priv *priv, u8 agc; u16 sig_avg; u16 noise_diff; - struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); - struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); - struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt); + struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); + struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); + struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); u8 *data = IWL_RX_DATA(pkt); /* MAC header */ @@ -1755,11 +1819,11 @@ void iwl_report_frame(struct iwl_priv *priv, else title = "Frame"; - rate = iwl_rate_index_from_plcp(rate_sym); + rate = iwl4965_rate_index_from_plcp(rate_sym); if (rate == -1) rate = 0; else - rate = iwl_rates[rate].ieee / 2; + rate = iwl4965_rates[rate].ieee / 2; /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -1781,25 +1845,25 @@ void iwl_report_frame(struct iwl_priv *priv, } } if (print_dump) - iwl_print_hex_dump(IWL_DL_RX, data, length); + iwl4965_print_hex_dump(IWL_DL_RX, data, length); } #endif -static void iwl_unset_hw_setting(struct iwl_priv *priv) +static void iwl4965_unset_hw_setting(struct iwl4965_priv *priv) { if (priv->hw_setting.shared_virt) pci_free_consistent(priv->pci_dev, - sizeof(struct iwl_shared), + sizeof(struct iwl4965_shared), priv->hw_setting.shared_virt, priv->hw_setting.shared_phys); } /** - * iwl_supported_rate_to_ie - fill in the supported rate in IE field + * iwl4965_supported_rate_to_ie - fill in the supported rate in IE field * * return : set the bit for each supported rate insert in ie */ -static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, +static u16 iwl4965_supported_rate_to_ie(u8 *ie, u16 supported_rate, u16 basic_rate, int *left) { u16 ret_rates = 0, bit; @@ -1810,7 +1874,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { if (bit & supported_rate) { ret_rates |= bit; - rates[*cnt] = iwl_rates[i].ieee | + rates[*cnt] = iwl4965_rates[i].ieee | ((bit & basic_rate) ? 0x80 : 0x00); (*cnt)++; (*left)--; @@ -1823,22 +1887,25 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, return ret_rates; } -#ifdef CONFIG_IWLWIFI_HT -void static iwl_set_ht_capab(struct ieee80211_hw *hw, - struct ieee80211_ht_capability *ht_cap, - u8 use_wide_chan); +#ifdef CONFIG_IWL4965_HT +void static iwl4965_set_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_cap *ht_cap, + u8 use_current_config); #endif /** - * iwl_fill_probe_req - fill in all required fields and IE for probe request + * iwl4965_fill_probe_req - fill in all required fields and IE for probe request */ -static u16 iwl_fill_probe_req(struct iwl_priv *priv, +static u16 iwl4965_fill_probe_req(struct iwl4965_priv *priv, struct ieee80211_mgmt *frame, int left, int is_direct) { int len = 0; u8 *pos = NULL; - u16 active_rates, ret_rates, cck_rates; + u16 active_rates, ret_rates, cck_rates, active_rate_basic; +#ifdef CONFIG_IWL4965_HT + struct ieee80211_hw_mode *mode; +#endif /* CONFIG_IWL4965_HT */ /* Make sure there is enough space for the probe request, * two mandatory IEs and the data */ @@ -1848,9 +1915,9 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, len += 24; frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->da, iwl4965_broadcast_addr, ETH_ALEN); memcpy(frame->sa, priv->mac_addr, ETH_ALEN); - memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN); + memcpy(frame->bssid, iwl4965_broadcast_addr, ETH_ALEN); frame->seq_ctrl = 0; /* fill in our indirect SSID IE */ @@ -1888,17 +1955,19 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, *pos++ = WLAN_EID_SUPP_RATES; *pos = 0; - priv->active_rate = priv->rates_mask; - active_rates = priv->active_rate; - priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; + /* exclude 60M rate */ + active_rates = priv->rates_mask; + active_rates &= ~IWL_RATE_60M_MASK; + + active_rate_basic = active_rates & IWL_BASIC_RATES_MASK; cck_rates = IWL_CCK_RATES_MASK & active_rates; - ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, - priv->active_rate_basic, &left); + ret_rates = iwl4965_supported_rate_to_ie(pos, cck_rates, + active_rate_basic, &left); active_rates &= ~ret_rates; - ret_rates = iwl_supported_rate_to_ie(pos, active_rates, - priv->active_rate_basic, &left); + ret_rates = iwl4965_supported_rate_to_ie(pos, active_rates, + active_rate_basic, &left); active_rates &= ~ret_rates; len += 2 + *pos; @@ -1914,25 +1983,22 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, /* ... fill it in... */ *pos++ = WLAN_EID_EXT_SUPP_RATES; *pos = 0; - iwl_supported_rate_to_ie(pos, active_rates, - priv->active_rate_basic, &left); + iwl4965_supported_rate_to_ie(pos, active_rates, + active_rate_basic, &left); if (*pos > 0) len += 2 + *pos; -#ifdef CONFIG_IWLWIFI_HT - if (is_direct && priv->is_ht_enabled) { - u8 use_wide_chan = 1; - - if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) - use_wide_chan = 0; +#ifdef CONFIG_IWL4965_HT + mode = priv->hw->conf.mode; + if (mode->ht_info.ht_supported) { pos += (*pos) + 1; *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_capability); - iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos, - use_wide_chan); - len += 2 + sizeof(struct ieee80211_ht_capability); + *pos++ = sizeof(struct ieee80211_ht_cap); + iwl4965_set_ht_capab(priv->hw, + (struct ieee80211_ht_cap *)pos, 0); + len += 2 + sizeof(struct ieee80211_ht_cap); } -#endif /*CONFIG_IWLWIFI_HT */ +#endif /*CONFIG_IWL4965_HT */ fill_end: return (u16)len; @@ -1941,16 +2007,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, /* * QoS support */ -#ifdef CONFIG_IWLWIFI_QOS -static int iwl_send_qos_params_command(struct iwl_priv *priv, - struct iwl_qosparam_cmd *qos) +#ifdef CONFIG_IWL4965_QOS +static int iwl4965_send_qos_params_command(struct iwl4965_priv *priv, + struct iwl4965_qosparam_cmd *qos) { - return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM, - sizeof(struct iwl_qosparam_cmd), qos); + return iwl4965_send_cmd_pdu(priv, REPLY_QOS_PARAM, + sizeof(struct iwl4965_qosparam_cmd), qos); } -static void iwl_reset_qos(struct iwl_priv *priv) +static void iwl4965_reset_qos(struct iwl4965_priv *priv) { u16 cw_min = 15; u16 cw_max = 1023; @@ -2037,13 +2103,10 @@ static void iwl_reset_qos(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl_activate_qos(struct iwl_priv *priv, u8 force) +static void iwl4965_activate_qos(struct iwl4965_priv *priv, u8 force) { unsigned long flags; - if (priv == NULL) - return; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -2057,23 +2120,28 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) !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; +#ifdef CONFIG_IWL4965_HT + if (priv->current_ht_config.is_ht) + priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK; +#endif /* CONFIG_IWL4965_HT */ + spin_unlock_irqrestore(&priv->lock, flags); - if (force || iwl_is_associated(priv)) { - IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", - priv->qos_data.qos_active); + if (force || iwl4965_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_qos_params_command(priv, + iwl4965_send_qos_params_command(priv, &(priv->qos_data.def_qos_parm)); } } -#endif /* CONFIG_IWLWIFI_QOS */ +#endif /* CONFIG_IWL4965_QOS */ /* * Power management (not Tx power!) functions */ @@ -2091,7 +2159,7 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) /* 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 iwl4965_power_vec_entry range_0[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0}, @@ -2101,7 +2169,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = { }; /* for tim > 10 */ -static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { +static struct iwl4965_power_vec_entry range_1[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, @@ -2114,11 +2182,11 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = { SLP_VEC(4, 7, 10, 10, 0xFF)}, 0} }; -int iwl_power_init_handle(struct iwl_priv *priv) +int iwl4965_power_init_handle(struct iwl4965_priv *priv) { int rc = 0, i; - struct iwl_power_mgr *pow_data; - int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC; + struct iwl4965_power_mgr *pow_data; + int size = sizeof(struct iwl4965_power_vec_entry) * IWL_POWER_AC; u16 pci_pm; IWL_DEBUG_POWER("Initialize power \n"); @@ -2137,7 +2205,7 @@ int iwl_power_init_handle(struct iwl_priv *priv) if (rc != 0) return 0; else { - struct iwl_powertable_cmd *cmd; + struct iwl4965_powertable_cmd *cmd; IWL_DEBUG_POWER("adjust power command flags\n"); @@ -2153,15 +2221,15 @@ int iwl_power_init_handle(struct iwl_priv *priv) return rc; } -static int iwl_update_power_cmd(struct iwl_priv *priv, - struct iwl_powertable_cmd *cmd, u32 mode) +static int iwl4965_update_power_cmd(struct iwl4965_priv *priv, + struct iwl4965_powertable_cmd *cmd, u32 mode) { int rc = 0, i; u8 skip; u32 max_sleep = 0; - struct iwl_power_vec_entry *range; + struct iwl4965_power_vec_entry *range; u8 period = 0; - struct iwl_power_mgr *pow_data; + struct iwl4965_power_mgr *pow_data; if (mode > IWL_POWER_INDEX_5) { IWL_DEBUG_POWER("Error invalid power mode \n"); @@ -2174,7 +2242,7 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, else range = &pow_data->pwr_range_1[1]; - memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd)); + memcpy(cmd, &range[mode].cmd, sizeof(struct iwl4965_powertable_cmd)); #ifdef IWL_MAC80211_DISABLE if (priv->assoc_network != NULL) { @@ -2217,14 +2285,14 @@ static int iwl_update_power_cmd(struct iwl_priv *priv, return rc; } -static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) +static int iwl4965_send_power_mode(struct iwl4965_priv *priv, u32 mode) { - u32 final_mode = mode; + u32 uninitialized_var(final_mode); int rc; - struct iwl_powertable_cmd cmd; + struct iwl4965_powertable_cmd cmd; /* If on battery, set to 3, - * if plugged into AC power, set to CAM ("continuosly aware mode"), + * if plugged into AC power, set to CAM ("continuously aware mode"), * else user level */ switch (mode) { case IWL_POWER_BATTERY: @@ -2240,9 +2308,9 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) cmd.keep_alive_beacons = 0; - iwl_update_power_cmd(priv, &cmd, final_mode); + iwl4965_update_power_cmd(priv, &cmd, final_mode); - rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); + rc = iwl4965_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd); if (final_mode == IWL_POWER_MODE_CAM) clear_bit(STATUS_POWER_PMI, &priv->status); @@ -2252,7 +2320,7 @@ static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode) return rc; } -int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +int iwl4965_is_network_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header) { /* Filter incoming packets to determine if they are targeted toward * this network, discarding packets coming from ourselves */ @@ -2282,7 +2350,7 @@ int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -const char *iwl_get_tx_fail_reason(u32 status) +static const char *iwl4965_get_tx_fail_reason(u32 status) { switch (status & TX_STATUS_MSK) { case TX_STATUS_SUCCESS: @@ -2309,11 +2377,11 @@ const char *iwl_get_tx_fail_reason(u32 status) } /** - * iwl_scan_cancel - Cancel any currently executing HW scan + * iwl4965_scan_cancel - Cancel any currently executing HW scan * * NOTE: priv->mutex is not required before calling this function */ -static int iwl_scan_cancel(struct iwl_priv *priv) +static int iwl4965_scan_cancel(struct iwl4965_priv *priv) { if (!test_bit(STATUS_SCAN_HW, &priv->status)) { clear_bit(STATUS_SCANNING, &priv->status); @@ -2336,17 +2404,17 @@ static int iwl_scan_cancel(struct iwl_priv *priv) } /** - * iwl_scan_cancel_timeout - Cancel any currently executing HW scan + * iwl4965_scan_cancel_timeout - Cancel any currently executing HW scan * @ms: amount of time to wait (in milliseconds) for scan to abort * * NOTE: priv->mutex must be held before calling this function */ -static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +static int iwl4965_scan_cancel_timeout(struct iwl4965_priv *priv, unsigned long ms) { unsigned long now = jiffies; int ret; - ret = iwl_scan_cancel(priv); + ret = iwl4965_scan_cancel(priv); if (ret && ms) { mutex_unlock(&priv->mutex); while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && @@ -2360,7 +2428,7 @@ static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) return ret; } -static void iwl_sequence_reset(struct iwl_priv *priv) +static void iwl4965_sequence_reset(struct iwl4965_priv *priv) { /* Reset ieee stats */ @@ -2371,13 +2439,13 @@ static void iwl_sequence_reset(struct iwl_priv *priv) priv->last_frag_num = -1; priv->last_packet_time = 0; - iwl_scan_cancel(priv); + iwl4965_scan_cancel(priv); } #define MAX_UCODE_BEACON_INTERVAL 4096 #define INTEL_CONN_LISTEN_INTERVAL __constant_cpu_to_le16(0xA) -static __le16 iwl_adjust_beacon_interval(u16 beacon_val) +static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) { u16 new_val = 0; u16 beacon_factor = 0; @@ -2390,7 +2458,7 @@ static __le16 iwl_adjust_beacon_interval(u16 beacon_val) return cpu_to_le16(new_val); } -static void iwl_setup_rxon_timing(struct iwl_priv *priv) +static void iwl4965_setup_rxon_timing(struct iwl4965_priv *priv) { u64 interval_tm_unit; u64 tsf, result; @@ -2420,14 +2488,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); priv->rxon_timing.beacon_interval = - iwl_adjust_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 = - iwl_adjust_beacon_interval(conf->beacon_int); + 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; @@ -2446,14 +2514,14 @@ static void iwl_setup_rxon_timing(struct iwl_priv *priv) le16_to_cpu(priv->rxon_timing.atim_window)); } -static int iwl_scan_initiate(struct iwl_priv *priv) +static int iwl4965_scan_initiate(struct iwl4965_priv *priv) { if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { IWL_ERROR("APs don't scan.\n"); return 0; } - if (!iwl_is_ready_rf(priv)) { + if (!iwl4965_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; } @@ -2480,9 +2548,9 @@ static int iwl_scan_initiate(struct iwl_priv *priv) return 0; } -static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +static int iwl4965_set_rxon_hwcrypto(struct iwl4965_priv *priv, int hw_decrypt) { - struct iwl_rxon_cmd *rxon = &priv->staging_rxon; + struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon; if (hw_decrypt) rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK; @@ -2492,7 +2560,7 @@ static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) return 0; } -static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) +static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode) { if (phymode == MODE_IEEE80211A) { priv->staging_rxon.flags &= @@ -2500,7 +2568,7 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) | RXON_FLG_CCK_MSK); priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; } else { - /* Copied from iwl_bg_post_associate() */ + /* Copied from iwl4965_bg_post_associate() */ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; else @@ -2516,11 +2584,11 @@ static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode) } /* - * initilize rxon structure with default values fromm eeprom + * initialize rxon structure with default values from eeprom */ -static void iwl_connection_init_rx_config(struct iwl_priv *priv) +static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) { - const struct iwl_channel_info *ch_info; + const struct iwl4965_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); @@ -2557,7 +2625,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl_get_channel_info(priv, priv->phymode, + ch_info = iwl4965_get_channel_info(priv, priv->phymode, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2577,7 +2645,7 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv) else priv->phymode = MODE_IEEE80211G; - iwl_set_flags_for_phymode(priv, priv->phymode); + iwl4965_set_flags_for_phymode(priv, priv->phymode); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2593,15 +2661,12 @@ static void iwl_connection_init_rx_config(struct iwl_priv *priv) iwl4965_set_rxon_chain(priv); } -static int iwl_set_mode(struct iwl_priv *priv, int mode) +static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode) { - if (!iwl_is_ready_rf(priv)) - return -EAGAIN; - if (mode == IEEE80211_IF_TYPE_IBSS) { - const struct iwl_channel_info *ch_info; + const struct iwl4965_channel_info *ch_info; - ch_info = iwl_get_channel_info(priv, + ch_info = iwl4965_get_channel_info(priv, priv->phymode, le16_to_cpu(priv->staging_rxon.channel)); @@ -2612,32 +2677,36 @@ static int iwl_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); + + iwl4965_clear_stations_table(priv); + + /* dont commit rxon if rf-kill is on*/ + if (!iwl4965_is_ready_rf(priv)) + return -EAGAIN; + cancel_delayed_work(&priv->scan_check); - if (iwl_scan_cancel_timeout(priv, 100)) { + if (iwl4965_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; } - priv->iw_mode = mode; - - iwl_connection_init_rx_config(priv); - memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); - - iwl_clear_stations_table(priv); - - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); return 0; } -static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, +static void iwl4965_build_tx_cmd_hwcrypto(struct iwl4965_priv *priv, struct ieee80211_tx_control *ctl, - struct iwl_cmd *cmd, + struct iwl4965_cmd *cmd, struct sk_buff *skb_frag, int last_frag) { - struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; + struct iwl4965_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo; switch (keyinfo->alg) { case ALG_CCMP: @@ -2680,8 +2749,8 @@ static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv, /* * handle build REPLY_TX command notification. */ -static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, - struct iwl_cmd *cmd, +static void iwl4965_build_tx_cmd_basic(struct iwl4965_priv *priv, + struct iwl4965_cmd *cmd, struct ieee80211_tx_control *ctrl, struct ieee80211_hdr *hdr, int is_unicast, u8 std_id) @@ -2703,6 +2772,10 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } + if (ieee80211_is_back_request(fc)) + tx_flags |= TX_CMD_FLG_ACK_MSK | TX_CMD_FLG_IMM_BA_RSP_MASK; + + cmd->cmd.tx.sta_id = std_id; if (ieee80211_get_morefrag(hdr)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; @@ -2729,11 +2802,9 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ || (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ) - cmd->cmd.tx.timeout.pm_frame_timeout = - cpu_to_le16(3); + cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); else - cmd->cmd.tx.timeout.pm_frame_timeout = - cpu_to_le16(2); + cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); } else cmd->cmd.tx.timeout.pm_frame_timeout = 0; @@ -2742,40 +2813,47 @@ static void iwl_build_tx_cmd_basic(struct iwl_priv *priv, cmd->cmd.tx.next_frame_len = 0; } -static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) +/** + * iwl4965_get_sta_id - Find station's index within station table + * + * If new IBSS station, create new entry in station table + */ +static int iwl4965_get_sta_id(struct iwl4965_priv *priv, + struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); DECLARE_MAC_BUF(mac); - /* If this frame is broadcast or not data then use the broadcast - * station id */ + /* If this frame is broadcast or management, use broadcast station id */ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || is_multicast_ether_addr(hdr->addr1)) return priv->hw_setting.bcast_sta_id; switch (priv->iw_mode) { - /* If this frame is part of a BSS network (we're a station), then - * we use the AP's station id */ + /* If we are a client station in a BSS network, use the special + * AP station entry (that's the only station we communicate with) */ case IEEE80211_IF_TYPE_STA: return IWL_AP_ID; /* If we are an AP, then find the station, or use BCAST */ case IEEE80211_IF_TYPE_AP: - sta_id = iwl_hw_find_station(priv, hdr->addr1); + sta_id = iwl4965_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; return priv->hw_setting.bcast_sta_id; - /* If this frame is part of a IBSS network, then we use the - * target specific station id */ + /* If this frame is going out to an IBSS network, find the station, + * or create a new station table entry */ case IEEE80211_IF_TYPE_IBSS: - sta_id = iwl_hw_find_station(priv, hdr->addr1); + sta_id = iwl4965_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) return sta_id; - sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC); + /* Create new station table entry */ + sta_id = iwl4965_add_station_flags(priv, hdr->addr1, + 0, CMD_ASYNC, NULL); if (sta_id != IWL_INVALID_STATION) return sta_id; @@ -2783,11 +2861,11 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) IWL_DEBUG_DROP("Station %s not in station map. " "Defaulting to broadcast...\n", print_mac(mac, hdr->addr1)); - iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); + iwl4965_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; default: - IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode); + IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode); return priv->hw_setting.bcast_sta_id; } } @@ -2795,18 +2873,19 @@ static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) /* * start REPLY_TX command process */ -static int iwl_tx_skb(struct iwl_priv *priv, +static int iwl4965_tx_skb(struct iwl4965_priv *priv, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct iwl_tfd_frame *tfd; + struct iwl4965_tfd_frame *tfd; u32 *control_flags; int txq_id = ctl->queue; - struct iwl_tx_queue *txq = NULL; - struct iwl_queue *q = NULL; + struct iwl4965_tx_queue *txq = NULL; + struct iwl4965_queue *q = NULL; dma_addr_t phys_addr; dma_addr_t txcmd_phys; - struct iwl_cmd *out_cmd = NULL; + dma_addr_t scratch_phys; + struct iwl4965_cmd *out_cmd = NULL; u16 len, idx, len_org; u8 id, hdr_len, unicast; u8 sta_id; @@ -2818,13 +2897,13 @@ static int iwl_tx_skb(struct iwl_priv *priv, int rc; spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { + if (iwl4965_is_rfkill(priv)) { IWL_DEBUG_DROP("Dropping - RF KILL\n"); goto drop_unlock; } - if (!priv->interface_id) { - IWL_DEBUG_DROP("Dropping - !priv->interface_id\n"); + if (!priv->vif) { + IWL_DEBUG_DROP("Dropping - !priv->vif\n"); goto drop_unlock; } @@ -2838,7 +2917,7 @@ static int iwl_tx_skb(struct iwl_priv *priv, fc = le16_to_cpu(hdr->frame_control); -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG if (ieee80211_is_auth(fc)) IWL_DEBUG_TX("Sending AUTH frame\n"); else if (ieee80211_is_assoc_request(fc)) @@ -2847,16 +2926,19 @@ static int iwl_tx_skb(struct iwl_priv *priv, IWL_DEBUG_TX("Sending REASSOC frame\n"); #endif - if (!iwl_is_associated(priv) && + /* drop all data frame if we are not associated */ + if (!iwl4965_is_associated(priv) && !priv->assoc_id && ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { - IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n"); + IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n"); goto drop_unlock; } spin_unlock_irqrestore(&priv->lock, flags); hdr_len = ieee80211_get_hdrlen(fc); - sta_id = iwl_get_sta_id(priv, hdr); + + /* Find (or create) index into station table for destination station */ + sta_id = iwl4965_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { DECLARE_MAC_BUF(mac); @@ -2876,40 +2958,62 @@ static int iwl_tx_skb(struct iwl_priv *priv, (hdr->seq_ctrl & __constant_cpu_to_le16(IEEE80211_SCTL_FRAG)); seq_number += 0x10; -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG /* aggregation is on for this <sta,tid> */ if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG) txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ } + + /* Descriptor for chosen Tx queue */ txq = &priv->txq[txq_id]; q = &txq->q; spin_lock_irqsave(&priv->lock, flags); - tfd = &txq->bd[q->first_empty]; + /* Set up first empty TFD within this queue's circular TFD buffer */ + tfd = &txq->bd[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); control_flags = (u32 *) tfd; - idx = get_cmd_index(q, q->first_empty, 0); + idx = get_cmd_index(q, q->write_ptr, 0); - memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->first_empty].skb[0] = skb; - memcpy(&(txq->txb[q->first_empty].status.control), + /* Set up driver data for this TFD */ + memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl4965_tx_info)); + txq->txb[q->write_ptr].skb[0] = skb; + memcpy(&(txq->txb[q->write_ptr].status.control), ctl, sizeof(struct ieee80211_tx_control)); + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_cmd = &txq->cmd[idx]; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx)); + + /* + * Set up the Tx-command (not MAC!) header. + * Store the chosen Tx queue and TFD index within the sequence field; + * after Tx, uCode's Tx response will return this value so driver can + * locate the frame within the tx queue and do post-tx processing. + */ out_cmd->hdr.cmd = REPLY_TX; out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->first_empty))); - /* copy frags header */ + INDEX_TO_SEQ(q->write_ptr))); + + /* Copy MAC header from skb into command buffer */ memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len); - /* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */ + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ len = priv->hw_setting.tx_cmd_len + - sizeof(struct iwl_cmd_header) + hdr_len; + sizeof(struct iwl4965_cmd_header) + hdr_len; len_org = len; len = (len + 3) & ~3; @@ -2919,36 +3023,53 @@ static int iwl_tx_skb(struct iwl_priv *priv, else len_org = 0; - txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx + - offsetof(struct iwl_cmd, hdr); + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl4965_cmd) * idx + + offsetof(struct iwl4965_cmd, hdr); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); + /* Add buffer containing Tx command and MAC(!) header to TFD's + * first entry */ + iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) - iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); + iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0); - /* 802.11 null functions have no payload... */ + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ len = skb->len - hdr_len; if (len) { phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len, len, PCI_DMA_TODEVICE); - iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); + iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len); } + /* Tell 4965 about any 2-byte padding after MAC header */ if (len_org) out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + /* Total # bytes to be transmitted */ len = (u16)skb->len; out_cmd->cmd.tx.len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); + iwl4965_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id); /* set is_hcca to 0; it probably will never be implemented */ - iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + iwl4965_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0); + + scratch_phys = txcmd_phys + sizeof(struct iwl4965_cmd_header) + + offsetof(struct iwl4965_tx_cmd, scratch); + out_cmd->cmd.tx.dram_lsb_ptr = cpu_to_le32(scratch_phys); + out_cmd->cmd.tx.dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + +#ifdef CONFIG_IWL4965_HT_AGG +#ifdef CONFIG_IWL4965_HT + /* TODO: move this functionality to rate scaling */ + iwl4965_tl_get_stats(priv, hdr); +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /*CONFIG_IWL4965_HT */ - iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys, - hdr, hdr_len, ctl, NULL); if (!ieee80211_get_morefrag(hdr)) { txq->need_update = 1; @@ -2961,27 +3082,29 @@ static int iwl_tx_skb(struct iwl_priv *priv, txq->need_update = 0; } - iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, + iwl4965_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload, sizeof(out_cmd->cmd.tx)); - iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, + iwl4965_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr, ieee80211_get_hdrlen(fc)); + /* Set up entry for this TFD in Tx byte-count array */ iwl4965_tx_queue_update_wr_ptr(priv, txq, len); - q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd); - rc = iwl_tx_queue_update_write_ptr(priv, txq); + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl4965_queue_inc_wrap(q->write_ptr, q->n_bd); + rc = iwl4965_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); if (rc) return rc; - if ((iwl_queue_space(q) < q->high_mark) + if ((iwl4965_queue_space(q) < q->high_mark) && priv->mac80211_registered) { if (wait_write_ptr) { spin_lock_irqsave(&priv->lock, flags); txq->need_update = 1; - iwl_tx_queue_update_write_ptr(priv, txq); + iwl4965_tx_queue_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } @@ -2996,13 +3119,13 @@ drop: return -1; } -static void iwl_set_rate(struct iwl_priv *priv) +static void iwl4965_set_rate(struct iwl4965_priv *priv) { const struct ieee80211_hw_mode *hw = NULL; struct ieee80211_rate *rate; int i; - hw = iwl_get_hw_mode(priv, priv->phymode); + hw = iwl4965_get_hw_mode(priv, priv->phymode); if (!hw) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; @@ -3020,7 +3143,7 @@ static void iwl_set_rate(struct iwl_priv *priv) if ((rate->val < IWL_RATE_COUNT) && (rate->flags & IEEE80211_RATE_SUPPORTED)) { IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl_rates[rate->val].plcp, + rate->val, iwl4965_rates[rate->val].plcp, (rate->flags & IEEE80211_RATE_BASIC) ? "*" : ""); priv->active_rate |= (1 << rate->val); @@ -3028,7 +3151,7 @@ static void iwl_set_rate(struct iwl_priv *priv) priv->active_rate_basic |= (1 << rate->val); } else IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl_rates[rate->val].plcp); + rate->val, iwl4965_rates[rate->val].plcp); } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -3057,7 +3180,7 @@ static void iwl_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) +static void iwl4965_radio_kill_sw(struct iwl4965_priv *priv, int disable_radio) { unsigned long flags; @@ -3068,21 +3191,21 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) disable_radio ? "OFF" : "ON"); if (disable_radio) { - iwl_scan_cancel(priv); + iwl4965_scan_cancel(priv); /* FIXME: This is a workaround for AP */ if (priv->iw_mode != IEEE80211_IF_TYPE_AP) { spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_SW_BIT_RFKILL); spin_unlock_irqrestore(&priv->lock, flags); - iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); + iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0); set_bit(STATUS_RF_KILL_SW, &priv->status); } return; } spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); clear_bit(STATUS_RF_KILL_SW, &priv->status); spin_unlock_irqrestore(&priv->lock, flags); @@ -3091,9 +3214,9 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) msleep(10); spin_lock_irqsave(&priv->lock, flags); - iwl_read32(priv, CSR_UCODE_DRV_GP1); - if (!iwl_grab_restricted_access(priv)) - iwl_release_restricted_access(priv); + iwl4965_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl4965_grab_nic_access(priv)) + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { @@ -3106,7 +3229,7 @@ static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio) return; } -void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, +void iwl4965_set_decrypted_flag(struct iwl4965_priv *priv, struct sk_buff *skb, u32 decrypt_res, struct ieee80211_rx_status *stats) { u16 fc = @@ -3138,97 +3261,10 @@ void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, } } -void iwl_handle_data_packet_monitor(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags) -{ - struct iwl_rt_rx_hdr *iwl_rt; - - /* First cache any information we need before we overwrite - * the information provided in the skb from the hardware */ - s8 signal = stats->ssi; - s8 noise = 0; - int rate = stats->rate; - u64 tsf = stats->mactime; - __le16 phy_flags_hw = cpu_to_le16(phy_flags); - - /* We received data from the HW, so stop the watchdog */ - if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) { - IWL_DEBUG_DROP("Dropping too large packet in monitor\n"); - return; - } - - /* copy the frame data to write after where the radiotap header goes */ - iwl_rt = (void *)rxb->skb->data; - memmove(iwl_rt->payload, data, len); - - iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */ - - /* total header + data */ - iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt)); - - /* Set the size of the skb to the size of the frame */ - skb_put(rxb->skb, sizeof(*iwl_rt) + len); - - /* Big bitfield of all the fields we provide in radiotap */ - iwl_rt->rt_hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)); - - /* Zero the flags, we'll add to them as we go */ - iwl_rt->rt_flags = 0; - - iwl_rt->rt_tsf = cpu_to_le64(tsf); - - /* Convert to dBm */ - iwl_rt->rt_dbmsignal = signal; - iwl_rt->rt_dbmnoise = noise; - - /* Convert the channel frequency and set the flags */ - iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq); - if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - iwl_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ)); - else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - iwl_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ)); - else /* 802.11g */ - iwl_rt->rt_chbitmask = - cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ)); - - rate = iwl_rate_index_from_plcp(rate); - if (rate == -1) - iwl_rt->rt_rate = 0; - else - iwl_rt->rt_rate = iwl_rates[rate].ieee; - - /* antenna number */ - iwl_rt->rt_antenna = - le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4; - - /* set the preamble flag if we have it */ - if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) - iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; - - IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); - - stats->flag |= RX_FLAG_RADIOTAP; - ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); - rxb->skb = NULL; -} - #define IWL_PACKET_RETRY_TIME HZ -int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) +int iwl4965_is_duplicate_packet(struct iwl4965_priv *priv, struct ieee80211_hdr *header) { u16 sc = le16_to_cpu(header->seq_ctrl); u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; @@ -3239,29 +3275,26 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) switch (priv->iw_mode) { case IEEE80211_IF_TYPE_IBSS:{ struct list_head *p; - struct iwl_ibss_seq *entry = NULL; + struct iwl4965_ibss_seq *entry = NULL; u8 *mac = header->addr2; int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); __list_for_each(p, &priv->ibss_mac_hash[index]) { - entry = - list_entry(p, struct iwl_ibss_seq, list); + entry = list_entry(p, struct iwl4965_ibss_seq, list); if (!compare_ether_addr(entry->mac, mac)) break; } if (p == &priv->ibss_mac_hash[index]) { entry = kzalloc(sizeof(*entry), GFP_ATOMIC); if (!entry) { - IWL_ERROR - ("Cannot malloc new mac entry\n"); + IWL_ERROR("Cannot malloc new mac entry\n"); return 0; } memcpy(entry->mac, mac, ETH_ALEN); entry->seq_num = seq; entry->frag_num = frag; entry->packet_time = jiffies; - list_add(&entry->list, - &priv->ibss_mac_hash[index]); + list_add(&entry->list, &priv->ibss_mac_hash[index]); return 0; } last_seq = &entry->seq_num; @@ -3295,7 +3328,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) return 1; } -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT #include "iwl-spectrum.h" @@ -3310,7 +3343,7 @@ int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) * the lower 3 bytes is the time in usec within one beacon interval */ -static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) { u32 quot; u32 rem; @@ -3329,7 +3362,7 @@ static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) * the same as HW timer counter counting down */ -static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +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; @@ -3348,13 +3381,13 @@ static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) return cpu_to_le32(res); } -static int iwl_get_measurement(struct iwl_priv *priv, +static int iwl4965_get_measurement(struct iwl4965_priv *priv, struct ieee80211_measurement_params *params, u8 type) { - struct iwl_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { + struct iwl4965_spectrum_cmd spectrum; + struct iwl4965_rx_packet *res; + struct iwl4965_host_cmd cmd = { .id = REPLY_SPECTRUM_MEASUREMENT_CMD, .data = (void *)&spectrum, .meta.flags = CMD_WANT_SKB, @@ -3364,9 +3397,9 @@ static int iwl_get_measurement(struct iwl_priv *priv, int spectrum_resp_status; int duration = le16_to_cpu(params->duration); - if (iwl_is_associated(priv)) + if (iwl4965_is_associated(priv)) add_time = - iwl_usecs_to_beacons( + iwl4965_usecs_to_beacons( le64_to_cpu(params->start_time) - priv->last_tsf, le16_to_cpu(priv->rxon_timing.beacon_interval)); @@ -3379,9 +3412,9 @@ static int iwl_get_measurement(struct iwl_priv *priv, cmd.len = sizeof(spectrum); spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - if (iwl_is_associated(priv)) + if (iwl4965_is_associated(priv)) spectrum.start_time = - iwl_add_beacon_time(priv->last_beacon_time, + iwl4965_add_beacon_time(priv->last_beacon_time, add_time, le16_to_cpu(priv->rxon_timing.beacon_interval)); else @@ -3394,11 +3427,11 @@ static int iwl_get_measurement(struct iwl_priv *priv, spectrum.flags |= RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl4965_send_cmd_sync(priv, &cmd); if (rc) return rc; - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + res = (struct iwl4965_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; @@ -3428,8 +3461,8 @@ static int iwl_get_measurement(struct iwl_priv *priv, } #endif -static void iwl_txstatus_to_ieee(struct iwl_priv *priv, - struct iwl_tx_info *tx_sta) +static void iwl4965_txstatus_to_ieee(struct iwl4965_priv *priv, + struct iwl4965_tx_info *tx_sta) { tx_sta->status.ack_signal = 0; @@ -3448,41 +3481,41 @@ static void iwl_txstatus_to_ieee(struct iwl_priv *priv, } /** - * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC. + * iwl4965_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd * - * When FW advances 'R' index, all entries between old and - * new 'R' index need to be reclaimed. As result, some free space - * forms. If there is enough free space (> low mark), wake Tx queue. + * When FW advances 'R' index, all entries between old and new 'R' index + * need to be reclaimed. As result, some free space forms. If there is + * enough free space (> low mark), wake the stack that feeds us. */ -int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +int iwl4965_tx_queue_reclaim(struct iwl4965_priv *priv, int txq_id, int index) { - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; + struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; + struct iwl4965_queue *q = &txq->q; int nfreed = 0; if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq id (%d), index %d, " "is out of range [0-%d] %d %d.\n", txq_id, - index, q->n_bd, q->first_empty, q->last_used); + index, q->n_bd, q->write_ptr, q->read_ptr); return 0; } - for (index = iwl_queue_inc_wrap(index, q->n_bd); - q->last_used != index; - q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) { + for (index = iwl4965_queue_inc_wrap(index, q->n_bd); + q->read_ptr != index; + q->read_ptr = iwl4965_queue_inc_wrap(q->read_ptr, q->n_bd)) { if (txq_id != IWL_CMD_QUEUE_NUM) { - iwl_txstatus_to_ieee(priv, - &(txq->txb[txq->q.last_used])); - iwl_hw_txq_free_tfd(priv, txq); + iwl4965_txstatus_to_ieee(priv, + &(txq->txb[txq->q.read_ptr])); + iwl4965_hw_txq_free_tfd(priv, txq); } else if (nfreed > 1) { IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index, - q->first_empty, q->last_used); + q->write_ptr, q->read_ptr); queue_work(priv->workqueue, &priv->restart); } nfreed++; } - if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) && + if (iwl4965_queue_space(q) > q->low_mark && (txq_id >= 0) && (txq_id != IWL_CMD_QUEUE_NUM) && priv->mac80211_registered) ieee80211_wake_queue(priv->hw, txq_id); @@ -3491,7 +3524,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) return nfreed; } -static int iwl_is_tx_success(u32 status) +static int iwl4965_is_tx_success(u32 status) { status &= TX_STATUS_MSK; return (status == TX_STATUS_SUCCESS) @@ -3503,22 +3536,22 @@ static int iwl_is_tx_success(u32 status) * Generic RX handler implementations * ******************************************************************************/ -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG -static inline int iwl_get_ra_sta_id(struct iwl_priv *priv, +static inline int iwl4965_get_ra_sta_id(struct iwl4965_priv *priv, struct ieee80211_hdr *hdr) { if (priv->iw_mode == IEEE80211_IF_TYPE_STA) return IWL_AP_ID; else { u8 *da = ieee80211_get_DA(hdr); - return iwl_hw_find_station(priv, da); + return iwl4965_hw_find_station(priv, da); } } -static struct ieee80211_hdr *iwl_tx_queue_get_hdr( - struct iwl_priv *priv, int txq_id, int idx) +static struct ieee80211_hdr *iwl4965_tx_queue_get_hdr( + struct iwl4965_priv *priv, int txq_id, int idx) { if (priv->txq[txq_id].txb[idx].skb[0]) return (struct ieee80211_hdr *)priv->txq[txq_id]. @@ -3526,16 +3559,20 @@ static struct ieee80211_hdr *iwl_tx_queue_get_hdr( return NULL; } -static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp) +static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) { __le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status + tx_resp->frame_count); return le32_to_cpu(*scd_ssn) & MAX_SN; } -static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwl_tx_resp *tx_resp, + +/** + * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue + */ +static int iwl4965_tx_status_reply_tx(struct iwl4965_priv *priv, + struct iwl4965_ht_agg *agg, + struct iwl4965_tx_resp *tx_resp, u16 start_idx) { u32 status; @@ -3547,15 +3584,17 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, u16 seq; if (agg->wait_for_ba) - IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n"); + IWL_DEBUG_TX_REPLY("got tx response w/o block-ack\n"); agg->frame_count = tx_resp->frame_count; agg->start_idx = start_idx; agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); agg->bitmap0 = agg->bitmap1 = 0; + /* # frames attempted by Tx command */ if (agg->frame_count == 1) { - struct iwl_tx_queue *txq ; + /* Only one frame was attempted; no block-ack will arrive */ + struct iwl4965_tx_queue *txq ; status = le32_to_cpu(frame_status[0]); txq_id = agg->txq_id; @@ -3564,28 +3603,30 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n", agg->frame_count, agg->start_idx); - tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status); + tx_status = &(priv->txq[txq_id].txb[txq->q.read_ptr].status); tx_status->retry_count = tx_resp->failure_frame; tx_status->queue_number = status & 0xff; tx_status->queue_length = tx_resp->bt_kill_count; tx_status->queue_length |= tx_resp->failure_rts; - tx_status->flags = iwl_is_tx_success(status)? + tx_status->flags = iwl4965_is_tx_success(status)? IEEE80211_TX_STATUS_ACK : 0; tx_status->control.tx_rate = - iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags); + iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags); /* FIXME: code repetition end */ IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n", status & 0xff, tx_resp->failure_frame); IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n", - iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags)); + iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags)); agg->wait_for_ba = 0; } else { + /* Two or more frames were attempted; expect block-ack */ u64 bitmap = 0; int start = agg->start_idx; + /* Construct bit-map of pending frames within Tx window */ for (i = 0; i < agg->frame_count; i++) { u16 sc; status = le32_to_cpu(frame_status[i]); @@ -3600,7 +3641,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n", agg->frame_count, txq_id, idx); - hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); + hdr = iwl4965_tx_queue_get_hdr(priv, txq_id, idx); sc = le16_to_cpu(hdr->seq_ctrl); if (idx != (SEQ_TO_SN(sc) & 0xff)) { @@ -3649,19 +3690,22 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, #endif #endif -static void iwl_rx_reply_tx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +/** + * iwl4965_rx_reply_tx - Handle standard (non-aggregation) Tx response + */ +static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); - struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl4965_tx_queue *txq = &priv->txq[txq_id]; struct ieee80211_tx_status *tx_status; - struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG int tid, sta_id; #endif #endif @@ -3669,18 +3713,18 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv, if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " "is out of range [0-%d] %d %d\n", txq_id, - index, txq->q.n_bd, txq->q.first_empty, - txq->q.last_used); + index, txq->q.n_bd, txq->q.write_ptr, + txq->q.read_ptr); return; } -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG if (txq->sched_retry) { - const u32 scd_ssn = iwl_get_scd_ssn(tx_resp); + const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); struct ieee80211_hdr *hdr = - iwl_tx_queue_get_hdr(priv, txq_id, index); - struct iwl_ht_agg *agg = NULL; + iwl4965_tx_queue_get_hdr(priv, txq_id, index); + struct iwl4965_ht_agg *agg = NULL; __le16 *qc = ieee80211_get_qos_ctrl(hdr); if (qc == NULL) { @@ -3690,7 +3734,7 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv, tid = le16_to_cpu(*qc) & 0xf; - sta_id = iwl_get_ra_sta_id(priv, hdr); + sta_id = iwl4965_get_ra_sta_id(priv, hdr); if (unlikely(sta_id == IWL_INVALID_STATION)) { IWL_ERROR("Station not known for\n"); return; @@ -3701,20 +3745,20 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv, iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index); if ((tx_resp->frame_count == 1) && - !iwl_is_tx_success(status)) { + !iwl4965_is_tx_success(status)) { /* TODO: send BAR */ } - if ((txq->q.last_used != (scd_ssn & 0xff))) { - index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); + if ((txq->q.read_ptr != (scd_ssn & 0xff))) { + index = iwl4965_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn " "%d index %d\n", scd_ssn , index); - iwl_tx_queue_reclaim(priv, txq_id, index); + iwl4965_tx_queue_reclaim(priv, txq_id, index); } } else { -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ - tx_status = &(txq->txb[txq->q.last_used].status); +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ + tx_status = &(txq->txb[txq->q.read_ptr].status); tx_status->retry_count = tx_resp->failure_frame; tx_status->queue_number = status; @@ -3722,35 +3766,35 @@ static void iwl_rx_reply_tx(struct iwl_priv *priv, tx_status->queue_length |= tx_resp->failure_rts; tx_status->flags = - iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; + iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; tx_status->control.tx_rate = - iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags); + iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags); IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " - "retries %d\n", txq_id, iwl_get_tx_fail_reason(status), + "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), status, le32_to_cpu(tx_resp->rate_n_flags), tx_resp->failure_frame); IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); if (index != -1) - iwl_tx_queue_reclaim(priv, txq_id, index); -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG + iwl4965_tx_queue_reclaim(priv, txq_id, index); +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG } -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } -static void iwl_rx_reply_alive(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_reply_alive(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_alive_resp *palive; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_alive_resp *palive; struct delayed_work *pwork; palive = &pkt->u.alive_frame; @@ -3764,12 +3808,12 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_DEBUG_INFO("Initialization Alive received.\n"); memcpy(&priv->card_alive_init, &pkt->u.alive_frame, - sizeof(struct iwl_init_alive_resp)); + sizeof(struct iwl4965_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)); + sizeof(struct iwl4965_alive_resp)); pwork = &priv->alive_start; } @@ -3782,19 +3826,19 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl_rx_reply_add_sta(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_reply_add_sta(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status); return; } -static void iwl_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_reply_error(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) " "seq 0x%04X ser 0x%08X\n", @@ -3807,23 +3851,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_csa(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; - struct iwl_csa_notification *csa = &(pkt->u.csa_notif); + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_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 iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_spectrum_measure_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); if (!report->state) { IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO, @@ -3836,35 +3880,35 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, #endif } -static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_pm_sleep_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); +#ifdef CONFIG_IWL4965_DEBUG + struct iwl4965_rx_packet *pkt = (void *)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 iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_pm_debug_statistics_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)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(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); + iwl4965_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } -static void iwl_bg_beacon_update(struct work_struct *work) +static void iwl4965_bg_beacon_update(struct work_struct *work) { - struct iwl_priv *priv = - container_of(work, struct iwl_priv, beacon_update); + struct iwl4965_priv *priv = + container_of(work, struct iwl4965_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->interface_id, NULL); + beacon = ieee80211_beacon_get(priv->hw, priv->vif, NULL); if (!beacon) { IWL_ERROR("update beacon failed\n"); @@ -3879,16 +3923,16 @@ static void iwl_bg_beacon_update(struct work_struct *work) priv->ibss_beacon = beacon; mutex_unlock(&priv->mutex); - iwl_send_beacon_cmd(priv); + iwl4965_send_beacon_cmd(priv); } -static void iwl_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_beacon_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status); - u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); +#ifdef CONFIG_IWL4965_DEBUG + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); + u8 rate = iwl4965_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", @@ -3905,25 +3949,25 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, } /* Service response to REPLY_SCAN_CMD (0x80) */ -static void iwl_rx_reply_scan(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_reply_scan(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scanreq_notification *notif = - (struct iwl_scanreq_notification *)pkt->u.raw; +#ifdef CONFIG_IWL4965_DEBUG + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_scanreq_notification *notif = + (struct iwl4965_scanreq_notification *)pkt->u.raw; IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); #endif } /* Service SCAN_START_NOTIFICATION (0x82) */ -static void iwl_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_scan_start_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scanstart_notification *notif = - (struct iwl_scanstart_notification *)pkt->u.raw; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_scanstart_notification *notif = + (struct iwl4965_scanstart_notification *)pkt->u.raw; priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); IWL_DEBUG_SCAN("Scan start: " "%d [802.11%s] " @@ -3935,12 +3979,12 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static void iwl_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_scan_results_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scanresults_notification *notif = - (struct iwl_scanresults_notification *)pkt->u.raw; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_scanresults_notification *notif = + (struct iwl4965_scanresults_notification *)pkt->u.raw; IWL_DEBUG_SCAN("Scan ch.res: " "%d [802.11%s] " @@ -3956,14 +4000,15 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, (priv->last_scan_jiffies, jiffies))); priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_scan_complete_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_scancomplete_notification *scan_notif = (void *)pkt->u.raw; IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", scan_notif->scanned_channels, @@ -3998,6 +4043,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, } priv->last_scan_jiffies = jiffies; + priv->next_scan_jiffies = 0; IWL_DEBUG_INFO("Setting scan to off\n"); clear_bit(STATUS_SCANNING, &priv->status); @@ -4016,10 +4062,10 @@ reschedule: /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_rx_card_state_notif(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (void *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (void *)rxb->skb->data; u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); unsigned long status = priv->status; @@ -4030,35 +4076,35 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | RF_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted( + if (!iwl4965_grab_nic_access(priv)) { + iwl4965_write_direct32( priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); } if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted( + if (!iwl4965_grab_nic_access(priv)) { + iwl4965_write_direct32( priv, HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); } } if (flags & RF_CARD_DISABLED) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl4965_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_restricted_access(priv)) - iwl_release_restricted_access(priv); + iwl4965_read32(priv, CSR_UCODE_DRV_GP1); + if (!iwl4965_grab_nic_access(priv)) + iwl4965_release_nic_access(priv); } } @@ -4074,7 +4120,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, clear_bit(STATUS_RF_KILL_SW, &priv->status); if (!(flags & RXON_CARD_DISABLED)) - iwl_scan_cancel(priv); + iwl4965_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != test_bit(STATUS_RF_KILL_HW, &priv->status)) || @@ -4086,7 +4132,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, } /** - * iwl_setup_rx_handlers - Initialize Rx handler callbacks + * 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. @@ -4094,61 +4140,58 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, * 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) +static void iwl4965_setup_rx_handlers(struct iwl4965_priv *priv) { - priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta; - priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[REPLY_ALIVE] = iwl4965_rx_reply_alive; + priv->rx_handlers[REPLY_ADD_STA] = iwl4965_rx_reply_add_sta; + priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; + iwl4965_rx_spectrum_measure_notif; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; - - /* NOTE: iwl_rx_statistics is different based on whether - * the build is for the 3945 or the 4965. See the - * corresponding implementation in iwl-XXXX.c - * - * The same handler is used for both the REPLY to a - * discrete statistics request from the host as well as - * for the periodic statistics notification from the uCode + 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_hw_rx_statistics; - priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics; + priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl4965_hw_rx_statistics; + priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl4965_hw_rx_statistics; - priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; - priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; + priv->rx_handlers[REPLY_SCAN_CMD] = iwl4965_rx_reply_scan; + priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl4965_rx_scan_start_notif; priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = - iwl_rx_scan_results_notif; + iwl4965_rx_scan_results_notif; priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = - iwl_rx_scan_complete_notif; - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; - priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx; + iwl4965_rx_scan_complete_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; + priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; - /* Setup hardware specific Rx handlers */ - iwl_hw_rx_handler_setup(priv); + /* Set up hardware specific Rx handlers */ + iwl4965_hw_rx_handler_setup(priv); } /** - * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them + * iwl4965_tx_cmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim * * If an Rx buffer has an async callback associated with it the callback * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ -static void iwl_tx_cmd_complete(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static void iwl4965_tx_cmd_complete(struct iwl4965_priv *priv, + struct iwl4965_rx_mem_buffer *rxb) { - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl4965_rx_packet *pkt = (struct iwl4965_rx_packet *)rxb->skb->data; u16 sequence = le16_to_cpu(pkt->hdr.sequence); int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); int huge = sequence & SEQ_HUGE_FRAME; int cmd_index; - struct iwl_cmd *cmd; + struct iwl4965_cmd *cmd; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced @@ -4169,7 +4212,7 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl_tx_queue_reclaim(priv, txq_id, index); + iwl4965_tx_queue_reclaim(priv, txq_id, index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -4181,9 +4224,11 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, /* * Rx theory of operation * - * The host allocates 32 DMA target addresses and passes the host address - * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is - * 0 to 31 + * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), + * each of which point to Receive Buffers to be filled by 4965. These get + * used not only for Rx frames, but for any command response or notification + * from the 4965. The driver and 4965 manage the Rx buffers by means + * of indexes into the circular buffer. * * Rx Queue Indexes * The host/firmware share two index registers for managing the Rx buffers. @@ -4199,10 +4244,10 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, * The queue is empty (no good data) if WRITE = READ - 1, and is full if * WRITE = READ. * - * During initialization the host sets up the READ queue position to the first + * During initialization, the host sets up the READ queue position to the first * INDEX position, and WRITE to the last (READ - 1 wrapped) * - * When the firmware places a packet in a buffer it will advance the READ index + * When the firmware places a packet in a buffer, it will advance the READ index * and fire the RX interrupt. The driver can then query the READ index and * process as many packets as possible, moving the WRITE index forward as it * resets the Rx queue buffers with new memory. @@ -4210,8 +4255,8 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, * The management in the driver is as follows: * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replensish the iwl->rxq->rx_free. - * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * to replenish the iwl->rxq->rx_free. + * + In iwl4965_rx_replenish (scheduled) if 'processed' != 'read' then the * iwl->rxq is replenished and the READ INDEX is updated (updating the * 'processed' and 'read' driver indexes as well) * + A received packet is processed and handed to the kernel network stack, @@ -4224,28 +4269,28 @@ static void iwl_tx_cmd_complete(struct iwl_priv *priv, * * Driver sequence: * - * iwl_rx_queue_alloc() Allocates rx_free - * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_rx_queue_restock - * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * iwl4965_rx_queue_alloc() Allocates rx_free + * iwl4965_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl4965_rx_queue_restock + * iwl4965_rx_queue_restock() Moves available buffers from rx_free into Rx * queue, updates firmware pointers, and updates * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl_rx_replenish + * are available, schedules iwl4965_rx_replenish * * -- enable interrupts -- - * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * ISR - iwl4965_rx() Detach iwl4965_rx_mem_buffers from pool up to the * READ INDEX, detaching the SKB from the pool. * Moves the packet buffer from queue to rx_used. - * Calls iwl_rx_queue_restock to refill any empty + * Calls iwl4965_rx_queue_restock to refill any empty * slots. * ... * */ /** - * iwl_rx_queue_space - Return number of free slots available in queue. + * iwl4965_rx_queue_space - Return number of free slots available in queue. */ -static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +static int iwl4965_rx_queue_space(const struct iwl4965_rx_queue *q) { int s = q->read - q->write; if (s <= 0) @@ -4258,15 +4303,9 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q) } /** - * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue - * - * NOTE: This function has 3945 and 4965 specific code sections - * but is declared in base due to the majority of the - * implementation being the same (only a numeric constant is - * different) - * + * iwl4965_rx_queue_update_write_ptr - Update the write pointer for the RX queue */ -int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) +int iwl4965_rx_queue_update_write_ptr(struct iwl4965_priv *priv, struct iwl4965_rx_queue *q) { u32 reg = 0; int rc = 0; @@ -4277,24 +4316,29 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) if (q->need_update == 0) goto exit_unlock; + /* If power-saving is in use, make sure device is awake */ if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - iwl_set_bit(priv, CSR_GP_CNTRL, + iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); goto exit_unlock; } - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) goto exit_unlock; - iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR, + /* Device expects a multiple of 8 */ + iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); + + /* Else device is assumed to be awake */ } else - iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); + /* Device expects a multiple of 8 */ + iwl4965_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7); q->need_update = 0; @@ -4305,11 +4349,9 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q) } /** - * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer. - * - * NOTE: This function has 3945 and 4965 specific code paths in it. + * iwl4965_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr */ -static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, +static inline __le32 iwl4965_dma_addr2rbd_ptr(struct iwl4965_priv *priv, dma_addr_t dma_addr) { return cpu_to_le32((u32)(dma_addr >> 8)); @@ -4317,31 +4359,34 @@ static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv, /** - * iwl_rx_queue_restock - refill RX queue from pre-allocated pool + * iwl4965_rx_queue_restock - refill RX queue from pre-allocated pool * - * If there are slots in the RX queue that need to be restocked, + * If there are slots in the RX queue that need to be restocked, * and we have free pre-allocated buffers, fill the ranks as much - * as we can pulling from rx_free. + * as we can, pulling from rx_free. * * This moves the 'write' index forward to catch up with 'processed', and * also updates the memory address in the firmware to reference the new * target buffer. */ -int iwl_rx_queue_restock(struct iwl_priv *priv) +static int iwl4965_rx_queue_restock(struct iwl4965_priv *priv) { - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl4965_rx_queue *rxq = &priv->rxq; struct list_head *element; - struct iwl_rx_mem_buffer *rxb; + struct iwl4965_rx_mem_buffer *rxb; unsigned long flags; int write, rc; spin_lock_irqsave(&rxq->lock, flags); write = rxq->write & ~0x7; - while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + while ((iwl4965_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + /* Get next free Rx buffer, remove from free list */ element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list); list_del(element); - rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr); + + /* Point to Rx buffer via next RBD in circular buffer */ + rxq->bd[rxq->write] = iwl4965_dma_addr2rbd_ptr(priv, rxb->dma_addr); rxq->queue[rxq->write] = rxb; rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; @@ -4353,13 +4398,14 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->rx_replenish); - /* If we've added more space for the firmware to place data, tell it */ + /* If we've added more space for the firmware to place data, tell it. + * Increment device's write pointer in multiples of 8. */ if ((write != (rxq->write & ~0x7)) || (abs(rxq->write - rxq->read) > 7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); - rc = iwl_rx_queue_update_write_ptr(priv, rxq); + rc = iwl4965_rx_queue_update_write_ptr(priv, rxq); if (rc) return rc; } @@ -4368,26 +4414,28 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) } /** - * iwl_rx_replensih - Move all used packet from rx_used to rx_free + * iwl4965_rx_replenish - Move all used packet from rx_used to rx_free * * When moving to rx_free an SKB is allocated for the slot. * - * Also restock the Rx queue via iwl_rx_queue_restock. - * This is called as a scheduled work item (except for during intialization) + * Also restock the Rx queue via iwl4965_rx_queue_restock. + * This is called as a scheduled work item (except for during initialization) */ -void iwl_rx_replenish(void *data) +static void iwl4965_rx_allocate(struct iwl4965_priv *priv) { - struct iwl_priv *priv = data; - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl4965_rx_queue *rxq = &priv->rxq; struct list_head *element; - struct iwl_rx_mem_buffer *rxb; + struct iwl4965_rx_mem_buffer *rxb; unsigned long flags; spin_lock_irqsave(&rxq->lock, flags); while (!list_empty(&rxq->rx_used)) { element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + rxb = list_entry(element, struct iwl4965_rx_mem_buffer, list); + + /* Alloc a new receive buffer */ rxb->skb = - alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC); + alloc_skb(priv->hw_setting.rx_buf_size, + __GFP_NOWARN | GFP_ATOMIC); if (!rxb->skb) { if (net_ratelimit()) printk(KERN_CRIT DRV_NAME @@ -4399,32 +4447,55 @@ void iwl_rx_replenish(void *data) } priv->alloc_rxb_skb++; list_del(element); + + /* Get physical address of RB/SKB */ rxb->dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, - IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; } spin_unlock_irqrestore(&rxq->lock, flags); +} + +/* + * this should be called while priv->lock is locked +*/ +static void __iwl4965_rx_replenish(void *data) +{ + struct iwl4965_priv *priv = data; + + iwl4965_rx_allocate(priv); + iwl4965_rx_queue_restock(priv); +} + + +void iwl4965_rx_replenish(void *data) +{ + struct iwl4965_priv *priv = data; + unsigned long flags; + + iwl4965_rx_allocate(priv); spin_lock_irqsave(&priv->lock, flags); - iwl_rx_queue_restock(priv); + iwl4965_rx_queue_restock(priv); spin_unlock_irqrestore(&priv->lock, flags); } /* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to * non NULL it is unmapped and freed */ -void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +static void iwl4965_rx_queue_free(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq) { int i; for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) { if (rxq->pool[i].skb != NULL) { pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->hw_setting.rx_buf_size, + PCI_DMA_FROMDEVICE); dev_kfree_skb(rxq->pool[i].skb); } } @@ -4434,21 +4505,25 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) rxq->bd = NULL; } -int iwl_rx_queue_alloc(struct iwl_priv *priv) +int iwl4965_rx_queue_alloc(struct iwl4965_priv *priv) { - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl4965_rx_queue *rxq = &priv->rxq; struct pci_dev *dev = priv->pci_dev; int i; spin_lock_init(&rxq->lock); INIT_LIST_HEAD(&rxq->rx_free); INIT_LIST_HEAD(&rxq->rx_used); + + /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) return -ENOMEM; + /* Fill the rx_used queue with _all_ of the Rx buffers */ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; @@ -4457,7 +4532,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) return 0; } -void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) +void iwl4965_rx_queue_reset(struct iwl4965_priv *priv, struct iwl4965_rx_queue *rxq) { unsigned long flags; int i; @@ -4471,7 +4546,8 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) if (rxq->pool[i].skb != NULL) { pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, - IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->hw_setting.rx_buf_size, + PCI_DMA_FROMDEVICE); priv->alloc_rxb_skb--; dev_kfree_skb(rxq->pool[i].skb); rxq->pool[i].skb = NULL; @@ -4504,7 +4580,7 @@ static u8 ratio2dB[100] = { /* Calculates a relative dB value from a ratio of linear * (i.e. not dB) signal levels. * Conversion assumes that levels are voltages (20*log), not powers (10*log). */ -int iwl_calc_db_from_ratio(int sig_ratio) +int iwl4965_calc_db_from_ratio(int sig_ratio) { /* 1000:1 or higher just report as 60 dB */ if (sig_ratio >= 1000) @@ -4530,7 +4606,7 @@ int iwl_calc_db_from_ratio(int sig_ratio) /* Calculate an indication of rx signal quality (a percentage, not dBm!). * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info * about formulas used below. */ -int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) +int iwl4965_calc_sig_qual(int rssi_dbm, int noise_dbm) { int sig_qual; int degradation = PERFECT_RSSI - rssi_dbm; @@ -4565,32 +4641,39 @@ int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) } /** - * iwl_rx_handle - Main entry function for receiving responses from the uCode + * iwl4965_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. */ -static void iwl_rx_handle(struct iwl_priv *priv) +static void iwl4965_rx_handle(struct iwl4965_priv *priv) { - struct iwl_rx_mem_buffer *rxb; - struct iwl_rx_packet *pkt; - struct iwl_rx_queue *rxq = &priv->rxq; + struct iwl4965_rx_mem_buffer *rxb; + struct iwl4965_rx_packet *pkt; + struct iwl4965_rx_queue *rxq = &priv->rxq; u32 r, i; int reclaim; unsigned long flags; + u8 fill_rx = 0; + u32 count = 0; - r = iwl_hw_get_rx_read(priv); + /* uCode's read index (stored in shared DRAM) indicates the last Rx + * buffer that the driver may process (last buffer filled by ucode). */ + r = iwl4965_hw_get_rx_read(priv); i = rxq->read; /* Rx interrupt, but nothing sent from uCode */ if (i == r) IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i); + if (iwl4965_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 queue slot associated with it + /* 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); @@ -4598,9 +4681,9 @@ static void iwl_rx_handle(struct iwl_priv *priv) rxq->queue[i] = NULL; pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, - IWL_RX_BUF_SIZE, + priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE); - pkt = (struct iwl_rx_packet *)rxb->skb->data; + pkt = (struct iwl4965_rx_packet *)rxb->skb->data; /* Reclaim a command buffer only if this packet is a response * to a (driver-originated) command. @@ -4617,7 +4700,7 @@ static void iwl_rx_handle(struct iwl_priv *priv) /* Based on type of command response or notification, * handle those that need handling via function in - * rx_handlers table. See iwl_setup_rx_handlers() */ + * rx_handlers table. See iwl4965_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d, %s, 0x%02x\n", r, i, @@ -4632,11 +4715,11 @@ static void iwl_rx_handle(struct iwl_priv *priv) } if (reclaim) { - /* Invoke any callbacks, transfer the skb to caller, - * and fire off the (possibly) blocking iwl_send_cmd() + /* Invoke any callbacks, transfer the skb to caller, and + * fire off the (possibly) blocking iwl4965_send_cmd() * as we reclaim the driver command queue */ if (rxb && rxb->skb) - iwl_tx_cmd_complete(priv, rxb); + iwl4965_tx_cmd_complete(priv, rxb); else IWL_WARNING("Claim null rxb?\n"); } @@ -4651,20 +4734,34 @@ static void iwl_rx_handle(struct iwl_priv *priv) } pci_unmap_single(priv->pci_dev, rxb->dma_addr, - IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); + priv->hw_setting.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; + __iwl4965_rx_replenish(priv); + count = 0; + } + } } /* Backtrack one entry */ priv->rxq.read = i; - iwl_rx_queue_restock(priv); + iwl4965_rx_queue_restock(priv); } -int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq) +/** + * iwl4965_tx_queue_update_write_ptr - Send new write index to hardware + */ +static int iwl4965_tx_queue_update_write_ptr(struct iwl4965_priv *priv, + struct iwl4965_tx_queue *txq) { u32 reg = 0; int rc = 0; @@ -4678,41 +4775,41 @@ int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, /* wake up nic if it's powered down ... * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg); - iwl_set_bit(priv, CSR_GP_CNTRL, + iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return rc; } /* restore this queue's parameters in nic hardware. */ - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) return rc; - iwl_write_restricted(priv, HBUS_TARG_WRPTR, - txq->q.first_empty | (txq_id << 8)); - iwl_release_restricted_access(priv); + iwl4965_write_direct32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); + iwl4965_release_nic_access(priv); /* else not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ } else - iwl_write32(priv, HBUS_TARG_WRPTR, - txq->q.first_empty | (txq_id << 8)); + iwl4965_write32(priv, HBUS_TARG_WRPTR, + txq->q.write_ptr | (txq_id << 8)); txq->need_update = 0; return rc; } -#ifdef CONFIG_IWLWIFI_DEBUG -static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) +#ifdef CONFIG_IWL4965_DEBUG +static void iwl4965_print_rx_config_cmd(struct iwl4965_rxon_cmd *rxon) { DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); - iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); + iwl4965_print_hex_dump(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", @@ -4729,24 +4826,24 @@ static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon) } #endif -static void iwl_enable_interrupts(struct iwl_priv *priv) +static void iwl4965_enable_interrupts(struct iwl4965_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); + iwl4965_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); } -static inline void iwl_disable_interrupts(struct iwl_priv *priv) +static inline void iwl4965_disable_interrupts(struct iwl4965_priv *priv) { clear_bit(STATUS_INT_ENABLED, &priv->status); /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); + iwl4965_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); + iwl4965_write32(priv, CSR_INT, 0xffffffff); + iwl4965_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); IWL_DEBUG_ISR("Disabled interrupts\n"); } @@ -4773,7 +4870,7 @@ static const char *desc_lookup(int i) #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) -static void iwl_dump_nic_error_log(struct iwl_priv *priv) +static void iwl4965_dump_nic_error_log(struct iwl4965_priv *priv) { u32 data2, line; u32 desc, time, count, base, data1; @@ -4782,18 +4879,18 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) base = le32_to_cpu(priv->card_alive.error_event_table_ptr); - if (!iwl_hw_valid_rtc_data_addr(base)) { + if (!iwl4965_hw_valid_rtc_data_addr(base)) { IWL_ERROR("Not valid error log pointer 0x%08X\n", base); return; } - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } - count = iwl_read_restricted_mem(priv, base); + count = iwl4965_read_targ_mem(priv, base); if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) { IWL_ERROR("Start IWL Error Log Dump:\n"); @@ -4801,15 +4898,15 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) priv->status, priv->config, count); } - desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32)); - blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32)); - blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32)); - ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32)); - ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32)); - data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32)); - data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32)); - line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32)); - time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32)); + desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32)); + blink1 = iwl4965_read_targ_mem(priv, base + 3 * sizeof(u32)); + blink2 = iwl4965_read_targ_mem(priv, base + 4 * sizeof(u32)); + ilink1 = iwl4965_read_targ_mem(priv, base + 5 * sizeof(u32)); + ilink2 = iwl4965_read_targ_mem(priv, base + 6 * sizeof(u32)); + data1 = iwl4965_read_targ_mem(priv, base + 7 * sizeof(u32)); + data2 = iwl4965_read_targ_mem(priv, base + 8 * sizeof(u32)); + line = iwl4965_read_targ_mem(priv, base + 9 * sizeof(u32)); + time = iwl4965_read_targ_mem(priv, base + 11 * sizeof(u32)); IWL_ERROR("Desc Time " "data1 data2 line\n"); @@ -4819,17 +4916,17 @@ static void iwl_dump_nic_error_log(struct iwl_priv *priv) IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, ilink1, ilink2); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); } #define EVENT_START_OFFSET (4 * sizeof(u32)) /** - * iwl_print_event_log - Dump error event log to syslog + * iwl4965_print_event_log - Dump error event log to syslog * - * NOTE: Must be called with iwl_grab_restricted_access() already obtained! + * NOTE: Must be called with iwl4965_grab_nic_access() already obtained! */ -static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, +static void iwl4965_print_event_log(struct iwl4965_priv *priv, u32 start_idx, u32 num_events, u32 mode) { u32 i; @@ -4853,21 +4950,21 @@ static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read_restricted_mem(priv, ptr); + ev = iwl4965_read_targ_mem(priv, ptr); ptr += sizeof(u32); - time = iwl_read_restricted_mem(priv, ptr); + time = iwl4965_read_targ_mem(priv, ptr); ptr += sizeof(u32); if (mode == 0) IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */ else { - data = iwl_read_restricted_mem(priv, ptr); + data = iwl4965_read_targ_mem(priv, ptr); ptr += sizeof(u32); IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev); } } } -static void iwl_dump_nic_event_log(struct iwl_priv *priv) +static void iwl4965_dump_nic_event_log(struct iwl4965_priv *priv) { int rc; u32 base; /* SRAM byte address of event log header */ @@ -4878,29 +4975,29 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) u32 size; /* # entries that we'll print */ base = le32_to_cpu(priv->card_alive.log_event_table_ptr); - if (!iwl_hw_valid_rtc_data_addr(base)) { + if (!iwl4965_hw_valid_rtc_data_addr(base)) { IWL_ERROR("Invalid event log pointer 0x%08X\n", base); return; } - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { IWL_WARNING("Can not read from adapter at this time.\n"); return; } /* event log header */ - capacity = iwl_read_restricted_mem(priv, base); - mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32))); + capacity = iwl4965_read_targ_mem(priv, base); + mode = iwl4965_read_targ_mem(priv, base + (1 * sizeof(u32))); + num_wraps = iwl4965_read_targ_mem(priv, base + (2 * sizeof(u32))); + next_entry = iwl4965_read_targ_mem(priv, base + (3 * sizeof(u32))); size = num_wraps ? capacity : next_entry; /* bail out if nothing in log */ if (size == 0) { IWL_ERROR("Start IWL Event Log Dump: nothing in log\n"); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); return; } @@ -4910,31 +5007,31 @@ static void iwl_dump_nic_event_log(struct iwl_priv *priv) /* if uCode has wrapped back to top of log, start at the oldest entry, * i.e the next one that uCode would fill. */ if (num_wraps) - iwl_print_event_log(priv, next_entry, + iwl4965_print_event_log(priv, next_entry, capacity - next_entry, mode); /* (then/else) start at top of log */ - iwl_print_event_log(priv, 0, next_entry, mode); + iwl4965_print_event_log(priv, 0, next_entry, mode); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); } /** - * iwl_irq_handle_error - called for HW or SW error interrupt from card + * iwl4965_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl_irq_handle_error(struct iwl_priv *priv) +static void iwl4965_irq_handle_error(struct iwl4965_priv *priv) { - /* Set the FW error flag -- cleared on iwl_down */ + /* 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 (iwl_debug_level & IWL_DL_FW_ERRORS) { - iwl_dump_nic_error_log(priv); - iwl_dump_nic_event_log(priv); - iwl_print_rx_config_cmd(&priv->staging_rxon); +#ifdef CONFIG_IWL4965_DEBUG + if (iwl4965_debug_level & IWL_DL_FW_ERRORS) { + iwl4965_dump_nic_error_log(priv); + iwl4965_dump_nic_event_log(priv); + iwl4965_print_rx_config_cmd(&priv->staging_rxon); } #endif @@ -4948,7 +5045,7 @@ static void iwl_irq_handle_error(struct iwl_priv *priv) IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS, "Restarting adapter due to uCode error.\n"); - if (iwl_is_associated(priv)) { + if (iwl4965_is_associated(priv)) { memcpy(&priv->recovery_rxon, &priv->active_rxon, sizeof(priv->recovery_rxon)); priv->error_recovering = 1; @@ -4957,16 +5054,16 @@ static void iwl_irq_handle_error(struct iwl_priv *priv) } } -static void iwl_error_recovery(struct iwl_priv *priv) +static void iwl4965_error_recovery(struct iwl4965_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; - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); - iwl_rxon_add_station(priv, priv->bssid, 1); + iwl4965_rxon_add_station(priv, priv->bssid, 1); spin_lock_irqsave(&priv->lock, flags); priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id); @@ -4974,12 +5071,12 @@ static void iwl_error_recovery(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl_irq_tasklet(struct iwl_priv *priv) +static void iwl4965_irq_tasklet(struct iwl4965_priv *priv) { u32 inta, handled = 0; u32 inta_fh; unsigned long flags; -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG u32 inta_mask; #endif @@ -4988,18 +5085,19 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* 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); + inta = iwl4965_read32(priv, CSR_INT); + iwl4965_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); + inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS); + iwl4965_write32(priv, CSR_FH_INT_STATUS, inta_fh); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & IWL_DL_ISR) { - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ +#ifdef CONFIG_IWL4965_DEBUG + if (iwl4965_debug_level & IWL_DL_ISR) { + /* just for debug */ + inta_mask = iwl4965_read32(priv, CSR_INT_MASK); IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); } @@ -5019,9 +5117,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) IWL_ERROR("Microcode HW error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); + iwl4965_disable_interrupts(priv); - iwl_irq_handle_error(priv); + iwl4965_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -5030,8 +5128,8 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) return; } -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_debug_level & (IWL_DL_ISR)) { +#ifdef CONFIG_IWL4965_DEBUG + if (iwl4965_debug_level & (IWL_DL_ISR)) { /* NIC fires this, but we don't use it, redundant with WAKEUP */ if (inta & CSR_INT_BIT_MAC_CLK_ACTV) IWL_DEBUG_ISR("Microcode started or stopped.\n"); @@ -5044,10 +5142,10 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) /* Safely ignore these bits for debug checks below */ inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE); - /* HW RF KILL switch toggled (4965 only) */ + /* HW RF KILL switch toggled */ if (inta & CSR_INT_BIT_RF_KILL) { int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & + if (!(iwl4965_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) hw_rf_kill = 1; @@ -5067,7 +5165,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_RF_KILL; } - /* Chip got too hot and stopped itself (4965 only) */ + /* 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; @@ -5077,20 +5175,20 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", inta); - iwl_irq_handle_error(priv); + 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_tx_queue_update_write_ptr(priv, &priv->txq[0]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]); - iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]); + iwl4965_rx_queue_update_write_ptr(priv, &priv->rxq); + iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[0]); + iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[1]); + iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[2]); + iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[3]); + iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[4]); + iwl4965_tx_queue_update_write_ptr(priv, &priv->txq[5]); handled |= CSR_INT_BIT_WAKEUP; } @@ -5099,7 +5197,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) * 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); + iwl4965_rx_handle(priv); handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); } @@ -5118,13 +5216,13 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) } /* Re-enable all interrupts */ - iwl_enable_interrupts(priv); + iwl4965_enable_interrupts(priv); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_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); +#ifdef CONFIG_IWL4965_DEBUG + if (iwl4965_debug_level & (IWL_DL_ISR)) { + inta = iwl4965_read32(priv, CSR_INT); + inta_mask = iwl4965_read32(priv, CSR_INT_MASK); + inta_fh = iwl4965_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); } @@ -5132,9 +5230,9 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static irqreturn_t iwl_isr(int irq, void *data) +static irqreturn_t iwl4965_isr(int irq, void *data) { - struct iwl_priv *priv = data; + struct iwl4965_priv *priv = data; u32 inta, inta_mask; u32 inta_fh; if (!priv) @@ -5146,12 +5244,12 @@ static irqreturn_t iwl_isr(int irq, void *data) * 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); + inta_mask = iwl4965_read32(priv, CSR_INT_MASK); /* just for debug */ + iwl4965_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); + inta = iwl4965_read32(priv, CSR_INT); + inta_fh = iwl4965_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, @@ -5171,7 +5269,7 @@ static irqreturn_t iwl_isr(int irq, void *data) IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", inta, inta_mask, inta_fh); - /* iwl_irq_tasklet() will service interrupts and re-enable them */ + /* iwl4965_irq_tasklet() will service interrupts and re-enable them */ tasklet_schedule(&priv->irq_tasklet); unplugged: @@ -5180,18 +5278,18 @@ static irqreturn_t iwl_isr(int irq, void *data) none: /* re-enable interrupts here since we don't have anything to service. */ - iwl_enable_interrupts(priv); + iwl4965_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } /************************** EEPROM BANDS **************************** * - * The iwl_eeprom_band definitions below provide the mapping from the + * The iwl4965_eeprom_band definitions below provide the mapping from the * EEPROM contents to the specific channel number supported for each * band. * - * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3 + * For example, iwl4965_priv->eeprom.band_3_channels[4] from the band_3 * definition below maps to physical channel 42 in the 5.2GHz spectrum. * The specific geography and calibration information for that channel * is contained in the eeprom map itself. @@ -5217,76 +5315,77 @@ static irqreturn_t iwl_isr(int irq, void *data) *********************************************************************/ /* 2.4 GHz */ -static const u8 iwl_eeprom_band_1[14] = { +static const u8 iwl4965_eeprom_band_1[14] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; /* 5.2 GHz bands */ -static const u8 iwl_eeprom_band_2[] = { +static const u8 iwl4965_eeprom_band_2[] = { /* 4915-5080MHz */ 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 }; -static const u8 iwl_eeprom_band_3[] = { /* 5205-5320MHz */ +static const u8 iwl4965_eeprom_band_3[] = { /* 5170-5320MHz */ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 }; -static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ +static const u8 iwl4965_eeprom_band_4[] = { /* 5500-5700MHz */ 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 }; -static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ +static const u8 iwl4965_eeprom_band_5[] = { /* 5725-5825MHz */ 145, 149, 153, 157, 161, 165 }; -static u8 iwl_eeprom_band_6[] = { /* 2.4 FAT channel */ +static u8 iwl4965_eeprom_band_6[] = { /* 2.4 FAT channel */ 1, 2, 3, 4, 5, 6, 7 }; -static u8 iwl_eeprom_band_7[] = { /* 5.2 FAT channel */ +static u8 iwl4965_eeprom_band_7[] = { /* 5.2 FAT channel */ 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 }; -static void iwl_init_band_reference(const struct iwl_priv *priv, int band, +static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, + int band, int *eeprom_ch_count, - const struct iwl_eeprom_channel + const struct iwl4965_eeprom_channel **eeprom_ch_info, const u8 **eeprom_ch_index) { switch (band) { case 1: /* 2.4GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_1); *eeprom_ch_info = priv->eeprom.band_1_channels; - *eeprom_ch_index = iwl_eeprom_band_1; + *eeprom_ch_index = iwl4965_eeprom_band_1; break; - case 2: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); + case 2: /* 4.9GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_2); *eeprom_ch_info = priv->eeprom.band_2_channels; - *eeprom_ch_index = iwl_eeprom_band_2; + *eeprom_ch_index = iwl4965_eeprom_band_2; break; case 3: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_3); *eeprom_ch_info = priv->eeprom.band_3_channels; - *eeprom_ch_index = iwl_eeprom_band_3; + *eeprom_ch_index = iwl4965_eeprom_band_3; break; - case 4: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); + case 4: /* 5.5GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_4); *eeprom_ch_info = priv->eeprom.band_4_channels; - *eeprom_ch_index = iwl_eeprom_band_4; + *eeprom_ch_index = iwl4965_eeprom_band_4; break; - case 5: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); + case 5: /* 5.7GHz band */ + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_5); *eeprom_ch_info = priv->eeprom.band_5_channels; - *eeprom_ch_index = iwl_eeprom_band_5; + *eeprom_ch_index = iwl4965_eeprom_band_5; break; - case 6: - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); + case 6: /* 2.4GHz FAT channels */ + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_6); *eeprom_ch_info = priv->eeprom.band_24_channels; - *eeprom_ch_index = iwl_eeprom_band_6; + *eeprom_ch_index = iwl4965_eeprom_band_6; break; - case 7: - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); + case 7: /* 5 GHz FAT channels */ + *eeprom_ch_count = ARRAY_SIZE(iwl4965_eeprom_band_7); *eeprom_ch_info = priv->eeprom.band_52_channels; - *eeprom_ch_index = iwl_eeprom_band_7; + *eeprom_ch_index = iwl4965_eeprom_band_7; break; default: BUG(); @@ -5294,7 +5393,12 @@ static void iwl_init_band_reference(const struct iwl_priv *priv, int band, } } -const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, +/** + * iwl4965_get_channel_info - Find driver's private channel info + * + * Based on band and channel number. + */ +const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv, int phymode, u16 channel) { int i; @@ -5321,13 +5425,16 @@ const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv, #define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \ ? # x " " : "") -static int iwl_init_channel_map(struct iwl_priv *priv) +/** + * iwl4965_init_channel_map - Set up driver's info for all possible channels + */ +static int iwl4965_init_channel_map(struct iwl4965_priv *priv) { int eeprom_ch_count = 0; const u8 *eeprom_ch_index = NULL; - const struct iwl_eeprom_channel *eeprom_ch_info = NULL; + const struct iwl4965_eeprom_channel *eeprom_ch_info = NULL; int band, ch; - struct iwl_channel_info *ch_info; + struct iwl4965_channel_info *ch_info; if (priv->channel_count) { IWL_DEBUG_INFO("Channel map already initialized.\n"); @@ -5343,15 +5450,15 @@ static int iwl_init_channel_map(struct iwl_priv *priv) IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n"); priv->channel_count = - ARRAY_SIZE(iwl_eeprom_band_1) + - ARRAY_SIZE(iwl_eeprom_band_2) + - ARRAY_SIZE(iwl_eeprom_band_3) + - ARRAY_SIZE(iwl_eeprom_band_4) + - ARRAY_SIZE(iwl_eeprom_band_5); + ARRAY_SIZE(iwl4965_eeprom_band_1) + + ARRAY_SIZE(iwl4965_eeprom_band_2) + + ARRAY_SIZE(iwl4965_eeprom_band_3) + + ARRAY_SIZE(iwl4965_eeprom_band_4) + + ARRAY_SIZE(iwl4965_eeprom_band_5); IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count); - priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * + priv->channel_info = kzalloc(sizeof(struct iwl4965_channel_info) * priv->channel_count, GFP_KERNEL); if (!priv->channel_info) { IWL_ERROR("Could not allocate channel_info\n"); @@ -5366,7 +5473,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv) * what just in the EEPROM) */ for (band = 1; band <= 5; band++) { - iwl_init_band_reference(priv, band, &eeprom_ch_count, + iwl4965_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); /* Loop through each band adding each of the channels */ @@ -5430,14 +5537,17 @@ static int iwl_init_channel_map(struct iwl_priv *priv) } } + /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ for (band = 6; band <= 7; band++) { int phymode; u8 fat_extension_chan; - iwl_init_band_reference(priv, band, &eeprom_ch_count, + iwl4965_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); + /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A; + /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { @@ -5449,11 +5559,13 @@ static int iwl_init_channel_map(struct iwl_priv *priv) else fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; + /* Set up driver's info for lower half */ iwl4965_set_fat_chan_info(priv, phymode, eeprom_ch_index[ch], &(eeprom_ch_info[ch]), fat_extension_chan); + /* Set up driver's info for upper half */ iwl4965_set_fat_chan_info(priv, phymode, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), @@ -5487,7 +5599,7 @@ static int iwl_init_channel_map(struct iwl_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) +static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, int phymode) { if (phymode == MODE_IEEE80211A) return IWL_ACTIVE_DWELL_TIME_52; @@ -5495,14 +5607,14 @@ static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode) return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) +static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode) { - u16 active = iwl_get_active_dwell_time(priv, phymode); + u16 active = iwl4965_get_active_dwell_time(priv, phymode); u16 passive = (phymode != MODE_IEEE80211A) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; - if (iwl_is_associated(priv)) { + if (iwl4965_is_associated(priv)) { /* If we're associated, we clamp the maximum passive * dwell time to be 98% of the beacon interval (minus * 2 * channel tune time) */ @@ -5518,30 +5630,30 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode) return passive; } -static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, +static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, u8 is_active, u8 direct_mask, - struct iwl_scan_channel *scan_ch) + struct iwl4965_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; const struct ieee80211_hw_mode *hw_mode; - const struct iwl_channel_info *ch_info; + const struct iwl4965_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl_get_hw_mode(priv, phymode); + hw_mode = iwl4965_get_hw_mode(priv, phymode); if (!hw_mode) return 0; channels = hw_mode->channels; - active_dwell = iwl_get_active_dwell_time(priv, phymode); - passive_dwell = iwl_get_passive_dwell_time(priv, phymode); + active_dwell = iwl4965_get_active_dwell_time(priv, phymode); + passive_dwell = iwl4965_get_passive_dwell_time(priv, phymode); for (i = 0, added = 0; i < hw_mode->num_channels; i++) { if (channels[i].chan == le16_to_cpu(priv->active_rxon.channel)) { - if (iwl_is_associated(priv)) { + if (iwl4965_is_associated(priv)) { IWL_DEBUG_SCAN ("Skipping current channel %d\n", le16_to_cpu(priv->active_rxon.channel)); @@ -5552,7 +5664,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, scan_ch->channel = channels[i].chan; - ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel); + ch_info = iwl4965_get_channel_info(priv, phymode, + scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", scan_ch->channel); @@ -5574,7 +5687,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, scan_ch->active_dwell = cpu_to_le16(active_dwell); scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* Set power levels to defaults */ + /* Set txpower levels to defaults */ scan_ch->tpc.dsp_atten = 110; /* scan_pwr_info->tpc.dsp_atten; */ @@ -5584,8 +5697,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level - scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3; + * power level: + * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3; */ } @@ -5603,7 +5716,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode, return added; } -static void iwl_reset_channel_flag(struct iwl_priv *priv) +static void iwl4965_reset_channel_flag(struct iwl4965_priv *priv) { int i, j; for (i = 0; i < 3; i++) { @@ -5613,13 +5726,13 @@ static void iwl_reset_channel_flag(struct iwl_priv *priv) } } -static void iwl_init_hw_rates(struct iwl_priv *priv, +static void iwl4965_init_hw_rates(struct iwl4965_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl_rates[i].ieee * 5; + rates[i].rate = iwl4965_rates[i].ieee * 5; rates[i].val = i; /* Rate scaling will work on indexes */ rates[i].val2 = i; rates[i].flags = IEEE80211_RATE_SUPPORTED; @@ -5631,7 +5744,7 @@ static void iwl_init_hw_rates(struct iwl_priv *priv, * If CCK 1M then set rate flag to CCK else CCK_2 * which is CCK | PREAMBLE2 */ - rates[i].flags |= (iwl_rates[i].plcp == 10) ? + rates[i].flags |= (iwl4965_rates[i].plcp == 10) ? IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; } @@ -5639,16 +5752,14 @@ static void iwl_init_hw_rates(struct iwl_priv *priv, if (IWL_BASIC_RATES_MASK & (1 << i)) rates[i].flags |= IEEE80211_RATE_BASIC; } - - iwl4965_init_hw_rates(priv, rates); } /** - * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom + * iwl4965_init_geos - Initialize mac80211's geo/channel info based from eeprom */ -static int iwl_init_geos(struct iwl_priv *priv) +static int iwl4965_init_geos(struct iwl4965_priv *priv) { - struct iwl_channel_info *ch; + struct iwl4965_channel_info *ch; struct ieee80211_hw_mode *modes; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; @@ -5658,10 +5769,8 @@ static int iwl_init_geos(struct iwl_priv *priv) A = 0, B = 1, G = 2, - A_11N = 3, - G_11N = 4, }; - int mode_count = 5; + int mode_count = 3; if (priv->modes) { IWL_DEBUG_INFO("Geography modes already initialized.\n"); @@ -5696,11 +5805,14 @@ static int iwl_init_geos(struct iwl_priv *priv) /* 5.2GHz channels start after the 2.4GHz channels */ modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; + modes[A].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)]; modes[A].rates = rates; modes[A].num_rates = 8; /* just OFDM */ modes[A].rates = &rates[4]; modes[A].num_channels = 0; +#ifdef CONFIG_IWL4965_HT + iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A); +#endif modes[B].mode = MODE_IEEE80211B; modes[B].channels = channels; @@ -5713,23 +5825,14 @@ static int iwl_init_geos(struct iwl_priv *priv) modes[G].rates = rates; modes[G].num_rates = 12; /* OFDM & CCK */ modes[G].num_channels = 0; - - modes[G_11N].mode = MODE_IEEE80211G; - modes[G_11N].channels = channels; - modes[G_11N].num_rates = 13; /* OFDM & CCK */ - modes[G_11N].rates = rates; - modes[G_11N].num_channels = 0; - - modes[A_11N].mode = MODE_IEEE80211A; - modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)]; - modes[A_11N].rates = &rates[4]; - modes[A_11N].num_rates = 9; /* just OFDM */ - modes[A_11N].num_channels = 0; +#ifdef CONFIG_IWL4965_HT + iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G); +#endif priv->ieee_channels = channels; priv->ieee_rates = rates; - iwl_init_hw_rates(priv, rates); + iwl4965_init_hw_rates(priv, rates); for (i = 0, geo_ch = channels; i < priv->channel_count; i++) { ch = &priv->channel_info[i]; @@ -5744,11 +5847,9 @@ static int iwl_init_geos(struct iwl_priv *priv) if (is_channel_a_band(ch)) { geo_ch = &modes[A].channels[modes[A].num_channels++]; - modes[A_11N].num_channels++; } else { geo_ch = &modes[B].channels[modes[B].num_channels++]; modes[G].num_channels++; - modes[G_11N].num_channels++; } geo_ch->freq = ieee80211chan2mhz(ch->channel); @@ -5814,57 +5915,22 @@ static int iwl_init_geos(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl4965_dealloc_ucode_pci(struct iwl4965_priv *priv) { - if (priv->ucode_code.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_code.len, - priv->ucode_code.v_addr, - priv->ucode_code.p_addr); - priv->ucode_code.v_addr = NULL; - } - if (priv->ucode_data.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_data.len, - priv->ucode_data.v_addr, - priv->ucode_data.p_addr); - priv->ucode_data.v_addr = NULL; - } - if (priv->ucode_data_backup.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_data_backup.len, - priv->ucode_data_backup.v_addr, - priv->ucode_data_backup.p_addr); - priv->ucode_data_backup.v_addr = NULL; - } - if (priv->ucode_init.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_init.len, - priv->ucode_init.v_addr, - priv->ucode_init.p_addr); - priv->ucode_init.v_addr = NULL; - } - if (priv->ucode_init_data.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_init_data.len, - priv->ucode_init_data.v_addr, - priv->ucode_init_data.p_addr); - priv->ucode_init_data.v_addr = NULL; - } - if (priv->ucode_boot.v_addr != NULL) { - pci_free_consistent(priv->pci_dev, - priv->ucode_boot.len, - priv->ucode_boot.v_addr, - priv->ucode_boot.p_addr); - priv->ucode_boot.v_addr = NULL; - } + 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); } /** - * iwl_verify_inst_full - verify runtime uCode image in card vs. host, + * iwl4965_verify_inst_full - verify runtime uCode image in card vs. host, * looking at all data. */ -static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) +static int iwl4965_verify_inst_full(struct iwl4965_priv *priv, __le32 *image, + u32 len) { u32 val; u32 save_len = len; @@ -5873,18 +5939,18 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) return rc; - iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); + iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND); errcnt = 0; for (; len > 0; len -= sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERROR("uCode INST section is invalid at " "offset 0x%x, is 0x%x, s/b 0x%x\n", @@ -5896,7 +5962,7 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) } } - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); if (!errcnt) IWL_DEBUG_INFO @@ -5907,11 +5973,11 @@ static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len) /** - * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host, + * iwl4965_verify_inst_sparse - verify runtime uCode image in card vs. host, * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) +static int iwl4965_verify_inst_sparse(struct iwl4965_priv *priv, __le32 *image, u32 len) { u32 val; int rc = 0; @@ -5920,7 +5986,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) IWL_DEBUG_INFO("ucode inst image size is %u\n", len); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) return rc; @@ -5928,9 +5994,9 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, + iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, i + RTC_INST_LOWER_BOUND); - val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT); + val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { #if 0 /* Enable this if you want to see details */ IWL_ERROR("uCode INST section is invalid at " @@ -5944,17 +6010,17 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len) } } - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); return rc; } /** - * iwl_verify_ucode - determine which instruction image is in SRAM, + * iwl4965_verify_ucode - determine which instruction image is in SRAM, * and verify its contents */ -static int iwl_verify_ucode(struct iwl_priv *priv) +static int iwl4965_verify_ucode(struct iwl4965_priv *priv) { __le32 *image; u32 len; @@ -5963,7 +6029,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv) /* Try bootstrap */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; - rc = iwl_verify_inst_sparse(priv, image, len); + rc = iwl4965_verify_inst_sparse(priv, image, len); if (rc == 0) { IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n"); return 0; @@ -5972,7 +6038,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv) /* Try initialize */ image = (__le32 *)priv->ucode_init.v_addr; len = priv->ucode_init.len; - rc = iwl_verify_inst_sparse(priv, image, len); + rc = iwl4965_verify_inst_sparse(priv, image, len); if (rc == 0) { IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n"); return 0; @@ -5981,7 +6047,7 @@ static int iwl_verify_ucode(struct iwl_priv *priv) /* Try runtime/protocol */ image = (__le32 *)priv->ucode_code.v_addr; len = priv->ucode_code.len; - rc = iwl_verify_inst_sparse(priv, image, len); + rc = iwl4965_verify_inst_sparse(priv, image, len); if (rc == 0) { IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n"); return 0; @@ -5989,18 +6055,19 @@ static int iwl_verify_ucode(struct iwl_priv *priv) IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n"); - /* Show first several data entries in instruction SRAM. - * Selection of bootstrap image is arbitrary. */ + /* Since nothing seems to match, show first several data entries in + * instruction SRAM, so maybe visual inspection will give a clue. + * Selection of bootstrap image (vs. other images) is arbitrary. */ image = (__le32 *)priv->ucode_boot.v_addr; len = priv->ucode_boot.len; - rc = iwl_verify_inst_full(priv, image, len); + rc = iwl4965_verify_inst_full(priv, image, len); return rc; } /* check contents of special bootstrap uCode SRAM */ -static int iwl_verify_bsm(struct iwl_priv *priv) +static int iwl4965_verify_bsm(struct iwl4965_priv *priv) { __le32 *image = priv->ucode_boot.v_addr; u32 len = priv->ucode_boot.len; @@ -6010,11 +6077,11 @@ static int iwl_verify_bsm(struct iwl_priv *priv) IWL_DEBUG_INFO("Begin verify bsm\n"); /* verify BSM SRAM contents */ - val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG); + val = iwl4965_read_prph(priv, BSM_WR_DWCOUNT_REG); for (reg = BSM_SRAM_LOWER_BOUND; reg < BSM_SRAM_LOWER_BOUND + len; reg += sizeof(u32), image ++) { - val = iwl_read_restricted_reg(priv, reg); + val = iwl4965_read_prph(priv, reg); if (val != le32_to_cpu(*image)) { IWL_ERROR("BSM uCode verification failed at " "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n", @@ -6031,7 +6098,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv) } /** - * iwl_load_bsm - Load bootstrap instructions + * iwl4965_load_bsm - Load bootstrap instructions * * BSM operation: * @@ -6062,7 +6129,7 @@ static int iwl_verify_bsm(struct iwl_priv *priv) * the runtime uCode instructions and the backup data cache into SRAM, * and re-launches the runtime uCode from where it left off. */ -static int iwl_load_bsm(struct iwl_priv *priv) +static int iwl4965_load_bsm(struct iwl4965_priv *priv) { __le32 *image = priv->ucode_boot.v_addr; u32 len = priv->ucode_boot.len; @@ -6082,8 +6149,8 @@ static int iwl_load_bsm(struct iwl_priv *priv) return -EINVAL; /* Tell bootstrap uCode where to find the "Initialize" uCode - * in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965. - * NOTE: iwl_initialize_alive_start() will replace these values, + * in host DRAM ... host DRAM physical address bits 35:4 for 4965. + * NOTE: iwl4965_initialize_alive_start() will replace these values, * after the "initialize" uCode has run, to point to * runtime/protocol instructions and backup data cache. */ pinst = priv->ucode_init.p_addr >> 4; @@ -6091,42 +6158,42 @@ static int iwl_load_bsm(struct iwl_priv *priv) inst_len = priv->ucode_init.len; data_len = priv->ucode_init_data.len; - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) return rc; - iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); + iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len); + iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len); /* Fill BSM memory with bootstrap instructions */ for (reg_offset = BSM_SRAM_LOWER_BOUND; reg_offset < BSM_SRAM_LOWER_BOUND + len; reg_offset += sizeof(u32), image++) - _iwl_write_restricted_reg(priv, reg_offset, + _iwl4965_write_prph(priv, reg_offset, le32_to_cpu(*image)); - rc = iwl_verify_bsm(priv); + rc = iwl4965_verify_bsm(priv); if (rc) { - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); return rc; } /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */ - iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0); - iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG, + iwl4965_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0); + iwl4965_write_prph(priv, BSM_WR_MEM_DST_REG, RTC_INST_LOWER_BOUND); - iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); + iwl4965_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32)); /* Load bootstrap code into instruction SRAM now, * to prepare to load "initialize" uCode */ - iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + iwl4965_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START); /* Wait for load of bootstrap uCode to finish */ for (i = 0; i < 100; i++) { - done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG); + done = iwl4965_read_prph(priv, BSM_WR_CTRL_REG); if (!(done & BSM_WR_CTRL_REG_BIT_START)) break; udelay(10); @@ -6140,29 +6207,30 @@ static int iwl_load_bsm(struct iwl_priv *priv) /* Enable future boot loads whenever power management unit triggers it * (e.g. when powering back up after power-save shutdown) */ - iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG, + iwl4965_write_prph(priv, BSM_WR_CTRL_REG, BSM_WR_CTRL_REG_BIT_START_EN); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); return 0; } -static void iwl_nic_start(struct iwl_priv *priv) +static void iwl4965_nic_start(struct iwl4965_priv *priv) { /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); + iwl4965_write32(priv, CSR_RESET, 0); } + /** - * iwl_read_ucode - Read uCode images from disk file. + * iwl4965_read_ucode - Read uCode images from disk file. * * Copy into buffers for card to fetch via bus-mastering */ -static int iwl_read_ucode(struct iwl_priv *priv) +static int iwl4965_read_ucode(struct iwl4965_priv *priv) { - struct iwl_ucode *ucode; - int rc = 0; + struct iwl4965_ucode *ucode; + int ret; const struct firmware *ucode_raw; const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode"; u8 *src; @@ -6171,9 +6239,10 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (rc < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc); + 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; } @@ -6183,7 +6252,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { IWL_ERROR("File size way too small!\n"); - rc = -EINVAL; + ret = -EINVAL; goto err_release; } @@ -6216,43 +6285,43 @@ static int iwl_read_ucode(struct iwl_priv *priv) IWL_DEBUG_INFO("uCode file size %d too small\n", (int)ucode_raw->size); - rc = -EINVAL; + ret = -EINVAL; goto err_release; } /* Verify that uCode images will fit in card's SRAM */ if (inst_size > IWL_MAX_INST_SIZE) { - IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n", - (int)inst_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode instr len %d too large to fit in\n", + inst_size); + ret = -EINVAL; goto err_release; } if (data_size > IWL_MAX_DATA_SIZE) { - IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n", - (int)data_size); - rc = -EINVAL; + IWL_DEBUG_INFO("uCode data len %d too large to fit in\n", + data_size); + ret = -EINVAL; goto err_release; } if (init_size > IWL_MAX_INST_SIZE) { IWL_DEBUG_INFO - ("uCode init instr len %d too large to fit in card\n", - (int)init_size); - rc = -EINVAL; + ("uCode init instr len %d too large to fit in\n", + init_size); + ret = -EINVAL; goto err_release; } if (init_data_size > IWL_MAX_DATA_SIZE) { IWL_DEBUG_INFO - ("uCode init data len %d too large to fit in card\n", - (int)init_data_size); - rc = -EINVAL; + ("uCode init data len %d too large to fit in\n", + init_data_size); + ret = -EINVAL; goto err_release; } if (boot_size > IWL_MAX_BSM_SIZE) { IWL_DEBUG_INFO - ("uCode boot instr len %d too large to fit in bsm\n", - (int)boot_size); - rc = -EINVAL; + ("uCode boot instr len %d too large to fit in\n", + boot_size); + ret = -EINVAL; goto err_release; } @@ -6262,66 +6331,50 @@ static int iwl_read_ucode(struct iwl_priv *priv) * 1) unmodified from disk * 2) backup cache for save/restore during power-downs */ priv->ucode_code.len = inst_size; - priv->ucode_code.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_code.len, - &(priv->ucode_code.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code); priv->ucode_data.len = data_size; - priv->ucode_data.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_data.len, - &(priv->ucode_data.p_addr)); + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data); priv->ucode_data_backup.len = data_size; - priv->ucode_data_backup.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_data_backup.len, - &(priv->ucode_data_backup.p_addr)); - + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup); /* Initialization instructions and data */ - priv->ucode_init.len = init_size; - priv->ucode_init.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_init.len, - &(priv->ucode_init.p_addr)); - - priv->ucode_init_data.len = init_data_size; - priv->ucode_init_data.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_init_data.len, - &(priv->ucode_init_data.p_addr)); + 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) */ - priv->ucode_boot.len = boot_size; - priv->ucode_boot.v_addr = - pci_alloc_consistent(priv->pci_dev, - priv->ucode_boot.len, - &(priv->ucode_boot.p_addr)); + if (boot_size) { + priv->ucode_boot.len = boot_size; + iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot); - if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr || - !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr || - !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr) - goto err_pci_alloc; + 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 %d\n", - (int)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 iwl_up() */ + * 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 %d\n", - (int)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); @@ -6329,8 +6382,8 @@ static int iwl_read_ucode(struct iwl_priv *priv) 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 %d\n", - (int)len); + IWL_DEBUG_INFO("Copying (but not loading) init instr len %Zd\n", + len); memcpy(priv->ucode_init.v_addr, src, len); } @@ -6338,16 +6391,15 @@ static int iwl_read_ucode(struct iwl_priv *priv) 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 %d\n", - (int)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 %d\n", - (int)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 */ @@ -6356,19 +6408,19 @@ static int iwl_read_ucode(struct iwl_priv *priv) err_pci_alloc: IWL_ERROR("failed to allocate pci memory\n"); - rc = -ENOMEM; - iwl_dealloc_ucode_pci(priv); + ret = -ENOMEM; + iwl4965_dealloc_ucode_pci(priv); err_release: release_firmware(ucode_raw); error: - return rc; + return ret; } /** - * iwl_set_ucode_ptrs - Set uCode address location + * iwl4965_set_ucode_ptrs - Set uCode address location * * Tell initialization uCode where to find runtime uCode. * @@ -6376,7 +6428,7 @@ static int iwl_read_ucode(struct iwl_priv *priv) * We need to replace them to load runtime uCode inst and data, * and to save runtime data when powering down. */ -static int iwl_set_ucode_ptrs(struct iwl_priv *priv) +static int iwl4965_set_ucode_ptrs(struct iwl4965_priv *priv) { dma_addr_t pinst; dma_addr_t pdata; @@ -6388,24 +6440,24 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv) pdata = priv->ucode_data_backup.p_addr >> 4; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_restricted_access(priv); + rc = iwl4965_grab_nic_access(priv); if (rc) { spin_unlock_irqrestore(&priv->lock, flags); return rc; } /* Tell bootstrap uCode where to find image to load */ - iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata); - iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, + iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst); + iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata); + iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); /* Inst bytecount must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ - iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, + iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -6415,7 +6467,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv) } /** - * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved + * iwl4965_init_alive_start - Called after REPLY_ALIVE notification received * * Called after REPLY_ALIVE notification received from "initialize" uCode. * @@ -6425,7 +6477,7 @@ static int iwl_set_ucode_ptrs(struct iwl_priv *priv) * * Tell "initialize" uCode to go ahead and load the runtime uCode. */ -static void iwl_init_alive_start(struct iwl_priv *priv) +static void iwl4965_init_alive_start(struct iwl4965_priv *priv) { /* Check alive response for "valid" sign from uCode */ if (priv->card_alive_init.is_valid != UCODE_VALID_OK) { @@ -6438,7 +6490,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv) /* Bootstrap uCode has loaded initialize uCode ... verify inst image. * This is a paranoid check, because we would not have gotten the * "initialize" alive if code weren't properly loaded. */ - if (iwl_verify_ucode(priv)) { + if (iwl4965_verify_ucode(priv)) { /* Runtime instruction load was bad; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n"); @@ -6452,7 +6504,7 @@ static void iwl_init_alive_start(struct iwl_priv *priv) * load and launch runtime uCode, which will send us another "Alive" * notification. */ IWL_DEBUG_INFO("Initialization Alive received.\n"); - if (iwl_set_ucode_ptrs(priv)) { + if (iwl4965_set_ucode_ptrs(priv)) { /* Runtime instruction load won't happen; * take it all the way back down so we can try again */ IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n"); @@ -6466,11 +6518,11 @@ static void iwl_init_alive_start(struct iwl_priv *priv) /** - * iwl_alive_start - called after REPLY_ALIVE notification received + * iwl4965_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's - * Alive gets handled by iwl_init_alive_start()). + * Alive gets handled by iwl4965_init_alive_start()). */ -static void iwl_alive_start(struct iwl_priv *priv) +static void iwl4965_alive_start(struct iwl4965_priv *priv) { int rc = 0; @@ -6486,14 +6538,14 @@ static void iwl_alive_start(struct iwl_priv *priv) /* 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)) { + if (iwl4965_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); + iwl4965_clear_stations_table(priv); rc = iwl4965_alive_notify(priv); if (rc) { @@ -6502,78 +6554,61 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - /* After the ALIVE response, we can process host commands */ + /* After the ALIVE response, we can send host commands to 4965 uCode */ set_bit(STATUS_ALIVE, &priv->status); /* Clear out the uCode error bit if it is set */ clear_bit(STATUS_FW_ERROR, &priv->status); - rc = iwl_init_channel_map(priv); + rc = iwl4965_init_channel_map(priv); if (rc) { IWL_ERROR("initializing regulatory failed: %d\n", rc); return; } - iwl_init_geos(priv); + iwl4965_init_geos(priv); + iwl4965_reset_channel_flag(priv); - if (iwl_is_rfkill(priv)) + if (iwl4965_is_rfkill(priv)) return; - if (!priv->mac80211_registered) { - /* Unlock so any user space entry points can call back into - * the driver without a deadlock... */ - mutex_unlock(&priv->mutex); - iwl_rate_control_register(priv->hw); - rc = ieee80211_register_hw(priv->hw); - priv->hw->conf.beacon_int = 100; - mutex_lock(&priv->mutex); - - if (rc) { - iwl_rate_control_unregister(priv->hw); - IWL_ERROR("Failed to register network " - "device (error %d)\n", rc); - return; - } - - priv->mac80211_registered = 1; - - iwl_reset_channel_flag(priv); - } else - ieee80211_start_queues(priv->hw); + ieee80211_start_queues(priv->hw); priv->active_rate = priv->rates_mask; priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK; - iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); + iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode)); - if (iwl_is_associated(priv)) { - struct iwl_rxon_cmd *active_rxon = - (struct iwl_rxon_cmd *)(&priv->active_rxon); + if (iwl4965_is_associated(priv)) { + struct iwl4965_rxon_cmd *active_rxon = + (struct iwl4965_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 */ - iwl_connection_init_rx_config(priv); + iwl4965_connection_init_rx_config(priv); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } - /* Configure BT coexistence */ - iwl_send_bt_config(priv); + /* Configure Bluetooth device coexistence support */ + iwl4965_send_bt_config(priv); /* Configure the adapter for unassociated operation */ - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ priv->notif_missed_beacons = 0; set_bit(STATUS_READY, &priv->status); iwl4965_rf_kill_ct_config(priv); + IWL_DEBUG_INFO("ALIVE processing complete.\n"); + wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) - iwl_error_recovery(priv); + iwl4965_error_recovery(priv); return; @@ -6581,9 +6616,9 @@ static void iwl_alive_start(struct iwl_priv *priv) queue_work(priv->workqueue, &priv->restart); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv); +static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv); -static void __iwl_down(struct iwl_priv *priv) +static void __iwl4965_down(struct iwl4965_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); @@ -6596,7 +6631,7 @@ static void __iwl_down(struct iwl_priv *priv) if (!exit_pending) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_clear_stations_table(priv); + iwl4965_clear_stations_table(priv); /* Unblock any waiting calls */ wake_up_interruptible_all(&priv->wait_command_queue); @@ -6607,17 +6642,17 @@ static void __iwl_down(struct iwl_priv *priv) 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); + iwl4965_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); /* tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); + iwl4965_disable_interrupts(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl_init() then + /* 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)) { + if (!iwl4965_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) << @@ -6639,53 +6674,52 @@ static void __iwl_down(struct iwl_priv *priv) STATUS_FW_ERROR; spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl4965_clear_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock_irqrestore(&priv->lock, flags); - iwl_hw_txq_ctx_stop(priv); - iwl_hw_rxq_stop(priv); + iwl4965_hw_txq_ctx_stop(priv); + iwl4965_hw_rxq_stop(priv); spin_lock_irqsave(&priv->lock, flags); - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, + if (!iwl4965_grab_nic_access(priv)) { + iwl4965_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_restricted_access(priv); + iwl4965_release_nic_access(priv); } spin_unlock_irqrestore(&priv->lock, flags); udelay(5); - iwl_hw_nic_stop_master(priv); - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - iwl_hw_nic_reset(priv); + iwl4965_hw_nic_stop_master(priv); + iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl4965_hw_nic_reset(priv); exit: - memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); + memset(&priv->card_alive, 0, sizeof(struct iwl4965_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); + iwl4965_clear_free_frames(priv); } -static void iwl_down(struct iwl_priv *priv) +static void iwl4965_down(struct iwl4965_priv *priv) { mutex_lock(&priv->mutex); - __iwl_down(priv); + __iwl4965_down(priv); mutex_unlock(&priv->mutex); - iwl_cancel_deferred_work(priv); + iwl4965_cancel_deferred_work(priv); } #define MAX_HW_RESTARTS 5 -static int __iwl_up(struct iwl_priv *priv) +static int __iwl4965_up(struct iwl4965_priv *priv) { - DECLARE_MAC_BUF(mac); int rc, i; - u32 hw_rf_kill = 0; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { IWL_WARNING("Exit pending; will not bring the NIC up\n"); @@ -6695,56 +6729,65 @@ static int __iwl_up(struct iwl_priv *priv) if (test_bit(STATUS_RF_KILL_SW, &priv->status)) { IWL_WARNING("Radio disabled by SW RF kill (module " "parameter)\n"); - return 0; + return -ENODEV; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl4965_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_WARNING("Radio disabled by HW RF Kill switch\n"); + return -ENODEV; + } + } + + if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { + IWL_ERROR("ucode not available for device bringup\n"); + return -EIO; } - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF); - rc = iwl_hw_nic_init(priv); + rc = iwl4965_hw_nic_init(priv); if (rc) { IWL_ERROR("Unable to int nic\n"); return rc; } /* 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, + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl4965_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); - iwl_enable_interrupts(priv); + iwl4965_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); + iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl4965_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); - - /* If platform's RF_KILL switch is set to KILL, - * wait for BIT_INT_RF_KILL interrupt before loading uCode - * and getting things started */ - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; + priv->ucode_data.len); - if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) { - IWL_WARNING("Radio disabled by HW RF Kill switch\n"); + /* We return success when we resume from suspend and rf_kill is on. */ + if (test_bit(STATUS_RF_KILL_HW, &priv->status)) return 0; - } for (i = 0; i < MAX_HW_RESTARTS; i++) { - iwl_clear_stations_table(priv); + iwl4965_clear_stations_table(priv); /* load bootstrap state machine, * load bootstrap program into processor's memory, * prepare to load the "initialize" uCode */ - rc = iwl_load_bsm(priv); + rc = iwl4965_load_bsm(priv); if (rc) { IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc); @@ -6752,14 +6795,7 @@ static int __iwl_up(struct iwl_priv *priv) } /* start card; "initialize" will load runtime ucode */ - iwl_nic_start(priv); - - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_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); + iwl4965_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -6767,7 +6803,7 @@ static int __iwl_up(struct iwl_priv *priv) } set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl_down(priv); + __iwl4965_down(priv); /* tried to restart and config the device for as long as our * patience could withstand */ @@ -6782,35 +6818,35 @@ static int __iwl_up(struct iwl_priv *priv) * *****************************************************************************/ -static void iwl_bg_init_alive_start(struct work_struct *data) +static void iwl4965_bg_init_alive_start(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, init_alive_start.work); + struct iwl4965_priv *priv = + container_of(data, struct iwl4965_priv, init_alive_start.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_init_alive_start(priv); + iwl4965_init_alive_start(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_alive_start(struct work_struct *data) +static void iwl4965_bg_alive_start(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, alive_start.work); + struct iwl4965_priv *priv = + container_of(data, struct iwl4965_priv, alive_start.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_alive_start(priv); + iwl4965_alive_start(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_rf_kill(struct work_struct *work) +static void iwl4965_bg_rf_kill(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); + struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, rf_kill); wake_up_interruptible(&priv->wait_command_queue); @@ -6819,7 +6855,7 @@ static void iwl_bg_rf_kill(struct work_struct *work) mutex_lock(&priv->mutex); - if (!iwl_is_rfkill(priv)) { + if (!iwl4965_is_rfkill(priv)) { IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL, "HW and/or SW RF Kill no longer active, restarting " "device\n"); @@ -6840,10 +6876,10 @@ static void iwl_bg_rf_kill(struct work_struct *work) #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) -static void iwl_bg_scan_check(struct work_struct *data) +static void iwl4965_bg_scan_check(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, scan_check.work); + struct iwl4965_priv *priv = + container_of(data, struct iwl4965_priv, scan_check.work); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6856,22 +6892,22 @@ static void iwl_bg_scan_check(struct work_struct *data) jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - iwl_send_scan_abort(priv); + iwl4965_send_scan_abort(priv); } mutex_unlock(&priv->mutex); } -static void iwl_bg_request_scan(struct work_struct *data) +static void iwl4965_bg_request_scan(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, request_scan); - struct iwl_host_cmd cmd = { + struct iwl4965_priv *priv = + container_of(data, struct iwl4965_priv, request_scan); + struct iwl4965_host_cmd cmd = { .id = REPLY_SCAN_CMD, - .len = sizeof(struct iwl_scan_cmd), + .len = sizeof(struct iwl4965_scan_cmd), .meta.flags = CMD_SIZE_HUGE, }; int rc = 0; - struct iwl_scan_cmd *scan; + struct iwl4965_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u8 direct_mask; int phymode; @@ -6880,7 +6916,7 @@ static void iwl_bg_request_scan(struct work_struct *data) mutex_lock(&priv->mutex); - if (!iwl_is_ready(priv)) { + if (!iwl4965_is_ready(priv)) { IWL_WARNING("request scan called when driver not ready.\n"); goto done; } @@ -6909,7 +6945,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } - if (iwl_is_rfkill(priv)) { + if (iwl4965_is_rfkill(priv)) { IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); goto done; } @@ -6925,7 +6961,7 @@ static void iwl_bg_request_scan(struct work_struct *data) } if (!priv->scan) { - priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + + priv->scan = kmalloc(sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE, GFP_KERNEL); if (!priv->scan) { rc = -ENOMEM; @@ -6933,12 +6969,12 @@ static void iwl_bg_request_scan(struct work_struct *data) } } scan = priv->scan; - memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + memset(scan, 0, sizeof(struct iwl4965_scan_cmd) + IWL_MAX_SCAN_SIZE); scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - if (iwl_is_associated(priv)) { + if (iwl4965_is_associated(priv)) { u16 interval = 0; u32 extra; u32 suspend_time = 100; @@ -6968,14 +7004,14 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->one_direct_scan) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s'\n", - iwl_escape_essid(priv->direct_ssid, + iwl4965_escape_essid(priv->direct_ssid, priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); direct_mask = 1; - } else if (!iwl_is_associated(priv) && priv->essid_len) { + } else if (!iwl4965_is_associated(priv) && priv->essid_len) { scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->essid_len; memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); @@ -6986,7 +7022,7 @@ static void iwl_bg_request_scan(struct work_struct *data) /* We don't build a direct scan probe request; the uCode will do * that based on the direct_mask added to each channel entry */ scan->tx_cmd.len = cpu_to_le16( - iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, + iwl4965_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, IWL_MAX_SCAN_SIZE - sizeof(scan), 0)); scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id; @@ -7000,7 +7036,7 @@ static void iwl_bg_request_scan(struct work_struct *data) case 2: scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, + iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK); scan->good_CRC_th = 0; @@ -7009,7 +7045,7 @@ static void iwl_bg_request_scan(struct work_struct *data) case 1: scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, + iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, RATE_MCS_ANT_B_MSK); scan->good_CRC_th = IWL_GOOD_CRC_TH; phymode = MODE_IEEE80211A; @@ -7036,23 +7072,23 @@ static void iwl_bg_request_scan(struct work_struct *data) if (direct_mask) IWL_DEBUG_SCAN ("Initiating direct scan for %s.\n", - iwl_escape_essid(priv->essid, priv->essid_len)); + iwl4965_escape_essid(priv->essid, priv->essid_len)); else IWL_DEBUG_SCAN("Initiating indirect scan.\n"); scan->channel_count = - iwl_get_channels_for_scan( + iwl4965_get_channels_for_scan( priv, phymode, 1, /* active */ direct_mask, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); cmd.len += le16_to_cpu(scan->tx_cmd.len) + - scan->channel_count * sizeof(struct iwl_scan_channel); + scan->channel_count * sizeof(struct iwl4965_scan_channel); cmd.data = scan; scan->len = cpu_to_le16(cmd.len); set_bit(STATUS_SCAN_HW, &priv->status); - rc = iwl_send_cmd_sync(priv, &cmd); + rc = iwl4965_send_cmd_sync(priv, &cmd); if (rc) goto done; @@ -7063,50 +7099,52 @@ static void iwl_bg_request_scan(struct work_struct *data) return; done: - /* inform mac80211 sacn aborted */ + /* inform mac80211 scan aborted */ queue_work(priv->workqueue, &priv->scan_completed); mutex_unlock(&priv->mutex); } -static void iwl_bg_up(struct work_struct *data) +static void iwl4965_bg_up(struct work_struct *data) { - struct iwl_priv *priv = container_of(data, struct iwl_priv, up); + struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, up); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - __iwl_up(priv); + __iwl4965_up(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_restart(struct work_struct *data) +static void iwl4965_bg_restart(struct work_struct *data) { - struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); + struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, restart); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl_down(priv); + iwl4965_down(priv); queue_work(priv->workqueue, &priv->up); } -static void iwl_bg_rx_replenish(struct work_struct *data) +static void iwl4965_bg_rx_replenish(struct work_struct *data) { - struct iwl_priv *priv = - container_of(data, struct iwl_priv, rx_replenish); + struct iwl4965_priv *priv = + container_of(data, struct iwl4965_priv, rx_replenish); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; mutex_lock(&priv->mutex); - iwl_rx_replenish(priv); + iwl4965_rx_replenish(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_post_associate(struct work_struct *data) +#define IWL_DELAY_NEXT_SCAN (HZ*2) + +static void iwl4965_bg_post_associate(struct work_struct *data) { - struct iwl_priv *priv = container_of(data, struct iwl_priv, + struct iwl4965_priv *priv = container_of(data, struct iwl4965_priv, post_associate.work); int rc = 0; @@ -7128,20 +7166,20 @@ static void iwl_bg_post_associate(struct work_struct *data) mutex_lock(&priv->mutex); - if (!priv->interface_id || !priv->is_open) { + if (!priv->vif || !priv->is_open) { mutex_unlock(&priv->mutex); return; } - iwl_scan_cancel_timeout(priv, 200); + iwl4965_scan_cancel_timeout(priv, 200); conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); - memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl_setup_rxon_timing(priv); - rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); + iwl4965_setup_rxon_timing(priv); + rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (rc) IWL_WARNING("REPLY_RXON_TIMING failed - " @@ -7149,15 +7187,10 @@ static void iwl_bg_post_associate(struct work_struct *data) priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; -#ifdef CONFIG_IWLWIFI_HT - if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht) - iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht); - else { - priv->active_rate_ht[0] = 0; - priv->active_rate_ht[1] = 0; - priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ; - } -#endif /* CONFIG_IWLWIFI_HT*/ +#ifdef CONFIG_IWL4965_HT + if (priv->current_ht_config.is_ht) + iwl4965_set_rxon_ht(priv, &priv->current_ht_config); +#endif /* CONFIG_IWL4965_HT*/ iwl4965_set_rxon_chain(priv); priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id); @@ -7180,22 +7213,22 @@ static void iwl_bg_post_associate(struct work_struct *data) } - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); switch (priv->iw_mode) { case IEEE80211_IF_TYPE_STA: - iwl_rate_scale_init(priv->hw, IWL_AP_ID); + iwl4965_rate_scale_init(priv->hw, IWL_AP_ID); break; case IEEE80211_IF_TYPE_IBSS: /* clear out the station table */ - iwl_clear_stations_table(priv); + iwl4965_clear_stations_table(priv); - iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); - iwl_rxon_add_station(priv, priv->bssid, 0); - iwl_rate_scale_init(priv->hw, IWL_STA_ID); - iwl_send_beacon_cmd(priv); + iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); + iwl4965_rxon_add_station(priv, priv->bssid, 0); + iwl4965_rate_scale_init(priv->hw, IWL_STA_ID); + iwl4965_send_beacon_cmd(priv); break; @@ -7205,55 +7238,61 @@ static void iwl_bg_post_associate(struct work_struct *data) break; } - iwl_sequence_reset(priv); + iwl4965_sequence_reset(priv); -#ifdef CONFIG_IWLWIFI_SENSITIVITY +#ifdef CONFIG_IWL4965_SENSITIVITY /* Enable Rx differential gain and sensitivity calibrations */ iwl4965_chain_noise_reset(priv); priv->start_calib = 1; -#endif /* CONFIG_IWLWIFI_SENSITIVITY */ +#endif /* CONFIG_IWL4965_SENSITIVITY */ if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) priv->assoc_station_added = 1; -#ifdef CONFIG_IWLWIFI_QOS - iwl_activate_qos(priv, 0); -#endif /* CONFIG_IWLWIFI_QOS */ +#ifdef CONFIG_IWL4965_QOS + iwl4965_activate_qos(priv, 0); +#endif /* CONFIG_IWL4965_QOS */ + /* we have just associated, don't start scan too early */ + priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN; mutex_unlock(&priv->mutex); } -static void iwl_bg_abort_scan(struct work_struct *work) +static void iwl4965_bg_abort_scan(struct work_struct *work) { - struct iwl_priv *priv = container_of(work, struct iwl_priv, - abort_scan); + struct iwl4965_priv *priv = container_of(work, struct iwl4965_priv, abort_scan); - if (!iwl_is_ready(priv)) + if (!iwl4965_is_ready(priv)) return; mutex_lock(&priv->mutex); set_bit(STATUS_SCAN_ABORTING, &priv->status); - iwl_send_scan_abort(priv); + iwl4965_send_scan_abort(priv); mutex_unlock(&priv->mutex); } -static void iwl_bg_scan_completed(struct work_struct *work) +static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + +static void iwl4965_bg_scan_completed(struct work_struct *work) { - struct iwl_priv *priv = - container_of(work, struct iwl_priv, scan_completed); + struct iwl4965_priv *priv = + container_of(work, struct iwl4965_priv, scan_completed); IWL_DEBUG(IWL_DL_INFO | IWL_DL_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_hw_reg_send_txpower(priv); + iwl4965_hw_reg_send_txpower(priv); mutex_unlock(&priv->mutex); } @@ -7263,50 +7302,123 @@ static void iwl_bg_scan_completed(struct work_struct *work) * *****************************************************************************/ -static int iwl_mac_start(struct ieee80211_hw *hw) +#define UCODE_READY_TIMEOUT (2 * HZ) + +static int iwl4965_mac_start(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_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); - priv->is_open = 1; + memset(&priv->staging_rxon, 0, sizeof(struct iwl4965_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; + } + } - if (!iwl_is_rfkill(priv)) - ieee80211_start_queues(priv->hw); + ret = __iwl4965_up(priv); mutex_unlock(&priv->mutex); + + 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 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("Wait for 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 iwl_mac_stop(struct ieee80211_hw *hw) +static void iwl4965_mac_stop(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); + if (!priv->is_open) { + IWL_DEBUG_MAC80211("leave - skip\n"); + return; + } - mutex_lock(&priv->mutex); - /* stop mac, cancel any scan request and clear - * RXON_FILTER_ASSOC_MSK BIT - */ priv->is_open = 0; - iwl_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - mutex_unlock(&priv->mutex); + + if (iwl4965_is_ready_rf(priv)) { + /* stop mac, cancel any scan request and clear + * RXON_FILTER_ASSOC_MSK BIT + */ + mutex_lock(&priv->mutex); + iwl4965_scan_cancel_timeout(priv, 100); + cancel_delayed_work(&priv->post_associate); + 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 iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, +static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *ctl) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); @@ -7318,29 +7430,29 @@ static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, ctl->tx_rate); - if (iwl_tx_skb(priv, skb, ctl)) + if (iwl4965_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); IWL_DEBUG_MAC80211("leave\n"); return 0; } -static int iwl_mac_add_interface(struct ieee80211_hw *hw, +static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; unsigned long flags; DECLARE_MAC_BUF(mac); - IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type); + IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); - if (priv->interface_id) { - IWL_DEBUG_MAC80211("leave - interface_id != 0\n"); + if (priv->vif) { + IWL_DEBUG_MAC80211("leave - vif != NULL\n"); return 0; } spin_lock_irqsave(&priv->lock, flags); - priv->interface_id = conf->if_id; + priv->vif = conf->vif; spin_unlock_irqrestore(&priv->lock, flags); @@ -7350,58 +7462,62 @@ static int iwl_mac_add_interface(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - iwl_set_mode(priv, conf->type); - IWL_DEBUG_MAC80211("leave\n"); + if (iwl4965_is_ready(priv)) + iwl4965_set_mode(priv, conf->type); + mutex_unlock(&priv->mutex); + IWL_DEBUG_MAC80211("leave\n"); return 0; } /** - * iwl_mac_config - mac80211 config callback + * 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 iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +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; + struct iwl4965_priv *priv = hw->priv; + const struct iwl4965_channel_info *ch_info; unsigned long flags; + int ret = 0; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); - if (!iwl_is_ready(priv)) { + priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); + + if (!iwl4965_is_ready(priv)) { IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return -EIO; + ret = -EIO; + goto out; } - /* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only - * what is exposed through include/ declrations */ - if (unlikely(!iwl_param_disable_hw_scan && + if (unlikely(!iwl4965_param_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; } spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl4965_get_channel_info(priv, conf->phymode, conf->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", conf->channel, conf->phymode); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); - mutex_unlock(&priv->mutex); - return -EINVAL; + ret = -EINVAL; + goto out; } -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT /* if we are switching fron ht to 2.4 clear flags * from any ht related info since 2.4 does not * support ht */ @@ -7411,57 +7527,56 @@ static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) #endif ) priv->staging_rxon.flags = 0; -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT */ - iwl_set_rxon_channel(priv, conf->phymode, conf->channel); + iwl4965_set_rxon_channel(priv, conf->phymode, conf->channel); - iwl_set_flags_for_phymode(priv, conf->phymode); + iwl4965_set_flags_for_phymode(priv, conf->phymode); /* The list of supported rates and rate mask can be different * for each phymode; since the phymode may have changed, reset * the rate mask to what mac80211 lists */ - iwl_set_rate(priv); + iwl4965_set_rate(priv); spin_unlock_irqrestore(&priv->lock, flags); #ifdef IEEE80211_CONF_CHANNEL_SWITCH if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl_hw_channel_switch(priv, conf->channel); - mutex_unlock(&priv->mutex); - return 0; + iwl4965_hw_channel_switch(priv, conf->channel); + goto out; } #endif - iwl_radio_kill_sw(priv, !conf->radio_enabled); + iwl4965_radio_kill_sw(priv, !conf->radio_enabled); if (!conf->radio_enabled) { IWL_DEBUG_MAC80211("leave - radio disabled\n"); - mutex_unlock(&priv->mutex); - return 0; + goto out; } - if (iwl_is_rfkill(priv)) { + if (iwl4965_is_rfkill(priv)) { IWL_DEBUG_MAC80211("leave - RF kill\n"); - mutex_unlock(&priv->mutex); - return -EIO; + ret = -EIO; + goto out; } - iwl_set_rate(priv); + iwl4965_set_rate(priv); if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl_commit_rxon(priv); + 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 0; + return ret; } -static void iwl_config_ap(struct iwl_priv *priv) +static void iwl4965_config_ap(struct iwl4965_priv *priv) { int rc = 0; @@ -7473,12 +7588,12 @@ static void iwl_config_ap(struct iwl_priv *priv) /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); /* RXON Timing */ - memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd)); - iwl_setup_rxon_timing(priv); - rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, + memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); + iwl4965_setup_rxon_timing(priv); + rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (rc) IWL_WARNING("REPLY_RXON_TIMING failed - " @@ -7510,23 +7625,24 @@ static void iwl_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); -#ifdef CONFIG_IWLWIFI_QOS - iwl_activate_qos(priv, 1); + iwl4965_commit_rxon(priv); +#ifdef CONFIG_IWL4965_QOS + iwl4965_activate_qos(priv, 1); #endif - iwl_rxon_add_station(priv, BROADCAST_ADDR, 0); + iwl4965_rxon_add_station(priv, iwl4965_broadcast_addr, 0); } - iwl_send_beacon_cmd(priv); + 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... */ } -static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, +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; + struct iwl4965_priv *priv = hw->priv; DECLARE_MAC_BUF(mac); unsigned long flags; int rc; @@ -7541,9 +7657,11 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } + if (!iwl4965_is_alive(priv)) + return -EAGAIN; + mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id); if (conf->bssid) IWL_DEBUG_MAC80211("bssid: %s\n", print_mac(mac, conf->bssid)); @@ -7560,8 +7678,8 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } - if (priv->interface_id != if_id) { - IWL_DEBUG_MAC80211("leave - interface_id != if_id\n"); + if (priv->vif != vif) { + IWL_DEBUG_MAC80211("leave - priv->vif != vif\n"); mutex_unlock(&priv->mutex); return 0; } @@ -7579,11 +7697,14 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, priv->ibss_beacon = conf->beacon; } + if (iwl4965_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)) { + if (iwl4965_scan_cancel_timeout(priv, 100)) { IWL_WARNING("Aborted scan still in progress " "after 100ms\n"); IWL_DEBUG_MAC80211("leaving - scan abort failed.\n"); @@ -7599,20 +7720,21 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == IEEE80211_IF_TYPE_AP) - iwl_config_ap(priv); + iwl4965_config_ap(priv); else { - rc = iwl_commit_rxon(priv); + rc = iwl4965_commit_rxon(priv); if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc) - iwl_rxon_add_station( + iwl4965_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); } } else { - iwl_scan_cancel_timeout(priv, 100); + iwl4965_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); } + done: spin_lock_irqsave(&priv->lock, flags); if (!conf->ssid_len) memset(priv->essid, 0, IW_ESSID_MAX_SIZE); @@ -7628,34 +7750,35 @@ static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id, return 0; } -static void iwl_configure_filter(struct ieee80211_hw *hw, +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) { /* * XXX: dummy - * see also iwl_connection_init_rx_config + * see also iwl4965_connection_init_rx_config */ *total_flags = 0; } -static void iwl_mac_remove_interface(struct ieee80211_hw *hw, +static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); - cancel_delayed_work(&priv->post_associate); - priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); - - if (priv->interface_id == conf->if_id) { - priv->interface_id = 0; + if (iwl4965_is_ready_rf(priv)) { + iwl4965_scan_cancel_timeout(priv, 100); + cancel_delayed_work(&priv->post_associate); + 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; @@ -7666,19 +7789,50 @@ static void iwl_mac_remove_interface(struct ieee80211_hw *hw, } -#define IWL_DELAY_NEXT_SCAN (HZ*2) -static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) +static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) +{ + struct iwl4965_priv *priv = hw->priv; + + if (changes & BSS_CHANGED_ERP_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) { + if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A)) + priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; + else + priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; + } + + if (changes & BSS_CHANGED_ASSOC) { + /* + * TODO: + * do stuff instead of sniffing assoc resp + */ + } + + if (iwl4965_is_associated(priv)) + iwl4965_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; + struct iwl4965_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)) { + if (!iwl4965_is_ready_rf(priv)) { rc = -EIO; IWL_DEBUG_MAC80211("leave - not ready or exit pending\n"); goto out_unlock; @@ -7690,17 +7844,21 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) 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)) { + 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); + IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", + iwl4965_escape_essid(ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) @@ -7709,7 +7867,7 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } else priv->one_direct_scan = 0; - rc = iwl_scan_initiate(priv); + rc = iwl4965_scan_initiate(priv); IWL_DEBUG_MAC80211("leave\n"); @@ -7720,18 +7878,18 @@ out_unlock: return rc; } -static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +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; + struct iwl4965_priv *priv = hw->priv; DECLARE_MAC_BUF(mac); int rc = 0; u8 sta_id; IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_param_hwcrypto) { + if (!iwl4965_param_hwcrypto) { IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n"); return -EOPNOTSUPP; } @@ -7740,7 +7898,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, /* only support pairwise keys */ return -EOPNOTSUPP; - sta_id = iwl_hw_find_station(priv, addr); + sta_id = iwl4965_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { IWL_DEBUG_MAC80211("leave - %s not in station map.\n", print_mac(mac, addr)); @@ -7749,24 +7907,24 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&priv->mutex); - iwl_scan_cancel_timeout(priv, 100); + iwl4965_scan_cancel_timeout(priv, 100); switch (cmd) { case SET_KEY: - rc = iwl_update_sta_key_info(priv, key, sta_id); + rc = iwl4965_update_sta_key_info(priv, key, sta_id); if (!rc) { - iwl_set_rxon_hwcrypto(priv, 1); - iwl_commit_rxon(priv); + iwl4965_set_rxon_hwcrypto(priv, 1); + iwl4965_commit_rxon(priv); key->hw_key_idx = sta_id; IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n"); key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; } break; case DISABLE_KEY: - rc = iwl_clear_sta_key_info(priv, sta_id); + rc = iwl4965_clear_sta_key_info(priv, sta_id); if (!rc) { - iwl_set_rxon_hwcrypto(priv, 0); - iwl_commit_rxon(priv); + iwl4965_set_rxon_hwcrypto(priv, 0); + iwl4965_commit_rxon(priv); IWL_DEBUG_MAC80211("disable hwcrypto key\n"); } break; @@ -7780,18 +7938,18 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return rc; } -static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, +static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) { - struct iwl_priv *priv = hw->priv; -#ifdef CONFIG_IWLWIFI_QOS + struct iwl4965_priv *priv = hw->priv; +#ifdef CONFIG_IWL4965_QOS unsigned long flags; int q; -#endif /* CONFIG_IWL_QOS */ +#endif /* CONFIG_IWL4965_QOS */ IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl4965_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); return -EIO; } @@ -7801,7 +7959,7 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, return 0; } -#ifdef CONFIG_IWLWIFI_QOS +#ifdef CONFIG_IWL4965_QOS if (!priv->qos_data.qos_enable) { priv->qos_data.qos_active = 0; IWL_DEBUG_MAC80211("leave - qos not enabled\n"); @@ -7824,30 +7982,30 @@ static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue, mutex_lock(&priv->mutex); 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); + iwl4965_activate_qos(priv, 1); + else if (priv->assoc_id && iwl4965_is_associated(priv)) + iwl4965_activate_qos(priv, 0); mutex_unlock(&priv->mutex); -#endif /*CONFIG_IWLWIFI_QOS */ +#endif /*CONFIG_IWL4965_QOS */ IWL_DEBUG_MAC80211("leave\n"); return 0; } -static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, +static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; int i, avail; - struct iwl_tx_queue *txq; - struct iwl_queue *q; + struct iwl4965_tx_queue *txq; + struct iwl4965_queue *q; unsigned long flags; IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl4965_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); return -EIO; } @@ -7857,7 +8015,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, for (i = 0; i < AC_NUM; i++) { txq = &priv->txq[i]; q = &txq->q; - avail = iwl_queue_space(q); + avail = iwl4965_queue_space(q); stats->data[i].len = q->n_window - avail; stats->data[i].limit = q->n_window - q->high_mark; @@ -7871,7 +8029,7 @@ static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, return 0; } -static int iwl_mac_get_stats(struct ieee80211_hw *hw, +static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { IWL_DEBUG_MAC80211("enter\n"); @@ -7880,7 +8038,7 @@ static int iwl_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) +static u64 iwl4965_mac_get_tsf(struct ieee80211_hw *hw) { IWL_DEBUG_MAC80211("enter\n"); IWL_DEBUG_MAC80211("leave\n"); @@ -7888,35 +8046,35 @@ static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw) return 0; } -static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) +static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; unsigned long flags; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); priv->lq_mngr.lq_ready = 0; -#ifdef CONFIG_IWLWIFI_HT +#ifdef CONFIG_IWL4965_HT spin_lock_irqsave(&priv->lock, flags); - memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info)); + memset(&priv->current_ht_config, 0, sizeof(struct iwl_ht_info)); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT_AGG /* if (priv->lq_mngr.agg_ctrl.granted_ba) iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/ - memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control)); + memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl4965_agg_control)); priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10; priv->lq_mngr.agg_ctrl.ba_timeout = 5000; priv->lq_mngr.agg_ctrl.auto_agg = 1; if (priv->lq_mngr.agg_ctrl.auto_agg) priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED; -#endif /*CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /*CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ -#ifdef CONFIG_IWLWIFI_QOS - iwl_reset_qos(priv); +#ifdef CONFIG_IWL4965_QOS + iwl4965_reset_qos(priv); #endif cancel_delayed_work(&priv->post_associate); @@ -7941,13 +8099,19 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) spin_unlock_irqrestore(&priv->lock, flags); + if (!iwl4965_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); + iwl4965_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); } /* Per mac80211.h: This is only used in IBSS mode... */ @@ -7958,32 +8122,25 @@ static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) return; } - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_MAC80211("leave - not ready\n"); - mutex_unlock(&priv->mutex); - return; - } - priv->only_active_channel = 0; - iwl_set_rate(priv); + iwl4965_set_rate(priv); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211("leave\n"); - } -static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, +static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct iwl_priv *priv = hw->priv; + struct iwl4965_priv *priv = hw->priv; unsigned long flags; mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl4965_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); mutex_unlock(&priv->mutex); return -EIO; @@ -8007,8 +8164,8 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, IWL_DEBUG_MAC80211("leave\n"); spin_unlock_irqrestore(&priv->lock, flags); -#ifdef CONFIG_IWLWIFI_QOS - iwl_reset_qos(priv); +#ifdef CONFIG_IWL4965_QOS + iwl4965_reset_qos(priv); #endif queue_work(priv->workqueue, &priv->post_associate.work); @@ -8018,133 +8175,62 @@ static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, return 0; } -#ifdef CONFIG_IWLWIFI_HT -union ht_cap_info { - struct { - u16 advanced_coding_cap :1; - u16 supported_chan_width_set :1; - u16 mimo_power_save_mode :2; - u16 green_field :1; - u16 short_GI20 :1; - u16 short_GI40 :1; - u16 tx_stbc :1; - u16 rx_stbc :1; - u16 beam_forming :1; - u16 delayed_ba :1; - u16 maximal_amsdu_size :1; - u16 cck_mode_at_40MHz :1; - u16 psmp_support :1; - u16 stbc_ctrl_frame_support :1; - u16 sig_txop_protection_support :1; - }; - u16 val; -} __attribute__ ((packed)); - -union ht_param_info{ - struct { - u8 max_rx_ampdu_factor :2; - u8 mpdu_density :3; - u8 reserved :3; - }; - u8 val; -} __attribute__ ((packed)); - -union ht_exra_param_info { - struct { - u8 ext_chan_offset :2; - u8 tx_chan_width :1; - u8 rifs_mode :1; - u8 controlled_access_only :1; - u8 service_interval_granularity :3; - }; - u8 val; -} __attribute__ ((packed)); - -union ht_operation_mode{ - struct { - u16 op_mode :2; - u16 non_GF :1; - u16 reserved :13; - }; - u16 val; -} __attribute__ ((packed)); - +#ifdef CONFIG_IWL4965_HT -static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap, - struct ieee80211_ht_additional_info *ht_extra, - struct sta_ht_info *ht_info_ap, - struct sta_ht_info *ht_info) +static void iwl4965_ht_info_fill(struct ieee80211_conf *conf, + struct iwl4965_priv *priv) { - union ht_cap_info cap; - union ht_operation_mode op_mode; - union ht_param_info param_info; - union ht_exra_param_info extra_param_info; + struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct ieee80211_ht_info *ht_conf = &conf->ht_conf; + struct ieee80211_ht_bss_info *ht_bss_conf = &conf->ht_bss_conf; IWL_DEBUG_MAC80211("enter: \n"); - if (!ht_info) { - IWL_DEBUG_MAC80211("leave: ht_info is NULL\n"); - return -1; + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) { + iwl_conf->is_ht = 0; + return; } - if (ht_cap) { - cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info); - param_info.val = ht_cap->mac_ht_params_info; - ht_info->is_ht = 1; - if (cap.short_GI20) - ht_info->sgf |= 0x1; - if (cap.short_GI40) - ht_info->sgf |= 0x2; - ht_info->is_green_field = cap.green_field; - ht_info->max_amsdu_size = cap.maximal_amsdu_size; - ht_info->supported_chan_width = cap.supported_chan_width_set; - ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode; - memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16); - - ht_info->ampdu_factor = param_info.max_rx_ampdu_factor; - ht_info->mpdu_density = param_info.mpdu_density; - - IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n", - ht_cap->supported_mcs_set[0], - ht_cap->supported_mcs_set[1]); - - if (ht_info_ap) { - ht_info->control_channel = ht_info_ap->control_channel; - ht_info->extension_chan_offset = - ht_info_ap->extension_chan_offset; - ht_info->tx_chan_width = ht_info_ap->tx_chan_width; - ht_info->operating_mode = ht_info_ap->operating_mode; - } - - if (ht_extra) { - extra_param_info.val = ht_extra->ht_param; - ht_info->control_channel = ht_extra->control_chan; - ht_info->extension_chan_offset = - extra_param_info.ext_chan_offset; - ht_info->tx_chan_width = extra_param_info.tx_chan_width; - op_mode.val = (u16) - le16_to_cpu(ht_extra->operation_mode); - ht_info->operating_mode = op_mode.op_mode; - IWL_DEBUG_MAC80211("control channel %d\n", - ht_extra->control_chan); - } - } else - ht_info->is_ht = 0; - + iwl_conf->is_ht = 1; + 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 |= 0x1; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) + iwl_conf->sgf |= 0x2; + + 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->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->extension_chan_offset = + ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_SEC_OFFSET; + 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"); - return 0; } -static int iwl_mac_conf_ht(struct ieee80211_hw *hw, - struct ieee80211_ht_capability *ht_cap, - struct ieee80211_ht_additional_info *ht_extra) +static int iwl4965_mac_conf_ht(struct ieee80211_hw *hw, + struct ieee80211_conf *conf) { - struct iwl_priv *priv = hw->priv; - int rs; + struct iwl4965_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter: \n"); - rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht); + iwl4965_ht_info_fill(conf, priv); iwl4965_set_rxon_chain(priv); if (priv && priv->assoc_id && @@ -8159,58 +8245,33 @@ static int iwl_mac_conf_ht(struct ieee80211_hw *hw, spin_unlock_irqrestore(&priv->lock, flags); } - IWL_DEBUG_MAC80211("leave: control channel %d\n", - ht_extra->control_chan); - return rs; - + IWL_DEBUG_MAC80211("leave:\n"); + return 0; } -static void iwl_set_ht_capab(struct ieee80211_hw *hw, - struct ieee80211_ht_capability *ht_cap, - u8 use_wide_chan) +static void iwl4965_set_ht_capab(struct ieee80211_hw *hw, + struct ieee80211_ht_cap *ht_cap, + u8 use_current_config) { - union ht_cap_info cap; - union ht_param_info param_info; - - memset(&cap, 0, sizeof(union ht_cap_info)); - memset(¶m_info, 0, sizeof(union ht_param_info)); - - cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K; - cap.green_field = 1; - cap.short_GI20 = 1; - cap.short_GI40 = 1; - cap.supported_chan_width_set = use_wide_chan; - cap.mimo_power_save_mode = 0x3; - - param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; - param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF; - ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val); - ht_cap->mac_ht_params_info = (u8) param_info.val; + struct ieee80211_conf *conf = &hw->conf; + struct ieee80211_hw_mode *mode = conf->mode; - ht_cap->supported_mcs_set[0] = 0xff; - ht_cap->supported_mcs_set[1] = 0xff; - ht_cap->supported_mcs_set[4] = - (cap.supported_chan_width_set) ? 0x1: 0x0; + if (use_current_config) { + ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap); + memcpy(ht_cap->supp_mcs_set, + conf->ht_conf.supp_mcs_set, 16); + } else { + ht_cap->cap_info = cpu_to_le16(mode->ht_info.cap); + memcpy(ht_cap->supp_mcs_set, + mode->ht_info.supp_mcs_set, 16); + } + ht_cap->ampdu_params_info = + (mode->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | + ((mode->ht_info.ampdu_density << 2) & + IEEE80211_HT_CAP_AMPDU_DENSITY); } -static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw, - struct ieee80211_ht_capability *ht_cap) -{ - u8 use_wide_channel = 1; - struct iwl_priv *priv = hw->priv; - - IWL_DEBUG_MAC80211("enter: \n"); - if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ) - use_wide_channel = 0; - - /* no fat tx allowed on 2.4GHZ */ - if (priv->phymode != MODE_IEEE80211A) - use_wide_channel = 0; - - iwl_set_ht_capab(hw, ht_cap, use_wide_channel); - IWL_DEBUG_MAC80211("leave: \n"); -} -#endif /*CONFIG_IWLWIFI_HT*/ +#endif /*CONFIG_IWL4965_HT*/ /***************************************************************************** * @@ -8218,7 +8279,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw, * *****************************************************************************/ -#ifdef CONFIG_IWLWIFI_DEBUG +#ifdef CONFIG_IWL4965_DEBUG /* * The following adds a new attribute to the sysfs representation @@ -8230,7 +8291,7 @@ static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw, static ssize_t show_debug_level(struct device_driver *d, char *buf) { - return sprintf(buf, "0x%08X\n", iwl_debug_level); + return sprintf(buf, "0x%08X\n", iwl4965_debug_level); } static ssize_t store_debug_level(struct device_driver *d, const char *buf, size_t count) @@ -8243,7 +8304,7 @@ static ssize_t store_debug_level(struct device_driver *d, printk(KERN_INFO DRV_NAME ": %s is not in hex or decimal form.\n", buf); else - iwl_debug_level = val; + iwl4965_debug_level = val; return strnlen(buf, count); } @@ -8251,7 +8312,7 @@ static ssize_t store_debug_level(struct device_driver *d, static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, show_debug_level, store_debug_level); -#endif /* CONFIG_IWLWIFI_DEBUG */ +#endif /* CONFIG_IWL4965_DEBUG */ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, char *buf) @@ -8262,7 +8323,7 @@ static ssize_t show_rf_kill(struct device *d, * 2 - HW based RF kill active * 3 - Both HW and SW based RF kill active */ - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) | (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0); @@ -8273,10 +8334,10 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; mutex_lock(&priv->mutex); - iwl_radio_kill_sw(priv, buf[0] == '1'); + iwl4965_radio_kill_sw(priv, buf[0] == '1'); mutex_unlock(&priv->mutex); return count; @@ -8287,12 +8348,12 @@ static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); static ssize_t show_temperature(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - if (!iwl_is_alive(priv)) + if (!iwl4965_is_alive(priv)) return -EAGAIN; - return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv)); + return sprintf(buf, "%d\n", iwl4965_hw_get_temperature(priv)); } static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); @@ -8301,15 +8362,15 @@ static ssize_t show_rs_window(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = d->driver_data; - return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID); + struct iwl4965_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) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; return sprintf(buf, "%d\n", priv->user_txpower_limit); } @@ -8317,7 +8378,7 @@ 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; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; char *p = (char *)buf; u32 val; @@ -8326,7 +8387,7 @@ static ssize_t store_tx_power(struct device *d, printk(KERN_INFO DRV_NAME ": %s is not in decimal form.\n", buf); else - iwl_hw_reg_set_txpower(priv, val); + iwl4965_hw_reg_set_txpower(priv, val); return count; } @@ -8336,7 +8397,7 @@ 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; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", priv->active_rxon.flags); } @@ -8345,19 +8406,19 @@ 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; + struct iwl4965_priv *priv = (struct iwl4965_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)) + if (iwl4965_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); - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -8370,7 +8431,7 @@ 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; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", le32_to_cpu(priv->active_rxon.filter_flags)); @@ -8380,20 +8441,20 @@ 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; + struct iwl4965_priv *priv = (struct iwl4965_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)) + if (iwl4965_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); - iwl_commit_rxon(priv); + iwl4965_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -8407,20 +8468,20 @@ static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, static ssize_t show_tune(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; return sprintf(buf, "0x%04X\n", (priv->phymode << 8) | le16_to_cpu(priv->active_rxon.channel)); } -static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode); +static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode); static ssize_t store_tune(struct device *d, struct device_attribute *attr, const char *buf, size_t count) { - struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; char *p = (char *)buf; u16 tune = simple_strtoul(p, &p, 0); u8 phymode = (tune >> 8) & 0xff; @@ -8431,9 +8492,9 @@ static ssize_t store_tune(struct device *d, mutex_lock(&priv->mutex); if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || (priv->phymode != phymode)) { - const struct iwl_channel_info *ch_info; + const struct iwl4965_channel_info *ch_info; - ch_info = iwl_get_channel_info(priv, phymode, channel); + ch_info = iwl4965_get_channel_info(priv, phymode, channel); if (!ch_info) { IWL_WARNING("Requested invalid phymode/channel " "combination: %d %d\n", phymode, channel); @@ -8442,18 +8503,18 @@ static ssize_t store_tune(struct device *d, } /* Cancel any currently running scans... */ - if (iwl_scan_cancel_timeout(priv, 100)) + if (iwl4965_scan_cancel_timeout(priv, 100)) IWL_WARNING("Could not cancel scan.\n"); else { IWL_DEBUG_INFO("Committing phymode and " "rxon.channel = %d %d\n", phymode, channel); - iwl_set_rxon_channel(priv, phymode, channel); - iwl_set_flags_for_phymode(priv, phymode); + iwl4965_set_rxon_channel(priv, phymode, channel); + iwl4965_set_flags_for_phymode(priv, phymode); - iwl_set_rate(priv); - iwl_commit_rxon(priv); + iwl4965_set_rate(priv); + iwl4965_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -8463,13 +8524,13 @@ static ssize_t store_tune(struct device *d, static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#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 iwl_spectrum_notification measure_report; + struct iwl4965_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; @@ -8501,7 +8562,7 @@ 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 iwl4965_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), @@ -8527,20 +8588,20 @@ static ssize_t store_measurement(struct device *d, IWL_DEBUG_INFO("Invoking measurement of type %d on " "channel %d (for '%s')\n", type, params.channel, buf); - iwl_get_measurement(priv, ¶ms, type); + iwl4965_get_measurement(priv, ¶ms, type); return count; } static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, show_measurement, store_measurement); -#endif /* CONFIG_IWLWIFI_SPECTRUM_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); + struct iwl4965_priv *priv = dev_get_drvdata(d); priv->retry_rate = simple_strtoul(buf, NULL, 0); if (priv->retry_rate <= 0) @@ -8552,7 +8613,7 @@ static ssize_t store_retry_rate(struct device *d, static ssize_t show_retry_rate(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl4965_priv *priv = dev_get_drvdata(d); return sprintf(buf, "%d", priv->retry_rate); } @@ -8563,14 +8624,14 @@ 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); + struct iwl4965_priv *priv = dev_get_drvdata(d); int rc; int mode; mode = simple_strtoul(buf, NULL, 0); mutex_lock(&priv->mutex); - if (!iwl_is_ready(priv)) { + if (!iwl4965_is_ready(priv)) { rc = -EAGAIN; goto out; } @@ -8581,7 +8642,7 @@ static ssize_t store_power_level(struct device *d, mode |= IWL_POWER_ENABLED; if (mode != priv->power_mode) { - rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode)); + rc = iwl4965_send_power_mode(priv, IWL_POWER_LEVEL(mode)); if (rc) { IWL_DEBUG_MAC80211("failed setting power mode.\n"); goto out; @@ -8617,7 +8678,7 @@ static const s32 period_duration[] = { static ssize_t show_power_level(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl4965_priv *priv = dev_get_drvdata(d); int level = IWL_POWER_LEVEL(priv->power_mode); char *p = buf; @@ -8652,18 +8713,18 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_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 iwl4965_priv *priv = dev_get_drvdata(d); int len = 0, i; struct ieee80211_channel *channels = NULL; const struct ieee80211_hw_mode *hw_mode = NULL; int count = 0; - if (!iwl_is_ready(priv)) + if (!iwl4965_is_ready(priv)) return -EAGAIN; - hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G); + hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211G); if (!hw_mode) - hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B); + hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211B); if (hw_mode) { channels = hw_mode->channels; count = hw_mode->num_channels; @@ -8690,7 +8751,7 @@ static ssize_t show_channels(struct device *d, flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? "active/passive" : "passive only"); - hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A); + hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211A); if (hw_mode) { channels = hw_mode->channels; count = hw_mode->num_channels; @@ -8726,17 +8787,17 @@ 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); + struct iwl4965_priv *priv = dev_get_drvdata(d); + u32 size = sizeof(struct iwl4965_notif_statistics); u32 len = 0, ofs = 0; u8 *data = (u8 *) & priv->statistics; int rc = 0; - if (!iwl_is_alive(priv)) + if (!iwl4965_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); - rc = iwl_send_statistics_request(priv); + rc = iwl4965_send_statistics_request(priv); mutex_unlock(&priv->mutex); if (rc) { @@ -8764,9 +8825,9 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL); static ssize_t show_antenna(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl4965_priv *priv = dev_get_drvdata(d); - if (!iwl_is_alive(priv)) + if (!iwl4965_is_alive(priv)) return -EAGAIN; return sprintf(buf, "%d\n", priv->antenna); @@ -8777,7 +8838,7 @@ static ssize_t store_antenna(struct device *d, const char *buf, size_t count) { int ant; - struct iwl_priv *priv = dev_get_drvdata(d); + struct iwl4965_priv *priv = dev_get_drvdata(d); if (count == 0) return 0; @@ -8789,7 +8850,7 @@ static ssize_t store_antenna(struct device *d, if ((ant >= 0) && (ant <= 2)) { IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant); - priv->antenna = (enum iwl_antenna)ant; + priv->antenna = (enum iwl4965_antenna)ant; } else IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant); @@ -8802,8 +8863,8 @@ static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna); 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)) + struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; + if (!iwl4965_is_alive(priv)) return -EAGAIN; return sprintf(buf, "0x%08x\n", (int)priv->status); } @@ -8817,7 +8878,7 @@ static ssize_t dump_error_log(struct device *d, char *p = (char *)buf; if (p[0] == '1') - iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data); + iwl4965_dump_nic_error_log((struct iwl4965_priv *)d->driver_data); return strnlen(buf, count); } @@ -8831,7 +8892,7 @@ static ssize_t dump_event_log(struct device *d, char *p = (char *)buf; if (p[0] == '1') - iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data); + iwl4965_dump_nic_event_log((struct iwl4965_priv *)d->driver_data); return strnlen(buf, count); } @@ -8844,34 +8905,34 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); * *****************************************************************************/ -static void iwl_setup_deferred_work(struct iwl_priv *priv) +static void iwl4965_setup_deferred_work(struct iwl4965_priv *priv) { priv->workqueue = create_workqueue(DRV_NAME); init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl_bg_up); - INIT_WORK(&priv->restart, iwl_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); - INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); - INIT_WORK(&priv->request_scan, iwl_bg_request_scan); - INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); - INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); - INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); - INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate); - INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); - INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); - INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); - - iwl_hw_setup_deferred_work(priv); + 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->scan_completed, iwl4965_bg_scan_completed); + INIT_WORK(&priv->request_scan, iwl4965_bg_request_scan); + INIT_WORK(&priv->abort_scan, iwl4965_bg_abort_scan); + INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); + INIT_DELAYED_WORK(&priv->post_associate, iwl4965_bg_post_associate); + INIT_DELAYED_WORK(&priv->init_alive_start, iwl4965_bg_init_alive_start); + INIT_DELAYED_WORK(&priv->alive_start, iwl4965_bg_alive_start); + INIT_DELAYED_WORK(&priv->scan_check, iwl4965_bg_scan_check); + + iwl4965_hw_setup_deferred_work(priv); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); + iwl4965_irq_tasklet, (unsigned long)priv); } -static void iwl_cancel_deferred_work(struct iwl_priv *priv) +static void iwl4965_cancel_deferred_work(struct iwl4965_priv *priv) { - iwl_hw_cancel_deferred_work(priv); + iwl4965_hw_cancel_deferred_work(priv); cancel_delayed_work_sync(&priv->init_alive_start); cancel_delayed_work(&priv->scan_check); @@ -8880,14 +8941,14 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->beacon_update); } -static struct attribute *iwl_sysfs_entries[] = { +static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_antenna.attr, &dev_attr_channels.attr, &dev_attr_dump_errors.attr, &dev_attr_dump_events.attr, &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT +#ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT &dev_attr_measurement.attr, #endif &dev_attr_power_level.attr, @@ -8903,54 +8964,56 @@ static struct attribute *iwl_sysfs_entries[] = { NULL }; -static struct attribute_group iwl_attribute_group = { +static struct attribute_group iwl4965_attribute_group = { .name = NULL, /* put in device directory */ - .attrs = iwl_sysfs_entries, + .attrs = iwl4965_sysfs_entries, }; -static struct ieee80211_ops iwl_hw_ops = { - .tx = iwl_mac_tx, - .start = iwl_mac_start, - .stop = iwl_mac_stop, - .add_interface = iwl_mac_add_interface, - .remove_interface = iwl_mac_remove_interface, - .config = iwl_mac_config, - .config_interface = iwl_mac_config_interface, - .configure_filter = iwl_configure_filter, - .set_key = iwl_mac_set_key, - .get_stats = iwl_mac_get_stats, - .get_tx_stats = iwl_mac_get_tx_stats, - .conf_tx = iwl_mac_conf_tx, - .get_tsf = iwl_mac_get_tsf, - .reset_tsf = iwl_mac_reset_tsf, - .beacon_update = iwl_mac_beacon_update, -#ifdef CONFIG_IWLWIFI_HT - .conf_ht = iwl_mac_conf_ht, - .get_ht_capab = iwl_mac_get_ht_capab, -#ifdef CONFIG_IWLWIFI_HT_AGG - .ht_tx_agg_start = iwl_mac_ht_tx_agg_start, - .ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop, - .ht_rx_agg_start = iwl_mac_ht_rx_agg_start, - .ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop, -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ - .hw_scan = iwl_mac_hw_scan +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, + .get_stats = iwl4965_mac_get_stats, + .get_tx_stats = iwl4965_mac_get_tx_stats, + .conf_tx = iwl4965_mac_conf_tx, + .get_tsf = iwl4965_mac_get_tsf, + .reset_tsf = iwl4965_mac_reset_tsf, + .beacon_update = iwl4965_mac_beacon_update, + .bss_info_changed = iwl4965_bss_info_changed, +#ifdef CONFIG_IWL4965_HT + .conf_ht = iwl4965_mac_conf_ht, + .ampdu_action = iwl4965_mac_ampdu_action, +#ifdef CONFIG_IWL4965_HT_AGG + .ht_tx_agg_start = iwl4965_mac_ht_tx_agg_start, + .ht_tx_agg_stop = iwl4965_mac_ht_tx_agg_stop, +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ + .hw_scan = iwl4965_mac_hw_scan }; -static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; - struct iwl_priv *priv; + struct iwl4965_priv *priv; struct ieee80211_hw *hw; int i; + DECLARE_MAC_BUF(mac); - if (iwl_param_disable_hw_scan) { + /* Disabling hardware scan means that mac80211 will perform scans + * "the hard way", rather than using device's scan. */ + if (iwl4965_param_disable_hw_scan) { IWL_DEBUG_INFO("Disabling hw_scan\n"); - iwl_hw_ops.hw_scan = NULL; + iwl4965_hw_ops.hw_scan = NULL; } - if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) || - (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) { + if ((iwl4965_param_queues_num > IWL_MAX_NUM_QUEUES) || + (iwl4965_param_queues_num < IWL_MIN_NUM_QUEUES)) { IWL_ERROR("invalid queues_num, should be between %d and %d\n", IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES); err = -EINVAL; @@ -8959,7 +9022,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* mac80211 allocates memory for this device instance, including * space for this driver's private structure */ - hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops); + hw = ieee80211_alloc_hw(sizeof(struct iwl4965_priv), &iwl4965_hw_ops); if (hw == NULL) { IWL_ERROR("Can not allocate network device\n"); err = -ENOMEM; @@ -8974,9 +9037,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->hw = hw; priv->pci_dev = pdev; - priv->antenna = (enum iwl_antenna)iwl_param_antenna; -#ifdef CONFIG_IWLWIFI_DEBUG - iwl_debug_level = iwl_param_debug; + priv->antenna = (enum iwl4965_antenna)iwl4965_param_antenna; +#ifdef CONFIG_IWL4965_DEBUG + iwl4965_debug_level = iwl4965_param_debug; atomic_set(&priv->restrict_refcnt, 0); #endif priv->retry_rate = 1; @@ -8995,12 +9058,14 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Tell mac80211 our Tx characteristics */ hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE; + /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG +#ifdef CONFIG_IWL4965_HT +#ifdef CONFIG_IWL4965_HT_AGG + /* Enhanced value; more queues, to support 11n aggregation */ hw->queues = 16; -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ +#endif /* CONFIG_IWL4965_HT_AGG */ +#endif /* CONFIG_IWL4965_HT */ spin_lock_init(&priv->lock); spin_lock_init(&priv->power_data.lock); @@ -9021,7 +9086,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); - iwl_clear_stations_table(priv); + /* Clear the driver's (not device's) station table */ + iwl4965_clear_stations_table(priv); priv->data_retry_limit = -1; priv->ieee_channels = NULL; @@ -9040,9 +9106,11 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = pci_request_regions(pdev, DRV_NAME); if (err) goto out_pci_disable_device; + /* 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); + priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -9055,7 +9123,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Initialize module parameter values here */ - if (iwl_param_disable) { + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (iwl4965_param_disable) { set_bit(STATUS_RF_KILL_SW, &priv->status); IWL_DEBUG_INFO("Radio disabled.\n"); } @@ -9064,91 +9133,92 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) priv->ps_mode = 0; priv->use_ant_b_for_management_frame = 1; /* start with ant B */ - priv->is_ht_enabled = 1; - priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ; priv->valid_antenna = 0x7; /* assume all 3 connected */ priv->ps_mode = IWL_MIMO_PS_NONE; - priv->cck_power_index_compensation = iwl_read32( - priv, CSR_HW_REV_WA_REG); + /* Choose which receivers/antennas to use */ iwl4965_set_rxon_chain(priv); printk(KERN_INFO DRV_NAME ": Detected Intel Wireless WiFi Link 4965AGN\n"); /* Device-specific setup */ - if (iwl_hw_set_hw_setting(priv)) { + if (iwl4965_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); - mutex_unlock(&priv->mutex); goto out_iounmap; } -#ifdef CONFIG_IWLWIFI_QOS - if (iwl_param_qos_enable) +#ifdef CONFIG_IWL4965_QOS + if (iwl4965_param_qos_enable) priv->qos_data.qos_enable = 1; - iwl_reset_qos(priv); + iwl4965_reset_qos(priv); priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; -#endif /* CONFIG_IWLWIFI_QOS */ +#endif /* CONFIG_IWL4965_QOS */ - iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6); - iwl_setup_deferred_work(priv); - iwl_setup_rx_handlers(priv); + iwl4965_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl4965_setup_deferred_work(priv); + iwl4965_setup_rx_handlers(priv); priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; - pci_enable_msi(pdev); - - err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); - if (err) { - IWL_ERROR("Error allocating IRQ %d\n", pdev->irq); - goto out_disable_msi; - } - - mutex_lock(&priv->mutex); + iwl4965_disable_interrupts(priv); - err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); + err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); - mutex_unlock(&priv->mutex); goto out_release_irq; } - /* fetch ucode file from disk, alloc and copy to bus-master buffers ... - * ucode filename and max sizes are card-specific. */ - err = iwl_read_ucode(priv); + /* nic init */ + iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + + iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl4965_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 = iwl4965_eeprom_init(priv); if (err) { - IWL_ERROR("Could not read microcode: %d\n", err); - mutex_unlock(&priv->mutex); - goto out_pci_alloc; + IWL_ERROR("Unable to init EEPROM\n"); + goto out_remove_sysfs; } + /* MAC Address location in EEPROM same for 3945/4965 */ + get_eeprom_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); - mutex_unlock(&priv->mutex); - - IWL_DEBUG_INFO("Queing UP work.\n"); + iwl4965_rate_control_register(priv->hw); + err = ieee80211_register_hw(priv->hw); + if (err) { + IWL_ERROR("Failed to register network device (error %d)\n", err); + goto out_remove_sysfs; + } - queue_work(priv->workqueue, &priv->up); + priv->hw->conf.beacon_int = 100; + priv->mac80211_registered = 1; + pci_save_state(pdev); + pci_disable_device(pdev); return 0; - out_pci_alloc: - iwl_dealloc_ucode_pci(priv); - - sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); out_release_irq: - free_irq(pdev->irq, priv); - - out_disable_msi: - pci_disable_msi(pdev); destroy_workqueue(priv->workqueue); priv->workqueue = NULL; - iwl_unset_hw_setting(priv); + iwl4965_unset_hw_setting(priv); out_iounmap: pci_iounmap(pdev, priv->hw_base); @@ -9163,9 +9233,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } -static void iwl_pci_remove(struct pci_dev *pdev) +static void iwl4965_pci_remove(struct pci_dev *pdev) { - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl4965_priv *priv = pci_get_drvdata(pdev); struct list_head *p, *q; int i; @@ -9176,43 +9246,41 @@ static void iwl_pci_remove(struct pci_dev *pdev) set_bit(STATUS_EXIT_PENDING, &priv->status); - iwl_down(priv); + iwl4965_down(priv); /* Free MAC hash list for ADHOC */ for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) { list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { list_del(p); - kfree(list_entry(p, struct iwl_ibss_seq, list)); + kfree(list_entry(p, struct iwl4965_ibss_seq, list)); } } - sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); - iwl_dealloc_ucode_pci(priv); + iwl4965_dealloc_ucode_pci(priv); if (priv->rxq.bd) - iwl_rx_queue_free(priv, &priv->rxq); - iwl_hw_txq_ctx_free(priv); + iwl4965_rx_queue_free(priv, &priv->rxq); + iwl4965_hw_txq_ctx_free(priv); - iwl_unset_hw_setting(priv); - iwl_clear_stations_table(priv); + iwl4965_unset_hw_setting(priv); + iwl4965_clear_stations_table(priv); if (priv->mac80211_registered) { ieee80211_unregister_hw(priv->hw); - iwl_rate_control_unregister(priv->hw); + iwl4965_rate_control_unregister(priv->hw); } /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); - /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes + /* 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; - free_irq(pdev->irq, priv); - pci_disable_msi(pdev); pci_iounmap(pdev, priv->hw_base); pci_release_regions(pdev); pci_disable_device(pdev); @@ -9231,93 +9299,31 @@ static void iwl_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM -static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) { - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl4965_priv *priv = pci_get_drvdata(pdev); - set_bit(STATUS_IN_SUSPEND, &priv->status); - - /* Take down the device; powers it off, etc. */ - iwl_down(priv); - - if (priv->mac80211_registered) - ieee80211_stop_queues(priv->hw); + if (priv->is_open) { + set_bit(STATUS_IN_SUSPEND, &priv->status); + iwl4965_mac_stop(priv->hw); + priv->is_open = 1; + } - pci_save_state(pdev); - pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); return 0; } -static void iwl_resume(struct iwl_priv *priv) +static int iwl4965_pci_resume(struct pci_dev *pdev) { - unsigned long flags; - - /* The following it a temporary work around due to the - * suspend / resume not fully initializing the NIC correctly. - * Without all of the following, resume will not attempt to take - * down the NIC (it shouldn't really need to) and will just try - * and bring the NIC back up. However that fails during the - * ucode verification process. This then causes iwl_down to be - * called *after* iwl_hw_nic_init() has succeeded -- which - * then lets the next init sequence succeed. So, we've - * replicated all of that NIC init code here... */ - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - iwl_hw_nic_init(priv); - - 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); - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - 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); - - /* tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - spin_lock_irqsave(&priv->lock, flags); - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - if (!iwl_grab_restricted_access(priv)) { - iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - iwl_release_restricted_access(priv); - } - spin_unlock_irqrestore(&priv->lock, flags); - - udelay(5); - - iwl_hw_nic_reset(priv); - - /* Bring the device back up */ - clear_bit(STATUS_IN_SUSPEND, &priv->status); - queue_work(priv->workqueue, &priv->up); -} - -static int iwl_pci_resume(struct pci_dev *pdev) -{ - struct iwl_priv *priv = pci_get_drvdata(pdev); - int err; - - printk(KERN_INFO "Coming out of suspend...\n"); + struct iwl4965_priv *priv = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - pci_restore_state(pdev); - - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries - * from interfering with C3 CPU state. pci_restore_state won't help - * here since it only restores the first 64 bytes pci config header. - */ - pci_write_config_byte(pdev, 0x41, 0x00); - iwl_resume(priv); + if (priv->is_open) + iwl4965_mac_start(priv->hw); + clear_bit(STATUS_IN_SUSPEND, &priv->status); return 0; } @@ -9329,33 +9335,33 @@ static int iwl_pci_resume(struct pci_dev *pdev) * *****************************************************************************/ -static struct pci_driver iwl_driver = { +static struct pci_driver iwl4965_driver = { .name = DRV_NAME, - .id_table = iwl_hw_card_ids, - .probe = iwl_pci_probe, - .remove = __devexit_p(iwl_pci_remove), + .id_table = iwl4965_hw_card_ids, + .probe = iwl4965_pci_probe, + .remove = __devexit_p(iwl4965_pci_remove), #ifdef CONFIG_PM - .suspend = iwl_pci_suspend, - .resume = iwl_pci_resume, + .suspend = iwl4965_pci_suspend, + .resume = iwl4965_pci_resume, #endif }; -static int __init iwl_init(void) +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 = pci_register_driver(&iwl_driver); + ret = pci_register_driver(&iwl4965_driver); if (ret) { IWL_ERROR("Unable to initialize PCI module\n"); return ret; } -#ifdef CONFIG_IWLWIFI_DEBUG - ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level); +#ifdef CONFIG_IWL4965_DEBUG + ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level); if (ret) { IWL_ERROR("Unable to create driver sysfs file\n"); - pci_unregister_driver(&iwl_driver); + pci_unregister_driver(&iwl4965_driver); return ret; } #endif @@ -9363,32 +9369,34 @@ static int __init iwl_init(void) return ret; } -static void __exit iwl_exit(void) +static void __exit iwl4965_exit(void) { -#ifdef CONFIG_IWLWIFI_DEBUG - driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level); +#ifdef CONFIG_IWL4965_DEBUG + driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level); #endif - pci_unregister_driver(&iwl_driver); + pci_unregister_driver(&iwl4965_driver); } -module_param_named(antenna, iwl_param_antenna, int, 0444); +module_param_named(antenna, iwl4965_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(disable, iwl_param_disable, int, 0444); +module_param_named(disable, iwl4965_param_disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); -module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444); +module_param_named(hwcrypto, iwl4965_param_hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "using hardware crypto engine (default 0 [software])\n"); -module_param_named(debug, iwl_param_debug, int, 0444); +module_param_named(debug, iwl4965_param_debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); -module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444); +module_param_named(disable_hw_scan, iwl4965_param_disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); -module_param_named(queues_num, iwl_param_queues_num, int, 0444); +module_param_named(queues_num, iwl4965_param_queues_num, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); /* QoS */ -module_param_named(qos_enable, iwl_param_qos_enable, int, 0444); +module_param_named(qos_enable, iwl4965_param_qos_enable, int, 0444); MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); +module_param_named(amsdu_size_8K, iwl4965_param_amsdu_size_8K, int, 0444); +MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); -module_exit(iwl_exit); -module_init(iwl_init); +module_exit(iwl4965_exit); +module_init(iwl4965_init); diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h deleted file mode 100644 index 432ce887807f..000000000000 --- a/drivers/net/wireless/iwlwifi/iwlwifi.h +++ /dev/null @@ -1,708 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2007 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 <ipw2100-admin@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwlwifi_h__ -#define __iwlwifi_h__ - -#include <linux/pci.h> /* for struct pci_device_id */ -#include <linux/kernel.h> -#include <net/ieee80211_radiotap.h> - -struct iwl_priv; - -/* Hardware specific file defines the PCI IDs table for that hardware module */ -extern struct pci_device_id iwl_hw_card_ids[]; - -#include "iwl-hw.h" -#if IWL == 3945 -#define DRV_NAME "iwl3945" -#include "iwl-3945-hw.h" -#elif IWL == 4965 -#define DRV_NAME "iwl4965" -#include "iwl-4965-hw.h" -#endif - -#include "iwl-prph.h" - -/* - * Driver implementation data structures, constants, inline - * functions - * - * NOTE: DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE - * - * Hardware specific declrations go into iwl-*hw.h - * - */ - -#include "iwl-debug.h" - -/* Default noise level to report when noise measurement is not available. - * This may be because we're: - * 1) Not associated (4965, no beacon statistics being sent to driver) - * 2) Scanning (noise measurement does not apply to associated channel) - * 3) Receiving CCK (3945 delivers noise info only for OFDM frames) - * Use default noise value of -127 ... this is below the range of measurable - * Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user. - * Also, -127 works better than 0 when averaging frames with/without - * noise info (e.g. averaging might be done in app); measured dBm values are - * always negative ... using a negative value as the default keeps all - * averages within an s8's (used in some apps) range of negative values. */ -#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127) - -/* Module parameters accessible from iwl-*.c */ -extern int iwl_param_disable_hw_scan; -extern int iwl_param_debug; -extern int iwl_param_mode; -extern int iwl_param_disable; -extern int iwl_param_antenna; -extern int iwl_param_hwcrypto; -extern int iwl_param_qos_enable; -extern int iwl_param_queues_num; - -enum iwl_antenna { - IWL_ANTENNA_DIVERSITY, - IWL_ANTENNA_MAIN, - IWL_ANTENNA_AUX -}; - -/* - * RTS threshold here is total size [2347] minus 4 FCS bytes - * Per spec: - * a value of 0 means RTS on all data/management packets - * a value > max MSDU size means no RTS - * else RTS for data/management frames where MPDU is larger - * than RTS value. - */ -#define DEFAULT_RTS_THRESHOLD 2347U -#define MIN_RTS_THRESHOLD 0U -#define MAX_RTS_THRESHOLD 2347U -#define MAX_MSDU_SIZE 2304U -#define MAX_MPDU_SIZE 2346U -#define DEFAULT_BEACON_INTERVAL 100U -#define DEFAULT_SHORT_RETRY_LIMIT 7U -#define DEFAULT_LONG_RETRY_LIMIT 4U - -struct iwl_rx_mem_buffer { - dma_addr_t dma_addr; - struct sk_buff *skb; - struct list_head list; -}; - -struct iwl_rt_rx_hdr { - struct ieee80211_radiotap_header rt_hdr; - __le64 rt_tsf; /* TSF */ - u8 rt_flags; /* radiotap packet flags */ - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channelMHz; /* channel in MHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - s8 rt_dbmnoise; - u8 rt_antenna; /* antenna number */ - u8 payload[0]; /* payload... */ -} __attribute__ ((packed)); - -struct iwl_rt_tx_hdr { - struct ieee80211_radiotap_header rt_hdr; - u8 rt_rate; /* rate in 500kb/s */ - __le16 rt_channel; /* channel in mHz */ - __le16 rt_chbitmask; /* channel bitfield */ - s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ - u8 rt_antenna; /* antenna number */ - u8 payload[0]; /* payload... */ -} __attribute__ ((packed)); - -/* - * Generic queue structure - * - * Contains common data for Rx and Tx queues - */ -struct iwl_queue { - int n_bd; /* number of BDs in this queue */ - int first_empty; /* 1-st empty entry (index) host_w*/ - int last_used; /* last used entry (index) host_r*/ - dma_addr_t dma_addr; /* physical addr for BD's */ - int n_window; /* safe queue window */ - u32 id; - int low_mark; /* low watermark, resume queue if free - * space more than this */ - int high_mark; /* high watermark, stop queue if free - * space less than this */ -} __attribute__ ((packed)); - -#define MAX_NUM_OF_TBS (20) - -struct iwl_tx_info { - struct ieee80211_tx_status status; - struct sk_buff *skb[MAX_NUM_OF_TBS]; -}; - -/** - * struct iwl_tx_queue - Tx Queue for DMA - * @need_update: need to update read/write index - * @shed_retry: queue is HT AGG enabled - * - * Queue consists of circular buffer of BD's and required locking structures. - */ -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_tx_info *txb; - int need_update; - int sched_retry; - int active; -}; - -#include "iwl-channel.h" - -#if IWL == 3945 -#include "iwl-3945-rs.h" -#else -#include "iwl-4965-rs.h" -#endif - -#define IWL_TX_FIFO_AC0 0 -#define IWL_TX_FIFO_AC1 1 -#define IWL_TX_FIFO_AC2 2 -#define IWL_TX_FIFO_AC3 3 -#define IWL_TX_FIFO_HCCA_1 5 -#define IWL_TX_FIFO_HCCA_2 6 -#define IWL_TX_FIFO_NONE 7 - -/* Minimum number of queues. MAX_NUM is defined in hw specific files */ -#define IWL_MIN_NUM_QUEUES 4 - -/* Power management (not Tx power) structures */ - -struct iwl_power_vec_entry { - struct iwl_powertable_cmd cmd; - u8 no_dtim; -}; -#define IWL_POWER_RANGE_0 (0) -#define IWL_POWER_RANGE_1 (1) - -#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_LIMIT 0x07 -#define IWL_POWER_MASK 0x0F -#define IWL_POWER_ENABLED 0x10 -#define IWL_POWER_LEVEL(x) ((x) & IWL_POWER_MASK) - -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]; - u8 active_index; - u32 dtim_val; -}; - -#define IEEE80211_DATA_LEN 2304 -#define IEEE80211_4ADDR_LEN 30 -#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -struct iwl_frame { - union { - struct ieee80211_hdr frame; - struct iwl_tx_beacon_cmd beacon; - u8 raw[IEEE80211_FRAME_LEN]; - u8 cmd[360]; - } u; - struct list_head list; -}; - -#define SEQ_TO_QUEUE(x) ((x >> 8) & 0xbf) -#define QUEUE_TO_SEQ(x) ((x & 0xbf) << 8) -#define SEQ_TO_INDEX(x) (x & 0xff) -#define INDEX_TO_SEQ(x) (x & 0xff) -#define SEQ_HUGE_FRAME (0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) -#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) -#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) -#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) - -enum { - /* CMD_SIZE_NORMAL = 0, */ - CMD_SIZE_HUGE = (1 << 0), - /* CMD_SYNC = 0, */ - CMD_ASYNC = (1 << 1), - /* CMD_NO_SKB = 0, */ - CMD_WANT_SKB = (1 << 2), -}; - -struct iwl_cmd; -struct iwl_priv; - -struct iwl_cmd_meta { - struct iwl_cmd_meta *source; - union { - struct sk_buff *skb; - int (*callback)(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb); - } __attribute__ ((packed)) u; - - /* The CMD_SIZE_HUGE flag bit indicates that the command - * structure is stored at the end of the shared queue memory. */ - u32 flags; - -} __attribute__ ((packed)); - -struct iwl_cmd { - struct iwl_cmd_meta meta; - struct iwl_cmd_header hdr; - union { - struct iwl_addsta_cmd addsta; - struct iwl_led_cmd led; - u32 flags; - u8 val8; - u16 val16; - u32 val32; - struct iwl_bt_cmd bt; - struct iwl_rxon_time_cmd rxon_time; - struct iwl_powertable_cmd powertable; - struct iwl_qosparam_cmd qosparam; - struct iwl_tx_cmd tx; - struct iwl_tx_beacon_cmd tx_beacon; - struct iwl_rxon_assoc_cmd rxon_assoc; - u8 *indirect; - u8 payload[360]; - } __attribute__ ((packed)) cmd; -} __attribute__ ((packed)); - -struct iwl_host_cmd { - u8 id; - u16 len; - struct iwl_cmd_meta meta; - const void *data; -}; - -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \ - sizeof(struct iwl_cmd_meta)) - -/* - * RX related structures and functions - */ -#define RX_FREE_BUFFERS 64 -#define RX_LOW_WATERMARK 8 - -#define SUP_RATE_11A_MAX_NUM_CHANNELS 8 -#define SUP_RATE_11B_MAX_NUM_CHANNELS 4 -#define SUP_RATE_11G_MAX_NUM_CHANNELS 12 - -/** - * struct iwl_rx_queue - Rx queue - * @processed: Internal index to last handled Rx packet - * @read: Shared index to newest available Rx buffer - * @write: Shared index to oldest written Rx packet - * @free_count: Number of pre-allocated buffers in rx_free - * @rx_free: list of free SKBs for use - * @rx_used: List of Rx buffers with no SKB - * @need_update: flag to indicate we need to update read/write index - * - * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers - */ -struct iwl_rx_queue { - __le32 *bd; - dma_addr_t dma_addr; - struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 processed; - u32 read; - u32 write; - u32 free_count; - struct list_head rx_free; - struct list_head rx_used; - int need_update; - spinlock_t lock; -}; - -#define IWL_SUPPORTED_RATES_IE_LEN 8 - -#define SCAN_INTERVAL 100 - -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - -#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ -#define STATUS_INT_ENABLED 1 -#define STATUS_RF_KILL_HW 2 -#define STATUS_RF_KILL_SW 3 -#define STATUS_INIT 4 -#define STATUS_ALIVE 5 -#define STATUS_READY 6 -#define STATUS_TEMPERATURE 7 -#define STATUS_GEO_CONFIGURED 8 -#define STATUS_EXIT_PENDING 9 -#define STATUS_IN_SUSPEND 10 -#define STATUS_STATISTICS 11 -#define STATUS_SCANNING 12 -#define STATUS_SCAN_ABORTING 13 -#define STATUS_SCAN_HW 14 -#define STATUS_POWER_PMI 15 -#define STATUS_FW_ERROR 16 - -#define MAX_TID_COUNT 9 - -#define IWL_INVALID_RATE 0xFF -#define IWL_INVALID_VALUE -1 - -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG -struct iwl_ht_agg { - u16 txq_id; - u16 frame_count; - u16 wait_for_ba; - u16 start_idx; - u32 bitmap0; - u32 bitmap1; - u32 rate_n_flags; -}; -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ -#endif - -struct iwl_tid_data { - u16 seq_number; -#if IWL == 4965 -#ifdef CONFIG_IWLWIFI_HT -#ifdef CONFIG_IWLWIFI_HT_AGG - struct iwl_ht_agg agg; -#endif /* CONFIG_IWLWIFI_HT_AGG */ -#endif /* CONFIG_IWLWIFI_HT */ -#endif -}; - -struct iwl_hw_key { - enum ieee80211_key_alg alg; - int keylen; - u8 key[32]; -}; - -union iwl_ht_rate_supp { - u16 rates; - struct { - u8 siso_rate; - u8 mimo_rate; - }; -}; - -#ifdef CONFIG_IWLWIFI_HT -#define CFG_HT_RX_AMPDU_FACTOR_DEF (0x3) -#define HT_IE_MAX_AMSDU_SIZE_4K (0) -#define CFG_HT_MPDU_DENSITY_2USEC (0x5) -#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC - -struct sta_ht_info { - u8 is_ht; - u16 rx_mimo_ps_mode; - u16 tx_mimo_ps_mode; - u16 control_channel; - u8 max_amsdu_size; - u8 ampdu_factor; - u8 mpdu_density; - u8 operating_mode; - u8 supported_chan_width; - u8 extension_chan_offset; - u8 is_green_field; - u8 sgf; - u8 supp_rates[16]; - u8 tx_chan_width; - u8 chan_width_cap; -}; -#endif /*CONFIG_IWLWIFI_HT */ - -#ifdef CONFIG_IWLWIFI_QOS - -union iwl_qos_capabity { - struct { - u8 edca_count:4; /* bit 0-3 */ - u8 q_ack:1; /* bit 4 */ - u8 queue_request:1; /* bit 5 */ - u8 txop_request:1; /* bit 6 */ - u8 reserved:1; /* bit 7 */ - } q_AP; - struct { - u8 acvo_APSD:1; /* bit 0 */ - u8 acvi_APSD:1; /* bit 1 */ - u8 ac_bk_APSD:1; /* bit 2 */ - u8 ac_be_APSD:1; /* bit 3 */ - u8 q_ack:1; /* bit 4 */ - u8 max_len:2; /* bit 5-6 */ - u8 more_data_ack:1; /* bit 7 */ - } q_STA; - u8 val; -}; - -/* QoS sturctures */ -struct iwl_qos_info { - int qos_enable; - int qos_active; - union iwl_qos_capabity qos_cap; - struct iwl_qosparam_cmd def_qos_parm; -}; -#endif /*CONFIG_IWLWIFI_QOS */ - -#define STA_PS_STATUS_WAKE 0 -#define STA_PS_STATUS_SLEEP 1 - -struct iwl_station_entry { - struct iwl_addsta_cmd sta; - struct iwl_tid_data tid[MAX_TID_COUNT]; -#if IWL == 3945 - union { - struct { - u8 rate; - u8 flags; - } s; - u16 rate_n_flags; - } current_rate; -#endif - u8 used; - u8 ps_status; - struct iwl_hw_key keyinfo; -}; - -/* one for each uCode image (inst/data, boot/init/runtime) */ -struct fw_image_desc { - void *v_addr; /* access by driver */ - dma_addr_t p_addr; /* access by card's busmaster DMA */ - u32 len; /* bytes */ -}; - -/* uCode file layout */ -struct iwl_ucode { - __le32 ver; /* major/minor/subminor */ - __le32 inst_size; /* bytes of runtime instructions */ - __le32 data_size; /* bytes of runtime data */ - __le32 init_size; /* bytes of initialization instructions */ - __le32 init_data_size; /* bytes of initialization data */ - __le32 boot_size; /* bytes of bootstrap instructions */ - u8 data[0]; /* data in same order as "size" elements */ -}; - -#define IWL_IBSS_MAC_HASH_SIZE 32 - -struct iwl_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num; - u16 frag_num; - unsigned long packet_time; - struct list_head list; -}; - -struct iwl_driver_hw_info { - u16 max_txq_num; - u16 ac_queue_count; - u32 rx_buffer_size; - u16 tx_cmd_len; - u16 max_rxq_size; - u16 max_rxq_log; - u32 cck_flag; - u8 max_stations; - u8 bcast_sta_id; - void *shared_virt; - dma_addr_t shared_phys; -}; - - -#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) -#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) -#define STA_FLG_MAX_AGG_SIZE_POS (19) -#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) -#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) -#define STA_FLG_AGG_MPDU_DENSITY_POS (23) -#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) -#define HT_SHORT_GI_20MHZ_ONLY (1 << 0) -#define HT_SHORT_GI_40MHZ_ONLY (1 << 1) - - -#include "iwl-priv.h" - -/* Requires full declaration of iwl_priv before including */ -#include "iwl-io.h" - -#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\ - x->u.rx_frame.stats.payload + \ - x->u.rx_frame.stats.phy_count)) -#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\ - IWL_RX_HDR(x)->payload + \ - le16_to_cpu(IWL_RX_HDR(x)->len))) -#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) -#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) - - -/****************************************************************************** - * - * Functions implemented in iwl-base.c which are forward declared here - * for use by iwl-*.c - * - *****************************************************************************/ -struct iwl_addsta_cmd; -extern int iwl_send_add_station(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -extern const char *iwl_get_tx_fail_reason(u32 status); -extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid, - int is_ap, u8 flags); -extern int iwl_is_network_packet(struct iwl_priv *priv, - struct ieee80211_hdr *header); -extern int iwl_power_init_handle(struct iwl_priv *priv); -extern int iwl_eeprom_init(struct iwl_priv *priv); -#ifdef CONFIG_IWLWIFI_DEBUG -extern void iwl_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, int group100); -#else -static inline void iwl_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) {} -#endif -extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl_tx_queue *txq); -extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb, - void *data, short len, - struct ieee80211_rx_status *stats, - u16 phy_flags); -extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr - *header); -extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -extern int iwl_rx_queue_alloc(struct iwl_priv *priv); -extern void iwl_rx_queue_reset(struct iwl_priv *priv, - struct iwl_rx_queue *rxq); -extern int iwl_calc_db_from_ratio(int sig_ratio); -extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm); -extern int iwl_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq, int count, u32 id); -extern int iwl_rx_queue_restock(struct iwl_priv *priv); -extern void iwl_rx_replenish(void *data); -extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq); -extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, - const void *data); -extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv, - struct iwl_host_cmd *cmd); -extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv, - struct iwl_host_cmd *cmd); -extern int __must_check iwl_send_cmd(struct iwl_priv *priv, - struct iwl_host_cmd *cmd); -extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); -extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl_rx_queue *q); -extern int iwl_send_statistics_request(struct iwl_priv *priv); -extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb, - u32 decrypt_res, - struct ieee80211_rx_status *stats); -extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr); - -extern const u8 BROADCAST_ADDR[ETH_ALEN]; - -/* - * Currently used by iwl-3945-rs... look at restructuring so that it doesn't - * call this... todo... fix that. -*/ -extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id, - u16 tx_rate, u8 flags); - -static inline int iwl_is_associated(struct iwl_priv *priv) -{ - return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0; -} - -/****************************************************************************** - * - * Functions implemented in iwl-[34]*.c which are forward declared here - * for use by iwl-base.c - * - * NOTE: The implementation of these functions are hardware specific - * which is why they are in the hardware specific files (vs. iwl-base.c) - * - * Naming convention -- - * iwl_ <-- Its part of iwlwifi (should be changed to iwl_) - * iwl_hw_ <-- Hardware specific (implemented in iwl-XXXX.c by all HW) - * iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX) - * iwl_bg_ <-- Called from work queue context - * iwl_mac_ <-- mac80211 callback - * - ****************************************************************************/ -extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv); -extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv); -extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv); -extern int iwl_hw_rxq_stop(struct iwl_priv *priv); -extern int iwl_hw_set_hw_setting(struct iwl_priv *priv); -extern int iwl_hw_nic_init(struct iwl_priv *priv); -extern void iwl_hw_card_show_info(struct iwl_priv *priv); -extern int iwl_hw_nic_stop_master(struct iwl_priv *priv); -extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv); -extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv); -extern int iwl_hw_nic_reset(struct iwl_priv *priv); -extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd, - dma_addr_t addr, u16 len); -extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); -extern int iwl_hw_get_temperature(struct iwl_priv *priv); -extern int iwl_hw_tx_queue_init(struct iwl_priv *priv, - struct iwl_tx_queue *txq); -extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, - struct iwl_frame *frame, u8 rate); -extern int iwl_hw_get_rx_read(struct iwl_priv *priv); -extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv, - struct iwl_cmd *cmd, - struct ieee80211_tx_control *ctrl, - struct ieee80211_hdr *hdr, - int sta_id, int tx_id); -extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv); -extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power); -extern void iwl_hw_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -extern void iwl_disable_events(struct iwl_priv *priv); -extern int iwl4965_get_temperature(const struct iwl_priv *priv); - -/** - * iwl_hw_find_station - Find station id for a given BSSID - * @bssid: MAC address of station ID to find - * - * NOTE: This should not be hardware specific but the code has - * not yet been merged into a single common layer for managing the - * station tables. - */ -extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid); - -extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel); -extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); -#endif diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c index 9cf0211de67f..5e10ce0d351c 100644 --- a/drivers/net/wireless/libertas/11d.c +++ b/drivers/net/wireless/libertas/11d.c @@ -43,16 +43,14 @@ static struct chan_freq_power channel_freq_power_UN_BG[] = { {14, 2484, TX_PWR_DEFAULT} }; -static u8 wlan_region_2_code(u8 * region) +static u8 lbs_region_2_code(u8 *region) { u8 i; - u8 size = sizeof(region_code_mapping)/ - sizeof(struct region_code_mapping); for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) region[i] = toupper(region[i]); - for (i = 0; i < size; i++) { + for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { if (!memcmp(region, region_code_mapping[i].region, COUNTRY_CODE_LEN)) return (region_code_mapping[i].code); @@ -62,12 +60,11 @@ static u8 wlan_region_2_code(u8 * region) return (region_code_mapping[0].code); } -static u8 *wlan_code_2_region(u8 code) +static u8 *lbs_code_2_region(u8 code) { u8 i; - u8 size = sizeof(region_code_mapping) - / sizeof(struct region_code_mapping); - for (i = 0; i < size; i++) { + + for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { if (region_code_mapping[i].code == code) return (region_code_mapping[i].region); } @@ -82,7 +79,7 @@ static u8 *wlan_code_2_region(u8 code) * @param nrchan number of channels * @return the nrchan-th chan number */ -static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) +static u8 lbs_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 *chan) /*find the nrchan-th chan after the firstchan*/ { u8 i; @@ -90,8 +87,7 @@ static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) u8 cfp_no; cfp = channel_freq_power_UN_BG; - cfp_no = sizeof(channel_freq_power_UN_BG) / - sizeof(struct chan_freq_power); + cfp_no = ARRAY_SIZE(channel_freq_power_UN_BG); for (i = 0; i < cfp_no; i++) { if ((cfp + i)->channel == firstchan) { @@ -117,7 +113,7 @@ static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) * @param parsed_region_chan pointer to parsed_region_chan_11d * @return TRUE; FALSE */ -static u8 wlan_channel_known_11d(u8 chan, +static u8 lbs_channel_known_11d(u8 chan, struct parsed_region_chan_11d * parsed_region_chan) { struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; @@ -138,19 +134,15 @@ static u8 wlan_channel_known_11d(u8 chan, return 0; } -u32 libertas_chan_2_freq(u8 chan, u8 band) +u32 lbs_chan_2_freq(u8 chan, u8 band) { struct chan_freq_power *cf; - u16 cnt; u16 i; u32 freq = 0; cf = channel_freq_power_UN_BG; - cnt = - sizeof(channel_freq_power_UN_BG) / - sizeof(struct chan_freq_power); - for (i = 0; i < cnt; i++) { + for (i = 0; i < ARRAY_SIZE(channel_freq_power_UN_BG); i++) { if (chan == cf[i].channel) freq = cf[i].freq; } @@ -160,7 +152,7 @@ u32 libertas_chan_2_freq(u8 chan, u8 band) static int generate_domain_info_11d(struct parsed_region_chan_11d *parsed_region_chan, - struct wlan_802_11d_domain_reg * domaininfo) + struct lbs_802_11d_domain_reg *domaininfo) { u8 nr_subband = 0; @@ -225,7 +217,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d * @param *parsed_region_chan pointer to parsed_region_chan_11d * @return N/A */ -static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan, +static void lbs_generate_parsed_region_chan_11d(struct region_channel *region_chan, struct parsed_region_chan_11d * parsed_region_chan) { @@ -246,7 +238,7 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_ parsed_region_chan->band = region_chan->band; parsed_region_chan->region = region_chan->region; memcpy(parsed_region_chan->countrycode, - wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); + lbs_code_2_region(region_chan->region), COUNTRY_CODE_LEN); lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region, parsed_region_chan->band); @@ -272,7 +264,7 @@ static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_ * @param chan chan * @return TRUE;FALSE */ -static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) +static u8 lbs_region_chan_supported_11d(u8 region, u8 band, u8 chan) { struct chan_freq_power *cfp; int cfp_no; @@ -281,7 +273,7 @@ static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) lbs_deb_enter(LBS_DEB_11D); - cfp = libertas_get_region_cfp_table(region, band, &cfp_no); + cfp = lbs_get_region_cfp_table(region, band, &cfp_no); if (cfp == NULL) return 0; @@ -346,7 +338,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* /*Step1: check region_code */ parsed_region_chan->region = region = - wlan_region_2_code(countryinfo->countrycode); + lbs_region_2_code(countryinfo->countrycode); lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region); lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode, @@ -375,7 +367,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { /*step4: channel is supported? */ - if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) { + if (!lbs_get_chan_11d(band, firstchan, i, &curchan)) { /* Chan is not found in UN table */ lbs_deb_11d("chan is not supported: %d \n", i); break; @@ -383,7 +375,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* lastchan = curchan; - if (wlan_region_chan_supported_11d + if (lbs_region_chan_supported_11d (region, band, curchan)) { /*step5: Check if curchan is supported by mrvl in region */ parsed_region_chan->chanpwr[idx].chan = curchan; @@ -419,14 +411,14 @@ done: * @param parsed_region_chan pointer to parsed_region_chan_11d * @return PASSIVE if chan is unknown; ACTIVE if chan is known */ -u8 libertas_get_scan_type_11d(u8 chan, +u8 lbs_get_scan_type_11d(u8 chan, struct parsed_region_chan_11d * parsed_region_chan) { u8 scan_type = CMD_SCAN_TYPE_PASSIVE; lbs_deb_enter(LBS_DEB_11D); - if (wlan_channel_known_11d(chan, parsed_region_chan)) { + if (lbs_channel_known_11d(chan, parsed_region_chan)) { lbs_deb_11d("found, do active scan\n"); scan_type = CMD_SCAN_TYPE_ACTIVE; } else { @@ -438,29 +430,29 @@ u8 libertas_get_scan_type_11d(u8 chan, } -void libertas_init_11d(wlan_private * priv) +void lbs_init_11d(struct lbs_private *priv) { - priv->adapter->enable11d = 0; - memset(&(priv->adapter->parsed_region_chan), 0, + priv->enable11d = 0; + memset(&(priv->parsed_region_chan), 0, sizeof(struct parsed_region_chan_11d)); return; } /** * @brief This function sets DOMAIN INFO to FW - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @return 0; -1 */ -static int set_domain_info_11d(wlan_private * priv) +static int set_domain_info_11d(struct lbs_private *priv) { int ret; - if (!priv->adapter->enable11d) { + if (!priv->enable11d) { lbs_deb_11d("dnld domain Info with 11d disabled\n"); return 0; } - ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, + ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); if (ret) @@ -471,28 +463,27 @@ static int set_domain_info_11d(wlan_private * priv) /** * @brief This function setups scan channels - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @param band band * @return 0 */ -int libertas_set_universaltable(wlan_private * priv, u8 band) +int lbs_set_universaltable(struct lbs_private *priv, u8 band) { - wlan_adapter *adapter = priv->adapter; u16 size = sizeof(struct chan_freq_power); u16 i = 0; - memset(adapter->universal_channel, 0, - sizeof(adapter->universal_channel)); + memset(priv->universal_channel, 0, + sizeof(priv->universal_channel)); - adapter->universal_channel[i].nrcfp = + priv->universal_channel[i].nrcfp = sizeof(channel_freq_power_UN_BG) / size; lbs_deb_11d("BG-band nrcfp %d\n", - adapter->universal_channel[i].nrcfp); + priv->universal_channel[i].nrcfp); - adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; - adapter->universal_channel[i].valid = 1; - adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE; - adapter->universal_channel[i].band = band; + priv->universal_channel[i].CFP = channel_freq_power_UN_BG; + priv->universal_channel[i].valid = 1; + priv->universal_channel[i].region = UNIVERSAL_REGION_CODE; + priv->universal_channel[i].band = band; i++; return 0; @@ -500,21 +491,20 @@ int libertas_set_universaltable(wlan_private * priv, u8 band) /** * @brief This function implements command CMD_802_11D_DOMAIN_INFO - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @param cmd pointer to cmd buffer * @param cmdno cmd ID * @param cmdOption cmd action * @return 0 */ -int libertas_cmd_802_11d_domain_info(wlan_private * priv, +int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmdno, u16 cmdoption) { struct cmd_ds_802_11d_domain_info *pdomaininfo = &cmd->params.domaininfo; struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; - wlan_adapter *adapter = priv->adapter; - u8 nr_subband = adapter->domainreg.nr_subband; + u8 nr_subband = priv->domainreg.nr_subband; lbs_deb_enter(LBS_DEB_11D); @@ -526,12 +516,12 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, - (int)(cmd->size)); + le16_to_cpu(cmd->size)); goto done; } domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); - memcpy(domain->countrycode, adapter->domainreg.countrycode, + memcpy(domain->countrycode, priv->domainreg.countrycode, sizeof(domain->countrycode)); domain->header.len = @@ -539,7 +529,7 @@ int libertas_cmd_802_11d_domain_info(wlan_private * priv, sizeof(domain->countrycode)); if (nr_subband) { - memcpy(domain->subband, adapter->domainreg.subband, + memcpy(domain->subband, priv->domainreg.subband, nr_subband * sizeof(struct ieeetypes_subbandset)); cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + @@ -560,11 +550,11 @@ done: /** * @brief This function parses countryinfo from AP and download country info to FW - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @param resp pointer to command response buffer * @return 0; -1 */ -int libertas_ret_802_11d_domain_info(wlan_private * priv, +int lbs_ret_802_11d_domain_info(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp; @@ -606,31 +596,30 @@ int libertas_ret_802_11d_domain_info(wlan_private * priv, /** * @brief This function parses countryinfo from AP and download country info to FW - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @return 0; -1 */ -int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, +int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, struct bss_descriptor * bss) { int ret; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_11D); - if (priv->adapter->enable11d) { - memset(&adapter->parsed_region_chan, 0, + if (priv->enable11d) { + memset(&priv->parsed_region_chan, 0, sizeof(struct parsed_region_chan_11d)); ret = parse_domain_info_11d(&bss->countryinfo, 0, - &adapter->parsed_region_chan); + &priv->parsed_region_chan); if (ret == -1) { lbs_deb_11d("error parsing domain_info from AP\n"); goto done; } - memset(&adapter->domainreg, 0, - sizeof(struct wlan_802_11d_domain_reg)); - generate_domain_info_11d(&adapter->parsed_region_chan, - &adapter->domainreg); + memset(&priv->domainreg, 0, + sizeof(struct lbs_802_11d_domain_reg)); + generate_domain_info_11d(&priv->parsed_region_chan, + &priv->domainreg); ret = set_domain_info_11d(priv); @@ -648,25 +637,23 @@ done: /** * @brief This function generates 11D info from user specified regioncode and download to FW - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @return 0; -1 */ -int libertas_create_dnld_countryinfo_11d(wlan_private * priv) +int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv) { int ret; - wlan_adapter *adapter = priv->adapter; struct region_channel *region_chan; u8 j; lbs_deb_enter(LBS_DEB_11D); - lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band); + lbs_deb_11d("curbssparams.band %d\n", priv->curbssparams.band); - if (priv->adapter->enable11d) { + if (priv->enable11d) { /* update parsed_region_chan_11; dnld domaininf to FW */ - for (j = 0; j < sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0]); j++) { - region_chan = &adapter->region_channel[j]; + for (j = 0; j < ARRAY_SIZE(priv->region_channel); j++) { + region_chan = &priv->region_channel[j]; lbs_deb_11d("%d region_chan->band %d\n", j, region_chan->band); @@ -674,29 +661,28 @@ int libertas_create_dnld_countryinfo_11d(wlan_private * priv) if (!region_chan || !region_chan->valid || !region_chan->CFP) continue; - if (region_chan->band != adapter->curbssparams.band) + if (region_chan->band != priv->curbssparams.band) continue; break; } - if (j >= sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0])) { + if (j >= ARRAY_SIZE(priv->region_channel)) { lbs_deb_11d("region_chan not found, band %d\n", - adapter->curbssparams.band); + priv->curbssparams.band); ret = -1; goto done; } - memset(&adapter->parsed_region_chan, 0, + memset(&priv->parsed_region_chan, 0, sizeof(struct parsed_region_chan_11d)); - wlan_generate_parsed_region_chan_11d(region_chan, - &adapter-> + lbs_generate_parsed_region_chan_11d(region_chan, + &priv-> parsed_region_chan); - memset(&adapter->domainreg, 0, - sizeof(struct wlan_802_11d_domain_reg)); - generate_domain_info_11d(&adapter->parsed_region_chan, - &adapter->domainreg); + memset(&priv->domainreg, 0, + sizeof(struct lbs_802_11d_domain_reg)); + generate_domain_info_11d(&priv->parsed_region_chan, + &priv->domainreg); ret = set_domain_info_11d(priv); diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h index 3a6d1f8db78f..811eea2cfba3 100644 --- a/drivers/net/wireless/libertas/11d.h +++ b/drivers/net/wireless/libertas/11d.h @@ -2,8 +2,8 @@ * This header file contains data structures and * function declarations of 802.11d */ -#ifndef _WLAN_11D_ -#define _WLAN_11D_ +#ifndef _LBS_11D_ +#define _LBS_11D_ #include "types.h" #include "defs.h" @@ -52,7 +52,7 @@ struct cmd_ds_802_11d_domain_info { } __attribute__ ((packed)); /** domain regulatory information */ -struct wlan_802_11d_domain_reg { +struct lbs_802_11d_domain_reg { /** country Code*/ u8 countrycode[COUNTRY_CODE_LEN]; /** No. of subband*/ @@ -78,26 +78,28 @@ struct region_code_mapping { u8 code; }; -u8 libertas_get_scan_type_11d(u8 chan, +struct lbs_private; + +u8 lbs_get_scan_type_11d(u8 chan, struct parsed_region_chan_11d *parsed_region_chan); -u32 libertas_chan_2_freq(u8 chan, u8 band); +u32 lbs_chan_2_freq(u8 chan, u8 band); -void libertas_init_11d(wlan_private * priv); +void lbs_init_11d(struct lbs_private *priv); -int libertas_set_universaltable(wlan_private * priv, u8 band); +int lbs_set_universaltable(struct lbs_private *priv, u8 band); -int libertas_cmd_802_11d_domain_info(wlan_private * priv, +int lbs_cmd_802_11d_domain_info(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmdno, u16 cmdOption); -int libertas_ret_802_11d_domain_info(wlan_private * priv, +int lbs_ret_802_11d_domain_info(struct lbs_private *priv, struct cmd_ds_command *resp); struct bss_descriptor; -int libertas_parse_dnld_countryinfo_11d(wlan_private * priv, +int lbs_parse_dnld_countryinfo_11d(struct lbs_private *priv, struct bss_descriptor * bss); -int libertas_create_dnld_countryinfo_11d(wlan_private * priv); +int lbs_create_dnld_countryinfo_11d(struct lbs_private *priv); -#endif /* _WLAN_11D_ */ +#endif diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index 0b133ce63805..d860fc375752 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -195,45 +195,33 @@ setuserscan where [ARGS]: - chan=[chan#][band][mode] where band is [a,b,g] and mode is - blank for active or 'p' for passive bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan ssid="[SSID]" specify a SSID filter for the scan keep=[0 or 1] keep the previous scan results (1), discard (0) dur=[scan time] time to scan for each channel in milliseconds - probes=[#] number of probe requests to send on each chan type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) - Any combination of the above arguments can be supplied on the command line. - If the chan token is absent, a full channel scan will be completed by - the driver. If the dur or probes tokens are absent, the driver default - setting will be used. The bssid and ssid fields, if blank, - will produce an unfiltered scan. The type field will default to 3 (Any) - and the keep field will default to 0 (Discard). + Any combination of the above arguments can be supplied on the command + line. If dur tokens are absent, the driver default setting will be used. + The bssid and ssid fields, if blank, will produce an unfiltered scan. + The type field will default to 3 (Any) and the keep field will default + to 0 (Discard). Examples: - 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band: - echo "chan=1g,6g,11g" > setuserscan + 1) Perform a passive scan on all channels for 20 ms per channel: + echo "dur=20" > setuserscan - 2) Perform a passive scan on channel 11 for 20 ms: - echo "chan=11gp dur=20" > setuserscan + 2) Perform an active scan for a specific SSID: + echo "ssid="TestAP"" > setuserscan - 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on - channel 36 in the 'a' band: - - echo "chan=1g,6g,11g,36ap" > setuserscan - - 4) Perform an active scan on channel 6 and 36 for a specific SSID: - echo "chan=6g,36a ssid="TestAP"" > setuserscan - - 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep + 3) Scan all available channels (B/G, A bands) for a specific BSSID, keep the current scan table intact, update existing or append new scan data: echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan - 6) Scan channel 6, for all infrastructure networks, sending two probe - requests. Keep the previous scan table intact. Update any duplicate - BSSID/SSID matches with the new scan data: - echo "chan=6g type=1 probes=2 keep=1" > setuserscan + 4) Scan for all infrastructure networks. + Keep the previous scan table intact. Update any duplicate BSSID/SSID + matches with the new scan data: + echo "type=1 keep=1" > setuserscan All entries in the scan table (not just the new scan data when keep=1) will be displayed upon completion by use of the getscantable ioctl. diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index b61b176e9d07..c622e9b63cd1 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -9,39 +9,16 @@ #include "decl.h" #include "hostcmd.h" #include "host.h" +#include "cmd.h" static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static void print_assoc_req(const char * extra, struct assoc_request * assoc_req) -{ - DECLARE_MAC_BUF(mac); - lbs_deb_assoc( - "#### Association Request: %s\n" - " flags: 0x%08lX\n" - " SSID: '%s'\n" - " channel: %d\n" - " band: %d\n" - " mode: %d\n" - " BSSID: %s\n" - " Encryption:%s%s%s\n" - " auth: %d\n", - extra, assoc_req->flags, - escape_essid(assoc_req->ssid, assoc_req->ssid_len), - assoc_req->channel, assoc_req->band, assoc_req->mode, - print_mac(mac, assoc_req->bssid), - assoc_req->secinfo.WPAenabled ? " WPA" : "", - assoc_req->secinfo.WPA2enabled ? " WPA2" : "", - assoc_req->secinfo.wep_enabled ? " WEP" : "", - assoc_req->secinfo.auth_mode); -} - -static int assoc_helper_essid(wlan_private *priv, +static int assoc_helper_essid(struct lbs_private *priv, struct assoc_request * assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; struct bss_descriptor * bss; int channel = -1; @@ -55,18 +32,17 @@ static int assoc_helper_essid(wlan_private *priv, if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) channel = assoc_req->channel; - lbs_deb_assoc("New SSID requested: '%s'\n", + lbs_deb_assoc("SSID '%s' requested\n", escape_essid(assoc_req->ssid, assoc_req->ssid_len)); if (assoc_req->mode == IW_MODE_INFRA) { - libertas_send_specific_ssid_scan(priv, assoc_req->ssid, + lbs_send_specific_ssid_scan(priv, assoc_req->ssid, assoc_req->ssid_len, 0); - bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid, + bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel); if (bss != NULL) { - lbs_deb_assoc("SSID found in scan list, associating\n"); memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - ret = wlan_associate(priv, assoc_req); + ret = lbs_associate(priv, assoc_req); } else { lbs_deb_assoc("SSID not found; cannot associate\n"); } @@ -74,23 +50,23 @@ static int assoc_helper_essid(wlan_private *priv, /* Scan for the network, do not save previous results. Stale * scan data will cause us to join a non-existant adhoc network */ - libertas_send_specific_ssid_scan(priv, assoc_req->ssid, + lbs_send_specific_ssid_scan(priv, assoc_req->ssid, assoc_req->ssid_len, 1); /* Search for the requested SSID in the scan table */ - bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid, + bss = lbs_find_ssid_in_list(priv, assoc_req->ssid, assoc_req->ssid_len, NULL, IW_MODE_ADHOC, channel); if (bss != NULL) { lbs_deb_assoc("SSID found, will join\n"); memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); - libertas_join_adhoc_network(priv, assoc_req); + lbs_join_adhoc_network(priv, assoc_req); } else { /* else send START command */ lbs_deb_assoc("SSID not found, creating adhoc network\n"); memcpy(&assoc_req->bss.ssid, &assoc_req->ssid, IW_ESSID_MAX_SIZE); assoc_req->bss.ssid_len = assoc_req->ssid_len; - libertas_start_adhoc_network(priv, assoc_req); + lbs_start_adhoc_network(priv, assoc_req); } } @@ -99,10 +75,9 @@ static int assoc_helper_essid(wlan_private *priv, } -static int assoc_helper_bssid(wlan_private *priv, +static int assoc_helper_bssid(struct lbs_private *priv, struct assoc_request * assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; struct bss_descriptor * bss; DECLARE_MAC_BUF(mac); @@ -111,7 +86,7 @@ static int assoc_helper_bssid(wlan_private *priv, print_mac(mac, assoc_req->bssid)); /* Search for index position in list for requested MAC */ - bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid, + bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, assoc_req->mode); if (bss == NULL) { lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " @@ -121,10 +96,10 @@ static int assoc_helper_bssid(wlan_private *priv, memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor)); if (assoc_req->mode == IW_MODE_INFRA) { - ret = wlan_associate(priv, assoc_req); - lbs_deb_assoc("ASSOC: wlan_associate(bssid) returned %d\n", ret); + ret = lbs_associate(priv, assoc_req); + lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret); } else if (assoc_req->mode == IW_MODE_ADHOC) { - libertas_join_adhoc_network(priv, assoc_req); + lbs_join_adhoc_network(priv, assoc_req); } out: @@ -133,11 +108,13 @@ out: } -static int assoc_helper_associate(wlan_private *priv, +static int assoc_helper_associate(struct lbs_private *priv, struct assoc_request * assoc_req) { int ret = 0, done = 0; + lbs_deb_enter(LBS_DEB_ASSOC); + /* If we're given and 'any' BSSID, try associating based on SSID */ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { @@ -145,42 +122,36 @@ static int assoc_helper_associate(wlan_private *priv, && compare_ether_addr(bssid_off, assoc_req->bssid)) { ret = assoc_helper_bssid(priv, assoc_req); done = 1; - if (ret) { - lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret); - } } } if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { ret = assoc_helper_essid(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC: bssid: ret = %d\n", ret); - } } + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -static int assoc_helper_mode(wlan_private *priv, +static int assoc_helper_mode(struct lbs_private *priv, struct assoc_request * assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); - if (assoc_req->mode == adapter->mode) + if (assoc_req->mode == priv->mode) goto done; if (assoc_req->mode == IW_MODE_INFRA) { - if (adapter->psstate != PS_STATE_FULL_POWER) - libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); - adapter->psmode = WLAN802_11POWERMODECAM; + if (priv->psstate != PS_STATE_FULL_POWER) + lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); + priv->psmode = LBS802_11POWERMODECAM; } - adapter->mode = assoc_req->mode; - ret = libertas_prepare_and_send_command(priv, + priv->mode = assoc_req->mode; + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, 0, CMD_OPTION_WAITFORRSP, OID_802_11_INFRASTRUCTURE_MODE, @@ -192,57 +163,76 @@ done: } -static int update_channel(wlan_private * priv) +int lbs_update_channel(struct lbs_private *priv) { - /* the channel in f/w could be out of sync, get the current channel */ - return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL, - CMD_OPT_802_11_RF_CHANNEL_GET, - CMD_OPTION_WAITFORRSP, 0, NULL); + int ret; + + /* the channel in f/w could be out of sync; get the current channel */ + lbs_deb_enter(LBS_DEB_ASSOC); + + ret = lbs_get_channel(priv); + if (ret > 0) { + priv->curbssparams.channel = ret; + ret = 0; + } + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); + return ret; } -void libertas_sync_channel(struct work_struct *work) +void lbs_sync_channel(struct work_struct *work) { - wlan_private *priv = container_of(work, wlan_private, sync_channel); + struct lbs_private *priv = container_of(work, struct lbs_private, + sync_channel); - if (update_channel(priv) != 0) + lbs_deb_enter(LBS_DEB_ASSOC); + if (lbs_update_channel(priv)) lbs_pr_info("Channel synchronization failed."); + lbs_deb_leave(LBS_DEB_ASSOC); } -static int assoc_helper_channel(wlan_private *priv, +static int assoc_helper_channel(struct lbs_private *priv, struct assoc_request * assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); - ret = update_channel(priv); - if (ret < 0) { - lbs_deb_assoc("ASSOC: channel: error getting channel."); + ret = lbs_update_channel(priv); + if (ret) { + lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); + goto done; } - if (assoc_req->channel == adapter->curbssparams.channel) + if (assoc_req->channel == priv->curbssparams.channel) goto done; + if (priv->mesh_dev) { + /* Change mesh channel first; 21.p21 firmware won't let + you change channel otherwise (even though it'll return + an error to this */ + lbs_mesh_config(priv, 0, assoc_req->channel); + } + lbs_deb_assoc("ASSOC: channel: %d -> %d\n", - adapter->curbssparams.channel, assoc_req->channel); + priv->curbssparams.channel, assoc_req->channel); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL, - CMD_OPT_802_11_RF_CHANNEL_SET, - CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel); - if (ret < 0) { - lbs_deb_assoc("ASSOC: channel: error setting channel."); - } + ret = lbs_set_channel(priv, assoc_req->channel); + if (ret < 0) + lbs_deb_assoc("ASSOC: channel: error setting channel.\n"); - ret = update_channel(priv); - if (ret < 0) { - lbs_deb_assoc("ASSOC: channel: error getting channel."); + /* FIXME: shouldn't need to grab the channel _again_ after setting + * it since the firmware is supposed to return the new channel, but + * whatever... */ + ret = lbs_update_channel(priv); + if (ret) { + lbs_deb_assoc("ASSOC: channel: error getting channel.\n"); + goto done; } - if (assoc_req->channel != adapter->curbssparams.channel) { - lbs_deb_assoc("ASSOC: channel: failed to update channel to %d", + if (assoc_req->channel != priv->curbssparams.channel) { + lbs_deb_assoc("ASSOC: channel: failed to update channel to %d\n", assoc_req->channel); - goto done; + goto restore_mesh; } if ( assoc_req->secinfo.wep_enabled @@ -255,83 +245,75 @@ static int assoc_helper_channel(wlan_private *priv, } /* Must restart/rejoin adhoc networks after channel change */ - set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); + set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); -done: + restore_mesh: + if (priv->mesh_dev) + lbs_mesh_config(priv, 1, priv->curbssparams.channel); + + done: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -static int assoc_helper_wep_keys(wlan_private *priv, - struct assoc_request * assoc_req) +static int assoc_helper_wep_keys(struct lbs_private *priv, + struct assoc_request *assoc_req) { - wlan_adapter *adapter = priv->adapter; int i; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); /* Set or remove WEP keys */ - if ( assoc_req->wep_keys[0].len - || assoc_req->wep_keys[1].len - || assoc_req->wep_keys[2].len - || assoc_req->wep_keys[3].len) { - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_SET_WEP, - CMD_ACT_ADD, - CMD_OPTION_WAITFORRSP, - 0, assoc_req); - } else { - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_SET_WEP, - CMD_ACT_REMOVE, - CMD_OPTION_WAITFORRSP, - 0, NULL); - } + if (assoc_req->wep_keys[0].len || assoc_req->wep_keys[1].len || + assoc_req->wep_keys[2].len || assoc_req->wep_keys[3].len) + ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_ADD, assoc_req); + else + ret = lbs_cmd_802_11_set_wep(priv, CMD_ACT_REMOVE, assoc_req); if (ret) goto out; /* enable/disable the MAC's WEP packet filter */ if (assoc_req->secinfo.wep_enabled) - adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE; + priv->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE; else - adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE; - ret = libertas_set_mac_packet_filter(priv); + priv->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE; + + ret = lbs_set_mac_packet_filter(priv); if (ret) goto out; - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); - /* Copy WEP keys into adapter wep key fields */ + /* Copy WEP keys into priv wep key fields */ for (i = 0; i < 4; i++) { - memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], - sizeof(struct enc_key)); + memcpy(&priv->wep_keys[i], &assoc_req->wep_keys[i], + sizeof(struct enc_key)); } - adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; + priv->wep_tx_keyidx = assoc_req->wep_tx_keyidx; - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -static int assoc_helper_secinfo(wlan_private *priv, +static int assoc_helper_secinfo(struct lbs_private *priv, struct assoc_request * assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; - u32 do_wpa; - u32 rsn = 0; + uint16_t do_wpa; + uint16_t rsn = 0; lbs_deb_enter(LBS_DEB_ASSOC); - memcpy(&adapter->secinfo, &assoc_req->secinfo, - sizeof(struct wlan_802_11_security)); + memcpy(&priv->secinfo, &assoc_req->secinfo, + sizeof(struct lbs_802_11_security)); - ret = libertas_set_mac_packet_filter(priv); + ret = lbs_set_mac_packet_filter(priv); if (ret) goto out; @@ -341,28 +323,19 @@ static int assoc_helper_secinfo(wlan_private *priv, */ /* Get RSN enabled/disabled */ - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_ENABLE_RSN, - CMD_ACT_GET, - CMD_OPTION_WAITFORRSP, - 0, &rsn); + ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_GET, &rsn); if (ret) { - lbs_deb_assoc("Failed to get RSN status: %d", ret); + lbs_deb_assoc("Failed to get RSN status: %d\n", ret); goto out; } /* Don't re-enable RSN if it's already enabled */ - do_wpa = (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled); + do_wpa = assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled; if (do_wpa == rsn) goto out; /* Set RSN enabled/disabled */ - rsn = do_wpa; - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_ENABLE_RSN, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, - 0, &rsn); + ret = lbs_cmd_802_11_enable_rsn(priv, CMD_ACT_SET, &do_wpa); out: lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -370,7 +343,7 @@ out: } -static int assoc_helper_wpa_keys(wlan_private *priv, +static int assoc_helper_wpa_keys(struct lbs_private *priv, struct assoc_request * assoc_req) { int ret = 0; @@ -385,7 +358,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv, if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_KEY_MATERIAL, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, @@ -399,7 +372,7 @@ static int assoc_helper_wpa_keys(wlan_private *priv, if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_KEY_MATERIAL, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, @@ -413,20 +386,19 @@ out: } -static int assoc_helper_wpa_ie(wlan_private *priv, +static int assoc_helper_wpa_ie(struct lbs_private *priv, struct assoc_request * assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { - memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); - adapter->wpa_ie_len = assoc_req->wpa_ie_len; + memcpy(&priv->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); + priv->wpa_ie_len = assoc_req->wpa_ie_len; } else { - memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN); - adapter->wpa_ie_len = 0; + memset(&priv->wpa_ie, 0, MAX_WPA_IE_LEN); + priv->wpa_ie_len = 0; } lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); @@ -434,55 +406,68 @@ static int assoc_helper_wpa_ie(wlan_private *priv, } -static int should_deauth_infrastructure(wlan_adapter *adapter, +static int should_deauth_infrastructure(struct lbs_private *priv, struct assoc_request * assoc_req) { - if (adapter->connect_status != LIBERTAS_CONNECTED) + int ret = 0; + + lbs_deb_enter(LBS_DEB_ASSOC); + + if (priv->connect_status != LBS_CONNECTED) return 0; if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { - lbs_deb_assoc("Deauthenticating due to new SSID in " - " configuration request.\n"); - return 1; + lbs_deb_assoc("Deauthenticating due to new SSID\n"); + ret = 1; + goto out; } if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { - if (adapter->secinfo.auth_mode != assoc_req->secinfo.auth_mode) { - lbs_deb_assoc("Deauthenticating due to updated security " - "info in configuration request.\n"); - return 1; + if (priv->secinfo.auth_mode != assoc_req->secinfo.auth_mode) { + lbs_deb_assoc("Deauthenticating due to new security\n"); + ret = 1; + goto out; } } if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - lbs_deb_assoc("Deauthenticating due to new BSSID in " - " configuration request.\n"); - return 1; + lbs_deb_assoc("Deauthenticating due to new BSSID\n"); + ret = 1; + goto out; } if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { - lbs_deb_assoc("Deauthenticating due to channel switch.\n"); - return 1; + lbs_deb_assoc("Deauthenticating due to channel switch\n"); + ret = 1; + goto out; } /* FIXME: deal with 'auto' mode somehow */ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { - if (assoc_req->mode != IW_MODE_INFRA) - return 1; + if (assoc_req->mode != IW_MODE_INFRA) { + lbs_deb_assoc("Deauthenticating due to leaving " + "infra mode\n"); + ret = 1; + goto out; + } } +out: + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return 0; } -static int should_stop_adhoc(wlan_adapter *adapter, +static int should_stop_adhoc(struct lbs_private *priv, struct assoc_request * assoc_req) { - if (adapter->connect_status != LIBERTAS_CONNECTED) + lbs_deb_enter(LBS_DEB_ASSOC); + + if (priv->connect_status != LBS_CONNECTED) return 0; - if (libertas_ssid_cmp(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len, + if (lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, assoc_req->ssid, assoc_req->ssid_len) != 0) return 1; @@ -493,18 +478,19 @@ static int should_stop_adhoc(wlan_adapter *adapter, } if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { - if (assoc_req->channel != adapter->curbssparams.channel) + if (assoc_req->channel != priv->curbssparams.channel) return 1; } + lbs_deb_leave(LBS_DEB_ASSOC); return 0; } -void libertas_association_worker(struct work_struct *work) +void lbs_association_worker(struct work_struct *work) { - wlan_private *priv = container_of(work, wlan_private, assoc_work.work); - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = container_of(work, struct lbs_private, + assoc_work.work); struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; @@ -512,16 +498,33 @@ void libertas_association_worker(struct work_struct *work) lbs_deb_enter(LBS_DEB_ASSOC); - mutex_lock(&adapter->lock); - assoc_req = adapter->pending_assoc_req; - adapter->pending_assoc_req = NULL; - adapter->in_progress_assoc_req = assoc_req; - mutex_unlock(&adapter->lock); + mutex_lock(&priv->lock); + assoc_req = priv->pending_assoc_req; + priv->pending_assoc_req = NULL; + priv->in_progress_assoc_req = assoc_req; + mutex_unlock(&priv->lock); if (!assoc_req) goto done; - print_assoc_req(__func__, assoc_req); + lbs_deb_assoc( + "Association Request:\n" + " flags: 0x%08lx\n" + " SSID: '%s'\n" + " chann: %d\n" + " band: %d\n" + " mode: %d\n" + " BSSID: %s\n" + " secinfo: %s%s%s\n" + " auth_mode: %d\n", + assoc_req->flags, + escape_essid(assoc_req->ssid, assoc_req->ssid_len), + assoc_req->channel, assoc_req->band, assoc_req->mode, + print_mac(mac, assoc_req->bssid), + assoc_req->secinfo.WPAenabled ? " WPA" : "", + assoc_req->secinfo.WPA2enabled ? " WPA2" : "", + assoc_req->secinfo.wep_enabled ? " WEP" : "", + assoc_req->secinfo.auth_mode); /* If 'any' SSID was specified, find an SSID to associate with */ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) @@ -538,7 +541,7 @@ void libertas_association_worker(struct work_struct *work) if (find_any_ssid) { u8 new_mode; - ret = libertas_find_best_network_ssid(priv, assoc_req->ssid, + ret = lbs_find_best_network_ssid(priv, assoc_req->ssid, &assoc_req->ssid_len, assoc_req->mode, &new_mode); if (ret) { lbs_deb_assoc("Could not find best network\n"); @@ -557,18 +560,18 @@ void libertas_association_worker(struct work_struct *work) * Check if the attributes being changing require deauthentication * from the currently associated infrastructure access point. */ - if (adapter->mode == IW_MODE_INFRA) { - if (should_deauth_infrastructure(adapter, assoc_req)) { - ret = libertas_send_deauthentication(priv); + if (priv->mode == IW_MODE_INFRA) { + if (should_deauth_infrastructure(priv, assoc_req)) { + ret = lbs_send_deauthentication(priv); if (ret) { lbs_deb_assoc("Deauthentication due to new " "configuration request failed: %d\n", ret); } } - } else if (adapter->mode == IW_MODE_ADHOC) { - if (should_stop_adhoc(adapter, assoc_req)) { - ret = libertas_stop_adhoc_network(priv); + } else if (priv->mode == IW_MODE_ADHOC) { + if (should_stop_adhoc(priv, assoc_req)) { + ret = lbs_stop_adhoc_network(priv); if (ret) { lbs_deb_assoc("Teardown of AdHoc network due to " "new configuration request failed: %d\n", @@ -581,58 +584,40 @@ void libertas_association_worker(struct work_struct *work) /* Send the various configuration bits to the firmware */ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { ret = assoc_helper_mode(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", - __LINE__, ret); + if (ret) goto out; - } } if (test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) { ret = assoc_helper_channel(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC(:%d) channel: ret = %d\n", - __LINE__, ret); + if (ret) goto out; - } } if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { ret = assoc_helper_wep_keys(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", - __LINE__, ret); + if (ret) goto out; - } } if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { ret = assoc_helper_secinfo(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", - __LINE__, ret); + if (ret) goto out; - } } if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { ret = assoc_helper_wpa_ie(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", - __LINE__, ret); + if (ret) goto out; - } } if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { ret = assoc_helper_wpa_keys(priv, assoc_req); - if (ret) { - lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", - __LINE__, ret); + if (ret) goto out; - } } /* SSID/BSSID should be the _last_ config option set, because they @@ -644,28 +629,27 @@ void libertas_association_worker(struct work_struct *work) ret = assoc_helper_associate(priv, assoc_req); if (ret) { - lbs_deb_assoc("ASSOC: association attempt unsuccessful: %d\n", + lbs_deb_assoc("ASSOC: association unsuccessful: %d\n", ret); success = 0; } - if (adapter->connect_status != LIBERTAS_CONNECTED) { - lbs_deb_assoc("ASSOC: association attempt unsuccessful, " - "not connected.\n"); + if (priv->connect_status != LBS_CONNECTED) { + lbs_deb_assoc("ASSOC: association unsuccessful, " + "not connected\n"); success = 0; } if (success) { - lbs_deb_assoc("ASSOC: association attempt successful. " - "Associated to '%s' (%s)\n", - escape_essid(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len), - print_mac(mac, adapter->curbssparams.bssid)); - libertas_prepare_and_send_command(priv, + lbs_deb_assoc("ASSOC: associated to '%s', %s\n", + escape_essid(priv->curbssparams.ssid, + priv->curbssparams.ssid_len), + print_mac(mac, priv->curbssparams.bssid)); + lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); - libertas_prepare_and_send_command(priv, + lbs_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0, CMD_OPTION_WAITFORRSP, 0, NULL); } else { @@ -679,9 +663,9 @@ out: ret); } - mutex_lock(&adapter->lock); - adapter->in_progress_assoc_req = NULL; - mutex_unlock(&adapter->lock); + mutex_lock(&priv->lock); + priv->in_progress_assoc_req = NULL; + mutex_unlock(&priv->lock); kfree(assoc_req); done: @@ -692,14 +676,15 @@ done: /* * Caller MUST hold any necessary locks */ -struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) +struct assoc_request *lbs_get_association_request(struct lbs_private *priv) { struct assoc_request * assoc_req; - if (!adapter->pending_assoc_req) { - adapter->pending_assoc_req = kzalloc(sizeof(struct assoc_request), + lbs_deb_enter(LBS_DEB_ASSOC); + if (!priv->pending_assoc_req) { + priv->pending_assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL); - if (!adapter->pending_assoc_req) { + if (!priv->pending_assoc_req) { lbs_pr_info("Not enough memory to allocate association" " request!\n"); return NULL; @@ -709,60 +694,59 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) /* Copy current configuration attributes to the association request, * but don't overwrite any that are already set. */ - assoc_req = adapter->pending_assoc_req; + assoc_req = priv->pending_assoc_req; if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { - memcpy(&assoc_req->ssid, &adapter->curbssparams.ssid, + memcpy(&assoc_req->ssid, &priv->curbssparams.ssid, IW_ESSID_MAX_SIZE); - assoc_req->ssid_len = adapter->curbssparams.ssid_len; + assoc_req->ssid_len = priv->curbssparams.ssid_len; } if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) - assoc_req->channel = adapter->curbssparams.channel; + assoc_req->channel = priv->curbssparams.channel; if (!test_bit(ASSOC_FLAG_BAND, &assoc_req->flags)) - assoc_req->band = adapter->curbssparams.band; + assoc_req->band = priv->curbssparams.band; if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) - assoc_req->mode = adapter->mode; + assoc_req->mode = priv->mode; if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { - memcpy(&assoc_req->bssid, adapter->curbssparams.bssid, + memcpy(&assoc_req->bssid, priv->curbssparams.bssid, ETH_ALEN); } if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { int i; for (i = 0; i < 4; i++) { - memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], + memcpy(&assoc_req->wep_keys[i], &priv->wep_keys[i], sizeof(struct enc_key)); } } if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) - assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx; + assoc_req->wep_tx_keyidx = priv->wep_tx_keyidx; if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { - memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, + memcpy(&assoc_req->wpa_mcast_key, &priv->wpa_mcast_key, sizeof(struct enc_key)); } if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { - memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, + memcpy(&assoc_req->wpa_unicast_key, &priv->wpa_unicast_key, sizeof(struct enc_key)); } if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { - memcpy(&assoc_req->secinfo, &adapter->secinfo, - sizeof(struct wlan_802_11_security)); + memcpy(&assoc_req->secinfo, &priv->secinfo, + sizeof(struct lbs_802_11_security)); } if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { - memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie, + memcpy(&assoc_req->wpa_ie, &priv->wpa_ie, MAX_WPA_IE_LEN); - assoc_req->wpa_ie_len = adapter->wpa_ie_len; + assoc_req->wpa_ie_len = priv->wpa_ie_len; } - print_assoc_req(__func__, assoc_req); - + lbs_deb_leave(LBS_DEB_ASSOC); return assoc_req; } diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h index e09b7490abbd..08372bbf3761 100644 --- a/drivers/net/wireless/libertas/assoc.h +++ b/drivers/net/wireless/libertas/assoc.h @@ -1,32 +1,12 @@ /* Copyright (C) 2006, Red Hat, Inc. */ -#ifndef _WLAN_ASSOC_H_ -#define _WLAN_ASSOC_H_ +#ifndef _LBS_ASSOC_H_ +#define _LBS_ASSOC_H_ #include "dev.h" -void libertas_association_worker(struct work_struct *work); +void lbs_association_worker(struct work_struct *work); +struct assoc_request *lbs_get_association_request(struct lbs_private *priv); +void lbs_sync_channel(struct work_struct *work); -struct assoc_request * wlan_get_association_request(wlan_adapter *adapter); - -void libertas_sync_channel(struct work_struct *work); - -#define ASSOC_DELAY (HZ / 2) -static inline void wlan_postpone_association_work(wlan_private *priv) -{ - if (priv->adapter->surpriseremoved) - return; - cancel_delayed_work(&priv->assoc_work); - queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY); -} - -static inline void wlan_cancel_association_work(wlan_private *priv) -{ - cancel_delayed_work(&priv->assoc_work); - if (priv->adapter->pending_assoc_req) { - kfree(priv->adapter->pending_assoc_req); - priv->adapter->pending_assoc_req = NULL; - } -} - -#endif /* _WLAN_ASSOC_H */ +#endif /* _LBS_ASSOC_H */ diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index be5cfd8402c7..eab020338fde 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -11,47 +11,139 @@ #include "dev.h" #include "join.h" #include "wext.h" +#include "cmd.h" -static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode); +static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv); +static void lbs_set_cmd_ctrl_node(struct lbs_private *priv, + struct cmd_ctrl_node *ptempnode, + void *pdata_buf); -static u16 commands_allowed_in_ps[] = { - CMD_802_11_RSSI, -}; /** - * @brief This function checks if the commans is allowed - * in PS mode not. + * @brief Checks whether a command is allowed in Power Save mode * * @param command the command ID - * @return TRUE or FALSE + * @return 1 if allowed, 0 if not allowed */ -static u8 is_command_allowed_in_ps(__le16 command) +static u8 is_command_allowed_in_ps(u16 cmd) { - int i; - - for (i = 0; i < ARRAY_SIZE(commands_allowed_in_ps); i++) { - if (command == cpu_to_le16(commands_allowed_in_ps[i])) - return 1; + switch (cmd) { + case CMD_802_11_RSSI: + return 1; + default: + break; } - return 0; } -static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd) +/** + * @brief Updates the hardware details like MAC address and regulatory region + * + * @param priv A pointer to struct lbs_private structure + * + * @return 0 on success, error on failure + */ +int lbs_update_hw_spec(struct lbs_private *priv) { - struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec; + struct cmd_ds_get_hw_spec cmd; + int ret = -1; + u32 i; + DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_GET_HW_SPEC); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN); - memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN); + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + memcpy(cmd.permanentaddr, priv->current_addr, ETH_ALEN); + ret = lbs_cmd_with_response(priv, CMD_GET_HW_SPEC, &cmd); + if (ret) + goto out; + + priv->fwcapinfo = le32_to_cpu(cmd.fwcapinfo); + + /* The firmware release is in an interesting format: the patch + * level is in the most significant nibble ... so fix that: */ + priv->fwrelease = le32_to_cpu(cmd.fwrelease); + priv->fwrelease = (priv->fwrelease << 8) | + (priv->fwrelease >> 24 & 0xff); + + /* Some firmware capabilities: + * CF card firmware 5.0.16p0: cap 0x00000303 + * USB dongle firmware 5.110.17p2: cap 0x00000303 + */ + printk("libertas: %s, fw %u.%u.%up%u, cap 0x%08x\n", + print_mac(mac, cmd.permanentaddr), + priv->fwrelease >> 24 & 0xff, + priv->fwrelease >> 16 & 0xff, + priv->fwrelease >> 8 & 0xff, + priv->fwrelease & 0xff, + priv->fwcapinfo); + lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", + cmd.hwifversion, cmd.version); + + /* Clamp region code to 8-bit since FW spec indicates that it should + * only ever be 8-bit, even though the field size is 16-bit. Some firmware + * returns non-zero high 8 bits here. + */ + priv->regioncode = le16_to_cpu(cmd.regioncode) & 0xFF; + + for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { + /* use the region code to search for the index */ + if (priv->regioncode == lbs_region_code_to_index[i]) + break; + } + + /* if it's unidentified region code, use the default (USA) */ + if (i >= MRVDRV_MAX_REGION_CODE) { + priv->regioncode = 0x10; + lbs_pr_info("unidentified region code; using the default (USA)\n"); + } + + if (priv->current_addr[0] == 0xff) + memmove(priv->current_addr, cmd.permanentaddr, ETH_ALEN); + + memcpy(priv->dev->dev_addr, priv->current_addr, ETH_ALEN); + if (priv->mesh_dev) + memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); + + if (lbs_set_regiontable(priv, priv->regioncode, 0)) { + ret = -1; + goto out; + } + if (lbs_set_universaltable(priv, 0)) { + ret = -1; + goto out; + } + +out: lbs_deb_leave(LBS_DEB_CMD); - return 0; + return ret; } -static int wlan_cmd_802_11_ps_mode(wlan_private * priv, +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) +{ + struct cmd_ds_host_sleep cmd_config; + int ret; + + cmd_config.hdr.size = cpu_to_le16(sizeof(cmd_config)); + cmd_config.criteria = cpu_to_le32(criteria); + cmd_config.gpio = priv->wol_gpio; + cmd_config.gap = priv->wol_gap; + + ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config); + if (!ret) { + lbs_deb_cmd("Set WOL criteria to %x\n", criteria); + priv->wol_criteria = criteria; + } else { + lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); + } + + return ret; +} +EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg); + +static int lbs_cmd_802_11_ps_mode(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action) { @@ -90,161 +182,161 @@ static int wlan_cmd_802_11_ps_mode(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) +int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, + uint16_t cmd_action, uint16_t *timeout) { - u16 *timeout = pdata_buf; + struct cmd_ds_802_11_inactivity_timeout cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); - cmd->size = - cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) - + S_DS_GEN); + cmd.hdr.command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action); + cmd.action = cpu_to_le16(cmd_action); - if (cmd_action) - cmd->params.inactivity_timeout.timeout = cpu_to_le16(*timeout); + if (cmd_action == CMD_ACT_SET) + cmd.timeout = cpu_to_le16(*timeout); else - cmd->params.inactivity_timeout.timeout = 0; + cmd.timeout = 0; - lbs_deb_leave(LBS_DEB_CMD); + ret = lbs_cmd_with_response(priv, CMD_802_11_INACTIVITY_TIMEOUT, &cmd); + + if (!ret) + *timeout = le16_to_cpu(cmd.timeout); + + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return 0; } -static int wlan_cmd_802_11_sleep_params(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) +int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, + struct sleep_params *sp) { - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params; + struct cmd_ds_802_11_sleep_params cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) + - S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS); - if (cmd_action == CMD_ACT_GET) { - memset(&adapter->sp, 0, sizeof(struct sleep_params)); - memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params)); - sp->action = cpu_to_le16(cmd_action); - } else if (cmd_action == CMD_ACT_SET) { - sp->action = cpu_to_le16(cmd_action); - sp->error = cpu_to_le16(adapter->sp.sp_error); - sp->offset = cpu_to_le16(adapter->sp.sp_offset); - sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime); - sp->calcontrol = (u8) adapter->sp.sp_calcontrol; - sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk; - sp->reserved = cpu_to_le16(adapter->sp.sp_reserved); + memset(&cmd, 0, sizeof(cmd)); + } else { + cmd.error = cpu_to_le16(sp->sp_error); + cmd.offset = cpu_to_le16(sp->sp_offset); + cmd.stabletime = cpu_to_le16(sp->sp_stabletime); + cmd.calcontrol = sp->sp_calcontrol; + cmd.externalsleepclk = sp->sp_extsleepclk; + cmd.reserved = cpu_to_le16(sp->sp_reserved); + } + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(cmd_action); + + ret = lbs_cmd_with_response(priv, CMD_802_11_SLEEP_PARAMS, &cmd); + + if (!ret) { + lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, " + "calcontrol 0x%x extsleepclk 0x%x\n", + le16_to_cpu(cmd.error), le16_to_cpu(cmd.offset), + le16_to_cpu(cmd.stabletime), cmd.calcontrol, + cmd.externalsleepclk); + + sp->sp_error = le16_to_cpu(cmd.error); + sp->sp_offset = le16_to_cpu(cmd.offset); + sp->sp_stabletime = le16_to_cpu(cmd.stabletime); + sp->sp_calcontrol = cmd.calcontrol; + sp->sp_extsleepclk = cmd.externalsleepclk; + sp->sp_reserved = le16_to_cpu(cmd.reserved); } - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return 0; } -static int wlan_cmd_802_11_set_wep(wlan_private * priv, - struct cmd_ds_command *cmd, - u32 cmd_act, - void * pdata_buf) +int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc) { - struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep; - wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_set_wep cmd; int ret = 0; - struct assoc_request * assoc_req = pdata_buf; lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_SET_WEP); - cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN); - - if (cmd_act == CMD_ACT_ADD) { - int i; + cmd.hdr.command = cpu_to_le16(CMD_802_11_SET_WEP); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - if (!assoc_req) { - lbs_deb_cmd("Invalid association request!"); - ret = -1; - goto done; - } + cmd.action = cpu_to_le16(cmd_action); - wep->action = cpu_to_le16(CMD_ACT_ADD); + if (cmd_action == CMD_ACT_ADD) { + int i; /* default tx key index */ - wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx & - (u32)CMD_WEP_KEY_INDEX_MASK)); + cmd.keyindex = cpu_to_le16(assoc->wep_tx_keyidx & + CMD_WEP_KEY_INDEX_MASK); /* Copy key types and material to host command structure */ for (i = 0; i < 4; i++) { - struct enc_key * pkey = &assoc_req->wep_keys[i]; + struct enc_key *pkey = &assoc->wep_keys[i]; switch (pkey->len) { case KEY_LEN_WEP_40: - wep->keytype[i] = CMD_TYPE_WEP_40_BIT; - memmove(&wep->keymaterial[i], pkey->key, - pkey->len); + cmd.keytype[i] = CMD_TYPE_WEP_40_BIT; + memmove(cmd.keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i); break; case KEY_LEN_WEP_104: - wep->keytype[i] = CMD_TYPE_WEP_104_BIT; - memmove(&wep->keymaterial[i], pkey->key, - pkey->len); + cmd.keytype[i] = CMD_TYPE_WEP_104_BIT; + memmove(cmd.keymaterial[i], pkey->key, pkey->len); lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i); break; case 0: break; default: lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n", - i, pkey->len); + i, pkey->len); ret = -1; goto done; break; } } - } else if (cmd_act == CMD_ACT_REMOVE) { + } else if (cmd_action == CMD_ACT_REMOVE) { /* ACT_REMOVE clears _all_ WEP keys */ - wep->action = cpu_to_le16(CMD_ACT_REMOVE); /* default tx key index */ - wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx & - (u32)CMD_WEP_KEY_INDEX_MASK)); - lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx); + cmd.keyindex = cpu_to_le16(priv->wep_tx_keyidx & + CMD_WEP_KEY_INDEX_MASK); + lbs_deb_cmd("SET_WEP: remove key %d\n", priv->wep_tx_keyidx); } - ret = 0; - + ret = lbs_cmd_with_response(priv, CMD_802_11_SET_WEP, &cmd); done: lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } -static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, - void * pdata_buf) +int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, + uint16_t *enable) { - struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn; - u32 * enable = pdata_buf; + struct cmd_ds_802_11_enable_rsn cmd; + int ret; lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN); - cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN); - penableRSN->action = cpu_to_le16(cmd_action); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(cmd_action); if (cmd_action == CMD_ACT_SET) { if (*enable) - penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN); + cmd.enable = cpu_to_le16(CMD_ENABLE_RSN); else - penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN); + cmd.enable = cpu_to_le16(CMD_DISABLE_RSN); lbs_deb_cmd("ENABLE_RSN: %d\n", *enable); } - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} + ret = lbs_cmd_with_response(priv, CMD_802_11_ENABLE_RSN, &cmd); + if (!ret && cmd_action == CMD_ACT_GET) + *enable = le16_to_cpu(cmd.enable); + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, struct enc_key * pkey) @@ -272,7 +364,7 @@ static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, lbs_deb_leave(LBS_DEB_CMD); } -static int wlan_cmd_802_11_key_material(wlan_private * priv, +static int lbs_cmd_802_11_key_material(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action, u32 cmd_oid, void *pdata_buf) @@ -319,7 +411,7 @@ done: return ret; } -static int wlan_cmd_802_11_reset(wlan_private * priv, +static int lbs_cmd_802_11_reset(struct lbs_private *priv, struct cmd_ds_command *cmd, int cmd_action) { struct cmd_ds_802_11_reset *reset = &cmd->params.reset; @@ -334,7 +426,7 @@ static int wlan_cmd_802_11_reset(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_get_log(wlan_private * priv, +static int lbs_cmd_802_11_get_log(struct lbs_private *priv, struct cmd_ds_command *cmd) { lbs_deb_enter(LBS_DEB_CMD); @@ -346,7 +438,7 @@ static int wlan_cmd_802_11_get_log(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_get_stat(wlan_private * priv, +static int lbs_cmd_802_11_get_stat(struct lbs_private *priv, struct cmd_ds_command *cmd) { lbs_deb_enter(LBS_DEB_CMD); @@ -358,13 +450,12 @@ static int wlan_cmd_802_11_get_stat(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, +static int lbs_cmd_802_11_snmp_mib(struct lbs_private *priv, struct cmd_ds_command *cmd, int cmd_action, int cmd_oid, void *pdata_buf) { struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib; - wlan_adapter *adapter = priv->adapter; u8 ucTemp; lbs_deb_enter(LBS_DEB_CMD); @@ -380,7 +471,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, u8 mode = (u8) (size_t) pdata_buf; pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I); - pSNMPMIB->bufsize = sizeof(u8); + pSNMPMIB->bufsize = cpu_to_le16(sizeof(u8)); if (mode == IW_MODE_ADHOC) { ucTemp = SNMP_MIB_VALUE_ADHOC; } else { @@ -400,8 +491,8 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I); if (cmd_action == CMD_ACT_SET) { - pSNMPMIB->querytype = CMD_ACT_SET; - pSNMPMIB->bufsize = sizeof(u16); + pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); + pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); ulTemp = *(u32 *)pdata_buf; *((__le16 *)(pSNMPMIB->value)) = cpu_to_le16((u16) ulTemp); @@ -433,7 +524,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, { u32 ulTemp; - pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I); + pSNMPMIB->oid = cpu_to_le16(RTSTHRESH_I); if (cmd_action == CMD_ACT_GET) { pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET); @@ -456,7 +547,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET); pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); *((__le16 *)(pSNMPMIB->value)) = - cpu_to_le16((u16) adapter->txretrycount); + cpu_to_le16((u16) priv->txretrycount); } break; @@ -479,47 +570,7 @@ static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_radio_control(wlan_private * priv, - struct cmd_ds_command *cmd, - int cmd_action) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_802_11_radio_control *pradiocontrol = &cmd->params.radio; - - lbs_deb_enter(LBS_DEB_CMD); - - cmd->size = - cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) + - S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL); - - pradiocontrol->action = cpu_to_le16(cmd_action); - - switch (adapter->preamble) { - case CMD_TYPE_SHORT_PREAMBLE: - pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE); - break; - - case CMD_TYPE_LONG_PREAMBLE: - pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE); - break; - - case CMD_TYPE_AUTO_PREAMBLE: - default: - pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE); - break; - } - - if (adapter->radioon) - pradiocontrol->control |= cpu_to_le16(TURN_ON_RF); - else - pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, +static int lbs_cmd_802_11_rf_tx_power(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { @@ -563,7 +614,7 @@ static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_monitor_mode(wlan_private * priv, +static int lbs_cmd_802_11_monitor_mode(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { @@ -583,13 +634,12 @@ static int wlan_cmd_802_11_monitor_mode(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, +static int lbs_cmd_802_11_rate_adapt_rateset(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action) { struct cmd_ds_802_11_rate_adapt_rateset *rateadapt = &cmd->params.rateset; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); cmd->size = @@ -598,46 +648,100 @@ static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET); rateadapt->action = cpu_to_le16(cmd_action); - rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto); - rateadapt->bitmap = cpu_to_le16(adapter->ratebitmap); + rateadapt->enablehwauto = cpu_to_le16(priv->enablehwauto); + rateadapt->bitmap = cpu_to_le16(priv->ratebitmap); lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_cmd_802_11_data_rate(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action) +/** + * @brief Get the current data rate + * + * @param priv A pointer to struct lbs_private structure + * + * @return The data rate on success, error on failure + */ +int lbs_get_data_rate(struct lbs_private *priv) { - struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate; - wlan_adapter *adapter = priv->adapter; + struct cmd_ds_802_11_data_rate cmd; + int ret = -1; lbs_deb_enter(LBS_DEB_CMD); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + - S_DS_GEN); - cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE); - memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); - pdatarate->action = cpu_to_le16(cmd_action); - - if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) { - pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate); - lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", - adapter->cur_rate); - } else if (cmd_action == CMD_ACT_SET_TX_AUTO) { + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_GET_TX_RATE); + + ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); + if (ret) + goto out; + + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd)); + + ret = (int) lbs_fw_index_to_data_rate(cmd.rates[0]); + lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", ret); + +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +/** + * @brief Set the data rate + * + * @param priv A pointer to struct lbs_private structure + * @param rate The desired data rate, or 0 to clear a locked rate + * + * @return 0 on success, error on failure + */ +int lbs_set_data_rate(struct lbs_private *priv, u8 rate) +{ + struct cmd_ds_802_11_data_rate cmd; + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + memset(&cmd, 0, sizeof(cmd)); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + if (rate > 0) { + cmd.action = cpu_to_le16(CMD_ACT_SET_TX_FIX_RATE); + cmd.rates[0] = lbs_data_rate_to_fw_index(rate); + if (cmd.rates[0] == 0) { + lbs_deb_cmd("DATA_RATE: invalid requested rate of" + " 0x%02X\n", rate); + ret = 0; + goto out; + } + lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n", cmd.rates[0]); + } else { + cmd.action = cpu_to_le16(CMD_ACT_SET_TX_AUTO); lbs_deb_cmd("DATA_RATE: setting auto\n"); } - lbs_deb_leave(LBS_DEB_CMD); - return 0; + ret = lbs_cmd_with_response(priv, CMD_802_11_DATA_RATE, &cmd); + if (ret) + goto out; + + lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) &cmd, sizeof (cmd)); + + /* FIXME: get actual rates FW can do if this command actually returns + * all data rates supported. + */ + priv->cur_rate = lbs_fw_index_to_data_rate(cmd.rates[0]); + lbs_deb_cmd("DATA_RATE: current rate is 0x%02x\n", priv->cur_rate); + +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; } -static int wlan_cmd_mac_multicast_adr(wlan_private * priv, +static int lbs_cmd_mac_multicast_adr(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action) { struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + @@ -647,39 +751,79 @@ static int wlan_cmd_mac_multicast_adr(wlan_private * priv, lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs); pMCastAdr->action = cpu_to_le16(cmd_action); pMCastAdr->nr_of_adrs = - cpu_to_le16((u16) adapter->nr_of_multicastmacaddr); - memcpy(pMCastAdr->maclist, adapter->multicastlist, - adapter->nr_of_multicastmacaddr * ETH_ALEN); + cpu_to_le16((u16) priv->nr_of_multicastmacaddr); + memcpy(pMCastAdr->maclist, priv->multicastlist, + priv->nr_of_multicastmacaddr * ETH_ALEN); lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_cmd_802_11_rf_channel(wlan_private * priv, - struct cmd_ds_command *cmd, - int option, void *pdata_buf) +/** + * @brief Get the radio channel + * + * @param priv A pointer to struct lbs_private structure + * + * @return The channel on success, error on failure + */ +int lbs_get_channel(struct lbs_private *priv) { - struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; + struct cmd_ds_802_11_rf_channel cmd; + int ret = 0; lbs_deb_enter(LBS_DEB_CMD); - cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) + - S_DS_GEN); - if (option == CMD_OPT_802_11_RF_CHANNEL_SET) { - rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf)); - } + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_GET); - rfchan->action = cpu_to_le16(option); + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd); + if (ret) + goto out; - lbs_deb_leave(LBS_DEB_CMD); - return 0; + ret = le16_to_cpu(cmd.channel); + lbs_deb_cmd("current radio channel is %d\n", ret); + +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; +} + +/** + * @brief Set the radio channel + * + * @param priv A pointer to struct lbs_private structure + * @param channel The desired channel, or 0 to clear a locked channel + * + * @return 0 on success, error on failure + */ +int lbs_set_channel(struct lbs_private *priv, u8 channel) +{ + struct cmd_ds_802_11_rf_channel cmd; + u8 old_channel = priv->curbssparams.channel; + int ret = 0; + + lbs_deb_enter(LBS_DEB_CMD); + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_OPT_802_11_RF_CHANNEL_SET); + cmd.channel = cpu_to_le16(channel); + + ret = lbs_cmd_with_response(priv, CMD_802_11_RF_CHANNEL, &cmd); + if (ret) + goto out; + + priv->curbssparams.channel = (uint8_t) le16_to_cpu(cmd.channel); + lbs_deb_cmd("channel switch from %d to %d\n", old_channel, + priv->curbssparams.channel); + +out: + lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); + return ret; } -static int wlan_cmd_802_11_rssi(wlan_private * priv, +static int lbs_cmd_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *cmd) { - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_RSSI); @@ -687,28 +831,28 @@ static int wlan_cmd_802_11_rssi(wlan_private * priv, cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR); /* reset Beacon SNR/NF/RSSI values */ - adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; - adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0; - adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0; - adapter->NF[TYPE_BEACON][TYPE_AVG] = 0; - adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; - adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; + priv->SNR[TYPE_BEACON][TYPE_AVG] = 0; + priv->NF[TYPE_BEACON][TYPE_NOAVG] = 0; + priv->NF[TYPE_BEACON][TYPE_AVG] = 0; + priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; + priv->RSSI[TYPE_BEACON][TYPE_AVG] = 0; lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_cmd_reg_access(wlan_private * priv, +static int lbs_cmd_reg_access(struct lbs_private *priv, struct cmd_ds_command *cmdptr, u8 cmd_action, void *pdata_buf) { - struct wlan_offset_value *offval; + struct lbs_offset_value *offval; lbs_deb_enter(LBS_DEB_CMD); - offval = (struct wlan_offset_value *)pdata_buf; + offval = (struct lbs_offset_value *)pdata_buf; - switch (cmdptr->command) { + switch (le16_to_cpu(cmdptr->command)) { case CMD_MAC_REG_ACCESS: { struct cmd_ds_mac_reg_access *macreg; @@ -773,11 +917,10 @@ static int wlan_cmd_reg_access(wlan_private * priv, return 0; } -static int wlan_cmd_802_11_mac_address(wlan_private * priv, +static int lbs_cmd_802_11_mac_address(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action) { - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS); @@ -789,19 +932,19 @@ static int wlan_cmd_802_11_mac_address(wlan_private * priv, if (cmd_action == CMD_ACT_SET) { memcpy(cmd->params.macadd.macadd, - adapter->current_addr, ETH_ALEN); - lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6); + priv->current_addr, ETH_ALEN); + lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", priv->current_addr, 6); } lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, +static int lbs_cmd_802_11_eeprom_access(struct lbs_private *priv, struct cmd_ds_command *cmd, int cmd_action, void *pdata_buf) { - struct wlan_ioctl_regrdwr *ea = pdata_buf; + struct lbs_ioctl_regrdwr *ea = pdata_buf; lbs_deb_enter(LBS_DEB_CMD); @@ -819,7 +962,7 @@ static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, return 0; } -static int wlan_cmd_bt_access(wlan_private * priv, +static int lbs_cmd_bt_access(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { @@ -857,7 +1000,7 @@ static int wlan_cmd_bt_access(wlan_private * priv, return 0; } -static int wlan_cmd_fwt_access(wlan_private * priv, +static int lbs_cmd_fwt_access(struct lbs_private *priv, struct cmd_ds_command *cmd, u16 cmd_action, void *pdata_buf) { @@ -879,47 +1022,72 @@ static int wlan_cmd_fwt_access(wlan_private * priv, return 0; } -static int wlan_cmd_mesh_access(wlan_private * priv, - struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, + struct cmd_ds_mesh_access *cmd) { - struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; + int ret; + lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action); - cmd->command = cpu_to_le16(CMD_MESH_ACCESS); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN); - cmd->result = 0; + cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS); + cmd->hdr.size = cpu_to_le16(sizeof(*cmd)); + cmd->hdr.result = 0; - if (pdata_buf) - memcpy(mesh_access, pdata_buf, sizeof(*mesh_access)); - else - memset(mesh_access, 0, sizeof(*mesh_access)); + cmd->action = cpu_to_le16(cmd_action); - mesh_access->action = cpu_to_le16(cmd_action); + ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd); lbs_deb_leave(LBS_DEB_CMD); - return 0; + return ret; } +EXPORT_SYMBOL_GPL(lbs_mesh_access); -static int wlan_cmd_set_boot2_ver(wlan_private * priv, +int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan) +{ + struct cmd_ds_mesh_config cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.action = cpu_to_le16(enable); + cmd.channel = cpu_to_le16(chan); + cmd.type = cpu_to_le16(priv->mesh_tlv); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + + if (enable) { + cmd.length = cpu_to_le16(priv->mesh_ssid_len); + memcpy(cmd.data, priv->mesh_ssid, priv->mesh_ssid_len); + } + lbs_deb_cmd("mesh config enable %d TLV %x channel %d SSID %s\n", + enable, priv->mesh_tlv, chan, + escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); + return lbs_cmd_with_response(priv, CMD_MESH_CONFIG, &cmd); +} + +static int lbs_cmd_bcn_ctrl(struct lbs_private * priv, struct cmd_ds_command *cmd, - u16 cmd_action, void *pdata_buf) + u16 cmd_action) { - struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver; - cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER); - cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN); - boot2_ver->version = priv->boot2_version; + struct cmd_ds_802_11_beacon_control + *bcn_ctrl = &cmd->params.bcn_ctrl; + + lbs_deb_enter(LBS_DEB_CMD); + cmd->size = + cpu_to_le16(sizeof(struct cmd_ds_802_11_beacon_control) + + S_DS_GEN); + cmd->command = cpu_to_le16(CMD_802_11_BEACON_CTRL); + + bcn_ctrl->action = cpu_to_le16(cmd_action); + bcn_ctrl->beacon_enable = cpu_to_le16(priv->beacon_enable); + bcn_ctrl->beacon_period = cpu_to_le16(priv->beacon_period); + + lbs_deb_leave(LBS_DEB_CMD); return 0; } -/* - * Note: NEVER use libertas_queue_cmd() with addtail==0 other than for - * the command timer, because it does not account for queued commands. - */ -void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail) +static void lbs_queue_cmd(struct lbs_private *priv, + struct cmd_ctrl_node *cmdnode) { unsigned long flags; - struct cmd_ds_command *cmdptr; + int addtail = 1; lbs_deb_enter(LBS_DEB_HOST); @@ -927,118 +1095,87 @@ void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n"); goto done; } - - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; - if (!cmdptr) { - lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n"); + if (!cmdnode->cmdbuf->size) { + lbs_deb_host("DNLD_CMD: cmd size is zero\n"); goto done; } + cmdnode->result = 0; /* Exit_PS command needs to be queued in the header always. */ - if (cmdptr->command == CMD_802_11_PS_MODE) { - struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; + if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) { + struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf[1]; + if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { - if (adapter->psstate != PS_STATE_FULL_POWER) + if (priv->psstate != PS_STATE_FULL_POWER) addtail = 0; } } - spin_lock_irqsave(&adapter->driver_lock, flags); + spin_lock_irqsave(&priv->driver_lock, flags); - if (addtail) { - list_add_tail((struct list_head *)cmdnode, - &adapter->cmdpendingq); - adapter->nr_cmd_pending++; - } else - list_add((struct list_head *)cmdnode, &adapter->cmdpendingq); + if (addtail) + list_add_tail(&cmdnode->list, &priv->cmdpendingq); + else + list_add(&cmdnode->list, &priv->cmdpendingq); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n", - le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command)); + le16_to_cpu(cmdnode->cmdbuf->command)); done: lbs_deb_leave(LBS_DEB_HOST); } -/* - * TODO: Fix the issue when DownloadcommandToStation is being called the - * second time when the command times out. All the cmdptr->xxx are in little - * endian and therefore all the comparissions will fail. - * For now - we are not performing the endian conversion the second time - but - * for PS and DEEP_SLEEP we need to worry - */ -static int DownloadcommandToStation(wlan_private * priv, - struct cmd_ctrl_node *cmdnode) +static void lbs_submit_command(struct lbs_private *priv, + struct cmd_ctrl_node *cmdnode) { unsigned long flags; - struct cmd_ds_command *cmdptr; - wlan_adapter *adapter = priv->adapter; - int ret = -1; - u16 cmdsize; - u16 command; + struct cmd_header *cmd; + uint16_t cmdsize; + uint16_t command; + int timeo = 5 * HZ; + int ret; lbs_deb_enter(LBS_DEB_HOST); - if (!adapter || !cmdnode) { - lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n"); - goto done; - } + cmd = cmdnode->cmdbuf; - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + spin_lock_irqsave(&priv->driver_lock, flags); + priv->cur_cmd = cmdnode; + priv->cur_cmd_retcode = 0; + spin_unlock_irqrestore(&priv->driver_lock, flags); - spin_lock_irqsave(&adapter->driver_lock, flags); - if (!cmdptr || !cmdptr->size) { - lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n"); - __libertas_cleanup_and_insert_cmd(priv, cmdnode); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - goto done; - } + cmdsize = le16_to_cpu(cmd->size); + command = le16_to_cpu(cmd->command); - adapter->cur_cmd = cmdnode; - adapter->cur_cmd_retcode = 0; - spin_unlock_irqrestore(&adapter->driver_lock, flags); + /* These commands take longer */ + if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE || + command == CMD_802_11_AUTHENTICATE) + timeo = 10 * HZ; - cmdsize = cmdptr->size; - command = cpu_to_le16(cmdptr->command); + lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n", + command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies); + lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize); - lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n", - command, le16_to_cpu(cmdptr->size), jiffies); - lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize); + ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize); - cmdnode->cmdwaitqwoken = 0; - cmdsize = cpu_to_le16(cmdsize); - - ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); - - if (ret != 0) { - lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n"); - spin_lock_irqsave(&adapter->driver_lock, flags); - adapter->cur_cmd_retcode = ret; - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - goto done; - } - - lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies); + if (ret) { + lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret); + /* Let the timer kick in and retry, and potentially reset + the whole thing if the condition persists */ + timeo = HZ; + } else + lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", + command, jiffies); /* Setup the timer after transmit command */ - if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE - || command == CMD_802_11_ASSOCIATE) - mod_timer(&adapter->command_timer, jiffies + (10*HZ)); - else - mod_timer(&adapter->command_timer, jiffies + (5*HZ)); - - ret = 0; + mod_timer(&priv->command_timer, jiffies + timeo); -done: - lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); - return ret; + lbs_deb_leave(LBS_DEB_HOST); } -static int wlan_cmd_mac_control(wlan_private * priv, +static int lbs_cmd_mac_control(struct lbs_private *priv, struct cmd_ds_command *cmd) { struct cmd_ds_mac_control *mac = &cmd->params.macctrl; @@ -1047,7 +1184,7 @@ static int wlan_cmd_mac_control(wlan_private * priv, cmd->command = cpu_to_le16(CMD_MAC_CONTROL); cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); - mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); + mac->action = cpu_to_le16(priv->currentpacketfilter); lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n", le16_to_cpu(mac->action), le16_to_cpu(cmd->size)); @@ -1058,54 +1195,98 @@ static int wlan_cmd_mac_control(wlan_private * priv, /** * This function inserts command node to cmdfreeq - * after cleans it. Requires adapter->driver_lock held. + * after cleans it. Requires priv->driver_lock held. */ -void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) +static void __lbs_cleanup_and_insert_cmd(struct lbs_private *priv, + struct cmd_ctrl_node *cmdnode) { - wlan_adapter *adapter = priv->adapter; + lbs_deb_enter(LBS_DEB_HOST); - if (!ptempcmd) - return; + if (!cmdnode) + goto out; + + cmdnode->callback = NULL; + cmdnode->callback_arg = 0; - cleanup_cmdnode(ptempcmd); - list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq); + memset(cmdnode->cmdbuf, 0, LBS_CMD_BUFFER_SIZE); + + list_add_tail(&cmdnode->list, &priv->cmdfreeq); + out: + lbs_deb_leave(LBS_DEB_HOST); } -static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) +static void lbs_cleanup_and_insert_cmd(struct lbs_private *priv, + struct cmd_ctrl_node *ptempcmd) { unsigned long flags; - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - __libertas_cleanup_and_insert_cmd(priv, ptempcmd); - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); + spin_lock_irqsave(&priv->driver_lock, flags); + __lbs_cleanup_and_insert_cmd(priv, ptempcmd); + spin_unlock_irqrestore(&priv->driver_lock, flags); } -int libertas_set_radio_control(wlan_private * priv) +void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, + int result) +{ + if (cmd == priv->cur_cmd) + priv->cur_cmd_retcode = result; + + cmd->result = result; + cmd->cmdwaitqwoken = 1; + wake_up_interruptible(&cmd->cmdwait_q); + + if (!cmd->callback) + __lbs_cleanup_and_insert_cmd(priv, cmd); + priv->cur_cmd = NULL; +} + +int lbs_set_radio_control(struct lbs_private *priv) { int ret = 0; + struct cmd_ds_802_11_radio_control cmd; lbs_deb_enter(LBS_DEB_CMD); - ret = libertas_prepare_and_send_command(priv, - CMD_802_11_RADIO_CONTROL, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + + switch (priv->preamble) { + case CMD_TYPE_SHORT_PREAMBLE: + cmd.control = cpu_to_le16(SET_SHORT_PREAMBLE); + break; + + case CMD_TYPE_LONG_PREAMBLE: + cmd.control = cpu_to_le16(SET_LONG_PREAMBLE); + break; + + case CMD_TYPE_AUTO_PREAMBLE: + default: + cmd.control = cpu_to_le16(SET_AUTO_PREAMBLE); + break; + } + + if (priv->radioon) + cmd.control |= cpu_to_le16(TURN_ON_RF); + else + cmd.control &= cpu_to_le16(~TURN_ON_RF); + + lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", priv->radioon, + priv->preamble); - lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n", - priv->adapter->radioon, priv->adapter->preamble); + ret = lbs_cmd_with_response(priv, CMD_802_11_RADIO_CONTROL, &cmd); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; } -int libertas_set_mac_packet_filter(wlan_private * priv) +int lbs_set_mac_packet_filter(struct lbs_private *priv) { int ret = 0; lbs_deb_enter(LBS_DEB_CMD); /* Send MAC control command to station */ - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_MAC_CONTROL, 0, 0, 0, NULL); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); @@ -1115,7 +1296,7 @@ int libertas_set_mac_packet_filter(wlan_private * priv) /** * @brief This function prepare the command before send to firmware. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param cmd_no command number * @param cmd_action command action: GET or SET * @param wait_option wait option: wait response or not @@ -1123,32 +1304,31 @@ int libertas_set_mac_packet_filter(wlan_private * priv) * @param pdata_buf A pointer to informaion buffer * @return 0 or -1 */ -int libertas_prepare_and_send_command(wlan_private * priv, +int lbs_prepare_and_send_command(struct lbs_private *priv, u16 cmd_no, u16 cmd_action, u16 wait_option, u32 cmd_oid, void *pdata_buf) { int ret = 0; - wlan_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmdnode; struct cmd_ds_command *cmdptr; unsigned long flags; lbs_deb_enter(LBS_DEB_HOST); - if (!adapter) { - lbs_deb_host("PREP_CMD: adapter is NULL\n"); + if (!priv) { + lbs_deb_host("PREP_CMD: priv is NULL\n"); ret = -1; goto done; } - if (adapter->surpriseremoved) { + if (priv->surpriseremoved) { lbs_deb_host("PREP_CMD: card removed\n"); ret = -1; goto done; } - cmdnode = libertas_get_free_cmd_ctrl_node(priv); + cmdnode = lbs_get_cmd_ctrl_node(priv); if (cmdnode == NULL) { lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); @@ -1159,138 +1339,107 @@ int libertas_prepare_and_send_command(wlan_private * priv, goto done; } - libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf); + lbs_set_cmd_ctrl_node(priv, cmdnode, pdata_buf); - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + cmdptr = (struct cmd_ds_command *)cmdnode->cmdbuf; lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no); - if (!cmdptr) { - lbs_deb_host("PREP_CMD: cmdptr is NULL\n"); - libertas_cleanup_and_insert_cmd(priv, cmdnode); - ret = -1; - goto done; - } - /* Set sequence number, command and INT option */ - adapter->seqnum++; - cmdptr->seqnum = cpu_to_le16(adapter->seqnum); + priv->seqnum++; + cmdptr->seqnum = cpu_to_le16(priv->seqnum); cmdptr->command = cpu_to_le16(cmd_no); cmdptr->result = 0; switch (cmd_no) { - case CMD_GET_HW_SPEC: - ret = wlan_cmd_hw_spec(priv, cmdptr); - break; case CMD_802_11_PS_MODE: - ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); + ret = lbs_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); break; case CMD_802_11_SCAN: - ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); + ret = lbs_cmd_80211_scan(priv, cmdptr, pdata_buf); break; case CMD_MAC_CONTROL: - ret = wlan_cmd_mac_control(priv, cmdptr); + ret = lbs_cmd_mac_control(priv, cmdptr); break; case CMD_802_11_ASSOCIATE: case CMD_802_11_REASSOCIATE: - ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); + ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf); break; case CMD_802_11_DEAUTHENTICATE: - ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); - break; - - case CMD_802_11_SET_WEP: - ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); + ret = lbs_cmd_80211_deauthenticate(priv, cmdptr); break; case CMD_802_11_AD_HOC_START: - ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); + ret = lbs_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); break; case CMD_CODE_DNLD: break; case CMD_802_11_RESET: - ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); + ret = lbs_cmd_802_11_reset(priv, cmdptr, cmd_action); break; case CMD_802_11_GET_LOG: - ret = wlan_cmd_802_11_get_log(priv, cmdptr); + ret = lbs_cmd_802_11_get_log(priv, cmdptr); break; case CMD_802_11_AUTHENTICATE: - ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); + ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf); break; case CMD_802_11_GET_STAT: - ret = wlan_cmd_802_11_get_stat(priv, cmdptr); + ret = lbs_cmd_802_11_get_stat(priv, cmdptr); break; case CMD_802_11_SNMP_MIB: - ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, + ret = lbs_cmd_802_11_snmp_mib(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; case CMD_MAC_REG_ACCESS: case CMD_BBP_REG_ACCESS: case CMD_RF_REG_ACCESS: - ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case CMD_802_11_RF_CHANNEL: - ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, - cmd_action, pdata_buf); + ret = lbs_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_RF_TX_POWER: - ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, + ret = lbs_cmd_802_11_rf_tx_power(priv, cmdptr, cmd_action, pdata_buf); break; - case CMD_802_11_RADIO_CONTROL: - ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); - break; - - case CMD_802_11_DATA_RATE: - ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); - break; case CMD_802_11_RATE_ADAPT_RATESET: - ret = wlan_cmd_802_11_rate_adapt_rateset(priv, + ret = lbs_cmd_802_11_rate_adapt_rateset(priv, cmdptr, cmd_action); break; case CMD_MAC_MULTICAST_ADR: - ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); + ret = lbs_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); break; case CMD_802_11_MONITOR_MODE: - ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr, + ret = lbs_cmd_802_11_monitor_mode(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_802_11_AD_HOC_JOIN: - ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); + ret = lbs_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); break; case CMD_802_11_RSSI: - ret = wlan_cmd_802_11_rssi(priv, cmdptr); + ret = lbs_cmd_802_11_rssi(priv, cmdptr); break; case CMD_802_11_AD_HOC_STOP: - ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); - break; - - case CMD_802_11_ENABLE_RSN: - ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action, - pdata_buf); + ret = lbs_cmd_80211_ad_hoc_stop(priv, cmdptr); break; case CMD_802_11_KEY_MATERIAL: - ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action, + ret = lbs_cmd_802_11_key_material(priv, cmdptr, cmd_action, cmd_oid, pdata_buf); break; @@ -1300,11 +1449,11 @@ int libertas_prepare_and_send_command(wlan_private * priv, break; case CMD_802_11_MAC_ADDRESS: - ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); + ret = lbs_cmd_802_11_mac_address(priv, cmdptr, cmd_action); break; case CMD_802_11_EEPROM_ACCESS: - ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, + ret = lbs_cmd_802_11_eeprom_access(priv, cmdptr, cmd_action, pdata_buf); break; @@ -1322,19 +1471,10 @@ int libertas_prepare_and_send_command(wlan_private * priv, goto done; case CMD_802_11D_DOMAIN_INFO: - ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, + ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_no, cmd_action); break; - case CMD_802_11_SLEEP_PARAMS: - ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); - break; - case CMD_802_11_INACTIVITY_TIMEOUT: - ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, - cmd_action, pdata_buf); - libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); - break; - case CMD_802_11_TPC_CFG: cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG); cmdptr->size = @@ -1361,13 +1501,15 @@ int libertas_prepare_and_send_command(wlan_private * priv, #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 cmdptr->size = - cpu_to_le16(gpio->header.len + S_DS_GEN + - ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); - gpio->header.len = cpu_to_le16(gpio->header.len); + cpu_to_le16(le16_to_cpu(gpio->header.len) + + S_DS_GEN + + ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); + gpio->header.len = gpio->header.len; ret = 0; break; } + case CMD_802_11_PWR_CFG: cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG); cmdptr->size = @@ -1379,19 +1521,11 @@ int libertas_prepare_and_send_command(wlan_private * priv, ret = 0; break; case CMD_BT_ACCESS: - ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); + ret = lbs_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_FWT_ACCESS: - ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case CMD_MESH_ACCESS: - ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); - break; - - case CMD_SET_BOOT2_VER: - ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf); + ret = lbs_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); break; case CMD_GET_TSF: @@ -1400,6 +1534,9 @@ int libertas_prepare_and_send_command(wlan_private * priv, S_DS_GEN); ret = 0; break; + case CMD_802_11_BEACON_CTRL: + ret = lbs_cmd_bcn_ctrl(priv, cmdptr, cmd_action); + break; default: lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no); ret = -1; @@ -1409,14 +1546,14 @@ int libertas_prepare_and_send_command(wlan_private * priv, /* return error, since the command preparation failed */ if (ret != 0) { lbs_deb_host("PREP_CMD: command preparation failed\n"); - libertas_cleanup_and_insert_cmd(priv, cmdnode); + lbs_cleanup_and_insert_cmd(priv, cmdnode); ret = -1; goto done; } cmdnode->cmdwaitqwoken = 0; - libertas_queue_cmd(adapter, cmdnode, 1); + lbs_queue_cmd(priv, cmdnode); wake_up_interruptible(&priv->waitq); if (wait_option & CMD_OPTION_WAITFORRSP) { @@ -1426,67 +1563,60 @@ int libertas_prepare_and_send_command(wlan_private * priv, cmdnode->cmdwaitqwoken); } - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd_retcode) { + spin_lock_irqsave(&priv->driver_lock, flags); + if (priv->cur_cmd_retcode) { lbs_deb_host("PREP_CMD: command failed with return code %d\n", - adapter->cur_cmd_retcode); - adapter->cur_cmd_retcode = 0; + priv->cur_cmd_retcode); + priv->cur_cmd_retcode = 0; ret = -1; } - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); done: lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command); +EXPORT_SYMBOL_GPL(lbs_prepare_and_send_command); /** * @brief This function allocates the command buffer and link * it to command free queue. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return 0 or -1 */ -int libertas_allocate_cmd_buffer(wlan_private * priv) +int lbs_allocate_cmd_buffer(struct lbs_private *priv) { int ret = 0; - u32 ulbufsize; + u32 bufsize; u32 i; - struct cmd_ctrl_node *tempcmd_array; - u8 *ptempvirtualaddr; - wlan_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmdarray; lbs_deb_enter(LBS_DEB_HOST); - /* Allocate and initialize cmdCtrlNode */ - ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; - - if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) { + /* Allocate and initialize the command array */ + bufsize = sizeof(struct cmd_ctrl_node) * LBS_NUM_CMD_BUFFERS; + if (!(cmdarray = kzalloc(bufsize, GFP_KERNEL))) { lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n"); ret = -1; goto done; } - adapter->cmd_array = tempcmd_array; + priv->cmd_array = cmdarray; - /* Allocate and initialize command buffers */ - ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; - for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { - if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) { + /* Allocate and initialize each command buffer in the command array */ + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + cmdarray[i].cmdbuf = kzalloc(LBS_CMD_BUFFER_SIZE, GFP_KERNEL); + if (!cmdarray[i].cmdbuf) { lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n"); ret = -1; goto done; } - - /* Update command buffer virtual */ - tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr; } - for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { - init_waitqueue_head(&tempcmd_array[i].cmdwait_q); - libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]); + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + init_waitqueue_head(&cmdarray[i].cmdwait_q); + lbs_cleanup_and_insert_cmd(priv, &cmdarray[i]); } - ret = 0; done: @@ -1497,39 +1627,36 @@ done: /** * @brief This function frees the command buffer. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return 0 or -1 */ -int libertas_free_cmd_buffer(wlan_private * priv) +int lbs_free_cmd_buffer(struct lbs_private *priv) { - u32 ulbufsize; /* Someone needs to die for this. Slowly and painfully */ + struct cmd_ctrl_node *cmdarray; unsigned int i; - struct cmd_ctrl_node *tempcmd_array; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_HOST); /* need to check if cmd array is allocated or not */ - if (adapter->cmd_array == NULL) { + if (priv->cmd_array == NULL) { lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n"); goto done; } - tempcmd_array = adapter->cmd_array; + cmdarray = priv->cmd_array; /* Release shared memory buffers */ - ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; - for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { - if (tempcmd_array[i].bufvirtualaddr) { - kfree(tempcmd_array[i].bufvirtualaddr); - tempcmd_array[i].bufvirtualaddr = NULL; + for (i = 0; i < LBS_NUM_CMD_BUFFERS; i++) { + if (cmdarray[i].cmdbuf) { + kfree(cmdarray[i].cmdbuf); + cmdarray[i].cmdbuf = NULL; } } /* Release cmd_ctrl_node */ - if (adapter->cmd_array) { - kfree(adapter->cmd_array); - adapter->cmd_array = NULL; + if (priv->cmd_array) { + kfree(priv->cmd_array); + priv->cmd_array = NULL; } done: @@ -1541,34 +1668,31 @@ done: * @brief This function gets a free command node if available in * command free queue. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL */ -struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) +static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv) { struct cmd_ctrl_node *tempnode; - wlan_adapter *adapter = priv->adapter; unsigned long flags; lbs_deb_enter(LBS_DEB_HOST); - if (!adapter) + if (!priv) return NULL; - spin_lock_irqsave(&adapter->driver_lock, flags); + spin_lock_irqsave(&priv->driver_lock, flags); - if (!list_empty(&adapter->cmdfreeq)) { - tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next; - list_del((struct list_head *)tempnode); + if (!list_empty(&priv->cmdfreeq)) { + tempnode = list_first_entry(&priv->cmdfreeq, + struct cmd_ctrl_node, list); + list_del(&tempnode->list); } else { lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n"); tempnode = NULL; } - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - if (tempnode) - cleanup_cmdnode(tempnode); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_leave(LBS_DEB_HOST); return tempnode; @@ -1580,47 +1704,26 @@ struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) * @param ptempnode A pointer to cmdCtrlNode structure * @return n/a */ -static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) -{ - lbs_deb_enter(LBS_DEB_HOST); - - if (!ptempnode) - return; - ptempnode->cmdwaitqwoken = 1; - wake_up_interruptible(&ptempnode->cmdwait_q); - ptempnode->status = 0; - ptempnode->cmd_oid = (u32) 0; - ptempnode->wait_option = 0; - ptempnode->pdata_buf = NULL; - - if (ptempnode->bufvirtualaddr != NULL) - memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); - - lbs_deb_leave(LBS_DEB_HOST); -} /** * @brief This function initializes the command node. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param ptempnode A pointer to cmd_ctrl_node structure - * @param cmd_oid cmd oid: treated as sub command - * @param wait_option wait option: wait response or not * @param pdata_buf A pointer to informaion buffer * @return 0 or -1 */ -void libertas_set_cmd_ctrl_node(wlan_private * priv, - struct cmd_ctrl_node *ptempnode, - u32 cmd_oid, u16 wait_option, void *pdata_buf) +static void lbs_set_cmd_ctrl_node(struct lbs_private *priv, + struct cmd_ctrl_node *ptempnode, + void *pdata_buf) { lbs_deb_enter(LBS_DEB_HOST); if (!ptempnode) return; - ptempnode->cmd_oid = cmd_oid; - ptempnode->wait_option = wait_option; - ptempnode->pdata_buf = pdata_buf; + ptempnode->callback = NULL; + ptempnode->callback_arg = (unsigned long)pdata_buf; lbs_deb_leave(LBS_DEB_HOST); } @@ -1630,60 +1733,58 @@ void libertas_set_cmd_ctrl_node(wlan_private * priv, * pending queue. It will put fimware back to PS mode * if applicable. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return 0 or -1 */ -int libertas_execute_next_command(wlan_private * priv) +int lbs_execute_next_command(struct lbs_private *priv) { - wlan_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmdnode = NULL; - struct cmd_ds_command *cmdptr; + struct cmd_header *cmd; unsigned long flags; int ret = 0; // Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the - // only caller to us is libertas_thread() and we get even when a + // only caller to us is lbs_thread() and we get even when a // data packet is received lbs_deb_enter(LBS_DEB_THREAD); - spin_lock_irqsave(&adapter->driver_lock, flags); + spin_lock_irqsave(&priv->driver_lock, flags); - if (adapter->cur_cmd) { + if (priv->cur_cmd) { lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n"); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } - if (!list_empty(&adapter->cmdpendingq)) { - cmdnode = (struct cmd_ctrl_node *) - adapter->cmdpendingq.next; + if (!list_empty(&priv->cmdpendingq)) { + cmdnode = list_first_entry(&priv->cmdpendingq, + struct cmd_ctrl_node, list); } - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); if (cmdnode) { - cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; + cmd = cmdnode->cmdbuf; - if (is_command_allowed_in_ps(cmdptr->command)) { - if ((adapter->psstate == PS_STATE_SLEEP) || - (adapter->psstate == PS_STATE_PRE_SLEEP)) { + if (is_command_allowed_in_ps(le16_to_cpu(cmd->command))) { + if ((priv->psstate == PS_STATE_SLEEP) || + (priv->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n", - le16_to_cpu(cmdptr->command), - adapter->psstate); + le16_to_cpu(cmd->command), + priv->psstate); ret = -1; goto done; } lbs_deb_host("EXEC_NEXT_CMD: OK to send command " - "0x%04x in psstate %d\n", - le16_to_cpu(cmdptr->command), - adapter->psstate); - } else if (adapter->psstate != PS_STATE_FULL_POWER) { + "0x%04x in psstate %d\n", + le16_to_cpu(cmd->command), priv->psstate); + } else if (priv->psstate != PS_STATE_FULL_POWER) { /* * 1. Non-PS command: * Queue it. set needtowakeup to TRUE if current state - * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS. + * is SLEEP, otherwise call lbs_ps_wakeup to send Exit_PS. * 2. PS command but not Exit_PS: * Ignore it. * 3. PS command Exit_PS: @@ -1691,18 +1792,17 @@ int libertas_execute_next_command(wlan_private * priv) * otherwise send this command down to firmware * immediately. */ - if (cmdptr->command != - cpu_to_le16(CMD_802_11_PS_MODE)) { + if (cmd->command != cpu_to_le16(CMD_802_11_PS_MODE)) { /* Prepare to send Exit PS, * this non PS command will be sent later */ - if ((adapter->psstate == PS_STATE_SLEEP) - || (adapter->psstate == PS_STATE_PRE_SLEEP) + if ((priv->psstate == PS_STATE_SLEEP) + || (priv->psstate == PS_STATE_PRE_SLEEP) ) { /* w/ new scheme, it will not reach here. since it is blocked in main_thread. */ - adapter->needtowakeup = 1; + priv->needtowakeup = 1; } else - libertas_ps_wakeup(priv, 0); + lbs_ps_wakeup(priv, 0); ret = 0; goto done; @@ -1711,8 +1811,7 @@ int libertas_execute_next_command(wlan_private * priv) * PS command. Ignore it if it is not Exit_PS. * otherwise send it down immediately. */ - struct cmd_ds_802_11_ps_mode *psm = - &cmdptr->params.psmode; + struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1]; lbs_deb_host( "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n", @@ -1721,20 +1820,24 @@ int libertas_execute_next_command(wlan_private * priv) cpu_to_le16(CMD_SUBCMD_EXIT_PS)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n"); - list_del((struct list_head *)cmdnode); - libertas_cleanup_and_insert_cmd(priv, cmdnode); + list_del(&cmdnode->list); + spin_lock_irqsave(&priv->driver_lock, flags); + lbs_complete_command(priv, cmdnode, 0); + spin_unlock_irqrestore(&priv->driver_lock, flags); ret = 0; goto done; } - if ((adapter->psstate == PS_STATE_SLEEP) || - (adapter->psstate == PS_STATE_PRE_SLEEP)) { + if ((priv->psstate == PS_STATE_SLEEP) || + (priv->psstate == PS_STATE_PRE_SLEEP)) { lbs_deb_host( "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n"); - list_del((struct list_head *)cmdnode); - libertas_cleanup_and_insert_cmd(priv, cmdnode); - adapter->needtowakeup = 1; + list_del(&cmdnode->list); + spin_lock_irqsave(&priv->driver_lock, flags); + lbs_complete_command(priv, cmdnode, 0); + spin_unlock_irqrestore(&priv->driver_lock, flags); + priv->needtowakeup = 1; ret = 0; goto done; @@ -1744,33 +1847,34 @@ int libertas_execute_next_command(wlan_private * priv) "EXEC_NEXT_CMD: sending EXIT_PS\n"); } } - list_del((struct list_head *)cmdnode); + list_del(&cmdnode->list); lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n", - le16_to_cpu(cmdptr->command)); - DownloadcommandToStation(priv, cmdnode); + le16_to_cpu(cmd->command)); + lbs_submit_command(priv, cmdnode); } else { /* * check if in power save mode, if yes, put the device back * to PS mode */ - if ((adapter->psmode != WLAN802_11POWERMODECAM) && - (adapter->psstate == PS_STATE_FULL_POWER) && - (adapter->connect_status == LIBERTAS_CONNECTED)) { - if (adapter->secinfo.WPAenabled || - adapter->secinfo.WPA2enabled) { + if ((priv->psmode != LBS802_11POWERMODECAM) && + (priv->psstate == PS_STATE_FULL_POWER) && + ((priv->connect_status == LBS_CONNECTED) || + (priv->mesh_connect_status == LBS_CONNECTED))) { + if (priv->secinfo.WPAenabled || + priv->secinfo.WPA2enabled) { /* check for valid WPA group keys */ - if (adapter->wpa_mcast_key.len || - adapter->wpa_unicast_key.len) { + if (priv->wpa_mcast_key.len || + priv->wpa_unicast_key.len) { lbs_deb_host( "EXEC_NEXT_CMD: WPA enabled and GTK_SET" " go back to PS_SLEEP"); - libertas_ps_sleep(priv, 0); + lbs_ps_sleep(priv, 0); } } else { lbs_deb_host( "EXEC_NEXT_CMD: cmdpendingq empty, " "go back to PS_SLEEP"); - libertas_ps_sleep(priv, 0); + lbs_ps_sleep(priv, 0); } } } @@ -1781,7 +1885,7 @@ done: return ret; } -void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) +void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str) { union iwreq_data iwrq; u8 buf[50]; @@ -1805,10 +1909,9 @@ void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) lbs_deb_leave(LBS_DEB_WEXT); } -static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) +static int sendconfirmsleep(struct lbs_private *priv, u8 *cmdptr, u16 size) { unsigned long flags; - wlan_adapter *adapter = priv->adapter; int ret = 0; lbs_deb_enter(LBS_DEB_HOST); @@ -1819,26 +1922,25 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size); ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size); - priv->dnld_sent = DNLD_RES_RECEIVED; - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->intcounter || adapter->currenttxskb) + spin_lock_irqsave(&priv->driver_lock, flags); + if (priv->intcounter || priv->currenttxskb) lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n", - adapter->intcounter, adapter->currenttxskb); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + priv->intcounter, priv->currenttxskb); + spin_unlock_irqrestore(&priv->driver_lock, flags); if (ret) { lbs_pr_alert( "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); } else { - spin_lock_irqsave(&adapter->driver_lock, flags); - if (!adapter->intcounter) { - adapter->psstate = PS_STATE_SLEEP; + spin_lock_irqsave(&priv->driver_lock, flags); + if (!priv->intcounter) { + priv->psstate = PS_STATE_SLEEP; } else { lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n", - adapter->intcounter); + priv->intcounter); } - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n"); } @@ -1847,7 +1949,7 @@ static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) return ret; } -void libertas_ps_sleep(wlan_private * priv, int wait_option) +void lbs_ps_sleep(struct lbs_private *priv, int wait_option) { lbs_deb_enter(LBS_DEB_HOST); @@ -1856,7 +1958,7 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option) * Remove this check if it is to be supported in IBSS mode also */ - libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL); lbs_deb_leave(LBS_DEB_HOST); @@ -1865,19 +1967,19 @@ void libertas_ps_sleep(wlan_private * priv, int wait_option) /** * @brief This function sends Exit_PS command to firmware. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param wait_option wait response or not * @return n/a */ -void libertas_ps_wakeup(wlan_private * priv, int wait_option) +void lbs_ps_wakeup(struct lbs_private *priv, int wait_option) { __le32 Localpsmode; lbs_deb_enter(LBS_DEB_HOST); - Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); + Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); - libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE, + lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_SUBCMD_EXIT_PS, wait_option, 0, &Localpsmode); @@ -1888,37 +1990,36 @@ void libertas_ps_wakeup(wlan_private * priv, int wait_option) * @brief This function checks condition and prepares to * send sleep confirm command to firmware if ok. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param psmode Power Saving mode * @return n/a */ -void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) +void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode) { unsigned long flags =0; - wlan_adapter *adapter = priv->adapter; u8 allowed = 1; lbs_deb_enter(LBS_DEB_HOST); if (priv->dnld_sent) { allowed = 0; - lbs_deb_host("dnld_sent was set"); + lbs_deb_host("dnld_sent was set\n"); } - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd) { + spin_lock_irqsave(&priv->driver_lock, flags); + if (priv->cur_cmd) { allowed = 0; - lbs_deb_host("cur_cmd was set"); + lbs_deb_host("cur_cmd was set\n"); } - if (adapter->intcounter > 0) { + if (priv->intcounter > 0) { allowed = 0; - lbs_deb_host("intcounter %d", adapter->intcounter); + lbs_deb_host("intcounter %d\n", priv->intcounter); } - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); if (allowed) { - lbs_deb_host("sending libertas_ps_confirm_sleep\n"); - sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep, + lbs_deb_host("sending lbs_ps_confirm_sleep\n"); + sendconfirmsleep(priv, (u8 *) & priv->lbs_ps_confirm_sleep, sizeof(struct PS_CMD_ConfirmSleep)); } else { lbs_deb_host("sleep confirm has been delayed\n"); @@ -1926,3 +2027,123 @@ void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) lbs_deb_leave(LBS_DEB_HOST); } + + +/** + * @brief Simple callback that copies response back into command + * + * @param priv A pointer to struct lbs_private structure + * @param extra A pointer to the original command structure for which + * 'resp' is a response + * @param resp A pointer to the command response + * + * @return 0 on success, error on failure + */ +int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp) +{ + struct cmd_header *buf = (void *)extra; + uint16_t copy_len; + + lbs_deb_enter(LBS_DEB_CMD); + + copy_len = min(le16_to_cpu(buf->size), le16_to_cpu(resp->size)); + lbs_deb_cmd("Copying back %u bytes; command response was %u bytes, " + "copy back buffer was %u bytes\n", copy_len, + le16_to_cpu(resp->size), le16_to_cpu(buf->size)); + memcpy(buf, resp, copy_len); + + lbs_deb_leave(LBS_DEB_CMD); + return 0; +} +EXPORT_SYMBOL_GPL(lbs_cmd_copyback); + +struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), + unsigned long callback_arg) +{ + struct cmd_ctrl_node *cmdnode; + + lbs_deb_enter(LBS_DEB_HOST); + + if (priv->surpriseremoved) { + lbs_deb_host("PREP_CMD: card removed\n"); + cmdnode = ERR_PTR(-ENOENT); + goto done; + } + + cmdnode = lbs_get_cmd_ctrl_node(priv); + if (cmdnode == NULL) { + lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); + + /* Wake up main thread to execute next command */ + wake_up_interruptible(&priv->waitq); + cmdnode = ERR_PTR(-ENOBUFS); + goto done; + } + + cmdnode->callback = callback; + cmdnode->callback_arg = callback_arg; + + /* Copy the incoming command to the buffer */ + memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size); + + /* Set sequence number, clean result, move to buffer */ + priv->seqnum++; + cmdnode->cmdbuf->command = cpu_to_le16(command); + cmdnode->cmdbuf->size = cpu_to_le16(in_cmd_size); + cmdnode->cmdbuf->seqnum = cpu_to_le16(priv->seqnum); + cmdnode->cmdbuf->result = 0; + + lbs_deb_host("PREP_CMD: command 0x%04x\n", command); + + /* here was the big old switch() statement, which is now obsolete, + * because the caller of lbs_cmd() sets up all of *cmd for us. */ + + cmdnode->cmdwaitqwoken = 0; + lbs_queue_cmd(priv, cmdnode); + wake_up_interruptible(&priv->waitq); + + done: + lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); + return cmdnode; +} + +int __lbs_cmd(struct lbs_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), + unsigned long callback_arg) +{ + struct cmd_ctrl_node *cmdnode; + unsigned long flags; + int ret = 0; + + lbs_deb_enter(LBS_DEB_HOST); + + cmdnode = __lbs_cmd_async(priv, command, in_cmd, in_cmd_size, + callback, callback_arg); + if (IS_ERR(cmdnode)) { + ret = PTR_ERR(cmdnode); + goto done; + } + + might_sleep(); + wait_event_interruptible(cmdnode->cmdwait_q, cmdnode->cmdwaitqwoken); + + spin_lock_irqsave(&priv->driver_lock, flags); + ret = cmdnode->result; + if (ret) + lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n", + command, ret); + + __lbs_cleanup_and_insert_cmd(priv, cmdnode); + spin_unlock_irqrestore(&priv->driver_lock, flags); + +done: + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(__lbs_cmd); + + diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h new file mode 100644 index 000000000000..b9ab85cc7913 --- /dev/null +++ b/drivers/net/wireless/libertas/cmd.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2007, Red Hat, Inc. */ + +#ifndef _LBS_CMD_H_ +#define _LBS_CMD_H_ + +#include "hostcmd.h" +#include "dev.h" + +/* lbs_cmd() infers the size of the buffer to copy data back into, from + the size of the target of the pointer. Since the command to be sent + may often be smaller, that size is set in cmd->size by the caller.*/ +#define lbs_cmd(priv, cmdnr, cmd, cb, cb_arg) ({ \ + uint16_t __sz = le16_to_cpu((cmd)->hdr.size); \ + (cmd)->hdr.size = cpu_to_le16(sizeof(*(cmd))); \ + __lbs_cmd(priv, cmdnr, &(cmd)->hdr, __sz, cb, cb_arg); \ +}) + +#define lbs_cmd_with_response(priv, cmdnr, cmd) \ + lbs_cmd(priv, cmdnr, cmd, lbs_cmd_copyback, (unsigned long) (cmd)) + +/* __lbs_cmd() will free the cmdnode and return success/failure. + __lbs_cmd_async() requires that the callback free the cmdnode */ +struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), + unsigned long callback_arg); +int __lbs_cmd(struct lbs_private *priv, uint16_t command, + struct cmd_header *in_cmd, int in_cmd_size, + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *), + unsigned long callback_arg); + +int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra, + struct cmd_header *resp); + +int lbs_update_hw_spec(struct lbs_private *priv); + +int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action, + struct cmd_ds_mesh_access *cmd); + +int lbs_get_data_rate(struct lbs_private *priv); +int lbs_set_data_rate(struct lbs_private *priv, u8 rate); + +int lbs_get_channel(struct lbs_private *priv); +int lbs_set_channel(struct lbs_private *priv, u8 channel); + +int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); + +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); +int lbs_suspend(struct lbs_private *priv); +int lbs_resume(struct lbs_private *priv); + +int lbs_cmd_802_11_inactivity_timeout(struct lbs_private *priv, + uint16_t cmd_action, uint16_t *timeout); +int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action, + struct sleep_params *sp); +int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action, + struct assoc_request *assoc); +int lbs_cmd_802_11_enable_rsn(struct lbs_private *priv, uint16_t cmd_action, + uint16_t *enable); + +#endif /* _LBS_CMD_H */ diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 8f90892ea22e..159216a91903 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -20,18 +20,17 @@ * reports disconnect to upper layer, clean tx/rx packets, * reset link state etc. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return n/a */ -void libertas_mac_event_disconnected(wlan_private * priv) +void lbs_mac_event_disconnected(struct lbs_private *priv) { - wlan_adapter *adapter = priv->adapter; union iwreq_data wrqu; - if (adapter->connect_status != LIBERTAS_CONNECTED) + if (priv->connect_status != LBS_CONNECTED) return; - lbs_deb_enter(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_ASSOC); memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; @@ -44,40 +43,36 @@ void libertas_mac_event_disconnected(wlan_private * priv) msleep_interruptible(1000); wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - /* Free Tx and Rx packets */ - kfree_skb(priv->adapter->currenttxskb); - priv->adapter->currenttxskb = NULL; - /* report disconnect to upper layer */ netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); + /* Free Tx and Rx packets */ + kfree_skb(priv->currenttxskb); + priv->currenttxskb = NULL; + priv->tx_pending_len = 0; + /* reset SNR/NF/RSSI values */ - memset(adapter->SNR, 0x00, sizeof(adapter->SNR)); - memset(adapter->NF, 0x00, sizeof(adapter->NF)); - memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI)); - memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); - memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); - adapter->nextSNRNF = 0; - adapter->numSNRNF = 0; - lbs_deb_cmd("current SSID '%s', length %u\n", - escape_essid(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len), - adapter->curbssparams.ssid_len); - - adapter->connect_status = LIBERTAS_DISCONNECTED; + memset(priv->SNR, 0x00, sizeof(priv->SNR)); + memset(priv->NF, 0x00, sizeof(priv->NF)); + memset(priv->RSSI, 0x00, sizeof(priv->RSSI)); + memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); + memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); + priv->nextSNRNF = 0; + priv->numSNRNF = 0; + priv->connect_status = LBS_DISCONNECTED; /* Clear out associated SSID and BSSID since connection is * no longer valid. */ - memset(&adapter->curbssparams.bssid, 0, ETH_ALEN); - memset(&adapter->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE); - adapter->curbssparams.ssid_len = 0; + memset(&priv->curbssparams.bssid, 0, ETH_ALEN); + memset(&priv->curbssparams.ssid, 0, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = 0; - if (adapter->psstate != PS_STATE_FULL_POWER) { + if (priv->psstate != PS_STATE_FULL_POWER) { /* make firmware to exit PS mode */ lbs_deb_cmd("disconnected, so exit PS mode\n"); - libertas_ps_wakeup(priv, 0); + lbs_ps_wakeup(priv, 0); } lbs_deb_leave(LBS_DEB_CMD); } @@ -85,11 +80,11 @@ void libertas_mac_event_disconnected(wlan_private * priv) /** * @brief This function handles MIC failure event. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @para event the event id * @return n/a */ -static void handle_mic_failureevent(wlan_private * priv, u32 event) +static void handle_mic_failureevent(struct lbs_private *priv, u32 event) { char buf[50]; @@ -104,15 +99,14 @@ static void handle_mic_failureevent(wlan_private * priv, u32 event) strcat(buf, "multicast "); } - libertas_send_iwevcustom_event(priv, buf); + lbs_send_iwevcustom_event(priv, buf); lbs_deb_leave(LBS_DEB_CMD); } -static int wlan_ret_reg_access(wlan_private * priv, +static int lbs_ret_reg_access(struct lbs_private *priv, u16 type, struct cmd_ds_command *resp) { int ret = 0; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); @@ -121,8 +115,8 @@ static int wlan_ret_reg_access(wlan_private * priv, { struct cmd_ds_mac_reg_access *reg = &resp->params.macreg; - adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); - adapter->offsetvalue.value = le32_to_cpu(reg->value); + priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); + priv->offsetvalue.value = le32_to_cpu(reg->value); break; } @@ -130,8 +124,8 @@ static int wlan_ret_reg_access(wlan_private * priv, { struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg; - adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); - adapter->offsetvalue.value = reg->value; + priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); + priv->offsetvalue.value = reg->value; break; } @@ -139,8 +133,8 @@ static int wlan_ret_reg_access(wlan_private * priv, { struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg; - adapter->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); - adapter->offsetvalue.value = reg->value; + priv->offsetvalue.offset = (u32)le16_to_cpu(reg->offset); + priv->offsetvalue.value = reg->value; break; } @@ -152,112 +146,23 @@ static int wlan_ret_reg_access(wlan_private * priv, return ret; } -static int wlan_ret_get_hw_spec(wlan_private * priv, - struct cmd_ds_command *resp) -{ - u32 i; - struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; - wlan_adapter *adapter = priv->adapter; - int ret = 0; - DECLARE_MAC_BUF(mac); - - lbs_deb_enter(LBS_DEB_CMD); - - adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo); - - memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4); - - lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n", - adapter->fwreleasenumber[2], adapter->fwreleasenumber[1], - adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]); - lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n", - print_mac(mac, hwspec->permanentaddr)); - lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n", - hwspec->hwifversion, hwspec->version); - - /* Clamp region code to 8-bit since FW spec indicates that it should - * only ever be 8-bit, even though the field size is 16-bit. Some firmware - * returns non-zero high 8 bits here. - */ - adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF; - - for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { - /* use the region code to search for the index */ - if (adapter->regioncode == libertas_region_code_to_index[i]) { - break; - } - } - - /* if it's unidentified region code, use the default (USA) */ - if (i >= MRVDRV_MAX_REGION_CODE) { - adapter->regioncode = 0x10; - lbs_pr_info("unidentified region code; using the default (USA)\n"); - } - - if (adapter->current_addr[0] == 0xff) - memmove(adapter->current_addr, hwspec->permanentaddr, ETH_ALEN); - - memcpy(priv->dev->dev_addr, adapter->current_addr, ETH_ALEN); - if (priv->mesh_dev) - memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); - - if (libertas_set_regiontable(priv, adapter->regioncode, 0)) { - ret = -1; - goto done; - } - - if (libertas_set_universaltable(priv, 0)) { - ret = -1; - goto done; - } - -done: - lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret); - return ret; -} - -static int wlan_ret_802_11_sleep_params(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_CMD); - - lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x " - "extsleepclk 0x%x\n", le16_to_cpu(sp->error), - le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime), - sp->calcontrol, sp->externalsleepclk); - - adapter->sp.sp_error = le16_to_cpu(sp->error); - adapter->sp.sp_offset = le16_to_cpu(sp->offset); - adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime); - adapter->sp.sp_calcontrol = sp->calcontrol; - adapter->sp.sp_extsleepclk = sp->externalsleepclk; - adapter->sp.sp_reserved = le16_to_cpu(sp->reserved); - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - -static int wlan_ret_802_11_stat(wlan_private * priv, +static int lbs_ret_802_11_stat(struct lbs_private *priv, struct cmd_ds_command *resp) { lbs_deb_enter(LBS_DEB_CMD); -/* currently adapter->wlan802_11Stat is unused +/* currently priv->wlan802_11Stat is unused struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; - wlan_adapter *adapter = priv->adapter; // TODO Convert it to Big endian befor copy - memcpy(&adapter->wlan802_11Stat, + memcpy(&priv->wlan802_11Stat, p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); */ lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_ret_802_11_snmp_mib(wlan_private * priv, +static int lbs_ret_802_11_snmp_mib(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; @@ -273,22 +178,22 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv, if (querytype == CMD_ACT_GET) { switch (oid) { case FRAGTHRESH_I: - priv->adapter->fragthsd = + priv->fragthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: frag threshold %u\n", - priv->adapter->fragthsd); + priv->fragthsd); break; case RTSTHRESH_I: - priv->adapter->rtsthsd = + priv->rtsthsd = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: rts threshold %u\n", - priv->adapter->rtsthsd); + priv->rtsthsd); break; case SHORT_RETRYLIM_I: - priv->adapter->txretrycount = + priv->txretrycount = le16_to_cpu(*((__le16 *)(smib->value))); lbs_deb_cmd("SNMP_RESP: tx retry count %u\n", - priv->adapter->rtsthsd); + priv->rtsthsd); break; default: break; @@ -299,12 +204,11 @@ static int wlan_ret_802_11_snmp_mib(wlan_private * priv, return 0; } -static int wlan_ret_802_11_key_material(wlan_private * priv, +static int lbs_ret_802_11_key_material(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_key_material *pkeymaterial = &resp->params.keymaterial; - wlan_adapter *adapter = priv->adapter; u16 action = le16_to_cpu(pkeymaterial->action); lbs_deb_enter(LBS_DEB_CMD); @@ -332,9 +236,9 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, break; if (key_flags & KEY_INFO_WPA_UNICAST) - pkey = &adapter->wpa_unicast_key; + pkey = &priv->wpa_unicast_key; else if (key_flags & KEY_INFO_WPA_MCAST) - pkey = &adapter->wpa_mcast_key; + pkey = &priv->wpa_mcast_key; else break; @@ -355,134 +259,85 @@ static int wlan_ret_802_11_key_material(wlan_private * priv, return 0; } -static int wlan_ret_802_11_mac_address(wlan_private * priv, +static int lbs_ret_802_11_mac_address(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); - memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN); + memcpy(priv->current_addr, macadd->macadd, ETH_ALEN); lbs_deb_enter(LBS_DEB_CMD); return 0; } -static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, +static int lbs_ret_802_11_rf_tx_power(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); - adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); + priv->txpowerlevel = le16_to_cpu(rtp->currentlevel); - lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel); + lbs_deb_cmd("TX power currently %d\n", priv->txpowerlevel); lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, +static int lbs_ret_802_11_rate_adapt_rateset(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_rate_adapt_rateset *rates = &resp->params.rateset; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); if (rates->action == CMD_ACT_GET) { - adapter->enablehwauto = le16_to_cpu(rates->enablehwauto); - adapter->ratebitmap = le16_to_cpu(rates->bitmap); + priv->enablehwauto = le16_to_cpu(rates->enablehwauto); + priv->ratebitmap = le16_to_cpu(rates->bitmap); } lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_ret_802_11_data_rate(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_CMD); - - lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate, - sizeof(struct cmd_ds_802_11_data_rate)); - - /* FIXME: get actual rates FW can do if this command actually returns - * all data rates supported. - */ - adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]); - lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate); - - lbs_deb_leave(LBS_DEB_CMD); - return 0; -} - -static int wlan_ret_802_11_rf_channel(wlan_private * priv, - struct cmd_ds_command *resp) -{ - struct cmd_ds_802_11_rf_channel *rfchannel = &resp->params.rfchannel; - wlan_adapter *adapter = priv->adapter; - u16 action = le16_to_cpu(rfchannel->action); - u16 newchannel = le16_to_cpu(rfchannel->currentchannel); - - lbs_deb_enter(LBS_DEB_CMD); - - if (action == CMD_OPT_802_11_RF_CHANNEL_GET - && adapter->curbssparams.channel != newchannel) { - lbs_deb_cmd("channel switch from %d to %d\n", - adapter->curbssparams.channel, newchannel); - - /* Update the channel again */ - adapter->curbssparams.channel = newchannel; - } - - lbs_deb_enter(LBS_DEB_CMD); - return 0; -} - -static int wlan_ret_802_11_rssi(wlan_private * priv, +static int lbs_ret_802_11_rssi(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); /* store the non average value */ - adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); - adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); + priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); + priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor); - adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); - adapter->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); + priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); + priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor); - adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = - CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], - adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + priv->RSSI[TYPE_BEACON][TYPE_NOAVG] = + CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], + priv->NF[TYPE_BEACON][TYPE_NOAVG]); - adapter->RSSI[TYPE_BEACON][TYPE_AVG] = - CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); + priv->RSSI[TYPE_BEACON][TYPE_AVG] = + CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, + priv->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); lbs_deb_cmd("RSSI: beacon %d, avg %d\n", - adapter->RSSI[TYPE_BEACON][TYPE_NOAVG], - adapter->RSSI[TYPE_BEACON][TYPE_AVG]); + priv->RSSI[TYPE_BEACON][TYPE_NOAVG], + priv->RSSI[TYPE_BEACON][TYPE_AVG]); lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int wlan_ret_802_11_eeprom_access(wlan_private * priv, +static int lbs_ret_802_11_eeprom_access(struct lbs_private *priv, struct cmd_ds_command *resp) { - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_regrdwr *pbuf; - pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; + struct lbs_ioctl_regrdwr *pbuf; + pbuf = (struct lbs_ioctl_regrdwr *) priv->prdeeprom; lbs_deb_enter_args(LBS_DEB_CMD, "len %d", le16_to_cpu(resp->params.rdeeprom.bytecount)); @@ -503,46 +358,45 @@ static int wlan_ret_802_11_eeprom_access(wlan_private * priv, return 0; } -static int wlan_ret_get_log(wlan_private * priv, +static int lbs_ret_get_log(struct lbs_private *priv, struct cmd_ds_command *resp) { struct cmd_ds_802_11_get_log *logmessage = &resp->params.glog; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_CMD); /* Stored little-endian */ - memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log)); + memcpy(&priv->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log)); lbs_deb_leave(LBS_DEB_CMD); return 0; } -static int libertas_ret_802_11_enable_rsn(wlan_private * priv, - struct cmd_ds_command *resp) +static int lbs_ret_802_11_bcn_ctrl(struct lbs_private * priv, + struct cmd_ds_command *resp) { - struct cmd_ds_802_11_enable_rsn *enable_rsn = &resp->params.enbrsn; - wlan_adapter *adapter = priv->adapter; - u32 * pdata_buf = adapter->cur_cmd->pdata_buf; + struct cmd_ds_802_11_beacon_control *bcn_ctrl = + &resp->params.bcn_ctrl; lbs_deb_enter(LBS_DEB_CMD); - if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) { - if (pdata_buf) - *pdata_buf = (u32) le16_to_cpu(enable_rsn->enable); + if (bcn_ctrl->action == CMD_ACT_GET) { + priv->beacon_enable = (u8) le16_to_cpu(bcn_ctrl->beacon_enable); + priv->beacon_period = le16_to_cpu(bcn_ctrl->beacon_period); } - lbs_deb_leave(LBS_DEB_CMD); + lbs_deb_enter(LBS_DEB_CMD); return 0; } -static inline int handle_cmd_response(u16 respcmd, - struct cmd_ds_command *resp, - wlan_private *priv) +static inline int handle_cmd_response(struct lbs_private *priv, + unsigned long dummy, + struct cmd_header *cmd_response) { + struct cmd_ds_command *resp = (struct cmd_ds_command *) cmd_response; int ret = 0; unsigned long flags; - wlan_adapter *adapter = priv->adapter; + uint16_t respcmd = le16_to_cpu(resp->command); lbs_deb_enter(LBS_DEB_HOST); @@ -550,218 +404,213 @@ static inline int handle_cmd_response(u16 respcmd, case CMD_RET(CMD_MAC_REG_ACCESS): case CMD_RET(CMD_BBP_REG_ACCESS): case CMD_RET(CMD_RF_REG_ACCESS): - ret = wlan_ret_reg_access(priv, respcmd, resp); - break; - - case CMD_RET(CMD_GET_HW_SPEC): - ret = wlan_ret_get_hw_spec(priv, resp); + ret = lbs_ret_reg_access(priv, respcmd, resp); break; case CMD_RET(CMD_802_11_SCAN): - ret = libertas_ret_80211_scan(priv, resp); + ret = lbs_ret_80211_scan(priv, resp); break; case CMD_RET(CMD_802_11_GET_LOG): - ret = wlan_ret_get_log(priv, resp); + ret = lbs_ret_get_log(priv, resp); break; case CMD_RET_802_11_ASSOCIATE: case CMD_RET(CMD_802_11_ASSOCIATE): case CMD_RET(CMD_802_11_REASSOCIATE): - ret = libertas_ret_80211_associate(priv, resp); + ret = lbs_ret_80211_associate(priv, resp); break; case CMD_RET(CMD_802_11_DISASSOCIATE): case CMD_RET(CMD_802_11_DEAUTHENTICATE): - ret = libertas_ret_80211_disassociate(priv, resp); + ret = lbs_ret_80211_disassociate(priv, resp); break; case CMD_RET(CMD_802_11_AD_HOC_START): case CMD_RET(CMD_802_11_AD_HOC_JOIN): - ret = libertas_ret_80211_ad_hoc_start(priv, resp); + ret = lbs_ret_80211_ad_hoc_start(priv, resp); break; case CMD_RET(CMD_802_11_GET_STAT): - ret = wlan_ret_802_11_stat(priv, resp); + ret = lbs_ret_802_11_stat(priv, resp); break; case CMD_RET(CMD_802_11_SNMP_MIB): - ret = wlan_ret_802_11_snmp_mib(priv, resp); + ret = lbs_ret_802_11_snmp_mib(priv, resp); break; case CMD_RET(CMD_802_11_RF_TX_POWER): - ret = wlan_ret_802_11_rf_tx_power(priv, resp); + ret = lbs_ret_802_11_rf_tx_power(priv, resp); break; case CMD_RET(CMD_802_11_SET_AFC): case CMD_RET(CMD_802_11_GET_AFC): - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc, + spin_lock_irqsave(&priv->driver_lock, flags); + memmove((void *)priv->cur_cmd->callback_arg, &resp->params.afc, sizeof(struct cmd_ds_802_11_afc)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; case CMD_RET(CMD_MAC_MULTICAST_ADR): case CMD_RET(CMD_MAC_CONTROL): - case CMD_RET(CMD_802_11_SET_WEP): case CMD_RET(CMD_802_11_RESET): case CMD_RET(CMD_802_11_AUTHENTICATE): - case CMD_RET(CMD_802_11_RADIO_CONTROL): case CMD_RET(CMD_802_11_BEACON_STOP): break; - case CMD_RET(CMD_802_11_ENABLE_RSN): - ret = libertas_ret_802_11_enable_rsn(priv, resp); - break; - - case CMD_RET(CMD_802_11_DATA_RATE): - ret = wlan_ret_802_11_data_rate(priv, resp); - break; case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET): - ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); - break; - case CMD_RET(CMD_802_11_RF_CHANNEL): - ret = wlan_ret_802_11_rf_channel(priv, resp); + ret = lbs_ret_802_11_rate_adapt_rateset(priv, resp); break; case CMD_RET(CMD_802_11_RSSI): - ret = wlan_ret_802_11_rssi(priv, resp); + ret = lbs_ret_802_11_rssi(priv, resp); break; case CMD_RET(CMD_802_11_MAC_ADDRESS): - ret = wlan_ret_802_11_mac_address(priv, resp); + ret = lbs_ret_802_11_mac_address(priv, resp); break; case CMD_RET(CMD_802_11_AD_HOC_STOP): - ret = libertas_ret_80211_ad_hoc_stop(priv, resp); + ret = lbs_ret_80211_ad_hoc_stop(priv, resp); break; case CMD_RET(CMD_802_11_KEY_MATERIAL): - ret = wlan_ret_802_11_key_material(priv, resp); + ret = lbs_ret_802_11_key_material(priv, resp); break; case CMD_RET(CMD_802_11_EEPROM_ACCESS): - ret = wlan_ret_802_11_eeprom_access(priv, resp); + ret = lbs_ret_802_11_eeprom_access(priv, resp); break; case CMD_RET(CMD_802_11D_DOMAIN_INFO): - ret = libertas_ret_802_11d_domain_info(priv, resp); - break; - - case CMD_RET(CMD_802_11_SLEEP_PARAMS): - ret = wlan_ret_802_11_sleep_params(priv, resp); - break; - case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT): - spin_lock_irqsave(&adapter->driver_lock, flags); - *((u16 *) adapter->cur_cmd->pdata_buf) = - le16_to_cpu(resp->params.inactivity_timeout.timeout); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + ret = lbs_ret_802_11d_domain_info(priv, resp); break; case CMD_RET(CMD_802_11_TPC_CFG): - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg, + spin_lock_irqsave(&priv->driver_lock, flags); + memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg, sizeof(struct cmd_ds_802_11_tpc_cfg)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; case CMD_RET(CMD_802_11_LED_GPIO_CTRL): - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio, + spin_lock_irqsave(&priv->driver_lock, flags); + memmove((void *)priv->cur_cmd->callback_arg, &resp->params.ledgpio, sizeof(struct cmd_ds_802_11_led_ctrl)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; + case CMD_RET(CMD_802_11_PWR_CFG): - spin_lock_irqsave(&adapter->driver_lock, flags); - memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg, + spin_lock_irqsave(&priv->driver_lock, flags); + memmove((void *)priv->cur_cmd->callback_arg, &resp->params.pwrcfg, sizeof(struct cmd_ds_802_11_pwr_cfg)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; case CMD_RET(CMD_GET_TSF): - spin_lock_irqsave(&adapter->driver_lock, flags); - memcpy(priv->adapter->cur_cmd->pdata_buf, + spin_lock_irqsave(&priv->driver_lock, flags); + memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.gettsf.tsfvalue, sizeof(u64)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; case CMD_RET(CMD_BT_ACCESS): - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd->pdata_buf) - memcpy(adapter->cur_cmd->pdata_buf, + spin_lock_irqsave(&priv->driver_lock, flags); + if (priv->cur_cmd->callback_arg) + memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.bt.addr1, 2 * ETH_ALEN); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; case CMD_RET(CMD_FWT_ACCESS): - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd->pdata_buf) - memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt, + spin_lock_irqsave(&priv->driver_lock, flags); + if (priv->cur_cmd->callback_arg) + memcpy((void *)priv->cur_cmd->callback_arg, &resp->params.fwt, sizeof(resp->params.fwt)); - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); break; - case CMD_RET(CMD_MESH_ACCESS): - if (adapter->cur_cmd->pdata_buf) - memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh, - sizeof(resp->params.mesh)); + case CMD_RET(CMD_802_11_BEACON_CTRL): + ret = lbs_ret_802_11_bcn_ctrl(priv, resp); break; + default: lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", - resp->command); + le16_to_cpu(resp->command)); break; } lbs_deb_leave(LBS_DEB_HOST); return ret; } -int libertas_process_rx_command(wlan_private * priv) +int lbs_process_rx_command(struct lbs_private *priv) { - u16 respcmd; - struct cmd_ds_command *resp; - wlan_adapter *adapter = priv->adapter; + uint16_t respcmd, curcmd; + struct cmd_header *resp; int ret = 0; - ulong flags; - u16 result; + unsigned long flags; + uint16_t result; lbs_deb_enter(LBS_DEB_HOST); - /* Now we got response from FW, cancel the command timer */ - del_timer(&adapter->command_timer); - - mutex_lock(&adapter->lock); - spin_lock_irqsave(&adapter->driver_lock, flags); + mutex_lock(&priv->lock); + spin_lock_irqsave(&priv->driver_lock, flags); - if (!adapter->cur_cmd) { + if (!priv->cur_cmd) { lbs_deb_host("CMD_RESP: cur_cmd is NULL\n"); ret = -1; - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); goto done; } - resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); + + resp = (void *)priv->upld_buf; + + curcmd = le16_to_cpu(resp->command); respcmd = le16_to_cpu(resp->command); result = le16_to_cpu(resp->result); - lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", - respcmd, priv->upld_len, jiffies); - lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr, - priv->upld_len); - - if (!(respcmd & 0x8000)) { - lbs_deb_host("invalid response!\n"); - adapter->cur_cmd_retcode = -1; - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); + lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n", + respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies); + lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); + + if (resp->seqnum != resp->seqnum) { + lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", + le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum)); + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + if (respcmd != CMD_RET(curcmd) && + respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) { + lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); + spin_unlock_irqrestore(&priv->driver_lock, flags); + ret = -1; + goto done; + } + + if (resp->result == cpu_to_le16(0x0004)) { + /* 0x0004 means -EAGAIN. Drop the response, let it time out + and be resubmitted */ + lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n", + le16_to_cpu(resp->command)); + spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } + /* Now we got response from FW, cancel the command timer */ + del_timer(&priv->command_timer); + priv->cmd_timed_out = 0; + if (priv->nr_retries) { + lbs_pr_info("Received result %x to command %x after %d retries\n", + result, curcmd, priv->nr_retries); + priv->nr_retries = 0; + } + /* Store the response code to cur_cmd_retcode. */ - adapter->cur_cmd_retcode = result;; + priv->cur_cmd_retcode = result; if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) { - struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode; + struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1]; u16 action = le16_to_cpu(psmode->action); lbs_deb_host( @@ -774,54 +623,45 @@ int libertas_process_rx_command(wlan_private * priv) /* * We should not re-try enter-ps command in * ad-hoc mode. It takes place in - * libertas_execute_next_command(). + * lbs_execute_next_command(). */ - if (adapter->mode == IW_MODE_ADHOC && + if (priv->mode == IW_MODE_ADHOC && action == CMD_SUBCMD_ENTER_PS) - adapter->psmode = WLAN802_11POWERMODECAM; + priv->psmode = LBS802_11POWERMODECAM; } else if (action == CMD_SUBCMD_ENTER_PS) { - adapter->needtowakeup = 0; - adapter->psstate = PS_STATE_AWAKE; + priv->needtowakeup = 0; + priv->psstate = PS_STATE_AWAKE; lbs_deb_host("CMD_RESP: ENTER_PS command response\n"); - if (adapter->connect_status != LIBERTAS_CONNECTED) { + if (priv->connect_status != LBS_CONNECTED) { /* * When Deauth Event received before Enter_PS command * response, We need to wake up the firmware. */ lbs_deb_host( - "disconnected, invoking libertas_ps_wakeup\n"); + "disconnected, invoking lbs_ps_wakeup\n"); - spin_unlock_irqrestore(&adapter->driver_lock, flags); - mutex_unlock(&adapter->lock); - libertas_ps_wakeup(priv, 0); - mutex_lock(&adapter->lock); - spin_lock_irqsave(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); + mutex_unlock(&priv->lock); + lbs_ps_wakeup(priv, 0); + mutex_lock(&priv->lock); + spin_lock_irqsave(&priv->driver_lock, flags); } } else if (action == CMD_SUBCMD_EXIT_PS) { - adapter->needtowakeup = 0; - adapter->psstate = PS_STATE_FULL_POWER; + priv->needtowakeup = 0; + priv->psstate = PS_STATE_FULL_POWER; lbs_deb_host("CMD_RESP: EXIT_PS command response\n"); } else { lbs_deb_host("CMD_RESP: PS action 0x%X\n", action); } - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); + lbs_complete_command(priv, priv->cur_cmd, result); + spin_unlock_irqrestore(&priv->driver_lock, flags); ret = 0; goto done; } - if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { - /* Copy the response back to response buffer */ - memcpy(adapter->cur_cmd->pdata_buf, resp, - le16_to_cpu(resp->size)); - adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; - } - /* If the command is not successful, cleanup and return failure */ if ((result != 0 || !(respcmd & 0x8000))) { lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n", @@ -836,106 +676,132 @@ int libertas_process_rx_command(wlan_private * priv) break; } - - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); + lbs_complete_command(priv, priv->cur_cmd, result); + spin_unlock_irqrestore(&priv->driver_lock, flags); ret = -1; goto done; } - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); - ret = handle_cmd_response(respcmd, resp, priv); + if (priv->cur_cmd && priv->cur_cmd->callback) { + ret = priv->cur_cmd->callback(priv, priv->cur_cmd->callback_arg, + resp); + } else + ret = handle_cmd_response(priv, 0, resp); - spin_lock_irqsave(&adapter->driver_lock, flags); - if (adapter->cur_cmd) { + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->cur_cmd) { /* Clean up and Put current command back to cmdfreeq */ - __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); - adapter->nr_cmd_pending--; - WARN_ON(adapter->nr_cmd_pending > 128); - adapter->cur_cmd = NULL; + lbs_complete_command(priv, priv->cur_cmd, result); } - spin_unlock_irqrestore(&adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); done: - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); return ret; } -int libertas_process_event(wlan_private * priv) +static int lbs_send_confirmwake(struct lbs_private *priv) +{ + struct cmd_header *cmd = &priv->lbs_ps_confirm_wake; + int ret = 0; + + lbs_deb_enter(LBS_DEB_HOST); + + cmd->command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM); + cmd->size = cpu_to_le16(sizeof(*cmd)); + cmd->seqnum = cpu_to_le16(++priv->seqnum); + cmd->result = 0; + + lbs_deb_host("SEND_WAKEC_CMD: before download\n"); + + lbs_deb_hex(LBS_DEB_HOST, "wake confirm command", (void *)cmd, sizeof(*cmd)); + + ret = priv->hw_host_to_card(priv, MVMS_CMD, (void *)cmd, sizeof(*cmd)); + if (ret) + lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n"); + + lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret); + return ret; +} + +int lbs_process_event(struct lbs_private *priv) { int ret = 0; - wlan_adapter *adapter = priv->adapter; u32 eventcause; lbs_deb_enter(LBS_DEB_CMD); - spin_lock_irq(&adapter->driver_lock); - eventcause = adapter->eventcause; - spin_unlock_irq(&adapter->driver_lock); + spin_lock_irq(&priv->driver_lock); + eventcause = priv->eventcause >> SBI_EVENT_CAUSE_SHIFT; + spin_unlock_irq(&priv->driver_lock); - lbs_deb_cmd("event cause 0x%x\n", eventcause); + lbs_deb_cmd("event cause %d\n", eventcause); - switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { + switch (eventcause) { case MACREG_INT_CODE_LINK_SENSED: lbs_deb_cmd("EVENT: MACREG_INT_CODE_LINK_SENSED\n"); break; case MACREG_INT_CODE_DEAUTHENTICATED: lbs_deb_cmd("EVENT: deauthenticated\n"); - libertas_mac_event_disconnected(priv); + lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_DISASSOCIATED: lbs_deb_cmd("EVENT: disassociated\n"); - libertas_mac_event_disconnected(priv); + lbs_mac_event_disconnected(priv); break; - case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: + case MACREG_INT_CODE_LINK_LOST_NO_SCAN: lbs_deb_cmd("EVENT: link lost\n"); - libertas_mac_event_disconnected(priv); + lbs_mac_event_disconnected(priv); break; case MACREG_INT_CODE_PS_SLEEP: lbs_deb_cmd("EVENT: sleep\n"); /* handle unexpected PS SLEEP event */ - if (adapter->psstate == PS_STATE_FULL_POWER) { + if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n"); break; } - adapter->psstate = PS_STATE_PRE_SLEEP; + priv->psstate = PS_STATE_PRE_SLEEP; - libertas_ps_confirm_sleep(priv, (u16) adapter->psmode); + lbs_ps_confirm_sleep(priv, (u16) priv->psmode); break; + case MACREG_INT_CODE_HOST_AWAKE: + lbs_deb_cmd("EVENT: HOST_AWAKE\n"); + lbs_send_confirmwake(priv); + break; + case MACREG_INT_CODE_PS_AWAKE: lbs_deb_cmd("EVENT: awake\n"); - /* handle unexpected PS AWAKE event */ - if (adapter->psstate == PS_STATE_FULL_POWER) { + if (priv->psstate == PS_STATE_FULL_POWER) { lbs_deb_cmd( "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); break; } - adapter->psstate = PS_STATE_AWAKE; + priv->psstate = PS_STATE_AWAKE; - if (adapter->needtowakeup) { + if (priv->needtowakeup) { /* * wait for the command processing to finish * before resuming sending - * adapter->needtowakeup will be set to FALSE - * in libertas_ps_wakeup() + * priv->needtowakeup will be set to FALSE + * in lbs_ps_wakeup() */ lbs_deb_cmd("waking up ...\n"); - libertas_ps_wakeup(priv, 0); + lbs_ps_wakeup(priv, 0); } break; @@ -979,24 +845,24 @@ int libertas_process_event(wlan_private * priv) break; } lbs_pr_info("EVENT: MESH_AUTO_STARTED\n"); - adapter->connect_status = LIBERTAS_CONNECTED; - if (priv->mesh_open == 1) { - netif_wake_queue(priv->mesh_dev); + priv->mesh_connect_status = LBS_CONNECTED; + if (priv->mesh_open) { netif_carrier_on(priv->mesh_dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->mesh_dev); } - adapter->mode = IW_MODE_ADHOC; + priv->mode = IW_MODE_ADHOC; schedule_work(&priv->sync_channel); break; default: - lbs_pr_alert("EVENT: unknown event id 0x%04x\n", - eventcause >> SBI_EVENT_CAUSE_SHIFT); + lbs_pr_alert("EVENT: unknown event id %d\n", eventcause); break; } - spin_lock_irq(&adapter->driver_lock); - adapter->eventcause = 0; - spin_unlock_irq(&adapter->driver_lock); + spin_lock_irq(&priv->driver_lock); + priv->eventcause = 0; + spin_unlock_irq(&priv->driver_lock); lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret); return ret; diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 0bda0b511910..fd67b770dd78 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -10,15 +10,16 @@ #include "decl.h" #include "host.h" #include "debugfs.h" +#include "cmd.h" -static struct dentry *libertas_dir = NULL; +static struct dentry *lbs_dir; static char *szStates[] = { "Connected", "Disconnected" }; #ifdef PROC_DEBUG -static void libertas_debug_init(wlan_private * priv, struct net_device *dev); +static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev); #endif static int open_file_generic(struct inode *inode, struct file *file) @@ -35,19 +36,19 @@ static ssize_t write_file_dummy(struct file *file, const char __user *buf, static const size_t len = PAGE_SIZE; -static ssize_t libertas_dev_info(struct file *file, char __user *userbuf, +static ssize_t lbs_dev_info(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; size_t pos = 0; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; ssize_t res; pos += snprintf(buf+pos, len-pos, "state = %s\n", - szStates[priv->adapter->connect_status]); + szStates[priv->connect_status]); pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", - (u32) priv->adapter->regioncode); + (u32) priv->regioncode); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); @@ -56,10 +57,10 @@ static ssize_t libertas_dev_info(struct file *file, char __user *userbuf, } -static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, +static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; size_t pos = 0; int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); @@ -70,8 +71,8 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, pos += snprintf(buf+pos, len-pos, "# | ch | rssi | bssid | cap | Qual | SSID \n"); - mutex_lock(&priv->adapter->lock); - list_for_each_entry (iter_bss, &priv->adapter->network_list, list) { + mutex_lock(&priv->lock); + list_for_each_entry (iter_bss, &priv->network_list, list) { u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS); u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); @@ -90,7 +91,7 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, numscansdone++; } - mutex_unlock(&priv->adapter->lock); + mutex_unlock(&priv->lock); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); @@ -98,83 +99,75 @@ static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, return res; } -static ssize_t libertas_sleepparams_write(struct file *file, +static ssize_t lbs_sleepparams_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - ssize_t buf_size, res; + struct lbs_private *priv = file->private_data; + ssize_t buf_size, ret; + struct sleep_params sp; int p1, p2, p3, p4, p5, p6; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; buf_size = min(count, len - 1); if (copy_from_user(buf, user_buf, buf_size)) { - res = -EFAULT; + ret = -EFAULT; goto out_unlock; } - res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); - if (res != 6) { - res = -EFAULT; + ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); + if (ret != 6) { + ret = -EINVAL; goto out_unlock; } - priv->adapter->sp.sp_error = p1; - priv->adapter->sp.sp_offset = p2; - priv->adapter->sp.sp_stabletime = p3; - priv->adapter->sp.sp_calcontrol = p4; - priv->adapter->sp.sp_extsleepclk = p5; - priv->adapter->sp.sp_reserved = p6; - - res = libertas_prepare_and_send_command(priv, - CMD_802_11_SLEEP_PARAMS, - CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, NULL); - - if (!res) - res = count; - else - res = -EINVAL; + sp.sp_error = p1; + sp.sp_offset = p2; + sp.sp_stabletime = p3; + sp.sp_calcontrol = p4; + sp.sp_extsleepclk = p5; + sp.sp_reserved = p6; + + ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp); + if (!ret) + ret = count; + else if (ret > 0) + ret = -EINVAL; out_unlock: free_page(addr); - return res; + return ret; } -static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf, +static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res; + struct lbs_private *priv = file->private_data; + ssize_t ret; size_t pos = 0; + struct sleep_params sp; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; - res = libertas_prepare_and_send_command(priv, - CMD_802_11_SLEEP_PARAMS, - CMD_ACT_GET, - CMD_OPTION_WAITFORRSP, 0, NULL); - if (res) { - res = -EFAULT; + ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); + if (ret) goto out_unlock; - } - pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error, - adapter->sp.sp_offset, adapter->sp.sp_stabletime, - adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk, - adapter->sp.sp_reserved); + pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error, + sp.sp_offset, sp.sp_stabletime, + sp.sp_calcontrol, sp.sp_extsleepclk, + sp.sp_reserved); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); out_unlock: free_page(addr); - return res; + return ret; } -static ssize_t libertas_extscan(struct file *file, const char __user *userbuf, +static ssize_t lbs_extscan(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; union iwreq_data wrqu; unsigned long addr = get_zeroed_page(GFP_KERNEL); @@ -186,7 +179,7 @@ static ssize_t libertas_extscan(struct file *file, const char __user *userbuf, goto out_unlock; } - libertas_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0); + lbs_send_specific_ssid_scan(priv, buf, strlen(buf)-1, 0); memset(&wrqu, 0, sizeof(union iwreq_data)); wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); @@ -196,45 +189,8 @@ out_unlock: return count; } -static int libertas_parse_chan(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur) -{ - char *start, *end, *hold, *str; - int i = 0; - - start = strstr(buf, "chan="); - if (!start) - return -EINVAL; - start += 5; - end = strchr(start, ' '); - if (!end) - end = buf + count; - hold = kzalloc((end - start)+1, GFP_KERNEL); - if (!hold) - return -ENOMEM; - strncpy(hold, start, end - start); - hold[(end-start)+1] = '\0'; - while(hold && (str = strsep(&hold, ","))) { - int chan; - char band, passive = 0; - sscanf(str, "%d%c%c", &chan, &band, &passive); - scan_cfg->chanlist[i].channumber = chan; - scan_cfg->chanlist[i].scantype = passive ? 1 : 0; - if (band == 'b' || band == 'g') - scan_cfg->chanlist[i].radiotype = 0; - else if (band == 'a') - scan_cfg->chanlist[i].radiotype = 1; - - scan_cfg->chanlist[i].scantime = dur; - i++; - } - - kfree(hold); - return i; -} - -static void libertas_parse_bssid(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) +static void lbs_parse_bssid(char *buf, size_t count, + struct lbs_ioctl_user_scan_cfg *scan_cfg) { char *hold; unsigned int mac[ETH_ALEN]; @@ -243,12 +199,13 @@ static void libertas_parse_bssid(char *buf, size_t count, if (!hold) return; hold += 6; - sscanf(hold, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5); + sscanf(hold, "%02x:%02x:%02x:%02x:%02x:%02x", + mac, mac+1, mac+2, mac+3, mac+4, mac+5); memcpy(scan_cfg->bssid, mac, ETH_ALEN); } -static void libertas_parse_ssid(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) +static void lbs_parse_ssid(char *buf, size_t count, + struct lbs_ioctl_user_scan_cfg *scan_cfg) { char *hold, *end; ssize_t size; @@ -267,7 +224,7 @@ static void libertas_parse_ssid(char *buf, size_t count, return; } -static int libertas_parse_clear(char *buf, size_t count, const char *tag) +static int lbs_parse_clear(char *buf, size_t count, const char *tag) { char *hold; int val; @@ -284,8 +241,8 @@ static int libertas_parse_clear(char *buf, size_t count, const char *tag) return val; } -static int libertas_parse_dur(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) +static int lbs_parse_dur(char *buf, size_t count, + struct lbs_ioctl_user_scan_cfg *scan_cfg) { char *hold; int val; @@ -299,25 +256,8 @@ static int libertas_parse_dur(char *buf, size_t count, return val; } -static void libertas_parse_probes(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) -{ - char *hold; - int val; - - hold = strstr(buf, "probes="); - if (!hold) - return; - hold += 7; - sscanf(hold, "%d", &val); - - scan_cfg->numprobes = val; - - return; -} - -static void libertas_parse_type(char *buf, size_t count, - struct wlan_ioctl_user_scan_cfg *scan_cfg) +static void lbs_parse_type(char *buf, size_t count, + struct lbs_ioctl_user_scan_cfg *scan_cfg) { char *hold; int val; @@ -337,1036 +277,324 @@ static void libertas_parse_type(char *buf, size_t count, return; } -static ssize_t libertas_setuserscan(struct file *file, +static ssize_t lbs_setuserscan(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; - struct wlan_ioctl_user_scan_cfg *scan_cfg; + struct lbs_ioctl_user_scan_cfg *scan_cfg; union iwreq_data wrqu; int dur; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; + char *buf = (char *)get_zeroed_page(GFP_KERNEL); - scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL); - if (!scan_cfg) + if (!buf) return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { res = -EFAULT; - goto out_unlock; + goto out_buf; + } + + scan_cfg = kzalloc(sizeof(struct lbs_ioctl_user_scan_cfg), GFP_KERNEL); + if (!scan_cfg) { + res = -ENOMEM; + goto out_buf; } + res = count; + + scan_cfg->bsstype = LBS_SCAN_BSS_TYPE_ANY; - scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY; + dur = lbs_parse_dur(buf, count, scan_cfg); + lbs_parse_bssid(buf, count, scan_cfg); + scan_cfg->clear_bssid = lbs_parse_clear(buf, count, "clear_bssid="); + lbs_parse_ssid(buf, count, scan_cfg); + scan_cfg->clear_ssid = lbs_parse_clear(buf, count, "clear_ssid="); + lbs_parse_type(buf, count, scan_cfg); - dur = libertas_parse_dur(buf, count, scan_cfg); - libertas_parse_chan(buf, count, scan_cfg, dur); - libertas_parse_bssid(buf, count, scan_cfg); - scan_cfg->clear_bssid = libertas_parse_clear(buf, count, "clear_bssid="); - libertas_parse_ssid(buf, count, scan_cfg); - scan_cfg->clear_ssid = libertas_parse_clear(buf, count, "clear_ssid="); - libertas_parse_probes(buf, count, scan_cfg); - libertas_parse_type(buf, count, scan_cfg); + lbs_scan_networks(priv, scan_cfg, 1); + wait_event_interruptible(priv->cmd_pending, + priv->surpriseremoved || !priv->last_scanned_channel); - wlan_scan_networks(priv, scan_cfg, 1); - wait_event_interruptible(priv->adapter->cmd_pending, - !priv->adapter->nr_cmd_pending); + if (priv->surpriseremoved) + goto out_scan_cfg; memset(&wrqu, 0x00, sizeof(union iwreq_data)); wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); -out_unlock: - free_page(addr); + out_scan_cfg: kfree(scan_cfg); - return count; + out_buf: + free_page((unsigned long)buf); + return res; } -static int libertas_event_initcmd(wlan_private *priv, void **response_buf, - struct cmd_ctrl_node **cmdnode, - struct cmd_ds_command **cmd) -{ - u16 wait_option = CMD_OPTION_WAITFORRSP; - - if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) { - lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n"); - return -ENOMEM; - } - if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) { - lbs_deb_debugfs("failed to allocate response buffer!\n"); - return -ENOMEM; - } - libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL); - init_waitqueue_head(&(*cmdnode)->cmdwait_q); - (*cmdnode)->pdata_buf = *response_buf; - (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; - (*cmdnode)->cmdwaitqwoken = 0; - *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; - (*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT); - (*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum); - (*cmd)->result = 0; - return 0; -} -static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) +/* + * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might + * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the + * firmware. Here's an example: + * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00 + * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03 + * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + * + * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length, + * 00 00 are the data bytes of this TLV. For this TLV, their meaning is + * defined in mrvlietypes_thresholds + * + * This function searches in this TLV data chunk for a given TLV type + * and returns a pointer to the first data byte of the TLV, or to NULL + * if the TLV hasn't been found. + */ +static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; + struct mrvlietypesheader *tlv_h; + uint16_t length; ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (void *)(response_buf + S_DS_GEN); - while (cmd_len < le16_to_cpu(pcmdptr->size)) { - struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); - switch (header->type) { - struct mrvlietypes_rssithreshold *Lowrssi; - case __constant_cpu_to_le16(TLV_TYPE_RSSI_LOW): - Lowrssi = (void *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - Lowrssi->rssivalue, - Lowrssi->rssifreq, - (event->events & cpu_to_le16(0x0001))?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } - - kfree(response_buf); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} - -static u16 libertas_get_events_bitmap(wlan_private *priv) -{ - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res; - u16 event_bitmap; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - return res; - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - return 0; - } - - if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - return 0; - } - - event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); - event_bitmap = le16_to_cpu(event->events); - kfree(response_buf); - return event_bitmap; + while (pos < size) { + tlv_h = (struct mrvlietypesheader *) tlv; + if (!tlv_h->len) + return NULL; + if (tlv_h->type == cpu_to_le16(tlv_type)) + return tlv_h; + length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h); + pos += length; + tlv += length; + } + return NULL; } -static ssize_t libertas_lowrssi_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_rssithreshold *rssi_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_SET); - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_rssithreshold)); - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); - rssi_threshold->header.type = cpu_to_le16(0x0104); - rssi_threshold->header.len = cpu_to_le16(2); - rssi_threshold->rssivalue = value; - rssi_threshold->rssifreq = freq; - event_bitmap |= subscribed ? 0x0001 : 0x0; - event->events = cpu_to_le16(event_bitmap); - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, +static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, + struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; + struct cmd_ds_802_11_subscribe_event *subscribed; + struct mrvlietypes_thresholds *got; + struct lbs_private *priv = file->private_data; + ssize_t ret = 0; + size_t pos = 0; + char *buf; + u8 value; + u8 freq; + int events = 0; - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } + buf = (char *)get_zeroed_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; + subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL); + if (!subscribed) { + ret = -ENOMEM; + goto out_page; } - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (void *)(response_buf + S_DS_GEN); - while (cmd_len < le16_to_cpu(pcmdptr->size)) { - struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); - switch (header->type) { - struct mrvlietypes_snrthreshold *LowSnr; - case __constant_cpu_to_le16(TLV_TYPE_SNR_LOW): - LowSnr = (void *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - LowSnr->snrvalue, - LowSnr->snrfreq, - (event->events & cpu_to_le16(0x0002))?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } + subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed)); + subscribed->action = cpu_to_le16(CMD_ACT_GET); - kfree(response_buf); + ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed); + if (ret) + goto out_cmd; - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} + got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv)); + if (got) { + value = got->value; + freq = got->freq; + events = le16_to_cpu(subscribed->events); -static ssize_t libertas_lowsnr_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_snrthreshold *snr_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_SET); - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_snrthreshold)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); - snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW); - snr_threshold->header.len = cpu_to_le16(2); - snr_threshold->snrvalue = value; - snr_threshold->snrfreq = freq; - event_bitmap |= subscribed ? 0x0002 : 0x0; - event->events = cpu_to_le16(event_bitmap); - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; + pos += snprintf(buf, len, "%d %d %d\n", value, freq, + !!(events & event_mask)); } - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } + ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - res = count; + out_cmd: + kfree(subscribed); -out_unlock: - free_page(addr); - return res; + out_page: + free_page((unsigned long)buf); + return ret; } -static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (void *)(response_buf + S_DS_GEN); - while (cmd_len < le16_to_cpu(pcmdptr->size)) { - struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); - switch (header->type) { - struct mrvlietypes_failurecount *failcount; - case __constant_cpu_to_le16(TLV_TYPE_FAILCOUNT): - failcount = (void *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - failcount->failvalue, - failcount->Failfreq, - (event->events & cpu_to_le16(0x0004))?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_failurecount); - break; - } - } - - kfree(response_buf); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; -} -static ssize_t libertas_failcount_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) +static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, + struct file *file, + const char __user *userbuf, size_t count, + loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_failurecount *failcount; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; + struct cmd_ds_802_11_subscribe_event *events; + struct mrvlietypes_thresholds *tlv; + struct lbs_private *priv = file->private_data; + ssize_t buf_size; + int value, freq, new_mask; + uint16_t curr_mask; + char *buf; + int ret; + + buf = (char *)get_zeroed_page(GFP_KERNEL); + if (!buf) + return -ENOMEM; buf_size = min(count, len - 1); if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; + ret = -EFAULT; + goto out_page; } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; + ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask); + if (ret != 3) { + ret = -EINVAL; + goto out_page; } - - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_SET); - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_failurecount)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - failcount = (struct mrvlietypes_failurecount *)(ptr); - failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT); - failcount->header.len = cpu_to_le16(2); - failcount->failvalue = value; - failcount->Failfreq = freq; - event_bitmap |= subscribed ? 0x0004 : 0x0; - event->events = cpu_to_le16(event_bitmap); - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = (struct cmd_ds_command *)response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; + events = kzalloc(sizeof(*events), GFP_KERNEL); + if (!events) { + ret = -ENOMEM; + goto out_page; } - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } + events->hdr.size = cpu_to_le16(sizeof(*events)); + events->action = cpu_to_le16(CMD_ACT_GET); - res = count; -out_unlock: - free_page(addr); - return res; -} - -static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } + ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); + if (ret) + goto out_events; - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); + curr_mask = le16_to_cpu(events->events); - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); + if (new_mask) + new_mask = curr_mask | event_mask; + else + new_mask = curr_mask & ~event_mask; - pcmdptr = response_buf; + /* Now everything is set and we can send stuff down to the firmware */ - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - free_page(addr); - kfree(response_buf); - return 0; - } + tlv = (void *)events->tlv; - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - free_page(addr); - kfree(response_buf); - return 0; - } + events->action = cpu_to_le16(CMD_ACT_SET); + events->events = cpu_to_le16(new_mask); + tlv->header.type = cpu_to_le16(tlv_type); + tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header)); + tlv->value = value; + if (tlv_type != TLV_TYPE_BCNMISS) + tlv->freq = freq; - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (void *)(response_buf + S_DS_GEN); - while (cmd_len < le16_to_cpu(pcmdptr->size)) { - struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); - switch (header->type) { - struct mrvlietypes_beaconsmissed *bcnmiss; - case __constant_cpu_to_le16(TLV_TYPE_BCNMISS): - bcnmiss = (void *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d N/A %d\n", - bcnmiss->beaconmissed, - (event->events & cpu_to_le16(0x0008))?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_beaconsmissed); - break; - } - } + /* The command header, the event mask, and the one TLV */ + events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 2 + sizeof(*tlv)); - kfree(response_buf); + ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; + if (!ret) + ret = count; + out_events: + kfree(events); + out_page: + free_page((unsigned long)buf); + return ret; } -static ssize_t libertas_bcnmiss_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) + +static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_beaconsmissed *bcnmiss; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; + return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, + file, userbuf, count, ppos); +} - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - event_bitmap = libertas_get_events_bitmap(priv); +static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, + file, userbuf, count, ppos); +} - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_SET); - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_beaconsmissed)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr); - bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS); - bcnmiss->header.len = cpu_to_le16(2); - bcnmiss->beaconmissed = value; - event_bitmap |= subscribed ? 0x0008 : 0x0; - event->events = cpu_to_le16(event_bitmap); - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } +static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, + file, userbuf, count, ppos); +} - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - free_page(addr); - kfree(response_buf); - return 0; - } - res = count; -out_unlock: - free_page(addr); - return res; +static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, + file, userbuf, count, ppos); } -static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, + +static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } - - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (void *)(response_buf + S_DS_GEN); - while (cmd_len < le16_to_cpu(pcmdptr->size)) { - struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); - switch (header->type) { - struct mrvlietypes_rssithreshold *Highrssi; - case __constant_cpu_to_le16(TLV_TYPE_RSSI_HIGH): - Highrssi = (void *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - Highrssi->rssivalue, - Highrssi->rssifreq, - (event->events & cpu_to_le16(0x0010))?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } - - kfree(response_buf); - - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; + return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, + file, userbuf, count, ppos); } -static ssize_t libertas_highrssi_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) -{ - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_rssithreshold *rssi_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } - event_bitmap = libertas_get_events_bitmap(priv); - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_SET); - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_rssithreshold)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); - rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH); - rssi_threshold->header.len = cpu_to_le16(2); - rssi_threshold->rssivalue = value; - rssi_threshold->rssifreq = freq; - event_bitmap |= subscribed ? 0x0010 : 0x0; - event->events = cpu_to_le16(event_bitmap); - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - return 0; - } +static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, + file, userbuf, count, ppos); +} - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - return 0; - } - res = count; -out_unlock: - free_page(addr); - return res; +static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, + file, userbuf, count, ppos); } -static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, + +static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - void *response_buf; - int res, cmd_len; - ssize_t pos = 0; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) { - free_page(addr); - return res; - } - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_GET); - pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN); - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; + return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, + file, userbuf, count, ppos); +} - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - event = (void *)(response_buf + S_DS_GEN); - while (cmd_len < le16_to_cpu(pcmdptr->size)) { - struct mrvlietypesheader *header = (void *)(response_buf + cmd_len); - switch (header->type) { - struct mrvlietypes_snrthreshold *HighSnr; - case __constant_cpu_to_le16(TLV_TYPE_SNR_HIGH): - HighSnr = (void *)(response_buf + cmd_len); - pos += snprintf(buf+pos, len-pos, "%d %d %d\n", - HighSnr->snrvalue, - HighSnr->snrfreq, - (event->events & cpu_to_le16(0x0020))?1:0); - default: - cmd_len += sizeof(struct mrvlietypes_snrthreshold); - break; - } - } +static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, + file, userbuf, count, ppos); +} - kfree(response_buf); - res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - free_page(addr); - return res; +static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, + file, userbuf, count, ppos); } -static ssize_t libertas_highsnr_write(struct file *file, - const char __user *userbuf, - size_t count, loff_t *ppos) +static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - ssize_t res, buf_size; - int value, freq, subscribed, cmd_len; - struct cmd_ctrl_node *pcmdnode; - struct cmd_ds_command *pcmdptr; - struct cmd_ds_802_11_subscribe_event *event; - struct mrvlietypes_snrthreshold *snr_threshold; - void *response_buf; - u16 event_bitmap; - u8 *ptr; - unsigned long addr = get_zeroed_page(GFP_KERNEL); - char *buf = (char *)addr; - - buf_size = min(count, len - 1); - if (copy_from_user(buf, userbuf, buf_size)) { - res = -EFAULT; - goto out_unlock; - } - res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); - if (res != 3) { - res = -EFAULT; - goto out_unlock; - } + return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, + file, userbuf, count, ppos); +} - event_bitmap = libertas_get_events_bitmap(priv); - res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); - if (res < 0) - goto out_unlock; - - event = &pcmdptr->params.subscribe_event; - event->action = cpu_to_le16(CMD_ACT_SET); - pcmdptr->size = cpu_to_le16(S_DS_GEN + - sizeof(struct cmd_ds_802_11_subscribe_event) + - sizeof(struct mrvlietypes_snrthreshold)); - cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); - ptr = (u8*) pcmdptr+cmd_len; - snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); - snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH); - snr_threshold->header.len = cpu_to_le16(2); - snr_threshold->snrvalue = value; - snr_threshold->snrfreq = freq; - event_bitmap |= subscribed ? 0x0020 : 0x0; - event->events = cpu_to_le16(event_bitmap); - - libertas_queue_cmd(adapter, pcmdnode, 1); - wake_up_interruptible(&priv->waitq); - - /* Sleep until response is generated by FW */ - wait_event_interruptible(pcmdnode->cmdwait_q, - pcmdnode->cmdwaitqwoken); - - pcmdptr = response_buf; - - if (pcmdptr->result) { - lbs_pr_err("%s: fail, result=%d\n", __func__, - le16_to_cpu(pcmdptr->result)); - kfree(response_buf); - free_page(addr); - return 0; - } +static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, + file, userbuf, count, ppos); +} - if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) { - lbs_pr_err("command response incorrect!\n"); - kfree(response_buf); - free_page(addr); - return 0; - } - res = count; -out_unlock: - free_page(addr); - return res; -} -static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, +static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct wlan_offset_value offval; + struct lbs_private *priv = file->private_data; + struct lbs_offset_value offval; ssize_t pos = 0; int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); @@ -1375,23 +603,23 @@ static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, offval.offset = priv->mac_offset; offval.value = 0; - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_MAC_REG_ACCESS, 0, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", - priv->mac_offset, adapter->offsetvalue.value); + priv->mac_offset, priv->offsetvalue.value); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); free_page(addr); return ret; } -static ssize_t libertas_rdmac_write(struct file *file, +static ssize_t lbs_rdmac_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; @@ -1408,15 +636,15 @@ out_unlock: return res; } -static ssize_t libertas_wrmac_write(struct file *file, +static ssize_t lbs_wrmac_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; u32 offset, value; - struct wlan_offset_value offval; + struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; @@ -1433,7 +661,7 @@ static ssize_t libertas_wrmac_write(struct file *file, offval.offset = offset; offval.value = value; - res = libertas_prepare_and_send_command(priv, + res = lbs_prepare_and_send_command(priv, CMD_MAC_REG_ACCESS, 1, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); @@ -1444,12 +672,11 @@ out_unlock: return res; } -static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, +static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct wlan_offset_value offval; + struct lbs_private *priv = file->private_data; + struct lbs_offset_value offval; ssize_t pos = 0; int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); @@ -1458,12 +685,12 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, offval.offset = priv->bbp_offset; offval.value = 0; - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_BBP_REG_ACCESS, 0, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", - priv->bbp_offset, adapter->offsetvalue.value); + priv->bbp_offset, priv->offsetvalue.value); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); free_page(addr); @@ -1471,11 +698,11 @@ static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, return ret; } -static ssize_t libertas_rdbbp_write(struct file *file, +static ssize_t lbs_rdbbp_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; @@ -1492,15 +719,15 @@ out_unlock: return res; } -static ssize_t libertas_wrbbp_write(struct file *file, +static ssize_t lbs_wrbbp_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; u32 offset, value; - struct wlan_offset_value offval; + struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; @@ -1517,7 +744,7 @@ static ssize_t libertas_wrbbp_write(struct file *file, offval.offset = offset; offval.value = value; - res = libertas_prepare_and_send_command(priv, + res = lbs_prepare_and_send_command(priv, CMD_BBP_REG_ACCESS, 1, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); @@ -1528,12 +755,11 @@ out_unlock: return res; } -static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, +static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; - wlan_adapter *adapter = priv->adapter; - struct wlan_offset_value offval; + struct lbs_private *priv = file->private_data; + struct lbs_offset_value offval; ssize_t pos = 0; int ret; unsigned long addr = get_zeroed_page(GFP_KERNEL); @@ -1542,12 +768,12 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, offval.offset = priv->rf_offset; offval.value = 0; - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_RF_REG_ACCESS, 0, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", - priv->rf_offset, adapter->offsetvalue.value); + priv->rf_offset, priv->offsetvalue.value); ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); free_page(addr); @@ -1555,11 +781,11 @@ static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, return ret; } -static ssize_t libertas_rdrf_write(struct file *file, +static ssize_t lbs_rdrf_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; @@ -1576,15 +802,15 @@ out_unlock: return res; } -static ssize_t libertas_wrrf_write(struct file *file, +static ssize_t lbs_wrrf_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { - wlan_private *priv = file->private_data; + struct lbs_private *priv = file->private_data; ssize_t res, buf_size; u32 offset, value; - struct wlan_offset_value offval; + struct lbs_offset_value offval; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; @@ -1601,7 +827,7 @@ static ssize_t libertas_wrrf_write(struct file *file, offval.offset = offset; offval.value = value; - res = libertas_prepare_and_send_command(priv, + res = lbs_prepare_and_send_command(priv, CMD_RF_REG_ACCESS, 1, CMD_OPTION_WAITFORRSP, 0, &offval); mdelay(10); @@ -1619,69 +845,69 @@ out_unlock: .write = (fwrite), \ } -struct libertas_debugfs_files { +struct lbs_debugfs_files { char *name; int perm; struct file_operations fops; }; -static struct libertas_debugfs_files debugfs_files[] = { - { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), }, - { "getscantable", 0444, FOPS(libertas_getscantable, +static struct lbs_debugfs_files debugfs_files[] = { + { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, + { "getscantable", 0444, FOPS(lbs_getscantable, write_file_dummy), }, - { "sleepparams", 0644, FOPS(libertas_sleepparams_read, - libertas_sleepparams_write), }, - { "extscan", 0600, FOPS(NULL, libertas_extscan), }, - { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), }, + { "sleepparams", 0644, FOPS(lbs_sleepparams_read, + lbs_sleepparams_write), }, + { "extscan", 0600, FOPS(NULL, lbs_extscan), }, + { "setuserscan", 0600, FOPS(NULL, lbs_setuserscan), }, }; -static struct libertas_debugfs_files debugfs_events_files[] = { - {"low_rssi", 0644, FOPS(libertas_lowrssi_read, - libertas_lowrssi_write), }, - {"low_snr", 0644, FOPS(libertas_lowsnr_read, - libertas_lowsnr_write), }, - {"failure_count", 0644, FOPS(libertas_failcount_read, - libertas_failcount_write), }, - {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read, - libertas_bcnmiss_write), }, - {"high_rssi", 0644, FOPS(libertas_highrssi_read, - libertas_highrssi_write), }, - {"high_snr", 0644, FOPS(libertas_highsnr_read, - libertas_highsnr_write), }, +static struct lbs_debugfs_files debugfs_events_files[] = { + {"low_rssi", 0644, FOPS(lbs_lowrssi_read, + lbs_lowrssi_write), }, + {"low_snr", 0644, FOPS(lbs_lowsnr_read, + lbs_lowsnr_write), }, + {"failure_count", 0644, FOPS(lbs_failcount_read, + lbs_failcount_write), }, + {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read, + lbs_bcnmiss_write), }, + {"high_rssi", 0644, FOPS(lbs_highrssi_read, + lbs_highrssi_write), }, + {"high_snr", 0644, FOPS(lbs_highsnr_read, + lbs_highsnr_write), }, }; -static struct libertas_debugfs_files debugfs_regs_files[] = { - {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), }, - {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), }, - {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), }, - {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), }, - {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), }, - {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), }, +static struct lbs_debugfs_files debugfs_regs_files[] = { + {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), }, + {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), }, + {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), }, + {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), }, + {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), }, + {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), }, }; -void libertas_debugfs_init(void) +void lbs_debugfs_init(void) { - if (!libertas_dir) - libertas_dir = debugfs_create_dir("libertas_wireless", NULL); + if (!lbs_dir) + lbs_dir = debugfs_create_dir("lbs_wireless", NULL); return; } -void libertas_debugfs_remove(void) +void lbs_debugfs_remove(void) { - if (libertas_dir) - debugfs_remove(libertas_dir); + if (lbs_dir) + debugfs_remove(lbs_dir); return; } -void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev) +void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev) { int i; - struct libertas_debugfs_files *files; - if (!libertas_dir) + struct lbs_debugfs_files *files; + if (!lbs_dir) goto exit; - priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir); + priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir); if (!priv->debugfs_dir) goto exit; @@ -1721,13 +947,13 @@ void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev) } #ifdef PROC_DEBUG - libertas_debug_init(priv, dev); + lbs_debug_init(priv, dev); #endif exit: return; } -void libertas_debugfs_remove_one(wlan_private *priv) +void lbs_debugfs_remove_one(struct lbs_private *priv) { int i; @@ -1754,8 +980,8 @@ void libertas_debugfs_remove_one(wlan_private *priv) #ifdef PROC_DEBUG -#define item_size(n) (FIELD_SIZEOF(wlan_adapter, n)) -#define item_addr(n) (offsetof(wlan_adapter, n)) +#define item_size(n) (FIELD_SIZEOF(struct lbs_private, n)) +#define item_addr(n) (offsetof(struct lbs_private, n)) struct debug_data { @@ -1764,7 +990,7 @@ struct debug_data { size_t addr; }; -/* To debug any member of wlan_adapter, simply add one line here. +/* To debug any member of struct lbs_private, simply add one line here. */ static struct debug_data items[] = { {"intcounter", item_size(intcounter), item_addr(intcounter)}, @@ -1785,7 +1011,7 @@ static int num_of_items = ARRAY_SIZE(items); * @param data data to output * @return number of output data */ -static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf, +static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { int val = 0; @@ -1829,7 +1055,7 @@ static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf, * @param data data to write * @return number of data */ -static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf, +static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, size_t cnt, loff_t *ppos) { int r, i; @@ -1881,21 +1107,21 @@ static ssize_t wlan_debugfs_write(struct file *f, const char __user *buf, return (ssize_t)cnt; } -static struct file_operations libertas_debug_fops = { +static struct file_operations lbs_debug_fops = { .owner = THIS_MODULE, .open = open_file_generic, - .write = wlan_debugfs_write, - .read = wlan_debugfs_read, + .write = lbs_debugfs_write, + .read = lbs_debugfs_read, }; /** * @brief create debug proc file * - * @param priv pointer wlan_private + * @param priv pointer struct lbs_private * @param dev pointer net_device * @return N/A */ -static void libertas_debug_init(wlan_private * priv, struct net_device *dev) +static void lbs_debug_init(struct lbs_private *priv, struct net_device *dev) { int i; @@ -1903,11 +1129,10 @@ static void libertas_debug_init(wlan_private * priv, struct net_device *dev) return; for (i = 0; i < num_of_items; i++) - items[i].addr += (size_t) priv->adapter; + items[i].addr += (size_t) priv; priv->debugfs_debug = debugfs_create_file("debug", 0644, priv->debugfs_dir, &items[0], - &libertas_debug_fops); + &lbs_debug_fops); } #endif - diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h index 880a11b95d26..f2b9c7ffe0fd 100644 --- a/drivers/net/wireless/libertas/debugfs.h +++ b/drivers/net/wireless/libertas/debugfs.h @@ -1,6 +1,10 @@ -void libertas_debugfs_init(void); -void libertas_debugfs_remove(void); +#ifndef _LBS_DEBUGFS_H_ +#define _LBS_DEBUGFS_H_ -void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev); -void libertas_debugfs_remove_one(wlan_private *priv); +void lbs_debugfs_init(void); +void lbs_debugfs_remove(void); +void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev); +void lbs_debugfs_remove_one(struct lbs_private *priv); + +#endif diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 87fea9d5b90a..aaacd9bd6bd2 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -3,80 +3,74 @@ * functions defined in other source files */ -#ifndef _WLAN_DECL_H_ -#define _WLAN_DECL_H_ +#ifndef _LBS_DECL_H_ +#define _LBS_DECL_H_ #include <linux/device.h> #include "defs.h" /** Function Prototype Declaration */ -struct wlan_private; +struct lbs_private; struct sk_buff; struct net_device; - -int libertas_set_mac_packet_filter(wlan_private * priv); - -void libertas_send_tx_feedback(wlan_private * priv); - -int libertas_free_cmd_buffer(wlan_private * priv); struct cmd_ctrl_node; -struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv); +struct cmd_ds_command; -void libertas_set_cmd_ctrl_node(wlan_private * priv, - struct cmd_ctrl_node *ptempnode, - u32 cmd_oid, u16 wait_option, void *pdata_buf); +int lbs_set_mac_packet_filter(struct lbs_private *priv); -int libertas_prepare_and_send_command(wlan_private * priv, - u16 cmd_no, - u16 cmd_action, - u16 wait_option, u32 cmd_oid, void *pdata_buf); +void lbs_send_tx_feedback(struct lbs_private *priv); -void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail); +int lbs_free_cmd_buffer(struct lbs_private *priv); -int libertas_allocate_cmd_buffer(wlan_private * priv); -int libertas_execute_next_command(wlan_private * priv); -int libertas_process_event(wlan_private * priv); -void libertas_interrupt(struct net_device *); -int libertas_set_radio_control(wlan_private * priv); -u32 libertas_fw_index_to_data_rate(u8 index); -u8 libertas_data_rate_to_fw_index(u32 rate); -void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); +int lbs_prepare_and_send_command(struct lbs_private *priv, + u16 cmd_no, + u16 cmd_action, + u16 wait_option, u32 cmd_oid, void *pdata_buf); -void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); +int lbs_allocate_cmd_buffer(struct lbs_private *priv); +int lbs_execute_next_command(struct lbs_private *priv); +int lbs_process_event(struct lbs_private *priv); +void lbs_interrupt(struct lbs_private *priv); +int lbs_set_radio_control(struct lbs_private *priv); +u32 lbs_fw_index_to_data_rate(u8 index); +u8 lbs_data_rate_to_fw_index(u32 rate); +void lbs_get_fwversion(struct lbs_private *priv, + char *fwversion, + int maxlen); /** The proc fs interface */ -int libertas_process_rx_command(wlan_private * priv); -int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); -void __libertas_cleanup_and_insert_cmd(wlan_private * priv, - struct cmd_ctrl_node *ptempcmd); - -int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band); - -int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *); +int lbs_process_rx_command(struct lbs_private *priv); +void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, + int result); +int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band); -void libertas_ps_sleep(wlan_private * priv, int wait_option); -void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode); -void libertas_ps_wakeup(wlan_private * priv, int wait_option); +int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *); -void libertas_tx_runqueue(wlan_private *priv); +void lbs_ps_sleep(struct lbs_private *priv, int wait_option); +void lbs_ps_confirm_sleep(struct lbs_private *priv, u16 psmode); +void lbs_ps_wakeup(struct lbs_private *priv, int wait_option); -struct chan_freq_power *libertas_find_cfp_by_band_and_channel( - wlan_adapter * adapter, u8 band, u16 channel); +struct chan_freq_power *lbs_find_cfp_by_band_and_channel( + struct lbs_private *priv, + u8 band, + u16 channel); -void libertas_mac_event_disconnected(wlan_private * priv); +void lbs_mac_event_disconnected(struct lbs_private *priv); -void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); +void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); /* main.c */ -struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, - int *cfp_no); -wlan_private *libertas_add_card(void *card, struct device *dmdev); -int libertas_remove_card(wlan_private *priv); -int libertas_start_card(wlan_private *priv); -int libertas_stop_card(wlan_private *priv); -int libertas_add_mesh(wlan_private *priv, struct device *dev); -void libertas_remove_mesh(wlan_private *priv); -int libertas_reset_device(wlan_private *priv); - -#endif /* _WLAN_DECL_H_ */ +struct chan_freq_power *lbs_get_region_cfp_table(u8 region, + u8 band, + int *cfp_no); +struct lbs_private *lbs_add_card(void *card, struct device *dmdev); +int lbs_remove_card(struct lbs_private *priv); +int lbs_start_card(struct lbs_private *priv); +int lbs_stop_card(struct lbs_private *priv); +int lbs_reset_device(struct lbs_private *priv); +void lbs_host_to_card_done(struct lbs_private *priv); + +int lbs_update_channel(struct lbs_private *priv); +#endif diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 3a0c9beefcf8..3053cc2160bc 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -2,8 +2,8 @@ * This header file contains global constant/enum definitions, * global variable declaration. */ -#ifndef _WLAN_DEFS_H_ -#define _WLAN_DEFS_H_ +#ifndef _LBS_DEFS_H_ +#define _LBS_DEFS_H_ #include <linux/spinlock.h> @@ -41,11 +41,11 @@ #define LBS_DEB_HEX 0x00200000 #define LBS_DEB_SDIO 0x00400000 -extern unsigned int libertas_debug; +extern unsigned int lbs_debug; #ifdef DEBUG #define LBS_DEB_LL(grp, grpnam, fmt, args...) \ -do { if ((libertas_debug & (grp)) == (grp)) \ +do { if ((lbs_debug & (grp)) == (grp)) \ printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \ in_interrupt() ? " (INT)" : "", ## args); } while (0) #else @@ -96,8 +96,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in int i = 0; if (len && - (libertas_debug & LBS_DEB_HEX) && - (libertas_debug & grp)) + (lbs_debug & LBS_DEB_HEX) && + (lbs_debug & grp)) { for (i = 1; i <= len; i++) { if ((i & 0xf) == 1) { @@ -132,15 +132,22 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in */ #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 -#define MRVDRV_NUM_OF_CMD_BUFFER 10 -#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) +#define LBS_NUM_CMD_BUFFERS 10 +#define LBS_CMD_BUFFER_SIZE (2 * 1024) #define MRVDRV_MAX_CHANNEL_SIZE 14 #define MRVDRV_ASSOCIATION_TIME_OUT 255 #define MRVDRV_SNAP_HEADER_LEN 8 -#define WLAN_UPLD_SIZE 2312 +#define LBS_UPLD_SIZE 2312 #define DEV_NAME_LEN 32 +/* Wake criteria for HOST_SLEEP_CFG command */ +#define EHS_WAKE_ON_BROADCAST_DATA 0x0001 +#define EHS_WAKE_ON_UNICAST_DATA 0x0002 +#define EHS_WAKE_ON_MAC_EVENT 0x0004 +#define EHS_WAKE_ON_MULTICAST_DATA 0x0008 +#define EHS_REMOVE_WAKEUP 0xFFFFFFFF + /** Misc constants */ /* This section defines 802.11 specific contants */ @@ -257,17 +264,11 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define MAX_LEDS 8 -#define IS_MESH_FRAME(x) (x->cb[6]) -#define SET_MESH_FRAME(x) (x->cb[6]=1) -#define UNSET_MESH_FRAME(x) (x->cb[6]=0) - /** Global Variable Declaration */ -typedef struct _wlan_private wlan_private; -typedef struct _wlan_adapter wlan_adapter; -extern const char libertas_driver_version[]; -extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; +extern const char lbs_driver_version[]; +extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE]; -extern u8 libertas_bg_rates[MAX_RATES]; +extern u8 lbs_bg_rates[MAX_RATES]; /** ENUM definition*/ /** SNRNF_TYPE */ @@ -284,13 +285,13 @@ enum SNRNF_DATA { MAX_TYPE_AVG }; -/** WLAN_802_11_POWER_MODE */ -enum WLAN_802_11_POWER_MODE { - WLAN802_11POWERMODECAM, - WLAN802_11POWERMODEMAX_PSP, - WLAN802_11POWERMODEFAST_PSP, +/** LBS_802_11_POWER_MODE */ +enum LBS_802_11_POWER_MODE { + LBS802_11POWERMODECAM, + LBS802_11POWERMODEMAX_PSP, + LBS802_11POWERMODEFAST_PSP, /*not a real mode, defined as an upper bound */ - WLAN802_11POWEMODEMAX + LBS802_11POWEMODEMAX }; /** PS_STATE */ @@ -308,16 +309,16 @@ enum DNLD_STATE { DNLD_CMD_SENT }; -/** WLAN_MEDIA_STATE */ -enum WLAN_MEDIA_STATE { - LIBERTAS_CONNECTED, - LIBERTAS_DISCONNECTED +/** LBS_MEDIA_STATE */ +enum LBS_MEDIA_STATE { + LBS_CONNECTED, + LBS_DISCONNECTED }; -/** WLAN_802_11_PRIVACY_FILTER */ -enum WLAN_802_11_PRIVACY_FILTER { - WLAN802_11PRIVFILTERACCEPTALL, - WLAN802_11PRIVFILTER8021XWEP +/** LBS_802_11_PRIVACY_FILTER */ +enum LBS_802_11_PRIVACY_FILTER { + LBS802_11PRIVFILTERACCEPTALL, + LBS802_11PRIVFILTER8021XWEP }; /** mv_ms_type */ @@ -382,4 +383,4 @@ enum SNMP_MIB_VALUE_e { #define FWT_DEFAULT_SLEEPMODE 0 #define FWT_DEFAULT_SNR 0 -#endif /* _WLAN_DEFS_H_ */ +#endif diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 1fb807aa91b9..58d7ef6b5ff5 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -1,21 +1,20 @@ /** * This file contains definitions and data structures specific * to Marvell 802.11 NIC. It contains the Device Information - * structure wlan_adapter. + * structure struct lbs_private.. */ -#ifndef _WLAN_DEV_H_ -#define _WLAN_DEV_H_ +#ifndef _LBS_DEV_H_ +#define _LBS_DEV_H_ #include <linux/netdevice.h> #include <linux/wireless.h> #include <linux/ethtool.h> #include <linux/debugfs.h> -#include <net/ieee80211.h> #include "defs.h" #include "scan.h" -extern struct ethtool_ops libertas_ethtool_ops; +extern struct ethtool_ops lbs_ethtool_ops; #define MAX_BSSID_PER_CHANNEL 16 @@ -53,7 +52,7 @@ struct region_channel { struct chan_freq_power *CFP; }; -struct wlan_802_11_security { +struct lbs_802_11_security { u8 WPAenabled; u8 WPA2enabled; u8 wep_enabled; @@ -78,16 +77,16 @@ struct current_bss_params { /** sleep_params */ struct sleep_params { - u16 sp_error; - u16 sp_offset; - u16 sp_stabletime; - u8 sp_calcontrol; - u8 sp_extsleepclk; - u16 sp_reserved; + uint16_t sp_error; + uint16_t sp_offset; + uint16_t sp_stabletime; + uint8_t sp_calcontrol; + uint8_t sp_extsleepclk; + uint16_t sp_reserved; }; /* Mesh statistics */ -struct wlan_mesh_stats { +struct lbs_mesh_stats { u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ u32 fwd_drop_ttl; /* Fwd: TTL zero */ @@ -99,26 +98,22 @@ struct wlan_mesh_stats { }; /** Private structure for the MV device */ -struct _wlan_private { - int open; +struct lbs_private { int mesh_open; int infra_open; int mesh_autostart_enabled; - __le16 boot2_version; char name[DEV_NAME_LEN]; void *card; - wlan_adapter *adapter; struct net_device *dev; struct net_device_stats stats; struct net_device *mesh_dev; /* Virtual device */ struct net_device *rtap_net_dev; - struct ieee80211_device *ieee; struct iw_statistics wstats; - struct wlan_mesh_stats mstats; + struct lbs_mesh_stats mstats; struct dentry *debugfs_dir; struct dentry *debugfs_debug; struct dentry *debugfs_files[6]; @@ -136,15 +131,13 @@ struct _wlan_private { /** Upload length */ u32 upld_len; /* Upload buffer */ - u8 upld_buf[WLAN_UPLD_SIZE]; + u8 upld_buf[LBS_UPLD_SIZE]; /* Download sent: bit0 1/0=data_sent/data_tx_done, bit1 1/0=cmd_sent/cmd_tx_done, all other bits reserved 0 */ u8 dnld_sent; - struct device *hotplug_device; - /** thread to service interrupts */ struct task_struct *main_thread; wait_queue_head_t waitq; @@ -155,65 +148,29 @@ struct _wlan_private { struct work_struct sync_channel; /** Hardware access */ - int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb); - int (*hw_get_int_status) (wlan_private * priv, u8 *); - int (*hw_read_event_cause) (wlan_private *); -}; + int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); + int (*hw_get_int_status) (struct lbs_private *priv, u8 *); + int (*hw_read_event_cause) (struct lbs_private *); -/** Association request - * - * Encapsulates all the options that describe a specific assocation request - * or configuration of the wireless card's radio, mode, and security settings. - */ -struct assoc_request { -#define ASSOC_FLAG_SSID 1 -#define ASSOC_FLAG_CHANNEL 2 -#define ASSOC_FLAG_BAND 3 -#define ASSOC_FLAG_MODE 4 -#define ASSOC_FLAG_BSSID 5 -#define ASSOC_FLAG_WEP_KEYS 6 -#define ASSOC_FLAG_WEP_TX_KEYIDX 7 -#define ASSOC_FLAG_WPA_MCAST_KEY 8 -#define ASSOC_FLAG_WPA_UCAST_KEY 9 -#define ASSOC_FLAG_SECINFO 10 -#define ASSOC_FLAG_WPA_IE 11 - unsigned long flags; + /* Wake On LAN */ + uint32_t wol_criteria; + uint8_t wol_gpio; + uint8_t wol_gap; - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - u8 channel; - u8 band; - u8 mode; - u8 bssid[ETH_ALEN]; - - /** WEP keys */ - struct enc_key wep_keys[4]; - u16 wep_tx_keyidx; - - /** WPA keys */ - struct enc_key wpa_mcast_key; - struct enc_key wpa_unicast_key; + /* was struct lbs_adapter from here... */ - struct wlan_802_11_security secinfo; - - /** WPA Information Elements*/ - u8 wpa_ie[MAX_WPA_IE_LEN]; - u8 wpa_ie_len; - - /* BSS to associate with for infrastructure of Ad-Hoc join */ - struct bss_descriptor bss; -}; - -/** Wlan adapter data structure*/ -struct _wlan_adapter { + /** Wlan adapter data structure*/ /** STATUS variables */ - u8 fwreleasenumber[4]; + u32 fwrelease; u32 fwcapinfo; /* protected with big lock */ struct mutex lock; - u8 tmptxbuf[WLAN_UPLD_SIZE]; + /* TX packet ready to be sent... */ + int tx_pending_len; /* -1 while building packet */ + + u8 tx_pending_buf[LBS_UPLD_SIZE]; /* protected by hard_start_xmit serialization */ /** command-related variables */ @@ -231,8 +188,7 @@ struct _wlan_adapter { struct list_head cmdpendingq; wait_queue_head_t cmd_pending; - u8 nr_cmd_pending; - /* command related variables protected by adapter->driver_lock */ + /* command related variables protected by priv->driver_lock */ /** Async and Sync Event variables */ u32 intcounter; @@ -244,17 +200,18 @@ struct _wlan_adapter { /** Timers */ struct timer_list command_timer; - - /* TX queue used in PS mode */ - spinlock_t txqueue_lock; - struct sk_buff *tx_queue_ps[NR_TX_QUEUE]; - unsigned int tx_queue_idx; + int nr_retries; + int cmd_timed_out; u8 hisregcpy; /** current ssid/bssid related parameters*/ struct current_bss_params curbssparams; + uint16_t mesh_tlv; + u8 mesh_ssid[IW_ESSID_MAX_SIZE + 1]; + u8 mesh_ssid_len; + /* IW_MODE_* */ u8 mode; @@ -263,6 +220,8 @@ struct _wlan_adapter { struct list_head network_free_list; struct bss_descriptor *networks; + u16 beacon_period; + u8 beacon_enable; u8 adhoccreate; /** capability Info used in Association, start, join */ @@ -286,11 +245,11 @@ struct _wlan_adapter { /** Tx-related variables (for single packet tx) */ struct sk_buff *currenttxskb; - u16 TxLockFlag; /** NIC Operation characteristics */ u16 currentpacketfilter; u32 connect_status; + u32 mesh_connect_status; u16 regioncode; u16 txpowerlevel; @@ -300,15 +259,17 @@ struct _wlan_adapter { u16 psmode; /* Wlan802_11PowermodeCAM=disable Wlan802_11PowermodeMAX_PSP=enable */ u32 psstate; + char ps_supported; u8 needtowakeup; - struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; + struct PS_CMD_ConfirmSleep lbs_ps_confirm_sleep; + struct cmd_header lbs_ps_confirm_wake; struct assoc_request * pending_assoc_req; struct assoc_request * in_progress_assoc_req; /** Encryption parameter */ - struct wlan_802_11_security secinfo; + struct lbs_802_11_security secinfo; /** WEP keys */ struct enc_key wep_keys[4]; @@ -338,9 +299,6 @@ struct _wlan_adapter { u8 cur_rate; u8 auto_rate; - /** sleep_params */ - struct sleep_params sp; - /** RF calibration data */ #define MAX_REGION_CHANNEL_NUM 2 @@ -350,7 +308,7 @@ struct _wlan_adapter { struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; /** 11D and Domain Regulatory Data */ - struct wlan_802_11d_domain_reg domainreg; + struct lbs_802_11d_domain_reg domainreg; struct parsed_region_chan_11d parsed_region_chan; /** FSM variable for 11d support */ @@ -358,14 +316,57 @@ struct _wlan_adapter { /** MISCELLANEOUS */ u8 *prdeeprom; - struct wlan_offset_value offsetvalue; + struct lbs_offset_value offsetvalue; struct cmd_ds_802_11_get_log logmsg; u32 monitormode; + int last_scanned_channel; u8 fw_ready; +}; + +/** Association request + * + * Encapsulates all the options that describe a specific assocation request + * or configuration of the wireless card's radio, mode, and security settings. + */ +struct assoc_request { +#define ASSOC_FLAG_SSID 1 +#define ASSOC_FLAG_CHANNEL 2 +#define ASSOC_FLAG_BAND 3 +#define ASSOC_FLAG_MODE 4 +#define ASSOC_FLAG_BSSID 5 +#define ASSOC_FLAG_WEP_KEYS 6 +#define ASSOC_FLAG_WEP_TX_KEYIDX 7 +#define ASSOC_FLAG_WPA_MCAST_KEY 8 +#define ASSOC_FLAG_WPA_UCAST_KEY 9 +#define ASSOC_FLAG_SECINFO 10 +#define ASSOC_FLAG_WPA_IE 11 + unsigned long flags; - u8 last_scanned_channel; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len; + u8 channel; + u8 band; + u8 mode; + u8 bssid[ETH_ALEN]; + + /** WEP keys */ + struct enc_key wep_keys[4]; + u16 wep_tx_keyidx; + + /** WPA keys */ + struct enc_key wpa_mcast_key; + struct enc_key wpa_unicast_key; + + struct lbs_802_11_security secinfo; + + /** WPA Information Elements*/ + u8 wpa_ie[MAX_WPA_IE_LEN]; + u8 wpa_ie_len; + + /* BSS to associate with for infrastructure of Ad-Hoc join */ + struct bss_descriptor bss; }; -#endif /* _WLAN_DEV_H_ */ +#endif diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 3dae15211b6a..21e6f988ea81 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -8,6 +8,8 @@ #include "dev.h" #include "join.h" #include "wext.h" +#include "cmd.h" + static const char * mesh_stat_strings[]= { "drop_duplicate_bcast", "drop_ttl_zero", @@ -19,35 +21,34 @@ static const char * mesh_stat_strings[]= { "tx_failed_cnt" }; -static void libertas_ethtool_get_drvinfo(struct net_device *dev, +static void lbs_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - wlan_private *priv = (wlan_private *) dev->priv; + struct lbs_private *priv = (struct lbs_private *) dev->priv; char fwver[32]; - libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1); + lbs_get_fwversion(priv, fwver, sizeof(fwver) - 1); strcpy(info->driver, "libertas"); - strcpy(info->version, libertas_driver_version); + strcpy(info->version, lbs_driver_version); strcpy(info->fw_version, fwver); } /* All 8388 parts have 16KiB EEPROM size at the time of writing. * In case that changes this needs fixing. */ -#define LIBERTAS_EEPROM_LEN 16384 +#define LBS_EEPROM_LEN 16384 -static int libertas_ethtool_get_eeprom_len(struct net_device *dev) +static int lbs_ethtool_get_eeprom_len(struct net_device *dev) { - return LIBERTAS_EEPROM_LEN; + return LBS_EEPROM_LEN; } -static int libertas_ethtool_get_eeprom(struct net_device *dev, +static int lbs_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_regrdwr regctrl; + struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_ioctl_regrdwr regctrl; char *ptr; int ret; @@ -55,47 +56,47 @@ static int libertas_ethtool_get_eeprom(struct net_device *dev, regctrl.offset = eeprom->offset; regctrl.NOB = eeprom->len; - if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN) + if (eeprom->offset + eeprom->len > LBS_EEPROM_LEN) return -EINVAL; // mutex_lock(&priv->mutex); - adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); - if (!adapter->prdeeprom) + priv->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); + if (!priv->prdeeprom) return -ENOMEM; - memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); + memcpy(priv->prdeeprom, ®ctrl, sizeof(regctrl)); /* +14 is for action, offset, and NOB in * response */ lbs_deb_ethtool("action:%d offset: %x NOB: %02x\n", regctrl.action, regctrl.offset, regctrl.NOB); - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_EEPROM_ACCESS, regctrl.action, CMD_OPTION_WAITFORRSP, 0, ®ctrl); if (ret) { - if (adapter->prdeeprom) - kfree(adapter->prdeeprom); + if (priv->prdeeprom) + kfree(priv->prdeeprom); goto done; } mdelay(10); - ptr = (char *)adapter->prdeeprom; + ptr = (char *)priv->prdeeprom; /* skip the command header, but include the "value" u32 variable */ - ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4; + ptr = ptr + sizeof(struct lbs_ioctl_regrdwr) - 4; /* * Return the result back to the user */ memcpy(bytes, ptr, eeprom->len); - if (adapter->prdeeprom) - kfree(adapter->prdeeprom); + if (priv->prdeeprom) + kfree(priv->prdeeprom); // mutex_unlock(&priv->mutex); ret = 0; @@ -105,17 +106,17 @@ done: return ret; } -static void libertas_ethtool_get_stats(struct net_device * dev, +static void lbs_ethtool_get_stats(struct net_device * dev, struct ethtool_stats * stats, u64 * data) { - wlan_private *priv = dev->priv; + struct lbs_private *priv = dev->priv; struct cmd_ds_mesh_access mesh_access; int ret; lbs_deb_enter(LBS_DEB_ETHTOOL); /* Get Mesh Statistics */ - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS, CMD_OPTION_WAITFORRSP, 0, &mesh_access); @@ -143,7 +144,7 @@ static void libertas_ethtool_get_stats(struct net_device * dev, lbs_deb_enter(LBS_DEB_ETHTOOL); } -static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset) +static int lbs_ethtool_get_sset_count(struct net_device * dev, int sset) { switch (sset) { case ETH_SS_STATS: @@ -153,7 +154,7 @@ static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset) } } -static void libertas_ethtool_get_strings (struct net_device * dev, +static void lbs_ethtool_get_strings(struct net_device *dev, u32 stringset, u8 * s) { @@ -173,12 +174,57 @@ static void libertas_ethtool_get_strings (struct net_device * dev, lbs_deb_enter(LBS_DEB_ETHTOOL); } -struct ethtool_ops libertas_ethtool_ops = { - .get_drvinfo = libertas_ethtool_get_drvinfo, - .get_eeprom = libertas_ethtool_get_eeprom, - .get_eeprom_len = libertas_ethtool_get_eeprom_len, - .get_sset_count = libertas_ethtool_get_sset_count, - .get_ethtool_stats = libertas_ethtool_get_stats, - .get_strings = libertas_ethtool_get_strings, +static void lbs_ethtool_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct lbs_private *priv = dev->priv; + + if (priv->wol_criteria == 0xffffffff) { + /* Interface driver didn't configure wake */ + wol->supported = wol->wolopts = 0; + return; + } + + wol->supported = WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY; + + if (priv->wol_criteria & EHS_WAKE_ON_UNICAST_DATA) + wol->wolopts |= WAKE_UCAST; + if (priv->wol_criteria & EHS_WAKE_ON_MULTICAST_DATA) + wol->wolopts |= WAKE_MCAST; + if (priv->wol_criteria & EHS_WAKE_ON_BROADCAST_DATA) + wol->wolopts |= WAKE_BCAST; + if (priv->wol_criteria & EHS_WAKE_ON_MAC_EVENT) + wol->wolopts |= WAKE_PHY; +} + +static int lbs_ethtool_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wol) +{ + struct lbs_private *priv = dev->priv; + uint32_t criteria = 0; + + if (priv->wol_criteria == 0xffffffff && wol->wolopts) + return -EOPNOTSUPP; + + if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY)) + return -EOPNOTSUPP; + + if (wol->wolopts & WAKE_UCAST) criteria |= EHS_WAKE_ON_UNICAST_DATA; + if (wol->wolopts & WAKE_MCAST) criteria |= EHS_WAKE_ON_MULTICAST_DATA; + if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA; + if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT; + + return lbs_host_sleep_cfg(priv, criteria); +} + +struct ethtool_ops lbs_ethtool_ops = { + .get_drvinfo = lbs_ethtool_get_drvinfo, + .get_eeprom = lbs_ethtool_get_eeprom, + .get_eeprom_len = lbs_ethtool_get_eeprom_len, + .get_sset_count = lbs_ethtool_get_sset_count, + .get_ethtool_stats = lbs_ethtool_get_stats, + .get_strings = lbs_ethtool_get_strings, + .get_wol = lbs_ethtool_get_wol, + .set_wol = lbs_ethtool_set_wol, }; diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index b37ddbca969f..1aa04076b1ac 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -2,25 +2,25 @@ * This file contains definitions of WLAN commands. */ -#ifndef _HOST_H_ -#define _HOST_H_ +#ifndef _LBS_HOST_H_ +#define _LBS_HOST_H_ /** PUBLIC DEFINITIONS */ -#define DEFAULT_AD_HOC_CHANNEL 6 -#define DEFAULT_AD_HOC_CHANNEL_A 36 +#define DEFAULT_AD_HOC_CHANNEL 6 +#define DEFAULT_AD_HOC_CHANNEL_A 36 /** IEEE 802.11 oids */ -#define OID_802_11_SSID 0x00008002 -#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 -#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 -#define OID_802_11_RTS_THRESHOLD 0x0000800A -#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D -#define OID_802_11_SUPPORTED_RATES 0x0000800E -#define OID_802_11_STATISTICS 0x00008012 -#define OID_802_11_TX_RETRYCOUNT 0x0000801D -#define OID_802_11D_ENABLE 0x00008020 - -#define CMD_OPTION_WAITFORRSP 0x0002 +#define OID_802_11_SSID 0x00008002 +#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 +#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 +#define OID_802_11_RTS_THRESHOLD 0x0000800A +#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D +#define OID_802_11_SUPPORTED_RATES 0x0000800E +#define OID_802_11_STATISTICS 0x00008012 +#define OID_802_11_TX_RETRYCOUNT 0x0000801D +#define OID_802_11D_ENABLE 0x00008020 + +#define CMD_OPTION_WAITFORRSP 0x0002 /** Host command IDs */ @@ -30,192 +30,189 @@ #define CMD_RET(cmd) (0x8000 | cmd) /* Return command convention exceptions: */ -#define CMD_RET_802_11_ASSOCIATE 0x8012 +#define CMD_RET_802_11_ASSOCIATE 0x8012 /* Command codes */ -#define CMD_CODE_DNLD 0x0002 -#define CMD_GET_HW_SPEC 0x0003 -#define CMD_EEPROM_UPDATE 0x0004 -#define CMD_802_11_RESET 0x0005 -#define CMD_802_11_SCAN 0x0006 -#define CMD_802_11_GET_LOG 0x000b -#define CMD_MAC_MULTICAST_ADR 0x0010 -#define CMD_802_11_AUTHENTICATE 0x0011 -#define CMD_802_11_EEPROM_ACCESS 0x0059 -#define CMD_802_11_ASSOCIATE 0x0050 -#define CMD_802_11_SET_WEP 0x0013 -#define CMD_802_11_GET_STAT 0x0014 -#define CMD_802_3_GET_STAT 0x0015 -#define CMD_802_11_SNMP_MIB 0x0016 -#define CMD_MAC_REG_MAP 0x0017 -#define CMD_BBP_REG_MAP 0x0018 -#define CMD_MAC_REG_ACCESS 0x0019 -#define CMD_BBP_REG_ACCESS 0x001a -#define CMD_RF_REG_ACCESS 0x001b -#define CMD_802_11_RADIO_CONTROL 0x001c -#define CMD_802_11_RF_CHANNEL 0x001d -#define CMD_802_11_RF_TX_POWER 0x001e -#define CMD_802_11_RSSI 0x001f -#define CMD_802_11_RF_ANTENNA 0x0020 - -#define CMD_802_11_PS_MODE 0x0021 - -#define CMD_802_11_DATA_RATE 0x0022 -#define CMD_RF_REG_MAP 0x0023 -#define CMD_802_11_DEAUTHENTICATE 0x0024 -#define CMD_802_11_REASSOCIATE 0x0025 -#define CMD_802_11_DISASSOCIATE 0x0026 -#define CMD_MAC_CONTROL 0x0028 -#define CMD_802_11_AD_HOC_START 0x002b -#define CMD_802_11_AD_HOC_JOIN 0x002c - -#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e -#define CMD_802_11_ENABLE_RSN 0x002f -#define CMD_802_11_PAIRWISE_TSC 0x0036 -#define CMD_802_11_GROUP_TSC 0x0037 -#define CMD_802_11_KEY_MATERIAL 0x005e - -#define CMD_802_11_SET_AFC 0x003c -#define CMD_802_11_GET_AFC 0x003d - -#define CMD_802_11_AD_HOC_STOP 0x0040 - -#define CMD_802_11_BEACON_STOP 0x0049 - -#define CMD_802_11_MAC_ADDRESS 0x004D -#define CMD_802_11_EEPROM_ACCESS 0x0059 - -#define CMD_802_11_BAND_CONFIG 0x0058 - -#define CMD_802_11D_DOMAIN_INFO 0x005b - -#define CMD_802_11_SLEEP_PARAMS 0x0066 - -#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 - -#define CMD_802_11_TPC_CFG 0x0072 -#define CMD_802_11_PWR_CFG 0x0073 - -#define CMD_802_11_LED_GPIO_CTRL 0x004e - -#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 - -#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 - -#define CMD_802_11_TX_RATE_QUERY 0x007f - -#define CMD_GET_TSF 0x0080 - -#define CMD_BT_ACCESS 0x0087 - -#define CMD_FWT_ACCESS 0x0095 - -#define CMD_802_11_MONITOR_MODE 0x0098 - -#define CMD_MESH_ACCESS 0x009b - -#define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_CODE_DNLD 0x0002 +#define CMD_GET_HW_SPEC 0x0003 +#define CMD_EEPROM_UPDATE 0x0004 +#define CMD_802_11_RESET 0x0005 +#define CMD_802_11_SCAN 0x0006 +#define CMD_802_11_GET_LOG 0x000b +#define CMD_MAC_MULTICAST_ADR 0x0010 +#define CMD_802_11_AUTHENTICATE 0x0011 +#define CMD_802_11_EEPROM_ACCESS 0x0059 +#define CMD_802_11_ASSOCIATE 0x0050 +#define CMD_802_11_SET_WEP 0x0013 +#define CMD_802_11_GET_STAT 0x0014 +#define CMD_802_3_GET_STAT 0x0015 +#define CMD_802_11_SNMP_MIB 0x0016 +#define CMD_MAC_REG_MAP 0x0017 +#define CMD_BBP_REG_MAP 0x0018 +#define CMD_MAC_REG_ACCESS 0x0019 +#define CMD_BBP_REG_ACCESS 0x001a +#define CMD_RF_REG_ACCESS 0x001b +#define CMD_802_11_RADIO_CONTROL 0x001c +#define CMD_802_11_RF_CHANNEL 0x001d +#define CMD_802_11_RF_TX_POWER 0x001e +#define CMD_802_11_RSSI 0x001f +#define CMD_802_11_RF_ANTENNA 0x0020 +#define CMD_802_11_PS_MODE 0x0021 +#define CMD_802_11_DATA_RATE 0x0022 +#define CMD_RF_REG_MAP 0x0023 +#define CMD_802_11_DEAUTHENTICATE 0x0024 +#define CMD_802_11_REASSOCIATE 0x0025 +#define CMD_802_11_DISASSOCIATE 0x0026 +#define CMD_MAC_CONTROL 0x0028 +#define CMD_802_11_AD_HOC_START 0x002b +#define CMD_802_11_AD_HOC_JOIN 0x002c +#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS 0x002e +#define CMD_802_11_ENABLE_RSN 0x002f +#define CMD_802_11_PAIRWISE_TSC 0x0036 +#define CMD_802_11_GROUP_TSC 0x0037 +#define CMD_802_11_SET_AFC 0x003c +#define CMD_802_11_GET_AFC 0x003d +#define CMD_802_11_AD_HOC_STOP 0x0040 +#define CMD_802_11_HOST_SLEEP_CFG 0x0043 +#define CMD_802_11_WAKEUP_CONFIRM 0x0044 +#define CMD_802_11_HOST_SLEEP_ACTIVATE 0x0045 +#define CMD_802_11_BEACON_STOP 0x0049 +#define CMD_802_11_MAC_ADDRESS 0x004d +#define CMD_802_11_LED_GPIO_CTRL 0x004e +#define CMD_802_11_EEPROM_ACCESS 0x0059 +#define CMD_802_11_BAND_CONFIG 0x0058 +#define CMD_802_11D_DOMAIN_INFO 0x005b +#define CMD_802_11_KEY_MATERIAL 0x005e +#define CMD_802_11_SLEEP_PARAMS 0x0066 +#define CMD_802_11_INACTIVITY_TIMEOUT 0x0067 +#define CMD_802_11_SLEEP_PERIOD 0x0068 +#define CMD_802_11_TPC_CFG 0x0072 +#define CMD_802_11_PWR_CFG 0x0073 +#define CMD_802_11_FW_WAKE_METHOD 0x0074 +#define CMD_802_11_SUBSCRIBE_EVENT 0x0075 +#define CMD_802_11_RATE_ADAPT_RATESET 0x0076 +#define CMD_802_11_TX_RATE_QUERY 0x007f +#define CMD_GET_TSF 0x0080 +#define CMD_BT_ACCESS 0x0087 +#define CMD_FWT_ACCESS 0x0095 +#define CMD_802_11_MONITOR_MODE 0x0098 +#define CMD_MESH_ACCESS 0x009b +#define CMD_MESH_CONFIG 0x00a3 +#define CMD_SET_BOOT2_VER 0x00a5 +#define CMD_802_11_BEACON_CTRL 0x00b0 /* For the IEEE Power Save */ -#define CMD_SUBCMD_ENTER_PS 0x0030 -#define CMD_SUBCMD_EXIT_PS 0x0031 -#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034 -#define CMD_SUBCMD_FULL_POWERDOWN 0x0035 -#define CMD_SUBCMD_FULL_POWERUP 0x0036 - -#define CMD_ENABLE_RSN 0x0001 -#define CMD_DISABLE_RSN 0x0000 +#define CMD_SUBCMD_ENTER_PS 0x0030 +#define CMD_SUBCMD_EXIT_PS 0x0031 +#define CMD_SUBCMD_SLEEP_CONFIRMED 0x0034 +#define CMD_SUBCMD_FULL_POWERDOWN 0x0035 +#define CMD_SUBCMD_FULL_POWERUP 0x0036 -#define CMD_ACT_SET 0x0001 -#define CMD_ACT_GET 0x0000 +#define CMD_ENABLE_RSN 0x0001 +#define CMD_DISABLE_RSN 0x0000 -#define CMD_ACT_GET_AES (CMD_ACT_GET + 2) -#define CMD_ACT_SET_AES (CMD_ACT_SET + 2) -#define CMD_ACT_REMOVE_AES (CMD_ACT_SET + 3) +#define CMD_ACT_GET 0x0000 +#define CMD_ACT_SET 0x0001 +#define CMD_ACT_GET_AES 0x0002 +#define CMD_ACT_SET_AES 0x0003 +#define CMD_ACT_REMOVE_AES 0x0004 /* Define action or option for CMD_802_11_SET_WEP */ -#define CMD_ACT_ADD 0x0002 -#define CMD_ACT_REMOVE 0x0004 -#define CMD_ACT_USE_DEFAULT 0x0008 +#define CMD_ACT_ADD 0x0002 +#define CMD_ACT_REMOVE 0x0004 +#define CMD_ACT_USE_DEFAULT 0x0008 -#define CMD_TYPE_WEP_40_BIT 0x01 -#define CMD_TYPE_WEP_104_BIT 0x02 +#define CMD_TYPE_WEP_40_BIT 0x01 +#define CMD_TYPE_WEP_104_BIT 0x02 -#define CMD_NUM_OF_WEP_KEYS 4 +#define CMD_NUM_OF_WEP_KEYS 4 -#define CMD_WEP_KEY_INDEX_MASK 0x3fff +#define CMD_WEP_KEY_INDEX_MASK 0x3fff /* Define action or option for CMD_802_11_RESET */ -#define CMD_ACT_HALT 0x0003 +#define CMD_ACT_HALT 0x0003 /* Define action or option for CMD_802_11_SCAN */ -#define CMD_BSS_TYPE_BSS 0x0001 -#define CMD_BSS_TYPE_IBSS 0x0002 -#define CMD_BSS_TYPE_ANY 0x0003 +#define CMD_BSS_TYPE_BSS 0x0001 +#define CMD_BSS_TYPE_IBSS 0x0002 +#define CMD_BSS_TYPE_ANY 0x0003 /* Define action or option for CMD_802_11_SCAN */ -#define CMD_SCAN_TYPE_ACTIVE 0x0000 -#define CMD_SCAN_TYPE_PASSIVE 0x0001 +#define CMD_SCAN_TYPE_ACTIVE 0x0000 +#define CMD_SCAN_TYPE_PASSIVE 0x0001 #define CMD_SCAN_RADIO_TYPE_BG 0 -#define CMD_SCAN_PROBE_DELAY_TIME 0 +#define CMD_SCAN_PROBE_DELAY_TIME 0 /* Define action or option for CMD_MAC_CONTROL */ -#define CMD_ACT_MAC_RX_ON 0x0001 -#define CMD_ACT_MAC_TX_ON 0x0002 -#define CMD_ACT_MAC_LOOPBACK_ON 0x0004 -#define CMD_ACT_MAC_WEP_ENABLE 0x0008 -#define CMD_ACT_MAC_INT_ENABLE 0x0010 -#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 -#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 -#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 -#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 -#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 +#define CMD_ACT_MAC_RX_ON 0x0001 +#define CMD_ACT_MAC_TX_ON 0x0002 +#define CMD_ACT_MAC_LOOPBACK_ON 0x0004 +#define CMD_ACT_MAC_WEP_ENABLE 0x0008 +#define CMD_ACT_MAC_INT_ENABLE 0x0010 +#define CMD_ACT_MAC_MULTICAST_ENABLE 0x0020 +#define CMD_ACT_MAC_BROADCAST_ENABLE 0x0040 +#define CMD_ACT_MAC_PROMISCUOUS_ENABLE 0x0080 +#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100 +#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE 0x0400 /* Define action or option for CMD_802_11_RADIO_CONTROL */ -#define CMD_TYPE_AUTO_PREAMBLE 0x0001 -#define CMD_TYPE_SHORT_PREAMBLE 0x0002 -#define CMD_TYPE_LONG_PREAMBLE 0x0003 - -#define TURN_ON_RF 0x01 -#define RADIO_ON 0x01 -#define RADIO_OFF 0x00 - -#define SET_AUTO_PREAMBLE 0x05 -#define SET_SHORT_PREAMBLE 0x03 -#define SET_LONG_PREAMBLE 0x01 +#define CMD_TYPE_AUTO_PREAMBLE 0x0001 +#define CMD_TYPE_SHORT_PREAMBLE 0x0002 +#define CMD_TYPE_LONG_PREAMBLE 0x0003 + +/* Event flags for CMD_802_11_SUBSCRIBE_EVENT */ +#define CMD_SUBSCRIBE_RSSI_LOW 0x0001 +#define CMD_SUBSCRIBE_SNR_LOW 0x0002 +#define CMD_SUBSCRIBE_FAILCOUNT 0x0004 +#define CMD_SUBSCRIBE_BCNMISS 0x0008 +#define CMD_SUBSCRIBE_RSSI_HIGH 0x0010 +#define CMD_SUBSCRIBE_SNR_HIGH 0x0020 + +#define TURN_ON_RF 0x01 +#define RADIO_ON 0x01 +#define RADIO_OFF 0x00 + +#define SET_AUTO_PREAMBLE 0x05 +#define SET_SHORT_PREAMBLE 0x03 +#define SET_LONG_PREAMBLE 0x01 /* Define action or option for CMD_802_11_RF_CHANNEL */ -#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 -#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 +#define CMD_OPT_802_11_RF_CHANNEL_GET 0x00 +#define CMD_OPT_802_11_RF_CHANNEL_SET 0x01 /* Define action or option for CMD_802_11_RF_TX_POWER */ -#define CMD_ACT_TX_POWER_OPT_GET 0x0000 -#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 -#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 -#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 +#define CMD_ACT_TX_POWER_OPT_GET 0x0000 +#define CMD_ACT_TX_POWER_OPT_SET_HIGH 0x8007 +#define CMD_ACT_TX_POWER_OPT_SET_MID 0x8004 +#define CMD_ACT_TX_POWER_OPT_SET_LOW 0x8000 -#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 -#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 -#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 +#define CMD_ACT_TX_POWER_INDEX_HIGH 0x0007 +#define CMD_ACT_TX_POWER_INDEX_MID 0x0004 +#define CMD_ACT_TX_POWER_INDEX_LOW 0x0000 /* Define action or option for CMD_802_11_DATA_RATE */ -#define CMD_ACT_SET_TX_AUTO 0x0000 -#define CMD_ACT_SET_TX_FIX_RATE 0x0001 -#define CMD_ACT_GET_TX_RATE 0x0002 +#define CMD_ACT_SET_TX_AUTO 0x0000 +#define CMD_ACT_SET_TX_FIX_RATE 0x0001 +#define CMD_ACT_GET_TX_RATE 0x0002 -#define CMD_ACT_SET_RX 0x0001 -#define CMD_ACT_SET_TX 0x0002 -#define CMD_ACT_SET_BOTH 0x0003 -#define CMD_ACT_GET_RX 0x0004 -#define CMD_ACT_GET_TX 0x0008 -#define CMD_ACT_GET_BOTH 0x000c +#define CMD_ACT_SET_RX 0x0001 +#define CMD_ACT_SET_TX 0x0002 +#define CMD_ACT_SET_BOTH 0x0003 +#define CMD_ACT_GET_RX 0x0004 +#define CMD_ACT_GET_TX 0x0008 +#define CMD_ACT_GET_BOTH 0x000c /* Define action or option for CMD_802_11_PS_MODE */ -#define CMD_TYPE_CAM 0x0000 -#define CMD_TYPE_MAX_PSP 0x0001 -#define CMD_TYPE_FAST_PSP 0x0002 +#define CMD_TYPE_CAM 0x0000 +#define CMD_TYPE_MAX_PSP 0x0001 +#define CMD_TYPE_FAST_PSP 0x0002 + +/* Options for CMD_802_11_FW_WAKE_METHOD */ +#define CMD_WAKE_METHOD_UNCHANGED 0x0000 +#define CMD_WAKE_METHOD_COMMAND_INT 0x0001 +#define CMD_WAKE_METHOD_GPIO 0x0002 /* Define action or option for CMD_BT_ACCESS */ enum cmd_bt_access_opts { @@ -237,8 +234,8 @@ enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_DEL, CMD_ACT_FWT_ACCESS_LOOKUP, CMD_ACT_FWT_ACCESS_LIST, - CMD_ACT_FWT_ACCESS_LIST_route, - CMD_ACT_FWT_ACCESS_LIST_neighbor, + CMD_ACT_FWT_ACCESS_LIST_ROUTE, + CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR, CMD_ACT_FWT_ACCESS_RESET, CMD_ACT_FWT_ACCESS_CLEANUP, CMD_ACT_FWT_ACCESS_TIME, @@ -264,27 +261,36 @@ enum cmd_mesh_access_opts { }; /** Card Event definition */ -#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000 -#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001 -#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002 -#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003 -#define MACREG_INT_CODE_LINK_SENSED 0x00000004 -#define MACREG_INT_CODE_CMD_FINISHED 0x00000005 -#define MACREG_INT_CODE_MIB_CHANGED 0x00000006 -#define MACREG_INT_CODE_INIT_DONE 0x00000007 -#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008 -#define MACREG_INT_CODE_DISASSOCIATED 0x00000009 -#define MACREG_INT_CODE_PS_AWAKE 0x0000000a -#define MACREG_INT_CODE_PS_SLEEP 0x0000000b -#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d -#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e -#define MACREG_INT_CODE_WM_AWAKE 0x0000000f -#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011 -#define MACREG_INT_CODE_RSSI_LOW 0x00000019 -#define MACREG_INT_CODE_SNR_LOW 0x0000001a -#define MACREG_INT_CODE_MAX_FAIL 0x0000001b -#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c -#define MACREG_INT_CODE_SNR_HIGH 0x0000001d -#define MACREG_INT_CODE_MESH_AUTO_STARTED 0x00000023 - -#endif /* _HOST_H_ */ +#define MACREG_INT_CODE_TX_PPA_FREE 0 +#define MACREG_INT_CODE_TX_DMA_DONE 1 +#define MACREG_INT_CODE_LINK_LOST_W_SCAN 2 +#define MACREG_INT_CODE_LINK_LOST_NO_SCAN 3 +#define MACREG_INT_CODE_LINK_SENSED 4 +#define MACREG_INT_CODE_CMD_FINISHED 5 +#define MACREG_INT_CODE_MIB_CHANGED 6 +#define MACREG_INT_CODE_INIT_DONE 7 +#define MACREG_INT_CODE_DEAUTHENTICATED 8 +#define MACREG_INT_CODE_DISASSOCIATED 9 +#define MACREG_INT_CODE_PS_AWAKE 10 +#define MACREG_INT_CODE_PS_SLEEP 11 +#define MACREG_INT_CODE_MIC_ERR_MULTICAST 13 +#define MACREG_INT_CODE_MIC_ERR_UNICAST 14 +#define MACREG_INT_CODE_WM_AWAKE 15 +#define MACREG_INT_CODE_DEEP_SLEEP_AWAKE 16 +#define MACREG_INT_CODE_ADHOC_BCN_LOST 17 +#define MACREG_INT_CODE_HOST_AWAKE 18 +#define MACREG_INT_CODE_STOP_TX 19 +#define MACREG_INT_CODE_START_TX 20 +#define MACREG_INT_CODE_CHANNEL_SWITCH 21 +#define MACREG_INT_CODE_MEASUREMENT_RDY 22 +#define MACREG_INT_CODE_WMM_CHANGE 23 +#define MACREG_INT_CODE_BG_SCAN_REPORT 24 +#define MACREG_INT_CODE_RSSI_LOW 25 +#define MACREG_INT_CODE_SNR_LOW 26 +#define MACREG_INT_CODE_MAX_FAIL 27 +#define MACREG_INT_CODE_RSSI_HIGH 28 +#define MACREG_INT_CODE_SNR_HIGH 29 +#define MACREG_INT_CODE_MESH_AUTO_STARTED 35 +#define MACREG_INT_CODE_FIRMWARE_READY 48 + +#endif diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index e1045dc02cce..d35b015b6657 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -2,8 +2,8 @@ * This file contains the function prototypes, data structure * and defines for all the host/station commands */ -#ifndef __HOSTCMD__H -#define __HOSTCMD__H +#ifndef _LBS_HOSTCMD_H +#define _LBS_HOSTCMD_H #include <linux/wireless.h> #include "11d.h" @@ -65,19 +65,21 @@ struct rxpd { u8 reserved[3]; }; +struct cmd_header { + __le16 command; + __le16 size; + __le16 seqnum; + __le16 result; +} __attribute__ ((packed)); + struct cmd_ctrl_node { - /* CMD link list */ struct list_head list; - u32 status; - /* CMD ID */ - u32 cmd_oid; - /*CMD wait option: wait for finish or no wait */ - u16 wait_option; - /* command parameter */ - void *pdata_buf; - /*command data */ - u8 *bufvirtualaddr; - u16 cmdflags; + int result; + /* command response */ + int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *); + unsigned long callback_arg; + /* command data */ + struct cmd_header *cmdbuf; /* wait queue */ u16 cmdwaitqwoken; wait_queue_head_t cmdwait_q; @@ -86,13 +88,13 @@ struct cmd_ctrl_node { /* Generic structure to hold all key types. */ struct enc_key { u16 len; - u16 flags; /* KEY_INFO_* from wlan_defs.h */ - u16 type; /* KEY_TYPE_* from wlan_defs.h */ + u16 flags; /* KEY_INFO_* from defs.h */ + u16 type; /* KEY_TYPE_* from defs.h */ u8 key[32]; }; -/* wlan_offset_value */ -struct wlan_offset_value { +/* lbs_offset_value */ +struct lbs_offset_value { u32 offset; u32 value; }; @@ -104,14 +106,19 @@ struct cmd_ds_gen { __le16 size; __le16 seqnum; __le16 result; + void *cmdresp[0]; }; #define S_DS_GEN sizeof(struct cmd_ds_gen) + + /* * Define data structure for CMD_GET_HW_SPEC * This structure defines the response for the GET_HW_SPEC command */ struct cmd_ds_get_hw_spec { + struct cmd_header hdr; + /* HW Interface version number */ __le16 hwifversion; /* HW version number */ @@ -129,8 +136,8 @@ struct cmd_ds_get_hw_spec { /* Number of antenna used */ __le16 nr_antenna; - /* FW release number, example 1,2,3,4 = 3.2.1p4 */ - u8 fwreleasenumber[4]; + /* FW release number, example 0x01030304 = 2.3.4p1 */ + __le32 fwrelease; /* Base Address of TxPD queue */ __le32 wcb_base; @@ -149,8 +156,17 @@ struct cmd_ds_802_11_reset { }; struct cmd_ds_802_11_subscribe_event { + struct cmd_header hdr; + __le16 action; __le16 events; + + /* A TLV to the CMD_802_11_SUBSCRIBE_EVENT command can contain a + * number of TLVs. From the v5.1 manual, those TLVs would add up to + * 40 bytes. However, future firmware might add additional TLVs, so I + * bump this up a bit. + */ + uint8_t tlv[128]; }; /* @@ -242,6 +258,8 @@ struct cmd_ds_802_11_ad_hoc_result { }; struct cmd_ds_802_11_set_wep { + struct cmd_header hdr; + /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ __le16 action; @@ -249,8 +267,8 @@ struct cmd_ds_802_11_set_wep { __le16 keyindex; /* 40, 128bit or TXWEP */ - u8 keytype[4]; - u8 keymaterial[4][16]; + uint8_t keytype[4]; + uint8_t keymaterial[4][16]; }; struct cmd_ds_802_3_get_stat { @@ -328,11 +346,21 @@ struct cmd_ds_rf_reg_access { }; struct cmd_ds_802_11_radio_control { + struct cmd_header hdr; + __le16 action; __le16 control; }; +struct cmd_ds_802_11_beacon_control { + __le16 action; + __le16 beacon_enable; + __le16 beacon_period; +}; + struct cmd_ds_802_11_sleep_params { + struct cmd_header hdr; + /* ACT_GET/ACT_SET */ __le16 action; @@ -346,16 +374,18 @@ struct cmd_ds_802_11_sleep_params { __le16 stabletime; /* control periodic calibration */ - u8 calcontrol; + uint8_t calcontrol; /* control the use of external sleep clock */ - u8 externalsleepclk; + uint8_t externalsleepclk; /* reserved field, should be set to zero */ __le16 reserved; }; struct cmd_ds_802_11_inactivity_timeout { + struct cmd_header hdr; + /* ACT_GET/ACT_SET */ __le16 action; @@ -364,11 +394,13 @@ struct cmd_ds_802_11_inactivity_timeout { }; struct cmd_ds_802_11_rf_channel { + struct cmd_header hdr; + __le16 action; - __le16 currentchannel; - __le16 rftype; - __le16 reserved; - u8 channellist[32]; + __le16 channel; + __le16 rftype; /* unused */ + __le16 reserved; /* unused */ + u8 channellist[32]; /* unused */ }; struct cmd_ds_802_11_rssi { @@ -406,13 +438,29 @@ struct cmd_ds_802_11_rf_antenna { }; struct cmd_ds_802_11_monitor_mode { - u16 action; - u16 mode; + __le16 action; + __le16 mode; }; struct cmd_ds_set_boot2_ver { - u16 action; - u16 version; + struct cmd_header hdr; + + __le16 action; + __le16 version; +}; + +struct cmd_ds_802_11_fw_wake_method { + struct cmd_header hdr; + + __le16 action; + __le16 method; +}; + +struct cmd_ds_802_11_sleep_period { + struct cmd_header hdr; + + __le16 action; + __le16 period; }; struct cmd_ds_802_11_ps_mode { @@ -437,6 +485,8 @@ struct PS_CMD_ConfirmSleep { }; struct cmd_ds_802_11_data_rate { + struct cmd_header hdr; + __le16 action; __le16 reserved; u8 rates[MAX_RATES]; @@ -488,6 +538,8 @@ struct cmd_ds_802_11_ad_hoc_join { } __attribute__ ((packed)); struct cmd_ds_802_11_enable_rsn { + struct cmd_header hdr; + __le16 action; __le16 enable; } __attribute__ ((packed)); @@ -512,6 +564,13 @@ struct MrvlIEtype_keyParamSet { u8 key[32]; }; +struct cmd_ds_host_sleep { + struct cmd_header hdr; + __le32 criteria; + uint8_t gpio; + uint8_t gap; +} __attribute__ ((packed)); + struct cmd_ds_802_11_key_material { __le16 action; struct MrvlIEtype_keyParamSet keyParamSet[2]; @@ -598,7 +657,21 @@ struct cmd_ds_fwt_access { u8 prec[ETH_ALEN]; } __attribute__ ((packed)); + +struct cmd_ds_mesh_config { + struct cmd_header hdr; + + __le16 action; + __le16 channel; + __le16 type; + __le16 length; + u8 data[128]; /* last position reserved */ +} __attribute__ ((packed)); + + struct cmd_ds_mesh_access { + struct cmd_header hdr; + __le16 action; __le32 data[32]; /* last position reserved */ } __attribute__ ((packed)); @@ -615,14 +688,12 @@ struct cmd_ds_command { /* command Body */ union { - struct cmd_ds_get_hw_spec hwspec; struct cmd_ds_802_11_ps_mode psmode; struct cmd_ds_802_11_scan scan; struct cmd_ds_802_11_scan_rsp scanresp; struct cmd_ds_mac_control macctrl; struct cmd_ds_802_11_associate associate; struct cmd_ds_802_11_deauthenticate deauth; - struct cmd_ds_802_11_set_wep wep; struct cmd_ds_802_11_ad_hoc_start ads; struct cmd_ds_802_11_reset reset; struct cmd_ds_802_11_ad_hoc_result result; @@ -634,17 +705,13 @@ struct cmd_ds_command { struct cmd_ds_802_11_rf_tx_power txp; struct cmd_ds_802_11_rf_antenna rant; struct cmd_ds_802_11_monitor_mode monitor; - struct cmd_ds_802_11_data_rate drate; struct cmd_ds_802_11_rate_adapt_rateset rateset; struct cmd_ds_mac_multicast_adr madr; struct cmd_ds_802_11_ad_hoc_join adj; - struct cmd_ds_802_11_radio_control radio; - struct cmd_ds_802_11_rf_channel rfchannel; struct cmd_ds_802_11_rssi rssi; struct cmd_ds_802_11_rssi_rsp rssirsp; struct cmd_ds_802_11_disassociate dassociate; struct cmd_ds_802_11_mac_address macadd; - struct cmd_ds_802_11_enable_rsn enbrsn; struct cmd_ds_802_11_key_material keymaterial; struct cmd_ds_mac_reg_access macreg; struct cmd_ds_bbp_reg_access bbpreg; @@ -654,8 +721,6 @@ struct cmd_ds_command { struct cmd_ds_802_11d_domain_info domaininfo; struct cmd_ds_802_11d_domain_info domaininforesp; - struct cmd_ds_802_11_sleep_params sleep_params; - struct cmd_ds_802_11_inactivity_timeout inactivity_timeout; struct cmd_ds_802_11_tpc_cfg tpccfg; struct cmd_ds_802_11_pwr_cfg pwrcfg; struct cmd_ds_802_11_afc afc; @@ -664,10 +729,8 @@ struct cmd_ds_command { struct cmd_tx_rate_query txrate; struct cmd_ds_bt_access bt; struct cmd_ds_fwt_access fwt; - struct cmd_ds_mesh_access mesh; - struct cmd_ds_set_boot2_ver boot2_ver; struct cmd_ds_get_tsf gettsf; - struct cmd_ds_802_11_subscribe_event subscribe_event; + struct cmd_ds_802_11_beacon_control bcn_ctrl; } params; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index ba4fc2b3bf0a..4b5ab9a6b97b 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -57,7 +57,7 @@ MODULE_LICENSE("GPL"); struct if_cs_card { struct pcmcia_device *p_dev; - wlan_private *priv; + struct lbs_private *priv; void __iomem *iobase; }; @@ -243,7 +243,7 @@ static inline void if_cs_disable_ints(struct if_cs_card *card) static irqreturn_t if_cs_interrupt(int irq, void *data) { - struct if_cs_card *card = (struct if_cs_card *)data; + struct if_cs_card *card = data; u16 int_cause; lbs_deb_enter(LBS_DEB_CS); @@ -253,25 +253,20 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) /* Not for us */ return IRQ_NONE; - } else if(int_cause == 0xffff) { + } else if (int_cause == 0xffff) { /* Read in junk, the card has probably been removed */ - card->priv->adapter->surpriseremoved = 1; + card->priv->surpriseremoved = 1; } else { - if(int_cause & IF_CS_H_IC_TX_OVER) { - card->priv->dnld_sent = DNLD_RES_RECEIVED; - if (!card->priv->adapter->cur_cmd) - wake_up_interruptible(&card->priv->waitq); - - if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED) - netif_wake_queue(card->priv->dev); - } + if (int_cause & IF_CS_H_IC_TX_OVER) + lbs_host_to_card_done(card->priv); /* clear interrupt */ if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK); } - - libertas_interrupt(card->priv->dev); + spin_lock(&card->priv->driver_lock); + lbs_interrupt(card->priv); + spin_unlock(&card->priv->driver_lock); return IRQ_HANDLED; } @@ -286,7 +281,7 @@ static irqreturn_t if_cs_interrupt(int irq, void *data) /* * Called from if_cs_host_to_card to send a command to the hardware */ -static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb) +static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb) { struct if_cs_card *card = (struct if_cs_card *)priv->card; int ret = -1; @@ -331,7 +326,7 @@ done: /* * Called from if_cs_host_to_card to send a data to the hardware */ -static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb) +static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb) { struct if_cs_card *card = (struct if_cs_card *)priv->card; @@ -354,7 +349,7 @@ static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb) /* * Get the command result out of the card. */ -static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len) +static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) { int ret = -1; u16 val; @@ -369,7 +364,7 @@ static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len) } *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); - if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) { + if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); goto out; } @@ -379,6 +374,9 @@ static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len) if (*len & 1) data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); + /* This is a workaround for a firmware that reports too much + * bytes */ + *len -= 8; ret = 0; out: lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len); @@ -386,7 +384,7 @@ out: } -static struct sk_buff *if_cs_receive_data(wlan_private *priv) +static struct sk_buff *if_cs_receive_data(struct lbs_private *priv) { struct sk_buff *skb = NULL; u16 len; @@ -616,7 +614,10 @@ done: /********************************************************************/ /* Send commands or data packets to the card */ -static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) +static int if_cs_host_to_card(struct lbs_private *priv, + u8 type, + u8 *buf, + u16 nb) { int ret = -1; @@ -641,18 +642,16 @@ static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) } -static int if_cs_get_int_status(wlan_private *priv, u8 *ireg) +static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg) { struct if_cs_card *card = (struct if_cs_card *)priv->card; - //wlan_adapter *adapter = priv->adapter; int ret = 0; u16 int_cause; - u8 *cmdbuf; *ireg = 0; lbs_deb_enter(LBS_DEB_CS); - if (priv->adapter->surpriseremoved) + if (priv->surpriseremoved) goto out; int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK; @@ -668,7 +667,7 @@ sbi_get_int_status_exit: /* is there a data packet for us? */ if (*ireg & IF_CS_C_S_RX_UPLD_RDY) { struct sk_buff *skb = if_cs_receive_data(priv); - libertas_process_rxed_packet(priv, skb); + lbs_process_rxed_packet(priv, skb); *ireg &= ~IF_CS_C_S_RX_UPLD_RDY; } @@ -678,31 +677,24 @@ sbi_get_int_status_exit: /* Card has a command result for us */ if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) { - spin_lock(&priv->adapter->driver_lock); - if (!priv->adapter->cur_cmd) { - cmdbuf = priv->upld_buf; - priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY; - } else { - cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; - } - - ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len); - spin_unlock(&priv->adapter->driver_lock); + spin_lock(&priv->driver_lock); + ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len); + spin_unlock(&priv->driver_lock); if (ret < 0) lbs_pr_err("could not receive cmd from card\n"); } out: - lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy); + lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy); return ret; } -static int if_cs_read_event_cause(wlan_private *priv) +static int if_cs_read_event_cause(struct lbs_private *priv) { lbs_deb_enter(LBS_DEB_CS); - priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5; + priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5; if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT); return 0; @@ -746,7 +738,7 @@ static void if_cs_release(struct pcmcia_device *p_dev) static int if_cs_probe(struct pcmcia_device *p_dev) { int ret = -ENOMEM; - wlan_private *priv; + struct lbs_private *priv; struct if_cs_card *card; /* CIS parsing */ tuple_t tuple; @@ -856,7 +848,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out2; /* Make this card known to the libertas driver */ - priv = libertas_add_card(card, &p_dev->dev); + priv = lbs_add_card(card, &p_dev->dev); if (!priv) { ret = -ENOMEM; goto out2; @@ -869,7 +861,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) priv->hw_get_int_status = if_cs_get_int_status; priv->hw_read_event_cause = if_cs_read_event_cause; - priv->adapter->fw_ready = 1; + priv->fw_ready = 1; /* Now actually get the IRQ */ ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt, @@ -885,7 +877,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) if_cs_enable_ints(card); /* And finally bring the card up */ - if (libertas_start_card(priv) != 0) { + if (lbs_start_card(priv) != 0) { lbs_pr_err("could not activate card\n"); goto out3; } @@ -894,7 +886,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev) goto out; out3: - libertas_remove_card(priv); + lbs_remove_card(priv); out2: ioport_unmap(card->iobase); out1: @@ -917,8 +909,8 @@ static void if_cs_detach(struct pcmcia_device *p_dev) lbs_deb_enter(LBS_DEB_CS); - libertas_stop_card(card->priv); - libertas_remove_card(card->priv); + lbs_stop_card(card->priv); + lbs_remove_card(card->priv); if_cs_disable_ints(card); if_cs_release(p_dev); kfree(card); @@ -939,7 +931,7 @@ static struct pcmcia_device_id if_cs_ids[] = { MODULE_DEVICE_TABLE(pcmcia, if_cs_ids); -static struct pcmcia_driver libertas_driver = { +static struct pcmcia_driver lbs_driver = { .owner = THIS_MODULE, .drv = { .name = DRV_NAME, @@ -955,7 +947,7 @@ static int __init if_cs_init(void) int ret; lbs_deb_enter(LBS_DEB_CS); - ret = pcmcia_register_driver(&libertas_driver); + ret = pcmcia_register_driver(&lbs_driver); lbs_deb_leave(LBS_DEB_CS); return ret; } @@ -964,7 +956,7 @@ static int __init if_cs_init(void) static void __exit if_cs_exit(void) { lbs_deb_enter(LBS_DEB_CS); - pcmcia_unregister_driver(&libertas_driver); + pcmcia_unregister_driver(&lbs_driver); lbs_deb_leave(LBS_DEB_CS); } diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 4f1efb108c28..eed73204bcc9 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -19,7 +19,7 @@ * current block size. * * As SDIO is still new to the kernel, it is unfortunately common with - * bugs in the host controllers related to that. One such bug is that + * bugs in the host controllers related to that. One such bug is that * controllers cannot do transfers that aren't a multiple of 4 bytes. * If you don't have time to fix the host controller driver, you can * work around the problem by modifying if_sdio_host_to_card() and @@ -40,11 +40,11 @@ #include "dev.h" #include "if_sdio.h" -static char *libertas_helper_name = NULL; -module_param_named(helper_name, libertas_helper_name, charp, 0644); +static char *lbs_helper_name = NULL; +module_param_named(helper_name, lbs_helper_name, charp, 0644); -static char *libertas_fw_name = NULL; -module_param_named(fw_name, libertas_fw_name, charp, 0644); +static char *lbs_fw_name = NULL; +module_param_named(fw_name, lbs_fw_name, charp, 0644); static const struct sdio_device_id if_sdio_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_LIBERTAS) }, @@ -82,7 +82,7 @@ struct if_sdio_packet { struct if_sdio_card { struct sdio_func *func; - wlan_private *priv; + struct lbs_private *priv; int model; unsigned long ioport; @@ -134,32 +134,26 @@ static int if_sdio_handle_cmd(struct if_sdio_card *card, lbs_deb_enter(LBS_DEB_SDIO); - spin_lock_irqsave(&card->priv->adapter->driver_lock, flags); + spin_lock_irqsave(&card->priv->driver_lock, flags); - if (!card->priv->adapter->cur_cmd) { - lbs_deb_sdio("discarding spurious response\n"); - ret = 0; - goto out; - } - - if (size > MRVDRV_SIZE_OF_CMD_BUFFER) { + if (size > LBS_CMD_BUFFER_SIZE) { lbs_deb_sdio("response packet too large (%d bytes)\n", (int)size); ret = -E2BIG; goto out; } - memcpy(card->priv->adapter->cur_cmd->bufvirtualaddr, buffer, size); + memcpy(card->priv->upld_buf, buffer, size); card->priv->upld_len = size; card->int_cause |= MRVDRV_CMD_UPLD_RDY; - libertas_interrupt(card->priv->dev); + lbs_interrupt(card->priv); ret = 0; out: - spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags); + spin_unlock_irqrestore(&card->priv->driver_lock, flags); lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -194,7 +188,7 @@ static int if_sdio_handle_data(struct if_sdio_card *card, memcpy(data, buffer, size); - libertas_process_rxed_packet(card->priv, skb); + lbs_process_rxed_packet(card->priv, skb); ret = 0; @@ -231,14 +225,14 @@ static int if_sdio_handle_event(struct if_sdio_card *card, event <<= SBI_EVENT_CAUSE_SHIFT; } - spin_lock_irqsave(&card->priv->adapter->driver_lock, flags); + spin_lock_irqsave(&card->priv->driver_lock, flags); card->event = event; card->int_cause |= MRVDRV_CARDEVENT; - libertas_interrupt(card->priv->dev); + lbs_interrupt(card->priv); - spin_unlock_irqrestore(&card->priv->adapter->driver_lock, flags); + spin_unlock_irqrestore(&card->priv->driver_lock, flags); ret = 0; @@ -454,7 +448,7 @@ static int if_sdio_prog_helper(struct if_sdio_card *card) chunk_size = min(size, (size_t)60); - *((u32*)chunk_buffer) = cpu_to_le32(chunk_size); + *((__le32*)chunk_buffer) = cpu_to_le32(chunk_size); memcpy(chunk_buffer + 4, firmware, chunk_size); /* lbs_deb_sdio("sending %d bytes chunk\n", chunk_size); @@ -694,7 +688,8 @@ out: /* Libertas callbacks */ /*******************************************************************/ -static int if_sdio_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb) +static int if_sdio_host_to_card(struct lbs_private *priv, + u8 type, u8 *buf, u16 nb) { int ret; struct if_sdio_card *card; @@ -775,7 +770,7 @@ out: return ret; } -static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg) +static int if_sdio_get_int_status(struct lbs_private *priv, u8 *ireg) { struct if_sdio_card *card; @@ -791,7 +786,7 @@ static int if_sdio_get_int_status(wlan_private *priv, u8 *ireg) return 0; } -static int if_sdio_read_event_cause(wlan_private *priv) +static int if_sdio_read_event_cause(struct lbs_private *priv) { struct if_sdio_card *card; @@ -799,7 +794,7 @@ static int if_sdio_read_event_cause(wlan_private *priv) card = priv->card; - priv->adapter->eventcause = card->event; + priv->eventcause = card->event; lbs_deb_leave(LBS_DEB_SDIO); @@ -834,12 +829,9 @@ static void if_sdio_interrupt(struct sdio_func *func) * Ignore the define name, this really means the card has * successfully received the command. */ - if (cause & IF_SDIO_H_INT_DNLD) { - if ((card->priv->dnld_sent == DNLD_DATA_SENT) && - (card->priv->adapter->connect_status == LIBERTAS_CONNECTED)) - netif_wake_queue(card->priv->dev); - card->priv->dnld_sent = DNLD_RES_RECEIVED; - } + if (cause & IF_SDIO_H_INT_DNLD) + lbs_host_to_card_done(card->priv); + if (cause & IF_SDIO_H_INT_UPLD) { ret = if_sdio_card_to_host(card); @@ -857,7 +849,7 @@ static int if_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { struct if_sdio_card *card; - wlan_private *priv; + struct lbs_private *priv; int ret, i; unsigned int model; struct if_sdio_packet *packet; @@ -905,15 +897,15 @@ static int if_sdio_probe(struct sdio_func *func, card->helper = if_sdio_models[i].helper; card->firmware = if_sdio_models[i].firmware; - if (libertas_helper_name) { + if (lbs_helper_name) { lbs_deb_sdio("overriding helper firmware: %s\n", - libertas_helper_name); - card->helper = libertas_helper_name; + lbs_helper_name); + card->helper = lbs_helper_name; } - if (libertas_fw_name) { - lbs_deb_sdio("overriding firmware: %s\n", libertas_fw_name); - card->firmware = libertas_fw_name; + if (lbs_fw_name) { + lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name); + card->firmware = lbs_fw_name; } sdio_claim_host(func); @@ -951,7 +943,7 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto reclaim; - priv = libertas_add_card(card, &func->dev); + priv = lbs_add_card(card, &func->dev); if (!priv) { ret = -ENOMEM; goto reclaim; @@ -964,7 +956,7 @@ static int if_sdio_probe(struct sdio_func *func, priv->hw_get_int_status = if_sdio_get_int_status; priv->hw_read_event_cause = if_sdio_read_event_cause; - priv->adapter->fw_ready = 1; + priv->fw_ready = 1; /* * Enable interrupts now that everything is set up @@ -975,7 +967,7 @@ static int if_sdio_probe(struct sdio_func *func, if (ret) goto reclaim; - ret = libertas_start_card(priv); + ret = lbs_start_card(priv); if (ret) goto err_activate_card; @@ -987,7 +979,7 @@ out: err_activate_card: flush_scheduled_work(); free_netdev(priv->dev); - kfree(priv->adapter); + kfree(priv); reclaim: sdio_claim_host(func); release_int: @@ -1017,11 +1009,11 @@ static void if_sdio_remove(struct sdio_func *func) card = sdio_get_drvdata(func); - card->priv->adapter->surpriseremoved = 1; + card->priv->surpriseremoved = 1; lbs_deb_sdio("call remove card\n"); - libertas_stop_card(card->priv); - libertas_remove_card(card->priv); + lbs_stop_card(card->priv); + lbs_remove_card(card->priv); flush_scheduled_work(); @@ -1052,7 +1044,7 @@ static struct sdio_driver if_sdio_driver = { /* Module functions */ /*******************************************************************/ -static int if_sdio_init_module(void) +static int __init if_sdio_init_module(void) { int ret = 0; @@ -1068,7 +1060,7 @@ static int if_sdio_init_module(void) return ret; } -static void if_sdio_exit_module(void) +static void __exit if_sdio_exit_module(void) { lbs_deb_enter(LBS_DEB_SDIO); diff --git a/drivers/net/wireless/libertas/if_sdio.h b/drivers/net/wireless/libertas/if_sdio.h index dfcaea7b168f..533bdfbf5d2a 100644 --- a/drivers/net/wireless/libertas/if_sdio.h +++ b/drivers/net/wireless/libertas/if_sdio.h @@ -9,8 +9,8 @@ * your option) any later version. */ -#ifndef LIBERTAS_IF_SDIO_H -#define LIBERTAS_IF_SDIO_H +#ifndef _LBS_IF_SDIO_H +#define _LBS_IF_SDIO_H #define IF_SDIO_IOPORT 0x00 diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cb59f46ed126..75aed9d07367 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -5,7 +5,6 @@ #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/netdevice.h> -#include <linux/list.h> #include <linux/usb.h> #define DRV_NAME "usb8xxx" @@ -14,24 +13,16 @@ #include "decl.h" #include "defs.h" #include "dev.h" +#include "cmd.h" #include "if_usb.h" -#define MESSAGE_HEADER_LEN 4 - -static const char usbdriver_name[] = "usb8xxx"; -static u8 *default_fw_name = "usb8388.bin"; +#define INSANEDEBUG 0 +#define lbs_deb_usb2(...) do { if (INSANEDEBUG) lbs_deb_usbd(__VA_ARGS__); } while (0) -static char *libertas_fw_name = NULL; -module_param_named(fw_name, libertas_fw_name, charp, 0644); +#define MESSAGE_HEADER_LEN 4 -/* - * We need to send a RESET command to all USB devices before - * we tear down the USB connection. Otherwise we would not - * be able to re-init device the device if the module gets - * loaded again. This is a list of all initialized USB devices, - * for the reset code see if_usb_reset_device() -*/ -static LIST_HEAD(usb_devices); +static char *lbs_fw_name = "usb8388.bin"; +module_param_named(fw_name, lbs_fw_name, charp, 0644); static struct usb_device_id if_usb_table[] = { /* Enter the device signature inside */ @@ -44,14 +35,16 @@ MODULE_DEVICE_TABLE(usb, if_usb_table); static void if_usb_receive(struct urb *urb); static void if_usb_receive_fwload(struct urb *urb); -static int if_usb_prog_firmware(struct usb_card_rec *cardp); -static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); -static int if_usb_get_int_status(wlan_private * priv, u8 *); -static int if_usb_read_event_cause(wlan_private *); -static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb); -static void if_usb_free(struct usb_card_rec *cardp); -static int if_usb_submit_rx_urb(struct usb_card_rec *cardp); -static int if_usb_reset_device(struct usb_card_rec *cardp); +static int if_usb_prog_firmware(struct if_usb_card *cardp); +static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb); +static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *); +static int if_usb_read_event_cause(struct lbs_private *); +static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, + uint16_t nb); +static void if_usb_free(struct if_usb_card *cardp); +static int if_usb_submit_rx_urb(struct if_usb_card *cardp); +static int if_usb_reset_device(struct if_usb_card *cardp); /** * @brief call back function to handle the status of the URB @@ -60,37 +53,22 @@ static int if_usb_reset_device(struct usb_card_rec *cardp); */ static void if_usb_write_bulk_callback(struct urb *urb) { - struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context; + struct if_usb_card *cardp = (struct if_usb_card *) urb->context; /* handle the transmission complete validations */ if (urb->status == 0) { - wlan_private *priv = cardp->priv; + struct lbs_private *priv = cardp->priv; - /* - lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n"); - lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n", - urb->actual_length); - */ + lbs_deb_usb2(&urb->dev->dev, "URB status is successful\n"); + lbs_deb_usb2(&urb->dev->dev, "Actual length transmitted %d\n", + urb->actual_length); /* Used for both firmware TX and regular TX. priv isn't * valid at firmware load time. */ - if (priv) { - wlan_adapter *adapter = priv->adapter; - struct net_device *dev = priv->dev; - - priv->dnld_sent = DNLD_RES_RECEIVED; - - /* Wake main thread if commands are pending */ - if (!adapter->cur_cmd) - wake_up_interruptible(&priv->waitq); - - if ((adapter->connect_status == LIBERTAS_CONNECTED)) { - netif_wake_queue(dev); - netif_wake_queue(priv->mesh_dev); - } - } + if (priv) + lbs_host_to_card_done(priv); } else { /* print the failure status number for debug */ lbs_pr_info("URB in failure status: %d\n", urb->status); @@ -101,10 +79,10 @@ static void if_usb_write_bulk_callback(struct urb *urb) /** * @brief free tx/rx urb, skb and rx buffer - * @param cardp pointer usb_card_rec + * @param cardp pointer if_usb_card * @return N/A */ -static void if_usb_free(struct usb_card_rec *cardp) +static void if_usb_free(struct if_usb_card *cardp) { lbs_deb_enter(LBS_DEB_USB); @@ -118,12 +96,58 @@ static void if_usb_free(struct usb_card_rec *cardp) usb_free_urb(cardp->rx_urb); cardp->rx_urb = NULL; - kfree(cardp->bulk_out_buffer); - cardp->bulk_out_buffer = NULL; + kfree(cardp->ep_out_buf); + cardp->ep_out_buf = NULL; lbs_deb_leave(LBS_DEB_USB); } +static void if_usb_setup_firmware(struct lbs_private *priv) +{ + struct if_usb_card *cardp = priv->card; + struct cmd_ds_set_boot2_ver b2_cmd; + struct cmd_ds_802_11_fw_wake_method wake_method; + + b2_cmd.hdr.size = cpu_to_le16(sizeof(b2_cmd)); + b2_cmd.action = 0; + b2_cmd.version = cardp->boot2_version; + + if (lbs_cmd_with_response(priv, CMD_SET_BOOT2_VER, &b2_cmd)) + lbs_deb_usb("Setting boot2 version failed\n"); + + priv->wol_gpio = 2; /* Wake via GPIO2... */ + priv->wol_gap = 20; /* ... after 20ms */ + lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA); + + wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); + wake_method.action = cpu_to_le16(CMD_ACT_GET); + if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) { + lbs_pr_info("Firmware does not seem to support PS mode\n"); + } else { + if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) { + lbs_deb_usb("Firmware seems to support PS with wake-via-command\n"); + priv->ps_supported = 1; + } else { + /* The versions which boot up this way don't seem to + work even if we set it to the command interrupt */ + lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n"); + } + } +} + +static void if_usb_fw_timeo(unsigned long priv) +{ + struct if_usb_card *cardp = (void *)priv; + + if (cardp->fwdnldover) { + lbs_deb_usb("Download complete, no event. Assuming success\n"); + } else { + lbs_pr_err("Download timed out\n"); + cardp->surprise_removed = 1; + } + wake_up(&cardp->fw_wq); +} + /** * @brief sets the configuration values * @param ifnum interface number @@ -136,23 +160,26 @@ static int if_usb_probe(struct usb_interface *intf, struct usb_device *udev; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - wlan_private *priv; - struct usb_card_rec *cardp; + struct lbs_private *priv; + struct if_usb_card *cardp; int i; udev = interface_to_usbdev(intf); - cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); + cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL); if (!cardp) { lbs_pr_err("Out of memory allocating private data.\n"); goto error; } + setup_timer(&cardp->fw_timeout, if_usb_fw_timeo, (unsigned long)cardp); + init_waitqueue_head(&cardp->fw_wq); + cardp->udev = udev; iface_desc = intf->cur_altsetting; lbs_deb_usbd(&udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" - " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", + " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", le16_to_cpu(udev->descriptor.bcdUSB), udev->descriptor.bDeviceClass, udev->descriptor.bDeviceSubClass, @@ -160,92 +187,62 @@ static int if_usb_probe(struct usb_interface *intf, for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK)) { - /* we found a bulk in endpoint */ - lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", - le16_to_cpu(endpoint->wMaxPacketSize)); - if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) { - lbs_deb_usbd(&udev->dev, - "Rx URB allocation failed\n"); - goto dealloc; - } - cardp->rx_urb_recall = 0; - - cardp->bulk_in_size = - le16_to_cpu(endpoint->wMaxPacketSize); - cardp->bulk_in_endpointAddr = - (endpoint-> - bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); - lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", - endpoint->bEndpointAddress); - } + if (usb_endpoint_is_bulk_in(endpoint)) { + cardp->ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize); + cardp->ep_in = usb_endpoint_num(endpoint); - if (((endpoint-> - bEndpointAddress & USB_ENDPOINT_DIR_MASK) == - USB_DIR_OUT) - && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK)) { - /* We found bulk out endpoint */ - if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) { - lbs_deb_usbd(&udev->dev, - "Tx URB allocation failed\n"); - goto dealloc; - } + lbs_deb_usbd(&udev->dev, "in_endpoint = %d\n", cardp->ep_in); + lbs_deb_usbd(&udev->dev, "Bulk in size is %d\n", cardp->ep_in_size); - cardp->bulk_out_size = - le16_to_cpu(endpoint->wMaxPacketSize); - lbs_deb_usbd(&udev->dev, - "Bulk out size is %d\n", - le16_to_cpu(endpoint->wMaxPacketSize)); - cardp->bulk_out_endpointAddr = - endpoint->bEndpointAddress; - lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", - endpoint->bEndpointAddress); - cardp->bulk_out_buffer = - kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, - GFP_KERNEL); - - if (!cardp->bulk_out_buffer) { - lbs_deb_usbd(&udev->dev, - "Could not allocate buffer\n"); - goto dealloc; - } + } else if (usb_endpoint_is_bulk_out(endpoint)) { + cardp->ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize); + cardp->ep_out = usb_endpoint_num(endpoint); + + lbs_deb_usbd(&udev->dev, "out_endpoint = %d\n", cardp->ep_out); + lbs_deb_usbd(&udev->dev, "Bulk out size is %d\n", cardp->ep_out_size); } } + if (!cardp->ep_out_size || !cardp->ep_in_size) { + lbs_deb_usbd(&udev->dev, "Endpoints not found\n"); + goto dealloc; + } + if (!(cardp->rx_urb = usb_alloc_urb(0, GFP_KERNEL))) { + lbs_deb_usbd(&udev->dev, "Rx URB allocation failed\n"); + goto dealloc; + } + if (!(cardp->tx_urb = usb_alloc_urb(0, GFP_KERNEL))) { + lbs_deb_usbd(&udev->dev, "Tx URB allocation failed\n"); + goto dealloc; + } + cardp->ep_out_buf = kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, GFP_KERNEL); + if (!cardp->ep_out_buf) { + lbs_deb_usbd(&udev->dev, "Could not allocate buffer\n"); + goto dealloc; + } /* Upload firmware */ - cardp->rinfo.cardp = cardp; if (if_usb_prog_firmware(cardp)) { - lbs_deb_usbd(&udev->dev, "FW upload failed"); + lbs_deb_usbd(&udev->dev, "FW upload failed\n"); goto err_prog_firmware; } - if (!(priv = libertas_add_card(cardp, &udev->dev))) + if (!(priv = lbs_add_card(cardp, &udev->dev))) goto err_prog_firmware; cardp->priv = priv; - - if (libertas_add_mesh(priv, &udev->dev)) - goto err_add_mesh; - - cardp->eth_dev = priv->dev; + cardp->priv->fw_ready = 1; priv->hw_host_to_card = if_usb_host_to_card; priv->hw_get_int_status = if_usb_get_int_status; priv->hw_read_event_cause = if_usb_read_event_cause; - priv->boot2_version = udev->descriptor.bcdDevice; + cardp->boot2_version = udev->descriptor.bcdDevice; - /* Delay 200 ms to waiting for the FW ready */ if_usb_submit_rx_urb(cardp); - msleep_interruptible(200); - priv->adapter->fw_ready = 1; - if (libertas_start_card(priv)) + if (lbs_start_card(priv)) goto err_start_card; - list_add_tail(&cardp->list, &usb_devices); + if_usb_setup_firmware(priv); usb_get_dev(udev); usb_set_intfdata(intf, cardp); @@ -253,9 +250,7 @@ static int if_usb_probe(struct usb_interface *intf, return 0; err_start_card: - libertas_remove_mesh(priv); -err_add_mesh: - libertas_remove_card(priv); + lbs_remove_card(priv); err_prog_firmware: if_usb_reset_device(cardp); dealloc: @@ -272,23 +267,17 @@ error: */ static void if_usb_disconnect(struct usb_interface *intf) { - struct usb_card_rec *cardp = usb_get_intfdata(intf); - wlan_private *priv = (wlan_private *) cardp->priv; + struct if_usb_card *cardp = usb_get_intfdata(intf); + struct lbs_private *priv = (struct lbs_private *) cardp->priv; lbs_deb_enter(LBS_DEB_MAIN); - /* Update Surprise removed to TRUE */ cardp->surprise_removed = 1; - list_del(&cardp->list); - if (priv) { - wlan_adapter *adapter = priv->adapter; - - adapter->surpriseremoved = 1; - libertas_stop_card(priv); - libertas_remove_mesh(priv); - libertas_remove_card(priv); + priv->surpriseremoved = 1; + lbs_stop_card(priv); + lbs_remove_card(priv); } /* Unlink and free urb */ @@ -302,102 +291,82 @@ static void if_usb_disconnect(struct usb_interface *intf) /** * @brief This function download FW - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @return 0 */ -static int if_prog_firmware(struct usb_card_rec *cardp) +static int if_usb_send_fw_pkt(struct if_usb_card *cardp) { - struct FWData *fwdata; - struct fwheader *fwheader; - u8 *firmware = cardp->fw->data; - - fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); - - if (!fwdata) - return -1; - - fwheader = &fwdata->fwheader; + struct fwdata *fwdata = cardp->ep_out_buf; + uint8_t *firmware = cardp->fw->data; + /* If we got a CRC failure on the last block, back + up and retry it */ if (!cardp->CRC_OK) { cardp->totalbytes = cardp->fwlastblksent; - cardp->fwseqnum = cardp->lastseqnum - 1; + cardp->fwseqnum--; } - /* - lbs_deb_usbd(&cardp->udev->dev, "totalbytes = %d\n", - cardp->totalbytes); - */ + lbs_deb_usb2(&cardp->udev->dev, "totalbytes = %d\n", + cardp->totalbytes); - memcpy(fwheader, &firmware[cardp->totalbytes], + /* struct fwdata (which we sent to the card) has an + extra __le32 field in between the header and the data, + which is not in the struct fwheader in the actual + firmware binary. Insert the seqnum in the middle... */ + memcpy(&fwdata->hdr, &firmware[cardp->totalbytes], sizeof(struct fwheader)); cardp->fwlastblksent = cardp->totalbytes; cardp->totalbytes += sizeof(struct fwheader); - /* lbs_deb_usbd(&cardp->udev->dev,"Copy Data\n"); */ memcpy(fwdata->data, &firmware[cardp->totalbytes], - le32_to_cpu(fwdata->fwheader.datalength)); + le32_to_cpu(fwdata->hdr.datalength)); - /* - lbs_deb_usbd(&cardp->udev->dev, - "Data length = %d\n", le32_to_cpu(fwdata->fwheader.datalength)); - */ + lbs_deb_usb2(&cardp->udev->dev, "Data length = %d\n", + le32_to_cpu(fwdata->hdr.datalength)); - cardp->fwseqnum = cardp->fwseqnum + 1; + fwdata->seqnum = cpu_to_le32(++cardp->fwseqnum); + cardp->totalbytes += le32_to_cpu(fwdata->hdr.datalength); - fwdata->seqnum = cpu_to_le32(cardp->fwseqnum); - cardp->lastseqnum = cardp->fwseqnum; - cardp->totalbytes += le32_to_cpu(fwdata->fwheader.datalength); + usb_tx_block(cardp, cardp->ep_out_buf, sizeof(struct fwdata) + + le32_to_cpu(fwdata->hdr.datalength)); + + if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) { + lbs_deb_usb2(&cardp->udev->dev, "There are data to follow\n"); + lbs_deb_usb2(&cardp->udev->dev, "seqnum = %d totalbytes = %d\n", + cardp->fwseqnum, cardp->totalbytes); + } else if (fwdata->hdr.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { + lbs_deb_usb2(&cardp->udev->dev, "Host has finished FW downloading\n"); + lbs_deb_usb2(&cardp->udev->dev, "Donwloading FW JUMP BLOCK\n"); - if (fwheader->dnldcmd == cpu_to_le32(FW_HAS_DATA_TO_RECV)) { - /* - lbs_deb_usbd(&cardp->udev->dev, "There are data to follow\n"); - lbs_deb_usbd(&cardp->udev->dev, - "seqnum = %d totalbytes = %d\n", cardp->fwseqnum, - cardp->totalbytes); - */ - memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); - - } else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) { - /* - lbs_deb_usbd(&cardp->udev->dev, - "Host has finished FW downloading\n"); - lbs_deb_usbd(&cardp->udev->dev, - "Donwloading FW JUMP BLOCK\n"); - */ - memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); - usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); cardp->fwfinalblk = 1; } - /* - lbs_deb_usbd(&cardp->udev->dev, - "The firmware download is done size is %d\n", - cardp->totalbytes); - */ - - kfree(fwdata); + lbs_deb_usb2(&cardp->udev->dev, "Firmware download done; size %d\n", + cardp->totalbytes); return 0; } -static int if_usb_reset_device(struct usb_card_rec *cardp) +static int if_usb_reset_device(struct if_usb_card *cardp) { + struct cmd_ds_command *cmd = cardp->ep_out_buf + 4; int ret; - wlan_private * priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); - /* Try a USB port reset first, if that fails send the reset - * command to the firmware. - */ + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); + + cmd->command = cpu_to_le16(CMD_802_11_RESET); + cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); + cmd->result = cpu_to_le16(0); + cmd->seqnum = cpu_to_le16(0x5a5a); + cmd->params.reset.action = cpu_to_le16(CMD_ACT_HALT); + usb_tx_block(cardp, cardp->ep_out_buf, 4 + S_DS_GEN + sizeof(struct cmd_ds_802_11_reset)); + + msleep(100); ret = usb_reset_device(cardp->udev); - if (!ret && priv) { - msleep(10); - ret = libertas_reset_device(priv); - msleep(10); - } + msleep(100); lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); @@ -406,12 +375,12 @@ static int if_usb_reset_device(struct usb_card_rec *cardp) /** * @brief This function transfer the data to the device. - * @param priv pointer to wlan_private + * @param priv pointer to struct lbs_private * @param payload pointer to payload data * @param nb data length * @return 0 or -1 */ -static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb) +static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb) { int ret = -1; @@ -423,17 +392,16 @@ static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb) usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, usb_sndbulkpipe(cardp->udev, - cardp->bulk_out_endpointAddr), + cardp->ep_out), payload, nb, if_usb_write_bulk_callback, cardp); cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { - /* transfer failed */ - lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed\n"); + lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb failed: %d\n", ret); ret = -1; } else { - /* lbs_deb_usbd(&cardp->udev->dev, "usb_submit_urb success\n"); */ + lbs_deb_usb2(&cardp->udev->dev, "usb_submit_urb success\n"); ret = 0; } @@ -441,11 +409,10 @@ tx_ret: return ret; } -static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, +static int __if_usb_submit_rx_urb(struct if_usb_card *cardp, void (*callbackfn)(struct urb *urb)) { struct sk_buff *skb; - struct read_cb_info *rinfo = &cardp->rinfo; int ret = -1; if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { @@ -453,25 +420,25 @@ static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp, goto rx_ret; } - rinfo->skb = skb; + cardp->rx_skb = skb; /* Fill the receive configuration URB and initialise the Rx call back */ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, - usb_rcvbulkpipe(cardp->udev, - cardp->bulk_in_endpointAddr), + usb_rcvbulkpipe(cardp->udev, cardp->ep_in), (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET), MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, - rinfo); + cardp); cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; - /* lbs_deb_usbd(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); */ + lbs_deb_usb2(&cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { - /* handle failure conditions */ - lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed\n"); + lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB failed: %d\n", ret); + kfree_skb(skb); + cardp->rx_skb = NULL; ret = -1; } else { - /* lbs_deb_usbd(&cardp->udev->dev, "Submit Rx URB success\n"); */ + lbs_deb_usb2(&cardp->udev->dev, "Submit Rx URB success\n"); ret = 0; } @@ -479,58 +446,78 @@ rx_ret: return ret; } -static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp) +static int if_usb_submit_rx_urb_fwload(struct if_usb_card *cardp) { return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload); } -static int if_usb_submit_rx_urb(struct usb_card_rec *cardp) +static int if_usb_submit_rx_urb(struct if_usb_card *cardp) { return __if_usb_submit_rx_urb(cardp, &if_usb_receive); } static void if_usb_receive_fwload(struct urb *urb) { - struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp; + struct if_usb_card *cardp = urb->context; + struct sk_buff *skb = cardp->rx_skb; struct fwsyncheader *syncfwheader; - struct bootcmdrespStr bootcmdresp; + struct bootcmdresp bootcmdresp; if (urb->status) { lbs_deb_usbd(&cardp->udev->dev, - "URB status is failed during fw load\n"); + "URB status is failed during fw load\n"); kfree_skb(skb); return; } - if (cardp->bootcmdresp == 0) { + if (cardp->fwdnldover) { + __le32 *tmp = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); + + if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) && + tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) { + lbs_pr_info("Firmware ready event received\n"); + wake_up(&cardp->fw_wq); + } else { + lbs_deb_usb("Waiting for confirmation; got %x %x\n", + le32_to_cpu(tmp[0]), le32_to_cpu(tmp[1])); + if_usb_submit_rx_urb_fwload(cardp); + } + kfree_skb(skb); + return; + } + if (cardp->bootcmdresp <= 0) { memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, sizeof(bootcmdresp)); + if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) { kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, - "Received valid boot command response\n"); + "Received valid boot command response\n"); return; } - if (bootcmdresp.u32magicnumber != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { - lbs_pr_info( - "boot cmd response wrong magic number (0x%x)\n", - le32_to_cpu(bootcmdresp.u32magicnumber)); - } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { - lbs_pr_info( - "boot cmd response cmd_tag error (%d)\n", - bootcmdresp.u8cmd_tag); - } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { - lbs_pr_info( - "boot cmd response result error (%d)\n", - bootcmdresp.u8result); + if (bootcmdresp.magic != cpu_to_le32(BOOT_CMD_MAGIC_NUMBER)) { + if (bootcmdresp.magic == cpu_to_le32(CMD_TYPE_REQUEST) || + bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) || + bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) { + if (!cardp->bootcmdresp) + lbs_pr_info("Firmware already seems alive; resetting\n"); + cardp->bootcmdresp = -1; + } else { + lbs_pr_info("boot cmd response wrong magic number (0x%x)\n", + le32_to_cpu(bootcmdresp.magic)); + } + } else if (bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) { + lbs_pr_info("boot cmd response cmd_tag error (%d)\n", + bootcmdresp.cmd); + } else if (bootcmdresp.result != BOOT_CMD_RESP_OK) { + lbs_pr_info("boot cmd response result error (%d)\n", + bootcmdresp.result); } else { cardp->bootcmdresp = 1; lbs_deb_usbd(&cardp->udev->dev, - "Received valid boot command response\n"); + "Received valid boot command response\n"); } kfree_skb(skb); if_usb_submit_rx_urb_fwload(cardp); @@ -545,50 +532,47 @@ static void if_usb_receive_fwload(struct urb *urb) } memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, - sizeof(struct fwsyncheader)); + sizeof(struct fwsyncheader)); if (!syncfwheader->cmd) { - /* - lbs_deb_usbd(&cardp->udev->dev, - "FW received Blk with correct CRC\n"); - lbs_deb_usbd(&cardp->udev->dev, - "FW received Blk seqnum = %d\n", - syncfwheader->seqnum); - */ + lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n"); + lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n", + le32_to_cpu(syncfwheader->seqnum)); cardp->CRC_OK = 1; } else { - lbs_deb_usbd(&cardp->udev->dev, - "FW received Blk with CRC error\n"); + lbs_deb_usbd(&cardp->udev->dev, "FW received Blk with CRC error\n"); cardp->CRC_OK = 0; } kfree_skb(skb); + /* reschedule timer for 200ms hence */ + mod_timer(&cardp->fw_timeout, jiffies + (HZ/5)); + if (cardp->fwfinalblk) { cardp->fwdnldover = 1; goto exit; } - if_prog_firmware(cardp); + if_usb_send_fw_pkt(cardp); + exit: if_usb_submit_rx_urb_fwload(cardp); -exit: + kfree(syncfwheader); return; - } #define MRVDRV_MIN_PKT_LEN 30 static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, - struct usb_card_rec *cardp, - wlan_private *priv) + struct if_usb_card *cardp, + struct lbs_private *priv) { - if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + - MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) { - lbs_deb_usbd(&cardp->udev->dev, - "Packet length is Invalid\n"); + if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + MESSAGE_HEADER_LEN + || recvlength < MRVDRV_MIN_PKT_LEN) { + lbs_deb_usbd(&cardp->udev->dev, "Packet length is Invalid\n"); kfree_skb(skb); return; } @@ -596,19 +580,19 @@ static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, skb_reserve(skb, IPFIELD_ALIGN_OFFSET); skb_put(skb, recvlength); skb_pull(skb, MESSAGE_HEADER_LEN); - libertas_process_rxed_packet(priv, skb); + + lbs_process_rxed_packet(priv, skb); priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); } -static inline void process_cmdrequest(int recvlength, u8 *recvbuff, +static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff, struct sk_buff *skb, - struct usb_card_rec *cardp, - wlan_private *priv) + struct if_usb_card *cardp, + struct lbs_private *priv) { - u8 *cmdbuf; - if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) { + if (recvlength > LBS_CMD_BUFFER_SIZE) { lbs_deb_usbd(&cardp->udev->dev, - "The receive buffer is too large\n"); + "The receive buffer is too large\n"); kfree_skb(skb); return; } @@ -616,28 +600,17 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, if (!in_interrupt()) BUG(); - spin_lock(&priv->adapter->driver_lock); - /* take care of cur_cmd = NULL case by reading the - * data to clear the interrupt */ - if (!priv->adapter->cur_cmd) { - cmdbuf = priv->upld_buf; - priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; - } else - cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; - + spin_lock(&priv->driver_lock); cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY; priv->upld_len = (recvlength - MESSAGE_HEADER_LEN); - memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, - priv->upld_len); + memcpy(priv->upld_buf, recvbuff + MESSAGE_HEADER_LEN, priv->upld_len); kfree_skb(skb); - libertas_interrupt(priv->dev); - spin_unlock(&priv->adapter->driver_lock); + lbs_interrupt(priv); + spin_unlock(&priv->driver_lock); lbs_deb_usbd(&cardp->udev->dev, "Wake up main thread to handle cmd response\n"); - - return; } /** @@ -649,35 +622,33 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff, */ static void if_usb_receive(struct urb *urb) { - struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; - struct sk_buff *skb = rinfo->skb; - struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp; - wlan_private * priv = cardp->priv; - + struct if_usb_card *cardp = urb->context; + struct sk_buff *skb = cardp->rx_skb; + struct lbs_private *priv = cardp->priv; int recvlength = urb->actual_length; - u8 *recvbuff = NULL; - u32 recvtype = 0; + uint8_t *recvbuff = NULL; + uint32_t recvtype = 0; + __le32 *pkt = (__le32 *)(skb->data + IPFIELD_ALIGN_OFFSET); lbs_deb_enter(LBS_DEB_USB); if (recvlength) { - __le32 tmp; - if (urb->status) { - lbs_deb_usbd(&cardp->udev->dev, - "URB status is failed\n"); + lbs_deb_usbd(&cardp->udev->dev, "RX URB failed: %d\n", + urb->status); kfree_skb(skb); goto setup_for_next; } recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; - memcpy(&tmp, recvbuff, sizeof(u32)); - recvtype = le32_to_cpu(tmp); + recvtype = le32_to_cpu(pkt[0]); lbs_deb_usbd(&cardp->udev->dev, "Recv length = 0x%x, Recv type = 0x%X\n", recvlength, recvtype); - } else if (urb->status) + } else if (urb->status) { + kfree_skb(skb); goto rx_exit; + } switch (recvtype) { case CMD_TYPE_DATA: @@ -690,24 +661,28 @@ static void if_usb_receive(struct urb *urb) case CMD_TYPE_INDICATION: /* Event cause handling */ - spin_lock(&priv->adapter->driver_lock); - cardp->usb_event_cause = le32_to_cpu(*(__le32 *) (recvbuff + MESSAGE_HEADER_LEN)); + spin_lock(&priv->driver_lock); + + cardp->usb_event_cause = le32_to_cpu(pkt[1]); + lbs_deb_usbd(&cardp->udev->dev,"**EVENT** 0x%X\n", - cardp->usb_event_cause); + cardp->usb_event_cause); + + /* Icky undocumented magic special case */ if (cardp->usb_event_cause & 0xffff0000) { - libertas_send_tx_feedback(priv); - spin_unlock(&priv->adapter->driver_lock); + lbs_send_tx_feedback(priv); + spin_unlock(&priv->driver_lock); break; } cardp->usb_event_cause <<= 3; cardp->usb_int_cause |= MRVDRV_CARDEVENT; kfree_skb(skb); - libertas_interrupt(priv->dev); - spin_unlock(&priv->adapter->driver_lock); + lbs_interrupt(priv); + spin_unlock(&priv->driver_lock); goto rx_exit; default: lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n", - recvtype); + recvtype); kfree_skb(skb); break; } @@ -720,58 +695,54 @@ rx_exit: /** * @brief This function downloads data to FW - * @param priv pointer to wlan_private structure + * @param priv pointer to struct lbs_private structure * @param type type of data * @param buf pointer to data buffer * @param len number of bytes * @return 0 or -1 */ -static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) +static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type, + uint8_t *payload, uint16_t nb) { - struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card; + struct if_usb_card *cardp = priv->card; lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type); lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb); if (type == MVMS_CMD) { - __le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST); + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_REQUEST); priv->dnld_sent = DNLD_CMD_SENT; - memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, - MESSAGE_HEADER_LEN); - } else { - __le32 tmp = cpu_to_le32(CMD_TYPE_DATA); + *(__le32 *)cardp->ep_out_buf = cpu_to_le32(CMD_TYPE_DATA); priv->dnld_sent = DNLD_DATA_SENT; - memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, - MESSAGE_HEADER_LEN); } - memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); + memcpy((cardp->ep_out_buf + MESSAGE_HEADER_LEN), payload, nb); - return usb_tx_block(cardp, cardp->bulk_out_buffer, - nb + MESSAGE_HEADER_LEN); + return usb_tx_block(cardp, cardp->ep_out_buf, nb + MESSAGE_HEADER_LEN); } -/* called with adapter->driver_lock held */ -static int if_usb_get_int_status(wlan_private * priv, u8 * ireg) +/* called with priv->driver_lock held */ +static int if_usb_get_int_status(struct lbs_private *priv, uint8_t *ireg) { - struct usb_card_rec *cardp = priv->card; + struct if_usb_card *cardp = priv->card; *ireg = cardp->usb_int_cause; cardp->usb_int_cause = 0; - lbs_deb_usbd(&cardp->udev->dev,"Int cause is 0x%X\n", *ireg); + lbs_deb_usbd(&cardp->udev->dev, "Int cause is 0x%X\n", *ireg); return 0; } -static int if_usb_read_event_cause(wlan_private * priv) +static int if_usb_read_event_cause(struct lbs_private *priv) { - struct usb_card_rec *cardp = priv->card; + struct if_usb_card *cardp = priv->card; - priv->adapter->eventcause = cardp->usb_event_cause; + priv->eventcause = cardp->usb_event_cause; /* Re-submit rx urb here to avoid event lost issue */ if_usb_submit_rx_urb(cardp); + return 0; } @@ -781,20 +752,17 @@ static int if_usb_read_event_cause(wlan_private * priv) * 2:Boot from FW in EEPROM * @return 0 */ -static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue) +static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue) { - struct bootcmdstr sbootcmd; - int i; + struct bootcmd *bootcmd = cardp->ep_out_buf; /* Prepare command */ - sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); - sbootcmd.u8cmd_tag = ivalue; - for (i=0; i<11; i++) - sbootcmd.au8dumy[i]=0x00; - memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); + bootcmd->magic = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER); + bootcmd->cmd = ivalue; + memset(bootcmd->pad, 0, sizeof(bootcmd->pad)); /* Issue command */ - usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); + usb_tx_block(cardp, cardp->ep_out_buf, sizeof(*bootcmd)); return 0; } @@ -807,10 +775,10 @@ static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue) * len image length * @return 0 or -1 */ -static int check_fwfile_format(u8 *data, u32 totlen) +static int check_fwfile_format(uint8_t *data, uint32_t totlen) { - u32 bincmd, exit; - u32 blksize, offset, len; + uint32_t bincmd, exit; + uint32_t blksize, offset, len; int ret; ret = 1; @@ -848,7 +816,7 @@ static int check_fwfile_format(u8 *data, u32 totlen) } -static int if_usb_prog_firmware(struct usb_card_rec *cardp) +static int if_usb_prog_firmware(struct if_usb_card *cardp) { int i = 0; static int reset_count = 10; @@ -856,10 +824,10 @@ static int if_usb_prog_firmware(struct usb_card_rec *cardp) lbs_deb_enter(LBS_DEB_USB); - if ((ret = request_firmware(&cardp->fw, libertas_fw_name, + if ((ret = request_firmware(&cardp->fw, lbs_fw_name, &cardp->udev->dev)) < 0) { lbs_pr_err("request_firmware() failed with %#x\n", ret); - lbs_pr_err("firmware %s not found\n", libertas_fw_name); + lbs_pr_err("firmware %s not found\n", lbs_fw_name); goto done; } @@ -886,7 +854,7 @@ restart: } while (cardp->bootcmdresp == 0 && j < 10); } while (cardp->bootcmdresp == 0 && i < 5); - if (cardp->bootcmdresp == 0) { + if (cardp->bootcmdresp <= 0) { if (--reset_count >= 0) { if_usb_reset_device(cardp); goto restart; @@ -904,15 +872,14 @@ restart: cardp->totalbytes = 0; cardp->fwfinalblk = 0; - if_prog_firmware(cardp); + /* Send the first firmware packet... */ + if_usb_send_fw_pkt(cardp); - do { - lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n"); - i++; - msleep_interruptible(100); - if (cardp->surprise_removed || i >= 20) - break; - } while (!cardp->fwdnldover); + /* ... and wait for the process to complete */ + wait_event_interruptible(cardp->fw_wq, cardp->surprise_removed || cardp->fwdnldover); + + del_timer_sync(&cardp->fw_timeout); + usb_kill_urb(cardp->rx_urb); if (!cardp->fwdnldover) { lbs_pr_info("failed to load fw, resetting device!\n"); @@ -926,11 +893,11 @@ restart: goto release_fw; } -release_fw: + release_fw: release_firmware(cardp->fw); cardp->fw = NULL; -done: + done: lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret); return ret; } @@ -939,66 +906,38 @@ done: #ifdef CONFIG_PM static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) { - struct usb_card_rec *cardp = usb_get_intfdata(intf); - wlan_private *priv = cardp->priv; + struct if_usb_card *cardp = usb_get_intfdata(intf); + struct lbs_private *priv = cardp->priv; + int ret; lbs_deb_enter(LBS_DEB_USB); - if (priv->adapter->psstate != PS_STATE_FULL_POWER) + if (priv->psstate != PS_STATE_FULL_POWER) return -1; - if (priv->mesh_dev && !priv->mesh_autostart_enabled) { - /* Mesh autostart must be activated while sleeping - * On resume it will go back to the current state - */ - struct cmd_ds_mesh_access mesh_access; - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = cpu_to_le32(1); - libertas_prepare_and_send_command(priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_SET_AUTOSTART_ENABLED, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); - } - - netif_device_detach(cardp->eth_dev); - netif_device_detach(priv->mesh_dev); + ret = lbs_suspend(priv); + if (ret) + goto out; /* Unlink tx & rx urb */ usb_kill_urb(cardp->tx_urb); usb_kill_urb(cardp->rx_urb); - cardp->rx_urb_recall = 1; - + out: lbs_deb_leave(LBS_DEB_USB); - return 0; + return ret; } static int if_usb_resume(struct usb_interface *intf) { - struct usb_card_rec *cardp = usb_get_intfdata(intf); - wlan_private *priv = cardp->priv; + struct if_usb_card *cardp = usb_get_intfdata(intf); + struct lbs_private *priv = cardp->priv; lbs_deb_enter(LBS_DEB_USB); - cardp->rx_urb_recall = 0; - - if_usb_submit_rx_urb(cardp->priv); + if_usb_submit_rx_urb(cardp); - netif_device_attach(cardp->eth_dev); - netif_device_attach(priv->mesh_dev); - - if (priv->mesh_dev && !priv->mesh_autostart_enabled) { - /* Mesh autostart was activated while sleeping - * Disable it if appropriate - */ - struct cmd_ds_mesh_access mesh_access; - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = cpu_to_le32(0); - libertas_prepare_and_send_command(priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_SET_AUTOSTART_ENABLED, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); - } + lbs_resume(priv); lbs_deb_leave(LBS_DEB_USB); return 0; @@ -1009,46 +948,30 @@ static int if_usb_resume(struct usb_interface *intf) #endif static struct usb_driver if_usb_driver = { - /* driver name */ - .name = usbdriver_name, - /* probe function name */ + .name = DRV_NAME, .probe = if_usb_probe, - /* disconnect function name */ .disconnect = if_usb_disconnect, - /* device signature table */ .id_table = if_usb_table, .suspend = if_usb_suspend, .resume = if_usb_resume, }; -static int if_usb_init_module(void) +static int __init if_usb_init_module(void) { int ret = 0; lbs_deb_enter(LBS_DEB_MAIN); - if (libertas_fw_name == NULL) { - libertas_fw_name = default_fw_name; - } - ret = usb_register(&if_usb_driver); lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -static void if_usb_exit_module(void) +static void __exit if_usb_exit_module(void) { - struct usb_card_rec *cardp, *cardp_temp; - lbs_deb_enter(LBS_DEB_MAIN); - list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) { - libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET, - CMD_ACT_HALT, 0, 0, NULL); - } - - /* API unregisters the driver from USB subsystem */ usb_deregister(&if_usb_driver); lbs_deb_leave(LBS_DEB_MAIN); @@ -1058,5 +981,5 @@ module_init(if_usb_init_module); module_exit(if_usb_exit_module); MODULE_DESCRIPTION("8388 USB WLAN Driver"); -MODULE_AUTHOR("Marvell International Ltd."); +MODULE_AUTHOR("Marvell International Ltd. and Red Hat, Inc."); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h index e07a10ed28b5..e4829a391eb9 100644 --- a/drivers/net/wireless/libertas/if_usb.h +++ b/drivers/net/wireless/libertas/if_usb.h @@ -1,79 +1,76 @@ -#ifndef _LIBERTAS_IF_USB_H -#define _LIBERTAS_IF_USB_H +#ifndef _LBS_IF_USB_H +#define _LBS_IF_USB_H -#include <linux/list.h> +#include <linux/wait.h> +#include <linux/timer.h> + +struct lbs_private; /** * This file contains definition for USB interface. */ -#define CMD_TYPE_REQUEST 0xF00DFACE -#define CMD_TYPE_DATA 0xBEADC0DE -#define CMD_TYPE_INDICATION 0xBEEFFACE +#define CMD_TYPE_REQUEST 0xF00DFACE +#define CMD_TYPE_DATA 0xBEADC0DE +#define CMD_TYPE_INDICATION 0xBEEFFACE -#define IPFIELD_ALIGN_OFFSET 2 +#define IPFIELD_ALIGN_OFFSET 2 -#define BOOT_CMD_FW_BY_USB 0x01 -#define BOOT_CMD_FW_IN_EEPROM 0x02 -#define BOOT_CMD_UPDATE_BOOT2 0x03 -#define BOOT_CMD_UPDATE_FW 0x04 -#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */ +#define BOOT_CMD_FW_BY_USB 0x01 +#define BOOT_CMD_FW_IN_EEPROM 0x02 +#define BOOT_CMD_UPDATE_BOOT2 0x03 +#define BOOT_CMD_UPDATE_FW 0x04 +#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* LVRM */ -struct bootcmdstr +struct bootcmd { - __le32 u32magicnumber; - u8 u8cmd_tag; - u8 au8dumy[11]; + __le32 magic; + uint8_t cmd; + uint8_t pad[11]; }; -#define BOOT_CMD_RESP_OK 0x0001 -#define BOOT_CMD_RESP_FAIL 0x0000 +#define BOOT_CMD_RESP_OK 0x0001 +#define BOOT_CMD_RESP_FAIL 0x0000 -struct bootcmdrespStr +struct bootcmdresp { - __le32 u32magicnumber; - u8 u8cmd_tag; - u8 u8result; - u8 au8dumy[2]; -}; - -/* read callback private data */ -struct read_cb_info { - struct usb_card_rec *cardp; - struct sk_buff *skb; + __le32 magic; + uint8_t cmd; + uint8_t result; + uint8_t pad[2]; }; /** USB card description structure*/ -struct usb_card_rec { - struct list_head list; - struct net_device *eth_dev; +struct if_usb_card { struct usb_device *udev; struct urb *rx_urb, *tx_urb; - void *priv; - struct read_cb_info rinfo; + struct lbs_private *priv; - int bulk_in_size; - u8 bulk_in_endpointAddr; + struct sk_buff *rx_skb; + uint32_t usb_event_cause; + uint8_t usb_int_cause; - u8 *bulk_out_buffer; - int bulk_out_size; - u8 bulk_out_endpointAddr; + uint8_t ep_in; + uint8_t ep_out; - const struct firmware *fw; - u8 CRC_OK; - u32 fwseqnum; - u32 lastseqnum; - u32 totalbytes; - u32 fwlastblksent; - u8 fwdnldover; - u8 fwfinalblk; - u8 surprise_removed; + int8_t bootcmdresp; - u32 usb_event_cause; - u8 usb_int_cause; + int ep_in_size; - u8 rx_urb_recall; + void *ep_out_buf; + int ep_out_size; - u8 bootcmdresp; + const struct firmware *fw; + struct timer_list fw_timeout; + wait_queue_head_t fw_wq; + uint32_t fwseqnum; + uint32_t totalbytes; + uint32_t fwlastblksent; + uint8_t CRC_OK; + uint8_t fwdnldover; + uint8_t fwfinalblk; + uint8_t surprise_removed; + + __le16 boot2_version; }; /** fwheader */ @@ -86,10 +83,10 @@ struct fwheader { #define FW_MAX_DATA_BLK_SIZE 600 /** FWData */ -struct FWData { - struct fwheader fwheader; +struct fwdata { + struct fwheader hdr; __le32 seqnum; - u8 data[FW_MAX_DATA_BLK_SIZE]; + uint8_t data[0]; }; /** fwsyncheader */ @@ -101,7 +98,5 @@ struct fwsyncheader { #define FW_HAS_DATA_TO_RECV 0x00000001 #define FW_HAS_LAST_BLOCK 0x00000004 -#define FW_DATA_XMIT_SIZE \ - sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32) #endif diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c index dc24a05c9447..2d4508048b68 100644 --- a/drivers/net/wireless/libertas/join.c +++ b/drivers/net/wireless/libertas/join.c @@ -30,16 +30,18 @@ * NOTE: Setting the MSB of the basic rates need to be taken * care, either before or after calling this function * - * @param adapter A pointer to wlan_adapter structure + * @param priv A pointer to struct lbs_private structure * @param rate1 the buffer which keeps input and output * @param rate1_size the size of rate1 buffer; new size of buffer on return * * @return 0 or -1 */ -static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size) +static int get_common_rates(struct lbs_private *priv, + u8 *rates, + u16 *rates_size) { - u8 *card_rates = libertas_bg_rates; - size_t num_card_rates = sizeof(libertas_bg_rates); + u8 *card_rates = lbs_bg_rates; + size_t num_card_rates = sizeof(lbs_bg_rates); int ret = 0, i, j; u8 tmp[30]; size_t tmp_size = 0; @@ -55,15 +57,15 @@ static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size) lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size); lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates); lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size); - lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate); + lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate); - if (!adapter->auto_rate) { + if (!priv->auto_rate) { for (i = 0; i < tmp_size; i++) { - if (tmp[i] == adapter->cur_rate) + if (tmp[i] == priv->cur_rate) goto done; } lbs_pr_alert("Previously set fixed data rate %#x isn't " - "compatible with the network.\n", adapter->cur_rate); + "compatible with the network.\n", priv->cur_rate); ret = -1; goto done; } @@ -85,7 +87,7 @@ done: * @param rates buffer of data rates * @param len size of buffer */ -static void libertas_set_basic_rate_flags(u8 * rates, size_t len) +static void lbs_set_basic_rate_flags(u8 *rates, size_t len) { int i; @@ -104,7 +106,7 @@ static void libertas_set_basic_rate_flags(u8 * rates, size_t len) * @param rates buffer of data rates * @param len size of buffer */ -void libertas_unset_basic_rate_flags(u8 * rates, size_t len) +void lbs_unset_basic_rate_flags(u8 *rates, size_t len) { int i; @@ -116,19 +118,18 @@ void libertas_unset_basic_rate_flags(u8 * rates, size_t len) /** * @brief Associate to a specific BSS discovered in a scan * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param pbssdesc Pointer to the BSS descriptor to associate with. * * @return 0-success, otherwise fail */ -int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) +int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret; - lbs_deb_enter(LBS_DEB_JOIN); + lbs_deb_enter(LBS_DEB_ASSOC); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req->bss.bssid); @@ -136,50 +137,50 @@ int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req) goto done; /* set preamble to firmware */ - if ( (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) + if ( (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) - adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; else - adapter->preamble = CMD_TYPE_LONG_PREAMBLE; + priv->preamble = CMD_TYPE_LONG_PREAMBLE; - libertas_set_radio_control(priv); + lbs_set_radio_control(priv); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } /** * @brief Start an Adhoc Network * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param adhocssid The ssid of the Adhoc Network * @return 0--success, -1--fail */ -int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req) +int lbs_start_adhoc_network(struct lbs_private *priv, + struct assoc_request *assoc_req) { - wlan_adapter *adapter = priv->adapter; int ret = 0; - adapter->adhoccreate = 1; + priv->adhoccreate = 1; - if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { + if (priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) { lbs_deb_join("AdhocStart: Short preamble\n"); - adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; } else { lbs_deb_join("AdhocStart: Long preamble\n"); - adapter->preamble = CMD_TYPE_LONG_PREAMBLE; + priv->preamble = CMD_TYPE_LONG_PREAMBLE; } - libertas_set_radio_control(priv); + lbs_set_radio_control(priv); lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START, 0, CMD_OPTION_WAITFORRSP, 0, assoc_req); return ret; @@ -188,34 +189,34 @@ int libertas_start_adhoc_network(wlan_private * priv, struct assoc_request * ass /** * @brief Join an adhoc network found in a previous scan * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param pbssdesc Pointer to a BSS descriptor found in a previous scan * to attempt to join * * @return 0--success, -1--fail */ -int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * assoc_req) +int lbs_join_adhoc_network(struct lbs_private *priv, + struct assoc_request *assoc_req) { - wlan_adapter *adapter = priv->adapter; struct bss_descriptor * bss = &assoc_req->bss; int ret = 0; lbs_deb_join("%s: Current SSID '%s', ssid length %u\n", __func__, - escape_essid(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len), - adapter->curbssparams.ssid_len); + escape_essid(priv->curbssparams.ssid, + priv->curbssparams.ssid_len), + priv->curbssparams.ssid_len); lbs_deb_join("%s: requested ssid '%s', ssid length %u\n", __func__, escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ - if ( adapter->curbssparams.ssid_len - && !libertas_ssid_cmp(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len, + if ( priv->curbssparams.ssid_len + && !lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, bss->ssid, bss->ssid_len) - && (adapter->mode == IW_MODE_ADHOC) - && (adapter->connect_status == LIBERTAS_CONNECTED)) { + && (priv->mode == IW_MODE_ADHOC) + && (priv->connect_status == LBS_CONNECTED)) { union iwreq_data wrqu; lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as " @@ -225,7 +226,7 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso * request really was successful, even if just a null-op. */ memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); @@ -235,22 +236,22 @@ int libertas_join_adhoc_network(wlan_private * priv, struct assoc_request * asso /* Use shortpreamble only when both creator and card supports short preamble */ if ( !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { + || !(priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) { lbs_deb_join("AdhocJoin: Long preamble\n"); - adapter->preamble = CMD_TYPE_LONG_PREAMBLE; + priv->preamble = CMD_TYPE_LONG_PREAMBLE; } else { lbs_deb_join("AdhocJoin: Short preamble\n"); - adapter->preamble = CMD_TYPE_SHORT_PREAMBLE; + priv->preamble = CMD_TYPE_SHORT_PREAMBLE; } - libertas_set_radio_control(priv); + lbs_set_radio_control(priv); lbs_deb_join("AdhocJoin: channel = %d\n", assoc_req->channel); lbs_deb_join("AdhocJoin: band = %c\n", assoc_req->band); - adapter->adhoccreate = 0; + priv->adhoccreate = 0; - ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN, 0, CMD_OPTION_WAITFORRSP, OID_802_11_SSID, assoc_req); @@ -258,38 +259,37 @@ out: return ret; } -int libertas_stop_adhoc_network(wlan_private * priv) +int lbs_stop_adhoc_network(struct lbs_private *priv) { - return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, + return lbs_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP, 0, CMD_OPTION_WAITFORRSP, 0, NULL); } /** * @brief Send Deauthentication Request * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return 0--success, -1--fail */ -int libertas_send_deauthentication(wlan_private * priv) +int lbs_send_deauthentication(struct lbs_private *priv) { - return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, + return lbs_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE, 0, CMD_OPTION_WAITFORRSP, 0, NULL); } /** * @brief This function prepares command of authenticate. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param cmd A pointer to cmd_ds_command structure * @param pdata_buf Void cast of pointer to a BSSID to authenticate with * * @return 0 or -1 */ -int libertas_cmd_80211_authenticate(wlan_private * priv, +int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; @@ -302,7 +302,7 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, + S_DS_GEN); /* translate auth mode to 802.11 defined wire value */ - switch (adapter->secinfo.auth_mode) { + switch (priv->secinfo.auth_mode) { case IW_AUTH_ALG_OPEN_SYSTEM: pauthenticate->authtype = 0x00; break; @@ -314,13 +314,13 @@ int libertas_cmd_80211_authenticate(wlan_private * priv, break; default: lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n", - adapter->secinfo.auth_mode); + priv->secinfo.auth_mode); goto out; } memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n", + lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", print_mac(mac, bssid), pauthenticate->authtype); ret = 0; @@ -329,10 +329,9 @@ out: return ret; } -int libertas_cmd_80211_deauthenticate(wlan_private * priv, +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, struct cmd_ds_command *cmd) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; lbs_deb_enter(LBS_DEB_JOIN); @@ -342,7 +341,7 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv, S_DS_GEN); /* set AP MAC address */ - memmove(dauth->macaddr, adapter->curbssparams.bssid, ETH_ALEN); + memmove(dauth->macaddr, priv->curbssparams.bssid, ETH_ALEN); /* Reason code 3 = Station is leaving */ #define REASON_CODE_STA_LEAVING 3 @@ -352,10 +351,9 @@ int libertas_cmd_80211_deauthenticate(wlan_private * priv, return 0; } -int libertas_cmd_80211_associate(wlan_private * priv, +int lbs_cmd_80211_associate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_associate *passo = &cmd->params.associate; int ret = 0; struct assoc_request * assoc_req = pdata_buf; @@ -368,11 +366,11 @@ int libertas_cmd_80211_associate(wlan_private * priv, struct mrvlietypes_ratesparamset *rates; struct mrvlietypes_rsnparamset *rsn; - lbs_deb_enter(LBS_DEB_JOIN); + lbs_deb_enter(LBS_DEB_ASSOC); pos = (u8 *) passo; - if (!adapter) { + if (!priv) { ret = -1; goto done; } @@ -416,22 +414,22 @@ int libertas_cmd_80211_associate(wlan_private * priv, rates->header.type = cpu_to_le16(TLV_TYPE_RATES); memcpy(&rates->rates, &bss->rates, MAX_RATES); tmplen = MAX_RATES; - if (get_common_rates(adapter, rates->rates, &tmplen)) { + if (get_common_rates(priv, rates->rates, &tmplen)) { ret = -1; goto done; } pos += sizeof(rates->header) + tmplen; rates->header.len = cpu_to_le16(tmplen); - lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen); + lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen); /* Copy the infra. association rates into Current BSS state structure */ - memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); - memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen); + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &rates->rates, tmplen); /* Set MSB on basic rates as the firmware requires, but _after_ * copying to current bss rates. */ - libertas_set_basic_rate_flags(rates->rates, tmplen); + lbs_set_basic_rate_flags(rates->rates, tmplen); if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { rsn = (struct mrvlietypes_rsnparamset *) pos; @@ -446,9 +444,9 @@ int libertas_cmd_80211_associate(wlan_private * priv, } /* update curbssparams */ - adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; + priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan; - if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; } @@ -460,18 +458,16 @@ int libertas_cmd_80211_associate(wlan_private * priv, if (bss->mode == IW_MODE_INFRA) tmpcap |= WLAN_CAPABILITY_ESS; passo->capability = cpu_to_le16(tmpcap); - lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n", - tmpcap, CAPINFO_MASK); + lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap); done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, +int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; int ret = 0; int cmdappendsize = 0; @@ -481,7 +477,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, lbs_deb_enter(LBS_DEB_JOIN); - if (!adapter) { + if (!priv) { ret = -1; goto done; } @@ -491,7 +487,7 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, /* * Fill in the parameters for 2 data structures: * 1. cmd_ds_802_11_ad_hoc_start command - * 2. adapter->scantable[i] + * 2. priv->scantable[i] * * Driver will fill up SSID, bsstype,IBSS param, Physical Param, * probe delay, and cap info. @@ -509,8 +505,10 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, /* set the BSS type */ adhs->bsstype = CMD_BSS_TYPE_IBSS; - adapter->mode = IW_MODE_ADHOC; - adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL); + priv->mode = IW_MODE_ADHOC; + if (priv->beacon_period == 0) + priv->beacon_period = MRVDRV_BEACON_INTERVAL; + adhs->beaconperiod = cpu_to_le16(priv->beacon_period); /* set Physical param set */ #define DS_PARA_IE_ID 3 @@ -548,24 +546,24 @@ int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); memset(adhs->rates, 0, sizeof(adhs->rates)); - ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates)); - memcpy(adhs->rates, libertas_bg_rates, ratesize); + ratesize = min(sizeof(adhs->rates), sizeof(lbs_bg_rates)); + memcpy(adhs->rates, lbs_bg_rates, ratesize); /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); - memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize); + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, &adhs->rates, ratesize); /* Set MSB on basic rates as the firmware requires, but _after_ * copying to current bss rates. */ - libertas_set_basic_rate_flags(adhs->rates, ratesize); + lbs_set_basic_rate_flags(adhs->rates, ratesize); lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]); lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n"); - if (libertas_create_dnld_countryinfo_11d(priv)) { + if (lbs_create_dnld_countryinfo_11d(priv)) { lbs_deb_join("ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); ret = -1; goto done; @@ -580,7 +578,7 @@ done: return ret; } -int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, +int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv, struct cmd_ds_command *cmd) { cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP); @@ -589,10 +587,9 @@ int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, return 0; } -int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, +int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj; struct assoc_request * assoc_req = pdata_buf; struct bss_descriptor *bss = &assoc_req->bss; @@ -633,26 +630,26 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, /* probedelay */ join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME); - adapter->curbssparams.channel = bss->channel; + priv->curbssparams.channel = bss->channel; /* Copy Data rates from the rates recorded in scan response */ memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates)); ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES); memcpy(join_cmd->bss.rates, bss->rates, ratesize); - if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) { + if (get_common_rates(priv, join_cmd->bss.rates, &ratesize)) { lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n"); ret = -1; goto done; } /* Copy the ad-hoc creating rates into Current BSS state structure */ - memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates)); - memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize); + memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates)); + memcpy(&priv->curbssparams.rates, join_cmd->bss.rates, ratesize); /* Set MSB on basic rates as the firmware requires, but _after_ * copying to current bss rates. */ - libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize); + lbs_set_basic_rate_flags(join_cmd->bss.rates, ratesize); join_cmd->bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow); @@ -663,12 +660,12 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, join_cmd->bss.capability = cpu_to_le16(tmp); } - if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { /* wake up first */ __le32 Localpsmode; - Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM); - ret = libertas_prepare_and_send_command(priv, + Localpsmode = cpu_to_le32(LBS802_11POWERMODECAM); + ret = lbs_prepare_and_send_command(priv, CMD_802_11_PS_MODE, CMD_ACT_SET, 0, 0, &Localpsmode); @@ -679,7 +676,7 @@ int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, } } - if (libertas_parse_dnld_countryinfo_11d(priv, bss)) { + if (lbs_parse_dnld_countryinfo_11d(priv, bss)) { ret = -1; goto done; } @@ -692,24 +689,23 @@ done: return ret; } -int libertas_ret_80211_associate(wlan_private * priv, +int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp) { - wlan_adapter *adapter = priv->adapter; int ret = 0; union iwreq_data wrqu; struct ieeetypes_assocrsp *passocrsp; struct bss_descriptor * bss; u16 status_code; - lbs_deb_enter(LBS_DEB_JOIN); + lbs_deb_enter(LBS_DEB_ASSOC); - if (!adapter->in_progress_assoc_req) { - lbs_deb_join("ASSOC_RESP: no in-progress association request\n"); + if (!priv->in_progress_assoc_req) { + lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n"); ret = -1; goto done; } - bss = &adapter->in_progress_assoc_req->bss; + bss = &priv->in_progress_assoc_req->bss; passocrsp = (struct ieeetypes_assocrsp *) & resp->params; @@ -734,96 +730,83 @@ int libertas_ret_80211_associate(wlan_private * priv, status_code = le16_to_cpu(passocrsp->statuscode); switch (status_code) { case 0x00: - lbs_deb_join("ASSOC_RESP: Association succeeded\n"); break; case 0x01: - lbs_deb_join("ASSOC_RESP: Association failed; invalid " - "parameters (status code %d)\n", status_code); + lbs_deb_assoc("ASSOC_RESP: invalid parameters\n"); break; case 0x02: - lbs_deb_join("ASSOC_RESP: Association failed; internal timer " - "expired while waiting for the AP (status code %d)" - "\n", status_code); + lbs_deb_assoc("ASSOC_RESP: internal timer " + "expired while waiting for the AP\n"); break; case 0x03: - lbs_deb_join("ASSOC_RESP: Association failed; association " - "was refused by the AP (status code %d)\n", - status_code); + lbs_deb_assoc("ASSOC_RESP: association " + "refused by AP\n"); break; case 0x04: - lbs_deb_join("ASSOC_RESP: Association failed; authentication " - "was refused by the AP (status code %d)\n", - status_code); + lbs_deb_assoc("ASSOC_RESP: authentication " + "refused by AP\n"); break; default: - lbs_deb_join("ASSOC_RESP: Association failed; reason unknown " - "(status code %d)\n", status_code); + lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x " + " unknown\n", status_code); break; } if (status_code) { - libertas_mac_event_disconnected(priv); + lbs_mac_event_disconnected(priv); ret = -1; goto done; } - lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params, + lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params, le16_to_cpu(resp->size) - S_DS_GEN); /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = LIBERTAS_CONNECTED; - - lbs_deb_join("ASSOC_RESP: assocated to '%s'\n", - escape_essid(bss->ssid, bss->ssid_len)); + priv->connect_status = LBS_CONNECTED; /* Update current SSID and BSSID */ - memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - adapter->curbssparams.ssid_len = bss->ssid_len; - memcpy(adapter->curbssparams.bssid, bss->bssid, ETH_ALEN); + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; + memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN); - lbs_deb_join("ASSOC_RESP: currentpacketfilter is %x\n", - adapter->currentpacketfilter); + lbs_deb_assoc("ASSOC_RESP: currentpacketfilter is 0x%x\n", + priv->currentpacketfilter); - adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0; - adapter->NF[TYPE_RXPD][TYPE_AVG] = 0; + priv->SNR[TYPE_RXPD][TYPE_AVG] = 0; + priv->NF[TYPE_RXPD][TYPE_AVG] = 0; - memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); - memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); - adapter->nextSNRNF = 0; - adapter->numSNRNF = 0; + memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR)); + memset(priv->rawNF, 0x00, sizeof(priv->rawNF)); + priv->nextSNRNF = 0; + priv->numSNRNF = 0; netif_carrier_on(priv->dev); - netif_wake_queue(priv->dev); - - if (priv->mesh_dev) { - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); - } + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); done: - lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret); + lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret); return ret; } -int libertas_ret_80211_disassociate(wlan_private * priv, +int lbs_ret_80211_disassociate(struct lbs_private *priv, struct cmd_ds_command *resp) { lbs_deb_enter(LBS_DEB_JOIN); - libertas_mac_event_disconnected(priv); + lbs_mac_event_disconnected(priv); lbs_deb_leave(LBS_DEB_JOIN); return 0; } -int libertas_ret_80211_ad_hoc_start(wlan_private * priv, +int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp) { - wlan_adapter *adapter = priv->adapter; int ret = 0; u16 command = le16_to_cpu(resp->command); u16 result = le16_to_cpu(resp->result); @@ -840,20 +823,20 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, lbs_deb_join("ADHOC_RESP: command = %x\n", command); lbs_deb_join("ADHOC_RESP: result = %x\n", result); - if (!adapter->in_progress_assoc_req) { + if (!priv->in_progress_assoc_req) { lbs_deb_join("ADHOC_RESP: no in-progress association request\n"); ret = -1; goto done; } - bss = &adapter->in_progress_assoc_req->bss; + bss = &priv->in_progress_assoc_req->bss; /* * Join result code 0 --> SUCCESS */ if (result) { lbs_deb_join("ADHOC_RESP: failed\n"); - if (adapter->connect_status == LIBERTAS_CONNECTED) { - libertas_mac_event_disconnected(priv); + if (priv->connect_status == LBS_CONNECTED) { + lbs_mac_event_disconnected(priv); } ret = -1; goto done; @@ -867,7 +850,7 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, escape_essid(bss->ssid, bss->ssid_len)); /* Send a Media Connected event, according to the Spec */ - adapter->connect_status = LIBERTAS_CONNECTED; + priv->connect_status = LBS_CONNECTED; if (command == CMD_RET(CMD_802_11_AD_HOC_START)) { /* Update the created network descriptor with the new BSSID */ @@ -875,27 +858,23 @@ int libertas_ret_80211_ad_hoc_start(wlan_private * priv, } /* Set the BSSID from the joined/started descriptor */ - memcpy(&adapter->curbssparams.bssid, bss->bssid, ETH_ALEN); + memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN); /* Set the new SSID to current SSID */ - memcpy(&adapter->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); - adapter->curbssparams.ssid_len = bss->ssid_len; + memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE); + priv->curbssparams.ssid_len = bss->ssid_len; netif_carrier_on(priv->dev); - netif_wake_queue(priv->dev); - - if (priv->mesh_dev) { - netif_carrier_on(priv->mesh_dev); - netif_wake_queue(priv->mesh_dev); - } + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); memset(&wrqu, 0, sizeof(wrqu)); - memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n"); - lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel); + lbs_deb_join("ADHOC_RESP: channel = %d\n", priv->curbssparams.channel); lbs_deb_join("ADHOC_RESP: BSSID = %s\n", print_mac(mac, padhocresult->bssid)); @@ -904,12 +883,12 @@ done: return ret; } -int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, +int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv, struct cmd_ds_command *resp) { lbs_deb_enter(LBS_DEB_JOIN); - libertas_mac_event_disconnected(priv); + lbs_mac_event_disconnected(priv); lbs_deb_leave(LBS_DEB_JOIN); return 0; diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h index 894a072b9f8d..c617d071f781 100644 --- a/drivers/net/wireless/libertas/join.h +++ b/drivers/net/wireless/libertas/join.h @@ -2,52 +2,52 @@ * Interface for the wlan infrastructure and adhoc join routines * * Driver interface functions and type declarations for the join module - * implemented in wlan_join.c. Process all start/join requests for + * implemented in join.c. Process all start/join requests for * both adhoc and infrastructure networks */ -#ifndef _WLAN_JOIN_H -#define _WLAN_JOIN_H +#ifndef _LBS_JOIN_H +#define _LBS_JOIN_H #include "defs.h" #include "dev.h" struct cmd_ds_command; -int libertas_cmd_80211_authenticate(wlan_private * priv, +int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, +int lbs_cmd_80211_ad_hoc_join(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, +int lbs_cmd_80211_ad_hoc_stop(struct lbs_private *priv, struct cmd_ds_command *cmd); -int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, +int lbs_cmd_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int libertas_cmd_80211_deauthenticate(wlan_private * priv, +int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, struct cmd_ds_command *cmd); -int libertas_cmd_80211_associate(wlan_private * priv, +int lbs_cmd_80211_associate(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int libertas_ret_80211_ad_hoc_start(wlan_private * priv, +int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv, struct cmd_ds_command *resp); -int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, +int lbs_ret_80211_ad_hoc_stop(struct lbs_private *priv, struct cmd_ds_command *resp); -int libertas_ret_80211_disassociate(wlan_private * priv, +int lbs_ret_80211_disassociate(struct lbs_private *priv, struct cmd_ds_command *resp); -int libertas_ret_80211_associate(wlan_private * priv, +int lbs_ret_80211_associate(struct lbs_private *priv, struct cmd_ds_command *resp); -int libertas_start_adhoc_network(wlan_private * priv, +int lbs_start_adhoc_network(struct lbs_private *priv, struct assoc_request * assoc_req); -int libertas_join_adhoc_network(wlan_private * priv, +int lbs_join_adhoc_network(struct lbs_private *priv, struct assoc_request * assoc_req); -int libertas_stop_adhoc_network(wlan_private * priv); +int lbs_stop_adhoc_network(struct lbs_private *priv); -int libertas_send_deauthentication(wlan_private * priv); +int lbs_send_deauthentication(struct lbs_private *priv); -int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req); +int lbs_associate(struct lbs_private *priv, struct assoc_request *assoc_req); -void libertas_unset_basic_rate_flags(u8 * rates, size_t len); +void lbs_unset_basic_rate_flags(u8 *rates, size_t len); #endif diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 1823b48a8ba7..84fb49ca0fae 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -6,7 +6,6 @@ #include <linux/moduleparam.h> #include <linux/delay.h> -#include <linux/freezer.h> #include <linux/etherdevice.h> #include <linux/netdevice.h> #include <linux/if_arp.h> @@ -22,9 +21,10 @@ #include "debugfs.h" #include "assoc.h" #include "join.h" +#include "cmd.h" #define DRIVER_RELEASE_VERSION "323.p0" -const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION +const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION #ifdef DEBUG "-dbg" #endif @@ -32,80 +32,80 @@ const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION /* Module parameters */ -unsigned int libertas_debug = 0; -module_param(libertas_debug, int, 0644); -EXPORT_SYMBOL_GPL(libertas_debug); +unsigned int lbs_debug; +EXPORT_SYMBOL_GPL(lbs_debug); +module_param_named(libertas_debug, lbs_debug, int, 0644); -#define WLAN_TX_PWR_DEFAULT 20 /*100mW */ -#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */ -#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */ -#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */ -#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */ +#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */ +#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */ /* Format { channel, frequency (MHz), maxtxpower } */ /* band: 'B/G', region: USA FCC/Canada IC */ static struct chan_freq_power channel_freq_power_US_BG[] = { - {1, 2412, WLAN_TX_PWR_US_DEFAULT}, - {2, 2417, WLAN_TX_PWR_US_DEFAULT}, - {3, 2422, WLAN_TX_PWR_US_DEFAULT}, - {4, 2427, WLAN_TX_PWR_US_DEFAULT}, - {5, 2432, WLAN_TX_PWR_US_DEFAULT}, - {6, 2437, WLAN_TX_PWR_US_DEFAULT}, - {7, 2442, WLAN_TX_PWR_US_DEFAULT}, - {8, 2447, WLAN_TX_PWR_US_DEFAULT}, - {9, 2452, WLAN_TX_PWR_US_DEFAULT}, - {10, 2457, WLAN_TX_PWR_US_DEFAULT}, - {11, 2462, WLAN_TX_PWR_US_DEFAULT} + {1, 2412, LBS_TX_PWR_US_DEFAULT}, + {2, 2417, LBS_TX_PWR_US_DEFAULT}, + {3, 2422, LBS_TX_PWR_US_DEFAULT}, + {4, 2427, LBS_TX_PWR_US_DEFAULT}, + {5, 2432, LBS_TX_PWR_US_DEFAULT}, + {6, 2437, LBS_TX_PWR_US_DEFAULT}, + {7, 2442, LBS_TX_PWR_US_DEFAULT}, + {8, 2447, LBS_TX_PWR_US_DEFAULT}, + {9, 2452, LBS_TX_PWR_US_DEFAULT}, + {10, 2457, LBS_TX_PWR_US_DEFAULT}, + {11, 2462, LBS_TX_PWR_US_DEFAULT} }; /* band: 'B/G', region: Europe ETSI */ static struct chan_freq_power channel_freq_power_EU_BG[] = { - {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT}, - {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT}, - {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT}, - {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT}, - {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT}, - {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT}, - {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT}, - {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT}, - {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT}, - {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT}, - {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT}, - {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT}, - {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT} + {1, 2412, LBS_TX_PWR_EMEA_DEFAULT}, + {2, 2417, LBS_TX_PWR_EMEA_DEFAULT}, + {3, 2422, LBS_TX_PWR_EMEA_DEFAULT}, + {4, 2427, LBS_TX_PWR_EMEA_DEFAULT}, + {5, 2432, LBS_TX_PWR_EMEA_DEFAULT}, + {6, 2437, LBS_TX_PWR_EMEA_DEFAULT}, + {7, 2442, LBS_TX_PWR_EMEA_DEFAULT}, + {8, 2447, LBS_TX_PWR_EMEA_DEFAULT}, + {9, 2452, LBS_TX_PWR_EMEA_DEFAULT}, + {10, 2457, LBS_TX_PWR_EMEA_DEFAULT}, + {11, 2462, LBS_TX_PWR_EMEA_DEFAULT}, + {12, 2467, LBS_TX_PWR_EMEA_DEFAULT}, + {13, 2472, LBS_TX_PWR_EMEA_DEFAULT} }; /* band: 'B/G', region: Spain */ static struct chan_freq_power channel_freq_power_SPN_BG[] = { - {10, 2457, WLAN_TX_PWR_DEFAULT}, - {11, 2462, WLAN_TX_PWR_DEFAULT} + {10, 2457, LBS_TX_PWR_DEFAULT}, + {11, 2462, LBS_TX_PWR_DEFAULT} }; /* band: 'B/G', region: France */ static struct chan_freq_power channel_freq_power_FR_BG[] = { - {10, 2457, WLAN_TX_PWR_FR_DEFAULT}, - {11, 2462, WLAN_TX_PWR_FR_DEFAULT}, - {12, 2467, WLAN_TX_PWR_FR_DEFAULT}, - {13, 2472, WLAN_TX_PWR_FR_DEFAULT} + {10, 2457, LBS_TX_PWR_FR_DEFAULT}, + {11, 2462, LBS_TX_PWR_FR_DEFAULT}, + {12, 2467, LBS_TX_PWR_FR_DEFAULT}, + {13, 2472, LBS_TX_PWR_FR_DEFAULT} }; /* band: 'B/G', region: Japan */ static struct chan_freq_power channel_freq_power_JPN_BG[] = { - {1, 2412, WLAN_TX_PWR_JP_DEFAULT}, - {2, 2417, WLAN_TX_PWR_JP_DEFAULT}, - {3, 2422, WLAN_TX_PWR_JP_DEFAULT}, - {4, 2427, WLAN_TX_PWR_JP_DEFAULT}, - {5, 2432, WLAN_TX_PWR_JP_DEFAULT}, - {6, 2437, WLAN_TX_PWR_JP_DEFAULT}, - {7, 2442, WLAN_TX_PWR_JP_DEFAULT}, - {8, 2447, WLAN_TX_PWR_JP_DEFAULT}, - {9, 2452, WLAN_TX_PWR_JP_DEFAULT}, - {10, 2457, WLAN_TX_PWR_JP_DEFAULT}, - {11, 2462, WLAN_TX_PWR_JP_DEFAULT}, - {12, 2467, WLAN_TX_PWR_JP_DEFAULT}, - {13, 2472, WLAN_TX_PWR_JP_DEFAULT}, - {14, 2484, WLAN_TX_PWR_JP_DEFAULT} + {1, 2412, LBS_TX_PWR_JP_DEFAULT}, + {2, 2417, LBS_TX_PWR_JP_DEFAULT}, + {3, 2422, LBS_TX_PWR_JP_DEFAULT}, + {4, 2427, LBS_TX_PWR_JP_DEFAULT}, + {5, 2432, LBS_TX_PWR_JP_DEFAULT}, + {6, 2437, LBS_TX_PWR_JP_DEFAULT}, + {7, 2442, LBS_TX_PWR_JP_DEFAULT}, + {8, 2447, LBS_TX_PWR_JP_DEFAULT}, + {9, 2452, LBS_TX_PWR_JP_DEFAULT}, + {10, 2457, LBS_TX_PWR_JP_DEFAULT}, + {11, 2462, LBS_TX_PWR_JP_DEFAULT}, + {12, 2467, LBS_TX_PWR_JP_DEFAULT}, + {13, 2472, LBS_TX_PWR_JP_DEFAULT}, + {14, 2484, LBS_TX_PWR_JP_DEFAULT} }; /** @@ -153,13 +153,13 @@ static struct region_cfp_table region_cfp_table[] = { /** * the table to keep region code */ -u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = +u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; /** * 802.11b/g supported bitrates (in 500Kb/s units) */ -u8 libertas_bg_rates[MAX_RATES] = +u8 lbs_bg_rates[MAX_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0x00, 0x00 }; @@ -179,7 +179,7 @@ static u8 fw_data_rates[MAX_RATES] = * @param idx The index of data rate * @return data rate or 0 */ -u32 libertas_fw_index_to_data_rate(u8 idx) +u32 lbs_fw_index_to_data_rate(u8 idx) { if (idx >= sizeof(fw_data_rates)) idx = 0; @@ -192,7 +192,7 @@ u32 libertas_fw_index_to_data_rate(u8 idx) * @param rate data rate * @return index or 0 */ -u8 libertas_data_rate_to_fw_index(u32 rate) +u8 lbs_data_rate_to_fw_index(u32 rate) { u8 i; @@ -213,16 +213,18 @@ u8 libertas_data_rate_to_fw_index(u32 rate) /** * @brief Get function for sysfs attribute anycast_mask */ -static ssize_t libertas_anycast_get(struct device * dev, +static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) { + struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_access mesh_access; + int ret; memset(&mesh_access, 0, sizeof(mesh_access)); - libertas_prepare_and_send_command(to_net_dev(dev)->priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_GET_ANYCAST, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access); + if (ret) + return ret; return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0])); } @@ -230,244 +232,191 @@ static ssize_t libertas_anycast_get(struct device * dev, /** * @brief Set function for sysfs attribute anycast_mask */ -static ssize_t libertas_anycast_set(struct device * dev, +static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { + struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_access mesh_access; uint32_t datum; + int ret; memset(&mesh_access, 0, sizeof(mesh_access)); sscanf(buf, "%x", &datum); mesh_access.data[0] = cpu_to_le32(datum); - libertas_prepare_and_send_command((to_net_dev(dev))->priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_SET_ANYCAST, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access); + if (ret) + return ret; + return strlen(buf); } -int libertas_add_rtap(wlan_private *priv); -void libertas_remove_rtap(wlan_private *priv); +static int lbs_add_rtap(struct lbs_private *priv); +static void lbs_remove_rtap(struct lbs_private *priv); +static int lbs_add_mesh(struct lbs_private *priv); +static void lbs_remove_mesh(struct lbs_private *priv); + /** * Get function for sysfs attribute rtap */ -static ssize_t libertas_rtap_get(struct device * dev, +static ssize_t lbs_rtap_get(struct device *dev, struct device_attribute *attr, char * buf) { - wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; - wlan_adapter *adapter = priv->adapter; - return snprintf(buf, 5, "0x%X\n", adapter->monitormode); + struct lbs_private *priv = to_net_dev(dev)->priv; + return snprintf(buf, 5, "0x%X\n", priv->monitormode); } /** * Set function for sysfs attribute rtap */ -static ssize_t libertas_rtap_set(struct device * dev, +static ssize_t lbs_rtap_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { int monitor_mode; - wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = to_net_dev(dev)->priv; sscanf(buf, "%x", &monitor_mode); - if (monitor_mode != WLAN_MONITOR_OFF) { - if(adapter->monitormode == monitor_mode) + if (monitor_mode != LBS_MONITOR_OFF) { + if(priv->monitormode == monitor_mode) return strlen(buf); - if (adapter->monitormode == WLAN_MONITOR_OFF) { - if (adapter->mode == IW_MODE_INFRA) - libertas_send_deauthentication(priv); - else if (adapter->mode == IW_MODE_ADHOC) - libertas_stop_adhoc_network(priv); - libertas_add_rtap(priv); + if (priv->monitormode == LBS_MONITOR_OFF) { + if (priv->infra_open || priv->mesh_open) + return -EBUSY; + if (priv->mode == IW_MODE_INFRA) + lbs_send_deauthentication(priv); + else if (priv->mode == IW_MODE_ADHOC) + lbs_stop_adhoc_network(priv); + lbs_add_rtap(priv); } - adapter->monitormode = monitor_mode; + priv->monitormode = monitor_mode; } else { - if(adapter->monitormode == WLAN_MONITOR_OFF) + if (priv->monitormode == LBS_MONITOR_OFF) return strlen(buf); - adapter->monitormode = WLAN_MONITOR_OFF; - libertas_remove_rtap(priv); - netif_wake_queue(priv->dev); - netif_wake_queue(priv->mesh_dev); + priv->monitormode = LBS_MONITOR_OFF; + lbs_remove_rtap(priv); + + if (priv->currenttxskb) { + dev_kfree_skb_any(priv->currenttxskb); + priv->currenttxskb = NULL; + } + + /* Wake queues, command thread, etc. */ + lbs_host_to_card_done(priv); } - libertas_prepare_and_send_command(priv, + lbs_prepare_and_send_command(priv, CMD_802_11_MONITOR_MODE, CMD_ACT_SET, - CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode); + CMD_OPTION_WAITFORRSP, 0, &priv->monitormode); return strlen(buf); } /** - * libertas_rtap attribute to be exported per mshX interface - * through sysfs (/sys/class/net/mshX/libertas-rtap) + * lbs_rtap attribute to be exported per ethX interface + * through sysfs (/sys/class/net/ethX/lbs_rtap) */ -static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get, - libertas_rtap_set ); +static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); /** - * anycast_mask attribute to be exported per mshX interface - * through sysfs (/sys/class/net/mshX/anycast_mask) + * Get function for sysfs attribute mesh */ -static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set); - -static ssize_t libertas_autostart_enabled_get(struct device * dev, +static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct cmd_ds_mesh_access mesh_access; - - memset(&mesh_access, 0, sizeof(mesh_access)); - libertas_prepare_and_send_command(to_net_dev(dev)->priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_GET_AUTOSTART_ENABLED, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); - - return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0])); + struct lbs_private *priv = to_net_dev(dev)->priv; + return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); } -static ssize_t libertas_autostart_enabled_set(struct device * dev, +/** + * Set function for sysfs attribute mesh + */ +static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct cmd_ds_mesh_access mesh_access; - uint32_t datum; - wlan_private * priv = (to_net_dev(dev))->priv; + struct lbs_private *priv = to_net_dev(dev)->priv; + int enable; int ret; - memset(&mesh_access, 0, sizeof(mesh_access)); - sscanf(buf, "%d", &datum); - mesh_access.data[0] = cpu_to_le32(datum); + sscanf(buf, "%x", &enable); + enable = !!enable; + if (enable == !!priv->mesh_dev) + return count; + + ret = lbs_mesh_config(priv, enable, priv->curbssparams.channel); + if (ret) + return ret; - ret = libertas_prepare_and_send_command(priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_SET_AUTOSTART_ENABLED, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); - if (ret == 0) - priv->mesh_autostart_enabled = datum ? 1 : 0; + if (enable) + lbs_add_mesh(priv); + else + lbs_remove_mesh(priv); - return strlen(buf); + return count; } -static DEVICE_ATTR(autostart_enabled, 0644, - libertas_autostart_enabled_get, libertas_autostart_enabled_set); +/** + * lbs_mesh attribute to be exported per ethX interface + * through sysfs (/sys/class/net/ethX/lbs_mesh) + */ +static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); -static struct attribute *libertas_mesh_sysfs_entries[] = { +/** + * anycast_mask attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/anycast_mask) + */ +static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); + +static struct attribute *lbs_mesh_sysfs_entries[] = { &dev_attr_anycast_mask.attr, - &dev_attr_autostart_enabled.attr, NULL, }; -static struct attribute_group libertas_mesh_attr_group = { - .attrs = libertas_mesh_sysfs_entries, +static struct attribute_group lbs_mesh_attr_group = { + .attrs = lbs_mesh_sysfs_entries, }; /** - * @brief Check if the device can be open and wait if necessary. - * - * @param dev A pointer to net_device structure - * @return 0 - * - * For USB adapter, on some systems the device open handler will be - * called before FW ready. Use the following flag check and wait - * function to work around the issue. - * - */ -static int pre_open_check(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; - int i = 0; - - while (!adapter->fw_ready && i < 20) { - i++; - msleep_interruptible(100); - } - if (!adapter->fw_ready) { - lbs_pr_err("firmware not ready\n"); - return -1; - } - - return 0; -} - -/** - * @brief This function opens the device + * @brief This function opens the ethX or mshX interface * * @param dev A pointer to net_device structure - * @return 0 + * @return 0 or -EBUSY if monitor mode active */ -static int libertas_dev_open(struct net_device *dev) +static int lbs_dev_open(struct net_device *dev) { - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = (struct lbs_private *) dev->priv ; + int ret = 0; lbs_deb_enter(LBS_DEB_NET); - priv->open = 1; + spin_lock_irq(&priv->driver_lock); - if (adapter->connect_status == LIBERTAS_CONNECTED) { - netif_carrier_on(priv->dev); - if (priv->mesh_dev) - netif_carrier_on(priv->mesh_dev); - } else { - netif_carrier_off(priv->dev); - if (priv->mesh_dev) - netif_carrier_off(priv->mesh_dev); + if (priv->monitormode != LBS_MONITOR_OFF) { + ret = -EBUSY; + goto out; } - lbs_deb_leave(LBS_DEB_NET); - return 0; -} -/** - * @brief This function opens the mshX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int libertas_mesh_open(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv ; - - if (pre_open_check(dev) == -1) - return -1; - priv->mesh_open = 1 ; - netif_wake_queue(priv->mesh_dev); - if (priv->infra_open == 0) - return libertas_dev_open(priv->dev) ; - return 0; -} - -/** - * @brief This function opens the ethX interface - * - * @param dev A pointer to net_device structure - * @return 0 - */ -static int libertas_open(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv ; - - if(pre_open_check(dev) == -1) - return -1; - priv->infra_open = 1 ; - netif_wake_queue(priv->dev); - if (priv->open == 0) - return libertas_dev_open(priv->dev) ; - return 0; -} - -static int libertas_dev_close(struct net_device *dev) -{ - wlan_private *priv = dev->priv; + if (dev == priv->mesh_dev) { + priv->mesh_open = 1; + priv->mesh_connect_status = LBS_CONNECTED; + netif_carrier_on(dev); + } else { + priv->infra_open = 1; - lbs_deb_enter(LBS_DEB_NET); + if (priv->connect_status == LBS_CONNECTED) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + } - netif_carrier_off(priv->dev); - priv->open = 0; + if (!priv->tx_pending_len) + netif_wake_queue(dev); + out: - lbs_deb_leave(LBS_DEB_NET); - return 0; + spin_unlock_irq(&priv->driver_lock); + lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); + return ret; } /** @@ -476,16 +425,23 @@ static int libertas_dev_close(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int libertas_mesh_close(struct net_device *dev) +static int lbs_mesh_stop(struct net_device *dev) { - wlan_private *priv = (wlan_private *) (dev->priv); + struct lbs_private *priv = (struct lbs_private *) (dev->priv); + + lbs_deb_enter(LBS_DEB_MESH); + spin_lock_irq(&priv->driver_lock); priv->mesh_open = 0; - netif_stop_queue(priv->mesh_dev); - if (priv->infra_open == 0) - return libertas_dev_close(dev); - else - return 0; + priv->mesh_connect_status = LBS_DISCONNECTED; + + netif_stop_queue(dev); + netif_carrier_off(dev); + + spin_unlock_irq(&priv->driver_lock); + + lbs_deb_leave(LBS_DEB_MESH); + return 0; } /** @@ -494,134 +450,86 @@ static int libertas_mesh_close(struct net_device *dev) * @param dev A pointer to net_device structure * @return 0 */ -static int libertas_close(struct net_device *dev) -{ - wlan_private *priv = (wlan_private *) dev->priv; - - netif_stop_queue(dev); - priv->infra_open = 0; - if (priv->mesh_open == 0) - return libertas_dev_close(dev); - else - return 0; -} - - -static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int lbs_eth_stop(struct net_device *dev) { - int ret = 0; - wlan_private *priv = dev->priv; + struct lbs_private *priv = (struct lbs_private *) dev->priv; lbs_deb_enter(LBS_DEB_NET); - if (priv->dnld_sent || priv->adapter->TxLockFlag) { - priv->stats.tx_dropped++; - goto done; - } - - netif_stop_queue(priv->dev); - if (priv->mesh_dev) - netif_stop_queue(priv->mesh_dev); + spin_lock_irq(&priv->driver_lock); + priv->infra_open = 0; + netif_stop_queue(dev); + spin_unlock_irq(&priv->driver_lock); - if (libertas_process_tx(priv, skb) == 0) - dev->trans_start = jiffies; -done: - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); - return ret; + lbs_deb_leave(LBS_DEB_NET); + return 0; } -/** - * @brief Mark mesh packets and handover them to libertas_hard_start_xmit - * - */ -static int libertas_mesh_pre_start_xmit(struct sk_buff *skb, - struct net_device *dev) +static void lbs_tx_timeout(struct net_device *dev) { - wlan_private *priv = dev->priv; - int ret; - - lbs_deb_enter(LBS_DEB_MESH); - if(priv->adapter->monitormode != WLAN_MONITOR_OFF) { - netif_stop_queue(dev); - return -EOPNOTSUPP; - } - - SET_MESH_FRAME(skb); + struct lbs_private *priv = (struct lbs_private *) dev->priv; - ret = libertas_hard_start_xmit(skb, priv->dev); - lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); - return ret; -} + lbs_deb_enter(LBS_DEB_TX); -/** - * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit - * - */ -static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - wlan_private *priv = dev->priv; - int ret; + lbs_pr_err("tx watch dog timeout\n"); - lbs_deb_enter(LBS_DEB_NET); + dev->trans_start = jiffies; - if(priv->adapter->monitormode != WLAN_MONITOR_OFF) { - netif_stop_queue(dev); - return -EOPNOTSUPP; + if (priv->currenttxskb) { + priv->eventcause = 0x01000000; + lbs_send_tx_feedback(priv); } + /* XX: Shouldn't we also call into the hw-specific driver + to kick it somehow? */ + lbs_host_to_card_done(priv); - UNSET_MESH_FRAME(skb); + /* More often than not, this actually happens because the + firmware has crapped itself -- rather than just a very + busy medium. So send a harmless command, and if/when + _that_ times out, we'll kick it in the head. */ + lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + 0, 0, NULL); - ret = libertas_hard_start_xmit(skb, dev); - lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); - return ret; + lbs_deb_leave(LBS_DEB_TX); } -static void libertas_tx_timeout(struct net_device *dev) +void lbs_host_to_card_done(struct lbs_private *priv) { - wlan_private *priv = (wlan_private *) dev->priv; + unsigned long flags; - lbs_deb_enter(LBS_DEB_TX); + lbs_deb_enter(LBS_DEB_THREAD); - lbs_pr_err("tx watch dog timeout\n"); + spin_lock_irqsave(&priv->driver_lock, flags); priv->dnld_sent = DNLD_RES_RECEIVED; - dev->trans_start = jiffies; - if (priv->adapter->currenttxskb) { - if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { - /* If we are here, we have not received feedback from - the previous packet. Assume TX_FAIL and move on. */ - priv->adapter->eventcause = 0x01000000; - libertas_send_tx_feedback(priv); - } else - wake_up_interruptible(&priv->waitq); - } else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { - netif_wake_queue(priv->dev); - if (priv->mesh_dev) - netif_wake_queue(priv->mesh_dev); - } + /* Wake main thread if commands are pending */ + if (!priv->cur_cmd || priv->tx_pending_len > 0) + wake_up_interruptible(&priv->waitq); - lbs_deb_leave(LBS_DEB_TX); + spin_unlock_irqrestore(&priv->driver_lock, flags); + lbs_deb_leave(LBS_DEB_THREAD); } +EXPORT_SYMBOL_GPL(lbs_host_to_card_done); /** * @brief This function returns the network statistics * - * @param dev A pointer to wlan_private structure + * @param dev A pointer to struct lbs_private structure * @return A pointer to net_device_stats structure */ -static struct net_device_stats *libertas_get_stats(struct net_device *dev) +static struct net_device_stats *lbs_get_stats(struct net_device *dev) { - wlan_private *priv = (wlan_private *) dev->priv; + struct lbs_private *priv = (struct lbs_private *) dev->priv; + lbs_deb_enter(LBS_DEB_NET); return &priv->stats; } -static int libertas_set_mac_address(struct net_device *dev, void *addr) +static int lbs_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; - wlan_private *priv = (wlan_private *) dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = (struct lbs_private *) dev->priv; struct sockaddr *phwaddr = addr; lbs_deb_enter(LBS_DEB_NET); @@ -629,15 +537,15 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr) /* In case it was called from the mesh device */ dev = priv->dev ; - memset(adapter->current_addr, 0, ETH_ALEN); + memset(priv->current_addr, 0, ETH_ALEN); /* dev->dev_addr is 8 bytes */ lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN); lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN); - memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); + memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); @@ -647,89 +555,86 @@ static int libertas_set_mac_address(struct net_device *dev, void *addr) goto done; } - lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN); - memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN); + lbs_deb_hex(LBS_DEB_NET, "priv->macaddr", priv->current_addr, ETH_ALEN); + memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN); if (priv->mesh_dev) - memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); + memcpy(priv->mesh_dev->dev_addr, priv->current_addr, ETH_ALEN); done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } -static int libertas_copy_multicast_address(wlan_adapter * adapter, +static int lbs_copy_multicast_address(struct lbs_private *priv, struct net_device *dev) { int i = 0; struct dev_mc_list *mcptr = dev->mc_list; for (i = 0; i < dev->mc_count; i++) { - memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); + memcpy(&priv->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); mcptr = mcptr->next; } - return i; - } -static void libertas_set_multicast_list(struct net_device *dev) +static void lbs_set_multicast_list(struct net_device *dev) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int oldpacketfilter; DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_NET); - oldpacketfilter = adapter->currentpacketfilter; + oldpacketfilter = priv->currentpacketfilter; if (dev->flags & IFF_PROMISC) { lbs_deb_net("enable promiscuous mode\n"); - adapter->currentpacketfilter |= + priv->currentpacketfilter |= CMD_ACT_MAC_PROMISCUOUS_ENABLE; - adapter->currentpacketfilter &= + priv->currentpacketfilter &= ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE | CMD_ACT_MAC_MULTICAST_ENABLE); } else { /* Multicast */ - adapter->currentpacketfilter &= + priv->currentpacketfilter &= ~CMD_ACT_MAC_PROMISCUOUS_ENABLE; if (dev->flags & IFF_ALLMULTI || dev->mc_count > MRVDRV_MAX_MULTICAST_LIST_SIZE) { lbs_deb_net( "enabling all multicast\n"); - adapter->currentpacketfilter |= + priv->currentpacketfilter |= CMD_ACT_MAC_ALL_MULTICAST_ENABLE; - adapter->currentpacketfilter &= + priv->currentpacketfilter &= ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { - adapter->currentpacketfilter &= + priv->currentpacketfilter &= ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE; if (!dev->mc_count) { lbs_deb_net("no multicast addresses, " "disabling multicast\n"); - adapter->currentpacketfilter &= + priv->currentpacketfilter &= ~CMD_ACT_MAC_MULTICAST_ENABLE; } else { int i; - adapter->currentpacketfilter |= + priv->currentpacketfilter |= CMD_ACT_MAC_MULTICAST_ENABLE; - adapter->nr_of_multicastmacaddr = - libertas_copy_multicast_address(adapter, dev); + priv->nr_of_multicastmacaddr = + lbs_copy_multicast_address(priv, dev); lbs_deb_net("multicast addresses: %d\n", dev->mc_count); for (i = 0; i < dev->mc_count; i++) { - lbs_deb_net("Multicast address %d:%s\n", + lbs_deb_net("Multicast address %d: %s\n", i, print_mac(mac, - adapter->multicastlist[i])); + priv->multicastlist[i])); } /* send multicast addresses to firmware */ - libertas_prepare_and_send_command(priv, + lbs_prepare_and_send_command(priv, CMD_MAC_MULTICAST_ADR, CMD_ACT_SET, 0, 0, NULL); @@ -737,26 +642,25 @@ static void libertas_set_multicast_list(struct net_device *dev) } } - if (adapter->currentpacketfilter != oldpacketfilter) { - libertas_set_mac_packet_filter(priv); + if (priv->currentpacketfilter != oldpacketfilter) { + lbs_set_mac_packet_filter(priv); } lbs_deb_leave(LBS_DEB_NET); } /** - * @brief This function handles the major jobs in the WLAN driver. + * @brief This function handles the major jobs in the LBS driver. * It handles all events generated by firmware, RX data received * from firmware and TX data sent from kernel. * - * @param data A pointer to wlan_thread structure + * @param data A pointer to lbs_thread structure * @return 0 */ -static int libertas_thread(void *data) +static int lbs_thread(void *data) { struct net_device *dev = data; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; wait_queue_t wait; u8 ireg = 0; @@ -764,215 +668,291 @@ static int libertas_thread(void *data) init_waitqueue_entry(&wait, current); - set_freezable(); for (;;) { - lbs_deb_thread( "main-thread 111: intcounter=%d " - "currenttxskb=%p dnld_sent=%d\n", - adapter->intcounter, - adapter->currenttxskb, priv->dnld_sent); + int shouldsleep; + + lbs_deb_thread( "main-thread 111: intcounter=%d currenttxskb=%p dnld_sent=%d\n", + priv->intcounter, priv->currenttxskb, priv->dnld_sent); add_wait_queue(&priv->waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(&adapter->driver_lock); - if ((adapter->psstate == PS_STATE_SLEEP) || - (!adapter->intcounter - && (priv->dnld_sent || adapter->cur_cmd || - list_empty(&adapter->cmdpendingq)))) { - lbs_deb_thread( - "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", - adapter->connect_status, adapter->intcounter, - adapter->psmode, adapter->psstate); - spin_unlock_irq(&adapter->driver_lock); + spin_lock_irq(&priv->driver_lock); + + if (kthread_should_stop()) + shouldsleep = 0; /* Bye */ + else if (priv->surpriseremoved) + shouldsleep = 1; /* We need to wait until we're _told_ to die */ + else if (priv->psstate == PS_STATE_SLEEP) + shouldsleep = 1; /* Sleep mode. Nothing we can do till it wakes */ + else if (priv->intcounter) + shouldsleep = 0; /* Interrupt pending. Deal with it now */ + else if (priv->cmd_timed_out) + shouldsleep = 0; /* Command timed out. Recover */ + else if (!priv->fw_ready) + shouldsleep = 1; /* Firmware not ready. We're waiting for it */ + else if (priv->dnld_sent) + shouldsleep = 1; /* Something is en route to the device already */ + else if (priv->tx_pending_len > 0) + shouldsleep = 0; /* We've a packet to send */ + else if (priv->cur_cmd) + shouldsleep = 1; /* Can't send a command; one already running */ + else if (!list_empty(&priv->cmdpendingq)) + shouldsleep = 0; /* We have a command to send */ + else + shouldsleep = 1; /* No command */ + + if (shouldsleep) { + lbs_deb_thread("main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", + priv->connect_status, priv->intcounter, + priv->psmode, priv->psstate); + spin_unlock_irq(&priv->driver_lock); schedule(); } else - spin_unlock_irq(&adapter->driver_lock); + spin_unlock_irq(&priv->driver_lock); - lbs_deb_thread( - "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " - "dnld_sent=%d\n", adapter->intcounter, - adapter->currenttxskb, priv->dnld_sent); + lbs_deb_thread("main-thread 222 (waking up): intcounter=%d currenttxskb=%p dnld_sent=%d\n", + priv->intcounter, priv->currenttxskb, priv->dnld_sent); set_current_state(TASK_RUNNING); remove_wait_queue(&priv->waitq, &wait); - try_to_freeze(); - - lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p " - "dnld_sent=%d\n", - adapter->intcounter, - adapter->currenttxskb, priv->dnld_sent); - - if (kthread_should_stop() - || adapter->surpriseremoved) { - lbs_deb_thread( - "main-thread: break from main thread: surpriseremoved=0x%x\n", - adapter->surpriseremoved); + + lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p dnld_sent=%d\n", + priv->intcounter, priv->currenttxskb, priv->dnld_sent); + + if (kthread_should_stop()) { + lbs_deb_thread("main-thread: break from main thread\n"); break; } + if (priv->surpriseremoved) { + lbs_deb_thread("adapter removed; waiting to die...\n"); + continue; + } + + spin_lock_irq(&priv->driver_lock); - spin_lock_irq(&adapter->driver_lock); - if (adapter->intcounter) { + if (priv->intcounter) { u8 int_status; - adapter->intcounter = 0; + + priv->intcounter = 0; int_status = priv->hw_get_int_status(priv, &ireg); if (int_status) { - lbs_deb_thread( - "main-thread: reading HOST_INT_STATUS_REG failed\n"); - spin_unlock_irq(&adapter->driver_lock); + lbs_deb_thread("main-thread: reading HOST_INT_STATUS_REG failed\n"); + spin_unlock_irq(&priv->driver_lock); continue; } - adapter->hisregcpy |= ireg; + priv->hisregcpy |= ireg; } - lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p " - "dnld_sent=%d\n", - adapter->intcounter, - adapter->currenttxskb, priv->dnld_sent); + lbs_deb_thread("main-thread 444: intcounter=%d currenttxskb=%p dnld_sent=%d\n", + priv->intcounter, priv->currenttxskb, priv->dnld_sent); /* command response? */ - if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) { + if (priv->hisregcpy & MRVDRV_CMD_UPLD_RDY) { lbs_deb_thread("main-thread: cmd response ready\n"); - adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; - spin_unlock_irq(&adapter->driver_lock); - libertas_process_rx_command(priv); - spin_lock_irq(&adapter->driver_lock); + priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY; + spin_unlock_irq(&priv->driver_lock); + lbs_process_rx_command(priv); + spin_lock_irq(&priv->driver_lock); } + if (priv->cmd_timed_out && priv->cur_cmd) { + struct cmd_ctrl_node *cmdnode = priv->cur_cmd; + + if (++priv->nr_retries > 10) { + lbs_pr_info("Excessive timeouts submitting command %x\n", + le16_to_cpu(cmdnode->cmdbuf->command)); + lbs_complete_command(priv, cmdnode, -ETIMEDOUT); + priv->nr_retries = 0; + } else { + priv->cur_cmd = NULL; + lbs_pr_info("requeueing command %x due to timeout (#%d)\n", + le16_to_cpu(cmdnode->cmdbuf->command), priv->nr_retries); + + /* Stick it back at the _top_ of the pending queue + for immediate resubmission */ + list_add(&cmdnode->list, &priv->cmdpendingq); + } + } + priv->cmd_timed_out = 0; + /* Any Card Event */ - if (adapter->hisregcpy & MRVDRV_CARDEVENT) { + if (priv->hisregcpy & MRVDRV_CARDEVENT) { lbs_deb_thread("main-thread: Card Event Activity\n"); - adapter->hisregcpy &= ~MRVDRV_CARDEVENT; + priv->hisregcpy &= ~MRVDRV_CARDEVENT; if (priv->hw_read_event_cause(priv)) { - lbs_pr_alert( - "main-thread: hw_read_event_cause failed\n"); - spin_unlock_irq(&adapter->driver_lock); + lbs_pr_alert("main-thread: hw_read_event_cause failed\n"); + spin_unlock_irq(&priv->driver_lock); continue; } - spin_unlock_irq(&adapter->driver_lock); - libertas_process_event(priv); + spin_unlock_irq(&priv->driver_lock); + lbs_process_event(priv); } else - spin_unlock_irq(&adapter->driver_lock); + spin_unlock_irq(&priv->driver_lock); + + if (!priv->fw_ready) + continue; /* Check if we need to confirm Sleep Request received previously */ - if (adapter->psstate == PS_STATE_PRE_SLEEP) { - if (!priv->dnld_sent && !adapter->cur_cmd) { - if (adapter->connect_status == - LIBERTAS_CONNECTED) { - lbs_deb_thread( - "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p " - "dnld_sent=%d cur_cmd=%p, confirm now\n", - adapter->intcounter, - adapter->currenttxskb, - priv->dnld_sent, - adapter->cur_cmd); - - libertas_ps_confirm_sleep(priv, - (u16) adapter->psmode); - } else { - /* workaround for firmware sending - * deauth/linkloss event immediately - * after sleep request, remove this - * after firmware fixes it - */ - adapter->psstate = PS_STATE_AWAKE; - lbs_pr_alert( - "main-thread: ignore PS_SleepConfirm in non-connected state\n"); - } + if (priv->psstate == PS_STATE_PRE_SLEEP && + !priv->dnld_sent && !priv->cur_cmd) { + if (priv->connect_status == LBS_CONNECTED) { + lbs_deb_thread("main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p dnld_sent=%d cur_cmd=%p, confirm now\n", + priv->intcounter, priv->currenttxskb, priv->dnld_sent, priv->cur_cmd); + + lbs_ps_confirm_sleep(priv, (u16) priv->psmode); + } else { + /* workaround for firmware sending + * deauth/linkloss event immediately + * after sleep request; remove this + * after firmware fixes it + */ + priv->psstate = PS_STATE_AWAKE; + lbs_pr_alert("main-thread: ignore PS_SleepConfirm in non-connected state\n"); } } /* The PS state is changed during processing of Sleep Request * event above */ - if ((priv->adapter->psstate == PS_STATE_SLEEP) || - (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) + if ((priv->psstate == PS_STATE_SLEEP) || + (priv->psstate == PS_STATE_PRE_SLEEP)) continue; /* Execute the next command */ - if (!priv->dnld_sent && !priv->adapter->cur_cmd) - libertas_execute_next_command(priv); + if (!priv->dnld_sent && !priv->cur_cmd) + lbs_execute_next_command(priv); /* Wake-up command waiters which can't sleep in - * libertas_prepare_and_send_command + * lbs_prepare_and_send_command */ - if (!adapter->nr_cmd_pending) - wake_up_all(&adapter->cmd_pending); - - libertas_tx_runqueue(priv); + if (!list_empty(&priv->cmdpendingq)) + wake_up_all(&priv->cmd_pending); + + spin_lock_irq(&priv->driver_lock); + if (!priv->dnld_sent && priv->tx_pending_len > 0) { + int ret = priv->hw_host_to_card(priv, MVMS_DAT, + priv->tx_pending_buf, + priv->tx_pending_len); + if (ret) { + lbs_deb_tx("host_to_card failed %d\n", ret); + priv->dnld_sent = DNLD_RES_RECEIVED; + } + priv->tx_pending_len = 0; + if (!priv->currenttxskb) { + /* We can wake the queues immediately if we aren't + waiting for TX feedback */ + if (priv->connect_status == LBS_CONNECTED) + netif_wake_queue(priv->dev); + if (priv->mesh_dev && + priv->mesh_connect_status == LBS_CONNECTED) + netif_wake_queue(priv->mesh_dev); + } + } + spin_unlock_irq(&priv->driver_lock); } - del_timer(&adapter->command_timer); - adapter->nr_cmd_pending = 0; - wake_up_all(&adapter->cmd_pending); + del_timer(&priv->command_timer); + wake_up_all(&priv->cmd_pending); lbs_deb_leave(LBS_DEB_THREAD); return 0; } +static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy, + struct cmd_header *cmd) +{ + lbs_deb_enter(LBS_DEB_FW); + + netif_device_detach(priv->dev); + if (priv->mesh_dev) + netif_device_detach(priv->mesh_dev); + + priv->fw_ready = 0; + lbs_deb_leave(LBS_DEB_FW); + return 0; +} + +int lbs_suspend(struct lbs_private *priv) +{ + struct cmd_header cmd; + int ret; + + lbs_deb_enter(LBS_DEB_FW); + + if (priv->wol_criteria == 0xffffffff) { + lbs_pr_info("Suspend attempt without configuring wake params!\n"); + return -EINVAL; + } + + memset(&cmd, 0, sizeof(cmd)); + + ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd, + sizeof(cmd), lbs_suspend_callback, 0); + if (ret) + lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret); + + lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); + return ret; +} +EXPORT_SYMBOL_GPL(lbs_suspend); + +int lbs_resume(struct lbs_private *priv) +{ + lbs_deb_enter(LBS_DEB_FW); + + priv->fw_ready = 1; + + /* Firmware doesn't seem to give us RX packets any more + until we send it some command. Might as well update */ + lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + 0, 0, NULL); + + netif_device_attach(priv->dev); + if (priv->mesh_dev) + netif_device_attach(priv->mesh_dev); + + lbs_deb_leave(LBS_DEB_FW); + return 0; +} +EXPORT_SYMBOL_GPL(lbs_resume); + /** * @brief This function downloads firmware image, gets * HW spec from firmware and set basic parameters to * firmware. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return 0 or -1 */ -static int wlan_setup_firmware(wlan_private * priv) +static int lbs_setup_firmware(struct lbs_private *priv) { int ret = -1; - wlan_adapter *adapter = priv->adapter; - struct cmd_ds_mesh_access mesh_access; lbs_deb_enter(LBS_DEB_FW); /* * Read MAC address from HW */ - memset(adapter->current_addr, 0xff, ETH_ALEN); - - ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); - + memset(priv->current_addr, 0xff, ETH_ALEN); + ret = lbs_update_hw_spec(priv); if (ret) { ret = -1; goto done; } - libertas_set_mac_packet_filter(priv); - - /* Get the supported Data rates */ - ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, - CMD_ACT_GET_TX_RATE, - CMD_OPTION_WAITFORRSP, 0, NULL); + lbs_set_mac_packet_filter(priv); - if (ret) { + ret = lbs_get_data_rate(priv); + if (ret < 0) { ret = -1; goto done; } - /* Disable mesh autostart */ - if (priv->mesh_dev) { - memset(&mesh_access, 0, sizeof(mesh_access)); - mesh_access.data[0] = cpu_to_le32(0); - ret = libertas_prepare_and_send_command(priv, - CMD_MESH_ACCESS, - CMD_ACT_MESH_SET_AUTOSTART_ENABLED, - CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access); - if (ret) { - ret = -1; - goto done; - } - priv->mesh_autostart_enabled = 0; - } - - /* Set the boot2 version in firmware */ - ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER, - 0, CMD_OPTION_WAITFORRSP, 0, NULL); - ret = 0; done: lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret); @@ -985,164 +965,130 @@ done: */ static void command_timer_fn(unsigned long data) { - wlan_private *priv = (wlan_private *)data; - wlan_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *ptempnode; - struct cmd_ds_command *cmd; + struct lbs_private *priv = (struct lbs_private *)data; unsigned long flags; - ptempnode = adapter->cur_cmd; - if (ptempnode == NULL) { - lbs_deb_fw("ptempnode empty\n"); - return; - } + lbs_deb_enter(LBS_DEB_CMD); + spin_lock_irqsave(&priv->driver_lock, flags); - cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; - if (!cmd) { - lbs_deb_fw("cmd is NULL\n"); - return; + if (!priv->cur_cmd) { + lbs_pr_info("Command timer expired; no pending command\n"); + goto out; } - lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command); - - if (!adapter->fw_ready) - return; - - spin_lock_irqsave(&adapter->driver_lock, flags); - adapter->cur_cmd = NULL; - spin_unlock_irqrestore(&adapter->driver_lock, flags); - - lbs_deb_fw("re-sending same command because of timeout\n"); - libertas_queue_cmd(adapter, ptempnode, 0); + lbs_pr_info("Command %x timed out\n", le16_to_cpu(priv->cur_cmd->cmdbuf->command)); + priv->cmd_timed_out = 1; wake_up_interruptible(&priv->waitq); - - return; +out: + spin_unlock_irqrestore(&priv->driver_lock, flags); + lbs_deb_leave(LBS_DEB_CMD); } -static int libertas_init_adapter(wlan_private * priv) +static int lbs_init_adapter(struct lbs_private *priv) { - wlan_adapter *adapter = priv->adapter; size_t bufsize; int i, ret = 0; + lbs_deb_enter(LBS_DEB_MAIN); + /* Allocate buffer to store the BSSID list */ bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor); - adapter->networks = kzalloc(bufsize, GFP_KERNEL); - if (!adapter->networks) { + priv->networks = kzalloc(bufsize, GFP_KERNEL); + if (!priv->networks) { lbs_pr_err("Out of memory allocating beacons\n"); ret = -1; goto out; } /* Initialize scan result lists */ - INIT_LIST_HEAD(&adapter->network_free_list); - INIT_LIST_HEAD(&adapter->network_list); + INIT_LIST_HEAD(&priv->network_free_list); + INIT_LIST_HEAD(&priv->network_list); for (i = 0; i < MAX_NETWORK_COUNT; i++) { - list_add_tail(&adapter->networks[i].list, - &adapter->network_free_list); + list_add_tail(&priv->networks[i].list, + &priv->network_free_list); } - adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); - adapter->libertas_ps_confirm_sleep.command = + priv->lbs_ps_confirm_sleep.seqnum = cpu_to_le16(++priv->seqnum); + priv->lbs_ps_confirm_sleep.command = cpu_to_le16(CMD_802_11_PS_MODE); - adapter->libertas_ps_confirm_sleep.size = + priv->lbs_ps_confirm_sleep.size = cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); - adapter->libertas_ps_confirm_sleep.action = + priv->lbs_ps_confirm_sleep.action = cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED); - memset(adapter->current_addr, 0xff, ETH_ALEN); - - adapter->connect_status = LIBERTAS_DISCONNECTED; - adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; - adapter->mode = IW_MODE_INFRA; - adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; - adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; - adapter->radioon = RADIO_ON; - adapter->auto_rate = 1; - adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; - adapter->psmode = WLAN802_11POWERMODECAM; - adapter->psstate = PS_STATE_FULL_POWER; + memset(priv->current_addr, 0xff, ETH_ALEN); - mutex_init(&adapter->lock); + priv->connect_status = LBS_DISCONNECTED; + priv->mesh_connect_status = LBS_DISCONNECTED; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + priv->mode = IW_MODE_INFRA; + priv->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL; + priv->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON; + priv->radioon = RADIO_ON; + priv->auto_rate = 1; + priv->capability = WLAN_CAPABILITY_SHORT_PREAMBLE; + priv->psmode = LBS802_11POWERMODECAM; + priv->psstate = PS_STATE_FULL_POWER; - memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); - adapter->tx_queue_idx = 0; - spin_lock_init(&adapter->txqueue_lock); + mutex_init(&priv->lock); - setup_timer(&adapter->command_timer, command_timer_fn, - (unsigned long)priv); + setup_timer(&priv->command_timer, command_timer_fn, + (unsigned long)priv); - INIT_LIST_HEAD(&adapter->cmdfreeq); - INIT_LIST_HEAD(&adapter->cmdpendingq); + INIT_LIST_HEAD(&priv->cmdfreeq); + INIT_LIST_HEAD(&priv->cmdpendingq); - spin_lock_init(&adapter->driver_lock); - init_waitqueue_head(&adapter->cmd_pending); - adapter->nr_cmd_pending = 0; + spin_lock_init(&priv->driver_lock); + init_waitqueue_head(&priv->cmd_pending); /* Allocate the command buffers */ - if (libertas_allocate_cmd_buffer(priv)) { + if (lbs_allocate_cmd_buffer(priv)) { lbs_pr_err("Out of memory allocating command buffers\n"); ret = -1; } out: + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; } -static void libertas_free_adapter(wlan_private * priv) +static void lbs_free_adapter(struct lbs_private *priv) { - wlan_adapter *adapter = priv->adapter; - - if (!adapter) { - lbs_deb_fw("why double free adapter?\n"); - return; - } - - lbs_deb_fw("free command buffer\n"); - libertas_free_cmd_buffer(priv); - - lbs_deb_fw("free command_timer\n"); - del_timer(&adapter->command_timer); + lbs_deb_enter(LBS_DEB_MAIN); - lbs_deb_fw("free scan results table\n"); - kfree(adapter->networks); - adapter->networks = NULL; + lbs_free_cmd_buffer(priv); + del_timer(&priv->command_timer); + kfree(priv->networks); + priv->networks = NULL; - /* Free the adapter object itself */ - lbs_deb_fw("free adapter\n"); - kfree(adapter); - priv->adapter = NULL; + lbs_deb_leave(LBS_DEB_MAIN); } /** * @brief This function adds the card. it will probe the - * card, allocate the wlan_priv and initialize the device. + * card, allocate the lbs_priv and initialize the device. * * @param card A pointer to card - * @return A pointer to wlan_private structure + * @return A pointer to struct lbs_private structure */ -wlan_private *libertas_add_card(void *card, struct device *dmdev) +struct lbs_private *lbs_add_card(void *card, struct device *dmdev) { struct net_device *dev = NULL; - wlan_private *priv = NULL; + struct lbs_private *priv = NULL; - lbs_deb_enter(LBS_DEB_NET); + lbs_deb_enter(LBS_DEB_MAIN); /* Allocate an Ethernet device and register it */ - if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { + dev = alloc_etherdev(sizeof(struct lbs_private)); + if (!dev) { lbs_pr_err("init ethX device failed\n"); goto done; } priv = dev->priv; - /* allocate buffer for wlan_adapter */ - if (!(priv->adapter = kzalloc(sizeof(wlan_adapter), GFP_KERNEL))) { - lbs_pr_err("allocate buffer for wlan_adapter failed\n"); - goto err_kzalloc; - } - - if (libertas_init_adapter(priv)) { + if (lbs_init_adapter(priv)) { lbs_pr_err("failed to initialize adapter structure.\n"); goto err_init_adapter; } @@ -1151,81 +1097,78 @@ wlan_private *libertas_add_card(void *card, struct device *dmdev) priv->card = card; priv->mesh_open = 0; priv->infra_open = 0; - priv->hotplug_device = dmdev; /* Setup the OS Interface to our functions */ - dev->open = libertas_open; - dev->hard_start_xmit = libertas_pre_start_xmit; - dev->stop = libertas_close; - dev->set_mac_address = libertas_set_mac_address; - dev->tx_timeout = libertas_tx_timeout; - dev->get_stats = libertas_get_stats; + dev->open = lbs_dev_open; + dev->hard_start_xmit = lbs_hard_start_xmit; + dev->stop = lbs_eth_stop; + dev->set_mac_address = lbs_set_mac_address; + dev->tx_timeout = lbs_tx_timeout; + dev->get_stats = lbs_get_stats; dev->watchdog_timeo = 5 * HZ; - dev->ethtool_ops = &libertas_ethtool_ops; + dev->ethtool_ops = &lbs_ethtool_ops; #ifdef WIRELESS_EXT - dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; + dev->wireless_handlers = (struct iw_handler_def *)&lbs_handler_def; #endif dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->set_multicast_list = libertas_set_multicast_list; + dev->set_multicast_list = lbs_set_multicast_list; SET_NETDEV_DEV(dev, dmdev); priv->rtap_net_dev = NULL; - if (device_create_file(dmdev, &dev_attr_libertas_rtap)) - goto err_init_adapter; lbs_deb_thread("Starting main thread...\n"); init_waitqueue_head(&priv->waitq); - priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main"); + priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main"); if (IS_ERR(priv->main_thread)) { lbs_deb_thread("Error creating main thread.\n"); - goto err_kthread_run; + goto err_init_adapter; } - priv->work_thread = create_singlethread_workqueue("libertas_worker"); - INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker); - INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker); - INIT_WORK(&priv->sync_channel, libertas_sync_channel); + priv->work_thread = create_singlethread_workqueue("lbs_worker"); + INIT_DELAYED_WORK(&priv->assoc_work, lbs_association_worker); + INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker); + INIT_WORK(&priv->sync_channel, lbs_sync_channel); - goto done; + sprintf(priv->mesh_ssid, "mesh"); + priv->mesh_ssid_len = 4; -err_kthread_run: - device_remove_file(dmdev, &dev_attr_libertas_rtap); + priv->wol_criteria = 0xffffffff; + priv->wol_gpio = 0xff; -err_init_adapter: - libertas_free_adapter(priv); + goto done; -err_kzalloc: +err_init_adapter: + lbs_free_adapter(priv); free_netdev(dev); priv = NULL; done: - lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv); + lbs_deb_leave_args(LBS_DEB_MAIN, "priv %p", priv); return priv; } -EXPORT_SYMBOL_GPL(libertas_add_card); +EXPORT_SYMBOL_GPL(lbs_add_card); -int libertas_remove_card(wlan_private *priv) +int lbs_remove_card(struct lbs_private *priv) { - wlan_adapter *adapter = priv->adapter; struct net_device *dev = priv->dev; union iwreq_data wrqu; lbs_deb_enter(LBS_DEB_MAIN); - libertas_remove_rtap(priv); + lbs_remove_mesh(priv); + lbs_remove_rtap(priv); dev = priv->dev; - device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap); cancel_delayed_work(&priv->scan_work); cancel_delayed_work(&priv->assoc_work); destroy_workqueue(priv->work_thread); - if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) { - adapter->psmode = WLAN802_11POWERMODECAM; - libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); + if (priv->psmode == LBS802_11POWERMODEMAX_PSP) { + priv->psmode = LBS802_11POWERMODECAM; + lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); @@ -1233,10 +1176,10 @@ int libertas_remove_card(wlan_private *priv) wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); /* Stop the thread servicing the interrupts */ - adapter->surpriseremoved = 1; + priv->surpriseremoved = 1; kthread_stop(priv->main_thread); - libertas_free_adapter(priv); + lbs_free_adapter(priv); priv->dev = NULL; free_netdev(dev); @@ -1244,10 +1187,10 @@ int libertas_remove_card(wlan_private *priv) lbs_deb_leave(LBS_DEB_MAIN); return 0; } -EXPORT_SYMBOL_GPL(libertas_remove_card); +EXPORT_SYMBOL_GPL(lbs_remove_card); -int libertas_start_card(wlan_private *priv) +int lbs_start_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; int ret = -1; @@ -1255,19 +1198,52 @@ int libertas_start_card(wlan_private *priv) lbs_deb_enter(LBS_DEB_MAIN); /* poke the firmware */ - ret = wlan_setup_firmware(priv); + ret = lbs_setup_firmware(priv); if (ret) goto done; /* init 802.11d */ - libertas_init_11d(priv); + lbs_init_11d(priv); if (register_netdev(dev)) { 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); + + /* 5.0.16p0 is known to NOT support any mesh */ + if (priv->fwrelease > 0x05001000) { + /* Enable mesh, if supported, and work out which TLV it uses. + 0x100 + 291 is an unofficial value used in 5.110.20.pXX + 0x100 + 37 is the official value used in 5.110.21.pXX + but we check them in that order because 20.pXX doesn't + give an error -- it just silently fails. */ + + /* 5.110.20.pXX firmware will fail the command if the channel + doesn't match the existing channel. But only if the TLV + is correct. If the channel is wrong, _BOTH_ versions will + give an error to 0x100+291, and allow 0x100+37 to succeed. + It's just that 5.110.20.pXX will not have done anything + useful */ + + priv->mesh_tlv = 0x100 + 291; + if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) { + priv->mesh_tlv = 0x100 + 37; + if (lbs_mesh_config(priv, 1, priv->curbssparams.channel)) + priv->mesh_tlv = 0; + } + if (priv->mesh_tlv) { + lbs_add_mesh(priv); - libertas_debugfs_init_one(priv, dev); + if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) + lbs_pr_err("cannot register lbs_mesh attribute\n"); + } + } + + lbs_debugfs_init_one(priv, dev); lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name); @@ -1277,10 +1253,10 @@ done: lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_start_card); +EXPORT_SYMBOL_GPL(lbs_start_card); -int libertas_stop_card(wlan_private *priv) +int lbs_stop_card(struct lbs_private *priv) { struct net_device *dev = priv->dev; int ret = -1; @@ -1292,31 +1268,35 @@ int libertas_stop_card(wlan_private *priv) netif_stop_queue(priv->dev); netif_carrier_off(priv->dev); - libertas_debugfs_remove_one(priv); + 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); /* Flush pending command nodes */ - spin_lock_irqsave(&priv->adapter->driver_lock, flags); - list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { + spin_lock_irqsave(&priv->driver_lock, flags); + list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { + cmdnode->result = -ENOENT; cmdnode->cmdwaitqwoken = 1; wake_up_interruptible(&cmdnode->cmdwait_q); } - spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); + spin_unlock_irqrestore(&priv->driver_lock, flags); unregister_netdev(dev); lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_stop_card); +EXPORT_SYMBOL_GPL(lbs_stop_card); /** * @brief This function adds mshX interface * - * @param priv A pointer to the wlan_private structure + * @param priv A pointer to the struct lbs_private structure * @return 0 if successful, -X otherwise */ -int libertas_add_mesh(wlan_private *priv, struct device *dev) +static int lbs_add_mesh(struct lbs_private *priv) { struct net_device *mesh_dev = NULL; int ret = 0; @@ -1332,16 +1312,16 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) mesh_dev->priv = priv; priv->mesh_dev = mesh_dev; - mesh_dev->open = libertas_mesh_open; - mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit; - mesh_dev->stop = libertas_mesh_close; - mesh_dev->get_stats = libertas_get_stats; - mesh_dev->set_mac_address = libertas_set_mac_address; - mesh_dev->ethtool_ops = &libertas_ethtool_ops; + mesh_dev->open = lbs_dev_open; + mesh_dev->hard_start_xmit = lbs_hard_start_xmit; + mesh_dev->stop = lbs_mesh_stop; + mesh_dev->get_stats = lbs_get_stats; + mesh_dev->set_mac_address = lbs_set_mac_address; + mesh_dev->ethtool_ops = &lbs_ethtool_ops; memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, sizeof(priv->dev->dev_addr)); - SET_NETDEV_DEV(priv->mesh_dev, dev); + SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent); #ifdef WIRELESS_EXT mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def; @@ -1353,7 +1333,7 @@ int libertas_add_mesh(wlan_private *priv, struct device *dev) goto err_free; } - ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); + ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); if (ret) goto err_unregister; @@ -1371,33 +1351,28 @@ done: lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_add_mesh); +EXPORT_SYMBOL_GPL(lbs_add_mesh); -void libertas_remove_mesh(wlan_private *priv) +static void lbs_remove_mesh(struct lbs_private *priv) { struct net_device *mesh_dev; - lbs_deb_enter(LBS_DEB_MAIN); - - if (!priv) - goto out; mesh_dev = priv->mesh_dev; + if (!mesh_dev) + return; + lbs_deb_enter(LBS_DEB_MESH); netif_stop_queue(mesh_dev); netif_carrier_off(priv->mesh_dev); - - sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group); + sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); unregister_netdev(mesh_dev); - - priv->mesh_dev = NULL ; + priv->mesh_dev = NULL; free_netdev(mesh_dev); - -out: - lbs_deb_leave(LBS_DEB_MAIN); + lbs_deb_leave(LBS_DEB_MESH); } -EXPORT_SYMBOL_GPL(libertas_remove_mesh); +EXPORT_SYMBOL_GPL(lbs_remove_mesh); /** * @brief This function finds the CFP in @@ -1408,7 +1383,7 @@ EXPORT_SYMBOL_GPL(libertas_remove_mesh); * @param cfp_no A pointer to CFP number * @return A pointer to CFP */ -struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no) +struct chan_freq_power *lbs_get_region_cfp_table(u8 region, u8 band, int *cfp_no) { int i, end; @@ -1430,9 +1405,8 @@ struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *c return NULL; } -int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band) +int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band) { - wlan_adapter *adapter = priv->adapter; int ret = 0; int i = 0; @@ -1441,24 +1415,22 @@ int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band) lbs_deb_enter(LBS_DEB_MAIN); - memset(adapter->region_channel, 0, sizeof(adapter->region_channel)); + memset(priv->region_channel, 0, sizeof(priv->region_channel)); - { - cfp = libertas_get_region_cfp_table(region, band, &cfp_no); - if (cfp != NULL) { - adapter->region_channel[i].nrcfp = cfp_no; - adapter->region_channel[i].CFP = cfp; - } else { - lbs_deb_main("wrong region code %#x in band B/G\n", - region); - ret = -1; - goto out; - } - adapter->region_channel[i].valid = 1; - adapter->region_channel[i].region = region; - adapter->region_channel[i].band = band; - i++; + cfp = lbs_get_region_cfp_table(region, band, &cfp_no); + if (cfp != NULL) { + priv->region_channel[i].nrcfp = cfp_no; + priv->region_channel[i].CFP = cfp; + } else { + lbs_deb_main("wrong region code %#x in band B/G\n", + region); + ret = -1; + goto out; } + priv->region_channel[i].valid = 1; + priv->region_channel[i].region = region; + priv->region_channel[i].band = band; + i++; out: lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; @@ -1472,58 +1444,46 @@ out: * @param dev A pointer to net_device structure * @return n/a */ -void libertas_interrupt(struct net_device *dev) +void lbs_interrupt(struct lbs_private *priv) { - wlan_private *priv = dev->priv; - lbs_deb_enter(LBS_DEB_THREAD); - lbs_deb_thread("libertas_interrupt: intcounter=%d\n", - priv->adapter->intcounter); - - priv->adapter->intcounter++; - - if (priv->adapter->psstate == PS_STATE_SLEEP) { - priv->adapter->psstate = PS_STATE_AWAKE; - netif_wake_queue(dev); - if (priv->mesh_dev) - netif_wake_queue(priv->mesh_dev); - } - + lbs_deb_thread("lbs_interrupt: intcounter=%d\n", priv->intcounter); + priv->intcounter++; + if (priv->psstate == PS_STATE_SLEEP) + priv->psstate = PS_STATE_AWAKE; wake_up_interruptible(&priv->waitq); lbs_deb_leave(LBS_DEB_THREAD); } -EXPORT_SYMBOL_GPL(libertas_interrupt); +EXPORT_SYMBOL_GPL(lbs_interrupt); -int libertas_reset_device(wlan_private *priv) +int lbs_reset_device(struct lbs_private *priv) { int ret; lbs_deb_enter(LBS_DEB_MAIN); - ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_RESET, CMD_ACT_HALT, 0, 0, NULL); msleep_interruptible(10); lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_reset_device); +EXPORT_SYMBOL_GPL(lbs_reset_device); -static int libertas_init_module(void) +static int __init lbs_init_module(void) { lbs_deb_enter(LBS_DEB_MAIN); - libertas_debugfs_init(); + lbs_debugfs_init(); lbs_deb_leave(LBS_DEB_MAIN); return 0; } -static void libertas_exit_module(void) +static void __exit lbs_exit_module(void) { lbs_deb_enter(LBS_DEB_MAIN); - - libertas_debugfs_remove(); - + lbs_debugfs_remove(); lbs_deb_leave(LBS_DEB_MAIN); } @@ -1531,79 +1491,89 @@ static void libertas_exit_module(void) * rtap interface support fuctions */ -static int libertas_rtap_open(struct net_device *dev) +static int lbs_rtap_open(struct net_device *dev) { - netif_carrier_off(dev); - netif_stop_queue(dev); - return 0; + /* Yes, _stop_ the queue. Because we don't support injection */ + lbs_deb_enter(LBS_DEB_MAIN); + netif_carrier_off(dev); + netif_stop_queue(dev); + lbs_deb_leave(LBS_DEB_LEAVE); + return 0; } -static int libertas_rtap_stop(struct net_device *dev) +static int lbs_rtap_stop(struct net_device *dev) { - return 0; + lbs_deb_enter(LBS_DEB_MAIN); + lbs_deb_leave(LBS_DEB_MAIN); + return 0; } -static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - netif_stop_queue(dev); - return -EOPNOTSUPP; + netif_stop_queue(dev); + return NETDEV_TX_BUSY; } -static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev) +static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev) { - wlan_private *priv = dev->priv; - return &priv->ieee->stats; + struct lbs_private *priv = dev->priv; + lbs_deb_enter(LBS_DEB_NET); + return &priv->stats; } -void libertas_remove_rtap(wlan_private *priv) +static void lbs_remove_rtap(struct lbs_private *priv) { + lbs_deb_enter(LBS_DEB_MAIN); if (priv->rtap_net_dev == NULL) return; unregister_netdev(priv->rtap_net_dev); - free_ieee80211(priv->rtap_net_dev); + free_netdev(priv->rtap_net_dev); priv->rtap_net_dev = NULL; + lbs_deb_leave(LBS_DEB_MAIN); } -int libertas_add_rtap(wlan_private *priv) +static int lbs_add_rtap(struct lbs_private *priv) { - int rc = 0; - - if (priv->rtap_net_dev) - return -EPERM; - - priv->rtap_net_dev = alloc_ieee80211(0); - if (priv->rtap_net_dev == NULL) - return -ENOMEM; - - - priv->ieee = netdev_priv(priv->rtap_net_dev); + int ret = 0; + struct net_device *rtap_dev; - strcpy(priv->rtap_net_dev->name, "rtap%d"); + lbs_deb_enter(LBS_DEB_MAIN); + if (priv->rtap_net_dev) { + ret = -EPERM; + goto out; + } - priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP; - priv->rtap_net_dev->open = libertas_rtap_open; - priv->rtap_net_dev->stop = libertas_rtap_stop; - priv->rtap_net_dev->get_stats = libertas_rtap_get_stats; - priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit; - priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list; - priv->rtap_net_dev->priv = priv; + rtap_dev = alloc_netdev(0, "rtap%d", ether_setup); + if (rtap_dev == NULL) { + ret = -ENOMEM; + goto out; + } - priv->ieee->iw_mode = IW_MODE_MONITOR; + memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN); + rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP; + rtap_dev->open = lbs_rtap_open; + rtap_dev->stop = lbs_rtap_stop; + rtap_dev->get_stats = lbs_rtap_get_stats; + rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; + rtap_dev->set_multicast_list = lbs_set_multicast_list; + rtap_dev->priv = priv; - rc = register_netdev(priv->rtap_net_dev); - if (rc) { - free_ieee80211(priv->rtap_net_dev); - priv->rtap_net_dev = NULL; - return rc; + ret = register_netdev(rtap_dev); + if (ret) { + free_netdev(rtap_dev); + goto out; } + priv->rtap_net_dev = rtap_dev; - return 0; +out: + lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret); + return ret; } -module_init(libertas_init_module); -module_exit(libertas_exit_module); +module_init(lbs_init_module); +module_exit(lbs_exit_module); MODULE_DESCRIPTION("Libertas WLAN Driver Library"); MODULE_AUTHOR("Marvell International Ltd."); diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index 0420e5b9ff9b..149557a478ac 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -35,134 +35,114 @@ struct rx80211packethdr { void *eth80211_hdr; } __attribute__ ((packed)); -static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb); +static int process_rxed_802_11_packet(struct lbs_private *priv, + struct sk_buff *skb); /** * @brief This function computes the avgSNR . * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return avgSNR */ -static u8 wlan_getavgsnr(wlan_private * priv) +static u8 lbs_getavgsnr(struct lbs_private *priv) { u8 i; u16 temp = 0; - wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF == 0) + if (priv->numSNRNF == 0) return 0; - for (i = 0; i < adapter->numSNRNF; i++) - temp += adapter->rawSNR[i]; - return (u8) (temp / adapter->numSNRNF); + for (i = 0; i < priv->numSNRNF; i++) + temp += priv->rawSNR[i]; + return (u8) (temp / priv->numSNRNF); } /** * @brief This function computes the AvgNF * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @return AvgNF */ -static u8 wlan_getavgnf(wlan_private * priv) +static u8 lbs_getavgnf(struct lbs_private *priv) { u8 i; u16 temp = 0; - wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF == 0) + if (priv->numSNRNF == 0) return 0; - for (i = 0; i < adapter->numSNRNF; i++) - temp += adapter->rawNF[i]; - return (u8) (temp / adapter->numSNRNF); + for (i = 0; i < priv->numSNRNF; i++) + temp += priv->rawNF[i]; + return (u8) (temp / priv->numSNRNF); } /** * @brief This function save the raw SNR/NF to our internel buffer * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param prxpd A pointer to rxpd structure of received packet * @return n/a */ -static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd) +static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd) { - wlan_adapter *adapter = priv->adapter; - if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR) - adapter->numSNRNF++; - adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr; - adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf; - adapter->nextSNRNF++; - if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR) - adapter->nextSNRNF = 0; + if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR) + priv->numSNRNF++; + priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr; + priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf; + priv->nextSNRNF++; + if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR) + priv->nextSNRNF = 0; return; } /** * @brief This function computes the RSSI in received packet. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param prxpd A pointer to rxpd structure of received packet * @return n/a */ -static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd) +static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd) { - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_RX); lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf); lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n", - adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); - adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; - adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; - wlan_save_rawSNRNF(priv, p_rx_pd); + priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; + priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; + lbs_save_rawSNRNF(priv, p_rx_pd); - adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE; - adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE; + priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE; + priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE; lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n", - adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); - adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] = - CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], - adapter->NF[TYPE_RXPD][TYPE_NOAVG]); + priv->RSSI[TYPE_RXPD][TYPE_NOAVG] = + CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG], + priv->NF[TYPE_RXPD][TYPE_NOAVG]); - adapter->RSSI[TYPE_RXPD][TYPE_AVG] = - CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, - adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); + priv->RSSI[TYPE_RXPD][TYPE_AVG] = + CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, + priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); lbs_deb_leave(LBS_DEB_RX); } -void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) -{ - lbs_deb_rx("skb->data %p\n", skb->data); - - if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { - skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); - } else { - if (priv->mesh_dev && IS_MESH_FRAME(skb)) - skb->protocol = eth_type_trans(skb, priv->mesh_dev); - else - skb->protocol = eth_type_trans(skb, priv->dev); - } - skb->ip_summed = CHECKSUM_UNNECESSARY; - netif_rx(skb); -} - /** * @brief This function processes received packet and forwards it * to kernel/upper layer * - * @param priv A pointer to wlan_private + * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ -int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) +int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb) { - wlan_adapter *adapter = priv->adapter; int ret = 0; - + struct net_device *dev = priv->dev; struct rxpackethdr *p_rx_pkt; struct rxpd *p_rx_pd; @@ -173,15 +153,15 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) lbs_deb_enter(LBS_DEB_RX); - if (priv->adapter->monitormode != WLAN_MONITOR_OFF) + skb->ip_summed = CHECKSUM_NONE; + + if (priv->monitormode != LBS_MONITOR_OFF) return process_rxed_802_11_packet(priv, skb); p_rx_pkt = (struct rxpackethdr *) skb->data; p_rx_pd = &p_rx_pkt->rx_pd; - if (p_rx_pd->rx_control & RxPD_MESH_FRAME) - SET_MESH_FRAME(skb); - else - UNSET_MESH_FRAME(skb); + if (priv->mesh_dev && (p_rx_pd->rx_control & RxPD_MESH_FRAME)) + dev = priv->mesh_dev; lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min_t(unsigned int, skb->len, 100)); @@ -257,23 +237,27 @@ int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (adapter->auto_rate) - adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate); + if (priv->auto_rate) + priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate); - wlan_compute_rssi(priv, p_rx_pd); + lbs_compute_rssi(priv, p_rx_pd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; - libertas_upload_rx_packet(priv, skb); + skb->protocol = eth_type_trans(skb, dev); + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); ret = 0; done: lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret); return ret; } -EXPORT_SYMBOL_GPL(libertas_process_rxed_packet); +EXPORT_SYMBOL_GPL(lbs_process_rxed_packet); /** * @brief This function converts Tx/Rx rates from the Marvell WLAN format @@ -319,13 +303,13 @@ static u8 convert_mv_rate_to_radiotap(u8 rate) * @brief This function processes a received 802.11 packet and forwards it * to kernel/upper layer * - * @param priv A pointer to wlan_private + * @param priv A pointer to struct lbs_private * @param skb A pointer to skb which includes the received packet * @return 0 or -1 */ -static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) +static int process_rxed_802_11_packet(struct lbs_private *priv, + struct sk_buff *skb) { - wlan_adapter *adapter = priv->adapter; int ret = 0; struct rx80211packethdr *p_rx_pkt; @@ -341,9 +325,10 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) // lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { - lbs_deb_rx("rx err: frame received wit bad length\n"); + lbs_deb_rx("rx err: frame received with bad length\n"); priv->stats.rx_length_errors++; - ret = 0; + ret = -EINVAL; + kfree(skb); goto done; } @@ -359,65 +344,56 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); /* create the exported radio header */ - if(priv->adapter->monitormode == WLAN_MONITOR_OFF) { - /* no radio header */ - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - } - else { - /* radiotap header */ - radiotap_hdr.hdr.it_version = 0; - /* XXX must check this value for pad */ - radiotap_hdr.hdr.it_pad = 0; - radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); - radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); - /* unknown values */ - radiotap_hdr.flags = 0; - radiotap_hdr.chan_freq = 0; - radiotap_hdr.chan_flags = 0; - radiotap_hdr.antenna = 0; - /* known values */ - radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); - /* XXX must check no carryout */ - radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; - radiotap_hdr.rx_flags = 0; - if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) - radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; - //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); - - /* chop the rxpd */ - skb_pull(skb, sizeof(struct rxpd)); - - /* add space for the new radio header */ - if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && - pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, - GFP_ATOMIC)) { - lbs_pr_alert("%s: couldn't pskb_expand_head\n", - __func__); - } - - pradiotap_hdr = - (struct rx_radiotap_hdr *)skb_push(skb, - sizeof(struct - rx_radiotap_hdr)); - memcpy(pradiotap_hdr, &radiotap_hdr, - sizeof(struct rx_radiotap_hdr)); + /* radiotap header */ + radiotap_hdr.hdr.it_version = 0; + /* XXX must check this value for pad */ + radiotap_hdr.hdr.it_pad = 0; + radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr)); + radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT); + /* unknown values */ + radiotap_hdr.flags = 0; + radiotap_hdr.chan_freq = 0; + radiotap_hdr.chan_flags = 0; + radiotap_hdr.antenna = 0; + /* known values */ + radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); + /* XXX must check no carryout */ + radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; + radiotap_hdr.rx_flags = 0; + if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) + radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; + //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); + + /* chop the rxpd */ + skb_pull(skb, sizeof(struct rxpd)); + + /* add space for the new radio header */ + if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && + pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) { + lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__); + ret = -ENOMEM; + kfree_skb(skb); + goto done; } + pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr)); + memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr)); + /* Take the data rate from the rxpd structure * only if the rate is auto */ - if (adapter->auto_rate) - adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate); + if (priv->auto_rate) + priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate); - wlan_compute_rssi(priv, prxpd); + lbs_compute_rssi(priv, prxpd); lbs_deb_rx("rx data: size of actual packet %d\n", skb->len); priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; - libertas_upload_rx_packet(priv, skb); + skb->protocol = eth_type_trans(skb, priv->rtap_net_dev); + netif_rx(skb); ret = 0; diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index ad1e67d984ce..9a61188b62e9 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -39,9 +39,8 @@ //! Memory needed to store a max number/size SSID TLV for a firmware scan #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) -//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max -#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \ - + sizeof(struct mrvlietypes_numprobes) \ +//! Maximum memory needed for a lbs_scan_cmd_config with all TLVs at max +#define MAX_SCAN_CFG_ALLOC (sizeof(struct lbs_scan_cmd_config) \ + CHAN_TLV_MAX_SIZE \ + SSID_TLV_MAX_SIZE) @@ -80,7 +79,23 @@ static inline void clear_bss_descriptor (struct bss_descriptor * bss) memset(bss, 0, offsetof(struct bss_descriptor, list)); } -static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, +/** + * @brief Compare two SSIDs + * + * @param ssid1 A pointer to ssid to compare + * @param ssid2 A pointer to ssid to compare + * + * @return 0: ssid is same, otherwise is different + */ +int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) +{ + if (ssid1_len != ssid2_len) + return -1; + + return memcmp(ssid1, ssid2, ssid1_len); +} + +static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -94,7 +109,7 @@ static inline int match_bss_no_security(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, +static inline int match_bss_static_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( secinfo->wep_enabled @@ -106,7 +121,7 @@ static inline int match_bss_static_wep(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, +static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -121,7 +136,7 @@ static inline int match_bss_wpa(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, +static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -136,7 +151,7 @@ static inline int match_bss_wpa2(struct wlan_802_11_security * secinfo, return 0; } -static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, +static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, struct bss_descriptor * match_bss) { if ( !secinfo->wep_enabled @@ -150,6 +165,18 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, return 0; } +static inline int is_same_network(struct bss_descriptor *src, + struct bss_descriptor *dst) +{ + /* A network is only a duplicate if the channel, BSSID, and ESSID + * all match. We treat all <hidden> with the same BSSID and channel + * as one network */ + return ((src->ssid_len == dst->ssid_len) && + (src->channel == dst->channel) && + !compare_ether_addr(src->bssid, dst->bssid) && + !memcmp(src->ssid, dst->ssid, src->ssid_len)); +} + /** * @brief Check if a scanned network compatible with the driver settings * @@ -163,13 +190,13 @@ static inline int match_bss_dynamic_wep(struct wlan_802_11_security * secinfo, * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP * * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * @param index Index in scantable to check against current driver settings * @param mode Network mode: Infrastructure or IBSS * * @return Index in scantable, or error code if negative */ -static int is_network_compatible(wlan_adapter * adapter, +static int is_network_compatible(struct lbs_private *priv, struct bss_descriptor * bss, u8 mode) { int matched = 0; @@ -179,34 +206,34 @@ static int is_network_compatible(wlan_adapter * adapter, if (bss->mode != mode) goto done; - if ((matched = match_bss_no_security(&adapter->secinfo, bss))) { + if ((matched = match_bss_no_security(&priv->secinfo, bss))) { goto done; - } else if ((matched = match_bss_static_wep(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_static_wep(&priv->secinfo, bss))) { goto done; - } else if ((matched = match_bss_wpa(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_wpa(&priv->secinfo, bss))) { lbs_deb_scan( - "is_network_compatible() WPA: wpa_ie=%#x " - "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0], - adapter->secinfo.wep_enabled ? "e" : "d", - adapter->secinfo.WPAenabled ? "e" : "d", - adapter->secinfo.WPA2enabled ? "e" : "d", + "is_network_compatible() WPA: wpa_ie 0x%x " + "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " + "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; - } else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_wpa2(&priv->secinfo, bss))) { lbs_deb_scan( - "is_network_compatible() WPA2: wpa_ie=%#x " - "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "privacy=%#x\n", bss->wpa_ie[0], bss->rsn_ie[0], - adapter->secinfo.wep_enabled ? "e" : "d", - adapter->secinfo.WPAenabled ? "e" : "d", - adapter->secinfo.WPA2enabled ? "e" : "d", + "is_network_compatible() WPA2: wpa_ie 0x%x " + "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s " + "privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; - } else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) { + } else if ((matched = match_bss_dynamic_wep(&priv->secinfo, bss))) { lbs_deb_scan( "is_network_compatible() dynamic WEP: " - "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n", + "wpa_ie 0x%x wpa2_ie 0x%x privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], (bss->capability & WLAN_CAPABILITY_PRIVACY)); goto done; @@ -214,12 +241,12 @@ static int is_network_compatible(wlan_adapter * adapter, /* bss security settings don't match those configured on card */ lbs_deb_scan( - "is_network_compatible() FAILED: wpa_ie=%#x " - "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s privacy=%#x\n", + "is_network_compatible() FAILED: wpa_ie 0x%x " + "wpa2_ie 0x%x WEP %s WPA %s WPA2 %s privacy 0x%x\n", bss->wpa_ie[0], bss->rsn_ie[0], - adapter->secinfo.wep_enabled ? "e" : "d", - adapter->secinfo.WPAenabled ? "e" : "d", - adapter->secinfo.WPA2enabled ? "e" : "d", + priv->secinfo.wep_enabled ? "e" : "d", + priv->secinfo.WPAenabled ? "e" : "d", + priv->secinfo.WPA2enabled ? "e" : "d", (bss->capability & WLAN_CAPABILITY_PRIVACY)); done: @@ -227,22 +254,6 @@ done: return matched; } -/** - * @brief Compare two SSIDs - * - * @param ssid1 A pointer to ssid to compare - * @param ssid2 A pointer to ssid to compare - * - * @return 0--ssid is same, otherwise is different - */ -int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) -{ - if (ssid1_len != ssid2_len) - return -1; - - return memcmp(ssid1, ssid2, ssid1_len); -} - @@ -252,17 +263,27 @@ int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) /* */ /*********************************************************************/ +void lbs_scan_worker(struct work_struct *work) +{ + struct lbs_private *priv = + container_of(work, struct lbs_private, scan_work.work); + + lbs_deb_enter(LBS_DEB_SCAN); + lbs_scan_networks(priv, NULL, 0); + lbs_deb_leave(LBS_DEB_SCAN); +} + /** * @brief Create a channel list for the driver to scan based on region info * - * Only used from wlan_scan_setup_scan_config() + * Only used from lbs_scan_setup_scan_config() * * Use the driver region/band information to construct a comprehensive list * of channels to scan. This routine is used for any scan that is not * provided a specific channel list to scan. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param scanchanlist Output parameter: resulting channel list to scan * @param filteredscan Flag indicating whether or not a BSSID or SSID filter * is being sent in the command to firmware. Used to @@ -272,12 +293,11 @@ int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len) * * @return void */ -static void wlan_scan_create_channel_list(wlan_private * priv, +static int lbs_scan_create_channel_list(struct lbs_private *priv, struct chanscanparamset * scanchanlist, u8 filteredscan) { - wlan_adapter *adapter = priv->adapter; struct region_channel *scanregion; struct chan_freq_power *cfp; int rgnidx; @@ -285,8 +305,6 @@ static void wlan_scan_create_channel_list(wlan_private * priv, int nextchan; u8 scantype; - lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan); - chanidx = 0; /* Set the default scan type to the user specified type, will later @@ -295,21 +313,22 @@ static void wlan_scan_create_channel_list(wlan_private * priv, */ scantype = CMD_SCAN_TYPE_ACTIVE; - for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { - if (priv->adapter->enable11d && - adapter->connect_status != LIBERTAS_CONNECTED) { + for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) { + if (priv->enable11d && + (priv->connect_status != LBS_CONNECTED) && + (priv->mesh_connect_status != LBS_CONNECTED)) { /* Scan all the supported chan for the first scan */ - if (!adapter->universal_channel[rgnidx].valid) + if (!priv->universal_channel[rgnidx].valid) continue; - scanregion = &adapter->universal_channel[rgnidx]; + scanregion = &priv->universal_channel[rgnidx]; /* clear the parsed_region_chan for the first scan */ - memset(&adapter->parsed_region_chan, 0x00, - sizeof(adapter->parsed_region_chan)); + memset(&priv->parsed_region_chan, 0x00, + sizeof(priv->parsed_region_chan)); } else { - if (!adapter->region_channel[rgnidx].valid) + if (!priv->region_channel[rgnidx].valid) continue; - scanregion = &adapter->region_channel[rgnidx]; + scanregion = &priv->region_channel[rgnidx]; } for (nextchan = 0; @@ -317,10 +336,10 @@ static void wlan_scan_create_channel_list(wlan_private * priv, cfp = scanregion->CFP + nextchan; - if (priv->adapter->enable11d) { + if (priv->enable11d) { scantype = - libertas_get_scan_type_11d(cfp->channel, - &adapter-> + lbs_get_scan_type_11d(cfp->channel, + &priv-> parsed_region_chan); } @@ -353,453 +372,151 @@ static void wlan_scan_create_channel_list(wlan_private * priv, } } } + return chanidx; } -/* Delayed partial scan worker */ -void libertas_scan_worker(struct work_struct *work) +/* + * Add SSID TLV of the form: + * + * TLV-ID SSID 00 00 + * length 06 00 + * ssid 4d 4e 54 45 53 54 + */ +static int lbs_scan_add_ssid_tlv(u8 *tlv, + const struct lbs_ioctl_user_scan_cfg *user_cfg) { - wlan_private *priv = container_of(work, wlan_private, scan_work.work); - - wlan_scan_networks(priv, NULL, 0); + struct mrvlietypes_ssidparamset *ssid_tlv = + (struct mrvlietypes_ssidparamset *)tlv; + ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID); + ssid_tlv->header.len = cpu_to_le16(user_cfg->ssid_len); + memcpy(ssid_tlv->ssid, user_cfg->ssid, user_cfg->ssid_len); + return sizeof(ssid_tlv->header) + user_cfg->ssid_len; } -/** - * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds - * - * Application layer or other functions can invoke wlan_scan_networks - * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct. - * This structure is used as the basis of one or many wlan_scan_cmd_config - * commands that are sent to the command processing module and sent to - * firmware. - * - * Create a wlan_scan_cmd_config based on the following user supplied - * parameters (if present): - * - SSID filter - * - BSSID filter - * - Number of Probes to be sent - * - channel list - * - * If the SSID or BSSID filter is not present, disable/clear the filter. - * If the number of probes is not set, use the adapter default setting - * Qualify the channel +/* + * Add CHANLIST TLV of the form * - * @param priv A pointer to wlan_private structure - * @param puserscanin NULL or pointer to scan configuration parameters - * @param ppchantlvout Output parameter: Pointer to the start of the - * channel TLV portion of the output scan config - * @param pscanchanlist Output parameter: Pointer to the resulting channel - * list to scan - * @param pmaxchanperscan Output parameter: Number of channels to scan for - * each issuance of the firmware scan command - * @param pfilteredscan Output parameter: Flag indicating whether or not - * a BSSID or SSID filter is being sent in the - * command to firmware. Used to increase the number - * of channels sent in a scan command and to - * disable the firmware channel scan filter. - * @param pscancurrentonly Output parameter: Flag indicating whether or not - * we are only scanning our current active channel + * TLV-ID CHANLIST 01 01 + * length 5b 00 + * channel 1 00 01 00 00 00 64 00 + * radio type 00 + * channel 01 + * scan type 00 + * min scan time 00 00 + * max scan time 64 00 + * channel 2 00 02 00 00 00 64 00 + * channel 3 00 03 00 00 00 64 00 + * channel 4 00 04 00 00 00 64 00 + * channel 5 00 05 00 00 00 64 00 + * channel 6 00 06 00 00 00 64 00 + * channel 7 00 07 00 00 00 64 00 + * channel 8 00 08 00 00 00 64 00 + * channel 9 00 09 00 00 00 64 00 + * channel 10 00 0a 00 00 00 64 00 + * channel 11 00 0b 00 00 00 64 00 + * channel 12 00 0c 00 00 00 64 00 + * channel 13 00 0d 00 00 00 64 00 * - * @return resulting scan configuration */ -static struct wlan_scan_cmd_config * -wlan_scan_setup_scan_config(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, - struct mrvlietypes_chanlistparamset ** ppchantlvout, - struct chanscanparamset * pscanchanlist, - int *pmaxchanperscan, - u8 * pfilteredscan, - u8 * pscancurrentonly) +static int lbs_scan_add_chanlist_tlv(u8 *tlv, + struct chanscanparamset *chan_list, + int chan_count) { - struct mrvlietypes_numprobes *pnumprobestlv; - struct mrvlietypes_ssidparamset *pssidtlv; - struct wlan_scan_cmd_config * pscancfgout = NULL; - u8 *ptlvpos; - u16 numprobes; - int chanidx; - int scantype; - int scandur; - int channel; - int radiotype; - - lbs_deb_enter(LBS_DEB_SCAN); - - pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); - if (pscancfgout == NULL) - goto out; - - /* The tlvbufferlen is calculated for each scan command. The TLVs added - * in this routine will be preserved since the routine that sends - * the command will append channelTLVs at *ppchantlvout. The difference - * between the *ppchantlvout and the tlvbuffer start will be used - * to calculate the size of anything we add in this routine. - */ - pscancfgout->tlvbufferlen = 0; - - /* Running tlv pointer. Assigned to ppchantlvout at end of function - * so later routines know where channels can be added to the command buf - */ - ptlvpos = pscancfgout->tlvbuffer; - - /* - * Set the initial scan paramters for progressive scanning. If a specific - * BSSID or SSID is used, the number of channels in the scan command - * will be increased to the absolute maximum - */ - *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD; - - /* Initialize the scan as un-filtered by firmware, set to TRUE below if - * a SSID or BSSID filter is sent in the command - */ - *pfilteredscan = 0; - - /* Initialize the scan as not being only on the current channel. If - * the channel list is customized, only contains one channel, and - * is the active channel, this is set true and data flow is not halted. - */ - *pscancurrentonly = 0; - - if (puserscanin) { - /* Set the bss type scan filter, use adapter setting if unset */ - pscancfgout->bsstype = - puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY; - - /* Set the number of probes to send, use adapter setting if unset */ - numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0; - - /* - * Set the BSSID filter to the incoming configuration, - * if non-zero. If not set, it will remain disabled (all zeros). - */ - memcpy(pscancfgout->bssid, puserscanin->bssid, - sizeof(pscancfgout->bssid)); - - if (puserscanin->ssid_len) { - pssidtlv = - (struct mrvlietypes_ssidparamset *) pscancfgout-> - tlvbuffer; - pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID); - pssidtlv->header.len = cpu_to_le16(puserscanin->ssid_len); - memcpy(pssidtlv->ssid, puserscanin->ssid, - puserscanin->ssid_len); - ptlvpos += sizeof(pssidtlv->header) + puserscanin->ssid_len; - } - - /* - * The default number of channels sent in the command is low to - * ensure the response buffer from the firmware does not truncate - * scan results. That is not an issue with an SSID or BSSID - * filter applied to the scan results in the firmware. - */ - if ( puserscanin->ssid_len - || (compare_ether_addr(pscancfgout->bssid, &zeromac[0]) != 0)) { - *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN; - *pfilteredscan = 1; - } - } else { - pscancfgout->bsstype = CMD_BSS_TYPE_ANY; - numprobes = 0; - } - - /* If the input config or adapter has the number of Probes set, add tlv */ - if (numprobes) { - pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos; - pnumprobestlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); - pnumprobestlv->header.len = cpu_to_le16(2); - pnumprobestlv->numprobes = cpu_to_le16(numprobes); - - ptlvpos += sizeof(*pnumprobestlv); - } - - /* - * Set the output for the channel TLV to the address in the tlv buffer - * past any TLVs that were added in this fuction (SSID, numprobes). - * channel TLVs will be added past this for each scan command, preserving - * the TLVs that were previously added. - */ - *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; - - if (!puserscanin || !puserscanin->chanlist[0].channumber) { - /* Create a default channel scan list */ - lbs_deb_scan("creating full region channel list\n"); - wlan_scan_create_channel_list(priv, pscanchanlist, - *pfilteredscan); - goto out; - } - - for (chanidx = 0; - chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX - && puserscanin->chanlist[chanidx].channumber; chanidx++) { - - channel = puserscanin->chanlist[chanidx].channumber; - (pscanchanlist + chanidx)->channumber = channel; - - radiotype = puserscanin->chanlist[chanidx].radiotype; - (pscanchanlist + chanidx)->radiotype = radiotype; - - scantype = puserscanin->chanlist[chanidx].scantype; - - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 1; - } else { - (pscanchanlist + - chanidx)->chanscanmode.passivescan = 0; - } - - if (puserscanin->chanlist[chanidx].scantime) { - scandur = puserscanin->chanlist[chanidx].scantime; - } else { - if (scantype == CMD_SCAN_TYPE_PASSIVE) { - scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; - } else { - scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; - } - } - - (pscanchanlist + chanidx)->minscantime = - cpu_to_le16(scandur); - (pscanchanlist + chanidx)->maxscantime = - cpu_to_le16(scandur); - } - - /* Check if we are only scanning the current channel */ - if ((chanidx == 1) && - (puserscanin->chanlist[0].channumber == - priv->adapter->curbssparams.channel)) { - *pscancurrentonly = 1; - lbs_deb_scan("scanning current channel only"); - } - -out: - return pscancfgout; + size_t size = sizeof(struct chanscanparamset) * chan_count; + struct mrvlietypes_chanlistparamset *chan_tlv = + (struct mrvlietypes_chanlistparamset *) tlv; + + chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); + memcpy(chan_tlv->chanscanparam, chan_list, size); + chan_tlv->header.len = cpu_to_le16(size); + return sizeof(chan_tlv->header) + size; } -/** - * @brief Construct and send multiple scan config commands to the firmware - * - * Only used from wlan_scan_networks() - * - * Previous routines have created a wlan_scan_cmd_config with any requested - * TLVs. This function splits the channel TLV into maxchanperscan lists - * and sends the portion of the channel TLV along with the other TLVs - * to the wlan_cmd routines for execution in the firmware. + +/* + * Add RATES TLV of the form * - * @param priv A pointer to wlan_private structure - * @param maxchanperscan Maximum number channels to be included in each - * scan command sent to firmware - * @param filteredscan Flag indicating whether or not a BSSID or SSID - * filter is being used for the firmware command - * scan command sent to firmware - * @param pscancfgout Scan configuration used for this scan. - * @param pchantlvout Pointer in the pscancfgout where the channel TLV - * should start. This is past any other TLVs that - * must be sent down in each firmware command. - * @param pscanchanlist List of channels to scan in maxchanperscan segments + * TLV-ID RATES 01 00 + * length 0e 00 + * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c * - * @return 0 or error return otherwise + * The rates are in lbs_bg_rates[], but for the 802.11b + * rates the high bit isn't set. */ -static int wlan_scan_channel_list(wlan_private * priv, - int maxchanperscan, - u8 filteredscan, - struct wlan_scan_cmd_config * pscancfgout, - struct mrvlietypes_chanlistparamset * pchantlvout, - struct chanscanparamset * pscanchanlist, - const struct wlan_ioctl_user_scan_cfg * puserscanin, - int full_scan) +static int lbs_scan_add_rates_tlv(u8 *tlv) { - struct chanscanparamset *ptmpchan; - struct chanscanparamset *pstartchan; - u8 scanband; - int doneearly; - int tlvidx; - int ret = 0; - int scanned = 0; - union iwreq_data wrqu; - - lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, " - "full_scan %d", maxchanperscan, filteredscan, full_scan); - - if (!pscancfgout || !pchantlvout || !pscanchanlist) { - lbs_deb_scan("pscancfgout, pchantlvout or " - "pscanchanlist is NULL\n"); - ret = -1; - goto out; - } - - pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); - - /* Set the temp channel struct pointer to the start of the desired list */ - ptmpchan = pscanchanlist; - - if (priv->adapter->last_scanned_channel && !puserscanin) - ptmpchan += priv->adapter->last_scanned_channel; - - /* Loop through the desired channel list, sending a new firmware scan - * commands for each maxchanperscan channels (or for 1,6,11 individually - * if configured accordingly) - */ - while (ptmpchan->channumber) { - - tlvidx = 0; - pchantlvout->header.len = 0; - scanband = ptmpchan->radiotype; - pstartchan = ptmpchan; - doneearly = 0; - - /* Construct the channel TLV for the scan command. Continue to - * insert channel TLVs until: - * - the tlvidx hits the maximum configured per scan command - * - the next channel to insert is 0 (end of desired channel list) - * - doneearly is set (controlling individual scanning of 1,6,11) - */ - while (tlvidx < maxchanperscan && ptmpchan->channumber - && !doneearly && scanned < 2) { - - lbs_deb_scan("channel %d, radio %d, passive %d, " - "dischanflt %d, maxscantime %d\n", - ptmpchan->channumber, - ptmpchan->radiotype, - ptmpchan->chanscanmode.passivescan, - ptmpchan->chanscanmode.disablechanfilt, - ptmpchan->maxscantime); - - /* Copy the current channel TLV to the command being prepared */ - memcpy(pchantlvout->chanscanparam + tlvidx, - ptmpchan, sizeof(pchantlvout->chanscanparam)); - - /* Increment the TLV header length by the size appended */ - /* Ew, it would be _so_ nice if we could just declare the - variable little-endian and let GCC handle it for us */ - pchantlvout->header.len = - cpu_to_le16(le16_to_cpu(pchantlvout->header.len) + - sizeof(pchantlvout->chanscanparam)); - - /* - * The tlv buffer length is set to the number of bytes of the - * between the channel tlv pointer and the start of the - * tlv buffer. This compensates for any TLVs that were appended - * before the channel list. - */ - pscancfgout->tlvbufferlen = ((u8 *) pchantlvout - - pscancfgout->tlvbuffer); - - /* Add the size of the channel tlv header and the data length */ - pscancfgout->tlvbufferlen += - (sizeof(pchantlvout->header) - + le16_to_cpu(pchantlvout->header.len)); - - /* Increment the index to the channel tlv we are constructing */ - tlvidx++; - - doneearly = 0; - - /* Stop the loop if the *current* channel is in the 1,6,11 set - * and we are not filtering on a BSSID or SSID. - */ - if (!filteredscan && (ptmpchan->channumber == 1 - || ptmpchan->channumber == 6 - || ptmpchan->channumber == 11)) { - doneearly = 1; - } - - /* Increment the tmp pointer to the next channel to be scanned */ - ptmpchan++; - scanned++; - - /* Stop the loop if the *next* channel is in the 1,6,11 set. - * This will cause it to be the only channel scanned on the next - * interation - */ - if (!filteredscan && (ptmpchan->channumber == 1 - || ptmpchan->channumber == 6 - || ptmpchan->channumber == 11)) { - doneearly = 1; - } - } - - /* Send the scan command to the firmware with the specified cfg */ - ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, - 0, 0, pscancfgout); - if (scanned >= 2 && !full_scan) { - ret = 0; - goto done; - } - scanned = 0; - } - -done: - priv->adapter->last_scanned_channel = ptmpchan->channumber; - - if (priv->adapter->last_scanned_channel) { - /* Schedule the next part of the partial scan */ - if (!full_scan && !priv->adapter->surpriseremoved) { - cancel_delayed_work(&priv->scan_work); - queue_delayed_work(priv->work_thread, &priv->scan_work, - msecs_to_jiffies(300)); - } - } else { - /* All done, tell userspace the scan table has been updated */ - memset(&wrqu, 0, sizeof(union iwreq_data)); - wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); + int i; + struct mrvlietypes_ratesparamset *rate_tlv = + (struct mrvlietypes_ratesparamset *) tlv; + + rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); + tlv += sizeof(rate_tlv->header); + for (i = 0; i < MAX_RATES; i++) { + *tlv = lbs_bg_rates[i]; + if (*tlv == 0) + break; + /* This code makes sure that the 802.11b rates (1 MBit/s, 2 + MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set. + Note that the values are MBit/s * 2, to mark them as + basic rates so that the firmware likes it better */ + if (*tlv == 0x02 || *tlv == 0x04 || + *tlv == 0x0b || *tlv == 0x16) + *tlv |= 0x80; + tlv++; } - -out: - lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); - return ret; + rate_tlv->header.len = cpu_to_le16(i); + return sizeof(rate_tlv->header) + i; } + /* - * Only used from wlan_scan_networks() -*/ -static void clear_selected_scan_list_entries(wlan_adapter *adapter, - const struct wlan_ioctl_user_scan_cfg *scan_cfg) + * Generate the CMD_802_11_SCAN command with the proper tlv + * for a bunch of channels. + */ +static int lbs_do_scan(struct lbs_private *priv, + u8 bsstype, + struct chanscanparamset *chan_list, + int chan_count, + const struct lbs_ioctl_user_scan_cfg *user_cfg) { - struct bss_descriptor *bss; - struct bss_descriptor *safe; - u32 clear_ssid_flag = 0, clear_bssid_flag = 0; + int ret = -ENOMEM; + struct lbs_scan_cmd_config *scan_cmd; + u8 *tlv; /* pointer into our current, growing TLV storage area */ - lbs_deb_enter(LBS_DEB_SCAN); + lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, " + "chan_count %d", + bsstype, chan_list[0].channumber, chan_count); - if (!scan_cfg) + /* create the fixed part for scan command */ + scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); + if (scan_cmd == NULL) goto out; - - if (scan_cfg->clear_ssid && scan_cfg->ssid_len) - clear_ssid_flag = 1; - - if (scan_cfg->clear_bssid - && (compare_ether_addr(scan_cfg->bssid, &zeromac[0]) != 0) - && (compare_ether_addr(scan_cfg->bssid, &bcastmac[0]) != 0)) { - clear_bssid_flag = 1; - } - - if (!clear_ssid_flag && !clear_bssid_flag) - goto out; - - mutex_lock(&adapter->lock); - list_for_each_entry_safe (bss, safe, &adapter->network_list, list) { - u32 clear = 0; - - /* Check for an SSID match */ - if ( clear_ssid_flag - && (bss->ssid_len == scan_cfg->ssid_len) - && !memcmp(bss->ssid, scan_cfg->ssid, bss->ssid_len)) - clear = 1; - - /* Check for a BSSID match */ - if ( clear_bssid_flag - && !compare_ether_addr(bss->bssid, scan_cfg->bssid)) - clear = 1; - - if (clear) { - list_move_tail (&bss->list, &adapter->network_free_list); - clear_bss_descriptor(bss); - } - } - mutex_unlock(&adapter->lock); + tlv = scan_cmd->tlvbuffer; + if (user_cfg) + memcpy(scan_cmd->bssid, user_cfg->bssid, ETH_ALEN); + scan_cmd->bsstype = bsstype; + + /* add TLVs */ + if (user_cfg && user_cfg->ssid_len) + tlv += lbs_scan_add_ssid_tlv(tlv, user_cfg); + if (chan_list && chan_count) + tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count); + tlv += lbs_scan_add_rates_tlv(tlv); + + /* This is the final data we are about to send */ + scan_cmd->tlvbufferlen = tlv - scan_cmd->tlvbuffer; + lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd, 1+6); + lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer, + scan_cmd->tlvbufferlen); + + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, 0, + CMD_OPTION_WAITFORRSP, 0, scan_cmd); out: - lbs_deb_leave(LBS_DEB_SCAN); + kfree(scan_cmd); + lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); + return ret; } @@ -812,32 +529,32 @@ out: * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param puserscanin Pointer to the input configuration for the requested * scan. - * @param full_scan ??? * * @return 0 or < 0 if error */ -int wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, +int lbs_scan_networks(struct lbs_private *priv, + const struct lbs_ioctl_user_scan_cfg *user_cfg, int full_scan) { - wlan_adapter * adapter = priv->adapter; - struct mrvlietypes_chanlistparamset *pchantlvout; - struct chanscanparamset * scan_chan_list = NULL; - struct wlan_scan_cmd_config * scan_cfg = NULL; - u8 filteredscan; - u8 scancurrentchanonly; - int maxchanperscan; - int ret; + int ret = -ENOMEM; + struct chanscanparamset *chan_list; + struct chanscanparamset *curr_chans; + int chan_count; + u8 bsstype = CMD_BSS_TYPE_ANY; + int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD; + int filteredscan = 0; + union iwreq_data wrqu; #ifdef CONFIG_LIBERTAS_DEBUG - struct bss_descriptor * iter_bss; + struct bss_descriptor *iter; int i = 0; DECLARE_MAC_BUF(mac); #endif - lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); + lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", + full_scan); /* Cancel any partial outstanding partial scans if this scan * is a full scan. @@ -845,90 +562,138 @@ int wlan_scan_networks(wlan_private * priv, if (full_scan && delayed_work_pending(&priv->scan_work)) cancel_delayed_work(&priv->scan_work); - scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * - WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); - if (scan_chan_list == NULL) { - ret = -ENOMEM; + /* Determine same scan parameters */ + if (user_cfg) { + if (user_cfg->bsstype) + bsstype = user_cfg->bsstype; + if (compare_ether_addr(user_cfg->bssid, &zeromac[0]) != 0) { + numchannels = MRVDRV_MAX_CHANNELS_PER_SCAN; + filteredscan = 1; + } + } + lbs_deb_scan("numchannels %d, bsstype %d, " + "filteredscan %d\n", + numchannels, bsstype, filteredscan); + + /* Create list of channels to scan */ + chan_list = kzalloc(sizeof(struct chanscanparamset) * + LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); + if (!chan_list) { + lbs_pr_alert("SCAN: chan_list empty\n"); goto out; } - scan_cfg = wlan_scan_setup_scan_config(priv, - puserscanin, - &pchantlvout, - scan_chan_list, - &maxchanperscan, - &filteredscan, - &scancurrentchanonly); - if (scan_cfg == NULL) { - ret = -ENOMEM; - goto out; + /* We want to scan all channels */ + chan_count = lbs_scan_create_channel_list(priv, chan_list, + filteredscan); + + netif_stop_queue(priv->dev); + netif_carrier_off(priv->dev); + if (priv->mesh_dev) { + netif_stop_queue(priv->mesh_dev); + netif_carrier_off(priv->mesh_dev); + } + + /* Prepare to continue an interrupted scan */ + lbs_deb_scan("chan_count %d, last_scanned_channel %d\n", + chan_count, priv->last_scanned_channel); + curr_chans = chan_list; + /* advance channel list by already-scanned-channels */ + if (priv->last_scanned_channel > 0) { + curr_chans += priv->last_scanned_channel; + chan_count -= priv->last_scanned_channel; } - clear_selected_scan_list_entries(adapter, puserscanin); + /* Send scan command(s) + * numchannels contains the number of channels we should maximally scan + * chan_count is the total number of channels to scan + */ - /* Keep the data path active if we are only scanning our current channel */ - if (!scancurrentchanonly) { - netif_stop_queue(priv->dev); - netif_carrier_off(priv->dev); - if (priv->mesh_dev) { - netif_stop_queue(priv->mesh_dev); - netif_carrier_off(priv->mesh_dev); + while (chan_count) { + int to_scan = min(numchannels, chan_count); + lbs_deb_scan("scanning %d of %d channels\n", + to_scan, chan_count); + ret = lbs_do_scan(priv, bsstype, curr_chans, + to_scan, user_cfg); + if (ret) { + lbs_pr_err("SCAN_CMD failed\n"); + goto out2; + } + curr_chans += to_scan; + chan_count -= to_scan; + + /* somehow schedule the next part of the scan */ + if (chan_count && + !full_scan && + !priv->surpriseremoved) { + /* -1 marks just that we're currently scanning */ + if (priv->last_scanned_channel < 0) + priv->last_scanned_channel = to_scan; + else + priv->last_scanned_channel += to_scan; + cancel_delayed_work(&priv->scan_work); + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(300)); + /* skip over GIWSCAN event */ + goto out; } - } - ret = wlan_scan_channel_list(priv, - maxchanperscan, - filteredscan, - scan_cfg, - pchantlvout, - scan_chan_list, - puserscanin, - full_scan); + } + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); #ifdef CONFIG_LIBERTAS_DEBUG /* Dump the scan table */ - mutex_lock(&adapter->lock); - lbs_deb_scan("The scan table contains:\n"); - list_for_each_entry (iter_bss, &adapter->network_list, list) { - lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n", - i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi, - escape_essid(iter_bss->ssid, iter_bss->ssid_len)); - } - mutex_unlock(&adapter->lock); + mutex_lock(&priv->lock); + lbs_deb_scan("scan table:\n"); + list_for_each_entry(iter, &priv->network_list, list) + lbs_deb_scan("%02d: BSSID %s, RSSI %d, SSID '%s'\n", + i++, print_mac(mac, iter->bssid), (s32) iter->rssi, + escape_essid(iter->ssid, iter->ssid_len)); + mutex_unlock(&priv->lock); #endif - if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { +out2: + priv->last_scanned_channel = 0; + +out: + if (priv->connect_status == LBS_CONNECTED) { netif_carrier_on(priv->dev); - netif_wake_queue(priv->dev); - if (priv->mesh_dev) { - netif_carrier_on(priv->mesh_dev); + if (!priv->tx_pending_len) + netif_wake_queue(priv->dev); + } + if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) { + netif_carrier_on(priv->mesh_dev); + if (!priv->tx_pending_len) netif_wake_queue(priv->mesh_dev); - } } - -out: - if (scan_cfg) - kfree(scan_cfg); - - if (scan_chan_list) - kfree(scan_chan_list); + kfree(chan_list); lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); return ret; } + + + +/*********************************************************************/ +/* */ +/* Result interpretation */ +/* */ +/*********************************************************************/ + /** * @brief Interpret a BSS scan response returned from the firmware * * Parse the various fixed fields and IEs passed back for a a BSS probe - * response or beacon from the scan command. Record information as needed - * in the scan table struct bss_descriptor for that entry. + * response or beacon from the scan command. Record information as needed + * in the scan table struct bss_descriptor for that entry. * * @param bss Output parameter: Pointer to the BSS Entry * * @return 0 or -1 */ -static int libertas_process_bss(struct bss_descriptor * bss, +static int lbs_process_bss(struct bss_descriptor *bss, u8 ** pbeaconinfo, int *bytesleft) { struct ieeetypes_fhparamset *pFH; @@ -946,7 +711,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo)); + beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo)); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } @@ -967,7 +732,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); - lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid)); + lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid)); pos += ETH_ALEN; if ((end - pos) < 12) { @@ -983,7 +748,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* RSSI is 1 byte long */ bss->rssi = *pos; - lbs_deb_scan("process_bss: RSSI=%02X\n", *pos); + lbs_deb_scan("process_bss: RSSI %d\n", *pos); pos++; /* time stamp is 8 bytes long */ @@ -995,18 +760,18 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* capability information is 2 bytes long */ bss->capability = le16_to_cpup((void *) pos); - lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability); + lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability); pos += 2; if (bss->capability & WLAN_CAPABILITY_PRIVACY) - lbs_deb_scan("process_bss: AP WEP enabled\n"); + lbs_deb_scan("process_bss: WEP enabled\n"); if (bss->capability & WLAN_CAPABILITY_IBSS) bss->mode = IW_MODE_ADHOC; else bss->mode = IW_MODE_INFRA; /* rest of the current buffer are IE's */ - lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos); + lbs_deb_scan("process_bss: IE len %zd\n", end - pos); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos); /* process variable IE */ @@ -1024,7 +789,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, case MFIE_TYPE_SSID: bss->ssid_len = elem->len; memcpy(bss->ssid, elem->data, elem->len); - lbs_deb_scan("ssid '%s', ssid length %u\n", + lbs_deb_scan("got SSID IE: '%s', len %u\n", escape_essid(bss->ssid, bss->ssid_len), bss->ssid_len); break; @@ -1033,16 +798,14 @@ static int libertas_process_bss(struct bss_descriptor * bss, n_basic_rates = min_t(u8, MAX_RATES, elem->len); memcpy(bss->rates, elem->data, n_basic_rates); got_basic_rates = 1; + lbs_deb_scan("got RATES IE\n"); break; case MFIE_TYPE_FH_SET: pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset)); -#if 0 /* I think we can store these LE */ - bss->phyparamset.fhparamset.dwelltime - = le16_to_cpu(bss->phyparamset.fhparamset.dwelltime); -#endif + lbs_deb_scan("got FH IE\n"); break; case MFIE_TYPE_DS_SET: @@ -1050,31 +813,31 @@ static int libertas_process_bss(struct bss_descriptor * bss, bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, sizeof(struct ieeetypes_dsparamset)); + lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; case MFIE_TYPE_CF_SET: pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); + lbs_deb_scan("got CF IE\n"); break; case MFIE_TYPE_IBSS_SET: pibss = (struct ieeetypes_ibssparamset *) pos; - bss->atimwindow = le32_to_cpu(pibss->atimwindow); + bss->atimwindow = le16_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, sizeof(struct ieeetypes_ibssparamset)); -#if 0 - bss->ssparamset.ibssparamset.atimwindow - = le16_to_cpu(bss->ssparamset.ibssparamset.atimwindow); -#endif + lbs_deb_scan("got IBSS IE\n"); break; case MFIE_TYPE_COUNTRY: pcountryinfo = (struct ieeetypes_countryinfoset *) pos; + lbs_deb_scan("got COUNTRY IE\n"); if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) || pcountryinfo->len > 254) { lbs_deb_scan("process_bss: 11D- Err " - "CountryInfo len =%d min=%zd max=254\n", + "CountryInfo len %d, min %zd, max 254\n", pcountryinfo->len, sizeof(pcountryinfo->countrycode)); ret = -1; @@ -1093,8 +856,11 @@ static int libertas_process_bss(struct bss_descriptor * bss, * already found. Data rate IE should come before * extended supported rate IE */ - if (!got_basic_rates) + lbs_deb_scan("got RATESEX IE\n"); + if (!got_basic_rates) { + lbs_deb_scan("... but ignoring it\n"); break; + } n_ex_rates = elem->len; if (n_basic_rates + n_ex_rates > MAX_RATES) @@ -1113,24 +879,36 @@ static int libertas_process_bss(struct bss_descriptor * bss, bss->wpa_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); - lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie, + lbs_deb_scan("got WPA IE\n"); + lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, elem->len); } else if (elem->len >= MARVELL_MESH_IE_LENGTH && elem->data[0] == 0x00 && elem->data[1] == 0x50 && elem->data[2] == 0x43 && elem->data[3] == 0x04) { + lbs_deb_scan("got mesh IE\n"); bss->mesh = 1; + } else { + lbs_deb_scan("got generiec IE: " + "%02x:%02x:%02x:%02x, len %d\n", + elem->data[0], elem->data[1], + elem->data[2], elem->data[3], + elem->len); } break; case MFIE_TYPE_RSN: + lbs_deb_scan("got RSN IE\n"); bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); - lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len); + lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", + bss->rsn_ie, elem->len); break; default: + lbs_deb_scan("got IE 0x%04x, len %d\n", + elem->id, elem->len); break; } @@ -1139,7 +917,7 @@ static int libertas_process_bss(struct bss_descriptor * bss, /* Timestamp */ bss->last_scanned = jiffies; - libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); + lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates)); ret = 0; @@ -1153,13 +931,13 @@ done: * * Used in association code * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * @param bssid BSSID to find in the scan list * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list, or error return code (< 0) */ -struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, +struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, u8 * bssid, u8 mode) { struct bss_descriptor * iter_bss; @@ -1177,14 +955,14 @@ struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, * continue past a matched bssid that is not compatible in case there * is an AP with multiple SSIDs assigned to the same BSSID */ - mutex_lock(&adapter->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { + mutex_lock(&priv->lock); + list_for_each_entry (iter_bss, &priv->network_list, list) { if (compare_ether_addr(iter_bss->bssid, bssid)) continue; /* bssid doesn't match */ switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: - if (!is_network_compatible(adapter, iter_bss, mode)) + if (!is_network_compatible(priv, iter_bss, mode)) break; found_bss = iter_bss; break; @@ -1193,7 +971,7 @@ struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter, break; } } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); out: lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); @@ -1205,14 +983,14 @@ out: * * Used in association code * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * @param ssid SSID to find in the list * @param bssid BSSID to qualify the SSID selection (if provided) * @param mode Network mode: Infrastructure or IBSS * * @return index in BSSID list */ -struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, +struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, int channel) { @@ -1223,14 +1001,14 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, lbs_deb_enter(LBS_DEB_SCAN); - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { + list_for_each_entry (iter_bss, &priv->network_list, list) { if ( !tmp_oldest || (iter_bss->last_scanned < tmp_oldest->last_scanned)) tmp_oldest = iter_bss; - if (libertas_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, + if (lbs_ssid_cmp(iter_bss->ssid, iter_bss->ssid_len, ssid, ssid_len) != 0) continue; /* ssid doesn't match */ if (bssid && compare_ether_addr(iter_bss->bssid, bssid) != 0) @@ -1241,7 +1019,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: - if (!is_network_compatible(adapter, iter_bss, mode)) + if (!is_network_compatible(priv, iter_bss, mode)) break; if (bssid) { @@ -1266,7 +1044,7 @@ struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, } out: - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss); return found_bss; } @@ -1277,12 +1055,13 @@ out: * Search the scan table for the best SSID that also matches the current * adapter network preference (infrastructure or adhoc) * - * @param adapter A pointer to wlan_adapter + * @param priv A pointer to struct lbs_private * * @return index in BSSID list */ -static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter, - u8 mode) +static struct bss_descriptor *lbs_find_best_ssid_in_list( + struct lbs_private *priv, + u8 mode) { u8 bestrssi = 0; struct bss_descriptor * iter_bss; @@ -1290,13 +1069,13 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad lbs_deb_enter(LBS_DEB_SCAN); - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); - list_for_each_entry (iter_bss, &adapter->network_list, list) { + list_for_each_entry (iter_bss, &priv->network_list, list) { switch (mode) { case IW_MODE_INFRA: case IW_MODE_ADHOC: - if (!is_network_compatible(adapter, iter_bss, mode)) + if (!is_network_compatible(priv, iter_bss, mode)) break; if (SCAN_RSSI(iter_bss->rssi) <= bestrssi) break; @@ -1313,7 +1092,7 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad } } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss); return best_bss; } @@ -1323,27 +1102,24 @@ static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * ad * * Used from association worker. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param pSSID A pointer to AP's ssid * * @return 0--success, otherwise--fail */ -int libertas_find_best_network_ssid(wlan_private * priv, +int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode) { - wlan_adapter *adapter = priv->adapter; int ret = -1; struct bss_descriptor * found; lbs_deb_enter(LBS_DEB_SCAN); - wlan_scan_networks(priv, NULL, 1); - if (adapter->surpriseremoved) + lbs_scan_networks(priv, NULL, 1); + if (priv->surpriseremoved) goto out; - wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); - - found = libertas_find_best_ssid_in_list(adapter, preferred_mode); + found = lbs_find_best_ssid_in_list(priv, preferred_mode); if (found && (found->ssid_len > 0)) { memcpy(out_ssid, &found->ssid, IW_ESSID_MAX_SIZE); *out_ssid_len = found->ssid_len; @@ -1356,57 +1132,24 @@ out: return ret; } -/** - * @brief Scan Network - * - * @param dev A pointer to net_device structure - * @param info A pointer to iw_request_info structure - * @param vwrq A pointer to iw_param structure - * @param extra A pointer to extra data buf - * - * @return 0 --success, otherwise fail - */ -int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, - struct iw_param *vwrq, char *extra) -{ - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - - lbs_deb_enter(LBS_DEB_SCAN); - - if (!delayed_work_pending(&priv->scan_work)) { - queue_delayed_work(priv->work_thread, &priv->scan_work, - msecs_to_jiffies(50)); - } - - if (adapter->surpriseremoved) - return -1; - - lbs_deb_leave(LBS_DEB_SCAN); - return 0; -} - /** * @brief Send a scan command for all available channels filtered on a spec * * Used in association code and from debugfs * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param ssid A pointer to the SSID to scan for * @param ssid_len Length of the SSID * @param clear_ssid Should existing scan results with this SSID * be cleared? - * @param prequestedssid A pointer to AP's ssid - * @param keeppreviousscan Flag used to save/clear scan table before scan * * @return 0-success, otherwise fail */ -int libertas_send_specific_ssid_scan(wlan_private * priv, +int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, u8 ssid_len, u8 clear_ssid) { - wlan_adapter *adapter = priv->adapter; - struct wlan_ioctl_user_scan_cfg scancfg; + struct lbs_ioctl_user_scan_cfg scancfg; int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d", @@ -1420,12 +1163,11 @@ int libertas_send_specific_ssid_scan(wlan_private * priv, scancfg.ssid_len = ssid_len; scancfg.clear_ssid = clear_ssid; - wlan_scan_networks(priv, &scancfg, 1); - if (adapter->surpriseremoved) { + lbs_scan_networks(priv, &scancfg, 1); + if (priv->surpriseremoved) { ret = -1; goto out; } - wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); out: lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); @@ -1441,13 +1183,13 @@ out: /* */ /*********************************************************************/ + #define MAX_CUSTOM_LEN 64 -static inline char *libertas_translate_scan(wlan_private *priv, +static inline char *lbs_translate_scan(struct lbs_private *priv, char *start, char *stop, struct bss_descriptor *bss) { - wlan_adapter *adapter = priv->adapter; struct chan_freq_power *cfp; char *current_val; /* For rates */ struct iw_event iwe; /* Temporary buffer */ @@ -1459,14 +1201,14 @@ static inline char *libertas_translate_scan(wlan_private *priv, lbs_deb_enter(LBS_DEB_SCAN); - cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel); + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel); if (!cfp) { lbs_deb_scan("Invalid channel number %d\n", bss->channel); start = NULL; goto out; } - /* First entry *MUST* be the AP BSSID */ + /* First entry *MUST* be the BSSID */ iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN); @@ -1502,25 +1244,25 @@ static inline char *libertas_translate_scan(wlan_private *priv, if (iwe.u.qual.qual > 100) iwe.u.qual.qual = 100; - if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; } else { iwe.u.qual.noise = - CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); } /* Locally created ad-hoc BSSs won't have beacons if this is the * only station in the adhoc network; so get signal strength * from receive statistics. */ - if ((adapter->mode == IW_MODE_ADHOC) - && adapter->adhoccreate - && !libertas_ssid_cmp(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len, + if ((priv->mode == IW_MODE_ADHOC) + && priv->adhoccreate + && !lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, bss->ssid, bss->ssid_len)) { int snr, nf; - snr = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; - nf = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; + nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; iwe.u.qual.level = CAL_RSSI(snr, nf); } start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN); @@ -1549,10 +1291,10 @@ static inline char *libertas_translate_scan(wlan_private *priv, stop, &iwe, IW_EV_PARAM_LEN); } if ((bss->mode == IW_MODE_ADHOC) - && !libertas_ssid_cmp(adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len, + && !lbs_ssid_cmp(priv->curbssparams.ssid, + priv->curbssparams.ssid_len, bss->ssid, bss->ssid_len) - && adapter->adhoccreate) { + && priv->adhoccreate) { iwe.u.bitrate.value = 22 * 500000; current_val = iwe_stream_add_value(start, current_val, stop, &iwe, IW_EV_PARAM_LEN); @@ -1596,6 +1338,54 @@ out: return start; } + +/** + * @brief Handle Scan Network ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *wrqu, char *extra) +{ + struct lbs_private *priv = dev->priv; + + lbs_deb_enter(LBS_DEB_SCAN); + + if (!netif_running(dev)) + return -ENETDOWN; + + /* mac80211 does this: + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->type != IEEE80211_IF_TYPE_xxx) + return -EOPNOTSUPP; + + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + req = (struct iw_scan_req *)extra; + ssid = req->essid; + ssid_len = req->essid_len; + } + */ + + if (!delayed_work_pending(&priv->scan_work)) + queue_delayed_work(priv->work_thread, &priv->scan_work, + msecs_to_jiffies(50)); + /* set marker that currently a scan is taking place */ + priv->last_scanned_channel = -1; + + if (priv->surpriseremoved) + return -EIO; + + lbs_deb_leave(LBS_DEB_SCAN); + return 0; +} + + /** * @brief Handle Retrieve scan table ioctl * @@ -1606,12 +1396,11 @@ out: * * @return 0 --success, otherwise fail */ -int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, +int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { #define SCAN_ITEM_SIZE 128 - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int err = 0; char *ev = extra; char *stop = ev + dwrq->length; @@ -1620,14 +1409,18 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, lbs_deb_enter(LBS_DEB_SCAN); + /* iwlist should wait until the current scan is finished */ + if (priv->last_scanned_channel) + return -EAGAIN; + /* Update RSSI if current BSS is a locally created ad-hoc BSS */ - if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) { - libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) { + lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); } - mutex_lock(&adapter->lock); - list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { + mutex_lock(&priv->lock); + list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { char * next_ev; unsigned long stale_time; @@ -1644,18 +1437,18 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_after(jiffies, stale_time)) { list_move_tail (&iter_bss->list, - &adapter->network_free_list); + &priv->network_free_list); clear_bss_descriptor(iter_bss); continue; } /* Translate to WE format this entry */ - next_ev = libertas_translate_scan(priv, ev, stop, iter_bss); + next_ev = lbs_translate_scan(priv, ev, stop, iter_bss); if (next_ev == NULL) continue; ev = next_ev; } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); dwrq->length = (ev - extra); dwrq->flags = 0; @@ -1677,24 +1470,25 @@ int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, /** * @brief Prepare a scan command to be sent to the firmware * - * Called from libertas_prepare_and_send_command() in cmd.c + * Called via lbs_prepare_and_send_command(priv, CMD_802_11_SCAN, ...) + * from cmd.c * * Sends a fixed lenght data part (specifying the BSS type and BSSID filters) * as well as a variable number/length of TLVs to the firmware. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param cmd A pointer to cmd_ds_command structure to be sent to * firmware with the cmd_DS_801_11_SCAN structure - * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used + * @param pdata_buf Void pointer cast of a lbs_scan_cmd_config struct used * to set the fields/TLVs for the command sent to firmware * * @return 0 or -1 */ -int libertas_cmd_80211_scan(wlan_private * priv, - struct cmd_ds_command *cmd, void *pdata_buf) +int lbs_cmd_80211_scan(struct lbs_private *priv, + struct cmd_ds_command *cmd, void *pdata_buf) { struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; - struct wlan_scan_cmd_config *pscancfg = pdata_buf; + struct lbs_scan_cmd_config *pscancfg = pdata_buf; lbs_deb_enter(LBS_DEB_SCAN); @@ -1703,32 +1497,14 @@ int libertas_cmd_80211_scan(wlan_private * priv, memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN); memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); - cmd->command = cpu_to_le16(CMD_802_11_SCAN); - /* size is equal to the sizeof(fixed portions) + the TLV len + header */ cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN + pscancfg->tlvbufferlen + S_DS_GEN); - lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n", - le16_to_cpu(cmd->command), le16_to_cpu(cmd->size), - le16_to_cpu(cmd->seqnum)); - lbs_deb_leave(LBS_DEB_SCAN); return 0; } -static inline int is_same_network(struct bss_descriptor *src, - struct bss_descriptor *dst) -{ - /* A network is only a duplicate if the channel, BSSID, and ESSID - * all match. We treat all <hidden> with the same BSSID and channel - * as one network */ - return ((src->ssid_len == dst->ssid_len) && - (src->channel == dst->channel) && - !compare_ether_addr(src->bssid, dst->bssid) && - !memcmp(src->ssid, dst->ssid, src->ssid_len)); -} - /** * @brief This function handles the command response of scan * @@ -1750,14 +1526,13 @@ static inline int is_same_network(struct bss_descriptor *src, * | bufsize and sizeof the fixed fields above) | * .-----------------------------------------------------------. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param resp A pointer to cmd_ds_command * * @return 0 or -1 */ -int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) +int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp) { - wlan_adapter *adapter = priv->adapter; struct cmd_ds_802_11_scan_rsp *pscan; struct bss_descriptor * iter_bss; struct bss_descriptor * safe; @@ -1771,11 +1546,11 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) lbs_deb_enter(LBS_DEB_SCAN); /* Prune old entries from scan table */ - list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) { + list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) { unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; if (time_before(jiffies, stale_time)) continue; - list_move_tail (&iter_bss->list, &adapter->network_free_list); + list_move_tail (&iter_bss->list, &priv->network_free_list); clear_bss_descriptor(iter_bss); } @@ -1789,12 +1564,11 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) goto done; } - bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize)); + bytesleft = le16_to_cpu(pscan->bssdescriptsize); lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft); - scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size)); - lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n", - pscan->nr_sets); + scanrespsize = le16_to_cpu(resp->size); + lbs_deb_scan("SCAN_RESP: scan results %d\n", pscan->nr_sets); pbssinfo = pscan->bssdesc_and_tlvbuffer; @@ -1821,14 +1595,14 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) /* Process the data fields and IEs returned for this BSS */ memset(&new, 0, sizeof (struct bss_descriptor)); - if (libertas_process_bss(&new, &pbssinfo, &bytesleft) != 0) { + if (lbs_process_bss(&new, &pbssinfo, &bytesleft) != 0) { /* error parsing the scan response, skipped */ lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n"); continue; } /* Try to find this bss in the scan table */ - list_for_each_entry (iter_bss, &adapter->network_list, list) { + list_for_each_entry (iter_bss, &priv->network_list, list) { if (is_same_network(iter_bss, &new)) { found = iter_bss; break; @@ -1842,21 +1616,21 @@ int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) if (found) { /* found, clear it */ clear_bss_descriptor(found); - } else if (!list_empty(&adapter->network_free_list)) { + } else if (!list_empty(&priv->network_free_list)) { /* Pull one from the free list */ - found = list_entry(adapter->network_free_list.next, + found = list_entry(priv->network_free_list.next, struct bss_descriptor, list); - list_move_tail(&found->list, &adapter->network_list); + list_move_tail(&found->list, &priv->network_list); } else if (oldest) { /* If there are no more slots, expire the oldest */ found = oldest; clear_bss_descriptor(found); - list_move_tail(&found->list, &adapter->network_list); + list_move_tail(&found->list, &priv->network_list); } else { continue; } - lbs_deb_scan("SCAN_RESP: BSSID = %s\n", + lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid)); /* Copy the locally created newbssentry to the scan table */ diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index c29c031bef8c..319f70dde350 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -2,10 +2,10 @@ * Interface for the wlan network scan routines * * Driver interface functions and type declarations for the scan module - * implemented in wlan_scan.c. + * implemented in scan.c. */ -#ifndef _WLAN_SCAN_H -#define _WLAN_SCAN_H +#ifndef _LBS_SCAN_H +#define _LBS_SCAN_H #include <net/ieee80211.h> #include "hostcmd.h" @@ -13,38 +13,38 @@ /** * @brief Maximum number of channels that can be sent in a setuserscan ioctl * - * @sa wlan_ioctl_user_scan_cfg + * @sa lbs_ioctl_user_scan_cfg */ -#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 +#define LBS_IOCTL_USER_SCAN_CHAN_MAX 50 -//! Infrastructure BSS scan type in wlan_scan_cmd_config -#define WLAN_SCAN_BSS_TYPE_BSS 1 +//! Infrastructure BSS scan type in lbs_scan_cmd_config +#define LBS_SCAN_BSS_TYPE_BSS 1 -//! Adhoc BSS scan type in wlan_scan_cmd_config -#define WLAN_SCAN_BSS_TYPE_IBSS 2 +//! Adhoc BSS scan type in lbs_scan_cmd_config +#define LBS_SCAN_BSS_TYPE_IBSS 2 -//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter -#define WLAN_SCAN_BSS_TYPE_ANY 3 +//! Adhoc or Infrastructure BSS scan type in lbs_scan_cmd_config, no filter +#define LBS_SCAN_BSS_TYPE_ANY 3 /** * @brief Structure used internally in the wlan driver to configure a scan. * * Sent to the command processing module to configure the firmware - * scan command prepared by libertas_cmd_80211_scan. + * scan command prepared by lbs_cmd_80211_scan. * - * @sa wlan_scan_networks + * @sa lbs_scan_networks * */ -struct wlan_scan_cmd_config { +struct lbs_scan_cmd_config { /** * @brief BSS type to be sent in the firmware command * * Field can be used to restrict the types of networks returned in the * scan. valid settings are: * - * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) - * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) - * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) + * - LBS_SCAN_BSS_TYPE_BSS (infrastructure) + * - LBS_SCAN_BSS_TYPE_IBSS (adhoc) + * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) */ u8 bsstype; @@ -68,12 +68,12 @@ struct wlan_scan_cmd_config { }; /** - * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg + * @brief IOCTL channel sub-structure sent in lbs_ioctl_user_scan_cfg * * Multiple instances of this structure are included in the IOCTL command * to configure a instance of a scan on the specific channel. */ -struct wlan_ioctl_user_scan_chan { +struct lbs_ioctl_user_scan_chan { u8 channumber; //!< channel Number to scan u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1 u8 scantype; //!< Scan type: Active = 0, Passive = 1 @@ -83,31 +83,26 @@ struct wlan_ioctl_user_scan_chan { /** * @brief IOCTL input structure to configure an immediate scan cmd to firmware * - * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies + * Used in the setuserscan (LBS_SET_USER_SCAN) private ioctl. Specifies * a number of parameters to be used in general for the scan as well - * as a channel list (wlan_ioctl_user_scan_chan) for each scan period + * as a channel list (lbs_ioctl_user_scan_chan) for each scan period * desired. * - * @sa libertas_set_user_scan_ioctl + * @sa lbs_set_user_scan_ioctl */ -struct wlan_ioctl_user_scan_cfg { +struct lbs_ioctl_user_scan_cfg { /** * @brief BSS type to be sent in the firmware command * * Field can be used to restrict the types of networks returned in the * scan. valid settings are: * - * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) - * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) - * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) + * - LBS_SCAN_BSS_TYPE_BSS (infrastructure) + * - LBS_SCAN_BSS_TYPE_IBSS (adhoc) + * - LBS_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) */ u8 bsstype; - /** - * @brief Configure the number of probe requests for active chan scans - */ - u8 numprobes; - /** * @brief BSSID filter sent in the firmware command to limit the results */ @@ -124,11 +119,6 @@ struct wlan_ioctl_user_scan_cfg { /* Clear existing scan results matching this SSID */ u8 clear_ssid; - - /** - * @brief Variable number (fixed maximum) of channels to scan up - */ - struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; }; /** @@ -174,30 +164,30 @@ struct bss_descriptor { struct list_head list; }; -int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); +int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len); -struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter, - u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode, - int channel); +struct bss_descriptor *lbs_find_ssid_in_list(struct lbs_private *priv, + u8 *ssid, u8 ssid_len, u8 *bssid, u8 mode, + int channel); -struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter, - u8 * bssid, u8 mode); +struct bss_descriptor *lbs_find_bssid_in_list(struct lbs_private *priv, + u8 *bssid, u8 mode); -int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid, +int lbs_find_best_network_ssid(struct lbs_private *priv, u8 *out_ssid, u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode); -int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid, +int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid, u8 ssid_len, u8 clear_ssid); -int libertas_cmd_80211_scan(wlan_private * priv, +int lbs_cmd_80211_scan(struct lbs_private *priv, struct cmd_ds_command *cmd, void *pdata_buf); -int libertas_ret_80211_scan(wlan_private * priv, +int lbs_ret_80211_scan(struct lbs_private *priv, struct cmd_ds_command *resp); -int wlan_scan_networks(wlan_private * priv, - const struct wlan_ioctl_user_scan_cfg * puserscanin, +int lbs_scan_networks(struct lbs_private *priv, + const struct lbs_ioctl_user_scan_cfg *puserscanin, int full_scan); struct ifreq; @@ -205,11 +195,11 @@ struct ifreq; struct iw_point; struct iw_param; struct iw_request_info; -int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, +int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra); -int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, +int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra); -void libertas_scan_worker(struct work_struct *work); +void lbs_scan_worker(struct work_struct *work); -#endif /* _WLAN_SCAN_H */ +#endif diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index fbec06c10dd7..00d95f75bd89 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -2,6 +2,7 @@ * This file contains the handling of TX in wlan driver. */ #include <linux/netdevice.h> +#include <linux/etherdevice.h> #include "hostcmd.h" #include "radiotap.h" @@ -49,188 +50,122 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) } /** - * @brief This function processes a single packet and sends - * to IF layer + * @brief This function checks the conditions and sends packet to IF + * layer if everything is ok. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param skb A pointer to skb which includes TX packet * @return 0 or -1 */ -static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) +int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - int ret = 0; - struct txpd localtxpd; - struct txpd *plocaltxpd = &localtxpd; - u8 *p802x_hdr; - struct tx_radiotap_hdr *pradiotap_hdr; - u32 new_rate; - u8 *ptr = priv->adapter->tmptxbuf; + unsigned long flags; + struct lbs_private *priv = dev->priv; + struct txpd *txpd; + char *p802x_hdr; + uint16_t pkt_len; + int ret; lbs_deb_enter(LBS_DEB_TX); - if (priv->adapter->surpriseremoved) - return -1; + ret = NETDEV_TX_OK; + + /* We need to protect against the queues being restarted before + we get round to stopping them */ + spin_lock_irqsave(&priv->driver_lock, flags); + + if (priv->surpriseremoved) + goto free; if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { lbs_deb_tx("tx err: skb length %d 0 or > %zd\n", skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); - ret = -1; - goto done; + /* We'll never manage to send this one; drop it and return 'OK' */ + + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + goto free; } - memset(plocaltxpd, 0, sizeof(struct txpd)); - plocaltxpd->tx_packet_length = cpu_to_le16(skb->len); + netif_stop_queue(priv->dev); + if (priv->mesh_dev) + netif_stop_queue(priv->mesh_dev); - /* offset of actual data */ - plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); + if (priv->tx_pending_len) { + /* This can happen if packets come in on the mesh and eth + device simultaneously -- there's no mutual exclusion on + hard_start_xmit() calls between devices. */ + lbs_deb_tx("Packet on %s while busy\n", dev->name); + ret = NETDEV_TX_BUSY; + goto unlock; + } + + priv->tx_pending_len = -1; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); + + txpd = (void *)priv->tx_pending_buf; + memset(txpd, 0, sizeof(struct txpd)); p802x_hdr = skb->data; - if (priv->adapter->monitormode != WLAN_MONITOR_OFF) { + pkt_len = skb->len; - /* locate radiotap header */ - pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; + if (dev == priv->rtap_net_dev) { + struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data; /* set txpd fields from the radiotap header */ - new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); - if (new_rate != 0) { - /* use new tx_control[4:0] */ - plocaltxpd->tx_control = cpu_to_le32(new_rate); - } + txpd->tx_control = cpu_to_le32(convert_radiotap_rate_to_mv(rtap_hdr->rate)); /* skip the radiotap header */ - p802x_hdr += sizeof(struct tx_radiotap_hdr); - plocaltxpd->tx_packet_length = - cpu_to_le16(le16_to_cpu(plocaltxpd->tx_packet_length) - - sizeof(struct tx_radiotap_hdr)); + p802x_hdr += sizeof(*rtap_hdr); + pkt_len -= sizeof(*rtap_hdr); + /* copy destination address from 802.11 header */ + memcpy(txpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); + } else { + /* copy destination address from 802.3 header */ + memcpy(txpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); } - /* copy destination address from 802.3 or 802.11 header */ - if (priv->adapter->monitormode != WLAN_MONITOR_OFF) - memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); - else - memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); - lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); + txpd->tx_packet_length = cpu_to_le16(pkt_len); + txpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd)); - if (IS_MESH_FRAME(skb)) { - plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); - } + if (dev == priv->mesh_dev) + txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME); - memcpy(ptr, plocaltxpd, sizeof(struct txpd)); + lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) &txpd, sizeof(struct txpd)); - ptr += sizeof(struct txpd); + lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); - lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); - memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length)); - ret = priv->hw_host_to_card(priv, MVMS_DAT, - priv->adapter->tmptxbuf, - le16_to_cpu(plocaltxpd->tx_packet_length) + - sizeof(struct txpd)); + memcpy(&txpd[1], p802x_hdr, le16_to_cpu(txpd->tx_packet_length)); - if (ret) { - lbs_deb_tx("tx err: hw_host_to_card returned 0x%X\n", ret); - goto done; - } + spin_lock_irqsave(&priv->driver_lock, flags); + priv->tx_pending_len = pkt_len + sizeof(struct txpd); - lbs_deb_tx("SendSinglePacket succeeds\n"); + lbs_deb_tx("%s lined up packet\n", __func__); -done: - if (!ret) { - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; - } else { - priv->stats.tx_dropped++; - priv->stats.tx_errors++; - } + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; - if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) { + dev->trans_start = jiffies; + + if (priv->monitormode != LBS_MONITOR_OFF) { /* Keep the skb to echo it back once Tx feedback is received from FW */ skb_orphan(skb); - /* stop processing outgoing pkts */ - netif_stop_queue(priv->dev); - if (priv->mesh_dev) - netif_stop_queue(priv->mesh_dev); - /* freeze any packets already in our queues */ - priv->adapter->TxLockFlag = 1; - } else { - dev_kfree_skb_any(skb); - priv->adapter->currenttxskb = NULL; - } - lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); - return ret; -} - - -void libertas_tx_runqueue(wlan_private *priv) -{ - wlan_adapter *adapter = priv->adapter; - int i; - - spin_lock(&adapter->txqueue_lock); - for (i = 0; i < adapter->tx_queue_idx; i++) { - struct sk_buff *skb = adapter->tx_queue_ps[i]; - spin_unlock(&adapter->txqueue_lock); - SendSinglePacket(priv, skb); - spin_lock(&adapter->txqueue_lock); - } - adapter->tx_queue_idx = 0; - spin_unlock(&adapter->txqueue_lock); -} - -static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) -{ - wlan_adapter *adapter = priv->adapter; - - spin_lock(&adapter->txqueue_lock); - - WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE); - adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; - if (adapter->tx_queue_idx == NR_TX_QUEUE) { - netif_stop_queue(priv->dev); - if (priv->mesh_dev) - netif_stop_queue(priv->mesh_dev); + /* Keep the skb around for when we get feedback */ + priv->currenttxskb = skb; } else { - netif_start_queue(priv->dev); - if (priv->mesh_dev) - netif_start_queue(priv->mesh_dev); - } - - spin_unlock(&adapter->txqueue_lock); -} - -/** - * @brief This function checks the conditions and sends packet to IF - * layer if everything is ok. - * - * @param priv A pointer to wlan_private structure - * @return n/a - */ -int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) -{ - int ret = -1; - - lbs_deb_enter(LBS_DEB_TX); - lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100)); - - if (priv->dnld_sent) { - lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", - priv->dnld_sent); - goto done; - } - - if ((priv->adapter->psstate == PS_STATE_SLEEP) || - (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) { - wlan_tx_queue(priv, skb); - return ret; + free: + dev_kfree_skb_any(skb); } + unlock: + spin_unlock_irqrestore(&priv->driver_lock, flags); + wake_up(&priv->waitq); - priv->adapter->currenttxskb = skb; - - ret = SendSinglePacket(priv, skb); -done: lbs_deb_leave_args(LBS_DEB_TX, "ret %d", ret); return ret; } @@ -239,24 +174,23 @@ done: * @brief This function sends to the host the last transmitted packet, * filling the radiotap headers with transmission information. * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @param status A 32 bit value containing transmission status. * * @returns void */ -void libertas_send_tx_feedback(wlan_private * priv) +void lbs_send_tx_feedback(struct lbs_private *priv) { - wlan_adapter *adapter = priv->adapter; struct tx_radiotap_hdr *radiotap_hdr; - u32 status = adapter->eventcause; + u32 status = priv->eventcause; int txfail; int try_count; - if (adapter->monitormode == WLAN_MONITOR_OFF || - adapter->currenttxskb == NULL) + if (priv->monitormode == LBS_MONITOR_OFF || + priv->currenttxskb == NULL) return; - radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data; + radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data; txfail = (status >> 24); @@ -269,14 +203,19 @@ void libertas_send_tx_feedback(wlan_private * priv) #endif try_count = (status >> 16) & 0xff; radiotap_hdr->data_retries = (try_count) ? - (1 + adapter->txretrycount - try_count) : 0; - libertas_upload_rx_packet(priv, adapter->currenttxskb); - adapter->currenttxskb = NULL; - priv->adapter->TxLockFlag = 0; - if (priv->adapter->connect_status == LIBERTAS_CONNECTED) { + (1 + priv->txretrycount - try_count) : 0; + + + priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb, + priv->rtap_net_dev); + netif_rx(priv->currenttxskb); + + priv->currenttxskb = NULL; + + if (priv->connect_status == LBS_CONNECTED) netif_wake_queue(priv->dev); - if (priv->mesh_dev) - netif_wake_queue(priv->mesh_dev); - } + + if (priv->mesh_dev && (priv->mesh_connect_status == LBS_CONNECTED)) + netif_wake_queue(priv->mesh_dev); } -EXPORT_SYMBOL_GPL(libertas_send_tx_feedback); +EXPORT_SYMBOL_GPL(lbs_send_tx_feedback); diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index a43a5f63c879..f0d57958b34b 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -1,8 +1,8 @@ /** * This header file contains definition for global types */ -#ifndef _WLAN_TYPES_ -#define _WLAN_TYPES_ +#ifndef _LBS_TYPES_H_ +#define _LBS_TYPES_H_ #include <linux/if_ether.h> #include <asm/byteorder.h> @@ -201,22 +201,11 @@ struct mrvlietypes_powercapability { s8 maxpower; } __attribute__ ((packed)); -struct mrvlietypes_rssithreshold { +/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */ +struct mrvlietypes_thresholds { struct mrvlietypesheader header; - u8 rssivalue; - u8 rssifreq; -} __attribute__ ((packed)); - -struct mrvlietypes_snrthreshold { - struct mrvlietypesheader header; - u8 snrvalue; - u8 snrfreq; -} __attribute__ ((packed)); - -struct mrvlietypes_failurecount { - struct mrvlietypesheader header; - u8 failvalue; - u8 Failfreq; + u8 value; + u8 freq; } __attribute__ ((packed)); struct mrvlietypes_beaconsmissed { @@ -250,4 +239,4 @@ struct mrvlietypes_ledgpio { struct led_pin ledpin[1]; } __attribute__ ((packed)); -#endif /* _WLAN_TYPES_ */ +#endif diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 395b7882d4d6..e8bfc26b10a4 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -19,30 +19,47 @@ #include "join.h" #include "wext.h" #include "assoc.h" +#include "cmd.h" + + +static inline void lbs_postpone_association_work(struct lbs_private *priv) +{ + if (priv->surpriseremoved) + return; + cancel_delayed_work(&priv->assoc_work); + queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2); +} + +static inline void lbs_cancel_association_work(struct lbs_private *priv) +{ + cancel_delayed_work(&priv->assoc_work); + kfree(priv->pending_assoc_req); + priv->pending_assoc_req = NULL; +} /** * @brief Find the channel frequency power info with specific channel * - * @param adapter A pointer to wlan_adapter structure + * @param priv A pointer to struct lbs_private structure * @param band it can be BAND_A, BAND_G or BAND_B * @param channel the channel for looking * @return A pointer to struct chan_freq_power structure or NULL if not find. */ -struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter, - u8 band, u16 channel) +struct chan_freq_power *lbs_find_cfp_by_band_and_channel( + struct lbs_private *priv, + u8 band, + u16 channel) { struct chan_freq_power *cfp = NULL; struct region_channel *rc; - int count = sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0]); int i, j; - for (j = 0; !cfp && (j < count); j++) { - rc = &adapter->region_channel[j]; + for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { + rc = &priv->region_channel[j]; - if (adapter->enable11d) - rc = &adapter->universal_channel[j]; + if (priv->enable11d) + rc = &priv->universal_channel[j]; if (!rc->valid || !rc->CFP) continue; if (rc->band != band) @@ -56,7 +73,7 @@ struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * ada } if (!cfp && channel) - lbs_deb_wext("libertas_find_cfp_by_band_and_channel: can't find " + lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find " "cfp by band %d / channel %d\n", band, channel); return cfp; @@ -65,25 +82,25 @@ struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * ada /** * @brief Find the channel frequency power info with specific frequency * - * @param adapter A pointer to wlan_adapter structure + * @param priv A pointer to struct lbs_private structure * @param band it can be BAND_A, BAND_G or BAND_B * @param freq the frequency for looking * @return A pointer to struct chan_freq_power structure or NULL if not find. */ -static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, - u8 band, u32 freq) +static struct chan_freq_power *find_cfp_by_band_and_freq( + struct lbs_private *priv, + u8 band, + u32 freq) { struct chan_freq_power *cfp = NULL; struct region_channel *rc; - int count = sizeof(adapter->region_channel) / - sizeof(adapter->region_channel[0]); int i, j; - for (j = 0; !cfp && (j < count); j++) { - rc = &adapter->region_channel[j]; + for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) { + rc = &priv->region_channel[j]; - if (adapter->enable11d) - rc = &adapter->universal_channel[j]; + if (priv->enable11d) + rc = &priv->universal_channel[j]; if (!rc->valid || !rc->CFP) continue; if (rc->band != band) @@ -107,22 +124,21 @@ static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, /** * @brief Set Radio On/OFF * - * @param priv A pointer to wlan_private structure + * @param priv A pointer to struct lbs_private structure * @option Radio Option * @return 0 --success, otherwise fail */ -static int wlan_radio_ioctl(wlan_private * priv, u8 option) +static int lbs_radio_ioctl(struct lbs_private *priv, u8 option) { int ret = 0; - wlan_adapter *adapter = priv->adapter; lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->radioon != option) { + if (priv->radioon != option) { lbs_deb_wext("switching radio %s\n", option ? "on" : "off"); - adapter->radioon = option; + priv->radioon = option; - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_RADIO_CONTROL, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, 0, NULL); @@ -135,22 +151,23 @@ static int wlan_radio_ioctl(wlan_private * priv, u8 option) /** * @brief Copy active data rates based on adapter mode and status * - * @param adapter A pointer to wlan_adapter structure + * @param priv A pointer to struct lbs_private structure * @param rate The buf to return the active rates */ -static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates) +static void copy_active_data_rates(struct lbs_private *priv, u8 *rates) { lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status != LIBERTAS_CONNECTED) - memcpy(rates, libertas_bg_rates, MAX_RATES); + if ((priv->connect_status != LBS_CONNECTED) && + (priv->mesh_connect_status != LBS_CONNECTED)) + memcpy(rates, lbs_bg_rates, MAX_RATES); else - memcpy(rates, adapter->curbssparams.rates, MAX_RATES); + memcpy(rates, priv->curbssparams.rates, MAX_RATES); lbs_deb_leave(LBS_DEB_WEXT); } -static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_name(struct net_device *dev, struct iw_request_info *info, char *cwrq, char *extra) { @@ -163,22 +180,21 @@ static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, return 0; } -static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct chan_freq_power *cfp; lbs_deb_enter(LBS_DEB_WEXT); - cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, - adapter->curbssparams.channel); + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, + priv->curbssparams.channel); if (!cfp) { - if (adapter->curbssparams.channel) + if (priv->curbssparams.channel) lbs_deb_wext("invalid channel %d\n", - adapter->curbssparams.channel); + priv->curbssparams.channel); return -EINVAL; } @@ -190,16 +206,15 @@ static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, return 0; } -static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status == LIBERTAS_CONNECTED) { - memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN); + if (priv->connect_status == LBS_CONNECTED) { + memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN); } else { memset(awrq->sa_data, 0, ETH_ALEN); } @@ -209,11 +224,10 @@ static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, return 0; } -static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); @@ -225,25 +239,24 @@ static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, return -E2BIG; } - mutex_lock(&adapter->lock); - memset(adapter->nodename, 0, sizeof(adapter->nodename)); - memcpy(adapter->nodename, extra, dwrq->length); - mutex_unlock(&adapter->lock); + mutex_lock(&priv->lock); + memset(priv->nodename, 0, sizeof(priv->nodename)); + memcpy(priv->nodename, extra, dwrq->length); + mutex_unlock(&priv->lock); lbs_deb_leave(LBS_DEB_WEXT); return 0; } -static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - dwrq->length = strlen(adapter->nodename); - memcpy(extra, adapter->nodename, dwrq->length); + dwrq->length = strlen(priv->nodename); + memcpy(extra, priv->nodename, dwrq->length); extra[dwrq->length] = '\0'; dwrq->flags = 1; /* active */ @@ -255,14 +268,13 @@ static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); /* Use nickname to indicate that mesh is on */ - if (adapter->connect_status == LIBERTAS_CONNECTED) { + if (priv->mesh_connect_status == LBS_CONNECTED) { strncpy(extra, "Mesh", 12); extra[12] = '\0'; dwrq->length = strlen(extra); @@ -277,25 +289,24 @@ static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, return 0; } -static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; u32 rthr = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; + priv->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; } else { if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) return -EINVAL; - adapter->rtsthsd = rthr; + priv->rtsthsd = rthr; } - ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_RTS_THRESHOLD, &rthr); @@ -303,23 +314,22 @@ static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, return ret; } -static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - adapter->rtsthsd = 0; - ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + priv->rtsthsd = 0; + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_RTS_THRESHOLD, NULL); if (ret) goto out; - vwrq->value = adapter->rtsthsd; + vwrq->value = priv->rtsthsd; vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); vwrq->fixed = 1; @@ -329,26 +339,25 @@ out: return ret; } -static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; u32 fthr = vwrq->value; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; + priv->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; } else { if (fthr < MRVDRV_FRAG_MIN_VALUE || fthr > MRVDRV_FRAG_MAX_VALUE) return -EINVAL; - adapter->fragthsd = fthr; + priv->fragthsd = fthr; } - ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); @@ -356,24 +365,23 @@ static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, return ret; } -static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - adapter->fragthsd = 0; - ret = libertas_prepare_and_send_command(priv, + priv->fragthsd = 0; + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_FRAGMENTATION_THRESHOLD, NULL); if (ret) goto out; - vwrq->value = adapter->fragthsd; + vwrq->value = priv->fragthsd; vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); vwrq->fixed = 1; @@ -383,15 +391,14 @@ out: return ret; } -static int wlan_get_mode(struct net_device *dev, +static int lbs_get_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - *uwrq = adapter->mode; + *uwrq = priv->mode; lbs_deb_leave(LBS_DEB_WEXT); return 0; @@ -409,17 +416,16 @@ static int mesh_wlan_get_mode(struct net_device *dev, return 0; } -static int wlan_get_txpow(struct net_device *dev, +static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_RF_TX_POWER, CMD_ACT_TX_POWER_OPT_GET, CMD_OPTION_WAITFORRSP, 0, NULL); @@ -427,10 +433,10 @@ static int wlan_get_txpow(struct net_device *dev, if (ret) goto out; - lbs_deb_wext("tx power level %d dbm\n", adapter->txpowerlevel); - vwrq->value = adapter->txpowerlevel; + lbs_deb_wext("tx power level %d dbm\n", priv->txpowerlevel); + vwrq->value = priv->txpowerlevel; vwrq->fixed = 1; - if (adapter->radioon) { + if (priv->radioon) { vwrq->disabled = 0; vwrq->flags = IW_TXPOW_DBM; } else { @@ -442,12 +448,11 @@ out: return ret; } -static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); @@ -460,9 +465,9 @@ static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, return -EINVAL; /* Adding 1 to convert retry count to try count */ - adapter->txretrycount = vwrq->value + 1; + priv->txretrycount = vwrq->value + 1; - ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, CMD_ACT_SET, CMD_OPTION_WAITFORRSP, OID_802_11_TX_RETRYCOUNT, NULL); @@ -478,17 +483,16 @@ out: return ret; } -static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); - adapter->txretrycount = 0; - ret = libertas_prepare_and_send_command(priv, + priv->txretrycount = 0; + ret = lbs_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB, CMD_ACT_GET, CMD_OPTION_WAITFORRSP, OID_802_11_TX_RETRYCOUNT, NULL); @@ -499,7 +503,7 @@ static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, if (!vwrq->flags) { vwrq->flags = IW_RETRY_LIMIT; /* Subtract 1 to convert try count to retry count */ - vwrq->value = adapter->txretrycount - 1; + vwrq->value = priv->txretrycount - 1; } out: @@ -546,12 +550,11 @@ static inline void sort_channels(struct iw_freq *freq, int num) * @param extra A pointer to extra data buf * @return 0 --success, otherwise fail */ -static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int i, j; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct iw_range *range = (struct iw_range *)extra; struct chan_freq_power *cfp; u8 rates[MAX_RATES + 1]; @@ -567,7 +570,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, range->max_nwid = 0; memset(rates, 0, sizeof(rates)); - copy_active_data_rates(adapter, rates); + copy_active_data_rates(priv, rates); range->num_bitrates = strnlen(rates, IW_MAX_BITRATES); for (i = 0; i < range->num_bitrates; i++) range->bitrate[i] = rates[i] * 500000; @@ -576,13 +579,14 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, range->num_bitrates); range->num_frequency = 0; - if (priv->adapter->enable11d && - adapter->connect_status == LIBERTAS_CONNECTED) { + if (priv->enable11d && + (priv->connect_status == LBS_CONNECTED || + priv->mesh_connect_status == LBS_CONNECTED)) { u8 chan_no; u8 band; struct parsed_region_chan_11d *parsed_region_chan = - &adapter->parsed_region_chan; + &priv->parsed_region_chan; if (parsed_region_chan == NULL) { lbs_deb_wext("11d: parsed_region_chan is NULL\n"); @@ -598,7 +602,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("chan_no %d\n", chan_no); range->freq[range->num_frequency].i = (long)chan_no; range->freq[range->num_frequency].m = - (long)libertas_chan_2_freq(chan_no, band) * 100000; + (long)lbs_chan_2_freq(chan_no, band) * 100000; range->freq[range->num_frequency].e = 1; range->num_frequency++; } @@ -606,13 +610,12 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, } if (!flag) { for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && (j < sizeof(adapter->region_channel) - / sizeof(adapter->region_channel[0])); j++) { - cfp = adapter->region_channel[j].CFP; + && (j < ARRAY_SIZE(priv->region_channel)); j++) { + cfp = priv->region_channel[j].CFP; for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) - && adapter->region_channel[j].valid + && priv->region_channel[j].valid && cfp - && (i < adapter->region_channel[j].nrcfp); i++) { + && (i < priv->region_channel[j].nrcfp); i++) { range->freq[range->num_frequency].i = (long)cfp->channel; range->freq[range->num_frequency].m = @@ -712,7 +715,7 @@ static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); range->event_capa[1] = IW_EVENT_CAPA_K_1; - if (adapter->fwcapinfo & FW_CAPINFO_WPA) { + if (priv->fwcapinfo & FW_CAPINFO_WPA) { range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP @@ -724,22 +727,28 @@ out: return 0; } -static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); + if (!priv->ps_supported) { + if (vwrq->disabled) + return 0; + else + return -EINVAL; + } + /* PS is currently supported only in Infrastructure mode * Remove this check if it is to be supported in IBSS mode also */ if (vwrq->disabled) { - adapter->psmode = WLAN802_11POWERMODECAM; - if (adapter->psstate != PS_STATE_FULL_POWER) { - libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); + priv->psmode = LBS802_11POWERMODECAM; + if (priv->psstate != PS_STATE_FULL_POWER) { + lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP); } return 0; @@ -754,33 +763,32 @@ static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, return -EINVAL; } - if (adapter->psmode != WLAN802_11POWERMODECAM) { + if (priv->psmode != LBS802_11POWERMODECAM) { return 0; } - adapter->psmode = WLAN802_11POWERMODEMAX_PSP; + priv->psmode = LBS802_11POWERMODEMAX_PSP; - if (adapter->connect_status == LIBERTAS_CONNECTED) { - libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP); + if (priv->connect_status == LBS_CONNECTED) { + lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP); } lbs_deb_leave(LBS_DEB_WEXT); return 0; } -static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int mode; lbs_deb_enter(LBS_DEB_WEXT); - mode = adapter->psmode; + mode = priv->psmode; - if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM)) - || adapter->connect_status == LIBERTAS_DISCONNECTED) + if ((vwrq->disabled = (mode == LBS802_11POWERMODECAM)) + || priv->connect_status == LBS_DISCONNECTED) { goto out; } @@ -792,7 +800,7 @@ out: return 0; } -static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) +static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) { enum { POOR = 30, @@ -802,8 +810,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) EXCELLENT = 95, PERFECT = 100 }; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; u32 rssi_qual; u32 tx_qual; u32 quality = 0; @@ -813,22 +820,23 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) lbs_deb_enter(LBS_DEB_WEXT); - priv->wstats.status = adapter->mode; + priv->wstats.status = priv->mode; /* If we're not associated, all quality values are meaningless */ - if (adapter->connect_status != LIBERTAS_CONNECTED) + if ((priv->connect_status != LBS_CONNECTED) && + (priv->mesh_connect_status != LBS_CONNECTED)) goto out; /* Quality by RSSI */ priv->wstats.qual.level = - CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], - adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG], + priv->NF[TYPE_BEACON][TYPE_NOAVG]); - if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { + if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; } else { priv->wstats.qual.noise = - CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); + CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]); } lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level); @@ -852,7 +860,7 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) /* Quality by TX errors */ priv->wstats.discard.retries = priv->stats.tx_errors; - tx_retries = le32_to_cpu(adapter->logmsg.retry); + tx_retries = le32_to_cpu(priv->logmsg.retry); if (tx_retries > 75) tx_qual = (90 - tx_retries) * POOR / 15; @@ -868,10 +876,10 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; quality = min(quality, tx_qual); - priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable); - priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag); + priv->wstats.discard.code = le32_to_cpu(priv->logmsg.wepundecryptable); + priv->wstats.discard.fragment = le32_to_cpu(priv->logmsg.rxfrag); priv->wstats.discard.retries = tx_retries; - priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure); + priv->wstats.discard.misc = le32_to_cpu(priv->logmsg.ackfailure); /* Calculate quality */ priv->wstats.qual.qual = min_t(u8, quality, 100); @@ -879,9 +887,9 @@ static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) stats_valid = 1; /* update stats asynchronously for future calls */ - libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, + lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, 0, 0, NULL); - libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0, + lbs_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0, 0, 0, NULL); out: if (!stats_valid) { @@ -901,19 +909,18 @@ out: } -static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { int ret = -EINVAL; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct chan_freq_power *cfp; struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); + mutex_lock(&priv->lock); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; goto out; @@ -923,7 +930,7 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, if (fwrq->e == 1) { long f = fwrq->m / 100000; - cfp = find_cfp_by_band_and_freq(adapter, 0, f); + cfp = find_cfp_by_band_and_freq(priv, 0, f); if (!cfp) { lbs_deb_wext("invalid freq %ld\n", f); goto out; @@ -938,7 +945,7 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, goto out; } - cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, fwrq->m); + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m); if (!cfp) { goto out; } @@ -949,23 +956,71 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, out: if (ret == 0) { set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } else { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); + } + mutex_unlock(&priv->lock); + + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; +} + +static int lbs_mesh_set_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + struct lbs_private *priv = dev->priv; + struct chan_freq_power *cfp; + int ret = -EINVAL; + + lbs_deb_enter(LBS_DEB_WEXT); + + /* If setting by frequency, convert to a channel */ + if (fwrq->e == 1) { + long f = fwrq->m / 100000; + + cfp = find_cfp_by_band_and_freq(priv, 0, f); + if (!cfp) { + lbs_deb_wext("invalid freq %ld\n", f); + goto out; + } + + fwrq->e = 0; + fwrq->m = (int) cfp->channel; + } + + /* Setting by channel number */ + if (fwrq->m > 1000 || fwrq->e > 0) { + goto out; + } + + cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m); + if (!cfp) { + goto out; + } + + if (fwrq->m != priv->curbssparams.channel) { + lbs_deb_wext("mesh channel change forces eth disconnect\n"); + if (priv->mode == IW_MODE_INFRA) + lbs_send_deauthentication(priv); + else if (priv->mode == IW_MODE_ADHOC) + lbs_stop_adhoc_network(priv); } - mutex_unlock(&adapter->lock); + lbs_mesh_config(priv, 1, fwrq->m); + lbs_update_channel(priv); + ret = 0; +out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; - u32 new_rate; - u16 action; + struct lbs_private *priv = dev->priv; + u8 new_rate = 0; int ret = -EINVAL; u8 rates[MAX_RATES + 1]; @@ -974,15 +1029,14 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, /* Auto rate? */ if (vwrq->value == -1) { - action = CMD_ACT_SET_TX_AUTO; - adapter->auto_rate = 1; - adapter->cur_rate = 0; + priv->auto_rate = 1; + priv->cur_rate = 0; } else { if (vwrq->value % 100000) goto out; memset(rates, 0, sizeof(rates)); - copy_active_data_rates(adapter, rates); + copy_active_data_rates(priv, rates); new_rate = vwrq->value / 500000; if (!memchr(rates, new_rate, sizeof(rates))) { lbs_pr_alert("fixed data rate 0x%X out of range\n", @@ -990,31 +1044,28 @@ static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, goto out; } - adapter->cur_rate = new_rate; - action = CMD_ACT_SET_TX_FIX_RATE; - adapter->auto_rate = 0; + priv->cur_rate = new_rate; + priv->auto_rate = 0; } - ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE, - action, CMD_OPTION_WAITFORRSP, 0, NULL); + ret = lbs_set_data_rate(priv, new_rate); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->connect_status == LIBERTAS_CONNECTED) { - vwrq->value = adapter->cur_rate * 500000; + if (priv->connect_status == LBS_CONNECTED) { + vwrq->value = priv->cur_rate * 500000; - if (adapter->auto_rate) + if (priv->auto_rate) vwrq->fixed = 0; else vwrq->fixed = 1; @@ -1028,12 +1079,11 @@ static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, return 0; } -static int wlan_set_mode(struct net_device *dev, +static int lbs_set_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); @@ -1046,18 +1096,18 @@ static int wlan_set_mode(struct net_device *dev, goto out; } - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); + mutex_lock(&priv->lock); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); } else { assoc_req->mode = *uwrq; set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq); } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1074,23 +1124,22 @@ out: * @param extra A pointer to extra data buf * @return 0 --success, otherwise fail */ -static int wlan_get_encode(struct net_device *dev, +static int lbs_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, u8 * extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; lbs_deb_enter(LBS_DEB_WEXT); lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n", - dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx); + dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx); dwrq->flags = 0; /* Authentication method */ - switch (adapter->secinfo.auth_mode) { + switch (priv->secinfo.auth_mode) { case IW_AUTH_ALG_OPEN_SYSTEM: dwrq->flags = IW_ENCODE_OPEN; break; @@ -1104,41 +1153,32 @@ static int wlan_get_encode(struct net_device *dev, break; } - if ( adapter->secinfo.wep_enabled - || adapter->secinfo.WPAenabled - || adapter->secinfo.WPA2enabled) { - dwrq->flags &= ~IW_ENCODE_DISABLED; - } else { - dwrq->flags |= IW_ENCODE_DISABLED; - } - memset(extra, 0, 16); - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); /* Default to returning current transmit key */ if (index < 0) - index = adapter->wep_tx_keyidx; + index = priv->wep_tx_keyidx; - if ((adapter->wep_keys[index].len) && adapter->secinfo.wep_enabled) { - memcpy(extra, adapter->wep_keys[index].key, - adapter->wep_keys[index].len); - dwrq->length = adapter->wep_keys[index].len; + if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) { + memcpy(extra, priv->wep_keys[index].key, + priv->wep_keys[index].len); + dwrq->length = priv->wep_keys[index].len; dwrq->flags |= (index + 1); /* Return WEP enabled */ dwrq->flags &= ~IW_ENCODE_DISABLED; - } else if ((adapter->secinfo.WPAenabled) - || (adapter->secinfo.WPA2enabled)) { + } else if ((priv->secinfo.WPAenabled) + || (priv->secinfo.WPA2enabled)) { /* return WPA enabled */ dwrq->flags &= ~IW_ENCODE_DISABLED; + dwrq->flags |= IW_ENCODE_NOKEY; } else { dwrq->flags |= IW_ENCODE_DISABLED; } - mutex_unlock(&adapter->lock); - - dwrq->flags |= IW_ENCODE_NOKEY; + mutex_unlock(&priv->lock); lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n", extra[0], extra[1], extra[2], @@ -1160,7 +1200,7 @@ static int wlan_get_encode(struct net_device *dev, * @param set_tx_key Force set TX key (1 = yes, 0 = no) * @return 0 --success, otherwise fail */ -static int wlan_set_wep_key(struct assoc_request *assoc_req, +static int lbs_set_wep_key(struct assoc_request *assoc_req, const char *key_material, u16 key_length, u16 index, @@ -1278,20 +1318,19 @@ static void disable_wpa(struct assoc_request *assoc_req) * @param extra A pointer to extra data buf * @return 0 --success, otherwise fail */ -static int wlan_set_encode(struct net_device *dev, +static int lbs_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct assoc_request * assoc_req; u16 is_default = 0, index = 0, set_tx_key = 0; lbs_deb_enter(LBS_DEB_WEXT); - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); + mutex_lock(&priv->lock); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; goto out; @@ -1317,7 +1356,7 @@ static int wlan_set_encode(struct net_device *dev, if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default)) set_tx_key = 1; - ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); + ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); if (ret) goto out; @@ -1335,11 +1374,11 @@ static int wlan_set_encode(struct net_device *dev, out: if (ret == 0) { set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } else { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; @@ -1354,14 +1393,13 @@ out: * @param extra A pointer to extra data buf * @return 0 on success, otherwise failure */ -static int wlan_get_encodeext(struct net_device *dev, +static int lbs_get_encodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int ret = -EINVAL; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int index, max_key_len; @@ -1377,46 +1415,46 @@ static int wlan_get_encodeext(struct net_device *dev, goto out; index--; } else { - index = adapter->wep_tx_keyidx; + index = priv->wep_tx_keyidx; } - if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY && + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && ext->alg != IW_ENCODE_ALG_WEP) { - if (index != 0 || adapter->mode != IW_MODE_INFRA) + if (index != 0 || priv->mode != IW_MODE_INFRA) goto out; } dwrq->flags = index + 1; memset(ext, 0, sizeof(*ext)); - if ( !adapter->secinfo.wep_enabled - && !adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled) { + if ( !priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { ext->alg = IW_ENCODE_ALG_NONE; ext->key_len = 0; dwrq->flags |= IW_ENCODE_DISABLED; } else { u8 *key = NULL; - if ( adapter->secinfo.wep_enabled - && !adapter->secinfo.WPAenabled - && !adapter->secinfo.WPA2enabled) { + if ( priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { /* WEP */ ext->alg = IW_ENCODE_ALG_WEP; - ext->key_len = adapter->wep_keys[index].len; - key = &adapter->wep_keys[index].key[0]; - } else if ( !adapter->secinfo.wep_enabled - && (adapter->secinfo.WPAenabled || - adapter->secinfo.WPA2enabled)) { + ext->key_len = priv->wep_keys[index].len; + key = &priv->wep_keys[index].key[0]; + } else if ( !priv->secinfo.wep_enabled + && (priv->secinfo.WPAenabled || + priv->secinfo.WPA2enabled)) { /* WPA */ struct enc_key * pkey = NULL; - if ( adapter->wpa_mcast_key.len - && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) - pkey = &adapter->wpa_mcast_key; - else if ( adapter->wpa_unicast_key.len - && (adapter->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED)) - pkey = &adapter->wpa_unicast_key; + if ( priv->wpa_mcast_key.len + && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_mcast_key; + else if ( priv->wpa_unicast_key.len + && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_unicast_key; if (pkey) { if (pkey->type == KEY_TYPE_ID_AES) { @@ -1461,22 +1499,21 @@ out: * @param extra A pointer to extra data buf * @return 0 --success, otherwise fail */ -static int wlan_set_encodeext(struct net_device *dev, +static int lbs_set_encodeext(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int alg = ext->alg; struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); + mutex_lock(&priv->lock); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; goto out; @@ -1503,7 +1540,7 @@ static int wlan_set_encodeext(struct net_device *dev, set_tx_key = 1; /* Copy key to driver */ - ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index, + ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index, set_tx_key); if (ret) goto out; @@ -1576,31 +1613,30 @@ static int wlan_set_encodeext(struct net_device *dev, out: if (ret == 0) { - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } else { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -static int wlan_set_genie(struct net_device *dev, +static int lbs_set_genie(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int ret = 0; struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); + mutex_lock(&priv->lock); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; goto out; @@ -1616,46 +1652,45 @@ static int wlan_set_genie(struct net_device *dev, memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length); assoc_req->wpa_ie_len = dwrq->length; } else { - memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie)); + memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie)); assoc_req->wpa_ie_len = 0; } out: if (ret == 0) { set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } else { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -static int wlan_get_genie(struct net_device *dev, +static int lbs_get_genie(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); - if (adapter->wpa_ie_len == 0) { + if (priv->wpa_ie_len == 0) { dwrq->length = 0; goto out; } - if (dwrq->length < adapter->wpa_ie_len) { + if (dwrq->length < priv->wpa_ie_len) { ret = -E2BIG; goto out; } - dwrq->length = adapter->wpa_ie_len; - memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len); + dwrq->length = priv->wpa_ie_len; + memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len); out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); @@ -1663,21 +1698,20 @@ out: } -static int wlan_set_auth(struct net_device *dev, +static int lbs_set_auth(struct net_device *dev, struct iw_request_info *info, struct iw_param *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct assoc_request * assoc_req; int ret = 0; int updated = 0; lbs_deb_enter(LBS_DEB_WEXT); - mutex_lock(&adapter->lock); - assoc_req = wlan_get_association_request(adapter); + mutex_lock(&priv->lock); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; goto out; @@ -1752,44 +1786,43 @@ out: if (ret == 0) { if (updated) set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } else if (ret != -EOPNOTSUPP) { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } -static int wlan_get_auth(struct net_device *dev, +static int lbs_get_auth(struct net_device *dev, struct iw_request_info *info, struct iw_param *dwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); switch (dwrq->flags & IW_AUTH_INDEX) { case IW_AUTH_WPA_VERSION: dwrq->value = 0; - if (adapter->secinfo.WPAenabled) + if (priv->secinfo.WPAenabled) dwrq->value |= IW_AUTH_WPA_VERSION_WPA; - if (adapter->secinfo.WPA2enabled) + if (priv->secinfo.WPA2enabled) dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; if (!dwrq->value) dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; break; case IW_AUTH_80211_AUTH_ALG: - dwrq->value = adapter->secinfo.auth_mode; + dwrq->value = priv->secinfo.auth_mode; break; case IW_AUTH_WPA_ENABLED: - if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled) + if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled) dwrq->value = 1; break; @@ -1802,25 +1835,24 @@ static int wlan_get_auth(struct net_device *dev, } -static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; u16 dbm; lbs_deb_enter(LBS_DEB_WEXT); if (vwrq->disabled) { - wlan_radio_ioctl(priv, RADIO_OFF); + lbs_radio_ioctl(priv, RADIO_OFF); return 0; } - adapter->preamble = CMD_TYPE_AUTO_PREAMBLE; + priv->preamble = CMD_TYPE_AUTO_PREAMBLE; - wlan_radio_ioctl(priv, RADIO_ON); + lbs_radio_ioctl(priv, RADIO_ON); /* Userspace check in iwrange if it should use dBm or mW, * therefore this should never happen... Jean II */ @@ -1836,7 +1868,7 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("txpower set %d dbm\n", dbm); - ret = libertas_prepare_and_send_command(priv, + ret = lbs_prepare_and_send_command(priv, CMD_802_11_RF_TX_POWER, CMD_ACT_TX_POWER_OPT_SET_LOW, CMD_OPTION_WAITFORRSP, 0, (void *)&dbm); @@ -1845,11 +1877,10 @@ static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, return ret; } -static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, +static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; lbs_deb_enter(LBS_DEB_WEXT); @@ -1861,19 +1892,19 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, /* * Get the current SSID */ - if (adapter->connect_status == LIBERTAS_CONNECTED) { - memcpy(extra, adapter->curbssparams.ssid, - adapter->curbssparams.ssid_len); - extra[adapter->curbssparams.ssid_len] = '\0'; + if (priv->connect_status == LBS_CONNECTED) { + memcpy(extra, priv->curbssparams.ssid, + priv->curbssparams.ssid_len); + extra[priv->curbssparams.ssid_len] = '\0'; } else { memset(extra, 0, 32); - extra[adapter->curbssparams.ssid_len] = '\0'; + extra[priv->curbssparams.ssid_len] = '\0'; } /* * If none, we may want to get the one that was set */ - dwrq->length = adapter->curbssparams.ssid_len; + dwrq->length = priv->curbssparams.ssid_len; dwrq->flags = 1; /* active */ @@ -1881,11 +1912,10 @@ static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, return 0; } -static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; int ret = 0; u8 ssid[IW_ESSID_MAX_SIZE]; u8 ssid_len = 0; @@ -1918,10 +1948,10 @@ static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, } out: - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); if (ret == 0) { /* Get or create the current association request */ - assoc_req = wlan_get_association_request(adapter); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { ret = -ENOMEM; } else { @@ -1929,17 +1959,65 @@ out: memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE); assoc_req->ssid_len = ssid_len; set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } } /* Cancel the association request if there was an error */ if (ret != 0) { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); + } + + mutex_unlock(&priv->lock); + + lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); + return ret; +} + +static int lbs_mesh_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct lbs_private *priv = dev->priv; + + lbs_deb_enter(LBS_DEB_WEXT); + + memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len); + + dwrq->length = priv->mesh_ssid_len; + + dwrq->flags = 1; /* active */ + + lbs_deb_leave(LBS_DEB_WEXT); + return 0; +} + +static int lbs_mesh_set_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct lbs_private *priv = dev->priv; + int ret = 0; + + lbs_deb_enter(LBS_DEB_WEXT); + + /* Check the size of the string */ + if (dwrq->length > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto out; } - mutex_unlock(&adapter->lock); + if (!dwrq->flags || !dwrq->length) { + ret = -EINVAL; + goto out; + } else { + /* Specific SSID requested */ + memcpy(priv->mesh_ssid, extra, dwrq->length); + priv->mesh_ssid_len = dwrq->length; + } + lbs_mesh_config(priv, 1, priv->curbssparams.channel); + out: lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret); return ret; } @@ -1953,11 +2031,10 @@ out: * @param extra A pointer to extra data buf * @return 0 --success, otherwise fail */ -static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, +static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - wlan_private *priv = dev->priv; - wlan_adapter *adapter = priv->adapter; + struct lbs_private *priv = dev->priv; struct assoc_request * assoc_req; int ret = 0; DECLARE_MAC_BUF(mac); @@ -1969,44 +2046,38 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data)); - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); /* Get or create the current association request */ - assoc_req = wlan_get_association_request(adapter); + assoc_req = lbs_get_association_request(priv); if (!assoc_req) { - wlan_cancel_association_work(priv); + lbs_cancel_association_work(priv); ret = -ENOMEM; } else { /* Copy the BSSID to the association request */ memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN); set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags); - wlan_postpone_association_work(priv); + lbs_postpone_association_work(priv); } - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); return ret; } -void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen) +void lbs_get_fwversion(struct lbs_private *priv, char *fwversion, int maxlen) { char fwver[32]; - mutex_lock(&adapter->lock); + mutex_lock(&priv->lock); - if (adapter->fwreleasenumber[3] == 0) - sprintf(fwver, "%u.%u.%u", - adapter->fwreleasenumber[2], - adapter->fwreleasenumber[1], - adapter->fwreleasenumber[0]); - else - sprintf(fwver, "%u.%u.%u.p%u", - adapter->fwreleasenumber[2], - adapter->fwreleasenumber[1], - adapter->fwreleasenumber[0], - adapter->fwreleasenumber[3]); + sprintf(fwver, "%u.%u.%u.p%u", + priv->fwrelease >> 24 & 0xff, + priv->fwrelease >> 16 & 0xff, + priv->fwrelease >> 8 & 0xff, + priv->fwrelease & 0xff); - mutex_unlock(&adapter->lock); + mutex_unlock(&priv->lock); snprintf(fwversion, maxlen, fwver); } @@ -2014,19 +2085,19 @@ void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen) /* * iwconfig settable callbacks */ -static const iw_handler wlan_handler[] = { +static const iw_handler lbs_handler[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) lbs_get_name, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ - (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ - (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ - (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ + (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */ + (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */ + (iw_handler) lbs_set_mode, /* SIOCSIWMODE */ + (iw_handler) lbs_get_mode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ (iw_handler) NULL, /* SIOCGIWSENS */ (iw_handler) NULL, /* SIOCSIWRANGE */ - (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) lbs_get_range, /* SIOCGIWRANGE */ (iw_handler) NULL, /* SIOCSIWPRIV */ (iw_handler) NULL, /* SIOCGIWPRIV */ (iw_handler) NULL, /* SIOCSIWSTATS */ @@ -2035,56 +2106,56 @@ static const iw_handler wlan_handler[] = { iw_handler_get_spy, /* SIOCGIWSPY */ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ - (iw_handler) wlan_set_wap, /* SIOCSIWAP */ - (iw_handler) wlan_get_wap, /* SIOCGIWAP */ + (iw_handler) lbs_set_wap, /* SIOCSIWAP */ + (iw_handler) lbs_get_wap, /* SIOCGIWAP */ (iw_handler) NULL, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ - (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */ - (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */ - (iw_handler) wlan_set_essid, /* SIOCSIWESSID */ - (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ - (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ - (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */ + (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */ + (iw_handler) lbs_set_essid, /* SIOCSIWESSID */ + (iw_handler) lbs_get_essid, /* SIOCGIWESSID */ + (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */ + (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ - (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ - (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ - (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ - (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ - (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ - (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ - (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ - (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ - (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ - (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ - (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ - (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ - (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) lbs_set_rate, /* SIOCSIWRATE */ + (iw_handler) lbs_get_rate, /* SIOCGIWRATE */ + (iw_handler) lbs_set_rts, /* SIOCSIWRTS */ + (iw_handler) lbs_get_rts, /* SIOCGIWRTS */ + (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */ + (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */ + (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */ + (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */ + (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */ + (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */ + (iw_handler) lbs_set_power, /* SIOCSIWPOWER */ + (iw_handler) lbs_get_power, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ - (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ - (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ - (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ - (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */ - (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */ + (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */ + (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */ + (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */ + (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */ + (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */ + (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ }; static const iw_handler mesh_wlan_handler[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) lbs_get_name, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ - (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */ + (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */ (iw_handler) NULL, /* SIOCSIWMODE */ (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ (iw_handler) NULL, /* SIOCGIWSENS */ (iw_handler) NULL, /* SIOCSIWRANGE */ - (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) lbs_get_range, /* SIOCGIWRANGE */ (iw_handler) NULL, /* SIOCSIWPRIV */ (iw_handler) NULL, /* SIOCGIWPRIV */ (iw_handler) NULL, /* SIOCSIWSTATS */ @@ -2097,46 +2168,46 @@ static const iw_handler mesh_wlan_handler[] = { (iw_handler) NULL, /* SIOCGIWAP */ (iw_handler) NULL, /* SIOCSIWMLME */ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ - (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */ - (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */ - (iw_handler) NULL, /* SIOCSIWESSID */ - (iw_handler) NULL, /* SIOCGIWESSID */ + (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */ + (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */ + (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */ + (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */ (iw_handler) NULL, /* SIOCSIWNICKN */ (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ - (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ - (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ - (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ - (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ - (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ - (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ - (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ - (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ - (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ - (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ - (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ - (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ - (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) lbs_set_rate, /* SIOCSIWRATE */ + (iw_handler) lbs_get_rate, /* SIOCGIWRATE */ + (iw_handler) lbs_set_rts, /* SIOCSIWRTS */ + (iw_handler) lbs_get_rts, /* SIOCGIWRTS */ + (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */ + (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */ + (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */ + (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */ + (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */ + (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */ + (iw_handler) lbs_set_power, /* SIOCSIWPOWER */ + (iw_handler) lbs_get_power, /* SIOCGIWPOWER */ (iw_handler) NULL, /* -- hole -- */ (iw_handler) NULL, /* -- hole -- */ - (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ - (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ - (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ - (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ - (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */ - (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */ + (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */ + (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */ + (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */ + (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */ + (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */ + (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */ (iw_handler) NULL, /* SIOCSIWPMKSA */ }; -struct iw_handler_def libertas_handler_def = { - .num_standard = ARRAY_SIZE(wlan_handler), - .standard = (iw_handler *) wlan_handler, - .get_wireless_stats = wlan_get_wireless_stats, +struct iw_handler_def lbs_handler_def = { + .num_standard = ARRAY_SIZE(lbs_handler), + .standard = (iw_handler *) lbs_handler, + .get_wireless_stats = lbs_get_wireless_stats, }; struct iw_handler_def mesh_handler_def = { .num_standard = ARRAY_SIZE(mesh_wlan_handler), .standard = (iw_handler *) mesh_wlan_handler, - .get_wireless_stats = wlan_get_wireless_stats, + .get_wireless_stats = lbs_get_wireless_stats, }; diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h index 6aa444c7de8d..a563d9a231b6 100644 --- a/drivers/net/wireless/libertas/wext.h +++ b/drivers/net/wireless/libertas/wext.h @@ -1,11 +1,11 @@ /** * This file contains definition for IOCTL call. */ -#ifndef _WLAN_WEXT_H_ -#define _WLAN_WEXT_H_ +#ifndef _LBS_WEXT_H_ +#define _LBS_WEXT_H_ -/** wlan_ioctl_regrdwr */ -struct wlan_ioctl_regrdwr { +/** lbs_ioctl_regrdwr */ +struct lbs_ioctl_regrdwr { /** Which register to access */ u16 whichreg; /** Read or Write */ @@ -15,9 +15,9 @@ struct wlan_ioctl_regrdwr { u32 value; }; -#define WLAN_MONITOR_OFF 0 +#define LBS_MONITOR_OFF 0 -extern struct iw_handler_def libertas_handler_def; +extern struct iw_handler_def lbs_handler_def; extern struct iw_handler_def mesh_handler_def; -#endif /* _WLAN_WEXT_H_ */ +#endif diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index ca6c2da7bc5d..6d13a0d15a0c 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -270,6 +270,37 @@ static inline void set_port_type(struct orinoco_private *priv) } } +#define ORINOCO_MAX_BSS_COUNT 64 +static int orinoco_bss_data_allocate(struct orinoco_private *priv) +{ + if (priv->bss_data) + return 0; + + priv->bss_data = + kzalloc(ORINOCO_MAX_BSS_COUNT * sizeof(bss_element), GFP_KERNEL); + if (!priv->bss_data) { + printk(KERN_WARNING "Out of memory allocating beacons"); + return -ENOMEM; + } + return 0; +} + +static void orinoco_bss_data_free(struct orinoco_private *priv) +{ + kfree(priv->bss_data); + priv->bss_data = NULL; +} + +static void orinoco_bss_data_init(struct orinoco_private *priv) +{ + int i; + + INIT_LIST_HEAD(&priv->bss_free_list); + INIT_LIST_HEAD(&priv->bss_list); + for (i = 0; i < ORINOCO_MAX_BSS_COUNT; i++) + list_add_tail(&priv->bss_data[i].list, &priv->bss_free_list); +} + /********************************************************************/ /* Device methods */ /********************************************************************/ @@ -1083,6 +1114,124 @@ static void orinoco_send_wevents(struct work_struct *work) orinoco_unlock(priv, &flags); } + +static inline void orinoco_clear_scan_results(struct orinoco_private *priv, + unsigned long scan_age) +{ + bss_element *bss; + bss_element *tmp_bss; + + /* Blow away current list of scan results */ + list_for_each_entry_safe(bss, tmp_bss, &priv->bss_list, list) { + if (!scan_age || + time_after(jiffies, bss->last_scanned + scan_age)) { + list_move_tail(&bss->list, &priv->bss_free_list); + /* Don't blow away ->list, just BSS data */ + memset(bss, 0, sizeof(bss->bss)); + bss->last_scanned = 0; + } + } +} + +static int orinoco_process_scan_results(struct net_device *dev, + unsigned char *buf, + int len) +{ + struct orinoco_private *priv = netdev_priv(dev); + int offset; /* In the scan data */ + union hermes_scan_info *atom; + int atom_len; + + switch (priv->firmware_type) { + case FIRMWARE_TYPE_AGERE: + atom_len = sizeof(struct agere_scan_apinfo); + offset = 0; + break; + case FIRMWARE_TYPE_SYMBOL: + /* Lack of documentation necessitates this hack. + * Different firmwares have 68 or 76 byte long atoms. + * We try modulo first. If the length divides by both, + * we check what would be the channel in the second + * frame for a 68-byte atom. 76-byte atoms have 0 there. + * Valid channel cannot be 0. */ + if (len % 76) + atom_len = 68; + else if (len % 68) + atom_len = 76; + else if (len >= 1292 && buf[68] == 0) + atom_len = 76; + else + atom_len = 68; + offset = 0; + break; + case FIRMWARE_TYPE_INTERSIL: + offset = 4; + if (priv->has_hostscan) { + atom_len = le16_to_cpup((__le16 *)buf); + /* Sanity check for atom_len */ + if (atom_len < sizeof(struct prism2_scan_apinfo)) { + printk(KERN_ERR "%s: Invalid atom_len in scan " + "data: %d\n", dev->name, atom_len); + return -EIO; + } + } else + atom_len = offsetof(struct prism2_scan_apinfo, atim); + break; + default: + return -EOPNOTSUPP; + } + + /* Check that we got an whole number of atoms */ + if ((len - offset) % atom_len) { + printk(KERN_ERR "%s: Unexpected scan data length %d, " + "atom_len %d, offset %d\n", dev->name, len, + atom_len, offset); + return -EIO; + } + + orinoco_clear_scan_results(priv, msecs_to_jiffies(15000)); + + /* Read the entries one by one */ + for (; offset + atom_len <= len; offset += atom_len) { + int found = 0; + bss_element *bss = NULL; + + /* Get next atom */ + atom = (union hermes_scan_info *) (buf + offset); + + /* Try to update an existing bss first */ + list_for_each_entry(bss, &priv->bss_list, list) { + if (compare_ether_addr(bss->bss.a.bssid, atom->a.bssid)) + continue; + if (le16_to_cpu(bss->bss.a.essid_len) != + le16_to_cpu(atom->a.essid_len)) + continue; + if (memcmp(bss->bss.a.essid, atom->a.essid, + le16_to_cpu(atom->a.essid_len))) + continue; + found = 1; + break; + } + + /* Grab a bss off the free list */ + if (!found && !list_empty(&priv->bss_free_list)) { + bss = list_entry(priv->bss_free_list.next, + bss_element, list); + list_del(priv->bss_free_list.next); + + list_add_tail(&bss->list, &priv->bss_list); + } + + if (bss) { + /* Always update the BSS to get latest beacon info */ + memcpy(&bss->bss, atom, sizeof(bss->bss)); + bss->last_scanned = jiffies; + } + } + + return 0; +} + static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { struct orinoco_private *priv = netdev_priv(dev); @@ -1208,6 +1357,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) union iwreq_data wrqu; unsigned char *buf; + /* Scan is no longer in progress */ + priv->scan_inprogress = 0; + /* Sanity check */ if (len > 4096) { printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n", @@ -1215,15 +1367,6 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) break; } - /* We are a strict producer. If the previous scan results - * have not been consumed, we just have to drop this - * frame. We can't remove the previous results ourselves, - * that would be *very* racy... Jean II */ - if (priv->scan_result != NULL) { - printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name); - break; - } - /* Allocate buffer for results */ buf = kmalloc(len, GFP_ATOMIC); if (buf == NULL) @@ -1248,18 +1391,17 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) } #endif /* ORINOCO_DEBUG */ - /* Allow the clients to access the results */ - priv->scan_len = len; - priv->scan_result = buf; - - /* Send an empty event to user space. - * We don't send the received data on the event because - * it would require us to do complex transcoding, and - * we want to minimise the work done in the irq handler - * Use a request to extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + if (orinoco_process_scan_results(dev, buf, len) == 0) { + /* Send an empty event to user space. + * We don't send the received data on the event because + * it would require us to do complex transcoding, and + * we want to minimise the work done in the irq handler + * Use a request to extract the data - Jean II */ + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + } + kfree(buf); } break; case HERMES_INQ_SEC_STAT_AGERE: @@ -1896,8 +2038,7 @@ static void orinoco_reset(struct work_struct *work) orinoco_unlock(priv, &flags); /* Scanning support: Cleanup of driver struct */ - kfree(priv->scan_result); - priv->scan_result = NULL; + orinoco_clear_scan_results(priv, 0); priv->scan_inprogress = 0; if (priv->hard_reset) { @@ -2412,6 +2553,10 @@ struct net_device *alloc_orinocodev(int sizeof_card, else priv->card = NULL; + if (orinoco_bss_data_allocate(priv)) + goto err_out_free; + orinoco_bss_data_init(priv); + /* Setup / override net_device fields */ dev->init = orinoco_init; dev->hard_start_xmit = orinoco_xmit; @@ -2447,13 +2592,16 @@ struct net_device *alloc_orinocodev(int sizeof_card, return dev; +err_out_free: + free_netdev(dev); + return NULL; } void free_orinocodev(struct net_device *dev) { struct orinoco_private *priv = netdev_priv(dev); - kfree(priv->scan_result); + orinoco_bss_data_free(priv); free_netdev(dev); } @@ -3841,23 +3989,10 @@ static int orinoco_ioctl_setscan(struct net_device *dev, * we access scan variables in priv is critical. * o scan_inprogress : not touched by irq handler * o scan_mode : not touched by irq handler - * o scan_result : irq is strict producer, non-irq is strict - * consumer. * o scan_len : synchronised with scan_result * Before modifying anything on those variables, please think hard ! * Jean II */ - /* If there is still some left-over scan results, get rid of it */ - if (priv->scan_result != NULL) { - /* What's likely is that a client did crash or was killed - * between triggering the scan request and reading the - * results, so we need to reset everything. - * Some clients that are too slow may suffer from that... - * Jean II */ - kfree(priv->scan_result); - priv->scan_result = NULL; - } - /* Save flags */ priv->scan_mode = srq->flags; @@ -3905,169 +4040,125 @@ static int orinoco_ioctl_setscan(struct net_device *dev, return err; } +#define MAX_CUSTOM_LEN 64 + /* Translate scan data returned from the card to a card independant * format that the Wireless Tools will understand - Jean II * Return message length or -errno for fatal errors */ -static inline int orinoco_translate_scan(struct net_device *dev, - char *buffer, - char *scan, - int scan_len) +static inline char *orinoco_translate_scan(struct net_device *dev, + char *current_ev, + char *end_buf, + union hermes_scan_info *bss, + unsigned int last_scanned) { struct orinoco_private *priv = netdev_priv(dev); - int offset; /* In the scan data */ - union hermes_scan_info *atom; - int atom_len; u16 capabilities; u16 channel; struct iw_event iwe; /* Temporary buffer */ - char * current_ev = buffer; - char * end_buf = buffer + IW_SCAN_MAX_DATA; - - switch (priv->firmware_type) { - case FIRMWARE_TYPE_AGERE: - atom_len = sizeof(struct agere_scan_apinfo); - offset = 0; - break; - case FIRMWARE_TYPE_SYMBOL: - /* Lack of documentation necessitates this hack. - * Different firmwares have 68 or 76 byte long atoms. - * We try modulo first. If the length divides by both, - * we check what would be the channel in the second - * frame for a 68-byte atom. 76-byte atoms have 0 there. - * Valid channel cannot be 0. */ - if (scan_len % 76) - atom_len = 68; - else if (scan_len % 68) - atom_len = 76; - else if (scan_len >= 1292 && scan[68] == 0) - atom_len = 76; + char *p; + char custom[MAX_CUSTOM_LEN]; + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->a.bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* Other entries will be displayed in the order we give them */ + + /* Add the ESSID */ + iwe.u.data.length = le16_to_cpu(bss->a.essid_len); + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid); + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + capabilities = le16_to_cpu(bss->a.capabilities); + if (capabilities & 0x3) { + if (capabilities & 0x1) + iwe.u.mode = IW_MODE_MASTER; else - atom_len = 68; - offset = 0; - break; - case FIRMWARE_TYPE_INTERSIL: - offset = 4; - if (priv->has_hostscan) { - atom_len = le16_to_cpup((__le16 *)scan); - /* Sanity check for atom_len */ - if (atom_len < sizeof(struct prism2_scan_apinfo)) { - printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n", - dev->name, atom_len); - return -EIO; - } - } else - atom_len = offsetof(struct prism2_scan_apinfo, atim); - break; - default: - return -EOPNOTSUPP; - } - - /* Check that we got an whole number of atoms */ - if ((scan_len - offset) % atom_len) { - printk(KERN_ERR "%s: Unexpected scan data length %d, " - "atom_len %d, offset %d\n", dev->name, scan_len, - atom_len, offset); - return -EIO; - } - - /* Read the entries one by one */ - for (; offset + atom_len <= scan_len; offset += atom_len) { - /* Get next atom */ - atom = (union hermes_scan_info *) (scan + offset); - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); - - /* Other entries will be displayed in the order we give them */ - - /* Add the ESSID */ - iwe.u.data.length = le16_to_cpu(atom->a.essid_len); - if (iwe.u.data.length > 32) - iwe.u.data.length = 32; - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - capabilities = le16_to_cpu(atom->a.capabilities); - if (capabilities & 0x3) { - if (capabilities & 0x1) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); - } - - channel = atom->s.channel; - if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) { - /* Add frequency */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = channel_frequency[channel-1] * 100000; - iwe.u.freq.e = 1; - current_ev = iwe_stream_add_event(current_ev, end_buf, - &iwe, IW_EV_FREQ_LEN); - } + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN); + } + + channel = bss->s.channel; + if ((channel >= 1) && (channel <= NUM_CHANNELS)) { + /* Add frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = channel_frequency[channel-1] * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(current_ev, end_buf, + &iwe, IW_EV_FREQ_LEN); + } + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = 0x10; /* no link quality */ + iwe.u.qual.level = (__u8) le16_to_cpu(bss->a.level) - 0x95; + iwe.u.qual.noise = (__u8) le16_to_cpu(bss->a.noise) - 0x95; + /* Wireless tools prior to 27.pre22 will show link quality + * anyway, so we provide a reasonable value. */ + if (iwe.u.qual.level > iwe.u.qual.noise) + iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; + else + iwe.u.qual.qual = 0; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); - /* Add quality statistics */ - iwe.cmd = IWEVQUAL; - iwe.u.qual.updated = 0x10; /* no link quality */ - iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95; - iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95; - /* Wireless tools prior to 27.pre22 will show link quality - * anyway, so we provide a reasonable value. */ - if (iwe.u.qual.level > iwe.u.qual.noise) - iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise; - else - iwe.u.qual.qual = 0; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (capabilities & 0x10) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, bss->a.essid); + + /* Add EXTRA: Age to display seconds since last beacon/probe response + * for given network. */ + iwe.cmd = IWEVCUSTOM; + p = custom; + p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + " Last beacon: %dms ago", + jiffies_to_msecs(jiffies - last_scanned)); + iwe.u.data.length = p - custom; + if (iwe.u.data.length) + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, custom); + + /* Bit rate is not available in Lucent/Agere firmwares */ + if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { + char *current_val = current_ev + IW_EV_LCP_LEN; + int i; + int step; - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (capabilities & 0x10) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) + step = 2; else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid); - - /* Bit rate is not available in Lucent/Agere firmwares */ - if (priv->firmware_type != FIRMWARE_TYPE_AGERE) { - char * current_val = current_ev + IW_EV_LCP_LEN; - int i; - int step; - - if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) - step = 2; - else - step = 1; - - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - /* Max 10 values */ - for (i = 0; i < 10; i += step) { - /* NULL terminated */ - if (atom->p.rates[i] == 0x0) - break; - /* Bit rate given in 500 kb/s units (+ 0x80) */ - iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000); - current_val = iwe_stream_add_value(current_ev, current_val, - end_buf, &iwe, - IW_EV_PARAM_LEN); - } - /* Check if we added any event */ - if ((current_val - current_ev) > IW_EV_LCP_LEN) - current_ev = current_val; + step = 1; + + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + /* Max 10 values */ + for (i = 0; i < 10; i += step) { + /* NULL terminated */ + if (bss->p.rates[i] == 0x0) + break; + /* Bit rate given in 500 kb/s units (+ 0x80) */ + iwe.u.bitrate.value = ((bss->p.rates[i] & 0x7f) * 500000); + current_val = iwe_stream_add_value(current_ev, current_val, + end_buf, &iwe, + IW_EV_PARAM_LEN); } - - /* The other data in the scan result are not really - * interesting, so for now drop it - Jean II */ + /* Check if we added any event */ + if ((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; } - return current_ev - buffer; + + return current_ev; } /* Return results of a scan */ @@ -4077,68 +4168,45 @@ static int orinoco_ioctl_getscan(struct net_device *dev, char *extra) { struct orinoco_private *priv = netdev_priv(dev); + bss_element *bss; int err = 0; unsigned long flags; + char *current_ev = extra; if (orinoco_lock(priv, &flags) != 0) return -EBUSY; - /* If no results yet, ask to try again later */ - if (priv->scan_result == NULL) { - if (priv->scan_inprogress) - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy. - * Second, we grab some rtnetlink lock before comming - * here (in dev_ioctl()). - * Third, we generate an Wireless Event, so the - * caller can wait itself on that - Jean II */ - err = -EAGAIN; - else - /* Client error, no scan results... - * The caller need to restart the scan. */ - err = -ENODATA; - } else { - /* We have some results to push back to user space */ - - /* Translate to WE format */ - int ret = orinoco_translate_scan(dev, extra, - priv->scan_result, - priv->scan_len); - - if (ret < 0) { - err = ret; - kfree(priv->scan_result); - priv->scan_result = NULL; - } else { - srq->length = ret; + if (priv->scan_inprogress) { + /* Important note : we don't want to block the caller + * until results are ready for various reasons. + * First, managing wait queues is complex and racy. + * Second, we grab some rtnetlink lock before comming + * here (in dev_ioctl()). + * Third, we generate an Wireless Event, so the + * caller can wait itself on that - Jean II */ + err = -EAGAIN; + goto out; + } - /* Return flags */ - srq->flags = (__u16) priv->scan_mode; + list_for_each_entry(bss, &priv->bss_list, list) { + /* Translate to WE format this entry */ + current_ev = orinoco_translate_scan(dev, current_ev, + extra + srq->length, + &bss->bss, + bss->last_scanned); - /* In any case, Scan results will be cleaned up in the - * reset function and when exiting the driver. - * The person triggering the scanning may never come to - * pick the results, so we need to do it in those places. - * Jean II */ - -#ifdef SCAN_SINGLE_READ - /* If you enable this option, only one client (the first - * one) will be able to read the result (and only one - * time). If there is multiple concurent clients that - * want to read scan results, this behavior is not - * advisable - Jean II */ - kfree(priv->scan_result); - priv->scan_result = NULL; -#endif /* SCAN_SINGLE_READ */ - /* Here, if too much time has elapsed since last scan, - * we may want to clean up scan results... - Jean II */ + /* Check if there is space for one more entry */ + if ((extra + srq->length - current_ev) <= IW_EV_ADDR_LEN) { + /* Ask user space to try again with a bigger buffer */ + err = -E2BIG; + goto out; } - - /* Scan is no longer in progress */ - priv->scan_inprogress = 0; } - + + srq->length = (current_ev - extra); + srq->flags = (__u16) priv->scan_mode; + +out: orinoco_unlock(priv, &flags); return err; } diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h index 4720fb20d66d..c6b1858abde8 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco.h @@ -36,6 +36,12 @@ typedef enum { FIRMWARE_TYPE_SYMBOL } fwtype_t; +typedef struct { + union hermes_scan_info bss; + unsigned long last_scanned; + struct list_head list; +} bss_element; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ int (*hard_reset)(struct orinoco_private *); @@ -105,10 +111,12 @@ struct orinoco_private { int promiscuous, mc_count; /* Scanning support */ + struct list_head bss_list; + struct list_head bss_free_list; + bss_element *bss_data; + int scan_inprogress; /* Scan pending... */ u32 scan_mode; /* Type of scan done */ - char * scan_result; /* Result of previous scan */ - int scan_len; /* Lenght of result */ }; #ifdef ORINOCO_DEBUG diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index 1437db0cf4b2..5cda49aff3a8 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -54,7 +54,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) u32 code = le32_to_cpu(bootrec->code); switch (code) { case BR_CODE_COMPONENT_ID: - switch (be32_to_cpu(*bootrec->data)) { + switch (be32_to_cpu(*(__be32 *)bootrec->data)) { case FW_FMAC: printk(KERN_INFO "p54: FreeMAC firmware\n"); break; @@ -78,14 +78,14 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) fw_version = (unsigned char*)bootrec->data; break; case BR_CODE_DESCR: - priv->rx_start = le32_to_cpu(bootrec->data[1]); + priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]); /* FIXME add sanity checking */ - priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500; + priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500; break; case BR_CODE_EXPOSED_IF: exp_if = (struct bootrec_exp_if *) bootrec->data; for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) - if (exp_if[i].if_id == 0x1a) + if (exp_if[i].if_id == cpu_to_le16(0x1a)) priv->fw_var = le16_to_cpu(exp_if[i].variant); break; case BR_CODE_DEPENDENT_IF: @@ -314,6 +314,7 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.phymode = MODE_IEEE80211G; rx_status.antenna = hdr->antenna; rx_status.mactime = le64_to_cpu(hdr->timestamp); + rx_status.flag |= RX_FLAG_TSFT; skb_pull(skb, sizeof(*hdr)); skb_trim(skb, le16_to_cpu(hdr->len)); @@ -374,7 +375,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) pad = entry_data->align[0]; - if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) { + if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { if (!(payload->status & 0x01)) status.flags |= IEEE80211_TX_STATUS_ACK; else @@ -853,7 +854,8 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) return ret; } -static int p54_config_interface(struct ieee80211_hw *dev, int if_id, +static int p54_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c index 410b54387f23..fa527723fbe0 100644 --- a/drivers/net/wireless/p54pci.c +++ b/drivers/net/wireless/p54pci.c @@ -48,10 +48,10 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) const struct firmware *fw_entry = NULL; __le32 reg; int err; - u32 *data; + __le32 *data; u32 remains, left, device_addr; - P54P_WRITE(int_enable, 0); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); @@ -82,7 +82,7 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) p54_parse_firmware(dev, fw_entry); - data = (u32 *) fw_entry->data; + data = (__le32 *) fw_entry->data; remains = fw_entry->size; device_addr = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { @@ -141,6 +141,7 @@ static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id) static int p54p_read_eeprom(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; int err; struct p54_control_hdr *hdr; void *eeprom; @@ -164,8 +165,8 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) goto out; } - memset(priv->ring_control, 0, sizeof(*priv->ring_control)); - P54P_WRITE(ring_control_base, priv->ring_control_dma); + memset(ring_control, 0, sizeof(*ring_control)); + P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma)); P54P_READ(ring_control_base); udelay(10); @@ -194,14 +195,14 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) tx_mapping = pci_map_single(priv->pdev, (void *)hdr, EEPROM_READBACK_LEN, PCI_DMA_TODEVICE); - priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); - priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); - priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); - priv->ring_control->tx_data[0].device_addr = hdr->req_id; - priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); + ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping); + ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010); + ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping); + ring_control->tx_data[0].device_addr = hdr->req_id; + ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN); - priv->ring_control->host_idx[2] = cpu_to_le32(1); - priv->ring_control->host_idx[1] = cpu_to_le32(1); + ring_control->host_idx[2] = cpu_to_le32(1); + ring_control->host_idx[1] = cpu_to_le32(1); wmb(); mdelay(100); @@ -215,8 +216,8 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, rx_mapping, 0x2010, PCI_DMA_FROMDEVICE); - alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len); - if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 || + alen = le16_to_cpu(ring_control->rx_mgmt[0].len); + if (le32_to_cpu(ring_control->device_idx[2]) != 1 || alen < 0x10) { printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n", pci_name(priv->pdev)); @@ -228,7 +229,7 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) out: kfree(eeprom); - P54P_WRITE(int_enable, 0); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); free_irq(priv->pdev->irq, priv); @@ -239,16 +240,17 @@ static int p54p_read_eeprom(struct ieee80211_hw *dev) static void p54p_refill_rx_ring(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; u32 limit, host_idx, idx; - host_idx = le32_to_cpu(priv->ring_control->host_idx[0]); + host_idx = le32_to_cpu(ring_control->host_idx[0]); limit = host_idx; - limit -= le32_to_cpu(priv->ring_control->device_idx[0]); - limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit; + limit -= le32_to_cpu(ring_control->device_idx[0]); + limit = ARRAY_SIZE(ring_control->rx_data) - limit; - idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data); + idx = host_idx % ARRAY_SIZE(ring_control->rx_data); while (limit-- > 1) { - struct p54p_desc *desc = &priv->ring_control->rx_data[idx]; + struct p54p_desc *desc = &ring_control->rx_data[idx]; if (!desc->host_addr) { struct sk_buff *skb; @@ -270,22 +272,23 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev) idx++; host_idx++; - idx %= ARRAY_SIZE(priv->ring_control->rx_data); + idx %= ARRAY_SIZE(ring_control->rx_data); } wmb(); - priv->ring_control->host_idx[0] = cpu_to_le32(host_idx); + ring_control->host_idx[0] = cpu_to_le32(host_idx); } static irqreturn_t p54p_interrupt(int irq, void *dev_id) { struct ieee80211_hw *dev = dev_id; struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; __le32 reg; spin_lock(&priv->lock); reg = P54P_READ(int_ident); - if (unlikely(reg == 0xFFFFFFFF)) { + if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) { spin_unlock(&priv->lock); return IRQ_HANDLED; } @@ -298,12 +301,12 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) struct p54p_desc *desc; u32 idx, i; i = priv->tx_idx; - i %= ARRAY_SIZE(priv->ring_control->tx_data); - priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]); - idx %= ARRAY_SIZE(priv->ring_control->tx_data); + i %= ARRAY_SIZE(ring_control->tx_data); + priv->tx_idx = idx = le32_to_cpu(ring_control->device_idx[1]); + idx %= ARRAY_SIZE(ring_control->tx_data); while (i != idx) { - desc = &priv->ring_control->tx_data[i]; + desc = &ring_control->tx_data[i]; if (priv->tx_buf[i]) { kfree(priv->tx_buf[i]); priv->tx_buf[i] = NULL; @@ -318,17 +321,17 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) desc->flags = 0; i++; - i %= ARRAY_SIZE(priv->ring_control->tx_data); + i %= ARRAY_SIZE(ring_control->tx_data); } i = priv->rx_idx; - i %= ARRAY_SIZE(priv->ring_control->rx_data); - priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]); - idx %= ARRAY_SIZE(priv->ring_control->rx_data); + i %= ARRAY_SIZE(ring_control->rx_data); + priv->rx_idx = idx = le32_to_cpu(ring_control->device_idx[0]); + idx %= ARRAY_SIZE(ring_control->rx_data); while (i != idx) { u16 len; struct sk_buff *skb; - desc = &priv->ring_control->rx_data[i]; + desc = &ring_control->rx_data[i]; len = le16_to_cpu(desc->len); skb = priv->rx_buf[i]; @@ -347,7 +350,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) } i++; - i %= ARRAY_SIZE(priv->ring_control->rx_data); + i %= ARRAY_SIZE(ring_control->rx_data); } p54p_refill_rx_ring(dev); @@ -366,6 +369,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, size_t len, int free_on_tx) { struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; unsigned long flags; struct p54p_desc *desc; dma_addr_t mapping; @@ -373,19 +377,19 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, spin_lock_irqsave(&priv->lock, flags); - device_idx = le32_to_cpu(priv->ring_control->device_idx[1]); - idx = le32_to_cpu(priv->ring_control->host_idx[1]); - i = idx % ARRAY_SIZE(priv->ring_control->tx_data); + device_idx = le32_to_cpu(ring_control->device_idx[1]); + idx = le32_to_cpu(ring_control->host_idx[1]); + i = idx % ARRAY_SIZE(ring_control->tx_data); mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); - desc = &priv->ring_control->tx_data[i]; + desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); desc->device_addr = data->req_id; desc->len = cpu_to_le16(len); desc->flags = 0; wmb(); - priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1); + ring_control->host_idx[1] = cpu_to_le32(idx + 1); if (free_on_tx) priv->tx_buf[i] = data; @@ -397,7 +401,7 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, /* FIXME: unlikely to happen because the device usually runs out of memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2) + if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); } @@ -421,7 +425,7 @@ static int p54p_open(struct ieee80211_hw *dev) p54p_upload_firmware(dev); - P54P_WRITE(ring_control_base, priv->ring_control_dma); + P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma)); P54P_READ(ring_control_base); wmb(); udelay(10); @@ -457,10 +461,11 @@ static int p54p_open(struct ieee80211_hw *dev) static void p54p_stop(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; + struct p54p_ring_control *ring_control = priv->ring_control; unsigned int i; struct p54p_desc *desc; - P54P_WRITE(int_enable, 0); + P54P_WRITE(int_enable, cpu_to_le32(0)); P54P_READ(int_enable); udelay(10); @@ -469,7 +474,7 @@ static void p54p_stop(struct ieee80211_hw *dev) P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET)); for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) { - desc = &priv->ring_control->rx_data[i]; + desc = &ring_control->rx_data[i]; if (desc->host_addr) pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), MAX_RX_SIZE, PCI_DMA_FROMDEVICE); @@ -478,7 +483,7 @@ static void p54p_stop(struct ieee80211_hw *dev) } for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) { - desc = &priv->ring_control->tx_data[i]; + desc = &ring_control->tx_data[i]; if (desc->host_addr) pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), le16_to_cpu(desc->len), PCI_DMA_TODEVICE); @@ -487,7 +492,7 @@ static void p54p_stop(struct ieee80211_hw *dev) priv->tx_buf[i] = NULL; } - memset(priv->ring_control, 0, sizeof(*priv->ring_control)); + memset(ring_control, 0, sizeof(ring_control)); } static int __devinit p54p_probe(struct pci_dev *pdev, diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h index 52feb597dc4a..5bedd7af385d 100644 --- a/drivers/net/wireless/p54pci.h +++ b/drivers/net/wireless/p54pci.h @@ -85,8 +85,8 @@ struct p54p_ring_control { struct p54p_desc tx_mgmt[4]; } __attribute__ ((packed)); -#define P54P_READ(r) __raw_readl(&priv->map->r) -#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r) +#define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r) +#define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r) struct p54p_priv { struct p54_common common; diff --git a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h index 3fadcb6f5297..19c33d313734 100644 --- a/drivers/net/wireless/prism54/isl_38xx.h +++ b/drivers/net/wireless/prism54/isl_38xx.h @@ -138,14 +138,14 @@ isl38xx_w32_flush(void __iomem *base, u32 val, unsigned long offset) #define MAX_FRAGMENT_SIZE_RX 1600 typedef struct { - u32 address; /* physical address on host */ - u16 size; /* packet size */ - u16 flags; /* set of bit-wise flags */ + __le32 address; /* physical address on host */ + __le16 size; /* packet size */ + __le16 flags; /* set of bit-wise flags */ } isl38xx_fragment; struct isl38xx_cb { - u32 driver_curr_frag[ISL38XX_CB_QCOUNT]; - u32 device_curr_frag[ISL38XX_CB_QCOUNT]; + __le32 driver_curr_frag[ISL38XX_CB_QCOUNT]; + __le32 device_curr_frag[ISL38XX_CB_QCOUNT]; isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 6d80ca421cf0..1b595a6525f4 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -165,8 +165,7 @@ prism54_update_stats(struct work_struct *work) struct obj_bss bss, *bss2; union oid_res_t r; - if (down_interruptible(&priv->stats_sem)) - return; + down(&priv->stats_sem); /* Noise floor. * I'm not sure if the unit is dBm. @@ -1118,7 +1117,7 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &index); } else { - if (!dwrq->flags & IW_ENCODE_MODE) { + if (!(dwrq->flags & IW_ENCODE_MODE)) { /* we cannot do anything. Complain. */ return -EINVAL; } @@ -1793,8 +1792,7 @@ prism54_clear_mac(struct islpci_acl *acl) struct list_head *ptr, *next; struct mac_entry *entry; - if (down_interruptible(&acl->sem)) - return; + down(&acl->sem); if (acl->size == 0) { up(&acl->sem); @@ -2116,8 +2114,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; - if (down_interruptible(&priv->wpa_sem)) - return; + down(&priv->wpa_sem); /* try to use existing entry */ list_for_each(ptr, &priv->bss_wpa_list) { @@ -2178,8 +2175,7 @@ prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) struct islpci_bss_wpa_ie *bss = NULL; size_t len = 0; - if (down_interruptible(&priv->wpa_sem)) - return 0; + down(&priv->wpa_sem); list_for_each(ptr, &priv->bss_wpa_list) { bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); @@ -2610,7 +2606,7 @@ prism2_ioctl_set_encryption(struct net_device *dev, mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &index); } else { - if (!param->u.crypt.flags & IW_ENCODE_MODE) { + if (!(param->u.crypt.flags & IW_ENCODE_MODE)) { /* we cannot do anything. Complain. */ return -EINVAL; } diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index 219dd651dc41..dbb538ccb4ec 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -861,7 +861,7 @@ islpci_setup(struct pci_dev *pdev) init_waitqueue_head(&priv->reset_done); /* init the queue read locks, process wait counter */ - sema_init(&priv->mgmt_sem, 1); + mutex_init(&priv->mgmt_lock); priv->mgmt_received = NULL; init_waitqueue_head(&priv->mgmt_wqueue); sema_init(&priv->stats_sem, 1); diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index 736666da6c24..4e0182ce835b 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -26,6 +26,7 @@ #include <linux/wireless.h> #include <net/iw_handler.h> #include <linux/list.h> +#include <linux/mutex.h> #include "isl_38xx.h" #include "isl_oid.h" @@ -164,7 +165,7 @@ typedef struct { wait_queue_head_t reset_done; /* used by islpci_mgt_transaction */ - struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */ + struct mutex mgmt_lock; /* serialize access to mailbox and wqueue */ struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ diff --git a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c index f49eb068c7d0..762e85bef55d 100644 --- a/drivers/net/wireless/prism54/islpci_eth.c +++ b/drivers/net/wireless/prism54/islpci_eth.c @@ -471,7 +471,7 @@ islpci_eth_receive(islpci_private *priv) wmb(); /* increment the driver read pointer */ - add_le32p((u32 *) &control_block-> + add_le32p(&control_block-> driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); } diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h index 5bf820defbd0..61454d32d74d 100644 --- a/drivers/net/wireless/prism54/islpci_eth.h +++ b/drivers/net/wireless/prism54/islpci_eth.h @@ -23,15 +23,15 @@ #include "islpci_dev.h" struct rfmon_header { - u16 unk0; /* = 0x0000 */ - u16 length; /* = 0x1400 */ - u32 clock; /* 1MHz clock */ + __le16 unk0; /* = 0x0000 */ + __le16 length; /* = 0x1400 */ + __le32 clock; /* 1MHz clock */ u8 flags; u8 unk1; u8 rate; u8 unk2; - u16 freq; - u16 unk3; + __le16 freq; + __le16 unk3; u8 rssi; u8 padding[3]; } __attribute__ ((packed)); @@ -47,20 +47,20 @@ struct rx_annex_header { #define P80211CAPTURE_VERSION 0x80211001 struct avs_80211_1_header { - uint32_t version; - uint32_t length; - uint64_t mactime; - uint64_t hosttime; - uint32_t phytype; - uint32_t channel; - uint32_t datarate; - uint32_t antenna; - uint32_t priority; - uint32_t ssi_type; - int32_t ssi_signal; - int32_t ssi_noise; - uint32_t preamble; - uint32_t encoding; + __be32 version; + __be32 length; + __be64 mactime; + __be64 hosttime; + __be32 phytype; + __be32 channel; + __be32 datarate; + __be32 antenna; + __be32 priority; + __be32 ssi_type; + __be32 ssi_signal; + __be32 ssi_noise; + __be32 preamble; + __be32 encoding; }; void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c index 2246f7930b4e..f7c677e2094d 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.c +++ b/drivers/net/wireless/prism54/islpci_mgt.c @@ -460,7 +460,7 @@ islpci_mgt_transaction(struct net_device *ndev, *recvframe = NULL; - if (down_interruptible(&priv->mgmt_sem)) + if (mutex_lock_interruptible(&priv->mgmt_lock)) return -ERESTARTSYS; prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); @@ -504,7 +504,7 @@ islpci_mgt_transaction(struct net_device *ndev, /* TODO: we should reset the device here */ out: finish_wait(&priv->mgmt_wqueue, &wait); - up(&priv->mgmt_sem); + mutex_unlock(&priv->mgmt_lock); return err; } diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h index fc53b587b722..f91a88fc1e35 100644 --- a/drivers/net/wireless/prism54/islpci_mgt.h +++ b/drivers/net/wireless/prism54/islpci_mgt.h @@ -86,7 +86,7 @@ extern int pc_debug; #define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 static inline void -add_le32p(u32 * le_number, u32 add) +add_le32p(__le32 * le_number, u32 add) { *le_number = cpu_to_le32(le32_to_cpup(le_number) + add); } diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index f87fe10059ae..f3858ee36f32 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -44,6 +44,7 @@ #include <linux/ioport.h> #include <linux/skbuff.h> #include <linux/ethtool.h> +#include <linux/ieee80211.h> #include <pcmcia/cs_types.h> #include <pcmcia/cs.h> @@ -997,13 +998,13 @@ static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data, int len) { - unsigned short int proto = ((struct ethhdr *)data)->h_proto; + __be16 proto = ((struct ethhdr *)data)->h_proto; if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */ DEBUG(3,"ray_cs translate_frame DIX II\n"); /* Copy LLC header to card buffer */ memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc)); memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2); - if ((proto == 0xf380) || (proto == 0x3781)) { + if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) { /* This is the selective translation table, only 2 entries */ writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]); } @@ -1014,7 +1015,7 @@ static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigne } else { /* already 802 type, and proto is length */ DEBUG(3,"ray_cs translate_frame 802\n"); - if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */ + if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */ DEBUG(3,"ray_cs translate_frame evil IPX\n"); memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN); return 0 - ETH_HLEN; @@ -1780,19 +1781,19 @@ static struct net_device_stats *ray_get_stats(struct net_device *dev) } if (readb(&p->mrx_overflow_for_host)) { - local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow)); + local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow)); writeb(0,&p->mrx_overflow); writeb(0,&p->mrx_overflow_for_host); } if (readb(&p->mrx_checksum_error_for_host)) { - local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error)); + local->stats.rx_crc_errors += swab16(readw(&p->mrx_checksum_error)); writeb(0,&p->mrx_checksum_error); writeb(0,&p->mrx_checksum_error_for_host); } if (readb(&p->rx_hec_error_for_host)) { - local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error)); + local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error)); writeb(0,&p->rx_hec_error); writeb(0,&p->rx_hec_error_for_host); } @@ -2316,32 +2317,17 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) { snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH); - struct mac_header *pmac = (struct mac_header *)skb->data; - unsigned short type = *(unsigned short *)psnap->ethertype; - unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff; - unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff; + struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data; + __be16 type = *(__be16 *)psnap->ethertype; int delta; struct ethhdr *peth; UCHAR srcaddr[ADDRLEN]; UCHAR destaddr[ADDRLEN]; + static UCHAR org_bridge[3] = {0, 0, 0xf8}; + static UCHAR org_1042[3] = {0, 0, 0}; - if (pmac->frame_ctl_2 & FC2_FROM_DS) { - if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */ - memcpy(destaddr, pmac->addr_3, ADDRLEN); - memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN); - } else { /* AP to terminal */ - memcpy(destaddr, pmac->addr_1, ADDRLEN); - memcpy(srcaddr, pmac->addr_3, ADDRLEN); - } - } else { /* Terminal to AP */ - if (pmac->frame_ctl_2 & FC2_TO_DS) { - memcpy(destaddr, pmac->addr_3, ADDRLEN); - memcpy(srcaddr, pmac->addr_2, ADDRLEN); - } else { /* Adhoc */ - memcpy(destaddr, pmac->addr_1, ADDRLEN); - memcpy(srcaddr, pmac->addr_2, ADDRLEN); - } - } + memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN); + memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN); #ifdef PCMCIA_DEBUG if (pc_debug > 3) { @@ -2349,33 +2335,34 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) printk(KERN_DEBUG "skb->data before untranslate"); for (i=0;i<64;i++) printk("%02x ",skb->data[i]); - printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n", - type,xsap,org); + printk("\n" KERN_DEBUG "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n", + ntohs(type), + psnap->dsap, psnap->ssap, psnap->ctrl, + psnap->org[0], psnap->org[1], psnap->org[2]); printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data); } #endif - if ( xsap != SNAP_ID) { + if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) { /* not a snap type so leave it alone */ - DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff); + DEBUG(3,"ray_cs untranslate NOT SNAP %02x %02x %02x\n", + psnap->dsap, psnap->ssap, psnap->ctrl); delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH); } else { /* Its a SNAP */ - if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC */ + if (memcmp(psnap->org, org_bridge, 3) == 0) { /* EtherII and nuke the LLC */ DEBUG(3,"ray_cs untranslate Bridge encap\n"); delta = RX_MAC_HEADER_LENGTH + sizeof(struct snaphdr_t) - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); peth->h_proto = type; - } - else { - if (org == RFC1042_ENCAP) { - switch (type) { - case RAY_IPX_TYPE: - case APPLEARP_TYPE: + } else if (memcmp(psnap->org, org_1042, 3) == 0) { + switch (ntohs(type)) { + case ETH_P_IPX: + case ETH_P_AARP: DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n"); delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); @@ -2389,14 +2376,12 @@ static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len) peth->h_proto = type; break; } - } - else { + } else { printk("ray_cs untranslate very confused by packet\n"); delta = RX_MAC_HEADER_LENGTH - ETH_HLEN; peth = (struct ethhdr *)(skb->data + delta); peth->h_proto = type; - } - } + } } /* TBD reserve skb_reserve(skb, delta); */ skb_pull(skb, delta); diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 31c1dd271627..d6cba138c7ab 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -24,11 +24,6 @@ Supported chipsets: RT2460. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2400pci" - #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -54,7 +49,7 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev) { u32 reg; unsigned int i; @@ -69,7 +64,7 @@ static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev) return reg; } -static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev, +static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; @@ -95,7 +90,7 @@ static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); } -static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev, +static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u32 reg; @@ -132,7 +127,7 @@ static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev, *value = rt2x00_get_field32(reg, BBPCSR_VALUE); } -static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev, +static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; @@ -195,13 +190,13 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) #ifdef CONFIG_RT2X00_LIB_DEBUGFS #define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) -static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev, +static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 *data) { rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); } -static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev, +static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); @@ -285,7 +280,7 @@ static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); + rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, CSR14, reg); @@ -397,7 +392,7 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) } static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, - int antenna_tx, int antenna_rx) + struct antenna_setup *ant) { u8 r1; u8 r4; @@ -408,14 +403,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Configure the TX antenna. */ - switch (antenna_tx) { - case ANTENNA_SW_DIVERSITY: + switch (ant->tx) { case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); break; case ANTENNA_A: rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); break; @@ -424,14 +425,20 @@ static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Configure the RX antenna. */ - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: + switch (ant->rx) { case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); break; case ANTENNA_A: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); break; @@ -485,9 +492,7 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, rt2400pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2400pci_config_antenna(rt2x00dev, - libconf->conf->antenna_sel_tx, - libconf->conf->antenna_sel_rx); + rt2400pci_config_antenna(rt2x00dev, &libconf->ant); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) rt2400pci_config_duration(rt2x00dev, libconf); } @@ -514,18 +519,10 @@ static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); - - if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { - rt2x00_set_field32(®, LEDCSR_LINK, 1); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); - } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { - rt2x00_set_field32(®, LEDCSR_LINK, 0); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); - } else { - rt2x00_set_field32(®, LEDCSR_LINK, 1); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); - } - + rt2x00_set_field32(®, LEDCSR_LINK, + (rt2x00dev->led_mode != LED_MODE_ASUS)); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, + (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); } @@ -542,7 +539,8 @@ static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev) /* * Link tuning */ -static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev) +static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) { u32 reg; u8 bbp; @@ -551,13 +549,13 @@ static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev) * Update FCS error count from register. */ rt2x00pci_register_read(rt2x00dev, CNT0, ®); - rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); /* * Update False CCA count from register. */ rt2400pci_bbp_read(rt2x00dev, 39, &bbp); - rt2x00dev->link.false_cca = bbp; + qual->false_cca = bbp; } static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev) @@ -582,10 +580,10 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) */ rt2400pci_bbp_read(rt2x00dev, 13, ®); - if (rt2x00dev->link.false_cca > 512 && reg < 0x20) { + if (rt2x00dev->link.qual.false_cca > 512 && reg < 0x20) { rt2400pci_bbp_write(rt2x00dev, 13, ++reg); rt2x00dev->link.vgc_level = reg; - } else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) { + } else if (rt2x00dev->link.qual.false_cca < 100 && reg > 0x08) { rt2400pci_bbp_write(rt2x00dev, 13, --reg); rt2x00dev->link.vgc_level = reg; } @@ -594,65 +592,43 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Initialization functions. */ -static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev) +static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) { - struct data_ring *ring = rt2x00dev->rx; - struct data_desc *rxd; - unsigned int i; + __le32 *rxd = entry->priv; u32 word; - memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) { - rxd = ring->entry[i].priv; - - rt2x00_desc_read(rxd, 2, &word); - rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, - ring->data_size); - rt2x00_desc_write(rxd, 2, word); - - rt2x00_desc_read(rxd, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, - ring->entry[i].data_dma); - rt2x00_desc_write(rxd, 1, word); + rt2x00_desc_read(rxd, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->ring->data_size); + rt2x00_desc_write(rxd, 2, word); - rt2x00_desc_read(rxd, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); - } + rt2x00_desc_read(rxd, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma); + rt2x00_desc_write(rxd, 1, word); - rt2x00_ring_index_clear(rt2x00dev->rx); + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); } -static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) { - struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); - struct data_desc *txd; - unsigned int i; + __le32 *txd = entry->priv; u32 word; - memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) { - txd = ring->entry[i].priv; - - rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, - ring->entry[i].data_dma); - rt2x00_desc_write(txd, 1, word); - - rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, - ring->data_size); - rt2x00_desc_write(txd, 2, word); + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma); + rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(txd, 0, word); - } + rt2x00_desc_read(txd, 2, &word); + rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH, entry->ring->data_size); + rt2x00_desc_write(txd, 2, word); - rt2x00_ring_index_clear(ring); + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); } static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev) @@ -660,15 +636,6 @@ static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev) u32 reg; /* - * Initialize rings. - */ - rt2400pci_init_rxring(rt2x00dev); - rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); - rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); - rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); - rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); - - /* * Initialize registers. */ rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); @@ -1014,53 +981,37 @@ static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, + struct sk_buff *skb, struct txdata_entry_desc *desc, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, struct ieee80211_tx_control *control) { + struct skb_desc *skbdesc = get_skb_desc(skb); + __le32 *txd = skbdesc->desc; u32 word; - u32 signal = 0; - u32 service = 0; - u32 length_high = 0; - u32 length_low = 0; - - /* - * The PLCP values should be treated as if they - * were BBP values. - */ - rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal); - rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5); - rt2x00_set_field32(&signal, BBPCSR_BUSY, 1); - - rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service); - rt2x00_set_field32(&service, BBPCSR_REGNUM, 6); - rt2x00_set_field32(&service, BBPCSR_BUSY, 1); - - rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high); - rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7); - rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1); - - rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low); - rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8); - rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1); /* * Start writing the descriptor words. */ rt2x00_desc_read(txd, 2, &word); - rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, skbdesc->data_len); rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 3, &word); - rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal); - rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_REGNUM, 5); + rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL_BUSY, 1); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_REGNUM, 6); + rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE_BUSY, 1); rt2x00_desc_write(txd, 3, word); rt2x00_desc_read(txd, 4, &word); - rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low); - rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, desc->length_low); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_REGNUM, 8); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW_BUSY, 1); + rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, desc->length_high); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_REGNUM, 7); + rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH_BUSY, 1); rt2x00_desc_write(txd, 4, word); rt2x00_desc_read(txd, 0, &word); @@ -1069,7 +1020,7 @@ static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - !(control->flags & IEEE80211_TXCTL_NO_ACK)); + test_bit(ENTRY_TXD_ACK, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_RTS, @@ -1099,12 +1050,12 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - if (queue == IEEE80211_TX_QUEUE_DATA0) - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); - else if (queue == IEEE80211_TX_QUEUE_DATA1) - rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); - else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, + (queue == IEEE80211_TX_QUEUE_DATA0)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, + (queue == IEEE80211_TX_QUEUE_DATA1)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, + (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } @@ -1114,7 +1065,7 @@ static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2400pci_fill_rxdone(struct data_entry *entry, struct rxdata_entry_desc *desc) { - struct data_desc *rxd = entry->priv; + __le32 *rxd = entry->priv; u32 word0; u32 word2; @@ -1135,6 +1086,7 @@ static void rt2400pci_fill_rxdone(struct data_entry *entry, entry->ring->rt2x00dev->rssi_offset; desc->ofdm = 0; desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); } /* @@ -1144,7 +1096,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) { struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); struct data_entry *entry; - struct data_desc *txd; + __le32 *txd; u32 word; int tx_status; int retry; @@ -1164,26 +1116,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); - rt2x00lib_txdone(entry, tx_status, retry); - - /* - * Make this entry available for reuse. - */ - entry->flags = 0; - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_desc_write(txd, 0, word); - rt2x00_ring_index_done_inc(ring); + rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry); } - - /* - * If the data ring was full before the txdone handler - * we must make sure the packet queue in the mac80211 stack - * is reenabled when the txdone handler has finished. - */ - entry = ring->entry; - if (!rt2x00_ring_full(ring)) - ieee80211_wake_queue(rt2x00dev->hw, - entry->tx_status.control.queue); } static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance) @@ -1315,12 +1249,23 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Identify default antenna configuration. */ - rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00dev->default_ant.tx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); - rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00dev->default_ant.rx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); /* + * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead. + * I am not 100% sure about this, but the legacy drivers do not + * indicate antenna swapping in software is required when + * diversity is enabled. + */ + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; + + /* * Store led mode, for correct led behaviour. */ rt2x00dev->led_mode = @@ -1447,7 +1392,6 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw, struct dev_addr_list *mc_list) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -1466,21 +1410,18 @@ static void rt2400pci_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. - * - Some filters are set based on interface type. */ *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - *total_flags |= FIF_PROMISC_IN_BSS; /* * Check if there is any work left for us. */ - if (intf->filter == *total_flags) + if (rt2x00dev->packet_filter == *total_flags) return; - intf->filter = *total_flags; + rt2x00dev->packet_filter = *total_flags; /* * Start configuration steps. @@ -1583,7 +1524,7 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .configure_filter = rt2400pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2400pci_set_retry_limit, - .erp_ie_changed = rt2x00mac_erp_ie_changed, + .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2400pci_get_tsf, @@ -1597,6 +1538,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .probe_hw = rt2400pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, + .init_rxentry = rt2400pci_init_rxentry, + .init_txentry = rt2400pci_init_txentry, .set_device_state = rt2400pci_set_device_state, .rfkill_poll = rt2400pci_rfkill_poll, .link_stats = rt2400pci_link_stats, @@ -1614,7 +1557,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { }; static const struct rt2x00_ops rt2400pci_ops = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .rxd_size = RXD_DESC_SIZE, .txd_size = TXD_DESC_SIZE, .eeprom_size = EEPROM_SIZE, @@ -1642,7 +1585,7 @@ MODULE_DEVICE_TABLE(pci, rt2400pci_device_table); MODULE_LICENSE("GPL"); static struct pci_driver rt2400pci_driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .id_table = rt2400pci_device_table, .probe = rt2x00pci_probe, .remove = __devexit_p(rt2x00pci_remove), diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index ae22501f085d..369aac6d0336 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -803,8 +803,8 @@ /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 8 * sizeof(struct data_desc) ) -#define RXD_DESC_SIZE ( 8 * sizeof(struct data_desc) ) +#define TXD_DESC_SIZE ( 8 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 8 * sizeof(__le32) ) /* * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. @@ -839,11 +839,21 @@ /* * Word3 & 4: PLCP information - */ -#define TXD_W3_PLCP_SIGNAL FIELD32(0x0000ffff) -#define TXD_W3_PLCP_SERVICE FIELD32(0xffff0000) -#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x0000ffff) -#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0xffff0000) + * The PLCP values should be treated as if they were BBP values. + */ +#define TXD_W3_PLCP_SIGNAL FIELD32(0x000000ff) +#define TXD_W3_PLCP_SIGNAL_REGNUM FIELD32(0x00007f00) +#define TXD_W3_PLCP_SIGNAL_BUSY FIELD32(0x00008000) +#define TXD_W3_PLCP_SERVICE FIELD32(0x00ff0000) +#define TXD_W3_PLCP_SERVICE_REGNUM FIELD32(0x7f000000) +#define TXD_W3_PLCP_SERVICE_BUSY FIELD32(0x80000000) + +#define TXD_W4_PLCP_LENGTH_LOW FIELD32(0x000000ff) +#define TXD_W3_PLCP_LENGTH_LOW_REGNUM FIELD32(0x00007f00) +#define TXD_W3_PLCP_LENGTH_LOW_BUSY FIELD32(0x00008000) +#define TXD_W4_PLCP_LENGTH_HIGH FIELD32(0x00ff0000) +#define TXD_W3_PLCP_LENGTH_HIGH_REGNUM FIELD32(0x7f000000) +#define TXD_W3_PLCP_LENGTH_HIGH_BUSY FIELD32(0x80000000) /* * Word5 diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 702321c30164..e874fdcae204 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -24,11 +24,6 @@ Supported chipsets: RT2560. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2500pci" - #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -54,7 +49,7 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev) { u32 reg; unsigned int i; @@ -69,7 +64,7 @@ static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev) return reg; } -static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev, +static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; @@ -95,7 +90,7 @@ static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); } -static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev, +static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u32 reg; @@ -132,7 +127,7 @@ static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev, *value = rt2x00_get_field32(reg, BBPCSR_VALUE); } -static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev, +static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; @@ -195,13 +190,13 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) #ifdef CONFIG_RT2X00_LIB_DEBUGFS #define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) -static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev, +static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 *data) { rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); } -static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev, +static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); @@ -289,7 +284,7 @@ static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, CSR14, ®); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); - rt2x00_set_field32(®, CSR14_TBCN, 1); + rt2x00_set_field32(®, CSR14_TBCN, (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field32(®, CSR14_BEACON_GEN, 0); rt2x00_set_field32(®, CSR14_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, CSR14, reg); @@ -424,7 +419,7 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, } static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, const int antenna_rx) + struct antenna_setup *ant) { u32 reg; u8 r14; @@ -437,18 +432,20 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Configure the TX antenna. */ - switch (antenna_tx) { - case ANTENNA_SW_DIVERSITY: - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); - rt2x00_set_field32(®, BBPCSR1_CCK, 2); - rt2x00_set_field32(®, BBPCSR1_OFDM, 2); - break; + switch (ant->tx) { case ANTENNA_A: rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); rt2x00_set_field32(®, BBPCSR1_CCK, 0); rt2x00_set_field32(®, BBPCSR1_OFDM, 0); break; + case ANTENNA_HW_DIVERSITY: + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); rt2x00_set_field32(®, BBPCSR1_CCK, 2); @@ -459,14 +456,18 @@ static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Configure the RX antenna. */ - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); - break; + switch (ant->rx) { case ANTENNA_A: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); break; + case ANTENNA_HW_DIVERSITY: + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); break; @@ -541,9 +542,7 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, rt2500pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2500pci_config_antenna(rt2x00dev, - libconf->conf->antenna_sel_tx, - libconf->conf->antenna_sel_rx); + rt2500pci_config_antenna(rt2x00dev, &libconf->ant); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) rt2500pci_config_duration(rt2x00dev, libconf); } @@ -559,18 +558,10 @@ static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, LEDCSR_ON_PERIOD, 70); rt2x00_set_field32(®, LEDCSR_OFF_PERIOD, 30); - - if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { - rt2x00_set_field32(®, LEDCSR_LINK, 1); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 0); - } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { - rt2x00_set_field32(®, LEDCSR_LINK, 0); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); - } else { - rt2x00_set_field32(®, LEDCSR_LINK, 1); - rt2x00_set_field32(®, LEDCSR_ACTIVITY, 1); - } - + rt2x00_set_field32(®, LEDCSR_LINK, + (rt2x00dev->led_mode != LED_MODE_ASUS)); + rt2x00_set_field32(®, LEDCSR_ACTIVITY, + (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); rt2x00pci_register_write(rt2x00dev, LEDCSR, reg); } @@ -587,7 +578,8 @@ static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev) /* * Link tuning */ -static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev) +static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) { u32 reg; @@ -595,13 +587,13 @@ static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev) * Update FCS error count from register. */ rt2x00pci_register_read(rt2x00dev, CNT0, ®); - rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); + qual->rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR); /* * Update False CCA count from register. */ rt2x00pci_register_read(rt2x00dev, CNT3, ®); - rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); + qual->false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA); } static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev) @@ -679,10 +671,10 @@ dynamic_cca_tune: * R17 is inside the dynamic tuning range, * start tuning the link based on the false cca counter. */ - if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) { + if (rt2x00dev->link.qual.false_cca > 512 && r17 < 0x40) { rt2500pci_bbp_write(rt2x00dev, 17, ++r17); rt2x00dev->link.vgc_level = r17; - } else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) { + } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > 0x32) { rt2500pci_bbp_write(rt2x00dev, 17, --r17); rt2x00dev->link.vgc_level = r17; } @@ -691,55 +683,35 @@ dynamic_cca_tune: /* * Initialization functions. */ -static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev) +static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) { - struct data_ring *ring = rt2x00dev->rx; - struct data_desc *rxd; - unsigned int i; + __le32 *rxd = entry->priv; u32 word; - memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) { - rxd = ring->entry[i].priv; - - rt2x00_desc_read(rxd, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, - ring->entry[i].data_dma); - rt2x00_desc_write(rxd, 1, word); - - rt2x00_desc_read(rxd, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); - } + rt2x00_desc_read(rxd, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, entry->data_dma); + rt2x00_desc_write(rxd, 1, word); - rt2x00_ring_index_clear(rt2x00dev->rx); + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); } -static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) { - struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); - struct data_desc *txd; - unsigned int i; + __le32 *txd = entry->priv; u32 word; - memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) { - txd = ring->entry[i].priv; - - rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, - ring->entry[i].data_dma); - rt2x00_desc_write(txd, 1, word); - - rt2x00_desc_read(txd, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(txd, 0, word); - } + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, entry->data_dma); + rt2x00_desc_write(txd, 1, word); - rt2x00_ring_index_clear(ring); + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); } static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev) @@ -747,15 +719,6 @@ static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev) u32 reg; /* - * Initialize rings. - */ - rt2500pci_init_rxring(rt2x00dev); - rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); - rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); - rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON); - rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); - - /* * Initialize registers. */ rt2x00pci_register_read(rt2x00dev, TXCSR2, ®); @@ -1170,12 +1133,12 @@ static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, + struct sk_buff *skb, struct txdata_entry_desc *desc, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, struct ieee80211_tx_control *control) { + struct skb_desc *skbdesc = get_skb_desc(skb); + __le32 *txd = skbdesc->desc; u32 word; /* @@ -1206,7 +1169,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - !(control->flags & IEEE80211_TXCTL_NO_ACK)); + test_bit(ENTRY_TXD_ACK, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, @@ -1216,7 +1179,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_RETRY_MODE, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } @@ -1239,12 +1202,12 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TXCSR0, ®); - if (queue == IEEE80211_TX_QUEUE_DATA0) - rt2x00_set_field32(®, TXCSR0_KICK_PRIO, 1); - else if (queue == IEEE80211_TX_QUEUE_DATA1) - rt2x00_set_field32(®, TXCSR0_KICK_TX, 1); - else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON) - rt2x00_set_field32(®, TXCSR0_KICK_ATIM, 1); + rt2x00_set_field32(®, TXCSR0_KICK_PRIO, + (queue == IEEE80211_TX_QUEUE_DATA0)); + rt2x00_set_field32(®, TXCSR0_KICK_TX, + (queue == IEEE80211_TX_QUEUE_DATA1)); + rt2x00_set_field32(®, TXCSR0_KICK_ATIM, + (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)); rt2x00pci_register_write(rt2x00dev, TXCSR0, reg); } @@ -1254,7 +1217,7 @@ static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500pci_fill_rxdone(struct data_entry *entry, struct rxdata_entry_desc *desc) { - struct data_desc *rxd = entry->priv; + __le32 *rxd = entry->priv; u32 word0; u32 word2; @@ -1272,6 +1235,7 @@ static void rt2500pci_fill_rxdone(struct data_entry *entry, entry->ring->rt2x00dev->rssi_offset; desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); } /* @@ -1281,7 +1245,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) { struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); struct data_entry *entry; - struct data_desc *txd; + __le32 *txd; u32 word; int tx_status; int retry; @@ -1301,26 +1265,8 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue) tx_status = rt2x00_get_field32(word, TXD_W0_RESULT); retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT); - rt2x00lib_txdone(entry, tx_status, retry); - - /* - * Make this entry available for reuse. - */ - entry->flags = 0; - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_desc_write(txd, 0, word); - rt2x00_ring_index_done_inc(ring); + rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry); } - - /* - * If the data ring was full before the txdone handler - * we must make sure the packet queue in the mac80211 stack - * is reenabled when the txdone handler has finished. - */ - entry = ring->entry; - if (!rt2x00_ring_full(ring)) - ieee80211_wake_queue(rt2x00dev->hw, - entry->tx_status.control.queue); } static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance) @@ -1420,9 +1366,12 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); - rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); - rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, + ANTENNA_SW_DIVERSITY); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, + ANTENNA_SW_DIVERSITY); + rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, + LED_MODE_DEFAULT); rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); @@ -1481,9 +1430,9 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Identify default antenna configuration. */ - rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00dev->default_ant.tx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); - rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00dev->default_ant.rx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); /* @@ -1774,7 +1723,6 @@ static void rt2500pci_configure_filter(struct ieee80211_hw *hw, struct dev_addr_list *mc_list) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -1793,22 +1741,19 @@ static void rt2500pci_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. - * - Some filters are set based on interface type. */ if (mc_count) *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - *total_flags |= FIF_PROMISC_IN_BSS; /* * Check if there is any work left for us. */ - if (intf->filter == *total_flags) + if (rt2x00dev->packet_filter == *total_flags) return; - intf->filter = *total_flags; + rt2x00dev->packet_filter = *total_flags; /* * Start configuration steps. @@ -1890,7 +1835,7 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .configure_filter = rt2500pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt2500pci_set_retry_limit, - .erp_ie_changed = rt2x00mac_erp_ie_changed, + .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt2500pci_get_tsf, @@ -1904,6 +1849,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .probe_hw = rt2500pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, + .init_rxentry = rt2500pci_init_rxentry, + .init_txentry = rt2500pci_init_txentry, .set_device_state = rt2500pci_set_device_state, .rfkill_poll = rt2500pci_rfkill_poll, .link_stats = rt2500pci_link_stats, @@ -1921,7 +1868,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { }; static const struct rt2x00_ops rt2500pci_ops = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .rxd_size = RXD_DESC_SIZE, .txd_size = TXD_DESC_SIZE, .eeprom_size = EEPROM_SIZE, @@ -1949,7 +1896,7 @@ MODULE_DEVICE_TABLE(pci, rt2500pci_device_table); MODULE_LICENSE("GPL"); static struct pci_driver rt2500pci_driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .id_table = rt2500pci_device_table, .probe = rt2x00pci_probe, .remove = __devexit_p(rt2x00pci_remove), diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index d92aa56b2f4b..92ba0902d107 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -1082,8 +1082,8 @@ /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 11 * sizeof(struct data_desc) ) -#define RXD_DESC_SIZE ( 11 * sizeof(struct data_desc) ) +#define TXD_DESC_SIZE ( 11 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 11 * sizeof(__le32) ) /* * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 18b1f9145389..86ded4066f5b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -24,11 +24,6 @@ Supported chipsets: RT2570. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2500usb" - #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -52,8 +47,10 @@ * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. + * If the usb_cache_mutex is already held then the _lock variants must + * be used instead. */ -static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev, +static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u16 *value) { @@ -64,8 +61,18 @@ static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev, *value = le16_to_cpu(reg); } -static inline void rt2500usb_register_multiread(const struct rt2x00_dev - *rt2x00dev, +static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u16 *value) +{ + __le16 reg; + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(u16), REGISTER_TIMEOUT); + *value = le16_to_cpu(reg); +} + +static inline void rt2500usb_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { @@ -75,7 +82,7 @@ static inline void rt2500usb_register_multiread(const struct rt2x00_dev value, length, timeout); } -static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev, +static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u16 value) { @@ -85,8 +92,17 @@ static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev, ®, sizeof(u16), REGISTER_TIMEOUT); } -static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev - *rt2x00dev, +static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u16 value) +{ + __le16 reg = cpu_to_le16(value); + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(u16), REGISTER_TIMEOUT); +} + +static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u16 length) { @@ -96,13 +112,13 @@ static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev value, length, timeout); } -static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev) +static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev) { u16 reg; unsigned int i; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read(rt2x00dev, PHY_CSR8, ®); + rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, ®); if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) break; udelay(REGISTER_BUSY_DELAY); @@ -111,17 +127,20 @@ static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev) return reg; } -static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev, +static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u16 reg; + mutex_lock(&rt2x00dev->usb_cache_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt2500usb_bbp_check(rt2x00dev); if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->usb_cache_mutex); return; } @@ -133,14 +152,18 @@ static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); - rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + + mutex_unlock(&rt2x00dev->usb_cache_mutex); } -static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev, +static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u16 reg; + mutex_lock(&rt2x00dev->usb_cache_mutex); + /* * Wait until the BBP becomes ready. */ @@ -157,7 +180,7 @@ static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); - rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); /* * Wait until the BBP becomes ready. @@ -166,14 +189,17 @@ static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev, if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) { ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); *value = 0xff; + mutex_unlock(&rt2x00dev->usb_cache_mutex); return; } - rt2500usb_register_read(rt2x00dev, PHY_CSR7, ®); + rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); + + mutex_unlock(&rt2x00dev->usb_cache_mutex); } -static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev, +static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u16 reg; @@ -182,20 +208,23 @@ static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev, if (!word) return; + mutex_lock(&rt2x00dev->usb_cache_mutex); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read(rt2x00dev, PHY_CSR10, ®); + rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®); if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) goto rf_write; udelay(REGISTER_BUSY_DELAY); } + mutex_unlock(&rt2x00dev->usb_cache_mutex); ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); return; rf_write: reg = 0; rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); - rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); reg = 0; rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); @@ -203,20 +232,22 @@ rf_write: rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); - rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); rt2x00_rf_write(rt2x00dev, word, value); + + mutex_unlock(&rt2x00dev->usb_cache_mutex); } #ifdef CONFIG_RT2X00_LIB_DEBUGFS #define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) ) -static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev, +static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 *data) { rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data); } -static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev, +static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data); @@ -296,7 +327,8 @@ static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, rt2500usb_register_read(rt2x00dev, TXRX_CSR19, ®); rt2x00_set_field16(®, TXRX_CSR19_TSF_COUNT, 1); - rt2x00_set_field16(®, TXRX_CSR19_TBCN, 1); + rt2x00_set_field16(®, TXRX_CSR19_TBCN, + (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field16(®, TXRX_CSR19_BEACON_GEN, 0); rt2x00_set_field16(®, TXRX_CSR19_TSF_SYNC, tsf_sync); rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg); @@ -385,7 +417,7 @@ static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, } static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, const int antenna_rx) + struct antenna_setup *ant) { u8 r2; u8 r14; @@ -400,8 +432,7 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Configure the TX antenna. */ - switch (antenna_tx) { - case ANTENNA_SW_DIVERSITY: + switch (ant->tx) { case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1); rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1); @@ -412,6 +443,13 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0); rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2); rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2); @@ -422,14 +460,20 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, /* * Configure the RX antenna. */ - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: + switch (ant->rx) { case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1); break; case ANTENNA_A: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); break; @@ -487,9 +531,7 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, rt2500usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt2500usb_config_antenna(rt2x00dev, - libconf->conf->antenna_sel_tx, - libconf->conf->antenna_sel_rx); + rt2500usb_config_antenna(rt2x00dev, &libconf->ant); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) rt2500usb_config_duration(rt2x00dev, libconf); } @@ -507,18 +549,10 @@ static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev) rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg); rt2500usb_register_read(rt2x00dev, MAC_CSR20, ®); - - if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) { - rt2x00_set_field16(®, MAC_CSR20_LINK, 1); - rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 0); - } else if (rt2x00dev->led_mode == LED_MODE_ASUS) { - rt2x00_set_field16(®, MAC_CSR20_LINK, 0); - rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); - } else { - rt2x00_set_field16(®, MAC_CSR20_LINK, 1); - rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, 1); - } - + rt2x00_set_field16(®, MAC_CSR20_LINK, + (rt2x00dev->led_mode != LED_MODE_ASUS)); + rt2x00_set_field16(®, MAC_CSR20_ACTIVITY, + (rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY)); rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg); } @@ -535,7 +569,8 @@ static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev) /* * Link tuning */ -static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev) +static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) { u16 reg; @@ -543,14 +578,13 @@ static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev) * Update FCS error count from register. */ rt2500usb_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); + qual->rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ rt2500usb_register_read(rt2x00dev, STA_CSR3, ®); - rt2x00dev->link.false_cca = - rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); + qual->false_cca = rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR); } static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev) @@ -673,10 +707,10 @@ static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev) if (r17 > up_bound) { rt2500usb_bbp_write(rt2x00dev, 17, up_bound); rt2x00dev->link.vgc_level = up_bound; - } else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + } else if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { rt2500usb_bbp_write(rt2x00dev, 17, ++r17); rt2x00dev->link.vgc_level = r17; - } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { rt2500usb_bbp_write(rt2x00dev, 17, --r17); rt2x00dev->link.vgc_level = r17; } @@ -755,9 +789,11 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); - reg &= ~0x0002; + rt2x00_set_field16(®, PHY_CSR2_LNA, 0); } else { - reg = 0x3002; + reg = 0; + rt2x00_set_field16(®, PHY_CSR2_LNA, 1); + rt2x00_set_field16(®, PHY_CSR2_LNA_MODE, 3); } rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg); @@ -884,8 +920,6 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev) return -EIO; } - rt2x00usb_enable_radio(rt2x00dev); - /* * Enable LED */ @@ -988,12 +1022,12 @@ static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, + struct sk_buff *skb, struct txdata_entry_desc *desc, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, struct ieee80211_tx_control *control) { + struct skb_desc *skbdesc = get_skb_desc(skb); + __le32 *txd = skbdesc->desc; u32 word; /* @@ -1018,7 +1052,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - !(control->flags & IEEE80211_TXCTL_NO_ACK)); + test_bit(ENTRY_TXD_ACK, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, @@ -1026,7 +1060,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_NEW_SEQ, !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)); rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); rt2x00_desc_write(txd, 0, word); } @@ -1079,10 +1113,10 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct data_entry *entry, struct rxdata_entry_desc *desc) { + struct skb_desc *skbdesc = get_skb_desc(entry->skb); struct urb *urb = entry->priv; - struct data_desc *rxd = (struct data_desc *)(entry->skb->data + - (urb->actual_length - - entry->ring->desc_size)); + __le32 *rxd = (__le32 *)(entry->skb->data + + (urb->actual_length - entry->ring->desc_size)); u32 word0; u32 word1; @@ -1103,8 +1137,15 @@ static void rt2500usb_fill_rxdone(struct data_entry *entry, entry->ring->rt2x00dev->rssi_offset; desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); - return; + /* + * Set descriptor and data pointer. + */ + skbdesc->desc = entry->skb->data + desc->size; + skbdesc->desc_len = entry->ring->desc_size; + skbdesc->data = entry->skb->data; + skbdesc->data_len = desc->size; } /* @@ -1163,9 +1204,12 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0); - rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0); - rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, + ANTENNA_SW_DIVERSITY); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, + ANTENNA_SW_DIVERSITY); + rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, + LED_MODE_DEFAULT); rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522); @@ -1275,12 +1319,23 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Identify default antenna configuration. */ - rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00dev->default_ant.tx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); - rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00dev->default_ant.rx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); /* + * When the eeprom indicates SW_DIVERSITY use HW_DIVERSITY instead. + * I am not 100% sure about this, but the legacy drivers do not + * indicate antenna swapping in software is required when + * diversity is enabled. + */ + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + rt2x00dev->default_ant.tx = ANTENNA_HW_DIVERSITY; + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + rt2x00dev->default_ant.rx = ANTENNA_HW_DIVERSITY; + + /* * Store led mode, for correct led behaviour. */ rt2x00dev->led_mode = @@ -1562,7 +1617,6 @@ static void rt2500usb_configure_filter(struct ieee80211_hw *hw, struct dev_addr_list *mc_list) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; u16 reg; /* @@ -1581,22 +1635,19 @@ static void rt2500usb_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. - * - Some filters are set based on interface type. */ if (mc_count) *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - *total_flags |= FIF_PROMISC_IN_BSS; /* * Check if there is any work left for us. */ - if (intf->filter == *total_flags) + if (rt2x00dev->packet_filter == *total_flags) return; - intf->filter = *total_flags; + rt2x00dev->packet_filter = *total_flags; /* * When in atomic context, reschedule and let rt2x00lib @@ -1638,8 +1689,8 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, struct rt2x00_dev *rt2x00dev = hw->priv; struct usb_device *usb_dev = interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - struct data_ring *ring = - rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); + struct skb_desc *desc; + struct data_ring *ring; struct data_entry *beacon; struct data_entry *guardian; int pipe = usb_sndbulkpipe(usb_dev, 1); @@ -1651,6 +1702,7 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, * initialization. */ control->queue = IEEE80211_TX_QUEUE_BEACON; + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); /* * Obtain 2 entries, one for the guardian byte, @@ -1661,23 +1713,34 @@ static int rt2500usb_beacon_update(struct ieee80211_hw *hw, beacon = rt2x00_get_data_entry(ring); /* - * First we create the beacon. + * Add the descriptor in front of the skb. */ skb_push(skb, ring->desc_size); memset(skb->data, 0, ring->desc_size); - rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, - (struct ieee80211_hdr *)(skb->data + - ring->desc_size), - skb->len - ring->desc_size, control); + /* + * Fill in skb descriptor + */ + desc = get_skb_desc(skb); + desc->desc_len = ring->desc_size; + desc->data_len = skb->len - ring->desc_size; + desc->desc = skb->data; + desc->data = skb->data + ring->desc_size; + desc->ring = ring; + desc->entry = beacon; + + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); + /* + * USB devices cannot blindly pass the skb->len as the + * length of the data to usb_fill_bulk_urb. Pass the skb + * to the driver to determine what the length should be. + */ length = rt2500usb_get_tx_data_len(rt2x00dev, skb); usb_fill_bulk_urb(beacon->priv, usb_dev, pipe, skb->data, length, rt2500usb_beacondone, beacon); - beacon->skb = skb; - /* * Second we need to create the guardian byte. * We only need a single byte, so lets recycle @@ -1710,7 +1773,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2500usb_configure_filter, .get_stats = rt2x00mac_get_stats, - .erp_ie_changed = rt2x00mac_erp_ie_changed, + .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .beacon_update = rt2500usb_beacon_update, @@ -1720,6 +1783,8 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .probe_hw = rt2500usb_probe_hw, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, + .init_rxentry = rt2x00usb_init_rxentry, + .init_txentry = rt2x00usb_init_txentry, .set_device_state = rt2500usb_set_device_state, .link_stats = rt2500usb_link_stats, .reset_tuner = rt2500usb_reset_tuner, @@ -1737,7 +1802,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { }; static const struct rt2x00_ops rt2500usb_ops = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .rxd_size = RXD_DESC_SIZE, .txd_size = TXD_DESC_SIZE, .eeprom_size = EEPROM_SIZE, @@ -1809,7 +1874,7 @@ MODULE_DEVICE_TABLE(usb, rt2500usb_device_table); MODULE_LICENSE("GPL"); static struct usb_driver rt2500usb_driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .id_table = rt2500usb_device_table, .probe = rt2x00usb_probe, .disconnect = rt2x00usb_disconnect, diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index b18d56e73cf1..9e0433722e3d 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -430,10 +430,21 @@ /* * MAC configuration registers. + */ + +/* * PHY_CSR2: TX MAC configuration. - * PHY_CSR3: RX MAC configuration. + * NOTE: Both register fields are complete dummy, + * documentation and legacy drivers are unclear un + * what this register means or what fields exists. */ #define PHY_CSR2 0x04c4 +#define PHY_CSR2_LNA FIELD16(0x0002) +#define PHY_CSR2_LNA_MODE FIELD16(0x3000) + +/* + * PHY_CSR3: RX MAC configuration. + */ #define PHY_CSR3 0x04c6 /* @@ -692,8 +703,8 @@ /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 5 * sizeof(struct data_desc) ) -#define RXD_DESC_SIZE ( 4 * sizeof(struct data_desc) ) +#define TXD_DESC_SIZE ( 5 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 4 * sizeof(__le32) ) /* * TX descriptor format for TX, PRIO, ATIM and Beacon Ring. diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c8f16f161c28..05927b908f80 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -31,6 +31,8 @@ #include <linux/skbuff.h> #include <linux/workqueue.h> #include <linux/firmware.h> +#include <linux/mutex.h> +#include <linux/etherdevice.h> #include <net/mac80211.h> @@ -40,9 +42,8 @@ /* * Module information. - * DRV_NAME should be set within the individual module source files. */ -#define DRV_VERSION "2.0.10" +#define DRV_VERSION "2.0.14" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -55,7 +56,7 @@ #define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...) \ printk(__kernlvl "%s -> %s: %s - " __msg, \ - DRV_NAME, __FUNCTION__, __lvl, ##__args) + KBUILD_MODNAME, __FUNCTION__, __lvl, ##__args) #ifdef CONFIG_RT2X00_DEBUG #define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...) \ @@ -133,20 +134,26 @@ */ static inline int is_rts_frame(u16 fc) { - return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); + return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS)); } static inline int is_cts_frame(u16 fc) { - return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); + return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS)); } static inline int is_probe_resp(u16 fc) { - return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); + return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)); +} + +static inline int is_beacon(u16 fc) +{ + return (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)); } /* @@ -180,18 +187,17 @@ struct rf_channel { }; /* - * To optimize the quality of the link we need to store - * the quality of received frames and periodically - * optimize the link. + * Antenna setup values. */ -struct link { - /* - * Link tuner counter - * The number of times the link has been tuned - * since the radio has been switched on. - */ - u32 count; +struct antenna_setup { + enum antenna rx; + enum antenna tx; +}; +/* + * Quality statistics about the currently active link. + */ +struct link_qual { /* * Statistics required for Link tuning. * For the average RSSI value we use the "Walking average" approach. @@ -211,7 +217,6 @@ struct link { * the new values correctly allowing a effective link tuning. */ int avg_rssi; - int vgc_level; int false_cca; /* @@ -240,6 +245,72 @@ struct link { #define WEIGHT_RSSI 20 #define WEIGHT_RX 40 #define WEIGHT_TX 40 +}; + +/* + * Antenna settings about the currently active link. + */ +struct link_ant { + /* + * Antenna flags + */ + unsigned int flags; +#define ANTENNA_RX_DIVERSITY 0x00000001 +#define ANTENNA_TX_DIVERSITY 0x00000002 +#define ANTENNA_MODE_SAMPLE 0x00000004 + + /* + * Currently active TX/RX antenna setup. + * When software diversity is used, this will indicate + * which antenna is actually used at this time. + */ + struct antenna_setup active; + + /* + * RSSI information for the different antenna's. + * These statistics are used to determine when + * to switch antenna when using software diversity. + * + * rssi[0] -> Antenna A RSSI + * rssi[1] -> Antenna B RSSI + */ + int rssi_history[2]; + + /* + * Current RSSI average of the currently active antenna. + * Similar to the avg_rssi in the link_qual structure + * this value is updated by using the walking average. + */ + int rssi_ant; +}; + +/* + * To optimize the quality of the link we need to store + * the quality of received frames and periodically + * optimize the link. + */ +struct link { + /* + * Link tuner counter + * The number of times the link has been tuned + * since the radio has been switched on. + */ + u32 count; + + /* + * Quality measurement values. + */ + struct link_qual qual; + + /* + * TX/RX antenna setup. + */ + struct link_ant ant; + + /* + * Active VGC level + */ + int vgc_level; /* * Work structure for scheduling periodic link tuning. @@ -248,36 +319,47 @@ struct link { }; /* - * Clear all counters inside the link structure. - * This can be easiest achieved by memsetting everything - * except for the work structure at the end. + * Small helper macro to work with moving/walking averages. */ -static inline void rt2x00_clear_link(struct link *link) -{ - memset(link, 0x00, sizeof(*link) - sizeof(link->work)); - link->rx_percentage = 50; - link->tx_percentage = 50; -} +#define MOVING_AVERAGE(__avg, __val, __samples) \ + ( (((__avg) * ((__samples) - 1)) + (__val)) / (__samples) ) /* - * Update the rssi using the walking average approach. + * When we lack RSSI information return something less then -80 to + * tell the driver to tune the device to maximum sensitivity. */ -static inline void rt2x00_update_link_rssi(struct link *link, int rssi) -{ - if (!link->avg_rssi) - link->avg_rssi = rssi; - else - link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8; -} +#define DEFAULT_RSSI ( -128 ) /* - * When the avg_rssi is unset or no frames have been received), - * we need to return the default value which needs to be less - * than -80 so the device will select the maximum sensitivity. + * Link quality access functions. */ static inline int rt2x00_get_link_rssi(struct link *link) { - return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128; + if (link->qual.avg_rssi && link->qual.rx_success) + return link->qual.avg_rssi; + return DEFAULT_RSSI; +} + +static inline int rt2x00_get_link_ant_rssi(struct link *link) +{ + if (link->ant.rssi_ant && link->qual.rx_success) + return link->ant.rssi_ant; + return DEFAULT_RSSI; +} + +static inline int rt2x00_get_link_ant_rssi_history(struct link *link, + enum antenna ant) +{ + if (link->ant.rssi_history[ant - ANTENNA_A]) + return link->ant.rssi_history[ant - ANTENNA_A]; + return DEFAULT_RSSI; +} + +static inline int rt2x00_update_ant_rssi(struct link *link, int rssi) +{ + int old_rssi = link->ant.rssi_history[link->ant.active.rx - ANTENNA_A]; + link->ant.rssi_history[link->ant.active.rx - ANTENNA_A] = rssi; + return old_rssi; } /* @@ -290,14 +372,12 @@ struct interface { * to us by the 80211 stack, and is used to request * new beacons. */ - int id; + struct ieee80211_vif *id; /* * Current working type (IEEE80211_IF_TYPE_*). - * When set to INVALID_INTERFACE, no interface is configured. */ int type; -#define INVALID_INTERFACE IEEE80211_IF_TYPE_INVALID /* * MAC of the device. @@ -308,11 +388,6 @@ struct interface { * BBSID of the AP to associate with. */ u8 bssid[ETH_ALEN]; - - /* - * Store the packet filter mode for the current interface. - */ - unsigned int filter; }; static inline int is_interface_present(struct interface *intf) @@ -362,6 +437,8 @@ struct rt2x00lib_conf { struct ieee80211_conf *conf; struct rf_channel rf; + struct antenna_setup ant; + int phymode; int basic_rates; @@ -397,12 +474,21 @@ struct rt2x00lib_ops { void (*uninitialize) (struct rt2x00_dev *rt2x00dev); /* + * Ring initialization handlers + */ + void (*init_rxentry) (struct rt2x00_dev *rt2x00dev, + struct data_entry *entry); + void (*init_txentry) (struct rt2x00_dev *rt2x00dev, + struct data_entry *entry); + + /* * Radio control handlers. */ int (*set_device_state) (struct rt2x00_dev *rt2x00dev, enum dev_state state); int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev); - void (*link_stats) (struct rt2x00_dev *rt2x00dev); + void (*link_stats) (struct rt2x00_dev *rt2x00dev, + struct link_qual *qual); void (*reset_tuner) (struct rt2x00_dev *rt2x00dev); void (*link_tuner) (struct rt2x00_dev *rt2x00dev); @@ -410,10 +496,8 @@ struct rt2x00lib_ops { * TX control handlers */ void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, + struct sk_buff *skb, struct txdata_entry_desc *desc, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, struct ieee80211_tx_control *control); int (*write_tx_data) (struct rt2x00_dev *rt2x00dev, struct data_ring *ring, struct sk_buff *skb, @@ -545,7 +629,7 @@ struct rt2x00_dev { * required for deregistration of debugfs. */ #ifdef CONFIG_RT2X00_LIB_DEBUGFS - const struct rt2x00debug_intf *debugfs_intf; + struct rt2x00debug_intf *debugfs_intf; #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ /* @@ -566,6 +650,13 @@ struct rt2x00_dev { struct hw_mode_spec spec; /* + * This is the default TX/RX antenna setup as indicated + * by the device's EEPROM. When mac80211 sets its + * antenna value to 0 we should be using these values. + */ + struct antenna_setup default_ant; + + /* * Register pointers * csr_addr: Base register address. (PCI) * csr_cache: CSR cache for usb_control_msg. (USB) @@ -574,6 +665,25 @@ struct rt2x00_dev { void *csr_cache; /* + * Mutex to protect register accesses on USB devices. + * There are 2 reasons this is needed, one is to ensure + * use of the csr_cache (for USB devices) by one thread + * isn't corrupted by another thread trying to access it. + * The other is that access to BBP and RF registers + * require multiple BUS transactions and if another thread + * attempted to access one of those registers at the same + * time one of the writes could silently fail. + */ + struct mutex usb_cache_mutex; + + /* + * Current packet filter configuration for the device. + * This contains all currently active FIF_* flags send + * to us by mac80211 during configure_filter(). + */ + unsigned int packet_filter; + + /* * Interface configuration. */ struct interface interface; @@ -697,13 +807,13 @@ struct rt2x00_dev { * Generic RF access. * The RF is being accessed by word index. */ -static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev, +static inline void rt2x00_rf_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 *data) { *data = rt2x00dev->rf[word]; } -static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev, +static inline void rt2x00_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { rt2x00dev->rf[word] = data; @@ -713,19 +823,19 @@ static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev, * Generic EEPROM access. * The EEPROM is being accessed by word index. */ -static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev, +static inline void *rt2x00_eeprom_addr(struct rt2x00_dev *rt2x00dev, const unsigned int word) { return (void *)&rt2x00dev->eeprom[word]; } -static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev, +static inline void rt2x00_eeprom_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u16 *data) { *data = le16_to_cpu(rt2x00dev->eeprom[word]); } -static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev, +static inline void rt2x00_eeprom_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, u16 data) { rt2x00dev->eeprom[word] = cpu_to_le16(data); @@ -804,9 +914,7 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, * TX descriptor initializer */ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, + struct sk_buff *skb, struct ieee80211_tx_control *control); /* @@ -821,14 +929,17 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); -int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, +int rt2x00mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); int rt2x00mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); -void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, - int cts_protection, int preamble); +void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 12914cf7156c..72cfe00c1ed7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -23,11 +23,6 @@ Abstract: rt2x00 generic configuration routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00lib" - #include <linux/kernel.h> #include <linux/module.h> @@ -94,12 +89,44 @@ void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); } +void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, + enum antenna rx, enum antenna tx) +{ + struct rt2x00lib_conf libconf; + + libconf.ant.rx = rx; + libconf.ant.tx = tx; + + /* + * Antenna setup changes require the RX to be disabled, + * else the changes will be ignored by the device. + */ + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); + + /* + * Write new antenna setup to device and reset the link tuner. + * The latter is required since we need to recalibrate the + * noise-sensitivity ratio for the new setup. + */ + rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf); + rt2x00lib_reset_link_tuner(rt2x00dev); + + rt2x00dev->link.ant.active.rx = libconf.ant.rx; + rt2x00dev->link.ant.active.tx = libconf.ant.tx; + + if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); +} + void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config) { struct rt2x00lib_conf libconf; struct ieee80211_hw_mode *mode; struct ieee80211_rate *rate; + struct antenna_setup *default_ant = &rt2x00dev->default_ant; + struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; int flags = 0; int short_slot_time; @@ -122,7 +149,39 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, flags |= CONFIG_UPDATE_CHANNEL; if (rt2x00dev->tx_power != conf->power_level) flags |= CONFIG_UPDATE_TXPOWER; - if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx) + + /* + * Determining changes in the antenna setups request several checks: + * antenna_sel_{r,t}x = 0 + * -> Does active_{r,t}x match default_{r,t}x + * -> Is default_{r,t}x SW_DIVERSITY + * antenna_sel_{r,t}x = 1/2 + * -> Does active_{r,t}x match antenna_sel_{r,t}x + * The reason for not updating the antenna while SW diversity + * should be used is simple: Software diversity means that + * we should switch between the antenna's based on the + * quality. This means that the current antenna is good enough + * to work with untill the link tuner decides that an antenna + * switch should be performed. + */ + if (!conf->antenna_sel_rx && + default_ant->rx != ANTENNA_SW_DIVERSITY && + default_ant->rx != active_ant->rx) + flags |= CONFIG_UPDATE_ANTENNA; + else if (conf->antenna_sel_rx && + conf->antenna_sel_rx != active_ant->rx) + flags |= CONFIG_UPDATE_ANTENNA; + else if (active_ant->rx == ANTENNA_SW_DIVERSITY) + flags |= CONFIG_UPDATE_ANTENNA; + + if (!conf->antenna_sel_tx && + default_ant->tx != ANTENNA_SW_DIVERSITY && + default_ant->tx != active_ant->tx) + flags |= CONFIG_UPDATE_ANTENNA; + else if (conf->antenna_sel_tx && + conf->antenna_sel_tx != active_ant->tx) + flags |= CONFIG_UPDATE_ANTENNA; + else if (active_ant->tx == ANTENNA_SW_DIVERSITY) flags |= CONFIG_UPDATE_ANTENNA; /* @@ -171,6 +230,22 @@ config: sizeof(libconf.rf)); } + if (flags & CONFIG_UPDATE_ANTENNA) { + if (conf->antenna_sel_rx) + libconf.ant.rx = conf->antenna_sel_rx; + else if (default_ant->rx != ANTENNA_SW_DIVERSITY) + libconf.ant.rx = default_ant->rx; + else if (active_ant->rx == ANTENNA_SW_DIVERSITY) + libconf.ant.rx = ANTENNA_B; + + if (conf->antenna_sel_tx) + libconf.ant.tx = conf->antenna_sel_tx; + else if (default_ant->tx != ANTENNA_SW_DIVERSITY) + libconf.ant.tx = default_ant->tx; + else if (active_ant->tx == ANTENNA_SW_DIVERSITY) + libconf.ant.tx = ANTENNA_B; + } + if (flags & CONFIG_UPDATE_SLOT_TIME) { short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; @@ -196,10 +271,17 @@ config: if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) rt2x00lib_reset_link_tuner(rt2x00dev); - rt2x00dev->curr_hwmode = libconf.phymode; - rt2x00dev->rx_status.phymode = conf->phymode; + if (flags & CONFIG_UPDATE_PHYMODE) { + rt2x00dev->curr_hwmode = libconf.phymode; + rt2x00dev->rx_status.phymode = conf->phymode; + } + rt2x00dev->rx_status.freq = conf->freq; rt2x00dev->rx_status.channel = conf->channel; rt2x00dev->tx_power = conf->power_level; - rt2x00dev->rx_status.antenna = conf->antenna_sel_rx; + + if (flags & CONFIG_UPDATE_ANTENNA) { + rt2x00dev->link.ant.active.rx = libconf.ant.rx; + rt2x00dev->link.ant.active.tx = libconf.ant.tx; + } } diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 9275d6f9517e..b44a9f4b9b7f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -23,18 +23,15 @@ Abstract: rt2x00 debugfs specific routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00lib" - #include <linux/debugfs.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/poll.h> #include <linux/uaccess.h> #include "rt2x00.h" #include "rt2x00lib.h" +#include "rt2x00dump.h" #define PRINT_LINE_LEN_MAX 32 @@ -55,18 +52,22 @@ struct rt2x00debug_intf { /* * Debugfs entries for: * - driver folder - * - driver file - * - chipset file - * - device flags file - * - register offset/value files - * - eeprom offset/value files - * - bbp offset/value files - * - rf offset/value files + * - driver file + * - chipset file + * - device flags file + * - register folder + * - csr offset/value files + * - eeprom offset/value files + * - bbp offset/value files + * - rf offset/value files + * - frame dump folder + * - frame dump file */ struct dentry *driver_folder; struct dentry *driver_entry; struct dentry *chipset_entry; struct dentry *dev_flags; + struct dentry *register_folder; struct dentry *csr_off_entry; struct dentry *csr_val_entry; struct dentry *eeprom_off_entry; @@ -75,6 +76,24 @@ struct rt2x00debug_intf { struct dentry *bbp_val_entry; struct dentry *rf_off_entry; struct dentry *rf_val_entry; + struct dentry *frame_folder; + struct dentry *frame_dump_entry; + + /* + * The frame dump file only allows a single reader, + * so we need to store the current state here. + */ + unsigned long frame_dump_flags; +#define FRAME_DUMP_FILE_OPEN 1 + + /* + * We queue each frame before dumping it to the user, + * per read command we will pass a single skb structure + * so we should be prepared to queue multiple sk buffers + * before sending it to userspace. + */ + struct sk_buff_head frame_dump_skbqueue; + wait_queue_head_t frame_dump_waitqueue; /* * Driver and chipset files will use a data buffer @@ -93,6 +112,59 @@ struct rt2x00debug_intf { unsigned int offset_rf; }; +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb) +{ + struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; + struct skb_desc *desc = get_skb_desc(skb); + struct sk_buff *skbcopy; + struct rt2x00dump_hdr *dump_hdr; + struct timeval timestamp; + + do_gettimeofday(×tamp); + + if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) + return; + + if (skb_queue_len(&intf->frame_dump_skbqueue) > 20) { + DEBUG(rt2x00dev, "txrx dump queue length exceeded.\n"); + return; + } + + skbcopy = alloc_skb(sizeof(*dump_hdr) + desc->desc_len + desc->data_len, + GFP_ATOMIC); + if (!skbcopy) { + DEBUG(rt2x00dev, "Failed to copy skb for dump.\n"); + return; + } + + dump_hdr = (struct rt2x00dump_hdr *)skb_put(skbcopy, sizeof(*dump_hdr)); + dump_hdr->version = cpu_to_le32(DUMP_HEADER_VERSION); + dump_hdr->header_length = cpu_to_le32(sizeof(*dump_hdr)); + dump_hdr->desc_length = cpu_to_le32(desc->desc_len); + dump_hdr->data_length = cpu_to_le32(desc->data_len); + dump_hdr->chip_rt = cpu_to_le16(rt2x00dev->chip.rt); + dump_hdr->chip_rf = cpu_to_le16(rt2x00dev->chip.rf); + dump_hdr->chip_rev = cpu_to_le32(rt2x00dev->chip.rev); + dump_hdr->type = cpu_to_le16(desc->frame_type); + dump_hdr->ring_index = desc->ring->queue_idx; + dump_hdr->entry_index = desc->entry->entry_idx; + dump_hdr->timestamp_sec = cpu_to_le32(timestamp.tv_sec); + dump_hdr->timestamp_usec = cpu_to_le32(timestamp.tv_usec); + + memcpy(skb_put(skbcopy, desc->desc_len), desc->desc, desc->desc_len); + memcpy(skb_put(skbcopy, desc->data_len), desc->data, desc->data_len); + + skb_queue_tail(&intf->frame_dump_skbqueue, skbcopy); + wake_up_interruptible(&intf->frame_dump_waitqueue); + + /* + * Verify that the file has not been closed while we were working. + */ + if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) + skb_queue_purge(&intf->frame_dump_skbqueue); +} + static int rt2x00debug_file_open(struct inode *inode, struct file *file) { struct rt2x00debug_intf *intf = inode->i_private; @@ -114,13 +186,96 @@ static int rt2x00debug_file_release(struct inode *inode, struct file *file) return 0; } +static int rt2x00debug_open_ring_dump(struct inode *inode, struct file *file) +{ + struct rt2x00debug_intf *intf = inode->i_private; + int retval; + + retval = rt2x00debug_file_open(inode, file); + if (retval) + return retval; + + if (test_and_set_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags)) { + rt2x00debug_file_release(inode, file); + return -EBUSY; + } + + return 0; +} + +static int rt2x00debug_release_ring_dump(struct inode *inode, struct file *file) +{ + struct rt2x00debug_intf *intf = inode->i_private; + + skb_queue_purge(&intf->frame_dump_skbqueue); + + clear_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags); + + return rt2x00debug_file_release(inode, file); +} + +static ssize_t rt2x00debug_read_ring_dump(struct file *file, + char __user *buf, + size_t length, + loff_t *offset) +{ + struct rt2x00debug_intf *intf = file->private_data; + struct sk_buff *skb; + size_t status; + int retval; + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + retval = + wait_event_interruptible(intf->frame_dump_waitqueue, + (skb = + skb_dequeue(&intf->frame_dump_skbqueue))); + if (retval) + return retval; + + status = min((size_t)skb->len, length); + if (copy_to_user(buf, skb->data, status)) { + status = -EFAULT; + goto exit; + } + + *offset += status; + +exit: + kfree_skb(skb); + + return status; +} + +static unsigned int rt2x00debug_poll_ring_dump(struct file *file, + poll_table *wait) +{ + struct rt2x00debug_intf *intf = file->private_data; + + poll_wait(file, &intf->frame_dump_waitqueue, wait); + + if (!skb_queue_empty(&intf->frame_dump_skbqueue)) + return POLLOUT | POLLWRNORM; + + return 0; +} + +static const struct file_operations rt2x00debug_fop_ring_dump = { + .owner = THIS_MODULE, + .read = rt2x00debug_read_ring_dump, + .poll = rt2x00debug_poll_ring_dump, + .open = rt2x00debug_open_ring_dump, + .release = rt2x00debug_release_ring_dump, +}; + #define RT2X00DEBUGFS_OPS_READ(__name, __format, __type) \ static ssize_t rt2x00debug_read_##__name(struct file *file, \ char __user *buf, \ size_t length, \ loff_t *offset) \ { \ - struct rt2x00debug_intf *intf = file->private_data; \ + struct rt2x00debug_intf *intf = file->private_data; \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ @@ -150,7 +305,7 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ size_t length, \ loff_t *offset) \ { \ - struct rt2x00debug_intf *intf = file->private_data; \ + struct rt2x00debug_intf *intf = file->private_data; \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ @@ -254,11 +409,15 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, const struct rt2x00debug *debug = intf->debug; char *data; - data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL); + data = kzalloc(8 * PRINT_LINE_LEN_MAX, GFP_KERNEL); if (!data) return NULL; blob->data = data; + data += sprintf(data, "rt chip: %04x\n", intf->rt2x00dev->chip.rt); + data += sprintf(data, "rf chip: %04x\n", intf->rt2x00dev->chip.rf); + data += sprintf(data, "revision:%08x\n", intf->rt2x00dev->chip.rev); + data += sprintf(data, "\n"); data += sprintf(data, "csr length: %d\n", debug->csr.word_count); data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count); data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count); @@ -306,12 +465,17 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->dev_flags)) goto exit; -#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name) \ + intf->register_folder = + debugfs_create_dir("register", intf->driver_folder); + if (IS_ERR(intf->register_folder)) + goto exit; + +#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ ({ \ (__intf)->__name##_off_entry = \ debugfs_create_u32(__stringify(__name) "_offset", \ S_IRUGO | S_IWUSR, \ - (__intf)->driver_folder, \ + (__intf)->register_folder, \ &(__intf)->offset_##__name); \ if (IS_ERR((__intf)->__name##_off_entry)) \ goto exit; \ @@ -319,18 +483,32 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) (__intf)->__name##_val_entry = \ debugfs_create_file(__stringify(__name) "_value", \ S_IRUGO | S_IWUSR, \ - (__intf)->driver_folder, \ + (__intf)->register_folder, \ (__intf), &rt2x00debug_fop_##__name);\ if (IS_ERR((__intf)->__name##_val_entry)) \ goto exit; \ }) - RT2X00DEBUGFS_CREATE_ENTRY(intf, csr); - RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom); - RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp); - RT2X00DEBUGFS_CREATE_ENTRY(intf, rf); + RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr); + RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, eeprom); + RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, bbp); + RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, rf); -#undef RT2X00DEBUGFS_CREATE_ENTRY +#undef RT2X00DEBUGFS_CREATE_REGISTER_ENTRY + + intf->frame_folder = + debugfs_create_dir("frame", intf->driver_folder); + if (IS_ERR(intf->frame_folder)) + goto exit; + + intf->frame_dump_entry = + debugfs_create_file("dump", S_IRUGO, intf->frame_folder, + intf, &rt2x00debug_fop_ring_dump); + if (IS_ERR(intf->frame_dump_entry)) + goto exit; + + skb_queue_head_init(&intf->frame_dump_skbqueue); + init_waitqueue_head(&intf->frame_dump_waitqueue); return; @@ -343,11 +521,15 @@ exit: void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) { - const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; + struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf; if (unlikely(!intf)) return; + skb_queue_purge(&intf->frame_dump_skbqueue); + + debugfs_remove(intf->frame_dump_entry); + debugfs_remove(intf->frame_folder); debugfs_remove(intf->rf_val_entry); debugfs_remove(intf->rf_off_entry); debugfs_remove(intf->bbp_val_entry); @@ -356,6 +538,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) debugfs_remove(intf->eeprom_off_entry); debugfs_remove(intf->csr_val_entry); debugfs_remove(intf->csr_off_entry); + debugfs_remove(intf->register_folder); debugfs_remove(intf->dev_flags); debugfs_remove(intf->chipset_entry); debugfs_remove(intf->driver_entry); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index 860e8fa3a0da..d37efbd09c41 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -30,9 +30,9 @@ struct rt2x00_dev; #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ struct reg##__name { \ - void (*read)(const struct rt2x00_dev *rt2x00dev, \ + void (*read)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type *data); \ - void (*write)(const struct rt2x00_dev *rt2x00dev, \ + void (*write)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type data); \ \ unsigned int word_size; \ diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index ff399f8083e9..c4be2ac4d7a4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -23,16 +23,12 @@ Abstract: rt2x00 generic device routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00lib" - #include <linux/kernel.h> #include <linux/module.h> #include "rt2x00.h" #include "rt2x00lib.h" +#include "rt2x00dump.h" /* * Ring handler. @@ -67,7 +63,21 @@ EXPORT_SYMBOL_GPL(rt2x00lib_get_ring); */ static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev) { - rt2x00_clear_link(&rt2x00dev->link); + rt2x00dev->link.count = 0; + rt2x00dev->link.vgc_level = 0; + + memset(&rt2x00dev->link.qual, 0, sizeof(rt2x00dev->link.qual)); + + /* + * The RX and TX percentage should start at 50% + * this will assure we will get at least get some + * decent value when the link tuner starts. + * The value will be dropped and overwritten with + * the correct (measured )value anyway during the + * first run of the link tuner. + */ + rt2x00dev->link.qual.rx_percentage = 50; + rt2x00dev->link.qual.tx_percentage = 50; /* * Reset the link tuner. @@ -93,6 +103,46 @@ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev) } /* + * Ring initialization + */ +static void rt2x00lib_init_rxrings(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring = rt2x00dev->rx; + unsigned int i; + + if (!rt2x00dev->ops->lib->init_rxentry) + return; + + if (ring->data_addr) + memset(ring->data_addr, 0, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) + rt2x00dev->ops->lib->init_rxentry(rt2x00dev, &ring->entry[i]); + + rt2x00_ring_index_clear(ring); +} + +static void rt2x00lib_init_txrings(struct rt2x00_dev *rt2x00dev) +{ + struct data_ring *ring; + unsigned int i; + + if (!rt2x00dev->ops->lib->init_txentry) + return; + + txringall_for_each(rt2x00dev, ring) { + if (ring->data_addr) + memset(ring->data_addr, 0, rt2x00_get_ring_size(ring)); + + for (i = 0; i < ring->stats.limit; i++) + rt2x00dev->ops->lib->init_txentry(rt2x00dev, + &ring->entry[i]); + + rt2x00_ring_index_clear(ring); + } +} + +/* * Radio control handlers. */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -108,6 +158,12 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) return 0; /* + * Initialize all data rings. + */ + rt2x00lib_init_rxrings(rt2x00dev); + rt2x00lib_init_txrings(rt2x00dev); + + /* * Enable radio. */ status = rt2x00dev->ops->lib->set_device_state(rt2x00dev, @@ -179,26 +235,153 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) rt2x00lib_start_link_tuner(rt2x00dev); } -static void rt2x00lib_precalculate_link_signal(struct link *link) +static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) { - if (link->rx_failed || link->rx_success) - link->rx_percentage = - (link->rx_success * 100) / - (link->rx_failed + link->rx_success); + enum antenna rx = rt2x00dev->link.ant.active.rx; + enum antenna tx = rt2x00dev->link.ant.active.tx; + int sample_a = + rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A); + int sample_b = + rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B); + + /* + * We are done sampling. Now we should evaluate the results. + */ + rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE; + + /* + * During the last period we have sampled the RSSI + * from both antenna's. It now is time to determine + * which antenna demonstrated the best performance. + * When we are already on the antenna with the best + * performance, then there really is nothing for us + * left to do. + */ + if (sample_a == sample_b) + return; + + if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) { + if (sample_a > sample_b && rx == ANTENNA_B) + rx = ANTENNA_A; + else if (rx == ANTENNA_A) + rx = ANTENNA_B; + } + + if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) { + if (sample_a > sample_b && tx == ANTENNA_B) + tx = ANTENNA_A; + else if (tx == ANTENNA_A) + tx = ANTENNA_B; + } + + rt2x00lib_config_antenna(rt2x00dev, rx, tx); +} + +static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) +{ + enum antenna rx = rt2x00dev->link.ant.active.rx; + enum antenna tx = rt2x00dev->link.ant.active.tx; + int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link); + int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr); + + /* + * Legacy driver indicates that we should swap antenna's + * when the difference in RSSI is greater that 5. This + * also should be done when the RSSI was actually better + * then the previous sample. + * When the difference exceeds the threshold we should + * sample the rssi from the other antenna to make a valid + * comparison between the 2 antennas. + */ + if ((rssi_curr - rssi_old) > -5 || (rssi_curr - rssi_old) < 5) + return; + + rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE; + + if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) + rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + + if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) + tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + + rt2x00lib_config_antenna(rt2x00dev, rx, tx); +} + +static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) +{ + /* + * Determine if software diversity is enabled for + * either the TX or RX antenna (or both). + * Always perform this check since within the link + * tuner interval the configuration might have changed. + */ + rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY; + rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY; + + if (rt2x00dev->hw->conf.antenna_sel_rx == 0 && + rt2x00dev->default_ant.rx != ANTENNA_SW_DIVERSITY) + rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY; + if (rt2x00dev->hw->conf.antenna_sel_tx == 0 && + rt2x00dev->default_ant.tx != ANTENNA_SW_DIVERSITY) + rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY; + + if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) && + !(rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY)) { + rt2x00dev->link.ant.flags &= ~ANTENNA_MODE_SAMPLE; + return; + } + + /* + * If we have only sampled the data over the last period + * we should now harvest the data. Otherwise just evaluate + * the data. The latter should only be performed once + * every 2 seconds. + */ + if (rt2x00dev->link.ant.flags & ANTENNA_MODE_SAMPLE) + rt2x00lib_evaluate_antenna_sample(rt2x00dev); + else if (rt2x00dev->link.count & 1) + rt2x00lib_evaluate_antenna_eval(rt2x00dev); +} + +static void rt2x00lib_update_link_stats(struct link *link, int rssi) +{ + int avg_rssi = rssi; + + /* + * Update global RSSI + */ + if (link->qual.avg_rssi) + avg_rssi = MOVING_AVERAGE(link->qual.avg_rssi, rssi, 8); + link->qual.avg_rssi = avg_rssi; + + /* + * Update antenna RSSI + */ + if (link->ant.rssi_ant) + rssi = MOVING_AVERAGE(link->ant.rssi_ant, rssi, 8); + link->ant.rssi_ant = rssi; +} + +static void rt2x00lib_precalculate_link_signal(struct link_qual *qual) +{ + if (qual->rx_failed || qual->rx_success) + qual->rx_percentage = + (qual->rx_success * 100) / + (qual->rx_failed + qual->rx_success); else - link->rx_percentage = 50; + qual->rx_percentage = 50; - if (link->tx_failed || link->tx_success) - link->tx_percentage = - (link->tx_success * 100) / - (link->tx_failed + link->tx_success); + if (qual->tx_failed || qual->tx_success) + qual->tx_percentage = + (qual->tx_success * 100) / + (qual->tx_failed + qual->tx_success); else - link->tx_percentage = 50; + qual->tx_percentage = 50; - link->rx_success = 0; - link->rx_failed = 0; - link->tx_success = 0; - link->tx_failed = 0; + qual->rx_success = 0; + qual->rx_failed = 0; + qual->tx_success = 0; + qual->tx_failed = 0; } static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, @@ -225,8 +408,8 @@ static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev, * defines to calculate the current link signal. */ signal = ((WEIGHT_RSSI * rssi_percentage) + - (WEIGHT_TX * rt2x00dev->link.tx_percentage) + - (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100; + (WEIGHT_TX * rt2x00dev->link.qual.tx_percentage) + + (WEIGHT_RX * rt2x00dev->link.qual.rx_percentage)) / 100; return (signal > 100) ? 100 : signal; } @@ -246,10 +429,9 @@ static void rt2x00lib_link_tuner(struct work_struct *work) /* * Update statistics. */ - rt2x00dev->ops->lib->link_stats(rt2x00dev); - + rt2x00dev->ops->lib->link_stats(rt2x00dev, &rt2x00dev->link.qual); rt2x00dev->low_level_stats.dot11FCSErrorCount += - rt2x00dev->link.rx_failed; + rt2x00dev->link.qual.rx_failed; /* * Only perform the link tuning when Link tuning @@ -259,10 +441,15 @@ static void rt2x00lib_link_tuner(struct work_struct *work) rt2x00dev->ops->lib->link_tuner(rt2x00dev); /* + * Evaluate antenna setup. + */ + rt2x00lib_evaluate_antenna(rt2x00dev); + + /* * Precalculate a portion of the link signal which is * in based on the tx/rx success/failure counters. */ - rt2x00lib_precalculate_link_signal(&rt2x00dev->link); + rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual); /* * Increase tuner counter, and reschedule the next link tuner run. @@ -276,7 +463,7 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, filter_work); - unsigned int filter = rt2x00dev->interface.filter; + unsigned int filter = rt2x00dev->packet_filter; /* * Since we had stored the filter inside interface.filter, @@ -284,7 +471,7 @@ static void rt2x00lib_packetfilter_scheduled(struct work_struct *work) * assume nothing has changed (*total_flags will be compared * to interface.filter to determine if any action is required). */ - rt2x00dev->interface.filter = 0; + rt2x00dev->packet_filter = 0; rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw, filter, &filter, 0, NULL); @@ -294,10 +481,17 @@ static void rt2x00lib_configuration_scheduled(struct work_struct *work) { struct rt2x00_dev *rt2x00dev = container_of(work, struct rt2x00_dev, config_work); - int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + struct ieee80211_bss_conf bss_conf; - rt2x00mac_erp_ie_changed(rt2x00dev->hw, - IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble); + bss_conf.use_short_preamble = + test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags); + + /* + * FIXME: shouldn't invoke it this way because all other contents + * of bss_conf is invalid. + */ + rt2x00mac_bss_info_changed(rt2x00dev->hw, rt2x00dev->interface.id, + &bss_conf, BSS_CHANGED_ERP_PREAMBLE); } /* @@ -350,8 +544,8 @@ void rt2x00lib_txdone(struct data_entry *entry, tx_status->ack_signal = 0; tx_status->excessive_retries = (status == TX_FAIL_RETRY); tx_status->retry_count = retry; - rt2x00dev->link.tx_success += success; - rt2x00dev->link.tx_failed += retry + fail; + rt2x00dev->link.qual.tx_success += success; + rt2x00dev->link.qual.tx_failed += retry + fail; if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) { if (success) @@ -371,9 +565,11 @@ void rt2x00lib_txdone(struct data_entry *entry, } /* - * Send the tx_status to mac80211, - * that method also cleans up the skb structure. + * Send the tx_status to mac80211 & debugfs. + * mac80211 will clean up the skb structure. */ + get_skb_desc(entry->skb)->frame_type = DUMP_FRAME_TXDONE; + rt2x00debug_dump_frame(rt2x00dev, entry->skb); ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status); entry->skb = NULL; } @@ -386,8 +582,10 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; struct ieee80211_hw_mode *mode; struct ieee80211_rate *rate; + struct ieee80211_hdr *hdr; unsigned int i; int val = 0; + u16 fc; /* * Update RX statistics. @@ -412,17 +610,28 @@ void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb, } } - rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi); - rt2x00dev->link.rx_success++; + /* + * Only update link status if this is a beacon frame carrying our bssid. + */ + hdr = (struct ieee80211_hdr*)skb->data; + fc = le16_to_cpu(hdr->frame_control); + if (is_beacon(fc) && desc->my_bss) + rt2x00lib_update_link_stats(&rt2x00dev->link, desc->rssi); + + rt2x00dev->link.qual.rx_success++; + rx_status->rate = val; rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi); rx_status->ssi = desc->rssi; rx_status->flag = desc->flags; + rx_status->antenna = rt2x00dev->link.ant.active.rx; /* - * Send frame to mac80211 + * Send frame to mac80211 & debugfs */ + get_skb_desc(skb)->frame_type = DUMP_FRAME_RXDONE; + rt2x00debug_dump_frame(rt2x00dev, skb); ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status); } EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); @@ -431,36 +640,25 @@ EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); * TX descriptor initializer */ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, + struct sk_buff *skb, struct ieee80211_tx_control *control) { struct txdata_entry_desc desc; - struct data_ring *ring; + struct skb_desc *skbdesc = get_skb_desc(skb); + struct ieee80211_hdr *ieee80211hdr = skbdesc->data; int tx_rate; int bitrate; + int length; int duration; int residual; u16 frame_control; u16 seq_ctrl; - /* - * Make sure the descriptor is properly cleared. - */ - memset(&desc, 0x00, sizeof(desc)); + memset(&desc, 0, sizeof(desc)); - /* - * Get ring pointer, if we fail to obtain the - * correct ring, then use the first TX ring. - */ - ring = rt2x00lib_get_ring(rt2x00dev, control->queue); - if (!ring) - ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); - - desc.cw_min = ring->tx_params.cw_min; - desc.cw_max = ring->tx_params.cw_max; - desc.aifs = ring->tx_params.aifs; + desc.cw_min = skbdesc->ring->tx_params.cw_min; + desc.cw_max = skbdesc->ring->tx_params.cw_max; + desc.aifs = skbdesc->ring->tx_params.aifs; /* * Identify queue @@ -482,12 +680,21 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, tx_rate = control->tx_rate; /* + * Check whether this frame is to be acked + */ + if (!(control->flags & IEEE80211_TXCTL_NO_ACK)) + __set_bit(ENTRY_TXD_ACK, &desc.flags); + + /* * Check if this is a RTS/CTS frame */ if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) { __set_bit(ENTRY_TXD_BURST, &desc.flags); - if (is_rts_frame(frame_control)) + if (is_rts_frame(frame_control)) { __set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags); + __set_bit(ENTRY_TXD_ACK, &desc.flags); + } else + __clear_bit(ENTRY_TXD_ACK, &desc.flags); if (control->rts_cts_rate) tx_rate = control->rts_cts_rate; } @@ -532,17 +739,18 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP); desc.service = 0x04; + length = skbdesc->data_len + FCS_LEN; if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) { - desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f; - desc.length_low = ((length + FCS_LEN) & 0x3f); + desc.length_high = (length >> 6) & 0x3f; + desc.length_low = length & 0x3f; } else { bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE); /* * Convert length to microseconds. */ - residual = get_duration_res(length + FCS_LEN, bitrate); - duration = get_duration(length + FCS_LEN, bitrate); + residual = get_duration_res(length, bitrate); + duration = get_duration(length, bitrate); if (residual != 0) { duration++; @@ -565,8 +773,22 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, desc.signal |= 0x08; } - rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc, - ieee80211hdr, length, control); + rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, skb, &desc, control); + + /* + * Update ring entry. + */ + skbdesc->entry->skb = skb; + memcpy(&skbdesc->entry->tx_status.control, control, sizeof(*control)); + + /* + * The frame has been completely initialized and ready + * for sending to the device. The caller will push the + * frame to the device, but we are going to push the + * frame to debugfs here. + */ + skbdesc->frame_type = DUMP_FRAME_TX; + rt2x00debug_dump_frame(rt2x00dev, skb); } EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc); @@ -809,6 +1031,7 @@ static int rt2x00lib_alloc_entries(struct data_ring *ring, entry[i].flags = 0; entry[i].ring = ring; entry[i].skb = NULL; + entry[i].entry_idx = i; } ring->entry = entry; @@ -866,7 +1089,7 @@ static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev) } } -void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) +static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) { if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags)) return; @@ -887,7 +1110,7 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev) rt2x00lib_free_ring_entries(rt2x00dev); } -int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) +static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev) { int status; @@ -930,12 +1153,65 @@ exit: return status; } +int rt2x00lib_start(struct rt2x00_dev *rt2x00dev) +{ + int retval; + + if (test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + return 0; + + /* + * If this is the first interface which is added, + * we should load the firmware now. + */ + if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) { + retval = rt2x00lib_load_firmware(rt2x00dev); + if (retval) + return retval; + } + + /* + * Initialize the device. + */ + retval = rt2x00lib_initialize(rt2x00dev); + if (retval) + return retval; + + /* + * Enable radio. + */ + retval = rt2x00lib_enable_radio(rt2x00dev); + if (retval) { + rt2x00lib_uninitialize(rt2x00dev); + return retval; + } + + __set_bit(DEVICE_STARTED, &rt2x00dev->flags); + + return 0; +} + +void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev) +{ + if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + return; + + /* + * Perhaps we can add something smarter here, + * but for now just disabling the radio should do. + */ + rt2x00lib_disable_radio(rt2x00dev); + + __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); +} + /* * driver allocation handlers. */ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring; + unsigned int index; /* * We need the following rings: @@ -963,11 +1239,18 @@ static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev) /* * Initialize ring parameters. - * cw_min: 2^5 = 32. - * cw_max: 2^10 = 1024. + * RX: queue_idx = 0 + * TX: queue_idx = IEEE80211_TX_QUEUE_DATA0 + index + * TX: cw_min: 2^5 = 32. + * TX: cw_max: 2^10 = 1024. */ - ring_for_each(rt2x00dev, ring) { + rt2x00dev->rx->rt2x00dev = rt2x00dev; + rt2x00dev->rx->queue_idx = 0; + + index = IEEE80211_TX_QUEUE_DATA0; + txring_for_each(rt2x00dev, ring) { ring->rt2x00dev = rt2x00dev; + ring->queue_idx = index++; ring->tx_params.aifs = 2; ring->tx_params.cw_min = 5; ring->tx_params.cw_max = 10; @@ -1008,7 +1291,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) /* * Reset current working type. */ - rt2x00dev->interface.type = INVALID_INTERFACE; + rt2x00dev->interface.type = IEEE80211_IF_TYPE_INVALID; /* * Allocate ring array. @@ -1112,7 +1395,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state) * Disable radio and unitialize all items * that must be recreated on resume. */ - rt2x00mac_stop(rt2x00dev->hw); + rt2x00lib_stop(rt2x00dev); rt2x00lib_uninitialize(rt2x00dev); rt2x00debug_deregister(rt2x00dev); @@ -1134,7 +1417,6 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) int retval; NOTICE(rt2x00dev, "Waking up.\n"); - __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); /* * Open the debugfs entry. @@ -1150,7 +1432,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reinitialize device and all active interfaces. */ - retval = rt2x00mac_start(rt2x00dev->hw); + retval = rt2x00lib_start(rt2x00dev); if (retval) goto exit; @@ -1166,6 +1448,11 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) rt2x00lib_config_type(rt2x00dev, intf->type); /* + * We are ready again to receive requests from mac80211. + */ + __set_bit(DEVICE_PRESENT, &rt2x00dev->flags); + + /* * It is possible that during that mac80211 has attempted * to send frames while we were suspending or resuming. * In that case we have disabled the TX queue and should diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h new file mode 100644 index 000000000000..99f3f367adce --- /dev/null +++ b/drivers/net/wireless/rt2x00/rt2x00dump.h @@ -0,0 +1,121 @@ +/* + Copyright (C) 2004 - 2007 rt2x00 SourceForge Project + <http://rt2x00.serialmonkey.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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. + */ + +/* + Module: rt2x00dump + Abstract: Data structures for the rt2x00debug & userspace. + */ + +#ifndef RT2X00DUMP_H +#define RT2X00DUMP_H + +/** + * DOC: Introduction + * + * This header is intended to be exported to userspace, + * to make the structures and enumerations available to userspace + * applications. This means that all data types should be exportable. + * + * When rt2x00 is compiled with debugfs support enabled, + * it is possible to capture all data coming in and out of the device + * by reading the frame dump file. This file can have only a single reader. + * The following frames will be reported: + * - All incoming frames (rx) + * - All outgoing frames (tx, including beacon and atim) + * - All completed frames (txdone including atim) + * + * The data is send to the file using the following format: + * + * [rt2x00dump header][hardware descriptor][ieee802.11 frame] + * + * rt2x00dump header: The description of the dumped frame, as well as + * additional information usefull for debugging. See &rt2x00dump_hdr. + * hardware descriptor: Descriptor that was used to receive or transmit + * the frame. + * ieee802.11 frame: The actual frame that was received or transmitted. + */ + +/** + * enum rt2x00_dump_type - Frame type + * + * These values are used for the @type member of &rt2x00dump_hdr. + * @DUMP_FRAME_RXDONE: This frame has been received by the hardware. + * @DUMP_FRAME_TX: This frame is queued for transmission to the hardware. + * @DUMP_FRAME_TXDONE: This frame indicates the device has handled + * the tx event which has either succeeded or failed. A frame + * with this type should also have been reported with as a + * %DUMP_FRAME_TX frame. + */ +enum rt2x00_dump_type { + DUMP_FRAME_RXDONE = 1, + DUMP_FRAME_TX = 2, + DUMP_FRAME_TXDONE = 3, +}; + +/** + * struct rt2x00dump_hdr - Dump frame header + * + * Each frame dumped to the debugfs file starts with this header + * attached. This header contains the description of the actual + * frame which was dumped. + * + * New fields inside the structure must be appended to the end of + * the structure. This way userspace tools compiled for earlier + * header versions can still correctly handle the frame dump + * (although they will not handle all data passed to them in the dump). + * + * @version: Header version should always be set to %DUMP_HEADER_VERSION. + * This field must be checked by userspace to determine if it can + * handle this frame. + * @header_length: The length of the &rt2x00dump_hdr structure. This is + * used for compatibility reasons so userspace can easily determine + * the location of the next field in the dump. + * @desc_length: The length of the device descriptor. + * @data_length: The length of the frame data (including the ieee802.11 header. + * @chip_rt: RT chipset + * @chip_rf: RF chipset + * @chip_rev: Chipset revision + * @type: The frame type (&rt2x00_dump_type) + * @ring_index: The index number of the data ring. + * @entry_index: The index number of the entry inside the data ring. + * @timestamp_sec: Timestamp - seconds + * @timestamp_usec: Timestamp - microseconds + */ +struct rt2x00dump_hdr { + __le32 version; +#define DUMP_HEADER_VERSION 2 + + __le32 header_length; + __le32 desc_length; + __le32 data_length; + + __le16 chip_rt; + __le16 chip_rf; + __le32 chip_rev; + + __le16 type; + __u8 ring_index; + __u8 entry_index; + + __le32 timestamp_sec; + __le32 timestamp_usec; +}; + +#endif /* RT2X00DUMP_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c index 236025f8b90f..0a475e4e2442 100644 --- a/drivers/net/wireless/rt2x00/rt2x00firmware.c +++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c @@ -23,11 +23,6 @@ Abstract: rt2x00 firmware loading routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00lib" - #include <linux/crc-itu-t.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 06d9bc0015c0..1adbd28e0973 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -44,8 +44,8 @@ void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev); /* * Initialization handlers. */ -int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev); -void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); +int rt2x00lib_start(struct rt2x00_dev *rt2x00dev); +void rt2x00lib_stop(struct rt2x00_dev *rt2x00dev); /* * Configuration handlers. @@ -53,6 +53,8 @@ void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev); void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac); void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid); void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type); +void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, + enum antenna rx, enum antenna tx); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config); @@ -78,6 +80,7 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev) #ifdef CONFIG_RT2X00_LIB_DEBUGFS void rt2x00debug_register(struct rt2x00_dev *rt2x00dev); void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev); +void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb); #else static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) { @@ -86,6 +89,11 @@ static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev) { } + +static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, + struct sk_buff *skb) +{ +} #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 85ea8a8e658e..e3f15e518c76 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -23,11 +23,6 @@ Abstract: rt2x00 generic mac80211 routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00lib" - #include <linux/kernel.h> #include <linux/module.h> @@ -89,7 +84,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, */ if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) { ieee80211_stop_queues(hw); - return 0; + return NETDEV_TX_OK; } /* @@ -115,15 +110,24 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) && (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT))) { - if (rt2x00_ring_free(ring) <= 1) + if (rt2x00_ring_free(ring) <= 1) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; + } - if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) + if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control)) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; + } } - if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) + if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) { + ieee80211_stop_queue(rt2x00dev->hw, control->queue); return NETDEV_TX_BUSY; + } + + if (rt2x00_ring_full(ring)) + ieee80211_stop_queue(rt2x00dev->hw, control->queue); if (rt2x00dev->ops->lib->kick_tx_queue) rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue); @@ -135,41 +139,11 @@ EXPORT_SYMBOL_GPL(rt2x00mac_tx); int rt2x00mac_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; - int status; - if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) || - test_bit(DEVICE_STARTED, &rt2x00dev->flags)) + if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return 0; - /* - * If this is the first interface which is added, - * we should load the firmware now. - */ - if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) { - status = rt2x00lib_load_firmware(rt2x00dev); - if (status) - return status; - } - - /* - * Initialize the device. - */ - status = rt2x00lib_initialize(rt2x00dev); - if (status) - return status; - - /* - * Enable radio. - */ - status = rt2x00lib_enable_radio(rt2x00dev); - if (status) { - rt2x00lib_uninitialize(rt2x00dev); - return status; - } - - __set_bit(DEVICE_STARTED, &rt2x00dev->flags); - - return 0; + return rt2x00lib_start(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00mac_start); @@ -180,13 +154,7 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) return; - /* - * Perhaps we can add something smarter here, - * but for now just disabling the radio should do. - */ - rt2x00lib_disable_radio(rt2x00dev); - - __clear_bit(DEVICE_STARTED, &rt2x00dev->flags); + rt2x00lib_stop(rt2x00dev); } EXPORT_SYMBOL_GPL(rt2x00mac_stop); @@ -213,7 +181,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, is_interface_present(intf)) return -ENOBUFS; - intf->id = conf->if_id; + intf->id = conf->vif; intf->type = conf->type; if (conf->type == IEEE80211_IF_TYPE_AP) memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); @@ -247,7 +215,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, return; intf->id = 0; - intf->type = INVALID_INTERFACE; + intf->type = IEEE80211_IF_TYPE_INVALID; memset(&intf->bssid, 0x00, ETH_ALEN); memset(&intf->mac, 0x00, ETH_ALEN); @@ -297,7 +265,8 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } EXPORT_SYMBOL_GPL(rt2x00mac_config); -int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id, +int rt2x00mac_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -373,23 +342,27 @@ int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats); -void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, - int cts_protection, int preamble) +void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) { struct rt2x00_dev *rt2x00dev = hw->priv; int short_preamble; int ack_timeout; int ack_consume_time; int difs; + int preamble; /* * We only support changing preamble mode. */ - if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE)) + if (!(changes & BSS_CHANGED_ERP_PREAMBLE)) return; - short_preamble = !preamble; - preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE; + short_preamble = bss_conf->use_short_preamble; + preamble = bss_conf->use_short_preamble ? + SHORT_PREAMBLE : PREAMBLE; difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ? SHORT_DIFS : DIFS; @@ -405,7 +378,7 @@ void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes, rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble, ack_timeout, ack_consume_time); } -EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed); +EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue, const struct ieee80211_tx_queue_params *params) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 04663eb31950..804a9980055d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -23,11 +23,6 @@ Abstract: rt2x00 generic pci device routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00pci" - #include <linux/dma-mapping.h> #include <linux/kernel.h> #include <linux/module.h> @@ -43,9 +38,9 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct data_ring *ring = - rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON); - struct data_entry *entry = rt2x00_get_data_entry(ring); + struct skb_desc *desc; + struct data_ring *ring; + struct data_entry *entry; /* * Just in case mac80211 doesn't set this correctly, @@ -53,14 +48,22 @@ int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * initialization. */ control->queue = IEEE80211_TX_QUEUE_BEACON; + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + entry = rt2x00_get_data_entry(ring); /* - * Update the beacon entry. + * Fill in skb descriptor */ + desc = get_skb_desc(skb); + desc->desc_len = ring->desc_size; + desc->data_len = skb->len; + desc->desc = entry->priv; + desc->data = skb->data; + desc->ring = ring; + desc->entry = entry; + memcpy(entry->data_addr, skb->data, skb->len); - rt2x00lib_write_tx_desc(rt2x00dev, entry->priv, - (struct ieee80211_hdr *)skb->data, - skb->len, control); + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * Enable beacon generation. @@ -78,15 +81,13 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct data_ring *ring, struct sk_buff *skb, struct ieee80211_tx_control *control) { - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; struct data_entry *entry = rt2x00_get_data_entry(ring); - struct data_desc *txd = entry->priv; + __le32 *txd = entry->priv; + struct skb_desc *desc; u32 word; - if (rt2x00_ring_full(ring)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00_ring_full(ring)) return -EINVAL; - } rt2x00_desc_read(txd, 0, &word); @@ -96,37 +97,42 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - ieee80211_stop_queue(rt2x00dev->hw, control->queue); return -EINVAL; } - entry->skb = skb; - memcpy(&entry->tx_status.control, control, sizeof(*control)); + /* + * Fill in skb descriptor + */ + desc = get_skb_desc(skb); + desc->desc_len = ring->desc_size; + desc->data_len = skb->len; + desc->desc = entry->priv; + desc->data = skb->data; + desc->ring = ring; + desc->entry = entry; + memcpy(entry->data_addr, skb->data, skb->len); - rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr, - skb->len, control); + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); rt2x00_ring_index_inc(ring); - if (rt2x00_ring_full(ring)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); - return 0; } EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data); /* - * RX data handlers. + * TX/RX data handlers. */ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring = rt2x00dev->rx; struct data_entry *entry; - struct data_desc *rxd; struct sk_buff *skb; struct ieee80211_hdr *hdr; + struct skb_desc *skbdesc; struct rxdata_entry_desc desc; int header_size; + __le32 *rxd; int align; u32 word; @@ -138,7 +144,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) break; - memset(&desc, 0x00, sizeof(desc)); + memset(&desc, 0, sizeof(desc)); rt2x00dev->ops->lib->fill_rxdone(entry, &desc); hdr = (struct ieee80211_hdr *)entry->data_addr; @@ -163,6 +169,17 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) memcpy(skb_put(skb, desc.size), entry->data_addr, desc.size); /* + * Fill in skb descriptor + */ + skbdesc = get_skb_desc(skb); + skbdesc->desc_len = entry->ring->desc_size; + skbdesc->data_len = skb->len; + skbdesc->desc = entry->priv; + skbdesc->data = skb->data; + skbdesc->ring = ring; + skbdesc->entry = entry; + + /* * Send the frame to rt2x00lib for further processing. */ rt2x00lib_rxdone(entry, skb, &desc); @@ -177,6 +194,37 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) } EXPORT_SYMBOL_GPL(rt2x00pci_rxdone); +void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry, + const int tx_status, const int retry) +{ + u32 word; + + rt2x00lib_txdone(entry, tx_status, retry); + + /* + * Make this entry available for reuse. + */ + entry->flags = 0; + + rt2x00_desc_read(entry->priv, 0, &word); + rt2x00_set_field32(&word, TXD_ENTRY_OWNER_NIC, 0); + rt2x00_set_field32(&word, TXD_ENTRY_VALID, 0); + rt2x00_desc_write(entry->priv, 0, word); + + rt2x00_ring_index_done_inc(entry->ring); + + /* + * If the data ring was full before the txdone handler + * we must make sure the packet queue in the mac80211 stack + * is reenabled when the txdone handler has finished. + */ + if (!rt2x00_ring_full(entry->ring)) + ieee80211_wake_queue(rt2x00dev->hw, + entry->tx_status.control.queue); + +} +EXPORT_SYMBOL_GPL(rt2x00pci_txdone); + /* * Device initialization handlers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 82adeac061d0..2d1eb8144da4 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -57,7 +57,7 @@ /* * Register access. */ -static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev, +static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, const unsigned long offset, u32 *value) { @@ -65,14 +65,14 @@ static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev, } static inline void -rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev, +rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned long offset, void *value, const u16 length) { memcpy_fromio(value, rt2x00dev->csr_addr + offset, length); } -static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev, +static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, const unsigned long offset, u32 value) { @@ -80,7 +80,7 @@ static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev, } static inline void -rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev, +rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned long offset, void *value, const u16 length) { @@ -101,9 +101,11 @@ int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_control *control); /* - * RX data handlers. + * RX/TX data handlers. */ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev); +void rt2x00pci_txdone(struct rt2x00_dev *rt2x00dev, struct data_entry *entry, + const int tx_status, const int retry); /* * Device initialization handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c index a0f8b8e0a24b..34a96d44e306 100644 --- a/drivers/net/wireless/rt2x00/rt2x00rfkill.c +++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c @@ -23,11 +23,6 @@ Abstract: rt2x00 rfkill routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00lib" - #include <linux/input-polldev.h> #include <linux/kernel.h> #include <linux/module.h> @@ -68,8 +63,10 @@ static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev) struct rt2x00_dev *rt2x00dev = poll_dev->private; int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); - if (rt2x00dev->rfkill->state != state) + if (rt2x00dev->rfkill->state != state) { input_report_key(poll_dev->input, KEY_WLAN, 1); + input_report_key(poll_dev->input, KEY_WLAN, 0); + } } int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) @@ -92,6 +89,13 @@ int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev) return retval; } + /* + * Force initial poll which will detect the initial device state, + * and correctly sends the signal to the rfkill layer about this + * state. + */ + rt2x00rfkill_poll(rt2x00dev->poll_dev); + return 0; } @@ -114,26 +118,41 @@ int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev) rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); if (!rt2x00dev->rfkill) { ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n"); - return -ENOMEM; + goto exit; } rt2x00dev->rfkill->name = rt2x00dev->ops->name; rt2x00dev->rfkill->data = rt2x00dev; - rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); + rt2x00dev->rfkill->state = -1; rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio; rt2x00dev->poll_dev = input_allocate_polled_device(); if (!rt2x00dev->poll_dev) { ERROR(rt2x00dev, "Failed to allocate polled device.\n"); - rfkill_free(rt2x00dev->rfkill); - return -ENOMEM; + goto exit_free_rfkill; } rt2x00dev->poll_dev->private = rt2x00dev; rt2x00dev->poll_dev->poll = rt2x00rfkill_poll; rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL; + rt2x00dev->poll_dev->input->name = rt2x00dev->ops->name; + rt2x00dev->poll_dev->input->phys = wiphy_name(rt2x00dev->hw->wiphy); + rt2x00dev->poll_dev->input->id.bustype = BUS_HOST; + rt2x00dev->poll_dev->input->id.vendor = 0x1814; + rt2x00dev->poll_dev->input->id.product = rt2x00dev->chip.rt; + rt2x00dev->poll_dev->input->id.version = rt2x00dev->chip.rev; + rt2x00dev->poll_dev->input->dev.parent = device; + rt2x00dev->poll_dev->input->evbit[0] = BIT(EV_KEY); + set_bit(KEY_WLAN, rt2x00dev->poll_dev->input->keybit); + return 0; + +exit_free_rfkill: + rfkill_free(rt2x00dev->rfkill); + +exit: + return -ENOMEM; } void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h index 1a864d32cfbd..1caa6d688c40 100644 --- a/drivers/net/wireless/rt2x00/rt2x00ring.h +++ b/drivers/net/wireless/rt2x00/rt2x00ring.h @@ -27,19 +27,27 @@ #define RT2X00RING_H /* - * data_desc - * Each data entry also contains a descriptor which is used by the - * device to determine what should be done with the packet and - * what the current status is. - * This structure is greatly simplified, but the descriptors - * are basically a list of little endian 32 bit values. - * Make the array by default 1 word big, this will allow us - * to use sizeof() correctly. + * skb_desc + * Descriptor information for the skb buffer */ -struct data_desc { - __le32 word[1]; +struct skb_desc { + unsigned int frame_type; + + unsigned int desc_len; + unsigned int data_len; + + void *desc; + void *data; + + struct data_ring *ring; + struct data_entry *entry; }; +static inline struct skb_desc* get_skb_desc(struct sk_buff *skb) +{ + return (struct skb_desc*)&skb->cb[0]; +} + /* * rxdata_entry_desc * Summary of information that has been read from the @@ -51,6 +59,7 @@ struct rxdata_entry_desc { int ofdm; int size; int flags; + int my_bss; }; /* @@ -66,6 +75,7 @@ struct txdata_entry_desc { #define ENTRY_TXD_MORE_FRAG 4 #define ENTRY_TXD_REQ_TIMESTAMP 5 #define ENTRY_TXD_BURST 6 +#define ENTRY_TXD_ACK 7 /* * Queue ID. ID's 0-4 are data TX rings @@ -134,6 +144,11 @@ struct data_entry { */ void *data_addr; dma_addr_t data_dma; + + /* + * Entry identification number (index). + */ + unsigned int entry_idx; }; /* @@ -172,6 +187,13 @@ struct data_ring { void *data_addr; /* + * Queue identification number: + * RX: 0 + * TX: IEEE80211_TX_* + */ + unsigned int queue_idx; + + /* * Index variables. */ u16 index; @@ -253,16 +275,16 @@ static inline int rt2x00_ring_free(struct data_ring *ring) /* * TX/RX Descriptor access functions. */ -static inline void rt2x00_desc_read(struct data_desc *desc, +static inline void rt2x00_desc_read(__le32 *desc, const u8 word, u32 *value) { - *value = le32_to_cpu(desc->word[word]); + *value = le32_to_cpu(desc[word]); } -static inline void rt2x00_desc_write(struct data_desc *desc, +static inline void rt2x00_desc_write(__le32 *desc, const u8 word, const u32 value) { - desc->word[word] = cpu_to_le32(value); + desc[word] = cpu_to_le32(value); } #endif /* RT2X00RING_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index 568d73847dca..84e9bdb73910 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -23,14 +23,10 @@ Abstract: rt2x00 generic usb device routines. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt2x00usb" - #include <linux/kernel.h> #include <linux/module.h> #include <linux/usb.h> +#include <linux/bug.h> #include "rt2x00.h" #include "rt2x00usb.h" @@ -38,7 +34,7 @@ /* * Interfacing with the HW. */ -int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, +int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, @@ -52,6 +48,7 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, (requesttype == USB_VENDOR_REQUEST_IN) ? usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { status = usb_control_msg(usb_dev, pipe, request, requesttype, value, offset, buffer, buffer_length, @@ -76,13 +73,15 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, } EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request); -int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, - const u8 request, const u8 requesttype, - const u16 offset, void *buffer, - const u16 buffer_length, const int timeout) +int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, const int timeout) { int status; + BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex)); + /* * Check for Cache availability. */ @@ -103,6 +102,25 @@ int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, return status; } +EXPORT_SYMBOL_GPL(rt2x00usb_vendor_req_buff_lock); + +int rt2x00usb_vendor_request_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; + + mutex_lock(&rt2x00dev->usb_cache_mutex); + + status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, + requesttype, offset, buffer, + buffer_length, timeout); + + mutex_unlock(&rt2x00dev->usb_cache_mutex); + + return status; +} EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff); /* @@ -113,7 +131,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) struct data_entry *entry = (struct data_entry *)urb->context; struct data_ring *ring = entry->ring; struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; - struct data_desc *txd = (struct data_desc *)entry->skb->data; + __le32 *txd = (__le32 *)entry->skb->data; u32 word; int tx_status; @@ -158,20 +176,17 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, struct usb_device *usb_dev = interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); struct data_entry *entry = rt2x00_get_data_entry(ring); - int pipe = usb_sndbulkpipe(usb_dev, 1); + struct skb_desc *desc; u32 length; - if (rt2x00_ring_full(ring)) { - ieee80211_stop_queue(rt2x00dev->hw, control->queue); + if (rt2x00_ring_full(ring)) return -EINVAL; - } if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) { ERROR(rt2x00dev, "Arrived at non-free entry in the non-full queue %d.\n" "Please file bug report to %s.\n", control->queue, DRV_PROJECT); - ieee80211_stop_queue(rt2x00dev->hw, control->queue); return -EINVAL; } @@ -181,12 +196,18 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, skb_push(skb, ring->desc_size); memset(skb->data, 0, ring->desc_size); - rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, - (struct ieee80211_hdr *)(skb->data + - ring->desc_size), - skb->len - ring->desc_size, control); - memcpy(&entry->tx_status.control, control, sizeof(*control)); - entry->skb = skb; + /* + * Fill in skb descriptor + */ + desc = get_skb_desc(skb); + desc->desc_len = ring->desc_size; + desc->data_len = skb->len - ring->desc_size; + desc->desc = skb->data; + desc->data = skb->data + ring->desc_size; + desc->ring = ring; + desc->entry = entry; + + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * USB devices cannot blindly pass the skb->len as the @@ -199,15 +220,12 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, * Initialize URB and send the frame to the device. */ __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_fill_bulk_urb(entry->priv, usb_dev, pipe, + usb_fill_bulk_urb(entry->priv, usb_dev, usb_sndbulkpipe(usb_dev, 1), skb->data, length, rt2x00usb_interrupt_txdone, entry); usb_submit_urb(entry->priv, GFP_ATOMIC); rt2x00_ring_index_inc(ring); - if (rt2x00_ring_full(ring)) - ieee80211_stop_queue(rt2x00dev->hw, control->queue); - return 0; } EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data); @@ -222,6 +240,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) struct rt2x00_dev *rt2x00dev = ring->rt2x00dev; struct sk_buff *skb; struct ieee80211_hdr *hdr; + struct skb_desc *skbdesc; struct rxdata_entry_desc desc; int header_size; int frame_size; @@ -238,7 +257,14 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) if (urb->actual_length < entry->ring->desc_size || urb->status) goto skip_entry; - memset(&desc, 0x00, sizeof(desc)); + /* + * Fill in skb descriptor + */ + skbdesc = get_skb_desc(entry->skb); + skbdesc->ring = ring; + skbdesc->entry = entry; + + memset(&desc, 0, sizeof(desc)); rt2x00dev->ops->lib->fill_rxdone(entry, &desc); /* @@ -264,9 +290,6 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) /* * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. - * After that trim the entire buffer down to only - * contain the valid frame data excluding the device - * descriptor. */ hdr = (struct ieee80211_hdr *)entry->skb->data; header_size = @@ -276,6 +299,16 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) skb_push(entry->skb, 2); memmove(entry->skb->data, entry->skb->data + 2, skb->len - 2); } + + /* + * Trim the entire buffer down to only contain the valid frame data + * excluding the device descriptor. The position of the descriptor + * varies. This means that we should check where the descriptor is + * and decide if we need to pull the data pointer to exclude the + * device descriptor. + */ + if (skbdesc->data > skbdesc->desc) + skb_pull(entry->skb, skbdesc->desc_len); skb_trim(entry->skb, desc.size); /* @@ -303,43 +336,6 @@ skip_entry: /* * Radio handlers */ -void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev) -{ - struct usb_device *usb_dev = - interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); - struct data_ring *ring; - struct data_entry *entry; - unsigned int i; - - /* - * Initialize the TX rings - */ - txringall_for_each(rt2x00dev, ring) { - for (i = 0; i < ring->stats.limit; i++) - ring->entry[i].flags = 0; - - rt2x00_ring_index_clear(ring); - } - - /* - * Initialize and start the RX ring. - */ - rt2x00_ring_index_clear(rt2x00dev->rx); - - for (i = 0; i < rt2x00dev->rx->stats.limit; i++) { - entry = &rt2x00dev->rx->entry[i]; - - usb_fill_bulk_urb(entry->priv, usb_dev, - usb_rcvbulkpipe(usb_dev, 1), - entry->skb->data, entry->skb->len, - rt2x00usb_interrupt_rxdone, entry); - - __set_bit(ENTRY_OWNER_NIC, &entry->flags); - usb_submit_urb(entry->priv, GFP_ATOMIC); - } -} -EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio); - void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev) { struct data_ring *ring; @@ -361,6 +357,29 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); /* * Device initialization handlers. */ +void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) +{ + struct usb_device *usb_dev = + interface_to_usbdev(rt2x00dev_usb(rt2x00dev)); + + usb_fill_bulk_urb(entry->priv, usb_dev, + usb_rcvbulkpipe(usb_dev, 1), + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); + + __set_bit(ENTRY_OWNER_NIC, &entry->flags); + usb_submit_urb(entry->priv, GFP_ATOMIC); +} +EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); + +void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) +{ + entry->flags = 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); + static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_ring *ring) { @@ -400,7 +419,7 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) struct sk_buff *skb; unsigned int entry_size; unsigned int i; - int status; + int uninitialized_var(status); /* * Allocate DMA @@ -507,6 +526,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00dev->dev = usb_intf; rt2x00dev->ops = ops; rt2x00dev->hw = hw; + mutex_init(&rt2x00dev->usb_cache_mutex); rt2x00dev->usb_maxpacket = usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1); diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 2681abe4d49e..e40df4050cd0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -91,7 +91,7 @@ * a buffer allocated by kmalloc. Failure to do so can lead * to unexpected behavior depending on the architecture. */ -int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, +int rt2x00usb_vendor_request(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, const u16 value, void *buffer, const u16 buffer_length, @@ -107,18 +107,25 @@ int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev, * kmalloc. Hence the reason for using a previously allocated cache * which has been allocated properly. */ -int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev, +int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, const u8 request, const u8 requesttype, const u16 offset, void *buffer, const u16 buffer_length, const int timeout); /* + * A version of rt2x00usb_vendor_request_buff which must be called + * if the usb_cache_mutex is already held. */ +int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, + const u8 request, const u8 requesttype, + const u16 offset, void *buffer, + const u16 buffer_length, const int timeout); + +/* * Simple wrapper around rt2x00usb_vendor_request to write a single * command to the device. Since we don't use the buffer argument we * don't have to worry about kmalloc here. */ -static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev - *rt2x00dev, +static inline int rt2x00usb_vendor_request_sw(struct rt2x00_dev *rt2x00dev, const u8 request, const u16 offset, const u16 value, @@ -134,8 +141,8 @@ static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev * from the device. Note that the eeprom argument _must_ be allocated using * kmalloc for correct handling inside the kernel USB layer. */ -static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev, - __le16 *eeprom, const u16 lenght) +static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, + __le16 *eeprom, const u16 lenght) { int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16)); @@ -147,7 +154,6 @@ static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev, /* * Radio handlers */ -void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev); void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev); /* @@ -160,6 +166,10 @@ int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev, /* * Device initialization handlers. */ +void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry); +void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry); int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index ecae968ce091..ab52f221cd71 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -24,11 +24,6 @@ Supported chipsets: RT2561, RT2561s, RT2661. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt61pci" - #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -52,7 +47,7 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev) +static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev) { u32 reg; unsigned int i; @@ -67,7 +62,7 @@ static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev) return reg; } -static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev, +static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; @@ -93,7 +88,7 @@ static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev, rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); } -static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev, +static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u32 reg; @@ -130,7 +125,7 @@ static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev, *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); } -static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev, +static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; @@ -160,7 +155,7 @@ rf_write: rt2x00_rf_write(rt2x00dev, word, value); } -static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev, +static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1) { @@ -220,13 +215,13 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) #ifdef CONFIG_RT2X00_LIB_DEBUGFS #define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) -static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev, +static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 *data) { rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); } -static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev, +static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); @@ -322,7 +317,8 @@ static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, + (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -411,8 +407,7 @@ static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, } static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, - const int antenna_rx) + struct antenna_setup *ant) { u8 r3; u8 r4; @@ -423,32 +418,39 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 77, &r77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, - !rt2x00_rf(&rt2x00dev->chip, RF5225)); + rt2x00_rf(&rt2x00dev->chip, RF5325)); - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: + /* + * Configure the RX antenna. + */ + switch (ant->rx) { case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - !!(rt2x00dev->curr_hwmode != HWMODE_A)); + (rt2x00dev->curr_hwmode != HWMODE_A)); break; case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); else - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); else - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); break; } @@ -458,8 +460,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, } static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, - const int antenna_rx) + struct antenna_setup *ant) { u8 r3; u8 r4; @@ -470,22 +471,31 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 77, &r77); rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, - !rt2x00_rf(&rt2x00dev->chip, RF2527)); + rt2x00_rf(&rt2x00dev->chip, RF2529)); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: + /* + * Configure the RX antenna. + */ + switch (ant->rx) { case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); break; case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); break; } @@ -501,23 +511,18 @@ static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, MAC_CSR13, ®); - if (p1 != 0xff) { - rt2x00_set_field32(®, MAC_CSR13_BIT4, !!p1); - rt2x00_set_field32(®, MAC_CSR13_BIT12, 0); - rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); - } - if (p2 != 0xff) { - rt2x00_set_field32(®, MAC_CSR13_BIT3, !p2); - rt2x00_set_field32(®, MAC_CSR13_BIT11, 0); - rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); - } + rt2x00_set_field32(®, MAC_CSR13_BIT4, p1); + rt2x00_set_field32(®, MAC_CSR13_BIT12, 0); + + rt2x00_set_field32(®, MAC_CSR13_BIT3, !p2); + rt2x00_set_field32(®, MAC_CSR13_BIT11, 0); + + rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg); } static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, - const int antenna_rx) + struct antenna_setup *ant) { - u16 eeprom; u8 r3; u8 r4; u8 r77; @@ -525,70 +530,36 @@ static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev, rt61pci_bbp_read(rt2x00dev, 3, &r3); rt61pci_bbp_read(rt2x00dev, 4, &r4); rt61pci_bbp_read(rt2x00dev, 77, &r77); - rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); - - if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && - rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); - rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1); - rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); - } else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) { - if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) { - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); - rt61pci_bbp_write(rt2x00dev, 77, r77); - } - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); - } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && - rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); - rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - - switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { - case 0: - rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); - break; - case 1: - rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); - break; - case 2: - rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); - break; - case 3: - rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); - break; - } - } else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) && - !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) { - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); + /* FIXME: Antenna selection for the rf 2529 is very confusing in the + * legacy driver. The code below should be ok for non-diversity setups. + */ - switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { - case 0: - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); - rt61pci_bbp_write(rt2x00dev, 77, r77); - rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1); - break; - case 1: - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); - rt61pci_bbp_write(rt2x00dev, 77, r77); - rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0); - break; - case 2: - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); - rt61pci_bbp_write(rt2x00dev, 77, r77); - rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); - break; - case 3: - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); - rt61pci_bbp_write(rt2x00dev, 77, r77); - rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); - break; - } + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); + rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0); + break; + case ANTENNA_SW_DIVERSITY: + case ANTENNA_HW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ + case ANTENNA_B: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); + rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1); + break; } + rt61pci_bbp_write(rt2x00dev, 77, r77); rt61pci_bbp_write(rt2x00dev, 3, r3); rt61pci_bbp_write(rt2x00dev, 4, r4); } @@ -625,46 +596,44 @@ static const struct antenna_sel antenna_sel_bg[] = { }; static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, const int antenna_rx) + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; unsigned int i; u32 reg; - rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®); - if (rt2x00dev->curr_hwmode == HWMODE_A) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); - - rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); - rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); } else { sel = antenna_sel_bg; lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); - - rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); - rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); } for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, + (rt2x00dev->curr_hwmode == HWMODE_B || + rt2x00dev->curr_hwmode == HWMODE_G)); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, + (rt2x00dev->curr_hwmode == HWMODE_A)); + rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); if (rt2x00_rf(&rt2x00dev->chip, RF5225) || rt2x00_rf(&rt2x00dev->chip, RF5325)) - rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); + rt61pci_config_antenna_5x(rt2x00dev, ant); else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) - rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); + rt61pci_config_antenna_2x(rt2x00dev, ant); else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) - rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, - antenna_rx); + rt61pci_config_antenna_2x(rt2x00dev, ant); else - rt61pci_config_antenna_2529(rt2x00dev, antenna_tx, - antenna_rx); + rt61pci_config_antenna_2529(rt2x00dev, ant); } } @@ -709,8 +678,7 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, - libconf->conf->antenna_sel_rx); + rt61pci_config_antenna(rt2x00dev, &libconf->ant); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) rt61pci_config_duration(rt2x00dev, libconf); } @@ -721,7 +689,6 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) { u32 reg; - u16 led_reg; u8 arg0; u8 arg1; @@ -730,15 +697,14 @@ static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, 30); rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg); - led_reg = rt2x00dev->led_reg; - rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1); - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) - rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1); - else - rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, + (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, + (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); - arg0 = led_reg & 0xff; - arg1 = (led_reg >> 8) & 0xff; + arg0 = rt2x00dev->led_reg & 0xff; + arg1 = (rt2x00dev->led_reg >> 8) & 0xff; rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1); } @@ -792,7 +758,8 @@ static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) /* * Link tuning */ -static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev) +static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) { u32 reg; @@ -800,14 +767,13 @@ static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev) * Update FCS error count from register. */ rt2x00pci_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ rt2x00pci_register_read(rt2x00dev, STA_CSR1, ®); - rt2x00dev->link.false_cca = - rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); + qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev) @@ -904,11 +870,11 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) * r17 does not yet exceed upper limit, continue and base * the r17 tuning on the false CCA count. */ - if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { if (++r17 > up_bound) r17 = up_bound; rt61pci_bbp_write(rt2x00dev, 17, r17); - } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { if (--r17 < low_bound) r17 = low_bound; rt61pci_bbp_write(rt2x00dev, 17, r17); @@ -1023,64 +989,46 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data, return 0; } -static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev) +static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) { - struct data_ring *ring = rt2x00dev->rx; - struct data_desc *rxd; - unsigned int i; + __le32 *rxd = entry->priv; u32 word; - memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) { - rxd = ring->entry[i].priv; - - rt2x00_desc_read(rxd, 5, &word); - rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - ring->entry[i].data_dma); - rt2x00_desc_write(rxd, 5, word); + rt2x00_desc_read(rxd, 5, &word); + rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, + entry->data_dma); + rt2x00_desc_write(rxd, 5, word); - rt2x00_desc_read(rxd, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(rxd, 0, word); - } - - rt2x00_ring_index_clear(rt2x00dev->rx); + rt2x00_desc_read(rxd, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(rxd, 0, word); } -static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue) +static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, + struct data_entry *entry) { - struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue); - struct data_desc *txd; - unsigned int i; + __le32 *txd = entry->priv; u32 word; - memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring)); - - for (i = 0; i < ring->stats.limit; i++) { - txd = ring->entry[i].priv; - - rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); - rt2x00_desc_write(txd, 1, word); - - rt2x00_desc_read(txd, 5, &word); - rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue); - rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i); - rt2x00_desc_write(txd, 5, word); + rt2x00_desc_read(txd, 1, &word); + rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1); + rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 6, &word); - rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, - ring->entry[i].data_dma); - rt2x00_desc_write(txd, 6, word); + rt2x00_desc_read(txd, 5, &word); + rt2x00_set_field32(&word, TXD_W5_PID_TYPE, entry->ring->queue_idx); + rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, entry->entry_idx); + rt2x00_desc_write(txd, 5, word); - rt2x00_desc_read(txd, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(txd, 0, word); - } + rt2x00_desc_read(txd, 6, &word); + rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS, + entry->data_dma); + rt2x00_desc_write(txd, 6, word); - rt2x00_ring_index_clear(ring); + rt2x00_desc_read(txd, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(txd, 0, word); } static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) @@ -1088,16 +1036,6 @@ static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev) u32 reg; /* - * Initialize rings. - */ - rt61pci_init_rxring(rt2x00dev); - rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0); - rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1); - rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2); - rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3); - rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4); - - /* * Initialize registers. */ rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, ®); @@ -1565,12 +1503,12 @@ static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, - struct txdata_entry_desc *desc, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, - struct ieee80211_tx_control *control) + struct sk_buff *skb, + struct txdata_entry_desc *desc, + struct ieee80211_tx_control *control) { + struct skb_desc *skbdesc = get_skb_desc(skb); + __le32 *txd = skbdesc->desc; u32 word; /* @@ -1599,7 +1537,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 5, word); rt2x00_desc_read(txd, 11, &word); - rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length); + rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, skbdesc->data_len); rt2x00_desc_write(txd, 11, word); rt2x00_desc_read(txd, 0, &word); @@ -1608,7 +1546,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - !(control->flags & IEEE80211_TXCTL_NO_ACK)); + test_bit(ENTRY_TXD_ACK, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, @@ -1618,7 +1556,7 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST, test_bit(ENTRY_TXD_BURST, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); @@ -1649,16 +1587,16 @@ static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev, } rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, ®); - if (queue == IEEE80211_TX_QUEUE_DATA0) - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, 1); - else if (queue == IEEE80211_TX_QUEUE_DATA1) - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, 1); - else if (queue == IEEE80211_TX_QUEUE_DATA2) - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, 1); - else if (queue == IEEE80211_TX_QUEUE_DATA3) - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, 1); - else if (queue == IEEE80211_TX_QUEUE_DATA4) - rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, 1); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC0, + (queue == IEEE80211_TX_QUEUE_DATA0)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC1, + (queue == IEEE80211_TX_QUEUE_DATA1)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC2, + (queue == IEEE80211_TX_QUEUE_DATA2)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_AC3, + (queue == IEEE80211_TX_QUEUE_DATA3)); + rt2x00_set_field32(®, TX_CNTL_CSR_KICK_TX_MGMT, + (queue == IEEE80211_TX_QUEUE_DATA4)); rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg); } @@ -1709,7 +1647,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt61pci_fill_rxdone(struct data_entry *entry, struct rxdata_entry_desc *desc) { - struct data_desc *rxd = entry->priv; + __le32 *rxd = entry->priv; u32 word0; u32 word1; @@ -1727,8 +1665,7 @@ static void rt61pci_fill_rxdone(struct data_entry *entry, desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1); desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); - - return; + desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); } /* @@ -1739,7 +1676,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) struct data_ring *ring; struct data_entry *entry; struct data_entry *entry_done; - struct data_desc *txd; + __le32 *txd; u32 word; u32 reg; u32 old_reg; @@ -1809,24 +1746,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev) tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT); retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT); - rt2x00lib_txdone(entry, tx_status, retry); - - /* - * Make this entry available for reuse. - */ - entry->flags = 0; - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_desc_write(txd, 0, word); - rt2x00_ring_index_done_inc(entry->ring); - - /* - * If the data ring was full before the txdone handler - * we must make sure the packet queue in the mac80211 stack - * is reenabled when the txdone handler has finished. - */ - if (!rt2x00_ring_full(ring)) - ieee80211_wake_queue(rt2x00dev->hw, - entry->tx_status.control.queue); + rt2x00pci_txdone(rt2x00dev, entry, tx_status, retry); } } @@ -1920,8 +1840,10 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, + ANTENNA_B); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, + ANTENNA_B); rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); @@ -2025,11 +1947,17 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) } /* + * Determine number of antenna's. + */ + if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) + __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); + + /* * Identify default antenna configuration. */ - rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00dev->default_ant.tx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); - rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00dev->default_ant.rx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); /* @@ -2039,12 +1967,6 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags); /* - * Determine number of antenna's. - */ - if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2) - __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags); - - /* * Detect if this device has an hardware controlled radio. */ #ifdef CONFIG_RT61PCI_RFKILL @@ -2072,6 +1994,38 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); /* + * When working with a RF2529 chip without double antenna + * the antenna settings should be gathered from the NIC + * eeprom word. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2529) && + !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { + switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) { + case 0: + rt2x00dev->default_ant.tx = ANTENNA_B; + rt2x00dev->default_ant.rx = ANTENNA_A; + break; + case 1: + rt2x00dev->default_ant.tx = ANTENNA_B; + rt2x00dev->default_ant.rx = ANTENNA_B; + break; + case 2: + rt2x00dev->default_ant.tx = ANTENNA_A; + rt2x00dev->default_ant.rx = ANTENNA_A; + break; + case 3: + rt2x00dev->default_ant.tx = ANTENNA_A; + rt2x00dev->default_ant.rx = ANTENNA_B; + break; + } + + if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) + rt2x00dev->default_ant.tx = ANTENNA_SW_DIVERSITY; + if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) + rt2x00dev->default_ant.rx = ANTENNA_SW_DIVERSITY; + } + + /* * Store led settings, for correct led behaviour. * If the eeprom value is invalid, * switch to default led mode. @@ -2325,7 +2279,6 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw, struct dev_addr_list *mc_list) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -2344,22 +2297,19 @@ static void rt61pci_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. - * - Some filters are set based on interface type. */ if (mc_count) *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - *total_flags |= FIF_PROMISC_IN_BSS; /* * Check if there is any work left for us. */ - if (intf->filter == *total_flags) + if (rt2x00dev->packet_filter == *total_flags) return; - intf->filter = *total_flags; + rt2x00dev->packet_filter = *total_flags; /* * Start configuration steps. @@ -2426,6 +2376,9 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct skb_desc *desc; + struct data_ring *ring; + struct data_entry *entry; /* * Just in case the ieee80211 doesn't set this, @@ -2433,6 +2386,8 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * initialization. */ control->queue = IEEE80211_TX_QUEUE_BEACON; + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + entry = rt2x00_get_data_entry(ring); /* * We need to append the descriptor in front of the @@ -2446,15 +2401,23 @@ static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, } /* - * First we create the beacon. + * Add the descriptor in front of the skb. + */ + skb_push(skb, ring->desc_size); + memset(skb->data, 0, ring->desc_size); + + /* + * Fill in skb descriptor */ - skb_push(skb, TXD_DESC_SIZE); - memset(skb->data, 0, TXD_DESC_SIZE); + desc = get_skb_desc(skb); + desc->desc_len = ring->desc_size; + desc->data_len = skb->len - ring->desc_size; + desc->desc = skb->data; + desc->data = skb->data + ring->desc_size; + desc->ring = ring; + desc->entry = entry; - rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, - (struct ieee80211_hdr *)(skb->data + - TXD_DESC_SIZE), - skb->len - TXD_DESC_SIZE, control); + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * Write entire beacon with descriptor to register, @@ -2478,7 +2441,7 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .configure_filter = rt61pci_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt61pci_set_retry_limit, - .erp_ie_changed = rt2x00mac_erp_ie_changed, + .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt61pci_get_tsf, @@ -2493,6 +2456,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .load_firmware = rt61pci_load_firmware, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, + .init_rxentry = rt61pci_init_rxentry, + .init_txentry = rt61pci_init_txentry, .set_device_state = rt61pci_set_device_state, .rfkill_poll = rt61pci_rfkill_poll, .link_stats = rt61pci_link_stats, @@ -2510,7 +2475,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { }; static const struct rt2x00_ops rt61pci_ops = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .rxd_size = RXD_DESC_SIZE, .txd_size = TXD_DESC_SIZE, .eeprom_size = EEPROM_SIZE, @@ -2547,7 +2512,7 @@ MODULE_FIRMWARE(FIRMWARE_RT2661); MODULE_LICENSE("GPL"); static struct pci_driver rt61pci_driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .id_table = rt61pci_device_table, .probe = rt2x00pci_probe, .remove = __devexit_p(rt2x00pci_remove), diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 6721d7dd32bc..4c6524eedad0 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -1077,13 +1077,19 @@ struct hw_pairwise_ta_entry { * R4: RX antenna control * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529) */ -#define BBP_R4_RX_ANTENNA FIELD8(0x03) + +/* + * ANTENNA_CONTROL semantics (guessed): + * 0x1: Software controlled antenna switching (fixed or SW diversity) + * 0x2: Hardware diversity. + */ +#define BBP_R4_RX_ANTENNA_CONTROL FIELD8(0x03) #define BBP_R4_RX_FRAME_END FIELD8(0x20) /* * R77 */ -#define BBP_R77_PAIR FIELD8(0x03) +#define BBP_R77_RX_ANTENNA FIELD8(0x03) /* * RF registers @@ -1240,8 +1246,8 @@ struct hw_pairwise_ta_entry { /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 16 * sizeof(struct data_desc) ) -#define RXD_DESC_SIZE ( 16 * sizeof(struct data_desc) ) +#define TXD_DESC_SIZE ( 16 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 16 * sizeof(__le32) ) /* * TX descriptor format for TX, PRIO and Beacon Ring. diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index c0671c2e6e73..4d576ab3e7f9 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -24,11 +24,6 @@ Supported chipsets: rt2571W & rt2671. */ -/* - * Set enviroment defines for rt2x00.h - */ -#define DRV_NAME "rt73usb" - #include <linux/delay.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -52,8 +47,9 @@ * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. + * The _lock versions must be used if you already hold the usb_cache_mutex */ -static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev, +static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 *value) { __le32 reg; @@ -63,8 +59,17 @@ static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev, *value = le32_to_cpu(reg); } -static inline void rt73usb_register_multiread(const struct rt2x00_dev - *rt2x00dev, +static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(u32), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { @@ -74,7 +79,7 @@ static inline void rt73usb_register_multiread(const struct rt2x00_dev value, length, timeout); } -static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev, +static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, const unsigned int offset, u32 value) { __le32 reg = cpu_to_le32(value); @@ -83,8 +88,16 @@ static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev, ®, sizeof(u32), REGISTER_TIMEOUT); } -static inline void rt73usb_register_multiwrite(const struct rt2x00_dev - *rt2x00dev, +static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(u32), REGISTER_TIMEOUT); +} + +static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, const unsigned int offset, void *value, const u32 length) { @@ -94,13 +107,13 @@ static inline void rt73usb_register_multiwrite(const struct rt2x00_dev value, length, timeout); } -static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev) +static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) { u32 reg; unsigned int i; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read(rt2x00dev, PHY_CSR3, ®); + rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, ®); if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) break; udelay(REGISTER_BUSY_DELAY); @@ -109,17 +122,20 @@ static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev) return reg; } -static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev, +static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; + mutex_lock(&rt2x00dev->usb_cache_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt73usb_bbp_check(rt2x00dev); if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->usb_cache_mutex); return; } @@ -132,20 +148,24 @@ static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - rt73usb_register_write(rt2x00dev, PHY_CSR3, reg); + rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + mutex_unlock(&rt2x00dev->usb_cache_mutex); } -static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev, +static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u32 reg; + mutex_lock(&rt2x00dev->usb_cache_mutex); + /* * Wait until the BBP becomes ready. */ reg = rt73usb_bbp_check(rt2x00dev); if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); + mutex_unlock(&rt2x00dev->usb_cache_mutex); return; } @@ -157,7 +177,7 @@ static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - rt73usb_register_write(rt2x00dev, PHY_CSR3, reg); + rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); /* * Wait until the BBP becomes ready. @@ -170,9 +190,10 @@ static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev, } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + mutex_unlock(&rt2x00dev->usb_cache_mutex); } -static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev, +static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; @@ -181,13 +202,16 @@ static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev, if (!word) return; + mutex_lock(&rt2x00dev->usb_cache_mutex); + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read(rt2x00dev, PHY_CSR4, ®); + rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, ®); if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) goto rf_write; udelay(REGISTER_BUSY_DELAY); } + mutex_unlock(&rt2x00dev->usb_cache_mutex); ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); return; @@ -200,25 +224,26 @@ rf_write: * all others contain 20 bits. */ rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, - 20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527))); + 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); - rt73usb_register_write(rt2x00dev, PHY_CSR4, reg); + rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->usb_cache_mutex); } #ifdef CONFIG_RT2X00_LIB_DEBUGFS #define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) -static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev, +static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 *data) { rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data); } -static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev, +static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev, const unsigned int word, u32 data) { rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); @@ -302,7 +327,8 @@ static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type, */ rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); - rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); + rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, + (tsf_sync == TSF_SYNC_BEACON)); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, tsf_sync); rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); @@ -396,12 +422,12 @@ static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, - const int antenna_rx) + struct antenna_setup *ant) { u8 r3; u8 r4; u8 r77; + u8 temp; rt73usb_bbp_read(rt2x00dev, 3, &r3); rt73usb_bbp_read(rt2x00dev, 4, &r4); @@ -409,30 +435,38 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0); - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: + /* + * Configure the RX antenna. + */ + switch (ant->rx) { case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); - rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - !!(rt2x00dev->curr_hwmode != HWMODE_A)); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); + temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags) + && (rt2x00dev->curr_hwmode != HWMODE_A); + rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp); break; case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); else - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); else - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); break; } @@ -442,8 +476,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, } static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, - const int antenna_rx) + struct antenna_setup *ant) { u8 r3; u8 r4; @@ -457,18 +490,27 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev, rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); - switch (antenna_rx) { - case ANTENNA_SW_DIVERSITY: + /* + * Configure the RX antenna. + */ + switch (ant->rx) { case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); break; case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - rt2x00_set_field8(&r77, BBP_R77_PAIR, 3); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); break; + case ANTENNA_SW_DIVERSITY: + /* + * NOTE: We should never come here because rt2x00lib is + * supposed to catch this and send us the correct antenna + * explicitely. However we are nog going to bug about this. + * Instead, just default to antenna B. + */ case ANTENNA_B: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - rt2x00_set_field8(&r77, BBP_R77_PAIR, 0); + rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); break; } @@ -509,40 +551,40 @@ static const struct antenna_sel antenna_sel_bg[] = { }; static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, - const int antenna_tx, const int antenna_rx) + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; unsigned int i; u32 reg; - rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); - if (rt2x00dev->curr_hwmode == HWMODE_A) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); - - rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 0); - rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 1); } else { sel = antenna_sel_bg; lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags); - - rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, 1); - rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, 0); } for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); + rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); + + rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, + (rt2x00dev->curr_hwmode == HWMODE_B || + rt2x00dev->curr_hwmode == HWMODE_G)); + rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, + (rt2x00dev->curr_hwmode == HWMODE_A)); + rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); if (rt2x00_rf(&rt2x00dev->chip, RF5226) || rt2x00_rf(&rt2x00dev->chip, RF5225)) - rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx); + rt73usb_config_antenna_5x(rt2x00dev, ant); else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || rt2x00_rf(&rt2x00dev->chip, RF2527)) - rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx); + rt73usb_config_antenna_2x(rt2x00dev, ant); } static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, @@ -586,8 +628,7 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); if (flags & CONFIG_UPDATE_ANTENNA) - rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx, - libconf->conf->antenna_sel_rx); + rt73usb_config_antenna(rt2x00dev, &libconf->ant); if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) rt73usb_config_duration(rt2x00dev, libconf); } @@ -605,12 +646,10 @@ static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev) rt73usb_register_write(rt2x00dev, MAC_CSR14, reg); rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) - rt2x00_set_field16(&rt2x00dev->led_reg, - MCU_LEDCS_LINK_A_STATUS, 1); - else - rt2x00_set_field16(&rt2x00dev->led_reg, - MCU_LEDCS_LINK_BG_STATUS, 1); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, + (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); + rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, + (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, rt2x00dev->led_reg, REGISTER_TIMEOUT); @@ -659,7 +698,8 @@ static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi) /* * Link tuning */ -static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev) +static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, + struct link_qual *qual) { u32 reg; @@ -667,15 +707,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev) * Update FCS error count from register. */ rt73usb_register_read(rt2x00dev, STA_CSR0, ®); - rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); + qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ rt73usb_register_read(rt2x00dev, STA_CSR1, ®); - reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); - rt2x00dev->link.false_cca = - rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); + qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev) @@ -781,12 +819,12 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) * r17 does not yet exceed upper limit, continue and base * the r17 tuning on the false CCA count. */ - if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) { + if (rt2x00dev->link.qual.false_cca > 512 && r17 < up_bound) { r17 += 4; if (r17 > up_bound) r17 = up_bound; rt73usb_bbp_write(rt2x00dev, 17, r17); - } else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) { + } else if (rt2x00dev->link.qual.false_cca < 100 && r17 > low_bound) { r17 -= 4; if (r17 < low_bound) r17 = low_bound; @@ -1098,8 +1136,6 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) return -EIO; } - rt2x00usb_enable_radio(rt2x00dev); - /* * Enable LED */ @@ -1193,12 +1229,12 @@ static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev, * TX descriptor initialization */ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, - struct data_desc *txd, - struct txdata_entry_desc *desc, - struct ieee80211_hdr *ieee80211hdr, - unsigned int length, - struct ieee80211_tx_control *control) + struct sk_buff *skb, + struct txdata_entry_desc *desc, + struct ieee80211_tx_control *control) { + struct skb_desc *skbdesc = get_skb_desc(skb); + __le32 *txd = skbdesc->desc; u32 word; /* @@ -1233,7 +1269,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_ACK, - !(control->flags & IEEE80211_TXCTL_NO_ACK)); + test_bit(ENTRY_TXD_ACK, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_TIMESTAMP, test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_OFDM, @@ -1243,7 +1279,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, !!(control->flags & IEEE80211_TXCTL_LONG_RETRY_LIMIT)); rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0); - rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length); + rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skbdesc->data_len); rt2x00_set_field32(&word, TXD_W0_BURST2, test_bit(ENTRY_TXD_BURST, &desc->flags)); rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE); @@ -1340,7 +1376,8 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) static void rt73usb_fill_rxdone(struct data_entry *entry, struct rxdata_entry_desc *desc) { - struct data_desc *rxd = (struct data_desc *)entry->skb->data; + struct skb_desc *skbdesc = get_skb_desc(entry->skb); + __le32 *rxd = (__le32 *)entry->skb->data; u32 word0; u32 word1; @@ -1358,13 +1395,15 @@ static void rt73usb_fill_rxdone(struct data_entry *entry, desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1); desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM); desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); + desc->my_bss = !!rt2x00_get_field32(word0, RXD_W0_MY_BSS); /* - * Pull the skb to clear the descriptor area. + * Set descriptor and data pointer. */ - skb_pull(entry->skb, entry->ring->desc_size); - - return; + skbdesc->desc = entry->skb->data; + skbdesc->desc_len = entry->ring->desc_size; + skbdesc->data = entry->skb->data + entry->ring->desc_size; + skbdesc->data_len = desc->size; } /* @@ -1392,8 +1431,10 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); if (word == 0xffff) { rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2); - rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2); + rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, + ANTENNA_B); + rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, + ANTENNA_B); rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0); rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0); @@ -1502,9 +1543,9 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) /* * Identify default antenna configuration. */ - rt2x00dev->hw->conf.antenna_sel_tx = + rt2x00dev->default_ant.tx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT); - rt2x00dev->hw->conf.antenna_sel_rx = + rt2x00dev->default_ant.rx = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT); /* @@ -1806,7 +1847,6 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw, struct dev_addr_list *mc_list) { struct rt2x00_dev *rt2x00dev = hw->priv; - struct interface *intf = &rt2x00dev->interface; u32 reg; /* @@ -1825,22 +1865,19 @@ static void rt73usb_configure_filter(struct ieee80211_hw *hw, * Apply some rules to the filters: * - Some filters imply different filters to be set. * - Some things we can't filter out at all. - * - Some filters are set based on interface type. */ if (mc_count) *total_flags |= FIF_ALLMULTI; if (*total_flags & FIF_OTHER_BSS || *total_flags & FIF_PROMISC_IN_BSS) *total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS; - if (is_interface_type(intf, IEEE80211_IF_TYPE_AP)) - *total_flags |= FIF_PROMISC_IN_BSS; /* * Check if there is any work left for us. */ - if (intf->filter == *total_flags) + if (rt2x00dev->packet_filter == *total_flags) return; - intf->filter = *total_flags; + rt2x00dev->packet_filter = *total_flags; /* * When in atomic context, reschedule and let rt2x00lib @@ -1926,6 +1963,9 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_control *control) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct skb_desc *desc; + struct data_ring *ring; + struct data_entry *entry; int timeout; /* @@ -1934,17 +1974,27 @@ static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb, * initialization. */ control->queue = IEEE80211_TX_QUEUE_BEACON; + ring = rt2x00lib_get_ring(rt2x00dev, control->queue); + entry = rt2x00_get_data_entry(ring); + + /* + * Add the descriptor in front of the skb. + */ + skb_push(skb, ring->desc_size); + memset(skb->data, 0, ring->desc_size); /* - * First we create the beacon. + * Fill in skb descriptor */ - skb_push(skb, TXD_DESC_SIZE); - memset(skb->data, 0, TXD_DESC_SIZE); + desc = get_skb_desc(skb); + desc->desc_len = ring->desc_size; + desc->data_len = skb->len - ring->desc_size; + desc->desc = skb->data; + desc->data = skb->data + ring->desc_size; + desc->ring = ring; + desc->entry = entry; - rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data, - (struct ieee80211_hdr *)(skb->data + - TXD_DESC_SIZE), - skb->len - TXD_DESC_SIZE, control); + rt2x00lib_write_tx_desc(rt2x00dev, skb, control); /* * Write entire beacon with descriptor to register, @@ -1971,7 +2021,7 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .configure_filter = rt73usb_configure_filter, .get_stats = rt2x00mac_get_stats, .set_retry_limit = rt73usb_set_retry_limit, - .erp_ie_changed = rt2x00mac_erp_ie_changed, + .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, .get_tsf = rt73usb_get_tsf, @@ -1985,6 +2035,8 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .load_firmware = rt73usb_load_firmware, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, + .init_rxentry = rt2x00usb_init_rxentry, + .init_txentry = rt2x00usb_init_txentry, .set_device_state = rt73usb_set_device_state, .link_stats = rt73usb_link_stats, .reset_tuner = rt73usb_reset_tuner, @@ -2002,7 +2054,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { }; static const struct rt2x00_ops rt73usb_ops = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .rxd_size = RXD_DESC_SIZE, .txd_size = TXD_DESC_SIZE, .eeprom_size = EEPROM_SIZE, @@ -2089,7 +2141,7 @@ MODULE_FIRMWARE(FIRMWARE_RT2571); MODULE_LICENSE("GPL"); static struct usb_driver rt73usb_driver = { - .name = DRV_NAME, + .name = KBUILD_MODNAME, .id_table = rt73usb_device_table, .probe = rt2x00usb_probe, .disconnect = rt2x00usb_disconnect, diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index f0951519f74b..d49dcaacecee 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -713,13 +713,19 @@ struct hw_pairwise_ta_entry { * R4: RX antenna control * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529) */ -#define BBP_R4_RX_ANTENNA FIELD8(0x03) + +/* + * ANTENNA_CONTROL semantics (guessed): + * 0x1: Software controlled antenna switching (fixed or SW diversity) + * 0x2: Hardware diversity. + */ +#define BBP_R4_RX_ANTENNA_CONTROL FIELD8(0x03) #define BBP_R4_RX_FRAME_END FIELD8(0x20) /* * R77 */ -#define BBP_R77_PAIR FIELD8(0x03) +#define BBP_R77_RX_ANTENNA FIELD8(0x03) /* * RF registers @@ -860,8 +866,8 @@ struct hw_pairwise_ta_entry { /* * DMA descriptor defines. */ -#define TXD_DESC_SIZE ( 6 * sizeof(struct data_desc) ) -#define RXD_DESC_SIZE ( 6 * sizeof(struct data_desc) ) +#define TXD_DESC_SIZE ( 6 * sizeof(__le32) ) +#define RXD_DESC_SIZE ( 6 * sizeof(__le32) ) /* * TX descriptor format for TX, PRIO and Beacon Ring. diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h new file mode 100644 index 000000000000..2cbfe3c8081f --- /dev/null +++ b/drivers/net/wireless/rtl8180.h @@ -0,0 +1,151 @@ +#ifndef RTL8180_H +#define RTL8180_H + +#include "rtl818x.h" + +#define MAX_RX_SIZE IEEE80211_MAX_RTS_THRESHOLD + +#define RF_PARAM_ANALOGPHY (1 << 0) +#define RF_PARAM_ANTBDEFAULT (1 << 1) +#define RF_PARAM_CARRIERSENSE1 (1 << 2) +#define RF_PARAM_CARRIERSENSE2 (1 << 3) + +#define BB_ANTATTEN_CHAN14 0x0C +#define BB_ANTENNA_B 0x40 + +#define BB_HOST_BANG (1 << 30) +#define BB_HOST_BANG_EN (1 << 2) +#define BB_HOST_BANG_CLK (1 << 1) +#define BB_HOST_BANG_DATA 1 + +#define ANAPARAM_TXDACOFF_SHIFT 27 +#define ANAPARAM_PWR0_SHIFT 28 +#define ANAPARAM_PWR0_MASK (0x07 << ANAPARAM_PWR0_SHIFT) +#define ANAPARAM_PWR1_SHIFT 20 +#define ANAPARAM_PWR1_MASK (0x7F << ANAPARAM_PWR1_SHIFT) + +enum rtl8180_tx_desc_flags { + RTL8180_TX_DESC_FLAG_NO_ENC = (1 << 15), + RTL8180_TX_DESC_FLAG_TX_OK = (1 << 15), + RTL8180_TX_DESC_FLAG_SPLCP = (1 << 16), + RTL8180_TX_DESC_FLAG_RX_UNDER = (1 << 16), + RTL8180_TX_DESC_FLAG_MOREFRAG = (1 << 17), + RTL8180_TX_DESC_FLAG_CTS = (1 << 18), + RTL8180_TX_DESC_FLAG_RTS = (1 << 23), + RTL8180_TX_DESC_FLAG_LS = (1 << 28), + RTL8180_TX_DESC_FLAG_FS = (1 << 29), + RTL8180_TX_DESC_FLAG_DMA = (1 << 30), + RTL8180_TX_DESC_FLAG_OWN = (1 << 31) +}; + +struct rtl8180_tx_desc { + __le32 flags; + __le16 rts_duration; + __le16 plcp_len; + __le32 tx_buf; + __le32 frame_len; + __le32 next_tx_desc; + u8 cw; + u8 retry_limit; + u8 agc; + u8 flags2; + u32 reserved[2]; +} __attribute__ ((packed)); + +enum rtl8180_rx_desc_flags { + RTL8180_RX_DESC_FLAG_ICV_ERR = (1 << 12), + RTL8180_RX_DESC_FLAG_CRC32_ERR = (1 << 13), + RTL8180_RX_DESC_FLAG_PM = (1 << 14), + RTL8180_RX_DESC_FLAG_RX_ERR = (1 << 15), + RTL8180_RX_DESC_FLAG_BCAST = (1 << 16), + RTL8180_RX_DESC_FLAG_PAM = (1 << 17), + RTL8180_RX_DESC_FLAG_MCAST = (1 << 18), + RTL8180_RX_DESC_FLAG_SPLCP = (1 << 25), + RTL8180_RX_DESC_FLAG_FOF = (1 << 26), + RTL8180_RX_DESC_FLAG_DMA_FAIL = (1 << 27), + RTL8180_RX_DESC_FLAG_LS = (1 << 28), + RTL8180_RX_DESC_FLAG_FS = (1 << 29), + RTL8180_RX_DESC_FLAG_EOR = (1 << 30), + RTL8180_RX_DESC_FLAG_OWN = (1 << 31) +}; + +struct rtl8180_rx_desc { + __le32 flags; + __le32 flags2; + union { + __le32 rx_buf; + __le64 tsft; + }; +} __attribute__ ((packed)); + +struct rtl8180_tx_ring { + struct rtl8180_tx_desc *desc; + dma_addr_t dma; + unsigned int idx; + unsigned int entries; + struct sk_buff_head queue; +}; + +struct rtl8180_priv { + /* common between rtl818x drivers */ + struct rtl818x_csr __iomem *map; + const struct rtl818x_rf_ops *rf; + struct ieee80211_vif *vif; + int mode; + + /* rtl8180 driver specific */ + spinlock_t lock; + struct rtl8180_rx_desc *rx_ring; + dma_addr_t rx_ring_dma; + unsigned int rx_idx; + struct sk_buff *rx_buf[32]; + struct rtl8180_tx_ring tx_ring[4]; + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_hw_mode modes[2]; + struct pci_dev *pdev; + u32 rx_conf; + + int r8185; + u32 anaparam; + u16 rfparam; + u8 csthreshold; +}; + +void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); +void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam); + +static inline u8 rtl818x_ioread8(struct rtl8180_priv *priv, u8 __iomem *addr) +{ + return ioread8(addr); +} + +static inline u16 rtl818x_ioread16(struct rtl8180_priv *priv, __le16 __iomem *addr) +{ + return ioread16(addr); +} + +static inline u32 rtl818x_ioread32(struct rtl8180_priv *priv, __le32 __iomem *addr) +{ + return ioread32(addr); +} + +static inline void rtl818x_iowrite8(struct rtl8180_priv *priv, + u8 __iomem *addr, u8 val) +{ + iowrite8(val, addr); +} + +static inline void rtl818x_iowrite16(struct rtl8180_priv *priv, + __le16 __iomem *addr, u16 val) +{ + iowrite16(val, addr); +} + +static inline void rtl818x_iowrite32(struct rtl8180_priv *priv, + __le32 __iomem *addr, u32 val) +{ + iowrite32(val, addr); +} + +#endif /* RTL8180_H */ diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c new file mode 100644 index 000000000000..07f37b0ccf91 --- /dev/null +++ b/drivers/net/wireless/rtl8180_dev.c @@ -0,0 +1,1051 @@ + +/* + * Linux device driver for RTL8180 / RTL8185 + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8180 driver, which is: + * Copyright 2004-2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/etherdevice.h> +#include <linux/eeprom_93cx6.h> +#include <net/mac80211.h> + +#include "rtl8180.h" +#include "rtl8180_rtl8225.h" +#include "rtl8180_sa2400.h" +#include "rtl8180_max2820.h" +#include "rtl8180_grf5101.h" + +MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); +MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>"); +MODULE_DESCRIPTION("RTL8180 / RTL8185 PCI wireless driver"); +MODULE_LICENSE("GPL"); + +static struct pci_device_id rtl8180_table[] __devinitdata = { + /* rtl8185 */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8185) }, + { PCI_DEVICE(PCI_VENDOR_ID_BELKIN, 0x701f) }, + + /* rtl8180 */ + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8180) }, + { PCI_DEVICE(0x1799, 0x6001) }, + { PCI_DEVICE(0x1799, 0x6020) }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, + { } +}; + +MODULE_DEVICE_TABLE(pci, rtl8180_table); + +void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + int i = 10; + u32 buf; + + buf = (data << 8) | addr; + + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf | 0x80); + while (i--) { + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->PHY[0], buf); + if (rtl818x_ioread8(priv, &priv->map->PHY[2]) == (data & 0xFF)) + return; + } +} + +static void rtl8180_handle_rx(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + unsigned int count = 32; + + while (count--) { + struct rtl8180_rx_desc *entry = &priv->rx_ring[priv->rx_idx]; + struct sk_buff *skb = priv->rx_buf[priv->rx_idx]; + u32 flags = le32_to_cpu(entry->flags); + + if (flags & RTL8180_RX_DESC_FLAG_OWN) + return; + + if (unlikely(flags & (RTL8180_RX_DESC_FLAG_DMA_FAIL | + RTL8180_RX_DESC_FLAG_FOF | + RTL8180_RX_DESC_FLAG_RX_ERR))) + goto done; + else { + u32 flags2 = le32_to_cpu(entry->flags2); + struct ieee80211_rx_status rx_status = {0}; + struct sk_buff *new_skb = dev_alloc_skb(MAX_RX_SIZE); + + if (unlikely(!new_skb)) + goto done; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + skb_put(skb, flags & 0xFFF); + + rx_status.antenna = (flags2 >> 15) & 1; + /* TODO: improve signal/rssi reporting */ + rx_status.signal = flags2 & 0xFF; + rx_status.ssi = (flags2 >> 8) & 0x7F; + rx_status.rate = (flags >> 20) & 0xF; + rx_status.freq = dev->conf.freq; + rx_status.channel = dev->conf.channel; + rx_status.phymode = dev->conf.phymode; + rx_status.mactime = le64_to_cpu(entry->tsft); + rx_status.flag |= RX_FLAG_TSFT; + if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR) + rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; + + ieee80211_rx_irqsafe(dev, skb, &rx_status); + + skb = new_skb; + priv->rx_buf[priv->rx_idx] = skb; + *((dma_addr_t *) skb->cb) = + pci_map_single(priv->pdev, skb_tail_pointer(skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + } + + done: + entry->rx_buf = cpu_to_le32(*((dma_addr_t *)skb->cb)); + entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN | + MAX_RX_SIZE); + if (priv->rx_idx == 31) + entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR); + priv->rx_idx = (priv->rx_idx + 1) % 32; + } +} + +static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb; + struct ieee80211_tx_status status = { {0} }; + struct ieee80211_tx_control *control; + u32 flags = le32_to_cpu(entry->flags); + + if (flags & RTL8180_TX_DESC_FLAG_OWN) + return; + + ring->idx = (ring->idx + 1) % ring->entries; + skb = __skb_dequeue(&ring->queue); + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + + control = *((struct ieee80211_tx_control **)skb->cb); + if (control) + memcpy(&status.control, control, sizeof(*control)); + kfree(control); + + if (!(status.control.flags & IEEE80211_TXCTL_NO_ACK)) { + if (flags & RTL8180_TX_DESC_FLAG_TX_OK) + status.flags = IEEE80211_TX_STATUS_ACK; + else + status.excessive_retries = 1; + } + status.retry_count = flags & 0xFF; + + ieee80211_tx_status_irqsafe(dev, skb, &status); + if (ring->entries - skb_queue_len(&ring->queue) == 2) + ieee80211_wake_queue(dev, prio); + } +} + +static irqreturn_t rtl8180_interrupt(int irq, void *dev_id) +{ + struct ieee80211_hw *dev = dev_id; + struct rtl8180_priv *priv = dev->priv; + u16 reg; + + spin_lock(&priv->lock); + reg = rtl818x_ioread16(priv, &priv->map->INT_STATUS); + if (unlikely(reg == 0xFFFF)) { + spin_unlock(&priv->lock); + return IRQ_HANDLED; + } + + rtl818x_iowrite16(priv, &priv->map->INT_STATUS, reg); + + if (reg & (RTL818X_INT_TXB_OK | RTL818X_INT_TXB_ERR)) + rtl8180_handle_tx(dev, 3); + + if (reg & (RTL818X_INT_TXH_OK | RTL818X_INT_TXH_ERR)) + rtl8180_handle_tx(dev, 2); + + if (reg & (RTL818X_INT_TXN_OK | RTL818X_INT_TXN_ERR)) + rtl8180_handle_tx(dev, 1); + + if (reg & (RTL818X_INT_TXL_OK | RTL818X_INT_TXL_ERR)) + rtl8180_handle_tx(dev, 0); + + if (reg & (RTL818X_INT_RX_OK | RTL818X_INT_RX_ERR)) + rtl8180_handle_rx(dev); + + spin_unlock(&priv->lock); + + return IRQ_HANDLED; +} + +static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring; + struct rtl8180_tx_desc *entry; + unsigned long flags; + unsigned int idx, prio; + dma_addr_t mapping; + u32 tx_flags; + u16 plcp_len = 0; + __le16 rts_duration = 0; + + prio = control->queue; + ring = &priv->tx_ring[prio]; + + mapping = pci_map_single(priv->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + + tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | + RTL8180_TX_DESC_FLAG_LS | (control->tx_rate << 24) | + (control->rts_cts_rate << 19) | skb->len; + + if (priv->r8185) + tx_flags |= RTL8180_TX_DESC_FLAG_DMA | + RTL8180_TX_DESC_FLAG_NO_ENC; + + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + tx_flags |= RTL8180_TX_DESC_FLAG_RTS; + else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + tx_flags |= RTL8180_TX_DESC_FLAG_CTS; + + *((struct ieee80211_tx_control **) skb->cb) = + kmemdup(control, sizeof(*control), GFP_ATOMIC); + + if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, + control); + + if (!priv->r8185) { + unsigned int remainder; + + plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), + (control->rate->rate * 2) / 10); + remainder = (16 * (skb->len + 4)) % + ((control->rate->rate * 2) / 10); + if (remainder > 0 && remainder <= 6) + plcp_len |= 1 << 15; + } + + spin_lock_irqsave(&priv->lock, flags); + idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries; + entry = &ring->desc[idx]; + + entry->rts_duration = rts_duration; + entry->plcp_len = cpu_to_le16(plcp_len); + entry->tx_buf = cpu_to_le32(mapping); + entry->frame_len = cpu_to_le32(skb->len); + entry->flags2 = control->alt_retry_rate != -1 ? + control->alt_retry_rate << 4 : 0; + entry->retry_limit = control->retry_limit; + entry->flags = cpu_to_le32(tx_flags); + __skb_queue_tail(&ring->queue, skb); + if (ring->entries - skb_queue_len(&ring->queue) < 2) + ieee80211_stop_queue(dev, control->queue); + spin_unlock_irqrestore(&priv->lock, flags); + + rtl818x_iowrite8(priv, &priv->map->TX_DMA_POLLING, (1 << (prio + 4))); + + return 0; +} + +void rtl8180_set_anaparam(struct rtl8180_priv *priv, u32 anaparam) +{ + u8 reg; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, anaparam); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, + reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static int rtl8180_init_hw(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg; + + rtl818x_iowrite8(priv, &priv->map->CMD, 0); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(10); + + /* reset */ + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + rtl818x_ioread8(priv, &priv->map->CMD); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= (1 << 1); + reg |= RTL818X_CMD_RESET; + rtl818x_iowrite8(priv, &priv->map->CMD, RTL818X_CMD_RESET); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(200); + + /* check success of reset */ + if (rtl818x_ioread8(priv, &priv->map->CMD) & RTL818X_CMD_RESET) { + printk(KERN_ERR "%s: reset timeout!\n", wiphy_name(dev->wiphy)); + return -ETIMEDOUT; + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_LOAD); + rtl818x_ioread8(priv, &priv->map->CMD); + msleep(200); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG3) & (1 << 3)) { + /* For cardbus */ + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + reg |= 1 << 1; + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg); + reg = rtl818x_ioread16(priv, &priv->map->FEMR); + reg |= (1 << 15) | (1 << 14) | (1 << 4); + rtl818x_iowrite16(priv, &priv->map->FEMR, reg); + } + + rtl818x_iowrite8(priv, &priv->map->MSR, 0); + + if (!priv->r8185) + rtl8180_set_anaparam(priv, priv->anaparam); + + rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); + rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); + rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); + rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); + rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); + + /* TODO: necessary? specs indicate not */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); + rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg & ~(1 << 3)); + if (priv->r8185) { + reg = rtl818x_ioread8(priv, &priv->map->CONFIG2); + rtl818x_iowrite8(priv, &priv->map->CONFIG2, reg | (1 << 4)); + } + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + /* TODO: set CONFIG5 for calibrating AGC on rtl8180 + philips radio? */ + + /* TODO: turn off hw wep on rtl8180 */ + + rtl818x_iowrite32(priv, &priv->map->INT_TIMEOUT, 0); + + if (priv->r8185) { + rtl818x_iowrite8(priv, &priv->map->WPA_CONF, 0); + rtl818x_iowrite8(priv, &priv->map->RATE_FALLBACK, 0x81); + rtl818x_iowrite8(priv, &priv->map->RESP_RATE, (8 << 4) | 0); + + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + + /* TODO: set ClkRun enable? necessary? */ + reg = rtl818x_ioread8(priv, &priv->map->GP_ENABLE); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, reg & ~(1 << 6)); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | (1 << 2)); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + } else { + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x1); + rtl818x_iowrite8(priv, &priv->map->SECURITY, 0); + + rtl818x_iowrite8(priv, &priv->map->PHY_DELAY, 0x6); + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, 0x4C); + } + + priv->rf->init(dev); + if (priv->r8185) + rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); + return 0; +} + +static int rtl8180_init_rx_ring(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_rx_desc *entry; + int i; + + priv->rx_ring = pci_alloc_consistent(priv->pdev, + sizeof(*priv->rx_ring) * 32, + &priv->rx_ring_dma); + + if (!priv->rx_ring || (unsigned long)priv->rx_ring & 0xFF) { + printk(KERN_ERR "%s: Cannot allocate RX ring\n", + wiphy_name(dev->wiphy)); + return -ENOMEM; + } + + memset(priv->rx_ring, 0, sizeof(*priv->rx_ring) * 32); + priv->rx_idx = 0; + + for (i = 0; i < 32; i++) { + struct sk_buff *skb = dev_alloc_skb(MAX_RX_SIZE); + dma_addr_t *mapping; + entry = &priv->rx_ring[i]; + if (!skb) + return 0; + + priv->rx_buf[i] = skb; + mapping = (dma_addr_t *)skb->cb; + *mapping = pci_map_single(priv->pdev, skb_tail_pointer(skb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + entry->rx_buf = cpu_to_le32(*mapping); + entry->flags = cpu_to_le32(RTL8180_RX_DESC_FLAG_OWN | + MAX_RX_SIZE); + } + entry->flags |= cpu_to_le32(RTL8180_RX_DESC_FLAG_EOR); + return 0; +} + +static void rtl8180_free_rx_ring(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + for (i = 0; i < 32; i++) { + struct sk_buff *skb = priv->rx_buf[i]; + if (!skb) + continue; + + pci_unmap_single(priv->pdev, + *((dma_addr_t *)skb->cb), + MAX_RX_SIZE, PCI_DMA_FROMDEVICE); + kfree_skb(skb); + } + + pci_free_consistent(priv->pdev, sizeof(*priv->rx_ring) * 32, + priv->rx_ring, priv->rx_ring_dma); + priv->rx_ring = NULL; +} + +static int rtl8180_init_tx_ring(struct ieee80211_hw *dev, + unsigned int prio, unsigned int entries) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_desc *ring; + dma_addr_t dma; + int i; + + ring = pci_alloc_consistent(priv->pdev, sizeof(*ring) * entries, &dma); + if (!ring || (unsigned long)ring & 0xFF) { + printk(KERN_ERR "%s: Cannot allocate TX ring (prio = %d)\n", + wiphy_name(dev->wiphy), prio); + return -ENOMEM; + } + + memset(ring, 0, sizeof(*ring)*entries); + priv->tx_ring[prio].desc = ring; + priv->tx_ring[prio].dma = dma; + priv->tx_ring[prio].idx = 0; + priv->tx_ring[prio].entries = entries; + skb_queue_head_init(&priv->tx_ring[prio].queue); + + for (i = 0; i < entries; i++) + ring[i].next_tx_desc = + cpu_to_le32((u32)dma + ((i + 1) % entries) * sizeof(*ring)); + + return 0; +} + +static void rtl8180_free_tx_ring(struct ieee80211_hw *dev, unsigned int prio) +{ + struct rtl8180_priv *priv = dev->priv; + struct rtl8180_tx_ring *ring = &priv->tx_ring[prio]; + + while (skb_queue_len(&ring->queue)) { + struct rtl8180_tx_desc *entry = &ring->desc[ring->idx]; + struct sk_buff *skb = __skb_dequeue(&ring->queue); + + pci_unmap_single(priv->pdev, le32_to_cpu(entry->tx_buf), + skb->len, PCI_DMA_TODEVICE); + kfree(*((struct ieee80211_tx_control **) skb->cb)); + kfree_skb(skb); + ring->idx = (ring->idx + 1) % ring->entries; + } + + pci_free_consistent(priv->pdev, sizeof(*ring->desc)*ring->entries, + ring->desc, ring->dma); + ring->desc = NULL; +} + +static int rtl8180_start(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int ret, i; + u32 reg; + + ret = rtl8180_init_rx_ring(dev); + if (ret) + return ret; + + for (i = 0; i < 4; i++) + if ((ret = rtl8180_init_tx_ring(dev, i, 16))) + goto err_free_rings; + + ret = rtl8180_init_hw(dev); + if (ret) + goto err_free_rings; + + rtl818x_iowrite32(priv, &priv->map->RDSAR, priv->rx_ring_dma); + rtl818x_iowrite32(priv, &priv->map->TBDA, priv->tx_ring[3].dma); + rtl818x_iowrite32(priv, &priv->map->THPDA, priv->tx_ring[2].dma); + rtl818x_iowrite32(priv, &priv->map->TNPDA, priv->tx_ring[1].dma); + rtl818x_iowrite32(priv, &priv->map->TLPDA, priv->tx_ring[0].dma); + + ret = request_irq(priv->pdev->irq, &rtl8180_interrupt, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (ret) { + printk(KERN_ERR "%s: failed to register IRQ handler\n", + wiphy_name(dev->wiphy)); + goto err_free_rings; + } + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0xFFFF); + + rtl818x_iowrite32(priv, &priv->map->MAR[0], ~0); + rtl818x_iowrite32(priv, &priv->map->MAR[1], ~0); + + reg = RTL818X_RX_CONF_ONLYERLPKT | + RTL818X_RX_CONF_RX_AUTORESETPHY | + RTL818X_RX_CONF_MGMT | + RTL818X_RX_CONF_DATA | + (7 << 8 /* MAX RX DMA */) | + RTL818X_RX_CONF_BROADCAST | + RTL818X_RX_CONF_NICMAC; + + if (priv->r8185) + reg |= RTL818X_RX_CONF_CSDM1 | RTL818X_RX_CONF_CSDM2; + else { + reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE1) + ? RTL818X_RX_CONF_CSDM1 : 0; + reg |= (priv->rfparam & RF_PARAM_CARRIERSENSE2) + ? RTL818X_RX_CONF_CSDM2 : 0; + } + + priv->rx_conf = reg; + rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg); + + if (priv->r8185) { + reg = rtl818x_ioread8(priv, &priv->map->CW_CONF); + reg &= ~RTL818X_CW_CONF_PERPACKET_CW_SHIFT; + reg |= RTL818X_CW_CONF_PERPACKET_RETRY_SHIFT; + rtl818x_iowrite8(priv, &priv->map->CW_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->TX_AGC_CTL); + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_GAIN_SHIFT; + reg &= ~RTL818X_TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT; + reg |= RTL818X_TX_AGC_CTL_FEEDBACK_ANT; + rtl818x_iowrite8(priv, &priv->map->TX_AGC_CTL, reg); + + /* disable early TX */ + rtl818x_iowrite8(priv, (u8 __iomem *)priv->map + 0xec, 0x3f); + } + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg |= (6 << 21 /* MAX TX DMA */) | + RTL818X_TX_CONF_NO_ICV; + + if (priv->r8185) + reg &= ~RTL818X_TX_CONF_PROBE_DTS; + else + reg &= ~RTL818X_TX_CONF_HW_SEQNUM; + + /* different meaning, same value on both rtl8185 and rtl8180 */ + reg &= ~RTL818X_TX_CONF_SAT_HWPLCP; + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg |= RTL818X_CMD_RX_ENABLE; + reg |= RTL818X_CMD_TX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->mode = IEEE80211_IF_TYPE_MNTR; + return 0; + + err_free_rings: + rtl8180_free_rx_ring(dev); + for (i = 0; i < 4; i++) + if (priv->tx_ring[i].desc) + rtl8180_free_tx_ring(dev, i); + + return ret; +} + +static void rtl8180_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u8 reg; + int i; + + priv->mode = IEEE80211_IF_TYPE_INVALID; + + rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); + + reg = rtl818x_ioread8(priv, &priv->map->CMD); + reg &= ~RTL818X_CMD_TX_ENABLE; + reg &= ~RTL818X_CMD_RX_ENABLE; + rtl818x_iowrite8(priv, &priv->map->CMD, reg); + + priv->rf->stop(dev); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); + rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + free_irq(priv->pdev->irq, dev); + + rtl8180_free_rx_ring(dev); + for (i = 0; i < 4; i++) + rtl8180_free_tx_ring(dev, i); +} + +static int rtl8180_add_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + + if (priv->mode != IEEE80211_IF_TYPE_MNTR) + return -EOPNOTSUPP; + + switch (conf->type) { + case IEEE80211_IF_TYPE_STA: + priv->mode = conf->type; + break; + default: + return -EOPNOTSUPP; + } + + priv->vif = conf->vif; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], + cpu_to_le32(*(u32 *)conf->mac_addr)); + rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], + cpu_to_le16(*(u16 *)(conf->mac_addr + 4))); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + return 0; +} + +static void rtl8180_remove_interface(struct ieee80211_hw *dev, + struct ieee80211_if_init_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + priv->mode = IEEE80211_IF_TYPE_MNTR; + priv->vif = NULL; +} + +static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + + priv->rf->set_chan(dev, conf); + + return 0; +} + +static int rtl8180_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + for (i = 0; i < ETH_ALEN; i++) + rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); + + if (is_valid_ether_addr(conf->bssid)) + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_INFRA); + else + rtl818x_iowrite8(priv, &priv->map->MSR, RTL818X_MSR_NO_LINK); + + return 0; +} + +static void rtl8180_configure_filter(struct ieee80211_hw *dev, + unsigned int changed_flags, + unsigned int *total_flags, + int mc_count, struct dev_addr_list *mclist) +{ + struct rtl8180_priv *priv = dev->priv; + + if (changed_flags & FIF_FCSFAIL) + priv->rx_conf ^= RTL818X_RX_CONF_FCS; + if (changed_flags & FIF_CONTROL) + priv->rx_conf ^= RTL818X_RX_CONF_CTRL; + if (changed_flags & FIF_OTHER_BSS) + priv->rx_conf ^= RTL818X_RX_CONF_MONITOR; + if (*total_flags & FIF_ALLMULTI || mc_count > 0) + priv->rx_conf |= RTL818X_RX_CONF_MULTICAST; + else + priv->rx_conf &= ~RTL818X_RX_CONF_MULTICAST; + + *total_flags = 0; + + if (priv->rx_conf & RTL818X_RX_CONF_FCS) + *total_flags |= FIF_FCSFAIL; + if (priv->rx_conf & RTL818X_RX_CONF_CTRL) + *total_flags |= FIF_CONTROL; + if (priv->rx_conf & RTL818X_RX_CONF_MONITOR) + *total_flags |= FIF_OTHER_BSS; + if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST) + *total_flags |= FIF_ALLMULTI; + + rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf); +} + +static const struct ieee80211_ops rtl8180_ops = { + .tx = rtl8180_tx, + .start = rtl8180_start, + .stop = rtl8180_stop, + .add_interface = rtl8180_add_interface, + .remove_interface = rtl8180_remove_interface, + .config = rtl8180_config, + .config_interface = rtl8180_config_interface, + .configure_filter = rtl8180_configure_filter, +}; + +static void rtl8180_eeprom_register_read(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8180_priv *priv = dev->priv; + u8 reg = rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + + eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; + eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; + eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; + eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; +} + +static void rtl8180_eeprom_register_write(struct eeprom_93cx6 *eeprom) +{ + struct ieee80211_hw *dev = eeprom->data; + struct rtl8180_priv *priv = dev->priv; + u8 reg = 2 << 6; + + if (eeprom->reg_data_in) + reg |= RTL818X_EEPROM_CMD_WRITE; + if (eeprom->reg_data_out) + reg |= RTL818X_EEPROM_CMD_READ; + if (eeprom->reg_data_clock) + reg |= RTL818X_EEPROM_CMD_CK; + if (eeprom->reg_chip_select) + reg |= RTL818X_EEPROM_CMD_CS; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); +} + +static int __devinit rtl8180_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct ieee80211_hw *dev; + struct rtl8180_priv *priv; + unsigned long mem_addr, mem_len; + unsigned int io_addr, io_len; + int err, i; + struct eeprom_93cx6 eeprom; + const char *chip_name, *rf_name = NULL; + u32 reg; + u16 eeprom_val; + DECLARE_MAC_BUF(mac); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot enable new PCI device\n", + pci_name(pdev)); + return err; + } + + err = pci_request_regions(pdev, KBUILD_MODNAME); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot obtain PCI resources\n", + pci_name(pdev)); + return err; + } + + io_addr = pci_resource_start(pdev, 0); + io_len = pci_resource_len(pdev, 0); + mem_addr = pci_resource_start(pdev, 1); + mem_len = pci_resource_len(pdev, 1); + + if (mem_len < sizeof(struct rtl818x_csr) || + io_len < sizeof(struct rtl818x_csr)) { + printk(KERN_ERR "%s (rtl8180): Too short PCI resources\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + if ((err = pci_set_dma_mask(pdev, 0xFFFFFF00ULL)) || + (err = pci_set_consistent_dma_mask(pdev, 0xFFFFFF00ULL))) { + printk(KERN_ERR "%s (rtl8180): No suitable DMA available\n", + pci_name(pdev)); + goto err_free_reg; + } + + pci_set_master(pdev); + + dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8180_ops); + if (!dev) { + printk(KERN_ERR "%s (rtl8180): ieee80211 alloc failed\n", + pci_name(pdev)); + err = -ENOMEM; + goto err_free_reg; + } + + priv = dev->priv; + priv->pdev = pdev; + + SET_IEEE80211_DEV(dev, &pdev->dev); + pci_set_drvdata(pdev, dev); + + priv->map = pci_iomap(pdev, 1, mem_len); + if (!priv->map) + priv->map = pci_iomap(pdev, 0, io_len); + + if (!priv->map) { + printk(KERN_ERR "%s (rtl8180): Cannot map device memory\n", + pci_name(pdev)); + goto err_free_dev; + } + + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); + memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); + priv->modes[0].mode = MODE_IEEE80211G; + priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates); + priv->modes[0].rates = priv->rates; + priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels); + priv->modes[0].channels = priv->channels; + priv->modes[1].mode = MODE_IEEE80211B; + priv->modes[1].num_rates = 4; + priv->modes[1].rates = priv->rates; + priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); + priv->modes[1].channels = priv->channels; + priv->mode = IEEE80211_IF_TYPE_INVALID; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_RX_INCLUDES_FCS; + dev->queues = 1; + dev->max_rssi = 65; + + reg = rtl818x_ioread32(priv, &priv->map->TX_CONF); + reg &= RTL818X_TX_CONF_HWVER_MASK; + switch (reg) { + case RTL818X_TX_CONF_R8180_ABCD: + chip_name = "RTL8180"; + break; + case RTL818X_TX_CONF_R8180_F: + chip_name = "RTL8180vF"; + break; + case RTL818X_TX_CONF_R8185_ABC: + chip_name = "RTL8185"; + break; + case RTL818X_TX_CONF_R8185_D: + chip_name = "RTL8185vD"; + break; + default: + printk(KERN_ERR "%s (rtl8180): Unknown chip! (0x%x)\n", + pci_name(pdev), reg >> 25); + goto err_iounmap; + } + + priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; + if (priv->r8185) { + if ((err = ieee80211_register_hwmode(dev, &priv->modes[0]))) + goto err_iounmap; + + pci_try_set_mwi(pdev); + } + + if ((err = ieee80211_register_hwmode(dev, &priv->modes[1]))) + goto err_iounmap; + + eeprom.data = dev; + eeprom.register_read = rtl8180_eeprom_register_read; + eeprom.register_write = rtl8180_eeprom_register_write; + if (rtl818x_ioread32(priv, &priv->map->RX_CONF) & (1 << 6)) + eeprom.width = PCI_EEPROM_WIDTH_93C66; + else + eeprom.width = PCI_EEPROM_WIDTH_93C46; + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_PROGRAM); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + eeprom_93cx6_read(&eeprom, 0x06, &eeprom_val); + eeprom_val &= 0xFF; + switch (eeprom_val) { + case 1: rf_name = "Intersil"; + break; + case 2: rf_name = "RFMD"; + break; + case 3: priv->rf = &sa2400_rf_ops; + break; + case 4: priv->rf = &max2820_rf_ops; + break; + case 5: priv->rf = &grf5101_rf_ops; + break; + case 9: priv->rf = rtl8180_detect_rf(dev); + break; + case 10: + rf_name = "RTL8255"; + break; + default: + printk(KERN_ERR "%s (rtl8180): Unknown RF! (0x%x)\n", + pci_name(pdev), eeprom_val); + goto err_iounmap; + } + + if (!priv->rf) { + printk(KERN_ERR "%s (rtl8180): %s RF frontend not supported!\n", + pci_name(pdev), rf_name); + goto err_iounmap; + } + + eeprom_93cx6_read(&eeprom, 0x17, &eeprom_val); + priv->csthreshold = eeprom_val >> 8; + if (!priv->r8185) { + __le32 anaparam; + eeprom_93cx6_multiread(&eeprom, 0xD, (__le16 *)&anaparam, 2); + priv->anaparam = le32_to_cpu(anaparam); + eeprom_93cx6_read(&eeprom, 0x19, &priv->rfparam); + } + + eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *)dev->wiphy->perm_addr, 3); + if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { + printk(KERN_WARNING "%s (rtl8180): Invalid hwaddr! Using" + " randomly generated MAC addr\n", pci_name(pdev)); + random_ether_addr(dev->wiphy->perm_addr); + } + + /* CCK TX power */ + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); + priv->channels[i].val = txpwr & 0xFF; + priv->channels[i + 1].val = txpwr >> 8; + } + + /* OFDM TX power */ + if (priv->r8185) { + for (i = 0; i < 14; i += 2) { + u16 txpwr; + eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); + priv->channels[i].val |= (txpwr & 0xFF) << 8; + priv->channels[i + 1].val |= txpwr & 0xFF00; + } + } + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + spin_lock_init(&priv->lock); + + err = ieee80211_register_hw(dev); + if (err) { + printk(KERN_ERR "%s (rtl8180): Cannot register device\n", + pci_name(pdev)); + goto err_iounmap; + } + + printk(KERN_INFO "%s: hwaddr %s, %s + %s\n", + wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + chip_name, priv->rf->name); + + return 0; + + err_iounmap: + iounmap(priv->map); + + err_free_dev: + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(dev); + + err_free_reg: + pci_release_regions(pdev); + pci_disable_device(pdev); + return err; +} + +static void __devexit rtl8180_remove(struct pci_dev *pdev) +{ + struct ieee80211_hw *dev = pci_get_drvdata(pdev); + struct rtl8180_priv *priv; + + if (!dev) + return; + + ieee80211_unregister_hw(dev); + + priv = dev->priv; + + pci_iounmap(pdev, priv->map); + pci_release_regions(pdev); + pci_disable_device(pdev); + ieee80211_free_hw(dev); +} + +#ifdef CONFIG_PM +static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) +{ + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int rtl8180_resume(struct pci_dev *pdev) +{ + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + return 0; +} + +#endif /* CONFIG_PM */ + +static struct pci_driver rtl8180_driver = { + .name = KBUILD_MODNAME, + .id_table = rtl8180_table, + .probe = rtl8180_probe, + .remove = __devexit_p(rtl8180_remove), +#ifdef CONFIG_PM + .suspend = rtl8180_suspend, + .resume = rtl8180_resume, +#endif /* CONFIG_PM */ +}; + +static int __init rtl8180_init(void) +{ + return pci_register_driver(&rtl8180_driver); +} + +static void __exit rtl8180_exit(void) +{ + pci_unregister_driver(&rtl8180_driver); +} + +module_init(rtl8180_init); +module_exit(rtl8180_exit); diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c new file mode 100644 index 000000000000..8293e19c4c59 --- /dev/null +++ b/drivers/net/wireless/rtl8180_grf5101.c @@ -0,0 +1,179 @@ + +/* + * Radio tuning for GCT GRF5101 on RTL8180 + * + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <net/mac80211.h> + +#include "rtl8180.h" +#include "rtl8180_grf5101.h" + +static const int grf5101_encode[] = { + 0x0, 0x8, 0x4, 0xC, + 0x2, 0xA, 0x6, 0xE, + 0x1, 0x9, 0x5, 0xD, + 0x3, 0xB, 0x7, 0xF +}; + +static void write_grf5101(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + phy_config = grf5101_encode[(data >> 8) & 0xF]; + phy_config |= grf5101_encode[(data >> 4) & 0xF] << 4; + phy_config |= grf5101_encode[data & 0xF] << 8; + phy_config |= grf5101_encode[(addr >> 1) & 0xF] << 12; + phy_config |= (addr & 1) << 16; + phy_config |= grf5101_encode[(data & 0xf000) >> 12] << 24; + + /* MAC will bang bits to the chip */ + phy_config |= 0x90000000; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(3); +} + +static void grf5101_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant = GRF5101_ANTENNA; + + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); +} + +static void grf5101_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + u32 txpw = priv->channels[conf->channel - 1].val & 0xFF; + u32 chan = conf->channel - 1; + + /* set TX power */ + write_grf5101(dev, 0x15, 0x0); + write_grf5101(dev, 0x06, txpw); + write_grf5101(dev, 0x15, 0x10); + write_grf5101(dev, 0x15, 0x0); + + /* set frequency */ + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x0B, chan); + write_grf5101(dev, 0x07, 0x1000); + + grf5101_write_phy_antenna(dev, chan); +} + +static void grf5101_rf_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u32 anaparam; + + anaparam = priv->anaparam; + anaparam &= 0x000fffff; + anaparam |= 0x3f900000; + rtl8180_set_anaparam(priv, anaparam); + + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x1f, 0x45); + write_grf5101(dev, 0x1f, 0x5); + write_grf5101(dev, 0x00, 0x8e4); +} + +static void grf5101_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + rtl8180_set_anaparam(priv, priv->anaparam); + + write_grf5101(dev, 0x1f, 0x0); + write_grf5101(dev, 0x1f, 0x0); + write_grf5101(dev, 0x1f, 0x40); + write_grf5101(dev, 0x1f, 0x60); + write_grf5101(dev, 0x1f, 0x61); + write_grf5101(dev, 0x1f, 0x61); + write_grf5101(dev, 0x00, 0xae4); + write_grf5101(dev, 0x1f, 0x1); + write_grf5101(dev, 0x1f, 0x41); + write_grf5101(dev, 0x1f, 0x61); + + write_grf5101(dev, 0x01, 0x1a23); + write_grf5101(dev, 0x02, 0x4971); + write_grf5101(dev, 0x03, 0x41de); + write_grf5101(dev, 0x04, 0x2d80); + write_grf5101(dev, 0x05, 0x68ff); /* 0x61ff original value */ + write_grf5101(dev, 0x06, 0x0); + write_grf5101(dev, 0x07, 0x0); + write_grf5101(dev, 0x08, 0x7533); + write_grf5101(dev, 0x09, 0xc401); + write_grf5101(dev, 0x0a, 0x0); + write_grf5101(dev, 0x0c, 0x1c7); + write_grf5101(dev, 0x0d, 0x29d3); + write_grf5101(dev, 0x0e, 0x2e8); + write_grf5101(dev, 0x10, 0x192); + write_grf5101(dev, 0x11, 0x248); + write_grf5101(dev, 0x12, 0x0); + write_grf5101(dev, 0x13, 0x20c4); + write_grf5101(dev, 0x14, 0xf4fc); + write_grf5101(dev, 0x15, 0x0); + write_grf5101(dev, 0x16, 0x1500); + + write_grf5101(dev, 0x07, 0x1000); + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0xa8); + rtl8180_write_phy(dev, 3, 0x0); + rtl8180_write_phy(dev, 4, 0xc0); + rtl8180_write_phy(dev, 5, 0x90); + rtl8180_write_phy(dev, 6, 0x1e); + rtl8180_write_phy(dev, 7, 0x64); + + grf5101_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x88); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc0); /* enable ant diversity */ + else + rtl8180_write_phy(dev, 0x12, 0x40); /* disable ant diversity */ + + rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); + + rtl8180_write_phy(dev, 0x19, 0x0); + rtl8180_write_phy(dev, 0x1a, 0xa0); + rtl8180_write_phy(dev, 0x1b, 0x44); +} + +const struct rtl818x_rf_ops grf5101_rf_ops = { + .name = "GCT", + .init = grf5101_rf_init, + .stop = grf5101_rf_stop, + .set_chan = grf5101_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl8180_grf5101.h new file mode 100644 index 000000000000..76647111bcff --- /dev/null +++ b/drivers/net/wireless/rtl8180_grf5101.h @@ -0,0 +1,28 @@ +#ifndef RTL8180_GRF5101_H +#define RTL8180_GRF5101_H + +/* + * Radio tuning for GCT GRF5101 on RTL8180 + * + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * 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. + */ + +#define GRF5101_ANTENNA 0xA3 + +extern const struct rtl818x_rf_ops grf5101_rf_ops; + +#endif /* RTL8180_GRF5101_H */ diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c new file mode 100644 index 000000000000..98fe9fd64968 --- /dev/null +++ b/drivers/net/wireless/rtl8180_max2820.c @@ -0,0 +1,150 @@ +/* + * Radio tuning for Maxim max2820 on RTL8180 + * + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <net/mac80211.h> + +#include "rtl8180.h" +#include "rtl8180_max2820.h" + +static const u32 max2820_chan[] = { + 12, /* CH 1 */ + 17, + 22, + 27, + 32, + 37, + 42, + 47, + 52, + 57, + 62, + 67, + 72, + 84, /* CH 14 */ +}; + +static void write_max2820(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + phy_config = 0x90 + (data & 0xf); + phy_config <<= 16; + phy_config += addr; + phy_config <<= 8; + phy_config += (data >> 4) & 0xff; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(1); +} + +static void max2820_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant; + + ant = MAXIM_ANTENNA; + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); +} + +static void max2820_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + unsigned int chan_idx = conf ? conf->channel - 1 : 0; + u32 txpw = priv->channels[chan_idx].val & 0xFF; + u32 chan = max2820_chan[chan_idx]; + + /* While philips SA2400 drive the PA bias from + * sa2400, for MAXIM we do this directly from BB */ + rtl8180_write_phy(dev, 3, txpw); + + max2820_write_phy_antenna(dev, chan); + write_max2820(dev, 3, chan); +} + +static void max2820_rf_stop(struct ieee80211_hw *dev) +{ + rtl8180_write_phy(dev, 3, 0x8); + write_max2820(dev, 1, 0); +} + + +static void max2820_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + + /* MAXIM from netbsd driver */ + write_max2820(dev, 0, 0x007); /* test mode as indicated in datasheet */ + write_max2820(dev, 1, 0x01e); /* enable register */ + write_max2820(dev, 2, 0x001); /* synt register */ + + max2820_rf_set_channel(dev, NULL); + + write_max2820(dev, 4, 0x313); /* rx register */ + + /* PA is driven directly by the BB, we keep the MAXIM bias + * at the highest value in case that setting it to lower + * values may introduce some further attenuation somewhere.. + */ + write_max2820(dev, 5, 0x00f); + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0x88); /* sys1 */ + rtl8180_write_phy(dev, 3, 0x08); /* txagc */ + rtl8180_write_phy(dev, 4, 0xf8); /* lnadet */ + rtl8180_write_phy(dev, 5, 0x90); /* ifagcinit */ + rtl8180_write_phy(dev, 6, 0x1a); /* ifagclimit */ + rtl8180_write_phy(dev, 7, 0x64); /* ifagcdet */ + + max2820_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x88); /* trl */ + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc7); + else + rtl8180_write_phy(dev, 0x12, 0x47); + + rtl8180_write_phy(dev, 0x13, 0x9b); + + rtl8180_write_phy(dev, 0x19, 0x0); /* CHESTLIM */ + rtl8180_write_phy(dev, 0x1a, 0x9f); /* CHSQLIM */ + + max2820_rf_set_channel(dev, NULL); +} + +const struct rtl818x_rf_ops max2820_rf_ops = { + .name = "Maxim", + .init = max2820_rf_init, + .stop = max2820_rf_stop, + .set_chan = max2820_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl8180_max2820.h new file mode 100644 index 000000000000..61cf6d1e7d57 --- /dev/null +++ b/drivers/net/wireless/rtl8180_max2820.h @@ -0,0 +1,28 @@ +#ifndef RTL8180_MAX2820_H +#define RTL8180_MAX2820_H + +/* + * Radio tuning for Maxim max2820 on RTL8180 + * + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * 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. + */ + +#define MAXIM_ANTENNA 0xb3 + +extern const struct rtl818x_rf_ops max2820_rf_ops; + +#endif /* RTL8180_MAX2820_H */ diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl8180_rtl8225.c new file mode 100644 index 000000000000..ef3832bee85c --- /dev/null +++ b/drivers/net/wireless/rtl8180_rtl8225.c @@ -0,0 +1,779 @@ + +/* + * Radio tuning for RTL8225 on RTL8180 + * + * Copyright 2007 Michael Wu <flamingice@sourmilk.net> + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Based on the r8180 driver, which is: + * Copyright 2005 Andrea Merello <andreamrl@tiscali.it>, et al. + * + * Thanks to Realtek for their support! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <net/mac80211.h> + +#include "rtl8180.h" +#include "rtl8180_rtl8225.h" + +static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg80, reg84, reg82; + u32 bangdata; + int i; + + bangdata = (data << 4) | (addr & 0xf); + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput) & 0xfff3; + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x7); + + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x7 | 0x400); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + for (i = 15; i >= 0; i--) { + u16 reg = reg80 | !!(bangdata & (1 << i)); + + if (i & 1) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg | (1 << 1)); + + if (!(i & 1)) + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(10); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x400); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); +} + +static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg80, reg82, reg84, out; + int i; + + reg80 = rtl818x_ioread16(priv, &priv->map->RFPinsOutput); + reg82 = rtl818x_ioread16(priv, &priv->map->RFPinsEnable); + reg84 = rtl818x_ioread16(priv, &priv->map->RFPinsSelect) | 0x400; + + reg80 &= ~0xF; + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82 | 0x000F); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84 | 0x000F); + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(4); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(5); + + for (i = 4; i >= 0; i--) { + u16 reg = reg80 | ((addr >> i) & 1); + + if (!(i & 1)) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + if (i & 1) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + } + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x000E); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x040E); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + out = 0; + for (i = 11; i >= 0; i--) { + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(1); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 1)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + if (rtl818x_ioread16(priv, &priv->map->RFPinsInput) & (1 << 1)) + out |= 1 << i; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + } + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, + reg80 | (1 << 3) | (1 << 2)); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + udelay(2); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, reg82); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x03A0); + + return out; +} + +static const u16 rtl8225bcd_rxgain[] = { + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, + 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, + 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, + 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, + 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, + 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, + 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, + 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, + 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, + 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, + 0x07aa, 0x07ab, 0x07ac, 0x07ad, 0x07b0, 0x07b1, 0x07b2, 0x07b3, + 0x07b4, 0x07b5, 0x07b8, 0x07b9, 0x07ba, 0x07bb, 0x07bb +}; + +static const u8 rtl8225_agc[] = { + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, + 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, + 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, + 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, + 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, + 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, + 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, + 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, + 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, + 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +static const u8 rtl8225_gain[] = { + 0x23, 0x88, 0x7c, 0xa5, /* -82dbm */ + 0x23, 0x88, 0x7c, 0xb5, /* -82dbm */ + 0x23, 0x88, 0x7c, 0xc5, /* -82dbm */ + 0x33, 0x80, 0x79, 0xc5, /* -78dbm */ + 0x43, 0x78, 0x76, 0xc5, /* -74dbm */ + 0x53, 0x60, 0x73, 0xc5, /* -70dbm */ + 0x63, 0x58, 0x70, 0xc5, /* -66dbm */ +}; + +static const u8 rtl8225_threshold[] = { + 0x8d, 0x8d, 0x8d, 0x8d, 0x9d, 0xad, 0xbd +}; + +static const u8 rtl8225_tx_gain_cck_ofdm[] = { + 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e +}; + +static const u8 rtl8225_tx_power_cck[] = { + 0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02, + 0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02, + 0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02, + 0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02, + 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03 +}; + +static const u8 rtl8225_tx_power_cck_ch14[] = { + 0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225_tx_power_ofdm[] = { + 0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4 +}; + +static const u32 rtl8225_chan[] = { + 0x085c, 0x08dc, 0x095c, 0x09dc, 0x0a5c, 0x0adc, 0x0b5c, + 0x0bdc, 0x0c5c, 0x0cdc, 0x0d5c, 0x0ddc, 0x0e5c, 0x0f72 +}; + +static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + u32 reg; + int i; + + cck_power = priv->channels[channel - 1].val & 0xFF; + ofdm_power = priv->channels[channel - 1].val >> 8; + + cck_power = min(cck_power, (u8)35); + ofdm_power = min(ofdm_power, (u8)35); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, + rtl8225_tx_gain_cck_ofdm[cck_power / 6] >> 1); + + if (channel == 14) + tmp = &rtl8225_tx_power_cck_ch14[(cck_power % 6) * 8]; + else + tmp = &rtl8225_tx_power_cck[(cck_power % 6) * 8]; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + msleep(1); /* FIXME: optional? */ + + /* anaparam2 on */ + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_ON); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, + rtl8225_tx_gain_cck_ofdm[ofdm_power/6] >> 1); + + tmp = &rtl8225_tx_power_ofdm[ofdm_power % 6]; + + rtl8225_write_phy_ofdm(dev, 5, *tmp); + rtl8225_write_phy_ofdm(dev, 7, *tmp); + + msleep(1); +} + +static void rtl8225_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); + + /* host_pci_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(200); /* FIXME: ehh?? */ + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x000a8008); + + /* TODO: check if we need really to change BRSR to do RF config */ + rtl818x_ioread16(priv, &priv->map->BRSR); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8BE); + rtl8225_write(dev, 0x5, 0xBF0); /* TODO: minipci */ + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, rtl8225_chan[0]); + rtl8225_write(dev, 0x8, 0x01F); + rtl8225_write(dev, 0x9, 0x334); + rtl8225_write(dev, 0xA, 0xFD4); + rtl8225_write(dev, 0xB, 0x391); + rtl8225_write(dev, 0xC, 0x050); + rtl8225_write(dev, 0xD, 0x6DB); + rtl8225_write(dev, 0xE, 0x029); + rtl8225_write(dev, 0xF, 0x914); msleep(1); + + rtl8225_write(dev, 0x2, 0xC4D); msleep(100); + + rtl8225_write(dev, 0x0, 0x127); + + for (i = 0; i < ARRAY_SIZE(rtl8225bcd_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225bcd_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x027); + rtl8225_write(dev, 0x0, 0x22F); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + msleep(1); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + msleep(1); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x06, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x11, 0x03); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); + rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); + rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1); + rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); + rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); + rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); + rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); msleep(1); + + rtl8225_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + rtl8225_write(dev, 0x0c, 0x50); + /* set OFDM initial gain */ + rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[4 * 4]); + rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[4 * 4 + 1]); + rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[4 * 4 + 2]); + rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[4 * 4 + 3]); + /* set CCK threshold */ + rtl8225_write_phy_cck(dev, 0x41, rtl8225_threshold[0]); +} + +static const u8 rtl8225z2_tx_power_cck_ch14[] = { + 0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00 +}; + +static const u8 rtl8225z2_tx_power_cck_B[] = { + 0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x04 +}; + +static const u8 rtl8225z2_tx_power_cck_A[] = { + 0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04 +}; + +static const u8 rtl8225z2_tx_power_cck[] = { + 0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04 +}; + +static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) +{ + struct rtl8180_priv *priv = dev->priv; + u8 cck_power, ofdm_power; + const u8 *tmp; + int i; + + cck_power = priv->channels[channel - 1].val & 0xFF; + ofdm_power = priv->channels[channel - 1].val >> 8; + + if (channel == 14) + tmp = rtl8225z2_tx_power_cck_ch14; + else if (cck_power == 12) + tmp = rtl8225z2_tx_power_cck_B; + else if (cck_power == 13) + tmp = rtl8225z2_tx_power_cck_A; + else + tmp = rtl8225z2_tx_power_cck; + + for (i = 0; i < 8; i++) + rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); + + cck_power = min(cck_power, (u8)35); + if (cck_power == 13 || cck_power == 14) + cck_power = 12; + if (cck_power >= 15) + cck_power -= 2; + + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, cck_power); + rtl818x_ioread8(priv, &priv->map->TX_GAIN_CCK); + msleep(1); + + ofdm_power = min(ofdm_power, (u8)35); + rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, ofdm_power); + + rtl8225_write_phy_ofdm(dev, 2, 0x62); + rtl8225_write_phy_ofdm(dev, 5, 0x00); + rtl8225_write_phy_ofdm(dev, 6, 0x40); + rtl8225_write_phy_ofdm(dev, 7, 0x00); + rtl8225_write_phy_ofdm(dev, 8, 0x40); + + msleep(1); +} + +static const u16 rtl8225z2_rxgain[] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0008, 0x0009, + 0x000a, 0x000b, 0x0102, 0x0103, 0x0104, 0x0105, 0x0140, 0x0141, + 0x0142, 0x0143, 0x0144, 0x0145, 0x0180, 0x0181, 0x0182, 0x0183, + 0x0184, 0x0185, 0x0188, 0x0189, 0x018a, 0x018b, 0x0243, 0x0244, + 0x0245, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0288, + 0x0289, 0x028a, 0x028b, 0x028c, 0x0342, 0x0343, 0x0344, 0x0345, + 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0388, 0x0389, + 0x038a, 0x038b, 0x038c, 0x038d, 0x0390, 0x0391, 0x0392, 0x0393, + 0x0394, 0x0395, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, + 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a8, 0x03a9, + 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, + 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb +}; + +static void rtl8225z2_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + int i; + + rtl8180_set_anaparam(priv, RTL8225_ANAPARAM_ON); + + /* host_pci_init */ + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(200); /* FIXME: ehh?? */ + rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0xFF & ~(1 << 6)); + + rtl818x_iowrite32(priv, &priv->map->RF_TIMING, 0x00088008); + + /* TODO: check if we need really to change BRSR to do RF config */ + rtl818x_ioread16(priv, &priv->map->BRSR); + rtl818x_iowrite16(priv, &priv->map->BRSR, 0xFFFF); + rtl818x_iowrite32(priv, &priv->map->RF_PARA, 0x00100044); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, 0x44); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + rtl8225_write(dev, 0x0, 0x0B7); msleep(1); + rtl8225_write(dev, 0x1, 0xEE0); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); msleep(1); + rtl8225_write(dev, 0x3, 0x441); msleep(1); + rtl8225_write(dev, 0x4, 0x8C3); msleep(1); + rtl8225_write(dev, 0x5, 0xC72); msleep(1); + rtl8225_write(dev, 0x6, 0x0E6); msleep(1); + rtl8225_write(dev, 0x7, 0x82A); msleep(1); + rtl8225_write(dev, 0x8, 0x03F); msleep(1); + rtl8225_write(dev, 0x9, 0x335); msleep(1); + rtl8225_write(dev, 0xa, 0x9D4); msleep(1); + rtl8225_write(dev, 0xb, 0x7BB); msleep(1); + rtl8225_write(dev, 0xc, 0x850); msleep(1); + rtl8225_write(dev, 0xd, 0xCDF); msleep(1); + rtl8225_write(dev, 0xe, 0x02B); msleep(1); + rtl8225_write(dev, 0xf, 0x114); msleep(100); + + if (!(rtl8225_read(dev, 6) & (1 << 7))) { + rtl8225_write(dev, 0x02, 0x0C4D); + msleep(200); + rtl8225_write(dev, 0x02, 0x044D); + msleep(100); + /* TODO: readd calibration failure message when the calibration + check works */ + } + + rtl8225_write(dev, 0x0, 0x1B7); + rtl8225_write(dev, 0x3, 0x002); + rtl8225_write(dev, 0x5, 0x004); + + for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); + } + + rtl8225_write(dev, 0x0, 0x0B7); msleep(100); + rtl8225_write(dev, 0x2, 0xC4D); + + msleep(200); + rtl8225_write(dev, 0x2, 0x44D); + msleep(100); + + rtl8225_write(dev, 0x00, 0x2BF); + rtl8225_write(dev, 0xFF, 0xFFFF); + + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + + for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { + rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); + msleep(1); + rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); + msleep(1); + } + + msleep(1); + + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x02, 0x62); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x11); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1e, 0xb3); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); /* FIXME: not needed? */ + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + + rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); + rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); + rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); + rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x10, 0x93); msleep(1); + rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); + rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x13, 0xd0); + rtl8225_write_phy_cck(dev, 0x19, 0x00); + rtl8225_write_phy_cck(dev, 0x1a, 0xa0); + rtl8225_write_phy_cck(dev, 0x1b, 0x08); + rtl8225_write_phy_cck(dev, 0x40, 0x86); + rtl8225_write_phy_cck(dev, 0x41, 0x8a); msleep(1); + rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); + rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); + rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); + rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); + rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); + rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + + rtl818x_iowrite8(priv, (u8 __iomem *)((void __iomem *)priv->map + 0x5B), 0x0D); msleep(1); + + rtl8225z2_rf_set_tx_power(dev, 1); + + /* RX antenna default to A */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + + rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ + msleep(1); + rtl818x_iowrite32(priv, (__le32 __iomem *)((void __iomem *)priv->map + 0x94), 0x15c00002); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); +} + +static void rtl8225_rf_stop(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u8 reg; + + rtl8225_write(dev, 0x4, 0x1f); msleep(1); + + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); + reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg | RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM2, RTL8225_ANAPARAM2_OFF); + rtl818x_iowrite32(priv, &priv->map->ANAPARAM, RTL8225_ANAPARAM_OFF); + rtl818x_iowrite8(priv, &priv->map->CONFIG3, reg & ~RTL818X_CONFIG3_ANAPARAM_WRITE); + rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); +} + +static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + + if (priv->rf->init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, conf->channel); + else + rtl8225z2_rf_set_tx_power(dev, conf->channel); + + rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]); + msleep(10); + + if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 81); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x44); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 81); + rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); + } +} + +static const struct rtl818x_rf_ops rtl8225_ops = { + .name = "rtl8225", + .init = rtl8225_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u16 reg8, reg9; + + rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); + rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x0488); + rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); + rtl818x_ioread8(priv, &priv->map->EEPROM_CMD); + msleep(100); + + rtl8225_write(dev, 0, 0x1B7); + + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); + + rtl8225_write(dev, 0, 0x0B7); + + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; + + return &rtl8225z2_ops; +} diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl8180_rtl8225.h new file mode 100644 index 000000000000..310013a2d726 --- /dev/null +++ b/drivers/net/wireless/rtl8180_rtl8225.h @@ -0,0 +1,23 @@ +#ifndef RTL8180_RTL8225_H +#define RTL8180_RTL8225_H + +#define RTL8225_ANAPARAM_ON 0xa0000b59 +#define RTL8225_ANAPARAM2_ON 0x860dec11 +#define RTL8225_ANAPARAM_OFF 0xa00beb59 +#define RTL8225_ANAPARAM2_OFF 0x840dec11 + +const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *); + +static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, + u8 addr, u8 data) +{ + rtl8180_write_phy(dev, addr, data); +} + +static inline void rtl8225_write_phy_cck(struct ieee80211_hw *dev, + u8 addr, u8 data) +{ + rtl8180_write_phy(dev, addr, data | 0x10000); +} + +#endif /* RTL8180_RTL8225_H */ diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c new file mode 100644 index 000000000000..e08ace7b1cb7 --- /dev/null +++ b/drivers/net/wireless/rtl8180_sa2400.c @@ -0,0 +1,201 @@ + +/* + * Radio tuning for Philips SA2400 on RTL8180 + * + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <net/mac80211.h> + +#include "rtl8180.h" +#include "rtl8180_sa2400.h" + +static const u32 sa2400_chan[] = { + 0x00096c, /* ch1 */ + 0x080970, + 0x100974, + 0x180978, + 0x000980, + 0x080984, + 0x100988, + 0x18098c, + 0x000994, + 0x080998, + 0x10099c, + 0x1809a0, + 0x0009a8, + 0x0009b4, /* ch 14 */ +}; + +static void write_sa2400(struct ieee80211_hw *dev, u8 addr, u32 data) +{ + struct rtl8180_priv *priv = dev->priv; + u32 phy_config; + + /* MAC will bang bits to the sa2400. sw 3-wire is NOT used */ + phy_config = 0xb0000000; + + phy_config |= ((u32)(addr & 0xf)) << 24; + phy_config |= data & 0xffffff; + + rtl818x_iowrite32(priv, + (__le32 __iomem *) &priv->map->RFPinsOutput, phy_config); + + msleep(3); +} + +static void sa2400_write_phy_antenna(struct ieee80211_hw *dev, short chan) +{ + struct rtl8180_priv *priv = dev->priv; + u8 ant = SA2400_ANTENNA; + + if (priv->rfparam & RF_PARAM_ANTBDEFAULT) + ant |= BB_ANTENNA_B; + + if (chan == 14) + ant |= BB_ANTATTEN_CHAN14; + + rtl8180_write_phy(dev, 0x10, ant); + +} + +static void sa2400_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) +{ + struct rtl8180_priv *priv = dev->priv; + u32 txpw = priv->channels[conf->channel - 1].val & 0xFF; + u32 chan = sa2400_chan[conf->channel - 1]; + + write_sa2400(dev, 7, txpw); + + sa2400_write_phy_antenna(dev, chan); + + write_sa2400(dev, 0, chan); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); +} + +static void sa2400_rf_stop(struct ieee80211_hw *dev) +{ + write_sa2400(dev, 4, 0); +} + +static void sa2400_rf_init(struct ieee80211_hw *dev) +{ + struct rtl8180_priv *priv = dev->priv; + u32 anaparam, txconf; + u8 firdac; + int analogphy = priv->rfparam & RF_PARAM_ANALOGPHY; + + anaparam = priv->anaparam; + anaparam &= ~(1 << ANAPARAM_TXDACOFF_SHIFT); + anaparam &= ~ANAPARAM_PWR1_MASK; + anaparam &= ~ANAPARAM_PWR0_MASK; + + if (analogphy) { + anaparam |= SA2400_ANA_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT; + firdac = 0; + } else { + anaparam |= (SA2400_DIG_ANAPARAM_PWR1_ON << ANAPARAM_PWR1_SHIFT); + anaparam |= (SA2400_ANAPARAM_PWR0_ON << ANAPARAM_PWR0_SHIFT); + firdac = 1 << SA2400_REG4_FIRDAC_SHIFT; + } + + rtl8180_set_anaparam(priv, anaparam); + + write_sa2400(dev, 0, sa2400_chan[0]); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); + write_sa2400(dev, 4, 0x19340 | firdac); + write_sa2400(dev, 5, 0x1dfb | (SA2400_MAX_SENS - 54) << 15); + write_sa2400(dev, 4, 0x19348 | firdac); /* calibrate VCO */ + + if (!analogphy) + write_sa2400(dev, 4, 0x1938c); /*???*/ + + write_sa2400(dev, 4, 0x19340 | firdac); + + write_sa2400(dev, 0, sa2400_chan[0]); + write_sa2400(dev, 1, 0xbb50); + write_sa2400(dev, 2, 0x80); + write_sa2400(dev, 3, 0); + write_sa2400(dev, 4, 0x19344 | firdac); /* calibrate filter */ + + /* new from rtl8180 embedded driver (rtl8181 project) */ + write_sa2400(dev, 6, 0x13ff | (1 << 23)); /* MANRX */ + write_sa2400(dev, 8, 0); /* VCO */ + + if (analogphy) { + rtl8180_set_anaparam(priv, anaparam | + (1 << ANAPARAM_TXDACOFF_SHIFT)); + + txconf = rtl818x_ioread32(priv, &priv->map->TX_CONF); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + txconf | RTL818X_TX_CONF_LOOPBACK_CONT); + + write_sa2400(dev, 4, 0x19341); /* calibrates DC */ + + /* a 5us sleep is required here, + * we rely on the 3ms delay introduced in write_sa2400 */ + write_sa2400(dev, 4, 0x19345); + + /* a 20us sleep is required here, + * we rely on the 3ms delay introduced in write_sa2400 */ + + rtl818x_iowrite32(priv, &priv->map->TX_CONF, txconf); + + rtl8180_set_anaparam(priv, anaparam); + } + /* end new code */ + + write_sa2400(dev, 4, 0x19341 | firdac); /* RTX MODE */ + + /* baseband configuration */ + rtl8180_write_phy(dev, 0, 0x98); + rtl8180_write_phy(dev, 3, 0x38); + rtl8180_write_phy(dev, 4, 0xe0); + rtl8180_write_phy(dev, 5, 0x90); + rtl8180_write_phy(dev, 6, 0x1a); + rtl8180_write_phy(dev, 7, 0x64); + + sa2400_write_phy_antenna(dev, 1); + + rtl8180_write_phy(dev, 0x11, 0x80); + + if (rtl818x_ioread8(priv, &priv->map->CONFIG2) & + RTL818X_CONFIG2_ANTENNA_DIV) + rtl8180_write_phy(dev, 0x12, 0xc7); /* enable ant diversity */ + else + rtl8180_write_phy(dev, 0x12, 0x47); /* disable ant diversity */ + + rtl8180_write_phy(dev, 0x13, 0x90 | priv->csthreshold); + + rtl8180_write_phy(dev, 0x19, 0x0); + rtl8180_write_phy(dev, 0x1a, 0xa0); +} + +const struct rtl818x_rf_ops sa2400_rf_ops = { + .name = "Philips", + .init = sa2400_rf_init, + .stop = sa2400_rf_stop, + .set_chan = sa2400_rf_set_channel +}; diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl8180_sa2400.h new file mode 100644 index 000000000000..a4aaa0d413f1 --- /dev/null +++ b/drivers/net/wireless/rtl8180_sa2400.h @@ -0,0 +1,36 @@ +#ifndef RTL8180_SA2400_H +#define RTL8180_SA2400_H + +/* + * Radio tuning for Philips SA2400 on RTL8180 + * + * Copyright 2007 Andrea Merello <andreamrl@tiscali.it> + * + * Code from the BSD driver and the rtl8181 project have been + * very useful to understand certain things + * + * I want to thanks the Authors of such projects and the Ndiswrapper + * project Authors. + * + * A special Big Thanks also is for all people who donated me cards, + * making possible the creation of the original rtl8180 driver + * from which this code is derived! + * + * 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. + */ + +#define SA2400_ANTENNA 0x91 +#define SA2400_DIG_ANAPARAM_PWR1_ON 0x8 +#define SA2400_ANA_ANAPARAM_PWR1_ON 0x28 +#define SA2400_ANAPARAM_PWR0_ON 0x3 + +/* RX sensitivity in dbm */ +#define SA2400_MAX_SENS 85 + +#define SA2400_REG4_FIRDAC_SHIFT 7 + +extern const struct rtl818x_rf_ops sa2400_rf_ops; + +#endif /* RTL8180_SA2400_H */ diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 6ad322ef0da1..8680a0b6433c 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -64,9 +64,9 @@ struct rtl8187_tx_hdr { struct rtl8187_priv { /* common between rtl818x drivers */ struct rtl818x_csr *map; - void (*rf_init)(struct ieee80211_hw *); + const struct rtl818x_rf_ops *rf; + struct ieee80211_vif *vif; int mode; - int if_id; /* rtl8187 specific */ struct ieee80211_channel channels[14]; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index bd1ab3b3afc0..0d71716d750d 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -150,7 +150,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { flags |= RTL8187_TX_FLAG_RTS; - rts_dur = ieee80211_rts_duration(dev, priv->if_id, skb->len, control); + rts_dur = ieee80211_rts_duration(dev, priv->vif, + skb->len, control); } if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) flags |= RTL8187_TX_FLAG_CTS; @@ -227,6 +228,7 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.channel = dev->conf.channel; rx_status.phymode = dev->conf.phymode; rx_status.mactime = le64_to_cpu(hdr->mac_time); + rx_status.flag |= RX_FLAG_TSFT; if (flags & (1 << 13)) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; ieee80211_rx_irqsafe(dev, skb, &rx_status); @@ -392,37 +394,19 @@ static int rtl8187_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FF7); msleep(100); - priv->rf_init(dev); + priv->rf->init(dev); rtl818x_iowrite16(priv, &priv->map->BRSR, 0x01F3); - reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & 0xfffe; - rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 0x1); + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); rtl818x_iowrite16(priv, (__le16 *)0xFFFE, 0x10); rtl818x_iowrite8(priv, &priv->map->TALLY_SEL, 0x80); rtl818x_iowrite8(priv, (u8 *)0xFFFF, 0x60); - rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); return 0; } -static void rtl8187_set_channel(struct ieee80211_hw *dev, int channel) -{ - u32 reg; - struct rtl8187_priv *priv = dev->priv; - - 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 - * card will stop work until next reset - */ - rtl818x_iowrite32(priv, &priv->map->TX_CONF, - reg | RTL818X_TX_CONF_LOOPBACK_MAC); - msleep(10); - rtl8225_rf_set_channel(dev, channel); - msleep(10); - rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); -} - static int rtl8187_start(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; @@ -491,7 +475,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev) reg &= ~RTL818X_CMD_RX_ENABLE; rtl818x_iowrite8(priv, &priv->map->CMD, reg); - rtl8225_rf_stop(dev); + priv->rf->stop(dev); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG4); @@ -542,7 +526,19 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8187_priv *priv = dev->priv; - rtl8187_set_channel(dev, conf->channel); + u32 reg; + + 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 + * card will stop work until next reset + */ + rtl818x_iowrite32(priv, &priv->map->TX_CONF, + reg | RTL818X_TX_CONF_LOOPBACK_MAC); + msleep(10); + priv->rf->set_chan(dev, conf); + msleep(10); + rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); @@ -565,14 +561,13 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) return 0; } -static int rtl8187_config_interface(struct ieee80211_hw *dev, int if_id, +static int rtl8187_config_interface(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct rtl8187_priv *priv = dev->priv; int i; - priv->if_id = if_id; - for (i = 0; i < ETH_ALEN; i++) rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]); @@ -752,23 +747,16 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, &priv->txpwr_base); - reg = rtl818x_ioread16(priv, &priv->map->PGSELECT) & ~1; - rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg | 1); + reg = rtl818x_ioread8(priv, &priv->map->PGSELECT) & ~1; + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg | 1); /* 0 means asic B-cut, we should use SW 3 wire * bit-by-bit banging for radio. 1 means we can use * USB specific request to write radio registers */ priv->asic_rev = rtl818x_ioread8(priv, (u8 *)0xFFFE) & 0x3; - rtl818x_iowrite16(priv, &priv->map->PGSELECT, reg); + rtl818x_iowrite8(priv, &priv->map->PGSELECT, reg); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - rtl8225_write(dev, 0, 0x1B7); - - if (rtl8225_read(dev, 8) != 0x588 || rtl8225_read(dev, 9) != 0x700) - priv->rf_init = rtl8225_rf_init; - else - priv->rf_init = rtl8225z2_rf_init; - - rtl8225_write(dev, 0, 0x0B7); + priv->rf = rtl8187_detect_rf(dev); err = ieee80211_register_hw(dev); if (err) { @@ -778,8 +766,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n", wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), - priv->asic_rev, priv->rf_init == rtl8225_rf_init ? - "rtl8225" : "rtl8225z2"); + priv->asic_rev, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index efc41207780e..b713de17ba0a 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -101,7 +101,7 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) msleep(2); } -void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) +static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) { struct rtl8187_priv *priv = dev->priv; @@ -111,7 +111,7 @@ void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) rtl8225_write_bitbang(dev, addr, data); } -u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) +static u16 rtl8225_read(struct ieee80211_hw *dev, u8 addr) { struct rtl8187_priv *priv = dev->priv; u16 reg80, reg82, reg84, out; @@ -325,7 +325,7 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) msleep(1); } -void rtl8225_rf_init(struct ieee80211_hw *dev) +static void rtl8225_rf_init(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; int i; @@ -567,7 +567,7 @@ static const u8 rtl8225z2_gain_bg[] = { 0x63, 0x15, 0xc5 /* -66dBm */ }; -void rtl8225z2_rf_init(struct ieee80211_hw *dev) +static void rtl8225z2_rf_init(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; int i; @@ -715,7 +715,7 @@ void rtl8225z2_rf_init(struct ieee80211_hw *dev) rtl818x_iowrite32(priv, (__le32 *)0xFF94, 0x3dc00002); } -void rtl8225_rf_stop(struct ieee80211_hw *dev) +static void rtl8225_rf_stop(struct ieee80211_hw *dev) { u8 reg; struct rtl8187_priv *priv = dev->priv; @@ -731,15 +731,47 @@ void rtl8225_rf_stop(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); } -void rtl8225_rf_set_channel(struct ieee80211_hw *dev, int channel) +static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, + struct ieee80211_conf *conf) { struct rtl8187_priv *priv = dev->priv; - if (priv->rf_init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, channel); + if (priv->rf->init == rtl8225_rf_init) + rtl8225_rf_set_tx_power(dev, conf->channel); else - rtl8225z2_rf_set_tx_power(dev, channel); + rtl8225z2_rf_set_tx_power(dev, conf->channel); - rtl8225_write(dev, 0x7, rtl8225_chan[channel - 1]); + rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]); msleep(10); } + +static const struct rtl818x_rf_ops rtl8225_ops = { + .name = "rtl8225", + .init = rtl8225_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +static const struct rtl818x_rf_ops rtl8225z2_ops = { + .name = "rtl8225z2", + .init = rtl8225z2_rf_init, + .stop = rtl8225_rf_stop, + .set_chan = rtl8225_rf_set_channel +}; + +const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *dev) +{ + u16 reg8, reg9; + + rtl8225_write(dev, 0, 0x1B7); + + reg8 = rtl8225_read(dev, 8); + reg9 = rtl8225_read(dev, 9); + + rtl8225_write(dev, 0, 0x0B7); + + if (reg8 != 0x588 || reg9 != 0x700) + return &rtl8225_ops; + + return &rtl8225z2_ops; +} diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl8187_rtl8225.h index 798ba4a97376..d39ed0295b6e 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.h +++ b/drivers/net/wireless/rtl8187_rtl8225.h @@ -20,14 +20,7 @@ #define RTL8225_ANAPARAM_OFF 0xa00beb59 #define RTL8225_ANAPARAM2_OFF 0x840dec11 -void rtl8225_write(struct ieee80211_hw *, u8 addr, u16 data); -u16 rtl8225_read(struct ieee80211_hw *, u8 addr); - -void rtl8225_rf_init(struct ieee80211_hw *); -void rtl8225z2_rf_init(struct ieee80211_hw *); -void rtl8225_rf_stop(struct ieee80211_hw *); -void rtl8225_rf_set_channel(struct ieee80211_hw *, int); - +const struct rtl818x_rf_ops * rtl8187_detect_rf(struct ieee80211_hw *); static inline void rtl8225_write_phy_ofdm(struct ieee80211_hw *dev, u8 addr, u32 data) diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 880d4becae31..1e7d6f8278d7 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -58,13 +58,17 @@ struct rtl818x_csr { #define RTL818X_INT_TX_FO (1 << 15) __le32 TX_CONF; #define RTL818X_TX_CONF_LOOPBACK_MAC (1 << 17) +#define RTL818X_TX_CONF_LOOPBACK_CONT (3 << 17) #define RTL818X_TX_CONF_NO_ICV (1 << 19) #define RTL818X_TX_CONF_DISCW (1 << 20) +#define RTL818X_TX_CONF_SAT_HWPLCP (1 << 24) #define RTL818X_TX_CONF_R8180_ABCD (2 << 25) #define RTL818X_TX_CONF_R8180_F (3 << 25) #define RTL818X_TX_CONF_R8185_ABC (4 << 25) #define RTL818X_TX_CONF_R8185_D (5 << 25) #define RTL818X_TX_CONF_HWVER_MASK (7 << 25) +#define RTL818X_TX_CONF_PROBE_DTS (1 << 29) +#define RTL818X_TX_CONF_HW_SEQNUM (1 << 30) #define RTL818X_TX_CONF_CW_MIN (1 << 31) __le32 RX_CONF; #define RTL818X_RX_CONF_MONITOR (1 << 0) @@ -75,8 +79,12 @@ struct rtl818x_csr { #define RTL818X_RX_CONF_DATA (1 << 18) #define RTL818X_RX_CONF_CTRL (1 << 19) #define RTL818X_RX_CONF_MGMT (1 << 20) +#define RTL818X_RX_CONF_ADDR3 (1 << 21) +#define RTL818X_RX_CONF_PM (1 << 22) #define RTL818X_RX_CONF_BSSID (1 << 23) #define RTL818X_RX_CONF_RX_AUTORESETPHY (1 << 28) +#define RTL818X_RX_CONF_CSDM1 (1 << 29) +#define RTL818X_RX_CONF_CSDM2 (1 << 30) #define RTL818X_RX_CONF_ONLYERLPKT (1 << 31) __le32 INT_TIMEOUT; __le32 TBDA; @@ -92,6 +100,7 @@ struct rtl818x_csr { u8 CONFIG0; u8 CONFIG1; u8 CONFIG2; +#define RTL818X_CONFIG2_ANTENNA_DIV (1 << 6) __le32 ANAPARAM; u8 MSR; #define RTL818X_MSR_NO_LINK (0 << 2) @@ -104,14 +113,17 @@ struct rtl818x_csr { #define RTL818X_CONFIG4_VCOOFF (1 << 7) u8 TESTR; u8 reserved_9[2]; - __le16 PGSELECT; + u8 PGSELECT; + u8 SECURITY; __le32 ANAPARAM2; u8 reserved_10[12]; __le16 BEACON_INTERVAL; __le16 ATIM_WND; __le16 BEACON_INTERVAL_TIME; __le16 ATIMTR_INTERVAL; - u8 reserved_11[4]; + u8 PHY_DELAY; + u8 CARRIER_SENSE_COUNTER; + u8 reserved_11[2]; u8 PHY[4]; __le16 RFPinsOutput; __le16 RFPinsEnable; @@ -149,11 +161,20 @@ struct rtl818x_csr { u8 RETRY_CTR; u8 reserved_18[5]; __le32 RDSAR; - u8 reserved_19[18]; - u16 TALLY_CNT; + u8 reserved_19[12]; + __le16 FEMR; + u8 reserved_20[4]; + __le16 TALLY_CNT; u8 TALLY_SEL; } __attribute__((packed)); +struct rtl818x_rf_ops { + char *name; + void (*init)(struct ieee80211_hw *); + void (*stop)(struct ieee80211_hw *); + void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); +}; + static const struct ieee80211_rate rtl818x_rates[] = { { .rate = 10, .val = 0, diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index a1f8a1687842..03384a43186b 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -49,27 +49,6 @@ static int __init wv_psa_to_irq(u8 irqval) return -1; } -#ifdef STRUCT_CHECK -/*------------------------------------------------------------------*/ -/* - * Sanity routine to verify the sizes of the various WaveLAN interface - * structures. - */ -static char *wv_struct_check(void) -{ -#define SC(t,s,n) if (sizeof(t) != s) return(n); - - SC(psa_t, PSA_SIZE, "psa_t"); - SC(mmw_t, MMW_SIZE, "mmw_t"); - SC(mmr_t, MMR_SIZE, "mmr_t"); - SC(ha_t, HA_SIZE, "ha_t"); - -#undef SC - - return ((char *) NULL); -} /* wv_struct_check */ -#endif /* STRUCT_CHECK */ - /********************* HOST ADAPTER SUBROUTINES *********************/ /* * Useful subroutines to manage the WaveLAN ISA interface @@ -3740,7 +3719,7 @@ static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac) * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for detail on * how to configure your card. */ - for (i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) + for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) if ((mac[0] == MAC_ADDRESSES[i][0]) && (mac[1] == MAC_ADDRESSES[i][1]) && (mac[2] == MAC_ADDRESSES[i][2])) @@ -4215,14 +4194,11 @@ struct net_device * __init wavelan_probe(int unit) int i; int r = 0; -#ifdef STRUCT_CHECK - if (wv_struct_check() != (char *) NULL) { - printk(KERN_WARNING - "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", - dev->name, wv_struct_check()); - return -ENODEV; - } -#endif /* STRUCT_CHECK */ + /* compile-time check the sizes of structures */ + BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); + BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); + BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); + BUILD_BUG_ON(sizeof(ha_t) != HA_SIZE); dev = alloc_etherdev(sizeof(net_local)); if (!dev) diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index fe242812d858..b33ac47dd8df 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -400,7 +400,6 @@ */ #undef SET_PSA_CRC /* Calculate and set the CRC on PSA (slower) */ #define USE_PSA_CONFIG /* Use info from the PSA. */ -#undef STRUCT_CHECK /* Verify padding of structures. */ #undef EEPROM_IS_PROTECTED /* doesn't seem to be necessary */ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical). */ #undef SET_MAC_ADDRESS /* Experimental */ diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index 577c647824fe..c2037b2a05bf 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -71,27 +71,6 @@ static void wv_nwid_filter(unsigned char mode, net_local *lp); * (wavelan modem or i82593) */ -#ifdef STRUCT_CHECK -/*------------------------------------------------------------------*/ -/* - * Sanity routine to verify the sizes of the various WaveLAN interface - * structures. - */ -static char * -wv_structuct_check(void) -{ -#define SC(t,s,n) if (sizeof(t) != s) return(n); - - SC(psa_t, PSA_SIZE, "psa_t"); - SC(mmw_t, MMW_SIZE, "mmw_t"); - SC(mmr_t, MMR_SIZE, "mmr_t"); - -#undef SC - - return((char *) NULL); -} /* wv_structuct_check */ -#endif /* STRUCT_CHECK */ - /******************* MODEM MANAGEMENT SUBROUTINES *******************/ /* * Useful subroutines to manage the modem of the wavelan @@ -3223,14 +3202,14 @@ wv_mmc_init(struct net_device * dev) * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on * how to configure your card... */ - for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) - if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && - (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && - (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) + for (i = 0; i < ARRAY_SIZE(MAC_ADDRESSES); i++) + if ((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) && + (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) && + (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2])) break; /* If we have not found it... */ - if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3)) + if (i == ARRAY_SIZE(MAC_ADDRESSES)) { #ifdef DEBUG_CONFIG_ERRORS printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n", @@ -3794,14 +3773,10 @@ wv_hw_config(struct net_device * dev) printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name); #endif -#ifdef STRUCT_CHECK - if(wv_structuct_check() != (char *) NULL) - { - printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n", - dev->name, wv_structuct_check()); - return FALSE; - } -#endif /* STRUCT_CHECK == 1 */ + /* compile-time check the sizes of structures */ + BUILD_BUG_ON(sizeof(psa_t) != PSA_SIZE); + BUILD_BUG_ON(sizeof(mmw_t) != MMW_SIZE); + BUILD_BUG_ON(sizeof(mmr_t) != MMR_SIZE); /* Reset the pcmcia interface */ if(wv_pcmcia_reset(dev) == FALSE) diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 4b9de0093a7b..33dd97094227 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -459,7 +459,6 @@ #undef WAVELAN_ROAMING_EXT /* Enable roaming wireless extensions */ #undef SET_PSA_CRC /* Set the CRC in PSA (slower) */ #define USE_PSA_CONFIG /* Use info from the PSA */ -#undef STRUCT_CHECK /* Verify padding of structures */ #undef EEPROM_IS_PROTECTED /* Doesn't seem to be necessary */ #define MULTICAST_AVOID /* Avoid extra multicast (I'm sceptical) */ #undef SET_MAC_ADDRESS /* Experimental */ @@ -548,7 +547,7 @@ typedef struct wavepoint_beacon spec_id2, /* Unused */ pdu_type, /* Unused */ seq; /* WavePoint beacon sequence number */ - unsigned short domain_id, /* WavePoint Domain ID */ + __be16 domain_id, /* WavePoint Domain ID */ nwid; /* WavePoint NWID */ } wavepoint_beacon; diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig index d1ab24a95630..74b31eafe72d 100644 --- a/drivers/net/wireless/zd1211rw/Kconfig +++ b/drivers/net/wireless/zd1211rw/Kconfig @@ -1,14 +1,13 @@ config ZD1211RW tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" - depends on USB && IEEE80211_SOFTMAC && WLAN_80211 && EXPERIMENTAL - select WIRELESS_EXT + depends on USB && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER ---help--- This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless chip, present in many USB-wireless adapters. - Device firmware is required alongside this driver. You can download the - firmware distribution from http://zd1211.ath.cx/get-firmware + Device firmware is required alongside this driver. You can download + the firmware distribution from http://zd1211.ath.cx/get-firmware config ZD1211RW_DEBUG bool "ZyDAS ZD1211 debugging" diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile index 7a2f2a98edab..cc36126cee88 100644 --- a/drivers/net/wireless/zd1211rw/Makefile +++ b/drivers/net/wireless/zd1211rw/Makefile @@ -1,7 +1,6 @@ obj-$(CONFIG_ZD1211RW) += zd1211rw.o -zd1211rw-objs := zd_chip.o zd_ieee80211.o \ - zd_mac.o zd_netdev.o \ +zd1211rw-objs := zd_chip.o zd_ieee80211.o zd_mac.o \ zd_rf_al2230.o zd_rf_rf2959.o \ zd_rf_al7230b.o zd_rf_uw2453.o \ zd_rf.o zd_usb.o diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index f831b68f1b9c..99e5b03b3f51 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -1,4 +1,7 @@ -/* zd_chip.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,12 +33,12 @@ #include "zd_rf.h" void zd_chip_init(struct zd_chip *chip, - struct net_device *netdev, + struct ieee80211_hw *hw, struct usb_interface *intf) { memset(chip, 0, sizeof(*chip)); mutex_init(&chip->mutex); - zd_usb_init(&chip->usb, netdev, intf); + zd_usb_init(&chip->usb, hw, intf); zd_rf_init(&chip->rf); } @@ -50,7 +53,7 @@ void zd_chip_clear(struct zd_chip *chip) static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size) { - u8 *addr = zd_usb_to_netdev(&chip->usb)->dev_addr; + u8 *addr = zd_mac_get_perm_addr(zd_chip_to_mac(chip)); return scnprintf(buffer, size, "%02x-%02x-%02x", addr[0], addr[1], addr[2]); } @@ -378,15 +381,18 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) }; DECLARE_MAC_BUF(mac); - reqs[0].value = (mac_addr[3] << 24) - | (mac_addr[2] << 16) - | (mac_addr[1] << 8) - | mac_addr[0]; - reqs[1].value = (mac_addr[5] << 8) - | mac_addr[4]; - - dev_dbg_f(zd_chip_dev(chip), - "mac addr %s\n", print_mac(mac, mac_addr)); + if (mac_addr) { + reqs[0].value = (mac_addr[3] << 24) + | (mac_addr[2] << 16) + | (mac_addr[1] << 8) + | mac_addr[0]; + reqs[1].value = (mac_addr[5] << 8) + | mac_addr[4]; + dev_dbg_f(zd_chip_dev(chip), + "mac addr %s\n", print_mac(mac, mac_addr)); + } else { + dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n"); + } mutex_lock(&chip->mutex); r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs)); @@ -980,7 +986,7 @@ static int print_fw_version(struct zd_chip *chip) return 0; } -static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std) +static int set_mandatory_rates(struct zd_chip *chip, int mode) { u32 rates; ZD_ASSERT(mutex_is_locked(&chip->mutex)); @@ -988,11 +994,11 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std) * that the device is supporting. Until further notice we should try * to support 802.11g also for full speed USB. */ - switch (std) { - case IEEE80211B: + switch (mode) { + case MODE_IEEE80211B: rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M; break; - case IEEE80211G: + case MODE_IEEE80211G: rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M| CR_RATE_6M|CR_RATE_12M|CR_RATE_24M; break; @@ -1003,24 +1009,17 @@ static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std) } int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, - u8 rts_rate, int preamble) + int preamble) { - int rts_mod = ZD_RX_CCK; u32 value = 0; - /* Modulation bit */ - if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM) - rts_mod = ZD_RX_OFDM; - - dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n", - rts_rate, preamble); - - value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE; - value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE; + dev_dbg_f(zd_chip_dev(chip), "preamble=%x\n", preamble); value |= preamble << RTSCTS_SH_RTS_PMB_TYPE; value |= preamble << RTSCTS_SH_CTS_PMB_TYPE; - /* We always send 11M self-CTS messages, like the vendor driver. */ + /* We always send 11M RTS/self-CTS messages, like the vendor driver. */ + value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_RTS_RATE; + value |= ZD_RX_CCK << RTSCTS_SH_RTS_MOD_TYPE; value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE; value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE; @@ -1109,7 +1108,7 @@ int zd_chip_init_hw(struct zd_chip *chip) * It might be discussed, whether we should suppport pure b mode for * full speed USB. */ - r = set_mandatory_rates(chip, IEEE80211G); + r = set_mandatory_rates(chip, MODE_IEEE80211G); if (r) goto out; /* Disabling interrupts is certainly a smart thing here. @@ -1320,12 +1319,17 @@ out: return r; } -int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates) +int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) { - ZD_ASSERT((cr_rates & ~(CR_RATES_80211B | CR_RATES_80211G)) == 0); - dev_dbg_f(zd_chip_dev(chip), "%x\n", cr_rates); + int r; + + if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G)) + return -EINVAL; - return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); + mutex_lock(&chip->mutex); + r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL); + mutex_unlock(&chip->mutex); + return r; } static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size) @@ -1468,56 +1472,44 @@ u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, { return (status->frame_status&ZD_RX_OFDM) ? ofdm_qual_percent(status->signal_quality_ofdm, - zd_rate_from_ofdm_plcp_header(rx_frame), + zd_rate_from_ofdm_plcp_header(rx_frame), size) : cck_qual_percent(status->signal_quality_cck); } -u8 zd_rx_strength_percent(u8 rssi) -{ - int r = (rssi*100) / 41; - if (r > 100) - r = 100; - return (u8) r; -} - -u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status) +/** + * zd_rx_rate - report zd-rate + * @rx_frame - received frame + * @rx_status - rx_status as given by the device + * + * This function converts the rate as encoded in the received packet to the + * zd-rate, we are using on other places in the driver. + */ +u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status) { - static const u16 ofdm_rates[] = { - [ZD_OFDM_PLCP_RATE_6M] = 60, - [ZD_OFDM_PLCP_RATE_9M] = 90, - [ZD_OFDM_PLCP_RATE_12M] = 120, - [ZD_OFDM_PLCP_RATE_18M] = 180, - [ZD_OFDM_PLCP_RATE_24M] = 240, - [ZD_OFDM_PLCP_RATE_36M] = 360, - [ZD_OFDM_PLCP_RATE_48M] = 480, - [ZD_OFDM_PLCP_RATE_54M] = 540, - }; - u16 rate; + u8 zd_rate; if (status->frame_status & ZD_RX_OFDM) { - /* Deals with PLCP OFDM rate (not zd_rates) */ - u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame); - rate = ofdm_rates[ofdm_rate & 0xf]; + zd_rate = zd_rate_from_ofdm_plcp_header(rx_frame); } else { switch (zd_cck_plcp_header_signal(rx_frame)) { case ZD_CCK_PLCP_SIGNAL_1M: - rate = 10; + zd_rate = ZD_CCK_RATE_1M; break; case ZD_CCK_PLCP_SIGNAL_2M: - rate = 20; + zd_rate = ZD_CCK_RATE_2M; break; case ZD_CCK_PLCP_SIGNAL_5M5: - rate = 55; + zd_rate = ZD_CCK_RATE_5_5M; break; case ZD_CCK_PLCP_SIGNAL_11M: - rate = 110; + zd_rate = ZD_CCK_RATE_11M; break; default: - rate = 0; + zd_rate = 0; } } - return rate; + return zd_rate; } int zd_chip_switch_radio_on(struct zd_chip *chip) @@ -1557,20 +1549,22 @@ void zd_chip_disable_int(struct zd_chip *chip) mutex_unlock(&chip->mutex); } -int zd_chip_enable_rx(struct zd_chip *chip) +int zd_chip_enable_rxtx(struct zd_chip *chip) { int r; mutex_lock(&chip->mutex); + zd_usb_enable_tx(&chip->usb); r = zd_usb_enable_rx(&chip->usb); mutex_unlock(&chip->mutex); return r; } -void zd_chip_disable_rx(struct zd_chip *chip) +void zd_chip_disable_rxtx(struct zd_chip *chip) { mutex_lock(&chip->mutex); zd_usb_disable_rx(&chip->usb); + zd_usb_disable_tx(&chip->usb); mutex_unlock(&chip->mutex); } diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index 8009b70213e2..009c03777a35 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h @@ -1,4 +1,7 @@ -/* zd_chip.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -433,9 +436,10 @@ enum { #define CR_GROUP_HASH_P2 CTL_REG(0x0628) #define CR_RX_TIMEOUT CTL_REG(0x062C) + /* Basic rates supported by the BSS. When producing ACK or CTS messages, the * device will use a rate in this table that is less than or equal to the rate - * of the incoming frame which prompted the response */ + * of the incoming frame which prompted the response. */ #define CR_BASIC_RATE_TBL CTL_REG(0x0630) #define CR_RATE_1M (1 << 0) /* 802.11b */ #define CR_RATE_2M (1 << 1) /* 802.11b */ @@ -509,14 +513,37 @@ enum { #define CR_UNDERRUN_CNT CTL_REG(0x0688) #define CR_RX_FILTER CTL_REG(0x068c) +#define RX_FILTER_ASSOC_REQUEST (1 << 0) #define RX_FILTER_ASSOC_RESPONSE (1 << 1) +#define RX_FILTER_REASSOC_REQUEST (1 << 2) #define RX_FILTER_REASSOC_RESPONSE (1 << 3) +#define RX_FILTER_PROBE_REQUEST (1 << 4) #define RX_FILTER_PROBE_RESPONSE (1 << 5) +/* bits 6 and 7 reserved */ #define RX_FILTER_BEACON (1 << 8) +#define RX_FILTER_ATIM (1 << 9) #define RX_FILTER_DISASSOC (1 << 10) #define RX_FILTER_AUTH (1 << 11) -#define AP_RX_FILTER 0x0400feff -#define STA_RX_FILTER 0x0000ffff +#define RX_FILTER_DEAUTH (1 << 12) +#define RX_FILTER_PSPOLL (1 << 26) +#define RX_FILTER_RTS (1 << 27) +#define RX_FILTER_CTS (1 << 28) +#define RX_FILTER_ACK (1 << 29) +#define RX_FILTER_CFEND (1 << 30) +#define RX_FILTER_CFACK (1 << 31) + +/* Enable bits for all frames you are interested in. */ +#define STA_RX_FILTER (RX_FILTER_ASSOC_REQUEST | RX_FILTER_ASSOC_RESPONSE | \ + RX_FILTER_REASSOC_REQUEST | RX_FILTER_REASSOC_RESPONSE | \ + RX_FILTER_PROBE_REQUEST | RX_FILTER_PROBE_RESPONSE | \ + (0x3 << 6) /* vendor driver sets these reserved bits */ | \ + RX_FILTER_BEACON | RX_FILTER_ATIM | RX_FILTER_DISASSOC | \ + RX_FILTER_AUTH | RX_FILTER_DEAUTH | \ + (0x7 << 13) /* vendor driver sets these reserved bits */ | \ + RX_FILTER_PSPOLL | RX_FILTER_ACK) /* 0x2400ffff */ + +#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \ + RX_FILTER_CFEND | RX_FILTER_CFACK) /* Monitor mode sets filter to 0xfffff */ @@ -730,7 +757,7 @@ static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf) #define zd_chip_dev(chip) (&(chip)->usb.intf->dev) void zd_chip_init(struct zd_chip *chip, - struct net_device *netdev, + struct ieee80211_hw *hw, struct usb_interface *intf); void zd_chip_clear(struct zd_chip *chip); int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr); @@ -835,14 +862,12 @@ int zd_chip_switch_radio_on(struct zd_chip *chip); int zd_chip_switch_radio_off(struct zd_chip *chip); int zd_chip_enable_int(struct zd_chip *chip); void zd_chip_disable_int(struct zd_chip *chip); -int zd_chip_enable_rx(struct zd_chip *chip); -void zd_chip_disable_rx(struct zd_chip *chip); +int zd_chip_enable_rxtx(struct zd_chip *chip); +void zd_chip_disable_rxtx(struct zd_chip *chip); int zd_chip_enable_hwint(struct zd_chip *chip); int zd_chip_disable_hwint(struct zd_chip *chip); int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel); - -int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, - u8 rts_rate, int preamble); +int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, int preamble); static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type) { @@ -859,17 +884,7 @@ static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates) return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates); } -int zd_chip_set_basic_rates_locked(struct zd_chip *chip, u16 cr_rates); - -static inline int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) -{ - int r; - - mutex_lock(&chip->mutex); - r = zd_chip_set_basic_rates_locked(chip, cr_rates); - mutex_unlock(&chip->mutex); - return r; -} +int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates); int zd_chip_lock_phy_regs(struct zd_chip *chip); int zd_chip_unlock_phy_regs(struct zd_chip *chip); @@ -893,9 +908,8 @@ struct rx_status; u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, const struct rx_status *status); -u8 zd_rx_strength_percent(u8 rssi); -u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status); +u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status); struct zd_mc_hash { u32 low; diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h index 505b4d7dd0e2..5200db405610 100644 --- a/drivers/net/wireless/zd1211rw/zd_def.h +++ b/drivers/net/wireless/zd1211rw/zd_def.h @@ -1,4 +1,7 @@ -/* zd_def.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c index 189160efd2ae..7c277ec43f79 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c @@ -1,4 +1,7 @@ -/* zd_ieee80211.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,178 +19,85 @@ */ /* - * A lot of this code is generic and should be moved into the upper layers - * at some point. + * In the long term, we'll probably find a better way of handling regulatory + * requirements outside of the driver. */ -#include <linux/errno.h> -#include <linux/wireless.h> #include <linux/kernel.h> -#include <net/ieee80211.h> +#include <net/mac80211.h> -#include "zd_def.h" #include "zd_ieee80211.h" #include "zd_mac.h" +struct channel_range { + u8 regdomain; + u8 start; + u8 end; /* exclusive (channel must be less than end) */ +}; + static const struct channel_range channel_ranges[] = { - [0] = { 0, 0}, - [ZD_REGDOMAIN_FCC] = { 1, 12}, - [ZD_REGDOMAIN_IC] = { 1, 12}, - [ZD_REGDOMAIN_ETSI] = { 1, 14}, - [ZD_REGDOMAIN_JAPAN] = { 1, 14}, - [ZD_REGDOMAIN_SPAIN] = { 1, 14}, - [ZD_REGDOMAIN_FRANCE] = { 1, 14}, + { ZD_REGDOMAIN_FCC, 1, 12 }, + { ZD_REGDOMAIN_IC, 1, 12 }, + { ZD_REGDOMAIN_ETSI, 1, 14 }, + { ZD_REGDOMAIN_JAPAN, 1, 14 }, + { ZD_REGDOMAIN_SPAIN, 1, 14 }, + { ZD_REGDOMAIN_FRANCE, 1, 14 }, /* Japan originally only had channel 14 available (see CHNL_ID 0x40 in * 802.11). However, in 2001 the range was extended to include channels * 1-13. The ZyDAS devices still use the old region code but are * designed to allow the extra channel access in Japan. */ - [ZD_REGDOMAIN_JAPAN_ADD] = { 1, 15}, + { ZD_REGDOMAIN_JAPAN_ADD, 1, 15 }, }; -const struct channel_range *zd_channel_range(u8 regdomain) -{ - if (regdomain >= ARRAY_SIZE(channel_ranges)) - regdomain = 0; - return &channel_ranges[regdomain]; -} - -int zd_regdomain_supports_channel(u8 regdomain, u8 channel) -{ - const struct channel_range *range = zd_channel_range(regdomain); - return range->start <= channel && channel < range->end; -} - -int zd_regdomain_supported(u8 regdomain) -{ - const struct channel_range *range = zd_channel_range(regdomain); - return range->start != 0; -} - -/* Stores channel frequencies in MHz. */ -static const u16 channel_frequencies[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, 2472, 2484, -}; - -#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies) - -static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz) -{ - u32 factor; - - freq->e = 0; - if (mhz >= 1000000000U) { - pr_debug("zd1211 mhz %u to large\n", mhz); - freq->m = 0; - return -EINVAL; - } - - factor = 1000; - while (mhz >= factor) { - - freq->e += 1; - factor *= 10; - } - - factor /= 1000U; - freq->m = mhz * (1000000U/factor) + hz/factor; - - return 0; -} - -int zd_channel_to_freq(struct iw_freq *freq, u8 channel) +static const struct channel_range *zd_channel_range(u8 regdomain) { - if (channel > NUM_CHANNELS) { - freq->m = 0; - freq->e = 0; - return -EINVAL; - } - if (!channel) { - freq->m = 0; - freq->e = 0; - return -EINVAL; + int i; + for (i = 0; i < ARRAY_SIZE(channel_ranges); i++) { + const struct channel_range *range = &channel_ranges[i]; + if (range->regdomain == regdomain) + return range; } - return compute_freq(freq, channel_frequencies[channel-1], 0); + return NULL; } -static int freq_to_mhz(const struct iw_freq *freq) -{ - u32 factor; - int e; - - /* Such high frequencies are not supported. */ - if (freq->e > 6) - return -EINVAL; - - factor = 1; - for (e = freq->e; e > 0; --e) { - factor *= 10; - } - factor = 1000000U / factor; - - if (freq->m % factor) { - return -EINVAL; - } - - return freq->m / factor; -} +#define CHAN_TO_IDX(chan) ((chan) - 1) -int zd_find_channel(u8 *channel, const struct iw_freq *freq) +static void unmask_bg_channels(struct ieee80211_hw *hw, + const struct channel_range *range, + struct ieee80211_hw_mode *mode) { - int i, r; - u32 mhz; - - if (freq->m < 1000) { - if (freq->m > NUM_CHANNELS || freq->m == 0) - return -EINVAL; - *channel = freq->m; - return 1; - } - - r = freq_to_mhz(freq); - if (r < 0) - return r; - mhz = r; + u8 channel; - for (i = 0; i < NUM_CHANNELS; i++) { - if (mhz == channel_frequencies[i]) { - *channel = i+1; - return 1; - } + for (channel = range->start; channel < range->end; channel++) { + struct ieee80211_channel *chan = + &mode->channels[CHAN_TO_IDX(channel)]; + chan->flag |= IEEE80211_CHAN_W_SCAN | + IEEE80211_CHAN_W_ACTIVE_SCAN | + IEEE80211_CHAN_W_IBSS; } - - return -EINVAL; } -int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain) +void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain) { - struct ieee80211_geo geo; + struct zd_mac *mac = zd_hw_mac(hw); const struct channel_range *range; - int i; - u8 channel; - dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)), - "regdomain %#04x\n", regdomain); + dev_dbg(zd_mac_dev(mac), "regdomain %#02x\n", regdomain); range = zd_channel_range(regdomain); - if (range->start == 0) { - dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)), - "zd1211 regdomain %#04x not supported\n", - regdomain); - return -EINVAL; + if (!range) { + /* The vendor driver overrides the regulatory domain and + * allowed channel registers and unconditionally restricts + * available channels to 1-11 everywhere. Match their + * questionable behaviour only for regdomains which we don't + * recognise. */ + dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: " + "%#02x. Defaulting to FCC.\n", regdomain); + range = zd_channel_range(ZD_REGDOMAIN_FCC); } - memset(&geo, 0, sizeof(geo)); - - for (i = 0, channel = range->start; channel < range->end; channel++) { - struct ieee80211_channel *chan = &geo.bg[i++]; - chan->freq = channel_frequencies[channel - 1]; - chan->channel = channel; - } - - geo.bg_channels = i; - memcpy(geo.name, "XX ", 4); - ieee80211_set_geo(ieee, &geo); - return 0; + unmask_bg_channels(hw, range, &mac->modes[0]); + unmask_bg_channels(hw, range, &mac->modes[1]); } + diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h index fbf6491dce7e..26b79f197587 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h @@ -1,7 +1,27 @@ +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #ifndef _ZD_IEEE80211_H #define _ZD_IEEE80211_H -#include <net/ieee80211.h> +#include <net/mac80211.h> /* Additional definitions from the standards. */ @@ -19,22 +39,7 @@ enum { MAX_CHANNEL24 = 14, }; -struct channel_range { - u8 start; - u8 end; /* exclusive (channel must be less than end) */ -}; - -struct iw_freq; - -int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain); - -const struct channel_range *zd_channel_range(u8 regdomain); -int zd_regdomain_supports_channel(u8 regdomain, u8 channel); -int zd_regdomain_supported(u8 regdomain); - -/* for 2.4 GHz band */ -int zd_channel_to_freq(struct iw_freq *freq, u8 channel); -int zd_find_channel(u8 *channel, const struct iw_freq *freq); +void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain); #define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80 @@ -54,8 +59,8 @@ static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header) * * See the struct zd_ctrlset definition in zd_mac.h. */ -#define ZD_OFDM_PLCP_RATE_6M 0xb -#define ZD_OFDM_PLCP_RATE_9M 0xf +#define ZD_OFDM_PLCP_RATE_6M 0xb +#define ZD_OFDM_PLCP_RATE_9M 0xf #define ZD_OFDM_PLCP_RATE_12M 0xa #define ZD_OFDM_PLCP_RATE_18M 0xe #define ZD_OFDM_PLCP_RATE_24M 0x9 @@ -87,10 +92,4 @@ static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header) #define ZD_CCK_PLCP_SIGNAL_5M5 0x37 #define ZD_CCK_PLCP_SIGNAL_11M 0x6e -enum ieee80211_std { - IEEE80211B = 0x01, - IEEE80211A = 0x02, - IEEE80211G = 0x04, -}; - #endif /* _ZD_IEEE80211_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 5298a8bf1129..49127e4b42c2 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1,4 +1,9 @@ -/* zd_mac.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> + * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net> + * Copyright (c) 2007 Luis R. Rodriguez <mcgrof@winlab.rutgers.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 @@ -17,7 +22,6 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/wireless.h> #include <linux/usb.h> #include <linux/jiffies.h> #include <net/ieee80211_radiotap.h> @@ -26,81 +30,105 @@ #include "zd_chip.h" #include "zd_mac.h" #include "zd_ieee80211.h" -#include "zd_netdev.h" #include "zd_rf.h" -static void ieee_init(struct ieee80211_device *ieee); -static void softmac_init(struct ieee80211softmac_device *sm); -static void set_rts_cts_work(struct work_struct *work); -static void set_basic_rates_work(struct work_struct *work); +/* This table contains the hardware specific values for the modulation rates. */ +static const struct ieee80211_rate zd_rates[] = { + { .rate = 10, + .val = ZD_CCK_RATE_1M, + .flags = IEEE80211_RATE_CCK }, + { .rate = 20, + .val = ZD_CCK_RATE_2M, + .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 55, + .val = ZD_CCK_RATE_5_5M, + .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 110, + .val = ZD_CCK_RATE_11M, + .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_CCK_2 }, + { .rate = 60, + .val = ZD_OFDM_RATE_6M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 90, + .val = ZD_OFDM_RATE_9M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 120, + .val = ZD_OFDM_RATE_12M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 180, + .val = ZD_OFDM_RATE_18M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 240, + .val = ZD_OFDM_RATE_24M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 360, + .val = ZD_OFDM_RATE_36M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 480, + .val = ZD_OFDM_RATE_48M, + .flags = IEEE80211_RATE_OFDM }, + { .rate = 540, + .val = ZD_OFDM_RATE_54M, + .flags = IEEE80211_RATE_OFDM }, +}; + +static const struct ieee80211_channel zd_channels[] = { + { .chan = 1, + .freq = 2412}, + { .chan = 2, + .freq = 2417}, + { .chan = 3, + .freq = 2422}, + { .chan = 4, + .freq = 2427}, + { .chan = 5, + .freq = 2432}, + { .chan = 6, + .freq = 2437}, + { .chan = 7, + .freq = 2442}, + { .chan = 8, + .freq = 2447}, + { .chan = 9, + .freq = 2452}, + { .chan = 10, + .freq = 2457}, + { .chan = 11, + .freq = 2462}, + { .chan = 12, + .freq = 2467}, + { .chan = 13, + .freq = 2472}, + { .chan = 14, + .freq = 2484} +}; static void housekeeping_init(struct zd_mac *mac); static void housekeeping_enable(struct zd_mac *mac); static void housekeeping_disable(struct zd_mac *mac); -static void set_multicast_hash_handler(struct work_struct *work); - -static void do_rx(unsigned long mac_ptr); - -int zd_mac_init(struct zd_mac *mac, - struct net_device *netdev, - struct usb_interface *intf) -{ - struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev); - - memset(mac, 0, sizeof(*mac)); - spin_lock_init(&mac->lock); - mac->netdev = netdev; - INIT_DELAYED_WORK(&mac->set_rts_cts_work, set_rts_cts_work); - INIT_DELAYED_WORK(&mac->set_basic_rates_work, set_basic_rates_work); - - skb_queue_head_init(&mac->rx_queue); - tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac); - tasklet_disable(&mac->rx_tasklet); - - ieee_init(ieee); - softmac_init(ieee80211_priv(netdev)); - zd_chip_init(&mac->chip, netdev, intf); - housekeeping_init(mac); - INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); - return 0; -} - -static int reset_channel(struct zd_mac *mac) -{ - int r; - unsigned long flags; - const struct channel_range *range; - - spin_lock_irqsave(&mac->lock, flags); - range = zd_channel_range(mac->regdomain); - if (!range->start) { - r = -EINVAL; - goto out; - } - mac->requested_channel = range->start; - r = 0; -out: - spin_unlock_irqrestore(&mac->lock, flags); - return r; -} - -int zd_mac_preinit_hw(struct zd_mac *mac) +int zd_mac_preinit_hw(struct ieee80211_hw *hw) { int r; u8 addr[ETH_ALEN]; + struct zd_mac *mac = zd_hw_mac(hw); r = zd_chip_read_mac_addr_fw(&mac->chip, addr); if (r) return r; - memcpy(mac->netdev->dev_addr, addr, ETH_ALEN); + SET_IEEE80211_PERM_ADDR(hw, addr); + return 0; } -int zd_mac_init_hw(struct zd_mac *mac) +int zd_mac_init_hw(struct ieee80211_hw *hw) { int r; + struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; u8 default_regdomain; @@ -116,22 +144,9 @@ int zd_mac_init_hw(struct zd_mac *mac) r = zd_read_regdomain(chip, &default_regdomain); if (r) goto disable_int; - if (!zd_regdomain_supported(default_regdomain)) { - /* The vendor driver overrides the regulatory domain and - * allowed channel registers and unconditionally restricts - * available channels to 1-11 everywhere. Match their - * questionable behaviour only for regdomains which we don't - * recognise. */ - dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: " - "%#04x. Defaulting to FCC.\n", default_regdomain); - default_regdomain = ZD_REGDOMAIN_FCC; - } spin_lock_irq(&mac->lock); mac->regdomain = mac->default_regdomain = default_regdomain; spin_unlock_irq(&mac->lock); - r = reset_channel(mac); - if (r) - goto disable_int; /* We must inform the device that we are doing encryption/decryption in * software at the moment. */ @@ -139,9 +154,7 @@ int zd_mac_init_hw(struct zd_mac *mac) if (r) goto disable_int; - r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain); - if (r) - goto disable_int; + zd_geo_init(hw, mac->regdomain); r = 0; disable_int: @@ -153,8 +166,6 @@ out: void zd_mac_clear(struct zd_mac *mac) { flush_workqueue(zd_workqueue); - skb_queue_purge(&mac->rx_queue); - tasklet_kill(&mac->rx_tasklet); zd_chip_clear(&mac->chip); ZD_ASSERT(!spin_is_locked(&mac->lock)); ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); @@ -162,34 +173,27 @@ void zd_mac_clear(struct zd_mac *mac) static int set_rx_filter(struct zd_mac *mac) { - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; - return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); -} + unsigned long flags; + u32 filter = STA_RX_FILTER; -static int set_sniffer(struct zd_mac *mac) -{ - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - return zd_iowrite32(&mac->chip, CR_SNIFFER_ON, - ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0); - return 0; + spin_lock_irqsave(&mac->lock, flags); + if (mac->pass_ctrl) + filter |= RX_FILTER_CTRL; + spin_unlock_irqrestore(&mac->lock, flags); + + return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); } static int set_mc_hash(struct zd_mac *mac) { struct zd_mc_hash hash; - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - zd_mc_clear(&hash); - if (ieee->iw_mode == IW_MODE_MONITOR) - zd_mc_add_all(&hash); - return zd_chip_set_multicast_hash(&mac->chip, &hash); } -int zd_mac_open(struct net_device *netdev) +static int zd_op_start(struct ieee80211_hw *hw) { - struct zd_mac *mac = zd_netdev_mac(netdev); + struct zd_mac *mac = zd_hw_mac(hw); struct zd_chip *chip = &mac->chip; struct zd_usb *usb = &chip->usb; int r; @@ -200,46 +204,33 @@ int zd_mac_open(struct net_device *netdev) goto out; } - tasklet_enable(&mac->rx_tasklet); - r = zd_chip_enable_int(chip); if (r < 0) goto out; - r = zd_write_mac_addr(chip, netdev->dev_addr); - if (r) - goto disable_int; - r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G); if (r < 0) goto disable_int; r = set_rx_filter(mac); if (r) goto disable_int; - r = set_sniffer(mac); - if (r) - goto disable_int; r = set_mc_hash(mac); if (r) goto disable_int; r = zd_chip_switch_radio_on(chip); if (r < 0) goto disable_int; - r = zd_chip_set_channel(chip, mac->requested_channel); - if (r < 0) - goto disable_radio; - r = zd_chip_enable_rx(chip); + r = zd_chip_enable_rxtx(chip); if (r < 0) goto disable_radio; r = zd_chip_enable_hwint(chip); if (r < 0) - goto disable_rx; + goto disable_rxtx; housekeeping_enable(mac); - ieee80211softmac_start(netdev); return 0; -disable_rx: - zd_chip_disable_rx(chip); +disable_rxtx: + zd_chip_disable_rxtx(chip); disable_radio: zd_chip_switch_radio_off(chip); disable_int: @@ -248,494 +239,190 @@ out: return r; } -int zd_mac_stop(struct net_device *netdev) +/** + * clear_tx_skb_control_block - clears the control block of tx skbuffs + * @skb: a &struct sk_buff pointer + * + * This clears the control block of skbuff buffers, which were transmitted to + * the device. Notify that the function is not thread-safe, so prevent + * multiple calls. + */ +static void clear_tx_skb_control_block(struct sk_buff *skb) { - struct zd_mac *mac = zd_netdev_mac(netdev); - struct zd_chip *chip = &mac->chip; + struct zd_tx_skb_control_block *cb = + (struct zd_tx_skb_control_block *)skb->cb; - netif_stop_queue(netdev); + kfree(cb->control); + cb->control = NULL; +} - /* - * The order here deliberately is a little different from the open() +/** + * kfree_tx_skb - frees a tx skbuff + * @skb: a &struct sk_buff pointer + * + * Frees the tx skbuff. Frees also the allocated control structure in the + * control block if necessary. + */ +static void kfree_tx_skb(struct sk_buff *skb) +{ + clear_tx_skb_control_block(skb); + dev_kfree_skb_any(skb); +} + +static void zd_op_stop(struct ieee80211_hw *hw) +{ + struct zd_mac *mac = zd_hw_mac(hw); + struct zd_chip *chip = &mac->chip; + struct sk_buff *skb; + struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue; + + /* The order here deliberately is a little different from the open() * method, since we need to make sure there is no opportunity for RX - * frames to be processed by softmac after we have stopped it. + * frames to be processed by mac80211 after we have stopped it. */ - zd_chip_disable_rx(chip); - skb_queue_purge(&mac->rx_queue); - tasklet_disable(&mac->rx_tasklet); + zd_chip_disable_rxtx(chip); housekeeping_disable(mac); - ieee80211softmac_stop(netdev); - - /* Ensure no work items are running or queued from this point */ - cancel_delayed_work(&mac->set_rts_cts_work); - cancel_delayed_work(&mac->set_basic_rates_work); flush_workqueue(zd_workqueue); - mac->updating_rts_rate = 0; - mac->updating_basic_rates = 0; zd_chip_disable_hwint(chip); zd_chip_switch_radio_off(chip); zd_chip_disable_int(chip); - return 0; -} - -int zd_mac_set_mac_address(struct net_device *netdev, void *p) -{ - int r; - unsigned long flags; - struct sockaddr *addr = p; - struct zd_mac *mac = zd_netdev_mac(netdev); - struct zd_chip *chip = &mac->chip; - DECLARE_MAC_BUF(mac2); - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - - dev_dbg_f(zd_mac_dev(mac), - "Setting MAC to %s\n", print_mac(mac2, addr->sa_data)); - - if (netdev->flags & IFF_UP) { - r = zd_write_mac_addr(chip, addr->sa_data); - if (r) - return r; - } - - spin_lock_irqsave(&mac->lock, flags); - memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN); - spin_unlock_irqrestore(&mac->lock, flags); - - return 0; -} - -static void set_multicast_hash_handler(struct work_struct *work) -{ - struct zd_mac *mac = container_of(work, struct zd_mac, - set_multicast_hash_work); - struct zd_mc_hash hash; - - spin_lock_irq(&mac->lock); - hash = mac->multicast_hash; - spin_unlock_irq(&mac->lock); - zd_chip_set_multicast_hash(&mac->chip, &hash); + while ((skb = skb_dequeue(ack_wait_queue))) + kfree_tx_skb(skb); } -void zd_mac_set_multicast_list(struct net_device *dev) -{ - struct zd_mac *mac = zd_netdev_mac(dev); - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - struct zd_mc_hash hash; - struct dev_mc_list *mc; - unsigned long flags; - DECLARE_MAC_BUF(mac2); - - if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) || - ieee->iw_mode == IW_MODE_MONITOR) { - zd_mc_add_all(&hash); - } else { - zd_mc_clear(&hash); - for (mc = dev->mc_list; mc; mc = mc->next) { - dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", - print_mac(mac2, mc->dmi_addr)); - zd_mc_add_addr(&hash, mc->dmi_addr); - } - } - - spin_lock_irqsave(&mac->lock, flags); - mac->multicast_hash = hash; - spin_unlock_irqrestore(&mac->lock, flags); - queue_work(zd_workqueue, &mac->set_multicast_hash_work); -} - -int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain) -{ - int r; - u8 channel; - - ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&mac->lock); - if (regdomain == 0) { - regdomain = mac->default_regdomain; - } - if (!zd_regdomain_supported(regdomain)) { - spin_unlock_irq(&mac->lock); - return -EINVAL; - } - mac->regdomain = regdomain; - channel = mac->requested_channel; - spin_unlock_irq(&mac->lock); - - r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain); - if (r) - return r; - if (!zd_regdomain_supports_channel(regdomain, channel)) { - r = reset_channel(mac); - if (r) - return r; - } +/** + * init_tx_skb_control_block - initializes skb control block + * @skb: a &sk_buff pointer + * @dev: pointer to the mac80221 device + * @control: mac80211 tx control applying for the frame in @skb + * + * Initializes the control block of the skbuff to be transmitted. + */ +static int init_tx_skb_control_block(struct sk_buff *skb, + struct ieee80211_hw *hw, + struct ieee80211_tx_control *control) +{ + struct zd_tx_skb_control_block *cb = + (struct zd_tx_skb_control_block *)skb->cb; + + ZD_ASSERT(sizeof(*cb) <= sizeof(skb->cb)); + memset(cb, 0, sizeof(*cb)); + cb->hw= hw; + cb->control = kmalloc(sizeof(*control), GFP_ATOMIC); + if (cb->control == NULL) + return -ENOMEM; + memcpy(cb->control, control, sizeof(*control)); return 0; } -u8 zd_mac_get_regdomain(struct zd_mac *mac) -{ - unsigned long flags; - u8 regdomain; - - spin_lock_irqsave(&mac->lock, flags); - regdomain = mac->regdomain; - spin_unlock_irqrestore(&mac->lock, flags); - return regdomain; -} - -/* Fallback to lowest rate, if rate is unknown. */ -static u8 rate_to_zd_rate(u8 rate) -{ - switch (rate) { - case IEEE80211_CCK_RATE_2MB: - return ZD_CCK_RATE_2M; - case IEEE80211_CCK_RATE_5MB: - return ZD_CCK_RATE_5_5M; - case IEEE80211_CCK_RATE_11MB: - return ZD_CCK_RATE_11M; - case IEEE80211_OFDM_RATE_6MB: - return ZD_OFDM_RATE_6M; - case IEEE80211_OFDM_RATE_9MB: - return ZD_OFDM_RATE_9M; - case IEEE80211_OFDM_RATE_12MB: - return ZD_OFDM_RATE_12M; - case IEEE80211_OFDM_RATE_18MB: - return ZD_OFDM_RATE_18M; - case IEEE80211_OFDM_RATE_24MB: - return ZD_OFDM_RATE_24M; - case IEEE80211_OFDM_RATE_36MB: - return ZD_OFDM_RATE_36M; - case IEEE80211_OFDM_RATE_48MB: - return ZD_OFDM_RATE_48M; - case IEEE80211_OFDM_RATE_54MB: - return ZD_OFDM_RATE_54M; - } - return ZD_CCK_RATE_1M; -} - -static u16 rate_to_cr_rate(u8 rate) -{ - switch (rate) { - case IEEE80211_CCK_RATE_2MB: - return CR_RATE_1M; - case IEEE80211_CCK_RATE_5MB: - return CR_RATE_5_5M; - case IEEE80211_CCK_RATE_11MB: - return CR_RATE_11M; - case IEEE80211_OFDM_RATE_6MB: - return CR_RATE_6M; - case IEEE80211_OFDM_RATE_9MB: - return CR_RATE_9M; - case IEEE80211_OFDM_RATE_12MB: - return CR_RATE_12M; - case IEEE80211_OFDM_RATE_18MB: - return CR_RATE_18M; - case IEEE80211_OFDM_RATE_24MB: - return CR_RATE_24M; - case IEEE80211_OFDM_RATE_36MB: - return CR_RATE_36M; - case IEEE80211_OFDM_RATE_48MB: - return CR_RATE_48M; - case IEEE80211_OFDM_RATE_54MB: - return CR_RATE_54M; - } - return CR_RATE_1M; -} - -static void try_enable_tx(struct zd_mac *mac) -{ - unsigned long flags; - - spin_lock_irqsave(&mac->lock, flags); - if (mac->updating_rts_rate == 0 && mac->updating_basic_rates == 0) - netif_wake_queue(mac->netdev); - spin_unlock_irqrestore(&mac->lock, flags); -} - -static void set_rts_cts_work(struct work_struct *work) +/** + * tx_status - reports tx status of a packet if required + * @hw - a &struct ieee80211_hw pointer + * @skb - a sk-buffer + * @status - the tx status of the packet without control information + * @success - True for successfull transmission of the frame + * + * This information calls ieee80211_tx_status_irqsafe() if required by the + * control information. It copies the control information into the status + * information. + * + * If no status information has been requested, the skb is freed. + */ +static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_status *status, + bool success) { - struct zd_mac *mac = - container_of(work, struct zd_mac, set_rts_cts_work.work); - unsigned long flags; - u8 rts_rate; - unsigned int short_preamble; - - mutex_lock(&mac->chip.mutex); - - spin_lock_irqsave(&mac->lock, flags); - mac->updating_rts_rate = 0; - rts_rate = mac->rts_rate; - short_preamble = mac->short_preamble; - spin_unlock_irqrestore(&mac->lock, flags); - - zd_chip_set_rts_cts_rate_locked(&mac->chip, rts_rate, short_preamble); - mutex_unlock(&mac->chip.mutex); + struct zd_tx_skb_control_block *cb = (struct zd_tx_skb_control_block *) + skb->cb; - try_enable_tx(mac); + ZD_ASSERT(cb->control != NULL); + memcpy(&status->control, cb->control, sizeof(status->control)); + if (!success) + status->excessive_retries = 1; + clear_tx_skb_control_block(skb); + ieee80211_tx_status_irqsafe(hw, skb, status); } -static void set_basic_rates_work(struct work_struct *work) +/** + * zd_mac_tx_failed - callback for failed frames + * @dev: the mac80211 wireless device + * + * This function is called if a frame couldn't be succesfully be + * transferred. The first frame from the tx queue, will be selected and + * reported as error to the upper layers. + */ +void zd_mac_tx_failed(struct ieee80211_hw *hw) { - struct zd_mac *mac = - container_of(work, struct zd_mac, set_basic_rates_work.work); - unsigned long flags; - u16 basic_rates; - - mutex_lock(&mac->chip.mutex); - - spin_lock_irqsave(&mac->lock, flags); - mac->updating_basic_rates = 0; - basic_rates = mac->basic_rates; - spin_unlock_irqrestore(&mac->lock, flags); - - zd_chip_set_basic_rates_locked(&mac->chip, basic_rates); - mutex_unlock(&mac->chip.mutex); + struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; + struct sk_buff *skb; + struct ieee80211_tx_status status = {{0}}; - try_enable_tx(mac); + skb = skb_dequeue(q); + if (skb == NULL) + return; + tx_status(hw, skb, &status, 0); } -static void bssinfo_change(struct net_device *netdev, u32 changes) -{ - struct zd_mac *mac = zd_netdev_mac(netdev); - struct ieee80211softmac_device *softmac = ieee80211_priv(netdev); - struct ieee80211softmac_bss_info *bssinfo = &softmac->bssinfo; - int need_set_rts_cts = 0; - int need_set_rates = 0; - u16 basic_rates; - unsigned long flags; - - dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); - - if (changes & IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE) { - spin_lock_irqsave(&mac->lock, flags); - mac->short_preamble = bssinfo->short_preamble; - spin_unlock_irqrestore(&mac->lock, flags); - need_set_rts_cts = 1; - } - - if (changes & IEEE80211SOFTMAC_BSSINFOCHG_RATES) { - /* Set RTS rate to highest available basic rate */ - u8 hi_rate = ieee80211softmac_highest_supported_rate(softmac, - &bssinfo->supported_rates, 1); - hi_rate = rate_to_zd_rate(hi_rate); - - spin_lock_irqsave(&mac->lock, flags); - if (hi_rate != mac->rts_rate) { - mac->rts_rate = hi_rate; - need_set_rts_cts = 1; - } - spin_unlock_irqrestore(&mac->lock, flags); - - /* Set basic rates */ - need_set_rates = 1; - if (bssinfo->supported_rates.count == 0) { - /* Allow the device to be flexible */ - basic_rates = CR_RATES_80211B | CR_RATES_80211G; +/** + * zd_mac_tx_to_dev - callback for USB layer + * @skb: a &sk_buff pointer + * @error: error value, 0 if transmission successful + * + * Informs the MAC layer that the frame has successfully transferred to the + * device. If an ACK is required and the transfer to the device has been + * successful, the packets are put on the @ack_wait_queue with + * the control set removed. + */ +void zd_mac_tx_to_dev(struct sk_buff *skb, int error) +{ + struct zd_tx_skb_control_block *cb = + (struct zd_tx_skb_control_block *)skb->cb; + struct ieee80211_hw *hw = cb->hw; + + if (likely(cb->control)) { + skb_pull(skb, sizeof(struct zd_ctrlset)); + if (unlikely(error || + (cb->control->flags & IEEE80211_TXCTL_NO_ACK))) + { + struct ieee80211_tx_status status = {{0}}; + tx_status(hw, skb, &status, !error); } else { - int i = 0; - basic_rates = 0; - - for (i = 0; i < bssinfo->supported_rates.count; i++) { - u16 rate = bssinfo->supported_rates.rates[i]; - if ((rate & IEEE80211_BASIC_RATE_MASK) == 0) - continue; + struct sk_buff_head *q = + &zd_hw_mac(hw)->ack_wait_queue; - rate &= ~IEEE80211_BASIC_RATE_MASK; - basic_rates |= rate_to_cr_rate(rate); - } + skb_queue_tail(q, skb); + while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) + zd_mac_tx_failed(hw); } - spin_lock_irqsave(&mac->lock, flags); - mac->basic_rates = basic_rates; - spin_unlock_irqrestore(&mac->lock, flags); - } - - /* Schedule any changes we made above */ - - spin_lock_irqsave(&mac->lock, flags); - if (need_set_rts_cts && !mac->updating_rts_rate) { - mac->updating_rts_rate = 1; - netif_stop_queue(mac->netdev); - queue_delayed_work(zd_workqueue, &mac->set_rts_cts_work, 0); - } - if (need_set_rates && !mac->updating_basic_rates) { - mac->updating_basic_rates = 1; - netif_stop_queue(mac->netdev); - queue_delayed_work(zd_workqueue, &mac->set_basic_rates_work, - 0); - } - spin_unlock_irqrestore(&mac->lock, flags); -} - -static void set_channel(struct net_device *netdev, u8 channel) -{ - struct zd_mac *mac = zd_netdev_mac(netdev); - - dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel); - - zd_chip_set_channel(&mac->chip, channel); -} - -int zd_mac_request_channel(struct zd_mac *mac, u8 channel) -{ - unsigned long lock_flags; - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - - if (ieee->iw_mode == IW_MODE_INFRA) - return -EPERM; - - spin_lock_irqsave(&mac->lock, lock_flags); - if (!zd_regdomain_supports_channel(mac->regdomain, channel)) { - spin_unlock_irqrestore(&mac->lock, lock_flags); - return -EINVAL; - } - mac->requested_channel = channel; - spin_unlock_irqrestore(&mac->lock, lock_flags); - if (netif_running(mac->netdev)) - return zd_chip_set_channel(&mac->chip, channel); - else - return 0; -} - -u8 zd_mac_get_channel(struct zd_mac *mac) -{ - u8 channel = zd_chip_get_channel(&mac->chip); - - dev_dbg_f(zd_mac_dev(mac), "channel %u\n", channel); - return channel; -} - -int zd_mac_set_mode(struct zd_mac *mac, u32 mode) -{ - struct ieee80211_device *ieee; - - switch (mode) { - case IW_MODE_AUTO: - case IW_MODE_ADHOC: - case IW_MODE_INFRA: - mac->netdev->type = ARPHRD_ETHER; - break; - case IW_MODE_MONITOR: - mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP; - break; - default: - dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode); - return -EINVAL; - } - - ieee = zd_mac_to_ieee80211(mac); - ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&ieee->lock); - ieee->iw_mode = mode; - spin_unlock_irq(&ieee->lock); - - if (netif_running(mac->netdev)) { - int r = set_rx_filter(mac); - if (r) - return r; - return set_sniffer(mac); - } - - return 0; -} - -int zd_mac_get_mode(struct zd_mac *mac, u32 *mode) -{ - unsigned long flags; - struct ieee80211_device *ieee; - - ieee = zd_mac_to_ieee80211(mac); - spin_lock_irqsave(&ieee->lock, flags); - *mode = ieee->iw_mode; - spin_unlock_irqrestore(&ieee->lock, flags); - return 0; -} - -int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range) -{ - int i; - const struct channel_range *channel_range; - u8 regdomain; - - memset(range, 0, sizeof(*range)); - - /* FIXME: Not so important and depends on the mode. For 802.11g - * usually this value is used. It seems to be that Bit/s number is - * given here. - */ - range->throughput = 27 * 1000 * 1000; - - range->max_qual.qual = 100; - range->max_qual.level = 100; - - /* FIXME: Needs still to be tuned. */ - range->avg_qual.qual = 71; - range->avg_qual.level = 80; - - /* FIXME: depends on standard? */ - range->min_rts = 256; - range->max_rts = 2346; - - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - - range->max_encoding_tokens = WEP_KEYS; - range->num_encoding_sizes = 2; - range->encoding_size[0] = 5; - range->encoding_size[1] = WEP_KEY_LEN; - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 20; - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - ZD_ASSERT(!irqs_disabled()); - spin_lock_irq(&mac->lock); - regdomain = mac->regdomain; - spin_unlock_irq(&mac->lock); - channel_range = zd_channel_range(regdomain); - - range->num_channels = channel_range->end - channel_range->start; - range->old_num_channels = range->num_channels; - range->num_frequency = range->num_channels; - range->old_num_frequency = range->num_frequency; - - for (i = 0; i < range->num_frequency; i++) { - struct iw_freq *freq = &range->freq[i]; - freq->i = channel_range->start + i; - zd_channel_to_freq(freq, freq->i); + } else { + kfree_tx_skb(skb); } - - return 0; } static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) { /* ZD_PURE_RATE() must be used to remove the modulation type flag of - * the zd-rate values. */ + * the zd-rate values. + */ static const u8 rate_divisor[] = { - [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1, - [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2, - - /* bits must be doubled */ - [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11, - - [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11, - [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6, - [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9, - [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12, - [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18, - [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24, - [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36, - [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48, - [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54, + [ZD_PURE_RATE(ZD_CCK_RATE_1M)] = 1, + [ZD_PURE_RATE(ZD_CCK_RATE_2M)] = 2, + /* Bits must be doubled. */ + [ZD_PURE_RATE(ZD_CCK_RATE_5_5M)] = 11, + [ZD_PURE_RATE(ZD_CCK_RATE_11M)] = 11, + [ZD_PURE_RATE(ZD_OFDM_RATE_6M)] = 6, + [ZD_PURE_RATE(ZD_OFDM_RATE_9M)] = 9, + [ZD_PURE_RATE(ZD_OFDM_RATE_12M)] = 12, + [ZD_PURE_RATE(ZD_OFDM_RATE_18M)] = 18, + [ZD_PURE_RATE(ZD_OFDM_RATE_24M)] = 24, + [ZD_PURE_RATE(ZD_OFDM_RATE_36M)] = 36, + [ZD_PURE_RATE(ZD_OFDM_RATE_48M)] = 48, + [ZD_PURE_RATE(ZD_OFDM_RATE_54M)] = 54, }; u32 bits = (u32)tx_length * 8; @@ -764,34 +451,10 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) return bits/divisor; } -static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr_4addr *hdr) -{ - struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); - u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl)); - u8 rate; - int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0; - int is_multicast = is_multicast_ether_addr(hdr->addr1); - int short_preamble = ieee80211softmac_short_preamble_ok(softmac, - is_multicast, is_mgt); - - rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt); - cs->modulation = rate_to_zd_rate(rate); - - /* Set short preamble bit when appropriate */ - if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK - && cs->modulation != ZD_CCK_RATE_1M) - cs->modulation |= ZD_CCK_PREA_SHORT; -} - static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr_4addr *header) + struct ieee80211_hdr *header, u32 flags) { - struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev); - unsigned int tx_length = le16_to_cpu(cs->tx_length); - u16 fctl = le16_to_cpu(header->frame_ctl); - u16 ftype = WLAN_FC_GET_TYPE(fctl); - u16 stype = WLAN_FC_GET_STYPE(fctl); + u16 fctl = le16_to_cpu(header->frame_control); /* * CONTROL TODO: @@ -802,7 +465,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0) + if (flags & IEEE80211_TXCTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -810,54 +473,37 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control |= ZD_CS_MULTICAST; /* PS-POLL */ - if (ftype == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) + if ((fctl & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) == + (IEEE80211_FTYPE_CTL|IEEE80211_STYPE_PSPOLL)) cs->control |= ZD_CS_PS_POLL_FRAME; - /* Unicast data frames over the threshold should have RTS */ - if (!is_multicast_ether_addr(header->addr1) && - ftype != IEEE80211_FTYPE_MGMT && - tx_length > zd_netdev_ieee80211(mac->netdev)->rts) + if (flags & IEEE80211_TXCTL_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - /* Use CTS-to-self protection if required */ - if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM && - ieee80211softmac_protection_needed(softmac)) { - /* FIXME: avoid sending RTS *and* self-CTS, is that correct? */ - cs->control &= ~ZD_CS_RTS; + if (flags & IEEE80211_TXCTL_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; - } /* FIXME: Management frame? */ } static int fill_ctrlset(struct zd_mac *mac, - struct ieee80211_txb *txb, - int frag_num) + struct sk_buff *skb, + struct ieee80211_tx_control *control) { int r; - struct sk_buff *skb = txb->fragments[frag_num]; - struct ieee80211_hdr_4addr *hdr = - (struct ieee80211_hdr_4addr *) skb->data; - unsigned int frag_len = skb->len + IEEE80211_FCS_LEN; - unsigned int next_frag_len; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + unsigned int frag_len = skb->len + FCS_LEN; unsigned int packet_length; struct zd_ctrlset *cs = (struct zd_ctrlset *) skb_push(skb, sizeof(struct zd_ctrlset)); - if (frag_num+1 < txb->nr_frags) { - next_frag_len = txb->fragments[frag_num+1]->len + - IEEE80211_FCS_LEN; - } else { - next_frag_len = 0; - } ZD_ASSERT(frag_len <= 0xffff); - ZD_ASSERT(next_frag_len <= 0xffff); - cs_set_modulation(mac, cs, hdr); + cs->modulation = control->tx_rate; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr); + cs_set_control(mac, cs, hdr, control->flags); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -886,419 +532,417 @@ static int fill_ctrlset(struct zd_mac *mac, if (r < 0) return r; cs->current_length = cpu_to_le16(r); - - if (next_frag_len == 0) { - cs->next_frame_length = 0; - } else { - r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation), - next_frag_len); - if (r < 0) - return r; - cs->next_frame_length = cpu_to_le16(r); - } + cs->next_frame_length = 0; return 0; } -static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri) +/** + * zd_op_tx - transmits a network frame to the device + * + * @dev: mac80211 hardware device + * @skb: socket buffer + * @control: the control structure + * + * This function transmit an IEEE 802.11 network frame to the device. The + * control block of the skbuff will be initialized. If necessary the incoming + * mac80211 queues will be stopped. + */ +static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_control *control) { - int i, r; - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + struct zd_mac *mac = zd_hw_mac(hw); + int r; - for (i = 0; i < txb->nr_frags; i++) { - struct sk_buff *skb = txb->fragments[i]; + r = fill_ctrlset(mac, skb, control); + if (r) + return r; - r = fill_ctrlset(mac, txb, i); - if (r) { - ieee->stats.tx_dropped++; - return r; - } - r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len); - if (r) { - ieee->stats.tx_dropped++; - return r; - } + r = init_tx_skb_control_block(skb, hw, control); + if (r) + return r; + r = zd_usb_tx(&mac->chip.usb, skb); + if (r) { + clear_tx_skb_control_block(skb); + return r; } - - /* FIXME: shouldn't this be handled by the upper layers? */ - mac->netdev->trans_start = jiffies; - - ieee80211_txb_free(txb); return 0; } -struct zd_rt_hdr { - struct ieee80211_radiotap_header rt_hdr; - u8 rt_flags; - u8 rt_rate; - u16 rt_channel; - u16 rt_chbitmask; -} __attribute__((packed)); - -static void fill_rt_header(void *buffer, struct zd_mac *mac, - const struct ieee80211_rx_stats *stats, - const struct rx_status *status) -{ - struct zd_rt_hdr *hdr = buffer; - - hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; - hdr->rt_hdr.it_pad = 0; - hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr)); - hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_RATE)); - - hdr->rt_flags = 0; - if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256)) - hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP; - - hdr->rt_rate = stats->rate / 5; - - /* FIXME: 802.11a */ - hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz( - _zd_chip_get_channel(&mac->chip))); - hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ | - ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) == - ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK)); -} - -/* Returns 1 if the data packet is for us and 0 otherwise. */ -static int is_data_packet_for_us(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) -{ - struct net_device *netdev = ieee->dev; - u16 fc = le16_to_cpu(hdr->frame_ctl); - - ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA); - - switch (ieee->iw_mode) { - case IW_MODE_ADHOC: - if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || - compare_ether_addr(hdr->addr3, ieee->bssid) != 0) - return 0; - break; - case IW_MODE_AUTO: - case IW_MODE_INFRA: - if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != - IEEE80211_FCTL_FROMDS || - compare_ether_addr(hdr->addr2, ieee->bssid) != 0) - return 0; - break; - default: - ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR); - return 0; - } - - return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 || - (is_multicast_ether_addr(hdr->addr1) && - compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) || - (netdev->flags & IFF_PROMISC); -} - -/* Filters received packets. The function returns 1 if the packet should be - * forwarded to ieee80211_rx(). If the packet should be ignored the function - * returns 0. If an invalid packet is found the function returns -EINVAL. +/** + * filter_ack - filters incoming packets for acknowledgements + * @dev: the mac80211 device + * @rx_hdr: received header + * @stats: the status for the received packet * - * The function calls ieee80211_rx_mgt() directly. + * This functions looks for ACK packets and tries to match them with the + * frames in the tx queue. If a match is found the frame will be dequeued and + * the upper layers is informed about the successful transmission. If + * mac80211 queues have been stopped and the number of frames still to be + * transmitted is low the queues will be opened again. * - * It has been based on ieee80211_rx_any. + * Returns 1 if the frame was an ACK, 0 if it was ignored. */ -static int filter_rx(struct ieee80211_device *ieee, - const u8 *buffer, unsigned int length, - struct ieee80211_rx_stats *stats) +static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, + struct ieee80211_rx_status *stats) { - struct ieee80211_hdr_4addr *hdr; - u16 fc; - - if (ieee->iw_mode == IW_MODE_MONITOR) - return 1; - - hdr = (struct ieee80211_hdr_4addr *)buffer; - fc = le16_to_cpu(hdr->frame_ctl); - if ((fc & IEEE80211_FCTL_VERS) != 0) - return -EINVAL; + u16 fc = le16_to_cpu(rx_hdr->frame_control); + struct sk_buff *skb; + struct sk_buff_head *q; + unsigned long flags; - switch (WLAN_FC_GET_TYPE(fc)) { - case IEEE80211_FTYPE_MGMT: - if (length < sizeof(struct ieee80211_hdr_3addr)) - return -EINVAL; - ieee80211_rx_mgt(ieee, hdr, stats); - return 0; - case IEEE80211_FTYPE_CTL: + if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) != + (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK)) return 0; - case IEEE80211_FTYPE_DATA: - /* Ignore invalid short buffers */ - if (length < sizeof(struct ieee80211_hdr_3addr)) - return -EINVAL; - return is_data_packet_for_us(ieee, hdr); - } - return -EINVAL; + q = &zd_hw_mac(hw)->ack_wait_queue; + spin_lock_irqsave(&q->lock, flags); + for (skb = q->next; skb != (struct sk_buff *)q; skb = skb->next) { + struct ieee80211_hdr *tx_hdr; + + tx_hdr = (struct ieee80211_hdr *)skb->data; + if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1))) + { + struct ieee80211_tx_status status = {{0}}; + status.flags = IEEE80211_TX_STATUS_ACK; + status.ack_signal = stats->ssi; + __skb_unlink(skb, q); + tx_status(hw, skb, &status, 1); + goto out; + } + } +out: + spin_unlock_irqrestore(&q->lock, flags); + return 1; } -static void update_qual_rssi(struct zd_mac *mac, - const u8 *buffer, unsigned int length, - u8 qual_percent, u8 rssi_percent) +int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) { - unsigned long flags; - struct ieee80211_hdr_3addr *hdr; - int i; + struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_rx_status stats; + const struct rx_status *status; + struct sk_buff *skb; + int bad_frame = 0; + u16 fc; + bool is_qos, is_4addr, need_padding; - hdr = (struct ieee80211_hdr_3addr *)buffer; - if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) - return; - if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0) - return; + if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ + + FCS_LEN + sizeof(struct rx_status)) + return -EINVAL; - spin_lock_irqsave(&mac->lock, flags); - i = mac->stats_count % ZD_MAC_STATS_BUFFER_SIZE; - mac->qual_buffer[i] = qual_percent; - mac->rssi_buffer[i] = rssi_percent; - mac->stats_count++; - spin_unlock_irqrestore(&mac->lock, flags); -} + memset(&stats, 0, sizeof(stats)); -static int fill_rx_stats(struct ieee80211_rx_stats *stats, - const struct rx_status **pstatus, - struct zd_mac *mac, - const u8 *buffer, unsigned int length) -{ - const struct rx_status *status; + /* Note about pass_failed_fcs and pass_ctrl access below: + * mac locking intentionally omitted here, as this is the only unlocked + * reader and the only writer is configure_filter. Plus, if there were + * any races accessing these variables, it wouldn't really matter. + * If mac80211 ever provides a way for us to access filter flags + * from outside configure_filter, we could improve on this. Also, this + * situation may change once we implement some kind of DMA-into-skb + * RX path. */ - *pstatus = status = (struct rx_status *) + /* Caller has to ensure that length >= sizeof(struct rx_status). */ + status = (struct rx_status *) (buffer + (length - sizeof(struct rx_status))); if (status->frame_status & ZD_RX_ERROR) { - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - ieee->stats.rx_errors++; - if (status->frame_status & ZD_RX_TIMEOUT_ERROR) - ieee->stats.rx_missed_errors++; - else if (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) - ieee->stats.rx_fifo_errors++; - else if (status->frame_status & ZD_RX_DECRYPTION_ERROR) - ieee->ieee_stats.rx_discards_undecryptable++; - else if (status->frame_status & ZD_RX_CRC32_ERROR) { - ieee->stats.rx_crc_errors++; - ieee->ieee_stats.rx_fcs_errors++; + if (mac->pass_failed_fcs && + (status->frame_status & ZD_RX_CRC32_ERROR)) { + stats.flag |= RX_FLAG_FAILED_FCS_CRC; + bad_frame = 1; + } else { + return -EINVAL; } - else if (status->frame_status & ZD_RX_CRC16_ERROR) - ieee->stats.rx_crc_errors++; - return -EINVAL; } - memset(stats, 0, sizeof(struct ieee80211_rx_stats)); - stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN + - + sizeof(struct rx_status)); - /* FIXME: 802.11a */ - stats->freq = IEEE80211_24GHZ_BAND; - stats->received_channel = _zd_chip_get_channel(&mac->chip); - stats->rssi = zd_rx_strength_percent(status->signal_strength); - stats->signal = zd_rx_qual_percent(buffer, + stats.channel = _zd_chip_get_channel(&mac->chip); + stats.freq = zd_channels[stats.channel - 1].freq; + stats.phymode = MODE_IEEE80211G; + stats.ssi = status->signal_strength; + stats.signal = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); - stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL; - stats->rate = zd_rx_rate(buffer, status); - if (stats->rate) - stats->mask |= IEEE80211_STATMASK_RATE; + stats.rate = zd_rx_rate(buffer, status); + + length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status); + buffer += ZD_PLCP_HEADER_SIZE; + + /* Except for bad frames, filter each frame to see if it is an ACK, in + * which case our internal TX tracking is updated. Normally we then + * bail here as there's no need to pass ACKs on up to the stack, but + * there is also the case where the stack has requested us to pass + * control frames on up (pass_ctrl) which we must consider. */ + if (!bad_frame && + filter_ack(hw, (struct ieee80211_hdr *)buffer, &stats) + && !mac->pass_ctrl) + return 0; - return 0; -} + fc = le16_to_cpu(*((__le16 *) buffer)); -static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) -{ - int r; - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - struct ieee80211_rx_stats stats; - const struct rx_status *status; + is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && + ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA); + is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == + (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); + need_padding = is_qos ^ is_4addr; - if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + - IEEE80211_FCS_LEN + sizeof(struct rx_status)) - { - ieee->stats.rx_errors++; - ieee->stats.rx_length_errors++; - goto free_skb; + skb = dev_alloc_skb(length + (need_padding ? 2 : 0)); + if (skb == NULL) + return -ENOMEM; + if (need_padding) { + /* Make sure the the payload data is 4 byte aligned. */ + skb_reserve(skb, 2); } - r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); - if (r) { - /* Only packets with rx errors are included here. - * The error stats have already been set in fill_rx_stats. - */ - goto free_skb; - } + memcpy(skb_put(skb, length), buffer, length); - __skb_pull(skb, ZD_PLCP_HEADER_SIZE); - __skb_trim(skb, skb->len - - (IEEE80211_FCS_LEN + sizeof(struct rx_status))); + ieee80211_rx_irqsafe(hw, skb, &stats); + return 0; +} - ZD_ASSERT(IS_ALIGNED((unsigned long)skb->data, 4)); +static int zd_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) +{ + struct zd_mac *mac = zd_hw_mac(hw); - update_qual_rssi(mac, skb->data, skb->len, stats.signal, - status->signal_strength); + /* using IEEE80211_IF_TYPE_INVALID to indicate no mode selected */ + if (mac->type != IEEE80211_IF_TYPE_INVALID) + return -EOPNOTSUPP; - r = filter_rx(ieee, skb->data, skb->len, &stats); - if (r <= 0) { - if (r < 0) { - ieee->stats.rx_errors++; - dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); - } - goto free_skb; + switch (conf->type) { + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_STA: + mac->type = conf->type; + break; + default: + return -EOPNOTSUPP; } - if (ieee->iw_mode == IW_MODE_MONITOR) - fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac, - &stats, status); - - r = ieee80211_rx(ieee, skb, &stats); - if (r) - return; -free_skb: - /* We are always in a soft irq. */ - dev_kfree_skb(skb); + return zd_write_mac_addr(&mac->chip, conf->mac_addr); } -static void do_rx(unsigned long mac_ptr) +static void zd_op_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_if_init_conf *conf) { - struct zd_mac *mac = (struct zd_mac *)mac_ptr; - struct sk_buff *skb; + struct zd_mac *mac = zd_hw_mac(hw); + mac->type = IEEE80211_IF_TYPE_INVALID; + zd_write_mac_addr(&mac->chip, NULL); +} - while ((skb = skb_dequeue(&mac->rx_queue)) != NULL) - zd_mac_rx(mac, skb); +static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +{ + struct zd_mac *mac = zd_hw_mac(hw); + return zd_chip_set_channel(&mac->chip, conf->channel); } -int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) +static int zd_op_config_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_if_conf *conf) { - struct sk_buff *skb; - unsigned int reserved = - ALIGN(max_t(unsigned int, - sizeof(struct zd_rt_hdr), ZD_PLCP_HEADER_SIZE), 4) - - ZD_PLCP_HEADER_SIZE; - - skb = dev_alloc_skb(reserved + length); - if (!skb) { - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); - ieee->stats.rx_dropped++; - return -ENOMEM; - } - skb_reserve(skb, reserved); - memcpy(__skb_put(skb, length), buffer, length); - skb_queue_tail(&mac->rx_queue, skb); - tasklet_schedule(&mac->rx_tasklet); + struct zd_mac *mac = zd_hw_mac(hw); + + spin_lock_irq(&mac->lock); + mac->associated = is_valid_ether_addr(conf->bssid); + spin_unlock_irq(&mac->lock); + + /* TODO: do hardware bssid filtering */ return 0; } -static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev, - int pri) +static void set_multicast_hash_handler(struct work_struct *work) { - return zd_mac_tx(zd_netdev_mac(netdev), txb, pri); + struct zd_mac *mac = + container_of(work, struct zd_mac, set_multicast_hash_work); + struct zd_mc_hash hash; + + spin_lock_irq(&mac->lock); + hash = mac->multicast_hash; + spin_unlock_irq(&mac->lock); + + zd_chip_set_multicast_hash(&mac->chip, &hash); } -static void set_security(struct net_device *netdev, - struct ieee80211_security *sec) +static void set_rx_filter_handler(struct work_struct *work) { - struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev); - struct ieee80211_security *secinfo = &ieee->sec; - int keyidx; - - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n"); - - for (keyidx = 0; keyidx<WEP_KEYS; keyidx++) - if (sec->flags & (1<<keyidx)) { - secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx]; - secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; - memcpy(secinfo->keys[keyidx], sec->keys[keyidx], - SCM_KEY_LEN); - } + struct zd_mac *mac = + container_of(work, struct zd_mac, set_rx_filter_work); + int r; - if (sec->flags & SEC_ACTIVE_KEY) { - secinfo->active_key = sec->active_key; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .active_key = %d\n", sec->active_key); - } - if (sec->flags & SEC_UNICAST_GROUP) { - secinfo->unicast_uses_group = sec->unicast_uses_group; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .unicast_uses_group = %d\n", - sec->unicast_uses_group); - } - if (sec->flags & SEC_LEVEL) { - secinfo->level = sec->level; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .level = %d\n", sec->level); - } - if (sec->flags & SEC_ENABLED) { - secinfo->enabled = sec->enabled; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .enabled = %d\n", sec->enabled); - } - if (sec->flags & SEC_ENCRYPT) { - secinfo->encrypt = sec->encrypt; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .encrypt = %d\n", sec->encrypt); - } - if (sec->flags & SEC_AUTH_MODE) { - secinfo->auth_mode = sec->auth_mode; - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), - " .auth_mode = %d\n", sec->auth_mode); + dev_dbg_f(zd_mac_dev(mac), "\n"); + r = set_rx_filter(mac); + if (r) + dev_err(zd_mac_dev(mac), "set_rx_filter_handler error %d\n", r); +} + +#define SUPPORTED_FIF_FLAGS \ + (FIF_PROMISC_IN_BSS | FIF_ALLMULTI | FIF_FCSFAIL | FIF_CONTROL | \ + FIF_OTHER_BSS) +static void zd_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *new_flags, + int mc_count, struct dev_mc_list *mclist) +{ + struct zd_mc_hash hash; + struct zd_mac *mac = zd_hw_mac(hw); + unsigned long flags; + int i; + + /* Only deal with supported flags */ + changed_flags &= SUPPORTED_FIF_FLAGS; + *new_flags &= SUPPORTED_FIF_FLAGS; + + /* changed_flags is always populated but this driver + * doesn't support all FIF flags so its possible we don't + * need to do anything */ + if (!changed_flags) + return; + + if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { + zd_mc_add_all(&hash); + } else { + DECLARE_MAC_BUF(macbuf); + + zd_mc_clear(&hash); + for (i = 0; i < mc_count; i++) { + if (!mclist) + break; + dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", + print_mac(macbuf, mclist->dmi_addr)); + zd_mc_add_addr(&hash, mclist->dmi_addr); + mclist = mclist->next; + } } + + spin_lock_irqsave(&mac->lock, flags); + mac->pass_failed_fcs = !!(*new_flags & FIF_FCSFAIL); + mac->pass_ctrl = !!(*new_flags & FIF_CONTROL); + mac->multicast_hash = hash; + spin_unlock_irqrestore(&mac->lock, flags); + queue_work(zd_workqueue, &mac->set_multicast_hash_work); + + if (changed_flags & FIF_CONTROL) + queue_work(zd_workqueue, &mac->set_rx_filter_work); + + /* no handling required for FIF_OTHER_BSS as we don't currently + * do BSSID filtering */ + /* FIXME: in future it would be nice to enable the probe response + * filter (so that the driver doesn't see them) until + * FIF_BCN_PRBRESP_PROMISC is set. however due to atomicity here, we'd + * have to schedule work to enable prbresp reception, which might + * happen too late. For now we'll just listen and forward them all the + * time. */ } -static void ieee_init(struct ieee80211_device *ieee) +static void set_rts_cts_work(struct work_struct *work) { - ieee->mode = IEEE_B | IEEE_G; - ieee->freq_band = IEEE80211_24GHZ_BAND; - ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION; - ieee->tx_headroom = sizeof(struct zd_ctrlset); - ieee->set_security = set_security; - ieee->hard_start_xmit = netdev_tx; - - /* Software encryption/decryption for now */ - ieee->host_build_iv = 0; - ieee->host_encrypt = 1; - ieee->host_decrypt = 1; - - /* FIXME: default to managed mode, until ieee80211 and zd1211rw can - * correctly support AUTO */ - ieee->iw_mode = IW_MODE_INFRA; + struct zd_mac *mac = + container_of(work, struct zd_mac, set_rts_cts_work); + unsigned long flags; + unsigned int short_preamble; + + mutex_lock(&mac->chip.mutex); + + spin_lock_irqsave(&mac->lock, flags); + mac->updating_rts_rate = 0; + short_preamble = mac->short_preamble; + spin_unlock_irqrestore(&mac->lock, flags); + + zd_chip_set_rts_cts_rate_locked(&mac->chip, short_preamble); + mutex_unlock(&mac->chip.mutex); } -static void softmac_init(struct ieee80211softmac_device *sm) +static void zd_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf, + u32 changes) { - sm->set_channel = set_channel; - sm->bssinfo_change = bssinfo_change; + struct zd_mac *mac = zd_hw_mac(hw); + unsigned long flags; + + dev_dbg_f(zd_mac_dev(mac), "changes: %x\n", changes); + + if (changes & BSS_CHANGED_ERP_PREAMBLE) { + spin_lock_irqsave(&mac->lock, flags); + mac->short_preamble = bss_conf->use_short_preamble; + if (!mac->updating_rts_rate) { + mac->updating_rts_rate = 1; + /* FIXME: should disable TX here, until work has + * completed and RTS_CTS reg is updated */ + queue_work(zd_workqueue, &mac->set_rts_cts_work); + } + spin_unlock_irqrestore(&mac->lock, flags); + } } -struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev) +static const struct ieee80211_ops zd_ops = { + .tx = zd_op_tx, + .start = zd_op_start, + .stop = zd_op_stop, + .add_interface = zd_op_add_interface, + .remove_interface = zd_op_remove_interface, + .config = zd_op_config, + .config_interface = zd_op_config_interface, + .configure_filter = zd_op_configure_filter, + .bss_info_changed = zd_op_bss_info_changed, +}; + +struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) { - struct zd_mac *mac = zd_netdev_mac(ndev); - struct iw_statistics *iw_stats = &mac->iw_stats; - unsigned int i, count, qual_total, rssi_total; + struct zd_mac *mac; + struct ieee80211_hw *hw; + int i; - memset(iw_stats, 0, sizeof(struct iw_statistics)); - /* We are not setting the status, because ieee->state is not updated - * at all and this driver doesn't track authentication state. - */ - spin_lock_irq(&mac->lock); - count = mac->stats_count < ZD_MAC_STATS_BUFFER_SIZE ? - mac->stats_count : ZD_MAC_STATS_BUFFER_SIZE; - qual_total = rssi_total = 0; - for (i = 0; i < count; i++) { - qual_total += mac->qual_buffer[i]; - rssi_total += mac->rssi_buffer[i]; + hw = ieee80211_alloc_hw(sizeof(struct zd_mac), &zd_ops); + if (!hw) { + dev_dbg_f(&intf->dev, "out of memory\n"); + return NULL; } - spin_unlock_irq(&mac->lock); - iw_stats->qual.updated = IW_QUAL_NOISE_INVALID; - if (count > 0) { - iw_stats->qual.qual = qual_total / count; - iw_stats->qual.level = rssi_total / count; - iw_stats->qual.updated |= - IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED; - } else { - iw_stats->qual.updated |= - IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID; + + mac = zd_hw_mac(hw); + + memset(mac, 0, sizeof(*mac)); + spin_lock_init(&mac->lock); + mac->hw = hw; + + mac->type = IEEE80211_IF_TYPE_INVALID; + + memcpy(mac->channels, zd_channels, sizeof(zd_channels)); + memcpy(mac->rates, zd_rates, sizeof(zd_rates)); + mac->modes[0].mode = MODE_IEEE80211G; + mac->modes[0].num_rates = ARRAY_SIZE(zd_rates); + mac->modes[0].rates = mac->rates; + mac->modes[0].num_channels = ARRAY_SIZE(zd_channels); + mac->modes[0].channels = mac->channels; + mac->modes[1].mode = MODE_IEEE80211B; + mac->modes[1].num_rates = 4; + mac->modes[1].rates = mac->rates; + mac->modes[1].num_channels = ARRAY_SIZE(zd_channels); + mac->modes[1].channels = mac->channels; + + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; + hw->max_rssi = 100; + hw->max_signal = 100; + + hw->queues = 1; + hw->extra_tx_headroom = sizeof(struct zd_ctrlset); + + skb_queue_head_init(&mac->ack_wait_queue); + + for (i = 0; i < 2; i++) { + if (ieee80211_register_hwmode(hw, &mac->modes[i])) { + dev_dbg_f(&intf->dev, "cannot register hwmode\n"); + ieee80211_free_hw(hw); + return NULL; + } } - /* TODO: update counter */ - return iw_stats; + + zd_chip_init(&mac->chip, hw, intf); + housekeeping_init(mac); + INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); + INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work); + INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler); + + SET_IEEE80211_DEV(hw, &intf->dev); + return hw; } #define LINK_LED_WORK_DELAY HZ @@ -1308,18 +952,17 @@ static void link_led_handler(struct work_struct *work) struct zd_mac *mac = container_of(work, struct zd_mac, housekeeping.link_led_work.work); struct zd_chip *chip = &mac->chip; - struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev); int is_associated; int r; spin_lock_irq(&mac->lock); - is_associated = sm->associnfo.associated != 0; + is_associated = mac->associated; spin_unlock_irq(&mac->lock); r = zd_chip_control_leds(chip, is_associated ? LED_ASSOCIATED : LED_SCANNING); if (r) - dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); + dev_dbg_f(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r); queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work, LINK_LED_WORK_DELAY); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 1b15bde3ff60..2dde108df767 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -1,4 +1,7 @@ -/* zd_mac.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,14 +21,11 @@ #ifndef _ZD_MAC_H #define _ZD_MAC_H -#include <linux/wireless.h> #include <linux/kernel.h> -#include <linux/workqueue.h> -#include <net/ieee80211.h> -#include <net/ieee80211softmac.h> +#include <net/mac80211.h> #include "zd_chip.h" -#include "zd_netdev.h" +#include "zd_ieee80211.h" struct zd_ctrlset { u8 modulation; @@ -57,7 +57,7 @@ struct zd_ctrlset { /* The two possible modulation types. Notify that 802.11b doesn't use the CCK * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain * consistent with uses the term at other places. - */ + */ #define ZD_CCK 0x00 #define ZD_OFDM 0x10 @@ -141,58 +141,68 @@ struct rx_status { #define ZD_RX_CRC16_ERROR 0x40 #define ZD_RX_ERROR 0x80 +enum mac_flags { + MAC_FIXED_CHANNEL = 0x01, +}; + struct housekeeping { struct delayed_work link_led_work; }; +/** + * struct zd_tx_skb_control_block - control block for tx skbuffs + * @control: &struct ieee80211_tx_control pointer + * @context: context pointer + * + * This structure is used to fill the cb field in an &sk_buff to transmit. + * The control field is NULL, if there is no requirement from the mac80211 + * stack to report about the packet ACK. This is the case if the flag + * IEEE80211_TXCTL_NO_ACK is not set in &struct ieee80211_tx_control. + */ +struct zd_tx_skb_control_block { + struct ieee80211_tx_control *control; + struct ieee80211_hw *hw; + void *context; +}; + #define ZD_MAC_STATS_BUFFER_SIZE 16 +#define ZD_MAC_MAX_ACK_WAITERS 10 + struct zd_mac { struct zd_chip chip; spinlock_t lock; - struct net_device *netdev; - - /* Unlocked reading possible */ - struct iw_statistics iw_stats; - + struct ieee80211_hw *hw; struct housekeeping housekeeping; struct work_struct set_multicast_hash_work; + struct work_struct set_rts_cts_work; + struct work_struct set_rx_filter_work; struct zd_mc_hash multicast_hash; - struct delayed_work set_rts_cts_work; - struct delayed_work set_basic_rates_work; - - struct tasklet_struct rx_tasklet; - struct sk_buff_head rx_queue; - - unsigned int stats_count; - u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; - u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; u8 regdomain; u8 default_regdomain; - u8 requested_channel; - - /* A bitpattern of cr_rates */ - u16 basic_rates; - - /* A zd_rate */ - u8 rts_rate; + int type; + int associated; + struct sk_buff_head ack_wait_queue; + struct ieee80211_channel channels[14]; + struct ieee80211_rate rates[12]; + struct ieee80211_hw_mode modes[2]; /* Short preamble (used for RTS/CTS) */ unsigned int short_preamble:1; /* flags to indicate update in progress */ unsigned int updating_rts_rate:1; - unsigned int updating_basic_rates:1; -}; -static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac) -{ - return zd_netdev_ieee80211(mac->netdev); -} + /* whether to pass frames with CRC errors to stack */ + unsigned int pass_failed_fcs:1; -static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev) + /* whether to pass control frames to stack */ + unsigned int pass_ctrl:1; +}; + +static inline struct zd_mac *zd_hw_mac(struct ieee80211_hw *hw) { - return ieee80211softmac_priv(netdev); + return hw->priv; } static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip) @@ -205,35 +215,22 @@ static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb) return zd_chip_to_mac(zd_usb_to_chip(usb)); } +static inline u8 *zd_mac_get_perm_addr(struct zd_mac *mac) +{ + return mac->hw->wiphy->perm_addr; +} + #define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip)) -int zd_mac_init(struct zd_mac *mac, - struct net_device *netdev, - struct usb_interface *intf); +struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf); void zd_mac_clear(struct zd_mac *mac); -int zd_mac_preinit_hw(struct zd_mac *mac); -int zd_mac_init_hw(struct zd_mac *mac); - -int zd_mac_open(struct net_device *netdev); -int zd_mac_stop(struct net_device *netdev); -int zd_mac_set_mac_address(struct net_device *dev, void *p); -void zd_mac_set_multicast_list(struct net_device *netdev); - -int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length); - -int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain); -u8 zd_mac_get_regdomain(struct zd_mac *zd_mac); - -int zd_mac_request_channel(struct zd_mac *mac, u8 channel); -u8 zd_mac_get_channel(struct zd_mac *mac); - -int zd_mac_set_mode(struct zd_mac *mac, u32 mode); -int zd_mac_get_mode(struct zd_mac *mac, u32 *mode); - -int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range); +int zd_mac_preinit_hw(struct ieee80211_hw *hw); +int zd_mac_init_hw(struct ieee80211_hw *hw); -struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev); +int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length); +void zd_mac_tx_failed(struct ieee80211_hw *hw); +void zd_mac_tx_to_dev(struct sk_buff *skb, int error); #ifdef DEBUG void zd_dump_rx_status(const struct rx_status *status); diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c deleted file mode 100644 index 047cab3d87df..000000000000 --- a/drivers/net/wireless/zd1211rw/zd_netdev.c +++ /dev/null @@ -1,264 +0,0 @@ -/* zd_netdev.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <net/ieee80211.h> -#include <net/ieee80211softmac.h> -#include <net/ieee80211softmac_wx.h> -#include <net/iw_handler.h> - -#include "zd_def.h" -#include "zd_netdev.h" -#include "zd_mac.h" -#include "zd_ieee80211.h" - -/* Region 0 means reset regdomain to default. */ -static int zd_set_regdomain(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - const u8 *regdomain = (u8 *)req; - return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain); -} - -static int zd_get_regdomain(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - u8 *regdomain = (u8 *)req; - if (!regdomain) - return -EINVAL; - *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev)); - return 0; -} - -static const struct iw_priv_args zd_priv_args[] = { - { - .cmd = ZD_PRIV_SET_REGDOMAIN, - .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - .name = "set_regdomain", - }, - { - .cmd = ZD_PRIV_GET_REGDOMAIN, - .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, - .name = "get_regdomain", - }, -}; - -#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV] - -static const iw_handler zd_priv_handler[] = { - PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain, - PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain, -}; - -static int iw_get_name(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - /* FIXME: check whether 802.11a will also supported */ - strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ); - return 0; -} - -static int iw_get_nick(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - strcpy(extra, "zd1211"); - req->data.length = strlen(extra); - req->data.flags = 1; - return 0; -} - -static int iw_set_freq(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - int r; - struct zd_mac *mac = zd_netdev_mac(netdev); - struct iw_freq *freq = &req->freq; - u8 channel; - - r = zd_find_channel(&channel, freq); - if (r < 0) - return r; - r = zd_mac_request_channel(mac, channel); - return r; -} - -static int iw_get_freq(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - struct zd_mac *mac = zd_netdev_mac(netdev); - struct iw_freq *freq = &req->freq; - - return zd_channel_to_freq(freq, zd_mac_get_channel(mac)); -} - -static int iw_set_mode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode); -} - -static int iw_get_mode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode); -} - -static int iw_get_range(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *req, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - - dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n"); - req->data.length = sizeof(*range); - return zd_mac_get_range(zd_netdev_mac(netdev), range); -} - -static int iw_set_encode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -static int iw_get_encode(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -static int iw_set_encodeext(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -static int iw_get_encodeext(struct net_device *netdev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info, - data, extra); -} - -#define WX(x) [(x)-SIOCIWFIRST] - -static const iw_handler zd_standard_iw_handlers[] = { - WX(SIOCGIWNAME) = iw_get_name, - WX(SIOCGIWNICKN) = iw_get_nick, - WX(SIOCSIWFREQ) = iw_set_freq, - WX(SIOCGIWFREQ) = iw_get_freq, - WX(SIOCSIWMODE) = iw_set_mode, - WX(SIOCGIWMODE) = iw_get_mode, - WX(SIOCGIWRANGE) = iw_get_range, - WX(SIOCSIWENCODE) = iw_set_encode, - WX(SIOCGIWENCODE) = iw_get_encode, - WX(SIOCSIWENCODEEXT) = iw_set_encodeext, - WX(SIOCGIWENCODEEXT) = iw_get_encodeext, - WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, - WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, - WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, - WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, - WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, - WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, - WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, - WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, - WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, - WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, - WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, - WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, - WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme, -}; - -static const struct iw_handler_def iw_handler_def = { - .standard = zd_standard_iw_handlers, - .num_standard = ARRAY_SIZE(zd_standard_iw_handlers), - .private = zd_priv_handler, - .num_private = ARRAY_SIZE(zd_priv_handler), - .private_args = zd_priv_args, - .num_private_args = ARRAY_SIZE(zd_priv_args), - .get_wireless_stats = zd_mac_get_wireless_stats, -}; - -struct net_device *zd_netdev_alloc(struct usb_interface *intf) -{ - int r; - struct net_device *netdev; - struct zd_mac *mac; - - netdev = alloc_ieee80211softmac(sizeof(struct zd_mac)); - if (!netdev) { - dev_dbg_f(&intf->dev, "out of memory\n"); - return NULL; - } - - mac = zd_netdev_mac(netdev); - r = zd_mac_init(mac, netdev, intf); - if (r) { - usb_set_intfdata(intf, NULL); - free_ieee80211(netdev); - return NULL; - } - - SET_NETDEV_DEV(netdev, &intf->dev); - - dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags); - dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features); - - netdev->open = zd_mac_open; - netdev->stop = zd_mac_stop; - /* netdev->get_stats = */ - netdev->set_multicast_list = zd_mac_set_multicast_list; - netdev->set_mac_address = zd_mac_set_mac_address; - netdev->wireless_handlers = &iw_handler_def; - /* netdev->ethtool_ops = */ - - return netdev; -} - -void zd_netdev_free(struct net_device *netdev) -{ - if (!netdev) - return; - - zd_mac_clear(zd_netdev_mac(netdev)); - free_ieee80211(netdev); -} - -void zd_netdev_disconnect(struct net_device *netdev) -{ - unregister_netdev(netdev); -} diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h deleted file mode 100644 index 374a957073c1..000000000000 --- a/drivers/net/wireless/zd1211rw/zd_netdev.h +++ /dev/null @@ -1,45 +0,0 @@ -/* zd_netdev.h: Header for net device related functions. - * - * 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 _ZD_NETDEV_H -#define _ZD_NETDEV_H - -#include <linux/usb.h> -#include <linux/netdevice.h> -#include <net/ieee80211.h> - -#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV) -#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1) - -static inline struct ieee80211_device *zd_netdev_ieee80211( - struct net_device *ndev) -{ - return netdev_priv(ndev); -} - -static inline struct net_device *zd_ieee80211_to_netdev( - struct ieee80211_device *ieee) -{ - return ieee->dev; -} - -struct net_device *zd_netdev_alloc(struct usb_interface *intf); -void zd_netdev_free(struct net_device *netdev); - -void zd_netdev_disconnect(struct net_device *netdev); - -#endif /* _ZD_NETDEV_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index abe5d38f7f4d..ec4129312813 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c @@ -1,4 +1,7 @@ -/* zd_rf.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index 30502f26b71c..79dc1035592d 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h @@ -1,4 +1,7 @@ -/* zd_rf.h +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 006774de3202..74a8f7a55591 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c @@ -1,4 +1,7 @@ -/* zd_rf_al2230.c: Functions for the AL2230 RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index 73d0bb26f810..65095d661e6b 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c @@ -1,4 +1,7 @@ -/* zd_rf_al7230b.c: Functions for the AL7230B RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index cc70d40684ea..0597d862fbd2 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c @@ -1,4 +1,7 @@ -/* zd_rf_rfmd.c: Functions for the RFMD RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c index 857dcf3eae61..439799b84876 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c @@ -1,4 +1,7 @@ -/* zd_rf_uw2453.c: Functions for the UW2453 RF controller +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -403,7 +406,7 @@ static int uw2453_init_hw(struct zd_rf *rf) if (r) return r; - if (!intr_status & 0xf) { + if (!(intr_status & 0xf)) { dev_dbg_f(zd_chip_dev(chip), "PLL locked on configuration %d\n", i); found_config = i; diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index c755b6923812..7942b15acfe7 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -1,4 +1,8 @@ -/* zd_usb.c +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> + * Copyright (C) 2006-2007 Michael Wu <flamingice@sourmilk.net> * * 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 @@ -17,18 +21,16 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/module.h> #include <linux/firmware.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/skbuff.h> #include <linux/usb.h> #include <linux/workqueue.h> -#include <net/ieee80211.h> +#include <net/mac80211.h> #include <asm/unaligned.h> #include "zd_def.h" -#include "zd_netdev.h" #include "zd_mac.h" #include "zd_usb.h" @@ -55,6 +57,7 @@ static struct usb_device_id usb_ids[] = { { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 }, { USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 }, + { USB_DEVICE(0x157e, 0x300a), .driver_info = DEVICE_ZD1211 }, /* ZD1211B */ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, @@ -353,18 +356,6 @@ out: spin_unlock(&intr->lock); } -static inline void handle_retry_failed_int(struct urb *urb) -{ - struct zd_usb *usb = urb->context; - struct zd_mac *mac = zd_usb_to_mac(usb); - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - - ieee->stats.tx_errors++; - ieee->ieee_stats.tx_retry_limit_exceeded++; - dev_dbg_f(urb_dev(urb), "retry failed interrupt\n"); -} - - static void int_urb_complete(struct urb *urb) { int r; @@ -400,7 +391,7 @@ static void int_urb_complete(struct urb *urb) handle_regs_int(urb); break; case USB_INT_ID_RETRY_FAILED: - handle_retry_failed_int(urb); + zd_mac_tx_failed(zd_usb_to_hw(urb->context)); break; default: dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb, @@ -530,14 +521,10 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, unsigned int length) { int i; - struct zd_mac *mac = zd_usb_to_mac(usb); const struct rx_length_info *length_info; if (length < sizeof(struct rx_length_info)) { /* It's not a complete packet anyhow. */ - struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); - ieee->stats.rx_errors++; - ieee->stats.rx_length_errors++; return; } length_info = (struct rx_length_info *) @@ -561,13 +548,13 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, n = l+k; if (n > length) return; - zd_mac_rx_irq(mac, buffer+l, k); + zd_mac_rx(zd_usb_to_hw(usb), buffer+l, k); if (i >= 2) return; l = (n+3) & ~3; } } else { - zd_mac_rx_irq(mac, buffer, length); + zd_mac_rx(zd_usb_to_hw(usb), buffer, length); } } @@ -629,7 +616,7 @@ resubmit: usb_submit_urb(urb, GFP_ATOMIC); } -static struct urb *alloc_urb(struct zd_usb *usb) +static struct urb *alloc_rx_urb(struct zd_usb *usb) { struct usb_device *udev = zd_usb_to_usbdev(usb); struct urb *urb; @@ -653,7 +640,7 @@ static struct urb *alloc_urb(struct zd_usb *usb) return urb; } -static void free_urb(struct urb *urb) +static void free_rx_urb(struct urb *urb) { if (!urb) return; @@ -671,11 +658,11 @@ int zd_usb_enable_rx(struct zd_usb *usb) dev_dbg_f(zd_usb_dev(usb), "\n"); r = -ENOMEM; - urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); + urbs = kcalloc(RX_URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); if (!urbs) goto error; - for (i = 0; i < URBS_COUNT; i++) { - urbs[i] = alloc_urb(usb); + for (i = 0; i < RX_URBS_COUNT; i++) { + urbs[i] = alloc_rx_urb(usb); if (!urbs[i]) goto error; } @@ -688,10 +675,10 @@ int zd_usb_enable_rx(struct zd_usb *usb) goto error; } rx->urbs = urbs; - rx->urbs_count = URBS_COUNT; + rx->urbs_count = RX_URBS_COUNT; spin_unlock_irq(&rx->lock); - for (i = 0; i < URBS_COUNT; i++) { + for (i = 0; i < RX_URBS_COUNT; i++) { r = usb_submit_urb(urbs[i], GFP_KERNEL); if (r) goto error_submit; @@ -699,7 +686,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) return 0; error_submit: - for (i = 0; i < URBS_COUNT; i++) { + for (i = 0; i < RX_URBS_COUNT; i++) { usb_kill_urb(urbs[i]); } spin_lock_irq(&rx->lock); @@ -708,8 +695,8 @@ error_submit: spin_unlock_irq(&rx->lock); error: if (urbs) { - for (i = 0; i < URBS_COUNT; i++) - free_urb(urbs[i]); + for (i = 0; i < RX_URBS_COUNT; i++) + free_rx_urb(urbs[i]); } return r; } @@ -731,7 +718,7 @@ void zd_usb_disable_rx(struct zd_usb *usb) for (i = 0; i < count; i++) { usb_kill_urb(urbs[i]); - free_urb(urbs[i]); + free_rx_urb(urbs[i]); } kfree(urbs); @@ -741,9 +728,142 @@ void zd_usb_disable_rx(struct zd_usb *usb) spin_unlock_irqrestore(&rx->lock, flags); } +/** + * zd_usb_disable_tx - disable transmission + * @usb: the zd1211rw-private USB structure + * + * Frees all URBs in the free list and marks the transmission as disabled. + */ +void zd_usb_disable_tx(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + struct list_head *pos, *n; + + spin_lock_irqsave(&tx->lock, flags); + list_for_each_safe(pos, n, &tx->free_urb_list) { + list_del(pos); + usb_free_urb(list_entry(pos, struct urb, urb_list)); + } + tx->enabled = 0; + tx->submitted_urbs = 0; + /* The stopped state is ignored, relying on ieee80211_wake_queues() + * in a potentionally following zd_usb_enable_tx(). + */ + spin_unlock_irqrestore(&tx->lock, flags); +} + +/** + * zd_usb_enable_tx - enables transmission + * @usb: a &struct zd_usb pointer + * + * This function enables transmission and prepares the &zd_usb_tx data + * structure. + */ +void zd_usb_enable_tx(struct zd_usb *usb) +{ + unsigned long flags; + struct zd_usb_tx *tx = &usb->tx; + + spin_lock_irqsave(&tx->lock, flags); + tx->enabled = 1; + tx->submitted_urbs = 0; + ieee80211_wake_queues(zd_usb_to_hw(usb)); + tx->stopped = 0; + spin_unlock_irqrestore(&tx->lock, flags); +} + +/** + * alloc_tx_urb - provides an tx URB + * @usb: a &struct zd_usb pointer + * + * Allocates a new URB. If possible takes the urb from the free list in + * usb->tx. + */ +static struct urb *alloc_tx_urb(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + struct list_head *entry; + struct urb *urb; + + spin_lock_irqsave(&tx->lock, flags); + if (list_empty(&tx->free_urb_list)) { + urb = usb_alloc_urb(0, GFP_ATOMIC); + goto out; + } + entry = tx->free_urb_list.next; + list_del(entry); + urb = list_entry(entry, struct urb, urb_list); +out: + spin_unlock_irqrestore(&tx->lock, flags); + return urb; +} + +/** + * free_tx_urb - frees a used tx URB + * @usb: a &struct zd_usb pointer + * @urb: URB to be freed + * + * Frees the the transmission URB, which means to put it on the free URB + * list. + */ +static void free_tx_urb(struct zd_usb *usb, struct urb *urb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + if (!tx->enabled) { + usb_free_urb(urb); + goto out; + } + list_add(&urb->urb_list, &tx->free_urb_list); +out: + spin_unlock_irqrestore(&tx->lock, flags); +} + +static void tx_dec_submitted_urbs(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + --tx->submitted_urbs; + if (tx->stopped && tx->submitted_urbs <= ZD_USB_TX_LOW) { + ieee80211_wake_queues(zd_usb_to_hw(usb)); + tx->stopped = 0; + } + spin_unlock_irqrestore(&tx->lock, flags); +} + +static void tx_inc_submitted_urbs(struct zd_usb *usb) +{ + struct zd_usb_tx *tx = &usb->tx; + unsigned long flags; + + spin_lock_irqsave(&tx->lock, flags); + ++tx->submitted_urbs; + if (!tx->stopped && tx->submitted_urbs > ZD_USB_TX_HIGH) { + ieee80211_stop_queues(zd_usb_to_hw(usb)); + tx->stopped = 1; + } + spin_unlock_irqrestore(&tx->lock, flags); +} + +/** + * tx_urb_complete - completes the execution of an URB + * @urb: a URB + * + * This function is called if the URB has been transferred to a device or an + * error has happened. + */ static void tx_urb_complete(struct urb *urb) { int r; + struct sk_buff *skb; + struct zd_tx_skb_control_block *cb; + struct zd_usb *usb; switch (urb->status) { case 0: @@ -761,9 +881,12 @@ static void tx_urb_complete(struct urb *urb) goto resubmit; } free_urb: - usb_buffer_free(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); - usb_free_urb(urb); + skb = (struct sk_buff *)urb->context; + zd_mac_tx_to_dev(skb, urb->status); + cb = (struct zd_tx_skb_control_block *)skb->cb; + usb = &zd_hw_mac(cb->hw)->chip.usb; + free_tx_urb(usb, urb); + tx_dec_submitted_urbs(usb); return; resubmit: r = usb_submit_urb(urb, GFP_ATOMIC); @@ -773,43 +896,40 @@ resubmit: } } -/* Puts the frame on the USB endpoint. It doesn't wait for - * completion. The frame must contain the control set. +/** + * zd_usb_tx: initiates transfer of a frame of the device + * + * @usb: the zd1211rw-private USB structure + * @skb: a &struct sk_buff pointer + * + * This function tranmits a frame to the device. It doesn't wait for + * completion. The frame must contain the control set and have all the + * control set information available. + * + * The function returns 0 if the transfer has been successfully initiated. */ -int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length) +int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb) { int r; struct usb_device *udev = zd_usb_to_usbdev(usb); struct urb *urb; - void *buffer; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = alloc_tx_urb(usb); if (!urb) { r = -ENOMEM; goto out; } - buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC, - &urb->transfer_dma); - if (!buffer) { - r = -ENOMEM; - goto error_free_urb; - } - memcpy(buffer, frame, length); - usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT), - buffer, length, tx_urb_complete, NULL); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + skb->data, skb->len, tx_urb_complete, skb); r = usb_submit_urb(urb, GFP_ATOMIC); if (r) goto error; + tx_inc_submitted_urbs(usb); return 0; error: - usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer, - urb->transfer_dma); -error_free_urb: - usb_free_urb(urb); + free_tx_urb(usb, urb); out: return r; } @@ -838,16 +958,20 @@ static inline void init_usb_rx(struct zd_usb *usb) static inline void init_usb_tx(struct zd_usb *usb) { - /* FIXME: at this point we will allocate a fixed number of urb's for - * use in a cyclic scheme */ + struct zd_usb_tx *tx = &usb->tx; + spin_lock_init(&tx->lock); + tx->enabled = 0; + tx->stopped = 0; + INIT_LIST_HEAD(&tx->free_urb_list); + tx->submitted_urbs = 0; } -void zd_usb_init(struct zd_usb *usb, struct net_device *netdev, +void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, struct usb_interface *intf) { memset(usb, 0, sizeof(*usb)); usb->intf = usb_get_intf(intf); - usb_set_intfdata(usb->intf, netdev); + usb_set_intfdata(usb->intf, hw); init_usb_interrupt(usb); init_usb_tx(usb); init_usb_rx(usb); @@ -973,7 +1097,7 @@ int zd_usb_init_hw(struct zd_usb *usb) return r; } - r = zd_mac_init_hw(mac); + r = zd_mac_init_hw(mac->hw); if (r) { dev_dbg_f(zd_usb_dev(usb), "couldn't initialize mac. Error number %d\n", r); @@ -987,9 +1111,9 @@ int zd_usb_init_hw(struct zd_usb *usb) static int probe(struct usb_interface *intf, const struct usb_device_id *id) { int r; - struct zd_usb *usb; struct usb_device *udev = interface_to_usbdev(intf); - struct net_device *netdev = NULL; + struct zd_usb *usb; + struct ieee80211_hw *hw = NULL; print_id(udev); @@ -1007,57 +1131,65 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } - usb_reset_device(interface_to_usbdev(intf)); + r = usb_reset_device(udev); + if (r) { + dev_err(&intf->dev, + "couldn't reset usb device. Error number %d\n", r); + goto error; + } - netdev = zd_netdev_alloc(intf); - if (netdev == NULL) { + hw = zd_mac_alloc_hw(intf); + if (hw == NULL) { r = -ENOMEM; goto error; } - usb = &zd_netdev_mac(netdev)->chip.usb; + usb = &zd_hw_mac(hw)->chip.usb; usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0; - r = zd_mac_preinit_hw(zd_netdev_mac(netdev)); + r = zd_mac_preinit_hw(hw); if (r) { dev_dbg_f(&intf->dev, "couldn't initialize mac. Error number %d\n", r); goto error; } - r = register_netdev(netdev); + r = ieee80211_register_hw(hw); if (r) { dev_dbg_f(&intf->dev, - "couldn't register netdev. Error number %d\n", r); + "couldn't register device. Error number %d\n", r); goto error; } dev_dbg_f(&intf->dev, "successful\n"); - dev_info(&intf->dev,"%s\n", netdev->name); + dev_info(&intf->dev, "%s\n", wiphy_name(hw->wiphy)); return 0; error: usb_reset_device(interface_to_usbdev(intf)); - zd_netdev_free(netdev); + if (hw) { + zd_mac_clear(zd_hw_mac(hw)); + ieee80211_free_hw(hw); + } return r; } static void disconnect(struct usb_interface *intf) { - struct net_device *netdev = zd_intf_to_netdev(intf); + struct ieee80211_hw *hw = zd_intf_to_hw(intf); struct zd_mac *mac; struct zd_usb *usb; /* Either something really bad happened, or we're just dealing with * a DEVICE_INSTALLER. */ - if (netdev == NULL) + if (hw == NULL) return; - mac = zd_netdev_mac(netdev); + mac = zd_hw_mac(hw); usb = &mac->chip.usb; dev_dbg_f(zd_usb_dev(usb), "\n"); - zd_netdev_disconnect(netdev); + ieee80211_unregister_hw(hw); /* Just in case something has gone wrong! */ zd_usb_disable_rx(usb); @@ -1070,12 +1202,13 @@ static void disconnect(struct usb_interface *intf) */ usb_reset_device(interface_to_usbdev(intf)); - zd_netdev_free(netdev); + zd_mac_clear(mac); + ieee80211_free_hw(hw); dev_dbg(&intf->dev, "disconnected\n"); } static struct usb_driver driver = { - .name = "zd1211rw", + .name = KBUILD_MODNAME, .id_table = usb_ids, .probe = probe, .disconnect = disconnect, diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h index 961a7a12ad68..049f8b91f020 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.h +++ b/drivers/net/wireless/zd1211rw/zd_usb.h @@ -1,4 +1,7 @@ -/* zd_usb.h: Header for USB interface implemented by ZD1211 chip +/* ZD1211 USB-WLAN driver for Linux + * + * Copyright (C) 2005-2007 Ulrich Kunitz <kune@deine-taler.de> + * Copyright (C) 2006-2007 Daniel Drake <dsd@gentoo.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +29,9 @@ #include "zd_def.h" +#define ZD_USB_TX_HIGH 5 +#define ZD_USB_TX_LOW 2 + enum devicetype { DEVICE_ZD1211 = 0, DEVICE_ZD1211B = 1, @@ -165,7 +171,7 @@ static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr) return (struct usb_int_regs *)intr->read_regs.buffer; } -#define URBS_COUNT 5 +#define RX_URBS_COUNT 5 struct zd_usb_rx { spinlock_t lock; @@ -176,8 +182,21 @@ struct zd_usb_rx { int urbs_count; }; +/** + * struct zd_usb_tx - structure used for transmitting frames + * @lock: lock for transmission + * @free_urb_list: list of free URBs, contains all the URBs, which can be used + * @submitted_urbs: atomic integer that counts the URBs having sent to the + * device, which haven't been completed + * @enabled: enabled flag, indicates whether tx is enabled + * @stopped: indicates whether higher level tx queues are stopped + */ struct zd_usb_tx { spinlock_t lock; + struct list_head free_urb_list; + int submitted_urbs; + int enabled; + int stopped; }; /* Contains the usb parts. The structure doesn't require a lock because intf @@ -198,17 +217,17 @@ static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb) return interface_to_usbdev(usb->intf); } -static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf) +static inline struct ieee80211_hw *zd_intf_to_hw(struct usb_interface *intf) { return usb_get_intfdata(intf); } -static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb) +static inline struct ieee80211_hw *zd_usb_to_hw(struct zd_usb *usb) { - return zd_intf_to_netdev(usb->intf); + return zd_intf_to_hw(usb->intf); } -void zd_usb_init(struct zd_usb *usb, struct net_device *netdev, +void zd_usb_init(struct zd_usb *usb, struct ieee80211_hw *hw, struct usb_interface *intf); int zd_usb_init_hw(struct zd_usb *usb); void zd_usb_clear(struct zd_usb *usb); @@ -221,7 +240,10 @@ void zd_usb_disable_int(struct zd_usb *usb); int zd_usb_enable_rx(struct zd_usb *usb); void zd_usb_disable_rx(struct zd_usb *usb); -int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length); +void zd_usb_enable_tx(struct zd_usb *usb); +void zd_usb_disable_tx(struct zd_usb *usb); + +int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb); int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, const zd_addr_t *addresses, unsigned int count); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index bca37bf0f545..7483d45bc5bc 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1073,7 +1073,7 @@ static void xennet_release_rx_bufs(struct netfront_info *np) if (!xen_feature(XENFEAT_auto_translated_physmap)) { /* Do all the remapping work and M2P updates. */ MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu, - 0, DOMID_SELF); + NULL, DOMID_SELF); mcl++; HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl); } diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index a6d6b2488ffc..703b85edb004 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -364,7 +364,7 @@ static __inline__ int led_get_net_activity(void) struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) continue; - if (LOOPBACK(in_dev->ifa_list->ifa_local)) + if (ipv4_is_loopback(in_dev->ifa_list->ifa_local)) continue; stats = dev->get_stats(dev); rx_total += stats->rx_packets; diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index ebb09e98d215..de34aa9d3136 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -120,7 +120,7 @@ struct pdcspath_entry pdcspath_entry_##_name = { \ }; #define PDCS_ATTR(_name, _mode, _show, _store) \ -struct subsys_attribute pdcs_attr_##_name = { \ +struct kobj_attribute pdcs_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode}, \ .show = _show, \ .store = _store, \ @@ -523,15 +523,15 @@ static struct pdcspath_entry *pdcspath_entries[] = { /** * pdcs_size_read - Stable Storage size output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static ssize_t -pdcs_size_read(struct kset *kset, char *buf) +static ssize_t pdcs_size_read(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) { char *out = buf; - if (!kset || !buf) + if (!buf) return -EINVAL; /* show the size of the stable storage */ @@ -542,17 +542,17 @@ pdcs_size_read(struct kset *kset, char *buf) /** * pdcs_auto_read - Stable Storage autoboot/search flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag */ -static ssize_t -pdcs_auto_read(struct kset *kset, char *buf, int knob) +static ssize_t pdcs_auto_read(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf, int knob) { char *out = buf; struct pdcspath_entry *pathentry; - if (!kset || !buf) + if (!buf) return -EINVAL; /* Current flags are stored in primary boot path entry */ @@ -568,40 +568,37 @@ pdcs_auto_read(struct kset *kset, char *buf, int knob) /** * pdcs_autoboot_read - Stable Storage autoboot flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static inline ssize_t -pdcs_autoboot_read(struct kset *kset, char *buf) +static ssize_t pdcs_autoboot_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return pdcs_auto_read(kset, buf, PF_AUTOBOOT); + return pdcs_auto_read(kobj, attr, buf, PF_AUTOBOOT); } /** * pdcs_autosearch_read - Stable Storage autoboot flag output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static inline ssize_t -pdcs_autosearch_read(struct kset *kset, char *buf) +static ssize_t pdcs_autosearch_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { - return pdcs_auto_read(kset, buf, PF_AUTOSEARCH); + return pdcs_auto_read(kobj, attr, buf, PF_AUTOSEARCH); } /** * pdcs_timer_read - Stable Storage timer count output (in seconds). - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * The value of the timer field correponds to a number of seconds in powers of 2. */ -static ssize_t -pdcs_timer_read(struct kset *kset, char *buf) +static ssize_t pdcs_timer_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; struct pdcspath_entry *pathentry; - if (!kset || !buf) + if (!buf) return -EINVAL; /* Current flags are stored in primary boot path entry */ @@ -618,15 +615,14 @@ pdcs_timer_read(struct kset *kset, char *buf) /** * pdcs_osid_read - Stable Storage OS ID register output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. */ -static ssize_t -pdcs_osid_read(struct kset *kset, char *buf) +static ssize_t pdcs_osid_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; - if (!kset || !buf) + if (!buf) return -EINVAL; out += sprintf(out, "%s dependent data (0x%.4x)\n", @@ -637,18 +633,17 @@ pdcs_osid_read(struct kset *kset, char *buf) /** * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * This can hold 16 bytes of OS-Dependent data. */ -static ssize_t -pdcs_osdep1_read(struct kset *kset, char *buf) +static ssize_t pdcs_osdep1_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; u32 result[4]; - if (!kset || !buf) + if (!buf) return -EINVAL; if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK) @@ -664,18 +659,17 @@ pdcs_osdep1_read(struct kset *kset, char *buf) /** * pdcs_diagnostic_read - Stable Storage Diagnostic register output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * I have NFC how to interpret the content of that register ;-). */ -static ssize_t -pdcs_diagnostic_read(struct kset *kset, char *buf) +static ssize_t pdcs_diagnostic_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; u32 result; - if (!kset || !buf) + if (!buf) return -EINVAL; /* get diagnostic */ @@ -689,18 +683,17 @@ pdcs_diagnostic_read(struct kset *kset, char *buf) /** * pdcs_fastsize_read - Stable Storage FastSize register output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * This register holds the amount of system RAM to be tested during boot sequence. */ -static ssize_t -pdcs_fastsize_read(struct kset *kset, char *buf) +static ssize_t pdcs_fastsize_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; u32 result; - if (!kset || !buf) + if (!buf) return -EINVAL; /* get fast-size */ @@ -718,13 +711,12 @@ pdcs_fastsize_read(struct kset *kset, char *buf) /** * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The output buffer to write to. * * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available. */ -static ssize_t -pdcs_osdep2_read(struct kset *kset, char *buf) +static ssize_t pdcs_osdep2_read(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) { char *out = buf; unsigned long size; @@ -736,7 +728,7 @@ pdcs_osdep2_read(struct kset *kset, char *buf) size = pdcs_size - 224; - if (!kset || !buf) + if (!buf) return -EINVAL; for (i=0; i<size; i+=4) { @@ -751,7 +743,6 @@ pdcs_osdep2_read(struct kset *kset, char *buf) /** * pdcs_auto_write - This function handles autoboot/search flag modifying. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag @@ -760,8 +751,9 @@ pdcs_osdep2_read(struct kset *kset, char *buf) * We expect a precise syntax: * \"n\" (n == 0 or 1) to toggle AutoBoot Off or On */ -static ssize_t -pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob) +static ssize_t pdcs_auto_write(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count, int knob) { struct pdcspath_entry *pathentry; unsigned char flags; @@ -771,7 +763,7 @@ pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!kset || !buf || !count) + if (!buf || !count) return -EINVAL; /* We'll use a local copy of buf */ @@ -826,7 +818,6 @@ parse_error: /** * pdcs_autoboot_write - This function handles autoboot flag modifying. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -834,15 +825,15 @@ parse_error: * We expect a precise syntax: * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On */ -static inline ssize_t -pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_autoboot_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { - return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT); + return pdcs_auto_write(kset, attr, buf, count, PF_AUTOBOOT); } /** * pdcs_autosearch_write - This function handles autosearch flag modifying. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -850,15 +841,15 @@ pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count) * We expect a precise syntax: * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On */ -static inline ssize_t -pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_autosearch_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { - return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH); + return pdcs_auto_write(kset, attr, buf, count, PF_AUTOSEARCH); } /** * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -866,15 +857,16 @@ pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count) * write approach. It's up to userspace to deal with it when constructing * its input buffer. */ -static ssize_t -pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_osdep1_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { u8 in[16]; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!kset || !buf || !count) + if (!buf || !count) return -EINVAL; if (unlikely(pdcs_osid != OS_ID_LINUX)) @@ -895,7 +887,6 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count) /** * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input. - * @kset: An allocated and populated struct kset. We don't use it tho. * @buf: The input buffer to read from. * @count: The number of bytes to be read. * @@ -903,8 +894,9 @@ pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count) * byte-by-byte write approach. It's up to userspace to deal with it when * constructing its input buffer. */ -static ssize_t -pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count) +static ssize_t pdcs_osdep2_write(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) { unsigned long size; unsigned short i; @@ -913,7 +905,7 @@ pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count) if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!kset || !buf || !count) + if (!buf || !count) return -EINVAL; if (unlikely(pdcs_size <= 224)) @@ -951,21 +943,25 @@ static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL); static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL); static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write); -static struct subsys_attribute *pdcs_subsys_attrs[] = { - &pdcs_attr_size, - &pdcs_attr_autoboot, - &pdcs_attr_autosearch, - &pdcs_attr_timer, - &pdcs_attr_osid, - &pdcs_attr_osdep1, - &pdcs_attr_diagnostic, - &pdcs_attr_fastsize, - &pdcs_attr_osdep2, +static struct attribute *pdcs_subsys_attrs[] = { + &pdcs_attr_size.attr, + &pdcs_attr_autoboot.attr, + &pdcs_attr_autosearch.attr, + &pdcs_attr_timer.attr, + &pdcs_attr_osid.attr, + &pdcs_attr_osdep1.attr, + &pdcs_attr_diagnostic.attr, + &pdcs_attr_fastsize.attr, + &pdcs_attr_osdep2.attr, NULL, }; -static decl_subsys(paths, &ktype_pdcspath, NULL); -static decl_subsys(stable, NULL, NULL); +static struct attribute_group pdcs_attr_group = { + .attrs = pdcs_subsys_attrs, +}; + +static struct kobject *stable_kobj; +static struct kset *paths_kset; /** * pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage. @@ -995,12 +991,12 @@ pdcs_register_pathentries(void) if (err < 0) continue; - if ((err = kobject_set_name(&entry->kobj, "%s", entry->name))) - return err; - kobj_set_kset_s(entry, paths_subsys); - if ((err = kobject_register(&entry->kobj))) + entry->kobj.kset = paths_kset; + err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL, + "%s", entry->name); + if (err) return err; - + /* kobject is now registered */ write_lock(&entry->rw_lock); entry->ready = 2; @@ -1012,6 +1008,7 @@ pdcs_register_pathentries(void) } write_unlock(&entry->rw_lock); + kobject_uevent(&entry->kobj, KOBJ_ADD); } return 0; @@ -1029,7 +1026,7 @@ pdcs_unregister_pathentries(void) for (i = 0; (entry = pdcspath_entries[i]); i++) { read_lock(&entry->rw_lock); if (entry->ready >= 2) - kobject_unregister(&entry->kobj); + kobject_put(&entry->kobj); read_unlock(&entry->rw_lock); } } @@ -1041,8 +1038,7 @@ pdcs_unregister_pathentries(void) static int __init pdc_stable_init(void) { - struct subsys_attribute *attr; - int i, rc = 0, error = 0; + int rc = 0, error = 0; u32 result; /* find the size of the stable storage */ @@ -1062,21 +1058,24 @@ pdc_stable_init(void) /* the actual result is 16 bits away */ pdcs_osid = (u16)(result >> 16); - /* For now we'll register the stable subsys within this driver */ - if ((rc = firmware_register(&stable_subsys))) + /* For now we'll register the directory at /sys/firmware/stable */ + stable_kobj = kobject_create_and_add("stable", firmware_kobj); + if (!stable_kobj) { + rc = -ENOMEM; goto fail_firmreg; + } /* Don't forget the root entries */ - for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++) - if (attr->show) - error = subsys_create_file(&stable_subsys, attr); - - /* register the paths subsys as a subsystem of stable subsys */ - kobj_set_kset_s(&paths_subsys, stable_subsys); - if ((rc = subsystem_register(&paths_subsys))) - goto fail_subsysreg; + error = sysfs_create_group(stable_kobj, pdcs_attr_group); - /* now we create all "files" for the paths subsys */ + /* register the paths kset as a child of the stable kset */ + paths_kset = kset_create_and_add("paths", NULL, stable_kobj); + if (!paths_kset) { + rc = -ENOMEM; + goto fail_ksetreg; + } + + /* now we create all "files" for the paths kset */ if ((rc = pdcs_register_pathentries())) goto fail_pdcsreg; @@ -1084,10 +1083,10 @@ pdc_stable_init(void) fail_pdcsreg: pdcs_unregister_pathentries(); - subsystem_unregister(&paths_subsys); + kset_unregister(paths_kset); -fail_subsysreg: - firmware_unregister(&stable_subsys); +fail_ksetreg: + kobject_put(stable_kobj); fail_firmreg: printk(KERN_INFO PDCS_PREFIX " bailing out\n"); @@ -1098,9 +1097,8 @@ static void __exit pdc_stable_exit(void) { pdcs_unregister_pathentries(); - subsystem_unregister(&paths_subsys); - - firmware_unregister(&stable_subsys); + kset_unregister(paths_kset); + kobject_put(stable_kobj); } diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index 47d26b65e99a..750ebd7a4c10 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -429,7 +429,7 @@ static int __init ibm_acpiphp_init(void) int retval = 0; acpi_status status; struct acpi_device *device; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; + struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; dbg("%s\n", __FUNCTION__); @@ -476,7 +476,7 @@ init_return: static void __exit ibm_acpiphp_exit(void) { acpi_status status; - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj; + struct kobject *sysdir = &pci_hotplug_slots_kset->kobj; dbg("%s\n", __FUNCTION__); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 01c351c176ac..47bb0e1ff3fa 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -61,7 +61,7 @@ static int debug; static LIST_HEAD(pci_hotplug_slot_list); -struct kset pci_hotplug_slots_subsys; +struct kset *pci_hotplug_slots_kset; static ssize_t hotplug_slot_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) @@ -96,8 +96,6 @@ static struct kobj_type hotplug_slot_ktype = { .release = &hotplug_slot_release, }; -decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL); - /* these strings match up with the values in pci_bus_speed */ static char *pci_bus_speed_strings[] = { "33 MHz PCI", /* 0x00 */ @@ -632,18 +630,19 @@ int pci_hp_register (struct hotplug_slot *slot) return -EINVAL; } - kobject_set_name(&slot->kobj, "%s", slot->name); - kobj_set_kset_s(slot, pci_hotplug_slots_subsys); - /* this can fail if we have already registered a slot with the same name */ - if (kobject_register(&slot->kobj)) { - err("Unable to register kobject"); + slot->kobj.kset = pci_hotplug_slots_kset; + result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, + "%s", slot->name); + if (result) { + err("Unable to register kobject '%s'", slot->name); return -EINVAL; } - + list_add (&slot->slot_list, &pci_hotplug_slot_list); result = fs_add_slot (slot); + kobject_uevent(&slot->kobj, KOBJ_ADD); dbg ("Added slot %s to the list\n", slot->name); return result; } @@ -672,7 +671,7 @@ int pci_hp_deregister (struct hotplug_slot *slot) fs_remove_slot (slot); dbg ("Removed slot %s from the list\n", slot->name); - kobject_unregister(&slot->kobj); + kobject_put(&slot->kobj); return 0; } @@ -700,11 +699,15 @@ int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, static int __init pci_hotplug_init (void) { int result; + struct kset *pci_bus_kset; - kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys); - result = subsystem_register(&pci_hotplug_slots_subsys); - if (result) { - err("Register subsys with error %d\n", result); + pci_bus_kset = bus_get_kset(&pci_bus_type); + + pci_hotplug_slots_kset = kset_create_and_add("slots", NULL, + &pci_bus_kset->kobj); + if (!pci_hotplug_slots_kset) { + result = -ENOMEM; + err("Register subsys error\n"); goto exit; } result = cpci_hotplug_init(debug); @@ -715,9 +718,9 @@ static int __init pci_hotplug_init (void) info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); goto exit; - + err_subsys: - subsystem_unregister(&pci_hotplug_slots_subsys); + kset_unregister(pci_hotplug_slots_kset); exit: return result; } @@ -725,7 +728,7 @@ exit: static void __exit pci_hotplug_exit (void) { cpci_hotplug_exit(); - subsystem_unregister(&pci_hotplug_slots_subsys); + kset_unregister(pci_hotplug_slots_kset); } module_init(pci_hotplug_init); @@ -737,7 +740,7 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys); +EXPORT_SYMBOL_GPL(pci_hotplug_slots_kset); EXPORT_SYMBOL_GPL(pci_hp_register); EXPORT_SYMBOL_GPL(pci_hp_deregister); EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index a080fedf0332..e32148a8fa12 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -23,44 +23,13 @@ #define MAX_DRC_NAME_LEN 64 -/* Store return code of dlpar operation in attribute struct */ -struct dlpar_io_attr { - int rc; - struct attribute attr; - ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf, - size_t nbytes); -}; -/* Common show callback for all attrs, display the return code - * of the dlpar op */ -static ssize_t -dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) -{ - struct dlpar_io_attr *dlpar_attr = container_of(attr, - struct dlpar_io_attr, attr); - return sprintf(buf, "%d\n", dlpar_attr->rc); -} - -static ssize_t -dlpar_attr_store(struct kobject * kobj, struct attribute * attr, - const char *buf, size_t nbytes) -{ - struct dlpar_io_attr *dlpar_attr = container_of(attr, - struct dlpar_io_attr, attr); - return dlpar_attr->store ? - dlpar_attr->store(dlpar_attr, buf, nbytes) : -EIO; -} - -static struct sysfs_ops dlpar_attr_sysfs_ops = { - .show = dlpar_attr_show, - .store = dlpar_attr_store, -}; - -static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, - const char *buf, size_t nbytes) +static ssize_t add_slot_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; char *end; + int rc; if (nbytes >= MAX_DRC_NAME_LEN) return 0; @@ -72,15 +41,25 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, end = &drc_name[nbytes]; *end = '\0'; - dlpar_attr->rc = dlpar_add_slot(drc_name); + rc = dlpar_add_slot(drc_name); + if (rc) + return rc; return nbytes; } -static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, - const char *buf, size_t nbytes) +static ssize_t add_slot_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "0\n"); +} + +static ssize_t remove_slot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t nbytes) { char drc_name[MAX_DRC_NAME_LEN]; + int rc; char *end; if (nbytes >= MAX_DRC_NAME_LEN) @@ -93,22 +72,24 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, end = &drc_name[nbytes]; *end = '\0'; - dlpar_attr->rc = dlpar_remove_slot(drc_name); + rc = dlpar_remove_slot(drc_name); + if (rc) + return rc; return nbytes; } -static struct dlpar_io_attr add_slot_attr = { - .rc = 0, - .attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, }, - .store = add_slot_store, -}; +static ssize_t remove_slot_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "0\n"); +} -static struct dlpar_io_attr remove_slot_attr = { - .rc = 0, - .attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644}, - .store = remove_slot_store, -}; +static struct kobj_attribute add_slot_attr = + __ATTR(ADD_SLOT_ATTR_NAME, 0644, add_slot_show, add_slot_store); + +static struct kobj_attribute remove_slot_attr = + __ATTR(REMOVE_SLOT_ATTR_NAME, 0644, remove_slot_show, remove_slot_store); static struct attribute *default_attrs[] = { &add_slot_attr.attr, @@ -116,37 +97,29 @@ static struct attribute *default_attrs[] = { NULL, }; -static void dlpar_io_release(struct kobject *kobj) -{ - /* noop */ - return; -} - -struct kobj_type ktype_dlpar_io = { - .release = dlpar_io_release, - .sysfs_ops = &dlpar_attr_sysfs_ops, - .default_attrs = default_attrs, +static struct attribute_group dlpar_attr_group = { + .attrs = default_attrs, }; -struct kset dlpar_io_kset = { - .kobj = {.ktype = &ktype_dlpar_io, - .parent = &pci_hotplug_slots_subsys.kobj}, - .ktype = &ktype_dlpar_io, -}; +static struct kobject *dlpar_kobj; int dlpar_sysfs_init(void) { - kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME); - if (kset_register(&dlpar_io_kset)) { - printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n", - kobject_name(&dlpar_io_kset.kobj)); + int error; + + dlpar_kobj = kobject_create_and_add(DLPAR_KOBJ_NAME, + &pci_hotplug_slots_kset->kobj); + if (!dlpar_kobj) return -EINVAL; - } - return 0; + error = sysfs_create_group(dlpar_kobj, &dlpar_attr_group); + if (error) + kobject_put(dlpar_kobj); + return error; } void dlpar_sysfs_exit(void) { - kset_unregister(&dlpar_io_kset); + sysfs_remove_group(dlpar_kobj, &dlpar_attr_group); + kobject_put(dlpar_kobj); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 6d1a21611818..c4fa35d1dd77 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -1,6 +1,11 @@ /* * drivers/pci/pci-driver.c * + * (C) Copyright 2002-2004, 2007 Greg Kroah-Hartman <greg@kroah.com> + * (C) Copyright 2007 Novell Inc. + * + * Released under the GPL v2 only. + * */ #include <linux/pci.h> @@ -96,17 +101,21 @@ pci_create_newid_file(struct pci_driver *drv) { int error = 0; if (drv->probe != NULL) - error = sysfs_create_file(&drv->driver.kobj, - &driver_attr_new_id.attr); + error = driver_create_file(&drv->driver, &driver_attr_new_id); return error; } +static void pci_remove_newid_file(struct pci_driver *drv) +{ + driver_remove_file(&drv->driver, &driver_attr_new_id); +} #else /* !CONFIG_HOTPLUG */ static inline void pci_free_dynids(struct pci_driver *drv) {} static inline int pci_create_newid_file(struct pci_driver *drv) { return 0; } +static inline void pci_remove_newid_file(struct pci_driver *drv) {} #endif /** @@ -352,50 +361,6 @@ static void pci_device_shutdown(struct device *dev) drv->shutdown(pci_dev); } -#define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj) -#define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr) - -static ssize_t -pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) -{ - struct device_driver *driver = kobj_to_pci_driver(kobj); - struct driver_attribute *dattr = attr_to_driver_attribute(attr); - ssize_t ret; - - if (!get_driver(driver)) - return -ENODEV; - - ret = dattr->show ? dattr->show(driver, buf) : -EIO; - - put_driver(driver); - return ret; -} - -static ssize_t -pci_driver_attr_store(struct kobject * kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct device_driver *driver = kobj_to_pci_driver(kobj); - struct driver_attribute *dattr = attr_to_driver_attribute(attr); - ssize_t ret; - - if (!get_driver(driver)) - return -ENODEV; - - ret = dattr->store ? dattr->store(driver, buf, count) : -EIO; - - put_driver(driver); - return ret; -} - -static struct sysfs_ops pci_driver_sysfs_ops = { - .show = pci_driver_attr_show, - .store = pci_driver_attr_store, -}; -static struct kobj_type pci_driver_kobj_type = { - .sysfs_ops = &pci_driver_sysfs_ops, -}; - /** * __pci_register_driver - register a new pci driver * @drv: the driver structure to register @@ -417,7 +382,6 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, drv->driver.bus = &pci_bus_type; drv->driver.owner = owner; drv->driver.mod_name = mod_name; - drv->driver.kobj.ktype = &pci_driver_kobj_type; spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list); @@ -447,6 +411,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner, void pci_unregister_driver(struct pci_driver *drv) { + pci_remove_newid_file(drv); driver_unregister(&drv->driver); pci_free_dynids(drv); } diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c5ca3134513a..5fd585293e79 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1210,16 +1210,19 @@ static void __init pci_sort_breadthfirst_klist(void) struct klist_node *n; struct device *dev; struct pci_dev *pdev; + struct klist *device_klist; - spin_lock(&pci_bus_type.klist_devices.k_lock); - list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { + device_klist = bus_get_device_klist(&pci_bus_type); + + spin_lock(&device_klist->k_lock); + list_for_each_safe(pos, tmp, &device_klist->k_list) { n = container_of(pos, struct klist_node, n_node); dev = container_of(n, struct device, knode_bus); pdev = to_pci_dev(dev); pci_insertion_sort_klist(pdev, &sorted_devices); } - list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); - spin_unlock(&pci_bus_type.klist_devices.k_lock); + list_splice(&sorted_devices, &device_klist->k_list); + spin_unlock(&device_klist->k_lock); } static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 5cf89a91da1e..15c18f5246d6 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -312,8 +312,7 @@ pcmcia_create_newid_file(struct pcmcia_driver *drv) { int error = 0; if (drv->probe != NULL) - error = sysfs_create_file(&drv->drv.kobj, - &driver_attr_new_id.attr); + error = driver_create_file(&drv->drv, &driver_attr_new_id); return error; } diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 874923fcb2f9..e439044d88f2 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -29,6 +29,7 @@ #include <asm/irq.h> #include <asm/system.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/pxa2xx-regs.h> #include <pcmcia/cs_types.h> #include <pcmcia/ss.h> diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c index 5dba68fe33f5..a8364d815222 100644 --- a/drivers/pnp/pnpbios/bioscalls.c +++ b/drivers/pnp/pnpbios/bioscalls.c @@ -61,7 +61,7 @@ set_base(gdt[(selname) >> 3], (u32)(address)); \ set_limit(gdt[(selname) >> 3], size); \ } while(0) -static struct desc_struct bad_bios_desc = { 0, 0x00409200 }; +static struct desc_struct bad_bios_desc; /* * At some point we want to use this stack frame pointer to unwind @@ -477,6 +477,9 @@ void pnpbios_calls_init(union pnp_bios_install_struct *header) pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; + bad_bios_desc.a = 0; + bad_bios_desc.b = 0x00409200; + set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); for (i = 0; i < NR_CPUS; i++) { diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index bbf3ee10da04..7e29b90a4f63 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c @@ -13,6 +13,7 @@ #include <linux/power_supply.h> #include <linux/apm-emulation.h> +static DEFINE_MUTEX(apm_mutex); #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ POWER_SUPPLY_PROP_##prop, val) @@ -23,67 +24,86 @@ static struct power_supply *main_battery; -static void find_main_battery(void) -{ - struct device *dev; - struct power_supply *bat = NULL; - struct power_supply *max_charge_bat = NULL; - struct power_supply *max_energy_bat = NULL; +struct find_bat_param { + struct power_supply *main; + struct power_supply *bat; + struct power_supply *max_charge_bat; + struct power_supply *max_energy_bat; union power_supply_propval full; - int max_charge = 0; - int max_energy = 0; + int max_charge; + int max_energy; +}; - main_battery = NULL; +static int __find_main_battery(struct device *dev, void *data) +{ + struct find_bat_param *bp = (struct find_bat_param *)data; - list_for_each_entry(dev, &power_supply_class->devices, node) { - bat = dev_get_drvdata(dev); + bp->bat = dev_get_drvdata(dev); - if (bat->use_for_apm) { - /* nice, we explicitly asked to report this battery. */ - main_battery = bat; - return; - } + if (bp->bat->use_for_apm) { + /* nice, we explicitly asked to report this battery. */ + bp->main = bp->bat; + return 1; + } - if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full) || - !PSY_PROP(bat, CHARGE_FULL, &full)) { - if (full.intval > max_charge) { - max_charge_bat = bat; - max_charge = full.intval; - } - } else if (!PSY_PROP(bat, ENERGY_FULL_DESIGN, &full) || - !PSY_PROP(bat, ENERGY_FULL, &full)) { - if (full.intval > max_energy) { - max_energy_bat = bat; - max_energy = full.intval; - } + if (!PSY_PROP(bp->bat, CHARGE_FULL_DESIGN, &bp->full) || + !PSY_PROP(bp->bat, CHARGE_FULL, &bp->full)) { + if (bp->full.intval > bp->max_charge) { + bp->max_charge_bat = bp->bat; + bp->max_charge = bp->full.intval; + } + } else if (!PSY_PROP(bp->bat, ENERGY_FULL_DESIGN, &bp->full) || + !PSY_PROP(bp->bat, ENERGY_FULL, &bp->full)) { + if (bp->full.intval > bp->max_energy) { + bp->max_energy_bat = bp->bat; + bp->max_energy = bp->full.intval; } } + return 0; +} + +static void find_main_battery(void) +{ + struct find_bat_param bp; + int error; + + memset(&bp, 0, sizeof(struct find_bat_param)); + main_battery = NULL; + bp.main = main_battery; + + error = class_for_each_device(power_supply_class, &bp, + __find_main_battery); + if (error) { + main_battery = bp.main; + return; + } - if ((max_energy_bat && max_charge_bat) && - (max_energy_bat != max_charge_bat)) { + if ((bp.max_energy_bat && bp.max_charge_bat) && + (bp.max_energy_bat != bp.max_charge_bat)) { /* try guess battery with more capacity */ - if (!PSY_PROP(max_charge_bat, VOLTAGE_MAX_DESIGN, &full)) { - if (max_energy > max_charge * full.intval) - main_battery = max_energy_bat; + if (!PSY_PROP(bp.max_charge_bat, VOLTAGE_MAX_DESIGN, + &bp.full)) { + if (bp.max_energy > bp.max_charge * bp.full.intval) + main_battery = bp.max_energy_bat; else - main_battery = max_charge_bat; - } else if (!PSY_PROP(max_energy_bat, VOLTAGE_MAX_DESIGN, - &full)) { - if (max_charge > max_energy / full.intval) - main_battery = max_charge_bat; + main_battery = bp.max_charge_bat; + } else if (!PSY_PROP(bp.max_energy_bat, VOLTAGE_MAX_DESIGN, + &bp.full)) { + if (bp.max_charge > bp.max_energy / bp.full.intval) + main_battery = bp.max_charge_bat; else - main_battery = max_energy_bat; + main_battery = bp.max_energy_bat; } else { /* give up, choice any */ - main_battery = max_energy_bat; + main_battery = bp.max_energy_bat; } - } else if (max_charge_bat) { - main_battery = max_charge_bat; - } else if (max_energy_bat) { - main_battery = max_energy_bat; + } else if (bp.max_charge_bat) { + main_battery = bp.max_charge_bat; + } else if (bp.max_energy_bat) { + main_battery = bp.max_energy_bat; } else { /* give up, try the last if any */ - main_battery = bat; + main_battery = bp.bat; } } @@ -207,10 +227,10 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) union power_supply_propval status; union power_supply_propval capacity, time_to_full, time_to_empty; - down(&power_supply_class->sem); + mutex_lock(&apm_mutex); find_main_battery(); if (!main_battery) { - up(&power_supply_class->sem); + mutex_unlock(&apm_mutex); return; } @@ -278,7 +298,7 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) } } - up(&power_supply_class->sem); + mutex_unlock(&apm_mutex); } static int __init apm_battery_init(void) diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index a63b75cf75e2..03d6a38464ef 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -20,28 +20,29 @@ struct class *power_supply_class; +static int __power_supply_changed_work(struct device *dev, void *data) +{ + struct power_supply *psy = (struct power_supply *)data; + struct power_supply *pst = dev_get_drvdata(dev); + int i; + + for (i = 0; i < psy->num_supplicants; i++) + if (!strcmp(psy->supplied_to[i], pst->name)) { + if (pst->external_power_changed) + pst->external_power_changed(pst); + } + return 0; +} + static void power_supply_changed_work(struct work_struct *work) { struct power_supply *psy = container_of(work, struct power_supply, changed_work); - int i; dev_dbg(psy->dev, "%s\n", __FUNCTION__); - for (i = 0; i < psy->num_supplicants; i++) { - struct device *dev; - - down(&power_supply_class->sem); - list_for_each_entry(dev, &power_supply_class->devices, node) { - struct power_supply *pst = dev_get_drvdata(dev); - - if (!strcmp(psy->supplied_to[i], pst->name)) { - if (pst->external_power_changed) - pst->external_power_changed(pst); - } - } - up(&power_supply_class->sem); - } + class_for_each_device(power_supply_class, psy, + __power_supply_changed_work); power_supply_update_leds(psy); @@ -55,32 +56,35 @@ void power_supply_changed(struct power_supply *psy) schedule_work(&psy->changed_work); } -int power_supply_am_i_supplied(struct power_supply *psy) +static int __power_supply_am_i_supplied(struct device *dev, void *data) { union power_supply_propval ret = {0,}; - struct device *dev; - - down(&power_supply_class->sem); - list_for_each_entry(dev, &power_supply_class->devices, node) { - struct power_supply *epsy = dev_get_drvdata(dev); - int i; - - for (i = 0; i < epsy->num_supplicants; i++) { - if (!strcmp(epsy->supplied_to[i], psy->name)) { - if (epsy->get_property(epsy, - POWER_SUPPLY_PROP_ONLINE, &ret)) - continue; - if (ret.intval) - goto out; - } + struct power_supply *psy = (struct power_supply *)data; + struct power_supply *epsy = dev_get_drvdata(dev); + int i; + + for (i = 0; i < epsy->num_supplicants; i++) { + if (!strcmp(epsy->supplied_to[i], psy->name)) { + if (epsy->get_property(epsy, + POWER_SUPPLY_PROP_ONLINE, &ret)) + continue; + if (ret.intval) + return ret.intval; } } -out: - up(&power_supply_class->sem); + return 0; +} + +int power_supply_am_i_supplied(struct power_supply *psy) +{ + int error; + + error = class_for_each_device(power_supply_class, psy, + __power_supply_am_i_supplied); - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval); + dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error); - return ret.intval; + return error; } int power_supply_register(struct device *parent, struct power_supply *psy) diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h index b242cee656e7..80e3f03b5041 100644 --- a/drivers/rapidio/rio.h +++ b/drivers/rapidio/rio.h @@ -31,8 +31,8 @@ extern struct rio_route_ops __end_rio_route_ops[]; /* Helpers internal to the RIO core code */ #define DECLARE_RIO_ROUTE_SECTION(section, vid, did, add_hook, get_hook) \ - static struct rio_route_ops __rio_route_ops __attribute_used__ \ - __attribute__((__section__(#section))) = { vid, did, add_hook, get_hook }; + static struct rio_route_ops __rio_route_ops __used \ + __section(section)= { vid, did, add_hook, get_hook }; /** * DECLARE_RIO_ROUTE_OPS - Registers switch routing operations diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 1e6715ec51ef..45e4b9648176 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -404,7 +404,7 @@ config RTC_DRV_SA1100 config RTC_DRV_SH tristate "SuperH On-Chip RTC" - depends on RTC_CLASS && (CPU_SH3 || CPU_SH4) + depends on RTC_CLASS && SUPERH help Say Y here to enable support for the on-chip RTC found in most SuperH processors. diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index f1e00ff54ce8..7e3ad4f3b343 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -251,20 +251,23 @@ void rtc_update_irq(struct rtc_device *rtc, } EXPORT_SYMBOL_GPL(rtc_update_irq); +static int __rtc_match(struct device *dev, void *data) +{ + char *name = (char *)data; + + if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) + return 1; + return 0; +} + struct rtc_device *rtc_class_open(char *name) { struct device *dev; struct rtc_device *rtc = NULL; - down(&rtc_class->sem); - list_for_each_entry(dev, &rtc_class->devices, node) { - if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) { - dev = get_device(dev); - if (dev) - rtc = to_rtc_device(dev); - break; - } - } + dev = class_find_device(rtc_class, name, __rtc_match); + if (dev) + rtc = to_rtc_device(dev); if (rtc) { if (!try_module_get(rtc->owner)) { @@ -272,7 +275,6 @@ struct rtc_device *rtc_class_open(char *name) rtc = NULL; } } - up(&rtc_class->sem); return rtc; } diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index dfef1637bfb8..e0900ca678ec 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -16,7 +16,7 @@ #define DRV_VERSION "0.3" /* Addresses to scan: none. This chip cannot be detected. */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD; diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index 1c743641b73b..725b0c73c333 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -61,7 +61,7 @@ /* i2c configuration */ #define ISL1208_I2C_ADDR 0xde -static unsigned short normal_i2c[] = { +static const unsigned short normal_i2c[] = { ISL1208_I2C_ADDR>>1, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; /* defines addr_data */ diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index a1cd448639c9..7683412970c4 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -54,7 +54,7 @@ #define MAX6900_I2C_ADDR 0xa0 -static unsigned short normal_i2c[] = { +static const unsigned short normal_i2c[] = { MAX6900_I2C_ADDR >> 1, I2C_CLIENT_END }; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 0242d803ebe5..b3317fcc16c3 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -25,7 +25,7 @@ * located at 0x51 will pass the validation routine due to * the way the registers are implemented. */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /* Module parameters */ I2C_CLIENT_INSMOD; diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 556d0e7da35b..c973ba94c422 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -40,7 +40,7 @@ struct pcf8583 { #define CTRL_ALARM 0x02 #define CTRL_TIMER 0x01 -static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; /* Module parameters */ I2C_CLIENT_INSMOD; diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 6f1e9a9804bc..2eb38520f0c8 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -337,6 +337,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc)) return PTR_ERR(rtc); + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, rtc); return 0; @@ -352,9 +354,38 @@ static int sa1100_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (pdev->dev.power.power_state.event != state.event) { + if (state.event == PM_EVENT_SUSPEND && + device_may_wakeup(&pdev->dev)) + enable_irq_wake(IRQ_RTCAlrm); + + pdev->dev.power.power_state = state; + } + return 0; +} + +static int sa1100_rtc_resume(struct platform_device *pdev) +{ + if (pdev->dev.power.power_state.event != PM_EVENT_ON) { + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(IRQ_RTCAlrm); + pdev->dev.power.power_state = PMSG_ON; + } + return 0; +} +#else +#define sa1100_rtc_suspend NULL +#define sa1100_rtc_resume NULL +#endif + static struct platform_driver sa1100_rtc_driver = { .probe = sa1100_rtc_probe, .remove = sa1100_rtc_remove, + .suspend = sa1100_rtc_suspend, + .resume = sa1100_rtc_resume, .driver = { .name = "sa1100-rtc", }, diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 8e8c8b8e81ee..c1d6a1880ccf 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -26,17 +26,7 @@ #include <asm/rtc.h> #define DRV_NAME "sh-rtc" -#define DRV_VERSION "0.1.3" - -#ifdef CONFIG_CPU_SH3 -#define rtc_reg_size sizeof(u16) -#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ -#define RTC_DEF_CAPABILITIES 0UL -#elif defined(CONFIG_CPU_SH4) -#define rtc_reg_size sizeof(u32) -#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ -#define RTC_DEF_CAPABILITIES RTC_CAP_4_DIGIT_YEAR -#endif +#define DRV_VERSION "0.1.6" #define RTC_REG(r) ((r) * rtc_reg_size) @@ -58,6 +48,18 @@ #define RCR1 RTC_REG(14) /* Control */ #define RCR2 RTC_REG(15) /* Control */ +/* + * Note on RYRAR and RCR3: Up until this point most of the register + * definitions are consistent across all of the available parts. However, + * the placement of the optional RYRAR and RCR3 (the RYRAR control + * register used to control RYRCNT/RYRAR compare) varies considerably + * across various parts, occasionally being mapped in to a completely + * unrelated address space. For proper RYRAR support a separate resource + * would have to be handed off, but as this is purely optional in + * practice, we simply opt not to support it, thereby keeping the code + * quite a bit more simplified. + */ + /* ALARM Bits - or with BCD encoded value */ #define AR_ENB 0x80 /* Enable for alarm cmp */ diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index b3fae357ca49..b90fb1866ce9 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -32,7 +32,7 @@ * unknown chips, the user must explicitly set the probe parameter. */ -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD; diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index be9f22d52fd8..0a89e080b389 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile @@ -2,8 +2,8 @@ # S/390 block devices # -dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o -dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o +dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_alias.o +dasd_fba_mod-objs := dasd_fba.o dasd_diag_mod-objs := dasd_diag.o dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \ dasd_genhd.o dasd_erp.o diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index e6bfce690ca3..d640427c74c8 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -48,13 +48,15 @@ MODULE_LICENSE("GPL"); /* * SECTION: prototypes for static functions of dasd.c */ -static int dasd_alloc_queue(struct dasd_device * device); -static void dasd_setup_queue(struct dasd_device * device); -static void dasd_free_queue(struct dasd_device * device); -static void dasd_flush_request_queue(struct dasd_device *); -static int dasd_flush_ccw_queue(struct dasd_device *, int); -static void dasd_tasklet(struct dasd_device *); +static int dasd_alloc_queue(struct dasd_block *); +static void dasd_setup_queue(struct dasd_block *); +static void dasd_free_queue(struct dasd_block *); +static void dasd_flush_request_queue(struct dasd_block *); +static int dasd_flush_block_queue(struct dasd_block *); +static void dasd_device_tasklet(struct dasd_device *); +static void dasd_block_tasklet(struct dasd_block *); static void do_kick_device(struct work_struct *); +static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); /* * SECTION: Operations on the device structure. @@ -65,26 +67,23 @@ static wait_queue_head_t dasd_flush_wq; /* * Allocate memory for a new device structure. */ -struct dasd_device * -dasd_alloc_device(void) +struct dasd_device *dasd_alloc_device(void) { struct dasd_device *device; - device = kzalloc(sizeof (struct dasd_device), GFP_ATOMIC); - if (device == NULL) + device = kzalloc(sizeof(struct dasd_device), GFP_ATOMIC); + if (!device) return ERR_PTR(-ENOMEM); - /* open_count = 0 means device online but not in use */ - atomic_set(&device->open_count, -1); /* Get two pages for normal block device operations. */ device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1); - if (device->ccw_mem == NULL) { + if (!device->ccw_mem) { kfree(device); return ERR_PTR(-ENOMEM); } /* Get one page for error recovery. */ device->erp_mem = (void *) get_zeroed_page(GFP_ATOMIC | GFP_DMA); - if (device->erp_mem == NULL) { + if (!device->erp_mem) { free_pages((unsigned long) device->ccw_mem, 1); kfree(device); return ERR_PTR(-ENOMEM); @@ -93,10 +92,9 @@ dasd_alloc_device(void) dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2); dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE); spin_lock_init(&device->mem_lock); - spin_lock_init(&device->request_queue_lock); - atomic_set (&device->tasklet_scheduled, 0); + atomic_set(&device->tasklet_scheduled, 0); tasklet_init(&device->tasklet, - (void (*)(unsigned long)) dasd_tasklet, + (void (*)(unsigned long)) dasd_device_tasklet, (unsigned long) device); INIT_LIST_HEAD(&device->ccw_queue); init_timer(&device->timer); @@ -110,8 +108,7 @@ dasd_alloc_device(void) /* * Free memory of a device structure. */ -void -dasd_free_device(struct dasd_device *device) +void dasd_free_device(struct dasd_device *device) { kfree(device->private); free_page((unsigned long) device->erp_mem); @@ -120,10 +117,42 @@ dasd_free_device(struct dasd_device *device) } /* + * Allocate memory for a new device structure. + */ +struct dasd_block *dasd_alloc_block(void) +{ + struct dasd_block *block; + + block = kzalloc(sizeof(*block), GFP_ATOMIC); + if (!block) + return ERR_PTR(-ENOMEM); + /* open_count = 0 means device online but not in use */ + atomic_set(&block->open_count, -1); + + spin_lock_init(&block->request_queue_lock); + atomic_set(&block->tasklet_scheduled, 0); + tasklet_init(&block->tasklet, + (void (*)(unsigned long)) dasd_block_tasklet, + (unsigned long) block); + INIT_LIST_HEAD(&block->ccw_queue); + spin_lock_init(&block->queue_lock); + init_timer(&block->timer); + + return block; +} + +/* + * Free memory of a device structure. + */ +void dasd_free_block(struct dasd_block *block) +{ + kfree(block); +} + +/* * Make a new device known to the system. */ -static int -dasd_state_new_to_known(struct dasd_device *device) +static int dasd_state_new_to_known(struct dasd_device *device) { int rc; @@ -133,12 +162,13 @@ dasd_state_new_to_known(struct dasd_device *device) */ dasd_get_device(device); - rc = dasd_alloc_queue(device); - if (rc) { - dasd_put_device(device); - return rc; + if (device->block) { + rc = dasd_alloc_queue(device->block); + if (rc) { + dasd_put_device(device); + return rc; + } } - device->state = DASD_STATE_KNOWN; return 0; } @@ -146,21 +176,24 @@ dasd_state_new_to_known(struct dasd_device *device) /* * Let the system forget about a device. */ -static int -dasd_state_known_to_new(struct dasd_device * device) +static int dasd_state_known_to_new(struct dasd_device *device) { /* Disable extended error reporting for this device. */ dasd_eer_disable(device); /* Forget the discipline information. */ - if (device->discipline) + if (device->discipline) { + if (device->discipline->uncheck_device) + device->discipline->uncheck_device(device); module_put(device->discipline->owner); + } device->discipline = NULL; if (device->base_discipline) module_put(device->base_discipline->owner); device->base_discipline = NULL; device->state = DASD_STATE_NEW; - dasd_free_queue(device); + if (device->block) + dasd_free_queue(device->block); /* Give up reference we took in dasd_state_new_to_known. */ dasd_put_device(device); @@ -170,19 +203,19 @@ dasd_state_known_to_new(struct dasd_device * device) /* * Request the irq line for the device. */ -static int -dasd_state_known_to_basic(struct dasd_device * device) +static int dasd_state_known_to_basic(struct dasd_device *device) { int rc; /* Allocate and register gendisk structure. */ - rc = dasd_gendisk_alloc(device); - if (rc) - return rc; - + if (device->block) { + rc = dasd_gendisk_alloc(device->block); + if (rc) + return rc; + } /* register 'device' debug area, used for all DBF_DEV_XXX calls */ - device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2, - 8 * sizeof (long)); + device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 1, + 8 * sizeof(long)); debug_register_view(device->debug_area, &debug_sprintf_view); debug_set_level(device->debug_area, DBF_WARNING); DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created"); @@ -194,16 +227,17 @@ dasd_state_known_to_basic(struct dasd_device * device) /* * Release the irq line for the device. Terminate any running i/o. */ -static int -dasd_state_basic_to_known(struct dasd_device * device) +static int dasd_state_basic_to_known(struct dasd_device *device) { int rc; - - dasd_gendisk_free(device); - rc = dasd_flush_ccw_queue(device, 1); + if (device->block) { + dasd_gendisk_free(device->block); + dasd_block_clear_timer(device->block); + } + rc = dasd_flush_device_queue(device); if (rc) return rc; - dasd_clear_timer(device); + dasd_device_clear_timer(device); DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device); if (device->debug_area != NULL) { @@ -228,26 +262,32 @@ dasd_state_basic_to_known(struct dasd_device * device) * In case the analysis returns an error, the device setup is stopped * (a fake disk was already added to allow formatting). */ -static int -dasd_state_basic_to_ready(struct dasd_device * device) +static int dasd_state_basic_to_ready(struct dasd_device *device) { int rc; + struct dasd_block *block; rc = 0; - if (device->discipline->do_analysis != NULL) - rc = device->discipline->do_analysis(device); - if (rc) { - if (rc != -EAGAIN) - device->state = DASD_STATE_UNFMT; - return rc; - } + block = device->block; /* make disk known with correct capacity */ - dasd_setup_queue(device); - set_capacity(device->gdp, device->blocks << device->s2b_shift); - device->state = DASD_STATE_READY; - rc = dasd_scan_partitions(device); - if (rc) - device->state = DASD_STATE_BASIC; + if (block) { + if (block->base->discipline->do_analysis != NULL) + rc = block->base->discipline->do_analysis(block); + if (rc) { + if (rc != -EAGAIN) + device->state = DASD_STATE_UNFMT; + return rc; + } + dasd_setup_queue(block); + set_capacity(block->gdp, + block->blocks << block->s2b_shift); + device->state = DASD_STATE_READY; + rc = dasd_scan_partitions(block); + if (rc) + device->state = DASD_STATE_BASIC; + } else { + device->state = DASD_STATE_READY; + } return rc; } @@ -256,28 +296,31 @@ dasd_state_basic_to_ready(struct dasd_device * device) * Forget format information. Check if the target level is basic * and if it is create fake disk for formatting. */ -static int -dasd_state_ready_to_basic(struct dasd_device * device) +static int dasd_state_ready_to_basic(struct dasd_device *device) { int rc; - rc = dasd_flush_ccw_queue(device, 0); - if (rc) - return rc; - dasd_destroy_partitions(device); - dasd_flush_request_queue(device); - device->blocks = 0; - device->bp_block = 0; - device->s2b_shift = 0; device->state = DASD_STATE_BASIC; + if (device->block) { + struct dasd_block *block = device->block; + rc = dasd_flush_block_queue(block); + if (rc) { + device->state = DASD_STATE_READY; + return rc; + } + dasd_destroy_partitions(block); + dasd_flush_request_queue(block); + block->blocks = 0; + block->bp_block = 0; + block->s2b_shift = 0; + } return 0; } /* * Back to basic. */ -static int -dasd_state_unfmt_to_basic(struct dasd_device * device) +static int dasd_state_unfmt_to_basic(struct dasd_device *device) { device->state = DASD_STATE_BASIC; return 0; @@ -291,17 +334,31 @@ dasd_state_unfmt_to_basic(struct dasd_device * device) static int dasd_state_ready_to_online(struct dasd_device * device) { + int rc; + + if (device->discipline->ready_to_online) { + rc = device->discipline->ready_to_online(device); + if (rc) + return rc; + } device->state = DASD_STATE_ONLINE; - dasd_schedule_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); return 0; } /* * Stop the requeueing of requests again. */ -static int -dasd_state_online_to_ready(struct dasd_device * device) +static int dasd_state_online_to_ready(struct dasd_device *device) { + int rc; + + if (device->discipline->online_to_ready) { + rc = device->discipline->online_to_ready(device); + if (rc) + return rc; + } device->state = DASD_STATE_READY; return 0; } @@ -309,8 +366,7 @@ dasd_state_online_to_ready(struct dasd_device * device) /* * Device startup state changes. */ -static int -dasd_increase_state(struct dasd_device *device) +static int dasd_increase_state(struct dasd_device *device) { int rc; @@ -345,8 +401,7 @@ dasd_increase_state(struct dasd_device *device) /* * Device shutdown state changes. */ -static int -dasd_decrease_state(struct dasd_device *device) +static int dasd_decrease_state(struct dasd_device *device) { int rc; @@ -381,8 +436,7 @@ dasd_decrease_state(struct dasd_device *device) /* * This is the main startup/shutdown routine. */ -static void -dasd_change_state(struct dasd_device *device) +static void dasd_change_state(struct dasd_device *device) { int rc; @@ -409,17 +463,15 @@ dasd_change_state(struct dasd_device *device) * dasd_kick_device will schedule a call do do_kick_device to the kernel * event daemon. */ -static void -do_kick_device(struct work_struct *work) +static void do_kick_device(struct work_struct *work) { struct dasd_device *device = container_of(work, struct dasd_device, kick_work); dasd_change_state(device); - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); dasd_put_device(device); } -void -dasd_kick_device(struct dasd_device *device) +void dasd_kick_device(struct dasd_device *device) { dasd_get_device(device); /* queue call to dasd_kick_device to the kernel event daemon. */ @@ -429,8 +481,7 @@ dasd_kick_device(struct dasd_device *device) /* * Set the target state for a device and starts the state change. */ -void -dasd_set_target_state(struct dasd_device *device, int target) +void dasd_set_target_state(struct dasd_device *device, int target) { /* If we are in probeonly mode stop at DASD_STATE_READY. */ if (dasd_probeonly && target > DASD_STATE_READY) @@ -447,14 +498,12 @@ dasd_set_target_state(struct dasd_device *device, int target) /* * Enable devices with device numbers in [from..to]. */ -static inline int -_wait_for_device(struct dasd_device *device) +static inline int _wait_for_device(struct dasd_device *device) { return (device->state == device->target); } -void -dasd_enable_device(struct dasd_device *device) +void dasd_enable_device(struct dasd_device *device) { dasd_set_target_state(device, DASD_STATE_ONLINE); if (device->state <= DASD_STATE_KNOWN) @@ -475,20 +524,20 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF; /* * Increments counter in global and local profiling structures. */ -#define dasd_profile_counter(value, counter, device) \ +#define dasd_profile_counter(value, counter, block) \ { \ int index; \ for (index = 0; index < 31 && value >> (2+index); index++); \ dasd_global_profile.counter[index]++; \ - device->profile.counter[index]++; \ + block->profile.counter[index]++; \ } /* * Add profiling information for cqr before execution. */ -static void -dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, - struct request *req) +static void dasd_profile_start(struct dasd_block *block, + struct dasd_ccw_req *cqr, + struct request *req) { struct list_head *l; unsigned int counter; @@ -498,19 +547,19 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, /* count the length of the chanq for statistics */ counter = 0; - list_for_each(l, &device->ccw_queue) + list_for_each(l, &block->ccw_queue) if (++counter >= 31) break; dasd_global_profile.dasd_io_nr_req[counter]++; - device->profile.dasd_io_nr_req[counter]++; + block->profile.dasd_io_nr_req[counter]++; } /* * Add profiling information for cqr after execution. */ -static void -dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, - struct request *req) +static void dasd_profile_end(struct dasd_block *block, + struct dasd_ccw_req *cqr, + struct request *req) { long strtime, irqtime, endtime, tottime; /* in microseconds */ long tottimeps, sectors; @@ -532,27 +581,27 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, if (!dasd_global_profile.dasd_io_reqs) memset(&dasd_global_profile, 0, - sizeof (struct dasd_profile_info_t)); + sizeof(struct dasd_profile_info_t)); dasd_global_profile.dasd_io_reqs++; dasd_global_profile.dasd_io_sects += sectors; - if (!device->profile.dasd_io_reqs) - memset(&device->profile, 0, - sizeof (struct dasd_profile_info_t)); - device->profile.dasd_io_reqs++; - device->profile.dasd_io_sects += sectors; + if (!block->profile.dasd_io_reqs) + memset(&block->profile, 0, + sizeof(struct dasd_profile_info_t)); + block->profile.dasd_io_reqs++; + block->profile.dasd_io_sects += sectors; - dasd_profile_counter(sectors, dasd_io_secs, device); - dasd_profile_counter(tottime, dasd_io_times, device); - dasd_profile_counter(tottimeps, dasd_io_timps, device); - dasd_profile_counter(strtime, dasd_io_time1, device); - dasd_profile_counter(irqtime, dasd_io_time2, device); - dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device); - dasd_profile_counter(endtime, dasd_io_time3, device); + dasd_profile_counter(sectors, dasd_io_secs, block); + dasd_profile_counter(tottime, dasd_io_times, block); + dasd_profile_counter(tottimeps, dasd_io_timps, block); + dasd_profile_counter(strtime, dasd_io_time1, block); + dasd_profile_counter(irqtime, dasd_io_time2, block); + dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, block); + dasd_profile_counter(endtime, dasd_io_time3, block); } #else -#define dasd_profile_start(device, cqr, req) do {} while (0) -#define dasd_profile_end(device, cqr, req) do {} while (0) +#define dasd_profile_start(block, cqr, req) do {} while (0) +#define dasd_profile_end(block, cqr, req) do {} while (0) #endif /* CONFIG_DASD_PROFILE */ /* @@ -562,9 +611,9 @@ dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, * memory and 2) dasd_smalloc_request uses the static ccw memory * that gets allocated for each device. */ -struct dasd_ccw_req * -dasd_kmalloc_request(char *magic, int cplength, int datasize, - struct dasd_device * device) +struct dasd_ccw_req *dasd_kmalloc_request(char *magic, int cplength, + int datasize, + struct dasd_device *device) { struct dasd_ccw_req *cqr; @@ -600,9 +649,9 @@ dasd_kmalloc_request(char *magic, int cplength, int datasize, return cqr; } -struct dasd_ccw_req * -dasd_smalloc_request(char *magic, int cplength, int datasize, - struct dasd_device * device) +struct dasd_ccw_req *dasd_smalloc_request(char *magic, int cplength, + int datasize, + struct dasd_device *device) { unsigned long flags; struct dasd_ccw_req *cqr; @@ -649,8 +698,7 @@ dasd_smalloc_request(char *magic, int cplength, int datasize, * idal lists that might have been created by dasd_set_cda and the * struct dasd_ccw_req itself. */ -void -dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) +void dasd_kfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) { #ifdef CONFIG_64BIT struct ccw1 *ccw; @@ -667,8 +715,7 @@ dasd_kfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) dasd_put_device(device); } -void -dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) +void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device) { unsigned long flags; @@ -681,14 +728,13 @@ dasd_sfree_request(struct dasd_ccw_req * cqr, struct dasd_device * device) /* * Check discipline magic in cqr. */ -static inline int -dasd_check_cqr(struct dasd_ccw_req *cqr) +static inline int dasd_check_cqr(struct dasd_ccw_req *cqr) { struct dasd_device *device; if (cqr == NULL) return -EINVAL; - device = cqr->device; + device = cqr->startdev; if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) { DEV_MESSAGE(KERN_WARNING, device, " dasd_ccw_req 0x%08x magic doesn't match" @@ -706,8 +752,7 @@ dasd_check_cqr(struct dasd_ccw_req *cqr) * ccw_device_clear can fail if the i/o subsystem * is in a bad mood. */ -int -dasd_term_IO(struct dasd_ccw_req * cqr) +int dasd_term_IO(struct dasd_ccw_req *cqr) { struct dasd_device *device; int retries, rc; @@ -717,13 +762,13 @@ dasd_term_IO(struct dasd_ccw_req * cqr) if (rc) return rc; retries = 0; - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev; while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) { rc = ccw_device_clear(device->cdev, (long) cqr); switch (rc) { case 0: /* termination successful */ cqr->retries--; - cqr->status = DASD_CQR_CLEAR; + cqr->status = DASD_CQR_CLEAR_PENDING; cqr->stopclk = get_clock(); cqr->starttime = 0; DBF_DEV_EVENT(DBF_DEBUG, device, @@ -753,7 +798,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr) } retries++; } - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); return rc; } @@ -761,8 +806,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr) * Start the i/o. This start_IO can fail if the channel is really busy. * In that case set up a timer to start the request later. */ -int -dasd_start_IO(struct dasd_ccw_req * cqr) +int dasd_start_IO(struct dasd_ccw_req *cqr) { struct dasd_device *device; int rc; @@ -771,12 +815,12 @@ dasd_start_IO(struct dasd_ccw_req * cqr) rc = dasd_check_cqr(cqr); if (rc) return rc; - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev; if (cqr->retries < 0) { DEV_MESSAGE(KERN_DEBUG, device, "start_IO: request %p (%02x/%i) - no retry left.", cqr, cqr->status, cqr->retries); - cqr->status = DASD_CQR_FAILED; + cqr->status = DASD_CQR_ERROR; return -EIO; } cqr->startclk = get_clock(); @@ -833,8 +877,7 @@ dasd_start_IO(struct dasd_ccw_req * cqr) * The head of the ccw queue will have status DASD_CQR_IN_IO for 1), * DASD_CQR_QUEUED for 2) and 3). */ -static void -dasd_timeout_device(unsigned long ptr) +static void dasd_device_timeout(unsigned long ptr) { unsigned long flags; struct dasd_device *device; @@ -844,14 +887,13 @@ dasd_timeout_device(unsigned long ptr) /* re-activate request queue */ device->stopped &= ~DASD_STOPPED_PENDING; spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); } /* * Setup timeout for a device in jiffies. */ -void -dasd_set_timer(struct dasd_device *device, int expires) +void dasd_device_set_timer(struct dasd_device *device, int expires) { if (expires == 0) { if (timer_pending(&device->timer)) @@ -862,7 +904,7 @@ dasd_set_timer(struct dasd_device *device, int expires) if (mod_timer(&device->timer, jiffies + expires)) return; } - device->timer.function = dasd_timeout_device; + device->timer.function = dasd_device_timeout; device->timer.data = (unsigned long) device; device->timer.expires = jiffies + expires; add_timer(&device->timer); @@ -871,15 +913,14 @@ dasd_set_timer(struct dasd_device *device, int expires) /* * Clear timeout for a device. */ -void -dasd_clear_timer(struct dasd_device *device) +void dasd_device_clear_timer(struct dasd_device *device) { if (timer_pending(&device->timer)) del_timer(&device->timer); } -static void -dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) +static void dasd_handle_killed_request(struct ccw_device *cdev, + unsigned long intparm) { struct dasd_ccw_req *cqr; struct dasd_device *device; @@ -893,7 +934,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) return; } - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev; if (device == NULL || device != dasd_device_from_cdev_locked(cdev) || strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { @@ -905,46 +946,32 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm) /* Schedule request to be retried. */ cqr->status = DASD_CQR_QUEUED; - dasd_clear_timer(device); - dasd_schedule_bh(device); + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); dasd_put_device(device); } -static void -dasd_handle_state_change_pending(struct dasd_device *device) +void dasd_generic_handle_state_change(struct dasd_device *device) { - struct dasd_ccw_req *cqr; - struct list_head *l, *n; - /* First of all start sense subsystem status request. */ dasd_eer_snss(device); device->stopped &= ~DASD_STOPPED_PENDING; - - /* restart all 'running' IO on queue */ - list_for_each_safe(l, n, &device->ccw_queue) { - cqr = list_entry(l, struct dasd_ccw_req, list); - if (cqr->status == DASD_CQR_IN_IO) { - cqr->status = DASD_CQR_QUEUED; - } - } - dasd_clear_timer(device); - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); } /* * Interrupt handler for "normal" ssch-io based dasd devices. */ -void -dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, - struct irb *irb) +void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, + struct irb *irb) { struct dasd_ccw_req *cqr, *next; struct dasd_device *device; unsigned long long now; int expires; - dasd_era_t era; - char mask; if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { @@ -969,29 +996,25 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat), (unsigned int) intparm); - /* first of all check for state change pending interrupt */ - mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.dstat & mask) == mask) { + /* check for unsolicited interrupts */ + cqr = (struct dasd_ccw_req *) intparm; + if (!cqr || ((irb->scsw.cc == 1) && + (irb->scsw.fctl & SCSW_FCTL_START_FUNC) && + (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) { + if (cqr && cqr->status == DASD_CQR_IN_IO) + cqr->status = DASD_CQR_QUEUED; device = dasd_device_from_cdev_locked(cdev); if (!IS_ERR(device)) { - dasd_handle_state_change_pending(device); + dasd_device_clear_timer(device); + device->discipline->handle_unsolicited_interrupt(device, + irb); dasd_put_device(device); } return; } - cqr = (struct dasd_ccw_req *) intparm; - - /* check for unsolicited interrupts */ - if (cqr == NULL) { - MESSAGE(KERN_DEBUG, - "unsolicited interrupt received: bus_id %s", - cdev->dev.bus_id); - return; - } - - device = (struct dasd_device *) cqr->device; - if (device == NULL || + device = (struct dasd_device *) cqr->startdev; + if (!device || strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s", cdev->dev.bus_id); @@ -999,12 +1022,12 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, } /* Check for clear pending */ - if (cqr->status == DASD_CQR_CLEAR && + if (cqr->status == DASD_CQR_CLEAR_PENDING && irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { - cqr->status = DASD_CQR_QUEUED; - dasd_clear_timer(device); + cqr->status = DASD_CQR_CLEARED; + dasd_device_clear_timer(device); wake_up(&dasd_flush_wq); - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); return; } @@ -1017,277 +1040,170 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, } DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr); - - /* Find out the appropriate era_action. */ - if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) - era = dasd_era_fatal; - else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && - irb->scsw.cstat == 0 && - !irb->esw.esw0.erw.cons) - era = dasd_era_none; - else if (irb->esw.esw0.erw.cons) - era = device->discipline->examine_error(cqr, irb); - else - era = dasd_era_recover; - - DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era); + next = NULL; expires = 0; - if (era == dasd_era_none) { - cqr->status = DASD_CQR_DONE; + if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && + irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) { + /* request was completed successfully */ + cqr->status = DASD_CQR_SUCCESS; cqr->stopclk = now; /* Start first request on queue if possible -> fast_io. */ - if (cqr->list.next != &device->ccw_queue) { - next = list_entry(cqr->list.next, - struct dasd_ccw_req, list); - if ((next->status == DASD_CQR_QUEUED) && - (!device->stopped)) { - if (device->discipline->start_IO(next) == 0) - expires = next->expires; - else - DEV_MESSAGE(KERN_DEBUG, device, "%s", - "Interrupt fastpath " - "failed!"); - } + if (cqr->devlist.next != &device->ccw_queue) { + next = list_entry(cqr->devlist.next, + struct dasd_ccw_req, devlist); } - } else { /* error */ - memcpy(&cqr->irb, irb, sizeof (struct irb)); + } else { /* error */ + memcpy(&cqr->irb, irb, sizeof(struct irb)); if (device->features & DASD_FEATURE_ERPLOG) { - /* dump sense data */ dasd_log_sense(cqr, irb); } - switch (era) { - case dasd_era_fatal: - cqr->status = DASD_CQR_FAILED; - cqr->stopclk = now; - break; - case dasd_era_recover: + /* If we have no sense data, or we just don't want complex ERP + * for this request, but if we have retries left, then just + * reset this request and retry it in the fastpath + */ + if (!(cqr->irb.esw.esw0.erw.cons && + test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) && + cqr->retries > 0) { + DEV_MESSAGE(KERN_DEBUG, device, + "default ERP in fastpath (%i retries left)", + cqr->retries); + cqr->lpm = LPM_ANYPATH; + cqr->status = DASD_CQR_QUEUED; + next = cqr; + } else cqr->status = DASD_CQR_ERROR; - break; - default: - BUG(); - } + } + if (next && (next->status == DASD_CQR_QUEUED) && + (!device->stopped)) { + if (device->discipline->start_IO(next) == 0) + expires = next->expires; + else + DEV_MESSAGE(KERN_DEBUG, device, "%s", + "Interrupt fastpath " + "failed!"); } if (expires != 0) - dasd_set_timer(device, expires); + dasd_device_set_timer(device, expires); else - dasd_clear_timer(device); - dasd_schedule_bh(device); + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); } /* - * posts the buffer_cache about a finalized request + * If we have an error on a dasd_block layer request then we cancel + * and return all further requests from the same dasd_block as well. */ -static inline void -dasd_end_request(struct request *req, int uptodate) +static void __dasd_device_recovery(struct dasd_device *device, + struct dasd_ccw_req *ref_cqr) { - if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) - BUG(); - add_disk_randomness(req->rq_disk); - end_that_request_last(req, uptodate); -} + struct list_head *l, *n; + struct dasd_ccw_req *cqr; -/* - * Process finished error recovery ccw. - */ -static inline void -__dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr) -{ - dasd_erp_fn_t erp_fn; + /* + * only requeue request that came from the dasd_block layer + */ + if (!ref_cqr->block) + return; - if (cqr->status == DASD_CQR_DONE) - DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful"); - else - DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful"); - erp_fn = device->discipline->erp_postaction(cqr); - erp_fn(cqr); -} + list_for_each_safe(l, n, &device->ccw_queue) { + cqr = list_entry(l, struct dasd_ccw_req, devlist); + if (cqr->status == DASD_CQR_QUEUED && + ref_cqr->block == cqr->block) { + cqr->status = DASD_CQR_CLEARED; + } + } +}; /* - * Process ccw request queue. + * Remove those ccw requests from the queue that need to be returned + * to the upper layer. */ -static void -__dasd_process_ccw_queue(struct dasd_device * device, - struct list_head *final_queue) +static void __dasd_device_process_ccw_queue(struct dasd_device *device, + struct list_head *final_queue) { struct list_head *l, *n; struct dasd_ccw_req *cqr; - dasd_erp_fn_t erp_fn; -restart: /* Process request with final status. */ list_for_each_safe(l, n, &device->ccw_queue) { - cqr = list_entry(l, struct dasd_ccw_req, list); + cqr = list_entry(l, struct dasd_ccw_req, devlist); + /* Stop list processing at the first non-final request. */ - if (cqr->status != DASD_CQR_DONE && - cqr->status != DASD_CQR_FAILED && - cqr->status != DASD_CQR_ERROR) + if (cqr->status == DASD_CQR_QUEUED || + cqr->status == DASD_CQR_IN_IO || + cqr->status == DASD_CQR_CLEAR_PENDING) break; - /* Process requests with DASD_CQR_ERROR */ if (cqr->status == DASD_CQR_ERROR) { - if (cqr->irb.scsw.fctl & SCSW_FCTL_HALT_FUNC) { - cqr->status = DASD_CQR_FAILED; - cqr->stopclk = get_clock(); - } else { - if (cqr->irb.esw.esw0.erw.cons && - test_bit(DASD_CQR_FLAGS_USE_ERP, - &cqr->flags)) { - erp_fn = device->discipline-> - erp_action(cqr); - erp_fn(cqr); - } else - dasd_default_erp_action(cqr); - } - goto restart; - } - - /* First of all call extended error reporting. */ - if (dasd_eer_enabled(device) && - cqr->status == DASD_CQR_FAILED) { - dasd_eer_write(device, cqr, DASD_EER_FATALERROR); - - /* restart request */ - cqr->status = DASD_CQR_QUEUED; - cqr->retries = 255; - device->stopped |= DASD_STOPPED_QUIESCE; - goto restart; + __dasd_device_recovery(device, cqr); } - - /* Process finished ERP request. */ - if (cqr->refers) { - __dasd_process_erp(device, cqr); - goto restart; - } - /* Rechain finished requests to final queue */ - cqr->endclk = get_clock(); - list_move_tail(&cqr->list, final_queue); + list_move_tail(&cqr->devlist, final_queue); } } -static void -dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data) -{ - struct request *req; - struct dasd_device *device; - int status; - - req = (struct request *) data; - device = cqr->device; - dasd_profile_end(device, cqr, req); - status = cqr->device->discipline->free_cp(cqr,req); - spin_lock_irq(&device->request_queue_lock); - dasd_end_request(req, status); - spin_unlock_irq(&device->request_queue_lock); -} - - /* - * Fetch requests from the block device queue. + * the cqrs from the final queue are returned to the upper layer + * by setting a dasd_block state and calling the callback function */ -static void -__dasd_process_blk_queue(struct dasd_device * device) +static void __dasd_device_process_final_queue(struct dasd_device *device, + struct list_head *final_queue) { - struct request_queue *queue; - struct request *req; + struct list_head *l, *n; struct dasd_ccw_req *cqr; - int nr_queued; - - queue = device->request_queue; - /* No queue ? Then there is nothing to do. */ - if (queue == NULL) - return; - - /* - * We requeue request from the block device queue to the ccw - * queue only in two states. In state DASD_STATE_READY the - * partition detection is done and we need to requeue requests - * for that. State DASD_STATE_ONLINE is normal block device - * operation. - */ - if (device->state != DASD_STATE_READY && - device->state != DASD_STATE_ONLINE) - return; - nr_queued = 0; - /* Now we try to fetch requests from the request queue */ - list_for_each_entry(cqr, &device->ccw_queue, list) - if (cqr->status == DASD_CQR_QUEUED) - nr_queued++; - while (!blk_queue_plugged(queue) && - elv_next_request(queue) && - nr_queued < DASD_CHANQ_MAX_SIZE) { - req = elv_next_request(queue); - if (device->features & DASD_FEATURE_READONLY && - rq_data_dir(req) == WRITE) { - DBF_DEV_EVENT(DBF_ERR, device, - "Rejecting write request %p", - req); - blkdev_dequeue_request(req); - dasd_end_request(req, 0); - continue; - } - if (device->stopped & DASD_STOPPED_DC_EIO) { - blkdev_dequeue_request(req); - dasd_end_request(req, 0); - continue; - } - cqr = device->discipline->build_cp(device, req); - if (IS_ERR(cqr)) { - if (PTR_ERR(cqr) == -ENOMEM) - break; /* terminate request queue loop */ - if (PTR_ERR(cqr) == -EAGAIN) { - /* - * The current request cannot be build right - * now, we have to try later. If this request - * is the head-of-queue we stop the device - * for 1/2 second. - */ - if (!list_empty(&device->ccw_queue)) - break; - device->stopped |= DASD_STOPPED_PENDING; - dasd_set_timer(device, HZ/2); - break; - } - DBF_DEV_EVENT(DBF_ERR, device, - "CCW creation failed (rc=%ld) " - "on request %p", - PTR_ERR(cqr), req); - blkdev_dequeue_request(req); - dasd_end_request(req, 0); - continue; + list_for_each_safe(l, n, final_queue) { + cqr = list_entry(l, struct dasd_ccw_req, devlist); + list_del_init(&cqr->devlist); + if (cqr->block) + spin_lock_bh(&cqr->block->queue_lock); + switch (cqr->status) { + case DASD_CQR_SUCCESS: + cqr->status = DASD_CQR_DONE; + break; + case DASD_CQR_ERROR: + cqr->status = DASD_CQR_NEED_ERP; + break; + case DASD_CQR_CLEARED: + cqr->status = DASD_CQR_TERMINATED; + break; + default: + DEV_MESSAGE(KERN_ERR, device, + "wrong cqr status in __dasd_process_final_queue " + "for cqr %p, status %x", + cqr, cqr->status); + BUG(); } - cqr->callback = dasd_end_request_cb; - cqr->callback_data = (void *) req; - cqr->status = DASD_CQR_QUEUED; - blkdev_dequeue_request(req); - list_add_tail(&cqr->list, &device->ccw_queue); - dasd_profile_start(device, cqr, req); - nr_queued++; + if (cqr->block) + spin_unlock_bh(&cqr->block->queue_lock); + if (cqr->callback != NULL) + (cqr->callback)(cqr, cqr->callback_data); } } + + /* * Take a look at the first request on the ccw queue and check * if it reached its expire time. If so, terminate the IO. */ -static void -__dasd_check_expire(struct dasd_device * device) +static void __dasd_device_check_expire(struct dasd_device *device) { struct dasd_ccw_req *cqr; if (list_empty(&device->ccw_queue)) return; - cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); + cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); if ((cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) && (time_after_eq(jiffies, cqr->expires + cqr->starttime))) { if (device->discipline->term_IO(cqr) != 0) { /* Hmpf, try again in 5 sec */ - dasd_set_timer(device, 5*HZ); DEV_MESSAGE(KERN_ERR, device, "internal error - timeout (%is) expired " "for cqr %p, termination failed, " "retrying in 5s", (cqr->expires/HZ), cqr); + cqr->expires += 5*HZ; + dasd_device_set_timer(device, 5*HZ); } else { DEV_MESSAGE(KERN_ERR, device, "internal error - timeout (%is) expired " @@ -1301,77 +1217,53 @@ __dasd_check_expire(struct dasd_device * device) * Take a look at the first request on the ccw queue and check * if it needs to be started. */ -static void -__dasd_start_head(struct dasd_device * device) +static void __dasd_device_start_head(struct dasd_device *device) { struct dasd_ccw_req *cqr; int rc; if (list_empty(&device->ccw_queue)) return; - cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); + cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); if (cqr->status != DASD_CQR_QUEUED) return; - /* Non-temporary stop condition will trigger fail fast */ - if (device->stopped & ~DASD_STOPPED_PENDING && - test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && - (!dasd_eer_enabled(device))) { - cqr->status = DASD_CQR_FAILED; - dasd_schedule_bh(device); + /* when device is stopped, return request to previous layer */ + if (device->stopped) { + cqr->status = DASD_CQR_CLEARED; + dasd_schedule_device_bh(device); return; } - /* Don't try to start requests if device is stopped */ - if (device->stopped) - return; rc = device->discipline->start_IO(cqr); if (rc == 0) - dasd_set_timer(device, cqr->expires); + dasd_device_set_timer(device, cqr->expires); else if (rc == -EACCES) { - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); } else /* Hmpf, try again in 1/2 sec */ - dasd_set_timer(device, 50); -} - -static inline int -_wait_for_clear(struct dasd_ccw_req *cqr) -{ - return (cqr->status == DASD_CQR_QUEUED); + dasd_device_set_timer(device, 50); } /* - * Remove all requests from the ccw queue (all = '1') or only block device - * requests in case all = '0'. - * Take care of the erp-chain (chained via cqr->refers) and remove either - * the whole erp-chain or none of the erp-requests. - * If a request is currently running, term_IO is called and the request - * is re-queued. Prior to removing the terminated request we need to wait - * for the clear-interrupt. - * In case termination is not possible we stop processing and just finishing - * the already moved requests. + * Go through all request on the dasd_device request queue, + * terminate them on the cdev if necessary, and return them to the + * submitting layer via callback. + * Note: + * Make sure that all 'submitting layers' still exist when + * this function is called!. In other words, when 'device' is a base + * device then all block layer requests must have been removed before + * via dasd_flush_block_queue. */ -static int -dasd_flush_ccw_queue(struct dasd_device * device, int all) +int dasd_flush_device_queue(struct dasd_device *device) { - struct dasd_ccw_req *cqr, *orig, *n; - int rc, i; - + struct dasd_ccw_req *cqr, *n; + int rc; struct list_head flush_queue; INIT_LIST_HEAD(&flush_queue); spin_lock_irq(get_ccwdev_lock(device->cdev)); rc = 0; -restart: - list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) { - /* get original request of erp request-chain */ - for (orig = cqr; orig->refers != NULL; orig = orig->refers); - - /* Flush all request or only block device requests? */ - if (all == 0 && cqr->callback != dasd_end_request_cb && - orig->callback != dasd_end_request_cb) { - continue; - } + list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { /* Check status and move request to flush_queue */ switch (cqr->status) { case DASD_CQR_IN_IO: @@ -1387,90 +1279,60 @@ restart: } break; case DASD_CQR_QUEUED: - case DASD_CQR_ERROR: - /* set request to FAILED */ cqr->stopclk = get_clock(); - cqr->status = DASD_CQR_FAILED; + cqr->status = DASD_CQR_CLEARED; break; - default: /* do not touch the others */ + default: /* no need to modify the others */ break; } - /* Rechain request (including erp chain) */ - for (i = 0; cqr != NULL; cqr = cqr->refers, i++) { - cqr->endclk = get_clock(); - list_move_tail(&cqr->list, &flush_queue); - } - if (i > 1) - /* moved more than one request - need to restart */ - goto restart; + list_move_tail(&cqr->devlist, &flush_queue); } - finished: spin_unlock_irq(get_ccwdev_lock(device->cdev)); - /* Now call the callback function of flushed requests */ -restart_cb: - list_for_each_entry_safe(cqr, n, &flush_queue, list) { - if (cqr->status == DASD_CQR_CLEAR) { - /* wait for clear interrupt! */ - wait_event(dasd_flush_wq, _wait_for_clear(cqr)); - cqr->status = DASD_CQR_FAILED; - } - /* Process finished ERP request. */ - if (cqr->refers) { - __dasd_process_erp(device, cqr); - /* restart list_for_xx loop since dasd_process_erp - * might remove multiple elements */ - goto restart_cb; - } - /* call the callback function */ - cqr->endclk = get_clock(); - if (cqr->callback != NULL) - (cqr->callback)(cqr, cqr->callback_data); - } + /* + * After this point all requests must be in state CLEAR_PENDING, + * CLEARED, SUCCESS or ERROR. Now wait for CLEAR_PENDING to become + * one of the others. + */ + list_for_each_entry_safe(cqr, n, &flush_queue, devlist) + wait_event(dasd_flush_wq, + (cqr->status != DASD_CQR_CLEAR_PENDING)); + /* + * Now set each request back to TERMINATED, DONE or NEED_ERP + * and call the callback function of flushed requests + */ + __dasd_device_process_final_queue(device, &flush_queue); return rc; } /* * Acquire the device lock and process queues for the device. */ -static void -dasd_tasklet(struct dasd_device * device) +static void dasd_device_tasklet(struct dasd_device *device) { struct list_head final_queue; - struct list_head *l, *n; - struct dasd_ccw_req *cqr; atomic_set (&device->tasklet_scheduled, 0); INIT_LIST_HEAD(&final_queue); spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Check expire time of first request on the ccw queue. */ - __dasd_check_expire(device); - /* Finish off requests on ccw queue */ - __dasd_process_ccw_queue(device, &final_queue); + __dasd_device_check_expire(device); + /* find final requests on ccw queue */ + __dasd_device_process_ccw_queue(device, &final_queue); spin_unlock_irq(get_ccwdev_lock(device->cdev)); /* Now call the callback function of requests with final status */ - list_for_each_safe(l, n, &final_queue) { - cqr = list_entry(l, struct dasd_ccw_req, list); - list_del_init(&cqr->list); - if (cqr->callback != NULL) - (cqr->callback)(cqr, cqr->callback_data); - } - spin_lock_irq(&device->request_queue_lock); - spin_lock(get_ccwdev_lock(device->cdev)); - /* Get new request from the block device request queue */ - __dasd_process_blk_queue(device); + __dasd_device_process_final_queue(device, &final_queue); + spin_lock_irq(get_ccwdev_lock(device->cdev)); /* Now check if the head of the ccw queue needs to be started. */ - __dasd_start_head(device); - spin_unlock(get_ccwdev_lock(device->cdev)); - spin_unlock_irq(&device->request_queue_lock); + __dasd_device_start_head(device); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); dasd_put_device(device); } /* * Schedules a call to dasd_tasklet over the device tasklet. */ -void -dasd_schedule_bh(struct dasd_device * device) +void dasd_schedule_device_bh(struct dasd_device *device) { /* Protect against rescheduling. */ if (atomic_cmpxchg (&device->tasklet_scheduled, 0, 1) != 0) @@ -1480,160 +1342,109 @@ dasd_schedule_bh(struct dasd_device * device) } /* - * Queue a request to the head of the ccw_queue. Start the I/O if - * possible. + * Queue a request to the head of the device ccw_queue. + * Start the I/O if possible. */ -void -dasd_add_request_head(struct dasd_ccw_req *req) +void dasd_add_request_head(struct dasd_ccw_req *cqr) { struct dasd_device *device; unsigned long flags; - device = req->device; + device = cqr->startdev; spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - req->status = DASD_CQR_QUEUED; - req->device = device; - list_add(&req->list, &device->ccw_queue); + cqr->status = DASD_CQR_QUEUED; + list_add(&cqr->devlist, &device->ccw_queue); /* let the bh start the request to keep them in order */ - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); } /* - * Queue a request to the tail of the ccw_queue. Start the I/O if - * possible. + * Queue a request to the tail of the device ccw_queue. + * Start the I/O if possible. */ -void -dasd_add_request_tail(struct dasd_ccw_req *req) +void dasd_add_request_tail(struct dasd_ccw_req *cqr) { struct dasd_device *device; unsigned long flags; - device = req->device; + device = cqr->startdev; spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - req->status = DASD_CQR_QUEUED; - req->device = device; - list_add_tail(&req->list, &device->ccw_queue); + cqr->status = DASD_CQR_QUEUED; + list_add_tail(&cqr->devlist, &device->ccw_queue); /* let the bh start the request to keep them in order */ - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); } /* - * Wakeup callback. + * Wakeup helper for the 'sleep_on' functions. */ -static void -dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data) +static void dasd_wakeup_cb(struct dasd_ccw_req *cqr, void *data) { wake_up((wait_queue_head_t *) data); } -static inline int -_wait_for_wakeup(struct dasd_ccw_req *cqr) +static inline int _wait_for_wakeup(struct dasd_ccw_req *cqr) { struct dasd_device *device; int rc; - device = cqr->device; + device = cqr->startdev; spin_lock_irq(get_ccwdev_lock(device->cdev)); rc = ((cqr->status == DASD_CQR_DONE || - cqr->status == DASD_CQR_FAILED) && - list_empty(&cqr->list)); + cqr->status == DASD_CQR_NEED_ERP || + cqr->status == DASD_CQR_TERMINATED) && + list_empty(&cqr->devlist)); spin_unlock_irq(get_ccwdev_lock(device->cdev)); return rc; } /* - * Attempts to start a special ccw queue and waits for its completion. + * Queue a request to the tail of the device ccw_queue and wait for + * it's completion. */ -int -dasd_sleep_on(struct dasd_ccw_req * cqr) +int dasd_sleep_on(struct dasd_ccw_req *cqr) { wait_queue_head_t wait_q; struct dasd_device *device; int rc; - device = cqr->device; - spin_lock_irq(get_ccwdev_lock(device->cdev)); + device = cqr->startdev; init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; cqr->callback_data = (void *) &wait_q; - cqr->status = DASD_CQR_QUEUED; - list_add_tail(&cqr->list, &device->ccw_queue); - - /* let the bh start the request to keep them in order */ - dasd_schedule_bh(device); - - spin_unlock_irq(get_ccwdev_lock(device->cdev)); - + dasd_add_request_tail(cqr); wait_event(wait_q, _wait_for_wakeup(cqr)); /* Request status is either done or failed. */ - rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; + rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; return rc; } /* - * Attempts to start a special ccw queue and wait interruptible - * for its completion. + * Queue a request to the tail of the device ccw_queue and wait + * interruptible for it's completion. */ -int -dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr) +int dasd_sleep_on_interruptible(struct dasd_ccw_req *cqr) { wait_queue_head_t wait_q; struct dasd_device *device; - int rc, finished; - - device = cqr->device; - spin_lock_irq(get_ccwdev_lock(device->cdev)); + int rc; + device = cqr->startdev; init_waitqueue_head (&wait_q); cqr->callback = dasd_wakeup_cb; cqr->callback_data = (void *) &wait_q; - cqr->status = DASD_CQR_QUEUED; - list_add_tail(&cqr->list, &device->ccw_queue); - - /* let the bh start the request to keep them in order */ - dasd_schedule_bh(device); - spin_unlock_irq(get_ccwdev_lock(device->cdev)); - - finished = 0; - while (!finished) { - rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr)); - if (rc != -ERESTARTSYS) { - /* Request is final (done or failed) */ - rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; - break; - } - spin_lock_irq(get_ccwdev_lock(device->cdev)); - switch (cqr->status) { - case DASD_CQR_IN_IO: - /* terminate runnig cqr */ - if (device->discipline->term_IO) { - cqr->retries = -1; - device->discipline->term_IO(cqr); - /* wait (non-interruptible) for final status - * because signal ist still pending */ - spin_unlock_irq(get_ccwdev_lock(device->cdev)); - wait_event(wait_q, _wait_for_wakeup(cqr)); - spin_lock_irq(get_ccwdev_lock(device->cdev)); - rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; - finished = 1; - } - break; - case DASD_CQR_QUEUED: - /* request */ - list_del_init(&cqr->list); - rc = -EIO; - finished = 1; - break; - default: - /* cqr with 'non-interruptable' status - just wait */ - break; - } - spin_unlock_irq(get_ccwdev_lock(device->cdev)); + dasd_add_request_tail(cqr); + rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr)); + if (rc == -ERESTARTSYS) { + dasd_cancel_req(cqr); + /* wait (non-interruptible) for final status */ + wait_event(wait_q, _wait_for_wakeup(cqr)); } + rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; return rc; } @@ -1643,25 +1454,23 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr) * and be put back to status queued, before the special request is added * to the head of the queue. Then the special request is waited on normally. */ -static inline int -_dasd_term_running_cqr(struct dasd_device *device) +static inline int _dasd_term_running_cqr(struct dasd_device *device) { struct dasd_ccw_req *cqr; if (list_empty(&device->ccw_queue)) return 0; - cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list); + cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, devlist); return device->discipline->term_IO(cqr); } -int -dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr) +int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr) { wait_queue_head_t wait_q; struct dasd_device *device; int rc; - device = cqr->device; + device = cqr->startdev; spin_lock_irq(get_ccwdev_lock(device->cdev)); rc = _dasd_term_running_cqr(device); if (rc) { @@ -1673,17 +1482,17 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr) cqr->callback = dasd_wakeup_cb; cqr->callback_data = (void *) &wait_q; cqr->status = DASD_CQR_QUEUED; - list_add(&cqr->list, &device->ccw_queue); + list_add(&cqr->devlist, &device->ccw_queue); /* let the bh start the request to keep them in order */ - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); spin_unlock_irq(get_ccwdev_lock(device->cdev)); wait_event(wait_q, _wait_for_wakeup(cqr)); /* Request status is either done or failed. */ - rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; + rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; return rc; } @@ -1692,11 +1501,14 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr) * This is useful to timeout requests. The request will be * terminated if it is currently in i/o. * Returns 1 if the request has been terminated. + * 0 if there was no need to terminate the request (not started yet) + * negative error code if termination failed + * Cancellation of a request is an asynchronous operation! The calling + * function has to wait until the request is properly returned via callback. */ -int -dasd_cancel_req(struct dasd_ccw_req *cqr) +int dasd_cancel_req(struct dasd_ccw_req *cqr) { - struct dasd_device *device = cqr->device; + struct dasd_device *device = cqr->startdev; unsigned long flags; int rc; @@ -1704,74 +1516,454 @@ dasd_cancel_req(struct dasd_ccw_req *cqr) spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); switch (cqr->status) { case DASD_CQR_QUEUED: - /* request was not started - just set to failed */ - cqr->status = DASD_CQR_FAILED; + /* request was not started - just set to cleared */ + cqr->status = DASD_CQR_CLEARED; break; case DASD_CQR_IN_IO: /* request in IO - terminate IO and release again */ - if (device->discipline->term_IO(cqr) != 0) - /* what to do if unable to terminate ?????? - e.g. not _IN_IO */ - cqr->status = DASD_CQR_FAILED; - cqr->stopclk = get_clock(); - rc = 1; + rc = device->discipline->term_IO(cqr); + if (rc) { + DEV_MESSAGE(KERN_ERR, device, + "dasd_cancel_req is unable " + " to terminate request %p, rc = %d", + cqr, rc); + } else { + cqr->stopclk = get_clock(); + rc = 1; + } break; - case DASD_CQR_DONE: - case DASD_CQR_FAILED: - /* already finished - do nothing */ + default: /* already finished or clear pending - do nothing */ break; - default: - DEV_MESSAGE(KERN_ALERT, device, - "invalid status %02x in request", - cqr->status); + } + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + dasd_schedule_device_bh(device); + return rc; +} + + +/* + * SECTION: Operations of the dasd_block layer. + */ + +/* + * Timeout function for dasd_block. This is used when the block layer + * is waiting for something that may not come reliably, (e.g. a state + * change interrupt) + */ +static void dasd_block_timeout(unsigned long ptr) +{ + unsigned long flags; + struct dasd_block *block; + + block = (struct dasd_block *) ptr; + spin_lock_irqsave(get_ccwdev_lock(block->base->cdev), flags); + /* re-activate request queue */ + block->base->stopped &= ~DASD_STOPPED_PENDING; + spin_unlock_irqrestore(get_ccwdev_lock(block->base->cdev), flags); + dasd_schedule_block_bh(block); +} + +/* + * Setup timeout for a dasd_block in jiffies. + */ +void dasd_block_set_timer(struct dasd_block *block, int expires) +{ + if (expires == 0) { + if (timer_pending(&block->timer)) + del_timer(&block->timer); + return; + } + if (timer_pending(&block->timer)) { + if (mod_timer(&block->timer, jiffies + expires)) + return; + } + block->timer.function = dasd_block_timeout; + block->timer.data = (unsigned long) block; + block->timer.expires = jiffies + expires; + add_timer(&block->timer); +} + +/* + * Clear timeout for a dasd_block. + */ +void dasd_block_clear_timer(struct dasd_block *block) +{ + if (timer_pending(&block->timer)) + del_timer(&block->timer); +} + +/* + * posts the buffer_cache about a finalized request + */ +static inline void dasd_end_request(struct request *req, int error) +{ + if (__blk_end_request(req, error, blk_rq_bytes(req))) BUG(); +} + +/* + * Process finished error recovery ccw. + */ +static inline void __dasd_block_process_erp(struct dasd_block *block, + struct dasd_ccw_req *cqr) +{ + dasd_erp_fn_t erp_fn; + struct dasd_device *device = block->base; + + if (cqr->status == DASD_CQR_DONE) + DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful"); + else + DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful"); + erp_fn = device->discipline->erp_postaction(cqr); + erp_fn(cqr); +} +/* + * Fetch requests from the block device queue. + */ +static void __dasd_process_request_queue(struct dasd_block *block) +{ + struct request_queue *queue; + struct request *req; + struct dasd_ccw_req *cqr; + struct dasd_device *basedev; + unsigned long flags; + queue = block->request_queue; + basedev = block->base; + /* No queue ? Then there is nothing to do. */ + if (queue == NULL) + return; + + /* + * We requeue request from the block device queue to the ccw + * queue only in two states. In state DASD_STATE_READY the + * partition detection is done and we need to requeue requests + * for that. State DASD_STATE_ONLINE is normal block device + * operation. + */ + if (basedev->state < DASD_STATE_READY) + return; + /* Now we try to fetch requests from the request queue */ + while (!blk_queue_plugged(queue) && + elv_next_request(queue)) { + + req = elv_next_request(queue); + + if (basedev->features & DASD_FEATURE_READONLY && + rq_data_dir(req) == WRITE) { + DBF_DEV_EVENT(DBF_ERR, basedev, + "Rejecting write request %p", + req); + blkdev_dequeue_request(req); + dasd_end_request(req, -EIO); + continue; + } + cqr = basedev->discipline->build_cp(basedev, block, req); + if (IS_ERR(cqr)) { + if (PTR_ERR(cqr) == -EBUSY) + break; /* normal end condition */ + if (PTR_ERR(cqr) == -ENOMEM) + break; /* terminate request queue loop */ + if (PTR_ERR(cqr) == -EAGAIN) { + /* + * The current request cannot be build right + * now, we have to try later. If this request + * is the head-of-queue we stop the device + * for 1/2 second. + */ + if (!list_empty(&block->ccw_queue)) + break; + spin_lock_irqsave(get_ccwdev_lock(basedev->cdev), flags); + basedev->stopped |= DASD_STOPPED_PENDING; + spin_unlock_irqrestore(get_ccwdev_lock(basedev->cdev), flags); + dasd_block_set_timer(block, HZ/2); + break; + } + DBF_DEV_EVENT(DBF_ERR, basedev, + "CCW creation failed (rc=%ld) " + "on request %p", + PTR_ERR(cqr), req); + blkdev_dequeue_request(req); + dasd_end_request(req, -EIO); + continue; + } + /* + * Note: callback is set to dasd_return_cqr_cb in + * __dasd_block_start_head to cover erp requests as well + */ + cqr->callback_data = (void *) req; + cqr->status = DASD_CQR_FILLED; + blkdev_dequeue_request(req); + list_add_tail(&cqr->blocklist, &block->ccw_queue); + dasd_profile_start(block, cqr, req); + } +} + +static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) +{ + struct request *req; + int status; + int error = 0; + + req = (struct request *) cqr->callback_data; + dasd_profile_end(cqr->block, cqr, req); + status = cqr->memdev->discipline->free_cp(cqr, req); + if (status <= 0) + error = status ? status : -EIO; + dasd_end_request(req, error); +} + +/* + * Process ccw request queue. + */ +static void __dasd_process_block_ccw_queue(struct dasd_block *block, + struct list_head *final_queue) +{ + struct list_head *l, *n; + struct dasd_ccw_req *cqr; + dasd_erp_fn_t erp_fn; + unsigned long flags; + struct dasd_device *base = block->base; + +restart: + /* Process request with final status. */ + list_for_each_safe(l, n, &block->ccw_queue) { + cqr = list_entry(l, struct dasd_ccw_req, blocklist); + if (cqr->status != DASD_CQR_DONE && + cqr->status != DASD_CQR_FAILED && + cqr->status != DASD_CQR_NEED_ERP && + cqr->status != DASD_CQR_TERMINATED) + continue; + + if (cqr->status == DASD_CQR_TERMINATED) { + base->discipline->handle_terminated_request(cqr); + goto restart; + } + + /* Process requests that may be recovered */ + if (cqr->status == DASD_CQR_NEED_ERP) { + if (cqr->irb.esw.esw0.erw.cons && + test_bit(DASD_CQR_FLAGS_USE_ERP, + &cqr->flags)) { + erp_fn = base->discipline->erp_action(cqr); + erp_fn(cqr); + } + goto restart; + } + + /* First of all call extended error reporting. */ + if (dasd_eer_enabled(base) && + cqr->status == DASD_CQR_FAILED) { + dasd_eer_write(base, cqr, DASD_EER_FATALERROR); + + /* restart request */ + cqr->status = DASD_CQR_FILLED; + cqr->retries = 255; + spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); + base->stopped |= DASD_STOPPED_QUIESCE; + spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), + flags); + goto restart; + } + + /* Process finished ERP request. */ + if (cqr->refers) { + __dasd_block_process_erp(block, cqr); + goto restart; + } + + /* Rechain finished requests to final queue */ + cqr->endclk = get_clock(); + list_move_tail(&cqr->blocklist, final_queue); + } +} + +static void dasd_return_cqr_cb(struct dasd_ccw_req *cqr, void *data) +{ + dasd_schedule_block_bh(cqr->block); +} + +static void __dasd_block_start_head(struct dasd_block *block) +{ + struct dasd_ccw_req *cqr; + + if (list_empty(&block->ccw_queue)) + return; + /* We allways begin with the first requests on the queue, as some + * of previously started requests have to be enqueued on a + * dasd_device again for error recovery. + */ + list_for_each_entry(cqr, &block->ccw_queue, blocklist) { + if (cqr->status != DASD_CQR_FILLED) + continue; + /* Non-temporary stop condition will trigger fail fast */ + if (block->base->stopped & ~DASD_STOPPED_PENDING && + test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) && + (!dasd_eer_enabled(block->base))) { + cqr->status = DASD_CQR_FAILED; + dasd_schedule_block_bh(block); + continue; + } + /* Don't try to start requests if device is stopped */ + if (block->base->stopped) + return; + + /* just a fail safe check, should not happen */ + if (!cqr->startdev) + cqr->startdev = block->base; + + /* make sure that the requests we submit find their way back */ + cqr->callback = dasd_return_cqr_cb; + + dasd_add_request_tail(cqr); + } +} + +/* + * Central dasd_block layer routine. Takes requests from the generic + * block layer request queue, creates ccw requests, enqueues them on + * a dasd_device and processes ccw requests that have been returned. + */ +static void dasd_block_tasklet(struct dasd_block *block) +{ + struct list_head final_queue; + struct list_head *l, *n; + struct dasd_ccw_req *cqr; + + atomic_set(&block->tasklet_scheduled, 0); + INIT_LIST_HEAD(&final_queue); + spin_lock(&block->queue_lock); + /* Finish off requests on ccw queue */ + __dasd_process_block_ccw_queue(block, &final_queue); + spin_unlock(&block->queue_lock); + /* Now call the callback function of requests with final status */ + spin_lock_irq(&block->request_queue_lock); + list_for_each_safe(l, n, &final_queue) { + cqr = list_entry(l, struct dasd_ccw_req, blocklist); + list_del_init(&cqr->blocklist); + __dasd_cleanup_cqr(cqr); + } + spin_lock(&block->queue_lock); + /* Get new request from the block device request queue */ + __dasd_process_request_queue(block); + /* Now check if the head of the ccw queue needs to be started. */ + __dasd_block_start_head(block); + spin_unlock(&block->queue_lock); + spin_unlock_irq(&block->request_queue_lock); + dasd_put_device(block->base); +} + +static void _dasd_wake_block_flush_cb(struct dasd_ccw_req *cqr, void *data) +{ + wake_up(&dasd_flush_wq); +} + +/* + * Go through all request on the dasd_block request queue, cancel them + * on the respective dasd_device, and return them to the generic + * block layer. + */ +static int dasd_flush_block_queue(struct dasd_block *block) +{ + struct dasd_ccw_req *cqr, *n; + int rc, i; + struct list_head flush_queue; + + INIT_LIST_HEAD(&flush_queue); + spin_lock_bh(&block->queue_lock); + rc = 0; +restart: + list_for_each_entry_safe(cqr, n, &block->ccw_queue, blocklist) { + /* if this request currently owned by a dasd_device cancel it */ + if (cqr->status >= DASD_CQR_QUEUED) + rc = dasd_cancel_req(cqr); + if (rc < 0) + break; + /* Rechain request (including erp chain) so it won't be + * touched by the dasd_block_tasklet anymore. + * Replace the callback so we notice when the request + * is returned from the dasd_device layer. + */ + cqr->callback = _dasd_wake_block_flush_cb; + for (i = 0; cqr != NULL; cqr = cqr->refers, i++) + list_move_tail(&cqr->blocklist, &flush_queue); + if (i > 1) + /* moved more than one request - need to restart */ + goto restart; + } + spin_unlock_bh(&block->queue_lock); + /* Now call the callback function of flushed requests */ +restart_cb: + list_for_each_entry_safe(cqr, n, &flush_queue, blocklist) { + wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED)); + /* Process finished ERP request. */ + if (cqr->refers) { + __dasd_block_process_erp(block, cqr); + /* restart list_for_xx loop since dasd_process_erp + * might remove multiple elements */ + goto restart_cb; + } + /* call the callback function */ + cqr->endclk = get_clock(); + list_del_init(&cqr->blocklist); + __dasd_cleanup_cqr(cqr); } - spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); - dasd_schedule_bh(device); return rc; } /* - * SECTION: Block device operations (request queue, partitions, open, release). + * Schedules a call to dasd_tasklet over the device tasklet. + */ +void dasd_schedule_block_bh(struct dasd_block *block) +{ + /* Protect against rescheduling. */ + if (atomic_cmpxchg(&block->tasklet_scheduled, 0, 1) != 0) + return; + /* life cycle of block is bound to it's base device */ + dasd_get_device(block->base); + tasklet_hi_schedule(&block->tasklet); +} + + +/* + * SECTION: external block device operations + * (request queue handling, open, release, etc.) */ /* * Dasd request queue function. Called from ll_rw_blk.c */ -static void -do_dasd_request(struct request_queue * queue) +static void do_dasd_request(struct request_queue *queue) { - struct dasd_device *device; + struct dasd_block *block; - device = (struct dasd_device *) queue->queuedata; - spin_lock(get_ccwdev_lock(device->cdev)); + block = queue->queuedata; + spin_lock(&block->queue_lock); /* Get new request from the block device request queue */ - __dasd_process_blk_queue(device); + __dasd_process_request_queue(block); /* Now check if the head of the ccw queue needs to be started. */ - __dasd_start_head(device); - spin_unlock(get_ccwdev_lock(device->cdev)); + __dasd_block_start_head(block); + spin_unlock(&block->queue_lock); } /* * Allocate and initialize request queue and default I/O scheduler. */ -static int -dasd_alloc_queue(struct dasd_device * device) +static int dasd_alloc_queue(struct dasd_block *block) { int rc; - device->request_queue = blk_init_queue(do_dasd_request, - &device->request_queue_lock); - if (device->request_queue == NULL) + block->request_queue = blk_init_queue(do_dasd_request, + &block->request_queue_lock); + if (block->request_queue == NULL) return -ENOMEM; - device->request_queue->queuedata = device; + block->request_queue->queuedata = block; - elevator_exit(device->request_queue->elevator); - rc = elevator_init(device->request_queue, "deadline"); + elevator_exit(block->request_queue->elevator); + rc = elevator_init(block->request_queue, "deadline"); if (rc) { - blk_cleanup_queue(device->request_queue); + blk_cleanup_queue(block->request_queue); return rc; } return 0; @@ -1780,79 +1972,76 @@ dasd_alloc_queue(struct dasd_device * device) /* * Allocate and initialize request queue. */ -static void -dasd_setup_queue(struct dasd_device * device) +static void dasd_setup_queue(struct dasd_block *block) { int max; - blk_queue_hardsect_size(device->request_queue, device->bp_block); - max = device->discipline->max_blocks << device->s2b_shift; - blk_queue_max_sectors(device->request_queue, max); - blk_queue_max_phys_segments(device->request_queue, -1L); - blk_queue_max_hw_segments(device->request_queue, -1L); - blk_queue_max_segment_size(device->request_queue, -1L); - blk_queue_segment_boundary(device->request_queue, -1L); - blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL); + blk_queue_hardsect_size(block->request_queue, block->bp_block); + max = block->base->discipline->max_blocks << block->s2b_shift; + blk_queue_max_sectors(block->request_queue, max); + blk_queue_max_phys_segments(block->request_queue, -1L); + blk_queue_max_hw_segments(block->request_queue, -1L); + blk_queue_max_segment_size(block->request_queue, -1L); + blk_queue_segment_boundary(block->request_queue, -1L); + blk_queue_ordered(block->request_queue, QUEUE_ORDERED_DRAIN, NULL); } /* * Deactivate and free request queue. */ -static void -dasd_free_queue(struct dasd_device * device) +static void dasd_free_queue(struct dasd_block *block) { - if (device->request_queue) { - blk_cleanup_queue(device->request_queue); - device->request_queue = NULL; + if (block->request_queue) { + blk_cleanup_queue(block->request_queue); + block->request_queue = NULL; } } /* * Flush request on the request queue. */ -static void -dasd_flush_request_queue(struct dasd_device * device) +static void dasd_flush_request_queue(struct dasd_block *block) { struct request *req; - if (!device->request_queue) + if (!block->request_queue) return; - spin_lock_irq(&device->request_queue_lock); - while ((req = elv_next_request(device->request_queue))) { + spin_lock_irq(&block->request_queue_lock); + while ((req = elv_next_request(block->request_queue))) { blkdev_dequeue_request(req); - dasd_end_request(req, 0); + dasd_end_request(req, -EIO); } - spin_unlock_irq(&device->request_queue_lock); + spin_unlock_irq(&block->request_queue_lock); } -static int -dasd_open(struct inode *inp, struct file *filp) +static int dasd_open(struct inode *inp, struct file *filp) { struct gendisk *disk = inp->i_bdev->bd_disk; - struct dasd_device *device = disk->private_data; + struct dasd_block *block = disk->private_data; + struct dasd_device *base = block->base; int rc; - atomic_inc(&device->open_count); - if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { + atomic_inc(&block->open_count); + if (test_bit(DASD_FLAG_OFFLINE, &base->flags)) { rc = -ENODEV; goto unlock; } - if (!try_module_get(device->discipline->owner)) { + if (!try_module_get(base->discipline->owner)) { rc = -EINVAL; goto unlock; } if (dasd_probeonly) { - DEV_MESSAGE(KERN_INFO, device, "%s", + DEV_MESSAGE(KERN_INFO, base, "%s", "No access to device due to probeonly mode"); rc = -EPERM; goto out; } - if (device->state <= DASD_STATE_BASIC) { - DBF_DEV_EVENT(DBF_ERR, device, " %s", + if (base->state <= DASD_STATE_BASIC) { + DBF_DEV_EVENT(DBF_ERR, base, " %s", " Cannot open unrecognized device"); rc = -ENODEV; goto out; @@ -1861,41 +2050,41 @@ dasd_open(struct inode *inp, struct file *filp) return 0; out: - module_put(device->discipline->owner); + module_put(base->discipline->owner); unlock: - atomic_dec(&device->open_count); + atomic_dec(&block->open_count); return rc; } -static int -dasd_release(struct inode *inp, struct file *filp) +static int dasd_release(struct inode *inp, struct file *filp) { struct gendisk *disk = inp->i_bdev->bd_disk; - struct dasd_device *device = disk->private_data; + struct dasd_block *block = disk->private_data; - atomic_dec(&device->open_count); - module_put(device->discipline->owner); + atomic_dec(&block->open_count); + module_put(block->base->discipline->owner); return 0; } /* * Return disk geometry. */ -static int -dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +static int dasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { - struct dasd_device *device; + struct dasd_block *block; + struct dasd_device *base; - device = bdev->bd_disk->private_data; - if (!device) + block = bdev->bd_disk->private_data; + base = block->base; + if (!block) return -ENODEV; - if (!device->discipline || - !device->discipline->fill_geometry) + if (!base->discipline || + !base->discipline->fill_geometry) return -EINVAL; - device->discipline->fill_geometry(device, geo); - geo->start = get_start_sect(bdev) >> device->s2b_shift; + base->discipline->fill_geometry(block, geo); + geo->start = get_start_sect(bdev) >> block->s2b_shift; return 0; } @@ -1909,6 +2098,9 @@ dasd_device_operations = { .getgeo = dasd_getgeo, }; +/******************************************************************************* + * end of block device operations + */ static void dasd_exit(void) @@ -1937,9 +2129,8 @@ dasd_exit(void) * Initial attempt at a probe function. this can be simplified once * the other detection code is gone. */ -int -dasd_generic_probe (struct ccw_device *cdev, - struct dasd_discipline *discipline) +int dasd_generic_probe(struct ccw_device *cdev, + struct dasd_discipline *discipline) { int ret; @@ -1969,19 +2160,20 @@ dasd_generic_probe (struct ccw_device *cdev, ret = ccw_device_set_online(cdev); if (ret) printk(KERN_WARNING - "dasd_generic_probe: could not initially online " - "ccw-device %s\n", cdev->dev.bus_id); - return ret; + "dasd_generic_probe: could not initially " + "online ccw-device %s; return code: %d\n", + cdev->dev.bus_id, ret); + return 0; } /* * This will one day be called from a global not_oper handler. * It is also used by driver_unregister during module unload. */ -void -dasd_generic_remove (struct ccw_device *cdev) +void dasd_generic_remove(struct ccw_device *cdev) { struct dasd_device *device; + struct dasd_block *block; cdev->handler = NULL; @@ -2001,7 +2193,15 @@ dasd_generic_remove (struct ccw_device *cdev) */ dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ + block = device->block; + device->block = NULL; dasd_delete_device(device); + /* + * life cycle of block is bound to device, so delete it after + * device was safely removed + */ + if (block) + dasd_free_block(block); } /* @@ -2009,10 +2209,8 @@ dasd_generic_remove (struct ccw_device *cdev) * the device is detected for the first time and is supposed to be used * or the user has started activation through sysfs. */ -int -dasd_generic_set_online (struct ccw_device *cdev, - struct dasd_discipline *base_discipline) - +int dasd_generic_set_online(struct ccw_device *cdev, + struct dasd_discipline *base_discipline) { struct dasd_discipline *discipline; struct dasd_device *device; @@ -2048,6 +2246,7 @@ dasd_generic_set_online (struct ccw_device *cdev, device->base_discipline = base_discipline; device->discipline = discipline; + /* check_device will allocate block device if necessary */ rc = discipline->check_device(device); if (rc) { printk (KERN_WARNING @@ -2067,6 +2266,8 @@ dasd_generic_set_online (struct ccw_device *cdev, cdev->dev.bus_id); rc = -ENODEV; dasd_set_target_state(device, DASD_STATE_NEW); + if (device->block) + dasd_free_block(device->block); dasd_delete_device(device); } else pr_debug("dasd_generic device %s found\n", @@ -2081,10 +2282,10 @@ dasd_generic_set_online (struct ccw_device *cdev, return rc; } -int -dasd_generic_set_offline (struct ccw_device *cdev) +int dasd_generic_set_offline(struct ccw_device *cdev) { struct dasd_device *device; + struct dasd_block *block; int max_count, open_count; device = dasd_device_from_cdev(cdev); @@ -2101,30 +2302,39 @@ dasd_generic_set_offline (struct ccw_device *cdev) * the blkdev_get in dasd_scan_partitions. We are only interested * in the other openers. */ - max_count = device->bdev ? 0 : -1; - open_count = (int) atomic_read(&device->open_count); - if (open_count > max_count) { - if (open_count > 0) - printk (KERN_WARNING "Can't offline dasd device with " - "open count = %i.\n", - open_count); - else - printk (KERN_WARNING "%s", - "Can't offline dasd device due to internal " - "use\n"); - clear_bit(DASD_FLAG_OFFLINE, &device->flags); - dasd_put_device(device); - return -EBUSY; + if (device->block) { + struct dasd_block *block = device->block; + max_count = block->bdev ? 0 : -1; + open_count = (int) atomic_read(&block->open_count); + if (open_count > max_count) { + if (open_count > 0) + printk(KERN_WARNING "Can't offline dasd " + "device with open count = %i.\n", + open_count); + else + printk(KERN_WARNING "%s", + "Can't offline dasd device due " + "to internal use\n"); + clear_bit(DASD_FLAG_OFFLINE, &device->flags); + dasd_put_device(device); + return -EBUSY; + } } dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ + block = device->block; + device->block = NULL; dasd_delete_device(device); - + /* + * life cycle of block is bound to device, so delete it after + * device was safely removed + */ + if (block) + dasd_free_block(block); return 0; } -int -dasd_generic_notify(struct ccw_device *cdev, int event) +int dasd_generic_notify(struct ccw_device *cdev, int event) { struct dasd_device *device; struct dasd_ccw_req *cqr; @@ -2145,27 +2355,22 @@ dasd_generic_notify(struct ccw_device *cdev, int event) if (device->state < DASD_STATE_BASIC) break; /* Device is active. We want to keep it. */ - if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) { - list_for_each_entry(cqr, &device->ccw_queue, list) - if (cqr->status == DASD_CQR_IN_IO) - cqr->status = DASD_CQR_FAILED; - device->stopped |= DASD_STOPPED_DC_EIO; - } else { - list_for_each_entry(cqr, &device->ccw_queue, list) - if (cqr->status == DASD_CQR_IN_IO) { - cqr->status = DASD_CQR_QUEUED; - cqr->retries++; - } - device->stopped |= DASD_STOPPED_DC_WAIT; - dasd_set_timer(device, 0); - } - dasd_schedule_bh(device); + list_for_each_entry(cqr, &device->ccw_queue, devlist) + if (cqr->status == DASD_CQR_IN_IO) { + cqr->status = DASD_CQR_QUEUED; + cqr->retries++; + } + device->stopped |= DASD_STOPPED_DC_WAIT; + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); ret = 1; break; case CIO_OPER: /* FIXME: add a sanity check. */ - device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO); - dasd_schedule_bh(device); + device->stopped &= ~DASD_STOPPED_DC_WAIT; + dasd_schedule_device_bh(device); + if (device->block) + dasd_schedule_block_bh(device->block); ret = 1; break; } @@ -2195,7 +2400,8 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, ccw->cda = (__u32)(addr_t)rdc_buffer; ccw->count = rdc_buffer_size; - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; cqr->expires = 10*HZ; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 2; @@ -2217,13 +2423,12 @@ int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, return PTR_ERR(cqr); ret = dasd_sleep_on(cqr); - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return ret; } EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars); -static int __init -dasd_init(void) +static int __init dasd_init(void) { int rc; @@ -2231,7 +2436,7 @@ dasd_init(void) init_waitqueue_head(&dasd_flush_wq); /* register 'common' DASD debug area, used for all DBF_XXX calls */ - dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long)); + dasd_debug_area = debug_register("dasd", 1, 1, 8 * sizeof(long)); if (dasd_debug_area == NULL) { rc = -ENOMEM; goto failed; @@ -2277,15 +2482,18 @@ EXPORT_SYMBOL(dasd_diag_discipline_pointer); EXPORT_SYMBOL(dasd_add_request_head); EXPORT_SYMBOL(dasd_add_request_tail); EXPORT_SYMBOL(dasd_cancel_req); -EXPORT_SYMBOL(dasd_clear_timer); +EXPORT_SYMBOL(dasd_device_clear_timer); +EXPORT_SYMBOL(dasd_block_clear_timer); EXPORT_SYMBOL(dasd_enable_device); EXPORT_SYMBOL(dasd_int_handler); EXPORT_SYMBOL(dasd_kfree_request); EXPORT_SYMBOL(dasd_kick_device); EXPORT_SYMBOL(dasd_kmalloc_request); -EXPORT_SYMBOL(dasd_schedule_bh); +EXPORT_SYMBOL(dasd_schedule_device_bh); +EXPORT_SYMBOL(dasd_schedule_block_bh); EXPORT_SYMBOL(dasd_set_target_state); -EXPORT_SYMBOL(dasd_set_timer); +EXPORT_SYMBOL(dasd_device_set_timer); +EXPORT_SYMBOL(dasd_block_set_timer); EXPORT_SYMBOL(dasd_sfree_request); EXPORT_SYMBOL(dasd_sleep_on); EXPORT_SYMBOL(dasd_sleep_on_immediatly); @@ -2299,4 +2507,7 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove); EXPORT_SYMBOL_GPL(dasd_generic_notify); EXPORT_SYMBOL_GPL(dasd_generic_set_online); EXPORT_SYMBOL_GPL(dasd_generic_set_offline); - +EXPORT_SYMBOL_GPL(dasd_generic_handle_state_change); +EXPORT_SYMBOL_GPL(dasd_flush_device_queue); +EXPORT_SYMBOL_GPL(dasd_alloc_block); +EXPORT_SYMBOL_GPL(dasd_free_block); diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c deleted file mode 100644 index 1ddab8991d92..000000000000 --- a/drivers/s390/block/dasd_3370_erp.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * File...........: linux/drivers/s390/block/dasd_3370_erp.c - * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 - * - */ - -#define PRINTK_HEADER "dasd_erp(3370)" - -#include "dasd_int.h" - - -/* - * DASD_3370_ERP_EXAMINE - * - * DESCRIPTION - * Checks only for fatal/no/recover error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * The logic is based on the 'IBM 3880 Storage Control Reference' manual - * 'Chapter 7. 3370 Sense Data'. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for all others. - */ -dasd_era_t -dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) -{ - char *sense = irb->ecw; - - /* check for successful execution first */ - if (irb->scsw.cstat == 0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; - if (sense[0] & 0x80) { /* CMD reject */ - return dasd_era_fatal; - } - if (sense[0] & 0x40) { /* Drive offline */ - return dasd_era_recover; - } - if (sense[0] & 0x20) { /* Bus out parity */ - return dasd_era_recover; - } - if (sense[0] & 0x10) { /* equipment check */ - if (sense[1] & 0x80) { - return dasd_era_fatal; - } - return dasd_era_recover; - } - if (sense[0] & 0x08) { /* data check */ - if (sense[1] & 0x80) { - return dasd_era_fatal; - } - return dasd_era_recover; - } - if (sense[0] & 0x04) { /* overrun */ - if (sense[1] & 0x80) { - return dasd_era_fatal; - } - return dasd_era_recover; - } - if (sense[1] & 0x40) { /* invalid blocksize */ - return dasd_era_fatal; - } - if (sense[1] & 0x04) { /* file protected */ - return dasd_era_recover; - } - if (sense[1] & 0x01) { /* operation incomplete */ - return dasd_era_recover; - } - if (sense[2] & 0x80) { /* check data erroor */ - return dasd_era_recover; - } - if (sense[2] & 0x10) { /* Env. data present */ - return dasd_era_recover; - } - /* examine the 24 byte sense data */ - return dasd_era_recover; - -} /* END dasd_3370_erp_examine */ diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 5b7385e430ea..c361ab69ec00 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -26,158 +26,6 @@ struct DCTL_data { /* ***************************************************************************** - * SECTION ERP EXAMINATION - ***************************************************************************** - */ - -/* - * DASD_3990_ERP_EXAMINE_24 - * - * DESCRIPTION - * Checks only for fatal (unrecoverable) error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * Each bit configuration leading to an action code 2 (Exit with - * programming error or unusual condition indication) - * are handled as fatal errors. - * - * All other configurations are handled as recoverable errors. - * - * RETURN VALUES - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for all others. - */ -static dasd_era_t -dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense) -{ - - struct dasd_device *device = cqr->device; - - /* check for 'Command Reject' */ - if ((sense[0] & SNS0_CMD_REJECT) && - (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { - - DEV_MESSAGE(KERN_ERR, device, "%s", - "EXAMINE 24: Command Reject detected - " - "fatal error"); - - return dasd_era_fatal; - } - - /* check for 'Invalid Track Format' */ - if ((sense[1] & SNS1_INV_TRACK_FORMAT) && - (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { - - DEV_MESSAGE(KERN_ERR, device, "%s", - "EXAMINE 24: Invalid Track Format detected " - "- fatal error"); - - return dasd_era_fatal; - } - - /* check for 'No Record Found' */ - if (sense[1] & SNS1_NO_REC_FOUND) { - - /* FIXME: fatal error ?!? */ - DEV_MESSAGE(KERN_ERR, device, - "EXAMINE 24: No Record Found detected %s", - device->state <= DASD_STATE_BASIC ? - " " : "- fatal error"); - - return dasd_era_fatal; - } - - /* return recoverable for all others */ - return dasd_era_recover; -} /* END dasd_3990_erp_examine_24 */ - -/* - * DASD_3990_ERP_EXAMINE_32 - * - * DESCRIPTION - * Checks only for fatal/no/recoverable error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for recoverable others. - */ -static dasd_era_t -dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense) -{ - - struct dasd_device *device = cqr->device; - - switch (sense[25]) { - case 0x00: - return dasd_era_none; - - case 0x01: - DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error"); - - return dasd_era_fatal; - - default: - - return dasd_era_recover; - } - -} /* end dasd_3990_erp_examine_32 */ - -/* - * DASD_3990_ERP_EXAMINE - * - * DESCRIPTION - * Checks only for fatal/no/recover error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * The logic is based on the 'IBM 3990 Storage Control Reference' manual - * 'Chapter 7. Error Recovery Procedures'. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for all others. - */ -dasd_era_t -dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) -{ - - char *sense = irb->ecw; - dasd_era_t era = dasd_era_recover; - struct dasd_device *device = cqr->device; - - /* check for successful execution first */ - if (irb->scsw.cstat == 0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; - - /* distinguish between 24 and 32 byte sense data */ - if (sense[27] & DASD_SENSE_BIT_0) { - - era = dasd_3990_erp_examine_24(cqr, sense); - - } else { - - era = dasd_3990_erp_examine_32(cqr, sense); - - } - - /* log the erp chain if fatal error occurred */ - if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { - dasd_log_sense(cqr, irb); - } - - return era; - -} /* END dasd_3990_erp_examine */ - -/* - ***************************************************************************** * SECTION ERP HANDLING ***************************************************************************** */ @@ -206,7 +54,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status) { struct dasd_ccw_req *cqr = erp->refers; - dasd_free_erp_request(erp, erp->device); + dasd_free_erp_request(erp, erp->memdev); cqr->status = final_status; return cqr; @@ -224,15 +72,17 @@ static void dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; + unsigned long flags; DEV_MESSAGE(KERN_INFO, device, "blocking request queue for %is", expires/HZ); + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); device->stopped |= DASD_STOPPED_PENDING; - erp->status = DASD_CQR_QUEUED; - - dasd_set_timer(device, expires); + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + erp->status = DASD_CQR_FILLED; + dasd_block_set_timer(device->block, expires); } /* @@ -251,7 +101,7 @@ static struct dasd_ccw_req * dasd_3990_erp_int_req(struct dasd_ccw_req * erp) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; /* first time set initial retry counter and erp_function */ /* and retry once without blocking queue */ @@ -292,11 +142,14 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp) static void dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; __u8 opm; + unsigned long flags; /* try alternate valid path */ + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); opm = ccw_device_get_path_mask(device->cdev); + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); //FIXME: start with get_opm ? if (erp->lpm == 0) erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum); @@ -309,9 +162,8 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) "try alternate lpm=%x (lpum=%x / opm=%x)", erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm); - /* reset status to queued to handle the request again... */ - if (erp->status > DASD_CQR_QUEUED) - erp->status = DASD_CQR_QUEUED; + /* reset status to submit the request again... */ + erp->status = DASD_CQR_FILLED; erp->retries = 1; } else { DEV_MESSAGE(KERN_ERR, device, @@ -320,8 +172,7 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) erp->irb.esw.esw0.sublog.lpum, opm); /* post request with permanent error */ - if (erp->status > DASD_CQR_QUEUED) - erp->status = DASD_CQR_FAILED; + erp->status = DASD_CQR_FAILED; } } /* end dasd_3990_erp_alternate_path */ @@ -344,14 +195,14 @@ static struct dasd_ccw_req * dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; struct DCTL_data *DCTL_data; struct ccw1 *ccw; struct dasd_ccw_req *dctl_cqr; dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1, - sizeof (struct DCTL_data), - erp->device); + sizeof(struct DCTL_data), + device); if (IS_ERR(dctl_cqr)) { DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate DCTL-CQR"); @@ -365,13 +216,14 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) DCTL_data->modifier = modifier; ccw = dctl_cqr->cpaddr; - memset(ccw, 0, sizeof (struct ccw1)); + memset(ccw, 0, sizeof(struct ccw1)); ccw->cmd_code = CCW_CMD_DCTL; ccw->count = 4; ccw->cda = (__u32)(addr_t) DCTL_data; dctl_cqr->function = dasd_3990_erp_DCTL; dctl_cqr->refers = erp; - dctl_cqr->device = erp->device; + dctl_cqr->startdev = device; + dctl_cqr->memdev = device; dctl_cqr->magic = erp->magic; dctl_cqr->expires = 5 * 60 * HZ; dctl_cqr->retries = 2; @@ -435,7 +287,7 @@ static struct dasd_ccw_req * dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; /* first time set initial retry counter and erp_function */ /* and retry once without waiting for state change pending */ @@ -472,7 +324,7 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) "redriving request immediately, " "%d retries left", erp->retries); - erp->status = DASD_CQR_QUEUED; + erp->status = DASD_CQR_FILLED; } } @@ -530,7 +382,7 @@ static void dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; char msg_format = (sense[7] & 0xF0); char msg_no = (sense[7] & 0x0F); @@ -1157,7 +1009,7 @@ static struct dasd_ccw_req * dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_com_rej; @@ -1198,7 +1050,7 @@ static struct dasd_ccw_req * dasd_3990_erp_bus_out(struct dasd_ccw_req * erp) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; /* first time set initial retry counter and erp_function */ /* and retry once without blocking queue */ @@ -1237,7 +1089,7 @@ static struct dasd_ccw_req * dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_equip_check; @@ -1279,7 +1131,6 @@ dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense) erp = dasd_3990_erp_action_5(erp); } - return erp; } /* end dasd_3990_erp_equip_check */ @@ -1299,7 +1150,7 @@ static struct dasd_ccw_req * dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_data_check; @@ -1358,7 +1209,7 @@ static struct dasd_ccw_req * dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_overrun; @@ -1387,7 +1238,7 @@ static struct dasd_ccw_req * dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_inv_format; @@ -1403,8 +1254,7 @@ dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense) } else { DEV_MESSAGE(KERN_ERR, device, "%s", - "Invalid Track Format - Fatal error should have " - "been handled within the interrupt handler"); + "Invalid Track Format - Fatal error"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); } @@ -1428,7 +1278,7 @@ static struct dasd_ccw_req * dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense) { - struct dasd_device *device = default_erp->device; + struct dasd_device *device = default_erp->startdev; DEV_MESSAGE(KERN_ERR, device, "%s", "End-of-Cylinder - must never happen"); @@ -1453,7 +1303,7 @@ static struct dasd_ccw_req * dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_env_data; @@ -1463,11 +1313,9 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense) /* don't retry on disabled interface */ if (sense[7] != 0x0F) { - erp = dasd_3990_erp_action_4(erp, sense); } else { - - erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO); + erp->status = DASD_CQR_FILLED; } return erp; @@ -1490,11 +1338,10 @@ static struct dasd_ccw_req * dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense) { - struct dasd_device *device = default_erp->device; + struct dasd_device *device = default_erp->startdev; DEV_MESSAGE(KERN_ERR, device, "%s", - "No Record Found - Fatal error should " - "have been handled within the interrupt handler"); + "No Record Found - Fatal error "); return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); @@ -1517,7 +1364,7 @@ static struct dasd_ccw_req * dasd_3990_erp_file_prot(struct dasd_ccw_req * erp) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected"); @@ -1526,6 +1373,43 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp) } /* end dasd_3990_erp_file_prot */ /* + * DASD_3990_ERP_INSPECT_ALIAS + * + * DESCRIPTION + * Checks if the original request was started on an alias device. + * If yes, it modifies the original and the erp request so that + * the erp request can be started on a base device. + * + * PARAMETER + * erp pointer to the currently created default ERP + * + * RETURN VALUES + * erp pointer to the modified ERP, or NULL + */ + +static struct dasd_ccw_req *dasd_3990_erp_inspect_alias( + struct dasd_ccw_req *erp) +{ + struct dasd_ccw_req *cqr = erp->refers; + + if (cqr->block && + (cqr->block->base != cqr->startdev)) { + if (cqr->startdev->features & DASD_FEATURE_ERPLOG) { + DEV_MESSAGE(KERN_ERR, cqr->startdev, + "ERP on alias device for request %p," + " recover on base device %s", cqr, + cqr->block->base->cdev->dev.bus_id); + } + dasd_eckd_reset_ccw_to_base_io(cqr); + erp->startdev = cqr->block->base; + erp->function = dasd_3990_erp_inspect_alias; + return erp; + } else + return NULL; +} + + +/* * DASD_3990_ERP_INSPECT_24 * * DESCRIPTION @@ -1623,7 +1507,7 @@ static struct dasd_ccw_req * dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->retries = 256; erp->function = dasd_3990_erp_action_10_32; @@ -1657,13 +1541,14 @@ static struct dasd_ccw_req * dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) { - struct dasd_device *device = default_erp->device; + struct dasd_device *device = default_erp->startdev; __u32 cpa = 0; struct dasd_ccw_req *cqr; struct dasd_ccw_req *erp; struct DE_eckd_data *DE_data; + struct PFX_eckd_data *PFX_data; char *LO_data; /* LO_eckd_data_t */ - struct ccw1 *ccw; + struct ccw1 *ccw, *oldccw; DEV_MESSAGE(KERN_DEBUG, device, "%s", "Write not finished because of unexpected condition"); @@ -1702,8 +1587,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* Build new ERP request including DE/LO */ erp = dasd_alloc_erp_request((char *) &cqr->magic, 2 + 1,/* DE/LO + TIC */ - sizeof (struct DE_eckd_data) + - sizeof (struct LO_eckd_data), device); + sizeof(struct DE_eckd_data) + + sizeof(struct LO_eckd_data), device); if (IS_ERR(erp)) { DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP"); @@ -1712,10 +1597,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* use original DE */ DE_data = erp->data; - memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data)); + oldccw = cqr->cpaddr; + if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) { + PFX_data = cqr->data; + memcpy(DE_data, &PFX_data->define_extend, + sizeof(struct DE_eckd_data)); + } else + memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data)); /* create LO */ - LO_data = erp->data + sizeof (struct DE_eckd_data); + LO_data = erp->data + sizeof(struct DE_eckd_data); if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { @@ -1748,7 +1639,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* create DE ccw */ ccw = erp->cpaddr; - memset(ccw, 0, sizeof (struct ccw1)); + memset(ccw, 0, sizeof(struct ccw1)); ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; ccw->flags = CCW_FLAG_CC; ccw->count = 16; @@ -1756,7 +1647,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* create LO ccw */ ccw++; - memset(ccw, 0, sizeof (struct ccw1)); + memset(ccw, 0, sizeof(struct ccw1)); ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; ccw->flags = CCW_FLAG_CC; ccw->count = 16; @@ -1770,7 +1661,8 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* fill erp related fields */ erp->function = dasd_3990_erp_action_1B_32; erp->refers = default_erp->refers; - erp->device = device; + erp->startdev = device; + erp->memdev = device; erp->magic = default_erp->magic; erp->expires = 0; erp->retries = 256; @@ -1803,7 +1695,7 @@ static struct dasd_ccw_req * dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) { - struct dasd_device *device = previous_erp->device; + struct dasd_device *device = previous_erp->startdev; __u32 cpa = 0; struct dasd_ccw_req *cqr; struct dasd_ccw_req *erp; @@ -1827,7 +1719,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) DEV_MESSAGE(KERN_DEBUG, device, "%s", "Imprecise ending is set - just retry"); - previous_erp->status = DASD_CQR_QUEUED; + previous_erp->status = DASD_CQR_FILLED; return previous_erp; } @@ -1850,7 +1742,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) erp = previous_erp; /* update the LO with the new returned sense data */ - LO_data = erp->data + sizeof (struct DE_eckd_data); + LO_data = erp->data + sizeof(struct DE_eckd_data); if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { @@ -1889,7 +1781,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) ccw++; /* addr of TIC ccw */ ccw->cda = cpa; - erp->status = DASD_CQR_QUEUED; + erp->status = DASD_CQR_FILLED; return erp; @@ -1968,9 +1860,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) * try further actions. */ erp->lpm = 0; - - erp->status = DASD_CQR_ERROR; - + erp->status = DASD_CQR_NEED_ERP; } } @@ -2047,7 +1937,7 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense) if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) { /* set to suspended duplex state then restart */ - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; DEV_MESSAGE(KERN_ERR, device, "%s", "Set device to suspended duplex state should be " @@ -2081,28 +1971,26 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense) { if ((erp->function == dasd_3990_erp_compound_retry) && - (erp->status == DASD_CQR_ERROR)) { + (erp->status == DASD_CQR_NEED_ERP)) { dasd_3990_erp_compound_path(erp, sense); } if ((erp->function == dasd_3990_erp_compound_path) && - (erp->status == DASD_CQR_ERROR)) { + (erp->status == DASD_CQR_NEED_ERP)) { erp = dasd_3990_erp_compound_code(erp, sense); } if ((erp->function == dasd_3990_erp_compound_code) && - (erp->status == DASD_CQR_ERROR)) { + (erp->status == DASD_CQR_NEED_ERP)) { dasd_3990_erp_compound_config(erp, sense); } /* if no compound action ERP specified, the request failed */ - if (erp->status == DASD_CQR_ERROR) { - + if (erp->status == DASD_CQR_NEED_ERP) erp->status = DASD_CQR_FAILED; - } return erp; @@ -2127,7 +2015,7 @@ static struct dasd_ccw_req * dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; erp->function = dasd_3990_erp_inspect_32; @@ -2149,8 +2037,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) case 0x01: /* fatal error */ DEV_MESSAGE(KERN_ERR, device, "%s", - "Fatal error should have been " - "handled within the interrupt handler"); + "Retry not recommended - Fatal error"); erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); break; @@ -2253,6 +2140,11 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp) /* already set up new ERP ! */ char *sense = erp->refers->irb.ecw; + /* if this problem occured on an alias retry on base */ + erp_new = dasd_3990_erp_inspect_alias(erp); + if (erp_new) + return erp_new; + /* distinguish between 24 and 32 byte sense data */ if (sense[27] & DASD_SENSE_BIT_0) { @@ -2287,13 +2179,13 @@ static struct dasd_ccw_req * dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) { - struct dasd_device *device = cqr->device; + struct dasd_device *device = cqr->startdev; struct ccw1 *ccw; /* allocate additional request block */ struct dasd_ccw_req *erp; - erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device); + erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, device); if (IS_ERR(erp)) { if (cqr->retries <= 0) { DEV_MESSAGE(KERN_ERR, device, "%s", @@ -2305,7 +2197,7 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) "Unable to allocate ERP request " "(%i retries left)", cqr->retries); - dasd_set_timer(device, (HZ << 3)); + dasd_block_set_timer(device->block, (HZ << 3)); } return cqr; } @@ -2319,7 +2211,9 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) ccw->cda = (long)(cqr->cpaddr); erp->function = dasd_3990_erp_add_erp; erp->refers = cqr; - erp->device = cqr->device; + erp->startdev = device; + erp->memdev = device; + erp->block = cqr->block; erp->magic = cqr->magic; erp->expires = 0; erp->retries = 256; @@ -2466,7 +2360,7 @@ static struct dasd_ccw_req * dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) { - struct dasd_device *device = erp->device; + struct dasd_device *device = erp->startdev; char *sense = erp->irb.ecw; /* check for 24 byte sense ERP */ @@ -2557,7 +2451,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, struct dasd_ccw_req *erp) { - struct dasd_device *device = erp_head->device; + struct dasd_device *device = erp_head->startdev; struct dasd_ccw_req *erp_done = erp_head; /* finished req */ struct dasd_ccw_req *erp_free = NULL; /* req to be freed */ @@ -2569,13 +2463,13 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, "original request was lost\n"); /* remove the request from the device queue */ - list_del(&erp_done->list); + list_del(&erp_done->blocklist); erp_free = erp_done; erp_done = erp_done->refers; /* free the finished erp request */ - dasd_free_erp_request(erp_free, erp_free->device); + dasd_free_erp_request(erp_free, erp_free->memdev); } /* end while */ @@ -2603,7 +2497,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, erp->retries, erp); /* handle the request again... */ - erp->status = DASD_CQR_QUEUED; + erp->status = DASD_CQR_FILLED; } } else { @@ -2620,7 +2514,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, * DASD_3990_ERP_ACTION * * DESCRIPTION - * controll routine for 3990 erp actions. + * control routine for 3990 erp actions. * Has to be called with the queue lock (namely the s390_irq_lock) acquired. * * PARAMETER @@ -2636,9 +2530,8 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, struct dasd_ccw_req * dasd_3990_erp_action(struct dasd_ccw_req * cqr) { - struct dasd_ccw_req *erp = NULL; - struct dasd_device *device = cqr->device; + struct dasd_device *device = cqr->startdev; struct dasd_ccw_req *temp_erp = NULL; if (device->features & DASD_FEATURE_ERPLOG) { @@ -2704,10 +2597,11 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } } - /* enqueue added ERP request */ - if (erp->status == DASD_CQR_FILLED) { - erp->status = DASD_CQR_QUEUED; - list_add(&erp->list, &device->ccw_queue); + /* enqueue ERP request if it's a new one */ + if (list_empty(&erp->blocklist)) { + cqr->status = DASD_CQR_IN_ERP; + /* add erp request before the cqr */ + list_add_tail(&erp->blocklist, &cqr->blocklist); } return erp; diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c deleted file mode 100644 index 6e082688475a..000000000000 --- a/drivers/s390/block/dasd_9336_erp.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * File...........: linux/drivers/s390/block/dasd_9336_erp.c - * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 - * - */ - -#define PRINTK_HEADER "dasd_erp(9336)" - -#include "dasd_int.h" - - -/* - * DASD_9336_ERP_EXAMINE - * - * DESCRIPTION - * Checks only for fatal/no/recover error. - * A detailed examination of the sense data is done later outside - * the interrupt handler. - * - * The logic is based on the 'IBM 3880 Storage Control Reference' manual - * 'Chapter 7. 9336 Sense Data'. - * - * RETURN VALUES - * dasd_era_none no error - * dasd_era_fatal for all fatal (unrecoverable errors) - * dasd_era_recover for all others. - */ -dasd_era_t -dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) -{ - /* check for successful execution first */ - if (irb->scsw.cstat == 0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; - - /* examine the 24 byte sense data */ - return dasd_era_recover; - -} /* END dasd_9336_erp_examine */ diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c deleted file mode 100644 index ddecb9808ed4..000000000000 --- a/drivers/s390/block/dasd_9343_erp.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * File...........: linux/drivers/s390/block/dasd_9345_erp.c - * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> - * Bugreports.to..: <Linux390@de.ibm.com> - * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 - * - */ - -#define PRINTK_HEADER "dasd_erp(9343)" - -#include "dasd_int.h" - -dasd_era_t -dasd_9343_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) -{ - if (irb->scsw.cstat == 0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; - - return dasd_era_recover; -} diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c new file mode 100644 index 000000000000..3a40bee9d358 --- /dev/null +++ b/drivers/s390/block/dasd_alias.c @@ -0,0 +1,903 @@ +/* + * PAV alias management for the DASD ECKD discipline + * + * Copyright IBM Corporation, 2007 + * Author(s): Stefan Weinhuber <wein@de.ibm.com> + */ + +#include <linux/list.h> +#include <asm/ebcdic.h> +#include "dasd_int.h" +#include "dasd_eckd.h" + +#ifdef PRINTK_HEADER +#undef PRINTK_HEADER +#endif /* PRINTK_HEADER */ +#define PRINTK_HEADER "dasd(eckd):" + + +/* + * General concept of alias management: + * - PAV and DASD alias management is specific to the eckd discipline. + * - A device is connected to an lcu as long as the device exists. + * dasd_alias_make_device_known_to_lcu will be called wenn the + * device is checked by the eckd discipline and + * dasd_alias_disconnect_device_from_lcu will be called + * before the device is deleted. + * - The dasd_alias_add_device / dasd_alias_remove_device + * functions mark the point when a device is 'ready for service'. + * - A summary unit check is a rare occasion, but it is mandatory to + * support it. It requires some complex recovery actions before the + * devices can be used again (see dasd_alias_handle_summary_unit_check). + * - dasd_alias_get_start_dev will find an alias device that can be used + * instead of the base device and does some (very simple) load balancing. + * This is the function that gets called for each I/O, so when improving + * something, this function should get faster or better, the rest has just + * to be correct. + */ + + +static void summary_unit_check_handling_work(struct work_struct *); +static void lcu_update_work(struct work_struct *); +static int _schedule_lcu_update(struct alias_lcu *, struct dasd_device *); + +static struct alias_root aliastree = { + .serverlist = LIST_HEAD_INIT(aliastree.serverlist), + .lock = __SPIN_LOCK_UNLOCKED(aliastree.lock), +}; + +static struct alias_server *_find_server(struct dasd_uid *uid) +{ + struct alias_server *pos; + list_for_each_entry(pos, &aliastree.serverlist, server) { + if (!strncmp(pos->uid.vendor, uid->vendor, + sizeof(uid->vendor)) + && !strncmp(pos->uid.serial, uid->serial, + sizeof(uid->serial))) + return pos; + }; + return NULL; +} + +static struct alias_lcu *_find_lcu(struct alias_server *server, + struct dasd_uid *uid) +{ + struct alias_lcu *pos; + list_for_each_entry(pos, &server->lculist, lcu) { + if (pos->uid.ssid == uid->ssid) + return pos; + }; + return NULL; +} + +static struct alias_pav_group *_find_group(struct alias_lcu *lcu, + struct dasd_uid *uid) +{ + struct alias_pav_group *pos; + __u8 search_unit_addr; + + /* for hyper pav there is only one group */ + if (lcu->pav == HYPER_PAV) { + if (list_empty(&lcu->grouplist)) + return NULL; + else + return list_first_entry(&lcu->grouplist, + struct alias_pav_group, group); + } + + /* for base pav we have to find the group that matches the base */ + if (uid->type == UA_BASE_DEVICE) + search_unit_addr = uid->real_unit_addr; + 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) + return pos; + }; + return NULL; +} + +static struct alias_server *_allocate_server(struct dasd_uid *uid) +{ + struct alias_server *server; + + server = kzalloc(sizeof(*server), GFP_KERNEL); + if (!server) + return ERR_PTR(-ENOMEM); + memcpy(server->uid.vendor, uid->vendor, sizeof(uid->vendor)); + memcpy(server->uid.serial, uid->serial, sizeof(uid->serial)); + INIT_LIST_HEAD(&server->server); + INIT_LIST_HEAD(&server->lculist); + return server; +} + +static void _free_server(struct alias_server *server) +{ + kfree(server); +} + +static struct alias_lcu *_allocate_lcu(struct dasd_uid *uid) +{ + struct alias_lcu *lcu; + + lcu = kzalloc(sizeof(*lcu), GFP_KERNEL); + if (!lcu) + return ERR_PTR(-ENOMEM); + lcu->uac = kzalloc(sizeof(*(lcu->uac)), GFP_KERNEL | GFP_DMA); + if (!lcu->uac) + goto out_err1; + lcu->rsu_cqr = kzalloc(sizeof(*lcu->rsu_cqr), GFP_KERNEL | GFP_DMA); + if (!lcu->rsu_cqr) + goto out_err2; + lcu->rsu_cqr->cpaddr = kzalloc(sizeof(struct ccw1), + GFP_KERNEL | GFP_DMA); + if (!lcu->rsu_cqr->cpaddr) + goto out_err3; + lcu->rsu_cqr->data = kzalloc(16, GFP_KERNEL | GFP_DMA); + if (!lcu->rsu_cqr->data) + goto out_err4; + + memcpy(lcu->uid.vendor, uid->vendor, sizeof(uid->vendor)); + memcpy(lcu->uid.serial, uid->serial, sizeof(uid->serial)); + lcu->uid.ssid = uid->ssid; + lcu->pav = NO_PAV; + lcu->flags = NEED_UAC_UPDATE | UPDATE_PENDING; + INIT_LIST_HEAD(&lcu->lcu); + INIT_LIST_HEAD(&lcu->inactive_devices); + INIT_LIST_HEAD(&lcu->active_devices); + INIT_LIST_HEAD(&lcu->grouplist); + INIT_WORK(&lcu->suc_data.worker, summary_unit_check_handling_work); + INIT_DELAYED_WORK(&lcu->ruac_data.dwork, lcu_update_work); + spin_lock_init(&lcu->lock); + return lcu; + +out_err4: + kfree(lcu->rsu_cqr->cpaddr); +out_err3: + kfree(lcu->rsu_cqr); +out_err2: + kfree(lcu->uac); +out_err1: + kfree(lcu); + return ERR_PTR(-ENOMEM); +} + +static void _free_lcu(struct alias_lcu *lcu) +{ + kfree(lcu->rsu_cqr->data); + kfree(lcu->rsu_cqr->cpaddr); + kfree(lcu->rsu_cqr); + kfree(lcu->uac); + kfree(lcu); +} + +/* + * This is the function that will allocate all the server and lcu data, + * so this function must be called first for a new device. + * If the return value is 1, the lcu was already known before, if it + * is 0, this is a new lcu. + * Negative return code indicates that something went wrong (e.g. -ENOMEM) + */ +int dasd_alias_make_device_known_to_lcu(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + unsigned long flags; + struct alias_server *server, *newserver; + struct alias_lcu *lcu, *newlcu; + int is_lcu_known; + struct dasd_uid *uid; + + private = (struct dasd_eckd_private *) device->private; + uid = &private->uid; + spin_lock_irqsave(&aliastree.lock, flags); + is_lcu_known = 1; + server = _find_server(uid); + if (!server) { + spin_unlock_irqrestore(&aliastree.lock, flags); + newserver = _allocate_server(uid); + if (IS_ERR(newserver)) + return PTR_ERR(newserver); + spin_lock_irqsave(&aliastree.lock, flags); + server = _find_server(uid); + if (!server) { + list_add(&newserver->server, &aliastree.serverlist); + server = newserver; + is_lcu_known = 0; + } else { + /* someone was faster */ + _free_server(newserver); + } + } + + lcu = _find_lcu(server, uid); + if (!lcu) { + spin_unlock_irqrestore(&aliastree.lock, flags); + newlcu = _allocate_lcu(uid); + if (IS_ERR(newlcu)) + return PTR_ERR(lcu); + spin_lock_irqsave(&aliastree.lock, flags); + lcu = _find_lcu(server, uid); + if (!lcu) { + list_add(&newlcu->lcu, &server->lculist); + lcu = newlcu; + is_lcu_known = 0; + } else { + /* someone was faster */ + _free_lcu(newlcu); + } + is_lcu_known = 0; + } + spin_lock(&lcu->lock); + list_add(&device->alias_list, &lcu->inactive_devices); + private->lcu = lcu; + spin_unlock(&lcu->lock); + spin_unlock_irqrestore(&aliastree.lock, flags); + + return is_lcu_known; +} + +/* + * This function removes a device from the scope of alias management. + * The complicated part is to make sure that it is not in use by + * any of the workers. If necessary cancel the work. + */ +void dasd_alias_disconnect_device_from_lcu(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + unsigned long flags; + struct alias_lcu *lcu; + struct alias_server *server; + int was_pending; + + private = (struct dasd_eckd_private *) device->private; + lcu = private->lcu; + spin_lock_irqsave(&lcu->lock, flags); + list_del_init(&device->alias_list); + /* make sure that the workers don't use this device */ + if (device == lcu->suc_data.device) { + spin_unlock_irqrestore(&lcu->lock, flags); + cancel_work_sync(&lcu->suc_data.worker); + spin_lock_irqsave(&lcu->lock, flags); + if (device == lcu->suc_data.device) + lcu->suc_data.device = NULL; + } + was_pending = 0; + if (device == lcu->ruac_data.device) { + spin_unlock_irqrestore(&lcu->lock, flags); + was_pending = 1; + cancel_delayed_work_sync(&lcu->ruac_data.dwork); + spin_lock_irqsave(&lcu->lock, flags); + if (device == lcu->ruac_data.device) + lcu->ruac_data.device = NULL; + } + private->lcu = NULL; + spin_unlock_irqrestore(&lcu->lock, flags); + + spin_lock_irqsave(&aliastree.lock, flags); + spin_lock(&lcu->lock); + if (list_empty(&lcu->grouplist) && + list_empty(&lcu->active_devices) && + list_empty(&lcu->inactive_devices)) { + list_del(&lcu->lcu); + spin_unlock(&lcu->lock); + _free_lcu(lcu); + lcu = NULL; + } else { + if (was_pending) + _schedule_lcu_update(lcu, NULL); + spin_unlock(&lcu->lock); + } + server = _find_server(&private->uid); + if (server && list_empty(&server->lculist)) { + list_del(&server->server); + _free_server(server); + } + spin_unlock_irqrestore(&aliastree.lock, flags); +} + +/* + * This function assumes that the unit address configuration stored + * in the lcu is up to date and will update the device uid before + * adding it to a pav group. + */ +static int _add_device_to_lcu(struct alias_lcu *lcu, + struct dasd_device *device) +{ + + struct dasd_eckd_private *private; + struct alias_pav_group *group; + struct dasd_uid *uid; + + private = (struct dasd_eckd_private *) device->private; + uid = &private->uid; + uid->type = lcu->uac->unit[uid->real_unit_addr].ua_type; + uid->base_unit_addr = lcu->uac->unit[uid->real_unit_addr].base_ua; + dasd_set_uid(device->cdev, &private->uid); + + /* if we have no PAV anyway, we don't need to bother with PAV groups */ + if (lcu->pav == NO_PAV) { + list_move(&device->alias_list, &lcu->active_devices); + return 0; + } + + group = _find_group(lcu, uid); + if (!group) { + group = kzalloc(sizeof(*group), GFP_ATOMIC); + if (!group) + return -ENOMEM; + memcpy(group->uid.vendor, uid->vendor, sizeof(uid->vendor)); + memcpy(group->uid.serial, uid->serial, sizeof(uid->serial)); + group->uid.ssid = uid->ssid; + if (uid->type == UA_BASE_DEVICE) + group->uid.base_unit_addr = uid->real_unit_addr; + else + group->uid.base_unit_addr = uid->base_unit_addr; + INIT_LIST_HEAD(&group->group); + INIT_LIST_HEAD(&group->baselist); + INIT_LIST_HEAD(&group->aliaslist); + list_add(&group->group, &lcu->grouplist); + } + if (uid->type == UA_BASE_DEVICE) + list_move(&device->alias_list, &group->baselist); + else + list_move(&device->alias_list, &group->aliaslist); + private->pavgroup = group; + return 0; +}; + +static void _remove_device_from_lcu(struct alias_lcu *lcu, + struct dasd_device *device) +{ + struct dasd_eckd_private *private; + struct alias_pav_group *group; + + private = (struct dasd_eckd_private *) device->private; + list_move(&device->alias_list, &lcu->inactive_devices); + group = private->pavgroup; + if (!group) + return; + private->pavgroup = NULL; + if (list_empty(&group->baselist) && list_empty(&group->aliaslist)) { + list_del(&group->group); + kfree(group); + return; + } + if (group->next == device) + group->next = NULL; +}; + +static int read_unit_address_configuration(struct dasd_device *device, + struct alias_lcu *lcu) +{ + struct dasd_psf_prssd_data *prssdp; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + int rc; + unsigned long flags; + + cqr = dasd_kmalloc_request("ECKD", + 1 /* PSF */ + 1 /* RSSD */ , + (sizeof(struct dasd_psf_prssd_data)), + device); + if (IS_ERR(cqr)) + return PTR_ERR(cqr); + cqr->startdev = device; + cqr->memdev = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 10; + cqr->expires = 20 * HZ; + + /* Prepare for Read Subsystem Data */ + prssdp = (struct dasd_psf_prssd_data *) cqr->data; + memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data)); + prssdp->order = PSF_ORDER_PRSSD; + prssdp->suborder = 0x0e; /* Read unit address configuration */ + /* all other bytes of prssdp must be zero */ + + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_PSF; + ccw->count = sizeof(struct dasd_psf_prssd_data); + ccw->flags |= CCW_FLAG_CC; + ccw->cda = (__u32)(addr_t) prssdp; + + /* Read Subsystem Data - feature codes */ + memset(lcu->uac, 0, sizeof(*(lcu->uac))); + + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_RSSD; + ccw->count = sizeof(*(lcu->uac)); + ccw->cda = (__u32)(addr_t) lcu->uac; + + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + + /* need to unset flag here to detect race with summary unit check */ + spin_lock_irqsave(&lcu->lock, flags); + lcu->flags &= ~NEED_UAC_UPDATE; + spin_unlock_irqrestore(&lcu->lock, flags); + + do { + rc = dasd_sleep_on(cqr); + } while (rc && (cqr->retries > 0)); + if (rc) { + spin_lock_irqsave(&lcu->lock, flags); + lcu->flags |= NEED_UAC_UPDATE; + spin_unlock_irqrestore(&lcu->lock, flags); + } + dasd_kfree_request(cqr, cqr->memdev); + return rc; +} + +static int _lcu_update(struct dasd_device *refdev, struct alias_lcu *lcu) +{ + unsigned long flags; + struct alias_pav_group *pavgroup, *tempgroup; + struct dasd_device *device, *tempdev; + int i, rc; + struct dasd_eckd_private *private; + + spin_lock_irqsave(&lcu->lock, flags); + list_for_each_entry_safe(pavgroup, tempgroup, &lcu->grouplist, group) { + list_for_each_entry_safe(device, tempdev, &pavgroup->baselist, + alias_list) { + list_move(&device->alias_list, &lcu->active_devices); + private = (struct dasd_eckd_private *) device->private; + private->pavgroup = NULL; + } + list_for_each_entry_safe(device, tempdev, &pavgroup->aliaslist, + alias_list) { + list_move(&device->alias_list, &lcu->active_devices); + private = (struct dasd_eckd_private *) device->private; + private->pavgroup = NULL; + } + list_del(&pavgroup->group); + kfree(pavgroup); + } + spin_unlock_irqrestore(&lcu->lock, flags); + + rc = read_unit_address_configuration(refdev, lcu); + if (rc) + return rc; + + spin_lock_irqsave(&lcu->lock, flags); + lcu->pav = NO_PAV; + for (i = 0; i < MAX_DEVICES_PER_LCU; ++i) { + switch (lcu->uac->unit[i].ua_type) { + case UA_BASE_PAV_ALIAS: + lcu->pav = BASE_PAV; + break; + case UA_HYPER_PAV_ALIAS: + lcu->pav = HYPER_PAV; + break; + } + if (lcu->pav != NO_PAV) + break; + } + + list_for_each_entry_safe(device, tempdev, &lcu->active_devices, + alias_list) { + _add_device_to_lcu(lcu, device); + } + spin_unlock_irqrestore(&lcu->lock, flags); + return 0; +} + +static void lcu_update_work(struct work_struct *work) +{ + struct alias_lcu *lcu; + struct read_uac_work_data *ruac_data; + struct dasd_device *device; + unsigned long flags; + int rc; + + ruac_data = container_of(work, struct read_uac_work_data, dwork.work); + lcu = container_of(ruac_data, struct alias_lcu, ruac_data); + device = ruac_data->device; + rc = _lcu_update(device, lcu); + /* + * Need to check flags again, as there could have been another + * prepare_update or a new device a new device while we were still + * processing the data + */ + spin_lock_irqsave(&lcu->lock, flags); + if (rc || (lcu->flags & NEED_UAC_UPDATE)) { + DEV_MESSAGE(KERN_WARNING, device, "could not update" + " alias data in lcu (rc = %d), retry later", rc); + schedule_delayed_work(&lcu->ruac_data.dwork, 30*HZ); + } else { + lcu->ruac_data.device = NULL; + lcu->flags &= ~UPDATE_PENDING; + } + spin_unlock_irqrestore(&lcu->lock, flags); +} + +static int _schedule_lcu_update(struct alias_lcu *lcu, + struct dasd_device *device) +{ + struct dasd_device *usedev = NULL; + struct alias_pav_group *group; + + lcu->flags |= NEED_UAC_UPDATE; + if (lcu->ruac_data.device) { + /* already scheduled or running */ + return 0; + } + if (device && !list_empty(&device->alias_list)) + usedev = device; + + if (!usedev && !list_empty(&lcu->grouplist)) { + group = list_first_entry(&lcu->grouplist, + struct alias_pav_group, group); + if (!list_empty(&group->baselist)) + usedev = list_first_entry(&group->baselist, + struct dasd_device, + alias_list); + else if (!list_empty(&group->aliaslist)) + usedev = list_first_entry(&group->aliaslist, + struct dasd_device, + alias_list); + } + if (!usedev && !list_empty(&lcu->active_devices)) { + usedev = list_first_entry(&lcu->active_devices, + struct dasd_device, alias_list); + } + /* + * if we haven't found a proper device yet, give up for now, the next + * device that will be set active will trigger an lcu update + */ + if (!usedev) + return -EINVAL; + lcu->ruac_data.device = usedev; + schedule_delayed_work(&lcu->ruac_data.dwork, 0); + return 0; +} + +int dasd_alias_add_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + struct alias_lcu *lcu; + unsigned long flags; + int rc; + + private = (struct dasd_eckd_private *) device->private; + lcu = private->lcu; + rc = 0; + spin_lock_irqsave(&lcu->lock, flags); + if (!(lcu->flags & UPDATE_PENDING)) { + rc = _add_device_to_lcu(lcu, device); + if (rc) + lcu->flags |= UPDATE_PENDING; + } + if (lcu->flags & UPDATE_PENDING) { + list_move(&device->alias_list, &lcu->active_devices); + _schedule_lcu_update(lcu, device); + } + spin_unlock_irqrestore(&lcu->lock, flags); + return rc; +} + +int dasd_alias_remove_device(struct dasd_device *device) +{ + struct dasd_eckd_private *private; + struct alias_lcu *lcu; + unsigned long flags; + + private = (struct dasd_eckd_private *) device->private; + lcu = private->lcu; + spin_lock_irqsave(&lcu->lock, flags); + _remove_device_from_lcu(lcu, device); + spin_unlock_irqrestore(&lcu->lock, flags); + return 0; +} + +struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *base_device) +{ + + struct dasd_device *alias_device; + struct alias_pav_group *group; + struct alias_lcu *lcu; + struct dasd_eckd_private *private, *alias_priv; + unsigned long flags; + + private = (struct dasd_eckd_private *) base_device->private; + group = private->pavgroup; + lcu = private->lcu; + if (!group || !lcu) + return NULL; + if (lcu->pav == NO_PAV || + lcu->flags & (NEED_UAC_UPDATE | UPDATE_PENDING)) + return NULL; + + spin_lock_irqsave(&lcu->lock, flags); + alias_device = group->next; + if (!alias_device) { + if (list_empty(&group->aliaslist)) { + spin_unlock_irqrestore(&lcu->lock, flags); + return NULL; + } else { + alias_device = list_first_entry(&group->aliaslist, + struct dasd_device, + alias_list); + } + } + if (list_is_last(&alias_device->alias_list, &group->aliaslist)) + group->next = list_first_entry(&group->aliaslist, + struct dasd_device, alias_list); + else + group->next = list_first_entry(&alias_device->alias_list, + struct dasd_device, alias_list); + spin_unlock_irqrestore(&lcu->lock, flags); + alias_priv = (struct dasd_eckd_private *) alias_device->private; + if ((alias_priv->count < private->count) && !alias_device->stopped) + return alias_device; + else + return NULL; +} + +/* + * Summary unit check handling depends on the way alias devices + * are handled so it is done here rather then in dasd_eckd.c + */ +static int reset_summary_unit_check(struct alias_lcu *lcu, + struct dasd_device *device, + char reason) +{ + struct dasd_ccw_req *cqr; + int rc = 0; + + cqr = lcu->rsu_cqr; + strncpy((char *) &cqr->magic, "ECKD", 4); + ASCEBC((char *) &cqr->magic, 4); + cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RSCK; + cqr->cpaddr->flags = 0 ; + cqr->cpaddr->count = 16; + cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; + ((char *)cqr->data)[0] = reason; + + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 255; /* set retry counter to enable basic ERP */ + cqr->startdev = device; + cqr->memdev = device; + cqr->block = NULL; + cqr->expires = 5 * HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + + rc = dasd_sleep_on_immediatly(cqr); + return rc; +} + +static void _restart_all_base_devices_on_lcu(struct alias_lcu *lcu) +{ + struct alias_pav_group *pavgroup; + struct dasd_device *device; + struct dasd_eckd_private *private; + + /* active and inactive list can contain alias as well as base devices */ + list_for_each_entry(device, &lcu->active_devices, alias_list) { + private = (struct dasd_eckd_private *) device->private; + if (private->uid.type != UA_BASE_DEVICE) + continue; + dasd_schedule_block_bh(device->block); + dasd_schedule_device_bh(device); + } + list_for_each_entry(device, &lcu->inactive_devices, alias_list) { + private = (struct dasd_eckd_private *) device->private; + if (private->uid.type != UA_BASE_DEVICE) + continue; + dasd_schedule_block_bh(device->block); + dasd_schedule_device_bh(device); + } + list_for_each_entry(pavgroup, &lcu->grouplist, group) { + list_for_each_entry(device, &pavgroup->baselist, alias_list) { + dasd_schedule_block_bh(device->block); + dasd_schedule_device_bh(device); + } + } +} + +static void flush_all_alias_devices_on_lcu(struct alias_lcu *lcu) +{ + struct alias_pav_group *pavgroup; + struct dasd_device *device, *temp; + struct dasd_eckd_private *private; + int rc; + unsigned long flags; + LIST_HEAD(active); + + /* + * Problem here ist that dasd_flush_device_queue may wait + * for termination of a request to complete. We can't keep + * the lcu lock during that time, so we must assume that + * the lists may have changed. + * Idea: first gather all active alias devices in a separate list, + * then flush the first element of this list unlocked, and afterwards + * check if it is still on the list before moving it to the + * active_devices list. + */ + + spin_lock_irqsave(&lcu->lock, flags); + list_for_each_entry_safe(device, temp, &lcu->active_devices, + alias_list) { + private = (struct dasd_eckd_private *) device->private; + if (private->uid.type == UA_BASE_DEVICE) + continue; + list_move(&device->alias_list, &active); + } + + list_for_each_entry(pavgroup, &lcu->grouplist, group) { + list_splice_init(&pavgroup->aliaslist, &active); + } + while (!list_empty(&active)) { + device = list_first_entry(&active, struct dasd_device, + alias_list); + spin_unlock_irqrestore(&lcu->lock, flags); + rc = dasd_flush_device_queue(device); + spin_lock_irqsave(&lcu->lock, flags); + /* + * only move device around if it wasn't moved away while we + * were waiting for the flush + */ + if (device == list_first_entry(&active, + struct dasd_device, alias_list)) + list_move(&device->alias_list, &lcu->active_devices); + } + spin_unlock_irqrestore(&lcu->lock, flags); +} + +/* + * This function is called in interrupt context, so the + * cdev lock for device is already locked! + */ +static void _stop_all_devices_on_lcu(struct alias_lcu *lcu, + struct dasd_device *device) +{ + struct alias_pav_group *pavgroup; + struct dasd_device *pos; + + list_for_each_entry(pos, &lcu->active_devices, alias_list) { + if (pos != device) + spin_lock(get_ccwdev_lock(pos->cdev)); + pos->stopped |= DASD_STOPPED_SU; + if (pos != device) + spin_unlock(get_ccwdev_lock(pos->cdev)); + } + list_for_each_entry(pos, &lcu->inactive_devices, alias_list) { + if (pos != device) + spin_lock(get_ccwdev_lock(pos->cdev)); + pos->stopped |= DASD_STOPPED_SU; + if (pos != device) + spin_unlock(get_ccwdev_lock(pos->cdev)); + } + list_for_each_entry(pavgroup, &lcu->grouplist, group) { + list_for_each_entry(pos, &pavgroup->baselist, alias_list) { + if (pos != device) + spin_lock(get_ccwdev_lock(pos->cdev)); + pos->stopped |= DASD_STOPPED_SU; + if (pos != device) + spin_unlock(get_ccwdev_lock(pos->cdev)); + } + list_for_each_entry(pos, &pavgroup->aliaslist, alias_list) { + if (pos != device) + spin_lock(get_ccwdev_lock(pos->cdev)); + pos->stopped |= DASD_STOPPED_SU; + if (pos != device) + spin_unlock(get_ccwdev_lock(pos->cdev)); + } + } +} + +static void _unstop_all_devices_on_lcu(struct alias_lcu *lcu) +{ + struct alias_pav_group *pavgroup; + struct dasd_device *device; + unsigned long flags; + + list_for_each_entry(device, &lcu->active_devices, alias_list) { + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + device->stopped &= ~DASD_STOPPED_SU; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + } + + list_for_each_entry(device, &lcu->inactive_devices, alias_list) { + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + device->stopped &= ~DASD_STOPPED_SU; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + } + + list_for_each_entry(pavgroup, &lcu->grouplist, group) { + list_for_each_entry(device, &pavgroup->baselist, alias_list) { + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + device->stopped &= ~DASD_STOPPED_SU; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), + flags); + } + list_for_each_entry(device, &pavgroup->aliaslist, alias_list) { + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + device->stopped &= ~DASD_STOPPED_SU; + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), + flags); + } + } +} + +static void summary_unit_check_handling_work(struct work_struct *work) +{ + struct alias_lcu *lcu; + struct summary_unit_check_work_data *suc_data; + unsigned long flags; + struct dasd_device *device; + + suc_data = container_of(work, struct summary_unit_check_work_data, + worker); + lcu = container_of(suc_data, struct alias_lcu, suc_data); + device = suc_data->device; + + /* 1. flush alias devices */ + flush_all_alias_devices_on_lcu(lcu); + + /* 2. reset summary unit check */ + spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); + device->stopped &= ~(DASD_STOPPED_SU | DASD_STOPPED_PENDING); + spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + reset_summary_unit_check(lcu, device, suc_data->reason); + + spin_lock_irqsave(&lcu->lock, flags); + _unstop_all_devices_on_lcu(lcu); + _restart_all_base_devices_on_lcu(lcu); + /* 3. read new alias configuration */ + _schedule_lcu_update(lcu, device); + lcu->suc_data.device = NULL; + spin_unlock_irqrestore(&lcu->lock, flags); +} + +/* + * note: this will be called from int handler context (cdev locked) + */ +void dasd_alias_handle_summary_unit_check(struct dasd_device *device, + struct irb *irb) +{ + struct alias_lcu *lcu; + char reason; + struct dasd_eckd_private *private; + + private = (struct dasd_eckd_private *) device->private; + + reason = irb->ecw[8]; + DEV_MESSAGE(KERN_WARNING, device, "%s %x", + "eckd handle summary unit check: reason", reason); + + lcu = private->lcu; + if (!lcu) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "device not ready to handle summary" + " unit check (no lcu structure)"); + return; + } + spin_lock(&lcu->lock); + _stop_all_devices_on_lcu(lcu, device); + /* prepare for lcu_update */ + private->lcu->flags |= NEED_UAC_UPDATE | UPDATE_PENDING; + /* If this device is about to be removed just return and wait for + * the next interrupt on a different device + */ + if (list_empty(&device->alias_list)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "device is in offline processing," + " don't do summary unit check handling"); + spin_unlock(&lcu->lock); + return; + } + if (lcu->suc_data.device) { + /* already scheduled or running */ + DEV_MESSAGE(KERN_WARNING, device, "%s", + "previous instance of summary unit check worker" + " still pending"); + spin_unlock(&lcu->lock); + return ; + } + lcu->suc_data.reason = reason; + lcu->suc_data.device = device; + spin_unlock(&lcu->lock); + schedule_work(&lcu->suc_data.worker); +}; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 0c67258fb9ec..f4fb40257348 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -49,22 +49,6 @@ struct dasd_devmap { }; /* - * dasd_server_ssid_map contains a globally unique storage server subsystem ID. - * dasd_server_ssid_list contains the list of all subsystem IDs accessed by - * the DASD device driver. - */ -struct dasd_server_ssid_map { - struct list_head list; - struct system_id { - char vendor[4]; - char serial[15]; - __u16 ssid; - } sid; -}; - -static struct list_head dasd_server_ssid_list; - -/* * Parameter parsing functions for dasd= parameter. The syntax is: * <devno> : (0x)?[0-9a-fA-F]+ * <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+ @@ -721,8 +705,9 @@ dasd_ro_store(struct device *dev, struct device_attribute *attr, devmap->features &= ~DASD_FEATURE_READONLY; if (devmap->device) devmap->device->features = devmap->features; - if (devmap->device && devmap->device->gdp) - set_disk_ro(devmap->device->gdp, val); + if (devmap->device && devmap->device->block + && devmap->device->block->gdp) + set_disk_ro(devmap->device->block->gdp, val); spin_unlock(&dasd_devmap_lock); return count; } @@ -893,12 +878,16 @@ dasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf) devmap = dasd_find_busid(dev->bus_id); spin_lock(&dasd_devmap_lock); - if (!IS_ERR(devmap)) - alias = devmap->uid.alias; + if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { + spin_unlock(&dasd_devmap_lock); + return sprintf(buf, "0\n"); + } + if (devmap->uid.type == UA_BASE_PAV_ALIAS || + devmap->uid.type == UA_HYPER_PAV_ALIAS) + alias = 1; else alias = 0; spin_unlock(&dasd_devmap_lock); - return sprintf(buf, alias ? "1\n" : "0\n"); } @@ -930,19 +919,36 @@ static ssize_t dasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dasd_devmap *devmap; - char uid[UID_STRLEN]; + char uid_string[UID_STRLEN]; + char ua_string[3]; + struct dasd_uid *uid; devmap = dasd_find_busid(dev->bus_id); spin_lock(&dasd_devmap_lock); - if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0) - snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x", - devmap->uid.vendor, devmap->uid.serial, - devmap->uid.ssid, devmap->uid.unit_addr); - else - uid[0] = 0; + if (IS_ERR(devmap) || strlen(devmap->uid.vendor) == 0) { + spin_unlock(&dasd_devmap_lock); + return sprintf(buf, "\n"); + } + uid = &devmap->uid; + switch (uid->type) { + case UA_BASE_DEVICE: + sprintf(ua_string, "%02x", uid->real_unit_addr); + break; + case UA_BASE_PAV_ALIAS: + sprintf(ua_string, "%02x", uid->base_unit_addr); + break; + case UA_HYPER_PAV_ALIAS: + sprintf(ua_string, "xx"); + break; + default: + /* should not happen, treat like base device */ + 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); spin_unlock(&dasd_devmap_lock); - - return snprintf(buf, PAGE_SIZE, "%s\n", uid); + return snprintf(buf, PAGE_SIZE, "%s\n", uid_string); } static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL); @@ -1040,39 +1046,16 @@ int dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid) { struct dasd_devmap *devmap; - struct dasd_server_ssid_map *srv, *tmp; devmap = dasd_find_busid(cdev->dev.bus_id); if (IS_ERR(devmap)) return PTR_ERR(devmap); - /* generate entry for server_ssid_map */ - srv = (struct dasd_server_ssid_map *) - kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL); - if (!srv) - return -ENOMEM; - strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1); - strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1); - srv->sid.ssid = uid->ssid; - - /* server is already contained ? */ spin_lock(&dasd_devmap_lock); devmap->uid = *uid; - list_for_each_entry(tmp, &dasd_server_ssid_list, list) { - if (!memcmp(&srv->sid, &tmp->sid, - sizeof(struct system_id))) { - kfree(srv); - srv = NULL; - break; - } - } - - /* add servermap to serverlist */ - if (srv) - list_add(&srv->list, &dasd_server_ssid_list); spin_unlock(&dasd_devmap_lock); - return (srv ? 1 : 0); + return 0; } EXPORT_SYMBOL_GPL(dasd_set_uid); @@ -1138,9 +1121,6 @@ dasd_devmap_init(void) dasd_max_devindex = 0; for (i = 0; i < 256; i++) INIT_LIST_HEAD(&dasd_hashlists[i]); - - /* Initialize servermap structure. */ - INIT_LIST_HEAD(&dasd_server_ssid_list); return 0; } diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 571320ab9e1a..d91df38ee4f7 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -142,7 +142,7 @@ dasd_diag_erp(struct dasd_device *device) int rc; mdsk_term_io(device); - rc = mdsk_init_io(device, device->bp_block, 0, NULL); + rc = mdsk_init_io(device, device->block->bp_block, 0, NULL); if (rc) DEV_MESSAGE(KERN_WARNING, device, "DIAG ERP unsuccessful, " "rc=%d", rc); @@ -158,11 +158,11 @@ dasd_start_diag(struct dasd_ccw_req * cqr) struct dasd_diag_req *dreq; int rc; - device = cqr->device; + device = cqr->startdev; if (cqr->retries < 0) { DEV_MESSAGE(KERN_WARNING, device, "DIAG start_IO: request %p " "- no retry left)", cqr); - cqr->status = DASD_CQR_FAILED; + cqr->status = DASD_CQR_ERROR; return -EIO; } private = (struct dasd_diag_private *) device->private; @@ -184,7 +184,7 @@ dasd_start_diag(struct dasd_ccw_req * cqr) switch (rc) { case 0: /* Synchronous I/O finished successfully */ cqr->stopclk = get_clock(); - cqr->status = DASD_CQR_DONE; + cqr->status = DASD_CQR_SUCCESS; /* Indicate to calling function that only a dasd_schedule_bh() and no timer is needed */ rc = -EACCES; @@ -209,12 +209,12 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr) { struct dasd_device *device; - device = cqr->device; + device = cqr->startdev; mdsk_term_io(device); - mdsk_init_io(device, device->bp_block, 0, NULL); - cqr->status = DASD_CQR_CLEAR; + mdsk_init_io(device, device->block->bp_block, 0, NULL); + cqr->status = DASD_CQR_CLEAR_PENDING; cqr->stopclk = get_clock(); - dasd_schedule_bh(device); + dasd_schedule_device_bh(device); return 0; } @@ -247,7 +247,7 @@ dasd_ext_handler(__u16 code) return; } cqr = (struct dasd_ccw_req *) ip; - device = (struct dasd_device *) cqr->device; + device = (struct dasd_device *) cqr->startdev; if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) { DEV_MESSAGE(KERN_WARNING, device, " magic number of dasd_ccw_req 0x%08X doesn't" @@ -260,10 +260,10 @@ dasd_ext_handler(__u16 code) spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); /* Check for a pending clear operation */ - if (cqr->status == DASD_CQR_CLEAR) { - cqr->status = DASD_CQR_QUEUED; - dasd_clear_timer(device); - dasd_schedule_bh(device); + if (cqr->status == DASD_CQR_CLEAR_PENDING) { + cqr->status = DASD_CQR_CLEARED; + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); return; } @@ -272,11 +272,11 @@ dasd_ext_handler(__u16 code) expires = 0; if (status == 0) { - cqr->status = DASD_CQR_DONE; + cqr->status = DASD_CQR_SUCCESS; /* Start first request on queue if possible -> fast_io. */ if (!list_empty(&device->ccw_queue)) { next = list_entry(device->ccw_queue.next, - struct dasd_ccw_req, list); + struct dasd_ccw_req, devlist); if (next->status == DASD_CQR_QUEUED) { rc = dasd_start_diag(next); if (rc == 0) @@ -296,10 +296,10 @@ dasd_ext_handler(__u16 code) } if (expires != 0) - dasd_set_timer(device, expires); + dasd_device_set_timer(device, expires); else - dasd_clear_timer(device); - dasd_schedule_bh(device); + dasd_device_clear_timer(device); + dasd_schedule_device_bh(device); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); } @@ -309,6 +309,7 @@ dasd_ext_handler(__u16 code) static int dasd_diag_check_device(struct dasd_device *device) { + struct dasd_block *block; struct dasd_diag_private *private; struct dasd_diag_characteristics *rdc_data; struct dasd_diag_bio bio; @@ -328,6 +329,16 @@ dasd_diag_check_device(struct dasd_device *device) ccw_device_get_id(device->cdev, &private->dev_id); device->private = (void *) private; } + block = dasd_alloc_block(); + if (IS_ERR(block)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "could not allocate dasd block structure"); + kfree(device->private); + return PTR_ERR(block); + } + device->block = block; + block->base = device; + /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); rdc_data->dev_nr = private->dev_id.devno; @@ -409,14 +420,14 @@ dasd_diag_check_device(struct dasd_device *device) sizeof(DASD_DIAG_CMS1)) == 0) { /* get formatted blocksize from label block */ bsize = (unsigned int) label->block_size; - device->blocks = (unsigned long) label->block_count; + block->blocks = (unsigned long) label->block_count; } else - device->blocks = end_block; - device->bp_block = bsize; - device->s2b_shift = 0; /* bits to shift 512 to get a block */ + block->blocks = end_block; + block->bp_block = bsize; + block->s2b_shift = 0; /* bits to shift 512 to get a block */ for (sb = 512; sb < bsize; sb = sb << 1) - device->s2b_shift++; - rc = mdsk_init_io(device, device->bp_block, 0, NULL); + block->s2b_shift++; + rc = mdsk_init_io(device, block->bp_block, 0, NULL); if (rc) { DEV_MESSAGE(KERN_WARNING, device, "DIAG initialization " "failed (rc=%d)", rc); @@ -424,9 +435,9 @@ dasd_diag_check_device(struct dasd_device *device) } else { DEV_MESSAGE(KERN_INFO, device, "(%ld B/blk): %ldkB", - (unsigned long) device->bp_block, - (unsigned long) (device->blocks << - device->s2b_shift) >> 1); + (unsigned long) block->bp_block, + (unsigned long) (block->blocks << + block->s2b_shift) >> 1); } out: free_page((long) label); @@ -436,22 +447,16 @@ out: /* Fill in virtual disk geometry for device. Return zero on success, non-zero * otherwise. */ static int -dasd_diag_fill_geometry(struct dasd_device *device, struct hd_geometry *geo) +dasd_diag_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) { - if (dasd_check_blocksize(device->bp_block) != 0) + if (dasd_check_blocksize(block->bp_block) != 0) return -EINVAL; - geo->cylinders = (device->blocks << device->s2b_shift) >> 10; + geo->cylinders = (block->blocks << block->s2b_shift) >> 10; geo->heads = 16; - geo->sectors = 128 >> device->s2b_shift; + geo->sectors = 128 >> block->s2b_shift; return 0; } -static dasd_era_t -dasd_diag_examine_error(struct dasd_ccw_req * cqr, struct irb * stat) -{ - return dasd_era_fatal; -} - static dasd_erp_fn_t dasd_diag_erp_action(struct dasd_ccw_req * cqr) { @@ -466,8 +471,9 @@ dasd_diag_erp_postaction(struct dasd_ccw_req * cqr) /* Create DASD request from block device request. Return pointer to new * request on success, ERR_PTR otherwise. */ -static struct dasd_ccw_req * -dasd_diag_build_cp(struct dasd_device * device, struct request *req) +static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, + struct dasd_block *block, + struct request *req) { struct dasd_ccw_req *cqr; struct dasd_diag_req *dreq; @@ -486,17 +492,17 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) rw_cmd = MDSK_WRITE_REQ; else return ERR_PTR(-EINVAL); - blksize = device->bp_block; + blksize = block->bp_block; /* Calculate record id of first and last block. */ - first_rec = req->sector >> device->s2b_shift; - last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; + first_rec = req->sector >> block->s2b_shift; + last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; rq_for_each_segment(bv, req, iter) { if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + count += bv->bv_len >> (block->s2b_shift + 9); } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -505,7 +511,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) datasize = sizeof(struct dasd_diag_req) + count*sizeof(struct dasd_diag_bio); cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0, - datasize, device); + datasize, memdev); if (IS_ERR(cqr)) return cqr; @@ -529,7 +535,9 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req) cqr->buildclk = get_clock(); if (req->cmd_flags & REQ_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->device = device; + cqr->startdev = memdev; + cqr->memdev = memdev; + cqr->block = block; cqr->expires = DIAG_TIMEOUT; cqr->status = DASD_CQR_FILLED; return cqr; @@ -543,10 +551,15 @@ dasd_diag_free_cp(struct dasd_ccw_req *cqr, struct request *req) int status; status = cqr->status == DASD_CQR_DONE; - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return status; } +static void dasd_diag_handle_terminated_request(struct dasd_ccw_req *cqr) +{ + cqr->status = DASD_CQR_FILLED; +}; + /* Fill in IOCTL data for device. */ static int dasd_diag_fill_info(struct dasd_device * device, @@ -583,7 +596,7 @@ static struct dasd_discipline dasd_diag_discipline = { .fill_geometry = dasd_diag_fill_geometry, .start_IO = dasd_start_diag, .term_IO = dasd_diag_term_IO, - .examine_error = dasd_diag_examine_error, + .handle_terminated_request = dasd_diag_handle_terminated_request, .erp_action = dasd_diag_erp_action, .erp_postaction = dasd_diag_erp_postaction, .build_cp = dasd_diag_build_cp, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 44adf8496bda..61f16937c1e0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -52,16 +52,6 @@ MODULE_LICENSE("GPL"); static struct dasd_discipline dasd_eckd_discipline; -struct dasd_eckd_private { - struct dasd_eckd_characteristics rdc_data; - struct dasd_eckd_confdata conf_data; - struct dasd_eckd_path path_data; - struct eckd_count count_area[5]; - int init_cqr_status; - int uses_cdl; - struct attrib_data_t attrib; /* e.g. cache operations */ -}; - /* The ccw bus type uses this table to find devices that it sends to * dasd_eckd_probe */ static struct ccw_device_id dasd_eckd_ids[] = { @@ -188,7 +178,7 @@ check_XRC (struct ccw1 *de_ccw, if (rc == -ENOSYS || rc == -EACCES) rc = 0; - de_ccw->count = sizeof (struct DE_eckd_data); + de_ccw->count = sizeof(struct DE_eckd_data); de_ccw->flags |= CCW_FLAG_SLI; return rc; } @@ -208,7 +198,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, ccw->count = 16; ccw->cda = (__u32) __pa(data); - memset(data, 0, sizeof (struct DE_eckd_data)); + memset(data, 0, sizeof(struct DE_eckd_data)); switch (cmd) { case DASD_ECKD_CCW_READ_HOME_ADDRESS: case DASD_ECKD_CCW_READ_RECORD_ZERO: @@ -280,6 +270,132 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, return rc; } +static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata, + struct dasd_device *device) +{ + struct dasd_eckd_private *private; + int rc; + + private = (struct dasd_eckd_private *) device->private; + if (!private->rdc_data.facilities.XRC_supported) + return 0; + + /* switch on System Time Stamp - needed for XRC Support */ + pfxdata->define_extend.ga_extended |= 0x08; /* 'Time Stamp Valid' */ + pfxdata->define_extend.ga_extended |= 0x02; /* 'Extended Parameter' */ + pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ + + rc = get_sync_clock(&pfxdata->define_extend.ep_sys_time); + /* Ignore return code if sync clock is switched off. */ + if (rc == -ENOSYS || rc == -EACCES) + rc = 0; + return rc; +} + +static int prefix(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, int trk, + int totrk, int cmd, struct dasd_device *basedev, + struct dasd_device *startdev) +{ + struct dasd_eckd_private *basepriv, *startpriv; + struct DE_eckd_data *data; + struct ch_t geo, beg, end; + int rc = 0; + + basepriv = (struct dasd_eckd_private *) basedev->private; + startpriv = (struct dasd_eckd_private *) startdev->private; + data = &pfxdata->define_extend; + + ccw->cmd_code = DASD_ECKD_CCW_PFX; + ccw->flags = 0; + ccw->count = sizeof(*pfxdata); + ccw->cda = (__u32) __pa(pfxdata); + + 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->validity.define_extend = 1; + + /* private uid is kept up to date, conf_data may be outdated */ + if (startpriv->uid.type != UA_BASE_DEVICE) { + pfxdata->validity.verify_base = 1; + if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) + pfxdata->validity.hyper_pav = 1; + } + + /* define extend data (mostly)*/ + switch (cmd) { + case DASD_ECKD_CCW_READ_HOME_ADDRESS: + case DASD_ECKD_CCW_READ_RECORD_ZERO: + case DASD_ECKD_CCW_READ: + case DASD_ECKD_CCW_READ_MT: + case DASD_ECKD_CCW_READ_CKD: + case DASD_ECKD_CCW_READ_CKD_MT: + case DASD_ECKD_CCW_READ_KD: + case DASD_ECKD_CCW_READ_KD_MT: + case DASD_ECKD_CCW_READ_COUNT: + data->mask.perm = 0x1; + data->attributes.operation = basepriv->attrib.operation; + break; + case DASD_ECKD_CCW_WRITE: + case DASD_ECKD_CCW_WRITE_MT: + case DASD_ECKD_CCW_WRITE_KD: + case DASD_ECKD_CCW_WRITE_KD_MT: + data->mask.perm = 0x02; + data->attributes.operation = basepriv->attrib.operation; + rc = check_XRC_on_prefix(pfxdata, basedev); + break; + case DASD_ECKD_CCW_WRITE_CKD: + case DASD_ECKD_CCW_WRITE_CKD_MT: + data->attributes.operation = DASD_BYPASS_CACHE; + rc = check_XRC_on_prefix(pfxdata, basedev); + break; + case DASD_ECKD_CCW_ERASE: + case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: + case DASD_ECKD_CCW_WRITE_RECORD_ZERO: + data->mask.perm = 0x3; + data->mask.auth = 0x1; + data->attributes.operation = DASD_BYPASS_CACHE; + rc = check_XRC_on_prefix(pfxdata, basedev); + break; + default: + DEV_MESSAGE(KERN_ERR, basedev, "unknown opcode 0x%x", cmd); + break; + } + + data->attributes.mode = 0x3; /* ECKD */ + + if ((basepriv->rdc_data.cu_type == 0x2105 || + basepriv->rdc_data.cu_type == 0x2107 || + basepriv->rdc_data.cu_type == 0x1750) + && !(basepriv->uses_cdl && trk < 2)) + data->ga_extended |= 0x40; /* Regular Data Format Mode */ + + geo.cyl = basepriv->rdc_data.no_cyl; + geo.head = basepriv->rdc_data.trk_per_cyl; + beg.cyl = trk / geo.head; + beg.head = trk % geo.head; + end.cyl = totrk / geo.head; + end.head = totrk % geo.head; + + /* check for sequential prestage - enhance cylinder range */ + if (data->attributes.operation == DASD_SEQ_PRESTAGE || + data->attributes.operation == DASD_SEQ_ACCESS) { + + if (end.cyl + basepriv->attrib.nr_cyl < geo.cyl) + end.cyl += basepriv->attrib.nr_cyl; + else + end.cyl = (geo.cyl - 1); + } + + data->beg_ext.cyl = beg.cyl; + data->beg_ext.head = beg.head; + data->end_ext.cyl = end.cyl; + data->end_ext.head = end.head; + return rc; +} + static void locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, int rec_on_trk, int no_rec, int cmd, @@ -300,7 +416,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, ccw->count = 16; ccw->cda = (__u32) __pa(data); - memset(data, 0, sizeof (struct LO_eckd_data)); + memset(data, 0, sizeof(struct LO_eckd_data)); sector = 0; if (rec_on_trk) { switch (private->rdc_data.dev_type) { @@ -441,12 +557,15 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) sizeof(uid->serial) - 1); EBCASC(uid->serial, sizeof(uid->serial) - 1); uid->ssid = confdata->neq.subsystemID; - if (confdata->ned2.sneq.flags == 0x40) { - uid->alias = 1; - uid->unit_addr = confdata->ned2.sneq.base_unit_addr; - } else - uid->unit_addr = confdata->ned1.unit_addr; - + 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; + if (uid->type == UA_BASE_PAV_ALIAS) + uid->base_unit_addr = confdata->ned2.sneq.base_unit_addr; + } else { + uid->type = UA_BASE_DEVICE; + } return 0; } @@ -470,7 +589,9 @@ static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device, ccw->cda = (__u32)(addr_t)rcd_buffer; ccw->count = ciw->count; - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; + cqr->block = NULL; cqr->expires = 10*HZ; cqr->lpm = lpm; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); @@ -511,7 +632,7 @@ static int dasd_eckd_read_conf_lpm(struct dasd_device *device, /* * on success we update the user input parms */ - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); if (ret) goto out_error; @@ -557,19 +678,19 @@ dasd_eckd_read_conf(struct dasd_device *device) "data retrieved"); continue; /* no error */ } - if (conf_len != sizeof (struct dasd_eckd_confdata)) { + 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)); + 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)); + sizeof(struct dasd_eckd_confdata)); conf_data_saved++; } switch (((char *)conf_data)[242] & 0x07){ @@ -586,39 +707,104 @@ dasd_eckd_read_conf(struct dasd_device *device) return 0; } +static int dasd_eckd_read_features(struct dasd_device *device) +{ + struct dasd_psf_prssd_data *prssdp; + struct dasd_rssd_features *features; + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + int rc; + struct dasd_eckd_private *private; + + private = (struct dasd_eckd_private *) device->private; + cqr = dasd_smalloc_request(dasd_eckd_discipline.name, + 1 /* PSF */ + 1 /* RSSD */ , + (sizeof(struct dasd_psf_prssd_data) + + sizeof(struct dasd_rssd_features)), + device); + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate initialization request"); + return PTR_ERR(cqr); + } + cqr->startdev = device; + cqr->memdev = device; + cqr->block = NULL; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 5; + cqr->expires = 10 * HZ; + + /* Prepare for Read Subsystem Data */ + prssdp = (struct dasd_psf_prssd_data *) cqr->data; + memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data)); + prssdp->order = PSF_ORDER_PRSSD; + prssdp->suborder = 0x41; /* Read Feature Codes */ + /* all other bytes of prssdp must be zero */ + + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_PSF; + ccw->count = sizeof(struct dasd_psf_prssd_data); + ccw->flags |= CCW_FLAG_CC; + ccw->cda = (__u32)(addr_t) prssdp; + + /* Read Subsystem Data - feature codes */ + features = (struct dasd_rssd_features *) (prssdp + 1); + memset(features, 0, sizeof(struct dasd_rssd_features)); + + ccw++; + ccw->cmd_code = DASD_ECKD_CCW_RSSD; + ccw->count = sizeof(struct dasd_rssd_features); + ccw->cda = (__u32)(addr_t) features; + + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + rc = dasd_sleep_on(cqr); + if (rc == 0) { + prssdp = (struct dasd_psf_prssd_data *) cqr->data; + features = (struct dasd_rssd_features *) (prssdp + 1); + memcpy(&private->features, features, + sizeof(struct dasd_rssd_features)); + } + dasd_sfree_request(cqr, cqr->memdev); + return rc; +} + + /* * Build CP for Perform Subsystem Function - SSC. */ -static struct dasd_ccw_req * -dasd_eckd_build_psf_ssc(struct dasd_device *device) +static struct dasd_ccw_req *dasd_eckd_build_psf_ssc(struct dasd_device *device) { - struct dasd_ccw_req *cqr; - struct dasd_psf_ssc_data *psf_ssc_data; - struct ccw1 *ccw; + struct dasd_ccw_req *cqr; + struct dasd_psf_ssc_data *psf_ssc_data; + struct ccw1 *ccw; - cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , + cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ , sizeof(struct dasd_psf_ssc_data), device); - if (IS_ERR(cqr)) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", "Could not allocate PSF-SSC request"); - return cqr; - } - psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; - psf_ssc_data->order = PSF_ORDER_SSC; - psf_ssc_data->suborder = 0x08; - - ccw = cqr->cpaddr; - ccw->cmd_code = DASD_ECKD_CCW_PSF; - ccw->cda = (__u32)(addr_t)psf_ssc_data; - ccw->count = 66; - - cqr->device = device; - cqr->expires = 10*HZ; - cqr->buildclk = get_clock(); - cqr->status = DASD_CQR_FILLED; - return cqr; + return cqr; + } + psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data; + psf_ssc_data->order = PSF_ORDER_SSC; + psf_ssc_data->suborder = 0x88; + psf_ssc_data->reserved[0] = 0x88; + + ccw = cqr->cpaddr; + ccw->cmd_code = DASD_ECKD_CCW_PSF; + ccw->cda = (__u32)(addr_t)psf_ssc_data; + ccw->count = 66; + + cqr->startdev = device; + cqr->memdev = device; + cqr->block = NULL; + cqr->expires = 10*HZ; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + return cqr; } /* @@ -629,28 +815,28 @@ dasd_eckd_build_psf_ssc(struct dasd_device *device) static int dasd_eckd_psf_ssc(struct dasd_device *device) { - struct dasd_ccw_req *cqr; - int rc; - - cqr = dasd_eckd_build_psf_ssc(device); - if (IS_ERR(cqr)) - return PTR_ERR(cqr); - - rc = dasd_sleep_on(cqr); - if (!rc) - /* trigger CIO to reprobe devices */ - css_schedule_reprobe(); - dasd_sfree_request(cqr, cqr->device); - return rc; + struct dasd_ccw_req *cqr; + int rc; + + cqr = dasd_eckd_build_psf_ssc(device); + if (IS_ERR(cqr)) + return PTR_ERR(cqr); + + rc = dasd_sleep_on(cqr); + if (!rc) + /* trigger CIO to reprobe devices */ + css_schedule_reprobe(); + dasd_sfree_request(cqr, cqr->memdev); + return rc; } /* * Valide storage server of current device. */ -static int -dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid) +static int dasd_eckd_validate_server(struct dasd_device *device) { int rc; + struct dasd_eckd_private *private; /* Currently PAV is the only reason to 'validate' server on LPAR */ if (dasd_nopav || MACHINE_IS_VM) @@ -659,9 +845,11 @@ dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid) rc = dasd_eckd_psf_ssc(device); /* may be requested feature is not available on server, * therefore just report error and go ahead */ + private = (struct dasd_eckd_private *) device->private; DEV_MESSAGE(KERN_INFO, device, "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d", - uid->vendor, uid->serial, uid->ssid, rc); + private->uid.vendor, private->uid.serial, + private->uid.ssid, rc); /* RE-Read Configuration Data */ return dasd_eckd_read_conf(device); } @@ -674,9 +862,9 @@ static int dasd_eckd_check_characteristics(struct dasd_device *device) { struct dasd_eckd_private *private; - struct dasd_uid uid; + struct dasd_block *block; void *rdc_data; - int rc; + int is_known, rc; private = (struct dasd_eckd_private *) device->private; if (private == NULL) { @@ -699,27 +887,54 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Configuration Data */ rc = dasd_eckd_read_conf(device); if (rc) - return rc; + goto out_err1; /* Generate device unique id and register in devmap */ - rc = dasd_eckd_generate_uid(device, &uid); + rc = dasd_eckd_generate_uid(device, &private->uid); if (rc) - return rc; - rc = dasd_set_uid(device->cdev, &uid); - if (rc == 1) /* new server found */ - rc = dasd_eckd_validate_server(device, &uid); + goto out_err1; + dasd_set_uid(device->cdev, &private->uid); + + if (private->uid.type == UA_BASE_DEVICE) { + block = dasd_alloc_block(); + if (IS_ERR(block)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "could not allocate dasd block structure"); + rc = PTR_ERR(block); + goto out_err1; + } + device->block = block; + block->base = device; + } + + /* register lcu with alias handling, enable PAV if this is a new lcu */ + is_known = dasd_alias_make_device_known_to_lcu(device); + if (is_known < 0) { + rc = is_known; + goto out_err2; + } + if (!is_known) { + /* new lcu found */ + rc = dasd_eckd_validate_server(device); /* will switch pav on */ + if (rc) + goto out_err3; + } + + /* Read Feature Codes */ + rc = dasd_eckd_read_features(device); if (rc) - return rc; + goto out_err3; /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); memset(rdc_data, 0, sizeof(rdc_data)); rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); - if (rc) + if (rc) { DEV_MESSAGE(KERN_WARNING, device, "Read device characteristics returned " "rc=%d", rc); - + goto out_err3; + } DEV_MESSAGE(KERN_INFO, device, "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d", private->rdc_data.dev_type, @@ -729,9 +944,24 @@ dasd_eckd_check_characteristics(struct dasd_device *device) private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl, private->rdc_data.sec_per_trk); + return 0; + +out_err3: + dasd_alias_disconnect_device_from_lcu(device); +out_err2: + dasd_free_block(device->block); + device->block = NULL; +out_err1: + kfree(device->private); + device->private = NULL; return rc; } +static void dasd_eckd_uncheck_device(struct dasd_device *device) +{ + dasd_alias_disconnect_device_from_lcu(device); +} + static struct dasd_ccw_req * dasd_eckd_analysis_ccw(struct dasd_device *device) { @@ -755,7 +985,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) /* Define extent for the first 3 tracks. */ define_extent(ccw++, cqr->data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device); - LO_data = cqr->data + sizeof (struct DE_eckd_data); + LO_data = cqr->data + sizeof(struct DE_eckd_data); /* Locate record for the first 4 records on track 0. */ ccw[-1].flags |= CCW_FLAG_CC; locate_record(ccw++, LO_data++, 0, 0, 4, @@ -783,7 +1013,9 @@ dasd_eckd_analysis_ccw(struct dasd_device *device) ccw->count = 8; ccw->cda = (__u32)(addr_t) count_data; - cqr->device = device; + cqr->block = NULL; + cqr->startdev = device; + cqr->memdev = device; cqr->retries = 0; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -803,7 +1035,7 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data) struct dasd_eckd_private *private; struct dasd_device *device; - device = init_cqr->device; + device = init_cqr->startdev; private = (struct dasd_eckd_private *) device->private; private->init_cqr_status = init_cqr->status; dasd_sfree_request(init_cqr, device); @@ -811,13 +1043,13 @@ dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr, void *data) } static int -dasd_eckd_start_analysis(struct dasd_device *device) +dasd_eckd_start_analysis(struct dasd_block *block) { struct dasd_eckd_private *private; struct dasd_ccw_req *init_cqr; - private = (struct dasd_eckd_private *) device->private; - init_cqr = dasd_eckd_analysis_ccw(device); + private = (struct dasd_eckd_private *) block->base->private; + init_cqr = dasd_eckd_analysis_ccw(block->base); if (IS_ERR(init_cqr)) return PTR_ERR(init_cqr); init_cqr->callback = dasd_eckd_analysis_callback; @@ -828,13 +1060,15 @@ dasd_eckd_start_analysis(struct dasd_device *device) } static int -dasd_eckd_end_analysis(struct dasd_device *device) +dasd_eckd_end_analysis(struct dasd_block *block) { + struct dasd_device *device; struct dasd_eckd_private *private; struct eckd_count *count_area; unsigned int sb, blk_per_trk; int status, i; + device = block->base; private = (struct dasd_eckd_private *) device->private; status = private->init_cqr_status; private->init_cqr_status = -1; @@ -846,7 +1080,7 @@ dasd_eckd_end_analysis(struct dasd_device *device) private->uses_cdl = 1; /* Calculate number of blocks/records per track. */ - blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block); + blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); /* Check Track 0 for Compatible Disk Layout */ count_area = NULL; for (i = 0; i < 3; i++) { @@ -876,56 +1110,65 @@ dasd_eckd_end_analysis(struct dasd_device *device) if (count_area != NULL && count_area->kl == 0) { /* we found notthing violating our disk layout */ if (dasd_check_blocksize(count_area->dl) == 0) - device->bp_block = count_area->dl; + block->bp_block = count_area->dl; } - if (device->bp_block == 0) { + if (block->bp_block == 0) { DEV_MESSAGE(KERN_WARNING, device, "%s", "Volume has incompatible disk layout"); return -EMEDIUMTYPE; } - device->s2b_shift = 0; /* bits to shift 512 to get a block */ - for (sb = 512; sb < device->bp_block; sb = sb << 1) - device->s2b_shift++; + block->s2b_shift = 0; /* bits to shift 512 to get a block */ + for (sb = 512; sb < block->bp_block; sb = sb << 1) + block->s2b_shift++; - blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block); - device->blocks = (private->rdc_data.no_cyl * + blk_per_trk = recs_per_track(&private->rdc_data, 0, block->bp_block); + block->blocks = (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * blk_per_trk); DEV_MESSAGE(KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s", - (device->bp_block >> 10), + (block->bp_block >> 10), ((private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl * - blk_per_trk * (device->bp_block >> 9)) >> 1), - ((blk_per_trk * device->bp_block) >> 10), + blk_per_trk * (block->bp_block >> 9)) >> 1), + ((blk_per_trk * block->bp_block) >> 10), private->uses_cdl ? "compatible disk layout" : "linux disk layout"); return 0; } -static int -dasd_eckd_do_analysis(struct dasd_device *device) +static int dasd_eckd_do_analysis(struct dasd_block *block) { struct dasd_eckd_private *private; - private = (struct dasd_eckd_private *) device->private; + private = (struct dasd_eckd_private *) block->base->private; if (private->init_cqr_status < 0) - return dasd_eckd_start_analysis(device); + return dasd_eckd_start_analysis(block); else - return dasd_eckd_end_analysis(device); + return dasd_eckd_end_analysis(block); } +static int dasd_eckd_ready_to_online(struct dasd_device *device) +{ + return dasd_alias_add_device(device); +}; + +static int dasd_eckd_online_to_ready(struct dasd_device *device) +{ + return dasd_alias_remove_device(device); +}; + static int -dasd_eckd_fill_geometry(struct dasd_device *device, struct hd_geometry *geo) +dasd_eckd_fill_geometry(struct dasd_block *block, struct hd_geometry *geo) { struct dasd_eckd_private *private; - private = (struct dasd_eckd_private *) device->private; - if (dasd_check_blocksize(device->bp_block) == 0) { + private = (struct dasd_eckd_private *) block->base->private; + if (dasd_check_blocksize(block->bp_block) == 0) { geo->sectors = recs_per_track(&private->rdc_data, - 0, device->bp_block); + 0, block->bp_block); } geo->cylinders = private->rdc_data.no_cyl; geo->heads = private->rdc_data.trk_per_cyl; @@ -1037,7 +1280,7 @@ dasd_eckd_format_device(struct dasd_device * device, locate_record(ccw++, (struct LO_eckd_data *) data, fdata->start_unit, 0, rpt + 1, DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, - device->bp_block); + device->block->bp_block); data += sizeof(struct LO_eckd_data); break; case 0x04: /* Invalidate track. */ @@ -1110,43 +1353,28 @@ dasd_eckd_format_device(struct dasd_device * device, ccw++; } } - fcp->device = device; - fcp->retries = 2; /* set retry counter to enable ERP */ + fcp->startdev = device; + fcp->memdev = device; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &fcp->flags); + fcp->retries = 5; /* set retry counter to enable default ERP */ fcp->buildclk = get_clock(); fcp->status = DASD_CQR_FILLED; return fcp; } -static dasd_era_t -dasd_eckd_examine_error(struct dasd_ccw_req * cqr, struct irb * irb) +static void dasd_eckd_handle_terminated_request(struct dasd_ccw_req *cqr) { - struct dasd_device *device = (struct dasd_device *) cqr->device; - struct ccw_device *cdev = device->cdev; - - if (irb->scsw.cstat == 0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; - - switch (cdev->id.cu_type) { - case 0x3990: - case 0x2105: - case 0x2107: - case 0x1750: - return dasd_3990_erp_examine(cqr, irb); - case 0x9343: - return dasd_9343_erp_examine(cqr, irb); - case 0x3880: - default: - DEV_MESSAGE(KERN_WARNING, device, "%s", - "default (unknown CU type) - RECOVERABLE return"); - return dasd_era_recover; + cqr->status = DASD_CQR_FILLED; + if (cqr->block && (cqr->startdev != cqr->block->base)) { + dasd_eckd_reset_ccw_to_base_io(cqr); + cqr->startdev = cqr->block->base; } -} +}; static dasd_erp_fn_t dasd_eckd_erp_action(struct dasd_ccw_req * cqr) { - struct dasd_device *device = (struct dasd_device *) cqr->device; + struct dasd_device *device = (struct dasd_device *) cqr->startdev; struct ccw_device *cdev = device->cdev; switch (cdev->id.cu_type) { @@ -1168,8 +1396,37 @@ dasd_eckd_erp_postaction(struct dasd_ccw_req * cqr) return dasd_default_erp_postaction; } -static struct dasd_ccw_req * -dasd_eckd_build_cp(struct dasd_device * device, struct request *req) + +static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, + struct irb *irb) +{ + char mask; + + /* first of all check for state change pending interrupt */ + mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; + if ((irb->scsw.dstat & mask) == mask) { + dasd_generic_handle_state_change(device); + return; + } + + /* summary unit check */ + if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) { + dasd_alias_handle_summary_unit_check(device, irb); + return; + } + + /* just report other unsolicited interrupts */ + DEV_MESSAGE(KERN_DEBUG, device, "%s", + "unsolicited interrupt received"); + device->discipline->dump_sense(device, NULL, irb); + dasd_schedule_device_bh(device); + + return; +}; + +static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, + struct dasd_block *block, + struct request *req) { struct dasd_eckd_private *private; unsigned long *idaws; @@ -1185,8 +1442,11 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) sector_t first_trk, last_trk; unsigned int first_offs, last_offs; unsigned char cmd, rcmd; + int use_prefix; + struct dasd_device *basedev; - private = (struct dasd_eckd_private *) device->private; + basedev = block->base; + private = (struct dasd_eckd_private *) basedev->private; if (rq_data_dir(req) == READ) cmd = DASD_ECKD_CCW_READ_MT; else if (rq_data_dir(req) == WRITE) @@ -1194,13 +1454,13 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) else return ERR_PTR(-EINVAL); /* Calculate number of blocks/records per track. */ - blksize = device->bp_block; + blksize = block->bp_block; blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); /* Calculate record id of first and last block. */ - first_rec = first_trk = req->sector >> device->s2b_shift; + first_rec = first_trk = req->sector >> block->s2b_shift; first_offs = sector_div(first_trk, blk_per_trk); last_rec = last_trk = - (req->sector + req->nr_sectors - 1) >> device->s2b_shift; + (req->sector + req->nr_sectors - 1) >> block->s2b_shift; last_offs = sector_div(last_trk, blk_per_trk); /* Check struct bio and count the number of blocks for the request. */ count = 0; @@ -1209,20 +1469,33 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) if (bv->bv_len & (blksize - 1)) /* Eckd can only do full blocks. */ return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + count += bv->bv_len >> (block->s2b_shift + 9); #if defined(CONFIG_64BIT) if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) - cidaw += bv->bv_len >> (device->s2b_shift + 9); + cidaw += bv->bv_len >> (block->s2b_shift + 9); #endif } /* Paranoia. */ if (count != last_rec - first_rec + 1) return ERR_PTR(-EINVAL); - /* 1x define extent + 1x locate record + number of blocks */ - cplength = 2 + count; - /* 1x define extent + 1x locate record + cidaws*sizeof(long) */ - datasize = sizeof(struct DE_eckd_data) + sizeof(struct LO_eckd_data) + - cidaw * sizeof(unsigned long); + + /* use the prefix command if available */ + use_prefix = private->features.feature[8] & 0x01; + if (use_prefix) { + /* 1x prefix + number of blocks */ + cplength = 2 + count; + /* 1x prefix + cidaws*sizeof(long) */ + datasize = sizeof(struct PFX_eckd_data) + + sizeof(struct LO_eckd_data) + + cidaw * sizeof(unsigned long); + } else { + /* 1x define extent + 1x locate record + number of blocks */ + cplength = 2 + count; + /* 1x define extent + 1x locate record + cidaws*sizeof(long) */ + datasize = sizeof(struct DE_eckd_data) + + sizeof(struct LO_eckd_data) + + cidaw * sizeof(unsigned long); + } /* Find out the number of additional locate record ccws for cdl. */ if (private->uses_cdl && first_rec < 2*blk_per_trk) { if (last_rec >= 2*blk_per_trk) @@ -1232,26 +1505,42 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) } /* Allocate the ccw request. */ cqr = dasd_smalloc_request(dasd_eckd_discipline.name, - cplength, datasize, device); + cplength, datasize, startdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; - /* First ccw is define extent. */ - if (define_extent(ccw++, cqr->data, first_trk, - last_trk, cmd, device) == -EAGAIN) { - /* Clock not in sync and XRC is enabled. Try again later. */ - dasd_sfree_request(cqr, device); - return ERR_PTR(-EAGAIN); + /* First ccw is define extent or prefix. */ + if (use_prefix) { + if (prefix(ccw++, cqr->data, first_trk, + last_trk, cmd, basedev, startdev) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. + * Try again later. + */ + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-EAGAIN); + } + idaws = (unsigned long *) (cqr->data + + sizeof(struct PFX_eckd_data)); + } else { + if (define_extent(ccw++, cqr->data, first_trk, + last_trk, cmd, startdev) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. + * Try again later. + */ + dasd_sfree_request(cqr, startdev); + return ERR_PTR(-EAGAIN); + } + idaws = (unsigned long *) (cqr->data + + sizeof(struct DE_eckd_data)); } /* Build locate_record+read/write/ccws. */ - idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data)); LO_data = (struct LO_eckd_data *) (idaws + cidaw); recid = first_rec; if (private->uses_cdl == 0 || recid > 2*blk_per_trk) { /* Only standard blocks so there is just one locate record. */ ccw[-1].flags |= CCW_FLAG_CC; locate_record(ccw++, LO_data++, first_trk, first_offs + 1, - last_rec - recid + 1, cmd, device, blksize); + last_rec - recid + 1, cmd, basedev, blksize); } rq_for_each_segment(bv, req, iter) { dst = page_address(bv->bv_page) + bv->bv_offset; @@ -1281,7 +1570,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) ccw[-1].flags |= CCW_FLAG_CC; locate_record(ccw++, LO_data++, trkid, recoffs + 1, - 1, rcmd, device, count); + 1, rcmd, basedev, count); } /* Locate record for standard blocks ? */ if (private->uses_cdl && recid == 2*blk_per_trk) { @@ -1289,7 +1578,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) locate_record(ccw++, LO_data++, trkid, recoffs + 1, last_rec - recid + 1, - cmd, device, count); + cmd, basedev, count); } /* Read/write ccw. */ ccw[-1].flags |= CCW_FLAG_CC; @@ -1310,7 +1599,9 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) } if (req->cmd_flags & REQ_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->device = device; + cqr->startdev = startdev; + cqr->memdev = startdev; + cqr->block = block; cqr->expires = 5 * 60 * HZ; /* 5 minutes */ cqr->lpm = private->path_data.ppm; cqr->retries = 256; @@ -1333,10 +1624,10 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) if (!dasd_page_cache) goto out; - private = (struct dasd_eckd_private *) cqr->device->private; - blksize = cqr->device->bp_block; + private = (struct dasd_eckd_private *) cqr->block->base->private; + blksize = cqr->block->bp_block; blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize); - recid = req->sector >> cqr->device->s2b_shift; + recid = req->sector >> cqr->block->s2b_shift; ccw = cqr->cpaddr; /* Skip over define extent & locate record. */ ccw++; @@ -1367,10 +1658,71 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) } out: status = cqr->status == DASD_CQR_DONE; - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return status; } +/* + * Modify ccw chain in cqr so it can be started on a base device. + * + * Note that this is not enough to restart the cqr! + * Either reset cqr->startdev as well (summary unit check handling) + * or restart via separate cqr (as in ERP handling). + */ +void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *cqr) +{ + struct ccw1 *ccw; + struct PFX_eckd_data *pfxdata; + + ccw = cqr->cpaddr; + pfxdata = cqr->data; + + if (ccw->cmd_code == DASD_ECKD_CCW_PFX) { + pfxdata->validity.verify_base = 0; + pfxdata->validity.hyper_pav = 0; + } +} + +#define DASD_ECKD_CHANQ_MAX_SIZE 4 + +static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base, + struct dasd_block *block, + struct request *req) +{ + struct dasd_eckd_private *private; + struct dasd_device *startdev; + unsigned long flags; + struct dasd_ccw_req *cqr; + + startdev = dasd_alias_get_start_dev(base); + if (!startdev) + startdev = base; + private = (struct dasd_eckd_private *) startdev->private; + if (private->count >= DASD_ECKD_CHANQ_MAX_SIZE) + return ERR_PTR(-EBUSY); + + spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags); + private->count++; + cqr = dasd_eckd_build_cp(startdev, block, req); + if (IS_ERR(cqr)) + private->count--; + spin_unlock_irqrestore(get_ccwdev_lock(startdev->cdev), flags); + return cqr; +} + +static int dasd_eckd_free_alias_cp(struct dasd_ccw_req *cqr, + struct request *req) +{ + struct dasd_eckd_private *private; + unsigned long flags; + + spin_lock_irqsave(get_ccwdev_lock(cqr->memdev->cdev), flags); + private = (struct dasd_eckd_private *) cqr->memdev->private; + private->count--; + spin_unlock_irqrestore(get_ccwdev_lock(cqr->memdev->cdev), flags); + return dasd_eckd_free_cp(cqr, req); +} + static int dasd_eckd_fill_info(struct dasd_device * device, struct dasd_information2_t * info) @@ -1384,9 +1736,9 @@ 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); + info->confdata_size = sizeof(struct dasd_eckd_confdata); memcpy(info->configuration_data, &private->conf_data, - sizeof (struct dasd_eckd_confdata)); + sizeof(struct dasd_eckd_confdata)); return 0; } @@ -1419,7 +1771,8 @@ dasd_eckd_release(struct dasd_device *device) cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->retries = 2; /* set retry counter to enable basic ERP */ @@ -1429,7 +1782,7 @@ dasd_eckd_release(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -1459,7 +1812,8 @@ dasd_eckd_reserve(struct dasd_device *device) cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->retries = 2; /* set retry counter to enable basic ERP */ @@ -1469,7 +1823,7 @@ dasd_eckd_reserve(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -1498,7 +1852,8 @@ dasd_eckd_steal_lock(struct dasd_device *device) cqr->cpaddr->flags |= CCW_FLAG_SLI; cqr->cpaddr->count = 32; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->retries = 2; /* set retry counter to enable basic ERP */ @@ -1508,7 +1863,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -1526,52 +1881,52 @@ dasd_eckd_performance(struct dasd_device *device, void __user *argp) cqr = dasd_smalloc_request(dasd_eckd_discipline.name, 1 /* PSF */ + 1 /* RSSD */ , - (sizeof (struct dasd_psf_prssd_data) + - sizeof (struct dasd_rssd_perf_stats_t)), + (sizeof(struct dasd_psf_prssd_data) + + sizeof(struct dasd_rssd_perf_stats_t)), device); if (IS_ERR(cqr)) { DEV_MESSAGE(KERN_WARNING, device, "%s", "Could not allocate initialization request"); return PTR_ERR(cqr); } - cqr->device = device; + cqr->startdev = device; + cqr->memdev = device; cqr->retries = 0; cqr->expires = 10 * HZ; /* Prepare for Read Subsystem Data */ prssdp = (struct dasd_psf_prssd_data *) cqr->data; - memset(prssdp, 0, sizeof (struct dasd_psf_prssd_data)); + memset(prssdp, 0, sizeof(struct dasd_psf_prssd_data)); prssdp->order = PSF_ORDER_PRSSD; - prssdp->suborder = 0x01; /* Perfomance Statistics */ + prssdp->suborder = 0x01; /* Performance Statistics */ prssdp->varies[1] = 0x01; /* Perf Statistics for the Subsystem */ ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_PSF; - ccw->count = sizeof (struct dasd_psf_prssd_data); + ccw->count = sizeof(struct dasd_psf_prssd_data); ccw->flags |= CCW_FLAG_CC; ccw->cda = (__u32)(addr_t) prssdp; /* Read Subsystem Data - Performance Statistics */ stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); - memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t)); + memset(stats, 0, sizeof(struct dasd_rssd_perf_stats_t)); ccw++; ccw->cmd_code = DASD_ECKD_CCW_RSSD; - ccw->count = sizeof (struct dasd_rssd_perf_stats_t); + ccw->count = sizeof(struct dasd_rssd_perf_stats_t); ccw->cda = (__u32)(addr_t) stats; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on(cqr); if (rc == 0) { - /* Prepare for Read Subsystem Data */ prssdp = (struct dasd_psf_prssd_data *) cqr->data; stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1); if (copy_to_user(argp, stats, sizeof(struct dasd_rssd_perf_stats_t))) rc = -EFAULT; } - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -1594,7 +1949,7 @@ dasd_eckd_get_attrib(struct dasd_device *device, void __user *argp) rc = 0; if (copy_to_user(argp, (long *) &attrib, - sizeof (struct attrib_data_t))) + sizeof(struct attrib_data_t))) rc = -EFAULT; return rc; @@ -1627,8 +1982,10 @@ dasd_eckd_set_attrib(struct dasd_device *device, void __user *argp) } static int -dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp) +dasd_eckd_ioctl(struct dasd_block *block, unsigned int cmd, void __user *argp) { + struct dasd_device *device = block->base; + switch (cmd) { case BIODASDGATTR: return dasd_eckd_get_attrib(device, argp); @@ -1685,9 +2042,8 @@ dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) * Print sense data and related channel program. * Parts are printed because printk buffer is only 1024 bytes. */ -static void -dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, - struct irb *irb) +static void dasd_eckd_dump_sense(struct dasd_device *device, + struct dasd_ccw_req *req, struct irb *irb) { char *page; struct ccw1 *first, *last, *fail, *from, *to; @@ -1743,37 +2099,40 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, } printk("%s", page); - /* dump the Channel Program (max 140 Bytes per line) */ - /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */ - first = req->cpaddr; - for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); - to = min(first + 6, last); - len = sprintf(page, KERN_ERR PRINTK_HEADER - " Related CP in req: %p\n", req); - dasd_eckd_dump_ccw_range(first, to, page + len); - printk("%s", page); + if (req) { + /* req == NULL for unsolicited interrupts */ + /* dump the Channel Program (max 140 Bytes per line) */ + /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */ + first = req->cpaddr; + for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++); + to = min(first + 6, last); + len = sprintf(page, KERN_ERR PRINTK_HEADER + " Related CP in req: %p\n", req); + dasd_eckd_dump_ccw_range(first, to, page + len); + printk("%s", page); - /* print failing CCW area (maximum 4) */ - /* scsw->cda is either valid or zero */ - len = 0; - from = ++to; - fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */ - if (from < fail - 2) { - from = fail - 2; /* there is a gap - print header */ - len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n"); - } - to = min(fail + 1, last); - len += dasd_eckd_dump_ccw_range(from, to, page + len); - - /* print last CCWs (maximum 2) */ - from = max(from, ++to); - if (from < last - 1) { - from = last - 1; /* there is a gap - print header */ - len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); + /* print failing CCW area (maximum 4) */ + /* scsw->cda is either valid or zero */ + len = 0; + from = ++to; + fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */ + if (from < fail - 2) { + from = fail - 2; /* there is a gap - print header */ + len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n"); + } + to = min(fail + 1, last); + len += dasd_eckd_dump_ccw_range(from, to, page + len); + + /* print last CCWs (maximum 2) */ + from = max(from, ++to); + if (from < last - 1) { + from = last - 1; /* there is a gap - print header */ + len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); + } + len += dasd_eckd_dump_ccw_range(from, last, page + len); + if (len > 0) + printk("%s", page); } - len += dasd_eckd_dump_ccw_range(from, last, page + len); - if (len > 0) - printk("%s", page); free_page((unsigned long) page); } @@ -1796,16 +2155,20 @@ static struct dasd_discipline dasd_eckd_discipline = { .ebcname = "ECKD", .max_blocks = 240, .check_device = dasd_eckd_check_characteristics, + .uncheck_device = dasd_eckd_uncheck_device, .do_analysis = dasd_eckd_do_analysis, + .ready_to_online = dasd_eckd_ready_to_online, + .online_to_ready = dasd_eckd_online_to_ready, .fill_geometry = dasd_eckd_fill_geometry, .start_IO = dasd_start_IO, .term_IO = dasd_term_IO, + .handle_terminated_request = dasd_eckd_handle_terminated_request, .format_device = dasd_eckd_format_device, - .examine_error = dasd_eckd_examine_error, .erp_action = dasd_eckd_erp_action, .erp_postaction = dasd_eckd_erp_postaction, - .build_cp = dasd_eckd_build_cp, - .free_cp = dasd_eckd_free_cp, + .handle_unsolicited_interrupt = dasd_eckd_handle_unsolicited_interrupt, + .build_cp = dasd_eckd_build_alias_cp, + .free_cp = dasd_eckd_free_alias_cp, .dump_sense = dasd_eckd_dump_sense, .fill_info = dasd_eckd_fill_info, .ioctl = dasd_eckd_ioctl, diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h index 712ff1650134..fc2509c939bc 100644 --- a/drivers/s390/block/dasd_eckd.h +++ b/drivers/s390/block/dasd_eckd.h @@ -39,6 +39,8 @@ #define DASD_ECKD_CCW_READ_CKD_MT 0x9e #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d #define DASD_ECKD_CCW_RESERVE 0xB4 +#define DASD_ECKD_CCW_PFX 0xE7 +#define DASD_ECKD_CCW_RSCK 0xF9 /* * Perform Subsystem Function / Sub-Orders @@ -137,6 +139,25 @@ struct LO_eckd_data { __u16 length; } __attribute__ ((packed)); +/* Prefix data for format 0x00 and 0x01 */ +struct PFX_eckd_data { + unsigned char format; + struct { + unsigned char define_extend:1; + unsigned char time_stamp:1; + unsigned char verify_base:1; + unsigned char hyper_pav:1; + unsigned char reserved:4; + } __attribute__ ((packed)) validity; + __u8 base_address; + __u8 aux; + __u8 base_lss; + __u8 reserved[7]; + struct DE_eckd_data define_extend; + struct LO_eckd_data locate_record; + __u8 LO_extended_data[4]; +} __attribute__ ((packed)); + struct dasd_eckd_characteristics { __u16 cu_type; struct { @@ -254,7 +275,9 @@ struct dasd_eckd_confdata { } __attribute__ ((packed)) ned; struct { unsigned char flags; /* byte 0 */ - unsigned char res2[7]; /* byte 1- 7 */ + 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 */ @@ -343,6 +366,11 @@ struct dasd_eckd_path { __u8 npm; }; +struct dasd_rssd_features { + char feature[256]; +} __attribute__((packed)); + + /* * Perform Subsystem Function - Prepare for Read Subsystem Data */ @@ -365,4 +393,99 @@ struct dasd_psf_ssc_data { unsigned char reserved[59]; } __attribute__((packed)); + +/* + * some structures and definitions for alias handling + */ +struct dasd_unit_address_configuration { + struct { + char ua_type; + char base_ua; + } unit[256]; +} __attribute__((packed)); + + +#define MAX_DEVICES_PER_LCU 256 + +/* flags on the LCU */ +#define NEED_UAC_UPDATE 0x01 +#define UPDATE_PENDING 0x02 + +enum pavtype {NO_PAV, BASE_PAV, HYPER_PAV}; + + +struct alias_root { + struct list_head serverlist; + spinlock_t lock; +}; + +struct alias_server { + struct list_head server; + struct dasd_uid uid; + struct list_head lculist; +}; + +struct summary_unit_check_work_data { + char reason; + struct dasd_device *device; + struct work_struct worker; +}; + +struct read_uac_work_data { + struct dasd_device *device; + struct delayed_work dwork; +}; + +struct alias_lcu { + struct list_head lcu; + struct dasd_uid uid; + enum pavtype pav; + char flags; + spinlock_t lock; + struct list_head grouplist; + struct list_head active_devices; + struct list_head inactive_devices; + struct dasd_unit_address_configuration *uac; + struct summary_unit_check_work_data suc_data; + struct read_uac_work_data ruac_data; + struct dasd_ccw_req *rsu_cqr; +}; + +struct alias_pav_group { + struct list_head group; + struct dasd_uid uid; + struct alias_lcu *lcu; + struct list_head baselist; + struct list_head aliaslist; + struct dasd_device *next; +}; + + +struct dasd_eckd_private { + struct dasd_eckd_characteristics rdc_data; + struct dasd_eckd_confdata conf_data; + struct dasd_eckd_path path_data; + struct eckd_count count_area[5]; + int init_cqr_status; + int uses_cdl; + struct attrib_data_t attrib; /* e.g. cache operations */ + struct dasd_rssd_features features; + + /* alias managemnet */ + struct dasd_uid uid; + struct alias_pav_group *pavgroup; + struct alias_lcu *lcu; + int count; +}; + + + +int dasd_alias_make_device_known_to_lcu(struct dasd_device *); +void dasd_alias_disconnect_device_from_lcu(struct dasd_device *); +int dasd_alias_add_device(struct dasd_device *); +int dasd_alias_remove_device(struct dasd_device *); +struct dasd_device *dasd_alias_get_start_dev(struct dasd_device *); +void dasd_alias_handle_summary_unit_check(struct dasd_device *, struct irb *); +void dasd_eckd_reset_ccw_to_base_io(struct dasd_ccw_req *); + #endif /* DASD_ECKD_H */ diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 0c081a664ee8..6e53ab606e97 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -336,7 +336,7 @@ static void dasd_eer_write_snss_trigger(struct dasd_device *device, unsigned long flags; struct eerbuffer *eerb; - snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0; + snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO; if (snss_rc) data_size = 0; else @@ -404,10 +404,11 @@ void dasd_eer_snss(struct dasd_device *device) set_bit(DASD_FLAG_EER_SNSS, &device->flags); return; } + /* cdev is already locked, can't use dasd_add_request_head */ clear_bit(DASD_FLAG_EER_SNSS, &device->flags); cqr->status = DASD_CQR_QUEUED; - list_add(&cqr->list, &device->ccw_queue); - dasd_schedule_bh(device); + list_add(&cqr->devlist, &device->ccw_queue); + dasd_schedule_device_bh(device); } /* @@ -415,7 +416,7 @@ void dasd_eer_snss(struct dasd_device *device) */ static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data) { - struct dasd_device *device = cqr->device; + struct dasd_device *device = cqr->startdev; unsigned long flags; dasd_eer_write(device, cqr, DASD_EER_STATECHANGE); @@ -458,7 +459,7 @@ int dasd_eer_enable(struct dasd_device *device) if (!cqr) return -ENOMEM; - cqr->device = device; + cqr->startdev = device; cqr->retries = 255; cqr->expires = 10 * HZ; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index caa5d91420f8..8f10000851a3 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -46,6 +46,8 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize, if (cqr == NULL) return ERR_PTR(-ENOMEM); memset(cqr, 0, sizeof(struct dasd_ccw_req)); + INIT_LIST_HEAD(&cqr->devlist); + INIT_LIST_HEAD(&cqr->blocklist); data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L); cqr->cpaddr = NULL; if (cplength > 0) { @@ -66,7 +68,7 @@ dasd_alloc_erp_request(char *magic, int cplength, int datasize, } void -dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device) +dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device) { unsigned long flags; @@ -81,11 +83,11 @@ dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device) * dasd_default_erp_action just retries the current cqr */ struct dasd_ccw_req * -dasd_default_erp_action(struct dasd_ccw_req * cqr) +dasd_default_erp_action(struct dasd_ccw_req *cqr) { struct dasd_device *device; - device = cqr->device; + device = cqr->startdev; /* just retry - there is nothing to save ... I got no sense data.... */ if (cqr->retries > 0) { @@ -93,12 +95,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr) "default ERP called (%i retries left)", cqr->retries); cqr->lpm = LPM_ANYPATH; - cqr->status = DASD_CQR_QUEUED; + cqr->status = DASD_CQR_FILLED; } else { DEV_MESSAGE (KERN_WARNING, device, "%s", "default ERP called (NO retry left)"); cqr->status = DASD_CQR_FAILED; - cqr->stopclk = get_clock (); + cqr->stopclk = get_clock(); } return cqr; } /* end dasd_default_erp_action */ @@ -117,15 +119,12 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr) * RETURN VALUES * cqr pointer to the original CQR */ -struct dasd_ccw_req * -dasd_default_erp_postaction(struct dasd_ccw_req * cqr) +struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr) { - struct dasd_device *device; int success; BUG_ON(cqr->refers == NULL || cqr->function == NULL); - device = cqr->device; success = cqr->status == DASD_CQR_DONE; /* free all ERPs - but NOT the original cqr */ @@ -133,10 +132,10 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr) struct dasd_ccw_req *refers; refers = cqr->refers; - /* remove the request from the device queue */ - list_del(&cqr->list); + /* remove the request from the block queue */ + list_del(&cqr->blocklist); /* free the finished erp request */ - dasd_free_erp_request(cqr, device); + dasd_free_erp_request(cqr, cqr->memdev); cqr = refers; } @@ -157,7 +156,7 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) { struct dasd_device *device; - device = cqr->device; + device = cqr->startdev; /* dump sense data */ if (device->discipline && device->discipline->dump_sense) device->discipline->dump_sense(device, cqr, irb); diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 1d95822e0b8e..d13ea05089a7 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -117,6 +117,7 @@ locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, static int dasd_fba_check_characteristics(struct dasd_device *device) { + struct dasd_block *block; struct dasd_fba_private *private; struct ccw_device *cdev = device->cdev; void *rdc_data; @@ -133,6 +134,16 @@ dasd_fba_check_characteristics(struct dasd_device *device) } device->private = (void *) private; } + block = dasd_alloc_block(); + if (IS_ERR(block)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "could not allocate dasd block structure"); + kfree(device->private); + return PTR_ERR(block); + } + device->block = block; + block->base = device; + /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); @@ -155,60 +166,37 @@ dasd_fba_check_characteristics(struct dasd_device *device) return 0; } -static int -dasd_fba_do_analysis(struct dasd_device *device) +static int dasd_fba_do_analysis(struct dasd_block *block) { struct dasd_fba_private *private; int sb, rc; - private = (struct dasd_fba_private *) device->private; + private = (struct dasd_fba_private *) block->base->private; rc = dasd_check_blocksize(private->rdc_data.blk_size); if (rc) { - DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d", + DEV_MESSAGE(KERN_INFO, block->base, "unknown blocksize %d", private->rdc_data.blk_size); return rc; } - device->blocks = private->rdc_data.blk_bdsa; - device->bp_block = private->rdc_data.blk_size; - device->s2b_shift = 0; /* bits to shift 512 to get a block */ + block->blocks = private->rdc_data.blk_bdsa; + block->bp_block = private->rdc_data.blk_size; + block->s2b_shift = 0; /* bits to shift 512 to get a block */ for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1) - device->s2b_shift++; + block->s2b_shift++; return 0; } -static int -dasd_fba_fill_geometry(struct dasd_device *device, struct hd_geometry *geo) +static int dasd_fba_fill_geometry(struct dasd_block *block, + struct hd_geometry *geo) { - if (dasd_check_blocksize(device->bp_block) != 0) + if (dasd_check_blocksize(block->bp_block) != 0) return -EINVAL; - geo->cylinders = (device->blocks << device->s2b_shift) >> 10; + geo->cylinders = (block->blocks << block->s2b_shift) >> 10; geo->heads = 16; - geo->sectors = 128 >> device->s2b_shift; + geo->sectors = 128 >> block->s2b_shift; return 0; } -static dasd_era_t -dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb) -{ - struct dasd_device *device; - struct ccw_device *cdev; - - device = (struct dasd_device *) cqr->device; - if (irb->scsw.cstat == 0x00 && - irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) - return dasd_era_none; - - cdev = device->cdev; - switch (cdev->id.dev_type) { - case 0x3370: - return dasd_3370_erp_examine(cqr, irb); - case 0x9336: - return dasd_9336_erp_examine(cqr, irb); - default: - return dasd_era_recover; - } -} - static dasd_erp_fn_t dasd_fba_erp_action(struct dasd_ccw_req * cqr) { @@ -221,13 +209,34 @@ dasd_fba_erp_postaction(struct dasd_ccw_req * cqr) if (cqr->function == dasd_default_erp_action) return dasd_default_erp_postaction; - DEV_MESSAGE(KERN_WARNING, cqr->device, "unknown ERP action %p", + DEV_MESSAGE(KERN_WARNING, cqr->startdev, "unknown ERP action %p", cqr->function); return NULL; } -static struct dasd_ccw_req * -dasd_fba_build_cp(struct dasd_device * device, struct request *req) +static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, + struct irb *irb) +{ + char mask; + + /* first of all check for state change pending interrupt */ + mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; + if ((irb->scsw.dstat & mask) == mask) { + dasd_generic_handle_state_change(device); + return; + } + + /* check for unsolicited interrupts */ + DEV_MESSAGE(KERN_DEBUG, device, "%s", + "unsolicited interrupt received"); + device->discipline->dump_sense(device, NULL, irb); + dasd_schedule_device_bh(device); + return; +}; + +static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, + struct dasd_block *block, + struct request *req) { struct dasd_fba_private *private; unsigned long *idaws; @@ -242,17 +251,17 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) unsigned int blksize, off; unsigned char cmd; - private = (struct dasd_fba_private *) device->private; + private = (struct dasd_fba_private *) block->base->private; if (rq_data_dir(req) == READ) { cmd = DASD_FBA_CCW_READ; } else if (rq_data_dir(req) == WRITE) { cmd = DASD_FBA_CCW_WRITE; } else return ERR_PTR(-EINVAL); - blksize = device->bp_block; + blksize = block->bp_block; /* Calculate record id of first and last block. */ - first_rec = req->sector >> device->s2b_shift; - last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift; + first_rec = req->sector >> block->s2b_shift; + last_rec = (req->sector + req->nr_sectors - 1) >> block->s2b_shift; /* Check struct bio and count the number of blocks for the request. */ count = 0; cidaw = 0; @@ -260,7 +269,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) if (bv->bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); - count += bv->bv_len >> (device->s2b_shift + 9); + count += bv->bv_len >> (block->s2b_shift + 9); #if defined(CONFIG_64BIT) if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) cidaw += bv->bv_len / blksize; @@ -284,13 +293,13 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) } /* Allocate the ccw request. */ cqr = dasd_smalloc_request(dasd_fba_discipline.name, - cplength, datasize, device); + cplength, datasize, memdev); if (IS_ERR(cqr)) return cqr; ccw = cqr->cpaddr; /* First ccw is define extent. */ define_extent(ccw++, cqr->data, rq_data_dir(req), - device->bp_block, req->sector, req->nr_sectors); + block->bp_block, req->sector, req->nr_sectors); /* Build locate_record + read/write ccws. */ idaws = (unsigned long *) (cqr->data + sizeof(struct DE_fba_data)); LO_data = (struct LO_fba_data *) (idaws + cidaw); @@ -326,7 +335,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) ccw[-1].flags |= CCW_FLAG_CC; } ccw->cmd_code = cmd; - ccw->count = device->bp_block; + ccw->count = block->bp_block; if (idal_is_needed(dst, blksize)) { ccw->cda = (__u32)(addr_t) idaws; ccw->flags = CCW_FLAG_IDA; @@ -342,7 +351,9 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req) } if (req->cmd_flags & REQ_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->device = device; + cqr->startdev = memdev; + cqr->memdev = memdev; + cqr->block = block; cqr->expires = 5 * 60 * HZ; /* 5 minutes */ cqr->retries = 32; cqr->buildclk = get_clock(); @@ -363,8 +374,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) if (!dasd_page_cache) goto out; - private = (struct dasd_fba_private *) cqr->device->private; - blksize = cqr->device->bp_block; + private = (struct dasd_fba_private *) cqr->block->base->private; + blksize = cqr->block->bp_block; ccw = cqr->cpaddr; /* Skip over define extent & locate record. */ ccw++; @@ -394,10 +405,15 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) } out: status = cqr->status == DASD_CQR_DONE; - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); return status; } +static void dasd_fba_handle_terminated_request(struct dasd_ccw_req *cqr) +{ + cqr->status = DASD_CQR_FILLED; +}; + static int dasd_fba_fill_info(struct dasd_device * device, struct dasd_information2_t * info) @@ -546,9 +562,10 @@ static struct dasd_discipline dasd_fba_discipline = { .fill_geometry = dasd_fba_fill_geometry, .start_IO = dasd_start_IO, .term_IO = dasd_term_IO, - .examine_error = dasd_fba_examine_error, + .handle_terminated_request = dasd_fba_handle_terminated_request, .erp_action = dasd_fba_erp_action, .erp_postaction = dasd_fba_erp_postaction, + .handle_unsolicited_interrupt = dasd_fba_handle_unsolicited_interrupt, .build_cp = dasd_fba_build_cp, .free_cp = dasd_fba_free_cp, .dump_sense = dasd_fba_dump_sense, diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 47ba4462708d..aee6565aaf98 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -25,14 +25,15 @@ /* * Allocate and register gendisk structure for device. */ -int -dasd_gendisk_alloc(struct dasd_device *device) +int dasd_gendisk_alloc(struct dasd_block *block) { struct gendisk *gdp; + struct dasd_device *base; int len; /* Make sure the minor for this device exists. */ - if (device->devindex >= DASD_PER_MAJOR) + base = block->base; + if (base->devindex >= DASD_PER_MAJOR) return -EBUSY; gdp = alloc_disk(1 << DASD_PARTN_BITS); @@ -41,9 +42,9 @@ dasd_gendisk_alloc(struct dasd_device *device) /* Initialize gendisk structure. */ gdp->major = DASD_MAJOR; - gdp->first_minor = device->devindex << DASD_PARTN_BITS; + gdp->first_minor = base->devindex << DASD_PARTN_BITS; gdp->fops = &dasd_device_operations; - gdp->driverfs_dev = &device->cdev->dev; + gdp->driverfs_dev = &base->cdev->dev; /* * Set device name. @@ -53,53 +54,51 @@ dasd_gendisk_alloc(struct dasd_device *device) * dasdaaaa - dasdzzzz : 456976 devices, added up = 475252 */ len = sprintf(gdp->disk_name, "dasd"); - if (device->devindex > 25) { - if (device->devindex > 701) { - if (device->devindex > 18277) + if (base->devindex > 25) { + if (base->devindex > 701) { + if (base->devindex > 18277) len += sprintf(gdp->disk_name + len, "%c", - 'a'+(((device->devindex-18278) + 'a'+(((base->devindex-18278) /17576)%26)); len += sprintf(gdp->disk_name + len, "%c", - 'a'+(((device->devindex-702)/676)%26)); + 'a'+(((base->devindex-702)/676)%26)); } len += sprintf(gdp->disk_name + len, "%c", - 'a'+(((device->devindex-26)/26)%26)); + 'a'+(((base->devindex-26)/26)%26)); } - len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26)); + len += sprintf(gdp->disk_name + len, "%c", 'a'+(base->devindex%26)); - if (device->features & DASD_FEATURE_READONLY) + if (block->base->features & DASD_FEATURE_READONLY) set_disk_ro(gdp, 1); - gdp->private_data = device; - gdp->queue = device->request_queue; - device->gdp = gdp; - set_capacity(device->gdp, 0); - add_disk(device->gdp); + gdp->private_data = block; + gdp->queue = block->request_queue; + block->gdp = gdp; + set_capacity(block->gdp, 0); + add_disk(block->gdp); return 0; } /* * Unregister and free gendisk structure for device. */ -void -dasd_gendisk_free(struct dasd_device *device) +void dasd_gendisk_free(struct dasd_block *block) { - if (device->gdp) { - del_gendisk(device->gdp); - device->gdp->queue = NULL; - put_disk(device->gdp); - device->gdp = NULL; + if (block->gdp) { + del_gendisk(block->gdp); + block->gdp->queue = NULL; + put_disk(block->gdp); + block->gdp = NULL; } } /* * Trigger a partition detection. */ -int -dasd_scan_partitions(struct dasd_device * device) +int dasd_scan_partitions(struct dasd_block *block) { struct block_device *bdev; - bdev = bdget_disk(device->gdp, 0); + bdev = bdget_disk(block->gdp, 0); if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0) return -ENODEV; /* @@ -117,7 +116,7 @@ dasd_scan_partitions(struct dasd_device * device) * is why the assignment to device->bdev is done AFTER * the BLKRRPART ioctl. */ - device->bdev = bdev; + block->bdev = bdev; return 0; } @@ -125,8 +124,7 @@ dasd_scan_partitions(struct dasd_device * device) * Remove all inodes in the system for a device, delete the * partitions and make device unusable by setting its size to zero. */ -void -dasd_destroy_partitions(struct dasd_device * device) +void dasd_destroy_partitions(struct dasd_block *block) { /* The two structs have 168/176 byte on 31/64 bit. */ struct blkpg_partition bpart; @@ -137,8 +135,8 @@ dasd_destroy_partitions(struct dasd_device * device) * Get the bdev pointer from the device structure and clear * device->bdev to lower the offline open_count limit again. */ - bdev = device->bdev; - device->bdev = NULL; + bdev = block->bdev; + block->bdev = NULL; /* * See fs/partition/check.c:delete_partition @@ -149,17 +147,16 @@ dasd_destroy_partitions(struct dasd_device * device) memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); barg.data = (void __force __user *) &bpart; barg.op = BLKPG_DEL_PARTITION; - for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) + for (bpart.pno = block->gdp->minors - 1; bpart.pno > 0; bpart.pno--) ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); - invalidate_partition(device->gdp, 0); + invalidate_partition(block->gdp, 0); /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ blkdev_put(bdev); - set_capacity(device->gdp, 0); + set_capacity(block->gdp, 0); } -int -dasd_gendisk_init(void) +int dasd_gendisk_init(void) { int rc; @@ -174,8 +171,7 @@ dasd_gendisk_init(void) return 0; } -void -dasd_gendisk_exit(void) +void dasd_gendisk_exit(void) { unregister_blkdev(DASD_MAJOR, "dasd"); } diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index d427daeef511..44b2984dfbee 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -64,13 +64,7 @@ * SECTION: Type definitions */ struct dasd_device; - -typedef enum { - dasd_era_fatal = -1, /* no chance to recover */ - dasd_era_none = 0, /* don't recover, everything alright */ - dasd_era_msg = 1, /* don't recover, just report... */ - dasd_era_recover = 2 /* recovery action recommended */ -} dasd_era_t; +struct dasd_block; /* BIT DEFINITIONS FOR SENSE DATA */ #define DASD_SENSE_BIT_0 0x80 @@ -151,19 +145,22 @@ do { \ struct dasd_ccw_req { unsigned int magic; /* Eye catcher */ - struct list_head list; /* list_head for request queueing. */ + struct list_head devlist; /* for dasd_device request queue */ + struct list_head blocklist; /* for dasd_block request queue */ /* Where to execute what... */ - struct dasd_device *device; /* device the request is for */ + struct dasd_block *block; /* the originating block device */ + struct dasd_device *memdev; /* the device used to allocate this */ + struct dasd_device *startdev; /* device the request is started on */ struct ccw1 *cpaddr; /* address of channel program */ - char status; /* status of this request */ + char status; /* status of this request */ short retries; /* A retry counter */ unsigned long flags; /* flags of this request */ /* ... and how */ unsigned long starttime; /* jiffies time of request start */ int expires; /* expiration period in jiffies */ - char lpm; /* logical path mask */ + char lpm; /* logical path mask */ void *data; /* pointer to data area */ /* these are important for recovering erroneous requests */ @@ -178,20 +175,27 @@ struct dasd_ccw_req { unsigned long long endclk; /* TOD-clock of request termination */ /* Callback that is called after reaching final status. */ - void (*callback)(struct dasd_ccw_req *, void *data); - void *callback_data; + void (*callback)(struct dasd_ccw_req *, void *data); + void *callback_data; }; /* * dasd_ccw_req -> status can be: */ -#define DASD_CQR_FILLED 0x00 /* request is ready to be processed */ -#define DASD_CQR_QUEUED 0x01 /* request is queued to be processed */ -#define DASD_CQR_IN_IO 0x02 /* request is currently in IO */ -#define DASD_CQR_DONE 0x03 /* request is completed successfully */ -#define DASD_CQR_ERROR 0x04 /* request is completed with error */ -#define DASD_CQR_FAILED 0x05 /* request is finally failed */ -#define DASD_CQR_CLEAR 0x06 /* request is clear pending */ +#define DASD_CQR_FILLED 0x00 /* request is ready to be processed */ +#define DASD_CQR_DONE 0x01 /* request is completed successfully */ +#define DASD_CQR_NEED_ERP 0x02 /* request needs recovery action */ +#define DASD_CQR_IN_ERP 0x03 /* request is in recovery */ +#define DASD_CQR_FAILED 0x04 /* request is finally failed */ +#define DASD_CQR_TERMINATED 0x05 /* request was stopped by driver */ + +#define DASD_CQR_QUEUED 0x80 /* request is queued to be processed */ +#define DASD_CQR_IN_IO 0x81 /* request is currently in IO */ +#define DASD_CQR_ERROR 0x82 /* request is completed with error */ +#define DASD_CQR_CLEAR_PENDING 0x83 /* request is clear pending */ +#define DASD_CQR_CLEARED 0x84 /* request was cleared */ +#define DASD_CQR_SUCCESS 0x85 /* request was successfull */ + /* per dasd_ccw_req flags */ #define DASD_CQR_FLAGS_USE_ERP 0 /* use ERP for this request */ @@ -214,52 +218,71 @@ struct dasd_discipline { struct list_head list; /* used for list of disciplines */ - /* - * Device recognition functions. check_device is used to verify - * the sense data and the information returned by read device - * characteristics. It returns 0 if the discipline can be used - * for the device in question. - * do_analysis is used in the step from device state "basic" to - * state "accept". It returns 0 if the device can be made ready, - * it returns -EMEDIUMTYPE if the device can't be made ready or - * -EAGAIN if do_analysis started a ccw that needs to complete - * before the analysis may be repeated. - */ - int (*check_device)(struct dasd_device *); - int (*do_analysis) (struct dasd_device *); - - /* - * Device operation functions. build_cp creates a ccw chain for - * a block device request, start_io starts the request and - * term_IO cancels it (e.g. in case of a timeout). format_device - * returns a ccw chain to be used to format the device. - */ + /* + * Device recognition functions. check_device is used to verify + * the sense data and the information returned by read device + * characteristics. It returns 0 if the discipline can be used + * for the device in question. uncheck_device is called during + * device shutdown to deregister a device from its discipline. + */ + int (*check_device) (struct dasd_device *); + void (*uncheck_device) (struct dasd_device *); + + /* + * do_analysis is used in the step from device state "basic" to + * state "accept". It returns 0 if the device can be made ready, + * it returns -EMEDIUMTYPE if the device can't be made ready or + * -EAGAIN if do_analysis started a ccw that needs to complete + * before the analysis may be repeated. + */ + int (*do_analysis) (struct dasd_block *); + + /* + * Last things to do when a device is set online, and first things + * when it is set offline. + */ + int (*ready_to_online) (struct dasd_device *); + int (*online_to_ready) (struct dasd_device *); + + /* + * Device operation functions. build_cp creates a ccw chain for + * a block device request, start_io starts the request and + * term_IO cancels it (e.g. in case of a timeout). format_device + * returns a ccw chain to be used to format the device. + * handle_terminated_request allows to examine a cqr and prepare + * it for retry. + */ struct dasd_ccw_req *(*build_cp) (struct dasd_device *, + struct dasd_block *, struct request *); int (*start_IO) (struct dasd_ccw_req *); int (*term_IO) (struct dasd_ccw_req *); + void (*handle_terminated_request) (struct dasd_ccw_req *); struct dasd_ccw_req *(*format_device) (struct dasd_device *, struct format_data_t *); int (*free_cp) (struct dasd_ccw_req *, struct request *); - /* - * Error recovery functions. examine_error() returns a value that - * indicates what to do for an error condition. If examine_error() + + /* + * Error recovery functions. examine_error() returns a value that + * indicates what to do for an error condition. If examine_error() * returns 'dasd_era_recover' erp_action() is called to create a - * special error recovery ccw. erp_postaction() is called after - * an error recovery ccw has finished its execution. dump_sense - * is called for every error condition to print the sense data - * to the console. - */ - dasd_era_t(*examine_error) (struct dasd_ccw_req *, struct irb *); + * special error recovery ccw. erp_postaction() is called after + * an error recovery ccw has finished its execution. dump_sense + * is called for every error condition to print the sense data + * to the console. + */ dasd_erp_fn_t(*erp_action) (struct dasd_ccw_req *); dasd_erp_fn_t(*erp_postaction) (struct dasd_ccw_req *); void (*dump_sense) (struct dasd_device *, struct dasd_ccw_req *, struct irb *); + void (*handle_unsolicited_interrupt) (struct dasd_device *, + struct irb *); + /* i/o control functions. */ - int (*fill_geometry) (struct dasd_device *, struct hd_geometry *); + int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); - int (*ioctl) (struct dasd_device *, unsigned int, void __user *); + int (*ioctl) (struct dasd_block *, unsigned int, void __user *); }; extern struct dasd_discipline *dasd_diag_discipline_pointer; @@ -267,12 +290,18 @@ extern struct dasd_discipline *dasd_diag_discipline_pointer; /* * Unique identifier for dasd device. */ +#define UA_NOT_CONFIGURED 0x00 +#define UA_BASE_DEVICE 0x01 +#define UA_BASE_PAV_ALIAS 0x02 +#define UA_HYPER_PAV_ALIAS 0x03 + struct dasd_uid { - __u8 alias; + __u8 type; char vendor[4]; char serial[15]; __u16 ssid; - __u8 unit_addr; + __u8 real_unit_addr; + __u8 base_unit_addr; }; /* @@ -293,14 +322,9 @@ struct dasd_uid { struct dasd_device { /* Block device stuff. */ - struct gendisk *gdp; - struct request_queue *request_queue; - spinlock_t request_queue_lock; - struct block_device *bdev; + struct dasd_block *block; + unsigned int devindex; - unsigned long blocks; /* size of volume in blocks */ - unsigned int bp_block; /* bytes per block */ - unsigned int s2b_shift; /* log2 (bp_block/512) */ unsigned long flags; /* per device flags */ unsigned short features; /* copy of devmap-features (read-only!) */ @@ -316,9 +340,8 @@ struct dasd_device { int state, target; int stopped; /* device (ccw_device_start) was stopped */ - /* Open and reference count. */ + /* reference count. */ atomic_t ref_count; - atomic_t open_count; /* ccw queue and memory for static ccw/erp buffers. */ struct list_head ccw_queue; @@ -337,20 +360,45 @@ struct dasd_device { struct ccw_device *cdev; + /* hook for alias management */ + struct list_head alias_list; +}; + +struct dasd_block { + /* Block device stuff. */ + struct gendisk *gdp; + struct request_queue *request_queue; + spinlock_t request_queue_lock; + struct block_device *bdev; + atomic_t open_count; + + unsigned long blocks; /* size of volume in blocks */ + unsigned int bp_block; /* bytes per block */ + unsigned int s2b_shift; /* log2 (bp_block/512) */ + + struct dasd_device *base; + struct list_head ccw_queue; + spinlock_t queue_lock; + + atomic_t tasklet_scheduled; + struct tasklet_struct tasklet; + struct timer_list timer; + #ifdef CONFIG_DASD_PROFILE struct dasd_profile_info_t profile; #endif }; + + /* reasons why device (ccw_device_start) was stopped */ #define DASD_STOPPED_NOT_ACC 1 /* not accessible */ #define DASD_STOPPED_QUIESCE 2 /* Quiesced */ #define DASD_STOPPED_PENDING 4 /* long busy */ #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ -#define DASD_STOPPED_DC_EIO 16 /* disconnected, return -EIO */ +#define DASD_STOPPED_SU 16 /* summary unit check handling */ /* per device flags */ -#define DASD_FLAG_DSC_ERROR 2 /* return -EIO when disconnected */ #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ #define DASD_FLAG_EER_SNSS 4 /* A SNSS is required */ #define DASD_FLAG_EER_IN_USE 5 /* A SNSS request is running */ @@ -489,6 +537,9 @@ dasd_kmalloc_set_cda(struct ccw1 *ccw, void *cda, struct dasd_device *device) struct dasd_device *dasd_alloc_device(void); void dasd_free_device(struct dasd_device *); +struct dasd_block *dasd_alloc_block(void); +void dasd_free_block(struct dasd_block *); + void dasd_enable_device(struct dasd_device *); void dasd_set_target_state(struct dasd_device *, int); void dasd_kick_device(struct dasd_device *); @@ -497,18 +548,23 @@ void dasd_add_request_head(struct dasd_ccw_req *); void dasd_add_request_tail(struct dasd_ccw_req *); int dasd_start_IO(struct dasd_ccw_req *); int dasd_term_IO(struct dasd_ccw_req *); -void dasd_schedule_bh(struct dasd_device *); +void dasd_schedule_device_bh(struct dasd_device *); +void dasd_schedule_block_bh(struct dasd_block *); int dasd_sleep_on(struct dasd_ccw_req *); int dasd_sleep_on_immediatly(struct dasd_ccw_req *); int dasd_sleep_on_interruptible(struct dasd_ccw_req *); -void dasd_set_timer(struct dasd_device *, int); -void dasd_clear_timer(struct dasd_device *); +void dasd_device_set_timer(struct dasd_device *, int); +void dasd_device_clear_timer(struct dasd_device *); +void dasd_block_set_timer(struct dasd_block *, int); +void dasd_block_clear_timer(struct dasd_block *); int dasd_cancel_req(struct dasd_ccw_req *); +int dasd_flush_device_queue(struct dasd_device *); int dasd_generic_probe (struct ccw_device *, struct dasd_discipline *); void dasd_generic_remove (struct ccw_device *cdev); int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); +void dasd_generic_handle_state_change(struct dasd_device *); int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); @@ -542,10 +598,10 @@ int dasd_busid_known(char *); /* externals in dasd_gendisk.c */ int dasd_gendisk_init(void); void dasd_gendisk_exit(void); -int dasd_gendisk_alloc(struct dasd_device *); -void dasd_gendisk_free(struct dasd_device *); -int dasd_scan_partitions(struct dasd_device *); -void dasd_destroy_partitions(struct dasd_device *); +int dasd_gendisk_alloc(struct dasd_block *); +void dasd_gendisk_free(struct dasd_block *); +int dasd_scan_partitions(struct dasd_block *); +void dasd_destroy_partitions(struct dasd_block *); /* externals in dasd_ioctl.c */ int dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -563,20 +619,9 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int, void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_log_sense(struct dasd_ccw_req *, struct irb *); -/* externals in dasd_3370_erp.c */ -dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *); - /* externals in dasd_3990_erp.c */ -dasd_era_t dasd_3990_erp_examine(struct dasd_ccw_req *, struct irb *); struct dasd_ccw_req *dasd_3990_erp_action(struct dasd_ccw_req *); -/* externals in dasd_9336_erp.c */ -dasd_era_t dasd_9336_erp_examine(struct dasd_ccw_req *, struct irb *); - -/* externals in dasd_9336_erp.c */ -dasd_era_t dasd_9343_erp_examine(struct dasd_ccw_req *, struct irb *); -struct dasd_ccw_req *dasd_9343_erp_action(struct dasd_ccw_req *); - /* externals in dasd_eer.c */ #ifdef CONFIG_DASD_EER int dasd_eer_init(void); diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 672eb0a3dd0b..91a64630cb0f 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -38,15 +38,15 @@ dasd_ioctl_api_version(void __user *argp) static int dasd_ioctl_enable(struct block_device *bdev) { - struct dasd_device *device = bdev->bd_disk->private_data; + struct dasd_block *block = bdev->bd_disk->private_data; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - dasd_enable_device(device); + dasd_enable_device(block->base); /* Formatting the dasd device can change the capacity. */ mutex_lock(&bdev->bd_mutex); - i_size_write(bdev->bd_inode, (loff_t)get_capacity(device->gdp) << 9); + i_size_write(bdev->bd_inode, (loff_t)get_capacity(block->gdp) << 9); mutex_unlock(&bdev->bd_mutex); return 0; } @@ -58,7 +58,7 @@ dasd_ioctl_enable(struct block_device *bdev) static int dasd_ioctl_disable(struct block_device *bdev) { - struct dasd_device *device = bdev->bd_disk->private_data; + struct dasd_block *block = bdev->bd_disk->private_data; if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -71,7 +71,7 @@ dasd_ioctl_disable(struct block_device *bdev) * using the BIODASDFMT ioctl. Therefore the correct state for the * device is DASD_STATE_BASIC that allows to do basic i/o. */ - dasd_set_target_state(device, DASD_STATE_BASIC); + dasd_set_target_state(block->base, DASD_STATE_BASIC); /* * Set i_size to zero, since read, write, etc. check against this * value. @@ -85,19 +85,19 @@ dasd_ioctl_disable(struct block_device *bdev) /* * Quiesce device. */ -static int -dasd_ioctl_quiesce(struct dasd_device *device) +static int dasd_ioctl_quiesce(struct dasd_block *block) { unsigned long flags; + struct dasd_device *base; + base = block->base; if (!capable (CAP_SYS_ADMIN)) return -EACCES; - DEV_MESSAGE (KERN_DEBUG, device, "%s", - "Quiesce IO on device"); - spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - device->stopped |= DASD_STOPPED_QUIESCE; - spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + DEV_MESSAGE(KERN_DEBUG, base, "%s", "Quiesce IO on device"); + spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); + base->stopped |= DASD_STOPPED_QUIESCE; + spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); return 0; } @@ -105,22 +105,21 @@ dasd_ioctl_quiesce(struct dasd_device *device) /* * Quiesce device. */ -static int -dasd_ioctl_resume(struct dasd_device *device) +static int dasd_ioctl_resume(struct dasd_block *block) { unsigned long flags; + struct dasd_device *base; + base = block->base; if (!capable (CAP_SYS_ADMIN)) return -EACCES; - DEV_MESSAGE (KERN_DEBUG, device, "%s", - "resume IO on device"); - - spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - device->stopped &= ~DASD_STOPPED_QUIESCE; - spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); + DEV_MESSAGE(KERN_DEBUG, base, "%s", "resume IO on device"); + spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); + base->stopped &= ~DASD_STOPPED_QUIESCE; + spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); - dasd_schedule_bh (device); + dasd_schedule_block_bh(block); return 0; } @@ -130,22 +129,23 @@ dasd_ioctl_resume(struct dasd_device *device) * commands to format a single unit of the device. In terms of the ECKD * devices this means CCWs are generated to format a single track. */ -static int -dasd_format(struct dasd_device * device, struct format_data_t * fdata) +static int dasd_format(struct dasd_block *block, struct format_data_t *fdata) { struct dasd_ccw_req *cqr; + struct dasd_device *base; int rc; - if (device->discipline->format_device == NULL) + base = block->base; + if (base->discipline->format_device == NULL) return -EPERM; - if (device->state != DASD_STATE_BASIC) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + if (base->state != DASD_STATE_BASIC) { + DEV_MESSAGE(KERN_WARNING, base, "%s", "dasd_format: device is not disabled! "); return -EBUSY; } - DBF_DEV_EVENT(DBF_NOTICE, device, + DBF_DEV_EVENT(DBF_NOTICE, base, "formatting units %d to %d (%d B blocks) flags %d", fdata->start_unit, fdata->stop_unit, fdata->blksize, fdata->intensity); @@ -156,20 +156,20 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata) * enabling the device later. */ if (fdata->start_unit == 0) { - struct block_device *bdev = bdget_disk(device->gdp, 0); + struct block_device *bdev = bdget_disk(block->gdp, 0); bdev->bd_inode->i_blkbits = blksize_bits(fdata->blksize); bdput(bdev); } while (fdata->start_unit <= fdata->stop_unit) { - cqr = device->discipline->format_device(device, fdata); + cqr = base->discipline->format_device(base, fdata); if (IS_ERR(cqr)) return PTR_ERR(cqr); rc = dasd_sleep_on_interruptible(cqr); - dasd_sfree_request(cqr, cqr->device); + dasd_sfree_request(cqr, cqr->memdev); if (rc) { if (rc != -ERESTARTSYS) - DEV_MESSAGE(KERN_ERR, device, + DEV_MESSAGE(KERN_ERR, base, " Formatting of unit %d failed " "with rc = %d", fdata->start_unit, rc); @@ -186,7 +186,7 @@ dasd_format(struct dasd_device * device, struct format_data_t * fdata) static int dasd_ioctl_format(struct block_device *bdev, void __user *argp) { - struct dasd_device *device = bdev->bd_disk->private_data; + struct dasd_block *block = bdev->bd_disk->private_data; struct format_data_t fdata; if (!capable(CAP_SYS_ADMIN)) @@ -194,51 +194,47 @@ dasd_ioctl_format(struct block_device *bdev, void __user *argp) if (!argp) return -EINVAL; - if (device->features & DASD_FEATURE_READONLY) + if (block->base->features & DASD_FEATURE_READONLY) return -EROFS; if (copy_from_user(&fdata, argp, sizeof(struct format_data_t))) return -EFAULT; if (bdev != bdev->bd_contains) { - DEV_MESSAGE(KERN_WARNING, device, "%s", + DEV_MESSAGE(KERN_WARNING, block->base, "%s", "Cannot low-level format a partition"); return -EINVAL; } - return dasd_format(device, &fdata); + return dasd_format(block, &fdata); } #ifdef CONFIG_DASD_PROFILE /* * Reset device profile information */ -static int -dasd_ioctl_reset_profile(struct dasd_device *device) +static int dasd_ioctl_reset_profile(struct dasd_block *block) { - memset(&device->profile, 0, sizeof (struct dasd_profile_info_t)); + memset(&block->profile, 0, sizeof(struct dasd_profile_info_t)); return 0; } /* * Return device profile information */ -static int -dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp) +static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) { if (dasd_profile_level == DASD_PROFILE_OFF) return -EIO; - if (copy_to_user(argp, &device->profile, - sizeof (struct dasd_profile_info_t))) + if (copy_to_user(argp, &block->profile, + sizeof(struct dasd_profile_info_t))) return -EFAULT; return 0; } #else -static int -dasd_ioctl_reset_profile(struct dasd_device *device) +static int dasd_ioctl_reset_profile(struct dasd_block *block) { return -ENOSYS; } -static int -dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp) +static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp) { return -ENOSYS; } @@ -247,87 +243,88 @@ dasd_ioctl_read_profile(struct dasd_device *device, void __user *argp) /* * Return dasd information. Used for BIODASDINFO and BIODASDINFO2. */ -static int -dasd_ioctl_information(struct dasd_device *device, - unsigned int cmd, void __user *argp) +static int dasd_ioctl_information(struct dasd_block *block, + unsigned int cmd, void __user *argp) { struct dasd_information2_t *dasd_info; unsigned long flags; int rc; + struct dasd_device *base; struct ccw_device *cdev; struct ccw_dev_id dev_id; - if (!device->discipline->fill_info) + base = block->base; + if (!base->discipline->fill_info) return -EINVAL; dasd_info = kzalloc(sizeof(struct dasd_information2_t), GFP_KERNEL); if (dasd_info == NULL) return -ENOMEM; - rc = device->discipline->fill_info(device, dasd_info); + rc = base->discipline->fill_info(base, dasd_info); if (rc) { kfree(dasd_info); return rc; } - cdev = device->cdev; + cdev = base->cdev; ccw_device_get_id(cdev, &dev_id); dasd_info->devno = dev_id.devno; - dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev); + dasd_info->schid = _ccw_device_get_subchannel_number(base->cdev); dasd_info->cu_type = cdev->id.cu_type; dasd_info->cu_model = cdev->id.cu_model; dasd_info->dev_type = cdev->id.dev_type; dasd_info->dev_model = cdev->id.dev_model; - dasd_info->status = device->state; + dasd_info->status = base->state; /* * The open_count is increased for every opener, that includes * the blkdev_get in dasd_scan_partitions. * This must be hidden from user-space. */ - dasd_info->open_count = atomic_read(&device->open_count); - if (!device->bdev) + dasd_info->open_count = atomic_read(&block->open_count); + if (!block->bdev) dasd_info->open_count++; /* * check if device is really formatted * LDL / CDL was returned by 'fill_info' */ - if ((device->state < DASD_STATE_READY) || - (dasd_check_blocksize(device->bp_block))) + if ((base->state < DASD_STATE_READY) || + (dasd_check_blocksize(block->bp_block))) dasd_info->format = DASD_FORMAT_NONE; dasd_info->features |= - ((device->features & DASD_FEATURE_READONLY) != 0); + ((base->features & DASD_FEATURE_READONLY) != 0); - if (device->discipline) - memcpy(dasd_info->type, device->discipline->name, 4); + if (base->discipline) + memcpy(dasd_info->type, base->discipline->name, 4); else memcpy(dasd_info->type, "none", 4); - if (device->request_queue->request_fn) { + if (block->request_queue->request_fn) { struct list_head *l; #ifdef DASD_EXTENDED_PROFILING { struct list_head *l; - spin_lock_irqsave(&device->lock, flags); - list_for_each(l, &device->request_queue->queue_head) + spin_lock_irqsave(&block->lock, flags); + list_for_each(l, &block->request_queue->queue_head) dasd_info->req_queue_len++; - spin_unlock_irqrestore(&device->lock, flags); + spin_unlock_irqrestore(&block->lock, flags); } #endif /* DASD_EXTENDED_PROFILING */ - spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - list_for_each(l, &device->ccw_queue) + spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); + list_for_each(l, &base->ccw_queue) dasd_info->chanq_len++; - spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), + spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); } rc = 0; if (copy_to_user(argp, dasd_info, ((cmd == (unsigned int) BIODASDINFO2) ? - sizeof (struct dasd_information2_t) : - sizeof (struct dasd_information_t)))) + sizeof(struct dasd_information2_t) : + sizeof(struct dasd_information_t)))) rc = -EFAULT; kfree(dasd_info); return rc; @@ -339,7 +336,7 @@ dasd_ioctl_information(struct dasd_device *device, static int dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) { - struct dasd_device *device = bdev->bd_disk->private_data; + struct dasd_block *block = bdev->bd_disk->private_data; int intval; if (!capable(CAP_SYS_ADMIN)) @@ -351,11 +348,10 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp) return -EFAULT; set_disk_ro(bdev->bd_disk, intval); - return dasd_set_feature(device->cdev, DASD_FEATURE_READONLY, intval); + return dasd_set_feature(block->base->cdev, DASD_FEATURE_READONLY, intval); } -static int -dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd, +static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, unsigned long arg) { struct cmbdata __user *argp = (void __user *) arg; @@ -363,7 +359,7 @@ dasd_ioctl_readall_cmb(struct dasd_device *device, unsigned int cmd, struct cmbdata data; int ret; - ret = cmf_readall(device->cdev, &data); + ret = cmf_readall(block->base->cdev, &data); if (!ret && copy_to_user(argp, &data, min(size, sizeof(*argp)))) return -EFAULT; return ret; @@ -374,10 +370,10 @@ dasd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct block_device *bdev = inode->i_bdev; - struct dasd_device *device = bdev->bd_disk->private_data; + struct dasd_block *block = bdev->bd_disk->private_data; void __user *argp = (void __user *)arg; - if (!device) + if (!block) return -ENODEV; if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { @@ -391,33 +387,33 @@ dasd_ioctl(struct inode *inode, struct file *file, case BIODASDENABLE: return dasd_ioctl_enable(bdev); case BIODASDQUIESCE: - return dasd_ioctl_quiesce(device); + return dasd_ioctl_quiesce(block); case BIODASDRESUME: - return dasd_ioctl_resume(device); + return dasd_ioctl_resume(block); case BIODASDFMT: return dasd_ioctl_format(bdev, argp); case BIODASDINFO: - return dasd_ioctl_information(device, cmd, argp); + return dasd_ioctl_information(block, cmd, argp); case BIODASDINFO2: - return dasd_ioctl_information(device, cmd, argp); + return dasd_ioctl_information(block, cmd, argp); case BIODASDPRRD: - return dasd_ioctl_read_profile(device, argp); + return dasd_ioctl_read_profile(block, argp); case BIODASDPRRST: - return dasd_ioctl_reset_profile(device); + return dasd_ioctl_reset_profile(block); case BLKROSET: return dasd_ioctl_set_ro(bdev, argp); case DASDAPIVER: return dasd_ioctl_api_version(argp); case BIODASDCMFENABLE: - return enable_cmf(device->cdev); + return enable_cmf(block->base->cdev); case BIODASDCMFDISABLE: - return disable_cmf(device->cdev); + return disable_cmf(block->base->cdev); case BIODASDREADALLCMB: - return dasd_ioctl_readall_cmb(device, cmd, arg); + return dasd_ioctl_readall_cmb(block, cmd, arg); default: /* if the discipline has an ioctl method try it. */ - if (device->discipline->ioctl) { - int rval = device->discipline->ioctl(device, cmd, argp); + if (block->base->discipline->ioctl) { + int rval = block->base->discipline->ioctl(block, cmd, argp); if (rval != -ENOIOCTLCMD) return rval; } diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index ac7e8ef504cb..28a86f070048 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -54,11 +54,16 @@ static int dasd_devices_show(struct seq_file *m, void *v) { struct dasd_device *device; + struct dasd_block *block; char *substr; device = dasd_device_from_devindex((unsigned long) v - 1); if (IS_ERR(device)) return 0; + if (device->block) + block = device->block; + else + return 0; /* Print device number. */ seq_printf(m, "%s", device->cdev->dev.bus_id); /* Print discipline string. */ @@ -67,14 +72,14 @@ dasd_devices_show(struct seq_file *m, void *v) else seq_printf(m, "(none)"); /* Print kdev. */ - if (device->gdp) + if (block->gdp) seq_printf(m, " at (%3d:%6d)", - device->gdp->major, device->gdp->first_minor); + block->gdp->major, block->gdp->first_minor); else seq_printf(m, " at (???:??????)"); /* Print device name. */ - if (device->gdp) - seq_printf(m, " is %-8s", device->gdp->disk_name); + if (block->gdp) + seq_printf(m, " is %-8s", block->gdp->disk_name); else seq_printf(m, " is ????????"); /* Print devices features. */ @@ -100,14 +105,14 @@ dasd_devices_show(struct seq_file *m, void *v) case DASD_STATE_READY: case DASD_STATE_ONLINE: seq_printf(m, "active "); - if (dasd_check_blocksize(device->bp_block)) + if (dasd_check_blocksize(block->bp_block)) seq_printf(m, "n/f "); else seq_printf(m, "at blocksize: %d, %ld blocks, %ld MB", - device->bp_block, device->blocks, - ((device->bp_block >> 9) * - device->blocks) >> 11); + block->bp_block, block->blocks, + ((block->bp_block >> 9) * + block->blocks) >> 11); break; default: seq_printf(m, "no stat"); @@ -137,7 +142,7 @@ static void dasd_devices_stop(struct seq_file *m, void *v) { } -static struct seq_operations dasd_devices_seq_ops = { +static const struct seq_operations dasd_devices_seq_ops = { .start = dasd_devices_start, .next = dasd_devices_next, .stop = dasd_devices_stop, diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 15a5789b7734..7779bfce1c31 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -82,7 +82,7 @@ struct dcssblk_dev_info { struct request_queue *dcssblk_queue; }; -static struct list_head dcssblk_devices = LIST_HEAD_INIT(dcssblk_devices); +static LIST_HEAD(dcssblk_devices); static struct rw_semaphore dcssblk_devices_sem; /* diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 130de19916f2..7e73e39a1741 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -3,7 +3,7 @@ # obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ - sclp_info.o sclp_config.o sclp_chp.o + sclp_cmd.o sclp_config.o sclp_cpi_sys.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 20442fbf9346..a86c0534cd49 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -295,7 +295,7 @@ module_init(mon_init); module_exit(mon_exit); module_param_named(max_bufs, mon_max_bufs, int, 0644); -MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers" +MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers " "that can be active at one time"); MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>"); diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 8d1c64a24dec..0d98f1ff2edd 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -66,7 +66,7 @@ struct raw3270 { static DEFINE_MUTEX(raw3270_mutex); /* List of 3270 devices. */ -static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices); +static LIST_HEAD(raw3270_devices); /* * Flag to indicate if the driver has been registered. Some operations @@ -1210,7 +1210,7 @@ struct raw3270_notifier { void (*notifier)(int, int); }; -static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier); +static LIST_HEAD(raw3270_notifier); int raw3270_register_notifier(void (*notifier)(int, int)) { diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index c7318a125852..aa8186d18aee 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -56,8 +56,6 @@ typedef unsigned int sclp_cmdw_t; #define SCLP_CMDW_READ_EVENT_DATA 0x00770005 #define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005 #define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 -#define SCLP_CMDW_READ_SCP_INFO 0x00020001 -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define GDS_ID_MDSMU 0x1310 #define GDS_ID_MDSROUTEINFO 0x1311 @@ -83,6 +81,8 @@ extern u64 sclp_facilities; #define SCLP_HAS_CHP_INFO (sclp_facilities & 0x8000000000000000ULL) #define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) +#define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL) +#define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL) struct gds_subvector { u8 length; diff --git a/drivers/s390/char/sclp_chp.c b/drivers/s390/char/sclp_chp.c deleted file mode 100644 index c68f5e7e63a0..000000000000 --- a/drivers/s390/char/sclp_chp.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - * drivers/s390/char/sclp_chp.c - * - * Copyright IBM Corp. 2007 - * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> - */ - -#include <linux/types.h> -#include <linux/gfp.h> -#include <linux/errno.h> -#include <linux/completion.h> -#include <asm/sclp.h> -#include <asm/chpid.h> - -#include "sclp.h" - -#define TAG "sclp_chp: " - -#define SCLP_CMDW_CONFIGURE_CHANNEL_PATH 0x000f0001 -#define SCLP_CMDW_DECONFIGURE_CHANNEL_PATH 0x000e0001 -#define SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION 0x00030001 - -static inline sclp_cmdw_t get_configure_cmdw(struct chp_id chpid) -{ - return SCLP_CMDW_CONFIGURE_CHANNEL_PATH | chpid.id << 8; -} - -static inline sclp_cmdw_t get_deconfigure_cmdw(struct chp_id chpid) -{ - return SCLP_CMDW_DECONFIGURE_CHANNEL_PATH | chpid.id << 8; -} - -static void chp_callback(struct sclp_req *req, void *data) -{ - struct completion *completion = data; - - complete(completion); -} - -struct chp_cfg_sccb { - struct sccb_header header; - u8 ccm; - u8 reserved[6]; - u8 cssid; -} __attribute__((packed)); - -struct chp_cfg_data { - struct chp_cfg_sccb sccb; - struct sclp_req req; - struct completion completion; -} __attribute__((packed)); - -static int do_configure(sclp_cmdw_t cmd) -{ - struct chp_cfg_data *data; - int rc; - - if (!SCLP_HAS_CHP_RECONFIG) - return -EOPNOTSUPP; - /* Prepare sccb. */ - data = (struct chp_cfg_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!data) - return -ENOMEM; - data->sccb.header.length = sizeof(struct chp_cfg_sccb); - data->req.command = cmd; - data->req.sccb = &(data->sccb); - data->req.status = SCLP_REQ_FILLED; - data->req.callback = chp_callback; - data->req.callback_data = &(data->completion); - init_completion(&data->completion); - - /* Perform sclp request. */ - rc = sclp_add_request(&(data->req)); - if (rc) - goto out; - wait_for_completion(&data->completion); - - /* Check response .*/ - if (data->req.status != SCLP_REQ_DONE) { - printk(KERN_WARNING TAG "configure channel-path request failed " - "(status=0x%02x)\n", data->req.status); - rc = -EIO; - goto out; - } - switch (data->sccb.header.response_code) { - case 0x0020: - case 0x0120: - case 0x0440: - case 0x0450: - break; - default: - printk(KERN_WARNING TAG "configure channel-path failed " - "(cmd=0x%08x, response=0x%04x)\n", cmd, - data->sccb.header.response_code); - rc = -EIO; - break; - } -out: - free_page((unsigned long) data); - - return rc; -} - -/** - * sclp_chp_configure - perform configure channel-path sclp command - * @chpid: channel-path ID - * - * Perform configure channel-path command sclp command for specified chpid. - * Return 0 after command successfully finished, non-zero otherwise. - */ -int sclp_chp_configure(struct chp_id chpid) -{ - return do_configure(get_configure_cmdw(chpid)); -} - -/** - * sclp_chp_deconfigure - perform deconfigure channel-path sclp command - * @chpid: channel-path ID - * - * Perform deconfigure channel-path command sclp command for specified chpid - * and wait for completion. On success return 0. Return non-zero otherwise. - */ -int sclp_chp_deconfigure(struct chp_id chpid) -{ - return do_configure(get_deconfigure_cmdw(chpid)); -} - -struct chp_info_sccb { - struct sccb_header header; - u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; - u8 standby[SCLP_CHP_INFO_MASK_SIZE]; - u8 configured[SCLP_CHP_INFO_MASK_SIZE]; - u8 ccm; - u8 reserved[6]; - u8 cssid; -} __attribute__((packed)); - -struct chp_info_data { - struct chp_info_sccb sccb; - struct sclp_req req; - struct completion completion; -} __attribute__((packed)); - -/** - * sclp_chp_read_info - perform read channel-path information sclp command - * @info: resulting channel-path information data - * - * Perform read channel-path information sclp command and wait for completion. - * On success, store channel-path information in @info and return 0. Return - * non-zero otherwise. - */ -int sclp_chp_read_info(struct sclp_chp_info *info) -{ - struct chp_info_data *data; - int rc; - - if (!SCLP_HAS_CHP_INFO) - return -EOPNOTSUPP; - /* Prepare sccb. */ - data = (struct chp_info_data *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!data) - return -ENOMEM; - data->sccb.header.length = sizeof(struct chp_info_sccb); - data->req.command = SCLP_CMDW_READ_CHANNEL_PATH_INFORMATION; - data->req.sccb = &(data->sccb); - data->req.status = SCLP_REQ_FILLED; - data->req.callback = chp_callback; - data->req.callback_data = &(data->completion); - init_completion(&data->completion); - - /* Perform sclp request. */ - rc = sclp_add_request(&(data->req)); - if (rc) - goto out; - wait_for_completion(&data->completion); - - /* Check response .*/ - if (data->req.status != SCLP_REQ_DONE) { - printk(KERN_WARNING TAG "read channel-path info request failed " - "(status=0x%02x)\n", data->req.status); - rc = -EIO; - goto out; - } - if (data->sccb.header.response_code != 0x0010) { - printk(KERN_WARNING TAG "read channel-path info failed " - "(response=0x%04x)\n", data->sccb.header.response_code); - rc = -EIO; - goto out; - } - memcpy(info->recognized, data->sccb.recognized, - SCLP_CHP_INFO_MASK_SIZE); - memcpy(info->standby, data->sccb.standby, - SCLP_CHP_INFO_MASK_SIZE); - memcpy(info->configured, data->sccb.configured, - SCLP_CHP_INFO_MASK_SIZE); -out: - free_page((unsigned long) data); - - return rc; -} diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c new file mode 100644 index 000000000000..b5c23396f8fe --- /dev/null +++ b/drivers/s390/char/sclp_cmd.c @@ -0,0 +1,398 @@ +/* + * drivers/s390/char/sclp_cmd.c + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, + * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> + */ + +#include <linux/completion.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <asm/chpid.h> +#include <asm/sclp.h> +#include "sclp.h" + +#define TAG "sclp_cmd: " + +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 + +struct read_info_sccb { + struct sccb_header header; /* 0-7 */ + u16 rnmax; /* 8-9 */ + u8 rnsize; /* 10 */ + u8 _reserved0[24 - 11]; /* 11-15 */ + u8 loadparm[8]; /* 24-31 */ + u8 _reserved1[48 - 32]; /* 32-47 */ + u64 facilities; /* 48-55 */ + u8 _reserved2[84 - 56]; /* 56-83 */ + u8 fac84; /* 84 */ + u8 _reserved3[91 - 85]; /* 85-90 */ + u8 flags; /* 91 */ + u8 _reserved4[100 - 92]; /* 92-99 */ + u32 rnsize2; /* 100-103 */ + u64 rnmax2; /* 104-111 */ + u8 _reserved5[4096 - 112]; /* 112-4095 */ +} __attribute__((packed, aligned(PAGE_SIZE))); + +static struct read_info_sccb __initdata early_read_info_sccb; +static int __initdata early_read_info_sccb_valid; + +u64 sclp_facilities; +static u8 sclp_fac84; + +static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) +{ + int rc; + + __ctl_set_bit(0, 9); + rc = sclp_service_call(cmd, sccb); + if (rc) + goto out; + __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | + PSW_MASK_WAIT | PSW_DEFAULT_KEY); + local_irq_disable(); +out: + /* Contents of the sccb might have changed. */ + barrier(); + __ctl_clear_bit(0, 9); + return rc; +} + +void __init sclp_read_info_early(void) +{ + int rc; + int i; + struct read_info_sccb *sccb; + sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, + SCLP_CMDW_READ_SCP_INFO}; + + sccb = &early_read_info_sccb; + for (i = 0; i < ARRAY_SIZE(commands); i++) { + do { + memset(sccb, 0, sizeof(*sccb)); + sccb->header.length = sizeof(*sccb); + sccb->header.control_mask[2] = 0x80; + rc = sclp_cmd_sync_early(commands[i], sccb); + } while (rc == -EBUSY); + + if (rc) + break; + if (sccb->header.response_code == 0x10) { + early_read_info_sccb_valid = 1; + break; + } + if (sccb->header.response_code != 0x1f0) + break; + } +} + +void __init sclp_facilities_detect(void) +{ + if (!early_read_info_sccb_valid) + return; + sclp_facilities = early_read_info_sccb.facilities; + sclp_fac84 = early_read_info_sccb.fac84; +} + +unsigned long long __init sclp_memory_detect(void) +{ + unsigned long long memsize; + struct read_info_sccb *sccb; + + if (!early_read_info_sccb_valid) + return 0; + sccb = &early_read_info_sccb; + if (sccb->rnsize) + memsize = sccb->rnsize << 20; + else + memsize = sccb->rnsize2 << 20; + if (sccb->rnmax) + memsize *= sccb->rnmax; + else + memsize *= sccb->rnmax2; + return memsize; +} + +/* + * This function will be called after sclp_memory_detect(), which gets called + * early from early.c code. Therefore the sccb should have valid contents. + */ +void __init sclp_get_ipl_info(struct sclp_ipl_info *info) +{ + struct read_info_sccb *sccb; + + if (!early_read_info_sccb_valid) + return; + sccb = &early_read_info_sccb; + info->is_valid = 1; + if (sccb->flags & 0x2) + info->has_dump = 1; + memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); +} + +static void sclp_sync_callback(struct sclp_req *req, void *data) +{ + struct completion *completion = data; + + complete(completion); +} + +static int do_sync_request(sclp_cmdw_t cmd, void *sccb) +{ + struct completion completion; + struct sclp_req *request; + int rc; + + request = kzalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + request->command = cmd; + request->sccb = sccb; + request->status = SCLP_REQ_FILLED; + request->callback = sclp_sync_callback; + request->callback_data = &completion; + init_completion(&completion); + + /* Perform sclp request. */ + rc = sclp_add_request(request); + if (rc) + goto out; + wait_for_completion(&completion); + + /* Check response. */ + if (request->status != SCLP_REQ_DONE) { + printk(KERN_WARNING TAG "sync request failed " + "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status); + rc = -EIO; + } +out: + kfree(request); + return rc; +} + +/* + * CPU configuration related functions. + */ + +#define SCLP_CMDW_READ_CPU_INFO 0x00010001 +#define SCLP_CMDW_CONFIGURE_CPU 0x00110001 +#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 + +struct read_cpu_info_sccb { + struct sccb_header header; + u16 nr_configured; + u16 offset_configured; + u16 nr_standby; + u16 offset_standby; + u8 reserved[4096 - 16]; +} __attribute__((packed, aligned(PAGE_SIZE))); + +static void sclp_fill_cpu_info(struct sclp_cpu_info *info, + struct read_cpu_info_sccb *sccb) +{ + char *page = (char *) sccb; + + memset(info, 0, sizeof(*info)); + info->configured = sccb->nr_configured; + info->standby = sccb->nr_standby; + info->combined = sccb->nr_configured + sccb->nr_standby; + info->has_cpu_type = sclp_fac84 & 0x1; + memcpy(&info->cpu, page + sccb->offset_configured, + info->combined * sizeof(struct sclp_cpu_entry)); +} + +int sclp_get_cpu_info(struct sclp_cpu_info *info) +{ + int rc; + struct read_cpu_info_sccb *sccb; + + if (!SCLP_HAS_CPU_INFO) + return -EOPNOTSUPP; + sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + return -ENOMEM; + sccb->header.length = sizeof(*sccb); + rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb); + if (rc) + goto out; + if (sccb->header.response_code != 0x0010) { + printk(KERN_WARNING TAG "readcpuinfo failed " + "(response=0x%04x)\n", sccb->header.response_code); + rc = -EIO; + goto out; + } + sclp_fill_cpu_info(info, sccb); +out: + free_page((unsigned long) sccb); + return rc; +} + +struct cpu_configure_sccb { + struct sccb_header header; +} __attribute__((packed, aligned(8))); + +static int do_cpu_configure(sclp_cmdw_t cmd) +{ + struct cpu_configure_sccb *sccb; + int rc; + + if (!SCLP_HAS_CPU_RECONFIG) + return -EOPNOTSUPP; + /* + * This is not going to cross a page boundary since we force + * kmalloc to have a minimum alignment of 8 bytes on s390. + */ + sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA); + if (!sccb) + return -ENOMEM; + sccb->header.length = sizeof(*sccb); + rc = do_sync_request(cmd, sccb); + if (rc) + goto out; + switch (sccb->header.response_code) { + case 0x0020: + case 0x0120: + break; + default: + printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, " + "response=0x%04x)\n", cmd, sccb->header.response_code); + rc = -EIO; + break; + } +out: + kfree(sccb); + return rc; +} + +int sclp_cpu_configure(u8 cpu) +{ + return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8); +} + +int sclp_cpu_deconfigure(u8 cpu) +{ + return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8); +} + +/* + * Channel path configuration related functions. + */ + +#define SCLP_CMDW_CONFIGURE_CHPATH 0x000f0001 +#define SCLP_CMDW_DECONFIGURE_CHPATH 0x000e0001 +#define SCLP_CMDW_READ_CHPATH_INFORMATION 0x00030001 + +struct chp_cfg_sccb { + struct sccb_header header; + u8 ccm; + u8 reserved[6]; + u8 cssid; +} __attribute__((packed)); + +static int do_chp_configure(sclp_cmdw_t cmd) +{ + struct chp_cfg_sccb *sccb; + int rc; + + if (!SCLP_HAS_CHP_RECONFIG) + return -EOPNOTSUPP; + /* Prepare sccb. */ + sccb = (struct chp_cfg_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + return -ENOMEM; + sccb->header.length = sizeof(*sccb); + rc = do_sync_request(cmd, sccb); + if (rc) + goto out; + switch (sccb->header.response_code) { + case 0x0020: + case 0x0120: + case 0x0440: + case 0x0450: + break; + default: + printk(KERN_WARNING TAG "configure channel-path failed " + "(cmd=0x%08x, response=0x%04x)\n", cmd, + sccb->header.response_code); + rc = -EIO; + break; + } +out: + free_page((unsigned long) sccb); + return rc; +} + +/** + * sclp_chp_configure - perform configure channel-path sclp command + * @chpid: channel-path ID + * + * Perform configure channel-path command sclp command for specified chpid. + * Return 0 after command successfully finished, non-zero otherwise. + */ +int sclp_chp_configure(struct chp_id chpid) +{ + return do_chp_configure(SCLP_CMDW_CONFIGURE_CHPATH | chpid.id << 8); +} + +/** + * sclp_chp_deconfigure - perform deconfigure channel-path sclp command + * @chpid: channel-path ID + * + * Perform deconfigure channel-path command sclp command for specified chpid + * and wait for completion. On success return 0. Return non-zero otherwise. + */ +int sclp_chp_deconfigure(struct chp_id chpid) +{ + return do_chp_configure(SCLP_CMDW_DECONFIGURE_CHPATH | chpid.id << 8); +} + +struct chp_info_sccb { + struct sccb_header header; + u8 recognized[SCLP_CHP_INFO_MASK_SIZE]; + u8 standby[SCLP_CHP_INFO_MASK_SIZE]; + u8 configured[SCLP_CHP_INFO_MASK_SIZE]; + u8 ccm; + u8 reserved[6]; + u8 cssid; +} __attribute__((packed)); + +/** + * sclp_chp_read_info - perform read channel-path information sclp command + * @info: resulting channel-path information data + * + * Perform read channel-path information sclp command and wait for completion. + * On success, store channel-path information in @info and return 0. Return + * non-zero otherwise. + */ +int sclp_chp_read_info(struct sclp_chp_info *info) +{ + struct chp_info_sccb *sccb; + int rc; + + if (!SCLP_HAS_CHP_INFO) + return -EOPNOTSUPP; + /* Prepare sccb. */ + sccb = (struct chp_info_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + return -ENOMEM; + sccb->header.length = sizeof(*sccb); + rc = do_sync_request(SCLP_CMDW_READ_CHPATH_INFORMATION, sccb); + if (rc) + goto out; + if (sccb->header.response_code != 0x0010) { + printk(KERN_WARNING TAG "read channel-path info failed " + "(response=0x%04x)\n", sccb->header.response_code); + rc = -EIO; + goto out; + } + memcpy(info->recognized, sccb->recognized, SCLP_CHP_INFO_MASK_SIZE); + memcpy(info->standby, sccb->standby, SCLP_CHP_INFO_MASK_SIZE); + memcpy(info->configured, sccb->configured, SCLP_CHP_INFO_MASK_SIZE); +out: + free_page((unsigned long) sccb); + return rc; +} diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 5322e5e54a98..9dc77f14fa52 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -29,12 +29,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work) struct sys_device *sysdev; printk(KERN_WARNING TAG "cpu capability changed.\n"); - lock_cpu_hotplug(); + get_online_cpus(); for_each_online_cpu(cpu) { sysdev = get_cpu_sysdev(cpu); kobject_uevent(&sysdev->kobj, KOBJ_CHANGE); } - unlock_cpu_hotplug(); + put_online_cpus(); } static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c index 82a13d9fdfe4..5716487b8c9d 100644 --- a/drivers/s390/char/sclp_cpi.c +++ b/drivers/s390/char/sclp_cpi.c @@ -1,255 +1,41 @@ /* - * Author: Martin Peschke <mpeschke@de.ibm.com> - * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation + * drivers/s390/char/sclp_cpi.c + * SCLP control programm identification * - * SCLP Control-Program Identification. + * Copyright IBM Corp. 2001, 2007 + * Author(s): Martin Peschke <mpeschke@de.ibm.com> + * Michael Ernst <mernst@de.ibm.com> */ -#include <linux/version.h> #include <linux/kmod.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/string.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <asm/ebcdic.h> -#include <asm/semaphore.h> - -#include "sclp.h" -#include "sclp_rw.h" - -#define CPI_LENGTH_SYSTEM_TYPE 8 -#define CPI_LENGTH_SYSTEM_NAME 8 -#define CPI_LENGTH_SYSPLEX_NAME 8 - -struct cpi_evbuf { - struct evbuf_header header; - u8 id_format; - u8 reserved0; - u8 system_type[CPI_LENGTH_SYSTEM_TYPE]; - u64 reserved1; - u8 system_name[CPI_LENGTH_SYSTEM_NAME]; - u64 reserved2; - u64 system_level; - u64 reserved3; - u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME]; - u8 reserved4[16]; -} __attribute__((packed)); - -struct cpi_sccb { - struct sccb_header header; - struct cpi_evbuf cpi_evbuf; -} __attribute__((packed)); - -/* Event type structure for write message and write priority message */ -static struct sclp_register sclp_cpi_event = -{ - .send_mask = EVTYP_CTLPROGIDENT_MASK -}; +#include <linux/version.h> +#include "sclp_cpi_sys.h" MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Identify this operating system instance " + "to the System z hardware"); +MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, " + "Michael Ernst <mernst@de.ibm.com>"); -MODULE_AUTHOR( - "Martin Peschke, IBM Deutschland Entwicklung GmbH " - "<mpeschke@de.ibm.com>"); - -MODULE_DESCRIPTION( - "identify this operating system instance to the S/390 " - "or zSeries hardware"); +static char *system_name = ""; +static char *sysplex_name = ""; -static char *system_name = NULL; module_param(system_name, charp, 0); MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters"); - -static char *sysplex_name = NULL; -#ifdef ALLOW_SYSPLEX_NAME module_param(sysplex_name, charp, 0); MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters"); -#endif - -/* use default value for this field (as well as for system level) */ -static char *system_type = "LINUX"; -static int -cpi_check_parms(void) +static int __init cpi_module_init(void) { - /* reject if no system type specified */ - if (!system_type) { - printk("cpi: bug: no system type specified\n"); - return -EINVAL; - } - - /* reject if system type larger than 8 characters */ - if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) { - printk("cpi: bug: system type has length of %li characters - " - "only %i characters supported\n", - strlen(system_type), CPI_LENGTH_SYSTEM_TYPE); - return -EINVAL; - } - - /* reject if no system name specified */ - if (!system_name) { - printk("cpi: no system name specified\n"); - return -EINVAL; - } - - /* reject if system name larger than 8 characters */ - if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) { - printk("cpi: system name has length of %li characters - " - "only %i characters supported\n", - strlen(system_name), CPI_LENGTH_SYSTEM_NAME); - return -EINVAL; - } - - /* reject if specified sysplex name larger than 8 characters */ - if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) { - printk("cpi: sysplex name has length of %li characters" - " - only %i characters supported\n", - strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME); - return -EINVAL; - } - return 0; + return sclp_cpi_set_data(system_name, sysplex_name, "LINUX", + LINUX_VERSION_CODE); } -static void -cpi_callback(struct sclp_req *req, void *data) -{ - struct semaphore *sem; - - sem = (struct semaphore *) data; - up(sem); -} - -static struct sclp_req * -cpi_prepare_req(void) -{ - struct sclp_req *req; - struct cpi_sccb *sccb; - struct cpi_evbuf *evb; - - req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL); - if (req == NULL) - return ERR_PTR(-ENOMEM); - sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA); - if (sccb == NULL) { - kfree(req); - return ERR_PTR(-ENOMEM); - } - memset(sccb, 0, sizeof(struct cpi_sccb)); - - /* setup SCCB for Control-Program Identification */ - sccb->header.length = sizeof(struct cpi_sccb); - sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf); - sccb->cpi_evbuf.header.type = 0x0B; - evb = &sccb->cpi_evbuf; - - /* set system type */ - memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE); - memcpy(evb->system_type, system_type, strlen(system_type)); - sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE); - EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE); - - /* set system name */ - memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME); - memcpy(evb->system_name, system_name, strlen(system_name)); - sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME); - EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME); - - /* set system level */ - evb->system_level = LINUX_VERSION_CODE; - - /* set sysplex name */ - if (sysplex_name) { - memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME); - memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name)); - sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME); - EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME); - } - - /* prepare request data structure presented to SCLP driver */ - req->command = SCLP_CMDW_WRITE_EVENT_DATA; - req->sccb = sccb; - req->status = SCLP_REQ_FILLED; - req->callback = cpi_callback; - return req; -} - -static void -cpi_free_req(struct sclp_req *req) -{ - free_page((unsigned long) req->sccb); - kfree(req); -} - -static int __init -cpi_module_init(void) -{ - struct semaphore sem; - struct sclp_req *req; - int rc; - - rc = cpi_check_parms(); - if (rc) - return rc; - - rc = sclp_register(&sclp_cpi_event); - if (rc) { - /* could not register sclp event. Die. */ - printk(KERN_WARNING "cpi: could not register to hardware " - "console.\n"); - return -EINVAL; - } - if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) { - printk(KERN_WARNING "cpi: no control program identification " - "support\n"); - sclp_unregister(&sclp_cpi_event); - return -EOPNOTSUPP; - } - - req = cpi_prepare_req(); - if (IS_ERR(req)) { - printk(KERN_WARNING "cpi: couldn't allocate request\n"); - sclp_unregister(&sclp_cpi_event); - return PTR_ERR(req); - } - - /* Prepare semaphore */ - sema_init(&sem, 0); - req->callback_data = &sem; - /* Add request to sclp queue */ - rc = sclp_add_request(req); - if (rc) { - printk(KERN_WARNING "cpi: could not start request\n"); - cpi_free_req(req); - sclp_unregister(&sclp_cpi_event); - return rc; - } - /* make "insmod" sleep until callback arrives */ - down(&sem); - - rc = ((struct cpi_sccb *) req->sccb)->header.response_code; - if (rc != 0x0020) { - printk(KERN_WARNING "cpi: failed with response code 0x%x\n", - rc); - rc = -ECOMM; - } else - rc = 0; - - cpi_free_req(req); - sclp_unregister(&sclp_cpi_event); - - return rc; -} - - static void __exit cpi_module_exit(void) { } - -/* declare driver module init/cleanup functions */ module_init(cpi_module_init); module_exit(cpi_module_exit); - diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c new file mode 100644 index 000000000000..41617032afdc --- /dev/null +++ b/drivers/s390/char/sclp_cpi_sys.c @@ -0,0 +1,400 @@ +/* + * drivers/s390/char/sclp_cpi_sys.c + * SCLP control program identification sysfs interface + * + * Copyright IBM Corp. 2001, 2007 + * Author(s): Martin Peschke <mpeschke@de.ibm.com> + * Michael Ernst <mernst@de.ibm.com> + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/stat.h> +#include <linux/device.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/kmod.h> +#include <linux/timer.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/completion.h> +#include <asm/ebcdic.h> +#include <asm/sclp.h> +#include "sclp.h" +#include "sclp_rw.h" +#include "sclp_cpi_sys.h" + +#define CPI_LENGTH_NAME 8 +#define CPI_LENGTH_LEVEL 16 + +struct cpi_evbuf { + struct evbuf_header header; + u8 id_format; + u8 reserved0; + u8 system_type[CPI_LENGTH_NAME]; + u64 reserved1; + u8 system_name[CPI_LENGTH_NAME]; + u64 reserved2; + u64 system_level; + u64 reserved3; + u8 sysplex_name[CPI_LENGTH_NAME]; + u8 reserved4[16]; +} __attribute__((packed)); + +struct cpi_sccb { + struct sccb_header header; + struct cpi_evbuf cpi_evbuf; +} __attribute__((packed)); + +static struct sclp_register sclp_cpi_event = { + .send_mask = EVTYP_CTLPROGIDENT_MASK, +}; + +static char system_name[CPI_LENGTH_NAME + 1]; +static char sysplex_name[CPI_LENGTH_NAME + 1]; +static char system_type[CPI_LENGTH_NAME + 1]; +static u64 system_level; + +static void set_data(char *field, char *data) +{ + memset(field, ' ', CPI_LENGTH_NAME); + memcpy(field, data, strlen(data)); + sclp_ascebc_str(field, CPI_LENGTH_NAME); +} + +static void cpi_callback(struct sclp_req *req, void *data) +{ + struct completion *completion = data; + + complete(completion); +} + +static struct sclp_req *cpi_prepare_req(void) +{ + struct sclp_req *req; + struct cpi_sccb *sccb; + struct cpi_evbuf *evb; + + req = kzalloc(sizeof(struct sclp_req), GFP_KERNEL); + if (!req) + return ERR_PTR(-ENOMEM); + sccb = (struct cpi_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) { + kfree(req); + return ERR_PTR(-ENOMEM); + } + + /* setup SCCB for Control-Program Identification */ + sccb->header.length = sizeof(struct cpi_sccb); + sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf); + sccb->cpi_evbuf.header.type = 0x0b; + evb = &sccb->cpi_evbuf; + + /* set system type */ + set_data(evb->system_type, system_type); + + /* set system name */ + set_data(evb->system_name, system_name); + + /* set sytem level */ + evb->system_level = system_level; + + /* set sysplex name */ + set_data(evb->sysplex_name, sysplex_name); + + /* prepare request data structure presented to SCLP driver */ + req->command = SCLP_CMDW_WRITE_EVENT_DATA; + req->sccb = sccb; + req->status = SCLP_REQ_FILLED; + req->callback = cpi_callback; + return req; +} + +static void cpi_free_req(struct sclp_req *req) +{ + free_page((unsigned long) req->sccb); + kfree(req); +} + +static int cpi_req(void) +{ + struct completion completion; + struct sclp_req *req; + int rc; + int response; + + rc = sclp_register(&sclp_cpi_event); + if (rc) { + printk(KERN_WARNING "cpi: could not register " + "to hardware console.\n"); + goto out; + } + if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) { + printk(KERN_WARNING "cpi: no control program " + "identification support\n"); + rc = -EOPNOTSUPP; + goto out_unregister; + } + + req = cpi_prepare_req(); + if (IS_ERR(req)) { + printk(KERN_WARNING "cpi: could not allocate request\n"); + rc = PTR_ERR(req); + goto out_unregister; + } + + init_completion(&completion); + req->callback_data = &completion; + + /* Add request to sclp queue */ + rc = sclp_add_request(req); + if (rc) { + printk(KERN_WARNING "cpi: could not start request\n"); + goto out_free_req; + } + + wait_for_completion(&completion); + + if (req->status != SCLP_REQ_DONE) { + printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n", + req->status); + rc = -EIO; + goto out_free_req; + } + + response = ((struct cpi_sccb *) req->sccb)->header.response_code; + if (response != 0x0020) { + printk(KERN_WARNING "cpi: failed with " + "response code 0x%x\n", response); + rc = -EIO; + } + +out_free_req: + cpi_free_req(req); + +out_unregister: + sclp_unregister(&sclp_cpi_event); + +out: + return rc; +} + +static int check_string(const char *attr, const char *str) +{ + size_t len; + size_t i; + + len = strlen(str); + + if ((len > 0) && (str[len - 1] == '\n')) + len--; + + if (len > CPI_LENGTH_NAME) + return -EINVAL; + + for (i = 0; i < len ; i++) { + if (isalpha(str[i]) || isdigit(str[i]) || + strchr("$@# ", str[i])) + continue; + return -EINVAL; + } + + return 0; +} + +static void set_string(char *attr, const char *value) +{ + size_t len; + size_t i; + + len = strlen(value); + + if ((len > 0) && (value[len - 1] == '\n')) + len--; + + for (i = 0; i < CPI_LENGTH_NAME; i++) { + if (i < len) + attr[i] = toupper(value[i]); + else + attr[i] = ' '; + } +} + +static ssize_t system_name_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return snprintf(page, PAGE_SIZE, "%s\n", system_name); +} + +static ssize_t system_name_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t len) +{ + int rc; + + rc = check_string("system_name", buf); + if (rc) + return rc; + + set_string(system_name, buf); + + return len; +} + +static struct kobj_attribute system_name_attr = + __ATTR(system_name, 0644, system_name_show, system_name_store); + +static ssize_t sysplex_name_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name); +} + +static ssize_t sysplex_name_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t len) +{ + int rc; + + rc = check_string("sysplex_name", buf); + if (rc) + return rc; + + set_string(sysplex_name, buf); + + return len; +} + +static struct kobj_attribute sysplex_name_attr = + __ATTR(sysplex_name, 0644, sysplex_name_show, sysplex_name_store); + +static ssize_t system_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return snprintf(page, PAGE_SIZE, "%s\n", system_type); +} + +static ssize_t system_type_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t len) +{ + int rc; + + rc = check_string("system_type", buf); + if (rc) + return rc; + + set_string(system_type, buf); + + return len; +} + +static struct kobj_attribute system_type_attr = + __ATTR(system_type, 0644, system_type_show, system_type_store); + +static ssize_t system_level_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + unsigned long long level = system_level; + + return snprintf(page, PAGE_SIZE, "%#018llx\n", level); +} + +static ssize_t system_level_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t len) +{ + unsigned long long level; + char *endp; + + level = simple_strtoull(buf, &endp, 16); + + if (endp == buf) + return -EINVAL; + if (*endp == '\n') + endp++; + if (*endp) + return -EINVAL; + + system_level = level; + + return len; +} + +static struct kobj_attribute system_level_attr = + __ATTR(system_level, 0644, system_level_show, system_level_store); + +static ssize_t set_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) +{ + int rc; + + rc = cpi_req(); + if (rc) + return rc; + + return len; +} + +static struct kobj_attribute set_attr = __ATTR(set, 0200, NULL, set_store); + +static struct attribute *cpi_attrs[] = { + &system_name_attr.attr, + &sysplex_name_attr.attr, + &system_type_attr.attr, + &system_level_attr.attr, + &set_attr.attr, + NULL, +}; + +static struct attribute_group cpi_attr_group = { + .attrs = cpi_attrs, +}; + +static struct kset *cpi_kset; + +int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type, + const u64 level) +{ + int rc; + + rc = check_string("system_name", system); + if (rc) + return rc; + rc = check_string("sysplex_name", sysplex); + if (rc) + return rc; + rc = check_string("system_type", type); + if (rc) + return rc; + + set_string(system_name, system); + set_string(sysplex_name, sysplex); + set_string(system_type, type); + system_level = level; + + return cpi_req(); +} +EXPORT_SYMBOL(sclp_cpi_set_data); + +static int __init cpi_init(void) +{ + int rc; + + cpi_kset = kset_create_and_add("cpi", NULL, firmware_kobj); + if (!cpi_kset) + return -ENOMEM; + + rc = sysfs_create_group(&cpi_kset->kobj, &cpi_attr_group); + if (rc) + kset_unregister(cpi_kset); + + return rc; +} + +__initcall(cpi_init); diff --git a/drivers/s390/char/sclp_cpi_sys.h b/drivers/s390/char/sclp_cpi_sys.h new file mode 100644 index 000000000000..deef3e6ff496 --- /dev/null +++ b/drivers/s390/char/sclp_cpi_sys.h @@ -0,0 +1,15 @@ +/* + * drivers/s390/char/sclp_cpi_sys.h + * SCLP control program identification sysfs interface + * + * Copyright IBM Corp. 2007 + * Author(s): Michael Ernst <mernst@de.ibm.com> + */ + +#ifndef __SCLP_CPI_SYS_H__ +#define __SCLP_CPI_SYS_H__ + +int sclp_cpi_set_data(const char *system, const char *sysplex, + const char *type, u64 level); + +#endif /* __SCLP_CPI_SYS_H__ */ diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c deleted file mode 100644 index a1136e052750..000000000000 --- a/drivers/s390/char/sclp_info.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * drivers/s390/char/sclp_info.c - * - * Copyright IBM Corp. 2007 - * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> - */ - -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <asm/sclp.h> -#include "sclp.h" - -struct sclp_readinfo_sccb { - struct sccb_header header; /* 0-7 */ - u16 rnmax; /* 8-9 */ - u8 rnsize; /* 10 */ - u8 _reserved0[24 - 11]; /* 11-23 */ - u8 loadparm[8]; /* 24-31 */ - u8 _reserved1[48 - 32]; /* 32-47 */ - u64 facilities; /* 48-55 */ - u8 _reserved2[91 - 56]; /* 56-90 */ - u8 flags; /* 91 */ - u8 _reserved3[100 - 92]; /* 92-99 */ - u32 rnsize2; /* 100-103 */ - u64 rnmax2; /* 104-111 */ - u8 _reserved4[4096 - 112]; /* 112-4095 */ -} __attribute__((packed, aligned(4096))); - -static struct sclp_readinfo_sccb __initdata early_readinfo_sccb; -static int __initdata early_readinfo_sccb_valid; - -u64 sclp_facilities; - -void __init sclp_readinfo_early(void) -{ - int ret; - int i; - struct sclp_readinfo_sccb *sccb; - sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, - SCLP_CMDW_READ_SCP_INFO}; - - /* Enable service signal subclass mask. */ - __ctl_set_bit(0, 9); - sccb = &early_readinfo_sccb; - for (i = 0; i < ARRAY_SIZE(commands); i++) { - do { - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->header.control_mask[2] = 0x80; - ret = sclp_service_call(commands[i], sccb); - } while (ret == -EBUSY); - - if (ret) - break; - __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | - PSW_MASK_WAIT | PSW_DEFAULT_KEY); - local_irq_disable(); - /* - * Contents of the sccb might have changed - * therefore a barrier is needed. - */ - barrier(); - if (sccb->header.response_code == 0x10) { - early_readinfo_sccb_valid = 1; - break; - } - if (sccb->header.response_code != 0x1f0) - break; - } - /* Disable service signal subclass mask again. */ - __ctl_clear_bit(0, 9); -} - -void __init sclp_facilities_detect(void) -{ - if (!early_readinfo_sccb_valid) - return; - sclp_facilities = early_readinfo_sccb.facilities; -} - -unsigned long long __init sclp_memory_detect(void) -{ - unsigned long long memsize; - struct sclp_readinfo_sccb *sccb; - - if (!early_readinfo_sccb_valid) - return 0; - sccb = &early_readinfo_sccb; - if (sccb->rnsize) - memsize = sccb->rnsize << 20; - else - memsize = sccb->rnsize2 << 20; - if (sccb->rnmax) - memsize *= sccb->rnmax; - else - memsize *= sccb->rnmax2; - return memsize; -} - -/* - * This function will be called after sclp_memory_detect(), which gets called - * early from early.c code. Therefore the sccb should have valid contents. - */ -void __init sclp_get_ipl_info(struct sclp_ipl_info *info) -{ - struct sclp_readinfo_sccb *sccb; - - if (!early_readinfo_sccb_valid) - return; - sccb = &early_readinfo_sccb; - info->is_valid = 1; - if (sccb->flags & 0x2) - info->has_dump = 1; - memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); -} diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index d6b06ab81188..ad7195d3de0c 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -76,7 +76,7 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab) } /* - * Return a pointer to the orignal page that has been used to create + * Return a pointer to the original page that has been used to create * the buffer. */ void * diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index da25f8e24152..8246ef3ab095 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -1495,7 +1495,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, device->cdev->dev.bus_id); return tape_3590_erp_basic(device, request, irb, -EPERM); case 0x8013: - PRINT_WARN("(%s): Another host has priviliged access to the " + PRINT_WARN("(%s): Another host has privileged access to the " "tape device\n", device->cdev->dev.bus_id); PRINT_WARN("(%s): To solve the problem unload the current " "cartridge!\n", device->cdev->dev.bus_id); diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index eeb92e2ed0cc..ddc4a114e7f4 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -74,11 +74,10 @@ tapeblock_trigger_requeue(struct tape_device *device) * Post finished request. */ static void -tapeblock_end_request(struct request *req, int uptodate) +tapeblock_end_request(struct request *req, int error) { - if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) + if (__blk_end_request(req, error, blk_rq_bytes(req))) BUG(); - end_that_request_last(req, uptodate); } static void @@ -91,7 +90,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) device = ccw_req->device; req = (struct request *) data; - tapeblock_end_request(req, ccw_req->rc == 0); + tapeblock_end_request(req, (ccw_req->rc == 0) ? 0 : -EIO); if (ccw_req->rc == 0) /* Update position. */ device->blk_data.block_position = @@ -119,7 +118,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) ccw_req = device->discipline->bread(device, req); if (IS_ERR(ccw_req)) { DBF_EVENT(1, "TBLOCK: bread failed\n"); - tapeblock_end_request(req, 0); + tapeblock_end_request(req, -EIO); return PTR_ERR(ccw_req); } ccw_req->callback = __tapeblock_end_request; @@ -132,7 +131,7 @@ tapeblock_start_request(struct tape_device *device, struct request *req) * Start/enqueueing failed. No retries in * this case. */ - tapeblock_end_request(req, 0); + tapeblock_end_request(req, -EIO); device->discipline->free_bread(ccw_req); } @@ -177,7 +176,7 @@ tapeblock_requeue(struct work_struct *work) { if (rq_data_dir(req) == WRITE) { DBF_EVENT(1, "TBLOCK: Rejecting write request\n"); blkdev_dequeue_request(req); - tapeblock_end_request(req, 0); + tapeblock_end_request(req, -EIO); continue; } spin_unlock_irq(&device->blk_data.request_queue_lock); diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 2fae6338ee1c..7ad8cf157641 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -37,7 +37,7 @@ static void tape_long_busy_timeout(unsigned long data); * we can assign the devices to minor numbers of the same major * The list is protected by the rwlock */ -static struct list_head tape_device_list = LIST_HEAD_INIT(tape_device_list); +static LIST_HEAD(tape_device_list); static DEFINE_RWLOCK(tape_device_lock); /* diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index cea49f001f89..c9b96d51b28f 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -97,7 +97,7 @@ static void tape_proc_stop(struct seq_file *m, void *v) { } -static struct seq_operations tape_proc_seq = { +static const struct seq_operations tape_proc_seq = { .start = tape_proc_start, .next = tape_proc_next, .stop = tape_proc_stop, diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index e0c4c508e121..d364e0bfae12 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -683,7 +683,7 @@ static int vmlogrdr_register_driver(void) /* Register with iucv driver */ ret = iucv_register(&vmlogrdr_iucv_handler, 1); if (ret) { - printk (KERN_ERR "vmlogrdr: failed to register with" + printk (KERN_ERR "vmlogrdr: failed to register with " "iucv driver\n"); goto out; } diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index d70a6e65bf14..7689b500a104 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -759,7 +759,7 @@ static loff_t ur_llseek(struct file *file, loff_t offset, int whence) return newpos; } -static struct file_operations ur_fops = { +static const struct file_operations ur_fops = { .owner = THIS_MODULE, .open = ur_open, .release = ur_release, diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 7073daf77981..f523501e6e6c 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -470,7 +470,7 @@ static loff_t zcore_lseek(struct file *file, loff_t offset, int orig) return rc; } -static struct file_operations zcore_fops = { +static const struct file_operations zcore_fops = { .owner = THIS_MODULE, .llseek = zcore_lseek, .read = zcore_read, diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 5287631fbfc8..b7a07a866291 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -1,12 +1,12 @@ /* * drivers/s390/cio/airq.c - * S/390 common I/O routines -- support for adapter interruptions + * Support for adapter interruptions * - * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - * Cornelia Huck (cornelia.huck@de.ibm.com) - * Arnd Bergmann (arndb@de.ibm.com) + * Copyright IBM Corp. 1999,2007 + * Author(s): Ingo Adlung <adlung@de.ibm.com> + * Cornelia Huck <cornelia.huck@de.ibm.com> + * Arnd Bergmann <arndb@de.ibm.com> + * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> */ #include <linux/init.h> @@ -14,72 +14,131 @@ #include <linux/slab.h> #include <linux/rcupdate.h> +#include <asm/airq.h> + +#include "cio.h" #include "cio_debug.h" -#include "airq.h" -static adapter_int_handler_t adapter_handler; +#define NR_AIRQS 32 +#define NR_AIRQS_PER_WORD sizeof(unsigned long) +#define NR_AIRQ_WORDS (NR_AIRQS / NR_AIRQS_PER_WORD) -/* - * register for adapter interrupts - * - * With HiperSockets the zSeries architecture provides for - * means of adapter interrups, pseudo I/O interrupts that are - * not tied to an I/O subchannel, but to an adapter. However, - * it doesn't disclose the info how to enable/disable them, but - * to recognize them only. Perhaps we should consider them - * being shared interrupts, and thus build a linked list - * of adapter handlers ... to be evaluated ... - */ -int -s390_register_adapter_interrupt (adapter_int_handler_t handler) -{ - int ret; - char dbf_txt[15]; +union indicator_t { + unsigned long word[NR_AIRQ_WORDS]; + unsigned char byte[NR_AIRQS]; +} __attribute__((packed)); - CIO_TRACE_EVENT (4, "rgaint"); +struct airq_t { + adapter_int_handler_t handler; + void *drv_data; +}; - if (handler == NULL) - ret = -EINVAL; - else - ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0); - if (!ret) - synchronize_sched(); /* Allow interrupts to complete. */ +static union indicator_t indicators; +static struct airq_t *airqs[NR_AIRQS]; - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (4, dbf_txt); +static int register_airq(struct airq_t *airq) +{ + int i; - return ret; + for (i = 0; i < NR_AIRQS; i++) + if (!cmpxchg(&airqs[i], NULL, airq)) + return i; + return -ENOMEM; } -int -s390_unregister_adapter_interrupt (adapter_int_handler_t handler) +/** + * s390_register_adapter_interrupt() - register adapter interrupt handler + * @handler: adapter handler to be registered + * @drv_data: driver data passed with each call to the handler + * + * Returns: + * Pointer to the indicator to be used on success + * ERR_PTR() if registration failed + */ +void *s390_register_adapter_interrupt(adapter_int_handler_t handler, + void *drv_data) { + struct airq_t *airq; + char dbf_txt[16]; int ret; - char dbf_txt[15]; - CIO_TRACE_EVENT (4, "urgaint"); - - if (handler == NULL) - ret = -EINVAL; - else { - adapter_handler = NULL; - synchronize_sched(); /* Allow interrupts to complete. */ - ret = 0; + airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); + if (!airq) { + ret = -ENOMEM; + goto out; } - sprintf (dbf_txt, "ret:%d", ret); - CIO_TRACE_EVENT (4, dbf_txt); - - return ret; + airq->handler = handler; + airq->drv_data = drv_data; + ret = register_airq(airq); + if (ret < 0) + kfree(airq); +out: + snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); + CIO_TRACE_EVENT(4, dbf_txt); + if (ret < 0) + return ERR_PTR(ret); + else + return &indicators.byte[ret]; } +EXPORT_SYMBOL(s390_register_adapter_interrupt); -void -do_adapter_IO (void) +/** + * s390_unregister_adapter_interrupt - unregister adapter interrupt handler + * @ind: indicator for which the handler is to be unregistered + */ +void s390_unregister_adapter_interrupt(void *ind) { - CIO_TRACE_EVENT (6, "doaio"); + struct airq_t *airq; + char dbf_txt[16]; + int i; - if (adapter_handler) - (*adapter_handler) (); + i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]); + snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); + CIO_TRACE_EVENT(4, dbf_txt); + indicators.byte[i] = 0; + airq = xchg(&airqs[i], NULL); + /* + * Allow interrupts to complete. This will ensure that the airq handle + * is no longer referenced by any interrupt handler. + */ + synchronize_sched(); + kfree(airq); } +EXPORT_SYMBOL(s390_unregister_adapter_interrupt); + +#define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) -EXPORT_SYMBOL (s390_register_adapter_interrupt); -EXPORT_SYMBOL (s390_unregister_adapter_interrupt); +void do_adapter_IO(void) +{ + int w; + int i; + unsigned long word; + struct airq_t *airq; + + /* + * Access indicator array in word-sized chunks to minimize storage + * fetch operations. + */ + for (w = 0; w < NR_AIRQ_WORDS; w++) { + word = indicators.word[w]; + i = w * NR_AIRQS_PER_WORD; + /* + * Check bytes within word for active indicators. + */ + while (word) { + if (word & INDICATOR_MASK) { + airq = airqs[i]; + if (likely(airq)) + airq->handler(&indicators.byte[i], + airq->drv_data); + else + /* + * Reset ill-behaved indicator. + */ + indicators.byte[i] = 0; + } + word <<= 8; + i++; + } + } +} diff --git a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h deleted file mode 100644 index 7d6be3fdcd66..000000000000 --- a/drivers/s390/cio/airq.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef S390_AINTERRUPT_H -#define S390_AINTERRUPT_H - -typedef int (*adapter_int_handler_t)(void); - -extern int s390_register_adapter_interrupt(adapter_int_handler_t handler); -extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler); -extern void do_adapter_IO (void); - -#endif diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index bd5f16f80bf8..e8597ec92247 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -348,7 +348,7 @@ cio_ignore_write(struct file *file, const char __user *user_buf, return user_len; } -static struct seq_operations cio_ignore_proc_seq_ops = { +static const struct seq_operations cio_ignore_proc_seq_ops = { .start = cio_ignore_proc_seq_start, .stop = cio_ignore_proc_seq_stop, .next = cio_ignore_proc_seq_next, diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5baa517c3b66..3964056a9a47 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -35,8 +35,8 @@ ccwgroup_bus_match (struct device * dev, struct device_driver * drv) struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; - gdev = container_of(dev, struct ccwgroup_device, dev); - gdrv = container_of(drv, struct ccwgroup_driver, driver); + gdev = to_ccwgroupdev(dev); + gdrv = to_ccwgroupdrv(drv); if (gdev->creator_id == gdrv->driver_id) return 1; @@ -75,8 +75,10 @@ static void ccwgroup_ungroup_callback(struct device *dev) struct ccwgroup_device *gdev = to_ccwgroupdev(dev); mutex_lock(&gdev->reg_mutex); - __ccwgroup_remove_symlinks(gdev); - device_unregister(dev); + if (device_is_registered(&gdev->dev)) { + __ccwgroup_remove_symlinks(gdev); + device_unregister(dev); + } mutex_unlock(&gdev->reg_mutex); } @@ -111,7 +113,7 @@ ccwgroup_release (struct device *dev) gdev = to_ccwgroupdev(dev); for (i = 0; i < gdev->count; i++) { - gdev->cdev[i]->dev.driver_data = NULL; + dev_set_drvdata(&gdev->cdev[i]->dev, NULL); put_device(&gdev->cdev[i]->dev); } kfree(gdev); @@ -196,11 +198,11 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, goto error; } /* Don't allow a device to belong to more than one group. */ - if (gdev->cdev[i]->dev.driver_data) { + if (dev_get_drvdata(&gdev->cdev[i]->dev)) { rc = -EINVAL; goto error; } - gdev->cdev[i]->dev.driver_data = gdev; + dev_set_drvdata(&gdev->cdev[i]->dev, gdev); } gdev->creator_id = creator_id; @@ -234,8 +236,8 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, error: for (i = 0; i < argc; i++) if (gdev->cdev[i]) { - if (gdev->cdev[i]->dev.driver_data == gdev) - gdev->cdev[i]->dev.driver_data = NULL; + if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) + dev_set_drvdata(&gdev->cdev[i]->dev, NULL); put_device(&gdev->cdev[i]->dev); } mutex_unlock(&gdev->reg_mutex); @@ -408,6 +410,7 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) /* register our new driver with the core */ cdriver->driver.bus = &ccwgroup_bus_type; cdriver->driver.name = cdriver->name; + cdriver->driver.owner = cdriver->owner; return driver_register(&cdriver->driver); } @@ -463,8 +466,8 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; - if (cdev->dev.driver_data) { - gdev = (struct ccwgroup_device *)cdev->dev.driver_data; + gdev = dev_get_drvdata(&cdev->dev); + if (gdev) { if (get_device(&gdev->dev)) { mutex_lock(&gdev->reg_mutex); if (device_is_registered(&gdev->dev)) diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 597c0c76a2ad..e7ba16a74ef7 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -89,7 +89,8 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) /* Copy data */ ret = 0; memset(ssd, 0, sizeof(struct chsc_ssd_info)); - if ((ssd_area->st != 0) && (ssd_area->st != 2)) + if ((ssd_area->st != SUBCHANNEL_TYPE_IO) && + (ssd_area->st != SUBCHANNEL_TYPE_MSG)) goto out_free; ssd->path_mask = ssd_area->path_mask; ssd->fla_valid_mask = ssd_area->fla_valid_mask; @@ -132,20 +133,16 @@ static void terminate_internal_io(struct subchannel *sch) device_set_intretry(sch); /* Call handler. */ if (sch->driver && sch->driver->termination) - sch->driver->termination(&sch->dev); + sch->driver->termination(sch); } -static int -s390_subchannel_remove_chpid(struct device *dev, void *data) +static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) { int j; int mask; - struct subchannel *sch; - struct chp_id *chpid; + struct chp_id *chpid = data; struct schib schib; - sch = to_subchannel(dev); - chpid = data; for (j = 0; j < 8; j++) { mask = 0x80 >> j; if ((sch->schib.pmcw.pim & mask) && @@ -158,7 +155,7 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) spin_lock_irq(sch->lock); stsch(sch->schid, &schib); - if (!schib.pmcw.dnv) + if (!css_sch_is_valid(&schib)) goto out_unreg; memcpy(&sch->schib, &schib, sizeof(struct schib)); /* Check for single path devices. */ @@ -172,12 +169,12 @@ s390_subchannel_remove_chpid(struct device *dev, void *data) terminate_internal_io(sch); /* Re-start path verification. */ if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); } } else { /* trigger path verification. */ if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); else if (sch->lpm == mask) goto out_unreg; } @@ -201,12 +198,10 @@ void chsc_chp_offline(struct chp_id chpid) if (chp_get_status(chpid) <= 0) return; - bus_for_each_dev(&css_bus_type, NULL, &chpid, - s390_subchannel_remove_chpid); + for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid); } -static int -s390_process_res_acc_new_sch(struct subchannel_id schid) +static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) { struct schib schib; /* @@ -252,18 +247,10 @@ static int get_res_chpid_mask(struct chsc_ssd_info *ssd, return 0; } -static int -__s390_process_res_acc(struct subchannel_id schid, void *data) +static int __s390_process_res_acc(struct subchannel *sch, void *data) { int chp_mask, old_lpm; - struct res_acc_data *res_data; - struct subchannel *sch; - - res_data = data; - sch = get_subchannel_by_schid(schid); - if (!sch) - /* Check if a subchannel is newly available. */ - return s390_process_res_acc_new_sch(schid); + struct res_acc_data *res_data = data; spin_lock_irq(sch->lock); chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); @@ -279,10 +266,10 @@ __s390_process_res_acc(struct subchannel_id schid, void *data) if (!old_lpm && sch->lpm) device_trigger_reprobe(sch); else if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); out: spin_unlock_irq(sch->lock); - put_device(&sch->dev); + return 0; } @@ -305,7 +292,8 @@ static void s390_process_res_acc (struct res_acc_data *res_data) * The more information we have (info), the less scanning * will we have to do. */ - for_each_subchannel(__s390_process_res_acc, res_data); + for_each_subchannel_staged(__s390_process_res_acc, + s390_process_res_acc_new_sch, res_data); } static int @@ -499,8 +487,7 @@ void chsc_process_crw(void) } while (sei_area->flags & 0x80); } -static int -__chp_add_new_sch(struct subchannel_id schid) +static int __chp_add_new_sch(struct subchannel_id schid, void *data) { struct schib schib; @@ -514,45 +501,37 @@ __chp_add_new_sch(struct subchannel_id schid) } -static int -__chp_add(struct subchannel_id schid, void *data) +static int __chp_add(struct subchannel *sch, void *data) { int i, mask; - struct chp_id *chpid; - struct subchannel *sch; - - chpid = data; - sch = get_subchannel_by_schid(schid); - if (!sch) - /* Check if the subchannel is now available. */ - return __chp_add_new_sch(schid); + struct chp_id *chpid = data; + spin_lock_irq(sch->lock); for (i=0; i<8; i++) { mask = 0x80 >> i; if ((sch->schib.pmcw.pim & mask) && - (sch->schib.pmcw.chpid[i] == chpid->id)) { - if (stsch(sch->schid, &sch->schib) != 0) { - /* Endgame. */ - spin_unlock_irq(sch->lock); - return -ENXIO; - } + (sch->schib.pmcw.chpid[i] == chpid->id)) break; - } } if (i==8) { spin_unlock_irq(sch->lock); return 0; } + if (stsch(sch->schid, &sch->schib)) { + spin_unlock_irq(sch->lock); + css_schedule_eval(sch->schid); + return 0; + } sch->lpm = ((sch->schib.pmcw.pim & sch->schib.pmcw.pam & sch->schib.pmcw.pom) | mask) & sch->opm; if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); spin_unlock_irq(sch->lock); - put_device(&sch->dev); + return 0; } @@ -564,7 +543,8 @@ void chsc_chp_online(struct chp_id chpid) CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) != 0) - for_each_subchannel(__chp_add, &chpid); + for_each_subchannel_staged(__chp_add, __chp_add_new_sch, + &chpid); } static void __s390_subchannel_vary_chpid(struct subchannel *sch, @@ -589,7 +569,7 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, if (!old_lpm) device_trigger_reprobe(sch); else if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); break; } sch->opm &= ~mask; @@ -603,37 +583,29 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, terminate_internal_io(sch); /* Re-start path verification. */ if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); } } else if (!sch->lpm) { if (device_trigger_verify(sch) != 0) css_schedule_eval(sch->schid); } else if (sch->driver && sch->driver->verify) - sch->driver->verify(&sch->dev); + sch->driver->verify(sch); break; } spin_unlock_irqrestore(sch->lock, flags); } -static int s390_subchannel_vary_chpid_off(struct device *dev, void *data) +static int s390_subchannel_vary_chpid_off(struct subchannel *sch, void *data) { - struct subchannel *sch; - struct chp_id *chpid; - - sch = to_subchannel(dev); - chpid = data; + struct chp_id *chpid = data; __s390_subchannel_vary_chpid(sch, *chpid, 0); return 0; } -static int s390_subchannel_vary_chpid_on(struct device *dev, void *data) +static int s390_subchannel_vary_chpid_on(struct subchannel *sch, void *data) { - struct subchannel *sch; - struct chp_id *chpid; - - sch = to_subchannel(dev); - chpid = data; + struct chp_id *chpid = data; __s390_subchannel_vary_chpid(sch, *chpid, 1); return 0; @@ -643,13 +615,7 @@ static int __s390_vary_chpid_on(struct subchannel_id schid, void *data) { struct schib schib; - struct subchannel *sch; - sch = get_subchannel_by_schid(schid); - if (sch) { - put_device(&sch->dev); - return 0; - } if (stsch_err(schid, &schib)) /* We're through */ return -ENXIO; @@ -669,12 +635,13 @@ int chsc_chp_vary(struct chp_id chpid, int on) * Redo PathVerification on the devices the chpid connects to */ - bus_for_each_dev(&css_bus_type, NULL, &chpid, on ? - s390_subchannel_vary_chpid_on : - s390_subchannel_vary_chpid_off); if (on) - /* Scan for new devices on varied on path. */ - for_each_subchannel(__s390_vary_chpid_on, NULL); + for_each_subchannel_staged(s390_subchannel_vary_chpid_on, + __s390_vary_chpid_on, &chpid); + else + for_each_subchannel_staged(s390_subchannel_vary_chpid_off, + NULL, &chpid); + return 0; } @@ -1075,7 +1042,7 @@ chsc_determine_css_characteristics(void) scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsc_area) { - CIO_MSG_EVENT(0, "Was not able to determine available" + CIO_MSG_EVENT(0, "Was not able to determine available " "CHSCs due to no memory.\n"); return -ENOMEM; } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 46905345159e..60590a12d529 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -23,11 +23,12 @@ #include <asm/reset.h> #include <asm/ipl.h> #include <asm/chpid.h> -#include "airq.h" +#include <asm/airq.h> #include "cio.h" #include "css.h" #include "chsc.h" #include "ioasm.h" +#include "io_sch.h" #include "blacklist.h" #include "cio_debug.h" #include "chp.h" @@ -56,39 +57,37 @@ __setup ("cio_msg=", cio_setup); /* * Function: cio_debug_init - * Initializes three debug logs (under /proc/s390dbf) for common I/O: - * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on + * Initializes three debug logs for common I/O: + * - cio_msg logs generic cio messages * - cio_trace logs the calling of different functions - * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on - * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW + * - cio_crw logs machine check related cio messages */ -static int __init -cio_debug_init (void) +static int __init cio_debug_init(void) { - cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long)); + cio_debug_msg_id = debug_register("cio_msg", 16, 1, 16 * sizeof(long)); if (!cio_debug_msg_id) goto out_unregister; - debug_register_view (cio_debug_msg_id, &debug_sprintf_view); - debug_set_level (cio_debug_msg_id, 2); - cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 16); + debug_register_view(cio_debug_msg_id, &debug_sprintf_view); + debug_set_level(cio_debug_msg_id, 2); + cio_debug_trace_id = debug_register("cio_trace", 16, 1, 16); if (!cio_debug_trace_id) goto out_unregister; - debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view); - debug_set_level (cio_debug_trace_id, 2); - cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long)); + debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view); + debug_set_level(cio_debug_trace_id, 2); + cio_debug_crw_id = debug_register("cio_crw", 16, 1, 16 * sizeof(long)); if (!cio_debug_crw_id) goto out_unregister; - debug_register_view (cio_debug_crw_id, &debug_sprintf_view); - debug_set_level (cio_debug_crw_id, 2); + debug_register_view(cio_debug_crw_id, &debug_sprintf_view); + debug_set_level(cio_debug_crw_id, 4); return 0; out_unregister: if (cio_debug_msg_id) - debug_unregister (cio_debug_msg_id); + debug_unregister(cio_debug_msg_id); if (cio_debug_trace_id) - debug_unregister (cio_debug_trace_id); + debug_unregister(cio_debug_trace_id); if (cio_debug_crw_id) - debug_unregister (cio_debug_crw_id); + debug_unregister(cio_debug_crw_id); printk(KERN_WARNING"cio: could not initialize debugging\n"); return -1; } @@ -147,7 +146,7 @@ cio_tpi(void) spin_lock(sch->lock); memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); if (sch->driver && sch->driver->irq) - sch->driver->irq(&sch->dev); + sch->driver->irq(sch); spin_unlock(sch->lock); irq_exit (); _local_bh_enable(); @@ -184,33 +183,35 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ { char dbf_txt[15]; int ccode; + struct orb *orb; - CIO_TRACE_EVENT (4, "stIO"); - CIO_TRACE_EVENT (4, sch->dev.bus_id); + CIO_TRACE_EVENT(4, "stIO"); + CIO_TRACE_EVENT(4, sch->dev.bus_id); + orb = &to_io_private(sch)->orb; /* sch is always under 2G. */ - sch->orb.intparm = (__u32)(unsigned long)sch; - sch->orb.fmt = 1; + orb->intparm = (u32)(addr_t)sch; + orb->fmt = 1; - sch->orb.pfch = sch->options.prefetch == 0; - sch->orb.spnd = sch->options.suspend; - sch->orb.ssic = sch->options.suspend && sch->options.inter; - sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm; + orb->pfch = sch->options.prefetch == 0; + orb->spnd = sch->options.suspend; + orb->ssic = sch->options.suspend && sch->options.inter; + orb->lpm = (lpm != 0) ? lpm : sch->lpm; #ifdef CONFIG_64BIT /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ - sch->orb.c64 = 1; - sch->orb.i2k = 0; + orb->c64 = 1; + orb->i2k = 0; #endif - sch->orb.key = key >> 4; + orb->key = key >> 4; /* issue "Start Subchannel" */ - sch->orb.cpa = (__u32) __pa (cpa); - ccode = ssch (sch->schid, &sch->orb); + orb->cpa = (__u32) __pa(cpa); + ccode = ssch(sch->schid, orb); /* process condition code */ - sprintf (dbf_txt, "ccode:%d", ccode); - CIO_TRACE_EVENT (4, dbf_txt); + sprintf(dbf_txt, "ccode:%d", ccode); + CIO_TRACE_EVENT(4, dbf_txt); switch (ccode) { case 0: @@ -405,8 +406,8 @@ cio_modify (struct subchannel *sch) /* * Enable subchannel. */ -int -cio_enable_subchannel (struct subchannel *sch, unsigned int isc) +int cio_enable_subchannel(struct subchannel *sch, unsigned int isc, + u32 intparm) { char dbf_txt[15]; int ccode; @@ -425,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) for (retry = 5, ret = 0; retry > 0; retry--) { sch->schib.pmcw.ena = 1; sch->schib.pmcw.isc = isc; - sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; + sch->schib.pmcw.intparm = intparm; ret = cio_modify(sch); if (ret == -ENODEV) break; @@ -567,7 +568,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) */ if (sch->st != 0) { CIO_DEBUG(KERN_INFO, 0, - "cio: Subchannel 0.%x.%04x reports " + "Subchannel 0.%x.%04x reports " "non-I/O subchannel type %04X\n", sch->schid.ssid, sch->schid.sch_no, sch->st); /* We stop here for non-io subchannels. */ @@ -576,11 +577,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) } /* Initialization for io subchannels. */ - if (!sch->schib.pmcw.dnv) { - /* io subchannel but device number is invalid. */ + if (!css_sch_is_valid(&sch->schib)) { err = -ENODEV; goto out; } + /* Devno is valid. */ if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { /* @@ -600,7 +601,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) sch->lpm = sch->schib.pmcw.pam & sch->opm; CIO_DEBUG(KERN_INFO, 0, - "cio: Detected device %04x on subchannel 0.%x.%04X" + "Detected device %04x on subchannel 0.%x.%04X" " - PIM = %02X, PAM = %02X, POM = %02X\n", sch->schib.pmcw.dev, sch->schid.ssid, sch->schid.sch_no, sch->schib.pmcw.pim, @@ -680,7 +681,7 @@ do_IRQ (struct pt_regs *regs) sizeof (irb->scsw)); /* Call interrupt handler if there is one. */ if (sch->driver && sch->driver->irq) - sch->driver->irq(&sch->dev); + sch->driver->irq(sch); } if (sch) spin_unlock(sch->lock); @@ -698,8 +699,14 @@ do_IRQ (struct pt_regs *regs) #ifdef CONFIG_CCW_CONSOLE static struct subchannel console_subchannel; +static struct io_subchannel_private console_priv; static int console_subchannel_in_use; +void *cio_get_console_priv(void) +{ + return &console_priv; +} + /* * busy wait for the next interrupt on the console */ @@ -738,9 +745,9 @@ cio_test_for_console(struct subchannel_id schid, void *data) { if (stsch_err(schid, &console_subchannel.schib) != 0) return -ENXIO; - if (console_subchannel.schib.pmcw.dnv && - console_subchannel.schib.pmcw.dev == - console_devno) { + if ((console_subchannel.schib.pmcw.st == SUBCHANNEL_TYPE_IO) && + console_subchannel.schib.pmcw.dnv && + (console_subchannel.schib.pmcw.dev == console_devno)) { console_irq = schid.sch_no; return 1; /* found */ } @@ -758,6 +765,7 @@ cio_get_console_sch_no(void) /* VM provided us with the irq number of the console. */ schid.sch_no = console_irq; if (stsch(schid, &console_subchannel.schib) != 0 || + (console_subchannel.schib.pmcw.st != SUBCHANNEL_TYPE_IO) || !console_subchannel.schib.pmcw.dnv) return -1; console_devno = console_subchannel.schib.pmcw.dev; @@ -804,7 +812,7 @@ cio_probe_console(void) ctl_set_bit(6, 24); console_subchannel.schib.pmcw.isc = 7; console_subchannel.schib.pmcw.intparm = - (__u32)(unsigned long)&console_subchannel; + (u32)(addr_t)&console_subchannel; ret = cio_modify(&console_subchannel); if (ret) { console_subchannel_in_use = 0; @@ -1022,7 +1030,7 @@ static int __reipl_subchannel_match(struct subchannel_id schid, void *data) if (stsch_reset(schid, &schib)) return -ENXIO; - if (schib.pmcw.dnv && + if ((schib.pmcw.st == SUBCHANNEL_TYPE_IO) && schib.pmcw.dnv && (schib.pmcw.dev == match_id->devid.devno) && (schid.ssid == match_id->devid.ssid)) { match_id->schid = schid; @@ -1068,6 +1076,8 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo) return -ENODEV; if (stsch(schid, &schib)) return -ENODEV; + if (schib.pmcw.st != SUBCHANNEL_TYPE_IO) + return -ENODEV; if (!schib.pmcw.dnv) return -ENODEV; iplinfo->devno = schib.pmcw.dev; diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 7446c39951a7..52afa4c784de 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -11,32 +11,32 @@ * path management control word */ struct pmcw { - __u32 intparm; /* interruption parameter */ - __u32 qf : 1; /* qdio facility */ - __u32 res0 : 1; /* reserved zeros */ - __u32 isc : 3; /* interruption sublass */ - __u32 res5 : 3; /* reserved zeros */ - __u32 ena : 1; /* enabled */ - __u32 lm : 2; /* limit mode */ - __u32 mme : 2; /* measurement-mode enable */ - __u32 mp : 1; /* multipath mode */ - __u32 tf : 1; /* timing facility */ - __u32 dnv : 1; /* device number valid */ - __u32 dev : 16; /* device number */ - __u8 lpm; /* logical path mask */ - __u8 pnom; /* path not operational mask */ - __u8 lpum; /* last path used mask */ - __u8 pim; /* path installed mask */ - __u16 mbi; /* measurement-block index */ - __u8 pom; /* path operational mask */ - __u8 pam; /* path available mask */ - __u8 chpid[8]; /* CHPID 0-7 (if available) */ - __u32 unused1 : 8; /* reserved zeros */ - __u32 st : 3; /* subchannel type */ - __u32 unused2 : 18; /* reserved zeros */ - __u32 mbfc : 1; /* measurement block format control */ - __u32 xmwme : 1; /* extended measurement word mode enable */ - __u32 csense : 1; /* concurrent sense; can be enabled ...*/ + u32 intparm; /* interruption parameter */ + u32 qf : 1; /* qdio facility */ + u32 res0 : 1; /* reserved zeros */ + u32 isc : 3; /* interruption sublass */ + u32 res5 : 3; /* reserved zeros */ + u32 ena : 1; /* enabled */ + u32 lm : 2; /* limit mode */ + u32 mme : 2; /* measurement-mode enable */ + u32 mp : 1; /* multipath mode */ + u32 tf : 1; /* timing facility */ + u32 dnv : 1; /* device number valid */ + u32 dev : 16; /* device number */ + u8 lpm; /* logical path mask */ + u8 pnom; /* path not operational mask */ + u8 lpum; /* last path used mask */ + u8 pim; /* path installed mask */ + u16 mbi; /* measurement-block index */ + u8 pom; /* path operational mask */ + u8 pam; /* path available mask */ + u8 chpid[8]; /* CHPID 0-7 (if available) */ + u32 unused1 : 8; /* reserved zeros */ + u32 st : 3; /* subchannel type */ + u32 unused2 : 18; /* reserved zeros */ + u32 mbfc : 1; /* measurement block format control */ + u32 xmwme : 1; /* extended measurement word mode enable */ + u32 csense : 1; /* concurrent sense; can be enabled ...*/ /* ... per MSCH, however, if facility */ /* ... is not installed, this results */ /* ... in an operand exception. */ @@ -52,31 +52,6 @@ struct schib { __u8 mda[4]; /* model dependent area */ } __attribute__ ((packed,aligned(4))); -/* - * operation request block - */ -struct orb { - __u32 intparm; /* interruption parameter */ - __u32 key : 4; /* flags, like key, suspend control, etc. */ - __u32 spnd : 1; /* suspend control */ - __u32 res1 : 1; /* reserved */ - __u32 mod : 1; /* modification control */ - __u32 sync : 1; /* synchronize control */ - __u32 fmt : 1; /* format control */ - __u32 pfch : 1; /* prefetch control */ - __u32 isic : 1; /* initial-status-interruption control */ - __u32 alcc : 1; /* address-limit-checking control */ - __u32 ssic : 1; /* suppress-suspended-interr. control */ - __u32 res2 : 1; /* reserved */ - __u32 c64 : 1; /* IDAW/QDIO 64 bit control */ - __u32 i2k : 1; /* IDAW 2/4kB block size control */ - __u32 lpm : 8; /* logical path mask */ - __u32 ils : 1; /* incorrect length */ - __u32 zero : 6; /* reserved zeros */ - __u32 orbx : 1; /* ORB extension control */ - __u32 cpa; /* channel program address */ -} __attribute__ ((packed,aligned(4))); - /* subchannel data structure used by I/O subroutines */ struct subchannel { struct subchannel_id schid; @@ -85,7 +60,7 @@ struct subchannel { enum { SUBCHANNEL_TYPE_IO = 0, SUBCHANNEL_TYPE_CHSC = 1, - SUBCHANNEL_TYPE_MESSAGE = 2, + SUBCHANNEL_TYPE_MSG = 2, SUBCHANNEL_TYPE_ADM = 3, } st; /* subchannel type */ @@ -99,11 +74,10 @@ struct subchannel { __u8 lpm; /* logical path mask */ __u8 opm; /* operational path mask */ struct schib schib; /* subchannel information block */ - struct orb orb; /* operation request block */ - struct ccw1 sense_ccw; /* static ccw for sense command */ struct chsc_ssd_info ssd_info; /* subchannel description */ struct device dev; /* entry in device tree */ struct css_driver *driver; + void *private; /* private per subchannel type data */ } __attribute__ ((aligned(8))); #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ @@ -111,7 +85,7 @@ struct subchannel { #define to_subchannel(n) container_of(n, struct subchannel, dev) extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id); -extern int cio_enable_subchannel (struct subchannel *, unsigned int); +extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32); extern int cio_disable_subchannel (struct subchannel *); extern int cio_cancel (struct subchannel *); extern int cio_clear (struct subchannel *); @@ -125,6 +99,7 @@ extern int cio_get_options (struct subchannel *); extern int cio_modify (struct subchannel *); int cio_create_sch_lock(struct subchannel *); +void do_adapter_IO(void); /* Use with care. */ #ifdef CONFIG_CCW_CONSOLE @@ -133,10 +108,12 @@ extern void cio_release_console(void); extern int cio_is_console(struct subchannel_id); extern struct subchannel *cio_get_console_subchannel(void); extern spinlock_t * cio_get_console_lock(void); +extern void *cio_get_console_priv(void); #else #define cio_is_console(schid) 0 #define cio_get_console_subchannel() NULL -#define cio_get_console_lock() NULL; +#define cio_get_console_lock() NULL +#define cio_get_console_priv() NULL #endif extern int cio_show_msg; diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h index c9bf8989930f..d7429ef6c666 100644 --- a/drivers/s390/cio/cio_debug.h +++ b/drivers/s390/cio/cio_debug.h @@ -8,20 +8,19 @@ extern debug_info_t *cio_debug_msg_id; extern debug_info_t *cio_debug_trace_id; extern debug_info_t *cio_debug_crw_id; -#define CIO_TRACE_EVENT(imp, txt) do { \ +#define CIO_TRACE_EVENT(imp, txt) do { \ debug_text_event(cio_debug_trace_id, imp, txt); \ } while (0) -#define CIO_MSG_EVENT(imp, args...) do { \ - debug_sprintf_event(cio_debug_msg_id, imp , ##args); \ +#define CIO_MSG_EVENT(imp, args...) do { \ + debug_sprintf_event(cio_debug_msg_id, imp , ##args); \ } while (0) -#define CIO_CRW_EVENT(imp, args...) do { \ - debug_sprintf_event(cio_debug_crw_id, imp , ##args); \ +#define CIO_CRW_EVENT(imp, args...) do { \ + debug_sprintf_event(cio_debug_crw_id, imp , ##args); \ } while (0) -static inline void -CIO_HEX_EVENT(int level, void *data, int length) +static inline void CIO_HEX_EVENT(int level, void *data, int length) { if (unlikely(!cio_debug_trace_id)) return; @@ -32,9 +31,10 @@ CIO_HEX_EVENT(int level, void *data, int length) } } -#define CIO_DEBUG(printk_level,event_level,msg...) ({ \ - if (cio_show_msg) printk(printk_level msg); \ - CIO_MSG_EVENT (event_level, msg); \ -}) +#define CIO_DEBUG(printk_level, event_level, msg...) do { \ + if (cio_show_msg) \ + printk(printk_level "cio: " msg); \ + CIO_MSG_EVENT(event_level, msg); \ + } while (0) #endif diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index c3df2cd009a4..3b45bbe6cce0 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -51,6 +51,62 @@ for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) return ret; } +struct cb_data { + void *data; + struct idset *set; + int (*fn_known_sch)(struct subchannel *, void *); + int (*fn_unknown_sch)(struct subchannel_id, void *); +}; + +static int call_fn_known_sch(struct device *dev, void *data) +{ + struct subchannel *sch = to_subchannel(dev); + struct cb_data *cb = data; + int rc = 0; + + idset_sch_del(cb->set, sch->schid); + if (cb->fn_known_sch) + rc = cb->fn_known_sch(sch, cb->data); + return rc; +} + +static int call_fn_unknown_sch(struct subchannel_id schid, void *data) +{ + struct cb_data *cb = data; + int rc = 0; + + if (idset_sch_contains(cb->set, schid)) + rc = cb->fn_unknown_sch(schid, cb->data); + return rc; +} + +int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), + int (*fn_unknown)(struct subchannel_id, + void *), void *data) +{ + struct cb_data cb; + int rc; + + cb.set = idset_sch_new(); + if (!cb.set) + return -ENOMEM; + idset_fill(cb.set); + cb.data = data; + cb.fn_known_sch = fn_known; + cb.fn_unknown_sch = fn_unknown; + /* Process registered subchannels. */ + rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch); + if (rc) + goto out; + /* Process unregistered subchannels. */ + if (fn_unknown) + rc = for_each_subchannel(call_fn_unknown_sch, &cb); +out: + idset_free(cb.set); + + return rc; +} + static struct subchannel * css_alloc_subchannel(struct subchannel_id schid) { @@ -77,7 +133,7 @@ css_alloc_subchannel(struct subchannel_id schid) * This is fine even on 64bit since the subchannel is always located * under 2G. */ - sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; + sch->schib.pmcw.intparm = (u32)(addr_t)sch; ret = cio_modify(sch); if (ret) { kfree(sch->lock); @@ -237,11 +293,25 @@ get_subchannel_by_schid(struct subchannel_id schid) return dev ? to_subchannel(dev) : NULL; } +/** + * css_sch_is_valid() - check if a subchannel is valid + * @schib: subchannel information block for the subchannel + */ +int css_sch_is_valid(struct schib *schib) +{ + if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv) + return 0; + return 1; +} +EXPORT_SYMBOL_GPL(css_sch_is_valid); + static int css_get_subchannel_status(struct subchannel *sch) { struct schib schib; - if (stsch(sch->schid, &schib) || !schib.pmcw.dnv) + if (stsch(sch->schid, &schib)) + return CIO_GONE; + if (!css_sch_is_valid(&schib)) return CIO_GONE; if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) return CIO_REVALIDATE; @@ -293,7 +363,7 @@ static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) action = UNREGISTER; if (sch->driver && sch->driver->notify) { spin_unlock_irqrestore(sch->lock, flags); - ret = sch->driver->notify(&sch->dev, event); + ret = sch->driver->notify(sch, event); spin_lock_irqsave(sch->lock, flags); if (ret) action = NONE; @@ -349,7 +419,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) /* Will be done on the slow path. */ return -EAGAIN; } - if (stsch_err(schid, &schib) || !schib.pmcw.dnv) { + if (stsch_err(schid, &schib) || !css_sch_is_valid(&schib)) { /* Unusable - ignore. */ return 0; } @@ -388,20 +458,56 @@ static int __init slow_subchannel_init(void) return 0; } -static void css_slow_path_func(struct work_struct *unused) +static int slow_eval_known_fn(struct subchannel *sch, void *data) { - struct subchannel_id schid; + int eval; + int rc; - CIO_TRACE_EVENT(4, "slowpath"); spin_lock_irq(&slow_subchannel_lock); - init_subchannel_id(&schid); - while (idset_sch_get_first(slow_subchannel_set, &schid)) { - idset_sch_del(slow_subchannel_set, schid); - spin_unlock_irq(&slow_subchannel_lock); - css_evaluate_subchannel(schid, 1); - spin_lock_irq(&slow_subchannel_lock); + eval = idset_sch_contains(slow_subchannel_set, sch->schid); + idset_sch_del(slow_subchannel_set, sch->schid); + spin_unlock_irq(&slow_subchannel_lock); + if (eval) { + rc = css_evaluate_known_subchannel(sch, 1); + if (rc == -EAGAIN) + css_schedule_eval(sch->schid); } + return 0; +} + +static int slow_eval_unknown_fn(struct subchannel_id schid, void *data) +{ + int eval; + int rc = 0; + + spin_lock_irq(&slow_subchannel_lock); + eval = idset_sch_contains(slow_subchannel_set, schid); + idset_sch_del(slow_subchannel_set, schid); spin_unlock_irq(&slow_subchannel_lock); + if (eval) { + rc = css_evaluate_new_subchannel(schid, 1); + switch (rc) { + case -EAGAIN: + css_schedule_eval(schid); + rc = 0; + break; + case -ENXIO: + case -ENOMEM: + case -EIO: + /* These should abort looping */ + break; + default: + rc = 0; + } + } + return rc; +} + +static void css_slow_path_func(struct work_struct *unused) +{ + CIO_TRACE_EVENT(4, "slowpath"); + for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn, + NULL); } static DECLARE_WORK(slow_path_work, css_slow_path_func); @@ -430,7 +536,6 @@ void css_schedule_eval_all(void) /* Reprobe subchannel if unregistered. */ static int reprobe_subchannel(struct subchannel_id schid, void *data) { - struct subchannel *sch; int ret; CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n", @@ -438,13 +543,6 @@ static int reprobe_subchannel(struct subchannel_id schid, void *data) if (need_reprobe) return -EAGAIN; - sch = get_subchannel_by_schid(schid); - if (sch) { - /* Already known. */ - put_device(&sch->dev); - return 0; - } - ret = css_probe_device(schid); switch (ret) { case 0: @@ -472,7 +570,7 @@ static void reprobe_all(struct work_struct *unused) /* Make sure initial subchannel scan is done. */ wait_event(ccw_device_init_wq, atomic_read(&ccw_device_init_count) == 0); - ret = for_each_subchannel(reprobe_subchannel, NULL); + ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL); CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret, need_reprobe); @@ -787,8 +885,8 @@ int sch_is_pseudo_sch(struct subchannel *sch) static int css_bus_match (struct device *dev, struct device_driver *drv) { - struct subchannel *sch = container_of (dev, struct subchannel, dev); - struct css_driver *driver = container_of (drv, struct css_driver, drv); + struct subchannel *sch = to_subchannel(dev); + struct css_driver *driver = to_cssdriver(drv); if (sch->st == driver->subchannel_type) return 1; @@ -796,32 +894,36 @@ css_bus_match (struct device *dev, struct device_driver *drv) return 0; } -static int -css_probe (struct device *dev) +static int css_probe(struct device *dev) { struct subchannel *sch; + int ret; sch = to_subchannel(dev); - sch->driver = container_of (dev->driver, struct css_driver, drv); - return (sch->driver->probe ? sch->driver->probe(sch) : 0); + sch->driver = to_cssdriver(dev->driver); + ret = sch->driver->probe ? sch->driver->probe(sch) : 0; + if (ret) + sch->driver = NULL; + return ret; } -static int -css_remove (struct device *dev) +static int css_remove(struct device *dev) { struct subchannel *sch; + int ret; sch = to_subchannel(dev); - return (sch->driver->remove ? sch->driver->remove(sch) : 0); + ret = sch->driver->remove ? sch->driver->remove(sch) : 0; + sch->driver = NULL; + return ret; } -static void -css_shutdown (struct device *dev) +static void css_shutdown(struct device *dev) { struct subchannel *sch; sch = to_subchannel(dev); - if (sch->driver->shutdown) + if (sch->driver && sch->driver->shutdown) sch->driver->shutdown(sch); } @@ -833,6 +935,34 @@ struct bus_type css_bus_type = { .shutdown = css_shutdown, }; +/** + * css_driver_register - register a css driver + * @cdrv: css driver to register + * + * This is mainly a wrapper around driver_register that sets name + * and bus_type in the embedded struct device_driver correctly. + */ +int css_driver_register(struct css_driver *cdrv) +{ + cdrv->drv.name = cdrv->name; + cdrv->drv.bus = &css_bus_type; + cdrv->drv.owner = cdrv->owner; + return driver_register(&cdrv->drv); +} +EXPORT_SYMBOL_GPL(css_driver_register); + +/** + * css_driver_unregister - unregister a css driver + * @cdrv: css driver to unregister + * + * This is a wrapper around driver_unregister. + */ +void css_driver_unregister(struct css_driver *cdrv) +{ + driver_unregister(&cdrv->drv); +} +EXPORT_SYMBOL_GPL(css_driver_unregister); + subsys_initcall(init_channel_subsystem); MODULE_LICENSE("GPL"); diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 81215ef32435..b70554523552 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -58,64 +58,6 @@ struct pgid { __u32 tod_high; /* high word TOD clock */ } __attribute__ ((packed)); -#define MAX_CIWS 8 - -/* - * sense-id response buffer layout - */ -struct senseid { - /* common part */ - __u8 reserved; /* always 0x'FF' */ - __u16 cu_type; /* control unit type */ - __u8 cu_model; /* control unit model */ - __u16 dev_type; /* device type */ - __u8 dev_model; /* device model */ - __u8 unused; /* padding byte */ - /* extended part */ - struct ciw ciw[MAX_CIWS]; /* variable # of CIWs */ -} __attribute__ ((packed,aligned(4))); - -struct ccw_device_private { - struct ccw_device *cdev; - struct subchannel *sch; - int state; /* device state */ - atomic_t onoff; - unsigned long registered; - struct ccw_dev_id dev_id; /* device id */ - struct subchannel_id schid; /* subchannel number */ - __u8 imask; /* lpm mask for SNID/SID/SPGID */ - int iretry; /* retry counter SNID/SID/SPGID */ - struct { - unsigned int fast:1; /* post with "channel end" */ - unsigned int repall:1; /* report every interrupt status */ - unsigned int pgroup:1; /* do path grouping */ - unsigned int force:1; /* allow forced online */ - } __attribute__ ((packed)) options; - struct { - unsigned int pgid_single:1; /* use single path for Set PGID */ - unsigned int esid:1; /* Ext. SenseID supported by HW */ - unsigned int dosense:1; /* delayed SENSE required */ - unsigned int doverify:1; /* delayed path verification */ - unsigned int donotify:1; /* call notify function */ - unsigned int recog_done:1; /* dev. recog. complete */ - unsigned int fake_irb:1; /* deliver faked irb */ - unsigned int intretry:1; /* retry internal operation */ - } __attribute__((packed)) flags; - unsigned long intparm; /* user interruption parameter */ - struct qdio_irq *qdio_data; - struct irb irb; /* device status */ - struct senseid senseid; /* SenseID info */ - struct pgid pgid[8]; /* path group IDs per chpid*/ - struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ - struct work_struct kick_work; - wait_queue_head_t wait_q; - struct timer_list timer; - void *cmb; /* measurement information */ - struct list_head cmb_list; /* list of measured devices */ - u64 cmb_start_time; /* clock value of cmb reset */ - void *cmb_wait; /* deferred cmb enable/disable */ -}; - /* * A css driver handles all subchannels of one type. * Currently, we only care about I/O subchannels (type 0), these @@ -123,25 +65,35 @@ struct ccw_device_private { */ struct subchannel; struct css_driver { + struct module *owner; unsigned int subchannel_type; struct device_driver drv; - void (*irq)(struct device *); - int (*notify)(struct device *, int); - void (*verify)(struct device *); - void (*termination)(struct device *); + void (*irq)(struct subchannel *); + int (*notify)(struct subchannel *, int); + void (*verify)(struct subchannel *); + void (*termination)(struct subchannel *); int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); + const char *name; }; +#define to_cssdriver(n) container_of(n, struct css_driver, drv) + /* * all css_drivers have the css_bus_type */ extern struct bus_type css_bus_type; +extern int css_driver_register(struct css_driver *); +extern void css_driver_unregister(struct css_driver *); + extern void css_sch_device_unregister(struct subchannel *); extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; +int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), + int (*fn_unknown)(struct subchannel_id, + void *), void *data); extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); extern void css_process_crw(int, int); extern void css_reiterate_subchannels(void); @@ -188,6 +140,8 @@ void css_schedule_eval(struct subchannel_id schid); void css_schedule_eval_all(void); int sch_is_pseudo_sch(struct subchannel *); +struct schib; +int css_sch_is_valid(struct schib *); extern struct workqueue_struct *slow_path_wq; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 74f6b539974a..d35dc3f25d06 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -17,6 +17,7 @@ #include <linux/list.h> #include <linux/device.h> #include <linux/workqueue.h> +#include <linux/timer.h> #include <asm/ccwdev.h> #include <asm/cio.h> @@ -28,6 +29,12 @@ #include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" + +static struct timer_list recovery_timer; +static spinlock_t recovery_lock; +static int recovery_phase; +static const unsigned long recovery_delay[] = { 3, 30, 300 }; /******************* bus type handling ***********************/ @@ -115,19 +122,18 @@ static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env) struct bus_type ccw_bus_type; -static int io_subchannel_probe (struct subchannel *); -static int io_subchannel_remove (struct subchannel *); -static int io_subchannel_notify(struct device *, int); -static void io_subchannel_verify(struct device *); -static void io_subchannel_ioterm(struct device *); +static void io_subchannel_irq(struct subchannel *); +static int io_subchannel_probe(struct subchannel *); +static int io_subchannel_remove(struct subchannel *); +static int io_subchannel_notify(struct subchannel *, int); +static void io_subchannel_verify(struct subchannel *); +static void io_subchannel_ioterm(struct subchannel *); static void io_subchannel_shutdown(struct subchannel *); static struct css_driver io_subchannel_driver = { + .owner = THIS_MODULE, .subchannel_type = SUBCHANNEL_TYPE_IO, - .drv = { - .name = "io_subchannel", - .bus = &css_bus_type, - }, + .name = "io_subchannel", .irq = io_subchannel_irq, .notify = io_subchannel_notify, .verify = io_subchannel_verify, @@ -142,6 +148,8 @@ struct workqueue_struct *ccw_device_notify_work; wait_queue_head_t ccw_device_init_wq; atomic_t ccw_device_init_count; +static void recovery_func(unsigned long data); + static int __init init_ccw_bus_type (void) { @@ -149,6 +157,7 @@ init_ccw_bus_type (void) init_waitqueue_head(&ccw_device_init_wq); atomic_set(&ccw_device_init_count, 0); + setup_timer(&recovery_timer, recovery_func, 0); ccw_device_work = create_singlethread_workqueue("cio"); if (!ccw_device_work) @@ -166,7 +175,8 @@ init_ccw_bus_type (void) if ((ret = bus_register (&ccw_bus_type))) goto out_err; - if ((ret = driver_register(&io_subchannel_driver.drv))) + ret = css_driver_register(&io_subchannel_driver); + if (ret) goto out_err; wait_event(ccw_device_init_wq, @@ -186,7 +196,7 @@ out_err: static void __exit cleanup_ccw_bus_type (void) { - driver_unregister(&io_subchannel_driver.drv); + css_driver_unregister(&io_subchannel_driver); bus_unregister(&ccw_bus_type); destroy_workqueue(ccw_device_notify_work); destroy_workqueue(ccw_device_work); @@ -773,7 +783,7 @@ static void sch_attach_device(struct subchannel *sch, { css_update_ssd_info(sch); spin_lock_irq(sch->lock); - sch->dev.driver_data = cdev; + sch_set_cdev(sch, cdev); cdev->private->schid = sch->schid; cdev->ccwlock = sch->lock; device_trigger_reprobe(sch); @@ -795,7 +805,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch, put_device(&other_sch->dev); return; } - other_sch->dev.driver_data = NULL; + sch_set_cdev(other_sch, NULL); /* No need to keep a subchannel without ccw device around. */ css_sch_device_unregister(other_sch); put_device(&other_sch->dev); @@ -831,12 +841,12 @@ static void sch_create_and_recog_new_device(struct subchannel *sch) return; } spin_lock_irq(sch->lock); - sch->dev.driver_data = cdev; + sch_set_cdev(sch, cdev); spin_unlock_irq(sch->lock); /* Start recognition for the new ccw device. */ if (io_subchannel_recog(cdev, sch)) { spin_lock_irq(sch->lock); - sch->dev.driver_data = NULL; + sch_set_cdev(sch, NULL); spin_unlock_irq(sch->lock); if (cdev->dev.release) cdev->dev.release(&cdev->dev); @@ -940,7 +950,7 @@ io_subchannel_register(struct work_struct *work) cdev->private->dev_id.devno, ret); put_device(&cdev->dev); spin_lock_irqsave(sch->lock, flags); - sch->dev.driver_data = NULL; + sch_set_cdev(sch, NULL); spin_unlock_irqrestore(sch->lock, flags); kfree (cdev->private); kfree (cdev); @@ -1022,7 +1032,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) int rc; struct ccw_device_private *priv; - sch->dev.driver_data = cdev; + sch_set_cdev(sch, cdev); sch->driver = &io_subchannel_driver; cdev->ccwlock = sch->lock; @@ -1082,7 +1092,7 @@ static void ccw_device_move_to_sch(struct work_struct *work) } if (former_parent) { spin_lock_irq(former_parent->lock); - former_parent->dev.driver_data = NULL; + sch_set_cdev(former_parent, NULL); spin_unlock_irq(former_parent->lock); css_sch_device_unregister(former_parent); /* Reset intparm to zeroes. */ @@ -1096,6 +1106,18 @@ out: put_device(&cdev->dev); } +static void io_subchannel_irq(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + + CIO_TRACE_EVENT(3, "IRQ"); + CIO_TRACE_EVENT(3, sch->dev.bus_id); + if (cdev) + dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); +} + static int io_subchannel_probe (struct subchannel *sch) { @@ -1104,13 +1126,13 @@ io_subchannel_probe (struct subchannel *sch) unsigned long flags; struct ccw_dev_id dev_id; - if (sch->dev.driver_data) { + cdev = sch_get_cdev(sch); + if (cdev) { /* * This subchannel already has an associated ccw_device. * Register it and exit. This happens for all early * device, e.g. the console. */ - cdev = sch->dev.driver_data; cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); @@ -1132,6 +1154,11 @@ io_subchannel_probe (struct subchannel *sch) */ dev_id.devno = sch->schib.pmcw.dev; dev_id.ssid = sch->schid.ssid; + /* Allocate I/O subchannel private data. */ + sch->private = kzalloc(sizeof(struct io_subchannel_private), + GFP_KERNEL | GFP_DMA); + if (!sch->private) + return -ENOMEM; cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); if (!cdev) cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), @@ -1149,16 +1176,18 @@ io_subchannel_probe (struct subchannel *sch) return 0; } cdev = io_subchannel_create_ccwdev(sch); - if (IS_ERR(cdev)) + if (IS_ERR(cdev)) { + kfree(sch->private); return PTR_ERR(cdev); - + } rc = io_subchannel_recog(cdev, sch); if (rc) { spin_lock_irqsave(sch->lock, flags); - sch->dev.driver_data = NULL; + sch_set_cdev(sch, NULL); spin_unlock_irqrestore(sch->lock, flags); if (cdev->dev.release) cdev->dev.release(&cdev->dev); + kfree(sch->private); } return rc; @@ -1170,25 +1199,25 @@ io_subchannel_remove (struct subchannel *sch) struct ccw_device *cdev; unsigned long flags; - if (!sch->dev.driver_data) + cdev = sch_get_cdev(sch); + if (!cdev) return 0; - cdev = sch->dev.driver_data; /* Set ccw device to not operational and drop reference. */ spin_lock_irqsave(cdev->ccwlock, flags); - sch->dev.driver_data = NULL; + sch_set_cdev(sch, NULL); cdev->private->state = DEV_STATE_NOT_OPER; spin_unlock_irqrestore(cdev->ccwlock, flags); ccw_device_unregister(cdev); put_device(&cdev->dev); + kfree(sch->private); return 0; } -static int -io_subchannel_notify(struct device *dev, int event) +static int io_subchannel_notify(struct subchannel *sch, int event) { struct ccw_device *cdev; - cdev = dev->driver_data; + cdev = sch_get_cdev(sch); if (!cdev) return 0; if (!cdev->drv) @@ -1198,22 +1227,20 @@ io_subchannel_notify(struct device *dev, int event) return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; } -static void -io_subchannel_verify(struct device *dev) +static void io_subchannel_verify(struct subchannel *sch) { struct ccw_device *cdev; - cdev = dev->driver_data; + cdev = sch_get_cdev(sch); if (cdev) dev_fsm_event(cdev, DEV_EVENT_VERIFY); } -static void -io_subchannel_ioterm(struct device *dev) +static void io_subchannel_ioterm(struct subchannel *sch) { struct ccw_device *cdev; - cdev = dev->driver_data; + cdev = sch_get_cdev(sch); if (!cdev) return; /* Internal I/O will be retried by the interrupt handler. */ @@ -1231,7 +1258,7 @@ io_subchannel_shutdown(struct subchannel *sch) struct ccw_device *cdev; int ret; - cdev = sch->dev.driver_data; + cdev = sch_get_cdev(sch); if (cio_is_console(sch->schid)) return; @@ -1271,6 +1298,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) { int rc; + /* Attach subchannel private data. */ + sch->private = cio_get_console_priv(); + memset(sch->private, 0, sizeof(struct io_subchannel_private)); /* Initialize the ccw_device structure. */ cdev->dev.parent= &sch->dev; rc = io_subchannel_recog(cdev, sch); @@ -1456,6 +1486,7 @@ int ccw_driver_register(struct ccw_driver *cdriver) drv->bus = &ccw_bus_type; drv->name = cdriver->name; + drv->owner = cdriver->owner; return driver_register(drv); } @@ -1481,6 +1512,60 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev) return sch->schid; } +static int recovery_check(struct device *dev, void *data) +{ + struct ccw_device *cdev = to_ccwdev(dev); + int *redo = data; + + spin_lock_irq(cdev->ccwlock); + switch (cdev->private->state) { + case DEV_STATE_DISCONNECTED: + CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + *redo = 1; + break; + case DEV_STATE_DISCONNECTED_SENSE_ID: + *redo = 1; + break; + } + spin_unlock_irq(cdev->ccwlock); + + return 0; +} + +static void recovery_func(unsigned long data) +{ + int redo = 0; + + bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check); + if (redo) { + spin_lock_irq(&recovery_lock); + if (!timer_pending(&recovery_timer)) { + if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1) + recovery_phase++; + mod_timer(&recovery_timer, jiffies + + recovery_delay[recovery_phase] * HZ); + } + spin_unlock_irq(&recovery_lock); + } else + CIO_MSG_EVENT(2, "recovery: end\n"); +} + +void ccw_device_schedule_recovery(void) +{ + unsigned long flags; + + CIO_MSG_EVENT(2, "recovery: schedule\n"); + spin_lock_irqsave(&recovery_lock, flags); + if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { + recovery_phase = 0; + mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ); + } + spin_unlock_irqrestore(&recovery_lock, flags); +} + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(ccw_device_set_online); EXPORT_SYMBOL(ccw_device_set_offline); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 0d4089600439..d40a2ffaa000 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -5,6 +5,8 @@ #include <asm/atomic.h> #include <linux/wait.h> +#include "io_sch.h" + /* * states of the device statemachine */ @@ -74,7 +76,6 @@ extern struct workqueue_struct *ccw_device_notify_work; extern wait_queue_head_t ccw_device_init_wq; extern atomic_t ccw_device_init_count; -void io_subchannel_irq (struct device *pdev); void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); @@ -87,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +void ccw_device_schedule_recovery(void); + /* Function prototypes for device status and basic sense stuff. */ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index bfad421cda66..4b92c84fb438 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -25,14 +25,16 @@ #include "ioasm.h" #include "chp.h" +static int timeout_log_enabled; + int device_is_online(struct subchannel *sch) { struct ccw_device *cdev; - if (!sch->dev.driver_data) + cdev = sch_get_cdev(sch); + if (!cdev) return 0; - cdev = sch->dev.driver_data; return (cdev->private->state == DEV_STATE_ONLINE); } @@ -41,9 +43,9 @@ device_is_disconnected(struct subchannel *sch) { struct ccw_device *cdev; - if (!sch->dev.driver_data) + cdev = sch_get_cdev(sch); + if (!cdev) return 0; - cdev = sch->dev.driver_data; return (cdev->private->state == DEV_STATE_DISCONNECTED || cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID); } @@ -53,19 +55,21 @@ device_set_disconnected(struct subchannel *sch) { struct ccw_device *cdev; - if (!sch->dev.driver_data) + cdev = sch_get_cdev(sch); + if (!cdev) return; - cdev = sch->dev.driver_data; ccw_device_set_timeout(cdev, 0); cdev->private->flags.fake_irb = 0; cdev->private->state = DEV_STATE_DISCONNECTED; + if (cdev->online) + ccw_device_schedule_recovery(); } void device_set_intretry(struct subchannel *sch) { struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev = sch_get_cdev(sch); if (!cdev) return; cdev->private->flags.intretry = 1; @@ -75,13 +79,62 @@ int device_trigger_verify(struct subchannel *sch) { struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev = sch_get_cdev(sch); if (!cdev || !cdev->online) return -EINVAL; dev_fsm_event(cdev, DEV_EVENT_VERIFY); return 0; } +static int __init ccw_timeout_log_setup(char *unused) +{ + timeout_log_enabled = 1; + return 1; +} + +__setup("ccw_timeout_log", ccw_timeout_log_setup); + +static void ccw_timeout_log(struct ccw_device *cdev) +{ + struct schib schib; + struct subchannel *sch; + struct io_subchannel_private *private; + int cc; + + sch = to_subchannel(cdev->dev.parent); + private = to_io_private(sch); + cc = stsch(sch->schid, &schib); + + printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " + "device information:\n", get_clock()); + printk(KERN_WARNING "cio: orb:\n"); + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + &private->orb, sizeof(private->orb), 0); + printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); + printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); + printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " + "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); + + if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw || + (void *)(addr_t)private->orb.cpa == cdev->private->iccws) + printk(KERN_WARNING "cio: last channel program (intern):\n"); + else + printk(KERN_WARNING "cio: last channel program:\n"); + + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + (void *)(addr_t)private->orb.cpa, + sizeof(struct ccw1), 0); + printk(KERN_WARNING "cio: ccw device state: %d\n", + cdev->private->state); + printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); + printk(KERN_WARNING "cio: schib:\n"); + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + &schib, sizeof(schib), 0); + printk(KERN_WARNING "cio: ccw device flags:\n"); + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + &cdev->private->flags, sizeof(cdev->private->flags), 0); +} + /* * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. */ @@ -92,6 +145,8 @@ ccw_device_timeout(unsigned long data) cdev = (struct ccw_device *) data; spin_lock_irq(cdev->ccwlock); + if (timeout_log_enabled) + ccw_timeout_log(cdev); dev_fsm_event(cdev, DEV_EVENT_TIMEOUT); spin_unlock_irq(cdev->ccwlock); } @@ -122,9 +177,9 @@ device_kill_pending_timer(struct subchannel *sch) { struct ccw_device *cdev; - if (!sch->dev.driver_data) + cdev = sch_get_cdev(sch); + if (!cdev) return; - cdev = sch->dev.driver_data; ccw_device_set_timeout(cdev, 0); } @@ -268,7 +323,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) switch (state) { case DEV_STATE_NOT_OPER: CIO_DEBUG(KERN_WARNING, 2, - "cio: SenseID : unknown device %04x on subchannel " + "SenseID : unknown device %04x on subchannel " "0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); break; @@ -294,7 +349,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) } /* Issue device info message. */ CIO_DEBUG(KERN_INFO, 2, - "cio: SenseID : device 0.%x.%04x reports: " + "SenseID : device 0.%x.%04x reports: " "CU Type/Mod = %04X/%02X, Dev Type/Mod = " "%04X/%02X\n", cdev->private->dev_id.ssid, @@ -304,7 +359,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) break; case DEV_STATE_BOXED: CIO_DEBUG(KERN_WARNING, 2, - "cio: SenseID : boxed device %04x on subchannel " + "SenseID : boxed device %04x on subchannel " "0.%x.%04x\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); break; @@ -349,7 +404,7 @@ ccw_device_oper_notify(struct work_struct *work) sch = to_subchannel(cdev->dev.parent); if (sch->driver && sch->driver->notify) { spin_unlock_irqrestore(cdev->ccwlock, flags); - ret = sch->driver->notify(&sch->dev, CIO_OPER); + ret = sch->driver->notify(sch, CIO_OPER); spin_lock_irqsave(cdev->ccwlock, flags); } else ret = 0; @@ -389,7 +444,7 @@ ccw_device_done(struct ccw_device *cdev, int state) if (state == DEV_STATE_BOXED) CIO_DEBUG(KERN_WARNING, 2, - "cio: Boxed device %04x on subchannel %04x\n", + "Boxed device %04x on subchannel %04x\n", cdev->private->dev_id.devno, sch->schid.sch_no); if (cdev->private->flags.donotify) { @@ -500,7 +555,8 @@ ccw_device_recognition(struct ccw_device *cdev) (cdev->private->state != DEV_STATE_BOXED)) return -EINVAL; sch = to_subchannel(cdev->dev.parent); - ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc); + ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc, + (u32)(addr_t)sch); if (ret != 0) /* Couldn't enable the subchannel for i/o. Sick device. */ return ret; @@ -587,9 +643,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) default: /* Reset oper notify indication after verify error. */ cdev->private->flags.donotify = 0; - if (cdev->online) + if (cdev->online) { + ccw_device_set_timeout(cdev, 0); dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - else + } else ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } @@ -610,7 +667,8 @@ ccw_device_online(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); if (css_init_done && !get_device(&cdev->dev)) return -ENODEV; - ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc); + ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc, + (u32)(addr_t)sch); if (ret != 0) { /* Couldn't enable the subchannel for i/o. Sick device. */ if (ret == -ENODEV) @@ -937,7 +995,7 @@ void device_kill_io(struct subchannel *sch) int ret; struct ccw_device *cdev; - cdev = sch->dev.driver_data; + cdev = sch_get_cdev(sch); ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -990,7 +1048,8 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); - if (cio_enable_subchannel(sch, sch->schib.pmcw.isc) != 0) + if (cio_enable_subchannel(sch, sch->schib.pmcw.isc, + (u32)(addr_t)sch) != 0) /* Couldn't enable the subchannel for i/o. Sick device. */ return; @@ -1006,9 +1065,9 @@ device_trigger_reprobe(struct subchannel *sch) { struct ccw_device *cdev; - if (!sch->dev.driver_data) + cdev = sch_get_cdev(sch); + if (!cdev) return; - cdev = sch->dev.driver_data; if (cdev->private->state != DEV_STATE_DISCONNECTED) return; @@ -1028,7 +1087,7 @@ device_trigger_reprobe(struct subchannel *sch) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; - sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; + sch->schib.pmcw.intparm = (u32)(addr_t)sch; /* We should also udate ssd info, but this has to wait. */ /* Check if this is another device which appeared on the same sch. */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { @@ -1223,21 +1282,4 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { }, }; -/* - * io_subchannel_irq is called for "real" interrupts or for status - * pending conditions on msch. - */ -void -io_subchannel_irq (struct device *pdev) -{ - struct ccw_device *cdev; - - cdev = to_subchannel(pdev)->dev.driver_data; - - CIO_TRACE_EVENT (3, "IRQ"); - CIO_TRACE_EVENT (3, pdev->bus_id); - if (cdev) - dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); -} - EXPORT_SYMBOL_GPL(ccw_device_set_timeout); diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 156f3f9786b5..918b8b89cf9a 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c @@ -24,6 +24,7 @@ #include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /* * Input : @@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev) return -EAGAIN; } if (irb->scsw.cc == 3) { - if ((sch->orb.lpm & - sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) + u8 lpm; + + lpm = to_io_private(sch)->orb.lpm; + if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x " "on subchannel 0.%x.%04x is " - "'not operational'\n", sch->orb.lpm, + "'not operational'\n", lpm, cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no); return -EACCES; diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index 7fd2dadc3297..49b58eb0fab8 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -501,7 +501,7 @@ ccw_device_stlck(struct ccw_device *cdev) return -ENOMEM; } spin_lock_irqsave(sch->lock, flags); - ret = cio_enable_subchannel(sch, 3); + ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch); if (ret) goto out_unlock; /* diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index cb1879a96818..c52449a1f9fc 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -22,6 +22,7 @@ #include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /* * Helper function called from interrupt context to decide whether an @@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) return -EAGAIN; } if (irb->scsw.cc == 3) { + u8 lpm; + + lpm = to_io_private(sch)->orb.lpm; CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, - sch->schid.sch_no, sch->orb.lpm); + sch->schid.sch_no, lpm); return -EACCES; } i = 8 - ffs(cdev->private->imask); diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index aa96e6752592..ebe0848cfe33 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -20,6 +20,7 @@ #include "css.h" #include "device.h" #include "ioasm.h" +#include "io_sch.h" /* * Check for any kind of channel or interface control check but don't @@ -310,6 +311,7 @@ int ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) { struct subchannel *sch; + struct ccw1 *sense_ccw; sch = to_subchannel(cdev->dev.parent); @@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) /* * We have ending status but no sense information. Do a basic sense. */ - sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE; - sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw); - sch->sense_ccw.count = SENSE_MAX_COUNT; - sch->sense_ccw.flags = CCW_FLAG_SLI; + sense_ccw = &to_io_private(sch)->sense_ccw; + sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE; + sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw); + sense_ccw->count = SENSE_MAX_COUNT; + sense_ccw->flags = CCW_FLAG_SLI; /* Reset internal retry indication. */ cdev->private->flags.intretry = 0; - return cio_start (sch, &sch->sense_ccw, 0xff); + return cio_start(sch, sense_ccw, 0xff); } /* diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h new file mode 100644 index 000000000000..8c613160bfce --- /dev/null +++ b/drivers/s390/cio/io_sch.h @@ -0,0 +1,163 @@ +#ifndef S390_IO_SCH_H +#define S390_IO_SCH_H + +#include "schid.h" + +/* + * operation request block + */ +struct orb { + u32 intparm; /* interruption parameter */ + u32 key : 4; /* flags, like key, suspend control, etc. */ + u32 spnd : 1; /* suspend control */ + u32 res1 : 1; /* reserved */ + u32 mod : 1; /* modification control */ + u32 sync : 1; /* synchronize control */ + u32 fmt : 1; /* format control */ + u32 pfch : 1; /* prefetch control */ + u32 isic : 1; /* initial-status-interruption control */ + u32 alcc : 1; /* address-limit-checking control */ + u32 ssic : 1; /* suppress-suspended-interr. control */ + u32 res2 : 1; /* reserved */ + u32 c64 : 1; /* IDAW/QDIO 64 bit control */ + u32 i2k : 1; /* IDAW 2/4kB block size control */ + u32 lpm : 8; /* logical path mask */ + u32 ils : 1; /* incorrect length */ + u32 zero : 6; /* reserved zeros */ + u32 orbx : 1; /* ORB extension control */ + u32 cpa; /* channel program address */ +} __attribute__ ((packed, aligned(4))); + +struct io_subchannel_private { + struct orb orb; /* operation request block */ + struct ccw1 sense_ccw; /* static ccw for sense command */ +} __attribute__ ((aligned(8))); + +#define to_io_private(n) ((struct io_subchannel_private *)n->private) +#define sch_get_cdev(n) (dev_get_drvdata(&n->dev)) +#define sch_set_cdev(n, c) (dev_set_drvdata(&n->dev, c)) + +#define MAX_CIWS 8 + +/* + * sense-id response buffer layout + */ +struct senseid { + /* common part */ + u8 reserved; /* always 0x'FF' */ + u16 cu_type; /* control unit type */ + u8 cu_model; /* control unit model */ + u16 dev_type; /* device type */ + u8 dev_model; /* device model */ + u8 unused; /* padding byte */ + /* extended part */ + struct ciw ciw[MAX_CIWS]; /* variable # of CIWs */ +} __attribute__ ((packed, aligned(4))); + +struct ccw_device_private { + struct ccw_device *cdev; + struct subchannel *sch; + int state; /* device state */ + atomic_t onoff; + unsigned long registered; + struct ccw_dev_id dev_id; /* device id */ + struct subchannel_id schid; /* subchannel number */ + u8 imask; /* lpm mask for SNID/SID/SPGID */ + int iretry; /* retry counter SNID/SID/SPGID */ + struct { + unsigned int fast:1; /* post with "channel end" */ + unsigned int repall:1; /* report every interrupt status */ + unsigned int pgroup:1; /* do path grouping */ + unsigned int force:1; /* allow forced online */ + } __attribute__ ((packed)) options; + struct { + unsigned int pgid_single:1; /* use single path for Set PGID */ + unsigned int esid:1; /* Ext. SenseID supported by HW */ + unsigned int dosense:1; /* delayed SENSE required */ + unsigned int doverify:1; /* delayed path verification */ + unsigned int donotify:1; /* call notify function */ + unsigned int recog_done:1; /* dev. recog. complete */ + unsigned int fake_irb:1; /* deliver faked irb */ + unsigned int intretry:1; /* retry internal operation */ + } __attribute__((packed)) flags; + unsigned long intparm; /* user interruption parameter */ + struct qdio_irq *qdio_data; + struct irb irb; /* device status */ + struct senseid senseid; /* SenseID info */ + struct pgid pgid[8]; /* path group IDs per chpid*/ + struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ + struct work_struct kick_work; + wait_queue_head_t wait_q; + struct timer_list timer; + void *cmb; /* measurement information */ + struct list_head cmb_list; /* list of measured devices */ + u64 cmb_start_time; /* clock value of cmb reset */ + void *cmb_wait; /* deferred cmb enable/disable */ +}; + +static inline int ssch(struct subchannel_id schid, volatile struct orb *addr) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode; + + asm volatile( + " ssch 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + return ccode; +} + +static inline int rsch(struct subchannel_id schid) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode; + + asm volatile( + " rsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +static inline int csch(struct subchannel_id schid) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode; + + asm volatile( + " csch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +static inline int hsch(struct subchannel_id schid) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode; + + asm volatile( + " hsch\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +static inline int xsch(struct subchannel_id schid) +{ + register struct subchannel_id reg1 asm("1") = schid; + int ccode; + + asm volatile( + " .insn rre,0xb2760000,%1,0\n" + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1) : "cc"); + return ccode; +} + +#endif diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h index 7153dd959082..652ea3625f9d 100644 --- a/drivers/s390/cio/ioasm.h +++ b/drivers/s390/cio/ioasm.h @@ -109,72 +109,6 @@ static inline int tpi( volatile struct tpi_info *addr) return ccode; } -static inline int ssch(struct subchannel_id schid, - volatile struct orb *addr) -{ - register struct subchannel_id reg1 asm ("1") = schid; - int ccode; - - asm volatile( - " ssch 0(%2)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); - return ccode; -} - -static inline int rsch(struct subchannel_id schid) -{ - register struct subchannel_id reg1 asm ("1") = schid; - int ccode; - - asm volatile( - " rsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); - return ccode; -} - -static inline int csch(struct subchannel_id schid) -{ - register struct subchannel_id reg1 asm ("1") = schid; - int ccode; - - asm volatile( - " csch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); - return ccode; -} - -static inline int hsch(struct subchannel_id schid) -{ - register struct subchannel_id reg1 asm ("1") = schid; - int ccode; - - asm volatile( - " hsch\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); - return ccode; -} - -static inline int xsch(struct subchannel_id schid) -{ - register struct subchannel_id reg1 asm ("1") = schid; - int ccode; - - asm volatile( - " .insn rre,0xb2760000,%1,0\n" - " ipm %0\n" - " srl %0,28" - : "=d" (ccode) : "d" (reg1) : "cc"); - return ccode; -} - static inline int chsc(void *chsc_area) { typedef struct { char _[4096]; } addr_type; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 40a3208c7cf3..e2a781b6b21d 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -48,11 +48,11 @@ #include <asm/debug.h> #include <asm/s390_rdev.h> #include <asm/qdio.h> +#include <asm/airq.h> #include "cio.h" #include "css.h" #include "device.h" -#include "airq.h" #include "qdio.h" #include "ioasm.h" #include "chsc.h" @@ -96,7 +96,7 @@ static debug_info_t *qdio_dbf_slsb_in; static volatile struct qdio_q *tiq_list=NULL; /* volatile as it could change during a while loop */ static DEFINE_SPINLOCK(ttiq_list_lock); -static int register_thinint_result; +static void *tiqdio_ind; static void tiqdio_tl(unsigned long); static DECLARE_TASKLET(tiqdio_tasklet,tiqdio_tl,0); @@ -399,7 +399,7 @@ qdio_get_indicator(void) { int i; - for (i=1;i<INDICATORS_PER_CACHELINE;i++) + for (i = 0; i < INDICATORS_PER_CACHELINE; i++) if (!indicator_used[i]) { indicator_used[i]=1; return indicators+i; @@ -1408,8 +1408,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) if (q->hydra_gives_outbound_pcis) { if (!q->siga_sync_done_on_thinints) { SYNC_MEMORY_ALL; - } else if ((!q->siga_sync_done_on_outb_tis)&& - (q->hydra_gives_outbound_pcis)) { + } else if (!q->siga_sync_done_on_outb_tis) { SYNC_MEMORY_ALL_OUTB; } } else { @@ -1911,8 +1910,7 @@ qdio_fill_thresholds(struct qdio_irq *irq_ptr, } } -static int -tiqdio_thinint_handler(void) +static void tiqdio_thinint_handler(void *ind, void *drv_data) { QDIO_DBF_TEXT4(0,trace,"thin_int"); @@ -1925,7 +1923,6 @@ tiqdio_thinint_handler(void) tiqdio_clear_global_summary(); tiqdio_inbound_checks(); - return 0; } static void @@ -2445,7 +2442,7 @@ tiqdio_set_subchannel_ind(struct qdio_irq *irq_ptr, int reset_to_zero) real_addr_dev_st_chg_ind=0; } else { real_addr_local_summary_bit= - virt_to_phys((volatile void *)indicators); + virt_to_phys((volatile void *)tiqdio_ind); real_addr_dev_st_chg_ind= virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind); } @@ -3740,23 +3737,25 @@ static void tiqdio_register_thinints(void) { char dbf_text[20]; - register_thinint_result= - s390_register_adapter_interrupt(&tiqdio_thinint_handler); - if (register_thinint_result) { - sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff)); + + tiqdio_ind = + s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL); + if (IS_ERR(tiqdio_ind)) { + sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind)); QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_PRINT_ERR("failed to register adapter handler " \ - "(rc=%i).\nAdapter interrupts might " \ + "(rc=%li).\nAdapter interrupts might " \ "not work. Continuing.\n", - register_thinint_result); + PTR_ERR(tiqdio_ind)); + tiqdio_ind = NULL; } } static void tiqdio_unregister_thinints(void) { - if (!register_thinint_result) - s390_unregister_adapter_interrupt(&tiqdio_thinint_handler); + if (tiqdio_ind) + s390_unregister_adapter_interrupt(tiqdio_ind); } static int @@ -3768,8 +3767,8 @@ qdio_get_qdio_memory(void) for (i=1;i<INDICATORS_PER_CACHELINE;i++) indicator_used[i]=0; indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE), - GFP_KERNEL); - if (!indicators) + GFP_KERNEL); + if (!indicators) return -ENOMEM; return 0; } @@ -3780,7 +3779,6 @@ qdio_release_qdio_memory(void) kfree(indicators); } - static void qdio_unregister_dbf_views(void) { diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 6d7aad18f6f0..37870e4e938e 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -57,7 +57,7 @@ of the queue to 0 */ #define QDIO_ESTABLISH_TIMEOUT (1*HZ) -#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10) +#define QDIO_ACTIVATE_TIMEOUT (5*HZ) #define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ) #define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ) #define QDIO_FORCE_CHECK_TIMEOUT (10*HZ) diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 3561982749e3..c3076217871e 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -2416,7 +2416,7 @@ init_ccw_bk(struct net_device *dev) privptr->p_buff_pages_perwrite); #endif if (p_buff==NULL) { - printk(KERN_INFO "%s:%s __get_free_pages" + printk(KERN_INFO "%s:%s __get_free_pages " "for writes buf failed : get is for %d pages\n", dev->name, __FUNCTION__, diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 0fd663b23d76..7bfe8d707a34 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1115,7 +1115,7 @@ list_modified: rc = lcs_send_setipm(card, ipm); spin_lock_irqsave(&card->ipm_lock, flags); if (rc) { - PRINT_INFO("Adding multicast address failed." + PRINT_INFO("Adding multicast address failed. " "Table possibly full!\n"); /* store ipm in failed list -> will be added * to ipm_list again, so a retry will be done diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index c7ea9381db9f..f3d893cfe61d 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -198,8 +198,7 @@ struct iucv_connection { /** * Linked list of all connection structs. */ -static struct list_head iucv_connection_list = - LIST_HEAD_INIT(iucv_connection_list); +static LIST_HEAD(iucv_connection_list); static DEFINE_RWLOCK(iucv_connection_rwlock); /** @@ -2089,6 +2088,11 @@ static struct attribute_group netiucv_drv_attr_group = { .attrs = netiucv_drv_attrs, }; +static struct attribute_group *netiucv_drv_attr_groups[] = { + &netiucv_drv_attr_group, + NULL, +}; + static void netiucv_banner(void) { PRINT_INFO("NETIUCV driver initialized\n"); @@ -2113,7 +2117,6 @@ static void __exit netiucv_exit(void) netiucv_unregister_device(dev); } - sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); driver_unregister(&netiucv_driver); iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); @@ -2133,6 +2136,7 @@ static int __init netiucv_init(void) if (rc) goto out_dbf; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); + netiucv_driver.groups = netiucv_drv_attr_groups; rc = driver_register(&netiucv_driver); if (rc) { PRINT_ERR("NETIUCV: failed to register driver.\n"); @@ -2140,18 +2144,9 @@ static int __init netiucv_init(void) goto out_iucv; } - rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); - if (rc) { - PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); - IUCV_DBF_TEXT_(setup, 2, - "ret %d - netiucv_drv_attr_group\n", rc); - goto out_driver; - } netiucv_banner(); return rc; -out_driver: - driver_unregister(&netiucv_driver); out_iucv: iucv_unregister(&netiucv_handler, 1); out_dbf: diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index ff999ff0b627..62606ce26e55 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -3890,7 +3890,7 @@ qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card) break; } } - if (rc && !(VLAN_DEV_INFO(dev)->real_dev->priv == (void *)card)) + if (rc && !(vlan_dev_info(dev)->real_dev->priv == (void *)card)) return 0; #endif @@ -3930,7 +3930,7 @@ qeth_get_card_from_dev(struct net_device *dev) card = (struct qeth_card *)dev->priv; else if (rc == QETH_VLAN_CARD) card = (struct qeth_card *) - VLAN_DEV_INFO(dev)->real_dev->priv; + vlan_dev_info(dev)->real_dev->priv; QETH_DBF_TEXT_(trace, 4, "%d", rc); return card ; @@ -8340,7 +8340,7 @@ qeth_arp_constructor(struct neighbour *neigh) neigh->parms = neigh_parms_clone(parms); rcu_read_unlock(); - neigh->type = inet_addr_type(*(__be32 *) neigh->primary_key); + neigh->type = inet_addr_type(&init_net, *(__be32 *) neigh->primary_key); neigh->nud_state = NUD_NOARP; neigh->ops = arp_direct_ops; neigh->output = neigh->ops->queue_xmit; diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c index f1ff165a5e05..46ecd03a597e 100644 --- a/drivers/s390/net/qeth_proc.c +++ b/drivers/s390/net/qeth_proc.c @@ -146,7 +146,7 @@ qeth_procfile_seq_show(struct seq_file *s, void *it) return 0; } -static struct seq_operations qeth_procfile_seq_ops = { +static const struct seq_operations qeth_procfile_seq_ops = { .start = qeth_procfile_seq_start, .stop = qeth_procfile_seq_stop, .next = qeth_procfile_seq_next, @@ -264,7 +264,7 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it) return 0; } -static struct seq_operations qeth_perf_procfile_seq_ops = { +static const struct seq_operations qeth_perf_procfile_seq_ops = { .start = qeth_procfile_seq_start, .stop = qeth_procfile_seq_stop, .next = qeth_procfile_seq_next, diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 47bb47b48581..8735a415a116 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -42,7 +42,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); static struct iucv_path *smsg_path; static DEFINE_SPINLOCK(smsg_list_lock); -static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); +static LIST_HEAD(smsg_list); static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); static void smsg_message_pending(struct iucv_path *, struct iucv_message *); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 00118499018b..874b55ed00a3 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -844,8 +844,6 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); - init_waitqueue_head(&unit->scsi_scan_wq); - /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index e01cbf152a81..edc5015e920d 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -52,6 +52,9 @@ static struct ccw_driver zfcp_ccw_driver = { .set_offline = zfcp_ccw_set_offline, .notify = zfcp_ccw_notify, .shutdown = zfcp_ccw_shutdown, + .driver = { + .groups = zfcp_driver_attr_groups, + }, }; MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id); @@ -120,6 +123,9 @@ zfcp_ccw_remove(struct ccw_device *ccw_device) list_for_each_entry_safe(port, p, &adapter->port_remove_lh, list) { list_for_each_entry_safe(unit, u, &port->unit_remove_lh, list) { + if (atomic_test_mask(ZFCP_STATUS_UNIT_REGISTERED, + &unit->status)) + scsi_remove_device(unit->device); zfcp_unit_dequeue(unit); } zfcp_port_dequeue(port); @@ -251,16 +257,7 @@ zfcp_ccw_notify(struct ccw_device *ccw_device, int event) int __init zfcp_ccw_register(void) { - int retval; - - retval = ccw_driver_register(&zfcp_ccw_driver); - if (retval) - goto out; - retval = zfcp_sysfs_driver_create_files(&zfcp_ccw_driver.driver); - if (retval) - ccw_driver_unregister(&zfcp_ccw_driver); - out: - return retval; + return ccw_driver_register(&zfcp_ccw_driver); } /** diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index ffa3bf756943..701046c9bb33 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -161,12 +161,6 @@ void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) { strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE); level = 4; - } else if ((prot_status_qual->doubleword[0] != 0) || - (prot_status_qual->doubleword[1] != 0) || - (fsf_status_qual->doubleword[0] != 0) || - (fsf_status_qual->doubleword[1] != 0)) { - strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE); - level = 3; } else { strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE); level = 6; diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index e268f79bdbd2..9e9f6c1e4e5d 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -118,7 +118,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) #define ZFCP_SBAL_TIMEOUT (5*HZ) -#define ZFCP_TYPE2_RECOVERY_TIME (8*HZ) +#define ZFCP_TYPE2_RECOVERY_TIME 8 /* seconds */ /* queue polling (values in microseconds) */ #define ZFCP_MAX_INPUT_THRESHOLD 5000 /* FIXME: tune */ @@ -139,7 +139,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list, unsigned int size) #define ZFCP_STATUS_READS_RECOM FSF_STATUS_READS_RECOM /* Do 1st retry in 1 second, then double the timeout for each following retry */ -#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 100 +#define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 1 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7 /* timeout value for "default timer" for fsf requests */ @@ -983,10 +983,6 @@ struct zfcp_unit { struct scsi_device *device; /* scsi device struct pointer */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; - wait_queue_head_t scsi_scan_wq; /* can be used to wait until - all scsi_scan_target - requests have been - completed. */ }; /* FSF request */ @@ -1127,6 +1123,20 @@ zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id) return NULL; } +static inline struct zfcp_fsf_req * +zfcp_reqlist_find_safe(struct zfcp_adapter *adapter, struct zfcp_fsf_req *req) +{ + struct zfcp_fsf_req *request; + unsigned int idx; + + for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) { + list_for_each_entry(request, &adapter->req_list[idx], list) + if (request == req) + return request; + } + return NULL; +} + /* * functions needed for reference/usage counting */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 07fa824d179f..2dc8110ebf74 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -131,7 +131,7 @@ static void zfcp_close_qdio(struct zfcp_adapter *adapter) debug_text_event(adapter->erp_dbf, 3, "qdio_down2a"); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - msleep(1000); + ssleep(1); debug_text_event(adapter->erp_dbf, 3, "qdio_down2b"); /* cleanup used outbound sbals */ @@ -456,7 +456,7 @@ zfcp_test_link(struct zfcp_port *port) zfcp_port_get(port); retval = zfcp_erp_adisc(port); - if (retval != 0) { + if (retval != 0 && retval != -EBUSY) { zfcp_port_put(port); ZFCP_LOG_NORMAL("reopen needed for port 0x%016Lx " "on adapter %s\n ", port->wwpn, @@ -846,7 +846,8 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) if (erp_action->fsf_req) { /* take lock to ensure that request is not deleted meanwhile */ spin_lock(&adapter->req_list_lock); - if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) { + if (zfcp_reqlist_find_safe(adapter, erp_action->fsf_req) && + erp_action->fsf_req->erp_action == erp_action) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req, @@ -1285,7 +1286,7 @@ zfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action) * note: no lock in subsequent strategy routines * (this allows these routine to call schedule, e.g. * kmalloc with such flags or qdio_initialize & friends) - * Note: in case of timeout, the seperate strategies will fail + * Note: in case of timeout, the separate strategies will fail * anyhow. No need for a special action. Even worse, a nameserver * failure would not wake up waiting ports without the call. */ @@ -1609,7 +1610,6 @@ static void zfcp_erp_scsi_scan(struct work_struct *work) scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, unit->scsi_lun, 0); atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); - wake_up(&unit->scsi_scan_wq); zfcp_unit_put(unit); kfree(p); } @@ -1900,7 +1900,7 @@ zfcp_erp_adapter_strategy(struct zfcp_erp_action *erp_action) ZFCP_LOG_INFO("Waiting to allow the adapter %s " "to recover itself\n", zfcp_get_busid_by_adapter(adapter)); - msleep(jiffies_to_msecs(ZFCP_TYPE2_RECOVERY_TIME)); + ssleep(ZFCP_TYPE2_RECOVERY_TIME); } return retval; @@ -2080,7 +2080,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action) debug_text_event(adapter->erp_dbf, 3, "qdio_down1a"); while (qdio_shutdown(adapter->ccw_device, QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS) - msleep(1000); + ssleep(1); debug_text_event(adapter->erp_dbf, 3, "qdio_down1b"); failed_qdio_establish: @@ -2165,7 +2165,7 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) ZFCP_LOG_DEBUG("host connection still initialising... " "waiting and retrying...\n"); /* sleep a little bit before retry */ - msleep(jiffies_to_msecs(sleep)); + ssleep(sleep); sleep *= 2; } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 8534cf09546c..06b1079b7f3d 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -27,8 +27,7 @@ extern struct zfcp_data zfcp_data; /******************************** SYSFS *************************************/ -extern int zfcp_sysfs_driver_create_files(struct device_driver *); -extern void zfcp_sysfs_driver_remove_files(struct device_driver *); +extern struct attribute_group *zfcp_driver_attr_groups[]; extern int zfcp_sysfs_adapter_create_files(struct device *); extern void zfcp_sysfs_adapter_remove_files(struct device *); extern int zfcp_sysfs_port_create_files(struct device *, u32); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index ff866ebd44ac..0dff05840ee2 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -502,7 +502,7 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_NO_RECOM: - ZFCP_LOG_NORMAL("bug: No recommendation could be given for a" + ZFCP_LOG_NORMAL("bug: No recommendation could be given for a " "problem on the adapter %s " "Stopping all operations on this adapter. ", zfcp_get_busid_by_adapter(fsf_req->adapter)); @@ -813,7 +813,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) { - ZFCP_LOG_NORMAL("bug: Reopen port indication received for" + ZFCP_LOG_NORMAL("bug: Reopen port indication received for " "nonexisting port with d_id 0x%06x on " "adapter %s. Ignored.\n", status_buffer->d_id & ZFCP_DID_MASK, @@ -1116,6 +1116,10 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, goto out; } + if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &unit->status))) + goto unit_blocked; + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; @@ -1131,22 +1135,13 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); - if (retval) { - ZFCP_LOG_INFO("error: Failed to send abort command request " - "on adapter %s, port 0x%016Lx, unit 0x%016Lx\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, unit->fcp_lun); + if (!retval) + goto out; + + unit_blocked: zfcp_fsf_req_free(fsf_req); fsf_req = NULL; - goto out; - } - ZFCP_LOG_DEBUG("Abort FCP Command request initiated " - "(adapter%s, port d_id=0x%06x, " - "unit x%016Lx, old_req_id=0x%lx)\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->d_id, - unit->fcp_lun, old_req_id); out: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return fsf_req; @@ -1164,8 +1159,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) { int retval = -EINVAL; struct zfcp_unit *unit; - unsigned char status_qual = - new_fsf_req->qtcb->header.fsf_status_qual.word[0]; + union fsf_status_qual *fsf_stat_qual = + &new_fsf_req->qtcb->header.fsf_status_qual; if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { /* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */ @@ -1178,7 +1173,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) switch (new_fsf_req->qtcb->header.fsf_status) { case FSF_PORT_HANDLE_NOT_VALID: - if (status_qual >> 4 != status_qual % 0xf) { + if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { debug_text_event(new_fsf_req->adapter->erp_dbf, 3, "fsf_s_phand_nv0"); /* @@ -1207,8 +1202,7 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) break; case FSF_LUN_HANDLE_NOT_VALID: - if (status_qual >> 4 != status_qual % 0xf) { - /* 2 */ + if (fsf_stat_qual->word[0] != fsf_stat_qual->word[1]) { debug_text_event(new_fsf_req->adapter->erp_dbf, 3, "fsf_s_lhand_nv0"); /* @@ -1674,6 +1668,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) goto failed_req; } + if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &els->port->status))) { + ret = -EBUSY; + goto port_blocked; + } + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); if (zfcp_use_one_sbal(els->req, els->req_count, els->resp, els->resp_count)){ @@ -1755,6 +1755,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto out; + port_blocked: failed_send: zfcp_fsf_req_free(fsf_req); @@ -2280,7 +2281,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action) &lock_flags, &fsf_req); if (retval) { ZFCP_LOG_INFO("error: Out of resources. Could not create an " - "exchange port data request for" + "exchange port data request for " "the adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, @@ -2339,7 +2340,7 @@ zfcp_fsf_exchange_port_data_sync(struct zfcp_adapter *adapter, 0, NULL, &lock_flags, &fsf_req); if (retval) { ZFCP_LOG_INFO("error: Out of resources. Could not create an " - "exchange port data request for" + "exchange port data request for " "the adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); write_unlock_irqrestore(&adapter->request_queue.queue_lock, @@ -3592,6 +3593,12 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, goto failed_req_create; } + if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &unit->status))) { + retval = -EBUSY; + goto unit_blocked; + } + zfcp_unit_get(unit); fsf_req->unit = unit; @@ -3732,6 +3739,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, send_failed: no_fit: failed_scsi_cmnd: + unit_blocked: zfcp_unit_put(unit); zfcp_fsf_req_free(fsf_req); fsf_req = NULL; @@ -3766,6 +3774,10 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, goto out; } + if (unlikely(!atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, + &unit->status))) + goto unit_blocked; + /* * Used to decide on proper handler in the return path, * could be either zfcp_fsf_send_fcp_command_task_handler or @@ -3799,25 +3811,13 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT); retval = zfcp_fsf_req_send(fsf_req); - if (retval) { - ZFCP_LOG_INFO("error: Could not send an FCP-command (task " - "management) on adapter %s, port 0x%016Lx for " - "unit LUN 0x%016Lx\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, - unit->fcp_lun); - zfcp_fsf_req_free(fsf_req); - fsf_req = NULL; + if (!retval) goto out; - } - ZFCP_LOG_TRACE("Send FCP Command (task management function) initiated " - "(adapter %s, port 0x%016Lx, unit 0x%016Lx, " - "tm_flags=0x%x)\n", - zfcp_get_busid_by_adapter(adapter), - unit->port->wwpn, - unit->fcp_lun, - tm_flags); + unit_blocked: + zfcp_fsf_req_free(fsf_req); + fsf_req = NULL; + out: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return fsf_req; @@ -4224,10 +4224,10 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", fcp_rsp_iu->fcp_sns_len); - memcpy(&scpnt->sense_buffer, + memcpy(scpnt->sense_buffer, zfcp_get_fcp_sns_info_ptr(fcp_rsp_iu), sns_len); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, - (void *) &scpnt->sense_buffer, sns_len); + (void *)scpnt->sense_buffer, sns_len); } /* check for overrun */ @@ -4725,7 +4725,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, /* allocate new FSF request */ fsf_req = zfcp_fsf_req_alloc(pool, req_flags); if (unlikely(NULL == fsf_req)) { - ZFCP_LOG_DEBUG("error: Could not put an FSF request into" + ZFCP_LOG_DEBUG("error: Could not put an FSF request into " "the outbound (send) queue.\n"); ret = -ENOMEM; goto failed_fsf_req; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 51d92b196ee7..22fdc17e0d0e 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -529,7 +529,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) /** - * zfcp_qdio_sbale_fill - set address and lenght in current SBALE + * zfcp_qdio_sbale_fill - set address and length in current SBALE * on request_queue */ static void diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index abae2027f7e5..b9daf5c05862 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -51,7 +51,6 @@ struct zfcp_data zfcp_data = { .queuecommand = zfcp_scsi_queuecommand, .eh_abort_handler = zfcp_scsi_eh_abort_handler, .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler, - .eh_bus_reset_handler = zfcp_scsi_eh_host_reset_handler, .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler, .can_queue = 4096, .this_id = -1, @@ -181,9 +180,6 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) if (unit) { zfcp_erp_wait(unit->port->adapter); - wait_event(unit->scsi_scan_wq, - atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, - &unit->status) == 0); atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); sdpnt->hostdata = NULL; unit->device = NULL; @@ -262,8 +258,9 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, goto out; } - if (unlikely( - !atomic_test_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &unit->status))) { + tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer, + ZFCP_REQ_AUTO_CLEANUP); + if (unlikely(tmp == -EBUSY)) { ZFCP_LOG_DEBUG("adapter %s not ready or unit 0x%016Lx " "on port 0x%016Lx in recovery\n", zfcp_get_busid_by_unit(unit), @@ -272,9 +269,6 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit, goto out; } - tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer, - ZFCP_REQ_AUTO_CLEANUP); - if (unlikely(tmp < 0)) { ZFCP_LOG_DEBUG("error: initiation of Send FCP Cmnd failed\n"); retval = SCSI_MLQUEUE_HOST_BUSY; @@ -459,7 +453,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) retval = SUCCESS; goto out; } - ZFCP_LOG_NORMAL("resetting unit 0x%016Lx\n", unit->fcp_lun); + ZFCP_LOG_NORMAL("resetting unit 0x%016Lx on port 0x%016Lx, adapter %s\n", + unit->fcp_lun, unit->port->wwpn, + zfcp_get_busid_by_adapter(unit->port->adapter)); /* * If we do not know whether the unit supports 'logical unit reset' @@ -542,7 +538,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, } /** - * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset + * zfcp_scsi_eh_host_reset_handler - handler for host reset */ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { @@ -552,8 +548,10 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) unit = (struct zfcp_unit*) scpnt->device->hostdata; adapter = unit->port->adapter; - ZFCP_LOG_NORMAL("host/bus reset because of problems with " - "unit 0x%016Lx\n", unit->fcp_lun); + ZFCP_LOG_NORMAL("host reset because of problems with " + "unit 0x%016Lx on port 0x%016Lx, adapter %s\n", + unit->fcp_lun, unit->port->wwpn, + zfcp_get_busid_by_adapter(unit->port->adapter)); zfcp_erp_adapter_reopen(adapter, 0); zfcp_erp_wait(adapter); diff --git a/drivers/s390/scsi/zfcp_sysfs_driver.c b/drivers/s390/scsi/zfcp_sysfs_driver.c index 005e62f8593b..651edd58906a 100644 --- a/drivers/s390/scsi/zfcp_sysfs_driver.c +++ b/drivers/s390/scsi/zfcp_sysfs_driver.c @@ -98,28 +98,9 @@ static struct attribute_group zfcp_driver_attr_group = { .attrs = zfcp_driver_attrs, }; -/** - * zfcp_sysfs_create_driver_files - create sysfs driver files - * @dev: pointer to belonging device - * - * Create all sysfs attributes of the zfcp device driver - */ -int -zfcp_sysfs_driver_create_files(struct device_driver *drv) -{ - return sysfs_create_group(&drv->kobj, &zfcp_driver_attr_group); -} - -/** - * zfcp_sysfs_remove_driver_files - remove sysfs driver files - * @dev: pointer to belonging device - * - * Remove all sysfs attributes of the zfcp device driver - */ -void -zfcp_sysfs_driver_remove_files(struct device_driver *drv) -{ - sysfs_remove_group(&drv->kobj, &zfcp_driver_attr_group); -} +struct attribute_group *zfcp_driver_attr_groups[] = { + &zfcp_driver_attr_group, + NULL, +}; #undef ZFCP_LOG_AREA diff --git a/drivers/scsi/.gitignore b/drivers/scsi/.gitignore index b385af314356..c89ae9a04399 100644 --- a/drivers/scsi/.gitignore +++ b/drivers/scsi/.gitignore @@ -1,3 +1 @@ 53c700_d.h -53c7xx_d.h -53c7xx_u.h diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index afb262b4be15..b4912d1cee2a 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1990,7 +1990,6 @@ static struct scsi_host_template driver_template = { .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = twa_host_attrs, .emulated = 1 }; @@ -2010,6 +2009,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id } pci_set_master(pdev); + pci_try_set_mwi(pdev); if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 59716ebeb10c..d09532162217 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2261,7 +2261,6 @@ static struct scsi_host_template driver_template = { .max_sectors = TW_MAX_SECTORS, .cmd_per_lun = TW_MAX_CMDS_PER_LUN, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = tw_host_attrs, .emulated = 1 }; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 71ff3fbfce12..f4c4fe90240a 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -608,7 +608,8 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, scsi_print_sense("53c700", SCp); #endif - dma_unmap_single(hostdata->dev, slot->dma_handle, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); + dma_unmap_single(hostdata->dev, slot->dma_handle, + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); /* restore the old result if the request sense was * successful */ if (result == 0) @@ -1010,7 +1011,7 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, cmnd[1] = (SCp->device->lun & 0x7) << 5; cmnd[2] = 0; cmnd[3] = 0; - cmnd[4] = sizeof(SCp->sense_buffer); + cmnd[4] = SCSI_SENSE_BUFFERSIZE; cmnd[5] = 0; /* Here's a quiet hack: the * REQUEST_SENSE command is six bytes, @@ -1024,14 +1025,14 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, SCp->cmd_len = 6; /* command length for * REQUEST_SENSE */ slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); - slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); - slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); + slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); + slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE); slot->SG[0].pAddr = bS_to_host(slot->dma_handle); slot->SG[1].ins = bS_to_host(SCRIPT_RETURN); slot->SG[1].pAddr = 0; slot->resume_offset = hostdata->pScript; dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE); - dma_cache_sync(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); + dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); /* queue the command for reissue */ slot->state = NCR_700_SLOT_QUEUED; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 49e1ffa4b2ff..4d3ebb1af490 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2947,7 +2947,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou } } memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataLength = sizeof(Command->sense_buffer); + CCB->SenseDataLength = SCSI_SENSE_BUFFERSIZE; CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE); CCB->Command = Command; Command->scsi_done = CompletionRoutine; @@ -3575,7 +3575,6 @@ static struct scsi_host_template Bus_Logic_template = { .unchecked_isa_dma = 1, .max_sectors = 128, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; /* diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 184c7ae78519..14fc7f39e83e 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -341,11 +341,11 @@ config ISCSI_TCP The userspace component needed to initialize the driver, documentation, and sample configuration files can be found here: - http://linux-iscsi.sf.net + http://open-iscsi.org config SGIWD93_SCSI tristate "SGI WD93C93 SCSI Driver" - depends on SGI_IP22 && SCSI + depends on SGI_HAS_WD93 && SCSI help If you have a Western Digital WD93 SCSI controller on an SGI MIPS system, say Y. Otherwise, say N. @@ -573,10 +573,10 @@ config SCSI_ARCMSR_AER source "drivers/scsi/megaraid/Kconfig.megaraid" config SCSI_HPTIOP - tristate "HighPoint RocketRAID 3xxx Controller support" + tristate "HighPoint RocketRAID 3xxx/4xxx Controller support" depends on SCSI && PCI help - This option enables support for HighPoint RocketRAID 3xxx + This option enables support for HighPoint RocketRAID 3xxx/4xxx controllers. To compile this driver as a module, choose M here; the module @@ -1288,17 +1288,6 @@ config SCSI_PAS16 To compile this driver as a module, choose M here: the module will be called pas16. -config SCSI_PSI240I - tristate "PSI240i support" - depends on ISA && SCSI - help - This is support for the PSI240i EIDE interface card which acts as a - SCSI host adapter. Please read the SCSI-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - To compile this driver as a module, choose M here: the - module will be called psi240i. - config SCSI_QLOGIC_FAS tristate "Qlogic FAS SCSI support" depends on ISA && SCSI @@ -1359,21 +1348,6 @@ config SCSI_LPFC This lpfc driver supports the Emulex LightPulse Family of Fibre Channel PCI host adapters. -config SCSI_SEAGATE - tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support" - depends on X86 && ISA && SCSI - select CHECK_SIGNATURE - ---help--- - These are 8-bit SCSI controllers; the ST-01 is also supported by - this driver. It is explained in section 3.9 of the SCSI-HOWTO, - available from <http://www.tldp.org/docs.html#howto>. If it - doesn't work out of the box, you may have to change some macros at - compiletime, which are described in <file:drivers/scsi/seagate.c>. - - To compile this driver as a module, choose M here: the - module will be called seagate. - -# definitely looks not 64bit safe: config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" depends on (EISA || MCA) && SCSI diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 2e6129f13d38..93e1428d03fc 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -16,9 +16,8 @@ CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS -CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM -subdir-$(CONFIG_PCMCIA) += pcmcia +obj-$(CONFIG_PCMCIA) += pcmcia/ obj-$(CONFIG_SCSI) += scsi_mod.o obj-$(CONFIG_SCSI_TGT) += scsi_tgt.o @@ -59,7 +58,6 @@ obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o -obj-$(CONFIG_SCSI_PSI240I) += psi240i.o obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o @@ -90,7 +88,6 @@ obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/ obj-$(CONFIG_SCSI_LPFC) += lpfc/ obj-$(CONFIG_SCSI_PAS16) += pas16.o -obj-$(CONFIG_SCSI_SEAGATE) += seagate.o obj-$(CONFIG_SCSI_T128) += t128.o obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o obj-$(CONFIG_SCSI_DTC3280) += dtc.o diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 2597209183d0..eeddbd19eba5 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -295,16 +295,16 @@ static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) * various queues are valid. */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } } @@ -932,7 +932,7 @@ static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags) * @instance: adapter to remove */ -static void __devexit NCR5380_exit(struct Scsi_Host *instance) +static void NCR5380_exit(struct Scsi_Host *instance) { struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; @@ -975,14 +975,14 @@ static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingr++; break; } @@ -1157,16 +1157,17 @@ static void NCR5380_main(struct work_struct *work) * Locks: takes the needed instance locks */ -static irqreturn_t NCR5380_intr(int irq, void *dev_id) +static irqreturn_t NCR5380_intr(int dummy, void *dev_id) { NCR5380_local_declare(); - struct Scsi_Host *instance = (struct Scsi_Host *)dev_id; + struct Scsi_Host *instance = dev_id; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; int done; unsigned char basr; unsigned long flags; - dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq)); + dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", + instance->irq)); do { done = 1; diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index 137d065db3da..6961f78742ae 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -1065,7 +1065,6 @@ static struct scsi_host_template driver_template = .cmd_per_lun = 1 /* commands per lun */, .unchecked_isa_dma = 1 /* unchecked_isa_dma */, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index d3a6d15fb77a..f608d4a1d6da 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -1071,7 +1071,6 @@ static struct scsi_host_template inia100_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static int __devinit inia100_probe_one(struct pci_dev *pdev, diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index b7c5385e2efe..23f27c9c9895 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -73,18 +73,9 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in) } if (!dir_in) { - /* copy to bounce buffer for a write */ - if (cmd->use_sg) -#if 0 - panic ("scsi%ddma: incomplete s/g support", - instance->host_no); -#else + /* copy to bounce buffer for a write */ memcpy (HDATA(instance)->dma_bounce_buffer, cmd->SCp.ptr, cmd->SCp.this_residual); -#endif - else - memcpy (HDATA(instance)->dma_bounce_buffer, - cmd->request_buffer, cmd->request_bufflen); } } @@ -144,30 +135,13 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, /* copy from a bounce buffer, if necessary */ if (status && HDATA(instance)->dma_bounce_buffer) { - if (SCpnt && SCpnt->use_sg) { -#if 0 - panic ("scsi%d: incomplete s/g support", - instance->host_no); -#else - if( HDATA(instance)->dma_dir ) + if( HDATA(instance)->dma_dir ) memcpy (SCpnt->SCp.ptr, HDATA(instance)->dma_bounce_buffer, SCpnt->SCp.this_residual); - kfree (HDATA(instance)->dma_bounce_buffer); - HDATA(instance)->dma_bounce_buffer = NULL; - HDATA(instance)->dma_bounce_len = 0; - -#endif - } else { - if (HDATA(instance)->dma_dir && SCpnt) - memcpy (SCpnt->request_buffer, - HDATA(instance)->dma_bounce_buffer, - SCpnt->request_bufflen); - - kfree (HDATA(instance)->dma_bounce_buffer); - HDATA(instance)->dma_bounce_buffer = NULL; - HDATA(instance)->dma_bounce_len = 0; - } + kfree (HDATA(instance)->dma_bounce_buffer); + HDATA(instance)->dma_bounce_buffer = NULL; + HDATA(instance)->dma_bounce_len = 0; } } diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 796f1c4d772e..d7255c8bf281 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -70,12 +70,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in) if (!dir_in) { /* copy to bounce buffer for a write */ - if (cmd->use_sg) { - memcpy (HDATA(a3000_host)->dma_bounce_buffer, - cmd->SCp.ptr, cmd->SCp.this_residual); - } else - memcpy (HDATA(a3000_host)->dma_bounce_buffer, - cmd->request_buffer, cmd->request_bufflen); + memcpy (HDATA(a3000_host)->dma_bounce_buffer, + cmd->SCp.ptr, cmd->SCp.this_residual); } addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer); @@ -146,7 +142,7 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, /* copy from a bounce buffer, if necessary */ if (status && HDATA(instance)->dma_bounce_buffer) { - if (SCpnt && SCpnt->use_sg) { + if (SCpnt) { if (HDATA(instance)->dma_dir && SCpnt) memcpy (SCpnt->SCp.ptr, HDATA(instance)->dma_bounce_buffer, @@ -155,11 +151,6 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, HDATA(instance)->dma_bounce_buffer = NULL; HDATA(instance)->dma_bounce_len = 0; } else { - if (HDATA(instance)->dma_dir && SCpnt) - memcpy (SCpnt->request_buffer, - HDATA(instance)->dma_bounce_buffer, - SCpnt->request_bufflen); - kfree (HDATA(instance)->dma_bounce_buffer); HDATA(instance)->dma_bounce_buffer = NULL; HDATA(instance)->dma_bounce_len = 0; diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index a77ab8d693d4..d7235f42cf5f 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -31,9 +31,9 @@ #include <linux/slab.h> #include <linux/completion.h> #include <linux/blkdev.h> -#include <linux/dma-mapping.h> #include <asm/semaphore.h> #include <asm/uaccess.h> +#include <linux/highmem.h> /* For flush_kernel_dcache_page */ #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -56,54 +56,54 @@ /* * Sense codes */ - -#define SENCODE_NO_SENSE 0x00 -#define SENCODE_END_OF_DATA 0x00 -#define SENCODE_BECOMING_READY 0x04 -#define SENCODE_INIT_CMD_REQUIRED 0x04 -#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A -#define SENCODE_INVALID_COMMAND 0x20 -#define SENCODE_LBA_OUT_OF_RANGE 0x21 -#define SENCODE_INVALID_CDB_FIELD 0x24 -#define SENCODE_LUN_NOT_SUPPORTED 0x25 -#define SENCODE_INVALID_PARAM_FIELD 0x26 -#define SENCODE_PARAM_NOT_SUPPORTED 0x26 -#define SENCODE_PARAM_VALUE_INVALID 0x26 -#define SENCODE_RESET_OCCURRED 0x29 -#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E -#define SENCODE_INQUIRY_DATA_CHANGED 0x3F -#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 -#define SENCODE_DIAGNOSTIC_FAILURE 0x40 -#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 -#define SENCODE_INVALID_MESSAGE_ERROR 0x49 -#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c -#define SENCODE_OVERLAPPED_COMMAND 0x4E + +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E /* * Additional sense codes */ - -#define ASENCODE_NO_SENSE 0x00 -#define ASENCODE_END_OF_DATA 0x05 -#define ASENCODE_BECOMING_READY 0x01 -#define ASENCODE_INIT_CMD_REQUIRED 0x02 -#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 -#define ASENCODE_INVALID_COMMAND 0x00 -#define ASENCODE_LBA_OUT_OF_RANGE 0x00 -#define ASENCODE_INVALID_CDB_FIELD 0x00 -#define ASENCODE_LUN_NOT_SUPPORTED 0x00 -#define ASENCODE_INVALID_PARAM_FIELD 0x00 -#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 -#define ASENCODE_PARAM_VALUE_INVALID 0x02 -#define ASENCODE_RESET_OCCURRED 0x00 -#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 -#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 -#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 -#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 -#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 -#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 -#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 -#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 #define BYTE0(x) (unsigned char)(x) #define BYTE1(x) (unsigned char)((x) >> 8) @@ -115,8 +115,8 @@ *----------------------------------------------------------------------------*/ /* SCSI inquiry data */ struct inquiry_data { - u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ - u8 inqd_dtq; /* RMB | Device Type Qualifier */ + u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + u8 inqd_dtq; /* RMB | Device Type Qualifier */ u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ u8 inqd_len; /* Additional length (n-4) */ @@ -130,7 +130,7 @@ struct inquiry_data { /* * M O D U L E G L O B A L S */ - + static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap); static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg); static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg); @@ -141,9 +141,10 @@ static char *aac_get_status_string(u32 status); /* * Non dasd selection is handled entirely in aachba now - */ - + */ + static int nondasd = -1; +static int aac_cache = 0; static int dacmode = -1; int aac_commit = -1; @@ -152,6 +153,8 @@ int aif_timeout = 120; module_param(nondasd, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); +module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache"); module_param(dacmode, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR); @@ -179,7 +182,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health che int aac_check_reset = 1; module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter."); +MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it."); int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); @@ -193,12 +196,12 @@ static inline int aac_valid_context(struct scsi_cmnd *scsicmd, struct fib *fibptr) { struct scsi_device *device; - if (unlikely(!scsicmd || !scsicmd->scsi_done )) { + if (unlikely(!scsicmd || !scsicmd->scsi_done)) { dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n")); - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - return 0; - } + aac_fib_complete(fibptr); + aac_fib_free(fibptr); + return 0; + } scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; device = scsicmd->device; if (unlikely(!device || !scsi_device_online(device))) { @@ -240,7 +243,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag) FsaNormal, 1, 1, NULL, NULL); - if (status < 0 ) { + if (status < 0) { printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n"); } else { struct aac_get_config_status_resp *reply @@ -264,10 +267,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag) struct aac_commit_config * dinfo; aac_fib_init(fibptr); dinfo = (struct aac_commit_config *) fib_data(fibptr); - + dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG); - + status = aac_fib_send(ContainerCommand, fibptr, sizeof (struct aac_commit_config), @@ -293,7 +296,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag) int aac_get_containers(struct aac_dev *dev) { struct fsa_dev_info *fsa_dev_ptr; - u32 index; + u32 index; int status = 0; struct fib * fibptr; struct aac_get_container_count *dinfo; @@ -363,6 +366,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne if (buf && transfer_len > 0) memcpy(buf + offset, data, transfer_len); + flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset)); kunmap_atomic(buf - sg->offset, KM_IRQ0); } @@ -395,7 +399,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr) do { *dp++ = (*sp) ? *sp++ : ' '; } while (--count > 0); - aac_internal_transfer(scsicmd, d, + aac_internal_transfer(scsicmd, d, offsetof(struct inquiry_data, inqd_pid), sizeof(d)); } } @@ -431,13 +435,13 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data)); status = aac_fib_send(ContainerCommand, - cmd_fibcontext, + cmd_fibcontext, sizeof (struct aac_get_name), - FsaNormal, - 0, 1, - (fib_callback) get_container_name_callback, + FsaNormal, + 0, 1, + (fib_callback)get_container_name_callback, (void *) scsicmd); - + /* * Check that the command queued to the controller */ @@ -445,7 +449,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; } - + printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); aac_fib_complete(cmd_fibcontext); aac_fib_free(cmd_fibcontext); @@ -652,42 +656,47 @@ struct scsi_inq { * @a: string to copy from * @b: string to copy to * - * Copy a String from one location to another + * Copy a String from one location to another * without copying \0 */ static void inqstrcpy(char *a, char *b) { - while(*a != (char)0) + while (*a != (char)0) *b++ = *a++; } static char *container_types[] = { - "None", - "Volume", - "Mirror", - "Stripe", - "RAID5", - "SSRW", - "SSRO", - "Morph", - "Legacy", - "RAID4", - "RAID10", - "RAID00", - "V-MIRRORS", - "PSEUDO R4", + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", "RAID50", "RAID5D", "RAID5D0", "RAID1E", "RAID6", "RAID60", - "Unknown" + "Unknown" }; - +char * get_container_type(unsigned tindex) +{ + if (tindex >= ARRAY_SIZE(container_types)) + tindex = ARRAY_SIZE(container_types) - 1; + return container_types[tindex]; +} /* Function: setinqstr * @@ -707,16 +716,21 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex) if (dev->supplement_adapter_info.AdapterTypeText[0]) { char * cp = dev->supplement_adapter_info.AdapterTypeText; - int c = sizeof(str->vid); - while (*cp && *cp != ' ' && --c) - ++cp; - c = *cp; - *cp = '\0'; - inqstrcpy (dev->supplement_adapter_info.AdapterTypeText, - str->vid); - *cp = c; - while (*cp && *cp != ' ') - ++cp; + int c; + if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C')) + inqstrcpy("SMC", str->vid); + else { + c = sizeof(str->vid); + while (*cp && *cp != ' ' && --c) + ++cp; + c = *cp; + *cp = '\0'; + inqstrcpy (dev->supplement_adapter_info.AdapterTypeText, + str->vid); + *cp = c; + while (*cp && *cp != ' ') + ++cp; + } while (*cp == ' ') ++cp; /* last six chars reserved for vol type */ @@ -898,9 +912,8 @@ static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(cmd->sense_buffer)) - ? sizeof(cmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); + min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); cmd->scsi_done(cmd); return 1; } @@ -981,7 +994,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 aac_fib_init(fib); readcmd = (struct aac_read *) fib_data(fib); readcmd->command = cpu_to_le32(VM_CtBlockRead); - readcmd->cid = cpu_to_le16(scmd_id(cmd)); + readcmd->cid = cpu_to_le32(scmd_id(cmd)); readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); readcmd->count = cpu_to_le32(count * 512); @@ -1013,7 +1026,8 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); writecmd->count = cpu_to_le32(count<<9); writecmd->cid = cpu_to_le16(scmd_id(cmd)); - writecmd->flags = fua ? + writecmd->flags = (fua && ((aac_cache & 5) != 1) && + (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ? cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) : cpu_to_le16(IO_TYPE_WRITE); writecmd->bpTotal = 0; @@ -1072,7 +1086,7 @@ static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3 aac_fib_init(fib); writecmd = (struct aac_write *) fib_data(fib); writecmd->command = cpu_to_le32(VM_CtBlockWrite); - writecmd->cid = cpu_to_le16(scmd_id(cmd)); + writecmd->cid = cpu_to_le32(scmd_id(cmd)); writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); writecmd->count = cpu_to_le32(count * 512); writecmd->sg.count = cpu_to_le32(1); @@ -1190,6 +1204,15 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) (fib_callback) aac_srb_callback, (void *) cmd); } +static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) +{ + if ((sizeof(dma_addr_t) > 4) && + (num_physpages > (0xFFFFFFFFULL >> PAGE_SHIFT)) && + (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) + return FAILED; + return aac_scsi_32(fib, cmd); +} + int aac_get_adapter_info(struct aac_dev* dev) { struct fib* fibptr; @@ -1207,11 +1230,11 @@ int aac_get_adapter_info(struct aac_dev* dev) memset(info,0,sizeof(*info)); rcode = aac_fib_send(RequestAdapterInfo, - fibptr, + fibptr, sizeof(*info), - FsaNormal, + FsaNormal, -1, 1, /* First `interrupt' command uses special wait */ - NULL, + NULL, NULL); if (rcode < 0) { @@ -1222,29 +1245,29 @@ int aac_get_adapter_info(struct aac_dev* dev) memcpy(&dev->adapter_info, info, sizeof(*info)); if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) { - struct aac_supplement_adapter_info * info; + struct aac_supplement_adapter_info * sinfo; aac_fib_init(fibptr); - info = (struct aac_supplement_adapter_info *) fib_data(fibptr); + sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr); - memset(info,0,sizeof(*info)); + memset(sinfo,0,sizeof(*sinfo)); rcode = aac_fib_send(RequestSupplementAdapterInfo, fibptr, - sizeof(*info), + sizeof(*sinfo), FsaNormal, 1, 1, NULL, NULL); if (rcode >= 0) - memcpy(&dev->supplement_adapter_info, info, sizeof(*info)); + memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo)); } - /* - * GetBusInfo + /* + * GetBusInfo */ aac_fib_init(fibptr); @@ -1267,6 +1290,8 @@ int aac_get_adapter_info(struct aac_dev* dev) 1, 1, NULL, NULL); + /* reasoned default */ + dev->maximum_num_physicals = 16; if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) { dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus); dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount); @@ -1276,7 +1301,7 @@ int aac_get_adapter_info(struct aac_dev* dev) char buffer[16]; tmp = le32_to_cpu(dev->adapter_info.kernelrev); printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n", - dev->name, + dev->name, dev->id, tmp>>24, (tmp>>16)&0xff, @@ -1305,19 +1330,21 @@ int aac_get_adapter_info(struct aac_dev* dev) (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), dev->supplement_adapter_info.VpdInfo.Tsid); } - if (!aac_check_reset || + if (!aac_check_reset || ((aac_check_reset != 1) && (dev->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_IGNORE_RESET))) { + AAC_OPTION_IGNORE_RESET))) { printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", dev->name, dev->id); } } + dev->cache_protected = 0; + dev->jbod = ((dev->supplement_adapter_info.FeatureBits & + AAC_FEATURE_JBOD) != 0); dev->nondasd_support = 0; dev->raid_scsi_mode = 0; - if(dev->adapter_info.options & AAC_OPT_NONDASD){ + if(dev->adapter_info.options & AAC_OPT_NONDASD) dev->nondasd_support = 1; - } /* * If the firmware supports ROMB RAID/SCSI mode and we are currently @@ -1338,11 +1365,10 @@ int aac_get_adapter_info(struct aac_dev* dev) if (dev->raid_scsi_mode != 0) printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n", dev->name, dev->id); - - if(nondasd != -1) { + + if (nondasd != -1) dev->nondasd_support = (nondasd!=0); - } - if(dev->nondasd_support != 0){ + if(dev->nondasd_support != 0) { printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); } @@ -1371,12 +1397,14 @@ int aac_get_adapter_info(struct aac_dev* dev) rcode = -ENOMEM; } } - /* + /* * Deal with configuring for the individualized limits of each packet * interface. */ dev->a_ops.adapter_scsi = (dev->dac_support) - ? aac_scsi_64 + ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32) + ? aac_scsi_32_64 + : aac_scsi_64) : aac_scsi_32; if (dev->raw_io_interface) { dev->a_ops.adapter_bounds = (dev->raw_io_64) @@ -1393,8 +1421,8 @@ int aac_get_adapter_info(struct aac_dev* dev) if (dev->dac_support) { dev->a_ops.adapter_read = aac_read_block64; dev->a_ops.adapter_write = aac_write_block64; - /* - * 38 scatter gather elements + /* + * 38 scatter gather elements */ dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - @@ -1498,9 +1526,8 @@ static void io_callback(void *context, struct fib * fibptr) ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer)) - ? sizeof(scsicmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); + min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); } aac_fib_complete(fibptr); aac_fib_free(fibptr); @@ -1524,7 +1551,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) case READ_6: dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd))); - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | + lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; count = scsicmd->cmnd[4]; @@ -1534,32 +1561,32 @@ static int aac_read(struct scsi_cmnd * scsicmd) case READ_16: dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd))); - lba = ((u64)scsicmd->cmnd[2] << 56) | - ((u64)scsicmd->cmnd[3] << 48) | + lba = ((u64)scsicmd->cmnd[2] << 56) | + ((u64)scsicmd->cmnd[3] << 48) | ((u64)scsicmd->cmnd[4] << 40) | ((u64)scsicmd->cmnd[5] << 32) | - ((u64)scsicmd->cmnd[6] << 24) | + ((u64)scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; - count = (scsicmd->cmnd[10] << 24) | + count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) | (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; break; case READ_12: dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd))); - lba = ((u64)scsicmd->cmnd[2] << 24) | + lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - count = (scsicmd->cmnd[6] << 24) | + (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; + count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) | - (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; + (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; break; default: dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd))); - lba = ((u64)scsicmd->cmnd[2] << 24) | - (scsicmd->cmnd[3] << 16) | + lba = ((u64)scsicmd->cmnd[2] << 24) | + (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; break; @@ -1584,7 +1611,7 @@ static int aac_read(struct scsi_cmnd * scsicmd) scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; return 0; } - + printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); /* * For some reason, the Fib didn't queue, return QUEUE_FULL @@ -1619,11 +1646,11 @@ static int aac_write(struct scsi_cmnd * scsicmd) } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */ dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd))); - lba = ((u64)scsicmd->cmnd[2] << 56) | + lba = ((u64)scsicmd->cmnd[2] << 56) | ((u64)scsicmd->cmnd[3] << 48) | ((u64)scsicmd->cmnd[4] << 40) | ((u64)scsicmd->cmnd[5] << 32) | - ((u64)scsicmd->cmnd[6] << 24) | + ((u64)scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) | @@ -1712,8 +1739,8 @@ static void synchronize_callback(void *context, struct fib *fibptr) ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, 0, 0); memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min(sizeof(dev->fsa_dev[cid].sense_data), - sizeof(cmd->sense_buffer))); + min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); } aac_fib_complete(fibptr); @@ -1798,7 +1825,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) if (active) return SCSI_MLQUEUE_DEVICE_BUSY; - aac = (struct aac_dev *)scsicmd->device->host->hostdata; + aac = (struct aac_dev *)sdev->host->hostdata; if (aac->in_reset) return SCSI_MLQUEUE_HOST_BUSY; @@ -1850,14 +1877,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd) * Emulate a SCSI command and queue the required request for the * aacraid firmware. */ - + int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { u32 cid; struct Scsi_Host *host = scsicmd->device->host; struct aac_dev *dev = (struct aac_dev *)host->hostdata; struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; - + if (fsa_dev_ptr == NULL) return -1; /* @@ -1898,7 +1925,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) } } } else { /* check for physical non-dasd devices */ - if ((dev->nondasd_support == 1) || expose_physicals) { + if (dev->nondasd_support || expose_physicals || + dev->jbod) { if (dev->in_reset) return -1; return aac_send_srb_fib(scsicmd); @@ -1913,7 +1941,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * else Command for the controller itself */ else if ((scsicmd->cmnd[0] != INQUIRY) && /* only INQUIRY & TUR cmnd supported for controller */ - (scsicmd->cmnd[0] != TEST_UNIT_READY)) + (scsicmd->cmnd[0] != TEST_UNIT_READY)) { dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; @@ -1922,9 +1950,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer)) - ? sizeof(scsicmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); + min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); scsicmd->scsi_done(scsicmd); return 0; } @@ -1939,7 +1966,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); memset(&inq_data, 0, sizeof (struct inquiry_data)); - if (scsicmd->cmnd[1] & 0x1 ) { + if (scsicmd->cmnd[1] & 0x1) { char *arr = (char *)&inq_data; /* EVPD bit set */ @@ -1974,10 +2001,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ASENCODE_NO_SENSE, 0, 7, 2, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > - sizeof(scsicmd->sense_buffer)) - ? sizeof(scsicmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); + min_t(size_t, + sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); } scsicmd->scsi_done(scsicmd); return 0; @@ -2092,7 +2118,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected bit 4: 0/1 = FUA enabled */ - if (dev->raw_io_interface) + if (dev->raw_io_interface && ((aac_cache & 5) != 1)) mode_buf[2] = 0x10; mode_buf[3] = 0; /* Block descriptor length */ if (((scsicmd->cmnd[2] & 0x3f) == 8) || @@ -2100,7 +2126,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[0] = 6; mode_buf[4] = 8; mode_buf[5] = 1; - mode_buf[6] = 0x04; /* WCE */ + mode_buf[6] = ((aac_cache & 6) == 2) + ? 0 : 0x04; /* WCE */ mode_buf_length = 7; if (mode_buf_length > scsicmd->cmnd[4]) mode_buf_length = scsicmd->cmnd[4]; @@ -2123,7 +2150,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected bit 4: 0/1 = FUA enabled */ - if (dev->raw_io_interface) + if (dev->raw_io_interface && ((aac_cache & 5) != 1)) mode_buf[3] = 0x10; mode_buf[4] = 0; /* reserved */ mode_buf[5] = 0; /* reserved */ @@ -2134,7 +2161,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[1] = 9; mode_buf[8] = 8; mode_buf[9] = 1; - mode_buf[10] = 0x04; /* WCE */ + mode_buf[10] = ((aac_cache & 6) == 2) + ? 0 : 0x04; /* WCE */ mode_buf_length = 11; if (mode_buf_length > scsicmd->cmnd[8]) mode_buf_length = scsicmd->cmnd[8]; @@ -2179,7 +2207,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) return 0; } - switch (scsicmd->cmnd[0]) + switch (scsicmd->cmnd[0]) { case READ_6: case READ_10: @@ -2192,11 +2220,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) * corresponds to a container. Needed to convert * containers to /dev/sd device names */ - + if (scsicmd->request->rq_disk) strlcpy(fsa_dev_ptr[cid].devname, scsicmd->request->rq_disk->disk_name, - min(sizeof(fsa_dev_ptr[cid].devname), + min(sizeof(fsa_dev_ptr[cid].devname), sizeof(scsicmd->request->rq_disk->disk_name) + 1)); return aac_read(scsicmd); @@ -2210,9 +2238,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) return aac_write(scsicmd); case SYNCHRONIZE_CACHE: + if (((aac_cache & 6) == 6) && dev->cache_protected) { + scsicmd->result = DID_OK << 16 | + COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; + scsicmd->scsi_done(scsicmd); + return 0; + } /* Issue FIB to tell Firmware to flush it's cache */ - return aac_synchronize(scsicmd); - + if ((aac_cache & 6) != 2) + return aac_synchronize(scsicmd); + /* FALLTHRU */ default: /* * Unhandled commands @@ -2223,9 +2258,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, 0, 0, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer)) - ? sizeof(scsicmd->sense_buffer) - : sizeof(dev->fsa_dev[cid].sense_data)); + min_t(size_t, + sizeof(dev->fsa_dev[cid].sense_data), + SCSI_SENSE_BUFFERSIZE)); scsicmd->scsi_done(scsicmd); return 0; } @@ -2243,7 +2278,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg) return -EFAULT; if (qd.cnum == -1) qd.cnum = qd.id; - else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) + else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) { if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) return -EINVAL; @@ -2370,7 +2405,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr) scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ /* - * Calculate resid for sg + * Calculate resid for sg */ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) @@ -2385,10 +2420,8 @@ static void aac_srb_callback(void *context, struct fib * fibptr) if (le32_to_cpu(srbreply->status) != ST_OK){ int len; printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); - len = (le32_to_cpu(srbreply->sense_data_size) > - sizeof(scsicmd->sense_buffer)) ? - sizeof(scsicmd->sense_buffer) : - le32_to_cpu(srbreply->sense_data_size); + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); } @@ -2412,7 +2445,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr) case WRITE_12: case READ_16: case WRITE_16: - if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) { + if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) { printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); } else { printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); @@ -2481,26 +2514,23 @@ static void aac_srb_callback(void *context, struct fib * fibptr) printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", le32_to_cpu(srbreply->srb_status) & 0x3F, aac_get_status_string( - le32_to_cpu(srbreply->srb_status) & 0x3F), - scsicmd->cmnd[0], + le32_to_cpu(srbreply->srb_status) & 0x3F), + scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status)); #endif scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; break; } - if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){ // Check Condition + if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) { int len; scsicmd->result |= SAM_STAT_CHECK_CONDITION; - len = (le32_to_cpu(srbreply->sense_data_size) > - sizeof(scsicmd->sense_buffer)) ? - sizeof(scsicmd->sense_buffer) : - le32_to_cpu(srbreply->sense_data_size); + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); #ifdef AAC_DETAILED_STATUS_INFO printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len); #endif memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); - } /* * OR in the scsi status (already shifted up a bit) @@ -2517,7 +2547,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr) * aac_send_scb_fib * @scsicmd: the scsi command block * - * This routine will form a FIB and fill in the aac_srb from the + * This routine will form a FIB and fill in the aac_srb from the * scsicmd passed in. */ @@ -2731,7 +2761,7 @@ static struct aac_srb_status_info srb_status_info[] = { { SRB_STATUS_ERROR_RECOVERY, "Error Recovery"}, { SRB_STATUS_NOT_STARTED, "Not Started"}, { SRB_STATUS_NOT_IN_USE, "Not In Use"}, - { SRB_STATUS_FORCE_ABORT, "Force Abort"}, + { SRB_STATUS_FORCE_ABORT, "Force Abort"}, { SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"}, { 0xff, "Unknown Error"} }; diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 9abba8b90f70..3195d29f2177 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1,4 +1,4 @@ -#if (!defined(dprintk)) +#ifndef dprintk # define dprintk(x) #endif /* eg: if (nblank(dprintk(x))) */ @@ -12,7 +12,7 @@ *----------------------------------------------------------------------------*/ #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 2449 +# define AAC_DRIVER_BUILD 2455 # define AAC_DRIVER_BRANCH "-ms" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -50,9 +50,9 @@ struct diskparm /* * Firmware constants */ - + #define CT_NONE 0 -#define CT_OK 218 +#define CT_OK 218 #define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */ #define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/id/lun */ @@ -107,12 +107,12 @@ struct user_sgentryraw { struct sgmap { __le32 count; - struct sgentry sg[1]; + struct sgentry sg[1]; }; struct user_sgmap { u32 count; - struct user_sgentry sg[1]; + struct user_sgentry sg[1]; }; struct sgmap64 { @@ -137,18 +137,18 @@ struct user_sgmapraw { struct creation_info { - u8 buildnum; /* e.g., 588 */ - u8 usec; /* e.g., 588 */ - u8 via; /* e.g., 1 = FSU, - * 2 = API + u8 buildnum; /* e.g., 588 */ + u8 usec; /* e.g., 588 */ + u8 via; /* e.g., 1 = FSU, + * 2 = API */ - u8 year; /* e.g., 1997 = 97 */ + u8 year; /* e.g., 1997 = 97 */ __le32 date; /* - * unsigned Month :4; // 1 - 12 - * unsigned Day :6; // 1 - 32 - * unsigned Hour :6; // 0 - 23 - * unsigned Minute :6; // 0 - 60 - * unsigned Second :6; // 0 - 60 + * unsigned Month :4; // 1 - 12 + * unsigned Day :6; // 1 - 32 + * unsigned Hour :6; // 0 - 23 + * unsigned Minute :6; // 0 - 60 + * unsigned Second :6; // 0 - 60 */ __le32 serial[2]; /* e.g., 0x1DEADB0BFAFAF001 */ }; @@ -184,7 +184,7 @@ struct creation_info /* * Set the queues on a 16 byte alignment */ - + #define QUEUE_ALIGNMENT 16 /* @@ -203,9 +203,9 @@ struct aac_entry { * The adapter assumes the ProducerIndex and ConsumerIndex are grouped * adjacently and in that order. */ - + struct aac_qhdr { - __le64 header_addr;/* Address to hand the adapter to access + __le64 header_addr;/* Address to hand the adapter to access to this queue head */ __le32 *producer; /* The producer index for this queue (host address) */ __le32 *consumer; /* The consumer index for this queue (host address) */ @@ -215,7 +215,7 @@ struct aac_qhdr { * Define all the events which the adapter would like to notify * the host of. */ - + #define HostNormCmdQue 1 /* Change in host normal priority command queue */ #define HostHighCmdQue 2 /* Change in host high priority command queue */ #define HostNormRespQue 3 /* Change in host normal priority response queue */ @@ -286,17 +286,17 @@ struct aac_fibhdr { u8 StructType; /* Type FIB */ u8 Flags; /* Flags for FIB */ __le16 Size; /* Size of this FIB in bytes */ - __le16 SenderSize; /* Size of the FIB in the sender + __le16 SenderSize; /* Size of the FIB in the sender (for response sizing) */ __le32 SenderFibAddress; /* Host defined data in the FIB */ - __le32 ReceiverFibAddress;/* Logical address of this FIB for + __le32 ReceiverFibAddress;/* Logical address of this FIB for the adapter */ u32 SenderData; /* Place holder for the sender to store data */ union { struct { - __le32 _ReceiverTimeStart; /* Timestamp for + __le32 _ReceiverTimeStart; /* Timestamp for receipt of fib */ - __le32 _ReceiverTimeDone; /* Timestamp for + __le32 _ReceiverTimeDone; /* Timestamp for completion of fib */ } _s; } _u; @@ -311,7 +311,7 @@ struct hw_fib { * FIB commands */ -#define TestCommandResponse 1 +#define TestCommandResponse 1 #define TestAdapterCommand 2 /* * Lowlevel and comm commands @@ -350,10 +350,6 @@ struct hw_fib { #define ContainerCommand64 501 #define ContainerRawIo 502 /* - * Cluster Commands - */ -#define ClusterCommand 550 -/* * Scsi Port commands (scsi passthrough) */ #define ScsiPortCommand 600 @@ -375,19 +371,19 @@ struct hw_fib { */ enum fib_xfer_state { - HostOwned = (1<<0), - AdapterOwned = (1<<1), - FibInitialized = (1<<2), - FibEmpty = (1<<3), - AllocatedFromPool = (1<<4), - SentFromHost = (1<<5), - SentFromAdapter = (1<<6), - ResponseExpected = (1<<7), - NoResponseExpected = (1<<8), - AdapterProcessed = (1<<9), - HostProcessed = (1<<10), - HighPriority = (1<<11), - NormalPriority = (1<<12), + HostOwned = (1<<0), + AdapterOwned = (1<<1), + FibInitialized = (1<<2), + FibEmpty = (1<<3), + AllocatedFromPool = (1<<4), + SentFromHost = (1<<5), + SentFromAdapter = (1<<6), + ResponseExpected = (1<<7), + NoResponseExpected = (1<<8), + AdapterProcessed = (1<<9), + HostProcessed = (1<<10), + HighPriority = (1<<11), + NormalPriority = (1<<12), Async = (1<<13), AsyncIo = (1<<13), // rpbfix: remove with new regime PageFileIo = (1<<14), // rpbfix: remove with new regime @@ -420,7 +416,7 @@ struct aac_init __le32 AdapterFibAlign; __le32 printfbuf; __le32 printfbufsiz; - __le32 HostPhysMemPages; /* number of 4k pages of host + __le32 HostPhysMemPages; /* number of 4k pages of host physical memory */ __le32 HostElapsedSeconds; /* number of seconds since 1970. */ /* @@ -481,7 +477,7 @@ struct adapter_ops struct aac_driver_ident { - int (*init)(struct aac_dev *dev); + int (*init)(struct aac_dev *dev); char * name; char * vname; char * model; @@ -489,7 +485,7 @@ struct aac_driver_ident int quirks; }; /* - * Some adapter firmware needs communication memory + * Some adapter firmware needs communication memory * below 2gig. This tells the init function to set the * dma mask such that fib memory will be allocated where the * adapter firmware can get to it. @@ -521,33 +517,39 @@ struct aac_driver_ident #define AAC_QUIRK_17SG 0x0010 /* + * Some adapter firmware does not support 64 bit scsi passthrough + * commands. + */ +#define AAC_QUIRK_SCSI_32 0x0020 + +/* * The adapter interface specs all queues to be located in the same * physically contigous block. The host structure that defines the * commuication queues will assume they are each a separate physically * contigous memory region that will support them all being one big - * contigous block. + * contigous block. * There is a command and response queue for each level and direction of * commuication. These regions are accessed by both the host and adapter. */ - + struct aac_queue { - u64 logical; /*address we give the adapter */ + u64 logical; /*address we give the adapter */ struct aac_entry *base; /*system virtual address */ - struct aac_qhdr headers; /*producer,consumer q headers*/ - u32 entries; /*Number of queue entries */ + struct aac_qhdr headers; /*producer,consumer q headers*/ + u32 entries; /*Number of queue entries */ wait_queue_head_t qfull; /*Event to wait on if q full */ wait_queue_head_t cmdready; /*Cmd ready from the adapter */ - /* This is only valid for adapter to host command queues. */ - spinlock_t *lock; /* Spinlock for this queue must take this lock before accessing the lock */ + /* This is only valid for adapter to host command queues. */ + spinlock_t *lock; /* Spinlock for this queue must take this lock before accessing the lock */ spinlock_t lockdata; /* Actual lock (used only on one side of the lock) */ - struct list_head cmdq; /* A queue of FIBs which need to be prcessed by the FS thread. This is */ - /* only valid for command queues which receive entries from the adapter. */ + struct list_head cmdq; /* A queue of FIBs which need to be prcessed by the FS thread. This is */ + /* only valid for command queues which receive entries from the adapter. */ u32 numpending; /* Number of entries on outstanding queue. */ struct aac_dev * dev; /* Back pointer to adapter structure */ }; /* - * Message queues. The order here is important, see also the + * Message queues. The order here is important, see also the * queue type ordering */ @@ -559,12 +561,12 @@ struct aac_queue_block /* * SaP1 Message Unit Registers */ - + struct sa_drawbridge_CSR { - /* Offset | Name */ + /* Offset | Name */ __le32 reserved[10]; /* 00h-27h | Reserved */ u8 LUT_Offset; /* 28h | Lookup Table Offset */ - u8 reserved1[3]; /* 29h-2bh | Reserved */ + u8 reserved1[3]; /* 29h-2bh | Reserved */ __le32 LUT_Data; /* 2ch | Looup Table Data */ __le32 reserved2[26]; /* 30h-97h | Reserved */ __le16 PRICLEARIRQ; /* 98h | Primary Clear Irq */ @@ -583,8 +585,8 @@ struct sa_drawbridge_CSR { __le32 MAILBOX5; /* bch | Scratchpad 5 */ __le32 MAILBOX6; /* c0h | Scratchpad 6 */ __le32 MAILBOX7; /* c4h | Scratchpad 7 */ - __le32 ROM_Setup_Data; /* c8h | Rom Setup and Data */ - __le32 ROM_Control_Addr;/* cch | Rom Control and Address */ + __le32 ROM_Setup_Data; /* c8h | Rom Setup and Data */ + __le32 ROM_Control_Addr;/* cch | Rom Control and Address */ __le32 reserved3[12]; /* d0h-ffh | reserved */ __le32 LUT[64]; /* 100h-1ffh | Lookup Table Entries */ }; @@ -597,7 +599,7 @@ struct sa_drawbridge_CSR { #define Mailbox5 SaDbCSR.MAILBOX5 #define Mailbox6 SaDbCSR.MAILBOX6 #define Mailbox7 SaDbCSR.MAILBOX7 - + #define DoorbellReg_p SaDbCSR.PRISETIRQ #define DoorbellReg_s SaDbCSR.SECSETIRQ #define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ @@ -611,19 +613,19 @@ struct sa_drawbridge_CSR { #define DOORBELL_5 0x0020 #define DOORBELL_6 0x0040 - + #define PrintfReady DOORBELL_5 #define PrintfDone DOORBELL_5 - + struct sa_registers { struct sa_drawbridge_CSR SaDbCSR; /* 98h - c4h */ }; - + #define Sa_MINIPORT_REVISION 1 #define sa_readw(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) -#define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) +#define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) #define sa_writew(AEP, CSR, value) writew(value, &((AEP)->regs.sa->CSR)) #define sa_writel(AEP, CSR, value) writel(value, &((AEP)->regs.sa->CSR)) @@ -640,21 +642,21 @@ struct rx_mu_registers { __le32 IMRx[2]; /* 1310h | 10h | Inbound Message Registers */ __le32 OMRx[2]; /* 1318h | 18h | Outbound Message Registers */ __le32 IDR; /* 1320h | 20h | Inbound Doorbell Register */ - __le32 IISR; /* 1324h | 24h | Inbound Interrupt + __le32 IISR; /* 1324h | 24h | Inbound Interrupt Status Register */ - __le32 IIMR; /* 1328h | 28h | Inbound Interrupt - Mask Register */ + __le32 IIMR; /* 1328h | 28h | Inbound Interrupt + Mask Register */ __le32 ODR; /* 132Ch | 2Ch | Outbound Doorbell Register */ - __le32 OISR; /* 1330h | 30h | Outbound Interrupt + __le32 OISR; /* 1330h | 30h | Outbound Interrupt Status Register */ - __le32 OIMR; /* 1334h | 34h | Outbound Interrupt + __le32 OIMR; /* 1334h | 34h | Outbound Interrupt Mask Register */ __le32 reserved2; /* 1338h | 38h | Reserved */ __le32 reserved3; /* 133Ch | 3Ch | Reserved */ __le32 InboundQueue;/* 1340h | 40h | Inbound Queue Port relative to firmware */ __le32 OutboundQueue;/*1344h | 44h | Outbound Queue Port relative to firmware */ - /* * Must access through ATU Inbound - Translation Window */ + /* * Must access through ATU Inbound + Translation Window */ }; struct rx_inbound { @@ -710,12 +712,12 @@ struct rkt_registers { typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); struct aac_fib_context { - s16 type; // used for verification of structure - s16 size; + s16 type; // used for verification of structure + s16 size; u32 unique; // unique value representing this context ulong jiffies; // used for cleanup - dmb changed to ulong struct list_head next; // used to link context's into a linked list - struct semaphore wait_sem; // this is used to wait for the next fib to arrive. + struct semaphore wait_sem; // this is used to wait for the next fib to arrive. int wait; // Set to true when thread is in WaitForSingleObject unsigned long count; // total number of FIBs on FibList struct list_head fib_list; // this holds fibs and their attachd hw_fibs @@ -734,9 +736,9 @@ struct sense_data { u8 EOM:1; /* End Of Medium - reserved for random access devices */ u8 filemark:1; /* Filemark - reserved for random access devices */ - u8 information[4]; /* for direct-access devices, contains the unsigned - * logical block address or residue associated with - * the sense key + u8 information[4]; /* for direct-access devices, contains the unsigned + * logical block address or residue associated with + * the sense key */ u8 add_sense_len; /* number of additional sense bytes to follow this field */ u8 cmnd_info[4]; /* not used */ @@ -746,7 +748,7 @@ struct sense_data { u8 bit_ptr:3; /* indicates which byte of the CDB or parameter data * was in error */ - u8 BPV:1; /* bit pointer valid (BPV): 1- indicates that + u8 BPV:1; /* bit pointer valid (BPV): 1- indicates that * the bit_ptr field has valid value */ u8 reserved2:2; @@ -780,24 +782,24 @@ struct fib { /* * The Adapter that this I/O is destined for. */ - struct aac_dev *dev; + struct aac_dev *dev; /* * This is the event the sendfib routine will wait on if the * caller did not pass one and this is synch io. */ - struct semaphore event_wait; + struct semaphore event_wait; spinlock_t event_lock; u32 done; /* gets set to 1 when fib is complete */ - fib_callback callback; - void *callback_data; + fib_callback callback; + void *callback_data; u32 flags; // u32 dmb was ulong /* * And for the internal issue/reply queues (we may be able * to merge these two) */ struct list_head fiblink; - void *data; + void *data; struct hw_fib *hw_fib_va; /* Actual shared object */ dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ }; @@ -807,7 +809,7 @@ struct fib { * * This is returned by the RequestAdapterInfo block */ - + struct aac_adapter_info { __le32 platform; @@ -826,7 +828,7 @@ struct aac_adapter_info __le32 biosrev; __le32 biosbuild; __le32 cluster; - __le32 clusterchannelmask; + __le32 clusterchannelmask; __le32 serial[2]; __le32 battery; __le32 options; @@ -863,9 +865,10 @@ struct aac_supplement_adapter_info __le32 SupportedOptions2; __le32 ReservedGrowth[1]; }; -#define AAC_FEATURE_FALCON 0x00000010 -#define AAC_OPTION_MU_RESET 0x00000001 -#define AAC_OPTION_IGNORE_RESET 0x00000002 +#define AAC_FEATURE_FALCON cpu_to_le32(0x00000010) +#define AAC_FEATURE_JBOD cpu_to_le32(0x08000000) +#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001) +#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002) #define AAC_SIS_VERSION_V3 3 #define AAC_SIS_SLOT_UNKNOWN 0xFF @@ -916,13 +919,13 @@ struct aac_bus_info_response { #define AAC_OPT_HOST_TIME_FIB cpu_to_le32(1<<4) #define AAC_OPT_RAID50 cpu_to_le32(1<<5) #define AAC_OPT_4GB_WINDOW cpu_to_le32(1<<6) -#define AAC_OPT_SCSI_UPGRADEABLE cpu_to_le32(1<<7) +#define AAC_OPT_SCSI_UPGRADEABLE cpu_to_le32(1<<7) #define AAC_OPT_SOFT_ERR_REPORT cpu_to_le32(1<<8) -#define AAC_OPT_SUPPORTED_RECONDITION cpu_to_le32(1<<9) +#define AAC_OPT_SUPPORTED_RECONDITION cpu_to_le32(1<<9) #define AAC_OPT_SGMAP_HOST64 cpu_to_le32(1<<10) #define AAC_OPT_ALARM cpu_to_le32(1<<11) #define AAC_OPT_NONDASD cpu_to_le32(1<<12) -#define AAC_OPT_SCSI_MANAGED cpu_to_le32(1<<13) +#define AAC_OPT_SCSI_MANAGED cpu_to_le32(1<<13) #define AAC_OPT_RAID_SCSI_MODE cpu_to_le32(1<<14) #define AAC_OPT_SUPPLEMENT_ADAPTER_INFO cpu_to_le32(1<<16) #define AAC_OPT_NEW_COMM cpu_to_le32(1<<17) @@ -942,7 +945,7 @@ struct aac_dev /* * Map for 128 fib objects (64k) - */ + */ dma_addr_t hw_fib_pa; struct hw_fib *hw_fib_va; struct hw_fib *aif_base_va; @@ -953,24 +956,24 @@ struct aac_dev struct fib *free_fib; spinlock_t fib_lock; - + struct aac_queue_block *queues; /* * The user API will use an IOCTL to register itself to receive * FIBs from the adapter. The following list is used to keep * track of all the threads that have requested these FIBs. The - * mutex is used to synchronize access to all data associated + * mutex is used to synchronize access to all data associated * with the adapter fibs. */ struct list_head fib_list; struct adapter_ops a_ops; unsigned long fsrev; /* Main driver's revision number */ - + unsigned base_size; /* Size of mapped in region */ struct aac_init *init; /* Holds initialization info to communicate with adapter */ - dma_addr_t init_pa; /* Holds physical address of the init struct */ - + dma_addr_t init_pa; /* Holds physical address of the init struct */ + struct pci_dev *pdev; /* Our PCI interface */ void * printfbuf; /* pointer to buffer used for printf's from the adapter */ void * comm_addr; /* Base address of Comm area */ @@ -984,11 +987,11 @@ struct aac_dev struct fsa_dev_info *fsa_dev; struct task_struct *thread; int cardtype; - + /* * The following is the device specific extension. */ -#if (!defined(AAC_MIN_FOOTPRINT_SIZE)) +#ifndef AAC_MIN_FOOTPRINT_SIZE # define AAC_MIN_FOOTPRINT_SIZE 8192 #endif union @@ -1009,7 +1012,9 @@ struct aac_dev /* These are in adapter info but they are in the io flow so * lets break them out so we don't have to do an AND to check them */ - u8 nondasd_support; + u8 nondasd_support; + u8 jbod; + u8 cache_protected; u8 dac_support; u8 raid_scsi_mode; u8 comm_interface; @@ -1066,18 +1071,19 @@ struct aac_dev (dev)->a_ops.adapter_comm(dev, comm) #define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) +#define FIB_CONTEXT_FLAG (0x00000002) /* * Define the command values */ - + #define Null 0 -#define GetAttributes 1 -#define SetAttributes 2 -#define Lookup 3 -#define ReadLink 4 -#define Read 5 -#define Write 6 +#define GetAttributes 1 +#define SetAttributes 2 +#define Lookup 3 +#define ReadLink 4 +#define Read 5 +#define Write 6 #define Create 7 #define MakeDirectory 8 #define SymbolicLink 9 @@ -1173,19 +1179,19 @@ struct aac_dev struct aac_read { - __le32 command; - __le32 cid; - __le32 block; - __le32 count; + __le32 command; + __le32 cid; + __le32 block; + __le32 count; struct sgmap sg; // Must be last in struct because it is variable }; struct aac_read64 { - __le32 command; - __le16 cid; - __le16 sector_count; - __le32 block; + __le32 command; + __le16 cid; + __le16 sector_count; + __le32 block; __le16 pad; __le16 flags; struct sgmap64 sg; // Must be last in struct because it is variable @@ -1193,26 +1199,26 @@ struct aac_read64 struct aac_read_reply { - __le32 status; - __le32 count; + __le32 status; + __le32 count; }; struct aac_write { __le32 command; - __le32 cid; - __le32 block; - __le32 count; - __le32 stable; // Not used + __le32 cid; + __le32 block; + __le32 count; + __le32 stable; // Not used struct sgmap sg; // Must be last in struct because it is variable }; struct aac_write64 { - __le32 command; - __le16 cid; - __le16 sector_count; - __le32 block; + __le32 command; + __le16 cid; + __le16 sector_count; + __le32 block; __le16 pad; __le16 flags; #define IO_TYPE_WRITE 0x00000000 @@ -1223,7 +1229,7 @@ struct aac_write64 struct aac_write_reply { __le32 status; - __le32 count; + __le32 count; __le32 committed; }; @@ -1326,10 +1332,10 @@ struct aac_srb_reply #define SRB_NoDataXfer 0x0000 #define SRB_DisableDisconnect 0x0004 #define SRB_DisableSynchTransfer 0x0008 -#define SRB_BypassFrozenQueue 0x0010 +#define SRB_BypassFrozenQueue 0x0010 #define SRB_DisableAutosense 0x0020 #define SRB_DataIn 0x0040 -#define SRB_DataOut 0x0080 +#define SRB_DataOut 0x0080 /* * SRB Functions - set in aac_srb->function @@ -1352,7 +1358,7 @@ struct aac_srb_reply #define SRBF_RemoveDevice 0x0016 #define SRBF_DomainValidation 0x0017 -/* +/* * SRB SCSI Status - set in aac_srb->scsi_status */ #define SRB_STATUS_PENDING 0x00 @@ -1511,17 +1517,17 @@ struct aac_get_container_count_resp { */ struct aac_mntent { - __le32 oid; + __le32 oid; u8 name[16]; /* if applicable */ struct creation_info create_info; /* if applicable */ __le32 capacity; - __le32 vol; /* substrate structure */ - __le32 obj; /* FT_FILESYS, etc. */ - __le32 state; /* unready for mounting, + __le32 vol; /* substrate structure */ + __le32 obj; /* FT_FILESYS, etc. */ + __le32 state; /* unready for mounting, readonly, etc. */ - union aac_contentinfo fileinfo; /* Info specific to content + union aac_contentinfo fileinfo; /* Info specific to content manager (eg, filesystem) */ - __le32 altoid; /* != oid <==> snapshot or + __le32 altoid; /* != oid <==> snapshot or broken mirror exists */ __le32 capacityhigh; }; @@ -1538,7 +1544,7 @@ struct aac_query_mount { struct aac_mount { __le32 status; - __le32 type; /* should be same as that requested */ + __le32 type; /* should be same as that requested */ __le32 count; struct aac_mntent mnt[1]; }; @@ -1608,7 +1614,7 @@ struct aac_delete_disk { u32 disknum; u32 cnum; }; - + struct fib_ioctl { u32 fibctx; @@ -1622,10 +1628,10 @@ struct revision __le32 version; __le32 build; }; - + /* - * Ugly - non Linux like ioctl coding for back compat. + * Ugly - non Linux like ioctl coding for back compat. */ #define CTL_CODE(function, method) ( \ @@ -1633,7 +1639,7 @@ struct revision ) /* - * Define the method codes for how buffers are passed for I/O and FS + * Define the method codes for how buffers are passed for I/O and FS * controls */ @@ -1644,15 +1650,15 @@ struct revision * Filesystem ioctls */ -#define FSACTL_SENDFIB CTL_CODE(2050, METHOD_BUFFERED) -#define FSACTL_SEND_RAW_SRB CTL_CODE(2067, METHOD_BUFFERED) +#define FSACTL_SENDFIB CTL_CODE(2050, METHOD_BUFFERED) +#define FSACTL_SEND_RAW_SRB CTL_CODE(2067, METHOD_BUFFERED) #define FSACTL_DELETE_DISK 0x163 #define FSACTL_QUERY_DISK 0x173 #define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(2100, METHOD_BUFFERED) #define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(2101, METHOD_BUFFERED) #define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(2102, METHOD_BUFFERED) #define FSACTL_MINIPORT_REV_CHECK CTL_CODE(2107, METHOD_BUFFERED) -#define FSACTL_GET_PCI_INFO CTL_CODE(2119, METHOD_BUFFERED) +#define FSACTL_GET_PCI_INFO CTL_CODE(2119, METHOD_BUFFERED) #define FSACTL_FORCE_DELETE_DISK CTL_CODE(2120, METHOD_NEITHER) #define FSACTL_GET_CONTAINERS 2131 #define FSACTL_SEND_LARGE_FIB CTL_CODE(2138, METHOD_BUFFERED) @@ -1661,7 +1667,7 @@ struct revision struct aac_common { /* - * If this value is set to 1 then interrupt moderation will occur + * If this value is set to 1 then interrupt moderation will occur * in the base commuication support. */ u32 irq_mod; @@ -1690,11 +1696,11 @@ extern struct aac_common aac_config; * The following macro is used when sending and receiving FIBs. It is * only used for debugging. */ - + #ifdef DBG #define FIB_COUNTER_INCREMENT(counter) (counter)++ #else -#define FIB_COUNTER_INCREMENT(counter) +#define FIB_COUNTER_INCREMENT(counter) #endif /* @@ -1726,17 +1732,17 @@ extern struct aac_common aac_config; * * The adapter reports is present state through the phase. Only * a single phase should be ever be set. Each phase can have multiple - * phase status bits to provide more detailed information about the - * state of the board. Care should be taken to ensure that any phase + * phase status bits to provide more detailed information about the + * state of the board. Care should be taken to ensure that any phase * status bits that are set when changing the phase are also valid * for the new phase or be cleared out. Adapter software (monitor, - * iflash, kernel) is responsible for properly maintining the phase + * iflash, kernel) is responsible for properly maintining the phase * status mailbox when it is running. - * - * MONKER_API Phases * - * Phases are bit oriented. It is NOT valid to have multiple bits set - */ + * MONKER_API Phases + * + * Phases are bit oriented. It is NOT valid to have multiple bits set + */ #define SELF_TEST_FAILED 0x00000004 #define MONITOR_PANIC 0x00000020 @@ -1759,16 +1765,22 @@ extern struct aac_common aac_config; * For FIB communication, we need all of the following things * to send back to the user. */ - -#define AifCmdEventNotify 1 /* Notify of event */ + +#define AifCmdEventNotify 1 /* Notify of event */ #define AifEnConfigChange 3 /* Adapter configuration change */ #define AifEnContainerChange 4 /* Container configuration change */ #define AifEnDeviceFailure 5 /* SCSI device failed */ +#define AifEnEnclosureManagement 13 /* EM_DRIVE_* */ +#define EM_DRIVE_INSERTION 31 +#define EM_DRIVE_REMOVAL 32 +#define AifEnBatteryEvent 14 /* Change in Battery State */ #define AifEnAddContainer 15 /* A new array was created */ #define AifEnDeleteContainer 16 /* A container was deleted */ #define AifEnExpEvent 23 /* Firmware Event Log */ #define AifExeFirmwarePanic 3 /* Firmware Event Panic */ #define AifHighPriority 3 /* Highest Priority Event */ +#define AifEnAddJBOD 30 /* JBOD created */ +#define AifEnDeleteJBOD 31 /* JBOD deleted */ #define AifCmdJobProgress 2 /* Progress report */ #define AifJobCtrZero 101 /* Array Zero progress */ @@ -1780,11 +1792,11 @@ extern struct aac_common aac_config; #define AifDenVolumeExtendComplete 201 /* A volume extend completed */ #define AifReqJobList 100 /* Gets back complete job list */ #define AifReqJobsForCtr 101 /* Gets back jobs for specific container */ -#define AifReqJobsForScsi 102 /* Gets back jobs for specific SCSI device */ -#define AifReqJobReport 103 /* Gets back a specific job report or list of them */ +#define AifReqJobsForScsi 102 /* Gets back jobs for specific SCSI device */ +#define AifReqJobReport 103 /* Gets back a specific job report or list of them */ #define AifReqTerminateJob 104 /* Terminates job */ #define AifReqSuspendJob 105 /* Suspends a job */ -#define AifReqResumeJob 106 /* Resumes a job */ +#define AifReqResumeJob 106 /* Resumes a job */ #define AifReqSendAPIReport 107 /* API generic report requests */ #define AifReqAPIJobStart 108 /* Start a job from the API */ #define AifReqAPIJobUpdate 109 /* Update a job report from the API */ @@ -1803,8 +1815,8 @@ struct aac_aifcmd { }; /** - * Convert capacity to cylinders - * accounting for the fact capacity could be a 64 bit value + * Convert capacity to cylinders + * accounting for the fact capacity could be a 64 bit value * */ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) @@ -1861,6 +1873,7 @@ int aac_probe_container(struct aac_dev *dev, int cid); int _aac_rx_init(struct aac_dev *dev); int aac_rx_select_comm(struct aac_dev *dev, int comm); int aac_rx_deliver_producer(struct fib * fib); +char * get_container_type(unsigned type); extern int numacb; extern int acbsize; extern char aac_driver_version[]; diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 1e6d7a9c75bf..f8afa358b6b6 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -48,13 +48,13 @@ * ioctl_send_fib - send a FIB from userspace * @dev: adapter is being processed * @arg: arguments to the ioctl call - * + * * This routine sends a fib to the adapter on behalf of a user level * program. */ # define AAC_DEBUG_PREAMBLE KERN_INFO # define AAC_DEBUG_POSTAMBLE - + static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) { struct hw_fib * kfib; @@ -71,7 +71,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) if(fibptr == NULL) { return -ENOMEM; } - + kfib = fibptr->hw_fib_va; /* * First copy in the header so that we can check the size field. @@ -109,7 +109,7 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { aac_adapter_interrupt(dev); /* - * Since we didn't really send a fib, zero out the state to allow + * Since we didn't really send a fib, zero out the state to allow * cleanup code not to assert. */ kfib->header.XferState = 0; @@ -169,7 +169,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; fibctx->size = sizeof(struct aac_fib_context); - /* + /* * Yes yes, I know this could be an index, but we have a * better guarantee of uniqueness for the locked loop below. * Without the aid of a persistent history, this also helps @@ -189,7 +189,7 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) INIT_LIST_HEAD(&fibctx->fib_list); fibctx->jiffies = jiffies/HZ; /* - * Now add this context onto the adapter's + * Now add this context onto the adapter's * AdapterFibContext list. */ spin_lock_irqsave(&dev->fib_lock, flags); @@ -207,12 +207,12 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) } list_add_tail(&fibctx->next, &dev->fib_list); spin_unlock_irqrestore(&dev->fib_lock, flags); - if (copy_to_user(arg, &fibctx->unique, + if (copy_to_user(arg, &fibctx->unique, sizeof(fibctx->unique))) { status = -EFAULT; } else { status = 0; - } + } } return status; } @@ -221,8 +221,8 @@ static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) * next_getadapter_fib - get the next fib * @dev: adapter to use * @arg: ioctl argument - * - * This routine will get the next Fib, if available, from the AdapterFibContext + * + * This routine will get the next Fib, if available, from the AdapterFibContext * passed in from the user. */ @@ -234,7 +234,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) int status; struct list_head * entry; unsigned long flags; - + if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) return -EFAULT; /* @@ -275,13 +275,12 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) */ return_fib: if (!list_empty(&fibctx->fib_list)) { - struct list_head * entry; /* * Pull the next fib from the fibs */ entry = fibctx->fib_list.next; list_del(entry); - + fib = list_entry(entry, struct fib, fiblink); fibctx->count--; spin_unlock_irqrestore(&dev->fib_lock, flags); @@ -289,7 +288,7 @@ return_fib: kfree(fib->hw_fib_va); kfree(fib); return -EFAULT; - } + } /* * Free the space occupied by this copy of the fib. */ @@ -318,7 +317,7 @@ return_fib: } } else { status = -EAGAIN; - } + } } fibctx->jiffies = jiffies/HZ; return status; @@ -368,7 +367,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) * * This routine will close down the fibctx passed in from the user. */ - + static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) { struct aac_fib_context *fibctx; @@ -415,7 +414,7 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) * @arg: ioctl arguments * * This routine returns the driver version. - * Under Linux, there have been no version incompatibilities, so this is + * Under Linux, there have been no version incompatibilities, so this is * simple! */ @@ -426,12 +425,12 @@ static int check_revision(struct aac_dev *dev, void __user *arg) u32 version; response.compat = 1; - version = (simple_strtol(driver_version, + version = (simple_strtol(driver_version, &driver_version, 10) << 24) | 0x00000400; version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; version += simple_strtol(driver_version + 1, NULL, 10); response.version = cpu_to_le32(version); -# if (defined(AAC_DRIVER_BUILD)) +# ifdef AAC_DRIVER_BUILD response.build = cpu_to_le32(AAC_DRIVER_BUILD); # else response.build = cpu_to_le32(9999); @@ -475,7 +474,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) return -EBUSY; } if (!capable(CAP_SYS_ADMIN)){ - dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); + dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); return -EPERM; } /* @@ -490,7 +489,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ - dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); + dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); rcode = -EFAULT; goto cleanup; } @@ -507,7 +506,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) goto cleanup; } if(copy_from_user(user_srbcmd, user_srb,fibsize)){ - dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); + dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); rcode = -EFAULT; goto cleanup; } @@ -526,7 +525,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) srbcmd->retry_limit = 0; // Obsolete parameter srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); - + switch (flags & (SRB_DataIn | SRB_DataOut)) { case SRB_DataOut: data_dir = DMA_TO_DEVICE; @@ -582,7 +581,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) void* p; /* Does this really need to be GFP_DMA? */ p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(p == 0) { + if(!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", upsg->sg[i].count,i,upsg->count)); rcode = -ENOMEM; @@ -594,7 +593,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_list[i] = p; // save so we can clean up later sg_indx = i; - if( flags & SRB_DataOut ){ + if (flags & SRB_DataOut) { if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); rcode = -EFAULT; @@ -626,7 +625,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) void* p; /* Does this really need to be GFP_DMA? */ p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(p == 0) { + if(!p) { kfree (usg); dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", usg->sg[i].count,i,usg->count)); @@ -637,7 +636,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_list[i] = p; // save so we can clean up later sg_indx = i; - if( flags & SRB_DataOut ){ + if (flags & SRB_DataOut) { if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ kfree (usg); dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); @@ -668,7 +667,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) void* p; /* Does this really need to be GFP_DMA? */ p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(p == 0) { + if(!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", usg->sg[i].count,i,usg->count)); rcode = -ENOMEM; @@ -680,7 +679,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_list[i] = p; // save so we can clean up later sg_indx = i; - if( flags & SRB_DataOut ){ + if (flags & SRB_DataOut) { if(copy_from_user(p,sg_user[i],usg->sg[i].count)){ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); rcode = -EFAULT; @@ -698,7 +697,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) dma_addr_t addr; void* p; p = kmalloc(upsg->sg[i].count, GFP_KERNEL); - if(p == 0) { + if (!p) { dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", upsg->sg[i].count, i, upsg->count)); rcode = -ENOMEM; @@ -708,7 +707,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) sg_list[i] = p; // save so we can clean up later sg_indx = i; - if( flags & SRB_DataOut ){ + if (flags & SRB_DataOut) { if(copy_from_user(p, sg_user[i], upsg->sg[i].count)) { dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); @@ -734,19 +733,19 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) } if (status != 0){ - dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); + dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); rcode = -ENXIO; goto cleanup; } - if( flags & SRB_DataIn ) { + if (flags & SRB_DataIn) { for(i = 0 ; i <= sg_indx; i++){ byte_count = le32_to_cpu( (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count : srbcmd->sg.sg[i].count); if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ - dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); + dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); rcode = -EFAULT; goto cleanup; @@ -756,7 +755,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) reply = (struct aac_srb_reply *) fib_data(srbfib); if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){ - dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); + dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); rcode = -EFAULT; goto cleanup; } @@ -775,34 +774,34 @@ cleanup: } struct aac_pci_info { - u32 bus; - u32 slot; + u32 bus; + u32 slot; }; static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) { - struct aac_pci_info pci_info; + struct aac_pci_info pci_info; pci_info.bus = dev->pdev->bus->number; pci_info.slot = PCI_SLOT(dev->pdev->devfn); if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { - dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); - return -EFAULT; + dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); + return -EFAULT; } - return 0; + return 0; } - + int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) { int status; - + /* * HBA gets first crack */ - + status = aac_dev_ioctl(dev, cmd, arg); if(status != -ENOTTY) return status; @@ -832,7 +831,7 @@ int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) break; default: status = -ENOTTY; - break; + break; } return status; } diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 8736813a0296..89cc8b7b42a2 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -301,10 +301,10 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, 0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) && (status[0] == 0x00000001)) { - if (status[1] & AAC_OPT_NEW_COMM_64) + if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64)) dev->raw_io_64 = 1; if (dev->a_ops.adapter_comm && - (status[1] & AAC_OPT_NEW_COMM)) + (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) dev->comm_interface = AAC_COMM_MESSAGE; if ((dev->comm_interface == AAC_COMM_MESSAGE) && (status[2] > dev->base_size)) { diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index abce48ccc85b..81b36923e0ef 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -56,7 +56,7 @@ * Allocate and map the shared PCI space for the FIB blocks used to * talk to the Adaptec firmware. */ - + static int fib_map_alloc(struct aac_dev *dev) { dprintk((KERN_INFO @@ -109,14 +109,16 @@ int aac_fib_setup(struct aac_dev * dev) } if (i<0) return -ENOMEM; - + hw_fib = dev->hw_fib_va; hw_fib_pa = dev->hw_fib_pa; memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); /* * Initialise the fibs */ - for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++) + for (i = 0, fibptr = &dev->fibs[i]; + i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); + i++, fibptr++) { fibptr->dev = dev; fibptr->hw_fib_va = hw_fib; @@ -148,13 +150,13 @@ int aac_fib_setup(struct aac_dev * dev) * Allocate a fib from the adapter fib pool. If the pool is empty we * return NULL. */ - + struct fib *aac_fib_alloc(struct aac_dev *dev) { struct fib * fibptr; unsigned long flags; spin_lock_irqsave(&dev->fib_lock, flags); - fibptr = dev->free_fib; + fibptr = dev->free_fib; if(!fibptr){ spin_unlock_irqrestore(&dev->fib_lock, flags); return fibptr; @@ -171,6 +173,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev) * each I/O */ fibptr->hw_fib_va->header.XferState = 0; + fibptr->flags = 0; fibptr->callback = NULL; fibptr->callback_data = NULL; @@ -183,7 +186,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev) * * Frees up a fib and places it on the appropriate queue */ - + void aac_fib_free(struct fib *fibptr) { unsigned long flags; @@ -204,10 +207,10 @@ void aac_fib_free(struct fib *fibptr) /** * aac_fib_init - initialise a fib * @fibptr: The fib to initialize - * + * * Set up the generic fib fields ready for use */ - + void aac_fib_init(struct fib *fibptr) { struct hw_fib *hw_fib = fibptr->hw_fib_va; @@ -227,12 +230,12 @@ void aac_fib_init(struct fib *fibptr) * Will deallocate and return to the free pool the FIB pointed to by the * caller. */ - + static void fib_dealloc(struct fib * fibptr) { struct hw_fib *hw_fib = fibptr->hw_fib_va; BUG_ON(hw_fib->header.StructType != FIB_MAGIC); - hw_fib->header.XferState = 0; + hw_fib->header.XferState = 0; } /* @@ -241,7 +244,7 @@ static void fib_dealloc(struct fib * fibptr) * these routines and are the only routines which have a knowledge of the * how these queues are implemented. */ - + /** * aac_get_entry - get a queue entry * @dev: Adapter @@ -254,7 +257,7 @@ static void fib_dealloc(struct fib * fibptr) * is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is * returned. */ - + static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) { struct aac_queue * q; @@ -279,26 +282,27 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr idx = ADAP_NORM_RESP_ENTRIES; } if (idx != le32_to_cpu(*(q->headers.consumer))) - *nonotify = 1; + *nonotify = 1; } if (qid == AdapNormCmdQueue) { - if (*index >= ADAP_NORM_CMD_ENTRIES) + if (*index >= ADAP_NORM_CMD_ENTRIES) *index = 0; /* Wrap to front of the Producer Queue. */ } else { - if (*index >= ADAP_NORM_RESP_ENTRIES) + if (*index >= ADAP_NORM_RESP_ENTRIES) *index = 0; /* Wrap to front of the Producer Queue. */ } - if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */ + /* Queue is full */ + if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { printk(KERN_WARNING "Queue %d full, %u outstanding.\n", qid, q->numpending); return 0; } else { - *entry = q->base + *index; + *entry = q->base + *index; return 1; } -} +} /** * aac_queue_get - get the next free QE @@ -320,31 +324,29 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw { struct aac_entry * entry = NULL; int map = 0; - + if (qid == AdapNormCmdQueue) { /* if no entries wait for some if caller wants to */ - while (!aac_get_entry(dev, qid, &entry, index, nonotify)) - { + while (!aac_get_entry(dev, qid, &entry, index, nonotify)) { printk(KERN_ERR "GetEntries failed\n"); } - /* - * Setup queue entry with a command, status and fib mapped - */ - entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); - map = 1; + /* + * Setup queue entry with a command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); + map = 1; } else { - while(!aac_get_entry(dev, qid, &entry, index, nonotify)) - { + while (!aac_get_entry(dev, qid, &entry, index, nonotify)) { /* if no entries wait for some if caller wants to */ } - /* - * Setup queue entry with command, status and fib mapped - */ - entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); - entry->addr = hw_fib->header.SenderFibAddress; - /* Restore adapters pointer to the FIB */ + /* + * Setup queue entry with command, status and fib mapped + */ + entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); + entry->addr = hw_fib->header.SenderFibAddress; + /* Restore adapters pointer to the FIB */ hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ - map = 0; + map = 0; } /* * If MapFib is true than we need to map the Fib and put pointers @@ -356,8 +358,8 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw } /* - * Define the highest level of host to adapter communication routines. - * These routines will support host to adapter FS commuication. These + * Define the highest level of host to adapter communication routines. + * These routines will support host to adapter FS commuication. These * routines have no knowledge of the commuication method used. This level * sends and receives FIBs. This level has no knowledge of how these FIBs * get passed back and forth. @@ -379,7 +381,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw * an event to wait on must be supplied. This event will be set when a * response FIB is received from the adapter. */ - + int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *callback_data) @@ -392,16 +394,17 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned))) return -EBUSY; /* - * There are 5 cases with the wait and reponse requested flags. + * There are 5 cases with the wait and reponse requested flags. * The only invalid cases are if the caller requests to wait and * does not request a response and if the caller does not want a * response and the Fib is not allocated from pool. If a response * is not requesed the Fib will just be deallocaed by the DPC * routine when the response comes back from the adapter. No - * further processing will be done besides deleting the Fib. We + * further processing will be done besides deleting the Fib. We * will have a debug mode where the adapter can notify the host * it had a problem and the host can log that fact. */ + fibptr->flags = 0; if (wait && !reply) { return -EINVAL; } else if (!wait && reply) { @@ -413,7 +416,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } else if (wait && reply) { hw_fib->header.XferState |= cpu_to_le32(ResponseExpected); FIB_COUNTER_INCREMENT(aac_config.NormalSent); - } + } /* * Map the fib into 32bits by using the fib number */ @@ -436,7 +439,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) { return -EMSGSIZE; - } + } /* * Get a queue entry connect the FIB to it and send an notify * the adapter a command is ready. @@ -450,10 +453,10 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, if (!wait) { fibptr->callback = callback; fibptr->callback_data = callback_data; + fibptr->flags = FIB_CONTEXT_FLAG; } fibptr->done = 0; - fibptr->flags = 0; FIB_COUNTER_INCREMENT(aac_config.FibsSent); @@ -473,9 +476,9 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, aac_adapter_deliver(fibptr); /* - * If the caller wanted us to wait for response wait now. + * If the caller wanted us to wait for response wait now. */ - + if (wait) { spin_unlock_irqrestore(&fibptr->event_lock, flags); /* Only set for first known interruptable command */ @@ -522,7 +525,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } spin_unlock_irqrestore(&fibptr->event_lock, flags); BUG_ON(fibptr->done == 0); - + if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) return -ETIMEDOUT; return 0; @@ -537,15 +540,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, return 0; } -/** +/** * aac_consumer_get - get the top of the queue * @dev: Adapter * @q: Queue * @entry: Return entry * * Will return a pointer to the entry on the top of the queue requested that - * we are a consumer of, and return the address of the queue entry. It does - * not change the state of the queue. + * we are a consumer of, and return the address of the queue entry. It does + * not change the state of the queue. */ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry) @@ -560,10 +563,10 @@ int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entr * the end of the queue, else we just use the entry * pointed to by the header index */ - if (le32_to_cpu(*q->headers.consumer) >= q->entries) - index = 0; + if (le32_to_cpu(*q->headers.consumer) >= q->entries) + index = 0; else - index = le32_to_cpu(*q->headers.consumer); + index = le32_to_cpu(*q->headers.consumer); *entry = q->base + index; status = 1; } @@ -587,12 +590,12 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer)) wasfull = 1; - + if (le32_to_cpu(*q->headers.consumer) >= q->entries) *q->headers.consumer = cpu_to_le32(1); else *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1); - + if (wasfull) { switch (qid) { @@ -608,7 +611,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) } aac_adapter_notify(dev, notify); } -} +} /** * aac_fib_adapter_complete - complete adapter issued fib @@ -630,32 +633,32 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) if (hw_fib->header.XferState == 0) { if (dev->comm_interface == AAC_COMM_MESSAGE) kfree (hw_fib); - return 0; + return 0; } /* * If we plan to do anything check the structure type first. - */ - if ( hw_fib->header.StructType != FIB_MAGIC ) { + */ + if (hw_fib->header.StructType != FIB_MAGIC) { if (dev->comm_interface == AAC_COMM_MESSAGE) kfree (hw_fib); - return -EINVAL; + return -EINVAL; } /* * This block handles the case where the adapter had sent us a * command and we have finished processing the command. We - * call completeFib when we are done processing the command - * and want to send a response back to the adapter. This will + * call completeFib when we are done processing the command + * and want to send a response back to the adapter. This will * send the completed cdb to the adapter. */ if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) { if (dev->comm_interface == AAC_COMM_MESSAGE) { kfree (hw_fib); } else { - u32 index; - hw_fib->header.XferState |= cpu_to_le32(HostProcessed); + u32 index; + hw_fib->header.XferState |= cpu_to_le32(HostProcessed); if (size) { size += sizeof(struct aac_fibhdr); - if (size > le16_to_cpu(hw_fib->header.SenderSize)) + if (size > le16_to_cpu(hw_fib->header.SenderSize)) return -EMSGSIZE; hw_fib->header.Size = cpu_to_le16(size); } @@ -667,12 +670,11 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) if (!(nointr & (int)aac_config.irq_mod)) aac_adapter_notify(dev, AdapNormRespQueue); } + } else { + printk(KERN_WARNING "aac_fib_adapter_complete: " + "Unknown xferstate detected.\n"); + BUG(); } - else - { - printk(KERN_WARNING "aac_fib_adapter_complete: Unknown xferstate detected.\n"); - BUG(); - } return 0; } @@ -682,7 +684,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) * * Will do all necessary work to complete a FIB. */ - + int aac_fib_complete(struct fib *fibptr) { struct hw_fib * hw_fib = fibptr->hw_fib_va; @@ -692,15 +694,15 @@ int aac_fib_complete(struct fib *fibptr) */ if (hw_fib->header.XferState == 0) - return 0; + return 0; /* * If we plan to do anything check the structure type first. - */ + */ if (hw_fib->header.StructType != FIB_MAGIC) - return -EINVAL; + return -EINVAL; /* - * This block completes a cdb which orginated on the host and we + * This block completes a cdb which orginated on the host and we * just need to deallocate the cdb or reinit it. At this point the * command is complete that we had sent to the adapter and this * cdb could be reused. @@ -721,7 +723,7 @@ int aac_fib_complete(struct fib *fibptr) fib_dealloc(fibptr); } else { BUG(); - } + } return 0; } @@ -741,7 +743,7 @@ void aac_printf(struct aac_dev *dev, u32 val) { int length = val & 0xffff; int level = (val >> 16) & 0xffff; - + /* * The size of the printfbuf is set in port.c * There is no variable or define for it @@ -755,7 +757,7 @@ void aac_printf(struct aac_dev *dev, u32 val) else printk(KERN_INFO "%s:%s", dev->name, cp); } - memset(cp, 0, 256); + memset(cp, 0, 256); } @@ -773,20 +775,20 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) { struct hw_fib * hw_fib = fibptr->hw_fib_va; struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data; - u32 container; + u32 channel, id, lun, container; struct scsi_device *device; enum { NOTHING, DELETE, ADD, CHANGE - } device_config_needed; + } device_config_needed = NOTHING; /* Sniff for container changes */ if (!dev || !dev->fsa_dev) return; - container = (u32)-1; + container = channel = id = lun = (u32)-1; /* * We have set this up to try and minimize the number of @@ -796,13 +798,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) */ switch (le32_to_cpu(aifcmd->command)) { case AifCmdDriverNotify: - switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) { + switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) { /* * Morph or Expand complete */ case AifDenMorphComplete: case AifDenVolumeExtendComplete: - container = le32_to_cpu(((u32 *)aifcmd->data)[1]); + container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); if (container >= dev->maximum_num_containers) break; @@ -814,9 +816,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) */ if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) { - device = scsi_device_lookup(dev->scsi_host_ptr, - CONTAINER_TO_CHANNEL(container), - CONTAINER_TO_ID(container), + device = scsi_device_lookup(dev->scsi_host_ptr, + CONTAINER_TO_CHANNEL(container), + CONTAINER_TO_ID(container), CONTAINER_TO_LUN(container)); if (device) { dev->fsa_dev[container].config_needed = CHANGE; @@ -835,25 +837,29 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) if (container >= dev->maximum_num_containers) break; if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) && + le32_to_cpu(*(__le32 *)aifcmd->data)) && time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } else for (container = 0; container < dev->maximum_num_containers; ++container) { if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) && + le32_to_cpu(*(__le32 *)aifcmd->data)) && time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } break; case AifCmdEventNotify: - switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) { + switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) { + case AifEnBatteryEvent: + dev->cache_protected = + (((__le32 *)aifcmd->data)[1] == cpu_to_le32(3)); + break; /* * Add an Array. */ case AifEnAddContainer: - container = le32_to_cpu(((u32 *)aifcmd->data)[1]); + container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); if (container >= dev->maximum_num_containers) break; dev->fsa_dev[container].config_needed = ADD; @@ -866,7 +872,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) * Delete an Array. */ case AifEnDeleteContainer: - container = le32_to_cpu(((u32 *)aifcmd->data)[1]); + container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); if (container >= dev->maximum_num_containers) break; dev->fsa_dev[container].config_needed = DELETE; @@ -880,7 +886,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) * waiting on something else, setup to wait on a Config Change. */ case AifEnContainerChange: - container = le32_to_cpu(((u32 *)aifcmd->data)[1]); + container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); if (container >= dev->maximum_num_containers) break; if (dev->fsa_dev[container].config_waiting_on && @@ -895,6 +901,60 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) case AifEnConfigChange: break; + case AifEnAddJBOD: + case AifEnDeleteJBOD: + container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); + if ((container >> 28)) + break; + channel = (container >> 24) & 0xF; + if (channel >= dev->maximum_num_channels) + break; + id = container & 0xFFFF; + if (id >= dev->maximum_num_physicals) + break; + lun = (container >> 16) & 0xFF; + channel = aac_phys_to_logical(channel); + device_config_needed = + (((__le32 *)aifcmd->data)[0] == + cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE; + break; + + case AifEnEnclosureManagement: + /* + * If in JBOD mode, automatic exposure of new + * physical target to be suppressed until configured. + */ + if (dev->jbod) + break; + switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) { + case EM_DRIVE_INSERTION: + case EM_DRIVE_REMOVAL: + container = le32_to_cpu( + ((__le32 *)aifcmd->data)[2]); + if ((container >> 28)) + break; + channel = (container >> 24) & 0xF; + if (channel >= dev->maximum_num_channels) + break; + id = container & 0xFFFF; + lun = (container >> 16) & 0xFF; + if (id >= dev->maximum_num_physicals) { + /* legacy dev_t ? */ + if ((0x2000 <= id) || lun || channel || + ((channel = (id >> 7) & 0x3F) >= + dev->maximum_num_channels)) + break; + lun = (id >> 4) & 7; + id &= 0xF; + } + channel = aac_phys_to_logical(channel); + device_config_needed = + (((__le32 *)aifcmd->data)[3] + == cpu_to_le32(EM_DRIVE_INSERTION)) ? + ADD : DELETE; + break; + } + break; } /* @@ -905,13 +965,13 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) if (container >= dev->maximum_num_containers) break; if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) && + le32_to_cpu(*(__le32 *)aifcmd->data)) && time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } else for (container = 0; container < dev->maximum_num_containers; ++container) { if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(u32 *)aifcmd->data)) && + le32_to_cpu(*(__le32 *)aifcmd->data)) && time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) dev->fsa_dev[container].config_waiting_on = 0; } @@ -926,9 +986,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) * wait for a container change. */ - if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero)) - && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5]) - || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) { + if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) && + (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] || + ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) { for (container = 0; container < dev->maximum_num_containers; ++container) { @@ -943,9 +1003,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) jiffies; } } - if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero)) - && (((u32 *)aifcmd->data)[6] == 0) - && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) { + if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) && + ((__le32 *)aifcmd->data)[6] == 0 && + ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) { for (container = 0; container < dev->maximum_num_containers; ++container) { @@ -963,7 +1023,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) break; } - device_config_needed = NOTHING; + if (device_config_needed == NOTHING) for (container = 0; container < dev->maximum_num_containers; ++container) { if ((dev->fsa_dev[container].config_waiting_on == 0) && @@ -972,6 +1032,9 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) device_config_needed = dev->fsa_dev[container].config_needed; dev->fsa_dev[container].config_needed = NOTHING; + channel = CONTAINER_TO_CHANNEL(container); + id = CONTAINER_TO_ID(container); + lun = CONTAINER_TO_LUN(container); break; } } @@ -995,34 +1058,56 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) /* * force reload of disk info via aac_probe_container */ - if ((device_config_needed == CHANGE) - && (dev->fsa_dev[container].valid == 1)) - dev->fsa_dev[container].valid = 2; - if ((device_config_needed == CHANGE) || - (device_config_needed == ADD)) + if ((channel == CONTAINER_CHANNEL) && + (device_config_needed != NOTHING)) { + if (dev->fsa_dev[container].valid == 1) + dev->fsa_dev[container].valid = 2; aac_probe_container(dev, container); - device = scsi_device_lookup(dev->scsi_host_ptr, - CONTAINER_TO_CHANNEL(container), - CONTAINER_TO_ID(container), - CONTAINER_TO_LUN(container)); + } + device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun); if (device) { switch (device_config_needed) { case DELETE: + if (scsi_device_online(device)) { + scsi_device_set_state(device, SDEV_OFFLINE); + sdev_printk(KERN_INFO, device, + "Device offlined - %s\n", + (channel == CONTAINER_CHANNEL) ? + "array deleted" : + "enclosure services event"); + } + break; + case ADD: + if (!scsi_device_online(device)) { + sdev_printk(KERN_INFO, device, + "Device online - %s\n", + (channel == CONTAINER_CHANNEL) ? + "array created" : + "enclosure services event"); + scsi_device_set_state(device, SDEV_RUNNING); + } + /* FALLTHRU */ case CHANGE: + if ((channel == CONTAINER_CHANNEL) + && (!dev->fsa_dev[container].valid)) { + if (!scsi_device_online(device)) + break; + scsi_device_set_state(device, SDEV_OFFLINE); + sdev_printk(KERN_INFO, device, + "Device offlined - %s\n", + "array failed"); + break; + } scsi_rescan_device(&device->sdev_gendev); default: break; } scsi_device_put(device); + device_config_needed = NOTHING; } - if (device_config_needed == ADD) { - scsi_add_device(dev->scsi_host_ptr, - CONTAINER_TO_CHANNEL(container), - CONTAINER_TO_ID(container), - CONTAINER_TO_LUN(container)); - } - + if (device_config_needed == ADD) + scsi_add_device(dev->scsi_host_ptr, channel, id, lun); } static int _aac_reset_adapter(struct aac_dev *aac, int forced) @@ -1099,7 +1184,8 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) free_irq(aac->pdev->irq, aac); kfree(aac->fsa_dev); aac->fsa_dev = NULL; - if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) { + quirks = aac_get_driver_ident(index)->quirks; + if (quirks & AAC_QUIRK_31BIT) { if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) || ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK)))) goto out; @@ -1110,7 +1196,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) } if ((retval = (*(aac_get_driver_ident(index)->init))(aac))) goto out; - if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) + if (quirks & AAC_QUIRK_31BIT) if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) goto out; if (jafo) { @@ -1121,15 +1207,14 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) } } (void)aac_get_adapter_info(aac); - quirks = aac_get_driver_ident(index)->quirks; if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) { - host->sg_tablesize = 34; - host->max_sectors = (host->sg_tablesize * 8) + 112; - } - if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) { - host->sg_tablesize = 17; - host->max_sectors = (host->sg_tablesize * 8) + 112; - } + host->sg_tablesize = 34; + host->max_sectors = (host->sg_tablesize * 8) + 112; + } + if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) { + host->sg_tablesize = 17; + host->max_sectors = (host->sg_tablesize * 8) + 112; + } aac_get_config_status(aac, 1); aac_get_containers(aac); /* @@ -1217,12 +1302,13 @@ int aac_reset_adapter(struct aac_dev * aac, int forced) } /* Quiesce build, flush cache, write through mode */ - aac_send_shutdown(aac); + if (forced < 2) + aac_send_shutdown(aac); spin_lock_irqsave(host->host_lock, flagv); - retval = _aac_reset_adapter(aac, forced); + retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1))); spin_unlock_irqrestore(host->host_lock, flagv); - if (retval == -ENODEV) { + if ((forced < 2) && (retval == -ENODEV)) { /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */ struct fib * fibctx = aac_fib_alloc(aac); if (fibctx) { @@ -1338,11 +1424,11 @@ int aac_check_health(struct aac_dev * aac) fib->data = hw_fib->data; aif = (struct aac_aifcmd *)hw_fib->data; aif->command = cpu_to_le32(AifCmdEventNotify); - aif->seqnum = cpu_to_le32(0xFFFFFFFF); - aif->data[0] = AifEnExpEvent; - aif->data[1] = AifExeFirmwarePanic; - aif->data[2] = AifHighPriority; - aif->data[3] = BlinkLED; + aif->seqnum = cpu_to_le32(0xFFFFFFFF); + ((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent); + ((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic); + ((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority); + ((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED); /* * Put the FIB onto the @@ -1372,14 +1458,14 @@ int aac_check_health(struct aac_dev * aac) printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); - if (!aac_check_reset || + if (!aac_check_reset || ((aac_check_reset != 1) && (aac->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_IGNORE_RESET))) + AAC_OPTION_IGNORE_RESET))) goto out; host = aac->scsi_host_ptr; if (aac->thread->pid != current->pid) spin_lock_irqsave(host->host_lock, flagv); - BlinkLED = _aac_reset_adapter(aac, 0); + BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1); if (aac->thread->pid != current->pid) spin_unlock_irqrestore(host->host_lock, flagv); return BlinkLED; @@ -1399,7 +1485,7 @@ out: * until the queue is empty. When the queue is empty it will wait for * more FIBs. */ - + int aac_command_thread(void *data) { struct aac_dev *dev = data; @@ -1425,30 +1511,29 @@ int aac_command_thread(void *data) add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait); set_current_state(TASK_INTERRUPTIBLE); dprintk ((KERN_INFO "aac_command_thread start\n")); - while(1) - { + while (1) { spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags); while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) { struct list_head *entry; struct aac_aifcmd * aifcmd; set_current_state(TASK_RUNNING); - + entry = dev->queues->queue[HostNormCmdQueue].cmdq.next; list_del(entry); - + spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags); fib = list_entry(entry, struct fib, fiblink); /* - * We will process the FIB here or pass it to a - * worker thread that is TBD. We Really can't + * We will process the FIB here or pass it to a + * worker thread that is TBD. We Really can't * do anything at this point since we don't have * anything defined for this thread to do. */ hw_fib = fib->hw_fib_va; memset(fib, 0, sizeof(struct fib)); fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof( struct fib ); + fib->size = sizeof(struct fib); fib->hw_fib_va = hw_fib; fib->data = hw_fib->data; fib->dev = dev; @@ -1462,20 +1547,19 @@ int aac_command_thread(void *data) *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); aac_fib_adapter_complete(fib, (u16)sizeof(u32)); } else { - struct list_head *entry; /* The u32 here is important and intended. We are using 32bit wrapping time to fit the adapter field */ - + u32 time_now, time_last; unsigned long flagv; unsigned num; struct hw_fib ** hw_fib_pool, ** hw_fib_p; struct fib ** fib_pool, ** fib_p; - + /* Sniff events */ - if ((aifcmd->command == + if ((aifcmd->command == cpu_to_le32(AifCmdEventNotify)) || - (aifcmd->command == + (aifcmd->command == cpu_to_le32(AifCmdJobProgress))) { aac_handle_aif(dev, fib); } @@ -1527,7 +1611,7 @@ int aac_command_thread(void *data) spin_lock_irqsave(&dev->fib_lock, flagv); entry = dev->fib_list.next; /* - * For each Context that is on the + * For each Context that is on the * fibctxList, make a copy of the * fib, and then set the event to wake up the * thread that is waiting for it. @@ -1552,7 +1636,7 @@ int aac_command_thread(void *data) */ time_last = fibctx->jiffies; /* - * Has it been > 2 minutes + * Has it been > 2 minutes * since the last read off * the queue? */ @@ -1583,7 +1667,7 @@ int aac_command_thread(void *data) */ list_add_tail(&newfib->fiblink, &fibctx->fib_list); fibctx->count++; - /* + /* * Set the event to wake up the * thread that is waiting. */ @@ -1655,11 +1739,11 @@ int aac_command_thread(void *data) struct fib *fibptr; if ((fibptr = aac_fib_alloc(dev))) { - u32 * info; + __le32 *info; aac_fib_init(fibptr); - info = (u32 *) fib_data(fibptr); + info = (__le32 *) fib_data(fibptr); if (now.tv_usec > 500000) ++now.tv_sec; diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index e6032ffc66a6..d1163ded132b 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -120,6 +120,7 @@ unsigned int aac_response_normal(struct aac_queue * q) * NOTE: we cannot touch the fib after this * call, because it may have been deallocated. */ + fib->flags = 0; fib->callback(fib->callback_data, fib); } else { unsigned long flagv; @@ -229,11 +230,9 @@ unsigned int aac_command_normal(struct aac_queue *q) * all QE there are and wake up all the waiters before exiting. */ -unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) +unsigned int aac_intr_normal(struct aac_dev * dev, u32 index) { - u32 index = le32_to_cpu(Index); - - dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, Index)); + dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); if ((index & 0x00000002L)) { struct hw_fib * hw_fib; struct fib * fib; @@ -301,7 +300,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) if (hwfib->header.Command == cpu_to_le16(NuFileSystem)) { - u32 *pstatus = (u32 *)hwfib->data; + __le32 *pstatus = (__le32 *)hwfib->data; if (*pstatus & cpu_to_le32(0xffff0000)) *pstatus = cpu_to_le32(ST_OK); } @@ -315,6 +314,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) * NOTE: we cannot touch the fib after this * call, because it may have been deallocated. */ + fib->flags = 0; fib->callback(fib->callback_data, fib); } else { unsigned long flagv; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 9dd331bc29b0..0e8267c1e915 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -159,27 +159,27 @@ static struct pci_device_id aac_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, aac_pci_tbl); /* - * dmb - For now we add the number of channels to this structure. + * dmb - For now we add the number of channels to this structure. * In the future we should add a fib that reports the number of channels * for the card. At that time we can remove the channels from here */ static struct aac_driver_ident aac_drivers[] = { - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */ - { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */ - { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */ - { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */ + { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */ + { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2120S (Crusader) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */ + { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */ @@ -224,8 +224,8 @@ static struct aac_driver_ident aac_drivers[] = { { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */ { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */ - { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */ - { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */ + { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */ + { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */ { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */ @@ -239,7 +239,7 @@ static struct aac_driver_ident aac_drivers[] = { * Queues a command for execution by the associated Host Adapter. * * TODO: unify with aac_scsi_cmd(). - */ + */ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -258,7 +258,7 @@ static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd } cmd->SCp.phase = AAC_OWNER_LOWLEVEL; return (aac_scsi_cmd(cmd) ? FAILED : 0); -} +} /** * aac_info - Returns the host adapter name @@ -292,21 +292,21 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype) * @capacity: the sector capacity of the disk * @geom: geometry block to fill in * - * Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. - * The default disk geometry is 64 heads, 32 sectors, and the appropriate - * number of cylinders so as not to exceed drive capacity. In order for + * Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. + * The default disk geometry is 64 heads, 32 sectors, and the appropriate + * number of cylinders so as not to exceed drive capacity. In order for * disks equal to or larger than 1 GB to be addressable by the BIOS - * without exceeding the BIOS limitation of 1024 cylinders, Extended - * Translation should be enabled. With Extended Translation enabled, - * drives between 1 GB inclusive and 2 GB exclusive are given a disk - * geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive - * are given a disk geometry of 255 heads and 63 sectors. However, if - * the BIOS detects that the Extended Translation setting does not match - * the geometry in the partition table, then the translation inferred - * from the partition table will be used by the BIOS, and a warning may + * without exceeding the BIOS limitation of 1024 cylinders, Extended + * Translation should be enabled. With Extended Translation enabled, + * drives between 1 GB inclusive and 2 GB exclusive are given a disk + * geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive + * are given a disk geometry of 255 heads and 63 sectors. However, if + * the BIOS detects that the Extended Translation setting does not match + * the geometry in the partition table, then the translation inferred + * from the partition table will be used by the BIOS, and a warning may * be displayed. */ - + static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *geom) { @@ -333,10 +333,10 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors); - /* + /* * Read the first 1024 bytes from the disk device, if the boot * sector partition table is valid, search for a partition table - * entry whose end_head matches one of the standard geometry + * entry whose end_head matches one of the standard geometry * translations ( 64/32, 128/32, 255/63 ). */ buf = scsi_bios_ptable(bdev); @@ -401,30 +401,44 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, static int aac_slave_configure(struct scsi_device *sdev) { + struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; if ((sdev->type == TYPE_DISK) && - (sdev_channel(sdev) != CONTAINER_CHANNEL)) { + (sdev_channel(sdev) != CONTAINER_CHANNEL) && + (!aac->jbod || sdev->inq_periph_qual) && + (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) { if (expose_physicals == 0) return -ENXIO; - if (expose_physicals < 0) { - struct aac_dev *aac = - (struct aac_dev *)sdev->host->hostdata; - if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) - sdev->no_uld_attach = 1; - } + if (expose_physicals < 0) + sdev->no_uld_attach = 1; } if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && - (sdev_channel(sdev) == CONTAINER_CHANNEL)) { + (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) && + !sdev->no_uld_attach) { struct scsi_device * dev; struct Scsi_Host *host = sdev->host; unsigned num_lsu = 0; unsigned num_one = 0; unsigned depth; + unsigned cid; + /* + * Firmware has an individual device recovery time typically + * of 35 seconds, give us a margin. + */ + if (sdev->timeout < (45 * HZ)) + sdev->timeout = 45 * HZ; + for (cid = 0; cid < aac->maximum_num_containers; ++cid) + if (aac->fsa_dev[cid].valid) + ++num_lsu; __shost_for_each_device(dev, host) { if (dev->tagged_supported && (dev->type == TYPE_DISK) && - (sdev_channel(dev) == CONTAINER_CHANNEL)) - ++num_lsu; - else + (!aac->raid_scsi_mode || + (sdev_channel(sdev) != 2)) && + !dev->no_uld_attach) { + if ((sdev_channel(dev) != CONTAINER_CHANNEL) + || !aac->fsa_dev[sdev_id(dev)].valid) + ++num_lsu; + } else ++num_one; } if (num_lsu == 0) @@ -481,9 +495,35 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth) return sdev->queue_depth; } +static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_device * sdev = to_scsi_device(dev); + if (sdev_channel(sdev) != CONTAINER_CHANNEL) + return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach + ? "Hidden\n" : "JBOD"); + return snprintf(buf, PAGE_SIZE, "%s\n", + get_container_type(((struct aac_dev *)(sdev->host->hostdata)) + ->fsa_dev[sdev_id(sdev)].type)); +} + +static struct device_attribute aac_raid_level_attr = { + .attr = { + .name = "level", + .mode = S_IRUGO, + }, + .show = aac_show_raid_level +}; + +static struct device_attribute *aac_dev_attrs[] = { + &aac_raid_level_attr, + NULL, +}; + static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) { struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; return aac_do_ioctl(dev, cmd, arg); } @@ -506,17 +546,33 @@ static int aac_eh_abort(struct scsi_cmnd* cmd) break; case INQUIRY: case READ_CAPACITY: - case TEST_UNIT_READY: /* Mark associated FIB to not complete, eh handler does this */ for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { struct fib * fib = &aac->fibs[count]; if (fib->hw_fib_va->header.XferState && + (fib->flags & FIB_CONTEXT_FLAG) && (fib->callback_data == cmd)) { fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; ret = SUCCESS; } } + break; + case TEST_UNIT_READY: + /* Mark associated FIB to not complete, eh handler does this */ + for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { + struct scsi_cmnd * command; + struct fib * fib = &aac->fibs[count]; + if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) && + (fib->flags & FIB_CONTEXT_FLAG) && + ((command = fib->callback_data)) && + (command->device == cmd->device)) { + fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; + command->SCp.phase = AAC_OWNER_ERROR_HANDLER; + if (command == cmd) + ret = SUCCESS; + } + } } return ret; } @@ -539,12 +595,13 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { struct fib * fib = &aac->fibs[count]; if (fib->hw_fib_va->header.XferState && + (fib->flags & FIB_CONTEXT_FLAG) && (fib->callback_data == cmd)) { fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; } } - printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", + printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", AAC_DRIVERNAME); if ((count = aac_check_health(aac))) @@ -584,8 +641,11 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) * support a register, instead of a commanded, reset. */ if ((aac->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) == - le32_to_cpu(AAC_OPTION_MU_RESET)) + AAC_OPTION_MU_RESET) && + aac_check_reset && + ((aac_check_reset != 1) || + (aac->supplement_adapter_info.SupportedOptions2 & + AAC_OPTION_IGNORE_RESET))) aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */ return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ } @@ -632,8 +692,8 @@ static int aac_cfg_open(struct inode *inode, struct file *file) * Bugs: Needs locking against parallel ioctls lower down * Bugs: Needs to handle hot plugging */ - -static int aac_cfg_ioctl(struct inode *inode, struct file *file, + +static int aac_cfg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { if (!capable(CAP_SYS_RAWIO)) @@ -646,7 +706,7 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long { long ret; lock_kernel(); - switch (cmd) { + switch (cmd) { case FSACTL_MINIPORT_REV_CHECK: case FSACTL_SENDFIB: case FSACTL_OPEN_GET_ADAPTER_FIB: @@ -656,14 +716,14 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long case FSACTL_QUERY_DISK: case FSACTL_DELETE_DISK: case FSACTL_FORCE_DELETE_DISK: - case FSACTL_GET_CONTAINERS: + case FSACTL_GET_CONTAINERS: case FSACTL_SEND_LARGE_FIB: ret = aac_do_ioctl(dev, cmd, (void __user *)arg); break; case FSACTL_GET_NEXT_ADAPTER_FIB: { struct fib_ioctl __user *f; - + f = compat_alloc_user_space(sizeof(*f)); ret = 0; if (clear_user(f, sizeof(*f))) @@ -676,9 +736,9 @@ static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long } default: - ret = -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; break; - } + } unlock_kernel(); return ret; } @@ -735,6 +795,25 @@ static ssize_t aac_show_vendor(struct class_device *class_dev, return len; } +static ssize_t aac_show_flags(struct class_device *class_dev, char *buf) +{ + int len = 0; + struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata; + + if (nblank(dprintk(x))) + len = snprintf(buf, PAGE_SIZE, "dprintk\n"); +#ifdef AAC_DETAILED_STATUS_INFO + len += snprintf(buf + len, PAGE_SIZE - len, + "AAC_DETAILED_STATUS_INFO\n"); +#endif + if (dev->raw_io_interface && dev->raw_io_64) + len += snprintf(buf + len, PAGE_SIZE - len, + "SAI_READ_CAPACITY_16\n"); + if (dev->jbod) + len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n"); + return len; +} + static ssize_t aac_show_kernel_version(struct class_device *class_dev, char *buf) { @@ -742,7 +821,7 @@ static ssize_t aac_show_kernel_version(struct class_device *class_dev, int len, tmp; tmp = le32_to_cpu(dev->adapter_info.kernelrev); - len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", + len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff, le32_to_cpu(dev->adapter_info.kernelbuild)); return len; @@ -755,7 +834,7 @@ static ssize_t aac_show_monitor_version(struct class_device *class_dev, int len, tmp; tmp = le32_to_cpu(dev->adapter_info.monitorrev); - len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", + len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff, le32_to_cpu(dev->adapter_info.monitorbuild)); return len; @@ -768,7 +847,7 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev, int len, tmp; tmp = le32_to_cpu(dev->adapter_info.biosrev); - len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", + len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff, le32_to_cpu(dev->adapter_info.biosbuild)); return len; @@ -844,6 +923,13 @@ static struct class_device_attribute aac_vendor = { }, .show = aac_show_vendor, }; +static struct class_device_attribute aac_flags = { + .attr = { + .name = "flags", + .mode = S_IRUGO, + }, + .show = aac_show_flags, +}; static struct class_device_attribute aac_kernel_version = { .attr = { .name = "hba_kernel_version", @@ -898,6 +984,7 @@ static struct class_device_attribute aac_reset = { static struct class_device_attribute *aac_attrs[] = { &aac_model, &aac_vendor, + &aac_flags, &aac_kernel_version, &aac_monitor_version, &aac_bios_version, @@ -928,23 +1015,23 @@ static struct scsi_host_template aac_driver_template = { .compat_ioctl = aac_compat_ioctl, #endif .queuecommand = aac_queuecommand, - .bios_param = aac_biosparm, + .bios_param = aac_biosparm, .shost_attrs = aac_attrs, .slave_configure = aac_slave_configure, .change_queue_depth = aac_change_queue_depth, + .sdev_attrs = aac_dev_attrs, .eh_abort_handler = aac_eh_abort, .eh_host_reset_handler = aac_eh_reset, - .can_queue = AAC_NUM_IO_FIB, + .can_queue = AAC_NUM_IO_FIB, .this_id = MAXIMUM_NUM_CONTAINERS, .sg_tablesize = 16, .max_sectors = 128, #if (AAC_NUM_IO_FIB > 256) .cmd_per_lun = 256, -#else - .cmd_per_lun = AAC_NUM_IO_FIB, -#endif +#else + .cmd_per_lun = AAC_NUM_IO_FIB, +#endif .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .emulated = 1, }; @@ -979,18 +1066,18 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, goto out; error = -ENODEV; - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) goto out_disable_pdev; /* * If the quirk31 bit is set, the adapter needs adapter * to driver communication memory to be allocated below 2gig */ - if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) + if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) if (pci_set_dma_mask(pdev, DMA_31BIT_MASK) || pci_set_consistent_dma_mask(pdev, DMA_31BIT_MASK)) goto out_disable_pdev; - + pci_set_master(pdev); shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev)); @@ -1003,7 +1090,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, shost->max_cmd_len = 16; aac = (struct aac_dev *)shost->hostdata; - aac->scsi_host_ptr = shost; + aac->scsi_host_ptr = shost; aac->pdev = pdev; aac->name = aac_driver_template.name; aac->id = shost->unique_id; @@ -1040,7 +1127,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) goto out_deinit; - + aac->maximum_num_channels = aac_drivers[index].channels; error = aac_get_adapter_info(aac); if (error < 0) @@ -1049,7 +1136,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, /* * Lets override negotiations and drop the maximum SG limit to 34 */ - if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && + if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && (aac->scsi_host_ptr->sg_tablesize > 34)) { aac->scsi_host_ptr->sg_tablesize = 34; aac->scsi_host_ptr->max_sectors @@ -1066,17 +1153,17 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, /* * Firware printf works only with older firmware. */ - if (aac_drivers[index].quirks & AAC_QUIRK_34SG) + if (aac_drivers[index].quirks & AAC_QUIRK_34SG) aac->printf_enabled = 1; else aac->printf_enabled = 0; - + /* * max channel will be the physical channels plus 1 virtual channel * all containers are on the virtual channel 0 (CONTAINER_CHANNEL) * physical channels are address by their actual physical number+1 */ - if ((aac->nondasd_support == 1) || expose_physicals) + if (aac->nondasd_support || expose_physicals || aac->jbod) shost->max_channel = aac->maximum_num_channels; else shost->max_channel = 0; @@ -1148,10 +1235,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev) kfree(aac->queues); aac_adapter_ioremap(aac, 0); - + kfree(aac->fibs); kfree(aac->fsa_dev); - + list_del(&aac->entry); scsi_host_put(shost); pci_disable_device(pdev); @@ -1172,7 +1259,7 @@ static struct pci_driver aac_pci_driver = { static int __init aac_init(void) { int error; - + printk(KERN_INFO "Adaptec %s driver %s\n", AAC_DRIVERNAME, aac_driver_version); diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 73eef3dc5dc6..a08bbf1fd76c 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -465,7 +465,7 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled) u32 var; if (!(dev->supplement_adapter_info.SupportedOptions2 & - le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) { + AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) { if (bled) printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", dev->name, dev->id, bled); @@ -549,7 +549,9 @@ int _aac_rx_init(struct aac_dev *dev) dev->OIMR = status = rx_readb (dev, MUnit.OIMR); if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) && !aac_rx_restart_adapter(dev, 0)) - ++restart; + /* Make sure the Hardware FIFO is empty */ + while ((++restart < 512) && + (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); /* * Check to see if the board panic'd while booting. */ diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 38a1ee2eacd8..374ed025dc5a 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -8233,7 +8233,7 @@ static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) { ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); /* * Note: The 'status_byte()' macro used by * target drivers defined in scsi.h shifts the @@ -9136,7 +9136,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); dma_unmap_single(boardp->dev, scp->SCp.dma_handle, - sizeof(scp->sense_buffer), DMA_FROM_DEVICE); + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); /* * 'qdonep' contains the command's ending status. */ @@ -9166,7 +9166,7 @@ static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) { ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - sizeof(scp->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); /* * Note: The 'status_byte()' macro used by * target drivers defined in scsi.h shifts the @@ -9881,9 +9881,9 @@ static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp) { struct asc_board *board = shost_priv(scp->device->host); scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer, - sizeof(scp->sense_buffer), DMA_FROM_DEVICE); + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); dma_cache_sync(board->dev, scp->sense_buffer, - sizeof(scp->sense_buffer), DMA_FROM_DEVICE); + SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); return cpu_to_le32(scp->SCp.dma_handle); } @@ -9914,7 +9914,7 @@ static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, asc_scsi_q->q2.target_ix = ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp); - asc_scsi_q->q1.sense_len = sizeof(scp->sense_buffer); + asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE; /* * If there are any outstanding requests for the current target, @@ -10173,7 +10173,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, scsiqp->target_lun = scp->device->lun; scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); - scsiqp->sense_len = sizeof(scp->sense_buffer); + scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE; /* Build ADV_SCSI_REQ_Q */ diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index ea8c69947644..6ccdc96cc480 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -260,6 +260,7 @@ #include <scsi/scsi_dbg.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_spi.h> +#include <scsi/scsi_eh.h> #include "aha152x.h" static LIST_HEAD(aha152x_host_list); @@ -558,9 +559,7 @@ struct aha152x_hostdata { struct aha152x_scdata { Scsi_Cmnd *next; /* next sc in queue */ struct completion *done;/* semaphore to block on */ - unsigned char aha_orig_cmd_len; - unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE]; - int aha_orig_resid; + struct scsi_eh_save ses; }; /* access macros for hostdata */ @@ -1017,16 +1016,10 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete, SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ - if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) { - if (phase & check_condition) { - SCpnt->SCp.ptr = SCpnt->sense_buffer; - SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer); - scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer)); - } else { - SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - scsi_set_resid(SCpnt, 0); - } + if ((phase & resetting) || !scsi_sglist(SCpnt)) { + SCpnt->SCp.ptr = NULL; + SCpnt->SCp.this_residual = 0; + scsi_set_resid(SCpnt, 0); SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; } else { @@ -1561,10 +1554,7 @@ static void busfree_run(struct Scsi_Host *shpnt) } #endif - /* restore old command */ - memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd)); - cmd->cmd_len = sc->aha_orig_cmd_len; - scsi_set_resid(cmd, sc->aha_orig_resid); + scsi_eh_restore_cmnd(cmd, &sc->ses); cmd->SCp.Status = SAM_STAT_CHECK_CONDITION; @@ -1587,22 +1577,10 @@ static void busfree_run(struct Scsi_Host *shpnt) DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr)); #endif - /* save old command */ sc = SCDATA(ptr); /* It was allocated in aha152x_internal_queue? */ BUG_ON(!sc); - memcpy(sc->aha_orig_cmnd, ptr->cmnd, - sizeof(ptr->cmnd)); - sc->aha_orig_cmd_len = ptr->cmd_len; - sc->aha_orig_resid = scsi_get_resid(ptr); - - ptr->cmnd[0] = REQUEST_SENSE; - ptr->cmnd[1] = 0; - ptr->cmnd[2] = 0; - ptr->cmnd[3] = 0; - ptr->cmnd[4] = sizeof(ptr->sense_buffer); - ptr->cmnd[5] = 0; - ptr->cmd_len = 6; + scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0); DO_UNLOCK(flags); aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done); diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index bbcc2c52d79f..190568ebea3c 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -51,15 +51,6 @@ #define SCSI_BUF_PA(address) isa_virt_to_bus(address) #define SCSI_SG_PA(sgent) (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset) -static void BAD_DMA(void *address, unsigned int length) -{ - printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n", - address, - SCSI_BUF_PA(address), - length); - panic("Buffer at physical address > 16Mb used for aha1542"); -} - static void BAD_SG_DMA(Scsi_Cmnd * SCpnt, struct scatterlist *sgp, int nseg, @@ -545,7 +536,7 @@ static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id) we will still have it in the cdb when we come back */ if (ccb[mbo].tarstat == 2) memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], - sizeof(SCtmp->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); /* is there mail :-) */ @@ -597,8 +588,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) unchar target = SCpnt->device->id; unchar lun = SCpnt->device->lun; unsigned long flags; - void *buff = SCpnt->request_buffer; - int bufflen = SCpnt->request_bufflen; + int bufflen = scsi_bufflen(SCpnt); int mbo; struct mailbox *mb; struct ccb *ccb; @@ -619,7 +609,7 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) #if 0 /* scsi_request_sense() provides a buffer of size 256, so there is no reason to expect equality */ - if (bufflen != sizeof(SCpnt->sense_buffer)) + if (bufflen != SCSI_SENSE_BUFFERSIZE) printk(KERN_CRIT "aha1542: Wrong buffer length supplied " "for request sense (%d)\n", bufflen); #endif @@ -689,42 +679,29 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); - if (SCpnt->use_sg) { + if (bufflen) { struct scatterlist *sg; struct chain *cptr; #ifdef DEBUG unsigned char *ptr; #endif - int i; + int i, sg_count = scsi_sg_count(SCpnt); ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ - SCpnt->host_scribble = kmalloc(512, GFP_KERNEL | GFP_DMA); + SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count, + GFP_KERNEL | GFP_DMA); cptr = (struct chain *) SCpnt->host_scribble; if (cptr == NULL) { /* free the claimed mailbox slot */ HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL; return SCSI_MLQUEUE_HOST_BUSY; } - scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) { - if (sg->length == 0 || SCpnt->use_sg > 16 || - (((int) sg->offset) & 1) || (sg->length & 1)) { - unsigned char *ptr; - printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i); - scsi_for_each_sg(SCpnt, sg, SCpnt->use_sg, i) { - printk(KERN_CRIT "%d: %p %d\n", i, - sg_virt(sg), sg->length); - }; - printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr); - ptr = (unsigned char *) &cptr[i]; - for (i = 0; i < 18; i++) - printk("%02x ", ptr[i]); - panic("Foooooooood fight!"); - }; + scsi_for_each_sg(SCpnt, sg, sg_count, i) { any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg)); if (SCSI_SG_PA(sg) + sg->length - 1 > ISA_DMA_THRESHOLD) - BAD_SG_DMA(SCpnt, sg, SCpnt->use_sg, i); + BAD_SG_DMA(SCpnt, scsi_sglist(SCpnt), sg_count, i); any2scsi(cptr[i].datalen, sg->length); }; - any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); + any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr)); #ifdef DEBUG printk("cptr %x: ", cptr); @@ -735,10 +712,8 @@ static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) } else { ccb[mbo].op = 0; /* SCSI Initiator Command */ SCpnt->host_scribble = NULL; - any2scsi(ccb[mbo].datalen, bufflen); - if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD) - BAD_DMA(buff, bufflen); - any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff)); + any2scsi(ccb[mbo].datalen, 0); + any2scsi(ccb[mbo].dataptr, 0); }; ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ ccb[mbo].rsalen = 16; diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index f6722fd46008..7c45d88a205b 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -286,7 +286,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id) cdb when we come back */ if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) { memcpy(SCtmp->sense_buffer, ecbptr->sense, - sizeof(SCtmp->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status); } else errstatus = 0; @@ -563,7 +563,6 @@ static struct scsi_host_template aha1740_template = { .sg_tablesize = AHA1740_SCATTER, .cmd_per_lun = AHA1740_CMDLUN, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .eh_abort_handler = aha1740_eh_abort_handler, }; diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile index 9a6ce19a4030..e4f70c563bc2 100644 --- a/drivers/scsi/aic7xxx/Makefile +++ b/drivers/scsi/aic7xxx/Makefile @@ -33,11 +33,10 @@ aic79xx-y += aic79xx_osm.o \ aic79xx_proc.o \ aic79xx_osm_pci.o -EXTRA_CFLAGS += -Idrivers/scsi +ccflags-y += -Idrivers/scsi ifdef WARNINGS_BECOME_ERRORS -EXTRA_CFLAGS += -Werror +ccflags-y += -Werror endif -#EXTRA_CFLAGS += -g # Files generated that shall be removed upon make clean clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c @@ -46,53 +45,45 @@ clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c # Dependencies for generated files need to be listed explicitly $(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h +$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_reg.h $(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h -$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped -$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped +$(obj)/aic79xx_core.o: $(obj)/aic79xx_reg.h -$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h -$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h +$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h +$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h -aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE) := $(obj)/aic7xxx_seq.h \ - $(obj)/aic7xxx_reg.h +aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE) := $(obj)/aic7xxx_reg.h aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += $(obj)/aic7xxx_reg_print.c aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \ -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) -# Create a dependency chain in generated files -# to avoid concurrent invocations of the single -# rule that builds them all. -aic7xxx_seq.h: aic7xxx_reg.h -ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y) -aic7xxx_reg.h: aic7xxx_reg_print.c -endif -$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm +$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \ $(src)/aic7xxx.seq + +$(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h +else +$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped endif -aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE) := $(obj)/aic79xx_seq.h \ - $(obj)/aic79xx_reg.h +aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE) := $(obj)/aic79xx_reg.h aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) += $(obj)/aic79xx_reg_print.c aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \ -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y) -# Create a dependency chain in generated files -# to avoid concurrent invocations of the single -# rule that builds them all. -aic79xx_seq.h: aic79xx_reg.h -ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y) -aic79xx_reg.h: aic79xx_reg_print.c -endif -$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm +$(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \ $(src)/aic79xx.seq + +$(aic79xx-gen-y): $(obj)/aic79xx_seq.h +else +$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped endif $(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl] diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index ce638aa6005a..2f00467b6b8c 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1340,8 +1340,10 @@ struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); int ahd_pci_config(struct ahd_softc *, struct ahd_pci_identity *); int ahd_pci_test_register_access(struct ahd_softc *); +#ifdef CONFIG_PM void ahd_pci_suspend(struct ahd_softc *); void ahd_pci_resume(struct ahd_softc *); +#endif /************************** SCB and SCB queue management **********************/ void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, @@ -1352,8 +1354,10 @@ struct ahd_softc *ahd_alloc(void *platform_arg, char *name); int ahd_softc_init(struct ahd_softc *); void ahd_controller_info(struct ahd_softc *ahd, char *buf); int ahd_init(struct ahd_softc *ahd); +#ifdef CONFIG_PM int ahd_suspend(struct ahd_softc *ahd); void ahd_resume(struct ahd_softc *ahd); +#endif int ahd_default_config(struct ahd_softc *ahd); int ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd); @@ -1361,7 +1365,6 @@ int ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc); void ahd_intr_enable(struct ahd_softc *ahd, int enable); void ahd_pause_and_flushwork(struct ahd_softc *ahd); -int ahd_suspend(struct ahd_softc *ahd); void ahd_set_unit(struct ahd_softc *, int); void ahd_set_name(struct ahd_softc *, char *); struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index a7dd8cdda472..ade0fb8fbdb2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -7175,6 +7175,7 @@ ahd_pause_and_flushwork(struct ahd_softc *ahd) ahd->flags &= ~AHD_ALL_INTERRUPTS; } +#ifdef CONFIG_PM int ahd_suspend(struct ahd_softc *ahd) { @@ -7197,6 +7198,7 @@ ahd_resume(struct ahd_softc *ahd) ahd_intr_enable(ahd, TRUE); ahd_restart(ahd); } +#endif /************************** Busy Target Table *********************************/ /* diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 2d020405480c..014654792901 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -766,7 +766,6 @@ struct scsi_host_template aic79xx_driver_template = { .max_sectors = 8192, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, .target_alloc = ahd_linux_target_alloc, @@ -1784,7 +1783,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, if (scb->flags & SCB_SENSE) { sense_size = min(sizeof(struct scsi_sense_data) - ahd_get_sense_residual(scb), - (u_long)sizeof(cmd->sense_buffer)); + (u_long)SCSI_SENSE_BUFFERSIZE); sense_offset = 0; } else { /* @@ -1795,11 +1794,11 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, scb->sense_data; sense_size = min_t(size_t, scsi_4btoul(siu->sense_length), - sizeof(cmd->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); sense_offset = SIU_SENSE_OFFSET(siu); } - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); memcpy(cmd->sense_buffer, ahd_get_sense_buf(ahd, scb) + sense_offset, sense_size); @@ -1922,7 +1921,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) struct scsi_sense_data *sense; sense = (struct scsi_sense_data *) - &cmd->sense_buffer; + cmd->sense_buffer; if (sense->extra_len >= 5 && (sense->add_sense_code == 0x47 || sense->add_sense_code == 0x48)) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 66f0259edb69..4150c8a8fdc2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -43,17 +43,6 @@ #include "aic79xx_inline.h" #include "aic79xx_pci.h" -static int ahd_linux_pci_dev_probe(struct pci_dev *pdev, - const struct pci_device_id *ent); -static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, - u_long *base, u_long *base2); -static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, - u_long *bus_addr, - uint8_t __iomem **maddr); -static int ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg); -static int ahd_linux_pci_dev_resume(struct pci_dev *pdev); -static void ahd_linux_pci_dev_remove(struct pci_dev *pdev); - /* Define the macro locally since it's different for different class of chips. */ #define ID(x) \ @@ -85,17 +74,7 @@ static struct pci_device_id ahd_linux_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table); -static struct pci_driver aic79xx_pci_driver = { - .name = "aic79xx", - .probe = ahd_linux_pci_dev_probe, #ifdef CONFIG_PM - .suspend = ahd_linux_pci_dev_suspend, - .resume = ahd_linux_pci_dev_resume, -#endif - .remove = ahd_linux_pci_dev_remove, - .id_table = ahd_linux_pci_id_table -}; - static int ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) { @@ -139,6 +118,7 @@ ahd_linux_pci_dev_resume(struct pci_dev *pdev) return rc; } +#endif static void ahd_linux_pci_dev_remove(struct pci_dev *pdev) @@ -245,6 +225,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return (0); } +static struct pci_driver aic79xx_pci_driver = { + .name = "aic79xx", + .probe = ahd_linux_pci_dev_probe, +#ifdef CONFIG_PM + .suspend = ahd_linux_pci_dev_suspend, + .resume = ahd_linux_pci_dev_resume, +#endif + .remove = ahd_linux_pci_dev_remove, + .id_table = ahd_linux_pci_id_table +}; + int ahd_linux_pci_init(void) { diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 7a203a90601a..df853676e66a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -389,6 +389,7 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) return error; } +#ifdef CONFIG_PM void ahd_pci_suspend(struct ahd_softc *ahd) { @@ -415,6 +416,7 @@ ahd_pci_resume(struct ahd_softc *ahd) ahd_pci_write_config(ahd->dev_softc, CSIZE_LATTIME, ahd->suspend_state.pci_state.csize_lattime, /*bytes*/1); } +#endif /* * Perform some simple tests that should catch situations where diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 3d4e42d90452..c0344e617651 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -1143,7 +1143,9 @@ struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t); int ahc_pci_config(struct ahc_softc *, struct ahc_pci_identity *); int ahc_pci_test_register_access(struct ahc_softc *); +#ifdef CONFIG_PM void ahc_pci_resume(struct ahc_softc *ahc); +#endif /*************************** EISA/VL Front End ********************************/ struct aic7770_identity *aic7770_find_device(uint32_t); @@ -1170,8 +1172,10 @@ int ahc_chip_init(struct ahc_softc *ahc); int ahc_init(struct ahc_softc *ahc); void ahc_intr_enable(struct ahc_softc *ahc, int enable); void ahc_pause_and_flushwork(struct ahc_softc *ahc); +#ifdef CONFIG_PM int ahc_suspend(struct ahc_softc *ahc); int ahc_resume(struct ahc_softc *ahc); +#endif void ahc_set_unit(struct ahc_softc *, int); void ahc_set_name(struct ahc_softc *, char *); void ahc_alloc_scbs(struct ahc_softc *ahc); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index f350b5e89e76..6d2ae641273c 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -5078,6 +5078,7 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) ahc->flags &= ~AHC_ALL_INTERRUPTS; } +#ifdef CONFIG_PM int ahc_suspend(struct ahc_softc *ahc) { @@ -5113,7 +5114,7 @@ ahc_resume(struct ahc_softc *ahc) ahc_restart(ahc); return (0); } - +#endif /************************** Busy Target Table *********************************/ /* * Return the untagged transaction id for a given target/channel lun. diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 390b0fc991c5..99a3b33a3233 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -747,7 +747,6 @@ struct scsi_host_template aic7xxx_driver_template = { .max_sectors = 8192, .cmd_per_lun = 2, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .slave_alloc = ahc_linux_slave_alloc, .slave_configure = ahc_linux_slave_configure, .target_alloc = ahc_linux_target_alloc, @@ -1658,9 +1657,12 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) untagged_q = &(ahc->untagged_queues[target_offset]); TAILQ_REMOVE(untagged_q, scb, links.tqe); BUG_ON(!TAILQ_EMPTY(untagged_q)); - } - - if ((scb->flags & SCB_ACTIVE) == 0) { + } else if ((scb->flags & SCB_ACTIVE) == 0) { + /* + * Transactions aborted from the untagged queue may + * not have been dispatched to the controller, so + * only check the SCB_ACTIVE flag for tagged transactions. + */ printf("SCB %d done'd twice\n", scb->hscb->tag); ahc_dump_card_state(ahc); panic("Stopping for safety"); @@ -1801,12 +1803,12 @@ ahc_linux_handle_scsi_status(struct ahc_softc *ahc, sense_size = min(sizeof(struct scsi_sense_data) - ahc_get_sense_residual(scb), - (u_long)sizeof(cmd->sense_buffer)); + (u_long)SCSI_SENSE_BUFFERSIZE); memcpy(cmd->sense_buffer, ahc_get_sense_buf(ahc, scb), sense_size); - if (sense_size < sizeof(cmd->sense_buffer)) + if (sense_size < SCSI_SENSE_BUFFERSIZE) memset(&cmd->sense_buffer[sense_size], 0, - sizeof(cmd->sense_buffer) - sense_size); + SCSI_SENSE_BUFFERSIZE - sense_size); cmd->result |= (DRIVER_SENSE << 24); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_SENSE) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 4488946cff2e..dd6e21d6f1dd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -42,17 +42,6 @@ #include "aic7xxx_osm.h" #include "aic7xxx_pci.h" -static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, - const struct pci_device_id *ent); -static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, - u_long *base); -static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, - u_long *bus_addr, - uint8_t __iomem **maddr); -static int ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg); -static int ahc_linux_pci_dev_resume(struct pci_dev *pdev); -static void ahc_linux_pci_dev_remove(struct pci_dev *pdev); - /* Define the macro locally since it's different for different class of chips. */ #define ID(x) ID_C(x, PCI_CLASS_STORAGE_SCSI) @@ -132,17 +121,7 @@ static struct pci_device_id ahc_linux_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table); -static struct pci_driver aic7xxx_pci_driver = { - .name = "aic7xxx", - .probe = ahc_linux_pci_dev_probe, #ifdef CONFIG_PM - .suspend = ahc_linux_pci_dev_suspend, - .resume = ahc_linux_pci_dev_resume, -#endif - .remove = ahc_linux_pci_dev_remove, - .id_table = ahc_linux_pci_id_table -}; - static int ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) { @@ -182,6 +161,7 @@ ahc_linux_pci_dev_resume(struct pci_dev *pdev) return (ahc_resume(ahc)); } +#endif static void ahc_linux_pci_dev_remove(struct pci_dev *pdev) @@ -289,6 +269,17 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return (0); } +static struct pci_driver aic7xxx_pci_driver = { + .name = "aic7xxx", + .probe = ahc_linux_pci_dev_probe, +#ifdef CONFIG_PM + .suspend = ahc_linux_pci_dev_suspend, + .resume = ahc_linux_pci_dev_resume, +#endif + .remove = ahc_linux_pci_dev_remove, + .id_table = ahc_linux_pci_id_table +}; + int ahc_linux_pci_init(void) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c index ae35937b8055..56848f41e4f9 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c @@ -2020,6 +2020,7 @@ ahc_pci_chip_init(struct ahc_softc *ahc) return (ahc_chip_init(ahc)); } +#ifdef CONFIG_PM void ahc_pci_resume(struct ahc_softc *ahc) { @@ -2051,6 +2052,7 @@ ahc_pci_resume(struct ahc_softc *ahc) ahc_release_seeprom(&sd); } } +#endif static int ahc_aic785X_setup(struct ahc_softc *ahc) diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 8f8db5f0aef7..3bfd9296bbfa 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -2696,7 +2696,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) { pci_unmap_single(p->pdev, le32_to_cpu(scb->sg_list[0].address), - sizeof(cmd->sense_buffer), + SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); } if (scb->flags & SCB_RECOVERY_SCB) @@ -4267,13 +4267,13 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) sizeof(generic_sense)); scb->sense_cmd[1] = (cmd->device->lun << 5); - scb->sense_cmd[4] = sizeof(cmd->sense_buffer); + scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE; scb->sg_list[0].length = - cpu_to_le32(sizeof(cmd->sense_buffer)); + cpu_to_le32(SCSI_SENSE_BUFFERSIZE); scb->sg_list[0].address = cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer, - sizeof(cmd->sense_buffer), + SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); /* @@ -4296,7 +4296,7 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) hscb->residual_data_count[2] = 0; scb->sg_count = hscb->SG_segment_count = 1; - scb->sg_length = sizeof(cmd->sense_buffer); + scb->sg_length = SCSI_SENSE_BUFFERSIZE; scb->tag_action = 0; scb->flags |= SCB_SENSE; /* @@ -10293,7 +10293,6 @@ static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) aic7xxx_position(cmd) = scb->hscb->tag; cmd->scsi_done = fn; cmd->result = DID_OK; - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); aic7xxx_error(cmd) = DID_OK; aic7xxx_status(cmd) = 0; cmd->host_scribble = NULL; @@ -11142,7 +11141,6 @@ static struct scsi_host_template driver_template = { .max_sectors = 2048, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 3dce618bf414..72042cae7768 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -165,7 +165,7 @@ static int asd_init_target_ddb(struct domain_device *dev) if (dev->port->oob_mode != SATA_OOB_MODE) { flags |= OPEN_REQUIRED; if ((dev->dev_type == SATA_DEV) || - (dev->tproto & SAS_PROTO_STP)) { + (dev->tproto & SAS_PROTOCOL_STP)) { struct smp_resp *rps_resp = &dev->sata_dev.rps_resp; if (rps_resp->frame_type == SMP_RESPONSE && rps_resp->function == SMP_REPORT_PHY_SATA && @@ -193,7 +193,7 @@ static int asd_init_target_ddb(struct domain_device *dev) asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags); flags = 0; - if (dev->tproto & SAS_PROTO_STP) + if (dev->tproto & SAS_PROTOCOL_STP) flags |= STP_CL_POL_NO_TX; asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags); @@ -201,7 +201,7 @@ static int asd_init_target_ddb(struct domain_device *dev) asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF); asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF); - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) { + if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { i = asd_init_sata(dev); if (i < 0) { asd_free_ddb(asd_ha, ddb); diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c index 6bd8e3059d27..3d8c4ff1f2ef 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.c +++ b/drivers/scsi/aic94xx/aic94xx_dump.c @@ -903,11 +903,11 @@ void asd_dump_frame_rcvd(struct asd_phy *phy, int i; switch ((dl->status_block[1] & 0x70) >> 3) { - case SAS_PROTO_STP: + case SAS_PROTOCOL_STP: ASD_DPRINTK("STP proto device-to-host FIS:\n"); break; default: - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: ASD_DPRINTK("SAS proto IDENTIFY:\n"); break; } diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 0cd7eed9196c..098b5f39cd31 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -91,7 +91,7 @@ static int asd_init_phy(struct asd_phy *phy) sas_phy->enabled = 1; sas_phy->class = SAS; - sas_phy->iproto = SAS_PROTO_ALL; + sas_phy->iproto = SAS_PROTOCOL_ALL; sas_phy->tproto = 0; sas_phy->type = PHY_TYPE_PHYSICAL; sas_phy->role = PHY_ROLE_INITIATOR; diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index 491e5d8a98bc..150f6706d23f 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -72,6 +72,7 @@ struct flash_struct { u8 manuf; u8 dev_id; u8 sec_prot; + u8 method; u32 dir_offs; }; @@ -216,6 +217,8 @@ struct asd_ha_struct { struct dma_pool *scb_pool; struct asd_seq_data seq; /* sequencer related */ + u32 bios_status; + const struct firmware *bios_image; }; /* ---------- Common macros ---------- */ diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index b70d6e7f96e9..5d761eb67442 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/firmware.h> #include <scsi/scsi_host.h> @@ -36,6 +37,7 @@ #include "aic94xx_reg.h" #include "aic94xx_hwi.h" #include "aic94xx_seq.h" +#include "aic94xx_sds.h" /* The format is "version.release.patchlevel" */ #define ASD_DRIVER_VERSION "1.0.3" @@ -134,7 +136,7 @@ Err: return err; } -static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha) +static void asd_unmap_memio(struct asd_ha_struct *asd_ha) { struct asd_ha_addrspace *io_handle; @@ -171,7 +173,7 @@ static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha) return err; } -static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha) +static void asd_unmap_ioport(struct asd_ha_struct *asd_ha) { pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET); } @@ -208,7 +210,7 @@ Err: return err; } -static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha) +static void asd_unmap_ha(struct asd_ha_struct *asd_ha) { if (asd_ha->iospace) asd_unmap_ioport(asd_ha); @@ -313,6 +315,181 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev, } static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); +#define FLASH_CMD_NONE 0x00 +#define FLASH_CMD_UPDATE 0x01 +#define FLASH_CMD_VERIFY 0x02 + +struct flash_command { + u8 command[8]; + int code; +}; + +static struct flash_command flash_command_table[] = +{ + {"verify", FLASH_CMD_VERIFY}, + {"update", FLASH_CMD_UPDATE}, + {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ +}; + +struct error_bios { + char *reason; + int err_code; +}; + +static struct error_bios flash_error_table[] = +{ + {"Failed to open bios image file", FAIL_OPEN_BIOS_FILE}, + {"PCI ID mismatch", FAIL_CHECK_PCI_ID}, + {"Checksum mismatch", FAIL_CHECK_SUM}, + {"Unknown Error", FAIL_UNKNOWN}, + {"Failed to verify.", FAIL_VERIFY}, + {"Failed to reset flash chip.", FAIL_RESET_FLASH}, + {"Failed to find flash chip type.", FAIL_FIND_FLASH_ID}, + {"Failed to erash flash chip.", FAIL_ERASE_FLASH}, + {"Failed to program flash chip.", FAIL_WRITE_FLASH}, + {"Flash in progress", FLASH_IN_PROGRESS}, + {"Image file size Error", FAIL_FILE_SIZE}, + {"Input parameter error", FAIL_PARAMETERS}, + {"Out of memory", FAIL_OUT_MEMORY}, + {"OK", 0} /* Last entry err_code = 0. */ +}; + +static ssize_t asd_store_update_bios(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); + char *cmd_ptr, *filename_ptr; + struct bios_file_header header, *hdr_ptr; + int res, i; + u32 csum = 0; + int flash_command = FLASH_CMD_NONE; + int err = 0; + + cmd_ptr = kzalloc(count*2, GFP_KERNEL); + + if (!cmd_ptr) { + err = FAIL_OUT_MEMORY; + goto out; + } + + filename_ptr = cmd_ptr + count; + res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); + if (res != 2) { + err = FAIL_PARAMETERS; + goto out1; + } + + for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { + if (!memcmp(flash_command_table[i].command, + cmd_ptr, strlen(cmd_ptr))) { + flash_command = flash_command_table[i].code; + break; + } + } + if (flash_command == FLASH_CMD_NONE) { + err = FAIL_PARAMETERS; + goto out1; + } + + if (asd_ha->bios_status == FLASH_IN_PROGRESS) { + err = FLASH_IN_PROGRESS; + goto out1; + } + err = request_firmware(&asd_ha->bios_image, + filename_ptr, + &asd_ha->pcidev->dev); + if (err) { + asd_printk("Failed to load bios image file %s, error %d\n", + filename_ptr, err); + err = FAIL_OPEN_BIOS_FILE; + goto out1; + } + + hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data; + + if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor || + hdr_ptr->contrl_id.device != asd_ha->pcidev->device) && + (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor || + hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) { + + ASD_DPRINTK("The PCI vendor or device id does not match\n"); + ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x" + " pci vendor=%x pci dev=%x\n", + hdr_ptr->contrl_id.vendor, + hdr_ptr->contrl_id.device, + hdr_ptr->contrl_id.sub_vendor, + hdr_ptr->contrl_id.sub_device, + asd_ha->pcidev->vendor, + asd_ha->pcidev->device); + err = FAIL_CHECK_PCI_ID; + goto out2; + } + + if (hdr_ptr->filelen != asd_ha->bios_image->size) { + err = FAIL_FILE_SIZE; + goto out2; + } + + /* calculate checksum */ + for (i = 0; i < hdr_ptr->filelen; i++) + csum += asd_ha->bios_image->data[i]; + + if ((csum & 0x0000ffff) != hdr_ptr->checksum) { + ASD_DPRINTK("BIOS file checksum mismatch\n"); + err = FAIL_CHECK_SUM; + goto out2; + } + if (flash_command == FLASH_CMD_UPDATE) { + asd_ha->bios_status = FLASH_IN_PROGRESS; + err = asd_write_flash_seg(asd_ha, + &asd_ha->bios_image->data[sizeof(*hdr_ptr)], + 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); + if (!err) + err = asd_verify_flash_seg(asd_ha, + &asd_ha->bios_image->data[sizeof(*hdr_ptr)], + 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); + } else { + asd_ha->bios_status = FLASH_IN_PROGRESS; + err = asd_verify_flash_seg(asd_ha, + &asd_ha->bios_image->data[sizeof(header)], + 0, hdr_ptr->filelen-sizeof(header)); + } + +out2: + release_firmware(asd_ha->bios_image); +out1: + kfree(cmd_ptr); +out: + asd_ha->bios_status = err; + + if (!err) + return count; + else + return -err; +} + +static ssize_t asd_show_update_bios(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i; + struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); + + for (i = 0; flash_error_table[i].err_code != 0; i++) { + if (flash_error_table[i].err_code == asd_ha->bios_status) + break; + } + if (asd_ha->bios_status != FLASH_IN_PROGRESS) + asd_ha->bios_status = FLASH_OK; + + return snprintf(buf, PAGE_SIZE, "status=%x %s\n", + flash_error_table[i].err_code, + flash_error_table[i].reason); +} + +static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUGO, + asd_show_update_bios, asd_store_update_bios); + static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) { int err; @@ -328,9 +505,14 @@ static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); if (err) goto err_biosb; + err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); + if (err) + goto err_update_bios; return 0; +err_update_bios: + device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); err_biosb: device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); err_rev: @@ -343,6 +525,7 @@ static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha) device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); + device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); } /* The first entry, 0, is used for dynamic ids, the rest for devices @@ -589,6 +772,7 @@ static int __devinit asd_pci_probe(struct pci_dev *dev, asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; asd_ha->sas_ha.lldd_ha = asd_ha; + asd_ha->bios_status = FLASH_OK; asd_ha->name = asd_dev->name; asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index db6ab1a3b81e..0febad4dd75f 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -788,12 +788,12 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc) /* initiator port settings are in the hi nibble */ if (phy->sas_phy.role == PHY_ROLE_INITIATOR) - control_phy->port_type = SAS_PROTO_ALL << 4; + control_phy->port_type = SAS_PROTOCOL_ALL << 4; else if (phy->sas_phy.role == PHY_ROLE_TARGET) - control_phy->port_type = SAS_PROTO_ALL; + control_phy->port_type = SAS_PROTOCOL_ALL; else control_phy->port_type = - (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL; + (SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL; /* link reset retries, this should be nominal */ control_phy->link_reset_retries = 10; diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index 06509bff71f7..2a4c933eb89c 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -30,6 +30,7 @@ #include "aic94xx.h" #include "aic94xx_reg.h" +#include "aic94xx_sds.h" /* ---------- OCM stuff ---------- */ @@ -1083,3 +1084,391 @@ out: kfree(flash_dir); return err; } + +/** + * asd_verify_flash_seg - verify data with flash memory + * @asd_ha: pointer to the host adapter structure + * @src: pointer to the source data to be verified + * @dest_offset: offset from flash memory + * @bytes_to_verify: total bytes to verify + */ +int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_verify) +{ + u8 *src_buf; + u8 flash_char; + int err; + u32 nv_offset, reg, i; + + reg = asd_ha->hw_prof.flash.bar; + src_buf = NULL; + + err = FLASH_OK; + nv_offset = dest_offset; + src_buf = (u8 *)src; + for (i = 0; i < bytes_to_verify; i++) { + flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i); + if (flash_char != src_buf[i]) { + err = FAIL_VERIFY; + break; + } + } + return err; +} + +/** + * asd_write_flash_seg - write data into flash memory + * @asd_ha: pointer to the host adapter structure + * @src: pointer to the source data to be written + * @dest_offset: offset from flash memory + * @bytes_to_write: total bytes to write + */ +int asd_write_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_write) +{ + u8 *src_buf; + u32 nv_offset, reg, i; + int err; + + reg = asd_ha->hw_prof.flash.bar; + src_buf = NULL; + + err = asd_check_flash_type(asd_ha); + if (err) { + ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err); + return err; + } + + nv_offset = dest_offset; + err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write); + if (err) { + ASD_DPRINTK("Erase failed at offset:0x%x\n", + nv_offset); + return err; + } + + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + src_buf = (u8 *)src; + for (i = 0; i < bytes_to_write; i++) { + /* Setup program command sequence */ + switch (asd_ha->hw_prof.flash.method) { + case FLASH_METHOD_A: + { + asd_write_reg_byte(asd_ha, + (reg + 0xAAA), 0xAA); + asd_write_reg_byte(asd_ha, + (reg + 0x555), 0x55); + asd_write_reg_byte(asd_ha, + (reg + 0xAAA), 0xA0); + asd_write_reg_byte(asd_ha, + (reg + nv_offset + i), + (*(src_buf + i))); + break; + } + case FLASH_METHOD_B: + { + asd_write_reg_byte(asd_ha, + (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, + (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, + (reg + 0x555), 0xA0); + asd_write_reg_byte(asd_ha, + (reg + nv_offset + i), + (*(src_buf + i))); + break; + } + default: + break; + } + if (asd_chk_write_status(asd_ha, + (nv_offset + i), 0) != 0) { + ASD_DPRINTK("aicx: Write failed at offset:0x%x\n", + reg + nv_offset + i); + return FAIL_WRITE_FLASH; + } + } + + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + return 0; +} + +int asd_chk_write_status(struct asd_ha_struct *asd_ha, + u32 sector_addr, u8 erase_flag) +{ + u32 reg; + u32 loop_cnt; + u8 nv_data1, nv_data2; + u8 toggle_bit1; + + /* + * Read from DQ2 requires sector address + * while it's dont care for DQ6 + */ + reg = asd_ha->hw_prof.flash.bar; + + for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) { + nv_data1 = asd_read_reg_byte(asd_ha, reg); + nv_data2 = asd_read_reg_byte(asd_ha, reg); + + toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) + ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6)); + + if (toggle_bit1 == 0) { + return 0; + } else { + if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) { + nv_data1 = asd_read_reg_byte(asd_ha, + reg); + nv_data2 = asd_read_reg_byte(asd_ha, + reg); + toggle_bit1 = + ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) + ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6)); + + if (toggle_bit1 == 0) + return 0; + } + } + + /* + * ERASE is a sector-by-sector operation and requires + * more time to finish while WRITE is byte-byte-byte + * operation and takes lesser time to finish. + * + * For some strange reason a reduced ERASE delay gives different + * behaviour across different spirit boards. Hence we set + * a optimum balance of 50mus for ERASE which works well + * across all boards. + */ + if (erase_flag) { + udelay(FLASH_STATUS_ERASE_DELAY_COUNT); + } else { + udelay(FLASH_STATUS_WRITE_DELAY_COUNT); + } + } + return -1; +} + +/** + * asd_hwi_erase_nv_sector - Erase the flash memory sectors. + * @asd_ha: pointer to the host adapter structure + * @flash_addr: pointer to offset from flash memory + * @size: total bytes to erase. + */ +int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size) +{ + u32 reg; + u32 sector_addr; + + reg = asd_ha->hw_prof.flash.bar; + + /* sector staring address */ + sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK; + + /* + * Erasing an flash sector needs to be done in six consecutive + * write cyles. + */ + while (sector_addr < flash_addr+size) { + switch (asd_ha->hw_prof.flash.method) { + case FLASH_METHOD_A: + asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55); + asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80); + asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55); + asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30); + break; + case FLASH_METHOD_B: + asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30); + break; + default: + break; + } + + if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0) + return FAIL_ERASE_FLASH; + + sector_addr += FLASH_SECTOR_SIZE; + } + + return 0; +} + +int asd_check_flash_type(struct asd_ha_struct *asd_ha) +{ + u8 manuf_id; + u8 dev_id; + u8 sec_prot; + u32 inc; + u32 reg; + int err; + + /* get Flash memory base address */ + reg = asd_ha->hw_prof.flash.bar; + + /* Determine flash info */ + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN; + asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN; + asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN; + + /* Get flash info. This would most likely be AMD Am29LV family flash. + * First try the sequence for word mode. It is the same as for + * 008B (byte mode only), 160B (word mode) and 800D (word mode). + */ + inc = asd_ha->hw_prof.flash.wide ? 2 : 1; + asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA); + asd_write_reg_byte(asd_ha, reg + 0x555, 0x55); + asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90); + manuf_id = asd_read_reg_byte(asd_ha, reg); + dev_id = asd_read_reg_byte(asd_ha, reg + inc); + sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc); + /* Get out of autoselect mode. */ + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) " + "sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot); + err = asd_reset_flash(asd_ha); + if (err != 0) + return err; + + switch (manuf_id) { + case FLASH_MANUF_ID_AMD: + switch (sec_prot) { + case FLASH_DEV_ID_AM29LV800DT: + case FLASH_DEV_ID_AM29LV640MT: + case FLASH_DEV_ID_AM29F800B: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_ST: + switch (sec_prot) { + case FLASH_DEV_ID_STM29W800DT: + case FLASH_DEV_ID_STM29LV640: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_FUJITSU: + switch (sec_prot) { + case FLASH_DEV_ID_MBM29LV800TE: + case FLASH_DEV_ID_MBM29DL800TA: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + } + break; + case FLASH_MANUF_ID_MACRONIX: + switch (sec_prot) { + case FLASH_DEV_ID_MX29LV800BT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_A; + break; + } + break; + } + + if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) { + err = asd_reset_flash(asd_ha); + if (err) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + /* Issue Unlock sequence for AM29LV008BT */ + asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); + asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); + asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90); + manuf_id = asd_read_reg_byte(asd_ha, reg); + dev_id = asd_read_reg_byte(asd_ha, reg + inc); + sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc); + + ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot" + "(0x%x)\n", manuf_id, dev_id, sec_prot); + + err = asd_reset_flash(asd_ha); + if (err != 0) { + ASD_DPRINTK("couldn't reset flash. err=%d\n", err); + return err; + } + + switch (manuf_id) { + case FLASH_MANUF_ID_AMD: + switch (dev_id) { + case FLASH_DEV_ID_AM29LV008BT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_ST: + switch (dev_id) { + case FLASH_DEV_ID_STM29008: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + default: + break; + } + break; + case FLASH_MANUF_ID_FUJITSU: + switch (dev_id) { + case FLASH_DEV_ID_MBM29LV008TA: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + } + break; + case FLASH_MANUF_ID_INTEL: + switch (dev_id) { + case FLASH_DEV_ID_I28LV00TAT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + } + break; + case FLASH_MANUF_ID_MACRONIX: + switch (dev_id) { + case FLASH_DEV_ID_I28LV00TAT: + asd_ha->hw_prof.flash.method = FLASH_METHOD_B; + break; + } + break; + default: + return FAIL_FIND_FLASH_ID; + } + } + + if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) + return FAIL_FIND_FLASH_ID; + + asd_ha->hw_prof.flash.manuf = manuf_id; + asd_ha->hw_prof.flash.dev_id = dev_id; + asd_ha->hw_prof.flash.sec_prot = sec_prot; + return 0; +} diff --git a/drivers/scsi/aic94xx/aic94xx_sds.h b/drivers/scsi/aic94xx/aic94xx_sds.h new file mode 100644 index 000000000000..bb9795a04dc3 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_sds.h @@ -0,0 +1,121 @@ +/* + * Aic94xx SAS/SATA driver hardware interface header file. + * + * Copyright (C) 2005 Adaptec, Inc. All rights reserved. + * Copyright (C) 2005 Gilbert Wu <gilbert_wu@adaptec.com> + * + * This file is licensed under GPLv2. + * + * This file is part of the aic94xx driver. + * + * The aic94xx driver 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 of the + * License. + * + * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef _AIC94XX_SDS_H_ +#define _AIC94XX_SDS_H_ + +enum { + FLASH_METHOD_UNKNOWN, + FLASH_METHOD_A, + FLASH_METHOD_B +}; + +#define FLASH_MANUF_ID_AMD 0x01 +#define FLASH_MANUF_ID_ST 0x20 +#define FLASH_MANUF_ID_FUJITSU 0x04 +#define FLASH_MANUF_ID_MACRONIX 0xC2 +#define FLASH_MANUF_ID_INTEL 0x89 +#define FLASH_MANUF_ID_UNKNOWN 0xFF + +#define FLASH_DEV_ID_AM29LV008BT 0x3E +#define FLASH_DEV_ID_AM29LV800DT 0xDA +#define FLASH_DEV_ID_STM29W800DT 0xD7 +#define FLASH_DEV_ID_STM29LV640 0xDE +#define FLASH_DEV_ID_STM29008 0xEA +#define FLASH_DEV_ID_MBM29LV800TE 0xDA +#define FLASH_DEV_ID_MBM29DL800TA 0x4A +#define FLASH_DEV_ID_MBM29LV008TA 0x3E +#define FLASH_DEV_ID_AM29LV640MT 0x7E +#define FLASH_DEV_ID_AM29F800B 0xD6 +#define FLASH_DEV_ID_MX29LV800BT 0xDA +#define FLASH_DEV_ID_MX29LV008CT 0xDA +#define FLASH_DEV_ID_I28LV00TAT 0x3E +#define FLASH_DEV_ID_UNKNOWN 0xFF + +/* status bit mask values */ +#define FLASH_STATUS_BIT_MASK_DQ6 0x40 +#define FLASH_STATUS_BIT_MASK_DQ5 0x20 +#define FLASH_STATUS_BIT_MASK_DQ2 0x04 + +/* minimum value in micro seconds needed for checking status */ +#define FLASH_STATUS_ERASE_DELAY_COUNT 50 +#define FLASH_STATUS_WRITE_DELAY_COUNT 25 + +#define FLASH_SECTOR_SIZE 0x010000 +#define FLASH_SECTOR_SIZE_MASK 0xffff0000 + +#define FLASH_OK 0x000000 +#define FAIL_OPEN_BIOS_FILE 0x000100 +#define FAIL_CHECK_PCI_ID 0x000200 +#define FAIL_CHECK_SUM 0x000300 +#define FAIL_UNKNOWN 0x000400 +#define FAIL_VERIFY 0x000500 +#define FAIL_RESET_FLASH 0x000600 +#define FAIL_FIND_FLASH_ID 0x000700 +#define FAIL_ERASE_FLASH 0x000800 +#define FAIL_WRITE_FLASH 0x000900 +#define FAIL_FILE_SIZE 0x000a00 +#define FAIL_PARAMETERS 0x000b00 +#define FAIL_OUT_MEMORY 0x000c00 +#define FLASH_IN_PROGRESS 0x001000 + +struct controller_id { + u32 vendor; /* PCI Vendor ID */ + u32 device; /* PCI Device ID */ + u32 sub_vendor; /* PCI Subvendor ID */ + u32 sub_device; /* PCI Subdevice ID */ +}; + +struct image_info { + u32 ImageId; /* Identifies the image */ + u32 ImageOffset; /* Offset the beginning of the file */ + u32 ImageLength; /* length of the image */ + u32 ImageChecksum; /* Image checksum */ + u32 ImageVersion; /* Version of the image, could be build number */ +}; + +struct bios_file_header { + u8 signature[32]; /* Signature/Cookie to identify the file */ + u32 checksum; /*Entire file checksum with this field zero */ + u32 antidote; /* Entire file checksum with this field 0xFFFFFFFF */ + struct controller_id contrl_id; /*PCI id to identify the controller */ + u32 filelen; /*Length of the entire file*/ + u32 chunk_num; /*The chunk/part number for multiple Image files */ + u32 total_chunks; /*Total number of chunks/parts in the image file */ + u32 num_images; /* Number of images in the file */ + u32 build_num; /* Build number of this image */ + struct image_info image_header; +}; + +int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_verify); +int asd_write_flash_seg(struct asd_ha_struct *asd_ha, + void *src, u32 dest_offset, u32 bytes_to_write); +int asd_chk_write_status(struct asd_ha_struct *asd_ha, + u32 sector_addr, u8 erase_flag); +int asd_check_flash_type(struct asd_ha_struct *asd_ha); +int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, + u32 flash_addr, u32 size); +#endif diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index ee0a98bffcd4..965d4bb999d9 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -187,29 +187,13 @@ static void asd_get_response_tasklet(struct asd_ascb *ascb, ts->buf_valid_size = 0; edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; r = edb->vaddr; - if (task->task_proto == SAS_PROTO_SSP) { + if (task->task_proto == SAS_PROTOCOL_SSP) { struct ssp_response_iu *iu = r + 16 + sizeof(struct ssp_frame_hdr); ts->residual = le32_to_cpu(*(__le32 *)r); - ts->resp = SAS_TASK_COMPLETE; - if (iu->datapres == 0) - ts->stat = iu->status; - else if (iu->datapres == 1) - ts->stat = iu->resp_data[3]; - else if (iu->datapres == 2) { - ts->stat = SAM_CHECK_COND; - ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE, - be32_to_cpu(iu->sense_data_len)); - memcpy(ts->buf, iu->sense_data, ts->buf_valid_size); - if (iu->status != SAM_CHECK_COND) { - ASD_DPRINTK("device %llx sent sense data, but " - "stat(0x%x) is not CHECK_CONDITION" - "\n", - SAS_ADDR(task->dev->sas_addr), - iu->status); - } - } + + sas_ssp_task_response(&asd_ha->pcidev->dev, task, iu); } else { struct ata_task_resp *resp = (void *) &ts->buf[0]; @@ -341,14 +325,14 @@ Again: } switch (task->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: asd_unbuild_ata_ascb(ascb); break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: asd_unbuild_smp_ascb(ascb); break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: asd_unbuild_ssp_ascb(ascb); default: break; @@ -586,17 +570,17 @@ int asd_execute_task(struct sas_task *task, const int num, list_for_each_entry(a, &alist, list) { t = a->uldd_task; a->uldd_timer = 1; - if (t->task_proto & SAS_PROTO_STP) - t->task_proto = SAS_PROTO_STP; + if (t->task_proto & SAS_PROTOCOL_STP) + t->task_proto = SAS_PROTOCOL_STP; switch (t->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: res = asd_build_ata_ascb(a, t, gfp_flags); break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: res = asd_build_smp_ascb(a, t, gfp_flags); break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: res = asd_build_ssp_ascb(a, t, gfp_flags); break; default: @@ -633,14 +617,14 @@ out_err_unmap: t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; spin_unlock_irqrestore(&t->task_state_lock, flags); switch (t->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: asd_unbuild_ata_ascb(a); break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: asd_unbuild_smp_ascb(a); break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: asd_unbuild_ssp_ascb(a); default: break; diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index c0d0b7d7a8ce..87b2f6e6adfe 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -372,21 +372,21 @@ int asd_abort_task(struct sas_task *task) scb->header.opcode = ABORT_TASK; switch (task->task_proto) { - case SATA_PROTO: - case SAS_PROTO_STP: + case SAS_PROTOCOL_SATA: + case SAS_PROTOCOL_STP: scb->abort_task.proto_conn_rate = (1 << 5); /* STP */ break; - case SAS_PROTO_SSP: + case SAS_PROTOCOL_SSP: scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */ scb->abort_task.proto_conn_rate |= task->dev->linkrate; break; - case SAS_PROTO_SMP: + case SAS_PROTOCOL_SMP: break; default: break; } - if (task->task_proto == SAS_PROTO_SSP) { + if (task->task_proto == SAS_PROTOCOL_SSP) { scb->abort_task.ssp_frame.frame_type = SSP_TASK; memcpy(scb->abort_task.ssp_frame.hashed_dest_addr, task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); @@ -512,7 +512,7 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, int res = 1; struct scb *scb; - if (!(dev->tproto & SAS_PROTO_SSP)) + if (!(dev->tproto & SAS_PROTOCOL_SSP)) return TMF_RESP_FUNC_ESUPP; ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index d466a2dac1db..f4a202e8df26 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -122,7 +122,6 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .max_sectors = ARCMSR_MAX_XFER_SECTORS, .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = arcmsr_host_attrs, }; #ifdef CONFIG_SCSI_ARCMSR_AER @@ -634,9 +633,9 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) pcmd->result = DID_OK << 16; if (sensebuffer) { int sense_data_length = - sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer) - ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer); - memset(sensebuffer, 0, sizeof(pcmd->sense_buffer)); + sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE + ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE; + memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE); memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; sensebuffer->Valid = 1; diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index a9680b5e8ac6..93b61f148653 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -511,9 +511,9 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd) * various queues are valid. */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; /* ++roman: Try to merge some scatter-buffers if they are at @@ -523,8 +523,8 @@ static inline void initialize_SCp(Scsi_Cmnd *cmd) } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *)cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } } @@ -936,21 +936,21 @@ static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) } # endif # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingr++; break; } @@ -1352,21 +1352,21 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id) static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd) { # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { case WRITE: case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingr--; break; } @@ -1868,7 +1868,7 @@ static int do_abort(struct Scsi_Host *host) * the target sees, so we just handshake. */ - while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ) + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)) ; NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index fec58cc47f1c..db6de5e6afb3 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -471,18 +471,8 @@ go_42: /* * Complete the command */ - if (workreq->use_sg) { - pci_unmap_sg(dev->pdev, - (struct scatterlist *)workreq->request_buffer, - workreq->use_sg, - workreq->sc_data_direction); - } else if (workreq->request_bufflen && - workreq->sc_data_direction != DMA_NONE) { - pci_unmap_single(dev->pdev, - workreq->SCp.dma_handle, - workreq->request_bufflen, - workreq->sc_data_direction); - } + scsi_dma_unmap(workreq); + spin_lock_irqsave(dev->host->host_lock, flags); (*workreq->scsi_done) (workreq); #ifdef ED_DBGP @@ -624,7 +614,7 @@ static int atp870u_queuecommand(struct scsi_cmnd * req_p, c = scmd_channel(req_p); req_p->sense_buffer[0]=0; - req_p->resid = 0; + scsi_set_resid(req_p, 0); if (scmd_channel(req_p) > 1) { req_p->result = 0x00040000; done(req_p); @@ -722,7 +712,6 @@ static void send_s870(struct atp_unit *dev,unsigned char c) unsigned short int tmpcip, w; unsigned long l, bttl = 0; unsigned int workport; - struct scatterlist *sgpnt; unsigned long sg_count; if (dev->in_snd[c] != 0) { @@ -793,6 +782,8 @@ oktosend: } printk("\n"); #endif + l = scsi_bufflen(workreq); + if (dev->dev_id == ATP885_DEVID) { j = inb(dev->baseport + 0x29) & 0xfe; outb(j, dev->baseport + 0x29); @@ -800,12 +791,11 @@ oktosend: } if (workreq->cmnd[0] == READ_CAPACITY) { - if (workreq->request_bufflen > 8) { - workreq->request_bufflen = 0x08; - } + if (l > 8) + l = 8; } if (workreq->cmnd[0] == 0x00) { - workreq->request_bufflen = 0; + l = 0; } tmport = workport + 0x1b; @@ -852,40 +842,8 @@ oktosend: #ifdef ED_DBGP printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp); #endif - /* - * Figure out the transfer size - */ - if (workreq->use_sg) { -#ifdef ED_DBGP - printk("Using SGL\n"); -#endif - l = 0; - - sgpnt = (struct scatterlist *) workreq->request_buffer; - sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg, - workreq->sc_data_direction); - - for (i = 0; i < workreq->use_sg; i++) { - if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) { - panic("Foooooooood fight!"); - } - l += sgpnt[i].length; - } -#ifdef ED_DBGP - printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l); -#endif - } else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) { -#ifdef ED_DBGP - printk("Not using SGL\n"); -#endif - workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer, - workreq->request_bufflen, - workreq->sc_data_direction); - l = workreq->request_bufflen; -#ifdef ED_DBGP - printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l); -#endif - } else l = 0; + + sg_count = scsi_dma_map(workreq); /* * Write transfer size */ @@ -938,16 +896,16 @@ oktosend: * a linear chain. */ - if (workreq->use_sg) { - sgpnt = (struct scatterlist *) workreq->request_buffer; + if (l) { + struct scatterlist *sgpnt; i = 0; - for (j = 0; j < workreq->use_sg; j++) { - bttl = sg_dma_address(&sgpnt[j]); - l=sg_dma_len(&sgpnt[j]); + scsi_for_each_sg(workreq, sgpnt, sg_count, j) { + bttl = sg_dma_address(sgpnt); + l=sg_dma_len(sgpnt); #ifdef ED_DBGP - printk("1. bttl %x, l %x\n",bttl, l); + printk("1. bttl %x, l %x\n",bttl, l); #endif - while (l > 0x10000) { + while (l > 0x10000) { (((u16 *) (prd))[i + 3]) = 0x0000; (((u16 *) (prd))[i + 2]) = 0x0000; (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); @@ -965,32 +923,6 @@ oktosend: printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); printk("2. bttl %x, l %x\n",bttl, l); #endif - } else { - /* - * For a linear request write a chain of blocks - */ - bttl = workreq->SCp.dma_handle; - l = workreq->request_bufflen; - i = 0; -#ifdef ED_DBGP - printk("3. bttl %x, l %x\n",bttl, l); -#endif - while (l > 0x10000) { - (((u16 *) (prd))[i + 3]) = 0x0000; - (((u16 *) (prd))[i + 2]) = 0x0000; - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); - l -= 0x10000; - bttl += 0x10000; - i += 0x04; - } - (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000); - (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); -#ifdef ED_DBGP - printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); - printk("4. bttl %x, l %x\n",bttl, l); -#endif - } tmpcip += 4; #ifdef ED_DBGP diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 2311019304c0..7aad15436d24 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -21,6 +21,7 @@ #include <linux/compat.h> #include <linux/chio.h> /* here are all the ioctls */ #include <linux/mutex.h> +#include <linux/idr.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -33,6 +34,7 @@ #define CH_DT_MAX 16 #define CH_TYPES 8 +#define CH_MAX_DEVS 128 MODULE_DESCRIPTION("device driver for scsi media changer devices"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>"); @@ -88,17 +90,6 @@ static const char * vendor_labels[CH_TYPES-4] = { #define MAX_RETRIES 1 -static int ch_probe(struct device *); -static int ch_remove(struct device *); -static int ch_open(struct inode * inode, struct file * filp); -static int ch_release(struct inode * inode, struct file * filp); -static int ch_ioctl(struct inode * inode, struct file * filp, - unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -static long ch_ioctl_compat(struct file * filp, - unsigned int cmd, unsigned long arg); -#endif - static struct class * ch_sysfs_class; typedef struct { @@ -114,30 +105,8 @@ typedef struct { struct mutex lock; } scsi_changer; -static LIST_HEAD(ch_devlist); -static DEFINE_SPINLOCK(ch_devlist_lock); -static int ch_devcount; - -static struct scsi_driver ch_template = -{ - .owner = THIS_MODULE, - .gendrv = { - .name = "ch", - .probe = ch_probe, - .remove = ch_remove, - }, -}; - -static const struct file_operations changer_fops = -{ - .owner = THIS_MODULE, - .open = ch_open, - .release = ch_release, - .ioctl = ch_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ch_ioctl_compat, -#endif -}; +static DEFINE_IDR(ch_index_idr); +static DEFINE_SPINLOCK(ch_index_lock); static const struct { unsigned char sense; @@ -207,7 +176,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, { int errno, retries = 0, timeout, result; struct scsi_sense_hdr sshdr; - + timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) ? timeout_init : timeout_move; @@ -245,7 +214,7 @@ static int ch_elem_to_typecode(scsi_changer *ch, u_int elem) { int i; - + for (i = 0; i < CH_TYPES; i++) { if (elem >= ch->firsts[i] && elem < ch->firsts[i] + @@ -261,15 +230,15 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) u_char cmd[12]; u_char *buffer; int result; - + buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if(!buffer) return -ENOMEM; - + retry: memset(cmd,0,sizeof(cmd)); cmd[0] = READ_ELEMENT_STATUS; - cmd[1] = (ch->device->lun << 5) | + cmd[1] = (ch->device->lun << 5) | (ch->voltags ? 0x10 : 0) | ch_elem_to_typecode(ch,elem); cmd[2] = (elem >> 8) & 0xff; @@ -296,7 +265,7 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data) return result; } -static int +static int ch_init_elem(scsi_changer *ch) { int err; @@ -322,7 +291,7 @@ ch_readconfig(scsi_changer *ch) buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - + memset(cmd,0,sizeof(cmd)); cmd[0] = MODE_SENSE; cmd[1] = ch->device->lun << 5; @@ -365,7 +334,7 @@ ch_readconfig(scsi_changer *ch) } else { vprintk("reading element address assigment page failed!\n"); } - + /* vendor specific element types */ for (i = 0; i < 4; i++) { if (0 == vendor_counts[i]) @@ -443,7 +412,7 @@ static int ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) { u_char cmd[10]; - + dprintk("position: 0x%x\n",elem); if (0 == trans) trans = ch->firsts[CHET_MT]; @@ -462,7 +431,7 @@ static int ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) { u_char cmd[12]; - + dprintk("move: 0x%x => 0x%x\n",src,dest); if (0 == trans) trans = ch->firsts[CHET_MT]; @@ -484,7 +453,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src, u_int dest1, u_int dest2, int rotate1, int rotate2) { u_char cmd[12]; - + dprintk("exchange: 0x%x => 0x%x => 0x%x\n", src,dest1,dest2); if (0 == trans) @@ -501,7 +470,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src, cmd[8] = (dest2 >> 8) & 0xff; cmd[9] = dest2 & 0xff; cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0); - + return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE); } @@ -539,14 +508,14 @@ ch_set_voltag(scsi_changer *ch, u_int elem, elem, tag); memset(cmd,0,sizeof(cmd)); cmd[0] = SEND_VOLUME_TAG; - cmd[1] = (ch->device->lun << 5) | + cmd[1] = (ch->device->lun << 5) | ch_elem_to_typecode(ch,elem); cmd[2] = (elem >> 8) & 0xff; cmd[3] = elem & 0xff; cmd[5] = clear ? (alternate ? 0x0d : 0x0c) : (alternate ? 0x0b : 0x0a); - + cmd[9] = 255; memcpy(buffer,tag,32); @@ -562,7 +531,7 @@ static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) int retval = 0; u_char data[16]; unsigned int i; - + mutex_lock(&ch->lock); for (i = 0; i < ch->counts[type]; i++) { if (0 != ch_read_element_status @@ -599,20 +568,17 @@ ch_release(struct inode *inode, struct file *file) static int ch_open(struct inode *inode, struct file *file) { - scsi_changer *tmp, *ch; + scsi_changer *ch; int minor = iminor(inode); - spin_lock(&ch_devlist_lock); - ch = NULL; - list_for_each_entry(tmp,&ch_devlist,list) { - if (tmp->minor == minor) - ch = tmp; - } + spin_lock(&ch_index_lock); + ch = idr_find(&ch_index_idr, minor); + if (NULL == ch || scsi_device_get(ch->device)) { - spin_unlock(&ch_devlist_lock); + spin_unlock(&ch_index_lock); return -ENXIO; } - spin_unlock(&ch_devlist_lock); + spin_unlock(&ch_index_lock); file->private_data = ch; return 0; @@ -626,24 +592,24 @@ ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit) return 0; } -static int ch_ioctl(struct inode * inode, struct file * file, +static long ch_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { scsi_changer *ch = file->private_data; int retval; void __user *argp = (void __user *)arg; - + switch (cmd) { case CHIOGPARAMS: { struct changer_params params; - + params.cp_curpicker = 0; params.cp_npickers = ch->counts[CHET_MT]; params.cp_nslots = ch->counts[CHET_ST]; params.cp_nportals = ch->counts[CHET_IE]; params.cp_ndrives = ch->counts[CHET_DT]; - + if (copy_to_user(argp, ¶ms, sizeof(params))) return -EFAULT; return 0; @@ -673,11 +639,11 @@ static int ch_ioctl(struct inode * inode, struct file * file, return -EFAULT; return 0; } - + case CHIOPOSITION: { struct changer_position pos; - + if (copy_from_user(&pos, argp, sizeof (pos))) return -EFAULT; @@ -692,7 +658,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, mutex_unlock(&ch->lock); return retval; } - + case CHIOMOVE: { struct changer_move mv; @@ -705,7 +671,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, dprintk("CHIOMOVE: invalid parameter\n"); return -EBADSLT; } - + mutex_lock(&ch->lock); retval = ch_move(ch,0, ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, @@ -718,7 +684,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, case CHIOEXCHANGE: { struct changer_exchange mv; - + if (copy_from_user(&mv, argp, sizeof (mv))) return -EFAULT; @@ -728,7 +694,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, dprintk("CHIOEXCHANGE: invalid parameter\n"); return -EBADSLT; } - + mutex_lock(&ch->lock); retval = ch_exchange (ch,0, @@ -743,7 +709,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, case CHIOGSTATUS: { struct changer_element_status ces; - + if (copy_from_user(&ces, argp, sizeof (ces))) return -EFAULT; if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) @@ -759,19 +725,19 @@ static int ch_ioctl(struct inode * inode, struct file * file, u_char *buffer; unsigned int elem; int result,i; - + if (copy_from_user(&cge, argp, sizeof (cge))) return -EFAULT; if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) return -EINVAL; elem = ch->firsts[cge.cge_type] + cge.cge_unit; - + buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; mutex_lock(&ch->lock); - + voltag_retry: memset(cmd,0,sizeof(cmd)); cmd[0] = READ_ELEMENT_STATUS; @@ -782,7 +748,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, cmd[3] = elem & 0xff; cmd[5] = 1; cmd[9] = 255; - + if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) { cge.cge_status = buffer[18]; cge.cge_flags = 0; @@ -822,7 +788,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, } kfree(buffer); mutex_unlock(&ch->lock); - + if (copy_to_user(argp, &cge, sizeof (cge))) return -EFAULT; return result; @@ -835,7 +801,7 @@ static int ch_ioctl(struct inode * inode, struct file * file, mutex_unlock(&ch->lock); return retval; } - + case CHIOSVOLTAG: { struct changer_set_voltag csv; @@ -876,7 +842,7 @@ static long ch_ioctl_compat(struct file * file, unsigned int cmd, unsigned long arg) { scsi_changer *ch = file->private_data; - + switch (cmd) { case CHIOGPARAMS: case CHIOGVPARAMS: @@ -887,13 +853,12 @@ static long ch_ioctl_compat(struct file * file, case CHIOINITELEM: case CHIOSVOLTAG: /* compatible */ - return ch_ioctl(NULL /* inode, unused */, - file, cmd, arg); + return ch_ioctl(file, cmd, arg); case CHIOGSTATUS32: { struct changer_element_status32 ces32; unsigned char __user *data; - + if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) return -EFAULT; if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) @@ -915,63 +880,100 @@ static long ch_ioctl_compat(struct file * file, static int ch_probe(struct device *dev) { struct scsi_device *sd = to_scsi_device(dev); + struct class_device *class_dev; + int minor, ret = -ENOMEM; scsi_changer *ch; - + if (sd->type != TYPE_MEDIUM_CHANGER) return -ENODEV; - + ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (NULL == ch) return -ENOMEM; - ch->minor = ch_devcount; + if (!idr_pre_get(&ch_index_idr, GFP_KERNEL)) + goto free_ch; + + spin_lock(&ch_index_lock); + ret = idr_get_new(&ch_index_idr, ch, &minor); + spin_unlock(&ch_index_lock); + + if (ret) + goto free_ch; + + if (minor > CH_MAX_DEVS) { + ret = -ENODEV; + goto remove_idr; + } + + ch->minor = minor; sprintf(ch->name,"ch%d",ch->minor); + + class_dev = class_device_create(ch_sysfs_class, NULL, + MKDEV(SCSI_CHANGER_MAJOR, ch->minor), + dev, "s%s", ch->name); + if (IS_ERR(class_dev)) { + printk(KERN_WARNING "ch%d: class_device_create failed\n", + ch->minor); + ret = PTR_ERR(class_dev); + goto remove_idr; + } + mutex_init(&ch->lock); ch->device = sd; ch_readconfig(ch); if (init) ch_init_elem(ch); - class_device_create(ch_sysfs_class, NULL, - MKDEV(SCSI_CHANGER_MAJOR,ch->minor), - dev, "s%s", ch->name); - + dev_set_drvdata(dev, ch); sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); - - spin_lock(&ch_devlist_lock); - list_add_tail(&ch->list,&ch_devlist); - ch_devcount++; - spin_unlock(&ch_devlist_lock); + return 0; +remove_idr: + idr_remove(&ch_index_idr, minor); +free_ch: + kfree(ch); + return ret; } static int ch_remove(struct device *dev) { - struct scsi_device *sd = to_scsi_device(dev); - scsi_changer *tmp, *ch; + scsi_changer *ch = dev_get_drvdata(dev); - spin_lock(&ch_devlist_lock); - ch = NULL; - list_for_each_entry(tmp,&ch_devlist,list) { - if (tmp->device == sd) - ch = tmp; - } - BUG_ON(NULL == ch); - list_del(&ch->list); - spin_unlock(&ch_devlist_lock); + spin_lock(&ch_index_lock); + idr_remove(&ch_index_idr, ch->minor); + spin_unlock(&ch_index_lock); class_device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); kfree(ch->dt); kfree(ch); - ch_devcount--; return 0; } +static struct scsi_driver ch_template = { + .owner = THIS_MODULE, + .gendrv = { + .name = "ch", + .probe = ch_probe, + .remove = ch_remove, + }, +}; + +static const struct file_operations changer_fops = { + .owner = THIS_MODULE, + .open = ch_open, + .release = ch_release, + .unlocked_ioctl = ch_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ch_ioctl_compat, +#endif +}; + static int __init init_ch_module(void) { int rc; - + printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); if (IS_ERR(ch_sysfs_class)) { @@ -996,11 +998,12 @@ static int __init init_ch_module(void) return rc; } -static void __exit exit_ch_module(void) +static void __exit exit_ch_module(void) { scsi_unregister_driver(&ch_template.gendrv); unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); class_destroy(ch_sysfs_class); + idr_destroy(&ch_index_idr); } module_init(init_ch_module); diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 024553f9c247..403a7f2d8f9b 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -362,7 +362,6 @@ void scsi_print_command(struct scsi_cmnd *cmd) EXPORT_SYMBOL(scsi_print_command); /** - * * scsi_print_status - print scsi status description * @scsi_status: scsi status value * @@ -1369,7 +1368,7 @@ EXPORT_SYMBOL(scsi_print_sense); static const char * const hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE"}; #define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) static const char * const driverbyte_table[]={ diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index a9def6e1d30e..22ef3716e786 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1629,8 +1629,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - sizeof(srb->cmd->sense_buffer)); + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); } else { ptr = (u8 *)srb->cmd->cmnd; @@ -1915,8 +1914,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - sizeof(srb->cmd->sense_buffer)); + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); } srb->state |= SRB_COMMAND; @@ -3685,7 +3683,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, srb->target_status = 0; /* KG: Can this prevent crap sense data ? */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); /* Save some data */ srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address = @@ -3694,15 +3692,15 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, srb->segment_x[0].length; srb->xferred = srb->total_xfer_length; /* srb->segment_x : a one entry of S/G list table */ - srb->total_xfer_length = sizeof(cmd->sense_buffer); - srb->segment_x[0].length = sizeof(cmd->sense_buffer); + srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE; + srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE; /* Map sense buffer */ srb->segment_x[0].address = pci_map_single(acb->dev, cmd->sense_buffer, - sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE); + SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", cmd->sense_buffer, srb->segment_x[0].address, - sizeof(cmd->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); srb->sg_count = 1; srb->sg_index = 0; @@ -4765,7 +4763,6 @@ static struct scsi_host_template dc395x_driver_template = { .eh_bus_reset_handler = dc395x_eh_bus_reset, .unchecked_isa_dma = 0, .use_clustering = DISABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index b31d1c95c9fb..c9dd8392aab2 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -2296,9 +2296,8 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd) // copy over the request sense data if it was a check // condition status - if(dev_status == 0x02 /*CHECK_CONDITION*/) { - u32 len = sizeof(cmd->sense_buffer); - len = (len > 40) ? 40 : len; + if (dev_status == SAM_STAT_CHECK_CONDITION) { + u32 len = min(SCSI_SENSE_BUFFERSIZE, 40); // Copy over the sense data memcpy_fromio(cmd->sense_buffer, (reply+28) , len); if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && @@ -3341,7 +3340,6 @@ static struct scsi_host_template driver_template = { .this_id = 7, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index 7ead5210de96..8be3d76656fa 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -524,7 +524,6 @@ static struct scsi_host_template driver_template = { .this_id = 7, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) @@ -1623,9 +1622,9 @@ static void map_dma(unsigned int i, struct hostdata *ha) if (SCpnt->sense_buffer) cpp->sense_addr = H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer, - sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); - cpp->sense_len = sizeof SCpnt->sense_buffer; + cpp->sense_len = SCSI_SENSE_BUFFERSIZE; count = scsi_dma_map(SCpnt); BUG_ON(count < 0); diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index 982c5092be11..b5a60926e556 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -369,7 +369,6 @@ static int eata_pio_queue(struct scsi_cmnd *cmd, cp = &hd->ccb[y]; memset(cp, 0, sizeof(struct eata_ccb)); - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); cp->status = USED; /* claim free slot */ @@ -385,7 +384,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd, cp->DataIn = 0; /* Input mode */ cp->Interpret = (cmd->device->id == hd->hostid); - cp->cp_datalen = cpu_to_be32(cmd->request_bufflen); + cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd)); cp->Auto_Req_Sen = 0; cp->cp_reqDMA = 0; cp->reqlen = 0; @@ -402,14 +401,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd, cp->cmd = cmd; cmd->host_scribble = (char *) &hd->ccb[y]; - if (cmd->use_sg == 0) { + if (!scsi_bufflen(cmd)) { cmd->SCp.buffers_residual = 1; - cmd->SCp.ptr = cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; cmd->SCp.buffer = NULL; } else { - cmd->SCp.buffer = cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg; + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd); cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index 8335b608e571..85bd54c77b50 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -1017,24 +1017,6 @@ static irqreturn_t fd_mcs_intr(int irq, void *dev_id) printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in); #endif -#if ERRORS_ONLY - if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) { - if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) { - unsigned char key; - unsigned char code; - unsigned char qualifier; - - key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f; - code = (unsigned char) (*((char *) current_SC->request_buffer + 12)); - qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13)); - - if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) - && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code))) - - printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier); - } - } -#endif #if EVERY_ACCESS printk("BEFORE MY_DONE. . ."); #endif @@ -1097,7 +1079,9 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n"); } #if EVERY_ACCESS - printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen); + printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->target, *(unsigned char *) SCpnt->cmnd, + scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); #endif fd_mcs_make_bus_idle(shpnt); @@ -1107,14 +1091,14 @@ static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) /* Initialize static data */ - if (current_SC->use_sg) { - current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer; + if (scsi_bufflen(current_SC)) { + current_SC->SCp.buffer = scsi_sglist(current_SC); current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - current_SC->SCp.buffers_residual = current_SC->use_sg - 1; + current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; } else { - current_SC->SCp.ptr = (char *) current_SC->request_buffer; - current_SC->SCp.this_residual = current_SC->request_bufflen; + current_SC->SCp.ptr = NULL; + current_SC->SCp.this_residual = 0; current_SC->SCp.buffer = NULL; current_SC->SCp.buffers_residual = 0; } @@ -1166,7 +1150,9 @@ static void fd_mcs_print_info(Scsi_Cmnd * SCpnt) break; } - printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen); + printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, + scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout); #if DEBUG_RACE printk("in_interrupt_flag = %d\n", in_interrupt_flag); diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index b253b8c718d3..c82523908c2e 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -141,7 +141,7 @@ static void gdth_delay(int milliseconds); static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs); static irqreturn_t gdth_interrupt(int irq, void *dev_id); -static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, +static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int gdth_from_wait, int* pIndex); static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, Scsi_Cmnd *scp); @@ -165,7 +165,6 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive); static void gdth_enable_int(gdth_ha_str *ha); -static unchar gdth_get_status(gdth_ha_str *ha, int irq); static int gdth_test_busy(gdth_ha_str *ha); static int gdth_get_cmd_index(gdth_ha_str *ha); static void gdth_release_event(gdth_ha_str *ha); @@ -1334,14 +1333,12 @@ static void __init gdth_enable_int(gdth_ha_str *ha) } /* return IStatus if interrupt was from this card else 0 */ -static unchar gdth_get_status(gdth_ha_str *ha, int irq) +static unchar gdth_get_status(gdth_ha_str *ha) { unchar IStatus = 0; - TRACE(("gdth_get_status() irq %d ctr_count %d\n", irq, gdth_ctr_count)); + TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count)); - if (ha->irq != (unchar)irq) /* check IRQ */ - return false; if (ha->type == GDT_EISA) IStatus = inb((ushort)ha->bmic + EDOORREG); else if (ha->type == GDT_ISA) @@ -1523,7 +1520,7 @@ static int gdth_wait(gdth_ha_str *ha, int index, ulong32 time) return 1; /* no wait required */ do { - __gdth_interrupt(ha, (int)ha->irq, true, &wait_index); + __gdth_interrupt(ha, true, &wait_index); if (wait_index == index) { answer_found = TRUE; break; @@ -3036,7 +3033,7 @@ static void gdth_clear_events(void) /* SCSI interface functions */ -static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, +static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int gdth_from_wait, int* pIndex) { gdt6m_dpram_str __iomem *dp6m_ptr = NULL; @@ -3054,7 +3051,7 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, int act_int_coal = 0; #endif - TRACE(("gdth_interrupt() IRQ %d\n",irq)); + TRACE(("gdth_interrupt() IRQ %d\n", ha->irq)); /* if polling and not from gdth_wait() -> return */ if (gdth_polling) { @@ -3067,7 +3064,8 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, spin_lock_irqsave(&ha->smp_lock, flags); /* search controller */ - if (0 == (IStatus = gdth_get_status(ha, irq))) { + IStatus = gdth_get_status(ha); + if (IStatus == 0) { /* spurious interrupt */ if (!gdth_polling) spin_unlock_irqrestore(&ha->smp_lock, flags); @@ -3294,9 +3292,9 @@ static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, int irq, static irqreturn_t gdth_interrupt(int irq, void *dev_id) { - gdth_ha_str *ha = (gdth_ha_str *)dev_id; + gdth_ha_str *ha = dev_id; - return __gdth_interrupt(ha, irq, false, NULL); + return __gdth_interrupt(ha, false, NULL); } static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 24271a871b8c..880c78bff0e1 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -54,8 +54,7 @@ static struct class shost_class = { }; /** - * scsi_host_set_state - Take the given host through the host - * state model. + * scsi_host_set_state - Take the given host through the host state model. * @shost: scsi host to change the state of. * @state: state to change to. * @@ -343,7 +342,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; shost->active_mode = sht->supported_mode; - shost->use_sg_chaining = sht->use_sg_chaining; if (sht->supported_mode == MODE_UNKNOWN) /* means we didn't set it ... default to INITIATOR */ @@ -429,9 +427,17 @@ void scsi_unregister(struct Scsi_Host *shost) } EXPORT_SYMBOL(scsi_unregister); +static int __scsi_host_match(struct class_device *cdev, void *data) +{ + struct Scsi_Host *p; + unsigned short *hostnum = (unsigned short *)data; + + p = class_to_shost(cdev); + return p->host_no == *hostnum; +} + /** * scsi_host_lookup - get a reference to a Scsi_Host by host no - * * @hostnum: host number to locate * * Return value: @@ -439,19 +445,12 @@ EXPORT_SYMBOL(scsi_unregister); **/ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) { - struct class *class = &shost_class; struct class_device *cdev; - struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p; + struct Scsi_Host *shost = ERR_PTR(-ENXIO); - down(&class->sem); - list_for_each_entry(cdev, &class->children, node) { - p = class_to_shost(cdev); - if (p->host_no == hostnum) { - shost = scsi_host_get(p); - break; - } - } - up(&class->sem); + cdev = class_find_child(&shost_class, &hostnum, __scsi_host_match); + if (cdev) + shost = scsi_host_get(class_to_shost(cdev)); return shost; } diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 0844331abb87..ff149ad6bc4e 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -1,5 +1,5 @@ /* - * HighPoint RR3xxx controller driver for Linux + * HighPoint RR3xxx/4xxx controller driver for Linux * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -38,80 +38,84 @@ #include "hptiop.h" MODULE_AUTHOR("HighPoint Technologies, Inc."); -MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx SATA Controller Driver"); +MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver"); static char driver_name[] = "hptiop"; -static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver"; -static const char driver_ver[] = "v1.2 (070830)"; - -static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag); -static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag); +static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver"; +static const char driver_ver[] = "v1.3 (071203)"; + +static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec); +static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, + struct hpt_iop_request_scsi_command *req); +static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag); +static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag); static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg); -static inline void hptiop_pci_posting_flush(struct hpt_iopmu __iomem *iop) -{ - readl(&iop->outbound_intstatus); -} - -static int iop_wait_ready(struct hpt_iopmu __iomem *iop, u32 millisec) +static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec) { u32 req = 0; int i; for (i = 0; i < millisec; i++) { - req = readl(&iop->inbound_queue); + req = readl(&hba->u.itl.iop->inbound_queue); if (req != IOPMU_QUEUE_EMPTY) break; msleep(1); } if (req != IOPMU_QUEUE_EMPTY) { - writel(req, &iop->outbound_queue); - hptiop_pci_posting_flush(iop); + writel(req, &hba->u.itl.iop->outbound_queue); + readl(&hba->u.itl.iop->outbound_intstatus); return 0; } return -1; } -static void hptiop_request_callback(struct hptiop_hba *hba, u32 tag) +static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec) +{ + return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec); +} + +static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag) { if (tag & IOPMU_QUEUE_ADDR_HOST_BIT) - return hptiop_host_request_callback(hba, + hptiop_host_request_callback_itl(hba, tag & ~IOPMU_QUEUE_ADDR_HOST_BIT); else - return hptiop_iop_request_callback(hba, tag); + hptiop_iop_request_callback_itl(hba, tag); } -static inline void hptiop_drain_outbound_queue(struct hptiop_hba *hba) +static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba) { u32 req; - while ((req = readl(&hba->iop->outbound_queue)) != IOPMU_QUEUE_EMPTY) { + while ((req = readl(&hba->u.itl.iop->outbound_queue)) != + IOPMU_QUEUE_EMPTY) { if (req & IOPMU_QUEUE_MASK_HOST_BITS) - hptiop_request_callback(hba, req); + hptiop_request_callback_itl(hba, req); else { struct hpt_iop_request_header __iomem * p; p = (struct hpt_iop_request_header __iomem *) - ((char __iomem *)hba->iop + req); + ((char __iomem *)hba->u.itl.iop + req); if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) { if (readl(&p->context)) - hptiop_request_callback(hba, req); + hptiop_request_callback_itl(hba, req); else writel(1, &p->context); } else - hptiop_request_callback(hba, req); + hptiop_request_callback_itl(hba, req); } } } -static int __iop_intr(struct hptiop_hba *hba) +static int iop_intr_itl(struct hptiop_hba *hba) { - struct hpt_iopmu __iomem *iop = hba->iop; + struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop; u32 status; int ret = 0; @@ -119,6 +123,7 @@ static int __iop_intr(struct hptiop_hba *hba) if (status & IOPMU_OUTBOUND_INT_MSG0) { u32 msg = readl(&iop->outbound_msgaddr0); + dprintk("received outbound msg %x\n", msg); writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus); hptiop_message_callback(hba, msg); @@ -126,31 +131,115 @@ static int __iop_intr(struct hptiop_hba *hba) } if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) { - hptiop_drain_outbound_queue(hba); + hptiop_drain_outbound_queue_itl(hba); + ret = 1; + } + + return ret; +} + +static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu) +{ + u32 outbound_tail = readl(&mu->outbound_tail); + u32 outbound_head = readl(&mu->outbound_head); + + if (outbound_tail != outbound_head) { + u64 p; + + memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8); + outbound_tail++; + + if (outbound_tail == MVIOP_QUEUE_LEN) + outbound_tail = 0; + writel(outbound_tail, &mu->outbound_tail); + return p; + } else + return 0; +} + +static void mv_inbound_write(u64 p, struct hptiop_hba *hba) +{ + u32 inbound_head = readl(&hba->u.mv.mu->inbound_head); + u32 head = inbound_head + 1; + + if (head == MVIOP_QUEUE_LEN) + head = 0; + + memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8); + writel(head, &hba->u.mv.mu->inbound_head); + writel(MVIOP_MU_INBOUND_INT_POSTQUEUE, + &hba->u.mv.regs->inbound_doorbell); +} + +static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag) +{ + u32 req_type = (tag >> 5) & 0x7; + struct hpt_iop_request_scsi_command *req; + + dprintk("hptiop_request_callback_mv: tag=%llx\n", tag); + + BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0); + + switch (req_type) { + case IOP_REQUEST_TYPE_GET_CONFIG: + case IOP_REQUEST_TYPE_SET_CONFIG: + hba->msg_done = 1; + break; + + case IOP_REQUEST_TYPE_SCSI_COMMAND: + req = hba->reqs[tag >> 8].req_virt; + if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT)) + req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS); + + hptiop_finish_scsi_req(hba, tag>>8, req); + break; + + default: + break; + } +} + +static int iop_intr_mv(struct hptiop_hba *hba) +{ + u32 status; + int ret = 0; + + status = readl(&hba->u.mv.regs->outbound_doorbell); + writel(~status, &hba->u.mv.regs->outbound_doorbell); + + if (status & MVIOP_MU_OUTBOUND_INT_MSG) { + u32 msg; + msg = readl(&hba->u.mv.mu->outbound_msg); + dprintk("received outbound msg %x\n", msg); + hptiop_message_callback(hba, msg); + ret = 1; + } + + if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) { + u64 tag; + + while ((tag = mv_outbound_read(hba->u.mv.mu))) + hptiop_request_callback_mv(hba, tag); ret = 1; } return ret; } -static int iop_send_sync_request(struct hptiop_hba *hba, +static int iop_send_sync_request_itl(struct hptiop_hba *hba, void __iomem *_req, u32 millisec) { struct hpt_iop_request_header __iomem *req = _req; u32 i; - writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, - &req->flags); - + writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags); writel(0, &req->context); - - writel((unsigned long)req - (unsigned long)hba->iop, - &hba->iop->inbound_queue); - - hptiop_pci_posting_flush(hba->iop); + writel((unsigned long)req - (unsigned long)hba->u.itl.iop, + &hba->u.itl.iop->inbound_queue); + readl(&hba->u.itl.iop->outbound_intstatus); for (i = 0; i < millisec; i++) { - __iop_intr(hba); + iop_intr_itl(hba); if (readl(&req->context)) return 0; msleep(1); @@ -159,19 +248,49 @@ static int iop_send_sync_request(struct hptiop_hba *hba, return -1; } -static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec) +static int iop_send_sync_request_mv(struct hptiop_hba *hba, + u32 size_bits, u32 millisec) { + struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req; u32 i; hba->msg_done = 0; + reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST); + mv_inbound_write(hba->u.mv.internal_req_phy | + MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba); + + for (i = 0; i < millisec; i++) { + iop_intr_mv(hba); + if (hba->msg_done) + return 0; + msleep(1); + } + return -1; +} + +static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg) +{ + writel(msg, &hba->u.itl.iop->inbound_msgaddr0); + readl(&hba->u.itl.iop->outbound_intstatus); +} + +static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg) +{ + writel(msg, &hba->u.mv.mu->inbound_msg); + writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell); + readl(&hba->u.mv.regs->inbound_doorbell); +} - writel(msg, &hba->iop->inbound_msgaddr0); +static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec) +{ + u32 i; - hptiop_pci_posting_flush(hba->iop); + hba->msg_done = 0; + hba->ops->post_msg(hba, msg); for (i = 0; i < millisec; i++) { spin_lock_irq(hba->host->host_lock); - __iop_intr(hba); + hba->ops->iop_intr(hba); spin_unlock_irq(hba->host->host_lock); if (hba->msg_done) break; @@ -181,46 +300,67 @@ static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec) return hba->msg_done? 0 : -1; } -static int iop_get_config(struct hptiop_hba *hba, +static int iop_get_config_itl(struct hptiop_hba *hba, struct hpt_iop_request_get_config *config) { u32 req32; struct hpt_iop_request_get_config __iomem *req; - req32 = readl(&hba->iop->inbound_queue); + req32 = readl(&hba->u.itl.iop->inbound_queue); if (req32 == IOPMU_QUEUE_EMPTY) return -1; req = (struct hpt_iop_request_get_config __iomem *) - ((unsigned long)hba->iop + req32); + ((unsigned long)hba->u.itl.iop + req32); writel(0, &req->header.flags); writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type); writel(sizeof(struct hpt_iop_request_get_config), &req->header.size); writel(IOP_RESULT_PENDING, &req->header.result); - if (iop_send_sync_request(hba, req, 20000)) { + if (iop_send_sync_request_itl(hba, req, 20000)) { dprintk("Get config send cmd failed\n"); return -1; } memcpy_fromio(config, req, sizeof(*config)); - writel(req32, &hba->iop->outbound_queue); + writel(req32, &hba->u.itl.iop->outbound_queue); + return 0; +} + +static int iop_get_config_mv(struct hptiop_hba *hba, + struct hpt_iop_request_get_config *config) +{ + struct hpt_iop_request_get_config *req = hba->u.mv.internal_req; + + req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT); + req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG); + req->header.size = + cpu_to_le32(sizeof(struct hpt_iop_request_get_config)); + req->header.result = cpu_to_le32(IOP_RESULT_PENDING); + req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_GET_CONFIG<<5); + + if (iop_send_sync_request_mv(hba, 0, 20000)) { + dprintk("Get config send cmd failed\n"); + return -1; + } + + memcpy(config, req, sizeof(struct hpt_iop_request_get_config)); return 0; } -static int iop_set_config(struct hptiop_hba *hba, +static int iop_set_config_itl(struct hptiop_hba *hba, struct hpt_iop_request_set_config *config) { u32 req32; struct hpt_iop_request_set_config __iomem *req; - req32 = readl(&hba->iop->inbound_queue); + req32 = readl(&hba->u.itl.iop->inbound_queue); if (req32 == IOPMU_QUEUE_EMPTY) return -1; req = (struct hpt_iop_request_set_config __iomem *) - ((unsigned long)hba->iop + req32); + ((unsigned long)hba->u.itl.iop + req32); memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header), (u8 *)config + sizeof(struct hpt_iop_request_header), @@ -232,22 +372,52 @@ static int iop_set_config(struct hptiop_hba *hba, writel(sizeof(struct hpt_iop_request_set_config), &req->header.size); writel(IOP_RESULT_PENDING, &req->header.result); - if (iop_send_sync_request(hba, req, 20000)) { + if (iop_send_sync_request_itl(hba, req, 20000)) { dprintk("Set config send cmd failed\n"); return -1; } - writel(req32, &hba->iop->outbound_queue); + writel(req32, &hba->u.itl.iop->outbound_queue); return 0; } -static int hptiop_initialize_iop(struct hptiop_hba *hba) +static int iop_set_config_mv(struct hptiop_hba *hba, + struct hpt_iop_request_set_config *config) { - struct hpt_iopmu __iomem *iop = hba->iop; + struct hpt_iop_request_set_config *req = hba->u.mv.internal_req; - /* enable interrupts */ + memcpy(req, config, sizeof(struct hpt_iop_request_set_config)); + req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT); + req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG); + req->header.size = + cpu_to_le32(sizeof(struct hpt_iop_request_set_config)); + req->header.result = cpu_to_le32(IOP_RESULT_PENDING); + req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_SET_CONFIG<<5); + + if (iop_send_sync_request_mv(hba, 0, 20000)) { + dprintk("Set config send cmd failed\n"); + return -1; + } + + return 0; +} + +static void hptiop_enable_intr_itl(struct hptiop_hba *hba) +{ writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0), - &iop->outbound_intmask); + &hba->u.itl.iop->outbound_intmask); +} + +static void hptiop_enable_intr_mv(struct hptiop_hba *hba) +{ + writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG, + &hba->u.mv.regs->outbound_intmask); +} + +static int hptiop_initialize_iop(struct hptiop_hba *hba) +{ + /* enable interrupts */ + hba->ops->enable_intr(hba); hba->initialized = 1; @@ -261,37 +431,74 @@ static int hptiop_initialize_iop(struct hptiop_hba *hba) return 0; } -static int hptiop_map_pci_bar(struct hptiop_hba *hba) +static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index) { u32 mem_base_phy, length; void __iomem *mem_base_virt; + struct pci_dev *pcidev = hba->pcidev; - if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) { + + if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) { printk(KERN_ERR "scsi%d: pci resource invalid\n", hba->host->host_no); - return -1; + return 0; } - mem_base_phy = pci_resource_start(pcidev, 0); - length = pci_resource_len(pcidev, 0); + mem_base_phy = pci_resource_start(pcidev, index); + length = pci_resource_len(pcidev, index); mem_base_virt = ioremap(mem_base_phy, length); if (!mem_base_virt) { printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n", hba->host->host_no); + return 0; + } + return mem_base_virt; +} + +static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba) +{ + hba->u.itl.iop = hptiop_map_pci_bar(hba, 0); + if (hba->u.itl.iop) + return 0; + else + return -1; +} + +static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba) +{ + iounmap(hba->u.itl.iop); +} + +static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba) +{ + hba->u.mv.regs = hptiop_map_pci_bar(hba, 0); + if (hba->u.mv.regs == 0) + return -1; + + hba->u.mv.mu = hptiop_map_pci_bar(hba, 2); + if (hba->u.mv.mu == 0) { + iounmap(hba->u.mv.regs); return -1; } - hba->iop = mem_base_virt; - dprintk("hptiop_map_pci_bar: iop=%p\n", hba->iop); return 0; } +static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba) +{ + iounmap(hba->u.mv.regs); + iounmap(hba->u.mv.mu); +} + static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg) { dprintk("iop message 0x%x\n", msg); + if (msg == IOPMU_INBOUND_MSG0_NOP) + hba->msg_done = 1; + if (!hba->initialized) return; @@ -303,7 +510,7 @@ static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg) hba->msg_done = 1; } -static inline struct hptiop_request *get_req(struct hptiop_hba *hba) +static struct hptiop_request *get_req(struct hptiop_hba *hba) { struct hptiop_request *ret; @@ -316,30 +523,19 @@ static inline struct hptiop_request *get_req(struct hptiop_hba *hba) return ret; } -static inline void free_req(struct hptiop_hba *hba, struct hptiop_request *req) +static void free_req(struct hptiop_hba *hba, struct hptiop_request *req) { dprintk("free_req(%d, %p)\n", req->index, req); req->next = hba->req_list; hba->req_list = req; } -static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag) +static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, + struct hpt_iop_request_scsi_command *req) { - struct hpt_iop_request_scsi_command *req; struct scsi_cmnd *scp; - u32 tag; - - if (hba->iopintf_v2) { - tag = _tag & ~ IOPMU_QUEUE_REQUEST_RESULT_BIT; - req = hba->reqs[tag].req_virt; - if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT)) - req->header.result = IOP_RESULT_SUCCESS; - } else { - tag = _tag; - req = hba->reqs[tag].req_virt; - } - dprintk("hptiop_host_request_callback: req=%p, type=%d, " + dprintk("hptiop_finish_scsi_req: req=%p, type=%d, " "result=%d, context=0x%x tag=%d\n", req, req->header.type, req->header.result, req->header.context, tag); @@ -354,6 +550,8 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag) switch (le32_to_cpu(req->header.result)) { case IOP_RESULT_SUCCESS: + scsi_set_resid(scp, + scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length)); scp->result = (DID_OK<<16); break; case IOP_RESULT_BAD_TARGET: @@ -371,12 +569,12 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag) case IOP_RESULT_INVALID_REQUEST: scp->result = (DID_ABORT<<16); break; - case IOP_RESULT_MODE_SENSE_CHECK_CONDITION: + case IOP_RESULT_CHECK_CONDITION: + scsi_set_resid(scp, + scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length)); scp->result = SAM_STAT_CHECK_CONDITION; - memset(&scp->sense_buffer, - 0, sizeof(scp->sense_buffer)); - memcpy(&scp->sense_buffer, &req->sg_list, - min(sizeof(scp->sense_buffer), + memcpy(scp->sense_buffer, &req->sg_list, + min_t(size_t, SCSI_SENSE_BUFFERSIZE, le32_to_cpu(req->dataxfer_length))); break; @@ -391,15 +589,33 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 _tag) free_req(hba, &hba->reqs[tag]); } -void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag) +static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag) +{ + struct hpt_iop_request_scsi_command *req; + u32 tag; + + if (hba->iopintf_v2) { + tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT; + req = hba->reqs[tag].req_virt; + if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT)) + req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS); + } else { + tag = _tag; + req = hba->reqs[tag].req_virt; + } + + hptiop_finish_scsi_req(hba, tag, req); +} + +void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag) { struct hpt_iop_request_header __iomem *req; struct hpt_iop_request_ioctl_command __iomem *p; struct hpt_ioctl_k *arg; req = (struct hpt_iop_request_header __iomem *) - ((unsigned long)hba->iop + tag); - dprintk("hptiop_iop_request_callback: req=%p, type=%d, " + ((unsigned long)hba->u.itl.iop + tag); + dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, " "result=%d, context=0x%x tag=%d\n", req, readl(&req->type), readl(&req->result), readl(&req->context), tag); @@ -427,7 +643,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag) arg->result = HPT_IOCTL_RESULT_FAILED; arg->done(arg); - writel(tag, &hba->iop->outbound_queue); + writel(tag, &hba->u.itl.iop->outbound_queue); } static irqreturn_t hptiop_intr(int irq, void *dev_id) @@ -437,7 +653,7 @@ static irqreturn_t hptiop_intr(int irq, void *dev_id) unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); - handled = __iop_intr(hba); + handled = hba->ops->iop_intr(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); return handled; @@ -469,6 +685,57 @@ static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg) return HPT_SCP(scp)->sgcnt; } +static void hptiop_post_req_itl(struct hptiop_hba *hba, + struct hptiop_request *_req) +{ + struct hpt_iop_request_header *reqhdr = _req->req_virt; + + reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT | + (u32)_req->index); + reqhdr->context_hi32 = 0; + + if (hba->iopintf_v2) { + u32 size, size_bits; + + size = le32_to_cpu(reqhdr->size); + if (size < 256) + size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT; + else if (size < 512) + size_bits = IOPMU_QUEUE_ADDR_HOST_BIT; + else + size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT | + IOPMU_QUEUE_ADDR_HOST_BIT; + writel(_req->req_shifted_phy | size_bits, + &hba->u.itl.iop->inbound_queue); + } else + writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT, + &hba->u.itl.iop->inbound_queue); +} + +static void hptiop_post_req_mv(struct hptiop_hba *hba, + struct hptiop_request *_req) +{ + struct hpt_iop_request_header *reqhdr = _req->req_virt; + u32 size, size_bit; + + reqhdr->context = cpu_to_le32(_req->index<<8 | + IOP_REQUEST_TYPE_SCSI_COMMAND<<5); + reqhdr->context_hi32 = 0; + size = le32_to_cpu(reqhdr->size); + + if (size <= 256) + size_bit = 0; + else if (size <= 256*2) + size_bit = 1; + else if (size <= 256*3) + size_bit = 2; + else + size_bit = 3; + + mv_inbound_write((_req->req_shifted_phy << 5) | + MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba); +} + static int hptiop_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *)) { @@ -518,9 +785,6 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp, req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT); req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND); req->header.result = cpu_to_le32(IOP_RESULT_PENDING); - req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT | - (u32)_req->index); - req->header.context_hi32 = 0; req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp)); req->channel = scp->device->channel; req->target = scp->device->id; @@ -531,21 +795,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp, + sg_count * sizeof(struct hpt_iopsg)); memcpy(req->cdb, scp->cmnd, sizeof(req->cdb)); - - if (hba->iopintf_v2) { - u32 size_bits; - if (req->header.size < 256) - size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT; - else if (req->header.size < 512) - size_bits = IOPMU_QUEUE_ADDR_HOST_BIT; - else - size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT | - IOPMU_QUEUE_ADDR_HOST_BIT; - writel(_req->req_shifted_phy | size_bits, &hba->iop->inbound_queue); - } else - writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT, - &hba->iop->inbound_queue); - + hba->ops->post_req(hba, _req); return 0; cmd_done: @@ -563,9 +813,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba) { if (atomic_xchg(&hba->resetting, 1) == 0) { atomic_inc(&hba->reset_count); - writel(IOPMU_INBOUND_MSG0_RESET, - &hba->iop->inbound_msgaddr0); - hptiop_pci_posting_flush(hba->iop); + hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET); } wait_event_timeout(hba->reset_wq, @@ -601,8 +849,10 @@ static int hptiop_reset(struct scsi_cmnd *scp) static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) { - if(queue_depth > 256) - queue_depth = 256; + struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata; + + if (queue_depth > hba->max_requests) + queue_depth = hba->max_requests; scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); return queue_depth; } @@ -656,13 +906,32 @@ static struct scsi_host_template driver_template = { .unchecked_isa_dma = 0, .emulated = 0, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .proc_name = driver_name, .shost_attrs = hptiop_attrs, .this_id = -1, .change_queue_depth = hptiop_adjust_disk_queue_depth, }; +static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba) +{ + hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev, + 0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL); + if (hba->u.mv.internal_req) + return 0; + else + return -1; +} + +static int hptiop_internal_memfree_mv(struct hptiop_hba *hba) +{ + if (hba->u.mv.internal_req) { + dma_free_coherent(&hba->pcidev->dev, 0x800, + hba->u.mv.internal_req, hba->u.mv.internal_req_phy); + return 0; + } else + return -1; +} + static int __devinit hptiop_probe(struct pci_dev *pcidev, const struct pci_device_id *id) { @@ -708,6 +977,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, hba = (struct hptiop_hba *)host->hostdata; + hba->ops = (struct hptiop_adapter_ops *)id->driver_data; hba->pcidev = pcidev; hba->host = host; hba->initialized = 0; @@ -725,16 +995,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, host->n_io_port = 0; host->irq = pcidev->irq; - if (hptiop_map_pci_bar(hba)) + if (hba->ops->map_pci_bar(hba)) goto free_scsi_host; - if (iop_wait_ready(hba->iop, 20000)) { + if (hba->ops->iop_wait_ready(hba, 20000)) { printk(KERN_ERR "scsi%d: firmware not ready\n", hba->host->host_no); goto unmap_pci_bar; } - if (iop_get_config(hba, &iop_config)) { + if (hba->ops->internal_memalloc) { + if (hba->ops->internal_memalloc(hba)) { + printk(KERN_ERR "scsi%d: internal_memalloc failed\n", + hba->host->host_no); + goto unmap_pci_bar; + } + } + + if (hba->ops->get_config(hba, &iop_config)) { printk(KERN_ERR "scsi%d: get config failed\n", hba->host->host_no); goto unmap_pci_bar; @@ -770,7 +1048,7 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, set_config.vbus_id = cpu_to_le16(host->host_no); set_config.max_host_request_size = cpu_to_le16(req_size); - if (iop_set_config(hba, &set_config)) { + if (hba->ops->set_config(hba, &set_config)) { printk(KERN_ERR "scsi%d: set config failed\n", hba->host->host_no); goto unmap_pci_bar; @@ -839,21 +1117,24 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, free_request_mem: dma_free_coherent(&hba->pcidev->dev, - hba->req_size*hba->max_requests + 0x20, + hba->req_size * hba->max_requests + 0x20, hba->dma_coherent, hba->dma_coherent_handle); free_request_irq: free_irq(hba->pcidev->irq, hba); unmap_pci_bar: - iounmap(hba->iop); + if (hba->ops->internal_memfree) + hba->ops->internal_memfree(hba); -free_pci_regions: - pci_release_regions(pcidev) ; + hba->ops->unmap_pci_bar(hba); free_scsi_host: scsi_host_put(host); +free_pci_regions: + pci_release_regions(pcidev); + disable_pci_device: pci_disable_device(pcidev); @@ -865,8 +1146,6 @@ static void hptiop_shutdown(struct pci_dev *pcidev) { struct Scsi_Host *host = pci_get_drvdata(pcidev); struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; - struct hpt_iopmu __iomem *iop = hba->iop; - u32 int_mask; dprintk("hptiop_shutdown(%p)\n", hba); @@ -876,11 +1155,24 @@ static void hptiop_shutdown(struct pci_dev *pcidev) hba->host->host_no); /* disable all outbound interrupts */ - int_mask = readl(&iop->outbound_intmask); + hba->ops->disable_intr(hba); +} + +static void hptiop_disable_intr_itl(struct hptiop_hba *hba) +{ + u32 int_mask; + + int_mask = readl(&hba->u.itl.iop->outbound_intmask); writel(int_mask | IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE, - &iop->outbound_intmask); - hptiop_pci_posting_flush(iop); + &hba->u.itl.iop->outbound_intmask); + readl(&hba->u.itl.iop->outbound_intmask); +} + +static void hptiop_disable_intr_mv(struct hptiop_hba *hba) +{ + writel(0, &hba->u.mv.regs->outbound_intmask); + readl(&hba->u.mv.regs->outbound_intmask); } static void hptiop_remove(struct pci_dev *pcidev) @@ -901,7 +1193,10 @@ static void hptiop_remove(struct pci_dev *pcidev) hba->dma_coherent, hba->dma_coherent_handle); - iounmap(hba->iop); + if (hba->ops->internal_memfree) + hba->ops->internal_memfree(hba); + + hba->ops->unmap_pci_bar(hba); pci_release_regions(hba->pcidev); pci_set_drvdata(hba->pcidev, NULL); @@ -910,11 +1205,50 @@ static void hptiop_remove(struct pci_dev *pcidev) scsi_host_put(host); } +static struct hptiop_adapter_ops hptiop_itl_ops = { + .iop_wait_ready = iop_wait_ready_itl, + .internal_memalloc = 0, + .internal_memfree = 0, + .map_pci_bar = hptiop_map_pci_bar_itl, + .unmap_pci_bar = hptiop_unmap_pci_bar_itl, + .enable_intr = hptiop_enable_intr_itl, + .disable_intr = hptiop_disable_intr_itl, + .get_config = iop_get_config_itl, + .set_config = iop_set_config_itl, + .iop_intr = iop_intr_itl, + .post_msg = hptiop_post_msg_itl, + .post_req = hptiop_post_req_itl, +}; + +static struct hptiop_adapter_ops hptiop_mv_ops = { + .iop_wait_ready = iop_wait_ready_mv, + .internal_memalloc = hptiop_internal_memalloc_mv, + .internal_memfree = hptiop_internal_memfree_mv, + .map_pci_bar = hptiop_map_pci_bar_mv, + .unmap_pci_bar = hptiop_unmap_pci_bar_mv, + .enable_intr = hptiop_enable_intr_mv, + .disable_intr = hptiop_disable_intr_mv, + .get_config = iop_get_config_mv, + .set_config = iop_set_config_mv, + .iop_intr = iop_intr_mv, + .post_msg = hptiop_post_msg_mv, + .post_req = hptiop_post_req_mv, +}; + static struct pci_device_id hptiop_id_table[] = { - { PCI_VDEVICE(TTI, 0x3220) }, - { PCI_VDEVICE(TTI, 0x3320) }, - { PCI_VDEVICE(TTI, 0x3520) }, - { PCI_VDEVICE(TTI, 0x4320) }, + { PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops }, + { PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops }, + { 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, 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 }, {}, }; diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h index 2a5e46e001cb..a0289f219752 100644 --- a/drivers/scsi/hptiop.h +++ b/drivers/scsi/hptiop.h @@ -1,5 +1,5 @@ /* - * HighPoint RR3xxx controller driver for Linux + * HighPoint RR3xxx/4xxx controller driver for Linux * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify @@ -18,8 +18,7 @@ #ifndef _HPTIOP_H_ #define _HPTIOP_H_ -struct hpt_iopmu -{ +struct hpt_iopmu_itl { __le32 resrved0[4]; __le32 inbound_msgaddr0; __le32 inbound_msgaddr1; @@ -54,6 +53,40 @@ struct hpt_iopmu #define IOPMU_INBOUND_INT_ERROR 8 #define IOPMU_INBOUND_INT_POSTQUEUE 0x10 +#define MVIOP_QUEUE_LEN 512 + +struct hpt_iopmu_mv { + __le32 inbound_head; + __le32 inbound_tail; + __le32 outbound_head; + __le32 outbound_tail; + __le32 inbound_msg; + __le32 outbound_msg; + __le32 reserve[10]; + __le64 inbound_q[MVIOP_QUEUE_LEN]; + __le64 outbound_q[MVIOP_QUEUE_LEN]; +}; + +struct hpt_iopmv_regs { + __le32 reserved[0x20400 / 4]; + __le32 inbound_doorbell; + __le32 inbound_intmask; + __le32 outbound_doorbell; + __le32 outbound_intmask; +}; + +#define MVIOP_MU_QUEUE_ADDR_HOST_MASK (~(0x1full)) +#define MVIOP_MU_QUEUE_ADDR_HOST_BIT 4 + +#define MVIOP_MU_QUEUE_ADDR_IOP_HIGH32 0xffffffff +#define MVIOP_MU_QUEUE_REQUEST_RESULT_BIT 1 +#define MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT 2 + +#define MVIOP_MU_INBOUND_INT_MSG 1 +#define MVIOP_MU_INBOUND_INT_POSTQUEUE 2 +#define MVIOP_MU_OUTBOUND_INT_MSG 1 +#define MVIOP_MU_OUTBOUND_INT_POSTQUEUE 2 + enum hpt_iopmu_message { /* host-to-iop messages */ IOPMU_INBOUND_MSG0_NOP = 0, @@ -72,8 +105,7 @@ enum hpt_iopmu_message { IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_MAX = 0x3ff, }; -struct hpt_iop_request_header -{ +struct hpt_iop_request_header { __le32 size; __le32 type; __le32 flags; @@ -104,11 +136,10 @@ enum hpt_iop_result_type { IOP_RESULT_RESET, IOP_RESULT_INVALID_REQUEST, IOP_RESULT_BAD_TARGET, - IOP_RESULT_MODE_SENSE_CHECK_CONDITION, + IOP_RESULT_CHECK_CONDITION, }; -struct hpt_iop_request_get_config -{ +struct hpt_iop_request_get_config { struct hpt_iop_request_header header; __le32 interface_version; __le32 firmware_version; @@ -121,8 +152,7 @@ struct hpt_iop_request_get_config __le32 sdram_size; }; -struct hpt_iop_request_set_config -{ +struct hpt_iop_request_set_config { struct hpt_iop_request_header header; __le32 iop_id; __le16 vbus_id; @@ -130,15 +160,13 @@ struct hpt_iop_request_set_config __le32 reserve[6]; }; -struct hpt_iopsg -{ +struct hpt_iopsg { __le32 size; __le32 eot; /* non-zero: end of table */ __le64 pci_address; }; -struct hpt_iop_request_block_command -{ +struct hpt_iop_request_block_command { struct hpt_iop_request_header header; u8 channel; u8 target; @@ -156,8 +184,7 @@ struct hpt_iop_request_block_command #define IOP_BLOCK_COMMAND_FLUSH 4 #define IOP_BLOCK_COMMAND_SHUTDOWN 5 -struct hpt_iop_request_scsi_command -{ +struct hpt_iop_request_scsi_command { struct hpt_iop_request_header header; u8 channel; u8 target; @@ -168,8 +195,7 @@ struct hpt_iop_request_scsi_command struct hpt_iopsg sg_list[1]; }; -struct hpt_iop_request_ioctl_command -{ +struct hpt_iop_request_ioctl_command { struct hpt_iop_request_header header; __le32 ioctl_code; __le32 inbuf_size; @@ -182,11 +208,11 @@ struct hpt_iop_request_ioctl_command #define HPTIOP_MAX_REQUESTS 256u struct hptiop_request { - struct hptiop_request * next; - void * req_virt; - u32 req_shifted_phy; - struct scsi_cmnd * scp; - int index; + struct hptiop_request *next; + void *req_virt; + u32 req_shifted_phy; + struct scsi_cmnd *scp; + int index; }; struct hpt_scsi_pointer { @@ -198,9 +224,21 @@ struct hpt_scsi_pointer { #define HPT_SCP(scp) ((struct hpt_scsi_pointer *)&(scp)->SCp) struct hptiop_hba { - struct hpt_iopmu __iomem * iop; - struct Scsi_Host * host; - struct pci_dev * pcidev; + struct hptiop_adapter_ops *ops; + union { + struct { + struct hpt_iopmu_itl __iomem *iop; + } itl; + struct { + struct hpt_iopmv_regs *regs; + struct hpt_iopmu_mv __iomem *mu; + void *internal_req; + dma_addr_t internal_req_phy; + } mv; + } u; + + struct Scsi_Host *host; + struct pci_dev *pcidev; /* IOP config info */ u32 interface_version; @@ -213,15 +251,15 @@ struct hptiop_hba { u32 req_size; /* host-allocated request buffer size */ - int iopintf_v2: 1; - int initialized: 1; - int msg_done: 1; + u32 iopintf_v2: 1; + u32 initialized: 1; + u32 msg_done: 1; struct hptiop_request * req_list; struct hptiop_request reqs[HPTIOP_MAX_REQUESTS]; /* used to free allocated dma area */ - void * dma_coherent; + void *dma_coherent; dma_addr_t dma_coherent_handle; atomic_t reset_count; @@ -231,19 +269,35 @@ struct hptiop_hba { wait_queue_head_t ioctl_wq; }; -struct hpt_ioctl_k -{ +struct hpt_ioctl_k { struct hptiop_hba * hba; u32 ioctl_code; u32 inbuf_size; u32 outbuf_size; - void * inbuf; - void * outbuf; - u32 * bytes_returned; + void *inbuf; + void *outbuf; + u32 *bytes_returned; void (*done)(struct hpt_ioctl_k *); int result; /* HPT_IOCTL_RESULT_ */ }; +struct hptiop_adapter_ops { + int (*iop_wait_ready)(struct hptiop_hba *hba, u32 millisec); + int (*internal_memalloc)(struct hptiop_hba *hba); + int (*internal_memfree)(struct hptiop_hba *hba); + int (*map_pci_bar)(struct hptiop_hba *hba); + void (*unmap_pci_bar)(struct hptiop_hba *hba); + void (*enable_intr)(struct hptiop_hba *hba); + void (*disable_intr)(struct hptiop_hba *hba); + int (*get_config)(struct hptiop_hba *hba, + struct hpt_iop_request_get_config *config); + int (*set_config)(struct hptiop_hba *hba, + struct hpt_iop_request_set_config *config); + int (*iop_intr)(struct hptiop_hba *hba); + void (*post_msg)(struct hptiop_hba *hba, u32 msg); + void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req); +}; + #define HPT_IOCTL_RESULT_OK 0 #define HPT_IOCTL_RESULT_FAILED (-1) diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index db004a450732..4d15a62914e9 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -1501,7 +1501,6 @@ static struct scsi_host_template ibmmca_driver_template = { .sg_tablesize = 16, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static int ibmmca_probe(struct device *dev) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 5f2396c03958..78d46a900bb5 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -629,6 +629,16 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, list_del(&evt_struct->list); del_timer(&evt_struct->timer); + /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. + * Firmware will send a CRQ with a transport event (0xFF) to + * tell this client what has happened to the transport. This + * will be handled in ibmvscsi_handle_crq() + */ + if (rc == H_CLOSED) { + dev_warn(hostdata->dev, "send warning. " + "Receive queue closed, will retry.\n"); + goto send_busy; + } dev_err(hostdata->dev, "send error %d\n", rc); atomic_inc(&hostdata->request_limit); goto send_error; @@ -976,58 +986,74 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) int rsp_rc; unsigned long flags; u16 lun = lun_from_dev(cmd->device); + unsigned long wait_switch = 0; /* First, find this command in our sent list so we can figure * out the correct tag */ spin_lock_irqsave(hostdata->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - if (tmp_evt->cmnd == cmd) { - found_evt = tmp_evt; - break; + wait_switch = jiffies + (init_timeout * HZ); + do { + found_evt = NULL; + list_for_each_entry(tmp_evt, &hostdata->sent, list) { + if (tmp_evt->cmnd == cmd) { + found_evt = tmp_evt; + break; + } } - } - if (!found_evt) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - return SUCCESS; - } + if (!found_evt) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + return SUCCESS; + } - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n"); - return FAILED; - } + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + sdev_printk(KERN_ERR, cmd->device, + "failed to allocate abort event\n"); + return FAILED; + } - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - init_timeout); + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout); - tsk_mgmt = &evt->iu.srp.tsk_mgmt; + tsk_mgmt = &evt->iu.srp.tsk_mgmt; - /* Set up an abort SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; - tsk_mgmt->task_tag = (u64) found_evt; - - sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n", - tsk_mgmt->lun, tsk_mgmt->task_tag); - - evt->sync_srp = &srp_rsp; - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + /* Set up an abort SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->opcode = SRP_TSK_MGMT; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; + tsk_mgmt->task_tag = (u64) found_evt; + + evt->sync_srp = &srp_rsp; + + init_completion(&evt->comp); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + + if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) + break; + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + msleep(10); + spin_lock_irqsave(hostdata->host->host_lock, flags); + } while (time_before(jiffies, wait_switch)); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { sdev_printk(KERN_ERR, cmd->device, "failed to send abort() event. rc=%d\n", rsp_rc); return FAILED; } + sdev_printk(KERN_INFO, cmd->device, + "aborting command. lun 0x%lx, tag 0x%lx\n", + (((u64) lun) << 48), (u64) found_evt); + wait_for_completion(&evt->comp); /* make sure we got a good response */ @@ -1099,41 +1125,56 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) int rsp_rc; unsigned long flags; u16 lun = lun_from_dev(cmd->device); + unsigned long wait_switch = 0; spin_lock_irqsave(hostdata->host->host_lock, flags); - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n"); - return FAILED; - } + wait_switch = jiffies + (init_timeout * HZ); + do { + evt = get_event_struct(&hostdata->pool); + if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + sdev_printk(KERN_ERR, cmd->device, + "failed to allocate reset event\n"); + return FAILED; + } - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - init_timeout); + init_event_struct(evt, + sync_completion, + VIOSRP_SRP_FORMAT, + init_timeout); - tsk_mgmt = &evt->iu.srp.tsk_mgmt; + tsk_mgmt = &evt->iu.srp.tsk_mgmt; - /* Set up a lun reset SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; + /* Set up a lun reset SRP command */ + memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); + tsk_mgmt->opcode = SRP_TSK_MGMT; + tsk_mgmt->lun = ((u64) lun) << 48; + tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; - sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n", - tsk_mgmt->lun); + evt->sync_srp = &srp_rsp; + + init_completion(&evt->comp); + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); + + if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) + break; + + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + msleep(10); + spin_lock_irqsave(hostdata->host->host_lock, flags); + } while (time_before(jiffies, wait_switch)); - evt->sync_srp = &srp_rsp; - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2); spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { sdev_printk(KERN_ERR, cmd->device, "failed to send reset event. rc=%d\n", rsp_rc); return FAILED; } + sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n", + (((u64) lun) << 48)); + wait_for_completion(&evt->comp); /* make sure we got a good response */ @@ -1386,8 +1427,10 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev) unsigned long lock_flags = 0; spin_lock_irqsave(shost->host_lock, lock_flags); - if (sdev->type == TYPE_DISK) + if (sdev->type == TYPE_DISK) { sdev->allow_restart = 1; + sdev->timeout = 60 * HZ; + } scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); spin_unlock_irqrestore(shost->host_lock, lock_flags); return 0; @@ -1557,7 +1600,6 @@ static struct scsi_host_template driver_template = { .this_id = -1, .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = ibmvscsi_attrs, }; diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index 82bcab688b44..d63f11e95abf 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -292,7 +292,7 @@ static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0], cmd->usg_sg); - if (sc->use_sg) + if (scsi_sg_count(sc)) err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); spin_lock_irqsave(&target->lock, flags); diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 9706de9d98d5..db8bc20539e1 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -395,14 +395,12 @@ static int idescsi_expiry(ide_drive_t *drive) static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); - idescsi_pc_t *pc=scsi->pc; + ide_hwif_t *hwif = drive->hwif; + idescsi_pc_t *pc = scsi->pc; struct request *rq = pc->rq; - atapi_bcount_t bcount; - atapi_status_t status; - atapi_ireason_t ireason; - atapi_feature_t feature; - unsigned int temp; + u16 bcount; + u8 stat, ireason; #if IDESCSI_DEBUG_LOG printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n"); @@ -425,30 +423,29 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) (void) HWIF(drive)->ide_dma_end(drive); } - feature.all = 0; /* Clear the interrupt */ - status.all = HWIF(drive)->INB(IDE_STATUS_REG); + stat = drive->hwif->INB(IDE_STATUS_REG); - if (!status.b.drq) { + if ((stat & DRQ_STAT) == 0) { /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); local_irq_enable_in_hardirq(); - if (status.b.check) + if (stat & ERR_STAT) rq->errors++; idescsi_end_request (drive, 1, 0); return ide_stopped; } - bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); - bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); - ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); + bcount = (hwif->INB(IDE_BCOUNTH_REG) << 8) | + hwif->INB(IDE_BCOUNTL_REG); + ireason = hwif->INB(IDE_IREASON_REG); - if (ireason.b.cod) { + if (ireason & CD) { printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n"); return ide_do_reset (drive); } - if (ireason.b.io) { - temp = pc->actually_transferred + bcount.all; + if (ireason & IO) { + temp = pc->actually_transferred + bcount; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { printk(KERN_ERR "ide-scsi: The scsi wants to " @@ -461,11 +458,13 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) idescsi_input_buffers(drive, pc, temp); else drive->hwif->atapi_input_bytes(drive, pc->current_position, temp); - printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all); + printk(KERN_ERR "ide-scsi: transferred" + " %d of %d bytes\n", + temp, bcount); } pc->actually_transferred += temp; pc->current_position += temp; - idescsi_discard_data(drive, bcount.all - temp); + idescsi_discard_data(drive, bcount - temp); ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); return ide_started; } @@ -474,22 +473,24 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) #endif /* IDESCSI_DEBUG_LOG */ } } - if (ireason.b.io) { + if (ireason & IO) { clear_bit(PC_WRITING, &pc->flags); if (pc->sg) - idescsi_input_buffers(drive, pc, bcount.all); + idescsi_input_buffers(drive, pc, bcount); else - HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all); + hwif->atapi_input_bytes(drive, pc->current_position, + bcount); } else { set_bit(PC_WRITING, &pc->flags); if (pc->sg) - idescsi_output_buffers (drive, pc, bcount.all); + idescsi_output_buffers(drive, pc, bcount); else - HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all); + hwif->atapi_output_bytes(drive, pc->current_position, + bcount); } /* Update the current position */ - pc->actually_transferred += bcount.all; - pc->current_position += bcount.all; + pc->actually_transferred += bcount; + pc->current_position += bcount; /* And set the interrupt handler again */ ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry); @@ -501,16 +502,16 @@ static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; idescsi_scsi_t *scsi = drive_to_idescsi(drive); idescsi_pc_t *pc = scsi->pc; - atapi_ireason_t ireason; ide_startstop_t startstop; + u8 ireason; if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { printk(KERN_ERR "ide-scsi: Strange, packet command " "initiated yet DRQ isn't asserted\n"); return startstop; } - ireason.all = HWIF(drive)->INB(IDE_IREASON_REG); - if (!ireason.b.cod || ireason.b.io) { + ireason = hwif->INB(IDE_IREASON_REG); + if ((ireason & CD) == 0 || (ireason & IO)) { printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while " "issuing a packet command\n"); return ide_do_reset (drive); @@ -573,30 +574,26 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); ide_hwif_t *hwif = drive->hwif; - atapi_feature_t feature; - atapi_bcount_t bcount; + u16 bcount; + u8 dma = 0; scsi->pc=pc; /* Set the current packet command */ pc->actually_transferred=0; /* We haven't transferred any data yet */ pc->current_position=pc->buffer; - bcount.all = min(pc->request_transfer, 63 * 1024); /* Request to transfer the entire buffer at once */ + /* Request to transfer the entire buffer at once */ + bcount = min(pc->request_transfer, 63 * 1024); - feature.all = 0; if (drive->using_dma && !idescsi_map_sg(drive, pc)) { hwif->sg_mapped = 1; - feature.b.dma = !hwif->dma_setup(drive); + dma = !hwif->dma_setup(drive); hwif->sg_mapped = 0; } SELECT_DRIVE(drive); - if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); - HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG); - HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG); - HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); + ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK, bcount, dma); - if (feature.b.dma) + if (dma) set_bit(PC_DMA_OK, &pc->flags); if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) { @@ -922,8 +919,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd) } /* kill current request */ - blkdev_dequeue_request(req); - end_that_request_last(req, 0); + if (__blk_end_request(req, -EIO, 0)) + BUG(); if (blk_sense_request(req)) kfree(scsi->pc->buffer); kfree(scsi->pc); @@ -932,8 +929,8 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd) /* now nuke the drive queue */ while ((req = elv_next_request(drive->queue))) { - blkdev_dequeue_request(req); - end_that_request_last(req, 0); + if (__blk_end_request(req, -EIO, 0)) + BUG(); } HWGROUP(drive)->rq = NULL; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index a3d0c6b14958..f97d172844be 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -837,19 +837,16 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) /* Phase 4 - Setup scatter/gather buffers */ case 4: - if (cmd->use_sg) { - /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = - (struct scatterlist *) cmd->request_buffer; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); } else { - /* else fill the only available buffer */ cmd->SCp.buffer = NULL; - cmd->SCp.this_residual = cmd->request_bufflen; - cmd->SCp.ptr = cmd->request_buffer; + cmd->SCp.this_residual = 0; + cmd->SCp.ptr = NULL; } - cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.phase++; if (cmd->SCp.this_residual & 0x01) cmd->SCp.this_residual++; diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index c8b452f2878c..8053b1e86ccb 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -369,16 +369,16 @@ static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) * - SCp.phase records this command's SRCID_ER bit setting */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } cmd->SCp.have_data_in = 0; diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 01bf0189367d..0cc8868ea35d 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -823,7 +823,7 @@ static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_b { #if DEBUG_QUEUE - printk("append busy SCB %o; ", scbp); + printk("append busy SCB %p; ", scbp); #endif if (scbp->tagmsg) host->act_tags[scbp->target]++; @@ -2609,6 +2609,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c cblk->bufptr = cpu_to_le32((u32)dma_addr); cmnd->SCp.dma_handle = dma_addr; + cblk->sglen = nseg; cblk->flags |= SCF_SG; /* Turn on SG list flag */ total_len = 0; @@ -2832,7 +2833,6 @@ static struct scsi_host_template initio_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static int initio_probe_one(struct pci_dev *pdev, @@ -2869,6 +2869,7 @@ static int initio_probe_one(struct pci_dev *pdev, host = (struct initio_host *)shost->hostdata; memset(host, 0, sizeof(struct initio_host)); host->addr = pci_resource_start(pdev, 0); + host->bios_addr = bios_seg; if (!request_region(host->addr, 256, "i91u")) { printk(KERN_WARNING "initio: I/O port range 0x%x is busy.\n", host->addr); @@ -2895,6 +2896,8 @@ static int initio_probe_one(struct pci_dev *pdev, host->pci_dev = pdev; + host->semaph = 1; + spin_lock_init(&host->semaph_lock); host->num_scbs = num_scb; host->scb = scb; host->next_pending = scb; @@ -2911,7 +2914,7 @@ static int initio_probe_one(struct pci_dev *pdev, host->last_avail = prev; spin_lock_init(&host->avail_lock); - initio_init(host, phys_to_virt(bios_seg << 4)); + initio_init(host, phys_to_virt(((u32)bios_seg << 4))); host->jsstatus0 = 0; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0841df01bc19..73270ff892d9 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -84,7 +84,7 @@ /* * Global Data */ -static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head); +static LIST_HEAD(ipr_ioa_head); static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; static unsigned int ipr_max_speed = 1; static int ipr_testmode = 0; @@ -5142,6 +5142,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, struct ipr_ioadl_desc *last_ioadl = NULL; int len = qc->nbytes + qc->pad_len; struct scatterlist *sg; + unsigned int si; if (len == 0) return; @@ -5159,7 +5160,7 @@ static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); } - ata_for_each_sg(sg, qc) { + for_each_sg(qc->sg, sg, qc->n_elem, si) { ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); ioadl->address = cpu_to_be32(sg_dma_address(sg)); @@ -5222,12 +5223,12 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; break; - case ATA_PROT_ATAPI: - case ATA_PROT_ATAPI_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: regs->flags |= IPR_ATA_FLAG_PACKET_CMD; break; - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: regs->flags |= IPR_ATA_FLAG_PACKET_CMD; regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; break; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 5c5a9b2628fc..7505cca8e68e 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -389,17 +389,17 @@ static struct pci_device_id ips_pci_table[] = { MODULE_DEVICE_TABLE( pci, ips_pci_table ); static char ips_hot_plug_name[] = "ips"; - + static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); static void __devexit ips_remove_device(struct pci_dev *pci_dev); - + static struct pci_driver ips_pci_driver = { .name = ips_hot_plug_name, .id_table = ips_pci_table, .probe = ips_insert_device, .remove = __devexit_p(ips_remove_device), }; - + /* * Necessary forward function protoypes @@ -587,7 +587,7 @@ static void ips_setup_funclist(ips_ha_t * ha) { - /* + /* * Setup Functions */ if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) { @@ -702,12 +702,8 @@ ips_release(struct Scsi_Host *sh) /* free extra memory */ ips_free(ha); - /* Free I/O Region */ - if (ha->io_addr) - release_region(ha->io_addr, ha->io_len); - /* free IRQ */ - free_irq(ha->irq, ha); + free_irq(ha->pcidev->irq, ha); scsi_host_put(sh); @@ -1637,7 +1633,7 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr) return (IPS_FAILURE); } - if (ha->device_id == IPS_DEVICEID_COPPERHEAD && + if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && pt->CoppCP.cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW) { ret = ips_flash_copperhead(ha, pt, scb); @@ -2021,7 +2017,7 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) pt->ExtendedStatus = scb->extended_status; pt->AdapterType = ha->ad_type; - if (ha->device_id == IPS_DEVICEID_COPPERHEAD && + if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)) ips_free_flash_copperhead(ha); @@ -2075,13 +2071,13 @@ ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len) ha->mem_ptr); } - copy_info(&info, "\tIRQ number : %d\n", ha->irq); + copy_info(&info, "\tIRQ number : %d\n", ha->pcidev->irq); /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */ /* That keeps everything happy for "text" operations on the proc file. */ if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) { - if (ha->nvram->bios_low[3] == 0) { + if (ha->nvram->bios_low[3] == 0) { copy_info(&info, "\tBIOS Version : %c%c%c%c%c%c%c\n", ha->nvram->bios_high[0], ha->nvram->bios_high[1], @@ -2232,31 +2228,31 @@ ips_identify_controller(ips_ha_t * ha) { METHOD_TRACE("ips_identify_controller", 1); - switch (ha->device_id) { + switch (ha->pcidev->device) { case IPS_DEVICEID_COPPERHEAD: - if (ha->revision_id <= IPS_REVID_SERVERAID) { + if (ha->pcidev->revision <= IPS_REVID_SERVERAID) { ha->ad_type = IPS_ADTYPE_SERVERAID; - } else if (ha->revision_id == IPS_REVID_SERVERAID2) { + } else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) { ha->ad_type = IPS_ADTYPE_SERVERAID2; - } else if (ha->revision_id == IPS_REVID_NAVAJO) { + } else if (ha->pcidev->revision == IPS_REVID_NAVAJO) { ha->ad_type = IPS_ADTYPE_NAVAJO; - } else if ((ha->revision_id == IPS_REVID_SERVERAID2) + } else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2) && (ha->slot_num == 0)) { ha->ad_type = IPS_ADTYPE_KIOWA; - } else if ((ha->revision_id >= IPS_REVID_CLARINETP1) && - (ha->revision_id <= IPS_REVID_CLARINETP3)) { + } else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) && + (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) { if (ha->enq->ucMaxPhysicalDevices == 15) ha->ad_type = IPS_ADTYPE_SERVERAID3L; else ha->ad_type = IPS_ADTYPE_SERVERAID3; - } else if ((ha->revision_id >= IPS_REVID_TROMBONE32) && - (ha->revision_id <= IPS_REVID_TROMBONE64)) { + } else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) && + (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) { ha->ad_type = IPS_ADTYPE_SERVERAID4H; } break; case IPS_DEVICEID_MORPHEUS: - switch (ha->subdevice_id) { + switch (ha->pcidev->subsystem_device) { case IPS_SUBDEVICEID_4L: ha->ad_type = IPS_ADTYPE_SERVERAID4L; break; @@ -2285,7 +2281,7 @@ ips_identify_controller(ips_ha_t * ha) break; case IPS_DEVICEID_MARCO: - switch (ha->subdevice_id) { + switch (ha->pcidev->subsystem_device) { case IPS_SUBDEVICEID_6M: ha->ad_type = IPS_ADTYPE_SERVERAID6M; break; @@ -2332,20 +2328,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr) strncpy(ha->bios_version, " ?", 8); - if (ha->device_id == IPS_DEVICEID_COPPERHEAD) { + if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) { if (IPS_USE_MEMIO(ha)) { /* Memory Mapped I/O */ /* test 1st byte */ writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) return; writel(1, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) @@ -2353,20 +2349,20 @@ ips_get_bios_version(ips_ha_t * ha, int intr) /* Get Major version */ writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ major = readb(ha->mem_ptr + IPS_REG_FLDP); /* Get Minor version */ writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ minor = readb(ha->mem_ptr + IPS_REG_FLDP); /* Get SubMinor version */ writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ subminor = readb(ha->mem_ptr + IPS_REG_FLDP); @@ -2375,14 +2371,14 @@ ips_get_bios_version(ips_ha_t * ha, int intr) /* test 1st byte */ outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) return; outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) @@ -2390,21 +2386,21 @@ ips_get_bios_version(ips_ha_t * ha, int intr) /* Get Major version */ outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ major = inb(ha->io_addr + IPS_REG_FLDP); /* Get Minor version */ outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ minor = inb(ha->io_addr + IPS_REG_FLDP); /* Get SubMinor version */ outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ subminor = inb(ha->io_addr + IPS_REG_FLDP); @@ -2740,8 +2736,6 @@ ips_next(ips_ha_t * ha, int intr) SC->result = DID_OK; SC->host_scribble = NULL; - memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer)); - scb->target_id = SC->device->id; scb->lun = SC->device->lun; scb->bus = SC->device->channel; @@ -2780,10 +2774,11 @@ ips_next(ips_ha_t * ha, int intr) scb->dcdb.cmd_attribute = ips_command_direction[scb->scsi_cmd->cmnd[0]]; - /* Allow a WRITE BUFFER Command to Have no Data */ - /* This is Used by Tape Flash Utilites */ - if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) - scb->dcdb.cmd_attribute = 0; + /* Allow a WRITE BUFFER Command to Have no Data */ + /* This is Used by Tape Flash Utilites */ + if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && + (scb->data_len == 0)) + scb->dcdb.cmd_attribute = 0; if (!(scb->dcdb.cmd_attribute & 0x3)) scb->dcdb.transfer_length = 0; @@ -3404,7 +3399,7 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) /* Restrict access to physical DASD */ if (scb->scsi_cmd->cmnd[0] == INQUIRY) { - ips_scmd_buf_read(scb->scsi_cmd, + ips_scmd_buf_read(scb->scsi_cmd, &inquiryData, sizeof (inquiryData)); if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) { errcode = DID_TIME_OUT; @@ -3438,13 +3433,11 @@ ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; memcpy(scb->scsi_cmd->sense_buffer, tapeDCDB->sense_info, - sizeof (scb->scsi_cmd-> - sense_buffer)); + SCSI_SENSE_BUFFERSIZE); } else { memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info, - sizeof (scb->scsi_cmd-> - sense_buffer)); + SCSI_SENSE_BUFFERSIZE); } device_error = 2; /* check condition */ } @@ -3824,7 +3817,6 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) /* attempted, a Check Condition occurred, and Sense */ /* Data indicating an Invalid CDB OpCode is returned. */ sp = (char *) scb->scsi_cmd->sense_buffer; - memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer)); sp[0] = 0x70; /* Error Code */ sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */ @@ -4090,10 +4082,10 @@ ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) scb->scsi_cmd->result = errcode << 16; } else { /* bus == 0 */ /* restrict access to physical drives */ - if (scb->scsi_cmd->cmnd[0] == INQUIRY) { - ips_scmd_buf_read(scb->scsi_cmd, + if (scb->scsi_cmd->cmnd[0] == INQUIRY) { + ips_scmd_buf_read(scb->scsi_cmd, &inquiryData, sizeof (inquiryData)); - if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) + if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) scb->scsi_cmd->result = DID_TIME_OUT << 16; } } /* else */ @@ -4393,8 +4385,6 @@ ips_free(ips_ha_t * ha) ha->mem_ptr = NULL; } - if (ha->mem_addr) - release_mem_region(ha->mem_addr, ha->mem_len); ha->mem_addr = 0; } @@ -4661,8 +4651,8 @@ ips_isinit_morpheus(ips_ha_t * ha) uint32_t bits; METHOD_TRACE("ips_is_init_morpheus", 1); - - if (ips_isintr_morpheus(ha)) + + if (ips_isintr_morpheus(ha)) ips_flush_and_reset(ha); post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); @@ -4686,7 +4676,7 @@ ips_isinit_morpheus(ips_ha_t * ha) /* state ( was trying to INIT and an interrupt was already pending ) ... */ /* */ /****************************************************************************/ -static void +static void ips_flush_and_reset(ips_ha_t *ha) { ips_scb_t *scb; @@ -4718,9 +4708,9 @@ ips_flush_and_reset(ips_ha_t *ha) if (ret == IPS_SUCCESS) { time = 60 * IPS_ONE_SEC; /* Max Wait time is 60 seconds */ done = 0; - + while ((time > 0) && (!done)) { - done = ips_poll_for_flush_complete(ha); + done = ips_poll_for_flush_complete(ha); /* This may look evil, but it's only done during extremely rare start-up conditions ! */ udelay(1000); time--; @@ -4749,17 +4739,17 @@ static int ips_poll_for_flush_complete(ips_ha_t * ha) { IPS_STATUS cstatus; - + while (TRUE) { cstatus.value = (*ha->func.statupd) (ha); if (cstatus.value == 0xffffffff) /* If No Interrupt to process */ break; - + /* Success is when we see the Flush Command ID */ - if (cstatus.fields.command_id == IPS_MAX_CMDS ) + if (cstatus.fields.command_id == IPS_MAX_CMDS) return 1; - } + } return 0; } @@ -4903,7 +4893,7 @@ ips_init_copperhead(ips_ha_t * ha) /* Enable busmastering */ outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) /* fix for anaconda64 */ outl(0, ha->io_addr + IPS_REG_NDAE); @@ -4997,7 +4987,7 @@ ips_init_copperhead_memio(ips_ha_t * ha) /* Enable busmastering */ writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) /* fix for anaconda64 */ writel(0, ha->mem_ptr + IPS_REG_NDAE); @@ -5142,7 +5132,7 @@ ips_reset_copperhead(ips_ha_t * ha) METHOD_TRACE("ips_reset_copperhead", 1); DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", - ips_name, ha->host_num, ha->io_addr, ha->irq); + ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq); reset_counter = 0; @@ -5187,7 +5177,7 @@ ips_reset_copperhead_memio(ips_ha_t * ha) METHOD_TRACE("ips_reset_copperhead_memio", 1); DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", - ips_name, ha->host_num, ha->mem_addr, ha->irq); + ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); reset_counter = 0; @@ -5233,7 +5223,7 @@ ips_reset_morpheus(ips_ha_t * ha) METHOD_TRACE("ips_reset_morpheus", 1); DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", - ips_name, ha->host_num, ha->mem_addr, ha->irq); + ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); reset_counter = 0; @@ -5920,7 +5910,7 @@ ips_read_config(ips_ha_t * ha, int intr) return (0); } - + memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); return (1); } @@ -5959,7 +5949,7 @@ ips_readwrite_page5(ips_ha_t * ha, int write, int intr) scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; if (write) memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram)); - + /* issue the command */ if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) @@ -6196,32 +6186,32 @@ ips_erase_bios(ips_ha_t * ha) /* Clear the status register */ outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ outb(0x50, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* Erase Setup */ outb(0x20, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* Erase Confirm */ outb(0xD0, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* Erase Status */ outb(0x70, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ timeout = 80000; /* 80 seconds */ while (timeout > 0) { - if (ha->revision_id == IPS_REVID_TROMBONE64) { + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); udelay(25); /* 25 us */ } @@ -6241,13 +6231,13 @@ ips_erase_bios(ips_ha_t * ha) /* try to suspend the erase */ outb(0xB0, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* wait for 10 seconds */ timeout = 10000; while (timeout > 0) { - if (ha->revision_id == IPS_REVID_TROMBONE64) { + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); udelay(25); /* 25 us */ } @@ -6277,12 +6267,12 @@ ips_erase_bios(ips_ha_t * ha) /* Otherwise, we were successful */ /* clear status */ outb(0x50, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* enable reads */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (0); @@ -6308,32 +6298,32 @@ ips_erase_bios_memio(ips_ha_t * ha) /* Clear the status register */ writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* Erase Setup */ writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* Erase Confirm */ writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* Erase Status */ writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ timeout = 80000; /* 80 seconds */ while (timeout > 0) { - if (ha->revision_id == IPS_REVID_TROMBONE64) { + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); udelay(25); /* 25 us */ } @@ -6353,13 +6343,13 @@ ips_erase_bios_memio(ips_ha_t * ha) /* try to suspend the erase */ writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* wait for 10 seconds */ timeout = 10000; while (timeout > 0) { - if (ha->revision_id == IPS_REVID_TROMBONE64) { + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); udelay(25); /* 25 us */ } @@ -6389,12 +6379,12 @@ ips_erase_bios_memio(ips_ha_t * ha) /* Otherwise, we were successful */ /* clear status */ writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* enable reads */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (0); @@ -6423,21 +6413,21 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, for (i = 0; i < buffersize; i++) { /* write a byte */ outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ outb(0x40, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ outb(buffer[i], ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* wait up to one second */ timeout = 1000; while (timeout > 0) { - if (ha->revision_id == IPS_REVID_TROMBONE64) { + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { outl(0, ha->io_addr + IPS_REG_FLAP); udelay(25); /* 25 us */ } @@ -6454,11 +6444,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, if (timeout == 0) { /* timeout error */ outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (1); @@ -6468,11 +6458,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, if (status & 0x18) { /* programming error */ outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (1); @@ -6481,11 +6471,11 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, /* Enable reading */ outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (0); @@ -6514,21 +6504,21 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, for (i = 0; i < buffersize; i++) { /* write a byte */ writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ /* wait up to one second */ timeout = 1000; while (timeout > 0) { - if (ha->revision_id == IPS_REVID_TROMBONE64) { + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { writel(0, ha->mem_ptr + IPS_REG_FLAP); udelay(25); /* 25 us */ } @@ -6545,11 +6535,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, if (timeout == 0) { /* timeout error */ writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (1); @@ -6559,11 +6549,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, if (status & 0x18) { /* programming error */ writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (1); @@ -6572,11 +6562,11 @@ ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, /* Enable reading */ writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ return (0); @@ -6601,14 +6591,14 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, /* test 1st byte */ outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) return (1); outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) return (1); @@ -6617,7 +6607,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, for (i = 2; i < buffersize; i++) { outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); @@ -6650,14 +6640,14 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, /* test 1st byte */ writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) return (1); writel(1, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) return (1); @@ -6666,7 +6656,7 @@ ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, for (i = 2; i < buffersize; i++) { writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); - if (ha->revision_id == IPS_REVID_TROMBONE64) + if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ checksum = @@ -6837,24 +6827,18 @@ ips_register_scsi(int index) } ha = IPS_HA(sh); memcpy(ha, oldha, sizeof (ips_ha_t)); - free_irq(oldha->irq, oldha); + free_irq(oldha->pcidev->irq, oldha); /* Install the interrupt handler with the new ha */ - if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { + if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n"); - scsi_host_put(sh); - return -1; + goto err_out_sh; } kfree(oldha); - ips_sh[index] = sh; - ips_ha[index] = ha; /* Store away needed values for later use */ - sh->io_port = ha->io_addr; - sh->n_io_port = ha->io_addr ? 255 : 0; sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; - sh->irq = ha->irq; sh->sg_tablesize = sh->hostt->sg_tablesize; sh->can_queue = sh->hostt->can_queue; sh->cmd_per_lun = sh->hostt->cmd_per_lun; @@ -6867,10 +6851,21 @@ ips_register_scsi(int index) sh->max_channel = ha->nbus - 1; sh->can_queue = ha->max_cmds - 1; - scsi_add_host(sh, NULL); + if (scsi_add_host(sh, &ha->pcidev->dev)) + goto err_out; + + ips_sh[index] = sh; + ips_ha[index] = ha; + scsi_scan_host(sh); return 0; + +err_out: + free_irq(ha->pcidev->irq, ha); +err_out_sh: + scsi_host_put(sh); + return -1; } /*---------------------------------------------------------------------------*/ @@ -6882,20 +6877,14 @@ ips_register_scsi(int index) static void __devexit ips_remove_device(struct pci_dev *pci_dev) { - int i; - struct Scsi_Host *sh; - ips_ha_t *ha; + struct Scsi_Host *sh = pci_get_drvdata(pci_dev); - for (i = 0; i < IPS_MAX_ADAPTERS; i++) { - ha = ips_ha[i]; - if (ha) { - if ((pci_dev->bus->number == ha->pcidev->bus->number) && - (pci_dev->devfn == ha->pcidev->devfn)) { - sh = ips_sh[i]; - ips_release(sh); - } - } - } + pci_set_drvdata(pci_dev, NULL); + + ips_release(sh); + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); } /****************************************************************************/ @@ -6949,12 +6938,17 @@ module_exit(ips_module_exit); static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) { - int uninitialized_var(index); + int index = -1; int rc; METHOD_TRACE("ips_insert_device", 1); - if (pci_enable_device(pci_dev)) - return -1; + rc = pci_enable_device(pci_dev); + if (rc) + return rc; + + rc = pci_request_regions(pci_dev, "ips"); + if (rc) + goto err_out; rc = ips_init_phase1(pci_dev, &index); if (rc == SUCCESS) @@ -6970,6 +6964,19 @@ ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) ips_num_controllers++; ips_next_controller = ips_num_controllers; + + if (rc < 0) { + rc = -ENODEV; + goto err_out_regions; + } + + pci_set_drvdata(pci_dev, ips_sh[index]); + return 0; + +err_out_regions: + pci_release_regions(pci_dev); +err_out: + pci_disable_device(pci_dev); return rc; } @@ -6992,8 +6999,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) uint32_t mem_len; uint8_t bus; uint8_t func; - uint8_t irq; - uint16_t subdevice_id; int j; int index; dma_addr_t dma_address; @@ -7004,7 +7009,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) METHOD_TRACE("ips_init_phase1", 1); index = IPS_MAX_ADAPTERS; for (j = 0; j < IPS_MAX_ADAPTERS; j++) { - if (ips_ha[j] == 0) { + if (ips_ha[j] == NULL) { index = j; break; } @@ -7014,7 +7019,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) return -1; /* stuff that we get in dev */ - irq = pci_dev->irq; bus = pci_dev->bus->number; func = pci_dev->devfn; @@ -7042,34 +7046,17 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) uint32_t base; uint32_t offs; - if (!request_mem_region(mem_addr, mem_len, "ips")) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Couldn't allocate IO Memory space %x len %d.\n", - mem_addr, mem_len); - return -1; - } - base = mem_addr & PAGE_MASK; offs = mem_addr - base; ioremap_ptr = ioremap(base, PAGE_SIZE); + if (!ioremap_ptr) + return -1; mem_ptr = ioremap_ptr + offs; } else { ioremap_ptr = NULL; mem_ptr = NULL; } - /* setup I/O mapped area (if applicable) */ - if (io_addr) { - if (!request_region(io_addr, io_len, "ips")) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Couldn't allocate IO space %x len %d.\n", - io_addr, io_len); - return -1; - } - } - - subdevice_id = pci_dev->subsystem_device; - /* found a controller */ ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL); if (ha == NULL) { @@ -7078,13 +7065,11 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) return -1; } - ips_sh[index] = NULL; ips_ha[index] = ha; ha->active = 1; /* Store info in HA structure */ - ha->irq = irq; ha->io_addr = io_addr; ha->io_len = io_len; ha->mem_addr = mem_addr; @@ -7092,10 +7077,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) ha->mem_ptr = mem_ptr; ha->ioremap_ptr = ioremap_ptr; ha->host_num = (uint32_t) index; - ha->revision_id = pci_dev->revision; ha->slot_num = PCI_SLOT(pci_dev->devfn); - ha->device_id = pci_dev->device; - ha->subdevice_id = subdevice_id; ha->pcidev = pci_dev; /* @@ -7240,7 +7222,7 @@ ips_init_phase2(int index) } /* Install the interrupt handler */ - if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { + if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n"); return ips_abort_init(ha, index); @@ -7253,14 +7235,14 @@ ips_init_phase2(int index) if (!ips_allocatescbs(ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to allocate a CCB\n"); - free_irq(ha->irq, ha); + free_irq(ha->pcidev->irq, ha); return ips_abort_init(ha, index); } if (!ips_hainit(ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to initialize controller\n"); - free_irq(ha->irq, ha); + free_irq(ha->pcidev->irq, ha); return ips_abort_init(ha, index); } /* Free the temporary SCB */ @@ -7270,7 +7252,7 @@ ips_init_phase2(int index) if (!ips_allocatescbs(ha)) { IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to allocate CCBs\n"); - free_irq(ha->irq, ha); + free_irq(ha->pcidev->irq, ha); return ips_abort_init(ha, index); } diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 3bcbd9ff056b..e0657b6f009c 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -60,14 +60,14 @@ */ #define IPS_HA(x) ((ips_ha_t *) x->hostdata) #define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs) - #define IPS_IS_TROMBONE(ha) (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \ - (ha->revision_id >= IPS_REVID_TROMBONE32) && \ - (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0) - #define IPS_IS_CLARINET(ha) (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \ - (ha->revision_id >= IPS_REVID_CLARINETP1) && \ - (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0) - #define IPS_IS_MORPHEUS(ha) (ha->device_id == IPS_DEVICEID_MORPHEUS) - #define IPS_IS_MARCO(ha) (ha->device_id == IPS_DEVICEID_MARCO) + #define IPS_IS_TROMBONE(ha) (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \ + (ha->pcidev->revision >= IPS_REVID_TROMBONE32) && \ + (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) ? 1 : 0) + #define IPS_IS_CLARINET(ha) (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \ + (ha->pcidev->revision >= IPS_REVID_CLARINETP1) && \ + (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) ? 1 : 0) + #define IPS_IS_MORPHEUS(ha) (ha->pcidev->device == IPS_DEVICEID_MORPHEUS) + #define IPS_IS_MARCO(ha) (ha->pcidev->device == IPS_DEVICEID_MARCO) #define IPS_USE_I2O_DELIVER(ha) ((IPS_IS_MORPHEUS(ha) || \ (IPS_IS_TROMBONE(ha) && \ (ips_force_i2o))) ? 1 : 0) @@ -92,7 +92,7 @@ #ifndef min #define min(x,y) ((x) < (y) ? x : y) #endif - + #ifndef __iomem /* For clean compiles in earlier kernels without __iomem annotations */ #define __iomem #endif @@ -171,7 +171,7 @@ #define IPS_CMD_DOWNLOAD 0x20 #define IPS_CMD_RW_BIOSFW 0x22 #define IPS_CMD_GET_VERSION_INFO 0xC6 - #define IPS_CMD_RESET_CHANNEL 0x1A + #define IPS_CMD_RESET_CHANNEL 0x1A /* * Adapter Equates @@ -458,7 +458,7 @@ typedef struct { uint32_t reserved3; uint32_t buffer_addr; uint32_t reserved4; -} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; +} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; typedef struct { uint8_t op_code; @@ -552,7 +552,7 @@ typedef struct { uint32_t cccr; } IPS_NVRAM_CMD, *PIPS_NVRAM_CMD; -typedef struct +typedef struct { uint8_t op_code; uint8_t command_id; @@ -650,7 +650,7 @@ typedef struct { uint8_t device_address; uint8_t cmd_attribute; uint8_t cdb_length; - uint8_t reserved_for_LUN; + uint8_t reserved_for_LUN; uint32_t transfer_length; uint32_t buffer_pointer; uint16_t sg_count; @@ -790,7 +790,7 @@ typedef struct { /* SubSystem Parameter[4] */ #define IPS_GET_VERSION_SUPPORT 0x00018000 /* Mask for Versioning Support */ -typedef struct +typedef struct { uint32_t revision; uint8_t bootBlkVersion[32]; @@ -1034,7 +1034,6 @@ typedef struct ips_ha { uint8_t ha_id[IPS_MAX_CHANNELS+1]; uint32_t dcdb_active[IPS_MAX_CHANNELS]; uint32_t io_addr; /* Base I/O address */ - uint8_t irq; /* IRQ for adapter */ uint8_t ntargets; /* Number of targets */ uint8_t nbus; /* Number of buses */ uint8_t nlun; /* Number of Luns */ @@ -1066,10 +1065,7 @@ typedef struct ips_ha { int ioctl_reset; /* IOCTL Requested Reset Flag */ uint16_t reset_count; /* number of resets */ time_t last_ffdc; /* last time we sent ffdc info*/ - uint8_t revision_id; /* Revision level */ - uint16_t device_id; /* PCI device ID */ uint8_t slot_num; /* PCI Slot Number */ - uint16_t subdevice_id; /* Subsystem device ID */ int ioctl_len; /* size of ioctl buffer */ dma_addr_t ioctl_busaddr; /* dma address of ioctl buffer*/ uint8_t bios_version[8]; /* BIOS Revision */ diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 57ce2251abc8..b6f99dfbb038 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, " "Alex Aizman <itn780@yahoo.com>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -/* #define DEBUG_TCP */ +#undef DEBUG_TCP #define DEBUG_ASSERT #ifdef DEBUG_TCP @@ -67,115 +67,429 @@ MODULE_LICENSE("GPL"); static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); +static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment); + +/* + * Scatterlist handling: inside the iscsi_segment, we + * remember an index into the scatterlist, and set data/size + * to the current scatterlist entry. For highmem pages, we + * kmap as needed. + * + * Note that the page is unmapped when we return from + * TCP's data_ready handler, so we may end up mapping and + * unmapping the same page repeatedly. The whole reason + * for this is that we shouldn't keep the page mapped + * outside the softirq. + */ + +/** + * iscsi_tcp_segment_init_sg - init indicated scatterlist entry + * @segment: the buffer object + * @sg: scatterlist + * @offset: byte offset into that sg entry + * + * This function sets up the segment so that subsequent + * data is copied to the indicated sg entry, at the given + * offset. + */ static inline void -iscsi_buf_init_iov(struct iscsi_buf *ibuf, char *vbuf, int size) +iscsi_tcp_segment_init_sg(struct iscsi_segment *segment, + struct scatterlist *sg, unsigned int offset) { - sg_init_one(&ibuf->sg, vbuf, size); - ibuf->sent = 0; - ibuf->use_sendmsg = 1; + segment->sg = sg; + segment->sg_offset = offset; + segment->size = min(sg->length - offset, + segment->total_size - segment->total_copied); + segment->data = NULL; } +/** + * iscsi_tcp_segment_map - map the current S/G page + * @segment: iscsi_segment + * @recv: 1 if called from recv path + * + * We only need to possibly kmap data if scatter lists are being used, + * because the iscsi passthrough and internal IO paths will never use high + * mem pages. + */ static inline void -iscsi_buf_init_sg(struct iscsi_buf *ibuf, struct scatterlist *sg) +iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) { - sg_init_table(&ibuf->sg, 1); - sg_set_page(&ibuf->sg, sg_page(sg), sg->length, sg->offset); + struct scatterlist *sg; + + if (segment->data != NULL || !segment->sg) + return; + + sg = segment->sg; + BUG_ON(segment->sg_mapped); + BUG_ON(sg->length == 0); + /* - * Fastpath: sg element fits into single page + * If the page count is greater than one it is ok to send + * to the network layer's zero copy send path. If not we + * have to go the slow sendmsg path. We always map for the + * recv path. */ - if (sg->length + sg->offset <= PAGE_SIZE && !PageSlab(sg_page(sg))) - ibuf->use_sendmsg = 0; - else - ibuf->use_sendmsg = 1; - ibuf->sent = 0; + if (page_count(sg_page(sg)) >= 1 && !recv) + return; + + debug_tcp("iscsi_tcp_segment_map %s %p\n", recv ? "recv" : "xmit", + segment); + segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; } -static inline int -iscsi_buf_left(struct iscsi_buf *ibuf) +static inline void +iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { - int rc; + debug_tcp("iscsi_tcp_segment_unmap %p\n", segment); - rc = ibuf->sg.length - ibuf->sent; - BUG_ON(rc < 0); - return rc; + if (segment->sg_mapped) { + debug_tcp("iscsi_tcp_segment_unmap valid\n"); + kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); + segment->sg_mapped = NULL; + segment->data = NULL; + } } +/* + * Splice the digest buffer into the buffer + */ static inline void -iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf, - u8* crc) +iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest) { - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - - crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc); - buf->sg.length += sizeof(u32); + segment->data = digest; + segment->digest_len = ISCSI_DIGEST_SIZE; + segment->total_size += ISCSI_DIGEST_SIZE; + segment->size = ISCSI_DIGEST_SIZE; + segment->copied = 0; + segment->sg = NULL; + segment->hash = NULL; } +/** + * iscsi_tcp_segment_done - check whether the segment is complete + * @segment: iscsi segment to check + * @recv: set to one of this is called from the recv path + * @copied: number of bytes copied + * + * Check if we're done receiving this segment. If the receive + * buffer is full but we expect more data, move on to the + * next entry in the scatterlist. + * + * If the amount of data we received isn't a multiple of 4, + * we will transparently receive the pad bytes, too. + * + * This function must be re-entrant. + */ static inline int -iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn) +iscsi_tcp_segment_done(struct iscsi_segment *segment, int recv, unsigned copied) { - struct sk_buff *skb = tcp_conn->in.skb; - - tcp_conn->in.zero_copy_hdr = 0; + static unsigned char padbuf[ISCSI_PAD_LEN]; + struct scatterlist sg; + unsigned int pad; - if (tcp_conn->in.copy >= tcp_conn->hdr_size && - tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) { + debug_tcp("copied %u %u size %u %s\n", segment->copied, copied, + segment->size, recv ? "recv" : "xmit"); + if (segment->hash && copied) { /* - * Zero-copy PDU Header: using connection context - * to store header pointer. + * If a segment is kmapd we must unmap it before sending + * to the crypto layer since that will try to kmap it again. */ - if (skb_shinfo(skb)->frag_list == NULL && - !skb_shinfo(skb)->nr_frags) { - tcp_conn->in.hdr = (struct iscsi_hdr *) - ((char*)skb->data + tcp_conn->in.offset); - tcp_conn->in.zero_copy_hdr = 1; + iscsi_tcp_segment_unmap(segment); + + if (!segment->data) { + sg_init_table(&sg, 1); + sg_set_page(&sg, sg_page(segment->sg), copied, + segment->copied + segment->sg_offset + + segment->sg->offset); + } else + sg_init_one(&sg, segment->data + segment->copied, + copied); + crypto_hash_update(segment->hash, &sg, copied); + } + + segment->copied += copied; + if (segment->copied < segment->size) { + iscsi_tcp_segment_map(segment, recv); + return 0; + } + + segment->total_copied += segment->copied; + segment->copied = 0; + segment->size = 0; + + /* Unmap the current scatterlist page, if there is one. */ + iscsi_tcp_segment_unmap(segment); + + /* Do we have more scatterlist entries? */ + debug_tcp("total copied %u total size %u\n", segment->total_copied, + segment->total_size); + if (segment->total_copied < segment->total_size) { + /* Proceed to the next entry in the scatterlist. */ + iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg), + 0); + iscsi_tcp_segment_map(segment, recv); + BUG_ON(segment->size == 0); + return 0; + } + + /* Do we need to handle padding? */ + pad = iscsi_padding(segment->total_copied); + if (pad != 0) { + debug_tcp("consume %d pad bytes\n", pad); + segment->total_size += pad; + segment->size = pad; + segment->data = padbuf; + return 0; + } + + /* + * Set us up for transferring the data digest. hdr digest + * is completely handled in hdr done function. + */ + if (segment->hash) { + crypto_hash_final(segment->hash, segment->digest); + iscsi_tcp_segment_splice_digest(segment, + recv ? segment->recv_digest : segment->digest); + return 0; + } + + return 1; +} + +/** + * iscsi_tcp_xmit_segment - transmit segment + * @tcp_conn: the iSCSI TCP connection + * @segment: the buffer to transmnit + * + * This function transmits as much of the buffer as + * the network layer will accept, and returns the number of + * bytes transmitted. + * + * If CRC hashing is enabled, the function will compute the + * hash as it goes. When the entire segment has been transmitted, + * it will retrieve the hash value and send it as well. + */ +static int +iscsi_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) +{ + struct socket *sk = tcp_conn->sock; + unsigned int copied = 0; + int r = 0; + + while (!iscsi_tcp_segment_done(segment, 0, r)) { + struct scatterlist *sg; + unsigned int offset, copy; + int flags = 0; + + r = 0; + offset = segment->copied; + copy = segment->size - offset; + + if (segment->total_copied + segment->size < segment->total_size) + flags |= MSG_MORE; + + /* Use sendpage if we can; else fall back to sendmsg */ + if (!segment->data) { + sg = segment->sg; + offset += segment->sg_offset + sg->offset; + r = tcp_conn->sendpage(sk, sg_page(sg), offset, copy, + flags); } else { - /* ignoring return code since we checked - * in.copy before */ - skb_copy_bits(skb, tcp_conn->in.offset, - &tcp_conn->hdr, tcp_conn->hdr_size); - tcp_conn->in.hdr = &tcp_conn->hdr; + struct msghdr msg = { .msg_flags = flags }; + struct kvec iov = { + .iov_base = segment->data + offset, + .iov_len = copy + }; + + r = kernel_sendmsg(sk, &msg, &iov, 1, copy); } - tcp_conn->in.offset += tcp_conn->hdr_size; - tcp_conn->in.copy -= tcp_conn->hdr_size; - } else { - int hdr_remains; - int copylen; - /* - * PDU header scattered across SKB's, - * copying it... This'll happen quite rarely. - */ + if (r < 0) { + iscsi_tcp_segment_unmap(segment); + if (copied || r == -EAGAIN) + break; + return r; + } + copied += r; + } + return copied; +} + +/** + * iscsi_tcp_segment_recv - copy data to segment + * @tcp_conn: the iSCSI TCP connection + * @segment: the buffer to copy to + * @ptr: data pointer + * @len: amount of data available + * + * This function copies up to @len bytes to the + * given buffer, and returns the number of bytes + * consumed, which can actually be less than @len. + * + * If hash digest is enabled, the function will update the + * hash while copying. + * Combining these two operations doesn't buy us a lot (yet), + * but in the future we could implement combined copy+crc, + * just way we do for network layer checksums. + */ +static int +iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment, const void *ptr, + unsigned int len) +{ + unsigned int copy = 0, copied = 0; + + while (!iscsi_tcp_segment_done(segment, 1, copy)) { + if (copied == len) { + debug_tcp("iscsi_tcp_segment_recv copied %d bytes\n", + len); + break; + } + + copy = min(len - copied, segment->size - segment->copied); + debug_tcp("iscsi_tcp_segment_recv copying %d\n", copy); + memcpy(segment->data + segment->copied, ptr + copied, copy); + copied += copy; + } + return copied; +} - if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER) - tcp_conn->in.hdr_offset = 0; +static inline void +iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen, + unsigned char digest[ISCSI_DIGEST_SIZE]) +{ + struct scatterlist sg; - hdr_remains = tcp_conn->hdr_size - tcp_conn->in.hdr_offset; - BUG_ON(hdr_remains <= 0); + sg_init_one(&sg, hdr, hdrlen); + crypto_hash_digest(hash, &sg, hdrlen, digest); +} - copylen = min(tcp_conn->in.copy, hdr_remains); - skb_copy_bits(skb, tcp_conn->in.offset, - (char*)&tcp_conn->hdr + tcp_conn->in.hdr_offset, - copylen); +static inline int +iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) +{ + if (!segment->digest_len) + return 1; - debug_tcp("PDU gather offset %d bytes %d in.offset %d " - "in.copy %d\n", tcp_conn->in.hdr_offset, copylen, - tcp_conn->in.offset, tcp_conn->in.copy); + if (memcmp(segment->recv_digest, segment->digest, + segment->digest_len)) { + debug_scsi("digest mismatch\n"); + return 0; + } - tcp_conn->in.offset += copylen; - tcp_conn->in.copy -= copylen; - if (copylen < hdr_remains) { - tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER; - tcp_conn->in.hdr_offset += copylen; - return -EAGAIN; + return 1; +} + +/* + * Helper function to set up segment buffer + */ +static inline void +__iscsi_segment_init(struct iscsi_segment *segment, size_t size, + iscsi_segment_done_fn_t *done, struct hash_desc *hash) +{ + memset(segment, 0, sizeof(*segment)); + segment->total_size = size; + segment->done = done; + + if (hash) { + segment->hash = hash; + crypto_hash_init(hash); + } +} + +static inline void +iscsi_segment_init_linear(struct iscsi_segment *segment, void *data, + size_t size, iscsi_segment_done_fn_t *done, + struct hash_desc *hash) +{ + __iscsi_segment_init(segment, size, done, hash); + segment->data = data; + segment->size = size; +} + +static inline int +iscsi_segment_seek_sg(struct iscsi_segment *segment, + struct scatterlist *sg_list, unsigned int sg_count, + unsigned int offset, size_t size, + iscsi_segment_done_fn_t *done, struct hash_desc *hash) +{ + struct scatterlist *sg; + unsigned int i; + + debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", + offset, size); + __iscsi_segment_init(segment, size, done, hash); + for_each_sg(sg_list, sg, sg_count, i) { + debug_scsi("sg %d, len %u offset %u\n", i, sg->length, + sg->offset); + if (offset < sg->length) { + iscsi_tcp_segment_init_sg(segment, sg, offset); + return 0; } - tcp_conn->in.hdr = &tcp_conn->hdr; - tcp_conn->discontiguous_hdr_cnt++; - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; + offset -= sg->length; } + return ISCSI_ERR_DATA_OFFSET; +} + +/** + * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception + * @tcp_conn: iscsi connection to prep for + * + * This function always passes NULL for the hash argument, because when this + * function is called we do not yet know the final size of the header and want + * to delay the digest processing until we know that. + */ +static void +iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn) +{ + debug_tcp("iscsi_tcp_hdr_recv_prep(%p%s)\n", tcp_conn, + tcp_conn->iscsi_conn->hdrdgst_en ? ", digest enabled" : ""); + iscsi_segment_init_linear(&tcp_conn->in.segment, + tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr), + iscsi_tcp_hdr_recv_done, NULL); +} + +/* + * Handle incoming reply to any other type of command + */ +static int +iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) +{ + struct iscsi_conn *conn = tcp_conn->iscsi_conn; + int rc = 0; + + if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) + return ISCSI_ERR_DATA_DGST; + + rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, + conn->data, tcp_conn->in.datalen); + if (rc) + return rc; + + iscsi_tcp_hdr_recv_prep(tcp_conn); return 0; } +static void +iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) +{ + struct iscsi_conn *conn = tcp_conn->iscsi_conn; + struct hash_desc *rx_hash = NULL; + + if (conn->datadgst_en) + rx_hash = &tcp_conn->rx_hash; + + iscsi_segment_init_linear(&tcp_conn->in.segment, + conn->data, tcp_conn->in.datalen, + iscsi_tcp_data_recv_done, rx_hash); +} + /* * must be called with session lock */ @@ -184,7 +498,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_r2t_info *r2t; - struct scsi_cmnd *sc; /* flush ctask's r2t queues */ while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { @@ -193,12 +506,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n"); } - sc = ctask->sc; - if (unlikely(!sc)) - return; - - tcp_ctask->xmstate = XMSTATE_VALUE_IDLE; - tcp_ctask->r2t = NULL; + r2t = tcp_ctask->r2t; + if (r2t != NULL) { + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); + tcp_ctask->r2t = NULL; + } } /** @@ -217,11 +530,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int datasn = be32_to_cpu(rhdr->datasn); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - /* - * setup Data-In byte counter (gets decremented..) - */ - ctask->data_count = tcp_conn->in.datalen; - if (tcp_conn->in.datalen == 0) return 0; @@ -242,22 +550,20 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) { + sc->result = (DID_OK << 16) | rhdr->cmd_status; conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | + ISCSI_FLAG_DATA_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); if (res_count > 0 && - res_count <= scsi_bufflen(sc)) { + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || + res_count <= scsi_bufflen(sc))) scsi_set_resid(sc, res_count); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - } else + else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) { - scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - } else - sc->result = (DID_OK << 16) | rhdr->cmd_status; + } } conn->datain_pdus_cnt++; @@ -281,9 +587,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, struct iscsi_r2t_info *r2t) { struct iscsi_data *hdr; - struct scsi_cmnd *sc = ctask->sc; - int i, sg_count = 0; - struct scatterlist *sg; hdr = &r2t->dtask.hdr; memset(hdr, 0, sizeof(struct iscsi_data)); @@ -307,34 +610,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, conn->dataout_pdus_cnt++; r2t->sent = 0; - - iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr, - sizeof(struct iscsi_hdr)); - - sg = scsi_sglist(sc); - r2t->sg = NULL; - for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) { - /* FIXME: prefetch ? */ - if (sg_count + sg->length > r2t->data_offset) { - int page_offset; - - /* sg page found! */ - - /* offset within this page */ - page_offset = r2t->data_offset - sg_count; - - /* fill in this buffer */ - iscsi_buf_init_sg(&r2t->sendbuf, sg); - r2t->sendbuf.sg.offset += page_offset; - r2t->sendbuf.sg.length -= page_offset; - - /* xmit logic will continue with next one */ - r2t->sg = sg + 1; - break; - } - sg_count += sg->length; - } - BUG_ON(r2t->sg == NULL); } /** @@ -366,14 +641,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } /* fill-in new R2T associated with the task */ - spin_lock(&session->lock); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (!ctask->sc || ctask->mtask || - session->state != ISCSI_STATE_LOGGED_IN) { + if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " "recovery...\n", ctask->itt); - spin_unlock(&session->lock); return 0; } @@ -384,7 +656,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); - spin_unlock(&session->lock); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); return ISCSI_ERR_DATALEN; } @@ -395,10 +668,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_offset = be32_to_cpu(rhdr->data_offset); if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - spin_unlock(&session->lock); printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " "offset %u and total length %d\n", r2t->data_length, r2t->data_offset, scsi_bufflen(ctask->sc)); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); return ISCSI_ERR_DATALEN; } @@ -409,26 +683,55 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn = r2tsn + 1; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); - set_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate); - list_move_tail(&ctask->running, &conn->xmitqueue); - - scsi_queue_work(session->host, &conn->xmitwork); conn->r2t_pdus_cnt++; - spin_unlock(&session->lock); + iscsi_requeue_ctask(ctask); return 0; } +/* + * Handle incoming reply to DataIn command + */ static int -iscsi_tcp_hdr_recv(struct iscsi_conn *conn) +iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) +{ + struct iscsi_conn *conn = tcp_conn->iscsi_conn; + struct iscsi_hdr *hdr = tcp_conn->in.hdr; + int rc; + + if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) + return ISCSI_ERR_DATA_DGST; + + /* check for non-exceptional status */ + if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { + rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0); + if (rc) + return rc; + } + + iscsi_tcp_hdr_recv_prep(tcp_conn); + return 0; +} + +/** + * iscsi_tcp_hdr_dissect - process PDU header + * @conn: iSCSI connection + * @hdr: PDU header + * + * This function analyzes the header of the PDU received, + * and performs several sanity checks. If the PDU is accompanied + * by data, the receive buffer is set up to copy the incoming data + * to the correct location. + */ +static int +iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) { int rc = 0, opcode, ahslen; - struct iscsi_hdr *hdr; struct iscsi_session *session = conn->session; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - uint32_t cdgst, rdgst = 0, itt; - - hdr = tcp_conn->in.hdr; + struct iscsi_cmd_task *ctask; + uint32_t itt; /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); @@ -437,78 +740,73 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } - tcp_conn->data_copied = 0; - /* read AHS */ + /* Additional header segments. So far, we don't + * process additional headers. + */ ahslen = hdr->hlength << 2; - tcp_conn->in.offset += ahslen; - tcp_conn->in.copy -= ahslen; - if (tcp_conn->in.copy < 0) { - printk(KERN_ERR "iscsi_tcp: can't handle AHS with length " - "%d bytes\n", ahslen); - return ISCSI_ERR_AHSLEN; - } - - /* calculate read padding */ - tcp_conn->in.padding = tcp_conn->in.datalen & (ISCSI_PAD_LEN-1); - if (tcp_conn->in.padding) { - tcp_conn->in.padding = ISCSI_PAD_LEN - tcp_conn->in.padding; - debug_scsi("read padding %d bytes\n", tcp_conn->in.padding); - } - - if (conn->hdrdgst_en) { - struct scatterlist sg; - - sg_init_one(&sg, (u8 *)hdr, - sizeof(struct iscsi_hdr) + ahslen); - crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length, - (u8 *)&cdgst); - rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) + - ahslen); - if (cdgst != rdgst) { - printk(KERN_ERR "iscsi_tcp: hdrdgst error " - "recv 0x%x calc 0x%x\n", rdgst, cdgst); - return ISCSI_ERR_HDR_DGST; - } - } opcode = hdr->opcode & ISCSI_OPCODE_MASK; /* verify itt (itt encoding: age+cid+itt) */ rc = iscsi_verify_itt(conn, hdr, &itt); - if (rc == ISCSI_ERR_NO_SCSI_CMD) { - tcp_conn->in.datalen = 0; /* force drop */ - return 0; - } else if (rc) + if (rc) return rc; - debug_tcp("opcode 0x%x offset %d copy %d ahslen %d datalen %d\n", - opcode, tcp_conn->in.offset, tcp_conn->in.copy, - ahslen, tcp_conn->in.datalen); + debug_tcp("opcode 0x%x ahslen %d datalen %d\n", + opcode, ahslen, tcp_conn->in.datalen); switch(opcode) { case ISCSI_OP_SCSI_DATA_IN: - tcp_conn->in.ctask = session->cmds[itt]; - rc = iscsi_data_rsp(conn, tcp_conn->in.ctask); + ctask = session->cmds[itt]; + spin_lock(&conn->session->lock); + rc = iscsi_data_rsp(conn, ctask); + spin_unlock(&conn->session->lock); if (rc) return rc; + if (tcp_conn->in.datalen) { + struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + struct hash_desc *rx_hash = NULL; + + /* + * Setup copy of Data-In into the Scsi_Cmnd + * Scatterlist case: + * We set up the iscsi_segment to point to the next + * scatterlist entry to copy to. As we go along, + * we move on to the next scatterlist entry and + * update the digest per-entry. + */ + if (conn->datadgst_en) + rx_hash = &tcp_conn->rx_hash; + + debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " + "datalen=%d)\n", tcp_conn, + tcp_ctask->data_offset, + tcp_conn->in.datalen); + return iscsi_segment_seek_sg(&tcp_conn->in.segment, + scsi_sglist(ctask->sc), + scsi_sg_count(ctask->sc), + tcp_ctask->data_offset, + tcp_conn->in.datalen, + iscsi_tcp_process_data_in, + rx_hash); + } /* fall through */ case ISCSI_OP_SCSI_CMD_RSP: - tcp_conn->in.ctask = session->cmds[itt]; - if (tcp_conn->in.datalen) - goto copy_hdr; - - spin_lock(&session->lock); - rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); - spin_unlock(&session->lock); + if (tcp_conn->in.datalen) { + iscsi_tcp_data_recv_prep(tcp_conn); + return 0; + } + rc = iscsi_complete_pdu(conn, hdr, NULL, 0); break; case ISCSI_OP_R2T: - tcp_conn->in.ctask = session->cmds[itt]; + ctask = session->cmds[itt]; if (ahslen) rc = ISCSI_ERR_AHSLEN; - else if (tcp_conn->in.ctask->sc->sc_data_direction == - DMA_TO_DEVICE) - rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask); - else + else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { + spin_lock(&session->lock); + rc = iscsi_r2t_rsp(conn, ctask); + spin_unlock(&session->lock); + } else rc = ISCSI_ERR_PROTO; break; case ISCSI_OP_LOGIN_RSP: @@ -520,8 +818,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) * than 8K, but there are no targets that currently do this. * For now we fail until we find a vendor that needs it */ - if (ISCSI_DEF_MAX_RECV_SEG_LEN < - tcp_conn->in.datalen) { + if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { printk(KERN_ERR "iscsi_tcp: received buffer of len %u " "but conn buffer is only %u (opcode %0x)\n", tcp_conn->in.datalen, @@ -530,8 +827,13 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) break; } - if (tcp_conn->in.datalen) - goto copy_hdr; + /* If there's data coming in with the response, + * receive it to the connection's buffer. + */ + if (tcp_conn->in.datalen) { + iscsi_tcp_data_recv_prep(tcp_conn); + return 0; + } /* fall through */ case ISCSI_OP_LOGOUT_RSP: case ISCSI_OP_NOOP_IN: @@ -543,461 +845,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) break; } - return rc; - -copy_hdr: - /* - * if we did zero copy for the header but we will need multiple - * skbs to complete the command then we have to copy the header - * for later use - */ - if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <= - (tcp_conn->in.datalen + tcp_conn->in.padding + - (conn->datadgst_en ? 4 : 0))) { - debug_tcp("Copying header for later use. in.copy %d in.datalen" - " %d\n", tcp_conn->in.copy, tcp_conn->in.datalen); - memcpy(&tcp_conn->hdr, tcp_conn->in.hdr, - sizeof(struct iscsi_hdr)); - tcp_conn->in.hdr = &tcp_conn->hdr; - tcp_conn->in.zero_copy_hdr = 0; - } - return 0; -} - -/** - * iscsi_ctask_copy - copy skb bits to the destanation cmd task - * @conn: iscsi tcp connection - * @ctask: scsi command task - * @buf: buffer to copy to - * @buf_size: size of buffer - * @offset: offset within the buffer - * - * Notes: - * The function calls skb_copy_bits() and updates per-connection and - * per-cmd byte counters. - * - * Read counters (in bytes): - * - * conn->in.offset offset within in progress SKB - * conn->in.copy left to copy from in progress SKB - * including padding - * conn->in.copied copied already from in progress SKB - * conn->data_copied copied already from in progress buffer - * ctask->sent total bytes sent up to the MidLayer - * ctask->data_count left to copy from in progress Data-In - * buf_left left to copy from in progress buffer - **/ -static inline int -iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, - void *buf, int buf_size, int offset) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - int buf_left = buf_size - (tcp_conn->data_copied + offset); - unsigned size = min(tcp_conn->in.copy, buf_left); - int rc; - - size = min(size, ctask->data_count); - - debug_tcp("ctask_copy %d bytes at offset %d copied %d\n", - size, tcp_conn->in.offset, tcp_conn->in.copied); - - BUG_ON(size <= 0); - BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc)); - - rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, - (char*)buf + (offset + tcp_conn->data_copied), size); - /* must fit into skb->len */ - BUG_ON(rc); - - tcp_conn->in.offset += size; - tcp_conn->in.copy -= size; - tcp_conn->in.copied += size; - tcp_conn->data_copied += size; - tcp_ctask->sent += size; - ctask->data_count -= size; - - BUG_ON(tcp_conn->in.copy < 0); - BUG_ON(ctask->data_count < 0); - - if (buf_size != (tcp_conn->data_copied + offset)) { - if (!ctask->data_count) { - BUG_ON(buf_size - tcp_conn->data_copied < 0); - /* done with this PDU */ - return buf_size - tcp_conn->data_copied; - } - return -EAGAIN; + if (rc == 0) { + /* Anything that comes with data should have + * been handled above. */ + if (tcp_conn->in.datalen) + return ISCSI_ERR_PROTO; + iscsi_tcp_hdr_recv_prep(tcp_conn); } - /* done with this buffer or with both - PDU and buffer */ - tcp_conn->data_copied = 0; - return 0; + return rc; } /** - * iscsi_tcp_copy - copy skb bits to the destanation buffer - * @conn: iscsi tcp connection + * iscsi_tcp_hdr_recv_done - process PDU header * - * Notes: - * The function calls skb_copy_bits() and updates per-connection - * byte counters. - **/ -static inline int -iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - int buf_left = buf_size - tcp_conn->data_copied; - int size = min(tcp_conn->in.copy, buf_left); - int rc; - - debug_tcp("tcp_copy %d bytes at offset %d copied %d\n", - size, tcp_conn->in.offset, tcp_conn->data_copied); - BUG_ON(size <= 0); - - rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, - (char*)conn->data + tcp_conn->data_copied, size); - BUG_ON(rc); - - tcp_conn->in.offset += size; - tcp_conn->in.copy -= size; - tcp_conn->in.copied += size; - tcp_conn->data_copied += size; - - if (buf_size != tcp_conn->data_copied) - return -EAGAIN; - - return 0; -} - -static inline void -partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg, - int offset, int length) -{ - struct scatterlist temp; - - sg_init_table(&temp, 1); - sg_set_page(&temp, sg_page(sg), length, offset); - crypto_hash_update(desc, &temp, length); -} - -static void -iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len) -{ - struct scatterlist tmp; - - sg_init_one(&tmp, buf, len); - crypto_hash_update(&tcp_conn->rx_hash, &tmp, len); -} - -static int iscsi_scsi_data_in(struct iscsi_conn *conn) + * This is the callback invoked when the PDU header has + * been received. If the header is followed by additional + * header segments, we go back for more data. + */ +static int +iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) { - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_cmd_task *ctask = tcp_conn->in.ctask; - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct scsi_cmnd *sc = ctask->sc; - struct scatterlist *sg; - int i, offset, rc = 0; - - BUG_ON((void*)ctask != sc->SCp.ptr); - - offset = tcp_ctask->data_offset; - sg = scsi_sglist(sc); - - if (tcp_ctask->data_offset) - for (i = 0; i < tcp_ctask->sg_count; i++) - offset -= sg[i].length; - /* we've passed through partial sg*/ - if (offset < 0) - offset = 0; - - for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) { - char *dest; - - dest = kmap_atomic(sg_page(&sg[i]), KM_SOFTIRQ0); - rc = iscsi_ctask_copy(tcp_conn, ctask, dest + sg[i].offset, - sg[i].length, offset); - kunmap_atomic(dest, KM_SOFTIRQ0); - if (rc == -EAGAIN) - /* continue with the next SKB/PDU */ - return rc; - if (!rc) { - if (conn->datadgst_en) { - if (!offset) - crypto_hash_update( - &tcp_conn->rx_hash, - &sg[i], sg[i].length); - else - partial_sg_digest_update( - &tcp_conn->rx_hash, - &sg[i], - sg[i].offset + offset, - sg[i].length - offset); - } - offset = 0; - tcp_ctask->sg_count++; - } - - if (!ctask->data_count) { - if (rc && conn->datadgst_en) - /* - * data-in is complete, but buffer not... - */ - partial_sg_digest_update(&tcp_conn->rx_hash, - &sg[i], - sg[i].offset, - sg[i].length-rc); - rc = 0; - break; - } - - if (!tcp_conn->in.copy) - return -EAGAIN; - } - BUG_ON(ctask->data_count); + struct iscsi_conn *conn = tcp_conn->iscsi_conn; + struct iscsi_hdr *hdr; - /* check for non-exceptional status */ - if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) { - debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n", - (long)sc, sc->result, ctask->itt, - tcp_conn->in.hdr->flags); - spin_lock(&conn->session->lock); - __iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0); - spin_unlock(&conn->session->lock); + /* Check if there are additional header segments + * *prior* to computing the digest, because we + * may need to go back to the caller for more. + */ + hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf; + if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) { + /* Bump the header length - the caller will + * just loop around and get the AHS for us, and + * call again. */ + unsigned int ahslen = hdr->hlength << 2; + + /* Make sure we don't overflow */ + if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf)) + return ISCSI_ERR_AHSLEN; + + segment->total_size += ahslen; + segment->size += ahslen; + return 0; } - return rc; -} - -static int -iscsi_data_recv(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - int rc = 0, opcode; - - opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK; - switch (opcode) { - case ISCSI_OP_SCSI_DATA_IN: - rc = iscsi_scsi_data_in(conn); - break; - case ISCSI_OP_SCSI_CMD_RSP: - case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_ASYNC_EVENT: - case ISCSI_OP_REJECT: - /* - * Collect data segment to the connection's data - * placeholder - */ - if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) { - rc = -EAGAIN; - goto exit; + /* We're done processing the header. See if we're doing + * header digests; if so, set up the recv_digest buffer + * and go back for more. */ + if (conn->hdrdgst_en) { + if (segment->digest_len == 0) { + iscsi_tcp_segment_splice_digest(segment, + segment->recv_digest); + return 0; } + iscsi_tcp_dgst_header(&tcp_conn->rx_hash, hdr, + segment->total_copied - ISCSI_DIGEST_SIZE, + segment->digest); - rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data, - tcp_conn->in.datalen); - if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP) - iscsi_recv_digest_update(tcp_conn, conn->data, - tcp_conn->in.datalen); - break; - default: - BUG_ON(1); + if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) + return ISCSI_ERR_HDR_DGST; } -exit: - return rc; + + tcp_conn->in.hdr = hdr; + return iscsi_tcp_hdr_dissect(conn, hdr); } /** - * iscsi_tcp_data_recv - TCP receive in sendfile fashion + * iscsi_tcp_recv - TCP receive in sendfile fashion * @rd_desc: read descriptor * @skb: socket buffer * @offset: offset in skb * @len: skb->len - offset **/ static int -iscsi_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, - unsigned int offset, size_t len) +iscsi_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, + unsigned int offset, size_t len) { - int rc; struct iscsi_conn *conn = rd_desc->arg.data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - int processed; - char pad[ISCSI_PAD_LEN]; - struct scatterlist sg; - - /* - * Save current SKB and its offset in the corresponding - * connection context. - */ - tcp_conn->in.copy = skb->len - offset; - tcp_conn->in.offset = offset; - tcp_conn->in.skb = skb; - tcp_conn->in.len = tcp_conn->in.copy; - BUG_ON(tcp_conn->in.copy <= 0); - debug_tcp("in %d bytes\n", tcp_conn->in.copy); + struct iscsi_segment *segment = &tcp_conn->in.segment; + struct skb_seq_state seq; + unsigned int consumed = 0; + int rc = 0; -more: - tcp_conn->in.copied = 0; - rc = 0; + debug_tcp("in %d bytes\n", skb->len - offset); if (unlikely(conn->suspend_rx)) { debug_tcp("conn %d Rx suspended!\n", conn->id); return 0; } - if (tcp_conn->in_progress == IN_PROGRESS_WAIT_HEADER || - tcp_conn->in_progress == IN_PROGRESS_HEADER_GATHER) { - rc = iscsi_hdr_extract(tcp_conn); - if (rc) { - if (rc == -EAGAIN) - goto nomore; - else { - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return 0; - } - } + skb_prepare_seq_read(skb, offset, skb->len, &seq); + while (1) { + unsigned int avail; + const u8 *ptr; - /* - * Verify and process incoming PDU header. - */ - rc = iscsi_tcp_hdr_recv(conn); - if (!rc && tcp_conn->in.datalen) { - if (conn->datadgst_en) - crypto_hash_init(&tcp_conn->rx_hash); - tcp_conn->in_progress = IN_PROGRESS_DATA_RECV; - } else if (rc) { - iscsi_conn_failure(conn, rc); - return 0; + avail = skb_seq_read(consumed, &ptr, &seq); + if (avail == 0) { + debug_tcp("no more data avail. Consumed %d\n", + consumed); + break; } - } - - if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV && - tcp_conn->in.copy) { - uint32_t recv_digest; - - debug_tcp("extra data_recv offset %d copy %d\n", - tcp_conn->in.offset, tcp_conn->in.copy); - - if (!tcp_conn->data_copied) { - if (tcp_conn->in.padding) { - debug_tcp("padding -> %d\n", - tcp_conn->in.padding); - memset(pad, 0, tcp_conn->in.padding); - sg_init_one(&sg, pad, tcp_conn->in.padding); - crypto_hash_update(&tcp_conn->rx_hash, - &sg, sg.length); + BUG_ON(segment->copied >= segment->size); + + debug_tcp("skb %p ptr=%p avail=%u\n", skb, ptr, avail); + rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail); + BUG_ON(rc == 0); + consumed += rc; + + if (segment->total_copied >= segment->total_size) { + debug_tcp("segment done\n"); + rc = segment->done(tcp_conn, segment); + if (rc != 0) { + skb_abort_seq_read(&seq); + goto error; } - crypto_hash_final(&tcp_conn->rx_hash, - (u8 *) &tcp_conn->in.datadgst); - debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst); - } - rc = iscsi_tcp_copy(conn, sizeof(uint32_t)); - if (rc) { - if (rc == -EAGAIN) - goto again; - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return 0; - } - - memcpy(&recv_digest, conn->data, sizeof(uint32_t)); - if (recv_digest != tcp_conn->in.datadgst) { - debug_tcp("iscsi_tcp: data digest error!" - "0x%x != 0x%x\n", recv_digest, - tcp_conn->in.datadgst); - iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); - return 0; - } else { - debug_tcp("iscsi_tcp: data digest match!" - "0x%x == 0x%x\n", recv_digest, - tcp_conn->in.datadgst); - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; + /* The done() functions sets up the + * next segment. */ } } + skb_abort_seq_read(&seq); + conn->rxdata_octets += consumed; + return consumed; - if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV && - tcp_conn->in.copy) { - debug_tcp("data_recv offset %d copy %d\n", - tcp_conn->in.offset, tcp_conn->in.copy); - - rc = iscsi_data_recv(conn); - if (rc) { - if (rc == -EAGAIN) - goto again; - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return 0; - } - - if (tcp_conn->in.padding) - tcp_conn->in_progress = IN_PROGRESS_PAD_RECV; - else if (conn->datadgst_en) - tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV; - else - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; - tcp_conn->data_copied = 0; - } - - if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV && - tcp_conn->in.copy) { - int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied, - tcp_conn->in.copy); - - tcp_conn->in.copy -= copylen; - tcp_conn->in.offset += copylen; - tcp_conn->data_copied += copylen; - - if (tcp_conn->data_copied != tcp_conn->in.padding) - tcp_conn->in_progress = IN_PROGRESS_PAD_RECV; - else if (conn->datadgst_en) - tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV; - else - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; - tcp_conn->data_copied = 0; - } - - debug_tcp("f, processed %d from out of %d padding %d\n", - tcp_conn->in.offset - offset, (int)len, tcp_conn->in.padding); - BUG_ON(tcp_conn->in.offset - offset > len); - - if (tcp_conn->in.offset - offset != len) { - debug_tcp("continue to process %d bytes\n", - (int)len - (tcp_conn->in.offset - offset)); - goto more; - } - -nomore: - processed = tcp_conn->in.offset - offset; - BUG_ON(processed == 0); - return processed; - -again: - processed = tcp_conn->in.offset - offset; - debug_tcp("c, processed %d from out of %d rd_desc_cnt %d\n", - processed, (int)len, (int)rd_desc->count); - BUG_ON(processed == 0); - BUG_ON(processed > len); - - conn->rxdata_octets += processed; - return processed; +error: + debug_tcp("Error receiving PDU, errno=%d\n", rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + return 0; } static void iscsi_tcp_data_ready(struct sock *sk, int flag) { struct iscsi_conn *conn = sk->sk_user_data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; read_descriptor_t rd_desc; read_lock(&sk->sk_callback_lock); /* - * Use rd_desc to pass 'conn' to iscsi_tcp_data_recv. + * Use rd_desc to pass 'conn' to iscsi_tcp_recv. * We set count to 1 because we want the network layer to - * hand us all the skbs that are available. iscsi_tcp_data_recv + * hand us all the skbs that are available. iscsi_tcp_recv * handled pdus that cross buffers or pdus that still need data. */ rd_desc.arg.data = conn; rd_desc.count = 1; - tcp_read_sock(sk, &rd_desc, iscsi_tcp_data_recv); + tcp_read_sock(sk, &rd_desc, iscsi_tcp_recv); read_unlock(&sk->sk_callback_lock); + + /* If we had to (atomically) map a highmem page, + * unmap it now. */ + iscsi_tcp_segment_unmap(&tcp_conn->in.segment); } static void @@ -1077,121 +1079,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn) } /** - * iscsi_send - generic send routine - * @sk: kernel's socket - * @buf: buffer to write from - * @size: actual size to write - * @flags: socket's flags - */ -static inline int -iscsi_send(struct iscsi_conn *conn, struct iscsi_buf *buf, int size, int flags) + * iscsi_xmit - TCP transmit + **/ +static int +iscsi_xmit(struct iscsi_conn *conn) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct socket *sk = tcp_conn->sock; - int offset = buf->sg.offset + buf->sent, res; + struct iscsi_segment *segment = &tcp_conn->out.segment; + unsigned int consumed = 0; + int rc = 0; - /* - * if we got use_sg=0 or are sending something we kmallocd - * then we did not have to do kmap (kmap returns page_address) - * - * if we got use_sg > 0, but had to drop down, we do not - * set clustering so this should only happen for that - * slab case. - */ - if (buf->use_sendmsg) - res = sock_no_sendpage(sk, sg_page(&buf->sg), offset, size, flags); - else - res = tcp_conn->sendpage(sk, sg_page(&buf->sg), offset, size, flags); - - if (res >= 0) { - conn->txdata_octets += res; - buf->sent += res; - return res; + while (1) { + rc = iscsi_tcp_xmit_segment(tcp_conn, segment); + if (rc < 0) + goto error; + if (rc == 0) + break; + + consumed += rc; + + if (segment->total_copied >= segment->total_size) { + if (segment->done != NULL) { + rc = segment->done(tcp_conn, segment); + if (rc < 0) + goto error; + } + } } - tcp_conn->sendpage_failures_cnt++; - if (res == -EAGAIN) - res = -ENOBUFS; - else - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return res; + debug_tcp("xmit %d bytes\n", consumed); + + conn->txdata_octets += consumed; + return consumed; + +error: + /* Transmit error. We could initiate error recovery + * here. */ + debug_tcp("Error sending PDU, errno=%d\n", rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + return rc; } /** - * iscsi_sendhdr - send PDU Header via tcp_sendpage() - * @conn: iscsi connection - * @buf: buffer to write from - * @datalen: lenght of data to be sent after the header - * - * Notes: - * (Tx, Fast Path) - **/ + * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit + */ static inline int -iscsi_sendhdr(struct iscsi_conn *conn, struct iscsi_buf *buf, int datalen) +iscsi_tcp_xmit_qlen(struct iscsi_conn *conn) { - int flags = 0; /* MSG_DONTWAIT; */ - int res, size; - - size = buf->sg.length - buf->sent; - BUG_ON(buf->sent + size > buf->sg.length); - if (buf->sent + size != buf->sg.length || datalen) - flags |= MSG_MORE; - - res = iscsi_send(conn, buf, size, flags); - debug_tcp("sendhdr %d bytes, sent %d res %d\n", size, buf->sent, res); - if (res >= 0) { - if (size != res) - return -EAGAIN; - return 0; - } + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct iscsi_segment *segment = &tcp_conn->out.segment; - return res; + return segment->total_copied - segment->total_size; } -/** - * iscsi_sendpage - send one page of iSCSI Data-Out. - * @conn: iscsi connection - * @buf: buffer to write from - * @count: remaining data - * @sent: number of bytes sent - * - * Notes: - * (Tx, Fast Path) - **/ static inline int -iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf, - int *count, int *sent) +iscsi_tcp_flush(struct iscsi_conn *conn) { - int flags = 0; /* MSG_DONTWAIT; */ - int res, size; - - size = buf->sg.length - buf->sent; - BUG_ON(buf->sent + size > buf->sg.length); - if (size > *count) - size = *count; - if (buf->sent + size != buf->sg.length || *count != size) - flags |= MSG_MORE; - - res = iscsi_send(conn, buf, size, flags); - debug_tcp("sendpage: %d bytes, sent %d left %d sent %d res %d\n", - size, buf->sent, *count, *sent, res); - if (res >= 0) { - *count -= res; - *sent += res; - if (size != res) + int rc; + + while (iscsi_tcp_xmit_qlen(conn)) { + rc = iscsi_xmit(conn); + if (rc == 0) return -EAGAIN; - return 0; + if (rc < 0) + return rc; } - return res; + return 0; } -static inline void -iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_tcp_cmd_task *tcp_ctask) +/* + * This is called when we're done sending the header. + * Simply copy the data_segment to the send segment, and return. + */ +static int +iscsi_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) +{ + tcp_conn->out.segment = tcp_conn->out.data_segment; + debug_tcp("Header done. Next segment size %u total_size %u\n", + tcp_conn->out.segment.size, tcp_conn->out.segment.total_size); + return 0; +} + +static void +iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) { - crypto_hash_init(&tcp_conn->tx_hash); - tcp_ctask->digest_count = 4; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn, + conn->hdrdgst_en? ", digest enabled" : ""); + + /* Clear the data segment - needs to be filled in by the + * caller using iscsi_tcp_send_data_prep() */ + memset(&tcp_conn->out.data_segment, 0, sizeof(struct iscsi_segment)); + + /* If header digest is enabled, compute the CRC and + * place the digest into the same buffer. We make + * sure that both iscsi_tcp_ctask and mtask have + * sufficient room. + */ + if (conn->hdrdgst_en) { + iscsi_tcp_dgst_header(&tcp_conn->tx_hash, hdr, hdrlen, + hdr + hdrlen); + hdrlen += ISCSI_DIGEST_SIZE; + } + + /* Remember header pointer for later, when we need + * to decide whether there's a payload to go along + * with the header. */ + tcp_conn->out.hdr = hdr; + + iscsi_segment_init_linear(&tcp_conn->out.segment, hdr, hdrlen, + iscsi_tcp_send_hdr_done, NULL); +} + +/* + * Prepare the send buffer for the payload data. + * Padding and checksumming will all be taken care + * of by the iscsi_segment routines. + */ +static int +iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, + unsigned int count, unsigned int offset, + unsigned int len) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct hash_desc *tx_hash = NULL; + unsigned int hdr_spec_len; + + debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__, + tcp_conn, offset, len, + conn->datadgst_en? ", digest enabled" : ""); + + /* Make sure the datalen matches what the caller + said he would send. */ + hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength); + WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); + + if (conn->datadgst_en) + tx_hash = &tcp_conn->tx_hash; + + return iscsi_segment_seek_sg(&tcp_conn->out.data_segment, + sg, count, offset, len, + NULL, tx_hash); +} + +static void +iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, + size_t len) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct hash_desc *tx_hash = NULL; + unsigned int hdr_spec_len; + + debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len, + conn->datadgst_en? ", digest enabled" : ""); + + /* Make sure the datalen matches what the caller + said he would send. */ + hdr_spec_len = ntoh24(tcp_conn->out.hdr->dlength); + WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); + + if (conn->datadgst_en) + tx_hash = &tcp_conn->tx_hash; + + iscsi_segment_init_linear(&tcp_conn->out.data_segment, + data, len, NULL, tx_hash); } /** @@ -1207,12 +1261,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn, * * Called under connection lock. **/ -static void +static int iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, - struct iscsi_r2t_info *r2t, int left) + struct iscsi_r2t_info *r2t) { struct iscsi_data *hdr; - int new_offset; + int new_offset, left; + + BUG_ON(r2t->data_length - r2t->sent < 0); + left = r2t->data_length - r2t->sent; + if (left == 0) + return 0; hdr = &r2t->dtask.hdr; memset(hdr, 0, sizeof(struct iscsi_data)); @@ -1233,43 +1292,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, r2t->data_count = left; hdr->flags = ISCSI_FLAG_CMD_FINAL; } - conn->dataout_pdus_cnt++; - - iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr, - sizeof(struct iscsi_hdr)); - - if (iscsi_buf_left(&r2t->sendbuf)) - return; - - iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg); - r2t->sg += 1; -} -static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask, - unsigned long len) -{ - tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1); - if (!tcp_ctask->pad_count) - return; - - tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count; - debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count); - set_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate); + conn->dataout_pdus_cnt++; + return 1; } /** - * iscsi_tcp_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands + * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands * @conn: iscsi connection * @ctask: scsi command task * @sc: scsi command **/ -static void -iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) +static int +iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + struct iscsi_conn *conn = ctask->conn; + struct scsi_cmnd *sc = ctask->sc; + int err; BUG_ON(__kfifo_len(tcp_ctask->r2tqueue)); - tcp_ctask->xmstate = 1 << XMSTATE_BIT_CMD_HDR_INIT; + tcp_ctask->sent = 0; + tcp_ctask->exp_datasn = 0; + + /* Prepare PDU, optionally w/ immediate data */ + debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n", + conn->id, ctask->itt, ctask->imm_count, + ctask->unsol_count); + iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len); + + if (!ctask->imm_count) + return 0; + + /* If we have immediate data, attach a payload */ + err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc), + 0, ctask->imm_count); + if (err) + return err; + tcp_ctask->sent += ctask->imm_count; + ctask->imm_count = 0; + return 0; } /** @@ -1281,484 +1343,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) * The function can return -EAGAIN in which case caller must * call it again later, or recover. '0' return code means successful * xmit. - * - * Management xmit state machine consists of these states: - * XMSTATE_BIT_IMM_HDR_INIT - calculate digest of PDU Header - * XMSTATE_BIT_IMM_HDR - PDU Header xmit in progress - * XMSTATE_BIT_IMM_DATA - PDU Data xmit in progress - * XMSTATE_VALUE_IDLE - management PDU is done **/ static int iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) { - struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; int rc; - debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n", - conn->id, tcp_mtask->xmstate, mtask->itt); - - if (test_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate)) { - iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, - sizeof(struct iscsi_hdr)); - - if (mtask->data_count) { - set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate); - iscsi_buf_init_iov(&tcp_mtask->sendbuf, - (char*)mtask->data, - mtask->data_count); - } - - if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && - conn->stop_stage != STOP_CONN_RECOVER && - conn->hdrdgst_en) - iscsi_hdr_digest(conn, &tcp_mtask->headbuf, - (u8*)tcp_mtask->hdrext); - - tcp_mtask->sent = 0; - clear_bit(XMSTATE_BIT_IMM_HDR_INIT, &tcp_mtask->xmstate); - set_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate); - } - - if (test_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate)) { - rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf, - mtask->data_count); - if (rc) - return rc; - clear_bit(XMSTATE_BIT_IMM_HDR, &tcp_mtask->xmstate); - } - - if (test_and_clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate)) { - BUG_ON(!mtask->data_count); - /* FIXME: implement. - * Virtual buffer could be spreaded across multiple pages... - */ - do { - int rc; - - rc = iscsi_sendpage(conn, &tcp_mtask->sendbuf, - &mtask->data_count, &tcp_mtask->sent); - if (rc) { - set_bit(XMSTATE_BIT_IMM_DATA, &tcp_mtask->xmstate); - return rc; - } - } while (mtask->data_count); - } + /* Flush any pending data first. */ + rc = iscsi_tcp_flush(conn); + if (rc < 0) + return rc; - BUG_ON(tcp_mtask->xmstate != XMSTATE_VALUE_IDLE); if (mtask->hdr->itt == RESERVED_ITT) { struct iscsi_session *session = conn->session; spin_lock_bh(&session->lock); - list_del(&conn->mtask->running); - __kfifo_put(session->mgmtpool.queue, (void*)&conn->mtask, - sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); spin_unlock_bh(&session->lock); } + return 0; } +/* + * iscsi_tcp_ctask_xmit - xmit normal PDU task + * @conn: iscsi connection + * @ctask: iscsi command task + * + * We're expected to return 0 when everything was transmitted succesfully, + * -EAGAIN if there's still data in the queue, or != 0 for any other kind + * of error. + */ static int -iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { - struct scsi_cmnd *sc = ctask->sc; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + struct scsi_cmnd *sc = ctask->sc; int rc = 0; - if (test_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate)) { - tcp_ctask->sent = 0; - tcp_ctask->sg_count = 0; - tcp_ctask->exp_datasn = 0; - - if (sc->sc_data_direction == DMA_TO_DEVICE) { - struct scatterlist *sg = scsi_sglist(sc); - - iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg); - tcp_ctask->sg = sg + 1; - tcp_ctask->bad_sg = sg + scsi_sg_count(sc); - - debug_scsi("cmd [itt 0x%x total %d imm_data %d " - "unsol count %d, unsol offset %d]\n", - ctask->itt, scsi_bufflen(sc), - ctask->imm_count, ctask->unsol_count, - ctask->unsol_offset); - } - - iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr, - sizeof(struct iscsi_hdr)); - - if (conn->hdrdgst_en) - iscsi_hdr_digest(conn, &tcp_ctask->headbuf, - (u8*)tcp_ctask->hdrext); - clear_bit(XMSTATE_BIT_CMD_HDR_INIT, &tcp_ctask->xmstate); - set_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate); - } - - if (test_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate)) { - rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count); - if (rc) - return rc; - clear_bit(XMSTATE_BIT_CMD_HDR_XMIT, &tcp_ctask->xmstate); - - if (sc->sc_data_direction != DMA_TO_DEVICE) - return 0; - - if (ctask->imm_count) { - set_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate); - iscsi_set_padding(tcp_ctask, ctask->imm_count); - - if (ctask->conn->datadgst_en) { - iscsi_data_digest_init(ctask->conn->dd_data, - tcp_ctask); - tcp_ctask->immdigest = 0; - } - } - - if (ctask->unsol_count) { - set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate); - set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate); - } - } - return rc; -} - -static int -iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - int sent = 0, rc; - - if (test_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate)) { - iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, - tcp_ctask->pad_count); - if (conn->datadgst_en) - crypto_hash_update(&tcp_conn->tx_hash, - &tcp_ctask->sendbuf.sg, - tcp_ctask->sendbuf.sg.length); - } else if (!test_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate)) - return 0; - - clear_bit(XMSTATE_BIT_W_PAD, &tcp_ctask->xmstate); - clear_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate); - debug_scsi("sending %d pad bytes for itt 0x%x\n", - tcp_ctask->pad_count, ctask->itt); - rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count, - &sent); - if (rc) { - debug_scsi("padding send failed %d\n", rc); - set_bit(XMSTATE_BIT_W_RESEND_PAD, &tcp_ctask->xmstate); - } - return rc; -} - -static int -iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, - struct iscsi_buf *buf, uint32_t *digest) -{ - struct iscsi_tcp_cmd_task *tcp_ctask; - struct iscsi_tcp_conn *tcp_conn; - int rc, sent = 0; - - if (!conn->datadgst_en) - return 0; - - tcp_ctask = ctask->dd_data; - tcp_conn = conn->dd_data; - - if (!test_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate)) { - crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest); - iscsi_buf_init_iov(buf, (char*)digest, 4); - } - clear_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate); - - rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent); - if (!rc) - debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest, - ctask->itt); - else { - debug_scsi("sending digest 0x%x failed for itt 0x%x!\n", - *digest, ctask->itt); - set_bit(XMSTATE_BIT_W_RESEND_DATA_DIGEST, &tcp_ctask->xmstate); - } - return rc; -} - -static int -iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf, - struct scatterlist **sg, int *sent, int *count, - struct iscsi_buf *digestbuf, uint32_t *digest) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct iscsi_conn *conn = ctask->conn; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - int rc, buf_sent, offset; - - while (*count) { - buf_sent = 0; - offset = sendbuf->sent; - - rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent); - *sent = *sent + buf_sent; - if (buf_sent && conn->datadgst_en) - partial_sg_digest_update(&tcp_conn->tx_hash, - &sendbuf->sg, sendbuf->sg.offset + offset, - buf_sent); - if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) { - iscsi_buf_init_sg(sendbuf, *sg); - *sg = *sg + 1; - } - - if (rc) - return rc; - } - - rc = iscsi_send_padding(conn, ctask); - if (rc) +flush: + /* Flush any pending data first. */ + rc = iscsi_tcp_flush(conn); + if (rc < 0) return rc; - return iscsi_send_digest(conn, ctask, digestbuf, digest); -} - -static int -iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct iscsi_data_task *dtask; - int rc; - - set_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate); - if (test_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate)) { - dtask = &tcp_ctask->unsol_dtask; - - iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr); - iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr, - sizeof(struct iscsi_hdr)); - if (conn->hdrdgst_en) - iscsi_hdr_digest(conn, &tcp_ctask->headbuf, - (u8*)dtask->hdrext); - - clear_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate); - iscsi_set_padding(tcp_ctask, ctask->data_count); - } - - rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count); - if (rc) { - clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate); - set_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate); - return rc; - } + /* Are we done already? */ + if (sc->sc_data_direction != DMA_TO_DEVICE) + return 0; - if (conn->datadgst_en) { - dtask = &tcp_ctask->unsol_dtask; - iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask); - dtask->digest = 0; - } + if (ctask->unsol_count != 0) { + struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr; - debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n", - ctask->itt, ctask->unsol_count, tcp_ctask->sent); - return 0; -} + /* Prepare a header for the unsolicited PDU. + * The amount of data we want to send will be + * in ctask->data_count. + * FIXME: return the data count instead. + */ + iscsi_prep_unsolicit_data_pdu(ctask, hdr); -static int -iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - int rc; + debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", + ctask->itt, tcp_ctask->sent, ctask->data_count); - if (test_and_clear_bit(XMSTATE_BIT_UNS_HDR, &tcp_ctask->xmstate)) { - BUG_ON(!ctask->unsol_count); -send_hdr: - rc = iscsi_send_unsol_hdr(conn, ctask); + iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); + rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), + scsi_sg_count(sc), + tcp_ctask->sent, + ctask->data_count); if (rc) - return rc; - } - - if (test_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate)) { - struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask; - int start = tcp_ctask->sent; + goto fail; + tcp_ctask->sent += ctask->data_count; + ctask->unsol_count -= ctask->data_count; + goto flush; + } else { + struct iscsi_session *session = conn->session; + struct iscsi_r2t_info *r2t; - rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg, - &tcp_ctask->sent, &ctask->data_count, - &dtask->digestbuf, &dtask->digest); - ctask->unsol_count -= tcp_ctask->sent - start; - if (rc) - return rc; - clear_bit(XMSTATE_BIT_UNS_DATA, &tcp_ctask->xmstate); - /* - * Done with the Data-Out. Next, check if we need - * to send another unsolicited Data-Out. + /* All unsolicited PDUs sent. Check for solicited PDUs. */ - if (ctask->unsol_count) { - debug_scsi("sending more uns\n"); - set_bit(XMSTATE_BIT_UNS_INIT, &tcp_ctask->xmstate); - goto send_hdr; + spin_lock_bh(&session->lock); + r2t = tcp_ctask->r2t; + if (r2t != NULL) { + /* Continue with this R2T? */ + if (!iscsi_solicit_data_cont(conn, ctask, r2t)) { + debug_scsi(" done with r2t %p\n", r2t); + + __kfifo_put(tcp_ctask->r2tpool.queue, + (void*)&r2t, sizeof(void*)); + tcp_ctask->r2t = r2t = NULL; + } } - } - return 0; -} - -static int iscsi_send_sol_pdu(struct iscsi_conn *conn, - struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct iscsi_session *session = conn->session; - struct iscsi_r2t_info *r2t; - struct iscsi_data_task *dtask; - int left, rc; - if (test_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate)) { - if (!tcp_ctask->r2t) { - spin_lock_bh(&session->lock); + if (r2t == NULL) { __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t, sizeof(void*)); - spin_unlock_bh(&session->lock); + r2t = tcp_ctask->r2t; } -send_hdr: - r2t = tcp_ctask->r2t; - dtask = &r2t->dtask; - - if (conn->hdrdgst_en) - iscsi_hdr_digest(conn, &r2t->headbuf, - (u8*)dtask->hdrext); - clear_bit(XMSTATE_BIT_SOL_HDR_INIT, &tcp_ctask->xmstate); - set_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate); - } - - if (test_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate)) { - r2t = tcp_ctask->r2t; - dtask = &r2t->dtask; - - rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count); - if (rc) - return rc; - clear_bit(XMSTATE_BIT_SOL_HDR, &tcp_ctask->xmstate); - set_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate); + spin_unlock_bh(&session->lock); - if (conn->datadgst_en) { - iscsi_data_digest_init(conn->dd_data, tcp_ctask); - dtask->digest = 0; + /* Waiting for more R2Ts to arrive. */ + if (r2t == NULL) { + debug_tcp("no R2Ts yet\n"); + return 0; } - iscsi_set_padding(tcp_ctask, r2t->data_count); - debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n", - r2t->solicit_datasn - 1, ctask->itt, r2t->data_count, - r2t->sent); - } + debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", + r2t, r2t->solicit_datasn - 1, ctask->itt, + r2t->data_offset + r2t->sent, r2t->data_count); - if (test_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate)) { - r2t = tcp_ctask->r2t; - dtask = &r2t->dtask; + iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, + sizeof(struct iscsi_hdr)); - rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg, - &r2t->sent, &r2t->data_count, - &dtask->digestbuf, &dtask->digest); + rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), + scsi_sg_count(sc), + r2t->data_offset + r2t->sent, + r2t->data_count); if (rc) - return rc; - clear_bit(XMSTATE_BIT_SOL_DATA, &tcp_ctask->xmstate); - - /* - * Done with this Data-Out. Next, check if we have - * to send another Data-Out for this R2T. - */ - BUG_ON(r2t->data_length - r2t->sent < 0); - left = r2t->data_length - r2t->sent; - if (left) { - iscsi_solicit_data_cont(conn, ctask, r2t, left); - goto send_hdr; - } - - /* - * Done with this R2T. Check if there are more - * outstanding R2Ts ready to be processed. - */ - spin_lock_bh(&session->lock); - tcp_ctask->r2t = NULL; - __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, - sizeof(void*))) { - tcp_ctask->r2t = r2t; - spin_unlock_bh(&session->lock); - goto send_hdr; - } - spin_unlock_bh(&session->lock); + goto fail; + tcp_ctask->sent += r2t->data_count; + r2t->sent += r2t->data_count; + goto flush; } return 0; -} - -/** - * iscsi_tcp_ctask_xmit - xmit normal PDU task - * @conn: iscsi connection - * @ctask: iscsi command task - * - * Notes: - * The function can return -EAGAIN in which case caller must - * call it again later, or recover. '0' return code means successful - * xmit. - * The function is devided to logical helpers (above) for the different - * xmit stages. - * - *iscsi_send_cmd_hdr() - * XMSTATE_BIT_CMD_HDR_INIT - prepare Header and Data buffers Calculate - * Header Digest - * XMSTATE_BIT_CMD_HDR_XMIT - Transmit header in progress - * - *iscsi_send_padding - * XMSTATE_BIT_W_PAD - Prepare and send pading - * XMSTATE_BIT_W_RESEND_PAD - retry send pading - * - *iscsi_send_digest - * XMSTATE_BIT_W_RESEND_DATA_DIGEST - Finalize and send Data Digest - * XMSTATE_BIT_W_RESEND_DATA_DIGEST - retry sending digest - * - *iscsi_send_unsol_hdr - * XMSTATE_BIT_UNS_INIT - prepare un-solicit data header and digest - * XMSTATE_BIT_UNS_HDR - send un-solicit header - * - *iscsi_send_unsol_pdu - * XMSTATE_BIT_UNS_DATA - send un-solicit data in progress - * - *iscsi_send_sol_pdu - * XMSTATE_BIT_SOL_HDR_INIT - solicit data header and digest initialize - * XMSTATE_BIT_SOL_HDR - send solicit header - * XMSTATE_BIT_SOL_DATA - send solicit data - * - *iscsi_tcp_ctask_xmit - * XMSTATE_BIT_IMM_DATA - xmit managment data (??) - **/ -static int -iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - int rc = 0; - - debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n", - conn->id, tcp_ctask->xmstate, ctask->itt); - - rc = iscsi_send_cmd_hdr(conn, ctask); - if (rc) - return rc; - if (ctask->sc->sc_data_direction != DMA_TO_DEVICE) - return 0; - - if (test_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate)) { - rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg, - &tcp_ctask->sent, &ctask->imm_count, - &tcp_ctask->immbuf, &tcp_ctask->immdigest); - if (rc) - return rc; - clear_bit(XMSTATE_BIT_IMM_DATA, &tcp_ctask->xmstate); - } - - rc = iscsi_send_unsol_pdu(conn, ctask); - if (rc) - return rc; - - rc = iscsi_send_sol_pdu(conn, ctask); - if (rc) - return rc; - - return rc; +fail: + iscsi_conn_failure(conn, rc); + return -EIO; } static struct iscsi_cls_conn * @@ -1784,9 +1492,6 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->dd_data = tcp_conn; tcp_conn->iscsi_conn = conn; - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; - /* initial operational parameters */ - tcp_conn->hdr_size = sizeof(struct iscsi_hdr); tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); @@ -1863,11 +1568,9 @@ static void iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) { struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; iscsi_conn_stop(cls_conn, flag); iscsi_tcp_release_conn(conn); - tcp_conn->hdr_size = sizeof(struct iscsi_hdr); } static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, @@ -1967,7 +1670,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* * set receive state machine into initial state */ - tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; + iscsi_tcp_hdr_recv_prep(tcp_conn); return 0; free_socket: @@ -1977,10 +1680,17 @@ free_socket: /* called with host lock */ static void -iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) +iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) { - struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; - tcp_mtask->xmstate = 1 << XMSTATE_BIT_IMM_HDR_INIT; + debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt); + + /* Prepare PDU, optionally w/ immediate data */ + iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr)); + + /* If we have immediate data, attach a payload */ + if (mtask->data_count) + iscsi_tcp_send_linear_data_prepare(conn, mtask->data, + mtask->data_count); } static int @@ -2003,8 +1713,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) */ /* R2T pool */ - if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, - (void***)&tcp_ctask->r2ts, + if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL, sizeof(struct iscsi_r2t_info))) { goto r2t_alloc_fail; } @@ -2013,8 +1722,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) tcp_ctask->r2tqueue = kfifo_alloc( session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) { - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); goto r2t_alloc_fail; } } @@ -2027,8 +1735,7 @@ r2t_alloc_fail: struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); } return -ENOMEM; } @@ -2043,8 +1750,7 @@ iscsi_r2tpool_free(struct iscsi_session *session) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); - iscsi_pool_free(&tcp_ctask->r2tpool, - (void**)tcp_ctask->r2ts); + iscsi_pool_free(&tcp_ctask->r2tpool); } } @@ -2060,9 +1766,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, switch(param) { case ISCSI_PARAM_HDRDGST_EN: iscsi_set_param(cls_conn, param, buf, buflen); - tcp_conn->hdr_size = sizeof(struct iscsi_hdr); - if (conn->hdrdgst_en) - tcp_conn->hdr_size += sizeof(__u32); break; case ISCSI_PARAM_DATADGST_EN: iscsi_set_param(cls_conn, param, buf, buflen); @@ -2071,12 +1774,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, break; case ISCSI_PARAM_MAX_R2T: sscanf(buf, "%d", &value); - if (session->max_r2t == roundup_pow_of_two(value)) + if (value <= 0 || !is_power_of_2(value)) + return -EINVAL; + if (session->max_r2t == value) break; iscsi_r2tpool_free(session); iscsi_set_param(cls_conn, param, buf, buflen); - if (session->max_r2t & (session->max_r2t - 1)) - session->max_r2t = roundup_pow_of_two(session->max_r2t); if (iscsi_r2tpool_alloc(session)) return -ENOMEM; break; @@ -2183,14 +1886,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - ctask->hdr = &tcp_ctask->hdr; + ctask->hdr = &tcp_ctask->hdr.cmd_hdr; + ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE; } for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; - mtask->hdr = &tcp_mtask->hdr; + mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr; } if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session))) @@ -2222,10 +1926,11 @@ static struct scsi_host_template iscsi_sht = { .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, - .sg_tablesize = ISCSI_SG_TABLESIZE, + .sg_tablesize = 4096, .max_sectors = 0xFFFF, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, .slave_configure = iscsi_tcp_slave_configure, @@ -2257,14 +1962,17 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | - ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN, + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | + ISCSI_PING_TMO | ISCSI_RECV_TMO, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, - .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN, + .max_cmd_len = 16, /* session management */ .create_session = iscsi_tcp_session_create, .destroy_session = iscsi_tcp_session_destroy, @@ -2283,8 +1991,8 @@ static struct iscsi_transport iscsi_tcp_transport = { /* IO */ .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, - .init_cmd_task = iscsi_tcp_cmd_init, - .init_mgmt_task = iscsi_tcp_mgmt_init, + .init_cmd_task = iscsi_tcp_ctask_init, + .init_mgmt_task = iscsi_tcp_mtask_init, .xmit_cmd_task = iscsi_tcp_ctask_xmit, .xmit_mgmt_task = iscsi_tcp_mtask_xmit, .cleanup_cmd_task = iscsi_tcp_cleanup_ctask, diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 68c36cc8997e..ed0b991d1e72 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -24,71 +24,61 @@ #include <scsi/libiscsi.h> -/* Socket's Receive state machine */ -#define IN_PROGRESS_WAIT_HEADER 0x0 -#define IN_PROGRESS_HEADER_GATHER 0x1 -#define IN_PROGRESS_DATA_RECV 0x2 -#define IN_PROGRESS_DDIGEST_RECV 0x3 -#define IN_PROGRESS_PAD_RECV 0x4 - -/* xmit state machine */ -#define XMSTATE_VALUE_IDLE 0 -#define XMSTATE_BIT_CMD_HDR_INIT 0 -#define XMSTATE_BIT_CMD_HDR_XMIT 1 -#define XMSTATE_BIT_IMM_HDR 2 -#define XMSTATE_BIT_IMM_DATA 3 -#define XMSTATE_BIT_UNS_INIT 4 -#define XMSTATE_BIT_UNS_HDR 5 -#define XMSTATE_BIT_UNS_DATA 6 -#define XMSTATE_BIT_SOL_HDR 7 -#define XMSTATE_BIT_SOL_DATA 8 -#define XMSTATE_BIT_W_PAD 9 -#define XMSTATE_BIT_W_RESEND_PAD 10 -#define XMSTATE_BIT_W_RESEND_DATA_DIGEST 11 -#define XMSTATE_BIT_IMM_HDR_INIT 12 -#define XMSTATE_BIT_SOL_HDR_INIT 13 - -#define ISCSI_PAD_LEN 4 -#define ISCSI_SG_TABLESIZE SG_ALL -#define ISCSI_TCP_MAX_CMD_LEN 16 - struct crypto_hash; struct socket; +struct iscsi_tcp_conn; +struct iscsi_segment; + +typedef int iscsi_segment_done_fn_t(struct iscsi_tcp_conn *, + struct iscsi_segment *); + +struct iscsi_segment { + unsigned char *data; + unsigned int size; + unsigned int copied; + unsigned int total_size; + unsigned int total_copied; + + struct hash_desc *hash; + unsigned char recv_digest[ISCSI_DIGEST_SIZE]; + unsigned char digest[ISCSI_DIGEST_SIZE]; + unsigned int digest_len; + + struct scatterlist *sg; + void *sg_mapped; + unsigned int sg_offset; + + iscsi_segment_done_fn_t *done; +}; /* Socket connection recieve helper */ struct iscsi_tcp_recv { struct iscsi_hdr *hdr; - struct sk_buff *skb; - int offset; - int len; - int hdr_offset; - int copy; - int copied; - int padding; - struct iscsi_cmd_task *ctask; /* current cmd in progress */ + struct iscsi_segment segment; + + /* Allocate buffer for BHS + AHS */ + uint32_t hdr_buf[64]; /* copied and flipped values */ int datalen; - int datadgst; - char zero_copy_hdr; +}; + +/* Socket connection send helper */ +struct iscsi_tcp_send { + struct iscsi_hdr *hdr; + struct iscsi_segment segment; + struct iscsi_segment data_segment; }; struct iscsi_tcp_conn { struct iscsi_conn *iscsi_conn; struct socket *sock; - struct iscsi_hdr hdr; /* header placeholder */ - char hdrext[4*sizeof(__u16) + - sizeof(__u32)]; - int data_copied; int stop_stage; /* conn_stop() flag: * * stop to recover, * * stop to terminate */ - /* iSCSI connection-wide sequencing */ - int hdr_size; /* PDU header size */ - /* control data */ struct iscsi_tcp_recv in; /* TCP receive context */ - int in_progress; /* connection state machine */ + struct iscsi_tcp_send out; /* TCP send context */ /* old values for socket callbacks */ void (*old_data_ready)(struct sock *, int); @@ -103,29 +93,19 @@ struct iscsi_tcp_conn { uint32_t sendpage_failures_cnt; uint32_t discontiguous_hdr_cnt; - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); -}; + int error; -struct iscsi_buf { - struct scatterlist sg; - unsigned int sent; - char use_sendmsg; + ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); }; struct iscsi_data_task { struct iscsi_data hdr; /* PDU */ - char hdrext[sizeof(__u32)]; /* Header-Digest */ - struct iscsi_buf digestbuf; /* digest buffer */ - uint32_t digest; /* data digest */ + char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ }; struct iscsi_tcp_mgmt_task { struct iscsi_hdr hdr; - char hdrext[sizeof(__u32)]; /* Header-Digest */ - unsigned long xmstate; /* mgmt xmit progress */ - struct iscsi_buf headbuf; /* header buffer */ - struct iscsi_buf sendbuf; /* in progress buffer */ - int sent; + char hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */ }; struct iscsi_r2t_info { @@ -133,38 +113,26 @@ struct iscsi_r2t_info { __be32 exp_statsn; /* copied from R2T */ uint32_t data_length; /* copied from R2T */ uint32_t data_offset; /* copied from R2T */ - struct iscsi_buf headbuf; /* Data-Out Header Buffer */ - struct iscsi_buf sendbuf; /* Data-Out in progress buffer*/ int sent; /* R2T sequence progress */ int data_count; /* DATA-Out payload progress */ - struct scatterlist *sg; /* per-R2T SG list */ int solicit_datasn; - struct iscsi_data_task dtask; /* which data task */ + struct iscsi_data_task dtask; /* Data-Out header buf */ }; struct iscsi_tcp_cmd_task { - struct iscsi_cmd hdr; - char hdrext[4*sizeof(__u16)+ /* AHS */ - sizeof(__u32)]; /* HeaderDigest */ - char pad[ISCSI_PAD_LEN]; - int pad_count; /* padded bytes */ - struct iscsi_buf headbuf; /* header buf (xmit) */ - struct iscsi_buf sendbuf; /* in progress buffer*/ - unsigned long xmstate; /* xmit xtate machine */ + struct iscsi_hdr_buff { + struct iscsi_cmd cmd_hdr; + char hdrextbuf[ISCSI_MAX_AHS_SIZE + + ISCSI_DIGEST_SIZE]; + } hdr; + int sent; - struct scatterlist *sg; /* per-cmd SG list */ - struct scatterlist *bad_sg; /* assert statement */ - int sg_count; /* SG's to process */ - uint32_t exp_datasn; /* expected target's R2TSN/DataSN */ + uint32_t exp_datasn; /* expected target's R2TSN/DataSN */ int data_offset; - struct iscsi_r2t_info *r2t; /* in progress R2T */ - struct iscsi_queue r2tpool; + struct iscsi_r2t_info *r2t; /* in progress R2T */ + struct iscsi_pool r2tpool; struct kfifo *r2tqueue; - struct iscsi_r2t_info **r2ts; - int digest_count; - uint32_t immdigest; /* for imm data */ - struct iscsi_buf immbuf; /* for imm data digest */ - struct iscsi_data_task unsol_dtask; /* unsol data task */ + struct iscsi_data_task unsol_dtask; /* Data-Out header buf */ }; #endif /* ISCSI_H */ diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8b57af5baaec..553168ae44f1 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -24,6 +24,7 @@ #include <linux/types.h> #include <linux/kfifo.h> #include <linux/delay.h> +#include <linux/log2.h> #include <asm/unaligned.h> #include <net/tcp.h> #include <scsi/scsi_cmnd.h> @@ -86,7 +87,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) * xmit thread */ if (!list_empty(&session->leadconn->xmitqueue) || - __kfifo_len(session->leadconn->mgmtqueue)) + !list_empty(&session->leadconn->mgmtqueue)) scsi_queue_work(session->host, &session->leadconn->xmitwork); } @@ -122,6 +123,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, } EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); +static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) +{ + unsigned exp_len = ctask->hdr_len + len; + + if (exp_len > ctask->hdr_max) { + WARN_ON(1); + return -EINVAL; + } + + WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ + ctask->hdr_len = exp_len; + return 0; +} + /** * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu * @ctask: iscsi cmd task @@ -129,27 +144,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set * fields like dlength or final based on how much data it sends */ -static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) +static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) { struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; struct iscsi_cmd *hdr = ctask->hdr; struct scsi_cmnd *sc = ctask->sc; + unsigned hdrlength; + int rc; - hdr->opcode = ISCSI_OP_SCSI_CMD; - hdr->flags = ISCSI_ATTR_SIMPLE; - int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); - hdr->itt = build_itt(ctask->itt, conn->id, session->age); - hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); - hdr->cmdsn = cpu_to_be32(session->cmdsn); - session->cmdsn++; - hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); - memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); + ctask->hdr_len = 0; + rc = iscsi_add_hdr(ctask, sizeof(*hdr)); + if (rc) + return rc; + hdr->opcode = ISCSI_OP_SCSI_CMD; + hdr->flags = ISCSI_ATTR_SIMPLE; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); + hdr->itt = build_itt(ctask->itt, conn->id, session->age); + hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); + hdr->cmdsn = cpu_to_be32(session->cmdsn); + session->cmdsn++; + hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); + memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); if (sc->cmd_len < MAX_COMMAND_SIZE) memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len); - ctask->data_count = 0; ctask->imm_count = 0; if (sc->sc_data_direction == DMA_TO_DEVICE) { hdr->flags |= ISCSI_FLAG_CMD_WRITE; @@ -178,9 +198,9 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) else ctask->imm_count = min(scsi_bufflen(sc), conn->max_xmit_dlength); - hton24(ctask->hdr->dlength, ctask->imm_count); + hton24(hdr->dlength, ctask->imm_count); } else - zero_data(ctask->hdr->dlength); + zero_data(hdr->dlength); if (!session->initial_r2t_en) { ctask->unsol_count = min((session->first_burst), @@ -190,7 +210,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) if (!ctask->unsol_count) /* No unsolicit Data-Out's */ - ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; + hdr->flags |= ISCSI_FLAG_CMD_FINAL; } else { hdr->flags |= ISCSI_FLAG_CMD_FINAL; zero_data(hdr->dlength); @@ -199,13 +219,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->flags |= ISCSI_FLAG_CMD_READ; } - conn->scsicmd_pdus_cnt++; + /* calculate size of additional header segments (AHSs) */ + hdrlength = ctask->hdr_len - sizeof(*hdr); + + WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); + hdrlength /= ISCSI_PAD_LEN; + + WARN_ON(hdrlength >= 256); + hdr->hlength = hdrlength & 0xFF; + + if (conn->session->tt->init_cmd_task(conn->ctask)) + return EIO; - debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " + conn->scsicmd_pdus_cnt++; + debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " "cmdsn %d win %d]\n", - sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", + sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), - session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); + session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); + return 0; } /** @@ -218,13 +250,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) */ static void iscsi_complete_command(struct iscsi_cmd_task *ctask) { - struct iscsi_session *session = ctask->conn->session; + struct iscsi_conn *conn = ctask->conn; + struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = ctask->sc; ctask->state = ISCSI_TASK_COMPLETED; ctask->sc = NULL; /* SCSI eh reuses commands to verify us */ sc->SCp.ptr = NULL; + if (conn->ctask == ctask) + conn->ctask = NULL; list_del_init(&ctask->running); __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); sc->scsi_done(sc); @@ -241,6 +276,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) iscsi_complete_command(ctask); } +/* + * session lock must be held + */ +static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, + int err) +{ + struct scsi_cmnd *sc; + + sc = ctask->sc; + if (!sc) + return; + + if (ctask->state == ISCSI_TASK_PENDING) + /* + * cmd never made it to the xmit thread, so we should not count + * the cmd in the sequencing + */ + conn->session->queued_cmdsn--; + else + conn->session->tt->cleanup_cmd_task(conn, ctask); + + sc->result = err; + scsi_set_resid(sc, scsi_bufflen(sc)); + if (conn->ctask == ctask) + conn->ctask = NULL; + /* release ref from queuecommand */ + __iscsi_put_ctask(ctask); +} + +/** + * iscsi_free_mgmt_task - return mgmt task back to pool + * @conn: iscsi connection + * @mtask: mtask + * + * Must be called with session lock. + */ +void iscsi_free_mgmt_task(struct iscsi_conn *conn, + struct iscsi_mgmt_task *mtask) +{ + list_del_init(&mtask->running); + if (conn->login_mtask == mtask) + return; + + if (conn->ping_mtask == mtask) + conn->ping_mtask = NULL; + __kfifo_put(conn->session->mgmtpool.queue, + (void*)&mtask, sizeof(void*)); +} +EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); + +static struct iscsi_mgmt_task * +__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size) +{ + struct iscsi_session *session = conn->session; + struct iscsi_mgmt_task *mtask; + + if (session->state == ISCSI_STATE_TERMINATE) + return NULL; + + if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || + hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) + /* + * Login and Text are sent serially, in + * request-followed-by-response sequence. + * Same mtask can be used. Same ITT must be used. + * Note that login_mtask is preallocated at conn_create(). + */ + mtask = conn->login_mtask; + else { + BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); + BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); + + if (!__kfifo_get(session->mgmtpool.queue, + (void*)&mtask, sizeof(void*))) + return NULL; + } + + if (data_size) { + memcpy(mtask->data, data, data_size); + mtask->data_count = data_size; + } else + mtask->data_count = 0; + + memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); + INIT_LIST_HEAD(&mtask->running); + list_add_tail(&mtask->running, &conn->mgmtqueue); + return mtask; +} + +int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + int err = 0; + + spin_lock_bh(&session->lock); + if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) + err = -EPERM; + spin_unlock_bh(&session->lock); + scsi_queue_work(session->host, &conn->xmitwork); + return err; +} +EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); + /** * iscsi_cmd_rsp - SCSI Command Response processing * @conn: iscsi connection @@ -291,17 +432,19 @@ invalid_datalen: min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); } - if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | + ISCSI_FLAG_CMD_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); - if (res_count > 0 && res_count <= scsi_bufflen(sc)) + if (res_count > 0 && + (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || + res_count <= scsi_bufflen(sc))) scsi_set_resid(sc, res_count); else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) + } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | + ISCSI_FLAG_CMD_BIDI_OVERFLOW)) sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) - scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count)); out: debug_scsi("done [sc %lx res %d itt 0x%x]\n", @@ -318,18 +461,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; conn->tmfrsp_pdus_cnt++; - if (conn->tmabort_state != TMABORT_INITIAL) + if (conn->tmf_state != TMF_QUEUED) return; if (tmf->response == ISCSI_TMF_RSP_COMPLETE) - conn->tmabort_state = TMABORT_SUCCESS; + conn->tmf_state = TMF_SUCCESS; else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) - conn->tmabort_state = TMABORT_NOT_FOUND; + conn->tmf_state = TMF_NOT_FOUND; else - conn->tmabort_state = TMABORT_FAILED; + conn->tmf_state = TMF_FAILED; wake_up(&conn->ehwait); } +static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) +{ + struct iscsi_nopout hdr; + struct iscsi_mgmt_task *mtask; + + if (!rhdr && conn->ping_mtask) + return; + + memset(&hdr, 0, sizeof(struct iscsi_nopout)); + hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; + hdr.flags = ISCSI_FLAG_CMD_FINAL; + + if (rhdr) { + memcpy(hdr.lun, rhdr->lun, 8); + hdr.ttt = rhdr->ttt; + hdr.itt = RESERVED_ITT; + } else + hdr.ttt = RESERVED_ITT; + + mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); + if (!mtask) { + printk(KERN_ERR "Could not send nopout\n"); + return; + } + + /* only track our nops */ + if (!rhdr) { + conn->ping_mtask = mtask; + conn->last_ping = jiffies; + } + scsi_queue_work(conn->session->host, &conn->xmitwork); +} + static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen) { @@ -374,6 +550,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_mgmt_task *mtask; uint32_t itt; + conn->last_recv = jiffies; if (hdr->itt != RESERVED_ITT) itt = get_itt(hdr->itt); else @@ -429,10 +606,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, */ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) rc = ISCSI_ERR_CONN_FAILED; - list_del(&mtask->running); - if (conn->login_mtask != mtask) - __kfifo_put(session->mgmtpool.queue, - (void*)&mtask, sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); break; case ISCSI_OP_SCSI_TMFUNC_RSP: if (datalen) { @@ -441,20 +615,26 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } iscsi_tmf_rsp(conn, hdr); + iscsi_free_mgmt_task(conn, mtask); break; case ISCSI_OP_NOOP_IN: - if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { + if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || + datalen) { rc = ISCSI_ERR_PROTO; break; } conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) - rc = ISCSI_ERR_CONN_FAILED; - list_del(&mtask->running); - if (conn->login_mtask != mtask) - __kfifo_put(session->mgmtpool.queue, - (void*)&mtask, sizeof(void*)); + if (conn->ping_mtask != mtask) { + /* + * If this is not in response to one of our + * nops then it must be from userspace. + */ + if (iscsi_recv_pdu(conn->cls_conn, hdr, data, + datalen)) + rc = ISCSI_ERR_CONN_FAILED; + } + iscsi_free_mgmt_task(conn, mtask); break; default: rc = ISCSI_ERR_BAD_OPCODE; @@ -473,8 +653,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) break; - if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) - rc = ISCSI_ERR_CONN_FAILED; + iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr); break; case ISCSI_OP_REJECT: rc = iscsi_handle_reject(conn, hdr, data, datalen); @@ -609,20 +788,19 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, session->tt->init_mgmt_task(conn, mtask); debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", - hdr->opcode, hdr->itt, mtask->data_count); + hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, + mtask->data_count); } static int iscsi_xmit_mtask(struct iscsi_conn *conn) { struct iscsi_hdr *hdr = conn->mtask->hdr; - int rc, was_logout = 0; + int rc; + if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) + conn->session->state = ISCSI_STATE_LOGGING_OUT; spin_unlock_bh(&conn->session->lock); - if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { - conn->session->state = ISCSI_STATE_IN_RECOVERY; - iscsi_block_session(session_to_cls(conn->session)); - was_logout = 1; - } + rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); spin_lock_bh(&conn->session->lock); if (rc) @@ -630,11 +808,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) /* done with this in-progress mtask */ conn->mtask = NULL; - - if (was_logout) { - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - return -ENODATA; - } return 0; } @@ -658,21 +831,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) static int iscsi_xmit_ctask(struct iscsi_conn *conn) { struct iscsi_cmd_task *ctask = conn->ctask; - int rc = 0; - - /* - * serialize with TMF AbortTask - */ - if (ctask->state == ISCSI_TASK_ABORTING) - goto done; + int rc; __iscsi_get_ctask(ctask); spin_unlock_bh(&conn->session->lock); rc = conn->session->tt->xmit_cmd_task(conn, ctask); spin_lock_bh(&conn->session->lock); __iscsi_put_ctask(ctask); - -done: if (!rc) /* done with this ctask */ conn->ctask = NULL; @@ -680,6 +845,22 @@ done: } /** + * iscsi_requeue_ctask - requeue ctask to run from session workqueue + * @ctask: ctask to requeue + * + * LLDs that need to run a ctask from the session workqueue should call + * this. The session lock must be held. + */ +void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) +{ + struct iscsi_conn *conn = ctask->conn; + + list_move_tail(&ctask->running, &conn->requeue); + scsi_queue_work(conn->session->host, &conn->xmitwork); +} +EXPORT_SYMBOL_GPL(iscsi_requeue_ctask); + +/** * iscsi_data_xmit - xmit any command into the scheduled connection * @conn: iscsi connection * @@ -717,36 +898,40 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) * overflow us with nop-ins */ check_mgmt: - while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, - sizeof(void*))) { + while (!list_empty(&conn->mgmtqueue)) { + conn->mtask = list_entry(conn->mgmtqueue.next, + struct iscsi_mgmt_task, running); + if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { + iscsi_free_mgmt_task(conn, conn->mtask); + conn->mtask = NULL; + continue; + } + iscsi_prep_mtask(conn, conn->mtask); - list_add_tail(&conn->mtask->running, &conn->mgmt_run_list); + list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); rc = iscsi_xmit_mtask(conn); if (rc) goto again; } - /* process command queue */ + /* process pending command queue */ while (!list_empty(&conn->xmitqueue)) { - /* - * iscsi tcp may readd the task to the xmitqueue to send - * write data - */ + if (conn->tmf_state == TMF_QUEUED) + break; + conn->ctask = list_entry(conn->xmitqueue.next, struct iscsi_cmd_task, running); - switch (conn->ctask->state) { - case ISCSI_TASK_ABORTING: - break; - case ISCSI_TASK_PENDING: - iscsi_prep_scsi_cmd_pdu(conn->ctask); - conn->session->tt->init_cmd_task(conn->ctask); - /* fall through */ - default: - conn->ctask->state = ISCSI_TASK_RUNNING; - break; + if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { + fail_command(conn, conn->ctask, DID_IMM_RETRY << 16); + continue; + } + if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { + fail_command(conn, conn->ctask, DID_ABORT << 16); + continue; } - list_move_tail(conn->xmitqueue.next, &conn->run_list); + conn->ctask->state = ISCSI_TASK_RUNNING; + list_move_tail(conn->xmitqueue.next, &conn->run_list); rc = iscsi_xmit_ctask(conn); if (rc) goto again; @@ -755,7 +940,28 @@ check_mgmt: * we need to check the mgmt queue for nops that need to * be sent to aviod starvation */ - if (__kfifo_len(conn->mgmtqueue)) + if (!list_empty(&conn->mgmtqueue)) + goto check_mgmt; + } + + while (!list_empty(&conn->requeue)) { + if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) + break; + + /* + * we always do fastlogout - conn stop code will clean up. + */ + if (conn->session->state == ISCSI_STATE_LOGGING_OUT) + break; + + conn->ctask = list_entry(conn->requeue.next, + struct iscsi_cmd_task, running); + conn->ctask->state = ISCSI_TASK_RUNNING; + list_move_tail(conn->requeue.next, &conn->run_list); + rc = iscsi_xmit_ctask(conn); + if (rc) + goto again; + if (!list_empty(&conn->mgmtqueue)) goto check_mgmt; } spin_unlock_bh(&conn->session->lock); @@ -790,6 +996,7 @@ enum { FAILURE_SESSION_TERMINATE, FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, + FAILURE_SESSION_LOGGING_OUT, }; int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) @@ -805,8 +1012,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.ptr = NULL; host = sc->device->host; - session = iscsi_hostdata(host->hostdata); + spin_unlock(host->host_lock); + session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); /* @@ -822,17 +1030,22 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) * be entering our queuecommand while a block is starting * up because the block code is not locked) */ - if (session->state == ISCSI_STATE_IN_RECOVERY) { + switch (session->state) { + case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; goto reject; - } - - if (session->state == ISCSI_STATE_RECOVERY_FAILED) + case ISCSI_STATE_LOGGING_OUT: + reason = FAILURE_SESSION_LOGGING_OUT; + goto reject; + case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - else if (session->state == ISCSI_STATE_TERMINATE) + break; + case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; - else + break; + default: reason = FAILURE_SESSION_FREED; + } goto fault; } @@ -859,7 +1072,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) atomic_set(&ctask->refcount, 1); ctask->state = ISCSI_TASK_PENDING; - ctask->mtask = NULL; ctask->conn = conn; ctask->sc = sc; INIT_LIST_HEAD(&ctask->running); @@ -868,11 +1080,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) spin_unlock(&session->lock); scsi_queue_work(host, &conn->xmitwork); + spin_lock(host->host_lock); return 0; reject: spin_unlock(&session->lock); debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); + spin_lock(host->host_lock); return SCSI_MLQUEUE_HOST_BUSY; fault: @@ -882,6 +1096,7 @@ fault: sc->result = (DID_NO_CONNECT << 16); scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); + spin_lock(host->host_lock); return 0; } EXPORT_SYMBOL_GPL(iscsi_queuecommand); @@ -895,72 +1110,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) } EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); -static struct iscsi_mgmt_task * -__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, uint32_t data_size) -{ - struct iscsi_session *session = conn->session; - struct iscsi_mgmt_task *mtask; - - if (session->state == ISCSI_STATE_TERMINATE) - return NULL; - - if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || - hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) - /* - * Login and Text are sent serially, in - * request-followed-by-response sequence. - * Same mtask can be used. Same ITT must be used. - * Note that login_mtask is preallocated at conn_create(). - */ - mtask = conn->login_mtask; - else { - BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); - BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); - - if (!__kfifo_get(session->mgmtpool.queue, - (void*)&mtask, sizeof(void*))) - return NULL; - } - - if (data_size) { - memcpy(mtask->data, data, data_size); - mtask->data_count = data_size; - } else - mtask->data_count = 0; - - INIT_LIST_HEAD(&mtask->running); - memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); - __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); - return mtask; -} - -int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, - char *data, uint32_t data_size) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - int err = 0; - - spin_lock_bh(&session->lock); - if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) - err = -EPERM; - spin_unlock_bh(&session->lock); - scsi_queue_work(session->host, &conn->xmitwork); - return err; -} -EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); - void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) { struct iscsi_session *session = class_to_transport_session(cls_session); - struct iscsi_conn *conn = session->leadconn; spin_lock_bh(&session->lock); if (session->state != ISCSI_STATE_LOGGED_IN) { session->state = ISCSI_STATE_RECOVERY_FAILED; - if (conn) - wake_up(&conn->ehwait); + if (session->leadconn) + wake_up(&session->leadconn->ehwait); } spin_unlock_bh(&session->lock); } @@ -971,30 +1129,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) struct Scsi_Host *host = sc->device->host; struct iscsi_session *session = iscsi_hostdata(host->hostdata); struct iscsi_conn *conn = session->leadconn; - int fail_session = 0; + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_TERMINATE) { failed: debug_scsi("failing host reset: session terminated " "[CID %d age %d]\n", conn->id, session->age); spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); return FAILED; } - if (sc->SCp.phase == session->age) { - debug_scsi("failing connection CID %d due to SCSI host reset\n", - conn->id); - fail_session = 1; - } spin_unlock_bh(&session->lock); - + mutex_unlock(&session->eh_mutex); /* * we drop the lock here but the leadconn cannot be destoyed while * we are in the scsi eh */ - if (fail_session) - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); debug_scsi("iscsi_eh_host_reset wait for relogin\n"); wait_event_interruptible(conn->ehwait, @@ -1004,73 +1157,56 @@ failed: if (signal_pending(current)) flush_signals(current); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) printk(KERN_INFO "iscsi: host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); - + mutex_unlock(&session->eh_mutex); return SUCCESS; } EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); -static void iscsi_tmabort_timedout(unsigned long data) +static void iscsi_tmf_timedout(unsigned long data) { - struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data; - struct iscsi_conn *conn = ctask->conn; + struct iscsi_conn *conn = (struct iscsi_conn *)data; struct iscsi_session *session = conn->session; spin_lock(&session->lock); - if (conn->tmabort_state == TMABORT_INITIAL) { - conn->tmabort_state = TMABORT_TIMEDOUT; - debug_scsi("tmabort timedout [sc %p itt 0x%x]\n", - ctask->sc, ctask->itt); + if (conn->tmf_state == TMF_QUEUED) { + conn->tmf_state = TMF_TIMEDOUT; + debug_scsi("tmf timedout\n"); /* unblock eh_abort() */ wake_up(&conn->ehwait); } spin_unlock(&session->lock); } -static int iscsi_exec_abort_task(struct scsi_cmnd *sc, - struct iscsi_cmd_task *ctask) +static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, + struct iscsi_tm *hdr, int age, + int timeout) { - struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; - struct iscsi_tm *hdr = &conn->tmhdr; - - /* - * ctask timed out but session is OK requests must be serialized. - */ - memset(hdr, 0, sizeof(struct iscsi_tm)); - hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; - hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); - hdr->rtt = ctask->hdr->itt; - hdr->refcmdsn = ctask->hdr->cmdsn; + struct iscsi_mgmt_task *mtask; - ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, - NULL, 0); - if (!ctask->mtask) { + mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, + NULL, 0); + if (!mtask) { spin_unlock_bh(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - spin_lock_bh(&session->lock) - debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt); + spin_lock_bh(&session->lock); + debug_scsi("tmf exec failure\n"); return -EPERM; } - ctask->state = ISCSI_TASK_ABORTING; + conn->tmfcmd_pdus_cnt++; + conn->tmf_timer.expires = timeout * HZ + jiffies; + conn->tmf_timer.function = iscsi_tmf_timedout; + conn->tmf_timer.data = (unsigned long)conn; + add_timer(&conn->tmf_timer); + debug_scsi("tmf set timeout\n"); - debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); - - if (conn->tmabort_state == TMABORT_INITIAL) { - conn->tmfcmd_pdus_cnt++; - conn->tmabort_timer.expires = 20*HZ + jiffies; - conn->tmabort_timer.function = iscsi_tmabort_timedout; - conn->tmabort_timer.data = (unsigned long)ctask; - add_timer(&conn->tmabort_timer); - debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); - } spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); scsi_queue_work(session->host, &conn->xmitwork); @@ -1078,113 +1214,197 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, /* * block eh thread until: * - * 1) abort response - * 2) abort timeout + * 1) tmf response + * 2) tmf timeout * 3) session is terminated or restarted or userspace has * given up on recovery */ - wait_event_interruptible(conn->ehwait, - sc->SCp.phase != session->age || + wait_event_interruptible(conn->ehwait, age != session->age || session->state != ISCSI_STATE_LOGGED_IN || - conn->tmabort_state != TMABORT_INITIAL); + conn->tmf_state != TMF_QUEUED); if (signal_pending(current)) flush_signals(current); - del_timer_sync(&conn->tmabort_timer); + del_timer_sync(&conn->tmf_timer); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); + /* if the session drops it will clean up the mtask */ + if (age != session->age || + session->state != ISCSI_STATE_LOGGED_IN) + return -ENOTCONN; return 0; } /* - * session lock must be held + * Fail commands. session lock held and recv side suspended and xmit + * thread flushed */ -static struct iscsi_mgmt_task * -iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) +static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) { - int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); - struct iscsi_mgmt_task *task; + struct iscsi_cmd_task *ctask, *tmp; - debug_scsi("searching %d tasks\n", nr_tasks); + if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1)) + conn->ctask = NULL; - for (i = 0; i < nr_tasks; i++) { - __kfifo_get(fifo, (void*)&task, sizeof(void*)); - debug_scsi("check task %u\n", task->itt); + /* flush pending */ + list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { + if (lun == ctask->sc->device->lun || lun == -1) { + debug_scsi("failing pending sc %p itt 0x%x\n", + ctask->sc, ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); + } + } - if (task->itt == itt) { - debug_scsi("matched task\n"); - return task; + list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) { + if (lun == ctask->sc->device->lun || lun == -1) { + debug_scsi("failing requeued sc %p itt 0x%x\n", + ctask->sc, ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); } + } - __kfifo_put(fifo, (void*)&task, sizeof(void*)); + /* fail all other running */ + list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { + if (lun == ctask->sc->device->lun || lun == -1) { + debug_scsi("failing in progress sc %p itt 0x%x\n", + ctask->sc, ctask->itt); + fail_command(conn, ctask, DID_BUS_BUSY << 16); + } } - return NULL; } -static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) +static void iscsi_suspend_tx(struct iscsi_conn *conn) { - struct iscsi_conn *conn = ctask->conn; - struct iscsi_session *session = conn->session; - - if (!ctask->mtask) - return -EINVAL; + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + scsi_flush_work(conn->session->host); +} - if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt)) - list_del(&ctask->mtask->running); - __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, - sizeof(void*)); - ctask->mtask = NULL; - return 0; +static void iscsi_start_tx(struct iscsi_conn *conn) +{ + clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); + scsi_queue_work(conn->session->host, &conn->xmitwork); } -/* - * session lock must be held - */ -static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, - int err) +static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) { - struct scsi_cmnd *sc; + struct iscsi_cls_session *cls_session; + struct iscsi_session *session; + struct iscsi_conn *conn; + enum scsi_eh_timer_return rc = EH_NOT_HANDLED; - sc = ctask->sc; - if (!sc) - return; + cls_session = starget_to_session(scsi_target(scmd->device)); + session = class_to_transport_session(cls_session); - if (ctask->state == ISCSI_TASK_PENDING) + debug_scsi("scsi cmd %p timedout\n", scmd); + + spin_lock(&session->lock); + if (session->state != ISCSI_STATE_LOGGED_IN) { /* - * cmd never made it to the xmit thread, so we should not count - * the cmd in the sequencing + * We are probably in the middle of iscsi recovery so let + * that complete and handle the error. */ - conn->session->queued_cmdsn--; - else - conn->session->tt->cleanup_cmd_task(conn, ctask); - iscsi_ctask_mtask_cleanup(ctask); + rc = EH_RESET_TIMER; + goto done; + } - sc->result = err; - scsi_set_resid(sc, scsi_bufflen(sc)); - if (conn->ctask == ctask) - conn->ctask = NULL; - /* release ref from queuecommand */ - __iscsi_put_ctask(ctask); + conn = session->leadconn; + if (!conn) { + /* In the middle of shuting down */ + rc = EH_RESET_TIMER; + goto done; + } + + if (!conn->recv_timeout && !conn->ping_timeout) + goto done; + /* + * if the ping timedout then we are in the middle of cleaning up + * and can let the iscsi eh handle it + */ + if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + + (conn->ping_timeout * HZ), jiffies)) + rc = EH_RESET_TIMER; + /* + * if we are about to check the transport then give the command + * more time + */ + if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ), + jiffies)) + rc = EH_RESET_TIMER; + /* if in the middle of checking the transport then give us more time */ + if (conn->ping_mtask) + rc = EH_RESET_TIMER; +done: + spin_unlock(&session->lock); + debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh"); + return rc; } -static void iscsi_suspend_tx(struct iscsi_conn *conn) +static void iscsi_check_transport_timeouts(unsigned long data) { - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - scsi_flush_work(conn->session->host); + struct iscsi_conn *conn = (struct iscsi_conn *)data; + struct iscsi_session *session = conn->session; + unsigned long timeout, next_timeout = 0, last_recv; + + spin_lock(&session->lock); + if (session->state != ISCSI_STATE_LOGGED_IN) + goto done; + + timeout = conn->recv_timeout; + if (!timeout) + goto done; + + timeout *= HZ; + last_recv = conn->last_recv; + if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), + jiffies)) { + printk(KERN_ERR "ping timeout of %d secs expired, " + "last rx %lu, last ping %lu, now %lu\n", + conn->ping_timeout, last_recv, + conn->last_ping, jiffies); + spin_unlock(&session->lock); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + return; + } + + if (time_before_eq(last_recv + timeout, jiffies)) { + if (time_before_eq(conn->last_ping, last_recv)) { + /* send a ping to try to provoke some traffic */ + debug_scsi("Sending nopout as ping on conn %p\n", conn); + iscsi_send_nopout(conn, NULL); + } + next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); + } else { + next_timeout = last_recv + timeout; + } + + if (next_timeout) { + debug_scsi("Setting next tmo %lu\n", next_timeout); + mod_timer(&conn->transport_timer, next_timeout); + } +done: + spin_unlock(&session->lock); } -static void iscsi_start_tx(struct iscsi_conn *conn) +static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, + struct iscsi_tm *hdr) { - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - scsi_queue_work(conn->session->host, &conn->xmitwork); + memset(hdr, 0, sizeof(*hdr)); + hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; + hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; + hdr->flags |= ISCSI_FLAG_CMD_FINAL; + memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); + hdr->rtt = ctask->hdr->itt; + hdr->refcmdsn = ctask->hdr->cmdsn; } int iscsi_eh_abort(struct scsi_cmnd *sc) { struct Scsi_Host *host = sc->device->host; struct iscsi_session *session = iscsi_hostdata(host->hostdata); - struct iscsi_cmd_task *ctask; struct iscsi_conn *conn; - int rc; + struct iscsi_cmd_task *ctask; + struct iscsi_tm *hdr; + int rc, age; mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); @@ -1199,19 +1419,23 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) return SUCCESS; } - ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; - conn = ctask->conn; - - conn->eh_abort_cnt++; - debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); - /* * If we are not logged in or we have started a new session * then let the host reset code handle this */ - if (session->state != ISCSI_STATE_LOGGED_IN || - sc->SCp.phase != session->age) - goto failed; + if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN || + sc->SCp.phase != session->age) { + spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); + return FAILED; + } + + conn = session->leadconn; + conn->eh_abort_cnt++; + age = session->age; + + ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; + debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); /* ctask completed before time out */ if (!ctask->sc) { @@ -1219,27 +1443,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) goto success; } - /* what should we do here ? */ - if (conn->ctask == ctask) { - printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. " - "Failing abort\n", sc, ctask->itt); - goto failed; - } - if (ctask->state == ISCSI_TASK_PENDING) { fail_command(conn, ctask, DID_ABORT << 16); goto success; } - conn->tmabort_state = TMABORT_INITIAL; - rc = iscsi_exec_abort_task(sc, ctask); - if (rc || sc->SCp.phase != session->age || - session->state != ISCSI_STATE_LOGGED_IN) + /* only have one tmf outstanding at a time */ + if (conn->tmf_state != TMF_INITIAL) + goto failed; + conn->tmf_state = TMF_QUEUED; + + hdr = &conn->tmhdr; + iscsi_prep_abort_task_pdu(ctask, hdr); + + if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { + rc = FAILED; goto failed; - iscsi_ctask_mtask_cleanup(ctask); + } - switch (conn->tmabort_state) { - case TMABORT_SUCCESS: + switch (conn->tmf_state) { + case TMF_SUCCESS: spin_unlock_bh(&session->lock); iscsi_suspend_tx(conn); /* @@ -1248,22 +1471,26 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) write_lock_bh(conn->recv_lock); spin_lock(&session->lock); fail_command(conn, ctask, DID_ABORT << 16); + conn->tmf_state = TMF_INITIAL; spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); iscsi_start_tx(conn); goto success_unlocked; - case TMABORT_NOT_FOUND: - if (!ctask->sc) { + case TMF_TIMEDOUT: + spin_unlock_bh(&session->lock); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + goto failed_unlocked; + case TMF_NOT_FOUND: + if (!sc->SCp.ptr) { + conn->tmf_state = TMF_INITIAL; /* ctask completed before tmf abort response */ debug_scsi("sc completed while abort in progress\n"); goto success; } /* fall through */ default: - /* timedout or failed */ - spin_unlock_bh(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - goto failed_unlocked; + conn->tmf_state = TMF_INITIAL; + goto failed; } success: @@ -1276,65 +1503,152 @@ success_unlocked: failed: spin_unlock_bh(&session->lock); failed_unlocked: - debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); + debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, + ctask ? ctask->itt : 0); mutex_unlock(&session->eh_mutex); return FAILED; } EXPORT_SYMBOL_GPL(iscsi_eh_abort); +static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) +{ + memset(hdr, 0, sizeof(*hdr)); + hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; + hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; + hdr->flags |= ISCSI_FLAG_CMD_FINAL; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); + hdr->rtt = RESERVED_ITT; +} + +int iscsi_eh_device_reset(struct scsi_cmnd *sc) +{ + struct Scsi_Host *host = sc->device->host; + struct iscsi_session *session = iscsi_hostdata(host->hostdata); + struct iscsi_conn *conn; + struct iscsi_tm *hdr; + int rc = FAILED; + + debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); + + mutex_lock(&session->eh_mutex); + spin_lock_bh(&session->lock); + /* + * Just check if we are not logged in. We cannot check for + * the phase because the reset could come from a ioctl. + */ + if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) + goto unlock; + conn = session->leadconn; + + /* only have one tmf outstanding at a time */ + if (conn->tmf_state != TMF_INITIAL) + goto unlock; + conn->tmf_state = TMF_QUEUED; + + hdr = &conn->tmhdr; + iscsi_prep_lun_reset_pdu(sc, hdr); + + if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age, + session->lu_reset_timeout)) { + rc = FAILED; + goto unlock; + } + + switch (conn->tmf_state) { + case TMF_SUCCESS: + break; + case TMF_TIMEDOUT: + spin_unlock_bh(&session->lock); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); + goto done; + default: + conn->tmf_state = TMF_INITIAL; + goto unlock; + } + + rc = SUCCESS; + spin_unlock_bh(&session->lock); + + iscsi_suspend_tx(conn); + /* need to grab the recv lock then session lock */ + write_lock_bh(conn->recv_lock); + spin_lock(&session->lock); + fail_all_commands(conn, sc->device->lun); + conn->tmf_state = TMF_INITIAL; + spin_unlock(&session->lock); + write_unlock_bh(conn->recv_lock); + + iscsi_start_tx(conn); + goto done; + +unlock: + spin_unlock_bh(&session->lock); +done: + debug_scsi("iscsi_eh_device_reset %s\n", + rc == SUCCESS ? "SUCCESS" : "FAILED"); + mutex_unlock(&session->eh_mutex); + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); + +/* + * Pre-allocate a pool of @max items of @item_size. By default, the pool + * should be accessed via kfifo_{get,put} on q->queue. + * Optionally, the caller can obtain the array of object pointers + * by passing in a non-NULL @items pointer + */ int -iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) +iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) { - int i; + int i, num_arrays = 1; - *items = kmalloc(max * sizeof(void*), GFP_KERNEL); - if (*items == NULL) - return -ENOMEM; + memset(q, 0, sizeof(*q)); q->max = max; - q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL); - if (q->pool == NULL) { - kfree(*items); - return -ENOMEM; - } + + /* If the user passed an items pointer, he wants a copy of + * the array. */ + if (items) + num_arrays++; + q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL); + if (q->pool == NULL) + goto enomem; q->queue = kfifo_init((void*)q->pool, max * sizeof(void*), GFP_KERNEL, NULL); - if (q->queue == ERR_PTR(-ENOMEM)) { - kfree(q->pool); - kfree(*items); - return -ENOMEM; - } + if (q->queue == ERR_PTR(-ENOMEM)) + goto enomem; for (i = 0; i < max; i++) { - q->pool[i] = kmalloc(item_size, GFP_KERNEL); + q->pool[i] = kzalloc(item_size, GFP_KERNEL); if (q->pool[i] == NULL) { - int j; - - for (j = 0; j < i; j++) - kfree(q->pool[j]); - - kfifo_free(q->queue); - kfree(q->pool); - kfree(*items); - return -ENOMEM; + q->max = i; + goto enomem; } - memset(q->pool[i], 0, item_size); - (*items)[i] = q->pool[i]; __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*)); } + + if (items) { + *items = q->pool + max; + memcpy(*items, q->pool, max * sizeof(void *)); + } + return 0; + +enomem: + iscsi_pool_free(q); + return -ENOMEM; } EXPORT_SYMBOL_GPL(iscsi_pool_init); -void iscsi_pool_free(struct iscsi_queue *q, void **items) +void iscsi_pool_free(struct iscsi_pool *q) { int i; for (i = 0; i < q->max; i++) - kfree(items[i]); - kfree(q->pool); - kfree(items); + kfree(q->pool[i]); + if (q->pool) + kfree(q->pool); } EXPORT_SYMBOL_GPL(iscsi_pool_free); @@ -1387,7 +1701,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, qdepth = ISCSI_DEF_CMD_PER_LUN; } - if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || + if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET) { if (cmds_max != 0) printk(KERN_ERR "iscsi: invalid can_queue of %d. " @@ -1411,12 +1725,16 @@ iscsi_session_setup(struct iscsi_transport *iscsit, shost->max_cmd_len = iscsit->max_cmd_len; shost->transportt = scsit; shost->transportt->create_work_queue = 1; + shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; *hostno = shost->host_no; session = iscsi_hostdata(shost->hostdata); memset(session, 0, sizeof(struct iscsi_session)); session->host = shost; session->state = ISCSI_STATE_FREE; + session->fast_abort = 1; + session->lu_reset_timeout = 15; + session->abort_timeout = 10; session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; session->cmds_max = cmds_max; session->queued_cmdsn = session->cmdsn = initial_cmdsn; @@ -1479,9 +1797,9 @@ module_put: cls_session_fail: scsi_remove_host(shost); add_host_fail: - iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); + iscsi_pool_free(&session->mgmtpool); mgmtpool_alloc_fail: - iscsi_pool_free(&session->cmdpool, (void**)session->cmds); + iscsi_pool_free(&session->cmdpool); cmdpool_alloc_fail: scsi_host_put(shost); return NULL; @@ -1501,11 +1819,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) struct iscsi_session *session = iscsi_hostdata(shost->hostdata); struct module *owner = cls_session->transport->owner; - iscsi_unblock_session(cls_session); + iscsi_remove_session(cls_session); scsi_remove_host(shost); - iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); - iscsi_pool_free(&session->cmdpool, (void**)session->cmds); + iscsi_pool_free(&session->mgmtpool); + iscsi_pool_free(&session->cmdpool); kfree(session->password); kfree(session->password_in); @@ -1516,7 +1834,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) kfree(session->hwaddress); kfree(session->initiatorname); - iscsi_destroy_session(cls_session); + iscsi_free_session(cls_session); scsi_host_put(shost); module_put(owner); } @@ -1546,17 +1864,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->c_stage = ISCSI_CONN_INITIAL_STAGE; conn->id = conn_idx; conn->exp_statsn = 0; - conn->tmabort_state = TMABORT_INITIAL; + conn->tmf_state = TMF_INITIAL; + + init_timer(&conn->transport_timer); + conn->transport_timer.data = (unsigned long)conn; + conn->transport_timer.function = iscsi_check_transport_timeouts; + INIT_LIST_HEAD(&conn->run_list); INIT_LIST_HEAD(&conn->mgmt_run_list); + INIT_LIST_HEAD(&conn->mgmtqueue); INIT_LIST_HEAD(&conn->xmitqueue); - - /* initialize general immediate & non-immediate PDU commands queue */ - conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), - GFP_KERNEL, NULL); - if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) - goto mgmtqueue_alloc_fail; - + INIT_LIST_HEAD(&conn->requeue); INIT_WORK(&conn->xmitwork, iscsi_xmitworker); /* allocate login_mtask used for the login/text sequences */ @@ -1574,7 +1892,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) goto login_mtask_data_alloc_fail; conn->login_mtask->data = conn->data = data; - init_timer(&conn->tmabort_timer); + init_timer(&conn->tmf_timer); init_waitqueue_head(&conn->ehwait); return cls_conn; @@ -1583,8 +1901,6 @@ login_mtask_data_alloc_fail: __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, sizeof(void*)); login_mtask_alloc_fail: - kfifo_free(conn->mgmtqueue); -mgmtqueue_alloc_fail: iscsi_destroy_conn(cls_conn); return NULL; } @@ -1603,8 +1919,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) struct iscsi_session *session = conn->session; unsigned long flags; + del_timer_sync(&conn->transport_timer); + spin_lock_bh(&session->lock); - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; if (session->leadconn == conn) { /* @@ -1637,7 +1954,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } /* flush queued up work because we free the connection below */ - scsi_flush_work(session->host); + iscsi_suspend_tx(conn); spin_lock_bh(&session->lock); kfree(conn->data); @@ -1648,8 +1965,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) session->leadconn = NULL; spin_unlock_bh(&session->lock); - kfifo_free(conn->mgmtqueue); - iscsi_destroy_conn(cls_conn); } EXPORT_SYMBOL_GPL(iscsi_conn_teardown); @@ -1672,11 +1987,29 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) return -EINVAL; } + if (conn->ping_timeout && !conn->recv_timeout) { + printk(KERN_ERR "iscsi: invalid recv timeout of zero " + "Using 5 seconds\n."); + conn->recv_timeout = 5; + } + + if (conn->recv_timeout && !conn->ping_timeout) { + printk(KERN_ERR "iscsi: invalid ping timeout of zero " + "Using 5 seconds.\n"); + conn->ping_timeout = 5; + } + spin_lock_bh(&session->lock); conn->c_stage = ISCSI_CONN_STARTED; session->state = ISCSI_STATE_LOGGED_IN; session->queued_cmdsn = session->cmdsn; + conn->last_recv = jiffies; + conn->last_ping = jiffies; + if (conn->recv_timeout && conn->ping_timeout) + mod_timer(&conn->transport_timer, + jiffies + (conn->recv_timeout * HZ)); + switch(conn->stop_stage) { case STOP_CONN_RECOVER: /* @@ -1684,7 +2017,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) * commands after successful recovery */ conn->stop_stage = 0; - conn->tmabort_state = TMABORT_INITIAL; + conn->tmf_state = TMF_INITIAL; session->age++; spin_unlock_bh(&session->lock); @@ -1709,55 +2042,27 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) struct iscsi_mgmt_task *mtask, *tmp; /* handle pending */ - while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { - if (mtask == conn->login_mtask) - continue; + list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); - __kfifo_put(session->mgmtpool.queue, (void*)&mtask, - sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); } /* handle running */ list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); - list_del(&mtask->running); - - if (mtask == conn->login_mtask) - continue; - __kfifo_put(session->mgmtpool.queue, (void*)&mtask, - sizeof(void*)); + iscsi_free_mgmt_task(conn, mtask); } conn->mtask = NULL; } -/* Fail commands. Mutex and session lock held and recv side suspended */ -static void fail_all_commands(struct iscsi_conn *conn) -{ - struct iscsi_cmd_task *ctask, *tmp; - - /* flush pending */ - list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { - debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, - ctask->itt); - fail_command(conn, ctask, DID_BUS_BUSY << 16); - } - - /* fail all other running */ - list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { - debug_scsi("failing in progress sc %p itt 0x%x\n", - ctask->sc, ctask->itt); - fail_command(conn, ctask, DID_BUS_BUSY << 16); - } - - conn->ctask = NULL; -} - static void iscsi_start_session_recovery(struct iscsi_session *session, struct iscsi_conn *conn, int flag) { int old_stop_stage; + del_timer_sync(&conn->transport_timer); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (conn->stop_stage == STOP_CONN_TERM) { @@ -1818,7 +2123,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn); + fail_all_commands(conn, -1); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); mutex_unlock(&session->eh_mutex); @@ -1869,6 +2174,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, uint32_t value; switch(param) { + case ISCSI_PARAM_FAST_ABORT: + sscanf(buf, "%d", &session->fast_abort); + break; + case ISCSI_PARAM_ABORT_TMO: + sscanf(buf, "%d", &session->abort_timeout); + break; + case ISCSI_PARAM_LU_RESET_TMO: + sscanf(buf, "%d", &session->lu_reset_timeout); + break; + case ISCSI_PARAM_PING_TMO: + sscanf(buf, "%d", &conn->ping_timeout); + break; + case ISCSI_PARAM_RECV_TMO: + sscanf(buf, "%d", &conn->recv_timeout); + break; case ISCSI_PARAM_MAX_RECV_DLENGTH: sscanf(buf, "%d", &conn->max_recv_dlength); break; @@ -1983,6 +2303,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, int len; switch(param) { + case ISCSI_PARAM_FAST_ABORT: + len = sprintf(buf, "%d\n", session->fast_abort); + break; + case ISCSI_PARAM_ABORT_TMO: + len = sprintf(buf, "%d\n", session->abort_timeout); + break; + case ISCSI_PARAM_LU_RESET_TMO: + len = sprintf(buf, "%d\n", session->lu_reset_timeout); + break; case ISCSI_PARAM_INITIAL_R2T_EN: len = sprintf(buf, "%d\n", session->initial_r2t_en); break; @@ -2040,6 +2369,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, int len; switch(param) { + case ISCSI_PARAM_PING_TMO: + len = sprintf(buf, "%u\n", conn->ping_timeout); + break; + case ISCSI_PARAM_RECV_TMO: + len = sprintf(buf, "%u\n", conn->recv_timeout); + break; case ISCSI_PARAM_MAX_RECV_DLENGTH: len = sprintf(buf, "%u\n", conn->max_recv_dlength); break; diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig index c01a40d321d4..18f33cd54411 100644 --- a/drivers/scsi/libsas/Kconfig +++ b/drivers/scsi/libsas/Kconfig @@ -38,6 +38,15 @@ config SCSI_SAS_ATA Builds in ATA support into libsas. Will necessitate the loading of libata along with libsas. +config SCSI_SAS_HOST_SMP + bool "Support for SMP interpretation for SAS hosts" + default y + depends on SCSI_SAS_LIBSAS + help + Allows sas hosts to receive SMP frames. Selecting this + option builds an SMP interpreter into libsas. Say + N here if you want to save the few kb this consumes. + config SCSI_SAS_LIBSAS_DEBUG bool "Compile the SAS Domain Transport Attributes in debug mode" default y diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile index fd387b91856e..1ad1323c60fa 100644 --- a/drivers/scsi/libsas/Makefile +++ b/drivers/scsi/libsas/Makefile @@ -33,5 +33,7 @@ libsas-y += sas_init.o \ sas_dump.o \ sas_discover.o \ sas_expander.o \ - sas_scsi_host.o + sas_scsi_host.o \ + sas_task.o libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o +libsas-$(CONFIG_SCSI_SAS_HOST_SMP) += sas_host_smp.o
\ No newline at end of file diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 0829b55c64d2..0996f866f14c 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -158,8 +158,8 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) struct Scsi_Host *host = sas_ha->core.shost; struct sas_internal *i = to_sas_internal(host->transportt); struct scatterlist *sg; - unsigned int num = 0; unsigned int xfer = 0; + unsigned int si; task = sas_alloc_task(GFP_ATOMIC); if (!task) @@ -176,22 +176,20 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis); task->uldd_task = qc; - if (is_atapi_taskfile(&qc->tf)) { + if (ata_is_atapi(qc->tf.protocol)) { memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); task->total_xfer_len = qc->nbytes + qc->pad_len; task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem; } else { - ata_for_each_sg(sg, qc) { - num++; + for_each_sg(qc->sg, sg, qc->n_elem, si) xfer += sg->length; - } task->total_xfer_len = xfer; - task->num_scatter = num; + task->num_scatter = si; } task->data_dir = qc->dma_dir; - task->scatter = qc->__sg; + task->scatter = qc->sg; task->ata_task.retry_count = 1; task->task_state_flags = SAS_TASK_STATE_PENDING; qc->lldd_task = task; @@ -200,7 +198,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) case ATA_PROT_NCQ: task->ata_task.use_ncq = 1; /* fall through */ - case ATA_PROT_ATAPI_DMA: + case ATAPI_PROT_DMA: case ATA_PROT_DMA: task->ata_task.dma_xfer = 1; break; @@ -500,7 +498,7 @@ static int sas_execute_task(struct sas_task *task, void *buffer, int size, goto ex_err; } wait_for_completion(&task->completion); - res = -ETASK; + res = -ECOMM; if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { int res2; SAS_DPRINTK("task aborted, flags:0x%x\n", diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 5f3a0d7b18de..31b9af224243 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -98,7 +98,7 @@ static int sas_get_port_device(struct asd_sas_port *port) dev->dev_type = SATA_PM; else dev->dev_type = SATA_DEV; - dev->tproto = SATA_PROTO; + dev->tproto = SAS_PROTOCOL_SATA; } else { struct sas_identify_frame *id = (struct sas_identify_frame *) dev->frame_rcvd; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 8727436b222d..aefd865a5788 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size, } wait_for_completion(&task->completion); - res = -ETASK; + res = -ECOMM; if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { SAS_DPRINTK("smp task timed out or aborted\n"); i->dft->lldd_abort_task(task); @@ -109,6 +109,16 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size, task->task_status.stat == SAM_GOOD) { res = 0; break; + } if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_UNDERRUN) { + /* no error, but return the number of bytes of + * underrun */ + res = task->task_status.residual; + break; + } if (task->task_status.resp == SAS_TASK_COMPLETE && + task->task_status.stat == SAS_DATA_OVERRUN) { + res = -EMSGSIZE; + break; } else { SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " "status 0x%x\n", __FUNCTION__, @@ -656,9 +666,9 @@ static struct domain_device *sas_ex_discover_end_dev( sas_ex_get_linkrate(parent, child, phy); #ifdef CONFIG_SCSI_SAS_ATA - if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { + if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { child->dev_type = SATA_DEV; - if (phy->attached_tproto & SAS_PROTO_STP) + if (phy->attached_tproto & SAS_PROTOCOL_STP) child->tproto = phy->attached_tproto; if (phy->attached_sata_dev) child->tproto |= SATA_DEV; @@ -695,7 +705,7 @@ static struct domain_device *sas_ex_discover_end_dev( } } else #endif - if (phy->attached_tproto & SAS_PROTO_SSP) { + if (phy->attached_tproto & SAS_PROTOCOL_SSP) { child->dev_type = SAS_END_DEV; rphy = sas_end_device_alloc(phy->port); /* FIXME: error handling */ @@ -1896,11 +1906,9 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } /* no rphy means no smp target support (ie aic94xx host) */ - if (!rphy) { - printk("%s: can we send a smp request to a host?\n", - __FUNCTION__); - return -EINVAL; - } + if (!rphy) + return sas_smp_host_handler(shost, req, rsp); + type = rphy->identify.device_type; if (type != SAS_EDGE_EXPANDER_DEVICE && @@ -1926,6 +1934,15 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, ret = smp_execute_task(dev, bio_data(req->bio), req->data_len, bio_data(rsp->bio), rsp->data_len); + if (ret > 0) { + /* positive number is the untransferred residual */ + rsp->data_len = ret; + req->data_len = 0; + ret = 0; + } else if (ret == 0) { + rsp->data_len = 0; + req->data_len = 0; + } return ret; } diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c new file mode 100644 index 000000000000..16f93123271e --- /dev/null +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -0,0 +1,274 @@ +/* + * Serial Attached SCSI (SAS) Expander discovery and configuration + * + * Copyright (C) 2007 James E.J. Bottomley + * <James.Bottomley@HansenPartnership.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 only. + */ +#include <linux/scatterlist.h> +#include <linux/blkdev.h> + +#include "sas_internal.h" + +#include <scsi/scsi_transport.h> +#include <scsi/scsi_transport_sas.h> +#include "../scsi_sas_internal.h" + +static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data, + u8 phy_id) +{ + struct sas_phy *phy; + struct sas_rphy *rphy; + + if (phy_id >= sas_ha->num_phys) { + resp_data[2] = SMP_RESP_NO_PHY; + return; + } + resp_data[2] = SMP_RESP_FUNC_ACC; + + phy = sas_ha->sas_phy[phy_id]->phy; + resp_data[9] = phy_id; + resp_data[13] = phy->negotiated_linkrate; + memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE); + memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr, + SAS_ADDR_SIZE); + resp_data[40] = (phy->minimum_linkrate << 4) | + phy->minimum_linkrate_hw; + resp_data[41] = (phy->maximum_linkrate << 4) | + phy->maximum_linkrate_hw; + + if (!sas_ha->sas_phy[phy_id]->port || + !sas_ha->sas_phy[phy_id]->port->port_dev) + return; + + rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy; + resp_data[12] = rphy->identify.device_type << 4; + resp_data[14] = rphy->identify.initiator_port_protocols; + resp_data[15] = rphy->identify.target_port_protocols; +} + +static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data, + u8 phy_id) +{ + struct sas_rphy *rphy; + struct dev_to_host_fis *fis; + int i; + + if (phy_id >= sas_ha->num_phys) { + resp_data[2] = SMP_RESP_NO_PHY; + return; + } + + resp_data[2] = SMP_RESP_PHY_NO_SATA; + + if (!sas_ha->sas_phy[phy_id]->port) + return; + + rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy; + fis = (struct dev_to_host_fis *) + sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd; + if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA) + return; + + resp_data[2] = SMP_RESP_FUNC_ACC; + resp_data[9] = phy_id; + memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr, + SAS_ADDR_SIZE); + + /* check to see if we have a valid d2h fis */ + if (fis->fis_type != 0x34) + return; + + /* the d2h fis is required by the standard to be in LE format */ + for (i = 0; i < 20; i += 4) { + u8 *dst = resp_data + 24 + i, *src = + &sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i]; + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; + } +} + +static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id, + u8 phy_op, enum sas_linkrate min, + enum sas_linkrate max, u8 *resp_data) +{ + struct sas_internal *i = + to_sas_internal(sas_ha->core.shost->transportt); + struct sas_phy_linkrates rates; + + if (phy_id >= sas_ha->num_phys) { + resp_data[2] = SMP_RESP_NO_PHY; + return; + } + switch (phy_op) { + case PHY_FUNC_NOP: + case PHY_FUNC_LINK_RESET: + case PHY_FUNC_HARD_RESET: + case PHY_FUNC_DISABLE: + case PHY_FUNC_CLEAR_ERROR_LOG: + case PHY_FUNC_CLEAR_AFFIL: + case PHY_FUNC_TX_SATA_PS_SIGNAL: + break; + + default: + resp_data[2] = SMP_RESP_PHY_UNK_OP; + return; + } + + rates.minimum_linkrate = min; + rates.maximum_linkrate = max; + + if (i->dft->lldd_control_phy(sas_ha->sas_phy[phy_id], phy_op, &rates)) + resp_data[2] = SMP_RESP_FUNC_FAILED; + else + resp_data[2] = SMP_RESP_FUNC_ACC; +} + +int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, + struct request *rsp) +{ + u8 *req_data = NULL, *resp_data = NULL, *buf; + struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); + int error = -EINVAL, resp_data_len = rsp->data_len; + + /* eight is the minimum size for request and response frames */ + if (req->data_len < 8 || rsp->data_len < 8) + goto out; + + if (bio_offset(req->bio) + req->data_len > PAGE_SIZE || + bio_offset(rsp->bio) + rsp->data_len > PAGE_SIZE) { + shost_printk(KERN_ERR, shost, + "SMP request/response frame crosses page boundary"); + goto out; + } + + req_data = kzalloc(req->data_len, GFP_KERNEL); + + /* make sure frame can always be built ... we copy + * back only the requested length */ + resp_data = kzalloc(max(rsp->data_len, 128U), GFP_KERNEL); + + if (!req_data || !resp_data) { + error = -ENOMEM; + goto out; + } + + local_irq_disable(); + buf = kmap_atomic(bio_page(req->bio), KM_USER0) + bio_offset(req->bio); + memcpy(req_data, buf, req->data_len); + kunmap_atomic(buf - bio_offset(req->bio), KM_USER0); + local_irq_enable(); + + if (req_data[0] != SMP_REQUEST) + goto out; + + /* always succeeds ... even if we can't process the request + * the result is in the response frame */ + error = 0; + + /* set up default don't know response */ + resp_data[0] = SMP_RESPONSE; + resp_data[1] = req_data[1]; + resp_data[2] = SMP_RESP_FUNC_UNK; + + switch (req_data[1]) { + case SMP_REPORT_GENERAL: + req->data_len -= 8; + resp_data_len -= 32; + resp_data[2] = SMP_RESP_FUNC_ACC; + resp_data[9] = sas_ha->num_phys; + break; + + case SMP_REPORT_MANUF_INFO: + req->data_len -= 8; + resp_data_len -= 64; + resp_data[2] = SMP_RESP_FUNC_ACC; + memcpy(resp_data + 12, shost->hostt->name, + SAS_EXPANDER_VENDOR_ID_LEN); + memcpy(resp_data + 20, "libsas virt phy", + SAS_EXPANDER_PRODUCT_ID_LEN); + break; + + case SMP_READ_GPIO_REG: + /* FIXME: need GPIO support in the transport class */ + break; + + case SMP_DISCOVER: + req->data_len =- 16; + if (req->data_len < 0) { + req->data_len = 0; + error = -EINVAL; + goto out; + } + resp_data_len -= 56; + sas_host_smp_discover(sas_ha, resp_data, req_data[9]); + break; + + case SMP_REPORT_PHY_ERR_LOG: + /* FIXME: could implement this with additional + * libsas callbacks providing the HW supports it */ + break; + + case SMP_REPORT_PHY_SATA: + req->data_len =- 16; + if (req->data_len < 0) { + req->data_len = 0; + error = -EINVAL; + goto out; + } + resp_data_len -= 60; + sas_report_phy_sata(sas_ha, resp_data, req_data[9]); + break; + + case SMP_REPORT_ROUTE_INFO: + /* Can't implement; hosts have no routes */ + break; + + case SMP_WRITE_GPIO_REG: + /* FIXME: need GPIO support in the transport class */ + break; + + case SMP_CONF_ROUTE_INFO: + /* Can't implement; hosts have no routes */ + break; + + case SMP_PHY_CONTROL: + req->data_len =- 44; + if (req->data_len < 0) { + req->data_len = 0; + error = -EINVAL; + goto out; + } + resp_data_len -= 8; + sas_phy_control(sas_ha, req_data[9], req_data[10], + req_data[32] >> 4, req_data[33] >> 4, + resp_data); + break; + + case SMP_PHY_TEST_FUNCTION: + /* FIXME: should this be implemented? */ + break; + + default: + /* probably a 2.0 function */ + break; + } + + local_irq_disable(); + buf = kmap_atomic(bio_page(rsp->bio), KM_USER0) + bio_offset(rsp->bio); + memcpy(buf, resp_data, rsp->data_len); + flush_kernel_dcache_page(bio_page(rsp->bio)); + kunmap_atomic(buf - bio_offset(rsp->bio), KM_USER0); + local_irq_enable(); + rsp->data_len = resp_data_len; + + out: + kfree(req_data); + kfree(resp_data); + return error; +} diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 2b8213b1832d..b4f9368f116a 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -45,7 +45,7 @@ void sas_scsi_recover_host(struct Scsi_Host *shost); int sas_show_class(enum sas_class class, char *buf); -int sas_show_proto(enum sas_proto proto, char *buf); +int sas_show_proto(enum sas_protocol proto, char *buf); int sas_show_linkrate(enum sas_linkrate linkrate, char *buf); int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); @@ -80,6 +80,20 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); void sas_hae_reset(struct work_struct *work); +#ifdef CONFIG_SCSI_SAS_HOST_SMP +extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, + struct request *rsp); +#else +static inline int sas_smp_host_handler(struct Scsi_Host *shost, + struct request *req, + struct request *rsp) +{ + shost_printk(KERN_ERR, shost, + "Cannot send SMP to a sas host (not enabled in CONFIG)\n"); + return -EINVAL; +} +#endif + static inline void sas_queue_event(int event, spinlock_t *lock, unsigned long *pending, struct work_struct *work, diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 7663841eb4cf..f869fba86807 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -108,7 +108,7 @@ static void sas_scsi_task_done(struct sas_task *task) break; case SAM_CHECK_COND: memcpy(sc->sense_buffer, ts->buf, - max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); + min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); stat = SAM_CHECK_COND; break; default: @@ -148,7 +148,6 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, if (!task) return NULL; - *(u32 *)cmd->sense_buffer = 0; task->uldd_task = cmd; ASSIGN_SAS_TASK(cmd, task); @@ -200,6 +199,10 @@ int sas_queue_up(struct sas_task *task) */ int sas_queuecommand(struct scsi_cmnd *cmd, void (*scsi_done)(struct scsi_cmnd *)) + __releases(host->host_lock) + __acquires(dev->sata_dev.ap->lock) + __releases(dev->sata_dev.ap->lock) + __acquires(host->host_lock) { int res = 0; struct domain_device *dev = cmd_to_domain_dev(cmd); @@ -410,7 +413,7 @@ static int sas_recover_I_T(struct domain_device *dev) } /* Find the sas_phy that's attached to this device */ -struct sas_phy *find_local_sas_phy(struct domain_device *dev) +static struct sas_phy *find_local_sas_phy(struct domain_device *dev) { struct domain_device *pdev = dev->parent; struct ex_phy *exphy = NULL; @@ -464,7 +467,7 @@ int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) res = sas_phy_reset(phy, 1); if (res) SAS_DPRINTK("Bus reset of %s failed 0x%x\n", - phy->dev.kobj.k_name, + kobject_name(&phy->dev.kobj), res); if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) return SUCCESS; diff --git a/drivers/scsi/libsas/sas_task.c b/drivers/scsi/libsas/sas_task.c new file mode 100644 index 000000000000..594524d5bfa1 --- /dev/null +++ b/drivers/scsi/libsas/sas_task.c @@ -0,0 +1,36 @@ +#include <linux/kernel.h> +#include <scsi/sas.h> +#include <scsi/libsas.h> + +/* fill task_status_struct based on SSP response frame */ +void sas_ssp_task_response(struct device *dev, struct sas_task *task, + struct ssp_response_iu *iu) +{ + struct task_status_struct *tstat = &task->task_status; + + tstat->resp = SAS_TASK_COMPLETE; + + if (iu->datapres == 0) + tstat->stat = iu->status; + else if (iu->datapres == 1) + tstat->stat = iu->resp_data[3]; + else if (iu->datapres == 2) { + tstat->stat = SAM_CHECK_COND; + tstat->buf_valid_size = + min_t(int, SAS_STATUS_BUF_SIZE, + be32_to_cpu(iu->sense_data_len)); + memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size); + + if (iu->status != SAM_CHECK_COND) + dev_printk(KERN_WARNING, dev, + "dev %llx sent sense data, but " + "stat(%x) is not CHECK CONDITION\n", + SAS_ADDR(task->dev->sas_addr), + iu->status); + } + else + /* when datapres contains corrupt/unknown value... */ + tstat->stat = SAM_CHECK_COND; +} +EXPORT_SYMBOL_GPL(sas_ssp_task_response); + diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 2ad0a27dbaab..6d6a76e65a6c 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -192,18 +192,18 @@ static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md, if (dma_map) { iue = (struct iu_entry *) sc->SCp.ptr; - sg = sc->request_buffer; + sg = scsi_sglist(sc); - dprintk("%p %u %u %d\n", iue, sc->request_bufflen, - md->len, sc->use_sg); + dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc), + md->len, scsi_sg_count(sc)); - nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, + nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), DMA_BIDIRECTIONAL); if (!nsg) { - printk("fail to map %p %d\n", iue, sc->use_sg); + printk("fail to map %p %d\n", iue, scsi_sg_count(sc)); return 0; } - len = min(sc->request_bufflen, md->len); + len = min(scsi_bufflen(sc), md->len); } else len = md->len; @@ -229,10 +229,10 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, if (dma_map || ext_desc) { iue = (struct iu_entry *) sc->SCp.ptr; - sg = sc->request_buffer; + sg = scsi_sglist(sc); dprintk("%p %u %u %d %d\n", - iue, sc->request_bufflen, id->len, + iue, scsi_bufflen(sc), id->len, cmd->data_in_desc_cnt, cmd->data_out_desc_cnt); } @@ -268,13 +268,14 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, rdma: if (dma_map) { - nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL); + nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), + DMA_BIDIRECTIONAL); if (!nsg) { - eprintk("fail to map %p %d\n", iue, sc->use_sg); + eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc)); err = -EIO; goto free_mem; } - len = min(sc->request_bufflen, id->len); + len = min(scsi_bufflen(sc), id->len); } else len = id->len; @@ -425,8 +426,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, sc->SCp.ptr = info; memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE); - sc->request_bufflen = len; - sc->request_buffer = (void *) (unsigned long) addr; + sc->sdb.length = len; + sc->sdb.table.sgl = (void *) (unsigned long) addr; sc->tag = tag; err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun, cmd->tag); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index ba3ecab9baf3..f26b9538affe 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -29,7 +29,8 @@ struct lpfc_sli2_slim; #define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact the NameServer before giving up. */ #define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */ -#define LPFC_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ +#define LPFC_DEFAULT_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ +#define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */ #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ @@ -68,6 +69,7 @@ struct lpfc_dmabuf { struct list_head list; void *virt; /* virtual address ptr */ dma_addr_t phys; /* mapped address */ + uint32_t buffer_tag; /* used for tagged queue ring */ }; struct lpfc_dma_pool { @@ -272,10 +274,16 @@ struct lpfc_vport { #define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ #define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ #define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ -#define FC_RFF_NOT_SUPPORTED 0x40000 /* RFF_ID was rejected by switch */ #define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ #define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ + uint32_t ct_flags; +#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ +#define FC_CT_RNN_ID 0x2 /* RNN_ID accepted by switch */ +#define FC_CT_RSNN_NN 0x4 /* RSNN_NN accepted by switch */ +#define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ +#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ + struct list_head fc_nodes; /* Keep counters for the number of entries in each list. */ @@ -344,6 +352,7 @@ struct lpfc_vport { uint32_t cfg_discovery_threads; uint32_t cfg_log_verbose; uint32_t cfg_max_luns; + uint32_t cfg_enable_da_id; uint32_t dev_loss_tmo_changed; @@ -360,6 +369,7 @@ struct lpfc_vport { struct hbq_s { uint16_t entry_count; /* Current number of HBQ slots */ + uint16_t buffer_count; /* Current number of buffers posted */ uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ uint32_t hbqPutIdx; /* HBQ slot to use */ uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ @@ -377,6 +387,11 @@ struct hbq_s { #define LPFC_ELS_HBQ 0 #define LPFC_EXTRA_HBQ 1 +enum hba_temp_state { + HBA_NORMAL_TEMP, + HBA_OVER_TEMP +}; + struct lpfc_hba { struct lpfc_sli sli; uint32_t sli_rev; /* SLI2 or SLI3 */ @@ -457,7 +472,8 @@ struct lpfc_hba { uint64_t cfg_soft_wwnn; uint64_t cfg_soft_wwpn; uint32_t cfg_hba_queue_depth; - + uint32_t cfg_enable_hba_reset; + uint32_t cfg_enable_hba_heartbeat; lpfc_vpd_t vpd; /* vital product data */ @@ -544,8 +560,7 @@ struct lpfc_hba { struct list_head port_list; struct lpfc_vport *pport; /* physical lpfc_vport pointer */ uint16_t max_vpi; /* Maximum virtual nports */ -#define LPFC_MAX_VPI 100 /* Max number of VPI supported */ -#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */ +#define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ unsigned long *vpi_bmask; /* vpi allocation table */ /* Data structure used by fabric iocb scheduler */ @@ -563,16 +578,30 @@ struct lpfc_hba { struct dentry *hba_debugfs_root; atomic_t debugfs_vport_count; struct dentry *debug_hbqinfo; - struct dentry *debug_dumpslim; + struct dentry *debug_dumpHostSlim; + struct dentry *debug_dumpHBASlim; struct dentry *debug_slow_ring_trc; struct lpfc_debugfs_trc *slow_ring_trc; atomic_t slow_ring_trc_cnt; #endif + /* Used for deferred freeing of ELS data buffers */ + struct list_head elsbuf; + int elsbuf_cnt; + int elsbuf_prev_cnt; + + uint8_t temp_sensor_support; /* Fields used for heart beat. */ unsigned long last_completion_time; struct timer_list hb_tmofunc; uint8_t hb_outstanding; + /* + * Following bit will be set for all buffer tags which are not + * associated with any HBQ. + */ +#define QUE_BUFTAG_BIT (1<<31) + uint32_t buffer_tag_count; + enum hba_temp_state over_temp_state; }; static inline struct Scsi_Host * @@ -598,5 +627,15 @@ lpfc_is_link_up(struct lpfc_hba *phba) phba->link_state == LPFC_HBA_READY; } -#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ +#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ +#define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature + event */ +struct temp_event { + uint32_t event_type; + uint32_t event_code; + uint32_t data; +}; +#define LPFC_CRIT_TEMP 0x1 +#define LPFC_THRESHOLD_TEMP 0x2 +#define LPFC_NORMAL_TEMP 0x3 diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 80a11218b9bb..4bae4a2ed2f1 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -45,6 +45,10 @@ #define LPFC_MIN_DEVLOSS_TMO 1 #define LPFC_MAX_DEVLOSS_TMO 255 +#define LPFC_MAX_LINK_SPEED 8 +#define LPFC_LINK_SPEED_BITMAP 0x00000117 +#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8" + static void lpfc_jedec_to_ascii(int incr, char hdw[]) { @@ -86,6 +90,15 @@ lpfc_serialnum_show(struct class_device *cdev, char *buf) } static ssize_t +lpfc_temp_sensor_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support); +} + +static ssize_t lpfc_modeldesc_show(struct class_device *cdev, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -178,12 +191,9 @@ lpfc_state_show(struct class_device *cdev, char *buf) case LPFC_LINK_UP: case LPFC_CLEAR_LA: case LPFC_HBA_READY: - len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n"); + len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - "); switch (vport->port_state) { - len += snprintf(buf + len, PAGE_SIZE-len, - "initializing\n"); - break; case LPFC_LOCAL_CFG_LINK: len += snprintf(buf + len, PAGE_SIZE-len, "Configuring Link\n"); @@ -252,8 +262,7 @@ lpfc_issue_lip(struct Scsi_Host *shost) int mbxstatus = MBXERR_ERROR; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || - (vport->port_state != LPFC_VPORT_READY)) + (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); @@ -305,12 +314,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) psli = &phba->sli; + /* Wait a little for things to settle down, but not + * long enough for dev loss timeout to expire. + */ for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - /* The linkdown event takes 30 seconds to timeout. */ while (pring->txcmplq_cnt) { msleep(10); - if (cnt++ > 3000) { + if (cnt++ > 500) { /* 5 secs */ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0466 Outstanding IO when " @@ -336,6 +347,9 @@ lpfc_selective_reset(struct lpfc_hba *phba) struct completion online_compl; int status = 0; + if (!phba->cfg_enable_hba_reset) + return -EIO; + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); if (status != 0) @@ -409,6 +423,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) struct completion online_compl; int status=0; + if (!phba->cfg_enable_hba_reset) + return -EACCES; init_completion(&online_compl); if(strncmp(buf, "online", sizeof("online") - 1) == 0) { @@ -908,6 +924,8 @@ static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL); static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); +static CLASS_DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, + NULL); static char *lpfc_soft_wwn_key = "C99G71SL8032A"; @@ -971,6 +989,14 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) unsigned int i, j, cnt=count; u8 wwpn[8]; + if (!phba->cfg_enable_hba_reset) + return -EACCES; + spin_lock_irq(&phba->hbalock); + if (phba->over_temp_state == HBA_OVER_TEMP) { + spin_unlock_irq(&phba->hbalock); + return -EACCES; + } + spin_unlock_irq(&phba->hbalock); /* count may include a LF at end of string */ if (buf[cnt-1] == '\n') cnt--; @@ -1102,7 +1128,13 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" " 2 - select SLI-2 even on SLI-3 capable HBAs," " 3 - select SLI-3"); -LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality"); +int lpfc_enable_npiv = 0; +module_param(lpfc_enable_npiv, int, 0); +MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality"); +lpfc_param_show(enable_npiv); +lpfc_param_init(enable_npiv, 0, 0, 1); +static CLASS_DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, + lpfc_enable_npiv_show, NULL); /* # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear @@ -1248,6 +1280,13 @@ LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask"); /* +# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters +# objects that have been registered with the nameserver after login. +*/ +LPFC_VPORT_ATTR_R(enable_da_id, 0, 0, 1, + "Deregister nameserver objects before LOGO"); + +/* # lun_queue_depth: This parameter is used to limit the number of outstanding # commands per FCP LUN. Value range is [1,128]. Default value is 30. */ @@ -1369,7 +1408,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1, # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6]. # Default value is 0. */ -LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology"); +static int +lpfc_topology_set(struct lpfc_hba *phba, int val) +{ + int err; + uint32_t prev_val; + if (val >= 0 && val <= 6) { + prev_val = phba->cfg_topology; + phba->cfg_topology = val; + err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); + if (err) + phba->cfg_topology = prev_val; + return err; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "%d:0467 lpfc_topology attribute cannot be set to %d, " + "allowed range is [0, 6]\n", + phba->brd_no, val); + return -EINVAL; +} +static int lpfc_topology = 0; +module_param(lpfc_topology, int, 0); +MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology"); +lpfc_param_show(topology) +lpfc_param_init(topology, 0, 0, 6) +lpfc_param_store(topology) +static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, + lpfc_topology_show, lpfc_topology_store); /* # lpfc_link_speed: Link speed selection for initializing the Fibre Channel @@ -1381,7 +1446,59 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology"); # 8 = 8 Gigabaud # Value range is [0,8]. Default value is 0. */ -LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed"); +static int +lpfc_link_speed_set(struct lpfc_hba *phba, int val) +{ + int err; + uint32_t prev_val; + + if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) || + ((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) || + ((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || + ((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || + ((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb))) + return -EINVAL; + + if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED) + && (LPFC_LINK_SPEED_BITMAP & (1 << val))) { + prev_val = phba->cfg_link_speed; + phba->cfg_link_speed = val; + err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); + if (err) + phba->cfg_link_speed = prev_val; + return err; + } + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "%d:0469 lpfc_link_speed attribute cannot be set to %d, " + "allowed range is [0, 8]\n", + phba->brd_no, val); + return -EINVAL; +} + +static int lpfc_link_speed = 0; +module_param(lpfc_link_speed, int, 0); +MODULE_PARM_DESC(lpfc_link_speed, "Select link speed"); +lpfc_param_show(link_speed) +static int +lpfc_link_speed_init(struct lpfc_hba *phba, int val) +{ + if ((val >= 0 && val <= LPFC_MAX_LINK_SPEED) + && (LPFC_LINK_SPEED_BITMAP & (1 << val))) { + phba->cfg_link_speed = val; + return 0; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0454 lpfc_link_speed attribute cannot " + "be set to %d, allowed values are " + "["LPFC_LINK_SPEED_STRING"]\n", val); + phba->cfg_link_speed = 0; + return -EINVAL; +} + +lpfc_param_store(link_speed) +static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, + lpfc_link_speed_show, lpfc_link_speed_store); /* # lpfc_fcp_class: Determines FC class to use for the FCP protocol. @@ -1479,7 +1596,30 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, */ LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); +/* +# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. +# 0 = HBA resets disabled +# 1 = HBA resets enabled (default) +# Value range is [0,1]. Default value is 1. +*/ +LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver."); + +/* +# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer.. +# 0 = HBA Heartbeat disabled +# 1 = HBA Heartbeat enabled (default) +# Value range is [0,1]. Default value is 1. +*/ +LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat."); +/* + * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count + * This value can be set to values between 64 and 256. The default value is + * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer + * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE). + */ +LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, + LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_info, @@ -1494,6 +1634,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_state, &class_device_attr_num_discovered_ports, &class_device_attr_lpfc_drvr_version, + &class_device_attr_lpfc_temp_sensor, &class_device_attr_lpfc_log_verbose, &class_device_attr_lpfc_lun_queue_depth, &class_device_attr_lpfc_hba_queue_depth, @@ -1530,6 +1671,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_lpfc_soft_wwnn, &class_device_attr_lpfc_soft_wwpn, &class_device_attr_lpfc_soft_wwn_enable, + &class_device_attr_lpfc_enable_hba_reset, + &class_device_attr_lpfc_enable_hba_heartbeat, + &class_device_attr_lpfc_sg_seg_cnt, NULL, }; @@ -1552,6 +1696,7 @@ struct class_device_attribute *lpfc_vport_attrs[] = { &class_device_attr_lpfc_max_luns, &class_device_attr_nport_evt_cnt, &class_device_attr_npiv_info, + &class_device_attr_lpfc_enable_da_id, NULL, }; @@ -1727,13 +1872,18 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, spin_lock_irq(&phba->hbalock); + if (phba->over_temp_state == HBA_OVER_TEMP) { + sysfs_mbox_idle(phba); + spin_unlock_irq(&phba->hbalock); + return -EACCES; + } + if (off == 0 && phba->sysfs_mbox.state == SMBOX_WRITING && phba->sysfs_mbox.offset >= 2 * sizeof(uint32_t)) { switch (phba->sysfs_mbox.mbox->mb.mbxCommand) { /* Offline only */ - case MBX_WRITE_NV: case MBX_INIT_LINK: case MBX_DOWN_LINK: case MBX_CONFIG_LINK: @@ -1744,9 +1894,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, case MBX_DUMP_CONTEXT: case MBX_RUN_DIAGS: case MBX_RESTART: - case MBX_FLASH_WR_ULA: case MBX_SET_MASK: - case MBX_SET_SLIM: case MBX_SET_DEBUG: if (!(vport->fc_flag & FC_OFFLINE_MODE)) { printk(KERN_WARNING "mbox_read:Command 0x%x " @@ -1756,6 +1904,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, spin_unlock_irq(&phba->hbalock); return -EPERM; } + case MBX_WRITE_NV: + case MBX_WRITE_VPARMS: case MBX_LOAD_SM: case MBX_READ_NV: case MBX_READ_CONFIG: @@ -1772,6 +1922,8 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, case MBX_LOAD_EXP_ROM: case MBX_BEACON: case MBX_DEL_LD_ENTRY: + case MBX_SET_VARIABLE: + case MBX_WRITE_WWN: break; case MBX_READ_SPARM64: case MBX_READ_LA: @@ -1793,6 +1945,17 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, return -EPERM; } + /* If HBA encountered an error attention, allow only DUMP + * mailbox command until the HBA is restarted. + */ + if ((phba->pport->stopped) && + (phba->sysfs_mbox.mbox->mb.mbxCommand + != MBX_DUMP_MEMORY)) { + sysfs_mbox_idle(phba); + spin_unlock_irq(&phba->hbalock); + return -EPERM; + } + phba->sysfs_mbox.mbox->vport = vport; if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { @@ -1993,7 +2156,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost) fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; } - } + } else + fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; spin_unlock_irq(shost->host_lock); } @@ -2013,7 +2177,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost) node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn); else /* fabric is local port if there is no F/FL_Port */ - node_name = wwn_to_u64(vport->fc_nodename.u.wwn); + node_name = 0; spin_unlock_irq(shost->host_lock); @@ -2337,8 +2501,6 @@ struct fc_function_template lpfc_transport_functions = { .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, .terminate_rport_io = lpfc_terminate_rport_io, - .vport_create = lpfc_vport_create, - .vport_delete = lpfc_vport_delete, .dd_fcvport_size = sizeof(struct lpfc_vport *), }; @@ -2414,21 +2576,23 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_poll_tmo_init(phba, lpfc_poll_tmo); lpfc_enable_npiv_init(phba, lpfc_enable_npiv); lpfc_use_msi_init(phba, lpfc_use_msi); + lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); + lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); phba->cfg_poll = lpfc_poll; phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; - /* - * The total number of segments is the configuration value plus 2 - * since the IOCB need a command and response bde. - */ - phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2; + lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); + /* Also reinitialize the host templates with new values. */ + lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; /* * Since the sg_tablesize is module parameter, the sg_dma_buf_size - * used to create the sg_dma_buf_pool must be dynamically calculated + * used to create the sg_dma_buf_pool must be dynamically calculated. + * 2 segments are added since the IOCB needs a command and response bde. */ phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) + - (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64)); + ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64)); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); return; } @@ -2448,5 +2612,6 @@ lpfc_get_vport_cfgparam(struct lpfc_vport *vport) lpfc_discovery_threads_init(vport, lpfc_discovery_threads); lpfc_max_luns_init(vport, lpfc_max_luns); lpfc_scan_down_init(vport, lpfc_scan_down); + lpfc_enable_da_id_init(vport, lpfc_enable_da_id); return; } diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index a599e1510710..50fcb7c930bc 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -23,6 +23,8 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param); struct fc_rport; void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); + void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, struct lpfc_dmabuf *mp); @@ -43,9 +45,9 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove); int lpfc_linkdown(struct lpfc_hba *); +void lpfc_port_link_failure(struct lpfc_vport *); void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -66,15 +68,15 @@ int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t); struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *); int lpfc_nlp_put(struct lpfc_nodelist *); +int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp); struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); void lpfc_disc_list_loopmap(struct lpfc_vport *); void lpfc_disc_start(struct lpfc_vport *); -void lpfc_disc_flush_list(struct lpfc_vport *); void lpfc_cleanup_discovery_resources(struct lpfc_vport *); +void lpfc_cleanup(struct lpfc_vport *); void lpfc_disc_timeout(unsigned long); struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); -struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); void lpfc_worker_wake_up(struct lpfc_hba *); int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); @@ -82,17 +84,17 @@ int lpfc_do_work(void *); int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t); -void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, - struct lpfc_nodelist *); void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, struct serv_parm *, uint32_t); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); +void lpfc_more_plogi(struct lpfc_vport *); +void lpfc_more_adisc(struct lpfc_vport *); +void lpfc_end_rscn(struct lpfc_vport *); int lpfc_els_chk_latt(struct lpfc_vport *); int lpfc_els_abort_flogi(struct lpfc_hba *); int lpfc_initial_flogi(struct lpfc_vport *); int lpfc_initial_fdisc(struct lpfc_vport *); -int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t); int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); @@ -112,7 +114,6 @@ int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *, void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_els_retry_delay(unsigned long); void lpfc_els_retry_delay_handler(struct lpfc_nodelist *); -void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *); void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); int lpfc_els_handle_rscn(struct lpfc_vport *); @@ -124,7 +125,6 @@ int lpfc_els_disc_adisc(struct lpfc_vport *); int lpfc_els_disc_plogi(struct lpfc_vport *); void lpfc_els_timeout(unsigned long); void lpfc_els_timeout_handler(struct lpfc_vport *); -void lpfc_hb_timeout(unsigned long); void lpfc_hb_timeout_handler(struct lpfc_hba *); void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, @@ -142,7 +142,6 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *); int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); int lpfc_online(struct lpfc_hba *); -void lpfc_block_mgmt_io(struct lpfc_hba *); void lpfc_unblock_mgmt_io(struct lpfc_hba *); void lpfc_offline_prep(struct lpfc_hba *); void lpfc_offline(struct lpfc_hba *); @@ -165,7 +164,6 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int); void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *, uint32_t , LPFC_MBOXQ_t *); -struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t); struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *); void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *); @@ -178,7 +176,6 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba); void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba); struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); -void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); void lpfc_reset_barrier(struct lpfc_hba * phba); @@ -204,11 +201,14 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, struct lpfc_sli_ring *, dma_addr_t); + +uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *); +struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *, + struct lpfc_sli_ring *, uint32_t ); + int lpfc_sli_hbq_count(void); -int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t); int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); -struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t); int lpfc_sli_hbq_size(void); int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); @@ -219,9 +219,6 @@ int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, void lpfc_mbox_timeout(unsigned long); void lpfc_mbox_timeout_handler(struct lpfc_hba *); -struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter, - void *); -struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *); struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, struct lpfc_name *); @@ -260,6 +257,7 @@ extern struct scsi_host_template lpfc_vport_template; extern struct fc_function_template lpfc_transport_functions; extern struct fc_function_template lpfc_vport_transport_functions; extern int lpfc_sli_mode; +extern int lpfc_enable_npiv; int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); void lpfc_terminate_rport_io(struct fc_rport *); @@ -281,11 +279,8 @@ extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t, extern struct lpfc_hbq_init *lpfc_hbq_defs[]; /* Interface exported by fabric iocb scheduler */ -int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *); -void lpfc_fabric_abort_vport(struct lpfc_vport *); void lpfc_fabric_abort_nport(struct lpfc_nodelist *); void lpfc_fabric_abort_hba(struct lpfc_hba *); -void lpfc_fabric_abort_flogi(struct lpfc_hba *); void lpfc_fabric_block_timeout(unsigned long); void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); void lpfc_adjust_queue_depth(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index c701e4d611a9..92441ce610ed 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -19,7 +19,7 @@ *******************************************************************/ /* - * Fibre Channel SCSI LAN Device Driver CT support + * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS */ #include <linux/blkdev.h> @@ -57,45 +57,27 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION; -/* - * lpfc_ct_unsol_event - */ static void -lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_dmabuf *mp, uint32_t size) +lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct lpfc_dmabuf *mp, uint32_t size) { if (!mp) { - printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, " - "piocbq = %p, status = x%x, mp = %p, size = %d\n", - __FUNCTION__, __LINE__, - piocbq, piocbq->iocb.ulpStatus, mp, size); + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "0146 Ignoring unsolicted CT No HBQ " + "status = x%x\n", + piocbq->iocb.ulpStatus); } - - printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, " - "buffer = %p, size = %d, status = x%x\n", - __FUNCTION__, __LINE__, - piocbq, mp, size, - piocbq->iocb.ulpStatus); - + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "0145 Ignoring unsolicted CT HBQ Size:%d " + "status = x%x\n", + size, piocbq->iocb.ulpStatus); } static void -lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_dmabuf *mp, uint32_t size) +lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct lpfc_dmabuf *mp, uint32_t size) { - if (!mp) { - printk(KERN_ERR "%s (%d): Unsolited CT, no " - "HBQ buffer, piocbq = %p, status = x%x\n", - __FUNCTION__, __LINE__, - piocbq, piocbq->iocb.ulpStatus); - } else { - lpfc_ct_unsol_buffer(phba, piocbq, mp, size); - printk(KERN_ERR "%s (%d): Ignoring unsolicted CT " - "piocbq = %p, buffer = %p, size = %d, " - "status = x%x\n", - __FUNCTION__, __LINE__, - piocbq, mp, size, piocbq->iocb.ulpStatus); - } + lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); } void @@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *iocbq; dma_addr_t paddr; uint32_t size; - struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; - struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; - - piocbq->context2 = NULL; - piocbq->context3 = NULL; + struct list_head head; + struct lpfc_dmabuf *bdeBuf; if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); @@ -122,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* Not enough posted buffers; Try posting more buffers */ phba->fc_stat.NoRcvBuf++; if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, pring, 0, 1); + lpfc_post_buffer(phba, pring, 2, 1); return; } @@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - list_for_each_entry(iocbq, &piocbq->list, list) { + INIT_LIST_HEAD(&head); + list_add_tail(&head, &piocbq->list); + list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) { - printk(KERN_ERR "%s (%d): Unsolited CT, no " - "BDE, iocbq = %p, status = x%x\n", - __FUNCTION__, __LINE__, - iocbq, iocbq->iocb.ulpStatus); + if (icmd->ulpBdeCount == 0) continue; - } - + bdeBuf = iocbq->context2; + iocbq->context2 = NULL; size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size); - lpfc_in_buf_free(phba, bdeBuf1); + lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); + lpfc_in_buf_free(phba, bdeBuf); if (icmd->ulpBdeCount == 2) { - lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2, - size); - lpfc_in_buf_free(phba, bdeBuf2); + bdeBuf = iocbq->context3; + iocbq->context3 = NULL; + size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; + lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, + size); + lpfc_in_buf_free(phba, bdeBuf); } } + list_del(&head); } else { struct lpfc_iocbq *next; list_for_each_entry_safe(iocbq, next, &piocbq->list, list) { icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) { - printk(KERN_ERR "%s (%d): Unsolited CT, no " - "BDE, iocbq = %p, status = x%x\n", - __FUNCTION__, __LINE__, - iocbq, iocbq->iocb.ulpStatus); - continue; - } - + if (icmd->ulpBdeCount == 0) + lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0); for (i = 0; i < icmd->ulpBdeCount; i++) { paddr = getPaddr(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow); @@ -176,6 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } list_del(&iocbq->list); lpfc_sli_release_iocbq(phba, iocbq); + lpfc_post_buffer(phba, pring, i, 1); } } } @@ -203,7 +179,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, struct lpfc_dmabuf *mp; int cnt, i = 0; - /* We get chucks of FCELSSIZE */ + /* We get chunks of FCELSSIZE */ cnt = size > FCELSSIZE ? FCELSSIZE: size; while (size) { @@ -426,6 +402,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) lpfc_set_disctmo(vport); vport->num_disc_nodes = 0; + vport->fc_ns_retry = 0; list_add_tail(&head, &mp->list); @@ -458,7 +435,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) ((lpfc_find_vport_by_did(phba, Did) == NULL) || vport->cfg_peer_port_login)) { if ((vport->port_type != LPFC_NPIV_PORT) || - (vport->fc_flag & FC_RFF_NOT_SUPPORTED) || + (!(vport->ct_flags & FC_CT_RFF_ID)) || (!vport->cfg_restrict_login)) { ndlp = lpfc_setup_disc_node(vport, Did); if (ndlp) { @@ -506,7 +483,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) Did, vport->fc_flag, vport->fc_rscn_id_cnt); - if (lpfc_ns_cmd(vport, + /* This NPortID was previously + * a FCP target, * Don't even + * bother to send GFF_ID. + */ + ndlp = lpfc_findnode_did(vport, + Did); + if (ndlp && (ndlp->nlp_type & + NLP_FCP_TARGET)) + lpfc_setup_disc_node + (vport, Did); + else if (lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, 0, Did) == 0) vport->num_disc_nodes++; @@ -554,7 +541,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_nodelist *ndlp; - int rc; + int rc, retry; /* First save ndlp, before we overwrite it */ ndlp = cmdiocb->context_un.ndlp; @@ -574,7 +561,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (vport->load_flag & FC_UNLOADING) goto out; - if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0216 Link event during NS query\n"); @@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (irsp->ulpStatus) { /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - (irsp->un.ulpWord[4] != IOERR_NO_RESOURCES)) + retry = 1; + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (irsp->un.ulpWord[4]) { + case IOERR_NO_RESOURCES: + /* We don't increment the retry + * count for this case. + */ + break; + case IOERR_LINK_DOWN: + case IOERR_SLI_ABORTED: + case IOERR_SLI_DOWN: + retry = 0; + break; + default: + vport->fc_ns_retry++; + } + } + else vport->fc_ns_retry++; - /* CT command is being retried */ - rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, + + if (retry) { + /* CT command is being retried */ + rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, vport->fc_ns_retry, 0); - if (rc == 0) - goto out; + if (rc == 0) { + /* success */ + goto out; + } + } } lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, @@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; struct lpfc_sli_ct_request *CTrsp; - int did; + int did, rc, retry; uint8_t fbits; struct lpfc_nodelist *ndlp; @@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } else { + /* Check for retry */ + if (cmdiocb->retry < LPFC_MAX_NS_RETRY) { + retry = 1; + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (irsp->un.ulpWord[4]) { + case IOERR_NO_RESOURCES: + /* We don't increment the retry + * count for this case. + */ + break; + case IOERR_LINK_DOWN: + case IOERR_SLI_ABORTED: + case IOERR_SLI_DOWN: + retry = 0; + break; + default: + cmdiocb->retry++; + } + } + else + cmdiocb->retry++; + + if (retry) { + /* CT command is being retried */ + rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, + cmdiocb->retry, did); + if (rc == 0) { + /* success */ + lpfc_ct_free_iocb(phba, cmdiocb); + return; + } + } + } lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0267 NameServer GFF Rsp " "x%x Error (%d %d) Data: x%x x%x\n", @@ -778,8 +818,8 @@ out: static void -lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) +lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) { struct lpfc_vport *vport = cmdiocb->vport; struct lpfc_dmabuf *inp; @@ -809,7 +849,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0209 RFT request completes, latt %d, " + "0209 CT Request completes, latt %d, " "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n", latt, irsp->ulpStatus, CTrsp->CommandResponse.bits.CmdRsp, @@ -848,10 +888,44 @@ out: } static void +lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RFT_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); + return; +} + +static void lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RNN_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -859,7 +933,20 @@ static void lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RSPN_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -867,7 +954,32 @@ static void lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) { - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + IOCB_t *irsp = &rspiocb->iocb; + struct lpfc_vport *vport = cmdiocb->vport; + + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; + + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RSNN_NN; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); + return; +} + +static void +lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + + /* even if it fails we will act as though it succeeded. */ + vport->ct_flags = 0; + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -878,10 +990,17 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp = &rspiocb->iocb; struct lpfc_vport *vport = cmdiocb->vport; - if (irsp->ulpStatus != IOSTAT_SUCCESS) - vport->fc_flag |= FC_RFF_NOT_SUPPORTED; + if (irsp->ulpStatus == IOSTAT_SUCCESS) { + struct lpfc_dmabuf *outp; + struct lpfc_sli_ct_request *CTrsp; - lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb); + outp = (struct lpfc_dmabuf *) cmdiocb->context2; + CTrsp = (struct lpfc_sli_ct_request *) outp->virt; + if (CTrsp->CommandResponse.bits.CmdRsp == + be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) + vport->ct_flags |= FC_CT_RFF_ID; + } + lpfc_cmpl_ct(phba, cmdiocb, rspiocb); return; } @@ -1001,6 +1120,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; + else if (cmdcode == SLI_CTNS_DA_ID) + bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFF_ID) bpl->tus.f.bdeSize = RFF_REQUEST_SZ; else @@ -1029,31 +1150,34 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_GFF_ID: CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_GFF_ID); - CtReq->un.gff.PortId = be32_to_cpu(context); + CtReq->un.gff.PortId = cpu_to_be32(context); cmpl = lpfc_cmpl_ct_cmd_gff_id; break; case SLI_CTNS_RFT_ID: + vport->ct_flags &= ~FC_CT_RFT_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RFT_ID); - CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID); + CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID); CtReq->un.rft.fcpReg = 1; cmpl = lpfc_cmpl_ct_cmd_rft_id; break; case SLI_CTNS_RNN_ID: + vport->ct_flags &= ~FC_CT_RNN_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RNN_ID); - CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID); + CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID); memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename, sizeof (struct lpfc_name)); cmpl = lpfc_cmpl_ct_cmd_rnn_id; break; case SLI_CTNS_RSPN_ID: + vport->ct_flags &= ~FC_CT_RSPN_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RSPN_ID); - CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID); + CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID); size = sizeof(CtReq->un.rspn.symbname); CtReq->un.rspn.len = lpfc_vport_symbolic_port_name(vport, @@ -1061,6 +1185,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, cmpl = lpfc_cmpl_ct_cmd_rspn_id; break; case SLI_CTNS_RSNN_NN: + vport->ct_flags &= ~FC_CT_RSNN_NN; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RSNN_NN); memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename, @@ -1071,11 +1196,18 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, CtReq->un.rsnn.symbname, size); cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; break; + case SLI_CTNS_DA_ID: + /* Implement DA_ID Nameserver request */ + CtReq->CommandResponse.bits.CmdRsp = + be16_to_cpu(SLI_CTNS_DA_ID); + CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID); + cmpl = lpfc_cmpl_ct_cmd_da_id; + break; case SLI_CTNS_RFF_ID: - vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED; + vport->ct_flags &= ~FC_CT_RFF_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RFF_ID); - CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);; + CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID);; CtReq->un.rff.fbits = FC4_FEATURE_INIT; CtReq->un.rff.type_code = FC_FCP_DATA; cmpl = lpfc_cmpl_ct_cmd_rff_id; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index d6a98bc970ff..783d1eea13ef 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -43,6 +43,7 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_version.h" +#include "lpfc_compat.h" #include "lpfc_debugfs.h" #ifdef CONFIG_LPFC_DEBUG_FS @@ -75,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0); MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services"); /* This MUST be a power of 2 */ -static int lpfc_debugfs_max_disc_trc = 0; +static int lpfc_debugfs_max_disc_trc; module_param(lpfc_debugfs_max_disc_trc, int, 0); MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc, "Set debugfs discovery trace depth"); /* This MUST be a power of 2 */ -static int lpfc_debugfs_max_slow_ring_trc = 0; +static int lpfc_debugfs_max_slow_ring_trc; module_param(lpfc_debugfs_max_slow_ring_trc, int, 0); MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc, "Set debugfs slow ring trace depth"); -static int lpfc_debugfs_mask_disc_trc = 0; +int lpfc_debugfs_mask_disc_trc; module_param(lpfc_debugfs_mask_disc_trc, int, 0); MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, "Set debugfs discovery trace mask"); @@ -100,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, #define LPFC_NODELIST_SIZE 8192 #define LPFC_NODELIST_ENTRY_SIZE 120 -/* dumpslim output buffer size */ -#define LPFC_DUMPSLIM_SIZE 4096 +/* dumpHBASlim output buffer size */ +#define LPFC_DUMPHBASLIM_SIZE 4096 + +/* dumpHostSlim output buffer size */ +#define LPFC_DUMPHOSTSLIM_SIZE 4096 /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 @@ -243,16 +247,17 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) raw_index = phba->hbq_get[i]; getidx = le32_to_cpu(raw_index); len += snprintf(buf+len, size-len, - "entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", - hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx, - hbqs->local_hbqGetIdx, getidx); + "entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", + hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, + hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; for (j=0; j<hbqs->entry_count; j++) { len += snprintf(buf+len, size-len, "%03d: %08x %04x %05x ", j, - hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag); - + le32_to_cpu(hbqe->bde.addrLow), + le32_to_cpu(hbqe->bde.tus.w), + le32_to_cpu(hbqe->buffer_tag)); i = 0; found = 0; @@ -276,7 +281,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); - if (phys == hbqe->bde.addrLow) { + if (phys == le32_to_cpu(hbqe->bde.addrLow)) { len += snprintf(buf+len, size-len, "Buf%d: %p %06x\n", i, hbq_buf->dbuf.virt, hbq_buf->tag); @@ -297,18 +302,58 @@ skipit: return len; } +static int lpfc_debugfs_last_hba_slim_off; + +static int +lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) +{ + int len = 0; + int i, off; + uint32_t *ptr; + char buffer[1024]; + + off = 0; + spin_lock_irq(&phba->hbalock); + + len += snprintf(buf+len, size-len, "HBA SLIM\n"); + lpfc_memcpy_from_slim(buffer, + ((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off, + 1024); + + ptr = (uint32_t *)&buffer[0]; + off = lpfc_debugfs_last_hba_slim_off; + + /* Set it up for the next time */ + lpfc_debugfs_last_hba_slim_off += 1024; + if (lpfc_debugfs_last_hba_slim_off >= 4096) + lpfc_debugfs_last_hba_slim_off = 0; + + i = 1024; + while (i > 0) { + len += snprintf(buf+len, size-len, + "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", + off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), + *(ptr+5), *(ptr+6), *(ptr+7)); + ptr += 8; + i -= (8 * sizeof(uint32_t)); + off += (8 * sizeof(uint32_t)); + } + + spin_unlock_irq(&phba->hbalock); + return len; +} + static int -lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size) +lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) { int len = 0; - int cnt, i, off; + int i, off; uint32_t word0, word1, word2, word3; uint32_t *ptr; struct lpfc_pgp *pgpp; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - cnt = LPFC_DUMPSLIM_SIZE; off = 0; spin_lock_irq(&phba->hbalock); @@ -620,7 +665,34 @@ out: } static int -lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file) +lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file) +{ + struct lpfc_hba *phba = inode->i_private; + struct lpfc_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + /* Round to page boundry */ + debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer, + LPFC_DUMPHBASLIM_SIZE); + file->private_data = debug; + + rc = 0; +out: + return rc; +} + +static int +lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file) { struct lpfc_hba *phba = inode->i_private; struct lpfc_debug *debug; @@ -631,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file) goto out; /* Round to page boundry */ - debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL); + debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL); if (!debug->buffer) { kfree(debug); goto out; } - debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer, - LPFC_DUMPSLIM_SIZE); + debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer, + LPFC_DUMPHOSTSLIM_SIZE); file->private_data = debug; rc = 0; @@ -741,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_dumpslim -static struct file_operations lpfc_debugfs_op_dumpslim = { +#undef lpfc_debugfs_op_dumpHBASlim +static struct file_operations lpfc_debugfs_op_dumpHBASlim = { + .owner = THIS_MODULE, + .open = lpfc_debugfs_dumpHBASlim_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_debugfs_read, + .release = lpfc_debugfs_release, +}; + +#undef lpfc_debugfs_op_dumpHostSlim +static struct file_operations lpfc_debugfs_op_dumpHostSlim = { .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpslim_open, + .open = lpfc_debugfs_dumpHostSlim_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_read, .release = lpfc_debugfs_release, @@ -812,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } - /* Setup dumpslim */ - snprintf(name, sizeof(name), "dumpslim"); - phba->debug_dumpslim = + /* Setup dumpHBASlim */ + snprintf(name, sizeof(name), "dumpHBASlim"); + phba->debug_dumpHBASlim = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dumpHBASlim); + if (!phba->debug_dumpHBASlim) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0409 Cannot create debugfs dumpHBASlim\n"); + goto debug_failed; + } + + /* Setup dumpHostSlim */ + snprintf(name, sizeof(name), "dumpHostSlim"); + phba->debug_dumpHostSlim = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpslim); - if (!phba->debug_dumpslim) { + phba, &lpfc_debugfs_op_dumpHostSlim); + if (!phba->debug_dumpHostSlim) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0409 Cannot create debugfs dumpslim\n"); + "0409 Cannot create debugfs dumpHostSlim\n"); goto debug_failed; } @@ -970,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ phba->debug_hbqinfo = NULL; } - if (phba->debug_dumpslim) { - debugfs_remove(phba->debug_dumpslim); /* dumpslim */ - phba->debug_dumpslim = NULL; + if (phba->debug_dumpHBASlim) { + debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */ + phba->debug_dumpHBASlim = NULL; + } + if (phba->debug_dumpHostSlim) { + debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ + phba->debug_dumpHostSlim = NULL; } if (phba->slow_ring_trc) { kfree(phba->slow_ring_trc); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index aacac9ac5381..cfe81c50529a 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -36,7 +36,6 @@ enum lpfc_work_type { LPFC_EVT_WARM_START, LPFC_EVT_KILL, LPFC_EVT_ELS_RETRY, - LPFC_EVT_DEV_LOSS_DELAY, LPFC_EVT_DEV_LOSS, }; @@ -92,6 +91,7 @@ struct lpfc_nodelist { #define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */ #define NLP_RNID_SND 0x400 /* sent RNID request for this entry */ #define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */ +#define NLP_DEFER_RM 0x10000 /* Remove this ndlp if no longer used */ #define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */ #define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */ #define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8085900635d4..c6b739dc6bc3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -18,7 +18,7 @@ * more details, a copy of which can be found in the file COPYING * * included with this package. * *******************************************************************/ - +/* See Fibre Channel protocol T11 FC-LS for details */ #include <linux/blkdev.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -42,6 +42,14 @@ static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); +static void lpfc_fabric_abort_vport(struct lpfc_vport *vport); +static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, uint8_t retry); +static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, + struct lpfc_iocbq *iocb); +static void lpfc_register_new_vport(struct lpfc_hba *phba, + struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp); static int lpfc_max_els_tries = 3; @@ -109,14 +117,11 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, /* fill in BDEs for command */ /* Allocate buffer for command payload */ - if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) || - ((pcmd->virt = lpfc_mbuf_alloc(phba, - MEM_PRI, &(pcmd->phys))) == 0)) { - kfree(pcmd); - - lpfc_sli_release_iocbq(phba, elsiocb); - return NULL; - } + pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (pcmd) + pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); + if (!pcmd || !pcmd->virt) + goto els_iocb_free_pcmb_exit; INIT_LIST_HEAD(&pcmd->list); @@ -126,13 +131,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (prsp) prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &prsp->phys); - if (prsp == 0 || prsp->virt == 0) { - kfree(prsp); - lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); - kfree(pcmd); - lpfc_sli_release_iocbq(phba, elsiocb); - return NULL; - } + if (!prsp || !prsp->virt) + goto els_iocb_free_prsp_exit; INIT_LIST_HEAD(&prsp->list); } else { prsp = NULL; @@ -143,15 +143,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (pbuflist) pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pbuflist->phys); - if (pbuflist == 0 || pbuflist->virt == 0) { - lpfc_sli_release_iocbq(phba, elsiocb); - lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); - lpfc_mbuf_free(phba, prsp->virt, prsp->phys); - kfree(pcmd); - kfree(prsp); - kfree(pbuflist); - return NULL; - } + if (!pbuflist || !pbuflist->virt) + goto els_iocb_free_pbuf_exit; INIT_LIST_HEAD(&pbuflist->list); @@ -196,7 +189,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, bpl->tus.w = le32_to_cpu(bpl->tus.w); } + /* prevent preparing iocb with NULL ndlp reference */ elsiocb->context1 = lpfc_nlp_get(ndlp); + if (!elsiocb->context1) + goto els_iocb_free_pbuf_exit; elsiocb->context2 = pcmd; elsiocb->context3 = pbuflist; elsiocb->retry = retry; @@ -222,8 +218,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, cmdSize); } return elsiocb; -} +els_iocb_free_pbuf_exit: + lpfc_mbuf_free(phba, prsp->virt, prsp->phys); + kfree(pbuflist); + +els_iocb_free_prsp_exit: + lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); + kfree(prsp); + +els_iocb_free_pcmb_exit: + kfree(pcmd); + lpfc_sli_release_iocbq(phba, elsiocb); + return NULL; +} static int lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) @@ -234,40 +242,53 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp; struct serv_parm *sp; int rc; + int err = 0; sp = &phba->fc_fabparam; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) + if (!ndlp) { + err = 1; goto fail; + } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (!mbox) { + err = 2; goto fail; + } vport->port_state = LPFC_FABRIC_CFG_LINK; lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); - if (rc == MBX_NOT_FINISHED) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + err = 3; goto fail_free_mbox; + } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (!mbox) { + err = 4; goto fail; + } rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0); - if (rc) + if (rc) { + err = 5; goto fail_free_mbox; + } mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); - if (rc == MBX_NOT_FINISHED) + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + err = 6; goto fail_issue_reg_login; + } return 0; @@ -282,7 +303,7 @@ fail_free_mbox: fail: lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0249 Cannot issue Register Fabric login\n"); + "0249 Cannot issue Register Fabric login: Err %d\n", err); return -ENXIO; } @@ -370,11 +391,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } } - ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID; lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && @@ -429,8 +451,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, - MBX_NOWAIT | MBX_STOP_IOCB); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); goto fail; @@ -463,6 +484,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_nlp_put(ndlp); } + /* If we are pt2pt with another NPort, force NPIV off! */ + phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT; spin_unlock_irq(shost->host_lock); @@ -488,6 +512,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { + /* One additional decrement on node reference count to + * trigger the release of the node + */ lpfc_nlp_put(ndlp); goto out; } @@ -562,8 +589,13 @@ flogifail: /* Start discovery */ lpfc_disc_start(vport); + } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || + ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) && + (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) && + (phba->link_state != LPFC_CLEAR_LA)) { + /* If FLOGI failed enable link interrupt. */ + lpfc_issue_clear_la(phba, vport); } - out: lpfc_els_free_iocb(phba, cmdiocb); } @@ -685,6 +717,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) { @@ -696,7 +731,11 @@ lpfc_initial_flogi(struct lpfc_vport *vport) } else { lpfc_dequeue_node(vport, ndlp); } + if (lpfc_issue_els_flogi(vport, ndlp, 0)) { + /* This decrement of reference count to node shall kick off + * the release of the node. + */ lpfc_nlp_put(ndlp); } return 1; @@ -720,11 +759,16 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) lpfc_dequeue_node(vport, ndlp); } if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { + /* decrement node reference count to trigger the release of + * the node. + */ lpfc_nlp_put(ndlp); + return 0; } return 1; } -static void + +void lpfc_more_plogi(struct lpfc_vport *vport) { int sentplogi; @@ -752,6 +796,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, { struct lpfc_vport *vport = ndlp->vport; struct lpfc_nodelist *new_ndlp; + struct lpfc_rport_data *rdata; + struct fc_rport *rport; struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; uint32_t rc; @@ -788,11 +834,34 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, lpfc_unreg_rpi(vport, new_ndlp); new_ndlp->nlp_DID = ndlp->nlp_DID; new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; + + if (ndlp->nlp_flag & NLP_NPR_2B_DISC) + new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); /* Move this back to NPR state */ - if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) + if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { + /* The new_ndlp is replacing ndlp totally, so we need + * to put ndlp on UNUSED list and try to free it. + */ + + /* Fix up the rport accordingly */ + rport = ndlp->rport; + if (rport) { + rdata = rport->dd_data; + if (rdata->pnode == ndlp) { + lpfc_nlp_put(ndlp); + ndlp->rport = NULL; + rdata->pnode = lpfc_nlp_get(new_ndlp); + new_ndlp->rport = rport; + } + new_ndlp->nlp_type = ndlp->nlp_type; + } + lpfc_drop_node(vport, ndlp); + } else { lpfc_unreg_rpi(vport, ndlp); ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ @@ -801,6 +870,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, return new_ndlp; } +void +lpfc_end_rscn(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (vport->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs came in while we were + * processing this one. + */ + if (vport->fc_rscn_id_cnt || + (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) + lpfc_els_handle_rscn(vport); + else { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(shost->host_lock); + } + } +} + static void lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) @@ -871,13 +961,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } /* PLOGI failed */ - if (ndlp->nlp_DID == NameServer_DID) { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0250 Nameserver login error: " - "0x%x / 0x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4]); - } /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ if (lpfc_error_lost_link(irsp)) { rc = NLP_STE_FREED_NODE; @@ -905,20 +988,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while - * we were processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } } @@ -933,6 +1003,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) struct lpfc_hba *phba = vport->phba; struct serv_parm *sp; IOCB_t *icmd; + struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; @@ -943,8 +1014,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ + ndlp = lpfc_findnode_did(vport, did); + /* If ndlp if not NULL, we will bump the reference count on it */ + cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did, + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; @@ -1109,7 +1183,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 0; } -static void +void lpfc_more_adisc(struct lpfc_vport *vport) { int sentadisc; @@ -1134,8 +1208,6 @@ lpfc_more_adisc(struct lpfc_vport *vport) static void lpfc_rscn_disc(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - lpfc_can_disctmo(vport); /* RSCN discovery */ @@ -1144,19 +1216,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport) if (lpfc_els_disc_plogi(vport)) return; - if (vport->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs came in while we were - * processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } static void @@ -1413,6 +1473,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; + spin_lock_irq(shost->host_lock); + if (ndlp->nlp_flag & NLP_LOGO_SND) { + spin_unlock_irq(shost->host_lock); + return 0; + } + spin_unlock_irq(shost->host_lock); + cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_LOGO); @@ -1499,6 +1566,9 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) ndlp->nlp_DID, ELS_CMD_SCR); if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ lpfc_nlp_put(ndlp); return 1; } @@ -1520,10 +1590,17 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) phba->fc_stat.elsXmitSCR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the rlease of + * the node. + */ lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); return 1; } + /* This will cause the callback-function lpfc_cmpl_els_cmd to + * trigger the release of node. + */ lpfc_nlp_put(ndlp); return 0; } @@ -1555,6 +1632,9 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RNID); if (!elsiocb) { + /* This will trigger the release of the node just + * allocated + */ lpfc_nlp_put(ndlp); return 1; } @@ -1591,35 +1671,21 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) phba->fc_stat.elsXmitFARPR++; elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { + /* The additional lpfc_nlp_put will cause the following + * lpfc_els_free_iocb routine to trigger the release of + * the node. + */ lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); return 1; } + /* This will cause the callback-function lpfc_cmpl_els_cmd to + * trigger the release of the node. + */ lpfc_nlp_put(ndlp); return 0; } -static void -lpfc_end_rscn(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while we were - * processing this one. - */ - if (vport->fc_rscn_id_cnt || - (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) - lpfc_els_handle_rscn(vport); - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } - } -} - void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { @@ -1675,7 +1741,10 @@ lpfc_els_retry_delay(unsigned long ptr) return; } - evtp->evt_arg1 = ndlp; + /* We need to hold the node by incrementing the reference + * count until the queued work is done + */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); evtp->evt = LPFC_EVT_ELS_RETRY; list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) @@ -1759,6 +1828,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, uint32_t *elscmd; struct ls_rjt stat; int retry = 0, maxretry = lpfc_max_els_tries, delay = 0; + int logerr = 0; uint32_t cmd = 0; uint32_t did; @@ -1815,6 +1885,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case IOERR_NO_RESOURCES: + logerr = 1; /* HBA out of resources */ retry = 1; if (cmdiocb->retry > 100) delay = 100; @@ -1843,6 +1914,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: + logerr = 1; /* Fabric / Remote NPort out of resources */ retry = 1; break; @@ -1923,6 +1995,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; + if ((cmd == ELS_CMD_FLOGI) && + (phba->fc_topology != TOPOLOGY_LOOP)) { + /* FLOGI retry policy */ + retry = 1; + maxretry = 48; + if (cmdiocb->retry >= 32) + delay = 1000; + } + if ((++cmdiocb->retry) >= maxretry) { phba->fc_stat.elsRetryExceeded++; retry = 0; @@ -2006,11 +2087,46 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } /* No retry ELS command <elsCmd> to remote NPORT <did> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + if (logerr) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0137 No retry ELS command x%x to remote " + "NPORT x%x: Out of Resources: Error:x%x/%x\n", + cmd, did, irsp->ulpStatus, + irsp->un.ulpWord[4]); + } + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0108 No retry ELS command x%x to remote " "NPORT x%x Retried:%d Error:x%x/%x\n", cmd, did, cmdiocb->retry, irsp->ulpStatus, irsp->un.ulpWord[4]); + } + return 0; +} + +static int +lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1) +{ + struct lpfc_dmabuf *buf_ptr; + + /* Free the response before processing the command. */ + if (!list_empty(&buf_ptr1->list)) { + list_remove_head(&buf_ptr1->list, buf_ptr, + struct lpfc_dmabuf, + list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); + } + lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); + kfree(buf_ptr1); + return 0; +} + +static int +lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) +{ + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); return 0; } @@ -2018,30 +2134,63 @@ int lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; + struct lpfc_nodelist *ndlp; - if (elsiocb->context1) { - lpfc_nlp_put(elsiocb->context1); + ndlp = (struct lpfc_nodelist *)elsiocb->context1; + if (ndlp) { + if (ndlp->nlp_flag & NLP_DEFER_RM) { + lpfc_nlp_put(ndlp); + + /* If the ndlp is not being used by another discovery + * thread, free it. + */ + if (!lpfc_nlp_not_used(ndlp)) { + /* If ndlp is being used by another discovery + * thread, just clear NLP_DEFER_RM + */ + ndlp->nlp_flag &= ~NLP_DEFER_RM; + } + } + else + lpfc_nlp_put(ndlp); elsiocb->context1 = NULL; } /* context2 = cmd, context2->next = rsp, context3 = bpl */ if (elsiocb->context2) { - buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; - /* Free the response before processing the command. */ - if (!list_empty(&buf_ptr1->list)) { - list_remove_head(&buf_ptr1->list, buf_ptr, - struct lpfc_dmabuf, - list); - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); + if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { + /* Firmware could still be in progress of DMAing + * payload, so don't free data buffer till after + * a hbeat. + */ + elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE; + buf_ptr = elsiocb->context2; + elsiocb->context2 = NULL; + if (buf_ptr) { + buf_ptr1 = NULL; + spin_lock_irq(&phba->hbalock); + if (!list_empty(&buf_ptr->list)) { + list_remove_head(&buf_ptr->list, + buf_ptr1, struct lpfc_dmabuf, + list); + INIT_LIST_HEAD(&buf_ptr1->list); + list_add_tail(&buf_ptr1->list, + &phba->elsbuf); + phba->elsbuf_cnt++; + } + INIT_LIST_HEAD(&buf_ptr->list); + list_add_tail(&buf_ptr->list, &phba->elsbuf); + phba->elsbuf_cnt++; + spin_unlock_irq(&phba->hbalock); + } + } else { + buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; + lpfc_els_free_data(phba, buf_ptr1); } - lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); - kfree(buf_ptr1); } if (elsiocb->context3) { buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); + lpfc_els_free_bpl(phba, buf_ptr); } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -2065,15 +2214,20 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - switch (ndlp->nlp_state) { - case NLP_STE_UNUSED_NODE: /* node is just allocated */ - lpfc_drop_node(vport, ndlp); - break; - case NLP_STE_NPR_NODE: /* NPort Recovery mode */ - lpfc_unreg_rpi(vport, ndlp); - break; - default: - break; + + if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + /* NPort Recovery mode or node is just allocated */ + if (!lpfc_nlp_not_used(ndlp)) { + /* If the ndlp is being used by another discovery + * thread, just unregister the RPI. + */ + lpfc_unreg_rpi(vport, ndlp); + } else { + /* Indicate the node has already released, should + * not reference to it from within lpfc_els_free_iocb. + */ + cmdiocb->context1 = NULL; + } } lpfc_els_free_iocb(phba, cmdiocb); return; @@ -2089,7 +2243,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - lpfc_nlp_put(ndlp); + if (ndlp) { + lpfc_nlp_put(ndlp); + /* This is the end of the default RPI cleanup logic for this + * ndlp. If no other discovery threads are using this ndlp. + * we should free all resources associated with it. + */ + lpfc_nlp_not_used(ndlp); + } return; } @@ -2100,15 +2261,29 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL; struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL; - IOCB_t *irsp; + IOCB_t *irsp; + uint8_t *pcmd; LPFC_MBOXQ_t *mbox = NULL; struct lpfc_dmabuf *mp = NULL; + uint32_t ls_rjt = 0; irsp = &rspiocb->iocb; if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; + /* First determine if this is a LS_RJT cmpl. Note, this callback + * function can have cmdiocb->contest1 (ndlp) field set to NULL. + */ + pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); + if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { + /* A LS_RJT associated with Default RPI cleanup has its own + * seperate code path. + */ + if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + ls_rjt = 1; + } + /* Check to see if link went down during discovery */ if (!ndlp || lpfc_els_chk_latt(vport)) { if (mbox) { @@ -2119,6 +2294,15 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } mempool_free(mbox, phba->mbox_mem_pool); } + if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + if (lpfc_nlp_not_used(ndlp)) { + ndlp = NULL; + /* Indicate the node has already released, + * should not reference to it from within + * the routine lpfc_els_free_iocb. + */ + cmdiocb->context1 = NULL; + } goto out; } @@ -2150,20 +2334,39 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); } - if (lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) { goto out; } - lpfc_nlp_put(ndlp); - /* NOTE: we should have messages for unsuccessful - reglogin */ + + /* ELS rsp: Cannot issue reg_login for <NPortid> */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0138 ELS rsp: Cannot issue reg_login for x%x " + "Data: x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi); + + if (lpfc_nlp_not_used(ndlp)) { + ndlp = NULL; + /* Indicate node has already been released, + * should not reference to it from within + * the routine lpfc_els_free_iocb. + */ + cmdiocb->context1 = NULL; + } } else { /* Do not drop node for lpfc_els_abort'ed ELS cmds */ if (!lpfc_error_lost_link(irsp) && ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - lpfc_drop_node(vport, ndlp); - ndlp = NULL; + if (lpfc_nlp_not_used(ndlp)) { + ndlp = NULL; + /* Indicate node has already been + * released, should not reference + * to it from within the routine + * lpfc_els_free_iocb. + */ + cmdiocb->context1 = NULL; + } } } mp = (struct lpfc_dmabuf *) mbox->context1; @@ -2178,7 +2381,21 @@ out: spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); spin_unlock_irq(shost->host_lock); + + /* If the node is not being used by another discovery thread, + * and we are sending a reject, we are done with it. + * Release driver reference count here and free associated + * resources. + */ + if (ls_rjt) + if (lpfc_nlp_not_used(ndlp)) + /* Indicate node has already been released, + * should not reference to it from within + * the routine lpfc_els_free_iocb. + */ + cmdiocb->context1 = NULL; } + lpfc_els_free_iocb(phba, cmdiocb); return; } @@ -2349,14 +2566,6 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0); - /* If the node is in the UNUSED state, and we are sending - * a reject, we are done with it. Release driver reference - * count here. The outstanding els will release its reference on - * completion and the node can be freed then. - */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_nlp_put(ndlp); - if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); return 1; @@ -2642,7 +2851,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) } } } - if (sentplogi == 0) { + if (sentplogi) { + lpfc_set_disctmo(vport); + } + else { spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_NLP_MORE; spin_unlock_irq(shost->host_lock); @@ -2830,10 +3042,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, "RCV RSCN defer: did:x%x/ste:x%x flg:x%x", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DEFERRED; if ((rscn_cnt < FC_MAX_HOLD_RSCN) && !(vport->fc_flag & FC_RSCN_DISCOVERY)) { - spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_MODE; spin_unlock_irq(shost->host_lock); if (rscn_cnt) { @@ -2862,7 +3074,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_rscn_id_cnt, vport->fc_flag, vport->port_state); } else { - spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DISCOVERY; spin_unlock_irq(shost->host_lock); /* ReDiscovery RSCN */ @@ -2877,7 +3088,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* send RECOVERY event for ALL nodes that match RSCN payload */ lpfc_rscn_recovery_check(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_RSCN_DEFERRED; + spin_unlock_irq(shost->host_lock); return 0; } @@ -2929,6 +3142,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) /* To process RSCN, first compare RSCN data with NameServer */ vport->fc_ns_retry = 0; + vport->num_disc_nodes = 0; + ndlp = lpfc_findnode_did(vport, NameServer_DID); if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Good ndlp, issue CT Request to NameServer */ @@ -3022,8 +3237,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, mbox->mb.un.varInitLnk.lipsr_AL_PA = 0; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox - (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); @@ -3140,7 +3354,10 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, lpfc_max_els_tries, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); + + /* Decrement the ndlp reference count from previous mbox command */ lpfc_nlp_put(ndlp); + if (!elsiocb) return; @@ -3160,13 +3377,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) status |= 0x4; rps_rsp->rsvd1 = 0; - rps_rsp->portStatus = be16_to_cpu(status); - rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt); - rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt); - rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt); - rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt); - rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord); - rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt); + rps_rsp->portStatus = cpu_to_be16(status); + rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); + rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); + rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); + rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); + rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); + rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); /* Xmit ELS RPS ACC response tag <ulpIoTag> */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "0118 Xmit ELS RPS ACC response tag x%x xri x%x, " @@ -3223,11 +3440,13 @@ lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, mbox->context2 = lpfc_nlp_get(ndlp); mbox->vport = vport; mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; - if (lpfc_sli_issue_mbox (phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) + != MBX_NOT_FINISHED) /* Mbox completion will send ELS Response */ return 0; - + /* Decrement reference count used for the failed mbox + * command. + */ lpfc_nlp_put(ndlp); mempool_free(mbox, phba->mbox_mem_pool); } @@ -3461,6 +3680,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * other NLP_FABRIC logins */ lpfc_drop_node(vport, ndlp); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding I/O now since this * device is marked for PLOGI @@ -3469,8 +3689,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } } - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); return 0; } @@ -3711,6 +3929,7 @@ static void lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) { + struct Scsi_Host *shost; struct lpfc_nodelist *ndlp; struct ls_rjt stat; uint32_t *payload; @@ -3750,11 +3969,19 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, goto dropit; lpfc_nlp_init(vport, ndlp, did); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { ndlp->nlp_type |= NLP_FABRIC; } - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + } + else { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* This is simular to the new node path */ + lpfc_nlp_get(ndlp); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + newnode = 1; + } } phba->fc_stat.elsRcvFrame++; @@ -3783,6 +4010,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_err = LSRJT_UNABLE_TPC; break; } + + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; + spin_unlock_irq(shost->host_lock); + lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); @@ -3795,7 +4028,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvFLOGI++; lpfc_els_rcv_flogi(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_LOGO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3825,7 +4058,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_ADISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3897,7 +4130,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_RPS: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3907,7 +4140,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRPS++; lpfc_els_rcv_rps(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3917,7 +4150,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; case ELS_CMD_RNID: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3927,7 +4160,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(vport, elsiocb, ndlp); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3942,7 +4175,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); if (newnode) - lpfc_drop_node(vport, ndlp); + lpfc_nlp_put(ndlp); break; } @@ -3958,10 +4191,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return; dropit: - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + if (vport && !(vport->load_flag & FC_UNLOADING)) + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, "(%d):0111 Dropping received ELS cmd " "Data: x%x x%x x%x\n", - vport ? vport->vpi : 0xffff, icmd->ulpStatus, + vport->vpi, icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); phba->fc_stat.elsRcvDrop++; } @@ -4114,8 +4348,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; MAILBOX_t *mb = &pmb->mb; + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - lpfc_nlp_put(ndlp); + spin_unlock_irq(shost->host_lock); if (mb->mbxStatus) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, @@ -4135,7 +4370,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) default: /* Try to recover from this error */ lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); lpfc_initial_fdisc(vport); break; } @@ -4146,14 +4383,21 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) else lpfc_do_scr_ns_plogi(phba, vport); } + + /* Now, we decrement the ndlp reference count held for this + * callback function + */ + lpfc_nlp_put(ndlp); + mempool_free(pmb, phba->mbox_mem_pool); return; } -void +static void lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LPFC_MBOXQ_t *mbox; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -4162,25 +4406,31 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; - if (lpfc_sli_issue_mbox(phba, mbox, - MBX_NOWAIT | MBX_STOP_IOCB) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { + /* mailbox command not success, decrement ndlp + * reference count for this command + */ + lpfc_nlp_put(ndlp); mempool_free(mbox, phba->mbox_mem_pool); - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "0253 Register VPI: Can't send mbox\n"); + goto mbox_err_exit; } } else { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "0254 Register VPI: no memory\n"); - - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - lpfc_nlp_put(ndlp); + goto mbox_err_exit; } + return; + +mbox_err_exit: + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); + return; } static void @@ -4251,7 +4501,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_unreg_rpi(vport, np); } lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) @@ -4259,14 +4511,15 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, else lpfc_do_scr_ns_plogi(phba, vport); - lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */ + /* Unconditionaly kick off releasing fabric node for vports */ + lpfc_nlp_put(ndlp); } out: lpfc_els_free_iocb(phba, cmdiocb); } -int +static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry) { @@ -4539,7 +4792,7 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } -int +static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) { unsigned long iflags; @@ -4583,7 +4836,7 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) } -void lpfc_fabric_abort_vport(struct lpfc_vport *vport) +static void lpfc_fabric_abort_vport(struct lpfc_vport *vport) { LIST_HEAD(completions); struct lpfc_hba *phba = vport->phba; @@ -4663,6 +4916,7 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba) } +#if 0 void lpfc_fabric_abort_flogi(struct lpfc_hba *phba) { LIST_HEAD(completions); @@ -4693,5 +4947,6 @@ void lpfc_fabric_abort_flogi(struct lpfc_hba *phba) (piocb->iocb_cmpl) (phba, piocb, piocb); } } +#endif /* 0 */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index c81c2b3228d6..dc042bd97baa 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -57,6 +57,7 @@ static uint8_t lpfcAlpaArray[] = { }; static void lpfc_disc_timeout_handler(struct lpfc_vport *); +static void lpfc_disc_flush_list(struct lpfc_vport *vport); void lpfc_terminate_rport_io(struct fc_rport *rport) @@ -107,20 +108,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) struct lpfc_nodelist * ndlp; struct lpfc_vport *vport; struct lpfc_hba *phba; - struct completion devloss_compl; struct lpfc_work_evt *evtp; + int put_node; + int put_rport; rdata = rport->dd_data; ndlp = rdata->pnode; - - if (!ndlp) { - if (rport->scsi_target_id != -1) { - printk(KERN_ERR "Cannot find remote node" - " for rport in dev_loss_tmo_callbk x%x\n", - rport->port_id); - } + if (!ndlp) return; - } vport = ndlp->vport; phba = vport->phba; @@ -129,15 +124,35 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) "rport devlosscb: sid:x%x did:x%x flg:x%x", ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); - init_completion(&devloss_compl); + /* Don't defer this if we are in the process of deleting the vport + * or unloading the driver. The unload will cleanup the node + * appropriately we just need to cleanup the ndlp rport info here. + */ + if (vport->load_flag & FC_UNLOADING) { + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); + return; + } + + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + evtp = &ndlp->dev_loss_evt; if (!list_empty(&evtp->evt_listp)) return; spin_lock_irq(&phba->hbalock); - evtp->evt_arg1 = ndlp; - evtp->evt_arg2 = &devloss_compl; + /* We need to hold the node by incrementing the reference + * count until this queued work is done + */ + evtp->evt_arg1 = lpfc_nlp_get(ndlp); evtp->evt = LPFC_EVT_DEV_LOSS; list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) @@ -145,8 +160,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) spin_unlock_irq(&phba->hbalock); - wait_for_completion(&devloss_compl); - return; } @@ -154,7 +167,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) * This function is called from the worker thread when dev_loss_tmo * expire. */ -void +static void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) { struct lpfc_rport_data *rdata; @@ -162,6 +175,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) struct lpfc_vport *vport; struct lpfc_hba *phba; uint8_t *name; + int put_node; + int put_rport; int warn_on = 0; rport = ndlp->rport; @@ -178,14 +193,32 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) "rport devlosstmo:did:x%x type:x%x id:x%x", ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); - if (!(vport->load_flag & FC_UNLOADING) && - ndlp->nlp_state == NLP_STE_MAPPED_NODE) + /* Don't defer this if we are in the process of deleting the vport + * or unloading the driver. The unload will cleanup the node + * appropriately we just need to cleanup the ndlp rport info here. + */ + if (vport->load_flag & FC_UNLOADING) { + if (ndlp->nlp_sid != NLP_NO_SID) { + /* flush the target */ + lpfc_sli_abort_iocb(vport, + &phba->sli.ring[phba->sli.fcp_ring], + ndlp->nlp_sid, 0, LPFC_CTX_TGT); + } + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); return; + } - if (ndlp->nlp_type & NLP_FABRIC) { - int put_node; - int put_rport; + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + if (ndlp->nlp_type & NLP_FABRIC) { /* We will clean up these Nodes in linkup */ put_node = rdata->pnode != NULL; put_rport = ndlp->rport != NULL; @@ -227,23 +260,20 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ndlp->nlp_state, ndlp->nlp_rpi); } + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); + if (!(vport->load_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) + (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) { lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); - else { - int put_node; - int put_rport; - - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); } } @@ -260,7 +290,6 @@ lpfc_work_list_done(struct lpfc_hba *phba) { struct lpfc_work_evt *evtp = NULL; struct lpfc_nodelist *ndlp; - struct lpfc_vport *vport; int free_evt; spin_lock_irq(&phba->hbalock); @@ -270,35 +299,22 @@ lpfc_work_list_done(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); free_evt = 1; switch (evtp->evt) { - case LPFC_EVT_DEV_LOSS_DELAY: - free_evt = 0; /* evt is part of ndlp */ - ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); - vport = ndlp->vport; - if (!vport) - break; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlossdly:did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - if (!(vport->load_flag & FC_UNLOADING) && - !(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); - } - break; case LPFC_EVT_ELS_RETRY: ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); lpfc_els_retry_delay_handler(ndlp); free_evt = 0; /* evt is part of ndlp */ + /* decrement the node reference count held + * for this queued work + */ + lpfc_nlp_put(ndlp); break; case LPFC_EVT_DEV_LOSS: ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); - lpfc_nlp_get(ndlp); lpfc_dev_loss_tmo_handler(ndlp); free_evt = 0; - complete((struct completion *)(evtp->evt_arg2)); + /* decrement the node reference count held for + * this queued work + */ lpfc_nlp_put(ndlp); break; case LPFC_EVT_ONLINE: @@ -373,7 +389,7 @@ lpfc_work_done(struct lpfc_hba *phba) lpfc_handle_latt(phba); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS; i++) { + for(i = 0; i <= phba->max_vpi; i++) { /* * We could have no vports in array if unloading, so if * this happens then just use the pport @@ -405,14 +421,14 @@ lpfc_work_done(struct lpfc_hba *phba) vport->work_port_events &= ~work_port_events; spin_unlock_irq(&vport->work_port_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); pring = &phba->sli.ring[LPFC_ELS_RING]; status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); status >>= (4*LPFC_ELS_RING); if ((status & HA_RXMASK) || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { - if (pring->flag & LPFC_STOP_IOCB_MASK) { + if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; } else { lpfc_sli_handle_slow_ring_event(phba, pring, @@ -544,6 +560,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; int rc; @@ -552,7 +569,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; - if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) + if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || + ((vport->port_type == LPFC_NPIV_PORT) && + (ndlp->nlp_DID == NameServer_DID))) lpfc_unreg_rpi(vport, ndlp); /* Leave Fabric nodes alone on link down */ @@ -565,14 +584,30 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) } if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } } +void +lpfc_port_link_failure(struct lpfc_vport *vport) +{ + /* Cleanup any outstanding RSCN activity */ + lpfc_els_flush_rscn(vport); + + /* Cleanup any outstanding ELS commands */ + lpfc_els_flush_cmd(vport); + + lpfc_cleanup_rpis(vport, 0); + + /* Turn off discovery timer if its running */ + lpfc_can_disctmo(vport); +} + static void lpfc_linkdown_port(struct lpfc_vport *vport) { - struct lpfc_nodelist *ndlp, *next_ndlp; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); @@ -581,21 +616,8 @@ lpfc_linkdown_port(struct lpfc_vport *vport) "Link Down: state:x%x rtry:x%x flg:x%x", vport->port_state, vport->fc_ns_retry, vport->fc_flag); - /* Cleanup any outstanding RSCN activity */ - lpfc_els_flush_rscn(vport); - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(vport); + lpfc_port_link_failure(vport); - lpfc_cleanup_rpis(vport, 0); - - /* free any ndlp's on unused list */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(vport, ndlp); - - /* Turn off discovery timer if its running */ - lpfc_can_disctmo(vport); } int @@ -618,18 +640,18 @@ lpfc_linkdown(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { /* Issue a LINK DOWN event to all nodes */ lpfc_linkdown_port(vports[i]); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); /* Clean up any firmware default rpi's */ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb); mb->vport = vport; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mb, phba->mbox_mem_pool); } @@ -643,8 +665,7 @@ lpfc_linkdown(struct lpfc_hba *phba) lpfc_config_link(phba, mb); mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mb->vport = vport; - if (lpfc_sli_issue_mbox(phba, mb, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mb, phba->mbox_mem_pool); } @@ -686,7 +707,6 @@ static void lpfc_linkup_port(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp, *next_ndlp; struct lpfc_hba *phba = vport->phba; if ((vport->load_flag & FC_UNLOADING) != 0) @@ -713,11 +733,6 @@ lpfc_linkup_port(struct lpfc_vport *vport) if (vport->fc_flag & FC_LBIT) lpfc_linkup_cleanup_nodes(vport); - /* free any ndlp's in unused state */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, - nlp_listp) - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(vport, ndlp); } static int @@ -734,9 +749,9 @@ lpfc_linkup(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) lpfc_linkup_port(vports[i]); - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) lpfc_issue_clear_la(phba, phba->pport); @@ -749,7 +764,7 @@ lpfc_linkup(struct lpfc_hba *phba) * as the completion routine when the command is * handed off to the SLI layer. */ -void +static void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; @@ -852,8 +867,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * LPFC_FLOGI while waiting for FLOGI cmpl */ if (vport->port_state != LPFC_FLOGI) { - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); } return; @@ -1022,8 +1035,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) lpfc_read_sparam(phba, sparam_mbox, 0); sparam_mbox->vport = vport; sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; - rc = lpfc_sli_issue_mbox(phba, sparam_mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mp = (struct lpfc_dmabuf *) sparam_mbox->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -1040,8 +1052,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) lpfc_config_link(phba, cfglink_mbox); cfglink_mbox->vport = vport; cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; - rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); if (rc != MBX_NOT_FINISHED) return; mempool_free(cfglink_mbox, phba->mbox_mem_pool); @@ -1174,6 +1185,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); + /* decrement the node reference count held for this callback + * function. + */ lpfc_nlp_put(ndlp); return; @@ -1219,7 +1233,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) lpfc_unreg_vpi(phba, vport->vpi, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; - rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, "1800 Could not issue unreg_vpi\n"); @@ -1319,7 +1333,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for(i = 0; - i < LPFC_MAX_VPORTS && vports[i] != NULL; + i <= phba->max_vpi && vports[i] != NULL; i++) { if (vports[i]->port_type == LPFC_PHYSICAL_PORT) continue; @@ -1335,7 +1349,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) "Fabric support\n"); } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_do_scr_ns_plogi(phba, vport); } @@ -1361,11 +1375,16 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (mb->mbxStatus) { out: + /* decrement the node reference count held for this + * callback function. + */ lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - lpfc_drop_node(vport, ndlp); + + /* If no other thread is using the ndlp, free it */ + lpfc_nlp_not_used(ndlp); if (phba->fc_topology == TOPOLOGY_LOOP) { /* @@ -1410,6 +1429,9 @@ out: goto out; } + /* decrement the node reference count held for this + * callback function. + */ lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -1656,8 +1678,18 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) void lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + /* + * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should + * be used if we wish to issue the "last" lpfc_nlp_put() to remove + * the ndlp from the vport. The ndlp marked as UNUSED on the list + * until ALL other outstanding threads have completed. We check + * that the ndlp not already in the UNUSED state before we proceed. + */ + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + return; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); lpfc_nlp_put(ndlp); + return; } /* @@ -1868,8 +1900,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) mempool_free(mbox, phba->mbox_mem_pool); } @@ -1892,8 +1923,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport) lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); } @@ -1912,8 +1943,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if (rc == MBX_NOT_FINISHED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, "1815 Could not issue " @@ -1981,11 +2012,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) list_del_init(&ndlp->dev_loss_evt.evt_listp); - if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) { - list_del_init(&ndlp->dev_loss_evt.evt_listp); - complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2)); - } - lpfc_unreg_rpi(vport, ndlp); return 0; @@ -1999,12 +2025,39 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) static void lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata; + LPFC_MBOXQ_t *mbox; + int rc; if (ndlp->nlp_flag & NLP_DELAY_TMO) { lpfc_cancel_retry_delay_tmo(vport, ndlp); } + if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { + /* For this case we need to cleanup the default rpi + * allocated by the firmware. + */ + if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) + != NULL) { + rc = lpfc_reg_login(phba, vport->vpi, ndlp->nlp_DID, + (uint8_t *) &vport->fc_sparam, mbox, 0); + if (rc) { + mempool_free(mbox, phba->mbox_mem_pool); + } + else { + mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; + mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; + mbox->vport = vport; + mbox->context2 = NULL; + rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + } + } + } + } + lpfc_cleanup_node(vport, ndlp); /* @@ -2132,6 +2185,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) } if (vport->fc_flag & FC_RSCN_MODE) { if (lpfc_rscn_payload_check(vport, did)) { + /* If we've already recieved a PLOGI from this NPort + * we don't need to try to discover it again. + */ + if (ndlp->nlp_flag & NLP_RCV_PLOGI) + return NULL; + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -2144,8 +2203,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) } else ndlp = NULL; } else { + /* If we've already recieved a PLOGI from this NPort, + * or we are already in the process of discovery on it, + * we don't need to try to discover it again. + */ if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || - ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) + ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || + ndlp->nlp_flag & NLP_RCV_PLOGI) return NULL; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); @@ -2220,8 +2284,7 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) lpfc_clear_la(phba, mbox); mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | - MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); lpfc_disc_flush_list(vport); @@ -2244,8 +2307,7 @@ lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox); regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi; regvpimbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, regvpimbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(regvpimbox, phba->mbox_mem_pool); } @@ -2414,7 +2476,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } } -void +static void lpfc_disc_flush_list(struct lpfc_vport *vport) { struct lpfc_nodelist *ndlp, *next_ndlp; @@ -2426,7 +2488,6 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { lpfc_free_tx(phba, ndlp); - lpfc_nlp_put(ndlp); } } } @@ -2516,6 +2577,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) if (ndlp->nlp_type & NLP_FABRIC) { /* Clean up the ndlp on Fabric connections */ lpfc_drop_node(vport, ndlp); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding IO now since device * is marked for PLOGI. @@ -2524,9 +2586,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) } } if (vport->port_state != LPFC_FLOGI) { - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); + return; } break; @@ -2536,7 +2597,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Initial FLOGI timeout */ lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0222 Initial %s timeout\n", - vport->vpi ? "FLOGI" : "FDISC"); + vport->vpi ? "FDISC" : "FLOGI"); /* Assume no Fabric and go on with discovery. * Check for outstanding ELS FLOGI to abort. @@ -2558,10 +2619,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(vport, NameServer_DID); if (ndlp) - lpfc_nlp_put(ndlp); - /* Start discovery */ - lpfc_disc_start(vport); - break; + lpfc_els_abort(phba, ndlp); + + /* ReStart discovery */ + goto restart_disc; case LPFC_NS_QRY: /* Check for wait for NameServer Rsp timeout */ @@ -2580,6 +2641,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) } vport->fc_ns_retry = 0; +restart_disc: /* * Discovery is over. * set port_state to PORT_READY if SLI2. @@ -2608,8 +2670,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; initlinkmbox->vport = vport; initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, initlinkmbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT); lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) mempool_free(initlinkmbox, phba->mbox_mem_pool); @@ -2664,12 +2725,14 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) clrlaerr = 1; break; + case LPFC_LINK_UP: + lpfc_issue_clear_la(phba, vport); + /* Drop thru */ case LPFC_LINK_UNKNOWN: case LPFC_WARM_START: case LPFC_INIT_START: case LPFC_INIT_MBX_CMDS: case LPFC_LINK_DOWN: - case LPFC_LINK_UP: case LPFC_HBA_ERROR: lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0230 Unexpected timeout, hba link " @@ -2723,7 +2786,9 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) else mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60); - /* Mailbox took a reference to the node */ + /* decrement the node reference count held for this callback + * function. + */ lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -2747,19 +2812,19 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param) sizeof(ndlp->nlp_portname)) == 0; } -struct lpfc_nodelist * +static struct lpfc_nodelist * __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) { struct lpfc_nodelist *ndlp; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && - filter(ndlp, param)) + if (filter(ndlp, param)) return ndlp; } return NULL; } +#if 0 /* * Search node lists for a remote port matching filter criteria * Caller needs to hold host_lock before calling this routine. @@ -2775,6 +2840,7 @@ lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) spin_unlock_irq(shost->host_lock); return ndlp; } +#endif /* 0 */ /* * This routine looks up the ndlp lists for the given RPI. If rpi found it @@ -2786,6 +2852,7 @@ __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi); } +#if 0 struct lpfc_nodelist * lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) { @@ -2797,6 +2864,7 @@ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) spin_unlock_irq(shost->host_lock); return ndlp; } +#endif /* 0 */ /* * This routine looks up the ndlp lists for the given WWPN. If WWPN found it @@ -2837,6 +2905,9 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return; } +/* This routine releases all resources associated with a specifc NPort's ndlp + * and mempool_free's the nodelist. + */ static void lpfc_nlp_release(struct kref *kref) { @@ -2851,16 +2922,57 @@ lpfc_nlp_release(struct kref *kref) mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); } +/* This routine bumps the reference count for a ndlp structure to ensure + * that one discovery thread won't free a ndlp while another discovery thread + * is using it. + */ struct lpfc_nodelist * lpfc_nlp_get(struct lpfc_nodelist *ndlp) { - if (ndlp) + if (ndlp) { + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node get: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); kref_get(&ndlp->kref); + } return ndlp; } + +/* This routine decrements the reference count for a ndlp structure. If the + * count goes to 0, this indicates the the associated nodelist should be freed. + */ int lpfc_nlp_put(struct lpfc_nodelist *ndlp) { + if (ndlp) { + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); + } return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; } + +/* This routine free's the specified nodelist if it is not in use + * by any other discovery thread. This routine returns 1 if the ndlp + * is not being used by anyone and has been freed. A return value of + * 0 indicates it is being used by another discovery thread and the + * refcount is left unchanged. + */ +int +lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) +{ + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node not used: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); + + if (atomic_read(&ndlp->kref.refcount) == 1) { + lpfc_nlp_put(ndlp); + return 1; + } + return 0; +} + diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 451accd5564b..041f83e7634a 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -139,6 +139,9 @@ struct lpfc_sli_ct_request { uint8_t len; uint8_t symbname[255]; } rsnn; + struct da_id { /* For DA_ID requests */ + uint32_t port_id; + } da_id; struct rspn { /* For RSPN_ID requests */ uint32_t PortId; uint8_t len; @@ -150,11 +153,7 @@ struct lpfc_sli_ct_request { struct gff_acc { uint8_t fbits[128]; } gff_acc; -#ifdef __BIG_ENDIAN_BITFIELD #define FCP_TYPE_FEATURE_OFFSET 7 -#else /* __LITTLE_ENDIAN_BITFIELD */ -#define FCP_TYPE_FEATURE_OFFSET 4 -#endif struct rff { uint32_t PortId; uint8_t reserved[2]; @@ -177,6 +176,8 @@ struct lpfc_sli_ct_request { sizeof(struct rnn)) #define RSNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rsnn)) +#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ + sizeof(struct da_id)) #define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rspn)) @@ -1228,7 +1229,8 @@ typedef struct { /* FireFly BIU registers */ #define HS_FFER3 0x20000000 /* Bit 29 */ #define HS_FFER2 0x40000000 /* Bit 30 */ #define HS_FFER1 0x80000000 /* Bit 31 */ -#define HS_FFERM 0xFF000000 /* Mask for error bits 31:24 */ +#define HS_CRIT_TEMP 0x00000100 /* Bit 8 */ +#define HS_FFERM 0xFF000100 /* Mask for error bits 31:24 and 8 */ /* Host Control Register */ @@ -1277,12 +1279,14 @@ typedef struct { /* FireFly BIU registers */ #define MBX_DEL_LD_ENTRY 0x1D #define MBX_RUN_PROGRAM 0x1E #define MBX_SET_MASK 0x20 -#define MBX_SET_SLIM 0x21 +#define MBX_SET_VARIABLE 0x21 #define MBX_UNREG_D_ID 0x23 #define MBX_KILL_BOARD 0x24 #define MBX_CONFIG_FARP 0x25 #define MBX_BEACON 0x2A #define MBX_HEARTBEAT 0x31 +#define MBX_WRITE_VPARMS 0x32 +#define MBX_ASYNCEVT_ENABLE 0x33 #define MBX_CONFIG_HBQ 0x7C #define MBX_LOAD_AREA 0x81 @@ -1297,7 +1301,7 @@ typedef struct { /* FireFly BIU registers */ #define MBX_REG_VNPID 0x96 #define MBX_UNREG_VNPID 0x97 -#define MBX_FLASH_WR_ULA 0x98 +#define MBX_WRITE_WWN 0x98 #define MBX_SET_DEBUG 0x99 #define MBX_LOAD_EXP_ROM 0x9C @@ -1344,6 +1348,7 @@ typedef struct { /* FireFly BIU registers */ /* SLI_2 IOCB Command Set */ +#define CMD_ASYNC_STATUS 0x7C #define CMD_RCV_SEQUENCE64_CX 0x81 #define CMD_XMIT_SEQUENCE64_CR 0x82 #define CMD_XMIT_SEQUENCE64_CX 0x83 @@ -1368,6 +1373,7 @@ typedef struct { /* FireFly BIU registers */ #define CMD_FCP_TRECEIVE64_CX 0xA1 #define CMD_FCP_TRSP64_CX 0xA3 +#define CMD_QUE_XRI64_CX 0xB3 #define CMD_IOCB_RCV_SEQ64_CX 0xB5 #define CMD_IOCB_RCV_ELS64_CX 0xB7 #define CMD_IOCB_RCV_CONT64_CX 0xBB @@ -1406,6 +1412,8 @@ typedef struct { /* FireFly BIU registers */ #define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ #define MBX_TIMEOUT 0xfffffe /* time-out expired waiting for */ +#define TEMPERATURE_OFFSET 0xB0 /* Slim offset for critical temperature event */ + /* * Begin Structure Definitions for Mailbox Commands */ @@ -2606,6 +2614,18 @@ typedef struct { uint32_t IPAddress; } CONFIG_FARP_VAR; +/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */ + +typedef struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd:30; + uint32_t ring:2; /* Ring for ASYNC_EVENT iocb Bits 0-1*/ +#else /* __LITTLE_ENDIAN */ + uint32_t ring:2; /* Ring for ASYNC_EVENT iocb Bits 0-1*/ + uint32_t rsvd:30; +#endif +} ASYNCEVT_ENABLE_VAR; + /* Union of all Mailbox Command types */ #define MAILBOX_CMD_WSIZE 32 #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) @@ -2645,6 +2665,7 @@ typedef union { CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ + ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ } MAILVARIANTS; /* @@ -2973,6 +2994,34 @@ typedef struct { #endif } RCV_ELS_REQ64; +/* IOCB Command template for RCV_SEQ64 */ +struct rcv_seq64 { + struct ulp_bde64 elsReq; + uint32_t hbq_1; + uint32_t parmRo; +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rctl:8; + uint32_t type:8; + uint32_t dfctl:8; + uint32_t ls:1; + uint32_t fs:1; + uint32_t rsvd2:3; + uint32_t si:1; + uint32_t bc:1; + uint32_t rsvd3:1; +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint32_t rsvd3:1; + uint32_t bc:1; + uint32_t si:1; + uint32_t rsvd2:3; + uint32_t fs:1; + uint32_t ls:1; + uint32_t dfctl:8; + uint32_t type:8; + uint32_t rctl:8; +#endif +}; + /* IOCB Command template for all 64 bit FCP Initiator commands */ typedef struct { ULP_BDL bdl; @@ -2987,6 +3036,21 @@ typedef struct { uint32_t fcpt_Length; /* transfer ready for IWRITE */ } FCPT_FIELDS64; +/* IOCB Command template for Async Status iocb commands */ +typedef struct { + uint32_t rsvd[4]; + uint32_t param; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t evt_code; /* High order bits word 5 */ + uint16_t sub_ctxt_tag; /* Low order bits word 5 */ +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint16_t sub_ctxt_tag; /* High order bits word 5 */ + uint16_t evt_code; /* Low order bits word 5 */ +#endif +} ASYNCSTAT_FIELDS; +#define ASYNC_TEMP_WARN 0x100 +#define ASYNC_TEMP_SAFE 0x101 + /* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7) or CMD_IOCB_RCV_SEQ64_CX (0xB5) */ @@ -3004,7 +3068,26 @@ struct rcv_sli3 { struct ulp_bde64 bde2; }; +/* Structure used for a single HBQ entry */ +struct lpfc_hbq_entry { + struct ulp_bde64 bde; + uint32_t buffer_tag; +}; +/* IOCB Command template for QUE_XRI64_CX (0xB3) command */ +typedef struct { + struct lpfc_hbq_entry buff; + uint32_t rsvd; + uint32_t rsvd1; +} QUE_XRI64_CX_FIELDS; + +struct que_xri64cx_ext_fields { + uint32_t iotag64_low; + uint32_t iotag64_high; + uint32_t ebde_count; + uint32_t rsvd; + struct lpfc_hbq_entry buff[5]; +}; typedef struct _IOCB { /* IOCB structure */ union { @@ -3028,6 +3111,9 @@ typedef struct _IOCB { /* IOCB structure */ XMT_SEQ_FIELDS64 xseq64; /* XMIT / BCAST cmd */ FCPI_FIELDS64 fcpi64; /* FCP 64 bit Initiator template */ FCPT_FIELDS64 fcpt64; /* FCP 64 bit target template */ + ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ + QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ + struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ } un; @@ -3085,6 +3171,10 @@ typedef struct _IOCB { /* IOCB structure */ union { struct rcv_sli3 rcvsli3; /* words 8 - 15 */ + + /* words 8-31 used for que_xri_cx iocb */ + struct que_xri64cx_ext_fields que_xri64cx_ext_words; + uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ } unsli3; @@ -3124,12 +3214,6 @@ typedef struct _IOCB { /* IOCB structure */ } IOCB_t; -/* Structure used for a single HBQ entry */ -struct lpfc_hbq_entry { - struct ulp_bde64 bde; - uint32_t buffer_tag; -}; - #define SLI1_SLIM_SIZE (4 * 1024) @@ -3172,6 +3256,8 @@ lpfc_is_LC_HBA(unsigned short device) (device == PCI_DEVICE_ID_BSMB) || (device == PCI_DEVICE_ID_ZMID) || (device == PCI_DEVICE_ID_ZSMB) || + (device == PCI_DEVICE_ID_SAT_MID) || + (device == PCI_DEVICE_ID_SAT_SMB) || (device == PCI_DEVICE_ID_RFLY)) return 1; else diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ecebdfa00470..3205f7488d1c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -212,6 +212,18 @@ out_free_mbox: return 0; } +/* Completion handler for config async event mailbox command. */ +static void +lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) +{ + if (pmboxq->mb.mbxStatus == MBX_SUCCESS) + phba->temp_sensor_support = 1; + else + phba->temp_sensor_support = 0; + mempool_free(pmboxq, phba->mbox_mem_pool); + return; +} + /************************************************************************/ /* */ /* lpfc_config_port_post */ @@ -234,6 +246,15 @@ lpfc_config_port_post(struct lpfc_hba *phba) int i, j; int rc; + spin_lock_irq(&phba->hbalock); + /* + * If the Config port completed correctly the HBA is not + * over heated any more. + */ + if (phba->over_temp_state == HBA_OVER_TEMP) + phba->over_temp_state = HBA_NORMAL_TEMP; + spin_unlock_irq(&phba->hbalock); + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { phba->link_state = LPFC_HBA_ERROR; @@ -343,7 +364,7 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->link_state = LPFC_LINK_DOWN; - /* Only process IOCBs on ring 0 till hba_state is READY */ + /* Only process IOCBs on ELS ring till hba_state is READY */ if (psli->ring[psli->extra_ring].cmdringaddr) psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT; if (psli->ring[psli->fcp_ring].cmdringaddr) @@ -409,7 +430,21 @@ lpfc_config_port_post(struct lpfc_hba *phba) return -EIO; } /* MBOX buffer will be freed in mbox compl */ + pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + lpfc_config_async(phba, pmb, LPFC_ELS_RING); + pmb->mbox_cmpl = lpfc_config_async_cmpl; + pmb->vport = phba->pport; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { + lpfc_printf_log(phba, + KERN_ERR, + LOG_INIT, + "0456 Adapter failed to issue " + "ASYNCEVT_ENABLE mbox status x%x \n.", + rc); + mempool_free(pmb, phba->mbox_mem_pool); + } return (0); } @@ -449,6 +484,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; struct lpfc_dmabuf *mp, *next_mp; + struct lpfc_iocbq *iocb; + IOCB_t *cmd = NULL; + LIST_HEAD(completions); int i; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) @@ -464,16 +502,42 @@ lpfc_hba_down_post(struct lpfc_hba *phba) } } + spin_lock_irq(&phba->hbalock); for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; + + /* At this point in time the HBA is either reset or DOA. Either + * way, nothing should be on txcmplq as it will NEVER complete. + */ + list_splice_init(&pring->txcmplq, &completions); + pring->txcmplq_cnt = 0; + spin_unlock_irq(&phba->hbalock); + + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, + list); + cmd = &iocb->iocb; + list_del_init(&iocb->list); + + if (!iocb->iocb_cmpl) + lpfc_sli_release_iocbq(phba, iocb); + else { + cmd->ulpStatus = IOSTAT_LOCAL_REJECT; + cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + (iocb->iocb_cmpl) (phba, iocb, iocb); + } + } + lpfc_sli_abort_iocb_ring(phba, pring); + spin_lock_irq(&phba->hbalock); } + spin_unlock_irq(&phba->hbalock); return 0; } /* HBA heart beat timeout handler */ -void +static void lpfc_hb_timeout(unsigned long ptr) { struct lpfc_hba *phba; @@ -512,8 +576,10 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmboxq; + struct lpfc_dmabuf *buf_ptr; int retval; struct lpfc_sli *psli = &phba->sli; + LIST_HEAD(completions); if ((phba->link_state == LPFC_HBA_ERROR) || (phba->pport->load_flag & FC_UNLOADING) || @@ -540,49 +606,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) } spin_unlock_irq(&phba->pport->work_port_lock); - /* If there is no heart beat outstanding, issue a heartbeat command */ - if (!phba->hb_outstanding) { - pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); - if (!pmboxq) { - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - return; + if (phba->elsbuf_cnt && + (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) { + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->elsbuf, &completions); + phba->elsbuf_cnt = 0; + phba->elsbuf_prev_cnt = 0; + spin_unlock_irq(&phba->hbalock); + + while (!list_empty(&completions)) { + list_remove_head(&completions, buf_ptr, + struct lpfc_dmabuf, list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); } + } + phba->elsbuf_prev_cnt = phba->elsbuf_cnt; - lpfc_heart_beat(phba, pmboxq); - pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; - pmboxq->vport = phba->pport; - retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + /* If there is no heart beat outstanding, issue a heartbeat command */ + if (phba->cfg_enable_hba_heartbeat) { + if (!phba->hb_outstanding) { + pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); + if (!pmboxq) { + mod_timer(&phba->hb_tmofunc, + jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + return; + } - if (retval != MBX_BUSY && retval != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); + lpfc_heart_beat(phba, pmboxq); + pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; + pmboxq->vport = phba->pport; + retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + + if (retval != MBX_BUSY && retval != MBX_SUCCESS) { + mempool_free(pmboxq, phba->mbox_mem_pool); + mod_timer(&phba->hb_tmofunc, + jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + return; + } mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); + phba->hb_outstanding = 1; return; + } else { + /* + * If heart beat timeout called with hb_outstanding set + * we need to take the HBA offline. + */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0459 Adapter heartbeat failure, " + "taking this port offline.\n"); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_unblock_mgmt_io(phba); + phba->link_state = LPFC_HBA_ERROR; + lpfc_hba_down_post(phba); } - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); - phba->hb_outstanding = 1; - return; - } else { - /* - * If heart beat timeout called with hb_outstanding set we - * need to take the HBA offline. - */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0459 Adapter heartbeat failure, taking " - "this port offline.\n"); + } +} - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; - spin_unlock_irq(&phba->hbalock); +static void +lpfc_offline_eratt(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - lpfc_hba_down_post(phba); - } + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + lpfc_offline_prep(phba); + + lpfc_offline(phba); + lpfc_reset_barrier(phba); + lpfc_sli_brdreset(phba); + lpfc_hba_down_post(phba); + lpfc_sli_brdready(phba, HS_MBRDY); + lpfc_unblock_mgmt_io(phba); + phba->link_state = LPFC_HBA_ERROR; + return; } /************************************************************************/ @@ -601,6 +706,8 @@ lpfc_handle_eratt(struct lpfc_hba *phba) struct lpfc_sli_ring *pring; struct lpfc_vport **vports; uint32_t event_data; + unsigned long temperature; + struct temp_event temp_event_data; struct Scsi_Host *shost; int i; @@ -608,6 +715,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba) * since we cannot communicate with the pci card anyway. */ if (pci_channel_offline(phba->pcidev)) return; + /* If resets are disabled then leave the HBA alone and return */ + if (!phba->cfg_enable_hba_reset) + return; if (phba->work_hs & HS_FFER6 || phba->work_hs & HS_FFER5) { @@ -620,14 +730,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for(i = 0; - i < LPFC_MAX_VPORTS && vports[i] != NULL; + i <= phba->max_vpi && vports[i] != NULL; i++){ shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->fc_flag |= FC_ESTABLISH_LINK; spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(&phba->hbalock); @@ -655,6 +765,31 @@ lpfc_handle_eratt(struct lpfc_hba *phba) return; } lpfc_unblock_mgmt_io(phba); + } else if (phba->work_hs & HS_CRIT_TEMP) { + temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET); + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + temp_event_data.event_code = LPFC_CRIT_TEMP; + temp_event_data.data = (uint32_t)temperature; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0459 Adapter maximum temperature exceeded " + "(%ld), taking this port offline " + "Data: x%x x%x x%x\n", + temperature, phba->work_hs, + phba->work_status[0], phba->work_status[1]); + + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), + (char *) &temp_event_data, + SCSI_NL_VID_TYPE_PCI + | PCI_VENDOR_ID_EMULEX); + + spin_lock_irq(&phba->hbalock); + phba->over_temp_state = HBA_OVER_TEMP; + spin_unlock_irq(&phba->hbalock); + lpfc_offline_eratt(phba); + } else { /* The if clause above forces this code path when the status * failure is a value other than FFER6. Do not call the offline @@ -672,14 +807,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) sizeof(event_data), (char *) &event_data, SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; - spin_unlock_irq(&phba->hbalock); - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - lpfc_hba_down_post(phba); + lpfc_offline_eratt(phba); } } @@ -699,21 +827,25 @@ lpfc_handle_latt(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmb; volatile uint32_t control; struct lpfc_dmabuf *mp; - int rc = -ENOMEM; + int rc = 0; pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) + if (!pmb) { + rc = 1; goto lpfc_handle_latt_err_exit; + } mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) + if (!mp) { + rc = 2; goto lpfc_handle_latt_free_pmb; + } mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) + if (!mp->virt) { + rc = 3; goto lpfc_handle_latt_free_mp; - - rc = -EIO; + } /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); @@ -722,9 +854,11 @@ lpfc_handle_latt(struct lpfc_hba *phba) lpfc_read_la(phba, pmb, mp); pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; pmb->vport = vport; - rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)); - if (rc == MBX_NOT_FINISHED) + rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + rc = 4; goto lpfc_handle_latt_free_mbuf; + } /* Clear Link Attention in HA REG */ spin_lock_irq(&phba->hbalock); @@ -756,10 +890,8 @@ lpfc_handle_latt_err_exit: lpfc_linkdown(phba); phba->link_state = LPFC_HBA_ERROR; - /* The other case is an error from issue_mbox */ - if (rc == -ENOMEM) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "0300 READ_LA: no buffers\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); return; } @@ -1088,9 +1220,8 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt, /* Allocate buffer to post */ mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); if (mp1) - mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, - &mp1->phys); - if (mp1 == 0 || mp1->virt == 0) { + mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys); + if (!mp1 || !mp1->virt) { kfree(mp1); lpfc_sli_release_iocbq(phba, iocb); pring->missbufcnt = cnt; @@ -1104,7 +1235,7 @@ lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt, if (mp2) mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp2->phys); - if (mp2 == 0 || mp2->virt == 0) { + if (!mp2 || !mp2->virt) { kfree(mp2); lpfc_mbuf_free(phba, mp1->virt, mp1->phys); kfree(mp1); @@ -1280,15 +1411,39 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) kfree(HashWorking); } -static void +void lpfc_cleanup(struct lpfc_vport *vport) { + struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; + int i = 0; - /* clean up phba - lpfc specific */ - lpfc_can_disctmo(vport); - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) - lpfc_nlp_put(ndlp); + if (phba->link_state > LPFC_LINK_DOWN) + lpfc_port_link_failure(vport); + + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_type & NLP_FABRIC) + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } + + /* At this point, ALL ndlp's should be gone + * because of the previous NLP_EVT_DEVICE_RM. + * Lets wait for this to happen, if needed. + */ + while (!list_empty(&vport->fc_nodes)) { + + if (i++ > 3000) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + "0233 Nodelist not empty\n"); + break; + } + + /* Wait for any activity on ndlps to settle */ + msleep(10); + } return; } @@ -1307,14 +1462,14 @@ lpfc_establish_link_tmo(unsigned long ptr) phba->pport->fc_flag, phba->pport->port_state); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); spin_lock_irqsave(shost->host_lock, iflag); vports[i]->fc_flag &= ~FC_ESTABLISH_LINK; spin_unlock_irqrestore(shost->host_lock, iflag); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); } void @@ -1339,6 +1494,16 @@ lpfc_stop_phba_timers(struct lpfc_hba *phba) return; } +static void +lpfc_block_mgmt_io(struct lpfc_hba * phba) +{ + unsigned long iflag; + + spin_lock_irqsave(&phba->hbalock, iflag); + phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO; + spin_unlock_irqrestore(&phba->hbalock, iflag); +} + int lpfc_online(struct lpfc_hba *phba) { @@ -1369,7 +1534,7 @@ lpfc_online(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); @@ -1378,23 +1543,13 @@ lpfc_online(struct lpfc_hba *phba) vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_unblock_mgmt_io(phba); return 0; } void -lpfc_block_mgmt_io(struct lpfc_hba * phba) -{ - unsigned long iflag; - - spin_lock_irqsave(&phba->hbalock, iflag); - phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO; - spin_unlock_irqrestore(&phba->hbalock, iflag); -} - -void lpfc_unblock_mgmt_io(struct lpfc_hba * phba) { unsigned long iflag; @@ -1409,6 +1564,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) { struct lpfc_vport *vport = phba->pport; struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_vport **vports; + int i; if (vport->fc_flag & FC_OFFLINE_MODE) return; @@ -1417,10 +1574,34 @@ lpfc_offline_prep(struct lpfc_hba * phba) lpfc_linkdown(phba); - /* Issue an unreg_login to all nodes */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) - if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) - lpfc_unreg_rpi(vport, ndlp); + /* Issue an unreg_login to all nodes on all vports */ + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { + struct Scsi_Host *shost; + + if (vports[i]->load_flag & FC_UNLOADING) + continue; + shost = lpfc_shost_from_vport(vports[i]); + list_for_each_entry_safe(ndlp, next_ndlp, + &vports[i]->fc_nodes, + nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + continue; + if (ndlp->nlp_type & NLP_FABRIC) { + lpfc_disc_state_machine(vports[i], ndlp, + NULL, NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vports[i], ndlp, + NULL, NLP_EVT_DEVICE_RM); + } + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_ADISC; + spin_unlock_irq(shost->host_lock); + lpfc_unreg_rpi(vports[i], ndlp); + } + } + } + lpfc_destroy_vport_work_array(phba, vports); lpfc_sli_flush_mbox_queue(phba); } @@ -1439,9 +1620,9 @@ lpfc_offline(struct lpfc_hba *phba) lpfc_stop_phba_timers(phba); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) lpfc_stop_vport_timers(vports[i]); - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0460 Bring Adapter offline\n"); /* Bring down the SLI Layer and cleanup. The HBA is offline @@ -1452,15 +1633,14 @@ lpfc_offline(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); - lpfc_cleanup(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->work_port_events = 0; vports[i]->fc_flag |= FC_OFFLINE_MODE; spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); } /****************************************************************************** @@ -1674,6 +1854,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) fc_host_supported_speeds(shost) = 0; if (phba->lmt & LMT_10Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT; + if (phba->lmt & LMT_8Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT; if (phba->lmt & LMT_4Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT; if (phba->lmt & LMT_2Gb) @@ -1707,13 +1889,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) struct Scsi_Host *shost = NULL; void *ptr; unsigned long bar0map_len, bar2map_len; - int error = -ENODEV; + int error = -ENODEV, retval; int i, hbq_count; uint16_t iotag; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_enable_device(pdev)) + if (pci_enable_device_bars(pdev, bars)) goto out; - if (pci_request_regions(pdev, LPFC_DRIVER_NAME)) + if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) goto out_disable_device; phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL); @@ -1823,9 +2006,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) lpfc_sli_setup(phba); lpfc_sli_queue_setup(phba); - error = lpfc_mem_alloc(phba); - if (error) + retval = lpfc_mem_alloc(phba); + if (retval) { + error = retval; goto out_free_hbqslimp; + } /* Initialize and populate the iocb list per host. */ INIT_LIST_HEAD(&phba->lpfc_iocb_list); @@ -1880,6 +2065,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) /* Initialize list of fabric iocbs */ INIT_LIST_HEAD(&phba->fabric_iocb_list); + /* Initialize list to save ELS buffers */ + INIT_LIST_HEAD(&phba->elsbuf); + vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); if (!vport) goto out_kthread_stop; @@ -1891,8 +2079,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) pci_set_drvdata(pdev, shost); if (phba->cfg_use_msi) { - error = pci_enable_msi(phba->pcidev); - if (!error) + retval = pci_enable_msi(phba->pcidev); + if (!retval) phba->using_msi = 1; else lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -1900,11 +2088,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) "with IRQ\n"); } - error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, + retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, LPFC_DRIVER_NAME, phba); - if (error) { + if (retval) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable interrupt handler failed\n"); + error = retval; goto out_disable_msi; } @@ -1914,11 +2103,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; - if (lpfc_alloc_sysfs_attr(vport)) + if (lpfc_alloc_sysfs_attr(vport)) { + error = -ENOMEM; goto out_free_irq; + } - if (lpfc_sli_hba_setup(phba)) + if (lpfc_sli_hba_setup(phba)) { + error = -ENODEV; goto out_remove_device; + } /* * hba setup may have changed the hba_queue_depth so we need to adjust @@ -1975,7 +2168,7 @@ out_idr_remove: out_free_phba: kfree(phba); out_release_regions: - pci_release_regions(pdev); + pci_release_selected_regions(pdev, bars); out_disable_device: pci_disable_device(pdev); out: @@ -1991,6 +2184,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); @@ -1998,8 +2193,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev) kfree(vport->vname); lpfc_free_sysfs_attr(vport); + kthread_stop(phba->worker_thread); + fc_remove_host(shost); scsi_remove_host(shost); + lpfc_cleanup(vport); + /* * Bring down the SLI Layer. This step disable all interrupts, * clears the rings, discards all mailbox commands, and resets @@ -2014,9 +2213,6 @@ lpfc_pci_remove_one(struct pci_dev *pdev) spin_unlock_irq(&phba->hbalock); lpfc_debugfs_terminate(vport); - lpfc_cleanup(vport); - - kthread_stop(phba->worker_thread); /* Release the irq reservation */ free_irq(phba->pcidev->irq, phba); @@ -2048,7 +2244,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) kfree(phba); - pci_release_regions(pdev); + pci_release_selected_regions(pdev, bars); pci_disable_device(pdev); } @@ -2239,12 +2435,22 @@ lpfc_init(void) printk(LPFC_MODULE_DESC "\n"); printk(LPFC_COPYRIGHT "\n"); + if (lpfc_enable_npiv) { + lpfc_transport_functions.vport_create = lpfc_vport_create; + lpfc_transport_functions.vport_delete = lpfc_vport_delete; + } lpfc_transport_template = fc_attach_transport(&lpfc_transport_functions); - lpfc_vport_transport_template = - fc_attach_transport(&lpfc_vport_transport_functions); - if (!lpfc_transport_template || !lpfc_vport_transport_template) + if (lpfc_transport_template == NULL) return -ENOMEM; + if (lpfc_enable_npiv) { + lpfc_vport_transport_template = + fc_attach_transport(&lpfc_vport_transport_functions); + if (lpfc_vport_transport_template == NULL) { + fc_release_transport(lpfc_transport_template); + return -ENOMEM; + } + } error = pci_register_driver(&lpfc_driver); if (error) { fc_release_transport(lpfc_transport_template); @@ -2259,7 +2465,8 @@ lpfc_exit(void) { pci_unregister_driver(&lpfc_driver); fc_release_transport(lpfc_transport_template); - fc_release_transport(lpfc_vport_transport_template); + if (lpfc_enable_npiv) + fc_release_transport(lpfc_vport_transport_template); } module_init(lpfc_init); diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 626e4d878725..c5841d7565f7 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -26,6 +26,7 @@ #define LOG_IP 0x20 /* IP traffic history */ #define LOG_FCP 0x40 /* FCP traffic history */ #define LOG_NODE 0x80 /* Node table events */ +#define LOG_TEMP 0x100 /* Temperature sensor events */ #define LOG_MISC 0x400 /* Miscellaneous events */ #define LOG_SLI 0x800 /* SLI events */ #define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */ diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index a592733664e9..dfc63f6ccd7b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -82,6 +82,24 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) } /**********************************************/ +/* lpfc_config_async Issue a */ +/* MBX_ASYNC_EVT_ENABLE mailbox command */ +/**********************************************/ +void +lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, + uint32_t ring) +{ + MAILBOX_t *mb; + + mb = &pmb->mb; + memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); + mb->mbxCommand = MBX_ASYNCEVT_ENABLE; + mb->un.varCfgAsyncEvent.ring = ring; + mb->mbxOwner = OWN_HOST; + return; +} + +/**********************************************/ /* lpfc_heart_beat Issue a HEART_BEAT */ /* mailbox command */ /**********************************************/ @@ -270,8 +288,10 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) /* Get a buffer to hold the HBAs Service Parameters */ - if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) || - ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) { + mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + if (mp) + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp || !mp->virt) { kfree(mp); mb->mbxCommand = MBX_READ_SPARM64; /* READ_SPARAM: no buffers */ @@ -369,8 +389,10 @@ lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, mb->mbxOwner = OWN_HOST; /* Get a buffer to hold NPorts Service Parameters */ - if (((mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == NULL) || - ((mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys))) == 0)) { + mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); + if (mp) + mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); + if (!mp || !mp->virt) { kfree(mp); mb->mbxCommand = MBX_REG_LOGIN64; /* REG_LOGIN: no buffers */ @@ -874,7 +896,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) case MBX_DOWN_LOAD: /* 0x1C */ case MBX_DEL_LD_ENTRY: /* 0x1D */ case MBX_LOAD_AREA: /* 0x81 */ - case MBX_FLASH_WR_ULA: /* 0x98 */ + case MBX_WRITE_WWN: /* 0x98 */ case MBX_LOAD_EXP_ROM: /* 0x9C */ return LPFC_MBOX_TMO_FLASH_CMD; } diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 43c3b8a0d76a..6dc5ab8d6716 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba) fail_free_hbq_pool: lpfc_sli_hbqbuf_free_all(phba); + pci_pool_destroy(phba->lpfc_hbq_pool); fail_free_nlp_mem_pool: mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 880af0cd463d..4a0e3406e37a 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -287,6 +287,24 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); + if (wwn_to_u64(sp->portName.u.wwn) == 0) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0140 PLOGI Reject: invalid nname\n"); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, + NULL); + return 0; + } + if (wwn_to_u64(sp->nodeName.u.wwn) == 0) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0141 PLOGI Reject: invalid pname\n"); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; + stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, + NULL); + return 0; + } if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; @@ -343,8 +361,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_config_link(phba, mbox); mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mbox->vport = vport; - rc = lpfc_sli_issue_mbox - (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); goto out; @@ -407,6 +424,61 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp, mbox); return 1; } + + /* If the remote NPort logs into us, before we can initiate + * discovery to them, cleanup the NPort from discovery accordingly. + */ + if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + del_timer_sync(&ndlp->nlp_delayfunc); + ndlp->nlp_last_elscmd = 0; + + if (!list_empty(&ndlp->els_retry_evt.evt_listp)) + list_del_init(&ndlp->els_retry_evt.evt_listp); + + if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); + + if ((ndlp->nlp_flag & NLP_ADISC_SND) && + (vport->num_disc_nodes)) { + /* Check to see if there are more + * ADISCs to be sent + */ + lpfc_more_adisc(vport); + + if ((vport->num_disc_nodes == 0) && + (vport->fc_npr_cnt)) + lpfc_els_disc_plogi(vport); + + if (vport->num_disc_nodes == 0) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + lpfc_end_rscn(vport); + } + } + else if (vport->num_disc_nodes) { + /* Check to see if there are more + * PLOGIs to be sent + */ + lpfc_more_plogi(vport); + + if (vport->num_disc_nodes == 0) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + lpfc_end_rscn(vport); + } + } + } + } + lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); return 1; @@ -501,12 +573,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - } else { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); } + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; @@ -594,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; } +static uint32_t +lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + /* This transition is only legal if we previously + * rcv'ed a PLOGI. Since we don't want 2 discovery threads + * working on the same NPortID, do nothing for this thread + * to stop it. + */ + if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + "0253 Illegal State Transition: node x%x " + "event x%x, state x%x Data: x%x x%x\n", + ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, + ndlp->nlp_flag); + } + return ndlp->nlp_state; +} + /* Start of Discovery State Machine routines */ static uint32_t @@ -605,11 +693,8 @@ lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, cmdiocb = (struct lpfc_iocbq *) arg; if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { - ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } - lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -618,7 +703,6 @@ lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { lpfc_issue_els_logo(vport, ndlp, 0); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -633,7 +717,6 @@ lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_flag |= NLP_LOGO_ACC; spin_unlock_irq(shost->host_lock); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -642,7 +725,6 @@ static uint32_t lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -650,7 +732,6 @@ static uint32_t lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { - lpfc_drop_node(vport, ndlp); return NLP_STE_FREED_NODE; } @@ -752,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, uint32_t evt) { struct lpfc_hba *phba = vport->phba; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb, *rspiocb; struct lpfc_dmabuf *pcmd, *prsp, *mp; uint32_t *lp; @@ -778,6 +860,12 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, lp = (uint32_t *) prsp->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); + if (wwn_to_u64(sp->portName.u.wwn) == 0 || + wwn_to_u64(sp->nodeName.u.wwn) == 0) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0142 PLOGI RSP: Invalid WWN.\n"); + goto out; + } if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3)) goto out; /* PLOGI chkparm OK */ @@ -828,13 +916,15 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, } mbox->context2 = lpfc_nlp_get(ndlp); mbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) != MBX_NOT_FINISHED) { lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); return ndlp->nlp_state; } + /* decrement node reference count to the failed mbox + * command + */ lpfc_nlp_put(ndlp); mp = (struct lpfc_dmabuf *) mbox->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -864,13 +954,27 @@ out: "0261 Cannot Register NameServer login\n"); } - /* Free this node since the driver cannot login or has the wrong - sparm */ - lpfc_drop_node(vport, ndlp); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DEFER_RM; + spin_unlock_irq(shost->host_lock); return NLP_STE_FREED_NODE; } static uint32_t +lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + return ndlp->nlp_state; +} + +static uint32_t +lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) +{ + return ndlp->nlp_state; +} + +static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { @@ -1137,7 +1241,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); + __lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } lpfc_nlp_put(ndlp); @@ -1197,8 +1301,8 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, * retry discovery. */ if (mb->mbxStatus == MBXERR_RPI_FULL) { - ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -1378,7 +1482,7 @@ out: lpfc_issue_els_logo(vport, ndlp, 0); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -1753,7 +1857,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, irsp = &rspiocb->iocb; if (irsp->ulpStatus) { - lpfc_drop_node(vport, ndlp); + ndlp->nlp_flag |= NLP_DEFER_RM; return NLP_STE_FREED_NODE; } return ndlp->nlp_state; @@ -1942,9 +2046,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_rcv_els_plogi_issue, /* RCV_PRLO */ lpfc_cmpl_plogi_plogi_issue, /* CMPL_PLOGI */ lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ + lpfc_cmpl_logo_plogi_issue, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ + lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN */ lpfc_device_rm_plogi_issue, /* DEVICE_RM */ lpfc_device_recov_plogi_issue, /* DEVICE_RECOVERY */ @@ -1968,7 +2072,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ lpfc_disc_illegal, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ @@ -1982,7 +2086,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 4e46045dea6d..fc5c3a42b05a 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { new_queue_depth = @@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) new_queue_depth); } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); atomic_set(&phba->num_rsrc_err, 0); atomic_set(&phba->num_cmd_success, 0); } @@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { if (sdev->ordered_tags) @@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) sdev->queue_depth+1); } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); atomic_set(&phba->num_rsrc_err, 0); atomic_set(&phba->num_cmd_success, 0); } @@ -380,7 +380,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) (num_bde * sizeof (struct ulp_bde64)); iocb_cmd->ulpBdeCount = 1; iocb_cmd->ulpLe = 1; - fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd)); + fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); return 0; } @@ -542,6 +542,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, int result; struct scsi_device *sdev, *tmp_sdev; int depth = 0; + unsigned long flags; lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; @@ -608,6 +609,15 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { + /* + * If there is a thread waiting for command completion + * wake up the thread. + */ + spin_lock_irqsave(sdev->host->host_lock, flags); + lpfc_cmd->pCmd = NULL; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); + spin_unlock_irqrestore(sdev->host->host_lock, flags); lpfc_release_scsi_buf(phba, lpfc_cmd); return; } @@ -669,6 +679,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } } + /* + * If there is a thread waiting for command completion + * wake up the thread. + */ + spin_lock_irqsave(sdev->host->host_lock, flags); + lpfc_cmd->pCmd = NULL; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); + spin_unlock_irqrestore(sdev->host->host_lock, flags); + lpfc_release_scsi_buf(phba, lpfc_cmd); } @@ -743,6 +763,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, piocbq->iocb.ulpContext = pnode->nlp_rpi; if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) piocbq->iocb.ulpFCP2Rcvy = 1; + else + piocbq->iocb.ulpFCP2Rcvy = 0; piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); piocbq->context1 = lpfc_cmd; @@ -1018,8 +1040,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) struct lpfc_iocbq *abtsiocb; struct lpfc_scsi_buf *lpfc_cmd; IOCB_t *cmd, *icmd; - unsigned int loop_count = 0; int ret = SUCCESS; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); lpfc_block_error_handler(cmnd); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; @@ -1074,17 +1096,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_sli_poll_fcp_ring (phba); + lpfc_cmd->waitq = &waitq; /* Wait for abort to complete */ - while (lpfc_cmd->pCmd == cmnd) - { - if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_sli_poll_fcp_ring (phba); + wait_event_timeout(waitq, + (lpfc_cmd->pCmd != cmnd), + (2*vport->cfg_devloss_tmo*HZ)); - schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ); - if (++loop_count - > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT) - break; - } + spin_lock_irq(shost->host_lock); + lpfc_cmd->waitq = NULL; + spin_unlock_irq(shost->host_lock); if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; @@ -1438,8 +1458,7 @@ struct scsi_host_template lpfc_template = { .slave_destroy = lpfc_slave_destroy, .scan_finished = lpfc_scan_finished, .this_id = -1, - .sg_tablesize = LPFC_SG_SEG_CNT, - .use_sg_chaining = ENABLE_SG_CHAINING, + .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_hba_attrs, @@ -1459,10 +1478,9 @@ struct scsi_host_template lpfc_vport_template = { .slave_destroy = lpfc_slave_destroy, .scan_finished = lpfc_scan_finished, .this_id = -1, - .sg_tablesize = LPFC_SG_SEG_CNT, + .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = lpfc_vport_attrs, .max_sectors = 0xFFFF, }; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 31787bb6d53e..daba92374985 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -138,6 +138,7 @@ struct lpfc_scsi_buf { * Iotag is in here */ struct lpfc_iocbq cur_iocbq; + wait_queue_head_t *waitq; }; #define LPFC_SCSI_DMA_EXT_SIZE 264 diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ce348c5c706c..fdd01e384e36 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -106,7 +106,7 @@ lpfc_sli_get_iocbq(struct lpfc_hba *phba) return iocbq; } -void +static void __lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) { size_t start_clean = offsetof(struct lpfc_iocbq, iocb); @@ -199,6 +199,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_RCV_ELS_REQ_CX: case CMD_RCV_SEQUENCE64_CX: case CMD_RCV_ELS_REQ64_CX: + case CMD_ASYNC_STATUS: case CMD_IOCB_RCV_SEQ64_CX: case CMD_IOCB_RCV_ELS64_CX: case CMD_IOCB_RCV_CONT64_CX: @@ -473,8 +474,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) if (pring->txq_cnt && lpfc_is_link_up(phba) && (pring->ringno != phba->sli.fcp_ring || - phba->sli.sli_flag & LPFC_PROCESS_LA) && - !(pring->flag & LPFC_STOP_IOCB_MBX)) { + phba->sli.sli_flag & LPFC_PROCESS_LA)) { while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) && (nextiocb = lpfc_sli_ringtx_get(phba, pring))) @@ -489,32 +489,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return; } -/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */ -static void -lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno) -{ - struct lpfc_pgp *pgp = (phba->sli_rev == 3) ? - &phba->slim2p->mbx.us.s3_pgp.port[ringno] : - &phba->slim2p->mbx.us.s2.port[ringno]; - unsigned long iflags; - - /* If the ring is active, flag it */ - spin_lock_irqsave(&phba->hbalock, iflags); - if (phba->sli.ring[ringno].cmdringaddr) { - if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) { - phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX; - /* - * Force update of the local copy of cmdGetInx - */ - phba->sli.ring[ringno].local_getidx - = le32_to_cpu(pgp->cmdGetInx); - lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]); - } - } - spin_unlock_irqrestore(&phba->hbalock, iflags); -} - -struct lpfc_hbq_entry * +static struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) { struct hbq_s *hbqp = &phba->hbqs[hbqno]; @@ -565,6 +540,7 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) list_del(&hbq_buf->dbuf.list); (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf); } + phba->hbqs[i].buffer_count = 0; } } @@ -633,8 +609,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) return 0; } - start = lpfc_hbq_defs[hbqno]->buffer_count; - end = count + lpfc_hbq_defs[hbqno]->buffer_count; + start = phba->hbqs[hbqno].buffer_count; + end = count + start; if (end > lpfc_hbq_defs[hbqno]->entry_count) { end = lpfc_hbq_defs[hbqno]->entry_count; } @@ -646,7 +622,7 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) return 1; hbq_buffer->tag = (i | (hbqno << 16)); if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) - lpfc_hbq_defs[hbqno]->buffer_count++; + phba->hbqs[hbqno].buffer_count++; else (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); } @@ -660,14 +636,14 @@ lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno) lpfc_hbq_defs[qno]->add_count)); } -int +static int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno) { return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno, lpfc_hbq_defs[qno]->init_count)); } -struct hbq_dmabuf * +static struct hbq_dmabuf * lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) { struct lpfc_dmabuf *d_buf; @@ -686,7 +662,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) } lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, "1803 Bad hbq tag. Data: x%x x%x\n", - tag, lpfc_hbq_defs[tag >> 16]->buffer_count); + tag, phba->hbqs[tag >> 16].buffer_count); return NULL; } @@ -712,6 +688,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_LOAD_SM: case MBX_READ_NV: case MBX_WRITE_NV: + case MBX_WRITE_VPARMS: case MBX_RUN_BIU_DIAG: case MBX_INIT_LINK: case MBX_DOWN_LINK: @@ -739,7 +716,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_DEL_LD_ENTRY: case MBX_RUN_PROGRAM: case MBX_SET_MASK: - case MBX_SET_SLIM: + case MBX_SET_VARIABLE: case MBX_UNREG_D_ID: case MBX_KILL_BOARD: case MBX_CONFIG_FARP: @@ -751,9 +728,10 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_READ_RPI64: case MBX_REG_LOGIN64: case MBX_READ_LA64: - case MBX_FLASH_WR_ULA: + case MBX_WRITE_WWN: case MBX_SET_DEBUG: case MBX_LOAD_EXP_ROM: + case MBX_ASYNCEVT_ENABLE: case MBX_REG_VPI: case MBX_UNREG_VPI: case MBX_HEARTBEAT: @@ -953,6 +931,17 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) return &new_hbq_entry->dbuf; } +static struct lpfc_dmabuf * +lpfc_sli_get_buff(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, + uint32_t tag) +{ + if (tag & QUE_BUFTAG_BIT) + return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); + else + return lpfc_sli_replace_hbqbuff(phba, tag); +} + static int lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *saveq) @@ -961,19 +950,112 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, WORD5 * w5p; uint32_t Rctl, Type; uint32_t match, i; + struct lpfc_iocbq *iocbq; match = 0; irsp = &(saveq->iocb); - if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) - || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) - || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX) - || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) { + + if (irsp->ulpStatus == IOSTAT_NEED_BUFFER) + return 1; + if (irsp->ulpCommand == CMD_ASYNC_STATUS) { + if (pring->lpfc_sli_rcv_async_status) + pring->lpfc_sli_rcv_async_status(phba, pring, saveq); + else + lpfc_printf_log(phba, + KERN_WARNING, + LOG_SLI, + "0316 Ring %d handler: unexpected " + "ASYNC_STATUS iocb received evt_code " + "0x%x\n", + pring->ringno, + irsp->un.asyncstat.evt_code); + return 1; + } + + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + if (irsp->ulpBdeCount != 0) { + saveq->context2 = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + if (!saveq->context2) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0341 Ring %d Cannot find buffer for " + "an unsolicited iocb. tag 0x%x\n", + pring->ringno, + irsp->un.ulpWord[3]); + } + if (irsp->ulpBdeCount == 2) { + saveq->context3 = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[7]); + if (!saveq->context3) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0342 Ring %d Cannot find buffer for an" + " unsolicited iocb. tag 0x%x\n", + pring->ringno, + irsp->unsli3.sli3Words[7]); + } + list_for_each_entry(iocbq, &saveq->list, list) { + irsp = &(iocbq->iocb); + if (irsp->ulpBdeCount != 0) { + iocbq->context2 = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + if (!iocbq->context2) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0343 Ring %d Cannot find " + "buffer for an unsolicited iocb" + ". tag 0x%x\n", pring->ringno, + irsp->un.ulpWord[3]); + } + if (irsp->ulpBdeCount == 2) { + iocbq->context3 = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[7]); + if (!iocbq->context3) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0344 Ring %d Cannot find " + "buffer for an unsolicited " + "iocb. tag 0x%x\n", + pring->ringno, + irsp->unsli3.sli3Words[7]); + } + } + } + if (irsp->ulpBdeCount != 0 && + (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX || + irsp->ulpStatus == IOSTAT_INTERMED_RSP)) { + int found = 0; + + /* search continue save q for same XRI */ + list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) { + if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) { + list_add_tail(&saveq->list, &iocbq->list); + found = 1; + break; + } + } + if (!found) + list_add_tail(&saveq->clist, + &pring->iocb_continue_saveq); + if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) { + list_del_init(&iocbq->clist); + saveq = iocbq; + irsp = &(saveq->iocb); + } else + return 0; + } + if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) || + (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) || + (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) { Rctl = FC_ELS_REQ; Type = FC_ELS_DATA; } else { - w5p = - (WORD5 *) & (saveq->iocb.un. - ulpWord[5]); + w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]); Rctl = w5p->hcsw.Rctl; Type = w5p->hcsw.Type; @@ -988,15 +1070,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - if (irsp->ulpBdeCount != 0) - saveq->context2 = lpfc_sli_replace_hbqbuff(phba, - irsp->un.ulpWord[3]); - if (irsp->ulpBdeCount == 2) - saveq->context3 = lpfc_sli_replace_hbqbuff(phba, - irsp->unsli3.sli3Words[7]); - } - /* unSolicited Responses */ if (pring->prt[0].profile) { if (pring->prt[0].lpfc_sli_rcv_unsol_event) @@ -1006,12 +1079,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } else { /* We must search, based on rctl / type for the right routine */ - for (i = 0; i < pring->num_mask; - i++) { - if ((pring->prt[i].rctl == - Rctl) - && (pring->prt[i]. - type == Type)) { + for (i = 0; i < pring->num_mask; i++) { + if ((pring->prt[i].rctl == Rctl) + && (pring->prt[i].type == Type)) { if (pring->prt[i].lpfc_sli_rcv_unsol_event) (pring->prt[i].lpfc_sli_rcv_unsol_event) (phba, pring, saveq); @@ -1084,6 +1154,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOSTAT_LOCAL_REJECT; saveq->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; + + /* Firmware could still be in progress + * of DMAing payload, so don't free data + * buffer till after a hbeat. + */ + saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; } } (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); @@ -1572,12 +1648,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - if (list_empty(&(pring->iocb_continueq))) { - list_add(&rspiocbp->list, &(pring->iocb_continueq)); - } else { - list_add_tail(&rspiocbp->list, - &(pring->iocb_continueq)); - } + list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); pring->iocb_continueq_cnt++; if (irsp->ulpLe) { @@ -1642,17 +1713,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); if (type == LPFC_SOL_IOCB) { - spin_unlock_irqrestore(&phba->hbalock, - iflag); + spin_unlock_irqrestore(&phba->hbalock, iflag); rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); spin_lock_irqsave(&phba->hbalock, iflag); } else if (type == LPFC_UNSOL_IOCB) { - spin_unlock_irqrestore(&phba->hbalock, - iflag); + spin_unlock_irqrestore(&phba->hbalock, iflag); rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); spin_lock_irqsave(&phba->hbalock, iflag); + if (!rc) + free_saveq = 0; } else if (type == LPFC_ABORT_IOCB) { if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) && ((cmdiocbp = @@ -1921,8 +1992,8 @@ lpfc_sli_brdkill(struct lpfc_hba *phba) "0329 Kill HBA Data: x%x x%x\n", phba->pport->port_state, psli->sli_flag); - if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL)) == 0) + pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmb) return 1; /* Disable the error attention */ @@ -2113,7 +2184,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) <status> */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0436 Adapter failed to init, " - "timeout, status reg x%x\n", status); + "timeout, status reg x%x, " + "FW Data: A8 x%x AC x%x\n", status, + readl(phba->MBslimaddr + 0xa8), + readl(phba->MBslimaddr + 0xac)); phba->link_state = LPFC_HBA_ERROR; return -ETIMEDOUT; } @@ -2125,7 +2199,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) <status> */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0437 Adapter failed to init, " - "chipset, status reg x%x\n", status); + "chipset, status reg x%x, " + "FW Data: A8 x%x AC x%x\n", status, + readl(phba->MBslimaddr + 0xa8), + readl(phba->MBslimaddr + 0xac)); phba->link_state = LPFC_HBA_ERROR; return -EIO; } @@ -2153,7 +2230,10 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba) /* Adapter failed to init, chipset, status reg <status> */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0438 Adapter failed to init, chipset, " - "status reg x%x\n", status); + "status reg x%x, " + "FW Data: A8 x%x AC x%x\n", status, + readl(phba->MBslimaddr + 0xa8), + readl(phba->MBslimaddr + 0xac)); phba->link_state = LPFC_HBA_ERROR; return -EIO; } @@ -2485,11 +2565,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) lpfc_sli_abort_iocb_ring(phba, pring); lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0316 Resetting board due to mailbox timeout\n"); + "0345 Resetting board due to mailbox timeout\n"); /* * lpfc_offline calls lpfc_sli_hba_down which will clean up * on oustanding mailbox commands. */ + /* If resets are disabled then set error state and return. */ + if (!phba->cfg_enable_hba_reset) { + phba->link_state = LPFC_HBA_ERROR; + return; + } lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); @@ -2507,6 +2592,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) uint32_t status, evtctr; uint32_t ha_copy; int i; + unsigned long timeout; unsigned long drvr_flag = 0; volatile uint32_t word0, ldata; void __iomem *to_slim; @@ -2519,7 +2605,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) "1806 Mbox x%x failed. No vport\n", pmbox->mb.mbxCommand); dump_stack(); - return MBXERR_ERROR; + return MBX_NOT_FINISHED; } } @@ -2571,21 +2657,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) return MBX_NOT_FINISHED; } - /* Handle STOP IOCB processing flag. This is only meaningful - * if we are not polling for mbox completion. - */ - if (flag & MBX_STOP_IOCB) { - flag &= ~MBX_STOP_IOCB; - /* Now flag each ring */ - for (i = 0; i < psli->num_rings; i++) { - /* If the ring is active, flag it */ - if (psli->ring[i].cmdringaddr) { - psli->ring[i].flag |= - LPFC_STOP_IOCB_MBX; - } - } - } - /* Another mailbox command is still being processed, queue this * command to be processed later. */ @@ -2620,23 +2691,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) return MBX_BUSY; } - /* Handle STOP IOCB processing flag. This is only meaningful - * if we are not polling for mbox completion. - */ - if (flag & MBX_STOP_IOCB) { - flag &= ~MBX_STOP_IOCB; - if (flag == MBX_NOWAIT) { - /* Now flag each ring */ - for (i = 0; i < psli->num_rings; i++) { - /* If the ring is active, flag it */ - if (psli->ring[i].cmdringaddr) { - psli->ring[i].flag |= - LPFC_STOP_IOCB_MBX; - } - } - } - } - psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; /* If we are not polling, we MUST be in SLI2 mode */ @@ -2714,18 +2768,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) } wmb(); - /* interrupt board to doit right away */ - writel(CA_MBATT, phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ switch (flag) { case MBX_NOWAIT: - /* Don't wait for it to finish, just return */ + /* Set up reference to mailbox command */ psli->mbox_active = pmbox; + /* Interrupt board to do it */ + writel(CA_MBATT, phba->CAregaddr); + readl(phba->CAregaddr); /* flush */ + /* Don't wait for it to finish, just return */ break; case MBX_POLL: + /* Set up null reference to mailbox command */ psli->mbox_active = NULL; + /* Interrupt board to do it */ + writel(CA_MBATT, phba->CAregaddr); + readl(phba->CAregaddr); /* flush */ + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { /* First read mbox status word */ word0 = *((volatile uint32_t *)&phba->slim2p->mbx); @@ -2737,15 +2797,15 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) /* Read the HBA Host Attention Register */ ha_copy = readl(phba->HAregaddr); - - i = lpfc_mbox_tmo_val(phba, mb->mbxCommand); - i *= 1000; /* Convert to ms */ - + timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, + mb->mbxCommand) * + 1000) + jiffies; + i = 0; /* Wait for command to complete */ while (((word0 & OWN_CHIP) == OWN_CHIP) || (!(ha_copy & HA_MBATT) && (phba->link_state > LPFC_WARM_START))) { - if (i-- <= 0) { + if (time_after(jiffies, timeout)) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); @@ -2758,12 +2818,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) && (evtctr != psli->slistat.mbox_event)) break; - spin_unlock_irqrestore(&phba->hbalock, - drvr_flag); - - msleep(1); - - spin_lock_irqsave(&phba->hbalock, drvr_flag); + if (i++ > 10) { + spin_unlock_irqrestore(&phba->hbalock, + drvr_flag); + msleep(1); + spin_lock_irqsave(&phba->hbalock, drvr_flag); + } if (psli->sli_flag & LPFC_SLI2_ACTIVE) { /* First copy command data */ @@ -2848,7 +2908,7 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* * Lockless version of lpfc_sli_issue_iocb. */ -int +static int __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb, uint32_t flag) { @@ -2879,9 +2939,9 @@ __lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* * Check to see if we are blocking IOCB processing because of a - * outstanding mbox command. + * outstanding event. */ - if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX)) + if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT)) goto iocb_busy; if (unlikely(phba->link_state == LPFC_LINK_DOWN)) { @@ -2993,6 +3053,61 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba) return 0; } +static void +lpfc_sli_async_event_handler(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq) +{ + IOCB_t *icmd; + uint16_t evt_code; + uint16_t temp; + struct temp_event temp_event_data; + struct Scsi_Host *shost; + + icmd = &iocbq->iocb; + evt_code = icmd->un.asyncstat.evt_code; + temp = icmd->ulpContext; + + if ((evt_code != ASYNC_TEMP_WARN) && + (evt_code != ASYNC_TEMP_SAFE)) { + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0346 Ring %d handler: unexpected ASYNC_STATUS" + " evt_code 0x%x\n", + pring->ringno, + icmd->un.asyncstat.evt_code); + return; + } + temp_event_data.data = (uint32_t)temp; + temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; + if (evt_code == ASYNC_TEMP_WARN) { + temp_event_data.event_code = LPFC_THRESHOLD_TEMP; + lpfc_printf_log(phba, + KERN_ERR, + LOG_TEMP, + "0347 Adapter is very hot, please take " + "corrective action. temperature : %d Celsius\n", + temp); + } + if (evt_code == ASYNC_TEMP_SAFE) { + temp_event_data.event_code = LPFC_NORMAL_TEMP; + lpfc_printf_log(phba, + KERN_ERR, + LOG_TEMP, + "0340 Adapter temperature is OK now. " + "temperature : %d Celsius\n", + temp); + } + + /* Send temperature change event to applications */ + shost = lpfc_shost_from_vport(phba->pport); + fc_host_post_vendor_event(shost, fc_get_event_number(), + sizeof(temp_event_data), (char *) &temp_event_data, + SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); + +} + + int lpfc_sli_setup(struct lpfc_hba *phba) { @@ -3059,6 +3174,8 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->fast_iotag = 0; pring->iotag_ctr = 0; pring->iotag_max = 4096; + pring->lpfc_sli_rcv_async_status = + lpfc_sli_async_event_handler; pring->num_mask = 4; pring->prt[0].profile = 0; /* Mask 0 */ pring->prt[0].rctl = FC_ELS_REQ; @@ -3123,6 +3240,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&pring->txq); INIT_LIST_HEAD(&pring->txcmplq); INIT_LIST_HEAD(&pring->iocb_continueq); + INIT_LIST_HEAD(&pring->iocb_continue_saveq); INIT_LIST_HEAD(&pring->postbufq); } spin_unlock_irq(&phba->hbalock); @@ -3193,6 +3311,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) LIST_HEAD(completions); struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; + struct lpfc_dmabuf *buf_ptr; LPFC_MBOXQ_t *pmb; struct lpfc_iocbq *iocb; IOCB_t *cmd = NULL; @@ -3232,6 +3351,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) } } + spin_lock_irqsave(&phba->hbalock, flags); + list_splice_init(&phba->elsbuf, &completions); + phba->elsbuf_cnt = 0; + phba->elsbuf_prev_cnt = 0; + spin_unlock_irqrestore(&phba->hbalock, flags); + + while (!list_empty(&completions)) { + list_remove_head(&completions, buf_ptr, + struct lpfc_dmabuf, list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); + } + /* Return any active mbox cmds */ del_timer_sync(&psli->mbox_tmo); spin_lock_irqsave(&phba->hbalock, flags); @@ -3294,6 +3426,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 0; } +uint32_t +lpfc_sli_get_buffer_tag(struct lpfc_hba *phba) +{ + spin_lock_irq(&phba->hbalock); + phba->buffer_tag_count++; + /* + * Always set the QUE_BUFTAG_BIT to distiguish between + * a tag assigned by HBQ. + */ + phba->buffer_tag_count |= QUE_BUFTAG_BIT; + spin_unlock_irq(&phba->hbalock); + return phba->buffer_tag_count; +} + +struct lpfc_dmabuf * +lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + uint32_t tag) +{ + struct lpfc_dmabuf *mp, *next_mp; + struct list_head *slp = &pring->postbufq; + + /* Search postbufq, from the begining, looking for a match on tag */ + spin_lock_irq(&phba->hbalock); + list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { + if (mp->buffer_tag == tag) { + list_del_init(&mp->list); + pring->postbufq_cnt--; + spin_unlock_irq(&phba->hbalock); + return mp; + } + } + + spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0410 Cannot find virtual addr for buffer tag on " + "ring %d Data x%lx x%p x%p x%x\n", + pring->ringno, (unsigned long) tag, + slp->next, slp->prev, pring->postbufq_cnt); + + return NULL; +} struct lpfc_dmabuf * lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, @@ -3361,6 +3534,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, pring->txcmplq_cnt--; spin_unlock_irq(&phba->hbalock); + /* Firmware could still be in progress of DMAing + * payload, so don't free data buffer till after + * a hbeat. + */ + abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; + abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; @@ -3699,7 +3878,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, unsigned long flag; /* The caller must leave context1 empty. */ - if (pmboxq->context1 != 0) + if (pmboxq->context1) return MBX_NOT_FINISHED; /* setup wake call as IOCB callback */ @@ -3771,7 +3950,6 @@ lpfc_intr_handler(int irq, void *dev_id) uint32_t ha_copy; uint32_t work_ha_copy; unsigned long status; - int i; uint32_t control; MAILBOX_t *mbox, *pmbox; @@ -3888,7 +4066,6 @@ lpfc_intr_handler(int irq, void *dev_id) } if (work_ha_copy & HA_ERATT) { - phba->link_state = LPFC_HBA_ERROR; /* * There was a link/board error. Read the * status register to retrieve the error event @@ -3920,7 +4097,7 @@ lpfc_intr_handler(int irq, void *dev_id) * Stray Mailbox Interrupt, mbxCommand <cmd> * mbxStatus <status> */ - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "(%d):0304 Stray Mailbox " "Interrupt mbxCommand x%x " @@ -3928,51 +4105,60 @@ lpfc_intr_handler(int irq, void *dev_id) (vport ? vport->vpi : 0), pmbox->mbxCommand, pmbox->mbxStatus); - } - phba->last_completion_time = jiffies; - del_timer_sync(&phba->sli.mbox_tmo); - - phba->sli.mbox_active = NULL; - if (pmb->mbox_cmpl) { - lpfc_sli_pcimem_bcopy(mbox, pmbox, - MAILBOX_CMD_SIZE); - } - if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { - pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; + /* clear mailbox attention bit */ + work_ha_copy &= ~HA_MBATT; + } else { + phba->last_completion_time = jiffies; + del_timer(&phba->sli.mbox_tmo); - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX dflt rpi: : status:x%x rpi:x%x", - (uint32_t)pmbox->mbxStatus, - pmbox->un.varWords[0], 0); - - if ( !pmbox->mbxStatus) { - mp = (struct lpfc_dmabuf *) - (pmb->context1); - ndlp = (struct lpfc_nodelist *) - pmb->context2; - - /* Reg_LOGIN of dflt RPI was successful. - * new lets get rid of the RPI using the - * same mbox buffer. - */ - lpfc_unreg_login(phba, vport->vpi, - pmbox->un.varWords[0], pmb); - pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - pmb->context1 = mp; - pmb->context2 = ndlp; - pmb->vport = vport; - spin_lock(&phba->hbalock); - phba->sli.sli_flag &= - ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock(&phba->hbalock); - goto send_current_mbox; + phba->sli.mbox_active = NULL; + if (pmb->mbox_cmpl) { + lpfc_sli_pcimem_bcopy(mbox, pmbox, + MAILBOX_CMD_SIZE); + } + if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { + pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; + + lpfc_debugfs_disc_trc(vport, + LPFC_DISC_TRC_MBOX_VPORT, + "MBOX dflt rpi: : " + "status:x%x rpi:x%x", + (uint32_t)pmbox->mbxStatus, + pmbox->un.varWords[0], 0); + + if (!pmbox->mbxStatus) { + mp = (struct lpfc_dmabuf *) + (pmb->context1); + ndlp = (struct lpfc_nodelist *) + pmb->context2; + + /* Reg_LOGIN of dflt RPI was + * successful. new lets get + * rid of the RPI using the + * same mbox buffer. + */ + lpfc_unreg_login(phba, + vport->vpi, + pmbox->un.varWords[0], + pmb); + pmb->mbox_cmpl = + lpfc_mbx_cmpl_dflt_rpi; + pmb->context1 = mp; + pmb->context2 = ndlp; + pmb->vport = vport; + spin_lock(&phba->hbalock); + phba->sli.sli_flag &= + ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock(&phba->hbalock); + goto send_current_mbox; + } } + spin_lock(&phba->pport->work_port_lock); + phba->pport->work_port_events &= + ~WORKER_MBOX_TMO; + spin_unlock(&phba->pport->work_port_lock); + lpfc_mbox_cmpl_put(phba, pmb); } - spin_lock(&phba->pport->work_port_lock); - phba->pport->work_port_events &= ~WORKER_MBOX_TMO; - spin_unlock(&phba->pport->work_port_lock); - lpfc_mbox_cmpl_put(phba, pmb); } if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active == NULL)) { @@ -3990,10 +4176,6 @@ send_current_mbox: lpfc_mbox_cmpl_put(phba, pmb); goto send_next_mbox; } - } else { - /* Turn on IOCB processing */ - for (i = 0; i < phba->sli.num_rings; i++) - lpfc_sli_turn_on_ring(phba, i); } } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 51b2b6b949be..7249fd252cbb 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd { struct lpfc_iocbq { /* lpfc_iocbqs are used in double linked lists */ struct list_head list; + struct list_head clist; uint16_t iotag; /* pre-assigned IO tag */ uint16_t rsvd1; @@ -44,6 +45,7 @@ struct lpfc_iocbq { #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ +#define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ uint8_t abort_count; uint8_t rsvd2; @@ -92,8 +94,6 @@ typedef struct lpfcMboxq { #define MBX_POLL 1 /* poll mailbox till command done, then return */ #define MBX_NOWAIT 2 /* issue command then return immediately */ -#define MBX_STOP_IOCB 4 /* Stop iocb processing till mbox cmds - complete */ #define LPFC_MAX_RING_MASK 4 /* max num of rctl/type masks allowed per ring */ @@ -129,9 +129,7 @@ struct lpfc_sli_ring { uint16_t flag; /* ring flags */ #define LPFC_DEFERRED_RING_EVENT 0x001 /* Deferred processing a ring event */ #define LPFC_CALL_RING_AVAILABLE 0x002 /* indicates cmd was full */ -#define LPFC_STOP_IOCB_MBX 0x010 /* Stop processing IOCB cmds mbox */ #define LPFC_STOP_IOCB_EVENT 0x020 /* Stop processing IOCB cmds event */ -#define LPFC_STOP_IOCB_MASK 0x030 /* Stop processing IOCB cmds mask */ uint16_t abtsiotag; /* tracks next iotag to use for ABTS */ uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */ @@ -163,9 +161,12 @@ struct lpfc_sli_ring { struct list_head iocb_continueq; uint16_t iocb_continueq_cnt; /* current length of queue */ uint16_t iocb_continueq_max; /* max length */ + struct list_head iocb_continue_saveq; struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK]; uint32_t num_mask; /* number of mask entries in prt array */ + void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *, + struct lpfc_sli_ring *, struct lpfc_iocbq *); struct lpfc_sli_ring_stat stats; /* SLI statistical info */ @@ -199,9 +200,6 @@ struct lpfc_hbq_init { uint32_t add_count; /* number to allocate when starved */ } ; -#define LPFC_MAX_HBQ 16 - - /* Structure used to hold SLI statistical counters and info */ struct lpfc_sli_stat { uint64_t mbox_stat_err; /* Mbox cmds completed status error */ diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 0081f49286bc..4b633d39a82a 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,10 +18,10 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.2.2" +#define LPFC_DRIVER_VERSION "8.2.4" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex. All rights reserved." +#define LPFC_COPYRIGHT "Copyright(c) 2004-2008 Emulex. All rights reserved." diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index dcb415e717c3..9fad7663c117 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -125,15 +125,26 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) pmb->vport = vport; rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2); if (rc != MBX_SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, - "1818 VPort failed init, mbxCmd x%x " - "READ_SPARM mbxStatus x%x, rc = x%x\n", - mb->mbxCommand, mb->mbxStatus, rc); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - if (rc != MBX_TIMEOUT) - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; + if (signal_pending(current)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + "1830 Signal aborted mbxCmd x%x\n", + mb->mbxCommand); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + if (rc != MBX_TIMEOUT) + mempool_free(pmb, phba->mbox_mem_pool); + return -EINTR; + } else { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, + "1818 VPort failed init, mbxCmd x%x " + "READ_SPARM mbxStatus x%x, rc = x%x\n", + mb->mbxCommand, mb->mbxStatus, rc); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + if (rc != MBX_TIMEOUT) + mempool_free(pmb, phba->mbox_mem_pool); + return -EIO; + } } memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); @@ -204,6 +215,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) int instance; int vpi; int rc = VPORT_ERROR; + int status; if ((phba->sli_rev < 3) || !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { @@ -248,13 +260,19 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) vport->vpi = vpi; lpfc_debugfs_initialize(vport); - if (lpfc_vport_sparm(phba, vport)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1813 Create VPORT failed. " - "Cannot get sparam\n"); + if ((status = lpfc_vport_sparm(phba, vport))) { + if (status == -EINTR) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + "1831 Create VPORT Interrupted.\n"); + rc = VPORT_ERROR; + } else { + lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, + "1813 Create VPORT failed. " + "Cannot get sparam\n"); + rc = VPORT_NORESOURCES; + } lpfc_free_vpi(phba, vpi); destroy_port(vport); - rc = VPORT_NORESOURCES; goto error_out; } @@ -427,7 +445,6 @@ int lpfc_vport_delete(struct fc_vport *fc_vport) { struct lpfc_nodelist *ndlp = NULL; - struct lpfc_nodelist *next_ndlp; struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; struct lpfc_hba *phba = vport->phba; @@ -482,8 +499,18 @@ lpfc_vport_delete(struct fc_vport *fc_vport) ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP) { - + phba->link_state >= LPFC_LINK_UP) { + if (vport->cfg_enable_da_id) { + timeout = msecs_to_jiffies(phba->fc_ratov * 2000); + if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) + while (vport->ct_flags && timeout) + timeout = schedule_timeout(timeout); + else + lpfc_printf_log(vport->phba, KERN_WARNING, + LOG_VPORT, + "1829 CT command failed to " + "delete objects on fabric. \n"); + } /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) { @@ -503,23 +530,20 @@ lpfc_vport_delete(struct fc_vport *fc_vport) } skip_logo: + lpfc_cleanup(vport); lpfc_sli_host_down(vport); - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); - } - lpfc_stop_vport_timers(vport); lpfc_unreg_all_rpis(vport); - lpfc_unreg_default_rpis(vport); - /* - * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the - * scsi_host_put() to release the vport. - */ - lpfc_mbx_unreg_vpi(vport); + + if (!(phba->pport->load_flag & FC_UNLOADING)) { + lpfc_unreg_default_rpis(vport); + /* + * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) + * does the scsi_host_put() to release the vport. + */ + lpfc_mbx_unreg_vpi(vport); + } lpfc_free_vpi(phba, vport->vpi); vport->work_port_events = 0; @@ -532,16 +556,13 @@ skip_logo: return VPORT_OK; } -EXPORT_SYMBOL(lpfc_vport_create); -EXPORT_SYMBOL(lpfc_vport_delete); - struct lpfc_vport ** lpfc_create_vport_work_array(struct lpfc_hba *phba) { struct lpfc_vport *port_iterator; struct lpfc_vport **vports; int index = 0; - vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *), + vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *), GFP_KERNEL); if (vports == NULL) return NULL; @@ -560,12 +581,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) } void -lpfc_destroy_vport_work_array(struct lpfc_vport **vports) +lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) { int i; if (vports == NULL) return; - for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++) + for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++) scsi_host_put(lpfc_shost_from_vport(vports[i])); kfree(vports); } diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h index 91da17751a37..96c445333b69 100644 --- a/drivers/scsi/lpfc/lpfc_vport.h +++ b/drivers/scsi/lpfc/lpfc_vport.h @@ -89,7 +89,7 @@ int lpfc_vport_delete(struct fc_vport *); int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *); int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint); struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *); -void lpfc_destroy_vport_work_array(struct lpfc_vport **); +void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **); /* * queuecommand VPORT-specific return codes. Specified in the host byte code. diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index a035001f4438..b12ad7c7c673 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -402,7 +402,6 @@ static struct scsi_host_template mac53c94_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 66c652035730..4d59ae8491a4 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4490,7 +4490,6 @@ static struct scsi_host_template megaraid_template = { .sg_tablesize = MAX_SGLIST, .cmd_per_lun = DEF_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .eh_abort_handler = megaraid_abort, .eh_device_reset_handler = megaraid_reset, .eh_bus_reset_handler = megaraid_reset, @@ -4889,7 +4888,7 @@ __megaraid_shutdown(adapter_t *adapter) mdelay(1000); } -static void +static void __devexit megaraid_remove_one(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index c8923108183a..6db77c00e3ee 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -300,7 +300,7 @@ static struct pci_device_id pci_id_table_g[] = { MODULE_DEVICE_TABLE(pci, pci_id_table_g); -static struct pci_driver megaraid_pci_driver_g = { +static struct pci_driver megaraid_pci_driver = { .name = "megaraid", .id_table = pci_id_table_g, .probe = megaraid_probe_one, @@ -361,7 +361,6 @@ static struct scsi_host_template megaraid_template_g = { .eh_host_reset_handler = megaraid_reset_handler, .change_queue_depth = megaraid_change_queue_depth, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .sdev_attrs = megaraid_sdev_attrs, .shost_attrs = megaraid_shost_attrs, }; @@ -394,7 +393,7 @@ megaraid_init(void) // register as a PCI hot-plug driver module - rval = pci_register_driver(&megaraid_pci_driver_g); + rval = pci_register_driver(&megaraid_pci_driver); if (rval < 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not register hotplug support.\n")); @@ -415,7 +414,7 @@ megaraid_exit(void) con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); // unregister as PCI hotplug driver - pci_unregister_driver(&megaraid_pci_driver_g); + pci_unregister_driver(&megaraid_pci_driver); return; } diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index e3c5c5282203..672c759ac24d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -2,7 +2,7 @@ * * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2003-2005 LSI Logic Corporation. + * Copyright (c) 2003-2005 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.10-rc5 + * Version : v00.00.03.16-rc1 * * Authors: * (email-id : megaraidlinux@lsi.com) @@ -31,6 +31,7 @@ #include <linux/moduleparam.h> #include <linux/module.h> #include <linux/spinlock.h> +#include <linux/mutex.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/uio.h> @@ -46,10 +47,18 @@ #include <scsi/scsi_host.h> #include "megaraid_sas.h" +/* + * poll_mode_io:1- schedule complete completion from q cmd + */ +static unsigned int poll_mode_io; +module_param_named(poll_mode_io, poll_mode_io, int, 0); +MODULE_PARM_DESC(poll_mode_io, + "Complete cmds from IO path, (default=0)"); + MODULE_LICENSE("GPL"); MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux@lsi.com"); -MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver"); +MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); /* * PCI ID table for all supported controllers @@ -76,6 +85,10 @@ static DEFINE_MUTEX(megasas_async_queue_mutex); static u32 megasas_dbg_lvl; +static void +megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, + u8 alt_status); + /** * megasas_get_cmd - Get a command from the free pool * @instance: Adapter soft state @@ -855,6 +868,12 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) atomic_inc(&instance->fw_outstanding); instance->instancet->fire_cmd(cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set); + /* + * Check if we have pend cmds to be completed + */ + if (poll_mode_io && atomic_read(&instance->fw_outstanding)) + tasklet_schedule(&instance->isr_tasklet); + return 0; @@ -886,6 +905,64 @@ static int megasas_slave_configure(struct scsi_device *sdev) } /** + * megasas_complete_cmd_dpc - Returns FW's controller structure + * @instance_addr: Address of adapter soft state + * + * Tasklet to complete cmds + */ +static void megasas_complete_cmd_dpc(unsigned long instance_addr) +{ + u32 producer; + u32 consumer; + u32 context; + struct megasas_cmd *cmd; + struct megasas_instance *instance = + (struct megasas_instance *)instance_addr; + unsigned long flags; + + /* If we have already declared adapter dead, donot complete cmds */ + if (instance->hw_crit_error) + return; + + spin_lock_irqsave(&instance->completion_lock, flags); + + producer = *instance->producer; + consumer = *instance->consumer; + + while (consumer != producer) { + context = instance->reply_queue[consumer]; + + cmd = instance->cmd_list[context]; + + megasas_complete_cmd(instance, cmd, DID_OK); + + consumer++; + if (consumer == (instance->max_fw_cmds + 1)) { + consumer = 0; + } + } + + *instance->consumer = producer; + + spin_unlock_irqrestore(&instance->completion_lock, flags); + + /* + * Check if we can restore can_queue + */ + if (instance->flag & MEGASAS_FW_BUSY + && time_after(jiffies, instance->last_time + 5 * HZ) + && atomic_read(&instance->fw_outstanding) < 17) { + + spin_lock_irqsave(instance->host->host_lock, flags); + instance->flag &= ~MEGASAS_FW_BUSY; + instance->host->can_queue = + instance->max_fw_cmds - MEGASAS_INT_CMDS; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + } +} + +/** * megasas_wait_for_outstanding - Wait for all outstanding cmds * @instance: Adapter soft state * @@ -908,6 +985,11 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { printk(KERN_NOTICE "megasas: [%2d]waiting for %d " "commands to complete\n",i,outstanding); + /* + * Call cmd completion routine. Cmd to be + * be completed directly without depending on isr. + */ + megasas_complete_cmd_dpc((unsigned long)instance); } msleep(1000); @@ -1100,7 +1182,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) static struct scsi_host_template megasas_template = { .module = THIS_MODULE, - .name = "LSI Logic SAS based MegaRAID driver", + .name = "LSI SAS based MegaRAID driver", .proc_name = "megaraid_sas", .slave_configure = megasas_slave_configure, .queuecommand = megasas_queue_command, @@ -1110,7 +1192,6 @@ static struct scsi_host_template megasas_template = { .eh_timed_out = megasas_reset_timer, .bios_param = megasas_bios_param, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; /** @@ -1749,57 +1830,119 @@ megasas_get_ctrl_info(struct megasas_instance *instance, } /** - * megasas_complete_cmd_dpc - Returns FW's controller structure - * @instance_addr: Address of adapter soft state + * megasas_issue_init_mfi - Initializes the FW + * @instance: Adapter soft state * - * Tasklet to complete cmds + * Issues the INIT MFI cmd */ -static void megasas_complete_cmd_dpc(unsigned long instance_addr) +static int +megasas_issue_init_mfi(struct megasas_instance *instance) { - u32 producer; - u32 consumer; u32 context; + struct megasas_cmd *cmd; - struct megasas_instance *instance = (struct megasas_instance *)instance_addr; - unsigned long flags; - /* If we have already declared adapter dead, donot complete cmds */ - if (instance->hw_crit_error) - return; + struct megasas_init_frame *init_frame; + struct megasas_init_queue_info *initq_info; + dma_addr_t init_frame_h; + dma_addr_t initq_info_h; - producer = *instance->producer; - consumer = *instance->consumer; + /* + * Prepare a init frame. Note the init frame points to queue info + * structure. Each frame has SGL allocated after first 64 bytes. For + * this frame - since we don't need any SGL - we use SGL's space as + * queue info structure + * + * We will not get a NULL command below. We just created the pool. + */ + cmd = megasas_get_cmd(instance); - while (consumer != producer) { - context = instance->reply_queue[consumer]; + init_frame = (struct megasas_init_frame *)cmd->frame; + initq_info = (struct megasas_init_queue_info *) + ((unsigned long)init_frame + 64); - cmd = instance->cmd_list[context]; + init_frame_h = cmd->frame_phys_addr; + initq_info_h = init_frame_h + 64; - megasas_complete_cmd(instance, cmd, DID_OK); + context = init_frame->context; + memset(init_frame, 0, MEGAMFI_FRAME_SIZE); + memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); + init_frame->context = context; - consumer++; - if (consumer == (instance->max_fw_cmds + 1)) { - consumer = 0; - } - } + initq_info->reply_queue_entries = instance->max_fw_cmds + 1; + initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; - *instance->consumer = producer; + initq_info->producer_index_phys_addr_lo = instance->producer_h; + initq_info->consumer_index_phys_addr_lo = instance->consumer_h; + + init_frame->cmd = MFI_CMD_INIT; + init_frame->cmd_status = 0xFF; + init_frame->queue_info_new_phys_addr_lo = initq_info_h; + + init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); /* - * Check if we can restore can_queue + * disable the intr before firing the init frame to FW */ - if (instance->flag & MEGASAS_FW_BUSY - && time_after(jiffies, instance->last_time + 5 * HZ) - && atomic_read(&instance->fw_outstanding) < 17) { + instance->instancet->disable_intr(instance->reg_set); - spin_lock_irqsave(instance->host->host_lock, flags); - instance->flag &= ~MEGASAS_FW_BUSY; - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; + /* + * Issue the init frame in polled mode + */ - spin_unlock_irqrestore(instance->host->host_lock, flags); + if (megasas_issue_polled(instance, cmd)) { + printk(KERN_ERR "megasas: Failed to init firmware\n"); + megasas_return_cmd(instance, cmd); + goto fail_fw_init; } + megasas_return_cmd(instance, cmd); + + return 0; + +fail_fw_init: + return -EINVAL; +} + +/** + * megasas_start_timer - Initializes a timer object + * @instance: Adapter soft state + * @timer: timer object to be initialized + * @fn: timer function + * @interval: time interval between timer function call + */ +static inline void +megasas_start_timer(struct megasas_instance *instance, + struct timer_list *timer, + void *fn, unsigned long interval) +{ + init_timer(timer); + timer->expires = jiffies + interval; + timer->data = (unsigned long)instance; + timer->function = fn; + add_timer(timer); +} + +/** + * megasas_io_completion_timer - Timer fn + * @instance_addr: Address of adapter soft state + * + * Schedules tasklet for cmd completion + * if poll_mode_io is set + */ +static void +megasas_io_completion_timer(unsigned long instance_addr) +{ + struct megasas_instance *instance = + (struct megasas_instance *)instance_addr; + + if (atomic_read(&instance->fw_outstanding)) + tasklet_schedule(&instance->isr_tasklet); + + /* Restart timer */ + if (poll_mode_io) + mod_timer(&instance->io_completion_timer, + jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL); } /** @@ -1814,22 +1957,15 @@ static int megasas_init_mfi(struct megasas_instance *instance) u32 reply_q_sz; u32 max_sectors_1; u32 max_sectors_2; + u32 tmp_sectors; struct megasas_register_set __iomem *reg_set; - - struct megasas_cmd *cmd; struct megasas_ctrl_info *ctrl_info; - - struct megasas_init_frame *init_frame; - struct megasas_init_queue_info *initq_info; - dma_addr_t init_frame_h; - dma_addr_t initq_info_h; - /* * Map the message registers */ instance->base_addr = pci_resource_start(instance->pdev, 0); - if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) { + if (pci_request_regions(instance->pdev, "megasas: LSI")) { printk(KERN_DEBUG "megasas: IO memory region busy!\n"); return -EBUSY; } @@ -1900,52 +2036,8 @@ static int megasas_init_mfi(struct megasas_instance *instance) goto fail_reply_queue; } - /* - * Prepare a init frame. Note the init frame points to queue info - * structure. Each frame has SGL allocated after first 64 bytes. For - * this frame - since we don't need any SGL - we use SGL's space as - * queue info structure - * - * We will not get a NULL command below. We just created the pool. - */ - cmd = megasas_get_cmd(instance); - - init_frame = (struct megasas_init_frame *)cmd->frame; - initq_info = (struct megasas_init_queue_info *) - ((unsigned long)init_frame + 64); - - init_frame_h = cmd->frame_phys_addr; - initq_info_h = init_frame_h + 64; - - memset(init_frame, 0, MEGAMFI_FRAME_SIZE); - memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); - - initq_info->reply_queue_entries = instance->max_fw_cmds + 1; - initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; - - initq_info->producer_index_phys_addr_lo = instance->producer_h; - initq_info->consumer_index_phys_addr_lo = instance->consumer_h; - - init_frame->cmd = MFI_CMD_INIT; - init_frame->cmd_status = 0xFF; - init_frame->queue_info_new_phys_addr_lo = initq_info_h; - - init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); - - /* - * disable the intr before firing the init frame to FW - */ - instance->instancet->disable_intr(instance->reg_set); - - /* - * Issue the init frame in polled mode - */ - if (megasas_issue_polled(instance, cmd)) { - printk(KERN_DEBUG "megasas: Failed to init firmware\n"); + if (megasas_issue_init_mfi(instance)) goto fail_fw_init; - } - - megasas_return_cmd(instance, cmd); ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); @@ -1958,17 +2050,20 @@ static int megasas_init_mfi(struct megasas_instance *instance) * Note that older firmwares ( < FW ver 30) didn't report information * to calculate max_sectors_1. So the number ended up as zero always. */ + tmp_sectors = 0; if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) { max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) * ctrl_info->max_strips_per_io; max_sectors_2 = ctrl_info->max_request_size; - instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2) - ? max_sectors_1 : max_sectors_2; - } else - instance->max_sectors_per_req = instance->max_num_sge * - PAGE_SIZE / 512; + tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); + } + + instance->max_sectors_per_req = instance->max_num_sge * + PAGE_SIZE / 512; + if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) + instance->max_sectors_per_req = tmp_sectors; kfree(ctrl_info); @@ -1976,12 +2071,17 @@ static int megasas_init_mfi(struct megasas_instance *instance) * Setup tasklet for cmd completion */ - tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, - (unsigned long)instance); + tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, + (unsigned long)instance); + + /* Initialize the cmd completion timer */ + if (poll_mode_io) + megasas_start_timer(instance, &instance->io_completion_timer, + megasas_io_completion_timer, + MEGASAS_COMPLETION_TIMER_INTERVAL); return 0; fail_fw_init: - megasas_return_cmd(instance, cmd); pci_free_consistent(instance->pdev, reply_q_sz, instance->reply_queue, instance->reply_queue_h); @@ -2263,6 +2363,28 @@ static int megasas_io_attach(struct megasas_instance *instance) return 0; } +static int +megasas_set_dma_mask(struct pci_dev *pdev) +{ + /* + * All our contollers are capable of performing 64-bit DMA + */ + if (IS_DMA64) { + if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) { + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) + goto fail_set_dma_mask; + } + } else { + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) + goto fail_set_dma_mask; + } + return 0; + +fail_set_dma_mask: + return 1; +} + /** * megasas_probe_one - PCI hotplug entry point * @pdev: PCI device structure @@ -2296,19 +2418,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_set_master(pdev); - /* - * All our contollers are capable of performing 64-bit DMA - */ - if (IS_DMA64) { - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) { - - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) - goto fail_set_dma_mask; - } - } else { - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) - goto fail_set_dma_mask; - } + if (megasas_set_dma_mask(pdev)) + goto fail_set_dma_mask; host = scsi_host_alloc(&megasas_template, sizeof(struct megasas_instance)); @@ -2357,8 +2468,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) init_waitqueue_head(&instance->abort_cmd_wait_q); spin_lock_init(&instance->cmd_pool_lock); + spin_lock_init(&instance->completion_lock); - sema_init(&instance->aen_mutex, 1); + mutex_init(&instance->aen_mutex); sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS); /* @@ -2490,8 +2602,10 @@ static void megasas_flush_cache(struct megasas_instance *instance) /** * megasas_shutdown_controller - Instructs FW to shutdown the controller * @instance: Adapter soft state + * @opcode: Shutdown/Hibernate */ -static void megasas_shutdown_controller(struct megasas_instance *instance) +static void megasas_shutdown_controller(struct megasas_instance *instance, + u32 opcode) { struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; @@ -2514,7 +2628,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance) dcmd->flags = MFI_FRAME_DIR_NONE; dcmd->timeout = 0; dcmd->data_xfer_len = 0; - dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN; + dcmd->opcode = opcode; megasas_issue_blocked_cmd(instance, cmd); @@ -2524,6 +2638,139 @@ static void megasas_shutdown_controller(struct megasas_instance *instance) } /** + * megasas_suspend - driver suspend entry point + * @pdev: PCI device structure + * @state: PCI power state to suspend routine + */ +static int __devinit +megasas_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct Scsi_Host *host; + struct megasas_instance *instance; + + instance = pci_get_drvdata(pdev); + host = instance->host; + + if (poll_mode_io) + del_timer_sync(&instance->io_completion_timer); + + megasas_flush_cache(instance); + megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); + tasklet_kill(&instance->isr_tasklet); + + pci_set_drvdata(instance->pdev, instance); + instance->instancet->disable_intr(instance->reg_set); + free_irq(instance->pdev->irq, instance); + + pci_save_state(pdev); + pci_disable_device(pdev); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +/** + * megasas_resume- driver resume entry point + * @pdev: PCI device structure + */ +static int __devinit +megasas_resume(struct pci_dev *pdev) +{ + int rval; + struct Scsi_Host *host; + struct megasas_instance *instance; + + instance = pci_get_drvdata(pdev); + host = instance->host; + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + + /* + * PCI prepping: enable device set bus mastering and dma mask + */ + rval = pci_enable_device(pdev); + + if (rval) { + printk(KERN_ERR "megasas: Enable device failed\n"); + return rval; + } + + pci_set_master(pdev); + + if (megasas_set_dma_mask(pdev)) + goto fail_set_dma_mask; + + /* + * Initialize MFI Firmware + */ + + *instance->producer = 0; + *instance->consumer = 0; + + atomic_set(&instance->fw_outstanding, 0); + + /* + * We expect the FW state to be READY + */ + if (megasas_transition_to_ready(instance)) + goto fail_ready_state; + + if (megasas_issue_init_mfi(instance)) + goto fail_init_mfi; + + tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc, + (unsigned long)instance); + + /* + * Register IRQ + */ + if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, + "megasas", instance)) { + printk(KERN_ERR "megasas: Failed to register IRQ\n"); + goto fail_irq; + } + + instance->instancet->enable_intr(instance->reg_set); + + /* + * Initiate AEN (Asynchronous Event Notification) + */ + if (megasas_start_aen(instance)) + printk(KERN_ERR "megasas: Start AEN failed\n"); + + /* Initialize the cmd completion timer */ + if (poll_mode_io) + megasas_start_timer(instance, &instance->io_completion_timer, + megasas_io_completion_timer, + MEGASAS_COMPLETION_TIMER_INTERVAL); + return 0; + +fail_irq: +fail_init_mfi: + if (instance->evt_detail) + pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), + instance->evt_detail, + instance->evt_detail_h); + + if (instance->producer) + pci_free_consistent(pdev, sizeof(u32), instance->producer, + instance->producer_h); + if (instance->consumer) + pci_free_consistent(pdev, sizeof(u32), instance->consumer, + instance->consumer_h); + scsi_host_put(host); + +fail_set_dma_mask: +fail_ready_state: + + pci_disable_device(pdev); + + return -ENODEV; +} + +/** * megasas_detach_one - PCI hot"un"plug entry point * @pdev: PCI device structure */ @@ -2536,9 +2783,12 @@ static void megasas_detach_one(struct pci_dev *pdev) instance = pci_get_drvdata(pdev); host = instance->host; + if (poll_mode_io) + del_timer_sync(&instance->io_completion_timer); + scsi_remove_host(instance->host); megasas_flush_cache(instance); - megasas_shutdown_controller(instance); + megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); tasklet_kill(&instance->isr_tasklet); /* @@ -2660,6 +2910,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, void *sense = NULL; dma_addr_t sense_handle; u32 *sense_ptr; + unsigned long *sense_buff; memset(kbuff_arr, 0, sizeof(kbuff_arr)); @@ -2764,14 +3015,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, */ if (ioc->sense_len) { /* - * sense_ptr points to the location that has the user + * sense_buff points to the location that has the user * sense buffer address */ - sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); + sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw + + ioc->sense_off); - if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), - sense, ioc->sense_len)) { + if (copy_to_user((void __user *)(unsigned long)(*sense_buff), + sense, ioc->sense_len)) { + printk(KERN_ERR "megasas: Failed to copy out to user " + "sense data\n"); error = -EFAULT; goto out; } @@ -2874,10 +3127,10 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) if (!instance) return -ENODEV; - down(&instance->aen_mutex); + mutex_lock(&instance->aen_mutex); error = megasas_register_aen(instance, aen.seq_num, aen.class_locale_word); - up(&instance->aen_mutex); + mutex_unlock(&instance->aen_mutex); return error; } @@ -2977,6 +3230,8 @@ static struct pci_driver megasas_pci_driver = { .id_table = megasas_pci_table, .probe = megasas_probe_one, .remove = __devexit_p(megasas_detach_one), + .suspend = megasas_suspend, + .resume = megasas_resume, .shutdown = megasas_shutdown, }; @@ -3004,7 +3259,7 @@ static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date, static ssize_t megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf) { - return sprintf(buf,"%u",megasas_dbg_lvl); + return sprintf(buf, "%u\n", megasas_dbg_lvl); } static ssize_t @@ -3019,7 +3274,65 @@ megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t coun } static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl, - megasas_sysfs_set_dbg_lvl); + megasas_sysfs_set_dbg_lvl); + +static ssize_t +megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf) +{ + return sprintf(buf, "%u\n", poll_mode_io); +} + +static ssize_t +megasas_sysfs_set_poll_mode_io(struct device_driver *dd, + const char *buf, size_t count) +{ + int retval = count; + int tmp = poll_mode_io; + int i; + struct megasas_instance *instance; + + if (sscanf(buf, "%u", &poll_mode_io) < 1) { + printk(KERN_ERR "megasas: could not set poll_mode_io\n"); + retval = -EINVAL; + } + + /* + * Check if poll_mode_io is already set or is same as previous value + */ + if ((tmp && poll_mode_io) || (tmp == poll_mode_io)) + goto out; + + if (poll_mode_io) { + /* + * Start timers for all adapters + */ + for (i = 0; i < megasas_mgmt_info.max_index; i++) { + instance = megasas_mgmt_info.instance[i]; + if (instance) { + megasas_start_timer(instance, + &instance->io_completion_timer, + megasas_io_completion_timer, + MEGASAS_COMPLETION_TIMER_INTERVAL); + } + } + } else { + /* + * Delete timers for all adapters + */ + for (i = 0; i < megasas_mgmt_info.max_index; i++) { + instance = megasas_mgmt_info.instance[i]; + if (instance) + del_timer_sync(&instance->io_completion_timer); + } + } + +out: + return retval; +} + +static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUGO, + megasas_sysfs_show_poll_mode_io, + megasas_sysfs_set_poll_mode_io); /** * megasas_init - Driver load entry point @@ -3070,8 +3383,16 @@ static int __init megasas_init(void) &driver_attr_dbg_lvl); if (rval) goto err_dcf_dbg_lvl; + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_poll_mode_io); + if (rval) + goto err_dcf_poll_mode_io; return rval; + +err_dcf_poll_mode_io: + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_dbg_lvl); err_dcf_dbg_lvl: driver_remove_file(&megasas_pci_driver.driver, &driver_attr_release_date); @@ -3090,6 +3411,8 @@ err_pcidrv: static void __exit megasas_exit(void) { driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_poll_mode_io); + driver_remove_file(&megasas_pci_driver.driver, &driver_attr_dbg_lvl); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_release_date); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 4dffc918a414..6466bdf548c2 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2,7 +2,7 @@ * * Linux MegaRAID driver for SAS based RAID controllers * - * Copyright (c) 2003-2005 LSI Logic Corporation. + * Copyright (c) 2003-2005 LSI Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -18,9 +18,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.03.10-rc5" -#define MEGASAS_RELDATE "May 17, 2007" -#define MEGASAS_EXT_VERSION "Thu May 17 10:09:32 PDT 2007" +#define MEGASAS_VERSION "00.00.03.16-rc1" +#define MEGASAS_RELDATE "Nov. 07, 2007" +#define MEGASAS_EXT_VERSION "Thu. Nov. 07 10:09:32 PDT 2007" /* * Device IDs @@ -117,6 +117,7 @@ #define MR_FLUSH_DISK_CACHE 0x02 #define MR_DCMD_CTRL_SHUTDOWN 0x01050000 +#define MR_DCMD_HIBERNATE_SHUTDOWN 0x01060000 #define MR_ENABLE_DRIVE_SPINDOWN 0x01 #define MR_DCMD_CTRL_EVENT_GET_INFO 0x01040100 @@ -570,7 +571,8 @@ struct megasas_ctrl_info { #define IS_DMA64 (sizeof(dma_addr_t) == 8) #define MFI_OB_INTR_STATUS_MASK 0x00000002 -#define MFI_POLL_TIMEOUT_SECS 10 +#define MFI_POLL_TIMEOUT_SECS 60 +#define MEGASAS_COMPLETION_TIMER_INTERVAL (HZ/10) #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 @@ -1083,13 +1085,15 @@ struct megasas_instance { struct megasas_cmd **cmd_list; struct list_head cmd_pool; spinlock_t cmd_pool_lock; + /* used to synch producer, consumer ptrs in dpc */ + spinlock_t completion_lock; struct dma_pool *frame_dma_pool; struct dma_pool *sense_dma_pool; struct megasas_evt_detail *evt_detail; dma_addr_t evt_detail_h; struct megasas_cmd *aen_cmd; - struct semaphore aen_mutex; + struct mutex aen_mutex; struct semaphore ioctl_sem; struct Scsi_Host *host; @@ -1108,6 +1112,8 @@ struct megasas_instance { u8 flag; unsigned long last_time; + + struct timer_list io_completion_timer; }; #define MEGASAS_IS_LOGICAL(scp) \ diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 7470ff39ab22..651d09b08f2a 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1843,7 +1843,6 @@ static struct scsi_host_template mesh_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 2, .use_clustering = DISABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 016c462bc771..c5ebf018b378 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -4963,10 +4963,11 @@ void ncr_complete (struct ncb *np, struct ccb *cp) ** Copy back sense data to caller's buffer. */ memcpy(cmd->sense_buffer, cp->sense_buf, - min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf))); + min_t(size_t, SCSI_SENSE_BUFFERSIZE, + sizeof(cp->sense_buf))); if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { - u_char * p = (u_char*) & cmd->sense_buffer; + u_char *p = cmd->sense_buffer; int i; PRINT_ADDR(cmd, "sense data:"); for (i=0; i<14; i++) printk (" %x", *p++); diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 28161dc95e0d..7fed35372150 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -281,7 +281,6 @@ static struct scsi_host_template nsp32_template = { .cmd_per_lun = 1, .this_id = NSP32_HOST_SCSIID, .use_clustering = DISABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .eh_abort_handler = nsp32_eh_abort, .eh_bus_reset_handler = nsp32_eh_bus_reset, .eh_host_reset_handler = nsp32_eh_host_reset, diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index fa481b515ead..53857c6b6d4d 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -6,7 +6,8 @@ menuconfig SCSI_LOWLEVEL_PCMCIA bool "PCMCIA SCSI adapter support" depends on SCSI!=n && PCMCIA!=n -if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA +# drivers have problems when build in, so require modules +if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m config PCMCIA_AHA152X tristate "Adaptec AHA152X PCMCIA support" diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index a45d89b14147..5082ca3c6876 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -135,6 +135,11 @@ static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ #define NSP_DEBUG_BUF_LEN 150 +static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc) +{ + scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc); +} + static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...) { va_list args; @@ -192,8 +197,10 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt, #endif nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d", - SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg); + nsp_dbg(NSP_DEBUG_QUEUECOMMAND, + "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d", + SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt), + scsi_bufflen(SCpnt), scsi_sg_count(SCpnt)); //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC); SCpnt->scsi_done = done; @@ -225,7 +232,7 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt, SCpnt->SCp.have_data_in = IO_UNKNOWN; SCpnt->SCp.sent_command = 0; SCpnt->SCp.phase = PH_UNDETERMINED; - SCpnt->resid = SCpnt->request_bufflen; + scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); /* setup scratch area SCp.ptr : buffer pointer @@ -233,14 +240,14 @@ static int nsp_queuecommand(struct scsi_cmnd *SCpnt, SCp.buffer : next buffer SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ - if (SCpnt->use_sg) { - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + if (scsi_bufflen(SCpnt)) { + SCpnt->SCp.buffer = scsi_sglist(SCpnt); SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; } else { - SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.ptr = NULL; + SCpnt->SCp.this_residual = 0; SCpnt->SCp.buffer = NULL; SCpnt->SCp.buffers_residual = 0; } @@ -721,7 +728,9 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) ocount = data->FifoCount; nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d", - SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual); + SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr, + SCpnt->SCp.this_residual, SCpnt->SCp.buffer, + SCpnt->SCp.buffers_residual); time_out = 1000; @@ -771,7 +780,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) return; } - SCpnt->resid -= res; + nsp_inc_resid(SCpnt, -res); SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; @@ -795,10 +804,12 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) if (time_out == 0) { nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", - SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual); + scsi_get_resid(SCpnt), SCpnt->SCp.this_residual, + SCpnt->SCp.buffers_residual); } nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount); - nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid); + nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, + scsi_get_resid(SCpnt)); } /* @@ -816,7 +827,9 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) ocount = data->FifoCount; nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x", - data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid); + data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, + SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, + scsi_get_resid(SCpnt)); time_out = 1000; @@ -830,7 +843,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res); /* Put back pointer */ - SCpnt->resid += res; + nsp_inc_resid(SCpnt, res); SCpnt->SCp.ptr -= res; SCpnt->SCp.this_residual += res; ocount -= res; @@ -866,7 +879,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) break; } - SCpnt->resid -= res; + nsp_inc_resid(SCpnt, -res); SCpnt->SCp.ptr += res; SCpnt->SCp.this_residual -= res; ocount += res; @@ -886,10 +899,12 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) data->FifoCount = ocount; if (time_out == 0) { - nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid); + nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", + scsi_get_resid(SCpnt)); } nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); - nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid); + nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, + scsi_get_resid(SCpnt)); } #undef RFIFO_CRIT #undef WFIFO_CRIT @@ -911,9 +926,8 @@ static int nsp_nexus(struct scsi_cmnd *SCpnt) nsp_index_write(base, SYNCREG, sync->SyncRegister); nsp_index_write(base, ACKWIDTH, sync->AckWidth); - if (SCpnt->use_sg == 0 || - SCpnt->resid % 4 != 0 || - SCpnt->resid <= PAGE_SIZE ) { + if (scsi_get_resid(SCpnt) % 4 != 0 || + scsi_get_resid(SCpnt) <= PAGE_SIZE ) { data->TransferMode = MODE_IO8; } else if (nsp_burst_mode == BURST_MEM32) { data->TransferMode = MODE_MEM32; diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 969b9387a0c3..3454a5714749 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -692,7 +692,6 @@ static struct scsi_host_template sym53c500_driver_template = { .sg_tablesize = 32, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .shost_attrs = SYM53C500_shost_attrs }; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 67ee51a3d7e1..f655ae320b48 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -750,18 +750,16 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) cmd->SCp.phase++; case 4: /* Phase 4 - Setup scatter/gather buffers */ - if (cmd->use_sg) { - /* if many buffers are available, start filling the first */ - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); } else { - /* else fill the only available buffer */ cmd->SCp.buffer = NULL; - cmd->SCp.this_residual = cmd->request_bufflen; - cmd->SCp.ptr = cmd->request_buffer; + cmd->SCp.this_residual = 0; + cmd->SCp.ptr = NULL; } - cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.phase++; case 5: /* Phase 5 - Data transfer stage */ diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c deleted file mode 100644 index 899e89d6fe67..000000000000 --- a/drivers/scsi/psi240i.c +++ /dev/null @@ -1,689 +0,0 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. - * - * Copyright (c) 1997 Perceptive Solutions, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * File Name: psi240i.c - * - * Description: SCSI driver for the PSI240I EIDE interface card. - * - *-M*************************************************************************/ - -#include <linux/module.h> - -#include <linux/blkdev.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <linux/stat.h> - -#include <asm/dma.h> -#include <asm/system.h> -#include <asm/io.h> -#include "scsi.h" -#include <scsi/scsi_host.h> - -#include "psi240i.h" -#include "psi_chip.h" - -//#define DEBUG 1 - -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -#define MAXBOARDS 6 /* Increase this and the sizes of the arrays below, if you need more. */ - -#define PORT_DATA 0 -#define PORT_ERROR 1 -#define PORT_SECTOR_COUNT 2 -#define PORT_LBA_0 3 -#define PORT_LBA_8 4 -#define PORT_LBA_16 5 -#define PORT_LBA_24 6 -#define PORT_STAT_CMD 7 -#define PORT_SEL_FAIL 8 -#define PORT_IRQ_STATUS 9 -#define PORT_ADDRESS 10 -#define PORT_FAIL 11 -#define PORT_ALT_STAT 12 - -typedef struct - { - UCHAR device; // device code - UCHAR byte6; // device select register image - UCHAR spigot; // spigot number - UCHAR expectingIRQ; // flag for expecting and interrupt - USHORT sectors; // number of sectors per track - USHORT heads; // number of heads - USHORT cylinders; // number of cylinders for this device - USHORT spareword; // placeholder - ULONG blocks; // number of blocks on device - } OUR_DEVICE, *POUR_DEVICE; - -typedef struct - { - USHORT ports[13]; - OUR_DEVICE device[8]; - struct scsi_cmnd *pSCmnd; - IDE_STRUCT ide; - ULONG startSector; - USHORT sectorCount; - struct scsi_cmnd *SCpnt; - VOID *buffer; - USHORT expectingIRQ; - } ADAPTER240I, *PADAPTER240I; - -#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata) - -static struct Scsi_Host *PsiHost[6] = {NULL,}; /* One for each IRQ level (10-15) */ -static IDENTIFY_DATA identifyData; -static SETUP ChipSetup; - -static USHORT portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5}; - -/**************************************************************** - * Name: WriteData :LOCAL - * - * Description: Write data to device. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: TRUE if drive does not assert DRQ in time. - * - ****************************************************************/ -static int WriteData (PADAPTER240I padapter) - { - ULONG timer; - USHORT *pports = padapter->ports; - - timer = jiffies + TIMEOUT_DRQ; // calculate the timeout value - do { - if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ ) - { - outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256); - return 0; - } - } while ( time_after(timer, jiffies) ); // test for timeout - - padapter->ide.ide.ides.cmd = 0; // null out the command byte - return 1; - } -/**************************************************************** - * Name: IdeCmd :LOCAL - * - * Description: Process a queued command from the SCSI manager. - * - * Parameters: padapter - Pointer adapter data structure. - * - * Returns: Zero if no error or status register contents on error. - * - ****************************************************************/ -static UCHAR IdeCmd (PADAPTER240I padapter) - { - ULONG timer; - USHORT *pports = padapter->ports; - UCHAR status; - - outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]); // select the spigot - outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]); // select the drive - timer = jiffies + TIMEOUT_READY; // calculate the timeout value - do { - status = inb_p (padapter->ports[PORT_STAT_CMD]); - if ( status & IDE_STATUS_DRDY ) - { - outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]); - outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]); - outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]); - outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]); - padapter->expectingIRQ = 1; - outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]); - - if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE ) - return (WriteData (padapter)); - - return 0; - } - } while ( time_after(timer, jiffies) ); // test for timeout - - padapter->ide.ide.ides.cmd = 0; // null out the command byte - return status; - } -/**************************************************************** - * Name: SetupTransfer :LOCAL - * - * Description: Setup a data transfer command. - * - * Parameters: padapter - Pointer adapter data structure. - * drive - Drive/head register upper nibble only. - * - * Returns: TRUE if no data to transfer. - * - ****************************************************************/ -static int SetupTransfer (PADAPTER240I padapter, UCHAR drive) - { - if ( padapter->sectorCount ) - { - *(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector; - padapter->ide.ide.ide[6] |= drive; - padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount; - padapter->sectorCount -= padapter->ide.ide.ides.sectors; // bump the start and count for next xfer - padapter->startSector += padapter->ide.ide.ides.sectors; - return 0; - } - else - { - padapter->ide.ide.ides.cmd = 0; // null out the command byte - padapter->SCpnt = NULL; - return 1; - } - } -/**************************************************************** - * Name: DecodeError :LOCAL - * - * Description: Decode and process device errors. - * - * Parameters: pshost - Pointer to host data block. - * status - Status register code. - * - * Returns: The driver status code. - * - ****************************************************************/ -static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status) - { - PADAPTER240I padapter = HOSTDATA(pshost); - UCHAR error; - - padapter->expectingIRQ = 0; - padapter->SCpnt = NULL; - if ( status & IDE_STATUS_WRITE_FAULT ) - { - return DID_PARITY << 16; - } - if ( status & IDE_STATUS_BUSY ) - return DID_BUS_BUSY << 16; - - error = inb_p (padapter->ports[PORT_ERROR]); - DEB(printk ("\npsi240i error register: %x", error)); - switch ( error ) - { - case IDE_ERROR_AMNF: - case IDE_ERROR_TKONF: - case IDE_ERROR_ABRT: - case IDE_ERROR_IDFN: - case IDE_ERROR_UNC: - case IDE_ERROR_BBK: - default: - return DID_ERROR << 16; - } - return DID_ERROR << 16; - } -/**************************************************************** - * Name: Irq_Handler :LOCAL - * - * Description: Interrupt handler. - * - * Parameters: irq - Hardware IRQ number. - * dev_id - - * - * Returns: TRUE if drive is not ready in time. - * - ****************************************************************/ -static void Irq_Handler (int irq, void *dev_id) - { - struct Scsi_Host *shost; // Pointer to host data block - PADAPTER240I padapter; // Pointer to adapter control structure - USHORT *pports; // I/O port array - struct scsi_cmnd *SCpnt; - UCHAR status; - int z; - - DEB(printk ("\npsi240i received interrupt\n")); - - shost = PsiHost[irq - 10]; - if ( !shost ) - panic ("Splunge!"); - - padapter = HOSTDATA(shost); - pports = padapter->ports; - SCpnt = padapter->SCpnt; - - if ( !padapter->expectingIRQ ) - { - DEB(printk ("\npsi240i Unsolicited interrupt\n")); - return; - } - padapter->expectingIRQ = 0; - - status = inb_p (padapter->ports[PORT_STAT_CMD]); // read the device status - if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) - goto irqerror; - - DEB(printk ("\npsi240i processing interrupt")); - switch ( padapter->ide.ide.ides.cmd ) // decide how to handle the interrupt - { - case IDE_CMD_READ_MULTIPLE: - if ( status & IDE_STATUS_DRQ ) - { - insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256); - padapter->buffer += padapter->ide.ide.ides.sectors * 512; - if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) - { - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - if ( !(status = IdeCmd (padapter)) ) - return; - } - break; - - case IDE_CMD_WRITE_MULTIPLE: - padapter->buffer += padapter->ide.ide.ides.sectors * 512; - if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) ) - { - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - if ( !(status = IdeCmd (padapter)) ) - return; - break; - - case IDE_COMMAND_IDENTIFY: - { - PINQUIRYDATA pinquiryData = SCpnt->request_buffer; - - if ( status & IDE_STATUS_DRQ ) - { - insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1); - - memset (pinquiryData, 0, SCpnt->request_bufflen); // Zero INQUIRY data structure. - pinquiryData->DeviceType = 0; - pinquiryData->Versions = 2; - pinquiryData->AdditionalLength = 35 - 4; - - // Fill in vendor identification fields. - for ( z = 0; z < 8; z += 2 ) - { - pinquiryData->VendorId[z] = ((UCHAR *)identifyData.ModelNumber)[z + 1]; - pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z]; - } - - // Initialize unused portion of product id. - for ( z = 0; z < 4; z++ ) - pinquiryData->ProductId[12 + z] = ' '; - - // Move firmware revision from IDENTIFY data to - // product revision in INQUIRY data. - for ( z = 0; z < 4; z += 2 ) - { - pinquiryData->ProductRevisionLevel[z] = ((UCHAR *)identifyData.FirmwareRevision)[z + 1]; - pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z]; - } - - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - break; - } - - default: - SCpnt->result = DID_OK << 16; - padapter->SCpnt = NULL; - SCpnt->scsi_done (SCpnt); - return; - } - -irqerror:; - DEB(printk ("\npsi240i error Device Status: %X\n", status)); - SCpnt->result = DecodeError (shost, status); - SCpnt->scsi_done (SCpnt); - } - -static irqreturn_t do_Irq_Handler (int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); - Irq_Handler(irq, dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -/**************************************************************** - * Name: Psi240i_QueueCommand - * - * Description: Process a queued command from the SCSI manager. - * - * Parameters: SCpnt - Pointer to SCSI command structure. - * done - Pointer to done function to call. - * - * Returns: Status code. - * - ****************************************************************/ -static int Psi240i_QueueCommand(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) - { - UCHAR *cdb = (UCHAR *)SCpnt->cmnd; - // Pointer to SCSI CDB - PADAPTER240I padapter = HOSTDATA (SCpnt->device->host); - // Pointer to adapter control structure - POUR_DEVICE pdev = &padapter->device [SCpnt->device->id]; - // Pointer to device information - UCHAR rc; - // command return code - - SCpnt->scsi_done = done; - padapter->ide.ide.ides.spigot = pdev->spigot; - padapter->buffer = SCpnt->request_buffer; - if (done) - { - if ( !pdev->device ) - { - SCpnt->result = DID_BAD_TARGET << 16; - done (SCpnt); - return 0; - } - } - else - { - printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb); - return 0; - } - - switch ( *cdb ) - { - case SCSIOP_INQUIRY: // inquiry CDB - { - padapter->ide.ide.ide[6] = pdev->byte6; - padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY; - break; - } - - case SCSIOP_TEST_UNIT_READY: // test unit ready CDB - SCpnt->result = DID_OK << 16; - done (SCpnt); - return 0; - - case SCSIOP_READ_CAPACITY: // read capctiy CDB - { - PREAD_CAPACITY_DATA pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer; - - pdata->blksiz = 0x20000; - XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks); - SCpnt->result = DID_OK << 16; - done (SCpnt); - return 0; - } - - case SCSIOP_VERIFY: // verify CDB - *(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]); - padapter->ide.ide.ide[6] |= pdev->byte6; - padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8)); - padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY; - break; - - case SCSIOP_READ: // read10 CDB - padapter->startSector = XSCSI2LONG (&cdb[2]); - padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; - break; - - case SCSIOP_READ6: // read6 CDB - padapter->startSector = SCSI2LONG (&cdb[1]); - padapter->sectorCount = cdb[4]; - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE; - break; - - case SCSIOP_WRITE: // write10 CDB - padapter->startSector = XSCSI2LONG (&cdb[2]); - padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8); - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; - break; - case SCSIOP_WRITE6: // write6 CDB - padapter->startSector = SCSI2LONG (&cdb[1]); - padapter->sectorCount = cdb[4]; - SetupTransfer (padapter, pdev->byte6); - padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE; - break; - - default: - DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); - return 0; - } - - padapter->SCpnt = SCpnt; // Save this command data - - rc = IdeCmd (padapter); - if ( rc ) - { - padapter->expectingIRQ = 0; - DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd)); - SCpnt->result = DID_ERROR << 16; - done (SCpnt); - return 0; - } - DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd)); - return 0; - } - -/*************************************************************************** - * Name: ReadChipMemory - * - * Description: Read information from controller memory. - * - * Parameters: psetup - Pointer to memory image of setup information. - * base - base address of memory. - * length - lenght of data space in bytes. - * port - I/O address of data port. - * - * Returns: Nothing. - * - **************************************************************************/ -static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port) - { - USHORT z, zz; - UCHAR *pd = (UCHAR *)pdata; - outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup data port - zz = 0; - while ( zz < length ) - { - outw_p (base, port + REG_ADDRESS); // setup address - - for ( z = 0; z < 8; z++ ) - { - if ( (zz + z) < length ) - *pd++ = inb_p (port + z); // read data byte - } - zz += 8; - base += 8; - } - } -/**************************************************************** - * Name: Psi240i_Detect - * - * Description: Detect and initialize our boards. - * - * Parameters: tpnt - Pointer to SCSI host template structure. - * - * Returns: Number of adapters found. - * - ****************************************************************/ -static int Psi240i_Detect (struct scsi_host_template *tpnt) - { - int board; - int count = 0; - int unit; - int z; - USHORT port, port_range = 16; - CHIP_CONFIG_N chipConfig; - CHIP_DEVICE_N chipDevice[8]; - struct Scsi_Host *pshost; - - for ( board = 0; board < MAXBOARDS; board++ ) // scan for I/O ports - { - pshost = NULL; - port = portAddr[board]; // get base address to test - if ( !request_region (port, port_range, "psi240i") ) - continue; - if ( inb_p (port + REG_FAIL) != CHIP_ID ) // do the first test for likley hood that it is us - goto host_init_failure; - outb_p (SEL_NONE, port + REG_SEL_FAIL); // setup EEPROM/RAM access - outw (0, port + REG_ADDRESS); // setup EEPROM address zero - if ( inb_p (port) != 0x55 ) // test 1st byte - goto host_init_failure; // nope - if ( inb_p (port + 1) != 0xAA ) // test 2nd byte - goto host_init_failure; // nope - - // at this point our board is found and can be accessed. Now we need to initialize - // our informatation and register with the kernel. - - - ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port); - ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port); - ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port); - - if ( !chipConfig.numDrives ) // if no devices on this board - goto host_init_failure; - - pshost = scsi_register (tpnt, sizeof(ADAPTER240I)); - if(pshost == NULL) - goto host_init_failure; - - PsiHost[chipConfig.irq - 10] = pshost; - pshost->unique_id = port; - pshost->io_port = port; - pshost->n_io_port = 16; /* Number of bytes of I/O space used */ - pshost->irq = chipConfig.irq; - - for ( z = 0; z < 11; z++ ) // build regester address array - HOSTDATA(pshost)->ports[z] = port + z; - HOSTDATA(pshost)->ports[11] = port + REG_FAIL; - HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT; - DEB (printk ("\nPorts =")); - DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]);); - - for ( z = 0; z < chipConfig.numDrives; ++z ) - { - unit = chipDevice[z].channel & 0x0F; - HOSTDATA(pshost)->device[unit].device = ChipSetup.setupDevice[unit].device; - HOSTDATA(pshost)->device[unit].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); - HOSTDATA(pshost)->device[unit].spigot = (UCHAR)(1 << (unit >> 1)); - HOSTDATA(pshost)->device[unit].sectors = ChipSetup.setupDevice[unit].sectors; - HOSTDATA(pshost)->device[unit].heads = ChipSetup.setupDevice[unit].heads; - HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders; - HOSTDATA(pshost)->device[unit].blocks = ChipSetup.setupDevice[unit].blocks; - DEB (printk ("\nHOSTDATA->device = %X", HOSTDATA(pshost)->device[unit].device)); - DEB (printk ("\n byte6 = %X", HOSTDATA(pshost)->device[unit].byte6)); - DEB (printk ("\n spigot = %X", HOSTDATA(pshost)->device[unit].spigot)); - DEB (printk ("\n sectors = %X", HOSTDATA(pshost)->device[unit].sectors)); - DEB (printk ("\n heads = %X", HOSTDATA(pshost)->device[unit].heads)); - DEB (printk ("\n cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders)); - DEB (printk ("\n blocks = %lX", HOSTDATA(pshost)->device[unit].blocks)); - } - - if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) - { - printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x IRQ = %d\n", port, chipConfig.irq); - printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n"); - count++; - continue; - } - - printk ("Unable to allocate IRQ for PSI-240I controller.\n"); - -host_init_failure: - - release_region (port, port_range); - if (pshost) - scsi_unregister (pshost); - - } - return count; - } - -static int Psi240i_Release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -/**************************************************************** - * Name: Psi240i_BiosParam - * - * Description: Process the biosparam request from the SCSI manager to - * return C/H/S data. - * - * Parameters: disk - Pointer to SCSI disk structure. - * dev - Major/minor number from kernel. - * geom - Pointer to integer array to place geometry data. - * - * Returns: zero. - * - ****************************************************************/ -static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int geom[]) - { - POUR_DEVICE pdev; - - pdev = &(HOSTDATA(sdev->host)->device[sdev_id(sdev)]); - - geom[0] = pdev->heads; - geom[1] = pdev->sectors; - geom[2] = pdev->cylinders; - return 0; - } - -MODULE_LICENSE("GPL"); - -static struct scsi_host_template driver_template = { - .proc_name = "psi240i", - .name = "PSI-240I EIDE Disk Controller", - .detect = Psi240i_Detect, - .release = Psi240i_Release, - .queuecommand = Psi240i_QueueCommand, - .bios_param = Psi240i_BiosParam, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = SG_NONE, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h deleted file mode 100644 index 21ebb9214004..000000000000 --- a/drivers/scsi/psi240i.h +++ /dev/null @@ -1,315 +0,0 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. - * - * Copyright (c) 1997 Perceptive Solutions, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * File Name: psi240i.h - * - * Description: Header file for the SCSI driver for the PSI240I - * EIDE interface card. - * - *-M*************************************************************************/ -#ifndef _PSI240I_H -#define _PSI240I_H - -#include <linux/types.h> - -#ifndef PSI_EIDE_SCSIOP -#define PSI_EIDE_SCSIOP 1 - -/************************************************/ -/* Some defines that we like */ -/************************************************/ -#define CHAR char -#define UCHAR unsigned char -#define SHORT short -#define USHORT unsigned short -#define BOOL unsigned short -#define LONG long -#define ULONG unsigned long -#define VOID void - -/************************************************/ -/* Timeout konstants */ -/************************************************/ -#define TIMEOUT_READY 10 // 100 mSec -#define TIMEOUT_DRQ 40 // 400 mSec - -/************************************************/ -/* Misc. macros */ -/************************************************/ -#define ANY2SCSI(up, p) \ -((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \ -((UCHAR *)up)[1] = ((ULONG)(p)); - -#define SCSI2LONG(up) \ -( (((long)*(((UCHAR *)up))) << 16) \ -+ (((long)(((UCHAR *)up)[1])) << 8) \ -+ ((long)(((UCHAR *)up)[2])) ) - -#define XANY2SCSI(up, p) \ -((UCHAR *)up)[0] = ((long)(p)) >> 24; \ -((UCHAR *)up)[1] = ((long)(p)) >> 16; \ -((UCHAR *)up)[2] = ((long)(p)) >> 8; \ -((UCHAR *)up)[3] = ((long)(p)); - -#define XSCSI2LONG(up) \ -( (((long)(((UCHAR *)up)[0])) << 24) \ -+ (((long)(((UCHAR *)up)[1])) << 16) \ -+ (((long)(((UCHAR *)up)[2])) << 8) \ -+ ((long)(((UCHAR *)up)[3])) ) - -/************************************************/ -/* SCSI CDB operation codes */ -/************************************************/ -#define SCSIOP_TEST_UNIT_READY 0x00 -#define SCSIOP_REZERO_UNIT 0x01 -#define SCSIOP_REWIND 0x01 -#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 -#define SCSIOP_REQUEST_SENSE 0x03 -#define SCSIOP_FORMAT_UNIT 0x04 -#define SCSIOP_READ_BLOCK_LIMITS 0x05 -#define SCSIOP_REASSIGN_BLOCKS 0x07 -#define SCSIOP_READ6 0x08 -#define SCSIOP_RECEIVE 0x08 -#define SCSIOP_WRITE6 0x0A -#define SCSIOP_PRINT 0x0A -#define SCSIOP_SEND 0x0A -#define SCSIOP_SEEK6 0x0B -#define SCSIOP_TRACK_SELECT 0x0B -#define SCSIOP_SLEW_PRINT 0x0B -#define SCSIOP_SEEK_BLOCK 0x0C -#define SCSIOP_PARTITION 0x0D -#define SCSIOP_READ_REVERSE 0x0F -#define SCSIOP_WRITE_FILEMARKS 0x10 -#define SCSIOP_FLUSH_BUFFER 0x10 -#define SCSIOP_SPACE 0x11 -#define SCSIOP_INQUIRY 0x12 -#define SCSIOP_VERIFY6 0x13 -#define SCSIOP_RECOVER_BUF_DATA 0x14 -#define SCSIOP_MODE_SELECT 0x15 -#define SCSIOP_RESERVE_UNIT 0x16 -#define SCSIOP_RELEASE_UNIT 0x17 -#define SCSIOP_COPY 0x18 -#define SCSIOP_ERASE 0x19 -#define SCSIOP_MODE_SENSE 0x1A -#define SCSIOP_START_STOP_UNIT 0x1B -#define SCSIOP_STOP_PRINT 0x1B -#define SCSIOP_LOAD_UNLOAD 0x1B -#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C -#define SCSIOP_SEND_DIAGNOSTIC 0x1D -#define SCSIOP_MEDIUM_REMOVAL 0x1E -#define SCSIOP_READ_CAPACITY 0x25 -#define SCSIOP_READ 0x28 -#define SCSIOP_WRITE 0x2A -#define SCSIOP_SEEK 0x2B -#define SCSIOP_LOCATE 0x2B -#define SCSIOP_WRITE_VERIFY 0x2E -#define SCSIOP_VERIFY 0x2F -#define SCSIOP_SEARCH_DATA_HIGH 0x30 -#define SCSIOP_SEARCH_DATA_EQUAL 0x31 -#define SCSIOP_SEARCH_DATA_LOW 0x32 -#define SCSIOP_SET_LIMITS 0x33 -#define SCSIOP_READ_POSITION 0x34 -#define SCSIOP_SYNCHRONIZE_CACHE 0x35 -#define SCSIOP_COMPARE 0x39 -#define SCSIOP_COPY_COMPARE 0x3A -#define SCSIOP_WRITE_DATA_BUFF 0x3B -#define SCSIOP_READ_DATA_BUFF 0x3C -#define SCSIOP_CHANGE_DEFINITION 0x40 -#define SCSIOP_READ_SUB_CHANNEL 0x42 -#define SCSIOP_READ_TOC 0x43 -#define SCSIOP_READ_HEADER 0x44 -#define SCSIOP_PLAY_AUDIO 0x45 -#define SCSIOP_PLAY_AUDIO_MSF 0x47 -#define SCSIOP_PLAY_TRACK_INDEX 0x48 -#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 -#define SCSIOP_PAUSE_RESUME 0x4B -#define SCSIOP_LOG_SELECT 0x4C -#define SCSIOP_LOG_SENSE 0x4D -#define SCSIOP_MODE_SELECT10 0x55 -#define SCSIOP_MODE_SENSE10 0x5A -#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6 -#define SCSIOP_MECHANISM_STATUS 0xBD -#define SCSIOP_READ_CD 0xBE - -// IDE command definitions -#define IDE_COMMAND_ATAPI_RESET 0x08 -#define IDE_COMMAND_READ 0x20 -#define IDE_COMMAND_WRITE 0x30 -#define IDE_COMMAND_RECALIBRATE 0x10 -#define IDE_COMMAND_SEEK 0x70 -#define IDE_COMMAND_SET_PARAMETERS 0x91 -#define IDE_COMMAND_VERIFY 0x40 -#define IDE_COMMAND_ATAPI_PACKET 0xA0 -#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1 -#define IDE_CMD_READ_MULTIPLE 0xC4 -#define IDE_CMD_WRITE_MULTIPLE 0xC5 -#define IDE_CMD_SET_MULTIPLE 0xC6 -#define IDE_COMMAND_WRITE_DMA 0xCA -#define IDE_COMMAND_READ_DMA 0xC8 -#define IDE_COMMAND_IDENTIFY 0xEC - -// IDE status definitions -#define IDE_STATUS_ERROR 0x01 -#define IDE_STATUS_INDEX 0x02 -#define IDE_STATUS_CORRECTED_ERROR 0x04 -#define IDE_STATUS_DRQ 0x08 -#define IDE_STATUS_DSC 0x10 -#define IDE_STATUS_WRITE_FAULT 0x20 -#define IDE_STATUS_DRDY 0x40 -#define IDE_STATUS_BUSY 0x80 - -// IDE error definitions -#define IDE_ERROR_AMNF 0x01 -#define IDE_ERROR_TKONF 0x02 -#define IDE_ERROR_ABRT 0x04 -#define IDE_ERROR_MCR 0x08 -#define IDE_ERROR_IDFN 0x10 -#define IDE_ERROR_MC 0x20 -#define IDE_ERROR_UNC 0x40 -#define IDE_ERROR_BBK 0x80 - -// IDE interface structure -typedef struct _IDE_STRUCT - { - union - { - UCHAR ide[9]; - struct - { - USHORT data; - UCHAR sectors; - UCHAR lba[4]; - UCHAR cmd; - UCHAR spigot; - } ides; - } ide; - } IDE_STRUCT; - -// SCSI read capacity structure -typedef struct _READ_CAPACITY_DATA - { - ULONG blks; /* total blocks (converted to little endian) */ - ULONG blksiz; /* size of each (converted to little endian) */ - } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; - -// SCSI inquiry data -#ifndef HOSTS_C - -typedef struct _INQUIRYDATA - { - UCHAR DeviceType :5; - UCHAR DeviceTypeQualifier :3; - UCHAR DeviceTypeModifier :7; - UCHAR RemovableMedia :1; - UCHAR Versions; - UCHAR ResponseDataFormat; - UCHAR AdditionalLength; - UCHAR Reserved[2]; - UCHAR SoftReset :1; - UCHAR CommandQueue :1; - UCHAR Reserved2 :1; - UCHAR LinkedCommands :1; - UCHAR Synchronous :1; - UCHAR Wide16Bit :1; - UCHAR Wide32Bit :1; - UCHAR RelativeAddressing :1; - UCHAR VendorId[8]; - UCHAR ProductId[16]; - UCHAR ProductRevisionLevel[4]; - UCHAR VendorSpecific[20]; - UCHAR Reserved3[40]; - } INQUIRYDATA, *PINQUIRYDATA; -#endif - -// IDE IDENTIFY data -typedef struct _IDENTIFY_DATA - { - USHORT GeneralConfiguration; // 00 - USHORT NumberOfCylinders; // 02 - USHORT Reserved1; // 04 - USHORT NumberOfHeads; // 06 - USHORT UnformattedBytesPerTrack; // 08 - USHORT UnformattedBytesPerSector; // 0A - USHORT SectorsPerTrack; // 0C - USHORT VendorUnique1[3]; // 0E - USHORT SerialNumber[10]; // 14 - USHORT BufferType; // 28 - USHORT BufferSectorSize; // 2A - USHORT NumberOfEccBytes; // 2C - USHORT FirmwareRevision[4]; // 2E - USHORT ModelNumber[20]; // 36 - UCHAR MaximumBlockTransfer; // 5E - UCHAR VendorUnique2; // 5F - USHORT DoubleWordIo; // 60 - USHORT Capabilities; // 62 - USHORT Reserved2; // 64 - UCHAR VendorUnique3; // 66 - UCHAR PioCycleTimingMode; // 67 - UCHAR VendorUnique4; // 68 - UCHAR DmaCycleTimingMode; // 69 - USHORT TranslationFieldsValid:1; // 6A - USHORT Reserved3:15; - USHORT NumberOfCurrentCylinders; // 6C - USHORT NumberOfCurrentHeads; // 6E - USHORT CurrentSectorsPerTrack; // 70 - ULONG CurrentSectorCapacity; // 72 - USHORT Reserved4[197]; // 76 - } IDENTIFY_DATA, *PIDENTIFY_DATA; - -// Identify data without the Reserved4. -typedef struct _IDENTIFY_DATA2 { - USHORT GeneralConfiguration; // 00 - USHORT NumberOfCylinders; // 02 - USHORT Reserved1; // 04 - USHORT NumberOfHeads; // 06 - USHORT UnformattedBytesPerTrack; // 08 - USHORT UnformattedBytesPerSector; // 0A - USHORT SectorsPerTrack; // 0C - USHORT VendorUnique1[3]; // 0E - USHORT SerialNumber[10]; // 14 - USHORT BufferType; // 28 - USHORT BufferSectorSize; // 2A - USHORT NumberOfEccBytes; // 2C - USHORT FirmwareRevision[4]; // 2E - USHORT ModelNumber[20]; // 36 - UCHAR MaximumBlockTransfer; // 5E - UCHAR VendorUnique2; // 5F - USHORT DoubleWordIo; // 60 - USHORT Capabilities; // 62 - USHORT Reserved2; // 64 - UCHAR VendorUnique3; // 66 - UCHAR PioCycleTimingMode; // 67 - UCHAR VendorUnique4; // 68 - UCHAR DmaCycleTimingMode; // 69 - USHORT TranslationFieldsValid:1; // 6A - USHORT Reserved3:15; - USHORT NumberOfCurrentCylinders; // 6C - USHORT NumberOfCurrentHeads; // 6E - USHORT CurrentSectorsPerTrack; // 70 - ULONG CurrentSectorCapacity; // 72 - } IDENTIFY_DATA2, *PIDENTIFY_DATA2; - -#endif // PSI_EIDE_SCSIOP - -// function prototypes -int Psi240i_Command(struct scsi_cmnd *SCpnt); -int Psi240i_Abort(struct scsi_cmnd *SCpnt); -int Psi240i_Reset(struct scsi_cmnd *SCpnt, unsigned int flags); -#endif diff --git a/drivers/scsi/psi_chip.h b/drivers/scsi/psi_chip.h deleted file mode 100644 index 224cf8f64c97..000000000000 --- a/drivers/scsi/psi_chip.h +++ /dev/null @@ -1,195 +0,0 @@ -/*+M************************************************************************* - * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux. - * - * Copyright (c) 1997 Perceptive Solutions, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * File Name: psi_chip.h - * - * Description: This file contains the interface defines and - * error codes. - * - *-M*************************************************************************/ -#ifndef PSI_CHIP -#define PSI_CHIP - -/************************************************/ -/* Misc konstants */ -/************************************************/ -#define CHIP_MAXDRIVES 8 - -/************************************************/ -/* Chip I/O addresses */ -/************************************************/ -#define CHIP_ADRS_0 0x0130 -#define CHIP_ADRS_1 0x0150 -#define CHIP_ADRS_2 0x0190 -#define CHIP_ADRS_3 0x0210 -#define CHIP_ADRS_4 0x0230 -#define CHIP_ADRS_5 0x0250 - -/************************************************/ -/* EEPROM locations */ -/************************************************/ -#define CHIP_EEPROM_BIOS 0x0000 // BIOS base address -#define CHIP_EEPROM_DATA 0x2000 // SETUP data base address -#define CHIP_EEPROM_FACTORY 0x2400 // FACTORY data base address -#define CHIP_EEPROM_SETUP 0x3000 // SETUP PROGRAM base address - -#define CHIP_EEPROM_SIZE 32768U // size of the entire EEPROM -#define CHIP_EEPROM_BIOS_SIZE 8192 // size of the BIOS in bytes -#define CHIP_EEPROM_DATA_SIZE 4096 // size of factory, setup, log data block in bytes -#define CHIP_EEPROM_SETUP_SIZE 20480U // size of the setup program in bytes - -/************************************************/ -/* Chip Interrupts */ -/************************************************/ -#define CHIP_IRQ_10 0x72 -#define CHIP_IRQ_11 0x73 -#define CHIP_IRQ_12 0x74 - -/************************************************/ -/* Chip Setup addresses */ -/************************************************/ -#define CHIP_SETUP_BASE 0x0000C000L - -/************************************************/ -/* Chip Register address offsets */ -/************************************************/ -#define REG_DATA 0x00 -#define REG_ERROR 0x01 -#define REG_SECTOR_COUNT 0x02 -#define REG_LBA_0 0x03 -#define REG_LBA_8 0x04 -#define REG_LBA_16 0x05 -#define REG_LBA_24 0x06 -#define REG_STAT_CMD 0x07 -#define REG_SEL_FAIL 0x08 -#define REG_IRQ_STATUS 0x09 -#define REG_ADDRESS 0x0A -#define REG_FAIL 0x0C -#define REG_ALT_STAT 0x0E -#define REG_DRIVE_ADRS 0x0F - -/************************************************/ -/* Chip RAM locations */ -/************************************************/ -#define CHIP_DEVICE 0x8000 -#define CHIP_DEVICE_0 0x8000 -#define CHIP_DEVICE_1 0x8008 -#define CHIP_DEVICE_2 0x8010 -#define CHIP_DEVICE_3 0x8018 -#define CHIP_DEVICE_4 0x8020 -#define CHIP_DEVICE_5 0x8028 -#define CHIP_DEVICE_6 0x8030 -#define CHIP_DEVICE_7 0x8038 -typedef struct - { - UCHAR channel; // channel of this device (0-8). - UCHAR spt; // Sectors Per Track. - ULONG spc; // Sectors Per Cylinder. - } CHIP_DEVICE_N; - -#define CHIP_CONFIG 0x8100 // address of boards configuration. -typedef struct - { - UCHAR irq; // interrupt request channel number - UCHAR numDrives; // Number of accessible drives - UCHAR fastFormat; // Boolean for fast format enable - } CHIP_CONFIG_N; - -#define CHIP_MAP 0x8108 // eight byte device type map. - - -#define CHIP_RAID 0x8120 // array of RAID signature structures and LBA -#define CHIP_RAID_1 0x8120 -#define CHIP_RAID_2 0x8130 -#define CHIP_RAID_3 0x8140 -#define CHIP_RAID_4 0x8150 - -/************************************************/ -/* Chip Register Masks */ -/************************************************/ -#define CHIP_ID 0x7B -#define SEL_RAM 0x8000 -#define MASK_FAIL 0x80 - -/************************************************/ -/* Chip cable select bits */ -/************************************************/ -#define SECTORSXFER 8 - -/************************************************/ -/* Chip cable select bits */ -/************************************************/ -#define SEL_NONE 0x00 -#define SEL_1 0x01 -#define SEL_2 0x02 -#define SEL_3 0x04 -#define SEL_4 0x08 - -/************************************************/ -/* Programmable Interrupt Controller*/ -/************************************************/ -#define PIC1 0x20 // first 8259 base port address -#define PIC2 0xA0 // second 8259 base port address -#define INT_OCW1 1 // Operation Control Word 1: IRQ mask -#define EOI 0x20 // non-specific end-of-interrupt - -/************************************************/ -/* Device/Geometry controls */ -/************************************************/ -#define GEOMETRY_NONE 0x0 // No device -#define GEOMETRY_AUTO 0x1 // Geometry set automatically -#define GEOMETRY_USER 0x2 // User supplied geometry - -#define DEVICE_NONE 0x0 // No device present -#define DEVICE_INACTIVE 0x1 // device present but not registered active -#define DEVICE_ATAPI 0x2 // ATAPI device (CD_ROM, Tape, Etc...) -#define DEVICE_DASD_NONLBA 0x3 // Non LBA incompatible device -#define DEVICE_DASD_LBA 0x4 // LBA compatible device - -/************************************************/ -/* Setup Structure Definitions */ -/************************************************/ -typedef struct // device setup parameters - { - UCHAR geometryControl; // geometry control flags - UCHAR device; // device code - USHORT sectors; // number of sectors per track - USHORT heads; // number of heads - USHORT cylinders; // number of cylinders for this device - ULONG blocks; // number of blocks on device - USHORT spare1; - USHORT spare2; - } SETUP_DEVICE, *PSETUP_DEVICE; - -typedef struct // master setup structure - { - USHORT startupDelay; - USHORT promptBIOS; - USHORT fastFormat; - USHORT spare2; - USHORT spare3; - USHORT spare4; - USHORT spare5; - USHORT spare6; - SETUP_DEVICE setupDevice[8]; - } SETUP, *PSETUP; - -#endif - diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 288640756099..68c0d09ffe78 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -528,7 +528,7 @@ __setup("qla1280=", qla1280_setup); #define CMD_CDBLEN(Cmnd) Cmnd->cmd_len #define CMD_CDBP(Cmnd) Cmnd->cmnd #define CMD_SNSP(Cmnd) Cmnd->sense_buffer -#define CMD_SNSLEN(Cmnd) sizeof(Cmnd->sense_buffer) +#define CMD_SNSLEN(Cmnd) SCSI_SENSE_BUFFERSIZE #define CMD_RESULT(Cmnd) Cmnd->result #define CMD_HANDLE(Cmnd) Cmnd->host_scribble #define CMD_REQUEST(Cmnd) Cmnd->request->cmd @@ -3715,7 +3715,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt, } else sense_sz = 0; memset(cmd->sense_buffer + sense_sz, 0, - sizeof(cmd->sense_buffer) - sense_sz); + SCSI_SENSE_BUFFERSIZE - sense_sz); dprintk(2, "qla1280_status_entry: Check " "condition Sense data, b %i, t %i, " @@ -4204,7 +4204,6 @@ static struct scsi_host_template qla1280_driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile index 71ddb5db4944..c51fd1f86639 100644 --- a/drivers/scsi/qla2xxx/Makefile +++ b/drivers/scsi/qla2xxx/Makefile @@ -1,4 +1,4 @@ qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ - qla_dbg.o qla_sup.o qla_attr.o qla_mid.o + qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index fb388b8c07cf..adf97320574b 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -9,7 +9,7 @@ #include <linux/kthread.h> #include <linux/vmalloc.h> -int qla24xx_vport_disable(struct fc_vport *, bool); +static int qla24xx_vport_disable(struct fc_vport *, bool); /* SYSFS attributes --------------------------------------------------------- */ @@ -958,7 +958,7 @@ qla2x00_issue_lip(struct Scsi_Host *shost) { scsi_qla_host_t *ha = shost_priv(shost); - set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags); + qla2x00_loop_reset(ha); return 0; } @@ -967,35 +967,51 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) { scsi_qla_host_t *ha = shost_priv(shost); int rval; - uint16_t mb_stat[1]; - link_stat_t stat_buf; + struct link_statistics *stats; + dma_addr_t stats_dma; struct fc_host_statistics *pfc_host_stat; - rval = QLA_FUNCTION_FAILED; pfc_host_stat = &ha->fc_host_stat; memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics)); + stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma); + if (stats == NULL) { + DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n", + __func__, ha->host_no)); + goto done; + } + memset(stats, 0, DMA_POOL_SIZE); + + rval = QLA_FUNCTION_FAILED; if (IS_FWI2_CAPABLE(ha)) { - rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf, - sizeof(stat_buf) / 4, mb_stat); + rval = qla24xx_get_isp_stats(ha, stats, stats_dma); } else if (atomic_read(&ha->loop_state) == LOOP_READY && !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) && !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) && !ha->dpc_active) { /* Must be in a 'READY' state for statistics retrieval. */ - rval = qla2x00_get_link_status(ha, ha->loop_id, &stat_buf, - mb_stat); + rval = qla2x00_get_link_status(ha, ha->loop_id, stats, + stats_dma); } if (rval != QLA_SUCCESS) - goto done; + goto done_free; + + pfc_host_stat->link_failure_count = stats->link_fail_cnt; + pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt; + pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt; + pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt; + pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt; + pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt; + if (IS_FWI2_CAPABLE(ha)) { + pfc_host_stat->tx_frames = stats->tx_frames; + pfc_host_stat->rx_frames = stats->rx_frames; + pfc_host_stat->dumped_frames = stats->dumped_frames; + pfc_host_stat->nos_count = stats->nos_rcvd; + } - pfc_host_stat->link_failure_count = stat_buf.link_fail_cnt; - pfc_host_stat->loss_of_sync_count = stat_buf.loss_sync_cnt; - pfc_host_stat->loss_of_signal_count = stat_buf.loss_sig_cnt; - pfc_host_stat->prim_seq_protocol_err_count = stat_buf.prim_seq_err_cnt; - pfc_host_stat->invalid_tx_word_count = stat_buf.inval_xmit_word_cnt; - pfc_host_stat->invalid_crc_count = stat_buf.inval_crc_cnt; +done_free: + dma_pool_free(ha->s_dma_pool, stats, stats_dma); done: return pfc_host_stat; } @@ -1113,7 +1129,7 @@ vport_create_failed_2: return FC_VPORT_FAILED; } -int +static int qla24xx_vport_delete(struct fc_vport *fc_vport) { scsi_qla_host_t *ha = shost_priv(fc_vport->shost); @@ -1124,7 +1140,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) down(&ha->vport_sem); ha->cur_vport_count--; - clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map); + clear_bit(vha->vp_idx, ha->vp_idx_map); up(&ha->vport_sem); kfree(vha->node_name); @@ -1146,7 +1162,7 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) return 0; } -int +static int qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) { scsi_qla_host_t *vha = fc_vport->dd_data; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index eaa04dabcdf6..d88e98c476b0 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1051,6 +1051,7 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) struct qla25xx_fw_dump *fw; uint32_t ext_mem_cnt; void *nxt; + struct qla2xxx_fce_chain *fcec; risc_address = ext_mem_cnt = 0; flags = 0; @@ -1321,10 +1322,31 @@ qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval != QLA_SUCCESS) goto qla25xx_fw_dump_failed_0; + /* Fibre Channel Trace Buffer. */ nxt = qla2xxx_copy_queues(ha, nxt); if (ha->eft) memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); + /* Fibre Channel Event Buffer. */ + if (!ha->fce) + goto qla25xx_fw_dump_failed_0; + + ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); + + fcec = nxt + ntohl(ha->fw_dump->eft_size); + fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST); + fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) + + fce_calc_size(ha->fce_bufs)); + fcec->size = htonl(fce_calc_size(ha->fce_bufs)); + fcec->addr_l = htonl(LSD(ha->fce_dma)); + fcec->addr_h = htonl(MSD(ha->fce_dma)); + + iter_reg = fcec->eregs; + for (cnt = 0; cnt < 8; cnt++) + *iter_reg++ = htonl(ha->fce_mb[cnt]); + + memcpy(iter_reg, ha->fce, ntohl(fcec->size)); + qla25xx_fw_dump_failed_0: if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, @@ -1428,21 +1450,6 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd) printk(" sp flags=0x%x\n", sp->flags); } -void -qla2x00_dump_pkt(void *pkt) -{ - uint32_t i; - uint8_t *data = (uint8_t *) pkt; - - for (i = 0; i < 64; i++) { - if (!(i % 4)) - printk("\n%02x: ", i); - - printk("%02x ", data[i]); - } - printk("\n"); -} - #if defined(QL_DEBUG_ROUTINES) /* * qla2x00_formatted_dump_buffer diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index a50ecf0b7c84..524598afc81c 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -256,6 +256,25 @@ struct qla25xx_fw_dump { #define EFT_BYTES_PER_BUFFER 0x4000 #define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS)) +#define FCE_NUM_BUFFERS 64 +#define FCE_BYTES_PER_BUFFER 0x400 +#define FCE_SIZE ((FCE_BYTES_PER_BUFFER) * (FCE_NUM_BUFFERS)) +#define fce_calc_size(b) ((FCE_BYTES_PER_BUFFER) * (b)) + +struct qla2xxx_fce_chain { + uint32_t type; + uint32_t chain_size; + + uint32_t size; + uint32_t addr_l; + uint32_t addr_h; + uint32_t eregs[8]; +}; + +#define DUMP_CHAIN_VARIANT 0x80000000 +#define DUMP_CHAIN_FCE 0x7FFFFAF0 +#define DUMP_CHAIN_LAST 0x80000000 + struct qla2xxx_fw_dump { uint8_t signature[4]; uint32_t version; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 04e8cbca4c0d..6f129da37589 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -623,9 +623,6 @@ typedef struct { #define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ #define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ -#define TC_ENABLE 4 -#define TC_DISABLE 5 - /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -862,14 +859,20 @@ typedef struct { #define GLSO_SEND_RPS BIT_0 #define GLSO_USE_DID BIT_3 -typedef struct { - uint32_t link_fail_cnt; - uint32_t loss_sync_cnt; - uint32_t loss_sig_cnt; - uint32_t prim_seq_err_cnt; - uint32_t inval_xmit_word_cnt; - uint32_t inval_crc_cnt; -} link_stat_t; +struct link_statistics { + uint32_t link_fail_cnt; + uint32_t loss_sync_cnt; + uint32_t loss_sig_cnt; + uint32_t prim_seq_err_cnt; + uint32_t inval_xmit_word_cnt; + uint32_t inval_crc_cnt; + uint32_t unused1[0x1b]; + uint32_t tx_frames; + uint32_t rx_frames; + uint32_t dumped_frames; + uint32_t unused2[2]; + uint32_t nos_rcvd; +}; /* * NVRAM Command values. @@ -2116,14 +2119,6 @@ struct qla_msix_entry { #define WATCH_INTERVAL 1 /* number of seconds */ -/* NPIV */ -#define MAX_MULTI_ID_LOOP 126 -#define MAX_MULTI_ID_FABRIC 64 -#define MAX_NUM_VPORT_LOOP (MAX_MULTI_ID_LOOP - 1) -#define MAX_NUM_VPORT_FABRIC (MAX_MULTI_ID_FABRIC - 1) -#define MAX_NUM_VHBA_LOOP (MAX_MULTI_ID_LOOP - 1) -#define MAX_NUM_VHBA_FABRIC (MAX_MULTI_ID_FABRIC - 1) - /* * Linux Host Adapter structure */ @@ -2161,6 +2156,7 @@ typedef struct scsi_qla_host { uint32_t gpsc_supported :1; uint32_t vsan_enabled :1; uint32_t npiv_supported :1; + uint32_t fce_enabled :1; } flags; atomic_t loop_state; @@ -2273,8 +2269,7 @@ typedef struct scsi_qla_host { int bars; device_reg_t __iomem *iobase; /* Base I/O address */ - unsigned long pio_address; - unsigned long pio_length; + resource_size_t pio_address; #define MIN_IOBASE_LEN 0x100 /* ISP ring lock, rings, and indexes */ @@ -2416,9 +2411,9 @@ typedef struct scsi_qla_host { #define MBX_INTR_WAIT 2 #define MBX_UPDATE_FLASH_ACTIVE 3 - struct semaphore mbx_cmd_sem; /* Serialialize mbx access */ struct semaphore vport_sem; /* Virtual port synchronization */ - struct semaphore mbx_intr_sem; /* Used for completion notification */ + struct completion mbx_cmd_comp; /* Serialize mbx access */ + struct completion mbx_intr_comp; /* Used for completion notification */ uint32_t mbx_flags; #define MBX_IN_PROGRESS BIT_0 @@ -2455,6 +2450,15 @@ typedef struct scsi_qla_host { dma_addr_t eft_dma; void *eft; + struct dentry *dfs_dir; + struct dentry *dfs_fce; + dma_addr_t fce_dma; + void *fce; + uint32_t fce_bufs; + uint16_t fce_mb[8]; + uint64_t fce_wr, fce_rd; + struct mutex fce_mutex; + uint8_t host_str[16]; uint32_t pci_attr; uint16_t chip_revision; @@ -2507,7 +2511,7 @@ typedef struct scsi_qla_host { struct list_head vp_list; /* list of VP */ struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ - uint8_t vp_idx_map[16]; + unsigned long vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / sizeof(unsigned long)]; uint16_t num_vhosts; /* number of vports created */ uint16_t num_vsans; /* number of vsan created */ uint16_t vp_idx; /* vport ID */ diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c new file mode 100644 index 000000000000..1479c60441c8 --- /dev/null +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -0,0 +1,175 @@ +/* + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2005 QLogic Corporation + * + * See LICENSE.qla2xxx for copyright and licensing details. + */ +#include "qla_def.h" + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +static struct dentry *qla2x00_dfs_root; +static atomic_t qla2x00_dfs_root_count; + +static int +qla2x00_dfs_fce_show(struct seq_file *s, void *unused) +{ + scsi_qla_host_t *ha = s->private; + uint32_t cnt; + uint32_t *fce; + uint64_t fce_start; + + mutex_lock(&ha->fce_mutex); + + seq_printf(s, "FCE Trace Buffer\n"); + seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr); + seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma); + seq_printf(s, "FCE Enable Registers\n"); + seq_printf(s, "%08x %08x %08x %08x %08x %08x\n", + ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4], + ha->fce_mb[5], ha->fce_mb[6]); + + fce = (uint32_t *) ha->fce; + fce_start = (unsigned long long) ha->fce_dma; + for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) { + if (cnt % 8 == 0) + seq_printf(s, "\n%llx: ", + (unsigned long long)((cnt * 4) + fce_start)); + else + seq_printf(s, " "); + seq_printf(s, "%08x", *fce++); + } + + seq_printf(s, "\nEnd\n"); + + mutex_unlock(&ha->fce_mutex); + + return 0; +} + +static int +qla2x00_dfs_fce_open(struct inode *inode, struct file *file) +{ + scsi_qla_host_t *ha = inode->i_private; + int rval; + + if (!ha->flags.fce_enabled) + goto out; + + mutex_lock(&ha->fce_mutex); + + /* Pause tracing to flush FCE buffers. */ + rval = qla2x00_disable_fce_trace(ha, &ha->fce_wr, &ha->fce_rd); + if (rval) + qla_printk(KERN_WARNING, ha, + "DebugFS: Unable to disable FCE (%d).\n", rval); + + ha->flags.fce_enabled = 0; + + mutex_unlock(&ha->fce_mutex); +out: + return single_open(file, qla2x00_dfs_fce_show, ha); +} + +static int +qla2x00_dfs_fce_release(struct inode *inode, struct file *file) +{ + scsi_qla_host_t *ha = inode->i_private; + int rval; + + if (ha->flags.fce_enabled) + goto out; + + mutex_lock(&ha->fce_mutex); + + /* Re-enable FCE tracing. */ + ha->flags.fce_enabled = 1; + memset(ha->fce, 0, fce_calc_size(ha->fce_bufs)); + rval = qla2x00_enable_fce_trace(ha, ha->fce_dma, ha->fce_bufs, + ha->fce_mb, &ha->fce_bufs); + if (rval) { + qla_printk(KERN_WARNING, ha, + "DebugFS: Unable to reinitialize FCE (%d).\n", rval); + ha->flags.fce_enabled = 0; + } + + mutex_unlock(&ha->fce_mutex); +out: + return single_release(inode, file); +} + +static const struct file_operations dfs_fce_ops = { + .open = qla2x00_dfs_fce_open, + .read = seq_read, + .llseek = seq_lseek, + .release = qla2x00_dfs_fce_release, +}; + +int +qla2x00_dfs_setup(scsi_qla_host_t *ha) +{ + if (!IS_QLA25XX(ha)) + goto out; + if (!ha->fce) + goto out; + + if (qla2x00_dfs_root) + goto create_dir; + + atomic_set(&qla2x00_dfs_root_count, 0); + qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL); + if (!qla2x00_dfs_root) { + qla_printk(KERN_NOTICE, ha, + "DebugFS: Unable to create root directory.\n"); + goto out; + } + +create_dir: + if (ha->dfs_dir) + goto create_nodes; + + mutex_init(&ha->fce_mutex); + ha->dfs_dir = debugfs_create_dir(ha->host_str, qla2x00_dfs_root); + if (!ha->dfs_dir) { + qla_printk(KERN_NOTICE, ha, + "DebugFS: Unable to create ha directory.\n"); + goto out; + } + + atomic_inc(&qla2x00_dfs_root_count); + +create_nodes: + ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha, + &dfs_fce_ops); + if (!ha->dfs_fce) { + qla_printk(KERN_NOTICE, ha, + "DebugFS: Unable to fce node.\n"); + goto out; + } +out: + return 0; +} + +int +qla2x00_dfs_remove(scsi_qla_host_t *ha) +{ + if (ha->dfs_fce) { + debugfs_remove(ha->dfs_fce); + ha->dfs_fce = NULL; + } + + if (ha->dfs_dir) { + debugfs_remove(ha->dfs_dir); + ha->dfs_dir = NULL; + atomic_dec(&qla2x00_dfs_root_count); + } + + if (atomic_read(&qla2x00_dfs_root_count) == 0 && + qla2x00_dfs_root) { + debugfs_remove(qla2x00_dfs_root); + qla2x00_dfs_root = NULL; + } + + return 0; +} diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 25364b1aaf12..9337e138ed63 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -952,9 +952,31 @@ struct device_reg_24xx { uint32_t iobase_sdata; }; +/* Trace Control *************************************************************/ + +#define TC_AEN_DISABLE 0 + +#define TC_EFT_ENABLE 4 +#define TC_EFT_DISABLE 5 + +#define TC_FCE_ENABLE 8 +#define TC_FCE_OPTIONS 0 +#define TC_FCE_DEFAULT_RX_SIZE 2112 +#define TC_FCE_DEFAULT_TX_SIZE 2112 +#define TC_FCE_DISABLE 9 +#define TC_FCE_DISABLE_TRACE BIT_0 + /* MID Support ***************************************************************/ -#define MAX_MID_VPS 125 +#define MIN_MULTI_ID_FABRIC 64 /* Must be power-of-2. */ +#define MAX_MULTI_ID_FABRIC 256 /* ... */ + +#define for_each_mapped_vp_idx(_ha, _idx) \ + for (_idx = find_next_bit((_ha)->vp_idx_map, \ + (_ha)->max_npiv_vports + 1, 1); \ + _idx <= (_ha)->max_npiv_vports; \ + _idx = find_next_bit((_ha)->vp_idx_map, \ + (_ha)->max_npiv_vports + 1, _idx + 1)) \ struct mid_conf_entry_24xx { uint16_t reserved_1; @@ -982,7 +1004,7 @@ struct mid_init_cb_24xx { uint16_t count; uint16_t options; - struct mid_conf_entry_24xx entries[MAX_MID_VPS]; + struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC]; }; @@ -1002,10 +1024,6 @@ struct mid_db_entry_24xx { uint8_t reserved_1; }; -struct mid_db_24xx { - struct mid_db_entry_24xx entries[MAX_MID_VPS]; -}; - /* * Virtual Fabric ID type definition. */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 09cb2a908059..ba35fc26ce6b 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -65,33 +65,25 @@ extern int ql2xextended_error_logging; extern int ql2xqfullrampup; extern int num_hosts; +extern int qla2x00_loop_reset(scsi_qla_host_t *); + /* * Global Functions in qla_mid.c source file. */ -extern struct scsi_host_template qla2x00_driver_template; extern struct scsi_host_template qla24xx_driver_template; extern struct scsi_transport_template *qla2xxx_transport_vport_template; -extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); extern void qla2x00_timer(scsi_qla_host_t *); extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long); -extern void qla2x00_stop_timer(scsi_qla_host_t *); -extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *); extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *); extern int qla24xx_disable_vp (scsi_qla_host_t *); extern int qla24xx_enable_vp (scsi_qla_host_t *); -extern void qla2x00_mem_free(scsi_qla_host_t *); extern int qla24xx_control_vp(scsi_qla_host_t *, int ); extern int qla24xx_modify_vp_config(scsi_qla_host_t *); extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t); extern void qla2x00_vp_stop_timer(scsi_qla_host_t *); extern int qla24xx_configure_vhba (scsi_qla_host_t *); -extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int); -extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t); -extern int qla2x00_do_dpc_vp(scsi_qla_host_t *); extern void qla24xx_report_id_acquisition(scsi_qla_host_t *, struct vp_rpt_id_entry_24xx *); -extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *, - uint8_t *); extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *); extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *); @@ -103,8 +95,6 @@ extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *); extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int); extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int); -extern int qla2x00_down_timeout(struct semaphore *, unsigned long); - extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *); @@ -113,7 +103,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *); extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *); extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *); extern void qla2x00_vp_abort_isp(scsi_qla_host_t *); -extern int qla24xx_vport_delete(struct fc_vport *); /* * Global Function Prototypes in qla_iocb.c source file. @@ -222,21 +211,16 @@ extern int qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map); extern int -qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, link_stat_t *, - uint16_t *); +qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *, + dma_addr_t); extern int -qla24xx_get_isp_stats(scsi_qla_host_t *, uint32_t *, uint32_t, uint16_t *); +qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, + dma_addr_t); extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *); extern int qla24xx_abort_target(fc_port_t *); -extern int qla2x00_system_error(scsi_qla_host_t *); - -extern int -qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *, - uint16_t *); - extern int qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); @@ -244,13 +228,19 @@ extern int qla2x00_stop_firmware(scsi_qla_host_t *); extern int -qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t); +qla2x00_enable_eft_trace(scsi_qla_host_t *, dma_addr_t, uint16_t); +extern int +qla2x00_disable_eft_trace(scsi_qla_host_t *); extern int -qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); +qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *, + uint32_t *); extern int -qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *); +qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *); + +extern int +qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); extern int qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); @@ -270,11 +260,7 @@ extern void qla2x00_free_irqs(scsi_qla_host_t *); /* * Global Function Prototypes in qla_sup.c source file. */ -extern void qla2x00_lock_nvram_access(scsi_qla_host_t *); -extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *); extern void qla2x00_release_nvram_protection(scsi_qla_host_t *); -extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t); -extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t); extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *, uint32_t, uint32_t); extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, @@ -321,7 +307,6 @@ extern void qla25xx_fw_dump(scsi_qla_host_t *, int); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *); -extern void qla2x00_dump_pkt(void *); /* * Global Function Prototypes in qla_gs.c source file. @@ -356,4 +341,10 @@ extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_init_host_attr(scsi_qla_host_t *); extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); + +/* + * Global Function Prototypes in qla_dfs.c source file. + */ +extern int qla2x00_dfs_setup(scsi_qla_host_t *); +extern int qla2x00_dfs_remove(scsi_qla_host_t *); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 191dafd89be0..d0633ca894be 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -732,9 +732,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) { int rval; uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, - eft_size; - dma_addr_t eft_dma; - void *eft; + eft_size, fce_size; + dma_addr_t tc_dma; + void *tc; if (ha->fw_dump) { qla_printk(KERN_WARNING, ha, @@ -743,7 +743,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) } ha->fw_dumped = 0; - fixed_size = mem_size = eft_size = 0; + fixed_size = mem_size = eft_size = fce_size = 0; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { fixed_size = sizeof(struct qla2100_fw_dump); } else if (IS_QLA23XX(ha)) { @@ -758,21 +758,21 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) sizeof(uint32_t); /* Allocate memory for Extended Trace Buffer. */ - eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma, + tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, GFP_KERNEL); - if (!eft) { + if (!tc) { qla_printk(KERN_WARNING, ha, "Unable to allocate " "(%d KB) for EFT.\n", EFT_SIZE / 1024); goto cont_alloc; } - rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma, - EFT_NUM_BUFFERS); + memset(tc, 0, EFT_SIZE); + rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS); if (rval) { qla_printk(KERN_WARNING, ha, "Unable to initialize " "EFT (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft, - eft_dma); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, + tc_dma); goto cont_alloc; } @@ -780,9 +780,40 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) EFT_SIZE / 1024); eft_size = EFT_SIZE; - memset(eft, 0, eft_size); - ha->eft_dma = eft_dma; - ha->eft = eft; + ha->eft_dma = tc_dma; + ha->eft = tc; + + /* Allocate memory for Fibre Channel Event Buffer. */ + if (!IS_QLA25XX(ha)) + goto cont_alloc; + + tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, + GFP_KERNEL); + if (!tc) { + qla_printk(KERN_WARNING, ha, "Unable to allocate " + "(%d KB) for FCE.\n", FCE_SIZE / 1024); + goto cont_alloc; + } + + memset(tc, 0, FCE_SIZE); + rval = qla2x00_enable_fce_trace(ha, tc_dma, FCE_NUM_BUFFERS, + ha->fce_mb, &ha->fce_bufs); + if (rval) { + qla_printk(KERN_WARNING, ha, "Unable to initialize " + "FCE (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, + tc_dma); + ha->flags.fce_enabled = 0; + goto cont_alloc; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", + FCE_SIZE / 1024); + + fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE; + ha->flags.fce_enabled = 1; + ha->fce_dma = tc_dma; + ha->fce = tc; } cont_alloc: req_q_size = ha->request_q_length * sizeof(request_t); @@ -790,7 +821,7 @@ cont_alloc: dump_size = offsetof(struct qla2xxx_fw_dump, isp); dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + - eft_size; + eft_size + fce_size; ha->fw_dump = vmalloc(dump_size); if (!ha->fw_dump) { @@ -922,9 +953,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) ha->flags.npiv_supported = 1; if ((!ha->max_npiv_vports) || ((ha->max_npiv_vports + 1) % - MAX_MULTI_ID_FABRIC)) + MIN_MULTI_ID_FABRIC)) ha->max_npiv_vports = - MAX_NUM_VPORT_FABRIC; + MIN_MULTI_ID_FABRIC - 1; } if (ql2xallocfwdump) @@ -1162,7 +1193,10 @@ qla2x00_init_rings(scsi_qla_host_t *ha) DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no)); - mid_init_cb->count = ha->max_npiv_vports; + if (ha->flags.npiv_supported) + mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); + + mid_init_cb->options = __constant_cpu_to_le16(BIT_1); rval = qla2x00_init_firmware(ha, ha->init_cb_size); if (rval) { @@ -2566,14 +2600,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) /* Bypass virtual ports of the same host. */ if (pha->num_vhosts) { - vp_index = find_next_bit( - (unsigned long *)pha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, 1); - - for (;vp_index <= MAX_MULTI_ID_FABRIC; - vp_index = find_next_bit( - (unsigned long *)pha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) { + for_each_mapped_vp_idx(pha, vp_index) { empty_vp_index = 1; found_vp = 0; list_for_each_entry(vha, &pha->vp_list, @@ -2592,7 +2619,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) new_fcport->d_id.b24 == vha->d_id.b24) break; } - if (vp_index <= MAX_MULTI_ID_FABRIC) + + if (vp_index <= pha->max_npiv_vports) continue; } @@ -3245,7 +3273,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); if (ha->eft) { - rval = qla2x00_trace_control(ha, TC_ENABLE, + rval = qla2x00_enable_eft_trace(ha, ha->eft_dma, EFT_NUM_BUFFERS); if (rval) { qla_printk(KERN_WARNING, ha, @@ -3253,6 +3281,21 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) "(%d).\n", rval); } } + + if (ha->fce) { + ha->flags.fce_enabled = 1; + memset(ha->fce, 0, + fce_calc_size(ha->fce_bufs)); + rval = qla2x00_enable_fce_trace(ha, + ha->fce_dma, ha->fce_bufs, ha->fce_mb, + &ha->fce_bufs); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to reinitialize FCE " + "(%d).\n", rval); + ha->flags.fce_enabled = 0; + } + } } else { /* failed the ISP abort */ ha->flags.online = 1; if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 1104bd2eed40..642a0c3f09c6 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -104,7 +104,7 @@ qla2100_intr_handler(int irq, void *dev_id) if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - up(&ha->mbx_intr_sem); + complete(&ha->mbx_intr_comp); } return (IRQ_HANDLED); @@ -216,7 +216,7 @@ qla2300_intr_handler(int irq, void *dev_id) if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - up(&ha->mbx_intr_sem); + complete(&ha->mbx_intr_comp); } return (IRQ_HANDLED); @@ -347,10 +347,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) break; case MBA_SYSTEM_ERR: /* System Error */ - mb[1] = RD_MAILBOX_REG(ha, reg, 1); - mb[2] = RD_MAILBOX_REG(ha, reg, 2); - mb[3] = RD_MAILBOX_REG(ha, reg, 3); - qla_printk(KERN_INFO, ha, "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", mb[1], mb[2], mb[3]); @@ -579,12 +575,15 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) /* Check if the Vport has issued a SCR */ if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags)) break; + /* Only handle SCNs for our Vport index. */ + if (ha->flags.npiv_supported && ha->vp_idx != mb[3]) + break; DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", ha->host_no)); DEBUG(printk(KERN_INFO - "scsi(%ld): RSCN database changed -- %04x %04x.\n", - ha->host_no, mb[1], mb[2])); + "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n", + ha->host_no, mb[1], mb[2], mb[3])); rscn_entry = (mb[1] << 16) | mb[2]; host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) | @@ -823,6 +822,35 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha) WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index); } +static inline void +qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len) +{ + struct scsi_cmnd *cp = sp->cmd; + + if (sense_len >= SCSI_SENSE_BUFFERSIZE) + sense_len = SCSI_SENSE_BUFFERSIZE; + + CMD_ACTUAL_SNSLEN(cp) = sense_len; + sp->request_sense_length = sense_len; + sp->request_sense_ptr = cp->sense_buffer; + if (sp->request_sense_length > 32) + sense_len = 32; + + memcpy(cp->sense_buffer, sense_data, sense_len); + + sp->request_sense_ptr += sense_len; + sp->request_sense_length -= sense_len; + if (sp->request_sense_length != 0) + sp->ha->status_srb = sp; + + DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) " + "cmd=%p pid=%ld\n", __func__, sp->ha->host_no, cp->device->channel, + cp->device->id, cp->device->lun, cp, cp->serial_number)); + if (sense_len) + DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, + CMD_ACTUAL_SNSLEN(cp))); +} + /** * qla2x00_status_entry() - Process a Status IOCB entry. * @ha: SCSI driver HA context @@ -977,36 +1005,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) if (lscsi_status != SS_CHECK_CONDITION) break; - /* Copy Sense Data into sense buffer. */ - memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer)); - + memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); if (!(scsi_status & SS_SENSE_LEN_VALID)) break; - if (sense_len >= sizeof(cp->sense_buffer)) - sense_len = sizeof(cp->sense_buffer); - - CMD_ACTUAL_SNSLEN(cp) = sense_len; - sp->request_sense_length = sense_len; - sp->request_sense_ptr = cp->sense_buffer; - - if (sp->request_sense_length > 32) - sense_len = 32; - - memcpy(cp->sense_buffer, sense_data, sense_len); - - sp->request_sense_ptr += sense_len; - sp->request_sense_length -= sense_len; - if (sp->request_sense_length != 0) - ha->status_srb = sp; - - DEBUG5(printk("%s(): Check condition Sense data, " - "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", __func__, - ha->host_no, cp->device->channel, cp->device->id, - cp->device->lun, cp, cp->serial_number)); - if (sense_len) - DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, - CMD_ACTUAL_SNSLEN(cp))); + qla2x00_handle_sense(sp, sense_data, sense_len); break; case CS_DATA_UNDERRUN: @@ -1061,34 +1064,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) if (lscsi_status != SS_CHECK_CONDITION) break; - /* Copy Sense Data into sense buffer */ - memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer)); - + memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); if (!(scsi_status & SS_SENSE_LEN_VALID)) break; - if (sense_len >= sizeof(cp->sense_buffer)) - sense_len = sizeof(cp->sense_buffer); - - CMD_ACTUAL_SNSLEN(cp) = sense_len; - sp->request_sense_length = sense_len; - sp->request_sense_ptr = cp->sense_buffer; - - if (sp->request_sense_length > 32) - sense_len = 32; - - memcpy(cp->sense_buffer, sense_data, sense_len); - - sp->request_sense_ptr += sense_len; - sp->request_sense_length -= sense_len; - if (sp->request_sense_length != 0) - ha->status_srb = sp; - - DEBUG5(printk("%s(): Check condition Sense data, " - "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n", - __func__, ha->host_no, cp->device->channel, - cp->device->id, cp->device->lun, cp, - cp->serial_number)); + qla2x00_handle_sense(sp, sense_data, sense_len); /* * In case of a Underrun condition, set both the lscsi @@ -1108,10 +1088,6 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt) cp->result = DID_ERROR << 16 | lscsi_status; } - - if (sense_len) - DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, - CMD_ACTUAL_SNSLEN(cp))); } else { /* * If RISC reports underrun and target does not report @@ -1621,7 +1597,7 @@ qla24xx_intr_handler(int irq, void *dev_id) if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - up(&ha->mbx_intr_sem); + complete(&ha->mbx_intr_comp); } return IRQ_HANDLED; @@ -1758,7 +1734,7 @@ qla24xx_msix_default(int irq, void *dev_id) if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - up(&ha->mbx_intr_sem); + complete(&ha->mbx_intr_comp); } return IRQ_HANDLED; @@ -1853,6 +1829,18 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) goto skip_msix; } + if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && + (ha->pdev->subsystem_device == 0x7040 || + ha->pdev->subsystem_device == 0x7041 || + ha->pdev->subsystem_device == 0x1705)) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n", + ha->pdev->subsystem_vendor, + ha->pdev->subsystem_device)); + + goto skip_msi; + } + ret = qla24xx_enable_msix(ha); if (!ret) { DEBUG2(qla_printk(KERN_INFO, ha, diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index ccd662a6f5dc..0c10c0b0fb73 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -8,19 +8,6 @@ #include <linux/delay.h> -static void -qla2x00_mbx_sem_timeout(unsigned long data) -{ - struct semaphore *sem_ptr = (struct semaphore *)data; - - DEBUG11(printk("qla2x00_sem_timeout: entered.\n")); - - if (sem_ptr != NULL) { - up(sem_ptr); - } - - DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n")); -} /* * qla2x00_mailbox_command @@ -47,7 +34,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp) int rval; unsigned long flags = 0; device_reg_t __iomem *reg; - struct timer_list tmp_intr_timer; uint8_t abort_active; uint8_t io_lock_on; uint16_t command; @@ -72,7 +58,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp) * non ISP abort time. */ if (!abort_active) { - if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) { + if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, + mcp->tov * HZ)) { /* Timeout occurred. Return error. */ DEBUG2_3_11(printk("%s(%ld): cmd access timeout. " "Exiting.\n", __func__, ha->host_no)); @@ -135,22 +122,6 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp) /* Wait for mbx cmd completion until timeout */ if (!abort_active && io_lock_on) { - /* sleep on completion semaphore */ - DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n", - __func__, ha->host_no)); - - init_timer(&tmp_intr_timer); - tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem; - tmp_intr_timer.expires = jiffies + mcp->tov * HZ; - tmp_intr_timer.function = - (void (*)(unsigned long))qla2x00_mbx_sem_timeout; - - DEBUG11(printk("%s(%ld): Adding timer.\n", __func__, - ha->host_no)); - add_timer(&tmp_intr_timer); - - DEBUG11(printk("%s(%ld): going to unlock & sleep. " - "time=0x%lx.\n", __func__, ha->host_no, jiffies)); set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); @@ -160,17 +131,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp) WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); - /* Wait for either the timer to expire - * or the mbox completion interrupt - */ - down(&ha->mbx_intr_sem); + wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ); - DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__, - ha->host_no, jiffies)); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); - /* delete the timer */ - del_timer(&tmp_intr_timer); } else { DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__, ha->host_no, command)); @@ -299,7 +263,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp) /* Allow next mbx cmd to come in. */ if (!abort_active) - up(&ha->mbx_cmd_sem); + complete(&ha->mbx_cmd_comp); if (rval) { DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, " @@ -905,7 +869,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; mcp->mb[9] = ha->vp_idx; - mcp->out_mb = MBX_0; + mcp->out_mb = MBX_9|MBX_0; mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; @@ -1016,7 +980,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", ha->host_no)); - if (ha->flags.npiv_supported) + if (ha->fw_attributes & BIT_2) mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE; else mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; @@ -2042,29 +2006,20 @@ qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map) */ int qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, - link_stat_t *ret_buf, uint16_t *status) + struct link_statistics *stats, dma_addr_t stats_dma) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - link_stat_t *stat_buf; - dma_addr_t stat_buf_dma; + uint32_t *siter, *diter, dwords; DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma); - if (stat_buf == NULL) { - DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n", - __func__, ha->host_no)); - return BIT_0; - } - memset(stat_buf, 0, sizeof(link_stat_t)); - mcp->mb[0] = MBC_GET_LINK_STATUS; - mcp->mb[2] = MSW(stat_buf_dma); - mcp->mb[3] = LSW(stat_buf_dma); - mcp->mb[6] = MSW(MSD(stat_buf_dma)); - mcp->mb[7] = LSW(MSD(stat_buf_dma)); + mcp->mb[2] = MSW(stats_dma); + mcp->mb[3] = LSW(stats_dma); + mcp->mb[6] = MSW(MSD(stats_dma)); + mcp->mb[7] = LSW(MSD(stats_dma)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; mcp->in_mb = MBX_0; if (IS_FWI2_CAPABLE(ha)) { @@ -2089,78 +2044,43 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n", __func__, ha->host_no, mcp->mb[0])); - status[0] = mcp->mb[0]; - rval = BIT_1; + rval = QLA_FUNCTION_FAILED; } else { - /* copy over data -- firmware data is LE. */ - ret_buf->link_fail_cnt = - le32_to_cpu(stat_buf->link_fail_cnt); - ret_buf->loss_sync_cnt = - le32_to_cpu(stat_buf->loss_sync_cnt); - ret_buf->loss_sig_cnt = - le32_to_cpu(stat_buf->loss_sig_cnt); - ret_buf->prim_seq_err_cnt = - le32_to_cpu(stat_buf->prim_seq_err_cnt); - ret_buf->inval_xmit_word_cnt = - le32_to_cpu(stat_buf->inval_xmit_word_cnt); - ret_buf->inval_crc_cnt = - le32_to_cpu(stat_buf->inval_crc_cnt); - - DEBUG11(printk("%s(%ld): stat dump: fail_cnt=%d " - "loss_sync=%d loss_sig=%d seq_err=%d " - "inval_xmt_word=%d inval_crc=%d.\n", __func__, - ha->host_no, stat_buf->link_fail_cnt, - stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt, - stat_buf->prim_seq_err_cnt, - stat_buf->inval_xmit_word_cnt, - stat_buf->inval_crc_cnt)); + /* Copy over data -- firmware data is LE. */ + dwords = offsetof(struct link_statistics, unused1) / 4; + siter = diter = &stats->link_fail_cnt; + while (dwords--) + *diter++ = le32_to_cpu(*siter++); } } else { /* Failed. */ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, rval)); - rval = BIT_1; } - dma_pool_free(ha->s_dma_pool, stat_buf, stat_buf_dma); - return rval; } int -qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords, - uint16_t *status) +qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats, + dma_addr_t stats_dma) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - uint32_t *sbuf, *siter; - dma_addr_t sbuf_dma; + uint32_t *siter, *diter, dwords; DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - if (dwords > (DMA_POOL_SIZE / 4)) { - DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs " - "(max %d).\n", __func__, ha->host_no, dwords, - DMA_POOL_SIZE / 4)); - return BIT_0; - } - sbuf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &sbuf_dma); - if (sbuf == NULL) { - DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n", - __func__, ha->host_no)); - return BIT_0; - } - memset(sbuf, 0, DMA_POOL_SIZE); - mcp->mb[0] = MBC_GET_LINK_PRIV_STATS; - mcp->mb[2] = MSW(sbuf_dma); - mcp->mb[3] = LSW(sbuf_dma); - mcp->mb[6] = MSW(MSD(sbuf_dma)); - mcp->mb[7] = LSW(MSD(sbuf_dma)); - mcp->mb[8] = dwords; + mcp->mb[2] = MSW(stats_dma); + mcp->mb[3] = LSW(stats_dma); + mcp->mb[6] = MSW(MSD(stats_dma)); + mcp->mb[7] = LSW(MSD(stats_dma)); + mcp->mb[8] = sizeof(struct link_statistics) / 4; + mcp->mb[9] = ha->vp_idx; mcp->mb[10] = 0; - mcp->out_mb = MBX_10|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; mcp->tov = 30; mcp->flags = IOCTL_CMD; @@ -2170,23 +2090,20 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords, if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n", __func__, ha->host_no, mcp->mb[0])); - status[0] = mcp->mb[0]; - rval = BIT_1; + rval = QLA_FUNCTION_FAILED; } else { /* Copy over data -- firmware data is LE. */ - siter = sbuf; + dwords = sizeof(struct link_statistics) / 4; + siter = diter = &stats->link_fail_cnt; while (dwords--) - *dwbuf++ = le32_to_cpu(*siter++); + *diter++ = le32_to_cpu(*siter++); } } else { /* Failed. */ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, rval)); - rval = BIT_1; } - dma_pool_free(ha->s_dma_pool, sbuf, sbuf_dma); - return rval; } @@ -2331,6 +2248,8 @@ atarget_done: return rval; } +#if 0 + int qla2x00_system_error(scsi_qla_host_t *ha) { @@ -2360,47 +2279,7 @@ qla2x00_system_error(scsi_qla_host_t *ha) return rval; } -/** - * qla2x00_get_serdes_params() - - * @ha: HA context - * - * Returns - */ -int -qla2x00_get_serdes_params(scsi_qla_host_t *ha, uint16_t *sw_em_1g, - uint16_t *sw_em_2g, uint16_t *sw_em_4g) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - - mcp->mb[0] = MBC_SERDES_PARAMS; - mcp->mb[1] = 0; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_0; - mcp->tov = 30; - mcp->flags = 0; - rval = qla2x00_mailbox_command(ha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, - ha->host_no, rval, mcp->mb[0])); - } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); - - if (sw_em_1g) - *sw_em_1g = mcp->mb[2]; - if (sw_em_2g) - *sw_em_2g = mcp->mb[3]; - if (sw_em_4g) - *sw_em_4g = mcp->mb[4]; - } - - return rval; -} +#endif /* 0 */ /** * qla2x00_set_serdes_params() - @@ -2471,7 +2350,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha) } int -qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, +qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma, uint16_t buffers) { int rval; @@ -2484,22 +2363,18 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_TRACE_CONTROL; - mcp->mb[1] = ctrl; - mcp->out_mb = MBX_1|MBX_0; + mcp->mb[1] = TC_EFT_ENABLE; + mcp->mb[2] = LSW(eft_dma); + mcp->mb[3] = MSW(eft_dma); + mcp->mb[4] = LSW(MSD(eft_dma)); + mcp->mb[5] = MSW(MSD(eft_dma)); + mcp->mb[6] = buffers; + mcp->mb[7] = TC_AEN_DISABLE; + mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_1|MBX_0; - if (ctrl == TC_ENABLE) { - mcp->mb[2] = LSW(eft_dma); - mcp->mb[3] = MSW(eft_dma); - mcp->mb[4] = LSW(MSD(eft_dma)); - mcp->mb[5] = MSW(MSD(eft_dma)); - mcp->mb[6] = buffers; - mcp->mb[7] = 0; - mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2; - } mcp->tov = 30; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); - if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); @@ -2511,8 +2386,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, } int -qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, - uint16_t off, uint16_t count) +qla2x00_disable_eft_trace(scsi_qla_host_t *ha) { int rval; mbx_cmd_t mc; @@ -2523,24 +2397,16 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = addr; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); - mcp->mb[6] = MSW(MSD(sfp_dma)); - mcp->mb[7] = LSW(MSD(sfp_dma)); - mcp->mb[8] = count; - mcp->mb[9] = off; - mcp->mb[10] = 0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; + mcp->mb[0] = MBC_TRACE_CONTROL; + mcp->mb[1] = TC_EFT_DISABLE; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); - if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, - ha->host_no, rval, mcp->mb[0])); + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } @@ -2549,176 +2415,168 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, } int -qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, - uint16_t *port_speed, uint16_t *mb) +qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma, + uint16_t buffers, uint16_t *mb, uint32_t *dwords) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (!IS_IIDMA_CAPABLE(ha)) + if (!IS_QLA25XX(ha)) return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - mcp->mb[0] = MBC_PORT_PARAMS; - mcp->mb[1] = loop_id; - mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0; - mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; + mcp->mb[0] = MBC_TRACE_CONTROL; + mcp->mb[1] = TC_FCE_ENABLE; + mcp->mb[2] = LSW(fce_dma); + mcp->mb[3] = MSW(fce_dma); + mcp->mb[4] = LSW(MSD(fce_dma)); + mcp->mb[5] = MSW(MSD(fce_dma)); + mcp->mb[6] = buffers; + mcp->mb[7] = TC_AEN_DISABLE; + mcp->mb[8] = 0; + mcp->mb[9] = TC_FCE_DEFAULT_RX_SIZE; + mcp->mb[10] = TC_FCE_DEFAULT_TX_SIZE; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| + MBX_1|MBX_0; + mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); - - /* Return mailbox statuses. */ - if (mb != NULL) { - mb[0] = mcp->mb[0]; - mb[1] = mcp->mb[1]; - mb[3] = mcp->mb[3]; - mb[4] = mcp->mb[4]; - mb[5] = mcp->mb[5]; - } - if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, - ha->host_no, rval)); + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); - if (port_speed) - *port_speed = mcp->mb[3]; + + if (mb) + memcpy(mb, mcp->mb, 8 * sizeof(*mb)); + if (dwords) + *dwords = mcp->mb[6]; } return rval; } int -qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, - uint16_t port_speed, uint16_t *mb) +qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (!IS_IIDMA_CAPABLE(ha)) + if (!IS_FWI2_CAPABLE(ha)) return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - mcp->mb[0] = MBC_PORT_PARAMS; - mcp->mb[1] = loop_id; - mcp->mb[2] = BIT_0; - mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); - mcp->mb[4] = mcp->mb[5] = 0; - mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; + mcp->mb[0] = MBC_TRACE_CONTROL; + mcp->mb[1] = TC_FCE_DISABLE; + mcp->mb[2] = TC_FCE_DISABLE_TRACE; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| + MBX_1|MBX_0; mcp->tov = 30; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); - - /* Return mailbox statuses. */ - if (mb != NULL) { - mb[0] = mcp->mb[0]; - mb[1] = mcp->mb[1]; - mb[3] = mcp->mb[3]; - mb[4] = mcp->mb[4]; - mb[5] = mcp->mb[5]; - } - if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, - ha->host_no, rval)); + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + + if (wr) + *wr = (uint64_t) mcp->mb[5] << 48 | + (uint64_t) mcp->mb[4] << 32 | + (uint64_t) mcp->mb[3] << 16 | + (uint64_t) mcp->mb[2]; + if (rd) + *rd = (uint64_t) mcp->mb[9] << 48 | + (uint64_t) mcp->mb[8] << 32 | + (uint64_t) mcp->mb[7] << 16 | + (uint64_t) mcp->mb[6]; } return rval; } -/* - * qla24xx_get_vp_database - * Get the VP's database for all configured ports. - * - * Input: - * ha = adapter block pointer. - * size = size of initialization control block. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ int -qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size) +qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, + uint16_t off, uint16_t count) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("scsi(%ld):%s - entered.\n", - ha->host_no, __func__)); + if (!IS_FWI2_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; - mcp->mb[0] = MBC_MID_GET_VP_DATABASE; - mcp->mb[2] = MSW(ha->init_cb_dma); - mcp->mb[3] = LSW(ha->init_cb_dma); - mcp->mb[4] = 0; - mcp->mb[5] = 0; - mcp->mb[6] = MSW(MSD(ha->init_cb_dma)); - mcp->mb[7] = LSW(MSD(ha->init_cb_dma)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->buf_size = size; - mcp->flags = MBX_DMA_OUT; - mcp->tov = MBX_TOV_SECONDS; + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_READ_SFP; + mcp->mb[1] = addr; + mcp->mb[2] = MSW(sfp_dma); + mcp->mb[3] = LSW(sfp_dma); + mcp->mb[6] = MSW(MSD(sfp_dma)); + mcp->mb[7] = LSW(MSD(sfp_dma)); + mcp->mb[8] = count; + mcp->mb[9] = off; + mcp->mb[10] = 0; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { - /*EMPTY*/ - DEBUG2_3_11(printk("%s(%ld): failed=%x " - "mb0=%x.\n", - __func__, ha->host_no, rval, mcp->mb[0])); + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + ha->host_no, rval, mcp->mb[0])); } else { - /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", - __func__, ha->host_no)); + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; } int -qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id) +qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, + uint16_t port_speed, uint16_t *mb) { int rval; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + if (!IS_IIDMA_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); - mcp->mb[0] = MBC_MID_GET_VP_ENTRY; - mcp->mb[2] = MSW(ha->init_cb_dma); - mcp->mb[3] = LSW(ha->init_cb_dma); - mcp->mb[4] = 0; - mcp->mb[5] = 0; - mcp->mb[6] = MSW(MSD(ha->init_cb_dma)); - mcp->mb[7] = LSW(MSD(ha->init_cb_dma)); - mcp->mb[9] = vp_id; - mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_0; - mcp->buf_size = size; - mcp->flags = MBX_DMA_OUT; + mcp->mb[0] = MBC_PORT_PARAMS; + mcp->mb[1] = loop_id; + mcp->mb[2] = BIT_0; + mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); + mcp->mb[4] = mcp->mb[5] = 0; + mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; mcp->tov = 30; + mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); + /* Return mailbox statuses. */ + if (mb != NULL) { + mb[0] = mcp->mb[0]; + mb[1] = mcp->mb[1]; + mb[3] = mcp->mb[3]; + mb[4] = mcp->mb[4]; + mb[5] = mcp->mb[5]; + } + if (rval != QLA_SUCCESS) { - /*EMPTY*/ - DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x " - "mb0=%x.\n", - ha->host_no, rval, mcp->mb[0])); + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); } else { - /*EMPTY*/ - DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n", - ha->host_no)); + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -2873,7 +2731,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__, ha->host_no, vp_index)); - if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP) + if (vp_index == 0 || vp_index >= ha->max_npiv_vports) return QLA_PARAMETER_ERROR; vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 821ee74aadc6..cf784cdafb01 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -39,7 +39,7 @@ qla2x00_vp_stop_timer(scsi_qla_host_t *vha) } } -uint32_t +static uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *vha) { uint32_t vp_id; @@ -47,16 +47,15 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha) /* Find an empty slot and assign an vp_id */ down(&ha->vport_sem); - vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC); - if (vp_id > MAX_MULTI_ID_FABRIC) { - DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n", - vp_id)); + vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1); + if (vp_id > ha->max_npiv_vports) { + DEBUG15(printk ("vp_id %d is bigger than max-supported %d.\n", + vp_id, ha->max_npiv_vports)); up(&ha->vport_sem); return vp_id; } - set_bit(vp_id, (unsigned long *)ha->vp_idx_map); + set_bit(vp_id, ha->vp_idx_map); ha->num_vhosts++; vha->vp_idx = vp_id; list_add_tail(&vha->vp_list, &ha->vp_list); @@ -73,12 +72,12 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) down(&ha->vport_sem); vp_id = vha->vp_idx; ha->num_vhosts--; - clear_bit(vp_id, (unsigned long *)ha->vp_idx_map); + clear_bit(vp_id, ha->vp_idx_map); list_del(&vha->vp_list); up(&ha->vport_sem); } -scsi_qla_host_t * +static scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name) { scsi_qla_host_t *vha; @@ -216,11 +215,7 @@ qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb) if (ha->parent) return; - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, 1); - for (;i <= MAX_MULTI_ID_FABRIC; - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, i + 1)) { + for_each_mapped_vp_idx(ha, i) { vp_idx_matched = 0; list_for_each_entry(vha, &ha->vp_list, vp_list) { @@ -270,7 +265,7 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) qla24xx_enable_vp(vha); } -int +static int qla2x00_do_dpc_vp(scsi_qla_host_t *vha) { if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { @@ -311,11 +306,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha) clear_bit(VP_DPC_NEEDED, &ha->dpc_flags); - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, 1); - for (;i <= MAX_MULTI_ID_FABRIC; - i = find_next_bit((unsigned long *)ha->vp_idx_map, - MAX_MULTI_ID_FABRIC + 1, i + 1)) { + for_each_mapped_vp_idx(ha, i) { vp_idx_matched = 0; list_for_each_entry(vha, &ha->vp_list, vp_list) { @@ -350,15 +341,17 @@ qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport) /* Check up unique WWPN */ u64_to_wwn(fc_vport->port_name, port_name); + if (!memcmp(port_name, ha->port_name, WWN_SIZE)) + return VPCERR_BAD_WWN; vha = qla24xx_find_vhost_by_name(ha, port_name); if (vha) return VPCERR_BAD_WWN; /* Check up max-npiv-supports */ if (ha->num_vhosts > ha->max_npiv_vports) { - DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than " - "max_npv_vports %d.\n", ha->host_no, - (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports)); + DEBUG15(printk("scsi(%ld): num_vhosts %ud is bigger than " + "max_npv_vports %ud.\n", ha->host_no, + ha->num_vhosts, ha->max_npiv_vports)); return VPCERR_UNSUPPORTED; } return 0; @@ -412,8 +405,9 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) } vha->mgmt_svr_loop_id = 10 + vha->vp_idx; - init_MUTEX(&vha->mbx_cmd_sem); - init_MUTEX_LOCKED(&vha->mbx_intr_sem); + init_completion(&vha->mbx_cmd_comp); + complete(&vha->mbx_cmd_comp); + init_completion(&vha->mbx_intr_comp); INIT_LIST_HEAD(&vha->list); INIT_LIST_HEAD(&vha->fcports); @@ -450,7 +444,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) num_hosts++; down(&ha->vport_sem); - set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map); + set_bit(vha->vp_idx, ha->vp_idx_map); ha->cur_vport_count++; up(&ha->vport_sem); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8ecc0470b8f3..3954ed2d7b51 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -105,13 +105,12 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *); static int qla2xxx_eh_device_reset(struct scsi_cmnd *); static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); static int qla2xxx_eh_host_reset(struct scsi_cmnd *); -static int qla2x00_loop_reset(scsi_qla_host_t *ha); static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); static int qla2x00_change_queue_depth(struct scsi_device *, int); static int qla2x00_change_queue_type(struct scsi_device *, int); -struct scsi_host_template qla2x00_driver_template = { +static struct scsi_host_template qla2x00_driver_template = { .module = THIS_MODULE, .name = QLA2XXX_DRIVER_NAME, .queuecommand = qla2x00_queuecommand, @@ -132,7 +131,6 @@ struct scsi_host_template qla2x00_driver_template = { .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, /* @@ -164,7 +162,6 @@ struct scsi_host_template qla24xx_driver_template = { .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, @@ -179,13 +176,6 @@ struct scsi_transport_template *qla2xxx_transport_vport_template = NULL; * Timer routines */ -void qla2x00_timer(scsi_qla_host_t *); - -__inline__ void qla2x00_start_timer(scsi_qla_host_t *, - void *, unsigned long); -static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long); -__inline__ void qla2x00_stop_timer(scsi_qla_host_t *); - __inline__ void qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval) { @@ -203,7 +193,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval) mod_timer(&ha->timer, jiffies + interval * HZ); } -__inline__ void +static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *ha) { del_timer_sync(&ha->timer); @@ -214,12 +204,11 @@ static int qla2x00_do_dpc(void *data); static void qla2x00_rst_aen(scsi_qla_host_t *); -uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); -void qla2x00_mem_free(scsi_qla_host_t *ha); +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *); +static void qla2x00_mem_free(scsi_qla_host_t *ha); static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha); static void qla2x00_free_sp_pool(scsi_qla_host_t *ha); static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *); -void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *); /* -------------------------------------------------------------------------- */ @@ -1060,7 +1049,7 @@ eh_host_reset_lock: * Returns: * 0 = success */ -static int +int qla2x00_loop_reset(scsi_qla_host_t *ha) { int ret; @@ -1479,8 +1468,7 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha) static int qla2x00_iospace_config(scsi_qla_host_t *ha) { - unsigned long pio, pio_len, pio_flags; - unsigned long mmio, mmio_len, mmio_flags; + resource_size_t pio; if (pci_request_selected_regions(ha->pdev, ha->bars, QLA2XXX_DRIVER_NAME)) { @@ -1495,10 +1483,8 @@ qla2x00_iospace_config(scsi_qla_host_t *ha) /* We only need PIO for Flash operations on ISP2312 v2 chips. */ pio = pci_resource_start(ha->pdev, 0); - pio_len = pci_resource_len(ha->pdev, 0); - pio_flags = pci_resource_flags(ha->pdev, 0); - if (pio_flags & IORESOURCE_IO) { - if (pio_len < MIN_IOBASE_LEN) { + if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) { + if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { qla_printk(KERN_WARNING, ha, "Invalid PCI I/O region size (%s)...\n", pci_name(ha->pdev)); @@ -1511,28 +1497,23 @@ qla2x00_iospace_config(scsi_qla_host_t *ha) pio = 0; } ha->pio_address = pio; - ha->pio_length = pio_len; skip_pio: /* Use MMIO operations for all accesses. */ - mmio = pci_resource_start(ha->pdev, 1); - mmio_len = pci_resource_len(ha->pdev, 1); - mmio_flags = pci_resource_flags(ha->pdev, 1); - - if (!(mmio_flags & IORESOURCE_MEM)) { + if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) { qla_printk(KERN_ERR, ha, - "region #0 not an MMIO resource (%s), aborting\n", + "region #1 not an MMIO resource (%s), aborting\n", pci_name(ha->pdev)); goto iospace_error_exit; } - if (mmio_len < MIN_IOBASE_LEN) { + if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) { qla_printk(KERN_ERR, ha, "Invalid PCI mem region size (%s), aborting\n", pci_name(ha->pdev)); goto iospace_error_exit; } - ha->iobase = ioremap(mmio, MIN_IOBASE_LEN); + ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN); if (!ha->iobase) { qla_printk(KERN_ERR, ha, "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev)); @@ -1701,9 +1682,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* load the F/W, read paramaters, and init the H/W */ ha->instance = num_hosts; - init_MUTEX(&ha->mbx_cmd_sem); init_MUTEX(&ha->vport_sem); - init_MUTEX_LOCKED(&ha->mbx_intr_sem); + init_completion(&ha->mbx_cmd_comp); + complete(&ha->mbx_cmd_comp); + init_completion(&ha->mbx_intr_comp); INIT_LIST_HEAD(&ha->list); INIT_LIST_HEAD(&ha->fcports); @@ -1807,6 +1789,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) qla2x00_init_host_attr(ha); + qla2x00_dfs_setup(ha); + qla_printk(KERN_INFO, ha, "\n" " QLogic Fibre Channel HBA Driver: %s\n" " QLogic %s - %s\n" @@ -1838,6 +1822,8 @@ qla2x00_remove_one(struct pci_dev *pdev) ha = pci_get_drvdata(pdev); + qla2x00_dfs_remove(ha); + qla2x00_free_sysfs_attr(ha); fc_remove_host(ha->host); @@ -1871,8 +1857,11 @@ qla2x00_free_device(scsi_qla_host_t *ha) kthread_stop(t); } + if (ha->flags.fce_enabled) + qla2x00_disable_fce_trace(ha, NULL, NULL); + if (ha->eft) - qla2x00_trace_control(ha, TC_DISABLE, 0, 0); + qla2x00_disable_eft_trace(ha); ha->flags.online = 0; @@ -2016,7 +2005,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer) * 0 = success. * 1 = failure. */ -uint8_t +static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *ha) { char name[16]; @@ -2213,7 +2202,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) * Input: * ha = adapter block pointer. */ -void +static void qla2x00_mem_free(scsi_qla_host_t *ha) { struct list_head *fcpl, *fcptemp; @@ -2228,6 +2217,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha) /* free sp pool */ qla2x00_free_sp_pool(ha); + if (ha->fce) + dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, + ha->fce_dma); + if (ha->fw_dump) { if (ha->eft) dma_free_coherent(&ha->pdev->dev, @@ -2748,23 +2741,6 @@ qla2x00_timer(scsi_qla_host_t *ha) qla2x00_restart_timer(ha, WATCH_INTERVAL); } -/* XXX(hch): crude hack to emulate a down_timeout() */ -int -qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout) -{ - const unsigned int step = 100; /* msecs */ - unsigned int iterations = jiffies_to_msecs(timeout)/100; - - do { - if (!down_trylock(sema)) - return 0; - if (msleep_interruptible(step)) - break; - } while (--iterations > 0); - - return -ETIMEDOUT; -} - /* Firmware interface routines. */ #define FW_BLOBS 6 diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index ad2fa01bd233..b68fb73613ed 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -22,7 +22,7 @@ static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t); * qla2x00_lock_nvram_access() - * @ha: HA context */ -void +static void qla2x00_lock_nvram_access(scsi_qla_host_t *ha) { uint16_t data; @@ -55,7 +55,7 @@ qla2x00_lock_nvram_access(scsi_qla_host_t *ha) * qla2x00_unlock_nvram_access() - * @ha: HA context */ -void +static void qla2x00_unlock_nvram_access(scsi_qla_host_t *ha) { struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -74,7 +74,7 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha) * * Returns the word read from nvram @addr. */ -uint16_t +static uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr) { uint16_t data; @@ -93,7 +93,7 @@ qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr) * @addr: Address in NVRAM to write * @data: word to program */ -void +static void qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) { int count; @@ -550,7 +550,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, int ret; uint32_t liter, miter; uint32_t sec_mask, rest_addr, conf_addr; - uint32_t fdata, findex ; + uint32_t fdata, findex, cnt; uint8_t man_id, flash_id; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; dma_addr_t optrom_dma; @@ -690,8 +690,14 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, 0xff0000) | ((fdata >> 16) & 0xff)); } - /* Enable flash write-protection. */ + /* Enable flash write-protection and wait for completion. */ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); + for (cnt = 300; cnt && + qla24xx_read_flash_dword(ha, + flash_conf_to_access_addr(0x005)) & BIT_0; + cnt--) { + udelay(10); + } /* Disable flash write. */ WRT_REG_DWORD(®->ctrl_status, diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index ae6f7a2fb19f..2c2f6b4697c7 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k5" +#define QLA2XXX_VERSION "8.02.00-k7" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index d692c713416a..cbe0a17ced5f 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -5,6 +5,7 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ +#include <scsi/iscsi_if.h> #include "ql4_def.h" #include "ql4_glbl.h" #include "ql4_dbg.h" @@ -1305,7 +1306,8 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, atomic_set(&ddb_entry->relogin_timer, 0); clear_bit(DF_RELOGIN, &ddb_entry->flags); clear_bit(DF_NO_RELOGIN, &ddb_entry->flags); - iscsi_if_create_session_done(ddb_entry->conn); + iscsi_session_event(ddb_entry->sess, + ISCSI_KEVENT_CREATE_SESSION); /* * Change the lun state to READY in case the lun TIMEOUT before * the device came back. diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index 4a154beb0d39..0f029d0d7315 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -123,15 +123,14 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, break; /* Copy Sense Data into sense buffer. */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt); if (sensebytecnt == 0) break; memcpy(cmd->sense_buffer, sts_entry->senseData, - min(sensebytecnt, - (uint16_t) sizeof(cmd->sense_buffer))); + min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE)); DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " "ASC/ASCQ = %02x/%02x\n", ha->host_no, @@ -208,8 +207,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, break; /* Copy Sense Data into sense buffer. */ - memset(cmd->sense_buffer, 0, - sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt); @@ -217,8 +215,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, break; memcpy(cmd->sense_buffer, sts_entry->senseData, - min(sensebytecnt, - (uint16_t) sizeof(cmd->sense_buffer))); + min_t(uint16_t, sensebytecnt, SCSI_SENSE_BUFFERSIZE)); DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, " "ASC/ASCQ = %02x/%02x\n", ha->host_no, diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 89460d27c689..2e2b9fedffcc 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -94,7 +94,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, @@ -173,18 +172,6 @@ static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag) printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); } -static ssize_t format_addr(char *buf, const unsigned char *addr, int len) -{ - int i; - char *cp = buf; - - for (i = 0; i < len; i++) - cp += sprintf(cp, "%02x%c", addr[i], - i == (len - 1) ? '\n' : ':'); - return cp - buf; -} - - static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf) { @@ -193,7 +180,7 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost, switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: - len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN); + len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); break; case ISCSI_HOST_PARAM_IPADDRESS: len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0], @@ -298,8 +285,7 @@ void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry) return; if (ddb_entry->conn) { - iscsi_if_destroy_session_done(ddb_entry->conn); - iscsi_destroy_conn(ddb_entry->conn); + atomic_set(&ddb_entry->state, DDB_STATE_DEAD); iscsi_remove_session(ddb_entry->sess); } iscsi_free_session(ddb_entry->sess); @@ -309,6 +295,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) { int err; + ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); if (err) { DEBUG2(printk(KERN_ERR "Could not add session.\n")); @@ -321,9 +308,6 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } - - ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; - iscsi_if_create_session_done(ddb_entry->conn); return 0; } diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 1769f965eedf..1e874f1fb5c6 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -197,7 +197,6 @@ static struct scsi_host_template qlogicfas_driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = 1, .use_clustering = DISABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static __init int qlogicfas_init(void) diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 7a2e7986b038..65455ab1f3b9 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -871,11 +871,12 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, struct scatterlist *sg, *s; int i, n; - if (Cmnd->use_sg) { + if (scsi_bufflen(Cmnd)) { int sg_count; - sg = (struct scatterlist *) Cmnd->request_buffer; - sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction); + sg = scsi_sglist(Cmnd); + sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd), + Cmnd->sc_data_direction); ds = cmd->dataseg; cmd->segment_cnt = sg_count; @@ -914,16 +915,6 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, } sg_count -= n; } - } else if (Cmnd->request_bufflen) { - Cmnd->SCp.ptr = (char *)(unsigned long) - sbus_map_single(qpti->sdev, - Cmnd->request_buffer, - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - - cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr); - cmd->dataseg[0].d_count = Cmnd->request_bufflen; - cmd->segment_cnt = 1; } else { cmd->dataseg[0].d_base = 0; cmd->dataseg[0].d_count = 0; @@ -1151,7 +1142,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) if (sts->state_flags & SF_GOT_SENSE) memcpy(Cmnd->sense_buffer, sts->req_sense_data, - sizeof(Cmnd->sense_buffer)); + SCSI_SENSE_BUFFERSIZE); if (sts->hdr.entry_type == ENTRY_STATUS) Cmnd->result = @@ -1159,17 +1150,11 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) else Cmnd->result = DID_ERROR << 16; - if (Cmnd->use_sg) { + if (scsi_bufflen(Cmnd)) sbus_unmap_sg(qpti->sdev, - (struct scatterlist *)Cmnd->request_buffer, - Cmnd->use_sg, + scsi_sglist(Cmnd), scsi_sg_count(Cmnd), Cmnd->sc_data_direction); - } else if (Cmnd->request_bufflen) { - sbus_unmap_single(qpti->sdev, - (__u32)((unsigned long)Cmnd->SCp.ptr), - Cmnd->request_bufflen, - Cmnd->sc_data_direction); - } + qpti->cmd_count[Cmnd->device->id]--; sbus_writew(out_ptr, qpti->qregs + MBOX5); Cmnd->host_scribble = (unsigned char *) done_queue; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 0fb1709ce5e3..b35d19472caa 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -122,6 +122,11 @@ static const char *const scsi_device_types[] = { "Automation/Drive ", }; +/** + * scsi_device_type - Return 17 char string indicating device type. + * @type: type number to look up + */ + const char * scsi_device_type(unsigned type) { if (type == 0x1e) @@ -136,32 +141,45 @@ const char * scsi_device_type(unsigned type) EXPORT_SYMBOL(scsi_device_type); struct scsi_host_cmd_pool { - struct kmem_cache *slab; - unsigned int users; - char *name; - unsigned int slab_flags; - gfp_t gfp_mask; + struct kmem_cache *cmd_slab; + struct kmem_cache *sense_slab; + unsigned int users; + char *cmd_name; + char *sense_name; + unsigned int slab_flags; + gfp_t gfp_mask; }; static struct scsi_host_cmd_pool scsi_cmd_pool = { - .name = "scsi_cmd_cache", + .cmd_name = "scsi_cmd_cache", + .sense_name = "scsi_sense_cache", .slab_flags = SLAB_HWCACHE_ALIGN, }; static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { - .name = "scsi_cmd_cache(DMA)", + .cmd_name = "scsi_cmd_cache(DMA)", + .sense_name = "scsi_sense_cache(DMA)", .slab_flags = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA, .gfp_mask = __GFP_DMA, }; static DEFINE_MUTEX(host_cmd_pool_mutex); +/** + * __scsi_get_command - Allocate a struct scsi_cmnd + * @shost: host to transmit command + * @gfp_mask: allocation mask + * + * Description: allocate a struct scsi_cmd from host's slab, recycling from the + * host's free_list if necessary. + */ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) { struct scsi_cmnd *cmd; + unsigned char *buf; - cmd = kmem_cache_alloc(shost->cmd_pool->slab, - gfp_mask | shost->cmd_pool->gfp_mask); + cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab, + gfp_mask | shost->cmd_pool->gfp_mask); if (unlikely(!cmd)) { unsigned long flags; @@ -173,19 +191,32 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) list_del_init(&cmd->list); } spin_unlock_irqrestore(&shost->free_list_lock, flags); + + if (cmd) { + buf = cmd->sense_buffer; + memset(cmd, 0, sizeof(*cmd)); + cmd->sense_buffer = buf; + } + } else { + buf = kmem_cache_alloc(shost->cmd_pool->sense_slab, + gfp_mask | shost->cmd_pool->gfp_mask); + if (likely(buf)) { + memset(cmd, 0, sizeof(*cmd)); + cmd->sense_buffer = buf; + } else { + kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); + cmd = NULL; + } } return cmd; } EXPORT_SYMBOL_GPL(__scsi_get_command); -/* - * Function: scsi_get_command() - * - * Purpose: Allocate and setup a scsi command block - * - * Arguments: dev - parent scsi device - * gfp_mask- allocator flags +/** + * scsi_get_command - Allocate and setup a scsi command block + * @dev: parent scsi device + * @gfp_mask: allocator flags * * Returns: The allocated scsi command structure. */ @@ -202,7 +233,6 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) if (likely(cmd != NULL)) { unsigned long flags; - memset(cmd, 0, sizeof(*cmd)); cmd->device = dev; init_timer(&cmd->eh_timeout); INIT_LIST_HEAD(&cmd->list); @@ -217,6 +247,12 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) } EXPORT_SYMBOL(scsi_get_command); +/** + * __scsi_put_command - Free a struct scsi_cmnd + * @shost: dev->host + * @cmd: Command to free + * @dev: parent scsi device + */ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, struct device *dev) { @@ -230,19 +266,19 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, } spin_unlock_irqrestore(&shost->free_list_lock, flags); - if (likely(cmd != NULL)) - kmem_cache_free(shost->cmd_pool->slab, cmd); + if (likely(cmd != NULL)) { + kmem_cache_free(shost->cmd_pool->sense_slab, + cmd->sense_buffer); + kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); + } put_device(dev); } EXPORT_SYMBOL(__scsi_put_command); -/* - * Function: scsi_put_command() - * - * Purpose: Free a scsi command block - * - * Arguments: cmd - command block to free +/** + * scsi_put_command - Free a scsi command block + * @cmd: command block to free * * Returns: Nothing. * @@ -263,12 +299,13 @@ void scsi_put_command(struct scsi_cmnd *cmd) } EXPORT_SYMBOL(scsi_put_command); -/* - * Function: scsi_setup_command_freelist() - * - * Purpose: Setup the command freelist for a scsi host. +/** + * scsi_setup_command_freelist - Setup the command freelist for a scsi host. + * @shost: host to allocate the freelist for. * - * Arguments: shost - host to allocate the freelist for. + * Description: The command freelist protects against system-wide out of memory + * deadlock by preallocating one SCSI command structure for each host, so the + * system can always write to a swap file on a device associated with that host. * * Returns: Nothing. */ @@ -282,16 +319,24 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) /* * Select a command slab for this host and create it if not - * yet existant. + * yet existent. */ mutex_lock(&host_cmd_pool_mutex); pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool); if (!pool->users) { - pool->slab = kmem_cache_create(pool->name, - sizeof(struct scsi_cmnd), 0, - pool->slab_flags, NULL); - if (!pool->slab) + pool->cmd_slab = kmem_cache_create(pool->cmd_name, + sizeof(struct scsi_cmnd), 0, + pool->slab_flags, NULL); + if (!pool->cmd_slab) + goto fail; + + pool->sense_slab = kmem_cache_create(pool->sense_name, + SCSI_SENSE_BUFFERSIZE, 0, + pool->slab_flags, NULL); + if (!pool->sense_slab) { + kmem_cache_destroy(pool->cmd_slab); goto fail; + } } pool->users++; @@ -301,29 +346,36 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) /* * Get one backup command for this host. */ - cmd = kmem_cache_alloc(shost->cmd_pool->slab, - GFP_KERNEL | shost->cmd_pool->gfp_mask); + cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab, + GFP_KERNEL | shost->cmd_pool->gfp_mask); if (!cmd) goto fail2; - list_add(&cmd->list, &shost->free_list); + + cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab, + GFP_KERNEL | + shost->cmd_pool->gfp_mask); + if (!cmd->sense_buffer) + goto fail2; + + list_add(&cmd->list, &shost->free_list); return 0; fail2: - if (!--pool->users) - kmem_cache_destroy(pool->slab); - return -ENOMEM; + if (cmd) + kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); + mutex_lock(&host_cmd_pool_mutex); + if (!--pool->users) { + kmem_cache_destroy(pool->cmd_slab); + kmem_cache_destroy(pool->sense_slab); + } fail: mutex_unlock(&host_cmd_pool_mutex); return -ENOMEM; - } -/* - * Function: scsi_destroy_command_freelist() - * - * Purpose: Release the command freelist for a scsi host. - * - * Arguments: shost - host that's freelist is going to be destroyed +/** + * scsi_destroy_command_freelist - Release the command freelist for a scsi host. + * @shost: host whose freelist is going to be destroyed */ void scsi_destroy_command_freelist(struct Scsi_Host *shost) { @@ -332,12 +384,16 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); list_del_init(&cmd->list); - kmem_cache_free(shost->cmd_pool->slab, cmd); + kmem_cache_free(shost->cmd_pool->sense_slab, + cmd->sense_buffer); + kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); } mutex_lock(&host_cmd_pool_mutex); - if (!--shost->cmd_pool->users) - kmem_cache_destroy(shost->cmd_pool->slab); + if (!--shost->cmd_pool->users) { + kmem_cache_destroy(shost->cmd_pool->cmd_slab); + kmem_cache_destroy(shost->cmd_pool->sense_slab); + } mutex_unlock(&host_cmd_pool_mutex); } @@ -441,8 +497,12 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) } #endif -/* - * Assign a serial number to the request for error recovery +/** + * scsi_cmd_get_serial - Assign a serial number to a command + * @host: the scsi host + * @cmd: command to assign serial number to + * + * Description: a serial number identifies a request for error recovery * and debugging purposes. Protected by the Host_Lock of host. */ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd) @@ -452,14 +512,12 @@ static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd cmd->serial_number = host->cmd_serial_number++; } -/* - * Function: scsi_dispatch_command - * - * Purpose: Dispatch a command to the low-level driver. - * - * Arguments: cmd - command block we are dispatching. +/** + * scsi_dispatch_command - Dispatch a command to the low-level driver. + * @cmd: command block we are dispatching. * - * Notes: + * Return: nonzero return request was rejected and device's queue needs to be + * plugged. */ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) { @@ -585,7 +643,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) /** * scsi_req_abort_cmd -- Request command recovery for the specified command - * cmd: pointer to the SCSI command of interest + * @cmd: pointer to the SCSI command of interest * * This function requests that SCSI Core start recovery for the * command by deleting the timer and adding the command to the eh @@ -606,9 +664,9 @@ EXPORT_SYMBOL(scsi_req_abort_cmd); * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives * ownership back to SCSI Core -- i.e. the LLDD has finished with it. * - * This function is the mid-level's (SCSI Core) interrupt routine, which - * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues - * the command to the done queue for further processing. + * Description: This function is the mid-level's (SCSI Core) interrupt routine, + * which regains ownership of the SCSI command (de facto) from a LLDD, and + * enqueues the command to the done queue for further processing. * * This is the producer of the done queue who enqueues at the tail. * @@ -617,7 +675,7 @@ EXPORT_SYMBOL(scsi_req_abort_cmd); static void scsi_done(struct scsi_cmnd *cmd) { /* - * We don't have to worry about this one timing out any more. + * We don't have to worry about this one timing out anymore. * If we are unable to remove the timer, then the command * has already timed out. In which case, we have no choice but to * let the timeout function run, as we have no idea where in fact @@ -660,10 +718,11 @@ static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) return *(struct scsi_driver **)cmd->request->rq_disk->private_data; } -/* - * Function: scsi_finish_command +/** + * scsi_finish_command - cleanup and pass command back to upper layer + * @cmd: the command * - * Purpose: Pass command off to upper layer for finishing of I/O + * Description: Pass command off to upper layer for finishing of I/O * request, waking processes that are waiting on results, * etc. */ @@ -698,7 +757,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "Notifying upper driver of completion " "(result %x)\n", cmd->result)); - good_bytes = cmd->request_bufflen; + good_bytes = scsi_bufflen(cmd); if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { drv = scsi_cmd_to_driver(cmd); if (drv->done) @@ -708,18 +767,14 @@ void scsi_finish_command(struct scsi_cmnd *cmd) } EXPORT_SYMBOL(scsi_finish_command); -/* - * Function: scsi_adjust_queue_depth() - * - * Purpose: Allow low level drivers to tell us to change the queue depth - * on a specific SCSI device - * - * Arguments: sdev - SCSI Device in question - * tagged - Do we use tagged queueing (non-0) or do we treat - * this device as an untagged device (0) - * tags - Number of tags allowed if tagged queueing enabled, - * or number of commands the low level driver can - * queue up in non-tagged mode (as per cmd_per_lun). +/** + * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth + * @sdev: SCSI Device in question + * @tagged: Do we use tagged queueing (non-0) or do we treat + * this device as an untagged device (0) + * @tags: Number of tags allowed if tagged queueing enabled, + * or number of commands the low level driver can + * queue up in non-tagged mode (as per cmd_per_lun). * * Returns: Nothing * @@ -742,8 +797,8 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - /* Check to see if the queue is managed by the block layer - * if it is, and we fail to adjust the depth, exit */ + /* Check to see if the queue is managed by the block layer. + * If it is, and we fail to adjust the depth, exit. */ if (blk_queue_tagged(sdev->request_queue) && blk_queue_resize_tags(sdev->request_queue, tags) != 0) goto out; @@ -772,20 +827,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) } EXPORT_SYMBOL(scsi_adjust_queue_depth); -/* - * Function: scsi_track_queue_full() +/** + * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth + * @sdev: SCSI Device in question + * @depth: Current number of outstanding SCSI commands on this device, + * not counting the one returned as QUEUE_FULL. * - * Purpose: This function will track successive QUEUE_FULL events on a + * Description: This function will track successive QUEUE_FULL events on a * specific SCSI device to determine if and when there is a * need to adjust the queue depth on the device. * - * Arguments: sdev - SCSI Device in question - * depth - Current number of outstanding SCSI commands on - * this device, not counting the one returned as - * QUEUE_FULL. - * - * Returns: 0 - No change needed - * >0 - Adjust queue depth to this new depth + * Returns: 0 - No change needed, >0 - Adjust queue depth to this new depth, * -1 - Drop back to untagged operation using host->cmd_per_lun * as the untagged command depth * @@ -824,10 +876,10 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth) EXPORT_SYMBOL(scsi_track_queue_full); /** - * scsi_device_get - get an addition reference to a scsi_device + * scsi_device_get - get an additional reference to a scsi_device * @sdev: device to get a reference to * - * Gets a reference to the scsi_device and increments the use count + * Description: Gets a reference to the scsi_device and increments the use count * of the underlying LLDD module. You must hold host_lock of the * parent Scsi_Host or already have a reference when calling this. */ @@ -849,8 +901,8 @@ EXPORT_SYMBOL(scsi_device_get); * scsi_device_put - release a reference to a scsi_device * @sdev: device to release a reference on. * - * Release a reference to the scsi_device and decrements the use count - * of the underlying LLDD module. The device is freed once the last + * Description: Release a reference to the scsi_device and decrements the use + * count of the underlying LLDD module. The device is freed once the last * user vanishes. */ void scsi_device_put(struct scsi_device *sdev) @@ -867,7 +919,7 @@ void scsi_device_put(struct scsi_device *sdev) } EXPORT_SYMBOL(scsi_device_put); -/* helper for shost_for_each_device, thus not documented */ +/* helper for shost_for_each_device, see that for documentation */ struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, struct scsi_device *prev) { @@ -895,6 +947,8 @@ EXPORT_SYMBOL(__scsi_iterate_devices); /** * starget_for_each_device - helper to walk all devices of a target * @starget: target whose devices we want to iterate over. + * @data: Opaque passed to each function call. + * @fn: Function to call on each device * * This traverses over each device of @starget. The devices have * a reference that must be released by scsi_host_put when breaking @@ -946,13 +1000,13 @@ EXPORT_SYMBOL(__starget_for_each_device); * @starget: SCSI target pointer * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @lun for a give - * @starget. The returned scsi_device does not have an additional + * Description: Looks up the scsi_device with the specified @lun for a given + * @starget. The returned scsi_device does not have an additional * reference. You must hold the host's host_lock over this call and * any access to the returned scsi_device. * - * Note: The only reason why drivers would want to use this is because - * they're need to access the device list in irq context. Otherwise you + * Note: The only reason why drivers should use this is because + * they need to access the device list in irq context. Otherwise you * really want to use scsi_device_lookup_by_target instead. **/ struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget, @@ -974,9 +1028,9 @@ EXPORT_SYMBOL(__scsi_device_lookup_by_target); * @starget: SCSI target pointer * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @channel, @id, @lun for a - * give host. The returned scsi_device has an additional reference that - * needs to be release with scsi_host_put once you're done with it. + * Description: Looks up the scsi_device with the specified @channel, @id, @lun + * for a given host. The returned scsi_device has an additional reference that + * needs to be released with scsi_device_put once you're done with it. **/ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget, uint lun) @@ -996,19 +1050,19 @@ struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget, EXPORT_SYMBOL(scsi_device_lookup_by_target); /** - * scsi_device_lookup - find a device given the host (UNLOCKED) + * __scsi_device_lookup - find a device given the host (UNLOCKED) * @shost: SCSI host pointer * @channel: SCSI channel (zero if only one channel) - * @pun: SCSI target number (physical unit number) + * @id: SCSI target number (physical unit number) * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @channel, @id, @lun for a - * give host. The returned scsi_device does not have an additional reference. - * You must hold the host's host_lock over this call and any access to the - * returned scsi_device. + * Description: Looks up the scsi_device with the specified @channel, @id, @lun + * for a given host. The returned scsi_device does not have an additional + * reference. You must hold the host's host_lock over this call and any access + * to the returned scsi_device. * * Note: The only reason why drivers would want to use this is because - * they're need to access the device list in irq context. Otherwise you + * they need to access the device list in irq context. Otherwise you * really want to use scsi_device_lookup instead. **/ struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost, @@ -1033,9 +1087,9 @@ EXPORT_SYMBOL(__scsi_device_lookup); * @id: SCSI target number (physical unit number) * @lun: SCSI Logical Unit Number * - * Looks up the scsi_device with the specified @channel, @id, @lun for a - * give host. The returned scsi_device has an additional reference that - * needs to be release with scsi_host_put once you're done with it. + * Description: Looks up the scsi_device with the specified @channel, @id, @lun + * for a given host. The returned scsi_device has an additional reference that + * needs to be released with scsi_device_put once you're done with it. **/ struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost, uint channel, uint id, uint lun) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 46cae5a212de..1541c174937a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -280,6 +280,8 @@ static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, unsigned int num, struct sdebug_dev_info * devip); static int resp_report_luns(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); +static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip); static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, int arr_len); static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, @@ -311,12 +313,48 @@ static void sdebug_max_tgts_luns(void); static struct device pseudo_primary; static struct bus_type pseudo_lld_bus; +static void get_data_transfer_info(unsigned char *cmd, + unsigned long long *lba, unsigned int *num) +{ + int i; + + switch (*cmd) { + case WRITE_16: + case READ_16: + for (*lba = 0, i = 0; i < 8; ++i) { + if (i > 0) + *lba <<= 8; + *lba += cmd[2 + i]; + } + *num = cmd[13] + (cmd[12] << 8) + + (cmd[11] << 16) + (cmd[10] << 24); + break; + case WRITE_12: + case READ_12: + *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); + break; + case WRITE_10: + case READ_10: + case XDWRITEREAD_10: + *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + *num = cmd[8] + (cmd[7] << 8); + break; + case WRITE_6: + case READ_6: + *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + *num = (0 == cmd[4]) ? 256 : cmd[4]; + break; + default: + break; + } +} static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int len, k, j; + int len, k; unsigned int num; unsigned long long lba; int errsts = 0; @@ -329,7 +367,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) if (done == NULL) return 0; /* assume mid level reprocessing command */ - SCpnt->resid = 0; + scsi_set_resid(SCpnt, 0); if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, len = SCpnt->cmd_len; k < len; ++k) @@ -452,28 +490,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) break; if (scsi_debug_fake_rw) break; - if ((*cmd) == READ_16) { - for (lba = 0, j = 0; j < 8; ++j) { - if (j > 0) - lba <<= 8; - lba += cmd[2 + j]; - } - num = cmd[13] + (cmd[12] << 8) + - (cmd[11] << 16) + (cmd[10] << 24); - } else if ((*cmd) == READ_12) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); - } else if ((*cmd) == READ_10) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[8] + (cmd[7] << 8); - } else { /* READ (6) */ - lba = cmd[3] + (cmd[2] << 8) + - ((cmd[1] & 0x1f) << 16); - num = (0 == cmd[4]) ? 256 : cmd[4]; - } + get_data_transfer_info(cmd, &lba, &num); errsts = resp_read(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, @@ -500,28 +517,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) break; if (scsi_debug_fake_rw) break; - if ((*cmd) == WRITE_16) { - for (lba = 0, j = 0; j < 8; ++j) { - if (j > 0) - lba <<= 8; - lba += cmd[2 + j]; - } - num = cmd[13] + (cmd[12] << 8) + - (cmd[11] << 16) + (cmd[10] << 24); - } else if ((*cmd) == WRITE_12) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); - } else if ((*cmd) == WRITE_10) { - lba = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - num = cmd[8] + (cmd[7] << 8); - } else { /* WRITE (6) */ - lba = cmd[3] + (cmd[2] << 8) + - ((cmd[1] & 0x1f) << 16); - num = (0 == cmd[4]) ? 256 : cmd[4]; - } + get_data_transfer_info(cmd, &lba, &num); errsts = resp_write(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, @@ -549,6 +545,28 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) case WRITE_BUFFER: errsts = check_readiness(SCpnt, 1, devip); break; + case XDWRITEREAD_10: + if (!scsi_bidi_cmnd(SCpnt)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + errsts = check_condition_result; + break; + } + + errsts = check_readiness(SCpnt, 0, devip); + if (errsts) + break; + if (scsi_debug_fake_rw) + break; + get_data_transfer_info(cmd, &lba, &num); + errsts = resp_read(SCpnt, lba, num, devip); + if (errsts) + break; + errsts = resp_write(SCpnt, lba, num, devip); + if (errsts) + break; + errsts = resp_xdwriteread(SCpnt, lba, num, devip); + break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " @@ -601,28 +619,18 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, int k, req_len, act_len, len, active; void * kaddr; void * kaddr_off; - struct scatterlist * sg; + struct scatterlist *sg; + struct scsi_data_buffer *sdb = scsi_in(scp); - if (0 == scp->request_bufflen) + if (!sdb->length) return 0; - if (NULL == scp->request_buffer) + if (!sdb->table.sgl) return (DID_ERROR << 16); - if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || - (scp->sc_data_direction == DMA_FROM_DEVICE))) + if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) return (DID_ERROR << 16); - if (0 == scp->use_sg) { - req_len = scp->request_bufflen; - act_len = (req_len < arr_len) ? req_len : arr_len; - memcpy(scp->request_buffer, arr, act_len); - if (scp->resid) - scp->resid -= act_len; - else - scp->resid = req_len - act_len; - return 0; - } active = 1; req_len = act_len = 0; - scsi_for_each_sg(scp, sg, scp->use_sg, k) { + for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) { if (active) { kaddr = (unsigned char *) kmap_atomic(sg_page(sg), KM_USER0); @@ -640,10 +648,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, } req_len += sg->length; } - if (scp->resid) - scp->resid -= act_len; + if (sdb->resid) + sdb->resid -= act_len; else - scp->resid = req_len - act_len; + sdb->resid = req_len - act_len; return 0; } @@ -656,22 +664,14 @@ static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, void * kaddr_off; struct scatterlist * sg; - if (0 == scp->request_bufflen) + if (0 == scsi_bufflen(scp)) return 0; - if (NULL == scp->request_buffer) + if (NULL == scsi_sglist(scp)) return -1; - if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || - (scp->sc_data_direction == DMA_TO_DEVICE))) + if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) return -1; - if (0 == scp->use_sg) { - req_len = scp->request_bufflen; - len = (req_len < max_arr_len) ? req_len : max_arr_len; - memcpy(arr, scp->request_buffer, len); - return len; - } - sg = scsi_sglist(scp); req_len = fin = 0; - for (k = 0; k < scp->use_sg; ++k, sg = sg_next(sg)) { + scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) { kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); if (NULL == kaddr) return -1; @@ -1973,6 +1973,50 @@ static int resp_report_luns(struct scsi_cmnd * scp, min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } +static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip) +{ + int i, j, ret = -1; + unsigned char *kaddr, *buf; + unsigned int offset; + struct scatterlist *sg; + struct scsi_data_buffer *sdb = scsi_in(scp); + + /* better not to use temporary buffer. */ + buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); + if (!buf) + return ret; + + offset = 0; + scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) { + kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); + if (!kaddr) + goto out; + + memcpy(buf + offset, kaddr + sg->offset, sg->length); + offset += sg->length; + kunmap_atomic(kaddr, KM_USER0); + } + + offset = 0; + for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { + kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); + if (!kaddr) + goto out; + + for (j = 0; j < sg->length; j++) + *(kaddr + sg->offset + j) ^= *(buf + offset + j); + + offset += sg->length; + kunmap_atomic(kaddr, KM_USER0); + } + ret = 0; +out: + kfree(buf); + + return ret; +} + /* When timer goes off this function is called. */ static void timer_intr_handler(unsigned long indx) { @@ -2006,6 +2050,7 @@ static int scsi_debug_slave_alloc(struct scsi_device * sdp) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); + set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags); return 0; } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 348cc5a6e3cd..b8de041bc0ae 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -276,11 +276,12 @@ static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length, } /** - * scsi_dev_info_list_add: add one dev_info list entry. + * scsi_dev_info_list_add - add one dev_info list entry. + * @compatible: if true, null terminate short strings. Otherwise space pad. * @vendor: vendor string * @model: model (product) string * @strflags: integer string - * @flag: if strflags NULL, use this flag value + * @flags: if strflags NULL, use this flag value * * Description: * Create and add one dev_info entry for @vendor, @model, @strflags or @@ -322,8 +323,7 @@ static int scsi_dev_info_list_add(int compatible, char *vendor, char *model, } /** - * scsi_dev_info_list_add_str: parse dev_list and add to the - * scsi_dev_info_list. + * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. * @dev_list: string of device flags to add * * Description: @@ -374,15 +374,15 @@ static int scsi_dev_info_list_add_str(char *dev_list) } /** - * get_device_flags - get device specific flags from the dynamic device - * list. Called during scan time. + * get_device_flags - get device specific flags from the dynamic device list. + * @sdev: &scsi_device to get flags for * @vendor: vendor name * @model: model name * * Description: * Search the scsi_dev_info_list for an entry matching @vendor and * @model, if found, return the matching flags value, else return - * the host or global default settings. + * the host or global default settings. Called during scan time. **/ int scsi_get_device_flags(struct scsi_device *sdev, const unsigned char *vendor, @@ -483,13 +483,11 @@ stop_output: } /* - * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via - * /proc. + * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc. * - * Use: echo "vendor:model:flag" > /proc/scsi/device_info - * - * To add a black/white list entry for vendor and model with an integer - * value of flag to the scsi device info list. + * Description: Adds a black/white list entry for vendor and model with an + * integer value of flag to the scsi device info list. + * To use, echo "vendor:model:flag" > /proc/scsi/device_info */ static int proc_scsi_devinfo_write(struct file *file, const char __user *buf, unsigned long length, void *data) @@ -532,8 +530,7 @@ MODULE_PARM_DESC(default_dev_flags, "scsi default device flag integer value"); /** - * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove - * the scsi_dev_info_list. + * scsi_dev_info_list_delete - called from scsi.c:exit_scsi to remove the scsi_dev_info_list. **/ void scsi_exit_devinfo(void) { @@ -552,13 +549,12 @@ void scsi_exit_devinfo(void) } /** - * scsi_dev_list_init: set up the dynamic device list. - * @dev_list: string of device flags to add + * scsi_init_devinfo - set up the dynamic device list. * * Description: - * Add command line @dev_list entries, then add + * Add command line entries from scsi_dev_flags, then add * scsi_static_device_list entries to the scsi device info list. - **/ + */ int __init scsi_init_devinfo(void) { #ifdef CONFIG_SCSI_PROC_FS diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ebaca4ca4a13..045a0868fc7b 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -62,7 +62,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost) * @shost: SCSI host to invoke error handling on. * * Schedule SCSI EH without scmd. - **/ + */ void scsi_schedule_eh(struct Scsi_Host *shost) { unsigned long flags; @@ -86,7 +86,7 @@ EXPORT_SYMBOL_GPL(scsi_schedule_eh); * * Return value: * 0 on failure. - **/ + */ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) { struct Scsi_Host *shost = scmd->device->host; @@ -121,7 +121,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) * This should be turned into an inline function. Each scsi command * has its own timer, and as it is added to the queue, we set up the * timer. When the command completes, we cancel the timer. - **/ + */ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, void (*complete)(struct scsi_cmnd *)) { @@ -155,7 +155,7 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, * Return value: * 1 if we were able to detach the timer. 0 if we blew it, and the * timer function has already started to run. - **/ + */ int scsi_delete_timer(struct scsi_cmnd *scmd) { int rtn; @@ -181,7 +181,7 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) * only in that the normal completion handling might run, but if the * normal completion function determines that the timer has already * fired, then it mustn't do anything. - **/ + */ void scsi_times_out(struct scsi_cmnd *scmd) { enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *); @@ -224,7 +224,7 @@ void scsi_times_out(struct scsi_cmnd *scmd) * * Return value: * 0 when dev was taken offline by error recovery. 1 OK to proceed. - **/ + */ int scsi_block_when_processing_errors(struct scsi_device *sdev) { int online; @@ -245,7 +245,7 @@ EXPORT_SYMBOL(scsi_block_when_processing_errors); * scsi_eh_prt_fail_stats - Log info on failures. * @shost: scsi host being recovered. * @work_q: Queue of scsi cmds to process. - **/ + */ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, struct list_head *work_q) { @@ -295,7 +295,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, * Notes: * When a deferred error is detected the current command has * not been executed and needs retrying. - **/ + */ static int scsi_check_sense(struct scsi_cmnd *scmd) { struct scsi_sense_hdr sshdr; @@ -398,7 +398,7 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) * queued during error recovery. the main difference here is that we * don't allow for the possibility of retries here, and we are a lot * more restrictive about what we consider acceptable. - **/ + */ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) { /* @@ -452,7 +452,7 @@ static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) /** * scsi_eh_done - Completion function for error handling. * @scmd: Cmd that is done. - **/ + */ static void scsi_eh_done(struct scsi_cmnd *scmd) { struct completion *eh_action; @@ -469,7 +469,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) /** * scsi_try_host_reset - ask host adapter to reset itself * @scmd: SCSI cmd to send hsot reset. - **/ + */ static int scsi_try_host_reset(struct scsi_cmnd *scmd) { unsigned long flags; @@ -498,7 +498,7 @@ static int scsi_try_host_reset(struct scsi_cmnd *scmd) /** * scsi_try_bus_reset - ask host to perform a bus reset * @scmd: SCSI cmd to send bus reset. - **/ + */ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) { unsigned long flags; @@ -533,7 +533,7 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) * unreliable for a given host, then the host itself needs to put a * timer on it, and set the host back to a consistent state prior to * returning. - **/ + */ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) { int rtn; @@ -568,7 +568,7 @@ static int __scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) * author of the low-level driver wishes this operation to be timed, * they can provide this facility themselves. helper functions in * scsi_error.c can be supplied to make this easier to do. - **/ + */ static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd) { /* @@ -601,7 +601,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) * sent must be one that does not transfer any data. If @sense_bytes != 0 * @cmnd is ignored and this functions sets up a REQUEST_SENSE command * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer. - **/ + */ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, unsigned char *cmnd, int cmnd_size, unsigned sense_bytes) { @@ -617,29 +617,27 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, ses->cmd_len = scmd->cmd_len; memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd)); ses->data_direction = scmd->sc_data_direction; - ses->bufflen = scmd->request_bufflen; - ses->buffer = scmd->request_buffer; - ses->use_sg = scmd->use_sg; - ses->resid = scmd->resid; + ses->sdb = scmd->sdb; + ses->next_rq = scmd->request->next_rq; ses->result = scmd->result; + memset(&scmd->sdb, 0, sizeof(scmd->sdb)); + scmd->request->next_rq = NULL; + if (sense_bytes) { - scmd->request_bufflen = min_t(unsigned, - sizeof(scmd->sense_buffer), sense_bytes); + scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE, + sense_bytes); sg_init_one(&ses->sense_sgl, scmd->sense_buffer, - scmd->request_bufflen); - scmd->request_buffer = &ses->sense_sgl; + scmd->sdb.length); + scmd->sdb.table.sgl = &ses->sense_sgl; scmd->sc_data_direction = DMA_FROM_DEVICE; - scmd->use_sg = 1; + scmd->sdb.table.nents = 1; memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); scmd->cmnd[0] = REQUEST_SENSE; - scmd->cmnd[4] = scmd->request_bufflen; + scmd->cmnd[4] = scmd->sdb.length; scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); } else { - scmd->request_buffer = NULL; - scmd->request_bufflen = 0; scmd->sc_data_direction = DMA_NONE; - scmd->use_sg = 0; if (cmnd) { memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); memcpy(scmd->cmnd, cmnd, cmnd_size); @@ -657,7 +655,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, * Zero the sense buffer. The scsi spec mandates that any * untransferred sense data should be interpreted as being zero. */ - memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); + memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); } EXPORT_SYMBOL(scsi_eh_prep_cmnd); @@ -667,7 +665,7 @@ EXPORT_SYMBOL(scsi_eh_prep_cmnd); * @ses: saved information from a coresponding call to scsi_prep_eh_cmnd * * Undo any damage done by above scsi_prep_eh_cmnd(). - **/ + */ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) { /* @@ -676,10 +674,8 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) scmd->cmd_len = ses->cmd_len; memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd)); scmd->sc_data_direction = ses->data_direction; - scmd->request_bufflen = ses->bufflen; - scmd->request_buffer = ses->buffer; - scmd->use_sg = ses->use_sg; - scmd->resid = ses->resid; + scmd->sdb = ses->sdb; + scmd->request->next_rq = ses->next_rq; scmd->result = ses->result; } EXPORT_SYMBOL(scsi_eh_restore_cmnd); @@ -697,7 +693,7 @@ EXPORT_SYMBOL(scsi_eh_restore_cmnd); * * Return value: * SUCCESS or FAILED or NEEDS_RETRY - **/ + */ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, int cmnd_size, int timeout, unsigned sense_bytes) { @@ -765,7 +761,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, * Some hosts automatically obtain this information, others require * that we obtain it on our own. This function will *not* return until * the command either times out, or it completes. - **/ + */ static int scsi_request_sense(struct scsi_cmnd *scmd) { return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0); @@ -779,10 +775,10 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) * Notes: * We don't want to use the normal command completion while we are are * still handling errors - it may cause other commands to be queued, - * and that would disturb what we are doing. thus we really want to + * and that would disturb what we are doing. Thus we really want to * keep a list of pending commands for final completion, and once we * are ready to leave error handling we handle completion for real. - **/ + */ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) { scmd->device->host->host_failed--; @@ -794,7 +790,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); /** * scsi_eh_get_sense - Get device sense data. * @work_q: Queue of commands to process. - * @done_q: Queue of proccessed commands.. + * @done_q: Queue of processed commands. * * Description: * See if we need to request sense information. if so, then get it @@ -802,7 +798,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); * * Notes: * This has the unfortunate side effect that if a shost adapter does - * not automatically request sense information, that we end up shutting + * not automatically request sense information, we end up shutting * it down before we request it. * * All drivers should request sense information internally these days, @@ -810,7 +806,7 @@ EXPORT_SYMBOL(scsi_eh_finish_cmd); * * XXX: Long term this code should go away, but that needs an audit of * all LLDDs first. - **/ + */ int scsi_eh_get_sense(struct list_head *work_q, struct list_head *done_q) { @@ -858,11 +854,11 @@ EXPORT_SYMBOL_GPL(scsi_eh_get_sense); /** * scsi_eh_tur - Send TUR to device. - * @scmd: Scsi cmd to send TUR + * @scmd: &scsi_cmnd to send TUR * * Return value: * 0 - Device is ready. 1 - Device NOT ready. - **/ + */ static int scsi_eh_tur(struct scsi_cmnd *scmd) { static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; @@ -887,17 +883,17 @@ retry_tur: } /** - * scsi_eh_abort_cmds - abort canceled commands. - * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. + * scsi_eh_abort_cmds - abort pending commands. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. * * Decription: * Try and see whether or not it makes sense to try and abort the - * running command. this only works out to be the case if we have one - * command that has timed out. if the command simply failed, it makes + * running command. This only works out to be the case if we have one + * command that has timed out. If the command simply failed, it makes * no sense to try and abort the command, since as far as the shost * adapter is concerned, it isn't running. - **/ + */ static int scsi_eh_abort_cmds(struct list_head *work_q, struct list_head *done_q) { @@ -931,11 +927,11 @@ static int scsi_eh_abort_cmds(struct list_head *work_q, /** * scsi_eh_try_stu - Send START_UNIT to device. - * @scmd: Scsi cmd to send START_UNIT + * @scmd: &scsi_cmnd to send START_UNIT * * Return value: * 0 - Device is ready. 1 - Device NOT ready. - **/ + */ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) { static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; @@ -956,13 +952,14 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) /** * scsi_eh_stu - send START_UNIT if needed - * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. + * @shost: &scsi host being recovered. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. * * Notes: * If commands are failing due to not ready, initializing command required, * try revalidating the device, which will end up sending a start unit. - **/ + */ static int scsi_eh_stu(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1008,14 +1005,15 @@ static int scsi_eh_stu(struct Scsi_Host *shost, /** * scsi_eh_bus_device_reset - send bdr if needed * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. * * Notes: - * Try a bus device reset. still, look to see whether we have multiple + * Try a bus device reset. Still, look to see whether we have multiple * devices that are jammed or not - if we have multiple devices, it * makes no sense to try bus_device_reset - we really would need to try * a bus_reset instead. - **/ + */ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1063,9 +1061,10 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, /** * scsi_eh_bus_reset - send a bus reset - * @shost: scsi host being recovered. - * @eh_done_q: list_head for processed commands. - **/ + * @shost: &scsi host being recovered. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. + */ static int scsi_eh_bus_reset(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1122,7 +1121,7 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost, * scsi_eh_host_reset - send a host reset * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. - **/ + */ static int scsi_eh_host_reset(struct list_head *work_q, struct list_head *done_q) { @@ -1157,8 +1156,7 @@ static int scsi_eh_host_reset(struct list_head *work_q, * scsi_eh_offline_sdevs - offline scsi devices that fail to recover * @work_q: list_head for processed commands. * @done_q: list_head for processed commands. - * - **/ + */ static void scsi_eh_offline_sdevs(struct list_head *work_q, struct list_head *done_q) { @@ -1191,7 +1189,7 @@ static void scsi_eh_offline_sdevs(struct list_head *work_q, * is woken. In cases where the error code indicates an error that * doesn't require the error handler read (i.e. we don't need to * abort/reset), this function should return SUCCESS. - **/ + */ int scsi_decide_disposition(struct scsi_cmnd *scmd) { int rtn; @@ -1372,7 +1370,7 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd) * * If scsi_allocate_request() fails for what ever reason, we * completely forget to lock the door. - **/ + */ static void scsi_eh_lock_door(struct scsi_device *sdev) { unsigned char cmnd[MAX_COMMAND_SIZE]; @@ -1396,7 +1394,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) * Notes: * When we entered the error handler, we blocked all further i/o to * this device. we need to 'reverse' this process. - **/ + */ static void scsi_restart_operations(struct Scsi_Host *shost) { struct scsi_device *sdev; @@ -1440,9 +1438,9 @@ static void scsi_restart_operations(struct Scsi_Host *shost) /** * scsi_eh_ready_devs - check device ready state and recover if not. * @shost: host to be recovered. - * @eh_done_q: list_head for processed commands. - * - **/ + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. + */ void scsi_eh_ready_devs(struct Scsi_Host *shost, struct list_head *work_q, struct list_head *done_q) @@ -1458,8 +1456,7 @@ EXPORT_SYMBOL_GPL(scsi_eh_ready_devs); /** * scsi_eh_flush_done_q - finish processed commands or retry them. * @done_q: list_head of processed commands. - * - **/ + */ void scsi_eh_flush_done_q(struct list_head *done_q) { struct scsi_cmnd *scmd, *next; @@ -1513,7 +1510,7 @@ EXPORT_SYMBOL(scsi_eh_flush_done_q); * scsi_finish_cmd() called for it. we do all of the retry stuff * here, so when we restart the host after we return it should have an * empty queue. - **/ + */ static void scsi_unjam_host(struct Scsi_Host *shost) { unsigned long flags; @@ -1540,7 +1537,7 @@ static void scsi_unjam_host(struct Scsi_Host *shost) * Notes: * This is the main error handling loop. This is run as a kernel thread * for every SCSI host and handles all error handling activity. - **/ + */ int scsi_error_handler(void *data) { struct Scsi_Host *shost = data; @@ -1699,8 +1696,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag) memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd)); scmd->scsi_done = scsi_reset_provider_done_command; - scmd->request_buffer = NULL; - scmd->request_bufflen = 0; + memset(&scmd->sdb, 0, sizeof(scmd->sdb)); scmd->cmd_len = 0; @@ -1769,7 +1765,7 @@ EXPORT_SYMBOL(scsi_reset_provider); * * Return value: * 1 if valid sense data information found, else 0; - **/ + */ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr) { @@ -1819,14 +1815,12 @@ int scsi_command_normalize_sense(struct scsi_cmnd *cmd, struct scsi_sense_hdr *sshdr) { return scsi_normalize_sense(cmd->sense_buffer, - sizeof(cmd->sense_buffer), sshdr); + SCSI_SENSE_BUFFERSIZE, sshdr); } EXPORT_SYMBOL(scsi_command_normalize_sense); /** - * scsi_sense_desc_find - search for a given descriptor type in - * descriptor sense data format. - * + * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. * @sense_buffer: byte array of descriptor format sense data * @sb_len: number of valid bytes in sense_buffer * @desc_type: value of descriptor type to find @@ -1837,7 +1831,7 @@ EXPORT_SYMBOL(scsi_command_normalize_sense); * * Return value: * pointer to start of (first) descriptor if found else NULL - **/ + */ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, int desc_type) { @@ -1865,9 +1859,7 @@ const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, EXPORT_SYMBOL(scsi_sense_desc_find); /** - * scsi_get_sense_info_fld - attempts to get information field from - * sense data (either fixed or descriptor format) - * + * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format) * @sense_buffer: byte array of sense data * @sb_len: number of valid bytes in sense_buffer * @info_out: pointer to 64 integer where 8 or 4 byte information @@ -1875,7 +1867,7 @@ EXPORT_SYMBOL(scsi_sense_desc_find); * * Return value: * 1 if information field found, 0 if not found. - **/ + */ int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, u64 * info_out) { diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 32293f451669..28b19ef26309 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -174,10 +174,15 @@ static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) } -/* - * the scsi_ioctl() function differs from most ioctls in that it does - * not take a major/minor number as the dev field. Rather, it takes - * a pointer to a scsi_devices[] element, a structure. +/** + * scsi_ioctl - Dispatch ioctl to scsi device + * @sdev: scsi device receiving ioctl + * @cmd: which ioctl is it + * @arg: data associated with ioctl + * + * Description: The scsi_ioctl() function differs from most ioctls in that it + * does not take a major/minor number as the dev field. Rather, it takes + * a pointer to a &struct scsi_device. */ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) { @@ -239,7 +244,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT, - NORMAL_RETRIES); + NORMAL_RETRIES, NULL); case SCSI_IOCTL_START_UNIT: scsi_cmd[0] = START_STOP; scsi_cmd[1] = 0; @@ -264,9 +269,12 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) } EXPORT_SYMBOL(scsi_ioctl); -/* - * the scsi_nonblock_ioctl() function is designed for ioctls which may - * be executed even if the device is in recovery. +/** + * scsi_nonblock_ioctl() - Handle SG_SCSI_RESET + * @sdev: scsi device receiving ioctl + * @cmd: Must be SC_SCSI_RESET + * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST} + * @filp: either NULL or a &struct file which must have the O_NONBLOCK flag. */ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, void __user *arg, struct file *filp) @@ -276,7 +284,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, /* The first set of iocts may be executed even if we're doing * error processing, as long as the device was opened * non-blocking */ - if (filp && filp->f_flags & O_NONBLOCK) { + if (filp && (filp->f_flags & O_NONBLOCK)) { if (scsi_host_in_recovery(sdev->host)) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index a9ac5b1b1667..b12fb310e399 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -8,6 +8,7 @@ */ #include <linux/bio.h> +#include <linux/bitops.h> #include <linux/blkdev.h> #include <linux/completion.h> #include <linux/kernel.h> @@ -34,13 +35,6 @@ #define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools) #define SG_MEMPOOL_SIZE 2 -/* - * The maximum number of SG segments that we will put inside a scatterlist - * (unless chaining is used). Should ideally fit inside a single page, to - * avoid a higher order allocation. - */ -#define SCSI_MAX_SG_SEGMENTS 128 - struct scsi_host_sg_pool { size_t size; char *name; @@ -48,22 +42,31 @@ struct scsi_host_sg_pool { mempool_t *pool; }; -#define SP(x) { x, "sgpool-" #x } +#define SP(x) { x, "sgpool-" __stringify(x) } +#if (SCSI_MAX_SG_SEGMENTS < 32) +#error SCSI_MAX_SG_SEGMENTS is too small (must be 32 or greater) +#endif static struct scsi_host_sg_pool scsi_sg_pools[] = { SP(8), SP(16), -#if (SCSI_MAX_SG_SEGMENTS > 16) - SP(32), #if (SCSI_MAX_SG_SEGMENTS > 32) - SP(64), + SP(32), #if (SCSI_MAX_SG_SEGMENTS > 64) + SP(64), +#if (SCSI_MAX_SG_SEGMENTS > 128) SP(128), +#if (SCSI_MAX_SG_SEGMENTS > 256) +#error SCSI_MAX_SG_SEGMENTS is too large (256 MAX) +#endif #endif #endif #endif + SP(SCSI_MAX_SG_SEGMENTS) }; #undef SP +static struct kmem_cache *scsi_bidi_sdb_cache; + static void scsi_run_queue(struct request_queue *q); /* @@ -175,7 +178,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) * * returns the req->errors value which is the scsi_cmnd result * field. - **/ + */ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, unsigned char *sense, int timeout, int retries, int flags) @@ -274,7 +277,7 @@ static void scsi_bi_endio(struct bio *bio, int error) /** * scsi_req_map_sg - map a scatterlist into a request * @rq: request to fill - * @sg: scatterlist + * @sgl: scatterlist * @nsegs: number of elements * @bufflen: len of buffer * @gfp: memory allocation flags @@ -365,14 +368,16 @@ free_bios: * @sdev: scsi device * @cmd: scsi command * @cmd_len: length of scsi cdb - * @data_direction: data direction + * @data_direction: DMA_TO_DEVICE, DMA_FROM_DEVICE, or DMA_NONE * @buffer: data buffer (this can be a kernel buffer or scatterlist) * @bufflen: len of buffer * @use_sg: if buffer is a scatterlist this is the number of elements * @timeout: request timeout in seconds * @retries: number of times to retry request - * @flags: or into request flags - **/ + * @privdata: data passed to done() + * @done: callback function when done + * @gfp: memory allocation flags + */ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd, int cmd_len, int data_direction, void *buffer, unsigned bufflen, int use_sg, int timeout, int retries, void *privdata, @@ -438,8 +443,8 @@ EXPORT_SYMBOL_GPL(scsi_execute_async); static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) { cmd->serial_number = 0; - cmd->resid = 0; - memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer); + scsi_set_resid(cmd, 0); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); if (cmd->cmd_len == 0) cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); } @@ -524,7 +529,7 @@ static void scsi_run_queue(struct request_queue *q) struct Scsi_Host *shost = sdev->host; unsigned long flags; - if (sdev->single_lun) + if (scsi_target(sdev)->single_lun) scsi_single_lun_run(sdev); spin_lock_irqsave(shost->host_lock, flags); @@ -632,7 +637,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost) * of upper level post-processing and scsi_io_completion). * * Arguments: cmd - command that is complete. - * uptodate - 1 if I/O indicates success, <= 0 for I/O error. + * error - 0 if I/O indicates success, < 0 for I/O error. * bytes - number of bytes of completed I/O * requeue - indicates whether we should requeue leftovers. * @@ -647,26 +652,25 @@ void scsi_run_host_queues(struct Scsi_Host *shost) * at some point during this call. * Notes: If cmd was requeued, upon return it will be a stale pointer. */ -static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, +static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, int bytes, int requeue) { struct request_queue *q = cmd->device->request_queue; struct request *req = cmd->request; - unsigned long flags; /* * If there are blocks left over at the end, set up the command * to queue the remainder of them. */ - if (end_that_request_chunk(req, uptodate, bytes)) { + if (blk_end_request(req, error, bytes)) { int leftover = (req->hard_nr_sectors << 9); if (blk_pc_request(req)) leftover = req->data_len; /* kill remainder if no retrys */ - if (!uptodate && blk_noretry_request(req)) - end_that_request_chunk(req, 0, leftover); + if (error && blk_noretry_request(req)) + blk_end_request(req, error, leftover); else { if (requeue) { /* @@ -681,14 +685,6 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, } } - add_disk_randomness(req->rq_disk); - - spin_lock_irqsave(q->queue_lock, flags); - if (blk_rq_tagged(req)) - blk_queue_end_tag(q, req); - end_that_request_last(req, uptodate); - spin_unlock_irqrestore(q->queue_lock, flags); - /* * This will goose the queue request function at the end, so we don't * need to worry about launching another command. @@ -697,182 +693,57 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate, return NULL; } -/* - * Like SCSI_MAX_SG_SEGMENTS, but for archs that have sg chaining. This limit - * is totally arbitrary, a setting of 2048 will get you at least 8mb ios. - */ -#define SCSI_MAX_SG_CHAIN_SEGMENTS 2048 - static inline unsigned int scsi_sgtable_index(unsigned short nents) { unsigned int index; - switch (nents) { - case 1 ... 8: + BUG_ON(nents > SCSI_MAX_SG_SEGMENTS); + + if (nents <= 8) index = 0; - break; - case 9 ... 16: - index = 1; - break; -#if (SCSI_MAX_SG_SEGMENTS > 16) - case 17 ... 32: - index = 2; - break; -#if (SCSI_MAX_SG_SEGMENTS > 32) - case 33 ... 64: - index = 3; - break; -#if (SCSI_MAX_SG_SEGMENTS > 64) - case 65 ... 128: - index = 4; - break; -#endif -#endif -#endif - default: - printk(KERN_ERR "scsi: bad segment count=%d\n", nents); - BUG(); - } + else + index = get_count_order(nents) - 3; return index; } -struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, gfp_t gfp_mask) +static void scsi_sg_free(struct scatterlist *sgl, unsigned int nents) { struct scsi_host_sg_pool *sgp; - struct scatterlist *sgl, *prev, *ret; - unsigned int index; - int this, left; - - BUG_ON(!cmd->use_sg); - - left = cmd->use_sg; - ret = prev = NULL; - do { - this = left; - if (this > SCSI_MAX_SG_SEGMENTS) { - this = SCSI_MAX_SG_SEGMENTS - 1; - index = SG_MEMPOOL_NR - 1; - } else - index = scsi_sgtable_index(this); - - left -= this; - sgp = scsi_sg_pools + index; + sgp = scsi_sg_pools + scsi_sgtable_index(nents); + mempool_free(sgl, sgp->pool); +} - sgl = mempool_alloc(sgp->pool, gfp_mask); - if (unlikely(!sgl)) - goto enomem; +static struct scatterlist *scsi_sg_alloc(unsigned int nents, gfp_t gfp_mask) +{ + struct scsi_host_sg_pool *sgp; - sg_init_table(sgl, sgp->size); + sgp = scsi_sg_pools + scsi_sgtable_index(nents); + return mempool_alloc(sgp->pool, gfp_mask); +} - /* - * first loop through, set initial index and return value - */ - if (!ret) - ret = sgl; +static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, + gfp_t gfp_mask) +{ + int ret; - /* - * chain previous sglist, if any. we know the previous - * sglist must be the biggest one, or we would not have - * ended up doing another loop. - */ - if (prev) - sg_chain(prev, SCSI_MAX_SG_SEGMENTS, sgl); + BUG_ON(!nents); - /* - * if we have nothing left, mark the last segment as - * end-of-list - */ - if (!left) - sg_mark_end(&sgl[this - 1]); - - /* - * don't allow subsequent mempool allocs to sleep, it would - * violate the mempool principle. - */ - gfp_mask &= ~__GFP_WAIT; - gfp_mask |= __GFP_HIGH; - prev = sgl; - } while (left); + ret = __sg_alloc_table(&sdb->table, nents, SCSI_MAX_SG_SEGMENTS, + gfp_mask, scsi_sg_alloc); + if (unlikely(ret)) + __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, + scsi_sg_free); - /* - * ->use_sg may get modified after dma mapping has potentially - * shrunk the number of segments, so keep a copy of it for free. - */ - cmd->__use_sg = cmd->use_sg; return ret; -enomem: - if (ret) { - /* - * Free entries chained off ret. Since we were trying to - * allocate another sglist, we know that all entries are of - * the max size. - */ - sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1; - prev = ret; - ret = &ret[SCSI_MAX_SG_SEGMENTS - 1]; - - while ((sgl = sg_chain_ptr(ret)) != NULL) { - ret = &sgl[SCSI_MAX_SG_SEGMENTS - 1]; - mempool_free(sgl, sgp->pool); - } - - mempool_free(prev, sgp->pool); - } - return NULL; } -EXPORT_SYMBOL(scsi_alloc_sgtable); - -void scsi_free_sgtable(struct scsi_cmnd *cmd) +static void scsi_free_sgtable(struct scsi_data_buffer *sdb) { - struct scatterlist *sgl = cmd->request_buffer; - struct scsi_host_sg_pool *sgp; - - /* - * if this is the biggest size sglist, check if we have - * chained parts we need to free - */ - if (cmd->__use_sg > SCSI_MAX_SG_SEGMENTS) { - unsigned short this, left; - struct scatterlist *next; - unsigned int index; - - left = cmd->__use_sg - (SCSI_MAX_SG_SEGMENTS - 1); - next = sg_chain_ptr(&sgl[SCSI_MAX_SG_SEGMENTS - 1]); - while (left && next) { - sgl = next; - this = left; - if (this > SCSI_MAX_SG_SEGMENTS) { - this = SCSI_MAX_SG_SEGMENTS - 1; - index = SG_MEMPOOL_NR - 1; - } else - index = scsi_sgtable_index(this); - - left -= this; - - sgp = scsi_sg_pools + index; - - if (left) - next = sg_chain_ptr(&sgl[sgp->size - 1]); - - mempool_free(sgl, sgp->pool); - } - - /* - * Restore original, will be freed below - */ - sgl = cmd->request_buffer; - sgp = scsi_sg_pools + SG_MEMPOOL_NR - 1; - } else - sgp = scsi_sg_pools + scsi_sgtable_index(cmd->__use_sg); - - mempool_free(sgl, sgp->pool); + __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free); } -EXPORT_SYMBOL(scsi_free_sgtable); - /* * Function: scsi_release_buffers() * @@ -890,17 +761,49 @@ EXPORT_SYMBOL(scsi_free_sgtable); * the scatter-gather table, and potentially any bounce * buffers. */ -static void scsi_release_buffers(struct scsi_cmnd *cmd) +void scsi_release_buffers(struct scsi_cmnd *cmd) +{ + if (cmd->sdb.table.nents) + scsi_free_sgtable(&cmd->sdb); + + memset(&cmd->sdb, 0, sizeof(cmd->sdb)); + + if (scsi_bidi_cmnd(cmd)) { + struct scsi_data_buffer *bidi_sdb = + cmd->request->next_rq->special; + scsi_free_sgtable(bidi_sdb); + kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb); + cmd->request->next_rq->special = NULL; + } +} +EXPORT_SYMBOL(scsi_release_buffers); + +/* + * Bidi commands Must be complete as a whole, both sides at once. + * If part of the bytes were written and lld returned + * scsi_in()->resid and/or scsi_out()->resid this information will be left + * in req->data_len and req->next_rq->data_len. The upper-layer driver can + * decide what to do with this information. + */ +void scsi_end_bidi_request(struct scsi_cmnd *cmd) { - if (cmd->use_sg) - scsi_free_sgtable(cmd); + struct request *req = cmd->request; + unsigned int dlen = req->data_len; + unsigned int next_dlen = req->next_rq->data_len; + + req->data_len = scsi_out(cmd)->resid; + req->next_rq->data_len = scsi_in(cmd)->resid; + + /* The req and req->next_rq have not been completed */ + BUG_ON(blk_end_bidi_request(req, 0, dlen, next_dlen)); + + scsi_release_buffers(cmd); /* - * Zero these out. They now point to freed memory, and it is - * dangerous to hang onto the pointers. + * This will goose the queue request function at the end, so we don't + * need to worry about launching another command. */ - cmd->request_buffer = NULL; - cmd->request_bufflen = 0; + scsi_next_command(cmd); } /* @@ -934,7 +837,7 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; - int this_count = cmd->request_bufflen; + int this_count = scsi_bufflen(cmd); struct request_queue *q = cmd->device->request_queue; struct request *req = cmd->request; int clear_errors = 1; @@ -942,8 +845,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) int sense_valid = 0; int sense_deferred = 0; - scsi_release_buffers(cmd); - if (result) { sense_valid = scsi_command_normalize_sense(cmd, &sshdr); if (sense_valid) @@ -966,9 +867,17 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) req->sense_len = len; } } - req->data_len = cmd->resid; + if (scsi_bidi_cmnd(cmd)) { + /* will also release_buffers */ + scsi_end_bidi_request(cmd); + return; + } + req->data_len = scsi_get_resid(cmd); } + BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ + scsi_release_buffers(cmd); + /* * Next deal with any sectors which we were able to correctly * handle. @@ -976,7 +885,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " "%d bytes done.\n", req->nr_sectors, good_bytes)); - SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); if (clear_errors) req->errors = 0; @@ -985,7 +893,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * are leftovers and there is some kind of error * (result != 0), retry the rest. */ - if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL) + if (scsi_end_request(cmd, 0, good_bytes, result == 0) == NULL) return; /* good_bytes = 0, or (inclusive) there were leftovers and @@ -999,7 +907,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * and quietly refuse further access. */ cmd->device->changed = 1; - scsi_end_request(cmd, 0, this_count, 1); + scsi_end_request(cmd, -EIO, this_count, 1); return; } else { /* Must have been a power glitch, or a @@ -1031,7 +939,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_requeue_command(q, cmd); return; } else { - scsi_end_request(cmd, 0, this_count, 1); + scsi_end_request(cmd, -EIO, this_count, 1); return; } break; @@ -1059,7 +967,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) "Device not ready", &sshdr); - scsi_end_request(cmd, 0, this_count, 1); + scsi_end_request(cmd, -EIO, this_count, 1); return; case VOLUME_OVERFLOW: if (!(req->cmd_flags & REQ_QUIET)) { @@ -1069,7 +977,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_print_sense("", cmd); } /* See SSC3rXX or current. */ - scsi_end_request(cmd, 0, this_count, 1); + scsi_end_request(cmd, -EIO, this_count, 1); return; default: break; @@ -1090,64 +998,82 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) scsi_print_sense("", cmd); } } - scsi_end_request(cmd, 0, this_count, !result); + scsi_end_request(cmd, -EIO, this_count, !result); } -/* - * Function: scsi_init_io() - * - * Purpose: SCSI I/O initialize function. - * - * Arguments: cmd - Command descriptor we wish to initialize - * - * Returns: 0 on success - * BLKPREP_DEFER if the failure is retryable - * BLKPREP_KILL if the failure is fatal - */ -static int scsi_init_io(struct scsi_cmnd *cmd) +static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, + gfp_t gfp_mask) { - struct request *req = cmd->request; - int count; - - /* - * We used to not use scatter-gather for single segment request, - * but now we do (it makes highmem I/O easier to support without - * kmapping pages) - */ - cmd->use_sg = req->nr_phys_segments; + int count; /* * If sg table allocation fails, requeue request later. */ - cmd->request_buffer = scsi_alloc_sgtable(cmd, GFP_ATOMIC); - if (unlikely(!cmd->request_buffer)) { - scsi_unprep_request(req); + if (unlikely(scsi_alloc_sgtable(sdb, req->nr_phys_segments, + gfp_mask))) { return BLKPREP_DEFER; } req->buffer = NULL; if (blk_pc_request(req)) - cmd->request_bufflen = req->data_len; + sdb->length = req->data_len; else - cmd->request_bufflen = req->nr_sectors << 9; + sdb->length = req->nr_sectors << 9; /* * Next, walk the list, and fill in the addresses and sizes of * each segment. */ - count = blk_rq_map_sg(req->q, req, cmd->request_buffer); - if (likely(count <= cmd->use_sg)) { - cmd->use_sg = count; - return BLKPREP_OK; + count = blk_rq_map_sg(req->q, req, sdb->table.sgl); + BUG_ON(count > sdb->table.nents); + sdb->table.nents = count; + return BLKPREP_OK; +} + +/* + * Function: scsi_init_io() + * + * Purpose: SCSI I/O initialize function. + * + * Arguments: cmd - Command descriptor we wish to initialize + * + * Returns: 0 on success + * BLKPREP_DEFER if the failure is retryable + * BLKPREP_KILL if the failure is fatal + */ +int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) +{ + int error = scsi_init_sgtable(cmd->request, &cmd->sdb, gfp_mask); + if (error) + goto err_exit; + + if (blk_bidi_rq(cmd->request)) { + struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( + scsi_bidi_sdb_cache, GFP_ATOMIC); + if (!bidi_sdb) { + error = BLKPREP_DEFER; + goto err_exit; + } + + cmd->request->next_rq->special = bidi_sdb; + error = scsi_init_sgtable(cmd->request->next_rq, bidi_sdb, + GFP_ATOMIC); + if (error) + goto err_exit; } - printk(KERN_ERR "Incorrect number of segments after building list\n"); - printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg); - printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, - req->current_nr_sectors); + return BLKPREP_OK ; + +err_exit: + scsi_release_buffers(cmd); + if (error == BLKPREP_KILL) + scsi_put_command(cmd); + else /* BLKPREP_DEFER */ + scsi_unprep_request(cmd->request); - return BLKPREP_KILL; + return error; } +EXPORT_SYMBOL(scsi_init_io); static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, struct request *req) @@ -1193,16 +1119,14 @@ int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) BUG_ON(!req->nr_phys_segments); - ret = scsi_init_io(cmd); + ret = scsi_init_io(cmd, GFP_ATOMIC); if (unlikely(ret)) return ret; } else { BUG_ON(req->data_len); BUG_ON(req->data); - cmd->request_bufflen = 0; - cmd->request_buffer = NULL; - cmd->use_sg = 0; + memset(&cmd->sdb, 0, sizeof(cmd->sdb)); req->buffer = NULL; } @@ -1244,7 +1168,7 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) if (unlikely(!cmd)) return BLKPREP_DEFER; - return scsi_init_io(cmd); + return scsi_init_io(cmd, GFP_ATOMIC); } EXPORT_SYMBOL(scsi_setup_fs_cmnd); @@ -1557,7 +1481,7 @@ static void scsi_request_fn(struct request_queue *q) if (!scsi_host_queue_ready(q, shost, sdev)) goto not_ready; - if (sdev->single_lun) { + if (scsi_target(sdev)->single_lun) { if (scsi_target(sdev)->starget_sdev_user && scsi_target(sdev)->starget_sdev_user != sdev) goto not_ready; @@ -1654,20 +1578,7 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, * this limit is imposed by hardware restrictions */ blk_queue_max_hw_segments(q, shost->sg_tablesize); - - /* - * In the future, sg chaining support will be mandatory and this - * ifdef can then go away. Right now we don't have all archs - * converted, so better keep it safe. - */ -#ifdef ARCH_HAS_SG_CHAIN - if (shost->use_sg_chaining) - blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS); - else - blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS); -#else - blk_queue_max_phys_segments(q, SCSI_MAX_SG_SEGMENTS); -#endif + blk_queue_max_phys_segments(q, SCSI_MAX_SG_CHAIN_SEGMENTS); blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); @@ -1675,6 +1586,14 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, if (!shost->use_clustering) clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + + /* + * set a reasonable default alignment on word boundaries: the + * host and device may alter it using + * blk_queue_update_dma_alignment() later. + */ + blk_queue_dma_alignment(q, 0x03); + return q; } EXPORT_SYMBOL(__scsi_alloc_queue); @@ -1758,6 +1677,14 @@ int __init scsi_init_queue(void) return -ENOMEM; } + scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb", + sizeof(struct scsi_data_buffer), + 0, 0, NULL); + if (!scsi_bidi_sdb_cache) { + printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n"); + goto cleanup_io_context; + } + for (i = 0; i < SG_MEMPOOL_NR; i++) { struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; int size = sgp->size * sizeof(struct scatterlist); @@ -1767,6 +1694,7 @@ int __init scsi_init_queue(void) if (!sgp->slab) { printk(KERN_ERR "SCSI: can't init sg slab %s\n", sgp->name); + goto cleanup_bidi_sdb; } sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE, @@ -1774,10 +1702,25 @@ int __init scsi_init_queue(void) if (!sgp->pool) { printk(KERN_ERR "SCSI: can't init sg mempool %s\n", sgp->name); + goto cleanup_bidi_sdb; } } return 0; + +cleanup_bidi_sdb: + for (i = 0; i < SG_MEMPOOL_NR; i++) { + struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; + if (sgp->pool) + mempool_destroy(sgp->pool); + if (sgp->slab) + kmem_cache_destroy(sgp->slab); + } + kmem_cache_destroy(scsi_bidi_sdb_cache); +cleanup_io_context: + kmem_cache_destroy(scsi_io_context_cache); + + return -ENOMEM; } void scsi_exit_queue(void) @@ -1785,6 +1728,7 @@ void scsi_exit_queue(void) int i; kmem_cache_destroy(scsi_io_context_cache); + kmem_cache_destroy(scsi_bidi_sdb_cache); for (i = 0; i < SG_MEMPOOL_NR; i++) { struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; @@ -1804,7 +1748,7 @@ void scsi_exit_queue(void) * @timeout: command timeout * @retries: number of retries before failing * @data: returns a structure abstracting the mode header data - * @sense: place to put sense data (or NULL if no sense to be collected). + * @sshdr: place to put sense data (or NULL if no sense to be collected). * must be SCSI_SENSE_BUFFERSIZE big. * * Returns zero if successful; negative error number or scsi @@ -1871,8 +1815,7 @@ scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage, EXPORT_SYMBOL_GPL(scsi_mode_select); /** - * scsi_mode_sense - issue a mode sense, falling back from 10 to - * six bytes if necessary. + * scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary. * @sdev: SCSI device to be queried * @dbd: set if mode sense will allow block descriptors to be returned * @modepage: mode page being requested @@ -1881,13 +1824,13 @@ EXPORT_SYMBOL_GPL(scsi_mode_select); * @timeout: command timeout * @retries: number of retries before failing * @data: returns a structure abstracting the mode header data - * @sense: place to put sense data (or NULL if no sense to be collected). + * @sshdr: place to put sense data (or NULL if no sense to be collected). * must be SCSI_SENSE_BUFFERSIZE big. * * Returns zero if unsuccessful, or the header offset (either 4 * or 8 depending on whether a six or ten byte command was * issued) if successful. - **/ + */ int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, @@ -1981,40 +1924,69 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, } EXPORT_SYMBOL(scsi_mode_sense); +/** + * scsi_test_unit_ready - test if unit is ready + * @sdev: scsi device to change the state of. + * @timeout: command timeout + * @retries: number of retries before failing + * @sshdr_external: Optional pointer to struct scsi_sense_hdr for + * returning sense. Make sure that this is cleared before passing + * in. + * + * Returns zero if unsuccessful or an error if TUR failed. For + * removable media, a return of NOT_READY or UNIT_ATTENTION is + * translated to success, with the ->changed flag updated. + **/ int -scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) +scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, + struct scsi_sense_hdr *sshdr_external) { char cmd[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0, }; - struct scsi_sense_hdr sshdr; + struct scsi_sense_hdr *sshdr; int result; - - result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, - timeout, retries); + + if (!sshdr_external) + sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); + else + sshdr = sshdr_external; + + /* try to eat the UNIT_ATTENTION if there are enough retries */ + do { + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr, + timeout, retries); + } while ((driver_byte(result) & DRIVER_SENSE) && + sshdr && sshdr->sense_key == UNIT_ATTENTION && + --retries); + + if (!sshdr) + /* could not allocate sense buffer, so can't process it */ + return result; if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { - if ((scsi_sense_valid(&sshdr)) && - ((sshdr.sense_key == UNIT_ATTENTION) || - (sshdr.sense_key == NOT_READY))) { + if ((scsi_sense_valid(sshdr)) && + ((sshdr->sense_key == UNIT_ATTENTION) || + (sshdr->sense_key == NOT_READY))) { sdev->changed = 1; result = 0; } } + if (!sshdr_external) + kfree(sshdr); return result; } EXPORT_SYMBOL(scsi_test_unit_ready); /** - * scsi_device_set_state - Take the given device through the device - * state model. + * scsi_device_set_state - Take the given device through the device state model. * @sdev: scsi device to change the state of. * @state: state to change to. * * Returns zero if unsuccessful or an error if the requested * transition is illegal. - **/ + */ int scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) { @@ -2264,7 +2236,7 @@ EXPORT_SYMBOL_GPL(sdev_evt_send_simple); * Must be called with user context, may sleep. * * Returns zero if unsuccessful or an error if not. - **/ + */ int scsi_device_quiesce(struct scsi_device *sdev) { @@ -2289,7 +2261,7 @@ EXPORT_SYMBOL(scsi_device_quiesce); * queues. * * Must be called with user context, may sleep. - **/ + */ void scsi_device_resume(struct scsi_device *sdev) { @@ -2326,8 +2298,7 @@ scsi_target_resume(struct scsi_target *starget) EXPORT_SYMBOL(scsi_target_resume); /** - * scsi_internal_device_block - internal function to put a device - * temporarily into the SDEV_BLOCK state + * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state * @sdev: device to block * * Block request made by scsi lld's to temporarily stop all @@ -2342,7 +2313,7 @@ EXPORT_SYMBOL(scsi_target_resume); * state, all commands are deferred until the scsi lld reenables * the device with scsi_device_unblock or device_block_tmo fires. * This routine assumes the host_lock is held on entry. - **/ + */ int scsi_internal_device_block(struct scsi_device *sdev) { @@ -2382,7 +2353,7 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block); * (which must be a legal transition) allowing the midlayer to * goose the queue for this device. This routine assumes the * host_lock is held upon entry. - **/ + */ int scsi_internal_device_unblock(struct scsi_device *sdev) { @@ -2460,7 +2431,7 @@ EXPORT_SYMBOL_GPL(scsi_target_unblock); /** * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt - * @sg: scatter-gather list + * @sgl: scatter-gather list * @sg_count: number of segments in sg * @offset: offset in bytes into sg, on return offset into the mapped area * @len: bytes to map, on return number of bytes mapped @@ -2509,8 +2480,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, EXPORT_SYMBOL(scsi_kmap_atomic_sg); /** - * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously - * mapped with scsi_kmap_atomic_sg + * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg * @virt: virtual address to be unmapped */ void scsi_kunmap_atomic_sg(void *virt) diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c index 40579edca101..370c78cc1cb5 100644 --- a/drivers/scsi/scsi_netlink.c +++ b/drivers/scsi/scsi_netlink.c @@ -32,11 +32,12 @@ EXPORT_SYMBOL_GPL(scsi_nl_sock); /** - * scsi_nl_rcv_msg - - * Receive message handler. Extracts message from a receive buffer. + * scsi_nl_rcv_msg - Receive message handler. + * @skb: socket receive buffer + * + * Description: Extracts message from a receive buffer. * Validates message header and calls appropriate transport message handler * - * @skb: socket receive buffer * **/ static void @@ -99,9 +100,7 @@ next_msg: /** - * scsi_nl_rcv_event - - * Event handler for a netlink socket. - * + * scsi_nl_rcv_event - Event handler for a netlink socket. * @this: event notifier block * @event: event type * @ptr: event payload @@ -129,9 +128,7 @@ static struct notifier_block scsi_netlink_notifier = { /** - * scsi_netlink_init - - * Called by SCSI subsystem to intialize the SCSI transport netlink - * interface + * scsi_netlink_init - Called by SCSI subsystem to intialize the SCSI transport netlink interface * **/ void @@ -160,16 +157,14 @@ scsi_netlink_init(void) /** - * scsi_netlink_exit - - * Called by SCSI subsystem to disable the SCSI transport netlink - * interface + * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface * **/ void scsi_netlink_exit(void) { if (scsi_nl_sock) { - sock_release(scsi_nl_sock->sk_socket); + netlink_kernel_release(scsi_nl_sock); netlink_unregister_notifier(&scsi_netlink_notifier); } diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index bb6f051beda8..ed395154a5b1 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -45,6 +45,16 @@ static struct proc_dir_entry *proc_scsi; /* Protect sht->present and sht->proc_dir */ static DEFINE_MUTEX(global_host_template_mutex); +/** + * proc_scsi_read - handle read from /proc by calling host's proc_info() command + * @buffer: passed to proc_info + * @start: passed to proc_info + * @offset: passed to proc_info + * @length: passed to proc_info + * @eof: returns whether length read was less than requested + * @data: pointer to a &struct Scsi_Host + */ + static int proc_scsi_read(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { @@ -57,6 +67,13 @@ static int proc_scsi_read(char *buffer, char **start, off_t offset, return n; } +/** + * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info() + * @file: not used + * @buf: source of data to write. + * @count: number of bytes (at most PROC_BLOCK_SIZE) to write. + * @data: pointer to &struct Scsi_Host + */ static int proc_scsi_write_proc(struct file *file, const char __user *buf, unsigned long count, void *data) { @@ -80,6 +97,13 @@ out: return ret; } +/** + * scsi_proc_hostdir_add - Create directory in /proc for a scsi host + * @sht: owner of this directory + * + * Sets sht->proc_dir to the new directory. + */ + void scsi_proc_hostdir_add(struct scsi_host_template *sht) { if (!sht->proc_info) @@ -97,6 +121,10 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht) mutex_unlock(&global_host_template_mutex); } +/** + * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host + * @sht: owner of directory + */ void scsi_proc_hostdir_rm(struct scsi_host_template *sht) { if (!sht->proc_info) @@ -110,6 +138,11 @@ void scsi_proc_hostdir_rm(struct scsi_host_template *sht) mutex_unlock(&global_host_template_mutex); } + +/** + * scsi_proc_host_add - Add entry for this host to appropriate /proc dir + * @shost: host to add + */ void scsi_proc_host_add(struct Scsi_Host *shost) { struct scsi_host_template *sht = shost->hostt; @@ -133,6 +166,10 @@ void scsi_proc_host_add(struct Scsi_Host *shost) p->owner = sht->module; } +/** + * scsi_proc_host_rm - remove this host's entry from /proc + * @shost: which host + */ void scsi_proc_host_rm(struct Scsi_Host *shost) { char name[10]; @@ -143,7 +180,14 @@ void scsi_proc_host_rm(struct Scsi_Host *shost) sprintf(name,"%d", shost->host_no); remove_proc_entry(name, shost->hostt->proc_dir); } - +/** + * proc_print_scsidevice - return data about this host + * @dev: A scsi device + * @data: &struct seq_file to output to. + * + * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type, + * and revision. + */ static int proc_print_scsidevice(struct device *dev, void *data) { struct scsi_device *sdev = to_scsi_device(dev); @@ -189,6 +233,21 @@ static int proc_print_scsidevice(struct device *dev, void *data) return 0; } +/** + * scsi_add_single_device - Respond to user request to probe for/add device + * @host: user-supplied decimal integer + * @channel: user-supplied decimal integer + * @id: user-supplied decimal integer + * @lun: user-supplied decimal integer + * + * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi. + * + * does scsi_host_lookup() and either user_scan() if that transport + * type supports it, or else scsi_scan_host_selected() + * + * Note: this seems to be aimed exclusively at SCSI parallel busses. + */ + static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) { struct Scsi_Host *shost; @@ -206,6 +265,16 @@ static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) return error; } +/** + * scsi_remove_single_device - Respond to user request to remove a device + * @host: user-supplied decimal integer + * @channel: user-supplied decimal integer + * @id: user-supplied decimal integer + * @lun: user-supplied decimal integer + * + * Description: called by writing "scsi remove-single-device" to + * /proc/scsi/scsi. Does a scsi_device_lookup() and scsi_remove_device() + */ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) { struct scsi_device *sdev; @@ -226,6 +295,25 @@ static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) return error; } +/** + * proc_scsi_write - handle writes to /proc/scsi/scsi + * @file: not used + * @buf: buffer to write + * @length: length of buf, at most PAGE_SIZE + * @ppos: not used + * + * Description: this provides a legacy mechanism to add or remove devices by + * Host, Channel, ID, and Lun. To use, + * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or + * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with + * "0 1 2 3" replaced by the Host, Channel, Id, and Lun. + * + * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB, + * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to + * provide a unique identifier and nothing more. + */ + + static ssize_t proc_scsi_write(struct file *file, const char __user *buf, size_t length, loff_t *ppos) { @@ -291,6 +379,11 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } +/** + * proc_scsi_show - show contents of /proc/scsi/scsi (attached devices) + * @s: output goes here + * @p: not used + */ static int proc_scsi_show(struct seq_file *s, void *p) { seq_printf(s, "Attached devices:\n"); @@ -298,10 +391,17 @@ static int proc_scsi_show(struct seq_file *s, void *p) return 0; } +/** + * proc_scsi_open - glue function + * @inode: not used + * @file: passed to single_open() + * + * Associates proc_scsi_show with this file + */ static int proc_scsi_open(struct inode *inode, struct file *file) { /* - * We don't really needs this for the write case but it doesn't + * We don't really need this for the write case but it doesn't * harm either. */ return single_open(file, proc_scsi_show, NULL); @@ -315,6 +415,9 @@ static const struct file_operations proc_scsi_operations = { .release = single_release, }; +/** + * scsi_init_procfs - create scsi and scsi/scsi in procfs + */ int __init scsi_init_procfs(void) { struct proc_dir_entry *pde; @@ -336,6 +439,9 @@ err1: return -ENOMEM; } +/** + * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs + */ void scsi_exit_procfs(void) { remove_proc_entry("scsi/scsi", NULL); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 40ea71cd2ca6..1dc165ad17fb 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -221,6 +221,9 @@ static void scsi_unlock_floptical(struct scsi_device *sdev, /** * scsi_alloc_sdev - allocate and setup a scsi_Device + * @starget: which target to allocate a &scsi_device for + * @lun: which lun + * @hostdata: usually NULL and set by ->slave_alloc instead * * Description: * Allocate, initialize for io, and return a pointer to a scsi_Device. @@ -472,7 +475,6 @@ static void scsi_target_reap_usercontext(struct work_struct *work) /** * scsi_target_reap - check to see if target is in use and destroy if not - * * @starget: target to be checked * * This is used after removing a LUN or doing a last put of the target @@ -863,7 +865,7 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, sdev->no_start_on_add = 1; if (*bflags & BLIST_SINGLELUN) - sdev->single_lun = 1; + scsi_target(sdev)->single_lun = 1; sdev->use_10_for_rw = 1; @@ -928,8 +930,7 @@ static inline void scsi_destroy_sdev(struct scsi_device *sdev) #ifdef CONFIG_SCSI_LOGGING /** - * scsi_inq_str - print INQUIRY data from min to max index, - * strip trailing whitespace + * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace * @buf: Output buffer with at least end-first+1 bytes of space * @inq: Inquiry buffer (input) * @first: Offset of string into inq @@ -957,9 +958,10 @@ static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq, * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it * @starget: pointer to target device structure * @lun: LUN of target device - * @sdevscan: probe the LUN corresponding to this scsi_device - * @sdevnew: store the value of any new scsi_device allocated * @bflagsp: store bflags here if not NULL + * @sdevp: probe the LUN corresponding to this scsi_device + * @rescan: if nonzero skip some code only needed on first scan + * @hostdata: passed to scsi_alloc_sdev() * * Description: * Call scsi_probe_lun, if a LUN with an attached device is found, @@ -1110,6 +1112,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, * scsi_sequential_lun_scan - sequentially scan a SCSI target * @starget: pointer to target structure to scan * @bflags: black/white list flag for LUN 0 + * @scsi_level: Which version of the standard does this device adhere to + * @rescan: passed to scsi_probe_add_lun() * * Description: * Generally, scan from LUN 1 (LUN 0 is assumed to already have been @@ -1220,7 +1224,7 @@ EXPORT_SYMBOL(scsilun_to_int); /** * int_to_scsilun: reverts an int into a scsi_lun - * @int: integer to be reverted + * @lun: integer to be reverted * @scsilun: struct scsi_lun to be set. * * Description: @@ -1252,18 +1256,22 @@ EXPORT_SYMBOL(int_to_scsilun); /** * scsi_report_lun_scan - Scan using SCSI REPORT LUN results - * @sdevscan: scan the host, channel, and id of this scsi_device + * @starget: which target + * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN + * @rescan: nonzero if we can skip code only needed on first scan * * Description: - * If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN - * command, and scan the resulting list of LUNs by calling - * scsi_probe_and_add_lun. + * Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command. + * Scan the resulting list of LUNs by calling scsi_probe_and_add_lun. * - * Modifies sdevscan->lun. + * If BLINK_REPORTLUN2 is set, scan a target that supports more than 8 + * LUNs even if it's older than SCSI-3. + * If BLIST_NOREPORTLUN is set, return 1 always. + * If BLIST_NOLUN is set, return 0 always. * * Return: * 0: scan completed (or no memory, so further scanning is futile) - * 1: no report lun scan, or not configured + * 1: could not scan with REPORT LUN **/ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, int rescan) @@ -1481,6 +1489,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, if (scsi_host_scan_allowed(shost)) scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); mutex_unlock(&shost->scan_mutex); + transport_configure_device(&starget->dev); scsi_target_reap(starget); put_device(&starget->dev); @@ -1561,6 +1570,7 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel, out_reap: /* now determine if the target has any children at all * and if not, nuke it */ + transport_configure_device(&starget->dev); scsi_target_reap(starget); put_device(&starget->dev); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 00b386677392..ed83cdb6e67d 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1018,6 +1018,7 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost) } transport_register_device(&shost->shost_gendev); + transport_configure_device(&shost->shost_gendev); return 0; } diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c index 9815a1a2db24..d2557dbc2dc1 100644 --- a/drivers/scsi/scsi_tgt_if.c +++ b/drivers/scsi/scsi_tgt_if.c @@ -112,7 +112,7 @@ int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id, memset(&ev, 0, sizeof(ev)); ev.p.cmd_req.host_no = shost->host_no; ev.p.cmd_req.itn_id = itn_id; - ev.p.cmd_req.data_len = cmd->request_bufflen; + ev.p.cmd_req.data_len = scsi_bufflen(cmd); memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); ev.p.cmd_req.attribute = cmd->tag; diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index a91761c3645f..91630baea532 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -180,7 +180,7 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work) container_of(work, struct scsi_tgt_cmd, work); struct scsi_cmnd *cmd = tcmd->rq->special; - dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction, + dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction, rq_data_dir(cmd->request)); scsi_unmap_user_pages(tcmd); scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); @@ -327,12 +327,11 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) { struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); + dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request)); scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); - if (cmd->request_buffer) - scsi_free_sgtable(cmd); + scsi_release_buffers(cmd); queue_work(scsi_tgtd, &tcmd->work); } @@ -342,7 +341,7 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd) struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); int err; - dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request)); + dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request)); err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done); switch (err) { @@ -353,30 +352,6 @@ static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd) return 0; } -static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask) -{ - struct request *rq = cmd->request; - int count; - - cmd->use_sg = rq->nr_phys_segments; - cmd->request_buffer = scsi_alloc_sgtable(cmd, gfp_mask); - if (!cmd->request_buffer) - return -ENOMEM; - - cmd->request_bufflen = rq->data_len; - - dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq)); - count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer); - if (likely(count <= cmd->use_sg)) { - cmd->use_sg = count; - return 0; - } - - eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg); - scsi_free_sgtable(cmd); - return -EINVAL; -} - /* TODO: test this crap and replace bio_map_user with new interface maybe */ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, unsigned long uaddr, unsigned int len, int rw) @@ -402,9 +377,11 @@ static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, } tcmd->bio = rq->bio; - err = scsi_tgt_init_cmd(cmd, GFP_KERNEL); - if (err) + err = scsi_init_io(cmd, GFP_KERNEL); + if (err) { + scsi_release_buffers(cmd); goto unmap_rq; + } return 0; @@ -496,8 +473,8 @@ int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag, } cmd = rq->special; - dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n", - cmd, cmd->cmnd[0], result, len, cmd->request_bufflen, + dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n", + cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd), rq_data_dir(rq), cmd->cmnd[0]); if (result == TASK_ABORTED) { @@ -617,7 +594,7 @@ int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result) struct Scsi_Host *shost; int err = -EINVAL; - dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); + dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id); shost = scsi_host_lookup(host_no); if (IS_ERR(shost)) { diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 7a7cfe583b2a..b1119da6e88c 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -481,9 +481,9 @@ MODULE_PARM_DESC(dev_loss_tmo, " exceeded, the scsi target is removed. Value should be" " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT."); -/** +/* * Netlink Infrastructure - **/ + */ static atomic_t fc_event_seq; @@ -491,10 +491,10 @@ static atomic_t fc_event_seq; * fc_get_event_number - Obtain the next sequential FC event number * * Notes: - * We could have inline'd this, but it would have required fc_event_seq to + * We could have inlined this, but it would have required fc_event_seq to * be exposed. For now, live with the subroutine call. * Atomic used to avoid lock/unlock... - **/ + */ u32 fc_get_event_number(void) { @@ -505,7 +505,6 @@ EXPORT_SYMBOL(fc_get_event_number); /** * fc_host_post_event - called to post an even on an fc_host. - * * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @event_code: fc_host event being posted @@ -513,7 +512,7 @@ EXPORT_SYMBOL(fc_get_event_number); * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_host_post_event(struct Scsi_Host *shost, u32 event_number, enum fc_host_event_code event_code, u32 event_data) @@ -579,17 +578,16 @@ EXPORT_SYMBOL(fc_host_post_event); /** - * fc_host_post_vendor_event - called to post a vendor unique event on - * a fc_host - * + * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host * @shost: host the event occurred on * @event_number: fc event number obtained from get_fc_event_number() * @data_len: amount, in bytes, of vendor unique data * @data_buf: pointer to vendor unique data + * @vendor_id: Vendor id * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, u32 data_len, char * data_buf, u64 vendor_id) @@ -1900,7 +1898,6 @@ static int fc_vport_match(struct attribute_container *cont, /** * fc_timed_out - FC Transport I/O timeout intercept handler - * * @scmd: The SCSI command which timed out * * This routine protects against error handlers getting invoked while a @@ -1920,7 +1917,7 @@ static int fc_vport_match(struct attribute_container *cont, * * Notes: * This routine assumes no locks are held on entry. - **/ + */ static enum scsi_eh_timer_return fc_timed_out(struct scsi_cmnd *scmd) { @@ -2133,7 +2130,7 @@ EXPORT_SYMBOL(fc_release_transport); * 1 - work queued for execution * 0 - work is already queued * -EINVAL - work queue doesn't exist - **/ + */ static int fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) { @@ -2152,7 +2149,7 @@ fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) /** * fc_flush_work - Flush a fc_host's workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. - **/ + */ static void fc_flush_work(struct Scsi_Host *shost) { @@ -2175,7 +2172,7 @@ fc_flush_work(struct Scsi_Host *shost) * * Return value: * 1 on success / 0 already queued / < 0 for error - **/ + */ static int fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, unsigned long delay) @@ -2195,7 +2192,7 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, /** * fc_flush_devloss - Flush a fc_host's devloss workqueue. * @shost: Pointer to Scsi_Host bound to fc_host. - **/ + */ static void fc_flush_devloss(struct Scsi_Host *shost) { @@ -2212,21 +2209,20 @@ fc_flush_devloss(struct Scsi_Host *shost) /** - * fc_remove_host - called to terminate any fc_transport-related elements - * for a scsi host. - * @rport: remote port to be unblocked. + * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host. + * @shost: Which &Scsi_Host * * This routine is expected to be called immediately preceeding the * a driver's call to scsi_remove_host(). * * WARNING: A driver utilizing the fc_transport, which fails to call - * this routine prior to scsi_remote_host(), will leave dangling + * this routine prior to scsi_remove_host(), will leave dangling * objects in /sys/class/fc_remote_ports. Access to any of these * objects can result in a system crash !!! * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_remove_host(struct Scsi_Host *shost) { @@ -2281,10 +2277,10 @@ EXPORT_SYMBOL(fc_remove_host); /** * fc_starget_delete - called to delete the scsi decendents of an rport - * (target and all sdevs) - * * @work: remote port to be operated on. - **/ + * + * Deletes target and all sdevs. + */ static void fc_starget_delete(struct work_struct *work) { @@ -2303,9 +2299,8 @@ fc_starget_delete(struct work_struct *work) /** * fc_rport_final_delete - finish rport termination and delete it. - * * @work: remote port to be deleted. - **/ + */ static void fc_rport_final_delete(struct work_struct *work) { @@ -2375,7 +2370,7 @@ fc_rport_final_delete(struct work_struct *work) * * Notes: * This routine assumes no locks are held on entry. - **/ + */ static struct fc_rport * fc_rport_create(struct Scsi_Host *shost, int channel, struct fc_rport_identifiers *ids) @@ -2462,8 +2457,7 @@ delete_rport: } /** - * fc_remote_port_add - notifies the fc transport of the existence - * of a remote FC port. + * fc_remote_port_add - notify fc transport of the existence of a remote FC port. * @shost: scsi host the remote port is connected to. * @channel: Channel on shost port connected to. * @ids: The world wide names, fc address, and FC4 port @@ -2499,7 +2493,7 @@ delete_rport: * * Notes: * This routine assumes no locks are held on entry. - **/ + */ struct fc_rport * fc_remote_port_add(struct Scsi_Host *shost, int channel, struct fc_rport_identifiers *ids) @@ -2683,19 +2677,18 @@ EXPORT_SYMBOL(fc_remote_port_add); /** - * fc_remote_port_delete - notifies the fc transport that a remote - * port is no longer in existence. + * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence. * @rport: The remote port that no longer exists * * The LLDD calls this routine to notify the transport that a remote * port is no longer part of the topology. Note: Although a port * may no longer be part of the topology, it may persist in the remote * ports displayed by the fc_host. We do this under 2 conditions: - * - If the port was a scsi target, we delay its deletion by "blocking" it. + * 1) If the port was a scsi target, we delay its deletion by "blocking" it. * This allows the port to temporarily disappear, then reappear without * disrupting the SCSI device tree attached to it. During the "blocked" * period the port will still exist. - * - If the port was a scsi target and disappears for longer than we + * 2) If the port was a scsi target and disappears for longer than we * expect, we'll delete the port and the tear down the SCSI device tree * attached to it. However, we want to semi-persist the target id assigned * to that port if it eventually does exist. The port structure will @@ -2709,7 +2702,8 @@ EXPORT_SYMBOL(fc_remote_port_add); * temporary blocked state. From the LLDD's perspective, the rport no * longer exists. From the SCSI midlayer's perspective, the SCSI target * exists, but all sdevs on it are blocked from further I/O. The following - * is then expected: + * is then expected. + * * If the remote port does not return (signaled by a LLDD call to * fc_remote_port_add()) within the dev_loss_tmo timeout, then the * scsi target is removed - killing all outstanding i/o and removing the @@ -2731,7 +2725,7 @@ EXPORT_SYMBOL(fc_remote_port_add); * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_remote_port_delete(struct fc_rport *rport) { @@ -2792,12 +2786,12 @@ fc_remote_port_delete(struct fc_rport *rport) EXPORT_SYMBOL(fc_remote_port_delete); /** - * fc_remote_port_rolechg - notifies the fc transport that the roles - * on a remote may have changed. + * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed. * @rport: The remote port that changed. + * @roles: New roles for this port. * - * The LLDD calls this routine to notify the transport that the roles - * on a remote port may have changed. The largest effect of this is + * Description: The LLDD calls this routine to notify the transport that the + * roles on a remote port may have changed. The largest effect of this is * if a port now becomes a FCP Target, it must be allocated a * scsi target id. If the port is no longer a FCP target, any * scsi target id value assigned to it will persist in case the @@ -2810,7 +2804,7 @@ EXPORT_SYMBOL(fc_remote_port_delete); * * Notes: * This routine assumes no locks are held on entry. - **/ + */ void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) { @@ -2875,12 +2869,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) EXPORT_SYMBOL(fc_remote_port_rolechg); /** - * fc_timeout_deleted_rport - Timeout handler for a deleted remote port, - * which we blocked, and has now failed to return - * in the allotted time. - * + * fc_timeout_deleted_rport - Timeout handler for a deleted remote port. * @work: rport target that failed to reappear in the allotted time. - **/ + * + * Description: An attempt to delete a remote port blocks, and if it fails + * to return in the allotted time this gets called. + */ static void fc_timeout_deleted_rport(struct work_struct *work) { @@ -2984,14 +2978,12 @@ fc_timeout_deleted_rport(struct work_struct *work) } /** - * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a - * disconnected SCSI target. - * + * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target. * @work: rport to terminate io on. * * Notes: Only requests the failure of the io, not that all are flushed * prior to returning. - **/ + */ static void fc_timeout_fail_rport_io(struct work_struct *work) { @@ -3008,9 +3000,8 @@ fc_timeout_fail_rport_io(struct work_struct *work) /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. - * * @work: remote port to be scanned. - **/ + */ static void fc_scsi_scan_rport(struct work_struct *work) { @@ -3047,7 +3038,7 @@ fc_scsi_scan_rport(struct work_struct *work) * * Notes: * This routine assumes no locks are held on entry. - **/ + */ static int fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev, struct fc_vport_identifiers *ids, struct fc_vport **ret_vport) @@ -3172,7 +3163,7 @@ delete_vport: * * Notes: * This routine assumes no locks are held on entry. - **/ + */ int fc_vport_terminate(struct fc_vport *vport) { @@ -3232,9 +3223,8 @@ EXPORT_SYMBOL(fc_vport_terminate); /** * fc_vport_sched_delete - workq-based delete request for a vport - * * @work: vport to be deleted. - **/ + */ static void fc_vport_sched_delete(struct work_struct *work) { diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 5428d15f23c6..0d7b4e79415c 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,10 +30,10 @@ #include <scsi/scsi_transport_iscsi.h> #include <scsi/iscsi_if.h> -#define ISCSI_SESSION_ATTRS 15 +#define ISCSI_SESSION_ATTRS 18 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-724" +#define ISCSI_TRANSPORT_VERSION "2.0-867" struct iscsi_internal { int daemon_pid; @@ -50,6 +50,7 @@ struct iscsi_internal { }; static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ +static struct workqueue_struct *iscsi_eh_timer_workq; /* * list of registered transports and lock that must @@ -115,6 +116,8 @@ static struct attribute_group iscsi_transport_group = { .attrs = iscsi_transport_attrs, }; + + static int iscsi_setup_host(struct transport_container *tc, struct device *dev, struct class_device *cdev) { @@ -124,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); + + snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", + shost->host_no); + ihost->unbind_workq = create_singlethread_workqueue( + ihost->unbind_workq_name); + if (!ihost->unbind_workq) + return -ENOMEM; + return 0; +} + +static int iscsi_remove_host(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct Scsi_Host *shost = dev_to_shost(dev); + struct iscsi_host *ihost = shost->shost_data; + + destroy_workqueue(ihost->unbind_workq); return 0; } static DECLARE_TRANSPORT_CLASS(iscsi_host_class, "iscsi_host", iscsi_setup_host, - NULL, + iscsi_remove_host, NULL); static DECLARE_TRANSPORT_CLASS(iscsi_session_class, @@ -252,7 +272,7 @@ static void session_recovery_timedout(struct work_struct *work) void iscsi_unblock_session(struct iscsi_cls_session *session) { if (!cancel_delayed_work(&session->recovery_work)) - flush_scheduled_work(); + flush_workqueue(iscsi_eh_timer_workq); scsi_target_unblock(&session->dev); } EXPORT_SYMBOL_GPL(iscsi_unblock_session); @@ -260,11 +280,40 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session); void iscsi_block_session(struct iscsi_cls_session *session) { scsi_target_block(&session->dev); - schedule_delayed_work(&session->recovery_work, - session->recovery_tmo * HZ); + queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, + session->recovery_tmo * HZ); } EXPORT_SYMBOL_GPL(iscsi_block_session); +static void __iscsi_unbind_session(struct work_struct *work) +{ + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + unbind_work); + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + + /* Prevent new scans and make sure scanning is not in progress */ + mutex_lock(&ihost->mutex); + if (list_empty(&session->host_list)) { + mutex_unlock(&ihost->mutex); + return; + } + list_del_init(&session->host_list); + mutex_unlock(&ihost->mutex); + + scsi_remove_target(&session->dev); + iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); +} + +static int iscsi_unbind_session(struct iscsi_cls_session *session) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + + return queue_work(ihost->unbind_workq, &session->unbind_work); +} + struct iscsi_cls_session * iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport) @@ -281,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); + INIT_WORK(&session->unbind_work, __iscsi_unbind_session); /* this is released in the dev's release function */ scsi_host_get(shost); @@ -297,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost; + unsigned long flags; int err; ihost = shost->shost_data; @@ -313,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) } transport_register_device(&session->dev); + spin_lock_irqsave(&sesslock, flags); + list_add(&session->sess_list, &sesslist); + spin_unlock_irqrestore(&sesslock, flags); + mutex_lock(&ihost->mutex); list_add(&session->host_list, &ihost->sessions); mutex_unlock(&ihost->mutex); + + iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); return 0; release_host: @@ -328,9 +385,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session); * iscsi_create_session - create iscsi class session * @shost: scsi host * @transport: iscsi transport + * @target_id: which target * * This can be called from a LLD or iscsi_transport. - **/ + */ struct iscsi_cls_session * iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport, @@ -350,19 +408,58 @@ iscsi_create_session(struct Scsi_Host *shost, } EXPORT_SYMBOL_GPL(iscsi_create_session); +static void iscsi_conn_release(struct device *dev) +{ + struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); + struct device *parent = conn->dev.parent; + + kfree(conn); + put_device(parent); +} + +static int iscsi_is_conn_dev(const struct device *dev) +{ + return dev->release == iscsi_conn_release; +} + +static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) +{ + if (!iscsi_is_conn_dev(dev)) + return 0; + return iscsi_destroy_conn(iscsi_dev_to_conn(dev)); +} + void iscsi_remove_session(struct iscsi_cls_session *session) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; + unsigned long flags; + int err; - if (!cancel_delayed_work(&session->recovery_work)) - flush_scheduled_work(); + spin_lock_irqsave(&sesslock, flags); + list_del(&session->sess_list); + spin_unlock_irqrestore(&sesslock, flags); - mutex_lock(&ihost->mutex); - list_del(&session->host_list); - mutex_unlock(&ihost->mutex); + /* + * If we are blocked let commands flow again. The lld or iscsi + * layer should set up the queuecommand to fail commands. + */ + iscsi_unblock_session(session); + iscsi_unbind_session(session); + /* + * If the session dropped while removing devices then we need to make + * sure it is not blocked + */ + if (!cancel_delayed_work(&session->recovery_work)) + flush_workqueue(iscsi_eh_timer_workq); + flush_workqueue(ihost->unbind_workq); - scsi_remove_target(&session->dev); + /* hw iscsi may not have removed all connections from session */ + err = device_for_each_child(&session->dev, NULL, + iscsi_iter_destroy_conn_fn); + if (err) + dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete " + "all connections for session. Error %d.\n", err); transport_unregister_device(&session->dev); device_del(&session->dev); @@ -371,9 +468,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session); void iscsi_free_session(struct iscsi_cls_session *session) { + iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION); put_device(&session->dev); } - EXPORT_SYMBOL_GPL(iscsi_free_session); /** @@ -382,7 +479,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session); * * Can be called by a LLD or iscsi_transport. There must not be * any running connections. - **/ + */ int iscsi_destroy_session(struct iscsi_cls_session *session) { iscsi_remove_session(session); @@ -391,20 +488,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_destroy_session); -static void iscsi_conn_release(struct device *dev) -{ - struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); - struct device *parent = conn->dev.parent; - - kfree(conn); - put_device(parent); -} - -static int iscsi_is_conn_dev(const struct device *dev) -{ - return dev->release == iscsi_conn_release; -} - /** * iscsi_create_conn - create iscsi class connection * @session: iscsi cls session @@ -418,12 +501,13 @@ static int iscsi_is_conn_dev(const struct device *dev) * for software iscsi we could be trying to preallocate a connection struct * in which case there could be two connection structs and cid would be * non-zero. - **/ + */ struct iscsi_cls_conn * iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) { struct iscsi_transport *transport = session->transport; struct iscsi_cls_conn *conn; + unsigned long flags; int err; conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL); @@ -452,6 +536,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) goto release_parent_ref; } transport_register_device(&conn->dev); + + spin_lock_irqsave(&connlock, flags); + list_add(&conn->conn_list, &connlist); + conn->active = 1; + spin_unlock_irqrestore(&connlock, flags); return conn; release_parent_ref: @@ -465,17 +554,23 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn); /** * iscsi_destroy_conn - destroy iscsi class connection - * @session: iscsi cls session + * @conn: iscsi cls session * * This can be called from a LLD or iscsi_transport. - **/ + */ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) { + unsigned long flags; + + spin_lock_irqsave(&connlock, flags); + conn->active = 0; + list_del(&conn->conn_list); + spin_unlock_irqrestore(&connlock, flags); + transport_unregister_device(&conn->dev); device_unregister(&conn->dev); return 0; } - EXPORT_SYMBOL_GPL(iscsi_destroy_conn); /* @@ -685,132 +780,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) } /** - * iscsi_if_destroy_session_done - send session destr. completion event - * @conn: last connection for session - * - * This is called by HW iscsi LLDs to notify userpsace that its HW has - * removed a session. - **/ -int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) + * iscsi_session_event - send session destr. completion event + * @session: iscsi class session + * @event: type of event + */ +int iscsi_session_event(struct iscsi_cls_session *session, + enum iscsi_uevent_e event) { struct iscsi_internal *priv; - struct iscsi_cls_session *session; struct Scsi_Host *shost; struct iscsi_uevent *ev; struct sk_buff *skb; struct nlmsghdr *nlh; - unsigned long flags; int rc, len = NLMSG_SPACE(sizeof(*ev)); - priv = iscsi_if_transport_lookup(conn->transport); + priv = iscsi_if_transport_lookup(session->transport); if (!priv) return -EINVAL; - - session = iscsi_dev_to_session(conn->dev.parent); shost = iscsi_session_to_shost(session); skb = alloc_skb(len, GFP_KERNEL); if (!skb) { - dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " - "session creation event\n"); + dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " + "of session event %u\n", event); return -ENOMEM; } nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(conn->transport); - ev->type = ISCSI_KEVENT_DESTROY_SESSION; - ev->r.d_session.host_no = shost->host_no; - ev->r.d_session.sid = session->sid; - - /* - * this will occur if the daemon is not up, so we just warn - * the user and when the daemon is restarted it will handle it - */ - rc = iscsi_broadcast_skb(skb, GFP_KERNEL); - if (rc < 0) - dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " - "session destruction event. Check iscsi daemon\n"); - - spin_lock_irqsave(&sesslock, flags); - list_del(&session->sess_list); - spin_unlock_irqrestore(&sesslock, flags); + ev->transport_handle = iscsi_handle(session->transport); - spin_lock_irqsave(&connlock, flags); - conn->active = 0; - list_del(&conn->conn_list); - spin_unlock_irqrestore(&connlock, flags); - - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done); - -/** - * iscsi_if_create_session_done - send session creation completion event - * @conn: leading connection for session - * - * This is called by HW iscsi LLDs to notify userpsace that its HW has - * created a session or a existing session is back in the logged in state. - **/ -int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) -{ - struct iscsi_internal *priv; - struct iscsi_cls_session *session; - struct Scsi_Host *shost; - struct iscsi_uevent *ev; - struct sk_buff *skb; - struct nlmsghdr *nlh; - unsigned long flags; - int rc, len = NLMSG_SPACE(sizeof(*ev)); - - priv = iscsi_if_transport_lookup(conn->transport); - if (!priv) + ev->type = event; + switch (event) { + case ISCSI_KEVENT_DESTROY_SESSION: + ev->r.d_session.host_no = shost->host_no; + ev->r.d_session.sid = session->sid; + break; + case ISCSI_KEVENT_CREATE_SESSION: + ev->r.c_session_ret.host_no = shost->host_no; + ev->r.c_session_ret.sid = session->sid; + break; + case ISCSI_KEVENT_UNBIND_SESSION: + ev->r.unbind_session.host_no = shost->host_no; + ev->r.unbind_session.sid = session->sid; + break; + default: + dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n", + event); + kfree_skb(skb); return -EINVAL; - - session = iscsi_dev_to_session(conn->dev.parent); - shost = iscsi_session_to_shost(session); - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) { - dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " - "session creation event\n"); - return -ENOMEM; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(conn->transport); - ev->type = ISCSI_UEVENT_CREATE_SESSION; - ev->r.c_session_ret.host_no = shost->host_no; - ev->r.c_session_ret.sid = session->sid; - /* * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ rc = iscsi_broadcast_skb(skb, GFP_KERNEL); if (rc < 0) - dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " - "session creation event. Check iscsi daemon\n"); - - spin_lock_irqsave(&sesslock, flags); - list_add(&session->sess_list, &sesslist); - spin_unlock_irqrestore(&sesslock, flags); - - spin_lock_irqsave(&connlock, flags); - list_add(&conn->conn_list, &connlist); - conn->active = 1; - spin_unlock_irqrestore(&connlock, flags); + dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " + "of session event %u. Check iscsi daemon\n", event); return rc; } -EXPORT_SYMBOL_GPL(iscsi_if_create_session_done); +EXPORT_SYMBOL_GPL(iscsi_session_event); static int iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) { struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; - unsigned long flags; uint32_t hostno; session = transport->create_session(transport, &priv->t, @@ -821,10 +858,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) if (!session) return -ENOMEM; - spin_lock_irqsave(&sesslock, flags); - list_add(&session->sess_list, &sesslist); - spin_unlock_irqrestore(&sesslock, flags); - ev->r.c_session_ret.host_no = hostno; ev->r.c_session_ret.sid = session->sid; return 0; @@ -835,7 +868,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) { struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; - unsigned long flags; session = iscsi_session_lookup(ev->u.c_conn.sid); if (!session) { @@ -854,28 +886,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; - - spin_lock_irqsave(&connlock, flags); - list_add(&conn->conn_list, &connlist); - conn->active = 1; - spin_unlock_irqrestore(&connlock, flags); - return 0; } static int iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) { - unsigned long flags; struct iscsi_cls_conn *conn; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) return -EINVAL; - spin_lock_irqsave(&connlock, flags); - conn->active = 0; - list_del(&conn->conn_list); - spin_unlock_irqrestore(&connlock, flags); if (transport->destroy_conn) transport->destroy_conn(conn); @@ -1002,7 +1023,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct iscsi_internal *priv; struct iscsi_cls_session *session; struct iscsi_cls_conn *conn; - unsigned long flags; priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); if (!priv) @@ -1020,13 +1040,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); - if (session) { - spin_lock_irqsave(&sesslock, flags); - list_del(&session->sess_list); - spin_unlock_irqrestore(&sesslock, flags); - + if (session) transport->destroy_session(session); - } else + else + err = -EINVAL; + break; + case ISCSI_UEVENT_UNBIND_SESSION: + session = iscsi_session_lookup(ev->u.d_session.sid); + if (session) + iscsi_unbind_session(session); + else err = -EINVAL; break; case ISCSI_UEVENT_CREATE_CONN: @@ -1179,6 +1202,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); +iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO); +iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO); #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) @@ -1217,6 +1242,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1); iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1); iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1); iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); +iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); +iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); +iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ @@ -1413,6 +1441,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); + SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO); + SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO); BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; @@ -1438,6 +1468,9 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN); SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD); SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN); + SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); + SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); + SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); BUG_ON(count > ISCSI_SESSION_ATTRS); @@ -1518,8 +1551,14 @@ static __init int iscsi_transport_init(void) goto unregister_session_class; } + iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh"); + if (!iscsi_eh_timer_workq) + goto release_nls; + return 0; +release_nls: + netlink_kernel_release(nls); unregister_session_class: transport_class_unregister(&iscsi_session_class); unregister_conn_class: @@ -1533,7 +1572,8 @@ unregister_transport_class: static void __exit iscsi_transport_exit(void) { - sock_release(nls->sk_socket); + destroy_workqueue(iscsi_eh_timer_workq); + netlink_kernel_release(nls); transport_class_unregister(&iscsi_connection_class); transport_class_unregister(&iscsi_session_class); transport_class_unregister(&iscsi_host_class); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 3120f4b3a11a..f2149d0bb999 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -173,6 +173,7 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, handler = to_sas_internal(shost->transportt)->f->smp_handler; ret = handler(shost, rphy, req); + req->errors = ret; spin_lock_irq(q->queue_lock); @@ -323,7 +324,7 @@ static int do_sas_phy_delete(struct device *dev, void *data) } /** - * sas_remove_children -- tear down a devices SAS data structures + * sas_remove_children - tear down a devices SAS data structures * @dev: device belonging to the sas object * * Removes all SAS PHYs and remote PHYs for a given object @@ -336,7 +337,7 @@ void sas_remove_children(struct device *dev) EXPORT_SYMBOL(sas_remove_children); /** - * sas_remove_host -- tear down a Scsi_Host's SAS data structures + * sas_remove_host - tear down a Scsi_Host's SAS data structures * @shost: Scsi Host that is torn down * * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. @@ -577,7 +578,7 @@ static void sas_phy_release(struct device *dev) } /** - * sas_phy_alloc -- allocates and initialize a SAS PHY structure + * sas_phy_alloc - allocates and initialize a SAS PHY structure * @parent: Parent device * @number: Phy index * @@ -618,7 +619,7 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) EXPORT_SYMBOL(sas_phy_alloc); /** - * sas_phy_add -- add a SAS PHY to the device hierarchy + * sas_phy_add - add a SAS PHY to the device hierarchy * @phy: The PHY to be added * * Publishes a SAS PHY to the rest of the system. @@ -638,7 +639,7 @@ int sas_phy_add(struct sas_phy *phy) EXPORT_SYMBOL(sas_phy_add); /** - * sas_phy_free -- free a SAS PHY + * sas_phy_free - free a SAS PHY * @phy: SAS PHY to free * * Frees the specified SAS PHY. @@ -655,7 +656,7 @@ void sas_phy_free(struct sas_phy *phy) EXPORT_SYMBOL(sas_phy_free); /** - * sas_phy_delete -- remove SAS PHY + * sas_phy_delete - remove SAS PHY * @phy: SAS PHY to remove * * Removes the specified SAS PHY. If the SAS PHY has an @@ -677,7 +678,7 @@ sas_phy_delete(struct sas_phy *phy) EXPORT_SYMBOL(sas_phy_delete); /** - * scsi_is_sas_phy -- check if a struct device represents a SAS PHY + * scsi_is_sas_phy - check if a struct device represents a SAS PHY * @dev: device to check * * Returns: @@ -843,7 +844,6 @@ EXPORT_SYMBOL(sas_port_alloc_num); /** * sas_port_add - add a SAS port to the device hierarchy - * * @port: port to be added * * publishes a port to the rest of the system @@ -868,7 +868,7 @@ int sas_port_add(struct sas_port *port) EXPORT_SYMBOL(sas_port_add); /** - * sas_port_free -- free a SAS PORT + * sas_port_free - free a SAS PORT * @port: SAS PORT to free * * Frees the specified SAS PORT. @@ -885,7 +885,7 @@ void sas_port_free(struct sas_port *port) EXPORT_SYMBOL(sas_port_free); /** - * sas_port_delete -- remove SAS PORT + * sas_port_delete - remove SAS PORT * @port: SAS PORT to remove * * Removes the specified SAS PORT. If the SAS PORT has an @@ -924,7 +924,7 @@ void sas_port_delete(struct sas_port *port) EXPORT_SYMBOL(sas_port_delete); /** - * scsi_is_sas_port -- check if a struct device represents a SAS port + * scsi_is_sas_port - check if a struct device represents a SAS port * @dev: device to check * * Returns: @@ -1309,6 +1309,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy) /** * sas_end_device_alloc - allocate an rphy for an end device + * @parent: which port * * Allocates an SAS remote PHY structure, connected to @parent. * @@ -1345,6 +1346,8 @@ EXPORT_SYMBOL(sas_end_device_alloc); /** * sas_expander_alloc - allocate an rphy for an end device + * @parent: which port + * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE * * Allocates an SAS remote PHY structure, connected to @parent. * @@ -1383,7 +1386,7 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent, EXPORT_SYMBOL(sas_expander_alloc); /** - * sas_rphy_add -- add a SAS remote PHY to the device hierarchy + * sas_rphy_add - add a SAS remote PHY to the device hierarchy * @rphy: The remote PHY to be added * * Publishes a SAS remote PHY to the rest of the system. @@ -1430,8 +1433,8 @@ int sas_rphy_add(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_add); /** - * sas_rphy_free -- free a SAS remote PHY - * @rphy SAS remote PHY to free + * sas_rphy_free - free a SAS remote PHY + * @rphy: SAS remote PHY to free * * Frees the specified SAS remote PHY. * @@ -1459,7 +1462,7 @@ void sas_rphy_free(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_free); /** - * sas_rphy_delete -- remove and free SAS remote PHY + * sas_rphy_delete - remove and free SAS remote PHY * @rphy: SAS remote PHY to remove and free * * Removes the specified SAS remote PHY and frees it. @@ -1473,7 +1476,7 @@ sas_rphy_delete(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_delete); /** - * sas_rphy_remove -- remove SAS remote PHY + * sas_rphy_remove - remove SAS remote PHY * @rphy: SAS remote phy to remove * * Removes the specified SAS remote PHY. @@ -1504,7 +1507,7 @@ sas_rphy_remove(struct sas_rphy *rphy) EXPORT_SYMBOL(sas_rphy_remove); /** - * scsi_is_sas_rphy -- check if a struct device represents a SAS remote PHY + * scsi_is_sas_rphy - check if a struct device represents a SAS remote PHY * @dev: device to check * * Returns: @@ -1604,7 +1607,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1) /** - * sas_attach_transport -- instantiate SAS transport template + * sas_attach_transport - instantiate SAS transport template * @ft: SAS transport class function template */ struct scsi_transport_template * @@ -1715,7 +1718,7 @@ sas_attach_transport(struct sas_function_template *ft) EXPORT_SYMBOL(sas_attach_transport); /** - * sas_release_transport -- release SAS transport template instance + * sas_release_transport - release SAS transport template instance * @t: transport template instance */ void sas_release_transport(struct scsi_transport_template *t) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 4df21c92ff1e..1fb60313a516 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -52,13 +52,6 @@ struct spi_internal { struct scsi_transport_template t; struct spi_function_template *f; - /* The actual attributes */ - struct class_device_attribute private_attrs[SPI_NUM_ATTRS]; - /* The array of null terminated pointers to attributes - * needed by scsi_sysfs.c */ - struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1]; - struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS]; - struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1]; }; #define to_spi_internal(tmpl) container_of(tmpl, struct spi_internal, t) @@ -174,17 +167,20 @@ static int spi_host_setup(struct transport_container *tc, struct device *dev, return 0; } +static int spi_host_configure(struct transport_container *tc, + struct device *dev, + struct class_device *cdev); + static DECLARE_TRANSPORT_CLASS(spi_host_class, "spi_host", spi_host_setup, NULL, - NULL); + spi_host_configure); static int spi_host_match(struct attribute_container *cont, struct device *dev) { struct Scsi_Host *shost; - struct spi_internal *i; if (!scsi_is_host_device(dev)) return 0; @@ -194,11 +190,13 @@ static int spi_host_match(struct attribute_container *cont, != &spi_host_class.class) return 0; - i = to_spi_internal(shost->transportt); - - return &i->t.host_attrs.ac == cont; + return &shost->transportt->host_attrs.ac == cont; } +static int spi_target_configure(struct transport_container *tc, + struct device *dev, + struct class_device *cdev); + static int spi_device_configure(struct transport_container *tc, struct device *dev, struct class_device *cdev) @@ -300,8 +298,10 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ struct spi_internal *i = to_spi_internal(shost->transportt); \ \ + if (!i->f->set_##field) \ + return -EINVAL; \ val = simple_strtoul(buf, NULL, 0); \ - i->f->set_##field(starget, val); \ + i->f->set_##field(starget, val); \ return count; \ } @@ -317,6 +317,8 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ struct spi_transport_attrs *tp \ = (struct spi_transport_attrs *)&starget->starget_data; \ \ + if (i->f->set_##field) \ + return -EINVAL; \ val = simple_strtoul(buf, NULL, 0); \ if (val > tp->max_##field) \ val = tp->max_##field; \ @@ -327,14 +329,14 @@ store_spi_transport_##field(struct class_device *cdev, const char *buf, \ #define spi_transport_rd_attr(field, format_string) \ spi_transport_show_function(field, format_string) \ spi_transport_store_function(field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, \ show_spi_transport_##field, \ store_spi_transport_##field); #define spi_transport_simple_attr(field, format_string) \ spi_transport_show_simple(field, format_string) \ spi_transport_store_simple(field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, \ show_spi_transport_##field, \ store_spi_transport_##field); @@ -342,7 +344,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ spi_transport_show_function(field, format_string) \ spi_transport_store_max(field, format_string) \ spi_transport_simple_attr(max_##field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ +static CLASS_DEVICE_ATTR(field, S_IRUGO, \ show_spi_transport_##field, \ store_spi_transport_##field); @@ -472,6 +474,9 @@ store_spi_transport_period(struct class_device *cdev, const char *buf, (struct spi_transport_attrs *)&starget->starget_data; int period, retval; + if (!i->f->set_period) + return -EINVAL; + retval = store_spi_transport_period_helper(cdev, buf, count, &period); if (period < tp->min_period) @@ -482,7 +487,7 @@ store_spi_transport_period(struct class_device *cdev, const char *buf, return retval; } -static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, +static CLASS_DEVICE_ATTR(period, S_IRUGO, show_spi_transport_period, store_spi_transport_period); @@ -490,9 +495,14 @@ static ssize_t show_spi_transport_min_period(struct class_device *cdev, char *buf) { struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct spi_internal *i = to_spi_internal(shost->transportt); struct spi_transport_attrs *tp = (struct spi_transport_attrs *)&starget->starget_data; + if (!i->f->set_period) + return -EINVAL; + return show_spi_transport_period_helper(buf, tp->min_period); } @@ -509,7 +519,7 @@ store_spi_transport_min_period(struct class_device *cdev, const char *buf, } -static CLASS_DEVICE_ATTR(min_period, S_IRUGO | S_IWUSR, +static CLASS_DEVICE_ATTR(min_period, S_IRUGO, show_spi_transport_min_period, store_spi_transport_min_period); @@ -531,12 +541,15 @@ static ssize_t store_spi_host_signalling(struct class_device *cdev, struct spi_internal *i = to_spi_internal(shost->transportt); enum spi_signal_type type = spi_signal_to_value(buf); + if (!i->f->set_signalling) + return -EINVAL; + if (type != SPI_SIGNAL_UNKNOWN) i->f->set_signalling(shost, type); return count; } -static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR, +static CLASS_DEVICE_ATTR(signalling, S_IRUGO, show_spi_host_signalling, store_spi_host_signalling); @@ -1262,35 +1275,6 @@ int spi_print_msg(const unsigned char *msg) EXPORT_SYMBOL(spi_print_msg); #endif /* ! CONFIG_SCSI_CONSTANTS */ -#define SETUP_ATTRIBUTE(field) \ - i->private_attrs[count] = class_device_attr_##field; \ - if (!i->f->set_##field) { \ - i->private_attrs[count].attr.mode = S_IRUGO; \ - i->private_attrs[count].store = NULL; \ - } \ - i->attrs[count] = &i->private_attrs[count]; \ - if (i->f->show_##field) \ - count++ - -#define SETUP_RELATED_ATTRIBUTE(field, rel_field) \ - i->private_attrs[count] = class_device_attr_##field; \ - if (!i->f->set_##rel_field) { \ - i->private_attrs[count].attr.mode = S_IRUGO; \ - i->private_attrs[count].store = NULL; \ - } \ - i->attrs[count] = &i->private_attrs[count]; \ - if (i->f->show_##rel_field) \ - count++ - -#define SETUP_HOST_ATTRIBUTE(field) \ - i->private_host_attrs[count] = class_device_attr_##field; \ - if (!i->f->set_##field) { \ - i->private_host_attrs[count].attr.mode = S_IRUGO; \ - i->private_host_attrs[count].store = NULL; \ - } \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - count++ - static int spi_device_match(struct attribute_container *cont, struct device *dev) { @@ -1343,16 +1327,156 @@ static DECLARE_TRANSPORT_CLASS(spi_transport_class, "spi_transport", spi_setup_transport_attrs, NULL, - NULL); + spi_target_configure); static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class, spi_device_match, spi_device_configure); +static struct attribute *host_attributes[] = { + &class_device_attr_signalling.attr, + NULL +}; + +static struct attribute_group host_attribute_group = { + .attrs = host_attributes, +}; + +static int spi_host_configure(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) +{ + struct kobject *kobj = &cdev->kobj; + struct Scsi_Host *shost = transport_class_to_shost(cdev); + struct spi_internal *si = to_spi_internal(shost->transportt); + struct attribute *attr = &class_device_attr_signalling.attr; + int rc = 0; + + if (si->f->set_signalling) + rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR); + + return rc; +} + +/* returns true if we should be showing the variable. Also + * overloads the return by setting 1<<1 if the attribute should + * be writeable */ +#define TARGET_ATTRIBUTE_HELPER(name) \ + (si->f->show_##name ? 1 : 0) + \ + (si->f->set_##name ? 2 : 0) + +static int target_attribute_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct class_device *cdev = + container_of(kobj, struct class_device, kobj); + struct scsi_target *starget = transport_class_to_starget(cdev); + struct Scsi_Host *shost = transport_class_to_shost(cdev); + struct spi_internal *si = to_spi_internal(shost->transportt); + + if (attr == &class_device_attr_period.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(period); + else if (attr == &class_device_attr_min_period.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(period); + else if (attr == &class_device_attr_offset.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(offset); + else if (attr == &class_device_attr_max_offset.attr && + spi_support_sync(starget)) + return TARGET_ATTRIBUTE_HELPER(offset); + else if (attr == &class_device_attr_width.attr && + spi_support_wide(starget)) + return TARGET_ATTRIBUTE_HELPER(width); + else if (attr == &class_device_attr_max_width.attr && + spi_support_wide(starget)) + return TARGET_ATTRIBUTE_HELPER(width); + else if (attr == &class_device_attr_iu.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(iu); + else if (attr == &class_device_attr_dt.attr && + spi_support_dt(starget)) + return TARGET_ATTRIBUTE_HELPER(dt); + else if (attr == &class_device_attr_qas.attr && + spi_support_qas(starget)) + return TARGET_ATTRIBUTE_HELPER(qas); + else if (attr == &class_device_attr_wr_flow.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(wr_flow); + else if (attr == &class_device_attr_rd_strm.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(rd_strm); + else if (attr == &class_device_attr_rti.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(rti); + else if (attr == &class_device_attr_pcomp_en.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(pcomp_en); + else if (attr == &class_device_attr_hold_mcs.attr && + spi_support_ius(starget)) + return TARGET_ATTRIBUTE_HELPER(hold_mcs); + else if (attr == &class_device_attr_revalidate.attr) + return 1; + + return 0; +} + +static struct attribute *target_attributes[] = { + &class_device_attr_period.attr, + &class_device_attr_min_period.attr, + &class_device_attr_offset.attr, + &class_device_attr_max_offset.attr, + &class_device_attr_width.attr, + &class_device_attr_max_width.attr, + &class_device_attr_iu.attr, + &class_device_attr_dt.attr, + &class_device_attr_qas.attr, + &class_device_attr_wr_flow.attr, + &class_device_attr_rd_strm.attr, + &class_device_attr_rti.attr, + &class_device_attr_pcomp_en.attr, + &class_device_attr_hold_mcs.attr, + &class_device_attr_revalidate.attr, + NULL +}; + +static struct attribute_group target_attribute_group = { + .attrs = target_attributes, + .is_visible = target_attribute_is_visible, +}; + +static int spi_target_configure(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) +{ + struct kobject *kobj = &cdev->kobj; + int i; + struct attribute *attr; + int rc; + + for (i = 0; (attr = target_attributes[i]) != NULL; i++) { + int j = target_attribute_group.is_visible(kobj, attr, i); + + /* FIXME: as well as returning -EEXIST, which we'd like + * to ignore, sysfs also does a WARN_ON and dumps a trace, + * which is bad, so temporarily, skip attributes that are + * already visible (the revalidate one) */ + if (j && attr != &class_device_attr_revalidate.attr) + rc = sysfs_add_file_to_group(kobj, attr, + target_attribute_group.name); + /* and make the attribute writeable if we have a set + * function */ + if ((j & 1)) + rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR); + } + + return 0; +} + struct scsi_transport_template * spi_attach_transport(struct spi_function_template *ft) { - int count = 0; struct spi_internal *i = kzalloc(sizeof(struct spi_internal), GFP_KERNEL); @@ -1360,47 +1484,17 @@ spi_attach_transport(struct spi_function_template *ft) return NULL; i->t.target_attrs.ac.class = &spi_transport_class.class; - i->t.target_attrs.ac.attrs = &i->attrs[0]; + i->t.target_attrs.ac.grp = &target_attribute_group; i->t.target_attrs.ac.match = spi_target_match; transport_container_register(&i->t.target_attrs); i->t.target_size = sizeof(struct spi_transport_attrs); i->t.host_attrs.ac.class = &spi_host_class.class; - i->t.host_attrs.ac.attrs = &i->host_attrs[0]; + i->t.host_attrs.ac.grp = &host_attribute_group; i->t.host_attrs.ac.match = spi_host_match; transport_container_register(&i->t.host_attrs); i->t.host_size = sizeof(struct spi_host_attrs); i->f = ft; - SETUP_ATTRIBUTE(period); - SETUP_RELATED_ATTRIBUTE(min_period, period); - SETUP_ATTRIBUTE(offset); - SETUP_RELATED_ATTRIBUTE(max_offset, offset); - SETUP_ATTRIBUTE(width); - SETUP_RELATED_ATTRIBUTE(max_width, width); - SETUP_ATTRIBUTE(iu); - SETUP_ATTRIBUTE(dt); - SETUP_ATTRIBUTE(qas); - SETUP_ATTRIBUTE(wr_flow); - SETUP_ATTRIBUTE(rd_strm); - SETUP_ATTRIBUTE(rti); - SETUP_ATTRIBUTE(pcomp_en); - SETUP_ATTRIBUTE(hold_mcs); - - /* if you add an attribute but forget to increase SPI_NUM_ATTRS - * this bug will trigger */ - BUG_ON(count > SPI_NUM_ATTRS); - - i->attrs[count++] = &class_device_attr_revalidate; - - i->attrs[count] = NULL; - - count = 0; - SETUP_HOST_ATTRIBUTE(signalling); - - BUG_ON(count > SPI_HOST_ATTRS); - - i->host_attrs[count] = NULL; - return &i->t; } EXPORT_SYMBOL(spi_attach_transport); diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 65c584db33bd..2445c98ae95e 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -185,11 +185,10 @@ static int srp_host_match(struct attribute_container *cont, struct device *dev) /** * srp_rport_add - add a SRP remote port to the device hierarchy - * * @shost: scsi host the remote port is connected to. * @ids: The port id for the remote port. * - * publishes a port to the rest of the system + * Publishes a port to the rest of the system. */ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, struct srp_rport_identifiers *ids) @@ -242,8 +241,8 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, EXPORT_SYMBOL_GPL(srp_rport_add); /** - * srp_rport_del -- remove a SRP remote port - * @port: SRP remote port to remove + * srp_rport_del - remove a SRP remote port + * @rport: SRP remote port to remove * * Removes the specified SRP remote port. */ @@ -271,7 +270,7 @@ static int do_srp_rport_del(struct device *dev, void *data) } /** - * srp_remove_host -- tear down a Scsi_Host's SRP data structures + * srp_remove_host - tear down a Scsi_Host's SRP data structures * @shost: Scsi Host that is torn down * * Removes all SRP remote ports for a given Scsi_Host. @@ -297,7 +296,7 @@ static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result) } /** - * srp_attach_transport -- instantiate SRP transport template + * srp_attach_transport - instantiate SRP transport template * @ft: SRP transport class function template */ struct scsi_transport_template * @@ -337,7 +336,7 @@ srp_attach_transport(struct srp_function_template *ft) EXPORT_SYMBOL_GPL(srp_attach_transport); /** - * srp_release_transport -- release SRP transport template instance + * srp_release_transport - release SRP transport template instance * @t: transport template instance */ void srp_release_transport(struct scsi_transport_template *t) diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index cd68a66c7bb3..3f21bc65e8c6 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -24,6 +24,14 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); +/** + * scsi_bios_ptable - Read PC partition table out of first sector of device. + * @dev: from this device + * + * Description: Reads the first sector from the device and returns %0x42 bytes + * starting at offset %0x1be. + * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error. + */ unsigned char *scsi_bios_ptable(struct block_device *dev) { unsigned char *res = kmalloc(66, GFP_KERNEL); @@ -43,15 +51,17 @@ unsigned char *scsi_bios_ptable(struct block_device *dev) } EXPORT_SYMBOL(scsi_bios_ptable); -/* - * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip) +/** + * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors. + * @bdev: which device + * @capacity: size of the disk in sectors + * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders * - * Purpose : to determine the BIOS mapping used for a drive in a + * Description : determine the BIOS mapping/geometry used for a drive in a * SCSI-CAM system, storing the results in ip as required * by the HDIO_GETGEO ioctl(). * * Returns : -1 on failure, 0 on success. - * */ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) @@ -98,15 +108,18 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) } EXPORT_SYMBOL(scsicam_bios_param); -/* - * Function : static int scsi_partsize(unsigned char *buf, unsigned long - * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); +/** + * scsi_partsize - Parse cylinders/heads/sectors from PC partition table + * @buf: partition table, see scsi_bios_ptable() + * @capacity: size of the disk in sectors + * @cyls: put cylinders here + * @hds: put heads here + * @secs: put sectors here * - * Purpose : to determine the BIOS mapping used to create the partition + * Description: determine the BIOS mapping/geometry used to create the partition * table, storing the results in *cyls, *hds, and *secs * - * Returns : -1 on failure, 0 on success. - * + * Returns: -1 on failure, 0 on success. */ int scsi_partsize(unsigned char *buf, unsigned long capacity, @@ -194,7 +207,7 @@ EXPORT_SYMBOL(scsi_partsize); * * WORKING X3T9.2 * DRAFT 792D - * + * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf * * Revision 6 * 10-MAR-94 diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a69b155f39a2..51a5557f42dd 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -395,6 +395,15 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) goto out; } + /* + * Some devices (some sdcards for one) don't like it if the + * last sector gets read in a larger then 1 sector read. + */ + 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)); @@ -510,7 +519,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) SCpnt->cmnd[4] = (unsigned char) this_count; SCpnt->cmnd[5] = 0; } - SCpnt->request_bufflen = this_count * sdp->sector_size; + SCpnt->sdb.length = this_count * sdp->sector_size; /* * We shouldn't disconnect in the middle of a sector, so with a dumb @@ -736,6 +745,7 @@ static int sd_media_changed(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; + struct scsi_sense_hdr *sshdr = NULL; int retval; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); @@ -749,8 +759,11 @@ static int sd_media_changed(struct gendisk *disk) * can deal with it then. It is only because of unrecoverable errors * that we would ever take a device offline in the first place. */ - if (!scsi_device_online(sdp)) - goto not_present; + if (!scsi_device_online(sdp)) { + set_media_not_present(sdkp); + retval = 1; + goto out; + } /* * Using TEST_UNIT_READY enables differentiation between drive with @@ -762,8 +775,12 @@ static int sd_media_changed(struct gendisk *disk) * sd_revalidate() is called. */ retval = -ENODEV; - if (scsi_block_when_processing_errors(sdp)) - retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); + + if (scsi_block_when_processing_errors(sdp)) { + sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); + retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES, + sshdr); + } /* * Unable to test, unit probably not ready. This usually @@ -771,8 +788,13 @@ static int sd_media_changed(struct gendisk *disk) * and we will figure it out later once the drive is * available again. */ - if (retval) - goto not_present; + if (retval || (scsi_sense_valid(sshdr) && + /* 0x3a is medium not present */ + sshdr->asc == 0x3a)) { + set_media_not_present(sdkp); + retval = 1; + goto out; + } /* * For removable scsi disk we have to recognise the presence @@ -783,12 +805,12 @@ static int sd_media_changed(struct gendisk *disk) retval = sdp->changed; sdp->changed = 0; - +out: + if (retval != sdkp->previous_state) + sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL); + sdkp->previous_state = retval; + kfree(sshdr); return retval; - -not_present: - set_media_not_present(sdkp); - return 1; } static int sd_sync_cache(struct scsi_disk *sdkp) @@ -904,7 +926,7 @@ static struct block_device_operations sd_fops = { static int sd_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; - unsigned int xfer_size = SCpnt->request_bufflen; + unsigned int xfer_size = scsi_bufflen(SCpnt); unsigned int good_bytes = result ? 0 : xfer_size; u64 start_lba = SCpnt->request->sector; u64 bad_lba; diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c deleted file mode 100644 index b11324479b5b..000000000000 --- a/drivers/scsi/seagate.c +++ /dev/null @@ -1,1667 +0,0 @@ -/* - * seagate.c Copyright (C) 1992, 1993 Drew Eckhardt - * low level scsi driver for ST01/ST02, Future Domain TMC-885, - * TMC-950 by Drew Eckhardt <drew@colorado.edu> - * - * Note : TMC-880 boards don't work because they have two bits in - * the status register flipped, I'll fix this "RSN" - * [why do I have strong feeling that above message is from 1993? :-) - * pavel@ucw.cz] - * - * This card does all the I/O via memory mapped I/O, so there is no need - * to check or allocate a region of the I/O address space. - */ - -/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt - * macros, replaced assembler routines with C. There's probably a - * performance hit, but I only have a cdrom and can't tell. Define - * SEAGATE_USE_ASM if you want the old assembler code -- SJT - * - * 1998-jul-29 - created DPRINTK macros and made it work under - * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz> - * - * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to - * read the physical disk geometry, a bad mistake. Of course it doesn't - * matter much what geometry one invents, but on large disks it - * returned 256 (or more) heads, causing all kind of failures. - * Of course this means that people might see a different geometry now, - * so boot parameters may be necessary in some cases. - */ - -/* - * Configuration : - * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE - * -DIRQ will override the default of 5. - * Note: You can now set these options from the kernel's "command line". - * The syntax is: - * - * st0x=ADDRESS,IRQ (for a Seagate controller) - * or: - * tmc8xx=ADDRESS,IRQ (for a TMC-8xx or TMC-950 controller) - * eg: - * tmc8xx=0xC8000,15 - * - * will configure the driver for a TMC-8xx style controller using IRQ 15 - * with a base address of 0xC8000. - * - * -DARBITRATE - * Will cause the host adapter to arbitrate for the - * bus for better SCSI-II compatibility, rather than just - * waiting for BUS FREE and then doing its thing. Should - * let us do one command per Lun when I integrate my - * reorganization changes into the distribution sources. - * - * -DDEBUG=65535 - * Will activate debug code. - * - * -DFAST or -DFAST32 - * Will use blind transfers where possible - * - * -DPARITY - * This will enable parity. - * - * -DSEAGATE_USE_ASM - * Will use older seagate assembly code. should be (very small amount) - * Faster. - * - * -DSLOW_RATE=50 - * Will allow compatibility with broken devices that don't - * handshake fast enough (ie, some CD ROM's) for the Seagate - * code. - * - * 50 is some number, It will let you specify a default - * transfer rate if handshaking isn't working correctly. - * - * -DOLDCNTDATASCEME There is a new sceme to set the CONTROL - * and DATA reigsters which complies more closely - * with the SCSI2 standard. This hopefully eliminates - * the need to swap the order these registers are - * 'messed' with. It makes the following two options - * obsolete. To reenable the old sceme define this. - * - * The following to options are patches from the SCSI.HOWTO - * - * -DSWAPSTAT This will swap the definitions for STAT_MSG and STAT_CD. - * - * -DSWAPCNTDATA This will swap the order that seagate.c messes with - * the CONTROL an DATA registers. - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/signal.h> -#include <linux/string.h> -#include <linux/proc_fs.h> -#include <linux/init.h> -#include <linux/blkdev.h> -#include <linux/stat.h> -#include <linux/delay.h> -#include <linux/io.h> - -#include <asm/system.h> -#include <asm/uaccess.h> - -#include <scsi/scsi_cmnd.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi.h> - -#include <scsi/scsi_dbg.h> -#include <scsi/scsi_host.h> - - -#ifdef DEBUG -#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0) -#else -#define DPRINTK( when, msg... ) do { } while (0) -#define DEBUG 0 -#endif -#define DANY( msg... ) DPRINTK( 0xffff, msg ); - -#ifndef IRQ -#define IRQ 5 -#endif - -#ifdef FAST32 -#define FAST -#endif - -#undef LINKED /* Linked commands are currently broken! */ - -#if defined(OVERRIDE) && !defined(CONTROLLER) -#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type -#endif - -#ifndef __i386__ -#undef SEAGATE_USE_ASM -#endif - -/* - Thanks to Brian Antoine for the example code in his Messy-Loss ST-01 - driver, and Mitsugu Suzuki for information on the ST-01 - SCSI host. -*/ - -/* - CONTROL defines -*/ - -#define CMD_RST 0x01 -#define CMD_SEL 0x02 -#define CMD_BSY 0x04 -#define CMD_ATTN 0x08 -#define CMD_START_ARB 0x10 -#define CMD_EN_PARITY 0x20 -#define CMD_INTR 0x40 -#define CMD_DRVR_ENABLE 0x80 - -/* - STATUS -*/ -#ifdef SWAPSTAT -#define STAT_MSG 0x08 -#define STAT_CD 0x02 -#else -#define STAT_MSG 0x02 -#define STAT_CD 0x08 -#endif - -#define STAT_BSY 0x01 -#define STAT_IO 0x04 -#define STAT_REQ 0x10 -#define STAT_SEL 0x20 -#define STAT_PARITY 0x40 -#define STAT_ARB_CMPL 0x80 - -/* - REQUESTS -*/ - -#define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG) -#define REQ_DATAOUT 0 -#define REQ_DATAIN STAT_IO -#define REQ_CMDOUT STAT_CD -#define REQ_STATIN (STAT_CD | STAT_IO) -#define REQ_MSGOUT (STAT_MSG | STAT_CD) -#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO) - -extern volatile int seagate_st0x_timeout; - -#ifdef PARITY -#define BASE_CMD CMD_EN_PARITY -#else -#define BASE_CMD 0 -#endif - -/* - Debugging code -*/ - -#define PHASE_BUS_FREE 1 -#define PHASE_ARBITRATION 2 -#define PHASE_SELECTION 4 -#define PHASE_DATAIN 8 -#define PHASE_DATAOUT 0x10 -#define PHASE_CMDOUT 0x20 -#define PHASE_MSGIN 0x40 -#define PHASE_MSGOUT 0x80 -#define PHASE_STATUSIN 0x100 -#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN) -#define PRINT_COMMAND 0x200 -#define PHASE_EXIT 0x400 -#define PHASE_RESELECT 0x800 -#define DEBUG_FAST 0x1000 -#define DEBUG_SG 0x2000 -#define DEBUG_LINKED 0x4000 -#define DEBUG_BORKEN 0x8000 - -/* - * Control options - these are timeouts specified in .01 seconds. - */ - -/* 30, 20 work */ -#define ST0X_BUS_FREE_DELAY 25 -#define ST0X_SELECTION_DELAY 25 - -#define SEAGATE 1 /* these determine the type of the controller */ -#define FD 2 - -#define ST0X_ID_STR "Seagate ST-01/ST-02" -#define FD_ID_STR "TMC-8XX/TMC-950" - -static int internal_command (unsigned char target, unsigned char lun, - const void *cmnd, - void *buff, int bufflen, int reselect); - -static int incommand; /* set if arbitration has finished - and we are in some command phase. */ - -static unsigned int base_address = 0; /* Where the card ROM starts, used to - calculate memory mapped register - location. */ - -static void __iomem *st0x_cr_sr; /* control register write, status - register read. 256 bytes in - length. - Read is status of SCSI BUS, as per - STAT masks. */ - -static void __iomem *st0x_dr; /* data register, read write 256 - bytes in length. */ - -static volatile int st0x_aborted = 0; /* set when we are aborted, ie by a - time out, etc. */ - -static unsigned char controller_type = 0; /* set to SEAGATE for ST0x - boards or FD for TMC-8xx - boards */ -static int irq = IRQ; - -module_param(base_address, uint, 0); -module_param(controller_type, byte, 0); -module_param(irq, int, 0); -MODULE_LICENSE("GPL"); - - -#define retcode(result) (((result) << 16) | (message << 8) | status) -#define STATUS ((u8) readb(st0x_cr_sr)) -#define DATA ((u8) readb(st0x_dr)) -#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); } -#define WRITE_DATA(d) { writeb((d), st0x_dr); } - -#ifndef OVERRIDE -static unsigned int seagate_bases[] = { - 0xc8000, 0xca000, 0xcc000, - 0xce000, 0xdc000, 0xde000 -}; - -typedef struct { - const unsigned char *signature; - unsigned offset; - unsigned length; - unsigned char type; -} Signature; - -static Signature __initdata signatures[] = { - {"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE}, - {"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE}, - -/* - * The following two lines are NOT mistakes. One detects ROM revision - * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter, - * and this is not going to change, the "SEAGATE" and "SCSI" together - * are probably "good enough" - */ - - {"SEAGATE SCSI BIOS ", 16, 17, SEAGATE}, - {"SEAGATE SCSI BIOS ", 17, 17, SEAGATE}, - -/* - * However, future domain makes several incompatible SCSI boards, so specific - * signatures must be used. - */ - - {"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD}, - {"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD}, - {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD}, - {"IBM F1 BIOS V1.1004/30/92", 5, 25, FD}, - {"FUTURE DOMAIN TMC-950", 5, 21, FD}, - /* Added for 2.2.16 by Matthias_Heidbrink@b.maus.de */ - {"IBM F1 V1.2009/22/93", 5, 25, FD}, -}; - -#define NUM_SIGNATURES ARRAY_SIZE(signatures) -#endif /* n OVERRIDE */ - -/* - * hostno stores the hostnumber, as told to us by the init routine. - */ - -static int hostno = -1; -static void seagate_reconnect_intr (int, void *); -static irqreturn_t do_seagate_reconnect_intr (int, void *); -static int seagate_st0x_bus_reset(struct scsi_cmnd *); - -#ifdef FAST -static int fast = 1; -#else -#define fast 0 -#endif - -#ifdef SLOW_RATE -/* - * Support for broken devices : - * The Seagate board has a handshaking problem. Namely, a lack - * thereof for slow devices. You can blast 600K/second through - * it if you are polling for each byte, more if you do a blind - * transfer. In the first case, with a fast device, REQ will - * transition high-low or high-low-high before your loop restarts - * and you'll have no problems. In the second case, the board - * will insert wait states for up to 13.2 usecs for REQ to - * transition low->high, and everything will work. - * - * However, there's nothing in the state machine that says - * you *HAVE* to see a high-low-high set of transitions before - * sending the next byte, and slow things like the Trantor CD ROMS - * will break because of this. - * - * So, we need to slow things down, which isn't as simple as it - * seems. We can't slow things down period, because then people - * who don't recompile their kernels will shoot me for ruining - * their performance. We need to do it on a case per case basis. - * - * The best for performance will be to, only for borken devices - * (this is stored on a per-target basis in the scsi_devices array) - * - * Wait for a low->high transition before continuing with that - * transfer. If we timeout, continue anyways. We don't need - * a long timeout, because REQ should only be asserted until the - * corresponding ACK is received and processed. - * - * Note that we can't use the system timer for this, because of - * resolution, and we *really* can't use the timer chip since - * gettimeofday() and the beeper routines use that. So, - * the best thing for us to do will be to calibrate a timing - * loop in the initialization code using the timer chip before - * gettimeofday() can screw with it. - * - * FIXME: this is broken (not borken :-). Empty loop costs less than - * loop with ISA access in it! -- pavel@ucw.cz - */ - -static int borken_calibration = 0; - -static void __init borken_init (void) -{ - register int count = 0, start = jiffies + 1, stop = start + 25; - - /* FIXME: There may be a better approach, this is a straight port for - now */ - preempt_disable(); - while (time_before (jiffies, start)) - cpu_relax(); - for (; time_before (jiffies, stop); ++count) - cpu_relax(); - preempt_enable(); - -/* - * Ok, we now have a count for .25 seconds. Convert to a - * count per second and divide by transfer rate in K. */ - - borken_calibration = (count * 4) / (SLOW_RATE * 1024); - - if (borken_calibration < 1) - borken_calibration = 1; -} - -static inline void borken_wait (void) -{ - register int count; - - for (count = borken_calibration; count && (STATUS & STAT_REQ); --count) - cpu_relax(); - -#if (DEBUG & DEBUG_BORKEN) - if (count) - printk ("scsi%d : borken timeout\n", hostno); -#endif -} - -#endif /* def SLOW_RATE */ - -/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP() - * contains at least one ISA access, which takes more than 0.125 - * usec. So if we loop 8 times time in usec, we are safe. - */ - -#define ULOOP( i ) for (clock = i*8;;) -#define TIMEOUT (!(clock--)) - -static int __init seagate_st0x_detect (struct scsi_host_template * tpnt) -{ - struct Scsi_Host *instance; - int i, j; - unsigned long cr, dr; - - tpnt->proc_name = "seagate"; -/* - * First, we try for the manual override. - */ - DANY ("Autodetecting ST0x / TMC-8xx\n"); - - if (hostno != -1) { - printk (KERN_ERR "seagate_st0x_detect() called twice?!\n"); - return 0; - } - -/* If the user specified the controller type from the command line, - controller_type will be non-zero, so don't try to detect one */ - - if (!controller_type) { -#ifdef OVERRIDE - base_address = OVERRIDE; - controller_type = CONTROLLER; - - DANY ("Base address overridden to %x, controller type is %s\n", - base_address, - controller_type == SEAGATE ? "SEAGATE" : "FD"); -#else /* OVERRIDE */ -/* - * To detect this card, we simply look for the signature - * from the BIOS version notice in all the possible locations - * of the ROM's. This has a nice side effect of not trashing - * any register locations that might be used by something else. - * - * XXX - note that we probably should be probing the address - * space for the on-board RAM instead. - */ - - for (i = 0; i < ARRAY_SIZE(seagate_bases); ++i) { - void __iomem *p = ioremap(seagate_bases[i], 0x2000); - if (!p) - continue; - for (j = 0; j < NUM_SIGNATURES; ++j) - if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) { - base_address = seagate_bases[i]; - controller_type = signatures[j].type; - break; - } - iounmap(p); - } -#endif /* OVERRIDE */ - } - /* (! controller_type) */ - tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6; - tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR; - - if (!base_address) { - printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n"); - return 0; - } - - cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00); - dr = cr + 0x200; - st0x_cr_sr = ioremap(cr, 0x100); - st0x_dr = ioremap(dr, 0x100); - - DANY("%s detected. Base address = %x, cr = %x, dr = %x\n", - tpnt->name, base_address, cr, dr); - - /* - * At all times, we will use IRQ 5. Should also check for IRQ3 - * if we lose our first interrupt. - */ - instance = scsi_register (tpnt, 0); - if (instance == NULL) - return 0; - - hostno = instance->host_no; - if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) { - printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq); - return 0; - } - instance->irq = irq; - instance->io_port = base_address; -#ifdef SLOW_RATE - printk(KERN_INFO "Calibrating borken timer... "); - borken_init(); - printk(" %d cycles per transfer\n", borken_calibration); -#endif - printk (KERN_INFO "This is one second... "); - { - int clock; - ULOOP (1 * 1000 * 1000) { - STATUS; - if (TIMEOUT) - break; - } - } - - printk ("done, %s options:" -#ifdef ARBITRATE - " ARBITRATE" -#endif -#if DEBUG - " DEBUG" -#endif -#ifdef FAST - " FAST" -#ifdef FAST32 - "32" -#endif -#endif -#ifdef LINKED - " LINKED" -#endif -#ifdef PARITY - " PARITY" -#endif -#ifdef SEAGATE_USE_ASM - " SEAGATE_USE_ASM" -#endif -#ifdef SLOW_RATE - " SLOW_RATE" -#endif -#ifdef SWAPSTAT - " SWAPSTAT" -#endif -#ifdef SWAPCNTDATA - " SWAPCNTDATA" -#endif - "\n", tpnt->name); - return 1; -} - -static const char *seagate_st0x_info (struct Scsi_Host *shpnt) -{ - static char buffer[64]; - - snprintf(buffer, 64, "%s at irq %d, address 0x%05X", - (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR, - irq, base_address); - return buffer; -} - -/* - * These are our saved pointers for the outstanding command that is - * waiting for a reconnect - */ - -static unsigned char current_target, current_lun; -static unsigned char *current_cmnd, *current_data; -static int current_nobuffs; -static struct scatterlist *current_buffer; -static int current_bufflen; - -#ifdef LINKED -/* - * linked_connected indicates whether or not we are currently connected to - * linked_target, linked_lun and in an INFORMATION TRANSFER phase, - * using linked commands. - */ - -static int linked_connected = 0; -static unsigned char linked_target, linked_lun; -#endif - -static void (*done_fn) (struct scsi_cmnd *) = NULL; -static struct scsi_cmnd *SCint = NULL; - -/* - * These control whether or not disconnect / reconnect will be attempted, - * or are being attempted. - */ - -#define NO_RECONNECT 0 -#define RECONNECT_NOW 1 -#define CAN_RECONNECT 2 - -/* - * LINKED_RIGHT indicates that we are currently connected to the correct target - * for this command, LINKED_WRONG indicates that we are connected to the wrong - * target. Note that these imply CAN_RECONNECT and require defined(LINKED). - */ - -#define LINKED_RIGHT 3 -#define LINKED_WRONG 4 - -/* - * This determines if we are expecting to reconnect or not. - */ - -static int should_reconnect = 0; - -/* - * The seagate_reconnect_intr routine is called when a target reselects the - * host adapter. This occurs on the interrupt triggered by the target - * asserting SEL. - */ - -static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave (dev->host_lock, flags); - seagate_reconnect_intr (irq, dev_id); - spin_unlock_irqrestore (dev->host_lock, flags); - return IRQ_HANDLED; -} - -static void seagate_reconnect_intr (int irq, void *dev_id) -{ - int temp; - struct scsi_cmnd *SCtmp; - - DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno); - - if (!should_reconnect) - printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno); - else { - should_reconnect = 0; - - DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", - hostno, current_target, current_data, current_bufflen); - - temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW); - - if (msg_byte(temp) != DISCONNECT) { - if (done_fn) { - DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp); - if (!SCint) - panic ("SCint == NULL in seagate"); - SCtmp = SCint; - SCint = NULL; - SCtmp->result = temp; - done_fn(SCtmp); - } else - printk(KERN_ERR "done_fn() not defined.\n"); - } - } -} - -/* - * The seagate_st0x_queue_command() function provides a queued interface - * to the seagate SCSI driver. Basically, it just passes control onto the - * seagate_command() function, after fixing it so that the done_fn() - * is set to the one passed to the function. We have to be very careful, - * because there are some commands on some devices that do not disconnect, - * and if we simply call the done_fn when the command is done then another - * command is started and queue_command is called again... We end up - * overflowing the kernel stack, and this tends not to be such a good idea. - */ - -static int recursion_depth = 0; - -static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt, - void (*done) (struct scsi_cmnd *)) -{ - int result, reconnect; - struct scsi_cmnd *SCtmp; - - DANY ("seagate: que_command"); - done_fn = done; - current_target = SCpnt->device->id; - current_lun = SCpnt->device->lun; - current_cmnd = SCpnt->cmnd; - current_data = (unsigned char *) SCpnt->request_buffer; - current_bufflen = SCpnt->request_bufflen; - SCint = SCpnt; - if (recursion_depth) - return 1; - recursion_depth++; - do { -#ifdef LINKED - /* - * Set linked command bit in control field of SCSI command. - */ - - current_cmnd[SCpnt->cmd_len] |= 0x01; - if (linked_connected) { - DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno); - if (linked_target == current_target && linked_lun == current_lun) - { - DPRINTK(DEBUG_LINKED, "correct\n"); - reconnect = LINKED_RIGHT; - } else { - DPRINTK(DEBUG_LINKED, "incorrect\n"); - reconnect = LINKED_WRONG; - } - } else -#endif /* LINKED */ - reconnect = CAN_RECONNECT; - - result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd, - SCint->request_buffer, SCint->request_bufflen, reconnect); - if (msg_byte(result) == DISCONNECT) - break; - SCtmp = SCint; - SCint = NULL; - SCtmp->result = result; - done_fn(SCtmp); - } - while (SCint); - recursion_depth--; - return 0; -} - -static int internal_command (unsigned char target, unsigned char lun, - const void *cmnd, void *buff, int bufflen, int reselect) -{ - unsigned char *data = NULL; - struct scatterlist *buffer = NULL; - int clock, temp, nobuffs = 0, done = 0, len = 0; -#if DEBUG - int transfered = 0, phase = 0, newphase; -#endif - register unsigned char status_read; - unsigned char tmp_data, tmp_control, status = 0, message = 0; - unsigned transfersize = 0, underflow = 0; -#ifdef SLOW_RATE - int borken = (int) SCint->device->borken; /* Does the current target require - Very Slow I/O ? */ -#endif - - incommand = 0; - st0x_aborted = 0; - -#if (DEBUG & PRINT_COMMAND) - printk("scsi%d : target = %d, command = ", hostno, target); - __scsi_print_command((unsigned char *) cmnd); -#endif - -#if (DEBUG & PHASE_RESELECT) - switch (reselect) { - case RECONNECT_NOW: - printk("scsi%d : reconnecting\n", hostno); - break; -#ifdef LINKED - case LINKED_RIGHT: - printk("scsi%d : connected, can reconnect\n", hostno); - break; - case LINKED_WRONG: - printk("scsi%d : connected to wrong target, can reconnect\n", - hostno); - break; -#endif - case CAN_RECONNECT: - printk("scsi%d : allowed to reconnect\n", hostno); - break; - default: - printk("scsi%d : not allowed to reconnect\n", hostno); - } -#endif - - if (target == (controller_type == SEAGATE ? 7 : 6)) - return DID_BAD_TARGET; - - /* - * We work it differently depending on if this is is "the first time," - * or a reconnect. If this is a reselect phase, then SEL will - * be asserted, and we must skip selection / arbitration phases. - */ - - switch (reselect) { - case RECONNECT_NOW: - DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno); - /* - * At this point, we should find the logical or of our ID - * and the original target's ID on the BUS, with BSY, SEL, - * and I/O signals asserted. - * - * After ARBITRATION phase is completed, only SEL, BSY, - * and the target ID are asserted. A valid initiator ID - * is not on the bus until IO is asserted, so we must wait - * for that. - */ - ULOOP (100 * 1000) { - temp = STATUS; - if ((temp & STAT_IO) && !(temp & STAT_BSY)) - break; - if (TIMEOUT) { - DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno); - return (DID_BAD_INTR << 16); - } - } - - /* - * After I/O is asserted by the target, we can read our ID - * and its ID off of the BUS. - */ - - if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) { - DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp); - return (DID_BAD_INTR << 16); - } - - if (!(temp & (1 << current_target))) { - printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt. Data bus = %d\n", hostno, temp); - return (DID_BAD_INTR << 16); - } - - buffer = current_buffer; - cmnd = current_cmnd; /* WDE add */ - data = current_data; /* WDE add */ - len = current_bufflen; /* WDE add */ - nobuffs = current_nobuffs; - - /* - * We have determined that we have been selected. At this - * point, we must respond to the reselection by asserting - * BSY ourselves - */ - -#if 1 - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY); -#else - WRITE_CONTROL (BASE_CMD | CMD_BSY); -#endif - - /* - * The target will drop SEL, and raise BSY, at which time - * we must drop BSY. - */ - - ULOOP (100 * 1000) { - if (!(STATUS & STAT_SEL)) - break; - if (TIMEOUT) { - WRITE_CONTROL (BASE_CMD | CMD_INTR); - DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno); - return (DID_BAD_INTR << 16); - } - } - WRITE_CONTROL (BASE_CMD); - /* - * At this point, we have connected with the target - * and can get on with our lives. - */ - break; - case CAN_RECONNECT: -#ifdef LINKED - /* - * This is a bletcherous hack, just as bad as the Unix #! - * interpreter stuff. If it turns out we are using the wrong - * I_T_L nexus, the easiest way to deal with it is to go into - * our INFORMATION TRANSFER PHASE code, send a ABORT - * message on MESSAGE OUT phase, and then loop back to here. - */ -connect_loop: -#endif - DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno); - - /* - * BUS FREE PHASE - * - * On entry, we make sure that the BUS is in a BUS FREE - * phase, by insuring that both BSY and SEL are low for - * at least one bus settle delay. Several reads help - * eliminate wire glitch. - */ - -#ifndef ARBITRATE -#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock. - clock = jiffies + ST0X_BUS_FREE_DELAY; - - while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock)) - cpu_relax(); - - if (time_after (jiffies, clock)) - return retcode (DID_BUS_BUSY); - else if (st0x_aborted) - return retcode (st0x_aborted); -#endif - DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno); - - clock = jiffies + ST0X_SELECTION_DELAY; - - /* - * Arbitration/selection procedure : - * 1. Disable drivers - * 2. Write HOST adapter address bit - * 3. Set start arbitration. - * 4. We get either ARBITRATION COMPLETE or SELECT at this - * point. - * 5. OR our ID and targets on bus. - * 6. Enable SCSI drivers and asserted SEL and ATTN - */ - -#ifdef ARBITRATE - /* FIXME: verify host lock is always held here */ - WRITE_CONTROL(0); - WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40); - WRITE_CONTROL(CMD_START_ARB); - - ULOOP (ST0X_SELECTION_DELAY * 10000) { - status_read = STATUS; - if (status_read & STAT_ARB_CMPL) - break; - if (st0x_aborted) /* FIXME: What? We are going to do something even after abort? */ - break; - if (TIMEOUT || (status_read & STAT_SEL)) { - printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno); - WRITE_CONTROL (BASE_CMD); - return retcode (DID_NO_CONNECT); - } - } - DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno); -#endif - - /* - * When the SCSI device decides that we're gawking at it, - * it will respond by asserting BUSY on the bus. - * - * Note : the Seagate ST-01/02 product manual says that we - * should twiddle the DATA register before the control - * register. However, this does not work reliably so we do - * it the other way around. - * - * Probably could be a problem with arbitration too, we - * really should try this with a SCSI protocol or logic - * analyzer to see what is going on. - */ - tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40)); - tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0); - - /* FIXME: verify host lock is always held here */ -#ifdef OLDCNTDATASCEME -#ifdef SWAPCNTDATA - WRITE_CONTROL (tmp_control); - WRITE_DATA (tmp_data); -#else - WRITE_DATA (tmp_data); - WRITE_CONTROL (tmp_control); -#endif -#else - tmp_control ^= CMD_BSY; /* This is guesswork. What used to be in driver */ - WRITE_CONTROL (tmp_control); /* could never work: it sent data into control */ - WRITE_DATA (tmp_data); /* register and control info into data. Hopefully */ - tmp_control ^= CMD_BSY; /* fixed, but order of first two may be wrong. */ - WRITE_CONTROL (tmp_control); /* -- pavel@ucw.cz */ -#endif - - ULOOP (250 * 1000) { - if (st0x_aborted) { - /* - * If we have been aborted, and we have a - * command in progress, IE the target - * still has BSY asserted, then we will - * reset the bus, and notify the midlevel - * driver to expect sense. - */ - - WRITE_CONTROL (BASE_CMD); - if (STATUS & STAT_BSY) { - printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno); - seagate_st0x_bus_reset(NULL); - return retcode (DID_RESET); - } - return retcode (st0x_aborted); - } - if (STATUS & STAT_BSY) - break; - if (TIMEOUT) { - DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS); - return retcode (DID_NO_CONNECT); - } - } - - /* Establish current pointers. Take into account scatter / gather */ - - if ((nobuffs = SCint->use_sg)) { -#if (DEBUG & DEBUG_SG) - { - int i; - printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs); - for (i = 0; i < nobuffs; ++i) - printk("scsi%d : buffer %d address = %p length = %d\n", - hostno, i, - sg_virt(&buffer[i]), - buffer[i].length); - } -#endif - - buffer = (struct scatterlist *) SCint->request_buffer; - len = buffer->length; - data = sg_virt(buffer); - } else { - DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno); - buffer = NULL; - len = SCint->request_bufflen; - data = (unsigned char *) SCint->request_buffer; - } - - DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n", - hostno, len); - - break; -#ifdef LINKED - case LINKED_RIGHT: - break; - case LINKED_WRONG: - break; -#endif - } /* end of switch(reselect) */ - - /* - * There are several conditions under which we wish to send a message : - * 1. When we are allowing disconnect / reconnect, and need to - * establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit - * set. - * - * 2. When we are doing linked commands, are have the wrong I_T_L - * nexus established and want to send an ABORT message. - */ - - /* GCC does not like an ifdef inside a macro, so do it the hard way. */ -#ifdef LINKED - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0)); -#else - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0)); -#endif - - /* - * INFORMATION TRANSFER PHASE - * - * The nasty looking read / write inline assembler loops we use for - * DATAIN and DATAOUT phases are approximately 4-5 times as fast as - * the 'C' versions - since we're moving 1024 bytes of data, this - * really adds up. - * - * SJT: The nasty-looking assembler is gone, so it's slower. - * - */ - - DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno); - - incommand = 1; - transfersize = SCint->transfersize; - underflow = SCint->underflow; - - /* - * Now, we poll the device for status information, - * and handle any requests it makes. Note that since we are unsure - * of how much data will be flowing across the system, etc and - * cannot make reasonable timeouts, that we will instead have the - * midlevel driver handle any timeouts that occur in this phase. - */ - - while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) { -#ifdef PARITY - if (status_read & STAT_PARITY) { - printk(KERN_ERR "scsi%d : got parity error\n", hostno); - st0x_aborted = DID_PARITY; - } -#endif - if (status_read & STAT_REQ) { -#if ((DEBUG & PHASE_ETC) == PHASE_ETC) - if ((newphase = (status_read & REQ_MASK)) != phase) { - phase = newphase; - switch (phase) { - case REQ_DATAOUT: - printk ("scsi%d : phase = DATA OUT\n", hostno); - break; - case REQ_DATAIN: - printk ("scsi%d : phase = DATA IN\n", hostno); - break; - case REQ_CMDOUT: - printk - ("scsi%d : phase = COMMAND OUT\n", hostno); - break; - case REQ_STATIN: - printk ("scsi%d : phase = STATUS IN\n", hostno); - break; - case REQ_MSGOUT: - printk - ("scsi%d : phase = MESSAGE OUT\n", hostno); - break; - case REQ_MSGIN: - printk ("scsi%d : phase = MESSAGE IN\n", hostno); - break; - default: - printk ("scsi%d : phase = UNKNOWN\n", hostno); - st0x_aborted = DID_ERROR; - } - } -#endif - switch (status_read & REQ_MASK) { - case REQ_DATAOUT: - /* - * If we are in fast mode, then we simply splat - * the data out in word-sized chunks as fast as - * we can. - */ - - if (!len) { -#if 0 - printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun); - st0x_aborted = DID_ERROR; - fast = 0; -#endif - break; - } - - if (fast && transfersize - && !(len % transfersize) - && (len >= transfersize) -#ifdef FAST32 - && !(transfersize % 4) -#endif - ) { - DPRINTK (DEBUG_FAST, - "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" - " len = %d, data = %08x\n", - hostno, SCint->underflow, - SCint->transfersize, len, - data); - - /* SJT: Start. Fast Write */ -#ifdef SEAGATE_USE_ASM - __asm__ ("cld\n\t" -#ifdef FAST32 - "shr $2, %%ecx\n\t" - "1:\t" - "lodsl\n\t" - "movl %%eax, (%%edi)\n\t" -#else - "1:\t" - "lodsb\n\t" - "movb %%al, (%%edi)\n\t" -#endif - "loop 1b;" - /* output */ : - /* input */ :"D" (st0x_dr), - "S" - (data), - "c" (SCint->transfersize) -/* clobbered */ - : "eax", "ecx", - "esi"); -#else /* SEAGATE_USE_ASM */ - memcpy_toio(st0x_dr, data, transfersize); -#endif /* SEAGATE_USE_ASM */ -/* SJT: End */ - len -= transfersize; - data += transfersize; - DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); - } else { - /* - * We loop as long as we are in a - * data out phase, there is data to - * send, and BSY is still active. - */ - -/* SJT: Start. Slow Write. */ -#ifdef SEAGATE_USE_ASM - - int __dummy_1, __dummy_2; - -/* - * We loop as long as we are in a data out phase, there is data to send, - * and BSY is still active. - */ -/* Local variables : len = ecx , data = esi, - st0x_cr_sr = ebx, st0x_dr = edi -*/ - __asm__ ( - /* Test for any data here at all. */ - "orl %%ecx, %%ecx\n\t" - "jz 2f\n\t" "cld\n\t" -/* "movl st0x_cr_sr, %%ebx\n\t" */ -/* "movl st0x_dr, %%edi\n\t" */ - "1:\t" - "movb (%%ebx), %%al\n\t" - /* Test for BSY */ - "test $1, %%al\n\t" - "jz 2f\n\t" - /* Test for data out phase - STATUS & REQ_MASK should be - REQ_DATAOUT, which is 0. */ - "test $0xe, %%al\n\t" - "jnz 2f\n\t" - /* Test for REQ */ - "test $0x10, %%al\n\t" - "jz 1b\n\t" - "lodsb\n\t" - "movb %%al, (%%edi)\n\t" - "loop 1b\n\t" "2:\n" - /* output */ :"=S" (data), "=c" (len), - "=b" - (__dummy_1), - "=D" (__dummy_2) -/* input */ - : "0" (data), "1" (len), - "2" (st0x_cr_sr), - "3" (st0x_dr) -/* clobbered */ - : "eax"); -#else /* SEAGATE_USE_ASM */ - while (len) { - unsigned char stat; - - stat = STATUS; - if (!(stat & STAT_BSY) - || ((stat & REQ_MASK) != - REQ_DATAOUT)) - break; - if (stat & STAT_REQ) { - WRITE_DATA (*data++); - --len; - } - } -#endif /* SEAGATE_USE_ASM */ -/* SJT: End. */ - } - - if (!len && nobuffs) { - --nobuffs; - ++buffer; - len = buffer->length; - data = sg_virt(buffer); - DPRINTK (DEBUG_SG, - "scsi%d : next scatter-gather buffer len = %d address = %08x\n", - hostno, len, data); - } - break; - - case REQ_DATAIN: -#ifdef SLOW_RATE - if (borken) { -#if (DEBUG & (PHASE_DATAIN)) - transfered += len; -#endif - for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) { - *data++ = DATA; - borken_wait(); - } -#if (DEBUG & (PHASE_DATAIN)) - transfered -= len; -#endif - } else -#endif - - if (fast && transfersize - && !(len % transfersize) - && (len >= transfersize) -#ifdef FAST32 - && !(transfersize % 4) -#endif - ) { - DPRINTK (DEBUG_FAST, - "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" - " len = %d, data = %08x\n", - hostno, SCint->underflow, - SCint->transfersize, len, - data); - -/* SJT: Start. Fast Read */ -#ifdef SEAGATE_USE_ASM - __asm__ ("cld\n\t" -#ifdef FAST32 - "shr $2, %%ecx\n\t" - "1:\t" - "movl (%%esi), %%eax\n\t" - "stosl\n\t" -#else - "1:\t" - "movb (%%esi), %%al\n\t" - "stosb\n\t" -#endif - "loop 1b\n\t" - /* output */ : - /* input */ :"S" (st0x_dr), - "D" - (data), - "c" (SCint->transfersize) -/* clobbered */ - : "eax", "ecx", - "edi"); -#else /* SEAGATE_USE_ASM */ - memcpy_fromio(data, st0x_dr, len); -#endif /* SEAGATE_USE_ASM */ -/* SJT: End */ - len -= transfersize; - data += transfersize; -#if (DEBUG & PHASE_DATAIN) - printk ("scsi%d: transfered += %d\n", hostno, transfersize); - transfered += transfersize; -#endif - - DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data); - } else { - -#if (DEBUG & PHASE_DATAIN) - printk ("scsi%d: transfered += %d\n", hostno, len); - transfered += len; /* Assume we'll transfer it all, then - subtract what we *didn't* transfer */ -#endif - -/* - * We loop as long as we are in a data in phase, there is room to read, - * and BSY is still active - */ - -/* SJT: Start. */ -#ifdef SEAGATE_USE_ASM - - int __dummy_3, __dummy_4; - -/* Dummy clobbering variables for the new gcc-2.95 */ - -/* - * We loop as long as we are in a data in phase, there is room to read, - * and BSY is still active - */ - /* Local variables : ecx = len, edi = data - esi = st0x_cr_sr, ebx = st0x_dr */ - __asm__ ( - /* Test for room to read */ - "orl %%ecx, %%ecx\n\t" - "jz 2f\n\t" "cld\n\t" -/* "movl st0x_cr_sr, %%esi\n\t" */ -/* "movl st0x_dr, %%ebx\n\t" */ - "1:\t" - "movb (%%esi), %%al\n\t" - /* Test for BSY */ - "test $1, %%al\n\t" - "jz 2f\n\t" - /* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, - = STAT_IO, which is 4. */ - "movb $0xe, %%ah\n\t" - "andb %%al, %%ah\n\t" - "cmpb $0x04, %%ah\n\t" - "jne 2f\n\t" - /* Test for REQ */ - "test $0x10, %%al\n\t" - "jz 1b\n\t" - "movb (%%ebx), %%al\n\t" - "stosb\n\t" - "loop 1b\n\t" "2:\n" - /* output */ :"=D" (data), "=c" (len), - "=S" - (__dummy_3), - "=b" (__dummy_4) -/* input */ - : "0" (data), "1" (len), - "2" (st0x_cr_sr), - "3" (st0x_dr) -/* clobbered */ - : "eax"); -#else /* SEAGATE_USE_ASM */ - while (len) { - unsigned char stat; - - stat = STATUS; - if (!(stat & STAT_BSY) - || ((stat & REQ_MASK) != - REQ_DATAIN)) - break; - if (stat & STAT_REQ) { - *data++ = DATA; - --len; - } - } -#endif /* SEAGATE_USE_ASM */ -/* SJT: End. */ -#if (DEBUG & PHASE_DATAIN) - printk ("scsi%d: transfered -= %d\n", hostno, len); - transfered -= len; /* Since we assumed all of Len got * - transfered, correct our mistake */ -#endif - } - - if (!len && nobuffs) { - --nobuffs; - ++buffer; - len = buffer->length; - data = sg_virt(buffer); - DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data); - } - break; - - case REQ_CMDOUT: - while (((status_read = STATUS) & STAT_BSY) && - ((status_read & REQ_MASK) == REQ_CMDOUT)) - if (status_read & STAT_REQ) { - WRITE_DATA (*(const unsigned char *) cmnd); - cmnd = 1 + (const unsigned char *)cmnd; -#ifdef SLOW_RATE - if (borken) - borken_wait (); -#endif - } - break; - - case REQ_STATIN: - status = DATA; - break; - - case REQ_MSGOUT: - /* - * We can only have sent a MSG OUT if we - * requested to do this by raising ATTN. - * So, we must drop ATTN. - */ - WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE); - /* - * If we are reconnecting, then we must - * send an IDENTIFY message in response - * to MSGOUT. - */ - switch (reselect) { - case CAN_RECONNECT: - WRITE_DATA (IDENTIFY (1, lun)); - DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno); - break; -#ifdef LINKED - case LINKED_WRONG: - WRITE_DATA (ABORT); - linked_connected = 0; - reselect = CAN_RECONNECT; - goto connect_loop; - DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno); -#endif /* LINKED */ - DPRINTK (DEBUG_LINKED, "correct\n"); - default: - WRITE_DATA (NOP); - printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target); - } - break; - - case REQ_MSGIN: - switch (message = DATA) { - case DISCONNECT: - DANY("seagate: deciding to disconnect\n"); - should_reconnect = 1; - current_data = data; /* WDE add */ - current_buffer = buffer; - current_bufflen = len; /* WDE add */ - current_nobuffs = nobuffs; -#ifdef LINKED - linked_connected = 0; -#endif - done = 1; - DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno); - break; - -#ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: -#endif - case COMMAND_COMPLETE: - /* - * Note : we should check for underflow here. - */ - DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno); - done = 1; - break; - case ABORT: - DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno); - done = 1; - break; - case SAVE_POINTERS: - current_buffer = buffer; - current_bufflen = len; /* WDE add */ - current_data = data; /* WDE mod */ - current_nobuffs = nobuffs; - DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno); - break; - case RESTORE_POINTERS: - buffer = current_buffer; - cmnd = current_cmnd; - data = current_data; /* WDE mod */ - len = current_bufflen; - nobuffs = current_nobuffs; - DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno); - break; - default: - - /* - * IDENTIFY distinguishes itself - * from the other messages by - * setting the high bit. - * - * Note : we need to handle at - * least one outstanding command - * per LUN, and need to hash the - * SCSI command for that I_T_L - * nexus based on the known ID - * (at this point) and LUN. - */ - - if (message & 0x80) { - DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7); - } else { - /* - * We should go into a - * MESSAGE OUT phase, and - * send a MESSAGE_REJECT - * if we run into a message - * that we don't like. The - * seagate driver needs - * some serious - * restructuring first - * though. - */ - DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target); - } - } - break; - default: - printk(KERN_ERR "scsi%d : unknown phase.\n", hostno); - st0x_aborted = DID_ERROR; - } /* end of switch (status_read & REQ_MASK) */ -#ifdef SLOW_RATE - /* - * I really don't care to deal with borken devices in - * each single byte transfer case (ie, message in, - * message out, status), so I'll do the wait here if - * necessary. - */ - if(borken) - borken_wait(); -#endif - - } /* if(status_read & STAT_REQ) ends */ - } /* while(((status_read = STATUS)...) ends */ - - DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered); - -#if (DEBUG & PHASE_EXIT) -#if 0 /* Doesn't work for scatter/gather */ - printk("Buffer : \n"); - for(i = 0; i < 20; ++i) - printk("%02x ", ((unsigned char *) data)[i]); /* WDE mod */ - printk("\n"); -#endif - printk("scsi%d : status = ", hostno); - scsi_print_status(status); - printk(" message = %02x\n", message); -#endif - - /* We shouldn't reach this until *after* BSY has been deasserted */ - -#ifdef LINKED - else - { - /* - * Fix the message byte so that unsuspecting high level drivers - * don't puke when they see a LINKED COMMAND message in place of - * the COMMAND COMPLETE they may be expecting. Shouldn't be - * necessary, but it's better to be on the safe side. - * - * A non LINKED* message byte will indicate that the command - * completed, and we are now disconnected. - */ - - switch (message) { - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - message = COMMAND_COMPLETE; - linked_target = current_target; - linked_lun = current_lun; - linked_connected = 1; - DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno); - /* We also will need to adjust status to accommodate intermediate - conditions. */ - if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD)) - status = GOOD; - break; - /* - * We should also handle what are "normal" termination - * messages here (ABORT, BUS_DEVICE_RESET?, and - * COMMAND_COMPLETE individually, and flake if things - * aren't right. - */ - default: - DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno); - linked_connected = 0; - } - } -#endif /* LINKED */ - - if (should_reconnect) { - DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno); - WRITE_CONTROL (BASE_CMD | CMD_INTR); - } else - WRITE_CONTROL (BASE_CMD); - - return retcode (st0x_aborted); -} /* end of internal_command */ - -static int seagate_st0x_abort(struct scsi_cmnd * SCpnt) -{ - st0x_aborted = DID_ABORT; - return SUCCESS; -} - -#undef ULOOP -#undef TIMEOUT - -/* - * the seagate_st0x_reset function resets the SCSI bus - * - * May be called with SCpnt = NULL - */ - -static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt) -{ - /* No timeouts - this command is going to fail because it was reset. */ - DANY ("scsi%d: Reseting bus... ", hostno); - - /* assert RESET signal on SCSI bus. */ - WRITE_CONTROL (BASE_CMD | CMD_RST); - - mdelay (20); - - WRITE_CONTROL (BASE_CMD); - st0x_aborted = DID_RESET; - - DANY ("done.\n"); - return SUCCESS; -} - -static int seagate_st0x_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - release_region(shost->io_port, shost->n_io_port); - return 0; -} - -static struct scsi_host_template driver_template = { - .detect = seagate_st0x_detect, - .release = seagate_st0x_release, - .info = seagate_st0x_info, - .queuecommand = seagate_st0x_queue_command, - .eh_abort_handler = seagate_st0x_abort, - .eh_bus_reset_handler = seagate_st0x_bus_reset, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index f1871ea04045..aba28f335b88 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -48,6 +48,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ #include <linux/blkdev.h> #include <linux/delay.h> #include <linux/scatterlist.h> +#include <linux/blktrace_api.h> #include "scsi.h" #include <scsi/scsi_dbg.h> @@ -602,8 +603,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) * but is is possible that the app intended SG_DXFER_TO_DEV, because there * is a non-zero input_size, so emit a warning. */ - if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) - if (printk_ratelimit()) + if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) { + static char cmd[TASK_COMM_LEN]; + if (strcmp(current->comm, cmd) && printk_ratelimit()) { printk(KERN_WARNING "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--" "guessing data in;\n" KERN_WARNING " " @@ -611,6 +613,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) old_hdr.reply_len - (int)SZ_SG_HEADER, input_size, (unsigned int) cmnd[0], current->comm); + strcpy(cmd, current->comm); + } + } k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); return (k < 0) ? k : count; } @@ -1063,6 +1068,17 @@ sg_ioctl(struct inode *inode, struct file *filp, case BLKSECTGET: return put_user(sdp->device->request_queue->max_sectors * 512, ip); + case BLKTRACESETUP: + return blk_trace_setup(sdp->device->request_queue, + sdp->disk->disk_name, + sdp->device->sdev_gendev.devt, + (char *)arg); + case BLKTRACESTART: + return blk_trace_startstop(sdp->device->request_queue, 1); + case BLKTRACESTOP: + return blk_trace_startstop(sdp->device->request_queue, 0); + case BLKTRACETEARDOWN: + return blk_trace_remove(sdp->device->request_queue); default: if (read_only) return -EPERM; /* don't know so take safe approach */ @@ -1418,7 +1434,6 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) goto out; } - class_set_devdata(cl_dev, sdp); error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1); if (error) goto cdev_add_err; @@ -1431,11 +1446,14 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) MKDEV(SCSI_GENERIC_MAJOR, sdp->index), cl_dev->dev, "%s", disk->disk_name); - if (IS_ERR(sg_class_member)) - printk(KERN_WARNING "sg_add: " - "class_device_create failed\n"); + if (IS_ERR(sg_class_member)) { + printk(KERN_ERR "sg_add: " + "class_device_create failed\n"); + error = PTR_ERR(sg_class_member); + goto cdev_add_err; + } class_set_devdata(sg_class_member, sdp); - error = sysfs_create_link(&scsidp->sdev_gendev.kobj, + error = sysfs_create_link(&scsidp->sdev_gendev.kobj, &sg_class_member->kobj, "generic"); if (error) printk(KERN_ERR "sg_add: unable to make symlink " @@ -1447,6 +1465,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) "Attached scsi generic sg%d type %d\n", sdp->index, scsidp->type); + class_set_devdata(cl_dev, sdp); + return 0; cdev_add_err: @@ -2521,7 +2541,7 @@ sg_idr_max_id(int id, void *p, void *data) static int sg_last_dev(void) { - int k = 0; + int k = -1; unsigned long iflags; read_lock_irqsave(&sg_index_lock, iflags); diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index eef82758d047..26cfc56c7091 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -33,10 +33,9 @@ struct ip22_hostdata { struct WD33C93_hostdata wh; - struct hpc_data { - dma_addr_t dma; - void *cpu; - } hd; + dma_addr_t dma; + void *cpu; + struct device *dev; }; #define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata)) @@ -46,6 +45,11 @@ struct hpc_chunk { u32 _padding; /* align to quadword boundary */ }; +/* space for hpc dma descriptors */ +#define HPC_DMA_SIZE PAGE_SIZE + +#define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) + static irqreturn_t sgiwd93_intr(int irq, void *dev_id) { struct Scsi_Host * host = dev_id; @@ -59,15 +63,17 @@ static irqreturn_t sgiwd93_intr(int irq, void *dev_id) } static inline -void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp) +void fill_hpc_entries(struct ip22_hostdata *hd, struct scsi_cmnd *cmd, int din) { unsigned long len = cmd->SCp.this_residual; void *addr = cmd->SCp.ptr; dma_addr_t physaddr; unsigned long count; + struct hpc_chunk *hcp; - physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction); + physaddr = dma_map_single(hd->dev, addr, len, DMA_DIR(din)); cmd->SCp.dma_handle = physaddr; + hcp = hd->cpu; while (len) { /* @@ -89,6 +95,9 @@ void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp) */ hcp->desc.pbuf = 0; hcp->desc.cntinfo = HPCDMA_EOX; + dma_cache_sync(hd->dev, hd->cpu, + (unsigned long)(hcp + 1) - (unsigned long)hd->cpu, + DMA_TO_DEVICE); } static int dma_setup(struct scsi_cmnd *cmd, int datainp) @@ -96,9 +105,8 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp) struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host); struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) cmd->device->host->base; - struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu; - pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp); + pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hdata->cpu); hdata->wh.dma_dir = datainp; @@ -111,12 +119,12 @@ static int dma_setup(struct scsi_cmnd *cmd, int datainp) if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0) return 1; - fill_hpc_entries(hcp, cmd, datainp); + fill_hpc_entries(hdata, cmd, datainp); pr_debug(" HPCGO\n"); /* Start up the HPC. */ - hregs->ndptr = hdata->hd.dma; + hregs->ndptr = hdata->dma; if (datainp) hregs->ctrl = HPC3_SCTRL_ACTIVE; else @@ -134,6 +142,9 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, if (!SCpnt) return; + if (SCpnt->SCp.ptr == NULL || SCpnt->SCp.this_residual == 0) + return; + hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base; pr_debug("dma_stop: status<%d> ", status); @@ -145,8 +156,9 @@ static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, barrier(); } hregs->ctrl = 0; - dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual, - SCpnt->sc_data_direction); + dma_unmap_single(hdata->dev, SCpnt->SCp.dma_handle, + SCpnt->SCp.this_residual, + DMA_DIR(hdata->wh.dma_dir)); pr_debug("\n"); } @@ -159,23 +171,25 @@ void sgiwd93_reset(unsigned long base) udelay(50); hregs->ctrl = 0; } +EXPORT_SYMBOL_GPL(sgiwd93_reset); -static inline void init_hpc_chain(struct hpc_data *hd) +static inline void init_hpc_chain(struct ip22_hostdata *hdata) { - struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu; - struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma; + struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu; + dma_addr_t dma = hdata->dma; unsigned long start, end; start = (unsigned long) hcp; - end = start + PAGE_SIZE; + end = start + HPC_DMA_SIZE; while (start < end) { - hcp->desc.pnext = (u32) (dma + 1); + hcp->desc.pnext = (u32) (dma + sizeof(struct hpc_chunk)); hcp->desc.cntinfo = HPCDMA_EOX; - hcp++; dma++; + hcp++; + dma += sizeof(struct hpc_chunk); start += sizeof(struct hpc_chunk); }; hcp--; - hcp->desc.pnext = hd->dma; + hcp->desc.pnext = hdata->dma; } static int sgiwd93_bus_reset(struct scsi_cmnd *cmd) @@ -234,16 +248,17 @@ static int __init sgiwd93_probe(struct platform_device *pdev) host->irq = irq; hdata = host_to_hostdata(host); - hdata->hd.cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, - &hdata->hd.dma, GFP_KERNEL); - if (!hdata->hd.cpu) { + hdata->dev = &pdev->dev; + hdata->cpu = dma_alloc_noncoherent(&pdev->dev, HPC_DMA_SIZE, + &hdata->dma, GFP_KERNEL); + if (!hdata->cpu) { printk(KERN_WARNING "sgiwd93: Could not allocate memory for " "host %d buffer.\n", unit); err = -ENOMEM; goto out_put; } - init_hpc_chain(&hdata->hd); + init_hpc_chain(hdata); regs.SASR = wdregs + 3; regs.SCMD = wdregs + 7; @@ -273,7 +288,7 @@ static int __init sgiwd93_probe(struct platform_device *pdev) out_irq: free_irq(irq, host); out_free: - dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); + dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); out_put: scsi_host_put(host); out: @@ -289,7 +304,7 @@ static void __exit sgiwd93_remove(struct platform_device *pdev) scsi_remove_host(host); free_irq(pd->irq, host); - dma_free_coherent(&pdev->dev, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); + dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); scsi_host_put(host); } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index c61999031141..50ba49250203 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -67,8 +67,6 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); #define SR_DISKS 256 -#define MAX_RETRIES 3 -#define SR_TIMEOUT (30 * HZ) #define SR_CAPABILITIES \ (CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \ CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \ @@ -179,21 +177,28 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) { struct scsi_cd *cd = cdi->handle; int retval; + struct scsi_sense_hdr *sshdr; if (CDSL_CURRENT != slot) { /* no changer support */ return -EINVAL; } - retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES); - if (retval) { - /* Unable to test, unit probably not ready. This usually - * means there is no disc in the drive. Mark as changed, - * and we will figure it out later once the drive is - * available again. */ + sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); + retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + sshdr); + if (retval || (scsi_sense_valid(sshdr) && + /* 0x3a is medium not present */ + sshdr->asc == 0x3a)) { + /* Media not present or unable to test, unit probably not + * ready. This usually means there is no disc in the drive. + * Mark as changed, and we will figure it out later once + * the drive is available again. + */ cd->device->changed = 1; - return 1; /* This will force a flush, if called from - * check_disk_change */ + /* This will force a flush, if called from check_disk_change */ + retval = 1; + goto out; }; retval = cd->device->changed; @@ -203,9 +208,17 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) if (retval) { /* check multisession offset etc */ sr_cd_check(cdi); - get_sectorsize(cd); } + +out: + /* Notify userspace, that media has changed. */ + if (retval != cd->previous_state) + sdev_evt_send_simple(cd->device, SDEV_EVT_MEDIA_CHANGE, + GFP_KERNEL); + cd->previous_state = retval; + kfree(sshdr); + return retval; } @@ -218,7 +231,7 @@ static int sr_media_change(struct cdrom_device_info *cdi, int slot) static int sr_done(struct scsi_cmnd *SCpnt) { int result = SCpnt->result; - int this_count = SCpnt->request_bufflen; + int this_count = scsi_bufflen(SCpnt); int good_bytes = (result == 0 ? this_count : 0); int block_sectors = 0; long error_sector; @@ -366,17 +379,18 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) } { - struct scatterlist *sg = SCpnt->request_buffer; - int i, size = 0; - for (i = 0; i < SCpnt->use_sg; i++) - size += sg[i].length; + struct scatterlist *sg; + int i, size = 0, sg_count = scsi_sg_count(SCpnt); + + scsi_for_each_sg(SCpnt, sg, sg_count, i) + size += sg->length; - if (size != SCpnt->request_bufflen && SCpnt->use_sg) { + if (size != scsi_bufflen(SCpnt)) { scmd_printk(KERN_ERR, SCpnt, "mismatch count %d, bytes %d\n", - size, SCpnt->request_bufflen); - if (SCpnt->request_bufflen > size) - SCpnt->request_bufflen = size; + size, scsi_bufflen(SCpnt)); + if (scsi_bufflen(SCpnt) > size) + SCpnt->sdb.length = size; } } @@ -384,12 +398,12 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) * request doesn't start on hw block boundary, add scatter pads */ if (((unsigned int)rq->sector % (s_size >> 9)) || - (SCpnt->request_bufflen % s_size)) { + (scsi_bufflen(SCpnt) % s_size)) { scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n"); goto out; } - this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9); + this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9); SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", @@ -403,7 +417,7 @@ static int sr_prep_fn(struct request_queue *q, struct request *rq) if (this_count > 0xffff) { this_count = 0xffff; - SCpnt->request_bufflen = this_count * s_size; + SCpnt->sdb.length = this_count * s_size; } SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index d65de9621b27..81fbc0b78a52 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -20,6 +20,9 @@ #include <linux/genhd.h> #include <linux/kref.h> +#define MAX_RETRIES 3 +#define SR_TIMEOUT (30 * HZ) + struct scsi_device; /* The CDROM is fairly slow, so we need a little extra time */ @@ -37,6 +40,7 @@ typedef struct scsi_cd { unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ unsigned readcd_cdda:1; /* reading audio data using READ_CD */ + unsigned previous_state:1; /* media has changed */ struct cdrom_device_info cdi; /* We hold gendisk and scsi_device references on probe and use * the refs on this kref to decide when to release them */ diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index e1589f91706a..d5cebff1d646 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -275,18 +275,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) /* ---------------------------------------------------------------------- */ /* interface to cdrom.c */ -static int test_unit_ready(Scsi_CD *cd) -{ - struct packet_command cgc; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_TEST_UNIT_READY; - cgc.quiet = 1; - cgc.data_direction = DMA_NONE; - cgc.timeout = IOCTL_TIMEOUT; - return sr_do_ioctl(cd, &cgc); -} - int sr_tray_move(struct cdrom_device_info *cdi, int pos) { Scsi_CD *cd = cdi->handle; @@ -310,14 +298,46 @@ int sr_lock_door(struct cdrom_device_info *cdi, int lock) int sr_drive_status(struct cdrom_device_info *cdi, int slot) { + struct scsi_cd *cd = cdi->handle; + struct scsi_sense_hdr sshdr; + struct media_event_desc med; + if (CDSL_CURRENT != slot) { /* we have no changer support */ return -EINVAL; } - if (0 == test_unit_ready(cdi->handle)) + if (0 == scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, + &sshdr)) return CDS_DISC_OK; - return CDS_TRAY_OPEN; + if (!cdrom_get_media_event(cdi, &med)) { + if (med.media_present) + return CDS_DISC_OK; + else if (med.door_open) + return CDS_TRAY_OPEN; + else + return CDS_NO_DISC; + } + + /* + * 0x04 is format in progress .. but there must be a disc present! + */ + if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04) + return CDS_DISC_OK; + + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ + if (scsi_sense_valid(&sshdr) && + /* 0x3a is medium not present */ + sshdr.asc == 0x3a) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; + + return CDS_DRIVE_NOT_READY; } int sr_disk_status(struct cdrom_device_info *cdi) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 328c47c6aeb1..71952703125a 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -9,7 +9,7 @@ Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and Eric Youngdale. - Copyright 1992 - 2007 Kai Makisara + Copyright 1992 - 2008 Kai Makisara email Kai.Makisara@kolumbus.fi Some small formal changes - aeb, 950809 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support */ -static const char *verstr = "20070203"; +static const char *verstr = "20080117"; #include <linux/module.h> @@ -3214,8 +3214,7 @@ static int partition_tape(struct scsi_tape *STp, int size) /* The ioctl command */ -static int st_ioctl(struct inode *inode, struct file *file, - unsigned int cmd_in, unsigned long arg) +static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) { int i, cmd_nr, cmd_type, bt; int retval = 0; @@ -3870,7 +3869,7 @@ static const struct file_operations st_fops = .owner = THIS_MODULE, .read = st_read, .write = st_write, - .ioctl = st_ioctl, + .unlocked_ioctl = st_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = st_compat_ioctl, #endif diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index e3fab3a6aed7..72f6d8015358 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -1123,7 +1123,6 @@ static struct scsi_host_template driver_template = { .this_id = -1, .sg_tablesize = ST_MAX_SG, .cmd_per_lun = ST_CMD_PER_LUN, - .use_sg_chaining = ENABLE_SG_CHAINING, }; static int stex_set_dma_mask(struct pci_dev * pdev) diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 2dcde373b20e..bcaba86060ab 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -515,9 +515,9 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd) * various queues are valid. */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; @@ -528,8 +528,8 @@ static __inline__ void initialize_SCp(struct scsi_cmnd *cmd) } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } } @@ -935,7 +935,7 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd, } # endif # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { @@ -943,14 +943,14 @@ static int NCR5380_queue_command(struct scsi_cmnd *cmd, case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingw++; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); hostdata->pendingr++; break; } @@ -1345,7 +1345,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, struct scsi_cmnd *cmd) { # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) # endif switch (cmd->cmnd[0]) { @@ -1353,14 +1353,14 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, case WRITE_6: case WRITE_10: hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingw--; break; case READ: case READ_6: case READ_10: hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ + /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/ hostdata->pendingr--; break; } @@ -1863,7 +1863,7 @@ static int do_abort (struct Scsi_Host *host) * the target sees, so we just handshake. */ - while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 90cee94d9522..6325901e5093 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -328,27 +328,13 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id) { struct Scsi_Host *dev = dev_id; - int base = 0; + int base = dev->io_port; int i; unsigned long flags = 0; unsigned char status_reg, pio_int_reg, int_reg; struct scatterlist *sg; unsigned int tot_trans = 0; - /* We search the base address of the host adapter which caused the interrupt */ - /* FIXME: should pass dev_id sensibly as hosts[i] */ - for(i = 0; i < host_index && !base; i++) - if(irq == hosts[i].irq) - base = hosts[i].base; - /* If no adapter found, we cannot handle the interrupt. Leave a message */ - /* and continue. This should never happen... */ - if(!base) - { - printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq); - return IRQ_NONE; - } - /* Now we have the base address and we can start handling the interrupt */ - spin_lock_irqsave(dev->host_lock,flags); status_reg = inb(base + STATUS_REG); pio_int_reg = inb(base + PIO_INT_REG); @@ -854,6 +840,5 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 1, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 9e0908d1981a..d39107b7669b 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -207,10 +207,9 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid) /* * Bounce back the sense data to user. */ - memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); memcpy(cmd->sense_buffer, cp->sns_bbuf, - min(sizeof(cmd->sense_buffer), - (size_t)SYM_SNS_BBUF_LEN)); + min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN)); #if 0 /* * If the device reports a UNIT ATTENTION condition @@ -609,22 +608,24 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) */ #define WAIT_FOR_PCI_RECOVERY 35 if (pci_channel_offline(pdev)) { - struct completion *io_reset; int finished_reset = 0; init_completion(&eh_done); spin_lock_irq(shost->host_lock); /* Make sure we didn't race */ if (pci_channel_offline(pdev)) { - if (!sym_data->io_reset) - sym_data->io_reset = &eh_done; - io_reset = sym_data->io_reset; + BUG_ON(sym_data->io_reset); + sym_data->io_reset = &eh_done; } else { finished_reset = 1; } spin_unlock_irq(shost->host_lock); if (!finished_reset) - finished_reset = wait_for_completion_timeout(io_reset, + finished_reset = wait_for_completion_timeout + (sym_data->io_reset, WAIT_FOR_PCI_RECOVERY*HZ); + spin_lock_irq(shost->host_lock); + sym_data->io_reset = NULL; + spin_unlock_irq(shost->host_lock); if (!finished_reset) return SCSI_FAILED; } @@ -1680,7 +1681,6 @@ static struct scsi_host_template sym2_template = { .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .this_id = 7, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, .max_sectors = 0xFFFF, #ifdef SYM_LINUX_PROC_INFO_SUPPORT .proc_info = sym53c8xx_proc_info, @@ -1744,7 +1744,7 @@ static int __devinit sym2_probe(struct pci_dev *pdev, return -ENODEV; } -static void __devexit sym2_remove(struct pci_dev *pdev) +static void sym2_remove(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); @@ -1879,7 +1879,6 @@ static void sym2_io_resume(struct pci_dev *pdev) spin_lock_irq(shost->host_lock); if (sym_data->io_reset) complete_all(sym_data->io_reset); - sym_data->io_reset = NULL; spin_unlock_irq(shost->host_lock); } @@ -2056,7 +2055,7 @@ static struct pci_driver sym2_driver = { .name = NAME53C8XX, .id_table = sym2_id_table, .probe = sym2_probe, - .remove = __devexit_p(sym2_remove), + .remove = sym2_remove, .err_handler = &sym2_err_handler, }; diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 44193049c4ae..5b04ddfed26c 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -444,7 +444,7 @@ static int dc390_pci_map (struct dc390_srb* pSRB) /* Map sense buffer */ if (pSRB->SRBFlag & AUTO_REQSENSE) { - pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer)); + pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, 1, DMA_FROM_DEVICE); cmdp->saved_dma_handle = sg_dma_address(pSRB->pSegmentList); @@ -599,7 +599,7 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); DC390_write8 (ScsiFifo, 0); DC390_write8 (ScsiFifo, 0); - DC390_write8 (ScsiFifo, sizeof(scmd->sense_buffer)); + DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE); DC390_write8 (ScsiFifo, 0); DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n")); } @@ -1389,7 +1389,7 @@ dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); DC390_write8 (ScsiFifo, 0); DC390_write8 (ScsiFifo, 0); - DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE); DC390_write8 (ScsiFifo, 0); DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n")); } diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 7edd6ceb13b2..662c00451be4 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -451,7 +451,6 @@ static struct scsi_host_template driver_template = { .this_id = 7, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) @@ -1121,9 +1120,9 @@ static void map_dma(unsigned int i, unsigned int j) { if (SCpnt->sense_buffer) cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, - sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE)); + SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); - cpp->sense_len = sizeof SCpnt->sense_buffer; + cpp->sense_len = SCSI_SENSE_BUFFERSIZE; if (scsi_bufflen(SCpnt)) { count = scsi_dma_map(SCpnt); diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 6d1f0edd7985..f385dce8dfbe 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -298,9 +298,16 @@ static inline int find_and_clear_bit_16(unsigned long *field) { int rv; - if (*field == 0) panic("No free mscp"); - asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b" - : "=&r" (rv), "=m" (*field) : "1" (*field)); + if (*field == 0) + panic("No free mscp"); + + asm volatile ( + "xorl %0,%0\n\t" + "0: bsfw %1,%w0\n\t" + "btr %0,%1\n\t" + "jnc 0b" + : "=&r" (rv), "=m" (*field) :); + return rv; } @@ -741,7 +748,7 @@ static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt, } my_mscp->command_link = 0; /*???*/ my_mscp->scsi_command_link_id = 0; /*???*/ - my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer; + my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE; my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len; memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs); my_mscp->adapter_status = 0; @@ -1197,6 +1204,5 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index fdbb92d1f722..f286c37da7e0 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -407,16 +407,16 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd, * - SCp.phase records this command's SRCID_ER bit setting */ - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; + if (scsi_bufflen(cmd)) { + cmd->SCp.buffer = scsi_sglist(cmd); + cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; + cmd->SCp.ptr = NULL; + cmd->SCp.this_residual = 0; } /* WD docs state that at the conclusion of a "LEVEL2" command, the diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 03cd44f231df..c975c01b3a02 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1108,13 +1108,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt, scb->host = host; nseg = scsi_sg_count(SCpnt); - if (nseg) { + if (nseg > 1) { struct scatterlist *sg; unsigned i; - if (SCpnt->device->host->sg_tablesize == SG_NONE) { - panic("wd7000_queuecommand: scatter/gather not supported.\n"); - } dprintk("Using scatter/gather with %d elements.\n", nseg); sgb = scb->sgb; @@ -1128,7 +1125,10 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt, } } else { scb->op = 0; - any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt))); + if (nseg) { + struct scatterlist *sg = scsi_sglist(SCpnt); + any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset); + } any2scsi(scb->maxlen, scsi_bufflen(SCpnt)); } @@ -1524,7 +1524,7 @@ static __init int wd7000_detect(struct scsi_host_template *tpnt) * For boards before rev 6.0, scatter/gather isn't supported. */ if (host->rev1 < 6) - sh->sg_tablesize = SG_NONE; + sh->sg_tablesize = 1; present++; /* count it */ @@ -1671,7 +1671,6 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 1, .unchecked_isa_dma = 1, .use_clustering = ENABLE_CLUSTERING, - .use_sg_chaining = ENABLE_SG_CHAINING, }; #include "scsi_module.c" diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index facb67855619..6a48dfa1efe8 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -277,6 +277,8 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_iflag & INPCK) port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + tty_encode_baud_rate(tty, baud, baud); + /* * Which character status flags should we ignore? */ diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 6f475b609864..ac2a3ef28d55 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -442,7 +442,8 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart) set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, INTR_ON_BUF, DIMENSION_LINEAR, - DATA_SIZE_8)); + DATA_SIZE_8, + DMA_SYNC_RESTART)); set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); @@ -689,7 +690,8 @@ static int bfin_serial_startup(struct uart_port *port) set_dma_config(uart->rx_dma_channel, set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, INTR_ON_ROW, DIMENSION_2D, - DATA_SIZE_8)); + DATA_SIZE_8, + DMA_SYNC_RESTART)); set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT); set_dma_x_modify(uart->rx_dma_channel, 1); set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT); diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 9d3105b64a7a..9c2df5c857cf 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c @@ -48,7 +48,7 @@ #include <linux/vmalloc.h> #include <linux/smp.h> #include <linux/spinlock.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/firmware.h> #include <linux/bitops.h> @@ -65,7 +65,7 @@ #define ICOM_VERSION_STR "1.3.1" #define NR_PORTS 128 #define ICOM_PORT ((struct icom_port *)port) -#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj) +#define to_icom_adapter(d) container_of(d, struct icom_adapter, kref) static const struct pci_device_id icom_pci_table[] = { { @@ -141,6 +141,7 @@ static inline void trace(struct icom_port *, char *, unsigned long) {}; #else static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {}; #endif +static void icom_kref_release(struct kref *kref); static void free_port_memory(struct icom_port *icom_port) { @@ -1063,11 +1064,11 @@ static int icom_open(struct uart_port *port) { int retval; - kobject_get(&ICOM_PORT->adapter->kobj); + kref_get(&ICOM_PORT->adapter->kref); retval = startup(ICOM_PORT); if (retval) { - kobject_put(&ICOM_PORT->adapter->kobj); + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); trace(ICOM_PORT, "STARTUP_ERROR", 0); return retval; } @@ -1088,7 +1089,7 @@ static void icom_close(struct uart_port *port) shutdown(ICOM_PORT); - kobject_put(&ICOM_PORT->adapter->kobj); + kref_put(&ICOM_PORT->adapter->kref, icom_kref_release); } static void icom_set_termios(struct uart_port *port, @@ -1485,18 +1486,14 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) pci_release_regions(icom_adapter->pci_dev); } -static void icom_kobj_release(struct kobject *kobj) +static void icom_kref_release(struct kref *kref) { struct icom_adapter *icom_adapter; - icom_adapter = to_icom_adapter(kobj); + icom_adapter = to_icom_adapter(kref); icom_remove_adapter(icom_adapter); } -static struct kobj_type icom_kobj_type = { - .release = icom_kobj_release, -}; - static int __devinit icom_probe(struct pci_dev *dev, const struct pci_device_id *ent) { @@ -1592,8 +1589,7 @@ static int __devinit icom_probe(struct pci_dev *dev, } } - kobject_init(&icom_adapter->kobj); - icom_adapter->kobj.ktype = &icom_kobj_type; + kref_init(&icom_adapter->kref); return 0; probe_exit2: @@ -1619,7 +1615,7 @@ static void __devexit icom_remove(struct pci_dev *dev) icom_adapter = list_entry(tmp, struct icom_adapter, icom_adapter_entry); if (icom_adapter->pci_dev == dev) { - kobject_put(&icom_adapter->kobj); + kref_put(&icom_adapter->kref, icom_kref_release); return; } } diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h index e8578d8cd35e..027455496745 100644 --- a/drivers/serial/icom.h +++ b/drivers/serial/icom.h @@ -270,7 +270,7 @@ struct icom_adapter { #define V2_ONE_PORT_RVX_ONE_PORT_IMBED_MDM 0x0251 int numb_ports; struct list_head icom_adapter_entry; - struct kobject kobj; + struct kref kref; }; /* prototype */ diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 73440e26834b..ddf639144538 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -302,7 +302,7 @@ static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag) } sci_out(port, SCFCR, fcr_val); } -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || defined(CONFIG_CPU_SUBTYPE_SH7721) static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) { unsigned int fcr_val = 0; @@ -395,7 +395,8 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } else { #ifdef CONFIG_CPU_SUBTYPE_SH7343 /* Nothing */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \ +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) || \ defined(CONFIG_CPU_SUBTYPE_SHX3) ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ @@ -408,6 +409,7 @@ 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) diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index d24621ce799a..f5764ebcfe07 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -46,7 +46,8 @@ */ # define SCSCR_INIT(port) (port->mapbase == SCIF2) ? 0xF3 : 0xF0 # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCIF_ONLY #define SCIF_ORER 0x0200 /* overrun error bit */ @@ -119,6 +120,12 @@ # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCI_ONLY # define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port) +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +# define SCSPTR0 0xffe00024 /* 16 bit SCIF */ +# define SCSPTR1 0xffe08024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH7770) # define SCSPTR0 0xff923020 /* 16 bit SCIF */ # define SCSPTR1 0xff924020 /* 16 bit SCIF */ @@ -142,7 +149,9 @@ # define SCIF_OPER 0x0001 /* Overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ + defined(CONFIG_CPU_SUBTYPE_SH7206) || \ + defined(CONFIG_CPU_SUBTYPE_SH7263) # define SCSPTR0 0xfffe8020 /* 16 bit SCIF */ # define SCSPTR1 0xfffe8820 /* 16 bit SCIF */ # define SCSPTR2 0xfffe9020 /* 16 bit SCIF */ @@ -214,7 +223,8 @@ #define SCIF_DR 0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */ #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + 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 @@ -252,7 +262,8 @@ # define SCxSR_PER(port) SCIF_PER # define SCxSR_BRK(port) SCIF_BRK #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) # define SCxSR_RDxF_CLEAR(port) (sci_in(port,SCxSR)&0xfffc) # define SCxSR_ERROR_CLEAR(port) (sci_in(port,SCxSR)&0xfd73) # define SCxSR_TDxE_CLEAR(port) (sci_in(port,SCxSR)&0xffdf) @@ -361,7 +372,8 @@ #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size) #elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCIF_FNS(name, scif_offset, scif_size) \ CPU_SCIF_FNS(name, scif_offset, scif_size) #else @@ -388,7 +400,8 @@ #endif #if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) SCIF_FNS(SCSMR, 0x00, 16) SCIF_FNS(SCBRR, 0x04, 8) @@ -412,6 +425,7 @@ SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8) SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8) SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16) #if defined(CONFIG_CPU_SUBTYPE_SH7760) || \ + defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ defined(CONFIG_CPU_SUBTYPE_SH7785) SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16) @@ -510,7 +524,8 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port) return; } } -#elif defined(CONFIG_CPU_SUBTYPE_SH7720) +#elif defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xa4430000) @@ -580,6 +595,15 @@ static inline int sci_rxd_in(struct uart_port *port) int ch = (port->mapbase - SMR0) >> 3; return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0; } +#elif defined(CONFIG_CPU_SUBTYPE_SH7763) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffe00000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffe08000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + return 1; +} #elif defined(CONFIG_CPU_SUBTYPE_SH7770) static inline int sci_rxd_in(struct uart_port *port) { @@ -617,7 +641,9 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7206) +#elif defined(CONFIG_CPU_SUBTYPE_SH7203) || \ + defined(CONFIG_CPU_SUBTYPE_SH7206) || \ + defined(CONFIG_CPU_SUBTYPE_SH7263) static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xfffe8000) @@ -688,11 +714,13 @@ static inline int sci_rxd_in(struct uart_port *port) * -- Mitch Davis - 15 Jul 2000 */ -#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \ +#if defined(CONFIG_CPU_SUBTYPE_SH7763) || \ + 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) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) + defined(CONFIG_CPU_SUBTYPE_SH7720) || \ + defined(CONFIG_CPU_SUBTYPE_SH7721) #define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1) #elif defined(__H8300H__) || defined(__H8300S__) #define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index abf05048c638..aaaea81e412a 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -153,6 +153,7 @@ config SPI_OMAP24XX config SPI_PXA2XX tristate "PXA2xx SSP SPI master" depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL + select PXA_SSP help This enables using a PXA2xx SSP port as a SPI master controller. The driver can be configured to use any SSP port and additional diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index 3cdab131c4a9..ea61724ae225 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -350,6 +350,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) tx = xfer->tx_buf; do { + c -= 1; if (tx != NULL) { if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXS) < 0) { @@ -380,7 +381,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) word_len, *(rx - 1)); #endif } - c -= 1; } while (c); } else if (word_len <= 16) { u16 *rx; @@ -389,6 +389,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { + c -= 2; if (tx != NULL) { if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXS) < 0) { @@ -419,7 +420,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) word_len, *(rx - 1)); #endif } - c -= 2; } while (c); } else if (word_len <= 32) { u32 *rx; @@ -428,6 +428,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { + c -= 4; if (tx != NULL) { if (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXS) < 0) { @@ -458,7 +459,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) word_len, *(rx - 1)); #endif } - c -= 4; } while (c); } diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index 1c2ab541d37d..eb817b8eb024 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -27,6 +27,7 @@ #include <linux/spi/spi.h> #include <linux/workqueue.h> #include <linux/delay.h> +#include <linux/clk.h> #include <asm/io.h> #include <asm/irq.h> @@ -36,6 +37,8 @@ #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> +#include <asm/arch/regs-ssp.h> +#include <asm/arch/ssp.h> #include <asm/arch/pxa2xx_spi.h> MODULE_AUTHOR("Stephen Street"); @@ -80,6 +83,9 @@ struct driver_data { /* Driver model hookup */ struct platform_device *pdev; + /* SSP Info */ + struct ssp_device *ssp; + /* SPI framework hookup */ enum pxa_ssp_type ssp_type; struct spi_master *master; @@ -778,6 +784,16 @@ int set_dma_burst_and_threshold(struct chip_data *chip, struct spi_device *spi, return retval; } +static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate) +{ + unsigned long ssp_clk = clk_get_rate(ssp->clk); + + if (ssp->type == PXA25x_SSP) + return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; + else + return ((ssp_clk / rate - 1) & 0xfff) << 8; +} + static void pump_transfers(unsigned long data) { struct driver_data *drv_data = (struct driver_data *)data; @@ -785,6 +801,7 @@ static void pump_transfers(unsigned long data) struct spi_transfer *transfer = NULL; struct spi_transfer *previous = NULL; struct chip_data *chip = NULL; + struct ssp_device *ssp = drv_data->ssp; void *reg = drv_data->ioaddr; u32 clk_div = 0; u8 bits = 0; @@ -866,12 +883,7 @@ static void pump_transfers(unsigned long data) if (transfer->bits_per_word) bits = transfer->bits_per_word; - if (reg == SSP1_VIRT) - clk_div = SSP1_SerClkDiv(speed); - else if (reg == SSP2_VIRT) - clk_div = SSP2_SerClkDiv(speed); - else if (reg == SSP3_VIRT) - clk_div = SSP3_SerClkDiv(speed); + clk_div = ssp_get_clk_div(ssp, speed); if (bits <= 8) { drv_data->n_bytes = 1; @@ -1074,6 +1086,7 @@ static int setup(struct spi_device *spi) struct pxa2xx_spi_chip *chip_info = NULL; struct chip_data *chip; struct driver_data *drv_data = spi_master_get_devdata(spi->master); + struct ssp_device *ssp = drv_data->ssp; unsigned int clk_div; if (!spi->bits_per_word) @@ -1157,18 +1170,7 @@ static int setup(struct spi_device *spi) } } - if (drv_data->ioaddr == SSP1_VIRT) - clk_div = SSP1_SerClkDiv(spi->max_speed_hz); - else if (drv_data->ioaddr == SSP2_VIRT) - clk_div = SSP2_SerClkDiv(spi->max_speed_hz); - else if (drv_data->ioaddr == SSP3_VIRT) - clk_div = SSP3_SerClkDiv(spi->max_speed_hz); - else - { - dev_err(&spi->dev, "failed setup: unknown IO address=0x%p\n", - drv_data->ioaddr); - return -ENODEV; - } + clk_div = ssp_get_clk_div(ssp, spi->max_speed_hz); chip->speed_hz = spi->max_speed_hz; chip->cr0 = clk_div @@ -1183,15 +1185,15 @@ static int setup(struct spi_device *spi) /* NOTE: PXA25x_SSP _could_ use external clocking ... */ if (drv_data->ssp_type != PXA25x_SSP) - dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n", + dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n", spi->bits_per_word, - (CLOCK_SPEED_HZ) + clk_get_rate(ssp->clk) / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)), spi->mode & 0x3); else - dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n", + dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n", spi->bits_per_word, - (CLOCK_SPEED_HZ/2) + clk_get_rate(ssp->clk) / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)), spi->mode & 0x3); @@ -1323,14 +1325,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) struct pxa2xx_spi_master *platform_info; struct spi_master *master; struct driver_data *drv_data = 0; - struct resource *memory_resource; - int irq; + struct ssp_device *ssp; int status = 0; platform_info = dev->platform_data; - if (platform_info->ssp_type == SSP_UNDEFINED) { - dev_err(&pdev->dev, "undefined SSP\n"); + ssp = ssp_request(pdev->id, pdev->name); + if (ssp == NULL) { + dev_err(&pdev->dev, "failed to request SSP%d\n", pdev->id); return -ENODEV; } @@ -1338,12 +1340,14 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) master = spi_alloc_master(dev, sizeof(struct driver_data) + 16); if (!master) { dev_err(&pdev->dev, "can not alloc spi_master\n"); + ssp_free(ssp); return -ENOMEM; } drv_data = spi_master_get_devdata(master); drv_data->master = master; drv_data->master_info = platform_info; drv_data->pdev = pdev; + drv_data->ssp = ssp; master->bus_num = pdev->id; master->num_chipselect = platform_info->num_chipselect; @@ -1351,21 +1355,13 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) master->setup = setup; master->transfer = transfer; - drv_data->ssp_type = platform_info->ssp_type; + drv_data->ssp_type = ssp->type; drv_data->null_dma_buf = (u32 *)ALIGN((u32)(drv_data + sizeof(struct driver_data)), 8); - /* Setup register addresses */ - memory_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!memory_resource) { - dev_err(&pdev->dev, "memory resources not defined\n"); - status = -ENODEV; - goto out_error_master_alloc; - } - - drv_data->ioaddr = (void *)io_p2v((unsigned long)(memory_resource->start)); - drv_data->ssdr_physical = memory_resource->start + 0x00000010; - if (platform_info->ssp_type == PXA25x_SSP) { + drv_data->ioaddr = ssp->mmio_base; + drv_data->ssdr_physical = ssp->phys_base + SSDR; + if (ssp->type == PXA25x_SSP) { drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; drv_data->dma_cr1 = 0; drv_data->clear_sr = SSSR_ROR; @@ -1377,15 +1373,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR; } - /* Attach to IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "irq resource not defined\n"); - status = -ENODEV; - goto out_error_master_alloc; - } - - status = request_irq(irq, ssp_int, 0, dev->bus_id, drv_data); + status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data); if (status < 0) { dev_err(&pdev->dev, "can not get IRQ\n"); goto out_error_master_alloc; @@ -1418,29 +1406,12 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) goto out_error_dma_alloc; } - if (drv_data->ioaddr == SSP1_VIRT) { - DRCMRRXSSDR = DRCMR_MAPVLD - | drv_data->rx_channel; - DRCMRTXSSDR = DRCMR_MAPVLD - | drv_data->tx_channel; - } else if (drv_data->ioaddr == SSP2_VIRT) { - DRCMRRXSS2DR = DRCMR_MAPVLD - | drv_data->rx_channel; - DRCMRTXSS2DR = DRCMR_MAPVLD - | drv_data->tx_channel; - } else if (drv_data->ioaddr == SSP3_VIRT) { - DRCMRRXSS3DR = DRCMR_MAPVLD - | drv_data->rx_channel; - DRCMRTXSS3DR = DRCMR_MAPVLD - | drv_data->tx_channel; - } else { - dev_err(dev, "bad SSP type\n"); - goto out_error_dma_alloc; - } + DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel; + DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel; } /* Enable SOC clock */ - pxa_set_cken(platform_info->clock_enable, 1); + clk_enable(ssp->clk); /* Load default SSP configuration */ write_SSCR0(0, drv_data->ioaddr); @@ -1479,7 +1450,7 @@ out_error_queue_alloc: destroy_queue(drv_data); out_error_clock_enabled: - pxa_set_cken(platform_info->clock_enable, 0); + clk_disable(ssp->clk); out_error_dma_alloc: if (drv_data->tx_channel != -1) @@ -1488,17 +1459,18 @@ out_error_dma_alloc: pxa_free_dma(drv_data->rx_channel); out_error_irq_alloc: - free_irq(irq, drv_data); + free_irq(ssp->irq, drv_data); out_error_master_alloc: spi_master_put(master); + ssp_free(ssp); return status; } static int pxa2xx_spi_remove(struct platform_device *pdev) { struct driver_data *drv_data = platform_get_drvdata(pdev); - int irq; + struct ssp_device *ssp = drv_data->ssp; int status = 0; if (!drv_data) @@ -1520,28 +1492,21 @@ static int pxa2xx_spi_remove(struct platform_device *pdev) /* Disable the SSP at the peripheral and SOC level */ write_SSCR0(0, drv_data->ioaddr); - pxa_set_cken(drv_data->master_info->clock_enable, 0); + clk_disable(ssp->clk); /* Release DMA */ if (drv_data->master_info->enable_dma) { - if (drv_data->ioaddr == SSP1_VIRT) { - DRCMRRXSSDR = 0; - DRCMRTXSSDR = 0; - } else if (drv_data->ioaddr == SSP2_VIRT) { - DRCMRRXSS2DR = 0; - DRCMRTXSS2DR = 0; - } else if (drv_data->ioaddr == SSP3_VIRT) { - DRCMRRXSS3DR = 0; - DRCMRTXSS3DR = 0; - } + DRCMR(ssp->drcmr_rx) = 0; + DRCMR(ssp->drcmr_tx) = 0; pxa_free_dma(drv_data->tx_channel); pxa_free_dma(drv_data->rx_channel); } /* Release IRQ */ - irq = platform_get_irq(pdev, 0); - if (irq >= 0) - free_irq(irq, drv_data); + free_irq(ssp->irq, drv_data); + + /* Release SSP */ + ssp_free(ssp); /* Disconnect from the SPI framework */ spi_unregister_master(drv_data->master); @@ -1576,6 +1541,7 @@ static int suspend_devices(struct device *dev, void *pm_message) static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state) { struct driver_data *drv_data = platform_get_drvdata(pdev); + struct ssp_device *ssp = drv_data->ssp; int status = 0; /* Check all childern for current power state */ @@ -1588,7 +1554,7 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state) if (status != 0) return status; write_SSCR0(0, drv_data->ioaddr); - pxa_set_cken(drv_data->master_info->clock_enable, 0); + clk_disable(ssp->clk); return 0; } @@ -1596,10 +1562,11 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state) static int pxa2xx_spi_resume(struct platform_device *pdev) { struct driver_data *drv_data = platform_get_drvdata(pdev); + struct ssp_device *ssp = drv_data->ssp; int status = 0; /* Enable the SSP clock */ - pxa_set_cken(drv_data->master_info->clock_enable, 1); + clk_disable(ssp->clk); /* Start the queue running */ status = start_queue(drv_data); diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 93e9de46977a..682a6a48fec3 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -485,6 +485,15 @@ void spi_unregister_master(struct spi_master *master) } EXPORT_SYMBOL_GPL(spi_unregister_master); +static int __spi_master_match(struct device *dev, void *data) +{ + struct spi_master *m; + u16 *bus_num = data; + + m = container_of(dev, struct spi_master, dev); + return m->bus_num == *bus_num; +} + /** * spi_busnum_to_master - look up master associated with bus_num * @bus_num: the master's bus number @@ -499,17 +508,12 @@ struct spi_master *spi_busnum_to_master(u16 bus_num) { struct device *dev; struct spi_master *master = NULL; - struct spi_master *m; - - down(&spi_master_class.sem); - list_for_each_entry(dev, &spi_master_class.children, node) { - m = container_of(dev, struct spi_master, dev); - if (m->bus_num == bus_num) { - master = spi_master_get(m); - break; - } - } - up(&spi_master_class.sem); + + dev = class_find_device(&spi_master_class, &bus_num, + __spi_master_match); + if (dev) + master = container_of(dev, struct spi_master, dev); + /* reference got in class_find_device */ return master; } EXPORT_SYMBOL_GPL(spi_busnum_to_master); diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index f145d8a4cfde..1a31f7a72848 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -27,6 +27,8 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4329) }, { 0, }, }; MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl); diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 85a20546e827..9028ed5715a1 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -872,14 +872,22 @@ EXPORT_SYMBOL(ssb_clockspeed); static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev) { + u32 rev = ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV; + /* The REJECT bit changed position in TMSLOW between * Backplane revisions. */ - switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) { + switch (rev) { case SSB_IDLOW_SSBREV_22: return SSB_TMSLOW_REJECT_22; case SSB_IDLOW_SSBREV_23: return SSB_TMSLOW_REJECT_23; + case SSB_IDLOW_SSBREV_24: /* TODO - find the proper REJECT bits */ + case SSB_IDLOW_SSBREV_25: /* same here */ + case SSB_IDLOW_SSBREV_26: /* same here */ + case SSB_IDLOW_SSBREV_27: /* same here */ + return SSB_TMSLOW_REJECT_23; /* this is a guess */ default: + printk(KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev); WARN_ON(1); } return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23); diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 0ab095c6581a..b434df75047f 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -212,29 +212,29 @@ static inline u8 ssb_crc8(u8 crc, u8 data) return t[crc ^ data]; } -static u8 ssb_sprom_crc(const u16 *sprom) +static u8 ssb_sprom_crc(const u16 *sprom, u16 size) { int word; u8 crc = 0xFF; - for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) { + for (word = 0; word < size - 1; word++) { crc = ssb_crc8(crc, sprom[word] & 0x00FF); crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8); } - crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF); + crc = ssb_crc8(crc, sprom[size - 1] & 0x00FF); crc ^= 0xFF; return crc; } -static int sprom_check_crc(const u16 *sprom) +static int sprom_check_crc(const u16 *sprom, u16 size) { u8 crc; u8 expected_crc; u16 tmp; - crc = ssb_sprom_crc(sprom); - tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC; + crc = ssb_sprom_crc(sprom, size); + tmp = sprom[size - 1] & SSB_SPROM_REVISION_CRC; expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT; if (crc != expected_crc) return -EPROTO; @@ -246,8 +246,8 @@ static void sprom_do_read(struct ssb_bus *bus, u16 *sprom) { int i; - for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) - sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2)); + for (i = 0; i < bus->sprom_size; i++) + sprom[i] = ioread16(bus->mmio + SSB_SPROM_BASE + (i * 2)); } static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) @@ -255,6 +255,7 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) struct pci_dev *pdev = bus->host_pci; int i, err; u32 spromctl; + u16 size = bus->sprom_size; ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl); @@ -266,12 +267,12 @@ static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom) goto err_ctlreg; ssb_printk(KERN_NOTICE PFX "[ 0%%"); msleep(500); - for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { - if (i == SSB_SPROMSIZE_WORDS / 4) + for (i = 0; i < size; i++) { + if (i == size / 4) ssb_printk("25%%"); - else if (i == SSB_SPROMSIZE_WORDS / 2) + else if (i == size / 2) ssb_printk("50%%"); - else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3) + else if (i == (size * 3) / 4) ssb_printk("75%%"); else if (i % 2) ssb_printk("."); @@ -296,24 +297,53 @@ err_ctlreg: return err; } -static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) +static s8 r123_extract_antgain(u8 sprom_revision, const u16 *in, + u16 mask, u16 shift) +{ + u16 v; + u8 gain; + + v = in[SPOFF(SSB_SPROM1_AGAIN)]; + gain = (v & mask) >> shift; + if (gain == 0xFF) + gain = 2; /* If unset use 2dBm */ + if (sprom_revision == 1) { + /* Convert to Q5.2 */ + gain <<= 2; + } else { + /* Q5.2 Fractional part is stored in 0xC0 */ + gain = ((gain & 0xC0) >> 6) | ((gain & 0x3F) << 2); + } + + return (s8)gain; +} + +static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) { int i; u16 v; + s8 gain; + u16 loc[3]; - SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0); - SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0); - SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0); + if (out->revision == 3) { /* rev 3 moved MAC */ + loc[0] = SSB_SPROM3_IL0MAC; + loc[1] = SSB_SPROM3_ET0MAC; + loc[2] = SSB_SPROM3_ET1MAC; + } else { + loc[0] = SSB_SPROM1_IL0MAC; + loc[1] = SSB_SPROM1_ET0MAC; + loc[2] = SSB_SPROM1_ET1MAC; + } for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM1_IL0MAC) + i]; + v = in[SPOFF(loc[0]) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM1_ET0MAC) + i]; + v = in[SPOFF(loc[1]) + i]; *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); } for (i = 0; i < 3; i++) { - v = in[SPOFF(SSB_SPROM1_ET1MAC) + i]; + v = in[SPOFF(loc[2]) + i]; *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); } SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0); @@ -324,9 +354,9 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, SSB_SPROM1_BINF_CCODE_SHIFT); - SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, + SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, SSB_SPROM1_BINF_ANTA_SHIFT); - SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, + SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, SSB_SPROM1_BINF_ANTBG_SHIFT); SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0); SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0); @@ -347,100 +377,108 @@ static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in) SSB_SPROM1_ITSSI_A_SHIFT); SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0); SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); - SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0); - SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG, - SSB_SPROM1_AGAIN_BG_SHIFT); - for (i = 0; i < 4; i++) { - v = in[SPOFF(SSB_SPROM1_OEM) + i]; - *(((__le16 *)out->oem) + i) = cpu_to_le16(v); - } + if (out->revision >= 2) + SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + + /* Extract the antenna gain values. */ + gain = r123_extract_antgain(out->revision, in, + SSB_SPROM1_AGAIN_BG, + SSB_SPROM1_AGAIN_BG_SHIFT); + out->antenna_gain.ghz24.a0 = gain; + out->antenna_gain.ghz24.a1 = gain; + out->antenna_gain.ghz24.a2 = gain; + out->antenna_gain.ghz24.a3 = gain; + gain = r123_extract_antgain(out->revision, in, + SSB_SPROM1_AGAIN_A, + SSB_SPROM1_AGAIN_A_SHIFT); + out->antenna_gain.ghz5.a0 = gain; + out->antenna_gain.ghz5.a1 = gain; + out->antenna_gain.ghz5.a2 = gain; + out->antenna_gain.ghz5.a3 = gain; } -static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in) +static void sprom_extract_r4(struct ssb_sprom *out, const u16 *in) { int i; u16 v; - SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); - SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0); - SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO, - SSB_SPROM2_MAXP_A_LO_SHIFT); - SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0); - SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0); - SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0); - SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0); - SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0); - SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0); - SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0); - for (i = 0; i < 4; i++) { - v = in[SPOFF(SSB_SPROM2_CCODE) + i]; - *(((__le16 *)out->country_str) + i) = cpu_to_le16(v); + /* extract the equivalent of the r1 variables */ + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM4_IL0MAC) + i]; + *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM4_ET0MAC) + i]; + *(((__be16 *)out->et0mac) + i) = cpu_to_be16(v); + } + for (i = 0; i < 3; i++) { + v = in[SPOFF(SSB_SPROM4_ET1MAC) + i]; + *(((__be16 *)out->et1mac) + i) = cpu_to_be16(v); + } + SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); + SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, + SSB_SPROM4_ETHPHY_ET1A_SHIFT); + SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); + SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); + SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); + SPEX(ant_available_a, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_A, + SSB_SPROM4_ANTAVAIL_A_SHIFT); + SPEX(ant_available_bg, SSB_SPROM4_ANTAVAIL, SSB_SPROM4_ANTAVAIL_BG, + SSB_SPROM4_ANTAVAIL_BG_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_MAXP_BG_MASK, 0); + SPEX(itssi_bg, SSB_SPROM4_MAXP_BG, SSB_SPROM4_ITSSI_BG, + SSB_SPROM4_ITSSI_BG_SHIFT); + SPEX(maxpwr_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_MAXP_A_MASK, 0); + SPEX(itssi_a, SSB_SPROM4_MAXP_A, SSB_SPROM4_ITSSI_A, + SSB_SPROM4_ITSSI_A_SHIFT); + SPEX(gpio0, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM4_GPIOA, SSB_SPROM4_GPIOA_P1, + SSB_SPROM4_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM4_GPIOB, SSB_SPROM4_GPIOB_P3, + SSB_SPROM4_GPIOB_P3_SHIFT); + + /* Extract the antenna gain values. */ + SPEX(antenna_gain.ghz24.a0, SSB_SPROM4_AGAIN01, + SSB_SPROM4_AGAIN0, SSB_SPROM4_AGAIN0_SHIFT); + SPEX(antenna_gain.ghz24.a1, SSB_SPROM4_AGAIN01, + SSB_SPROM4_AGAIN1, SSB_SPROM4_AGAIN1_SHIFT); + SPEX(antenna_gain.ghz24.a2, SSB_SPROM4_AGAIN23, + SSB_SPROM4_AGAIN2, SSB_SPROM4_AGAIN2_SHIFT); + SPEX(antenna_gain.ghz24.a3, SSB_SPROM4_AGAIN23, + SSB_SPROM4_AGAIN3, SSB_SPROM4_AGAIN3_SHIFT); + memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24, + sizeof(out->antenna_gain.ghz5)); + + /* TODO - get remaining rev 4 stuff needed */ } -static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in) -{ - out->ofdmapo = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8; - out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8; - out->ofdmapo <<= 16; - out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8; - out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8; - - out->ofdmalpo = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8; - out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8; - out->ofdmalpo <<= 16; - out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8; - out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8; - - out->ofdmahpo = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8; - out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8; - out->ofdmahpo <<= 16; - out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8; - out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8; - - SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON, - SSB_SPROM3_GPIOLDC_ON_SHIFT); - SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF, - SSB_SPROM3_GPIOLDC_OFF_SHIFT); - SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0); - SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M, - SSB_SPROM3_CCKPO_2M_SHIFT); - SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M, - SSB_SPROM3_CCKPO_55M_SHIFT); - SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M, - SSB_SPROM3_CCKPO_11M_SHIFT); - - out->ofdmgpo = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8; - out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8; - out->ofdmgpo <<= 16; - out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8; - out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8; -} - -static int sprom_extract(struct ssb_bus *bus, - struct ssb_sprom *out, const u16 *in) +static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, + const u16 *in, u16 size) { memset(out, 0, sizeof(*out)); - SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0); - SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC, - SSB_SPROM_REVISION_CRC_SHIFT); - + out->revision = in[size - 1] & 0x00FF; + ssb_dprintk(KERN_DEBUG PFX "SPROM revision %d detected.\n", out->revision); if ((bus->chip_id & 0xFF00) == 0x4400) { /* Workaround: The BCM44XX chip has a stupid revision * number stored in the SPROM. * Always extract r1. */ - sprom_extract_r1(&out->r1, in); + out->revision = 1; + sprom_extract_r123(out, in); + } else if (bus->chip_id == 0x4321) { + /* the BCM4328 has a chipid == 0x4321 and a rev 4 SPROM */ + out->revision = 4; + sprom_extract_r4(out, in); } else { if (out->revision == 0) goto unsupported; - if (out->revision >= 1 && out->revision <= 3) - sprom_extract_r1(&out->r1, in); - if (out->revision >= 2 && out->revision <= 3) - sprom_extract_r2(&out->r2, in); - if (out->revision == 3) - sprom_extract_r3(&out->r3, in); - if (out->revision >= 4) + if (out->revision >= 1 && out->revision <= 3) { + sprom_extract_r123(out, in); + } + if (out->revision == 4) + sprom_extract_r4(out, in); + if (out->revision >= 5) goto unsupported; } @@ -448,7 +486,7 @@ static int sprom_extract(struct ssb_bus *bus, unsupported: ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d " "detected. Will extract v1\n", out->revision); - sprom_extract_r1(&out->r1, in); + sprom_extract_r123(out, in); return 0; } @@ -458,16 +496,29 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, int err = -ENOMEM; u16 *buf; - buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL); if (!buf) goto out; + bus->sprom_size = SSB_SPROMSIZE_WORDS_R123; sprom_do_read(bus, buf); - err = sprom_check_crc(buf); + err = sprom_check_crc(buf, bus->sprom_size); if (err) { - ssb_printk(KERN_WARNING PFX - "WARNING: Invalid SPROM CRC (corrupt SPROM)\n"); + /* check for rev 4 sprom - has special signature */ + if (buf[32] == 0x5372) { + kfree(buf); + buf = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16), + GFP_KERNEL); + if (!buf) + goto out; + bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; + sprom_do_read(bus, buf); + err = sprom_check_crc(buf, bus->sprom_size); + } + if (err) + ssb_printk(KERN_WARNING PFX "WARNING: Invalid" + " SPROM CRC (corrupt SPROM)\n"); } - err = sprom_extract(bus, sprom, buf); + err = sprom_extract(bus, sprom, buf, bus->sprom_size); kfree(buf); out: @@ -581,29 +632,28 @@ const struct ssb_bus_ops ssb_pci_ops = { .write32 = ssb_pci_write32, }; -static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len) +static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, u16 size) { int i, pos = 0; - for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) { + for (i = 0; i < size; i++) pos += snprintf(buf + pos, buf_len - pos - 1, "%04X", swab16(sprom[i]) & 0xFFFF); - } pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); return pos + 1; } -static int hex2sprom(u16 *sprom, const char *dump, size_t len) +static int hex2sprom(u16 *sprom, const char *dump, size_t len, u16 size) { char tmp[5] = { 0 }; int cnt = 0; unsigned long parsed; - if (len < SSB_SPROMSIZE_BYTES * 2) + if (len < size * 2) return -EINVAL; - while (cnt < SSB_SPROMSIZE_WORDS) { + while (cnt < size) { memcpy(tmp, dump, 4); dump += 4; parsed = simple_strtoul(tmp, NULL, 16); @@ -627,7 +677,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, if (!bus) goto out; err = -ENOMEM; - sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); if (!sprom) goto out; @@ -640,7 +690,7 @@ static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev, sprom_do_read(bus, sprom); mutex_unlock(&bus->pci_sprom_mutex); - count = sprom2hex(sprom, buf, PAGE_SIZE); + count = sprom2hex(sprom, buf, PAGE_SIZE, bus->sprom_size); err = 0; out_kfree: @@ -662,15 +712,15 @@ static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev, if (!bus) goto out; err = -ENOMEM; - sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL); + sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); if (!sprom) goto out; - err = hex2sprom(sprom, buf, count); + err = hex2sprom(sprom, buf, count, bus->sprom_size); if (err) { err = -EINVAL; goto out_kfree; } - err = sprom_check_crc(sprom); + err = sprom_check_crc(sprom, bus->sprom_size); if (err) { err = -EINVAL; goto out_kfree; diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index bb44a76b3eb5..46816cda8b98 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c @@ -94,7 +94,6 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, struct ssb_device *dev) { int err; - unsigned long flags; #if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG ssb_printk(KERN_INFO PFX @@ -103,11 +102,9 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, dev->core_index); #endif - spin_lock_irqsave(&bus->bar_lock, flags); err = ssb_pcmcia_switch_coreidx(bus, dev->core_index); if (!err) bus->mapped_device = dev; - spin_unlock_irqrestore(&bus->bar_lock, flags); return err; } @@ -115,14 +112,12 @@ int ssb_pcmcia_switch_core(struct ssb_bus *bus, int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) { int attempts = 0; - unsigned long flags; conf_reg_t reg; - int res, err = 0; + int res; SSB_WARN_ON((seg != 0) && (seg != 1)); reg.Offset = 0x34; reg.Function = 0; - spin_lock_irqsave(&bus->bar_lock, flags); while (1) { reg.Action = CS_WRITE; reg.Value = seg; @@ -143,13 +138,11 @@ int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg) udelay(10); } bus->mapped_pcmcia_seg = seg; -out_unlock: - spin_unlock_irqrestore(&bus->bar_lock, flags); - return err; + + return 0; error: ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n"); - err = -ENODEV; - goto out_unlock; + return -ENODEV; } static int select_core_and_segment(struct ssb_device *dev, @@ -182,22 +175,33 @@ static int select_core_and_segment(struct ssb_device *dev, static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset) { struct ssb_bus *bus = dev->bus; + unsigned long flags; + int err; + u16 value = 0xFFFF; - if (unlikely(select_core_and_segment(dev, &offset))) - return 0xFFFF; + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (likely(!err)) + value = readw(bus->mmio + offset); + spin_unlock_irqrestore(&bus->bar_lock, flags); - return readw(bus->mmio + offset); + return value; } static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) { struct ssb_bus *bus = dev->bus; - u32 lo, hi; + unsigned long flags; + int err; + u32 lo = 0xFFFFFFFF, hi = 0xFFFFFFFF; - if (unlikely(select_core_and_segment(dev, &offset))) - return 0xFFFFFFFF; - lo = readw(bus->mmio + offset); - hi = readw(bus->mmio + offset + 2); + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (likely(!err)) { + lo = readw(bus->mmio + offset); + hi = readw(bus->mmio + offset + 2); + } + spin_unlock_irqrestore(&bus->bar_lock, flags); return (lo | (hi << 16)); } @@ -205,22 +209,31 @@ static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset) static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value) { struct ssb_bus *bus = dev->bus; + unsigned long flags; + int err; - if (unlikely(select_core_and_segment(dev, &offset))) - return; - writew(value, bus->mmio + offset); + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (likely(!err)) + writew(value, bus->mmio + offset); + mmiowb(); + spin_unlock_irqrestore(&bus->bar_lock, flags); } static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value) { struct ssb_bus *bus = dev->bus; + unsigned long flags; + int err; - if (unlikely(select_core_and_segment(dev, &offset))) - return; - writeb((value & 0xFF000000) >> 24, bus->mmio + offset + 3); - writeb((value & 0x00FF0000) >> 16, bus->mmio + offset + 2); - writeb((value & 0x0000FF00) >> 8, bus->mmio + offset + 1); - writeb((value & 0x000000FF) >> 0, bus->mmio + offset + 0); + spin_lock_irqsave(&bus->bar_lock, flags); + err = select_core_and_segment(dev, &offset); + if (likely(!err)) { + writew((value & 0x0000FFFF), bus->mmio + offset); + writew(((value & 0xFFFF0000) >> 16), bus->mmio + offset + 2); + } + mmiowb(); + spin_unlock_irqrestore(&bus->bar_lock, flags); } /* Not "static", as it's used in main.c */ @@ -231,10 +244,12 @@ const struct ssb_bus_ops ssb_pcmcia_ops = { .write32 = ssb_pcmcia_write32, }; +#include <linux/etherdevice.h> int ssb_pcmcia_get_invariants(struct ssb_bus *bus, struct ssb_init_invariants *iv) { //TODO + random_ether_addr(iv->sprom.il0mac); return 0; } diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index 865f32b63b5c..cc246faa3590 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -34,12 +34,12 @@ struct uio_device { wait_queue_head_t wait; int vma_count; struct uio_info *info; - struct kset map_attr_kset; + struct kobject *map_dir; }; static int uio_major; static DEFINE_IDR(uio_idr); -static struct file_operations uio_fops; +static const struct file_operations uio_fops; /* UIO class infrastructure */ static struct uio_class { @@ -51,47 +51,48 @@ static struct uio_class { * attributes */ -static struct attribute attr_addr = { - .name = "addr", - .mode = S_IRUGO, +struct uio_map { + struct kobject kobj; + struct uio_mem *mem; }; +#define to_map(map) container_of(map, struct uio_map, kobj) -static struct attribute attr_size = { - .name = "size", - .mode = S_IRUGO, -}; -static struct attribute* map_attrs[] = { - &attr_addr, &attr_size, NULL -}; - -static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr, +static ssize_t map_attr_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj); + struct uio_map *map = to_map(kobj); + struct uio_mem *mem = map->mem; - if (strncmp(attr->name,"addr",4) == 0) + if (strncmp(attr->attr.name, "addr", 4) == 0) return sprintf(buf, "0x%lx\n", mem->addr); - if (strncmp(attr->name,"size",4) == 0) + if (strncmp(attr->attr.name, "size", 4) == 0) return sprintf(buf, "0x%lx\n", mem->size); return -ENODEV; } -static void map_attr_release(struct kobject *kobj) -{ - /* TODO ??? */ -} +static struct kobj_attribute attr_attribute = + __ATTR(addr, S_IRUGO, map_attr_show, NULL); +static struct kobj_attribute size_attribute = + __ATTR(size, S_IRUGO, map_attr_show, NULL); -static struct sysfs_ops map_attr_ops = { - .show = map_attr_show, +static struct attribute *attrs[] = { + &attr_attribute.attr, + &size_attribute.attr, + NULL, /* need to NULL terminate the list of attributes */ }; +static void map_release(struct kobject *kobj) +{ + struct uio_map *map = to_map(kobj); + kfree(map); +} + static struct kobj_type map_attr_type = { - .release = map_attr_release, - .sysfs_ops = &map_attr_ops, - .default_attrs = map_attrs, + .release = map_release, + .default_attrs = attrs, }; static ssize_t show_name(struct device *dev, @@ -148,6 +149,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) int mi; int map_found = 0; struct uio_mem *mem; + struct uio_map *map; ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp); if (ret) @@ -159,31 +161,34 @@ static int uio_dev_add_attributes(struct uio_device *idev) break; if (!map_found) { map_found = 1; - kobject_set_name(&idev->map_attr_kset.kobj,"maps"); - idev->map_attr_kset.ktype = &map_attr_type; - idev->map_attr_kset.kobj.parent = &idev->dev->kobj; - ret = kset_register(&idev->map_attr_kset); - if (ret) - goto err_remove_group; + idev->map_dir = kobject_create_and_add("maps", + &idev->dev->kobj); + if (!idev->map_dir) + goto err; } - kobject_init(&mem->kobj); - kobject_set_name(&mem->kobj,"map%d",mi); - mem->kobj.parent = &idev->map_attr_kset.kobj; - mem->kobj.kset = &idev->map_attr_kset; - ret = kobject_add(&mem->kobj); + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) + goto err; + kobject_init(&map->kobj, &map_attr_type); + map->mem = mem; + mem->map = map; + ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi); + if (ret) + goto err; + ret = kobject_uevent(&map->kobj, KOBJ_ADD); if (ret) - goto err_remove_maps; + goto err; } return 0; -err_remove_maps: +err: for (mi--; mi>=0; mi--) { mem = &idev->info->mem[mi]; - kobject_unregister(&mem->kobj); + map = mem->map; + kobject_put(&map->kobj); } - kset_unregister(&idev->map_attr_kset); /* Needed ? */ -err_remove_group: + kobject_put(idev->map_dir); sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); err_group: dev_err(idev->dev, "error creating sysfs files (%d)\n", ret); @@ -198,9 +203,9 @@ static void uio_dev_del_attributes(struct uio_device *idev) mem = &idev->info->mem[mi]; if (mem->size == 0) break; - kobject_unregister(&mem->kobj); + kobject_put(&mem->map->kobj); } - kset_unregister(&idev->map_attr_kset); + kobject_put(idev->map_dir); sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp); } @@ -503,7 +508,7 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma) } } -static struct file_operations uio_fops = { +static const struct file_operations uio_fops = { .owner = THIS_MODULE, .open = uio_open, .release = uio_release, diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 7580aa5da0f8..7a6499008b89 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -33,6 +33,7 @@ config USB_ARCH_HAS_OHCI default y if ARCH_LH7A404 default y if ARCH_S3C2410 default y if PXA27x + default y if PXA3xx default y if ARCH_EP93XX default y if ARCH_AT91 default y if ARCH_PNX4008 diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index c51f8e9312e0..7c3aaa9c5402 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -91,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv) goto exit; if (usb_drv->probe != NULL) - error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj, - &driver_attr_new_id.attr); + error = driver_create_file(&usb_drv->drvwrap.driver, + &driver_attr_new_id); exit: return error; } @@ -103,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv) return; if (usb_drv->probe != NULL) - sysfs_remove_file(&usb_drv->drvwrap.driver.kobj, - &driver_attr_new_id.attr); + driver_remove_file(&usb_drv->drvwrap.driver, + &driver_attr_new_id); } static void usb_free_dynids(struct usb_driver *usb_drv) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index f81d08d6538b..77a3759d6fc7 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -308,7 +308,7 @@ config USB_S3C2410_DEBUG config USB_GADGET_AT91 boolean "AT91 USB Device Port" - depends on ARCH_AT91 && !ARCH_AT91SAM9RL + depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 select USB_GADGET_SELECTED help Many Atmel AT91 processors (such as the AT91RM2000) have a diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index ecfe800fd720..ddd4ee1f2413 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -997,7 +997,7 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ohci_hcd_lh7a404_driver #endif -#ifdef CONFIG_PXA27x +#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) #include "ohci-pxa27x.c" #define PLATFORM_DRIVER ohci_hcd_pxa27x_driver #endif diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 5cfa3d1c4413..74e1f4be10bb 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -47,7 +47,7 @@ #endif #ifdef CONFIG_TPS65010 -#include <asm/arch/tps65010.h> +#include <linux/i2c/tps65010.h> #else #define LOW 0 diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index ca2a6abbc117..6c52c66b659f 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -112,9 +112,9 @@ static int isp1301_detach(struct i2c_client *client); static int isp1301_command(struct i2c_client *client, unsigned int cmd, void *arg); -static unsigned short normal_i2c[] = +static const unsigned short normal_i2c[] = { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END }; -static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END }; +static const unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_i2c, @@ -123,7 +123,6 @@ static struct i2c_client_address_data addr_data = { }; struct i2c_driver isp1301_driver = { - .id = I2C_DRIVERID_I2CDEV, /* Fake Id */ .class = I2C_CLASS_HWMON, .attach_adapter = isp1301_probe, .detach_client = isp1301_detach, diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 23d2fe5a62f4..ff9a79843471 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -22,6 +22,7 @@ #include <linux/device.h> #include <linux/signal.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <asm/mach-types.h> #include <asm/hardware.h> @@ -32,6 +33,8 @@ #define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 ) +static struct clk *usb_clk; + /* PMM_NPS_MODE -- PMM Non-power switching mode Ports are powered continuously. @@ -80,7 +83,7 @@ static int pxa27x_start_hc(struct device *dev) inf = dev->platform_data; - pxa_set_cken(CKEN_USBHOST, 1); + clk_enable(usb_clk); UHCHR |= UHCHR_FHR; udelay(11); @@ -123,7 +126,7 @@ static void pxa27x_stop_hc(struct device *dev) UHCCOMS |= 1; udelay(10); - pxa_set_cken(CKEN_USBHOST, 0); + clk_disable(usb_clk); } @@ -158,6 +161,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device return -ENOMEM; } + usb_clk = clk_get(&pdev->dev, "USBCLK"); + if (IS_ERR(usb_clk)) + return PTR_ERR(usb_clk); + hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); if (!hcd) return -ENOMEM; @@ -201,6 +208,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err1: usb_put_hcd(hcd); + clk_put(usb_clk); return retval; } @@ -225,6 +233,7 @@ void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); + clk_put(usb_clk); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index 88aa59ab7563..f5a4e8d6a3b1 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -132,8 +132,7 @@ freecom_readdata (struct scsi_cmnd *srb, struct us_data *us, /* Now transfer all of our blocks. */ US_DEBUGP("Start of read\n"); - result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer, - count, srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, ipipe, srb); US_DEBUGP("freecom_readdata done!\n"); if (result > USB_STOR_XFER_SHORT) @@ -166,8 +165,7 @@ freecom_writedata (struct scsi_cmnd *srb, struct us_data *us, /* Now transfer all of our blocks. */ US_DEBUGP("Start of write\n"); - result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer, - count, srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, opipe, srb); US_DEBUGP("freecom_writedata done!\n"); if (result > USB_STOR_XFER_SHORT) @@ -281,7 +279,7 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) * and such will hang. */ US_DEBUGP("Device indicates that it has %d bytes available\n", le16_to_cpu (fst->Count)); - US_DEBUGP("SCSI requested %d\n", srb->request_bufflen); + US_DEBUGP("SCSI requested %d\n", scsi_bufflen(srb)); /* Find the length we desire to read. */ switch (srb->cmnd[0]) { @@ -292,12 +290,12 @@ int freecom_transport(struct scsi_cmnd *srb, struct us_data *us) length = le16_to_cpu(fst->Count); break; default: - length = srb->request_bufflen; + length = scsi_bufflen(srb); } /* verify that this amount is legal */ - if (length > srb->request_bufflen) { - length = srb->request_bufflen; + if (length > scsi_bufflen(srb)) { + length = scsi_bufflen(srb); US_DEBUGP("Truncating request to match buffer length: %d\n", length); } diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index 49ba6c0ff1e8..0db488624ab1 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -49,6 +49,7 @@ #include <linux/slab.h> #include <linux/hdreg.h> #include <linux/ide.h> +#include <linux/scatterlist.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -287,6 +288,7 @@ struct isd200_info { /* maximum number of LUNs supported */ unsigned char MaxLUNs; struct scsi_cmnd srb; + struct scatterlist sg; }; @@ -398,6 +400,31 @@ static void isd200_build_sense(struct us_data *us, struct scsi_cmnd *srb) * Transport routines ***********************************************************************/ +/************************************************************************** + * isd200_set_srb(), isd200_srb_set_bufflen() + * + * Two helpers to facilitate in initialization of scsi_cmnd structure + * Will need to change when struct scsi_cmnd changes + */ +static void isd200_set_srb(struct isd200_info *info, + enum dma_data_direction dir, void* buff, unsigned bufflen) +{ + struct scsi_cmnd *srb = &info->srb; + + if (buff) + sg_init_one(&info->sg, buff, bufflen); + + srb->sc_data_direction = dir; + srb->sdb.table.sgl = buff ? &info->sg : NULL; + srb->sdb.length = bufflen; + srb->sdb.table.nents = buff ? 1 : 0; +} + +static void isd200_srb_set_bufflen(struct scsi_cmnd *srb, unsigned bufflen) +{ + srb->sdb.length = bufflen; +} + /************************************************************************** * isd200_action @@ -432,9 +459,7 @@ static int isd200_action( struct us_data *us, int action, ata.generic.RegisterSelect = REG_CYLINDER_LOW | REG_CYLINDER_HIGH | REG_STATUS | REG_ERROR; - srb->sc_data_direction = DMA_FROM_DEVICE; - srb->request_buffer = pointer; - srb->request_bufflen = value; + isd200_set_srb(info, DMA_FROM_DEVICE, pointer, value); break; case ACTION_ENUM: @@ -444,7 +469,7 @@ static int isd200_action( struct us_data *us, int action, ACTION_SELECT_5; ata.generic.RegisterSelect = REG_DEVICE_HEAD; ata.write.DeviceHeadByte = value; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_RESET: @@ -453,7 +478,7 @@ static int isd200_action( struct us_data *us, int action, ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_REENABLE: @@ -462,7 +487,7 @@ static int isd200_action( struct us_data *us, int action, ACTION_SELECT_3|ACTION_SELECT_4; ata.generic.RegisterSelect = REG_DEVICE_CONTROL; ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_SOFT_RESET: @@ -471,21 +496,20 @@ static int isd200_action( struct us_data *us, int action, ata.generic.RegisterSelect = REG_DEVICE_HEAD | REG_COMMAND; ata.write.DeviceHeadByte = info->DeviceHead; ata.write.CommandByte = WIN_SRST; - srb->sc_data_direction = DMA_NONE; + isd200_set_srb(info, DMA_NONE, NULL, 0); break; case ACTION_IDENTIFY: US_DEBUGP(" isd200_action(IDENTIFY)\n"); ata.generic.RegisterSelect = REG_COMMAND; ata.write.CommandByte = WIN_IDENTIFY; - srb->sc_data_direction = DMA_FROM_DEVICE; - srb->request_buffer = (void *) info->id; - srb->request_bufflen = sizeof(struct hd_driveid); + isd200_set_srb(info, DMA_FROM_DEVICE, info->id, + sizeof(struct hd_driveid)); break; default: US_DEBUGP("Error: Undefined action %d\n",action); - break; + return ISD200_ERROR; } memcpy(srb->cmnd, &ata, sizeof(ata.generic)); @@ -590,7 +614,7 @@ static void isd200_invoke_transport( struct us_data *us, return; } - if ((srb->resid > 0) && + if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -1217,7 +1241,6 @@ static int isd200_get_inquiry_data( struct us_data *us ) return(retStatus); } - /************************************************************************** * isd200_scsi_to_ata * @@ -1266,7 +1289,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1284,7 +1307,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Media Status not supported, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1390,7 +1413,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ? WIN_DOORLOCK : WIN_DOORUNLOCK; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Not removeable media, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1416,7 +1439,7 @@ static int isd200_scsi_to_ata(struct scsi_cmnd *srb, struct us_data *us, ataCdb->generic.TransferBlockSize = 1; ataCdb->generic.RegisterSelect = REG_COMMAND; ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS; - srb->request_bufflen = 0; + isd200_srb_set_bufflen(srb, 0); } else { US_DEBUGP(" Nothing to do, just report okay\n"); srb->result = SAM_STAT_GOOD; @@ -1525,7 +1548,7 @@ int isd200_Initialization(struct us_data *us) void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) { - int sendToTransport = 1; + int sendToTransport = 1, orig_bufflen; union ata_cdb ataCdb; /* Make sure driver was initialized */ @@ -1533,11 +1556,14 @@ void isd200_ata_command(struct scsi_cmnd *srb, struct us_data *us) if (us->extra == NULL) US_DEBUGP("ERROR Driver not initialized\n"); - /* Convert command */ - srb->resid = 0; + scsi_set_resid(srb, 0); + /* scsi_bufflen might change in protocol translation to ata */ + orig_bufflen = scsi_bufflen(srb); sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb); /* send the command to the transport layer */ if (sendToTransport) isd200_invoke_transport(us, srb, &ataCdb); + + isd200_srb_set_bufflen(srb, orig_bufflen); } diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 889622baac20..a41ce21c0697 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -149,11 +149,7 @@ void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb, ***********************************************************************/ /* Copy a buffer of length buflen to/from the srb's transfer buffer. - * (Note: for scatter-gather transfers (srb->use_sg > 0), srb->request_buffer - * points to a list of s-g entries and we ignore srb->request_bufflen. - * For non-scatter-gather transfers, srb->request_buffer points to the - * transfer buffer itself and srb->request_bufflen is the buffer's length.) - * Update the *index and *offset variables so that the next copy will + * Update the **sgptr and *offset variables so that the next copy will * pick up from where this one left off. */ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, @@ -162,80 +158,64 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer, { unsigned int cnt; - /* If not using scatter-gather, just transfer the data directly. - * Make certain it will fit in the available buffer space. */ - if (srb->use_sg == 0) { - if (*offset >= srb->request_bufflen) - return 0; - cnt = min(buflen, srb->request_bufflen - *offset); - if (dir == TO_XFER_BUF) - memcpy((unsigned char *) srb->request_buffer + *offset, - buffer, cnt); - else - memcpy(buffer, (unsigned char *) srb->request_buffer + - *offset, cnt); - *offset += cnt; - - /* Using scatter-gather. We have to go through the list one entry + /* We have to go through the list one entry * at a time. Each s-g entry contains some number of pages, and * each page has to be kmap()'ed separately. If the page is already * in kernel-addressable memory then kmap() will return its address. * If the page is not directly accessible -- such as a user buffer * located in high memory -- then kmap() will map it to a temporary * position in the kernel's virtual address space. */ - } else { - struct scatterlist *sg = *sgptr; - - if (!sg) - sg = (struct scatterlist *) srb->request_buffer; - - /* This loop handles a single s-g list entry, which may - * include multiple pages. Find the initial page structure - * and the starting offset within the page, and update - * the *offset and *index values for the next loop. */ - cnt = 0; - while (cnt < buflen) { - struct page *page = sg_page(sg) + - ((sg->offset + *offset) >> PAGE_SHIFT); - unsigned int poff = - (sg->offset + *offset) & (PAGE_SIZE-1); - unsigned int sglen = sg->length - *offset; - - if (sglen > buflen - cnt) { - - /* Transfer ends within this s-g entry */ - sglen = buflen - cnt; - *offset += sglen; - } else { - - /* Transfer continues to next s-g entry */ - *offset = 0; - sg = sg_next(sg); - } - - /* Transfer the data for all the pages in this - * s-g entry. For each page: call kmap(), do the - * transfer, and call kunmap() immediately after. */ - while (sglen > 0) { - unsigned int plen = min(sglen, (unsigned int) - PAGE_SIZE - poff); - unsigned char *ptr = kmap(page); - - if (dir == TO_XFER_BUF) - memcpy(ptr + poff, buffer + cnt, plen); - else - memcpy(buffer + cnt, ptr + poff, plen); - kunmap(page); - - /* Start at the beginning of the next page */ - poff = 0; - ++page; - cnt += plen; - sglen -= plen; - } + struct scatterlist *sg = *sgptr; + + if (!sg) + sg = scsi_sglist(srb); + + /* This loop handles a single s-g list entry, which may + * include multiple pages. Find the initial page structure + * and the starting offset within the page, and update + * the *offset and **sgptr values for the next loop. */ + cnt = 0; + while (cnt < buflen) { + struct page *page = sg_page(sg) + + ((sg->offset + *offset) >> PAGE_SHIFT); + unsigned int poff = + (sg->offset + *offset) & (PAGE_SIZE-1); + unsigned int sglen = sg->length - *offset; + + if (sglen > buflen - cnt) { + + /* Transfer ends within this s-g entry */ + sglen = buflen - cnt; + *offset += sglen; + } else { + + /* Transfer continues to next s-g entry */ + *offset = 0; + sg = sg_next(sg); + } + + /* Transfer the data for all the pages in this + * s-g entry. For each page: call kmap(), do the + * transfer, and call kunmap() immediately after. */ + while (sglen > 0) { + unsigned int plen = min(sglen, (unsigned int) + PAGE_SIZE - poff); + unsigned char *ptr = kmap(page); + + if (dir == TO_XFER_BUF) + memcpy(ptr + poff, buffer + cnt, plen); + else + memcpy(buffer + cnt, ptr + poff, plen); + kunmap(page); + + /* Start at the beginning of the next page */ + poff = 0; + ++page; + cnt += plen; + sglen -= plen; } - *sgptr = sg; } + *sgptr = sg; /* Return the amount actually transferred */ return cnt; @@ -251,6 +231,6 @@ void usb_stor_set_xfer_buf(unsigned char *buffer, usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset, TO_XFER_BUF); - if (buflen < srb->request_bufflen) - srb->resid = srb->request_bufflen - buflen; + if (buflen < scsi_bufflen(srb)) + scsi_set_resid(srb, scsi_bufflen(srb) - buflen); } diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 7c9593b7b04e..8c1e2954f3b9 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -81,6 +81,16 @@ static int slave_alloc (struct scsi_device *sdev) */ sdev->inquiry_len = 36; + /* Scatter-gather buffers (all but the last) must have a length + * divisible by the bulk maxpacket size. Otherwise a data packet + * would end up being short, causing a premature end to the data + * transfer. Since high-speed bulk pipes have a maxpacket size + * of 512, we'll use that as the scsi device queue's DMA alignment + * mask. Guaranteeing proper alignment of the first buffer will + * have the desired effect because, except at the beginning and + * the end, scatter-gather buffers follow page boundaries. */ + blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); + /* * The UFI spec treates the Peripheral Qualifier bits in an * INQUIRY result as reserved and requires devices to set them @@ -100,16 +110,6 @@ static int slave_configure(struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); - /* Scatter-gather buffers (all but the last) must have a length - * divisible by the bulk maxpacket size. Otherwise a data packet - * would end up being short, causing a premature end to the data - * transfer. Since high-speed bulk pipes have a maxpacket size - * of 512, we'll use that as the scsi device queue's DMA alignment - * mask. Guaranteeing proper alignment of the first buffer will - * have the desired effect because, except at the beginning and - * the end, scatter-gather buffers follow page boundaries. */ - blk_queue_dma_alignment(sdev->request_queue, (512 - 1)); - /* Many devices have trouble transfering more than 32KB at a time, * while others have trouble with more than 64K. At this time we * are limiting both to 32K (64 sectores). @@ -187,6 +187,10 @@ static int slave_configure(struct scsi_device *sdev) * automatically, requiring a START-STOP UNIT command. */ sdev->allow_restart = 1; + /* Some USB cardreaders have trouble reading an sdcard's last + * sector in a larger then 1 sector read, since the performance + * impact is negible we set this flag for all USB disks */ + sdev->last_sector_bug = 1; } else { /* Non-disk-type devices don't need to blacklist any pages diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index b12202c5da2d..8972b17da843 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -1623,7 +1623,7 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) return USB_STOR_TRANSPORT_ERROR; } - if (srb->request_bufflen == 0) + if (scsi_bufflen(srb) == 0) return USB_STOR_TRANSPORT_GOOD; if (srb->sc_data_direction == DMA_TO_DEVICE || @@ -1634,12 +1634,9 @@ int sddr09_transport(struct scsi_cmnd *srb, struct us_data *us) US_DEBUGP("SDDR09: %s %d bytes\n", (srb->sc_data_direction == DMA_TO_DEVICE) ? "sending" : "receiving", - srb->request_bufflen); + scsi_bufflen(srb)); - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, - srb->request_bufflen, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index cb22a9ad1694..570c1250f6f3 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -130,7 +130,7 @@ static int usbat_write(struct us_data *us, * Convenience function to perform a bulk read */ static int usbat_bulk_read(struct us_data *us, - unsigned char *data, + void* buf, unsigned int len, int use_sg) { @@ -138,14 +138,14 @@ static int usbat_bulk_read(struct us_data *us, return USB_STOR_XFER_GOOD; US_DEBUGP("usbat_bulk_read: len = %d\n", len); - return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, data, len, use_sg, NULL); + return usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, buf, len, use_sg, NULL); } /* * Convenience function to perform a bulk write */ static int usbat_bulk_write(struct us_data *us, - unsigned char *data, + void* buf, unsigned int len, int use_sg) { @@ -153,7 +153,7 @@ static int usbat_bulk_write(struct us_data *us, return USB_STOR_XFER_GOOD; US_DEBUGP("usbat_bulk_write: len = %d\n", len); - return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, data, len, use_sg, NULL); + return usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, buf, len, use_sg, NULL); } /* @@ -314,7 +314,7 @@ static int usbat_wait_not_busy(struct us_data *us, int minutes) * Read block data from the data register */ static int usbat_read_block(struct us_data *us, - unsigned char *content, + void* buf, unsigned short len, int use_sg) { @@ -337,7 +337,7 @@ static int usbat_read_block(struct us_data *us, if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - result = usbat_bulk_read(us, content, len, use_sg); + result = usbat_bulk_read(us, buf, len, use_sg); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); } @@ -347,7 +347,7 @@ static int usbat_read_block(struct us_data *us, */ static int usbat_write_block(struct us_data *us, unsigned char access, - unsigned char *content, + void* buf, unsigned short len, int minutes, int use_sg) @@ -372,7 +372,7 @@ static int usbat_write_block(struct us_data *us, if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; - result = usbat_bulk_write(us, content, len, use_sg); + result = usbat_bulk_write(us, buf, len, use_sg); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -392,7 +392,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, unsigned char timeout, unsigned char qualifier, int direction, - unsigned char *content, + void *buf, unsigned short len, int use_sg, int minutes) @@ -472,7 +472,7 @@ static int usbat_hp8200e_rw_block_test(struct us_data *us, } result = usb_stor_bulk_transfer_sg(us, - pipe, content, len, use_sg, NULL); + pipe, buf, len, use_sg, NULL); /* * If we get a stall on the bulk download, we'll retry @@ -606,7 +606,7 @@ static int usbat_multiple_write(struct us_data *us, * other related details) are defined beforehand with _set_shuttle_features(). */ static int usbat_read_blocks(struct us_data *us, - unsigned char *buffer, + void* buffer, int len, int use_sg) { @@ -648,7 +648,7 @@ static int usbat_read_blocks(struct us_data *us, * other related details) are defined beforehand with _set_shuttle_features(). */ static int usbat_write_blocks(struct us_data *us, - unsigned char *buffer, + void* buffer, int len, int use_sg) { @@ -1170,15 +1170,15 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, US_DEBUGP("handle_read10: transfersize %d\n", srb->transfersize); - if (srb->request_bufflen < 0x10000) { + if (scsi_bufflen(srb) < 0x10000) { result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, registers, data, 19, USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), DMA_FROM_DEVICE, - srb->request_buffer, - srb->request_bufflen, srb->use_sg, 1); + scsi_sglist(srb), + scsi_bufflen(srb), scsi_sg_count(srb), 1); return result; } @@ -1196,7 +1196,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, len <<= 16; len |= data[7+7]; US_DEBUGP("handle_read10: GPCMD_READ_CD: len %d\n", len); - srb->transfersize = srb->request_bufflen/len; + srb->transfersize = scsi_bufflen(srb)/len; } if (!srb->transfersize) { @@ -1213,7 +1213,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, len = (65535/srb->transfersize) * srb->transfersize; US_DEBUGP("Max read is %d bytes\n", len); - len = min(len, srb->request_bufflen); + len = min(len, scsi_bufflen(srb)); buffer = kmalloc(len, GFP_NOIO); if (buffer == NULL) /* bloody hell! */ return USB_STOR_TRANSPORT_FAILED; @@ -1222,10 +1222,10 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, sector |= short_pack(data[7+5], data[7+4]); transferred = 0; - while (transferred != srb->request_bufflen) { + while (transferred != scsi_bufflen(srb)) { - if (len > srb->request_bufflen - transferred) - len = srb->request_bufflen - transferred; + if (len > scsi_bufflen(srb) - transferred) + len = scsi_bufflen(srb) - transferred; data[3] = len&0xFF; /* (cylL) = expected length (L) */ data[4] = (len>>8)&0xFF; /* (cylH) = expected length (H) */ @@ -1261,7 +1261,7 @@ static int usbat_hp8200e_handle_read10(struct us_data *us, transferred += len; sector += len / srb->transfersize; - } /* while transferred != srb->request_bufflen */ + } /* while transferred != scsi_bufflen(srb) */ kfree(buffer); return result; @@ -1429,9 +1429,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) unsigned char data[32]; unsigned int len; int i; - char string[64]; - len = srb->request_bufflen; + len = scsi_bufflen(srb); /* Send A0 (ATA PACKET COMMAND). Note: I guess we're never going to get any of the ATA @@ -1472,8 +1471,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) USBAT_ATA_DATA, USBAT_ATA_STATUS, 0xFD, (USBAT_QUAL_FCQ | USBAT_QUAL_ALQ), DMA_TO_DEVICE, - srb->request_buffer, - len, srb->use_sg, 10); + scsi_sglist(srb), + len, scsi_sg_count(srb), 10); if (result == USB_STOR_TRANSPORT_GOOD) { transferred += len; @@ -1540,23 +1539,8 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us) len = *status; - result = usbat_read_block(us, srb->request_buffer, len, srb->use_sg); - - /* Debug-print the first 32 bytes of the transfer */ - - if (!srb->use_sg) { - string[0] = 0; - for (i=0; i<len && i<32; i++) { - sprintf(string+strlen(string), "%02X ", - ((unsigned char *)srb->request_buffer)[i]); - if ((i%16)==15) { - US_DEBUGP("%s\n", string); - string[0] = 0; - } - } - if (string[0]!=0) - US_DEBUGP("%s\n", string); - } + result = usbat_read_block(us, scsi_sglist(srb), len, + scsi_sg_count(srb)); } return result; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index c646750ccc30..d9f4912f873d 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -459,6 +459,22 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, } /* + * Common used function. Transfer a complete command + * via usb_stor_bulk_transfer_sglist() above. Set cmnd resid + */ +int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, + struct scsi_cmnd* srb) +{ + unsigned int partial; + int result = usb_stor_bulk_transfer_sglist(us, pipe, scsi_sglist(srb), + scsi_sg_count(srb), scsi_bufflen(srb), + &partial); + + scsi_set_resid(srb, scsi_bufflen(srb) - partial); + return result; +} + +/* * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * @@ -508,7 +524,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) int result; /* send the command to the transport layer */ - srb->resid = 0; + scsi_set_resid(srb, 0); result = us->transport(srb, us); /* if the command gets aborted by the higher layers, we need to @@ -568,7 +584,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) * A short transfer on a command where we don't expect it * is unusual, but it doesn't mean we need to auto-sense. */ - if ((srb->resid > 0) && + if ((scsi_get_resid(srb) > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -593,7 +609,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) srb->cmd_len = 12; /* issue the auto-sense command */ - srb->resid = 0; + scsi_set_resid(srb, 0); temp_result = us->transport(us->srb, us); /* let's clean up right away */ @@ -649,7 +665,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) /* Did we transfer less than the minimum amount required? */ if (srb->result == SAM_STAT_GOOD && - srb->request_bufflen - srb->resid < srb->underflow) + scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); return; @@ -708,7 +724,7 @@ void usb_stor_stop_transport(struct us_data *us) int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) { - unsigned int transfer_length = srb->request_bufflen; + unsigned int transfer_length = scsi_bufflen(srb); unsigned int pipe = 0; int result; @@ -737,9 +753,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) if (transfer_length) { pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, transfer_length, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); US_DEBUGP("CBI data stage result is 0x%x\n", result); /* if we stalled the data transfer it means command failed */ @@ -808,7 +822,7 @@ int usb_stor_CBI_transport(struct scsi_cmnd *srb, struct us_data *us) */ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) { - unsigned int transfer_length = srb->request_bufflen; + unsigned int transfer_length = scsi_bufflen(srb); int result; /* COMMAND STAGE */ @@ -836,9 +850,7 @@ int usb_stor_CB_transport(struct scsi_cmnd *srb, struct us_data *us) if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, transfer_length, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); US_DEBUGP("CB data stage result is 0x%x\n", result); /* if we stalled the data transfer it means command failed */ @@ -904,7 +916,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) { struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; - unsigned int transfer_length = srb->request_bufflen; + unsigned int transfer_length = scsi_bufflen(srb); unsigned int residue; int result; int fake_sense = 0; @@ -955,9 +967,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (transfer_length) { unsigned int pipe = srb->sc_data_direction == DMA_FROM_DEVICE ? us->recv_bulk_pipe : us->send_bulk_pipe; - result = usb_stor_bulk_transfer_sg(us, pipe, - srb->request_buffer, transfer_length, - srb->use_sg, &srb->resid); + result = usb_stor_bulk_srb(us, pipe, srb); US_DEBUGP("Bulk data transfer result 0x%x\n", result); if (result == USB_STOR_XFER_ERROR) return USB_STOR_TRANSPORT_ERROR; @@ -1036,7 +1046,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) if (residue) { if (!(us->flags & US_FL_IGNORE_RESIDUE)) { residue = min(residue, transfer_length); - srb->resid = max(srb->resid, (int) residue); + scsi_set_resid(srb, max(scsi_get_resid(srb), + (int) residue)); } } diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h index 633a715850a4..ada7c2f43f84 100644 --- a/drivers/usb/storage/transport.h +++ b/drivers/usb/storage/transport.h @@ -139,6 +139,8 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len); extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, int use_sg, int *residual); +extern int usb_stor_bulk_srb(struct us_data* us, unsigned int pipe, + struct scsi_cmnd* srb); extern int usb_stor_port_reset(struct us_data *us); #endif diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5b3dbcfcda48..758435f8a6f8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -889,7 +889,7 @@ config FB_S1D13XXX config FB_ATMEL tristate "AT91/AT32 LCD Controller support" - depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32) + depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 || AVR32) select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 7c30cc8df71e..f8e711147501 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -30,7 +30,7 @@ #define ATMEL_LCDC_CVAL_DEFAULT 0xc8 #define ATMEL_LCDC_DMA_BURST_LEN 8 -#if defined(CONFIG_ARCH_AT91SAM9263) +#if defined(CONFIG_ARCH_AT91SAM9263) || defined(CONFIG_ARCH_AT91CAP9) #define ATMEL_LCDC_FIFO_SIZE 2048 #else #define ATMEL_LCDC_FIFO_SIZE 512 diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 74d11c318987..c8e7427a0bc8 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -224,7 +224,8 @@ static int config_dma(struct bfin_bf54xfb_info *fbi) set_dma_config(CH_EPPI0, set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, INTR_DISABLE, DIMENSION_2D, - DATA_SIZE_32)); + DATA_SIZE_32, + DMA_NOSYNC_KEEP_DMA_BUF)); set_dma_x_count(CH_EPPI0, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); set_dma_x_modify(CH_EPPI0, DMA_BUS_SIZE / 8); set_dma_y_count(CH_EPPI0, LCD_Y_RES); @@ -263,8 +264,7 @@ static int request_ports(struct bfin_bf54xfb_info *fbi) } } - gpio_direction_output(disp); - gpio_set_value(disp, 1); + gpio_direction_output(disp, 1); return 0; } diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index b87ed37ac0c1..2b53d1f56281 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -6,7 +6,7 @@ menu "Console display driver support" config VGA_CONSOLE bool "VGA text console" if EMBEDDED || !X86 - depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN + depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32 default y help Saying Y here will allow you to use Linux in text mode through a diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c index 49cd53e46c0a..0cd58f84fb46 100644 --- a/drivers/video/matrox/matroxfb_maven.c +++ b/drivers/video/matrox/matroxfb_maven.c @@ -1232,7 +1232,7 @@ static int maven_shutdown_client(struct i2c_client* clnt) { return 0; } -static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; I2C_CLIENT_INSMOD; static struct i2c_driver maven_driver; diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c index c604d935c188..31e978349a80 100644 --- a/drivers/video/omap/lcd_h3.c +++ b/drivers/video/omap/lcd_h3.c @@ -21,9 +21,9 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/i2c/tps65010.h> #include <asm/arch/gpio.h> -#include <asm/arch/tps65010.h> #include <asm/arch/omapfb.h> #define MODULE_NAME "omapfb-lcd_h3" diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index c31f549ebea0..1c656667b937 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -88,9 +88,7 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order, { gfp_t flags; unsigned long i; - pgprot_t wc_pageprot; - wc_pageprot = PAGE_KERNEL_NOCACHE; max_order++; do { /* @@ -126,14 +124,8 @@ static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order, /* * Change caching policy of the linear kernel map to avoid * mapping type conflicts with user-space mappings. - * The first global_flush_tlb() is really only there to do a global - * wbinvd(). */ - - global_flush_tlb(); - change_page_attr(virt_to_page(va->logical), va->size >> PAGE_SHIFT, - wc_pageprot); - global_flush_tlb(); + set_pages_uc(virt_to_page(va->logical), va->size >> PAGE_SHIFT); printk(KERN_DEBUG MODULE_NAME ": Allocated %ld bytes vram area at 0x%08lx\n", @@ -157,9 +149,8 @@ static void vmlfb_free_vram_area(struct vram_area *va) * Reset the linear kernel map caching policy. */ - change_page_attr(virt_to_page(va->logical), - va->size >> PAGE_SHIFT, PAGE_KERNEL); - global_flush_tlb(); + set_pages_wb(virt_to_page(va->logical), + va->size >> PAGE_SHIFT); /* * Decrease the usage count on the pages we've used diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index d93eb626b2f0..0fd5820d5c61 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -29,7 +29,7 @@ * However, the chip cannot be detected without doing an i2c write, * so use the force module parameter. */ -static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /** * Insmod parameters diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 52dff40ec192..afcdc69e37d6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG config AT32AP700X_WDT tristate "AT32AP700x watchdog" - depends on CPU_AT32AP7000 + depends on CPU_AT32AP700X help Watchdog timer embedded into AT32AP700x devices. This will reboot your system when the timeout is reached. @@ -609,7 +609,7 @@ config SBC_EPX_C3_WATCHDOG config INDYDOG tristate "Indy/I2 Hardware Watchdog" - depends on SGI_IP22 + depends on SGI_HAS_INDYDOG help Hardware driver for the Indy's/I2's watchdog. This is a watchdog timer that will reboot the machine after a 60 second @@ -639,6 +639,12 @@ config AR7_WDT help Hardware driver for the TI AR7 Watchdog Timer. +config TXX9_WDT + tristate "Toshiba TXx9 Watchdog Timer" + depends on CPU_TX39XX || CPU_TX49XX + help + Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. + # PARISC Architecture # POWERPC Architecture diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 87483cc63252..ebc21146d40c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -93,6 +93,7 @@ obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o obj-$(CONFIG_AR7_WDT) += ar7_wdt.o +obj-$(CONFIG_TXX9_WDT) += txx9wdt.o # PARISC Architecture diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index b481cc0e32e4..2b1fbdb2fcf7 100644 --- a/drivers/watchdog/alim1535_wdt.c +++ b/drivers/watchdog/alim1535_wdt.c @@ -413,18 +413,18 @@ static int __init watchdog_init(void) /* Calculate the watchdog's timeout */ ali_settimer(timeout); - ret = misc_register(&ali_miscdev); + ret = register_reboot_notifier(&ali_notifier); if (ret != 0) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - WATCHDOG_MINOR, ret); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + ret); goto out; } - ret = register_reboot_notifier(&ali_notifier); + ret = misc_register(&ali_miscdev); if (ret != 0) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - ret); - goto unreg_miscdev; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto unreg_reboot; } printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", @@ -432,8 +432,8 @@ static int __init watchdog_init(void) out: return ret; -unreg_miscdev: - misc_deregister(&ali_miscdev); +unreg_reboot: + unregister_reboot_notifier(&ali_notifier); goto out; } @@ -449,8 +449,8 @@ static void __exit watchdog_exit(void) ali_stop(); /* Deregister */ - unregister_reboot_notifier(&ali_notifier); misc_deregister(&ali_miscdev); + unregister_reboot_notifier(&ali_notifier); pci_dev_put(ali_pci); } diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index 67aed9f8c362..238273c98656 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c @@ -377,18 +377,18 @@ static int __init alim7101_wdt_init(void) timeout); } - rc = misc_register(&wdt_miscdev); + rc = register_reboot_notifier(&wdt_notifier); if (rc) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - wdt_miscdev.minor, rc); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out; } - rc = register_reboot_notifier(&wdt_notifier); + rc = misc_register(&wdt_miscdev); if (rc) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - rc); - goto err_out_miscdev; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_reboot; } if (nowayout) { @@ -399,8 +399,8 @@ static int __init alim7101_wdt_init(void) timeout, nowayout); return 0; -err_out_miscdev: - misc_deregister(&wdt_miscdev); +err_out_reboot: + unregister_reboot_notifier(&wdt_notifier); err_out: pci_dev_put(alim7101_pmu); return rc; diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c index cdaab8c3d3d0..2eb48c0df32c 100644 --- a/drivers/watchdog/ar7_wdt.c +++ b/drivers/watchdog/ar7_wdt.c @@ -279,7 +279,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file, } } -static struct file_operations ar7_wdt_fops = { +static const struct file_operations ar7_wdt_fops = { .owner = THIS_MODULE, .write = ar7_wdt_write, .ioctl = ar7_wdt_ioctl, diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 31dc7a69e90c..472be10f0686 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c @@ -390,7 +390,7 @@ static struct platform_driver bfin_wdt_driver = { .resume = bfin_wdt_resume, }; -static struct file_operations bfin_wdt_fops = { +static const struct file_operations bfin_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = bfin_wdt_write, diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c index 6330fc02464e..1b6d7d1b715d 100644 --- a/drivers/watchdog/it8712f_wdt.c +++ b/drivers/watchdog/it8712f_wdt.c @@ -296,7 +296,7 @@ it8712f_wdt_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations it8712f_wdt_fops = { +static const struct file_operations it8712f_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = it8712f_wdt_write, diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c index 11f6a111e75b..80a91d4cea11 100644 --- a/drivers/watchdog/mpc5200_wdt.c +++ b/drivers/watchdog/mpc5200_wdt.c @@ -158,7 +158,7 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file) return 0; } -static struct file_operations mpc5200_wdt_fops = { +static const struct file_operations mpc5200_wdt_fops = { .owner = THIS_MODULE, .write = mpc5200_wdt_write, .ioctl = mpc5200_wdt_ioctl, diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index dcfd401a7ad7..98451747d3cd 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c @@ -180,7 +180,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, return count; } -static struct file_operations mtx1_wdt_fops = { +static const struct file_operations mtx1_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .ioctl = mtx1_wdt_ioctl, diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c index e4f3cb6090bc..ef76f01625e7 100644 --- a/drivers/watchdog/sbc60xxwdt.c +++ b/drivers/watchdog/sbc60xxwdt.c @@ -359,20 +359,20 @@ static int __init sbc60xxwdt_init(void) } } - rc = misc_register(&wdt_miscdev); + rc = register_reboot_notifier(&wdt_notifier); if (rc) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - wdt_miscdev.minor, rc); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out_region2; } - rc = register_reboot_notifier(&wdt_notifier); + rc = misc_register(&wdt_miscdev); if (rc) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - rc); - goto err_out_miscdev; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_reboot; } printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", @@ -380,8 +380,8 @@ static int __init sbc60xxwdt_init(void) return 0; -err_out_miscdev: - misc_deregister(&wdt_miscdev); +err_out_reboot: + unregister_reboot_notifier(&wdt_notifier); err_out_region2: if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) release_region(wdt_stop,1); diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c index d4fd0fa2f176..d55882bca319 100644 --- a/drivers/watchdog/scx200_wdt.c +++ b/drivers/watchdog/scx200_wdt.c @@ -231,17 +231,17 @@ static int __init scx200_wdt_init(void) sema_init(&open_semaphore, 1); - r = misc_register(&scx200_wdt_miscdev); + r = register_reboot_notifier(&scx200_wdt_notifier); if (r) { + printk(KERN_ERR NAME ": unable to register reboot notifier"); release_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE); return r; } - r = register_reboot_notifier(&scx200_wdt_notifier); + r = misc_register(&scx200_wdt_miscdev); if (r) { - printk(KERN_ERR NAME ": unable to register reboot notifier"); - misc_deregister(&scx200_wdt_miscdev); + unregister_reboot_notifier(&scx200_wdt_notifier); release_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE); return r; @@ -252,8 +252,8 @@ static int __init scx200_wdt_init(void) static void __exit scx200_wdt_cleanup(void) { - unregister_reboot_notifier(&scx200_wdt_notifier); misc_deregister(&scx200_wdt_miscdev); + unregister_reboot_notifier(&scx200_wdt_notifier); release_region(scx200_cb_base + SCx200_WDT_OFFSET, SCx200_WDT_SIZE); } diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c new file mode 100644 index 000000000000..328b3c7211ef --- /dev/null +++ b/drivers/watchdog/txx9wdt.c @@ -0,0 +1,276 @@ +/* + * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs + * + * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/fs.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <asm/txx9tmr.h> + +#define TIMER_MARGIN 60 /* Default is 60 seconds */ + +static int timeout = TIMER_MARGIN; /* in seconds */ +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, + "Watchdog timeout in seconds. " + "(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), " + "default=" __MODULE_STRING(TIMER_MARGIN) ")"); + +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) ")"); + +#define WD_TIMER_CCD 7 /* 1/256 */ +#define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD)) +#define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK) + +static unsigned long txx9wdt_alive; +static int expect_close; +static struct txx9_tmr_reg __iomem *txx9wdt_reg; +static struct clk *txx9_imclk; + +static void txx9wdt_ping(void) +{ + __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); +} + +static void txx9wdt_start(void) +{ + __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); + __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr); + __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */ + __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, + &txx9wdt_reg->tcr); + __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); +} + +static void txx9wdt_stop(void) +{ + __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); + __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, + &txx9wdt_reg->tcr); +} + +static int txx9wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &txx9wdt_alive)) + return -EBUSY; + + if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) { + clear_bit(0, &txx9wdt_alive); + return -EBUSY; + } + + if (nowayout) + __module_get(THIS_MODULE); + + txx9wdt_start(); + return nonseekable_open(inode, file); +} + +static int txx9wdt_release(struct inode *inode, struct file *file) +{ + if (expect_close) + txx9wdt_stop(); + else { + printk(KERN_CRIT "txx9wdt: " + "Unexpected close, not stopping watchdog!\n"); + txx9wdt_ping(); + } + clear_bit(0, &txx9wdt_alive); + expect_close = 0; + return 0; +} + +static ssize_t txx9wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + expect_close = 0; + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + expect_close = 1; + } + } + txx9wdt_ping(); + } + return len; +} + +static int txx9wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_timeout; + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = "Hardware Watchdog for TXx9", + }; + + switch (cmd) { + default: + return -ENOTTY; + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + case WDIOC_KEEPALIVE: + txx9wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, p)) + return -EFAULT; + if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT) + return -EINVAL; + timeout = new_timeout; + txx9wdt_stop(); + txx9wdt_start(); + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(timeout, p); + } +} + +static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + txx9wdt_stop(); + return NOTIFY_DONE; +} + +static const struct file_operations txx9wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = txx9wdt_write, + .ioctl = txx9wdt_ioctl, + .open = txx9wdt_open, + .release = txx9wdt_release, +}; + +static struct miscdevice txx9wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &txx9wdt_fops, +}; + +static struct notifier_block txx9wdt_notifier = { + .notifier_call = txx9wdt_notify_sys +}; + +static int __init txx9wdt_probe(struct platform_device *dev) +{ + struct resource *res; + int ret; + + txx9_imclk = clk_get(NULL, "imbus_clk"); + if (IS_ERR(txx9_imclk)) { + ret = PTR_ERR(txx9_imclk); + txx9_imclk = NULL; + goto exit; + } + ret = clk_enable(txx9_imclk); + if (ret) { + clk_put(txx9_imclk); + txx9_imclk = NULL; + goto exit; + } + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + goto exit_busy; + if (!devm_request_mem_region(&dev->dev, + res->start, res->end - res->start + 1, + "txx9wdt")) + goto exit_busy; + txx9wdt_reg = devm_ioremap(&dev->dev, + res->start, res->end - res->start + 1); + if (!txx9wdt_reg) + goto exit_busy; + + ret = register_reboot_notifier(&txx9wdt_notifier); + if (ret) + goto exit; + + ret = misc_register(&txx9wdt_miscdev); + if (ret) { + unregister_reboot_notifier(&txx9wdt_notifier); + goto exit; + } + + printk(KERN_INFO "Hardware Watchdog Timer for TXx9: " + "timeout=%d sec (max %ld) (nowayout= %d)\n", + timeout, WD_MAX_TIMEOUT, nowayout); + + return 0; +exit_busy: + ret = -EBUSY; +exit: + if (txx9_imclk) { + clk_disable(txx9_imclk); + clk_put(txx9_imclk); + } + return ret; +} + +static int __exit txx9wdt_remove(struct platform_device *dev) +{ + misc_deregister(&txx9wdt_miscdev); + unregister_reboot_notifier(&txx9wdt_notifier); + clk_disable(txx9_imclk); + clk_put(txx9_imclk); + return 0; +} + +static struct platform_driver txx9wdt_driver = { + .remove = __exit_p(txx9wdt_remove), + .driver = { + .name = "txx9wdt", + .owner = THIS_MODULE, + }, +}; + +static int __init watchdog_init(void) +{ + return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe); +} + +static void __exit watchdog_exit(void) +{ + platform_driver_unregister(&txx9wdt_driver); +} + +module_init(watchdog_init); +module_exit(watchdog_exit); + +MODULE_DESCRIPTION("TXx9 Watchdog Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c index bcc9d48955de..f510a3a595e6 100644 --- a/drivers/watchdog/w83877f_wdt.c +++ b/drivers/watchdog/w83877f_wdt.c @@ -373,20 +373,20 @@ static int __init w83877f_wdt_init(void) goto err_out_region1; } - rc = misc_register(&wdt_miscdev); + rc = register_reboot_notifier(&wdt_notifier); if (rc) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - wdt_miscdev.minor, rc); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out_region2; } - rc = register_reboot_notifier(&wdt_notifier); + rc = misc_register(&wdt_miscdev); if (rc) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - rc); - goto err_out_miscdev; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_reboot; } printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", @@ -394,8 +394,8 @@ static int __init w83877f_wdt_init(void) return 0; -err_out_miscdev: - misc_deregister(&wdt_miscdev); +err_out_reboot: + unregister_reboot_notifier(&wdt_notifier); err_out_region2: release_region(WDT_PING,1); err_out_region1: diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c index b475529d2475..b209bcd7f789 100644 --- a/drivers/watchdog/w83977f_wdt.c +++ b/drivers/watchdog/w83977f_wdt.c @@ -494,20 +494,20 @@ static int __init w83977f_wdt_init(void) goto err_out; } - rc = misc_register(&wdt_miscdev); + rc = register_reboot_notifier(&wdt_notifier); if (rc) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - wdt_miscdev.minor, rc); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out_region; } - rc = register_reboot_notifier(&wdt_notifier); + rc = misc_register(&wdt_miscdev); if (rc) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - rc); - goto err_out_miscdev; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_reboot; } printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", @@ -515,8 +515,8 @@ static int __init w83977f_wdt_init(void) return 0; -err_out_miscdev: - misc_deregister(&wdt_miscdev); +err_out_reboot: + unregister_reboot_notifier(&wdt_notifier); err_out_region: release_region(IO_INDEX_PORT,2); err_out: diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index 53d0bb410df8..756fb15fdce7 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c @@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ static int io=0x240; static int irq=11; +static DEFINE_SPINLOCK(wdt_lock); + module_param(io, int, 0); MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); module_param(irq, int, 0); @@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val) static int wdt_start(void) { + unsigned long flags; + spin_lock_irqsave(&wdt_lock, flags); inb_p(WDT_DC); /* Disable watchdog */ wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ @@ -117,6 +121,7 @@ static int wdt_start(void) wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ wdt_ctr_load(2,65535); /* Length of reset pulse */ outb_p(0, WDT_DC); /* Enable watchdog */ + spin_unlock_irqrestore(&wdt_lock, flags); return 0; } @@ -128,9 +133,12 @@ static int wdt_start(void) static int wdt_stop (void) { + unsigned long flags; + spin_lock_irqsave(&wdt_lock, flags); /* Turn the card off */ inb_p(WDT_DC); /* Disable watchdog */ wdt_ctr_load(2,0); /* 0 length reset pulses now */ + spin_unlock_irqrestore(&wdt_lock, flags); return 0; } @@ -143,11 +151,14 @@ static int wdt_stop (void) static int wdt_ping(void) { + unsigned long flags; + spin_lock_irqsave(&wdt_lock, flags); /* Write a watchdog value */ inb_p(WDT_DC); /* Disable watchdog */ wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ outb_p(0, WDT_DC); /* Enable watchdog */ + spin_unlock_irqrestore(&wdt_lock, flags); return 0; } @@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t) static int wdt_get_status(int *status) { - unsigned char new_status=inb_p(WDT_SR); + unsigned char new_status; + unsigned long flags; + + spin_lock_irqsave(&wdt_lock, flags); + new_status = inb_p(WDT_SR); + spin_unlock_irqrestore(&wdt_lock, flags); *status=0; if (new_status & WDC_SR_ISOI0) @@ -214,8 +230,12 @@ static int wdt_get_status(int *status) static int wdt_get_temperature(int *temperature) { - unsigned short c=inb_p(WDT_RT); + unsigned short c; + unsigned long flags; + spin_lock_irqsave(&wdt_lock, flags); + c = inb_p(WDT_RT); + spin_unlock_irqrestore(&wdt_lock, flags); *temperature = (c * 11 / 15) + 7; return 0; } @@ -237,7 +257,10 @@ static irqreturn_t wdt_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(&wdt_lock); + status = inb_p(WDT_SR); printk(KERN_CRIT "WDT status %d\n", status); @@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) printk(KERN_CRIT "Reset in 5ms.\n"); #endif } + spin_unlock(&wdt_lock); return IRQ_HANDLED; } diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c index 9b7f6b6edef6..fb4b876c9fda 100644 --- a/drivers/watchdog/wdt977.c +++ b/drivers/watchdog/wdt977.c @@ -470,20 +470,20 @@ static int __init wd977_init(void) } } - rc = misc_register(&wdt977_miscdev); + rc = register_reboot_notifier(&wdt977_notifier); if (rc) { - printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", - wdt977_miscdev.minor, rc); + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); goto err_out_region; } - rc = register_reboot_notifier(&wdt977_notifier); + rc = misc_register(&wdt977_miscdev); if (rc) { - printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", - rc); - goto err_out_miscdev; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt977_miscdev.minor, rc); + goto err_out_reboot; } printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", @@ -491,8 +491,8 @@ static int __init wd977_init(void) return 0; -err_out_miscdev: - misc_deregister(&wdt977_miscdev); +err_out_reboot: + unregister_reboot_notifier(&wdt977_notifier); err_out_region: if (!machine_is_netwinder()) release_region(IO_INDEX_PORT,2); |